Index: /main/tags/2.25/gsdl/INSTALL.TXT
===================================================================
--- /main/tags/2.25/gsdl/INSTALL.TXT	(revision 21064)
+++ /main/tags/2.25/gsdl/INSTALL.TXT	(revision 21064)
@@ -0,0 +1,196 @@
+
+Greenstone installation instructions
+
+       Greenstone software:
+       
+     * Unix
+          + Source distribution
+          + Building collections
+     * Windows
+          + Source distribution
+          + Binary distributions
+          + Building collections
+       
+   Greenstone Collections
+   
+   Other software:
+     * Perl for Windows
+     * Apache web server
+       
+   For more information about how to use the software, consult The
+   Greenstone Digital Library Software manual.
+   
+Unix source distribution
+
+     * Download the latest version of the source distribution
+     * Extract the gzipped tar archive (tar xvzf gsdl-xx.x.tgz); this
+       will create a directory gsdl into which all software is installed
+     * In the gsdl directory, type ./configure
+     * When the configure script has finished running, type make
+     * Type make install, which copies the compiled library file into the
+       gsdl/cgi-bin directory, and also installs several executables that
+       are used to build collections into gsdl/bin/$GSDLOS
+     * Move both library and the gsdlsite.cfg configuration file to your
+       system's cgi-bin directory, so that the library runs as a cgi
+       script
+     * Edit the gsdlsite.cfg configuration file to suit your site. Set
+       the gsdlhome field to point to your gsdl directory. Other fields
+       that may need changing are httpprefix (the web path to the gsdl
+       directory) and httpimg (the path to gsdl/images)
+     * Build the Demo Collection that comes with the distribution
+     * Access the Greenstone Digital Library home page at
+       http://localhost/cgi-bin/library (replace "localhost" by the
+       server's URL if your Internet browser is not running on the server
+       computer)
+     * If the Demo Collection does not appear on the home page, run
+       library from the Unix command line to generate debugging
+       information to help you locate the problem
+     * Access the administration page at
+       http://localhost/cgi-bin/library?a=status
+       
+Windows source distribution
+
+     * Download the latest version of the source distribution--the same
+       source code as for Unix (though for Windows you may want to select
+       a zipped version)
+     * Extract the distribution using WinZip or a similar utility
+     * The default is to extract Greenstone directly into C:\ (i.e. a
+       directory C:\gsdl will be created into which all software is
+       installed)
+     * In the resulting gsdl directory type nmake win32.mak
+     * Type nmake /f win32.mak install, which copies the Web Library
+       version of library.exe into the gsdl\cgi-bin directory and the
+       Local Library version into the gsdl directory; it also installs
+       several executables that are used to build collections into
+       gsdl\bin\windows
+       
+Windows binary distributions
+
+       Three separate binary distributions are available for Windows: the
+       Local Library, the Web Library, and the Collection Builder. First
+       decide which distribution you want; then:
+       
+     * Download the latest version of the desired binary distribution
+     * Extract the distribution using WinZip or a similar utility
+     * The default is to extract Greenstone directly into C:\ (i.e. a
+       directory C:\gsdl will be created into which all software is
+       installed).
+     * If installing the Collection Builder as well as one of the
+       Libraries, be sure to extract both distributions in the same
+       directory. It is safe to allow files occurring in the second
+       distribution installed to overwrite those in the first.
+     * Follow the instructions below for the version you have downloaded:
+       Local Library
+          + Run the library.exe executable. This will automatically start
+            your Internet browser and load the Greenstone Digital Library
+            home page. The Demo collection should be accessible from this
+            page.
+          + Access the administration page at
+            http://localhost/cgi-bin/library?a=status
+       Web Library
+          + If Greenstone is not installed to C:\gsdl, edit the
+            gsdlsite.cfg configuration file (in the cgi-bin directory) by
+            setting the gsdlhome field to point to your gsdl directory
+          + If you do not already have a webserver, install Apache as
+            described below
+          + If using an existing webserver, check the gsdlsite.cfg
+            configuration file to ensure that httpprefix contains the web
+            path to the gsdl directory and httpimg contains the path to
+            gsdl\images
+          + The Greenstone Digital Library home page will appear as
+            http://localhost/cgi-bin/library (replace "localhost" by the
+            server's URL if your Internet browser is not running on the
+            server computer)
+          + If the Demo Collection does not appear on the home page, run
+            library.exe from the DOS prompt to generate debugging
+            information to help you locate the problem
+          + Access the administration page at
+            http://localhost/cgi-bin/library?a=status
+       Collection Builder
+          + If you do not already have Perl, you will need to install it
+            (see below)
+          + Download a test collection (e.g. the Demo Collection) and
+            build it
+          + Reload the Greenstone home page at
+            http://localhost/cgi-bin/library
+          + If the Demo Collection does not appear on the home page, run
+            library.exe from the DOS prompt to generate debugging
+            information to help you locate the problem
+       
+Greenstone Collections
+
+     * Install Greenstone as described above
+     * Download the required collection. Collection distributions with
+       filenames like ***_prebuilt.zip are pre-built collections. All
+       others will require building.
+     * Extract the .zip or .tgz file to your gsdl/collect directory
+     * Build the collection if it was not pre-built
+       
+   Once a new collection has been built, Greenstone will automatically
+   notice it and include it on the home page (when you click Reload).
+   
+   Building Greenstone Collections on Unix
+     * Source setup.bash or setup.csh from within the gsdl directory to
+       set up environment variables and path (e.g. source setup.bash)
+     * Note that pwd is used to set $GSDLHOME. If you need to be able to
+       source setup.bash or setup.csh from a directory other than gsdl
+       (e.g. from your .profile or .bashrc) you will need to edit the
+       script.
+     * Run build colname, where colname is the directory name of your
+       collection (e.g. demo).
+       
+   Building Greenstone Collections on Windows
+     * Make sure the setup.bat batch file is correct (i.e. that it sets
+       the GSDLHOME environment variable to the correct path of your gsdl
+       directory)
+     * run setup.bat
+     * Run build colname, where colname is the directory name of your
+       collection (e.g. demo).
+       
+   To find out more about building collections, consult The Greenstone
+   Digital Library Software manual.
+   
+Perl for Windows
+
+     * Download Perl (pre-5.6 version)
+     * Doubleclick the self-extracting executable and follow instructions
+       
+The Apache Webserver
+
+     * Download the latest version of the Apache distribution
+     * Doubleclick the self-extracting executable and follow instructions
+     * Configure Apache for use with Greenstone by adding the following
+       to your Apache server's httpd.conf configuration file (which
+       resides in the Apache conf directory)
+     * Existing server configurations may need to be configured
+       differently--see your system administrator if necessary
+         _____________________________________________________________
+       
+       # Some NT installations complain about an inability to work
+       ServerName
+       # out for themselves -- on most systems you can leave it commented
+       out.
+       # "localhost" should be replaced by www.yourserver.com if you plan
+       # to serve Greenstone to anyone other than the local machine.
+       # ServerName localhost
+       # Make cgi-bin point to your Greenstone cgi-bin directory.
+       # Note the forward
+       # slashes (/) instead of standard Windows
+       # backslashes (\) -- a hangover from Apache's Unix roots.
+       ScriptAlias /cgi-bin/ "c:/gsdl/cgi-bin/"
+       <Directory "c:/gsdl/cgi-bin">
+       AllowOverride None
+       Options None
+       </Directory>
+       # DocumentRoot points to your Greenstone root directory.
+       # Make sure that httpd.conf doesn't contain any other DocumentRoot
+       # directives -- if they come after this they'll override it
+       DocumentRoot "c:/gsdl"
+       <Directory "c:/gsdl">
+       Allow from All
+       </Directory>
+       # Redirect http://localhost to http://localhost/cgi-bin/library
+       # "localhost" should be replaced by www.yourserver.com if you plan
+       # to serve Greenstone to anyone other than the local machine.
+       Redirect /index.html http://localhost/cgi-bin/library
+         _____________________________________________________________
Index: /main/tags/2.25/gsdl/Makefile.in
===================================================================
--- /main/tags/2.25/gsdl/Makefile.in	(revision 21064)
+++ /main/tags/2.25/gsdl/Makefile.in	(revision 21064)
@@ -0,0 +1,96 @@
+###########################################################################
+#
+# Makefile -- gsdl
+# A component of the Greenstone digital library software
+# from the New Zealand Digital Library Project at the
+# University of Waikato, New Zealand.
+#
+# Copyright (C) 1999  The 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 = @PACKAGE@
+VERSION = @VERSION@
+
+@SET_MAKE@
+CC = @CC@
+CPP = @CXX@
+CFLAGS = @CFLAGS@
+LIBS   = @LIBS@
+MDEFINES =
+TOPSRC = `pwd`
+
+GSDLOS = @gsdlos@
+
+COMPILE = $(CC) -c
+
+SOURCES = 
+
+OBJECTS = 
+
+ALLFILES = $(OBJECTS)
+
+INSTALLDIRS = src/recpt src/txt2db src/db2txt src/hashfile packages/mg 
+
+OTHERDIRS = packages/mg lib src/mgpp src/colservr  src/recpt src/txt2db src/db2txt src/hashfile
+
+all:
+	for odir in $(OTHERDIRS); do \
+	  echo making $@ in $$odir; \
+	  (cd $$odir && $(MAKE) $(MDEFINES) $@) || exit 1; \
+	done
+
+install:
+	for idir in $(INSTALLDIRS); do \
+	  echo installing $$idir; \
+	  (cd $$idir && $(MAKE) install) || exit 1; \
+	done
+
+distclean:
+	rm -f Makefile config.cache config.h config.log stamp-h config.status
+	for subdir in $(INSTALLDIRS) $(OTHERDIRS); do \
+	  echo cleaning $@ in $$subdir; \
+	  (cd $$subdir && $(MAKE) distclean) || exit 1; \
+	done
+
+clean:
+	for subdir in $(INSTALLDIRS) $(OTHERDIRS); do \
+	  echo cleaning $@ in $$subdir; \
+	  (cd $$subdir && $(MAKE) clean) || exit 1; \
+	done
+
+
+# For an explanation of the following Makefile rules, see node
+# `Automatic Remaking' in GNU Autoconf documentation.
+Makefile: Makefile.in config.status
+	CONFIG_FILES=$@ CONFIG_HEADERS= ./config.status
+config.status: configure
+	./config.status --recheck
+configure: configure.in aclocal.m4
+	cd $(srcdir) && autoconf
+
+config.h: stamp-h
+stamp-h: config.h.in config.status
+	CONFIG_FILES= CONFIG_HEADERS=config.h ./config.status
+config.h.in: stamp-h.in
+stamp-h.in: configure.in aclocal.m4 acconfig.h
+	cd $(srcdir) && autoheader
+	$(TOUCH) $(srcdir)/stamp-h.in
+
+
+
Index: /main/tags/2.25/gsdl/README.TXT
===================================================================
--- /main/tags/2.25/gsdl/README.TXT	(revision 21064)
+++ /main/tags/2.25/gsdl/README.TXT	(revision 21064)
@@ -0,0 +1,179 @@
+   
+The Greenstone software
+
+       Here we explain the software packages and information collections
+       in the Greenstone Digital Library software that you can download
+       and run on your own computer. Installation instructions for each
+       version of the software are given separately.
+       Greenstone is open-source software, distributed under the terms of
+       the GNU General Public License.
+       For more information about how to use the software, read The
+       Greenstone Digital Library Software manual (PDF format, 570 Kb).
+       This document also describes how to obtain associated software,
+       that is also freely available--ActiveState Perl and the Apache
+       Webserver.
+       
+Greenstone Distributions
+
+       Versions of Greenstone are available for
+       
+     * Unix
+          + Source distribution
+     * Windows
+          + Source distribution
+          + Binary distributions
+               o Local Library
+               o Web Library
+               o Collection Builder
+       
+   and you can also download some
+   
+     * Greenstone Collections
+       
+   All distributions are downloaded using the ftp protocol. The
+   directories contain old versions too, but we recommend that you always
+   download the latest release.
+   
+Unix source distribution
+
+   Greenstone has been developed and thoroughly tested on Linux systems.
+       It has also been compiled and had some testing on SunOS 5.6.
+       Please tell us if you port it to other flavors of Unix. Currently,
+       only a source distribution is available for Unix (let us know if
+       you need Unix binaries).
+       
+   In order to compile the Greenstone source on Unix, you will need
+     * GCC, the Gnu C++ compiler. Greenstone makes extensive use of the
+       C++ standard template library (we've found it to be broken on some
+       older versions of GCC; please tell us if you have STL problems)
+     * GDBM, the Gnu database manager (www.gnu.org)
+       
+   In order to run the Greenstone software, you will also need
+     * Perl (version 5 or higher) (www.gnu.org)
+     * Webserver software, e.g. Apache (www.apache.org)
+       
+   Most Unix installations will already have all that is required.
+   
+Windows source distribution
+
+       The source code is the same for Windows as for Unix, but the
+       installation instructions are different. Greenstone has currently
+       only been compiled on Windows using Microsoft Visual C++ 4.2 (we
+       use this version to retain compatibility with Windows 3.x). Minor
+       problems may occur with compilers other than VC++ 4.2--these will
+       be sorted out very soon for VC++ 6.0 and various Windows ports of
+       GNU GCC.
+       
+   In order to compile the Greenstone source on Windows, you will need
+     * Microsoft Visual C++ 4.2
+     * STL, the C++ standard template library (newer versions of VC++ and
+       GCC come with STL included) (www.sgi.com/Technology/STL)
+       
+   The GDBM source is included in the Greenstone source distribution.
+   
+   In order to run the Greenstone software, you will also need
+     * Perl (we recommend ActivePerl, see below)
+     * Webserver software (we recommend Apache, see below)
+       
+Windows binary distributions
+
+       There are three separate binary distributions for Windows: the
+       Local Library, the Web Library, and the Collection Builder.
+       Local Library. This enables any Windows computer to serve
+       pre-built Greenstone collections. The package includes the Demo
+       Collection; other collections can be downloaded in pre-built form.
+       The software is the same as that used on Greenstone CD-ROMs.
+       The Local Library is intended for use on standalone computers or
+       computers that do not already have webserver software. It contains
+       a built-in webserver, with limited web-serving configurability, so
+       that other computers on the same network can also access the
+       library.
+       
+   In order to construct new Greenstone collections, you will also need
+     * Collection Builder
+       
+   Web Library. This enables any computer with an existing webserver
+   (e.g. Apache) to serve pre-built Greenstone collections. The package
+   includes the Demo Collection; other collections can be downloaded in
+   pre-built form.
+   
+   The Web Library differs from the Local Library because the Local
+   Library is intended for computers that do not already have webserver
+   software.
+   
+   In order to run the Web Library, you will also need
+     * Webserver software (we recommend Apache, see below)
+       
+   In order to construct new Greenstone collections, you will also need
+     * Collection Builder
+       
+   Collection Builder. This allows you to build collections containing
+   material of your choice. Once built, collections can be served by
+   either the Local Library or the Web Library package. Several NZDL
+   collections can be downloaded in unbuilt form (see below) and built
+   using the Collection Builder.
+   
+   This package does not include any collections. You need to download a
+   collection (e.g. the Demo Collection) in order to try it out.
+   
+   In order to run the Collection Builder, you will also need
+     * Perl (we recommend ActivePerl, see below)
+       
+   In order to serve any collections you build, you will also need
+     * Local Library or Web Library package
+       
+Associated Software
+
+       Perl. We recommend ActivePerl from www.activestate.com
+       It seems that newer versions (Perl 5.6) do not work with the
+       Greenstone building programs: accordingly, you should download a
+       pre-5.6 version. (Whether this is a bug in our code, in
+       ActiveState's port of Perl 5.6, or in Perl 5.6 itself, is
+       difficult to say.) Please tell us any information on which Perl
+       ports work and which don't.
+       
+   Apache Webserver. Apache is free, and easy to install.
+   
+Greenstone Collections
+
+   Several of the collections on the NZDL website are available for
+       download, either in pre-built or unbuilt form.
+       
+   Note: on Windows, you need the Collection Builder package to make use
+   of unbuilt collections.
+   
+   The following collections are currently available
+   
+   Arabic Demonstration Collection arabic 4.2 Mb
+   Bibliotheque pour le developpement ... tulane 340 Mb
+   Chinese Demonstration Collection chinese 0.47 Mb
+   Collection on Critical Global Issues unu 71 Mb
+   Collection on Critical Global Issues 2 ccgi 102 Mb
+   Computer Science Bibliographies csbib 112 Mb
+   Computer Science Technical Reports cstr 1800 Mb
+   Demo Collection demo 2.5 Mb
+   Food and Nutrition Library fnl 98 Mb
+   HCI Bibliography hcibib 4.8 Mb
+   Humanity Development Library hdl 387 Mb
+   Indigenous Peoples Collection ipc 3.6 Mb
+   Mäori Newspapers niupepa 659 Mb
+   Medical and Health Library mhl 73 Mb
+   Project Gutenberg Collection gberg 428 Mb
+   Sahel Point Doc unesco 78 Mb
+   The Computists' Weekly tcc 5.0 Mb
+   Tidbits tidbits 5.4 Mb
+   Virtual Disaster Library paho 73 Mb
+   Women's History Collection whist 12 Mb
+   World Environment Library envl 220 Mb
+   Youth Oral History collection ohist 421 Mb
+       
+Bugs
+
+   Please report bugs or installation problems to
+       greenstone@cs.waikato.ac.nz
+       
+              -----------------------------------------------
+                                      
+   New Zealand Digital Library Project
+   Department of Computer Science, University of Waikato, New Zealand
+   April 2000
Index: /main/tags/2.25/gsdl/WIN32cfg.h
===================================================================
--- /main/tags/2.25/gsdl/WIN32cfg.h	(revision 21064)
+++ /main/tags/2.25/gsdl/WIN32cfg.h	(revision 21064)
@@ -0,0 +1,163 @@
+/* config.h.  Generated automatically by configure.  */
+/* config.h.in.  Generated automatically from configure.in by autoheader.  */
+
+/* Define if on AIX 3.
+   System headers sometimes define this.
+   We just want to avoid a redefinition error message.  */
+#ifndef _ALL_SOURCE
+/* #undef _ALL_SOURCE */
+#endif
+
+/* Define if using alloca.c.  */
+/* #undef C_ALLOCA */
+
+/* Define to empty if the keyword does not work.  */
+/* #undef const */
+
+/* Define to one of _getb67, GETB67, getb67 for Cray-2 and Cray-YMP systems.
+   This function is required for alloca.c support on those systems.  */
+/* #undef CRAY_STACKSEG_END */
+
+/* Define if you have alloca, as a function or macro.  */
+#define HAVE_ALLOCA 1
+
+/* Define if you have <alloca.h> and it should be used (not on Ultrix).  */
+/* #define HAVE_ALLOCA_H 1 */
+
+/* Define if you don't have vprintf but do have _doprnt.  */
+/* #undef HAVE_DOPRNT */
+
+/* Define if you have the vprintf function.  */
+#define HAVE_VPRINTF 1
+
+/* Define if on MINIX.  */
+/* #undef _MINIX */
+
+/* Define to `long' if <sys/types.h> doesn't define.  */
+/* #undef off_t */
+
+/* Define if the system does not provide POSIX.1 features except
+   with this defined.  */
+/* #undef _POSIX_1_SOURCE */
+
+/* Define if you need to in order for stat and other things to work.  */
+/* #undef _POSIX_SOURCE */
+
+/* Define as the return type of signal handlers (int or void).  */
+#define RETSIGTYPE void
+
+/* Define to `unsigned' if <sys/types.h> doesn't define.  */
+/* #undef size_t */
+
+/* If using the C implementation of alloca, define if you know the
+   direction of stack growth for your system; otherwise it will be
+   automatically deduced at run-time.
+	STACK_DIRECTION > 0 => grows toward higher addresses
+	STACK_DIRECTION < 0 => grows toward lower addresses
+	STACK_DIRECTION = 0 => direction of growth unknown
+ */
+/* #undef STACK_DIRECTION */
+
+/* Define if you have the ANSI C header files.  */
+#define STDC_HEADERS 1
+
+/* Define if you can safely include both <sys/time.h> and <time.h>.  */
+/* #define TIME_WITH_SYS_TIME 1 */
+
+/* Define if your <sys/time.h> declares struct tm.  */
+/* #undef TM_IN_SYS_TIME */
+
+/* Define to the name of the distribution.  */
+#define PACKAGE "mg"
+
+/* Define to the version of the distribution.  */
+#define VERSION "1.2"
+
+/* Define to 1 if you have the valloc function.  */
+/* #define HAVE_VALLOC 1 */
+
+/* Define to 1 if ANSI function prototypes are usable.  */
+#define PROTOTYPES 1
+
+ 
+/* Define to 1 for better use of the debugging malloc library.  See
+   site ftp.antaire.com in antaire/src, file dmalloc/dmalloc.tar.gz.  */
+/* #undef WITH_DMALLOC */
+
+ 
+/* Define to 1 if GNU regex should be used instead of GNU rx.  */
+/* #undef WITH_REGEX */
+
+/* Some braindead header files do not have the requ'd function declarations */
+#define HAVE_FGETC_DECL 1
+#define HAVE_FREAD_DECL 1
+
+/* See if have this field in the prstatus_t structure */
+/* It stores the size of the process heap */
+/* #define HAVE_PR_BRKSIZE 1 */
+
+/* Define if you have the ftime function.  */
+/* #undef HAVE_FTIME */
+
+/* Define if you have the getpagesize function.  */
+/* #undef HAVE_GETPAGESIZE */
+
+/* Define if you have the getrusage function.  */
+/* #undef HAVE_GETRUSAGE */
+
+/* Define if you have the mallinfo function.  */
+/* #undef HAVE_MALLINFO */
+
+/* Define if you have the select function.  */
+#define HAVE_SELECT 1
+
+/* Define if you have the setbuffer function.  */
+/* #undef HAVE_SETBUFFER */
+
+/* Define if you have the strftime function.  */
+#define HAVE_STRFTIME 1
+
+/* Define if you have the strtol function.  */
+#define HAVE_STRTOL 1
+
+/* Define if you have the times function.  */
+/* #define HAVE_TIMES 1 */
+
+/* Define if you have the valloc function.  */
+/* #define HAVE_VALLOC 1 */
+
+/* Define if you have the <dirent.h> header file.  */
+/* #define HAVE_DIRENT_H 1 */
+
+/* Define if you have the <fcntl.h> header file.  */
+#define HAVE_FCNTL_H 1
+
+/* Define if you have the <limits.h> header file.  */
+#define HAVE_LIMITS_H 1
+
+/* Define if you have the <memory.h> header file.  */
+#define HAVE_MEMORY_H 1
+
+/* Define if you have the <ndir.h> header file.  */
+/* #undef HAVE_NDIR_H */
+
+/* Define if you have the <string.h> header file.  */
+#define HAVE_STRING_H 1
+
+/* Define if you have the <sys/dir.h> header file.  */
+/* #undef HAVE_SYS_DIR_H */
+
+/* Define if you have the <sys/ndir.h> header file.  */
+/* #undef HAVE_SYS_NDIR_H */
+
+/* Define if you have the <sys/procfs.h> header file.  */
+/* #define HAVE_SYS_PROCFS_H 1 */
+
+/* Define if you have the <sys/time.h> header file.  */
+/* #define HAVE_SYS_TIME_H 1 */
+
+/* Define if you have the <unistd.h> header file.  */
+/* #define HAVE_UNISTD_H 1 */
+
+/* Define if you have the m library (-lm).  */
+#define HAVE_LIBM 1
Index: /main/tags/2.25/gsdl/acconfig.h
===================================================================
--- /main/tags/2.25/gsdl/acconfig.h	(revision 21064)
+++ /main/tags/2.25/gsdl/acconfig.h	(revision 21064)
@@ -0,0 +1,43 @@
+/* Special definitions for mg, processed by autoheader.
+   Created by [TS:Aug/95] 
+   by grepping for AC_DEFINE on configure.in and using the appropriate defs 
+   of acconfig.h used by GNU tar.
+*/
+
+/* Define to the name of the distribution.  */
+#undef PACKAGE
+
+/* Define to the version of the distribution.  */
+#undef VERSION
+
+/* Define if `union wait' is the type of the first arg to wait functions.  */
+#undef HAVE_UNION_WAIT
+
+/* Define to 1 if you have the valloc function.  */
+#undef HAVE_VALLOC
+
+/* Define to 1 if ANSI function prototypes are usable.  */
+#undef PROTOTYPES
+ 
+/* Define to 1 for better use of the debugging malloc library.  See
+   site ftp.antaire.com in antaire/src, file dmalloc/dmalloc.tar.gz.  */
+#undef WITH_DMALLOC
+ 
+/* Define to 1 if GNU regex should be used instead of GNU rx.  */
+#undef WITH_REGEX
+
+/* Some braindead header files do not have the requ'd function declarations */
+#undef HAVE_FGETC_DECL
+#undef HAVE_FREAD_DECL
+
+/* See if have this field in the prstatus_t structure */
+/* It stores the size of the process heap */
+#undef HAVE_PR_BRKSIZE
+
+/* Define FASTCGI if needsbe */
+#undef USE_FASTCGI
+
+
+
+
+
Index: /main/tags/2.25/gsdl/aclocal.m4
===================================================================
--- /main/tags/2.25/gsdl/aclocal.m4	(revision 21064)
+++ /main/tags/2.25/gsdl/aclocal.m4	(revision 21064)
@@ -0,0 +1,141 @@
+# Local additions to Autoconf macros.
+# Copyright (C) 1992, 1994, 1995 Free Software Foundation, Inc.
+# François Pinard <pinard@iro.umontreal.ca>, 1992.
+
+# [TS:Aug/95] - chopped out the NLS stuff which I don't support
+
+## ------------------------------- ##
+## Check for function prototypes.  ##
+## ------------------------------- ##
+
+AC_DEFUN(fp_C_PROTOTYPES,
+[AC_REQUIRE([fp_PROG_CC_STDC])
+AC_MSG_CHECKING([for function prototypes])
+if test "$ac_cv_prog_cc_stdc" != no; then
+  AC_MSG_RESULT(yes)
+  AC_DEFINE(PROTOTYPES)
+  U= ANSI2KNR=
+else
+  AC_MSG_RESULT(no)
+  U=_ ANSI2KNR=ansi2knr
+fi
+AC_SUBST(U)dnl
+AC_SUBST(ANSI2KNR)dnl
+])
+
+## ----------------------------------------- ##
+## ANSIfy the C compiler whenever possible.  ##
+## ----------------------------------------- ##
+
+# @defmac AC_PROG_CC_STDC
+# @maindex PROG_CC_STDC
+# @ovindex CC
+# If the C compiler in not in ANSI C mode by default, try to add an option
+# to output variable @code{CC} to make it so.  This macro tries various
+# options that select ANSI C on some system or another.  It considers the
+# compiler to be in ANSI C mode if it defines @code{__STDC__} to 1 and
+# handles function prototypes correctly.
+#
+# If you use this macro, you should check after calling it whether the C
+# compiler has been set to accept ANSI C; if not, the shell variable
+# @code{ac_cv_prog_cc_stdc} is set to @samp{no}.  If you wrote your source
+# code in ANSI C, you can make an un-ANSIfied copy of it by using the
+# program @code{ansi2knr}, which comes with Ghostscript.
+# @end defmac
+
+AC_DEFUN(fp_PROG_CC_STDC,
+[AC_MSG_CHECKING(for ${CC-cc} option to accept ANSI C)
+AC_CACHE_VAL(ac_cv_prog_cc_stdc,
+[ac_cv_prog_cc_stdc=no
+ac_save_CFLAGS="$CFLAGS"
+# Don't try gcc -ansi; that turns off useful extensions and
+# breaks some systems' header files.
+# AIX			-qlanglvl=ansi
+# Ultrix and OSF/1	-std1
+# HP-UX			-Aa -D_HPUX_SOURCE
+# SVR4			-Xc
+for ac_arg in "" -qlanglvl=ansi -std1 "-Aa -D_HPUX_SOURCE" -Xc
+do
+  CFLAGS="$ac_save_CFLAGS $ac_arg"
+  AC_TRY_COMPILE(
+[#if !defined(__STDC__) || __STDC__ != 1
+choke me
+#endif	
+], [int test (int i, double x);
+struct s1 {int (*f) (int a);};
+struct s2 {int (*f) (double a);};],
+[ac_cv_prog_cc_stdc="$ac_arg"; break])
+done
+CFLAGS="$ac_save_CFLAGS"
+])
+AC_MSG_RESULT($ac_cv_prog_cc_stdc)
+case "x$ac_cv_prog_cc_stdc" in
+  x|xno) ;;
+  *) CC="$CC $ac_cv_prog_cc_stdc" ;;
+esac
+])
+
+## --------------------------------------------------------- ##
+## Use AC_PROG_INSTALL, supplementing it with INSTALL_SCRIPT ##
+## substitution.					     ##
+## --------------------------------------------------------- ##
+
+AC_DEFUN(fp_PROG_INSTALL,
+[AC_PROG_INSTALL
+test -z "$INSTALL_SCRIPT" && INSTALL_SCRIPT='${INSTALL} -m 755'
+AC_SUBST(INSTALL_SCRIPT)dnl
+])
+
+## ----------------------------------- ##
+## Check if --with-dmalloc was given.  ##
+## ----------------------------------- ##
+
+# I just checked, and GNU rx seems to work fine with a slightly
+# modified GNU m4.  So, I put out the test below in my aclocal.m4,
+# and will try to use it in my things.  The idea is to distribute
+# rx.[hc] and regex.[hc] together, for a while.  The WITH_REGEX symbol
+# (which should also be documented in acconfig.h) is used to decide
+# which of regex.h or rx.h should be included in the application.
+#
+# If `./configure --with-regex' is given, the package will use
+# the older regex.  Else, a check is made to see if rx is already
+# installed, as with newer Linux'es.  If not found, the package will
+# use the rx from the distribution.  If found, the package will use
+# the system's rx which, on Linux at least, will result in a smaller
+# executable file.
+
+AC_DEFUN(fp_WITH_DMALLOC,
+[AC_MSG_CHECKING(if malloc debugging is wanted)
+AC_ARG_WITH(dmalloc,
+[  --with-dmalloc          use dmalloc, as in
+                          ftp://ftp.letters.com/src/dmalloc/dmalloc.tar.gz],
+[if test "$withval" = yes; then
+  AC_MSG_RESULT(yes)
+  AC_DEFINE(WITH_DMALLOC)
+  LIBS="$LIBS -ldmalloc"
+  LDFLAGS="$LDFLAGS -g"
+else
+  AC_MSG_RESULT(no)
+fi], [AC_MSG_RESULT(no)])
+])
+
+## --------------------------------- ##
+## Check if --with-regex was given.  ##
+## --------------------------------- ##
+
+AC_DEFUN(fp_WITH_REGEX,
+[AC_MSG_CHECKING(which of rx or regex is wanted)
+AC_ARG_WITH(regex,
+[  --with-regex            use older regex in lieu of GNU rx for matching],
+[if test "$withval" = yes; then
+  ac_with_regex=1
+  AC_MSG_RESULT(regex)
+  AC_DEFINE(WITH_REGEX)
+  LIBOBJS="$LIBOBJS regex.o"
+fi])
+if test -z "$ac_with_regex"; then
+  AC_MSG_RESULT(rx)
+  AC_CHECK_FUNC(re_rx_search, , [LIBOBJS="$LIBOBJS rx.o"])
+fi
+AC_SUBST(LIBOBJS)dnl
+])
Index: /main/tags/2.25/gsdl/bin/script/build
===================================================================
--- /main/tags/2.25/gsdl/bin/script/build	(revision 21064)
+++ /main/tags/2.25/gsdl/bin/script/build	(revision 21064)
@@ -0,0 +1,145 @@
+#!/usr/bin/perl
+
+# This perl script may be called directly or by running build.bat on
+# windows (build.bat is in bin\windows)
+
+BEGIN {
+
+    die "GSDLHOME not set - did you remember to source setup.bash (unix) or " .
+	"run setup.bat (windows)?\n" unless defined $ENV{'GSDLHOME'};
+    die "GSDLOS not set - did you remember to source setup.bash (unix) or " .
+	"run setup.bat (windows)?\n" unless defined $ENV{'GSDLOS'};
+    unshift (@INC, "$ENV{'GSDLHOME'}/perllib");
+}
+
+use parsargv;
+use util;
+
+
+if (!parsargv::parse(\@ARGV, 
+		     'buildtype/^(build|import)$/import', \$buildtype,
+		     'maxdocs/^\-?\d+/-1', \$maxdocs)) {
+    &print_usage();
+    die "\n";
+}
+
+my ($collection) = @ARGV;
+
+if (!defined $collection || $collection !~ /\w/) {
+    print STDERR "You must specify a collection to build\n";
+    &print_usage();
+    die "\n";
+}
+
+if ($maxdocs == -1) {
+    $maxdocs = "";
+} else {
+    $maxdocs = "-maxdocs $maxdocs";
+}
+
+
+my $collectdir = &util::filename_cat ($ENV{'GSDLHOME'}, "collect", $collection);
+my $importdir = &util::filename_cat ($collectdir, "import");
+my $archivedir = &util::filename_cat ($collectdir, "archives");
+my $buildingdir = &util::filename_cat ($collectdir, "building");
+my $indexdir = &util::filename_cat ($collectdir, "index");
+my $bindir = &util::filename_cat ($ENV{'GSDLHOME'}, "bin");
+
+&main();
+
+sub print_usage {
+    print STDERR "\n  usage: $0 [options] collection-name\n\n";
+    print STDERR "  options:\n";
+    print STDERR "   -buildtype build|import If 'build' attempt to build directly\n";
+    print STDERR "                           from archives directory (bypassing import\n";
+    print STDERR "                           stage). Defaults to 'import'\n";
+    print STDERR "   -maxdocs number         Maximum number of documents to build\n\n";
+}
+
+sub main {
+
+    if (-e &util::filename_cat ($archivedir, "archives.inf")) {
+	if (&has_content ($importdir)) {
+	    if ($buildtype eq "build") {
+		&gsdl_build();
+	    } else {
+		&gsdl_import();
+		&gsdl_build();
+	    }
+	} else {
+	    # there are archives but no import, build directly from archives
+	    print STDERR "build: no import material was found, building directly\n";
+	    print STDERR "       from archives\n";
+	    &gsdl_build();
+	}
+    } else {
+	if (&has_content ($importdir)) {
+	    if ($buildtype eq "build") {
+		print STDERR "build: can't build directly from archives as no\n";
+		print STDERR "       imported archives exist (did you forget to\n";
+		print STDERR "       move the contents of $collection/import to\n";
+		print STDERR "       collection/archives?)\n";
+	    }
+	    &gsdl_import();
+	    &gsdl_build();
+	} else {
+	    # no import or archives
+	    print STDERR "build: ERROR: The $collection collection has no import\n";
+	    print STDERR "       or archives data. Try downloading an unbuilt version\n";
+	    print STDERR "       of the collection from www.nzdl.org\n";
+	    die "\n";
+	}
+    }
+}
+
+sub gsdl_import {
+
+    print STDERR "importing the $collection collection\n\n";
+
+    my $import = &util::filename_cat ($bindir, "script", "import.pl");
+    system ("perl $import -removeold $maxdocs $collection");
+    if (-e &util::filename_cat ($archivedir, "archives.inf")) {
+	print STDERR "$collection collection imported successfully\n\n";
+    } else {
+	die "\nimport.pl failed\n";
+    }
+}
+
+sub gsdl_build {
+
+    print STDERR "building the $collection collection\n\n";
+
+    my $buildcol = &util::filename_cat ($bindir, "script", "buildcol.pl");
+    system ("perl $buildcol $maxdocs $collection");
+    if (-e &util::filename_cat ($buildingdir, "text", "$collection.ldb") ||
+	-e &util::filename_cat ($buildingdir, "text", "$collection.bdb")) {
+	print STDERR "$collection collection built successfully\n\n";
+    } else {
+	die "\nbuildcol.pl failed\n";
+    }
+
+    # replace old indexes with new ones
+    if (&has_content ($indexdir)) {
+	print STDERR "removing old indexes\n";
+	&util::rm_r ($indexdir);
+    }
+    rmdir ($indexdir) if -d $indexdir;
+    rename ($buildingdir, $indexdir);
+}
+
+sub has_content {
+    my ($dir) = @_;
+
+    if (!-d $dir) {return 0;}
+
+    opendir (DIR, $dir) || return 0;
+    my @files = readdir DIR;
+    close DIR;
+    
+    foreach my $file (@files) {
+	if ($file !~ /^\.{1,2}$/) {
+	    return 1;
+	}
+    }
+    return 0;
+}
Index: /main/tags/2.25/gsdl/bin/script/buildcol.pl
===================================================================
--- /main/tags/2.25/gsdl/bin/script/buildcol.pl	(revision 21064)
+++ /main/tags/2.25/gsdl/bin/script/buildcol.pl	(revision 21064)
@@ -0,0 +1,244 @@
+#!/usr/bin/perl -w
+
+###########################################################################
+#
+# buildcol.pl -- This program will build a particular collection
+# A component of the Greenstone digital library software
+# from the New Zealand Digital Library Project at the 
+# University of Waikato, New Zealand.
+#
+# Copyright (C) 1999 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.
+#
+###########################################################################
+
+BEGIN {
+    die "GSDLHOME not set\n" unless defined $ENV{'GSDLHOME'};
+    die "GSDLOS not set\n" unless defined $ENV{'GSDLOS'};
+    unshift (@INC, "$ENV{'GSDLHOME'}/perllib");
+    unshift (@INC, "$ENV{'GSDLHOME'}/perllib/plugins");
+    unshift (@INC, "$ENV{'GSDLHOME'}/perllib/classify");
+}
+
+use colcfg;
+use parsargv;
+use util;
+
+&main();
+
+sub print_usage {
+    print STDERR "\n  usage: $0 [options] collection-name\n\n";
+    print STDERR "  options:\n";
+    print STDERR "   -verbosity number     0=none, 3=lots\n";
+    print STDERR "   -archivedir directory Where the archives live\n";
+    print STDERR "   -cachedir directory   Where to cache the archives\n";
+    print STDERR "   -builddir directory   Where to put the built indexes\n";
+    print STDERR "   -maxdocs number       Maximum number of documents to build\n";
+    print STDERR "   -debug                Print output to STDOUT\n";
+    print STDERR "   -mode all|compress_text|build_index|infodb\n";
+    print STDERR "   -index indexname      Index to build (will build all in\n"; 
+    print STDERR "                         config file if not set)\n";
+    print STDERR "   -keepold              will not destroy the current contents of the\n";
+    print STDERR "                         building directory\n";
+    print STDERR "   -allclassifications   Don't remove empty classifications\n";
+    print STDERR "   -create_images        Attempt to create default images for new\n";
+    print STDERR "                         collection. This relies on the Gimp being\n";
+    print STDERR "                         installed along with relevant perl modules\n";
+    print STDERR "                         to allow scripting from perl\n\n";
+}
+
+
+sub main
+{
+    my ($verbosity, $archivedir, $cachedir, $builddir, $maxdocs, 
+	$debug, $mode, $indexname, $keepold, $allclassifications,
+	$create_images);
+    if (!parsargv::parse(\@ARGV, 
+			 'verbosity/\d+/2', \$verbosity,
+			 'archivedir/.*/', \$archivedir,
+			 'cachedir/.*/', \$cachedir,
+			 'builddir/.*/', \$builddir,
+			 'maxdocs/^\-?\d+/-1', \$maxdocs,
+			 'debug', \$debug,
+			 'mode/^(all|compress_text|build_index|infodb)$/all', \$mode,
+			 'index/.*/', \$indexname,
+			 'keepold', \$keepold,
+			 'allclassifications', \$allclassifications,
+			 'create_images', \$create_images)) {
+	&print_usage();
+	die "\n";
+    }
+
+    # get and check the collection
+    if (($collection = &util::use_collection(@ARGV)) eq "") {
+	&print_usage();
+	die "\n";
+    }
+
+    # read the configuration file
+    $textindex = "section:text";
+    $configfilename = &util::filename_cat ($ENV{'GSDLCOLLECTDIR'}, "etc", "collect.cfg");
+    if (-e $configfilename) {
+	$collectcfg = &colcfg::read_collect_cfg ($configfilename);
+	if (defined $collectcfg->{'archivedir'} && $archivedir eq "") {
+	    $archivedir = $collectcfg->{'archivedir'};
+	}
+	if (defined $collectcfg->{'cachedir'} && $cachedir eq "") {
+	    $cachedir = $collectcfg->{'cachedir'};
+	}
+	if (defined $collectcfg->{'builddir'} && $builddir eq "") {
+	    $builddir = $collectcfg->{'builddir'};
+	}
+    } else {
+	die "Couldn't find the configuration file $configfilename\n";
+    }
+    
+    # create default images if required
+    if ($create_images) {
+	my $collection_name = $collection;
+	$collection_name = $collectcfg->{'collectionmeta'}->{'collectionname'} 
+	if defined $collectcfg->{'collectionmeta'}->{'collectionname'};
+	
+	&create_images ($collection_name);
+    }
+
+    # fill in the default archives and building directories if none
+    # were supplied, turn all \ into / and remove trailing /
+    $archivedir = "$ENV{'GSDLCOLLECTDIR'}/archives" if $archivedir eq "";
+    $archivedir =~ s/[\\\/]+/\//g;
+    $archivedir =~ s/\/$//;
+    $builddir = "$ENV{'GSDLCOLLECTDIR'}/building" if $builddir eq "";
+    $builddir =~ s/[\\\/]+/\//g;
+    $builddir =~ s/\/$//;
+
+    # update the archive cache if needed
+    if ($cachedir) {
+	print STDERR "Updating archive cache\n" if ($verbosity >= 1);
+
+	$cachedir =~ s/[\\\/]+$//;
+	$cachedir .= "/collect/$collection" unless 
+	    $cachedir =~ /collect\/$collection/;
+
+	$realarchivedir = "$cachedir/archives";
+	$realbuilddir = "$cachedir/building";
+	&util::mk_all_dir ($realarchivedir);
+	&util::mk_all_dir ($realbuilddir);
+	&util::cachedir ($archivedir, $realarchivedir, $verbosity);
+
+    } else {
+	$realarchivedir = $archivedir;
+	$realbuilddir = $builddir;
+    }
+
+    # build it in realbuilddir
+    &util::mk_all_dir ($realbuilddir);
+
+
+    # if a builder class has been created for this collection, use it
+    # otherwise, use the mg builder
+    if (-e "$ENV{'GSDLCOLLECTDIR'}/perllib/${collection}builder.pm") {
+	$builderdir = "$ENV{'GSDLCOLLECTDIR'}/perllib";
+	$buildertype = "${collection}builder";
+    } else {
+	$builderdir = "$ENV{'GSDLHOME'}/perllib";
+	$buildertype = "mgbuilder";
+    }
+	
+    require "$builderdir/$buildertype.pm";
+
+    eval("\$builder = new $buildertype(\$collection, " .
+	 "\$realarchivedir, \$realbuilddir, \$verbosity, " .
+	 "\$maxdocs, \$debug, \$keepold, \$allclassifications)");
+    die "$@" if $@;
+
+    $builder->init();
+
+    if ($mode =~ /^all$/i) {
+	$builder->compress_text($textindex);
+	$builder->build_indexes($indexname);
+	$builder->make_infodatabase();
+	$builder->collect_specific();
+    } elsif ($mode =~ /^compress_text$/i) {
+	$builder->compress_text($textindex);
+    } elsif ($mode =~ /^build_index$/i) {
+	$builder->build_indexes($indexname);	
+    } elsif ($mode =~ /^infodb$/i) {
+	$builder->make_infodatabase();
+    } else {
+	die "unknown mode: $mode\n";
+    }
+
+    $builder->make_auxiliary_files() if !$debug;
+    $builder->deinit();
+    
+    if (($realbuilddir ne $builddir) && !$debug) {
+	print STDERR "Copying back the cached build\n" if ($verbosity >= 1);
+	&util::rm_r ($builddir);
+	&util::cp_r ($realbuilddir, $builddir);
+    }
+}
+
+sub create_images {
+    my ($collection_name) = @_;
+
+    my $image_script = &util::filename_cat ($ENV{'GSDLHOME'}, "bin", "script", "gimp", "title_icon.pl");
+    if (!-e $image_script) {
+	print STDERR "WARNING: Image making script ($image_script) could not be found\n";
+	print STDERR "         Default images will not be generated\n\n";
+	return;
+    }
+
+    my $imagedir = &util::filename_cat ($ENV{'GSDLCOLLECTDIR'}, "images");
+
+    &util::mk_all_dir ($imagedir);
+
+    # create the images
+    system ("$image_script -size 1.5 -image_dir \"$imagedir\" -filename $collection.gif -text \"$collection_name\"");
+    system ("$image_script -image_dir \"$imagedir\" -filename ${collection}sm.gif -text \"$collection_name\"");
+
+    # update the collect.cfg configuration file (this will need
+    # to be changed when the config file format changes)
+    if (!open (CFGFILE, $configfilename)) {
+	print STDERR "WARNING: Couldn't open config file ($configfilename)\n";
+	print STDERR "         for updating so collection images may not be linked correctly\n";
+	return;
+    }
+
+    my $line = ""; my $file = "";
+    my $found = 0; my $foundsm = 0;
+    while (defined ($line = <CFGFILE>)) {
+	if ($line =~ /collectionmeta\s+iconcollection\s+/) {
+	    $line = "collectionmeta iconcollection _httpprefix_/collect/$collection/images/$collection.gif\n";
+	    $found = 1;
+	} elsif ($line =~ /collectionmeta\s+iconcollectionsmall\s+/) {
+	    $line = "collectionmeta iconcollectionsmall _httpprefix_/collect/$collection/images/${collection}sm.gif\n";
+	    $foundsm = 1;
+	}
+	$file .= $line;
+    }
+    close CFGFILE;
+
+    $file .= "collectionmeta iconcollection _httpprefix_/collect/$collection/images/$collection.gif\n" if !$found;
+    $file .= "collectionmeta iconcollectionsmall _httpprefix_/collect/$collection/images/${collection}sm.gif\n" if !$foundsm;
+
+    if (!open (CFGFILE, ">$configfilename")) {
+	print STDERR "WARNING: Couldn't open config file ($configfilename)\n";
+	print STDERR "         for updating so collection images may not be linked correctly\n";
+	return;
+    }
+    print CFGFILE $file;
+    close CFGFILE;
+}
Index: /main/tags/2.25/gsdl/bin/script/clean_archives.pl
===================================================================
--- /main/tags/2.25/gsdl/bin/script/clean_archives.pl	(revision 21064)
+++ /main/tags/2.25/gsdl/bin/script/clean_archives.pl	(revision 21064)
@@ -0,0 +1,109 @@
+#!/usr/local/bin/perl5
+
+###########################################################################
+#
+# clean_archives.pl
+# A component of the Greenstone digital library software
+# from the New Zealand Digital Library Project at the 
+# University of Waikato, New Zealand.
+#
+# Copyright (C) 1999 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.
+#
+###########################################################################
+
+
+# clean_archives.pl removes any doc.gml, doc.gml.gz, and empty
+# directories from the directory passed on the command line.
+
+BEGIN {
+    die "GSDLHOME not set\n" unless defined $ENV{'GSDLHOME'};
+    unshift (@INC, "$ENV{'GSDLHOME'}/perllib");
+    unshift (@INC, "$ENV{'GSDLHOME'}/perllib/plugins");
+}
+
+use parsargv;
+use util;
+
+sub print_usage {
+    print STDERR "\n  usage: $0 [options] archive-dir\n\n";
+    print STDERR "  oprions:\n";
+    print STDERR "   -verbose\n\n";
+}
+
+
+&main ();
+
+sub main {
+    
+    if (!parsargv::parse(\@ARGV, 
+			 'verbose', \$verbose)) {
+	&print_usage();
+	die "\n";
+    }
+
+    if (scalar (@ARGV) != 1) {
+	&print_usage();
+	die "\n";
+    }
+
+    my $dir = $ARGV[0];
+    
+    if (!-d $dir) {
+	&print_usage();
+	die "\n";
+    }
+	
+    &recurse_dir ($dir);
+}
+
+sub recurse_dir {
+    my ($dir) = @_;
+
+    opendir (DIR, $dir) || die;
+    my @files = readdir DIR;
+    closedir DIR;
+
+    foreach $file (@files) {
+	next if $file =~ /^\.+$/;
+	my $filename = &util::filename_cat($dir, $file);
+	
+	if (-d $filename) {
+	    &recurse_dir ($filename);
+	} elsif ($file =~ /^doc\.gml(\.gz)?$/) {
+
+	    unlink ($filename);
+	    print STDERR "removing $filename\n" if $verbose;
+	}
+    }
+
+    # remove the directory if it's now empty
+    opendir (DIR, $dir) || die;
+    @files = readdir DIR;
+    closedir DIR;
+
+    if (scalar(@files) == 0) {
+	rmdir ($dir);
+	print STDERR "removing empty directory $dir\n" if $verbosity;
+    } elsif (scalar(@files) == 2) {
+	my $empty = 1;
+	map { if ($_ !~ /^\.+$/) {$empty = 0;} } @files;
+	if ($empty) {
+	    rmdir ($dir);
+	    print STDERR "removing empty directory $dir\n" if $verbosity;
+	}
+    }
+}
Index: /main/tags/2.25/gsdl/bin/script/filecopy.pl
===================================================================
--- /main/tags/2.25/gsdl/bin/script/filecopy.pl	(revision 21064)
+++ /main/tags/2.25/gsdl/bin/script/filecopy.pl	(revision 21064)
@@ -0,0 +1,162 @@
+#!/usr/bin/perl -w
+
+###########################################################################
+#
+# filecopy.pl --
+# A component of the Greenstone digital library software
+# from the New Zealand Digital Library Project at the 
+# University of Waikato, New Zealand.
+#
+# Copyright (C) 1999 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.
+#
+###########################################################################
+
+
+# This program will "download" the specified files/directories
+
+BEGIN {
+    die "GSDLHOME not set\n" unless defined $ENV{'GSDLHOME'};
+    unshift (@INC, "$ENV{'GSDLHOME'}/perllib");
+}
+
+use util;
+use File::stat;
+
+sub print_usage
+{
+    print STDERR "\n  usage: $0 [filenames] [directories] collection-name\n\n";
+}
+
+
+sub download_files
+{
+    my $dirname = pop(@_);
+    my $full_importname 
+	= &util::filename_cat($ENV{'GSDLHOME'},"collect",$dirname,"import");
+
+    # split argv into 2 lists: files and directories
+    my (@files,@dirs) = ((),());
+    my $a;
+    foreach $a (@_)
+    {
+	$a =~ s/^\"//;
+	$a =~ s/\"$//;
+
+	if (-e $a)
+	{
+	    if (-d $a)
+	    {
+		push(@dirs,$a);
+	    }
+	    else
+	    {
+		push(@files,$a);
+	    }
+	}
+	else
+	{
+	    print STDERR "Error: filename '$a' does not exist\n";
+	}
+    }
+    
+    if (scalar(@files)>0)
+    {
+	my $f;	
+	foreach $f (@files)
+	{
+	    my $src_file = $f;
+	    my $dst_file = &get_dst_dir ($full_importname,$f);
+
+	    my $do_copy = "no";
+	    if (-e $dst_file)
+	    {
+		# compare file dates
+		my $src_stat = stat($src_file);
+		my $dst_stat = stat($dst_file);
+
+		if ($src_stat->mtime > $dst_stat->mtime)
+		{
+		    $do_copy = "yes";
+		}
+	    }
+	    else
+	    {
+		$do_copy = "yes";
+	    }
+
+	    if ($do_copy eq "yes")
+	    {
+		print STDOUT "Copying $src_file-->$dst_file\n";
+		&util::cp($src_file,$dst_file);
+	    }
+	}
+    }
+
+
+    if (scalar(@dirs)>0)
+    {
+	my $d;	
+	foreach $d (@dirs)
+	{
+	    my $src_dir = $d;
+	    my $dst_dir = &get_dst_dir ($full_importname, $d);
+	    if (!-e $dst_dir)
+	    {
+		# create it if it doesn't exist
+		&util::mk_all_dir($dst_dir);
+	    }
+
+	    # read in dir
+            if (!opendir (INDIR, $d)) 
+	    {
+                print STDERR "Error: Could not open directory $d\n";
+            } 
+	    else 
+	    {
+                my @sub_files = grep (!/^\.\.?$/, readdir (INDIR));
+                closedir (INDIR);
+
+		map { $_ = &util::filename_cat($d,$_); } @sub_files;
+		download_files(@sub_files,$dirname);
+	    }
+	}
+    }
+}
+
+sub main
+{
+    if (scalar(@ARGV)<2)
+    {
+	print_usage();
+	exit(1);
+    }
+
+    download_files(@ARGV);
+    return 0;
+}
+
+sub get_dst_dir {
+    my ($full_importname, $dir) = @_;
+
+    if ($ENV{'GSDLOS'} eq "windows") {
+	# don't want windows filenames like c:\gsdl\...\import\c:\dir
+	$dir =~ s/^[a-z]:[\\\/]//i;
+    }
+    return &util::filename_cat($full_importname,$dir);
+}
+
+&main();
Index: /main/tags/2.25/gsdl/bin/script/gimp/flash_button.pl
===================================================================
--- /main/tags/2.25/gsdl/bin/script/gimp/flash_button.pl	(revision 21064)
+++ /main/tags/2.25/gsdl/bin/script/gimp/flash_button.pl	(revision 21064)
@@ -0,0 +1,339 @@
+#!/usr/bin/perl -w
+
+###########################################################################
+#
+# flash_button.pl 
+# A component of the Greenstone digital library software
+# from the New Zealand Digital Library Project at the 
+# University of Waikato, New Zealand.
+#
+# Copyright (C) 1999 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.
+#
+###########################################################################
+
+# flash_button.pl generates all the flashy javascript type
+# buttons used by Greenstone
+# these are the buttons described in macro files as:
+# top_nav_button
+# nav_bar_button
+# document_button
+
+BEGIN {
+    die "GSDLHOME not set\n" unless defined $ENV{'GSDLHOME'};
+    unshift (@INC, "$ENV{'GSDLHOME'}/perllib");
+}
+
+use Gimp;
+use parsargv;
+use util;
+
+# set trace level to watch functions as they are executed
+#Gimp::set_trace(TRACE_ALL);
+#Gimp::set_trace(TRACE_CALL);
+
+my $gsdl_yellow = "#D2B464";
+my $black = "#000000";
+
+my ($cfg_file, $width, $height, $text, $filenamestem, $fixed_width,
+    $width_space, $whitespace, $dont_center, $bgcolor, $fontcolor, 
+    $fontsize, $fontname, $fontweight, $fontslant, $fontwidth, 
+    $fontspacing, $image_dir);
+
+sub print_usage {
+    print STDERR "\n  usage: $0 [options]\n\n";
+    print STDERR "  options:\n";
+    print STDERR "   -cfg_file file        configuration file containing one or more\n";
+    print STDERR "                         sets of the following options - use to create\n";
+    print STDERR "                         batches of images\n";
+    print STDERR "   -image_dir directory  directory to create images in [`pwd`]\n";
+    print STDERR "                         this should be full path to existing directory\n";
+    print STDERR "   -width number         width of button [65]\n";
+    print STDERR "   -height number        height of button [30]\n";
+    print STDERR "   -text string          button text\n";
+    print STDERR "   -filenamestem string  filename - two images will be produced -\n";
+    print STDERR "                         filenamestemon.gif and filenamestemof.gif\n";
+    print STDERR "   -fixed_width          fix width of image - if this isn't set\n";
+    print STDERR "                         image will be cropped with with width_space\n";
+    print STDERR "                         space at each side of text\n";
+    print STDERR "   -width_space number   width in pixels of blank space to leave at left\n";
+    print STDERR "                         and right edges of text [1]\n";
+    print STDERR "   -whitespace           add 1 pixel of white space at left and right edges\n";
+    print STDERR "                         of image\n";
+    print STDERR "   -dont_center          don't center text horizontally (only applicable if\n";
+    print STDERR "                         image is fixed width\n";
+    print STDERR "   -bgcolor hex_value    background color of button [$gsdl_yellow]\n";
+    print STDERR "   -fontcolor hex_value  text color [$black]\n";
+    print STDERR "   -fontsize number      font point size [10]\n";
+    print STDERR "   -fontname string      [lucida]\n";
+    print STDERR "   -fontweight string    [medium]\n";
+    print STDERR "   -fontslant            [r]\n";
+    print STDERR "   -fontwidth            [*]\n";
+    print STDERR "   -fontspacing          [*]\n\n";
+}
+
+sub reset_options {
+    $image_dir = "./";
+    $width = 65;
+    $height = 30;
+    $text = "";
+    $filenamestem = "";
+    $fixed_width = 0;
+    $width_space = 1;
+    $whitespace = 0;
+    $dont_center = 0;
+    $bgcolor = $gsdl_yellow;
+    $fontcolor = $black;
+    $fontsize = 10;
+    $fontname = "lucida";
+    $fontweight = "medium";
+    $fontslant = "r";
+    $fontwidth = "*";
+    $fontspacing = "*";
+}
+
+sub gsdl_flash_button {
+
+    if (!parsargv::parse(\@ARGV, 
+			 'cfg_file/.*/', \$cfg_file,
+			 'image_dir/.*/./', \$image_dir,
+			 'width/^\d+$/65', \$width,
+			 'height/^\d+$/30', \$height,
+			 'text/.*/', \$text,
+			 'filenamestem/.*', \$filenamestem,
+			 'fixed_width', \$fixed_width,
+			 'width_space/^\d+$/1', \$width_space,
+			 'whitespace', \$whitespace,
+			 'dont_center', \$dont_center,
+			 "bgcolor/#[0-9A-Fa-f]{6}/$gsdl_yellow", \$bgcolor,
+			 "fontcolor/#[0-9A-Fa-f]{6}/$black", \$fontcolor,
+			 'fontsize/^\d+$/10', \$fontsize,
+			 'fontname/.*/lucida', \$fontname,
+			 'fontweight/.*/medium', \$fontweight,
+			 'fontslant/.*/r', \$fontslant,
+			 'fontwidth/.*/*', \$fontwidth,
+			 'fontspacing/.*/*', \$fontspacing)) {
+	&print_usage();
+	die "flash_button.pl: incorrect options\n";
+    }
+
+    # will create wherever gimp was started up from if we don't do this
+    if ($image_dir eq "./") {
+	$image_dir = `pwd`;
+	chomp $image_dir;
+    }
+
+    # replace any '\n' occurring in text with carriage return
+    $text =~ s/\\n/\n/gi;
+    
+    if ($cfg_file =~ /\w/) {
+	
+	open (CONF, $cfg_file) || die "couldn't open cfg_file $cfg_file\n";
+	while (1) {
+
+	    &reset_options ();
+	
+	    # read image configuration entry
+	    my $status = &read_config_entry (CONF);
+	    if ($filenamestem !~ /\w/) {
+		if ($status) {last;}
+		else {next;}
+	    }
+
+	    &produce_images (0);
+	    if ($status) {last;}
+	}
+
+	close CONF;
+
+    } else {
+
+	&produce_images (0);
+
+    }
+}
+
+sub produce_images {
+    my ($off_img) = @_;
+    
+    # create image, set background color etc.
+    my ($image, $backlayer) = &create_image ($off_img);
+    
+    # set the text if there is any
+    if (length($text)) {
+
+	my $textlayer = gimp_text ($image, $backlayer, 0, 0, $text, 0, 1, 
+				   $fontsize, PIXELS, "*", $fontname, $fontweight, 
+				   $fontslant, $fontwidth, $fontspacing);
+	
+
+	my $textwidth = gimp_drawable_width($textlayer);
+	my $textheight = gimp_drawable_height($textlayer);
+
+	# check that text fits within image
+	if ($textheight > $height) {
+	    die "'$text' at fontsize of $fontsize pixels does not fit within image\n" . 
+		"$height pixels high. Decrease fontsize or increase image height\n";
+	}
+
+	my $spacers = $width_space * 2;
+	$spacers += 2 if $whitespace;
+
+	if (!$fixed_width || $textwidth > $width) {
+
+	    if ($fixed_width) {
+		print STDERR "WARNING (flash_button.pl): '$text' does not fit within $width pixel fixed width ";
+		print STDERR "image. Image width was increased to ",$textwidth + $spacers, " pixels\n";
+	    }
+	    
+	    $width = $textwidth + $spacers;
+
+	    # recreate image in new size
+	    ($image, $backlayer) = &create_image ($off_img);
+	    $textlayer = gimp_text ($image, $backlayer, 0, 0, $text, 0, 1, 
+				    $fontsize, PIXELS, "*", $fontname, $fontweight, 
+				    $fontslant, $fontwidth, $fontspacing);
+	    
+	}
+
+	my $y_offset = ($height-$textheight)-int($fontsize/5);
+	if ($text =~ /[gjpqy]/) {
+	    # descenders - put text at bottom of image, otherwise 
+	    # go for fontsize/5 pixels above bottom. This is kind of hacky 
+	    # and may need some playing with for different fonts/fontsizes
+	    $y_offset = $height-$textheight;
+	}
+
+	if ($fixed_width) {
+	    if ($dont_center) {
+		# don't center text horizontally (start it width_space pixels from left edge)
+		my $x_offset = $width_space;
+		$x_offset += 1 if $whitespace;
+		gimp_layer_set_offsets ($textlayer, $x_offset, $y_offset);
+	    } else {
+		gimp_layer_set_offsets ($textlayer, ($width-$textwidth)/2, $y_offset);
+	    }
+	} else {
+	    gimp_layer_set_offsets ($textlayer, $spacers / 2, $y_offset); 
+	}
+    }
+    
+    # add pixel of whitespace to each edge if required
+    if ($whitespace) {
+	gimp_rect_select ($image, 0, 0, 1, $height, 0, 0, 0);
+	gimp_edit_clear ($image, $backlayer);
+	gimp_selection_none ($image);
+	gimp_rect_select ($image, $width-1, 0, 1, $height, 0, 0, 0);
+	gimp_edit_clear ($image, $backlayer);
+	gimp_selection_none ($image);
+    }
+    
+    # flatten the image
+    my $finishedlayer = gimp_image_flatten ($image);
+    
+    # make indexed colour 
+    gimp_convert_indexed ($image, 0, 256);
+    
+    # save image
+    my $filename = $filenamestem . "on.gif";
+    $filename = $filenamestem . "of.gif" if $off_img;
+    $filename = &util::filename_cat ($image_dir, $filename);
+
+    gimp_file_save (RUN_NONINTERACTIVE, $image, $finishedlayer, $filename, $filename);
+
+    &produce_images (1) unless $off_img;    
+}
+
+sub create_image {
+    my ($off_img) = @_;
+
+    # create the image
+    my $image = gimp_image_new ($width, $height, RGB_IMAGE);
+    
+    # background layer
+    my $backlayer = gimp_layer_new ($image, $width, $height, RGB_IMAGE, 
+				    "BGLayer", 100, NORMAL_MODE);
+    
+    # add the background layer
+    gimp_image_add_layer ($image, $backlayer, 0);
+    
+    # set colour of background
+    gimp_palette_set_foreground ($bgcolor);
+    
+    # clear the background
+    gimp_selection_all ($image);
+    gimp_edit_clear ($image, $backlayer);
+    gimp_selection_none ($image);
+    
+    # create the gradient background
+    gimp_blend ($image, $backlayer, 0, NORMAL_MODE, LINEAR, 70, 0, REPEAT_NONE, 0, 0, 0, 5, $height-3, 5, 0);
+    
+    # adjust lightness of "off" gif
+    gimp_hue_saturation ($image, $backlayer, 0, 0, 100, 0) if $off_img;
+
+    # set colour of text
+    gimp_palette_set_foreground ($fontcolor);
+
+    return ($image, $backlayer);
+}
+
+# returns 1 if this is the last entry,
+sub read_config_entry {
+    my ($handle) = @_;
+
+    my $line = "";
+    while (defined ($line = <$handle>)) {
+	next unless $line =~ /\w/;
+	my @line = ();
+	if ($line =~ /^\-+/) {return 0;}
+	$line =~ s/^\#.*$//;   # remove comments
+	$line =~ s/\cM|\cJ//g; # remove end-of-line characters
+	$line =~ s/^\s+//;     # remove initial white space
+	while ($line =~ s/\s*(\"[^\"]*\"|\'[^\']*\'|\S+)\s*//) {
+	    if (defined $1) {
+		# remove any enclosing quotes
+		my $entry = $1;
+		$entry =~ s/^([\"\'])(.*)\1$/$2/;
+
+		# substitute any environment variables
+		$entry =~ s/\$(\w+)/$ENV{$1}/g;
+		$entry =~ s/\$\{(\w+)\}/$ENV{$1}/g;
+		
+		push (@line, $entry);
+	    } else {
+		push (@line, "");
+	    }
+	}
+	if (scalar (@line) == 2 && defined ${$line[0]}) {
+	    ${$line[0]} = $line[1];
+	}
+    }
+    return 1;
+}
+    
+sub query {
+
+  gimp_install_procedure("gsdl_flash_button", "create flashy javascript buttons for gsdl",
+                        "", "Stefan Boddie", "Stefan Boddie", "2000-03-10",
+                        "<Toolbox>/Xtns/gsdl_flash_button", "*", &PROC_EXTENSION,
+                        [[PARAM_INT32, "run_mode", "Interactive, [non-interactive]"]], []);
+}
+
+sub net {
+  gsdl_flash_button;
+}
+
+exit main;
Index: /main/tags/2.25/gsdl/bin/script/gimp/green_bar.pl
===================================================================
--- /main/tags/2.25/gsdl/bin/script/gimp/green_bar.pl	(revision 21064)
+++ /main/tags/2.25/gsdl/bin/script/gimp/green_bar.pl	(revision 21064)
@@ -0,0 +1,296 @@
+#!/usr/bin/perl -w
+
+###########################################################################
+#
+# green_bar.pl 
+# A component of the Greenstone digital library software
+# from the New Zealand Digital Library Project at the 
+# University of Waikato, New Zealand.
+#
+# Copyright (C) 1999 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.
+#
+###########################################################################
+
+# green_bar.pl generates all the black on green gradient background
+# images used by Greenstone. 
+# these are the icons described in macro files as:
+# green version of nav_bar_button
+# green_bar_left_aligned
+
+BEGIN {
+    die "GSDLHOME not set\n" unless defined $ENV{'GSDLHOME'};
+    unshift (@INC, "$ENV{'GSDLHOME'}/perllib");
+}
+
+use Gimp;
+use parsargv;
+use util;
+
+# set trace level to watch functions as they are executed
+#Gimp::set_trace(TRACE_ALL);
+#Gimp::set_trace(TRACE_CALL);
+
+my $gsdl_green = "#96c19b";
+my $black = "#000000";
+
+my ($cfg_file, $width, $height, $text, $filename, $width_space, 
+    $dont_center, $bgcolor, $fontcolor, $fontsize, $fontname, 
+    $fontweight, $fontslant, $fontwidth, $fontspacing, $image_dir);
+
+sub print_usage {
+    print STDERR "\n  usage: $0 [options] macrofile\n\n";
+    print STDERR "  options:\n";
+    print STDERR "   -cfg_file file        configuration file containing one or more\n";
+    print STDERR "                         sets of the following options - use to create\n";
+    print STDERR "                         batches of images\n";
+    print STDERR "   -image_dir directory  directory to create images in [`pwd`]\n";
+    print STDERR "                         this should be full path to existing directory\n";
+    print STDERR "   -width number         width of bar [87]\n";
+    print STDERR "   -height number        height of bar [17]\n";
+    print STDERR "   -text string          icon text\n";
+    print STDERR "   -filename string      filename of resulting image\n";
+    print STDERR "   -width_space number   width in pixels of blank space to leave at left\n";
+    print STDERR "                         and right edges of text [1]\n";
+    print STDERR "   -dont_center          don't center text horizontally\n";
+    print STDERR "   -bgcolor hex_value    background color of bar [$gsdl_green]\n";
+    print STDERR "   -fontcolor hex_value  text color [$black]\n";
+    print STDERR "   -fontsize number      font point size [17]\n";
+    print STDERR "   -fontname string      [lucida]\n";
+    print STDERR "   -fontweight string    [medium]\n";
+    print STDERR "   -fontslant            [r]\n";
+    print STDERR "   -fontwidth            [*]\n";
+    print STDERR "   -fontspacing          [*]\n\n";
+}
+
+sub reset_options {
+    $image_dir = "./";
+    $width = 87;
+    $height = 17;
+    $text = "";
+    $filename = "";
+    $width_space = 1;
+    $dont_center = 0;
+    $bgcolor = $gsdl_green;
+    $fontcolor = $black;
+    $fontsize = 17;
+    $fontname = "lucida";
+    $fontweight = "medium";
+    $fontslant = "r";
+    $fontwidth = "*";
+    $fontspacing = "*";
+}
+
+sub gsdl_green_bar {
+
+    if (!parsargv::parse(\@ARGV, 
+			 'cfg_file/.*/', \$cfg_file,
+			 'image_dir/.*/./', \$image_dir,
+			 'width/^\d+$/87', \$width,
+			 'height/^\d+$/17', \$height,
+			 'text/.*/', \$text,
+			 'filename/.*', \$filename,
+			 'width_space/^\d+$/1', \$width_space,
+			 'dont_center', \$dont_center,
+			 "bgcolor/#[0-9A-Fa-f]{6}/$gsdl_green", \$bgcolor,
+			 "fontcolor/#[0-9A-Fa-f]{6}/$black", \$fontcolor,
+			 'fontsize/^\d+$/17', \$fontsize,
+			 'fontname/.*/lucida', \$fontname,
+			 'fontweight/.*/medium', \$fontweight,
+			 'fontslant/.*/r', \$fontslant,
+			 'fontwidth/.*/*', \$fontwidth,
+			 'fontspacing/.*/*', \$fontspacing)) {
+	&print_usage();
+	die "green_bar.pl: incorrect options\n";
+    }
+
+    # will create wherever gimp was started up from if we don't do this
+    if ($image_dir eq "./") {
+	$image_dir = `pwd`;
+	chomp $image_dir;
+    }
+    
+    if ($cfg_file =~ /\w/) {
+	
+	open (CONF, $cfg_file) || die "couldn't open cfg_file $cfg_file\n";
+	while (1) {
+
+	    &reset_options ();
+	
+	    # read image configuration entry
+	    my $status = &read_config_entry (CONF);
+	    if ($filename !~ /\w/) {
+		if ($status) {last;}
+		else {next;}
+	    }
+
+	    &produce_image ();
+	    if ($status) {last;}
+	}
+
+	close CONF;
+
+    } else {
+
+	&produce_image ();
+
+    }
+}
+
+sub produce_image {
+    
+    # create image, set background color etc.
+    my ($image, $backlayer) = &create_image ();
+    
+    # set the text if there is any
+    if (length($text)) {
+
+	my $textlayer = gimp_text ($image, $backlayer, 0, 0, $text, 0, 1, 
+				   $fontsize, PIXELS, "*", $fontname, $fontweight, 
+				   $fontslant, $fontwidth, $fontspacing);
+	
+
+	my $textwidth = gimp_drawable_width($textlayer);
+	my $textheight = gimp_drawable_height($textlayer);
+
+	# check that text fits within image
+	if ($textheight > $height) {
+	    die "'$text' at fontsize of $fontsize pixels does not fit within image\n" . 
+		"$height pixels high. Decrease fontsize or increase image height\n";
+	}
+
+	my $spacers = $width_space * 2;
+
+	if ($textwidth > $width) {
+
+	    print STDERR "WARNING (green_bar.pl): '$text' does not fit within $width pixel fixed width ";
+	    print STDERR "image. Image width was increased to ",$textwidth + $spacers, " pixels\n";
+	    
+	    $width = $textwidth + $spacers;
+
+	    # recreate image in new size
+	    ($image, $backlayer) = &create_image ();
+	    $textlayer = gimp_text ($image, $backlayer, 0, 0, $text, 0, 1, 
+				    $fontsize, PIXELS, "*", $fontname, $fontweight, 
+				    $fontslant, $fontwidth, $fontspacing);
+	    
+	}
+
+	my $y_offset = ($height-$textheight)-int($fontsize/5);
+	if ($text =~ /[gjpqy]/) {
+	    # descenders - put text at bottom of image, otherwise 
+	    # go for fontsize/5 pixels above bottom. This is kind of hacky 
+	    # and may need some playing with for different fonts/fontsizes
+	    $y_offset = $height-$textheight;
+	}
+
+	if ($dont_center) {
+	    # don't center text horizontally (start it width_space pixels from left edge)
+	    my $x_offset = $width_space;
+	    gimp_layer_set_offsets ($textlayer, $x_offset, $y_offset);
+	} else {
+	    gimp_layer_set_offsets ($textlayer, ($width-$textwidth)/2, $y_offset);
+	}
+    }
+    
+    # flatten the image
+    my $finishedlayer = gimp_image_flatten ($image);
+    
+    # make indexed colour 
+    gimp_convert_indexed ($image, 0, 256);
+    
+    # save image
+    $filename = &util::filename_cat ($image_dir, $filename);
+
+    gimp_file_save (RUN_NONINTERACTIVE, $image, $finishedlayer, $filename, $filename);
+
+}
+
+sub create_image {
+    # create the image
+    my $image = gimp_image_new ($width, $height, RGB_IMAGE);
+    
+    # background layer
+    my $backlayer = gimp_layer_new ($image, $width, $height, RGB_IMAGE, 
+				    "BGLayer", 100, NORMAL_MODE);
+    
+    # add the background layer
+    gimp_image_add_layer ($image, $backlayer, 0);
+    
+    # set colour of background
+    gimp_palette_set_foreground ($bgcolor);
+    
+    # clear the background
+    gimp_selection_all ($image);
+    gimp_edit_clear ($image, $backlayer);
+    gimp_selection_none ($image);
+    
+    # create the gradient background
+    gimp_blend ($image, $backlayer, 0, NORMAL_MODE, LINEAR, 70, 0, REPEAT_NONE, 0, 0, 0, 5, $height-3, 5, 0);
+
+    # set colour of text
+    gimp_palette_set_foreground ($fontcolor);
+
+    return ($image, $backlayer);
+}
+
+# returns 1 if this is the last entry,
+sub read_config_entry {
+    my ($handle) = @_;
+
+    my $line = "";
+    while (defined ($line = <$handle>)) {
+	next unless $line =~ /\w/;
+	my @line = ();
+	if ($line =~ /^\-+/) {return 0;}
+	$line =~ s/^\#.*$//;   # remove comments
+	$line =~ s/\cM|\cJ//g; # remove end-of-line characters
+	$line =~ s/^\s+//;     # remove initial white space
+	while ($line =~ s/\s*(\"[^\"]*\"|\'[^\']*\'|\S+)\s*//) {
+	    if (defined $1) {
+		# remove any enclosing quotes
+		my $entry = $1;
+		$entry =~ s/^([\"\'])(.*)\1$/$2/;
+
+		# substitute any environment variables
+		$entry =~ s/\$(\w+)/$ENV{$1}/g;
+		$entry =~ s/\$\{(\w+)\}/$ENV{$1}/g;
+		
+		push (@line, $entry);
+	    } else {
+		push (@line, "");
+	    }
+	}
+	if (scalar (@line) == 2 && defined ${$line[0]}) {
+	    ${$line[0]} = $line[1];
+	}
+    }
+    return 1;
+}
+    
+sub query {
+
+  gimp_install_procedure("gsdl_green_bar", "create green bar icons for gsdl",
+                        "", "Stefan Boddie", "Stefan Boddie", "2000-03-10",
+                        "<Toolbox>/Xtns/gsdl_green_bar", "*", &PROC_EXTENSION,
+                        [[PARAM_INT32, "run_mode", "Interactive, [non-interactive]"]], []);
+}
+
+sub net {
+  gsdl_green_bar;
+}
+
+exit main;
Index: /main/tags/2.25/gsdl/bin/script/gimp/title_icon.pl
===================================================================
--- /main/tags/2.25/gsdl/bin/script/gimp/title_icon.pl	(revision 21064)
+++ /main/tags/2.25/gsdl/bin/script/gimp/title_icon.pl	(revision 21064)
@@ -0,0 +1,394 @@
+#!/usr/bin/perl -w
+
+###########################################################################
+#
+# title_icon.pl 
+# A component of the Greenstone digital library software
+# from the New Zealand Digital Library Project at the 
+# University of Waikato, New Zealand.
+#
+# Copyright (C) 1999 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.
+#
+###########################################################################
+
+# title_icon.pl generates all the green_title type icons and 
+# collection icons for Greenstone
+
+BEGIN {
+    die "GSDLHOME not set\n" unless defined $ENV{'GSDLHOME'};
+    unshift (@INC, "$ENV{'GSDLHOME'}/perllib");
+}
+
+use Gimp;
+use parsargv;
+use util;
+
+# set trace level to watch functions as they are executed
+#Gimp::set_trace(TRACE_ALL);
+#Gimp::set_trace(TRACE_CALL);
+
+my $gsdl_green = "#96c19b";
+my $black = "#000000";
+
+
+local ($cfg_file, $size, $imagefile, $width, $height, $imageheight, $stripecolor, $stripewidth, 
+       $stripe_alignment, $i_transparency, $text, $text_alignment, $filename, $textspace_x, 
+       $textspace_y, $bgcolor, $fontcolor, $fontsize, $minfontsize, $fontname, 
+       $fontweight, $fontslant, $fontwidth, $fontspacing, $image_dir, $dont_wrap);
+
+sub print_usage {
+    print STDERR "\n  usage: $0 [options] macrofile\n\n";
+    print STDERR "  options:\n";
+    print STDERR "   -cfg_file file         configuration file containing one or more\n";
+    print STDERR "                          sets of the following options - use to create\n";
+    print STDERR "                          batches of images\n";
+    print STDERR "   -size number           the overall size ratio of the image (i.e. a size\n";
+    print STDERR "                          of 2 will create an image twice the default size)\n";
+    print STDERR "   -image_dir directory   directory to create images in [`pwd`]\n";
+    print STDERR "                          this should be full path to existing directory\n";
+    print STDERR "   -imagefile             filename of image to embed within new icon\n";
+    print STDERR "   -width number          width of icon [150]\n";
+    print STDERR "   -height number         height of icon [44]\n";
+    print STDERR "   -imageheight number    this is the height of the image if the image contains\n";
+    print STDERR "                          an image (like collection icons) [110]\n";
+    print STDERR "   -stripecolor hex_value color of vertical stripe [$gsdl_green]\n";
+    print STDERR "   -stripewidth           width of vertical stripe [40]\n";
+    print STDERR "   -stripe_alignment      alignment of vertical stripe (left or right) [left]\n";
+    print STDERR "   -i_transparency number transparency of image within icon (0 > transparent > 100) [60]\n"; 
+    print STDERR "   -text string           image text\n";
+    print STDERR "   -text_alignment        alignment of text (left or right) [left]\n";
+    print STDERR "   -filename string       filename of resulting image\n";
+    print STDERR "   -textspace_x number    space in pixels between left/right edge of image and\n";
+    print STDERR "                          left/right edge of text [3]\n";
+    print STDERR "   -textspace_y number    space in pixels between top of image and top of\n";
+    print STDERR "                          text [3]\n";
+    print STDERR "   -bgcolor hex_value     background color of icon [$gsdl_green]\n";
+    print STDERR "   -fontcolor hex_value   text color [$black]\n";
+    print STDERR "   -fontsize number       font point size [17]\n";
+    print STDERR "   -minfontsize number    minimum point size font will be reduced to fit image [10]\n";
+    print STDERR "   -fontname string       [lucida]\n";
+    print STDERR "   -fontweight string     [medium]\n";
+    print STDERR "   -fontslant             [r]\n";
+    print STDERR "   -fontwidth             [*]\n";
+    print STDERR "   -fontspacing           [*]\n";
+    print STDERR "   -dont_wrap             don't attempt to wrap text\n\n";
+}
+
+sub reset_options {
+    $image_dir = "./";
+    $imagefile = "";
+    $width = int (150 * $size);
+    $height = int (44 * $size);
+    $imageheight = int (110 * $size);
+    $stripecolor = $gsdl_green;
+    $stripewidth = int (40 * $size);
+    $stripe_alignment = "left";
+    $i_transparency = 60;
+    $text = "";
+    $text_alignment = "left";
+    $filename = "";
+    $textspace_x = int (3 * $size);
+    $textspace_y = int (3 * $size);
+    $bgcolor = $gsdl_green;
+    $fontcolor = $black;
+    $fontsize = int (17 * $size);
+    $minfontsize = int (10 * $size);
+    $fontname = "lucida";
+    $fontweight = "medium";
+    $fontslant = "r";
+    $fontwidth = "*";
+    $fontspacing = "*";
+}
+
+sub gsdl_title_icon {
+
+    if (!parsargv::parse(\@ARGV, 
+			 'cfg_file/.*/', \$cfg_file,
+			 'size/\d+/1', \$size,
+			 'image_dir/.*/./', \$image_dir,
+			 'imagefile/.*/', \$imagefile,
+			 'width/^\d+$/150', \$width,
+			 'height/^\d+$/44', \$height,
+			 'imageheight/^\d+$/110', \$imageheight,
+			 "stripecolor/#[0-9A-Fa-f]{6}/$gsdl_green", \$stripecolor,
+			 'stripewidth/^\d+$/40', \$stripewidth,
+			 'stripe_alignment/^(left|right)$/left', \$stripe_alignment,
+			 'i_transparency/^\d+$/60', \$i_transparency,
+			 'text/.*/', \$text,
+			 'text_alignment/^(left|right)$/left', \$text_alignment,
+			 'filename/.*', \$filename,
+			 'textspace_x/^\d+$/3', \$textspace_x,
+			 'textspace_y/^\d+$/3', \$textspace_y,
+			 "bgcolor/#[0-9A-Fa-f]{6}/$gsdl_green", \$bgcolor,
+			 "fontcolor/#[0-9A-Fa-f]{6}/$black", \$fontcolor,
+			 'fontsize/^\d+$/17', \$fontsize,
+			 'minfontsize/^\d+$/10', \$minfontsize,
+			 'fontname/.*/lucida', \$fontname,
+			 'fontweight/.*/medium', \$fontweight,
+			 'fontslant/.*/r', \$fontslant,
+			 'fontwidth/.*/*', \$fontwidth,
+			 'fontspacing/.*/*', \$fontspacing,
+			 'dont_wrap', \$dont_wrap)) {
+	&print_usage();
+	die "title_icon.pl: incorrect options\n";
+    }
+
+    # will create wherever gimp was started up from if we don't do this
+    if ($image_dir eq "./") {
+	$image_dir = `pwd`;
+	chomp $image_dir;
+    }
+
+    if ($cfg_file =~ /\w/) {
+	
+	open (CONF, $cfg_file) || die "couldn't open cfg_file $cfg_file\n";
+	while (1) {
+
+	    &reset_options ();
+	
+	    # read image configuration entry
+	    my $status = &read_config_entry (CONF);
+	    if ($filename !~ /\w/) {
+		if ($status) {last;}
+		else {next;}
+	    }
+
+	    &produce_image ();
+	    if ($status) {last;}
+	}
+
+	close CONF;
+
+    } else {
+
+	&produce_image ();
+
+    }
+}
+
+sub produce_image {
+
+    &adjust_args ();
+    &wrap_text () unless $dont_wrap;
+
+    my $use_image = 0;
+    if ($imagefile =~ /\w/) {
+	if (!-r $imagefile) {
+	    print STDERR "WARNING (title_icon.pl): imagefile '$imagefile cannot be ";
+	    print STDERR "read - $filename will be created without the use of an image file\n";
+	} else {
+	    $use_image = 1;
+	    $height = $imageheight;
+	}
+    }
+
+    # create the image
+    my $image = gimp_image_new ($width, $height, RGB_IMAGE);
+	
+    # background layer
+    my $backlayer = gimp_layer_new ($image, $width, $height, RGB_IMAGE, 
+				    "BGLayer", 100, NORMAL_MODE);
+	
+    # add the background layer
+    gimp_image_add_layer ($image, $backlayer, 0);
+	
+    # set colour of stripe
+    gimp_palette_set_foreground ($stripecolor);
+	
+    # clear the background
+    gimp_selection_all ($image);
+    gimp_edit_clear ($image, $backlayer);
+    gimp_selection_none ($image);
+	
+    # fill in stripe
+    if ($stripe_alignment eq "left") {
+	gimp_rect_select ($image, 0, 0, $stripewidth, $height, 0, 0, 0);
+    } else {
+	gimp_rect_select ($image, $width-$stripewidth, 0, $stripewidth, $height, 0, 0, 0);
+    }
+    gimp_bucket_fill ($image, $backlayer, FG_BUCKET_FILL, NORMAL_MODE, 100, 0, 1, 0, 0);
+    gimp_selection_none ($image);
+	
+    # get image file (image goes on opposite side to stripe)
+    if ($use_image) {
+	my $rimage = gimp_file_load (RUN_NONINTERACTIVE, $imagefile, $imagefile);
+	my $rdraw = gimp_image_active_drawable ($rimage);
+	gimp_scale ($rimage, $rdraw, 1, 0, 0, $width-$stripewidth, $height);
+	gimp_edit_copy ($rimage, $rdraw);
+	
+	my $imagelayer = gimp_layer_new ($image, $width, $height, RGB_IMAGE, 
+					 "ImageLayer", $i_transparency, NORMAL_MODE);
+	
+	gimp_image_add_layer ($image, $imagelayer, 0);
+	
+	# clear the new layer
+	gimp_selection_all ($image);
+	gimp_edit_clear ($image, $imagelayer);
+	gimp_selection_none ($image);
+	
+	my $flayer = gimp_edit_paste ($image, $imagelayer, 1); 
+	if ($stripe_alignment eq "left") {
+	    gimp_layer_set_offsets($flayer, $stripewidth, 0);
+	    gimp_layer_set_offsets($imagelayer, $stripewidth, 0);
+	} else {
+	    gimp_layer_set_offsets($flayer, 0, 0);
+	    gimp_layer_set_offsets($imagelayer, 0, 0);
+	}
+    }
+	
+    # set colour of text
+    gimp_palette_set_foreground ($fontcolor);
+	
+    # set the text if there is any
+    my ($textlayer, $textheight, $textwidth);
+    my $fsize = $fontsize;
+    if (length($text)) {
+	$text =~ s/\\n/\n/gi;
+	while (1) {
+	    $textlayer = gimp_text ($image, $backlayer, 0, 0, $text, 0, 1, $fsize, 
+				    PIXELS, "*", $fontname, $fontweight, $fontslant, 
+				    $fontwidth, $fontspacing);
+	    
+	    # check that text fits within image
+	    $textwidth = gimp_drawable_width($textlayer);
+	    $textheight = gimp_drawable_height($textlayer);
+	    if ((($textwidth + $textspace_x) > $width) || 
+		(($textheight + $textspace_y) > $height)) {
+		if ($fsize < $minfontsize) {
+		    die "Error (title_icon.pl): text '$text' doesn't fit on ${width}x${height} image " .
+			"(minimum font size tried: $minfontsize\n";
+		} else {
+		    gimp_selection_all ($image);
+		    gimp_edit_clear ($image, $textlayer);
+		    gimp_selection_none ($image);
+		    $fsize --;
+		    print STDERR "WARNING (title_icon.pl): '$text' doesn't fit: reducing font size to $fsize\n";
+		}
+	    } else {
+		last;
+	    }
+	}
+	
+	# align text
+	if ($text_alignment eq "left") {
+	    gimp_layer_set_offsets ($textlayer, $textspace_x, $textspace_y);
+	} else {
+	    gimp_layer_set_offsets ($textlayer, ($width-$textwidth)-$textspace_x, $textspace_y);
+	}
+    }
+    
+    # flatten the image
+    my $finishedlayer = gimp_image_flatten ($image);
+	
+    if ($filename =~ /\.gif$/i) {
+	# make indexed colour (may need to do this for 
+	# other formats as well as gif)
+	gimp_convert_indexed ($image, 0, 256);
+    }
+	
+    # save image
+    my $filename = &util::filename_cat ($image_dir, $filename);
+    if ($filename =~ /\.jpe?g$/i) {
+	# gimp_file_save doesn't appear to work properly for jpegs
+	file_jpeg_save (RUN_NONINTERACTIVE, $image, $finishedlayer, 
+			$filename, $filename, 0.8, 0, 1);
+    } else {
+	gimp_file_save (RUN_NONINTERACTIVE, $image, $finishedlayer, 
+			$filename, $filename);
+    }
+}
+
+# returns 1 if this is the last entry,
+sub read_config_entry {
+    my ($handle) = @_;
+
+    my $line = "";
+    while (defined ($line = <$handle>)) {
+	next unless $line =~ /\w/;
+	my @line = ();
+	if ($line =~ /^\-+/) {return 0;}
+	$line =~ s/^\#.*$//;   # remove comments
+	$line =~ s/\cM|\cJ//g; # remove end-of-line characters
+	$line =~ s/^\s+//;     # remove initial white space
+	while ($line =~ s/\s*(\"[^\"]*\"|\'[^\']*\'|\S+)\s*//) {
+	    if (defined $1) {
+		# remove any enclosing quotes
+		my $entry = $1;
+		$entry =~ s/^([\"\'])(.*)\1$/$2/;
+
+		# substitute any environment variables
+		$entry =~ s/\$(\w+)/$ENV{$1}/g;
+		$entry =~ s/\$\{(\w+)\}/$ENV{$1}/g;
+		
+		push (@line, $entry);
+	    } else {
+		push (@line, "");
+	    }
+	}
+	if (scalar (@line) == 2 && defined ${$line[0]}) {
+	    ${$line[0]} = $line[1];
+	}
+    }
+    return 1;
+}
+
+# adjust arguments that are effected by the size argument
+sub adjust_args {    
+
+    if ($size != 1) {
+	my @size_args = ('width', 'height', 'imageheight', 'stripewidth',
+			 'textspace_x', 'textspace_y', 'fontsize', 'minfontsize');
+	foreach $arg (@size_args) {
+	    $$arg = int ($$arg * $size);
+	}
+    }
+}
+
+sub wrap_text {
+
+    # don't wrap text if it already contains carriage returns
+    return if $text =~ /\n/;
+
+    # the following assumes that all words are less than $wrap_length long
+    my $wrap_length = 14;
+
+    my $new_text = "";
+    while (length ($text) >= $wrap_length) {
+	my $line = substr ($text, 0, $wrap_length);
+	$text =~ s/^$line//;
+	$line =~ s/\s([^\s]*)$/\n/;
+	$text = $1 . $text;
+	$new_text .= $line;
+    }
+    $new_text .= $text;
+    $text = $new_text;
+}
+    
+sub query {
+
+  gimp_install_procedure("gsdl_title_icon", "create title icons for gsdl",
+                        "", "Stefan Boddie", "Stefan Boddie", "2000-03-10",
+                        "<Toolbox>/Xtns/gsdl_title_icon", "*", &PROC_EXTENSION,
+                        [[PARAM_INT32, "run_mode", "Interactive, [non-interactive]"]], []);
+}
+
+sub net {
+  gsdl_title_icon;
+}
+
+exit main;
+
Index: /main/tags/2.25/gsdl/bin/script/gsdlinfo.pl
===================================================================
--- /main/tags/2.25/gsdl/bin/script/gsdlinfo.pl	(revision 21064)
+++ /main/tags/2.25/gsdl/bin/script/gsdlinfo.pl	(revision 21064)
@@ -0,0 +1,135 @@
+#!/usr/local/bin/perl5 -w
+
+###########################################################################
+#
+# gsdlinfo.pl --
+# A component of the Greenstone digital library software
+# from the New Zealand Digital Library Project at the 
+# University of Waikato, New Zealand.
+#
+# Copyright (C) 1999 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.
+#
+###########################################################################
+
+# This program will look to see what collections are installed
+# under this file system
+
+BEGIN {
+    die "GSDLHOME not set\n" unless defined $ENV{'GSDLHOME'};
+    unshift (@INC, "$ENV{'GSDLHOME'}/perllib");
+}
+
+use parsargv;
+use colcfg;
+
+
+# the collection information is stored as an array of hashes
+# (one hash for each collection). The hash contains all the 
+# information in the collect and build configuration files
+
+
+# read in all the collection configuration information
+
+opendir (DIR, "$ENV{'GSDLHOME'}/collect") ||
+    die "ERROR - couldn't read the directory $ENV{'GSDLHOME'}/collect\n";
+@dir = readdir (DIR);
+closedir (DIR);
+
+@collections = ();
+foreach $dir (@dir) {
+    if ($dir =~ /^(\..*|modelcol|CVS)$/) {
+	# do nothing
+
+    } else {
+	# read in the collection configuration file
+	my $collectcfg = {};
+	if (-e "$ENV{'GSDLHOME'}/collect/$dir/etc/collect.cfg") {
+	    $collectcfg = &colcfg::read_collect_cfg ("$ENV{'GSDLHOME'}/collect/$dir/etc/collect.cfg");
+	}
+	$collectcfg->{'collection'} = $dir;
+
+	# read in the build configuration file
+	my $buildcfg = {};
+	if (-e "$ENV{'GSDLHOME'}/collect/$dir/index/build.cfg") {
+	    $buildcfg = &colcfg::read_build_cfg ("$ENV{'GSDLHOME'}/collect/$dir/index/build.cfg");
+	}
+
+	# add the merged configuration files to the current list of collections
+	push (@collections, {%$collectcfg, %$buildcfg});
+    }
+}
+
+
+# do any sorting requested
+
+
+# print out the collection information
+
+# {'creator'}->string
+# {'maintainer'}->array of strings
+# {'public'}->string
+# {'beta'}->string
+# {'key'}->string
+# {'indexes'}->array of strings
+# {'defaultindex'}->string
+# {'builddate'}->string
+# {'metadata'}->array of strings
+# {'languages'}->array of strings
+# {'numdocs'}->string
+# {'numwords'}->string
+# {'numbytes'}->string
+
+print "\n";
+foreach $info (@collections) {
+    if (defined $info->{'collection'}) {
+	$collection = $info->{'collection'};
+	if (defined $info->{'public'}) {
+	    $public = $info->{'public'};
+	} else {
+	    $public = "?";
+	}
+	if (defined $info->{'beta'}) {
+	    $beta = $info->{'beta'};
+	} else {
+	    $beta = "?";
+	}
+	if (defined $info->{'numdocs'}) {
+	    $numdocs = $info->{'numdocs'};
+	} else {
+	    $numdocs = "?";
+	}
+	if (defined $info->{'numbytes'}) {
+	    $numMbytes = int(($info->{'numbytes'}/1024.0/1024.0)*1000)/1000.0;
+	} else {
+	    $numMbytes = "?";
+	}
+	write;
+    }
+}
+print "\n";
+
+exit;
+
+format STDOUT_TOP = 
+  name   public  beta   documents  size (Mbytes)
+-------- ------ ------ ----------- -------------
+.
+
+format STDOUT = 
+@>>>>>>> @>>>>> @>>>>> @>>>>>>>>>> @>>>>>>>>>>>>
+$collection, $public, $beta, $numdocs, $numMbytes
+.
Index: /main/tags/2.25/gsdl/bin/script/gsw3mir.pl
===================================================================
--- /main/tags/2.25/gsdl/bin/script/gsw3mir.pl	(revision 21064)
+++ /main/tags/2.25/gsdl/bin/script/gsw3mir.pl	(revision 21064)
@@ -0,0 +1,52 @@
+#!/usr/bin/perl -w
+
+###########################################################################
+#
+# urldownload.pl --
+# A component of the Greenstone digital library software
+# from the New Zealand Digital Library Project at the 
+# University of Waikato, New Zealand.
+#
+# Copyright (C) 1999 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.
+#
+###########################################################################
+
+
+# This program will download the specified urls (http:, ftp: and file:)
+
+
+BEGIN {
+    die "GSDLHOME not set\n" unless defined $ENV{'GSDLHOME'};
+    unshift (@INC, "$ENV{'GSDLHOME'}/perllib");
+
+    unshift (@INC, "$ENV{'GSDLHOME'}/perllib/cpan/lib");
+    $ENV{'PATH'} = "$ENV{'GSDLHOME'}/perllib/cpan/bin:$ENV{'PATH'}";
+}
+
+my @quoted_argv = map { "\"$_\"" } @ARGV;
+
+my $args = join(' ', @quoted_argv);
+$cmd = "w3mir $args";
+
+my $status = system($cmd);
+$status /= 256;
+if ($status != 0)
+{
+    print STDERR "Error: failed to execute $cmd\n";
+    exit($status);
+}
+
Index: /main/tags/2.25/gsdl/bin/script/import.pl
===================================================================
--- /main/tags/2.25/gsdl/bin/script/import.pl	(revision 21064)
+++ /main/tags/2.25/gsdl/bin/script/import.pl	(revision 21064)
@@ -0,0 +1,195 @@
+#!/usr/bin/perl -w
+
+###########################################################################
+#
+# import.pl --
+# A component of the Greenstone digital library software
+# from the New Zealand Digital Library Project at the 
+# University of Waikato, New Zealand.
+#
+# Copyright (C) 1999 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.
+#
+###########################################################################
+
+
+# This program will import a number of files into a particular collection
+
+BEGIN {
+    die "GSDLHOME not set\n" unless defined $ENV{'GSDLHOME'};
+    die "GSDLOS not set\n" unless defined $ENV{'GSDLOS'};
+    unshift (@INC, "$ENV{'GSDLHOME'}/perllib");
+    unshift (@INC, "$ENV{'GSDLHOME'}/perllib/plugins");
+    unshift (@INC, "$ENV{'GSDLHOME'}/perllib/classify");
+}
+
+use strict;
+use arcinfo;
+use colcfg;
+use plugin;
+use docprint;
+use util;
+use parsargv;
+
+sub print_usage {
+    print STDERR "\n  usage: $0 [options] collection-name\n\n";
+    print STDERR "  options:\n";
+    print STDERR "   -verbosity number      0=none, 3=lots\n";
+    print STDERR "   -importdir directory   Where the original material lives\n";
+    print STDERR "   -archivedir directory  Where the converted material ends up\n";
+    print STDERR "   -keepold               Will not destroy the current contents of the\n";
+    print STDERR "                          archives directory (the default)\n";
+    print STDERR "   -removeold             Will remove the old contents of the archives\n";
+    print STDERR "                          directory -- use with care\n";
+    print STDERR "   -gzip                  Use gzip to compress resulting gml documents\n";
+    print STDERR "                          (don't forget to include ZIPPlug in your plugin\n";
+    print STDERR "                          list when building from compressed documents)\n";
+    print STDERR "   -maxdocs number        Maximum number of documents to import\n";
+    print STDERR "   -groupsize number      Number of GML documents to group into one file\n";
+    print STDERR "   -sortmeta metadata     Sort documents alphabetically by metadata for\n";
+    print STDERR "                          building. This will be disabled if groupsize > 1\n";
+    print STDERR "   -debug                 Print imported text to STDOUT\n\n";
+}
+
+
+&main ();
+
+sub main {
+    my ($verbosity, $importdir, $archivedir, $keepold, 
+	$removeold, $gzip, $groupsize, $debug, $maxdocs, $collection,
+	$configfilename, $collectcfg, $pluginfo, $sortmeta,
+	$archive_info_filename, $archive_info, $processor);
+    if (!parsargv::parse(\@ARGV, 
+			 'verbosity/\d+/2', \$verbosity,
+			 'importdir/.*/', \$importdir,
+			 'archivedir/.*/', \$archivedir,
+			 'keepold', \$keepold,
+			 'removeold', \$removeold,
+			 'gzip', \$gzip,
+			 'groupsize/\d+/1', \$groupsize,
+			 'sortmeta/.*/', \$sortmeta,
+			 'debug', \$debug,
+			 'maxdocs/^\-?\d+/-1', \$maxdocs)) {
+	&print_usage();
+	die "\n";
+    }
+
+    # set removeold to false if it has been defined
+    $removeold = 0 if ($keepold);
+
+    # get and check the collection name
+    if (($collection = &util::use_collection(@ARGV)) eq "") {
+	&print_usage();
+	die "\n";
+    }
+
+    # check sortmeta
+    $sortmeta = undef unless defined $sortmeta && $sortmeta =~ /\S/;
+    if (defined $sortmeta && $groupsize > 1) {
+	print STDERR "WARNING: import.pl cannot sort documents when groupsize > 1\n";
+	print STDERR "         sortmeta option will be ignored\n\n";
+	$sortmeta = undef;
+    }
+
+    # dynamically load 'docsave' module so it can pick up on a collection
+    # specific docsave.pm is specified.
+
+    unshift (@INC, "$ENV{'GSDLCOLLECTDIR'}/perllib");
+    require docsave;
+
+
+    # get the list of plugins for this collection
+    my $plugins = [];
+    $configfilename = &util::filename_cat ($ENV{'GSDLCOLLECTDIR'}, "etc/collect.cfg");
+    if (-e $configfilename) {
+	$collectcfg = &colcfg::read_collect_cfg ($configfilename);
+	if (defined $collectcfg->{'plugin'}) {
+	    $plugins = $collectcfg->{'plugin'};
+	}
+	if (defined $collectcfg->{'importdir'} && $importdir eq "") {
+	    $importdir = $collectcfg->{'importdir'};
+	}
+	if (defined $collectcfg->{'archivedir'} && $archivedir eq "") {
+	    $archivedir = $collectcfg->{'archivedir'};
+	}
+	if (defined $collectcfg->{'removeold'}) {
+	    if ($collectcfg->{'removeold'} =~ /^true$/i && !$keepold) {
+		$removeold = 1;
+	    }
+	    if ($collectcfg->{'removeold'} =~ /^false$/i && !$removeold) {
+		$removeold = 0;
+	    }
+	}
+    } else {
+	die "Couldn't find the configuration file $configfilename\n";
+    }
+    
+    # fill in the default import and archives directories if none
+    # were supplied, turn all \ into / and remove trailing /
+    $importdir = "$ENV{'GSDLCOLLECTDIR'}/import" if $importdir eq "";
+    $importdir =~ s/[\\\/]+/\//g;
+    $importdir =~ s/\/$//;
+    $archivedir = "$ENV{'GSDLCOLLECTDIR'}/archives" if $archivedir eq "";
+    $archivedir =~ s/[\\\/]+/\//g;
+    $archivedir =~ s/\/$//;
+
+    # load all the plugins
+    $pluginfo = &plugin::load_plugins ($plugins, $verbosity);
+    if (scalar(@$pluginfo) == 0) {
+	print STDERR "No plugins were loaded.\n";
+	die "\n";
+    }
+	
+    # remove the old contents of the archives directory if needed
+    if ($removeold && -e $archivedir) {
+	print STDERR "Warning - removing current contents of the archives directory\n";
+	print STDERR "          in preparation for the import\n";
+	sleep(5); # just in case...
+	&util::rm_r ($archivedir);
+    }
+    
+    # read the archive information file
+    if (!$debug) {
+	$archive_info_filename = &util::filename_cat ($archivedir, "archives.inf");
+	$archive_info = new arcinfo ();
+	$archive_info->load_info ($archive_info_filename);
+
+	# create a docsave object to process the documents
+	$processor = new docsave ($collection, $archive_info, $verbosity, $gzip, $groupsize);
+	$processor->setarchivedir ($archivedir);
+	$processor->set_sortmeta ($sortmeta) if defined $sortmeta;
+    } else {
+	$processor = new docprint ();
+    }
+
+    &plugin::begin($pluginfo, $importdir, $processor, $maxdocs);
+
+    # process the import directory
+    &plugin::read ($pluginfo, $importdir, "", {}, $processor, $maxdocs);
+    
+    &plugin::end($pluginfo);
+    
+    # write out the archive information file
+    if (!$debug) {
+	$processor->close_file_output() if $groupsize > 1;
+	$archive_info->save_info($archive_info_filename);
+    }
+}
+
+
+
+
+
Index: /main/tags/2.25/gsdl/bin/script/mgppbuildcol.pl
===================================================================
--- /main/tags/2.25/gsdl/bin/script/mgppbuildcol.pl	(revision 21064)
+++ /main/tags/2.25/gsdl/bin/script/mgppbuildcol.pl	(revision 21064)
@@ -0,0 +1,188 @@
+#!/usr/bin/perl -w
+
+###########################################################################
+#
+# mgppbuildcol.pl -- This program will build a particular collection
+# incorporates mgpp.
+# A component of the Greenstone digital library software
+# from the New Zealand Digital Library Project at the 
+# University of Waikato, New Zealand.
+#
+# Copyright (C) 1999 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.
+#
+###########################################################################
+
+BEGIN {
+    die "GSDLHOME not set\n" unless defined $ENV{'GSDLHOME'};
+    die "GSDLOS not set\n" unless defined $ENV{'GSDLOS'};
+    unshift (@INC, "$ENV{'GSDLHOME'}/perllib");
+    unshift (@INC, "$ENV{'GSDLHOME'}/perllib/plugins");
+}
+    #$ENV{'PATH'} = "$ENV{'GSDLHOME'}/src/mgpp/text:".$ENV{'PATH'};
+
+use colcfg;
+use parsargv;
+use util;
+
+&main();
+
+sub print_usage {
+    print STDERR "\n  usage: $0 [options] collection-name\n\n";
+    print STDERR "  options:\n";
+    print STDERR "   -verbosity number     0=none, 3=lots\n";
+    print STDERR "   -archivedir directory Where the archives live\n";
+    print STDERR "   -cachedir directory   Where to cache the archives\n";
+    print STDERR "   -builddir directory   Where to put the built indexes\n";
+    print STDERR "   -maxdocs number       Maximum number of documents to build\n";
+    print STDERR "   -debug                Print output to STDOUT\n";
+    print STDERR "   -mode all|compress_text|build_index|infodb\n";
+    print STDERR "   -index indexname      Index to build (will build all in\n"; 
+    print STDERR "                         config file if not set)\n";
+    print STDERR "   -keepold              will not destroy the current contents of the\n";
+    print STDERR "                         building directory\n";
+    print STDERR "   -allclassifications   Don't remove empty classifications\n\n";
+}
+
+
+sub main
+{
+    my ($verbosity, $archivedir, $cachedir, $builddir, $maxdocs, 
+	$debug, $mode, $indexname, $keepold, $allclassifications);
+    if (!parsargv::parse(\@ARGV, 
+			 'verbosity/\d+/2', \$verbosity,
+			 'archivedir/.*/', \$archivedir,
+			 'cachedir/.*/', \$cachedir,
+			 'builddir/.*/', \$builddir,
+			 'maxdocs/^\-?\d+/-1', \$maxdocs,
+			 'debug', \$debug,
+			 'mode/^(all|compress_text|build_index|infodb)$/all', \$mode,
+			 'index/.*/', \$indexname,
+			 'keepold', \$keepold,
+			 'allclassifications', \$allclassifications)) {
+	&print_usage();
+	die "\n";
+    }
+
+    # get and check the collection
+    # this sets up GSDLCOLLECTION (eg demo) and GSDLCOLLECTDIR (eg
+    # GSDLHOME/collect/demo )
+    if (($collection = &util::use_collection(@ARGV)) eq "") {
+	&print_usage();
+	die "\n";
+    }
+
+    # read the configuration file
+    $textindex = "text";
+    $configfilename = &util::filename_cat ($ENV{'GSDLCOLLECTDIR'}, "etc/collect.cfg");
+    if (-e $configfilename) {
+	$collectcfg = &colcfg::read_collect_cfg ($configfilename);
+	if (defined $collectcfg->{'textcompress'}) {
+	    $textindex = $collectcfg->{'textcompress'};
+	}
+	if (defined $collectcfg->{'archivedir'} && $archivedir eq "") {
+	    $archivedir = $collectcfg->{'archivedir'};
+	}
+	if (defined $collectcfg->{'cachedir'} && $cachedir eq "") {
+	    $cachedir = $collectcfg->{'cachedir'};
+	}
+	if (defined $collectcfg->{'builddir'} && $builddir eq "") {
+	    $builddir = $collectcfg->{'builddir'};
+	}
+    } else {
+	die "Couldn't find the configuration file $configfilename\n";
+    }
+    
+    # fill in the default archives and building directories if none
+    # were supplied, turn all \ into / and remove trailing /
+    $archivedir = "$ENV{'GSDLCOLLECTDIR'}/archives" if $archivedir eq "";
+    $archivedir =~ s/[\\\/]+/\//g;
+    $archivedir =~ s/\/$//;
+    $builddir = "$ENV{'GSDLCOLLECTDIR'}/building" if $builddir eq "";
+    $builddir =~ s/[\\\/]+/\//g;
+    $builddir =~ s/\/$//;
+
+    # update the archive cache if needed
+    if ($cachedir) {
+	print STDERR "Updating archive cache\n" if ($verbosity >= 1);
+
+	$cachedir =~ s/[\\\/]+$//;
+	$cachedir .= "/collect/$collection" unless 
+	    $cachedir =~ /collect\/$collection/;
+
+	$realarchivedir = "$cachedir/archives";
+	$realbuilddir = "$cachedir/building";
+	&util::mk_all_dir ($realarchivedir);
+	&util::mk_all_dir ($realbuilddir);
+	&util::cachedir ($archivedir, $realarchivedir, $verbosity);
+
+    } else {
+	$realarchivedir = $archivedir;
+	$realbuilddir = $builddir;
+    }
+
+    # build it in realbuilddir
+    &util::mk_all_dir ($realbuilddir);
+
+
+    # if a builder class has been created for this collection, use it
+    # otherwise, use the mg builder
+    if (-e "$ENV{'GSDLCOLLECTDIR'}/perllib/${collection}builder.pm") {
+	$builderdir = "$ENV{'GSDLCOLLECTDIR'}/perllib";
+	$buildertype = "${collection}builder";
+    } else {
+	$builderdir = "$ENV{'GSDLHOME'}/perllib";
+	$buildertype = "mgppbuilder";
+    }
+	
+    require "$builderdir/$buildertype.pm";
+
+    eval("\$builder = new $buildertype(\$collection, " .
+	 "\$realarchivedir, \$realbuilddir, \$verbosity, " .
+	 "\$maxdocs, \$debug, \$keepold, \$allclassifications)");
+    die "$@" if $@;
+
+    $builder->init();
+
+
+    print STDERR "text index=$textindex, indexname= $indexname\n";
+    if ($mode =~ /^all$/i) {
+#	$builder->build_collection($textindex, $indexname);
+	$builder->compress_text($textindex);
+	$builder->build_indexes($indexname);
+	$builder->make_infodatabase();
+	$builder->collect_specific();
+    } elsif ($mode =~ /^compress_text$/i) {
+	$builder->compress_text($textindex);
+    } elsif ($mode =~ /^build_index$/i) {
+	$builder->build_indexes($indexname);	
+    } elsif ($mode =~ /^infodb$/i) {
+	$builder->make_infodatabase();
+    } else {
+	die "unknown mode: $mode\n";
+    }
+
+    $builder->make_auxiliary_files() if !$debug;
+    $builder->deinit();
+    
+    if (($realbuilddir ne $builddir) && !$debug) {
+	print STDERR "Copying back the cached build\n" if ($verbosity >= 1);
+	&util::rm_r ($builddir);
+	&util::cp_r ($realbuilddir, $builddir);
+    }
+}
+
+
Index: /main/tags/2.25/gsdl/bin/script/mirror.pl
===================================================================
--- /main/tags/2.25/gsdl/bin/script/mirror.pl	(revision 21064)
+++ /main/tags/2.25/gsdl/bin/script/mirror.pl	(revision 21064)
@@ -0,0 +1,122 @@
+#!/usr/bin/perl -w
+
+###########################################################################
+#
+# mirror.pl
+#
+# A component of the Greenstone digital library software
+# from the New Zealand Digital Library Project at the 
+# University of Waikato, New Zealand.
+#
+# Copyright (C) 1999 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.
+#
+###########################################################################
+
+
+# This program uses w3mirror to mirror a web site.  It looks for a
+# w3mirror configuration file in etc/w3mir.cfg, and if it finds one then
+# it runs w3mirror (using this configuration file) in the import
+# directory.  Afterwards, a mirror of the web site (as dictated by the 
+# configuration file) will be in the import directory.
+
+BEGIN {
+    die "GSDLHOME not set\n" unless defined $ENV{'GSDLHOME'};
+    die "GSDLOS not set\n" unless defined $ENV{'GSDLOS'};
+    unshift (@INC, "$ENV{'GSDLHOME'}/perllib");
+    unshift (@INC, "$ENV{'GSDLHOME'}/perllib/plugins");
+    unshift (@INC, "$ENV{'GSDLHOME'}/perllib/classify");
+}
+
+use strict;
+use arcinfo;
+use colcfg;
+use plugin;
+use docprint;
+use util;
+use parsargv;
+
+sub print_usage {
+    print STDERR "\n  usage: $0 [options] collection-name\n\n";
+    print STDERR "  options:\n";
+    print STDERR "   -verbosity number      0=none, 3=lots\n";
+    print STDERR "   -importdir directory   Where to place the mirrored material\n";
+}
+
+
+&main ();
+
+sub main {
+    my ($verbosity, $importdir, $etcdir, 
+        $collection, $configfilename, $collectcfg);
+
+    if (!parsargv::parse(\@ARGV, 
+			 'verbosity/\d+/2', \$verbosity,
+			 'importdir/.*/', \$importdir )) {
+	&print_usage();
+	die "\n";
+    }
+
+    # get and check the collection name
+    if (($collection = &util::use_collection(@ARGV)) eq "") {
+	&print_usage();
+	die "\n";
+    }
+
+    # check the configuration file for options
+    my $interval = 0;
+    $configfilename = &util::filename_cat ($ENV{'GSDLCOLLECTDIR'}, "etc/collect.cfg");
+    if (-e $configfilename) {
+	$collectcfg = &colcfg::read_collect_cfg ($configfilename);
+	if (defined $collectcfg->{'importdir'} && $importdir eq "") {
+	    $importdir = $collectcfg->{'importdir'};
+	}
+    } else {
+	die "Couldn't find the configuration file $configfilename\n";
+    }
+    
+    # fill in the default import directories if none
+    # were supplied, turn all \ into / and remove trailing /
+    $importdir = "$ENV{'GSDLCOLLECTDIR'}/import" if $importdir eq "";
+    $importdir =~ s/[\\\/]+/\//g;
+    $importdir =~ s/\/$//;
+
+    $etcdir = "$ENV{'GSDLCOLLECTDIR'}/etc";
+
+    print "import directory: $importdir\n";
+    print "   w3config file: $etcdir/w3mir.cfg\n\n";
+
+    # make sure there is an import directory
+    if (! -e "$importdir") {
+	&util::mk_dir($importdir);
+    }
+
+    # make sure there is a w3mir file
+    if (! -e "$etcdir/w3mir.cfg") {
+	die "Couldn't find the w3mir configuration file $etcdir/w3mir.cfg\n";
+    }
+
+    # run the mirror program from the import directory
+    my  $command = "cd $importdir; gsw3mir.pl -cfgfile $etcdir/w3mir.cfg\n";
+    # print "\n$command\n";
+    `$command`;
+
+}
+
+
+
+
+
Index: /main/tags/2.25/gsdl/bin/script/mkcol.pl
===================================================================
--- /main/tags/2.25/gsdl/bin/script/mkcol.pl	(revision 21064)
+++ /main/tags/2.25/gsdl/bin/script/mkcol.pl	(revision 21064)
@@ -0,0 +1,224 @@
+#!/usr/bin/perl -w
+
+###########################################################################
+#
+# mkcol.pl --
+# A component of the Greenstone digital library software
+# from the New Zealand Digital Library Project at the 
+# University of Waikato, New Zealand.
+#
+# Copyright (C) 1999 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.
+#
+###########################################################################
+
+
+# This program will setup a new collection from a model one. It does this by
+# copying the model, moving files to have the correct names, and replacing
+# text within the files to match the parameters.
+
+BEGIN {
+    die "GSDLHOME not set\n" unless defined $ENV{'GSDLHOME'};
+    unshift (@INC, "$ENV{'GSDLHOME'}/perllib");
+}
+
+use parsargv;
+
+sub print_usage {
+    print STDERR "\n  usage: $0 [options] collection-name\n\n";
+    print STDERR "  options:\n";
+    print STDERR "   -creator email      Your email address\n";
+    print STDERR "   -maintainer email   The current maintainer's email address\n";
+    print STDERR "   -public true|false  If this collection has anonymous access\n";
+    print STDERR "   -beta true|false    If this collection is still under development\n";
+#    print STDERR "   -index type         The indexes which should be made\n";
+#    print STDERR "   -indextext name     The index description\n";
+#    print STDERR "   -defaultindex type  The index to use if no others are supplied\n";
+
+    print STDERR "   -title text         The title for the collection\n";
+    print STDERR "   -about text         The about text for the collection\n";
+    print STDERR "   -plugin text        perl plugin module to use (there may be multiple\n";
+    print STDERR "                       plugin entries\n";
+    print STDERR "   -refine   list      Space separated list of perl plugin modules to use\n";
+
+
+}
+
+sub traverse_dir
+{
+    my ($modeldir, $coldir) = @_;
+    my ($newfile, @filetext);
+
+    if (!(-e $coldir)) {
+
+	my $store_umask = umask(0002);
+	my $mkdir_ok = mkdir ($coldir, 0777);
+	umask($store_umask);
+
+	if (!$mkdir_ok) 
+	{
+	    die "$!";
+	}
+    }
+
+    opendir(DIR, $modeldir) || die "Can't read $modeldir";
+    my @files = grep(!/^(\.\.?|CVS)$/, readdir(DIR));
+    closedir(DIR);
+
+    foreach $file (@files)
+    {
+	if (-d "$modeldir/$file") {
+	    traverse_dir ("$modeldir/$file", "$coldir/$file");
+
+	} else {
+	    my $destfile = $file;
+	    $destfile =~ s/^\modelcol/$collection/;
+	    $destfile =~ s/^\MODELCOL/$capcollection/;
+
+	    print STDERR "doing replacements for $modeldir/$file\n";
+	    open (INFILE, "$modeldir/$file") || 
+		die "Can't read file $modeldir/$file";
+	    open (OUTFILE, ">$coldir/$destfile") ||
+		die "Can't create file $coldir/destfile";
+
+	    while (defined ($line = <INFILE>)) {
+		$line =~ s/\*\*collection\*\*/$collection/g;
+		$line =~ s/\*\*COLLECTION\*\*/$capcollection/g;
+		$line =~ s/\*\*creator\*\*/$creator/g;
+		$line =~ s/\*\*maintainer\*\*/$maintainer/g;
+		$line =~ s/\*\*public\*\*/$public/g;
+		$line =~ s/\*\*beta\*\*/$beta/g;
+		$line =~ s/\*\*indexes\*\*/$indexesstr/g;
+		$line =~ s/\*\*indexestext\*\*/$indexestextstr/g;
+		$line =~ s/\*\*defaultindex\*\*/$defaultindex/g;
+		$line =~ s/\*\*title\*\*/$title/g;
+		$line =~ s/\*\*about\*\*/$about/g;
+		$line =~ s/\*\*plugins\*\*/$pluginstring/g;
+		$line =~ s/\*\*refine\*\*/$refine/g;
+
+		print OUTFILE $line;
+	    }
+	    
+	    close (OUTFILE);
+	    close (INFILE);
+	}
+    }
+}
+
+
+my (@indexes, @indexestext, @plugin);
+
+# get and check options
+if (!&parsargv::parse(\@ARGV,
+		       'creator/\w+\@[\w\.]+/', \$creator,
+		       'maintainer/\w+\@[\w\.]+/', \$maintainer,
+		       'public/true|false/true', \$public,
+		       'beta/true|false/true', \$beta,
+		       'index/.*/document:all', \@indexes,
+		       'indextext/\.*/Terms must appear within the same document', \@indexestext,
+		       'defaultindex/.*/document:all', \$defaultindex,
+		       'title/.+/', \$title,
+		       'about/.+/', \$about,
+		       'plugin/.+', \@plugin,
+		       'refine/.+/', \$refine
+		       )) {
+    &print_usage();
+    die "\n";
+}
+
+# load default plugins if none were on command line    
+if (!scalar(@plugin)) {
+    @plugin = (GMLPlug,TEXTPlug,ArcPlug,RecPlug);
+}
+
+# get and check the collection name
+($collection) = @ARGV;
+if (!defined($collection)) {
+    &print_usage();
+    die "\n";
+}
+
+if (length($collection) > 8) {
+    print STDERR "The collection name must be less than 8 characters\n";
+    print STDERR "so compatibility with earlier filesystems can be\n";
+    print STDERR "maintained.\n";
+    die "\n";
+}
+
+if ($collection eq "modelcol") {
+    print STDERR "No collection can be named modelcol as this is the\n";
+    print STDERR "name of the model collection.\n";
+    die "\n";
+}
+
+if ($collection eq "CVS") {
+    print STDERR "No collection can be named CVS as this may interfere\n";
+    print STDERR "with directories created by the CVS versioning system\n";
+    die "\n";
+}
+
+if (!defined($creator) || $creator eq "") {
+    print STDERR "The creator was not defined. This variable is\n";
+    print STDERR "needed to recognise duplicate collection names.\n";
+    die "\n";
+}
+
+if (!defined($maintainer) || $maintainer eq "") {
+    $maintainer = $creator;
+}
+
+$public = "true" unless defined $public;
+$beta = "true" unless defined $beta;
+
+
+if (!defined($title) || $title eq "") {
+    $title = $collection;
+}
+
+# get capitalised version of the collection
+$capcollection = $collection;
+$capcollection =~ tr/a-z/A-Z/;
+
+
+# get the strings to include.
+$indexesstr = join ("\t", @indexes);
+$indexestextstr = "";
+for ($i=0; $i<scalar(@indexestext); $i++) {
+    $indexestextstr .= "_$indexes[$i]_[] {$indexestext[$i]}\n";
+}
+
+$pluginstring = "";
+foreach $plugin (@plugin) {
+    $pluginstring .= "plugin         $plugin\n";
+}
+
+# make sure the model collection exists
+die "Cannot find the model collection $ENV{'GSDLHOME'}/collect/modelcol" unless
+    (-d "$ENV{'GSDLHOME'}/collect/modelcol");
+
+# make sure this collection does not already exist
+if (-e "$ENV{'GSDLHOME'}/collect/$collection") {
+    print STDERR "This collection already exists\n";
+    die "\n";
+}
+
+
+# start creating the collection
+print STDERR "Creating the collection $collection\n\n";
+&traverse_dir ("$ENV{'GSDLHOME'}/collect/modelcol", "$ENV{'GSDLHOME'}/collect/$collection");
+print STDERR "\n\nThe new collection is in $ENV{'GSDLHOME'}/collect/$collection.\n\n";
+
+
Index: /main/tags/2.25/gsdl/bin/script/newsrc.pl
===================================================================
--- /main/tags/2.25/gsdl/bin/script/newsrc.pl	(revision 21064)
+++ /main/tags/2.25/gsdl/bin/script/newsrc.pl	(revision 21064)
@@ -0,0 +1,118 @@
+#!/usr/bin/perl -w
+
+###########################################################################
+#
+# newsrc.pl -- creates new blank source files
+# A component of the Greenstone digital library software
+# from the New Zealand Digital Library Project at the 
+# University of Waikato, New Zealand.
+#
+# Copyright (C) 1999 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.
+#
+###########################################################################
+
+foreach $filename (@ARGV) {
+    if (-e "$filename.cpp") {
+	print STDERR "$filename.cpp already exists\n";
+	next;
+    }
+    if (-e "$filename.h") {
+	print STDERR "$filename.h already exists\n";
+	next;
+    }
+
+    $upperfilename = $filename;
+    $upperfilename =~ tr/a-z/A-Z/;
+    $upperfilename =~ s/[^A-Z]/_/g;
+
+    print STDERR "Creating $filename.cpp\n";
+
+    open (CPPFILE, ">$filename.cpp") || die "Couldn't write $filename.cpp";
+    
+    print CPPFILE "/**********************************************************************\n";
+    print CPPFILE " *\n";
+    print CPPFILE " * $filename.cpp -- \n";
+    print CPPFILE " * A component of the Greenstone digital library software\n";
+    print CPPFILE " * from the New Zealand Digital Library Project at the\n";
+    print CPPFILE " * University of Waikato, New Zealand.\n";
+    print CPPFILE " *\n";
+    print CPPFILE " * Copyright (C) 2000  The New Zealand Digital Library Project\n";
+    print CPPFILE " *\n";
+    print CPPFILE " * This program is free software; you can redistribute it and/or modify\n";
+    print CPPFILE " * it under the terms of the GNU General Public License as published by\n";
+    print CPPFILE " * the Free Software Foundation; either version 2 of the License, or\n";
+    print CPPFILE " * (at your option) any later version.\n";
+    print CPPFILE " *\n";
+    print CPPFILE " * This program is distributed in the hope that it will be useful,\n";
+    print CPPFILE " * but WITHOUT ANY WARRANTY; without even the implied warranty of\n";
+    print CPPFILE " * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n";
+    print CPPFILE " * GNU General Public License for more details.\n";
+    print CPPFILE " *\n";
+    print CPPFILE " * You should have received a copy of the GNU General Public License\n";
+    print CPPFILE " * along with this program; if not, write to the Free Software\n";
+    print CPPFILE " * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.\n";
+    print CPPFILE " *\n";
+    print CPPFILE " *********************************************************************/\n";
+    print CPPFILE "\n";
+    print CPPFILE "\n";
+    print CPPFILE "#include \"$filename.h\"\n";
+    print CPPFILE "\n";
+
+    close (CPPFILE);
+
+
+    print STDERR "Creating $filename.h\n";
+
+    open (HFILE, ">$filename.h") || die "Couldn't write $filename.h";
+
+    print HFILE "/**********************************************************************\n";
+    print HFILE " *\n";
+    print HFILE " * $filename.h -- \n";
+    print HFILE " * A component of the Greenstone digital library software\n";
+    print HFILE " * from the New Zealand Digital Library Project at the\n";
+    print HFILE " * University of Waikato, New Zealand.\n";
+    print HFILE " *\n";
+    print HFILE " * Copyright (C) 2000  The New Zealand Digital Library Project\n";
+    print HFILE " *\n";
+    print HFILE " * This program is free software; you can redistribute it and/or modify\n";
+    print HFILE " * it under the terms of the GNU General Public License as published by\n";
+    print HFILE " * the Free Software Foundation; either version 2 of the License, or\n";
+    print HFILE " * (at your option) any later version.\n";
+    print HFILE " *\n";
+    print HFILE " * This program is distributed in the hope that it will be useful,\n";
+    print HFILE " * but WITHOUT ANY WARRANTY; without even the implied warranty of\n";
+    print HFILE " * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n";
+    print HFILE " * GNU General Public License for more details.\n";
+    print HFILE " *\n";
+    print HFILE " * You should have received a copy of the GNU General Public License\n";
+    print HFILE " * along with this program; if not, write to the Free Software\n";
+    print HFILE " * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.\n";
+    print HFILE " *\n";
+    print HFILE " *********************************************************************/\n";
+    print HFILE "\n";
+    print HFILE "\n";
+    print HFILE "\#ifndef ${upperfilename}_H\n";
+    print HFILE "\#define ${upperfilename}_H\n";
+    print HFILE "\n";
+    print HFILE "\n";
+    print HFILE "\n";
+    print HFILE "\n";
+    print HFILE "\#endif\n";
+
+    close (HFILE);
+}
+
Index: /main/tags/2.25/gsdl/bin/script/nightly.pl
===================================================================
--- /main/tags/2.25/gsdl/bin/script/nightly.pl	(revision 21064)
+++ /main/tags/2.25/gsdl/bin/script/nightly.pl	(revision 21064)
@@ -0,0 +1,106 @@
+#!/usr/bin/perl -w
+
+###########################################################################
+#
+# nightly.pl
+#
+# A component of the Greenstone digital library software
+# from the New Zealand Digital Library Project at the 
+# University of Waikato, New Zealand.
+#
+# Copyright (C) 1999 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.
+#
+###########################################################################
+
+
+# This program will find all thecollections under $GSDLHOME/collect
+# and use the update.pl script to update them all.  It should be run
+# every night to keep mirror collections up-to-date.
+
+
+BEGIN {
+    die "GSDLHOME not set\n" unless defined $ENV{'GSDLHOME'};
+    die "GSDLOS not set\n" unless defined $ENV{'GSDLOS'};
+    unshift (@INC, "$ENV{'GSDLHOME'}/perllib");
+    unshift (@INC, "$ENV{'GSDLHOME'}/perllib/plugins");
+    unshift (@INC, "$ENV{'GSDLHOME'}/perllib/classify");
+}
+
+use strict;
+use arcinfo;
+use colcfg;
+use plugin;
+use docprint;
+use util;
+use parsargv;
+
+sub print_usage {
+    print STDERR "\n  usage: $0 [options]\n\n";
+    print STDERR "  options:\n";
+    print STDERR "   -verbosity number      0=none, 3=lots\n";
+    print STDERR "   -importdir directory   Where to place the mirrored material\n";
+    print STDERR "   -archivedir directory  Where the converted material ends up\n";
+}
+
+
+&main ();
+
+sub main {
+    my ($verbosity, $collectdir, $name, $collection);
+
+    if (!parsargv::parse(\@ARGV, 
+			 'verbosity/\d+/2', \$verbosity )) {
+	&print_usage();
+	die "\n";
+    }
+
+
+    # get the contents of the collect directory
+    $collectdir =  &util::filename_cat($ENV{'GSDLHOME'}, "collect");
+    opendir(CDIR, $collectdir) || die "Cannot open $collectdir: $!";
+    my @files = readdir(CDIR);
+    closedir CDIR;
+
+
+    # update each collection
+    foreach $name (@files) {
+
+	$collection = &util::filename_cat($collectdir, $name);
+
+	# igore entries for "." and ".."
+	next unless ($name =~ /[^\.]/);
+
+	# ignore modelcol
+	next if ($name eq "modelcol");
+
+	# ignore entries that are not directories
+	next unless (-d $collection);
+
+	# ignore directories that do not have a subdir called etc
+	next unless (-d &util::filename_cat($collection, "etc"));
+
+	print "Updating: $name\n";
+	print `update.pl $name`;
+	
+    }
+
+}
+
+
+
+
+
Index: /main/tags/2.25/gsdl/bin/script/perlcalc.pl
===================================================================
--- /main/tags/2.25/gsdl/bin/script/perlcalc.pl	(revision 21064)
+++ /main/tags/2.25/gsdl/bin/script/perlcalc.pl	(revision 21064)
@@ -0,0 +1,5 @@
+#! /usr/local/bin/perl5 -w
+
+while (defined($line=<STDIN>)) {
+	print eval($line), "\n";
+}
Index: /main/tags/2.25/gsdl/bin/script/pluginfo.pl
===================================================================
--- /main/tags/2.25/gsdl/bin/script/pluginfo.pl	(revision 21064)
+++ /main/tags/2.25/gsdl/bin/script/pluginfo.pl	(revision 21064)
@@ -0,0 +1,106 @@
+#!/usr/bin/perl -w
+
+###########################################################################
+#
+# pluginfo.pl --
+# A component of the Greenstone digital library software
+# from the New Zealand Digital Library Project at the 
+# University of Waikato, New Zealand.
+#
+# Copyright (C) 1999 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.
+#
+###########################################################################
+
+
+# This program will print info about a plugin
+
+BEGIN {
+    die "GSDLHOME not set\n" unless defined $ENV{'GSDLHOME'};
+    die "GSDLOS not set\n" unless defined $ENV{'GSDLOS'};
+    unshift (@INC, "$ENV{'GSDLHOME'}/perllib");
+    unshift (@INC, "$ENV{'GSDLHOME'}/perllib/plugins");
+}
+
+use strict;
+use plugin;
+use util;
+use parsargv;
+
+sub print_usage {
+    print STDERR "\n  usage: $0 [options] plugin\n\n";
+    print STDERR "  options:\n";
+    print STDERR "   -collect collection-name  Giving a collection name will make pluginfo.pl\n";
+    print STDERR "                             look in collect/collection-name/perllib/plugins\n";
+    print STDERR "                             for plugin first. If it doesn't find it there\n";
+    print STDERR "                             it will look in the general perllib/plugins\n";
+    print STDERR "                             directory\n\n";
+}
+
+
+&main ();
+
+sub main {
+    my $collect = "";
+    if (!parsargv::parse(\@ARGV, 'collect.*/', \$collect)) {
+	&print_usage();
+	die "\n";
+    }
+
+    my $plugin = shift (@ARGV);
+    if (!defined $plugin || $plugin eq "") {
+	print STDERR "You must provide a plugin name\n";
+	&print_usage();
+	die "\n";
+    }
+
+    if ($collect ne "") {
+	$ENV{'GSDLCOLLECTDIR'} = &util::filename_cat ($ENV{'GSDLHOME'}, "collect", $collect);
+    } else {
+	$ENV{'GSDLCOLLECTDIR'} = $ENV{'GSDLHOME'};
+    }
+
+    my $pluginfo = &plugin::load_plugins ([[$plugin]]);
+
+    my $plugobj = shift @$pluginfo;
+
+    print STDERR "\n$plugin info:\n\n";
+	
+    print STDERR "Options may be passed to any plugin by including them in your collect.cfg\n";
+    print STDERR "configuration file.\n\n";
+
+    print STDERR "Plugins may take two types of options:\n\n";
+
+    print STDERR "General options are defined within the base class (BasPlug.pm) and are\n";
+    print STDERR "inherited by any plugin that has been correctly derived from BasPlug.\n\n";
+
+    print STDERR "Specific options are defined within the plugin itself and are available\n";
+    print STDERR "only to this particular plugin.\n\n";
+
+    print STDERR "$plugin takes the following specific options:\n";
+    $plugobj->print_usage();
+
+    print STDERR "$plugin takes the following general options\n";
+    &BasPlug::print_general_usage($plugin);
+
+    print STDERR "The default process_exp for $plugin is\n";
+    print STDERR "\"" . $plugobj->get_default_process_exp() . "\"\n\n";
+
+    print STDERR "The default block_exp for $plugin is\n";
+    print STDERR "\"" . $plugobj->get_default_block_exp() . "\"\n\n";
+
+}
+
Index: /main/tags/2.25/gsdl/bin/script/togb.pl
===================================================================
--- /main/tags/2.25/gsdl/bin/script/togb.pl	(revision 21064)
+++ /main/tags/2.25/gsdl/bin/script/togb.pl	(revision 21064)
@@ -0,0 +1,58 @@
+#!/usr/bin/perl -w
+
+###########################################################################
+#
+# togb.pl -- converts to GB
+#
+# Copyright (C) 1999 DigiLib Systems Limited, NZ.
+#
+# 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.
+#
+###########################################################################
+
+BEGIN {
+    die "GSDLHOME not set\n" unless defined $ENV{'GSDLHOME'};
+    unshift (@INC, "$ENV{'GSDLHOME'}/perllib");
+}
+
+use unicode;
+use multiread;
+use parsargv;
+
+
+$encoding = "utf8";
+if (!parsargv::parse(\@ARGV, 
+		     'unicode', \$unicode,
+		     'iso_8859_1', \$iso_8859_1,
+		     'gb', \$gb)) {
+    print STDERR "\n  usage: $0 [options]\n\n";
+    print STDERR "  options:\n";
+    print STDERR "   -unicode    input is in utf-8 or unicode (default)\n";
+    print STDERR "   -iso_8859_1 input is in extended ascii (ISO-8859-1 Latin 1)\n";
+    print STDERR "   -gb         input is in GB or GBK (simplified Chinese)\n\n";
+    die "\n";
+}
+
+$encoding = "utf8" if $unicode;
+$encoding = "iso_8859_1" if $iso_8859_1;
+$encoding = "gb" if $gb;
+
+$reader = new multiread ();
+$reader->set_handle ('main::STDIN');
+$reader->set_encoding ($encoding);
+$line = "";
+while (defined ($line = $reader->read_line())) {
+    print &gb::unicode2gb (&unicode::utf82unicode ($line));
+}
Index: /main/tags/2.25/gsdl/bin/script/touc.pl
===================================================================
--- /main/tags/2.25/gsdl/bin/script/touc.pl	(revision 21064)
+++ /main/tags/2.25/gsdl/bin/script/touc.pl	(revision 21064)
@@ -0,0 +1,78 @@
+#!/usr/bin/perl -w
+
+###########################################################################
+#
+# touc.pl -- converts to unicode
+#
+# Copyright (C) 1999 DigiLib Systems Limited, NZ.
+#
+# 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.
+#
+###########################################################################
+
+BEGIN {
+    die "GSDLHOME not set\n" unless defined $ENV{'GSDLHOME'};
+    unshift (@INC, "$ENV{'GSDLHOME'}/perllib");
+}
+
+use unicode;
+use multiread;
+use parsargv;
+
+
+$encoding = "utf8";
+if (!parsargv::parse(\@ARGV, 
+		     'unicode', \$unicode,
+		     'iso_8859_1', \$iso_8859_1,
+		     'iso_8859_6', \$iso_8859_6,
+		     'windows_1256', \$windows_1256,
+		     'gb', \$gb)) {
+    print STDERR "\n  usage: $0 [options]\n\n";
+    print STDERR "  options:\n";
+    print STDERR "   -unicode      input is in utf-8 or unicode (default)\n";
+    print STDERR "   -iso_8859_1   input is in extended ascii (ISO-8859-1 Latin 1)\n";
+    print STDERR "   -iso_8859_6   input is in 8 bit Arabic (ISO-8859-6)\n";
+    print STDERR "   -windows_1256 input is in Windows 1256 (Arabic)\n";
+    print STDERR "   -gb           input is in GB or GBK (simplified Chinese)\n\n";
+    die "\n";
+}
+
+$encoding = "utf8" if $unicode;
+$encoding = "iso_8859_1" if $iso_8859_1;
+$encoding = "iso_8859_6" if $iso_8859_6;
+$encoding = "windows_1256" if $windows_1256;
+$encoding = "gb" if $gb;
+
+
+if ($ENV{'GSDLOS'} =~ /windows/i) {
+    binmode (STDOUT); # silly windows
+}
+
+# output in little endian
+print "\xff\xfe";
+
+$reader = new multiread ();
+$reader->set_handle ('main::STDIN');
+$reader->set_encoding ($encoding);
+$line = "";
+$ucline = [];
+while (defined ($line = $reader->read_line())) {
+    $ucline = &unicode::utf82unicode ($line);
+    foreach $c (@$ucline) {
+	$c1 = chr (int ($c / 256));
+	$c2 = chr (int ($c % 256));
+	print "$c2$c1";
+    }
+}
Index: /main/tags/2.25/gsdl/bin/script/toutf8.pl
===================================================================
--- /main/tags/2.25/gsdl/bin/script/toutf8.pl	(revision 21064)
+++ /main/tags/2.25/gsdl/bin/script/toutf8.pl	(revision 21064)
@@ -0,0 +1,64 @@
+#!/usr/bin/perl -w
+
+###########################################################################
+#
+# toutf8.pl -- converts to utf8
+#
+# Copyright (C) 1999 DigiLib Systems Limited, NZ.
+#
+# 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.
+#
+###########################################################################
+
+BEGIN {
+    die "GSDLHOME not set\n" unless defined $ENV{'GSDLHOME'};
+    unshift (@INC, "$ENV{'GSDLHOME'}/perllib");
+}
+
+use unicode;
+use multiread;
+use parsargv;
+
+
+$encoding = "utf8";
+if (!parsargv::parse(\@ARGV, 
+		     'unicode', \$unicode,
+		     'iso_8859_1', \$iso_8859_1,
+		     'iso_8859_6', \$iso_8859_6,
+		     'windows_1256', \$windows_1256,
+		     'gb', \$gb)) {
+    print STDERR "\n  usage: $0 [options]\n\n";
+    print STDERR "  options:\n";
+    print STDERR "   -unicode      input is in utf-8 or unicode (default)\n";
+    print STDERR "   -iso_8859_1   input is in extended ascii (ISO-8859-1 Latin 1)\n";
+    print STDERR "   -iso_8859_6   input is in 8 bit Arabic (ISO-8859-6)\n";
+    print STDERR "   -windows_1256 input is in Windows 1256 (Arabic)\n";
+    print STDERR "   -gb           input is in GB or GBK (simplified Chinese)\n\n";
+    die "\n";
+}
+
+$encoding = "utf8" if $unicode;
+$encoding = "iso_8859_1" if $iso_8859_1;
+$encoding = "iso_8859_6" if $iso_8859_6;
+$encoding = "windows_1256" if $windows_1256;
+$encoding = "gb" if $gb;
+
+$reader = new multiread ();
+$reader->set_handle ('main::STDIN');
+$reader->set_encoding ($encoding);
+$line = "";
+while (defined ($line = $reader->read_line())) {
+    print $line;
+}
Index: /main/tags/2.25/gsdl/bin/script/translate.pl
===================================================================
--- /main/tags/2.25/gsdl/bin/script/translate.pl	(revision 21064)
+++ /main/tags/2.25/gsdl/bin/script/translate.pl	(revision 21064)
@@ -0,0 +1,305 @@
+#!/usr/bin/perl -w
+
+###########################################################################
+#
+# translate.pl 
+# A component of the Greenstone digital library software
+# from the New Zealand Digital Library Project at the 
+# University of Waikato, New Zealand.
+#
+# Copyright (C) 1999 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.
+#
+###########################################################################
+
+# translate.pl takes a translated macro file (filename passed in on command
+# line) and generates any images required by it. Check out english.dm for
+# an example of the format translate.pl expects
+
+# translate.pl uses gimp to generate images so needs gimp installed and set
+# up for scripting with perl
+
+BEGIN {
+    die "GSDLHOME not set\n" unless defined $ENV{'GSDLHOME'};
+    unshift (@INC, "$ENV{'GSDLHOME'}/perllib");
+}
+
+use Gimp;
+use parsargv;
+use util;
+
+# these html entities will be translated correctly when occurring in 
+# images. Any entities not in this list will not.
+my %rmap = ('auml' => chr (228),
+	    'euml' => chr (235),
+	    'iuml' => chr (239),
+	    'ouml' => chr (246),
+	    'uuml' => chr (252),
+	    'Auml' => chr (196),
+	    'Euml' => chr (203),
+	    'Iuml' => chr (207),
+	    'Ouml' => chr (214),
+	    'Uuml' => chr (220),
+	    'szlig' => chr (223),
+	    'aacute' => chr (225),
+	    'eacute' => chr (233),
+	    'iacute' => chr (237),
+	    'oacute' => chr (243),
+	    'uacute' => chr (250),
+	    'Aacute' => chr (193),
+	    'Eacute' => chr (201),
+	    'Iacute' => chr (205),
+	    'Oacute' => chr (211),
+	    'Uacute' => chr (218),
+	    'ntilde' => chr (241),
+	    'Ntilde' => chr (209));
+
+my $hand_made = 0;
+
+sub print_usage {
+    print STDERR "\n  usage: $0 [options] macrofile\n\n";
+    print STDERR "  options:\n";
+    print STDERR "   -save_orig_file       edited macrofile will be written to\n";
+    print STDERR "                         macrofile.new leaving macrofile unchanged\n";
+    print STDERR "   -language_symbol      ISO abbreviation of language (e.g. German=de,\n";
+    print STDERR "                         French=fr, Maori=mi)\n";
+    print STDERR "   -image_dir directory  full path to directory in which to create images\n";
+    print STDERR "                         (defaults to `pwd`/images)\n\n";
+}
+
+sub gsdl_translate {
+
+    if (!parsargv::parse(\@ARGV, 
+			 'save_orig_file', \$save_orig_file,
+			 'language_symbol/[A-Za-z]{2}', \$language_symbol,
+			 'image_dir/.*/images', \$image_dir)) {
+	&print_usage();
+	die "\n";
+    }
+
+    if ($image_dir eq "images") {
+	$image_dir = `pwd`;
+	chomp $image_dir;
+	$image_dir = &util::filename_cat ($image_dir, "images");
+    }
+
+    if (!defined $ARGV[0]) {
+	print STDERR "no macro file supplied\n\n";
+	&print_usage();
+	die "\n";
+    }
+    my $macrofile = $ARGV[0];
+    die "\nmacrofile $macrofile does not exist\n\n" unless -e $macrofile;
+
+    if (!-e $image_dir) {
+	mkdir ($image_dir, 511) || die "\ncouldn't create image_dir $image_dir\n\n";
+    }
+
+    open (INPUT, $macrofile) || die "\ncouldn't open $macrofile for reading\n\n";
+    open (OUTPUT, ">$macrofile.new") || die "\ncouldn't open temporary file $macrofile.new for writing\n\n";
+
+    &parse_file (INPUT, OUTPUT);
+
+    close OUTPUT;
+    close INPUT;
+
+    if (!$save_orig_file) {
+	`mv $macrofile.new $macrofile`;
+    }
+
+    print STDERR "\n\n";
+    print STDERR "translation of macro file $macrofile completed\n";
+    print STDERR "the translated macro file is $macrofile.new\n" if $save_orig_file;
+    print STDERR "\n";
+    if ($hand_made) {
+	print STDERR "$hand_made hand made images were found within $macrofile,\n";
+	print STDERR "these will need to be made by hand (grep $macrofile for 'hand_made'\n\n";
+    }
+    print STDERR "To add your new interface translation to Greenstone you'll need to:\n";
+    print STDERR "  1. Copy your new macro file to your GSDLHOME/macros directory\n";
+    print STDERR "  2. Add your new macro file to the macrofiles list in your\n";
+    print STDERR "     GSDLHOME/etc/main.cfg configuration file\n";
+    print STDERR "  3. Copy your newly created images from $image_dir to \n";
+    print STDERR "     GSDLHOME/images/$language_symbol/\n\n";
+    print STDERR "Access your new interface language by setting the language (l) cgi\n";
+    print STDERR "argument to '$language_symbol'\n\n";
+
+}
+
+sub parse_file {
+    my ($input, $output) = @_;
+
+    undef $/;
+    my $dmfile = <$input>;
+    $/ = "\n";
+
+    # process all the images
+
+    $dmfile =~ s/\n\#\#\s*\"([^\"]*)\"\s*\#\#\s*([^\s\#]*)\s*\#\#\s*([^\s\#]*)\s*\#\#(.*?)(?=(\n\#|\s*\Z))/&process_image ($1, $2, $3, $4)/esg;
+
+    # add language parameter to each macro
+    $dmfile =~ s/(\n\s*)(_[^_]*_)\s*(\[[^\]]*\])?\s*\{/$1 . &add_language_param ($2, $3)/esg;
+    
+    print $output $dmfile;
+}
+
+sub process_image {
+    my ($text, $image_type, $image_name, $image_macros) = @_;
+
+    my $origtext = $text;
+    $text =~ s/&(\d{3,4});/chr($1)/ge;
+    $text =~ s/&([^;]*);/$rmap{$1}/g;
+
+    # edit image macros
+    $image_macros =~ s/(_httpimg_\/)(?:[^\/\}]*\/)?([^\}]*\.(?:gif|jpe?g|png))/$1$language_symbol\/$2/gs;
+
+    if ($image_type eq "top_nav_button") {
+	
+	# generate images
+	my $options = "-text \"$text\" -filenamestem $image_name";
+	$options .= " -fontsize 12 -height 20 -whitespace -image_dir $image_dir";
+	`$ENV{'GSDLHOME'}/bin/script/gimp/flash_button.pl $options`;
+
+	# get width of new images and edit width macro
+	my $fullfilename = &util::filename_cat ($image_dir, "${image_name}on.gif");
+	&process_width_macro ($fullfilename, $image_name, \$image_macros);
+
+    } elsif ($image_type eq "nav_bar_button") {
+	
+	# generate on and off images
+	my $options = "-text \"$text\" -filenamestem $image_name";
+	$options .= " -fontsize 17 -height 17 -fixed_width -width 87";
+	$options .= " -image_dir $image_dir";
+	`$ENV{'GSDLHOME'}/bin/script/gimp/flash_button.pl $options`;
+
+	# generate green image
+	$options = "-text \"$text\" -filename ${image_name}gr.gif";
+	$options .= " -image_dir $image_dir";
+	`$ENV{'GSDLHOME'}/bin/script/gimp/green_bar.pl $options`;
+
+	# get width of new images and edit width macro
+	my $fullfilename = &util::filename_cat ($image_dir, "${image_name}on.gif");
+	&process_width_macro ($fullfilename, $image_name, \$image_macros);
+
+    } elsif ($image_type eq "document_button") {
+
+	# generate on and off images
+	my $options = "-text \"$text\" -filenamestem $image_name";
+	$options .= " -fixed_width -whitespace -image_dir $image_dir";
+	`$ENV{'GSDLHOME'}/bin/script/gimp/flash_button.pl $options`;
+
+	# get width of new images and edit width macro
+	my $fullfilename = &util::filename_cat ($image_dir, "${image_name}on.gif");
+	&process_width_macro ($fullfilename, $image_name, \$image_macros);
+
+    } elsif ($image_type eq "green_bar_left_aligned") {
+
+	# generate green bar image (we're assuming these bars are always 537
+	# pixels and are never stretched by excess text
+	my $options = "-text \"$text\" -filename ${image_name}.gif -dont_center";
+	$options .= " -width 537 -width_space 15 -image_dir $image_dir";
+	`$ENV{'GSDLHOME'}/bin/script/gimp/green_bar.pl $options`;
+
+    } elsif ($image_type eq "green_title") {
+
+	# read the width if it is specified in $image_macros
+        my ($width) = $image_macros =~ /_width${image_name}x?_\s*[^\{]*\{(\d+)\}/;
+        $width = 200 unless ($width);
+
+        # generate green title image
+	my $options = "-text \"$text\" -filename ${image_name}.gif -image_dir $image_dir";
+	$options .= " -width $width -height 57 -stripe_alignment right -text_alignment right";
+	$options .= " -fontsize 26 -fontweight bold";
+	`$ENV{'GSDLHOME'}/bin/script/gimp/title_icon.pl $options`;
+
+	# get width of resulting image and edit _width..._ macro in $image_macros
+        # (no longer needed since we always resize to the width read from $image_macros.)
+        # my $fullfilename = &util::filename_cat ($image_dir, "${image_name}.gif");
+	# &process_width_macro ($fullfilename, $image_name, \$image_macros);
+
+    } elsif ($image_type eq "hand_made") {
+	
+	$hand_made ++;
+
+    } else {
+	
+	print STDERR "WARNING (translate.pl): unknown image type found ($image_type)\n";
+
+    }
+
+    return "\n\#\# \"$origtext\" \#\# $image_type \#\# $image_name \#\#$image_macros";
+}
+
+sub process_width_macro {
+    my ($filename, $image_name, $image_macros) = @_;
+
+    my $img_info = &get_img_info ($filename);
+    $$image_macros =~ s/(_width${image_name}x?_\s*(?:\[[^\]]*\])?\s*\{)(\d+)(\})/$1$img_info->{'width'}$3/s;
+}
+
+sub add_language_param {
+    my ($macroname, $paramlist) = @_;
+
+    my $first = 1;
+    if (defined $paramlist) {
+	$paramlist =~ s/^\[//;
+	$paramlist =~ s/\]$//;
+	my @params = split /\,/, $paramlist;
+	$paramlist = "";
+	foreach $param (@params) {
+	    # remove any existing language parameter
+	    if ($param !~ /^l=/) {
+		$paramlist .= "," unless $first;
+		$paramlist .= $param;
+		$first = 0;
+	    }
+	}
+    }
+    $paramlist .= "," unless $first;
+    $paramlist .= "l=" . $language_symbol;
+    return "$macroname [$paramlist] {";
+}
+
+sub get_img_info {
+    my ($imagefile) = @_;
+    my %info = ();
+
+    if (!-r $imagefile) {
+	print STDERR "ERROR (translate.pl): couldn't open $imagefile to get dimensions\n";
+	$info{'width'} = 0;
+	$info{'height'} = 0;
+    } else {
+	my $image = gimp_file_load (RUN_NONINTERACTIVE, $imagefile, $imagefile);
+	$info{'width'} = gimp_image_width ($image);
+	$info{'height'} = gimp_image_height ($image);
+    }
+
+    return \%info;
+}
+
+sub query {
+
+  gimp_install_procedure("gsdl_translate", "translate macro files and create images",
+                        "", "Stefan Boddie", "Stefan Boddie", "2000-03-14",
+                        "<Toolbox>/Xtns/gsdl_translate", "*", &PROC_EXTENSION,
+                        [[PARAM_INT32, "run_mode", "Interactive, [non-interactive]"]], []);
+}
+
+sub net {
+  gsdl_translate;
+}
+
+exit main;
Index: /main/tags/2.25/gsdl/bin/script/unindex.pl
===================================================================
--- /main/tags/2.25/gsdl/bin/script/unindex.pl	(revision 21064)
+++ /main/tags/2.25/gsdl/bin/script/unindex.pl	(revision 21064)
@@ -0,0 +1,425 @@
+#!/usr/local/bin/perl5 -w
+
+###########################################################################
+#
+# unindex.pl --
+# A component of the Greenstone digital library software
+# from the New Zealand Digital Library Project at the 
+# University of Waikato, New Zealand.
+#
+# Copyright (C) 1999 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.
+#
+###########################################################################
+
+# this program will decompress all the text from a built index
+# and return it to gml format - may be slightly broken at present
+
+BEGIN {
+    die "GSDLHOME not set\n" unless defined $ENV{'GSDLHOME'};
+    die "GSDLOS not set\n" unless defined $ENV{'GSDLOS'};
+    unshift (@INC, "$ENV{'GSDLHOME'}/perllib");
+    $FileHandle = 'FH000';
+}
+
+use doc;
+use docsave;
+use util;
+use parsargv;
+use GDBM_File;
+use FileHandle;
+use English;
+
+select STDERR; $| = 1;
+select STDOUT; $| = 1;
+
+
+# globals
+$collection = "";
+$index = "";
+$textdir = "";
+$classinfo = {};
+$mgread = ++$FileHandle;
+$mgwrite = ++$FileHandle;
+
+
+
+sub print_usage {
+    print STDERR "\n  usage: $0 [options]\n\n";
+    print STDERR "  options:\n";
+    print STDERR "   -verbosity number      0=none, 3=lots\n";
+    print STDERR "   -indexdir directory    The index to be decompressed (defaults to ./index)\n";
+    print STDERR "   -archivedir directory  Where the converted material ends up (defaults to ./archives\n";
+    print STDERR "   -removeold             Will remove the old contents of the archives\n";
+    print STDERR "                          directory -- use with care\n\n";
+}
+
+&main ();
+
+sub main {
+    if (!parsargv::parse(\@ARGV, 
+			 'verbosity/\d+/2', \$verbosity,
+			 'indexdir/.*/index', \$indexdir,
+			 'archivedir/.*/archives', \$archivedir,
+			 'removeold', \$removeold)) {
+	&print_usage();
+	die "\n";
+    }
+
+    die "indexdir $indexdir does not exist\n\n" unless (-d $indexdir);
+    $indexdir =~ s/\/$//;
+    if (-d $archivedir) {
+	if ($removeold) {
+	    print STDERR "Warning - removing current contents of the archives directory $archivedir\n";
+	    print STDERR "          in preparation for the import\n";
+	    sleep(5); # just in case...
+	    &util::rm_r ($archivedir);
+	}
+    } else {
+	&util::mk_all_dir ($archivedir);
+    }
+
+    my $gdbmfile = &get_gdbmfile ($indexdir);
+    &set_index ();
+    &get_classinfo ($gdbmfile);
+    &openmg ();
+
+    # read the archive information file
+    my $archive_info_filename = &util::filename_cat ($archivedir, "archives.inf");
+    my $archive_info = new arcinfo ();
+    $archive_info->load_info ($archive_info_filename);
+
+    # create a docsave object to process the documents
+    my $processor = new docsave ("", $archive_info, $verbosity);
+    $processor->setarchivedir ($archivedir);
+
+    # create a document object for the classification file
+    my $clsudoc_obj = new doc($gdbmfile, "classification");
+    $clsudoc_obj->set_OID ("CLSU");
+
+    my ($doc_obj);
+    foreach $classification (keys %$classinfo) {
+	my $count = 0;
+	foreach $section (sort numerically keys %{$classinfo->{$classification}}) {
+	    print STDERR "\n$classification.$section" if $verbosity >= 2;
+	    if ($classification =~ /^B$/i) {
+		last if $count > 10;
+		# create a new document
+		$doc_obj = new doc ($classinfo->{$classification}->{$section}->{'9999999'}->{'jobnum'}, 
+				    "indexed_doc");
+		$doc_obj->set_OID();
+		my $cursection = $doc_obj->get_top_section();
+		&add_section_content ($doc_obj, $cursection,
+				      $classinfo->{$classification}->{$section});
+		&recurse_classinfo ($doc_obj, $classinfo->{$classification}->{$section}, 
+				    $doc_obj->get_end_child($cursection), 0);
+		$processor->process($doc_obj);
+	    } else {
+		my $classifier = &int_classification ($classification);
+		$clsudoc_obj->create_named_section("$classifier.$section");
+		&add_section_content ($clsudoc_obj, "$classifier.$section",
+				      $classinfo->{$classification}->{$section});
+		&recurse_classinfo ($clsudoc_obj, $classinfo->{$classification}->{$section}, 
+				    "", "$classifier.$section");
+	    }
+	    $count ++;
+	}
+    }
+    $processor->process($clsudoc_obj);
+    &closemg();
+
+    # write out the archive information file
+    $archive_info->save_info($archive_info_filename);
+}
+
+# returns the path to the gdbm info database - also
+# sets the $collection and $textdir global variable
+sub get_gdbmfile {
+    my ($indexdir) = @_;
+    my ($gdbmfile);
+
+    opendir (DIR, $indexdir) || die "Couldn't open directory $indexdir\n\n";
+    my @conts = readdir DIR;
+    close DIR;
+
+    foreach $file (@conts) {
+	if ($file =~ /text$/) {
+	    $textdir = $file;
+	    last;
+	}
+    }
+    die "No text directory found in $indexdir\n\n" 
+	unless defined $textdir && $textdir =~ /text$/;
+
+    $gdbmfile = &util::filename_cat ($indexdir, $textdir);
+
+    opendir (DIR, $gdbmfile) || die "Couldn't open directory $gdbmfile\n\n";
+    @conts = readdir DIR;
+    close DIR;
+
+    foreach $file (@conts) {
+	if ($file =~ /^(.*?)\.(?:ldb|bdb)$/) {
+	    $collection = $1;
+	    $gdbmfile = &util::filename_cat ($gdbmfile, $file);
+	    last;
+	}
+    }
+    
+    if (defined $collection && $collection =~ /\w/) {
+	$textdir = &util::filename_cat ($textdir, $collection);
+    } else {
+	die "collection global wasn't set\n";
+    }
+    return $gdbmfile if (-e $gdbmfile);
+    die "Couldn't find gdbm info database in $indexdir\n\n";
+}
+
+sub get_classinfo {
+    my ($gdbmfile) = @_;
+    my ($class);
+
+    open (DB2TXT, "db2txt $gdbmfile |") || die "couldn't open pipe to db2txt\n";
+
+    print STDERR "Generating classification table from $gdbmfile\n" if $verbosity >= 2;
+    my $count = 0;
+
+    $/ = '-' x 70;
+    my $entry = "";
+    while (defined ($entry = <DB2TXT>)) {
+	next unless $entry =~ /\w/;
+	$entry =~ s/\n+/\\n/g;
+	my ($key, $value) = $entry =~ /\[([^\]]*)\](.*)/;
+
+	print STDERR "." if (($count % 100) == 99 && $verbosity >= 2);
+
+	next if ($key !~ /\./); # ignore the docnums and top level of classifications
+
+	die "Badly formatted key $key in $gdbmfile\n\n" 
+	    unless (($class, $section) = $key =~ /^(.)\.(.*)$/);	
+	$classinfo->{$class} = {} unless defined $classinfo->{$class};
+	my @sections = split /\./, $section;
+
+	my $hashptr = $classinfo->{$class};
+	foreach $sec (@sections) {
+	    $hashptr->{$sec} = {} unless defined $hashptr->{$sec};
+	    $hashptr = $hashptr->{$sec};
+	}
+	&get_metadata ($key, \$value, $hashptr);
+
+	$count ++;
+    }
+
+    $/ = "\n";
+    print STDERR "\n" if $verbosity >= 2;
+}
+
+sub get_metadata {
+    my ($key, $gdb_str_ref, $hashsection) = @_;
+    
+    my ($title) = $$gdb_str_ref =~ /(?:<t>|<title>)(.*?)(?:\\n|$)/i; 
+    my ($docnum) = $$gdb_str_ref =~ /(?:<d>|<docnum>)(.*?)(?:\\n|$)/i; 
+    my ($jobnum) = $$gdb_str_ref =~ /(?:<j>|<jobnumber>)(.*?)(?:\\n|$)/i; 
+    my ($classifications) = $$gdb_str_ref =~ /(?:<x>|<classification>)(.*?)(?:\\n|$)/i; 
+    my $hastext = 1;
+    $hastext = 0 if ($$gdb_str_ref =~ /(?:<c>|<contains>)(.*?)(?:\\n|$)/i);
+    my ($creator) = $$gdb_str_ref =~ /<a>(.*?)(?:\\n|$)/i; 
+    my ($date) = $$gdb_str_ref =~ / <i>(.*?)(?:\\n|$)/i; 
+			
+    # just in case there are empty classifications			     
+    if ($hastext && !defined $docnum) {
+	print STDERR "\nwarning: $key entry has no contents\n" if $verbosity;
+	if ($verbosity >= 2) {
+	    my $valuestr = $$gdb_str_ref;
+	    $valuestr =~ s/\\n/\n/g;
+	    print STDERR "$valuestr\n";
+	}
+	$hastext = 0;
+    }
+
+    # shove metadata in 9999999 to keep it numeric and prevent 
+    # sorting from being a pain. Watch out for documents with
+    # 9999999 subsections ;-)
+    if (defined $hashsection->{'9999999'}) {
+	print STDERR "\nwarning: $key appears multiple times\n" if $verbosity;
+    } else {
+	$hashsection->{'9999999'}->{'Title'} = $title if defined $title;
+	$hashsection->{'9999999'}->{'docnum'} = $docnum if defined $docnum;
+	$hashsection->{'9999999'}->{'jobnum'} = $jobnum if defined $jobnum;
+	$hashsection->{'9999999'}->{'classifications'} = $classifications if defined $classifications;
+	$hashsection->{'9999999'}->{'hastext'} = $hastext;
+	$hashsection->{'9999999'}->{'Creator'} = $creator if defined $creator;
+	$hashsection->{'9999999'}->{'Date'} = $date if defined $date;
+    }
+}
+
+sub recurse_classinfo {
+    my ($doc_obj, $hashsection, $cursection, $class) = @_;
+    foreach $section (sort numerically keys %$hashsection) {
+	next if $section == 9999999;
+	if ($class) {
+	    $doc_obj->create_named_section("$class.$section");
+	    &add_section_content ($doc_obj, "$class.$section", $hashsection->{$section});
+	    &recurse_classinfo ($doc_obj, $hashsection->{$section}, "", "$class.$section");
+	} else {
+	    $cursection = 
+		$doc_obj->insert_section($doc_obj->get_end_child($doc_obj->get_parent_section($cursection)));
+	    &add_section_content ($doc_obj, $cursection, $hashsection->{$section});
+	    &recurse_classinfo ($doc_obj, $hashsection->{$section}, $doc_obj->get_end_child($cursection));
+	}
+    }
+}
+
+sub add_section_content {
+    my ($doc_obj, $cursection, $hashsection) = @_;
+
+    $doc_obj->add_metadata ($cursection, "Title", $hashsection->{'9999999'}->{'Title'})
+	if defined $hashsection->{'9999999'}->{'Title'};
+    $doc_obj->add_metadata ($cursection, "Creator", $hashsection->{'9999999'}->{'Creator'})
+	if defined $hashsection->{'9999999'}->{'Creator'};
+    $doc_obj->add_metadata ($cursection, "Date", $hashsection->{'9999999'}->{'Date'})
+	if defined $hashsection->{'9999999'}->{'Date'};
+
+    if (defined $hashsection->{'9999999'}->{'classifications'}) {
+	my @classifications = split /:/, $hashsection->{'9999999'}->{'classifications'};
+	map {$doc_obj->add_metadata ($cursection, 'Subject', $_); } @classifications;
+    }
+
+    $doc_obj->add_text ($cursection, &get_text ($hashsection->{'9999999'}->{'docnum'}))
+	if ($hashsection->{'9999999'}->{'hastext'});
+}
+
+sub set_index {
+    # check that $collection has been set
+    die "collection global was not set\n"
+	unless defined $collection && $collection =~ /\w/;
+
+    # find an index (just use first non-text directory we come across in $indexdir)
+    opendir (INDEXDIR, $indexdir) || die "couldn't open directory $indexdir\n";
+    my @indexes = readdir INDEXDIR;
+    close INDEXDIR;
+    foreach $i (@indexes) {
+	next if $i =~ /text$/i || $i =~ /\./ ;
+	$index = &util::filename_cat ($i, $collection);
+	last;
+    }
+}
+
+sub get_text {
+    my ($docnum) = @_;
+
+    print STDERR "." if $verbosity >= 2;
+    &mgcommand ($docnum);
+
+    <$mgread>;	# eat the document separator
+
+    my $text = "";
+    my $line = "";
+
+    while (defined ($line = <$mgread>))
+    {
+	last if $line =~ /^<\/mg>/;
+	$text .= $line;
+    }
+
+    # Read in the last statement, which should be:
+    #  "dd documents retrieved."
+    <$mgread>;
+
+    return $text;
+}
+
+sub numerically {$a <=> $b;}
+
+# converts leading letter of a classification into its ascii equivalent
+# i.e C.2.4 becomes 67.2.4
+sub int_classification {
+    my ($classification) = @_;
+    my $c = ord($classification);
+    $classification =~ s/^./$c/;
+
+    return $classification;
+}
+
+
+# mg stuff
+
+sub openmg {
+    
+    die "Unable to start mgquery." unless
+	openpipe($mgread, $mgwrite,
+		 "mgquery -d $indexdir -f $index -t $textdir");
+
+    $mgwrite->autoflush();
+
+    &mgcommand('.set expert true');
+    &mgcommand('.set terminator "</mg>\n"');
+    &mgcommand('.set mode text');
+    &mgcommand('.set query docnums');
+    &mgcommand('.set term_freq off');
+}
+
+sub closemg {
+    &mgcommand (".quit");
+    close($mgread);
+    close($mgwrite);
+}
+
+sub mgcommand {
+    my ($command) = @_;
+
+    return if $command =~ /^\s*$/;
+    print $mgwrite "$command\n";
+
+    # eat up the command executed which is echoed
+    <$mgread>;
+}
+
+# openpipe(READ, WRITE, CMD)
+# 
+# Like open2, except CMD's stderr is also redirected.
+# 
+sub openpipe
+{
+    my ($read, $write, $cmd) = @_;
+    my ($child_read, $child_write);
+
+    $child_read = ++$FileHandle;
+    $child_write = ++$FileHandle;
+
+    pipe($read, $child_write) || die "Failed pipe($read, $child_write): $!";
+    pipe($child_read, $write) || die "Failed pipe($child_read, $write): $!";
+    my $pid;
+
+    if (($pid = fork) < 0) {
+        die "Failed fork: $!";
+    } elsif ($pid == 0) {
+        close($read);
+        close($write);
+        open(STDIN, "<&$child_read");
+        open(STDOUT, ">&$child_write");
+        open(STDERR, ">&$child_write");
+        exec($cmd);
+        die "Failed exec $cmd: $!";
+    }
+
+    close($child_read);
+    close($child_write);
+
+    $write->autoflush();
+    $read->autoflush();
+
+    return 1;
+}
Index: /main/tags/2.25/gsdl/bin/script/update.pl
===================================================================
--- /main/tags/2.25/gsdl/bin/script/update.pl	(revision 21064)
+++ /main/tags/2.25/gsdl/bin/script/update.pl	(revision 21064)
@@ -0,0 +1,209 @@
+#!/usr/bin/perl -w
+
+###########################################################################
+#
+# update.pl
+#
+# A component of the Greenstone digital library software
+# from the New Zealand Digital Library Project at the 
+# University of Waikato, New Zealand.
+#
+# Copyright (C) 1999 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.
+#
+###########################################################################
+
+
+# This program updates any collections that are based on mirrors of
+# web sites after a certain interval.  It first checks that the
+# collection is a mirrored collection and whether it is time to 
+# update the collection.  If so, it updates the mirror with 
+# mirror.pl; then imports the collection with import.pl; then 
+# builds the collection with buildcol.pl; then replaces the 
+# existing index directory with the new building directory.
+# The etc/mirror.log file stores the STDOUT output.
+
+
+BEGIN {
+    die "GSDLHOME not set\n" unless defined $ENV{'GSDLHOME'};
+    die "GSDLOS not set\n" unless defined $ENV{'GSDLOS'};
+    unshift (@INC, "$ENV{'GSDLHOME'}/perllib");
+    unshift (@INC, "$ENV{'GSDLHOME'}/perllib/plugins");
+    unshift (@INC, "$ENV{'GSDLHOME'}/perllib/classify");
+}
+
+use strict;
+use arcinfo;
+use colcfg;
+use plugin;
+use docprint;
+use util;
+use parsargv;
+
+sub print_usage {
+    print STDERR "\n  usage: $0 [options] collection-name\n\n";
+    print STDERR "  options:\n";
+    print STDERR "   -verbosity number      0=none, 3=lots\n";
+    print STDERR "   -importdir directory   Where to place the mirrored material\n";
+    print STDERR "   -archivedir directory  Where the converted material ends up\n";
+}
+
+
+&main ();
+
+sub main {
+    my ($verbosity, $importdir, $archivedir, $builddir, $indexdir, $etcdir, 
+	$mirror, $interval, $logfile,
+        $collection, $configfilename, $collectcfg);
+
+    if (!parsargv::parse(\@ARGV, 
+			 'verbosity/\d+/2', \$verbosity,
+			 'importdir/.*/', \$importdir,
+			 'archivedir/.*/', \$archivedir )) {
+	&print_usage();
+	die "\n";
+    }
+
+    # get and check the collection name
+    if (($collection = &util::use_collection(@ARGV)) eq "") {
+	&print_usage();
+	die "\n";
+    }
+
+    # check the configuration file for options
+    $configfilename = &util::filename_cat ($ENV{'GSDLCOLLECTDIR'}, "etc/collect.cfg");
+    if (-e $configfilename) {
+	$collectcfg = &colcfg::read_collect_cfg ($configfilename);
+	if (defined $collectcfg->{'importdir'} && $importdir eq "") {
+	    $importdir = $collectcfg->{'importdir'};
+	}
+	if (defined $collectcfg->{'archivedir'} && $archivedir eq "") {
+	    $archivedir = $collectcfg->{'archivedir'};
+	}
+	if (defined $collectcfg->{'mirror'}) {
+	    $mirror = $collectcfg->{'mirror'};
+	}
+    } else {
+	die "Couldn't find the configuration file $configfilename\n";
+    }
+    
+    # fill in the default import and archives directories if none
+    # were supplied, turn all \ into / and remove trailing /
+    $importdir = "$ENV{'GSDLCOLLECTDIR'}/import" if $importdir eq "";
+    $importdir =~ s/[\\\/]+/\//g;
+    $importdir =~ s/\/$//;
+    $archivedir = "$ENV{'GSDLCOLLECTDIR'}/archives" if $archivedir eq "";
+    $archivedir =~ s/[\\\/]+/\//g;
+    $archivedir =~ s/\/$//;
+
+    $indexdir = "$ENV{'GSDLCOLLECTDIR'}/index";
+    $builddir = "$ENV{'GSDLCOLLECTDIR'}/building";
+    $etcdir = "$ENV{'GSDLCOLLECTDIR'}/etc";
+    $logfile = "$etcdir/mirror.log";
+
+    # if there is no mirror information, we're all done
+    if (!defined($mirror)) {
+	print "No mirror information\n";
+	exit;
+    }
+
+    # read the mirror interval
+    if (($#$mirror == 1) && ($$mirror[0] =~ /interval/)){
+	$interval = $$mirror[1];
+    } else {
+	die "Malformed mirror information: use \"mirror interval N\"\n" .
+	    "where N is the number of days between mirrors.\n";
+    }
+
+    # make sure there is a w3mir file
+    if (! -e "$etcdir/w3mir.cfg") {
+	die "Couldn't find the w3mir configuration file $etcdir/w3mir.cfg\n";
+    }
+
+    # make sure there is an import directory
+    if (! -e "$importdir") {
+	&util::mk_dir($importdir);
+    }
+
+    # make sure there is an empty archives directory
+    if (-e "$archivedir") {
+	&util::rm_r ($archivedir);
+    }
+    &util::mk_dir($archivedir);
+    
+    print "archives directory: $archivedir\n";
+    print "  import directory: $importdir\n";
+    print "     etc directory: $etcdir\n";
+    print "     w3config file: $etcdir/w3mir.cfg\n";
+
+    print "          interval: $interval days\n";
+
+    # how many days is it since the last mirror
+    my $seconds = 0;
+    if (-e "$logfile") {
+	my $now = time;
+	my @stats = stat("$logfile");
+	my $then = $stats[9];
+	# calculate the number of days since the last mirror
+	$seconds = $now - $then;
+    }
+    my $days = (($seconds / 3600) / 24);
+
+    # Is it too soon to start mirroring?
+    if (($seconds > 0) && ($interval > $days)) {
+	printf "Mirror not started: only %.1f days have passed\n", $days;
+	exit;
+    }
+    
+    # Mirror the remote site
+    open(WLOG, ">$logfile");
+    print WLOG "Starting mirror at " . time . "\n\n";
+    
+    my $command = "mirror.pl $collection";
+    print WLOG "Executing: $command\n";
+    print WLOG `$command`;
+    
+    # Import the collection
+    print WLOG "\n\nStarting import at " . time . "\n\n";
+    $command = "import.pl $collection";
+    print WLOG "Executing: $command\n";
+    print WLOG `$command`;
+
+    # Build the collection
+    print WLOG "\n\nStarting buildcol.pl at " . time . "\n\n";
+    $command = "buildcol.pl $collection";
+    print WLOG "Executing: $command\n";
+    print WLOG `$command`;
+
+    # Renaming the building directory to index
+    print WLOG "\n\nRenaming building directory at " . time . "\n\n";
+    if (-e $indexdir) {
+	&util::mv($indexdir, "$indexdir.old");
+	&util::mv($builddir, $indexdir);
+	&util::rm_r ("$indexdir.old");
+    } else {
+	&util::mv($builddir, $indexdir);
+    }
+
+
+    close WLOG;
+    
+}
+
+
+
+
+
Index: /main/tags/2.25/gsdl/bin/script/urlcopy.pl
===================================================================
--- /main/tags/2.25/gsdl/bin/script/urlcopy.pl	(revision 21064)
+++ /main/tags/2.25/gsdl/bin/script/urlcopy.pl	(revision 21064)
@@ -0,0 +1,183 @@
+#!/usr/bin/perl -w
+
+###########################################################################
+#
+# urlcopy.pl --
+# A component of the Greenstone digital library software
+# from the New Zealand Digital Library Project at the 
+# University of Waikato, New Zealand.
+#
+# Copyright (C) 1999 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.
+#
+###########################################################################
+
+
+# This program will download the specified urls (http:, ftp: and file:)
+
+BEGIN {
+    die "GSDLHOME not set\n" unless defined $ENV{'GSDLHOME'};
+    unshift (@INC, "$ENV{'GSDLHOME'}/perllib");
+
+    unshift (@INC, "$ENV{'GSDLHOME'}/perllib/cpan/lib");
+    $ENV{'PATH'} = "$ENV{'GSDLHOME'}/perllib/cpan/bin:$ENV{'PATH'}";
+}
+
+use util;
+use File::Basename;
+
+sub print_usage
+{
+    print STDERR "\n  usage: $0 [urls] collection-name\n\n";
+}
+
+sub main
+{
+    if (scalar(@ARGV)<2)
+    {
+	print_usage();
+	exit(1);
+    }
+
+    my $dirname = pop(@ARGV);
+    my $full_importname 
+	= &util::filename_cat($ENV{'GSDLHOME'},"collect",$dirname,"import");
+
+    mkdir ($full_importname, 0777) unless -e $full_importname;
+
+    # split argv into 3 lists: http, ftp and file
+    my (@http,@ftp,@file) = ((),(),());
+    my $a;
+    foreach $a (@ARGV)
+    {
+	$a =~ s/^\"//;
+	$a =~ s/\"$//;
+
+	if ($a =~ m/^http:/i)
+	{
+	    push(@http,$a);
+	}
+	elsif ($a =~ m/^ftp:/i)
+	{
+	    push(@ftp,$a);
+	}
+	elsif ($a =~ m/^file:/i)
+	{
+	    push(@file,$a);
+	}
+	else
+	{
+	    print STDERR "URL argument not supported: $a\n";
+	    print STDERR "Ingoring argument.\n";
+	}
+    }
+    
+    if (scalar(@http)>0)
+    {
+	my $w3mircfg_filename
+	    = &util::filename_cat($ENV{'GSDLHOME'},"tmp","$dirname.w3mir");
+
+	# create cfg file
+	open(CFGOUT,">$w3mircfg_filename")
+	    || die "Unable to open $w3mircfg_filename: $!";
+	print CFGOUT "Options: recurse\n\n";
+	
+	my $first = 1;
+	my $a;	
+	foreach $a (@http)
+	{
+	    my $src_url = $a;
+	    my $dst_dir = $a;
+	    $dst_dir =~ s/^http://i;
+	    $dst_dir = &util::filename_cat($full_importname,$dst_dir);
+
+	    if ($src_url !~ m/\/$/)
+	    {
+		# last name is a file => strip off filename
+		$dst_dir = &File::Basename::dirname($dst_dir);
+	    }
+	    if ($first)
+	    {
+		print CFGOUT "URL:        $src_url $dst_dir\n";
+		$first = 0;
+	    }
+	    else
+	    {
+		print CFGOUT "Also-queue: $src_url $dst_dir\n";
+	    }
+	}	    
+	print CFGOUT "\nFixup: run\n";
+	close(CFGOUT);
+
+	my $cmd = "cd $full_importname; ";
+	$cmd .= "w3mir.pl -cfgfile $w3mircfg_filename";
+
+	my $status = system($cmd);
+	$status /= 256;
+	if ($status != 0)
+	{
+	    print STDERR "An error was encountered executing: $cmd\n";
+	    exit($status);
+	}
+    }
+
+    if (scalar(@ftp)>0)
+    {
+	my $cmd = "cd $full_importname; ";
+	$cmd .= "ncftp ";
+	my $a;
+	foreach $a (@ftp)
+	{
+	    $a = "$a/" if ($a !~ m/\/$/);
+	    $cmd .= " \"$a/*\"";
+	}
+	my $status = system($cmd);
+	$status /= 256;
+	if ($status != 0)
+	{
+	    print STDERR "An error was encountered executing: $cmd\n";
+	    exit($status);
+	}
+
+    }
+
+    if (scalar(@file)>0)
+    {
+	my $cmd = "filedownload.pl";
+	my $a;
+	foreach $a (@file)
+	{
+	    $cmd .= " \"$a\"";
+	}
+	$cmd .= " $dirname";
+
+	my $status = system($cmd);
+	$status /= 256;
+	if ($status != 0)
+	{
+	    print STDERR "An error was encountered executing: $cmd\n";
+	    exit($status);
+	}
+    }
+
+    return 0;
+}
+
+&main();
+
+
+
+
Index: /main/tags/2.25/gsdl/cgi-bin/GSDLHOME.pm
===================================================================
--- /main/tags/2.25/gsdl/cgi-bin/GSDLHOME.pm	(revision 21064)
+++ /main/tags/2.25/gsdl/cgi-bin/GSDLHOME.pm	(revision 21064)
@@ -0,0 +1,36 @@
+package GSDLHOME;
+
+BEGIN {
+
+    if (!defined $ENV{'GSDLHOME'}) {
+	# read gsdlhome from gsdlsite.cfg
+	open (GSDLSITE, "gsdlsite.cfg") || die 
+	    "GSDLHOME.pm: unable to open gsdlsite.cfg\n";
+	my $line = "";
+	while (defined ($line = <GSDLSITE>)) {
+	    if ($line =~ /^gsdlhome\s+(.*?)\s*$/) {
+		$ENV{'GSDLHOME'} = $1;
+		last;
+	    }
+	}
+	die "GSDLHOME.pm: couldn't find gsdlhome field in gsdlsite.cfg\n"
+	    unless defined $ENV{'GSDLHOME'};
+    }
+
+    # just in case GSDLHOME has a slash on the end which would cause
+    # double slashes below
+    $ENV{'GSDLHOME'} =~ s/[\/\\]+$//;
+
+    $ENV{'GSDLOS'} = $^O;
+
+    if ($ENV{'GSDLOS'} =~ /(win|dos)/i) {
+	$ENV{'GSDLOS'} = 'windows';
+    }
+    
+    $ENV{'PATH'} .= ":$ENV{'GSDLHOME'}/bin/script";
+    $ENV{'PATH'} .= ":$ENV{'GSDLHOME'}/bin/$ENV{'GSDLOS'}";
+    unshift (@INC, "$ENV{'GSDLHOME'}/perllib");
+    unshift (@INC, "$ENV{'GSDLHOME'}/perllib/cpan");
+}
+
+1;
Index: /main/tags/2.25/gsdl/cgi-bin/gsdlsite.cfg
===================================================================
--- /main/tags/2.25/gsdl/cgi-bin/gsdlsite.cfg	(revision 21064)
+++ /main/tags/2.25/gsdl/cgi-bin/gsdlsite.cfg	(revision 21064)
@@ -0,0 +1,28 @@
+# this file should be placed in the same directory as your library
+# executable file. it should be edited to suit your site.
+
+# points to the GSDLHOME directory
+gsdlhome    **GSDLHOME**
+
+# this is the http address of GSDLHOME
+# if your webservers DocumentRoot is set to $GSDLHOME
+# then httpprefix can remain commented out
+#httpprefix  /gsdl
+
+# this is the http address of the directory which
+# contains the images for the interface.
+# if your webservers DocumentRoot is set to $GSDLHOME
+# then httpimg will be /images
+httpimg     /images
+
+# should contain the http address of this cgi script. This 
+# is not needed if the http server sets the environment variable 
+# SCRIPT_NAME
+#gwcgi       /cgi-bin/library
+
+# maxrequests is the most requests a fastcgi process
+# will serve before it exits. This can be set to a
+# low figure (like 1) while debugging and then set
+# to a high figure (like 10000) when everything is
+# working well.
+maxrequests 10000
Index: /main/tags/2.25/gsdl/cgi-bin/webpage_buildcol.pl
===================================================================
--- /main/tags/2.25/gsdl/cgi-bin/webpage_buildcol.pl	(revision 21064)
+++ /main/tags/2.25/gsdl/cgi-bin/webpage_buildcol.pl	(revision 21064)
@@ -0,0 +1,324 @@
+#!perl -w
+
+###########################################################################
+#
+# webpage_buildcol.pl --
+# A component of the Greenstone digital library software
+# from the New Zealand Digital Library Project at the 
+# University of Waikato, New Zealand.
+#
+# Copyright (C) 1999 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.
+#
+###########################################################################
+
+# This program is a webpage wrapper to the import.pl and buildcol.pl 
+#   processes
+# Note while it is in the cgi-bin directory, its arguments are supplied as 
+#  the more traditional command line argument.  The program is executed by
+#   an already running cgi program.
+
+package webpage_buildcol;
+
+use File::Basename;
+use GSDLHOME;
+use gflock;
+
+my $args;
+
+BEGIN
+{    
+    my $va_pair;
+    foreach $va_pair (@ARGV) 
+    { 
+	if ($va_pair =~ m/^(\w+)=(\"?)(.*)(\"?)$/)
+	{
+	    my ($variable,$assignment) = ($1,$3);
+	    $args->{$variable} = $assignment;
+	}
+    }
+}
+
+require util;
+require webpageutil;
+require cfgread;
+
+sub communicate_single_line
+{
+    my ($full_tmpname,$text) = @_;
+
+    if (open(TMPOUT,">$full_tmpname"))
+    {
+	if (&gflock::lock (webpage_buildcol::TMPOUT)) {
+	    print TMPOUT $text;
+	    close(TMPOUT);
+	    &gflock::unlock (webpage_buildcol::TMPOUT);
+
+	} else {
+	    # Problem locking file
+	    my $mess = "Unable to lock temporary communication file:";
+	    $mess .= " $full_tmpname";
+	    print STDERR "$mess\n";
+	    return;
+	}
+    }
+    else
+    {
+	my $mess = "Unable to open for writing";
+	$mess .= " communication temporary file: $full_tmpname.";
+	print STDERR "$mess\n";
+	return;
+    }
+}
+
+
+sub do_build
+{
+    my ($full_dirname,$dirname,$args) = @_;
+
+    my $tmpname = $args->{'bc1tmpname'};
+    my $full_tmpname = &util::filename_cat($ENV{'GSDLHOME'},"tmp",$tmpname);
+    my $cfg_filename = &util::filename_cat($full_dirname,"etc","collect.cfg");
+    my $full_importname = &util::filename_cat($full_dirname,"import");
+
+    my $log_filename = &util::filename_cat($ENV{'GSDLHOME'},"etc","$dirname.bld");
+    if (!open (LOGOUT, ">$log_filename"))
+    {
+	my $mess = "Error: Unable to open log file '$log_filename'";
+	print LOGOUT "$mess\n";
+	communicate_single_line($full_tmpname,$mess);
+	return "failure";
+    }
+
+    my $copy_data = $args->{'bc1copydata'};
+    my $do_import = $args->{'bc1doimport'};
+    my $do_build  = $args->{'bc1dobuild'};
+
+    my $building_cfg_text 
+	= &cfgread::read_cfg_file($cfg_filename,undef,undef,"^building");
+    my $copy_dir     = $building_cfg_text->{'building'}->{'copydir'};
+    my $input_dir    = $building_cfg_text->{'building'}->{'inputdir'};
+
+    if ($copy_data eq "true")
+    {
+	if ($copy_dir =~ m/^yes$/i)
+	{
+	    my $download_cmd = "perl " . &util::filename_cat ($ENV{'GSDLHOME'}, "bin", "script");
+
+	    # run filecopy.pl to download files
+	    $input_dir =~ s/^\s+//;
+	    $input_dir =~ s/\s+$//;
+	    $download_cmd = " filecopy.pl \"$input_dir\" \"$dirname\"";
+	    
+	    # execute download command and monitor the output generated
+	    if(!open(DOWNLOADOUT,"$download_cmd 2>&1 |"))
+	    {
+		my $mess = "Error: Unable to open pipe to command '$download_cmd'";
+		print LOGOUT "$mess\n";
+		communicate_single_line($full_tmpname,$mess);
+		close(LOGOUT);
+		return "failure";
+	    }
+	    while (defined($line=<DOWNLOADOUT>))
+	    {
+		print LOGOUT $line;
+		chop $line;
+		if ($line =~ m/^Error:/)
+		{
+		    print LOGOUT "$line";
+		    communicate_single_line($full_tmpname,"$line");
+		    close(DOWNLOADOUT);
+		    close(LOGOUT);
+		    return "failure";
+		}    
+		communicate_single_line($full_tmpname,"Copying data ...<br>$line");
+	    }
+	    
+	    close(DOWNLOADOUT);
+	}
+    }
+
+    if ((defined $copy_dir) && ($copy_dir =~ /^no$/i))
+    {
+	# link it
+	my $tail_dir = &File::Basename::basename($input_dir);
+	my $sym_dirname = &util::filename_cat($full_importname,$tail_dir);
+	
+	&util::rm_r($sym_dirname) if (-e $sym_dirname);
+
+	if (&util::soft_link($input_dir,$sym_dirname))
+	{
+	    my $mess = "Source data linked to $input_dir";
+	    communicate_single_line($full_tmpname,$mess);
+	}
+	else
+	{
+	    my $mess = "Error: unable to make symbolic link to source:";
+	    $mess .= " $input_dir";
+	    print LOGOUT "$mess\n";
+	    communicate_single_line($full_tmpname,$mess);
+	    close(LOGOUT);
+	    return "failure";
+	}
+    }
+
+    if ($do_import eq "true")
+    {
+	# Import operation
+	my $import_cmd = "perl ";
+	$import_cmd .= &util::filename_cat($ENV{'GSDLHOME'}, "bin", "script", "import.pl");
+	$import_cmd .= " -removeold $dirname";
+	
+	if(!open(IMPORTOUT,"$import_cmd 2>&1 |"))
+	{
+	    my $mess = "Error: Unable to open pipe to command '$import_cmd'";
+	    print LOGOUT "$mess\n";
+	    communicate_single_line($full_tmpname,$mess);
+	    close(LOGOUT);
+	    return "failure";
+	}
+	while (defined($line=<IMPORTOUT>))
+	{
+	    print LOGOUT $line;
+	    chop $line;
+	    if ($line =~ m/^Error:/)
+	    {
+		print LOGOUT "$line";
+		communicate_single_line($full_tmpname,"$line");
+		close(IMPORTOUT);
+		close(LOGOUT);
+		return "failure";
+	    }    
+	    communicate_single_line($full_tmpname,"Caching data ...<br>$line");
+	}
+	
+	close(IMPORTOUT);
+    }
+
+    if ($do_build eq "true")
+    {
+	my $full_archivename = &util::filename_cat($full_dirname,"archives");
+
+	# Build operation
+	my $build_cmd = "perl " . 
+	    &util::filename_cat($ENV{'GSDLHOME'}, "bin", "script", "buildcol.pl");
+	if (($do_import eq "true") 
+	    || (($do_import eq "false") && (-e $full_archivename)))
+	{
+	    $build_cmd .= " $dirname";
+	}
+	else
+	{
+	    $build_cmd .= " -archivedir $full_importname";
+	    $build_cmd .= " -cachedir $full_archivename";
+	    $build_cmd .= " $dirname";
+	}
+	
+	if(!open(BUILDOUT,"$build_cmd 2>&1 |"))
+	{
+	    my $mess = "Error: Unable to open pipe to command '$build_cmd'";
+	    print LOGOUT "$mess\n";
+	    communicate_single_line($full_tmpname,$mess);
+	    close(LOGOUT);
+	    return "failure";
+	}
+	while (defined($line=<BUILDOUT>))
+	{
+	    print LOGOUT $line;
+	    chop $line;
+	    if ($line =~ m/^Error:/)
+	    {
+		print LOGOUT "$line";
+		communicate_single_line($full_tmpname,"$line");
+		close(BUILDOUT);
+		close(LOGOUT);
+		return "failure";
+	    }    
+	    communicate_single_line($full_tmpname,"Creating indexes ...<br>$line");
+	}
+	
+	close(BUILDOUT);
+
+	# Make collection live
+	#--
+	# rm index
+	my $full_indexname = &util::filename_cat($full_dirname,"index");
+	&util::rm_r($full_indexname);
+	
+	# move building
+	my $full_buildingname = &util::filename_cat($full_dirname,"building");
+	&util::mv($full_buildingname,$full_indexname);
+	
+	my $full_imagesrc = &util::filename_cat($full_dirname,"building_images","imgsrc");
+	if (-e $full_imagesrc)
+	{
+	    my $full_imagedst = &util::filename_cat($full_dirname,"index","imgsrc");
+	    &util::soft_link($full_imagesrc,$full_imagedst);
+	}
+
+	# Recreate 'building' directory ready for next build
+	&util::mk_dir($full_buildingname);
+    }
+
+    communicate_single_line($full_tmpname,"Done");
+    close(LOGOUT);
+    return "success";
+}
+
+
+sub main
+{
+    # get arguments
+    my $dirname = $args->{'bc1dirname'};
+    if (!defined($dirname))
+    {
+	my $mess = "Directory name for collection missing.";
+	print STDERR "$mess\n";
+	return;
+    }
+
+    my $tmpname = $args->{'bc1tmpname'};
+    if (!defined($tmpname))
+    {
+	my $mess = "Temporary name for building communication missing.";
+	print STDERR "$mess\n";
+	return;
+    }
+
+    my $full_tmpname
+	= &util::filename_cat($ENV{'GSDLHOME'},"tmp",$tmpname);
+
+    communicate_single_line($full_tmpname,"Preparing to build.");
+
+    # Put lock on config file before any building is done as safe
+    # guard against any concurrent operations on this collection.
+    #--
+
+    my $full_dirname 
+	= &util::filename_cat($ENV{'GSDLHOME'},"collect",$dirname);
+    my $cfg_filename 
+	= &util::filename_cat($full_dirname,"etc","collect.cfg");
+
+    # do requested stages for building
+    my $result = do_build($full_dirname,$dirname,$args);
+    return if ($result ne "success");
+
+    my $mess_url = "$args->{'httpbuild'}&bca=mess&bc1dirname=$dirname";
+    print "Location: $mess_url&head=_headdone_&mess=_messdonebuildcol_\n\n";
+    print "done\n"; # in tmp file
+}
+
+&main();
Index: /main/tags/2.25/gsdl/cgi-bin/webpage_buildstatus.pl
===================================================================
--- /main/tags/2.25/gsdl/cgi-bin/webpage_buildstatus.pl	(revision 21064)
+++ /main/tags/2.25/gsdl/cgi-bin/webpage_buildstatus.pl	(revision 21064)
@@ -0,0 +1,103 @@
+#!perl -w
+
+###########################################################################
+#
+# webpage_buildstatus.pl --
+# A component of the Greenstone digital library software
+# from the New Zealand Digital Library Project at the 
+# University of Waikato, New Zealand.
+#
+# Copyright (C) 1999 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.
+#
+###########################################################################
+
+# This program is a webpage wrapper that checks on the progress of 
+#  import.pl and buildcol.pl processes
+
+use CGI;
+use GSDLHOME;
+
+require util;
+require webpageutil;
+
+sub parse_cgiargs
+{
+    # get arguments
+    my $cgi = new CGI;
+    my %args = ();
+
+    foreach $p ($cgi->param()) 
+    { 
+	$args{$p} = $cgi->param($p);
+    }
+
+    return \%args;
+}
+
+
+sub main
+{
+    # get arguments
+    my $args = parse_cgiargs();
+    my $bc1finished = 0;
+
+    my $tmpname = $args->{'bc1tmpname'};
+    if (!defined($tmpname))
+    {
+	my $mess = "Temporary filename for building communication not defined.";
+	$bc1finished = 1;
+	&webpageutil::status_location($args,$mess,$tmpname,$bc1finished);
+	return;
+    }
+
+    my $full_tmpname = &util::filename_cat($ENV{'GSDLHOME'},"tmp");
+
+    if (!-d $full_tmpname) {
+	mkdir ($full_tmpname, 0777);
+    }
+
+    $full_tmpname = &util::filename_cat($full_tmpname, $tmpname);
+
+    if (open(TMPIN,"<$full_tmpname"))
+    {
+	my @tmp_text = ();
+	my $line;
+	while (defined($line=<TMPIN>))
+	{
+	    chomp $line;
+	    push(@tmp_text,$line);
+	}
+	my $mess = join(" ",@tmp_text);
+	$bc1finished = 1 if ($mess eq "Done");
+	$bc1finished = -1 if ($mess =~ m/^Error:/);
+	# escape backslashes so they don't vanish from printed filenames
+	$mess =~ s/\\/\\\\/g;
+	&webpageutil::status_location($args,$mess,$tmpname,$bc1finished);
+
+	close(TMPIN);
+    }
+    else
+    {
+	my $mess = "Unable to open for reading temporary file: $full_tmpname.";
+	$bc1finished = 1;
+	&util::rm($full_tmpname);
+	&webpageutil::status_location($args,$mess,$tmpname,$bc1finished);
+	return;
+    }
+}
+
+&main();
Index: /main/tags/2.25/gsdl/cgi-bin/webpage_delcol.pl
===================================================================
--- /main/tags/2.25/gsdl/cgi-bin/webpage_delcol.pl	(revision 21064)
+++ /main/tags/2.25/gsdl/cgi-bin/webpage_delcol.pl	(revision 21064)
@@ -0,0 +1,107 @@
+#!perl -w
+
+###########################################################################
+#
+# webpage_delcol.pl --
+# A component of the Greenstone digital library software
+# from the New Zealand Digital Library Project at the 
+# University of Waikato, New Zealand.
+#
+# Copyright (C) 1999 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.
+#
+###########################################################################
+
+# This program is a webpage wrapper that deletes the named collection
+
+use CGI;
+use GSDLHOME;
+
+require util;
+require webpageutil;
+
+sub parse_cgiargs
+{
+    # get arguments
+    my $cgi = new CGI;
+    my %args = ();
+    
+    foreach $p ($cgi->param()) 
+    { 
+	$args{$p} = $cgi->param($p);
+    }
+
+    return \%args;
+}
+
+
+
+sub main
+{
+    # get arguments
+    my $args = parse_cgiargs();
+
+    my $dirname = $args->{'bc1dirname'};
+    if (!defined($dirname))
+    {
+	# directory name derived from the collection name missing
+	my $mess = "Directory name derived from the collection name missing.";
+	&webpageutil::error_location($args,$mess);
+	return;
+    }
+
+    my $delete_area = $args->{'bc1deletearea'};
+
+    if ($delete_area eq "all")
+    {
+	# delete all files
+	my $col_dir = &util::filename_cat($ENV{'GSDLHOME'},"collect",$dirname);
+	&util::rm_r($col_dir);
+
+    }
+    elsif ($delete_area eq "import")
+    {
+
+	my $collectdir =  &util::filename_cat($ENV{'GSDLHOME'},"collect",$dirname);
+	my $import_dir = &util::filename_cat($collectdir,"import");
+	my $archives_dir = &util::filename_cat($collectdir,"archives");
+	&util::rm_r($import_dir,$archives_dir);
+	&util::mk_dir($import_dir);
+    }
+    elsif ($delete_area eq "archives")
+    {
+	my $collectdir =  &util::filename_cat($ENV{'GSDLHOME'},"collect",$dirname);
+	my $archives_dir = &util::filename_cat($collectdir,"archives");
+	&util::rm_r($archives_dir);
+    }
+    else
+    {
+	# unrecoginised area to delete
+	my $mess = "Unrecognised area to delete: $delete_area";
+	&webpageutil::error_location($args,$mess);
+	return;
+    }
+
+    my $mess_url = "$args->{'httpbuild'}&bca=mess";
+    $mess_url .= "&bc1dirname=$dirname" if ($delete_area ne "all");
+    print "Location: $mess_url&head=_headdone_&mess=_messdonedelcol_\n\n";
+    return;
+
+}
+
+&main();
+
+
Index: /main/tags/2.25/gsdl/cgi-bin/webpage_editcol.pl
===================================================================
--- /main/tags/2.25/gsdl/cgi-bin/webpage_editcol.pl	(revision 21064)
+++ /main/tags/2.25/gsdl/cgi-bin/webpage_editcol.pl	(revision 21064)
@@ -0,0 +1,109 @@
+#!perl -w
+
+###########################################################################
+#
+# webpage_editcol.pl --
+# A component of the Greenstone digital library software
+# from the New Zealand Digital Library Project at the 
+# University of Waikato, New Zealand.
+#
+# Copyright (C) 1999 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.
+#
+###########################################################################
+
+# This program is a webpage wrapper for saving an edited config file
+
+package webpage_editcol;
+
+use CGI;
+use GSDLHOME;
+use gflock;
+
+require util;
+require webpageutil;
+
+sub parse_cgiargs
+{
+    # get arguments
+    my $cgi = new CGI;
+    my %args = ();
+
+    foreach $p ($cgi->param()) 
+    { 
+	$args{$p} = $cgi->param($p);
+    }
+
+    return \%args;
+}
+
+
+
+sub main
+{
+    # get arguments
+    my $args = parse_cgiargs();
+
+    my $dirname = $args->{'bc1dirname'};
+    if (!defined($dirname))
+    {
+	# directory name derived from the collection name missing
+	my $mess = "Directory name for collection missing.";
+	&webpageutil::error_location($args,$mess);
+	return;
+    }
+
+    my $cfg_filename 
+	= &util::filename_cat($ENV{'GSDLHOME'},"collect",$dirname,"etc","collect.cfg");
+
+    if (open(CFGOUT,">$cfg_filename"))
+    {
+	binmode (CFGOUT); # windows
+	
+	if (&gflock::lock (webpage_editcol::CFGOUT)) {
+	    my $cfg_text = $args->{'bc1cfgfile'};
+	    print CFGOUT "$cfg_text";
+	    &gflock::unlock (webpage_editcol::CFGOUT);
+	    close(CFGOUT);
+	}
+	else
+	{
+	    # problem locking file
+	    my $mess = "Unable to lock configuration file: $cfg_filename";
+	    &webpageutil::error_location($args,$mess);
+	    return;
+	}
+    }
+    else
+    {
+	# unable to open configuration file for writing
+	my $mess = "Unable to open for writing configuration file: $cfg_filename";
+	&webpageutil::error_location($args,$mess);
+	return;
+    }
+
+    my $mess_url = "$args->{'httpbuild'}&bca=mess&bc1dirname=$dirname";
+    print "Location: $mess_url&head=_headdone_&mess=_messdoneeditcol_\n\n";
+    return;
+
+}
+
+&main();
+
+
+
+
+
Index: /main/tags/2.25/gsdl/cgi-bin/webpage_mkcol.pl
===================================================================
--- /main/tags/2.25/gsdl/cgi-bin/webpage_mkcol.pl	(revision 21064)
+++ /main/tags/2.25/gsdl/cgi-bin/webpage_mkcol.pl	(revision 21064)
@@ -0,0 +1,231 @@
+#!perl -w
+
+###########################################################################
+#
+# webpage_mkcol.pl --
+# A component of the Greenstone digital library software
+# from the New Zealand Digital Library Project at the 
+# University of Waikato, New Zealand.
+#
+# Copyright (C) 1999 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.
+#
+###########################################################################
+
+# This program is a webpage wrapper to the mkcol.pl process
+
+package webpage_mkcol;
+
+use CGI;
+use GSDLHOME;
+use gflock;
+
+require util;
+require webpageutil;
+
+sub parse_cgiargs
+{
+    # get arguments
+    my $cgi = new CGI;
+    my %args = ();
+    
+    foreach $p ($cgi->param()) 
+    { 
+	$args{$p} = $cgi->param($p);
+    }
+
+    return \%args;
+}
+
+
+sub get_unique_dirname
+{
+    my ($args) = @_;
+
+    my $dirname = "";
+
+    my $fullname = $args->{'bc1fullname'};
+    my $in_gsdl_area = $args->{'bc1ingsdlarea'};
+    my $copy_dir = $args->{'bc1copydir'};
+
+    # if inputdir is in gsdl area then need to extract existing dirname
+    if (($in_gsdl_area eq "yes") && (($copy_dir eq "no")))
+    {
+	my $inputdir = $args->{'bc1inputdir'};
+	my $dirsep_re = &util::get_re_dirsep();
+	my @id_split = split(/$dirsep_re/,$inputdir);
+	while (@id_split>0)
+	{
+	    $dirname = pop(@id_split);
+	    last if ($dirname =~ m/(import|building)/i);
+	}
+	$dirname = pop(@id_split);
+
+	# check to see if config file already exists
+	my $cfg_filename
+	    = &util::filename_cat($ENV{'GSDLHOME'},"collect",$dirname,
+				 "etc","collect.cfg");
+	if (-e $cfg_filename)
+	{
+	    &webpageutil::error_location($args,"_messconfigexists_");
+	    return "";
+	}	
+    }
+    else
+    {
+	# clean up input for heuristic that derives directory name for a
+	# new collection
+	$fullname =~ s/\s+/ /g;
+	$fullname =~ tr/[A-Z]/[a-z]/;
+	my @fn_split = split(" ",$fullname);
+	map { $_ =~ s/\W//g } @fn_split; # remove any non-word characters
+	
+	my $no_words = scalar(@fn_split);
+	if ($no_words == 0)
+	{
+	    &webpageutil::error_location($args,"_messnofn_");
+	    return "";
+	}
+	
+	my $use_words = ($no_words<=6) ? $no_words : 6;
+	my $substr_len = int(6/$use_words);
+	
+	my $i;
+	for ($i=0; $i<$use_words; $i++)
+	{
+	    $dirname .= substr($fn_split[$i],0,$substr_len);
+	}
+	
+	# check to see if dirname is unique
+	my $fulldirname 
+	    = &util::filename_cat($ENV{'GSDLHOME'},"collect",$dirname);
+	if (-e $fulldirname)
+	{
+	    my $version = 0;
+	    do
+	    {
+		$version++;
+		$fulldirname 
+		    = &util::filename_cat($ENV{'GSDLHOME'},"collect",
+					  "${dirname}v$version");
+
+	    } while (-e $fulldirname);
+
+	    $dirname = "${dirname}v$version";
+	}
+    }
+
+    return $dirname;
+}
+
+
+sub main
+{
+    # get arguments
+    my $args = parse_cgiargs();
+    
+    # get unique dirname
+    my $unique_dirname = get_unique_dirname($args);
+    if ($unique_dirname ne "")
+    {
+	my $fullname      = $args->{'bc1fullname'};
+	my $contact_email = $args->{'bc1contactemail'};		
+	my $about_desc    = $args->{'bc1aboutdesc'};
+	my $src_format    = $args->{'bc1srcformat'};
+	my $input_dir     = $args->{'bc1inputdir'};
+	my $copy_dir      = $args->{'bc1copydir'};
+	my $in_gsdl_area  = $args->{'bc1ingsdlarea'};
+	my $acronyms      = $args->{'bc1acronyms'};
+
+	my $cmd = "perl ";
+	$cmd .= &util::filename_cat($ENV{'GSDLHOME'}, "bin", "script", "mkcol.pl");
+	$cmd .= " -title   \"$fullname\"";
+	$cmd .= " -creator $contact_email";
+	$cmd .= " -about   \"$about_desc\"";
+	$cmd .= " -plugin  \"GMLPlug\"";
+	if ($src_format eq "HTML") {
+	    $cmd .= " -plugin  \"HTMLPlug -keep_head\"";
+	} else {
+	    $cmd .= " -plugin  \"${src_format}Plug\"";
+	}
+	$cmd .= " -plugin  \"ArcPlug\"";
+	$cmd .= " -plugin  \"RecPlug\"";
+	$cmd .= " $unique_dirname";
+
+	my $status = system($cmd);
+	$status /= 256;
+
+	if ($status == 0)
+	{
+	    # append copydir and input_dir to end of collect.cfg we'll also
+	    # append DocumentUseHTML if processing HTML docs
+	    my $cfg_filename 
+		= &util::filename_cat($ENV{'GSDLHOME'},"collect",$unique_dirname,
+				      "etc","collect.cfg");
+	    if (open(CFGAPP,">>$cfg_filename"))
+	    {
+		if (&gflock::lock (webpage_mkcol::CFGAPP)) {
+		    print CFGAPP "\n";
+
+		    if ($src_format eq "HTML") {
+			print CFGAPP "format\tDocumentUseHTML\ttrue\n\n";
+		    }
+
+		    print CFGAPP "building\tinputdir\t\"$input_dir\"\n";
+		    print CFGAPP "building\tcopydir\t\t$copy_dir\n";
+		    print CFGAPP "building\tingsdlarea\t$in_gsdl_area\n";
+		    &gflock::unlock (webpage_mkcol::CFGAPP);
+		    close(CFGAPP);
+		}
+		else
+		{
+		    # problem locking file
+		    my $mess = "Unable to lock collection";
+		    $mess .= " configuration file: $cfg_filename";
+		    &webpageutil::error_location($args,$mess);
+		    close(CFGAPP);
+		    return;
+		}
+	    }
+	    else
+	    {
+		# problem
+		my $mess = "Unable to append to collection";
+		$mess .= " configuration file: $cfg_filename";
+		&webpageutil::error_location($args,$mess);
+		return;
+	    }
+	}
+	else
+	{
+	    my $mess = "An error was encountered: error status = $status";
+	    &webpageutil::error_location($args,$mess);
+	    return;
+	}
+    }
+    else
+    {
+	my $mess = "No unique directory name specified for collection";
+	&webpageutil::error_location($args,$mess);
+	return;
+    }
+
+    my $mess_url = "$args->{'httpbuild'}&bca=mess&bc1dirname=$unique_dirname";
+    print "Location: $mess_url&head=_headdone_&mess=_messdonenewcol_\n\n";
+
+}
+
+&main();
Index: /main/tags/2.25/gsdl/collect/demo/etc/mags.txt
===================================================================
--- /main/tags/2.25/gsdl/collect/demo/etc/mags.txt	(revision 21064)
+++ /main/tags/2.25/gsdl/collect/demo/etc/mags.txt	(revision 21064)
@@ -0,0 +1,15 @@
+CERES                                                              1  CERES
+"Food and Nutrition Bulletin"                                      2  "Food and Nutrition Bulletin"
+"The Courier"                                                      3  "The Courier"
+"SPORE Bulletin"                                                   4  "SPORE Bulletin"
+"Boiling Point"                                                    5  "Boiling Point"
+"Developing Ideas"                                                 6  "Developing Ideas"
+"GATE Magazine"                                                    7  "GATE Magazine"
+"Go Between"                                                       8  "Go Between"
+"Basin - News"                                                     9  "Basin - News"
+"HDD-(PHN)FLASH, newsletter on Population, Health and Nutrition"  10  "HDD-(PHN)FLASH, newsletter on Population, Health and Nutrition"
+"IDRC Reports"                                                    11  "IDRC Reports"
+"New and Noteworthy in Nutrition"                                 12  "New and Noteworthy in Nutrition"
+Seedling                                                          13  Seedling
+"Soft Energy Worldwide"                                           14  "Soft Energy Worldwide"
+"Sustainable energy News"                                         15  "Sustainable energy News"
Index: /main/tags/2.25/gsdl/collect/demo/etc/org.txt
===================================================================
--- /main/tags/2.25/gsdl/collect/demo/etc/org.txt	(revision 21064)
+++ /main/tags/2.25/gsdl/collect/demo/etc/org.txt	(revision 21064)
@@ -0,0 +1,60 @@
+accu	1	ACCU
+ag21	2	"Agenda 21"
+bgz	3	"BASIN - GTZ - SKAT"
+bostid	4	BOSTID
+cps	5	CPS
+cpas	6	"CTA Spore"
+cf	7	"Commonwealth Foundation"
+csu	8	"Computer Science Unplugged"
+dcs	9	"Development Consultancy Services"
+1echo	0	E.C.H.O
+ecc	11	"EC Courier"
+ecdg8	12	"EC DG8"
+echo	13	"Educational Concerns for Hunger Organization"
+fao	14	FAO
+faobfs	15	"FAO Better Farming series"
+ceres	16	"FAO Ceres"
+ff	17	"Food First"
+ghp	18	GHP
+grain	19	GRAIN
+gret	20	GRET
+gtz	21	GTZ
+gate	22	"GTZ GATE Magazine"
+habitat	23	Habitat
+idrc	24	IDRC
+iisd	25	IISD
+irma	26	IRMA
+bp	27	"ITDG Boiling Point"
+itdg	28	"ITDG Food Chain"
+iis	29	"Indian Institute of Sciences"
+chandra	30	"Individual Contributor Chandrakant"
+alkire	31	"Individual Contributor S. Alkire"
+inforse	32	Inforse
+iirr	33	"International Institute for Rural Reconstruction (IIRR)"
+msf	34	MSF
+ngls	35	NGLS
+norad	36	NORAD
+nri	37	NRI
+nsc	38	"North South Centre"
+op	39	"Orbi Pharma"
+oxfam	40	Oxfam
+pace	41	PACE
+paho	42	PAHO
+pc	43	"Peace Corps"
+pelum	44	Pelum
+sida	45	SIDA
+skat	46	SKAT
+tool	47	Tool
+un	48	UN
+unesco	49	UNESCO
+unicef	50	UNICEF
+fnb	51	"UNU Food and Nutrition Bulletin"
+unu	52	"UNU United Nations University"
+vso	53	VSO
+who	54	WHO
+wwf	55	WWF
+wwsf	56	WWSF
+wa	57	"Water Aid"
+winrock	58	Winrock
+ws	59	Workshop
+wb	60	"World Bank"
Index: /main/tags/2.25/gsdl/collect/demo/etc/sub.txt
===================================================================
--- /main/tags/2.25/gsdl/collect/demo/etc/sub.txt	(revision 21064)
+++ /main/tags/2.25/gsdl/collect/demo/etc/sub.txt	(revision 21064)
@@ -0,0 +1,245 @@
+1        1        "General reference"
+1.2      1.2      "Dictionaries, glossaries, language courses, terminology (all languages)"
+2        2        "Sustainable Development, International cooperation, Projects; NGO, Organizations, Poverty and Hunger Alleviation, Basic Human Needs"
+2.1      2.1      "Development policy and theory, international cooperation, national planning, national plans"
+2.2      2.2      "Development, national planning, national plans"
+2.3      2.3      "Project planning and evaluation (incl. project management and dissemination strategies)"
+2.4      2.4      "Regional development and planning incl. regional profiles"
+2.5      2.5      "Nongovernmental organizations (NGOs) in general, self- help organizations (their role in development). For specific organizations such as women's or peasants' see respective class within 06."
+2.6      2.6      "Organizations, institutions, United Nations (general, directories, yearbooks, annual reports, etc.)"
+2.6.1    2.6.1    "United Nations"
+2.6.2    2.6.2    "International organizations"
+2.6.3    2.6.3    "Regional organizations"
+2.6.5    2.6.5    "European Community - European Union"
+2.7      2.7      "Sustainable Development, Development models and examples; Best practices (general)"
+2.8      2.8      "Basic Human Needs"
+2.9      2.9      "Hunger and Poverty Alleviation"
+3        3        "Economics, Economic policies, Finance, Trade, Structural Adjustment"
+3.2      3.2      "Economic and social situation, economic policy, country reports (incl. national statistical yearbooks)"
+3.4      3.4      "Industrial economics, industrial development, foreign investment (incl. investment policy, investment promotion) incl.multinational corporations"
+3.6     3.6       "Trade and commerce, Export policy and reglementations"
+3.7     3.7       "Tourism (economic and social aspects)"
+3.8     3.8       "Labour economics"
+3.8.1   3.8.1     "Employment policy"
+3.10    3.10      "Structural Adjustment"
+4       4         "Business, Micro-entreprises, Management, Marketing, Finance, Microfinance, Cooperatives"
+4.1     4.1       "Business economics (general works, textbooks)"
+4.2     4.2       "Microeconomic planning techniques, Micro-entreprises"
+4.3     4.3       "Management and personnel management"
+4.4     4.4       "Business organization and administration, office management"
+4.5     4.5       "Marketing and commercialisation, export (from businesses viewpoint)"
+4.6     4.6       "Accounting"
+4.7     4.7       "Finance and microfinance / microcredit"
+4.8     4.8       "Cooperatives, cooperative movement"
+4.8.1   4.8.1     "Agricultural cooperatives"
+4.8.4   4.8.4     "Housing cooperatives"
+4.8.5   4.8.5     "Other specific cooperatives"
+5       5         "Politics, Public administration, Law and Legislation, Peace, Human Rights"
+5.2     5.2       "Public administration, Tasks of councillors"
+5.4     5.4       "Human rights, humanitarian law"
+5.4     5.5       "Disarmament, Peace, Conflict and Conflict Resolutions"
+6       6         "Society, Culture, Community, Woman, Youth, Population"
+6.1     6.1       "Social sciences, sociology (works comprising several subgroups) incl. participatory research and training"
+6.2     6.2       "Society, social structure, social change, social services, social movements, social groups, Minorities"
+6.3     6.3       "Community development, community organizing"
+6.4     6.4       "Women, gender and development, women's organizations"
+6.5     6.5       "Children and youth (youth centres)"
+6.6     6.6       "Demography and population"
+6.7     6.7       "Philosophy"
+6.8     6.8       "History, Cultural Heritage and Language"
+6.9     6.9       "Psychology"
+6.10    6.10      "Anthropology, ethnology"
+6.11    6.11      "Religion - Spirituality - Yoga"
+6.12    6.12      "Art, Literature, Creativity, Traditional Cultures, Fashion"
+7       7         "Education and Training"
+7.1     7.1       "Education and training (general works, theories, methods)"
+7.3     7.3       "Teaching methods and aids"
+7.4     7.4       "Adult education, Literacy training"
+7.5     7.5       "Early education, Primary education, Secondary education"
+7.6     7.6       "Specific courses or subjects, educational games"
+7.7     7.7       "Higher education"
+7.8     7.8       "Vocational, professional and practical training - for specific training- curricula, textbooks- see specific subject."
+7.9     7.9       "Health Education and Training (see under health and Nutrition)"
+7.10    7.10      "Environmental education, Global education, Psychological and assertiveness education, Non-formal education etc"
+7.11    7.11      "Language education"
+7.12    7.12      "Specialised education: see also under the subject"
+7.13    7.13      "Teacher Training"
+8       8         "Communication, Information and Documentation"
+8.1     8.1       "Communication, telecommunication, mass communication, mass media, film-making"
+8.2     8.2       "Information for development, Information transfer, Information policy"
+8.3     8.3       "Documentation, Library science and management, see also RAMP studies under 08.06"
+8.4     8.4       "Information technology, Computer science, Computer use, Use of computers for developing countries"
+8.5     8.5       "Internet, e-mail"
+8.6     8.6       "Records and Archives Management Programme (RAMP) of  UNESCO, Archive Management"
+9       9         "Transport"
+9.1     9.1       "Transport (rural and urban) (general works)"
+9.2     9.2       "Land transport"
+10      10        "Science, Research and Technology"
+10.1    10.1      "Natural science, technology, engineering, research and development, research methods and theory (general works, directories, encyclopedias)"
+10.2    10.2      "Transfer of technology and scientific cooperation"
+10.2.1  10.2.1    "Technology transfer and scientific cooperation for developing countries"
+10.3    10.3      "Appropriate/ Alternative/ Applied technology (AT), traditional, intermediate technology,  economic and social aspect, directories"
+10.8    10.8      "Biology"
+10.9    10.9      "Biotechnology, genetic engineering"
+10.10   10.10     "Medicine and Health : science and research"
+11      11        "Ecology, Biodiversity, Natural resources, Environment, Waste Disposal"
+11.1    11.1      "Natural resources, geography"
+11.1.1  11.1.1    "Climate, weather, meteorology . Climatologic Changes. Global warming"
+11.2    11.2      "Ecology, environmental policy, eco- development studies"
+11.3    11.3      "Resources conservation, environmental protection, biodiversity"
+11.3.1  11.3.1    "Arid zones, desertification"
+11.3.2  11.3.2    "Nature reserve, game reserve"
+11.3.3  11.3.3    "Rainforests and rainforest conservation"
+11.3.4  11.3.4    "Biodiversity conservation"
+11.4    11.4      "Erosion and erosion control - for techniques see agriculture and forestry."
+11.5    11.5      "Pollution, Pollution control, Pesticides, Biological monitoring, Asbestos"
+11.5.2  11.5.2    "Water pollution"
+11.5.4  11.5.4    "Pesticide pollution"
+11.5.5  11.5.5    "Asbestos"
+11.6    11.6      "Solid waste disposal"
+11.7    11.7      "Environmental Handbook of GTZ-BMZ"
+12      12        "Water, Sanitation and Sewage Disposal"
+12.1    12.1      "Water and sanitation, hydrology"
+12.2    12.2      "Water resources (surface water, groundwater)"
+12.3    12.3      "Hydraulic structures (dams, intakes, wells, ponds, cisterns)"
+12.4    12.4      "Pumps and other water- lifting devices"
+12.5    12.5      "Water supply and storage"
+12.6    12.6      "Water treatment and purification (biological, chemical, physical)"
+12.7    12.7      "Sanitation. Waste water and sewage disposal"
+13      13        "Health, Nutrition, Medicine"
+13.1    13.1      "Health (general works, incl. health economics and sociology, health statistics, health and community development)"
+13.1.1  13.1.1    "Health planning and policy"
+13.1.6  13.1.6    "Disasters, medicine in humanitarian emergencies"
+13.2    13.2      "Food, Nutrition and Malnutrition"
+13.3    13.3      "Family health,  Mother and Child care, Family planning, Pregnancy and Childbirth"
+13.4    13.4      "Community Health, Health Care Delivery, Extension workers and training"
+13.5    13.5      "Medicine, Clinical Care, Diseases, Hygiene, Emergencies (treatment of specific diseases, injuries, accidents)"
+13.6    13.6      "Health Education, Promotion, Prevention, AIDS Prevention, Safety, Books covering multiple health dimensions"
+13.7    13.7      "Production and use of medicines, essential drugs"
+13.7.1  13.7.1    "Pharmaceuticals and essential drugs"
+13.7.2  13.7.2"   "Herbal medicines, medicinal plants"
+13.8    13.8      "Health material and equipment; aids for disabled people"
+13.9    13.9      "Medical an nutrition research papers, medical and nutrition scientific studies, specialised tropical medicine publications"
+14      14        "Agriculture and Food Processing"
+14.1    14.1      "Agriculture (general works), Economics,  Policies, Development, Research, Management"
+14.1.1  14.1.1    "Land reform, Settlements, Rural Development and related topics"
+14.1.2  14.1.2    "Agricultural training and education"
+14.1.3  14.1.3    "Agricultural Science and Research"
+14.1.4  14.1.4    "Rural and Farm management"
+14.1.5  14.1.5    "Policies and Planning in agriculture"
+14.1.6  14.1.6    "Biotechnology and agriculture"
+14.1.7  14.1.7    "Agricultural finance systems"
+14.2    14.2      "Agricultural production systems (shifting cultivation, wet- land farming, dry- land farming, agroforestry), Sustainable Agriculture"
+14.3    14.3      "Organic farming, Eco-farming"
+14.4    14.4      "Agricultural implements, tools and machinery (incl. mechanization, agricultural transport) - for implements specific to particular plants see respective plant."
+14.5    14.5      "Soil and land management, improvement and treatment (incl. terracing, erosion control techniques, rangeland improvement)"
+14.6    14.6      "Irrigation and drainage - for hydraulic structures see 12.03."
+14.7    14.7      "Fertilization and composting"
+14.8    14.8      "Storage and packaging of agricultural products, Post-Harvest management"
+14.9    14.9      "Agricultural waste processing - for energy use see 20.06."
+14.10   14.10     "Food processing and preservation"
+14.10.2 14.10.2   "Food drying (all kinds)"
+14.10.3 14.10.3   "Fermented Foods"
+14.10.4 14.10.4   "Oil production and processing"
+14.12   14.12     "Better Farming series of FAO and INADES"
+15      15        "Plant and Crop Production, Protection, and Processing"
+15.1    15.1      "Plant/crop production and processing, vegetable gardening, botany (general works, publications comprising several plants and practical how to books, intercropping)"
+15.2    15.2      "Plant protection (incl. insecticidinal plants), Pests and Pest Control, Integrated Pest Management"
+15.4    15.4      "Cereals (rice, corn/maize, millet, sorghum, wheat, etc.)"
+15.5    15.5      "Starchy crops and root crops (cassava, potatoes, etc.)"
+15.6    15.6      "Oil- producing plants, vegetable oil, nuts"
+15.7    15.7      "Garden vegetables, legumes, mushrooms"
+15.8    15.8      "Fruits and wine (bananas, mango's, apple's etc)"
+15.10   15.10     "Coffee, Tea, Cocoa, Coca and other stimulants"
+15.12   15.12     "Rubber, resin, wax plants"
+15.14   15.14     "Fodder and pasture plants"
+15.15   15.15     "Other plants/crops, intercropping (for intercropping, see also under 15.01)"
+16      16        "Animal Husbandry and Animal Product Processing"
+16.1    16.1      "Animal husbandry (general,works) incl. animal feed, works covering several aspects and animals, zoology, see also other animals 6.11"
+16.2    16.2      "Veterinary medicine, animal diseases"
+16.3    16.3      "Animal traction (excl. implements), animal training"
+16.5    16.5      "Cattle"
+16.6    16.6      "Goats, sheep, camels"
+16.8    16.8      "Rabbits and guinea pigs"
+16.9    16.9      "Poultry, ducks and other birds"
+16.10   16.10     "Beekeeping and honey extraction"
+16.11   16.11     "Other animals (micro-livestock, little known animals, silkworms, reptiles, frogs, snails, game, etc.)"
+16.12   16.12     "Animal product processing - for processing of wool and silk see 19.08 - for processing of leather see 19.09"
+16.12.2 16.12.2   "Milk and egg processing (dairy, cheese)"
+17      17        "Fishery and Aquaculture"
+17.1    17.1      "Fishery and aquaculture (general works), fishery resources"
+17.2    17.2      "Fishing techniques and equipment"
+17.3    17.3      "Aquaculture, fish farming, fish production (fish ponds, feeding, etc.)"
+17.6    17.6      "Fishery product processing, storage, and marketing"
+18      18        "Forestry and Agroforestry"
+18.1    18.1      "Forestry, general works, Forest conservation"
+18.2    18.2      "Reforestation - for erosion control see 11.04 and 14.05."
+18.3    18.3      "Cultivation and conservation (nurseries), protection and pest resistance"
+18.4    18.4      "Forests, Cloud Forests"
+18.5    18.5      "Specific trees and other forestry plants (incl. bamboo)"
+18.6    18.6      "Agroforestry"
+18.7    18.7      "Sustainable exploitation and commercialisation of forest products"
+19      19        "Industry, Manufacture and Services"
+19.1    19.1      "Industry (general works, textbooks, directories) incl. industrial planning"
+19.2    19.2      "Industrial training, consulting - for vocational training see 07.08."
+19.3    19.3      "Small- scale industry, handicraft, home industry"
+19.4    19.4      "Industrial profiles and studies covering several sectors"
+19.5    19.5      "Recycling and solid waste services"
+19.7    19.7      "Mining and quarrying"
+19.8    19.8      "Textile industry, manufacture of wearing apparel (incl. processing of natural fibres)"
+19.11   19.11     "Pulp and paper products (incl. printing and bookbinding)"
+19.12   19.12     "Chemical and chemical products industry incl. soap and candle production, salt"
+19.13   19.13     "Pottery, ceramics, glass and glass products (incl. jewellery, buttons, chalk)"
+19.14   19.14     "Metal industry"
+19.14.1 19.14.1   "Forging and blacksmithing"
+19.17   19.17     "Packing Industry"
+20      20        "Energy , Renewable energies, Household energy"
+20.1    20.1      "Energy and power (general works) incl. energy per country, energy savings, and publications covering several sources of energy, rural energy"
+20.2    20.2      "Transformation, distribution and storage of energy and electricity"
+20.2.1  20.2.1    "Rural electrification"
+20.3    20.3      "Conventional energy resources (oil, petroleum, coal, natural gas, peat, nuclear energy)"
+20.4    20.4      "Renewable energy resources"
+20.4.1  20.4.1    "Bio-mass (general works)"
+20.5    20.5      "Wood and charcoal (incl. kilns and activated charcoal)"
+20.6    20.6      "Solid fuels from agricultural wastes and other organic material (pellets, eco- bricks, briquets)"
+20.7    20.7      "Biogas (incl. biogas equipment)"
+20.8    20.8      "Cookstoves, Fuel-saving cookstoves, Household Energy"
+20.10   20.10     "Alcohol and other liquid fuels"
+20.11   20.11     "Solar energy, photovoltaic energy"
+20.12   20.12     "Wind energy"
+20.13   20.13     "Hydropower"
+20.14   20.14     "New Energy technology and research, Planetary Association for Clean Energy publications"
+21      21        "Settlements, Housing, Building -  Infrastructure Construction (Roads etc)"
+21.1    21.1      "Settlements and housing: general works incl. low- cost housing, planning techniques, surveying, etc."
+21.2    21.2      "Urban settlements (urban housing programmes, urbanization, squatters, slums, slum improvement)"
+21.3    21.3      "Rural settlements"
+21.4    21.4      "Architecture and Building design"
+21.4.2  21.4.2    "Solar and climate responsive architecture"
+21.5    21.5      "Construction materials"
+21.6    21.6      "Building machinery and equipment"
+21.7    21.7      "Building and construction (building components, construction techniques)"
+21.7.1  21.7.1    "Roofing"
+21.9    21.9      "Civil engineering (roads, bridges, etc.) - Road Construction"
+22      22        "Disasters, Disaster Mitigation, Humanitarian and Food Aid, Humanitarian Interventions, Refugees"
+22.1    22.1      "Disasters and Disaster Mitigation, Organisation"
+22.2    22.2      "Humanitarian Aid, Food Aid"
+22.3    22.3      "Humanitarian Interventions and Conflicts"
+22.5    22.5      "Refugees"
+23      23        "Development Periodicals and Magazines"
+23.1    23.1      "BASIN-NEWS - Building Advisory Service and Information Network by GTZ- GATE, SKAT,  ITDG and CRATerre"
+23.2    23.2      "Boiling Point Newsletters on Household Energy of Intermediate Technology Development Group.and GTZ"
+23.3    23.3      "CERES - FAO Review on Agriculture and Development: 1976 - 1997"
+23.4    23.4      "Developing Ideas - Bi-monthly Digests by the International Institute for Sustainable Development"
+23.5    23.5      "ECHO's Human Development Notes by the Educational Concerns for Hunger network"
+23.6    23.6      "Food and Nutrition Bulletins 1978-1996 - United Nations University"
+23.7    23.7      "Food Chain, newsletters on Food Processing of Intermediate Technology Development Group."
+23.8    23.8      "GATE Development magazine of GTZ"
+23.9    23.9      "HDD-FLASH, newsletter on Population, Health and Nutrition of the Worldbank Human Development Department"
+23.10   23.10     "IDRC monthly and weekly reports 1993 - 1997"
+23.11   23.11     "New and Noteworthy in Nutrition - World Bank"
+23.12   23.12     "SEEDLING: bi-montly publication of GRAIN - Genetic Resources International - Spain"
+23.13   23.13     "SPORE Bulletins 1986-1996 of the CTA - Technical and Agricultural Centre of the European Union"
+23.14   23.14     "Sustainable Energy Newsletters of the INFORSE network"
+23.15   23.15     "The Courier ACP 1990 - 1996 Africa-Caribbean-Pacific - European Union"
+23.16   23.16     "The NGLS Magazine Go Between"
+24      24        "Resources, Product Lists, Catalogues, Internet Sites"
Index: /main/tags/2.25/gsdl/collect/demo/import/bostid/b17mie/b17mie.htm
===================================================================
--- /main/tags/2.25/gsdl/collect/demo/import/bostid/b17mie/b17mie.htm	(revision 21064)
+++ /main/tags/2.25/gsdl/collect/demo/import/bostid/b17mie/b17mie.htm	(revision 21064)
@@ -0,0 +1,7222 @@
+<HTML>
+<HEAD>
+<META HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=windows-1252">
+<META NAME="Generator" CONTENT="Microsoft Word 97">
+<TITLE>&lt;&lt;TOC1&gt;&gt; Microlivestock -  Little-Known Small Animals with a Promising Economic Future</TITLE>
+</HEAD>
+<BODY>
+
+<B><FONT FACE="Arial" SIZE=2><P>&lt;&lt;TOC1&gt;&gt; Microlivestock -  Little-Known Small Animals with a Promising Economic Future</P>
+</B><P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<B><P ALIGN="CENTER">&lt;&lt;TOC2&gt;&gt; Acknowledgments</P>
+</B><P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Board on Science and Tecnology for International Development </P>
+<P ALIGN="JUSTIFY">National Research Council</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">NOTICE: The project that is the subject of this report was approved by the Governing Board of the National Research Council, whose members are drawn from the councils of the National Academy of Sciences, the National Academy of Engineering, and the Institute of Medicine. The members of the committee responsible for the report were chosen for their special competence and with regard for appropriate balance.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">This report has been reviewed by a group other than the authors according to procedures approved by a Report Review Committee consisting of members of the National Academy of Sciences, the National Academy of Engineering, and the Institute of Medicine.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The National Academy of Sciences is a private, nonprofit, self-perpetuating society of distinguished scholars engaged in scientific and engineering research, dedicated to the furtherance of science and technology and to their use for the general welfare. Upon the authority of the charter granted to it by the Congress in 1863, the Academy has a mandate that requires it to advise the federal government on scientific and technical matters. Dr. Frank Press is president of the National Academy of Sciences.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The National Academy of Engineering was established in 1964, under the charter of the National Academy of Sciences, as a parallel organization of outstanding engineers. It is autonomous in its administration and in the selection of its members, sharing with the National Academy of Sciences the responsibility for advising the federal government. The National Academy of Engineering also sponsors engineering programs aimed at meeting national needs, encourages education and research, and recognizes the superior achievements of engineers. Dr. Robert M. White is president of the National Academy of Engineering.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The Institute of Medicine was established in 1970 by the National Academy of Sciences to secure the services of eminent members of appropriate professions in the examination of policy matters pertaining to the health of the public. The Institute acts under the responsibility given to the National Academy of Sciences by its congressional charter to be an adviser to the federal government and, upon its own initiative, to identify issues of medical care, research, and education. Dr. Samuel O. Their is president of the Institute of Medicine.</P>
+<P ALIGN="JUSTIFY">The National Research Council was organized by the National Academy of Sciences in 1916 to associate the broad community of science and technology with the Academy's purposes of furthering knowledge and advising the federal government. Functioning in accordance with general policies determined by the Academy, the Council has become the principal operating agency of both the National Academy of Sciences and the National Academy of Engineering in providing services to the government, the public, and the scientific and engineering communities. The Council is administered jointly by both Academies and the Institute of Medicine. Dr. Frank Press and Dr. Robert M. White are chairman and vice chairman, respectively, of the National Research Council.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The Board on Science and Technology for International Development (BOSTID) of the Office of International Affairs addresses a range of issues arising from the ways in which science and technology in developing countries can stimulate and complement the complex processes of social and economic development. It oversees a broad program of bilateral workshops with scientific organizations in developing countries and conducts special studies.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">This report was prepared by an ad hoc advisory panel of the Advisory Committee on Technology Innovation, Board on Science and Technology for International Development, Office of International Affairs, National Research Council. Staff support was funded by the Office of the Science Advisor, Agency for International Development, under Grant No. DAN-5538-G-SS-1023-00. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">PANEL ON MICROLIVESTOCK</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">RALPH W. PHILLIPS, Deputy Director General (Retired), Food and Agriculture Organization of the United Nations, Chairman </P>
+<P ALIGN="JUSTIFY">EDWARD S. AYENSU, Senior Advisor to the President, African Development Bank, Abidjan, Ivory Coast.</P>
+<P ALIGN="JUSTIFY">BONNIE V. BEAVER, Professor of Veterinary Medicine, Department of Small Animal Medicine and Surgery, Texas A&amp;M University, College Station, Texas, USA</P>
+<P ALIGN="JUSTIFY">KURT BENIRSCHKE, Professor of Pathology and Reproductive Medicine, University of California-San Diego, San Diego, California, USA</P>
+<P ALIGN="JUSTIFY">ROY D. CRAWFORD, Professor of Animal and Poultry Genetics, Department of Animal and Poultry Science, University of Saskatchewan, Saskatoon, Saskatchewan, Canada</P>
+<P ALIGN="JUSTIFY">TONY J. CUNHA, Distinguished Service Professor Emeritus, University of Florida, Gainesville, and Dean Emeritus, School of Agriculture, California Polytechnic University, Pomona, California, USA</P>
+<P ALIGN="JUSTIFY">DAVID E. DEPPNER, Director, New Forest Project, International Center, Washington, D.C., USA</P>
+<P ALIGN="JUSTIFY">ELIZABETH L. HENSON, Executive Director, American Minor Breeds Conservancy, Pittsboro, North Carolina, USA</P>
+<P ALIGN="JUSTIFY">DONALD L. HUSS, Menard, Texas, USA (Formerly Regional Animal Production Officer, FAO, Santiago, Chile)</P>
+<P ALIGN="JUSTIFY">DAVID R. LINCICOME, Guest Scientist, U.S. Department of Agriculture, Beltsville, Maryland, USA</P>
+<P ALIGN="JUSTIFY">THOMAS E. LOVEJOY, Assistant Secretary for External Affairs, Smithsonian Institution, Washington, D.C., USA</P>
+<P ALIGN="JUSTIFY">ARNE W. NORDSKOG, Professor Emeritus, Department of Animal Science, Iowa State University, Ames, Iowa, USA</P>
+<P ALIGN="JUSTIFY">LINDA M. PANEPINTO, Director, Miniature Swine Laboratory, Colorado State University, Fort Collins, Colorado, USA</P>
+<P ALIGN="JUSTIFY">KURT J. PETERS, Professor of Animal Breeding and Husbandry in the Tropics and Subtropics, University of Gottingen, Gottingen, West Germany, and Director of Research, International Livestock Centre for Africa, Addis Ababa, Ethiopia</P>
+<P ALIGN="JUSTIFY">JOHN A. PINO, Senior Fellow, National Research Council, Washington, D.C., USA</P>
+<P ALIGN="JUSTIFY">HUGH POPENOE, Director, International Program in Agriculture, University of Florida, Gainesville, Florida, USA</P>
+<P ALIGN="JUSTIFY">MICHAEL H. ROBINSON, Director, National Zoological Park, Washington, D.C., USA</P>
+<P ALIGN="JUSTIFY">KNUT SCHMIDT-NIELSON, James B. Duke Professor of Physiology, Department of Zoology, Duke University, Durham, North Carolina, USA </P>
+<P ALIGN="JUSTIFY">ALBERT E. SOLLOD, Associate Professor and Head, Section of International Veterinary Medicine, Tufts University, North Grafton, Massachusetts, USA </P>
+<P ALIGN="JUSTIFY">LEE M. TALBOT, Visiting Fellow, World Resources Institute, Washington, D.C., USA </P>
+<P ALIGN="JUSTIFY">CLAIR E. TERRILL, Sheep and Goat Scientist, U.S. Department of Agriculture, Beltsville, Maryland, USA </P>
+<P ALIGN="JUSTIFY">CHRISTEN M. WEMMER, Assistant Director for Conservation, National Zoological Park, Front Royal, Virginia, USA </P>
+<P ALIGN="JUSTIFY">DANNY C. WHARTON, Associate Curator Animal Departments, New York Zoological Park, Bronx Zoo, The Bronx, New York, USA </P>
+<P ALIGN="JUSTIFY">CHARLES A. WOODS, Professor and Curator, Florida State Museum, University of Florida, Gainesville, Florida, USA </P>
+<P ALIGN="JUSTIFY">THOMAS M. YUILL, Associate Dean for Research and Graduate Training, School of Veterinary Medicine, University of Wisconsin-Madison, Madison, Wisconsin, USA </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">* * *</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">NOEL D. VIETMEYER, Board on Science and Technology for International Development (BOSTID), National Research Council, Washington, D.C., Microlivestock Study Director and Scientific Editor </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">NATIONAL RESEARCH COUNCIL STAFF</P>
+<P ALIGN="JUSTIFY">F.R. RUSKIN, BOSTID Editor</P>
+<P ALIGN="JUSTIFY">MARK DAFFORN, Technical Writer</P>
+<P ALIGN="JUSTIFY">MARY JANE ENGQUIST, Staff Associate</P>
+<P ALIGN="JUSTIFY">ELIZABETH MOUZON, Senior Secretary</P>
+<P ALIGN="JUSTIFY">JOHN VREYENS, MUCIA Intern</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">CONTRIBUTORS</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The following individuals have made general contributions to the development of this book. All of the persons listed as research contacts in Appendix B also contributed - usually on one or two species that are their scientific specialty.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">ASHIQ AHMAD, Wildlife Management Specialist, Pakistan Forest Institute, Peshawar, Pakistan</P>
+<P ALIGN="JUSTIFY">ANGEL C. ALCALA, Division Research, Extension and Development, Silliman University, Dumaguete City, Philippines</P>
+<P ALIGN="JUSTIFY">HARTI AMMANN, Basel, Switzerland</P>
+<P ALIGN="JUSTIFY">PATRICK ANDAU, Forest Department, Sandakan, Sabah, Malaysia</P>
+<P ALIGN="JUSTIFY">S.P. ARORA, National Dairy Research Institute, Karnal, India</P>
+<P ALIGN="JUSTIFY">S. AYYAPPAN, CIFRI, Kausabyaganga, Bhubaneswar Orissa, India</P>
+<P ALIGN="JUSTIFY">WALTER BAKHUIS, Caribbean Marine Biological Institute, Willemstad, Curacao, Netherlands Antilles</P>
+<P ALIGN="JUSTIFY">JAMES R. BARBORAK, CATIE, Turrialba, Costa Rica</P>
+<P ALIGN="JUSTIFY">PUSHKAR NATH BHAT, Indian Veterinary Research Institute, Izatnagar, Uttar Pradesh, India</P>
+<P ALIGN="JUSTIFY">STEVE BENNETT, Curepe, Trinidad, West Indies</P>
+<P ALIGN="JUSTIFY">K.P. BLAND, Department of Physiology, Royal (Dick) School of Veterinary Studies, University of Edinburgh, Edinburgh, Scotland</P>
+<P ALIGN="JUSTIFY">MELVIN BOLTON, Yeppoon, Queensland, Australia</P>
+<P ALIGN="JUSTIFY">JOSEPH BONNEMAIRE, Ecole Nationale Superieure des Sciences Agronomiques Appliquees, Dijon, France</P>
+<P ALIGN="JUSTIFY">R.D.S. BRANCKRAERT, Faculte des Sciences Agronomiques, Universite du Burundi, Bujumbura, Burundi</P>
+<P ALIGN="JUSTIFY">PETER BRAZAITIS, Herpetology, New York Zoological Society, The Bronx, New York, USA</P>
+<P ALIGN="JUSTIFY">L. DE LA BRETONNE, JR., Louisiana Cooperative Extension Service, Louisiana State University, Baton Rouge, Louisiana, USA</P>
+<P ALIGN="JUSTIFY">P. BRINCK, Department of Animal Ecology, University of Lund, Lund, Sweden</P>
+<P ALIGN="JUSTIFY">LESLIE BROWNRIGG, CIAT, Cali, Colombia</P>
+<P ALIGN="JUSTIFY">D. HOMER BUCK, Illinois Natural History Survey, Kinmundy, Illinois, USA</P>
+<P ALIGN="JUSTIFY">GERARDO BUDOWSKI, Natural Renewable Resources Programme, CATIE, Turrialba, Costa Rica</P>
+<P ALIGN="JUSTIFY">DAVID BUTCHER, Taronga Zoo, Mosman, New South Wales, Australia</P>
+<P ALIGN="JUSTIFY">JULIAN O. CALDECOTT, World Wildlife Fund Malaysia, Kuching, Sarawak, Malaysia</P>
+<P ALIGN="JUSTIFY">GARY CALLIS, Texline, Texas, USA</P>
+<P ALIGN="JUSTIFY">J.K. CAMOENS, Asian Development Bank, Manila, Philippines</P>
+<P ALIGN="JUSTIFY">A. CHRISTOPHER CARMICHAEL, The Museum, Michigan State University, East Lansing, Michigan, USA</P>
+<P ALIGN="JUSTIFY">ROBERT H. CHABRECK, School of Forestry and Wildlife Management, Louisiana State University, Baton Rouge, Louisiana, USA</P>
+<P ALIGN="JUSTIFY">A.M. CHAGULA, Research, Ministry of Agriculture, Dar-es-Salaam, Tanzania</P>
+<P ALIGN="JUSTIFY">CHARAN CHANTALAKHANA, Department of Animal Science, Kasetsart  University, Bangkok, Thailand</P>
+<P ALIGN="JUSTIFY">PETER R. CHEEKE, Rabbit Research Center, Oregon State University, Corvallis,  Oregon, USA</P>
+<P ALIGN="JUSTIFY">G.S. CHILD, Forest Resources Division, FAO, Rome, Italy</P>
+<P ALIGN="JUSTIFY">A.S. CHOPRA, Ministry of Agriculture, Department of Agriculture and Cooperation,  New Delhi, India</P>
+<P ALIGN="JUSTIFY">W. Ross COCKRILL 29 Downs Park West, Bristol, England, BS6 7QH</P>
+<P ALIGN="JUSTIFY">CRISOSTOMO CORTES, Dairy Promotion and Extension Section, Dairy Development  Division, Manila, Philippines</P>
+<P ALIGN="JUSTIFY">WYLAND CRIPE, College of Veterinary Medicine, University of Florida, Gainesville,  Florida, USA</P>
+<P ALIGN="JUSTIFY">A. BEN DAVID, Holon, Israel</P>
+<P ALIGN="JUSTIFY">C. DEVENDRA, International Development Research Centre, Singapore</P>
+<P ALIGN="JUSTIFY">RODNEY DILLINGER, International Agency for Apiculture Development, Rockford,  Illinois, USA</P>
+<P ALIGN="JUSTIFY">DIRECTOR, Natal Parks Board, Pietermaritzburg, South Africa</P>
+<P ALIGN="JUSTIFY">ROLLANDE DUMONT, Ecole Nationale Superieure des Sciences Agronomiques  Appliquees, Dijon, France</P>
+<P ALIGN="JUSTIFY">N.G. EHIOBU, Department of Agricultural Sciences, College of Education, Agbor,  Nigeria</P>
+<P ALIGN="JUSTIFY">DONALD FARNER, Department of Zoology, University of Washington, Seattle,  Washington, USA</P>
+<P ALIGN="JUSTIFY">JOHN A. FERGUSON, Overseas Development Administration, Eland House, London,  England</P>
+<P ALIGN="JUSTIFY">ABELARDO FERRER D., Quinta Nueva Exparta, San Bernardino, Caracas,  Venezuela</P>
+<P ALIGN="JUSTIFY">LYNWOOD A. FIEDLER, Section of International Programs, U.S. Fish and Wildlife  Service, Denver Wildlife Research Center, Denver, Colorado, USA</P>
+<P ALIGN="JUSTIFY">H. FISCHER, Tropical Science Centre, Division of Tropical Veterinary Medicine,  Justus-Liebig University, Giessen, West Germany</P>
+<P ALIGN="JUSTIFY">J. FURTADO, Commonwealth Science Council, London, England</P>
+<P ALIGN="JUSTIFY">FRANK GOLLEY, Institute of Ecology, University of Georgia, Athens, Georgia, USA</P>
+<P ALIGN="JUSTIFY">E. GONZALES J., Instituto de Produccion Animal, Universidad Central de Venezuela,  El Limon-Maracay, Venezuela</P>
+<P ALIGN="JUSTIFY">GRAHAM GOUDIE, Mainland Holdings, Lae, Papua New Guinea</P>
+<P ALIGN="JUSTIFY">ALISTAIR GRAHAM, Tanglewood, Crowborough, East Sussex, England</P>
+<P ALIGN="JUSTIFY">GORDON GRIGG, Zoology, University of Sydney, Sydney, New South Wales, Australia</P>
+<P ALIGN="JUSTIFY">M.R. DE GUMAN, JR., Food and Fertilizer Technology Center, Taipei, Taiwan</P>
+<P ALIGN="JUSTIFY">COLIN P. GROVES, Department of Prehistory and Anthropology, The Australian  National University, Canberra, ACT, Australia </P>
+<P ALIGN="JUSTIFY">J. HARDOUIN, Institut de Medicine Tropicale "Prince Leopold," Antwerp, Belgium</P>
+<P ALIGN="JUSTIFY">GEOFFREY HAWTIN, International Development Research Centre, University of  British Columbia, Vancouver, B.C., Canada</P>
+<P ALIGN="JUSTIFY">GORDON HAVORD, Technical Advisory Division, UNDP, New York, New York, USA</P>
+<P ALIGN="JUSTIFY">TIN HLA, Veterinary Department, Director General's Office, Rangoon, Burma</P>
+<P ALIGN="JUSTIFY">JAMES HENTGES, Department of Animal Science, University of Florida, Gainesville, Florida, USA</P>
+<P ALIGN="JUSTIFY">W.F. HOLLANDER, Department of Genetics, Iowa State University, Ames, Iowa, USA</P>
+<P ALIGN="JUSTIFY">RENE E. HONEGGER, Herpetology, Zurich Zoo, Zurich, Switzerland</P>
+<P ALIGN="JUSTIFY">JACK HOWARTH, School of Veterinary Medicine, University of California, Davis, California, USA</P>
+<P ALIGN="JUSTIFY">HUANG CHU-CHIEN, Institute of Zoology, Academia Sinica, Beijing, China</P>
+<P ALIGN="JUSTIFY">ANGUS HUTTON, Gympie, Queensland, Australia</P>
+<P ALIGN="JUSTIFY">H.A. JASIOROWSKI, Animal Production and Health Division, FAO, Rome, Italy</P>
+<P ALIGN="JUSTIFY">MUHAMMAD YAQUB JAVAID, Directorate of Fisheries, Government of the Punjab, Punjab, India</P>
+<P ALIGN="JUSTIFY">J. MANGALARAJ JOHNSON, Nudumalai Sanctuary, Vannarpet, Udagamandalani, India</P>
+<P ALIGN="JUSTIFY">MATI KAAL, Tallinn Zoo, ESSR Tallinn, USSR</P>
+<P ALIGN="JUSTIFY">STELLAN KARLSSON, Simontorp Aquaculture AB, Blentarp, Sweden</P>
+<P ALIGN="JUSTIFY">JACKSON A. KATEGILE, International Development Research Centre, Nairobi, Kenya</P>
+<P ALIGN="JUSTIFY">ROBERT E. KENWARD, Institute of Terrestrial Ecology, Furzebrook Research Station, Wareham, Dorset, England</P>
+<P ALIGN="JUSTIFY">JAMES M. KEARNEY, Miami, Florida, USA</P>
+<P ALIGN="JUSTIFY">F. WAYNE KING, Florida State Museum, Gainesville, Florida, USA</P>
+<P ALIGN="JUSTIFY">H.-G. KLOS Zoologischer Garten Berlin, Berlin, West Germany</P>
+<P ALIGN="JUSTIFY">NELS M. KONNERUP, Boom International, Stanwood, Washington, USA</P>
+<P ALIGN="JUSTIFY">NAVU KWAPENA, Office of Environment and Conservation, Boroko, Papua New Guinea</P>
+<P ALIGN="JUSTIFY">THOMAS E. LACHER, Huxley College of Environmental Studies, Western Washington University, Bellingham, Washington, USA</P>
+<P ALIGN="JUSTIFY">JOHN K. LOOSLI, Gainesville, Florida, USA</P>
+<P ALIGN="JUSTIFY">PETER LUTZ, Rosenstiel School of Marine and Atmospheric Science, University of Miami, Miami, Florida, USA</P>
+<P ALIGN="JUSTIFY">CRAIG MACFARLAND, CATIE, Turrialba, Costa Rica</P>
+<P ALIGN="JUSTIFY">CONSTANCE M. MCCORKLE, Department of Rural Sociology, University of Missouri, Columbia, Missouri, USA</P>
+<P ALIGN="JUSTIFY">ROBERT E. MCDOWELL, Department of Animal Science, Cornell University, Ithaca, New York, USA</P>
+<P ALIGN="JUSTIFY">JEFFREY A. MCNEELY, International Union for Conservation of Nature and Natural Resources, Gland, Switzerland</P>
+<P ALIGN="JUSTIFY">ADRIAN G. MARSHALL, Institute of South-East Asian Biology, University of Aberdeen, Aberdeen, Scotland</P>
+<P ALIGN="JUSTIFY">RICHARD R. MARSHALL, Veterinary Medicine, Sutter Hospitals Medical Research Foundation, Sacramento, California, USA</P>
+<P ALIGN="JUSTIFY">G.H.G. MARTIN, Department of Zoology, Kenyatta University College, Nairobi, Kenya </P>
+<P ALIGN="JUSTIFY">IAN L. MASON, Edinburgh, Scotland</P>
+<P ALIGN="JUSTIFY">JOHN C. MASON, Pacific Biological Station, Nanaimo, B.C., Canada</P>
+<P ALIGN="JUSTIFY">J. MAYO MARTIN, Fish Farming Experimental Station, Stuttgart, Arkansas, USA</P>
+<P ALIGN="JUSTIFY">YOLANDA MATAMOROS, Escuela de Medicina Veterinaria, Universidad Nacional, Heredia, Costa Rica</P>
+<P ALIGN="JUSTIFY">ROBIN MCKERGON, Livestock Development Corporation, Lae, Papua New Guinea</P>
+<P ALIGN="JUSTIFY">M. MGHENI, Faculty of Agriculture, Sokoine University of Agriculture, Morogoro, Tanzania</P>
+<P ALIGN="JUSTIFY">P. MONGIN, Station de Recherches Avicoles, INRA-Centre de Tours, Nouzilly, Monnaie, France</P>
+<P ALIGN="JUSTIFY">JOSE ROBERTO DE ALENCAR MOREIRA, Agricultural Research Center of the Humid Tropics, Belem, Para, Brazil</P>
+<P ALIGN="JUSTIFY">W.L.R. OLIVER, Jersey Wildlife Preservation Trust, Jersey, Channel Islands, United Kingdom</P>
+<P ALIGN="JUSTIFY">WERNER PAUWELS, Basel, Switzerland</P>
+<P ALIGN="JUSTIFY">W.J.A. PAYNE, Worcester, England</P>
+<P ALIGN="JUSTIFY">IAN PLAYER, Wilderness Leadership School, Bellair, Natal, South Africa</P>
+<P ALIGN="JUSTIFY">JAMES H. POWELL, JR., Plainview, Texas, USA</P>
+<P ALIGN="JUSTIFY">WILLIAM R. PRITCHARD, School of Veterinary Medicine, University of California, Davis, California, USA</P>
+<P ALIGN="JUSTIFY">HECTOR HUGO LI PUN, International Development Research Centre, Bogota, Colombia</P>
+<P ALIGN="JUSTIFY">VICENTE T. QUIRANTE, Small Ruminant Collaborative Research Project, Bureau of Animal Industry, Manila, Philippines</P>
+<P ALIGN="JUSTIFY">DAN RATTNER, The Institute of Animal Research, Kibbutz Lahav, D.N. Negev, Israel</P>
+<P ALIGN="JUSTIFY">C.V. REDDY, Faculty of Veterinary Science, Andhra Pradesh Agricultural University, Rajendranagar, Hyderabad, India</P>
+<P ALIGN="JUSTIFY">RHOEHEIT, Institute of Applied Science and Technology, University Campus, Turkeyen, Guyana</P>
+<P ALIGN="JUSTIFY">CHARLES T. ROBBINS, Department of Zoology, Washington State University, Pullman, Washington, USA</P>
+<P ALIGN="JUSTIFY">CARMEN MA. ROJAS G., CATIE, Turrialba, Costa Rica</P>
+<P ALIGN="JUSTIFY">D.H.L. ROLLINSON, Sardinia, Italy</P>
+<P ALIGN="JUSTIFY">JULIO E. SANCHEZ P., Museo Nacional, San Jose, Costa Rica</P>
+<P ALIGN="JUSTIFY">JEFF SAYER, World Conservation Centre, Gland, Switzerland</P>
+<P ALIGN="JUSTIFY">G. SEIFERT, Tropical Cattle Research Centre, CSIRO, Rockhampton, Queensland, Australia </P>
+<P ALIGN="JUSTIFY">ANDRES ELOY SEIJAS, Servicio Nacional de Fauna Silvestre, Maracay, Venezuela</P>
+<P ALIGN="JUSTIFY">S.K. SHAH, Institute of Animal Sciences, National Institute of Health, Islamabad, Pakistan</P>
+<P ALIGN="JUSTIFY">SIEH CHENXIA, Department of Animal Science, Nanjing Agricultural College, Nanjing, People's Republic of China</P>
+<P ALIGN="JUSTIFY">B.P. SINGH, College of Veterinary and Animal Science, Chandra Sekhar Azad University of Agriculture and Technology, Mathura, Uttar Pradesh, India</P>
+<P ALIGN="JUSTIFY">C. CATIBOG SINHA, Forest Research Institute, College, Laguna, Philippines </P>
+<P ALIGN="JUSTIFY">A.J. SMITH, Tropical Animal Health, Royal (Dick) School of Veterinary Studies, University of Edinburgh, Edinburgh, Scotland, Great Britain</P>
+<P ALIGN="JUSTIFY">A. MITHAT EFENDI, Ankara, Turkey</P>
+<P ALIGN="JUSTIFY">HENRY STODDARD, Shamrock Veterinary Clinic and Fisheries, Cross City, Florida, USA</P>
+<P ALIGN="JUSTIFY">SUKUT SULARSASA, Faculty of Animal Husbandry, Gadjalu Mada University, Yogyakarta, Indonesia </P>
+<P ALIGN="JUSTIFY">D.L. SUTTON, Agricultural Research and Education Center, Fort Lauderdale, Florida, USA</P>
+<P ALIGN="JUSTIFY">NICHOLAS SMYTHE, Smithsonian Tropical Research Institute, Panama</P>
+<P ALIGN="JUSTIFY">J. SZUMIEC, Polish Academy of Sciences, Experimental Fish Culture Station, Chybie, Poland</P>
+<P ALIGN="JUSTIFY">N. TABUNAKAWAI, Ministry of Primary Industries, Suva, Fiji</P>
+<P ALIGN="JUSTIFY">FRANK M. THOMPSON, Wild Animal Brokers, Bradenton, Florida, USA</P>
+<P ALIGN="JUSTIFY">ALLEN D. TILLMAN, Stillwater, Oklahoma, USA</P>
+<P ALIGN="JUSTIFY">DON TULLOCH, Winnellie, Northern Territory, Australia</P>
+<P ALIGN="JUSTIFY">CONRADO A. VALDEZ, Dairy Development Division, Bureau of Animal Industry, Manila, Philippines</P>
+<P ALIGN="JUSTIFY">LUIS VARONA, Havana, Cuba</P>
+<P ALIGN="JUSTIFY">PRAN VOHRA, Department of Avian Sciences, College of Agricultural and Environmental Sciences, University of California, Davis, California, USA</P>
+<P ALIGN="JUSTIFY">ANTOON DE VOS Whitford, Auckland, New Zealand</P>
+<P ALIGN="JUSTIFY">GRAHAME WEBB, Conservation Commission of the Northern Territory, Winnellie, Northern Territory, Australia</P>
+<P ALIGN="JUSTIFY">DAGMAR WERNER, Fundacion Pro Iguana Verde, Heredia, Costa Rica</P>
+<P ALIGN="JUSTIFY">GARY WETTERBERG, Department of the Interior, Washington, D.C., USA</P>
+<P ALIGN="JUSTIFY">CHARLES H. WHARTON, Clayton, Georgia, USA</P>
+<P ALIGN="JUSTIFY">F.W. BERT WHEELER, College Station, Texas, USA</P>
+<P ALIGN="JUSTIFY">ROMULUS WHITAKER, Madras Crocodile Bank, Perur, Tamil Nadu, India</P>
+<P ALIGN="JUSTIFY">WILDLIFE CONSERVATION INTERNATIONAL, New York Zoological Society, The Bronx, New York, USA</P>
+<P ALIGN="JUSTIFY">R.R. YEO, USDA-ARS, University of California, Davis, California, USA</P>
+<P ALIGN="JUSTIFY">BRUCE A. YOUNG, Department of Animal Science, University of Alberta, Edmonton, Alberta, Canada</P>
+<P ALIGN="JUSTIFY">CHAROON YOUNGPRAPAKORN, The Samutprakan Crocodile Farm and Zoo, Samutprakan, Thailand</P>
+<P ALIGN="JUSTIFY">THOMAS M. YUILL School of Veterinary Medicine, University of Wisconsin, Madison, Madison, Wisconsin, USA</P>
+<P ALIGN="JUSTIFY">W. ZEILLER, Miami Seaquarium, Miami, Florida, USA </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<B><P ALIGN="CENTER">&lt;&lt;TOC2&gt;&gt; Preface</P>
+</B><P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The purpose of this report is to raise awareness of the potential of small livestock species and to stimulate their introduction into animal research and economic development programs. It is geared particularly towards benefiting developing nations.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">"Microlivestock" is a term we have coined for species that are inherently small, such as rabbits and poultry, as well as for breeds of cattle, sheep, goats, and pigs that are less than about half the size of the most common breeds. These miniature animals are seldom considered in the broad picture of livestock development, but they seem to have a promising future. Wherever land is scarce it seems reasonable to assume that, things being equal, small animals would be more attractive than large ones. And land for livestock is becoming increasingly scarce.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">In this report we have emphasized multipurpose species with promise for small  holders. In some species, the promise is immediate; in others, it is long term, and much research must be undertaken before that promise can be realized or even understood.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">We have included wild species that seem to have potential as future livestock. Some are threatened with extinction but are described here because their economic merits may be the key to acquiring support for their protection. Also we have highlighted rare breeds of domesticated species because the current tendency has been to concentrate on a small number of large breeds, and many potentially valuable breeds are becoming extinct through neglect.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The book was prepared after an intensive survey of more than 300 animal scientists in 80 countries. They suggested more than 150 species for inclusion. The staff then drafted chapters on about 40 species and these drafts were reviewed by more than 400 researchers worldwide. The thousands of resulting comments, corrections, and additions were integrated into the drafts. The panel then met to review the product, to select the most promising species, and to rework the chapters based on their own experiences and joint conclusions. The result is the current 35 chapters. Most of the case studies and accounts of innovations highlighted in the various sidebars were developed by the staff study director. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Collectively, this study covers many species, but it by no means exhausts all the microlivestock possibilities. Lack of space and time precludes discussion of creatures such as edible insects, snails, worms, turtles, and bats, which in some regions are highly regarded foods. Similarly, we have not included aquatic life. These decisions were arbitrary; perhaps invertebrates and aquatic species can be included in future volumes.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">This report is addressed to government administrators, technical assistance personnel, and researchers in agriculture, nutrition, and related disciplines who are concerned with helping developing countries achieve a more efficient and balanced exploitation of their biological resources. Hence, we deal with the animals in a general way and do not cover details of biology, husbandry, or economics. A selection of readings that contains such technical information is cited in Appendix A.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">A further goal of this project has been to explore the common ground between the disparate arms of animal science: to show that specialists in wildlife, zoology, and livestock science have much to learn from one another's field of expertise; to show that "fanciers" of pigeons, pheasants, chinchillas, iguanas, and other species may have much to offer livestock breeders - including germplasm; and that those who raise "obsolete" breeds are not only playing a vital role in the protection of rare genes but can offer the benefit of their experience to commercial livestock producers.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Throughout this report, the scientific names of mammals follow those in: Mammal Species of the World: A Taxonomic and Geographic Reference. 1982. J.H. Honacki, K.E. Kinman, and J.W. Koeppl, editors. Published by Allen Press, Inc.; and the Association of Systematics Collections, Lawrence, Kansas, USA. All dollar figures are in U.S. dollars; all ton figures are in metric tons.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">This report has been produced under the auspices of the Advisory Committee on Technology Innovation (ACTI) of the Board on Science and Technology for International Development, National Research Council. ACTI was mandated to assess innovative scientific and technological advances, with particular emphasis on those appropriate for developing countries. In this spirit, therefore, the current report includes some extremely unusual species. Whether these will eventually prove practical for widespread use is uncertain, but we present them here for researchers and others who look forward to challenges and enjoy the satisfaction of successful pioneering. The domestication of new poultry, as well as the management of rodents, iguanas, and small deer and antelope, should be viewed in this spirit.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Current titles in the ACTI series on managing tropical animal resources are: </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">· The Water Buffalo: New Prospects for an Underutilized Animal</P>
+<P ALIGN="JUSTIFY">· Little-Known Asian Animals with a Promising Economic Future</P>
+<P ALIGN="JUSTIFY">· Crocodiles as a Resource for the Tropics</P>
+<P ALIGN="JUSTIFY">· Butterfly Farming in Papua New Guinea.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">The production of these books has been supported largely by the Office of the Science Advisor of the U.S. Agency for International Development (AID), which also made this report possible.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">WARNING</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">If misunderstood, this book is potentially dangerous. Because of the severity of the food crisis, the panel has selected some animals - mainly in the rodent section - that are highly adaptable and grow quickly. These seem appropriate for raising only in areas where they already exist, which are clearly identified in those chapters. Such potentially invasive animals should not be introduced to other environments because they could become serious pests. In any trials, local species should always be given priority.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">How to cite this report:</P>
+<P ALIGN="JUSTIFY">National Research Council. 1991. Microlivestock: Little-Known Small Animals with a Promising Economic Future. National Academy Press, Washington, D.C. </P>
+<P ALIGN="JUSTIFY">Cover Design by David Bennett </P>
+<P ALIGN="JUSTIFY">In the developing countries, there are over 100 million farms of less than five hectares, supporting about 700 million people, who represent about 17 percent of the world population. Even more significant is the fact that about 50 million farms have less than one hectare of land. C. Devendra and Marcia Burns Goat Production in the Tropics We may now be in the wind down stage of bigger is better animal selection trend and it has certainly been a wild ride.... the lesson now being learned is that the bigger breeding animals . . . cost more to maintain, are often slower to reproduce, and may even have a shorter lifespan.</P>
+<P ALIGN="JUSTIFY">Kelly Klober</P>
+<P ALIGN="JUSTIFY">Small Farmer's Journal</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<B><P ALIGN="CENTER">&lt;&lt;TOC2&gt;&gt; Introduction</P>
+</B><P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&lt;&lt;I&gt;&gt; g001a.png FIGURE</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Like computers, livestock for use in developing countries should be getting smaller and becoming more "personal." Conventional "mainframes," such as cattle, are too large for the world's poorest people; they require too much space and expense. "Miniframes," such as the conventional breeds of sheep and goats, have an increasingly important role to play. But tiny, "user-friendly" species for home use are the ones highlighted in this report. We have called them "microlivestock."'</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">There are two types of microlivestock. One consists of extremely small forms of conventional livestock - such as cattle, sheep, goats, and pigs. The other consists of species that are inherently small poultry, rabbits, and rodents, for instance.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Microlivestock are important because the developing world's animal production is only a fraction of what it should be. Throughout Latin America, Asia, and Africa, the poor eat almost no meat, milk, or eggs - the most nutritious foods. It is estimated, for example, that in Mexico 25 million campesinos cannot afford meat. In poor countries, even the middle class eats less meat in a year than the populations of North America and Europe eat in a month. Malnutrition is common and its effects, especially on children, can be debilitating. It is one of mankind's most serious imbalances - and most pressing problems.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Rural families in the Third World usually subsist mainly on the products from their homes or farms. Thus, if we are to help their livestock production, more attention must be given to animals that are sized for their situations. Examples discussed in the report are summarized here.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Microbreeds Small breeds of cattle, sheep, goats, and pigs are common in the developing world. Because they are often raised for subsistence rather than for commerce, the national and global contribution that they make is often overlooked. These small, hardy animals deserve much greater recognition.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Later chapters highlight dozens of promising microbreeds. All are less than half average size; some are far smaller than that. The "miniBrahman" cow of Mexico is only 60 cm tall and weighs 140 kg; the southern Sudan dwarf sheep of eastern Africa can weigh as little as 11 kg; the Terai goat of Nepal weighs less than 12 kg; and the cuing pig of Mexico weighs merely 10 kg.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Poultry The widespread use of poultry in Third World villages demonstrates the importance of small, easily managed, household livestock. Small size, the ability to forage for themselves, and a natural desire to stay around the house put chickens, ducks, guinea fowl, and other birds among the most vital resources of rural Asia, Africa, and Latin America. Scratching a living out of the dirt, dust, ditches, and debris, these often-scrawny creatures are a resource to be taken seriously. For the most poverty stricken, a bony bird may be the only source of meat during much of a lifetime. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Among poultry, there are many underrated, but highly promising, species, including:</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">- Pigeon. These birds forage widely but return home, thereby providing the farmers with squab, one of the tastiest of all meats. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">- Quail. Small and efficient, they, too, are suited to home rearing, and in Japan and a few other countries, large numbers are raised commercially in very small space. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">- Muscovy. A native of South American rainforests, this bird is a major poultry resource of France, Taiwan, and a few other countries. Tame, tolerant, and tough, it deserves greater recognition everywhere. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">- Guinea Fowl. One of the most self-reliant of all domestic birds, this native of Africa is raised in huge numbers in Europe - notably France. Its potential for increased production elsewhere is exceptional. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">- Turkey. The traditional turkey of Mexico still exists as a scavenger bird in villages and household backyards. Unlike the highly selected modern breeds, it is self-reliant, robust, and disease-resistant. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Rabbits Like chickens, rabbits exemplify the vast possibilities that microlivestock offer for increasing meat production in the most poverty-stricken parts of the world. Captive rabbits have been popular as food at least since the time of the Romans. Rabbit rearing has been well established in Europe and China, and now national rabbit projects have begun in many developing nations.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Rodents Some 7,000 years ago, guinea pigs were domesticated as a source of food for the high Andes; even today in the uplands of Bolivia, Peru, and Ecuador, most Indians raise them inside their homes and regard them as an essential part of life. For many Indians, these indoor livestock are the main source of meat. Prolific, tractable, and easy to feed, house, and handle, guinea pigs are even kept in downtown apartment buildings - often in boxes under the bed. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Other rodents might also be suited to domestication; for instance, the potentially tamable, clean-living species of South American fields and woodlands - agouti, capybara, hutia, mare, coypu, pace, and vizcacha. Two remarkable domestication programs have been started in Africa: the grasscutter in West Africa and the giant rat in Nigeria. Both animals provide popular "bushmeat" and researchers are now learning to raise them in captivity. (Because of its tangy taste, Ghanaians actually pay three times more for grasscutter meat than for beef!)</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Antelope Another wild African mammal with potential for "household animal husbandry," the blue duiker, is a rabbit-sized antelope. In some areas of Central and Southern Africa the demand is so great that its population is declining at an alarming rate. Duiker rearing, if it can be made successful, might provide both food and an economic alternative to slaughtering the wild populations. It is reported that duikers are easy to maintain and they reproduce well in captivity.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The meat of several other tiny antelope species is also much sought in many African countries, and these animals are also suitably sized to feed the average family at one meal.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Deer Several species of tiny deer - smaller than many dogs - might make useful microlivestock, although much research is needed before their true potential can be judged. Normal-sized deer were once considered too easily frightened to be reared as domestic livestock, but several species are now raised on thousands of deer farms in New Zealand as well as in at least a dozen other countries.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Mouse deer and musk deer (which, strictly speaking, are not true deer at all) are of microlivestock size and are also possible future livestock. The musk deer produces one of the most valuable materials in the animal kingdom - more valuable, in fact, than gold. The musk from the male's glands is used in oriental medicines as well as in European perfumes. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Iguanas Over much of the Caribbean and Latin America, iguanas are a traditional source of food. Indeed, the meat of these large herbivorous lizards is so delicious they are being hunted to extinction throughout their wide range. Their eggs are much enjoyed also. Programs in Panama, Costa Rica, El Salvador, Curacao, and Argentina have developed simple methods to hatch and rear three iguana species. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Bees Honey bees are present almost everywhere, and honey and wax are high-value products that demand little processing and can be stored and transported easily. Innovations in equipment and technique have made beekeeping successful in the tropics without requiring sophisticated hives or elaborate training. Raising bees can also benefit the many crops that require pollination.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">THE MICROLIVESTOCK ADVANTAGES</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Although animal science has traditionally emphasized bigness, smallness has its advantages. Some of these are summarized below.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Economic</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Microlivestock lend themselves to economic niches that are not easily filled by large livestock. Much of their potential is for subsistence production. They are promising for the many peasants who, being outside the cash economy, are now unable to purchase meat, milk, cheese, or eggs. These people can afford only animals that can be raised within the home or backyard under ambient climatic conditions and on feeds that are cheap and easily available.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">A subsistence farmer is likely to benefit more from small species than from large because of several factors:</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">- The animals are less expensive to buy.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">- They are less of a financial risk to maintain. (A farmer with several small animals is less vulnerable to loss than a farmer with a single large animal, a feature that is particularly important in subsistence farming where success determines whether the family will survive.)</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">- They give a faster return on investment. (Small size generally signifies high reproductive capacity and a fast turnover.)</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">- They provide flexibility. (Farmers can more easily change the size of their herd or flock to match the amount of feed available at a given time. Also, they can sell animals according to the family's fluctuating needs for cash or food.) </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">- They provide a steadier source of income.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">- They increase the chances of successful breeding because greater numbers are usually kept. (This also means that breeding stock is more likely to be retained in times of scarcity.)</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">- They are more easily transported. (Who hasn't traveled in a Third World bus or train without chickens, ducks, or guinea pigs as fellow passengers?)</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">- In some cases they are more efficient converters of food energy.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">There are also a number of other benefits to small species.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">- Reduced Spoilage. A portion of meat that comes in a "package" of a size that can be readily consumed by a family is important in areas where refrigeration is unavailable or uneconomic. A family can eat the meat produced by most microlivestock in one meal or in one day to minimize the risk of spoilage.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">- Efficient Use of Space. The space required for handling and feeding microlivestock is proportionately less than that required for large animals. Low space requirements make many microlivestock (such as guinea pigs, rabbits, pigeons, and quail) available to landless rural inhabitants who have no room for a cow. This is particularly important with respect to feed production.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">- Cheaper Facilities. Facilities and equipment required for microlivestock are, by and large, smaller and simpler than those required for large animals. They often can be made from local products or scrap material or both.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">- Ease of Management. Farmers and villagers can manage small animals more easily than large, which is an advantage in the many places where women and children are the main keepers of livestock.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">- Increased Productivity. Small animals tend to fit well into existing farming systems, thereby expanding the resource base and recycling nutrients. Some - for example bees, ducks, and geese - can feed themselves by scavenging.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">- By-Products. Many species have fur, feathers, skins, and other by-products that are often more valuable than their meat, milk, or eggs. Examples include the feet and tails of rabbits, musk from musk deer, and pelts from rodents such as coypu. Processing such byproducts creates diversification for the farmer and perhaps jobs for the village.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">RATIONALE FOR LIVESTOCK PRODUCTION</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Many have argued that livestock raising should be discouraged, that it is a primary cause of desertification through overgrazing and that it is an inefficient converter of basic material and energy into human food. "Grow more pulses, grow more grains," these people cry. Their arguments can be valid where the land has high potential for permanent cultivation. Much of the world's surface, however, does not fit into that category, and it is in these areas and for those people who have no access to arable lands that a convincing case for livestock can most easily tee mace. As W.J.A. Payne has written:*</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">- Livestock, particularly ruminants, can process forage and waste crop materials inedible by man into nutritionally desirable food products, many of high protein, mineral and vitamin content and including some of high caloric value. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">- Approximately 40 percent of total land available in developing countries can be used only for some form of forage production and a further 30 percent is classified as forest with some potential for the production of forage. Some 12 percent of the world's total population live in areas where people depend almost entirely on the products obtained from ruminant livestock. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">- Livestock provide a range of extremely valuable by-products. Dung is not only a fertilizer and soil-stabilizer but also a fuel of often considerably greater value than the fodder consumed in its production. Other byproducts, especially hides and wool form the bases of rural enterprises that may provide significant incomes to the poorest members of society. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">- Animal plant and human life are ecologically interdependent. The establishment of agricultural systems in which livestock are integrated with crops, forestry and aquaculture is essential for the improvement of overall productivity. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Livestock produce food that adds to the nutritional quality and variety of human diets. Although it is possible for humans to exist without them, these foods are relished and sought after by the majority of humanity. These foods include meat, eggs and processed products such as biltong and cheese. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Feed</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">In general, small species tend to expand the food base by using a wider array of resources than do major livestock such as cattle. Many can be raised on feeds that people discard: fibrous residues, industry by-products, or kitchen wastes. Some collect minute feeds that otherwise go unused. For example, chickens and pigeons gather scattered seeds, turkeys gobble up insects, geese graze water weeds, iguanas feed in the tops of trees, and bees collect nectar and pollen from flowers that may be miles away.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Even some grazing microlivestock prefer different forages from those preferred by cattle. Antelope and deer, for instance, browse tree leaves; capybara and grasscutters eat reeds. Combining microlivestock with conventional livestock results in a more complete utilization of forage resources and greater animal production per hectare.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Under conditions of abundance, small size may be of no advantage in mammals, but if feed is limited, it is of great help. A small animal (or its keeper) needs to cover less area to fulfill its daily requirements, so that microlivestock may grow fat in areas where the forage is too sparse to support a larger animal. This is particularly vital when there are seasonal bottlenecks. For example, feed may be plentiful enough for most of the year to supply many large animals; however, the dry season may greatly restrict the numbers that can be kept.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Although small animals generally require proportionately higher inputs of feed, they also grow proportionately faster (see sidebar opposite). In addition, species such as rabbits, guinea pigs, and grasscutters digest fibrous matter with surprising efficiency, even though they are not true ruminants like cattle, sheep, and goats.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Reproduction</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Many small animals have high reproductive capacity with short gestation periods, large numbers of offspring, and rapid juvenile growth. They tend to reach sexual maturity at a younger age than large animals, and the interval between the generations can be very short. Thus, meat or other products can be produced more rapidly and more evenly throughout the year.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Cows, for example, produce a maximum of one calf per year. A pig, on the other hand, may produce 7 or more young; a rabbit, 30 or more; a chicken, more than 100.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Adaptability and Hardiness</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The survival rates and manageability of many small breeds and species can be outstanding. Smallness is often an adaptation to harsh environment. Indeed, a major promise for microlivestock is in special environmental niches. Where cold, heat, temperature fluctuations, aridity, or humidity are extreme, microlivestock are likely to show their greatest advantage. Chickens, guinea fowl, goats, and many other small species already live in villages, homes, and backyards in harsh and disease-prone climates, and are usually given no care and sometimes no food: they have to scavenge for their sustenance and survive as best they can. Such selection pressures result in animals of remarkable adaptability, tolerance, and robustness.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">Some microlivestock can produce under conditions where conventional species die. The capybara, for instance, is at home in the Latin American lowlands, where the climate is hot and humid and floods cause seasonal inundations. Cattle, by contrast, die because of malnutrition, foot rot, or drowning. Other microlivestock species with a wide tolerance to ecological extremes include the turkey, pigeon, and bee. And some dwarf breeds of cattle, sheep, goats, and pigs show surprising tolerance to trypanosomes, the parasites that make conventional breeds impossible to maintain throughout much of Africa.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Some small species can be raised in cities, where poverty and malnutrition are often worse than in rural areas. It is estimated, for instance, that one million livestock exist in Cairo, not counting the pigeons that are raised on countless rooftops. Goats and cattle are common in urban India, and many Third World cities have far more chickens than people.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&lt;&lt;I&gt;&gt; p9a.png Food utilization versus body size</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">MICROLIVESTOCK LIMITATIONS</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Raising microlivestock is not a panacea for the Third World's food problems. Efforts to develop them will not be without difficulties. Some likely problems are noted here.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">High Energy Requirements</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Smaller animals tend to have a higher feed requirement per unit of body weight than large animals. Anatomical and physiological constraints prevent them from meeting their relatively high energy requirements simply by increasing the rate of food ingestion. Therefore, for optimum production, some small animals, particularly nonruminants, require feed that is higher in protein and lower in fiber than large animals. This is particularly true when the small animals are compared with ruminants such as cattle, sheep, and goats.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Increased Labor Requirements</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The advantages of low investment, fast return on capital, flexibility, and efficient resource utilization are offset by higher demands for labor. Keeping small animals often requires considerable effort, and its economic viability may depend on the availability of cheap and willing labor. Many small animals are raised at home by family members, such as children, the elderly, and the handicapped, who have time available and whose labor costs are nominally zero.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Diseases</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Some potential microlivestock are undomesticated, and resistance to diseases and parasites is one justification for their consideration. However, the general healthiness of a species when it is free-ranging can be a misleading guide for its husbandry. Confining any animal in high density invariably increases the potential for the spread of infectious diseases and parasites. Moreover, mismanagement can foster respiratory and gastrointestinal diseases (such as salmonella or coccidiosis) that are rare among scattered populations.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Some microlivestock are potential reservoirs for diseases that affect not only local animals but people as well. This may limit their successful development in some areas. Although the dangers are often exaggerated, controls may be needed, particularly of rinderpest, tickborne diseases, and those diseases communicable to humans.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Predation</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Small size makes microlivestock easy prey.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Lack of Research</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Techniques to manage some microlivestock species are not yet well established. The development of appropriate husbandry techniques, as well as a better understanding of the animals' particular biological and behavioral characteristics, will be needed before major progress can be made. These species (for instance rodents, deer, and iguanas) may require collection of different genotypes, as well as studies of diseases, nutrition, and management.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Complex Logistics</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">It is complicated and expensive to reach millions of widely scattered peasants, each having only a handful of small animals. Even though total production may far exceed that of commercial farms raising large animals, the smallholdings are often dispersed, their animals are often used for subsistence rather than commerce, and their managers are often ill-trained and illiterate.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Legislative Restrictions</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The use of some microlivestock species may be restricted by legislation. For instance, some countries have meat and veterinary laws that work against the development of species other than cattle. Others have laws to protect wildlife, which could be important in the case of species such as antelope, deer, pace, and iguana.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Lack of Markets</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Microlivestock need not be just for home or local consumption; they can also be raised for market. But some commercial programs, including some with rabbits and guinea pigs, have failed because no public demand was developed.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Resistance to New Species</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">People have close associations with livestock, and in most cultures they do not easily accept animals or animal foods that are radically different from their traditional ones. In general, the ties between certain ethnic groups and a particular species or breed is very strong (one reason, for example, why European colonists introduced their own large breeds of cattle and sheep to Africa and Asia, paying little attention to small indigenous breeds). Moreover, people who are used to bringing the animal to the feed rather than the feed to the animal may resist a small animal that has to be penned up and fed by hand.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Opposition to Smallness</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Finally, there seems to be an innate human trait that considers bigger to be better, especially among the common livestock. For example, because many tropical cattle are small, there is strong inclination on the part of those responsible for livestock improvement to dismiss them or to increase their size by crossing them with large breeds.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">FUTURE OF MICROLIVESTOCK</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Small animals are likely to become increasingly important. As human populations increase, the space available for growing forage decreases, and this phenomenon favors small animals. Many villagers already have little or no pastureland. Some live in areas (the rice-growing areas of Southeast Asia, for instance) where crops are grown on almost every square meter almost every month of the year. Microlivestock are potentially important for urban areas of developing countries as well. There, too, land is at a premium and is usually inadequate for raising conventional livestock. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">So far, however, microlivestock have been largely ignored. Compared with cattle, they have been accorded little scientific effort. In the drive towards larger animals, stimulated by experience in the temperate zone, the virtually unstudied gene pool of small species and breeds has been mostly bypassed. There have been few attempts to assess or improve their farm productivity.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">This is unfortunate, and it is perhaps due to the fact that small animals may be less efficient at digesting certain foods and therefore technically less attractive than large, "modern" breeds. But to Third World peasants, an animal's efficiency is far less important than its survivability and manageability. If an animal cannot be raised under village conditions, its feed-use efficiency or milk yield is irrelevant.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Microlivestock production should be integrated into most ruraldevelopment projects. Small animals offer a way to improve the lives of people who are hard to reach by other methods. Only by expanding research on the husbandry, hygiene, nutrition, reproduction, physiology, and breeding can the promise of animals sized for small farms and villages be fulfilled. Moreover, the costs will be small compared with those of programs for large animals.2</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Specifically, experiment stations should produce and promote methods and materials for use in rearing microlivestock. Donors and development institutions, planners, and policymakers should note the potentials of microlivestock and the benefits that can be derived from them. Teaching manuals and materials are needed, and classes in microlivestock husbandry should be included in rural school curricula.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Raising personal livestock on weeds and table scraps in cages beside the house or boxes under the bed will, in many instances, get quality protein to the most poverty stricken more effectively than raising large livestock on pastures.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Although small size confers many advantages, the question is not whether the large or small animal is "best," but rather how well each can meet a person's varying requirements. In a given situation, livestock can be too small or too large. But the fact remains that not everyone who wants meat or money has the resources to acquire, keep, manage, or utilize a large animal.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The key is balance. Both microlivestock and traditional livestock deserve serious attention. Indeed, it seems likely that the two will seldom compete. Most microlivestock complement traditional livestock because of unique physical, physiological, behavioral, or economic characteristics. They increase the range of options for the millions of poor for whom the choice may not even be between large and small livestock, but between microlivestock and no livestock at all. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">It's an unfortunate fact that small animals don't have the prestige among Third World farmers that large animals do (perhaps this arose because children can look after goats and sheep but it takes men to look after cattle). Even sheep and goats are not accorded the same stature as cattle.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Hugh Popenoe</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Breeds and varieties were created from mutant genes and thus haste become living reservoirs of these genes, holding them for use in future generations of mankind.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Anonymous</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&lt;&lt;I&gt;&gt; g002a.png FIGURE</P>
+<P ALIGN="JUSTIFY"></P>
+<B><P ALIGN="CENTER">&lt;&lt;TOC2&gt;&gt; Part I : Microbreeds</P>
+</B><P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&lt;&lt;I&gt;&gt; g003a.png FIGURE</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Cattle, goats, sheep, and pigs supply millions of people around the world with the bulk of their cash and animal products. Yet scores of breeds - especially in the tropics - are left out of livestock development projects merely because they are considered too small. These "microbreeds"' have sometimes been considered genetic dead ends because they appear undersized and puny. Many of these traditional animals - some in local use for thousands of years - are disappearing, and even the small ancestors of large modern breeds are becoming extinct.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">These small breeds deserve to be studied and developed in their own right. Throughout Africa, Asia, and Latin America, these usually hardy animals are especially adapted to traditional husbandry practices and harsh local conditions. Some have remarkable qualities and are well adapted to resist hostile weather, ravaging pestilence, and poor diets. In remote places and in areas of extreme climate, they are often vitally important for basic subsistence.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Indeed, because of stress or disease, or insufficient forage, land, or money, microbreeds may be the only practical livestock in many settings. Their individual output may be low, but it can be efficient considering the lack of care and poor feeds they are given. Their availability and the growing number of small-sized farms in the developing world make them increasingly worthy of consideration.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The following chapters in this section describe microcattle, microgoats, microsheep, and micropigs. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<B><P>&lt;&lt;TOC3&gt;&gt; 1 Microcattle</P>
+</B><P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&lt;&lt;I&gt;&gt; g004a.png FIGURE</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">For the purposes of this report, "microcattle" are considered to be small breeds of cattle (Bos taurus and Bos indicus) with a mature weight of about 300 kg or less. In many areas of the developing world, these are actually the animals most widely held by farmers and pastoralists. They are often treasured because of their resilience and simple requirements. Many survive and produce under harsh conditions, grow rapidly, calve easily, show good maternal ability, yield lean meat, or have other advantages.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Microcattle have generally been ignored in the push towards larger animals, but they seem inherently suitable for traditional and small-farm husbandry. As rural people in developing countries improve their own productivity, as they become more aware of nutritional needs, and as they depend more upon cash economies, microcattle could become vital means for improving personal, dietary, and economic status.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">AREA OF POTENTIAL USE</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Worldwide.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">APPEARANCE AND SIZE</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Cattle have been classified in many ways, but they are generally designated as humped or humpless types. However, clear distinctions among them are sometimes difficult or impossible to make because they have intermingled for thousands of years. Representative microcattle types are listed at the end of the chapter. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">DISTRIBUTION</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">More than two-thirds of the world's 1.3 billion cattle are found in the developing world; one-third is in the tropics. As noted, a considerable number of these could be called "microcattle."</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">STATUS</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Many strains of microcattle are threatened with extinction because of replacement or crossbreeding with larger types. This is in some respects shortsighted because promoting just a few breeds contributes to narrowing of the genetic base, and valuable traits may be lost when selection is done to conform to any preconceived standard, including large size.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">HABITAT AND ENVIRONMENT</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Microcattle are adapted to a wide variety of habitats. Many types thrive - even with little or no attention - in climates that are hot, humid, arid, or beset by diseases and parasites.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">BIOLOGY</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Cattle are ruminants and digest fiber well, although they are selective foragers and prefer tender grasses and low-growing legumes.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">As with other tropical cattle, microbreeds generally reach physical and sexual maturity in 2 or 3 years. Many can breed year-round when conditions are favorable (gestation lasts about 9 months). Cows may remain fertile 10 years or more, and can live more than 20 years.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">BEHAVIOR</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Cattle usually graze from as few as four hours to as many as eight hours a day. If feed is of poor quality, they must forage (and ruminate) longer to receive adequate nutrition. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Microcattle are commonly docile and undemanding animals, and many small breeds are surprisingly responsive to humans.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">USES</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Like conventional breeds, microcattle produce the same well-known products: meat, milk, manure, hides, horn, blood, and bone. They are also used for traction.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Small cattle often produce only modest amounts of milk and meat per animal. However, given higher stocking rates, a herd of microcattle is often able to outyield larger, genetically improved animals on a per hectare basis, especially under stressful conditions. When their ability to survive adversity and poor management is taken into account, they may often be far and away the most efficient cattle for traditional husbandry.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Surprisingly, there is a place even for small draft animals. They tend to be active, thrifty (efficient), and more maneuverable in tight spaces, and so are adapted for use in the small fields, terraces, and paddies that are becoming increasingly common. The small hill cattle of Nepal, for instance, are valued because they can negotiate steep slopes and narrow terraces on Himalayan mountainsides. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">HUSBANDRY</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Microcattle are handled like their larger counterparts, but herding, tethering, fencing, and hobbling are generally easier.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">ADVANTAGES</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Cattle are familiar animals that are accepted in nearly all cultures; their meat, milk, manure, and leather are in demand almost everywhere. In many societies, beef is preferred over other meats, even by those who can rarely afford it.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">In most areas, organized breeding, production, and marketing associations are already in place. Microcattle can also integrate well into traditional forms of husbandry, whether in pastoral herds of hundreds or as solitary backyard milk cows.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Under humid and hot conditions, microcattle probably suffer less than larger breeds because their greater ratio of skin area to body mass enhances their ability to shed heat.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The number of cattle that can be kept on a given parcel of land may be increased, sometimes even doubled, with smaller animals. Microcattle can also be penned and fed cut-and-carry forage more easily than can larger cattle, and more of them can be maintained on the same amount of feed. This permits more continuous production and less financial hardship when an animal perishes.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Small cattle may require less labor because they are generally easier to handle, herd, confine, and transport. They usually have few problems with calving, and as a rule require little or no assistance.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Some microcattle have unusual tolerances to disease. In Africa, for instance, there are breeds that tolerate or resist trypanosomiasis, a parasitic disease that makes large areas of that continent uninhabitable for most other cattle breeds. Others seem more tolerant of internal or external parasites, theileriosis (east coast fever), rinderpest, or other afflictions.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">LIMITATIONS</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Microcattle often lack the prestige of larger breeds.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">When given quality forage and supplemental feeding, small unimproved cattle may not match the overall productivity of the large, highly developed breeds. Their greatest potential may prove to be for traditional husbandry and for grazing marginal areas where survival is more important than feed efficiency.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">BONSAI BRAHMAN</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">In Mexico, researchers are deliberately creating microcattle. Since 1970, Juan Manuel Berruecos Villalobos, former director of the Veterinary Medicine school at the National Autonomous University, has directed this enterprise. He and his colleagues have miniaturized cows by selecting the smallest specimens out of a herd of normal-sized Brahman cattle and breeding them with one another. After five generations, adult females average 15-180 kg adult males 20-220 kg. A few of the smallest cows are now only 60 cm tall and 140 kg in weight. Merely one-fifth of normal weight, they are shorter than the turkeys that share the barnyard with them. Indeed, they even get lost in the grassy pastures so that the farmers cannot see them.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">This program seems to have yielded a productive animal that can be cheaply and easily maintained in a small space. Berruecos has demonstrated that the tiny cows can be stocked on one-third the area needed to support one normal-sized cow. He reports that they are giving remarkable amounts of milk: up to four lifers a day, compared with six lifers from their full-sized counterparts. On a feed-intake to weight-gain basis, the tiny cattle are no less efficient than their normal-sized counterparts.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Although 17 years have gone into the selection of what Berruecos calls his "bonsai cattle," the process is not yet finished. Future goals include testing embryo transplants to see if one normal-sized cow can support multiple "microfetuses" (possibly as many as eight). This would help to rapidly increase the numbers of the miniature form, which weigh merely 4-5 kg at birth.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">All in all, the Mexican researchers see miniaturization as a new option for governments and farmers increasingly squeezed by shrinking farm land and rising production costs. Small livestock they say, are a way to produce more food on less land faster. For example, a campesino with almost no land can have one or two bonsais, but could never maintain a standard-sized cow.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">RESEARCH AND CONSERVATION NEEDS</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Their adaptability and robustness make microcattle worthy of preservation, study, and greater use, and they should be incorporated into many ongoing programs.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Selective breeding, although infrequently attempted, can probably improve productivity significantly. Records of breed history should be established, and unusual or special characteristics noted and the information disseminated. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&lt;&lt;I&gt;&gt; p24a.png Original distribution of wild cattle and banteng (Based on Mason , 1984)</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">In areas where small, indigenous breeds are being replaced, representative populations should be maintained and studied to increase understanding of their adaptive diversity and to retain a genetic storehouse for the future.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">REPRESENTATIVE EXAMPLES OF MICROCATTLE</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Dwarf West African Shorthorn</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">West African coastal forests, and inland. Female 125 kg; male 150 kg. Adaptation to harsh, humid climates and good resistance to trypanosomiasis and other diseases allow these small animals to exist where other cattle die. They are perhaps the smallest cattle of all (often weighing less than 100 kg). In the areas of worst disease and highest rainfall, this hardy animal is often found thriving, but half wild. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Muturu Nigeria. Female 160 kg; male 210 kg. This notable subtype is slightly larger. It is the most trypanotolerant of all cattle, showing no symptoms or loss of vitality. It is widely kept, mostly as a village scavenger and often as a pet, and yields a high percentage of meat. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">N'Dama</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">West Africa. 200-400 kg. These active, stocky animals utilize low-quality forage, produce good beef, and are used as light draft oxen. Milk production, though poor, improves with feeding level. N'Dama mature early and are exceptionally fertile, and they have already become important in breeding programs. They are resistant to trypanosomiasis, and can exist where temperatures average 30&Yacute; C with 1,500 mm annual rainfall. In the least hospitable areas, N'Damas ranging down to 200 kg are often the only cattle that can remain productive.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Rodope</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Southeastern Europe. Female 200 kg; male 350 kg. A humpless multipurpose breed - draft, milk, and beef - that is exceptionally hardy. The milk is high in butterfat. Possibly adaptable to the subtropics. It is rapidly being lost to crossbreeding.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Zebu</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Zebus are among the most important tropical domestic animals. However, the dwarfs are not well known, although in many areas they are preferred, especially as draft animals. Zebus use less water, even though their sweat glands are larger and more numerous than those of most other cattle. All have a low basal metabolism and resist heat well. In general, they also have high resistance to ticks and other parasites.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Taiwan Black Taiwan. Female 250 kg; male 250 kg. Well adapted to poor tropical conditions, these work animals are also used for meat. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Kedah-Kelantan Malaysia. Female 200 kg; male 250 kg. Hardy, well adapted cattle with exceptional fertility on a poor diet, both sexes are used as draft animals as well as sources of meat and cash. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Sinhala (Dwarf Zebu) Sri Lanka. Female 200 kg; male 250 kg. An ancient type of zebu, preferred for its handiness in cultivating small paddies and terraced fields. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Nuba Dwarf Sudan. 180-220 kg. These work animals are well proportioned but are not slaughtered for meat, and milk production is low. Although tolerant to trypanosomiasis, their numbers have dwindled because of crossbreeding. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Small Zebu Somalia. 160-230 kg. These small native cattle are used for beef, milk, and for work. They are well adapted to poor feed in a desolate environment. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Abyssinian Shorthorn Zebu (Showa) Central highlands of Ethiopia. Female 225 kg; male 305 kg. These widespread, small-humped cattle are very hardy. They produce beef and are generally milked, with surplus production about 2-4 kg daily. Resistant to many parasites, they also have a gentle disposition and make good work animals. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Dwarf Zebu (Mongalla) Tanzania, Uganda, and Kenya. Female 150 kg; male 250 kg. A highly variable, long-entrenched, small, East-African zebu with some nonzebu blood. Pastoralists favor it because of its hardiness. Although slow-maturing, it is well-fleshed, can yield excellent beef, and some types are milked. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Mashona Zimbabwe. Female 200 kg; male 250 kg. This hardy zebusanga type (see below) is widespread in drier areas and has a high resistance to disease and parasites. Since the 1940s, it has been bred for beef production and selected animals now weigh more than 500 kg. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Mini-Brahman Mexico. 135 kg. Downsized from 450-kg Brazilian zebus through selective breeding by Mexican researchers, these gentle animals are reported to yield two-thirds as much milk (3-4 liters daily) as the parent stock. Because of much higher stocking rates on grass, production per hectare is reportedly greater than with full-sized animals (see sidebar, page 22). </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Criollo</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Central and South America. Descendants of Spanish and Portuguese  cattle imported over 400 years ago, "criollo" cattle have adapted to a  wide range of harsh climates. Many varieties are small: mature females  often weigh 200-300 kg or less. They sometimes produce little beef or  milk under traditional conditions and management, but they are  extremely hardy and survive when other cattle perish. Through  importation and crossbreeding, many local types have been lost or are  threatened.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Chinampo Baja California, Mexico. 200-350 kg. Extremely tolerant of  wild desert conditions, these docile criollo cattle exist largely on scrub  and cactus. They get most of their water from succulent plants, have a  low metabolic rate and body temperature, and are mostly active at night. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Florida Scrub Florida, USA. 225-300 kg. Genetically isolated for more  than 300 years, the Florida Scrub is very hardy in harsh, subtropical  conditions. It has good resistance to ticks and screwworm, and can  subsist on forage with a high roughage content. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Sanga</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">This type - an ancient cross between longhorns or shorthorns and  humped animals - is found throughout eastern and southern Africa. It  weighs from 150 to 500 kg or more. Some types have been selectively  bred or crossed with European cattle and are quite productive.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Bavenda Transvaal, South Africa. 240-290 kg. This hardy and  disease tolerant tropical variety is small and prolific. It is generally used  for draft, barter, and beef. However, it has been crossbred with larger  animals so frequently that the smaller types are almost extinct; most  "Bavendas" now weigh more than 300 kg.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Ovambo' Northeastern Namibia. Female 160 kg; male 225 kg. A calm  and docile animal with a small hump, it is used by seasonal pastoralists  for beef and milk.  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Nilotic Sudan. 180-300 kg. These cattle of southern Sudan show great variation in size, partly due to environmental factors. They are generally resistant to local parasites and worms, have good potential for increased beef production, and their milk is very important locally.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Chadian "Native" and Dwarf Black Cattle</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Chad. Female 225 kg; male 275 kg. These two types are small, humped meat animals that graze the sparse savanna and are very drought resistant. Little scientific information exists about them.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">"Arab Cattle"</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Middle East. Small types (female 225 kg; male 300 kg) are used for meat and some milk, especially in Lebanon. There are many local forms with variable appearance, but all have small humps. Well adapted to grazing sparse vegetation on rough land, they are becoming rare due to crossbreeding.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Hill Cattle</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Nepal. Female 160 kg; male 200 kg. A widespread type often recrossed with Indian zebu animals, they are bred to be small. They are thrifty creatures that maintain themselves well on poor forage. Bulls make sure-footed draft animals on rough ground and slopes, and the cows are milked.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Tibetan Dwarf</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Tibet. Less than 250 kg. These humpless cattle are used as pack animals and can tolerate poor forage and high altitudes. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Yellow Cattle</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Southwest and south China. Female 220 kg; male 380 kg. In the subtropics and tropics, small multipurpose types of Yellow Cattle withstand high temperature and humidity. They are used mainly for work and meat, and seem well adapted to poor feed, harsh conditions, and rugged terrain. The Chowpei (190-380 kg) is a hardy working breed of more temperate areas in Hubei Province.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Cheju Hanwoo</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Korea. Female 230 kg; male 280 kg. A yellowish-brown Cheju Island native that has almost no calving difficulty, it is well adapted to poor grazing conditions in harsh environments and is docile and obedient.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Madura</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Indonesia. Female 220 kg; male 300 kg. An ancient cross between humped cattle and the banteng (see sidebar), these heat- and disease resistant hybrids also have good grazing and mothering ability, and are kept in the most extreme humid tropical environments. Breeding for fighting and racing has given them a poor disposition.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Dexter Cattle</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Ireland and North America. 220-360 kg. This breed can be traced back to eighteenth-century Ireland and is believed to have been developed by peasant farmers living on rough land. It is exceptionally hardy and produces both milk and meat. In North America, it has become popular among city folk who acquire country property, as this microbreed is particularly well suited to their usually tiny farms. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">BANTENG: THE CUTEST COW</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The banteng (Bos Javanicus) is a small Southeast Asian bovine with a promising future.* It is a different species from cattle. The two will interbreed, but the hybrid offspring are normally sterile.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Although almost entirely neglected by the animal science community, the banteng is remarkable for an ability to thrive under hot, humid, and disease-ridden conditions where cattle often grow poorly. The sexes are easily distinguished: males are jet black, females are golden brown. Both have bright white socks and rumps as if they had been freshly whitewashed. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Wild banteng are found in remote areas of countries from Burma to Indonesia. But only Indonesia has used it as a farm animal so far. It has more than 1.5 million domesticated banteng - some 20 percent of the country's total "cattle" population. Indonesian farmers value the animal's agility, which allows them to cultivate Relds too narrow for cattle to turn the prow. In addition, gourmets consider banteng meat the tastiest of all. Indonesia appreciates the banteng so much that it has established a genetic sanctuary on the island of Bali - banning cattle in order to maintain the banteng's genetic purity.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Outside Indonesia, only a few scientists have studied this animal, but it seems clear that it is particularly useful under tropical conditions. In heat and humidity, it thrives; even when cattle are starving, one rarely sees a skinny banteng. And demand for its meat is never ending.</P>
+<P ALIGN="JUSTIFY"></P>
+<I><P>&lt;&lt;TOC3&gt;&gt; 2 Microgoats</P>
+</I><P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">More than 90 percent of the world's nearly half billion goats (Capra hircus) are found in developing countries; many weigh less than 35 kg fully grown.` Such "microgoats" are noted for their high reproductive rates, rapid growth, early maturity, tasty meat, and rich milk' as well as for their robust constitution, ease of handling, and tolerance of climatic stress and poor feeds.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">To many people - especially where pigs and poultry are not common - meat and milk from microgoats are the primary animal proteins consumed during a lifetime. Perhaps the world's best foragers, goats eat practically anything made of cellulose, and are not dependent on grass. Because of their unselective feeding behavior, they are capable of living where the feeds - tree leaves, shrubs, and weeds - are too poor to support other types of livestock.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Such microgoats deserve wider recognition, for they are often the poor person's only source of milk, meat, and cash income. They are cheap to acquire and easy to maintain, even by people with little property and scarce resources.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">AREA OF POTENTIAL USE</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Worldwide, especially in arid and semiarid climates.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">APPEARANCE AND SIZE</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Goats generally have a long snout and an upright tail, by which they can be distinguished from most sheep. The mouth is unusual in having a mobile upper lip and a grasping tongue, which permits the animal to nibble even tiny leaves on spiny species.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Common commercial goat breeds generally weigh between 60 and 100 kg, with some weighing more than 200 kg. Microgoats may weigh less than 15 kg. Representative examples are listed at the end of the chapter.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">DISTRIBUTION</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Worldwide, with half in Asia and one-third in Africa.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">STATUS</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The FAO projects that world numbers may nearly double by the turn of the century. Goats are thus not endangered, but in some areas select populations of feral goats are being deliberately eradicated, with the consequent loss of potentially valuable genes. Some small breeds are also threatened by excessive crossbreeding with larger types.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">HABITAT AND ENVIRONMENT</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">One of the most adaptable of all livestock, goats can persist in conditions from arid to humid, and from sea level to high altitude. They are especially well adapted to hot, semiarid climates and to rocky, barren terrain.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">BIOLOGY</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">These ruminants can subsist on many feedstuffs that would otherwise be left to waste. Although selective browsers, they often prefer coarse leaves (including palm fronds) and shrubbery to palatable forage grass.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Most microgoats mature quickly, and in the tropics they can generally breed year-round. Their reproductive potential has often been underestimated; kidding is rarely difficult, and many types produce twins and sometimes even triplets or quadruplets.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">In hot, dry areas, goats require less attention than other livestock, and smaller goats have the added advantage of better heat dissipation. Some microgoats may also show disease resistance. For example, tolerance to trypanosomiasis makes them an important livestock in many regions of Africa. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">BEHAVIOR</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Goats are generally gentle, but can be easily frightened. They may become stubborn and aggressive when threatened or thwarted, and can prove hard to confine.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">If their feed smells of other animals - particularly of other goats -  they usually shun it unless nothing else is available. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">USES</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Microgoats mainly produce meat and form an important part of the diet in southern Asia, the Middle East, Africa, and Latin America, especially the Caribbean. Goat is sometimes a preferred meat, and there are few social or religious prohibitions against eating it.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Some microgoats are good milkers, and under stressful conditions they may keep producing when other livestock are dry. Goat milk is a valuable dietary supplement: it is nutritious, easily digestible, and usually commands premium prices. It makes excellent cheese and yogurt and can be used by people allergic to cow's milk.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Microgoats produce some of the finest and most valuable fibers in the world. Angora and Cashmere goats often weigh less than 30 kg fully grown, for example.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Goats produce a fine-textured, durable leather that finds extensive uses both locally and internationally. Horns, hooves, blood, and bone meal also have commercial value. Manure is another important product, and comes in fairly dry pellets that are easy to collect, store, and distribute.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Goats perform important functions in land management. Seeds of many trees (Acacia and Prosopis, for example) are "scarified" by passing through the goats' digestive system, fostering germination and natural revegetation. With care, goats can also be used to clear land of weeds and brush.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">HUSBANDRY</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Goats are often allowed to roam and scavenge for their own food. They form strong territorial attachments and can be trained to stay within a designated area. However, they cannot be kept from investigating - and quite probably devouring - anything within that territory. They are persistent browsers, so it is essential to prevent overstocking as well as raids on crops.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Variety of diet is important, and goats show much individuality in feed preferences. They are often raised on crop residue and kitchen refuse.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Goats can be run with other livestock without creating serious competition. The goats browse weedy shrubs, whereas the sheep and cattle graze more on grasses.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Although perhaps the hardiest of all livestock, most breeds benefit when they are provided shelter from rain and high-noon sun. Abrupt chilling and poor ventilation can cause severe respiratory problems. They are also susceptible to various maladies, such as internal parasites, especially when confined. The highest mortality, however, is caused when very young kids are not supplied with adequate feed and clean, dry shelter.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">ADVANTAGES</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">In most developing countries goats are already prominent in rural life. Common almost everywhere in Africa, Asia, and Latin America, they are dependable multi-use animals. They are particularly important in providing ready cash, such as for school fees, taxes, marriages, or funerals.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Goats integrate well in mixed agriculture, for example, by consuming leafy wastes, clearing land, and contributing fertilizer. In many places they are raised almost exclusively by women and children. If confined, goats require only simple, inexpensive shelters or pens, which makes them especially important as subsistence animals. In many situations, they may be the most efficient and economic producers for smallholders.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">These animals have a relatively fast rate of growth and early reproductive age, even under harsh conditions. They can graze rougher terrain than cattle and most sheep, can go for longer periods without water, and forage well in wooded areas where grass is lacking. They can derive most or all of their diet from roughage unusable by humans; high-energy feeds, such as protein supplements or carbohydrate supplements, are usually not needed even to fatten them for slaughter.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Goats are generally healthy and are not affected by many of the parasites and diseases that ravage other livestock. Some resistance to mange, internal parasites, foot-and-mouth disease, and other livestock scourges has been reported.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">LIMITATIONS</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">In some places (notably, in industrialized nations) there is a strong prejudice against goats and goat meat.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Smallness makes microgoats targets for predators and thieves.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Many small goats are poor milkers, especially under hardship conditions; however, even small amounts of milk can often fulfill a child's daily nutritional requirement or reinforce a nursing mother's diet.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Goats are independent and may wander away if not watched, and they can be difficult to pen. They may also have an unpleasant odor when kept confined (males are particularly malodorous during rutting season). </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Goats are often disparaged for degrading land and destroying vegetation because they continue to survive on overutilized lands often laid waste by mismanagement of sheep or cattle.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">FRESH GENES</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">A rare wild animal with spectacular horns, the bezoar (Capra aegagrus) is the goat's wild ancestor. People domesticated it before 7000 B.C., probably in the mountains along the Iran/ Iraq border. Until recent times, it remained widely scattered across the vast region between Greece and Pakistan, but it now exists only in pockets and is threatened with extinction.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">This would be a tragedy because the bezoar is a resilient wild species that crosses readily with domestic goats, and it could pass on its genetic inheritance for heat, drought, and cold tolerance: disease resistance; and other survival qualities.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&lt;&lt;I&gt;&gt; p39a.png Distribution of the bezoar. The arrow indicates the area where it was probably first domesticated, resulting in the goat as we know it (From Mason 1984)</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Fascinating science and valuable results probably await those willing to study this hardy, handsome creature and to explore the reharnessing of its genetic endowment. Today the bezoar is considered merely a trophy for hunters. The power of its genes to refresh - perhaps even revolutionize - the world's 500 million goats has been lost to sight. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">RESEARCH AND CONSERVATION NEEDS</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The microgoat's potential has hardly been realized. More research on performance and husbandry is needed to preserve and restore small breeds. Selective breeding for prolificacy, viability, and rapid growth, as well as more selective on-site culling, could greatly improve both meat and milk yields and quality.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Management systems that exploit smallness, stabilize production, and preserve the environment should be introduced and publicized in appropriate goat-rearing areas. Careful assessments of indigenous management methods should be made, particularly emphasizing their desirable characteristics. Improving hygiene in the wet season and supplemental feeding in the dry season are also important, as are disease- and parasite-control measures.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The undomesticated ibex and markhor could possibly be major contributors in the development of new, useful breeds for tropical and arid regions (see sidebar, page 42). </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">REPRESENTATIVE BREEDS OF MICROGOATS</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">West African Dwarf (Djallon)</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">West and Central Africa. Female 20 kg; male 30 kg. Adapted to humid lowlands, this widespread goat is particularly valuable for meat and skin production. Generally, it is bred for meat, but milk is sometimes an important secondary product. Sexual maturity is very early (3-6 months), and quadruplets occasionally occur (most goat breeds normally produce only single births). Related types go by the names "Cameroon Dwarf," "Dirdi," and "Nigerian Dwarf."</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Nubian Dwarf</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">United States. 35-40 kg (often less). A stable miniature variety of the milking Nubian, this microgoat has been developed recently in the United States by crossing standard-sized Nubians with the West African Dwarf. It combines a good milk output with high levels of butterfat.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">American Pygmy</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">United States. 15-25 kg. Derived from the West African Dwarf, it is noted for its hardiness and good nature, good milk production, and adaptability to various climates. There are several varieties, some for milking, others for meat.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Sudanese Nubian</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Northern Sudan. 25-30 kg. Widespread milk goats of riverain and urban areas.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Sudanese Dwarf</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Southern Sudan. 11-25 kg. A very hardy desert goat similar to the West African Dwarf, it averages 15 kg, but some mature individuals may weigh as little as 11 kg. Used for meat and hides, it produces little milk.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Small East African</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Kenya, Uganda, Tanzania. 20-30 kg. A widely neglected meat and hide animal found over a wide range, it is fast growing (sexual maturity at four months) and extremely hardy.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Mauritian</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Mauritius. 25-30 kg. A prolific, year-round breeder raised for meat production, it is often confined in simple shelters from birth to slaughter. Perhaps because of this isolation, mortality is less than 10 percent, even with little or no veterinary care.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Criollo</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Latin America. "Criollo" is a name given to several breeds of ancient Iberian blood with local adaptations to many unfavorable conditions. They are often small and hardy. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Creole Caribbean. Females 20 kg; males 25 kg. Robust meat goats of Spanish or West African origin that are kept throughout the Caribbean.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Crioulo Brazil. 30-35 kg. A meat and skin goat derived from Portuguese ancestors, it is hardy, prolific, undemanding, and adapted to harsh environments. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Chapper</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Pakistan. Female 20 kg; male 24 kg. Originating in dry regions, this meat and milk goat is a nonseasonal breeder with outstanding potential.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Barbari</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Pakistan, India. Females 20-25 kg; males 20-40 kg. A prolific, fastgrowing "urban" goat with high twinning and low mortality. Often kept inside houses, they adapt well to confinement and are important for both milk and meat.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Gaddi (White Himalaya)</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Hill districts of northern India. 25-30 kg. Kept for meat and their long, lustrous white hair, they are pure-breeding and healthy.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Changthangi (Ladakh)</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Kashmir, India. Male 20 kg. A pashmina (cashmere) goat of India, it is adapted to a high altitude, high humidity climate with extremes of temperature.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Terai</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Nepal. 8-12 kg. A very small, hardy animal of the southern lowlands, it kids year-round (sometimes twice), and often produces twins.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Southern Hill Goat</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Nepal. 12-16 kg. A small, mid-altitude goat resembling the Terai. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Black Bengal (Teddy, Bangladesh Dwarf)</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Eastern India and Pakistan. Female 10 kg; male 14 kg. A widespread, humid-area, meat goat that is early maturing and very prolific. It kids twice a year, and produces 60 percent twins and 10 percent triplets. It produces a superior leather.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Katjang</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Southeast Asia, China, and Pacific Islands. In places, less than 20 kg. A widespread, highly variable, hardy goat adapted to humid conditions, it usually has twins or triplets. Used for meat and skins, with exceptional females being milked.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Chinese Dwarf (Tibetan, Jining, Fuyang, or Chengdu Grey)</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">China. 20-40 kg. Well adapted to the humid tropics, it normally twins and is a good meat producer.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Heuk Yumso</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Korea. Female 25 kg; male 35 kg. A prolific cold-climate goat with a year-round breeding season. The meat is highly prized, and often sells at a premium due to its supposed health-giving effects.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Hejazi</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Middle East. Female 20 kg; male 20 kg. A meat goat, usually black, for harsh desert conditions.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Sinai (Black Bedouin)</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Sinai, Egypt and Negev Desert, Israel. Female 20 kg; male 50 kg. Native to dry, hot deserts, this milk and meat goat matures at 5-8 months and has a twinning rate over 50 percent. A most important characteristic is its drought tolerance. The female, for instance, can drink only once a day - at a pinch, once every other day - without losing appetite or reducing milk flow. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">WILD RELATIVES</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Several wild relatives will cross with the goat. Surprisingly, they have the same chromosome number (2n=60), and the offspring are frequently fertile. Although essentially unknown to agricultural science, these hybrids may offer a new gene pool for creating new farm animals and for improving the world's goats. They seem to combine the self-reliance of wild species with the usefulness of domestic ones. Artificial insemination and other modern techniques could make them easier to produce today than ever before.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Ibex*</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">A project in Israel has already produced a cross between the goat and the Nubian ibex (Capra ibex). The Sinai Desert goat, the breed that was used, ranks next to the camel in its ability to go without water - it often drinks only twice a week - but its meat has such a strong flavor that most people consider it dreadful. On the other hand, the ibex is compact and muscular and produces tender, mild meat that steak lovers find delicious. The product from crossbreeding the two is a creature seemingly able to endure extreme temperatures and drought, make use of poor pasture, and produce wonderful steaks.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">A herd of several hundred of these hybrids (dubbed 'ya-ez") has been created at Kibbutz Lahav in the northern Negev Desert area. Both sexes are fertile, and they can be bred with each other or with either parent. The meat is already in demand on the menus of elegant Tel Aviv hotels. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Markhor**</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">In Pakistan's northern uplands, it is not uncommon to find hybrids between domestic goats and the mountain goat known as "markhor" (Capra falconeri). Each year in Chitral and Gilgit, they can be found in the goat markets.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Markhors inhabit high elevations in rugged mountains and thrive on diets so meager as to be useless to goats. The hybrids are produced when markhor males - perhaps ousted by more dominant males - come in contact with feral domestic goats. However, some farmers raise young markhor and goats together (to overcome mutual resistance) and produce their own hybrids,</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">For a single hybrid animal local goatherds pay up to 5,000 rupees, a princely sum in this impoverished region. Traditionally, villagers have kept them as stud animals. They appreciate the animal's genetic endowment. Markhors tolerate extremes of cold and snow, are nimble and skilled at escaping predators, and survive on scanty fodder, Moreover, they have a high reproduction potential because they generally produce twins. As a result, they also tend to give more milk and it is rich in nutritive value. Instead of long body hairs, markhors possess insulating underfur - a soft and valuable raw material for the famous Kashmiri shawls.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Apparently, the hybrids can possess many of these qualities together with a calm disposition. Thus they could be useful in themselves and as conduits for passing such traits on to goats. </P>
+<P ALIGN="JUSTIFY"></P>
+<B><P>&lt;&lt;TOC3&gt;&gt; 3 Microsheep</P>
+</B><P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Among the hundreds of breeds of sheep (Ovis aries) in the world, those weighing less than 35 kg when mature have been largely ignored. Although these are common, the impression lingers that they are too small to be useful. Yet this virtually untapped gene pool is esnecially well adapted to traditional Third World animal husbandry. Given attention, these "microsheep" could boost meat, milk, skin, wool, and pelt production in many villages and small farms of Africa, Asia, and Latin America.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Many microsheep thrive in environments that tax the ability of larger breeds to survive. They are adapted to poor feeds and can be grazed in uncultivated wastelands unsuited to any other livestock except goats or camels. Because of their size, microsheep can fatten in areas where forage is so scattered and sparse that larger animals cannot cover enough ground to fill their bellies each day. In addition, their foraging complements that of other livestock. For example, sheep can graze rough grasses and weeds that cattle find unpalatable. Some survive even the stress of extreme aridity and for this reason are the predominant livestock in North Africa and the Middle East.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Many small breeds can be disease resistant. Some, for example, are widespread in the zones of Africa where trypanosomiasis is prevalent. They are generally less adversely affected by foot-and-mouth disease than are cattle, and some small native sheep seem to have fewer problems with insects and parasites than do most other livestock, including temperate-area sheep.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Giving more attention to the management and improvement of microsheep could pay back abundantly in the form of food, income, and improved land utilization in many parts of the developing world. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">AREA OF POTENTIAL USE</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Worldwide, but notably in drier regions of the tropics.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">APPEARANCE AND SIZE</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">An average weight for temperate sheep breeds is about 70 kg,' but the smallest microsheep weigh less than 20 kg fully grown. Many tropical microsheep are "hairless," and have little or no wool. These are often difficult to distinguish from goats, but (like all sheep) they generally have blunter snouts, more fat, and hanging tails. Some have greatly enlarged rumps or tails that store fat. Unlike goats, sheep have no odor-producing glands.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Some representative microsheep are described at the end of this chapter.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">DISTRIBUTION</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">More than one billion sheep occur worldwide, and they occupy every climatic zone in which people live. At least half are in developing countries.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">STATUS</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Although more than 1,000 breeds are recognized, only a handful dominate the world's sheep industries. Lesser-known breeds are rapidly becoming extinct (especially in developed countries, although scattered efforts are being made to preserve them). Elsewhere, genetic resources have not been properly evaluated, and potentially valuable stock is being lost before it is even understood.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">HABITAT AND ENVIRONMENT</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Sheep are among the most adaptable animals. Various types are kept in areas of extreme heat, cold, altitude, aridity, humidity, and rainfall. They are especially widespread in hot, dry climates, but some breeds also thrive in humid areas. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">BIOLOGY</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Sheep make efficient use of a wide variety of fodder: tree leaves, fortes, grasses, crop residues, and agricultural by-products, for instance. They often survive privation by calling on their reserves of body fat.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">In the tropics, sheep reach sexual maturity in about a year. Many breeds lamb year-round, which allows for a continuous production of premium meat. Gestation takes about five months, and lambing is usually timed to occur when feed is most abundant and nutritious. Microsheep often bear two or more young and, under good management, may produce lambs annually for more than five years.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">BEHAVIOR</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">These shy animals flock together and, in general, are managed with little effort. They are easily panicked, however, and rams can become aggressive during rutting or when threatened.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">THE LITTLE SHEEP THAT COULD</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Dozens of the world's neglected breeds of tiny sheep should be preserved from extinction, for many will undoubtedely prove to have outstanding qualities. Current efforts to save the Navajo sheep in the United States exemplify what can be achieved</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The Navajo is a microsheep, and is perhaps the oldest breed of sheep in the United States. It may have been introduced to North America in 1540 by the Spanish explorer Francisco Vazquez de Coronado, who was seeking the mythical Seven Golden Cities of Cibola in the region that is now Arizona and New Mexico. Smaller than many dogs, a full-grown Navajo sheep may weigh only 30 kg, but it became a big part of the culture of the Southwest. Although the Navajos and other local Indians had never seen sheep before the 1500s, they soon became shepherds and weavers, and their rugs made from the unique wool of this wiry little animal remain famous even today.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Navajo sheep have white or brown wool hanging in ringlets around their bodies. The fleece is a double coat: long, coarse guard hairs on the outside and short wool on the inside. It yields warm, waterproof, and long-lasting products. Many of the sheep have four horns because the Indians believed that this trait was sacred, and they favored four-horned rams for breeding purposes.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The number of Navajo sheep was reduced sharply between 1950 and 1950 because of severe overgrazing and replacement by improved wool breeds. In recent times there has been so little commercial and scientific interest in this microsheep that by the 1970s only a handful of purebred specimens survived. Since the late 1970s, however, Lyle McNeal, a Utah State University professor, has been working to save it from extinction. By 1988 he had a burgeoning flock at the university and was learning that this supposedly obsolete dwarf is amazingly useful.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The breed originated in the arid south of Spain (where it is called the "churro"), and it thrives in the hot, dry climate. Unlike normal breeds, it can exist in the desert without supplementary food and with little water. As McNeal has pointed out, any sheep that can survive and raise a lamb in the aridity and searing heat of the American Southwest has to be superior. He has found that the ewes have a strong maternal instinct, which is vital for protecting lambs against the coyotes that are common in the region. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Thanks to the efforts of McNeal and his colleagues, Indians are beginning to use Navajo sheep again; by 1988 there were more than 400 on the Navajo reservation, with their wool fetching premium prices. This tough little sheep could prove valuable not only for American Indians but for poor people in many other dry regions as well. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">USES</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">Microsheep are mainly kept for meat production, but - especially in arid regions - for milk as well. Their meat is usually lean with little "muttony" taste.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Wool or hair is taken from many breeds, although the yield is often small. Skins from hair sheep' thinner than cowhide, are widely used and are in international demand. In some places, manure is considered an important product. In Nepal, thousands of small sheep are used as pack animals, especially to carry salt into mountain valleys.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">HUSBANDRY</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">Most sheep are maintained in free-ranging flocks. Many are grazed (often tethered) over a small area during the day and confined in a "fold" at night. Others are penned or kept as village scavengers. These are usually fed supplements of household scraps.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Sheep form an integral part of a mixed farming economy; for example, they may graze pastures during the wet season, and survive on crop residues and field weeds during the dry season. They have excellent foraging capabilities and are often kept alongside goats. This broadens the variety of forages utilized and often increases total production from a single piece of land, for sheep and goats have complementary feeding habits and male goats help protect the sheep from some predators.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">In spite of the heavy toll that predators (such as feral dogs) can take on lambs and ewes, the largest proportion of sheep in the tropics are lost through lack of basic care. Modest supplemental feeding of lambs and inexpensive preventive medicines can do much to lower mortality and boost production.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">ADVANTAGES</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Sheep are multipurpose animals, and almost everywhere they produce several products. The rich milk is often preferred to that of cows or goats, especially for making cheese and yogurt.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Lambs form an important part of the household economy for much of the rural world, and only rarely is social or religious stigma attached to keeping or eating them. Indeed, sheep are the traditional feast animals of several religions, and in some places sheep meat is preferred to beef and sells at a premium.</P>
+<P ALIGN="JUSTIFY">By and large, all sheep products can be processed, utilized, or marketed by the producer. In addition, sheep marketing and transportation systems exist in most countries, at least to some degree.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Sheep are efficient producers and can provide a quick turnover for food and cash. On the brush and coarse grasses of marginal lands, they may be more productive than cattle, and on grass they may outproduce goats. As long as they are not overstocked, sheep do not degrade vegetation; unless starving they will not debark trees. Small breeds cause little erosion, even on steep slopes, heavily traveled paths, or near water holes.2 In South Asia, they have been continuously stocked on the same ground for thousands of years without causing apparent harm.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Because sheep have a natural tendency to accumulate fat, they "finish" well on grazing and usually do not require a high-energy finishing diet.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">LIMITATIONS</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Despite their general healthiness, sheep are affected by many internal parasites and diseases, a few of which are communicable to man. They are especially susceptible to infectious conjunctivitis (pinkeye).</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Predators and thieves can be greater threats than sickness. Labor inputs can be high because of the almost continual protection sheep need.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Some mutton has a strong taste that many find unappealing. However, the taste is carried mainly by the fat, and the generally lean microsheep are often commended for their fine-textured, sweet meat.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">RESEARCH AND CONSERVATION NEEDS</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The numerous breeds of small sheep should be investigated. Assessments should be made for the animals' ability to thrive under adverse conditions and for resistance to particular diseases and parasites.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">As noted, even minimal extension services and veterinary support for sheep could greatly decrease mortality, especially among lambs.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Improving microbreeds without increasing their size is one of the most interesting challenges facing sheep scientists today. While efforts should be made to conserve and select within types, research should also be conducted on hybrid vigor. Efforts to improve the pelt and fleece of microsheep should also be encouraged.</P>
+<P ALIGN="JUSTIFY">More studies on the interactions between sheep and cropping systems are needed. Sheep (and the manure they produce) could become important components of forestry (see sidebar), crop rotation, alley cropping, and other forms of sustainable agriculture. For instance, sheep are especially effective for weed control in plantation crops such as oil palm and rubber as well as in forests.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">SMALL SHEEP IN THE FOREST</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Even in countries with long traditions of raising large sheep, there are opportunities for using small, agile, hardy breeds. The following is an example.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Seeking safer methods for stopping brush from smothering newly planted trees, U.S. government foresters have turned from chemical defoliants to flocks of sheep. Court decisions in 1983 and 1984 barred the use of herbicides along Oregon's Pacific Coast. Various alternatives were tried, and the animals proved the most successful. Sheep are now the favored method for controlling unwanted vegetation. Indeed, they have changed the foresters' whore approach to managing reforestation.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Formerly, the U.S. Forest Service allowed the brush to grow on logged-over sites and then sprayed it down before planting tree seedlings. Now it plants grass to suppress brush and reduce erosion. The sites are later fertilized, tree seedlings are planted, and within a year sheep are brought in to graze. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Today, in the district around Alsea, Oregon sheep nimbly skirt old stumps to graze on the lush vegetation. Three times each summer since 1984, about 2,000 sheep have been guided across the replanted areas by a herder and a range conservationist. The sheep eat both the grass and the new buds on brush, but they leave most fir-tree seedlings untouched. The key, according to Rick Breckle, a forester, is to have enough sheep to graze an area evenly and to keep them moving so they don't resort to nibbling the young trees.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Previously, chemical brush treatments had annually cost $135-$353 per hectare. Now, sowing grass and grazing sheep costs about $300 per hectare. And there is a product to sell: the adult sheep don't fatten well, but the lambs bring a useful income at the end of the summer. What is more, Breckle reports that the trees seem to be growing faster - probably because of the manurings they receive.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">This method seems likely to be effective elsewhere - at least with trees that are unpalatable or too tall for their growing points to be nibbled. Malaysia, for instance, doubled its sheep population between 1986 and 1989, in part because it has begun raising sheep between the trees in rubber plantations. With the use of agroforestry increasing worldwide, small sheep could find a whole new application.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">REPRESENTATIVE EXAMPLES OF MICROSHEEP</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">West African Dwarf</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Senegal to Nigeria, and south to Angola. Female 25 kg; male 35 kg. Well adapted to warm, humid conditions. Prolific, and good disease resistance. Major meat producer in West Africa. Fast growing: by six months of age they approach adult weight.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Landim (Small East African)</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">East and Central Africa. 23-40 kg. Prolific, adaptable, long fat-tailed type. Large litter size for a sheep. In one recent test, ewes averaged more than 1.4 lambs.3 </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Berber</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Atlas Mountains. 25-41 kg. Needing little feed and remaining constantly outdoors, these extremely hardy sheep are exploited for meat and their coarse, hairy wool. They fatten easily when well fed.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Arab</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">North Africa. 40-50 kg. This thin-tailed sheep is exceptionally robust, and is resistant to extremes of temperature, drought, and poor nutrition. Primarily a meat producer, its wool is used for coarse cloths and carpets.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Southern Sudan Dwarf</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">One of the many small breeds of eastern and southern Africa, its weight ranges from 15 to 25 kg, but it may weigh as little as 11 kg. Yielding a fine, short fleece, this hardy, frugal sheep is often run with cattle to maximize grazing.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Hejazi</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Deserts of Arabia. 32 kg. A popular and ancient fat-tailed meat producer that is highly acclimatized to drought and privation.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Zel (Iranian Thin-Tailed)</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Caspian region of northern Iran. Female 30-32 kg. Well adapted to subtropical regions, they produce coarse wool, milk, and excellent meat that lacks the "mutton taste" and odor of some sheep meats.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Greek Zackel</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Mountain and island types. Female 30 kg; male 40 kg. These common sheep are active, hardy, and resistant to extremes of climate and disease. Primarily a milking sheep, their wool is used locally and lambs are slaughtered for special occasions. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Sitia</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Crete. Female 25 kg; male 30 kg. Another of the hardy, screwhorned "zackel" sheep common to the Balkans, they are adapted to poor pasturage and extensive herding. Quick maturing and highly fertile, they can be exploited for milk as well as for meat and coarse wool.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Common Albanian</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Female 25 kg; male 35 kg. Similar to the Greek Zackel, they are used as triple-purpose animals: meat, milk, and wool. They survive in low, marshy areas where parasites are common.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Zeta Yellow</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Yugoslavia. Female 25 kg; male 35 kg. A small, hardy sheep used for milk and some meat, its primary product is wool. Often unshorn for several years, the long fibers are woven into expensive carpets.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Pag</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Yugoslavia. Female 20-30 kg; male 25-35 kg. These wool, milk, and meat sheep are frugal and well adapted to scant vegetation and rocky terrain. Although they have a low birth rate and carcass yield, their milk and wool are commercially exploitable.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Roccia (Steinschaf)</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Northern Italy, Austria. Female 30 kg; Male 30-35 kg. These "stone sheep" resemble a goat in their ability to exploit the poor pastures of high, steep, rocky mountains. Although not highly productive, they are hardy and frugal and commonly produce twins.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Corsican</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Corsica (France). 25-30 kg. A hardy native breed that is well adapted to rather sparse feed conditions. Coarse wool, both white and black, is well suited for hand processing. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Entre Douro e Minho</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Portugal. Female 15-18 kg; Male 20-25 kg. These independent sheep yield a good wool in mountainous terrain that would otherwise be nonproductive.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Churra do Campo</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Portugal. Female 20 kg; male 30 kg. A coarse-woofed sheep extensively kept in Portugal's dry interior for milk and wool. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Galician</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Spain. Female 18 kg; male 25 kg. A milking breed that survives on  poor pasture, it also produces a marketable wool.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Soay</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Scotland. Female 25 kg; male 30 kg. Adapted to wide temperature  variations. Possibly the most primitive domesticated sheep of Europe,  probably unchanged from Viking times. Immune to foot rot. A wool  sheep with short brown fleece that is shed annually.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">North Ronaldsay (Orkney)</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Northern Scotland. 27-32 kg. Surviving year-round on seaweed,  this rare breed is adapted to high salt intake and the associated digestive  problems. Yield 1-2 kg medium-coarse wool.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Criollo</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Latin America. Derived from ''native'' Spanish Churro and Merino  sheep. Many are small and very hardy.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Navajo-Churro Southwestern United States. Female 45 kg; male 70  kg. Maternal, and very resistant to internal parasites and hoof rot.  Although the Navajo subsists and reproduces on little feed and scarce  water in desert regions, it was widely replaced by improved breeds  earlier in this century. Because of its hardiness, however, and the use of  its wool in traditional weaving, its numbers are rebounding (see sidebar,  page 50). </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Florida Native Southeastern United States. Females 35-45 kg;  males 45-6O kg. This long-isolated and highly variable sheep is  adapted to harsh subtropical climates and is known for its ability to  forage. A medium-wool breed, it is very resistant to intestinal parasites.  Verging on extinction due to neglect and uncontrolled crossbreeding. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Virgin Islands White Hair (St. Croix)</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Caribbean. Female 35-45 kg; male 45-55 kg. Hair sheep with  some wool in young animals. Well adapted to warm humid conditions, it has fairly good disease and parasite resistance and produces good meat. Prolific, it breeds most of the year and commonly has twins.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Magra (Chokhla)</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Northwest India, Pakistan.4 20-25 kg. Adapted to hot, dry areas, the extremely white and shiny fleece is valued for carpet wool. Slowmaturing and low fertility (lambing at 45 percent) plus extensive crossbreeding have led to serious declines in population.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Marwari</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Northwest India. 25-30 kg. A widespread, white-fleeced sheep that has a high resistance to disease and worms, good fertility, and low mortality. They do well in large flocks.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Mandya (Bandur)</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Southwest India. Female 25 kg; male 35 kg. An outstanding meat breed with good mutton quality, it adapts well to mixed farming and has unusually low lamb mortality.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Hu (Huyang, Lake Sheep)</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">China. Female 35 kg; male 45 kg. These fat-tailed sheep have a six month lambing interval and are very prolific. They are used under intensive management to produce meat, wool, and a valuable lambskin.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Javanese Thin-Tail</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">Indonesia. 25-40 kg. Widely held as a "bank account," these meat, manure, and skin sheep are well known for being prolific. Although single lambs are not uncommon, litters of six have also been recorded. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">WILD AND WOOLLY</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Considering that dozens of countries depend on the productivity of more than a billion domesticated sheep, it is remarkable that their wild ancestor is accorded no attention. This fast-declining animal is now little more than a trophy for hunters, a fact that should be of vital intemational concern.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Sheep were domesticated in the Middle East and Central Asia in the Stone Age era between 8,000 and 11,000 years ago.* Their wild ancestor was almost certainly the mouflon (Outs orientalis). However, domestication may have occurred in more than one place, and two other wild creatures, the urial (Outs vignei) and the argali (Outs ammon), also possibly provided genes to some sheep breeds.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The mouflon, urial, and argali still exist in the mountains of Central Asia, and a European subspecies of mouflon is also found in the Mediterranean, but only on Corsica, Cyprus, and Sardinia.** Because they live in remote, rugged, upland areas, these wild sheep are usually undisturbed, but the numbers are decreasing everywhere.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">This may be a serious loss because these animals could be extremely valuable. They are capable of crossing with domestic sheep, and the offspring are viable and fully fertile.*** For developing new meat-producing breeds, their potential seems almost limitless.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">During the thousands of years that sheep have been protected by humans, their wild ancestors have continued to face predators, parasites, disease, extreme cold and seasonal starvation. Their genetic endowment, forged and tempered in unforgiving harshness, could be a benefit for all future sheep generations. These animals appear to resist various diseases. Their meat is reported to be of excellent quality, notably lacking the strong mutton flavor that many people find objectionable. They have relatively short, thin tails - a feature that might eliminate the need for docking (tail removal) in the domestic flock. Some (for instance, the Asian mouflon and the urial) have rates of effective reproduction up to 1.6 lambs per ewe, more than twice the average of most domestic types, especially under the conditions where these wild creatures live.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">That mouflon and other wild sheep could have practical utility is suggested by research at Utah State University. Scientists there have mated mouflon with farm sheep to create sheep better able to defend themselves against coyotes and other natural dangers. Half-wild, half-tame sheep hybrids have existed on a ranch in southern Utah for the past decade. Also, in Cyprus similar mouflon x sheep hybrids have shown considerable promise.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">At the very least, this wiry little mountain sheep could be a model for educating students and the public. It is a living reminder of the fantastic changes that can be induced in animals by selection for various traits. Also, it is a "map" to the history of sheep domestication. Studies of mouflon genes, blood immunology, morphology, physiology, horn structure, skeleton, fleece, temperament, and a host of other features would help unravel the ancestry. These studies and various biochemical analyses would be a fascinating contribution to agriculture, science, history, and the public perception of the origins of our natural resources.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Genes from wild sheep are not likely to quickly benefit wool production. Lack of fleece is one reason why these creatures have been neglected but throughout most of Asia and in North Africa, sheep are bred primarily for meat and milk, and there is a growing worldwide interest in the use of hair sheep. All of this brings new possibilities for the use of this old resource.</P>
+<P ALIGN="JUSTIFY"></P>
+<B><P>&lt;&lt;TOC3&gt;&gt; 4 Micropigs</P>
+</B><P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&lt;&lt;I&gt;&gt; g005a.png FIGURE</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Most breeds of swine (Sus scrofa) are too large to be considered microlivestock, but there are some whose mature weight is less than 70 kg. These micropigs are particularly common in West Africa, South Asia, the East Indies, Latin America, and oceanic islands around the world. At least one, the Mexican Cuino, may weigh a mere 12 kg full-grown.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Many miniature swine have been developed for use in medical research, but their agricultural potential has been largely ignored. This is unfortunate, for micropigs of all types - native, feral, and laboratory - deserve investigation. Swine provide more meat worldwide than any other animal, and micropigs are potentially important sources of food and income for poor people in many parts of the developing world.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Smallness makes for nimble and self-sufficient pigs, in contrast to large, lethargic breeds. Small breeds are easier to manage and cheaper to maintain; the threat of injury from angry or frightened animals is lessened; and the sows are less likely to crush newborn piglets, often a major cause of mortality in large breeds. Some micropigs - particularly those from hot regions or wild populations - also have a higher resistance to heat, thirst, starvation, and some diseases.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Pigs adapt to a wide variety of management conditions, from scavenging to total confinement; some are even kept indoors.2 They gain weight quickly, mature rapidly, and help complement grazing livestock because they relish many otherwise unused wastes from kitchens, farms, and food industries, as well as other foods such as small roots, leafy trash, or bitter fruits that are not consumed by humans or ruminants. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">For these reasons, micropigs could become useful household and village livestock in the developing world, and they deserve greater attention than they now receive. Although their growth may not be as rapid as that of improved breeds raised under intensive commercial production, with modest care and minimum investment, backyard micropigs can produce sizable yields of meat and other products, as well as improved income for rural and even urban populations.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">AREA OF POTENTIAL USE</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Worldwide, especially in warm, humid areas.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">APPEARANCE AND SIZE</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Like full-sized breeds, micropigs are stout-bodied, short-legged animals with small tails and flexible snouts ending in flat discs. Examples of some micropigs are listed at the end of the chapter.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">DISTRIBUTION</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Domestic pigs are found all over the world, but their concentrations vary greatly. Africa has the fewest per capita, but in recent years they have gained increasing favor in the sub-Saharan regions. In Latin America, pigs have long been a major component of backyard agriculture. In the Middle East, an early center of domestication, pigs are not widely kept today because of religious dietary restrictions. In the Ear East, they are the major meat source, and China has more pigs than any other country. And in the Pacific region, pigs and chickens are often the only meat available.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">STATUS</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Pigs are becoming more popular: their worldwide numbers increased by about 20 percent in the 1970s. However, in most countries commercial pig production has focused on a mere handful of breeds, and much genetic diversity is unstudied or even threatened with extinction. Some microbreeds have already been lost, and others are dwindling in numbers.3 Many European breeds have been completely lost. The Cuino and some other Latin American criollo types are threatened, as are most of Africa's traditional breeds. China, however, has made notable efforts to preserve its native types. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">HABITAT AND ENVIRONMENT</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Although, as previously noted, pigs are found all over the world, they are in general adapted to warm, humid climates where many other livestock species are more susceptible to diseases and environmental stresses. They are also raised at high altitudes, such as in the Andes and Tibet. Although there are few climatic limitations to pig production, only about 20 percent of the world's pigs are currently kept in the tropics.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">BIOLOGY</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Pigs are omnivores, willing and able to eat almost anything.4 Unlike most other livestock, they eat their fill and sleep as the food digests, allowing humans to establish a convenient eating and sleeping schedule.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Pigs are prolific; a few Chinese breeds routinely have litters of 20 or more. Micropigs are no exception; litters of 6-10 are common. Piglets gain weight rapidly and can be weaned after a few weeks. Sexual maturity is sometimes attained as early as 4-6 months, depending on breed and environment. Pigs are usually slaughtered at 67 months of age, allowing them to be produced on an annual cycle. They can live 10-20 years.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Because of their smaller size, micropigs have a relatively greater skin-to-weight ratio than today's commercial breeds, and therefore they probably shed heat more effectively. Certainly they seem to perform better in tropical heat and humidity, which normally keep the heavier types from reaching their maximum productivity. Studies have suggested that an optimal size for some tropical environments - because of metabolic and feed efficiency - may be less than 65 kg.5</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">BEHAVIOR</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Pigs are social animals; they enjoy companionship and ferociously defend their young and sometimes even the humans who care for them. They are employed as guard animals in some areas and have been used extensively in behavioral research.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Contrary to common belief, pigs are clean and tidy if provided adequate space. Larger breeds, however, wallow in mud to stay cool in hot weather and require a wallow or shade (except for some Latin American types, which seem less susceptible to heat). Some lightcolored pigs sunburn easily.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Pigs will dig up earth with their mobile snouts; some breeds do it constantly. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">USES</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Fresh pork is the major pig product in tropical areas. It usually fetches premium prices, and in many places (such as the Pacific Islands and China) it is the most important red meat available to rural people. Nutritious and tasty, it is one of the easiest meats to preserve, needing only salt or melted fat. Processed products such as bacon and sausages can be important for both home consumption and cash sales.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Pig fat (lard) is a good source of food energy, and can substitute for cooking fats and oils. It is easily melted and clarified, is widely used to make soap, and is a valuable commercial product.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Pig skin, once degreased, is easily tanned into leathers that are popular for garments, shoes, and other products demanding soft, light, and flexible leathers.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Pig manure is a good fertilizer. Because the animals are often kept in confinement, it can be easily collected.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">HUSBANDRY</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">In many places, pigs are kept as free-roaming scavengers. They can be trained (by coaxing with feed, salt, or affection) to keep close to home, thereby helping to minimize destructive scavenging.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Herding is a higher level of management that requires more effort, but it allows pigs to be integrated into other types of agriculture while utilizing feeds that otherwise go to waste.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Because their exercise needs are minimal and dominance is quickly established within litters, pigs are the easiest hoofed livestock to raise in small enclosures (sties). However, fencing must be secure, and if sties are small, the animals must be moved frequently to prevent diseases and parasites from building up.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">ADVANTAGES</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Pigs are well-known, often traditional, animals in many areas, and people usually do not have to be taught how to manage and use them. Efficient scavengers, they can live, grow, and reproduce with a minimum of investment or specialized care. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Pigs are highly efficient converters of feed to meat. They can provide the greatest return for the least investment of any hoofed livestock because of their fecundity, low management costs, broad food preferences, and rapid growth.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Pigs normally accumulate fat during adolescent growth (making ''finishing" feeds less necessary). Some micropigs (especially those from feral ancestors) have the ability to quickly mobilize and store these body-fat reserves; in times of extreme scarcity, it aids their survival.6</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Pigs work well in multiple-cropping schemes. They are often used to help clear small plots by uprooting weeds, shrubs, and even small trees. In Southeast Asia, they are frequently raised in conjunction with aquaculture, their manure providing food for the fish.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">LIMITATIONS</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">If improperly managed or maintained in filthy conditions, pigs may quickly succumb to disease and parasite epidemics. Most diseases are communicated only among pigs, but some can be transmitted to humans. For this reason, pork should always be fully cooked.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Some cultures never eat pork. Others do, but nonetheless accord pigs and their keepers low status.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Young pigs are vulnerable to many predators.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">RESEARCH AND CONSERVATION NEEDS</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">A major survey of small pig breeds is needed. They have the potential to be valuable producers in their own right, as well as to improve other pig breeds. For instance, they represent a little-known reservoir of disease resistance and climatic adaptation. Governments, research stations, universities, and individuals should make special efforts to preserve types that have outstanding or unusual qualities.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">When it is necessary to eradicate feral pig populations (as is common on Pacific islands), representative stocks should be preserved. These rugged animals have been genetically isolated for decades or even centuries and are likely to carry valuable traits for survival under adversity.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Large breeds may be promising candidates for genetic "downsizing," which has already produced the many types of miniature pigs that are used in medical research. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">THE LITTLEST PIG</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Although this chapter highlights the world's smallest breeds, there exists a pig that is even smaller. It is, however, an entirely different species and it is on the brink of extinction.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The pigmy hog (Sus salvanius) is a shy and retiring wild creature of northeastern India. It is merely 60 cm long with a shoulder height of 25 cm, and weighs less than 10 kg. It was once found widely along the southern foothills of the Himalayas. Today, however, it apparently occurs in only one area, the Manas National Park in Assam. Despite this protection and the fact that it is listed among the 12 most endangered species on earth, it still falls victim to hunters and to habitat destruction - especially illegal grass fires.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">If saved from extinction, this minute species - barely reaching a person's calf - might become useful throughout the world. Its chromosome number is the same as that of the common pig and its physiological processes are probably also similar. Therefore, were its numbers to be built up, it might become a valued and well-known resource for laboratories and small farms. Its daily food intake and its space requirements are only a fraction of a normal pig's. It probably has exceptional tolerance to heat, humidity, and disease.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">This is not a domesticated species, and there is therefore much to learn before its usefulness can be clearly seen. Indeed, whether it can be reared in captivity is uncertain. Some attempts have ended in disaster, but this seems to have been the result of mismanagement.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Before there is any possibility of developing it, however, the pigmy hog must be preserved from ultimate loss. The last specimen could go into a villager's pot at any time now. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&lt;&lt;I&gt;&gt; g006a.png Adult male of the common pig (wild boar) and pigmy hog draw to same scale. (W.L.R. OLIVER)</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">REPRESENTATIVE EXAMPLES OF MICROPIGS</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">West African Dwarf (Nigerian Black, Ashanti)</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">West Africa. Mature weights of 25-45 kg are reported. In the humid lowland forests of West Africa this breed has long been kept by villagers, often as a scavenger. Indigenous to the hot, humid tsetse zones of West Africa, it seems resistant to trypanosomiasis.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Chinese Dwarfs</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">China (and Southeast Asian countries such as Vietnam) has long had small pigs - often characterized by numerous teats and large litters - associated with traditional intensive agriculture as well as scavenging conditions. Some Chinese pigs weighing less than 70 kg are adapted to tropical and subtropical conditions, but the smallest (20-35 kg) live in the cold climates and high altitudes of Gansu, Sichuan, and Tibet. Small black Chinese pigs were crossed with European types in the early 1800s and produced the foundation stock of many modern Western breeds.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Criollo</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">There are a number of "native" breeds throughout Latin America commonly known as "criollo." Many are quite small. Although, apparently, they are slow to mature and bear small litters, they adapt well to environmental extremes and are widely kept by rural inhabitants for food and income. Criollos are little studied and are being replaced by imported breeds before their possibly outstanding qualities can be quantified.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Cuino This micropig from the highlands of central Mexico may be descended from small Chinese types and is the smallest domestic pig, weighing as little as 10-12 kg fully grown. Hardy and an efficient scavenger, it can grow quickly when feed - especially corn - is abundant. A century ago the cuing was a widespread household animal and was used for a time for experimental work in central Mexico. It is now little known and could be threatened with extinction. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Black Hairless (felon, Tubasqueno, Birish) These small pigs of central and northern South America survive in hot, humid, adverse climates. They are adapted to bulkier feeds than most pigs and can thrive on fruit wastes. Many local types exist. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Nilo (Macao, Tatu, Canastrinha) This small, widespread, black, hairless pig of Brazil is often kept inside the house. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Yucatan Miniature Swine A subtype of the black hairless from Mexico's hot, arid Yucatan Peninsula, it was imported into the United States in 1960. It has been downsized for laboratory use in the United States and is known as the Yucatan Micropig (registered). Weight at sexual maturity has been lowered through selective breeding from 75 kg to, currently, between 30 and 50 kg, with an ultimate goal of 20-25 kg. There is no evidence of "dwarfism," stunting, or loss of reproductive performance, and it appears to hold notable promise as microlivestock for developing countries. The parent stock, used for meat and lard production in Yucatan, is renowned for gentleness, intelligence, resistance to disease, and relative lack of odor. Exceptional docility, even in older boars and sows with litters, makes them easy to handle without the need for specialized housing or equipment.7 </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Other Laboratory Breeds</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Other miniature laboratory pigs have potential for tropical use. These include the Goettingen, Hanford, Kangaroo Island, Ohmini, Pitman-Moore, and Sinclair (Hormel). In general they weigh 30-50 kg when ready for slaughter and mature at less than 70 kg.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Ossabaw</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">United States. 20-30 kg. Feral on Ossabaw Island, South Carolina, for more than 300 years, this pig is well adapted to environmental extremes. Unlike most domestic animals, it can maintain itself in coastal salt marshes. It has perhaps the highest percentage of fat of any pig. The piglets are very precocious, self-reliant, and robust.8</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Kunekune (Pua'a, Poaka)</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">New Zealand. Female 40 kg; male 50 kg. Perhaps of Chinese origin, these black-and-white spotted pigs are docile, slow, and easy to contain. Although late maturing, they can fatten on grass alone. Like other native breeds throughout the Pacific region (for example, the Pauta of Hawaii), stock is being lost through crossbreeding, displacement by other breeds, and eradication efforts. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">To find certain disease-resistant genes in poultry it may be necessary to go looking in the backyard chicken flocks in Latin America, Africa, or Asia.</P>
+<P ALIGN="JUSTIFY">Kelly Klober</P>
+<P ALIGN="JUSTIFY">Small Farmer's Journal</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">. . . Policies are needed to encourage development of a labor-intensive small-scale livestock sector, which would increase employment and provide a major market for surplus cereals. This sector, however, is particularly restrained by poor technology, poor public support services, and poor marketing channels. Third World livestock production of this type could provide a natural focus for foreign assistance that earlier seemed inappropriate because of concerns about global food scarcity.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">John W. Mellor International Food Policy Research Institute</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Successful development of agriculture often requires an intimate understanding of the society within which it is to take place - of its systems of values, of its customary restraints.... It has been necessary to understand what incentives the farmer needs to change, what practical difficulties he encounters introducing change, what his traditional pattern of land use is and how this pattern or system can be upset by thoughtless innovation.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">John de Wilde</P>
+<P ALIGN="JUSTIFY">Experience with Agricultural Development in Tropical Africa </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<B><P ALIGN="CENTER">&lt;&lt;TOC2&gt;&gt; Part II : Poultry</P>
+</B><P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&lt;&lt;I&gt;&gt; g007a.png FIGURE</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Chickens, ducks, muscovies, geese, guinea fowl, quail, pigeons, and turkeys epitomize the concept of microlivestock. Throughout Africa, Asia, and Latin America they are (collectively) the most common of all farm stock. In many - perhaps most - tropical countries, practically every family, settled or nomadic, owns some kind of poultry. In the countryside, in villages, even in cities, one or another species is seen almost everywhere; in some places, several may be seen together. Although raised in all levels of husbandry, these birds occur most often in scattered household flocks that scavenge for their food and survive with little care or management.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Their size bestows microlivestock advantages, including low capital cost, low food requirements, and little or no labor requirements. They are also "family sized": easily killed and dressed, with little waste or spoilage.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">These poultry species help meet the protein needs of the poorest people in the world. Some are raised even in areas where domestic cattle cannot survive because of afflictions such as trypanosomiasis and foot-and-mouth disease. Some are maintained under conditions of intensive confinement - provided a source of feed is available - and can be produced in areas with insufficient land for other meat-producing animals.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">In addition, these birds grow quickly and mature rapidly. (For instance, a chicken can, under proper conditions, reach maturity in 26 months.) They adapt readily to being fenced or penned much, or all, of the time. And, compared with the major farm livestock, their life cycles are short and their production of offspring is high. Thus, farmers can synchronize production to match seasonal changes in the availability of feed. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Although poultry contribute substantially to human nutrition in the tropics, it is a small fraction of what it could be. The meat is widely consumed and is in constant demand. An excellent source of protein, it also provides minerals such as calcium, phosphorus, and iron, as well as the B-complex vitamins riboflavin, thiamine, and niacin. Nutritionally as complete as red meat, it is much lower in cholesterol and saturated fats. Poultry eggs are also important sources of nutrients. They are a renewable resource, easy to prepare, and are among the best sources of quality protein and vitamins (except vitamin C).</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">In spite of their numbers and potential, poultry are rarely accorded primary consideration in economic development activities. All in all, these small birds lack the appeal of large, four-legged livestock. Indeed, most countries have little knowledge of the contribution household birds actually make to the well-being and diets of their peoples. In some countries - even those where birds are widely kept - there is little or no poultry research or extension. And where such programs do exist they usually focus almost exclusively on the production of chickens under "industrial" conditions near cities (see sidebar, page 75).</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Most developing countries now have these intensive chicken industries, in which birds are kept in complete confinement. However, these commercial operations provide food for people in the cash economy, not for subsistence farmers. Moreover, grain is sometimes diverted or imported to maintain these operations, perhaps causing food shortages, higher prices, or depleted foreign exchange. Thus, in this section we focus on other, neglected, aspects of poultry production.,</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The neglect of poultry that scavenge around the rural farmhouses and in village yards is understandable. The birds are scattered across the countryside where extension programs are difficult to implement. Their presence is often so ingrained in traditional village life that they are taken for granted and ignored by the authorities.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Yet village poultry deserve greater attention. As converters of vegetation into animal protein, poultry can be outstanding. In fact, it is estimated that, in terms of feed conversion, eggs rank with cow's milk as the most economically produced animal protein, and that poultry meat ranks above that of other domestic animals.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Most Third World poultry flocks live a wary, half-wild existence, scrounging for insects, earthworms, snails, seeds, leaves, and leftovers from the human diet. From dung and refuse piles they salvage undigested grains, as well as insects and other invertebrates. Often the persons who care for them are women or children. Some keep the birds around the house, penning them at night for protection from predators and thieves.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">This almost zero-cost production has, in spite of high losses, a remarkable rate of return. Any improvements that require the purchase of supplies cut severely into the profitability. The first step in improving the production of free-ranging poultry is vaccination against diseases (especially Newcastle disease, fowl pox, and Marek's disease) and a modest, supplemental feeding during times of seasonal scarcity. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">THE INDUSTRIAL CHICKEN</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Throughout modem livestock farming the trend is toward more intensive methods, and poultry specialists have set the pace. In many countries, since the 1920s, barnyard fowl have given way to egg and broiler factories. The old-fashioned chicken reared outside on corn stubbles for 5 or 6 months has been replaced by the broiler, mass-produced in controlled environment houses in 7 - 10 weeks.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">As a result of this revolution in poultry raising, small farmers who once made a comfortable living from a few laying hens have been forced out of business. These economic changes have also forced poultry men to have larger and larger flocks to survive. The largest broiler-chicken companies even control their own breed development, feed production, house construction, slaughtering, and freezing, many even have wholesale outlets.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The rapid changes in poultry farming methods can be attributed to the application of advanced technology. The development of the incubator to replace the mother hen sitting her seasonal clutch of eggs was the first mayor step toward intensive poultry farming.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">In addition, chickens were the first livestock to receive serious attention from geneticists. Before World War II, it was discovered that crossbreeding selected pure and inbred lines could result in dramatic increases in production. Hybrids tailor-made for egg or meat production quickly ousted the old pure breeds such as the Rhode Island Red White and Brown Leghorns, Light Sussex, and the various crosses among them. Chicken broilers made by crosses involving parents derived from Cornish and Plymouth Rock have supplanted all others.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">This situation now prevails in most industrialized countries. The breeding of commercial stocks is in the hands of a few corporations for each commodity (white eggs, brown eggs, chicken broilers, turkeys) and each has national or even global distribution of its hybrid stocks.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">A BREAKTHROUGH IN POULTRY HEALTH</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Newcastle disease is endemic in developing countries and is a constant threat to poultry. Farmers dread this virus, first identified half a century ago in northern England that brings diarrhea, paralysis, and death to most poultry. It is severe, highly contagious, and can cause 100 percent mortality. When it strikes an area, farmers must kill all chickens - even healthy ones - to stop it from spreading.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Only Australia, New Zealand, Northern Ireland and some Pacific islands are unaffected. But, although the disease is not found in Australia, certain strains of the virus are present in Australian chickens. These strains are completely harmless, but Australian researchers have found that they induce antibodies that are effective against Newcastle disease.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">In a joint project (funded by the Australian Centre for International Agricultural Research), scientists from Malaysia's University of Agriculture and Australia's University of Queensland* have put this to good use. They have produced a live culture of the harmless virus that farmers can spray onto feed pellets to vaccinate their birds.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Field tests of the new vaccine, carried out in Southeast Asia, have been extremely promising. Simply coating feeds with the virus seems to be enough to immunize some chickens, which then pass the immunity on to the others in the flock as well as to new hatchlings. In Malaysia, which has 49 million chickens and a population willing to pay a premium for tasty village poultry meat, one economist estimates that the vaccine might increase rural incomes by 25 percent.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Conventional vaccines must be stored under refrigerated conditions, which most villages lack. But the Malaysian workers made the Newcastle disease vaccine tolerant of heat. By selective breeding, they now have strains that resist 56&Yacute;C for at least 2 hours. Thus, even in the tropics, the vaccine remains effective for several weeks without refrigeration. The researchers have also devised methods for coating the vaccine onto pelleted feeds. Because the virus can withstand heat, they use a machine designed for coating pharmaceutical tablets.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">At this stage, the project is showing every promise of producing a cheap means of reducing Newcastle disease losses among chickens throughout much of the world. Already inquiries have come from other Asian countries and from Africa, and it is hoped that the vaccine may eventually benefit many countries. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<B><P>&lt;&lt;TOC3&gt;&gt; 5 Chicken</P>
+</B><P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&lt;&lt;I&gt;&gt; g008a.png FIGURE</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Chickens (Gallus gallus or Gallus domesticus)1 are the world's  major source of eggs and are a meat source that supports a food  industry in virtually every country. There may be as many as 6.5 billion  chickens, the equivalent of 1.4 birds for every person on earth.2</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">No other domesticated animal has enjoyed such universal acceptance,  and these birds are the prime example of the importance of  microlivestock. Kept throughout the Third World, they are one of the  least expensive and most efficient producers of animal protein.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">To the world's poor, chickens are probably the most nutritionally  important livestock species. For instance, in Mauritius and Nigeria more  than 70 percent of rural households keep scavenger chickens. In  Swaziland, more than 95 percent of rural households own chickens,  most of them scavengers. In Thailand, where commercial poultry  production is highly developed, 80-90 percent of rural households still  keep chickens in backyards and under houses. And in other developing  countries from Pakistan to Peru, a similar situation prevails.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Clearly, these chickens should be given far more attention. They  represent an animal and a production system with remarkable qualities;  they compete little with humans for food; they produce meat at low  cost; and they provide a critical nutritional resource.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Scavenger chickens are usually self-reliant, hardy birds capable of  withstanding the abuses of harsh climate, minimal management, and inadequate nutrition. They live largely on weed seeds, insects, and feeds that would otherwise go to waste.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Unfortunately, however, quantitative information about the backyard chicken is hard to obtain. Few countries have any knowledge of its actual contribution to the well-being and diet of their people. Notably lacking is an understanding of the factors limiting egg production, which is markedly low and perhaps could be raised dramatically with modest effort.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">AREA OF POTENTIAL USE</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Worldwide.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">APPEARANCE AND SIZE</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Chickens are so well known and ubiquitous that they need no further description. Varying in color from white through many shades of brown to black, they range in size from small bantams of less than 1 kg to giant breeds weighing 5 kg or more. Scavenger chickens tend to weigh about I kg.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The indigenous chickens of Asia are probably descended directly from the wild junglefowl. Those of West Africa are believed descended from European birds brought by the Portuguese in the sixteenth century; those of Latin America probably descend from Spanish birds introduced soon after the time of Columbus.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&lt;&lt;I&gt;&gt; p81a.png figure</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">DISTRIBUTION</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">All countries have chickens in large numbers.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">STATUS</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">They are not endangered, but industrial stocks are replacing traditional breeds to such an extent that much potentially valuable genetic heritage is disappearing. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">HABITAT AND ENVIRONMENT</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Although chickens derive from tropical species, they adapt to a wide  variety of environments. The modern Leghorn, for example, is found  from the hot plains of India to the frozen tundra of Siberia, and from  sea level to altitudes above 4,000 m in the Andes. (There are, however,  hatching problems at such high altitudes because of oxygen deficiency.)  They also occur in desert countries such as Saudi Arabia, which has a  vast poultry industry and even exports broilers. (However, the birds  need shade and a lot of water where it is hot and dry.)</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">BIOLOGY</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Chickens are omnivorous, living on seeds, insects, worms, leaves,  green grass, and kitchen scraps.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">A commercial bird may produce 280 eggs annually, but a scavenger  may produce close to none. Commonly, a farmyard hen lays a dozen  eggs, takes three weeks to hatch out a brood of chicks, stays with the  chicks six weeks or more, and only then starts laying again.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Egg production depends on daylength. For the highest production  rate, at least 12 hours of daylight are needed. The incubation period is  21 days. A hen can begin laying at 5 months of age or even earlier, but  in scavengers it may be much later. The average weight of the eggs is  approximately 55 g from industrial layers and approximately 40 g from  scavengers. Hatching success from breeder flocks often exceeds 90  percent. Industrial broilers can be marketed as early as 6 weeks, when  they are called "Cornish hens."</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">BEHAVIOR</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">These passive, gregarious birds have a pronounced social (pecking)  order. If acclimated, they remain on the premises and are unlikely to go  feral. If given a little evening meal of "scratch," they learn to come  home to roost at night.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">USES</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Chickens have multiple uses. They were probably first used for cock  fighting; later they were used in religious rituals, and only much later  were raised for eggs and meat. Today, chickens can provide a family  with eggs, meat, feathers, and sometimes cash.  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">HUSBANDRY</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">In different parts of the world, people keep scavenging chickens in  different ways. The managers are often women and children because  they have more time to spend at home to feed the birds and repel  predators. Some people leave the birds entirely to their own devices.  Many house them at night. Others take the birds each day to the fields,  where they may find much more food.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">There are many ingenious local practices. In Ghana, for example,  farmers "culture" termites for poultry by placing a moist piece of cow  dung (under a tin) over a known termite nest. The termites burrow into  the dung, and some can then be fed to the chickens each day. Because  termites digest cellulose, this system converts waste vegetation into  meat.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">A ratio of 1 male to 10-15 females is adequate for barnyard flocks.  Hens will lay eggs in the absence of a rooster - but of course the rooster  is needed if fertile eggs are wanted.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Removing chicks stimulates the hen to lay more eggs. This results in  more chicks being hatched, but it requires that the chicks be nurtured  and fed until they are old enough to fend for themselves.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">ADVANTAGES</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">Chickens are everywhere; every culture knows them and how to  husband them. They have been utilized for so many centuries that in  most societies their use is ingrained. Unlike the case with pork and beef,  there are few strictures against eating chicken meat or eggs.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The meat is high in quality protein, low in fat, and easily prepared. In  many countries, the village chicken's meat is preferred to that of  commercial broilers because it has better texture and stronger flavor.  Even in countries with vast poultry industries there is a growing demand  for the tasty, "organically grown," free-ranging chicken.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Chickens are more suited to "urban farming" than most types of  livestock and can be raised in many city situations.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The birds are conveniently sized, easily transported alive, and, by and  large, do not transmit diseases to humans.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">LIMITATIONS</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">Throughout Asia, Africa, and Latin America, the problems of village  chickens are mainly those discussed below.  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">High Hatching Mortality</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">Commonly, a hatch of eight or nine village chicks results in only two  or three live birds after a few days. A survey in Nigeria, for instance,  showed that 80 percent died before the age of eight weeks. Losses  elsewhere are known to be similar. This is mostly because of starvation,  cold, dehydration, predators (hawks, kites, snakes, dogs, and cats, for  example), diseases, parasites, accidents, and simply getting lost - all of  which can be prevented without great effort.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Chronic and Acute Disease</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">Poultry diseases can become epidemic in the villages because there  are few if any veterinarians. Newcastle disease, fowlpox, pullorum  disease, and coccidiosis, for example - all of which are endemic in the  Third World - can destroy the entire chicken population over large  areas. Lice and other parasites are also prevalent. Scavengers and  industrial birds seem to show no differences in their tolerance for such  diseases and parasites.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Low Egg Production</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">A survey in Nigeria showed that the annual production per hen was  merely 20 eggs. Such low production is common throughout the Third  World and is caused by a combination of low genetic potential,  inadequate nutrition, and poor management. Villagers rarely provide nest  boxes or laying areas, so that some eggs are just not found. Some birds  have high levels of broodiness, and eggs accumulating in a nest  stimulates this. There are indications, however, that some village  chickens (for example, some in China) have quite substantial egg-laying  potential when provided with adequate feed.3</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Low Egg Consumption</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">In the tropics, many people choose not to eat eggs. Often this is  because eggs are the source of the next generation of chickens;  sometimes it is because of superstition. Further, eggs do not keep well  because most are fertile and, exposed to constant tropical heat, undergo  rapid embryo development.  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Crop Damage</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">It is often necessary to confine the birds to protect young crops or  vegetable gardens.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">RESEARCH AND CONSERVATION NEEDS</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">Unlike the situation with small cattle, goats, sheep, and pigs, there are  few named and recognized breeds of Third World chickens. Yet, nearly  every country has at least one kind of village chicken. These have  survived there for centuries and are highly adapted to local conditions.  In village projects, these unnamed chickens deserve priority attention  before other types are sought from elsewhere.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Generally speaking, improving the production of scavenging poultry  does not require sophisticated research. Instead, simple precautions are  sufficient. These are discussed below.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Disease Control</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">At a national or regional level, the initial approach to increasing  chicken production in tropical areas should be disease control. There are  several outstanding instances of success in this endeavor. For example,  the spectacular rise of poultry production in Singapore (from 250,000  birds in 1949 to 20 million in 1957) followed the control of Ranikhet  disease. Village flock-health programs, carried out regularly by visiting  veterinarians ("barefoot veterinarians"), might be the answer to some of  the routine health problems. Today, a prime target should be Newcastle  disease, for which there are good chances for success (see page 76).</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Management</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">The first step in chicken production at the farm level is improved  management. With more care and attention, mortality can be greatly  reduced. Because incubating and brooding hens must spend the night on  the ground, they are extremely vulnerable. Even modest predator  controls can be highly beneficial. Building crude and inexpensive nest  boxes and constructing a simple holding area around them can  substantially raise production by ensuring that more chicks survive.  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">THE CHICKEN'S WILD ANCESTOR</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">Although little known to most people, the red junglefowl has  contributed more to every nation than any other wild bird. It is  the ancestor of the chicken.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Given its descendants importance worldwide, the neglect of  this bird is baffling. If the cow's wild ancestor, the aurochs, had  not become extinct in the 1600s, it would now be worth millions  of dollars as the ultimate source of cattle genetic diversity. Yet  the world's chicken industry remains virtually unaware of the  origin of its source of livelihood.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Like the aurochs, the red junglefowl has a wealth of wild  genes, and it deserves more recognition and protection. For one  thing the modern chicken - selectively bred in the temperate  zone - is highly susceptible to heat and humidity; the junglefowl,  on the other hand, is not. It inhabits the warmest and most humid  parts of Asia: Sri Lanka, India, Burma, Thailand, and most of  Southeast Asia. It may also be resistant to various chicken  diseases and pests.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">This is not a rare species. Throughout the wide crescent  stretching from Pakistan to Indonesia, junglefowls are still seen  in the wild, especially in forest clearings and lowland scrub.  Although they are a prized bag for hunters, they survive by fast  running and agile flying. They are sometimes sold in village  markets, but can easily be mistaken for domesticated chickens,  which in this region are often very similar. The wild junglefowl,  however, has feathered legs, a down-curving tail, and an overall  scragginess.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Junglefowls should be under intensive study. They are easy to  rear in captivity and do well in pens, even small ones, as long as  they are sheltered from rain and wind. One drawback is their  craze for scratching unless provided plenty of space they  promptly tear up all grass and dirt. Another is that junglecocks  are violent fighters and must be kept apart. (Cockfighting is  probably a major reason why they were initially selected, and  thus their aggressiveness is perhaps the reason we have the  chicken today.)</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">These highly adaptable creatures live in a variety of habitats,  from sea level to 2,000 m. Most, however, are found in and  around damp forests, secondary growth, dry scrub, bamboo  groves, and small woods near farms and villages. They are  amazingly clever at evading capture and thrive wherever there is  some cover.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Other junglefowl species might also provide useful poultry.  They, too, can be raised in captivity with comparative ease, as  long as the cocks are kept apart. Perhaps they might be tamed with imprinting and could prove useful as domestic fowl,  especially in marginal habitats. They are everywhere considered  culinary luxuries and their meat commands premium prices.  Moreover, several have colorful feathers, giving them additional  commercial value. These other species are:</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">- La Fayette's Junglefowl (Gallus lafayettei). Avery attractive  bird of Sri Lanka, it is little known in captivity, and only in the  United States are there any number in captivity.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">- Gray or Sonnerat's Junglefowl (Gallus sonnerati). A native  of India, this colorful bird produces feathers that are used in  tying the most prized trout and salmon flies. Demand is so great  that certain populations have declined, and since 1968 India has  banned all export of birds or feathers. Nonetheless, there are  several hundred in captivity in various countries.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">- Green Junglefowl (Gallus varius). This is yet another striking  bird. The cock has metallic, greenish-black feathering set off by  a comb that merges from brilliant green at the base to bright  purple and red at the top. Native to Java, Bali, and the  neighboring Indonesian islands as far out as Timor, it is found  particularly near rice paddies and rocky coasts. This species, too,  can be raised without great difficulty, and there are at least 90 in  captivity in various parts of the world.  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Nutrition</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">Improving poultry nutrition is also of prime importance. There are no quantitative data on the quality of a scavenging chicken's diet. Surveys are badly needed so that appropriate, low-cost supplements can be devised.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Chances are that the diet for chicks of scavenging poultry is almost always deficient in available energy. Minimal supplementation in the form of cereals or energy-rich by-products can greatly improve both egg and meat production. However, caution must always be exercised and the supplements given only to chicks. Overfed adults will give up scavenging and stay around the owner's house, without really producing much more meat or eggs.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Genetic Improvement</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">Although it seems attractive to replace the scrawny village chicken with bigger, faster-growing imported breeds, it is a process fraught with difficulty. Exotic breeds lack the ability to tolerate the rigors of mismanagement and environmental stress. Many cannot avoid predators, as a result either of being overweight or of having a poor conformation for flight. The local birds, however, probably have a genetic potential that is much higher than can be expressed in the constraining environment. Thus, the environmental constraints should be tackled first.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">However, the village birds may have a feed-conversion efficiency that is far less than ideal because they are adapted to a scavenging existence. Modern breeds imported into Ghana, for instance, showed a feed-conversion efficiency of less that 3.5:1 (weight of food eaten: growth and eggs), but the local birds had efficiencies of 11:1.4 </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Conservation</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">The need for preserving genetic variability is greater in poultry, especially in chickens, than in any other form of domestic animal. North America, for instance, which years ago had 50 or more common breeds, now relies on only 2 for meat production, and the others have been largely lost. Conservation of germplasm has become a matter of serious concern, and the saving of rare breeds in domestic fowl should not be delayed. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">THE SOUTH AMERICAN CHICKEN</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">Early European explorers of South America were surprised to discover an abundance of unusual chickens that laid colored eggs and had feathers resembling earrings on the side of the head. While the origin of this bird - commonly called the araucanian chicken and classified as Gallus inauris - is debatable, scientists generally agree that it is pre-Columbian. There is archeological evidence that this bird is native to the Americas. It is reported to have occurred in Chile, Ecuador, Bolivia, Costa Rica, Peru, and Easter Island. It still occurs in the wild in southern Chile and on Easter Island.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The araucanian has been called the "Easter-egg chicken" because it lays light green, light blue, and olive colored eggs. It lays well and has a delicious meat. In areas such as southern Chile the eggs are preferred over those of normal chickens because of their flavor and dark yellow yolk. This unusual bird has a high degree of variability; however, specimens of similar genetic background have been grouped to create "breeds" such as the White Araucanian, Black Araucanian, and Barred Araucanian. These are homozygotes and breed true.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The araucanian has been the subject of much public interest,. clubs dedicated to its preservation have been formed in the United States, Great Britain, and Chile. Its possible exploitation as a backyard microlivestock deserves serious consideration. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<B><P>&lt;&lt;TOC3&gt;&gt; 6 Ducks</P>
+</B><P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&lt;&lt;I&gt;&gt; g009a.png FIGURE</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">Domestic ducks (Anas platyrhynchos)1 are well known, but still have much unrealized promise for subsistence-level production. Although a major resource of Asia, where there is approximately one duck per 20 inhabitants, they are not so intensively used elsewhere. On a worldwide basis, for instance, they are of minor importance compared with chickens.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">This is unfortunate because ducks are easy to keep, adapt readily to a wide range of conditions (including small-farm culture), and require little investment. They are also easily managed under village conditions, particularly if a waterway is nearby, and appear to be more resistant to diseases and more adept at foraging than chickens.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Moreover, the products from ducks are in constant demand. Some breeds yield more eggs than the domestic chicken. And duck meat always sells at premium. A few recently created breeds (notably some in Taiwan) have much lower levels of fat than the traditional farm duck. This development could open up vast new markets for duck meat, especially in wealthy countries, where consumers are both concerned over fat in their diet and eager for alternatives to chicken.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Ducks are also efficient at converting waste resources - insects, weeds, aquatic plants, and fallen seeds, for instance - into meat and eggs. Indeed, they are among the most efficient of all food producers. Raised in confinement, ducks can convert 2.4-2.6 kg of concentrated feed into I kg of weight gain. The only domestic animal that has better feed conversion is the broiler chicken.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Raised as village birds and allowed to forage for themselves, ducks become less productive but become even more cost effective because much of the food they scavenge has no monetary value. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">AREA OF POTENTIAL USE</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">Worldwide.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">APPEARANCE AND SIZE</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">Several distinctive types have been developed in various regions. Most have lost the ability to fly any distance, but they retain a characteristic boatlike posture and a labored, waddling walk. The Indian Runner, however, has an almost erect stance that permits it to walk and run with apparent ease.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Domestic ducks range in body size from the diminutive Call, weighing less than I kg, to the largest meat strains (Pekin, Rouen, and Aylesbury, for example) weighing as much as 4.5 kg. For intensive conditions, the Pekin is the most popular meat breed around the world. In confinement it grows rapidly - weighing 2.5-3 kg at a market age of 78 weeks. In addition, it is hardy, does not fly, lays well, and produces good quality (but somewhat fatty) meat.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The Khaki Campbell breed is an outstanding egg producer, some individuals laying more than 300 eggs per bird per year.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The Taiwan Tsaiya (layer duck) is also a particularly efficient breed. It weighs 1.2 kg at maturity, starts laying at 120-140 days, and can produce 260-290 eggs a year. Its small body size, large egg weight, and phenomenal egg production make Brown Tsaiya the main breed for egg consumption in Taiwan. More than 2.5 million Brown Tsaiya ducks are raised annually for egg production.2</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">DISTRIBUTION</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">The domestic duck is distributed throughout the world; however, its greatest economic importance is in Southeast Asia, particularly in the wetland-rice areas. For example, about 28 percent of Taiwan's poultry are- ducks. In parts of Asia, some domestic flocks have as many as 20,000 birds. One farm near Kuala Lumpur, Malaysia, rears 40,000 ducks.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">STATUS</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">Although ducks are abundant, some Western breeds are becoming rare. Indigenous types are little known outside their home countries and have received little study, so their status is uncertain.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">HABITAT AND ENVIRONMENT</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">These adaptable creatures thrive in hot, humid climates. However, during torrid weather they must have access to shade, drinking water, and bathing water.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Ducks are well adapted to rivers, canals, lakes, ponds, marshes, and other aquatic locations. Moreover, they can be raised successfully in estuarine areas. Most ocean bays and inlets teem with plant and animal life that ducks relish, but (unlike wild sea ducks) domestic breeds have a low physiological tolerance for salt and must be supplied with fresh drinking water. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">BIOLOGY</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">Ducks search for food underwater, sieve organic matter from mud, root out morsels underground, and sometimes catch insects in the air. Their natural diet is normally about 90 percent vegetable matter (seeds, berries, fruits, nuts, bulbs, roots, succulent leaves, and grasses) and 10 percent animal matter (insects, snails, slugs, leeches, worms, eels, crustacea, and an occasional small fish or tadpole). They have little ability to utilize dietary fiber. Although they eat considerable quantities of tender grass, they are not true grazers (like geese), and don't eat coarse grasses and weeds at all. Sand and gravel is swallowed to serve as "grindstones" in the gizzard.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">When protected from accidents and predation, ducks live a surprisingly long time. It is not unusual for one to continue reproducing for up to 8 years, and there are reports of exceptional birds living more than 20 years.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Despite large differences in size, color, and appearance, all domestic breeds interbreed freely. Eggs normally take 28 days to incubate, brooding and rearing is performed solely by the female.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Depending on breed, a female may reach sexual maturity at about 20 weeks of age. Most begin laying at 20-26 weeks, but the best egg- laying varieties come into production at 16-18 weeks and lay profitably for 2 years.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">BEHAVIOR</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">It is generally well known that ducks are shy, nervous, and seldom aggressive towards each other or humans. Skilled and enthusiastic swimmers from the day they hatch, they spend many hours each day bathing and frolicking in any available water. However, most breeds can be raised successfully without swimming water.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Although wild ducks normally pair off, domestic drakes will mate indiscriminately with any females in a flock. In intensively raised flocks, I male to 6 females, and in village flocks, 1 male for up to 25 females, results in good fertility.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Most domestic ducks, particularly the egg-laying strains, have little instinct to brood. If not confined, they will lay eggs wherever they happen to be - occasionally even while swimming. To facilitate egg collection, some keepers confine ducks until noon. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">&lt;&lt;I&gt;&gt; p96a.png Figure</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">USES</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">As a meat source, ducks have major advantages. Their growth rate is phenomenal during the first few weeks. (Acceptable market weights can be attained under intensive management with birds as young as 6-7 weeks of age.) Yet, even in older birds, the meat remains tender and palatable.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Eggs from many breeds are typically 20-35 percent larger than chicken eggs, weighing on average about 73 g. They are nutritious, have more fat and protein, and contain less water than hen's eggs. They are often used in cooking and make excellent custards and ice cream. Eggs incubated until just before the embryos form feathers produce a delicacy known as balut in the Philippines. Salted eggs are popular in China and Southeast Asia.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Feathers and down (an insulating undercoat of fine, fluffy feathers) are valuable by-products. Down is particularly sought as a filler for pillows, comforters, and winter clothing.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Ducks have a special fondness for mosquito and beetle larvae, grasshoppers, snails, slugs, and crustaceans, and therefore are effective pest control agents. China, in particular, uses ducks to reduce pests in rice fields.3 Its farmers also keep ducks to clear fields of scattered grain, to clear rice paddy banks of burrowing crabs, and to clear aquatic weeds and algae out of small lakes, ponds, and canals. This not only improves the conditions for aquaculture and agriculture, it also fattens the ducks.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">HUSBANDRY</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">In Southeast Asia, droving is a traditional form of duck husbandry, much as it was in medieval Europe. The birds are herded along slowly, foraging in fields or riverbanks as they march to market. The journey might cover hundreds of kilometers and take as long as six months.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">This process, however, is generally declining, and most ducks are raised under farm conditions where they scavenge for much of their feed. Throughout Southeast Asia, ducks have been integrated with aquaculture.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Ducks can be raised on almost any kitchen wastes: vegetable trimmings, table scraps, garden leftovers, canning refuse, stale produce, and stale (but not moldy) baked goods. However, for top yields and quickest growth, protein-rich feeds are the key. Commercial duck farms rely on such things as fish scraps, grains, soybean meal, or coconut cake. Agricultural wastes such as sago chips, palm-kernel cake, and palm-oil sludge are being used in Malaysia.4</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Ducks have a very high requirement for niacin (a B vitamin). If chicken rations are used, a plentiful supply of fresh greens must be provided to avoid "cowboy legs," a symptom of niacin deficiency.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">ADVANTAGES</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">Of all domestic animals, ducks are among the most versatile and useful and have multiple advantages, including:</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">- Withstanding poor conditions;</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">- Producing food efficiently;</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">- Utilizing foodstuffs that normally go unharvested;</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">- Helping to control pests; and</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">- Helping to fertilize the soil.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">Also, they are readily herded (for instance, by children).</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Excellent foragers, they usually can find all their own food, getting by on only a minimum of supplements, if any. Raising them requires little work, and they provide farmers with food or an income from the sale of eggs, meat, and down.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Ducks can grow faster than broiler chickens if they have adequate nutrients. Like guinea fowl and geese, they are relatively resistant to disease. They also have a good tolerance to cold and, in most climates, don't need artificial heat.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">DOMESTICATING NEW DUCKS</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">Many species of ducks adapt readily to captivity; it is surprising, therefore, that only the mallard and the muscovy have been domesticated so far. Several wild tropical species seem especially worth exploring for possible future use in Third World farms, Because of the year-round tropical warmth, their instinct to migrate is either absent or unpronounced, and the heavy layer of fat (a feature of temperate-climate ducks that consumers in many countries consider a drawback) is lacking. Moreover, because of uniform daylength, they are ready to breed at any time of the year. Candidates for domestication as tropical ducks include:</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">- Whistling ducks (Dendrocygna species). These large, colorful, gooselike birds are noted for their beautiful, cheerful whistle.* They are long-necked perching ducks that are found throughout the tropics. By and large, they are gregarious, sedentary, vegetarian, and less arboreal than the muscovy - all positive traits for a poultry species.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The black-bellied whistling duck (D. auturunalis) seems especially promising. It is common throughout tropical America (southwestern United States to northwestern Argentina) and is sometimes kept in semicaptivity. Occasionally, in the highlands of Guatemala, for instance, Indians sell young ones they have reared as pets. When hand reared, the birds can become very tame. * * They eat grain and other vegetation, require no swimming water, and will voluntarily use nest boxes. In the wild, they "dump" large numbers of eggs so that even if substantial numbers were removed for artificial hatching, the wild populations should not be affected.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">- Greater wood ducks (Cairina species). The muscovy (C. moschata) was domesticated by South American Indians long before Europeans arrived (see page 124). Its counterparts in the forests of Southeast Asia and tropical Africa are, however, untried as domesticates. The white-winged wood duck (C. scutulata) is found from eastern India to Java. Hartlaub's duck (C. hartlaubi) occurs in forests and wooded savannas from Sierra Leone to Zaire. Both are rare in captivity, but might well prove to be future tropical resources. Both are strikingly similar to muscovies in size and habits, being large, phlegmatic, sedentary, and omnivorous. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">LIMITATIONS</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">Predators are the most important cause of losses in farm flocks. Ducks are almost incapable of defending themselves, and losses from dogs and poachers can be high. Locking them in at night both protects the birds and prevents eggs from being wastefully laid outside.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Ducks do suffer from some diseases, mainly those traceable to mismanagement such as poor diet, stagnant drinking water, moldy feed or bedding, or overcrowded and filthy conditions. Of all poultry, they are the most sensitive to aflatoxin, which usually comes from eating moldy feed. They are also susceptible to cholera (pasteurellosis) and botulism, either of which may wipe out entire flocks. Duck virus enteritis (duck plague) and duck virus hepatitis also can cause severe losses.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">If not carefully managed, ducks can become pests to some crops, especially cereals.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">As noted, ducks tend to be extremely poor mothers and can be helped by using broody chicken hens or female muscovies as surrogate mothers.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Major limitations to large-scale, intensive production are mud, smell, and noise.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Defeathering ducks is much more difficult than defeathering chickens because of an abundance of small pinfeathers and down feathers.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">RESEARCH AND CONSERVATION NEEDS</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">These birds already function so well that no fundamental research needs to be done. Nonetheless, there are a number of topics that could improve their production.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">For example, different types of low-cost systems need to be explored and developed. These must be low-input systems since cash is a limiting factor for most subsistence farmers. One possibility is the integration of duck and fish farming.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">A survey of all breeds is needed to determine their status and likelihood of extinction.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">One need in countries that already have ducks is to encourage the consumption of duck meat. Indonesia, for instance, has 25 million egg-producing ducks, but little duck meat is consumed.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Research on economically significant diseases is needed. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<B><P>&lt;&lt;TOC3&gt;&gt; 7 Geese</P>
+</B><P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&lt;&lt;I&gt;&gt; g010a.png Brown Chinese Geese</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Although geese (Anser spp.) were one of the first domesticated animals, they have yet to receive the level of commercial or industrial exploitation of chickens or even ducks. Thus, their global potential is far greater than is generally recognized today.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Domestic geese are easily managed and well suited to small-farm production; they are among the fastest growing avian species commonly raised for meat, and they have immediate application in many developing countries.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">These birds are especially appropriate for providing farmers a supplemental income. With little extra work they supply nutritious meat, huge eggs, and rich fat for cooking, as well as soft down and feathers for bedding and clothing. Moreover, their strident voices sound the alarm when strangers or predators approach. They are especially well suited to aquatic areas and marshy lands and are completely at home in warm shallow waterways. Nevertheless, they can thrive away from water. In fact, wherever pasture is available geese readily adapt to captivity.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Geese are grazers, and can be raised almost exclusively on pasture. They are excellent foragers, and on succulent grass can find most or all of their own food. With their powerful bills they pull up grasses and underwater plants and probe soil and water for roots, bulbs, and aquatic animals. Their long necks make them adept at gleaning weeds from hard-to-reach places - such as fence rows, ditches, and swampy areas that baffle larger livestock. They will also feast on vegetable trimmings, garden and table leftovers, canning refuse, and stale baked goods. Like other poultry, they pick up shattered grains of rice, wheat, barley, and other crops, which can reduce the bothersome problem of weeds volunteering in subsequent years.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Geese are available worldwide. In most climates, they require little or no housing. Given reasonable care and protection from predators, mortality can be extremely low. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">AREA OF POTENTIAL USE</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">Worldwide.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">APPEARANCE AND SIZE</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">Domestic geese come in an assortment of colors, sizes, and shapes. There are two main types, however. Descendants of the wild greylag goose (Anser anser) make up the domestic breeds common in North America and Europe, including the Embden, Toulouse, Pilgrim, American Buff, Pomeranian, Sebastopol, and Tufted Roman breeds. These are generally best suited to temperate climates. On the other hand, descendants of the wild "swan goose" (Anser cygnoides) make up the geese of Asia, including the Chinese and "African" types. These breeds seem better suited to hot climates.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">In addition to these, many European and Asian countries have their own local breeds and types, and there are even several wild species that show some potential for captive production.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">With their long legs and webbed toes, geese are equally at home walking or swimming. Avid walkers, they march long distances to find forage, but return home at dusk. Accomplished and graceful swimmers, geese are able to take to water soon after they hatch. Despite their large size, some domestic breeds - especially the leaner ones - have retained the ability to fly.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">DISTRIBUTION</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">Geese are found worldwide, but goose farming is nationally important only in Asia and Central Europe.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">STATUS</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">Domestic geese are not threatened, although much local variation among the breeds is being lost.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">HABITAT AND ENVIRONMENT</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">Most geese adapt well to hot climates - as long as some shade is available. Their waterproof feathers help them adapt well to high rainfall regions. They also tolerate extreme cold. (For instance, in Canada, geese are wintered outdoors in subfreezing temperatures, with merely 'e simple shelter from wind.)</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">For tropical developing countries, the Chinese type, which is widely kept in Southeast Asia, is especially promising. Smaller than most geese (although ganders can weigh over 5 kg), they are the best layers, the most active foragers (making them economical and useful as weeders), the most alert and "talkative," and they produce the leanest meat. Some European breeds, such as Embden and Toulouse, have also been used in the tropics with notable success. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">DOMESTICATING GEESE</P>
+<P ALIGN="JUSTIFY">(Temperate Zones)</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">Today's domestic geese are descended from two species: the greylag (Anser anser) and the swan goose (Anser cygnoides). These were domesticated in Europe and China, respectively. Their domestication occurred in ancient times, long before people knew about genetics, microorganisms, veterinary science, or behavior modifications such as imprinting. Today, armed with such knowledge, more geese may be amenable to domestication. Most of the 15 other wild species adapt to captivity. Compared to most birds, geese spend much time walking and swimming and are less inconvenienced by pinioning (removing the tip of the wing). Thus, they can be kept outdoors rather than in cages.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Both of the ancestors of today's domestic geese are native to the northern temperate zone. Two more wild species that might make useful domesticates are:</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">- Canada goose (Branta canadensis). North America. People feeding these birds in city parks and wildlife refuges are causing many local flocks to develop. These birds no longer migrate. They are increasing in numbers each year and are well on the way to de facto domestication.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">- American swan goose (Coscoroba coscoroba). Southern South America. Although most closely allied to swans in shape and physiology, this bird resembles a muscovy (see page 124) in size and behavior. Its calm disposition, as well as its attractive red feet and bill that accent its white plumage, have made it much sought as an ornament for parks.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">BIOLOGY</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">In its diet, the goose utilizes large quantities of tender forage. It can break down plant-cell walls and digest the contents. Although it has no crop for storing food, there is an enlargement at the end of the gullet that serves as a temporary storage organ. Sand and small gravel are swallowed to aid the gizzard in grinding hard seeds and fibrous grasses. Research has shown that geese can digest 15-20 percent of the fiber in their diet, which is 3-4 times the amount that other poultry species can digest.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The natural diet consists of grasses, seeds, roots, bulbs, berries, and fruits, normally supplemented with a little animal matter (mainly insects and snails) picked up incidentally. Most feeding takes place on land. They characteristically feed for prolonged periods, even at night.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Females may lay for 10 years or more. It is generally believed that reproduction is best in the second year and that it remains good until the fifth year. Geese outlive other types of poultry; life spans of 1520 years are common.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The eggs incubate in 27-31 days. The incubation time is more variable than in most poultry species, perhaps because geese have not been subjected to the selection pressure that is imposed by artificial incubators.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">BEHAVIOR</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">One of the most intelligent birds, the goose has a good memory and does not quickly forget people, animals, or situations that have frightened it. While personalities and habits vary among individual specimens, there are common behavioral patterns, such as the pecking order, that allow individuals to live peaceably together.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Unless conditions are crowded or there are too many males, geese normally live harmoniously both with themselves and with other creatures. The bond between male and female is strong. Changing mates is difficult, although most geese will eventually accept a new mate after a period of "mourning."</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Geese nest on the ground and prefer the water's edge, but they adapt readily to man-made nesting boxes. The gander usually stands guard while the goose incubates the eggs. He then assists in rearing the goslings. Most geese become irritated if intruders approach their nest or goslings, and will even attack people and large dogs. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">USES</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">As previously noted, these birds provide meat, eggs, fat, and down. The meat is lean, flavorful, and of outstanding quality. The fat accumulates between the skin and the flesh and can be rendered into a long-lasting oil. The eggs are large and taste much like chicken eggs. The "down" (the small, fluffy feathers that lie next to the body of adult birds) is the finest natural insulating material for clothing and bedding, and can fetch a premium price. Worldwide markets exist for both down and other goose feathers. In France, in particular, some geese are raised for their livers (foie gras).</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Geese can control many types of aquatic weeds in shallow water as well as grass and some types of palatable broad-leaf weeds on the banks of lakes, ponds, and canals. They can also be used as ''lawn mowers" and "weeders" among cotton, fruit trees, and other crops (see sidebar).</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Elongated necks not only allow geese to reach many different foods, they also help them keep a watchful eye on the surroundings. With their exceptional eyesight they can see great distances, and the position of the eyes gives them a wide field of vision. Geese are among the most alert of all animals, and strangers cannot calm them into silence. In the high Andes, in Southeast Asia, and in many other locations, they replace guard dogs. In Europe, they are used to guard whiskey warehouses and sensitive military installations (see page 111).</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">HUSBANDRY</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">Methods of caring for adult geese vary according to climate, breed, and people's experiences and needs. Overall, however, the birds cause little trouble and require little expense. They range freely without restriction, feeding themselves and returning home of their own accord. They have strong flocking instincts and can readily be herded from one area to another.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Like all young poultry, goslings are fragile. The highest mortality is caused by predators. Until the goslings are 6-10 weeks old, it is prudent to confine the parents and their young at night in a secure pen or building.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Geese are the only domestic fowl that can live and reproduce on a diet of grass. They cannot remain healthy on coarse dry fodder, but when grass is succulent they need little else other than drinking water. Many legumes also make excellent goose forage.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">In the tropics, eggs can be laid year-round. The production seldom exceeds 40 eggs per year, although with feed supplement and simple management, the Chinese breed may yield more than 100 eggs. Geese go broody quickly. To break up broodiness, the goose can be confined for 4 6 days away from, but in sight of, the ganders.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Goslings grow rapidly and can reach market size as early as 10-12 weeks; most geese, however, are marketed at 20-30 weeks of age, when they may weigh from 5 to 7 kg, depending on type and breed. Some young birds (also called green or junior geese), force-fed for rapid growth, are marketed at 4-6 kg when they are 8-10 weeks old.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">If fed a good diet to maximize growth and if slaughtered at, say, 10 weeks, the Embden, Chinese, or African will have a carcass low in fat. However, the carcass normally has much more fat than other poultry.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Geese must have a constant supply of reasonably clean drinking water during daylight hours. Although swimming water is not necessary, it promotes cleaner and healthier birds because they find it easier to care for their plumage.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">DOMESTICATING GEESE</P>
+<P ALIGN="JUSTIFY">(Tropics)</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">Geese of the tropics have seldom if ever been considered for domestication, but they might provide poultry of considerable value. Presumably they are more heat tolerant and lack the layers of subcutaneous fat (which the ancestors of today's geese needed for warmth in the Arctic). They might thus produce lean birds that would fetch premium prices because excessive fat is the major drawback of today's commercial geese. Examples of tropical species that might be domesticable are:</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">- Egyptian goose (AIopochen aegyptiacus). Found throughout the African tropics, this bird is already partly domesticated. However, it is bad tempered and quarrelsome and, so far, this has limited its utility. It has therefore been kept only under semidomestication, without intensive breeding.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">- Nene (Branta sandvicensis). A native of the Hawaiian Islands, this is one of the most endangered species on earth. So few specimens are in existence that farming enterprises cannot now be envisaged. Yet, should this bird prove amenable and suitable, the possibility of an economic future could boost efforts to build up its now meager populations.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">- Bar-headed goose (Anser indicus). India and Central Asia. These smallish geese are handsome, dainty, and have a musical horn-like call. They have distinct black bars across the nape, which gives them their popular name. Hand-reared specimens breed well in captivity. Despite heavy hunting they are still abundant.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">- Northern spur-winged goose (Plectropterus gambensis gambensis). Tropical Africa (Senegal to Zimbabwe). This large bird is a ground nester, but it has long bony spurs on the wings that enable it to easily protect its eggs and young from predators.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">- Semipalmated (magpie) goose (Anseranas semipalmata). Australia and New Guinea. One of the most aberrant and primitive of all waterfowl, this long-legged sturdy-billed bird has only partially webbed feet. It perches high in trees and has a loud ungooselike whistling call. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">THE WADDLING WORK FORCE</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">Because geese relish grasses and shun most broad-leafed plants, some enterprising U.S. farmers in the 1950s began using them to rid cotton fields of grassy weeds, which are difficult to kill with herbicides. The geese were put into the fields as soon as the crop came up. A brace of birds kept an acre of cotton weeded; a gaggle of 12 would gobble as many weeds as a hard-working man could clear with a hoe.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">This method of clearing fields was so effective that by 1960 more than 175,000 geese honked their way across the carefully tended farmland, mainly in the Southwest. Seven days a week, rain or shine, the feathered field hands slaved uncomplainingly from daybreak to dusk, even putting in overtime on moonlit nights. Many toiled so diligently that they worked themselves out of a job.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The geese cleared the fields more cheaply than hoe hands. They left the crop untouched and ate only the succulent young weeds. They did not damage crop roots (as hoes or tractors can), and they were safe and selective, unlike many herbicides. On top of all that they spread fertilizer for the farmer, and ultimately provided him meat for the market.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Eventually, farmers found that geese could be used to weed nearly all broad-leafed crops: asparagus, potatoes, berry fruits, tobacco, mint, grapes, beets, beans, hops, onions, and strawberries, for example. Geese were used in vineyards and fruit orchards to eat both weeds and the fallen fruits that could otherwise harbor damaging insects. They were employed in fields producing trees for the forest industry and flowers for florists shops. Some growers turned goslings loose in cornfields to consume the "suckers" (cone, after all, is a grass) as well as the grain left on the ground. This eliminated the problem of corn as a weed when different crops were later planted in those fields.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">In the 1970s when cotton acreage dropped and herbicides selective for the troublesome grasses were developed, the use of geese declined. But today, some organic farmers are returning to the practice. From February to June in the Pacific Northwest, fields are resounding once more to the old-fashioned racket of White Chinese geese. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">ADVANTAGES</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">Mature geese are independent creatures. When kept in small flocks and allowed to roam the farmyard or field, they require less attention than any other domestic bird with the possible exception of guinea fowl. In areas where grass is green for much of the year, they can be raised on less grain or concentrated feed than any other domestic fowl.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Durability is one of their most attractive features. Along with ducks, geese seem to be the most resistant of all poultry to disease, parasites, and cold or wet weather. They also do well in hot climates as long as drinking water and deep shade are available.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Growth is not only rapid, it is also efficient. If managed properly, goslings can produce I kg of body weight for every 2.25-3.5 kg of concentrated feed consumed.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Geese are not usually thought of as prolific layers. However, as noted, some strains of the Chinese breed will yield well over 100 eggs per goose per year. At 140-170 g per egg, that compares favorably with the output of laying chickens. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&lt;&lt;I&gt;&gt; p112a.png figure</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">LIMITATIONS</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">These birds are messy and their loud trumpeting is often irritating. However, unless they have been teased or mistreated or if they are nesting or brooding young, they are not aggressive. But kilo for kilo, they are stronger than most animals, and a harassed or angry adult can express its displeasure effectively with powerful bill and pounding wings.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Excessive concentrations of geese on ponds or along creeks encourages unsanitary conditions, muddies water, hastens bank erosion, and destroys plant life. Where sanitation is poor, salmonellosis can devastate geese and be transmitted, via meat and eggs, to humans. Coccidiosis and gizzard worm are other infections.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Defeathering geese is more difficult than plucking chickens because there are two coats (feathers and down) to remove.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">In some situations, geese may need a diet supplement (such as grain) if they are grazing vegetation exclusively. A balance must be struck: too much supplement and they will quit foraging and become too fat; too little and they grow slowly and may suffer malnutrition.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Geese are not fully mature until two years of age. Their overall reproductive rate, therefore, is lower than that of other poultry. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">RESEARCH AND CONSERVATION NEEDS</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">Poultry researchers worldwide should begin studies to clarify the role that geese could play in helping to feed Third World nations. Studies might include:</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">- Management practices for tropical areas;</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">- Breeding and management for increased egg production;</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">- Incubation techniques;</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">- Nutrition supplementation (for example, vitamins, minerals, energy, specific amino acids) needed by grazing geese;</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">- Physiology of digestion and reproduction;</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">- Clarifying the inheritance of various traits;</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">- Genetic selection for specific meat, eggs, growth factors, or disease resistance;</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">- Comparative studies of the relative efficiency (especially of feed utilization) of the various types and breeds for specific climates in underdeveloped countries;</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">- Weeding tropical crops with geese; and</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">- Studying diseases and cross-infection with other birds. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<B><P>&lt;&lt;TOC3&gt;&gt; 8 Guinea Fowl</P>
+</B><P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&lt;&lt;I&gt;&gt; g011a.png FIGURE</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">For Third World villages, the guinea fowl (Numida meleagris) could become much more valuable than it is today. The bird thrives under semi-intensive conditions, forages well, and requires little attention. It retains many of its wild ancestor's survival characteristics: it grows, reproduces, and yields well in both cool and hot conditions; it is relatively disease free; it requires little water or attention; it is almost as easily raised as chickens and turkeys; and it is a most useful all-round farm bird.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The guinea fowl's potential to increase meat production among hungry countries should be given greater recognition. The birds are widely known in Africa and occur in a few areas of Asia, but they show promise for use throughout all of Asia and Latin America and for increased use in Africa itself. Strains newly created for egg and meat production in Europe - notably in France - show excellent characteristics for industrial-scale production. Also, many semidomestic types in Africa deserve increased scientific assessment as scavenger birds.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Meat from domestic guinea fowl is dark and delicate, the flavor resembling that of game birds. It is a special delicacy, served in some of the world's finest restaurants. Several European countries eat vast amounts. Annual consumption in France, for example, is about 0.8 kg per capita.'</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Guinea fowl also produce substantial numbers of eggs. In Africa, these are often sold hard-boiled in local markets. In the Soviet Union, they are produced in large commercial operations. In France, guinea fowl strains have been developed that not only grow quickly but lay as many as 190 eggs a year.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Outside Europe, virtually all guinea fowl are raised as free-ranging birds. These find most of their feed by scratching around villages and farmyards. Their cost of production is small, and they yield food for subsistence farmers. In Europe, on the other hand, most are raised in confinement, with artificial insemination, artificial lighting, and special feeding. In the main, this is to produce meat for luxury markets.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Guinea fowl production is beginning to increase all over the world. During the last 20 years, for example, many of Europe's chicken farmers and breeders, wishing to diversify, have switched to this bird. The United States is now studying ways to establish industrial production, and both Japan and Australia are increasing their flocks. Nonetheless, there is still a vast untapped future for this bird.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">AREA OF POTENTIAL USE</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">Worldwide. This species is robust and resilient and adapts to many climates.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">APPEARANCE AND SIZE</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">Guinea fowl are somewhat larger than average scavenger-type chickens: adults weigh up to 2.5 kilograms. They have dark-grey feathers with small white spots. Their heads are bare with a bony ridge (helmet) on top, which makes them look something like vultures. The short tail feathers usually slope downwards.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The chicks, known as "keels," resemble young quail. They are brown striped with red beaks and legs. The sexes are indistinguishable until eight weeks of age. After that, the males' larger helmets and wattles and the cries of the different sexes can be identified. Both sexes give a one-syllable shriek, but females also have a two-syllable call.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Like the chicken, the guinea fowl is a gallinaceous species and possesses the characteristic sternum with posterior notches and a raised "thumb."</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Among domestic types are pearl, white, royal purple, and lavender. Pearl is the most common, and is probably the type first developed from the wild West African birds. Its handsome feathers are often used for ornamental purposes. The white is entirely white from the time of hatching and has a lighter skin. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&lt;&lt;I&gt;&gt; p117a.png figure</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">DISTRIBUTION</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">Europe dominates industrial production. France, Italy, the Soviet Union, and Hungary all raise millions of guinea fowl under intensive conditions, just as they raise chickens. Elsewhere, guinea fowl have become established as a semidomesticated species on small family farms. Native flocks are found about villages and homes in parts of East and West Africa, and free-ranging flocks can be seen in many parts of India, notably Punjab, Uttar Pradesh, Assam, and Madhya Pradesh. During the slavery era, they were introduced from Africa to the Americas to be used for food. In Jamaica, Central America, and Malaysia, the birds have reverted to the wild state and are treated as game.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">STATUS</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">Guinea fowl are abundant; in most places even wild populations are not threatened.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">HABITAT AND ENVIRONMENT</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">Guinea fowl are native to the grasslands and woodlands of most of Africa south of the Sahara where they occupy all habitats except dense forests and treeless deserts. Being native also to temperate South Africa, they appear to have an inherent adaptability to both heat and cold. However, in cool climates, regardless of daylength, they will not begin egg production until temperatures exceed 15&Yacute;C. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">BIOLOGY</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">Guinea fowl accept many foods: grains, leaves, ant eggs (for which they will tear anthills open), and even carrion.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Normally, they lay their first egg at about 18 weeks of age. Unlike many wild birds, which produce a single clutch a year, guinea hens lay continuously until adverse weather sets in.2 Free-range "domestic" guinea hens lay up to 60 eggs a season. And well-managed birds under intensive management lay close to 200. The eggs weigh approximately 40 g. Shells are stronger than those of chickens and are usually brown, but can be white or tinted.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The guinea hen goes broody after laying, which can be overcome by removing most of the eggs. A clutch of 15-20 is common. The incubation period is 27 days.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">BEHAVIOR</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">These birds never become "tame," but neither do they leave the premises. Although they stray farther than chickens do, they always return. They like to hide their eggs in a bushy corner, often in hollows scratched in the ground. They can fly, although even in the wild they do not fly far. They prefer to roost on high branches and (unless pinioned) can be hard to catch during the day.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Although wild guinea fowl live in groups, they are monogamous by nature and tend to bond in pairs. However, in domestication a single male may serve four or more females.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">USES</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">As noted, guinea fowl are valuable sources of both meat and eggs. They can also be used to control insect pests on vegetable crops.3</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Guinea fowl are good "watch animals"; they have fantastic eyesight, a harsh cry, and will shriek at the slightest provocation. Their agitation on sighting dogs, foxes, hawks, or other predators have saved the lives of many a chicken, duck, and turkey. They are brave and will attack even large animals that threaten them.4 </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">HUSBANDRY</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">Guinea fowl can be kept in confinement using the methods for raising battery chickens. In this system, breeding stock are housed in cages and artificially inseminated. It gives the best egg production and fertility but requires housing, equipment, and skilled labor.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">These birds can also be kept in a semidomestic state in and around the farmyard. In such cases they are penned until they are 12 weeks old. Unaccustomed to foraging for natural food, they constantly return to their artificial food supply. Eventually, however, they learn to subsist by scavenging.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The birds have been called "the worst parents in the world," and are almost incapable of looking after their keets.5 Because the females are such indifferent mothers, the eggs are best hatched in incubators or under other birds, to avoid the keets' being lost by their natural mothers. In many African countries, eggs are hatched under chickens.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Keets are often kept indoors until they are 3-4 weeks old to protect them from predators and wet weather. Sexual maturity can be delayed to as late as 32 weeks of age by holding the birds in windowless housing and controlling the lighting. This improves egg size and hatchability and reduces early mortality. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">GUINEA FOWL AND THE ANCIENTS</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">The earliest reference to guinea fowl can be found in murals in the Pyramid of Wenis at Saqqara in Egypt, painted about 2400 B.C. Aviaries were quite fashionable at the time, and wealthy landowners maintained guinea fowl within their walled gardens. A thousand years later, by the time of Queen Hatshepsut (about 1475 B.C.), the junglefowl (the ancestor of the chicken) had arrived, and from then on it was raised on a substantial scale. Records of this period refer to "walk-in" incubators, constructed of mud bricks and heated by cameldung fires. The largest could hold up to 90,000 eggs (mainly from junglefowl but some from guinea fowl) and hatching rates of up to 70 percent were claimed.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">By 400 B.C., guinea fowl were well established on farms in Greece. Later, they rose to importance in ancient Rome. Pliny the elder (in his Natural History, published 77 A.D.) stated that they were the last bird to be added to the Roman menu and that they were in great demand, both eggs and flesh being considered great delicacies. The emperor Caligula offered them as sacrifices to himself when he assumed the title of deity.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The guinea fowl then died out in Europe but was reintroduced by the Portuguese navigators returning from their African explorations in the late 1400s. They gave it the name pintada or "painted chicken" and this changed to pintade in French, while the name "Guinea fowl" (fowl from Africa) stayed in English, and gallina de Guinea in Spanish. Coincidentally, guinea fowl and turkeys were both introduced to England between 1530 and 1550, and the English, smitten with the original French misnomers, were left sorting out "Ginny birds" and "Turkey birds" for the remainder of the century. Both birds were adopted with great enthusiasm, and within 150 years they had utterly displaced the peafowl and swan as the major table birds for festive occasions.</P>
+<P ALIGN="JUSTIFY">Adapted from R.H.H. Belshaw, 1985 Guinea Fowl of the World</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">ADVANTAGES</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">Compared with the farmyard chicken the guinea fowl's advantages are:</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">- Low production costs;</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">- Premium quality meat;</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">- Greater capacity to utilize green feeds;</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">- Better ability to scavenge for insects and grains;</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">- Better ability to protect itself against predators; and</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">- Better resistance to common poultry parasites and diseases (for example, Newcastle disease and fowlpox).</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">Surprisingly, this semidomestic bird, which has been farmed for centuries, retains the characteristics (feather morphology, hardiness, social behavior) of its wild ancestor - even when subjected to the most modern intensive-rearing methods employing battery cages and artificial insemination. Thus, it thrives under semicaptive conditions and needs little special care. The birds forage well for themselves and do not require much attention; their meat is tasty and they produce substantial numbers of eggs. Unlike chickens, they don't scratch to get insects out of the soil, so they are less destructive to the garden.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">LIMITATIONS</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">In backyard production the guinea fowl is supreme, but when produced intensively it costs more to raise than chickens. In Europe, for instance, day-old keets cost about twice as much as day-old broiler chicks. (The major reason is that guinea fowl produce fewer hatching eggs and require a longer feeding period.) Guinea fowl are also more expensive to feed. Their feed conversion (for meat production at the marketing age) is about 3.3-3.6 as compared with a broiler's feed conversion of 1.8-1.9. Moreover, guinea fowl take about twice as long to reach marketable size: they are marketed for meat at age 12-14 weeks, compared with 7-8 weeks for the broilers. Therefore, the selling price of guinea fowl in the Western world is up to twice that of broilers.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Guinea fowl are nervous and stupid. They can be difficult to catch' and when panicking they can easily suffocate their keets.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">They are susceptible to some of the common diseases of chickens and turkeys. Salmonella is the most prevalent, but others are pullorum disease, staphylococcus, and Marek's disease. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">THE GUINEA FOWL'S WILD COUSINS</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">The domesticated guinea fowl is descended from just one subspecies of the family's seven known species and numerous subspecies. Some of the others may also have promise as poultry. They, too, generally occur in flocks in bushy grasslands and open forests in Africa. All feed on vegetable matter such as seeds, berries, and tender shoots, and on invertebrates such as slugs. They rarely fly except to roost. They acclimatize well are easy to maintain in captivity, and can survive long periods away from water.** Their disposition is tame and nonaggressive, and they mix well with other birds.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Wild subspecies closely related to the domestic guinea fowl that might make future poultry in their own right include the following:</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">- Gray-breasted guinea fowl (Numida meleagris galeata). This subspecies is the principal ancestor of domestic guinea fowls. It is found throughout West Africa and probably has many valuable genetic traits. There is much variation in the size and other characteristics among the various individuals. People along the Gambia, Volta, and Niger rivers have long traditions of breeding these birds.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">- Tufted guinea fowl (Numida meleagris meleagris). This subspecies is quite large and has black plumage thickly spotted with white dots. It is the probable ancestor of the birds reared in ancient Egypt and in the Roman empire (see page 120). Hill farmers in the southern Sudan sometimes breed them in captivity.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">- Mitred guinea fowl (Numida meleagris mitrata). Probably the most popular game bird in East Africa, this type has a bright blue-green head and red wattles. It was once a common sight in the wild but it has now been decimated by overhunting. It is now most numerous in the Masai lands of Kenya and Tanzania. It has been kept in a semidomesticated form in Zanzibar for several centuries. Zoos and aviaries around the world have imported it, and it has bred well for them.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Wild guinea fowl that are different species from the domestic one but that are still worth considering as potential poultry include the following:</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">- Black guinea fowl (Phasidus niger or Agelastes niger). This bird of the tropical rainforests of West and Central Africa is the size of a small chicken. It has sooty black plumage, a naked head, and a pink or yellow neck. It is seldom hunted because the meat tastes dreadful but this is probably because of a particularly pungent fungus they eat in the forest. Raised on fungus-free forages, these birds are probably very palatable. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">- Crested guinea hen (Guttera spp.). Three species. These strange-looking birds have a thick mop of inky black feathers above their black, naked faces. Widely distributed in the thickly forested areas of sub-Saharan Africa. Unlike the other species, they prefer the rainforest. They have a musical trumpeting call. At least one species has bred well in Europe. For example, a flourishing colony has been established in the Walsrode Bird Park in Germany.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">- Vulturine guinea fowl (Acryllium vulturinum). The largest of all guinea fowl, this species is found in parts of Ethiopia, Somalia, and East Africa. One of the most striking looking of all birds, its head is bare and blue, its body black with white spots, and its breast bears long bright cobalt-blue patches on either side. This has been reared as an aviary bird in both Europe and America and might make a useful domesticate.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">RESEARCH AND CONSERVATION NEEDS</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">Agencies involved in international economic development should undertake guinea fowl assessment trials, evaluations, and coordinated introductions to stimulate programs for small farmers and for industries in dozens of countries.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Breeders have been working to improve guinea fowl only since the 1950s. There is a need for more information on growth rate, health, egg production, feed conversion, body weight, carcass yield, laying intensity, fertility, hatchability, and egg weight - especially under free-ranging conditions.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Husbandry research should also be directed towards feeds and feeding systems for growing and breeding stock. Other efforts are needed to increase the hatchability of eggs under natural conditions (under guinea hens or surrogate mothers), and to identify the best lighting regimes (both sexual maturity and rate of lay are influenced by changes in daylength).</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The guinea fowl that has become an important domesticated bird throughout the civilized world is descended from just one of seven known species in the family. These birds generally occur in flocks in bushy grasslands and open forest in Africa and Madagascar, and some of the others may also have promise as poultry (see sidebar opposite). </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<B><P>&lt;&lt;TOC3&gt;&gt; 9 Muscovy</P>
+</B><P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&lt;&lt;I&gt;&gt; g012a.png FIGURE</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The muscovy (Cairina moschata), a unique ducklike species of the South American rainforest, belongs to a small group of waterfowl that perch in trees. In poultry science, however, it is normally grouped with domestic ducks for lack of a better classification.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Except in France, Italy and Taiwan muscovies have received little modern research. But their promise can be judged from the fact that they account for 50 percent of the duck meat consumed in France - about 60,000 tons per year - and they are often consumed in Italy and Taiwan as well.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">For Third World subsistence farming, muscovies have excellent possibilities. There is probably no better choice for a meat bird that requires minimal care and feed. Tame, quiet, and able to forage for much of their keep, they are inherently hardy, vigorous, and robust. They have heavily fleshed breasts and are highly prized for their meat, which is dark, more flavorful, and less fatty than that of common ducks. An average muscovy gives more meat than a chicken of the same age, and it also survives hot, wet environments better. In addition, muscovies are better parents than the domestic duck. Females are probably the best natural mothers of any poultry species, as measured by their success at incubating their eggs and caring for their young.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">All in all, this bird deserves more attention than it has received so far in Third World livestock projects. Dispersed around the warm and hot regions of the world, muscovies already exist in small numbers in backyards and villages, much like the domestic chicken in previous centuries. Despite a lack of research, the present unimproved stocks are already impressive meat yielders. Used more widely and more intensively, they could contribute much to poor people's meat supplies. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Crossing the muscovy with the common duck produces a hybrid that combines many of the advantages of both. This cross, known as "mulard," or "mule duck" in English, is raised in France for its liver and meat and is produced in quantity in Taiwan (see sidebar, page 132). It, too, has a major future role.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">AREA OF POTENTIAL USE</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">Muscovies are suitable for use almost anywhere that chickens can be kept. Moreover, their tropical ancestry and inherent robustness give them an advantage in hot and humid climates.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">APPEARANCE AND SIZE</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">Although a muscovy somewhat resembles a goose, it is one of the greater wood ducks of tropical South America. It was domesticated in pre-Columbian times, most likely in the rainforests of Colombia. Related wild types, looking very much like the muscovy, still occur in South American wetlands, particularly mangrove swamps.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Males have mature live weights of 5 kg and females about 2.5 kg. Both have broad and rounded wings. The adults have patches of bare skin around the eyes, rather than feathers. Much of this is covered in "caruncles," which superficially resemble warty outgrowths. The feet have sharp claws. Both sexes raise a crest of feathers when alarmed.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">There is much color variation among the various muscovy populations including types that are called white, colored, black, blue, chocolate, silver, buff, and pied.2 The most common types (they are not considered breeds) are the white and the colored. The white produces a cleaner looking carcass, but the colored is the most popular meat type in France. Its plumage is an iridescent greenish black, except for white forewings.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">DISTRIBUTION</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">The native range of the muscovy's probable wild ancestor covers much of Central America and northern South America. The domestic form also occurs over most of Latin America - from southern Chile to the northern limits of traditional culture in lowland Mexico - including the Caribbean, where it was present shortly after Columbus landed.3 The birds can be observed among the domestic fowl in the high Andes, for example, and are feral in southern coastal areas of the United States.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Carried across the Atlantic, probably in the early 1500s, the domesticated muscovy spread quickly in Europe, and thence to North America, Asia, Africa, and Oceania. Today, it finds favor with the food-loving French as "canard de Barbarie," and France has the greatest concentration of muscovies in Europe.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Down the centuries the muscovy became popular in tropical Asia (especially the Philippines and Indonesia) and in China and Taiwan. Throughout Indonesia (where it is known as "entok") it is popular with villagers for incubating eggs from ducks, geese, and chickens. It is now spreading into Oceania, and has recently gained particular favor in the Solomon Islands.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Muscovies are also known in Africa and can be found in many villages, especially in West Africa.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">STATUS</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">Not endangered.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">HABITAT AND ENVIRONMENT</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">Wild muscovies occur mainly along tropical jungle streams, but domestic muscovies are found in many environments from the heat of Central America to the cold of Central Europe. They also tolerate dry conditions, but they thrive best where climates are both hot and wet.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">BIOLOGY</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">Muscovies utilize high-fiber feeds better than chickens and common ducks, and eat larger quantities of grass. They also consume other green vegetation and readily snap up any insects they can find. If quality forage is available, only a small daily ration of grain or pellets is required for them to reach peak production.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Muscovy females normally hatch and raise large broods efficiently. It is not unusual to see them with a dozen or more fragile ducklings in tow - many of them adopted from other species. They bravely protect their young and have been known to beat off cats, dogs, foxes, and other marauders.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Normally, muscovies are healthy and live and breed for many years. They suffer few diseases, especially when free ranging. However, they seem to be more susceptible to duck virus enteritis (duck plague) than common ducks.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&lt;&lt;I&gt;&gt; p129a.png figure</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">BEHAVIOR</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">While appearing to be slow and lethargic, muscovies can be quick and agile when one tries to catch them. Females are strong fliers and readily clear a standard fence. Males frequently become so ponderous that they cannot get airborne without an elevated perch or the aid of a strong wind. Although they forage over a larger area than chickens, they generally neither decamp nor wander as far as common ducks.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Domesticated muscovies are either solitary or live together in small family groups, but sometimes in winter they flock together on bodies of water. They swim and dive well.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">These birds seldom make loud noises. A drake's voice resembles a muffled "puff"; females are almost mute. However, both can hiss or make a soft sound not unlike that of sleigh bells.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The muscovy is polygamous (a young male will try to mate with almost any fowl, including chickens). Mating can occur on land or in water. Males are pugnacious and tolerate no opposition. Because of this, they do not do well in close confinement.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">A BETTER FLY TRAP</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">The muscovy is a voracious omnivore that is particularly fond of insects. For years, some Canadian farmers have sworn that a few muscovies took care of all fly problems on their farms. In 1989, Ontario biologists Gordon Surgeoner and Barry Glofcheskie (see Research Contacts) decided to put this to the test.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Starting with laboratory trials, the entomologists first put a hungry five-week-old muscovy into a screened cage with 400 living houseflies. Within an hour it had eaten 326. Later, they placed four muscovies in separate cages containing 100 flies each. Within 30 minutes over 90 percent of the insects were gone. It took flypaper, fly traps, and bait cards anywhere from 15 to 86 hours to suppress the populations that much.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Moving to fleld tests, the researchers placed pairs of twoyear-old muscovies on several Ontario farms. Videotapes showed the birds snapping at houseflies and biting flies about every 30 seconds and being successful on 70 percent of their attempts. With that efficiency, they achieved 80-90 percent fly control in enclosures such as calf rooms or piggeries. The birds were given only water and had to scavenge for all their food. Females seemed to eat about 10 percent more flies than males, and individuals of any age between eight days and two years were equally effective.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The birds fit the practical needs for farmyard fly control. They stayed close to piglets and calves, to which flies are particularly attracted. They even snatched flies off the hides of resting animals without waking them up. On one farm, the birds huddled between sleeping piglets and were accepted by the sow lying beside them. This was noteworthy because most fly-catching devices (chemical, electrical, or mechanical) must be kept far from animals.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">To the Canadians, the economic advantages are clear. A 35-cow dairy needs $150-$590 worth of chemicals for controlling flies during the fly season; muscovy chicks, on the other hand, cost less than $2 each, eat for free, and can be sold for a profit of 200-400 percent.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The researchers point out that employing muscovies does not eliminate all need for insecticides, but it reduces the amounts required. And muscovies are biodegradable, will not cause a buildup of genetic resistance, and taste better than flypaper. Indeed, their meat is excellent, and the naturally mute birds seldom make any noise.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Reportedly, muscovies are kept in some houses in South America to control not only flies, but also roaches and other insects.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">USES</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">The muscovy is generally raised only for its meat, which is of excellent quality and taste. In stews it is hard to distinguish from pork; cured and smoked it is similar to lean ham.4 The fat content is low.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Muscovy eggs are as tasty as other duck eggs, and a muscovy female can supply a large number if she is kept from sitting.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">These birds are useful for clearing both terrestrial and aquatic weeds.5</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Down feathers are used, like those of other ducks, in clothing and comforters.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">HUSBANDRY</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">Muscovies may be raised like common ducks. An ideal grouping is one male to five or six females. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Except in Taiwan, France, Hungary, and a few other European countries, they exist predominantly in small flocks in farmyards and village ponds. However, they can be reared under intensive conditions in a shed or pen that is well lighted and equipped with low roosts and bedding. Under such conditions, they may be fed diets recommended for rearing common ducks or given coarse feeds, including whole grain. If chicken rations are used, fresh greens must be provided to avoid "cowboy" legs, a symptom of niacin deficiency.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Although they thrive in areas where there is abundant water, they do not require access to swimming water. They prefer to nest under cover and will use nesting boxes. A normal clutch size is 9-14 eggs; however, clutches of up to 28 can occur. There may be 4 clutches annually, and (when the hen does not have to brood the ducklings) some muscovies have laid 100 eggs in a year.6</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The egg weight, which increases with the female's age, ranges from 65 to 85 g. The eggs require 33-35 days to hatch, a week longer than the common duck's. Hatching success of 75 percent or more is common.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Compared with domestic ducks early growth is slow, which is perhaps why muscovies have not enjoyed wider industrial use. However, after the slow period they grow rapidly and, because they forage on a broader range of vegetation than common ducks, they can scavenge a large proportion of their diet at little or no cost.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">When raised intensively, females average 2 kg and males 4 kg at 11-12 weeks of age. Females may reach sexual maturity by 28 weeks of age; males require a month more.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">THE MULE DUCK OF TAIWAN</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">In parts of Europe, hybrids between muscovies and common ducks are reared for fattening. However, Taiwan has made the most outstanding use of this "mule duck." Thanks in part to this muscovy hybrid, Taiwan's duck industry has grown rapidly in the last decade. The total value of duck products now exceeds $346 million per year. Much of the boom in duck production is due to improved feeding disease control and management systems, but much is also due to the performance of the mule duck. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">This hybrid is now Taiwan's major meat-duck breed, and about 30 million are consumed each year. Indeed, the duck industry has been so successful that Taiwan is increasingly exporting frozen duck breast and drumstick meat to Japan. It now provides 24 percent of the duck meat eaten in Japan most of it coming from mule ducks. Also, Taiwan is exporting partially incubated mule-duck eggs throughout Southeast Asia. And mule ducks supply most of the raw material for Taiwan's large feather industry.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Taiwan farmers have been producing mule ducks for 250 years, but the recent jump in production is due to the use of artificial insemination to overcome the natural reticence of the different species to mate. Fortunately, artificial insemination is well developed and is a standard part of farming practice in Taiwan.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Mule ducks are successful because they have less fat than a broiler chicken and they grow faster. Indeed, they can reach a market weight of 2.8 kg at 65 - 75 days of age, depending upon the weather, season, and management. In part, this fast growth is because they are sterile and waste no energy in preparing for a sexual existence or in laying eggs.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The usual cross employs a muscovy male and a domesticduck female. The domestic breeds most employed for muleduck production are White Kaiya (Pekin male x White Tsaiya female), Large White Kaiya (Pekin male x White Kaiya female) and colored Kaiya. Both sexes of the hybrid offspring weigh about the same.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Crosses between a muscovy hen and a domestic drake are much rarer (traditionally, this was because of the different mating behavior of the two species, but even with artificial insemination available they are not much used) and the males of these hybrids are much heavier than the females. Females of this cross do lay eggs, but the eggs are small (about 40 g) and their embryos do not develop.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">There are almost 300 duck-breeding farms in Taiwan, annually producing more than 600,000 female domestic ducks for use in producing mule ducks. Some farmers combine duck raising with fish farming. The excrete of 4,000 ducks on one hectare of pond can provide 30,000 tilapia with 20 percent of their feed. It helps the farmer get rid of waste as well as giving him fresh fish to sell. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">ADVANTAGES</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">As noted, the muscovy is an extremely good forager and thrives under free-ranging conditions. Unlike other ducks, it grazes on grass and leaves and will maintain itself on pasture. Apparently, it can digest bran and other fibrous feeds better than common ducks can.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The males are larger than all but the largest strains of table duck. They have exceptionally broad, well-muscled breasts and provide one of the leanest meats of any waterfowl.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The muscovy is apparently more resistant to diseases that regularly decimate other poultry. This is one reason why villagers favored them: when chickens die, muscovies often survive.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The female's strong parental qualities help assure the survival of ducklings with a minimum of human intervention. Her ability to incubate and hatch most other poultry eggs is an added advantage to small farmers who have neither the capital to buy, nor the knowledge to operate, artificial incubators.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Unlike other ducks, muscovies are not easily alarmed, and fright does not affect their egg production and laying. Indeed, they are so phlegmatic that automobiles can be major causes of death.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">LIMITATIONS</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">Because they are a tropical species, these birds are much less tolerant of cold than common ducks and require more protection from freezing weather.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The muscovy's feed conversion is not as good as the chicken's. Also, compared with some other meat-duck breeds, muscovies have a slower rate of growth and require about 4 6 weeks longer to attain maximum development of breast muscles.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Muscovies can be difficult to handle. If their legs are free, the handler may be badly lacerated by the claws.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Although adults have a fair homing ability, muscovies may wander away when local forage is sparse, and young birds may be carried long distances downstream, never to return.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Because they feed on greenery, they can devastate gardens if the plants are very young.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Muscovies can be unsuspected carriers of poultry diseases, so that healthy-looking muscovies may infect the other species.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">RESEARCH AND CONSERVATION NEEDS</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">Poultry scientists should unite in efforts to advance technical knowledge and public appreciation of this bird. Governments and researchers should begin evaluations of local varieties and their uses and performances. The experiences of France, Italy, Eastern Europe, and Taiwan should be gathered and made available for a worldwide readership.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">It is important that the many muscovy varieties within the countries of Latin America - where the bird has a centuries-long history of domestication - be maintained and studied. Many superior varieties and specimens may be awaiting discovery.7</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The muscovy's nutritional requirements, range and confined systems of management, and disease vulnerability are poorly understood and need study. Especially needed are ways to increase growth rate. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<B><P>&lt;&lt;TOC3&gt;&gt; 10 Pigeon</P>
+</B><P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&lt;&lt;I&gt;&gt; g013a.png FIGURE</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Pigeons (Columba livia)1 are durable birds that can be raised with little effort. Able to survive in inhospitable climates, they fend for themselves - often ranging over many square kilometers to locate seeds and edible scraps. They have been raised for centuries, especially in North Africa and the Middle East. In parts of North America and Europe, they are produced as a delicacy for the gourmet market. But raising pigeons for food is not nearly as widespread as it could be; indeed, in modern times its potential has hardly been touched. Farmed pigeons are particularly promising as urban microlivestock because they require little space and thrive in cities.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Young pigeons (squab) grow at a rapid rate. Their meat is finely textured, has an attractive flavor, and is often used in place of game fowl. Tender and easily digested, it commands premium market prices. In many areas, the continuing demand is unfilled.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Pigeons are traditionally raised in dovecotes - "houses" that protect the birds from the elements and from predators. This system allows free-ranging flight and requires almost no human intervention. Dovecotes are a good source of both squab and garden manure, and they continue to be used, especially in Egypt. On the other hand, pigeons can also be raised in confinement - usually in enclosed yards - with all their needs supplied by the farmer. There are, for example, pigeon farms in the United States with up to 35,000 pairs of breeding birds.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Pigeon production may never rise enough to compete with commercial poultry as a major source of food, but for Third World villages these birds could become a significant addition to the diet as well as a source for substantial supplemental income. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">AREA OF POTENTIAL USE</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">Worldwide.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">APPEARANCE AND SIZE</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">Pigeons have small heads, plump, full-breasted bodies, and soft, dense plumage. They weigh from about 0.5 to nearly I kg. A few large breeds (Runts, for instance, which commonly weigh 1.4 kg) are the size of small domestic chickens.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Many breeds have been developed for meat production. They produce squab that grow quicker and have larger breasts than unselected birds.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">DISTRIBUTION</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">The wild ancestor of the common pigeon - domestic, wild, or feral -  is thought to be the rock pigeon or rock dove of Europe and Asia. Today its domestic descendants are bred in virtually every country, and those that have gone feral (reverted to the wild) occur in most of the world's cities and towns.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">STATUS</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">They are abundant. However, as with most other domestic species there is concern over the decline and loss of certain breeds. Societies have been organized (notably in the United Kingdom) to preserve rare types.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&lt;&lt;I&gt;&gt; p138a.png Natural habitat of the rock dove ancestor of the domestic pigeon</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">HABITAT AND ENVIRONMENT</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">The domestic pigeon can be raised equally well in temperate and tropical zones. Indeed, this adaptable species can be kept anywhere that wild pigeons exist, including arid and humid regions. It should be noted, however, that cold climates do not favor squab production and hot climates promote vermin and disease.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">BIOLOGY</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">The pigeon's natural diet consists mostly of seeds, but includes fruits, leaves, and some invertebrates. Feral pigeons consume a wide array of materials, including insects, bread, meat scraps, weed seeds, and many kinds of spilled grains at mills, wharves, railway yards, grain elevators, and farm fields.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">For the first four or five days of life, the young are fed "crop milk." This substance, common to pigeons and doves,2 is composed of cells from the lining of the crop and is very high in fats and nutritional energy. The phenomenal growth rate of young squab has been attributed to crop milk and to its early replacement (within 8-10 days) with concentrated foods, regurgitated by both parents. The parents feed the squab for about four weeks before pushing it out of the nest to prepare for the next clutch.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">In domestic birds, sexual maturity (as measured by age at first egg) is reached at 120-150 days. Life span can be 15 years, although growth and egg production decline rapidly after the third year.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">BEHAVIOR</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">Wild pigeons often nest on cliff sides. Domestic pigeons prefer to nest around buildings, in nooks and shelves and under the eaves - that is, in "pigeonholes."</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">In domestic varieties, the pair-bond often lasts until severe illness or death. Sometimes, however, a vigorous male will "invade" a nest and mate with the females there. Both sexes take nearly equal part in nest building, incubation, and caring for the young. Typically, there are two eggs to a clutch. Eight clutches a year is not uncommon for a breeding pair. The incubation period is 17-19 days.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Unlike most birds, pigeons drink by inserting their beaks into water and sucking up a continuous draft. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Courtship is characterized by cooing, prancing, and displays of spread, lowered tail feathers. "Bow and coo" exhibitions are unique to pigeons and doves and differ among species.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">USES</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">Pigeons are usually raised exclusively for meat. The squab are harvested just before full feather development and before the youngster has started to fly, usually at 21-30 days of age. At this time the ratio of flesh to inedible parts is highest; once flying begins, the meat becomes tougher. Weight depends upon breed, nutrition, and other factors, but usually ranges from 340 to 680 g.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Pigeons are extensively used for scientific research, notably in physiology and psychology. They are also widely kept as pets for plumage and for racing. The pigeon's unique homing ability was recognized in Roman times, and the birds have been trained to return to the dovecote from as far away as 700 km. Even today, homing pigeons are used to carry messages, especially during war.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">HUSBANDRY</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">Pigeons are easily trained to recognize "home." The wing feathers are clipped and the birds are fed close to the dovecote; by the time they refledge, their homing instinct has been developed. Alternatively, newly captured pigeons may be trained by confining them to the dovecote for at least one week. At first, a little grain is provided in the morning (this is to ensure the birds will return to the coop). The birds can obtain the rest themselves.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Any waterproof house that is easy to clean is suitable for keeping pigeons. Many traditional dovecotes are built of earthenware pots. In Asia and Europe, wooden pigeon towers are generally used.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Unlike chickens, pigeons do not prefer communal roosts. Instead, they prefer nesting shelves, of which there should be two for each breeding pair. The shelves are usually placed in dark corners and are fitted with low walls to keep eggs from rolling out.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Grit is important in the diet, both to provide minerals and to allow the birds to grind feed in their gizzards.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Commercial squab breeds are often kept permanently in pens, a process that requires care and experience. Growers expect an average of 12-14 squab per pair per year, although much depends on environment and management. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The birds need fresh water daily and water for bathing at least weekly. Since they feed their young by regurgitation, the adults must have a continuous supply of clean drinking water. Orphan squab can be fed egg yolk until old enough to consume adult feeds.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Like all poultry, confined pigeons must be provided enough supplemental feed to ensure a balanced diet. A mixture of whole grains can be fed for maximum production. It is important that grains be dry and free of mold (pigeons will not thrive on mash). Peas, beans, or similar pulses make good supplements.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">CARRIER PIGEONS</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">Most people consider message-carrying pigeons to be a quaint anachronism. But in a few countries (both developed and developing) carrier pigeons are making a comeback, and in the future they may be used routinely once again.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">New techniques are making this process far more practical than before. For example, in the past the pigeons would be flown in one direction only. They were transported away from home and at the appropriate time released to find their way back. That was very limiting. But it has since been found that pigeons can be trained to carry messages in two directions: flying from one point to another and then back again. They will do it twice a day, and with almost perfect reliability. The key is to place the feeding station at one end and the nest at the other. This limits the pigeon's range, but they still can handle round-trip distances up to 160 km.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">With a little ingenuity, there is no need for a person to monitor the stations to receive the messages as the bird arrives. One simple technique is to arrange the station with one-way doors - one opening inwards, the other outwards. Placing a bar across the outward door means that the bird cannot get out until someone releases it. Thus the message can always be retrieved.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">This system has been employed in Puerto Rico and Guatemala, but it could be used almost anywhere. In many parts of the Third World, in particular, there are remote areas with no phones and with hilly, rough terrain where delivering messages can take hours of strenuous travel. Some locations are subject to unexpected isolation by natural calamities or military or terrorist actions.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">In Puerto Rico, for instance, we kept pigeons in a village 32 km from the capital. The pigeons could get downtown in 20-30 minutes. It took us 1.5-2 hours each way by road. What was easy for the birds was a major trip for us. Pigeons carried the villagers' requests for certain foods and medicines. Our contact in the city then sent up the supplies by bus. The birds never let us down.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Carrier pigeons are useful for more than just flying far and fast. They have been bred for racing and their large pectoral muscles make them excellent meat producers - much better than the common pigeons normally raised for food. A pair of carriers typically will raise 12 - 16 young each year, and those not needed for message carrying can be butchered at 28 days of age - yielding meat that is nutritious and considered a delicacy in many countries.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">David Holderread</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">Every day on the northwest coast of France, Petit Gendamme, a black and white carrier pigeon, flies on average 23 km between hospitals on his blood delivery route. Trussed in tiny hand-sewn harnesses, he and a flock of carrier pigeons set out (except during the hunting season) with little red tubes of blood secured to their breasts.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">"It's a simple, effective, and cost-saving transport system," said Yves Le Henaff, head of the Avranches Hospital laboratory, Cotentin, France, a central blood-testing center that serves a number of isolated medical centers along the coast.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The service becomes particularly valuable during the summer tourist rush, when travellers flock to the seashore to visit nearby Mont Saint Michel, crowding the small country roads and increasing the risk of traffic accidents.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The birds' average flight time between the hospitals of Avranches and Granville, for example, a distance of about 27 km, is 20 minutes, including the time for harnessing up. And with a favorable western wind their best time can reach 11 minutes.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">While gasoline costs the equivalent of $0. 75 a lifer in France, hospital officials say that a few grains of corn is all it takes to run this operation. According to Le Henaff, who supervises the carrier pigeon operation, the hospital is saving up to $46 a day on gas and auto maintenance.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The 40-year-old Le Henaff got the idea five years ago from an article in a scientific journal describing a similar experiment in Britain. A year later, he and an associate called on the local seamstress to design a light harness that could hold a tube, which, when filled, weighs approximately 39 g.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The flock now consists of 40 veteran fliers and 20 carrier pigeons in training.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">And what if the winged creatures stray en route? Le Henaff has devised a fall-back option: two pigeons carry two different test tubes containing the same blood sample.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The birds fly every day of the year with the exception of the three-month autumn hunting season. Since the beginning of the experiment four years ago, there have been two casualties. Le Henaff believes the birds probably met their fate in some Normand's oven.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Sometimes weather is a factor, and heavy fog can keep the delivery team grounded.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">So far, the new job seems to benefit the pigeons, too. Unlike sickly city pigeons, whose average life span is about four years, well-cared-for carrier pigeons can live up to 15 years, Le Henaff said. "And how many people do you know who are willing to stay with the same outfit for that long?"</P>
+<P ALIGN="JUSTIFY">Sabine Maubouche</P>
+<P ALIGN="JUSTIFY">The Washington Post</P>
+<P ALIGN="JUSTIFY">December 2, 1986</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">ADVANTAGES</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">Under extensive conditions - where the birds are released each day to feed themselves - almost no land is needed. Under intensive conditions, where the birds spend their lives in confinement, a mere half hectare can be enough space to raise 2,000 pairs.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Free-ranging pigeons forage over a wider area than most domestic fowl because they fly out to find their feed. Nutrient requirements3 are similar to those of chickens and other fowl (making allowance for the energy needed for flying), so commercial feed and other supplements - if needed at all - are generally available.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">In dovecote culture, pigeons require little or no handling. They brood the young with little intervention. Although not continuous, the production of meat from these fast-growing, rapidly reproducing birds is more sustained than with most livestock.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Almost nowhere are there taboos against consuming pigeon meat. Prices received for squab are normally high, and in most places the demand is constant. The only limitation in some areas is the absence of an effective market, which is usually easy to create.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Squab contains a larger proportion of soluble protein and a smaller proportion of connective tissue than most meats and is therefore good for invalids and people with digestive disorders.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">As many hobbyists can testify, raising pigeons can be gratifying.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">LIMITATIONS</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">Pigeons are subject to few diseases. However, worms, lice, diarrhea (coccidiosis), canker (trichomoniasis), and salmonella (paratyphoid) occur at some time in most domestic breeds. Salmonella exists in low levels in most flocks and will flare up if birds are stressed. Treatments recommended for domestic chickens are usually suitable for pigeons. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">By flying over a wide area and eating grains and other foods, pigeons can cause conflicts with farmers. Indeed, in the 13th century the aristocracy's pigeons became a major grievance of the peasants who saw their seed devoured. On the other hand, "croppers" (breeds with large crops) were developed to steal grain from the lord's fields. The pigeon returned home and his crop was emptied of the grain, which was used by the peasant to make bread.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The birds can become nuisances. They leave droppings in annoying places, some people find them too noisy, and a few people are severely allergic to "pigeon dust."</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Every conceivable type of predator can be expected; therefore, precautions must be taken. The dovecote must be well protected against rats, which are the principal enemy of the eggs and the squabs.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Nesting birds need a high-protein diet to raise squab at the high rates of gain that are possible.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">RESEARCH AND CONSERVATION NEEDS</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">Poultry researchers should study the increased role pigeons might play in Third World economic development. Nothing comparable to the sophisticated selection employed with the domestic chicken has so far been attempted. Given such attention the gains could be great.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Among pressing research needs are:</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">- Breeding. This needs to be better understood. For example, the effects of hybridization and inbreeding need clarification.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">- Environmental limits. Little work has been done outside the temperate regions.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">- Diseases. These deserve increased attention.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">There is also the potential of "dovecotes" for wild pigeons. Numerous local species are well adapted to local conditions, and these deserve to be tested for "domestication."4 Many wild species quickly lose their fear of man, and in time they can even become too fat to fly. Wild pigeons are already found throughout the humid tropics and are trapped for meat and rearing in New Guinea and other places. They are already an important food source for many subsistence farmers and shifting cultivators, and with some dovecote management could provide a greater, more dependable source of food and income. The potential for domesticating local pigeon species, especially those suited to the tropics, deserves exploration. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<B><P>&lt;&lt;TOC3&gt;&gt; 11 Quail</P>
+</B><P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&lt;&lt;I&gt;&gt; g014a.png FIGURE</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Native to Asia and Europe, quail' (Coturnix coturnix2) have been farmed since ancient times, especially in the Far East. They reproduce rapidly and their rate of egg production is remarkable. They are also robust, disease resistant, and easy to keep, requiring only simple cages and equipment and little space. Yet they are not well known around the world and deserve wider testing.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Quail are so precocious that they can lay eggs when hardly more than 5 weeks old. It is said that about 20 of them are sufficient to keep an average family in eggs year-round. Quail eggs are very popular in Japan, where they are packed in thin plastic cases and sold fresh in many food stores. They are also boiled, shelled, and either canned or boxed like chicken eggs. Quail eggs are excellent as hors d'oeuvres and they also are used to make mayonnaise, cakes, and other prepared foods.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">In France, Italy, the United States, and some countries in Latin America (Brazil and Chile, for example) as well as throughout Asia, it is the meat that is consumed. It is particularly delicious when charcoal broiled. One company in Spain annually processes 20 million quail for meat.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Many of the domesticated strains seem to have originated in China, and migrating Chinese carried them throughout Asia. Today, millions of domestic quail are reared in Japan, Indonesia, Thailand, Taiwan, Hong Kong, Indochina, Philippines, and Malaysia, as well as in Brazil and Chile. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Commercial production is carried out, as in the chicken industry, in specialized units involving hatcheries, farms, and factories that process eggs and meat. However, quail have outstanding potential for village and "backyard" production as well. It is this aspect that deserves greater attention.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">AREA OF POTENTIAL USE</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">Worldwide.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">APPEARANCE AND SIZE</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">Quail come in various sizes. The smaller types are used for egg production, whereas the larger ones are better for meat. Adult females of improved meat strains may weigh up to 500 g. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">There are several color varieties. However, mature females are characterized by a tan-colored throat and breast, with black spots on the breast. Mature males, which are slightly smaller than females, have rusty-brown throats and breasts. All mature males have a bulbous structure, known as the foam gland, located at the upper edge of the vent.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">In the United States, the Pharaoh strain is the bird of choice for commercial production. Other available strains tend to be bred more for fancy than for food.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Quail eggs are mottled brown, but some strains have been selected for white shells. These eggs are often preferred by consumers and are easier to candle (the process of holding eggs up to a light to check for interior quality and stage of incubation). An average egg weighs 10 g - about 8 percent of the female's body weight. (By comparison, a chicken egg weighs about 3 percent of the hen's body weight.) Quail chicks weigh merely 5-6 g when hatched and are normally covered in yellowish down with brown stripes.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">DISTRIBUTION</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">The ancestral wild species is widely distributed over much of Europe and Asia as well as parts of North Africa. Although domestic quail are now available almost everywhere, Japan is probably the world leader in commercial production; quail farms are common throughout its central and southern regions.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">STATUS</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">Not endangered. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&lt;&lt;I&gt;&gt; p149a.png figure</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">HABITAT AND ENVIRONMENT</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">Quail are hardy birds that, within reasonable limits, can adapt to many different environments. However, they prefer temperate climates; the northern limit of their winter habitat is around 38&Yacute;N.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">BIOLOGY</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">A quail's diet in the wild consists of insects, grain, and various other seeds. To thrive and reproduce efficiently in captivity, it needs feeds that are relatively high in protein.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The females mature at about 5-6 weeks of age and usually come into full egg production by the age of 50 days. With proper care, they will lay 200-300 eggs per year, but at that rate they age quickly. The life span under domestic conditions can be up to 5 years. However, second-year egg production is normally less than half the first year's, and fertility and hatchability fall sharply after birds reach 6 months of age, even though egg and sperm production continue. Thus, the commercial life is only about a year.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Crosses between the wild and domestic stocks produce fertile hybrids. Repeated backcrossing to either wild quail or domestic quail is successful.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">BEHAVIOR</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">Only females hatch the eggs and raise the chicks. Males go off and court other females when their partners begin the nesting process.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">USES</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">Quail eggs taste like chicken eggs. They are often served hard boiled, pickled, fried, or scrambled. Because of their size they make attractive snacks or salad ingredients. They provide an alternative for some people who are allergic to chicken eggs. On frying, the yolk hardens before the albumen.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Quail meat is dark and can be prepared in all of the many ways used for chicken. The two meats are similar in taste, although quail is slightly gamier.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Because of its hardiness, small size, and short life cycle, quail are now commonly used as an experimental animal for biological research and for producing vaccines - especially the vaccine for Newcastle disease, to which quail are resistant. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Many fanciers and hobbyists have also become interested in raising this adaptable species as a pet. Science teachers find it an excellent subject for classroom projects. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">QUAIL IN JAPAN</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">In some areas of Japan, quail are widely raised for their eggs and meat. However, Japanese originally valued the quail as a songbird. Tradition has it that about 600 years ago people began to enjoy its rhythmic call. In the feudal age, raising song quail became particularly popular among Samurai warriors. Contests were held to identify the most beautiful quail song and birds with the best voices were interbred in closed colonies. Even photostimulation was practiced to induce singing in winter.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Around 1910, enthusiastic breeders produced the present domestic Japanese quail from the song quail. It was created as a food source and became a part of Japanese cuisine. During World War II it was almost exterminated, but Japanese quail breeders restored it from the few survivors and from birds imported from China. The original song quail, however, were lost. In the 1960s, commercial quail flocks rapidly recovered and Japan's quail population again reached its prewar level of about 2 million birds. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">A QUAIL IN EVERY POT: AN OLD DELICACY FINDS A NEW PUBLIC</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">For centuries, quail were considered a great delicacy: a dish that only eminent chefs would cook and diners with an appreciative palate could enjoy. These small migratory birds, which are found in one variety or another throughout the world, were available until recently almost exclusively to hunters in the wild.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">But now quail are in danger: in danger of becoming commonplace.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">In the last few years, quail have gone from being rarefied to a supermarket specialty item. They are on menus in the most elegant restaurants and the most casual cafes and bistros.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Why so much interest?</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Quail are now available semi-boneless, which makes them faster and easier to cook, and easier to eat as well. The breastbones are removed by hand before the birds are packaged and shipped to stores. The bones in the wings and legs remain.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">A stainless-steel V-shaped pin - invented and patented by a restaurant chef who wanted a way to keep quail flat for grilling is inserted into the breast. The pin can be left there throughout cooking and removed just before serving.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">While whole quail might require 45 minutes to cook, the semi-boneless variety can be grilled in less than 10 minutes, or pan-roasted, braised or sauteed in less than 20 minutes.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The flavor of farm-raised quail has also helped bring them into the mainstream. Most farm-raised quail have tender meat like the dark meat of chicken, whose flavor is enjoyed by many people.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">And at a time when people are searching for foods, specifically animal protein, with low fat and cholesterol, quail fills the bill. The Agriculture Department says that quail skin has about 7 percent fat, about the same as dark meat of roasted chicken without the skin.</P>
+<P ALIGN="JUSTIFY">Judith Banrett Adapted from The New York Times </P>
+<P ALIGN="JUSTIFY">June 21, 1989</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">HUSBANDRY</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">It is necessary to keep quail in battery cages on wire floors because males secrete a sticky foam (from the foam gland) with their feces; on a solid floor, this adheres to the feet and collects dung, leading to crippling and breakage of eggs.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Adult quail can live and produce successfully if they are allowed 80 cm2 of floor space per bird. However, for reproduction about twice that is needed to allow for mating rituals.3 If properly mated, high fertility rates and good egg hatchability can be expected. To obtain fertile eggs, one male is needed for roughly six females.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Eggs hatch in about 17 days. Chicks require careful attention. Brooding temperatures of between 31 C and 35 C  are needed for the first week and above 21 C for the second week. From the second week on, chicks can survive at room temperature. (These temperatures are similar to those required for common chickens.) In cold climates, supplemental heat may be needed as well as protection from cool drafts.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Clean water must be provided at all times, with care taken to prevent the chicks from drowning in their water troughs. Shallow trays, jar lids, or pans filled with marbles or stones may be used.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">ADVANTAGES</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">Quail production can be started with little money. These easy-care birds can be housed in small, simple, inexpensive cages.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">As noted, they are resistant to Newcastle disease.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">SIX OF ONE, HALF A DOZEN OF THE OTHER</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">The fact that chickens can be crossed with quail has been known for some time, but there has been little attempt to develop the fertile hybrids. Now Malaysia has begun a project aimed at producing a new poultry bird - a cross between a cockerel and a hen quail. Zainal Abidin bin Mohd Noor, of the Department of Veterinary Services in Kuala Lumpur, is creating a strain that produces eggs of good quality and meat with the flavor of both parents. The new bird is intermediate in size between chicken and quail which is convenient because it is about right for an individual helping.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The crossbreeding is done through artificial insemination. The progeny exhibit a range of appearances, sizes, and plumage colors, depending on the strains of cockerel and quail hens used. In the Malaysian research, cockerels have been local Ayam Kampung Bantam, Hybro, and Golden Comet hybrids. The quails have been local inbred Japanese quail (IJQ) and imported meat strain quail (IMSQ).</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The trials show that the hybrids derived from the IMSQ flocks grew faster and bigger than those from the IJQ cross. The best have been the Hybro x IMSQ crosses, which weigh 475 g at 10 weeks of age. The best of the IJQ group weighed 290 g during the same period.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">This type of "tropical game hen" might be a way to introduce hybrid vigor into poultry production.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The researchers who developed the hybrid have named it the "yamyuh." </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">LIMITATIONS</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">Although generally disease resistant, quail are affected by several common poultry diseases, including salmonella, cholera, blackhead, and lice. They also suffer epidemic mortality from "quail disease" (ulcerative enteritis), which can, however, be controlled with antibiotics.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Quail seem to require more protein than chickens, and produce best when given feed that is fairly high in protein.4 However, they also perform satisfactorily when fed rations designed for turkeys. They have high requirements for vitamin A, which they do not store.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Quail are not suitable as free-ranging "scavengers." They must be kept confined, which is a major constraint. Unlike chickens or pigeons, they have no homing instinct and will not remain on a given site; if released, they will be lost. In addition, since they nest on the ground, they are highly susceptible to predation; they must be protected, especially where certain animals, the mongoose for example, are common.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Artificial incubation is essential. Natural incubation using the female is futile; the females do not go broody and rarely incubate their eggs. The shells are extremely thin, but the eggs can be incubated under a small chicken hen, such as a bantam.5 The eggs are also subject to minute fractures. However, the shell membrane is extremely tough and unfertilized eggs are generally unaffected, but the cracks cause fertilized embryos to dehydrate and die. This is a serious limitation. Whenever quail husbandry is introduced, artificial incubation should be included.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">RESEARCH AND CONSERVATION NEEDS</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">Quail deserve to be included in all poultry research aimed at helping the Third World. Through its international scientific program, Japan, in particular, could apply to developing nations its vast experience with quail farming.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Experiences with quail in the tropics (for example, Japanese farmers in the Amazon Basin) and in tropical highlands (for instance, in India, Nepal, or Central Africa) should be collected and assessed to improve understanding of the environmental limits to Third World quail farming.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Cooperation between commercial and laboratory quail breeders should be encouraged. Mutants found at the commercial level would be useful for laboratory work. Conversely, introducing new stocks could help the farmer. In both cases, more genetic diversity might also lead to the production of hybrid vigor, and genetic variability would be conserved.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Sex-linked genes, if they can be found, would be useful to the commercial quail breeder for the rapid sexing of newly hatched chicks. This could lead to more efficient production techniques, like those in the chicken industry.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Although virtually all work to date has been on the Japanese quail, other species and subspecies warrant research and testing. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<B><P>&lt;&lt;TOC3&gt;&gt; 12 Turkey</P>
+</B><P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&lt;&lt;I&gt;&gt; g015a.png FIGURE</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The turkey (Meleagris gallopavo) is well-known in North America and Europe, but in the rest of the world, especially in developing countries, its potential has been largely overlooked. Partly, this is because chickens are so familiar and grow so well that there seems no reason to consider any other poultry. Partly, it is because modern turkeys have been so highly bred for intensive production that the resulting birds are inappropriate for home production.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Nevertheless, there is a much wider potential role for turkeys in the future. There are types that thrive as village birds or as scavengers, but these are little known even to turkey specialists. These primitive types are probably the least studied of all domestic fowl; little effort has been directed at increasing their productivity under free-ranging conditions. However, they retain their ancestral self-reliance and are widely used by farmers in Mexico. That they are unrecognized elsewhere is a serious oversight.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Native to North America, the turkey was domesticated by Indians about 400 BC, and today's Mexican birds seem to be direct descendants.' Unlike the large-breasted, modern commercial varieties, they mate naturally and they retain colored feathers and a narrow breast configuration. Their persistence in Mexico after 500 years of competition with other poultry highlights their adaptability, ruggedness, and usefulness to people.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">These birds complement chicken production. They are able to thrive under more arid conditions, they tolerate heat better, they range farther, and they have higher quality meat. Also, the percentage of edible meat is much greater than that from a chicken. Turkey meat is so low in fat that in the United States, at least, it is making strong inroads into markets that previously used chicken exclusively. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Turkeys are natural foragers and can be kept as scavengers. Indeed, they thrive best where they can rove about, feeding on seeds, fresh grass, other herbage, and insects. As long as drinking water is available, they will return to their roost in the evening.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Appreciation for the turkey could rise rapidly. Interest already has been shown by several African nations. A French company has created a strain of self-reliant farm turkeys and is exporting them to developing countries.2 Researchers in Mexico are displaying increased interest in their national resource. And as knowledge and breeding stock continue to be developed, it is likely that village turkeys will become increasingly popular around the world.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">AREA OF POTENTIAL USE</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">Worldwide.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">APPEARANCE AND SIZE</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">Modern turkey breeding has been so dominated by selection for increased size and muscling that commercial turkeys have leg problems and cannot mate naturally (they are inseminated artificially). These highly bred birds are adapted for large-volume intensive production, and must be raised with care. As noted, this chapter emphasizes the more self-reliant, less highly selected turkeys found in Mexico and a few other Latin American countries. They do not require artificial insemination, and with little attention can care for themselves and their young.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Fully grown "criollo" turkeys of Mexico are less than half the size of some improved strains. Males weigh between 5 and 8 kg; females, between 3 and 4 kg.3 They vary in color from white, through splashed or mottled, to black. The skin of the neck and head is bare, rough, warty, and blue and red in color. A soft fleshy protuberance at the forehead (the snood) resembles a finger. In males it swells during courtship. The front of the neck is a pendant wattle. A bundle of long, coarse bristles (the beard) stands out prominently from the center of the breast.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">DISTRIBUTION</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">The unimproved domestic turkey is essentially limited to central Mexico and scattered locations throughout nearby Latin American countries. Some village birds are also kept in India, Egypt, and other areas, but these are descended from semi-improved strains exported from North America and Europe in earlier times. Generally speaking, few turkeys are found in tropical countries outside Latin America.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">STATUS</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">Domesticated turkeys are not endangered; there are estimated to be about 124 million in the world. However, the wild Mexican varieties, ancestors to the first domesticated turkeys sent to Europe, may now be endangered since their distribution in southwestern Mexico has been greatly reduced. Certainly, some primitive domestic strains in the uplands of central Mexico are also being depleted. A separate type, independently domesticated by the Pueblo Indians of the southwestern United States, seems to have disappeared entirely.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">HABITAT AND ENVIRONMENT</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">Turkeys can be reared virtually anywhere. Their natural habitat is open forest and wooded areas of the North American continent, but in Mexico they are raised from sea level to over 2,000 m altitude, from  rainforest to desert, and from near-temperate climates to the tropics.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&lt;&lt;I&gt;&gt; p159a.png The original distribution of the turkey and the occellated</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">BIOLOGY</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">The range of diet is broad. Turkeys eat greens, fruits, seeds, nuts,  grasses, berries, roots, insects (locusts, cicadas, crickets, and  grasshoppers, for example), worms, slugs, and snails.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Reproduction is generally seasonal and is stimulated by increasing  daylength. (A minimum daylength of 12 hours is required.) The birds  can reach sexual maturity at six months of age and may start breeding at  this time. Ten days after first mating, the hen searches out a nest and  commences laying. Industrial birds in temperate climates lay, on  average, 90 eggs a year. The nondescript type of turkey in the tropics  seldom lays more than 20 small eggs (weighing about 60 am) before  going broody.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">BEHAVIOR</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">Domestic turkeys walk rather than fly, and find almost all their food  on the ground. They can, however, fly short distances to avoid  predators.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The commercial birds have lost many abilities for survival in the wild;  they can no longer exist without human care. However, village types  can do well with little management.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Turkeys prefer to make their own nests but can be induced to lay in a  convenient spot if provided with nest boxes.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">USES</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">These birds are raised almost exclusively for meat. In many countries,  they are a treat for holidays, birthdays, and weddings. In their native  range of Mexico and Central America, the "unimproved" birds are  usually produced as a cash crop for market. They receive little care or  feed, and thus they are almost all profit - providing a significant income  supplement to many rural homes.  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">HUSBANDRY</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">The principles of turkey management (nutrition, housing, rearing' and prevention of disease, for example) are basically the same as those for other poultry.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">In Mexico, turkeys are usually kept under free-ranging conditions around houses and villages. Some shelter and kitchen scraps are occasionally provided. A number of them, however, are confined in backyards as protection from marauders and for shelter against rain and wind.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">One male can service up to 12 females. Roomy nests are needed. (As a rule, turkeys require three times the space occupied by chickens.) Most range turkeys are corralled when they begin to lay, so as to protect them from predators. Eggs may be gathered to prevent broodiness and thereby increase production. The eggs may be kept for several days (cool, but not refrigerated) if turned daily, and then may be placed under a chicken hen. (A setting chicken can be used this way to hatch up to nine eggs at a time.) Hatching takes 28 days.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">As in other birds, newly hatched turkeys (poults) must be kept warm during the first weeks of life. Until they begin foraging and have full access to pasture they are usually fed broken grain or fine mash, as well as finely chopped, tender green feed.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Although free-ranging turkeys are simple to raise, confined turkeys require more complex management. The birds need uncrowded, well ventilated conditions and should be on a wire or slatted floor to reduce parasitic infections. Any feeds recommended for chicks are suitable, but the protein content should be somewhat higher; that is, about 27 percent. They can be fed mixed grains, corn, and chopped legume hay. It may be necessary to provide vitamin supplements and antibiotics and take steps to prevent coccidiosis.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">"AN INCOMPARABLY FINER BIRD"</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">The turkey was domesticated in Mexico some time before the Conquest. It is the one and only important domestic animal of North American origin. When the Spanish arrived, they found barnyard turkeys in the possession of Indians in all parts of Mexico and even in Central America. However, the Aztecs and the Tarascans, originating in west-central Mexico, seemed to have achieved the highest development of turkey culture, and it is probable that turkeys were domesticated in the western highlands, perhaps in Michoacan. Wild turkeys of that region are morphologically very similar to the primitive domestic bronze type. Both the Aztecs and Tarascans kept great numbers of the birds, including even white ones. They paid royal tribute to their respective kings in turkeys, according to the Relacion de Michoacan. The Tarascan king fed turkeys to the hawks and eagles in his zoo. The economy of some highland tribes was based on the cultivation of corn and the raising of turkeys.</P>
+<P ALIGN="JUSTIFY">A. Starker Leopold</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">THE INDUSTRIAL TURKEY</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">The modern domesticated turkey is thought to be descended from two differing wild subspecies, one found in Mexico and Central America and the other in the United States. The southern type is small, whereas the U.S. native is larger and has a characteristic bronze plumage.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Mexican turkeys were exported to Europe soon after the Conquest, and spread rapidly. In the 17th century, some were returned to North America, where they interbred with the eastern subspecies of wild turkey, producing a heavier bird, which was then re-exported to Europe.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">These types underwent little change until this century, when the Englishman Jesse Throssel bred them for meat quality. In the 1920s, he brought his improved birds to Canada, where their large size and broad breasts quickly made them foundation breeding stock. Crossed with the narrow-breasted North American types, these heavily muscled meat birds quickly supplanted other varieties.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">About the same time, the U.S. Department of Agriculture began the scientific development of a smaller meat turkey derived from a more diverse genetic base. By the 1950s, the Beltsville Small Whites predominated in the home consumption market in the United States.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">ADVANTAGES</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">The birds are efficient and generally take care of themselves. They tolerate dry, hot, or cold climates and forage farther than chickens. They are large, fast growing, highly marketable, low in fat, and tasty. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">THE TURKEY'S TROPICAL COUSIN</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">The ocellated turkey (Agriocharis ocellata) occurs in Yucatan, Guatemala, and Belize. It is much like the common turkey in size, form, and behavior: however, unlike the common turkey, which in Mexico lives in the high mountain pine and oak forests, the ocellated turkey inhabits bushy, semiforested lowlands. This splendid bird lacks the kind of beard sported by the common turkey gobbler, is generally more metallic in appearance, and has brighter coppery colors. The chief character is a neck and head that are bare, blue, and profusely covered with coral-colored pimples. It also has a yellow-tipped protuberance growing on the crown between the eyes.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">This species is worthy of investigation by poultry researchers because it might prove to be domesticable. It was possibly domesticated by the Mayas, whose ruins often include appropriately sized stone enclosures whose soil has elevated levels of phosphorus and potassium. Even today, in the rural Peten area of Guatemala, ocellated turkeys are sometimes kept around houses as scavengers.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">LIMITATIONS</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">Young birds are readily affected by temperature changes and must be protected from the sun as well as from sudden chills, such as may occur at night. They are particularly susceptible to dampness, especially if associated with cold. One peculiarity is the turkey's aversion to any change in feeding routine or the nature of the food.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Young turkeys are susceptible to parasitic infestation as well as to the same type of bacterial and virus diseases as chickens (for example, fowlpox and coccidiosis). Blackhead, a devastating disease of young turkeys, is carried by a common parasitic nematode, and can be contracted from chickens. Medicines are available to prevent or treat most disease and pest problems.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">RESEARCH AND CONSERVATION NEEDS</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">Turkey development is almost nonexistent in the Third World (and much of the rest of the world, too). Although commercial turkeys are highly developed in some countries, little or no research has been conducted on the criollo turkey. Research on physiology, disease, and husbandry of the criollo turkey should be given high priority.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The need for conservation of genetic variability is perhaps more critical in this species than in almost any other domesticated animal. The unimproved types in Mexico should be collected and assessed, and a program to conserve the stocks should be initiated. An analysis should also be made of the traditional management and performance of these birds. In addition, the four or five recognized turkey subspecies should be evaluated for their potential as seed stock for Third World countries. </P>
+<P ALIGN="JUSTIFY"></P>
+<B><P>&lt;&lt;TOC3&gt;&gt; 13 Potential New Poultry</P>
+</B><P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&lt;&lt;I&gt;&gt; g016a.png FIGURE</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Several preceding chapters have discussed the possibilities of domesticating certain wild birds.l Here, briefly, are highlighted other wild species with qualities that might make them suitable for sustained production. It should be understood that their practical use in the long run is pure speculation; they are included here merely to guide those interested in exploring the farthest frontiers of livestock science.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Collectively, poultry have become the most useful of all livestock and the most widespread. Yet only a handful of species are employed. Of the 9,000 bird species, only a few (for instance, chickens, ducks, geese, muscovies, pigeons, and turkeys) have been domesticated for farm use. Strictly speaking, all birds are edible - at least none have poisonous flesh - so it seems illogical to conclude that these are the only likely candidates. Perhaps they are not even the best.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">At first sight there may seem to be little need for new species, but poultry meat is in ever increasing demand and there are many niches where the main species are stricken by disease, or are afflicted by heat, humidity, altitude problems, or other hazards. For these areas, a new species might become a vital future resource. Perhaps some could even become globally important. The modern guinea fowl, for example, is a relative newcomer as a worldwide resource (see page 120).</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The birds now used as poultry were domesticated centuries ago by people unaware of behavior modification, nutrition, genetics, microbiology, disease control, and the other basics of domestication. Today we can tame species that they couldn't. In particular, the new understanding of "imprinting" may make the domestication of birds easier today than ever before. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">In this highly speculative concept, the birds described on the following pages are worth considering. They all eat vegetation and tend to live in flocks, which makes them likely to be easy to feed and to keep in crowded conditions. Most are sedentary, nonmigratory, and poor fliers. All but three (tinamous, sand grouse, and trumpeters) are gallinaceous.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Gallinaceous birds are already the most important to people. The best known are chickens, turkeys, quail, and guinea fowl. But there are about 240 other species. Most are chickenlike: heavy bodied with short, rounded wings, and adapted for life on the ground. Although some are solitary, many are sociable. Basically vegetarian, they also eat insects, worms, and other invertebrates. The young birds are extremely precocious, walking and feeding within hours of hatching. All of these are advantageous traits for domestication.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Game birds are also emphasized here. Many today are considered gourmet delights, and this should give them a head start in the marketplace. Indeed, some are already being raised in a small way on game farms and are at least partly on the way to domestication.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">CHACHALACAS</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">These brownish birds (Ortalis vetula and nine other species) are found throughout Central and South America, and, given research, could possibly be raised on a large scale. A sort of "tropical chicken," they tame easily, live together in dense populations, and protect their chicks extremely well. They commonly scavenge around houses and people often put out scraps to feed them.2 The chicks are easily hatched, grow fast, and can be fed standard chicken rations.3</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">There is already considerable demand for these birds. Everywhere they are found, they are prized as food. In some areas they constitute the single most important game species, and are heavily hunted to supply local communities. Although they have less meat than a chicken, it is tastier and darker.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Chachalacas are very adaptable. They occur mainly around forest edges and thrive in the thickets that appear after tropical forests have been felled. They do well close to humans, and their populations are not threatened, despite much hunting. Indeed, they seem well adapted to existence around villages and towns. Although not strong fliers, they are one of the few tree-roosting gallinaceous species. Primarily fruit eaters, they also consume tender leaves, twigs, and buds, and they scratch up the ground, presumably for insects.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Although excitable and noisy, chachalacas become remarkably tame when fed by people. In a few cases, full domestication has almost been reached. Farmers like to have chachalacas around and have even used them to guard domestic chickens. These very raucous and fearless birds will take on all potential threats, even weasels.4</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">GUANS</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">Close relatives of the chachalacas, guans5 are glossy black birds about the size of small geese. They are highly gregarious and perhaps could be raised in larger numbers. They commonly live around houses, farms, and settlements in their native region of tropical America.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Unlike most game birds, guans are chiefly tree dwellers, but they also feed on the ground. Some 12 species are known. All are relentlessly hunted for food and sport - their tameness and inability to fly far or fast making them easy targets. The rapid destruction of tropical forests threatens their populations in some parts of their range. Conservation projects and specific plans of action are being proposed for the most threatened species. Perhaps for the other species, game-ranching projects or even outright domestication might provide just the right incentive for their protection and multiplication.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">CURASSOWS</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">Curassows are also relatives of guans and chachalacas, but they are even larger - up to 1 m tall and 5 kg in weight. At least seven species are found over the vast area from northern Mexico to southern South America.6 Among them are Latin America's finest game birds.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">It might be possible to produce curassows in organized farming or ranching. They are commonly called "tropical turkeys" because they look like and run like turkeys. Indeed, Latin Americans normally refer to them as "pavos" or "pavones," as if they were the real thing. Their plumage ranges from deep blue to black, invariably with a purple gloss, and all have rather curly crests on their heads. They are not good fliers and spend most of their time on the ground.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Curassows are increasingly hunted; their tropical forest habitat is shrinking, and the subsequent loss of populations is a calamity. They are special targets, not only because they are large but also because their light-colored flesh makes exceptional eating.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">There is hope that these large wild fowls can be raised and managed in organized programs. Even now, people commonly keep them around their farms and villages. For example, on a number of Venezuelan ranches, yellow-raped curassows can be seen wandering around the cattle yards as if they were chickens.7</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">FOREST BIRD RANCHING</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">This report has intentionally focused on intensive farming - the type where people bring feed to animals in captivity. However, where this normal type of farming is of marginal value, `'ranching'' free-ranging birds may often be a more effective option. In this, the farmer simply monitors and improves the condition of the range and devises methods to harvest the birds on a sustainable basis. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">"Bird ranching" may today have outstanding merit, particularly in tropical rainforests. Hence, in this chapter we emphasize birds of the jungle. These might help make standing rainforests profitable producers of income, and thereby provide economic incentives to stop felling trees for cow pastures. Indeed, forest birds might become part of a whole new "salvation farming'' that makes forests more valuable than fields. It is a technique that may contribute to preserving both bird life and its vitally valuable habitat.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">MEGAPODES</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">Megapodes (family Megapodiidae) include some of the world's most interesting birds. They have temperature-sensitive beaks and employ nature's own heat sources as incubators. The best-known species build piles of leaves and use the heat of decomposition to incubate their eggs. The species of Papua New Guinea and Indonesia, however, take advantage of sun-warmed sand or even geothermal activity.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">People have long revered these birds. Aborigines in Australia, Melanesians in New Guinea, and many Micronesians all protect the bizarre nesting sites, and "farm" them for eggs. Local people consider the large eggs special delicacies, and sometimes the egg-laying sites are owned and exploited for generations without a single bird being killed for food.8</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Programs that provide sustainable supplies of eggs have been established in Papua New Guinea. One is near Mt. Tovarvar, a simmering volcano on the island of New Britain. Here, megapodes gather in large numbers to lay eggs in the hot sands. They dig until they locate sand that is exactly 32.7&Yacute;C, before laying their huge (more than 10 cm long and 6 cm wide) pink eggs. Each year the villagers dig up some 2O,OOO eggs, which are an important source of protein and cash income. The government now regulates the harvest in a way that protects the bird population while supplying a nourishing food.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Megapodes are found in only a few parts of the world, but projects such as those in Papua New Guinea provide hope and guidance not only for the sustainable "ranching" of megapodes, but also for other species elsewhere. Many wild birds yield locally important products down, colored feathers, eggs, meat, and skins, and they make excellent songbirds and pets, for example. Their management on a sustainable basis may in certain cases be the key to turning local people into the most dedicated conservationists of all.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">PARTRIDGES AND FRANCOLINS</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">Partridges include many small game birds native to the Old World. They are robust, precocious, and larger than quails. Some lay many eggs - the European partridge, for example, lays up to 26 in a clutch. Newly hatched chicks are soon able to feed themselves and can fly within a few weeks, sometimes even within the first few days.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Species that may make useful poultry include:</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">- The European (or gray) partridge (Perdix perdix); </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">- The rock partridge (Alectoris), bantamlike birds of Africa; and</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">- The chukar (A. graeca). </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">A native of the vast area from southeastern Europe to India and Manchuria, the chukar is stocked as a game bird in many countries. It is now produced routinely under poultrylike husbandry in many parts of the United States, not only for hunting clubs, but also for expensive food markets. The birds are generally raised on turkey rations and dress out at about 500 g after 18 weeks. They sell for more than broiler chickens and are a profitable sideline for increasing numbers of poultry farmers.9</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">A group of closely related birds are the francolins (genus Francolinus), of which there are 34 species in Africa and 5 in West and South Asia. These adaptable birds are sturdy, live in a variety of habitats, and tend to be rather noisy. Basically, they are partridges with leg spurs. They are highly regarded as a food source and are hunted and trapped wherever they are found.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Francolins are much like quail, but are several times larger. Arabs introduced one of the most beautiful species (Francolinus francolinus) into southern Spain, Sicily, and Greece during the Middle Ages. However, it was hunted so heavily that it soon became extinct in Europe. More recently, francolins have been introduced to the Soviet Union.'&Yacute;</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Francolins inhabit steppes, savannas, primeval forests, and mountains. They thrive in cultivated land with much cover. The clutch consists of 6-8 hard, thick-shelled eggs. In recent times at least one program to domesticate them for food has been started in Africa.11</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">MALAYSIA'S MOBILE MOUSETRAP</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">Although the report emphasizes microlivestock as food suppliers, it should be realized that small animals - even wild ones - can have other important uses as welt The following interesting example, with possible worldwide implications, comes from recent experiences in Malaysia. *</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Certain rodents are major pests on farms and plantations. Now, however, Malaysian zoologists are finding that owls, particularly barn owls (Tyto alba), can help control them. An owl pair and its chicks annually consume 1,500 or more rodents. This is not new knowledge; indeed, on farms throughout the world the barn owl has always been a welcome guest. What is new is that Malaysians are showing how outstandingly effective this process is, and they have initiated major projects to attract and maintain these feathered friends. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Barn owls are found in many parts of the world, but were formerly almost unknown in Peninsular Malaysia. In 1969, however, a pair began nesting in an oil-palm plantation in Johore State. Since then, these birds have steadily increased in numbers and have spread throughout most of the peninsula. Today, the population is increasing remarkably quickly as more and more managers erect nest boxes for the owls to live in.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The owls are proving to be a good way to remove rats and are notably effective in plantations of oil palm. They perch on fronds and fly under and between the rows of trees. A cost of $1 - $2 per hectare per year is all that is required to install nest boxes, a negligible outlay for the control of such a serious and expensive problem.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">It is believed that the barn owls hunt mainly in plantations and other agricultural areas and not in the rainforest. Barn owls are, after all primarily adapted to open spaces and not dense forest.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Perhaps this experience can be replicated and adopted in other locations and with other crops. Grain crops - notably rice - are particularly prone to the ravages of rodents, and one trial has commenced in Selangor State in a rice area. The concept of using owls for rodent control is also catching on in the United States. Indeed owl nest boxes are being erected in Central Park in the heart of New York City.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">PHEASANTS</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">One pheasant, the red junglefowl, gave the world the chicken (see page 86). The other 48 species may have some potential, too. These are rarely seen forest birds; all but one are confined to Asia.13 Because they are prolific they can sustain heavy predation, and many species, notably the ring-necked pheasant (Phasianus colchicus), are constantly hunted.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">People in several countries have learned to exploit pheasants on farms and estates. As a result, there is a vast amount of information on how to rear and manage these birds. So far, however, it has been applied only to sport hunting in wealthy societies; the potential of raising pheasants for the mass market should now be seriously addressed.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The most dramatic-looking pheasant, the peacock (Pavo cristatus), is raised as a poultry species in Vietnam. The meat of the young birds is considered outstanding. In fine restaurants in New York, a peacock dinner is reputed to cost $150. Common peafowls are considered sacred in many parts of India, where they have become so tame that they are essentially domesticated. They also control snakes.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">QUAIL</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">Domestic quail have been previously described (page 146)J but dozens of wild quail species and subspecies occupy many different habitats and ecological niches in almost all parts of the world. Out of all this genetic wealth only one species - the Japanese quail - is widely used. Yet many other species seem easy to raise, becoming exceedingly tame after about the sixth generation.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The management and even perhaps intensive production of these various local quails might provide long-term benefits for many developing nations. Quail meat ranks among the finest.14 Some of these lesser-studied birds are more meaty than the Japanese quail or have other possibly useful traits. Much is known about rearing a few of them because they are used in sport hunting or laboratory research. The possibility of domestication, therefore, is not farfetched.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Particular quail that might be considered for domestication are the lesser-known subspecies of Coturnix coturnix. These subspecies are found in various places, including the following:</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">- Europe (C. c. coturnix breeds in the area ranging from northern Russia to North Africa and from the British Isles to Siberia. In winter it migrates to tropical Africa, Asia, and southern India.)</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">- The Azores (C. c. conturbans) </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">- The Azores, Madeira, and the Canary Islands (C. c. confisa) </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">- Cape Verde Islands (C. c. inopinata) </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">- East Africa (C. c. erlangeri) </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">- Tropical Africa, southern Africa, Madagascar, and Mauritius (C. c. africana) </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">- Japan (C. c. japonica, the most probable ancestor of the domesticated quail)</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">- China (C. c. ussuriensis, a possible ancestor of the domesticated Japanese quail)</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">TINAMOUS</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">Tinamous are quail-like birds of Central and South America's forests and grasslands. They are, however, much larger than quail and resemble small chickens, with plump bodies and no visible tail. There are more than 40 species, and all are much sought for food because their meat is tender and flavorful. The breast is surprisingly large, and its flesh is pale and translucent. One species, the great tinamou (Tinamus major), has been called "the most perfect of birds for culinary purposes." Frozen tinamous from Argentina were formerly sold in the United States under the name "South American quail."</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Tinamous are found mainly in tropical areas, but are also widely distributed in Argentina and Chile. They dwell in varied habitats: rainforests, thickets, bushlands, savannas, and grasslands up to 5,000 m altitude in the Andes. Some species sleep in trees, others on the ground. They spend their days creeping about in heavy cover, flying only when forced.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">At least some species tame readily. Indeed, during the nesting period males become so tractable that they can be picked up off the nest. At the turn of the century, many tinamous were raised as game birds in France, England, Germany, and Hungary. However, for reasons unknown, subsequent attempts to settle them in Europe have failed. Tinamous have been raised in Canada without undue difficulty; they showed little or no stress under captivity and there were few losses.15</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Tinamous may also prove suitable for egg production. They lay clutches of 16-20 spectacular-looking shiny eggs that seem to be made of sky-blue and bright-green ceramic.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">SAND GROUSE</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">Sand grouse (mainly Pterocles species) are highly adapted to life in arid regions - desert, dry grasslands, arid savanna, and bushveld. Their entire body (including most of the bill and feet) is covered with dense down, which in the desert insulates them from the burning heat of midday and the freezing cold of night. It also protects the nostrils against blowing sand and dust.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">These pigeonlike birds are found throughout the drier regions of Africa and Asia - for instance, the Sahara, Kalahari, Namib, Arabian, and Thar deserts. They live mainly on small seeds, and sometimes flocks of thousands may be seen at waterholes, flying in for a drink from up to 80 km away. For peoples of the driest spots on earth, these birds may make a useful food species: for one thing, they are not endangered. Indeed, they are proliferating as drought and overgrazing is increasing the amount of dry, desolate rangeland that they prefer. The bore holes provided for livestock have both boosted their populations and afforded a place where these wide-ranging birds can be easily captured. When nesting, sand grouse are highly vulnerable to foxes, jackals, mongooses, and other predators. Protection of the nesting sites may be the key to maintaining their populations if harvesting schemes are introduced.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">TRUMPETERS</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">Trumpeters (Psophia species) might prove to be a useful species for sustainable production within tropical forests. As "tree poultry," these relatives of cranes could help provide meat without destroying the trees, as is now done to raise cattle.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">These chicken-sized birds inhabit South America's jungles.16 They are nonmigrating, ground-dwelling, and are often kept as pets, notably by Amerindians. Under human protection, trumpeters become very tame. They recognize strangers and challenge them with a loud cackle. 17 </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Fully adapted to the forest environment, they can run fast, but fly poorly. In the wild, this makes them easy targets for hunters. Because of this and the fact that they make excellent eating, they are approaching extinction in some areas.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">No attempts have been made to rear these birds in numbers, but this should be tried. They feed mainly on plant materials, particularly berries of all kinds. They also relish grasshoppers, spiders, and centipedes, and are particularly fond of termites.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Trumpeters require trees; they completely avoid cultivated land. Thus, as the destruction of forests in South America continues, their habitat is shrinking. Although their existence is not as yet threatened, the long-term prognosis is bleak. If managed in "forest-ranching" programs, however, they might be saved from extinction and thriving populations built up. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Interest in rabbits continues to increase. It is now widely recognized that the raising of small animals in developing countries has great potential as a means of improving human nutrition and economic security. The famines in Africa, Latin America, and Southeast Asia starkly illuminate the need for maximum efficiency in food production to maintain the quality of human life. Rabbit raising contributes to meeting these needs.</P>
+<P ALIGN="JUSTIFY">P.R. Cheeke, N.M. Patton, S.D. Lukefahr, and J.I. McNitt Rabbit Production </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Rabbits are especially well adapted to backyard rearing systems in which capital and fodder resources are usually limiting factors in animal production. When rabbits are reared according to the techniques appropriate to the environment they can do much to improve the family diet of many of the most needy rural families, while at the same time supplying them with a source of income. With more advanced technology rabbit production can also help to supply big city meat markets.</P>
+<P ALIGN="JUSTIFY">Food and Agriculture Organization The Rabbit: Husbandry, Health, and Production </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&lt;&lt;I&gt;&gt; g017a.png FIGURE</P>
+<P ALIGN="JUSTIFY"></P>
+<B><P ALIGN="CENTER">&lt;&lt;TOC2&gt;&gt; Part III : Rabbits</P>
+</B><P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">Contrary to popular opinion, the domestic rabbit is a substantial part of the world's meat supply. Annual production of rabbit meat is estimated to be one million metric tons, and the total number of rabbits is approximately 708 million.' However, rabbits are now intensively raised for food only in temperate, mostly industrialized, nations. France, Italy, and Spain, for example, have long consumed rabbit meat; West German production was 20,000 tons each year; Hungary raises rabbits in large numbers (two of its commercial rabbitries have more than 10,000 does each); and the United States raises almost 8.5 million rabbits each year for consumption in homes and restaurants.2</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">In most developing countries, on the other hand, rabbits are not well known - at least compared with other livestock. But they have great promise there, and in recent years there has been a dramatic increase in interest. For those developing countries where information is available, rabbit meat production almost doubled between 1966 and 1980. For instance, several African countries - among them Ghana, Kenya, Malawi, Mauritius, Mozambique, Nigeria, Sudan, Tanzania, Togo, and Zambia - now have national rabbit-raising programs. A number of Asian countries - such as the Philippines, Indonesia, India, and Vietnam - are also encouraging rabbit farming. And some Latin American countries - Mexico, Costa Rica, and El Salvador, for instance - are actively promoting rabbits for subsistence farmers.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Ghana is also extensively promoting rabbit farming. Although able to produce all the cereals its population needs, it cannot produce enough meat to satisfy demand. In response, the government organized "Operation Feed Yourself." The National Rabbit Project was created </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Hares</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">The common hare (Lepus europus) has not been domesticated, but it is nevertheless a major cash crop of several countries. In Argentina, for example, there is a booming, million-dollar enterprise that exports hundreds of thousands of carcasses, mainly to Germany where they are sold as game meat. For Argentine campesinos, many of whom have few sources of livelihood, trapping hares provides a vital income. In New Zealand, too, hare has become an export item.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">A closely related species (Lepus capensis) is native to Africa, and perhaps could be "ranched in the same fashion.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Rainforest Rabbit</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">The forest rabbit, or tapeti (Sylvilagus brasiliensis), is commonly eaten in its native habitat, which extends from southern Mexico to southern Brazil. It occurs in various hot and humid areas of Central and South America and probably within the Amazon Basin itself. Thus, this creature seems a possible candidate for a "tropical rabbit" that can be raised under sweltering conditions, perhaps even in rainforest regions. Although it seems to be heat resistant, it has an especially fine fur.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Little is now known about the tapeti. It is rather secretive and its natural history and even its range are still uncertain. However, its populations appear stable and it is not threatened with extinction. It produces litters of 1 - 5 young after a 44-day gestation, and may bear 4 litters a year. This may seem a lot, but compared with other wild rabbits, the litter size is small and the gestation period long. under this program to provide farmers with breeding stock and practical information on rearing rabbits. (To qualify for the purchase of new breeding stock, would-be rabbit raisers are required to take an intensive three-day course in rabbit husbandry, which is provided at no charge.) With both official and popular support, the rabbit's potential for Ghana has been enhanced through media campaigns complete with radio jingles (examples: "Get the bunny money!" "Grow rabbits - grow children." "Get into the rabbit habit!"), television spots, and large posters. Already, rabbit breeding is included in school curricula and rabbit meat is available in school lunches.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Other countries have mounted similar campaigns. In Mexico, for instance, teachers raise rabbits in rural schools as a way of training students; scores of government officials have taken to breeding rabbits in their homes; and several army units are raising rabbits as mess-hall substitutes for costly beef, pork, and chicken. In Nigeria, farmers can now acquire rabbits from 18 government rabbit-breeding centers, which distribute thousands of animals each year. In Costa Rica, the government has similarly established a series of breeding, distribution, and rabbit-farming training centers. And in El Salvador, the technology of rabbit production is being transferred to farmers via the army.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Although rabbits are ideal microlivestock in a general sense, rabbit rearing has many problems and limitations. Poor management is a common difficulty. Unlike the traditional method of keeping scavenger animals, rabbits have to be contained and cannot be left to find their own food. Raising rabbits requires more skills, more time, and much more effort than raising barnyard chickens or other familiar scavengers.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">For all that, rabbits produce more food than scavenging animals; they are less likely to damage crops because they are kept confined; they live exclusively on forage, which tends to grow vigorously in tropical zones; and they generally produce a more valuable product. The rabbit's potential is far from exploited, and rabbit farming will have to increase enormously before its promise for the small farms of the world is realized.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">There is, however, an increasing concern over a recent outbreak of an exceptionally virulent viral rabbit disease - hemorrhagic tracheopneumonis, which attacks the lungs and lung tissue, killing 48 hours after the onset of symptoms. The virus, which has ravaged the animals in parts of Asia and Europe, was identified in China five years ago in Angora rabbits imported from Germany. It spread to Korea in 1986, and in early 1988 moved through southern and eastern Europe and spread as far as Egypt. It has also been identified in Mexico. Vaccination may become a future prerequisite of rabbit rearing in many countries. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">FAST FOOD</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">The order Lagomorpha includes more than 60 small quickmaturing, and rapidly reproducing species. It seems illogical to think that only one is useful as microlivestock. In principle, any rabbit, hare, or pike could be raised in captivity. All are clean, fast growing and rapid breeding. They are opportunistic feeders and can digest fibrous vegetation. Their meat tastes better than chicken and does not carry the stigma of rodent. The animals are small inoffensive, efficient at foraging, and generally tolerant of difficult environments. In theory, at least, they could be raised on vegetation not used by people or by many domesticated livestock.</P>
+<P ALIGN="JUSTIFY">Species worthy of exploratory research include the following.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<B><P>&lt;&lt;TOC3&gt;&gt; 14 Domestic Rabbit</P>
+</B><P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&lt;&lt;I&gt;&gt; g018a.png FIGURE</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The domestic rabbit (Oryctolagus cuniculus)1 is suited to small-scale production and backyard farming. It is easily maintained, requires scant space, makes minimal demands on the family budget, and thrives on plant materials that are usually disdained by humans. It utilizes forage efficiently. even coarse vegetation that is high in fiber, and under ideal conditions it can grow so rapidly that its rate is only slightly lower than that of broiler chickens.2</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The rabbit's capacity for reproduction is legendary. In theory, a single male and four females can produce as many as 3,000 offspring a year, representing some 1,450 kg of meat - as much as an average sized cow.3 The meat is pink, delicately flavored, and is usually considered a premium product that provides variety in the diet. It has more protein and less fat and calories per gram than beef, pork, lamb, or chicken.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Some breeds are raised for their wool. The long-haired Angora, for instance, yields a luxury fiber that makes a soft, lustrous fabric. It sells at high prices and makes these animals very valuable.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Rabbit pelts also bring cash. They are used in fur coats and other luxury garments. In addition, rabbit feet and tails are used in good luck charms and many curios.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">AREA OF POTENTIAL USE</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">Worldwide.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">APPEARANCE AND SIZE</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">Rabbits are well known for their long ears, fluffy tails, and long hind legs. Many commercial breeds are white, although colored types are sometimes chosen because of special qualities in their meat or pelts.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">There are many breeds and much genetic diversity within and between breeds. (Almost 160 varieties are recognized by the American Rabbit Breeders Association.) However, in both North America and Europe, the New Zealand White has traditionally displaced most other breeds for commercial meat production. This medium-weight breed bears large litters, is a good milk producer, and has good mothering ability. It reproduces best under intensive farming and, among purebreds, yields the most meat. A full-grown New Zealand White weighs 4-5 kg, giving about 2 kg of meat at 8-10 weeks of age. Large breeds include the Flemish Giant or the Checkered Giant, which weigh more than 6 kg at maturity.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Hybrids are rapidly replacing purebreds in Europe for commercial production. Specific crosses of breeds have been shown experimentally to be more productive overall compared with purebred New Zealand Whites.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Different meat breeds are preferred in various countries. For example, in Ghana the most popular are Flemish Giants, New Zealand Whites, Yellow Silvers, and Checkered Giants; in Tanzania and Nigeria, New Zealand Whites and Dutch are preferred; in China, Chinchillas and Japanese Large Whites are the most widely consumed. Some smaller breeds - for instance, the Polish - are also valuable for husbandry.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Some Third World strains have already evolved. They show high tolerance to local conditions (for example, the Baladi - the main strain of the Sudan and the Near East - and the Criollo of Mexico). The Baladi has a small body and relatively low production, but it is hardy and tolerates harsh conditions.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Specialized breeds have been developed for wool, fur, and laboratory research. The Angora wool breed has already been mentioned. The Rex breed produces a high-quality pelt used in furs.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">DISTRIBUTION</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">The wild ancestor of the domestic rabbit was originally restricted to Spain and Portugal. Today, its descendants are found worldwide.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">STATUS</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">Plentiful.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">HABITAT AND ENVIRONMENT</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">Domestic rabbits are best suited to temperate climates, but they do well in tropical and subtropical conditions if hutches are constructed and sited to take advantage of shade and cooling breezes. Ventilation is important (but care must be taken to avoid direct exposure to cold drafts). Prolonged exposure to temperatures higher than 30&Yacute;C reduces both fertility and growth. Apparently, all breeds tolerate heat equally well. However, heat is shed through the ears, and the longer the ear, the more heat a rabbit will tolerate. Lop-eared varieties withstand heat poorly.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">BIOLOGY</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">Rabbits eat fibrous vegetation. In addition to normal feces, they produce special droppings called cecotropes. Softer and smaller than the regular fecal pellets, they are excreted in clusters and are swallowed as soon as they are eliminated. Cecotropes are rich in bacterial protein, and this double digestion (coprophagy) enables the animals to utilize the fermentation products formed in the cecum. This process is rather like that of ruminants, and rabbits are sometimes called pseudoruminants.4</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Breeding begins at 4-6 months of age and may continue up to age 4, occasionally to age 6. Gestation takes 28-32 days. Females can conceive within 24 hours after giving birth and can produce a second litter merely 4 weeks later. With good feed and early rebreeding, 9 or more litters a year are possible. (Such a rate is only achievable under exceptional management, however.) Litter size depends on breed and body weight. Small breeds average 4 young per litter; large breeds 810. Births occur at any time of the year, but production slackens when the weather is exceptionally cold or hot, when feed is scarce, or when days are short. Extremes of heat or cold can also affect the survival of the young.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Rabbits raised under subsistence conditions are likely to produce 4 or 5 litters a year, with an average of 5-8 young per litter' depending on management and feed quality.5 Annual production of about 20 weaned offspring per female per year under tropical and subtropical conditions is common. The young remain in the nest until they are 2-3 weeks old. Their eyes open at approximately 10 days of age. About 4 months are required to produce a 2-kg market rabbit under subsistence conditions. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">BEHAVIOR</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">Rabbits that receive human handling are very gentle and can be trained to live inside people's houses and even use a "litter box."</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">USES</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">Rabbits are multipurpose animals yielding the following products:</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">- Meat. Delicious hot or cold, fancy or plain, it can be breaded and fried, broiled, baked, or barbecued.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">- Wool. The fineness of rabbit hair is an asset in the production of wool, which is the plucked or shaved hair of the long-haired Angora breed. It is usually mixed with fine Merino sheep wool to give more substance and to improve its wearing quality. An average Angora rabbit produces about 850 g of wool each year. (Some specimens produce as much as 1,000 g.)</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">- Fur. The fur is dense.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">- Leather or vellum. Rabbit hide has the tension and strength required for tiny drive-belts in tape recorders and other delicate machines.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">- Fertilizer. Rabbit manure often contains high proportions of nitrogen, phosphorus, and potash, and it comes in convenient drypellet form.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">- Tourist charms. In many societies, rabbits are connected with good luck. Feet and tails are used for car decorations, key chains, charms, and mementos that appeal to tourists.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Rabbits are also used in biochemical and physiological research.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">HUSBANDRY</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">Rabbits can be housed in hutches ranging from sophisticated commercial cages to simple packing crates with a few ventilation holes and rough troughs for food and water. In all cases, watertight roofing is essential. A floor space of only 0.25 m&Yacute; is sufficient for one rabbit, but about 1 m&Yacute; is recommended for a female and her young.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Starting small-scale rabbit production is generally inexpensive. An almost infinite variety of backyard feeding and drinking equipment can be made from various scrap items, such as old bottles. The main criteria are that cleaning should be easy and spillage minimized.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">In practice, diets can be based largely on herbage: grass, leaves, legumes, crop residues, and kitchen scraps. However, the diet must be wholesome, and caged rabbits fed on forage usually need some grain or agricultural by-products (rice bran, for instance) as a dietary supplement. Supplementation is particularly important for newborns and lactating females, whose diet must contain about 16 percent protein and at least 18 percent fiber. When "noncommercial" feeds are used, salt must be added to prevent salt deficiency.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Because of higher protein content, legumes (for instance, alfalfa, cowpea, vetch, or pea) are better than grass. Alfalfa is particularly valuable, and in the Sudan and Mozambique it is already grown extensively for feeding rabbits. On diets consisting of alfalfa and rye grass, weaned New Zealand Whites have demonstrated growth rates of 38-39 g per day in animals weighing up to 2 kg.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">ADVANTAGES</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">Rabbits, as mentioned, can utilize almost any type of edible vegetation. Also, despite their diminutive size, they can collectively produce as much meat per unit of forage as large livestock, or even more (see page 183).6</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">There is much genetic diversity. Differences in growth rate, fertility, maternal ability, milk production, disease resistance, heat resistance, and other features have been noted. This is useful, since a wide genetic base enhances the likelihood of success of selection programs.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Rabbits are easy to handle and can be raised under primitive conditions. They require little financial investment and their husbandry is easily accomplished in the home by women and children.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The animal's rapid reproduction is a big advantage.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">LIMITATIONS</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">Tropical conditions produce special problems. There, rabbits must be protected from heat and rain. Stress brought on by high temperatures, high humidity, and wet conditions can lead to respiratory disorders and even sudden death.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Most diseases are caused by poor management. Dirty or wet cages lead to diarrhea, sores, mites, and ringworm, all of which can cause serious losses. Enteritis (diarrhea) often kills 20 percent or more of all rabbits before they attain market age and weight. A major disease problem in most countries is coccidiosis, which is particularly harmful to young rabbits. Again, damp and unsanitary conditions increase the susceptibility; better management can control it. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">In some countries - notably Australia and New Zealand - escaping rabbits have become a serious menace and have destroyed crops and grazing lands. Because of this threat, it is illegal to import rabbits into some countries.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">At present, many people are unaccustomed to eating rabbit. Indeed, where commercial ventures have been established in areas with an otherwise plentiful meat supply, there have been financial failures. However, where rabbit meat is familiar, there is usually great demand for it. Also, in poorer areas where animal protein is in short supply, the tasty pink meat is widely appreciated.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">HOW RABBITS WERE DOMESTICATED</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">For 30 or 40 million years the wild species Oryctolagus Cuniculus lived only in the area that today is Spain. Caves there contain Stone Age drawings of it. Phoenician traders landing on the Iberian Peninsula in about 1100 B.C. found huge numbers of these wild rabbits. The little animals were unknown to them and they mistook them for the hyraxes they had seen in Africa. (Although small and rabbitlike, the hyrax is actually related to elephants.) Since the Semitic name for hyrax was shaphan ("one who hides"), the Phoenicians named the peninsula l-shepan-im, from which the Latin name Hispania developed. Thus, "Spain" actually means "island of hyraxes," even though these African animals have never occurred there.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Given the rabbit's reproductive powers and adaptability it is surprising that it hadn't spread beyond Spain, but dense forests covered most of Europe after the last Ice Age. The rabbit, which is suited to open country, only spread rapidly after man had cleared most of the trees. Even then, the natural spread was slowed by the Pyrenees mountains blocking the way into the rest of Europe.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Ancient Romans became acquainted with rabbits after they invaded Spain, and they eagerly added wild rabbit meat to their banquets. The meat was so popular that around 1 A.D. Roman voyagers released a pair of rabbits onto the Balearic Islands. In time, these produced so many offspring that the islanders had to appeal to the Roman emperor for help. They even asked to be moved to another country if the emperor could not get rid of the plague of rabbits!</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Eventually, Romans in Italy, France, and other parts of the European mainland began raising rabbits for meat. They kept them in special cages called leporaria. Their rabbits were probably not truly domesticated; instead they were netted in the wild and caged for fattening before being prepared for the table. The Romans had little incentive to domesticate an animal that could be so easily captured.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Tne rabbit was the last farm animal to be domesticated. It seems likely that this did not begin until the Christian era when monks in French monasteries began taming rabbits. In those days, rabbit embryos and newborn young were considered delicacies, called "laurices." In 600 A.D. the Pope declared that laurices were "not meatp," and permitted them to be eaten during fasts and in monasteries of strict discipline where meat was forbidden. Within a few years, the animal was domesticated, </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">RESEARCH AND CONSERVATION NEEDS</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">Government-sponsored rabbit-research stations and programs are found in France, Germany, Italy, Spain, the United States, and the United Kingdom.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Rabbit husbandry is well known, but much basic research is needed; for example, specific nutrient requirements, breed comparisons, disease control, reproductive management, and efficient housing and equipment. There is a particular need to reduce the labor required for feeding, breeding, caging, and cleaning.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">With the increasing number of rabbit programs in Africa, Asia, and Latin America, there is a need to share information and ideas among the various countries. The exchange of experiences with rabbit breeding, health and nutrition, and the practical experiences and field studies could be of great value.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Further research in rabbit nutrition is necessary to identify nutrient requirements more precisely. Moreover, links between nutrition and disease should be clarified.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Further research into the cause and prevention of enteritis is needed. (At present, this condition is prevented by maintaining a fiber level in the diet of at least 18 percent and keeping the energy level relatively low.)</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Legume shrubs could be an answer to the feed problems in the dry season. Deep-rooted shrubby legumes, such as gliricidia or leucaena, remain green well into the dry season and have high protein contents. Rabbits find the leaves of leucaena palatable (see companion report Leucaena: Promising Forage and Tree Crop for the Tropics. National Academy Press. Washington, D.C. 1984), and they are fairly resistant to mimosine (a sometimes toxic amino acid found in leucaena foliage). More research on this promising approach is needed.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">As noted earlier (page 181), a killer virus has recently appeared. Studies into its epidemiology and control are most important. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Outsiders who hope to improve conditions in underdeveloped areas, sometimes . . . introduce new food avoidances to the communities they came to help [if outsiders] show repugnance toward consuming goats, . . . rats, . . . crows, insects, intestines and blood, then the people they are educating may likewise give up those . . . foods and lose valuable proteins.</P>
+<P ALIGN="JUSTIFY">Calvin W. Schwabe</P>
+<P ALIGN="JUSTIFY">Unmentionable Cuisine</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">You can count on the fingers of one hand the domestic animals that produce virtually all of mankind's meat and milk - a selection made more than 10,000 years ago by our Neolithic ancestors. Yet the earth teems with thousands of species of animals; why limit ourselves to cattle, pigs, goats, and sheep? Given the world's shortages of energy and water and arable land, why not try to domesticate wild animals? The effort would save many species from extinction, provide the world with more food, and introduce gentle farming to fragile environments.</P>
+<P ALIGN="JUSTIFY">N.D. Vietmeyer</P>
+<P ALIGN="JUSTIFY"> </P>
+<P ALIGN="JUSTIFY">&lt;&lt;I&gt;&gt; g019a.png FIGURE</P>
+<P ALIGN="JUSTIFY"></P>
+<B><P ALIGN="CENTER">&lt;&lt;TOC2&gt;&gt; Part IV : Rodents</P>
+</B><P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">Rodents are the world's most widespread, adaptable, and prolific group of mammals. They reproduce well, grow fast, learn quickly, and adapt to a wide variety of local conditions. Many convert vegetation into meat efficiently, digesting some fiber, even though their stomach, like man's, is a simple one.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">It seems probable, therefore, that some species would make suitable microlivestock - a notion supported by the previous domestication of the guinea pig, laboratory rat and mouse, gerbil, and hamster. Indeed, "ranching" rodents might be an effective way to increase food supplies in remote areas. It could also be a mechanism to ensure the survival of rare rodents whose natural habitats are being rapidly destroyed.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">RODENTS AS FOOD</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">Rodents are already common foods in many countries and are valued items of commerce. It has been estimated that 42 of 383 cultures eat rodents.! But the fact that they are a major meat source is almost unrecognized. This is due in part to cultural misunderstanding. Rodents suitable for human food or other products do not live in filth, like common rats. They are clean and vegetarian. Like rabbits, they eat grass and grains.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">In some regions of the world, cooked rodent meat is regarded as the epitome of dining. In many countries, local rodent species are the most eagerly sought meats. City markets in different parts of Latin America carry guinea pig, pace, capybara, and vizcacha. Markets in Asia may carry rice rats, cloud rats, and bandicoot rats. Those of rural Africa are filled with "bushmeats" - usually including grasscutters, giant rats, and several other rodent species. These are often preferred to the meat of domestic stock and fetch higher prices than beef. And the amounts of rodent bushmeat available are not minor. In one year, for example, hunters in Botswana have brought to market 3.3 million kg of meat of the rodent called springhare (see page 278).</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Fondness for rodent meat is not restricted to the tropics. In the United States, squirrel was once a much sought treat. Fat, nut-fed grey squirrels went into Brunswick stew, which has been called the most famous dish to emerge from the campfires and cabins of Colonial America. Thomas Jefferson liked it. Today, squirrel is the country's number two game animal (after deer), and many are still eaten.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Ancient Romans kept fat dormice in captivity, serving them as a delicacy. "The fat dormice are fattened up in barrel-like pots like those in country houses," wrote Varro (116-27 BC). "One feeds these animals large amounts of acorns, chestnuts, or other nuts."2 This small rodent remains a prized food in Europe and still appears on tables in certain areas. The meat is regarded as a delicacy because it tastes of almonds and other nuts. Often it is roasted, broiled, and cooked with its cracklings.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Rodents have seldom been included in livestock programs or economic development plans. Yet human appetite has actually caused the extinction of a number of species. Caribbean Indians ate several endemic rodents (one of which was as big as a bear), and may have caused several species to become extinct just before the time of Columbus. Others may soon follow the same dismal route, including the beautiful cloud rat of the Philippines, the hare-like mare of Argentina, the vizcacha of southern South America, and the gentle hutias of the Caribbean.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The guinea pig is described in a later chapter, but as it is the epitome of a rodent microlivestock species, some historical background is given here. It was domesticated for food use at least 7,000 years ago, probably in what is now the central highlands of Peru and Bolivia. With only llama and deer available, the prehistoric Andean peoples had few readily available sources of meat. They adopted wild cavies, and found that these rangeland rodents (which are more closely related to porcupines than to rats or mice) were gentle, manageable, and easy to rear. By the time the Spaniards arrived in the 1500s, the "cuy"  (pronounced "coo-ee," like the faint cry it makes) was a major food from  Argentina to the Caribbean.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">This impressed the conquistadores, who introduced cuys into Europe,  where they also became a delicacy.3 Within a century, these easily  transported animals began to appear on tables in many parts of the  Spanish empire. Guinea pigs are now reared in campesino huts in the  mountains of central Mexico, in the Philippines, and in several African  nations, along with other areas of the world.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Elsewhere, guinea pigs came to be used only as house pets and  laboratory animals. Although during World War II Mussolini's  government urged Italians to keep them to supplement their meager  meat rations, their use as food was largely ignored in most parts of the  world.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">DOMESTICATION</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">The idea of domesticating rodents may seem radical, but  domestication projects are already under way with capybara in  Venezuela (see page 206), pace in Panama (see next page and page  262), giant rat in Nigeria (see page 224), and the grasscutter in Ghana  (see page 232). Rodent husbandry is not complicated and the animals'  environmental requirements seem relatively simple and easy to satisfy.  Moreover, rodents are not usually fastidious feeders, and being  essentially vegetarian will readily accept a wide variety of commonly  available foodstuffs.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">LIMITATIONS</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">As with most animals with which man is in close contact, rodents can  transmit human diseases.4 With care, however, managed rodents need  not be any more dangerous to care for or to eat than pigs or  horses - both of which are worldwide food resources.  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">DOMESTICATING RODENTS</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">To domesticate the pace (see page 262) would seem to be impossible. These large rodents of Central and South America are nocturnal and fiercely territorial; they have low fecundity and take 10 months to reach weaning, and they have tender skin that is easily damaged Most researchers have written them off as candidates for domestication. But at least two have undertaken to beat the odds. We present the findings of one of them here to show that, using modem techniques, even species that normally fight each other to the death on sight are potential farm animals.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">Through years of studying paces in Panama, Smithsonian biologist Nicholas Smythe has found that with care and planning the aggressive behavior can be so radically altered that the animals become calm. Indeed, some become almost loving. Newborns, Smythe found, undergo "imprinting" and when he places them with docile adults or with humans, the fierce territoriality never develops. He nurses newborns on "surrogate" mothers that have been imprinted on people. The youngsters then welcome human company and, if fumed out of the cage, return there voluntarily. "It's difficult to imagine a more manageable animal," Smythe said. "Technically speaking they are behaviorally indistinguishable from traditional domestic animals."</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">As of this writing, Smythe has three generations totalling about 50 individuals, and has several "families" of gentle paces living together in harmony. He has observed that they lose their nocturnal habit and, although they live mainly on fruits in the wild, they readily eat leafy vegetables and other foods in captivity. His captive specimens have recently begun to breed. The offspring remain docile, but they have so far averaged only a little more than two young per female per year.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">"If we can just double the reproduction rate, then raising paces can compete economically with raising cattle," Smythe explained. "The potential for a bigger brood is all in the animal's anatomy, and if successful, paces in the wet tropics could produce as much protein as cattle."*</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Pacas need the shade and protection of the forest. Thus, pace raising might provide an alternative to cutting down rainforests for cattle raising. Instead of toppling trees and planting pastures, people could farm paces in the forest, and perhaps make as much or more money at the same time. In tropical America, the ready acceptance of pace meat is a near guarantee that all they produce will be snapped up at premium prices. In the past, many territorial and aggressive species have been dismissed as being impossible to domesticate or manage. But Smythe has demonstrated that with imprinting and other methods of behavior modification, these need be dismissed no longer.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Indeed, the pace may already be becoming a new domesticated species. In the first stage of his experiments, Smythe had to train his captive-born paces to be social and nonaggressive. Subsequent generations, however, need no training adopt the new behavior patterns of the parents, and do not revert to aggressive asocial behavior. By the third generation, they have become as accepting of, and indifferent to, people as cattle or sheep. </P>
+<P ALIGN="JUSTIFY"></P>
+<B><P>&lt;&lt;TOC3&gt;&gt; 15 Agouti</P>
+</B><P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&lt;&lt;I&gt;&gt; g020a.png FIGURE</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Among the best known of all animals of the American tropics, agoutis (Dasyprocta species)' are prolific rabbit- or hare-sized rodents that are probably easily farmed. They are valued for food and are hunted throughout most of their range. Indeed, agouti meat, once common in Latin markets. is now difficult to find because of indiscriminate killing. Agouti hunting is already prohibited in Brazil; restaurants in Belem, for example, once offered a variety of "cotta" (agouti) dishes at prices equivalent to those of choice filet mignon, but since the early 1970s they have been banned from serving it. Other countries will probably have to institute similar bans.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Agoutis are active, long-legged, and high-strung. They flee in panic at the slightest alarm. They do not climb but they do burrow occasionally, being essentially specialized ground-dwellers that live in tropical forest regions.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">There have been no organized scientific attempts to raise these swift, shy animals in captivity, but Latin Americans sometimes keep them as "domestics," especially in parks and large gardens. (Agoutis are well known, for instance at the Goeldi Museum in Belem, Brazil.) These animals seem to tame easily, and could perhaps be mass produced on a large scale like rabbits or guinea pigs. They make affectionate pets, sometimes refusing to return to the wild. A research project on captive breeding of two local agouti species (Dasyprocta mexicana and D. punctata) for food is already under way in Tuxtla Gutierrez, Mexico.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">AREA OF POTENTIAL USE</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">Most of lowland, tropical Latin America and the Caribbean. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">APPEARANCE AND SIZE</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">Agoutis are delicately built, graceful, nimble, and beautifully proportioned. They have slender bodies, short ears, and look somewhat like a rabbit that has been "jacked up" in back. Generally, adults are 40-60 cm long and weigh 2-5 kg. Some are even bigger.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">They run well and are good jumpers. From a standing start an agouti reportedly can leap as high as 2 m or as far as 6 m; however, as long as they are well fed, there is little problem keeping them behind a wall only 1 m high.2 Reportedly, they sometimes climb easy-sloping trees to collect green fruits, but researchers studying Central American agoutis report that they are strictly terrestrial.3 They swim well.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The body hair is thick, coarse, and glossy: pale orange to black on the back, and white to yellow on the belly. Some species have faint stripes, and some have a rump that contrasts with the rest of the back. The short tail is partially concealed under the long body hair.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">DISTRIBUTION</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">Agoutis occur over a vast area from southern Mexico to Paraguay, including many islands in the Caribbean.4</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">STATUS</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">Because they occasionally damage sugarcane plantings and because the meat is particularly tasty, people hunt agoutis relentlessly, especially near cities and towns. Now, in the l990s, they are becoming rare because of excessive hunting and habitat destruction. Many Latin Americans have never heard of them. In Mexico, for instance, there are few places where agoutis survive, and Dasyprocta mexicana may become extinct if habitat destruction and overhunting continue in its restricted range. In Costa Rica and Panama, agoutis occur only where there is little or no hunting or human interference.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">HABITAT AND ENVIRONMENT</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">From sea level to elevations of at least 2,500 m, the adaptable agouti lives in many habitats: moist lowland forests, dry upland forests, thick brush, and savannas. However, although they thrive in secondary growth areas, they are mainly forest dwellers. Nonetheless, they often enter fields to forage, and young animals occasionally are seen in open areas such as grassy stream banks and cultivated fields.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">BIOLOGY</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">Agoutis shelter in hollows among boulders, in riverbanks, or under tree roots. They also hide in heavy brush and sometimes in holes dug out by other species.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">These herbivores eat seeds, fruit, stalks, leaves, roots, and other succulent plant parts, as well as occasional insects and fungi.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">They seem to mate twice each year. The estrous cycle is variable, but is only about 34 days long. The young are born after a gestation period of 3.5-4 months. Usually, there are twins; however, single births and triplets have been recorded. Newborns are fully developed and are able to run around within hours. They start feeding on solids within a few days. Puberty occurs at about 9 months of age. Life expectancy is 10 years or more.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">BEHAVIOR</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">In the wild, agoutis are shy and retiring. Every sense seems constantly triggered for instantaneous action and sometimes they become hysterical. If danger threatens, they usually "freeze," but when discovered they stamp their feet as an alarm signal and dash away, nimbly dodging obstacles.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Despite excessive timidity, they can be violent among themselves.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">In undisturbed forests, agoutis are diurnal and are often seen. But around villages they become nocturnal, as a means of self-preservation.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">For the most part, these rodents live in loosely formed pairs, with previous litters living around their territory as "satellites." There is some "bigamy," some "philandering," and some "divorce."5.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Despite their long claws, they display much finger dexterity. To eat, they usually sit erect, crouching on their haunches and holding the food in their forepaws. If it has a skin' they carefully peel it before starting their meal. They save some nonperishable foods (nuts, for instance) by digging holes in scattered locations, dropping each one in a separate location, stamping it down, and covering it over. This behavior helps disperse the seeds of many species of trees so that agoutis benefit tropical forests and reforestation.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&lt;&lt;I&gt;&gt; p203a.png figure</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">USES</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">As noted, agoutis are popular game animals. They are often hunted with dogs that even follow them into the burrows. Agouti meat is tasty, although it is usually said to fall short of the meat of the pace (see page 262) because it is leaner and gamier.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">HUSBANDRY</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">Agoutis adapt well to captivity. With appropriate care they can be bred without difficulty.6 The nervousness that is pronounced in nature is quickly lost in captivity. The young become tame pets. They can be fed on foods such as leafy vegetables, fruit, potatoes, and bread scraps. Although many wild specimens have become nocturnal, captives readily readapt to daylight.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Being entirely terrestrial, agoutis require no trees, but they do need space. Given enough area, they get on well (with each other and with different species), and they breed freely. To avoid fighting, it seems necessary to separate females from males at puberty. Probably removing progeny from breeding pens at weaning could also help avoid most of the interpersonal aggression. In large areas with plenty of cover (banana plants, for instance), groups can be kept, but breeding may be disappointing. Husbandry may be most appropriate in large enclosures (50-100 agoutis) with some animals then removed to small cages 0.5-1 m&Yacute; for selective feeding.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">ACOUCHIES</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">Close relatives, the green and red acouchies (Myoprocta acouchy and Myoprocta exilis) also deserve study. These are smaller animals with longer tails, bearing a little plume of white hairs. Although even more delicate and hypersensitive than agoutis, they can be kept in captivity and breed well. They then become less nervous and are easily handled. Acouchies. show remarkable intelligence and even some affection for those they trust. They frequent rainforests, but are rare or even absent in disturbed areas. Adults weigh up to 1.5 kg.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The general biology (diet, reproduction, activity rhythm), is almost the same as that of the agouti, but they live in smaller home ranges (0.6-1.2 hectares versus 2.5 hectares for the agouti) and travel singly, although belonging to a well-established family unit. Adult males tolerate the juvenile males. They occur only in Colombia, the Guianas, Ecuador, Peru, and Brazil.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Farming methods would probably be the same as for the agoutis, but acouchies always need plant cover.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">ADVANTAGES</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">Agoutis are appropriately sized: a dressed carcass can weigh 1-3 kg. The meat is good, and large commercial undertakings in urban centers could profit from the ready market that already exists.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The animals are prolific: females can produce up to two litters a year, each litter averaging two offspring. In protected areas, populations may grow fast.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">These forest dwellers might provide a source of meat and income without destroying the forests in favor of cattle pastures. Also, they thrive in disturbed areas as long as there is some cover. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">LIMITATIONS</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">Experiments in Brazil show that agoutis are highly susceptible to foot-and-mouth disease.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The animals might become pests: they eat the roots, leaves, and fruit of agricultural crops and occasionally damage sugarcane and banana plants. However, current experience suggests that if they escape captivity they are quickly caught by hunters and do not reach pest levels.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Live agoutis have strong-smelling anal glands that may be offensive to breeders or could contaminate the meat if the animals are carelessly handled.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Where the rainforest is destroyed, the agouti population is destroyed. The animals were once well known throughout Latin America, but not anymore. In some areas, therefore, wild breeding stock may not be locally available. Moreover, people may have become sufficiently unfamiliar with them that their value may no longer be appreciated.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">In captivity, they can be the prey of large birds such as eagles.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">RESEARCH AND CONSERVATION NEEDS</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">The taxonomy of agouti species needs clarification.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Husbandry experiments are required, including studies on topics such as:</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">- Nutrition;</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">- Growth rate;</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">- Shelters and enclosures;</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">- Reproduction; and</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">- Techniques for catching, moving, marketing, and managing the animals.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">One area where agoutis might profitably be raised is in enclosures in palm plantations. Palms such as the babassu provide food, shade, and shelter, while fallen and rotten logs offer secure retreats from predators. This deserves investigation.8</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Instead of clearing vast areas of rainforest for cattle pasture, as is being done in much of Latin America, people might well "farm" agouties in the forests. Few of the settlers flooding into such regions can afford, let alone raise, beef. Small-scale agouti farming offers a promising and inexpensive alternative that would be gentle on the fragile land. </P>
+<P ALIGN="JUSTIFY"></P>
+<B><P>&lt;&lt;TOC3&gt;&gt; 16 Capybara</P>
+</B><P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&lt;&lt;I&gt;&gt; g021a.png FIGURE</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The capybara (Hydrochoerus hydrochaeris), the world's largest rodent, can be as big as a sheep and weigh as much as a small person. Its natural habitat is the environs of South America's rivers, marshlands, and swamps, where it feeds on the grasses and reeds that grow near water.1</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Because of its size, tasty meat, valuable leather, and rapid reproduction, the capybara is a candidate for both ranching and intensive husbandry throughout the hot and humid lowland tropical regions of Latin America. It seems easy to handle. It is commonly raised in zoos or occasionally as a pet, and has, in at least one instance, been proven successful in large commercial herds.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">In floodplain ecosystems, capybaras complement cattle because they prefer to graze swamp grasses rather than the dryland grasses on which cattle feed. They have simple stomachs, but are one of the more efficient herbivores. Although they are "selective feeders" that eat lush waterside grasses "preserved in quality" by the water, they also graze pasture, usually selecting new growth that is often too short and scattered for cattle, with their large muzzles, to eat.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">AREA OF POTENTIAL USE</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">The floodplains of the South American subtropics and tropics where the animal is indigenous.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">APPEARANCE AND SIZE</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">Although they have blunt, horselike heads, capybaras look like gigantic guinea pigs. They are ponderous, barrel shaped, and have a tail too small to be seen from a distance. Their skin is tough and covered by sparse, bristlelike hairs: the color above is reddish brown to gray; beneath, it is yellowish brown.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The front legs are shorter than the back. Slightly webbed toes - four on the front feet and three on the back - make them good swimmers. They dive with ease and can stay underwater for up to five minutes. They also move nimbly on land.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The capybara is extremely large for a rodent. In size and color, it looks much like a pig. Often more than 100 cm long and 50 cm high at the shoulder, it can exceed 50 kg liveweight. Indeed, specimens weighing up to 90 kg have been reported.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">DISTRIBUTION</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">Before livestock were introduced, the capybara grazed widely over riverine regions throughout South and Central America. Today, it is found in the flooded grasslands from Panama to Paraguay. Mainly, it occurs in the watersheds of the Orinoco, Amazon, Paraguay, and Parana rivers. High population densities exist in the Pantanal of western Brazil and on the Llanos floodplains of Venezuela and Colombia.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">STATUS</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">There are few precise population counts, but capybaras can occur in large numbers.2 However, in many areas they appear to be on the verge of extinction, being deliberately eradicated by farmers who think they compete with cattle and transmit diseases. Also, in some areas illegal hunting goes on year-round and great numbers are killed. The animals are particularly vulnerable during the dry season, when they concentrate around the diminished river channels and water holes.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">HABITAT AND ENVIRONMENT</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">As noted, most capybaras live in swampy or grassy areas bordering rivers. However, some are found in other habitats, ranging from open plains to tropical rainforests. But even here they stay near ponds, lakes, streams, and swamps, and never venture much more than 500 m from water.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&lt;&lt;I&gt;&gt; p210a.png The capybaras native range</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">BIOLOGY</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">The capybara, like all rodents, is a simple-stomached animal, but it is a true herbivore. Its digestive system is especially adapted for fibrous materials. The large cecum - the site of enzymatic digestion serves a function like that of the rumen of sheep, cattle, and goats. It has a digestive capacity similar to that of a sheep's rumen.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Like rabbits and all the rodents, capybaras are coprophagous. That is, during the morning hours when they are resting, soft feces from the cecum are passed a second time through the digestive system.3</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Contributing to the animal's digestive ability is its efficient mastication. It chews its forage seemingly incessantly, reducing it to extremely small particles before it is swallowed. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Under natural conditions, the females annually bear 1 or 2 litters, each averaging from 4 to 6 offspring. Birth weight is between 1 and 2 kg, depending on litter size and sex. Both males and females reach sexual maturity when they reach a liveweight of 30 kg or more usually between the first and second year of life.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">BEHAVIOR</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">Capybaras are intelligent, shy, inoffensive, and harmless. In undisturbed ecosystems, they are gregarious and live in family groups of up to 30. The young follow the mother about for many months after birth.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Unlike most rodents, they do not construct dens, but the groups have specific resting areas.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The animals are both diurnal and nocturnal and, like many herbivores, they graze at daybreak and dusk, and perhaps also at midnight. They spend the morning resting in weeds on riverbanks, and at noon they cool off by bathing for an hour or so before grazing. They may feed belly deep in water.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Capybaras wallow in mud, allowing it to dry on their skin before bathing again. Mange can develop in captivity when they cannot take a mud bath.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">When startled, a capybara barks loudly and dashes away, but after running 200 m or so it tires, slows down, and may lapse into hyperthermia. At that point a hunter can easily catch it. However, if the animal reaches water, it usually eludes the pursuer because it swims so well - especially underwater.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">USES</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">Capybara meat is white and has qualities and properties (such as high emulsification) that might allow it to compete with pork and other meats in the food industry. Spanish-style sausages, Italian-style mortadellas, frankfurters, and German-style smoked chops have been produced experimentally.4 However, at present, the meat is mainly consumed only in the dried and salted form. It is particularly popular in Venezuela, where more than 400 tons are sold every year, especially during Easter festivities.5 </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The capybara's hide is one of the best for glove making. This luxury product, known in international commerce as carpincho leather, fetches high prices on European markets because it is more heat resistant than most leathers and because it stretches in only one direction. This one way grain allows gloves to stretch sideways without lengthening and looking sloppy.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">HUSBANDRY</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">The capybara appears suitable for raising as a livestock animal. Amerindians traditionally collected capybara orphans during the hunting season and raised them until needed for food. Capybara breeding was reported in Brazil as early as 1565.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Modern attempts have been made towards domestication. Researchers at the Institute of Animal Production in Venezuela, for instance, started a breeding program in the 1970s using 20 females and 5 males. Since that time they have continuously kept capybaras in confinement. Through selection and management, they have improved the reproduction of captive animals. The current aim is to get 16 offspring per mother per year. Newborns are weaned after 5 weeks and the mother is returned to the breeding pen.6 In Colombia, similar work is in progress, and guidelines for raising capybaras on breeding farms have been published.7 In Brazil, research has been carried out to study capybara nutrition, genetics, management, reproduction, and social behavior in total confinement.8</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">ADVANTAGES</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">Throughout South America, the price of beef has increased greatly within the last few years, thereby providing a new incentive for capybara husbandry. It has also forced many campesinos to eat more wildlife, which adds another incentive for producing capybara meat on farms and thereby perhaps helping to relieve pressure on the wild stocks.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">When tame, the animals are amenable to handling without physical restraint. They are so tractable that in Surinam a blind man once used one as a guide animal. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Capybaras can be raised on a variety of readily available vegetation: leaves, roots, fruits, and vegetables. They thrive in coarse grasses, if given opportunity to select nutritious parts. Their large incisors allow them to bite off short grasses that many herbivores cannot use. For instance, they eat "capybara grass" (Paspalum fasciculatum) that is abundant on river edges in Venezuela and is normally too short for cattle to graze. This makes for low-cost feeding and utilization of a resource that is otherwise unused.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Capybaras are at home in hot, humid environments and are fully adapted to life on the tropical floodplains and seasonally flooded savannas. They thrive in extreme climates where cattle struggle, such as in the parts of the lower Paraguayan Chaco where summer temperatures reach 45&Yacute;C.9 An ecological benefit to raising capybaras is that there is no need to alter habitats by introducing exotic forage plants.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">They reproduce quickly. Age at first conception for females is about 1.5 years, and the time between parturitions is generally shorter than that of goats or sheep in the tropics. Young capybaras grow so fast that in 18 months they can reach a liveweight of more than 40 kg. In their natural conditions, they are more disease resistant than cattle. The annual productivity is said to exceed that of cattle in many parts of its range.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">This species is already so widely eaten in South America that the meat from farmed animals should be readily acceptable.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">LIMITATIONS</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">Capybaras occasionally raid fields and can harm sugarcane, rice, bananas, sweet potatoes, cassava, corn, and other crops. In many parts of Brazil, they are considered agricultural pests and are shot.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Confining these animals in high density may create serious problems. Infectious diseases and parasite outbreaks seem to be worse than those that occur with conventional livestock. Aggression might prove a limitation to capybara husbandry: it is almost impossible to cage two adult males together or to introduce new animals to an existing group.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The animals may transmit disease to people and livestock. They can harbor foot-and-mouth disease and are known to be susceptible to brucellosis. They also carry a form of trypanosome, Trypanosoma evansi. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Compared with cattle, capybara use only a small proportion of the total plant biomass. They are largely selective feeders, and for satisfactory performance must have sufficient area to select the plants they need. If placed in a paddock of only coarse grass, most will eventually die. Like goats and gazelles, capybara probably select a diet that is at least 15 percent richer in crude protein than a typical cattle diet.'&Yacute;</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">High mortality has never been observed in Venezuela, but keeping the animals alive on a farm in some areas may not be easy. In one trial, more than half (55 percent) of the capybara died of disease, and a few of septicemia (the result of wounds incurred during fights), but most apparently of trypanosomiasis. Other losses were caused by speeding vehicles (29 percent), poaching (6 percent), and predation, mainly by jaguars (12 percent)."</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">RESEARCH AND CONSERVATION NEEDS</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">It is important for researchers to undertake the following:</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">- Gather specimens from different regions for comparative evaluation.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">- Assess experiences of zoos and farms.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">- Undertake nutritional trials.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">- Initiate captive breeding trials - measurements of growth rates, space requirements, feed needs.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">- Characterize the animal's productivity.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">- Study the capybara's basic physiology and production potentials.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">- Investigate biological factors, such as reproductive physiology, and social behavior (both in the wild and under controlled conditions).</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">- Determine the factors influencing capybara reproduction, growth, and development.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">- Determine the animal's adaptability and economic merit in various farming systems.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">- Study the influence of environment on reproduction rate.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">- Determine their complementarily with water buffalo or other ruminants that normally use swampy habitats.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">- Determine relative causes of mortality (such as diseases specific to capybaras) and predation (especially of the young) by spectacled caiman, crested caracayes, black vultures, and others. </P>
+<P ALIGN="JUSTIFY"></P>
+<B><P>&lt;&lt;TOC3&gt;&gt; 17 Coypu</P>
+</B><P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&lt;&lt;I&gt;&gt; g022a.png FIGURE</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The coypu' (Myocastor coypus) is an aquatic rodent native to South America. It has been called the "South American beaver," but its size is actually closer to that of a small dog or an agouti. It seems suited to be a microlivestock species because, compared with most rodents' it has a large body size and a relatively high reproduction rate. Moreover, it is easy to manage, and there is much literature on how to raise it in captivity.2</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Fur is the main item of commercial value. In the late 19th century, it was in such high demand that the animal was nearly exterminated. However, in 1922 Argentineans began raising coypu in captivity and this practice spread through South America and to other regions. In many European countries and in various locations in the United States some specimens escaped or were released, and coypu have become established in the waterways.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Coypu meat is tasty and is consumed in many regions of South America as well as in parts of Europe. Because of the absence of musk glands, the meat is free of the "gamy" flavor found in squirrels and rabbits. It is moist, fine "rained, medium light in color, and firm. It is one of the mildest and tenderest of wild meats.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">AREA OF POTENTIAL USE</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">This animal has been widely distributed, but its area of safest use is within its natural range in South America. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">APPEARANCE AND SIZE</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">The coypu is adapted to a semiaquatic existence and has webbed feet, valvular nostrils that can be closed to keep water out, and underfur that remains dry even under water. Its long, powerful claws on the forefeet are used for grooming, excavating burrows, and digging up and holding food. The tail is slender; the extremely large incisor teeth are orange-red.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">An adult is 40-65 cm long and weighs 7-10 kg. Some occasionally weigh up to 17 kg. Males are larger than females. The pelage is thick, with coarse guard hairs overlying the underfur. The soft dense underfur (the commercially valuable pelt called "nutria") is about 2 cm long on the belly, and 2-5 cm long and less dense on the back. The color is yellowish to reddish brown on the back and pale yellow on the belly.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">DISTRIBUTION</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">The coypu is distributed through southern Brazil, Paraguay, Uruguay, Bolivia, Argentina, and Chile. It has been widely introduced in North America, Europe, northern Asia, and eastern Africa. As a result of escapes and releases from fur farms, the animals are now feral in Europe, North America, northern Asia, Japan, and East Africa. In the United States, they are abundant in Louisiana, Oregon, Florida, and the Chesapeake Bay region.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">STATUS</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">In various countries, the animal's status ranges from that of a rarity to that of a pest. Wild coypu are protected by law in Argentina because of overhunting, but there are about 100 producers of farmed coypu.3 Elsewhere the animals are destroyed en masse to reduce the threat of damage to irrigation ditches, dams, and agricultural crops. In England a decade-long program has eradicated them.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">HABITAT AND ENVIRONMENT</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">Coypu mainly inhabit the banks of fresh or brackish waterways.4 They live in temperate zones and are highly sensitive to freezing conditions. Also, their heat tolerance is poor; lowland tropical regions may be too hot for them.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&lt;&lt;I&gt;&gt; p219a.png figure</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">BIOLOGY</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">The coypu feeds mainly at night. The diet consists chiefly of plants, particularly water plants and reeds. Large amounts of fibrous vegetation is decomposed in the cecum, where bacteria break down cellulose particles. Mussels, snails, and other small organisms are also often eaten.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The animals burrow into soft soil or construct nests out of vegetation above ground.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Coypu are relatively fast breeding. Females first give birth at ages ranging from 6 to 15 months. From then on, they produce 2 or 3 litters a year. They are able to mate and give birth at any time of the year, although more young are born during certain seasons. The gestation period is between 128 and 140 days. There are 5 or 6 (sometimes up to 12) young in each litter. Newborns are well developed, able to see, and fully covered with hair at birth. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The female's four or five pairs of mammae are located on the side of the body, an adaptation that permits the young to nurse while floating with their mothers in the water. In captivity, young are nursed for two months, but can survive if weaned at five days. The mean body weight at birth is about 225 g, but growth is rapid during the first five months.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Coypu have a potential life span of more than six years. However, they seldom survive more than three years, and in the wild probably no animals are older than five years.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">BEHAVIOR</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">These are passive creatures, usually entirely lacking in aggression. They are shy and fearful; the slightest disturbance will send them scurrying to the shelter of water, a burrow, or other hiding place. With their large incisors they can bite viciously, but in captivity they tame down, even to where they can be carried around by hand. Compared with domestic animals, they are very sanitary in their feeding and living habits.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">In hot climates they are nocturnal, in cooler climates crepuscular, and in cold weather they become diurnal. Captive animals become conditioned to diurnal activity if fed during daylight hours. Most of the active period is spent feeding, grooming, and swimming. Grooming is done by scratching and "nibbling" the fur, and an oily secretion from glands located near the mouth and anus lubricates the pelage. Secretions from the anal glands are also employed for marking out territory.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Excellent swimmers, coypu spend most of their time in the water. They can remain submerged for five minutes or more. On land, they lumber about with awkward, clumsy movements; however, when the need arises they can run fast and jump short distances.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Although they usually live together in pairs, coypu will form large colonies. They tend to remain in one area throughout their lives: their daily "cruising range" has been measured at less than 45 m.5 However, drought or freezing weather can induce mass migrations.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The burrows, which are dug in sloping banks, are usually short with no branching tunnels and generally end in a simple chamber. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">USES</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">In South America, the coypu has a long history of use. Nutria fur was in such high demand and the animal was hunted so avidly at the beginning of the last century that it became rare and had to be protected by government decree. As a result, populations increased dramatically. Nowadays, coypu are protected in many areas, but widespread poaching has reduced their numbers and range.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Many thousands are killed each year just for the guard hairs, which are used in making felt.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Coypu are used in marsh management to reduce infestations of aquatic weeds and to keep waterways open.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">HUSBANDRY</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">In most areas where it is found, the coypu is trapped by commercial hunters. However, as noted, several countries have coypu farms. In Germany, the animals have been raised on diets consisting chiefly of potatoes supplemented with oats, clover, corn, hay, green forage, legumes, turnips, or cabbage. Elsewhere, feeds generally include such materials as hay, corn, crushed oats, greens, root vegetables, apples, bread, and rabbit feed.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">To confine coypu, a wall of stone or concrete or a fence of stout wire netting is necessary. It must be set 1 m deep into the ground and rise 1-1.5 m above ground. Water must be available.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Where selected strains of animals are kept, it is usual to house each female in separate small compartments, complete with pools and shelter boxes. Each is then paired with a male, which is removed after mating to leave the female to rear her brood in seclusion.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">ADVANTAGES</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">The fur is particularly valuable because the female's nipples are so high that the soft belly fur is unbroken.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">This herbivore is much cheaper to feed than the furbearing carnivores such as mink. Furs of coypu raised in captivity fetch a price about three times greater than furs from wild animals.6 </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">LIMITATIONS</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">Wherever the coypu has escaped it has damaged embankments and stream banks. The burrows sometimes weaken dikes that protect low lying areas from flooding. In northern Europe and eastern England, for example, it is considered a serious pest. In rice paddies, coypu could become particularly devastating. They can also damage crops and natural plant communities.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Coypu can carry viruses that result in toxoplasmosis, papillomatosis, rabies, and equine encephalomyelitis; bacteria that cause salmonellosis, paratyphoid, and leptospirosis; protozoans that produce sarcosporidiosis and coccidiosis; and rickettsia. Common diseases of captive specimens are bacterial pneumonia, hepatitis-nephritis, Strongyloides infection, and neoplasms.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">European winters often cause the coypu's tail (which is hairless) to freeze, but the animal hardly seems to notice. A more dangerous situation arises when lakes, streams, or rivers freeze over; beneath the ice, coypu cannot find their way as easily as beavers, and often drown.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">RESEARCH AND CONSERVATION NEEDS</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">Little research needs to be done. There is massive literature on farming coypu. Nonetheless, the animal's behavior is little studied, and there are few reliable published observations on its social organization. </P>
+<P ALIGN="JUSTIFY"></P>
+<B><P>&lt;&lt;TOC3&gt;&gt; 18 Giant Rat</P>
+</B><P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">The giant rat, also known as the pouched rat, is one of Africa's largest rodents.! Two species have been distinguished: Cricetomys gambianus, which lives chiefly in savannas and around the edges of forests and human settlements; and Cricetomys emini, which occurs mainly in rainforests. Both are highly prized as food </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">These animals are solitary, but they are easy to handle, have a gentle nature, and make good pets. Researchers at the University of Ibadan in Nigeria have been developing techniques for managing them in captivity. Breeding stocks were established in 1973, and since then so many generations have been bred that this small population is considered domesticated. Commercial-scale giant rat farming is now being established in southern Nigeria.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">This is a promising development because giant rats are a common "bushmeat" throughout much of Africa. Since these herbivores are well known there, and are acceptable as food, they may have as much or more potential as meat animals than the introduced rabbits that are getting considerable attention (see page 178).</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">AREA OF POTENTIAL USE</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">The intertropical zone of Africa from the southern Sahara to the northern Transvaal.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">APPEARANCE AND SIZE</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">This species is among the most striking of all African rodents. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Because of its large size, it often causes amazement - even alarm -  when seen for the first time. The body measures as much as 40 cm, and, on average, weighs about 1-1.5 kg. The record for a hand-reared specimen is 1.6 kg 2</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">Apart from its size, the best known species (Cricetomys gambianus) is noted for the dark hair around its eyes, a nose that is sharply divided into dark upper and pale lower regions, and a tail that has a dark (proximal) section and pale (distal) section. The overall body color is a dusky gray.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">The lesser known species (Cricetomys emini) has short, thin, and relatively sleek fur. Its upper parts are pale brown; the belly is white.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">DISTRIBUTION</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">Giant rats are commonly found from Senegal to Sudan, and as far south as the northern region of South Africa. The main species is mostly found in moist savannas, patches of forests, and rainforests. However, it can also be found in all West African vegetation zones from the semiarid Sahel to the coast. It also exists at high altitudes up to about 2,OOO m in West Africa and 3,000 m in eastern Africa.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">The rainforest species occurs in the great equatorial forest belts of Zaire and neighboring Central African countries.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">STATUS</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">These animals are probably not threatened with extinction. However, they have been exterminated in some areas (such as in parts of eastern Zaire) where the human population is dense, the land fully cultivated, and the wildlife overhunted. Although common, they are not as well known as one might suppose from their bulk and from the fact that they are sometimes found around, and even inside, houses.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">HABITAT AND ENVIRONMENT</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">Giant rats occur largely in lightly wooded dryland regions or in forested humid regions. They cannot tolerate high temperatures or truly arid conditions. They often live in farm areas and in gardens. Their burrows are commonly found inside deserted termite mounds and at the base of trees. Some have also been found in the middle of cassava fields. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&lt;&lt;I&gt;&gt; p227a.png The giant rats distribution</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">BIOLOGY</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">These are herbivores with a tendency to omnivory. They prefer fruits, but also subsist on tubers, grains, vegetables, leaves, legume pods, and wastes (such as banana peels). However, they are not grasseaters. Giant rats also kill and eat mice, insects (caterpillars, cockroaches, and locusts, for example), and probably many other small animals.3 They are particularly fond of mollusks (such as snails).</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">Reproduction is prolific and year-round. The female attains puberty at 20-23 weeks and the gestation period is about 20-42 days. The young are weaned at 21-26 days of age but stay with their mother until 2-3 months of age. So far, the record for the most litters has been 5 in 9 months. It thus seems possible that a female can reproduce 6 times a year. Litter size ranges between I and 5, but 4 is most common. Thus, in 1 year a single female could produce 24 or more young.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">BEHAVIOR</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">These strictly nocturnal animals usually lead solitary lives and forage alone. Mostly, they occupy a burrow by themselves, except when the </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">young are being raised. The burrows can be complex. Below the entrances are vertical shafts leading to a system of galleries and chambers for storing food, depositing droppings, sleeping, or breeding. The home range is individual and limited (1-6 hectares). In the wild, one male "supervises" the home ranges of several females.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">In captivity, the animals are often seen sitting up and ramming large amounts of food into their spacious cheek pouches. With full cheeks, they return to their burrows and disgorge the food into a "larder." Food (chiefly hard nuts) is stored there.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">They swim and climb well.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">USES</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">A study carried out in Nigeria showed that the giant rat produces about the same amount of meat as the domestic rabbit.4 The meat's nutritional value compares favorably with that of domestic livestock, and African villagers know how to preserve it by smoking or by salting.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">The giant rat has recently attracted attention as a potential laboratory animal.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">HUSBANDRY</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">Farmers in Nigeria have traditionally trapped the juveniles and fattened them for slaughter. They usually keep the animals in wire cages and feed them daily with food gathered in the wild as well as with scraps from the household.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">As noted, the program at the University of Ibadan indicates that the giant rat can be domesticated. Already, specimens are being bred and reared in an intensive program. They adapt to captivity after about a month. They are subsequently transferred into breeding cages, which are wooden boxes with a rectangular wire-mesh "playroom." Each cage holds a breeding pair or a nursing female with its young. Experimental feeding cages have also been designed.5</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">Food-preference trials show that palm fruits and root crops (especially sweet potato) are preferred to grains and vegetables. Nutritional studies show that the animals can tolerate up to 7 percent crude fiber in their rations. Although largely vegetarian, they eagerly consume dry and canned dog food. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">ADVANTAGES</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">These animals have several advantages:</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">· They are well known and much sought after for food.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">· They have adapted to life in lowland tropics.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">· They are able to live on locally available plant materials, including vegetable waste.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">· They reproduce rapidly.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">· They are more tolerant of captivity than the grasscutter (see next chapter). This is largely because omnivorous feeding makes them easier to feed than the grasscutter and other strict herbivores.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">LIMITATIONS</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">This species could easily become a pest. It is recommended for rearing only in areas where it already exists. The crops it damages include cacao, root crops, peanuts, maize, sorghum, vegetables, and stored grains and foods. There is also the possibility that this rodent may transmit diseases to humans.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">A project at the University of Kinshasa in Zaire reports problems in getting giant rats to reproduce in captivity. When two specimens were paired they sometimes fought so viciously that copulation was impossible.6 Special management may be required, such as housing animals in adjacent cages before actually introducing them to each other. Moreover, selection for docility may also be necessary.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">The ratlike appearance is not attractive, and a few African tribes have taboos against consuming the meat of these animals.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">RESEARCH AND CONSERVATION NEEDS</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">Throughout Africa south of the Sahara, giant rat domestication deserves experimentation and trials. Success would open up the potential for supplemental meat supplies in rural and urban areas where meat is now scarce. Tests are needed to determine the factors that favor breeding: temperature, aeration, light, privacy, and size and form of cages. Moreover, diets that are cheap and easy to make from local feedstuffs must be identified. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Further research on the domestication of the giant rat might include:</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">· Identifying husbandry techniques that are applicable at low cost in rural areas;</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">· Studying food digestibility and setting up various diets;</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">· Illuminating social behavior: pairing of animals, the best moment for pairing, duration of pairing, age of partners;</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">· Outlining the basics of husbandry (for instance, capital costs, food conversion ratios, growth rates) and making simple and cheap cages;</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">· Studying biology (anatomy, physiology, birth records, growth rate); and</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">· Testing the practical likelihood that this rodent may transmit diseases to people and other animals.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">The giant rat has an interesting commensal relationship with Hemimerus, an insect that feeds on secretions in the skin. It seems to cause no irritation or damage, and may even benefit the host by helping to keep the skin clean. Caging these animals results in the general loss of the insect, but attempts should be made to maintain them and to determine their role and life cycle.7</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">The potential of this species as a laboratory animal in nutritional, clinical, and pharmacological research also deserves exploration. </P>
+<P ALIGN="JUSTIFY"></P>
+<B><P>&lt;&lt;TOC3&gt;&gt; 19 Grasscutter</P>
+</B><P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&lt;&lt;I&gt;&gt; g023a.png FIGURE</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The grasscutter (Thryonomys swinderianus and Thryonomys gregorianus) is found in many forests and savannas of Africa. Its meat, said to resemble suckling pig, often sells for more per kilogram than chicken, beef, pork, or lamb. It is the preferred, and perhaps most expensive meat in West Africa. Indeed. in Ivory</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Coast it sells for about $9 per kg. With prices like that, grasscutter is a culinary luxury that only the wealthy can afford.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">If domestication of this wild species were successful in providing meat at a price similar to that of poultry (the second most popular meat), markets would be unlimited.2 However, as production costs are high, long-term research will be required before grasscutter production can be profitable to the small farmer. This research should now be undertaken.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">In an effort to capitalize on the markets for this delicacy, agricultural extension services of Cameroon, Ghana, Ivory Coast, Nigeria, Togo, and particularly Benin are already encouraging farmers to rear grasscutters as backyard livestock. They furnish breeding stock and information, and maintain central offices for records. In addition, a bilateral cooperation project in Benin has started experimental work on improved breeding methods combined with the study of animal responses under domestication.3</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">In future, this vegetarian animal might become the African equivalent of South America's guinea pig, playing an important role in reducing Africa's chronic protein shortage. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">AREA OF POTENTIAL USE</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Humid and subhumid Africa south of the Sahara.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">APPEARANCE AND SIZE</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">Grasscutters are robust animals with short tails, small ears, and stocky bodies. Taxonomically, they are more closely related to porcupines than to common rats or mice.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">Although many varieties have been described, there are probably only two species. The larger (Thryonomys swinderianus) weighs 9 kg or more and has a head-and-body length of up to 60 cm. The smaller species (Thryonomys gregorianus) may occasionally reach 8 kg and a body length of 50 cm.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">Both species have yellow-brown to gray-brown bodies, with whitish bellies. The fur is extremely coarse, firm, and bristly - reflecting the animal's kinship to the porcupine. The tail is scaly and has short, sparse hairs. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">Both species have thick, heavy claws and enormous orange incisors that can chew through even the toughest vegetation. (Grasscutters have been known to tear holes in corrugated iron fences.) Nevertheless, they do not bite when handled, although their claws sometimes cause injuries.4</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">DISTRIBUTION</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">Grasscutters occur in grassland or in wooded savanna throughout the humid and subhumid areas of Africa south of the Sahara. They often live in forest-savanna habitats where grass is present. They do not inhabit rainforest, dry scrub, or desert, but they have colonized the road borders in forest regions. Distribution is determined by availability of adequate or preferred grass species for food. Specifically, Thryonomys swinderianus occurs in virtually all countries of west, east, and southern Africa. Thryonomys gregorianus occurs in savannas in Cameroon, Central African Republic, Zaire, Sudan, Ethiopia, Kenya, Uganda, Tanzania, Malawi, Zambia, Zimbabwe, and Mozambique.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">STATUS</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">Despite heavy hunting, these animals are not threatened with extinction. Nonetheless, many individual populations are well below carrying capacity, or are extinct because of local overexploitation.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">HABITAT AND ENVIRONMENT</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">The larger grasscutter (T. swinderianus) generally lives in swampy, low-lying areas, especially along river banks and the borders of lakes and streams. Occasionally, it is found on higher ground among bushes and rocks, living where savanna grasses are dense and tangled enough to afford good cover. In Ivory Coast and southern Guinea, for instance, grasscutters are found (and hunted) throughout the savanna zones. And they can occur in close proximity to farmlands and people (for example, in southwest Nigeria).</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">BIOLOGY</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">Although the precise diet in the wild has not been determined, grasscutters are vegetarian. They consume nuts, bark, and the soft parts of grasses and shrubs. They particularly favor elephant grass and sweet potatoes. They commonly "raid" cassava and yam plantations, and are considered local pests.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Grasscutters reproduce year-round, although the births seem to peak at certain times of the year, correlated with weather conditions.5 Probably one male takes several females, and the family group possibly has more than one generation of young. The gestation is about 152 days. Apparently, litters normally contain between 2 and 4 young, but in Benin and Togo some litters of up to 11 or 12 are reported.6 Newborns are fully developed, their eyes are open, they weigh approximately 80 g, have thick fur, and quickly become accomplished runners.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&lt;&lt;I&gt;&gt; p236a.png figure</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">BEHAVIOR</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">Although they commonly forage in groups, grasscutters are generally solitary. They are nocturnal, and they travel at night through trails in reeds and grass, often to water. Most specimens seen in markets are males, possibly because males lead the groups and are thus most prone to being trapped.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">When alarmed, these animals stamp their hind feet and give a strange booming grunt. When fleeing, they can run very fast and, given a chance, will take to water. They swim with ease.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">For shelter, grasscutters usually weave nests of matted vegetation or scoop out shallow burrows.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">USES</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">In a broad geographic band across sub-Saharan Africa, cattle raising is severely limited by trypanosomiasis. There, other sources of animal protein, including rodents, are traditionally used. Thus, grasscutter meat constitutes an important food for many Africans. The animals are mostly caught and eaten by families for their own use, but some are sold in markets and especially in roadside stalls. Many families depend exclusively on selling bushmeat, particularly that of grasscutters. In Accra, Ghana, during one year, 73 tons of grasscutter meat were sold in the local market. This represented more than 15,000 animals. In southern Africa, too, people find that these rodents make tasty food, although they may cut off the tail to make the carcass look less ratlike.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The meat is usually eaten smoked, and is so much in demand that grasscutters are hunted in organized drives with spears, dogs, and sometimes fire. It is considered excellent, especially when cooked in soups and stews or barbecued.7 It has been described as resembling venison in flavor, but it is dark like the meat of wild duck.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">HUSBANDRY</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">In the savanna area of West Africa, people have traditionally captured wild grasscutters and raised them at home. As an extension of this, organized grasscutter husbandry has been initiated in West Africa. The animals are provided with marshy, tightly fenced areas with plenty of plant cover. The young are harvested from these areas and raised separately.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Ghanaian researcher Emanuel Asibey, a pioneer of this research, reports success at getting such captive stocks to reproduce. To this end, farmers are provided with breeding boxes and foundation grass cutter colonies. They are taught how to rear and feed the animals for home consumption or for cash income. Basically, the farmers make available large sheds where the animals can move freely. To prevent escape, the walls may be reinforced with cement plaster. The farmers also provide piles of grass, sugarcane, and other foods. A grasscutter reportedly takes about a month to adjust to such confinement. High mortality can occur in this period. The average weight of a mature, home-raised grasscutter is 4-7 kg. The average killing-out (dressed carcass) is 64 percent.8</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The Wildlife Domestication Unit of Ibadan University in Nigeria, another pioneer of rodent domestication, has also reported the potential of domesticated grasscutter colonies.9</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Research on grasscutter breeding, husbandry, and feeding is similarly being implemented by the Ministry for Rural Development in Benin and at the Lacena in Ivory Coast (see Research Contacts).</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">ADVANTAGES</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">The demand for grasscutter meat is so large that it is not being met. Markets for it already exist over much of Africa,</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">LIMITATIONS</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">Grasscutters can devastate such crops as rice, sugarcane, soybeans, peanuts, yams, cassava, sweet potatoes, oil-palm seedlings, maize, young rubber, sorghum, and wheat. Therefore, as with most rodents, they should be reared only in areas where they already exist.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">In past years, captive animals in Benin have suffered fatal Clostridium infections during September and October. In 1986, a broad-spectrum antibiotic was given with outstanding results. During this season, the animals also suffered from ascarid worms, which were also successfully treated with standard drugs.10</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">RESEARCH AND CONSERVATION NEEDS</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">Research is needed in the following areas:</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">- Digestive physiology, feeding habits, feed preferences, feed conversion and growth rate; </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">- Diseases (pathogens and parasites);</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">- Captive breeding and management (growth rates, space requirements, feed needs, etc);</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">- Performance under different environments;</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">- Productivity; and</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">- Basic biology (for example, chromosome type, reproductive physiology, and social behavior both in its wild state and under controlled conditions).</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Moreover, specimens should be gathered from different regions for comparative evaluation. A particular need is to select and breed docile specimens because today, even after several generations in captivity, the animal must still be handled with caution.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Although domestication of the grasscutter is encouraged, wild populations might also be managed to maximize and sustain production through habitat manipulation. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<B><P>&lt;&lt;TOC3&gt;&gt; 20 Guinea Pig</P>
+</B><P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&lt;&lt;I&gt;&gt; g024a.png FIGURE</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Guinea pigs (Cavia porcellus) are promising microlivestock because they require little capital or labor; provide an inexpensive, readily available, palatable meat; have no odor, and are suitable for keeping indoors. In the highlands of the Andes, many Indians raise them to supplement diets based on grains  and vegetables. Families eat them mostly on special occasions such as weddings and first communions, or they sell them to restaurants or peddle them in village markets.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The low cost of these small animals makes them available even to many landless peasants. For both the small farmer and apartment dweller, the guinea pig is a possible food reserve. It converts kitchen scraps and marginal wastelands into meat. According to estimates, 20 females and 2 males may produce enough meat year-round to provide an adequate meat diet for a family of 6.2</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Since husbandry practices are simple and cheap, the guinea pig is an excellent source of supplementary income. An FAO study at Ibarra, Ecuador, showed that on small mountain farms the guinea pig provided more profit than either pigs or dairy cows, partly because its meat fetched high prices.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Although domesticated guinea pigs are mainly a food resource of Latin America, their use has also spread to parts of Africa and Asia. They are raised, for instance, in Nigeria, Cameroon, Ghana, Sierra Leone, Togo, and Zaire. In southern Nigeria, at least 10 percent of all households raise guinea pigs for food, with colonies of up to 30 animals per household. Guinea pigs are also raised in small cages or cardboard boxes by small farmers in the Philippines.3</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The feeding efficiency is high: studies have shown that it takes between 3.2 and 5.7 kg of forage to produce 1 kg of growth. This makes guinea pigs more efficient than most farm mammals. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Guinea pigs seem especially adapted to the climate and forages of high-altitude zones, but the fact that they are being raised in Central and West Africa indicates that they are also adapted to the lowland tropics.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&lt;&lt;I&gt;&gt; p243a.png The native distribution of the guinea pigs wild ancestor</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">AREA OF POTENTIAL USE</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Worldwide.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">APPEARANCE AND SIZE</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">Guinea pigs have stocky bodies, fairly short hind legs, and short, unfurred ears. Adults can weigh up to 2 kg, but an average-sized specimen is about 0.5 kg. They are 20-40 cm long (average 28 cm) and have no tail. In domesticated forms, the pelage may be smooth or coarse, short or long, and in some types the hairs form rosettes.4 Domesticated types come in colors ranging from white to dark brown, as well as piebald.5 </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">DISTRIBUTION</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">The original home of the wild guinea pig is believed to have been the central highlands of Peru and Bolivia. Its domesticated descendants are important as meat animals mainly in that same area, but, as noted, they are also important in certain African and Asian countries.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">A few strains are distributed worldwide as laboratory animals and pets.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">STATUS</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">Domesticated guinea pigs, as a whole, are in no danger of extinction, although some rare strains are threatened.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">HABITAT AND ENVIRONMENT</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">These extremely adaptable animals are found in temperate zones and in the highland tropics, but they are usually kept indoors and protected from the extremes of weather. In Lambayeque and other departments of Peru, they are reared at elevations from sea level to more than 4,000 m. In areas where they are raised, daily temperatures fluctuate as much as 30&Yacute;C. In the Bolivian or Peruvian puna region, for instance, day temperatures can be 22&Yacute;C, while night temperatures are -7&Yacute;C. However, they cannot survive freezing temperatures and they may not perform well when exposed to the full tropical heat and sunlight. Many people of the Peruvian highlands keep the animals in darkness (for example, in wood boxes with little or no light).6</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The animal's original wild habitat is believed to have been an area of grasslands, forest edges, swamps, and rocks.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">BIOLOGY</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">These herbivores can be raised on kitchen scraps, garden wastes, and weedy vegetation plucked from backyards or roadsides. Andean peasants mainly feed them potato peels, scraps of cabbage, lettuce, carrot, wild grasses, corn stalks, and the foliage of miscellaneous wild plants. Some barley and alfalfa is grown specifically for guinea pigs; it is cut green and sold in small bundles in the markets. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Guinea pigs mate throughout the year except when climate is excessively adverse. Domestic breeds average 2-3 young per litter, although larger litters sometimes occur. The gestation period is 65-70 days with an average of 67. Females come into estrus every 13-24 days, and there is a fertile postpartum estrus.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Females can become pregnant when merely 3 months old, and many produce 4 litters every year from then on. In principle, a farmer starting with 1 male and 10 females could see his herd grow to 3,000 animals in one year.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Newborns are so large that the female's pubic bones must separate for the birth. They emerge fully developed, with fur and open eyes. They look like miniature adults, and they start eating grass and other feedstuffs within hours. (For this reason, babies orphaned at birth have been known to survive.) Weaning may be reached as early as 21 days of age.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The life span in captivity is as long as 8 years, but animals used for breeding usually live only 3.5 years. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">SUPER GUINEA PIGS</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">Even in their native region, guinea pigs have traditionally received little research attention. However, that began changing in the 1970s with the onset of meat shortages in Peru. (For a time the government restricted beef sales to only 15 days a month.)</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">For instance, in 1972 Peru began a guinea pig improvement project. Researchers from i a Molina National Agrarian University traveled throughout Peru gathering many kinds of guinea pigs short haired long haired black, white, yellow, brown, and even purple. Practically all the guinea pigs eaten in Peru are home grown, and researchers observed that the bigger ones were generally winding up in the stew, leaving the smaller ones for breeding. The people inadvertently were making the animals smaller. (This is a common phenomenon for many animals.)</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">To overcome it, the university research workers compared the mature size and growth rates of all the different guinea pigs. They selected and cross-bred the biggest, meatiest, and fastest-growing ones. This program, later taken over by Instituto Nacional de Investigacion y Promocion Agropecuaria (INIPA), produced remarkable results. The starting animals averaged little more than 0.5 kg, the resulting ones averaged almost 2 kg.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Peru's "super guinea pigs" are now getting international recognition. They have been introduced into the highlands of Honduras, where the animal is also part of the Indian cuisine. The FAO has shipped some to the Dominican Republic. In addition, Bolivia, Ecuador, and Colombia have all begun their own guinea pig improvement programs.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Within Peru the government has established 11 breeding stations to encourage the farming of guinea pigs for food. The goal is to provide better stud males to the people so that future animals will grow more quickly and reach a greater weight.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">BEHAVIOR</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">Guinea pigs generally congregate in small groups, normally made up of 5-10 adults. In favorable areas, however, such groups may coalesce into large colonies. The animals communicate incessantly among themselves, emitting a variety of squeaks and other noises.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Males, although good-natured with other species, often fight fiercely among themselves.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">USES</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">Guinea pigs are raised mainly for meat. Peru has about 20 million, which annually provide 16-17,000 tons of meat (only 4,000 tons less than Peru's sheep meat production).</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Guinea pigs are used worldwide for studies on disease, nutrition, heredity, and toxicology, as well as for the development of serums and other biomedical research. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">HUSBANDRY</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">Guinea pigs require so little space that a small cage or pit can house up to 10 females and 1 male. They can be raised in cages with wire floors of small mesh as well. The labor required is low. A colony of 1,000 females reportedly can be properly cared for by one person. A layer of wood shavings, shredded paper, straw, and dried corncobs is usually recommended for bedding. The droppings are odorless, so the bedding does not need changing as often as with other animals. When the diet mainly consists of greens, much urine is produced, and then the beds have to be changed frequently.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">When grown for meat, the young are weaned at 3-4 weeks and are ready for market in a matter of 10-13 weeks. Weight gain is rapid for the first 4-6 weeks, and then decreases. The carcasses normally dress out at about 65 percent, including the skin and legs. The meat's protein content is approximately 21 percent.7</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">In a few regions of Peru, guinea pigs are "herded" on the open range and retired at night into small adobe coops.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">ADVANTAGES</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">This small, inoffensive animal rarely bites, is easy to manage, and has no smell. It is an excellent supplemental meat supply. The improved breeds cannot climb or jump so that they are easy to contain. (Primitive "criollo" types, however, can jump.) If kept dry and given green vegetation, grain, and water, it survives in many environments.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">LIMITATIONS</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">A major constraint is consumer reluctance. Even in Latin America, attempts to promote guinea pig consumption outside the Indian communities have failed.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">When raised in a clean environment and under normal feeding conditions, guinea pigs thrive and reproduce and do not need routine vaccinations or antibiotics that cattle, sheep, and pigs often require. However, guinea pigs can be carriers of Chagas' disease and salmonella. Further, they are susceptible to pneumonia if temperatures change abruptly when conditions are wet. Coccidiosis and internal and external parasites are also common.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Green forages and surplus fruits or by-products are critical to provide vitamin C, which the animal is unable to synthesize for itself. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">RESEARCH AND CONSERVATION NEEDS</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">Since the greatest concentration of guinea pigs is found in the Andes, particular efforts should be directed towards this region. Already, research on guinea pigs has begun in some universities and government research stations in Colombia, Ecuador, Venezuela, Peru, and Bolivia, but more work is needed on matters such as:</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">- Breeding "elite" stock for distribution;</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">- Feeding and nutritional-requirement trials, especially for creating alternate feeds that peasants and commercial producers can use during seasons when conventional feeds are hard to get;</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">- Diseases and parasites that may limit production in small farming systems;</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">- Management practices concerning reproduction, housing, herd size, and feeding; and</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">- The genetic basis for weight gain and productivity.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Some research should be directed towards developing rations or introducing drought-resistant forages for the dry season because green forage is needed year-round. A range of practical and economical diets needs to be created.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Animal geneticists in Latin American countries should establish "elite" populations that can provide superior stock throughout the world. It can be anticipated that applying modern breeding methods to existing improved strains will result in great advances in a relatively short period and at little cost (see sidebar).</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Three species of wild cavies (Cavia aperea, C. fulgida, and C. tschudii), close relatives of the guinea pig, are native to South America and are declining drastically. Research to preserve them is urgently needed. C. aperea is a widely used item of food in rural Brazil and other parts of South America. </P>
+<P ALIGN="JUSTIFY"></P>
+<B><P>&lt;&lt;TOC3&gt;&gt; 21 Hutia</P>
+</B><P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&lt;&lt;I&gt;&gt; g025a.png Hispaniolan Hutia</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The first meat Christopher Columbus tasted in the New World was probably hutia, a rodent avidly hunted by the Carib Indians. Hutia bones have been unearthed from kitchen middens of pre-Columbian inhabitants of all the Greater Antilles. Indians carried live hutias on voyages possibly in a semidomestic state as a source of food. On some islands, hutias were so eagerly sought that their populations were destroyed long before Europeans arrived. Slaves in the cane fields also hunted hutias for food. The surviving species later suffered when forests were cleared and cats, dogs, mongooses, and other predators were introduced. Consequently, the majority of hutia species died out, and today most surviving members of the family (Capromyidae) are facing extinction. Human predation continues in some areas (for instance, in Jamaica) where the tradition of "coneyhunting" still endures in a few regions.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Hutias should be tested as possible microlivestock: success could create the incentive for their complete protection. The animals seem to take well to captivity. The Jamaican hutia is already overproducing in zoos, causing a local glut of animals. And hutias are, or were until recently, kept in barns by some people in Cuba, who fed them on banana and other vegetable waste and ate them regularly.'</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">POTENTIAL AREA OF USE</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">The Caribbean.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">APPEARANCE AND SIZE</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">Hutias are broad-headed, short-legged, robust animals with small eyes and ears. The various species are from 20 to 60 cm long and weigh from 1 to 9 kg - a size range from that of a guinea pig to that of a small dog. They walk with a slow, waddling motion, but can hop quickly if frightened or pursued. They also climb well.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The 10 1iving species are all big enough to be candidates for microlivestock. The best known and easiest species to keep in captivity are the Cuban hutia (Capromys pilorides) and Jamaican hutia (Geocapromys brownii). </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The Cuban hutia (also called hutia conga) is about 60 cm long, with coarse fur, a raccoon-shaped body, and a thick tail covered with sparse bristles. A forest dweller, it weighs up to 7 kg.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The short-tailed Jamaican hutia is smaller: it is 33-45 cm long and weighs up to 2.5 kg.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&lt;&lt;I&gt;&gt; p252a.png The hutias native range .</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">DISTRIBUTION</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">Hutias are found only in the Caribbean (Greater Antilles and Bahamas). Most species are confined to a single island, where they represent the only remaining indigenous land mammals. The Cuban hutia is found only in Cuba. The Jamaican hutia is found only in Jamaica, although a close relative occurs on East Plana Cay, Bahamas. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">STATUS</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">This once widely distributed and plentiful family is now failing. Of the 30 or so known recent taxa, more than half are already extinct, and the remainder all suffer from habitat alteration, predation by introduced animals, and hunting by man. With the exception of the Cuban hutia, all species are included on the list of the world's threatened mammals.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">HABITAT AND ENVIRONMENT</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">Hutia ranges have been so reduced that these animals survive only in the most inaccessible forests and rocky drylands. Both the Cuban and the Jamaican hutias occur in a variety of habitats from montane cloud forests to arid coastal semideserts.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">BIOLOGY</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">Most species are terrestrial, but some live in trees. The Cuban and Jamaican species are terrestrial, but they can climb trees if circumstances demand. They maneuver well on trunks and larger branches, descending head first like squirrels.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Hutias are primarily vegetarian, their diets consisting of leaves, bark, fruits, and twigs, as well as incidental catches of small animals such as lizards and invertebrates.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Hutias seem to breed year-round, generally giving birth to litters of 1-4 offspring after a gestation period of 16-20 weeks. The young are well developed at birth, fully haired, open eyed, and capable of most adult movements. After 10 days they begin taking solid food, although they are not fully weaned for at least a month and a half (5 months for the Cuban hutia). Sexual maturity is at 10 months; life expectancy is 8-11 years in captivity.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The Jamaican hutia has one of the highest diploid chromosome numbers (2n = 88) of any mammal.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">BEHAVIOR</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">Most hutias are wary and secretive and are easily displaced by human encroachment. They live like rabbits, hiding among tangled vegetation, in holes, and among rocks - communicating by voice and scent markings. They build shelters mainly in rock crevices, but also in the base of thick bushes or in natural cavities in trees. The Cuban hutia is often diurnal, whereas the Jamaican hutia is largely nocturnal.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">HISPANIOLAN HUTIA</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">The Hispaniolan hutia, or zagouti (Plagiodontia aedium) as it is known in Haiti is smaller than the two Capromyids discussed here, weighing just 1.2 kg. It is difficult to breed in captivity and has a lower reproductive rate than either the Jamaican or Cuban hutia. It is therefore less suitable as an economic or food source.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">However, there is a significant need for supplemental protein sources in both Haiti and the Dominican Republic. It might be possible to develop a special captive-breeding program for this animal, but it should be done with great care. It is important that a hunting tradition for this animal not be reestablished in rural areas of Haiti or the Dominican Republic, and that local organizations not be misled into believing that there will be a rapid increase in the numbers of this species in captivity.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">USES</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">Hutia meat is relished, especially in Jamaica. The animals are still hunted, often by using dogs that smell them out and retrieve them from a hole or hold them at bay in treetops.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">HUSBANDRY</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">Experiences of zoos suggest that the Cuban and Jamaican hutias will thrive in captivity. The animals are generally long-lived and have survived up to 17 years. They are often friendly with their keepers and, when tame, can be held and carried about without any particular danger. However, if angered they can inflict deep bites and should normally be handled with considerable caution.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">ADVANTAGES</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">These animals are already much in demand. Their meat has an excellent flavor and they are big enough to provide a worthwhile quantity. If husbandry could be developed on a sustainable basis, it could be used as a mechanism for both economic development and for saving the remnant populations.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">LIMITATIONS</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">Wild populations are threatened. Any captive population must be built up without endangering them.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">All hutias are susceptible to predation by domestic cats, mongooses, dogs, and human poachers, so care must be taken to design predator-proof breeding facilities.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">These animals are carriers of eastern equine encephalomyelitis, a serious disease of horses.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">RESEARCH AND CONSERVATION NEEDS</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">Hutias deserve urgent conservation attention. In particular, the following steps should be taken:</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">- Establish reserves in natural habitats containing breeding populations to ensure the survival of the genetic diversity of these animals.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">- Build up breeding populations in suitable zoos and livestock research centers.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">- Gather specimens from different regions for comparative evaluation.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">- Investigate hutia biology, including chromosome type, reproductive physiology, nutrition, and diseases.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">- Assess experiences of zoos.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">- Perform captive breeding trials, measuring growth rates, space requirements, food needs, and social behavior (both in its wild state and under controlled conditions).</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">- Study the social organization and tameability.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Colonies of some species could be established on uninhabited islands, as has been done with the Bahamian hutia Geocapromys ingrahami. Even this rare species might eventually be raised to yield meat for local inhabitants, as it is well adapted to dry and barren environments and was a regular food of the pre-Columbian Indians. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<B><P>&lt;&lt;TOC3&gt;&gt; 22 Mara</P>
+</B><P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&lt;&lt;I&gt;&gt; g026a.png FIGURE</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Many wild relatives of the guinea pig are native to South America. Some, such as the guinea pig itself, are small; others, such as the mare, are much bigger. Maras1 (Dolichotis patagonum) are as tall as terriers and, at first glance, look like dwarf antelopes or huge hares They have large ears and eyes, long legs, and short tails. They generally behave like hares or wild rabbits, but, like deer, they run with a stiff-legged gait when pursued by predators.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">These strange-looking creatures are found in temperate regions in the southern half of South America. They are dry-country animals, living on the thorn-scrub, desert plains of Argentina and the stony wastes of Patagonia.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Although exceedingly shy, restless, and watchful, mares tame easily, make good pets, and are much favored by the local populace. They were introduced to France last century, and in Victorian times Europeans sometimes bred them. These big, handsome rodents, grazing in little herds, were considered an attractive addition to the lawns of country estates.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">POTENTIAL AREA OF USE</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">Maras are best kept in their native region of southern South America. With care, however, they could be used in other areas because they are slow breeders and their population growth is easy to control.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">APPEARANCE AND SIZE</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">At first sight, these large rodents look like some weird hybrid. They have the long ears of a hare and the tidy body and spindly legs of a small antelope. Although related to guinea pigs, they are long legged. The tail is short; the ears are long and erect.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Average-size mares weigh about 8 kg, but large ones can be 1 m long and weigh up to 16 kg.2 Females are larger than males. The coat is light in color, with grey upper parts and whitish underparts. The limbs and feet are tinged a yellowish brown. The pelage is dense, with individual hairs standing at nearly right angles to the skin. This gives a harsh texture, even though the hairs are soft and fine.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">These animals can hop, walk, gallop, or run. They are extremely swift and can reach 45 km per hour over long distances. They are also accomplished jumpers, often leaping 2 m high from a standing start. The feet are compact and rather hooflike, but with sharp claws. The hind foot has three digits; the front foot has four.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">DISTRIBUTION</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">The mare's range in the thorn-scrub desert and Patagonian steppe of Argentina extends from about 28&Yacute;S to 50&Yacute;S.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">STATUS</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">Endangered. These animals, once plentiful, are now threatened because of the introduction of the European hare, which is more successful at competing for food. In many of the eastern parts of its distribution (see map) it is now extinct.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">HABITAT AND ENVIRONMENT</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">Maras inhabit open, dry plains and other treeless semidesert areas of coarse grass or scattered shrubs.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">BIOLOGY</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">Maras are pure vegetarians. They feed on short grasses and herbs that are sparsely distributed between patches of dry desert scrub. Usually, they are satisfied with a few coarse weeds and the shoots of bushes. However, their overall diet consists of any available vegetation: leaves, roots, fruits, and stems.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Female mares become sexually receptive within a few hours after giving birth. The estrous cycle is 35 days, plus or minus 5 days.3 The gestation period is 77 days. Each female gives birth to 1-3 young at the mouth of the den; the pups crawl inside to safety. Newborns are well developed, and within a few hours they begin grazing vegetation. They remain in the vicinity of the den for up to 4 months.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Initially, at least, the young are nervous and easily frightened.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">BEHAVIOR</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">Maras shelter in a burrow that they either construct for themselves or "borrow" from another animal that has abandoned it. They are active during the day and spend considerable time basking in the sun. They are always alert for danger. When alarmed, they flee at high speed. The white rump patch flashes a warning to the others, who then follow this "flag."</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">A fundamental element of their social system is the monogamous pair bond. Certainly in captivity, and probably in the wild as well, the bond between a pair lasts for life. When breeding, 20 or more pairs may band together temporarily to share a single den for the pups.4 </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The animals stand on straight legs, sit on bent haunches with the forepart of the body resting on the fully extended front legs, or recline in a catlike position with the front legs folded under the chest, an unusual position for a rodent. They travel in single file, with the female usually leading. Members of a pair maintain contact by means of a low grumble. Although the long legs can quickly carry it to safety, a mare usually stops every 20-30 m and turns to peer at its pursuer.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The animals clean themselves by licking their sides and apparently by "combing" their fur with their teeth. They wipe their faces as cats do, with the inside of a foreleg.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&lt;&lt;I&gt;&gt; p260a.png The maras native range</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">USES</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">Although the light-colored meat is said to be dry and flavorless, it is widely consumed in South America.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">HUSBANDRY</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">Maras have been successfully raised and bred in many zoos, and, as noted, have been kept as pets.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Adults make little use of any shelter; they seem fond of being out and about in all weather. As long as they have a protected burrow for the use of the pups, mare populations can thrive in severe climates.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">In zoos, diets include straw, vegetables, and crushed oats. Drinking water is supplied, although the animals rarely take it if they are feeding on fresh plant materials. They like to have salt blocks, however.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">In South America, one mare lived in captivity for almost 14 years; most specimens do not live beyond 10 years.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">ADVANTAGES</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">Maras are a good size for microlivestock. They have a short gestation period, and they are social and easy to maintain in groups. They can be successfully kept in pens and can be fed relatively low-quality forage. Colonies can grow to be quite large.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">LIMITATIONS</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">These animals can easily dig under the edges of cages and escape. Extra-deep foundations are needed.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Following heavy rains, care must be taken to keep them from drowning in their subterranean burrows.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">If suddenly disturbed, mares can become hysterical, leaping away regardless of anything in the way, and often seriously injuring or even killing themselves as a result. They fear bodily contact.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The mare's monogamous nature in the wild is a likely limitation. But perhaps, like chinchillas, the animal will become polygamous in captivity.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The animals are sensitive to tuberculosis when kept in humid conditions.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">RESEARCH AND CONSERVATION NEEDS</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">Research needs to increase understanding of the mare include:</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">- Nutritional trials;</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">- Husbandry experiments - measurements of growth rates, space requirements, feed needs;</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">- Productivity tests;</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">- Grazing-efficiency measurements;</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">- Exploration of commercial details; and</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">- Determination of diseases and parasites. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<B><P>&lt;&lt;TOC3&gt;&gt; 23 Paca</P>
+</B><P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">Pacas (Agouti paca)1,2 are large, white-spotted, almost tailless rodents with the potential to become a source of protein for the American tropics. They are found in lowlands from Mexico to northern Argentina. The meat is white and is considered the best of all Latin American game meat. It is common in local markets and restaurants. Tasting like a combination of pork and chicken, it sells at higher prices than beef and is a regular item of diet in some areas. In Costa Rica, pace is served on special occasions such as weddings or baptisms. It has a higher fat content than the lean meat of agoutis, rabbits, and chickens, and has no gamy taste.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Paca has promise as a microlivestock. In several countries, Belize and Mexico for example, people already keep them in cages beside their homes and fatten them on kitchen scraps. In Costa Rica, some are bred on farms, under houses, and even in apartments. Research on raising paces in captivity is under way at the Universidad Nacional in Heredia, Costa Rica; at the Smithsonian Tropical Research Institute in Balboa, Panama (see page 196); and at the Instituto de Historia Natural in Tuxtla Gutierrez, Mexico. In Turrialba, Costa Rica, an entrepreneur is already breeding and raising pace commercially.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">While the pace has potential as a food source, many problems still must be resolved before it can be recommended for mass rearing. If solved, however, this species would become an attractive microlivestock.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">AREA OF POTENTIAL USE</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">The pace has potential for use throughout its vast geographical range in Latin America.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">APPEARANCE AND SIZE</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">In general appearance, paces are somewhat like giant guinea pigs. The legs are short, the forefeet have four "fingers," and the hindfeet have five small, hooflike "toes." The feet are partially webbed and are adapted both for digging and for swimming. Pacas burrow with all four feet as well as their teeth; even large roots are no obstacle.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Adults weigh 6-14 kg, males being somewhat larger than females. Although they may become bulbously fat, paces remain "one of the fastest things on four feet. " From a standing start, even a fat specimen can jump at least 1 m off the ground. Pacas are also agile. However, their skin's epidermal layer is thin and fragile, and large strips may be ripped off as they rush headlong through spiky undergrowth. However, such wounds heal astonishingly fast - frequently within days.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Pacas are chocolate brown in colon The head is somewhat lighter in shade than the body, and the underparts are whitish or buff colored. There are usually four longitudinal rows of white spots that may merge into stripes along each side of the body. The fur is coarse, spiny, and slippery, and has no underwool. Each hair is stiff, relatively sharp, and very smooth, which makes paces extremely difficult for predators to hang on to.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Parts of the cheekbones are enlarged, and the cheeks can open to form special pouches. This is more developed in adult males than in females - indeed, adults can be readily sexed by head shape. The pouches are outside of the mouth and are fully haired. The animals use them mainly to create a resonating chamber for their booming bark and noisy tooth grinding. These enlarged cheeks push the large bulging eyes toward the top of the skull. The eyes are suited for nocturnal conditions, the senses of smell and hearing are uncannily acute, and there is an array of long whiskers that is used when maneuvering at night.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">DISTRIBUTION</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">Lowland paces are found throughout most of Latin America from east central Mexico to northern Paraguay, Argentina, and Minas Gerais, Brazil. This includes all of Central America and most of Colombia, Ecuador, Peru, Venezuela, and the Guianas. The animal has also been introduced into Cuba.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&lt;&lt;I&gt;&gt; p265a.png The pacas native range</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">STATUS</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">Burgeoning human populations are severely reducing many of Latin America's native animal resources, and the pace is one of the most persecuted. It has been exterminated within hunting range of virtually all cities, towns, and villages.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Several governments, recognizing the pace's plight, have passed laws prohibiting the hunting and marketing of its meat. Nevertheless, people continue to take it, usually at night, using trail dogs and headlights.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">HABITAT AND ENVIRONMENT</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">Pacas thrive in a variety of tropical habitats but are most common in forests, swamps, and partly cleared grazing lands. They inhabit most types of forests from deciduous woodland to rainforest. Usually, they stay near streams or rivers, but they often live where there is no permanent water. They are abundant only in little-disturbed forest areas. Although preferring low, dense tree cover, paces sometimes inhabit open rocky areas and farmland.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">BIOLOGY</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">These herbivores feed mainly on fruits, young seedlings, and some seeds. However, when fruits are scarce they may switch to browsing leaves and roots. They probably sometimes eat large insects, and, on rare occasion, may perhaps eat small vertebrates. Captive paces, like many other "frugivores," seem to develop a protein deficiency and will eagerly eat meat scraps on occasion.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The young are usually born singly after a gestation period of 146 days. There are probably 2 births a year. Females have an estrous period that begins shortly after giving birth. If mating does not take place at this time, the female becomes unreceptive until after the 3-month (sometimes 4- to 6-month) lactation is over. The length of the estrous cycle is 30 days.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">During daylight hours, paces seclude themselves in brushy cover, in or under fallen logs, or in extensive underground burrows. The burrows, which may be several meters long, are dug in moist soil or taken over from other animals; they are often in river banks, on slopes, among tree roots, or under rocks. Usually, several exits are provided, often being plugged with leaves as a disguise.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">BEHAVIOR</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">In the wild, paces dig large holes and rummage about the forest floor at night, gnawing on fruits. Pairs inhabit a defended area, sometimes living together in the same burrow, sometimes not. Also, they usually travel alone, following paths that lead to feeding grounds and water. Individual home ranges are small (1-3 hectares).</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Although paces are terrestrial, they enter water freely, they swim well, they copulate in water, and, when alarmed, they generally attempt to escape by swimming. They are also lively and playful; however, they can be exceedingly obstinate. Sometimes fighting among themselves becomes very savage. When angered they growl, sometimes noisily, and they can suddenly jump on aggressors, real or imagined, delivering frightful wounds with their chisel-like front teeth thrust forward like a spear. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">USES</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">As noted, pace meat is tasty and brings high prices in the markets. It is considered a delicacy in fine restaurants and was served to Queen Elizabeth during her October 1985 visit to Belize. In Mexico, paces, like pigs, are usually boiled unskinned. Even the skin is then edible.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">HUSBANDRY</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">If treated appropriately when young, paces become manageable. They undergo "imprinting," a characteristic of most species that have been domesticated. An imprinted pace becomes so tame that it seeks out human company, follows people around like an amiable dog and, if turned out of its cage, returns voluntarily. (To achieve this degree of tameness it is necessary to remove the animal from its mother at an early age.)</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Although wild paces are almost entirely nocturnal, tame paces are more active during daylight hours.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Young or partly grown paces are commonly exhibited in zoos. They eat prodigious quantities of almost any vegetation and have been called, "a good substitute for a large garbage pail." Diets can include rolled oats, raw vegetables, bananas, apples, and bread. They probably need additional protein occasionally, and seem to appreciate some fat in their diet.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">ADVANTAGES</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">If husbandry can be developed, the clamor for pace meat throughout tropical America would be a big economic incentive for farming these animals. The excellence and wide acceptance of the meat is an indication that pace farming would be taken up both in rural and urban areas and by many levels of society.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">LIMITATIONS</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">Pacas can harbor human diseases, including leishmaniasis and Chagas' disease.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Apart from the project in Panama (see page 194), paces have bred only sporadically in captivity, with few offspring surviving. However, successes have been recorded in zoos in London, San Diego, and Washington, D.C., and in a research project in Tuxtla Gutierrez, Mexico. In Costa Rica, they are also reportedly breeding well, with a survival rate of 90 percent since 1982, and 80 percent of the females are reproducing.3</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">All adult paces can be aggressive and dangerous. Their powerful incisors can inflict serious wounds. (They can even rip through planks.) Intraspecific aggression is one of the most serious impediments to captive breeding.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Unlike the capybara, the pace not only has a long gestation but usually bears a single young. Thus, the output of a single breeding female may be, at best, two offspring per year (at least this is the expected production in the wild). This "slow" breeding is a limitation. In captivity, however, there is a possibility that it can be speeded up.4 The fact that paces bond together in pairs is a limitation. If every female has to be accompanied by a male, then many (otherwise unnecessary) males have to be fed and maintained.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Male paces are considered difficult to keep as household pets because they spray females (or human substitutes) with a mixture of urine and glandular secretions. This can occur several times a day. In addition, they have anal glands that produce a musky odor that some people find objectionable.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">RESEARCH AND CONSERVATION NEEDS</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">Although paces are common in some areas over the vast region from Mexico to Argentina, they are little understood, even by zoologists. In fact, most data concerning this animal have come from interviews with local hunters. Intensive field work is needed to develop an understanding of the pace's biology, status, and habitat requirements.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The popularity of pace meat makes it urgent to start this work as well as to begin breeding paces on an organized basis. Such projects would lay the groundwork for preserving the species.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Particular research needs concern the following:</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">- Age structure and reproductive performance;</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">- Growth rates and feeding habits;</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">- Behavioral patterns in captivity;</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">- Nutritional requirements;</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">- Meat quality;</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">- Helminth and arthropod parasites;</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">- Role in transmitting or perpetuating diseases;</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">- Reproduction (such as external manifestations of estrus in females); and</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">- Genetic variations that would allow the selection of animals adapted to captivity and females that produce multiple offspring - twins, triplets, or more.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">Ways must be found to introduce more than one female to each male without inciting aggression. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<B><P>&lt;&lt;TOC3&gt;&gt; 24 Vizcacha</P>
+</B><P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&lt;&lt;I&gt;&gt; g027a.png FIGURE</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Vizcachas (Lagostomus maximus) are soft-furred South American rodents that look like long-tailed guinea pigs. They can weigh as much as 8 kg and are resilient animals, inhabiting dry pampas and shrub lands in northern Argentina and neighboring countries. They seem to have promise for producing meat and hides in marginal zones whithin their native habitat.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Like chinchillas (page 277), these rodents provide a prized furry pelt. They also provide meat that reportedly tastes "as good as hare," which in Europe is considered the epitome of dining. They are easily trapped alive in cheap, homemade, multiple-catch, funnel traps. And they are thought to be suitable for farming on a large scale.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">On the other hand, vizcachas are currently considered pests because they take grazing from cattle and sheep and because they build large burrows that undermine the land. Government campaigns have eradicated them in the richer agricultural areas of Argentina, but the animals are still common in marginal zones. There is evidence that they become more abundant when domestic livestock overgraze the land. In improverished marginal sites, where other livestock enterprises are unsuitable, the potential exists for game-ranching vizcachas.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">AREA OF POTENTIAL USE</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">Because of the potential hazard to new areas, vizcachas can be used only in the pampas regions of southern South America where they are already widespread.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">APPEARANCE AND SIZE</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">Vizcachas have short front legs, long, muscular hind legs, and round eyes and ears. Their heads seem oversized in proportion to their bodies. Males weigh 5-8 kg, females 2-4.5 kg.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Members of the same rodent subfamily as the chinchilla, they have a thick, soft, valuable fur that is grey or brown above, whitish or greyish below. They are, however, much larger than chinchillas.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Although basically running animals, vizcachas often jump bipedally (like kangaroos), and they sit erect while eating or grooming. The forefeet have four long flexible digits used to grasp food. Their soles and palms are naked and have fleshy pads (pallipes).</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">DISTRIBUTION</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">Vizcachas once swarmed widely over the savannas of southern Paraguay, Bolivia, and Argentina, but they are being systematically exterminated. Today they inhabit isolated areas of north, central, and western Argentina and southern Paraguay.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">STATUS</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">Since 1907, these animals have been mercilessly hunted. The governments of the Argentine provinces where they are mostly found, reward hunters for killing this "pest." However, the numbers are so reduced that now there is no need for a bounty system.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">HABITAT AND ENVIRONMENT</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">Vizcachas live in flat, dry, steppelike plains; in dry woodland (Chaco), and in low mountains.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">BIOLOGY</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">The fact that these rodents eat their own droppings (coprophagy) augments their ability to utilize natural forages, and allows them to abound in degraded zones. They feed on any plant materials they can find near their colonies, particularly grasses. In feeding trials, their daily dry matter intake was 2-5 percent of the body weight. The metabolic efficiency (dry matter per kg) was 33-56 percent; the digestive efficiency was 50-60 percent.2</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Male vizcachas become sexually mature at about seven months of age and remain fertile throughout the year. The gestation period is long: 154 days. Litters contain one or two young. Newborns are well developed, fully furred, and open eyed, although they cannot fend for themselves for at least three weeks. In the wild, one or two litters are reared each year.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">BEHAVIOR</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">Vizcachas are nocturnal and are active year-round. They inhabit underground burrows, living in colonies often containing many individuals. They collect a variety of materials (for example, bones, sticks, and stones), and heap them in piles above the entrances to their burrows.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Their hearing and sense of smell are acute. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&lt;&lt;I&gt;&gt; p274a.png Vizcachas native range</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">USES</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">Vizcachas have long been hunted for food as well as for their fur. Their meat is often consumed in pickled form in southern South America.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The skins are fabricated into table runners, rugs, bedspreads, slippers, and belts. The skins are also popular for overcoats.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Vizcachas can be kept in captivity without major difficulty.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">HUSBANDRY</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">In zoos, vizcachas are fed the typical diets furnished for vegetarian rodents: rolled oats, green vegetables, bananas, apples, and bread. They are usually kept indoors in wire-fronted cages, about 1 x 2 m in size, and provided with sleeping boxes.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Little is known about vizcacha husbandry, but in one trial, weight rose most rapidly in males until age 18 months (the average size was then 5.3 kg) and subsequently slowed. The heaviest male was 7.3 kg at 30-32 months. The female's weight gain was greatest until 16-18 months (average size 3.3 kg).3 </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">ADVANTAGES</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">The animals seem well adapted to harsh sites where the climate and forage make raising conventional livestock difficult.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The meat is white and has a good nutritive value because of its high digestibility, low levels of saturated fats, and high levels of proteins.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">In marginal zones of the pampas, these rodents appear far more productive than traditional livestock.4</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">LIMITATIONS</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">Vizcachas may do considerable damage by foraging in cultivated crops. As noted, ranchers claim that they take grazing away from domestic animals, 10 vizcachas eating as much as a sheep. In addition, they claim, vizcachas destroy pasture with their acidic urine. And the large burrow systems sometimes create a hazard.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Because their reproductive rate is low and their growth rate is only moderate, their commercial breeding might not be profitable except in well-designed projects with clear markets.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Vizcachas require sturdy pens, which implies a high initial cost for materials such as concrete and brick.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Vizcachas can be aggressive to one another, especially in captivity.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">RESEARCH AND CONSERVATION NEEDS</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">There are several possible research projects, including:</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">- Gathering specimens from different regions for comparative evaluation of characters such as biology, chromosome type, reproductive physiology, social behavior (both in its wild state and under controlled conditions);</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">- Attempting captive rearing and small-scale husbandry;</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">- Assessing performance under various environments; and</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">- Quantifying productivity and population dynamics in relation to rangeland use and improvement practices.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">A rational cropping program based on wild stocks is perhaps more viable than captive breeding. This could be organized so as to keep vizcacha numbers in check while sustaining a small chain of processing plants by providing a constant supply of meat and skins. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<B><P>&lt;&lt;TOC3&gt;&gt; 25 Other Rodents</P>
+</B><P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">The 10 previous chapters have described some rodent species that show promise as microlivestock. Rodentia, however, is one of the largest families of mammals, and the species highlighted by no means exhaust the possibilities. In this chapter we briefly mention others that deserve consideration and exploratory research. These might prove to be potential resources, at least in localized situations. Several are fast nearing extinction and they deserve protection and immediate attention from animal scientists.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">CHINCHILLAS</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">In the high Andes of South America are found the short-tailed chinchilla (Chinchilla brevicaudata) and the long-tailed chinchilla (Chinchilla lanigera). These plump little rodents have fur that is possibly the thickest, softest, and warmest of any animal's.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">On the surface they would seem to be ideal candidates for microlivestock in Third World regions. Indeed, in recent years chinchilla-rearing has been successfully carried out in northern India. However, raising these animals for commercial markets is a highly specialized and costly business because only rare and expensive breeding stock produces top-quality pelts, and all other pelts are worthless in today's marketplace.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">These guinea-pig-sized animals have round ears, a bushy tail, and range from 25 to 50 cm long. Adult males rarely weigh more than 500 g, but females may weigh up to 800 g.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">PACARANA</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">The pacarana (Dinomys branickii) is the third-largest living rodent only capybaras and some beavers are larger. But little is known about this seldom-encountered, forest-dwelling species. Nevertheless, pacaranas appear to be likely candidates for domestication. They are amazingly even-tempered and peaceful, and become surprisingly tame.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Because these animals are endangered they are unlikely candidates for microlivestock in the short run, but their large size and good meat could be the stimulus for an international effort to study, protect, and rear them in large numbers before it is too late.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Pacaranas are found along the eastern foothills of the Andes, including parts of Bolivia, Brazil, Colombia, Ecuador, and Peru. Their area of potential use is in Latin America and the Caribbean.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">It would be advantageous for livestock scientists to investigate this species in captivity. Studies are needed of the animal's general biology, including its nutritional requirements, reproductive capacity, behavior, and physiology. For wildlife specialists, there is a compelling need to protect this species.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">SPRINGHARE</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">Scattered through the dry lands of eastern and southern Africa - on numerous grasslands, plains, fossil lake beds, hill slopes, and floodplains - is the springhare (or springhaas). With its powerful hind legs, tiny forelegs, upright stance, and hopping gait, it looks something like a tiny kangaroo. It is commonly seen at night, eyes glowing a characteristic red in the headlights.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">This animal is an important source of food and skins for rural peoples throughout southern Africa. In Botswana, it is the principal bushmeat in the human diet.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Springhares are 35-40 cm long and weigh 3-4 kg. There is one species (Pedetes capensis) and two subspecies: the East African springhare and the Cape springhare (formerly Pedetes cafer). </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">ROCK CAVY</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">The rock cavy (Kerodon rupestris) is closely related to the guinea pig and occurs in the impoverished semiarid region of northeastern Brazil. It is large and lean and has a face somewhat resembling a dog's. It is hunted extensively and is an important source of meat for country people, who consider it a delicacy.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">This creature might be suitable as a microlivestock. It consumes leaves and bark, and breeds well in captivity. Famine is a serious periodic problem in the often-drought-stricken area, and protein deficiency is common. The rock cavy, like the guinea pig, may be amenable to domestication and may be able to provide the people with better nutrition. However, it is difficult to keep in a cage because it moves fast, climbs well, and easily slips out.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Because these rodents occur in rare and patchily distributed habitats, they are in desperate need of protection, whether or not they prove to have any long-term utility.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">SALT-DESERT CAVY</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">A smaller relative of the mare (page 256), the salt-desert cavy (Dolichotis salinicola) is rabbitlike in appearance and behavior. It has large ears and eyes, long legs, and a short tail. It lacks the mare's white rump patch.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">This animal inhabits dry, salty areas of the Chaco desert, particularly areas of dry, woody brush. Specifically, it is found in the saline western Chaco of Paraguay and northwestern Argentina, as well as in the extreme south of Bolivia. It is about 45 cm long and weighs up to 4 kg.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Although it might make a useful microlivestock in its native habitat, the salt-desert cavy breeds rapidly and can cause much devastation; it should never be introduced to new regions.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The salt-desert cavy's life in the wild is largely unknown; however, some have been successfully raised and bred in zoos. Exploratory research on keeping and managing these little creatures is warranted.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">OTHERS</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">As noted earlier (page 193), it has been estimated that 42 peoples of various cultures eat rodents. Most of these eat locally available species, some of which are listed below. Whether any have long-term usefulness is uncertain, but study of them in the wild and in captivity could result in some interesting and valuable scientific discoveries.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Solomon Islands Rodents</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">The Solomon Islands in the southwest Pacific are home to a collection of six rare giant rodents that live in the rainforest canopy. At one time they were important food items. Archeologists have dug up tens of thousands of rodent bones on sites where people lived as long as 30,000 years ago. These mysterious animals were classified last century, but most have not been seen by biologists for decades. However, one, the thinking rat (Solomys sapientis), was rediscovered in 1987 - the first time it had been reported seen since 1901. The others may also be inhabiting the dense and undisturbed forests.'</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The thinking rat was located on the island of Santa Isabel. It proved to be gentle, unafraid, and friendly. It lives in the forest canopy, weighs up to 1 kg, and feeds on nuts and fruits. Efforts to build up the population are urgently needed. The other species should also be sought.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Such animals could be a resource for rainforest production (perhaps in the manner of butterfly farming in Papua New Guinea2). They may never be plentiful enough to be food sources again, but they could nonetheless become valuable. Zoos the world over are likely first customers for these scientific curiosities if production can be boosted and the populations secured.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Giant New Guinea Rat</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">The giant New Guinea rat (Mallomys rothschildi) is often eaten in New Guinea. It is little known to science but is odorless and easily tamed. It grows so fast that it becomes as big as a guinea pig even before it is weaned. It feeds on a wide variety of tubers and vegetable products. An attractive species native to mountain forests, it has a long heavy tail and black fur with white ticking.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Porcupines</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">Porcupines, brush-tailed porcupines, and their relatives are distantly related to guinea pigs and are widely consumed as food in tropical regions. Examples are:</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">- Indian porcupine (Hystrix indica) and other species of South Asia.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">- Cape porcupine (H. africaeaustralis) of southern Africa.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">- Prehensile-tailed porcupine (Coendou prehensilis), which inhabits Central and South America. These nocturnal creatures live in the thick, leafy crowns of trees or in hollow trees or holes in the ground. Although often belligerent among themselves, they can be very friendly and tame toward humans.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Kiore</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">The kiore (Rattus exulans) was formerly an important component of  the diet of most Polynesians, including the Maoris of New Zealand. It  has been successfully reared in captivity in recent times. Unlike many  other rodents, this animal is normally not a scavenger; it is a clean,  even fastidious feeder that is basically a vegetarian (flowers, berries,  nuts, and seeds) and is reckoned remarkably good eating.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Soft-Furred Rat</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">The soft-furred rat (Praomys) is relatively large and slender and is  found in the tropical forests of Africa from sea level to more than  3,000 m. Among the most common rodents of the African jungle, it is  trapped almost everywhere. It feeds largely on plants, but eats large  quantities of ants and other insects. It has been raised successfully in  captivity and is eaten by villagers in Malawi.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Giant Squirrels</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">The giant squirrel (Ratufa bicolor) occurs throughout Indonesia,  Malaysia, and Sri Lanka. It is the largest squirrel on earth, almost the  size of a cat. A related species, the palm squirrel (Funambulus), also  gets very large. It can crop nuts in the very high treetops that are  inaccessible to people. It is widely used as food.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Squirrels</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">Squirrels of the genus Callosciurus (notably C. notatus and C.  prevostii) are significant pests on cocoa, oil palm, and mixed fruit  plantations in Southeast Asia. They can be reared and bred on a diet of  most types of fruit as long as a little protein, in the form of insects or  cooked wheat, is available. The systematic use of this animal may  offer a chance to turn a pest to advantage.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Cloud Rat</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">Two species of slender-tailed cloud rats (Phlocomys spp.) are found  only in southeastern Asia. They live in tree cavities, climb well, and  are well adapted to tree life.  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">One of these (P. cumingi) lives in the northeastern part of Luzon in the Philippines, where it appears to be thriving. It has a large body and long tail and is the largest member of the mouse subfamily.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The other (Crateromys schadenbergi) has long, thick hair and a thick, bushy tail. It lives in the mountainous areas of northern Luzon. A nocturnal animal, it feeds on buds, bark, and fruits.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Both are attractive, even fascinating, creatures that are relentlessly hunted for food. They might make useful livestock in forest situations.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Spiny Rat</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">The Cayenne spiny rat (Proechimys guyannensis) is found throughout most of South America. It is tasty, easily kept in captivity, and is popularly used in Colombia for food. A nocturnal animal, it is one of the most common mammals in many areas. It has been raised in captivity on bananas, sweet corn, coconut, grain, and various seeds.3</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Bamboo Rat</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">The bamboo rat (Rhyzomys spp.) is the largest rodent on the island of Sumatra in Indonesia; it weighs 2-4 kg and the body can be as long as 45 cm. It prefers to live in bamboo thickets and is hunted and eaten by many local peoples.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">There is a need - in considering any sort of game farming - to relate the animal's "preferred" conditions (range, feed, temperature, etc.) to the varying land and climate types not being effectively utilized. In other words, rather than looking at animals that might be farmed, it might be necessary to consider the terrain and climate and then seek animals that would "do" well under those conditions. One major fault with traditional farming has been the tendency to force traditional livestock onto unsuitable land. This has given rise to numerous serious problems. In many cases the most suitable use of an area is provided by several species grazing together to mutual benefit (e.g., goats and sheep on New Zealand hill country improve grazing for each other if ratios are right).</P>
+<P ALIGN="JUSTIFY">David Yerex</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&lt;&lt;I&gt;&gt; g028a.png FIGURE</P>
+<P ALIGN="JUSTIFY"></P>
+<B><P ALIGN="CENTER">&lt;&lt;TOC2&gt;&gt; Part V : Deer and Antelope</P>
+</B><P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">Several types of tropical deer' and antelope are no bigger than an average-size dog. These "microdeer" and "microantelope"2 are the smallest of all ruminants. Although there is considerable experience with rearing and utilizing the larger species, little is known about these miniature ones.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Given research, mouse deer, muntjac, musk deer, pudu, brocket, huemul, and water deer, as well as half a dozen small antelope, might prove to have considerable potential. Collectively, they come from diverse habitats, ranging from equatorial to subarctic and from moist rainforest to arid savanna. They are adapted to some environmental conditions that are only marginal for production of conventional livestock because of drought, heat, diseases, altitude, or other constraints.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">DEER FARMING</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">Deer appear to be unlikely candidates for livestock, but reindeer were probably among the first domesticated animals and have been draft animals for perhaps 2O,OOO years. Even today, tens of thousands of reindeer pull sleighs in the European arctic. On military expeditions, the ancient Romans took along herds of fallow deer as a source of meat, and more than 1,000 years ago deer were annually herded off the Scottish Highlands for winter meat supplies.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">In recent years, there have been breakthroughs in the "domestication" of deer. Species already being [armed are: red deer (New Zealand, Australia, Taiwan, Korea, Russia, China, Scotland, the United States), elk (New Zealand, Canada, the United States), fallow deer (New Zealand, Australia, England, Denmark, Sweden, Switzerland, Germany, the United States), ruse deer (Australia, Mauritius, New Zealand, Papua New Guinea), sika deer (Taiwan, New Zealand), musk deer (China, India), and PFre David's deer (New Zealand). Although not truly domesticated, even the moose has been tamed in Scandinavia and the Soviet Union, the calves being bottle-raised from three days of age.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">New Zealand has made particular progress in domesticating large deer (see sidebar). It seems probable, therefore, that similar success with small deer could be achieved. For those seeking interesting, pioneering research, microdeer are good candidates.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">ANTELOPE RANCHING AND FARMING</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">The worldwide experiences in domesticating various deer species suggest that the organized production of small antelope should also be considered. Several large species have already been studied and are used in game farming in eastern and southern Africa. Similar research on the smaller species, which so far have received little or no attention, is one of the more speculative ideas in this report. We put it forward only for consideration by researchers, but if exploratory studies prove successful, this is a topic deserving international support.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">In some parts of Africa there are large expanses of uninhabited lands, and producing any sort of livestock there is limited by aridity and by the presence of tsetse flies. But in this habitat live tiny antelope such as dikdik, suni, and klipspringer. In the rainforests and secondary forests are found duikers and the royal antelope. All these creatures have advantages that justify their consideration as microlivestock: they have a more rapid turnover than the big species, and they produce a high yield of quality meat. In addition, compared with cattle, these native ungulates make better use of the habitat. Cattle select a limited number of grass species; antelopes choose a wider range, and also include fortes, bushes, and trees.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">More important perhaps is their resistance to many diseases. Most, if not all, are resistant to trypanosomiasis, the disease carried by the tsetse fly. They are not immune to this and other tropical diseases, but they are less susceptible than cattle. However, part of this may be owing to their ability to roam widely; if confined and treated like domestic animals, they may also require some protection against parasites and diseases.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Antelopes are also more productive than cattle; that is, they produce a given quantity of meat more quickly because they breed better in the African hinterlands and grow more rapidly on its existing forages. On the other hand, they generally require a richer diet than cattle.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Finally, in their favor, antelopes affect the habitat less than the same density of cattle does; they spread out more while feeding and thereby cause less erosion.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">There are two ways of exploiting this potential. One is by "cropping"taking a controlled offtake from free-ranging populations without depressing the overall population. Several methods for producing meat this way from large antelope have been attempted in countries such as Kenya, Tanzania, and Mozambique. Few have persisted. Often this has been due to opposition from the vested interests of the cattle industry and from stringent veterinary requirements. Nonetheless, game ranching offers a means by which marginal lands could produce food of a high nutritional quality on a sustained basis.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The other method is by farming - that is, domesticating or partially domesticating the animals, keeping them in pens or herding them like cattle. Experiments in farming antelopes have been less common than game ranching, but one of the most interesting is that conducted on the Galana Ranch in Kenya. Three wild species - buffalo, eland, and oryx - were selected for comparison with cattle. Half-grown animals were preferred for capture, and it was found that if they were kept in the dark for the first week after capture, and then gradually provided with more and more space while they became familiar with people, after about six weeks they could be released into the open and herded from place to place. Grazing during the day under the eye of a herdsman, they allowed themselves to be herded back to a pen at night in the traditional African manner, where they would sleep around the campfire. This was a promising advance in behavior modification leading toward domestication. The oryx, for example, gained weight on grazing that would not even sustain cattle, and it required only a quarter of the amount of water.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">At bottom, the question is not what contribution antelopes can make to the African larder, for they already make a significant contribution through (largely illegal) hunting. The question is whether farming could make them a sustainable asset rather than their being senselessly squandered, as is the case at present. Although its potential has yet to be realized, antelope farming is not a panacea for Africa's food problems, and certainly not the world's, but it might pave the way to a new and more gentle way to make savannas useful. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">TAME GAME</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">Since the 1970s, deer have taken the place of sheep on many New Zealand pastures, and today the country has more than 5, 000 deer farms carrying over one million head, mainly red deer. It is now common along country roads to see tall fences surrounding graceful deer quietly grazing ryegrass and clover. And there are all the appurtenances for deer that exist for cattle and sheep. Auctions and shows are held regularly. Deer farmers have a professional association and produce their own glossy magazine. Government scientists publish pamphlets on the care and management of deer. There are recognized stud stags, computerized recording schemes for breed improvement, and even veterinary services specifically for deer. Hybridization between wapiti and red deer, and PFre David's deer and red deer, is accepted practice. The animals are moved by use of dogs (which command by mere presence rather than by bark or bite), and herds of up to 80 are shifted by truck. Slaughter facilities specifically for deer are in operation throughout the country.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">This transformation of a nervous, jumpy, and retiring wild species into a farm animal is a remarkable achievement. Once accustomed to people, many specimens become gentle, even affectionate, and will come at a farmer's call. Males are generally as easy to handle as females, except during the rutting season when they become aggressive and cannot be handled at all.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">However, even at the best of times the farmed deer must be handled gingerly. If the causes of stress are not quickly suppressed, hysteria can erupt throughout a herd; in an instant, quiet animals can be leaping suicidally in all directions, disoriented, diving head-on into fences, charging gates. Chronic stress, the causes of which are not always obvious, can result in illness or death, although this trait diminishes in subsequent generations of farm-born stock.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">A deer farm has to be laid out to certain special specifications. To prevent escapes, the boundary fences must be 2 m high with netting of 15- or 30-cm mesh. Inner fences need only be 1.5 m high. Water troughs are placed in the middle of the fields, and nothing is allowed to jut inwards from the fences because the animals tend to walk fencelines and take comfort from the illusion of openness. Because deer like to wallow in hot weather, some farmers also provide shallow waterholes.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Deer yards can be of any design, but the sides of the passageways and holding pens should be solid, as deer do not see fences very well, particularly when under pressure, and may injure themselves in a leap towards what appear to be wide open space. (New Zealanders usually make the sides of plywood.) Also, the holding pens should be roofed, as semidarkness has a calming effect. Animals that in the sunlight become hysterical on seeing a person in the distance, can, in the relative darkness of a roofed shed, be touched and even given injections.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Despite the special facilities, however, handling deer takes time and care and experience. The most successful farmers spend much time among the deer so that the animals become accustomed to human presence. This helps to make yard work easier. Also, new arrivals are allowed to wander through the yards on their own to become familiar with them. In addition, special tame deer are used as leads or decoys to encourage the rest of the herd to follow. Using such simple techniques, a formerly intractable species has become almost fully domesticated.</P>
+<P ALIGN="JUSTIFY"></P>
+<B><P>&lt;&lt;TOC3&gt;&gt; 26 Mouse Deer</P>
+</B><P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&lt;&lt;I&gt;&gt; g029a.png Lesser Malayan Deer</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Mouse deer1 (Tragulus spp. and Hyemoschus aquaticus) are among the smallest ruminants known. The lesser mouse deer of Southeast Asia is probably the smallest; an adult stands only 20 cm high and weighs a merc 1-2.5 kg.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Although they look vaguely like tiny deer, mouse deer differ in several particulars. The stomach is simpler and (like the camel's) has three instead of four effective compartments. Rumination occurs, but mouse deer are the most primitive of all ruminants. Indeed, they share a number of characteristics with nonruminants, including lack of horns or antlers; continually growing, tusklike upper canines in males; sharp-crowned premolars; and four fully developed toes.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Virtually unchanged in 25 million years of evolution, these are solitary, nocturnal, retiring animals that have seldom received detailed research. Whether they might make suitable microlivestock is unknown. However, they seem to be tractable, and people in Southeast Asia (Sarawak, for instance) have traditionally kept at least one of the species as backyard pets. Moreover, mouse deer are indigenous to tropical lowland regions and withstand the heat and humidity that are stressful to most conventional livestock species. They probably also are resistant to many diseases of those torrid regions.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">In the United States, mouse deer are being raised as laboratory animals for basic research on ungulates. This is because the animals are easier to handle than large deer or goats.2</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">APPEARANCE AND SIZE</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">Mouse deer are graceful, lithe, and look somewhat like large rodents. The Asian species are the shape and size of an agouti (see page 198); the African species is more like the pace (see page 262). All have short legs, a small head, and a pointed snout. Adults weigh from 1 to 5 kg, depending on species. The head and body are only 04-1 m long, and the shoulder height is merely 20-36 cm. Males are generally smaller than females.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">In most species the body is a rich brown with white spots and stripes. The belly is usually white. The animals stand on the middle toes, so that the lateral ones do not touch the ground. Neither sex bears antlers. In males the upper canines form long tusks that may extend outside the lips and even to below the line of the jaw.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">DISTRIBUTION</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">Twenty-five million years ago, early forms of mouse deer existed throughout Asia, Africa, and Europe. Today's species are restricted to tropical forests and mangrove thickets of Southeast Asia and Central Africa.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Of the three Asian species, the Indian mouse deer occurs in southern India and Sri Lanka; the larger Malayan mouse deer occurs on the mainland of Southeast Asia and the lesser Malayan mouse deer occurs on Java as well. The water chevrotain, a related African animal, is found from eastern Zaire to the Atlantic coast. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&lt;&lt;I&gt;&gt; p292a.png figure</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&lt;&lt;I&gt;&gt; p293a.png Range of water chevrotain .</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">STATUS</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">In recent years, human encroachment into the forest has caused the destruction of the mouse deer habitats and has put various mouse deer species under a pressure that is causing their populations to decline.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">HABITAT AND ENVIRONMENT</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">These animals inhabit equatorial forests and mixed secondary tropical forest. They generally live among undergrowth on the edges of dense lowland rainforests. They especially haunt rivers and swampy bush areas, seeking escape by water when in danger.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">BIOLOGY</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">Little about these animals is recorded. Essentially vegetarians, they feed chiefly on fruits, supplemented by leaves. They also eat insects (for instance, ants), if available. They do not seem to eat grass.3</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The premolars of the mouse deer are designed for piercing and chopping food rather than for chewing. As noted, the stomach consists of three functional compartments: the rumen, the reticulum, and the abomasum. (The omasum of ruminants is represented only by a rudimentary area.) The stomach occupies almost the whole of the abdominal cavity, extending from the diaphragm to the pelvic inlet, which provides this small animal with large food-storage capacity.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The blood has a very high erythrocyte (red blood corpuscle) count as well as the smallest erythrocyte size of any mammal. The flesh is "white" and the muscles contain little myoglobin.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Mature females reproduce almost continuously, and usually regardless of season. In the female larger Malayan mouse deer, mating occurs within 2 days of giving birth. In the African species, many births are synchronized with the rainy seasons, when fruits are plentiful. The gestation period is about 5-6 months, depending on the species. There is only one young per birth. Weaning normally occurs at 2-3 months, but can occur as early as 3 weeks, with sexual maturity achieved at 4-5 months (Asian species) and 10 months (African species). The young stay alone, hidden in vegetation during the first month or two.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">BEHAVIOR</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">Mouse deer are shy, keeping to dense jungle and depending on concealment for protection. Although often present in large numbers, they are seldom seen. Preferring to be near lakes, rivers, or streams, they can nevertheless wander I km or more from water. They feed mostly at dusk or at night, sheltering in undisturbed areas or under shady bushes during the day. They utter weak, bleating sounds, and when frightened, jump a meter or more in the air.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Communication is by scent and calls. The African species possess anal and preputial glands, with which, along with urine and feces, they mark their home ranges. Males of both Asian and African species possess a chin gland to mark either the vegetation or their mates.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Mouse deer are among the most excitable, nervous, and jumpy animals. One must tread softly in their presence for fear of causing absolute pandemonium and mishap.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">USES</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">Mouse deer are widely sought by native people for food, and their meat is highly regarded. Dressed carcasses have a high proportion of muscle (84 percent in Asian species), low proportion of bone (15 percent), and an insignificant amount of fat. The ratio of muscle to bone is large - 5.6:1. The mean dressing percentage of 62.1 percent is greater than that reported for cattle, water buffalo, or goat.5</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">HUSBANDRY</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">Adults are wild, generally intractable, and "flighty," but young animals (at least of the Asian species) tame readily and make good pets. Nevertheless, these are delicate creatures and must always be handled gently. Individuals caught in the wild tend to bash against the sides of cages.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Despite an unpromising temperament, Asian mouse deer are regularly bred in zoos, including those in Amsterdam, New York, and Zurich. They also have been reared successfully in small enclosures at several research institutes, such as the I.R.E.T. Institute, Makokou, Gabon; the Institute of Medical Research in Kuala Lumpur, Malaysia; and at Fort Detrick in the United States.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Perhaps the best way to breed this animal is by using the battery system of small units comprising one male and two females per cage. The costs are mostly for obtaining suitable enclosures and for feeding and watering troughs.6 The cages must be covered with mesh because the mouse deer can jump. However, the covering must be sufficiently high to allow the male to stand with its body vertical during copulation.7 They can be fed a variety of foods and grow well on stems of bean plants.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">ADVANTAGES</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">As noted, these are small, seemingly tractable creatures that are at home in the heat, humidity, and diseases of tropical lowlands. They might play a particularly important role as livestock for tropical rainforests; the forests could be left standing while the animal still produces meat. Today, in a widely condemned process, tropical rainforests are being felled in order to raise cattle for meat. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">LIMITATIONS</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">Small size makes mouse deer easy prey for various predators. In the wild, snakes, crocodiles, eagles, and forest cats feed on them.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Mouse deer are among the most excitable, nervous, and jumpy animals. One must tread softly in their presence for fear of causing absolute pandemonium and mishap.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The different species are solitary, and it is difficult to keep many individuals (especially males) in a restricted space. They must be kept in a quiet enclosure, with cover or good shelters.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">RESEARCH AND CONSERVATION NEEDS</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">The survival of these four "living fossils" depends on conserving their rainforest habitat and restricting hunting, especially night hunting. But studies of their propagation and management are also imperative.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">In particular, research is warranted on various aspects of their husbandry, such as enclosure design, space requirements, and health. A special research need is to understand the animal's nutritional requirements and to develop diets for use in captivity.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<B><P>&lt;&lt;TOC3&gt;&gt; 27 Muntjac</P>
+</B><P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&lt;&lt;I&gt;&gt; g030a.png FIGURE</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Muntjac, or barking deer (Muntiacus species), are among the most widespread but least known of all Asian animals.1 They are almost the size of an average dog and they bark, but they are true deer. These little animals adapt well to captivity and have been introduced to zoos and wildlife collections throughout the world.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">In recent years one species, the Reeves' muntjac, has become established in England, and a few specimens have settled into semicaptivity - staying behind fences, accepting human presence, and even eating out of people's hands. In Sarawak, villagers have also been known to keep muntjac, feeding them a diet of rice with some leafy matter occasionally added.2 Such experiences show that these small, shy deer can be calm and adaptable. It also shows that they can be raised on practical, artificial diets and that they are not strictly browsers. This creates the possibility (admittedly highly speculative) that they might make future microlivestock.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Muntjac produce lean, palatable venison and perhaps could be farmed on an organized basis. They are native to severe environments where heat, humidity, and endemic diseases make raising conventional livestock difficult. In future, given research, muntjac might become widespread contributors to Asian economic development. The lessons learned in captive breeding could also be important for conserving endangered muntjac species.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">One species, the Indian muntjac, has an incredibly low chromosome number (2n=7 in males; 2n=6 in females), which makes them particularly promising candidates for mammalian genetic studies. This species has regularly bred well in both zoos and research institutions.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">APPEARANCE AND SIZE</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">Muntjac are small and slender. Reeves' muntjac, the smallest, has a shoulder height of 45-60 cm. Fully grown, it weighs less than 20 kg; commonly it is merely 10-12 kg. The Java subspecies of the Indian muntjac is the biggest, with a shoulder height of 58 cm and a mature weight of 43 kg.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Antlers on the males usually include a main prong as well as a much shorter brow tine. Even the main prong is no larger than a finger, but its pointed tip is hooked and must be treated with caution. There are also two tusklike canine teeth that protrude from the mouth. These have sharp points and a knifelike posterior edge, capable of cutting to the bone a person's finger or another muntjac's rump.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Coloration varies from deep brown to yellowish or greyish brown with cream or whitish markings, depending on the species.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">DISTRIBUTION</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">Muntjac are native to a vast region from eastern China to Nepal, India, Sri Lanka, and Indonesia.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Almost a century ago, Indian and Reeves' muntjac were introduced to a deer park in southeast England. Some escaped, and (as noted) the Reeves' muntjac has adapted, spread, and settled down to life in the countryside.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">STATUS</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">Of the five muntjac species, the Reeves' and the Indian are well known and in no danger. For instance, recent estimates of annual game production have shown that there are about 650,000 Reeves' muntjac in China. The other three are threatened with extinction. Black, Roosevelt's, and Fea's muntjacs are virtually untried in captivity, but the success of raising Reeves' muntjac in English country gardens suggests that perhaps their populations could be saved through captive breeding.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">HABITAT AND ENVIRONMENT</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">In their native habitats, these small deer are usually found in dense vegetation on hilly ranges at elevations up to at least 3,000 m.3 </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&lt;&lt;I&gt;&gt; p301a.png The native ranges of the various muntjacs</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">BIOLOGY</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">Muntjac seem to be primarily browsers. However, in captivity they eat fresh grass, alfalfa hay, and feed pellets. They also readily eat root crops such as potatoes, carrots, and parsnips. They are "concentrate selectors," preferring foods low in fiber and rich in protein and nutrients. Captive specimens reportedly need; a supply of cut browse.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Breeding may occur year-round, but in practice it is synchronized with certain seasons. The first conception can occur as early as 6 months of age. One, occasionally two, young are born after a gestation of about 200 days. They weigh around I kg at birth, and the fawns usually remain hidden until they can move about with the mother. The females mate within a few days of giving birth. Life spans up to 16 years have been recorded.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">As noted, the Indian muntjac is a species of great cytogenetic interest. It has the lowest diploid chromosome numbers yet found in a mammal.4 The large, easily distinguishable chromosomes are a great advantage in tissue culture, and many laboratories now have muntjac cell lines. The karyotypes of the different species' chromosomes are very different; the Indian and Reeves' muntjac can hybridize, but the offspring are infertile.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">BEHAVIOR</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">Muntjac are dainty and have a captivating charm. Always on the alert, they are active both day and night. Often they will bark for an hour or more, but typically they bark for only a minute or two. When panicked, captive muntjac may rush into fences or walls. They can easily leap barriers 1.5 m high.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Males are highly territorial and defend their territories vigorously. Adult females also inhabit a specific territory, which they defend against strange individuals.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Males mark the ground at intervals by lowering the head and rubbing the frontal glands on the ground and by scraping their hooves against the ground. They mark trees by scraping the bark with the lower incisors and rubbing the base of their antlers.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">USES</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">In Asia, muntjac are hunted for meat, skins, and antlers.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">HUSBANDRY</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">Muntjac thrive and, at least under ideal conditions, breed freely in captivity. However, they may stop breeding if they are crowded.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">In England, zoos and private collections keep as many as six muntjac in an area of 40 x 20 m. Plenty of cover is provided for the animals to hide in. Fences almost 2 m high are used. (Lower fences are reportedly adequate where there is no risk of the deer being panicked by dogs or people.)</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">ADVANTAGES</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">Like other deer, muntjac produce extremely lean meat.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">They seem to be healthy animals. In Britain, wild and captive muntjac have few gastrointestinal worms, and ectoparasites such as ticks and lice are not a problem. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">MUNTJAC</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">In England, far from Asia's forests and mountains, the Reeves' muntjac is the subject of a peculiar chapter in the otherwise unhappy history of introduced species. Charmed by the deer's odd characteristics, the British have welcomed its invasion into gardens around the country. Now, there are tens of thousands of muntjacs on the loose, and some people have even adopted them as pets.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Although other alien species have wreaked havoc on native plants and animals, muntjacs appear to be a merciful exception. At least over the short term, muntjacs "have proven to be an almost innocuous asset to the countryside. They give pleasure to thousands and pain to few. Eating mostly ivy, grass, leaves, and prickly bushes, they rarely feed in one place long enough to do much damage except to an occasional suburban garden." </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Life for many muntjacs is made soft by homeowners who find the deer's large, dewy eyes and tiny antlers irresistible. The kind-hearted suburbanites put out salt licks, water, and kitchen scraps, and they built snug little shelters against the cold north wind. "All our adult deer will take food from the hand," says Walter Buckingham, who has kept muntjacs for five years in his garden in the county of </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Hertfordshire, just north of London.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The adaptable immigrant is colonizing new areas so rapidly, say biologists, that soon there may be more in England than in Asia. "In time," predicts muntjac-researcher Oliver Dansie (pictured opposite), "it may eventually establish itself as our most widely distributed deer species."</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">LIMITATIONS</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">In the wild these animals are not gregarious and are generally found alone or in pairs. Because of their strong territorial instincts, large males may not be able to be kept together without fighting. The upper canine teeth can inflict serious wounds. Some females are intolerant of each other as well.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Muntjac are fragile; they cannot be held by the legs, for example.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Some infectious diseases may prove to be of epizootic importance: foot-and-mouth disease, mucosal disease, epizootic hemorrhagic disease, rinderpest, and tuberculosis (all three types). This may be a problem, especially when people are raising the animals by hand.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">RESEARCH AND CONSERVATION NEEDS</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">To ensure a better understanding of their potential as microlivestock, muntjac deserve research and recognition from animal scientists and conservationists from Nepal to China. The English experience shows how populations of the endangered species might be built up. At present, however, none are receiving any husbandry research; only the two most common species can generally be found in zoos.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">These animals deserve investigation into physiology, reproductive requirements, fertility, nutrition (for example, food preferences, feeding strategies, and food utilization), growth, adaptability and environmental tolerance, diseases, management, social structure, and selection for calm temperament. </P>
+<P ALIGN="JUSTIFY"></P>
+<B><P>&lt;&lt;TOC3&gt;&gt; 28 Musk Deer</P>
+</B><P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">The musk deer (Moschus species)1 is so small that (like other ungulates in this section) it is only as large as an average-size dog. A gland in males produces musk, a thick, oily secretion that is one of the most valuable substances in the animal kingdom. Musk is used in Oriental Medicine as well as in Europeans perfumes, and in recent year it has sometimes sold for as much as three times the price of gold.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Musk is traditionally obtained by killing these deer and removing their glands. The dried glands, called pods, contain a reddish brown musk powder that has been a commodity in international commerce for more than 1,000 years. Despite bans in India (1972) and Nepal (1973), musk continues to be illegally exported, mainly via Hong Kong, for use in Japan and Europe. In Japan, for example, it is an ingredient in more than 200 different medicines.2 In Europe, musk goes into some of the most famous perfumes.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The international trade in Himalayan musk, originating from both northern and southern sides of the Himalayan divide, amounts to 200 kg per year, representing an annual slaughter of 20,000-32,000 male deer.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The commercial value of the animal makes it highly attractive for development as a livestock species. The economic force causing its slide toward extinction could be employed to protect and restore both the species and its habitat. Ranching these deer might put musk production on a sustainable footing. It might also encourage habitat protection, because in the harsh climate of the high Himalayas, rearing musk deer could be much more profitable to villagers than raising crops or cattle.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Musk deer are already being farmed under primitive conditions in China, where techniques for extracting musk without killing the animal have been developed. In India, small collections of musk deer have been established by the forest departments of Himachal Pradesh and Uttar Pradesh. For several years authorities in Nepal have successfully extracted musk from an adult male at the Kathmandu Zoo' without apparent harm to the animal.3 These experiences suggest that musk might become a farmed product. So far, however, success has been limited. The Chinese animals, for example, have a high mortality rate and the musk is said to be of poor quality. Nonetheless, these examples are valuable pioneering case studies that deserve recognition, support, and further development.4</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">APPEARANCE AND SIZE</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">With their long ears, arched back, and bounding gait, these diminutive deer remind one of large hares. The pointed face and large ears make their heads strikingly reminiscent of kangaroos. The coarse hair gives them a stocky appearance. The color varies according to species (and subspecies) from rich reddish brown to dark grey or black. The peculiarly brittle and wavy hair probably has good insulating properties, as it consists of air-filled cells arranged like a honeycomb.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Musk deer have an average mature weight of about 6-11 kg and a body length of 50-90 cm. They stand 50 60 cm high at the shoulder and 5 cm higher at the rump because the hind legs are longer than the forelegs. Some dwarf types are only 40-46 cm high. The tail is short, and in males it is naked, except for a terminal tuft of hair, because they mark their territories by constantly rubbing the caudal gland, which is located near the tail, onto objects.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">All four toes are flexible, which, compared to the rigid hoof of other ungulates, gives a firmer grip on precipitous slopes. The dew claws are enlarged and, together with the central digits, splay out, to minimize sinking in soft snow.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Neither sex possesses antlers, but males have long upper canine teeth that project well below the lips. The lower front teeth have a spatulate form that probably helps the animals scrape lichens from the surfaces of rocks and trees in winter, when most vegetation is snow covered. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&lt;&lt;I&gt;&gt; p309a.png The musk deers native range.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">DISTRIBUTION</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">The genus is distributed patchily throughout the forested mountainous parts of most of Asia. One population extends from just north of the Arctic Circle southward to the northern edge of Mongolia and Korea. Others occur in China, northern Vietnam, and the Himalayan region including Bhutan, Assam, Tibet, the Indian Himalayas, Nepal, and northern Pakistan.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">STATUS</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">During this century, the musk deer has rapidly declined throughout its former regions. In many parts of Afghanistan, Pakistan, India, Nepal, and probably Tibet, it is already regarded as rare, with a distribution that is becoming increasingly localized. Possible exceptions are Bhutan and most of China, where its population is thought to be stable. In southern China, a recent estimate puts the musk deer population at 100,000 head. In western and northwestern China, the population is estimated at 200,000-300,000 head.5</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">It is the uncontrolled hunt for musk that in most places is driving this animal toward extinction, but its habitat is also being increasingly destroyed by livestock and woodcutters. Part of the loss to hunters is owing to the mindless way in which the animals are caught. Most are snared in traps or nets or killed by poisoned stakes set on trails. This kills all the animals indiscriminately, even females and fawns, which produce no musk. This waste of reproductive animals is extremely destructive to the populations and is senselessly hastening the musk deer's extinction.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">HABITAT AND ENVIRONMENT</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">Musk deer mainly occur in upland woodland and scrub areas. They prefer remote, dense vegetation, especially birch-rhododendron forests in mountainous terrain. They are seldom found in treeless regions or areas thickly populated by people. In the Himalayas, the upper limit coincides approximately with the tree line, which is as high as 4,600 m at the eastern end.6</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">BIOLOGY</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">Despite its economic importance and wide distribution, little is known of the musk deer's biology. Nonetheless, it is known that musk deer have a gall bladder, a bovid feature that distinguishes it from the true deer.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The animals are browsers, relying on young leaves, buds, fruits, and flowers. During the winter, as snow deepens, they depend more on lichens growing above the snow on rocks or tree bark, although in shallow snow they scrape for vegetation with their hooves.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The male's musk sac is unique among deer. Situated between the umbilicus and penis, it contains the gelatinous, odoriferous oil. The amount varies with the season and the age of the animal, but pods of adult males usually weigh about 30 g; occasionally up to 45 g.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Males also have a caudal gland under the tail, which secretes a viscous yellow substance with a goaty smell. They mark vegetation with this secretion by rubbing their hindquarters against stems and branches.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Males become sexually mature at about 18 months, but females seem capable of reproducing in their first year. The estrous cycle is 18-25 days; the receptive period lasts 36 60 hours. Gestation varies from 178 to 192 days. Each female usually bears one or two fawns, rarely three. The fawn is precocious - able to stand and move within 15 minutes. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">BEHAVIOR</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">Musk deer are shy, furtive animals with keen senses of hearing, smell, and sight. They are normally solitary and are most active at dawn and dusk. Only under cover of darkness do they frequent the more open spaces. Except in the rutting season, more than two animals are seldom seen together; groups usually consist only of a female and her young. The alarm call, a loud hiss, is often accompanied by a highstepping, springy gait.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">In the wild, musk deer lead "orderly" lives. They use well established trails connecting well-established feeding places, resting places, and "latrines" where they deposit their droppings. Migration is uncommon.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Remarkably sure footed, musk deer climb cliffs and even the trunks of leaning trees. Being small and solitary, they rely on camouflage to avoid predators but flee through established escape routes when disturbed. If cornered, males defend themselves by slashing with their tusks, often inflicting deep cuts and severe injuries.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">USES</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">The strong-smelling, reddish-brown musk is obtainable only from this animal.7 It is used as a fixative in expensive perfumes to increase the retention of the fragrance on the skin. In Oriental medicines it is used in stimulants, sedatives, and other products. Some medicinal properties appear to be genuine.8 Recently, highly purified musk has been selling for as much as $27 a gram.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Trade in the Himalayan musk deer or its products is banned by all countries that are parties to the Convention on International Trade in Endangered Species of Wild Fauna and Flora (CITES). However, products from musk deer in the Soviet Union and China can be traded legally under license. It seems likely that if formal, self-sufficient, musk-deer farming projects can be established elsewhere, with safeguards to minimize poaching, a wider trade would be officially sanctioned.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">HUSBANDRY</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">Since at least 1919, Chinese scientists have been experimenting with the extraction of musk without killing the males. When the sexual activity is at its peak, the males are caught and musk removed from the pod with a runcible spoon (curved fork) inserted into the sac's aperture. The procedure takes only minutes. There are records of up to 9 g being recovered at a time.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">As noted, China established formal musk deer farms in 1958. They are clustered in the Maerkang, Miyalo, and Manchuan areas of Sichuan Province; the Zhenping county of Shanxi Province; and the Fuziling area of Anhui Province. Despite heavy initial losses of animals, mainly during transportation and acclimatization, the Chinese now breed musk deer in considerable numbers. However, juvenile mortality is still high and longevity relatively short. Zoos in other parts of the world have also had difficulties maintaining the animals.9</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">In captivity, musk deer readily accept many foods: lettuce, carrots, potatoes, apples, rolled oats, hay, alfalfa, bananas, some grass, bamboo leaves, and pumpkins, for example.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">LIMITATIONS</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">The musk deer's social system may represent an impediment to its successful reproduction in captivity. It is irascible and scares easily. In close confinement, males fight and may have to be isolated from each other.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">There is an inherent danger in any captive-breeding scheme in the Himalayas: resumption of legal trade in natural musk could damage the remaining populations by stimulating the market and providing an outlet for illicit musk from poached animals. Some biologists (notably in India) consider that a total ban on the trade in natural musk from all sources is essential.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">So far, removing the musk without damaging the animals has not proved commercially successful because of market resistance. Most purchasers require the entire pod in order to be certain that they are receiving the genuine product. Given a regularized farming program, however, it seems likely that mutual trust would circumvent this lack of confidence.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">RESEARCH AND CONSERVATION NEEDS</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">To protect this species will not be easy. It occurs in vast, remote areas that are difficult to patrol. The local people are poor and traditionally have used it as a source of income and food. The value of musk is so high that smuggling is already well organized and will be difficult to eradicate.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">It is imperative that the status of existing musk deer populations be established. This is especially important in Nepal. The total population may be not more than 500 in the wild.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">No matter what is achieved in farming, pressure on populations will only be reduced by protecting the wild specimens. Thus, the dietary requirements and behavior of musk deer should also be evaluated with a view to building up the wild populations directly. If the techniques of breeding and handling can be improved, farming the animal may also indirectly help wild populations by reducing the pressure to harvest them.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">An alternative to captive breeding might be ranching the wild animals. In this process, males would be caught periodically and the musk extracted before releasing them. The organized, sustainable harvesting is particularly attractive if developed at the rural level with revenue going directly to local people; it would provide them incentive to conserve not only "their" musk deer but also its habitat. For this purpose, today's musk deer hunters could be trained to extract musk from live animals, releasing and recapturing them on a controlled basis.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Another alternative could be controlled culling at a sustainable level, as is now done in the Soviet Union, where about 5 percent of the population is harvested each year. However, elsewhere annual culls at any level would not be feasible for at least 10 years because the populations are now so low. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&lt;&lt;I&gt;&gt; g031a.png FIGURE</P>
+<P ALIGN="JUSTIFY"></P>
+<B><P>&lt;&lt;TOC3&gt;&gt; 29 South America's Microdeer</P>
+</B><P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&lt;&lt;I&gt;&gt; g032a.png Pudu</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">South America contains three types of tiny, indigenous deer. None are well known to science, yet they are of microlivestock size, and if given research attention at least two might respond to rearing in captivity.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">PUDU</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">The pudu (pronounced "poo-doo") is native to temperate forests of the Andean region. It is among the smallest of all true deer, adult males being merely the size of small terriers and the females being smaller still. It is very shy and retiring and is endangered.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">All things considered, this animal would appear to be an unlikely candidate for microlivestock. But wherever it is found, the pudu is mercilessly hunted, and captive rearing might be the only way to save its populations from extinction. Indeed, it is already being raised in experimental herds in Chile and Argentina.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Pudus (also called the Andean dwarf deer) once ranged widely through the foothills, valleys, and lowlands of the Andes. They prefer the dark, dank underbrush of the cool rainforest, particularly thick bamboo stands. There are two species: Pudu pudu is distributed in parts of southern Bolivia and throughout much of southern Chile nearly to the Straits of Magellan. It is also found on islands off the Chilean coast. Pudu mephistophiles is distributed throughout the highlands of Ecuador, where it occurs only in cool areas at great height.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">With their short legs, stocky bodies, and compact heads, pudus do not look much like deer - more like small antelopes with foxlike faces and spiky antlers. Full grown, they are only 40 cm tall and weigh less than 12 kg. They have thick fur ranging from reddish brown to pale gray.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Because of the pudu's small size, shy and secretive nature, and forbidding habitat, few people have ever even seen one. Nonetheless, these animals tame easily and reportedly were once kept by South American Indians. Several generations were also once bred in a Paris apartment and were treated exactly like domestic dogs, which most people who saw them for the first time thought they were.'</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">In recent years, habitat destruction has greatly reduced the range and numbers of these attractive and fascinating little creatures. The International Union for the Conservation of Nature already lists them as vulnerable to extinction. Pudu studies are highly recommended, and raising pudus promises to be an interesting and valuable activity that may one day lead to one of the most intriguing microlivestock of all.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">BROCKET</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">Brockets (Mazama spp.) are small deer that occupy the place in South America's environment that duikers occupy in Africa (see page 326). They typically reside in thick brush. They occur widely throughout South America and are found in every country except Chile and Uruguay. They also occur in Central America, the West Indies, and Mexico.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">There are four species:</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">- Red brocket (Mazama americana), the most common and widespread, is found from Mexico to Argentina. It is also the largest species, with a mature weight of about 20 kg.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">- Gray (brown) brocket (Mazama gouazoubira) is also found throughout Latin America. It is slightly smaller, weighing about 17 kg.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">- Lesser brocket (Mazama rufina)2 resides in small and scattered locations in Venezuela, Ecuador, Peru, Bolivia, Brazil, Argentina, and Paraguay. It weighs 10-20 kg.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">- Dwarf brocket (Mazama chunyi) is found only in pockets of forest and brush on certain mountainsides in Venezuela, Colombia, Ecuador, and northern Peru. The smallest brocket, it weighs only 8-12 kg. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">Except for their size and color, all brockets look alike. The head,  neck, and tail are short; the ears are wide. The lumbar region is higher  than the shoulders, and this, together with an arched back, gives them a  hunched appearance not unlike a duiker's. The antlers are simple  spikes, never longer than a person's hand.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The different species are similar in behavior, too.3 They generally  wander around singly or in pairs. Although frequenting dense cover  during the day, they emerge at night to feed in open areas. Little is  known of their food preferences. But farmers know only too well how  fond they are of melons, beans, peppers, and corn. Doubtless, wild  forest fruits dominate their native diet.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Although extensively hunted, brockets are so adept at dodging into  dense brush that relatively few get caught. However, small size makes  them vulnerable to many other predators: puma, jaguar, ocelot, and  eagles and other large birds of prey. Near villages the domestic dog is  probably their worst enemy. (Infuriated vegetable growers commonly  set their dogs on them.)</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Although at first sight these retiring, nervous, and agile creatures  seem unlikely to be even potential microlivestock, young brockets are  sometimes caught and raised by people. It is not uncommon to find  them as pets on farms and in gardens. They seem to become very  tame and might therefore make useful livestock at some future time.  At least one species, the grey brocket, adjusts particularly well to life in  and around human settlements.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">HUEMUL</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">The third type of South American microdeer, the huemul,4 is a much  less likely candidate. It is very rare, very shy, and has so far shown  little likelihood of settling into captivity. However, huemul conservation  is critical: without urgent attention, the animal will become extinct.  Although totally protected by law, it is declining owing to poaching,  farm dogs, habitat loss and diseases transmitted by cattle and other  livestock.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">There are two species:</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">- The Chilean huemul (Hippocamelus bisulcus)5 occurs in high altitude forests, thickets, and grasslands in the Andes of southern Chile and Argentina.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">- The Peruvian huemul, or taruca (H. antisepsis), occurs in parts of the Andes of southern Peru and Bolivia as well as of northern Chile and Argentina.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Both species live in small herds above the tree line. They are very shy, and even though the Chilean national seal bears the depiction of a huemul, almost no Chilean (or anyone else, for that matter) has ever seen a live one.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">At less than 85 cm tall and probably weighing under 15 kg, huemuls are sized to be microlivestock. However, previous attempts at rearing them in Chile have met with little success. Nevertheless, huemuls have been kept in zoos in Germany, and such experiences - together with the increasing knowledge of how to raise red deer and other species - may eventually provide the keys to their continued existence. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&lt;&lt;I&gt;&gt; g033a.png FIGURE</P>
+<P ALIGN="JUSTIFY"></P>
+<B><P>&lt;&lt;TOC3&gt;&gt; 30 Water Deer</P>
+</B><P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&lt;&lt;I&gt;&gt; g034a.png FIGURE</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Little is known about the water deer' (Hydropotes inermis), but it should be considered along with mouse deer, muntjacs, musk deer, and others as a possible species for microlivestock development. It is comparable in size, and it is unusual among deer for producing large litters: births of triplets or more are common.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">As with the other species in this section, this is a highly speculative notion; however, there is some justification for it. The Zoological Society of London has successfully established breeding colonies, and other zoos have also bred the animal in captivity. The water deer has the advantage of rapid growth, early maturity, and high fecundity. Indeed, given protection, its populations have been known to increase rapidly.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">APPEARANCE AND SIZE</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">The animal has a graceful and delicate appearance, its best known characteristic being the male's long tusks. Both sexes are about the same size, standing 45-55 cm at the shoulder and weighing up to 19 kg. Body length is up to about I m, and the tail is so tiny that it is barely noticeable. The round-tipped ears are characteristically held erect above the head.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Water deer are somewhat like muntjacs, but they are longer in the leg and lighter in build. Their forelegs are shorter than their hindlegs so that they stand slightly higher at the haunches than at the shoulders. This gives them a hunched appearance.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The hair is generally thick and coarse, longest on the flanks and rump. The backs and sides are usually yellowish brown, finely stippled with black. In winter, the coat is thick and variable in color; pale fawn and peppery gray-brown are common shades. In summer, the coat is sleek and reddish. Fawns are white spotted at birth, but this dappling soon fades.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Neither sex has antlers. The upper canine teeth, especially in the males, are enlarged, forming curved tusks 7 cm long. These are much bigger than those in muntjacs and can protrude well below the jawline.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">In both sexes there is a small inguinal gland present between the hind legs, the only instance among deer.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">DISTRIBUTION</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">In China the water deer has a wide distribution range. It is mainly found in the provinces of Jiangsu, Zhejiang, Anhui, Jiangxi, Hunan, Hubei, and Fujian, the mid and lower Yangtze River Basin, and coastal areas and islands in central and eastern China. It is also found in Guilin, southern Sichuan Province, Guangxi Province, and Guangdong Province in the south.2</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">In Korea, the animal lives along the lower reaches of most rivers, except those in the extreme northeast. Its northern limit of distribution is probably about latitude 43&Yacute;N.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">At Woburn Park in England, a few escaped from a herd early this century and have increased and become established in a number of counties, particularly Bedfordshire, Hertfordshire, Cambridgeshire, and Norfolk.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">STATUS</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">In China, owing to increasing reclamation and cultivation of wetlands, the habitat of the water deer is gradually shrinking. At present the animal is protected by the government, which designates appropriate hunting seasons. It is estimated that about 10,000 are killed each year by hunters. In Korea the water deer is still plentiful. As noted, in England it is maintaining itself and is thriving in some protected parks. It is also reported to be present in France.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">HABITAT AND ENVIRONMENT</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">In its home range, the water deer is usually found among reeds and rushes in swampy areas. It also frequents the tall grasses and sparse shrubs of mountainsides and cultivated fields. In England it has adapted to a variety of habitats, including woodlands. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&lt;&lt;I&gt;&gt; p323a.png Native range of the water deer.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">BIOLOGY</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">The water deer is chiefly a grazer. It feeds mainly on reeds, coarse grasses, and some tree leaves.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">As previously mentioned, this is the most prolific species of deer. Up to seven fetuses have been observed in a single pregnant female, although the normal litters are two or three. The gestation period is about 176 days. Fawns are born in late spring or early summer, and weigh only about 0.5 kg at birth. Within 4 days the newborns can live almost exclusively on grasses. Usually, however, they are fully weaned after 4 8 weeks, but remain socially attached to the mother. They appear to become independent after about 4 months. Males become sexually mature at about 5-6 months; females at about 7-8 months.3</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">BEHAVIOR</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">Water deer are generally seen alone. Even where abundant, they seldom congregate in herds. Females are sometimes intolerant of each other, as are adult males or young males. However, in captivity, several females can graze and rest in loose aggregations. The peak period of grazing activity occurs around dusk. Feeding sessions are interspersed with periods of passive cud-chewing.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Water deer "bark" at intruders. During the rut, males are especially noisy and aggressive, and defend their territories with vigor. Fighting involves striking their tusks into the shoulder or back of their opponents. 3 Information from Lu Houji. These are extremely excitable little animals. When upset, they often "hump" their backs and bound away like rabbits. They are also good swimmers.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">USES</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">In China the water deer are hunted for their meat and skins, and newly born fawns are killed to obtain the mother's colostrum for medicinal purposes. In a few localities in England, the species has become a game animal.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">HUSBANDRY</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">The water deer is not yet known on "farms." However, it seems to be easily kept, has bred well in zoos, and has thrived in many British wildlife parks. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">ADVANTAGES</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">The assets of early maturity and high fecundity mean that the potential exists for rapid population expansion. Such an event occurred at Britain's Whipsnade Zoo. In 1929 and 1930, 32 deer were released into undeveloped pasture; by 1937, 120 fawns had been raised.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Because they are relatively small, and because in the wild state they aggregate only under exceptional conditions, water deer are unlikely to have any appreciable impact on vegetation in forests, farms, or gardens. Nonetheless, they can damage crops, and Chinese farmers, who consider them pests, often illegally kill them out of season.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">LIMITATIONS</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">These animals are swift and adept at escaping captivity. It is possible that because of territoriality only a single pair will live in a given area. Moreover, males are aggressive and must be kept apart.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">They seem able to withstand chilly weather well, but a combination of wet and cold is harmful. Their heavy winter coat, essential to survival in the Far East, renders the animal susceptible to dehydration and heat exhaustion in comparatively mild climates, such as England's.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">At birth, the tiny fawns are extremely vulnerable to a variety of predators, both birds and mammals. The species may need areas of dense cover or some shelter from wind.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">RESEARCH AND CONSERVATION NEEDS</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">The water deer has been successfully kept in semicaptivity for many years; however, for it to reach a level of domestication suitable for use as microlivestock, research is needed in the following areas:</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">- Reproduction;</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">- Performance under a range of environments;</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">- Grazing efficiency;</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">- Basic physiology;</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">- Captive breeding and domestication - measurements of growth rates, space requirements, and feed needs; and</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">- Modifying behavior to overcome territoriality - for instance, imprinting on humans, selection of docile specimens, hand rearing, and castration.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The water deer is not an endangered species; however, efforts should be made to preserve the populations in their native ranges and habitats. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<B><P>&lt;&lt;TOC3&gt;&gt; 31 Duikers</P>
+</B><P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&lt;&lt;I&gt;&gt; g035a.png Red Duiker</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Duikers (Cephalophus and Sylvicapra species) are small African antelopes. Although they are ruminants like cattle, sheep, and goats, some are hardly bigger than hares or rabbits. One, the blue duiker, is less than 40 cm high and usually weighs a mere 4-6 kg. It and some of the slightly larger duikers might be suitable for household husbandry because their meat is an extremely popular food throughout much of Africa. In West Africa, for example, it is one of the most common meats sold in both rural and urban markets.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">This idea, however, is highly speculative because, despite their popularity, little is known about these tiny animals. Their husbandry has been attempted only a few times, but the results were encouraging, and rearing duikers deserves further investigation. They are already being raised in captivity in the United States,' Zimbabwe,2 Togo,3 and Gabon. Researchers in Nigeria have bred blue duikers to the fourth generation and found that, if the animals were first handled by people while young, they remained docile.4 Even blue duikers caught in the wild tame quickly if they are very young, but by the time they reach 3.5 months, they become barely tolerant of man's presence.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">If duiker husbandry can be developed, it might provide not only a more regular source of meat, but also a lessening of the hunting pressures, thereby giving the wild populations a better chance of survival.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">AREA OF POTENTIAL USE</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">These antelopes are suitable for testing as microlivestock only in their native region, sub-Saharan Africa. Eventually, they might prove to have wider applicability. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">APPEARANCE AND SIZE</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">Duiker species vary from about the size of a small dog to that of a small donkey. Most are similar in shape and are characterized by short front legs, arched back, and pointed hoofs. The tail is stubby, often with a terminal tuft. The coat varies from reddish brown to nearly black, although a few species are blue-grey and one is zebra striped.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Females are slightly larger than males, but the sexes look alike. In most species, both sexes bear small straight horns that project backward from the skull, frequently hidden in a long tuft of hair.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">DISTRIBUTION</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">Duikers inhabit virtually all regions of Africa below the Sahara from Gambia in the west to Ethiopia in the east, and all countries as far south as South Africa.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">STATUS</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">Duikers are so shy that they are rarely encountered by people. But almost anywhere in Africa (other than North Africa), the observant traveler may glimpse them ducking into forests or thickets. Although there are still countless numbers, people are eating so many that in some localized areas the populations are fast heading toward extinction.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">HABITAT AND ENVIRONMENT</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">All but one species are found in rainforests or dense woodlands. The grey duiker, however, is found in savannas. If the vegetation is juicy, only a few of the species need a separate water source, so they can thrive in very dry sites.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">BIOLOGY</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">The main foods are fruits and seeds supplemented by leaves and shoots. Fruits, which they eat to a much greater degree than other antelopes, are an important part of their diet. Some rare species (for example, the red-flanked duiker, C. rufilatus) can graze. Occasionally (especially in captivity), duikers are also omnivorous, eating fish, crabs, insects, snails, frogs, small animals, or carrion; they also readily accept chopped meat. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Duikers reach sexual maturity at 9-15 months; gestation lasts about 7-8 months. In some species, females conceive a few days after calving on a 3- to 5-day postpartum estrus. Apparently one calf per birth is normal. A newborn blue duiker weighs between 0.4 and 0.7 kg.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Before one year of age, young duikers leave their parents to find their own mates and territories. Life expectancy is more than 10 years.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">BEHAVIOR</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">In spite of habitat differences, most duikers behave alike. In the wild they are nervous, shy, and retiring. When alarmed, they plunge into the protection of dense vegetation - hence the origin of the name duiker, which means "diver." Nonetheless, their behavior allows them to be easily netted. An experienced hunter can imitate duiker sounds and call the male out of the bush. Also, a startled animal freezes, thereby facilitating its capture.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Moving easily through dense vegetation, the head carried low, these tiny animals use regular runs. Forest duiker species are largely diurnal, although a few, such as the bay duiker, are nocturnal. Bush duikers are mainly nocturnal, feeding from early evening until morning. Such nocturnal species shelter during the day in holes (presumably dug by other animals) or inside fallen trees; the diurnal ones lie directly on the ground.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Blue duikers are the best-known species and are probably the most likely candidates for microlivestock (see page 332). They seem to be monogamous and apparently mate for life. Unlike most antelopes, their population densities can be high. The pairs reside in territories of 2-4 hectares, which both male and female stoutly defend against rivals. Other species appear to be polygamous and live in large territories (up to 80 hectares).</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">In captivity, the animals are generally calm. However, both males and females can be aggressive toward unfamiliar individuals of their own species. In an enclosure, one male can serve several females.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Large glands, located beneath each eye, exude a scent that is rubbed onto fences, trees, and other objects as territorial marking. In another form of marking the horns are rubbed against tree trunks.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">USES</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">As noted, duiker meat is much sought in many African countries, and the animals are regularly hunted. The meat is lean with little or no intramuscular fat (marbling). </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Duikers also have promise as experimental animals. They are true ruminants, with four-part stomachs, and they produce cud. Some are only rabbit size, they need far less room or feed than sheep, and thus are potentially an efficient test animal for determining the nutritional value of forages. Blue duikers, for instance, have a digestion efficiency comparable to that of sheep, but, because of their small size, a test needs only four rabbit cages and 5-10 kg of feed. Sheep, by comparison, require much more spacious facilities and 150 kg of feed.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">In Nigeria, blue duiker pelts are used in making karosses, a traditional dress. A single garment may contain up to 60 pelts.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">HUSBANDRY</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">Almost nothing is known about rearing duikers, but they seem to tame easily and perhaps may be kept in backyards like goats. Indeed, they reportedly make good house pets when hand raised. They are attractive, and from the day of capture young ones can be handled and petted.5</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The Nigerian researchers who bred blue duikers to the fourth generation bottle-fed young specimens five times a day. Older animals were given feeds that included banana, plantain, and papaya; leaves of hibiscus, cassava, and banana; and dried corn. Variety seemed to be important, and the researchers could not predict the quantity of particular foods the animals would choose on any given day. In addition to varied vegetables, a small dish of salt or a salt lick was sometimes required.6</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Duikers are unlikely to run away, except when startled. However, providing an enclosure is worthwhile. It enables them to establish a territory by marking poles, bushes, and fences. Although needing space in which to run, as little as 10 m&Yacute; is reportedly sufficient for 24 animals.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Satisfactory shelters include an open-ended oil drum laid on its side, a lean-to made of palm frond, or a small hut made of local matting. Apart from providing shade and protection, shelters should be built so that excited animals can run through them. When cornered, duikers tend to either flee for shelter or jump upwards; a run-through shelter can prevent a frightened one from accidentally leaping over the fence.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Based on their own experiences, researchers at Pennsylvania State University in the United States report that blue duikers raised in captivity are easy to maintain, reproduce well, and are not fussy about environmental conditions. In fact, they say, blue duikers seem to enjoy living in cages.7</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">In order to raise duikers successfully, post-pubertal males must be separated. A female should be bred with the same male throughout her productive life span.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">THE BLUE DUIKER</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">In one sense, the blue duiker is the most important animal in Africa. It is the only one found throughout the continent south of the Sahara. It occurs at a greater range of altitudes than most - as low as sea level in many places to almost 5,000 m elevation in Kenya. It occurs in habitats from dense rainforests to dryland savannas. And, in sub-Saharan Africa as a whole, the blue duiker is eaten more than any other animal (although in West Africa it is generally called Maxwell's duiker).</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">This very small antelope, caught by snare or net, can be found in the meat markets of villages, towns, and cities in all countries from Senegal to Madagascar. It is a source of food for tens of millions. Bushmen, Pygmies, Dinkas, and Mandingos, thousands of miles apart; all share the same fondness for duiker meat and for duiker-skin clothes.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Nevertheless, scientifically speaking, this is one of the world's least-known animals. And its numbers are diminishing rapidly. Areas that used to have plenty now have few or none. Overhunting and destruction of the rainforests are jointly contributing to their decline.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Despite the losses, people are snaring as many as they can, and there is no sense of concern - not even among most conservationists. However, in many locations there is already evidence that the animals won't be around much longer. Unless something is done - and soon - people will lose their major source of animal protein. If that happens, it is likely that they will move on to larger animals, such as gorillas, which would be an even worse disaster.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The best long-term solution is to organize duiker husbandry. Learning to rear duikers would benefit people throughout Africa. The blue duiker is the most suitable species; it is the most common and the most important. Also, it inhabits the edges of the forest and could therefore become a suitable species for ranching without denuding the forest.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Blue duikers are easy to maintain in captivity. They tame readily and like to shelter and sleep In boxes or cages. They are good converters of vegetation and produce top-quality lean meat. In addition, they are neither affected by tsetse flies nor are very susceptible to diseases.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The key now is to learn how to keep these very timid creatures under different conditions. We need to know their foods (especially foods that might be harvested from forests) and reproductive biology. We need to know the right numbers to house together. Most of all, we need projects aimed at rearing and breeding them in captivity under village conditions.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Vivian J. Wilson</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">ADVANTAGES</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">Many African countries already have a ready market for duiker meat. It is somewhat similar to goat meat, but most people agree that it is superior.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The animal can live on fibrous vegetation. Unlike conventional ruminant livestock, it is suitable for feeding an average family at one meal.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The ability to forage in undergrowth where other domestic livestock do not thrive makes duikers potential livestock for tropical forest and bushland regions. They can be raised for meat without cutting the trees or bushes to create pastures.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">LIMITATIONS</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">Duikers are easy prey for predators: eagles, pythons, wildcats, and people, among others. Thus, they probably require more sophisticated management than common livestock such as goats. However, the quality of their meat could more than compensate for the extra effort.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Some species are territorial, which means that they may do poorly in captivity, unless their social organization can be altered.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Under good conditions, the ideal slaughtering age reportedly occurs at 8-10 months, when the blue duiker can weigh 4 kg. Compared to rabbits and guinea pigs, production is relatively slow because of long gestation and lack of multiple births.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Duikers are resistant to trypanosomiasis.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">One general problem is that duikers have short, sharp horns designed specifically for jabbing. This could be a potential danger, especially since the males of some species become aggressive when their females are receptive. However, the horns can easily be clipped and taped to limit the danger. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">RESEARCH AND CONSERVATION NEEDS</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">Because of the duikers' secluded lifestyle, much has still to be learned about their habits. Specific information on behavior and breeding is needed.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Animal scientists in Africa should gather small herds for comparative studies. This will provide insights into whether duiker temperaments facilitate or hinder their utilization. In addition, assessments of diet, growth rates, behavior in captivity, reproductive rate, adaptability, and future potential can be made. Management considerations include clipping horns, trimming hooves, and controlling lice and fleas.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Research of particular value would be chemical analysis of duiker milk and of other characteristic glandular secretions. The latter lend themselves especially to a study of animal communication.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Parming duikers might help rescue the wild populations by relieving hunting pressures. Programs in this area are recommended for locations where overhunting is occurring. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&lt;&lt;I&gt;&gt; g036a.png FIGURE</P>
+<P ALIGN="JUSTIFY"></P>
+<B><P>&lt;&lt;TOC3&gt;&gt; 32 Other Small Antelope</P>
+</B><P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&lt;&lt;I&gt;&gt; g037a.png Klipspringer</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The least known and most obscure of all antelope are the delicate African creatures called dikdik, suni, royal antelope, pygmy antelope, and klipspringer. The smallest is a West African form of the royal antelope that stands a mere 25 cm high and weighs less than 2 kg. The four-horned antelope of South Asia is a similarly tough, tractable animal that is also the size of a small dog.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">None of these has previously been seriously considered for use as livestock, but they are possibly amenable to rearing in captivity and they provide some of the finest game meat in the world. Given New Zealand's experience with various deer species (see page 288) and Africa's experience with large antelopes, basic research to test out the possibility of organized dwarf-antelope production could prove to be rewarding.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">AREA OF POTENTIAL USE</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">The areas where these antelopes might be used are sub-Saharan Africa for the African species and South Asia for the four-horned antelope.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">APPEARANCE AND SIZE</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">Of these animals, some, such as the pygmy antelopes, have a crouched appearance with an arched back and short neck; others have a more upright posture with a long neck and a raised head. In all species, the males are smaller than the females and bear tiny spikelike horns. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">DISTRIBUTION</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">Collectively, these antelopes have native ranges covering huge areas of Africa and part of Asia.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Dikdik: Six species occur in two discontinuous distributions - one from Somalia and Ethiopia southward through Kenya and Tanzania, the other in Namibia and Angola. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Sunis: Eastern Africa, from Kenya to South Africa.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Royal antelope: West African forests. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Pygmy antelope: Central Africa from southeastern Nigeria to Zaire. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Klipspringer: Ethiopia to the Cape of Good Hope. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Four-horned antelope: India. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">STATUS</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">Many forms are protected by local laws, but none of the species is on the international endangered-species list.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">HABITAT AND ENVIRONMENT</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">The animals occupy habitats from dense, moist forests to dry, rocky outcrops and even to deserts. Their ranges have almost certainly been affected by humans - sometimes for the better, since many prefer the secondary growth that invades disturbed areas, notably after overgrazing or slash-and-burn agriculture.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Although dikdik and klipspringer usually frequent dry areas with scattered brush, the other dwarf antelopes normally stay in dense vegetation. All seem to live in definite areas and do not migrate. For instance:</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">- Dikdik live near streambanks.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">- Sunis inhabit dry country with thick bush, but they can also be found in reed scrub along rivers and in forests up to 3,000 m elevation.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">- Klipspringers live on stony mountain slopes, rocky outcrops' or the sides of steep gorges at altitudes from sea level to 4,000 m.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">- Four-horned antelopes live in undulating or hill country and shelter in tall grass and open jungle, a terrain more common to deer than to antelope. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">BIOLOGY</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">Most of these antelope browse on shrubs. They are "concentrate selectors," taking easily digested vegetation such as buds, fruit, and succulent young leaves.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Also, most obtain much of their water requirement from dew and the vegetation they consume. Klipspringers, for example, are able to live for months without drinking. Sunis and four-horned antelope, on the other hand, drink regularly and seldom live far from water sources.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Little is known of the reproduction and general performance of these animals. Females become sexually mature at about 6 months in the smaller species and 10 months in the larger. Males become sexually mature at about 14 months. The young are born throughout the year, but births peak with the vegetation flush following the first rains. Where there are two rainy seasons a year, two birth peaks occur. Usually a single calf is born. Dikdik is the only one whose reproduction has been studied in detail. Its pregnancy lasts 172 days, one young is born at a time, and the birth weight is 600-800 g.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Their longevity is unknown but is probably in the range of 10-12 years.l</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">BEHAVIOR</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">These tiny creatures have some of the habits of deer. They are shy and elusive and generally rely on concealment to escape detection. Their first response to a predator is to freeze, and then to flee like hares - dashing off in a series of erratic, zigzag leaps.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">They live alone, in pairs, or in small family groups, but sometimes congregate in larger groups in thorn thickets. The species that have been studied most (dikdik and klipspringer) are strongly pair bonded. (A male, a female, and one or two young is typical, and a klipspringer rarely moves more than 5 m from its mate.) However, the royal and pygmy antelopes and the suni are more solitary in their behavior. Four-horned antelope are usually seen alone or in pairs.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">These animals feed mostly in the early morning and late afternoon Some species deposit dung and urine on particular sites. And they repeatedly daub secretions from glands in front of the eyes onto plant stems, where a sticky mass accumulates. Glands near the hooves mark the ground along frequently traveled pathways. Males also mark females with the scent, thus reinforcing the bond. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The four-horned antelope has a whistling call, which helps keep the family group together. Males repeat it frequently in hot weather. Gestation is 8-8.5 months. If taken young, they reportedly tame easily.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">HUSBANDRY</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">Much more research needs to be done before attempts are made to convince anyone to domesticate these antelope. There are likely to be considerable difficulties. Guinea pigs, rabbits, and giant rats can successfully be kept in cages or small enclosures, but most antelope probably cannot. Larger enclosures will be needed.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The food habits and general behavior of these small animals must be studied closely. They are strictly monogamous, and it may be necessary to keep them in pairs. Reproduction, growth, and general performance must become understood under different environmental and nutritional conditions. Mixing species is another aspect to be examined - whether these antelope can be kept with other species in the same enclosure (typical of livestock farming in most poor nations) is not known.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">To settle such questions, representative species of microantelope should be gathered for comparative assessment. Researchers should focus on the animals' social structure, on husbandry methods for maintaining them over generations, and on how best to breed them. If the findings are promising, then a campaign to domesticate these antelope could be mounted.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">USES</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">Throughout most of their ranges these animals are highly sought "bushmeats." The meat is lean and of extremely high quality. In Zaire's Ituri Forest, for example, pygmies net and kill large numbers of pygmy antelope, hanging the carcasses on sticks by the roadside for sale.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Because of their small size, these species might make good laboratory animals for ruminant studies. The dikdik, for instance, becomes a fully functioning ruminant at a body weight of about only 1.5 kg.2 However, their digestive physiology is quite different from that of cattle, sheep, and goats, which makes them atypical ruminants.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Given organized production, it is likely that dwarf-antelope pelts could become commercially important. North Africa exports the hides of medium-size antelopes to Europe for use in fine sueded leathers. Hides of the small species would almost certainly be in demand as well if a steady supply could be obtained as a by-product of meat production.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">ADVANTAGES</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">Microantelope provide some of the finest game meat. They are small and perhaps tractable. Most are already widely eaten and are being eliminated over broad areas of their range. Turning them into a sustainable, economic food source could provide motivation for their conservation.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">These antelope can digest, and are adapted to, the indigenous forage over vast areas of Africa and South Asia. They are native to tropical habitats, where cattle and other livestock often grow poorly. They also appear to be resistant to trypanosomiasis.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">LIMITATIONS</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">Some African peoples (for example, the Kalahari Bushmen) have superstitions or social injunctions that prohibit the eating of some of these species.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Small antelope are probably not as efficient as larger ruminants in digesting fiber: the retention time in the rumen may be too short. On the other hand, quickly digestible cell walls of lush green plants can be used efficiently.3</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The territorial behavior of most of these species may limit their rearing in large numbers under captive conditions.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">RESEARCH AND CONSERVATION NEEDS</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">As noted, preliminary research on dwarf antelope husbandry is required. Specifically, studies should be conducted to assess:</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">- Growth rates, feed efficiency, and reproductive rate;</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">- Carcass quality;</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">- Economics and the likely cost of production per animal unit; and</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">- Studies of digestion.4 </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The few statistics available today on the use of wildlife as food are probably much below actual consumption. Most food consumption surveys record food obtained by hunting or trapping under the indiscriminate heading of "Bushmeat" and neglect to include the many small animals that are normally collected by children. In Africa, an amazing variety of wildlife is eaten, including all wild ungulates, primates, all cats, and many species of birds and reptiles.</P>
+<P ALIGN="JUSTIFY">Food and Agriculture Organization Ceres magazine</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">All the world's people must begin to overcome in themselves - and even more so in their children - senseless taboos about what is edible and what is not. Only then can we stop today's universal animal-protein wastage. How ironic it would be, in this scientific age, for mankind to starve largely because of a bunch of old wives' tales, irational beliefs, silly associations, and the lack of a sufficient spirit of culinary and gustatory adventure.</P>
+<P ALIGN="JUSTIFY">Calvin W. Schwabe Unmentionable Cuisine </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Iguana is really good, a thousand times better than chicken.</P>
+<P ALIGN="JUSTIFY">Omero Asinto, waiter Pochote Bar and Restaurant</P>
+<P ALIGN="JUSTIFY">Barranca, Costa Rica</P>
+<P ALIGN="JUSTIFY"></P>
+<B><P ALIGN="CENTER">&lt;&lt;TOC2&gt;&gt; Part VI : Lizards</P>
+</B><P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">Large lizards have been important foods since prehistoric times and are still commonly hunted in parts of Asia, Africa, and Latin America.1 Some (such as the monitor lizards seen in markets in Indochina) are carnivorous species that may be difficult to feed and raise economically. However, the iguanas of the Americas offer promise as microlivestock. They are herbivorous and feed primarily on leaves, flowers, and fruits, including many that are too high in the trees to be gathered by man or by other livestock.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Iguana meat is popular throughout much of Latin America, where consumers willingly pay more for it than for fish, poultry, pork, or beef. To fill the demand, several iguana species are hunted by rifle, slingshot, trap, and noose; they are even run down by trained dogs. Villagers (often small children) catch them for food for the family; professional hunters snare and sell them to vendors. Iguanas are hauled around in gunny sacks and wicker baskets by car, boat, horseback, and people on foot. In parts of El Salvador they have been known to arrive at the market by the truckload.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">As a result of this indiscriminate hunting, iguanas are now steadily becoming more scarce, and the destruction of their habitat makes the situation even worse. At present, many parts of Latin America's tropical forests are being cleared. The green iguana in particular depends on trees, and as forests disappear its populations are destroyed.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">However, iguanas are forest-edge species: they will grow well on ranches and farms as long as patches of trees are left standing. This offers the hope that they can be raised as microlivestock. They reproduce so prolifically that, in principle, populations can build up exponentially. Mature females, for example, may produce 30 or more eggs a year for up to 10 years.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">In the past few years, a notable research program in Panama and Costa Rica (see page 351) has laid the practical foundation for iguana farming. It has artificially incubated and raised thousands of green iguana hatchlings. With less than half a square meter of living space per animal, the hatchlings have grown as fast or faster than their wild counterparts. Unlike their kin in the wild - which in their first year of life suffer 95 percent mortality from birds, snakes, and other predators the captive-raised iguanas show almost 100 percent survival. This research project demonstrates that ranching iguanas both for food or for repopulating depleted habitats is feasible. In addition, experimental projects for farming green iguanas have begun in Curacao and El Salvador.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">As livestock, lizards have advantages. Being cold-blooded they do not carry human diseases (except for those such as salmonella that result from gross mismanagement). They can be kept in captivity in fairly high densities without diseases breaking out. Although often aggressive in the wild, they coexist in dense populations with few problems as long as they are well fed.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">There is an important conservation component as well. Farming these lizards may help check and may even reverse the downward trends of their populations by allowing large numbers to be released back to the wild at a size that inhibits predators.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">There are three alternatives for utilizing iguanas:</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">- To manage wild stocks as game animals;</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">- To raise iguanas on farms, like chickens and pigs; or</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">- To raise young iguanas in captivity and then release them into the wild where they can grow to full size and later be harvested on a sustainable basis.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Although the green iguana has so far received the most attention, two other Latin American species are in farming trials. Black iguanas (garrobos) are being raised experimentally in El Salvador and Costa Rica. And the omnivorous tegu lizard, which produces a valuable leather, is beginning to be farmed in Argentina and is briefly described opposite. Both iguana species are described in the following chapters. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">TEGU</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">The tegus (Tupinambis rufescens and T. teguixin) are large lizards of South America. They are highly prized for their skins, which are made into leather for handbags and similar items. Tegus are heavily exploited; on average, Argentina exports over one million skins a year - about $15 million worth. The 50-year-old tegu industry is estimated to support as many as 30,000 people, including tannery employees and people in rural areas who hunt the lizards full- or part-time. Poor agricultural conditions make farming difficult in the Chaco, and sale of a single tegu skin is worth more than a day's wages for a farmband. Some families also eat the tegu meat and use the fat for medicinal purposes. In many areas, the populations have already been driven to the verge of extinction. Husbandry, therefore, could be beneficial. Traders are hoping that captive operations run by families can eventually replace hunting.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Although usually associated with the arid regions of northern Argentina and Paraguay, the tegu's range actually covers much of South America - as far north as Colombia, including Trinidad and the Amazon basin. One species (T. rufescens) normally occurs in a dryland habitat, such as Argentina's Chaco region. It can occur in great numbers in pastures, probably because of the insects associated with cattle. But it also occurs in areas that are unsuitable for cattle. Some places where tegus are common are so dry that they can carry only a single cow in 10 hectares. There, farmers might find it profitable to raise tegus. This would maintain the native biological diversity while perhaps reducing the soil degradation that cattle cause.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The other species (T. tegubixin) occurs in wet forests, such as those found in Argentina's Formosa Province.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Tegus are scientifically interesting. Little is known about their biology, and basic studies are needed. They are not much eaten, but in some areas the tail is considered a delicacy. Indeed, deteriorating economic conditions are already making them more important as a food resource. Convincing campesinos that they can increase their cash income and their meat production by rationally exploiting these large lizards should not be difficult.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Sustainable exploitation could also benefit tegu conservation. Large populations still exist in some areas in Argentina and Paraguay, but, overall, the species are declining. A welldesigned management project could ensure the maintenance and reestablishment of large populations where numbers have drastically decreased. </P>
+<P ALIGN="JUSTIFY"></P>
+<B><P>&lt;&lt;TOC3&gt;&gt; 33 Green Iguana</P>
+</B><P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&lt;&lt;I&gt;&gt; g038a.png FIGURE</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">As noted, the green iguana (Iguana iguana) is consumed throughout Central America. It is already subject to heavy commercialization and its populations are plummeting. This is not likely to change: as human population increases, so does demand for iguana meat and eggs as well as for live iguanas, thousands of which are kept as house pets. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Because of its herbivorous diet, inoffensive nature, and high reproductive potential, this reptile is a prime species for intensive management. Alert, curious, and social, it is easily tamed from birth. Given minimal protection during the reproductive season, large populations can build up, and animals can be maintained in simple facilities.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">However, although iguanas can be maintained as microlivestock, they may require three years to reach market size. Raising them to maturity entirely under captive conditions is thus probably uneconomic at present, when specimens can still be inexpensively (albeit often illegally) harvested from the wild. However, it has been found that if released into the wild, most will remain in nearby trees, especially if people erect simple feeding stations and keep them stocked with table scraps or weedy vegetation. This makes for very low-cost production during the years of waiting.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Given such findings, iguana farming has a promising future. With research, growth rates can undoubtedly be increased and maintenance costs reduced. Also, iguanas are becoming more valuable each year. Even now, farming them could be economic in some areas where wild iguanas are scarce, especially if the young are released into forested sites when they have grown to a size where mortality is low.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Although green iguanas will happily graze pastures, they need trees. Iguana farming, therefore, provides a way to keep tropical forests standing while still providing people with meat and income. By growing lizards, farmers don't have to fell the forests to create space for growing food crops or cattle. Iguana farming thus gives an economic incentive to preserve the beleaguered tracts of remaining trees. It may even render reforestation economically attractive. And it may promote the use of shelterbelts and contour strips of trees in cattle-ranching areas. Today's researchers estimate that 200-300 kg of meat can be produced per year per hectare from iguanas.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">APPEARANCE AND SIZE</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">The green iguana can grow to more than 2 m long, but more than half of that length is in its whiplike tail. Adults of breeding size generally weigh 2-4 kg. The scaly skin is green, yellowish, or golden brown with dark markings; color is a function of age and reproductive stage.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">DISTRIBUTION</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">This large lizard is indigenous to a vast region stretching from Mexico to northern Brazil and Peru, including a number of Caribbean islands. In Mexico, it occurs in tropical forests along both coasts.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">STATUS</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">Green iguanas were formerly abundant throughout Central America, but no longer. In the mangrove forests along Mexico's Pacific coast, for instance, only 5 percent of the former population remains. In Guatemala's Pacific lowlands, mere remnants are left. In El Salvador's jungles, the animals have declined to 1 percent of their former density. And in both Panama and Costa Rica, the species is now officially classified as endangered.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">HABITAT AND ENVIRONMENT</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">The green iguana usually lives near water in tropical lowland forests. It thrives only as long as some trees remain. The forests may be either humid or seasonally dry. The animal normally inhabits the treetops, feeding on tender shoots and fruits in the canopy; few other herbivores can convert such forest foliage into food for humans.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">BIOLOGY</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">Like cattle and other herbivorous mammals, iguanas have a specialized digestive system with an enlarged fermentation chamber in which bacteria break down plant cells. Vegetation is converted into meat about as effectively as in cattle, but not as quickly.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">After reaching sexual maturity, at 2 or 3 years of age, females lay one clutch of 10 85 eggs each year. (For most specimens the average is probably about 35.)</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&lt;&lt;I&gt;&gt; p349a.png Native habitat of the green iguana</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">BEHAVIOR</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">The animals are generally slow moving and lethargic when cold, but during the heat of the day they become extremely alert and can run, swim, and climb with speed and agility.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">They have a complex social structure and a defined annual reproductive cycle. Hatchlings adapt easily to captivity both when artificially incubated and when captured in the wild. However, captured adults, used to living free, are hard to keep in small enclosures.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">USES</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">Green iguanas are used mainly for food. The meat tastes somewhat like chicken and in Latin America is typically cooked in a spicy stew. The eggs are also consumed. Small and leathery shelled, they are considered special delicacies and are said to cure various ailments.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">There is a sizable demand for live iguanas in the international pet trade.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Exploitation has been mainly for the flesh; the skins are wasted in most cases. However, given organized production, green iguana skin could perhaps become a farm by-product. It sells in the international reptile-leather market under the trade name "chameleon lizard." The hide is typically up to 20 cm wide. Thin and relatively fragile, it is glued to a fabric or cowhide backing to prevent it from tearing. The prime uses are for ladies' accessories, belts, wallets, and shoes. It is inappropriate for uses that involve flexure because the scales overlap and repeated flexing causes them to separate. The skin then becomes rough to the touch and loses its glossy finish.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">IGUANA MAMA</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">The program that now offers hope for raising green iguanas as microlivestock is the brainchild of zoologist Dagmar Werner. She began in 1983 by collecting 700 iguana eggs and then learning what to do with them "on the job."</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Through a combination of luck and intuition, coupled with determination, she discovered appropriate conditions for incubating the eggs on the first try - no less surprising because her incubators (dirt-filled wooden boxes warmed with light bulbs) were in an apartment in a high-rise building in Panama City. Nonetheless, most of the eggs hatched and the several hundred squirming young lizards were quickly trucked to a forest park near the Panama Canal. Here, for five years, assisted by a steady stream of enthusiastic Panamanian biology students, Wemer experimented with cages, feeds, facilities, breeding genetic selection, and the myriad aspects of management.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">These dedicated researchers eventually devised what might be considered a production line, and they hatched and raised tens of thousands of green iguanas, reduced the animals' infant mortality rate, and created the basic underpinnings for economic production.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">In 1988, administration for the project was shifted to neighboring Costa Rica, where Werner established another research farm as well as a fund-raising foundation. From there, she hopes to catalyze all Central America to take up iguana production.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Her immediate goal is, paradoxically, to preserve the lizards by putting an iguana in every pot. That will help reduce the indiscriminate hunting that is taking these animals toward extinction in the wild.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Her system is based on setting up feeding stations in the woods and releasing iguanas at seven months, an age at which they are virtually immune to predators. Iguanas need trees, and her ultimate goal is to help save the vanishing rainforests. With profitable iguana farming, she hopes to persuade farmers to save the trees as homes for iguanas, rather than clearing them for crops and cattle.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">"Iguana management and an international marketing system will protect, rather than exterminate, the iguana," Werner says. "I don't think iguana farming will stop deforestation. But I do think it will contribute a great deal." </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">HUSBANDRY</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">The iguana farming project in Panama and Costa Rica (see sidebar) provides a model for what might be done elsewhere. In its first five years of operation, the project raised more than 10,000 green iguanas.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">To create the farms, enclosures are constructed with sheet-metal wails sunk 30 cm in the ground.' Inside, the animals sleep in shelters made of bamboo and vegetation. Each shelter has an adjustable entrance slit through which young lizards can slither, but predators, which usually are larger, cannot. Most are set on stilts and food is served in the shade underneath. With this system, from 20 to 60 young iguanas are kept in an area of 10 m&Yacute; (0.5-0.17 m&Yacute; of land area per individual). In another "high-intensity" design, 30 hatchlings are kept in cages I m&Yacute; in size (only 0.05 m&Yacute; per individual).</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The iguana farms also include an artificial nest consisting of a "tunnel" leading to a sand-filled egg-laying chamber. (Both tunnel and chamber are made of concrete blocks or other predator-safe material.) Female iguanas (at least in captivity) prefer this to digging their own tunnels, and it is an important advance in iguana breeding because it produces a hatching success of close to 100 percent. Recent versions require no human intervention: the eggs incubate and hatch by themselves and the hatchlings climb out of the nest through a hollow bamboo "pipe" and fall into plastic bags, which can be easily emptied twice a day.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The iguanas are fed mixtures of broken rice meal, meat meal, bone meal, fish meal, papayas, bananas, mangos, avocados, and a variety of leaves and flowers. Each day they receive fresh-cut leaves from plants such as beans, mustard, or hibiscus. Hatchlings are raised to an age of 6-10 months, when they are big enough to be released into forests, farmland with scattered trees, or into village backyards with almost no vulnerability to predators.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">ADVANTAGES</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">With each female producing an average of 35 eggs annually, these animals have inherently high reproductive potential. And if the young are protected from predators during their first few months, populations can build up rapidly.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Iguanas adapt well to second-growth forest and to backyard conditions and can feed on the leaves of fruit trees or timber trees while the farmer can harvest the fruits or wood. Unless grossly overstocked, they are unlikely to affect the productivity of the trees.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">LIMITATIONS</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">These lizards may take three years to reach marketable size,2 and the cost of raising them to usable size entirely in captivity is currently greater than their market value as food. Less-expensive methods of raising the animals must be found if large-scale commercial iguana farming is to become economically feasible. The main problem is the high cost of the enclosures, not the cost of food. The food costs no more than that for raising a chicken to marketable size, but iguanas do not grow as fast as chickens. For smallholders the only cost of raising them is labor, and that is often unimportant. Free-ranging herbivorous lizards can damage home gardens.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">RESEARCH AND CONSERVATION NEEDS</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">For conservation purposes, the main need is to educate people throughout Latin America to the iguana's plight. For example, in Central America people catch pregnant females and cut out the eggs for food. (There is a widespread misconception that the females survive this brutality.) This is devastating to the iguana populations, yet by installing artificial nests, farmers could let the females live and still harvest the eggs. Moreover, people could eat half the eggs and incubate the other half to repopulate the trees around their farms.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">It is also important to develop an understanding of iguana reproduction in the wild. At present, the longevity, growth rate, and age of sexual maturity are not well known. Such information would provide baseline data for creating conservation measures to reverse the depletion of this natural resource.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Further husbandry research is needed. Costs must be reduced. The effectiveness of artificial nests must be tested in village practice. Survival rates of captive-raised young after release must be studied. And harvesting and recruitment schemes should be developed to secure optimum exploitation of the repopulated forests. </P>
+<P ALIGN="JUSTIFY"></P>
+<B><P>&lt;&lt;TOC3&gt;&gt; 34 Black Iguana</P>
+</B><P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&lt;&lt;I&gt;&gt; g039a.png FIGURE</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The work on green iguana husbandry may apply also to the black iguanas' (Ctenosaura similis, C. acanthura, C. hemilopha, and C. pectinata). These are similar lizards that live in dry habitats throughout Central America </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Exploitation of wild black iguanas for food began in ancient times and has continued in most places over hundreds of years without much harm to the natural populations. Until the 1970s, Latin Americans could obtain the meat and eggs with little effort, and the animals sold cheaply in city markets. In recent years, however, the lizards have become scarce and prices have risen sharply. For instance, in 1976 the central market of San Salvador was selling large specimens for the equivalent of 80 cents, but by 1979 prices were generally from three to six times as much. Today, black iguana meat costs more than fish, poultry, pork, or beef.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Eating small game animals is deeply rooted in the traditions of Central America and cannot readily be changed by legislation or education. Despite official edicts, campesinos on a subsistence diet will not willingly forego the little meat they get by capturing and eating lizards. Moreover, legislation is seldom effective because there are too few enforcement officials.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">As with the green iguana, it seems likely that when the factors causing hatchling mortality are reduced, a large harvestable annual surplus can be produced. Black iguanas efficiently convert vegetation into high-grade protein suitable for human consumption. Young ones, however, are insectivorous and carnivorous rather than purely herbivorous, and during their first weeks of life may require a more expensive diet (perhaps meat scraps) than green iguanas require. Moreover, most insectivorous lizards require moving prey. They may or may not accept meat scraps as food.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">APPEARANCE AND SIZE</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">Black iguanas are smaller and more stocky than green iguanas, but weigh up to 3 kg. Their tails are spiny and short. The scales on the tail are enlarged, grow in spirals, and are sharp-pointed. Other than that (apart from being generally greyish black in color), the two animals are similar in appearance.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">DISTRIBUTION</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">The different black iguana species range from northern Mexico along both coasts of Central America to Panama and Colombia's Caribbean islands. Most tolerate moderate human presence well, often thriving around town garbage dumps and cemeteries.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">STATUS</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">As recently as 1981, black iguanas were shipped to markets by the truckload. Today, they are generally limited or even absent over much of their original range. Nevertheless, they are still the major game animals across extensive areas of Central America. Many of those taken are gravid females, which is disastrous for the populations. Excessive insecticide spraying is also thought to be reducing their populations in some areas.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">HABITAT AND ENVIRONMENT</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">Black iguanas thrive in dry, open woodland. They particularly like rocky hillsides, for they depend for shelter on crevices, rock piles, or soft soil in which they dig burrows.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">BIOLOGY</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">These omnivores feed on foliage, flowers, and fruits, but also on insects and small vertebrates. Adults spend some of their time climbing trees, but they are much less arboreal than green iguanas. Hatchlings are initially terrestrial but have a mostly arboreal stage in their early weeks of life.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Females lay one clutch of 20-90 eggs each year. The eggs are much smaller than those of the green iguana and therefore are not as popular a food. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&lt;&lt;I&gt;&gt; p357a.png Distribution of the black iguana.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">BEHAVIOR</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">These lizards live in burrows or in holes in trees. A typical burrow has several entrances and is 1-2 m long. Several females may combine efforts to form a complex communal burrow with several individual nest chambers. They are such diligent diggers that many are caught while absorbed in the task of adding a new room.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">USES</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">In some places, even where they are not common, black iguanas are still intensively hunted. Because their meat is valuable, the reward justifies the considerable effort involved in finding and killing them. Hence, where populations are so depleted that organized hunting is unprofitable, the animals are still subjected to relentless destruction by individuals.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">HUSBANDRY</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">Farming black iguanas is a novel idea. However, it is not a foolish one. In 1981 the Centro de Recursos Naturales (CENREN) in El </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Salvador started a black iguana farming project. Since then, its researchers have collected data on growth rates, feeding patterns, and the maintenance and reproduction of captive adults. The program offers some promise of maintaining breeding stock in large outdoor enclosures, of producing large numbers of hatchlings, and of restocking depleted areas.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">OTHER IGUANAS</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">Other iguanas that deserve consideration for husbandry include the rock (rhinoceros) iguana (Cyclura cornuta), a herbivorous lizard of the Antillean region. This has been raised in considerable numbers at the National Zoo of Santo Domingo, Dominican Republic. Captive-bred specimens have reproduced at the age of 32 months, average clutch size has been about 15, and the average incubation time has been 82 days (at 31&Yacute;C). The innate tameness of these island iguanas renders them better adapted for captive rearing than either the green or the black iguana, and their greater size is an advantage as well. On the other hand, the length of time required to reach maturity, and the relatively small egg clutch (about half that of the green iguana and one-third that of the black iguana) are definite disadvantages.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">A related species, Iguana delicatissima, also deserves research and conservation attention. It occurs in the Leeward Islands and Martinique, and (as its specific name implies) is even better eating than the green iguana.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">ADVANTAGES</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">Latins believe that various ailments are cured or benefited by the flesh of these lizards, so they willingly pay much more for their meat than they would for equivalent amounts of other meats. In most places where the two occur together, the black iguana is preferred over the green iguana.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Compared with green iguana, the black iguana reproduces readily in captivity and has an even higher reproductive potential (averaging 43 eggs per clutch). It has the additional advantage that it thrives in deforested and altered habitats. It can survive near human settlements despite the attacks of dogs and cats, and it attains dense populations in suburban lots or open spaces. (It survives even downtown in cities such as Managua, but not in dense populations because dogs, cats, and humans take so many.) Hence, even in towns and cities, there are habitats capable of supporting it.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Black iguanas will feed on weedy vegetation or garbage, and adults seem easier to maintain in captivity than their green iguana counterparts.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">LIMITATIONS</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">The long delay (probably at least two years) before the animals reach marketable size might make it difficult for the grower to compete with common meats such as poultry or fish. Certain parasitic worms can make the flesh inedible.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Although smaller than green iguanas, black iguanas are much more aggressive and will defend what they perceive to be their territory. They can inflict a painful bite. They also tend to escape from captivity more readily.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">As noted, these omnivores depend on animal matter during part of their life cycle.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">RESEARCH AND CONSERVATION NEEDS</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">The biology of the black iguana deserves much more study.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Management techniques developed for the green iguana should be tested for their applicability for black iguana species. Harvesting and recruitment schemes must be developed to create sustainable populations in the wild. The specific needs for feeding the young also need to be addressed.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">I am convinced that in the Third World, it is only when poor people are assured of their livelihood that they will help us to safeguard their natural environments. So long as people remain hungry, it is very difficult to talk to them about conservation. As a result, I believe that development and conservation are inseparable. Only when conservation takes on a dimension of helping the poor, the downtrodden, the destitute, will it have an enduring impact.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">M.S. Swaminathan International Union for Conservation of Nature and Natural Resources</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">I suspect that wildness is an inherited characteristic as was found for the turkey by Starker Leopold. So in attempting domestication one should expect to have difficulty until there are enough animals that you can select breeding stock for quietness and tractability.</P>
+<P ALIGN="JUSTIFY">Ian McTaggart Cowan Emeritus Professor of Zoology</P>
+<P ALIGN="JUSTIFY">University of British Columbia</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Cattle will never be extinct for the simple reason that man eats cattle. The best way to preserve wild species is by demonstrating that they, too, can be a valuable resource.</P>
+<P ALIGN="JUSTIFY">Ernie Matteram</P>
+<P ALIGN="JUSTIFY">New York Times Magazine</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Wildlife utilization should be considered a legitimate form of land use, just as much as livestock husbandry. In fact, what has happened in the past is that Man has domesticated a limited number of animals, mainly in the temperate zones, while overlooking a considerable potential of other animals, which could be domesticated or used with equal validity.</P>
+<P ALIGN="JUSTIFY">Antoon De Vos </P>
+<P ALIGN="JUSTIFY"></P>
+<B><P ALIGN="CENTER">&lt;&lt;TOC2&gt;&gt; Part VII Others</P>
+</B><P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">As noted in the preface, this report by no means exhausts all the microlivestock possibilities. Lack of space and time precludes discussion of creatures such as edible insects, snails, worms, frogs, turtles, and bats, which in some regions are highly regarded foods. Similarly, we have not included fish, shrimp, and other aquatic life.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">This is not to say that these are less worthy of consideration. The decision to leave them out was arbitrary, but with several recent breakthroughs in tropical beekeeping it seems prudent to include bees. Accordingly, the final chapter of this book describes the smallest livestock of all.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Bees are one of the most promising microlivestock. They forage on flowers that are otherwise little utilized and produce honey, wax, and other products of high value. They are important as plant pollinators and can greatly increase the production of some crops. Bees can be kept virtually anywhere with little disruption of other activities, and they are easily available. </P>
+<P ALIGN="JUSTIFY"></P>
+<B><P>&lt;&lt;TOC3&gt;&gt; 35 Bees</P>
+</B><P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&lt;&lt;I&gt;&gt; g040a.png FIGURE</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Of all the livestock reviewed in this publication, bees are the smallest, the least demanding of space, probably the most familiar, and perhaps the most easily adapted to worldwide rural development efforts. For all that, however, they are an often forgotten component in agricultural programs. This is unfortunate because bees can be particularly valuable to tropical countries, providing pollination of crops, useful products, and a premium source of income.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Almost every village in every tropical country traditionally has had a beekeeper or two. Most use "seat-of-the-pants" methods and "rustic" hives, and this generally leads to low yields and inefficiencies. Today, numerous innovative methods and appropriate equipment are coming available. Many are still not widely known; however, their importance is slowly being recognized. Indeed, some developing countries are already turning bees into a valued natural resource.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">For example, in less than 10 years Kenya has become self-sufficient in honey production and - despite increased local consumption - is now exporting. In seven years, Papua New Guinea has met its local honey requirements and now also exports its surplus. In only four years, Thailand increased yearly production from practically nothing to more than 1,000 tons. In Brazil, beekeeping is more widespread and production greater than before the outbreak of the African honey bee. These achievements can be largely attributed to the promotion of innovative equipment, modern beekeeping techniques, and extension support for small-scale beekeepers.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">APPEARANCE AND SIZE</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">Honey bees are generally easily recognized and need no description here. The major species and subspecies are all roughly similar in appearance and size. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">DISTRIBUTION</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">Among several hundred species of bees that store honey and pollen in harvestable amounts, only two "social" species, Apis mellifera and Apis cerana, produce multiple combs and can be kept in hives.' Given adequate forage and proper management, they can build up a honey surplus that can be harvested without harming their colonies.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Apis mellifera, the most widely distributed and exploited honey bee, comes from Europe and Africa. The subspecies from Europe (especially the Italian type, A. mellifera ligustica) is normally preferred because of its docility and high honey yields. It is now the predominant honey bee throughout the temperate zones of Europe, North America, Australasia, and China. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Of the many subspecies in Africa, A. mellifera adansonii and A. mellifera scutellata have the widest native ranges. The latter was accidently released in Brazil in 1957. It has become naturalized and has dominated the European bees formerly kept by beekeepers. By l990, it had spread northwards to the southernmost areas of the United States and southwards deep into Argentina.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The docile Asian hive bee, A. cerana, is found in Asia from the Middle East to Japan and as far south as Indonesia. Although it produces much less honey per hive than A. mellifera, its overall production in many Southeast Asian countries may be greater.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">STATUS</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">Honey bees do not face extinction. However, genetic diversity is disappearing due to loss of habitat, insecticides, displacement by massproduced, genetically uniform queens and exotic breeds, destructive harvesting, and the spread of diseases and pests such as protozoans, bacteria, insects, and mites.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">HABITAT AND ENVIRONMENT</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">Honey bees can exist in locations from deserts to rainforests and from near the Arctic to the tropics. They occur wherever there is nectar, pollen, tree resin (for nest building), shelter, and a little water. Heat, drought, and especially rain and humidity may curtail their activities, but a well-managed colony can survive periods of extreme adversity. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">BIOLOGY</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">Honey bees live in rigidly hierarchical colonies. Normally there is a  single queen. After mating, she begins laying hundreds of eggs a day.  Those that are fertilized become sterile females, called workers; those  that remain unfertilized develop into males (drones), whose only role is  to fertilize future queens.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">After two or three years the queen, worn-out, starts laying fewer  and fewer eggs, and the colony may replace her. At that time a few  female larvae are raised on royal jelly, a nutritious, little-understood  secretion that causes them to develop into queens.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Workers perform different tasks as they mature. Young ones tend  the queen, guard the hive, and raise the larvae. Older ones, comprising  the vast majority of a colony's population, gather pollen and nectar and  water. Pollen provides the protein and fats, and the nectar, converted  into honey in the bee's body, provides carbohydrates to feed the colony.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">BEHAVIOR</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">Honey bee activities are dictated by weather, availability of food,  genetics, and the overall strength of the colony. They are mediated by  chemical interactions between the queen and the workers that control  almost all behavior.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">While the Asian and European hive bees are relatively docile, most  of the African subspecies are unpredictable and may defend their  colonies in great numbers and with great persistence. The threat of  "killer bees" has been greatly exaggerated, however. Africans have  provided them nests and hives - and harvested their honey - for  thousands of years.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Occasionally, large numbers of the bees in a colony split off from  their nest or hive. They usually cluster on a nearby tree or building,  calmly waiting for "scouts" to find a suitable new home. These  homeless swarms can be captured and will readily move into a hive  the simplest and cheapest way for beekeepers to acquire a colony.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">USES</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">Honey and beeswax are two of nature's best known and most  valuable products. Honey can be employed in hundreds of foods. It is  widely used in baking because, in addition to its flavor, it retains  moisture better than sugar or syrup, and the product keeps longer. Honey-based alcoholic beverages are popular in many parts of the world.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Beeswax also is used in many products, including candles, lubricants, polish, waterproofings, soaps, cosmetics, and electronics. Beeswax can be locally important for `'lost-wax" metal-casting and sculptures as well as batik-dyed clothing.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Both bee pollen and royal jelly are used in cosmetics and can be eaten. Bee venom is used medicinally, particularly in Europe and the developing world. Bee larvae are eaten raw or fried in many parts of Asia and Africa and are considered a delicacy.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">HUSBANDRY</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">Keeping bees means managing a colony so that it produces surplus honey or wax. Specifically this requires:</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">- Providing a suitable hive;</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">- Obtaining bees by collecting a swarm, transferring a wild colony, or purchasing a colony complete with an active queen;</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">- Maintaining the colony free from natural enemies in an area that allows it to produce excess honey; and</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">- Harvesting the excess honey without weakening the colony or causing it to flee (abscond).</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">ADVANTAGES</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">Few other livestock enterprises require less capital, less space, or less attention. Moreover, scarcely any other provides higher quality, more marketable products.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Beekeeping is a respected and traditional activity in most areas of the world. It promotes self-reliance and requires little, if any, land or money. It is an easy-entry cottage industry that can be started with minimal equipment or training. It can be done by any member of a family as it requires no special strength or size. It is especially appropriate for increasing women's income in the many areas where men are away working.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Beekeeping is suited to remote areas where many agricultural enterprises are at a competitive disadvantage because their products are bulky and far from the markets. Honey, wax, pollen, and other bee products can all be sold far from their point of origin, have high monetary value for their weight, and generally find a ready market. Local honeys often command premium prices (in part because many of them are considered medicinal). In addition, beekeeping encourages people to remain in rural areas rather than move to the city in search of an income.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Pollination increases the productivity of many crops, and therefore a few hives can boost local food production. By rotating hives among farmers' fields and orchards, a beekeeper performs a valuable service.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Beekeeping is also an important adjunct to reforestation and desert reclamation projects. It can provide income during the long wait for the trees to reach marketable size. Many forests are potential reservoirs of honey and other products. In some cases, the bees also enhance the fruitfulness and standing value of forests. They also increase pollination in tree-seed orchards and tree nurseries. And in newly established forests, bees improve reseeding potential. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">BETTER BEEHIVES</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">So many hives have been developed in recent years that a design now exists for almost any level of expertise. One of the most important for Third World beekeeping is the top-bar hive. This crate-like box, derived from an ancient Greek design, incorporates modern beekeeping principles but adds the innovation of sloping sides. Beneath its lid are removable boards (top bars) from which the bees hang the combs (because the sides are sloping the bees do not attach the edges of the comb to them). By lifting a top bar, the comb can be inspected and handled - and the honey harvested - with little disturbance to the colony.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">This simple hive can make beekeeping accessible to even the poorest people. It is easy to build and use, and can be locally constructed from scrap lumber. It is well suited for raising most types of honey bees.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">More elaborate and productive is the African long hive. In addition to having top bars, this square-sided box has removable frames within which the bees build their comb.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The most elaborate is the Langstroth hive - the type most common in temperate zones.* These yield the most honey. They can be made only where there are facilities for precise carpentry, where durable, nonwarping parts are available, and where there are good extension services to aid and assist beekeepers. Although traditional Langstroth hives are demanding to build and maintain, simplified designs have been created for use in developing countries.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">STINGLESS BEES</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">By far the most common bees in the tropics, perhaps in the  world, are bees that cannot sting. Their stingers are so akophied  as to be essentially nonexistent (but some can deliver a pretty  fierce bite). They live in colonies and store their honey in wax  pots, some as large as egg cups.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Stingless bees can be abundant. In a two-block area in  downtown Panama City, 150 nests have been counted. However,  many species depend on trees and their populations are  plummeting as more and more tropical forests are felled.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Like honey bees, stingless bees have been "domesticated." For  thousands of years in the tropical Americas, Indians have raised  them in special hives made out of logs, gourds, clay pots, and  other simple containers. Cortes reported in 1519 that Indians on  the island of Cozumel, the now popular tourist spot off the east  coast of Yucatan, practiced beekeeping. That was almost 300 years  before the European honeybee was introduced. A popular Mayan  drink was honey wine, and Mayan beekeepers carved stone  earplugs to keep these bees out of their ears.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Honey from stingless bees has less sugar than normal honey.  However, it is usually more tasty. It is used throughout the  tropics: the Americas, Central Africa, and Southeast Asia, for  instance. Normally, the nests are just robbed, which devastates  the bees because the queen cannot fly, and when she is disturbed  the colony dies. In some areas people open a little hole in the nest.  By putting in a plug, they can then harvest honey a couple of  times a year without destroying the colony.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Today, a few scientists are reconsidering stingless beekeeping.  In the state of Maranhao in Brazil, an area of crushing poverty,  biologist Warwick Kerr is harnessing stingless bees. He began  after learning that peasants were spending a third of their meager  incomes buying sugar. As part of his experiments, he keeps 60  hives stacked in his garage on the outskirts of the city of San Luis.  (A notable feature of these bees is that there is no prohibition  against keeping them in populated areas.)</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Kerr has found that stingless bees can be made to produce well.  After years of experimenting with different-sized boxes, he can  now obtain more than 4.5 lifers of honey per hive per year. He  reports that the stingless bees are easy to maintain, and can be  raised by poor peoole without land or equipment.  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">LIMITATIONS</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">Compared to raising four-footed livestock, beekeeping is inexpensive and fairly trouble free, but it is not without problems. Many things can go wrong, and include, for example:</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">- Losses. Bees are susceptible to various predators, pests, and diseases. Although ways to avoid or control most afflictions are available, once a colony becomes infested it may have to be destroyed.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">- Theft. Hives or combs - usually kept in secluded areas - that are full of honey are tempting targets and may be stolen.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">- Swarming and absconding. Some or all of the bees may leave a hive and start a new nest, taking even the honey with them.2</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">- Bad management. Beekeeping requires certain skills and knowledge, and sometimes frequent attention (such as when the colony is stressed, diseased, or swarming).</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">- Lack of equipment. Beekeepers need hives, smokers (to quiet and repel the bees), hive tools, and - advisable but not absolutely necessary - gloves and a veil.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">- Inadequate storage. Some areas lack the knowledge or the bottles in which to store liquid honey.3</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">- Pesticides and herbicides. Nectar- and pollen-collecting bees are vulnerable to insecticides, which farmers may apply (often inappropriately) at the time their crops are flowering. Herbicides can destroy important sources of bee forage.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">- Neighborhood concerns. Bees can sting people and livestock. Although wild bees (and other insects) are the principal culprits, the beekeeper is often blamed.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">- Stressful conditions. When rainfall, aridity, heat, or cold are excessive, bees often cannot produce surplus honey.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">RESEARCH AND CONSERVATION NEEDS</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">Surprisingly, much remains to be learned about the natural science of bees. Although some of the research requires sophisticated equipment and facilities, much can (or must) be performed locally by beekeepers because many factors - such as colony behavior, foraging habits, and microclimatic adaptation - depend on the local conditions. This research may include the following:</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">- Adaptation. The provision of locally adapted bee varieties is an important basis for developing advanced beekeeping. This can be done by selecting an appropriate local queen. Further, local breeding of queens and workers lessens the probability of importing exotic diseases and pests. Recent developments promise to move the mass production of queens and workers from the realm of high technology to common practice.4</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">- Integration. Continued developments in beekeeping cannot succeed without research, promotion, education, training, and extension services. These are essential for integrating beekeeping with agriculture and reforestation efforts. Thus, descriptions of agronomic plants should always include pollination requirements as well as nectar and pollen potentials. Planting nectar- and pollen-producing firewood species would increase the number of bees, which would in turn help ensure forest survival.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">- Bee plants. There is still much to be understood about the relative qualities that different plants bring to beekeeping. Recently, many valuable bee-forage plants have been identified.5 These deserve special consideration in any reforestation or beautification projects. Broad introduction of these plants may also encourage beekeeping that could produce high-value "specialty" honeys or ensure more continuous production of honey. There may also be a place for "bee farms," where every plant is bee forage.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">- New bee species. Nontraditional species of Apis as well as other members of the bee family (such as Anthophora, Bombus, Megachilae, Nomia, Osmia, Xylocopa, and especially Trigona and Melipona, which are stingless) should be studied to determine their role in pollination and - for some species - their further exploitation for honey. </P>
+<P ALIGN="JUSTIFY"></P>
+<B><P ALIGN="CENTER">&lt;&lt;TOC2&gt;&gt; Appendixes</P>
+</B><P ALIGN="JUSTIFY"></P>
+<B><P>&lt;&lt;TOC3&gt;&gt; A Selected Readings</P>
+</B><P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">A small selection follows of books and articles that are not too  difficult to locate and that will help readers explore each topic further. Obscure documents are accompanied by an address from which readers can obtain a reprint or photocopy.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">GENERAL</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Grzimek, B. 1975. Animal Life Encyclopedia. Vol. 1-13. Van Nostrand Reinhold  Company, New York.</P>
+<P ALIGN="JUSTIFY">Robbins, C.T. 1983. Wildlife Feeding and Nutrition. Academic Press, Inc., New York.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">MICROBREEDS</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Mason, I.L. 1988. A World Dictionary of Livestock Breeds, Types and Varieties.  Commonwealth Agricultural Bureaux, Farnham Royal, Buckinghamshire, UK. Microcattle</P>
+<P ALIGN="JUSTIFY">Barnard, J.P. and J.P. Venter. 1983. Indigenous and Exotic Beef Cattle in South West  Africa - A Progress Report. Available from Department of Agriculture and Nature  Conservation, PB 13184, Windhoek 9000, Namibia. (Sanga)</P>
+<P ALIGN="JUSTIFY">Cheng Peilieu. 1984. Livestock Breeds of China. FAO Animal Production and Health  Paper 46. Food and Agriculture Organization of the United Nations, Rome. 217 pp.</P>
+<P ALIGN="JUSTIFY">Cole, H.H. and W.N. Garrett, eds. 1974. Animal Agriculture. 2nd edition. W.H. Freeman  and Company, San Francisco, California, USA.</P>
+<P ALIGN="JUSTIFY">Epstein, H. and l.L. Mason. 1984. Cattle. Pages 6-27 in Evolution of Domesticated  Animals, I.L. Mason, ed. Longman, London.</P>
+<P ALIGN="JUSTIFY">Felius, M. 1985. Genus Bos: Cattle Breeds of the World. MSD-AGVET, Merck and Co.,  Rahway, New Jersey. 234 pp.</P>
+<P ALIGN="JUSTIFY">Gryseels, G. 1980. Improving Livestock and Farm Production in the Ethiopian Highlands:  Initial Results. ILCA study. International Livestock Centre for Africa, Addis Ababa,  Ethiopia.</P>
+<P ALIGN="JUSTIFY">ILCA. 1979. Trypanotolerant Livestock in West and Central Africa. Vol. 1, General Study.  International Livestock Centre for Africa, Addis Ababa, Ethiopia.</P>
+<P ALIGN="JUSTIFY">Joshi, N.R. and R.W. Phillips. 1953. Zebu Cattle of India and Pakistan. FAO Agricultural  Study No. 19. Food and Agriculture Organization of the United Nations, Rome. 297 pp.</P>
+<P ALIGN="JUSTIFY">Joshi, N.R., E.A. McLaughlin, and R.W. Phillips. 1957. Types and Breeds of African  Cattle. FAO Agricultural Study No. 37. Food and Agriculture Organization of the  United Nations, Rome. 297 pp. </P>
+<P ALIGN="JUSTIFY">Koger, M., T.J. Cunha, and A.C. Warnick, eds. 1973. Crossbreeding Beef Cattle. Series 2. University of Florida Press, Gainesville, Florida, USA.</P>
+<P ALIGN="JUSTIFY">Martinez Balboa, A. 1980. La Ganaderia en Baja California Sur. Vol. 1. Editorial J.B. La Paz, BCS: Mexico. 229 pp. (Criollo)</P>
+<P ALIGN="JUSTIFY">Mason, I.L. and J.P. Maule. The Indigenous Livestock of Eastern and Southern Africa. Commonwealth Agricultural Bureaux, Farnham Royal, Buckinghamshire, UK.</P>
+<P ALIGN="JUSTIFY">Maule, J.P. 1989. The Cattle of the Tropics. Centre for Tropical Veterinary Medicine, Edinburgh University, Edinburgh, UK.</P>
+<P ALIGN="JUSTIFY">McDowell, L.R., ed. 1985. Nutrition of Grazing Ruminants in Warm Climates. Academic Press, Inc., New York.</P>
+<P ALIGN="JUSTIFY">McDowell, R.E. 1972. Improvement of Livestock Production in Warm Climates. W.H. Freeman and Company, San Francisco, California, USA.</P>
+<P ALIGN="JUSTIFY">McDowell, R.E. 1983. Strategy for Improving Beef and Dairy Cattle in the Tropics. Cornell International Agricultural mimeo. Cornell University, Ithaca, New York.</P>
+<P ALIGN="JUSTIFY">Miller, W.J. 1979. Dairy Cattle Feeding and Nutrition. Academic Press, Inc., New York.</P>
+<P ALIGN="JUSTIFY">National Research Council. 1980. Animal Science in China. CSCPRC Report No. 12. National Academy Press, Washington, D.C.</P>
+<P ALIGN="JUSTIFY">National Research Council. 1981. Effect of Environment on Nutrient Requirements of Domestic Animals. National Academy Press, Washington, D.C.</P>
+<P ALIGN="JUSTIFY">Perry, T.W. 1980. Beef Cattle Feeding and Nutrition. Academic Press, Inc., New York.</P>
+<P ALIGN="JUSTIFY">Rollinson, D.H.L. 1984. Bali cattle. Pages 28-34 in Evolution of Domesticated Animals, I.L. Mason, ed. Longman, London.</P>
+<P ALIGN="JUSTIFY">Rouse, J.E. 1970. World Cattle. Vol. 1, Cattle of Europe, South America, Australia, and New Zealand. University of Oklahoma Press, Norman, Oklahoma, USA.</P>
+<P ALIGN="JUSTIFY">Rouse, J.E. 1970. World Cattle. Vol. 2, Cattle of Africa and Asia. University of Oklahoma Press, Norman, Oklahoma, USA.</P>
+<P ALIGN="JUSTIFY">Rouse, J.E. 1973. World Cattle. Vol.3, Cattle of North America. University of Oklahoma Press, Norman, Oklahoma, USA.</P>
+<P ALIGN="JUSTIFY">Rouse, J.E. 1977. The Criollo-Spanish Cattle in the Americas. University of Oklahoma Press, Norman, Oklahoma, USA. 303 pp.</P>
+<P ALIGN="JUSTIFY">Shirley, R.L. 1986. Nitrogen and Energy Nutrition of Ruminants. Academic Press, Inc., New York.</P>
+<P ALIGN="JUSTIFY">Thrower, W.R. 1954. The Dexter Cow. Revised third impression, 1980. The Spaulding Press, Bethel, Vermont, USA</P>
+<P ALIGN="JUSTIFY">Williamson, G. and W.J.A. Payne. 1965. An Introduction to Animal Husbandry in the Tropics. 2nd edition. Longman, London.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Microgoat</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Acharya, R.M. 1982. Sheep and Goat Breeds of India. FAO Animal Production and Health Paper No. 30. Food and Agriculture Organization of the United Nations, Rome.</P>
+<P ALIGN="JUSTIFY">Ademosun, A.A. 1985. Capra spp.: The Emblem of Anarchy - The King-Pin of Man's Pastoral Life. Ife Lectures No. 3. University of Ife, Ile-Ife, Nigeria.</P>
+<P ALIGN="JUSTIFY">Cheng Peilieu. 1984. Livestock Breeds of China. FAO Animal Production and Health Paper 46. Food and Agriculture Organization of the United Nations, Rome. 217 pp.</P>
+<P ALIGN="JUSTIFY">Cole, H.H. and W.N. Garrett. 1980. Animal Agriculture. W.H. Freeman and Company, San Francisco, California, USA.</P>
+<P ALIGN="JUSTIFY">Copland, J.W. 1985. Goat Production and Research in the Tropics. Proceedings of a workshop held at the University of Queensland, Brisbane, Australia, February 6-8, 1984. Australian Centre for International Agricultural Research (ACIAR) Proceedings Series No. 7, 118 pp.</P>
+<P ALIGN="JUSTIFY">Devendra, C. and M. Burns. 1983. Goat Production in the Tropics. Commonwealth Agricultural Bureaux, Farnham Royal, Buckinghamshire, UK. 83 pp.</P>
+<P ALIGN="JUSTIFY">Devendra, C. and G.L. McLeroy. 1983. Goat and Sheep Production in the Tropics. 2nd edition. Longman, London. 271 pp.</P>
+<P ALIGN="JUSTIFY">Devendra, C. and J.E. Owen. 1983. Quantitative and qualitative aspects of meat production from goats. World Animal Review (FAO) 47:19-29.</P>
+<P ALIGN="JUSTIFY">Fielding, D. Goat-keeping in Mauritius. Sonderdruck aus Zeitschrift fur Tierzuchtung und Zuchtungsbiologie. Vol 97(1)(1980):21-27.</P>
+<P ALIGN="JUSTIFY">Gall, C., ed. 1981. Goat Production. Academic Press, London. 619 pp.</P>
+<P ALIGN="JUSTIFY">Haenlein, G.F.W. and D.L. Ace. 1983. Goat Extension Handbook. University of Delaware Cooperative Extension Service, Newark, Delaware, USA.</P>
+<P ALIGN="JUSTIFY">Husnain, H.V. 1985. Sheep and Goats in Pakistan. FAO Animal Production and Health Paper No. 56. Food and Agriculture Organization of the United Nations, Rome.</P>
+<P ALIGN="JUSTIFY">International Development Research Centre (IDRC). Small Ruminant Production Systems in South and Southeast Asia, C. Devendra, ed. Proceedings of a workshop held in Bogor, Indonesia, October 6-10, 1986, cosponsored by the Small Ruminant Collaborative Research Support Program. Ottawa, Ontario, Canada.</P>
+<P ALIGN="JUSTIFY">ILCA. 1983. Peste des Petits Ruminants (PPR) in Sheep and Goats, D.H. Hill, ed. Proceedings of the International Workshop held at the International Institute of Tropical Agriculture (IITA), Ibadan, Nigeria, September 24-26, 1980. International Livestock Centre for Africa, Addis Ababa, Ethiopia.</P>
+<P ALIGN="JUSTIFY">ILCA. 1985. Sheep and Goats in Humid West Africa. Proceedings of the International Workshop held in Ibadan, Nigeria, January 23-26, 1984. International Livestock Centre for Africa, Addis Ababa, Ethiopia.</P>
+<P ALIGN="JUSTIFY">ILCA. 1979. Trypanotolerant Livestock in West and Central Africa. Vol. 1, General Study. International Livestock Centre for Africa, Addis Ababa, Ethiopia.</P>
+<P ALIGN="JUSTIFY">King, J.W.B., ed. 1988. Directory of Research on Sheep and Goats. Commonwealth Agricultural Bureaux International, Wallingford, Oxford, UK. 271 pp.</P>
+<P ALIGN="JUSTIFY">Mason, I.L. 1981. Breeds. Pages 57-110 in Goat Production, C. Gall, ed. Academic Press, London.</P>
+<P ALIGN="JUSTIFY">Mason, I.L. 1984. Goat. Pages 85-99 in Evolution of the Domesticated Animals, I.L. Mason, ed. Longman, London.</P>
+<P ALIGN="JUSTIFY">Mason, I.L. and J.P. Maule. 1960. The Indigenous Livestock of Eastern and Southern Africa. Commonwealth Agricultural Bureaux, Farnham Royal, Buckinghamshire, UK.</P>
+<P ALIGN="JUSTIFY">National Research Council, 1980. Animal Science in China. CSCPRC Report No. 12. National Academy Press, Washington, D.C.</P>
+<P ALIGN="JUSTIFY">Phillips, R.W., R.G. Johnson, and R.T. Moyer. 1945. The Livestock of China. U.S. Department of State Publication No. 2249, Far Eastern Series 9. U.S. Department of State, Washington, D.C. 174 pp.</P>
+<P ALIGN="JUSTIFY">Proceedings of the 3rd International Conference on Goat Production and Disease. January 10-15, 1982, University of Arizona, Tucson, Arizona. Copies can be obtained from Kent Leach, Dairy Goat Journal, P.O. Box 1808, Scottsdale, Arizona 85252, USA. </P>
+<P ALIGN="JUSTIFY">Williamson, G. and W.J.A. Payne. 1965. An Introduction to Animal Husbandry in the Tropics. 2nd edition. Longman, London.</P>
+<P ALIGN="JUSTIFY">Wilson, R.T., T. Murayi, and A. Rocha. 1989. Indigenous African small ruminant strains with potentially high reproductive performance. Small Ruminant Research 2: 107-117.</P>
+<P ALIGN="JUSTIFY">Winrock International, 1984. Sheep and Goats in Developing Countries. Winrock International Technical Paper. The World Bank, Washington, D.C. </P>
+<P ALIGN="JUSTIFY">Acharya, R.M. 1982. Sheep and Goat Breeds of lndia. FAO Animal Production and Health Paper No. 30. Food and Agriculture Organization of the United Nations, Rome.</P>
+<P ALIGN="JUSTIFY">Carles, A.B. 1983. Sheep Production in the Tropics. Oxford University Press, London. 213 pp.</P>
+<P ALIGN="JUSTIFY">Cheng Peilieu. 1984. Livestock Breeds of China. FAO Animal Production and Health Paper 46. Food and Agriculture Organization of the United Nations, Rome. 217 pp. Cole, H.H. and W.N. Garrett. 1980. Animal Agriculture. W.H. Freeman and Company,</P>
+<P ALIGN="JUSTIFY">San Francisco, Calffornia, USA.</P>
+<P ALIGN="JUSTIFY">Devendra, C. and G.L. McLeroy. 1983. Goat and Sheep Production in the Tropics. </P>
+<P ALIGN="JUSTIFY">Longman, London. 271 pp.</P>
+<P ALIGN="JUSTIFY">Fitzhugh, H.A. and G.E. Bradford, eds. 1983. Hair Sheep of Western Africa and the Americas. Westview Press, Boulder, Colorado, USA. </P>
+<P ALIGN="JUSTIFY">Husnain, H.V. 1985. Sheep and Goats in Pakistan. FAO Animal Production and Health Paper No. 56. Food and Agriculture Organization of the United Nations, Rome. International Development Research Centre (IDRC). 1987. Small Ruminant Production Systems in South and Southeast Asia, C. Devendra, ed. Proceedings of a workshop held in Bogor, Indonesia, October 6-10, 1986, cosponsored by the Small Ruminant Collaborative Research Support Program. IDRC, Ottawa, Canada. </P>
+<P ALIGN="JUSTIFY">ILCA. 1983. Peste des Petits Ruminants (PPR) in Sheep and Goats, D.H. Hill, ed. Proceedings of the International Workshop held at the International Institute of Tropical Agriculture (IITA), Ibadan, Nigeria, September 24-26, 1980. International Livestock Centre for Africa, Addis Ababa, Ethiopia.</P>
+<P ALIGN="JUSTIFY">ILCA. 1985. Sheep and Goats in Humid West Africa. Proceedings of the International Workshop held in Ibadan, Nigeria, January 23-26, 1984. International Livestock Centre for Africa, Addis Ababa, Ethiopia.</P>
+<P ALIGN="JUSTIFY">ILCA. 1979. Trypanotolerant Livestock in West and Central Africa. Vol. 1, Ceneral </P>
+<P ALIGN="JUSTIFY">Study. International Livestock Centre for Africa, Addis Ababa, Ethiopia. </P>
+<P ALIGN="JUSTIFY">King, J.W.B., ed. 1988. Directory of Research on Sheep and Goats. Commonwealth</P>
+<P ALIGN="JUSTIFY">Agricultural Bureaux International, Wallingford, Oxford, UK. 271 pp.</P>
+<P ALIGN="JUSTIFY">Mason, I.L. 1980. Prolific Tropical Sheep. FAO Animal Production and Health Paper No. 17. Food and Agriculture Organization of the United Nations, Rome.</P>
+<P ALIGN="JUSTIFY">Mason, l.L.1967. Sheep Breeds of the Mediterranean. Food andAgriculture Organization of the United Nations. Commonwealth Agricultural Bureaux, Farnham Royal, UK.</P>
+<P ALIGN="JUSTIFY">Mason, I.L. and J.P. Maule. 1960. The Indigenous Livestock of Eastern and Southern Africa. Commonwealth Agricultural Bureaux, Farnham Royal, Buckinghamshire, UK. Phillips, R.W., R.C. Johnson, and R.T. Moyer. 1945. The Livestock of China. U.S. Department of State Publication No. 2249, Far Eastern Series 9. U.S. Department of State, Washington, D.C. 174 pp.</P>
+<P ALIGN="JUSTIFY">Ponting, K. 1980. Sheep of the World. Blandford Press, Ltd., Poole, Dorset, UK.</P>
+<P ALIGN="JUSTIFY">Ryder, M.L. 1984. Sheep. Pages 63-85 in Evolution of Domesticated Animals, I.L. Mason, ed. Longman, London.</P>
+<P ALIGN="JUSTIFY">Ryder, M.L. 1983. Sheep and hIan. Monograph. Duckworth, London.</P>
+<P ALIGN="JUSTIFY">Terrill, C.E. 1970. Sheep breeds of the world. (505 breeds). USDA mimeo. U.S. Department of Agriculture, Washington, D.C. 163 pp.</P>
+<P ALIGN="JUSTIFY">Whitehurst, V.E., R.M. Crown, R.W. Phillips, and D.A. Spencer. 1947. Productivity of Columbia sheep in Florida and their use for crossing with native sheep. Florida Agricultural Experimental Station Bulletin 429. 34 pp.</P>
+<P ALIGN="JUSTIFY">Williamson, G. and W.J.A. Payne. 1965. An Introduotion to Animal Husbandry in the Tropics. 2nd edition. Longman, London. </P>
+<P ALIGN="JUSTIFY">Wilson, R.T., T. Murayi, and A. Rocha. 1989. Indigenous African small ruminant strains with potentially high reproductive performance. Small Ruminant Research 2: 107-117. Winrock International. 1984. Sheep and Goats in Developing Countries. Winrock International Technical Paper. The World Bank, Washington, D.C.</P>
+<P ALIGN="JUSTIFY">Yaltin, B.C. 1979. The Sheep Breeds of Afghanistan, lran, and Turkey. Food and Agriculture Organization of the United Nations, Rome.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Micropig</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Cheng Peilieu. 1984. Livestock Breeds of China. FAO Animal Production and Health Paper 46. Food and Agriculture Organization of the United Nations, Rome.</P>
+<P ALIGN="JUSTIFY">Clutton-Brock, J. 1981. Domesticated Animals from Early Times. British Museum (Natural History), London.</P>
+<P ALIGN="JUSTIFY">Cole, H.H. and W.N. Garrett. 1980. Animal Agriculture. W.H. Freeman and Company, San Francisco, Calffornia, USA.</P>
+<P ALIGN="JUSTIFY">Cunha, T.J. 1977. Swine Feeding and Nutrition. Academic Press, Inc., New York.</P>
+<P ALIGN="JUSTIFY">Epstein, H. and M. Bichard. 1984. Pigs. Pages 145-162 in Evolution of Domesticated </P>
+<P ALIGN="JUSTIFY">Animals, I.L. Mason, ed. Longman, London. </P>
+<P ALIGN="JUSTIFY">Krider, J.L., J.H. Conrad, and W.E. Carroll. 1982. Swine Production. McGraw-Hill Company, New York.</P>
+<P ALIGN="JUSTIFY">Mason, I.L. and J.P. Maule. 1960. The Indigenous Livestock of Eastern and Southern Africa. Commonwealth Agricultural Bureaux, Farnham Royal, Buckinghamshire, UK. National Research Council. 1983. Little-Known Asian Animals with a Promising Economic Future. National Academy Press, Washington, D.C. National Research Council. 1980. Animal Science in China. CSCPRC Report No. 12. National Academy Press, Washington, D.C.</P>
+<P ALIGN="JUSTIFY">Panepinto, L.M. 1986. Miniature swine in biomedical research. LabAnimal 15(8)(November/December 1986):21-27.</P>
+<P ALIGN="JUSTIFY">Panepinto, L.M., R.W. Phillips, L.R. Wheeler, and D.H. Will. 1978. The Yucatan miniature pig as a laboratory animal. Laboratory Animal Science 28(3):308-313.</P>
+<P ALIGN="JUSTIFY">Phillips, R.W. and T.Y. Hou. 1944. Chinese swine and their performance compared with modern and crosses between Chinese and modern breeds. Journal of Heredity 35:365-79.</P>
+<P ALIGN="JUSTIFY">Pond, W.G. and J.H. Maner. 1984. Swine Production and Nutrition. AVI Publishing Company, Westport, Connecticut, USA.</P>
+<P ALIGN="JUSTIFY">Williamson, G. and W.J.A. Payne. 1965. An Introduction to Animal Husbandry in the Tropics. 2nd edition. Longman, London. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">POULTRY</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">The World's Poultry Science Journal is published 3 times a year by the World's Poultry Science Association, (c/o Institut f-r Kleintierzucht, Dornbergstrasse 25/27, Postfach 280, C-3100 Celle, Germany). It has also published a multilingual poultry dictionary.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Poultry, an international journal on poultry, is published by Misset International, a department of Uitgeversmaatschappij, C. Misset b.v., Doetinchem-The Netherlands. (Address: Misset International, P.O. Box 4, 7000 BA Doetinchem, Netherlands.)</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Poultry Science is published monthly by the Poultry Science Association, Inc., 309 West Clark Street, Champaign, Illinois 61820, USA. British Poultry Science, a quarterly, is available c/o Longman Group Ltd., Subscriptions (Journals) Department, Fourth Avenue, Harlow, Essex CM195AA, UK. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Chicken</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Attfield, H.H.D. 1990. Raising Chickens and Ducks. Volunteers in Technical Assistance, Arlington, Virginia, USA.</P>
+<P ALIGN="JUSTIFY">Crawford, R.D. 1984. Domestic fowl. Pages 298-311 in Evolution of Domesticated Animals, I.L. Mason, ed. Longman, London.</P>
+<P ALIGN="JUSTIFY">Ensminger, M.E.1971. Poultry Science. Interstate Printers and Publishers, Inc., Danville, Illinois, USA.</P>
+<P ALIGN="JUSTIFY">Fielding, D. 1984. The silent scavengers. African Farming September/October 1984: 11-13.</P>
+<P ALIGN="JUSTIFY">Howman, K.C. 1980. Pheasants: Their Breeding and Management. K&amp;R Books, UK.</P>
+<P ALIGN="JUSTIFY">Huchzermeyer, F.W. 1973. Free ranging hybrid chickens under African tribal conditions. Rhodesian Agricultural Journal 70:73-75.</P>
+<P ALIGN="JUSTIFY">Latif, M.A. 1985. In-Depth Analysis on the Successful Experience of Poultry Production in Bangladesh. Report submitted to FAO-APHC Regional Animal Production and Health Office. FAD/UN, Bangkok, Thailand.</P>
+<P ALIGN="JUSTIFY">Matthewman, R.W. 1977. A Survey of Small Livestock Production at the Village Level in the Derived Savannah and Lowland Forest Zones of South West Nigeria. M.Sc. thesis, University of Reading, UK.</P>
+<P ALIGN="JUSTIFY">MTrat, P. 1986. Potential usefulness of the Na (Naked Neck) gene in poultry production. [Vorld's Poultry Science Journal 42:124-142.</P>
+<P ALIGN="JUSTIFY">Nesheim, M.C., R.E. Austic, and L.E. Card. 1979. Poultry Production. 12th edition. Lea and Febiger, Philadelphia.</P>
+<P ALIGN="JUSTIFY">Phillips, R.W., R.C. Johnson, and R.J. Moyer. 1945. The Livestock of China. U.S. Department of State Publication No. 2249, Far Eastern Series 9. U.S. Department of State, Washington, D.C. 174 pp.</P>
+<P ALIGN="JUSTIFY">Sainsbury, D. 1980. Poultry Health and Management. Granada, London.</P>
+<P ALIGN="JUSTIFY">Scott, M.L., M.C. Nesheim, and R.J. Young. 1982. Nutrition of the Chicken. M.L. Scott and Associates, Ithaca, New York.</P>
+<P ALIGN="JUSTIFY">Smith, A.J. nd. Supplementation for scavenging animals. Unpublished paper. Copies available from A.J. Smith, Centre for Tropical Veterinary Medicine, Easter Bush, Roslin, Midlothian EH25 9RG, Scotland, UK.</P>
+<P ALIGN="JUSTIFY">Somes, R. 1984. International Registry of Poultry Genetic Stocks. BuDetin 469, University of Connecticut Agricultural Experiment Station, Storrs, Connecticut, USA.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Araucanian</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Wilhelm, G.O.E. 1965-1966. La Gallina Araucana (Gallus inauris castelloi 1914). Universidad de Concepcion, Concepcion, Chile, Boletia de Concepcion 40:5-26.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Duck</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">A film, Duck Farmingan Indonesian Tradition, is available from the CSIRO Film and Video Unit, 314 Albert Street, East Melbourne 3002, Victoria, Australia. Soundtrack is in English or Indonesian and it is available in 16 mm or VHS/Beta Video.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Attfield, H.H.D. 1990. Raising Chickens and Ducks. Volunteers in Technical Assistance, Arlington, Virginia, USA. </P>
+<P ALIGN="JUSTIFY">Clayton, G.A. 1984. Common duck. Pages 334-339 in Evolution of Domesticated Animals, I.L. Mason, ed. Longman, London.</P>
+<P ALIGN="JUSTIFY">Farrell, D. and P. Stapleton, eds. 1986. Duck Production, Science and World Practice. Proceedingsofaduckproductionworkshop, November 18-22, 1985, Bogor, Indonesia. Central Research Institute for Animal Science. Available from Department of Biochemistry, Microbiology and Nutrition, University of New England, Armidale, NSW 2351, Australia. 430 pp.</P>
+<P ALIGN="JUSTIFY">Holderread, D. 1978. The Home Duck Flock. The Hen House, P.O. Box 492, Corvallis, Oregon 97330, USA.</P>
+<P ALIGN="JUSTIFY">Kingston, D.K., D. Kosasih, and I. Ardi. 1979. The Rearing of Alabio Dt~cklings -nd Management of the Laying Duck Flocks in the Swamps of South Kalimantan. Report No. 9. Centre for Animal Research and Development, Ciawi, Bogor, Indonesia.</P>
+<P ALIGN="JUSTIFY">Petheram, R.J. and A. Thahar. 1983. Duck egg production systems in West Java. Agricultural Systems 2:75-86.</P>
+<P ALIGN="JUSTIFY">Phillips, R.W., R.G. Johnson, and R.J. Moyer. 1945. The Livestock of China. U.S. Department of State Publication No. 2249, Far Eastern Series 9. U.S. Department of State, Washington, D.C. 174 pp.</P>
+<P ALIGN="JUSTIFY">Sainsbury, D. 1980. Poultry Health and Management. Granada, London.</P>
+<P ALIGN="JUSTIFY">Scott, M.L. and W.F. Dean. 1991. Nutrition and Management of Ducks. M.L. Scott of Ithaca, Publisher (P.O. Box 4464, Ithaca, New York 14852, USA)</P>
+<P ALIGN="JUSTIFY">Warren, A.G. 1972. Ducks and geese in the tropics. World Animal Review 3:35-36.</P>
+<P ALIGN="JUSTIFY">Yi Yung and Yu-Ping Zhon. 1980. The Pekin duck in China. World Animal Review 34:11-14.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Geese</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Crawford, R.D. 1984. Goose. Pages 345-349 in Evolution of Domesticated Animals, I.L. Mason, ed. Longman, London.</P>
+<P ALIGN="JUSTIFY">FAO. 1983. The Goose and its Possible Use for Controlling Weeds. Small Animals for Small Farms. GAN-I. FAO Regional Office for Latin America and the Caribbean, Casilla 10095, Santiago, Chile.</P>
+<P ALIGN="JUSTIFY">Holderread, D. 1981. The Book of Geesea Complete Guide to Raising the Home Flock. Hen House Publications, P.O. Box 492, Corvallis, Oregon 97339, USA.</P>
+<P ALIGN="JUSTIFY">Phillips, R.W., R.G. Johnson, and R.J. Moyer. 1945. The Livestock of China. U.S. Department of State Publication No. 2249, Far Eastern Series 9. U.S. Department of State, Washington, D.C. 174 pp.</P>
+<P ALIGN="JUSTIFY">Soames, B. 1980. Keeping Domestic Geese. Blandford, London. 159 pp.</P>
+<P ALIGN="JUSTIFY">USDA Extension Service. 1983. Raising Geese. Farmer's Bulletin No. 2251. U.S. Department of Agriculture, Washington, D.C.</P>
+<P ALIGN="JUSTIFY">Warren, A.G. 1972. Ducks and geese in the tropics. World Animal Review 3:35-36.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Guinea Fowl</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Many research papers have been published in French, Italian, Spanish, and Russian, but few in English.</P>
+<P ALIGN="JUSTIFY">Ayeni, J.S.O. 1983. Studies of Grey Breasted Helmet Guineafowl (Numida meleagris galeata Pallas) in Nigeria. World's Poultry Science Journal 39(2):143-151.</P>
+<P ALIGN="JUSTIFY">Belshaw, R.H.H. 1985. Guinea Fowl of the World. Nimrod Book Services, P.O. Box No. 1, Liss, Hampshire, UK. </P>
+<P ALIGN="JUSTIFY">Blum, J.C., J. Guillaume, and B. Leclercq. 1975. Studies of the energy and protein requirements of the growing guinea-fowl. Br-ish Poultry Science 16:157-168.</P>
+<P ALIGN="JUSTIFY">Cauchard, J.C. 1971. La Pintade. Henri Peladan, UzFs, France.</P>
+<P ALIGN="JUSTIFY">Chemillier, J. 1984. L'Alimentation de la Pintade. F. Hoffmann-La Roche and Cie, 52, Boulevard du Parc, 92521 Neuilly-sur-Seine, Cedex, France.</P>
+<P ALIGN="JUSTIFY">Commonwealth Agricultural Bureaux. 1968. Guinea Fowl Breeding and Managernent. Annotated Bibliography No. 85. The Commonwealth Bureau of Animal Breeding and Genetics, King's Buildings, Edinburgh 9, Scotland, UK.</P>
+<P ALIGN="JUSTIFY">Leclercq, B. 1982. Alimentation des Futurs Reproducteurs Pintades. Pages 101-111 in FertilitT et Alimentation des Volailles. I.N.R.A. Edit.7 Versailles, France.</P>
+<P ALIGN="JUSTIFY">Leclercq, R. and B. Sauveur. 1982. L'alimentation des reproducteurs pintades. Pages 113-135 in FertilitT et Alimentation des Volailles, I.N.R.A. edit., Versailles, France.</P>
+<P ALIGN="JUSTIFY">Lukefahr, S. Raising guinea fowl. Paper available from author, c/o International Small Livestock Research Center, Alabama Agricultural and Mechanical University. P.O. Box 264, Normal, Alabama 35762, USA.</P>
+<P ALIGN="JUSTIFY">Ministry of Agriculture, Fisheries and Food. 1985. Small-scale guinea-few! production. Pamphlet 934. Ministry of Agriculture, Fisheries and Food (Publications), Lion House, Alnwick, Northumberland NE66 2PF, UK.</P>
+<P ALIGN="JUSTIFY">Mongin, P. and M. Plouzeau. 1984. Guinea-fowl. Pages 322-324 in Evolution of Domesticated Animals, I . L. Mason, ed. Longman, London .</P>
+<P ALIGN="JUSTIFY">USDA. 1970. Raising Cuinea Fowl. Leaflet No. 519. U.S. Department of Agriculture, Washington, D.C.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Muscovy</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Clayton, G.A. 1984. Muscovy duck. Pages 340-344 in Evolution of Domesticated Animals, I.L. Mason, ed. Longman, London.</P>
+<P ALIGN="JUSTIFY">De Corville, H. 1972. La Production du Canard de Barbarie. Copies available from Institut nacional de la recherce agronomique (INRA), Nouzilly, France.</P>
+<P ALIGN="JUSTIFY">Farrell, D. and P. Stapleton, eds. 1986. Duck Production, Science and World Practice. Proceedings of a duck production workshop, November 18-22, 1985, Bogor, Indonesia. Central Research Institute for Animal Science. Copies available from D. Farrell, University of New England, Armidale, NSW 2351, Australia.</P>
+<P ALIGN="JUSTIFY">Jeffreys, M.D.W. 1956. The Muscovy duck. The Nigerian Field21(3):108-11.</P>
+<P ALIGN="JUSTIFY">Kingston, D.J., D. Kosasih, and I. Ardi. 1978. The Use of the Muscovy Drrck for Hatching of Alabio Duck &Yacute;ggs in the Swamplands of Kalimantan. Centre Report No. 7. Centre for Animal Research and Development, Bogor, Indonesia.</P>
+<P ALIGN="JUSTIFY">Richet, M. 1985. La production du canard de Barbarie. Techniques Agricoles 3770.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Pigeon</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Abs, M., ed. 1983. Pltysiology and Behavior of the Pigeon. Academic Press, Inc., New York.</P>
+<P ALIGN="JUSTIFY">Hawes, R.O. 1984. Pigeons. Pages 351-356 in Evolution of Domesticated Anirnals, I.L. Mason, ed. Longman, London.</P>
+<P ALIGN="JUSTIFY">Hollander, W.F. and W.J. Miller. 1981. Hereditary variants of behavior and vision in the pigeon. Iowa State Journal of Research 55(4):323-331.</P>
+<P ALIGN="JUSTIFY">Levi, W.M. 1965. Encyclopedia of Pigeon Breeds. T.F.H. Publications, Jersey City, New Jersey, USA. </P>
+<P ALIGN="JUSTIFY">Levi, W.M. 1981. The Pigeon. 2nd edition revised. Levi Publishing, Sumter, South Carolina, USA.</P>
+<P ALIGN="JUSTIFY">Murton, R.K., R.P.J. Thearle, and J. Thompson. 1972. Ecological studies of the feral pigeon (Columba livia). 1. Population, breeding biology and methods of control. II. Flock behaviour and social organisation. Ecology 9:835-889.</P>
+<P ALIGN="JUSTIFY">University of Wisconsin. 1977. Pigeons. Bulletin 4-H 135. University of Wisconsin, Madison, Wisconsin, USA.</P>
+<P ALIGN="JUSTIFY">USDA. 1963. Squab Raising. Farmers Bulletin No. 684. U.S. Department of Agriculture, Washington, D.C.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Quail</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Bourquin, O. 1980. Biology of rhe Quail (Coturnix coturnix Linnaeus 1758). Ph.D. thesis, University of Natal, Pietermaritzburg, Republic of South Africa.</P>
+<P ALIGN="JUSTIFY">Katoh, H. and N. Wakasugi. 1980. Studies on the blood groups in the Japanese quail: detection of three antigens and their inheritance. Developmental and Comparative Immunology 4:99-110.</P>
+<P ALIGN="JUSTIFY">Kawahara, T. 1973. Comparative study of quantitative traits between wild and domestic Japanese quail (Coturnix coturnix japonica). Experimental Animals 22(supplement): 138-50.</P>
+<P ALIGN="JUSTIFY">Marsh, A. Quail Manual. Marsh Farms, 7171 Patterson Drive, Garden Grove, Calffornia 92641, USA.</P>
+<P ALIGN="JUSTIFY">National Academy of Sciences. 1969. Coturnix (Coturnix coturnix japonica): Standards and Guidelines for the Breeding, Care, and Management of Laboratory' Animals. National Academy of Sciences, Washington, D.C.</P>
+<P ALIGN="JUSTIFY">Quail Production Technology. Leaflet No. 13/1982. Central Avian Research Institute, Izatnagar, India. </P>
+<P ALIGN="JUSTIFY">Somes, R.G., Jr. 1981. International Registry of Poultry Genetic Stocks. Storrs Agricultural Experiment Station, University of Connecticut, Storrs, Connecticut, USA.</P>
+<P ALIGN="JUSTIFY">Varghese, S.K. 1981. Coturnix Internationalat home and in the Caribbean. Poultry Science 60:1747.</P>
+<P ALIGN="JUSTIFY">Varghese, S.K. 1982. Coturnix production proves to be a profitable business. Poultry Science 61:1560.</P>
+<P ALIGN="JUSTIFY">Varghese, S.K. 1983. Processing and yield of coturnix (Japanese quail). Poultry Science 62:1517</P>
+<P ALIGN="JUSTIFY">Wakasugi, N. and K. Kondo. 1973. Breeding methods for maintenance of mutant genes and establishment of strains in the Japanese quail. Experimental Animals 22(Supplement): I 51 -9.</P>
+<P ALIGN="JUSTIFY">Woodard, A.E., A. Abplanalp, W.O. Wilson, and P. Vohra. 1973. Japanese Quail Husbandry in the Laboratory. Department of Avian Sciences, University of Calffornia, Davis, Calffornia 95616, USA.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Turkey</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Berg, R. and D. Halvorson. 1985. Turkey Management Guide. Minnesota Turkey Growers Association, 678 Transfer Road, St. Paul, Minnesota 55114, USA.</P>
+<P ALIGN="JUSTIFY">Crawford, R.D. 1984. Turkey. Pages 325-334 in Evolution of Domesticated Animals, I.L. Mason, ed. Longman, London. </P>
+<P ALIGN="JUSTIFY">Ensminger, M.E. 1971. PoultryScience. InterstatePrintersandPublishers, Inc., Danville,</P>
+<P ALIGN="JUSTIFY">Illinois, USA. Sainsbury, D. 1980. Poultry Health and Management. Granada, London.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">RABBITS</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">The Rabbit Research Center has been established at Oregon State University, Corvallis, Oregon 97331, USA. It publishes the Journal of Applied Rabbit Research, whose purpose is to convey current research information to those with an interest in commercial rabbit production. The journal describes research conducted at the center and reviews rabbit research results reported in the world's scientific literature.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Founded in 1976 in Paris, the World Rabbit Science Association (Typing House, Shurdington, Cheltenhem, Gloucestershire, GL51 SXF, UK) publishes a newsletter of coming events and chronicles the progress of rabbit farming in most countries of the world. Its aims are to facilitate the advancement of the various branches of the rabbit industry, disseminate knowledge, and study problems of production and marketing. Its members represent individuals and associations in 20 countries.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The American Rabbit Breeder's Association (1925 South Main Street, Bloomington, Illinois 61701, USA) has published a book, Guide to Producing Better Rabbits, which contains an abundance of information concerning management and diseases of the domestic rabbit. The organization also publishes a bimonthly magazine, Domestic Rabbit, that includes a great deal of updated information on rabbit raising.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Asociacion Espanola de Cunicultura (Spanish Rabbit Science Association), Now, 23 08785 Ballbona d'Anoia, Barcelona, Spain, has a set of slides for training, covering breeds, handling, pathology, and commercialization.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The Report of the Workshop on Rabbit Husbandry. Copies of this report are available free of charge from the International Foundation for Science, Sibyllegatan 47, S-114 42 Stockholm, Sweden. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">A Working Rabbit Literature Resources File. This materia, is directed at scientists working on some aspect of domestic rabbit research. It lists methods of computer searching for scientific reports in the world's scientific literature, various types of computer literature searches, including commerciaHy available ones, and government services. It a,so includes a list of prepared abstracts. The address is D.D. Caveny and H. L. Enos, Colorado State University, Fort Collins, Colorado 80523, USA. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Domestic Rabbit</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Ministry of Livestock Development. 1981. Rabbit Production. Kenya Ministry of Livestock Development. Copies can be obtained from the Agricultural Information Centre, P.O. Box 14733, Nairobi, Kenya.</P>
+<P ALIGN="JUSTIFY">Attfield, H.H.D. 1977. Rabbit Raising. Volunteers in Technical Assistance, 1815 Lynn</P>
+<P ALIGN="JUSTIFY">Street, Arlington, Virginia 22209, USA. 90 pp.</P>
+<P ALIGN="JUSTIFY">Bennett, R. 1975. Raising Rabbits the Modern Way. Garden Way Publishing, Charlotte, Vermont 05445, USA.</P>
+<P ALIGN="JUSTIFY">Cheeke, P.R. 1987. Rabbit Feeding and Nutrition. Academic Press, Inc., New York.</P>
+<P ALIGN="JUSTIFY">Cheeke, P.R., N.M. Patton, S.D. Lukefahr, and J.I. McNitt. 1986. Rabbit Production. Sixth edition. The Interstate, Danville, Illinois, USA. </P>
+<P ALIGN="JUSTIFY">FAO. 1986. Cooking Rabbits. Food and Agriculture Organization of the United Nations,  Regional Office for Latin America and the Caribbean, Santiago, Chile.</P>
+<P ALIGN="JUSTIFY">FAO. 1986. Self-Teaching Manual on Backyard Rabb- Rearing. Food and Agriculture  Organization of the United Nations, Regional Office for Latin America and the  Caribbean, Santiago, Chile.</P>
+<P ALIGN="JUSTIFY">FAO. 1986. Backyard Rabbit Rearing: Some Basic Husbandry Practices. Small Animals  for Small Farms. GAN-16. Food and Agriculture Organization of the United Nations,  Regional Office for Latin America and the Caribbean, Santiago, Chile.</P>
+<P ALIGN="JUSTIFY">Schlolaut, W., ed. 1985. A Compendium of Rabbit Production. Gesellschaft f-r  Technische Zusammenarbeit (GTZ) Publication No. 169. TZ-Verlagsgesellschaft mbH,  Postfach 36, D6101 Rossdorf, Germany.</P>
+<P ALIGN="JUSTIFY">Sicivaten, J. and D. Stahl. 1982. A Complete Handbook on Backyard and Commercial  Rabbit Production. CARE/Philippines.</P>
+<P ALIGN="JUSTIFY">Vogt, D.W. 1982. Raising Rabbits in Hawaii. Circular 499, Cooperative Extension  Service, College of Tropical Agriculture and Human Resources, University of Hawaii at  Manoa.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">RODENTS</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Agouti</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">A report summarizing preliminary results in a captive-breeding project in Mexico is available from A. D. Cuaron (see Research Contacts for address).</P>
+<P ALIGN="JUSTIFY">Deutsch, L.A., and G. Santos. 1984. Contribuitao pare o conhecimento do gOnero  Dasyproctareprodutao de cutiasentre cruzamente das espTcies Dasyprocta aguti,  Dasyprocta azarae e Dasyprocta fuliginosa. Congresso Brasileiro de Zoologia, II,  BelTm, 1984. Resumos. . .BelTm, SBZ/UFPalMPEC, p. 383-4/(Resumos 390). Copies  available from the authors, see Research Contacts.</P>
+<P ALIGN="JUSTIFY">Clark, M.M. and B.G. Galef, Jr. 1977. Patterns of agonistic interaction and space  utilization by agoutis, Dasyprocta punctata. Behavioral Biology 20:135-140.</P>
+<P ALIGN="JUSTIFY">Leopold, A.S. 1959. Pages 388-393 in Wildlife of Mexico. University of California Press,  Berkeley and Los Angeles.</P>
+<P ALIGN="JUSTIFY">Meritt, D.A., Jr. 1982. Bibliography of Dasyprocta (Rodentia). Brenesia 19/20:595-612.</P>
+<P ALIGN="JUSTIFY">Meritt, D.A., Jr. 1983. Preliminary observations on reproduction in the Central  American agouti, Dasyprocta punctata. Zoo Biology 2:127-131.</P>
+<P ALIGN="JUSTIFY">Morris, D. 1962. The behaviour of the green acouchi (Myoprocta pratti) with special  reference to scatter hoarding. Proceedings Zoological Society of London 139:701732.</P>
+<P ALIGN="JUSTIFY">Smith N. 1974. Agouti and babassu. Oryx 12(5):581-582.</P>
+<P ALIGN="JUSTIFY">Smythe, N. 1978. The Natural History of the Central American Agouti (Dasyprocta  punctata). Smithsonian Contributions to Zoology No. 257. Smithsonian Institution,  Washington, D.C., USA. 52 pp.</P>
+<P ALIGN="JUSTIFY">Tribe, C.J., R. Leher, M.C.O. Doglio, M.I.L. Rebello, D.S. Mello, and E.M.M. Guimar es.  1985. Uma tentative de esclarecimento do uso de espato e estrutura social na cutia  Dasyprocta a. aguti (Rodentia). Pages 296-7 in Congresso Brasileiro de Zoologia, 12,  Campinas, 1985. Resumos. . .Campinas, SBZ/UNICAMP, 1985. (Resumo 614.)  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Capybara</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">A capybara bibliography, Bibliograf a sobre Chiguires (Hydrochoerus hydrochaeris), is available from E. Gonzalez-Jimenez and JosT Roberto de Alencar Moreira (see Research Contacts for addresses).</P>
+<P ALIGN="JUSTIFY">Aliaga Rodriguez, L. 1979. Produccion de Cuyes. Universidad Nacional del Centro del Peru, Puno.</P>
+<P ALIGN="JUSTIFY">Baldizan, A., R.M. Dixon, and R. Parra. 1983. Digestion in the capybara (Hydrochoerus hydrochaeris). South African Journal of Animal Science 13(1):27-28.</P>
+<P ALIGN="JUSTIFY">Gonzalez-Jimenez, E. 1977a. The capybara, an indigenous source of meat in tropical America. World Animal Review', 21:24-30.</P>
+<P ALIGN="JUSTIFY">Gonzalez-Jimenez, E. 1977b. Digestive physiology and feeding of capybaras. Pages 167177 in Handbook Series in Nutrition and Food. Section G, Diets, Culture Media and Food Supplements, M. Rechcigl, ed. CRC Press, Cleveland, Ohio, USA.</P>
+<P ALIGN="JUSTIFY">Gonzalez-Jimenez, E. and R. Parra. 1975. The capybara, a meat-producing animal for the flooded areas of the tropics. Pages 81-86 in Proceedings of the Third World Conference on Animal Production, R.L. Reid, ed. Sydney University Press.</P>
+<P ALIGN="JUSTIFY">Gonzalez-Jimenez, E. 1984. Capybara. Pages 258-259 in Evolution of Domesticated Animals, I.L. Mason, ed. Longman, London.</P>
+<P ALIGN="JUSTIFY">Macdonald, D.W., K. Krantz, and R.T. Aplin. 1984. Behavioural, anatomical and chemical aspects of scent marking amongst Capybaras (Hydrochoerus hydrochaeris) (Rodentia:Caviomorpha). Journal of Zoology (London) 202:341-360.</P>
+<P ALIGN="JUSTIFY">Mones, A. and J. Ojasti. 1986. Hydrochoerus hydrochaeris. Mammalian Species 264: 1-7.</P>
+<P ALIGN="JUSTIFY">Ojasti, J. 1968. Notes on the mating behavior of the capybara. Journal of Mammalogy 49:345-374.</P>
+<P ALIGN="JUSTIFY">Ojasti, J. 1973. Estudio Biologico del Chiguire o Capybara. Fondo Nacional de Investigaciones Agropecuaria, Caracas, Republica de Venezuela. 27 pp.</P>
+<P ALIGN="JUSTIFY">Zara, J.L. 1973. Breeding and husbandry of the capybara at Evansville Zoo. International Zoo Yearbook 13:137-139.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Coypu</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Christen, M.F. 1978. Evaluacion nutritive de cuatro dietas mono especificas en la alimentacion del coipo (Myocastor coypus Molina 1782). Tesis. Faculty of Veterinary Science, Universidad Austral de Chile, Valdivia, Chile.</P>
+<P ALIGN="JUSTIFY">Deems, E.F., Jr., and D. Pursley. 1978. North American Fur bearers. Maryland Wildlife Administration, Department of Natural Resources, Cheltenham, Maryland, USA. pp. 155.</P>
+<P ALIGN="JUSTIFY">CORFO. n.d. Pieles fieas. Especie coipos. Tomo 1, I! and III. Santiago, Chile.</P>
+<P ALIGN="JUSTIFY">Murua, R., O. Newman, and J. Propelmann. 1981. Food habits of Myocastor coypus (Molina) in Chile. Pages 544-558 in Proceedings of rhe Worldwide Furbearer Conference, J.A. Chapman and D. Pursley, eds. Vol. 1. Worldwide Furbearer Conference, Inc., Frostburg, Maryland, USA.</P>
+<P ALIGN="JUSTIFY">Willner, G.R. 1982. Nutria; Myocastor coypu. Pages 1059-1076 in Wild Mammals of NorthAmerica, J.A. Chapman and G.A. Feldhamer, eds. The John Hopkins University Press, Baltimore, Maryland, USA. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Giant Rat</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Ajayi, S.S. 1975. Domestication of the African Giant Rat. Department of Forest Resources, University of Ibadan, Ibadan, Nigeria.</P>
+<P ALIGN="JUSTIFY">Faturoti, E.O., O.O. Tewe, and S.S. Ajayi. 1982. Crude fibre tolerance by the African giant rat (Cricetomys gambianus Waterhouse) (Potential sources of protein, Nigeria.) African Journal of Ecology 20(4):289-292.</P>
+<P ALIGN="JUSTIFY">Faturoti, E.O., O.O. Tewe, and S.S. Ajayi. 1983. Effect of varying dietary oil levels on the performance of the African giant rat (Cricetomys gambianus Waterhouse). Nutrition Reports International 27(3):525-530.</P>
+<P ALIGN="JUSTIFY">Den Hartog, A.P. and A. de Vos. 1973. The use of rodents as food in tropical Africa. Nutrition Newsletter (FAO) 11 (2):1-14.</P>
+<P ALIGN="JUSTIFY">Halcrow, J.G. 1958. The giant rat of East Africa. Nature (London) 181:649-650.</P>
+<P ALIGN="JUSTIFY">Matthewman, R.W. 1977. A Survey of Small Livestock Production at the Village Level in the Derived Savanna and Lowland Forest Zones of South West Nigeria. Development Studies 24. Department of Agriculture and Horticulture, University of Reading, UK.</P>
+<P ALIGN="JUSTIFY">Tewe, O.O., S.S. Ajayi, and E.O. Faturoti. 1984. Giant rat and cane rat. Pages 291-293 in Evolution of Domesticated Animals, I.L. Mason, ed. Longman, London.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Grasscutter</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Asibey, E.O.A. 1979. Some problems encountered in the field study of the grasscutter (Thryonomys swinderianus) population in Ghana. Pages 214-7 in Wildlife Management in Savannah Woodland, S.S. Ajayi and L. B. Halstead, eds. Cambridge University Press, Cambridge, UK.</P>
+<P ALIGN="JUSTIFY">Baptist, R. and G.A. Mensah. 1986. The Cane-RatFarm animal of the future? [Vorld Animal Review 60:2-6.</P>
+<P ALIGN="JUSTIFY">Matthewman, R.W. 1977. A Survey of Small Livestock Production at the Village Level in the Derived Savanna and Lowland Forest Zones of South West Nigeria. Development Study 24. Department of Agriculture and Horticulture, University of Reading, UK.</P>
+<P ALIGN="JUSTIFY">Pich, S. and K.J. Peters. 1985. Possibilities of using the cane cutter for meat production in Africa. Unpublished manuscript. Copies available from K.J. Peters, Institute of Animal Breeding, Gottingen, Germany.</P>
+<P ALIGN="JUSTIFY">Tewe, O.O., S.S. Ajayi, and E.O. Faturoti. 1984. Giant rat and cane rat. Pages 291-293 in Evolution of Domesticated Animals, I.L. Mason, ed. Longman, London.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Guinea Pig</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">"Let's Raise Guinea Pigs," a filmstrip on guinea pig farming, is available from World Neighbors International Headquarters, 5116 North Portland Avenue, Oklahoma City, Oklahoma73112, USA.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Aliaga Rodriguez, L. 1979. Produccion de Cuyes. Universidad Nacional del Centro del Peru, Huancayo, Peru. </P>
+<P ALIGN="JUSTIFY">Aliaga Rodriguez, L. 1983. improvement of Guinea Pig Breeding as a Means of Increasing the Productivity and Production of Meat for Consumption oy the Rural Population in Peru. National University of Central Peru, Huancayo, Peru.</P>
+<P ALIGN="JUSTIFY">Bolton, R. 1979. Guinea pigs, protein, and ritual. Ethnology 18(3):229-252.</P>
+<P ALIGN="JUSTIFY">Huss, D.L. 1982. Small animals for small farms in Latin America. World Animal Ret~iew (FAO) 43:24-29.</P>
+<P ALIGN="JUSTIFY">FAO. 1982. The Guinea Pig and a Hypothetical Development Centre. Small Animals for Small Farms. FAO, Regional Office for Latin America and the Caribbean, Santiago, Chile.</P>
+<P ALIGN="JUSTIFY">Loetz, E. and C. Novoa. 1983. Meat from the guinea pig. Span 26(2):84-86.</P>
+<P ALIGN="JUSTIFY">Muller-Haye, B. 1984. Guinea-pig or cuy. Pages 252-257 in Evolution of Domesticated Animals I.L. Mason, ed. Longman, London.</P>
+<P ALIGN="JUSTIFY">Stansfield, S.K., C.L. Scribner, R.M. Kaminski, T. Cairns, J.B. McCormick, and K.M. Johnson. 1982. Antibody to ebola virus in guinea pigs: Tandala, Zaire. The Journal of Infectious Diseases 146(4):483-486.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Hutia</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Anderson, S., C.A. Woods, G.S. Morgan, and W.L.R. Oliver. 1983. Geocaprornys brownii. Mammalian Species 201:1-5.</P>
+<P ALIGN="JUSTIFY">Canet, R.S. and V. Berovides Alvares. 1984. Ecomorfologia y rendimiento de la jutia conga (Capromys pilorides Say). Poeyana 279:1-19.</P>
+<P ALIGN="JUSTIFY">Canet, R.S. and V. Berovides Alvares. 1984. Reproduccion y ecolog~a de la jutia conga (Capromys pilorides Say). Poeyana 220:1-20.</P>
+<P ALIGN="JUSTIFY">Howe, R., and G.C. Clough. 1971. The Bahamian hutia Geocapromys ingrahami in captivity. international Zoo Yearbook 11:89-93.</P>
+<P ALIGN="JUSTIFY">Johnson, M.L., R.H. Taylor, and N.W. Winnick. 1975. The breeding and exhibition of capromyd rodents at Tacoma Zoo. International Zoo Yearbook 15:53-56.</P>
+<P ALIGN="JUSTIFY">Oliver, W.L.R. 1977. The hutias (Capromyidae) of the West Indies. International Zoo Yearbook 17:14-20.</P>
+<P ALIGN="JUSTIFY">Oliver, W.L.R. 1985. The Jamaican hutia or Indian Coney (Geocapromys brownii). A model programme for captive breeding and reintroduction? Symposium of the Association of British Wild Animal Keepers, 10:35-52. (Copies available from author, see Research Contacts.)</P>
+<P ALIGN="JUSTIFY">Rowlands, I.W., and B.J. Weir, eds. 1974. The Biology of Hystricomorph Rodents. Symposium of the Zoological Society of London, 34:1-482.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Mara</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Dubost, G. and H. Genest. 1974. Le comportement social d'une colonide mares, Dolichotis patagonum Z. dans le Parc de BranfTrT. Zeitschrift fin Tierpsychologie 35:225-302.</P>
+<P ALIGN="JUSTIFY">Taber, A.B. and D.W. Macdonald. 1984. Scent dispensing papillae and associated behaviour of the mare, Dolichotis patagonum (Rodentia: Caviomorpha). Journal of Zoology (London) 203:298-302. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Paca</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">A report summarizing progress in the captive-breeding project in Panama is available from Nicholas Smythe, Smithsonian Tropical Research Institute, Box 2071, Balboa, Panama. A report summarizing preliminary results in the captive-breeding project in Mexico is available from Alfredo D. Cuaron, (see Research Contacts).</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Collett, S.F. 1981. Population characteristics of Agouti paca (Rodentia) in Colombia. Michigan State University, Publications of the Museum, Biological Series 5(7): 485-602.</P>
+<P ALIGN="JUSTIFY">Matamoros, Y. 1982. Investigaciones preliminares sobre la reproduccion, comportamiento, alimentacion y manego del tepezcuinte (Cuniculus paca, Brisson) en cautiverio. Pages 961-992 in Zoologia Neotropical, Actas del VIII Congreso Latinoamericano de Zoologia, P.J. Salinas, ed. (Copies available from Y. Matamores, see Research Contacts.)</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Vizcacha</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Jackson, J.E. nd. Growth rates in vizcacha (Lagostomus maximus) in San Luis, Argentina. Instituto Nacional de Tecnologia Agropecuaria, San Luis, Argentina. (Copies available from author, see Research Contacts.)</P>
+<P ALIGN="JUSTIFY">Llanos, A.C., and J.A. Crespo. 1952. Ecologia de la vizcacha (Lagostomus maximus maximus Blainv.) en el nordeste de la provincia de Entre Rios. Revista de Investigaciones Agricolas (Buenos Aires) 6:289-378.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Other Rodents</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Butynski, T.M. 1973. Lffe history and economic value of the springhare (Pedetes capensis Forster) in Botswana. Botswana Notes Record 5:209-213.</P>
+<P ALIGN="JUSTIFY">Butynski, T.M. 1979. Reproductive ecology of the springhaas Pedetes capensis in Botswana. Journal of Zoology 189:221-232.</P>
+<P ALIGN="JUSTIFY">Butynski, T.M. 1984. Nocturnal ecology of the springhare, Pedetes capensis, in Botswana. African Journal of Ecology 22:7-22.</P>
+<P ALIGN="JUSTIFY">Butynski, T.M. and R. Mattingly. 1979. Burrow structure and fossorial ecology of the springhare Pedetes capensis in Botswana. African Journal of Ecology 17:205-215.</P>
+<P ALIGN="JUSTIFY">Kofron, C.P. 1987. Seasonal reproduction of the springhare, Pedetes capensis, in southeastern Zimbabwe. African Journal of Ecology 25.</P>
+<P ALIGN="JUSTIFY">Rosenthal, M.A., and D.A. Meritt. 1973. Hand-rearing springhaas at Lincoln Park Zoo. International Zoo Yearbook 18:206-208.</P>
+<P ALIGN="JUSTIFY">Smithers, R.H.N. 1983. The Mammals of the Southern African Subregion. University of Pretoria, Pretoria.</P>
+<P ALIGN="JUSTIFY">Velte, F.F. 1978. Hand-rearing springhaas Pedetes capensis at Rochester Zoo. International Zoo Yearbook 18:206-208. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">DEER AND ANTELOPE</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The Deer Farmer, a quarterly magazine, is published by the New Zealand Deer Farmers' Association, P.O. Box 2678, Wellington, New Zealand.</P>
+<P ALIGN="JUSTIFY">Deer Farming is the quarterly magazine of the British Deer Farmers Association (22 Levat Road, Inverness IV2 3NS, Scotland, UK).</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Chaplin, R.E. 1977. Deer. Blandford Press, Poole, Dorset, UK.</P>
+<P ALIGN="JUSTIFY">Hoffman, R.R. 1985. Digestion and feeding in deer: their morphophysiological adaptation. In Proceedings International Conference on Deer Biology and Production, eds. P.F. Fennessy and K.R. Drew. Royal Society of New Zealand Bulletin 22, Wellington, New Zealand.</P>
+<P ALIGN="JUSTIFY">Fennessy, P.F. and K.R. Drew, eds. 1985. Biology of Deer Production. Proceedings of an international conference held February 13-18, 1983, Dunedin, New Zealand. Royal Society of New Zealand Bulletin 22, Wellington, New Zealand. Available from Royal Society of New Zealand, Private Bag, Wellington, New Zealand.</P>
+<P ALIGN="JUSTIFY">Wemmer C., ed. 1987. The Biology and Management of the Cervidae. Smithsonian Institution Press, Washington, D.C., USA.</P>
+<P ALIGN="JUSTIFY">Yerex, D. 1982. The Farming of Deer. Agricultural Publishing, Box 176, Carterton, New Zealand.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Mouse Deer</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Kay, R.N.B. 1987. The comparative anatomy and physiology of digestion in tragulids and cervids and its relation to food intake. In The Biology and Management of the Cenvidae, C. Wemmer, ed. Smithsonian Institution Press, Washington, D.C.</P>
+<P ALIGN="JUSTIFY">Dubost, G. 1975. Le comportement du chevrotain africain, Hyemoschus aquaticus Ogilby (Artiodactyla, Ruminantia). Zeitschrift fdr Tierpsychologie 37:403-501.</P>
+<P ALIGN="JUSTIFY">Dubost, G. 1978. Un apertu sur l'Tcologie du chevrotain africain, Hyemoschus aquaticus Ogilby, Artiodactyle Tragulide. Mammalia 42:1-62.</P>
+<P ALIGN="JUSTIFY">Ralls, K., C. Barasch, and K. Minkowski. 1975. Behaviour of captive mouse deer, Tragulus napu. Zeitschrift Tierpsychology 37:356-378.</P>
+<P ALIGN="JUSTIFY">Robin, K.P. 1979. Zum Verhalten des Kleinkantschils (Tragulus javanicus). Ph.D. dissertation, University of Zurich. (Copies available from K.P. Robin, see Research Contacts.)</P>
+<P ALIGN="JUSTIFY">Vidyadaran, M.K., M. Hilmi, and R.A. Sirimane. 1982. The gross morphology of the stomach of the Malaysian lesser mousedeer (Tragrrlus javanicus). Pertanika 5(1): 34-38.</P>
+<P ALIGN="JUSTIFY">Vidyadran, M.K., S. Vellayan, and R. Karuppiah. 1983. Muscle weight distribution of the Malaysian lesser mousedeer (Tragulus javanicus). Pertanika 6(2):63-69. </P>
+<P ALIGN="JUSTIFY">Wharton, D.C. 1987. Captive Management of Tragulids at New York Zoological Park. In Biology and Management of the Cervidae, C. Wemmer, ed. Smithsonian Institution Press, Washington, D.C., USA.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Muntjac</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Anderson, J. 1981. Studies on digestion in Muntiacus reeves). M.Phil. thesis. Cambridge University. </P>
+<P ALIGN="JUSTIFY">Barrette, C. 1977. The social behavior of captive muntjac Muntiacus reeves) (Ogilby  1839). Zeitschrift f-r Tierpsychologie 43: 188-213.</P>
+<P ALIGN="JUSTIFY">Chaplin, R.E. 1977. Deer. Blandford Press, Poole, Dorset, England</P>
+<P ALIGN="JUSTIFY">Chapman, D.I., N.G. Chapman, J.G. Mathews, and D.H. Wurster-Hill. 1983. Chromosome  studies of feral muntjac (Muntiacus sp.) in England. Journal of Zoology, London  201:557-559.</P>
+<P ALIGN="JUSTIFY">Dansie, O. 1970. Muntjac. British Deer Society, Welwyn Garden City, England. 22 pp.</P>
+<P ALIGN="JUSTIFY">Dubost, G. 1970. L'organisation spatiale et sociale de Muntiacus reeves) Ogilby 1839 en  semi-liberte. Mammalia 34:331-355.</P>
+<P ALIGN="JUSTIFY">Dubost, G. 1971. Observations Tthologiques sur le muntjac (Muntiacus muntjak  Zimmermann 1780 et Muntiacus reeves) Ogilby 1839) en captivitT et semi-libertT.  Zeitschrift fdr Tierpsychologie 28:387-427.</P>
+<P ALIGN="JUSTIFY">Jackson, J.E., D.I. Chapman, and O. Dansie. 1977. A note on the food of muntjac deer  (Muntiacus reeves)). Journal of Zoology (London) 183:546-548.</P>
+<P ALIGN="JUSTIFY">Lu Ho-gee and Sheng He-lin. 1984. Status of the black muntjac Muntiacus crinifrons, in  eastern China. Mammal Review 14(1):29-36.</P>
+<P ALIGN="JUSTIFY">Oli, Madan K. 1986. Studies on stereotyped behavior of barking deer (Muntiacus  muntjak). M.S. dissertation, Institute of Science and Technology, Tribhauvan  University, Kathmandu, Nepal. 84 pp.</P>
+<P ALIGN="JUSTIFY">Shi Liming, Ye Yingying, and Duan Xinsheng. 1980. Comparative cytogenetic studies on  the red muntjac, Chinese muntjac, and their Fl hybrids. Cytogenetics and Cell Genetics  26:22-7.</P>
+<P ALIGN="JUSTIFY">Yonzon, Pralad B. 1978. Ecological studies on Muntaicus muntjack. Journal of Natural  History Museum (Nepal) 2(2):91-100.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Musk Deer</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Anonymous. 1974. Feeding musk deer in captivity and collecting musk from the live  animal. Dongwuxue Zhazi, China 2:11-14.</P>
+<P ALIGN="JUSTIFY">Anonymous. 1975. Preliminary experience in raising the survival rate of musk deer.  Dongwuxue Zhazi, China 1 :17-19.</P>
+<P ALIGN="JUSTIFY">Bannikov, A.G., S.K. Ustinov, and P.N. Lobanov. 1980. The musk deer Moschus  moschiferus in the USSR. International Union for Conservation of Nature and Natural  Resources (IUCN), Gland, Switzerland.</P>
+<P ALIGN="JUSTIFY">Bi, S.Z., Y.H. Yan, Z.X. Qing, P.T. Sheng, Y.M. Wu, C.F. Chen, G.K. Yang, T.B. Yin,  and Y.J. Lu. 1980. Dissection and analysis of the musk gland of M. moschiferus and a  preliminary investigation into its histology. The Protection and Use of Wild Animals  (China) 1: 14-19.</P>
+<P ALIGN="JUSTIFY">Green, M.J.B. 1978. Himalayan musk deer (Moschus moschiferus moschiferus). Pages  56-64 in Threatened Deer. International Union for Conservation of Nature and Natural  Resources (IUCN), Morges, Switzerland.</P>
+<P ALIGN="JUSTIFY">Green, M.J.B. 1985. The musk trade, with particular reference to its impact on the  Himalayan population of Moschus chrysogaster. In Conservation in Developir~g  Countries. Bombay Natural History Society, Bombay.</P>
+<P ALIGN="JUSTIFY">Green, M.J.B. 1985. Aspects of the Ecology of the Himalayan Musk Deer. Ph.D.  dissertation, University of Cambridge, U.K. 280 pp.</P>
+<P ALIGN="JUSTIFY">Groves, C.P. 1978. The taxonomy of Moschus, with particular reference to the Indian  Region. Journal of the Bombay Natural History Society 72:662-676.</P>
+<P ALIGN="JUSTIFY">Holloway, C.W. 1973. Threatened deer of the world: conservation status. Biological  Conservation 5(4).  </P>
+<P ALIGN="JUSTIFY">IUCN. 1974. Red Data Book: Mammalia. International Union for Conservation of Nature and Natural Resources (IUCN), Morges.</P>
+<P ALIGN="JUSTIFY">Jamwal, P.S. 1972. Collection of deer musk in Nepal. Journal of Bombay Natural History Society 69(3):647-649.</P>
+<P ALIGN="JUSTIFY">Seth, S.D., A. Muktiopadtiyay, K. Raghunatham, and R.B. Arora. 1975. Pharmodymamics of Musk. Central Council for Research on Indian Medicine and Homoeopathy, New Delhi, India.</P>
+<P ALIGN="JUSTIFY">Zhang B. 1983. Musk-deer. Their capture, domestication and care according to Chinese experience and methods. Unasylva 35(139):16-24.</P>
+<P ALIGN="JUSTIFY">Zhang, B.L., F.M. Dang, and B.S. Li. 1979. The Farming of Musk Deer. Agricultural Publishing Company, Peking.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Water Deer</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Chaplin, R.E. 1977. Deer. Blandford Press, Poole, Dorset, England.</P>
+<P ALIGN="JUSTIFY">Cooke, A. and L. Farrell. 1983. Chinese water deer (Hydropotes inermis). British Deer Society Publication No. 2. Elvy and Gibbs, Canterbury, UK.</P>
+<P ALIGN="JUSTIFY">Feer, F. 1982. Quelques observations Tthologiques sur l'Hydropote de chine, Hydropotes inennis (Swinhoe, 1870) en captivitT. Zeitschrift fitr Saeugetierkunde 47: 175-185.</P>
+<P ALIGN="JUSTIFY">Sheng Helin and L. Housl. 1984. A preliminary study on the river deer (Hydropotes inermis) population of Shoushau Island (China) and adjacent islets. Acta Theriologica Sinica 4:161-166.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Duikers</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Dittrich, L. 1972. Beobachtungen bei der Haltung von Cephalophus-Arten sowie zur Fortpflanzung und Jugendentwicklung von C. dorsalis und C. rufilatus in gefangenschaft. Zoologische Garten Lpz (N.F.) 42:1-16.</P>
+<P ALIGN="JUSTIFY">Dubost, G. 1980. L'Tcologie et la vie sociale du cTphalophe bleu (Cephalophus monticola Thunberg), petit ruminant forestier africain. Zeitschrift fur Tierpsychologie 54: 205-266.</P>
+<P ALIGN="JUSTIFY">Dunbar, R.l.M. and E.P. Dunbar. 1979. Observations on the social organisation of common duiker in Ethiopia. African Journal of Ecology 17:249-252.</P>
+<P ALIGN="JUSTIFY">Dunbar, R.I.M. and E.P. Dunbar. 1980. Animal Behaviour 28:219.</P>
+<P ALIGN="JUSTIFY">Ketelhodt, H.F. Von. 1977. The lambing interval of the blue duiker, Cephalophus monticola Gray in captivity, with observations on its breeding and care. South African Journal of Wildlife Research 7:41-43.</P>
+<P ALIGN="JUSTIFY">Ralls, K. 1975. Agonistic behavior in Maxwell's duiker, Cephalophus max~elli. Marnrnalia 39:241-249.</P>
+<P ALIGN="JUSTIFY">Schweers, S. 1984. The reproductive biology of the banded duiker Cephalophus zebra in comparison with other species of Cephalophus. Zeitschrift fur Saeugetierkunde 49(1):21-36.</P>
+<P ALIGN="JUSTIFY">Whittle, C. and P. Whittle. 1977. Domestication and breeding of Maxwell's duiker. The Nigerian Field 42(4):13-21.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Antelope</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Spinage, C.A. 1986. The Natural History of Antelopes. Christopher Helm, UK. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Klipspringer</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Dunbar, R. and P. Dunbar. 1974. Zeitschrift fur Tierpsychologie 35:481-493.</P>
+<P ALIGN="JUSTIFY">Dunbar, R.I.M. 1979. Energetics, thermoregulation and the behavioural ecology of klipspringer. African Journal of Ecology 17:217-230.</P>
+<P ALIGN="JUSTIFY">Dunbar, R. I . M . and E. P. Dunbar. 1 980 . The pairbond in klipspringer. A nimal Beha vior 28:219-229.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Dikdik</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Hendricks, H. 1975. Zeitschrift fdr Tierpsychologie 38:55-69.</P>
+<P ALIGN="JUSTIFY">Feer, F. 1979. Observations Tcologiques sur le neotrague de Bates (Neltragus bates) de Winton, 1903, Artiodactyle, ruminant, Bovide) du nord-est du gabon. Terre et vie 33: 159-239.</P>
+<P ALIGN="JUSTIFY">Hoppe, P.P. 1975. Acta Physiol. Scand. 95, 9A.</P>
+<P ALIGN="JUSTIFY">Hoppe, P. P. 1 976 . Tritiated water turnover in Kirk' s dikdik, Madoqua (Rhynchotragus) kirk), Gunther, 1880. Zeischrift far Sadgetierkunde, Mitt. 24:318-319.</P>
+<P ALIGN="JUSTIFY">Hoppe, P.P. 1977. How to survive heat and aridity: ecophysiology of the dikdik antelope. Veterinary Medical Review 1:77-86.</P>
+<P ALIGN="JUSTIFY">Hoppe, P.P. 1977. Comparison of voluntary food and water intake and digestion in Kirk's dik-dik and suni. East African Wildlife Journal 15:41-48.</P>
+<P ALIGN="JUSTIFY">Hoppe, P.P. 1977. Rumen fermentation and body weight in African ruminants. Pages 141-150 in Proceedings 13th International Congress of Game Biologists, T.J. Peterle, ed. Wildlife Society, Washington, D.C., USA.</P>
+<P ALIGN="JUSTIFY">Hoppe, P. 1984. Strategies of digestion in African herbivores. Pages 222-243 in Herbivore Nutrition in the Tropics and Subtropics. F.M.C. Gilchrist and R.I. Machie, eds. The Science Press, South Africa.</P>
+<P ALIGN="JUSTIFY">Hungate, R.E., G.D. Phillips, A. McGregor, D.P. Hungate, and H.K. Buechner. 1959. Microbial fermentation in certain mammals. Science 130:1192-1194.</P>
+<P ALIGN="JUSTIFY">Morat, P. and M. Nording. 1978. Maximum food intake and passage of markers in the alimentary tract of the lesser mouse-deer. Malaysian Applied Biology 7:11-17.</P>
+<P ALIGN="JUSTIFY">Yalden, D.W., M.J. Largen, and D. Kock. 1984. Catalogue of the mammals of Ethiopia. 5. Artiodactyla. Monitore Zoologico Italiano Supplemento 19:67-221.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">LIZARDS</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Green Iguana</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Burghardt, G.M. and A.S. Rand, eds. 1982. Iguanas of the World: Behavior, Ecology, and Conservation. Noyes, Park Ridge, New Jersey, USA.</P>
+<P ALIGN="JUSTIFY">Fitch, H.S. and R.W. Henderson. 1977. Age and Sex Differences, Reproduction and Conservation of Iguana iguana. Milwaukee Public Museum Press. Milwaukee, Wisconsin, USA.</P>
+<P ALIGN="JUSTIFY">Hirth, H.F. 1963. Some aspects of the natural history of Iguana iguana on a tropical strand. Ecology 44:613-615.</P>
+<P ALIGN="JUSTIFY">Klein, E.H. 1982. Reproduction of the green iguana (Iguana iguna L.) in the tropical dry forest of southern Honduras. Brenesia 19/20:301-310. </P>
+<P ALIGN="JUSTIFY">Lazell, J.D., Jr. 1973. The lizard genus Iguana in the Lesser Antilles. Bulletin of the Museum of Comparative Zoology, Harvard University 145(1):1-28.</P>
+<P ALIGN="JUSTIFY">Tamsitt, J.R. and D. Valdivieso. 1963. The herpetofauna of the Caribbean Islands San Andres and Providencia. Revista de Biologfa Tropical 11(2): 131- 139. (Copies available from C. LardT, see Research Contacts.)</P>
+<P ALIGN="JUSTIFY">Van Devender, R.W. 1982. Growth and ecology of spiny-tailed and green iguanas in Costa Rica. with comments on the evolution of herbivory and large body size. Pages 162-183 in Iguanas of the World. Behavior, Ecology, and Conservation. Noyes, Park Ridge, New Jersey, USA.</P>
+<P ALIGN="JUSTIFY">Werner, D. and T. Miller. 1984. Artificial nests for female green iguanas. Herpetological Review 15(2):57-58.</P>
+<P ALIGN="JUSTIFY">Werner, D. 1986. Iguana management in Central America. BOSTID Developments 6(1). 4 pp. (Available from BOSTID Publications, HA 476, National Research Council, 2101 Constitution Avenue, N.W., Washington, D.C. 20418.)</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Black Iguana</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Burghardt, G.M. and A.S. Rand, eds. 1982. Iguanas of the World: Behavior, Ecology, and Conservation. Noyes, Park Ridge, New Jersey, USA.</P>
+<P ALIGN="JUSTIFY">Fitch, H.S. and R.W. Henderson. 1978. Ecology and exploitation of Ctenosaura similis. University of Kansas Science Bulletin 51 :483-500. (Copies available from the authors, see Research Contacts.)</P>
+<P ALIGN="JUSTIFY">Fitch, H.S., R.W. Henderson, and D.M. Hillis. 1982. Exploitation of Iguanas in Central America. In Iguanas of the World: Behavior, Ecology, and Consen~ation. Noyes, Park Ridge, New Jersey, USA.</P>
+<P ALIGN="JUSTIFY">Iverson, J.B. 1979. Behavior and ecology of the rock iguana, Cyclura carinata. Bulletin of the Florida State Museum Biological Science 24(3):175-358.</P>
+<P ALIGN="JUSTIFY">Martinez, M.G. 1986. Habitos alimenticios de iguanas y garrobos. La Prensa Grafica, San Salvador, May 5:55. (Copies available from G. LardT, see Research Contacts.)</P>
+<P ALIGN="JUSTIFY">Sanchez, S.A. 1985. El garrobo. El Diario de Hoy, San Salvador June 18:36. (Copies available from G. LardT, see Research Contacts.)</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Tegu</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Donadio, O.K. and J.M. Gallardo. 1984. Biologia y Conservacion de las Especies del GTnero Tupinambis (Squamata, Sauria Teiidae) en la Republica Argentina. Revista del Museo Argentino de Ciencias Naturales 'Bernardino Rivadavia" Zoologia, 13(11):117-127. Agosto.</P>
+<P ALIGN="JUSTIFY">Revision Bibliografica de algunos aspectos de la Biologfa conservacion y explotacion de los lagartos del gTnero topinambis (Daudin, 1803) by Laura Venturino, Dr. Thesis, Universidad de la Republic (Uruguay) 1983).</P>
+<P ALIGN="JUSTIFY">Report to World Wildlife Fund, USA, Biologia y aprovechamiento de una poblacion de Tupinambis references, by Claudio Blanco and Leohor Pessina (1985).</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">BEES</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">In addition to the publications listed, many countries run beekeeping programs, and have literature and extension services available based on local experiences. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The International Bee Research Association (IBRA) publishes a Newsletter for Beekeepers in Tropical and Subtropical Countries twice each year. Its purpose is to provide a forum for exchange of information about beekeeping. The Newsletter is funded by the United Kingdom Overseas Development Agency (ODA) and is distributed free of charge to those in developing countries involved with beekeeping. Write to the International Bee Research Association, 18 North Road, Cardiff CFI 3DY, United Kingdom, for subscription information. The IBRA can also provide information on forthcoming conferences, grant programs, and the names of other beekeepers in your country. The International Agency for Apiculture Development (IAAD) publishes a quarterly newsletter called Cornucopia that contains articles from beekeepers around the world, especially from the developing world. It provides information on producing, selling, and manufacturing hive products on a local level and discusses agroforestry and the pest and pesticide problems of honeybees. Write to Cornucopia, c/o M. Coleman, 6N 909 Roosevelt Avenue, St. Charles, Illinois 60174, USA, for a free sample. Subscriptions are $12 a year.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Adjare, S. 1984. The Golden Insect: a Handbook on Beekeeping for Beginners. Technology Consultancy Centre, University of Science and Technology, Kumasi, Ghana, in association with Intermediate Technology Publications, Ltd., 9 King Street, Covent Garden, London, WC2 E8HN, UK. 103 pp.</P>
+<P ALIGN="JUSTIFY">Anderson, R.H., B. Buys, and M.F. Johannsmeier. 1983. Beekeeping in South Africa. Department of Agriculture BuHetin No. 394. Pretoria, South Africa. 207 pp.</P>
+<P ALIGN="JUSTIFY">Bradbear, N. and D. De Jong. 1985. The management of africanized honeybees. IBRA Leaflet No. 2. International Bee Research Association (IBRA). Available in English or Spanish from Hill House, Gerrards Cross, Buckinghamshire SL9 ONR, UK. 4 pp.</P>
+<P ALIGN="JUSTIFY">Clauss, B. 1982. A Beekeeping Handbook. Agricultural Information Service, Gaborne, Botswana. 65 pp.</P>
+<P ALIGN="JUSTIFY">Crane, E., P. Walker, and R. Day. 1984. Honey plants of the world. International Bee Research Association, London.</P>
+<P ALIGN="JUSTIFY">FAO. 1984. Proceedings of the expert consultation on beekeeping with Apis mellifera in tropical and sub-tropical Asia. 9-14 April, 1984. FAO Regional Office for Asia and the Tropical Region, Paliwan Mansion, Phra Atit Road, Bangkok, Thailand.</P>
+<P ALIGN="JUSTIFY">Gentry, C. 1984. Small Scale Beekeeping. Manual M-17. Peace Corps, Washington, D.C.</P>
+<P ALIGN="JUSTIFY">IBRC. 1976. Apiculture in Tropical Climates. E. Crane, ed. Full report of the First Conference. International Bee Research Association, London.</P>
+<P ALIGN="JUSTIFY">IBRC. 1982. Proceedings of the Second International Conference on Apiculture in Tropical Climates. New Delhi, 1980. International Bee Research Association, London.</P>
+<P ALIGN="JUSTIFY">IBRC. 1985. Proceedings of the Third international Conference on Apiculture in Tropical Climates. Nairobi, Kenya, November 5-9, 1984. International Bee Research Association, London.</P>
+<P ALIGN="JUSTIFY">IBRC. 1988. Proceedings of the Fourth International Conference on Apiculture in Tropical Climates. Cairo, Egypt, November 1988. International Bee Research Association, London.</P>
+<P ALIGN="JUSTIFY">Kigatiira, K.I. 1974. Hive Designs for Beekeeping in Kenya. Proceedings Entomological Society of Ontario 105:118-128.</P>
+<P ALIGN="JUSTIFY">McGregor, S.E. 1976. Insect Pollination of Cultivated Crop Plants. U.S. Department of Agriculture Handbook No. 496. Government Printing Office, Washington, D.C. 411 pp.</P>
+<P ALIGN="JUSTIFY">Razafindrakoto, C. 1972. Beekeeping in Madagascar. UniversitT Paul-Sabaier de Toulouse, France. 123 pp. </P>
+<P ALIGN="JUSTIFY">Sammataro, D. 1985. Beekeeping in the Philippines. 2nd edition. International Bee Research Association, London.</P>
+<P ALIGN="JUSTIFY">Sammataro, D. and A. Avitabile. 1986. Beekeepers Handbook. 2nd edition. Collier Books' MacMillan Co., New York.</P>
+<P ALIGN="JUSTIFY">Saubolle, B.R, and A. Bachmann. 1979. Beekeeping: an Introduction to Modern Beekeeping in Nepal. Sahayogi Prahashan, Tripureshwar, Kathmandu, Nepal.</P>
+<P ALIGN="JUSTIFY">Silberrad, Roger E.M. n.d. Beekeeping in Zambia. Apimondia. Available through the International Bee Research Association, London.</P>
+<P ALIGN="JUSTIFY">Singh, S. 1964. Beekeeping in India. Silver Jubilee Publication of the Entomological Society of India. Entomological Society of India, New Delhi.</P>
+<P ALIGN="JUSTIFY">Smith, Francis G. 1960. Beekeeping in the Tropics. Western Printing Service, Bristol UK.</P>
+<P ALIGN="JUSTIFY">Townsend, G.F. 1978. Preparation of Honey for Market. Ministry of Agriculture and Food Publication 544. Ministry of Agriculture and Food, Ontario, Canada.</P>
+<P ALIGN="JUSTIFY">Townsend, G.F. 1976. Transitional hives for use with the tropical African bee Apis mellifera adansonii. Pages 181-189 in Apiculture in Tropical Climates. E. Crane, ed. Full report of the First Conference. International Bee Research Association, London. </P>
+<P ALIGN="JUSTIFY"></P>
+<B><P>&lt;&lt;TOC3&gt;&gt; B Research Contacts</P>
+</B><P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">This section includes the names and addresses of individuals and institutions who are familiar with the animal listed. Each person has agreed to answer requests for information and advice. This personal follow-through is the main way this book can stimulate the development of microlivestock.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">MICROBREEDS</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Microcattle</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">B.K. Ahunu, Animal Science Department, University of Ghana, P.O. Box 25, Legon, Ghana</P>
+<P ALIGN="JUSTIFY">D.O. Alonge, Meat Hygiene and Preservation Laboratory, Faculty of Veterinary Medicine, University of Ibadan, Ibadan, Nigeria</P>
+<P ALIGN="JUSTIFY">M. Andres Poli, EEA San Luis INTA, CC 17, 5730 Mercedes (SL), Argentina</P>
+<P ALIGN="JUSTIFY">F.B. Bareeba, Department of Animal Science, Makerere University, P.O. Box 7062, Kampala, Uganda</P>
+<P ALIGN="JUSTIFY">J.A. Bennett, Department of Animal, Dairy, and Veterinary Sciences, Utah State University, Logan, Utah 84322-4815, USA</P>
+<P ALIGN="JUSTIFY">J.M. Berruecos V., School of Veterinary Medicine and Zoology, Universidad Nacional Aut6noma de MTxico, Ciudad Universitaria, Alvaro Obreg6n, 04510, Mexico D.F., Mexico</P>
+<P ALIGN="JUSTIFY">Cai Li, Animal Science and Veterinary Research Institute, Southwest College of Minority Nationalities, Chengdu, People's Republic of China</P>
+<P ALIGN="JUSTIFY">Centro de Investigaciones Pecuarias (CENIP), A.P. 227-9, Santo Domingo, Dominican Republic</P>
+<P ALIGN="JUSTIFY">G.L. Chan, B4-5 Nanyang Mansion, Shenzhen, Guangdong, People's Republic of China</P>
+<P ALIGN="JUSTIFY">Y. Cheneau, Institut d'Elevage et de MTdecine VTtTrinaire des Pays Tropicaux, Laboratoire de Farcha, BP 433, N'Djamena, Chad</P>
+<P ALIGN="JUSTIFY">Cheng Peilieu, Institute of Animal Science, Chinese Academy of Sciences, Beijing, People's Republic of China</P>
+<P ALIGN="JUSTIFY">W.R. Cockrill, 29 Downs Park West, Bristol BS6 7QH, UK</P>
+<P ALIGN="JUSTIFY">J.H. Conrad, Department of Animal Science, University of Florida, Gainesville, Florida 32611, USA</P>
+<P ALIGN="JUSTIFY">T.J. Cunha, P.O. Box R, La Verne, California 91750, USA</P>
+<P ALIGN="JUSTIFY">D.E. Deppner, Trees for the Future, 11306 Estona Drive, Silver Spring, Maryland 20902, USA (breeds of the Himalayas, East Indies)</P>
+<P ALIGN="JUSTIFY">C. Devendra, Agriculture Food and Nutrition Sciences Division, International Development Research Centre (IDRC), Tanglin P.O. Box 101, 9124 Singapore</P>
+<P ALIGN="JUSTIFY">N.l. Dim, Department of Animal Science, Faculty of Agriculture, Institute for Agricultural Research, Ahmadu Bello University, P.M.B. 1044, Zaria, Nigeria</P>
+<P ALIGN="JUSTIFY">Director, Agriculture and Forestry, PB 13184, Windhoek 9000, Namibia</P>
+<P ALIGN="JUSTIFY">V.M.S. Duarte, Instituto de Investigatao Veterinaria, C.P. 7, Huambo, Angola</P>
+<P ALIGN="JUSTIFY">M. Felius, Kerkhoflaan 47C, 3034 TA Rotterdam, The Netherlands</P>
+<P ALIGN="JUSTIFY">D. Fleharty, American Dexter Cattle Association, R.R. #1, Box 378, Concordia, Missouri 64020. USA </P>
+<P ALIGN="JUSTIFY">G. Garcia Lagombra, Animal Husbandry Department, Universidad Nacional "Pedro Henriquez Urena," Decanato Ciencias Agropecuarias, Km 5~/z Aut. Duarte, Santo Domingo, Dominican Republic</P>
+<P ALIGN="JUSTIFY">F. Gebreab, College of Veterinary Science, Addis Ababa University, Addis Ababa, Ethiopia</P>
+<P ALIGN="JUSTIFY">G.F.W. Haenlein, Department of Animal Science and Agricultural Biochemistry University of Delaware, Newark, Delaware 19717-1303, USA</P>
+<P ALIGN="JUSTIFY">Z.B. Jensen, Animal and Dairy Science Research Institute, PB X02, Irene, Transvaal 1675, South Africa</P>
+<P ALIGN="JUSTIFY">Jin Xizhen, Animal Science and Veterinary Research Institute, Southwest College of Minority Nationalities, Chengdu, People's Republic of China</P>
+<P ALIGN="JUSTIFY">G. Kitsopanidis, Faculty of Agriculture, Aristotelian University of Thessaloniki, University Campus, Thessaloniki, Greece</P>
+<P ALIGN="JUSTIFY">G.E. Kodituwakku, Department of Veterinary Clinical Studies, University of Peradeniya, Peradeniya, Sri Lanka</P>
+<P ALIGN="JUSTIFY">N.M. Konnerup, 74 North Sunrise Boulevard, Camano Island, Washington 98292, USA</P>
+<P ALIGN="JUSTIFY">L.Y.L. Li, Department of Animal Husbandry and Veterinary Science, South China Agricultural College, Ghangzhou, People's Republic of China</P>
+<P ALIGN="JUSTIFY">J.K. Loosli, 406 S.W. 40th Street, Gainesville, Florida 32607, USA</P>
+<P ALIGN="JUSTIFY">A.B. Lwoga, Sokoine University of Agriculture, P.O. Box 3000, Morogoro, Tanzania</P>
+<P ALIGN="JUSTIFY">A. Martinez Balboa, Legaspy 1025, Apartado Postal 43, 23000, La Paz, Baja California Sur, Mexico</P>
+<P ALIGN="JUSTIFY">A. Masam, Livestock Training Institute, Tengeru, P.O. Box 3101, Arusha, Tanzania</P>
+<P ALIGN="JUSTIFY">J.P. Maule, Hannahfield Quarry House, 578 Lanark Road West, Balerno, Midlothian EH 14 7BN, UK</P>
+<P ALIGN="JUSTIFY">M. Mazid, Faculty of Agriculture, University of Aleppo, Aleppo, Syria</P>
+<P ALIGN="JUSTIFY">L.R. McDowell, Department of Animal Sciences, University of Florida, Gainesville, Florida 32611, USA</P>
+<P ALIGN="JUSTIFY">J.A. Morgan, College of Natural Resources and Environmental Studies, University of Juba, P.O. Box 82, Juba, Sudan</P>
+<P ALIGN="JUSTIFY">D.B. Mpiri, Livestock Production Research Institute, Private Bag, Mpwapwa, Tanzania</P>
+<P ALIGN="JUSTIFY">Ni Shicheng, Animal Husbandry and Veterinary Science, Zhejiang Agricultural University, Hangzhou, People's Republic of China</P>
+<P ALIGN="JUSTIFY">B. Nikolov, Institute of Cattle and Sheep Breeding, 6000 Stara Zagora, Bulgaria</P>
+<P ALIGN="JUSTIFY">T. Olson, University of Florida, Gainesville, Florida 32611, USA</P>
+<P ALIGN="JUSTIFY">T.W. Perry, Department of Animal Sciences, Purdue University, West Lafayette, Indiana 47907, USA</P>
+<P ALIGN="JUSTIFY">R.W. Phillips, The Representative, Apartment 810, 1101 South Arlington Ridge Road, Arlington, Virginia 22202, USA</P>
+<P ALIGN="JUSTIFY">F. Pirchner, Technical University of Munich, D-8050 Munich-Weihenstephan, Germany</P>
+<P ALIGN="JUSTIFY">A. Ramamohana Rao, Postgraduate Studies, Andhra Pradesh Agricultural University, Rajendranagar, Hyderabad, Andhra Pradesh 500 030, India</P>
+<P ALIGN="JUSTIFY">Soedomo Reksohadiprodjo, Department of Animai Nutrition, Faculty of Animal Husbandry, Universitas Gadjah Mada, Sekip Blok N-42, Yogyakarta, Indonesia</P>
+<P ALIGN="JUSTIFY">A.Y. Robles, Dairy Training and Research Institute, University of the Philippines at Los Banos, College, Laguna 3732, Philippines</P>
+<P ALIGN="JUSTIFY">Sie Cheuxia, Department of Animal Science, Nanjing Agricultural University, Nanjing, People's Republic of China</P>
+<P ALIGN="JUSTIFY">A.D. Tillman, 523 West Harned Place, Stillwater, Oklahoma 74074, USA</P>
+<P ALIGN="JUSTIFY">J.C.M. Trail, Livestock Productivity and Trypanotolerance Group, International Livestock Centre for Africa (ILCA), P.O. Box 30709, Nairobi, Kenya</P>
+<P ALIGN="JUSTIFY">A.C. Warnick, Department of Animal Science, University of Florida, Gainesville, Florida 32611, USA </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Microgoat</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">E.A. Adebowale, Institute of Agricultural Research and Training, University of Ife, Moor Plantation, P.M.B. 5029, Ibadan, Nigeria</P>
+<P ALIGN="JUSTIFY">A.A. Adeloye, Faculty of Agriculture, Adeyemi College of Education, Onjo, Nigeria</P>
+<P ALIGN="JUSTIFY">A.A. Ademosun, Department of Animal Science, University of Ife, lle-Ife, Nigeria</P>
+<P ALIGN="JUSTIFY">I.F. Adu, N.A.P.R.I., Ahmadu Bello University, Zaria, Nigeria</P>
+<P ALIGN="JUSTIFY">I.A. Akinbode, Faculty of Agriculture, University of Ife, Ile-Ife, Nigeria</P>
+<P ALIGN="JUSTIFY">A.O. Akinsoyinu, Department of Animal Science, University of Ibadan, Ibadan, Nigeria</P>
+<P ALIGN="JUSTIFY">J.A. Akonji, Institut de Recherches Zootechniques, Office National de la Recherche Scientifique et Technique (ONAREST), B.P. 65, Yaounde, Cameroon</P>
+<P ALIGN="JUSTIFY">D.O. Alonge, Faculty of Veterinary Medicine, University of Ibadan, Ibadan, Nigeria</P>
+<P ALIGN="JUSTIFY">Baik Dong Hoon, Department of Animal Science, College of Agriculture, Jeonbug National University, JEONJU, 520, Republic of Korea</P>
+<P ALIGN="JUSTIFY">J.S.F. Barker, Department of Animal Science, University of New England, Armidale, New South Wales 2351, Australia</P>
+<P ALIGN="JUSTIFY">K. Boateng, Cooperative Extension Service, University of the Virgin Islands, Box L, Kingshill, St. Croix, Virgin Islands 00850, USA</P>
+<P ALIGN="JUSTIFY">G.E. Bradford, University of California, Davis, California 95616, USA</P>
+<P ALIGN="JUSTIFY">M.S. Browne, Nutrition Consulting Services, P.O. Box 788, St. Thomas, Virgin Islands 00801, USA</P>
+<P ALIGN="JUSTIFY">T.D. Bunch, Department of Animal, Dairy, and Veterinary Sciences, Utah State University, Logan, Utah 84322-4815, USA</P>
+<P ALIGN="JUSTIFY">T.C. Cartwright, Department of Animal Science, Texas A&amp;M University, College Station, Texas 77843, USA</P>
+<P ALIGN="JUSTIFY">Centro de Investigaciones Pecuarias (CENIP), A.P. 227-9, Santo Domingo, Dominican Republic</P>
+<P ALIGN="JUSTIFY">C. Devendra, Agriculture Food and Nutrition Sciences Division, International Development Research Centre (IDRC), Tanglin P.O. Box 101, 9124 Singapore, Singapore</P>
+<P ALIGN="JUSTIFY">N.I. Dim, Department of Animal Science, Faculty of Agriculture, Institute for Agricultural Research, Ahmadu Bello University, P.M.B. 1044, Zaria, Nigeria</P>
+<P ALIGN="JUSTIFY">D. Fielding, Centre for Tropical Veterinary Medicine, Royal (Dick) School of Veterinary Studies, University of Edinburgh, Easter Bush, Roslin, Midlothian EH25 9RG, Scotland, UK</P>
+<P ALIGN="JUSTIFY">H.A. Fitzhugh, Winrock International, Route 3, Petit Jean Mountain, Morrilton, Arkansas 72110, USA</P>
+<P ALIGN="JUSTIFY">W.C. Foote, Utah State University International Sheep and Goat Institute, UNC 48, Utah State University, Logan, Utah 84322, USA</P>
+<P ALIGN="JUSTIFY">G.R. Gerona, Department of Animal Science and Veterinary Medicine, Visayas State College of Agriculture, Baybay, Leyte, Philippines</P>
+<P ALIGN="JUSTIFY">G.F.W. Haenlein, Department of Animal Science and Agricultural Biochemistry, University of Delaware, Newark, Delaware 19717-1303, USA</P>
+<P ALIGN="JUSTIFY">A. Essa Haid, Essa International, Inc., 2550 M Street, Suite 405, Washington, D.C. 20037, USA (small East African)</P>
+<P ALIGN="JUSTIFY">W. Harding, Agrarian Society, Palazzo de la Salle, Valletta, Malta</P>
+<P ALIGN="JUSTIFY">M.A. Hasnath, Department of Animal Husbandry, Bangladesh Agricultural University, P.O. Agricultural University, Mymensingh, Bangladesh</P>
+<P ALIGN="JUSTIFY">A.S. Hoversland, Division of Research Grants, National Institutes of Health, 5333 Westbard Avenue, Bethesda, Maryland 20205, USA</P>
+<P ALIGN="JUSTIFY">L. Hulse, National Pygmy Goat Association, RFD #1, Fern Avenue, Amesbury, Massachusetts 01913, USA</P>
+<P ALIGN="JUSTIFY">T.P. Husband, Department of Natural Resource Science, University of Rhode Island, Kingston, Rhode Island 02881, USA (bezoar, agrimi) </P>
+<P ALIGN="JUSTIFY">D.L. Huss, P.O. Box 426, Menard, Texas 76859, USA</P>
+<P ALIGN="JUSTIFY">B. Hutchins, 2535 Halsted Road, Apartment 1, Rockford, Illinois 61103, USA</P>
+<P ALIGN="JUSTIFY">N. Iba+ez Herrera, Paraguay 160-Urbanizacion, Apartado 315, El Recreo, Trujillo, Peru</P>
+<P ALIGN="JUSTIFY">S. Karam Shah, Livestock Experimental Station Rakh Khairewala, District Muzaffergarh, Pakistan</P>
+<P ALIGN="JUSTIFY">C. Katongole, Faculty of Veterinary Medicine, Makerere University, PO Box 7062, Kampala, Uganda</P>
+<P ALIGN="JUSTIFY">G. Kiwuwa, Department of Animal Science, Makerere University, PO Box 7062, Kampala, Uganda</P>
+<P ALIGN="JUSTIFY">L.Y.L. Li, Department of Animal Husbandry and Veterinary Science, South China Agricultural College, Ghangzhou, People's Republic of China</P>
+<P ALIGN="JUSTIFY">D.R. Lincicome, Animal Parasitology Institute, U.S. Department of Agric£lture, Building 1180, BARC-East, Beltsville, Maryland 20705, USA</P>
+<P ALIGN="JUSTIFY">Liu Chengxiang, Animal Husbandry and Veterinary Science Research Institute, Guang^ dong Agricultural Academy, Guangdong, People's Republic of China</P>
+<P ALIGN="JUSTIFY">J.K. Loosli, 406 S.W. 40th Street, Gainesville, Florida 32607, USA</P>
+<P ALIGN="JUSTIFY">M. Mahyuddin Dahan, Department of Animal Sciences, Universiti Pertanian Malaysia, Serdang, Selangor, Malaysia</P>
+<P ALIGN="JUSTIFY">G.C.H. Mandari, Livestock Research Centre, West Kilimanjaro, P.O. Box 103, Hai, Tanzania</P>
+<P ALIGN="JUSTIFY">J. Mann, Institute of Tropical Veterinary Medicine, University of Giessen, Germany</P>
+<P ALIGN="JUSTIFY">A. Martinez Balboa, Legaspy 1025, Apartado Postal 43, 23000, La Paz, Baja California Sur, Mexico</P>
+<P ALIGN="JUSTIFY">I. Mecha, Department of Animal Science, University of Nigeria, Nsukka, Anambra State, Nigeria</P>
+<P ALIGN="JUSTIFY">J. Metcalf, School of Medicine, University of Oregon, Eugene, Oregon 97403, USA</P>
+<P ALIGN="JUSTIFY">K. Mitchell, Baptist Bible Institute, P.O. Box 301, Basseterre, St. Kitts, West Indies</P>
+<P ALIGN="JUSTIFY">M. Khusahry Mohd Yusuff, Malaysian Agricultural and Research Institute (MARDI), G.P.O. Box 12301, Kuala Lumpur 01-02, Malaysia</P>
+<P ALIGN="JUSTIFY">A. Monsi, Departments of Animal Science/Food Science and Technology, Rivers State University of Science and Technology, P.M.B. 5080, Port Harcourt, Nigeria</P>
+<P ALIGN="JUSTIFY">G. Montsma, Klomperweg 79, 6741 PD, Lunteren, Netherlands</P>
+<P ALIGN="JUSTIFY">J. Moore, Department of Animal Science, University of Florida, Gainesville, Florida 32611, USA</P>
+<P ALIGN="JUSTIFY">C.M. Munyabuntu, Department of Animal Science, P.O. Box 7062, Makerere University' Kampala, Uganda</P>
+<P ALIGN="JUSTIFY">Th. Murayi, Institut des Sciences Agronomiques du Rwanda, P.O. Box 138, Butare, Rwanda</P>
+<P ALIGN="JUSTIFY">W.N.M. Mwenya, School of Agricultural Sciences, University of Zambia, Box 32379, Lusaka, Zambia</P>
+<P ALIGN="JUSTIFY">A. Nivyobizi, FacultT des Sciences Agronomiques, UniversitT du Burundi, BP 2940, Bujumbura, Burundi</P>
+<P ALIGN="JUSTIFY">G.A. Norman, Tropical Development Research Institute, 56/62 Gray's Inn Road, London WCIX 8LU, UK</P>
+<P ALIGN="JUSTIFY">K. Okello-Lapenga, Department of Veterinary Pathobiology, Makerere University, PO Box 7062, Kampala, Uganda</P>
+<P ALIGN="JUSTIFY">S. Ramahefarison, DTpartement de Recherches Zootechniques et VTtTrinaires tCENRADERU), BP 904, Amatobe, Antananarivo, Madagascar</P>
+<P ALIGN="JUSTIFY">A. Ramamohana Rao, Postgraduate Studies, Andhra Pradesh Agricultural University, Rajendranagar, Hyderabad, Andhra Pradesh 500 030, India</P>
+<P ALIGN="JUSTIFY">R.K. Rastogi, Department of Livestock Science, University of the West Indies, St. Augustine, Trinidad, West Indies </P>
+<P ALIGN="JUSTIFY">G. Rasul, District Forest Officer &amp; Wildlffe Warden, P.O. Box 501, Gilgit (northern area), Pakistan</P>
+<P ALIGN="JUSTIFY">D. Rattner, Institute of Animal Research, Kibbutz Lahav, Israel (Sinai goat, ya-ez hybrids)</P>
+<P ALIGN="JUSTIFY">Soedomo Reksohadiprodjo, Department of Animal Nutrition, Faculty of Animal Husbandry, Universitas Gadjah Mada, Sekip Blok N-42, Yogyakarta, Indonesia</P>
+<P ALIGN="JUSTIFY">A. Repollo, Jr., Palawan National Agricultural College, Aborlan, Palawan, Philippines</P>
+<P ALIGN="JUSTIFY">A.Y. Robles, Dairy Training and Research Institute, University of the Pbilippines, Los Banos, Laguna 3732, Philippines</P>
+<P ALIGN="JUSTIFY">A. Rocha, Instituto de Reprodutao e Melhoramento Animal, C.P. 25, Matola, Mozambique</P>
+<P ALIGN="JUSTIFY">C. Rodriguez, Centro de Investigaciones Pecuarias (CENIP), Autopista Duarte Km 24, Apartado 227-9, Santo Domingo, Dominican Republic</P>
+<P ALIGN="JUSTIFY">M. Nasim Siddiqi, Zoology Department, University of Peshawar, N.W.F.P., Pakistan</P>
+<P ALIGN="JUSTIFY">M. Shelton, Texas A &amp; M University, College Station, Texas 77843, USA (criollo)</P>
+<P ALIGN="JUSTIFY">A. Shkolnik, Department of Zoology, Tel Aviv University, Tel Aviv, Israel</P>
+<P ALIGN="JUSTIFY">O.C. Simpson, Cameroon Road, Prairie View A&amp;M University, Prairie View, Texas 77445, USA</P>
+<P ALIGN="JUSTIFY">Sie Chenxia, Department of Animal Science, Nanjing Agricultural University, Nanjing, People's Republic of Cbina</P>
+<P ALIGN="JUSTIFY">R.G. Wahome, Department of Animal Production, University of Nairobi, P.O. Box 29053, Nairobi, Kenya</P>
+<P ALIGN="JUSTIFY">R. Watts, Animal Science Department, Natural Resources Development College, Lusaka, Zambia</P>
+<P ALIGN="JUSTIFY">R.T. Wilson, Bartridge House, Umberleigh, North Devon EX37 9AS, UK</P>
+<P ALIGN="JUSTIFY">H. Wood, Highland Game Farm, Route 4, Box 450, Alexandria, Indiana 46001, USA</P>
+<P ALIGN="JUSTIFY">T.P. Husband, Department of Natural Resources Science, University of Rhode Island, Kingston, Rhode Island 02881, USA</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Microsheep</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">E.A. Adebowale, Institute of Agricultural Research and Training, University of Ife, Moor Plantation, P.M.B. 5029, Ibadan, Nigeria</P>
+<P ALIGN="JUSTIFY">I.F. Adu, N.A.P.R.I., Ahmadu Bello University, Zaria, Nigeria</P>
+<P ALIGN="JUSTIFY">I.A. Akinbode, Faculty of Agriculture, University of Ife, Ile-Ife, Nigeria</P>
+<P ALIGN="JUSTIFY">A.O. Akinsoyinu, Department of Animal Science, University of Ibadan, Ibadan, Nigeria</P>
+<P ALIGN="JUSTIFY">M. Amin, Jammu and Kashmis State Sheep and Shearing Products Development Board, Nowshera, Srinigar, Kashmir 190 011, India</P>
+<P ALIGN="JUSTIFY">Ahmad Mustaffa B. HJ. Babjee, Veterinary Services Department, Ibu Pejabat Perkhidmatan Haiwan, Kementerian Pertanian, Malaysia, Jalan Mahameru, Kuala Lumpur 10-02, Malaysia (grazing in rubber plantations)</P>
+<P ALIGN="JUSTIFY">J.S.F. Barker, Department of Animal Science, University of New England, Armidale, New South Wales, 2351, Australia (Indonesian breeds)</P>
+<P ALIGN="JUSTIFY">K. Boateng, Cooperative Extension Service, College of the Virgin Islands, Box L, Kingshill, St. Croix, Virgin Islands 00850, USA</P>
+<P ALIGN="JUSTIFY">G.E. Bradford, University of Calffornia, Davis, Calffornia 95616, USA</P>
+<P ALIGN="JUSTIFY">R. Breckle, U.S. Forest Service, Alsea, Oregon 97324, USA (grazing sheep in forests)</P>
+<P ALIGN="JUSTIFY">T. Bunch, Department of Animal, Dairy, and Veterinary Sciences, Utah State University, Logan, Utah 84322-4815, USA (Iranian thin-tailed, Navajo, wild-sheep hybrids)</P>
+<P ALIGN="JUSTIFY">M. Carpio P., Departamento de Produccion Animal, Universidad Nacional Agraria, Apartado 456, La Molina, Lima, Peru </P>
+<P ALIGN="JUSTIFY">Centro de Investigaciones Pecuarias (CENIP), A.P. 227-9, Santo Domingo, Dominican Republic</P>
+<P ALIGN="JUSTIFY">S. Cottrell, Pippin Farm, 3081 Goshen Road, Bellingham, Washington 98226, USA</P>
+<P ALIGN="JUSTIFY">C. Courtney, Veterinary Faculty, University of Florida, Gainesville, Florida 32611, USA</P>
+<P ALIGN="JUSTIFY">D. Deller, Virgin Islands Department of Agriculture, St. Thomas, Virgin Islands 00820, USA</P>
+<P ALIGN="JUSTIFY">A. Dettmers, 5620 Longwood Avenue, Port Charlotte, Florida 33953, USA (West African dwarf)</P>
+<P ALIGN="JUSTIFY">C. Devendra, Agricultural Food and Nutrition Sciences Division International Development Research Centre (IDRC), Tanglin P.O. Box 101, 9124 Singapore, Singapore</P>
+<P ALIGN="JUSTIFY">N.l. Dim, Department of Animal Science, Faculty of Agriculture, Institute for Agricultural Research, Ahmadu Bello University, P.M.B. 1044, Zaria, Nigeria</P>
+<P ALIGN="JUSTIFY">K. Drew, Invermay Agricultural Research Centre, Private Bag, Mosgiel, New Zealand</P>
+<P ALIGN="JUSTIFY">F. El Amin, Department of Animal Husandry, Faculty of Veterinary Science, University of Khartoum, P.O. Box 32, Khartoum North, Sudan</P>
+<P ALIGN="JUSTIFY">Gholam-Hossein Erabi, Faculty of Agriculture, University of Tabriz, Tabriz 51664, Iran</P>
+<P ALIGN="JUSTIFY">H.A. Fitzhugh, Winrock International Institute for Agricultural Development, Route 3, Petit Jean Mountain, Morrilton, Arkansas 72110, USA</P>
+<P ALIGN="JUSTIFY">W. Foote, Animal' Dairy, and Veterinary Science Department, UNC 48, Utah State University, Logan, Utah 84322-4815, USA (Virgin Islands white hair, wild-sheep hybrids)</P>
+<P ALIGN="JUSTIFY">E.-H. Gueye, Centre de Recherches Zootechniques de Kolda, Institut SenTgalais de Recherches Agricoles, (ISRA), B.P. 53, Kolda, Senegal</P>
+<P ALIGN="JUSTIFY">G. Garcia Lagombra, Animal Husbandry Department, Universidad Nacional "Pedro Henriquez Urena," Decanato Ciencias Agropecuarias, Km 5 1/2 Aut. Duarte, Santo Domingo, Dominican Republic</P>
+<P ALIGN="JUSTIFY">G.F.W. Haenlein, Department of Animal Science and Agricultural Biochemistry, University of Delaware, Newark, Delaware 19717-1303, USA</P>
+<P ALIGN="JUSTIFY">E. Henson, Bemborough, Guiting Power, Cheltenham, Gloucester, UK (rare breeds)</P>
+<P ALIGN="JUSTIFY">D.L. Huss, P.O. Box 426, Menard, Texas 76859, USA</P>
+<P ALIGN="JUSTIFY">N. Ibanez Herrera, Paraguay 160 - Urbanizacion, Apartado 315, El Recreo, Trujillo, Peru</P>
+<P ALIGN="JUSTIFY">P. Jewell, Department of Physiology, University of Cambridge, Cambridge CB2 ITN, UK</P>
+<P ALIGN="JUSTIFY">Jones Sheep Farm, RR 2 Box 185-55, Peabody, Kansas 66866, USA</P>
+<P ALIGN="JUSTIFY">P.E. Loggins, Animal Science Department, 108-D Suite, University of Florida, Gainesville, Florida32611, USA</P>
+<P ALIGN="JUSTIFY">J.K. Loosli, 406 S.W. 40th Street, Gainesville, Florida 32607, USA</P>
+<P ALIGN="JUSTIFY">G.C.H. Mandari, Livestock Research Centre, West Kilimanjaro, P.O. Box 103, Hai, Tanzania</P>
+<P ALIGN="JUSTIFY">J.P. Maule, Hannahfield Quarry House, 578 Lanark Road West, Balerno, Midlothian EH14 7BN, UK</P>
+<P ALIGN="JUSTIFY">L.K. McNeal, Animal, Dairy, and Veterinary Science Department, UNC 48, Utah State University, Logan, Utah 84322-4815, USA</P>
+<P ALIGN="JUSTIFY">I. Mecha, Department of Animal Science, University of Nigeria, Nsukka, Anambra State, Nigeria</P>
+<P ALIGN="JUSTIFY">K. Mitchell, Baptist Bible Institute, P.O. Box 301, Basseterre, St. Kitts, West Indies</P>
+<P ALIGN="JUSTIFY">A. Monsi, Department of Animal Science, Food Science and Technology, Rivers State University of Science and Technology, P.M.B. 5080, Port Harcourt, Nigeria</P>
+<P ALIGN="JUSTIFY">C.M. Munyabuntu, Department of Animal Science, Makerere University, P.O. Box 7062, Kampala, Uganda </P>
+<P ALIGN="JUSTIFY">Th. Murayi, Institut des Sciences Agronomiques du Rwanda, P.O. Box 138, Butare, Rwanda</P>
+<P ALIGN="JUSTIFY">W.N.M. Mwenya, School of Agriculture Sciences, University of Zambia, Box 32379, Lusaka,  Zambia</P>
+<P ALIGN="JUSTIFY">M. Ngendahayo, Institut des Sciences Agronomiques du Rwanda, B.P. 138, Butare, Rwanda</P>
+<P ALIGN="JUSTIFY">R. Njwe, DTpartement des Sciences Animales, Ecole Nationale SupTrieure Agronomique, Centre  Universitaire de Dschang, B.P. 138, YaoundT, United Republic of Cameroon</P>
+<P ALIGN="JUSTIFY">W.J.A. Payne, 91 Bedwardine Road, London SE19 3AY, UK</P>
+<P ALIGN="JUSTIFY">R.W. Phillips, The Representative, Apartment 810, 1101 South Arlington Ridge Road, Arlington,  Virginia 22202, USA</P>
+<P ALIGN="JUSTIFY">G.V. Raghavan, Animal Science Department, College of Veterinary Science, Andhra Pradesh  Agricultural University, Rajendranagar, Hyderabad 500 030, Andhra Pradesh, India</P>
+<P ALIGN="JUSTIFY">A. Ramamohana Rao, Postgraduate Studies, Andhra Pradesh Agricultural University,  Rajendranagar, Hyderabad, Andhra Pradesh 500 030, India</P>
+<P ALIGN="JUSTIFY">R.K. Rastogi, Department of Livestock Science, University of the West Indies, St. Augustine,  Trinidad, West Indies</P>
+<P ALIGN="JUSTIFY">Soedomo Reksohadiprodjo, Department of Animal Nutrition, Faculty of Animal Husbandry,  Universitas Gadjah Mada, Sekip Blok N-42, Yogyakarta, Indonesia</P>
+<P ALIGN="JUSTIFY">A.Y. Robles, Dairy Training and Research Institute, University of the Philippines at Los Banos,  College, Laguna 3732, Philippines</P>
+<P ALIGN="JUSTIFY">A. Rocha, Instituto de Reprodutao e Melhoramento Animal, C.P. 25, Matola, Mozambique</P>
+<P ALIGN="JUSTIFY">M.L. Ryder, c/o H.F.R.O., Bush Estate, Penicuik, Edinburgh, UK (Barbados blackbelly, wool)</P>
+<P ALIGN="JUSTIFY">Sie Chenxia, Department of Animal Science, Nanjing Agricultural University, Nanjing, People's  Republic of China</P>
+<P ALIGN="JUSTIFY">C. David Simpson, Range and Wildlife Department, Texas Tech University, P.O. Box 4349,  Lubbock, Texas 79409, USA</P>
+<P ALIGN="JUSTIFY">C.E. Terrill, U.S. Department of Agriculture, Building 005, BARC-West, Beltsville, Maryland 20705,  USA</P>
+<P ALIGN="JUSTIFY">H.N. Turner, Genetics Research Laboratories, CSIRO, P.O. Box 184, North Ryde, New South  Wales 2113, Australia (Indonesian breeds)</P>
+<P ALIGN="JUSTIFY">R. Vaccaro, Universidad Nacional Agraria, La Molina, P.O. Box 456, Lima, Peru</P>
+<P ALIGN="JUSTIFY">R.G. Wahome, Department of Animal Production, P.O. Box 29053, Nairobi, Kenya</P>
+<P ALIGN="JUSTIFY">S. Wildeus, College of the Virgin Islands, Agricultural Experiment Station, R.R. 2, Box 10051  Kingshill, St. Croix, Virgin Islands 00850, USA</P>
+<P ALIGN="JUSTIFY">R.T. Wilson, Bartridge House, Umberleigh, North Devon EX37 9AS, UK</P>
+<P ALIGN="JUSTIFY">Wu Jitang, Animal and Veterinary Science, Jiangsu Province Academy of Agricultural Sciences,  Nanjing, People's Republic of China</P>
+<P ALIGN="JUSTIFY">A. Yenikoye, FacultT d'Agronomie, UniversitT de Niamey, B.P. 10662, Niamey, Niger</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Micropig</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">I.A. Akinbode, Faculty of Agriculture, University of Ife, Ile-Ife, Nigeria</P>
+<P ALIGN="JUSTIFY">D.O. Alonge, Meat Hygiene and Preservation Laboratory, Faculty of Veterinary Medicine,  University of Ibadan, Ibadan, Nigeria  </P>
+<P ALIGN="JUSTIFY">J.M. Andrews, Mesoamerican Ecology Institute, Tulane University, New Orleans, Louisiana 70118, USA (Yucatan pig)</P>
+<P ALIGN="JUSTIFY">G. Ashton-Peach, Box 17, Ohaeawai, Bay of Islands, New Zealand (kunekune)</P>
+<P ALIGN="JUSTIFY">M. Berruecos V. Muz, Facultad de Medicina Veterinaria y Zootecnia, Ciudad Universitaria, Mexico D.F., Mexico</P>
+<P ALIGN="JUSTIFY">R. Blakely, Sedgwick County Zoo, Wichita, Kansas 67203, USA (Ossabaw)</P>
+<P ALIGN="JUSTIFY">K. Boateng, Cooperative Extension Service, University of the Virgin Islands, Box L., Kingshill, St. Croix, Virgin Islands 00850, USA</P>
+<P ALIGN="JUSTIFY">I.L. Brisbin, Savannah River Ecology Laboratory, P.O. Drawer E, Aiken, South Carolina 29801, USA (Ossabaw)</P>
+<P ALIGN="JUSTIFY">L. Bustad, Veterinary School, Washington State University, Pullman, Washington, 99163, USA</P>
+<P ALIGN="JUSTIFY">C. Catibog-Sinha, Forest Products Research and Development Institute, College, Laguna 4031, Philippines</P>
+<P ALIGN="JUSTIFY">Centro de Investigaciones Pecuarias (CENIP), A.P. 227-9, Santo Domingo, Dominican Republic</P>
+<P ALIGN="JUSTIFY">Charles River Laboratories, Inc., 251 Ballardvale Street, Wilmington, Massachusetts 01887-0630, USA</P>
+<P ALIGN="JUSTIFY">J.H. Conrad, Department of Animal Science, University of Florida, Gainesville, Florida 32611, USA</P>
+<P ALIGN="JUSTIFY">T.J. Cunha, PO Box R, LaVerne, California 91750, USA</P>
+<P ALIGN="JUSTIFY">F. Dederer, 712 Brown Street, Philadelphia, Pennsylvania 19123, USA</P>
+<P ALIGN="JUSTIFY">A. Dettmers, 5620 Longwood Avenue, Port Charlotte, Florida 33953, USA (miniature pigs)</P>
+<P ALIGN="JUSTIFY">C. Devendra, Agriculture Food and Nutrition Sciences Division, International Development Research Centre (IDRC), Tanglin P.O. Box 101, 9124 Singapore</P>
+<P ALIGN="JUSTIFY">N.I. Dim, Department of Animal Science, Faculty of Agriculture, Ahmadu Bello University, P.M.B. 1044, Zaria, Nigeria</P>
+<P ALIGN="JUSTIFY">G. Edgar, Greenhill, I R.D., Balfour, Southland, New Zealand (kunekune)</P>
+<P ALIGN="JUSTIFY">H. Hendricks, Department of Animal, Dairy, and Veterinary Sciences, Utah State University, Logan, Utah 84322-4815, USA</P>
+<P ALIGN="JUSTIFY">B.J. Hepburn, Swine Program, Charles River Laboratories, 251 Ballardvale Street, Wilmington, Massachusetts 01887-0630, USA (laboratory pigs)</P>
+<P ALIGN="JUSTIFY">P. Holbrook, Aria Road' via Te Kuiti, New Zealand (kunekune)</P>
+<P ALIGN="JUSTIFY">R.R. Hook, Jr., Sinclair Medical Research Farm, University of Missouri, Route 3, Columbia, Missouri 65203, USA (laboratory pigs)</P>
+<P ALIGN="JUSTIFY">J.O. Ilori, Faculty of Agriculture, University of If e, Ile-Ife, Nigeria</P>
+<P ALIGN="JUSTIFY">G. E. Kodituwakku, Department of Veterinary Clinical Studies, University of Peradeniya, Peradeniya, Sri Lanka</P>
+<P ALIGN="JUSTIFY">J.K. Loosli, 406 S.W. 40th Street' Gainesville, Florida 32607, USA</P>
+<P ALIGN="JUSTIFY">J.H. Maner, Winrock International, Route 3, Petit Jean Mountain, Morrilton, Arkansas 72110, USA</P>
+<P ALIGN="JUSTIFY">J.J. Mayer, Savannah River Ecology Laboratory, P.O. Drawer E, Aiken, South Carolina 29801, USA (Ossabaw)</P>
+<P ALIGN="JUSTIFY">K. Mitchell, Baptist Bible Institute, P.O. Box 301, Basseterre, St. Kitts, West Indies</P>
+<P ALIGN="JUSTIFY">A. Monsi, Departments of Animal Science/Food Science and Technology, Rivers State University of Science and Technology, P.M.B. 508O, Port Harcourt, Nigeria</P>
+<P ALIGN="JUSTIFY">J. Mtimuni, Livestock Production Department, Bunda College of Agriculture, University of Malawi, P.O. Box 219, Lilongwe, Malawi</P>
+<P ALIGN="JUSTIFY">D.G. Mugisa, c/o Insure Consult, P.O. Box 30002, Nakivubo, Kampala, Uganda</P>
+<P ALIGN="JUSTIFY">K. Mull, 2834 Hamner Avenue #208, Norco, California 91760, USA</P>
+<P ALIGN="JUSTIFY">W.L.R. Oliver, Pigs and Peccaries Specialist Group, Jersey Wildlife Prescrvation Trust, Les AugrFs Manor, Jersey, Channel Islands, UK (pigmy hog) </P>
+<P ALIGN="JUSTIFY">L. Panepinto, Redstone Canyon, P.O. Box 105, Masonville, Colorado 80541, USA (miniature pigs)</P>
+<P ALIGN="JUSTIFY">W.J.A. Payne, 91 Bedwardine Road, London SE19 3AY, UK</P>
+<P ALIGN="JUSTIFY">C.C. Perdomo, Centro Nacional de Pesquisa de Suinos e Aves, BR 153, km 110, CP D-3, 89700 Concordia, SC, Brazil</P>
+<P ALIGN="JUSTIFY">R.W. Phillips, The Representative, Apartment 810, 1101 South Arlington Ridge Road, Arlington, Virginia 22202, USA (Chinese breeds)</P>
+<P ALIGN="JUSTIFY">W.G. Pond, Meat Animal Research Center, U.S. Department of Agriculture, Box 166, Clay Center, Nebraska 68933, USA</P>
+<P ALIGN="JUSTIFY">H. Popenoe, International Programs in Agriculture, 3028 McCarty Hall, University of Florida, Gainesville, Florida 32611, USA (New Guinea pigs)</P>
+<P ALIGN="JUSTIFY">B.S. Reddi, CoHege of Veterinary Science, Andhra Pradesh Agricultural University, Tirupati 517 502, India</P>
+<P ALIGN="JUSTIFY">S. Avendano Reyes, Instituto Nacional de las Investigaciones sobre los Recursos BiotTcnicos, (INIREB), Apartado Postal 97, MTrida, Yucatan, Mexico (Yucatan)</P>
+<P ALIGN="JUSTIFY">C. Robinson, Robinson's Racing Pigs, 5809 20th Avenue South, Tampa, Florida 336195457, USA (miniature pigs)</P>
+<P ALIGN="JUSTIFY">C. Arellano Sota, Regional Office for Latin America and the Caribbean, Food and Agriculture Organization of the United Nations, Casillo 10095, Santiago, Chile (Cuing)</P>
+<P ALIGN="JUSTIFY">A. Sriramamurty, College of Veterinary Science, Andhra Pradesh Agricultural University, Tirupati 517 502, India</P>
+<P ALIGN="JUSTIFY">M.M. Swindle, Comparative Medicine/Lab Animal Resources, Medical University of South Carolina, 171 Ashley Avenue, Charleston, South Carolina 29425, USA (laboratory pigs)</P>
+<P ALIGN="JUSTIFY">N. Tilakaratne, Veterinary Research Institute, Gannoruwa, Peradeniya, Sri Lanka</P>
+<P ALIGN="JUSTIFY">R.G. Wahome, Department of Animal Production, P.O. Box 29053, Nairobi, Kenya</P>
+<P ALIGN="JUSTIFY">Wu Jitang, Animal and Veterinary Science, Jiangsu Provincial Academy of Agricultural Sciences, Nanjing, People's Republic of China</P>
+<P ALIGN="JUSTIFY">Yong Shen Lee, Department of Animal Husbandry and Veterinary Medicine, South China Agricultural University, Guangzhou, People's Republic of China</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">POULTRY</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Information on poultry can generally be obtained from local ministries of agriculture or veterinary and livestock services. However, another source is the World's Poultry Science Association (c/o Institut fur Kleintierzucht, Dornbergstrasse 25/27, Postfach 280, C-3100 Celle, Germany). It has over 5,000 members from 40 national groups. Its objectives are (1) to advance poultry science and the poultry industry, (2) to disseminate and facilitate the exchange of knowledge pertaining to all branches of the poultry industry, (3) to encourage the promotion of world poultry congresses and regional conferences, and (4) to cooperate with other international organizations. It maintains working groups to explore and assess research work on tropical poultry problems. The World's Poultry Science Journal is published 3 times a year. It has also published a multilingual poultry dictionary.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Chicken</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">A.O. Aduku, Department of Animal Science, Faculty of Agriculture, Ahmadu Bello University, P.M.B. 1044, Zaria, Nigeria </P>
+<P ALIGN="JUSTIFY">D.O. Alonge, Meat Hygiene and Preservation Laboratory, Faculty of Veterinary Medicine, University of Ibadan, Ibadan, Nigeria</P>
+<P ALIGN="JUSTIFY">A. Ben-David, Poultry Production Specialist, 5, Azar Street, Holon 58291, Israel</P>
+<P ALIGN="JUSTIFY">I.L. Brisbin, Jr., Savannah River Ecology Laboratory, P.O. Drawer E, Aiken, South Carolina 29801, USA</P>
+<P ALIGN="JUSTIFY">J.K. Camoens, Senior Livestock Specialist, Asian Development Bank, P.O. Box 789, Manila 2800, Philippines</P>
+<P ALIGN="JUSTIFY">J.R. Couch, Poultry Science Department, Texas A&amp;M University, College Station, Texas 77843, USA</P>
+<P ALIGN="JUSTIFY">R.D. Crawford, Department of Animal and Poultry Science, University of Saskatchewan, Saskatoon, Saskatchewan S7N 0W0, Canada</P>
+<P ALIGN="JUSTIFY">M. Cuca G., Institucion de Ensenanza e Investigacion en Ciencias Agricolas, Colegio de Postgraduados, Chapingo, Mexico</P>
+<P ALIGN="JUSTIFY">N.I. Dim, Animal Science Department, Faculty of Agriculture, Ahmadu Bello University, P.M.B. 1044, Zaria, Nigeria</P>
+<P ALIGN="JUSTIFY">D. Fielding, Centre for Tropical Veterinary Medicine, Royal (Dick) School of Veterinary Studies, University of Edinburgh, Easter Bush, Roslin, Midlothian EH25 9RG, Scotland, UK</P>
+<P ALIGN="JUSTIFY">R.O. Hawes, Department of Animal and Veterinary Sciences, University of Maine, Orono, Maine 04469, USA</P>
+<P ALIGN="JUSTIFY">D. Holderread, P.O. Box 492, Corvallis, Oregon 97339, USA</P>
+<P ALIGN="JUSTIFY">C.H. Huang, Food and Fertilizer Technology Center for the Asian and Pacific Region, Fifih Floor, 14 Wenchow Street, Taipei, Taiwan</P>
+<P ALIGN="JUSTIFY">E.H. Ketelaars, Department of Tropical Husbandry, P.O. Box 338, 6700 A.H. Wageningen, The Netherlands</P>
+<P ALIGN="JUSTIFY">M.A. Latif, Department of Poultry Science, Bangladesh Agricultural University, Mymensingh, Bangladesh</P>
+<P ALIGN="JUSTIFY">H. Martoyo, Faculty of Animal Science, Institut Pertanian Bogor, Jalan Raya Pajajaran, Bogor, West Java, Indonesia</P>
+<P ALIGN="JUSTIFY">K. Mitchell, Baptist Bible Institute, P.O. Box 301, Basseterre, St. Kitts, West Indies</P>
+<P ALIGN="JUSTIFY">E.T. Moran, Jr., Poultry Science Department, Auburn University, Auburn, Alabama 36849-4291, USA</P>
+<P ALIGN="JUSTIFY">S. Ochetim, School of Agriculture, University of the South Pacific, Alafua Campus, Apia, Western Samo</P>
+<P ALIGN="JUSTIFY">S. Parks, Route 1, Box 47-C, Brookshire, Texas 77423, USA (Araucanian chicken)</P>
+<P ALIGN="JUSTIFY">R.W. Phillips, The Representative, Apt.810, 1101 South Arlington Ridge Road, Arlington, Virginia 22202, USA</P>
+<P ALIGN="JUSTIFY">H.L. Polley, Programme DTveloppement Plateau Bateke, CBZO, B.P. 4728, Kinshasa 2, Zaire</P>
+<P ALIGN="JUSTIFY">A. Ramakrishman, Center for Advanced Studies in Poultry Science, Kerala Agricultural University, Mannuthy 680 651, Kerala, India</P>
+<P ALIGN="JUSTIFY">C.V. Reddy, Faculty of Veterinary Science, Andhra Pradesh Agricultural University, Rajendranagar, Hyderabad 500 030, India</P>
+<P ALIGN="JUSTIFY">E. Ross, Department of Animal Science, University of Hawaii, Honolulu, Hawaii 96822, USA</P>
+<P ALIGN="JUSTIFY">M.L. Scott, 16 Spruce Lane, Ithaca, New York 14850, USA</P>
+<P ALIGN="JUSTIFY">T.J. Sexton, Agricultural Research Service, U.S. Department of Agriculture, Beltsville Agricultural Research Center, Building 262, Beltsville, Maryland 20705, USA</P>
+<P ALIGN="JUSTIFY">R.G. Somes, Nutritional Sciences, Box U-17, University of Connecticut, Storrs, Connecticut 06268, USA</P>
+<P ALIGN="JUSTIFY">M. Sunde, Poultry Science Department, University of Wisconsin, Madison, Wisconsin 53706, USA</P>
+<P ALIGN="JUSTIFY">R.T. Wilson, Bartridge House, Umberleigh, North Devon EX37 9AS, UK </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Duck</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">R.E. Abdelsamie, Department of Biochemistry, Microbiology, and Nutrition, University of New England, Armidale, New South Wales 2351, Australia</P>
+<P ALIGN="JUSTIFY">S. Ahmed, Department of Poultry Science, Bangladesh Agricultural University, Mymensingh, Bangladesh</P>
+<P ALIGN="JUSTIFY">A. Bande, PATI, Popondetta Agricultural College, Box 131, Popondetta, Oro Province, Papua New Guinea</P>
+<P ALIGN="JUSTIFY">R.S. Bird, Cherry Valley Farms Ltd., Rothwell, Lincoln LN7 6BR, UK</P>
+<P ALIGN="JUSTIFY">V.D. Bulbule, Central Duck Breeding Farm, Government of India, Hessaraghatta, Bangalore 560 088, India</P>
+<P ALIGN="JUSTIFY">J.K. Camoens, Asian Development Bank, P.O. Box 789, Manila 2800, Philippines</P>
+<P ALIGN="JUSTIFY">K.M. Cheng, Avian Genetics Laboratory, Department of Animal Science, University of British Columbia, Vancouver, British Columbia V6T 2A2, Canada</P>
+<P ALIGN="JUSTIFY">W.F. Dean, Cornell University Duck Research Laboratory, P.O. Box 217, Eastport, New York 11941, USA</P>
+<P ALIGN="JUSTIFY">N.I. Dim, Animal Science Department, Faculty of Agriculture, Ahmadu Bello University, P.M.B. 1044, Zaria, Nigeria</P>
+<P ALIGN="JUSTIFY">P. Edwards, Agricultural and Food Engineering Division, Asian Institute of Technology, P.O. Box 2754, Bangkok 10501, Thailand</P>
+<P ALIGN="JUSTIFY">L. Fishelson, Department of Zoology, Tel Aviv University, Ramat-ave, Tel Aviv 69978, Israel</P>
+<P ALIGN="JUSTIFY">W.F. Floresca, Department of Animal Science and Veterinary Medicine, Visayas State College of Agriculture, Baybay, Leyte 7127, Philippines</P>
+<P ALIGN="JUSTIFY">H. Godoy, Ingeniero Agronomio, Simon Bolivar 2397, Santiago, Chile</P>
+<P ALIGN="JUSTIFY">P. Hardjosworo, Fakultas Peternakan, Institut Pertanian Bogor, Bogor, Indonesia</P>
+<P ALIGN="JUSTIFY">R. Henry, Cherry Valley Farms Limited, Divisional Offices, North Kelsey Moor, Lincoln LN7 6HH, UK</P>
+<P ALIGN="JUSTIFY">D. Holderread, P.O. Box 492, Corvallis, Oregon 97339, USA</P>
+<P ALIGN="JUSTIFY">W.F. Hollander, Route 4, Box 168, Ames, lowa 5001O, USA</P>
+<P ALIGN="JUSTIFY">E. Hoffmann, Canning, Nova Scotia BOP IHO, Canada</P>
+<P ALIGN="JUSTIFY">C.H. Huang, Food and Fertilizer Technology Center for the Asian and Pacific Region, Fifth Floor, 14 Wenchow Street, Taipei, Taiwan</P>
+<P ALIGN="JUSTIFY">G. Ibanez H., Bolivar 451, Trujillo, Peru</P>
+<P ALIGN="JUSTIFY">Z. Jungkaro, Research Institute for Inland Fisheries, Jalan Sempur No. 1, Indonesia</P>
+<P ALIGN="JUSTIFY">G.A.R. Kamar, Animal Production Department, Faculty of Agriculture, Cairo University, Giza, Egypt</P>
+<P ALIGN="JUSTIFY">E.H. Ketelaars, Department of Tropical Husbandry, P.O. Box 338, 6700 A.H. Wageningen, The Netherlands</P>
+<P ALIGN="JUSTIFY">I.P. Kompiang, BaliPenelitianTernak, P.O. Box 123, Bogor 16001, WestJava, Indonesia</P>
+<P ALIGN="JUSTIFY">M.A. Latif, Department of Poultry Science, Bangladesh Agricultural University, Mymensingh, Bangladesh</P>
+<P ALIGN="JUSTIFY">H. Martoyo, Faculty of Animal Science, Institut Pertanian Bogor, Jalan Raya Pajajaran, Bogor, Indonesia</P>
+<P ALIGN="JUSTIFY">P. Mongin, Station de Recherches Avicoles, I.N.R.A., Nouzilly 37380 Monnaie, France</P>
+<P ALIGN="JUSTIFY">E.T. Moran, Jr., Poultry Science Department, Auburn University, Auburn, Alabama 36849-4291, USA</P>
+<P ALIGN="JUSTIFY">S. Ochetim, School of Agriculture, University of the South Pacific, Alafua Campus, Apia, Western Samoa</P>
+<P ALIGN="JUSTIFY">R.W. Phillips, The Representative, Apartment 810, 1101 South Arlington Ridge Road, Arlington, Virginia 22202, USA</P>
+<P ALIGN="JUSTIFY">H. Pingel, Karl-Marx-Universitat, Sektion TV, Lehrstuhl Geflugel- und Pelztierzucht, 7010 Leipzig, Stephanstrasse 12, Germany </P>
+<P ALIGN="JUSTIFY">S. Poernomo, Research Institute for Veterinary Science, Jalan R.E. Martadinata 32, P.O. Box 52, Bogor, West Java, Indonesia</P>
+<P ALIGN="JUSTIFY">A. Ramakrishman, Center for Advanced Studies in Poultry Science' Kerala Agricultural University, Mannuthy 680 651, Kerala, India</P>
+<P ALIGN="JUSTIFY">B. Retailleau, Grimaud FrFres S.A., La CorbiFre, 49450 Roussay, France</P>
+<P ALIGN="JUSTIFY">T.S. Sandhu, Cornell University Duck Research Laboratory, P.O. Box 217, Eastport, New York 11941, USA</P>
+<P ALIGN="JUSTIFY">M.L. Scott, 16 Spruce Lane, Ithaca, New York 14850, USA</P>
+<P ALIGN="JUSTIFY">B.K. Shingari, Department of Animal Science, Punjab Agricultural University, Ludhiana 141 004, India</P>
+<P ALIGN="JUSTIFY">C. Tai, Taiwan Livestock Research Institute, 112 Farm Road Shin-hua, Tainan, Taiwan 71210</P>
+<P ALIGN="JUSTIFY">B. Tangendjaja, Bali Penelitian Ternak, P.O. Box 123, Bogor 16001, Indonesia</P>
+<P ALIGN="JUSTIFY">Tian Fuh Shen, Department of Animal Husbandry, National Taiwan University, Taipei 10764, Taiwan</P>
+<P ALIGN="JUSTIFY">S.S. Tsai, Laboratory of Veterinary Pathology, National Pintung Institute of Agriculture, Pintung, Taiwan</P>
+<P ALIGN="JUSTIFY">A. Romero Villanueva, Centro Tropical de Capacitaci6n Agropecuaria y Forestal, Apartado Postal #4S, Macuspana 86700 Tabasco, Mexico</P>
+<P ALIGN="JUSTIFY">R.T. Wilson, Bartridge House, Umberleigh, North Devon EX37 9AS, UK</P>
+<P ALIGN="JUSTIFY">Wildfowl Trust, Slimbridge, UK</P>
+<P ALIGN="JUSTIFY">Yeong Shue Woh, Malaysian Agricultural Research and Development Institute (MARDI), G.P.O. No. 12301, 50774 Kuala Lumpur, Malaysia</P>
+<P ALIGN="JUSTIFY">Cha Tak Yimp, Poultry and Swine Unit, Department of Veterinary Services, Jalan Mahameru, 50630 Kuala Lumpur, Malaysia</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Geese</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Many universities have a department of animal or poultry science that should know about the culture and management of these birds.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">A. Bande, PATI, Popondetta Agricultural College, Box 131, Popondetta, Oro Province, Papua New Guinea</P>
+<P ALIGN="JUSTIFY">J.K. Camoens, Asian Development Bank, P.O. Box 789, Manila 2800, Philippines</P>
+<P ALIGN="JUSTIFY">F.D. Chesterley, 4502 Loomis Trail, Blaine, Washington 98230, USA</P>
+<P ALIGN="JUSTIFY">R.D. Crawford, Department of Animal and Poultry Science, University of Saskatchewan, Saskatoon, Saskatchewan S7N 0W0, Canada</P>
+<P ALIGN="JUSTIFY">N.l. Dim, Animal Science Department, Faculty of Agriculture, Ahmadu Bello University, P.M.B. 1044, Zaria, Nigeria</P>
+<P ALIGN="JUSTIFY">D. Holderread, P.O. Box 492, Corvallis, Oregon 97339, USA</P>
+<P ALIGN="JUSTIFY">S. Jackson, P.O. Box 3, Creenbank, Washington 98253, USA (weeder geese)</P>
+<P ALIGN="JUSTIFY">Liu Fuan, Department of Animal Husbandry and Veterinary Medicine, South China Agricultural University, Guangzhou, People's Republic of China</P>
+<P ALIGN="JUSTIFY">P. Mongin, Station de Recherches Avicoles, l.N.R.A., Nouzilly 37380, Monnaie, France</P>
+<P ALIGN="JUSTIFY">E. Ross, Department of Animal Science, University of Hawaii, Honolulu, Hawaii 96822, USA</P>
+<P ALIGN="JUSTIFY">B.K. Shingari, Department of Animal Science, Punjab Agricultural University, Ludhiana 141 004, India</P>
+<P ALIGN="JUSTIFY">H.R. Wilson, Poultry Science Department, University of Florida, Gainesville, Florida 32611, USA </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Guinea Fowl</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">A.O. Aduku, Department of Animal Science, Faculty of Agriculture, Ahmadu Bello University, P.M.B. 1044, Zaria, Nigeria</P>
+<P ALIGN="JUSTIFY">American Guinea Club, c/o Angie Papp, 620 Payne Road, New Albany, Indiana 47150, USA</P>
+<P ALIGN="JUSTIFY">J.S.O. Ayeni, Kainji Lake Research Institute, P.M.B. 666, New Bussa, Kwara State, Nigeria</P>
+<P ALIGN="JUSTIFY">A. Ben-David, 5, Azar Street, Holon 58291, Israel</P>
+<P ALIGN="JUSTIFY">G.S. Brah, Department of Animal Science, Punjab Agricultural University, Ludhiana 141 004, India</P>
+<P ALIGN="JUSTIFY">X. Colonna C., 14 Cotham Road, Bristol BS6 6DR, UK</P>
+<P ALIGN="JUSTIFY">N.I. Dim, Department of Animal Science, Faculty of Agriculture, Ahmadu Bello University, P.M.B. 1044, Zaria, Nigeria</P>
+<P ALIGN="JUSTIFY">R. Dumont, Ecole Nationale SupTrieure des Sciences Agronomiques AppliquTes, 26, boulevard Docteur Petitjean 21100 Dijon, France</P>
+<P ALIGN="JUSTIFY">R. Etches, Department of Animal and Poultry Science, University of Guelph, Guelph, Ontario NIG 2WI, Canada</P>
+<P ALIGN="JUSTIFY">D. Holderread, P.O. Box 492, Corvallis, Oregon 97339, USA</P>
+<P ALIGN="JUSTIFY">A.F. Hutton, Garaina Farms, Scrubby Creek Road, Gympie MS: 115, Queensland 4570, Australia</P>
+<P ALIGN="JUSTIFY">D.N. Johnson, Natal Parks, Game and Fish Preservation Board, P.O. Box 661, Pietermaritzburg 3200, South Africa</P>
+<P ALIGN="JUSTIFY">S.D. Lukefahr, International Small Livestock Research Center, Department of Food Science and Animal Industries, Alabama A&amp;:M University, P.O. Box 264, Normal, Alabama 35762, USA</P>
+<P ALIGN="JUSTIFY">W. Michie, Poultry Husbandry Division, North of Scotland College of Agriculture, Parkhead, Craibstone, Bucksburn, Aberdeen AB2 9SX, Scotland, UK</P>
+<P ALIGN="JUSTIFY">P. Mongin, Station de Recherches Avicoles, I.N.R.A., Nouzilly, 37380 Monnaie, France</P>
+<P ALIGN="JUSTIFY">S. Ochetim, School of Agriculture, University of the South Pacific, Alafua Campus, Apia, Western Samoa</P>
+<P ALIGN="JUSTIFY">A.N. Okaeme, Wildlife/Range Division, Kainji Lake Research Institute, P.M.B. 666, New Bussa, Kwara State, Nigeria</P>
+<P ALIGN="JUSTIFY">J.S. Sandhu, Poultry Breeder, Department of Animal Science, Punjab Agricultural University, Ludhiana 141 004, India</P>
+<P ALIGN="JUSTIFY">B.K. Shingari, Department of Animal Science, Punjab Agricultural University, Ludhiana 141 004, India</P>
+<P ALIGN="JUSTIFY">R.G. Somes, Nutritional Sciences, Box U-17, University of Connecticut, Storrs, Connecticut 06268, USA</P>
+<P ALIGN="JUSTIFY">R.T. Wilson, Bartridge House, Umberleigh, North Devon EX37 9AS, UK</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Muscovy</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">R.E. Abdelsamie, Department of Biochemistry, Microbiology, and Nutrition, University of New England, Armidale, New South Wales 2351, Australia</P>
+<P ALIGN="JUSTIFY">G.P. Bilong, Department of Primary Industry, Monogastric Research Centre, P.O. Box 73, Lae, Papua New Guinea</P>
+<P ALIGN="JUSTIFY">J.K. Camoens, Asian Development Bank, P.O. Box 789, Manila 2800, Philippines</P>
+<P ALIGN="JUSTIFY">H. de Carville, Station de Recherches Avicoles, I.N.R.A., Centre de Tours, Nouzilly 37380, Monnaie, France</P>
+<P ALIGN="JUSTIFY">F.D. Chesterley, 4502 Loomis Trail, Blaine, Washington 98230, USA</P>
+<P ALIGN="JUSTIFY">X. Colonna C., 14 Cotham Road, Bristol BS6 6DR, UK</P>
+<P ALIGN="JUSTIFY">N.I. Dim, Animal Science Department, Faculty of Agriculture, Ahmadu Bello University, P.M.B. 1044, Zaria, Nigeria</P>
+<P ALIGN="JUSTIFY">R. Dumont, Ecole Nationale SupTrieure des Sciences Agronomiques AppliquTes, 26, boulevard Docteur Petitjean 21100 Dijon, France</P>
+<P ALIGN="JUSTIFY">G.R. Gerona, Department of Animal Science and Veterinary Medicine, Visayas State College of Agriculture, Baybay, Leyte, Philippines</P>
+<P ALIGN="JUSTIFY">Barry Glofcheskie, Department of Environmental Biology, University of Guelph, Guelph, Ontario NIG 2WI, Canada (fly control)</P>
+<P ALIGN="JUSTIFY">D. Holderread' P.O. Box 492, Corvallis, Oregon 97339, USA</P>
+<P ALIGN="JUSTIFY">W.F. Hollander, Route 4, Box 168, Ames, Iowa 50010, USA</P>
+<P ALIGN="JUSTIFY">E. Hoffmann, Canning, Nova Scotia BOP IH0, Canada</P>
+<P ALIGN="JUSTIFY">C.H. Huang, Food and Fertilizer Technology Center for the Asian and Pacific Region, Fifth Floor, 14 Wenchow Street, Taipei, Taiwan (mule duck)</P>
+<P ALIGN="JUSTIFY">G.A.R. Kamar, Animal Production Department, Faculty of Agriculture, Cairo University, Giza, Egypt</P>
+<P ALIGN="JUSTIFY">W. Michie, Poultry Husbandry Division, North of Scotland College of Agriculture, Parkhead, Craibstone, Bucksburn, Aberdeen AB2 9SX, Scotland, UK</P>
+<P ALIGN="JUSTIFY">Donald E. Mock, Department of Extension Entomology, 239 Waters Hall, Kansas State University, Manhattan, Kansas 66506-4004, USA (fly control)</P>
+<P ALIGN="JUSTIFY">P. Mongin, Station de Recherches Avicoles, I.N.R.A., Nouzilly 37380 Monnaie, France</P>
+<P ALIGN="JUSTIFY">S. Ochetim, School of Agriculture, University of the South Pacific, Alafua Campus, Apia, Western Samoa</P>
+<P ALIGN="JUSTIFY">H. Pingel, Karl Marx Universitat, Sektion TV, Lehrstuhl Geflugel- und Pelztierzucht, 7010 Leipzig, Stephanstrasse 12, Germany</P>
+<P ALIGN="JUSTIFY">B. Retailleau, Grimaud FrFres S.A., La CorbiFre, 494S0 Roussay, France</P>
+<P ALIGN="JUSTIFY">I. Romboli, Le Quericole, Universita Delgi Studi di Pisa 56010 S. Piero A Grado, Italy</P>
+<P ALIGN="JUSTIFY">T.S. Sandhu, Cornell University Duck Research Laboratory, P.O. Box 217, Eastport, New York 11941, USA</P>
+<P ALIGN="JUSTIFY">G.A. Surgeoner, Department of Environmental Biology, University of Guelph, Guelph, Ontario NIG 2WI, Canada (fly control)</P>
+<P ALIGN="JUSTIFY">C. Tai, Taiwan Livestock Research Institute, 112 Farm Road Shin-hua. Tainan, Taiwan 71210</P>
+<P ALIGN="JUSTIFY">R.T. Wilson, Bartridge House, Umberleigh, North Devon EX37 9AS, UK</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Pigeon</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">A.O. Aduku, Department of Animal Science, Faculty of Agriculture, Ahmadu Bello University, P.M.B. 1044, Zaria, Nigeria</P>
+<P ALIGN="JUSTIFY">D.O. Alonge, Meat Hygiene and Preservation Laboratory, Faculty of Veterinary Medicine, University of Ibadan, Ibadan, Nigeria</P>
+<P ALIGN="JUSTIFY">J.K. Camoens, Asian Development Bank, P.O. Box 789, Manila 2800, Philippines</P>
+<P ALIGN="JUSTIFY">K.M. Cheng, Avian Genetics Laboratory, Department of Animal Science, University of British Columbia, Vancouver, British Columbia V6T 2A2, Canada</P>
+<P ALIGN="JUSTIFY">R. Dillinger, 3201 Huffman Boulevard, Rockford, Illinois 61103, USA</P>
+<P ALIGN="JUSTIFY">N.I. Dim, Animal Science Department, FacultyofAgriculture, AhmaduBello University, P.M.B. 1044, Zaria, Nigeria</P>
+<P ALIGN="JUSTIFY">R.O. Hawes, Department of Animal and Veterinary Sciences, University of Maine, Orono, Maine 04469, U.S.A.</P>
+<P ALIGN="JUSTIFY">D. Holderread, P.O. Box 492, Corvallis, Oregon 97339, USA (carrier pigeons) </P>
+<P ALIGN="JUSTIFY">W.F. Hollander, Route 4, Box 168, Ames, lowa 5001O, USA</P>
+<P ALIGN="JUSTIFY">M.A. Latif, Department of Poultry Science, Bangladesh Agricultural University, Mymensingh, Bangladesh</P>
+<P ALIGN="JUSTIFY">Y. Le HTnaff, Laboratoire de l'H(pital Avranches, Avranches, Cotentin, France (carrier pigeons)</P>
+<P ALIGN="JUSTIFY">S.D. Lukefahr, International Small Livestock Research Center, Department of Food Science and Animal Industries, Alabama A&amp;M University, P.O. Box 264, Normal, Alabama 35762, USA</P>
+<P ALIGN="JUSTIFY">G.A.R. Kamar, Animal Production Department, Faculty of Agriculture, Cairo University, Giza, Egypt</P>
+<P ALIGN="JUSTIFY">W.J. Miller, Department of Genetics, Iowa State University, Ames, Iowa 50011, USA</P>
+<P ALIGN="JUSTIFY">G. Owen, 6520 Wiscasset Road, Bethesda, Maryland 20816, USA</P>
+<P ALIGN="JUSTIFY">G. Pena PTrez, Apartado Postal 23, La Nucia, Alicante, Spain</P>
+<P ALIGN="JUSTIFY">E. Ross, Department of Animal Science, University of Hawaii, Honolulu, Hawaii 96822, USA</P>
+<P ALIGN="JUSTIFY">M.D. Roush, Green Valley Squab Farm, 1348 Green Valley Road, Folsom, California 9563O, USA</P>
+<P ALIGN="JUSTIFY">T.S. Sandbu, Cornell University Duck Research Laboratory, P.O. Box 217, Eastport, New York 11941, USA</P>
+<P ALIGN="JUSTIFY">J.S. Sim, Department of Animal Science, University of Alberta, Edmonton, Alberta TOG 2P5, Canada</P>
+<P ALIGN="JUSTIFY">R.T. Wilson, Bartridge House, Umberleigh, North Devon EX37 9AS, UK</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Quail</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">Many people raise Japanese quail. Probably the best way to locate a local source is to consult local pet stores, the county farm advisor's office, university faculty of agriculture, game-bird fanciers, and the like. Finding people with local research experience is usually most useful to beginners. Coturnix International, Inc., is a nonprofit organization with primary interests in promoting small domesticated food animal production for both youth training and improved nutrition. The use of coturnix (Japanese quail) for these purposes is already well established in a number of Michigan schools and in the Dominican Republic, with special emphasis on science projects, especially where nutritional inadequacies exist. The address is Coturnix International Inc., International Headquarters, 1111 Michigan Avenue, Box 250O, East Lansing, Michigan 48823, USA. Avian Sciences Department, University of California, Davis, California 95616, USA </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">J.K. Camoens, Asian Development Bank, P.O. Box 789, Manila 2800, Philippines </P>
+<P ALIGN="JUSTIFY">K.M. Cheng, Avian Genetics Laboratory, Department of Animal Science, University of British Columbia, Vancouver, British Columbia V6T 2A2, Canada</P>
+<P ALIGN="JUSTIFY">D.E. Deppner, Trees for the Future, 11306 Estona Drive, Silver Spring, Maryland 20902, USA</P>
+<P ALIGN="JUSTIFY">D. Holderread, P.O. Box 492, Corvallis, Oregon 97339, USA</P>
+<P ALIGN="JUSTIFY">S.D. Lukefahr, International Small Livestock Research Center, Department of Food</P>
+<P ALIGN="JUSTIFY">Science and Animal Industries, Alabama AOcM University, P.O. Box 264, Normal, Alabama 35762, USA</P>
+<P ALIGN="JUSTIFY">H.L. Marks, Genetics Unit, Room 107 Livestock-Poultry Building, University of Georgia, Athens, Georgia 30602, USA</P>
+<P ALIGN="JUSTIFY">A. Marsh, Marsh Farms, 7171 Patterson Drive, Garden Grove, California 92641, USA</P>
+<P ALIGN="JUSTIFY">H. Martoyo, Faculty of Animal Science, Institut Pertanian Bogor, Jalan Raya Pajajaran, Bogor, West Java, Indonesia</P>
+<P ALIGN="JUSTIFY">Z. Abidin bin Mohd Noor, Department of Veterinary Services, Jalan Sultan Salahuddin, 50630 Kuala Lumpur, Malaysia (chicken-quail hybrids)</P>
+<P ALIGN="JUSTIFY">P.K. Pani, Indian Veterinary Research Institute, Izatnagar 243 122, Bareilly, Uttar Pradesh, India</P>
+<P ALIGN="JUSTIFY">H. Pingel, Karl Marx Universitat, Sektion TV, Lehrstuhl Geflugel- und Pelztierzucht, 7010 Leipzig, Stephanstrasse 12, Germany</P>
+<P ALIGN="JUSTIFY">D. Polin, Department of Animal Science, Michigan State University, East Lansing, Michigan 48824, USA</P>
+<P ALIGN="JUSTIFY">C.V. Reddy, Faculty of Veterinary Science, Andhra Pradesh Agricultural University, Rajendranagar, Hyderabad 500 030, India</P>
+<P ALIGN="JUSTIFY">Rodale Research Center, RD #1, Box 323, Kutztown, Pennsylvania 19530, USA</P>
+<P ALIGN="JUSTIFY">E. Ross, Department of Animal Science, University of Hawaii, Honolulu, Hawaii 96822, USA</P>
+<P ALIGN="JUSTIFY">B.K. Shingari, Department of Animal Science, Punjab Agricultural University, Ludhiana 141 006, India</P>
+<P ALIGN="JUSTIFY">R.G. Somes, Nutritional Sciences, Box U-17, University of Connecticut, Storrs, Connecticut 06268, USA</P>
+<P ALIGN="JUSTIFY">R. Tempest, Heifer Project International, P.O. Box 808, Little Rock, Arkansas 72203, USA</P>
+<P ALIGN="JUSTIFY">S. K. Varghese, Department of Animal Science, Michigan State University, East Lansing, Michigan 48824-1225, USA</P>
+<P ALIGN="JUSTIFY">N. Wakasugi, Laboratory of Animal Genetics, Nagoya University, Furo-cho, Chikusaku, Nagoya, Japan</P>
+<P ALIGN="JUSTIFY">H.R. Wilson, Poultry Science Department, Archer Road, University of Florida, Gainesville, Florida 32611, USA</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Turkey</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">M. Berruecos V. Muz, Facultad de Medicina Veterinaria y Zootecnia, Ciudad Universitaria, Mexico D.F., Mexico</P>
+<P ALIGN="JUSTIFY">R.D. Crawford, Department of Animaland Poultry Science, UniversityofSaskatchewan, Saskatoon, Canada</P>
+<P ALIGN="JUSTIFY">M. Cuca G., Institucion de Ensenanza e Investigacion en Ciencias Agricolas, Colegio de Postgraduados, Chapingo, Mexico</P>
+<P ALIGN="JUSTIFY">K.E. Nestor, Ohio Agricultural Research and Development Center, Ohio State University, Wooster, Ohio</P>
+<P ALIGN="JUSTIFY">H. Pingel, Karl-Marx-Universitat, Sektion TV, Lehrstuhl Geflugel- und Pelztierzucht, 7010 Leipzig, Stephanstrasse 12, Germany</P>
+<P ALIGN="JUSTIFY">M.L. Scott, 16 Spruce Lane, Ithaca, New York 14850, USA</P>
+<P ALIGN="JUSTIFY">H.J. Sexton, Agricultural Research Service, U.S. Department of Agriculture, Beltsville Agricultural Research Center, Building 262, Beltsville, Maryland 20705, USA</P>
+<P ALIGN="JUSTIFY">R.G. Somes, Nutritional Sciences. Box U-17, University of Connecticut, Storrs, Connecticut 06268, USA</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Potential New Poultry</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">J.E. Duckett, P.O. Box 12378, 50776 Kuala Lumpur, Malaysia (barn owls)</P>
+<P ALIGN="JUSTIFY">W.R. Marion, Department of Wildlife and Range Science, University of Florida, Gainesville, Florida 32611, USA (chachalaca)</P>
+<P ALIGN="JUSTIFY">C. Smal, Wildlife Service, Sidmonton Place, Bray County, Wicklow, Ireland (barn owls) </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">RABBITS</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Domestic Rabbit</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">A.O. Aduku, Department of Animal Science, Faculty of Agriculture, Ahmadu Bello University,  P.M.B. 1044, Zaria, Nigeria</P>
+<P ALIGN="JUSTIFY">J. Baranga, Department of Zoology, Makerere University, P.O. Box 7062, Kampala, Uganda</P>
+<P ALIGN="JUSTIFY">M. Baselga, Departamento de Ciencia Animal, Escuela TTcnica Superior de Ingenieros  Agronomos, Camino de Vera 14, 46022 Valencia, Spain</P>
+<P ALIGN="JUSTIFY">C. de Blas, Departamento Alimentacion Animal, Escuela TTcnica Superior de Ingenieros  Agronomos, Ciudad Universitaria, 28040 Madrid, Spain</P>
+<P ALIGN="JUSTIFY">J.A. Castell6, Real Escuela Oficial y Superior de Avicultura (REOSA), Calle Plana Parafso, s/n  Arenys de Mar, Barcelona, Spain</P>
+<P ALIGN="JUSTIFY">C.B. Chawan, International Small Livestock Research Center, Department of Food Science and  Animal Industries, Alabama A&amp;M University, P.O. Box 264, Normal, Alabama 35762, USA</P>
+<P ALIGN="JUSTIFY">P.R. Cheeke, Rabbit Research Center, Department of Animal Science, Oregon State University,  Corvallis, Oregon 97331, USA</P>
+<P ALIGN="JUSTIFY">S. Fekete, University of Veterinary Science, Department of Animal Nutrition, Budapest, Pf.2,  H-1400 Hungary</P>
+<P ALIGN="JUSTIFY">J. Fernandez C., Departamento de Ciencia Animal, Escuela TTcnica Superior de Ingenieros  Agronomos, Universidad PolitTcnica de Valencia, Camino de Vera, 14, 46022 Valencia, Spain</P>
+<P ALIGN="JUSTIFY">C. Cervera Fras, Departamento de Ciencia Animal, Universidad PolitTcnica de Valencia, Apartado  22012, Valencia, Spain</P>
+<P ALIGN="JUSTIFY">D.J. Harris, Pel-Freez Rabbit Meat, Inc., P.O. Box 68, Rogers, Arkansas 72756, USA</P>
+<P ALIGN="JUSTIFY">J.A.B. Hundleby, Ciskei Agricultural Corporation Ltd., P.O. Box 59, Bisho, Ciskei, South Africa</P>
+<P ALIGN="JUSTIFY">D.L. Huss, P.O. Box 426, Menard, Texas 76859, USA</P>
+<P ALIGN="JUSTIFY">R. de Jong, Department of Tropical Animal Production, Marykeweg 40, 6709 P.G. Wageningen,  The Netherlands</P>
+<P ALIGN="JUSTIFY">L.A. Kamwanja, Bunda College of Agriculture, University of Malawi, P.O. Box 219, Lilongwe,  Malawi</P>
+<P ALIGN="JUSTIFY">M. Leyun, Instituto TTcnico Gesti6n Porcino (ITGP), Seccion Conejos, Ctra. del Sadar, s/n 31006  Pamplona (Navarra), Spain</P>
+<P ALIGN="JUSTIFY">H. Loliger, Lisztstrasse 20, 3100 Celle, Germany</P>
+<P ALIGN="JUSTIFY">S.D. Lukefahr, International Small Livestock Research Center, Department of Food Science and  Animal Industries, Alabama A&amp;M University, P.O. Box 264, Normal, Alabama 35762, USA</P>
+<P ALIGN="JUSTIFY">T.P.E. Makhambera, Bunda College of Agriculture, University of Malawi, P.O. Box 219, Lilongwe,  Malawi</P>
+<P ALIGN="JUSTIFY">J.I. McNitt, Center for Small Farm Research, Southern University, P.O. Box 11170, Baton Rouge,  Louisana 70813-1170, USA</P>
+<P ALIGN="JUSTIFY">M. Mgheni, Sokoine University of Agriculture, Animal Science and Production Department, P.O.  Box 3004, Morogoro, Tanzania</P>
+<P ALIGN="JUSTIFY">K. Mitchell, Baptist Bible Institute, P.O. Box 301, Basseterre, St. Kitts, West Indies</P>
+<P ALIGN="JUSTIFY">G.A. Norman, Tropical Products Institute, Culham, Abingdon, Oxfordshire OX14 3DA, UK</P>
+<P ALIGN="JUSTIFY">L.N. Odonker, P.O. Box 11, Tsito-Awudome, Volta Region, Ghana</P>
+<P ALIGN="JUSTIFY">O.C. Onwudike, Department of Animal Science, University of Ife, Ile-Ife, Nigeria  </P>
+<P ALIGN="JUSTIFY">G.G. Partridge, Rowett Research Institute, Bucksburn, Aberdeen AB2 9SB, Scotland, UK</P>
+<P ALIGN="JUSTIFY">N.M. Patton, Rabbit Research Center, Oregon State University, Corvallis, Oregon 97331, USA</P>
+<P ALIGN="JUSTIFY">M.J. Paya, Departamento de Microbiologia, Facultad de Veterinaria, Avenida Puerta de Hierro, Ciudad Universitaria, 28040 Madrid, Spain</P>
+<P ALIGN="JUSTIFY">T. PTrez, Departamento de Reproduccion Animal, Instituto Nacional de Investigaciones Agrarias (INIA), Avenida Puerta de Hierro, s/n, 28040 Madrid, Spain</P>
+<P ALIGN="JUSTIFY">H.L. Polley, Programme DTveloppement Plateau Bateke, CBZO, B.P. 4728, Kinshasa 2, Zaire</P>
+<P ALIGN="JUSTIFY">R. Ramchurn, School of Agriculture, University of Mauritius, RTduit, Mauritius</P>
+<P ALIGN="JUSTIFY">T.E. Reed, Box 98, Markle, Indiana 46770, USA</P>
+<P ALIGN="JUSTIFY">E. Respaldiza, Instituto Nacional de Investigaciones Agrarias (INIA), Departamento de Higiene y Sanidad Animal, Calle Embajadores, 68, 28012 Madrid, Spain</P>
+<P ALIGN="JUSTIFY">B. Retailleau, Grimaud FrFres S.A., La CorbiFre, 49450 Roussay, France</P>
+<P ALIGN="JUSTIFY">A. Rodriguez, Departamento Microbiologia e Inmunologia, Facultad de Veterinaria, Calle Miguel Servet, numero 117, 50013 Zaragoza, Spain</P>
+<P ALIGN="JUSTIFY">R. Rodriguez de L., "Conejos" Centro de Investigacion Cientifica del Estado de MTxico A.C., Camino a Huexotla No. 5, San Miguel Coatlinchan, 56170 Texcoco, Estado de MTxico, Mexico</P>
+<P ALIGN="JUSTIFY">W. Schlolaut, Hessen Institute for Animal Production, Neu-Ulrichstein, 6313 Homberg, West Germany</P>
+<P ALIGN="JUSTIFY">W.D. Semuguruka, Department of Veterinary Pathology, Faculty of Veterinary Medicine, Sokoine University of Agriculture, P.O. Box 3018, Chuo Kikuu Morogoro, Tanzania</P>
+<P ALIGN="JUSTIFY">I. Sierra, Departamento Produccion Animal, Facultad de Veterinaria, Calle Miguel Servet, numero 117, 50013 Zaragoza, Spain</P>
+<P ALIGN="JUSTIFY">R. Valls, Institut de Recerce i Tecnologia Agroalimentaria (IRTA), Torre Marimon, 08140 Caldes de Montbui, Barcelona, Spain</P>
+<P ALIGN="JUSTIFY">P. Zaragoza, Departamento de Genetica y Mejora, Facultad de Veterinaria, Calle Miguel Servet, numero 117, 50013 Zaragoza, Spain</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">RODENTS</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Agouti</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">C.J.R. Alho, Departamento de Biologia Animal, Universidade de Brasilia, 70910 Brazilia, DF, Brazil</P>
+<P ALIGN="JUSTIFY">R.H. Baker, 302 North Strickland Street, Eagle Lake, Texas 77434-1841, USA</P>
+<P ALIGN="JUSTIFY">H. Bonilla Encizo, ICA Tibaitata, Apartado Aereo 151123, BogotG, Colombia</P>
+<P ALIGN="JUSTIFY">A.D. Cuaron O., Instituto de Historia Natural, Apartado Postal No. 6, Tuxtla Gutierrez, Chiapas 29000, Mexico</P>
+<P ALIGN="JUSTIFY">L.A. Deutsch, Parque Zoologico de Sao Paulo, SGo Paulo, Brazil</P>
+<P ALIGN="JUSTIFY">G. Dubost, Laboratorie d'Ecologie, 4 avenue Petit ChGteau, 91800 Brunoy, France</P>
+<P ALIGN="JUSTIFY">J.K. Frenkel, Department of Pathology, University of Kansas Medical Center, Kansas City, Kansas 66013, USA</P>
+<P ALIGN="JUSTIFY">A. Escajadillo, Gorgas Memorial Laboratory, P.O. Box 935, APO Miami, Florida 340020012, USA OR Avenida Justo Arosemena 34-30, Apartado 6991, Panama 5, Panama</P>
+<P ALIGN="JUSTIFY">W. Hallwachs, Department of Biology, University of Pennsylvania, Philadelphia, Pennsylvania 19104-6018, USA </P>
+<P ALIGN="JUSTIFY">G. Hislop, Wildlife Section, Forest Division, Ministry of Food Production, Port-ofSpain, Trinidad and Tobago</P>
+<P ALIGN="JUSTIFY">S. Ingrand, I.N.R.A., Campus agronomique, B.P. 709, 97387 Kourou Cedex, French Guiana</P>
+<P ALIGN="JUSTIFY">D.H. Janzen, Department of Biology, University of Pennsylvania, Philadelphia, Pennsylvania 19104, USA</P>
+<P ALIGN="JUSTIFY">D. Kleiman, National Zoological Park, Washington, D.C. 20008, USA</P>
+<P ALIGN="JUSTIFY">A. Lavorenti, Animal Sciences Department, ESALQ Universidade de Sao Paulo, C.P. 9, Piracicaba, Sao Paulo 13.400, Brazil</P>
+<P ALIGN="JUSTIFY">D.A. Meritt, Jr., 2200 North Cannon Drive, Chicago, IHinois 60614, USA</P>
+<P ALIGN="JUSTIFY">J.R. de Alencar Moreira, EMBRAPA-CPATU, Agricultural Research Center of the Humid Tropics, Caixa Postal 48, BelTm, Para 66000, Brazil</P>
+<P ALIGN="JUSTIFY">C.Ma. Rojas G., CATIE, 7170 Turrialba, Costa Rica</P>
+<P ALIGN="JUSTIFY">G. Santos, Fundatao Parque Zoologico de Sao Paulo, Sao Paulo, Brazil</P>
+<P ALIGN="JUSTIFY">N. Smith, Department of Geography, University of Florida, Gainesville, Florida 32611, USA</P>
+<P ALIGN="JUSTIFY">N. Smythe, Smithsonian Tropical Research Institute, Box 2072, Balboa, Panama</P>
+<P ALIGN="JUSTIFY">O. Sousa, Department of Microbiology, Cinuad Universitaria "Dr Octavio MTndez Pereira," El Cangregio, Apartado Estafeta Universitaria, Panama City, Panama</P>
+<P ALIGN="JUSTIFY">A.B. Taber, Animal Behaviour Research Group, Department of Zoology, South Parks Road, Oxford OXI 3PS, UK</P>
+<P ALIGN="JUSTIFY">E. Wing, Florida State Museum, University of Florida, Gainesville, Florida 32611, USA</P>
+<P ALIGN="JUSTIFY">C.A. Woods, Florida State Museum, University of Florida, Gainesville, Florida 32611, USA</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Capybara</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">C.J.R. Alho, Departamento de Biologia Animal, Universidade de Brasilia, 70910 Brasilia, DF, Brazil</P>
+<P ALIGN="JUSTIFY">K.P. Bland, Department of Veterinary Physiology, Royal (Dick) School of Veterinary Studies, Summerhall, Edinburgh EH9 IQH, Scotland, UK</P>
+<P ALIGN="JUSTIFY">H. Bonilla Encizo, ICA Tibaitata, Apartado Aereo 151123, Bogota, Colombia</P>
+<P ALIGN="JUSTIFY">P.R. Cheeke, Rabbit Research Center, Department of Animal Science, Oregon State University, Corvallis, Oregon 97331, USA</P>
+<P ALIGN="JUSTIFY">T.J. Cunha, P.O. Box R, LaVerne, California 91750, USA</P>
+<P ALIGN="JUSTIFY">J.F. Eisenberg, Florida State Museum, University of Florida, Gainesville, Florida 32611, USA</P>
+<P ALIGN="JUSTIFY">F. Golley, Institute of Ecology, University of Georgia, Athens, Georgia 30601, USA</P>
+<P ALIGN="JUSTIFY">E. Gonzalez-Jimenez, Facultad de Agronomia, Universidad Central de Venezuela, Maracay, Venezuela</P>
+<P ALIGN="JUSTIFY">H. Hemmer, Institute of Zoology, Johannes Gutenberg University, Anemonenweg 18, D-6500 Mainz-Ebersheim, Germany</P>
+<P ALIGN="JUSTIFY">J.A. Howarth, School of Veterinary Medicine, University of California, Davis, California 95616, USA</P>
+<P ALIGN="JUSTIFY">S. Ingrand, I.N.R.A., Campus agronomique, B.P. 709, 97387 Kourou Cedex, French Guiana</P>
+<P ALIGN="JUSTIFY">N. Konnerup, 74 North Sunrise Boulevard, Camano Island, Washington 98292, USA</P>
+<P ALIGN="JUSTIFY">J.E. Jackson, Terraza Turrado 80, 5730 Villa Mercedes, San Luis, Argentina</P>
+<P ALIGN="JUSTIFY">D. Kleiman, National Zoological Park, Washington, D.C. 20008, USA</P>
+<P ALIGN="JUSTIFY">A. Lavorenti, Animal Sciences Department, ESALQ Universidade de Sao Paulo, C.P. 9, Piracicaba, Sao Paulo 13.400, Brazil </P>
+<P ALIGN="JUSTIFY">R.D. Lord, Biology Department, Indiana University of Pennsylvania, Indiana, Pennsylvania 15705, USA</P>
+<P ALIGN="JUSTIFY">D.W. MacDonald, Animal Behaviour Research Group, Department of Zoology, South Parks Road, Oxford OXI 3PS, UK</P>
+<P ALIGN="JUSTIFY">J.R. de Alencare Moreira, Agricultural Research Center of the Humid Tropics, EMBRAPA-CPATU, Caixa Postal 48" BelTm, Para 66000, Brazil</P>
+<P ALIGN="JUSTIFY">B. Muller-Haye, Food and Agricultural Organization of the United Nations, Room F524, Via delle Terme di Caracalla, 00100 Rome, Italy</P>
+<P ALIGN="JUSTIFY">J. Ojasti, Institute of Tropical Zoology, Apartado 47058, Universidad Central de Venezuela, Caracas 1041A, Venezuela</P>
+<P ALIGN="JUSTIFY">N.L. Rondon, Departamento de Engenharia Florestal, Centro de Ciencias Agrarias, Universidada Federal de Mato Grosso, Cuiaba-MT, 78000, Brazil</P>
+<P ALIGN="JUSTIFY">N. Smith, Department of Geography, University of Florida, Gainesville, Florida 32611, USA</P>
+<P ALIGN="JUSTIFY">A.E. Sollod, Section of International Veterinary Medicine, Tufts University, 200 Westboro Road, North Grafton, Massachusetts 01536, USA</P>
+<P ALIGN="JUSTIFY">F. Sunquist, Route 1, Box 1434, Melrose, Florida 32666, USA</P>
+<P ALIGN="JUSTIFY">A.B. Taber, Animal Behaviour Research Group, Department of Zoology, South Parks Road, Oxford OXI 3PS, UK</P>
+<P ALIGN="JUSTIFY">K.D. Thelen, FAO Regional Of fice for Latin America and the Caribbean, CasiHa 10095, Santiago, Chile</P>
+<P ALIGN="JUSTIFY">D. Wharton, New York Zoological Society, Bronx, New York 10460, USA</P>
+<P ALIGN="JUSTIFY">E. Wing, Florida State Museum, University of Florida, Gainesville, Florida 32611, USA</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Coypu</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">A.C. Carmichael, The Museum, Michigan State University, East Lansing, Michigan 48824-1045, USA</P>
+<P ALIGN="JUSTIFY">G. Chapman, Utah State University, Logan, Utah 84322, USA</P>
+<P ALIGN="JUSTIFY">L. Contreras, Universidad Cat61ica de Valpariso, Avenida Brasi. 295O, Casilla 4059, Valparaiso, Chile</P>
+<P ALIGN="JUSTIFY">D. Huss, P.O. Box 426, Menard, Texas 76859, USA</P>
+<P ALIGN="JUSTIFY">H.-G. Klos, Zoologischer Garten Berlin, Aktiengesellschaft, Hardenbergplatz, 1000 Berlin 30, Germany</P>
+<P ALIGN="JUSTIFY">P. Lutz, Rosenstiel School of Marine and Atmospheric Science, Biology and Living Resources, University of Miami, 4600 Rickenbacker Causeway, Miami, Florida 33149, USA</P>
+<P ALIGN="JUSTIFY">J.R. de Alencar Moreira, Agricultural Research Center of the Humid Tropics, Caixa Postal 48, BelTm, ParG, 66000, Brazil</P>
+<P ALIGN="JUSTIFY">J. Szumiec, Experimental Fish Culture Station, Polish Academy of Sciences, Golysz 43-422 Chybie, Poland</P>
+<P ALIGN="JUSTIFY">C.A. Woods, Florida State Museum, University of Florida, Gainesville, Florida 32611, USA</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Giant Rat</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Animal Research Institute, Council for Scientific and Industrial Research (CSIR), P.O. Box 20, Achimota, Chana</P>
+<P ALIGN="JUSTIFY">J. Baranga, Department of Zoology, Makerere University, P.O. Box 7062, Kampala, Uganda </P>
+<P ALIGN="JUSTIFY">K.P. Bland, Department of Veterinary Physiology, Royal (Dick) School of Veterinary Studies, Summerhall, Edinburgh EH9 IQH, Scotland, UK</P>
+<P ALIGN="JUSTIFY">P. Brinck, Ecology Building, Department of Animal Ecology, University of Lund, S223 62 Lund, Sweden</P>
+<P ALIGN="JUSTIFY">G. Dubost, Laboratorie d'Ecologie, 4 avenue Petit ChGteau, 91800 Brunoy, France</P>
+<P ALIGN="JUSTIFY">D. Fielding, Centre for Tropical Veterinary Medicine, Royal (Dick) School of Veterinary Studies, University of Edinburgh, Easter Bush, Roslin, Midlothian EH25 9RG, Scotland, UK</P>
+<P ALIGN="JUSTIFY">D.C.D. Happold, Department of Zoology, Australian National University, Canberra, Australian Capital Territory 2601, Australia</P>
+<P ALIGN="JUSTIFY">J.C. Heymans, BP 1910, Cotonou, Benin</P>
+<P ALIGN="JUSTIFY">J.A. Kamara, c/o Njala University College, Private Mail Bag, Freetown, Sierra Leone</P>
+<P ALIGN="JUSTIFY">M.H. Knight, Kalahari Gemsbok Park, Private Bag X5890, Upington 8800, South Africa</P>
+<P ALIGN="JUSTIFY">M. Malekani, DTpartement de Biologie, FacultT des Sciences, UniversitT de Kinshasa, B.P. 190, Kinshasa XI, Zaire</P>
+<P ALIGN="JUSTIFY">R.W. Matthewman, Centre for Tropical Veterinary Medicine, Royal (Dick) School for Veterinary Studies, University of Edinburgh, Easter Bush, Roslin, Midlothian EH25 9RG, Scotland, UK</P>
+<P ALIGN="JUSTIFY">A.J. Smith, Centre for Tropical Veterinary Medicine, Royal (Dick) School of Veterinary Studies, University of Edinburgh, Easter Bush, Roslin, Midlothian EH25 9RG, Scotland, UK</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Grasscutter</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">A. Alexander, Department of Biology, Natal University, King George V Avenue, Durban 4001, South Africa</P>
+<P ALIGN="JUSTIFY">E.O.A. Asibey, Department of Game and Wildlife, Ministry Post Office, Accra, Ghana</P>
+<P ALIGN="JUSTIFY">E.S. Ayensu, African Development Bank, 01 B.P. No. 1837, Abidjan 01, Ivory Coast</P>
+<P ALIGN="JUSTIFY">R. Baptist, Institute for Animal Production in the Tropics and Subtropics, University of Hohenheim (480), P.O. Box 700562, D-7000 Stuttgart 70, Germany</P>
+<P ALIGN="JUSTIFY">S.Y. Bimpong-Buta, Council for Law Reporting, P.O. Box M165, Accra, Ghana</P>
+<P ALIGN="JUSTIFY">P. Brinck, Department of Animal Ecology, University of Lund, Ecology Building, S223 62, Lund, Sweden</P>
+<P ALIGN="JUSTIFY">H. Dosso, Institut d'Ecologie Tropicale, Abidjan, Ivory Coast</P>
+<P ALIGN="JUSTIFY">D. Fielding, Centre for Tropical Veterinary Medicine, Royal (Dick) School of Veterinary Studies, University of Edinburgh, Easter Bush, Roslin, Midlothian EH25 9RG, Scotland, UK</P>
+<P ALIGN="JUSTIFY">D.C.D. Happold, Department of Zoology, Australian National University, Canberra, Australian Capital Territory 2601, Australia</P>
+<P ALIGN="JUSTIFY">J. Hardouin, Institut de Medicine Tropicale "Prince Leopold," Nationalestraat 155, B2000 Antwerp, Belgium</P>
+<P ALIGN="JUSTIFY">J.C. Heymans, BP 1910, Cotonou, Benin</P>
+<P ALIGN="JUSTIFY">A. Hutton, Garaina Farms, Scrubby Creek Road, Gympie MS:115, Queensland 4570, Australia</P>
+<P ALIGN="JUSTIFY">J.A. Kamara, c/o Njala University College, Private Mail Bag, Freetown, Sierra Leone</P>
+<P ALIGN="JUSTIFY">Laboratoire Centrale de Nutrition Animale (LACENA), B.P. 353, Abidjan 06, Ivory Coast</P>
+<P ALIGN="JUSTIFY">S.D. Lukefahr, International Small Livestock Research Center, Department of Food Science and Animal Industries, Alabama A&amp;M University, P.O. Box 264, Normal, Alabama 35762, USA</P>
+<P ALIGN="JUSTIFY">R.-P. Mack, Projet BTnino-Allemand Conseiller Technique auprTs du MDRAC, BP 504, Cotonou, Benin </P>
+<P ALIGN="JUSTIFY">G.H.G. Martin, Department of Zoology, Kenyatta University College, P.O. Box 43844, Nairobi, Kenya</P>
+<P ALIGN="JUSTIFY">R.W. Matthewman, Centre for Tropical Veterinary Medicine, Royal (Dick) School of Veterinary Studies, University of Edinburgh, Easter Bush, Roslin, Midlothian EH25 9RG, Scotland, UK</P>
+<P ALIGN="JUSTIFY">G.A. Mensah, Responsable PBAA (Projet BTnino-Allemand d'Aulacodiculture), P.B. 2359, Cotonou, Benin</P>
+<P ALIGN="JUSTIFY">T.A. Omole, Department of Animal Science, University of Ife, Ile-lfe, Nigeria</P>
+<P ALIGN="JUSTIFY">K.J. Peters, International Livestock Centre for Africa (ILCA), P.O. Box 5689, Addis Ababa, Ethiopia</P>
+<P ALIGN="JUSTIFY">F. Petter, MammifFres et Oiseaux, Museum National d'Histoire Naturelle Zoologie, 55 rue de Buffon 75005, Paris, France</P>
+<P ALIGN="JUSTIFY">W. Schr(der, Institute of Animal Breeding, Albrecht-Thaer-Weg 1, 3400 Gottingen, Germany</P>
+<P ALIGN="JUSTIFY">A.J. Smith, Centre for Tropical Veterinary Medicine, Royal (Dick) School of Veterinary Studies, University of Edinburgh, Easter Bush, Roslin, Midlothian EH25 9RG, Scotland, UK</P>
+<P ALIGN="JUSTIFY">D.W. Thomas, Department of Biology, University of Sherbrooke, Sherbrooke, Quebec JIK 2RI, Canada</P>
+<P ALIGN="JUSTIFY">St. von Korn, Institute of Animal Breeding, Albrecht-Thaer-Weg 1, 3400 G(ttingen, Germany</P>
+<P ALIGN="JUSTIFY">J. Walder, Presbyterian Rural Training Centre, P.O. Box 72, Bamenda, NW Province, Cameroon</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Guinea Pig</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">G.P. Bilong, Department of Pimary Industry, Monogastric Research Centre, P.O. Box 73, Lae, Papua New Guinea</P>
+<P ALIGN="JUSTIFY">K.P. Bland, Department of Physiology, Royal (Dick) School of Veterinary Studies, Summerhall, Edinburgh EH9 IQH, Scotland, UK</P>
+<P ALIGN="JUSTIFY">R. Bolton, Department of Anthropology, Pomona College, Claremont, California 91711, USA</P>
+<P ALIGN="JUSTIFY">H. Bonilla Encizo, ICA Tibaitata, Apartado Aereo 151123, Bogota, Colombia</P>
+<P ALIGN="JUSTIFY">J.K. Camoens, Asian Development Bank, P.O. Box 789, Manila 2800, Philippines</P>
+<P ALIGN="JUSTIFY">A. Del Carpio R., Facultad de Zootecnia, Universidad Nacional "Pedro Ruiz Gallo," Calle Atahualpa No. 179, Apartado 48, Lambayeque, Peru</P>
+<P ALIGN="JUSTIFY">P.R. Cheeke, Rabbit Research Center, Department of Animal Science, Oregon State University, Corvallis, Oregon 97331, USA</P>
+<P ALIGN="JUSTIFY">T.J. Cunha, P.O. Box R, LaVerne, California 91750, USA</P>
+<P ALIGN="JUSTIFY">J. Descailleux, Laboratorio GenTtica Humana, C.P. 11010, Lima 14, Peru</P>
+<P ALIGN="JUSTIFY">J.A. Ferguson, Overseas Development Administration, Eland House, Stug Place, London, UK</P>
+<P ALIGN="JUSTIFY">D. Fielding, Centre for Tropical Veterinary Medicine, Royal (Dick) School of Veterinary Studies, University of Edinburgh, Easter Bush, Roslin, Midlothian EH25 9RC, Scotland, UK</P>
+<P ALIGN="JUSTIFY">J.K. Frenkel, Department of Pathology, University of Kansas Medical Center, Kansas City, Kansas 66013, USA</P>
+<P ALIGN="JUSTIFY">J. Hardouin, Institut de MTdecine Tropicale "Prince Leopold," Nationalestraat IS5, B2000 Antwerpen, Belgium</P>
+<P ALIGN="JUSTIFY">R.E. Honegger, Zurich Zoo, Zurichbergstrasse 221, CH-8044 Zurich, Switzerland </P>
+<P ALIGN="JUSTIFY">J. Howarth, School of Veterinary Medicine, University of Calffornia, Davis, Calffornia 95616, USA</P>
+<P ALIGN="JUSTIFY">D.L. Huss, P.O. Box 426, Menard, Texas 76859, USA</P>
+<P ALIGN="JUSTIFY">J.E. Jackson, Terraza Turrado 80, 5730 Villa Mercedes, San Luis, Argentina</P>
+<P ALIGN="JUSTIFY">C. Jenkins, PNG Institute Medical Research, P.O. Box 60, Goroka, Eastern Highlands Province, Papua New Guinea</P>
+<P ALIGN="JUSTIFY">R. de Jong, Department of Tropical Animal Production, Marykeweg 40, 6709 PG Wageningen, The Netherlands</P>
+<P ALIGN="JUSTIFY">J.A. Kamara, c/o Njala University College, Private Mail Bag Freetown, Sierra Leone</P>
+<P ALIGN="JUSTIFY">P.J. Kohun, Department of Agriculture, PNG University of Technology, Lae, Papua New Guinea</P>
+<P ALIGN="JUSTIFY">N.M. Konnerup, 74 North Sunrise Boulevard, Camano Island, Washington 98292, USA</P>
+<P ALIGN="JUSTIFY">T.E. Lacher, Jr., Huxley College of Environmental Studies, Western Washington University, Bellingham, Washington 98225, USA</P>
+<P ALIGN="JUSTIFY">S.D. Lukefahr, International Small Livestock Research Center, Department of Feed Science and Animal Industries, Alabama A&amp;M University, P.O. Box 264, Normal, Alabama 35762, USA</P>
+<P ALIGN="JUSTIFY">R.C. Malik, Department of Agriculture, PNG University of Technology, Lae, Papua New Guinea</P>
+<P ALIGN="JUSTIFY">R.W. Matthewman, Centre for Tropical Veterinary Medicine, Royal (Dick) School of Veterinary Studies, University of Edinburgh, Easter Bush, Roslin, Midlothian EH25 9RG, Scotland, UK</P>
+<P ALIGN="JUSTIFY">A.R. Moreno, Departamento de Produccion Animal, Universidad Nacional Agraria, Apartado 456, La Molina, Lima, Peru</P>
+<P ALIGN="JUSTIFY">B. Muller-Haye, Food and Agriculture Organization of the United Nations, Room F524, Via delle Terme di Caracalla, 00100 Rome, Italy</P>
+<P ALIGN="JUSTIFY">H.L. Polley, Programme DTveloppement Plateau Bateke, CBZO, B.P. 4728, Kinshasa 2, Zaire</P>
+<P ALIGN="JUSTIFY">V. Purizaga A., Alcalde del Concejo Provincial de Pacasmayo, Dos de Mayo 360, Peru</P>
+<P ALIGN="JUSTIFY">V.T. Quirante, Bureau of Animal Industry, Research Center, Alabang 3124, Metro Manila, Philippines</P>
+<P ALIGN="JUSTIFY">C.V. Reddy, Faculty of Veterinary Science, Andhra Pradesh Agricultural University, Rajendranagar, Hyderabad 500 030, India</P>
+<P ALIGN="JUSTIFY">O.W. Robinson, Department of Animal Science, North Carolina State University, Box 7621 Raleigh, North Carolina 27695-7621, USA</P>
+<P ALIGN="JUSTIFY">A.J. Smith, Centre for Tropical Veterinary Medicine, Royal (Dick) School of Veterinary Studies, University of Edinburgh, Easter Bush, Roslin, Midlothian EH25 9RG, Scotland, UK</P>
+<P ALIGN="JUSTIFY">D. Wharton, New York Zoological Society, Bronx, New York 10460, USA</P>
+<P ALIGN="JUSTIFY">E. Wing, Florida State Museum, University of Florida, Gainesville, Florida 32611, USA</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Hutia</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">A.C. Allen, Hope Zoo, Kingston, Jamacia</P>
+<P ALIGN="JUSTIFY">R.S. Canet, Instituto de Zoologla, Academia Ciencias de Cuba, Calle 214, esq. a Avenida 19, No. 17A 09, Reparto Atabey, Havana 16, Cuba</P>
+<P ALIGN="JUSTIFY">D. Kleiman, National Zoological Park, Washington, D.C. 20008, USA</P>
+<P ALIGN="JUSTIFY">K. Jordan, Department of Zoology, University of Florida, Gainesville, Florida 32611, USA </P>
+<P ALIGN="JUSTIFY">W.L.R. Oliver, Jersey Wildlife Preservation Trust, Les AugrFs Manor, Jersey, Channel Islands, UK</P>
+<P ALIGN="JUSTIFY">J.A. Ottenwalder, Parque Zool6gico Nacional (ZOODOM), Apartado 2449, Santo Domingo, Dominican Republic</P>
+<P ALIGN="JUSTIFY">E. Wing, Florida State Museum, University of Florida, Gainesville, Florida 32611, USA</P>
+<P ALIGN="JUSTIFY">C. Woods, Florida State Museum, University of Florida, Gainesville, Florida 32611, USA</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Mara</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">L.T. Blankenship, Animal Resources Center, School of Medicine, East Carolina University, Greenville, North Carolina 27858-4354, USA</P>
+<P ALIGN="JUSTIFY">G. Dubost, Laboratoire d'Ecologie, 4 avenue Petit ChGteau, 91800 Brunoy, France</P>
+<P ALIGN="JUSTIFY">J.E. Jackson, Terraza Turrado 80, 5730 Villa Mercedes, San Luis, Agentina</P>
+<P ALIGN="JUSTIFY">D. Kleiman, National Zoological Park, Washington, D.C. 20008, USA</P>
+<P ALIGN="JUSTIFY">D.W. MacDonald, Animal Behaviour Research Group, Department of Zoology, South Parks Road, Oxford OXI 3PS, UK</P>
+<P ALIGN="JUSTIFY">W.H. Pryor, Jr., School of Medicine, East Carolina University, Greenville, North Carolina 27858-4354, USA</P>
+<P ALIGN="JUSTIFY">A.B. Taber, Animal Behaviour Research Group, Department of Zoology, South Parks Road, Oxford OXI 3PS, UK</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Paca</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">J.R. de Alencar Moreira, Agricultural Research Center of the Humid Tropics, EMBRAPA-CPATU, Caixa Postal 48, BelTm, Para 66000, Brazil</P>
+<P ALIGN="JUSTIFY">C.J.R. Alho, Departamento de Biologia Animal, Universidade de Brasilia, 70910 Brasilia, DF, Brazil</P>
+<P ALIGN="JUSTIFY">R.H. Baker, 302 North Strickland Street, Eagle Lake, Texas 77434-1841, USA</P>
+<P ALIGN="JUSTIFY">A.D. Cuardn O., Instituto de Historia Natural, Apartado Postal No. 6, Tuxtla Gutierrez, Chiapas 29000, Mexico</P>
+<P ALIGN="JUSTIFY">G. Dubost, Laboratoire d'Ecologie, 4 avenue Petit ChGteau, 91800 Brunoy, France</P>
+<P ALIGN="JUSTIFY">L. de Escalante, Zool6gico Nacional, Direccion del Patrimonio Natural y Cultural, San Salvador, El Salvador</P>
+<P ALIGN="JUSTIFY">J.K. Frenkel, Department of Pathology, University of Kansas Medical Center, Kansas City, Kansas 66013, USA</P>
+<P ALIGN="JUSTIFY">W. Hallwachs, Ecology and Systematics, Corson Hall, Cornell University, Ithaca, New York 14853, USA</P>
+<P ALIGN="JUSTIFY">C. Hislop, Wildlife Section, Forest Division, Ministry of Food Production, Port-ofSpain, Trinidad and Tobago</P>
+<P ALIGN="JUSTIFY">D.H. Janzen, Department of Biology, University of Pennsylvania, Philadelphia, Pennsylvania 19104, USA</P>
+<P ALIGN="JUSTIFY">D. Kleiman, National Zoological Park, Washington, D.C. 20008, USA</P>
+<P ALIGN="JUSTIFY">A. Lavorenti, Animal Sciences Department, ESALQ Universidade de Sao Paulo, C.P. 9, Piracicaba, Sao Paulo 13.400, Brazil</P>
+<P ALIGN="JUSTIFY">Y. Matamoros, Escuela de Medicina Veterinaria, Universidad Nacional, Apartado 86, Heredia, Costa Rica</P>
+<P ALIGN="JUSTIFY">D. Meritt, Jr., 2200 North Cannon Drive, Chicago, Illinois 60614, USA</P>
+<P ALIGN="JUSTIFY">C.Ma. Rojas G., CATIE, 7170 Turrialba, Costa Rica </P>
+<P ALIGN="JUSTIFY">O. Rosado, Ministry of Industry and Natural Resources, Belmopan, Belize</P>
+<P ALIGN="JUSTIFY">N. Smith, Department of Geography, University of Florida, Gainesville, Florida 32611, USA</P>
+<P ALIGN="JUSTIFY">N. Smythe, Smithsonian Tropical Research Institute, Box 2072, Balboa, Panama</P>
+<P ALIGN="JUSTIFY">V. Solis, Union Internacional pare la Conservacion de la Naturaleza y de los Recursos Naturales, Oficina Regional pare Centro AmTrica, Apartado Postal 91-1009-FECOSA, San JosT, Costa Rica</P>
+<P ALIGN="JUSTIFY">S. VaidTs, Centro Universitario del Norte Carrera ZootTcnica, Coban, A.V., Ciudad Guatemala 16001, Guatemala</P>
+<P ALIGN="JUSTIFY">E. Wing, Florida State Museum, University of Florida, Gainesville, Florida 32611, USA</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Vizcacha</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">H. Bonilla Encizo, ICA Tibaitata, Apartado Aereo 151123, Bogota, Colombia</P>
+<P ALIGN="JUSTIFY">J.E. Jackson, Terraza Turrado 80, 5730 Villa Mercedes, San Luis, Argentina</P>
+<P ALIGN="JUSTIFY">E.L. Marmillon, Estancias del Conlara S.A., Casilla de Correo 451, 5800 Rio Cuarto, Argentina</P>
+<P ALIGN="JUSTIFY">K.D. Thelen, FAO Regional Office for Latin America and the Caribbean, Casilla 10095, Santiago, Chile</P>
+<P ALIGN="JUSTIFY">E. Wing, Florida State Museum, University of Florida, Gainesville, Florida 32611, USA</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Other Rodents</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">T.M. Butynski, Impenetrable Forest Conservation Project, Zoology Department, Makerere University, P.O. Box 7062, Kampala, Uganda (springhare)</P>
+<P ALIGN="JUSTIFY">T. Flannery, Australian Museum, 6-8 College Street, Sydney, New South Wales 2000, Australia (Solomon Island rodents)</P>
+<P ALIGN="JUSTIFY">Inter-African Bureau for Animal Resources, Maendeleo House, Monrovia Street, POB 30786, Nairobi, Kenya (springhare)</P>
+<P ALIGN="JUSTIFY">N. Jacobsen, Nature Conservation Division, Private Bag X209, Pretoria 0001, South Africa (springhare)</P>
+<P ALIGN="JUSTIFY">C.P. Kofron, Museum of Zoology, Louisiana State University, Baton Rouge, Louisiana 70893, USA (springhare)</P>
+<P ALIGN="JUSTIFY">T. Leary, Ministry of Natural Resources, Honiara, Solomon Islands (Solomon Island rodents)</P>
+<P ALIGN="JUSTIFY">C.A. McLaughlin, San Diego Zoo, San Diego 92112, California, USA (springhare)</P>
+<P ALIGN="JUSTIFY">R.P. Millar, Department of Chemical Pathology, Medical School, Observatory 7925, South Africa (springhare)</P>
+<P ALIGN="JUSTIFY">J.D. Skinner, Mammal Research Institute, University of Pretoria, Pretoria 0002, South Africa (springhare)</P>
+<P ALIGN="JUSTIFY">Southern African Wildlife Management Association, POB 413, Pretoria, South Africa ( s p ring hare )</P>
+<P ALIGN="JUSTIFY">L. Talbot, 6656 Chitton Court, McLean, Virginia 22101, USA (springhare)</P>
+<P ALIGN="JUSTIFY">M. Van der Merwe, University of Pretoria, Mammal Research Institute, Pretoria 0002, South Africa (springhare)</P>
+<P ALIGN="JUSTIFY">Wildlife Society of Zimbabwe, POB 3497, Harare, Zimbabwe (springhare) </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">DEER AND ANTELOPE</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Mouse Deer</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">J.O. Caldecott, World Wildlife Fund Malaysia, 7 Jalan Ridgeway, 93200 Kuching, Sarawak, Malaysia</P>
+<P ALIGN="JUSTIFY">R. Chaplin, Burnhouse, Fountainhall, Galashiels, Selkirk TDI 2RX, UK</P>
+<P ALIGN="JUSTIFY">G.W.H. Davison, Zoology Department, Universiti Kebangsaan Malaysia, 43600 Bangi, Selangor, Malaysia</P>
+<P ALIGN="JUSTIFY">G. Dubost, Laboratoire d'Ecologie GTnTrale, 4 avenue Petit ChGteau, 91800 Brunoy, France</P>
+<P ALIGN="JUSTIFY">P. Grubb, 35 Downhills Park Road, London N17 6PE, UK</P>
+<P ALIGN="JUSTIFY">Liu Ruiqing, Kunming Institute of Zoology, Academia Sinica, Kunming, Yunnan Province, People's Republic of China</P>
+<P ALIGN="JUSTIFY">M. MacNamara, Fauna Research, Inc., 11 Park Avenue, Ardsley, New York 10502, USA</P>
+<P ALIGN="JUSTIFY">I. Muul, Integrated Conservation Research, P.O. Box 920, Harpers Ferry, West Virginia 25425, USA</P>
+<P ALIGN="JUSTIFY">M. Nordin, Bureau of Research and Consultancy, University Kebangsaan Malaysia, Bangi, Selangor, Malaysia</P>
+<P ALIGN="JUSTIFY">S. Pathak, Department of Genetics, M.D. Anderson Hospital and Tumor Institute, Houston, Texas 77030, USA</P>
+<P ALIGN="JUSTIFY">C.T. Robbins, Wildlife Biology Program, Washington State University, Pullman, Washington 99164-4220, USA</P>
+<P ALIGN="JUSTIFY">K. Robin, Tierpark Dahlholzli Bern, Dalmaziquai 149, CH-3005 Bern, Switzerland</P>
+<P ALIGN="JUSTIFY">C.R. Schmidt, Zoological Garden, CH-8044 Zurich, Switzerland</P>
+<P ALIGN="JUSTIFY">R.A. Sirimanne, Singapore Zooological Gardens, 80 Mandai Lake Road, Singapore 2572</P>
+<P ALIGN="JUSTIFY">L. Talbot, 6656 Chilton Court, McLean, Virginia 22101, USA</P>
+<P ALIGN="JUSTIFY">M.K. Vidyadaran, Faculty of Veterinary Science, Department of Animal Science, Universiti Pertanian Malaysia, Serdang 43400, Selangor, Malaysia</P>
+<P ALIGN="JUSTIFY">Wang Yingxiang, Kunming Institute of Zoology, Academia Sinica, Kunming, Yunan Province, People's Republic of China</P>
+<P ALIGN="JUSTIFY">D. Wharton, New York Zoological Society, Bronx, New York 10460, USA</P>
+<P ALIGN="JUSTIFY">G.C. Whittow, Department of Physiology, John A. Burns School of Medicine, University of Hawaii, 1960 East West Road, Honolulu, Hawaii 96822, USA</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Muntjac</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">C. Barrette, DTpartement de Biologie, FacultT des Sciences et de GTnie, UniversitT Laval, QuTbec, GIK 7P4, Canada</P>
+<P ALIGN="JUSTIFY">K. Benirschke, 8457 Prestwick Drive, La Jolla, California 92037, USA</P>
+<P ALIGN="JUSTIFY">The British Deer Society, Church Farm, Lower Basildon, Reading, Berkshire RG8 9NH, UK</P>
+<P ALIGN="JUSTIFY">J.O. Caldecott, World Wildlife Fund Malaysia, 7 Jalan Ridgeway, 933200 Kuching, Sarawak, Malaysia</P>
+<P ALIGN="JUSTIFY">N. Chapman, Larkmead, Barton Mills, Bury St. Edmunds, Suffolk IP28 6AA, UK</P>
+<P ALIGN="JUSTIFY">M. Coe, Department of Zoology, University of Oxford, South Parks Road, Oxford OXI 3PS, UK </P>
+<P ALIGN="JUSTIFY">O. Dansie, The Chapel, 2 Hobbs Hall, Welwyn, Hertsfordshire, UK</P>
+<P ALIGN="JUSTIFY">S.K. Dhungal, Department of Parks and Wildlffe, P.O. Box 860, Kathmandu, Nepal</P>
+<P ALIGN="JUSTIFY">C. Dubost, Laboratoire d'Ecologie GTnTrale, 4 avenue Petit ChGteau, 91800 Brunoy, France</P>
+<P ALIGN="JUSTIFY">R.J. Goss, Division of Biology and Medicine, Brown University, Providence, Rhode Island 02912, USA</P>
+<P ALIGN="JUSTIFY">C.P. Groves, Department of Prehistory and Anthropology, Australian National University, P.O. Box 4, Canberra, Australian Capital Territory 2600, Australia</P>
+<P ALIGN="JUSTIFY">P. Grubb, 35 Downhills Park Road, London N17 6PE, UK</P>
+<P ALIGN="JUSTIFY">S.P. Harding, Animal Ecology Research Group, Zoology Department, South Parks Road, Oxford OX1 3PS, UK</P>
+<P ALIGN="JUSTIFY">S. Harris, Department of Zoology, University of Bristol, Woodland Road, Bristol BS8 JUG, UK</P>
+<P ALIGN="JUSTIFY">H. Heck, CatskiH Game Farm, Inc., RD #1, Box 133, Catskill, New York 12414, USA</P>
+<P ALIGN="JUSTIFY">H.A. Jacobson, Fish and Wildlffe Department, Mississippi State University, Mississippi State, Mississippi 39762, USA</P>
+<P ALIGN="JUSTIFY">Liu Ruiqing, Kunming Institute of Zoology, Academia Sinica, Kunming, Yunnan Province, People's Republic of China</P>
+<P ALIGN="JUSTIFY">Lu Houji, Department of Biology, East China Normal University, Shanghai 200062, People's Republic of China</P>
+<P ALIGN="JUSTIFY">M. MacNamara, Fauna Research, Inc., 11 Park Avenue, Ardsley, New York 10502, USA</P>
+<P ALIGN="JUSTIFY">V.J.A. Manton, Zoological Society of London, Whipsnade Park, Dunstable, Bedfordshire LU6 2LF, UK</P>
+<P ALIGN="JUSTIFY">S. Miura, Department of Biology, Hyogo College of Medicine, Mukogawa-cho 1-1, Nishinomiya, Hyogo-ken 663, Japan</P>
+<P ALIGN="JUSTIFY">I. Muul, Integrated Conservation Research, P.O. Box 920, Harpers Ferry, West Virginia 25425, USA</P>
+<P ALIGN="JUSTIFY">S. Pathak, Department of Genetics, M.D. Anderson Hospital and Tumor Institute, Houston, Texas 77030, USA</P>
+<P ALIGN="JUSTIFY">C.T. Robbins, Wildlife Biology Program, Washington State University, Pullman, Washington 99164, USA</P>
+<P ALIGN="JUSTIFY">B. Seidel, Tierpark Berlin, Tierklinik, DDR-1136 Berlin, Friedrichsfelde, Germany</P>
+<P ALIGN="JUSTIFY">Shi Liming, Kunming Institute of Zoology, Academia Sinica, Kunming, Yunnan Province, People's Republic of China</P>
+<P ALIGN="JUSTIFY">H. Soma, Department of Obstetrics and Gynecology, Tokyo Medical College Hospital, 1-7, Nishishinjuku 6, Shinjuku-ku, Tokyo 160, Japan</P>
+<P ALIGN="JUSTIFY">S. Stadler, Fakultat fur Biologie, Universitat Bielefeld, 4800 Bielefeld, Universitatsstrasse 25, Germany</P>
+<P ALIGN="JUSTIFY">L. Talbot, 6656 Chilton Court, McLean, Virginia 22101, USA</P>
+<P ALIGN="JUSTIFY">P.F. Taylor, Taylor Energy Company, The 2-3-4 Loyola Building, New Orleans, Louisiana 70112, USA</P>
+<P ALIGN="JUSTIFY">Wang Yingziang, Kunming Institute of Zoology, Academia Sinica, Kunming, Yunnan Province, People's Republic of China</P>
+<P ALIGN="JUSTIFY">C. Wemmer, Conservation and Research Center, National Zoological Park, Front Royal, Virginia 22630, USA</P>
+<P ALIGN="JUSTIFY">D. Wharton, New York Zoological Society, Bronx, New York 10460, USA</P>
+<P ALIGN="JUSTIFY">D.M. Wurster-HiH, Department of Pathology, Dartmouth Medical School, Hanover, New Hampshire 03755, USA</P>
+<P ALIGN="JUSTIFY">R.H. Yahner, 320 Forest Resources Laboratory, Pennsylvania State University, University Park, Pennsylvania 16802, USA </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Musk Deer</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">R. Chaplin, Burnhouse, Fountainhall, Galashiels, Selkirk TDI 2RX, UK</P>
+<P ALIGN="JUSTIFY">S.K. Dhungel, Department of Parks and Wildlife, P.O. Box 860, Kathmandu, Nepal</P>
+<P ALIGN="JUSTIFY">A.J. Gaston, Canadian Wildlife Service, Ottawa KIA OE7, Canada</P>
+<P ALIGN="JUSTIFY">C.P. Groves, Department of Prehistory and Anthropology, Australian National University, P.O. Box 4, Canberra, Australian Capital Territory 2600, Australia</P>
+<P ALIGN="JUSTIFY">M.J.B. Green, IUCN Conservation Monitoring Centre, 219C Huntingdon Road, Carnbridge CB3 ODL, UK</P>
+<P ALIGN="JUSTIFY">P. Grubb, 35 Downhills Park Road, London N17 6PE, UK</P>
+<P ALIGN="JUSTIFY">M.L. Hunter, Jr., Wildlife Department, University of Maine, Orono, Maine 04469, USA</P>
+<P ALIGN="JUSTIFY">H.A. Jacobson, Fish and Wildlife Department, Mississippi State University, Mississippi State, Mississippi 39762, USA</P>
+<P ALIGN="JUSTIFY">B. Kattel, P.O. Box 3070, Kathmandu, Nepal</P>
+<P ALIGN="JUSTIFY">Liu Riqing, Kunming Institute of Zoology, Academia Sinica, Kunming Yunnan Province, People's Republic of China</P>
+<P ALIGN="JUSTIFY">Lu Houji, Department of Biology, East China Normal University, Shanghai 200062, People's Republic of China</P>
+<P ALIGN="JUSTIFY">J. McNeely, Program and Policy Division, International Union for Conservation of Nature and Natural Resources, Avenue du Mont-Blanc, CH1196 Gland, Switzerland</P>
+<P ALIGN="JUSTIFY">B.W. O'Gara, Montana Cooperative Wildlife Research Unit, University of Montana, Missoula, Montana 59812, USA</P>
+<P ALIGN="JUSTIFY">C.T. Robbins, Wildlife Biology Program, Washington State University, Pullman, Washington 99164-4220, USA</P>
+<P ALIGN="JUSTIFY">B. Seidel, Tierpark Berlin, Tierklinik, DDR-1136 Berlin, Friedrichsfelde, Germany</P>
+<P ALIGN="JUSTIFY">Shi Liming, Kunming Institute of Zoology, Academia Sinica, Kunming, Yunnan Province, People's Republic of China</P>
+<P ALIGN="JUSTIFY">P.F. Taylor, Taylor Energy Co., The 2-3-4 Loyola Building, New Orleans, Louisiana 70112, USA</P>
+<P ALIGN="JUSTIFY">Wang Yingxiang, Kunming Institute of Zoology, Academia Sinica, Kunming, Yunnan Province, People's Republic of China</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Water Deer</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">A. Cooke, Nature Conservancy Council, Northminster House, Peterborough PEI I UA, UK</P>
+<P ALIGN="JUSTIFY">L. Farrell, Nature Conservancy Council, Northminster House, Peterborough PEI IUA, UK</P>
+<P ALIGN="JUSTIFY">F. Feer, Laboratoire d'Ecologie GTnTrale, 4 avenue Petit ChGteau, 91800 Brunoy, France</P>
+<P ALIGN="JUSTIFY">P. Crubb, 35 Downhills Park Road, London N17 6PE, UK</P>
+<P ALIGN="JUSTIFY">Liu Riuqing, Kunming Institute of Zoology, Academia Sinica. Kunming Yunnan Province, People's Republic of China</P>
+<P ALIGN="JUSTIFY">Lu Houji, Department of Biology, East China Normal University, Shanghai 200062, People's Republic of China</P>
+<P ALIGN="JUSTIFY">V.J.A. Manton, Zoological Society of London, Whipsnade Park, Dunstable, Bedfordshire LU6 2LF, UK</P>
+<P ALIGN="JUSTIFY">B. Seidel, Tierpark Berlin, Tierklinik DDR-1136, Berlin, Friedrichsfelde, Germany</P>
+<P ALIGN="JUSTIFY">R Smith, Department of Zoology, Whiteknights Park, University of Reading, Reading, Berkshire RG6 2AH, UK</P>
+<P ALIGN="JUSTIFY">S. Stadler, Fakultat fur Biologie, Universitat Bielefeld, 4800 Bielefeld, Universitats strasse 25, Germany</P>
+<P ALIGN="JUSTIFY">P.F. Taylor, Taylor Energy Company, The 2-3-4 Loyola Building, New Orleans, Louisiana 70112, USA</P>
+<P ALIGN="JUSTIFY">C. Wemmer, Conservation and Research Center, National Zoological Park, Front Royal, VA 2263O, USA</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">South American Microdeer</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">M. Sampath, Trinidad and Tobago Wildlffe Breeders and Farmers Association, c/o 5 3/4 Mile Mark, Penal Rock Road, Penal, Trinidad, West Indies (red brocket)</P>
+<P ALIGN="JUSTIFY">M. MacNamara, Fauna Research, Inc., 11 Park Avenue, Ardsley, New York 10502, USA (pudu)</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Duikers</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">J. Baranga, Department of Zoology, Makerere University, P.O. Box 7062, Kampala, Uganda</P>
+<P ALIGN="JUSTIFY">B. Chardonnet, Projet Petits Ruminants, B.P. 65, Atakpame, Togo</P>
+<P ALIGN="JUSTIFY">R.L. Cowan, 324 Henning Building, Pennsylvania State University, University Park, Pennsylvania 16802, USA</P>
+<P ALIGN="JUSTIFY">G. Dubost, Laboratoire d'Ecologie GTnTrale, 4 avenue Petit ChGteau, 91800 Brunoy, France</P>
+<P ALIGN="JUSTIFY">RI.M. Dunbar, Department of Zoology, University of Liverpool, P.O. Box 147, Liverpool L69 3BX, UK</P>
+<P ALIGN="JUSTIFY">F. Feer, Laboratoire d'Ecologie GTnTrale, 4 avenue Petit ChGteau, 91800 Brunoy, France</P>
+<P ALIGN="JUSTIFY">K.R. Kranz, Zoological Society of Philadelphia, 34th Street and Girard Avenue, Philadelphia, Pennsylvania 19104, USA</P>
+<P ALIGN="JUSTIFY">S. Lumpkin, Department of Zoological Research, National Zoological Park, Washington, D.C. 20008, USA</P>
+<P ALIGN="JUSTIFY">I. Player, Wilderness Leadership School, P.O. Box 15036, BeHair 4006, Natal, South Africa</P>
+<P ALIGN="JUSTIFY">K. Pond, Department of Animal Science, North Carolina State University, Box 7621, Raleigh, North Carolina 27695, USA</P>
+<P ALIGN="JUSTIFY">S. Schweers, Bahnhofstrasse 29, D-6744 Kandee, Germany</P>
+<P ALIGN="JUSTIFY">J.D. Skinner, Mammal Research Institute, University of Pretoria, Pretoria 0002, South Africa</P>
+<P ALIGN="JUSTIFY">A.E. SoHod, International Veterinary Medicine, Tufis University, 200 Westboro Road, North Grafion, Massachusetts 01536, USA</P>
+<P ALIGN="JUSTIFY">L. Talbot, 6656 Chilton Court, McLean, Virginia 22101, USA</P>
+<P ALIGN="JUSTIFY">C.C. Udell, 14934 VaHey Vista Blouvard, Sherman Oaks, Calffornia 91403, USA</P>
+<P ALIGN="JUSTIFY">G.A. Varga, Department of Dairy and Animal Science, 225B Borland Laboratory, Pennsylvania State University, University Park, Pennsylvania 16802, USA</P>
+<P ALIGN="JUSTIFY">V.J. Wilson, Duiker Research and Breeding Centre, Chipangali Wildlife Trust, P.O. Box 1057, Bulawayo, Zimbabwe </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Other Small Antelope</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">L. Asibey, Department of Game and Wildlife, Ministry Post Office, Accra, Ghana</P>
+<P ALIGN="JUSTIFY">J. Baranga, Department of Zoology, Makerere University, P.O. Box 7062, Kampala, Uganda</P>
+<P ALIGN="JUSTIFY">J.I. Boshe, College of African Wildlife Management, Mweka, P.O. Box 3031, Moshi, Tanzania (dikdik)</P>
+<P ALIGN="JUSTIFY">B. Chardonnet, Project Petits Ruminants, BP 65, Atakpame, Togo (oribi)</P>
+<P ALIGN="JUSTIFY">S.K. Dhungel, Department of National Parks and Wildife, Conservation, Babar Mahal, Kathmandu, Nepal (four-horned antelope)</P>
+<P ALIGN="JUSTIFY">R.I.M. Dunbar, Department of Zoology, University of Liverpool, P.O. Box 147, Liverpool L69 3BX, UK (dikdik, klipspringer)</P>
+<P ALIGN="JUSTIFY">F. Feer, Laboratoire d'Ecologie GTnTrale, 4 avenue Petit ChGteau, 91800 Brunoy, France</P>
+<P ALIGN="JUSTIFY">A.M. Goebel, Department of Biology, University of Texas at Arlington, Arlington, Texas 76019, USA</P>
+<P ALIGN="JUSTIFY">P.P. Hoppe, Am Hauenstein 13, 6706 Wachenheim, Germany (dikdik, suni)</P>
+<P ALIGN="JUSTIFY">K.R. Kranz, Zoological Society of Philadelphia, 34th Street and Girard Avenue, Philadelphia, Pennsylvania 19104, USA (royal antelope, beira, dikdik, klipspringer, suni, four-horned antelope)</P>
+<P ALIGN="JUSTIFY">I. Player, Wilderness Leadership School, P.O. Box 15036, Bellair 4006, Natal, South Africa</P>
+<P ALIGN="JUSTIFY">E.N.W. Oppong, UNDP/FGN/FAO Livestock Project, P.O. Box 6603, Jos, Plateau State, Nigeria</P>
+<P ALIGN="JUSTIFY">W.R. Pritchard, School of Veterinary Medicine, University of California, Davis, California 95616, USA</P>
+<P ALIGN="JUSTIFY">J. Skinner, Mammal Research Institute, University of Pretoria, Pretoria 0002, South Africa (otibi, steinbok)</P>
+<P ALIGN="JUSTIFY">A.E. Sollod, International Veterinary Medicine, Tufts University, 200 Westboro Road, North Grafton, Massachusetts 01536, USA (dikdik, klipspringer)</P>
+<P ALIGN="JUSTIFY">L. Talbot, 6656 Chilton Court, McLean, Virginia 22101, USA (dikdik, klipspringer, four-horned antelope)</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">LIZARDS</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Green Iguana</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">K. Benirschke, 8457 Prestwick Drive, La Jolla, California 92037, USA</P>
+<P ALIGN="JUSTIFY">G.M. Burghardt, Department of Psychology, University of Tennessee, Knoxville, Tennessee 37996, USA</P>
+<P ALIGN="JUSTIFY">A. Ferreira, Parque Zoologico Nacional, Apartado 2449, Santo Domingo, Dominican Republic</P>
+<P ALIGN="JUSTIFY">H.S. Fitch, Route #3, Box 142, Lawrence, Kansas 66044, USA</P>
+<P ALIGN="JUSTIFY">G. Hemley, World Wildlife Fund, 1255 23rd Street, N.W., Washington, D.C. 20037, USA (for trade information)</P>
+<P ALIGN="JUSTIFY">R.W. Henderson, Milwaukee Public Museum, 800 West Wells Street, Milwaukee, Wisconsin 53233 USA</P>
+<P ALIGN="JUSTIFY">J. Higginson, Voluntaria del Cuerpo de Paz, #156 6a Avenida 1-46, Zona 2 Guatemala, Guatemala</P>
+<P ALIGN="JUSTIFY">J.B. Iverson, Department of Biology, Earlham College, Richmond, Indiana 47374, USA S.R. Kellert, School of Forestry and Environmental Studies, Yale University, 205 Prospect Street, New Haven, Connecticut 06511, USA</P>
+<P ALIGN="JUSTIFY">F.W. King, Florida State Museum, University of Florida, Gainesville, Florida 32601, USA</P>
+<P ALIGN="JUSTIFY">G. Larde, Ministerio de Agricultura y Ganaderia Planes de Renderos, Km. 10 Col. Los Angeles 13, CP 01196 San Salvador, El Salvador</P>
+<P ALIGN="JUSTIFY">D. Marcellini, National Zoological Park, Washington, D.C. 20008, USA</P>
+<P ALIGN="JUSTIFY">J.M. Mora, 200 m sur Pulperia la Uni6n, Cinco Esquinas, Carrieal, Alajuela, Costa Rica</P>
+<P ALIGN="JUSTIFY">J.A. Ottenwalder, Parque Zool6gico Nacional, Apartado 2449, Santo Domingo, Dominican Republic</P>
+<P ALIGN="JUSTIFY">G.C. Packard, Department of Zoology, Colorado State University, Fort Collins, Colorado 80523, USA</P>
+<P ALIGN="JUSTIFY">J.J. Perez, Condominio Su. Antonio 7, C. San Antonio Abad, San Salvador, El Salvador</P>
+<P ALIGN="JUSTIFY">J. Phillips, Research Department, San Diego Zoo, Box 551, San Diego, Calffornia 92112, USA</P>
+<P ALIGN="JUSTIFY">D. Werner, Fundacion Pro Iguana Verde, Apa,-tado 1501-3000, Heredia, Costa Rica</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Black Iguana</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">H.S. Fitch, Route #3, Box 142, Lawrence, Kansas 66044, USA</P>
+<P ALIGN="JUSTIFY">R.W. Henderson, Milwaukee Public Museum, 800 West Wells Street, Milwaukee, Wisconsin 53233, USA</P>
+<P ALIGN="JUSTIFY">J. Higginson, Voluntaria del Cuerpo de Paz, #156 6a Avenida 1-46, Zona 2 Guatemala, Guatemala</P>
+<P ALIGN="JUSTIFY">D.M. Hillis, Department of Biology, University of Miami, Coral Gables, Florida 33124, USA</P>
+<P ALIGN="JUSTIFY">G. Larde, Ministerio de Agricultura y Ganaderia, Planes de Renderos Km. 10 Col. Los Angeles 13, CP 01196, San Salvador, El Salvador</P>
+<P ALIGN="JUSTIFY">D. Marcellini, National Zoologica, Park, Washington, D.C. 20008, USA</P>
+<P ALIGN="JUSTIFY">J.M. Mora, 200 m sur Pulperita La Union, Cinco Esquinas, Carrieal, Alajuela, Costa Rica</P>
+<P ALIGN="JUSTIFY">G.C. Packard, Department of Zoology, Colorado State University, Fort Collins, Colorado 80523, USA</P>
+<P ALIGN="JUSTIFY">J.J. Perez, Condominio Su. Antonio 7, C. San Antonio Abad, San Salvador, El Salvador</P>
+<P ALIGN="JUSTIFY">J. Phillips, Research Department, San Diego Zoo, Box 551, San Diego, Calffornia 92112, USA</P>
+<P ALIGN="JUSTIFY">D. Werner, Fundacion Pro Iguana Verde, Apartado 1501-3000, Heredia, Costa Rica</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Rock Iguana</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">W. Auffenberg, Florida State Museum, University of Florida, Gainesville, Florida 32611, USA</P>
+<P ALIGN="JUSTIFY">D. Auth, Florida State Museum, University of Florida, Gainesville, Florida 32611, USA</P>
+<P ALIGN="JUSTIFY">T.J. Cullen, Cullen Vivarium, 3401 South 16th Street, Milwaukee, Wisconsin 53215 USA</P>
+<P ALIGN="JUSTIFY">A. Ferreira, Parque Zool6gico Nacional, Apartado 2449, Santo Domingo, Dominican Republic </P>
+<P ALIGN="JUSTIFY">R.W. Henderson, Mi]waukee Public Museum, 800 West Wells Street, Milwaukee, Wisconsin 53233, USA</P>
+<P ALIGN="JUSTIFY">J.B. Iverson, Department of Biology, Earlham College, Richmond, Indiana 47374, USA</P>
+<P ALIGN="JUSTIFY">J.A. Ottenwalder, Parque Zool6gico Nacional, Apartado 2449, Santo Domingo, Dominican Republic</P>
+<P ALIGN="JUSTIFY">T.A. Wiewandt, Wild Horizons, Inc., P.O. Box 5118, Tucson, Arizona 85703, USA</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Tegu</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">C.A. Blanco, Direccion Nacional de Fauna Silvestre, Avenida Paseo Colon 922 2&Yacute;piso, (1063) Buenos Aires, Argentina</P>
+<P ALIGN="JUSTIFY">O.K. Donadio, Museo Argentino de Ciencias Naturales, CC 220, Avenida Angel Gallardo 470, Suc. 5, 1405 Buenos Aires, Argentina</P>
+<P ALIGN="JUSTIFY">J.M. Gallardo, Museo Argentino de Ciencias Naturales, CC 220, Avenida Angel Gallardo 470, Suc. 5, 1405 Buenos Aires, Argentina</P>
+<P ALIGN="JUSTIFY">G. Hemley, World Wildlife Fund, 1255 23rd Street, N.W., Washington, D.C. 20037, USA</P>
+<P ALIGN="JUSTIFY">D. Marcellini, National Zoological Park, Washington, D.C. 20008, USA</P>
+<P ALIGN="JUSTIFY">E.L. Marmillon, Casilla de Correo 451, 5800 Rio Cuarto, Argentina</P>
+<P ALIGN="JUSTIFY">G.C. Packard, Department of Zoology, Colorado State University, Fort Collins, Colorado 80523, USA</P>
+<P ALIGN="JUSTIFY">D. Werner, Fundacion Pro Iguana Verde, Apartado 1501-3000, Heredia, Costa Rica</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">BEES</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Local Agriculture Extension Services and beekeepers are often the best source of information for beginning beekeeping. In addition, the following organizations can provide information: International Bee Research Association, 16/18 North Road, Cardiff CF1 3DY, UK; International Agency for Apiculture Development, 6N 909 Roosevelt, St. Charles, Illinois 60174, USA</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">I. Abt, Centre for International Agricultural Development Cooperation, Tel Aviv, Israel M. Adey. International Bee Research Association, 16/18 North Road, Cardiff CFI 3DY, UK</P>
+<P ALIGN="JUSTIFY">S.O. Adjare, Technology Consultancy Centre, University of Science and Technology, Kumasi, Ghana</P>
+<P ALIGN="JUSTIFY">All India Beekeepers' Association, 817 Sadashiv Peth, Poono 411 030, India</P>
+<P ALIGN="JUSTIFY">S.K.N. Atuahene, Forest Product Research Institute (Ghana Forestry Commission), University P.O. Box 63, Kumasi, Ghana</P>
+<P ALIGN="JUSTIFY">H.S. Brar, Department of Entomology, Punjab Agricultural University, Ludhiana 141 004, India</P>
+<P ALIGN="JUSTIFY">N. Bradbear, International Bee Research Association, North Road, Cardiff CFI 3DY, UK</P>
+<P ALIGN="JUSTIFY">D.M. Caron, Department of Entomology and Applied Ecology, University of Delaware, Newark, Delaware 19717, USA</P>
+<P ALIGN="JUSTIFY">B.S. Chahal, Department of Entomology, Punjab Agricultural University, Ludhiana 141 004, India</P>
+<P ALIGN="JUSTIFY">B. Clauss, Beekeeping Survey, Kabompo, Zambia </P>
+<P ALIGN="JUSTIFY">M.P. Coleman, International Agency for Apiculture Development, 6N 909 Roosevelt, St. Charles, Illinois 60174, USA</P>
+<P ALIGN="JUSTIFY">Director, or Resident Bee Specialist, Apiary Studies, Zoological Institute, Leningrad, USSR</P>
+<P ALIGN="JUSTIFY">D. DeJong, Departamento de Genetica, Faculdade de Medicina de Ribeirao Preto, Universidade Sao Paulo, 14.049Ribeirao Preto, Sao Paulo, Brazil</P>
+<P ALIGN="JUSTIFY">R.W. Dutton, Centre for Overseas Research and Development (CORD), University of Durham, South Road, Durham DHI 3LE, UK (Apisflorea) </P>
+<P ALIGN="JUSTIFY">E.H. Erickson, Carl Hayden Bee Research Center, Agricultural Research Service, U.S. Department of Agriculture, 2000 East Allen Road, Tucson, Arizona 85719, USA</P>
+<P ALIGN="JUSTIFY">Faculdade de Medicina de Ribeirao Preto, Departamento de GenTtica, 14100Ribeirao Preto, Sao Paulo, Brazil</P>
+<P ALIGN="JUSTIFY">R.D. Fell, Virginia Polytechnic Institute, Blacksburg, Virginia 24061, USA</P>
+<P ALIGN="JUSTIFY">K. Flottum, Gleanings in Bee Culture, 623 West Liberty Street, P.O. Box 706, Medina, Ohio 44258-0706, USA (editor)</P>
+<P ALIGN="JUSTIFY">J. Free, Rothamstead Experimental Station, Harpenden, Hertfordshire L5 2JQ, UK</P>
+<P ALIGN="JUSTIFY">D. Wolde-Semait Gebre-Wold, P.O. Box 7505, Addis Ababa, Ethiopia</P>
+<P ALIGN="JUSTIFY">C.B. Habarugira, AHO (Apiary), Mbara Stockfarm, Beekeeping Section, P.O. Box 4, Mbarara, Uganda</P>
+<P ALIGN="JUSTIFY">L.A.M. Hassan, Njiro Wildlife (Beekeeping) Research Centre, P.O. Box 661, Arusha, Tanzania</P>
+<P ALIGN="JUSTIFY">R. Hoopingarner, Department of Entomology, University of Michigan, East Lansing, Michigan 48824-1115, USA</P>
+<P ALIGN="JUSTIFY">W.E. Kerr, Departamento de Biolgia, Universidade Federal de UberlGndia, 38400 UberlGndia, Brazil</P>
+<P ALIGN="JUSTIFY">P.G. Kevan, or Resident Bee Specialist, Department of Environmental Biology, University of Guelph, Guelph, Ontario NIG 2WI, Canada</P>
+<P ALIGN="JUSTIFY">K.K. Kigatiia, Beekeeping Branch, Ministry of Agriculture c~ Livestock Development, P.O. Box 30028, Nairobi, Kenya</P>
+<P ALIGN="JUSTIFY">H.C. Killins, 163 Trowbridge Avenue, London, Ontario N6J 3M2, Canada</P>
+<P ALIGN="JUSTIFY">H.M. Kiwuwa, AHL (Apiary), Department of Veterinary Services, Headquarters, Beekeeping Section, P.O. Box 7141, Kampala, Uganda</P>
+<P ALIGN="JUSTIFY">G. Lanarolle, Apiculture Project, Bindunuwewa, Bandarawela, Sri Lanka</P>
+<P ALIGN="JUSTIFY">Y. Lensky, Triwaks Bee Research Center, Hebrew University Faculty of Agriculture, Rehovot 76-100, Israel</P>
+<P ALIGN="JUSTIFY">M.D. Levin, Carl Hayden Bee Research Center, Agricultural Research Service, U.S. Department of Agriculture, 2000 East Allen Road, Tucson, Arizona 85719, USA</P>
+<P ALIGN="JUSTIFY">M. Singh Limbu, Godavari Ashram, GPO Box 50, Kathmandu, Nepal</P>
+<P ALIGN="JUSTIFY">I. Mann, 14 Millimani Road, Box 20360, Nairobi, Kenya</P>
+<P ALIGN="JUSTIFY">R.J. McGinley, Department of Entomology, NHB-105, Smithsonian Institution, Washington, D.C. 20560, USA (Apoidea, except Apis) </P>
+<P ALIGN="JUSTIFY">J. McKay, Peace Corps, American Embassy, Asunci6n, Paraguay</P>
+<P ALIGN="JUSTIFY">C.D. Michener, Snow Entomological Museum, University of Kansas, Lawrence, Kansas 66045, USA</P>
+<P ALIGN="JUSTIFY">R.A. Morse, Department of Entomology, Cornell University, Ithaca, New York 14853, USA</P>
+<P ALIGN="JUSTIFY">J. Morton, Morton Collectanea, University of Miami, Box 248204, Coral Gables, Florida 37724, USA (bee plants)</P>
+<P ALIGN="JUSTIFY">D.G. Mugisa, c/o Insure Consult, P.O. Box 30002, Nakiuubo, Uganda</P>
+<P ALIGN="JUSTIFY">M. Bin Muid, Department of Plant Protection, Faculty of Agriculture, Universiti Pertanian Malaysia, Serdang 43400, Selangor, Malaysia</P>
+<P ALIGN="JUSTIFY">H.C. Mulzac, International Agency for Apiculture Development, 393 Decatur Street, Brooklyn, New York 11233, USA </P>
+<P ALIGN="JUSTIFY">K.S. Najar, Faculty of Agriculture, University of Aleppo, Aleppo, Syria</P>
+<P ALIGN="JUSTIFY">B.E. Nightingale, Box 23, Njoro, Kenya</P>
+<P ALIGN="JUSTIFY">G. Patty, Foreign Agriculture Service, U.S. Department of Agriculture, 6095 South Building, Washington, D.C. 20250, USA</P>
+<P ALIGN="JUSTIFY">L.M. Phiri, Office of Chief Beekeeping Officer, P/BAC Mwekera, Kitwe, Zambia</P>
+<P ALIGN="JUSTIFY">R. Pickard, Zoology Department, University College, P.O. Box 78, Cardiff CFI IXL, South Wales, UK</P>
+<P ALIGN="JUSTIFY">G.W. Robins, GPO Box 50, Kathmandu, Nepal</P>
+<P ALIGN="JUSTIFY">D. Roubik, Stop 105, Museum of Natural History, Smithsonian Institution, Washington, D.C. 20560, USA (stingless bees)</P>
+<P ALIGN="JUSTIFY">D. Sammataro, 7011 Spieth Road, Medina, Ohio 44256, USA (editor, Cornucopia) </P>
+<P ALIGN="JUSTIFY">G. Schechtel, Cnel. Bogado/Itapua, Paraguay</P>
+<P ALIGN="JUSTIFY">H. Shimanuki, Beneficial Insects Laboratory, Agricultural Research Service, U.S. Department of Agriculture, B-476 BARC-East, Beltsville, Maryland 20705, USA</P>
+<P ALIGN="JUSTIFY">O.R. Taylor, Department of Entomology, University of Kansas, Lawrence, Kansas 66045, USA</P>
+<P ALIGN="JUSTIFY">J.E. Tew, Agricultural Technical Institute, Ohio State University, Wooster, Ohio 44691, USA</P>
+<P ALIGN="JUSTIFY">M. Tomasko, Pennsylvania State University, 106 Patterson Building, University Park7 Pennsylvania 16802, USA</P>
+<P ALIGN="JUSTIFY">P. Torchio, Agricultural Research Service, U.S. Department of Agriculture, Bee Laboratory, Utah State University, Logan, Utah 84322-5310, USA</P>
+<P ALIGN="JUSTIFY">R. Wadlow, 8381 San Mateo, Ft. Myers, Florida 33907, USA</P>
+<P ALIGN="JUSTIFY">D.W. Whitehead, International Agency for Apiculture Development, c/o 1000 Connecticut Avenue NW, #707, Washington, D.C. 20036, USA</P>
+<P ALIGN="JUSTIFY">Siriwat Wongsiri, Department of Biology, Chulalongkorn University, Bangkok7 Thailand (Apis cerana) </P>
+<P ALIGN="JUSTIFY">Wu Yan-ru, Department of Insect Taxonomy and Faunistics, Institute of Zoology, Academia Sinica, 7 Zhongguancun Lu, Haitien, Beijing, People's Republic of China </P>
+<P ALIGN="JUSTIFY"></P>
+<B><P>&lt;&lt;TOC3&gt;&gt; C BIOGRAPHICAL SKETCHES OF PANEL MEMBERS</P>
+</B><P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">RALPH W. PHILLIPS retired in 1982 from the post of deputy director general of the Food and Agriculture Organization of the United Nations (FAO), Rome, Italy, a post he held for four years. Among his earlier posts were that of professor and head, Animal Husbandry Department, Utah State University; senior animal husbandman in charge, Genetic Investigations, United States Department of Agriculture (USDA); chief, Animal Production Branch and deputy director, Agriculture Division, FAO; and executive director, International Organization Affairs, USDA. Among his special assignments were: serving as consultant on animal breeding to the governments of China and India for the U.S. Department of State in 1943-44; and as scientific secretary for agriculture of the United Nations Conference on Science and Technology for the Benefit of Developing Countries, in Ceneva, Switzerland, 1962-63. Dr. Phillips holds a B.S. degree in agriculture from Berea College (1930), M.A. (1931) and Ph.D. (1934) degrees from the University of Missouri, and Honorary D.Sc. degrees from Berea College and West Virginia University. He has been awarded the Berea College Distinguished Alumnus Award and the USDA's Distinguished Service Award. He is author or coauthor of some 240 scientific papers, review papers, chapters in books, and books on various aspects of physiology of reproduction, genetics, livestock production, and international agriculture. In his research, writings, and international activities, Dr. Phillips has given particular attention to breeding in relation to the environment and to the identification and conservation of valuable animal genetic resources. He is also the author of a definitive history of FAO entitled FAO: Its Origins, Formation and Evolution, 19451981 and an autobiography, The World Was My Barnyard. </P>
+<P ALIGN="JUSTIFY">EDWARD S. AYENSU is currently senior advisor to the president of the African Development Bank. He is also president of ESA Associates, Washington, D.C., and former director of the Office of Biological Conservation, Smithsonian Institution, Washington, D.C. A citizen of Ghana, he received his B.A. in 1961 from Miami University in Ohio, M.Sc. from The George Washington University in 1963, and his Ph.D. in 1966 from the University of London. His research interests cover many areas of tropical biology. An internationally recognized expert on topics relating to science, technology, and development, especially in developing countries, he has also published extensively on tropical plants. Dr. Ayensu chairs and serves as a member of many international bodies. </P>
+<P ALIGN="JUSTIFY">BONNIE V. BEAVER, professor of small animal medicine and surgery, Texas A&amp;M University, College Station, is a specialist in animal behavior and problem behaviors, especially in domestic and laboratory animals. She received her B.S. and D.V.M. from the University of Minnesota and her M.S. from Texas A&amp;M. In addition to being a popular speaker at scientific meetings, she is the author of five books and numerous book chapters and articles. </P>
+<P ALIGN="JUSTIFY">KURT BENIRSCHKE, professor of pathology and reproductive medicine, University of California at San Diego, received his M.D. from the University of Hamburg, Germany, in 1948. He served on the faculties of Harvard and Dartmouth medical schools before coming to San Diego in 1970. At the San Diego Zoo he initiated a research department to advance knowledge in endangered species and now serves as a trustee of that organization. He has written on comparative mammalian cytogenetics, vanishing species, and human reproductive pathology. </P>
+<P ALIGN="JUSTIFY">ROY D. CRAWFORD is professor of animal and poultry genetics at the University of Saskatchewan, Saskatoon, Saskatchewan, Canada. He received his B.S.A. from the University of Saskatchewan in 1955, his M.S. in animal genetics from Cornell University in 1957, and his Ph.D. in poultry genetics from the University of Massachusetts in 1963. He was employed as a scientist with the Research Branch of Agriculture Canada from 1957 to 1964 in Prince Edward Island and Nova Scotia. He joined the faculty of the University of Saskatchewan in 1964. He was made a fellow of the Agricultural Institute of Canada in 1986 in recognition of his teaching and research work. His research interests include single gene genetics of poultry, and conservation of genetic resources in poultry and livestock. He has discovered and studied many mutants in chickens; some of them have biomedical importance, including one shown to be an animal genetic model of human grand mal epilepsy; some of them are potentially useful in food production, including an albinism mutant that is being developed for autosexing of commercial chicken broilers. He maintains a very large conservation collection of poultry genetic resources at the University of Saskatchewan and has prepared an inventory and assessment of Canada's poultry and livestock genetic resources. Dr. Crawford is a member of the Expert Panel on Animal Genetic Resources Conservation and Management, FAO/UNEP, Rome, and is a member of the Animal Resources Committee, Canadian Council on Animal Care, Ottawa. He serves on the International Scientific Committee for the French journal GTnTtique, STlection, +volution. He is a member of the Rare Breeds Survival Trust (UK) and is a board member of the American Minor Breeds Conservancy (USA). </P>
+<P ALIGN="JUSTIFY">TONY J. CUNHA, distinguished service professor emeritus, University of Florida, Gainesville, and dean emeritus, California State Polytechnic University, Pomona, received his Ph.D. at the University of Wisconsin in 1944. He has given more than 100 lectures in livestock feeding and nutrition in 40 foreign countries. He served as chairman of the Animal Nutrition Committee of the National Academy of Sciences and as a member of the NAS-NRC Board of Agriculture and Renewable Resources, Latin American Science Board, and as chairman of the livestock committee of two world food studies by NAS-NRC. He served as a member of the organizing committee for the first two World Conferences on Animal Production in Rome (1963) and Washington, D.C. (1968). He served as a member of the Title XII Board of International Food and Agricultural Joint Committee on Research and as chairman of its research priorities committee 1977-1981. He is author, editor, coeditor, or contributor to 30 books and author of more than 1,423 scientific and professional articles. He is a winner of 42 campus, state, national, and international honors and awards. </P>
+<P ALIGN="JUSTIFY">DAVID E. DEPPNER, director of Trees for the Future in Silver Spring, Maryland, has been a consultant for international development projects involving livestock and poultry management and marketing for the past 14 years. He has served in 17 countries of Asia, Africa, and Central America. He has written on processing livestock rations under tropical conditions and about the Madurese breed of cattle found in East Java, Indonesia, where he spent two years studying this ancient breed. He is currently providing technical assistance to projects in several countries for the development of improved forage production as an answer to destruction of natural resources of tropical uplands caused by overgrazing. He received his B.Sc. in animal science from Ohio State University in 1954 and M.Sc. in livestock economics from Araneta University, the Philippines, in 1977. </P>
+<P ALIGN="JUSTIFY">ELIZABETH L. HENSON is the director of the American Minor Breeds Conservancy, based in Pittsboro, North Carolina. She received an M.A. in zoology from Oxford University in 1980 and an M.Sc. in domestic animal breeding from Edinburgh University in 1981. Her primary interests are in the conservation of rare and endangered breeds and varieties of domestic livestock as a genetic resource for changing agricultural needs. She represented Britain at the first international conference on domestic animal conservation in Hungary in 1982, and was a member of the Office of Technology Assessment Committee on grassroots strategies to maintain genetic diversity in 1985. She is executive secretary for four British breed associations and is a member of the British Rare Breeds Survival Trust Technical Panel. </P>
+<P ALIGN="JUSTIFY">DONALD L. HUSS was regional animal production officer of the FAO Regional Office for Latin America and the Caribbean, Santiago, Chile, before his retirement. He received a B.S. in 1949, an M.A. in 1954, and a Ph.D. in 1959, all at Texas A&amp;M University. He was assistant professor of range management at Texas A&amp;M before joining the Food and Agricultural Organization of the United Nations (FAO) in 1967. He founded the FAO Regional Office's Small Animals for Small Farms programme in 1980. Professional assignments and travels in Latin America, the Caribbean' Near and Middle East, and Africa have contributed to his knowledge and experience in microlivestock development. Dr. Huss was recognized by Texas A&amp;M University by being chosen as the recipient of the Memorial Student Center Appreciation and Distinguished Service Awards in 1958 and 196O, respectively, and Honour Professor in the College of Agriculture in 1966 67. He also received the Society for Range Management's Outstanding Service and Achievement Award in 1975 and its Fellow Award in 1978. </P>
+<P ALIGN="JUSTIFY">DAVID RICHARD LINCICOME has been a guest scientist with the Animal Parasitology Institute, United States Department of Agriculture Experiment Station, Beltsville, Maryland, since 1978, having retired as professor of parasitology, Howard University, Washington, D.C., in 1970. He received the B.S. and M.S. degrees cum laude simultaneously in 1937 from the University of Illinois and a Ph.D. in tropical medicine from the Tulane Medical School, New Orleans, Louisiana, in 1941. His principal research interests have centered around morphologic studies on Acanthocephala, molecular exchanges of dependent cells and their environments, and diagnosis of parasitic diseases. He has been a breeder of Nubian and American pygmy goats for the past 20 years. Dr. Lincicome is currently a member of the Board of Directors of the American Dairy Goat Association and is past president of the National Pygmy Goat Association. He was founder and long time trustee of the American Dairy Goat Association Research Foundation. He is also past president of the Helminthological Society and currently serves the society as archivist. He received the Helminthological Society's Anniversary Award in 1975. He was founder and, for 27 years, editor of the journal Experimental Parasitology, and is the author and editor of more than 180 scientific contributions. </P>
+<P ALIGN="JUSTIFY">THOMAS E. LOVEJOY is a tropical biologist and ornithologist. He is assistant secretary for external affairs, Smithsonian Institution' Washington, D.C. He was formerly executive vice president for the World Wildlife Fund-U.S., chairman of the Wildlife Preservation Trust International, and a member of two commissions of the International Union for the Conservation of Nature and Natural </P>
+<P ALIGN="JUSTIFY">Resources. At present, Dr. Lovejoy is a principal investigator of the world's largest controlled ecological experiment, which is attempting to determine the optimum size for parks and reserves. This project, conceived and designed by Dr. Lovejoy, is called "the Minimum Critical Size of Ecosystems" and is a joint program of World Wildlife Fund-U. S. and Brazil's National Institute for Amazon Research. Dr. Lovejoy is also the principal advisor for NATURE (WNET/THIRTEEN, New York), a series that he started in 1980. As principal advisor, he recommends program content and oversees the factual accuracy of the program scripts. A member of 11 scientific societies, Dr. Lovejoy has received grants from 16 foundations and institutions and written more than 100 articles for various national and International publications. He has published three books, Key Environments, Pergamon Press, Oxford; Nearctic Avian Migrants in the Neotropics, a Department of the Interior publication; and Conservation of Tropical Forest Birds, an ICPB publication. He is currently working on The Magnificent Exception, a book on people and the biosphere.</P>
+<P ALIGN="JUSTIFY">ARNE W. NORDSKOG is professor emeritus, Department of Animal Science, Iowa State University. He received his B.S., M.S., and Ph.D. degrees from the University of Minnesota between 1937 and 1943. His training and principal area of research has been in quantitative genetics, but by about 1960 his interests shifted to immunogenetics and more recently to molecular genetics. He has traveled widely, spending two years as an instructor in agriculture at the University of Alaska (1937-39), and has been an NSF Research Fellow at Cal Tech (1960), a visiting professor at the University of Minnesota (1966), an FAO lecturer at the Indian Veterinary Institute (1973), and an FAO-sponsored lecturer on poultry breeding in China (1979). He has acted as a consultant to a commercial breeder in Japan for 20 years. He has been the major professor at Iowa State for more than 60 M.S. and Ph.D. candidates and has published more than 150 scientific papers. Dr. Nordskog is an honorary member of the Norwegian Poultry Breeding Association, a fellow of the Poultry Science Association, and a fellow of the AAAS. In 1972, he was the recipient of the Poultry Science Distinguished Service Research Award. </P>
+<P ALIGN="JUSTIFY">LINDA M. PANEPINTO, swine research consultant, was director of the Colorado State University Swine Laboratory through 1988. She earned her B.S. in animal sciences at Colorado State University in 1972. In 1973 she joined the research team developing Yucatan miniature swine at Colorado State University, where she was given primary responsibility for colony management, protocol development, and genetic selection programs. In 1977, she designed an experimental research program for the development of a line of Yucatan pigs with a genetic propensity for exceptionally small size. She has continued her work in that area and has developed the Yucatan Micropig, described elsewhere in this publication. Her other major professional area of interest has been the design of facilities and equipment for swine with emphasis on animal comfort and minimizing stress. Her invention, known as the Panepinto Sling, has been widely adopted as the primary restraint method for numerous medical schools and research facilities using swine in the laboratory. She has published extensively in the field.</P>
+<P ALIGN="JUSTIFY">KURT J. PETERS is professor of animal breeding and husbandry in the tropics and subtropics, University of Gottingen, and is currently director of research at the International Livestock Centre for Africa. He received his Dr. Agr. degree from the Technical University of Berlin in 1975. He has undertaken research in livestock production development in Southeast Asia and Africa. The major focus of his research has been small animals, with special attention given to the potential of unconventional animals. Early in 1985 he assumed his present position directing research at the International Livestock Centre for Africa. </P>
+<P ALIGN="JUSTIFY">JOHN A. PINO is a senior fellow of the National Research Council, Board on Agriculture, and is currently the project director of the study "Managing Global Genetic Resources: Agricultural Imperatives." He received his B.S. in agriculture in 1944-47 and Ph.D. in zoology in 1951 from Rutgers University. As an associate professor he taught and did research in the Department of Poultry Science at Rutgers until 1955 when he accepted a position with the Rockefeller Foundation as animal scientist with the Mexican Agricultural Program, becoming the associate director of that program in 1960. In 1965 he was transferred to the Rockefeller headquarters in New York and became director of the Agricultural Science Program in 1970. Most of his career has been in international agricultural development. He retired from the Foundation in 1983 and went to Washington to become agricultural science advisor at the InterAmerican Development Bank until July 1986 when he accepted his present position. Dr. Pino has been a member of the Board on Agriculture since 1983 and previously from 1973 to 1977. </P>
+<P ALIGN="JUSTIFY">HUGH POPENOE is professor of soils, agronomy, botany, and geography, and director of the Center for Tropical Agriculture and International Programs (Agriculture) at the University of Florida. He received his B.S. from the University of California at Davis in 1951 and his Ph.D. in soils from the University of Florida in 1960. His principal research interest has been in the area of tropical agriculture and land use. His early work on shifting cultivation is one of the major contributions to this system. He has traveled and worked in most of the countries in the tropical areas of Latin America, Asia, and Africa. His current interests include improving indigenous agricultural systems of small landholders, particularly with the integration of livestock and crops. He was chairman of the Advisory Committee on Technology Innovation and a member of the Board on Science and Technology for International Development (under whose aegis this report is presented). He chaired the BOSTID report panels on water buffalo and little-known Asian animals. Currently, he is on the International Advisory Committee of the National Science Foundation and serves as U.S. Board Member for the International Foundation of Science.</P>
+<P ALIGN="JUSTIFY">MICHAEL HILL ROBINSON, director of the Smithsonian Institution's National Zoological Park, is an animal behaviorist and a tropical biologist. Before his appointment to the National Zoo, Dr. Robinson served as deputy director of the Smithsonian Tropical Research Institute in Panama, which he joined in 1966 as a tropical biologist. He received his Ph.D. from Oxford University after being awarded his B.S., summa cum laude, from the University of Wales. His scientific interests include predator-prey interactions, evolution of adaptations, tropical biology, courtship and mating behavior, phenology of arthropods, and freshwater biology. In the course of his studies, Dr. Robinson has done research in the United States and throughout the developing world. Recent publications include articles on predator-prey interactions, tropical forest conservation, reproductive behavior in spiders, and the function and purpose of zoos in relation to education and conservation. Dr. Robinson's favorite animals are cats, of all kinds. </P>
+<P ALIGN="JUSTIFY">KNUT SCHMIDT-NIELSON, J.B. Duke Professor of Physiology in the Department of Zoology at Duke University, has studied animal responses to extreme environmental conditions. His major emphasis has been on life in hot deserts, and he is widely recognized for his studies of camels and other desert animals. His research has involved field studies in North and South America, Africa, Asia, and Australia. Dr. Schmidt-Nielson has written several books, which have been translated into more than a dozen languages, and he has published several hundred research papers. He has been elected to the National Academy of Sciences, the Royal Society, the French Academie des Sciences, and several other academies. </P>
+<P ALIGN="JUSTIFY">ALBERT E. SOLLOD, is associate professor and head of the international veterinary medicine section at Tufts University School of Veterinary Medicine. He is currently stationed in Niger as chief of party of the integrated livestock project and policy advisor in the Ministry of Animal Resources. He has consulted in 15 countries in Africa and Asia, and his research interests include interdisciplinary systems analysis, indigenous pastoral technologies, monitoring change in agricultural production systems, and monitoring and assessing drought impact.</P>
+<P ALIGN="JUSTIFY">LEE M. TALBOT received his Ph.D. in geography and ecology from the University of California at Berkeley in 1963 and has worked on environmental and natural resource ecology and management in over 110 countries. At present he is visiting fellow at the World Resources Institute, Washington, D.C., and senior environmental consultant to the World Bank. He carried out pioneering research in Africa and elsewhere on the use of wild animals for food production. He has written more than 180 scientific and technical publications, including ten books and monographs. </P>
+<P ALIGN="JUSTIFY">CLAIR E. TERRILL, animal scientist, collaborator, Agricultural Research Service, United States Department of Agriculture (USDA), Beltsville, Maryland, received his Ph.D. from the University of Missouri in 1936, served briefly at the Georgia Agricultural Experiment Station, and joined the USDA at the U.S. Sheep Experiment Station, Dubois, Idaho, in the same year. His research concerned genetics and reproduction of sheep, leading to national and international responsibility regarding research and production of sheep, goats, and other animals, with primary emphasis on increasing efficiency of production of meat, wool, and other products. </P>
+<P ALIGN="JUSTIFY">CHRISTIAN M. WEMMER is assistant director for conservation and captive breeding programs at the National Zoological Park and is also in charge of the zoo's 3,100 acre Conservation and Research Center in Front Royal, Virginia. He is vice chairman of the IUCN Deer Specialist Group and a member of the Mustelid and Viverrid Specialist Group of the same organization. His interest in evolutionary and conservation biology has been motivated by frequent travel to South Asia and his role as scientific coordinator of the Smithsonian Nepal Terai Ecology Project. For the past 12 years he has coordinated the development of facilities and programs at the Conservation and Research Center and with Dr. R. Rudran has promoted conservation training and wildlife research in developing nations. He has published over 50 papers on various aspects of mammalian biology and conservation and has co-edited with Benjamin Beck one book on PFre David's deer. His edited volume "The Biology and Management of the Cervidae" was published by the Smithsonian Institution Press. </P>
+<P ALIGN="JUSTIFY">DANNY C. WHARTON is associate curator, Animal Departments, at New York Zoological Park, Bronx, New York. He received a B.S. from the College of Idaho and an M.Sc. in 1975 from the School for International Training in Brattleboro, Vermont. His Ph.D. in biology was earned at Fordham University. Dr. Wharton was a Peace Corps volunteer to Ecuador 1969-71 and a Fulbright scholar to Germany 1976-77. His research interests have been in the genetic and demographic management of small populations. He works on several committees including the IUCN/SSC Captive Breeding Specialist Group, Species Survival Plan Committee of the American Association of Zoological Parks and Aquariums, and is species chairman for the North American Propagation Group for the Snow Leopard.</P>
+<P ALIGN="JUSTIFY">CHARLES A. WOODS IS curator of mammals at the Florida State Museum and a professor of zoology at the University of Florida. He received his B.S. in zoology from the University of Denver and his Ph.D. in zoology from the University of Massachusetts. He worked at the University of Vermont from 1970 to 1979 when he assumed his present position at the University of Florida. His principle research interests have been in the areas of mammalian ecology (Rodentia) and systematics and evolution and he is especially concerned with island biology. He has spent many years working in the West Indies on a variety of projects and has worked closely with the government of Haiti in establishing a plan for the National Parks of Haiti and in completing a biogeophysical inventory of the natural resources of Hispaniola. He is the ecological consultant for the Institut de Sauvegarde du Patrimoine National in Haiti. He is the author of a number of scientific articles on the fauna of the Antilles including a multivolume series on the fauna of the mountains of Haiti. </P>
+<P ALIGN="JUSTIFY">THOMAS M. YUILL is associate dean for research and graduate training of the School of Veterinary Medicine, assistant director of the Agricultural Experiment Station, and professor of pathobiology and of veterinary science at the University of Wisconsin-Madison. He received his B.S. in wildlife management from Utah State University in 1959 and his Ph.D. jointly in veterinary science and wildlife ecology in 1964 from the University of Wisconsin. His principal research interests are animal health and diseases of wildlife, including those transmissible to domestic animals and to man. He worked in Thailand for two years and has had active research programs in Colombia for 17 years, and Costa Rica for 5 years. He has recently become involved in animal health and production development in the Gambia, West Africa. Dr. Yuill is an executive committee member and immediate past president of the Organization for Tropical Studies and currently serves as president of the Wildlife Disease Association. He completed a five-year term as Chairman of the U.S. Virus Diseases Panel of the U.S.-Japan Cooperative Biomedical Sciences Program. </P>
+<P ALIGN="JUSTIFY"></P>
+<B><P ALIGN="CENTER">&lt;&lt;TOC2&gt;&gt; Board on Science and Technology for International Development (BOSTID)</P>
+</B><P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">ALEXANDER SHAKOW, Director, Strategic Planning and Review,</P>
+<P ALIGN="JUSTIFY">The World Bank, Washington, D.C., Chairman</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Members</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">PATRICIA BARNES-MCCONNELL, Director, Bean/Cowpea CRSP, East Lansing, Michigan</P>
+<P ALIGN="JUSTIFY">JORDAN J. BARUCH, President, Jordan Baruch Associates, Washington, D.C.</P>
+<P ALIGN="JUSTIFY">PETER D. BELL, President, The Edna McConnell Clark Foundation, New York, New York</P>
+<P ALIGN="JUSTIFY">BARRY BLOOM, Professor, Department of Microbiology, Albert Einstein College of Medicine, The Bronx, New York</P>
+<P ALIGN="JUSTIFY">JANE BORTNTCK, Assistant Chief, Congressional Research Service, Library of Congress, Washington, D.C.</P>
+<P ALIGN="JUSTIFY">GEORGE T. CURLIN, The National Institute of Allergy and Infectious Diseases, The National Institutes of Health, Bethesda, Maryland</P>
+<P ALIGN="JUSTIFY">DTRK FRANKENBERG, Director, Marine Sciences Program, University of North Carolina, Chapel Hill, North Carolina</P>
+<P ALIGN="JUSTIFY">RALPH HARDY, Boyce-Thompson Institute for Plant Research, Cornell University, Ithaca, New York</P>
+<P ALIGN="JUSTIFY">FREDERICK HORNE, Dean, College of Sciences, Oregon State University, Corvallis, Oregon</P>
+<P ALIGN="JUSTIFY">ELLEN MESSER, Allan Shaw Feinstein World Hunger Program, Brown University, Providence, Rhode Island</P>
+<P ALIGN="JUSTIFY">CHARLEs C. MUSCOPLAT, Executive Vice President, Molecular Genetics, Inc., Minneapolis, Minnesota</P>
+<P ALIGN="JUSTIFY">JAMES QUINN, Amos Tuck School of Business, Dartmouth College, Hanover, New Hampshire </P>
+<P ALIGN="JUSTIFY">VERNON RUTTAN, Regents Professor, Department of Agriculture and Applied Economics, Saint Paul, Minnesota</P>
+<P ALIGN="JUSTIFY">ANTHONY SAN PIETRO, Professor of Plant Biochemistry, Department of Biology, Bloomington, Indiana</P>
+<P ALIGN="JUSTIFY">ERNEST SMERDON, College of Engineering and Mines, University of Arizona, Tucson, Arizona</P>
+<P ALIGN="JUSTIFY">GERARD P. DINEEN, Foreign Secretary, National Academy of Engineering, National Research Council, Washington, D.C., ex officio </P>
+<P ALIGN="JUSTIFY">JAMES B. WYNGAARDEN, Foreign Secretary, National Academy of Sciences, National Research Council, Washington, D.C., ex officio </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Board on Science and Technology for International Development Publications and Information Services (H A-476E)</P>
+<P ALIGN="JUSTIFY">Office of International Affairs</P>
+<P ALIGN="JUSTIFY">National Research Council</P>
+<P ALIGN="JUSTIFY">2101 Constitution Avenue, N.W.</P>
+<P ALIGN="JUSTIFY">Washington, D.C. 20418 U SA</P>
+<P ALIGN="JUSTIFY"></P></FONT></BODY>
+</HTML>
Index: /main/tags/2.25/gsdl/collect/demo/import/bostid/b18ase/b18ase.htm
===================================================================
--- /main/tags/2.25/gsdl/collect/demo/import/bostid/b18ase/b18ase.htm	(revision 21064)
+++ /main/tags/2.25/gsdl/collect/demo/import/bostid/b18ase/b18ase.htm	(revision 21064)
@@ -0,0 +1,2736 @@
+<HTML>
+<HEAD>
+<META HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=windows-1252">
+<META NAME="Generator" CONTENT="Microsoft Word 97">
+<TITLE>&lt;&lt;TOC1&gt;&gt; Little Known Asian Animals With a Promising Economic Future</TITLE>
+</HEAD>
+<BODY>
+
+<B><FONT FACE="Arial" SIZE=2><P>&lt;&lt;TOC1&gt;&gt; Little Known Asian Animals With a Promising Economic Future</P>
+</B><P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Report of an Ad Hoc Panel of the Advisory Committee on Technology Innovation Board on Science and Technology for International Development Office of International Affairs National Research Council </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<B><P ALIGN="CENTER">&lt;&lt;TOC2&gt;&gt; Acknowledgments</P>
+</B><P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">NATIONAL ACADEMY PRESS</P>
+<P ALIGN="JUSTIFY">Washington, D.C. 1983</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">NOTICE: The project that is the subject of this report was approved by the Governing Board of the National Research Council, whose members are drawn from the Councils of the National Academy of Sciences, the National Academy of Engineering, and the Institute of Medicine. The members of the Committee responsible for the report were chosen for their special competences and with regard for appropiate balance.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">This report has been reviewed by a group other than the authors according to procedures approved by a Report Review Committee consisting of members of the National Academy of Sciences, the National Academy of Engineering, and the Institute of Medicine.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The National Research Council was established by the National Academy of Sciences in 1916 to associate the broad community of science and technology with the Academy's purposes of furthering knowledge and of advising the federal government. The Council operates in accordance with general policies determined by the Academy under the authority of its congressional charter of 1863, which establishes the Academy as a private, nonprofit, self-governing membership corporation. The Council has become the principal operating agency of both the National Academy of Sciences and the National Academy of Engineering in the conduct of their services to the government, the public, and the scientific and engineering communities. It is administered jointly by both Academies and the Institute of Medicine. The National Academy of Engineering and the Institute of Medicine were established in 1964 and 1970, respectively, under the charter of the National Academy of Sciences.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The Board on Science and Technology for International Development (BOSTID) of the Office of International Affairs addresses a range of issues arising from the ways in which science and technology in developing countries can stimulate and complement the complex processes of social and economic development. It oversees a broad program of bilateral workshops with scientific organizations in developing countries and conducts special studies. BOSTID's Advisory Committee on Technology Innovation publishes topical reviews of technical processes and biological resources of potential importance to developing countries.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">This report has been prepared by an ad hoc advisory panel of the Advisory Committee on Technology Innovation, Board on Science and Technology for International Development, Office of International Affairs, National Research Council. Program costs for the study were provided by the Office of Technical Resources, Bureau for Asia, Agency for International Development, under Grant No. ASB-0249-SS-00-1026-00 and the Office of the Science Advisor, Agency for International Development, under Grant No. DAN/ 5538-G-SS-1023-00.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Funding for this printing was provided by the Office of Agriculture, Bureau for Science and Technology, Agency for International Development, Washington, D.C., under Grant No. DAN 1406-G-SS-4001-00.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">First Printing, June 1983</P>
+<P ALIGN="JUSTIFY">Second Printing, July 1984</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Library of Congress Catalog Card Number 83-061909</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">Participants in the Study</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">HUGH POPENOE, Director, International Programs in Agriculture, University of Florida, Gainesville, Florida, USA, Chairman </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Contributors </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">AMBAR ROESYAT, Research Institute for Animal Husbandry, Bogor, Indonesia </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">1. B. ARKA, Faculty of Veterinary Science and Animal Husbandry, Udayana University, Bali, Indonesia </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">J. S. F. BARKER, Professor of Animal Sciences and Head of Department, The University of New England, Armidale, New South Wales, Australia </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">KURT BENIRSCHKE, Research Department, San Diego Zoological Garden, San Diego, California, USA </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">BEN BERESKIN, Research Geneticist, Nonruminant Animal Nutrition Laboratory, Animal Science Institute, United States Department of Agriculture, Beltsville, Maryland, USA </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">RALEIGH A. BLOUCH, World Wildlife Fund, Bogor, Indonesia </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">W. BONGERS, Nature Conservation Department, Wageningen Agricultural University, Wageningen, The Netherlands </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">I. BONNEMAIRE, Ecole Nationale Superieure des Sciences Agronomiques Appliquees, Dijon, France </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">A. A. BOSMA, Vakgroep Funktionele Morfologie, Rijksuniversiteit, Utrecht, The Netherlands </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">D. BUTCHER, Assistant Director, Western Plains Zoo, Dubbo, New South Wales, Australia </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">G. S. CHILD, Wildlife and Parks Management Officer, Food and Agriculture Organization, Rome, Italy </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">W. ROSS COCKRILL, International Animal Consultant, Almansil, Algarve, Portugal </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">PAUL CONRY, Division of Aquatic and Wildlife Resources, Department of Agriculture, Guam </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">HAROLD J. COOLIDGE, Former President, International Union for the Conservation of Nature, Beverly, Massachusetts, USA </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">W. P. CROWCROFT, General Director, Metropolitan Zoo, Toronto, Canada </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">TONY J. CUNHA, Dean Emeritus, California State Polytechnic University, Pomona, California, USA </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">D. DEPPNER, Tropical Livestock Consultant, Washington, D.C., USA </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">C. DEVENDRA, Head, Feed Resources and Animal Nutrition Branch, Malaysian Agricultural Research and Development Institute, Selangor, Malaysia </P>
+<P ALIGN="JUSTIFY">J. M. DOLAN, San Diego Zoological Garden, San Diego, California, USA DUKUT SULARSASA, Department of Tropical Veterinary Science, James Cook University, Townsville, Queensland, Australia </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">H. EPSTEIN, Faculty of Agriculture, The Hebrew University of Jerusalem, Tel Aviv, Israel (retired) </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">T. FINNIE, Taronga Zoo, Mosman, New South Wales, Australia </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">H. FISCHER, Director, Institute of Tropical Veterinary Medicine, JustusLiebig-Universitat, Giessen, Federal Republic of Germany </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">IAN FLETCHER, Project for Animal Research and Development, Bogor, Indonesia </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">ANNIE P. GRAY, Commonwealth Bureau of Animal Breeding and Genetics, Edinburgh, Scotland (retired) </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">R. B. GRIFFITHS, Director, Animal Production and Health Division, Food and Agriculture Organization, Rome, Italy </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">1. R. GRiMWOOD, Nairobi, Kenya </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">COLIN P. GROVES, Australian National University, Canberra, A.C.T., Australia </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">ULRICH HALDER, Swiss League for Nature Conservation, Basel, Switzerland </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">CHARLES G. HICKMAN, Livestock Consultant, A. Mithat Efendi Sokak No. 36/11, Cankaya, Ankara, Turkey </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">D. HOFFMAN, Veterinarian, Project for Animal Research and Development, Bogor, Indonesia </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">J. H. G. HOLMES, Department of Agriculture and Forestry, University of Melbourne, Victoria, Australia </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">H. HUITEMA, Veterinarian, Osterbeek, The Netherlands </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">J. H. HUTASOIT, Director-General, Livestock Services, Jakarta, Indonesia </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">BENT JORGENSEN, Director, Copenhagen Zoo, Copenhagen, Denmark </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">NAT KlEFFER, Department of Animal Science, Texas A&amp;M University, College Station, Texas, USA </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">F. WAYNE KING, Director and Professor, Florida State Museum, University of Florida, Gainesville, Florida, USA </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">GRAHAM W. M. KIRBY, Principal Animal Production Officer, Department of Primary Production, Darwin, Northern Territory, Australia </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">HEINZ-GEORG KLOS, Director, Zoologischer Garten, Berlin, West Germany </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">KUSMAT TANUDIMADJA, Professor of Veterinary Anatomy, Faculty of Veterinary Medicine, Institut Pertanian, Bogor, Indonesia </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">JOHN K. LOOSLI, Department of Animal Science, University of Florida, Gainesville, Florida, USA </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">JOHN A. LUKAS, White Oak Plantation, Yulee, Florida, USA </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">A. A. MACDONALD, Vakgroep Funktionele Morfologie, Rijksuniversiteit, Utrecht, The Netherlands </P>
+<P ALIGN="JUSTIFY">JOHN MACKINNON, Representative, World Wildlife Fund, Bogor, Indonesia </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">ROBERT E. McDOWELL, Professor, Department of Animal Science, Cornell University, Ithaca, New York, USA </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">JEFFREY A. McNEELY, Executive Officer, Commission on National Parks and Protected Areas, International Union for Conservation of Nature and Natural Resources, Gland, Switzerland </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">ADRIAN G. MARSHALL, Honorary Secretary, Institute of South-east Asian Biology, Department of Zoology, University of Aberdeen, Scotland </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">[AN L. MASON, Animal Breeding Consultant, Edinburgh, Scotland </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">GEERT MONTSMA, Vakgroepen Veefokkerij, Veehouderij, Tropische Veehouderij, Wageningen, The Netherlands </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">J. B. MORAN, Senior Research Officer, Animal and Irrigated Pastures Research Institute, Kyabram, Victoria, Australia </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">ROBERT H. MILLER, Chief, Milk Secretion and Mastitis Laboratory, Beltsville, Maryland, USA </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">JAN NARI, Director, Central Research Institute for Animal Science, Bogor, Indonesia </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">HARVEY NEESE, President, Agri-Food Systems International, Inc., Troy, Idaho, USA </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">I. M. NITIS, Department of Animal Nutrition and Tropical Pasture Production, Udayana University, Denpasar, Bali, Indonesia </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">WILLIAM L. R. OLIVER, Chairman, lUCN/SSC Pigs and Peccaries Specialist Group, Jersey, Channel Islands, United Kingdom </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">JOHN PAYNE, Wildlife Section, Forest Department, Sandakan, Sabah, Malaysia </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">W.J.A. PAYNE, Tropical Animal Breeding Consultant, London, England </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">RALPH W. PHILLIPS, Arlington, Virginia, USA </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">DONALD L. PLUCKNETT, Scientific Advisor, Consultative Group on International Agricultural Research, Washington, D.C., USA </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">DAVID W. ROBINSON, Associate Dean, International Programs, University of California, Davis, California, USA </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">PATRICK J. ROBINSON, Department of Agricultural and Forest Sciences, University of Oxford, Oxford, England </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">D. H. L. ROLLINSON, Animal Production Officer, Animal Production and Health Division, Food and Agriculture Organization of the United Nations, Rome, Italy </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">CLIVE ROOTS, Director, Assiniboine Park Zoo, Winnipeg, Manitoba, Canada </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">J. A. SAYER, Nature Conservation and National Parks Project, FAO, Rangoon, Burma </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">R. E. SATTER, Nature Conservation and National Parks Project, FAO, Rangoon, Burma </P>
+<P ALIGN="JUSTIFY">GEORCE B. SCHALLER, New York Zoological Society, New York, New York, USA </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">JOHN SCHOTTLER, Principal Animal Production Officer, Department of Primary Industry, Lae, Papua New Guinea </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">GEORGE SEIFERT, CSIRO, Rockhampton, Queensland, Australia </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">ROGER V. SHORT, Professor of Reproductive Biology, Monash University, Melbourne, Australia </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">C. C. SINHA, Outdoor Recreation and Wildlife Research Division, Forest Research Institute, College, Laguna, Philippines </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">FREDERICK J. SIMOONS, Professor, Department of Geography, University of California, Davis, USA </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">C. D. SIMPSON, Senior Extension Specialist, Department of Agricultural, Technical and Extension Services, Bulawayo, Zimbabwe </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">P. SITORUS, Research Institute for Animal Production, Bogor, Indonesia </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">A. J. SMITH, Royal School of Veterinary Studies, University of Edinburgh, Edinburgh, Scotland </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">D. J. STOLP-DIEPEVEEN, Department of Tropical Animal Production, Agricultural University, Wageningen, The Netherlands </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">SUBANDRlYO, Research Institute for Animal Production, Bogor, Indonesia </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">W. SUMADI, Faculty of Animal Husbandry, Gadjah Mada University, Yogyakarta, Indonesia </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">L. M. TALBOT, World Wildlife Fund International, Gland, Switzerland </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">WARREN D. THOMAS, Director, Los Angeles Zoo, Los Angeles, California, USA </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">J. L. THROP, Director, Taronga Zoo, Mosman, New South Wales, Australia </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">ALLEN D. TILLMAN, Private Consultant in Animal Production, Stillwater, Oklahoma, USA </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">DONALD G. TULLOCH, Division of Wildlife Research, CSIRO, Winnellie, Northern Territory, Australia </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">HELEN NEWTON TURNER, Genetics Research Laboratories, CSIRO, North Ryde, New South Wales, Australia </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">B. VAN PUIJENBROECK, Curator of Mammals, Royal Zoological Society of Antwerp, Antwerp, Belgium </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">E. J. WARWICK, Visiting Professor, Faculty of Animal Husbandry, Gadjah Mada University, Yogyakarta, Indonesia </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">WARTOMO HARDJOSUBROTO, Lecturer in Animal Husbandry, Faculty of Animal Husbandry, Gadjah Mada University, Yogyakarta, Indonesia </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">R. H. WHARTON, Chief Research Scientist, CSIRO, Long Pocket Laboratories, Brisbane, Australia </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">J. L. WHEELER, Project Manager, Project for Animal Research and Development, Bogor, Indonesia </P>
+<P ALIGN="JUSTIFY">M.H. WOODFORD, Wildlife Veterinarian, Food and Agriculture Organization, Rome, Italy </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">B.A.YOUNG, Department of Animal Science, the University of Alberta, Edmonton, Canada </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">M.ZULBARDI, Research Institute for Animal Production, Bogor, Indonesia </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">NOEL D. VIETMEYER, Professional Associate, Board on Science and Technology for International Development, Asian Animals Study Director </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">National Research Council Staff</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">F. R. RUSKIN, BOSTID Editor </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">MARY JANE ENGQUIST, Staff Associate </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">CONSTANCE RECKS, Administrative Secretary </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">It is high time that the world was made aware of the valuable, large ruminant genetic resources of Southeast Asia.</P>
+<P ALIGN="JUSTIFY">J. B. MORAN Livestock Specialist Animal and Irrigated Pastures Research Institute Kyabram, Victoria, Australia</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Without utilization preservation is doomed to failure. Local breeds able to perform well in difficult habitats, such as in sparse vegetation, mountainous terrain, or the tropics, should be used for their agricultural potential. Breeds that demonstrate hybrid vigor on crossing with improved or exotic breeds also merit utilization. Genetically unique breeds should be retained for scientific studies of genetics, evolution, and biochemistry. And aesthetically attractive and historically important breeds should be maintained in parks and preserves for their educational and cultural values.</P>
+<P ALIGN="JUSTIFY">I. L. MASON Animal Breeding Consultant Edinburgh. Scotland </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&lt;&lt;I&gt;&gt; p00.png YAK</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<B><P ALIGN="CENTER">&lt;&lt;TOC2&gt;&gt; Preface</P>
+</B><P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">This report began as a brief examination of the domesticated banteng, a little studied bovine that is an important livestock resource in eastern Indonesia. But the study expanded to include other possibly useful but obscure bovines of Asia: the madura (a hybrid between banteng and cattle), gaur, mithan, kouprey, anoa, tamaraw, yak, and yakowshybrids formed by crossing yaks with cattle. Four pig species were also included (the bearded pig, the Sulawesi warty pig, the Javan warty pig, and the pygmy hog) that are important traditional resources in parts of Asia, as well as the babirusaa piglike, wild animal of Sulawesi that may have a rudimentary rumen. (Asia also has some interesting, little-known breeds of cattle, water buffalo, sheep, goats, and the common pig, but in this report we have chosen to highlight unconventional species only.)</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">These animals are unfamiliar to international animal science. This report aims to kindle awareness of their possible promise and to stimulate their introduction into projects in the world's animal research facilities. Only through active investigation will the potential of these species - most of which are now familiar only to a small number of wildlife specialists - become clear. Many are threatened with extinction; their genetic merits should be assessed before it is too late.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Development agencies and governments in the tropics should regard local species, such as those described in this report, as important genetic material for bolstering the long-term success of domestic livestock breeding programs. These indigenous resources can probably be improved genetically to compare favorably with imported livestock, particularly in difficult tropical environments.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">This report was prepared after Hugh Popenoe, Chairman of the Advisory Committee on Technology Innovation (ACTI), and Noel Vietmeyer of the ACT! staff visited banteng researchers in Indonesia, northern Australia, and Papua New Guinea in May 1981. More than 90 researchers (see contributor's list) provided information to the report through correspondence.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">ACTI is a committee of the Board on Science and Technology for International Development, National Research Council. It assesses unconventional resources and technologies that might prove especially applicable to problems of developing countries. Current titles in the ACTI series Managing Tropical Animal Resources are: </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">· Water Buffalo: New Prospects for an Underutilized Animal (1981)</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">· Little-Known Asian Animals with a Promising Economic Future (1983) </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">· Crocodiles as a Resource for the Tropics (1983) </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">· Butterfly Farming in Papua New Guinea (1983). </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The production of these books has been supported largely by the U.S. Agency for International Development (AID). Program costs for this study were sponsored by AID'S Bureau for Asia, and staff costs by AID'S Office of the Science Advisor, which also made possible the free distribution of this report.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">This is an exploratory volume. It will, perhaps, lead in a few years' time to a more complete book on indigenous Asian animals - and perhaps also to similar books on little-known animals of Africa and Latin America. If you have material to contribute to the future edition, please send it to Noel Vietmeyer, JH213, National Academy of Sciences, 2101 Constitution Avenue, Washington, D.C. 20418, USA, who will contact you when any new publication on this subject is planned.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<B><P ALIGN="CENTER">&lt;&lt;TOC2&gt;&gt; Introduction</P>
+</B><P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Asia has several domesticated animals about which little is known. Among them are the banteng ("Bali cattle") of Indonesia, the yak of Central Asia's high country, and the mithan of the border region of India, Burma, and Bangladesh.( *The promise of another Asian animal, the water buffalo, is described in companion report no 32. ) Some Asian farmers use domesticated bovine hybrids: the madura (banteng-cattle hybrid) in Indonesia and the yakow (yak-cattle hybrid) in Central Asia. In addition, domesticated forms of at least two Asian pig species (the Indonesian wild boar and the Sulawesi warty pig) are important husbandry animals in parts of Indonesia.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Among Asia's undomesticated animals are five interesting and potentially valuable species of wild bovines: the kouprey in Thailand, Laos, and Kampuchea; the gaur in India and much of Southeast Asia; two species of anoas in Indonesia; and the tamaraw in the Philippines. There are also three species of undomesticated Asian pigs: the bearded pig, the Javan warty pig and pigmy hog. Perhaps the strangest Asian animal of all is the babirusa, a piglike species of eastern Indonesia that may be a rudimentary ruminant.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Many of these animals are either threatened or endangered species, and some will soon be extinct unless scientists, governments, and resource managers take forceful action to preserve them. Scientific management and a better understanding of the animals themselves is required.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">An important need is to investigate their potential as livestock resources. All seem to be disease resistant and well adapted to difficult natural conditions. Some will interbreed with conventional livestock and might thereby pass on important characters to hybrid progeny. A few of the wild species are ancestors of domestic livestock and could be important genetic reservoirs for maintaining or improving the quality of their domestic descendants. Others may make useful new domesticates.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Appreciation of their potential in the long-term for the world's agricultural development could create a momentum for the protection, preservation, and greater use of these little-known animals.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Imported Livestock</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">In the past, many thought that the best way to raise animal productivity in tropical developing countries was to introduce high-performing breeds from temperate industrialized areas. The fact that the exotic animals were much more productive than local stock made this seem very appealing. But many such importations ended in failure when the animals either quickly died or their growth or reproduction rates declined so drastically that the herds dwindled away or became uneconomic. These introductions had been made without adequate consideration of the local environment that was expected to support the imported animal.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">More recently, some animal scientists have decried the idea of wholesale importing of temperate-zone livestock into tropical countries without also evaluating the indigenous livestock. In many cases the local animals' apparent poor performance results not from their lack of genetic potential, but from inadequate feeding, breeding, selection, management, and health care.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Indigenous Animals</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Until an objective evaluation of particular indigenous breeds is undertaken, governments should regard local animals as vitally important for the long-term development of their domestic livestock industries.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">To achieve an agriculture that is compatible with nature, we should try to raise an animal as much as possible within its own natural environment. Indigenous species are necessarily well adapted to their surroundings and have survival qualities that imported livestock often lack. They generally select food, either graze or browse, better than foreign species and can therefore exploit the habitat more efficiently and live within it more harmoniously.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">But most of the livestock species the world depends on today are best adapted to temperate conditions. This is because Stone Age peoples in what today are Europe, the Middle East, and eastern China domesticated the prototypes of agricultural animals that were available in those places. The world's best-known breeds of cattle, wool sheep, and horses, for example, usually perform well in temperate regions and poorly in the tropics.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The species described in this report offer promise as new and important alternative livestock resources for tropical regions. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">Embryo Transplants</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">It seems likely that modern technology will substantially improve our ability to use new species and breeds of livestock. One of the most encouraging of the new biotechnology techniques is embryo transplantation. In this process multiple eggs (produced by hormonally stimulating female animals) are fertilized and transplanted to other female animals. The hormonal cycles of the donor and receiving animals are synchronized so that a pregnancy results.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">This technique is widely used to transfer embryos between cattle, but researchers are now exploring transfers between different species and even between different genera. In 1981, for example, animal scientists at the New York Zoological Garden transplanted a fertilized gaur ovum into a Holstein cow, which carried the gaur calf to term. Now veterinarians at the University of Florida are attempting to transplant water buffalo embryos into both zebu and Holstein-Friesian cattle, and vice versa. If such pioneering work can become everyday practice, it will open possibilities of using common livestock to raise rare animals.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Moreover, because embryos are thought to be free of many diseases, their shipment between nations may soon be permitted without elaborate quarantine precautions. Methods for freezing embryos have been worked out so that the tiny bundles of cells can be air freighted inexpensively in small, insulated containers. This may make animals such as those discussed in this report available to Africans, Latin Americans, North Americans, and Europeans. It may vastly simplify the worldwide exchange of animal genetic material and become the animal counterpart of exchanging seeds.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">An additional benefit of embryo transplants is that the surrogate mother's placental blood supply provides the fetus with natural immunity to some local diseases, thus perhaps reducing one of the most serious causes of failure when exotic animals are introduced to new environments. And at Utah State University it has been noted that raising wildsheep embryos in domestic ewes produces lambs that are more docile than if they were raised by their biological mothers. Embryo transplants may be a small step toward domesticating new animals.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">With these possibilities on the horizon, it becomes even more important that all countries preserve their indigenous animals. The rest of this report suggests and discusses Asian species for protection and study. </P>
+<P ALIGN="JUSTIFY"></P>
+<B><P ALIGN="CENTER">&lt;&lt;TOC2&gt;&gt; Part I : Domesticated Bovine Species</P>
+</B><P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">It seems probable that two of our widely used livestock species were domesticated in the Asian tropics: the zebu or humped cattle in India and the water buffalo in the humid marshlands of northeastern India or Southeast Asia. (Both the chicken and some races of pig may also have a tropical Asian origin, but the exact sites of their earliest domestication is unclear.) There are, however, other, much more localized, domesticated bovines in Asia. These are not well studied and deserve greatly increased recognition.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">This section highlights:</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">· Domesticated banteng</P>
+<P ALIGN="JUSTIFY">· Banteng-cattle hybrids</P>
+<P ALIGN="JUSTIFY">· Mithan</P>
+<P ALIGN="JUSTIFY">· Yak</P>
+<P ALIGN="JUSTIFY">· Yakows. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">It is time for the world's scientific community to study the genetics, evolution, and biochemical parameters of the unique animal resources, that are found in Southeast Asia. ALLEN D. TILLMAN Animal Consultant Stillwater, Oklahoma, USA </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Though well adapted for survival in their own harsh tropical environments, many domestic livestock breeds are being neglected in the race to achieve temperate zone levels of productivity. CHARLES HICKMAN Department of Dairy Cattle Breeding Ottawa, Canada </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Studies should be made of the present and potential role, productivity and efficiency of all domestic animals and birds, large and small, before they are replaced by imported types. Many wild species also could make important contributions to human welfare with proper management. J. K. LOOSLI Department of Animal Science University of Florida .</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The conservation of endangered genetic resources represents a genuine and welcome synthesis of the concerns of the agriculturalist and the wildlife enthusiast.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">JOHN TINKER British Journalist</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">&lt;&lt;I&gt;&gt; p06.png MITHAN</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<B><P>&lt;&lt;TOC3&gt;&gt; 1 Domesticated Banteng</P>
+</B><P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The banteng (*Bos javanicus is now the accepted name, but Bos sondaicus, Bibos banteng, and other synonyms have been used in the past. (See Hooijer, 1956.) The name "banteng" has traditionally referred to the wild form of Bos javanicus; the name "Bali cattle" to the domesticated form. This chapter describes the domesticated form, but we retain the name banteng to reinforce the fact that the animal is not a breed of cattle, but a distinct species. Despite a cattle-like appearance, the animals are at least as genetically remote from cattle as is the bison. Both produce sterile males when hybridized with European cattle. Australia. (N.D. Vietmeyer)) is a bovine that resembles a small cow. It is, however, an entirely different species from either European cattle (Bos taurus) or zebus (Bos indicus). </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">These docile animals thrive under hot, humid conditions and, like the water buffalo, have high resistance to ticks and tick-borne diseases. In parts of Southeast Asia they have proved acceptable for draft power and meat production, and they may have potential for many other regions of the world.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Appearance and Size</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Banteng are remarkably uniform in type and have changed little from their wild ancestors (see chapter 6). Bulls stand from 1.3 to 1.5 m high at the shoulders, while cows are about 1.2 m high. They have the general conformation of beef cattle. The skin is tight, the neck short, and the dewlap inconspicuous. The face is narrow and is carried horizontally with the large ears pointing forward. There is no hump, but the male possesses a distinctive crest over the thorax because the spines of the thoracic vertebrae are unusually elongated.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">On both sexes a striking white oval patch covers the rump and all four legs have white stockings. Calves and females are usually light brown with a thin black line along the middle of the back. Bulls are brown when young but usually turn near-black at maturity, unless castrated. Thus, in a herd the sexes - black males and brown females - are strikingly apparent.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Male horns grow sideways, upward, and outward from a horny mass on the forehead. Females lack this horny shield and their horns usually grow upward and back, eventually curving down again toward the head. Polled animals have not been reported.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Mature banteng bulls can weigh from 450 to 500 kg. Under exceptional conditions they may reach 550 kg.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Distribution</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Nearly all the world's domesticated banteng are found in Indonesia. They are particularly important on the islands of Bali, Kalimantan, Lombok, Sulawesi, Sumbawa, and Timor. On Bali and Sumbawa, they are virtually uncontaminated by crossbreeding with other cattle and are thought to have been domesticated there in prehistoric times. Since 1913 government officials have enforced a law that prohibits crossbreeding so as to maintain the purity of the breed.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Small numbers of banteng have been introduced to Sumatra, Malaysia, and northern Australia, and there are experimental herds in Texas, USA, and New South Wales, Australia.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">&lt;&lt;I&gt;&gt; p09.png DISTRIBUTION OF DOMESTICATED BANTEG</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Status</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Domesticated banteng account for about 20 percent of Indonesia's total population of "cattle." The banteng population increased from 1.1 million in 1967 to 1.4 million in 1975 and is now estimated to be more than 1.5 million.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Habitat and Environment</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Banteng are found mainly in lowland areas on Indonesian islands straddling the equator. The environment is monsoonal with mean annual temperatures ranging from 23° to 31°C. Most of the region receives heavy rainfall throughout the year, but dry spells as long as five months occur at some locations.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Biology</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Banteng normally have high conception rates. In northern Australia they regularly achieve 80-90 percent conception, as compared with the 50-60 percent of Brahman-Shorthorn crossbred cattle. Similar conception rates have been recorded in Sulawesi.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Little basic information on the banteng's reproductive physiology has been reported. However, it appears that this differs little from that of cattle. Sexual maturity has been observed as early as 13 months and mating at 16 months.* The gestation period is about one week longer than that of cattle and twinning is not common. At birth, males weigh about 16-17 kg and females about 14-15 kg (about half the size of Brahman-Shorthorn calves). Calves are not weaned at any specific time, and dams may continue suckling a calf until the next birth.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Banteng will crossbreed with domestic cattle, producing hybrids with notable vigor and heat tolerance (see chapter 2).</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">It has been reported that banteng have the ability to drink water with high salinity," and in northern Australia they have even been seen grazing seaweed on coral reefs at low tide.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">On high-quality diets, feed-conversion ratios approach those of other bovine species. For example, banteng bulls on high-concentrate diets have shown daily growth rates of 0.7 kg, compared with 0.7 kg in water buffalo, 0.8 kg in zebu cattle, and 0.9 kg in British cattle bulls.:"</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">As the banteng matures, its weight remains lower than that of cattle of similar age. However, relative to mature liveweight, this disadvantage is only about 8 percent.§</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Behaviour</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Banteng cannot be handled as roughly as domestic cattle. Cows and calves are timid and easily upset. When stressed they may run into fences and walls, incurring head and spinal injuries. They also easily get into a state of shock. Special squeeze chutes and other special facilities, along with much care in handling the animals, are essential. However, despite their lively temperament banteng are docile if reared, as in Indonesia, with frequent human contact.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Uses</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">These animals are promising beef producers. Gourmets consider banteng cuts among the finest of meats, and Indonesia cannot export enough to satisfy the demand in Hong Kong and Japan alone. The meat's outstanding characteristics are its tenderness and leanness. When the animals are maintained and finished under traditional village management, total fat content of the meat (both on a liveweight and carcass basis) is usually less than 4 percent. Little of the fat is deposited among the meat fibers (marbling); about two-thirds of it is mesenteric and the remainder is subcutaneous, laid down in small globules. The carcasses have a high dressing-out percentage.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Banteng have proved to be useful as draft animals for the farm but are reportedly less suitable than zebus for hauling carts on roads. Traditionally, both male and female animals are worked, but Balinese farmers normally use females for cultivating light soils only. Banteng are trained when they are about 2 years old and are reportedly easier to train than zebus.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Potential Advantages</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Like water buffaloes banteng can utilize low-quality feeds; they are similar in that they can live off forage unpalatable to cattle. It is rare to see banteng in poor condition. Animals of all ages appear to have an ability to maintain weight and body condition even when pasture quality is poor. In this respect, they have been noted to outperform cattle in Australia's Northern Territory. Moreover, due to their lower milk production banteng cows lose less weight and condition during lactation than, for example, Brahman-Shorthorn cows.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">In comparison with cattle (European breeds) kept under similar circumstances in Australia, banteng are less infested with external parasites. Their hair is short and their hide tough, which helps them resist ticks. Under field conditions few adult cattle ticks (Boophilus microplus) are observed on the animals, except on malnourished individuals, and the incidence of tick-borne disease is said to be very low. Sarcoptic mange is known to affect the animals, but it has a low incidence as well.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Banteng also appear to tolerate several internal parasites. Liver fluke is probably the most prevalent. Although the animals themselves appear healthy at slaughter, some 80 percent or more of carcasses are found to have partially infected livers. In addition, intestinal worms are often present.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The animals are only slightly affected by Asian trypanosomiasis (Trypanosoma evansi). </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Limitations</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The animals are poor milkers; their udders are almost invisible. The lactation varies from 6 to 10 months and milk production is only 0.9-2.8 kg per day.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">To keep from reverting to the wild state, banteng may need close contact with humans or regular handling.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">An unidentified banteng disease first appeared on Bali in 1964. Known locally as "jembrana," it spread rapidly, causing mortalities from 10 to 60 percent in certain localities. It was originally thought to be rinderpest; it is now believed to be caused by a rickettsia transmitted by cattle ticks. Outbreaks have occurred with decreasing intensity and virulence since the original outbreak. The disease is under intensive investigation.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">"Bali ziekte," a disease affecting only banteng, has also been noted. It is characterized by dry eczema, followed by severe necrosis of the skin and exposed mucous membrances.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Because of their high susceptibility to bovine malignant catarrhal fever, banteng must not be brought in contact with sheep and some other animals. This virus is widely disseminated in sheep and several domestic and wild hoofed mammals.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Research and Conservation Needs</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">There have been few scientific studies of banteng and no coordinated attempt to improve their performance. They deserve more recognition and they merit testing in tropical locations outside their traditional home in Indonesia.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The herds in northern Australia (descendants of animals remaining from an abortive colonization attempt in the 1820s) are in a relatively disease-free zone, and although they are feral, they can potentially provide animals for breeding and use in other nations. Although these few hundred banteng are a valuable resource, they are vulnerable to destruction if adverse environmental conditions arise or exotic diseases break out in Australia. Representatives of the herd should therefore be distributed and viable breeding stock established at several new locations. (Their genes and gene combinations may even prove valuable for the indigenous herds in Indonesia, and banteng research and development would make a valuable topic for cooperative research between Australia and Indonesia.)</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Research is particularly needed to identify the reasons for the banteng's apparent ability to maintain weight and body condition on poor-quality grazing.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The problems of bovine malignant catarrhal fever, Bali ziekte, and jembrana need increased attention, particularly directed toward prevention and control. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&lt;&lt;I&gt;&gt; p13.png FIGURE</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<B><P>&lt;&lt;TOC3&gt;&gt; 2 Banteng Cattle Hybrids</P>
+</B><P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Banteng and cattle have the same number of chromosomes, and they will interbreed. Few scientific details on the hybrid progeny are available, but on the Indonesian island of Madura they are a "stabilized crossbreed" because they seem to be genetically uniform. This hybridization took place some 1,500 years ago, when Indian invaders brought zebus of the Sinhala, or Ceylonese, type to Madura and crossed them with the banteng.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">These maduras reportedly show better growth rate than the pure banteng species itself. They are thrifty, hardy, and able to perform well under extremes of heat and poor nutrition. Though a hybrid in origin, both sexes of the madura are fully fertile. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">For more than 15 centuries the winners of the bull races ("kerapan sap)") have been the herd sires of Madurese villages. This long breeding history has led to an animal with the following characteristics:</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">· Long legs and small feet</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">· Elongated muscles of the rear legs</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">· Heavy muscling over the back, loin, and shoulder</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">· Quick reactions and nervous temperament</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">· Great heat tolerance</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">· The ability to perform well as a work animal.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Appearance and Size</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Banteng-cattle hybrids vary in appearance, depending on whether European or zebu cattle are used in the cross as well as on the amount of backcrossing.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Maduras (banteng x zebu) are graceful animals. Their bodies are neat, compact, and deep, with well developed forequarters. The cows attain an average weight of about 210 kg and bulls range from 350 to 375 kg at maturity.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Superficially, maduras are like Jersey cattle, except for having a much smaller udder. In most of them the banteng dominates the body structure and coat color. Bulls have a well-developed hump; females have almost none. There is no distinct dewlap. Horns are medium sized and curve upwards and slightly backwards. Ears are medium length and horizontal. Breeders on Madura accept only red-brown animals.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Distribution</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Today, crossbreeds of banteng and zebu are distributed throughout Indonesia. On the other hand, hybrids between banteng and European cattle have been made only in small programs in the United States and Australia. For example, researchers in central Texas are producing a cross that is one-eighth banteng/seven-eighths Charolais. They believe this will result in a beef animal able to grow well in warm, humid conditions. In the Northern Territory of Australia, no problems have been encountered in mating banteng bulls to Brahman-Shorthorn cows. Calves that are one-fourth banteng/three-fourths Brahman-Shorthorn have since been produced.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Status</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Virtually all of the 575,000 "cattle" on the Indonesian island of Madura are hybrid animals resulting from crossing indigenous domesticated banteng with zebus. More than 200 head of banteng/Charolais hybrids are found near Easterly, Texas, and a score or so banteng/ Brahman-Shorthorn hybrids are on a research station near Darwin, Australia.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Habitat and Environment</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The environment in Madura, where most of these hybrids occur, is monsoonal, with mean average temperatures as high as 31°C in the hot season, and dry spells as long as 5 months. It seems likely that judicious selection of the cattle breed could result in hybrids suitable for many other environments.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Biology</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">As noted, the animals on Madura are bred to be raced. They are probably the fastest running bovines. From a standing start, a yoked pair pulling a sled can reach 50 kph by the end of the 130-meter course. An unencumbered individual can approach the speed of a horse (about 68 kph).</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">When compared with other bovine genotypes in Indonesia, the performance of these hybrids is more closely related to the banteng than the zebu ancestry."</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">In the cross between banteng and European cattle all F1 bulls are sterile; their sperm development ceases at the secondary spermatocyte stage. Infertility also exists in most one-fourth banteng (although some sperm are present) and in all three-fourths banteng bulls. The fertility of the F1 cows, on the other hand, is high - 90 percent as compared with 70 percent for Brahman-Shorthorn cows.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Behavior</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The hybrids have a lively temperament. However, when they are reared with other domestic cattle or handled on a regular basis, they are almost as docile as cattle. For instance, they remain calm even in Madura's extremely crowded towns. Nevertheless, personal contact probably must be maintained to keep them accustomed to human management.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The cows are very protective of their calves.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Uses</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Several reports from the livestock service of the former Dutch colonial government, as well as several books on the East Indies, state that meat from the madura is the tenderest of any known breed. In addition, the hides are pliable and superior to those of cattle and are used in the highest quality leather goods. They command a price about 20 percent higher than zebu hides.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The breed is reportedly one of the best draft animals for its size in the world.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">Potential Advantages</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Maduras have several desirable traits, including those outlined below:</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">· Feed efficiency. With grain rations, yearling bulls can gain 1 kg on less than 7 kg of ration.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">· Thriftiness. The breed can maintain its body condition on low quality forages.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">· Heat tolerance. The madura has a high rate of cutaneous evaporation and is therefore well adapted to the tropical monsoonal climate. Teams of madura can plow or cultivate land for more than 6 hours, even at high temperatures.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">· Carcass quality. The madura fattens readily on a high-quality diet and  produces carcasses with high dressing percentages, a large rib-eye area, and  high yields of lean meat.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">· External fat thickness. A well-finished madura normally has only a slight  covering of fat over ribs and lower round. Maximum thickness (over the top  round) is less than 1.5 cm.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">· Intelligence. These animals are responsive and easily trained. The famous  dancing cattle of Madura, for instance, are actually these banteng-cattle  hybrids.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">· Parasite resistance. Despite often high levels of fluke infections, the  animals continue to work, reproduce, and maintain body condition.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Limitations</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Maduras have been bred for one thing - speed. Some of their genetic  limitations are:</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">· Low birth weight. The calves begin small, weighing 12-14 kg at birth, and  they continue to be slow weight gainers. [Feeding trials with yearling bulls  have shown daily gains of over 600 g for 180 days.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">· Poor lactation. Milk production is normally less than 1.5 lifers per day and lactation ends after about 4 months. The cows often fail to produce milk. Much of this is probably caused by poor nutrition.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Research and Conservation Needs</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">One of the important features of the madura is that its genetic variation has been largely removed during 1,500 years of continuous breeding; with study much valuable information could be obtained that is beneficial to all bovine breeds.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The following topics need further study:</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">· Fertility levels</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">· Crossbreeding to test the effect of using a wider range of cattle breeds*</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">· Assessment of the hybrid's advantages over the pure banteng</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">· Performance under a wide range of environments.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<B><P>&lt;&lt;TOC3&gt;&gt; 3 Mithan</P>
+</B><P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The mithan (Bos frontalis) is believed to be a domesticated form of gaur (see chapter 6).t (However, it resembles the banteng and some authors have proposed that it is a gaur-cattle cross, others a gaur-banteng cross.) The mithan is a domestic animal indigenous to parts of India, Burma, and Bangladesh. Because of large size and the high butterfat content of its milk it is widely used to crossbreed with cattle in Bhutan. It deserves greater recognition both in Asia and elsewhere.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">Appearance and Size</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The mithan is a handsome animal. Bulls may occasionally exceed 1.7 m at the shoulder and weigh 1,000 kg, but the average bull is about 1.5 m tall and weighs 540 kg. Cows are shorter and weigh less.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The animal has a dorsal ridge on the crest of the shoulders, a small but pronounced dewlap, and a generally flat forehead. Mithan horns are often of unusual girth; they are straight or gently curving, and many have an enormous base that practically covers the top of the skull.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Most calves and females are brown, but adult males are generally black with white stockings on all four legs. Some, however, are light brown, white, or piebald.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">In the hill ranges of Assam, where gaur are still plentiful and interbreeding between mithan and gaur frequently occurs, the mithans are massive and gaurlike. But in the Chin Hills, where gaur are scarce, the mithans have lost their bulky proportions, probably by interbreeding with cattle. With them, the high dorsal ridge on the shoulder (which lends so much to the imposing stature of the gaur) has disappeared, the horns are cowlike, and the varied coloring of the domestic cow begins to appear.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">Distribution</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Mithan are kept in a domesticated condition by the hill tribes of northeastern India (Mishmis, Mizo, Nagas), the Chittagong Hill tracts, and some Burmese hill ranges (Arakan and Chin Hills). It is the main domestic animal of the Nagas of Nagaland.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Status</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">In India feral herds totalling some 50,000 head roam the jungles of Arunachal Pradesh. Recently the Royal Government of Bhutan has established two herds by purchasing animals from Arunachal Pradesh. Bhutanese farmers have some 60,000 head of animals that are hybrids of mithan and the local breed of cattle.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The government of Bhutan is breeding mithans on government farms and distributing males to private breeders to improve the genetic base.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">Habitat and Environment</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The mithan is a grazing animal, but in some areas herds are allowed to browse freely in the woods; some return to the villages for protection at night, while others remain largely in the forests. The villagers keep the forest mithans nearby by providing salt, for which the animals have an insatiable craving.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Feral mithan live in the same habitat as gaurs and are said to move equally skillfully in mountainous terrain. Usually they are found at elevations from 600 to 3,000 m. However, in the Chittagong Hill tracts and the Mishmi country they descend to 300 m and lower, while in Bhutan they have been reported grazing in summer at altitudes as high as 3,300 m, for example around Thimphu.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&lt;&lt;I&gt;&gt; p23.png Mithan distribution. (after Simoons and Simoons, 1968)</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Biology</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Mithans are fully fertile amongst themselves. Also, they interbreed freely with the gaur, banteng, yak, and cattle of both the taurus and zebu types. Naga owners encourage the interbreeding with gaur, regarding it as an improvement of the race. (They arrange this by placing salt licks in the forest. After gaur bulls have formed a habit of coming to the licks, mithan cows are left there and in due course mating takes place.)</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The crosses between mithan and zebu are also encouraged in certain districts. Unlike most crosses between bovine species, those between mithan and cattle result in fertile male and female offspring (although some owners indicate that the F1 male is not a reliable breeder).</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Behavior</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">This is an unusually gentle animal with a quiet disposition, as revealed in the Chin tribe's expression "gentle as a mithan." Normally even a stranger is safe to approach one; if he gives it a bit of salt, it will usually follow him about. Thus, mithans are easily managed in a regular cattlerearing operation.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Many mithans are not domesticated in the strict sense. Their herds live in a semi-tame state near jungle villages and come to settlements only in the evening to lick salt.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Uses</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">In some regions of northern India, mithans are used for field work and as draft animals. They are also important as a meat supply. The Bhutanese government is establishing a national dairy-mithan breeding program, which could result in a valuable dairy animal.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">To many tribes of northeast India and Burma, mithans serve mainly as sacrificial animals. The Nagas use them as a kind of "currency" to pay for goods, to buy brides, and to pay penalties.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Hybrids resulting from backcrossing mithan with common cattle are also used as work animals. For at least a century, Bhutanese livestock breeders, particularly those in the eastern section, have mated mithan bulls to siri cows (Bos taurus) from India. This produces very profitable hybrid offspring that have high milk production. The milk is rich in total solids and produces exceptional yields of cheese and butter.* The male of the cross (called "jatsha") is a powerful draft animal, and the female ("jatshum") is a prized milk cow. To this day, extensive crossing continues.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Potential Advantages</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The mithan is potentially an animal that can be used in difficult terrain where most domestic cattle breeds do not perform well. Mithans are superior when it comes to feeding on steep slopes and cliffs and for grazing native grass and the leaves of local fodder trees. They are also adapted to tropical and subtropical environments. And they are able to maintain themselves in small herds (6-10 head) in dense jungle.*</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The mithan could prove valuable in other parts of the world, and it could be important particularly for the genetic improvement of cattle in the tropics.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">Limitations</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">If they are disturbed, mature mithans can be temperamental. They can be difficult to hold with normal fences or chutes, because of their size. When given injections or otherwise subjected to pain, they are liable to bolt to the jungle and not return.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">Research and Conservation Needs</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The productivity of these animals needs to be better characterized and defined. Attention should be given to their grazing efficiency as compared with that of cattle.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The two farms the Bhutan government has established for breeding mithans provide an opportunity to gather genetic information on the species and to have experimental matings take place to establish the most suitable animal for various conditions.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The genetic relationship of mithan to gayal, gaur, and cattle needs to be clarified. Although it is believed that the mithan and gayal are the same animal, one of this report's reviewers points out that the mithan of Bhutan are strikingly different in color, body shape, and horn structure from gayals seen in zoos in Europe and India. Although the mithan is now considered a domesticated gaur, many in the past have claimed it as a gaur-cattle hybrid. Physiological research could remove lingering doubts. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&lt;&lt;I&gt;&gt; p26.png FIGURE</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<B><P>&lt;&lt;TOC3&gt;&gt; 4 Yak</P>
+</B><P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The yak (Bos grunniens), is a grazing animal that is accustomed to traveling great distances in a harsh environment. Nothing is known about when it was first domesticated, but there has probably been a close association between man and yaks ever since the first humans migrated into the high mountains of Asia.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Appearance and Size</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Domesticated yaks are about the size of ordinary cattle and rarely exceed heights of 1.3 m at the shoulder. Their liveweight is generally 250-550 kg for the males and 180-350 kg for the females. They differ little from wild yaks except that they are smaller, have shorter and thinner horns, and may be rusty brown, black, silver grey, or piebald instead of black. Often they have whitish spots on their faces.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The yak's hair is long, especially on the flanks, where it forms a shaggy fringe that often reaches the ground. This, together with an underlying layer of thick, fine wool, protects the animal from the bitter cold of its native region. The yak has an enormous tail with a brush of long hair coming from its root, which is rare in bovines.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Long extensions of the thoracic vertebrae give the yak shoulders that look like a hump, but this is different from the boneless hump in zebus. The body is long, short-legged, and compact, with particularly large forequarters because, like the bison, the yak has 14 or 15 pairs of ribs instead of the 13 of domestic cattle.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The horns spread outward and upward, and the head is held low, like that of the bison. While no hornless domestic yaks have been reported in Nepal, more than 90 percent of those found in Mongolia lack horns.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Distribution</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Most yaks are found especially in the mountains and plateaus of Tibet and western China, however they occur from northern Afghanistan, Pakistan, India, and Bhutan to Mongolia, and the Soviet Union.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Status</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">There are more than one million domestic yaks in the world.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Habitat and Environment</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">In the Himalayas the domestic yak is almost always found above 2,000 m elevation. Males are sometimes brought as low as 1,700 m for mating with cattle (see chapter 6), but they do not fare well at such altitudes. In Mongolia and Buryatiya (U.S.S.R.), however, they are found as low as 1,500 m elevation.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">&lt;&lt;I&gt;&gt; p29.png Yak distribution. (after J. Bonnemaire, 1976)</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The wild yak lives in desolate mountain areas at altitudes of 4,000-6,000 m. Its habitat is the alpine tundra and the cold desert regions of the northern part of the Tibetan plateau. These barren mountain regions are remote and at higher elevations than the zones of human habitation.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Biology</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Yaks look ungainly, partly because they are covered with long hair, but they are agile climbers and can maneuver narrow mountain paths. Their long hair is one adaptation to the cold climate. Other adaptations are the small, compact scrotum of the male and udder of the female, the small teats (only 2-3 cm long) and covering of hair over the udder, and the covering of short hair over the muzzle, except just around the nostrils.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">In early summer yaks graze the lush grass in valley bottoms, but for much of the year they live on dry, coarse mountain grass and for long periods obtain water by eating snow.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The gestation length is 258 days - slightly shorter than that of cattle.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Behavior</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Domestic yaks are docile and easily managed.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Uses</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Yaks are especially useful as riding and pack animals; they can manage loads of more than 150 kg. At altitudes up to 6,000 m they may carry a pack or a person at a steady pace for days and still remain in good condition. In some regions they are the only feasible pack animal. Yak bulls (generally castrated) are also used for plowing and for threshing grain.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Occasionally the yak is slaughtered for meat. The meat is particularly important in parts of the USSR and in Mongolia, where in the cold, high-altitude environments it reportedly costs only half as much to produce as beef.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">In most areas milk production is an essential aspect of yak husbandry. Yields vary considerably according to management and nutrition, but they average about 600 kg and can be more than 1,000 kg per lactation. Yak milk is golden colored. It is much richer than cow's milk; a typical analysis is: total dry matter, 17.35 percent; fat, 6.5 percent; protein, 5.3 percent; and sugars, 4.6 percent. The fat globules are much larger than those in cow's milk. People of Tibetan stock use yak butter as a food staple and as a lighting fuel.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Yak hide, though apparently not as good as that of cattle, is used for many purposes. It makes outstanding saddles. Yak hair is used for making ropes, saddle blankets (purportedly the best in the world), grainstorage bags, and tents. The fine wool that occurs beneath the long hair is used for making felt. The annual yield of adult females and males is about 750 g and 1,600 g of hair and about 350 g and 600 g of wool, respectively.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Because yaks are often found above the timberline their dung is an important fuel in many areas. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Advantages</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Yaks can live and work hard in a cold climate. They are the only bovines to thrive at high altitudes. In cold, high areas they can work and produce meat and milk more efficiently and cheaply than cattle.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Limitations</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Yaks are not well able to eliminate surplus heat because their heavy coat reduces their ability to sweat. In warm climates their respiration rate and body temperature increase and they become exhausted and susceptible to infections. At low altitudes in Nepal yaks die of a variety of diseases. Apparently not even yak-cattle hybrid animals (see next chapter) can successfully live below 700 m in that part of the world. This is probably due to overheating, since during the first half of this century yaks grew successfully in trials at low altitudes in Alaska and northern Canada.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Research and Conservation Needs</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">· Yak improvement programs are much needed. It seems probable that the genetic potential of the species is far from realized because Buddhist beliefs oppose the deliberate killing of stock. Techniques for deep freezing yak semen have been successfully developed at Regents Park Zoo, London and should prove invaluable for improving the breed.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">· As a result of uncontrolled hunting the wild yak is endangered and is now restricted to remote barrens on upland plateaus and highlands in northern Tibet and Chinghai, inhospitable even to domestic yaks. The numbers of wild yak are unknown. They require total protection throughout their range and the establishment of adequately protected reserves with good pasture. To preserve their genetic purity, it is important to isolate wild yaks from domestic yaks and thus keep them pure.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">· A primary need is to catalog the numbers and locations of purebred yaks. Today we have little idea of the total breeding population. Gathering such information is difficult, owing to the geographical isolation of the communities involved.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">· It is also important to catalog the movement of yaks between different areas to see if enough genetic exchange occurs to prevent inbreeding of the population. Exchanges between local pastoralists were much more frequent in the past (for example, between Tibet and Nepal), but this is now more difficult because of border restrictions and because many yak </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">herders that used to move herds long distances have become sedentary farmers.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">· Breeding strategies, herd management, product processing, and herd hygiene in Nepal, Bhutan, Sikkim, northern India, and northern Pakistan, Tibet, Mongolia, and the Soviet Union all differ greatly. It is important to get an overall perspective so that the strengths of the different systems can be judged and the weaknesses reduced.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">· There are clearly different domestic yak "breeds" in terms of their appearance, and these need to be identified and compared systematically. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&lt;&lt;I&gt;&gt; p33.png FIGURE</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<B><P>&lt;&lt;TOC3&gt;&gt; 5 Yakows</P>
+</B><P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Yaks and cattle have the same diploid number of chromosomes (60). And in the regions where yaks are found, they are often interbred with cattle, either the humpless cattle (Bos taurus) of Tibet and Mongolia or the zebu (Bos indicus) of South Asia. As with mules, the hybrid offspring of cattle and yak surpass their parents in strength and vigor. Yakows* grow faster than their parents, and they suffer less from high temperatures than yaks. The hybrid cow reaches sexual maturity earlier and yields larger quantities of milk than the yak cow. The males, however, are sterile.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Appearance and Size</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The yakow's appearance varies with the type of cattle used in the cross. But because of the phenomenon of hybrid vigor (heterosis), the hybrids are considerably bigger than the mean size of their parents. (For instance, in one test the liveweight was approximately 18 percent higher than the average weight of the parents.) The hybrids also excel in hardiness, working ability, growth rate, and milk production.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Nevertheless, their appearance and performance is closer to that of the mother than of the father. Because of this, the yakows can be "custom designed" for various altitude zones. For example, the farmer at lower altitudes may produce cattle-like yakows by breeding yak bulls to domestic cows, while farmers at higher altitudes would use the reverse cross.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">Yakows have shorter hair and a much less downy undercoat than purebred yaks. They are similar in color to yaks. (In Nepal, black is most frequent, but brown shades and even white may occur.)</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Distribution</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Yakows are found in parts of northeastern Afghanistan, northern Pakistan, northeast and northwest India, Nepal, Sikkim, Bhutan, Tibet, western China, Mongolia, and southeastern Russia. They are found notably in the Himalayan region of Nepal, where they are bred by people of Tibetan culture and language. Sherpas, for instance, supply hybrid cows and heifers to dairy farmers throughout northeastern Nepal. Hybrids are also much bred in Ladakh (northern Pakistan) and Mongolia.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Whereas farmers in Nepal tend to use zebus to cross with yak, the inhabitants of the Tibetan plateau generally use Bos taurus cattle. People in some areas favor mating yak bulls to cows, while those in other areas prefer the reverse. But even within one village there can be a degree of specialization by different families, depending on wealth and the location of traditional grazing grounds. Generally, however, the crosses between domestic cattle bulls and yak cows are the predominant ones.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Status</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The number of yak-cattle hybrids in the world is unknown.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Habitat and Environment</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Like the yak, the hybrid can live in cold, barren, upland terrain, but it has the advantage of being able to adapt to lower altitudes. In winter, caravans of hybrids may come down as low as 1,600 m in some parts of Nepal, and hybrid herds (especially those resulting from crossing yak bulls with zebu cows) can spend several weeks grazing at altitudes as low as about 1,700 m in winter.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">Biology</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Female hybrids are fertile when mated with either parent stock. Male hybrids, however, are sterile. Although they have fully developed secondary sexual characters and show libido, their testes do not produce spermatozoa because the seminiferous tubules are poorly developed and the spermatogonia and their nuclei are degenerate.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">A few normal or motile spermatozoa may be found in the semen of backcrosses of the F1 hybrids to either parent, but as a rule the spermatozoa are normal and dead.* Backcrossing is reportedly not common, however, as the progeny do not retain hybrid vigor.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Behavior</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Tibetan farmers prefer the hybrids for plowing because of their docile temperament. The yak is said to be more stubborn.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Uses</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The hybrids are valued as beasts of burden and draft, and are often preferred over yaks. Male hybrids are generally castrated at about 3 years of age so as to increase their strength and size.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Potential Advantages</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Where pastures occur over areas of greatly varying altitude, the use of hybrid livestock is likely to be more efficient, in biological terms, than the use of yaks or cattle. By judiciously selecting cattle, yaks, or hybrids all altitudes from sea level to above 5,000 m can be utilized with best efficiency.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The hybrid's milk is intermediate in composition between that of its parents. However, hybrids yield up to 7 kg of milk per day against the yak's 3 kg. (It seems that the hybrid derived from cattle bull and female yak produces considerably more milk, with a higher fat content than that derived from yak bull x cattle female.) Also the female hybrids produce larger quantities of milk than Nepalese zebu cows on the same hill pastures. They also produce a calf each year, while under normal herd management yaks tend to produce a calf every 2 years.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">Limitations</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Hybrids do not tolerate extremes of altitude or cold as well as purebred yaks.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The normal gestation period for yaks is about 1 month shorter than that of cattle, and the gestation period for a hybrid is intermediate between that of the parents - hence there may be problems at calving when a female yak is sired by a bull from a large cattle breed.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Research and Conservation Needs</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Research is needed to identify differences in altitude tolerance between various hybrids. This should include measurements of hemoglobin count, respiration rate, and pulse rates at different altitudes.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Studies are also needed on all production characteristics, particularly on the meat and milk production potentials.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Cataloging the breeding strategies of different areas where hybrids occur would be useful, along with a historical perspective.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Research to determine the most productive hybrids by crossing different yak and cattle "breeds" in areas with different environmental conditions could be extremely useful. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<B><P ALIGN="CENTER">&lt;&lt;TOC2&gt;&gt; Part II : Wild Bovine Species</P>
+</B><P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">In various parts of Southeast Asia there exist little-known relatives of cattle and water buffaloes. Many of these wild animals are close to extinction, and attention is drawn to them in hope their populations will be preserved. All of them survive in tropical regions subject to environmental extremes - flooding annual rains, searing droughts, and swarming pests and parasites. These are conditions to which conventional livestock are poorly adapted.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">None of Africa's bovines is threatened with extinction, and both the European and American forms of bison are being preserved by governments and individuals. In Asia, however, there has been an alarming drop in the numbers of wild water buffalo, wild yak, wild banteng, kouprey, gaur, and tamaraw in recent years.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">This section describes:</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">· Wild banteng</P>
+<P ALIGN="JUSTIFY">· Gaur</P>
+<P ALIGN="JUSTIFY">· Kouprey</P>
+<P ALIGN="JUSTIFY">· Tamaraw</P>
+<P ALIGN="JUSTIFY">· Anoas</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">If not molested, many of these animals can thrive side by side with human settlements. They may therefore have an important future role in the development of the tropics. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">There is little point in conservation for conservation's sake, but loss of irreplaceable resources through ignorance, greed, or thoughtlessness should be avoided. It may be that these Asian animals have little merit other than their uniqueness, but at the very least, sufficient numbers should be conserved until we have time to find out. A. J. SMITH Royal School of Veterinary Studies, Edinburgh, Scotland </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Rapid human increase and relative poverty deny hope that any land can lie idle when so many would be robbed of an opportunity simply to exist. For wildlife to survive, let alone at its breathtaking best, we must think of new and better ways to justify its future, preferably by having it contribute to the welfare of those hard-pressed humans who inevitably are further disadvantaged by the creation of national parks. DAVID WESTERN New York Zoological Society, Bronx, New York, USA </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">There is an urgency to conserve and study nontraditional animal species, especially for use in the environmentally challenging tropical areas of the world. The philosophy plant scientists apply to exploring the potential of the plant kingdom needs to be more enthusiastically adopted for the world's animal species. G. W. M. KIRBY, Principal Animal Production Officer Department of Primary Production Darwin, Australia</P>
+<P ALIGN="JUSTIFY"> </P>
+<P ALIGN="JUSTIFY">&lt;&lt;I&gt;&gt; p40.png GAUR</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<B><P>&lt;&lt;TOC3&gt;&gt; 6  Wild Banteng</P>
+</B><P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The wild banteng (Bos javanicus)* are the most cowlike of all the wild bovines and are the parent stock of the 1.5 million domesticated banteng in Indonesia (see chapter 1). They have a scattered distribution throughout Southeast Asia, and three subspecies are recognized:</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">· The Java banteng Bos javanicus javanicus (Java and Bali)</P>
+<P ALIGN="JUSTIFY">· The Borneo banteng Bos javanicus lowi (Borneo)</P>
+<P ALIGN="JUSTIFY">· The Burma banteng Bos javanicus birmanicus (Burma, Thailand, Indochina).</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Appearance and Size</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Banteng have been called the most beautiful of all wild relatives of cattle. The cows are usually a vibrant reddish brown, while adult bulls are mostly blackish-brown and sometimes even blue-black (although in Burma and Indochina bulls remain golden brown like the cows, and in Thailand a few banteng have been recorded with white, deerlike spots on their brown coats). Both sexes have white "stockings" and a large white patch on their rumps.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Wild banteng are larger than their domesticated counterparts. Average-sized bulls of the Java and Burma subspecies stand 1.6 m high and weigh 635 kg, but bulls as large as 1.9 m and 825 kg have been recorded. Cows average 1.4 m in height and weigh 400 kg. The Borneo subspecies is smaller.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The horns of banteng bulls are angular, turning out and then up, with inward-pointing tips and reaching a spread of 60-75 cm. The horns of cows are short and crescent shaped. There is a patch of thick, naked skin between the horns.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">Distribution</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The animals are found in restricted localities scattered over an area ranging from the northeastern edge of India, through Burma, Thailand, the northern Malay Peninsula, central and southern Indochina, and the islands of Borneo, Java, and Bali.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Status</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Only a few thousand wild banteng survive, and their numbers are decreasing. Most populations are endangered because their habitats are being encroached upon by the growing human population. In Sabah, Malaysia, for example, the areas where an estimated 300-550 banteng (the last remaining herds) occur are scheduled for conversion to permanent agriculture. The animals are being forced to use smaller and smaller habitats, thus increasing losses caused by malnutrition, diseases, and parasites. In addition, throughout much of the animal's range, hunting, military operations, and perhaps interbreeding with domestic cattle are further reducing the original stocks.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">&lt;&lt;I&gt;&gt; p43.png Distribution of wild banteng. (courtesy of C.H. Wharton)</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Habitat and Environment</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The banteng's general distribution lies in the zone of deciduous monsoon forest in Southeast Asia. Habitats vary between the extremes of dry wooded parkland with large grassy plains to tropical rain forest with small clearings. The animals prefer flat or undulating terrain. In northern Kampuchea and eastern Java, they inhabit grassland savannas. In western Thailand, they live in a belt of grass and bamboo thickets along upper slopes of dry mountains.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Wild banteng inhabit sites from sea level to around 2,000 m elevation. They avoid large human settlements and plantations.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">In most areas there are no pronounced hot or cold seasons, but dry seasons can be long.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Biology</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Banteng prefer feeding on grass, but are fond of herbs, leaves, fruits and blossoms, as well as the sprouts of trees, brush, and young bamboo. Under favorable conditions they drink daily, preferring standing water. During droughts, they seem able to survive several days without water. In coastal areas where there are no mineral licks they can meet their need for salt by occasionally drinking seawater. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The sex ratio at birth is 140 males to 100 females, but mortality of bulls is heavy and the adult ratio is about three cows for every bull.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Calves are suckled until they are 14-16 months old.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Behavior</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">In undisturbed conditions, the banteng's daily activity has a more or less fixed rhythm. During daytime, the animals alternate active and resting periods of 2-3 hours each. The active periods predominantly involve feeding, drinking, and social interactions. While resting, the animals commonly ruminate.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">As a reaction to heavy rains or human disturbances, the animals retreat into dense vegetation. In regions with frequent human disturbance they generally appear in the open only at night. However, where they find particularly suitable localities they become somewhat accustomed to human presence and will venture out in daylight.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Banteng live alone or in small groups of up to eight members. Males separate from their mothers at an age of 2-3 years. Sometimes female calves continue living with their mother even beyond maturity.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Cows and dominant bulls command the best pastures, and young and weaker bulls roam widely, rarely leaving the protection of the thick forest.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The banteng bull has a reputation for extraordinary savagery, but stories of its lightning attack have been exaggerated. Wildlife biologists in Indonesia have not been able to document any such attacks and have no qualms about walking in banteng habitats.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Uses</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Wild banteng show important promise for improving domesticated banteng (see chapter 1) or for interbreeding with cattle (chapter 2). Almost 170 years ago Sir Stamford Raffles, founder of Singapore, noted that in Java "The degenerate domestic cows are sometimes driven into the forest to couple with the wild benteng, for the sake of improving that breed."</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Tourism could be developed in areas where these magnificent animals occur.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Potential Advantages</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Wild banteng are large, robust animals fully at home both in the heat and humidity of the wet season and in the hot dry season. Their genetic </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">endowment for such tolerance could be of significant value fin improving domestic stock.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Possible Limitations</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Wild banteng may prove to have a special susceptibility to diseases of domestic animals. Blackleg (Clostridium chauvoli) and mucosal disease have caused heavy losses in banteng in European zoos.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Capture of wild banteng may prove difficult.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Research and Conservation Needs</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Research on the physiology, production potential, and possible uses of wild banteng is needed.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Hunting and destruction of its habitats menace the wild banteng over all of its range. The only promising means for conservation is creation of nature reserves where hunting and forest destruction are forbidden. Conservation efforts should particularly include:</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">· Supporting government of Thailand efforts to conserve banteng in western Thailand and the Petchabun Range;</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">· Cooperating with the Burmese government in surveys to locate the best banteng habitats;</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">· Cooperating with the governments of Kampuchea and Laos to identify banteng habitats and establish appropriate protective measures; and</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">· Carrying out research in Java's nature reserves (Ujung Kulon National Park and Baluran Reserve) to ascertain the genetic distinctiveness of the banteng, its status, and its characteristics.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">In Sabah and other areas of Southeast Asia there are cattle breeding projects that use imported stock exclusively. Experimental crossbreeding of local banteng with this stock should be encouraged. There are some feral and domestic banteng, as well as hybrids between wild banteng and feral cattle, that should also be tested.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&lt;&lt;I&gt;&gt; p45.png FIGURE</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<B><P>&lt;&lt;TOC3&gt;&gt; 7 Gaur</P>
+</B><P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The gaur (Bos gaurus) would seem to be an ideal meat-producing animal. It is a large bovine with massive muscular development, and it has already been domesticated (see mithan, chapter 3). Gaurs, which are threatened with extinction, deserve much greater attention.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Two subspecies of gaurs are recognized.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">· Bos gaurus gaurus (India, Nepal) </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">· Bos gaurus laosiensis (Burma, Thailand, Laos, Vietnam, Kampuchea, West Malaysia). </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Appearance and Size</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">With its huge head, massive body, and sturdy limbs, the gaur is the embodiment of vigor and strength. It is among the biggest of bovines. Bulls weigh 600-940 kg and stand 1.6-1.9 m tall at the shoulder, but a record bull of 2.2 m and 1,225 kg has been recorded. Cows are only about 10 cm shorter in height, but they are more lightly built and weigh 150 kg less.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">On their shoulders gaur bulls have a striking muscular ridge that slopes down to the middle of the back, where it ends in an abrupt dip. The horns are crescent shaped, creamy yellow, and taper to a sharp point, which is usually tipped in black.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Newborns are a light golden yellow, but soon darken to coffee or reddish brown, the color of young bulls and cows. Old bulls are jet black, their bodies almost hairless. Gaurs have light colored forehead and yellowish or white stockings. Their eyes are brown but in certain lights, because of reflection, they appear blue.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Gaurs excrete an oily, aromatic sweat, unique to this species and to the mithan. It gives the animals a strong bovine smell and may be an adaptation for keeping away insects.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Distribution</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Once common throughout South and Southeast Asia, gaurs now survive only in scattered remnant herds of up to 30 animals in the hill forests of India, Nepal, Burma, Thailand, Laos, Kampuchea, Vietnam, and the Malay Peninsula.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">&lt;&lt;I&gt;&gt; p48.png Gaur distribution. (courtesy of C.H. Wharton)</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Historically, the largest concentrations have coexisted with farmers in areas of shifting cultivation. The animals adjust to disturbed land, and they also adapt to man's presence if not unduly harassed. For example, gaurs will feed in agricultural fields, along roadsides, and near occupied houses. Herds in national parks feed peacefully while tourists stand by. Gaurs in zoos also become quite tame and manageable.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Status</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Populations not protected in parks and reserves are in immediate danger of extinction. Even in the remotest hill forests gaurs are harassed by hunting, exposed to the diseases of domestic cattle, and driven from their natural habitat by human invasion. Most herds outside of parks or wildlife reserves are threatened by agricultural development, hydroelectric dam projects, human settlement, or extensive logging.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">In India, large populations still exist in the larger sanctuaries such as </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Mudumalai and Kanha Park. In Thailand diseases carried by domestic animals, poaching, and habitat destruction have reduced total gaur numbers to fewer than 500. In Malaysia, the population is estimated to be only 400 animals. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Habitat and Environment</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Gaurs typically live on gentle, undulating terrain with natural mineral licks. They inhabit gaps in the forest, such as abandoned clearings, where they can find grasses and shrubs. In the northern portions of their range, they inhabit deciduous and semideciduous hill and mountain forests with light brush and many grassy clearings. In the lowlands they live in open bamboo jungles, grassy plains near forests, or dense forests broken by glades or open meadows. (In the forest they probably depend to some extent on the slash and burn agriculture of hill people.)</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The animals appear to be adapting to increased human presence. They make use of such man-modified habitats as logged forests and fringe areas of agricultural estates that abound with grasses and early secondgrowth vegetation.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Biology</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Gaurs are combination grazers and browsers. They feed on the grasses of forest openings as well as on the young leaves, fruits, twigs, and bark of shrubs and juvenile trees. In one study in Malaysia, grasses comprised 41 percent of their diet, fortes 23 percent, and woody browse 36 percent."</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Gaurs develop large muscular bodies and maintain excellent condition on relatively low-quality feed. In the Malaysian study, crude protein content of grass species varied from 7.0 to 7.6 percent and phosphorus content varied from 0.11 to 0.17 percent; yet calves reached weights of 300 kg or more during their first year.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Birth and survival rates of up to 100 percent have been reported for wild gaur populations. Calves are born at any time of the year. The gestation period is 270 days, a little shorter than for banteng or domestic cattle and longer than for yak or kouprey.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Captive gaurs calve first at 2.5 years of age.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The gaur interbreeds with the mithan, and both have a diploid chromosome number of 2n = 58.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Behavior</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">By nature gaurs are shy and timid. As with most wild bovines, their hearing and eyesight seem comparatively poor. Their defense lies in their massive size and acute sense of smell. When a herd with juveniles is threatened by a predator, the adults form a protective circle around the young. Although individuals retreat from danger if they can, they have a unique form of threat: they approach their opponents broadside instead of head on, displaying the huge muscular body and dorsal ridge.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">In common with other wild bovids, gaurs habitually visit mineral licks, which appear to be necessary to their habitat and influence the herd's movements.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Unlike water buffaloes, gaurs do not wallow. They take cover in the forest during the heat of the day and may feed at night and in the early morning during hot weather. In populated areas such as near agricultural estates, they may feed only at night to avoid people.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">In the past, gaurs associated in loose herds of up to 400 animals, but today groups of only 5 to 12 animals are normally found. The herds, which are of more stable composition than those of banteng, are separated by sex for most of the year; however, during the rut stronger bulls form a series of "tending bonds" with estrous cows.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Uses</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Gaurs are thought to be interfertile with domestic cattle. If so, their attributes of size, massive muscular development, tolerance of heat and humidity, and resistance to diseases and parasites can contribute to beef production in the tropics. A gaur-cattle hybrid might also have immunity to some cattle diseases; if it retained the mild temperament of the domesticated parent, an extremely powerful beast of burden could be produced.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The gaur is a truly majestic animal. Its habit of using grassy forest clearings and salt licks makes it a likely tourist attraction in parks and reserves.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">Potential Advantages</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">In a climate and environment where domestic cattle are susceptible to heat stress and parasite infestation, gaur thrive and maintain body condition. Further, they are able to develop large muscular bodies and maintain excellent body conditions on relatively low-quality forage by feeding on a variety of woody browse, grasses, and fortes.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Retaining its wild instincts for survival, the gaur is better able to withstand predator attacks them domestic cattle. This could be an advantage when animals graze in remote areas. Adult gaurs are strong enough to defend themselves against a predator as powerful as a tiger. In addition, they are also very protective of their young.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Limitations</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Gaurs have little immunity to some cattle diseases. In many regions of India, cattle driven into the forests to graze infect gaur herds with rinderpest, foot and mouth disease, cattle plague, and other contagious diseases. Severe losses occur. Gaurs also appear very susceptible to malignant catarrhal fever.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Gaur numbers are declining throughout their range. If this trend is not reversed, it could effectively prohibit the use of gaur for domestication or crossbreeding purposes.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Gaurs are shy and excitable, making them difficult to catch, but once in captivity the animals calm down. Second generation zoo populations are easily worked and handled.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Gaurs on occasion damage cultivated crops such as young rubber trees and cassava. They require sturdy and well-kept fences.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Research and Conservation Needs</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">In Southeast Asia there is special need to support the efforts of the governments of Malaysia and Thailand to conserve this species and to identify important gaur populations. Similar protective measures are needed in Burma, Laos, Kampuchea, and Vietnam.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Research is needed to establish and manage new gaur herds in forest reserves and build up the gaur population in the world's zoos. Techniques have been developed to capture and release wild gaur safely.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Fertilized gaur ova have been successfully transferred into a foster Holstein cow. The cow carried the gaur fetus to a successful delivery. This could be the forerunner of an important means of rapidly expanding captive herds by transferring gaur embryos into cattle in different parts of the world.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Research is also needed on the basic physiology and production potential of gaur.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Crossbreeding experiments should be started immediately to establish the degree of interfertility between the gaur and other bovine species.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&lt;&lt;I&gt;&gt; p52.png FIGURE</P>
+<P ALIGN="JUSTIFY"></P>
+<B><P>&lt;&lt;TOC3&gt;&gt; 8 Kouprey</P>
+</B><P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The kouprey (Bos sauveli) is the most primitive of living cattle. Its features are typical of some forms that existed in the Pleistocene era, 600,000 years ago. Discovered by Western scientists only in 1937, the kouprey was the last large mammal to enter the biology books. It is perhaps the most primitive of living cattle and is closely allied to Bos namadicus, the wild ancestor of zebu cattle. In 1964 it was declared Cambodia's national animal. It is now perilously close to extinction, and for a decade no koupreys have been observed close enough for a positive identification by a specialist. In 1982, however, five of the animals were believed sighted in Thailand, near the border with Kampuchea. Thus there are hopes that the kouprey still exists.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Appearance and Size</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The kouprey is large. Males stand 1.5-2 m high at the shoulder and may weigh 900 kg. Females are approximately three-quarters the height and weight of the males. The body is slender and long-legged. The hump from the withers to the center of the back is smaller than that of the gaur, but larger than that of the banteng. There is a well-developed dewlap from the throat to the mid-chest, which in old animals is sometimes so pendulous that it drags through the grass in front of the forelegs.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Young bulls are gray, with black on the head and dewlap. Old bulls are entirely black and cows are mouse gray or dullish light brown. As in the gaur and the banteng, the lower parts of the legs have white stockings, but kouprey stockings have a streak of dark hair down the front.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">Kouprey. (P. Pfeffer)</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Kouprey horns are among the longest and widest of any bovine. The tips of the adult male horns are surrounded by rough, frayed tissue caused by the animals' habit of digging in the soil with their horns. The females have slender, lyre-shaped horns that corkscrew upwards, unlike those of any other wild or domesticated cattle.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Kouprey are said to have a grace more reminiscent of deer than cattle. They move at a light trot, as fast as 32 kph.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Distribution</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The kouprey's prevalence in ancient times is evidenced by prehistoric cave-paintings in Kampuchea. The animal was also a favorite of the ancient Khmers, who carved kouprey statues and featured the animal in bas-reliefs on temples, including the monuments of Angkor Wat. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Today, whatever kouprey exist are restricted to an area along both sides of the Mekong River in northern Kampuchea, the Dangrek Range, and other parts of eastern Thailand to the far south of Laos, and to the westernmost part of Vietnam. Although one or two small herds may still exist in remote pockets of Laos and Vietnam, the bulk of the population has always been centered in Kampuchea.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">There are no koupreys in captivity.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Status</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Because of their large size, gregarious behavior, comparatively low reproductive rate, and preference for open areas, kouprey are vulnerable to hunting. The impressive horns and other tissues are valued as trophies and as medicinals.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">In 1964 it was estimated there were about 500 kouprey in Kampuchea, but by 1970 fewer than 70 were left. The subsequent fate of the species is unknown because of the years of warfare in the area. (Early in 1970, the three nominal kouprey reserves of Kampuchea were overrun by military forces.)</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&lt;&lt;I&gt;&gt; p55.png KOUPREY DISTRIBUTION. (AFTER C.H. WHARTON )</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">In 1975 the kouprey stocks in Laos and Thailand were estimated at only 50 and 20 animals, respectively. By now, hunting and habitat destruction probably have all but eliminated the kouprey from Thailand. However, a reported sighting of five animals that had strayed across the border from Kampuchea was made in July 1982. (By the time Thai zoologists arrived to investigate, the herd apparently had crossed back into Kampuchea.)</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Habitat and Environment</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Like the banteng, the kouprey inhabits open sites such as light savannas, woodland meadows, and scattered glades in the monsoon forests. It is adapted to dry country. This type of habitat is not widespread in Indochina, and the range of the kouprey is consequently limited.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Kouprey spend most of the year among low rolling hills in open areas where grazing and visibility are good. These open areas are a fire climax mosaic of dry dipterocarp savannas and patches of dense forest. Fires occur each dry season, most of them deliberately set by man. Kouprey capitalize on the young growth in burned-over areas. They feed primarily on grasses, sedges, and tree leaves. They also require salt licks and a supply of water in the dry season.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Biology</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The gestation period is thought to be about 8.5 months. Cows leave the herd before parturition and return with their calves after about a month. They nurse their calves for about 6 months.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Behavior</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Kouprey are said to be even more shy than banteng and gaur. They feed in erratic patterns and are always alert and nervous.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Loose herds of 20 or more have been reported. These were of mixed composition, often with more than one adult male, and were usually led by an old female. Adult bulls sometimes form bachelor herds.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Kouprey utilize some of the same feeds as wild banteng, and the two animals often live in a loose association. They graze together, and, especially after the mating season, solitary kouprey bulls often associate with banteng herds. The two species do not, however, interbreed in the wild. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Uses</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The kouprey is a candidate for domestication and has important potential as breeding stock. It is a wild animal, but it may have been domesticated temporarily during the Khmer culture, 400-800 years ago.* Both Vietnam and Laos have cattle breeds that resemble kouprey, and a kouprey bull, reputed to be a domestic animal of the Stieng tribe, was exhibited in the Paris Menagerie in the mid-nineteenth century. It may be that kouprey are domestic even today in parts of Indochina.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Potential Advantages</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Kouprey survival has worldwide significance. The animals could be important for studies of bovine evolution and as a genetic resource for crossbreeding to improve disease resistance and other characteristics of domesticated bovines. For instance, the kouprey is thought to be resistant to rinderpest, a killer disease of domestic cattle. Also, kouprey bulls are distinctive for their long dewlap, and they probably have more skin area for their weight than other bovines and are therefore better able to eliminate body heat. This genetic trait may help large cattle breeds survive in the tropics.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Limitations</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The kouprey's potential may be moot - there may be none left in the world. It is feared that the warfare of recent years may have caused its extinction. However, if enough animals survive and can be protected, the kouprey could probably recover its numbers, as a higher calf-to-cow ratio (1:3) was reported for this species than for either banteng (1:4) or gaur (1:10).*</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">If wild kouprey are found, their capture is likely to be difficult.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Research and Conservation Needs</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">There is a long-term sequence of research needs for the kouprey, which includes the following:</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">.  Working with the governments of Thailand, Laos, and Kampuchea to identify any remaining pockets of this species and to establish conservation programs;</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">· Establishing one or more captive breeding herds (because there is little chance of the animal surviving in the wild owing to the fighting and turmoil in the area);</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">· Studying the animal's basic physiology and production potential;</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">· Exploring its possible commercial utilization; and</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">· Investigating the kouprey's genetic relationship to zebu cattle and the transferability of genetic characters through interbreeding. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&lt;&lt;I&gt;&gt; p58.png FIGURE</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<B><P>&lt;&lt;TOC3&gt;&gt; 9 Tamaraw</P>
+</B><P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The tamaraw (Bubalus mindorensis) is related to the water buffalo, one of Asia's most important animal resources, but it has never been domesticated or studied and is threatened with extinction.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Appearance and Size</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The tamaraw looks rather like a miniature water buffalo of the swamp type that is found in Southeast Asia. It reaches about I m in height and 300 kg in weight. It is much more stockily built and is blacker than the swamp buffalo. The tamaraw has white marks on the fetlocks, instead of completely white lower legs like the banteng, gaur, and kouprey. It has short (35-50 cm), very stout horns that curve out and back slightly.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Distribution</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Endemic to the Philippine island of Mindoro the tamaraw is now virtually restricted to three small areas (Mount Iglet/Mount Baco, Mount Calavita, and Sablayon) in Mindoro Occidental.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Status</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Because of its limited distribution, the tamaraw's future is of concern to conservationists. Until World War II, hunting was carefully regulated in its native region and no serious concern was felt for the animal's safety. Since then, however, increases in human population, lumbering, and ranching have restricted the tamaraw's habitat, and the availability of rifles and automatic weapons has seriously threatened its numbers. In 1971, research teams counted 148 head, consisting of 116 adults and 32 calves. The latest estimate is 150-200 head.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Of these last remaining animals, about 80 are located at Mount Iglit, a game refuge established in 1961 primarily to protect the tamaraw. Recently an active tamaraw conservation program has been started in a 400-hectare enclosed area on the refuge. Stockade traps have been built and tamaraw are beginning to move into them. The goal is to establish a small, semicaptive population that can be properly guarded, studied, and managed.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">&lt;&lt;I&gt;&gt; p61.png Tamaraw distribution. (courtesy Wildlife magazine)</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Habitat and Environment</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The habitat requirements of the tamaraw appear to be fairly flexible, and present habitat use reflects human pressures rather than the animal's preferences. In the past, tamaraw were found in virtually all parts of Mindoro, from sea level to mountain tops. They occupied open grasslands or glades, but hunting pressure and habitat change have forced it to retreat into forest environments.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">At present the tamaraw is found primarily in remote areas that have been partly cleared, largely by fire, so that only small pockets of trees remain among coarse grasses such as Imperata cylindrica (a widespread, unpalatable tropical weed commonly called cogon, kunai, alang alang, lalang, or blady grass), and "tahalib" (Saccharum spontaneum). The tamaraw uses the forest pockets for rest and retreat and the open land for grazing. It must have a supply of water for wallowing and drinking.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Biology</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">According to cattlemen, tamaraw eat both Imperata grass and tehalib but only when these are short and green. During the wet season when most forages are tall and unpalatable, the animals are known to feed on bamboo shoots.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Life expectancy is about 20 years. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">Behavior</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Tamaraw are reputed to be nocturnal, ferocious, and retiring. However, in earlier times they were reportedly relatively tame, diurnal animals of open areas. It was the continual hunting that made them increasingly nocturnal and secretive, and like other wild bovids they can become aggressive and dangerous when harassed or wounded. Given effective protection they doubtless would revert to placid, diurnal behavior.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Uses</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The tamaraw appears to be a possible livestock animal. Its meat and hides were highly regarded by local peoples, cattlemen, and visiting hunters. Because of its close relationship to the water buffalo, it may be able to provide genetic material for improving the health and hardiness of that valuable animal resource.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Advantages</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The animal is renowned for hardiness and resilience to heat, humidity, and poor forage, as well as its capability to thrive in a variety of environmental conditions.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Limitations</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Tamaraws have only once produced offspring in a zoo and may prove difficult to raise in captivity. However, they have been kept in captivity so seldom that the prospects are unclear. Experiences with other wild bovids suggests that captivity and captive breeding should be no problem.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Research and Conservation Needs</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The tamaraw must be protected and preserved. There is urgent need, for example, to establish more secure parks in the Philippines to rebuild the wild population to safe levels. Other conservation measures should include:</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">· Establishing and maintaining more reserves in natural habitats containing breeding populations, and</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">· Building up breeding populations in suitable zoos and livestock research centers.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Research is needed on the tamaraw's physiology, production characteristics, behavior, and genetic relationship to the water buffalo. None of these is well understood. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&lt;&lt;I&gt;&gt; p63.png FIGURE</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<B><P>&lt;&lt;TOC3&gt;&gt; 10 Anoas</P>
+</B><P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The lowland anoa (Bubalus depressicornis) and the mountain anoa (Bubalus quarlesi)* are small bovines that are related to the water buffalo but that are scarcely bigger than goats.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Appearance and Size</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Compared with other bovines, the anoa is tiny. It stands only 0.75-1 m tall at the shoulder. The mountain anoa is smaller than its lowland counterpart. The limbs are short, the body plump, and the neck thick.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Anoa horns are short and straight, reaching a maximum length of about 380 mm; they are ringed and triangular in cross section at the base in lowland species and simple and conical in cross section in mountain species.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Although the young are thickly covered with yellowish-brown woolly hair, the mountain anoa adults tend to have curly hair, while lowland anoa have straight hair or are hairless. Adults vary from dark brown to black, with frequent blotches of white on the face, nape, throat, and lower limbs. In mountain anoas the entire lower limbs are creamy white. The underbody parts are usually light brown. Males are generally darker than females.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The hide is exceptionally thick.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Distribution</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Anoas are native to dense, mature forests of Sulawesi in eastern Indonesia.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">Status</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Both species are abundant and well distributed on Sulawesi. Most of the northern, eastern, and southeastern peninsulas and the central area of Sulawesi are still forested and have anoa populations, and there are several large nature reserves to protect them. *</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Several of the world's zoos have anoa collections (see Research Contacts).</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Habitat and Environment</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The climate of Sulawesi is hot, but tempered by sea winds; annual rainfall varies from 500 mm to 4,000 mm. The eastern and southeastern peninsulas have a sparse population and a scattering of subsistence agriculture.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The lowland species is found in forests and was once common along the coasts. The mountain anoa is found in primary forests at high altitudes.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">&lt;&lt;I&gt;&gt; p66.png DISTRIBUTION OF ANOA</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Biology</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Anoas have a wide-ranging diet that includes grasses, ferns, saplings, palm, ginger, and fallen fruit, especially figs. It is of particular interest that the animals can live on a diet that contains no grass.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Anoas have a high requirement for minerals. They visit mineral-rich hot springs and salt licks, and they even drink from the sea.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The San Diego Zoo in the United States and Surabaya Zoo in Indonesia have successfully bred and reared the animals in captivity. The gestation period is 276-315 days, and there is generally only a single birth. The life expectancy is about 20-25 years.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Behavior</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Anoas are shy animals, but they can be aggressive. The sideways and upwards stab of their straight, sharp horns can be dangerous.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Except when the cows are about to give birth, anoas apparently associate in pairs rather than in herds. They enjoy water and frequently wallow in mud. Their gait is a trot, but a times they make clumsy leaps. During the morning they feed alone. In the heat of the afternoon they seek refuge under shade trees.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Uses</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">On Sulawesi anoas are prized for their hide, horns, and meat. The flesh, especially that of calves, is tender and well flavored.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Potential Advantages</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Although somewhat aggressive and pugnacious, anoas might make a suitable livestock animal. They grow and reproduce well in captivity and are adaptable and intelligent. Their small size makes them easier to handle than many other wild bovines.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">Limitations</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Little is known about the habits of these animals because of their wary nature, secluded environment, and restricted range. They can be tamed enough to obey commands ("lie down," for example) but they remain nervous and likely to butt strangers.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Research and Conservation Needs</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Surveys are needed throughout Sulawesi to determine the distribution and taxonomy of possible races of the two species, with a view to establishing a protected-area system that will ensure the survival of the genetic diversity of this group.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Research is also needed on social organization and tameability, as well as on the anoa's biological relationship to the tamaraw and water buffalo.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">One target should be to build up the zoo populations of both species. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&lt;&lt;I&gt;&gt; p68.png FIGURE</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<B><P ALIGN="CENTER">&lt;&lt;TOC2&gt;&gt; Part IlI : Pig and Piglike Species</P>
+</B><P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">In parts of Asia wild and feral pigs are often the most abundant source of meat. These animals are predominantly variants of the domestic pig, Sus scrofa, or of its ancestor, the Eurasian wild boar. Also contributing to the pig population are five Asian species:</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">· Bearded pig</P>
+<P ALIGN="JUSTIFY">· Sulawesi warty pig</P>
+<P ALIGN="JUSTIFY">· Javan warty pig</P>
+<P ALIGN="JUSTIFY">· Pigmy hog</P>
+<P ALIGN="JUSTIFY">· Babirusa</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">In Southeast Asia hybridization between these species and common pigs has resulted in a confusing diversity of forms and interrelationships. Because of their value, these pigs have been spread since prehistoric times by traders and migrating peoples, creating odd and unpredictable distribution patterns.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The species listed represent a gene pool of potential importance for the further development of one of man's most important sources of food. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">In many areas of the world, one must start with the native animals adapted to that environment. In many cases, they are the only animals the native human population can afford to begin with. And it is amazing the increased animal production that can result from the use of better production practices with them. TONY J. CUNHA, Dean Emeritus California State Polytechnic University Pomona, California, USA </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Fitting the animal to the vegetation might be a better approach than trying to fit the vegetation to the animal, especially on ranges that have been changed or degraded by man. JAMES TEER, Director Texas Parks and Wildlife Department, Austin, Texas, USA </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">There is now widespread realization that breed importation is not necessarily the quickest route to increased animal production. Indigenous, adapted breeds should be examined more closely and, where necessary, steps should be taken to ensure conservation of at least some of them. HELEN NEWTON TURNER Genetics Research Laboratories, CSIRO, North Ryde, New South Wales, Australia </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Maximizing the animal harvest, essentially of animal protein, assumes in concept that all animals will be fully exploited in efficient and economic production systems. C.DEVENDRA Malaysian Agricultural Research and Development Institute, Selangor, Malaysia </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&lt;&lt;I&gt;&gt; p70.png FIGURE</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<B><P>&lt;&lt;TOC3&gt;&gt; 11 The Bearded Pig</P>
+</B><P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Although it apparently has never been domesticated, the bearded pig (Sus barbatus) has a long history as an important resource in Southeast Asia. Human remains from the Niah Caves in Sarawak are accompanied by large numbers of its bones and teeth, indicating that 40,000 years ago it was the most commonly eaten large animal. Today in Sarawak and some other areas the bearded pig is still probably the most sought after source of wild meat.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Appearance and Size</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Bearded pigs are large. Boars measure 1-1.6 m in length (crown to rump), up to 1 m in height, and may weigh as much as 150 kg. Sows are smaller. Adult males have small facial warts (infraocular and preocular) and a bushy tuft of hair on the cheek. Both sexes vary in color from pale red-brown to yellow-brown or black. They have elongated skulls with longer, more flexible snouts than the common pig.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Distribution</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Five subspecies are recognized. They range through the Philippines (Balabac, Palawan and offshore islands, Calamianes, Luzon, Mainit, Mindanao, Jolo, Mindoro, and Cebu) to Borneo, Bangka, Sumatra, the Riau Archipelago, and the Malay Peninsula.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Status</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The Borneo subspecies (Sus barbatus barbatus) is still abundant in some parts of Sabah, Sarawak (including several wildlife reserves), and </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Kalimantan. It remains an important food resource for some hill tribes, although with the spread of Islam, attitudes toward pork are changing in some areas. The Malayan subspecies (Sus barbatus of) is now rare in the Malay Peninsula. It is also becoming rare in Sumatra as the lowland forests are logged and broken up by commercial interests and as the human population expands. The status of the three Philippine subspecies is currently unknown.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Habitat and Environment</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The bearded pig is most commonly found in both primary and secondary evergreen forests. However, it seems to have wide adaptability, and in Sarawak bearded pigs are found in virtually all habitats from the beaches to the upland rain forests.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Biology</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">No biological research has yet been conducted on bearded pigs, but naturalists have made several observations. The pigs eat the seeds of trees (for example, those of species of Dipterocarpaceae and Fageceae), fallen fruits (of Moraceae, Bombacaceae, and other plant families), roots, stems of wild bananas, herbs, and probably earthworms, and along the coast they dig up and eat turtle eggs.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Births occur throughout the year in Sabah, but the peak coincides with the fruiting season of forest trees, usually August-September. The litter size is from 3 to 11 piglets.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&lt;&lt;I&gt;&gt; p73.png FIGURE</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">Behavior</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">No behavioral studies have been conducted, but observations suggest that bearded pigs are generally sedentary animals, although in some areas they congregate into large groups that may travel long distances together.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Uses</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The species might be used (alone or together with other pig species) as a local source of meat, or even as the foundation of a meat industry. The bearded pig is accustomed to living in groups, which may make it suitable for husbandry or game management.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">There is evidence that the bearded pig will interbreed with the common pig, producing young in which both sexes are fertile.* The progeny might have considerable hybrid vigor.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Potential Advantages</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The bearded pig may have tolerance (if not actual resistance) to tropical diseases and conditions that affect the common pig. The species survives in areas of Southeast Asia where feral herds of common pigs are not common, apparently owing to their inability to cope with disease or other environmental challenges.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Limitations</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">No negative qualities have been reported, but the animal's biology, behavior, management, and potential uses are so far virtually unstudied.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Research and Conservation Needs</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Aspects of the animal's general biology that should be investigated include:</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">· Chromosome type and variability, and chromosomal differences between the bearded pig and other wild and domesticated pig species</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">· Reproductive physiology</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">· Nutritional physiology</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">· Social behavior (both in its wild state and under controlled conditions).</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">To assist in the selective capture of young bearded pigs in the wild, external features that characterize the species at an early age need to be identified.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">To assess the bearded pig's potential for contributing hybrid vigor, crossbreeding with other pig species should be attempted under controlled conditions.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<B><P>&lt;&lt;TOC3&gt;&gt; 12 The Sulawesi Warty Pig</P>
+</B><P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The Sulawesi warty pig (Sus celebensis) is one of the world's few domesticated animals. It is maintained as a village or household animal in a few areas of Southeast Asia, such as on the Indonesian island of Roti. The common pigs of New Guinea and parts of the Moluccas group are hybrids between this species and the common pig.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Appearance and Size</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Sulawesi warty pigs are medium sized, averaging about 60 cm high and 40-70 kg. Boars are larger than females and have longer (10 cm) tusks on both jaws. Boars have three pairs of prominent facial warts: on the snout, the cheek, and on the angle of the jaw. In sows these warts are small or absent entirely.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The animals are usually red-brown with sharply marked white and yellow undersides; older animals have a round white spot (about 3 cm in diameter) on each side of the upper cheek. Piglets have horizontal stripes on the body, which disappear as they mature.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The body is covered with scanty coarse hair, but stiff bristles, which become erect when the animal is alarmed, occur along the mid-dorsal line of the body. The longest and stiffest occur on the head and nape.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Distribution</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Native to mainland Sulawesi and certain surrounding islands, the Sulawesi warty pig has been introduced to the Lesser Sunda Islands (Flores, Sumba, Roti, Semau, and Timor), the Moluccas (Malmahera and Buru), and Simaleue, a small island west of Sumatra. In some parts of the Philippines (for instance, Naujan and Mindoro Oriental) the animal either occur naturally or has been introduced. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Hybrids between the Sulawesi warty pig and the common domestic pig occur on New Guinea, Ternate, Morotai, Bacan, Amron, Seram, Kei island, Aru island, and Sulawatti.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Status</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">In many islands of eastern Indonesia, this species is widespread and common. In a few places it is extremely abundant, particularly at higher altitudes; in others, it has been greatly reduced by overhunting, deforestation, and expanding human settlement.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Overall, however, Sulawesi warty pig populations are declining, probably due to increased hunting and to human alterations of the animal's habitats.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Habitat and Environment</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">This pig inhabits varied environments, including rain forest, mountain forest, grasslands, and agricultural areas.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&lt;&lt;I&gt;&gt; p77.png FIGURE</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">Biology</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Like the common pig, the Sulawesi warty pig has broad dietary preferences. It feeds on roots, fallen fruit, leaves, and young shoots. The bulk of its food consists of vegetable materials, but it also feeds on earthworms, insects, aquatic invertebrates, rats, birds, and even carrion.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The uterus and placenta are anatomically indistinguishable from those of the common pig. The litter size is from 2 to 8 piglets, with an average of 5.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Sows can give birth throughout the year, but usually have their young in April or May. The gestation period is about 4 months.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Behavior</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Breeding and farrowing occur in the forest and in open Imperata cylindrica grasslands. The pregnant female makes a nest of grasses, leaves, twigs, and branches, which she collects and places over a hole (approximately 2 m long) that she has previously dug. Here she gives birth.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Foraging is the main activity of the day and usually takes up several hours, mainly in the early morning and evening. In the wild the pigs travel in small groups, the young always traveling with an adult female. On the move, warty pigs feed and rest intermittently.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Uses</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">As a source of meat the Sulawesi warty pig has been recognized and exploited by local populations since prehistoric times. The presence of feral specimens far outside the pigs' natural range indicates that traders or migrants have long carried it with them on voyages, either as domestic stock or as wild specimens to be released for later capture.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The tusks, which can be carved like ivory, are a resource for local artisans. Wild specimens are suitable for sport hunting.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Potential Advantages</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">There is a body of unrecorded indigenous experience with this animal as a domesticate, but the information needs to be collected and appraised.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">The Sulawesi warty pig may be expected to possess resistance or tolerance to the many diseases prevalent in its native habitat.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">There is promising potential for hybridization between this species and domestic pigs, which might lead to the improvement of common pigs in tropical regions.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Limitations</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Apart from the unwritten knowledge of the indigenous people who raise the species, very little information is available on the characteristics and management of this animal.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Research and Conservation Needs</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The genetic variability within the species, as well as the karyotypic differences with common pigs and other Sus species, should be defined. Further, the hybrid vigor resulting from crossbreeding with other Sus species should be- quantified under controlled conditions. Apart from producing potentially important heat-tolerant livestock, crossbreeding may shed important light on the origins of the common pig in Asia.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The animal's nutritional requirements and reproductive biology also need study. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&lt;&lt;I&gt;&gt; p79.png FIGURE</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<B><P>&lt;&lt;TOC3&gt;&gt; 13 Javan Warty Pig</P>
+</B><P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The Javan warty pig (Sus verrucosus) apparently has never been domesticated, but it has been a resource for hunting peoples for centuries. Now, however, the human population in its native region is predominantly Moslem, and all pigs are widely regarded as agricultural pests. Increasing numbers of them are poisoned each year.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Appearance and Size</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The Javan warty pig can be up to 1.35 m long and 0.9 m tall. Mature males usually weigh between 80 and 120 kg; females are only half that weight - an unusually dramatic example of sexual dimorphism. The animal has a markedly elongated face with large warts, particularly the infraorbital wart and the smaller preorbital and mandibular warts. Body hairs can be black, red, or yellow, with black tips.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Distribution</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">This species is found only on the Indonesian islands of Java and Bawean. It was formerly found on Madura as well, but because of deforestation it is now thought to be extinct there. Two extant subspecies are recognized. The nominate one, Sus verrucosus verrucosus, occurs on mainland Java. The second, Sus verrucosus blouchi, a smaller animal, has recently been described on Bawean.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Status</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">For years it was thought that the Javan warty pig was extinct in the wild, but in October 1981 a herd was found in a small area on Mount Penanggungan in East Java. This population may prove to be substantial, and there is reason to hope that other populations can be found. Overall, however, it is clear that the Javan warty pig is endangered and declining in numbers. In many areas the animals are subjected to uncontrolled poisoning and hunting.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Five new reserves have recently been proposed to protect the animal in a variety of habitats because it is not found in appreciable numbers in any of Java's nature reserves.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The Bawean subspecies is believed to be relatively secure since the establishment of a large reserve.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">A breeding colony of 12 Javan warty pigs at the Surabaya Zoo includes 5 young ones born in captivity.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Habitat and Environment</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Habitats of the Javan warty pig appear to be confined to elevations below about 800 m. The animals prefer relatively large expanses of grassland or secondary vegetation, where human population is sparse. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&lt;&lt;I&gt;&gt; p82.png FIGURE</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">Biology</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The piglets can be born throughout the year; in one study of 8 sows the litter size ranged from 2 to 8, with a mean of 5.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The (diploid) chromosome number has been found to be 38, the same as that of the common pig. Hybridization between these species is thought to occur in the wild, but apparently not with enough frequency to contaminate the Javan warty pig gene pool.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Behavior</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Unreported.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Uses</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">These are omnivorous, adaptable animals that might make useful domesticates.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Potential Advantages</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The small size of the sows could make this species particularly appropriate for households or smallholder farms. The animal's genetic "distance" from the domestic pig may make it a useful generator of hybrid vigor in crossbreeds. It could have particular value because its meat is much leaner than pork from the common pig.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Limitations</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The numbers in the wild are now too few to permit any cropping.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">Research and Conservation Needs</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Efforts should be directed towards locating and breeding up the Javan warty pig populations that still exist. An immediate need is to isolate pure populations in reserves because it is essential to protect the animal from crossbreeding with other species. In addition, current specimens in zoos should be cataloged and a breeding program established. Other captive breeding colonies should also be started.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">It is important to determine the genetic differences between the Javan warty pig and the common pig, as well as the levels of existing hybridization between them. It is also necessary to determine what variation in karyotype may exist within the populations.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Basic ecological and behavioral studies are needed, as well as studies of the dietary requirements, growth rates, and nutritional physiology of captive specimens. The reproductive biology of the animal should be studied, and the possibility of crossbreeding it with other Sus species should be examined under controlled conditions.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The Javan warty pig's potential for local meat production should be evaluated. The benefit to rural people of converting an agricultural pest into a profitable source of income should be explored within the local religious context. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&lt;&lt;I&gt;&gt; p84.png FIGURE</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<B><P>&lt;&lt;TOC3&gt;&gt; 14 Pigmy Hog</P>
+</B><P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The pigmy hog (Sus salvanius), a shy and very small pig of northeastern India, is close to extinction because of hunters and the destruction of its habitat.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Appearance and Size</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The pigmy hog is only about 60 cm long, with a shoulder height of about 25 cm and a body weight of less than 10 kg. The hair is medium brown on the sides, darkening to blackish brown along the mid-dorsal line. A facial band of short, dark hair extends from the bridge of the nose to below the eye. The tiny tail is only 3 cm long.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Distribution</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">This animal was once widely found along the southern foothills of the Himalayas; today, it is definitely known to occur in only one area, the Manas National Park in Assam.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Status</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Pigmy hogs are seriously endangered; in the wild they are close to extinction. Captive animals are now reduced to a single male in the Assam State Zoo and four male siblings in the Zurich Zoo.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Habitat and Environment</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The few remaining pigmy hogs mainly inhabit tall-grass savannas, but it seems likely that they could adapt to other environments. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Pigmy hog. (W.L.R. Oliver)</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Biology</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The animal is omnivorous and consumes roots, tubers, grass, leaves, insects, earthworms, eggs, and carrion. While foraging, it undoubtedly consumes large quantities of earth as well.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The chromosome number, 38, is the same as that of the common pig. The karyotype is similar to that the common pig, but small, significant differences have been demonstrated using chromosome banding techniques.*</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The age at puberty, time of weaning, length of gestation and estrous cycle, and season of breeding are not yet known with certainty. However, the animal is known to have a single well-defined birth peak (April/May) that coincides with the onset of the rainy season when the food supply increases. The uterus and placenta are anatomically similar to those of the common pig. The litter size varies from 2 to 6. It is not known if the animal can be crossbred with the common pig.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">&lt;&lt;I&gt;&gt; p87.png Distribution of pigmy hog. (W.L.R. Oliver)</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Behavior</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The animals are shy, but can be tamed. They tend to forage and run in groups. Nest building is carried out by both males and females and is not restricted to pre-farrowing periods.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Uses</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">There is no evidence that the pigmy hog has ever been domesticated; it has, however, been extensively hunted and trapped, and recently it was still being sold for human consumption. There would probably be no inherent difficulty in maintaining this species in husbandry.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Potential Advantages</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The pigmy hog's small size may make it useful in studies of the physiology of pigs and like mammals. In particular, a study of the uterine capacity may contribute to our understanding of the maternal factors that influence the number and size of mammalian young at birth.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">It is unknown if the animal carries genetic resistance to diseases of the domestic pig, but given its habitat, such resistance seems likely.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Limitations</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The small numbers of surviving pigmy hogs obviate any consideration of its use in husbandry at the present time. Moreover, its nervous temperament might restrict its potential as a domesticate. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Research and Conservation Needs</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">It is essential to ensure the survival of this animal. Efforts should be directed towards locating and breeding up the populations that still exist. If its habitat could be protected by preventing the annual dry-season burning of grasses, it is possible that substantial populations could be established. Attempts should also be made to acquire two or more females as mates for the male pigmy hogs at the Assam and Zurich zoos.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">There is also an urgent need to ensure that the animals breed successfully in captivity, and the wealth of international expertise in pig reproduction should be applied to that end. For example, the reproductive biology of the animal could be studied by swine experts; the age at puberty, the length of the estrous cycle, the season of breeding (and whether it is influenced by light or temperature), the length of gestation, and time of weaning all need to be determined.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The animal is an omnivore, but the physiology of its digestion has not been studied. Thus, its nutritive requirements are not well enough known to ensure its survival in captivity or reserves.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Experiments should be made to determine if pigmy hog embryos can be brought to term in the uterus of the common pig. If so, such embryo transfers could be used to distribute embryos and set up new herds, lessening the risk of this species" extinction.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&lt;&lt;I&gt;&gt; p88.png Adult male of the common pig (wild boar Sus scrofa) and pigmy hog drawn to the same scale. (W.L.R. Oliver) </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<B><P>&lt;&lt;TOC3&gt;&gt; 15 The Babirusa</P>
+</B><P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The babirusa (Babyrousa babyrussa) is a piglike animal whose closest relative appears to be an ancestral animal that lived in Europe 35 million years ago. It is easily tamed, and in its native area there is an ancient tradition of raising young babirusa for meat and for the males' unique tusks. The animal appears to reproduce well in captivity, and with good management techniques it might gain wide use in the tropics.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Appearance and Size</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Male babirusa can be up to 110 cm long and 80 cm tall and weigh up to 100 kg; females are smaller. The male has large upper canines that grow upwards, piercing right through the flesh of the snout and curving back and downwards towards the forehead without ever entering the mouth. The female may sometimes have small upper canines projecting through the skin of the upper lip.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The animal is more slender than a pig of similar size. It has a gray or brown-grey skin color, although one subspecies, Babyrousa babyrussa babyrussa, has light body hair that is fawn colored or black.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Distribution</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The babirusa is unique to a few islands of eastern Indonesia: north, central, and southeast Sulawesi, the Togian Islands, and the Sula (Taliabu and Sulabesi) and Buru Islands. On Sula and Buru it is probably not native but was introduced in prehistoric times.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Status</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">On Sulawesi the babirusa remains abundant, despite hunting and the widespread clearing of the forest. Nevertheless, disturbances created by wood and rattan collectors, hunters, loggers, and farmers threaten the babirusa's survival. Throughout the rest of its range, it is also vulnerable to extinction.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Biologists are particularly concerned about some of the babirusa subspecies. The one from the north of mainland Sulawesi, Babyrousa babyrussa celebensis, is still relatively abundant in places and is probably in no immediate danger. The Togian Islands' subspecies, Babyrousa babyrussa togeanensis, is abundant in small islands but is threatened by Indonesia's settlement programs and deforestation. The Buru and Sula Islands subspecies, Babyrousa babyrussa babyrussa, may already be extinct; there have been no confirmed sightings in recent years.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">In 1981, there were 26 male and 27 female babirusa held in six zoo collections; 22 of these animals are in the Surabaya Zoo in Indonesia, where they breed well. Most, if not all, are believed to belong to the mainland Sulawesi race.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Habitat and Environment</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The animals mainly inhabit moist forests at low altitudes.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&lt;&lt;I&gt;&gt; p91.png FIGURE</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">Biology</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Precise details of babirusa biology are unknown, but the stomach has an extra sac, suggesting that the animals may have some ability to break down cellulose. Indeed, they browse leaves, a behavior more often found in a deer than in a pig, and have been referred to as "ruminant pigs." Babirusa also live on roots, berries, and grubs, making them true omnivores. Compared to other pigs, they do little rooting, and in captivity their enclosures remain quite grassy.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Babirusa are said to be sexually mature at 5-10 months, but this depends on nutrition. Gestation length is about 158 days. One or two young are produced although there are some reports of litters of three.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">One specimen was kept for 24 years in captivity.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">Behavior</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The babirusa is a social animal that moves in groups. A retiring native of the dense jungle, it is a fast runner and swims readily. Mating behavior in captivity generally resembles that of domestic pig. Evidence from zoo animals suggests that the male must be removed from the young at birth but that by the time they are a month old the young are safe from paternal attack.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Uses</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">When captured young or reared in captivity, the babirusa is easily tamed. It has potential as a domesticated species, and with appropriate management may provide a useful source of meat. The meat is tasty and of good quality.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Because of its unique tusks, the skull of the male finds ready markets. This could provide additional income to farmers raising babirusa for meat. The ivory of the tusks could also be a resource for local artisans.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Potential Advantages</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">As noted, the anatomy of the stomach suggests that the babirusa may be able to make more efficient use of fibrous foodstuffs than other pigs.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Limitations</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The babirusa produces only one or two young after a gestation period of just over five months; it may therefore take considerable time to build up herds.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Although the babirusa is easily tamed, it is not known whether it can be husbanded in large groups. Also, present lack of knowledge of the animal's nutrition may restrict its husbandry.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Research and Conservation Needs</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The number of animals in the wild is decreasing, and attempts should be made to determine their exact status. Particular attention should be paid to the subspecies Babyrousa babyrussa togeanensis and Babyrousa babyrussa babyrussa. Captive breeding programs for these subspecies should be started.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&lt;&lt;I&gt;&gt; p93.png When seen in longitudinal section, the stomach of babirusa presents striking similarities  to that of a relatively simple ruminant such as the domestic sheep. Every part except the  omasum, even including a rudimentary reticulum, is represented and occupies the same  relative position. The babirusa stomach differs from that of the domestic pig chiefly in  the enormous size of the diverticulum ventriculi, the prominence of the constrictions  that delimit its three main divisions, and in the size and complexity of the cardia. Regions  corresponding to parts of the ruminant stomach are labeled in brackets. (Information  from Davis, 1940; diagram courtesy Field Museum of Natural History, Chicago.)</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Wild populations should be maintained in several regions to ensure that  the species" genetic base is retained. Advantage could be taken of the large  number of islands in eastern Indonesia to establish reserves for the different  babirusa subspecies.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Currently, little is known about the biology of the animal in the wild its  diet, social behavior, or reproductive performance are almost unstudied. In  view of the relatively small number of babirusa in zoos and the scarcity of  information about the animal's growth rate and general biology, coordinated  studies between zoos could provide much basic information. It has been  suggested that a studbook be initiated for this species.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">It is clear from chromosome analysis that this pig differs markedly in  its karyotype from that of other pigs. However, more anatomical and  biochemical knowledge is needed.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Basic parameters of the animal's reproductive physiology are not known.  Questions to be answered include:</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">· Can the babirusa be induced to reproduce twice per year?</P>
+<P ALIGN="JUSTIFY">· Can babirusa embryos be developed to term in the uterus of the domestic  pig? If so, can the number of babirusas be rapidly multiplied in this way?</P>
+<P ALIGN="JUSTIFY">· Does the babirusa genotypic and gestation-length difference with the  common pig prevent the two from successfully crossbreeding? And if  crossbreeding can be achieved, will the progeny be fertile?  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&lt;&lt;I&gt;&gt; p94.png FIGURE</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<B><P ALIGN="CENTER">&lt;&lt;TOC2&gt;&gt; Part IV : Recommendations and  General Research  Needs</P>
+</B><P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The Asian animals described in this report are a natural resource whose  potential is barely glimpsed. They are virtually unknown to established  livestock interests and there has been little thought to developing them as  livestock. As a result, the research and trials that could lead to further use of  these animals is scattered, small scale, and conducted outside the mainstream  of livestock science, mainly by wildlife conservationists.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Yet these animals seem worth considering for use in husbandry in many  tropical regions, especially where poor grazing and harsh environments limit  the performance of conventional livestock. There is a pressing need for  research to develop these species and to explore their potential. Only through  rapid action can many of them be kept available for study and possible  inclusion in agriculture.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">One suggestion is that funds be provided to establish an Asian  native-livestock research-support team. Its primary purpose would be to  assist in the funding of research projects and to coordinate research being  done in various Asian countries. The team's goal would be to establish a  network of animal scientists based at institutions in Asia and elsewhere to  work cooperatively on the region's little-known bovines and pigs. In this  manner, relatively small sums of money could be used to stimulate and  coordinate Asia-wide research on indigenous animals.*</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Basic Research</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The time has come for basic studies on each of the 15 animals discussed in  this book. For each species, the following areas should be investigated:</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">· Physiology</P>
+<P ALIGN="JUSTIFY">· Reproductive requirements and fertility</P>
+<P ALIGN="JUSTIFY">· Nutritional requirements (such as food preferences, feeding strategies, and food utilization)</P>
+<P ALIGN="JUSTIFY">· Growth</P>
+<P ALIGN="JUSTIFY">· Adaptability and environmental tolerance (for instance, water balance, sweat rate, and shade-seeking habits, as well as temperature, pulse, and respiration rates, both under normal conditions and heat stress)</P>
+<P ALIGN="JUSTIFY">· Diseases</P>
+<P ALIGN="JUSTIFY">. Management (including stocking rates and other production characteristics</P>
+<P ALIGN="JUSTIFY">· Genetic selection for calm temperament, quick growth, and other desirable qualities</P>
+<P ALIGN="JUSTIFY">· Crossbreeding to take advantage of hybrid vigor</P>
+<P ALIGN="JUSTIFY">· Social structure (for example population density and distribution, social organization, leadership, herding potential, aggressiveness of bulls)</P>
+<P ALIGN="JUSTIFY">· Habitat characteristics (behavior-habitat interactions and herd dynamics, for instance).</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Studies are also needed on better utilization of products, such as milk, meat, hides, horn, and hair, from these animals.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Experimental transfer of fertilized eggs of all of these animals into domestic species should be explored with a view to establishing herds in secure and disease-free areas.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Efforts specific to domesticated and wild species, and to hybrids of these species, are discussed below. The report concludes with brief discussions of a few promising species not taken up in the body of the text.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Domesticated Species Improving Performance</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Little data is available on the performance of the domesticated animals discussed in this report. Yet the main value of these species lies in the new and superior genes and gene combinations that can be adapted to animal production in the tropics.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Studies need to be conducted with the indigenous species and strains in their native countries to determine if they will respond to improved conditions with improved performance. These projects could provide opportunities for geneticists and animal breeders to improve livestock production while conducting challenging basic research. It would be helpful to establish studbooks of captive specimens and to select and breed for desirable genetic qualities.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Genetic improvement must be directed towards remedying production deficiencies. Methods include selection of superior breeding animals, crossbreeding, and combinations of selection and crossbreeding. Different genetic improvement techniques will be required for each species. Progress should be regularly monitored against the unselected animals and the domestic livestock breeds.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">New Introductions</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Tropical countries should import breeding stock to evaluate the performance of some of these Asian animals in the local environment. Strict quarantine procedures must, of course, be observed.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Special emphasis should be placed on the domesticated banteng of eastern Indonesia. These animals are already an important source of human food and they may have considerable potential for increasing production elsewhere.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Wild Animals</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Wild animals contribute extensively to the welfare of people and economies of developing countries. In many areas they supply much of the animal protein consumed. But the contributions they make are largely unrecorded, and local officials and aid agencies seldom regard wildlife as an economic resource. As a result, few developing countries have analyzed how their people use indigenous animals for subsistence, and few nutritional studies recognize "bushmeat," although large numbers of people eat it.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Wildlife's contribution justifies more detailed and precise evaluations. In many tropical regions few people even know what species are present, let alone in what numbers. Ecologists and animal scientists should be employed to identify and collect data on the fauna of the tropical forests and how it is used by local people. Their work will provide baseline information on the species present and on the potential utility of the undisturbed natural ecosystems.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Initial Needs</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">All wildlife utilization must be based on a thorough knowledge of the resource, its numbers, the animals' condition, annual recruitment in the </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">various populations, and the seasonal movements of the herds. In addition, it is important to understand the interactions of the species with its habitat.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Thus, the immediate need is for action to assure the preservation of populations of these animals until research studies can be conducted.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">In this regard, priority actions include the following:</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">· Establishing adequate preserves</P>
+<P ALIGN="JUSTIFY">· Providing total protection for remaining animals</P>
+<P ALIGN="JUSTIFY">· Preventing poaching.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">With few exceptions, the wild species described in this report are under the pressures of agricultural and human expansion. Without efforts to preserve their habitats it will be difficult for these species to survive.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Developing Wildlife Resources</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Governments cannot stop hungry people from hunting game, but they can use this impetus to help protect some indigenous animals as well as forest and woodland habitats. Fostering the production and supply of wild animals such as those described in this book could open up a new: source of meat and other products, particularly for subsistence farmers in remote areas. In the last analysis, this may be the only way of protecting and maintaining these animals and developing local awareness of their value.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">International economic development organizations have traditionally shown little interest in wildlife or wildlife habitats. Yet maintaining these animals and their habitats is crucial to the continuing supply of many indigenous food animals, the most important of which are often the smaller ones that flourish in secondary growth. And the forests that support wildlife also protect some of the huge investments that AID, the World Bank, and other other agencies have made to help developing countries. The forest is the sponge that absorbs the water from tropical rains. Without trees covering the watersheds, heavy rains cause rushing water that erodes the land, despoils highways, silts up dams and reservoirs, knocks out bridges, and inundates towns, villages, and farm fields.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">In principle, the farming of tropical wildlife could become a force in preventing clear-felling of the tropical forests. Rational utilization of tropical animals offers productive alternative use of the land. In some cases, the farming of indigenous animals can fit smoothly into tropical habitats and into traditional village life, because the livestock and its needs are usually familiar to local people and are often ingrained in their traditions.( For successful examples see companion reports nos. 44 and 45, Butterfly Farming in Papua New Guinea and Crocodiles as a Resource for the Tropics. </P>
+<P ALIGN="JUSTIFY">Hybrid Animals)</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">Hybridization may offer new prospects for using underexploited tropical animal resources. This is a speculative notion, but it deserves serious attention.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Crossbreeding between the animals mentioned in this report holds exciting possibilities for expanding livestock options in the tropics. Some of the crosses, known or envisaged, are:</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">· gaur x cattle</P>
+<P ALIGN="JUSTIFY">· banteng x cattle</P>
+<P ALIGN="JUSTIFY">· kouprey x cattle</P>
+<P ALIGN="JUSTIFY">· yak x cattle</P>
+<P ALIGN="JUSTIFY">· yak x banteng</P>
+<P ALIGN="JUSTIFY">· anoa x water buffalo</P>
+<P ALIGN="JUSTIFY">· tamaraw x water buffalo</P>
+<P ALIGN="JUSTIFY">· domestic pig x warty pigs</P>
+<P ALIGN="JUSTIFY">· warty pigs x bearded pig</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Care must be taken, however, to guard against the dilution of wild genes by the escape of hybrid or interbreeding domestic species, or the establishment of feral hybrid populations.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">International Exchange of Pig Germ Plasm</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Present veterinary restrictions effectively prevent the movement of pigs between most countries. Relatively few species of wild pigs are therefore maintained in zoos outside their countries of origin. This stifles the promising potential for the species described in Part III, as well as for captive-breeding safeguards and research on the endangered species. It is important that attempts be made to identify channels for the future establishment of viable captive stocks both within Asia and elsewhere. Transfer of embryos should be verified as a means of permitting disease-free movement across frontiers.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Species Not Covered in this Report</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">This project, which began as a short report on banteng, quickly developed momentum as it brought in suggestion after suggestion of further species. Through pressures of time and budget, it was not possible to take up all of these interesting animals. Some of the omitted ones are listed below. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Takin (Budorcas taxicolor).* A heavily built, Southeast Asian hoofed mammal of the family Bovidae, the takin lives in small herds in the mountains, often above timberline. Though robust and short-legged, it can move about quickly and easily over difficult slopes. It stands up to about 1 m at the shoulder and has a shaggy yellowish- to blackish-brown coat. Both sexes have heavy horns that turn outward from the center of the forehead and then curve up and backward.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Goral (Naemorhedus goral).* This small Asian goatlike bovine has slightly backward curving cylindrical horns and a coarse brownish-grey coat. It is related to the chamois and serow (see below) but is distinguished from them by peculiarities in skull form, as well as by smaller size, shorter horns, and the absence of face glands. Gorals are native to a vast area, ranging from the Himalayas to eastern Siberia.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Serow (Capricorhis sumatrensis). The serow has been called a "goatantelope." Found in Sumatra, the Malay Peninsula, Vietnam, Thailand, Burma, the eastern Himalayas, and China, it lives on forest-clad slopes, such as the mountains of southern China that are the home of the giant panda. Serows have coarse black hair, long pointed ears, a distinct mane, and short, backward pointing horns.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Native species of goats are also valuable genetic resources of Asia and examples include ibex (Capra ibex), markhor (Capra falconeri), and bharal (Pseudois nayaur). There are also various species of sheep, including the various races of argalis (Ovis ammon), which form small herds in the mountains, often above timberline. Although robust and short-legged, these animals can move about quickly and easily over difficult slopes. Soviet animal breeders apparently are exploring some of the possibilities of using argalis in animal husbandry. They are crossing domestic sheep with arkhar (Ovis ammon karelini) to produce a commercially viable hybrid.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The marketable size of lamb might be increased appreciably to provide larger, leaner cuts of meat by crossing domestic sheep with the Marco Polo sheep (Ovis ammon polii), which is as big as deer and has a mature body weight of 400-500 pounds. Marco Polo sheep meat is reported to have none of the "mutton" favor of domestic sheep. Thus, crosses might enhance consumer acceptance of sheep meat.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Asia also has several species of deer that could have been included.§ The musk deer (Moschus moschiferus) is now domesticated in China for musk production and is a resource with a promising future. Also, sambar deer (Cervus unicolor), Asia's largest deer, may prove useful in husbandry. Several deer species are being farmed in New Zealand and ruse deer (Cervus rusa), which are native to South and Southeast Asia, are being farmed in Mauritius, Australia, and Papua New Guinea for meat and medicinal by-products. Two small, goat-sized Asian deer, the hog deer (Cervus porcinus) and the barking deer (Muntiacus muntjak), may also be worth considering. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&lt;&lt;I&gt;&gt; p101.png KOUPREY</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<B><P ALIGN="CENTER">&lt;&lt;TOC2&gt;&gt; Appendixes</P>
+</B><P ALIGN="JUSTIFY"></P>
+<B><P>&lt;&lt;TOC3&gt;&gt; Selected Readings</P>
+</B><P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">General</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Bohlken, H. 1961. Haustiere und Zoologische Systematik. Zeitschrift fur Tierzuchtung und Zuchtungsbiologie76:107-113.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Boonsong Lekagul, and J. A. McNeely. 1977. Mammals of Thailand. Association for the Conservation of Wildlife, Bangkok, Thailand. 758 pp.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Corbet, G. B., and J. E. Hill. 1980. A World List of Mammalian Species. British Museum of Natural History, London, England.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Groves, C. P. 1981. Ancestors for the Pigs, Taxonomy and Phylogeny of the Genus Sus. Department of Prehistory Technical Bulletin No. 3. Australian National University Press, Canberra, Australia. 96 pp.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Gray, A. P. 1972. Mammalian Hybrids: A Check-List with Bibliography. Commonwealth Technical Communication No. 10 (Rev.). Bureau of Animal Breeding and Genetics, Edinburgh, Scotland.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Honacki, J. H., K. E. Kinman, and J. W. Koeppl. 1982. Mammal Species of the World. Allen Press, Lawrence, Kansas, USA. 694 pp.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Mochi, U. and T. D. Carter. 1953. Hoofed Mammals of the World. Charles Scribner's Sons, New York.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Payne, W. J. A. 1970. Cattle Production in the Tropics. Longman, London, England.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Robbins, C. T. In Press. Wildlife Feeding and Nutrition. Academic Press, New York, USA.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Walker, E. P. 1975. Mammals of the World. The Johns Hopkins University Press, Baltimore, Maryland, USA, and London, England.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Wharton, C. H. 1969. Man, fire and wild cattle in Southeast Asia. Tall Timbers Fire Ecology Conference 8: 107-167.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Domesticated and Wild Banteng</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Appleton, D. C., G. Dryden, and A. C. Kondos. 1976. A comparison of the digestive efficiency of the water buffalo and Brahman and Banteng cattle. In Proceedings of the Australian Society of Animal Production 11.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Budiarso, I. T., and S. Hardjosworo. 1976. Jembrana disease in Bali cattle. Australian Veterinary Journal 52(2):97.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Copland, R. S. 1974. Observations on banteng cattle in Sabah. Tropical Animal Health and Production 6(2):89-94.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Darmadja, D., and P. Sutedja. 1975. Gestation period and calving interval in Bali cattle. Majalah Ilmiah Universitas Udayana 9:61 -65.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Darmadja, D., and P. Sutedja. 1976. Masa kebuntingan den interval beranak padas sapi Bali. In Proceedings, Seminar Reproduksi den Performance Sapi Bali, April 5-6, 1976. Dinas Peternakan Daerah Ternak Institute, Bali, Indonesia. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Devendra, C., T. Lee Kok Choc, and M. Pathmasingam. 1973. The productivity of Bali cattle in Malaysia. Malaysian Agricultural Journal 49(2):183-197.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Holmes, J. H. C., J. H. Schottler, and T. F. Leche. 1977. Southeast Asian cattle, buffalo, and beef in Papua New Guinea. In Agriculture in the Tropics, B. A. C. Enyi and T. H. Varghese, eds. University of Papua New Guinea, Port Moresby, Papua New Guinea.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Hoogerwerf, A. 1970. Udjung Kulan, The Land of the Last Javan Rhinoceros. E. J. Brill, Leiden, The Netherlands.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Hooijer, D. A. 1956. The valid name of the banteng Bibos javanicus d'Alton. Zoologische Mededelingenuitgegeven door het Rijksmuseum van Natuurlijke Historie te Leiden 34:223-226.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Jellinek, P. J., J. Avenell, A. Thahar, and P. Sitorus. 1980. Infertility associated with crossbreeding of Bali cattle. In Proceedings, 2nd Ruminant Seminar, Ciawi, Indonesia. 79 pp.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Jenkinson, D. M., and T. Nay. 1975. The sweat glands and hair follicles of different species of Bovidae. Australian Journal of Biological Science 28:55-68.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Kirby, G. W. M. 1979. Bali cattle in Australia. World Animal Review 31 :24-29.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Mason, 1. L. In Press. Evolution of Domesticated Animals. Longman, London, England.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Meijer, W. C. P. 1962. Das Balirind (Balinese Cattle). Die Neue Brehm-Bucherei, No. 303, A. Ziemsen Verlag, Wittenberg Lutherstadt, Federal Republic of Germany. (Translated from the Dutch by E. Mohr.)</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Moran, J. B. 1973a. Liveweight changes of Brahman cross, Shorthorn, Banteng and buffalo steers grazing improved pastures at Darwin, Northern Territory. Journal of the Australian Institute of Agricultural Science 39:68-9.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Moran, J. B. 1973b. Heat tolerance of Brahman cross, buffalo Banteng and Shorthorn steers during exposure to sun and as a result of exercise. Australian Journal of Agricultural Research 24:775-782.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Moran, J. B. 1978. Digestibility and water metabolism in Brahman cross, buffalo, Banteng and Shorthorn steers fed roughage diets. Journal of the Australian Institute of Agricultural Science 44: 57-59.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Moran, J. B. 1980. The prediction of chemical content of the whole carcass from the physically-dissected rib in cattle and buffaloes. Proceedings of the Australian Society of Animal Production 13:503.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Moran, J. B. 1981. Beef and buffalo production by smallholders in Indonesia. World Review of Animal Production 17:55-64.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Moran, J. B. 1982. The performance of Indonesian beef breeds under traditional and improved management systems. Pp. 347-351 in Animal Production and Health in the Tropics, M. R. Jainudeen and A. R. Omar, eds. Universiti Pertanian Malaysia, Serdang, Selangor, Malaysia.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Moran, J. B., B. W. Norton, and J. V. Nolan. 1979. The intake, digestibility and utilization of a low quality roughage by Brahman cross, buffalo, Banteng and Shorthorn steers. Australian Journal of Agricultural Research 30:333-340.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Namikawa, T., and W. Widodo. 1978. Electrophoretic variations of hemoglobin and serum albumin in the Indonesian cattle including Bali cattle (Bos banteng). Japanese Journal of Zootechnical Science 49(11):817-827.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Nitis, 1. M., K. Rika, M. Supardjata, K. D. Nurbudhi, and L. R. Humphreys. 1976. Productivity of improved pastures grazed by Bali cattle under coconuts: a preliminary report. Universitas Udayana, Denpasar, Bali, Indonesia. 18 pp.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Nitis, 1. M., and K. Rika. 1978. Bali cattle grazing improved pasture under coconuts. 1. Effects of stocking rate on steer performance and coconut yield. In Seminar on Integration of Animals with Plantation Crops, April 13-15. Preprint No. 10. Penang, Indonesia. 8 pp</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Nitis, 1. M. 1979a. Effects of replacing 30 percent of the green roughage with concentrate on the performance of Bali steer. Progress report to the International Development Research Centre, Ottawa, Canada. Centre file:3-P77-0087. 25 pp.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Nitis, 1. M. 1979b. Performance of Bali cattle fed grass supplemented with stylosanthes. Progress report to the International Foundation for Science, Sweden. Project No. RR 76. 15 pp.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Nitis, 1. M., K. Lana, 1. B. Sudana, N. Sutji, and 1. C. N. Sarka. I980. Persediaan den kebutuhan hijauan ternak di Bali (Roughage supply and requirement of livestock in </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Bali). Fakultas Kedokteran Hewan den Peternakan, Universitas Udayana, Denpasar, Bali, Indonesia. 218 pp. (Report series mimeograph.)</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Norton, B. W., J. B. Moran, and J. V. Nolan. 1979. Nitrogen metabolism in Brahman cross, buffalo, Banteng and Shorthorn steers fed on low quality roughage. Australian Journal of Agricultural Research 30:341.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Nursamad, M. 1972. Berat lahir den petumbuhan anak sapi Bali selama 4 bulan di kecamatan Watang Pulu, kabupaten Sidenreng, Sulawesi Selatan. Laporan, Fakultas Peternakan Universitas Hasanuddin yang berafinasi dengan Fakultas Peternakan Institut Pertanian Bogor, Bogor, Indonesia.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Pastika, M., and D. Darmadja. 1976. Performance reproduksi sapi Bali. In Proceedings, Seminar Reproduksi den Performance Sapi Bali, April 5-6, 1976. Dinas Peternakan Daerah Ternak Institut, Bali, lndonesia.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Payne, W. J. A., and D. H. L. Rollinson. 1973. Bali cattle. World Animal Review 7: 13-21.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Pulungan, H., and K. Ma'sum. 1977. Performance sapi Bali den hasil persilangannya dengan sapi Hereford den Shorthorn. Laporan Khusus Lembaga Penelitian Peternakan, Cabang Grati 1977 (Abstract).</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Robinson, D. W. 1977. Livestock in Indonesia. Research Report No. 1. Centre for Animal Research and Development, Bogor, Indonesia.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Siebert, B. D., and W. V. MacFarlane. 1969. Body water content and water turnover of tropical Bos taurus, Bos indicus, Bibos banteng, and Bos bubalus bubalis. Australian Journal of Agricultural Research 20:613-622.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Siregar, M. G., and 1. M. Suparjata. 1975. A half century existence of Bali cattle in South Sulawesi. Majalah llmiah Universitas Udayana 9: 13-21.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Subandriyo, P. Sitorus, M. Zulbardi, and A. Roesyat. 1979. Performance of Bali cattle, as work animals and milk and beef producers. Indonesian Agricultural Research and Development Journal 1(1/2):9-10, 24.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Sutedja, P., M. Kota, 1. B. Mantra, and D. Darmadja. 1976. Progress report beberapa performance pada sapi Bali. In Proceedings, Seminar Reproduksi den Performance Sapi Bali, April 5-6, 1976. Dinas Peternakan Daerah Ternak Institut, Bali, Indonesia.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Thahar, A., J. B. Moran, and J. T. Wood. In press. Studies on the haemotology of Indonesian large ruminants. Tropical Animal Health and Production.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Thahar, A., J. B. Moran, and R. E. Soerifpo. In press. Observations on the hair and skin of Indonesian large ruminants and their relationships to heat tolerance. SABRAO Journal.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Vercoe, J. E., and J. E. Frisch. 1977. The importance of voluntary feed intake and metabolic rate to production in different genotypes of cattle in different environments. Pp. I(c)-42 in Proceedings of the 3rd International Congress of the Society for the Advancement of Breeding Researchers in Asia and Oceania, Canberra, Australia.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Yeates, N. T. M., and P. J. Schmidt. 1974. Beef Cattle Production. Butterworths Pty Ltd., Chatswood, Sydney, Australia. 323 pp.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Banteng Cattle Hybrids</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Payne, W. J. A., and D. H. L. Rollinson. 1976. Madura cattle. Zeitschrift fur Tiezuchtung und Zuchtungsbiologie 93:89-100.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Mithan</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Simoons, F. J., and E. S. Simoons. 1968. A Ceremonial Ox of India: The Mithan in Nature, Culture, and History. The University of Wisconsin Press, Madison, Wisconsin, USA.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Mason, 1. L. In Press. Evolution of Domesticated Animals. Longman, London, England.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Scheurmann, E. 1975. Observations on the behaviour of the mithan (Bibos frontalis Lambert 1837) in captivity. Applied Animal Ethology I :321 -355. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Yak and Yakow</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Accolas, J. P., and J. P. Deffontaines. 1970. Quelques donnees sur l'elevage du Yak en Republique Populaire de Mongolie. Pp. 133-141 in The Yak: Its Role in the Economic and Cultural Life of Breeders in Central Asia. Societe d'Ethnozootechnie, 25 Boulevard Arago, 75013 Paris, France.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Bonadonna, T. 1970. Nuove possibilita per la Zootechnia dei tropic). Zootecnica e Veterinaria 25:202-221.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Bonnemaire, J. 1976. Le Yak domestique et son hybridation. Pp. 46-77 in The Yak: Its Role in the Economic and Cultural Life of Breeders in Central Asia. Societe d'Ethnozootechnie, Paris, France.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Dor, R. 1976. Note sur le Yak au Pamir. Pp. 126-131 in The Yak: Its Role in the Economic and Cultural Life of Breeders in Central Asia. Societe d'Ethnozootechnie, Paris, France.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Ekvall, R. B. 1968. Fields on the Hoof: Nexus of Tibetan Nomadic Pastoralism. Holt, Rinehart and Winston, New York, USA.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Epstein, H. 1974. Yak and chauri. World Animal Review 9:8-12.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Epstein, H. 1977. Yak and Yak-cattle hybrids. Chapter 3 in Domestic Animals of Nepal. Holmes and Meier Publishers, Inc., New York, USA, and London, England.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Ivanova, V. V. 1938. K voprosu izucenija plodovitosti samvoc gibridov jaka s rogatym skotom (On the fertility of male yak x cattle hybrids). Izvestiya Akademii Nauk SSSR, Seriya Biologicheskaya 883-884.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Phillips, R. W., R. G. Johnson, and R. T. Moyer. 1945. The livestock of China. Pp. 67-76 in United States Department of State Publication No. 2249; Far Eastern Series 9.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Phillips, R. W., I. A. Tolstoy, and R. G. Johnson. 1946. Yaks and Yak-cattle hybrids in Asia. The Journal of Heredity 37(6): 162-170; 37(7):206-215.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Schley, P. 1967. Der Yak und seine Kreuzung mit dem Rind in der Sowjetunion. Giessener Abhandlungen zur Agrar- und Wirtschaftsforschung des Europaischen Ostens, Vol. 44. Otto Harassowitz, Weisbaden, Federal Republic of Germany. 131 pp.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Shahrani, M. Nazif Mohib. 1979. The Kirghiz and Wakki of Afghanistan. University of Washington Press, Seattle, Washington, USA. 264 pp.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Vlasov, P., S. Gersenzon, and A. Poljakov. 1932. Gibridizacija mezdu jakom i krupnym rogatym skotom (Hybrids between yak and cattle). Problemy Zhivotnovodstva (1):48-57.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">White, W. T., R. W. Phillips, and E. C. Elting. 1946. Yaks and Yak-cattle hybrids in Alaska. Journal of Heredity 37:355-358.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Zawadowsky, M. M. 1931. Zebu-Yak hybrids. Journal of Heredity 22:297.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Zuitin, A. I. 1938. New data on the chromosome number in yak (Poephagus grunniens L.). Doklady Akademii Nauk Uzbekskoi SSR 19:201-202.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Wild Banteng</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">A unique, interesting film showing wild banteng, gaur and kouprey in Cambodia in 1951</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">is available for hire from The Coolidge Foundation, 38 Standley Street, Beverly, Massachusetts 01915, USA.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Boonsong Lekagul and J. A. McNeely. 1977. Mammals of Thailand. Association for the Conservation of Wildlife, Bangkok, Thailand. 758 pp.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Fischer, H., and E. Scheurmann. 1977. Cytogenetic investigations on domestic and wild animal populations in South and Southeast Asia. Animal Research and Development 6:63-71.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Halder, U. 1975. Okologie und Verhalten des banteng (Bos javanicus) in Java. Eine Feldstudie. Verlag Paul Parey, Hamburg and Berlin, Federal Republic of Germany. 124 pp.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Hoogerwerf, A. 1974. Report on a Visit to Wildlife Reserves in East Java. Mededelingen No. 21. Nederlandsche Commissie voor Internationale Natuurbescherming.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">McNeely, J. A. 1975. Wildlife and national parks in the Lower Mekong Basin. Unpub</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">lished report to the Committee for the Coordination of Investigations of the Lower  Mekong Basin, Economic Commission for Asia and the Far East, Bangkok, Thailand.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Sumardja, E. A. 1976. The relationships between banteng Bos javanicus (d'Alton) and  vegetation at the Pananjung-Pangandaran Nature Reserve. Research Grant No. 1237/  TF/VI/74. Preliminary Study Internal Report Biotrop. Bogor, Indonesia.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Wind, J., and H. Amir. 1977. Distribution of banteng (Bos javanicus) in Java and Bali,  Indonesia. Unpublished ms.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Wind, J., and H. Amir. 1977. Management Plan Baluran Reserve FAO INS/73/013.  Nature Conservation and Wildlife Management Project.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Gaur</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Boonsong Lekagul. 1965. The gaur. (Bos gaurus). Conservation News of South East  Asia 5:7-10.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Boonsong Lekagul and J. A. McNeely. 1977. Mammals of Thailand. Association for the  Conservation of Wildlife, Bangkok, Thailand. 758 pp.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Conry, P. J. 1980. The impact of development and the behavioural response of the  Malaysian seladang. Pp. 279-286 in Tropical Ecology and Development, Proceedings  Fifth International Symposium of Tropical Ecology. International Society of Tropical  Ecology, Kuala Lumpur, Malaysia.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Conry, P. J. 1981. Habitat selection and use, movements, and home range of Malayan  gaur (Bos gaurus hubbacki) in Central Pahang, Malaysia. M.S. thesis. University of  Montana, Missoula, Montana, USA. 120 pp.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Conry, P. J. (In press) Immobilizing Malayan gaur with etorphine. Journal of Wildlife  Management.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Fischer, H. 1975. The water buffalo and related species as important genetic resources:  their conservation, evaluation and utilization. In The Asiatic Water Buffalo.  Proceedings of an International Symposium, Khon Kaen, Thailand. Food and Fertilizer  Technology Center, Taipei, Taiwan.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Fischer, H. 1980. Hybrids between Gaur and Gayal and between Gayal and Banteng as  zoological rarities in Thailand. Animal Research and Development 12:116-119.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Fradrich, H., and H. G. Klos. 1976. Zur Haltung und Zucht des Gaurs, Bos gaurus.  Zoologische Garten 46(6):417-425.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Hussain, M. Khader. 1969. The southern Asiatic gaur or Indian bison (Bos gaurus  gaurus H. Smith). Cheetal 12(1):29-47.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Krishnan, M. 1972. An ecological survey of the larger mammals of peninsular India.  Journal of the Bombay Natural History Society 69:322-349.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Medway, Lord. 1978. The Wild Mammals of Malaya and Singapore. 2nd Edition. Oxford  University Press, Kuala Lumpur, Malaysia. 128 pp.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Momin Khan, M. K. bin 1973. Studies on the seladang (Bos gaurus) in the State of  Perak. Malaysian Nature Journal 26:163-169.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Sahai, R. C. 1972. Distribution, composition and herd size of Gaur (Bos gaurus) in  Palamau, Bihar. Cheetal 15:60-66.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Schaller, G. B. 1967. The Deer and the Tiger. Chicago University Press, Chicago, USA.  370 pp.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Weigun, L. E. 1971. The last refuge. Malaysian Nature Journal 24:132-137.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Weigun, L. E. 1972. The problems in the preservation of the seladang in the Malaysian  National Park. M.S. thesis. Michigan State University, East Lansing, Michigan, USA.  55 pp</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Kouprey</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Boonsong Lekagul and J. A. McNeely. 1977. Mammals of Thailand. Association for the  Conservation of Wildlife, Bangkok, Thailand. 758 pp.  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Coolidge, H. J. 1940. The Indo-Chinese Forest Ox or Kouprey. Memoirs, Museum of Comparative Zoology at Harvard College 54(6):421-431.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Coolidge, H. J. 1955. The Forest Ox or Kouprey of South East Asia. P. 109 in Breeding Beef Cattle for Unfavorable Environments, A. O. Rhoad, ed. University of Texas Press, Austin, Texas, USA.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Neese, H.C. 1976. Kouprey along the Laos/Cambodia border area. Unpublished report to the New York Zoological Society, 185 and Southern Blvd., New York, New York 10460, USA.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Pfeffer, P., and O. Kim-San. 1967. Le kouprey, Bos(Bibos) sauvelli, Urbain, 1937: discussion systematique et status actuel. Hypothese sur l'origine du zebu (Bos indicus). Mammalia 31(4):521-536.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Pfeffer, P. 1969. Considerations sur l'ecologie des forets claires du Cambodge oriental. Terre et Vie 23(1):3-24.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Wharton, C. H. 1957. An Ecological Study of the Kouprey. Novibos sauveli (Urbain). Monograph No. 5. Institute of Science and Technology, Manila, Philippines. 111 pp.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Anoas</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Dolan, J. M. 1965. Breeding of the lowland anoa in the San Diego Zoological Garden. Zeitschrift Saugetierekunde 30(4):241-248.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Duplaix-Hall, N., ed. 1975. International Zoo Yearbook 15. Zoological Society of London</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Fradrich, H. 1973. Einige Bemerkungen uber den Anoa. Zeitschrift des Kolner Zoo 16(3):101-105.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Fischer, H., and H. Hohn. 1976. Der Karyotyp eines weiblichen Tamarau (Anea mindorensis) [The Karyotype of a Female Tamaraw (Anoa mindorensis)]. Giessener Beitrage zur Erbpathologie und Zuchthygiene 6:173.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Groves, C. P. 1969. Systematics of the anoa (Mammalia, Bovidae) Beaufortia 17(223): 1-12.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Koulischer, L., J. Tyskens, and J. Mortelsmanns. 1972. The chromosomes of a male specimen of Anoa depressicornis quarlesi. Acta Pathologica, Antwerp 56:21.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Scheurmann, E., H. Hohn, and H. Fischer. 1977. The karyotype of a male Bubalus (Anoa) depressicornis quarlesi Ouwens 1911. In Symposium, Domesticated Animal Cytogenetics, Jouy en Josas.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Tamaraw</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Alvarez, J. B., Jr. 1970. Philippines tamaraw, here to stay. IUCN Publication, New Series 18:46-51.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Grimwood, l. R. 1975. National Parks and Wildlife Conservation in the Philippines. FAO: PHI/72/006. UNDP/FAO, Rome, Italy.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Harrisson, T. 1969. The tamaraw and its survival. Conservation News of South East Asia 8:60-61, 70.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Kuchn, D. 1975. Tamaraw at Mt. Iglit Came Refuge, Philippines. Tigerpaper 2(3):26.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Sitwell, N. 1975. On the track of the tamaraw. Wildlife 17:428-430.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Talbot, L. M., and M. H. Talbot. 1966. The tamaraw, Bubalus mindorensis (Heude). Observations and recommendations. Mammalia 30(1): 1 - 12.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Bearded </P>
+<P ALIGN="JUSTIFY">Pig</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Allen, E. F. 1948. The bearded pig. Malaysian Nature Journal 3(2):98-99.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Cranbrook, Earl of. 1979. A review of domestic pig remains from archaeological sites in </P>
+<P ALIGN="JUSTIFY">Diong, C. H. 1973. Studies of the Malayan wild pig in Perak and Johore. Malaysian Nature Journal26(2):120-151.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Croves, C. P. 1981. Ancestors for the Pigs, Taxonomy and Phylogeny of the Cenus Sus. Department of Prehistory Technical Bulletin No. 3. Australian National University Press, Canberra, Australia. 96 pp.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Hertwig, P. 1936. Artbastarde bei Tieren. Handbuch Vererb Wissenschaften 2B:21.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Hislop, J. A. 1949. Field notes on the bearded pig. Malaysian Nature Journal 4(2):62-64.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Hislop, J. A. 1952. More about the bearded pig. Malaysian Nature Journal 7:22-23.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">International Union for the Conservation of Nature. 1972. Red Data Book 1: Mammalia. IUCN, Cland, Switzerland. (This is a loose-leaf binder that is updated from time to time.)</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Kempe, J. E. 1948. The riddle of the bearded pig. Malaysian Nature Journal 3(1):36-42.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Lotsy, J. P. 1922. Die Aufarbeitung des kuhn'schen kreuzungsmaterials im Institut fur Tierzucht der Universitat Halle. Cenetica 4:32-61.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">MacKinnon, J. 1981. The distribution and status of wild pigs in Indonesia. IUCN/SSC Pigs and Peccaries Specialist Group. Unpublished report. 9 pp.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Medway, Lord. 1978. The Wild Mammals of Malaya and Singapore, 2nd Edition. Oxford University Press, Kuala Lumpur, Malaysia.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Mohr, E. 1960. Wilde Schweine. Die Neue Brehm-Biicherei, A. Ziemsen Verlag, Wittenberg Lutherstadt, Federal Republic of Cermany.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Oliver, W. L. R. 1981. First written report. IUCN/SSC Pigs and Peccaries Specialist group. Unpublished report. 14 pp.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Pfeffer, P. 1959. Bologie et migrations du sanglier de Borneo (Sus barbatus Muller 1869). Mammalia 23:277-303.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Sulawesi Warty Pig</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Appelman, F. J. 1955. Uber Sus celebensis Muller und Schlegel. Der Zoologische Garten 21:152-156.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Catibog-Sinha, C. S. 1981. The quantity and quality of wild food plants and the depredation of wild pigs in the Philippines. Ph.D. thesis. Oklahoma State University, Stillwater Oklahoma, USA.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Croves, C. P. 1981. Ancestors for the Pigs, Taxonomy and Phylogeny of the Cenus Sus. Department of Prehistory Technical Bulletin No. 3. Australian National University Press, Canberra, Australia. 96 pp.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Hooijer, D. A. 1968. Pleistocene Vertebrates from Celebes. 8. Sus celebensis Muller and Schlegel, 1845. Beaufortia 16:215-218.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">MacKinnon, J. 1981. The distribution and status of wild pigs in Indonesia. IUCN/SSC Pigs and Peccaries Specialist Croup. Unpublished report. 9 pp.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Mohr, E. 1960. Wilde Schweine. Die Neue Brehm-Bucherei, A. Ziemsen Verlag, Wittenberg Lutherstadt, Federal Republic of Germany.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Oliver, W. L. R. 1981. Interim report. IUCN/SSC Pigs and Peccaries Specialist Group. Unpublished report. 14, pp.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Javan Warty Pig</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Blouch, R. A. 1979. Proposed Bawean Island Wildlife Reserve Management Plan. World Wildlife Fund, Report to Directorate of Nature Conservation, Indonesia. Unpublished report. 63 pp.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Blouch, R. A. 1981. Results of a preliminary search for Sus verrucosus in the Mt. Arjuna area. World Wildlife Fund, Meru Betiri Project 1024. Unpublished report. 4 pp.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Groves, C. P. 1981. Ancestors for the Pigs, Taxonomy and Phylogeny of the Genus Sus. Department of Prehistory Technical Bulletin No. 3. Australian National University Press, Canberra, Australia. 96 pp.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Hoogerwerf, A. 1970. Udjung Kulonthe Land of the Last Javan Rhinoceros. E. J. Brill, I.eiden. The Netherlands. Pp. 330-349. </P>
+<P ALIGN="JUSTIFY">MacKinnon, J. 1981. The distribution and status of wild pigs in Indonesia. IUCN/SSC Pigs and Peccaries Specialist Group. Unpublished report. 9 pp.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Oliver, W. L. R. 1981. First written report. IUCN/SSC Pigs and Peccaries Specialist Group. Unpublished report. 14 pp.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Pigmy Hog</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Bosma, A. A., W. L. R. Oliver, and A. A. MacDonald. In press. The karyotype, including g- and c- banding patterns, of the pigmy hog Sus (Porcula) salvanius (Suidae, Mammalia).</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Groves, C. T. 1981. Ancestors for the Pigs, Taxonomy and Phylogeny of the Genus Sus. Department of Prehistory Technical Bulletin No. 3. Australian National University Press, Canberra, Australia. 96 pp.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Oliver, W. L. R. 1980. The Pigmy Hog: The Biology and Conservation of the Pigmy Hog Sus (Porcula) salvanius, and the Hispid Hare, Caprolagus hispidus. Special Scientific Report No. I. Jersey Wildlife Preservation Trust. 93 pp.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Oliver, W. L. R. 1981. Pigmy hog and hispid hare: further observations of the continuing decline (or, a lament for Barnadi and a good cause for skepticism). The Dodo, Journal of the Jersey Wildlife Preservation Trust 18:10-20.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Babirus a</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Bosma, A. A., 1980. The karyotype of the babirusa (Babyrousa babyrussa); karyotype evolution in the Suidae. Fourth European Colloquium Cytogenetics Domestic Animals 1980:238-241.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Bosma, A. A., and De Haan, N. A. 1981. The karyotype of Babrousa babyrussa (Suidae, Mammalia) Acta Zoologica et Pathologica Antverpiensia 76: 17-27.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Davis, D. D. 1940. Notes on the anatomy of the babirusa. Field Museum of Natural History-Zoology 22(5):363-411.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Fradich, H. 1974. A comparison of behaviour in the suidae. Pp. 133-144 in The Behaviour of Ungulates and Its Relation to Management. V. Ceist and F. Walther, eds. IUCN Publication No. 24.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Groves, C. P. 1981. Ancestors for the Pigs, Taxonomy and Phylogeny of the Genus Sus. Department of Prehistory Technical Bulletin, No. 3. Australian National University Press, Canberra, Australia. 96 pp.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Croves, C. P. 1980. Notes on the systematics of Babyrousa (Artiodactyla, Suidae). Zoologische Mededelingen, Deel 55(3):29-46.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">MacKinnon, J. 1981. The structure and function of the tusks of babirusa. Mammal Review 1 1(1):37-40.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">MacKinnon, J. 1981. The distribution and status of wild pigs in Indonesia. IUCN/SSC Pigs and Peccaries Specialist Group. Unpublished report. 9 pp.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Oliver, W. L. R. 1981. First written report. IUCN/SSC Pigs and Peccaries Specialist Group. Unpublished report. 14 pp.</P>
+<P ALIGN="JUSTIFY">1</P>
+<P ALIGN="JUSTIFY">Selmier, V. J. 1978. Only in Indonesia: the babirusa. Unpublished report to Directorate of Nature Conservation (P.P.A.), Bogor, Indonesia. 40 pp. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<B><P>&lt;&lt;TOC3&gt;&gt; Research Contacts</P>
+</B><P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Because Asia contains many livestock breeds about which little is known, an expert committee on Animal Genetic Resources has been recently formed by the Society for the Advancement of Breeding Researchers in Asia and Oceania (SABRAO). Its chairman is Professor J. S. F. Barker of the University of New England, Armidale, New South Wales 2351, Australia.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The Species Survival Commission of the International Union for the Conservation of Nature has a Wild Cattle Specialist Group that concerns itself with wild banteng, gaur, and kouprey. Its chairman is Mr. Mohd. Khan bin Momin Khan, Director-General, Wildlife and National Parks, West Malaysia, Kompleks Pejabat-Pejabat Kerajaan, Block K-20, Jalan Duta, Kuala Lumpur, Malaysia.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The following have particular knowledge of the animals described in this book, have contributed to the various chapters, and (in most cases) have agreed to provide advice to bona fide researchers wishing to study further the animals in this report.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Domesticated Banteng</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Ida Bagus Arka, Faculty for Veterinary Science and Animal Husbandry, Udayana University, Jalan Sudirman Sanglah, Denpasar, Bali, Indonesia J. S. F. Barker, Department of Animal Science, University of New</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">England, Armidale, New South Wales 2351, Australia</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">W. Bongers, Department of Nature Conservation, Wageningen Agricultural University, Ritzema Bosweg 32a, 6703AZ Wageningen, The Netherlands David Butcher, Western Plains Zoo, Box 813, Dubbo, New South Wales</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">2830, Australia (Banteng are available for research projects and zoos.</P>
+<P ALIGN="JUSTIFY">Quarantine for shipments between Australia and most countries are</P>
+<P ALIGN="JUSTIFY">straightforward)</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">J. K. Camoens, Livestock Specialist, Asian Development Bank, P.O. Box 789, Manila, Philippines 2800</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">David Deppner, 1603 Dayton Road, Hyattsville, Maryland 20783, USA</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">C. Devendra, Malaysian Agricultural Research and Development Institute (MARDI), Serdang, Selangor, Malaysia</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">J.-M. Duplan, Institut Technique de l'Elevage Bovin, Section Amelioration Genetique, Maison Nationale des Eleveurs, 149, rue de Bercy F, 75595 Paris Cedex 12, France</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">H. Fischer, Institute of Tropical Veterinary Medicine, 63 Giessen, Wilhelmstrasse 15, Federal Republic of Germany</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">S. I. Furtado, Universiti Malaya, Lembah Pantai, Kuala Lumpur 22-11, Malaysia.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">John Hodges, FAO, Via delle Terme di Caracalla, 00100 Rome, Italy</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">H. Huitema, Overzicht 60, 6862 CT, Oosterbeek, The Netherlands</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Graham W. M. Kirby, Principal Animal Production Officer, Department of Primary Production, P.O. Box 4160, Darwin, Northern Territory 5790, Australia</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Moh. Zain Katoe, P.T. United Livestock, Jalan Bau Massepe 472, ParePare, South Sulawesi, Indonesia</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">H. -G. Klos, Director, Zoologischer Garten Berlin, Hardenbergplatz 8 , 1000 Berlin 30, Federal Republic of Germany</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Prof. Kusmat, Dean, Faculty of Veterinary Medicine, Institut Pertanian Bogor, Jalan Oto Iskandardinata, Bogor, Indonesia</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Ian L. Mason, 8 Ramsay Garden, Edinburgh, EH1 1NA, Scotland</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Robert E. McDowell, Department of Animal Science, Frank B. Morrison Hall, Cornell University, Ithaca, New York 14853, USA</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">G. Montsma, Department of Animal Production, Wageningen Agricultural University, Ritzema Bosweg 32a, 6703 AZ Wageningen, The Netherlands</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">J. B. Moran, Senior Research Officer, Animal and Irrigated Pastures Research Institute, Kyabram, Victoria 3620, Australia</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Jan Nari, Director of Central Research Institute for Animal Science, Jalan Raya Pajajaran, Bogor, Indonesia</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">I. M. Nitis, Department of Animal Nutrition and Tropical Pasture Production, Udayana University, Jalan Sudirman Sanglah, Denpasar, Bali, Indonesia</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">W. J. A. Payne, 91 Bedwardine Road, London SE19 3AY, England</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Donald L. Plucknett, Consultative Group on International Agricultural Research, 1818 H Street, Washington, D.C. 20433, USA</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Research Institute for Animal Production, P.O. Box 123, Bogor, Indonesia (Amber Roesyat, Ian Fletcher, Dennis Hoffmann, P. Sitorus, Subandriyo, M. Zulbardi)</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">David W. Robinson, International Programs, University of California, Davis, California 95616, USA </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">D. H. L. Rollinson, Animal Production and Health Division, FAO, Via delle Terme di Caracalla, 00100 Rome, Italy</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">G. Seifert, CSIRO, Tropical Cattle Research Centre, P.O. Box 5545, Rockhampton Mail Centre, N. Rockhampton, Australia</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">C. David Simpson, Senior Extension Specialist, Veld, Pastures and Wildlife, Agritex Box 363, Bulawayo, Zimbabwe</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">A. J. Smith, Tropical Animal Health, Royal (Dick) School of Veterinary Studies, University of Edinburgh, Summerhall, Edinburgh, EH9 1QH Scotland</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Dukut Sularsasa, Department of Tropical Veterinary Science, James Cook University, Townsville, Queensland 4811, Australia</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">M. Syamsul Arifin, Jalan Amin Jakfar 41, Pamekasan Madura, Jatim, Indonesia</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Taronga Zoo, P.O. Box 20, Mosman, New South Wales 2088, Australia (T. Finnie and J. L. Throp)</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Frank M. Thompson, Wild Animal Brokers, 15605 S. R. #64, Bradenton, Florida 33508, USA</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Allen D. Tillman, 523 West Harned Place, Stillwater, Oklahoma 74074, USA</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Don Tulloch, P.O. Box 38841, Winnellie, Northern Territory 5789, Australia</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Helen Newton Turner, P.O. Box 184, North Ryde, New South Wales 2113, Australia</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Antoon de Vos, P.O. Box 34, Whitford, Auckland, New Zealand</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Robert Warren, Department or Range and Wildlife Management, Texas Tech University, Lubbock, Texas 79409, USA</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Everett J. Warwick, The Rockefeller Foundation, P.O. Box 63, Yogyakarta, D.I.Y., Indonesia</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">John Woodward, 35AI, Sultan Hasanudin, Ujung Pandang, South Sulawesi, Indonesia</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Zoos with Domesticated Banteng</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Antwerp, Belgium (Royal Zoological Society of Antwerp)</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Askaniya-Nova, USSR (Zoologicheskii Park Askaniya-Nova)</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Bangkok, Thailand (Dusit Zoological Park; banteng-mithan hybrid)</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Berlin, Federal Republic of Germany (Zoologischer Garten)</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Berlin, German Democratic Republic (Tierpark Berlin)</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Copenhagen, Denmark (Zoologisk Have)</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Dubbo, New South Wales, Australia (Western Plains Zoo)</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Jakarta, Indonesia (Kebun Binatang Ragunan)</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Kiev, USSR (Kievskii Zoologicheskii Park)</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Madrid, Spain (Zoo de la Casa de Campo; mithan-banteng hybrid)</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Pretoria, South Africa (National Zoological Gardens of South Africa) </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Rome, Italy (Giardino Zoologico e Museo de Zoologia del Comune de Rome and Zoorama)</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Rotterdam, The Netherlands (Stichting Koninklijke Rotterdamse Diergaarde; 2 male, 2 female, may be wild form)</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Surabaya, Indonesia (Kebun Binatang Surabaya)</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Yogyakarta, Indonesia</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Banteng-Cattle Hybrids</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Abubakar Aldjufri, Secretary, Asian Livestock Business Club, Kebun Pala I/79B Tanah Abang, Jakarta, Indonesia</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Saleh Aldjufri, Jalan Jakarta 42, Surabaya, Jawa Timur, Indonesia</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">David Deppner, 1603 Dayton Rd., Hyattsville, Maryland 20783, USA</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">H. Huitema, Overzicht 60, 6862 CT, Oosterbeek, The Netherlands</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Graham W. M. Kirby, Principal Animal Production Officer, Department of Primary Production, P.O. Box 4160, Darwin, Northern Territory 5790, Australia</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">J. B. Moran, Senior Research Officer, Animal and Irrigated Pastures Research Institute, Kyabram, Victoria 3620, Australia</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">W. J. A. Payne, 91 Bedwardine Road, London SE19 3AY, England</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">David W. Robinson, International Programs, University of California, Davis, California 95616, USA</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">D. H. L. Rollinson, Animal Production and Health Division, FAO, Via delle Terme di Caracalla, 00100 Rome, Italy</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">B. Wheeler, 1000 Shady Lane, College Station, Texas 77840, USA</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Mithan</P>
+<P ALIGN="JUSTIFY">Chaichana Satrulee, Dusit Zoological Park, Bangkok, Thailand</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">H. Fischer, Institute of Tropical Veterinary Medicine, 63 Giessen, Wilhelmstrasse 15, Federal Republic of Germany</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">C. von Furer Haimendorf, School of Oriental and African Studies, University of London, London WC1, England</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Charles G. Hickman, Livestock Consultant, A. Mithat Efendi Sokak No. 36/11, Cankaya, Ankara, Turkey</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Frederick J. Simoons, 140 Bartlett Ave., Woodland, California 95695, USA</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Zoos with Mithan (Gayal)</P>
+<P ALIGN="JUSTIFY">Aalborg, Denmark (Aalborg Zoologiske Have)</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">Amsterdam, The Netherlands (Stichting Koninklijk Zoologisch) </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Arnhem, The Netherlands (Burgers' Zoo and Safari)</P>
+<P ALIGN="JUSTIFY">Bangkok, Thailand (Dusit Zoological Park)</P>
+<P ALIGN="JUSTIFY">Berlin, German Democratic Republic (Tierpark Berlin)</P>
+<P ALIGN="JUSTIFY">Calcutta, India</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Cologne, Federal Republic of Germany (Aktiengesellschaft Zoologischer Garten)</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Heidelberg, Federal Republic of Germany (Tiergarten Heidelberg)</P>
+<P ALIGN="JUSTIFY">Kolmarden, Sweden (Koemardens Djurpark)</P>
+<P ALIGN="JUSTIFY">Madrid, Spain (Zoo de la Casa de Campo; mithan-banteng hybrid)</P>
+<P ALIGN="JUSTIFY">Rabat, Morocco (Pare Zoologique National)</P>
+<P ALIGN="JUSTIFY">Vienna, Austria (Schonbrunn Zoo)</P>
+<P ALIGN="JUSTIFY">Tallin, USSR (Tallinna Loomaaed)</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Yak</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Joseph Bonnemaire, Ecole Nationale Superieure des Sciences Agronomiques Appliquees, 26, Bd. Docteur Petitjean, 21100 Dijon, France</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Corneille Jest, Centre National de la Recherche Scientifique, 1, Place Artistide-Briand, 92190 Meudon, France</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">R. A. Kazarova, Director, Riga Zoological Garden, Meza prospekt 1, Riga 14 226014, Latvian SSR, USSR</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">K. K. Panday, Swiss Association for Technical Assistance (SATA), Box 113, Kathmandu, Nepal</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Ralph W. Phillips, The Representative, Apartment 810, 1101 South Arlington Ridge Road, Arlington, Virginia 22202, USA</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Patrick J. Robinson, Department of Agricultural and Forest Sciences, University of Oxford, Commonwealth Forestry Institute, South Parks Road, Oxford OX1 3RB, England</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">George B. Schaller, New York Zoological Society, 185 and Southern Blvd., New York, New York 10460, USA</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">T. B. Singh, Director General, Department of Livestock, HMG, Harihar Bhawan, Pulchowk, Laitpur, Nepal</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Societe d'Ethnozootechnie, 25, Boulevard Arago, 75013 Paris, France (R. Laurans)</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Zoos with Yak</P>
+<P ALIGN="JUSTIFY">Antwerp, Belgium (Royal Zoological Society of Antwerp)</P>
+<P ALIGN="JUSTIFY">Arnhem, The Netherlands (Burgers' Zoo and Safari)</P>
+<P ALIGN="JUSTIFY">Baltimore, Maryland, USA</P>
+<P ALIGN="JUSTIFY">Bronx, New York, USA (New York Zoological Park)</P>
+<P ALIGN="JUSTIFY">Chicago, Illinois, USA (Brookfield Zoo)</P>
+<P ALIGN="JUSTIFY">Denver, Colorado, USA (Denver Zoological Gardens)</P>
+<P ALIGN="JUSTIFY">Detroit, Michigan, USA (Detroit Zoological Park)</P>
+<P ALIGN="JUSTIFY">Evansville, Indiana, USA (Meeker Park Zoo)</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Granby, Quebec, Canada (Societe Zoologique de Granby, Inc.)</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Grand Rapids, Michigan, USA (John Ball Zoological Gardens)</P>
+<P ALIGN="JUSTIFY">Kansas City, Missouri, USA (Kansas City Zoological Gardens)</P>
+<P ALIGN="JUSTIFY">Knoxville, Tennessee, USA (Knoxville Municipal Zoo)</P>
+<P ALIGN="JUSTIFY">London, England</P>
+<P ALIGN="JUSTIFY">Rochester, New York, USA (Seneca Park Zoo)</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Rotterdam, The Netherlands (Stichting Koninklijke Rotterdamse Diergaarde)</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">San Diego, California, USA (San Diego Wild Animal Park)</P>
+<P ALIGN="JUSTIFY">Sioux Falls, South Dakota, USA (Great Plains Zoo)</P>
+<P ALIGN="JUSTIFY">South Bend, Indiana, USA (Potawatomi Park Zoo)</P>
+<P ALIGN="JUSTIFY">Syracuse, New York, USA (Burnet Zoo)</P>
+<P ALIGN="JUSTIFY">Toronto, Ontario, Canada (Metro Toronto Zoo)</P>
+<P ALIGN="JUSTIFY">Utica, New York, USA (Utica Zoo)</P>
+<P ALIGN="JUSTIFY">Wichita, Kansas, USA (Sedgwick County Zoo)</P>
+<P ALIGN="JUSTIFY">West Orange, New Jersey, USA (Turtleback Zoo)</P>
+<P ALIGN="JUSTIFY">Winnipeg, Manitoba, Canada (Assiniboine Park Zoo)</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Yakows</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Joseph Bonnemaire, Ecole Nationale Superieure des Sciences Agronomiques Appliquees, 26, Bd. Docteur Petitjean, 21100 Dijon, France</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Department of Agriculture, Hari Har Bhawan, Pulchok, Lalitpur, Kathmandu, Nepal</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Department of Animal Husbandry and Veterinary Science, Kathmandu, Nepal (Tewari and Burathoky)</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Director of Livestock Development, Peking, China</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Professor Karl Fredge, Department of Genetics, University of Uppsala, Uppsala, Sweden</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Indian Veterinary Research Institute, P.O. Izatnagar 243 122, Uttar Pradesh, India</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Livestock Division, National Agricultural Research Center, Islamabad, Pakistan</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">National Sheep and Yak Development Project, Dechhen Pelrithang, P.O. Bumthang, Bhutan</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Ralph W. Phillips, The Representative, Apartment 810, 1101 South Arlington Ridge Road, Arlington, Virginia 22202, USA</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Patrick J. Robinson, Department of Agricultural and Forest Sciences, University of Oxford, Commonwealth Forestry Institute, South Parks Road, Oxford OX1 3RB, England</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Whipsnade Zoo, Whipsnade, England</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Bruce A. Young, Department of Animal Science, University of Alberta, Edmonton, Alberta TOG 2P5, Canada </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Wild Banteng</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">H. Amir, c/o Ministry of Development Supervision and the Environment, JalanMirdekaBarat 15, Jakarta, Indonesia</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">J. H. Blower, National Parks Project, c/o UNDP, Box 650, Rangoon, Burma</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Bonsong Lekagul, Association for the Conservation of Wildlife, No. 4 Customhouse Road, Bangkok, Thailand</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Chaichana Satrulee, Dusit Zoological Park, Bangkok, Thailand</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Z. Coto, Tropical Forest Biology, SEAMEO-BIOTROP, P.O. Box 17, Bogor, Indonesia</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Forest Department, P.O. Box 311, Sandakan, Sabah, Malaysia (Patrick Andau, Assistant Chief Game Warden)</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">I. R. Grimwood, P.O. Box 45079, Nairobi, Kenya</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">C. P. Groves, Department of Prehistory and Anthropology, The Australian National University, P.O. Box 4, Canberra, ACT 2600, Australia</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">U. Halder, Swiss League for Nature Conservation, P.O. Box 73, CH4020 Basel, Switzerland</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">H. Huitema, Overzicht 60, 6862 CT, Oosterbeek, The Netherlands</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">F. Wayne King, Director and Professor, Florida State Museum, University of Florida, Gainesville, Florida 32601, USA</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Lembaga Biologi Nasional (LBN-LIPI), Bogor, Indonesia</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">John A. Lukas, White Oak Plantation, Rt. 3 Box 224, Yulee, Florida 32097, USA</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Jeffrey A. McNeely, Executive Officer, Commission on National Parks and Protected Areas, International Union for Conservation of Nature and Natural Resources, Avenue du Mont-Blanc, 1196 Gland, Switzerland</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">John Payne, Wildlife Section, Forest Department, P.O. Box 311, Sandakan, Sabah, Malaysia</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Somtob Norapuckprutikorn, Captive Propagation Section, Wildlife Conservation Division, Royal Forest Department, Bangkhen, Bangkok 9, Thailand</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">B. Wheeler, 1000 Shady Lane, College Station, Texas 77840, USA</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">M. H. Woodford, c/o FORW, FAO, Via delle Terme di Caracalla, 00100 Rome, Italy</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Zoos with Wild Banteng</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Albuquerque, USA (Rio Grande Zoological Park)</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Amsterdam, The Netherlands (Stichting Koninklijk Zoologisch)</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Bangkok, Thailand (Dusit Zoological Park)</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Berlin, Federal Republic of Germany (Zoologischer Garten)</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Chicago, Illinois, USA (Brookfield Zoo)</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Cologne, Federal Republic of Germany (Aktiengesellschaft Zoologischer Garten)</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Copenhagen, Denmark (Zoologisk Have)</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Darmstadt, Federal Republic of Germany (Vivarium Darmstadt)</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Dortmund, Federal Republic of Germany (Tierpark Dortmund)</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Dresden, German Democratic Republic (Zoologischer Garten Dresden)</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Frankfurt, Federal Republic of Germany</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Jakarta, Indonesia (Kebun Binatang Ragunan)</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">San Diego, California, USA</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">St. Louis, Missouri, USA (St. Louis Zoological Park)</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Surabaya, Indonesia (Kebun Binatang Surabaya)</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Yogyakarta, Indonesia</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Yulee, Florida, USA (White Oak Plantation)</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Gaur</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">John Aspinal, Howlett's Wildlife Park, near Canterbury, Kent, England</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Boonsong Lekagul, Association for the Conservation of Wildlife, No. 4 Customhouse Road, Bangkok, Thailand</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Paul Conry, Division of Aquatic and Wildlife Resources, Department of Agriculture, P.O. Box 23367, GMF Guam 96921, USA</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">H. Fischer, Institute of Tropical Veterinary Medicine, 63 Giessen, Wilhelmstrasse 15, Federal Republic of Germany</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">I. R. Grimwood, P.O. Box45079, Nairobi, Kenya</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Mohd Khan bin Momin Khan, Director-General, Department of Wildlife and National Parks, P.O. Box 611, Kuala Lumpur, Malaysia</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">R. A. Kazarova, Director, Riga Zoological Garden, Meza prospekt 1, Riga 14 226014, Latvian SSR, USSR</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">H.-G. Klos, Director, Zoologischer Garten Berlin, Hardenbergplatz 8, 1000 Berlin 30, Federal Republic of Germany</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Adrian G. Marshall, Department of Zoology, University of Aberdeen, Aberdeen, Scotland</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">George B. Schaller, New York Zoological Society, 185 and Southern Blvd., New York, New York 10460, USA</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Lee Simmons, Omaha Zoo, Omaha, Nebraska 68108, USA</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Janet Stover, Bronx Zoo, 185 and Southern Blvd., New York, New York 10460, USA</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Frank M. Thompson, Wild Animal Brokers, 15605 S. R. #64, Bradenton, Florida 33508, USA</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">M. H. Woodford, c/o FORW, FAO, Via delle Terme di Caracalla, 00100 Rome, Italy </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Zoos with Guar </P>
+<P ALIGN="JUSTIFY">The Berlin Zoo was assigned by the IUCN in cooperation with the</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">lUDZG to keep the guar studbook records. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Bangkok, Thailand (Dusit Zoological Park)</P>
+<P ALIGN="JUSTIFY">Berlin, Federal Republic of Germany (Zoologischer Garten)</P>
+<P ALIGN="JUSTIFY">Bronx, New York, USA (New York Zoological Park; 7 male, 3 female)</P>
+<P ALIGN="JUSTIFY">Brownsville, Texas, USA (Gladys Porter Zoo; 5 male, 10 female)</P>
+<P ALIGN="JUSTIFY">Copenhagen, Denmark (Zoologisk Have; 1 male, 2 female)</P>
+<P ALIGN="JUSTIFY">Holiday Island, Eureka Springs, Arkansas, USA</P>
+<P ALIGN="JUSTIFY">Hyderabad, Andhra Pradesh, India (Nehru Zoological Park)</P>
+<P ALIGN="JUSTIFY">Ivey, Wilburton, Oklahoma, USA</P>
+<P ALIGN="JUSTIFY">Kansas City, Missouri, USA (Kansas City Zoological Gardens; I male)</P>
+<P ALIGN="JUSTIFY">Kings Mill, Ohio, USA (Wild Animal Safari,; 1 male)</P>
+<P ALIGN="JUSTIFY">Kuala Lumpur, Malaysia</P>
+<P ALIGN="JUSTIFY">London, England</P>
+<P ALIGN="JUSTIFY">Los Angeles, California, USA (The Los Angeles Zoo; I male, 3 female)</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Memphis, Tennessee, USA (Memphis Zoo and Aquarium; I male, 2 female)</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Munich, Federal Republic of Germany (Munchener Tierpark Hellabrunn Ag)</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Mysore, Karnataka, India</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Oklahoma City, Oklahoma, USA (Oklahoma City Zoo; 7 male, 7 female)</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Omaha, Nebraska, USA (Henry Doorly Zoological Gardens; 7 male, 15 female)</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Riga, Latvian SSR, USSR (Riga Zoological Garden)</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">San Diego, California, USA (San Diego Wild Animal Park; 6 male, 6 female)</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">South Bend, Indiana, USA (Potawatomi Park Zoo; 1 male)</P>
+<P ALIGN="JUSTIFY">St. Louis, Missouri, USA (St. Louis Zoological Park; 1 male, 2 female)</P>
+<P ALIGN="JUSTIFY">Toronto, Ontario, Canada (Metro Toronto Zoo; 3 male, 1 female)</P>
+<P ALIGN="JUSTIFY">Vienna, Austria (Schonbrunn Zoo)</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Kouprey</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Boonsong Lekagul, Association for the Conservation of Wildlife, No. 4 Customhouse Road, Bangkok, Thailand</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Harold Coolidge, 38 Standley Street, Beverly, Massachusetts 01915, USA </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Jeffrey A. McNeely, Executive Officer, Commission on National Parks and Protected Areas, International Union for Conservation of Nature and Natural Resources, Avenue du Mont-Blanc, 1196 Gland, Switzerland</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Harvey C. Neese, P.O. Box 332, Troy, Idaho 83871, USA</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">David Anthony Parkinson, White House, San Roque 1, San Jose, Occidental Mindoro, Philippines</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Pierre Pfeffer, Zoologie, Mammiferes et Oiseaux Museum National d'Histoire Naturelle 55, rue de Buffon 75005 Paris, France</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">A. Kelly Shelton, 211-A North Cordova, Burbank, California 91505, USA</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Henry Stoddard, Branford Veterinary Clinics, Inc., P.O. Box 548, Branford, Florida 32008, USA</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Charles H. Wharton, Institute of Ecology, University of Georgia, Athens, Georgia 30602, USA (Rt. 2, Clayton, Georgia 30525)</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">World Conservation Centre, Avenue du Mont-Blanc, CH 1196 Gland, Switzerland (David Mitchell, Elizabeth Kemf)</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">M. H. Woodford, c/o FORW, FAO, Via delle Terme di Caracalla, 00100 Rome, Italy</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Zoos with Kouprey</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">None</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Anoas</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">J. M. Dolan, San Diego Zoological Garden, San Diego, California 92112, USA</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">H. Fischer, Institute of Tropical Veterinary Medicine, 63 Giessen, Wilhelmstrasse 15, Federal Republic of Germany</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">C. P. Groves, Department of Prehistory and Anthropology, The Australian National University, P.O. Box 4, Canberra, ACT 2600, Australia</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Zoos with Anoas</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Antwerp, Belgium (Royal Zoological Society of Antwerp; mountain anoa)</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Berlin, Federal Republic of Germany (Zoologischer Garten; mountain anoa)</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">London, England (lowland anoa)</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Leipzig, German Democratic Republic (Zoologischer Garten Leipzig; mountain anoa)</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Jakarta, Indonesia (Kebun Binatang Ragunan) </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Rotterdam, The Netherlands (Stichting Koninklijke Rotterdamse Diergaarde; 1 male, 3 female)</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">San Diego, California, USA (San Diego Zoological Garden; 1 male)</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">San Diego, California, USA (San Diego Wild Animal Park; 1 male)</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Surabaya, Indonesia (Kebun Binatang Surabaya)</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Sydney, New South Wales, Australia (Taronga Park Zoo)</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Tamaraw</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Department of Natural Resources, Quezon City, Manila, Philippines (J. B. Alvarez, Jr., Assistant Director)</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">H. Fischer, Institute of Tropical Veterinary Medicine, 63 Giessen, Wilhelmstrasse 15, Federal Republic of Germany</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">I. R. Grimwood, P.O. Box 45079, Nairobi, Kenya</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Natural Resources Conservation Office, Ministry of Natural Resources, Visayas Avenue, Diliman, Quezon City, Philippines</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">David Anthony Parkinson, White House, San Roque 1, San Jose, Occidental Mindoro, Philippines</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Ian Player, P.O. Box 192, Howick 3290, Natal, South Africa</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">N. Sitwell, c/o WWF(UK), 11-13 Ockford Rd., Godalming, Surrey GU7 lQU, England</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">L. M. Talbot, 6656 Chilton Court, McLean, Virginia 22101, USA</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Forest Research Institute, College, Laguna 3720, Philippines</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Bearded Pig</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Julian Oliver Caldecott, Sub-Department of Veterinary Anatomy, University of Cambridge, Downing Street, Cambridge CB2 3DY, England</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">C. P. Groves, Department of Prehistory and Anthropology, The AustralianNationalUniversity, P.O. Box4, Canberra, ACT 2600, Australia</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Alastair A. Macdonald, Department of Anatomy, Royal (Dick) School of Veterinary Studies, University of Edinburgh, Edinburgh EH9 10H, Scotland, United Kingdom</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">J. MacKinnon, WWF/IUCN Representative, P.O. Box 133, Bogor, Indonesia</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">National Parks and Wildlife Office, Sarawak Forest Department, Jalan Gartak, Kuching, Sarawak, Malaysia (Kron Aken, David Labang, Mike Kavanagh)</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">W. L. R. Oliver, Jersey Wildlife Preservation Trust, Les Augres Manor, Jersey, Channel Islands, United Kingdom</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">John Payne, Wildlife Section, Forest Department, P.O. Box 311, Sandakan, Sabah, Malaysia </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">M. H. Woodford, c/o FORW, FAO, Via delle Terme di Caracalla, 00100 Rome, Italy</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Zoos with Bearded Pig</P>
+<P ALIGN="JUSTIFY">Singapore, Singapore</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">Manila, Philippines</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Sulawesi Warty Pig</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">C. Catibog-Sinha, Outdoor Recreation and Wildlife Research Division, Forest Research Institute, College, Laguna 3720, Philippines</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">C. P. Groves, Department of Prehistory and Anthropology, The AustralianNationalUniversity, P.O. Box4, Canberra, ACT 2600, Australia</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Alastair A. Macdonald, Department of Anatomy, Royal (Dick) School of Veterinary Studies, University of Edinburgh, Edinburgh EH9 10H, Scotland, United Kingdom</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">J. Mackinnon, WWF/TUCN Representative, P.O. Box 133, Bogor, Indonesia</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">W. L. R. Oliver, Jersey Wildlife Preservation Trust, Les Augres Manor, Jersey, ChanneL Islands, United Kingdom</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">M. H. Woodford, c/o FORW, FAO, Via delle Terme di Caracalla, 00100 Rome, Italy</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Zoos with Sulawesi Warty Pig</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">None.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Javan Warty Pig</P>
+<P ALIGN="JUSTIFY">Raleigh A. Blouch, 2125 Forest Glen, Lansing, Michigan 48906, USA</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">A. A. Bosma, Department of Functional Morphology, Faculty of Veterinary Sciences, State University Utrecht, P.O. Box 80157, 3508 TD Utrecht, The Netherlands</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Directorate of Nature Conservation (PPA), Jalan Ir. H. Juanda 9, Bogor, Indonesia</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">C. P. Groves, Department of Prehistory and Anthropology, The Australian National University, P.O. Box 4, Canberra, ACT 2600, Australia</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Lembaga Biologi Nasional (LBN-LIPl), Bogor, Indonesia</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Alastair A. Macdonald, Department of Anatomy, Royal (Dick) School of Veterinary Studies, University of Edinburgh, Edinburgh EH9 10EI, Scotland, United Kingdom</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">J. MacKinnon, WWF/IUCN Representative, P.O. Box 133, Bogor, Indonesia </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">W. L. R. Oliver, Jersey Wildlife Preservation Trust, Les Augres Manor, Jersey, Channel Islands, United Kingdom</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Werner Pauwels, Pfeffingerstrasse 48, CM-053, Basel, Switzerland</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Perum Perhutani, Forest State Corporation, Jalan Jendral Gatot Subroto 17-18, Post Box 111, Jakarta, Indonesia</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">M. H. Woodford, c/o FORW, FAO, Via delle Terme di Caracalla, 00100 Rome, Italy</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Zoos with Javan Warty Pig</P>
+<P ALIGN="JUSTIFY">Jakarta, Indonesia (Kebun Binatang Ragunan)</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Surabaya, Indonesia (Kebun Binatang Surabaya)</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Pigmy Hog</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">A. A. Bosma, Department of Functional Morphology, Faculty of Veterinary Sciences, State University Utrecht, P.O. Box 80157, 3508 TD Utrecht, The Netherlands</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">P. C. Gogoi, Adviser Forests, (Wildlife and Environmental Planning), Meghalaya, P.O. Shillong 793 001, India</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">C. P. Groves, Department of Prehistory and Anthropology, The AustralianNationalUniversity, P.O. Box4, Canberra, ACT 2600, Australia</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Alastair A. Macdonald, Department of Anatomy, Royal (Dick) School of Veterinary Studies, University of Edinburgh, Edinburgh EH9 lOH, Scotland, United Kingdom</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">J. MacKinnon, WWF/IUCN Representative, P.O. Box 133, Bogor, Indonesia</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">W. L. R. Oliver, Jersey Wildlife Preservation Trust, Les Augres Manor, Jersey, Channel Islands, United Kingdom</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">S. Deb Roy, Manas National Park, P.O. Barpeta Road, Kamrup 781 315, India</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Zoos with Pigmy Hog</P>
+<P ALIGN="JUSTIFY">Gauhati, India (Assam State Zoo)</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Zurich, Switzerland</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Babirusa</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">A. A. Bosma, Department of Functional Morphology, Faculty of Veterinary Sciences, State University Utrecht, P.O. Box 80157, 3508 TD Utrecht, The Netherlands</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">C. P. Groves, Department of Prehistory and Anthropology, The Australian National University, P.O. Box 4, Canberra, ACT 2600, Australia </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Alastair A. Macdonald, Department of Anatomy, Royal (Dick) School of Veterinary Studies, University of Edinburgh, Edinburgh EH9 lOH, Scotland, United Kingdom</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">J. MacKinnon, WWF/IUCN Representative, P.O. Box 133, Bogor, Indonesia</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">W. L. R. Oliver, Jersey Wildlife Preservation Trust, Les Augres Manor, Jersey, Channel Islands, United Kingdom</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Victoria Selmier, 353 10th Street, San Francisco, California 94103, USA</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Zoos with Babirusa</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Antwerp, Belgium (Royal Zoological Society of Antwerp, W. de Meurichy)</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Bandung, Indonesia</P>
+<P ALIGN="JUSTIFY">Berlin, Federal Republic of Germany, (Zoologischer Garten)</P>
+<P ALIGN="JUSTIFY">Copenhagen, Denmark, (Zoologisk Have)</P>
+<P ALIGN="JUSTIFY">Frankfurt, Federal Republic of Germany</P>
+<P ALIGN="JUSTIFY">Jakarta, Indonesia, (Kebun Binatang Ragunan)</P>
+<P ALIGN="JUSTIFY">Nuremberg, Federal Republic of Germany</P>
+<P ALIGN="JUSTIFY">Poznan, Poland</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Rotterdam, The Netherlands (Stichting Koninklijke Rotterdamse Diergaarde)</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Stuttgart, Federal Republic of Germany</P>
+<P ALIGN="JUSTIFY">Surabaya, Indonesia, (Kebun Binatang Surabaya)</P>
+<P ALIGN="JUSTIFY"></P>
+<B><P ALIGN="CENTER">&lt;&lt;TOC2&gt;&gt; Advisory Committee on Technology Innovation</P>
+</B><P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">HUGH POPENOE, Director, International Programs in Agriculture, University of Florida, Gainesville, Florida, Chairman </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Members</P>
+<P ALIGN="JUSTIFY">WILLIAM BRADLEY, Consultant, New Hope, Pennsylvania</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">HAROLD DREGNE, Director, International Center for Arid and Semi-Arid Land Studies, Texas Tech University, Lubbock, Texas (member through 1981) </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">ELMER L. GADEN, JR., Department of Chemical Engineering, University of Virginia, Charlottesville, Virginia </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">CARL N. HODGES, Director, Environmental Research Laboratory, Tucson, Arizona </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">CYRUS MCKELL, Native Plants, Inc., Salt Lake City, Utah </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">FRANCOlS MERGEN, Pinchot Professor of Forestry, School of Forestry and Environmental Studies, Yale University, New Haven, Connecticut (member through 1982) </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">DONALD L. PLUCKNETT, Consultative Group on International Agricultural Research, Washington, D.C. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">THEODORE SUDIA, Deputy Science Advisor to the Secretary of Interior, Department of Interior, Washington, D.C. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<B><P ALIGN="CENTER">&lt;&lt;TOC2&gt;&gt; Board on Science and Technology for International Development</P>
+</B><P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">GEORGE BUGElARELLO, President, Polytechnic Institute of New York, Brooklyn, New York, Chairman </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Members</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">SAMUEL P. ASPER, Educational Commission for Foreign Medical Graduates, Philadelphia, Pennsylvania </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">DAVID BELL, Department of Population Sciences, Harvard School of Public Health, Boston, Massachusetts </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">LEONARD BERRY, Professor, Graduate School of Geography, Clark University, Worcester, Massachusetts </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">ERNEST.J. BRISKEY, Dean, School of Agriculture, Oregon State University, Corvallis, Oregon </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">HARRISON S. BROWN, Director, Resources Systems Institute, East-West Center, Honolulu, Hawaii </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">ROBERT H. BURRIS, Department of Biochemistry, University of Wisconsin, Madison, Wisconsin </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">CLAUDIA JEAN CARR, Associate Professor, Conservation and Resource Studies, University of California at Berkeley, Berkeley, California </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">NATE FIELDS, Director, Developing Markets, Control Data Corporation, Minneapolis, Minnesota </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">ROLAND J. FUCHS, Chairman, Department of Geography, University of Hawaii at Manoa, Honolulu, Hawaii </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">ELMER L. GADEN, JR., Department of Chemical Engineering, University of Virginia, Charlottesville, Virginia </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">JOHN HOWARD GIBBONS, Director, U.S. Congress, Office of Technology Assessment, Washington, D.C. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">N. BRUCE HANNAY, Foreign Secretary, National Academy of Engineering, Washington, D.C. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">WILLIAM HUGHES, Director, Engineering Energy Laboratory, Oklahoma State University, Stillwater, Oklahoma </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">WILLIAM A. W. KREBS, Vice President, Arthur D. Little, Inc., Acorn Park, Cambridge, Massachusetts </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">GEORGE I. LYTHCOTT, University of Wisconsin, School of Medicine, Madison, Wisconsin </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">JANICE E. PERLMAN, Executive Director, Committee for a New New York, New York City Partnership, New York, New York </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">HUGH POPENOE, Director, International Programs in Agriculture, University of Florida, Gainesville, Florida </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">FREDERICK C. ROBBINS, President, Institute of Medicine, National Academy of Sciences, Washington, D.C. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">WALTER A. ROSENBLITH, Foreign Secretary, National Academy of Sciences, Washington, D.C. </P>
+<P ALIGN="JUSTIFY">FREDERICK SEITZ, President Emeritus, The Rockefeller University, New York, New York </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">RALPH HERBERT SMUCKLER, Dean of International Studies and Programs, Michigan State University, East Lansing, Michigan </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">GILBERT F. WHITE, Institute of Behavioral Science, University of Colorado, Boulder, Colorado </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">BILL C. WRIGHT, Assistant Dean for International Programs, Oklahoma State University, Stillwater, Oklahoma </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">JOHN G. HURLEY, Director</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">MICHAEL G. C. McDONALD DOW, Associate Director/Studies </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">MICHAEL P. GREENE. Associate Director/Research Grants </P></FONT></BODY>
+</HTML>
Index: /main/tags/2.25/gsdl/collect/demo/import/bostid/b20cre/b20cre.htm
===================================================================
--- /main/tags/2.25/gsdl/collect/demo/import/bostid/b20cre/b20cre.htm	(revision 21064)
+++ /main/tags/2.25/gsdl/collect/demo/import/bostid/b20cre/b20cre.htm	(revision 21064)
@@ -0,0 +1,1032 @@
+<HTML>
+<HEAD>
+<META HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=windows-1252">
+<META NAME="Generator" CONTENT="Microsoft Word 97">
+<TITLE>&lt;&lt;TOC1&gt;&gt; Managing Tropical Animal Resources - Crocodiles as a Resource for the Tropics</TITLE>
+</HEAD>
+<BODY>
+
+<B><FONT FACE="Arial" SIZE=2><P>&lt;&lt;TOC1&gt;&gt; Managing Tropical Animal Resources - Crocodiles as a Resource for the Tropics</P>
+</B><P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Report of an Ad Hoc Panel of the</P>
+<P ALIGN="JUSTIFY">Advisory Committee on Technology Innovation</P>
+<P ALIGN="JUSTIFY">Board on Science and Technology for International Development</P>
+<P ALIGN="JUSTIFY">Office of International Affairs</P>
+<P ALIGN="JUSTIFY">National Research Council</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">In Cooperation with the Division of Wildlife, Department of Lands and Environment, Papua New Guinea</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">NATIONAL ACADEMY PRESS</P>
+<P ALIGN="JUSTIFY">Washington, D.C. 1983</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Board on Science and Technology for International Development(BOSTID) </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Panel on Crocodile Farming</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">EDWARD S. AYENSU, Director, Office of Biological Conservation, Smithsonian Institution, Washington, D.C., USA, Chairman </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">HOWARD W. CAMPBELL (deceased) U.S. Fish and Wildlife Service, Gainesville, Florida, USA </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">ARCHIE F. CARR, Jr., Department of Zoology, University of Florida, Gainesville, Florida, USA </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">F. WAYNE KING, Director, Florida Museum, Gainesville, Florida, USA </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">FRANCOIS MERGEN, Pinchot Professor of Forestry, Yale University, New Haven, Connecticut, USA </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">MICHAEL G. MORRIS, Furzebrook Research Station, Institute of Terrestrial Ecology, Wareham, Dorset, England </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">HUGH POPENOE, Director, International Programs in Agriculture, University of Florida, Gainesville, Florida, USA </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">ROBERT M. PYLE, Species Conservation Monitoring Unit, Cambridge, England </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">SHELDON R. SEVERINGHAUS, Representative, The Asia Foundation, Taipei, Taiwan </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Contributors</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Papua New Guinea</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">CAROL GABARA, Wildlife Division, Department of Oro Province, Popondetta </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">WASSAM GABARA, Wildlife Division, Department of Oro Province, Popondetta </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">KAROL KISOKAU, Director, Office of Environment and Conservation, Waigani </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">NAVU KWAPENA, Division of Wildlife, Department of Lands and Environment, Konedobu </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">MIRO LAUFA, Division of Wildlife, Department of Lands and Environment, Konedobu </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">GREG MITCHELL, Crocodile Farm, Lae </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">LEO NING, Division of Wildlife, Department of Lands and Environment, Wewak </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Other Countries</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">MIGUEE AEVAREZE DEE TORO, Instituto de Historia Natural, Departamento de Zoologia, Chiapas, Mexico</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">ANGUS D'A.BELLAIRS, Department of Anatomy, St. Mary's Hospital Medical School, University of London, England</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">PETER BRAZAITIS, Department of Herpetology, New York Zoological Society, Bronx, New York, USA</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">ROBERT H.CHABRECK, Louisiana Cooperative Wildlife Research Unit, Louisiana State University, Baton Rouge, Louisiana, USA</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">MAX C.DOWNES, The Game Conservation Centre, Melbourne, Australia</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">KARLHEINZ FUCHS, hoechst Aktiengesellschaft, Frankfurt, Federal Republic of Germany</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">CLAIRE HACEN, Reptile Products Association, New York, USA</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">RENEE.HONEGGER, Zurich Zoo, Zurich, Switzerland</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">TED JOANEN, Rockefeller Wildlife Refuge, Chenier, Louisiana, USA</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">JOHN LEVER, Koorana Crocodile Farm, Rockhampton, Queensland, Australia</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">WILLIAM MAGNUSSON, Instituto Nacional de Pesquisas da Amazonia, Manaus, Amazonia, Brazil</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">HARRY MESSEE, School of Physics, University of Sydney, Sydney, New South Wales, Australia</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">FRED PARKER, Kirwan Queensland, Australia</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">ANTHONY POOLEY, St. Lucia Estuary, Zululand, South Africa</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">CHARLES A.ROSS, National Museum of Natural History, Smithsonian Institution, Washington, D.C., USA</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">K.B.SALE, UNDP/FAO Crocodile Breeding and Management Project, Hyderabad, India</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">LUISVARONA, La Habana, Cuba</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">CHAROON YOUNGPRAPAKORN, The Samutprakan Crocodile Farm, Samutprakan, Thailand</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">UTAl YOUNGPRAPAKORN, The Samutprakan Crocodile Farm, Samutprakan, Thailand</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">MYRNA WATANABE, Co-editor of ICUN Newsleter, Brooklyn, New York, USA</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">ROMULUS WHITAKER, Guindy Deer Park, Madras, India</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">NOEL D. VIETMEYER, Professional Associate, Board on Science and Technology for International Development, Crocodile Study Director</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">National Research Council Staff</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">F. R. RUSKIN, BOSTID Editor</P>
+<P ALIGN="JUSTIFY">MARY lANE ENGQUIST, Staff Associate</P>
+<P ALIGN="JUSTIFY">CONSTANCE REGES, Administrative Secretary</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">This publication is dedicated to the memory of panel member Howard W. "Duke" Campbell who devoted most of his professional life to the conservation of crocodilians. Dr. Campbell was Chairman of the Crocodilian Specialist Group of the Survival Commission of the International Union for Conservation of Nature and Natural Resources at the time of his death in 1981.</P>
+<P ALIGN="JUSTIFY"></P>
+<B><P ALIGN="CENTER">&lt;&lt;TOC2&gt;&gt; Preface</P>
+</B><P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The panel that produced this report met in Papua New Guinea in May 1981. Its purpose was to consider the principles of the Papua New Guinea crocodile farming program and their implications for economic development and for the management and survival of crocodilians elsewhere.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Crocodiles are an integral part of the tropical fauna; they are ecologically important, biologically interesting, and, potentially, a renewable natural resource of considerable economic value. The panel hopes that through this report the possibility of saving and managing this animal throughout the tropics can be better assessed.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Members of the panel consulted officials of the Ministry of Wildlife and Conservation in Port Moresby and visited crocodile farms in Moitaka, Popondetta, and Lae. The panel is grateful to Karol Kisokau, Navu Kwapena, and Miro Laufa of the Division of Wildlife for arranging its itinerary and visits in Papua New Guinea. It also wishes to thank Yano Belo, Minister of Environment, for hosting an evening social at the Moitaka crocodile farm; Greg Mitchell and his wife Judy, who entertained the panel at their home in Lae and conducted a tour of their company's crocodile farm; and Wassam and Carol Gabara who acted as guides and hosts in Popondetta.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The Advisory Committee on Technology Innovation (ACTI) of the Board on Science and Technology for International Development, National Research Council, is assessing scientific and technological advances that might prove especially applicable to problems of developing countries. This report is one of a series that explores promising areas of science previously unknown, neglected, or overlooked. Current titles in the ACT! series on Managing Tropical Animal Resources include:</P>
+<P ALIGN="JUSTIFY">· Water Buffalo: New Prospects for an Underutilized Animal (1981) </P>
+<P ALIGN="JUSTIFY">· Little-Known Asian Animals with a Promising Economic Future (1983) </P>
+<P ALIGN="JUSTIFY">· Crocodiles as a Resource for the Tropics (1983) </P>
+<P ALIGN="JUSTIFY">· Butterfly Farming in Papua New Guinea (1983) </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">These activities are supported largely by the U.S. Agency for International Development (AID). Program costs for this study were sponsored by AID'S Bureau for Asia, and staff costs by AID'S Office of the Science Advisor, which also made possible the free distribution of this report. </P>
+<P ALIGN="JUSTIFY"></P>
+<B><P ALIGN="CENTER">&lt;&lt;TOC2&gt;&gt; 1 Introduction</P>
+</B><P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Crocodiles, alligators, caimans, and gavials ( Present-day crocodilians are grouped into three families: crocodiles, alligators and caimans, and gavials (gharials). The animals differ from one another only in minor characters such as shape of snout, arrangement of scutes, and dental features. This report focuses mainly on crocodile species, but its conclusions are generally applicable to alligators, caimans, and gavials.) have existed for some 200 million years - much longer than mammals - but they are now disappearing at alarming rates. Of the 21 or so species of crocodilians distributed in the warm waters of the world, at least 18 are threatened with extinction in most of the countries where they are found.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Although some species, such as the American alligator, appear to be out of danger because of strict conservation measures, many of the others survive mostly in national parks, protected preserves, or a few breeding stations. This is true for the slender-spouted crocodiles of Africa and Asia, the saltwater crocodile of Australia and Southeast Asia, the black caiman and Orinoco crocodile of South America, the Chinese alligator, the Siamese crocodile, and other species.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Habitat destruction is a major contributor to crocodilian decline; each year more breeding areas are disturbed as swamps and marshlands are drained, rivers dammed, estuaries reclaimed, and riverine forests denuded. However, illegal poaching by tribal people with their simple but effective traps, snares, and set hooks, as well as professional hunters operating with power boats, spotlights, and modern firearms are also decimating the animals over most of their ranges.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">To a large extent these animals are being destroyed because of their market value. Crocodile is regarded as the costliest and most fashionable leather in western markets. Since World War II, demand for crocodile leather shoes, handbags, luggage, wallets, watchbands, and other expensive luxury articles has far exceeded supply. Even small items such as purses and handbags sell for many hundreds of dollars each. For instance, a ladies' purse or handbag made from crocodile skin can command prices as high as $4,000. A pair of men's shoes may cost from $500 to $900, and a wallet from $150 to $250.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The crocodile trade peaked in the mid-1960s, when world markets absorbed more than 2 million crocodile skins each year. Today it is still large. In 1979, for instance, 1,000,000 caiman hides and 300,000 true crocodile hides entered international commerce. In 1981 the United States itself imported 100,000 hides.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">International markets for reptile hides and leathers are centered in France, Italy, the Federal Republic of Germany, and Japan. France, the single largest buyer of raw crocodilian hides, uses an estimated 300,000 to 400,000 skins a year. The major buyers of finished crocodile leather products are Hong Kong, Japan, Thailand, Singapore, and the United States.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Unrestricted hunting and poaching for hides are wiping out the large breeding animals. Excessive hunting has a devastating effect on crocodile populations because their age distribution is like a pyramid: a small number of breeding animals dominates a large number of juveniles and hatchlings, most of which never survive to maturity. Such societies, in which the size of future populations depends on only a few animals, are highly vulnerable to extinction; once some of the mature members are killed the population can crash. And it takes a long time for a crocodilian population to rebuild because for most large species the females do not begin breeding until they are at least 8 years old.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Rearing Crocodiles</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Although there may seem to be no future for many crocodile populations, the situation is not hopeless. With intelligent intervention and under good conditions they can recover rapidly. Mature crocodiles have no enemies other than man, and, given some care and protection, a small number of breeders can produce a huge number of progeny each year. Mature females of the various crocodilian species usually lay between 30 and 70 eggs each year, and under normal conditions most of these eggs hatch successfully. The key to conserving the population is to protect the few mature animals and their habitats. Then, because of their fecundity, crocodilians can rapidly build up large numbers of young.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">This has been exemplified by the American alligator (Alligator mississippiensis). Ten years ago its future seemed doubtful, but the legal protection of the populations has brought a remarkable recovery. Numbers are now so high that two states have lifted the ban on harvesting alligators, and between lo,ooo and 20,000 American alligator hides now enter commerce each year.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The past few decades have seen several other examples of successful crocodile-rearing projects. Later chapters of this book highlight the national program in Papua New Guinea. In addition, three successful government-operated farms exist in India (where all the progeny is returned to the wild because current Indian law prohibits commercial crocodile farms). A remarkable farm with more than 3,000 breeding animals operates on the outskirts of Bangkok, Thailand. Australia has four crocodile farms, and a few African countries now have crocodile farms that are already beginning to supply hides internationally. For example, in 1982 Zambia had two such farms, Zimbabwe, five, South Africa, four (with five more planned or under construction), and Kenya, one. Appendix A lists these and other countries that are initiating farms for various crocodilian species.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The early technical success of these projects offers the expectation that with an appropriate framework of safeguards and research, crocodiles might become a thriving resource for tropical nations. If such experiences can be replicated, crocodilians and their habitats may come to be considered as resources to be managed and treasured. This will require considerable investment, strict legislation and law enforcement, and international cooperation and research, as well as careful monitoring of the traffic in farmed hides. But national crocodile industries are a possibility, and they could result in thriving natural populations that are free from the danger of extinction.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Such prospects may also provide economic incentives for preserving the often-fragile ecosystem in which wild crocodilians live. Crocodile farming could play a part by slowing the uncontrolled draining of swamps and other wetlands that cover large areas of the lowland humid tropics of Asia, Africa, and Latin America.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Crocodiles as a managed resource could economically benefit remote areas of the lowland tropics. Villagers there often have few alternative sources of income and possibilities for economic development are limited. Because the human population is relatively sparse, few opportunities exist for local trading; even where fish are abundant the problems of marketing are formidable. Indeed, in some areas crocodiles may constitute the only readily salvable resource.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Crocodiles as Farm Animals</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Well-fed crocodiles grow quickly. Under ideal conditions they may reach lengths of 1 m or more in a year and 1.5 m in 2 years. They are normally harvested in the third year when they reach about 2 m in length. In this time their value may have risen from about $5 to as much as $200.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Crocodiles have acquired a reputation as voracious feeders; investigations reveal this to be false. The animals actually have modest food requirements. Many hatchling animals have a food conversion rate of about 50 percent; that is, the crocodile adds 1 kg of weight for every 2 kg of food it consumes. Cattle, sheep, and pigs would have to eat 3-5 times as much food to achieve the same weight increase. After 2 years the crocodile's growth rate begins to slow down. During the third year the conversion falls to about 25 or 30 percent, which is still a high figure, and makes crocodiles probably the most nutritionally efficient land animal for commercial husbandry. Only the growth of some fish is comparable.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The high food conversion efficiency is due to the fact that crocodiles have low metabolic rates and are normally extremely lethargic. They are active only in short bursts, spend hours immobile, and move only about one-third as much as mammals. Moreover, being reptiles, they spend almost no food energy maintaining body temperature. They bask in the sun to keep warm and seek shade or water to cool off. For these reasons crocodilians can thrive in marginal habitats unsuitable for mammals or birds (Investigations on the Nile crocodile showed that a pelican takes 3 days to consume food equal to its own weight, whereas a crocodile takes 125-160 days - Cott, 1961.) </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Crocodile farming is also space efficient. As long as they are sorted by size, hundreds of juveniles or dozens of larger animals can be penned together in a small area. Indeed crocodiles often choose to pile up on top of one another in stacks.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Little is known about disease in reptiles. However, as farm animals, crocodiles have a major advantage: they produce antibodies readily and have few problems with external infections. In the wild it is common to find crocodiles missing limbs or tips of tails, with eyes gouged out, or enormous scars on the body. But the wounds heal readily, with little sign of infection (The American alligator is being used at the University of Florida College of Veterinary Medicine as a model for studies on antibody formation.). This minimizes the need for veterinary services, a distinct benefit in remote village farms. Nevertheless, internal bacterial diseases, such as salmonella, can get out of hand and destroy a program by reducing growth rates, lowering hide quality, or killing the animals outright.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Crocodile Hides</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">It is the belly skin that is the valuable part of a crocodile, and the worth of a hide is determined by the size of the belly skin, the smallness of its scales, and the hide's general condition. (Holes, cuts, scars, and rot drastically reduce its value.)</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Although international markets utilize any crocodile skin from 0.3 m to 6 m long, the most sought-after hides are not the biggest but the moderate-sized ones from animals about 1.5-2 m long. These hides are approximately 25-50 cm in belly width.( A crocodile's total length is approximately 4-4.5 times the width of its belly). Large hides, for example those more than 3 or 4 m in length, are suitable only for luggage and briefcases because their scales are large. Smaller hides, on the other hand, are suitable both for items such as shoes, handbags, and wallets and for larger items.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Internationally, the most desirable hides come from the saltwater crocodile (Crocodylus porosus). It has proportionally the smallest belly scales of any crocodile, it lacks osteoderms,(Osteoderms are deposits of calcium carbonate under the skin. They are undesirable because they dissolve away during the tanning process, leaving a pitted surface),and on the side of its body the scales are uniformly small. The next most valuable hides probably come from Morelet's crocodile (Crocodylus moreletii), the American alligator, the Siamese crocodile (Crocodylus siamensis), and the Nile crocodile (Crocodylus niloticus). </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Papua New Guinea</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The rest of this report highlights the program in Papua New Guinea, where during the last 10 years the government has made crocodile rearing an organized industry, much as poultry farming is elsewhere. This program, which is beginning to establish crocodiles as a significant natural asset, is designed both to protect the wild populations and to integrate traditional uses of these reptiles into a scientifically managed hide industry.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">In Papua New Guinea crocodile farming (In the official terminology of the Convention on International Trade in Endangered Species of Wild Fauna and Flora (CITES), the Papua New Guinea program is "ranching" rather than "farming" because the young livestock are mostly culled from wild populations and are not bred on the farm) has become the cornerstone for the economic improvement of some of the world's poorest people. It offers a means for bringing the rural poor into the process of economic development, and it can be blended into a traditional village structure where land and resources may be communally owned.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The projects are small and many have had operational difficulties, but they suggest that conservation and economic development can be not only compatible, but also mutually reinforcing. The innovative idea is not that crocodiles can bring in money, but that sound conservation can be blended with marketing crocodile skins, meat, and by-products.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">An important aspect of this approach to crocodile conservation is that it is based on protecting the existing landscape and resources. It provides a tool for conserving the species in their own wild habitats so that survival will not depend on a few captive specimens living under artificial conditions. It requires none of the bush clearing, fencing, forage planting or pesticide spraying that domestic animals often demand ,important advantages in an economic development project in a fragile tropical swamp or rain forest ecosystem.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The Papua New Guinea approach, then, provides an economic incentive for wildlife protection. Everyone ,from the villager to the minister of trade ,has a stake in keeping the wild populations healthy. Out of self-interest, in addition to natural respect, large numbers of people become the guardians of the resource and the habitat needed to keep it surviving and productive.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The world's major conservation organizations have given Papua New Guinea's crocodile program their stamp of approval. In 1976 a team of scientists representing the International Union for the Conservation of Nature and Natural Resources, one of the most prestigious conservation organizations in the world, inspected the program. As a result, Papua New Guinea was given special dispensation, and its crocodile skins can be legally traded internationally. For example, because of its endangered status the saltwater crocodile is banned from trade by the Convention on international Trade in Endangered Species of Wild Fauna and Flora (CITES). An exemption, however, is granted to Papua New Guinea in recognition of the fact that its crocodiles now are sufficiently well managed to sustain a skin industry without seriously damaging the wild stock.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">This program serves as a model for nations of the Americas, Asia, and Africa where crocodilian resources are still unmanaged or managed poorly. Crocodiles are being destroyed so fast that within about five years Papua New Guinea and other countries that have organized crocodile farming operations may be the only ones supplying significant numbers of skins to the international market.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Although the principles developed in Papua New Guinea deserve international attention, the recipe will not be a cure-all for problems of rural development or crocodile conservation. Instead, the Papua New Guinea experience suggests that local social, political, economic, and conservation goals can become the impetus for a successful blend of village improvement and wildlife protection.</P>
+<P ALIGN="JUSTIFY"></P>
+<B><P ALIGN="CENTER">&lt;&lt;TOC2&gt;&gt; 2 Crocodile Farming in Papua New Guinea</P>
+</B><P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">As recently as the l950s, crocodiles were abundant in Papua New Guinea. Hunting was a major occupation and was unrestricted. Some Australians and Europeans made fortunes by shooting thousands of crocodiles a year to make shoes and handbags in Europe and North America.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Although it was obvious that wild populations could not sustain such wholesale slaughter, the destruction continued. By 1967 both the saltwater crocodile (Crocodylus porosus) and the freshwater crocodile (Crocodylus novaeguineae) were threatened with extinction. By 1968, despite increased hunting, the yield of skins had dropped in half; along the easily accessible river systems, crocodile populations had been wiped out. By 1969 the saltwater crocodile had disappeared from much of its range throughout the country, and wildlife officers estimated that without protection most specimens of breeding size would be eliminated within five years.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">But how could crocodiles be protected? Papua New Guinea is divided by mountain ranges, ravines, torrential rivers, forests, seas, malarial swamps, and more than 700 languages. It would take hundreds of trained wildlife officers to enforce a ban on crocodile hunting, particularly in the face of opposition from tribesmen who have traditionally harvested crocodiles for food, decorative items, and implements.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The challenge was given to the officers of the Wildlife Division. Under the leadership of Max C. Downes, these officials concluded that the best way to protect crocodile populations was to halt the slaughter of the large breeding adults and build up a new hide industry based on the increased numbers of young that would result.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Few young crocodiles ever reach breeding age in the wild. The tiny, virtually defenseless hatchlings are easy prey for large fish, birds, or other crocodiles. Almost all of them are killed by predators or by other natural causes, such as floods..</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Main areas of crocodile distribution in Papua New Guinea.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">What was needed, the wildlife officers concluded, were incentives to make these smaller animals economically attractive, incentives to encourage local people to raise small crocodiles to commercial size. If that could be accomplished, hundreds of hatchlings that would normally perish could be utilized without endangering the wild populations' future. Villagers could benefit by selling skins while the vital breeding-sized animals were being left alone to provide more hatchlings. The system could benefit both the villagers and the vulnerable crocodile populations.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&lt;&lt;I&gt;&gt; b20a.png Main areas of crocodile distribution in Papua New Guinea</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The idea was viable partly because many Papua New Guineans - particularly those of the Sepik and Fly Rivers - have ancient spiritual and cultural attachments to crocodiles. To them, the idea of handling and managing the animals is not unusual. Crocodile motifs are common in their art and they live in harmony with the big beasts and do not consider them dangerous pests to be eliminated.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Legislation passed by the Papua New Guinea government in 1969 capitalized on this tradition by making the villagers themselves the real force in crocodile protection. The law did not ban crocodile hunting, but instead banned the possession, sale, and export of skins larger than 20 inches (51 cm) wide. In this way, it protected breeding-sized animals while allowing for the harvest of juveniles. It also allowed a person to kill a crocodile if attacked (but barred the selling of the skin, if it were oversized).</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">In 1980, the legislation was supplemented by a law banning the export of small skins. Together, the bans on possessing large skins and exporting small skins have created a stimulus for gathering small crocodiles from the wild and rearing them to moderate size on farms. The legislation has been the impetus for crocodile farming.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Crocodile farming officially started in Papua New Guinea in 1972. In the late 1970s, it was extensively supported by a UNDP/FAO assistance program that provided personnel and funds for technical support and program management. Today there are about 300 small village farms (The numbers vary, since some villagers go in and out of production depending on their need for income, seasonal variation in river levels, the cost of fuel, and the availability of government extension agents) supplying a number of larger business groups that rear crocodiles.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Wildlife officers now teach crocodile farming, not crocodile conservation per se. They have introduced crocodile-rearing techniques to villagers all over Papua New Guinea. They help build pens and teach tribesmen how to care for the young reptiles, which are so vulnerable and timid that they can literally die of fright.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Government loans of up to US$10,000, along with matching development bank loans, are available to help a farmer enter the crocodile farming business. The funds pay for pumps for changing the water in the pens and sometimes for an outboard motor used in gathering young crocodiles. Everything else a villager needs can be obtained from the forest, including materials for pen construction; a small farm can therefore be established inexpensively.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The Three Types of Farms</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The government's crocodile management program recognizes three levels of operation: village farms (up to 300 crocodiles), small-business farms (up to 1,000 crocodiles), and large-business farms (more than 1,000 crocodiles).</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">A village crocodile farm consists of a small pen fenced with posts lashed together with vines. This stockade fence is about 1.5 m high and is sunk about 60 cm in the ground so the crocodiles cannot burrow out. Much of the enclosure is planted with grass, cassava, and banana trees to provide secluded areas where the animals, which regulate their body temperature by the warmth of the sun, can find shade. A shallow pool is excavated in the center.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">These village farms are usually run by only one or two people. Many are little more than pens scattered in the remote bush for holding young crocodiles until a buyer from a larger farm comes around. Small crocodiles bring less money than medium-sized animals, but the villager avoids having to feed and care for them for a long period.(Because of operational difficulties, many village farms were abandoned in 1982. Lack of proper husbandy - despite government efforts - were the main reason for these difficulties. Most villagers now collect and hold young only until buyers from commercial farms arrive. However, they are still earning money from crocodiles, and the concept of fully functioning village farms remains valid for the future in Papua New Guinea, as well as for appropriate sites elsewhere). </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The small-business farm usually consists of a group of enclosures (each about 6 m x 6 m) constructed of bush materials. It is typically located near an airstrip. It buys crocodiles from the village farmer and, in turn, supplies them to the larger farms, which sometimes dispatch aircraft to pick the animals up (Special cardboard shipping containers have been devised. They can be folded to make cylinders of various diameters to fit crocodiles of different sizes). </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Large-scale crocodile farms accommodate as many as 20,000 crocodiles and require a large investment. They serve to regulate the export of skins and are the major purchasers of live crocodiles from the smaller farms. During periods of drought, flooding, or diminished food supplies, the large-scale farms also act as emergency buyers. On the outskirts of Lae on Papua New Guinea's northern coast, there is a 100-hectare farm with nearly 8,000 crocodiles. It is associated with a poultry company, and the crocodiles are raised on the offal from the slaughterhouse.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Government Research and Extension</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The Wildlife Division has constructed four demonstration farms across the country and one large research farm at Moitaka near Port Moresby, the capital city. After training at one of these, a tribesman can start his own farm alone or can call on the government for further assistance.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Moitaka is also the site of short courses in crocodile farming. Prospective farmers are brought in for several weeks' training. They learn how to build pens, to feed and care for crocodiles, to kill and skin them, and to prepare the hides for market. They also learn about the crocodile laws and the reason they were enacted. A farm at Lake Murray, in a remote and swampy area of the Western Province, serves the same purpose. It is built entirely from bush materials (see picture, pp. 6-7).</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The Wildlife Division provides instruction books, profusely illustrated for the illiterate. The books include vivid descriptions of all phases of farming the animals.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Economic Gains</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">In 10 years, crocodile rearing has expanded remarkably in Papua New Guinea. It has already become the main source of income for the people of some swamp and river areas. The Ambunti area, for example, produces coffee and rice, but crocodile skins now bring in much of the area's income. By 1981 the farms nationwide contained a total of 30,000 crocodiles, ensuring a sustained production of at least 10,000 skins a year worth approximately US$ 1-2 million on the international market.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Because crocodiles are a familiar resource, villagers take to the program quickly. By contrast, introducing cattle or western-style crop raising requires massive education and training, in addition to some social and environmental disruption.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">On government farms in Papua New Guinea, fish-fed crocodiles have increased their belly width by 25 cm per year and are ready for slaughter in 2-3 years when the width approaches 50 cm. The selling price of the skin is then between $100 and $200, depending on species, flaws, and size.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">But skins are not the only product. A crocodile with a skin big enough to market can provide 20 kg of meat. The meat is white and is low in fat. Papua New Guinea is a net importer of meat, and crocodile farming is now augmenting local supplies. The large farm at Lae already sells frozen crocodile meat (including front and hind legs, tail steaks, ribs, and chops) both locally and on foreign markets. Some orders have come in from dealers in Paris who supply expensive French restaurants.</P>
+<P ALIGN="JUSTIFY"></P>
+<B><P ALIGN="CENTER">&lt;&lt;TOC2&gt;&gt; 3 Conclusions</P>
+</B><P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Benefits of Crocodile Farming</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Crocodile farming seems to be singularly appropriate for rural, isolated, lowland communities in the tropics. The land there is often unsuitable for conventional agriculture, and the people lead a tenuous existence or drift to the cities looking for work. In such areas, there are few opportunities for people to earn cash without drastic and expensive modifications to the environment.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Crocodile farming has many advantages over hunting the animal in the wild. For instance, crocodiles farms can:</P>
+<P ALIGN="JUSTIFY">· Permit government monitoring of the crocodile industry. (Hunters are more difficult to regulate since they work in remote areas, often undetected and crossing borders at will.)</P>
+<P ALIGN="JUSTIFY">· Yield a regular harvest of a specific number of animals of a selected size.</P>
+<P ALIGN="JUSTIFY">· Produce a standardized, premium product that better serves the needs of the international hide industry, making skins poached from the wild less desirable. (They may provide, for instance, a standard first grade 1-1.5 m long hide rather than hides of mixed size and quality.)</P>
+<P ALIGN="JUSTIFY">· Reduce the wasteful losses of hides from improper handling, the fate of a high proportion of skins now brought in from the wild.(*In remote areas, salt may become scarce late in the season as it is used for hides. This often results in insufficient salt being used when the supply runs out and hides subsequently rot or "slip". In some isolated areas, as much as 25 percent of the hides are lost or downgraded because of improper curing for lack of salt. However, skins produced on farms, especially near urban areas or large villages, are usually properly salted; if salt becomes scarce, killing of the animals can be delayed) </P>
+<P ALIGN="JUSTIFY">· Educate the public about crocodile ecology and the animal's importance to the habitat and the local economy.</P>
+<P ALIGN="JUSTIFY">· Provide sites for scientific studies on crocodilians. Studies conducted on alligators at the Rockefeller Refuge in Louisiana, USA, for example, have provided reproductive, nutritional, and growth data directed specifically towards developing efficient farming techniques.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">For some farms the earnings from hides, meat, and by-products may be supplemented by tourism (through gate admissions and the sale of curios), as well as by selling eggs and young to other farms for breeding stock.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">A long-term program of wise utilization of crocodiles can benefit governments by providing revenue from hides, curios, craftwork, and manufactured articles, as well as from export duties. Furthermore, in their natural state in parks and preserves, crocodiles are an important tourist attraction.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">In an effort to preserve crocodile habitats, the Papua New Guinea program has encouraged the collection of eggs or young from the wild and has discouraged the breeding of crocodiles in captivity. This is because a reliance on the wild creates economic incentives to conserve crocodile habitats; if the habitats are drained for human settlement or conventional agriculture the farmers lose the source of their stock.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Contrary to popular impression, preliminary observations indicate that crocodiles benefit commercial fisheries. The animals are important links in the ecosystems of rivers and lakes and are often the largest inhabitants of the freshwater wetlands. Their movements inhibit the growth of aquatic plants in the waterways, and, in areas with prolonged dry seasons, some species maintain residual waterholes that benefit small aquatic organisms that would otherwise perish. In estuaries and lakes, crocodiles enrich the nutrient content of the water by converting terrestrial prey into feces that in turn feed invertebrates and fish.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Where crocodiles have been eliminated, reductions in the tonnage of fish caught for human consumption can usually be demonstrated. For example, in Brazil, Kenya, and India, a decline in the fishermen's catch has paralleled the decline in crocodiles.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Limitations of Crocodile Farming</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Governments and individuals seeking rapid returns on investments should realize that a crocodile farming industry is not a get-rich-quick scheme. To build a stable national industry may require 10 years and an investment of at least $500,000 before it is biologically and economically successful.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Nevertheless, an organized industry is vital. A village crocodile-rearing pond is only profitable if there is someone to buy, grade, package, and ship the product with all its documentation. Services will be needed at all levels to advise on disease control, nutrition, skinning, and preserving the hides. In many parts of the world crocodile farms have been financial and conservation failures not just because of poor husbandry management, but also because of fiscal shortsightedness.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Selection of a suitable farm site is basic to the economics of the entire operation. Farms demand a steady supply of meat or fish to feed the crocodiles, and are most successful when located near a reliable source of inexpensive food. Some farms take advantage of offal from nearby chicken or cattle abattoirs; others use the fish by-catch from shrimping operations. In the absence of an inexpensive animal protein feed, the farm will have to raise its own food (tilapia is frequently used) or harvest it from the wild, both of which can be expensive.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Crocodile farms also require a steady year-round supply of clean water for the holding ponds and tanks. If this cannot be supplied by gravity flow from nearby sources, it must be pumped from wells or from nearby lakes or ponds. This, too, is likely to be expensive.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Despite the general hardiness of crocodiles, the farms must have access to veterinary care. Most disease problems stem from poor sanitation, low water temperatures, and poor diet, all of which can be easily corrected. But with large numbers of animals crowded together, disease problems, if not quickly diagnosed and treated, can wipe out the young captive animals in epidemic proportions.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Capturing and transporting large crocodilians is dangerous and difficult. Dealing with a large captive population of crocodiles of different age groups and sizes requires a great deal of experience.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Although crocodilians are common in zoos, successful breeding of these reptiles in captivity is so far a rare and remarkable event. However, researchers are now coming to understand the behavioral requirements for success. For instance, gravid females must have access to appropriate nesting sites, males must have ample space when they are penned in with other males, and juveniles and hatchlings must be separated from their parents and housed by size and feeding preferences. That prolific breeding can be achieved, however, is illustrated by the Samutprakan crocodile farm near Bangkok, Thailand, which reportedly has reared tens of thousands of its own animals and now aims for a population of 100,000 crocodiles by 1987.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Conservation</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The worldwide shortage of crocodile leather is becoming more acute each year, and it will be many years before any output from farms can significantly reduce pressure on wild populations. Thus, farming should be only one aspect of an overall conservation program that includes total protection of some populations in national parks and sanctuaries. In addition, the conservation of natural wetlands is an important part of overall economic planning. If wetlands are lost, many wild species in addition to crocodiles will be affected.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">In Australia, Asia, Africa, and the Americas, many crocodilian populations are poorly protected because governments lack the manpower or the will to enforce conservation laws rigorously, especially in the remote areas where the last remaining crocodiles reside. Because most wildlife departments in the tropics are short staffed and have vast areas to police, their efforts at wildlife protection are frequently ineffective. Moreover, some countries have been slow to introduce protective legislation for an animal that does not engender public sympathy.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Papua New Guinea's program offers one of the best hopes for saving all endangered crocodiles, alligators, caimans, and gavials. The methods developed there serve as a model for other nations. By providing an alternative, Papua New Guinea gives villagers the incentive to protect wild crocodiles that are breeding nearby so as to assure themselves of future supplies. The people themselves become the conservators of the local animals and habitats. In turn, watersheds, soils, and conventional agricultural development (including natural and forest products) can all benefit. The habitat is also preserved for many other wildlife species that share it, and genetic diversity can be maintained. Conversely, without a special incentive to conserve them, all these resources are normally degraded as a region develops.</P>
+<P ALIGN="JUSTIFY"></P>
+<B><P ALIGN="CENTER">&lt;&lt;TOC2&gt;&gt; 4 Regulations, Safeguards, and Research Needs</P>
+</B><P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The Papua New Guinea experience provides a model for other nations, but to implement such a program requires a foundation of legislation, government support, and legal safeguards. Prerequisites of any crocodile farming program are an overhaul of legislation, strict law enforcement, and reciprocal laws with neighboring countries.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The enforcement of wildlife regulations is so inadequate in most countries that crocodile farming is open to abuse. Farms can front for illegal poaching operations, and hides taken from the wild can be intermingled with hides produced on the ranch or farm unless government enforcement is stringent and inspection frequent.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Moreover, the stimulation of world trade in crocodile hides through the sale of farmed hides might lead to increased poaching of wild crocodiles or eggs. Poachers have fewer operating expenses than farmers, and unscrupulous hunters and dealers can harvest hides, steal crocodile eggs or young, and subsequently sell them through countries that lack enforcement capabilities. This practice could be disastrous for countries where crocodile populations have almost disappeared.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Government Regulations</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Before any farming scheme is attempted, protective legislation should be in operation throughout the country. This should make it unlawful to kill, capture by any means whatsoever, disturb willfully, or pursue any crocodiles, or to collect or gather any crocodile eggs without a permit.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">No crocodile eggs should be allowed to be imported or exported with out a permit. No persons should possess, sell, buy, donate, receive consequent upon a donation, convey, keep in captivity, or display any live crocodiles without being the holder of a permit. And no person should be allowed to import or export any crocodile, dead or alive, or any portion of a crocodile, processed or not, from any country without a permit.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Before granting a license for a commercial farm, the government should investigate the applicant's land tenure and financial resources, particularly since the farm will have to operate for three to four years before producing crocodiles suitable for culling. The applicant's ability and experience in rearing crocodiles should be determined. A plan of the proposed farm, including details of water and food supply and the proposed methods of harvesting food, should be examined.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">It is suggested that:</P>
+<P ALIGN="JUSTIFY">· No permit for egg harvesting should be issued until adequate rearing facilities have been prepared. The permit should state the name of the holder or his authorized representative, the annual total number of eggs allocated for harvesting, and the area where collection is permitted.(In some cases it is also important to specify a harvest time. Often it is best to take eggs laid early in the season because the female will then lay another clutch.) </P>
+<P ALIGN="JUSTIFY">· Permits should be issued on a year-by-year basis. The applicant should understand that the department may refuse to renew or issue further permits if the farm is not managed satisfactorily or if permit conditions have not been observed.</P>
+<P ALIGN="JUSTIFY">· The applicant should understand that the farm and all production records should be available for inspection by an official of the conservation department.</P>
+<P ALIGN="JUSTIFY">· The farmer should be required to submit periodic reports detailing the total number of nests raided and eggs harvested, the egg mortality, and the number of eggs hatched. Thereafter, the number of animals held in captivity, the rate of mortality and its causes, if known, and the number of animals sold or culled should be included in each report.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Furthermore, it is recommended that the permit holder release 5 percent of his annual crop of hatchlings in order to restock the natural habitat. In addition, a further 5 percent of the hatchling crop should be reared to a length of 1 m before being released, bringing the total release of young crocodilians to 10 percent of the annual crop of hatchlings.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The distribution of hatchlings and young reared animals should be supervised by the conservation department.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Unless government agencies monitor the wild populations of crocodilians being harvested for hides, eggs, or young, the farms themselves could become a major drain on those populations, leading to their extinction. Therefore, before any farming program is started, a survey of the breeding grounds should be undertaken to determine the number of nests available and those from which eggs can be taken with least danger to the wild population (for example, from nests on grounds likely to be flooded).</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">These breeding grounds should be fully protected; tourists on foot, in vehicles, or in launches should not be allowed to visit or disturb crocodiles during the breeding season.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">International Safeguards and Cooperation</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The international traffic in millions of unmarked crocodilian hides and products poses one of the greatest obstacles to enforcement of national and international endangered species regulations. Hides and skins frequently cannot be traced to their source or country of origin. Legally harvested or farmed animals cannot readily be distinguished from those exported in secret from illegal sources.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The need for internationally acceptable methods of marking individual hides and products is critical. Traffic in illegal crocodilian hides and products will continue as long as law enforcement agencies lack the means to detect them easily.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">In the United States a system has been developed in some states that enables conservation, police, and customs officials to monitor traffic in alligator hides. A conservation authority issues an official tag for each animal allowed by the license. All hides exported are tagged with a serially numbered plastic tag that cannot be removed without breaking it. The serial number is recorded on the export permit and with details of the buyer's and seller's name and address. This tag remains on the hide, right through the tanning process, until the hide reaches the manufacturer. Each tannery maintains a register of purchases that is available for inspection. This system also is being implemented in Zimbabwe and is worthy of trial in other countries.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The tagging of all hides and products for individual identification is an important safeguard. Other safeguards include:</P>
+<P ALIGN="JUSTIFY">· The use of engraved stamps or seals to authenticate legal licenses and export permits and make it more difficult for documents to be forged.</P>
+<P ALIGN="JUSTIFY">· Internationally accessible data and a retrieval system that allows law enforcement personnel to corroborate the authenticity of documentation and the origin of hides and products;</P>
+<P ALIGN="JUSTIFY">· Monitoring agencies to record and publish market statistics, traffic, and trends;</P>
+<P ALIGN="JUSTIFY">· Laws limiting the sale of hides only to nations that cooperate in an internationally sanctioned program of safeguards; and</P>
+<P ALIGN="JUSTIFY">· Research funding to monitor populations and develop new marking and identification techniques. (For instance, the use of dyes, roll marking, and infusion of detectable chemical tracers has yet to be fully explored.)</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Research Needs</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">There is urgent need for tannery owners, manufacturers, and conservation authorities to jointly work out the rational exploitation of crocodile populations. Commercial interests have reaped a rich reward over many years, and if the crocodile industry is to continue, its entrepreneurs must invest in management and conservation.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Clearly, research to improve farming techniques will be a wise investment for both commercial operators and the countries concerned. Surveys to determine population numbers and size as well as the structure of breeding stocks and recruitment rates are essential. Such surveys may indicate the need to establish sanctuaries to protect breeding stock and nesting grounds, or perhaps to ban hunting to allow populations to recover. A rearing program and restocking of suitable habitats might be necessary.</P>
+<P ALIGN="JUSTIFY"></P>
+<B><P ALIGN="CENTER">&lt;&lt;TOC2&gt;&gt; Appendixes</P>
+</B><P ALIGN="JUSTIFY"></P>
+<B><P>&lt;&lt;TOC3&gt;&gt; Appendix A: Crocodile Farming Around the World</P>
+</B><P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Experiences with crocodile farming in Papua New Guinea, the main subject of this report, are described in chapter 2. Here we summarize the status of similar efforts in other countries.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Australia</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Four crocodile farms have been established in Australia, one in the Northern Territory and three in Queensland. To date, only the Edward River farm, operated by the government as an aboriginal development project, has developed a successful breeding program. There, seven-yearold saltwater crocodiles (Crocodylus porosus) hatched on the farm from wild eggs are now breeding and laying fertile eggs. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Asia</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">People's Republic of China</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">A farm for Chinese alligators (Alligator sinensis) has been established at Xuancheng, Anhui Province. Its purpose is to breed alligators for conservation, although the hide of this species is not in great demand because it has many osteoderms in the belly scales. Recently the government has expressed interest in establishing a farm for saltwater crocodiles in southern China. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Taiwan</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Taiwan has one crocodile farm or rearing station, but it is too far north to breed its own stock, except in heated indoor enclosures.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Philippines</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">There are several buyers in the Philippines who maintain pens of crocodiles for short periods. None of these is a farm. A new experimental farm for the Philippine freshwater crocodile (Crocodylus novaeguineae mindorensis) was established by Silliman University in an attempt to preserve that endangered species and to promote an economic interest in crocodile conservation.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Micronesia</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">A farm for saltwater crocodiles has been established on Palau, where a small population of these crocodiles occurs in a brackish interior swamp. In the past, the government hired a hunter to reduce the population whenever the local people felt it had become sufficiently large to present a danger, about once a decade. Presumably the nuisance crocodiles will now end up in the farm. The farm, which has been in existence only for a year or two, earns money from tourist admissions as well as hide production.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Indonesia</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">A few crocodile-rearing stations have operated for several decades in Java, Sumatra, and Kalimantan. These have been stocked with eggs and young animals collected from the wild in Sumatra and Kalimantan. In the early 1970s, three such operations in Samarinda, East Kalimantan, closed down for lack of wild stock. At least one operation in Jakarta, Java, continues to survive, but with virtually no output of stock.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">A survey of Irian Jaya (Indonesian New Guinea) in 1980 indicated a number of ranches in that region as well, but revealed that some were having difficulty obtaining stock because of overharvest.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Singapore</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Singapore has a famous crocodile farm that figures prominently in tourism. It breeds some of its stock, but also obtains wild stock from all over Southeast Asia. Singapore has a thriving crocodile hide trade. Many buyers and several tanneries are located there.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Singapore is not a member of CITES and openly trades in any and all species of crocodilians.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Malaysia</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">There are several crocodile farms in West Malaysia (at Penang, for example) and at least one in East Malaysia (near Sandakan, Sabah). These started out as rearing stations relying on wild young, but have moved slowly toward breeding their own stock. The Penang farm depends on tourism to pay many of its expenses. The Sandakan farm is operated in conjunction with a duck and pig farm that supplies it with offal. Its stock consists of saltwater crocodiles. Until at least 1980, it had very little production from captive animals, but the owner is hoping to broaden his stock from them.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Sarawak (East Malaysia) also used to have several rearing farms. The present status of these operations is unknown.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Thailand</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The Samutprakan Crocodile Farm was started in 1950 with 20 wild crocodiles and an investment of US$500. Today it is reported to be the world's largest crocodile farm, with about 30,000 individuals. About 3,700 of these animals, placed in eight separate breeding ponds, are used for breeding stock, and there are plans for a population of 100,000 by 1987. The Samutprakan farm opened to the public 12 years ago and now receives about one million visitors annually.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Most of the farm's crocodiles are from the two species native to Thailand, the saltwater crocodile and the Siamese freshwater crocodile (Crocodylus siamensis). It also has hybrids of the two, as well as the indigenous false gavial (Tomistoma schlegelii) and five exotic species: South American caiman (Caiman crocodilus), New Guinea freshwater crocodile (Crocodylus novaeguineae), Chinese alligator (Alligator sinensis), broad-spouted caiman (Caiman latirostris), and dwarf caiman (Paleosuchus palpebrosus). The farm has succeeded in breeding South American caiman (Caiman crocodilus); the other species are approaching maturity and it is hoped they will breed in the near future.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The farm sells crocodile meat locally, mostly to restaurants as a delicacy (for US$5 per kg).</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The commercial and biological success of the farm is largely due to favorable conditions at Samutprakan. The temperature and humidity are high year-round, and low costs of labor and building materials permit the physical plant to be profitably established and maintained. The main cost is for food; approximately 4,000-5,000 kg of by-catch fish are needed daily at a cost of US 20 cents per kg. If the supply of fish is inadequate, the diet is supplemented with chicken wings, legs, and necks from a slaughterhouse.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Burma</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">In Rangoon there are some crocodile-holding pens operated by hide buyers. It is not clear whether breeding or farming of crocodiles occurs in them or whether the operation simply acts as a clearing center for wild hides. The government has expressed interest in establishing farms in the mangrove areas near the mouth of the Irrawaddy River. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">India</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">In 1974 an FAO report on India's crocodiles noted that the Indian gavial (Gavialis gangeticus) was on the verge of extinction, the saltwater crocodile was extremely rare, and the Indian mugger (Crocodylus palustris was a depleted, although not threatened, species).</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The government, with United Nations assistance, then initiated a project for the conservation and management of all three species. This program aimed to protect and restock habitats. Animals for restocking were obtained by collecting eggs laid in the wild, incubating them under controlled conditions, raising the resulting hatchlings, and returning juveniles to specially selected sanctuaries when they reached about 1.2 m in length,at which time they are free from predation other than by man.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The project has resulted in the comeback of the gavial. By March 1979, 200 gavials had been restored to the wild. The wild population now exceeds 1,000 animals of more than 2 m length, and the number is expected to increase rapidly through natural reproduction.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The project has also carried out extensive research on crocodiles, and since its founding in 1978 the Central Crocodile Breeding and Management Training Institute, located in Hyderabad, has trained many wildlife officers in crocodile protection. Crocodile-rearing facilities are also located near Madras, Lucknow, and Cuttack. All have had success in raising the animals and restocking their habitats.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The Indian crocodile project has been a notable success and it coincided with (and perhaps helped create) a wave of local interest in India's wildlife and its conservation.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Israel</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">A farm stocked with American alligators (Alligator mississippiensis) was established at a popular hotwater spring resort area, using animals supplied by a Florida farm. The Israeli program will earn money from tourist admissions and from future production of hides. The first successful hatching of captive-bred alligators was reported in 1982.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Africa</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Kenya</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Near Mombasa a farm for the Nile crocodile (Crocodylus niloticus) has been set up to produce hides from captive-bred stock. The farm is a demonstration project of a large cement factory that is attempting to return its limestone-mined areas to productive agriculture. Some sophisticated experiments are under way on crocodile nutrition, with food for the animals produced in an intensive aquaculture project using tilapia. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Zambia</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Zambia is planning a series of farms patterned after those in Zimbabwe (described below).</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Zimbabwe</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Zimbabwe has made great strides in captive breeding. In 1979, 87 captive females at two farms produced 1,906 eggs, and a third farm has set aside 30 captive females for breeding.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Four of the country's five crocodile farms are on the shores of Lake Kariba and the other is at Victoria Falls. The government allows each farm an annual allotment of wild eggs (averaging 2,000 to 2,500 eggs) for stocking its rearing programs. Each farm is also striving to become self sufficient in egg production by developing successful breeding programs. The government is considering reducing each farm's allotment by the number of eggs produced annually in the farm so that each will eventually become independent of the wild populations.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Zimbabwe farmers operate on a system that obliges them to return a small percentage of live animals to the wild if the government requires it. At present, this requirement is being waived because the wild population is increasing on its own.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Zimbabwe has built its crocodile conservation program on a broad base. Crocodiles are protected throughout the country, as game animals in the country at large and as totally protected species in parks and sanctuaries. Populations have increased dramatically, from endangered status in the l950s to over 50,000 individuals today. In the 1950s a survey of the Zambesi River and Lake Kariba revealed no crocodiles; today thousands are seen.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Zimbabwe's Department of National Parks and Wildlife is striving to ensure that its legitimate international trade in farm-raised hides does not provide illegal operators in other countries with the opportunity to sell poached hides (for example, forging papers that claim their hides originated on legitimate Zimbabwe farms). To make poaching difficult, Zimbabwe, taking a clue from the state of Louisiana, plans to use serially numbered nonremovable plastic tags to mark legitimate hides. Numbers of the tags will be noted on export permits. In addition, every export permit will be validated by the government with an engraved security stamp that is difficult to forge and that shows ink damage if any erasures or modifications are attempted. The use of such stamps is recommended by CITES, and Zimbabwe is the first nation to put them into use.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">South Africa</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">South Africa has four crocodile farms, and another five are planned or under construction. Apart from the Natal Parks Board Crocodile Research Station at St. Lucia Estuary, which breeds Nile crocodiles for restocking and conservation purposes, all farms are for tourism and hide production. So far only one farm, outside Pretoria, is reported to produce many offspring. Only the provinces of Transvaal and Natal have wild crocodiles, and neither allows eggs, young, or adults to be collected for stocking farms. Both provinces, however, permit the killing of nuisance crocodiles on private land. Transvaal will allow one or two nuisance crocodiles to be taken captive by farmers, but it refuses permission for removing larger numbers of nuisance animals,presumably for fear that this would generate a flood of spurious nuisance complaints. Natal will not permit the removal of any wild crocodiles to farms, nor will it supply offspring from the St. Lucia station to farmers. This makes the Pretoria farm the only source of crocodiles in South Africa.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Following the example of Zimbabwe, the South African farmers (present and potential) formed a crocodile farming association in 1982.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Botswana</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Several farms patterned after those in Zimbabwe are planned for the Okavango area. Petitions for approval are currently before the Botswana government.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Chad</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">In the late 1960s French businessmen established a farm for Nile crocodiles near Lake Chad. It collapsed after only a few years.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Ivory Coast</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The government of Ivory Coast has obtained assistance from Zimbabwe to establish a conservation program for its three native crocodiles: the Nile crocodile, African slender-spouted crocodile (Crocodylus cataphractus), and Congo dwarf crocodile (Osteolaemus tetraspis). Recommendations were made for conserving the wild populations as well as for establishing farms. Field studies are under way.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Europe</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Italy</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">A commercial farm for the South American caiman (Caiman crocodilus) was established in southern Italy in the late 1970s. Stock was obtained from Colombia. The animals, numbering in the thousands, arrived in Rome in winter and were transported south to the farm in an open truck. Most died from cold. Later shipments fared no better, and the few animals that survived died from poor husbandry. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The Americas</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">United States</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">There are between 15 and 20 successful alligator farms in the United States. Most are located in Florida and Louisiana, and there is at least one in California. All earn a portion of their money from tourist admissions.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Cuba</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">In the 1960s the Cuban government established at least two farms for crocodiles. One is located in the Zapata Peninsula National Park; the other is near Cienfuegos. The purpose of these farms is to breed crocodiles whose wetland habitat has been converted to sugar cane fields. Eventually, the farms will also produce a cash crop of hides.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Unfortunately, what started out as an admirable effort created several conservation problems because the farm managers did not realize there were two crocodiles in Cuba ,the American crocodile (Crocodylus acutus) in brackish waters, and the Cuban crocodile (Crocodylus rhombifer) in freshwater areas. The two were mixed in the farms and hybridization resulted.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Mexico</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The Mexican government has established several farms for Morelet's crocodile (Crocodylus moreletii) in Chiapas and Veracruz. The purpose is to breed the species in captivity to relieve hunting pressure on the wild population and prevent its extinction. Original funding was provided by the World Wildlife Fund. At least one of these farms still exists. Breeding has been achieved, but there have been problems of survival in hatchlings. The cause of the deaths has not been discovered.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">In recent years several businessmen in Mexico have expressed interest in starting one or more crocodile farms, but none has yet materialized.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">El Salvador</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">In the late 1960s, the Louisiana Game and Fisheries Commission supplied specimens of the American alligator to a cattle rancher in El Salvador for the purpose of establishing an experimental farm.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Louisiana was interested in studying growth rates of American alligators in a tropical nation where the animals did not have to undergo winter hibernation. The husbandry on the farm followed methods worked out in Louisiana. The animals grew fast and presumably have started breeding. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Venezuela</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">A captive breeding program for the Orinoco crocodile (Crocodylus intermedius) was established in Venezuela in the late 1970s on the ranch of Tomas Blohm. The operation is not commercial; its purpose is to prevent extinction of the species. The offspring may be used for restocking wild habitats in the future.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Under Venezuelan law there can be no commercial export of any crocodilians. In addition, the Orinoco crocodile and the various caimans are protected. However, the reptiles are everywhere killed as vermin.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Peru</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Peru has proposed harvesting certain wild populations of caimans (Caiman crocodilus) to supply animals to a ranching operation.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">BraziI</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The government of Brazil is interested in establishing farms for several species of caiman, including the yacare (Caiman crocodilusyacare). </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Other Latin American Nations</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">During the past two years, other Central and South American nations that have indicated their intention to set up farms for crocodiles or caimans are Bolivia, Colombia, Costa Rica, Ecuador, French Guiana, Guatemala, Guyana, Haiti, Honduras, Nicaragua, Panama, Paraguay, Suriname, and Uruguay. </P>
+<P ALIGN="JUSTIFY"></P>
+<B><P>&lt;&lt;TOC3&gt;&gt; Appendix B: Practical Crocodile Farming</P>
+</B><P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">This appendix is adapted from a paper by A. Pooley that detailed the lessons learned from farming crocodiles to restock depleted habitats in Natal, South Africa. The information is presented here not as a blueprint for setting up a farm, but to show prospective farmers some of the points that they must first consider before attempting to rear crocodiles.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Farm Location</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Reliable supplies of good water and suitable food are the most important considerations for establishment of a crocodile farm; the area selected must have both. Village farms also need to be close enough to wild crocodile populations for the animals to be obtained easily. Larger farms can be located farther from the source.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">For small farms, a natural supply of food should also be readily available in the wild. Areas that have a fishing industry are ideal locations. For large farms, sites near slaughterhouses or fish-processing facilities are ideal.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Other considerations also include the volume of water available throughout the year, the distance over which water must be piped to the ponds, and pumping costs. The quality of the water should be established, with samples tested for salinity and acidity and, where the supply comes from mineral springs, analyzed for harmful chemicals. Chlorinated water must be tested regularly to ensure that the chlorine content is not too high, and the nature of any factory effluents present should be determined. It is important to establish whether fish, frogs, crabs, mollusks, or aquatic insects survive in the water intended for use.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Bacterial analysis is advisable where the water is drawn from a river that drains an area densely populated by humans and livestock. If the water is found to be contaminated, the stagnant pond rearing pen system should not be used, particularly when Salmonella spp. are present in high concentrations.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">A filter system has advantages if water is pumped straight from a river carrying a heavy silt load. Apart from enabling farmers to see the animals in the pools, filtered water makes the pools and pipes easier to clean. Filtration can be achieved by drawing water from a deep pit close to the river so that the water collected seeps through sand or mud.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">A reservoir or a series of supply tanks is useful as an additional method of filtering water. In the event that pumping equipment fails, such a reserve supply may prove vital to the health and survival of the crocodiles.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The ponds should receive as much sun as possible, particularly during the winter months. A series of winter air temperature recordings would be useful in choosing the site of rearing pens, since valley temperatures are often several degrees lower than the temperatures some 50 to 100 m uphill. Preference should be given to the warmer locations, taking into account the direction of local winds and heavy rains.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Soil types are the next consideration. If soils are sandy and porous, earth ponds are impractical and a concrete lining is required to retain water.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Drainage of the ponds must be carefully considered. Drainage is far easier if the ponds are built on a slight rise. Water from the ponds must not be allowed to stagnate nearby; the drainage system must be efficient. It is recommended that pens be spaced at least 8 m apart and that their drainpipes lead underground at least 10 m before emptying.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Pen Construction</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Pens with rounded corners are the most successful. Crocodiles frequently choose to lie together in a pile. Square corners allow them to pile up against the angle, smothering those on the bottom and sometimes allowing animals to climb over the fence. With rounded corners, the pile cannot grow very high before the crocodiles slide sideways and the heap collapses.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Experiments in South Africa indicate that natural pools containing rooted vegetation are less prone to become sources of disease than are concrete pools. The surface of the concrete seems to become impregnated with liquid and debris from food and to become a breeding ground for bacteria. For hatchlings and very small juvenile crocodiles, concrete has an added disadvantage; its rough surface can abrade the belly skin when the animals slide in and out of the water, which can foster infection. In 5 or 10 years, even smooth concrete will erode sufficiently to become a problem.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Researchers elsewhere, however, report better results with concrete lined ponds, which they find easier to clean. Concrete pools are useful for summer because they can be scrubbed clean and because the volume of water used is small. Normally they need only be emptied, cleaned, and refilled every third day, and there is no wastage through seepage.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The pools are best built as channels. This provides more bank for basking and enables the pools to accommodate more crocodiles. Because the larger males become belligerent only when they can see each other, floating logs, patches of grass, or channel corners are visual barriers that reduce interactions. The channel system also gives more water edge, and this appears to satisfy the territorial instinct.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Crocodiles are famous for basking in the sun, but they die surprisingly easily of heat prostration. At least one-third of the land area of a farm pen should be shaded with vegetation. The amount of space around each pool is calculated to allow ample basking room for each animal, and an area of shade must likewise be provided.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">On land, crocodiles often seek contact with each other (thigmotaxis) and frequently lie piled on top of each other, but this should be a matter of choice rather than of overcrowding. There should be few enough animals in the enclosure to allow every crocodile to get out of the water if it chooses.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Ideally, only half the available number of pools should be occupied at a time, so that they can be used in rotation. In this system, the animals can be moved to fresh pools every two months (or as necessary), leaving the "used" pools to be drained and dried out to bake in the sun. After two months, the pools will then be clean and ready for use again.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">An important requirement is that the pools be at least 60 cm in depth; otherwise, the water becomes too hot in summer. The pool floor should be sloped towards the drain outlet to facilitate cleaning and flushing away uneaten food. Also, the outlet pipe should be 10 cm in diameter, with a stopcock outside the enclosure, so that the pool can be cleaned and emptied efficiently. It is essential to place a screen in the drainpipe to prevent small crocodiles from escaping or being sucked out of the pool during cleaning. After some time, stagnant ponds may become difficult to clean because of the heavy growth of algae on their sides. Hard-bristle scrubbing brushes are needed to dislodge this growth. Small amounts of copper sulfate in the water will help control algae if used regularly.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The entire pond and surrounding apron must be smoothly plastered to facilitate cleaning. It helps to have a water source close to each pool from which a hose pipe can be led to pressure spray and clean the pool and its apron.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">An important part of the design is a partly submerged, gently sloping ledge, some 45 cm in width, around the perimeter of the pool. This provides a shallow resting zone for the crocodiles and gives them easy access to the water. The crocodiles rest there when feeding, and the ledge prevents them from scraping their bellies and damaging their claws when they enter or leave the pool.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">For small crocodiles it is advisable to roof over the entire pen with wire netting or cries-crossed strands of wire. This protects against predators. Further, young crocodiles can climb vertical wire netting with ease and will escape unless the enclosure is either roofed or has side walls that slope inwards. A skirting board (planking, sheet iron, tin, or plastic sheeting) placed against the wire netting can also prevent this. If wire netting is used for the sides of the pens it should have mesh no larger than 1 cm so that hatchlings will not injure themselves by trying to climb through. While these pools are being cleaned, care must be exercised to prevent crocodiles from falling into the empty pool.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Water can be passed continuously through the pools. The advantage of this is that during hot summer weather, when crocodiles are feeding at their maximum rate, small uneaten food particles, feces, and urine are carried away. Constant dilution of the pond's water also ensures a low bacteria level. However, the pool must be drained and scrubbed clean at least weekly.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Earthen pools are easy and cheap to build and are a "natural" habitat where vegetation can be planted and small live fish introduced; insects, frogs, and other creatures attracted to the dams will be an important addition to the diet and health of the crocodiles. Earthen pools are ideal in climates where low winter temperatures are likely to cause respiratory illness in the young animals. During cold weather the crocodiles burrow into the mudbanks and survive nights of heavy frost.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Because of the animal's burrowing capabilities, it is important to provide a strip of land 4 m wide between the pool's edge and the boundary fence. Otherwise, crocodiles may tunnel beyond the fence line. Fences must be buried at least 1 m deep to intercept the burrows and to prevent predators from burrowing in. Burrowing, however, can be hazardous, because the burrows can collapse and suffocate the animals.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">In areas where the soil is porous or sandy, the floor of an earth dam can be sealed with concrete or plastic irrigation sheets. A layer of earth can be used to conceal this artificial floor. The disadvantages of earth pools are that, because of seepage, they require more water than concrete ones and that they require more maintenance because they cannot be efficiently cleaned. Even if the pools are provided with constantly circulating water, they eventually become fouled, particularly during hot weather.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Removing crocodiles from an earth pond can prove difficult, since most will take refuge in their burrows.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Capturing Crocodiles</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Crocodiles are located at night, usually from a boat, by shining a light along the edges of rivers and lagoons. Because of a reflective tapetum, the eyes of crocodiles glow reddish or orange and are visible for a hundred meters or more. If the population has not become exposed to hunting and become wary of people, the animals will not submerge when the light strikes them. Dazzled by the beam, they tolerate a stealthy approach, and small animals can simply be grabbed by hand or scooped up in a net. They can then be transported in sacks to the rearing pens. Larger animals may be noosed or baited into cylindrical screen traps at places they frequent along the water's edge.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Managing a Crocodile Farm</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">It is a problem to sort the young crocodiles. From one clutch of eggs, some individuals will be aggressive and others may be shy or extremely timid; growth may vary from rapid to very slow, with a few individuals classed as runts.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Larger animals can be so dominant that smaller individuals will not even attempt to feed. If sorting is not done, the smaller, less-aggressive individuals do not get a fair share of the food; they grow slowly and get bitten and harassed by the larger animals. At feeding time, some will flee to the opposite side of the pen and stop feeding altogether. Keeping the young animals sorted into classes of the same size avoids many of these problems.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Nutrition and Feeding</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Despite the crocodilian's reputation as a man-eater, small wild crocodiles live mainly on invertebrates and larger ones live mainly on fish. Papua New Guinea's farmers feed a varied diet of locally caught fish, crab, shrimp, frogs, snails, grasshoppers, beetles, and slaughterhouse waste. Whole animals minced up should be used, if necessary, because crocodiles require a diet of bone, intestine, scales, and other tissues to provide calcium and minerals. Bones in chopped fish must be minced thoroughly for hatchlings or very young crocodiles, or they should be fed very small fish supplemented by tadpoles or insects. One village in Papua New Guinea has shown remarkable success in rearing hatchlings on a diet of chopped fish and live freshwater shrimp.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Fish is an excellent food for the bulk feeding of a large captive population. Whole fish chopped into pieces, including the livers and hearts, forms a balanced diet that may be supplemented by meat, if available, to make up bulk. Small whole fish are particularly suitable; the crocodiles derive calcium from the bones and scales, plus roughage to facilitate digestion, while the flesh, liver, and heart are rich in nutrients and protein The main difficulty usually lies in harvesting enough fish to meet the crocodiles' demands.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Any method of supplementing the diet with live creatures is recommended. For instance, a light can be left burning in each pen about 15 cm above the water for attracting insects. Various types of insect traps may also be used.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Crocodiles also can be fed on a variety of wastes such as offal or noncommercial fish. Ideally, a large-scale farm should be located near a poultry slaughterhouse. (Cattle offal is also satisfactory, but it is not nutritionally adequate as a sole ration for crocodiles.) Even crocodile offal itself can be fed back to crocodiles. However, the use of offal will necessitate dietary supplements to assure sufficient phosphorus and calcium. These minerals are generally provided by feeding bones to the crocodiles.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Crocodiles usually consume their food in the water, but they can also be fed on land. They will eat daily, but are able to remain active for weeks without food. If they are fed in the water of a farm pen, the water will become polluted unless there is considerable flow to carry away the debris. In extreme cases, the pools become septic. To ensure the health of the growing animals, constantly flowing water is far superior to standing water. (The Samutprakan Crocodile Farm in Thailand feeds some of its animals in water, but the small feeding pools are separate from the large regular breeding pools and at a lower level to prevent their overflowing into the breeding pools.)</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">It is important to feed pieces of food small enough to be swallowed without difficulty. Large fish should be cut into elongated rather than square pieces, since the bones can cause damage during swallowing. Similarly, whole live fish should not be so large that the dorsal fin may cause damage to the reptile's throat and gullet.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">It is important to know the amount of food that each group of animals will consume at each meal. By feeding at the same time each day, it is easy to calculate how much is required. Moreover, the crocodiles become accustomed to a routine and the food is consumed while it is still fresh. In the hot summer months the animals will devour a full meal every 24 hours, but the feeding rate slackens with the onset of colder weather. It is then wise to start reducing frequency and quantities until food is required only every second or third day, depending on the climate. Generally, young crocodiles will refuse food when the air or water temperature falls below 60°F (15.6°C). Even in midsummer sudden cold spells may occur; at such times, it is usually futile to feed the animals or try to coax them to eat until the weather warms up again. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">During hot weather conditions it is preferable to feed late in the afternoon or evenings, mainly to avoid placing the food on a hot cement surface. The food should be spread out around the edge of the pool under the shaded area so that the animals do not have to climb over one another to reach it.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">In cemented pens the area where the food is laid out should be cleaned and scrubbed two hours after feeding time and any uneaten food removed from the water with a hand net. In earthen pools, the food should be placed at a different spot along the bank at each feeding. A useful aid to hygiene is keeping a few predacious fish, such as barbel (Clarias spp.), in each pool to clean up scraps of uneaten food.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Population Density</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Twenty-five crocodiles are considered the maximum manageable number per unit; staying within this limit reduces competition for food, bullying and fighting, and the number of injuries. A low stocking rate also results in a more even average growth rate. Most important is the fact that the overall health of the crocodiles is better than in a more crowded pen; disease problems are fewer and the symptoms easier to detect in a small group. If the units are spaced 8 m apart, there is also less danger of infectious disease spreading to other pens. The cleaning of pens is facilitated, and the disturbance caused by capturing crocodiles to be moved to other units is minimized. Housing 500 crocodiles in groups of 25 will require 20 separate pens, and an additional two pens should be provided to allow for intensive care of sick, injured, and weaker animals.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">During the first year, when animals are graded frequently, they will often be moved from one pen to another. Recording the number of animals housed in each pen will make it possible to keep track of numbers and movements.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Breeding</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Reproduction is impossible when crocodiles are kept in large groups composed of different species and sizes and in more or less unnatural enclosures.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Healthy, sexually mature pairs of crocodiles are usually not enough to start a breeding program. Genetic diversity to maintain a long-term breeding group must be considered, and certain environmental factors are vital for success. The distinct size and age classes of a free-living population must also be taken into consideration. Optimal sex ratios for breeding in enclosed compounds must be determined and adhered to. If a breeding unit is not based on regard for the animals' basic needs for space, nesting sites, and retreats, the larger specimens will disturb, injure, and often kill smaller specimens.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Diseases and Parasites</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Disease symptoms may be easily overlooked if the observer is not familiar with the behavior of crocodiles under a variety of conditions. It is essential to know how they normally walk, swim, sleep, feed, and bask in relation to the time of day, the air and water temperatures, and the amount of sunlight or rain, by day, by night, and at different seasons of the year. Caretakers should notice the appearance of feces from healthy animals to be able to detect evidence of diarrhea, and to identify misaligned teeth and weakened limbs to detect nutritional deficiencies. Eggs are critically dependent on specific temperature and moisture requirements if the embryos are to develop normally.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">It is often difficult to determine the cause of illness or death, and even if the ailment has been correctly diagnosed, it is not easy to capture and administer drugs to large numbers of sick animals. Some animals may be injured during the handling process. Emphasis on preventing disease, rather than curing it, is the best way of ensuring a healthy crop.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Almost inevitably, the water in the pools will harbor concentrations of bacteria such as salmonella. If strict hygiene is observed, however, the bacterial level will not be harmful.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">It is recommended that whenever possible animals found newly dead should be dissected and vital organs such as the brain, heart, lung, liver, spleen, kidney, and stomach removed for veterinary research. Blood slides should also be taken and feces samples collected. The various specimens must be carefully labeled, frozen as quickly as possible, and packed on ice in a vacuum flask for immediate dispatch to the nearest veterinary research institute or pathologist. Alternatively, dying animals may be sent live for research purposes.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">It is helpful for the handler to become thoroughly acquainted with the animal's internal anatomy, in order to distinguish between healthy and diseased organs. This knowledge, coupled with the symptoms noted before the animal dies, and the veterinary report, will be useful in future diagnosis and treatment.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">One problem for the crocodile farmer is a roundworm (nematode) parasite that burrows into the belly skin. When the burrow collapses it produces an undulating track across the belly and throat scales that ruins the hide. These parasites have been found in crocodiles from Latin America, Africa, Australia, Papua New Guinea, and Asia. They seem more prevalent in some areas and some farms than in others. The organism has been identified, but no treatment or control has been discovered. It is, however, believed that damp, muddy conditions foster the nematode, and that to reduce it pens should have areas of dry land where the animals can bask.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Killing, Skinning, and Tanning</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Some farmers kill the crocodiles themselves, but many rear the animals and then sell them to a larger concern that is better equipped to deal with the skins. Killing is done most quickly and humanely by catching the crocodile with a noose and severing the spinal cord just behind the skull.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Many hides are ruined or severely damaged during skinning. Even a single hole resulting from a slip of the skinning knife may reduce a hide's value by 25 percent.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">After skinning, the hides are normally coated with about 0.5 cm of coarse salt and rolled up. Within 48 hours they are unrolled and resalted. If the hide is not sufficiently salted, it may become infected with bacteria or fungi that cause the epidermis of the scales to decay or slip. Although this layer is removed during tannage, scale slip is a symptom of rot and usually causes damage to the finished hide product. If the decay is intense, the salted hides may become reddish or brown in color. This is called "red heat."</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Although salt remains the universally used preservative for raw hides, the reptile leather industry has developed chemical fixatives that are used in addition to salt for preserving hides for tanning. Most of these pretannage fixatives are liquid and require soaking the hide in a vat, which may not be feasible in remote areas.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">A pretanned hide is called a crust. It is green-gray (chrome tanned) or tan (vegetable tanned) and is stiff. The hide is dyed and glazed to its final finish. To increase the workability and to remove as many of the osteoderms as possible (if they are present), the underside of the hide is shaved to an even thickness. The shaving is done by craftsmen. If they shaved too much, the hide will be thin and weak, especially over the suture between the scales.</P>
+<P ALIGN="JUSTIFY"></P>
+<B><P>&lt;&lt;TOC3&gt;&gt; Appendix C: Selected Readings</P>
+</B><P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">General information on the management and status of crocodiles can be found in the following:</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">IUCN/Crocodile Specialist Group Newsletter. Available from the editors, Peter Brazaitis and Myrna Watanabe, c/o New York Zoological Park, Bronx Zoo, The Bronx, New York 10460, USA.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">A Field Guide of Captive Rearing and Management of Crocodiles in India is available from Mr. R. K. Rao, Director, Central Crocodile Breeding and Management Training Institute (Government of India), Hyderabad, Andhra Pradesh, India.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Blake, D. K. 1974. The rearing of crocodiles for commercial and conservation purposes in Rhodesia. The Rhodesia Science News 8(10):315-324.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Blake, D. K., and J. P. Loveridge. 1975. The role of commercial crocodile farming in crocodile conservation. Biological Conservation 8(4): 261-272.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Bolton, M. 1981. Crocodile Husbandry in Papua New Guinea. Field Document 4. FO: DP/ PNG/74/029. Food and Agriculture Organization of the United Nations, Rome, Italy. 103 pp.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Bolton, M., and M. Laufa. 1982. The crocodile project in Papua New Guinea. Biological Conservation 22:169-179.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Brazaitis, P. (In press) Problems in the Identification of Commercial Crocodilian Hides and the Effect on Law Enforcement. Proceedings of the IUCN Crocodile Specialist Group meeting in Zimbabwe September-October, 1982. International Union for the Conservation of Nature and Natural Resources, Gland, Switzerland.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Brazaitis, P. 1973. The identification of living crocodiles. Zoologica 58(3-4):59-101.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Cott, H. B. 1954. Ecology and economic status of the crocodile in Uganda. Record of the Symposium on African Hydrobiology and Inland Fisheries, Committee on Technical Cooperation for Africa South of the Sahara 6:119-122.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Cott, H. B. 1961. Scientific results of an inquiry into the ecology and economic status of the Nile crocodile (Crocodylus niloticus) in Uganda and Northern Rhodesia. Transactions of the Zoological Society of London 29(4):211-337.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Downes, M. C. 1978. An explanation of the National Policy for the Crocodile Programme. Wildlife Division, Department of Lands, Surveys and Environment, Konedobu, Papua New Guinea.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Fuchs, K., nd. Die Krokodilhaut Eduard Roether Verlag Darmstadt, Frankfurt, West Germany.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Graham, A., 1981. Mapping the pattern of crocodile nesting activity in Papua New Guinea. Field Document No. 3, FO: DP/PNG/74/029. Food and Agriculture Organization of the United Nations, Rome, Italy. 50 pp.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Joanen, T., and L. McNease. 1975. Notes on the Reproductive Biology and Captive Propagation of the American Alligator. Proceedings of the 29th Annual Conference of the Southeastern Association of Game and Fish Commissioners 29:407-415. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Joanen, T., and L. McNease. 1979. Culture of the American alligator. International Zoo Yearbook 19:61-66.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">King, F. W., and P. Brazaitis. 1971. Species identification of commercial crocodile skins. Zoologica 56(2): 15-72.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Loveridge, J. P. ed. 1982. The Zimbabwe Science News 16(9):196-219. Causeway, Zimbabwe. (Contains five articles on crocodilian research and conservation; from Zimbabwe, Australia the United States, and lndia.)</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Millichamp, N. J. ;980. Medical aspects of disease in reptile collections. In The Care and Breeding of Captive Reptiles, The British Herpetological Society, London, England.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Parker, F. 1981. New Crocodile Laws for Papua New Guinea. Division of Wildlife, Department of Lands and Environment, Konedobu, Papua New Guinea. 50 pp.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Pooley, A. C. 1969. Some observations on the rearing of crocodiles. Lammergeyer 10:45-59.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Pooley, A. C. 1971. Crocodile rearing and restocking. Pp. 104-130 in Crocodiles, IUCN Publications New Series Supplementary Paper 32. International Union for Conservation of Nature and Natural Resources, 1110 Gland, Switzerland.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Pooley, A. C. 1973. Conservation and Management of Crocodiles in Africa. Journal of the South African Wildlife Management Association 3(2):101-103.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Pooley, A. C. 1977. A report on Crocodile Farming. Papua New Guinea. Wildlife leaflet No. 77/27. pp. 1-14.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Pooley, A. C. 1981. Disappearing African Crocodiles. Oryx 16(1):38-40.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Pooley, A. C. (In press). The status of crocodiles in Africa. Paper Presented at 5th Meeting IUCN Survival Service Commission's Crocodile Specialist Group. Gainesville Florida, USA. September 1980.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Pooley, A. C., and C. Gans. 1976. The Nile crocodile. Scientific American 234(4): 114-124.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Wallis, B. E. 1980. Market prospects for reptile leathers. Report number ITC/DIP/12, International Trade Commission, Geneva, Switzerland. 50 pp.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Wermuth, Von H., and K. Fuchs. 1978. Bestimmen von Krokodilen und ihrer Haute. Gustav Fischer Verlag, Stuttgart, New York.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Whitaker, R. 1982. Export prospects from commercial crocodile farms in Bangladesh. ITC/UNCTAD, Geneva, Switzerland. 47 pp.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Whitaker, R., and M. Kemp. 1981. The crocodile industry in Papua New Guinea: Commercial Aspects. Field Document No. 2. FO:DP/PNC/74/029. Food and Agricultural Organization of the United Nations, Rome, Italy. 35 pp. </P>
+<P ALIGN="JUSTIFY"></P>
+<B><P>&lt;&lt;TOC3&gt;&gt; Appendix D: Research Contacts</P>
+</B><P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The following individuals are involved in crocodilian research. Most are biologists concerned with the conservation or natural history of the animals.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Australia</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Applied Ecology Crocodile Farm, Edward River, Queensland 4870</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Shelley Burgin, Total Environment Center, 18 Argyle Street, Sydney, New South Wales 2000</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Melvin Bolton, Woodbury Farm, Woodbury Road, M.S. 142, Via Yeppoon, Queensland 4703</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Max C. Downes, The Game Conservation Center, 24 Queens Parade, North Fitzroy, Victoria 3068</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Alistair Graham, P.O. Box41266, Darwin, Northern Territory 5792</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Gordon Grigg, Zoology A08, University of Sydney, Sydney, New South Wales 2006</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">John Lever, Koorana Crocodile Farm, M.S.F. 76, Rockhampton, Queensland 4702</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Harry Messel, Head, School of Physics, University of Sydney, Sydney, New South Wales 2006</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Fred Parker, 717 Ross River Road, Kirwan, Queensland 4814</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Grahame Webb, School of Zoology, University of New South Wales, Kensington 2033</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Bangladesh</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Mohd. Reza Khan, Assistant Professor, Department of Zoology, University of Dacca, Dacca 2</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Brazil</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">William Magnusson, Depto de Ecologia, Instituto Nacional de Pesquisas da Amazonia, Caixa Postal 478, 69000, Manaus, Amazonia</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Burma</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Ko Ko Gyi, Professor of Zoology, Rangoon Arts and Sciences University, Rangoon</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Nyan Taw, Research Officer, People's Pearl and Fishery Corporation, Myakhwanyo Street, Thaketa, Rangoon </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">People's Republic of China</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Huang Chu-Chien, Institute of Zoology, Chinese Academy of Science, Beijing</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The Swatow Prefecture Crocodile Farm, Shantou, Guang Dong Province</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Colombia</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Federico Medem, Instituto Roberto Franco, Apartado Aereo 2261, Villavicencio (Meta)</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Costa Rica</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Gerado Budowski, Head, Natural Renewable Resources Programme, CATIE, Turrialba</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Cuba</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Luis Varona, Norte 29, Nuevo Vedado, La Habana 6</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Dominican Republic</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Jose Alberto Ottenwalder, Museo Nacional de Historia Natural, Plaza de la Cultura, Santo Domingo</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Federal Republic of Germany</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Karlheinz Fuchs, Schillerstrasse 2, 6257 Hunfelder 2</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Guatemala</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Jaime Tres 1., Centro de Estudias Conservacionistas, Universidad de San Carlos de Guatemala, Avenida de la Reforma 0-63, Zona IO, Guatemala</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">India</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">B. C. Choudhury and Lala A. K. Singh, Central Crocodile Breeding and Management Training Institute, 19-4-319, Lake Dale, Rajendranagar Road, Hyderabad 500 264, Andhra Pradesh</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Indian Board for Wildlife, c/o Department of Environment, Bikaner House, Shahjahan Road, New Delhi 110 011</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">John Sale, UNDP/FAO Crocodile Breeding and Management Project, 19-4-319, Lake Dale, Rajendranagar Road Hyderabad 500 264, Andhra Pradesh</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">S. Shanmugunathan, Chief Wildlife Warden, Vivekananda Road, Coimbatore, Tamil Nadu</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Sudhakar Kar, Saltwater Crocodile Research and Conservation Unit, Danginal 754 220 Via Rejkanika, District Cuttack, Orissa</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Romulus Whitaker, Madras Snake Park Trust, Guindy Deer Park, Madras, Tamil Nadu, 600 002</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Italy</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">G. S. Child, Wildlife and Parks Management Of ficer FAO, Rome</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Japan</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Wataru Kimura, Proprietor, Atagawa Tropical and Alligator Garden, Atagawa Higashi Zlu Town, Shizuoka Prefecture</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Kenya</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">R.D. Haller , Bamburi Portland Cement Co. ,Ltd., P.O. Box 90202 ,Mombasa</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Malaysia</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Paul R. Wycherley, President, Malayan Nature Society, P.O. Box 150, Kuala Lumpur</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Mexico</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Miguel Alvarez del Toro, Director, Instituto de Historia Natural, Departamento de Zoologia, Apartado Postal No. 6, Tuxtle Gutierrez, Chiapas, 29000</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Marco Antonio Lascano B., INIREB, Apdo. No 281, Merida</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Nepal</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Tirtha Maskey, National Parks and Wildlife Conservation Office, Thapathali, P.O. Box 107, Kathmandu</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">New Zealand</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Antoon de Vos, Box 34, Whitford, Auckland</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Nicaragua</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Milton G. Camacho B., Instituto Nicaraguense de Recursos Naturales y del Ambiente (IRENA), Depto. de Fauna Silvestre, Kim 12 1/2 Carreterra Norte, Managua.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Pakistan</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Ashiq Ahmad, Wildlife Management Specialist, Pakistan Forest Institute, Peshawar</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Abdul Latif Rao, Conservator of Wildlife, National Council for Conservation of Wildlife, Ministry of Food and Agriculture, U.G. St. 51, Sector F 6/4, Islamabad</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Papua New Guinea</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Miro Laufa, Division of Wildlife, Department of Lands and Environment, P.O. Box 2585, Konedobu</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Karol Kisokau, Director, Office of Environment and Conservation, Central Government Offices, Waigani</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Navu Kwapena, Division of Wildlife, Department of Lands and Environment, Konedobu</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Graham Goudie, Crocodile Farm, Lae</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Martin Hollands, Monitoring Ecologist, National Crocodile Project, P.O. Box 2585 Konedobu</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Peru</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Pedro Vasques Ruesta, Departamento de Manejo Forestal, Universidad Nacional Agraria, Apdo. 456, La Molina</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Philippines</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Angel C. Alcala, Division Research, Extension and Development, Silliman University, Dumaguete City, 6501, Negros</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">School of Agriculture, Silliman University, Dumaguete City, 6501, Negros.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">South Africa</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">H. B. Anthony, The Natal Parks, Game and Fish Preservation Board, Box 662, Pietermaritzburg, Natal</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Antony Pooley, P.O. Box 42, St. Lucia Estuary, 3936 Zululand</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Switzerland</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Rene E. Honegger, Curator, Zurich Zoo, Zurichbergstrasse 221, 8044 Zurich</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Thailand</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">U. Srisomboon, Ministry of Agriculture, Department of Livestock Development, Bangkok Utai Youngprapakorn and Charoon Youngprapakorn, The Samutprakan Crocodile Farm and Zoo Co., Ltd., Talban Road, Samutprakan</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">United Kingdom</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Angus d'A. Bellairs, Department of Anatomy, St. Mary's Hospital Medical School University of London, Paddington, London W2</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">H. Robert Bustard, Isle of Man</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">United States</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">John Behler, New York Zoological Society, 185th Street &amp; Southern Blvd., The Bronx, New York 10460</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Peter Brazaitis, New York Zoological Society, 185th Street &amp; Southern Blvd., The Bronx New York 10460</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Gary Callis, Rt. I, Box 360, Clayton, New Mexico</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Robert H. Chabreck, Louisiana State University, School of Forestry and Wildlife Management, Baton Rouge, Louisiana 70803</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Michael Davenport, Department of Herpetology, National Zoological Park, Smithsonian Institution, Washington, D.C. 20008</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Claire Hagen, Representative, Reptile Products Association, 120 Cabrini Blvd., New York, New York 10033</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Fred Hauptfuhrer, Director of Planning and Development, World Wildlife Fund, Inc., 910 17th Street NW, Washington, D.C. 20006</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Howard Hunt, Atlanta Zoological Park, 518 Atlanta Ave. S.E., Atlanta, Georgia 30315</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Ted Joanen, Rockefeller Wildlife Refuge, Route 1, Box 20-B, Grand Chenier, Louisiana 70643</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">F. Wayne King, Director, Florida State Museum, Gainesville, Florida 32611</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Jeffrey W. Lang, Biology Department, University of North Dakota, University Station, Grand Forks, North Dakota 58202</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Charles J. Lankester, UNDP, I United Nations Plaza, New York, New York 10017</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">James H. Powell, 1110 Kokomo Street, Plainview, Texas 79072</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Charles A. Ross, Division of Reptiles and Amphibians, National Museum of Natural History, Smithsonian Institution, Washington, D.C. 20560</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Myrna Watanabe, 141 Columbia Heights, Brooklyn, New York 11201</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Uruguay</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Federico Achaval, Departamento de Zoologia (Vertebrados), Universidad de la Republic Cerrito73, Montevideo</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Venezuela</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Tomas Blohm, Apartado 69, Caracas 1010-A</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Andres Seijas Y., Servicio Nacional de Fauna Silvestre, MARNR, Apartado 184, Maracay</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Zimbabwe</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">D. K. Blake, Department of National Parks and Wildlife Management, P.O. Box 8365, Causeway, Harare</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">John Loveridge, Zoology Department, University of Zimbabwe, P.O. Box MP 167, Mount Pleasant, Harare</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Kevin van Jaarsveldt, Crocodile Farmers Association of Zimbabwe, P.O. Box 2569, Harare </P>
+<P ALIGN="JUSTIFY"></P>
+<B><P>&lt;&lt;TOC3&gt;&gt; Appendix E: Biographical Sketches of Panel Members</P>
+</B><P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">EDWARD S. AYENSU, Director of the Office of Biological Secretary General Smithsonian Institution, Washington, D.C., is currently the Secretary General of the International Union of Biological Sciences. He received his B.A. in 1961 from Miami University in Ohio, M.Sc. from The George Washington University in 1963, and his Ph.D. in 1966 from the University of London. His research interests are in comparative anatomy and phylogeny of flowering plants, commercial timbers, histology of monocotyledons, economic botany, and tropical biology. An internationally recognized expert on tropical plants, he has published extensively in these areas and on topics relating to science, technology, and development, especially in developing countries. Dr. Ayensu was co-chairman of the Panel on Underexploited Tropical Plants of the Advisory Committee on Technology Innovation and chairs and serves as a member of many international bodies. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">ARCHIE F. CARR, JR., is Graduate Research Professor in the Department of Zoology, University of Florida, Gainesville. As Technical Director of the Caribbean Conservation Corporation, he has directed a seasonal research program at the breeding ground of the green turtle at Tortuguero, Costa Rica, since 1952, with continuous grants from the National Science Foundation from 1955 to 1980, and has carried out investigations of marine turtle ecology and navigation in various parts of the world. The author of numerous papers, articles, and books, he received the Daniel Giraud Elliot Medal of the National Academy of Sciences for Handbook of Turtles and the John Burroughs Medal for The Windward Road. He is Research Associate of the American Museum of Natural History; Affiliate Curator of Natural Sciences, Florida State Museum; Chairman of the Marine Turtle Specialist Group of the Survival Service Commission, International Union for the Conservation of Nature; Honorary Consultant of the World Wildlife Fund; Fellow of the Linnean Society of London; Fellow of the American Fisheries Society; and a member of Phi Beta Kappa and Sigma Xi.In 1973 he was awarded a gold medal from the World Wildlife Fund for the application of scientific findings to the conservation of marine turtles. In 1975 he received the Edward W. Browning Award for achievement in biological conservation. In 1978 Dr. Carr was awarded the Gold Medal of the New York Zoological Society for contributions to natural science and conservation; in 1978 he became Officer of the Order of the Golden Ark (The Netherlands).</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">F. WAYNE KING is the Director of the Florida State Museum, Gainesville. He received a B.S. in 1957 and an M.S. in 1961 from the University of Florida and a Ph.D. from 1966 from the University of Miami. His research interests are in wildlife conservation and habitat preservation, impact of international trade on wildlife populations, and ecology and behavior of reptile populations. He worked at the New York Zoological Society from 1967 to 1975. As an international wildlife consultant, Dr. King has received honors from the Dominican Republic, the American Association of Zoological Parks and Aquariums, and from H.R.H. Prince Bernhard of The Netherlands. He has served on committees advising the State Department and the International Union for Conservation of Nature and Natural Resources on policies regarding the trade of crocodile skins, turtle products, and other wildlife materials. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">FRANCOIS MERGEN, Pinchot Professor of Forestry and Professor of Forest Genetics, Yale University, was Dean of the School of Forestry and Environmental Studies at Yale from 1965 to 1975. He received a B.A. from Luxembourg College and a B.Sc.F. from the University of New Brunswick in 1950, an M.F. in ecology in 1951, and a Ph.D. in forest genetics from Yale in 1954. He is especially knowledgeable about francophone Africa and was chairman of the Sahel program of the Board on Science and Technology for International Development and a member of the Advisory Committee on Technology Innovation. From 1960 to 1965 he was research collaborator at the Brookhaven National Laboratory. In 1966 he was the recipient of the Award for Outstanding Achievement in Biological Research from the Society of American Foresters and in 1975 was Distinguished Professor (Fulbright-Hays Program) in Yugoslavia. Before joining the Yale faculty, he served as project leader in forest genetics for the U.S. Forest Service in Florida. He has served as a consultant to FAO, various foreign governments, and private forestry companies, and he has traveled extensively in the tropical countries of Asia, Africa, and Latin America. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">MICHAEL G. MORRIS is head of the Furzebrook Research Station of the Institute of Terrestrial Ecology (National Environment Research Council, U.K.). He received a B.A. in natural sciences (zoology) at the University of Cambridge of 1958, M.A. in 1962, and received his Ph.D. from London University in research on the integrated control of orchard pests. Dr. Morris worked at Monks Wood Experimental Station on the effects of grassland management on populations of invertebrates and developed a strong interest in community and applied ecology, particularly the conservation of insect populations. Recently he has become involved with problems of butterfly conservation and resource utilization. He is Secretary of the Joint Committee for the Conservation of British Insects, a Vice-Chairman of the Lepidoptera Specialist Group of lUCN'S Survival Commission, and Chairman of the Habitat and Species Protection Committee of SEL (Societal Europaea Lepidoptero-Logica). </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">HUGH L. POPENOE is Professor of Soils, Agronomy, Botany, and Geography and Director of the Center for Tropical Agriculture and International Programs (Agriculture) at the University of Florida. He received his B.S. from the University of California at Davis in 1951 and his Ph.D. in soils from the University of Florida in 1960. His principal research interest has been in the area of tropical agriculture and land use. His early work on shifting cultivation is one of the major contributions to this system. He has traveled and worked in most of the countries in the tropical areas of Latin America, Asia, and Africa. He is past Chairman of the Board of Trustees of the Escuela Agricola Panamericana in Honduras, Visiting Lecturer on Tropical Public Health at the Harvard School of Public Health, and a Fellow of the American Association for the Advancement of Science, the American Society of Agronomy, the America Geographical Society, and the International Soils Science Society. He is Chairman of the Advisory Committee for Technology Innovation and a member of the Board on Science and Technology for International Development. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">ROBERT MICHAEL PYLE, a writer and consulting lepidopterist based in Gray's River, Washington, has served since 1979 as Co-Compiler of the lUCN Invertebrate Red Data Book. In this capacity he is consultant to the Conservation Monitoring Center in Cambridge, England. After receiving his B.S. and M.S. at the University of Washington, he took his Ph.D. through the School of Forestry and Environmental Studies at Yale University in 1976. He worked for the Government of Papua New Guinea on the conservation and utilization of insect resources and then with the Nature Conservancy as Northwest Land Steward. A former Fulbright Scholar to the United Kingdom, Dr. Pyle subsequently founded the Xerces Society for conservation of beneficial insects and their habitats. He has been chairman of IUCN'S Lepidoptera Specialist Group (Species Survival Commission) since 1976. His publications include the Audubon Society Field Guide to North American Butterflies. A comprehensive book on insect conservation in his next project.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">SHELDON R. SEVERINGHAUS received his Ph.D. from Cornell University in 1977 in natural resources management. He has worked on various wildlife research projects in Asia since 1964 and is representative for the Asia Foundation in Taiwan. He has published articles on butterfly conservation and wildlife industries in Taiwan, where he has been studying the butterfly and wildlife farming projects. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">NOEL D. VIETMEYER, staff officer for this study, is Professional Associate of the Board on Science and Technology for International Development. A New Zealander with a Ph.D. in organic chemistry from the University of California, Berkeley, he now works on innovations in science that are important for developing countries. </P>
+<P ALIGN="JUSTIFY"></P>
+<B><P ALIGN="CENTER">&lt;&lt;TOC2&gt;&gt; Advisory Committee on Technology Innovation</P>
+</B><P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">HUGH POPENOE, Director, International Programs in Agriculture, University of Florida, Gainesville, Florida, Chairman </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Members</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">WILLIAM BRADLEY, Consultant, New Hope, Pennsylvania</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">HAROLD DREGNE, Director, International Center for Arid and Semi-Arid Land Studies, Texas Tech University, Lubbock, Texas (member through 1981) </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">ELMER L. GADEN, JR., Department of Chemical Engineering, University of Virginia, Charlottesville, Virginia </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">CARL N. HODGES, Director, Environmental Research Laboratory, Tucson, Arizona </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">CYRUS MCKELL, Native Plants, Inc., Salt Lake City, Utah </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">FRANCOIS MERGEN, Pinchot Professor of Forestry, School of Forestry and Environmental Studies, Yale University, New Haven, Connecticut (member through 1982) </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">DONALD L. PLUCKNETT, Consultative Group on International Agricultural Research, Washington, D.C. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">THEODORE SUDIA, Deputy Science Advisor to the Secretary of Interior, Department of Interior, Washington, D.C. </P>
+<P ALIGN="JUSTIFY"></P>
+<B><P ALIGN="CENTER">&lt;&lt;TOC2&gt;&gt; Board on Science and Technology for International Development</P>
+</B><P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">GEORGE BUGLIARELLO, President, Polytechnic Institute of New York, Brooklyn, New York, Chairman </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Members</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">SAMUEL P. ASPER, Educational Commission for Foreign Medical Graduates, Philadelphia, Pennsylvania </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">DAVID BELL, Department of Population Sciences, Harvard School of Public Health, Boston, Massachusetts </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">LEONARD BERRY, Professor, Graduate School of Geography, Clark University, Worcester, Massachusetts </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">ERNEST I. BRISKEY, Dean, School of Agriculture, Oregon State University, Corvallis, Oregon </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">HARRISON S. BROWN, Director, Resources Systems Institute, East-West Center, Honolulu, Hawaii </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">ROBERT H. BURRIS, Department of Biochemistry, University of Wisconsin, Madison, Wisconsin </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">CLAUDIA JEAN CARR, Associate Professor, Conservation and Resource Studies, University of California at Berkeley, Berkeley, California </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">NATE FIELDS, Director, Developing Markets, Control Data Corporation, Minneapolis, Minnesota </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">ROLAND J. FUCHS, Chairman, Department of Geography, University of Hawaii at Manoa, Honolulu, Hawaii </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">ELMER L. GADEN, JR., Department of Chemical Engineering, University of Virginia, Charlottesville, Virginia </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">JOHN HOWARD GIBBONS, Director, U.S. Congress, Office of Technology Assessment, Washington, D.C. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">N. BRUCE HANNAY, Foreign Secretary, National Academy of Engineering, Washington, D.C. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">WILLIAM HUGHES, Director, Engineering Energy Laboratory, Oklahoma State University, Stillwater, Oklahoma </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">WILLIAM A. W. KREBS, Vice President, Arthur D. Little, Inc., Acorn Park, Cambridge, Massachusetts </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">GEORGE I. LYTHCOTT, University of Wisconsin, School of Medicine, Madison, Wisconsin </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">JANICE E. PERLMAN, Executive Director, Committee for a New New York, New York City Partnership, New York, New York </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">HUGH POPENOE, Director, International Programs in Agriculture, University of Florida, Gainesville, Florida </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">FREDERICK C. ROBBINS, President, Institute of Medicine, National Academy of Sciences, Washington, D.C. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">WALTER A. ROSENBLITH, Foreign Secretary, National Academy of Sciences, Washington, D.C. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">FREDERICK SEITZ, President Emeritus, The Rockefeller University, New York, New York </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">RALPH HERBERT SMUCKLER, Dean of International Studies and Programs, Michigan State University, East Lansing, Michigan </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">GILBERT F. WHITE, Institute of Behavioral Science, University of Colorado, Boulder, Colorado </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">BILL C. WRIGHT, Assistant Dean for International Programs, Oklahoma State University, Stillwater, Oklahoma </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">JOHN G. HURLEY, Director</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">MICHAEL G. C. McDONALD DOW, Associate Director/Studies </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">MICHAEL P. GREENE, Associate Director/Research Grants </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">&nbsp;</P></FONT></BODY>
+</HTML>
Index: /main/tags/2.25/gsdl/collect/demo/import/bostid/b21wae/b21wae.htm
===================================================================
--- /main/tags/2.25/gsdl/collect/demo/import/bostid/b21wae/b21wae.htm	(revision 21064)
+++ /main/tags/2.25/gsdl/collect/demo/import/bostid/b21wae/b21wae.htm	(revision 21064)
@@ -0,0 +1,1752 @@
+<HTML>
+<HEAD>
+<META HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=windows-1252">
+<META NAME="Generator" CONTENT="Microsoft Word 97">
+<TITLE>&lt;&lt;TOC1&gt;&gt; The Water Buffalo: New Prospects For An Underutilized Animal (1984)</TITLE>
+</HEAD>
+<BODY>
+
+<B><FONT FACE="Arial" SIZE=2><P>&lt;&lt;TOC1&gt;&gt; The Water Buffalo: New Prospects For An Underutilized Animal (1984)</P>
+</B><P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">Original editon 1981</P>
+<P ALIGN="JUSTIFY">Second printing 1984</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Report of an Ad Hoc Panel of the</P>
+<P ALIGN="JUSTIFY">Advisory Committee on Technology Innovation</P>
+<P ALIGN="JUSTIFY">Board on Science and Technology for International Development</P>
+<P ALIGN="JUSTIFY">Commission on International Relations</P>
+<P ALIGN="JUSTIFY">National Research Council</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<B><P ALIGN="CENTER">&lt;&lt;TOC2&gt;&gt; Panel on Water Buffalo</P>
+</B><P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">HUGH POPENOE, Director, International Programs in Agriculture, University of  Florida, Gainesville, Florida, USA, Chairman </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">STEVE P. BENNETT, Bennett's Animal Clinic, Port of Spain, Trinidad, West Indies</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">CHARAN CHANTALAKHANA, Dean, Department of Animal Science, Kasetsart  University, Bangkok, Thailand</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">DONALD D. CHARLES, Senior Lecturer, Meat Production, Department of Animal  Husbandry, University of Queensland, St. Lucia, Queensland, Australia</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">W. ROSS COCKRILL, Livestock Expert, Food and Agriculture Organization (retired),  Rome, Italy</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">WYLAND CRIPE, Department of Veterinary Science, University of Florida,  Gainesville, Florida, USA</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">TONY J. CUNHA, Dean, School of Agriculture, California Polytechnic University,  Pomona, California, USA</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">A. JOHN DE BOER, Winrock International Livestock Research and Training Center,  Morrilton, Arkansas, USA</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">MAARTEN DROST, Department of Veterinary Science, University of Florida,  Gainesville, Florida, USA</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">MOHAMED ALI EL-ASHRY, Department of Animal Production, Faculty of  Agriculture, Shoubra el Khiema, Cairo, Egypt </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">ABELARDO FERRERD ., Former Director, Breeding Administration Centers,  Animal Sciences Division, Ministry of Agriculture, Caracas, Venezuela</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">JEAN K. GARDNER, Former Chief, Logistics Division USAID/Philippines, Jackson,  Mississippi, USA</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">JAMES F. HENTGES, Department of Animal Science,University of Florida,  Gainesville, Florida, USA</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">JACK HOWARTH, School of Veterinary Medicine, University of California, Davis,  California, USA</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">NELS M. KONNERUP, Livestock Expert, Agency for International Development  (retired), Washington, D.C., USA</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">A. P LEONARDS, Water buffalo breeder, Lake Charles, Louisiana, USA</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">JOHN K. LOOSLI, Department of Animal Science, University of Florida, Gainesville,  Florida, USA</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">JOSEPH MADAMBA, Director, Asian Institute of Aquaculture, Iloilo, Philippines</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">CRISTO NASCIMENTO,Director, Brazilian Agriculture Research Corporation  (EMBRAPA), Agriculture Research Center for Humid Tropics (CPATU), Belem,  Para, Brazil</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">DONALD L. PLUCKNETT, Consultative Group on International Agricultural  Research, The World Bank, Washington, D.C., USA</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">WILLIAM R. PRITCHARD, Dean, School of Veterinary Medicine, University of California, Davis, California, USA</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">J. THOMAS REID, (deceased), Department of Animal Science, Cornell University, Ithaca, New York, USA</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">JOHN H. SCHOTTLER, Animal Production Officer, Department of Primary Industries, Lae, Papua New Guinea </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">DALBIR SINGH DEV, Dean, Animal Science Department, College of Agriculture, Agricultural University, Ludhiana, Punjab, India </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">ROBERT W. TOUCHBERRY, Dean, Department of Animal Science, University of Minnesota, St. Paul, Minnesota, USA</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">DONALD G. TULLOCH, Division of Wildlife Research, Commonwealth Scientific and Industrial Research Organization, Winnellie, Australia </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">NOEL D. VIETMEYER, Board on Science and Technology for International Development, National Research Council, Washington, D.C., Staff Study Director </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">MARY JANE ENGQUIST, Board on Science and Technology for International Development, National Research Council, Washington, D.C., Staff Associate </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<B><P ALIGN="CENTER">&lt;&lt;TOC2&gt;&gt; Preface</P>
+</B><P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The water buffalo is an animal resource whose potential seems to have been barely recognized or examined outside of Asia. Throughout the world there are proponents and enthusiasts for the various breeds of cattle; the water buffalo, however, is not a cow and it has been neglected. Nevertheless, this symbol of Asian life and endurance has performed notably well in recent trials in such diverse places as the United States, Australia, Papua New Guinea, Trinidad, Costa Rica, Venezuela, and Brazil. In Italy and Egypt as well as Bulgaria and other Balkan states the water buffalo has been an important part of animal husbandry for centuries. In each of these places certain herds of water buffalo appear to have equaled or surpassed the local cattle in growth, environmental tolerance, health, and the production of meat and calves.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Although these are empirical observations lacking painstaking, detailed experimentation, they do seem to indicate that the water buffalo could become an important resource in tropical, subtropical, and warm temperate zones in developing and developed countries.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">If this is the case, then it is clear that many countries should begin water buffalo research. Serious attention by scientists could help dispel the misperceptions and uncertainties surrounding the animal and encourage its true qualities to emerge.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">This report describes the water buffalo's attributes as perceived by several animal scientists. It is designed to present the apparent strengths of buffaloes compared with those of cattle, to introduce researchers and administrators to the animal's potential, and to identify priorities for buffalo research and testing.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The panel that produced this report met at Gainesville, Florida, in July 1979. It was composed of leading water buffalo experts (particularly those from outside Asia who have directed the beginnings of water buffalo industries in their countries) and leading American animal scientists, many of whom are also familiar with the animal.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">This report complements The Husbandry and Health of the Domestic Buffalo, edited by W. Ross Cockrill and published in 1974 by the Food and Agriculture Organization of the United Nations. Cockrill's 933-page book is a "bible" of water buffalo knowledge and provides details of breeds, world distribution, physiology, and an extensive bibliography.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The present report is an introduction to the water buffalo and its potential. It is written particularly for decision makers, as well as scholars or students, in the hope that it will stimulate their interest in the animal and thereby increase the appreciation of, and funding for, buffalo research. The report includes much empirical observation, largely from the panel members. Some of these observations may, in the long run, prove not to be universally applicable. Much benchmark information needs to be obtained.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Since its creation in 1971, the Advisory Committee on Technology Innovation (ACTI) has investigated innovative ways to use current technology and resources to help developing countries. Often this has meant taking a fresh look at some neglected and unappreciated plant or animal species. The committee assembles ad hoc panels of experts (usually incorporating both skeptics and proponents) to scrutinize the topics selected. The panel reports serve to draw attention to neglected, but promising, technologies and resources. (For a list of ACTI reports, see page 115.) ACTI reports are provided free to developing countries under funding by the Agency for International Development (AID).</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Program costs for this study were provided by AID'S Office of Agriculture, Development Support Bureau, and staff support was provided by the Office of Science and Technology, Development Support Bureau.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The final draft of this report was edited and prepared for publication by F. R. Ruskin. Bibliographic editing was by Wendy D. White. Cover art was by Deborah Hanson.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<B><P ALIGN="CENTER">&lt;&lt;TOC2&gt;&gt; 1 Introduction</P>
+</B><P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The domesticated water buffalo Bubalus bubalis numbers at least 130 million-one-ninth the number of cattle in the world. It is estimated that between 1961 and 1981 the world's buffalo population increased by 11 percent, keeping pace with the percentage increase in the cattle population.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Although there are some pedigreed water buffaloes, most are nondescript animals that have not been selected or bred for productivity. There are two general types-the Swamp buffalo and the River buffalo.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Swamp buffaloes are slate gray, droopy necked, and ox-like, with massive backswept horns that make them favorite subjects for postcards and wooden statuettes in the Far East. They are found from the Philippines to as far west as India. They wallow in any water or mud puddle they can find or make. Primarily employed as a work animal, the Swamp buffalo is also used for meat but almost never for milk production.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">River buffaloes are found farther west, from India to Egypt and Europe. Usually black or dark gray, with tightly coiled or drooping straight horns, they prefer to wallow in clean water. River buffaloes produce much more milk than Swamp buffaloes. They are the dairy type of water buffalo. In India, River buffaloes play an important role in the rural economy as suppliers of milk and draft power. River buffaloes make up about 35 percent of India's milk animals (other than goats) but produce almost 70 percent of its milk. Buffalo butterfat is the major source of cooking oil (ghee) in some Asian countries, including India and Pakistan.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Although water buffaloes are bovine creatures that somewhat resemble cattle, they are genetically further removed from cattle than are the North American bison (improperly called buffalo) whose massive forequarters, shaggy mane, and small hindquarters are unlike those of cattle. While bison can be bred with cattle to produce hybrids,( This is not, however, very successful, the male progeny (at least of the F 1 generation) are sterile).there is no well-documented case of a mating between water buffalo and cattle that has produced progeny.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Parts of Asia and even Europe have depended on water buffaloes for centuries. Their crescent horns, coarse skin, wide muzzles, and low-carried heads are represented on seals struck 5,000 years ago in the Indus Valley, suggesting that the animal had already been domesticated in the area that is now India and Pakistan. Although buffaloes were in use in China 4,000 years ago, they are not mentioned in the literature or seen in the art of the ancient Egyptians, Romans, or Greeks, to whom they were apparently unknown. It was not until about 600 A.D. that Arabs brought the animal from Mesopotamia and began moving it westward into the Near East (modern Syria, Israel, and Turkey). Water buffaloes were later introduced to Europe by pilgrims and crusaders returning from the Holy Land in the Middle Ages. In Italy buffaloes adapted to the area of the Pontine Marshes southeast of Rome and the area south of Naples. They also became established in Hungary, Romania, Yugoslavia, Greece, and Bulgaria and have remained there ever since.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Villagers in medieval Egypt adopted the water buffalo, which has since become the most important domestic animal in modern Egypt. Indeed, during the last 50 years, their buffalo population has doubled to over 2 million head. The animals now supply Egypt with more meat-much of it in the form of tender "veal"-than any other domestic animal. They also provide milk, cooking oil, and cheese.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Other areas have capitalized on the water buffalo's promise only in very recent times. For instance, small lots of the animals brought to Brazil (from Italy, India, and elsewhere) during the last 84 years have reproduced so well that they now total about 400,000 head and are still increasing, especially in the lower Amazon region. Buffalo meat and milk are now sold widely in Amazon towns and villages; the meat sells for the same price as beef. Nearby countries have also become familiar with the water buffalo. Trinidad imported several breeds from India between 1905 and 1908, while Venezuela, Colombia, and Guyana have been importing them in recent decades. During the 1970s Costa Rica, Ecuador, Cayenne, Panama, Suriname, and Guyana introduced small herds. By 1979 the buffalo in Venezuela numbered more than 7,000 head.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Across the Pacific, the new nation of Papua New Guinea has found the water buffalo well suited to its difficult environment. For 9 years the government has attempted to run cattle on the Sepik and Ramu Plains on Papua New Guinea's north coast, where the temperatures are high and the forage of poor quality. But the cattle remain thin and underweight. In the 1960s animal scientists began evaluating water buffaloes already living in Papua New Guinea and, encouraged by the results, introduced additional buffaloes from Australia. These have performed remarkably well, producing greater numbers of calves and much more meat than the cattle in the region. The buffaloes appear to maintain appetite despite the heat and humidity, whereas cattle do not. The government of Papua New Guinea has since imported more water buffaloes and today has thriving herds totaling almost 3,500 head. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The United States has been slow to recognize the water buffalo's potential, but the first herd (50 head) ever imported for commercial farming arrived in February 1978.(Air-freighted from the wilds of Guam, the U.S. island possession on the western Pacific, by panel member Tony Leonards. Prior to that time (in 1974), four head of water buffalo were imported to the Department of Animal science' university of Florida, for study. The only other water buffaloes in North America were a few animals in zoos.) The humble water buffalo, normally considered fit only for the steamy rice fields of Asia, is now proving itself on farm fields in Florida and Louisiana. As a result, interest in the animal is on the rise in U.S. university and farm circles.  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">From experience accumulated in Asia, Egypt, South America, Papua New Guinea, Australia, the United States, and elsewhere, animal scientists now perceive that many general impressions about the water buffalo are incorrect.  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">For example, it is widely believed that the water buffalo is mean and vicious. Encyclopedias reinforce this perception, and in the Western world it is the prevalent impression of the animal. The truth is, however, that unless wounded or severely stressed, the domesticated water buffalo is one of the gentlest of all farm animals. Despite an intimidating appearance, it is more like a household pet-sociable, gentle, and serene. In rural Asia the care of water buffaloes is often fumed over to small boys and girls aged about four to nine. The children spend their days with their family's gentle buffalo, riding it to water, washing it down, waiting while it rolls and wallows, and then riding it to some source of forage, perhaps a grassy field or thicket. It is not uncommon to see a buffalo patiently feeding, with a young friend stretched prone on its broad gray back, asleep.  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Perhaps the notion about the viciousness of water buffaloes stems from confusing them with the mean-tempered African buffalo Syncerus caffer, actually a distant relative with which they will not interbreed and which is classified in a different genus.  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Ferocity is the most blatant misconception concerning the water buffalo, although other fallacies are widely reported as well.  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">One generally held belief is that water buffaloes can be raised only near water. Actually, buffaloes love to wallow, but they grow and reproduce normally without it, although in hot climates they must have shade available.  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Another belief is that the water buffalo is exclusively a tropical animal. River-type buffaloes, however, have been used to pull snow plows during Bulgarian winters. They are found in Italy (over 100,000 head), Albania, Yugoslavia, Greece, Turkey, the Georgia and Azerbaijan areas of the Soviet Union (almost 500,000 head) and other temperate-zone regions as well. They are also found in cold, mountainous areas of Pakistan, Afghanistan, and Nepal.  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&lt;&lt;I&gt;&gt; p04to05.png World Distribution of Water Buffaloes</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Yet another misconception is that the water buffalo is just a poor man's beast of burden. In addition to providing fine lean meat, buffaloes in fact provide rich milk. Mozzarella cheese, one of the most popular in Europe, comes from the buffaloes in Italy. Buffalo milk has a higher content of both butterfat and nonfat solids than cow's milk does. It therefore often brings higher prices than cow's milk. Throughout much of India it is in such demand that cow's milk is sometimes hard to sell.  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Many of the misconceptions generally held about buffaloes are based on little data and much prejudice. For instance, it is widely believed that water buffalo meat is tough and less desirable than beef. However, when the animals are raised for meat, buffalo steaks are lean, as tender as beef, and in appearance it is difficult to distinguish the two. In taste-preference tests at the University of Queensland, buffalo steaks were preferred over those from Angus and Hereford cattle. Tests conducted in Trinidad, Venezuela, the United States, and Malaysia produced similar results.  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Australia has shipped water buffalo meat to Hong Kong, the United States, Germany, and Scandinavia. Buffalo meat is now available in stores in Australia's Northern Territory, where demand exceeds supply. It sells at competitive prices and is particularly sought for barbecues and the famous Australian meat pie. In the Philippines, two-thirds of the meat consumed in homes and restaurants is actually water buffalo, a fact that many Filipinos do not realize.  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Compared with cattle,waterbuffaloes apparently have an efficient digestive system, one which extracts nourishment from forage so coarse and poor that cattle do not thrive on it. Thin cattle are commonly seen in Asia and northern Australia, for example, but it's rare to see a protruding rib on a buffalo, even though it uses the same source of feed.  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">In Asia, the Middle East, and Europe, water buffaloes live on coarse vegetation on the marginal land traditionally left to the peasants. They help make human survival possible. An old Chinese woman in Taiwan once told panelist W. Ross Cockrill: "To my family the buffalo is more important than I am. When I die, they'll weep for me; but if our buffalo dies, they may starve."  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">A better understanding of the water buffalo could be invaluable to many developing nations. In particular, improved production of water buffalo meat offers hope for helping feed India, the second most populous nation on earth. Although India for religious reasons forbids the slaughter of cows, it has no prohibitions regarding slaughter of water buffaloes or the consumption of buffalo meat.  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Most developing countries are in the tropics, and the water buffalo is inherently a tropical animal. It is comfortable in hot, humid environments. In the Amazon, for example, buffaloes are now common on the landscape and may even replace cattle completely.  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Tropical countries have more serious disease problems than temperate countries do. Although susceptible to most cattle diseases, the water buffalo seems to resist ticks and often appears to be more resistant to some of the most devastating plagues that make cattle raising risky, difficult, and sometimes impossible in the tropics. Several researchers report that when water buffaloes are allowed to wallow, their mud-coated skin seems to deter insect and tick ectoparasites and they consequently require greatly reduced treatment with insecticides. Although the buffalo fly (Siphona exigua) affects the animals, other pests such as the warble fly and the screwworm, for example, seldom affect healthy buffaloes. AIso, despite their inclination for living in swamps, Avers, and ponds, diseases of the feet such as foot rot and foot abscesses are rare.  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Another benefit to developing countries is the water buffalo's legendary strength. A large part of the total farm power available in South China, Thailand, Indonesia, the Philippines, the Indochina states, India, and Pakistan comes from this "living tractor." Dependable and docile, the animals pull plows, harrows, and carts with loads that weigh several tons. In the Amazon buffalo teams pull boats laden with cargo and tourists through shallows and swamps.  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The petroleum crisis has forced many farmers to reconsider animal power even in some of the technically advanced countries. Buffaloes are not only extraordinarily strong, they can also work in deep mud that may bog down a tractor. Even up to their bellies they forge on, dragging both plow and driver through the mud. Although its average walking speed is only about 3 kilometers per hour, the buffalo, unlike its mechanical competition, doesn't need gasoline or spare parts and its working life is often 20 years or more.  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">Breeds</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">As already noted, the major genetic divisions of the water buffalo are the Swamp buffalo of the eastern half of Asia, which has swept-back horns, and the River buffalo of the western half of Asia, which usually has curled horns. There is also the Mediterranean buffalo, which is of the River type but has been isolated for so long that it has developed some unique characteristics. (Records of the buffalo in Italy date back 1,000 years, during which there have been no reported imports.) Mediterranean buffaloes are stocky, high yielding animals that combine both beef and dairy characteristics.  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Although there is only one breed of Swamp buffalo, certain subgroups seem to have specific inherited characteristics. For example, the buffaloes of Thailand are noted for their large size, averaging 450-550 kg, and weights of up to 1,000 kg have been observed. Elsewhere, Swamp buffaloes range from 250 kg for some small animals in China to 300 kg in Burma and 500-600 kg in Laos.  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Only in India and Pakistan are there well-defined breeds with standard qualities. There are eighteen River buffalo breeds in South Asia, which are further classified into five major groups designated as the Murrah, Gujarat, Uttar  Pradesh, Central Indian, and South Indian breeds. These are the five groups and  main breeds:  </P>
+<P ALIGN="JUSTIFY"></P></FONT>
+<TABLE BORDER CELLSPACING=2 CELLPADDING=7 WIDTH=484>
+<TR><TD WIDTH="21%" VALIGN="TOP">
+<B><FONT FACE="Arial" SIZE=2><P ALIGN="JUSTIFY">Group</B></FONT></TD>
+<TD WIDTH="79%" VALIGN="TOP">
+<B><FONT FACE="Arial" SIZE=2><P ALIGN="JUSTIFY">Breeds</B></FONT></TD>
+</TR>
+<TR><TD WIDTH="21%" VALIGN="TOP">
+<FONT FACE="Arial" SIZE=2><P ALIGN="JUSTIFY">Murrah</FONT></TD>
+<TD WIDTH="79%" VALIGN="TOP">
+<FONT FACE="Arial" SIZE=2><P ALIGN="JUSTIFY">Murrah, Nili/Ravi, Kundi</FONT></TD>
+</TR>
+<TR><TD WIDTH="21%" VALIGN="TOP">
+<FONT FACE="Arial" SIZE=2><P ALIGN="JUSTIFY">Gujarat</FONT></TD>
+<TD WIDTH="79%" VALIGN="TOP">
+<FONT FACE="Arial" SIZE=2><P ALIGN="JUSTIFY">Surti, Mehsana, Jafarabadi</FONT></TD>
+</TR>
+<TR><TD WIDTH="21%" VALIGN="TOP">
+<FONT FACE="Arial" SIZE=2><P ALIGN="JUSTIFY">Uttar Pradesh</FONT></TD>
+<TD WIDTH="79%" VALIGN="TOP">
+<FONT FACE="Arial" SIZE=2><P ALIGN="JUSTIFY">Bhadawari, Tarai</FONT></TD>
+</TR>
+<TR><TD WIDTH="21%" VALIGN="TOP">
+<FONT FACE="Arial" SIZE=2><P ALIGN="JUSTIFY">Central Indian</FONT></TD>
+<TD WIDTH="79%" VALIGN="TOP">
+<FONT FACE="Arial" SIZE=2><P ALIGN="JUSTIFY">Nagpuri, Pandharpun, Manda, Jerangi, Kalahandi, Sambalpur</FONT></TD>
+</TR>
+<TR><TD WIDTH="21%" VALIGN="TOP">
+<FONT FACE="Arial" SIZE=2><P ALIGN="JUSTIFY">South Indian</FONT></TD>
+<TD WIDTH="79%" VALIGN="TOP">
+<FONT FACE="Arial" SIZE=2><P ALIGN="JUSTIFY">Toda,  South Kanara</FONT></TD>
+</TR>
+</TABLE>
+
+<FONT FACE="Arial" SIZE=2><P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The best-known breeds are Murrah, Nili/Ravl, Jafarabadi, Surti, Mehsana, and  Nagpuri. Most of the buffaloes of the Indian subcontinent belong to a nondescript  group known as the Desi buffalo. There is no controlled breeding among these  animals and most are quite small, yield little milk, and are variable in color.  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">Genetics</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The Swamp buffalo has 48 chromosomes, the River buffalo, 50. The chromosomal  material is, however, similar in the two types and they crossbreed to produce fertile  hybrid progeny. Cattle, however, have 60 chromosomes and although mating  between cattle and buffaloes is common, hybrids from the union are unlikely to  occur.( In 1965 a reputed hybrid was born at Askaniya Nova Zoopark in the Soviet Union  (see Gray, A., 1971. Mammalian Hybrids, Commonwealth Agricultural Bureaux,  Slough, England, p. 126). Hybrids have also been reported from China (Van  Fu-Czao 1959, Gibridy buivolc i krupnogo  i rogatogo skota(buffalo and  cattlehybrids)Zhivotnovodstro, Mosk., 21:92). Both of these reports seem doubtful  because despite many attempts, no other hybrids have ever been claimed to have  been produced). </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Individual buffaloes show large variation in milk yield, conformation, horn shape,  color, meat production, temperament, growth rate, and other characteristics.  Selection for survival under adverse conditions has occurred naturally (those that  could not stand adversity died early) and farmers have probably tended to select  animals of gentle temperament. But systematic genetic improvement has almost  never been attempted. It seems likely that further selection could quickly improve  their productivity.  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Unfortunately, the large bulls that would be best for breeding purposes are often  being selected as draft animals and castrated, or sent to slaughter, or (as with  some feral animals in northern Australia and on the Amazon island of Marajo) shot  by hunters. The result is that the buffalo's overall size in countries such as Thailand  and Indonesia has been decreasing as the genes for large size and fast growth are  lost.  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">Limitations  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The buffalo is still largely an animal of the village, and many of its reported  limitations are caused more by its environment than by the animal itself. Moreover,  much of the animal's genetic potential is obscured by environmental influences. For  example, for many breeds and types the genetic variations in milk yield and growth  cannot be accurately determined because they are overwhelmed by the effects of  inadequate nutrition and management.  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Nevertheless, some inherent limitations of buffaloes can be identified. For instance,  buffaloes suffer if forced to remain, even for a few hours, in direct sunlight. They  have only one-tenth the density of sweat glands of cattle and their coating of hair is  correspondingly sparse, providing little protection from the sun. Accordingly,  buffaloes must not be driven over long distances in the heat of the day. They must  be allowed time for watering and, if possible, for wallowing. Driving under a hot sun  for long hours will cause heat exhaustion and possibly death; losses can be very  high and can occur suddenly. Young calves are particularly affected by heat.  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Buffaloes are also sensitive to extreme cold and seem less able than cattle to  adapt to truly cold climates(A rule of thumb is that buffaloes don't do well where the sun is inadequate to ripen,  say, cotton, grapes, or Ace. Kaleff, B., 1942. Der Hausbuffel und seine  Zuchtungsbiologie im Vergleich zum Rind. Zeitschsift Tierzucht Biologze,  51:131-178). Sudden drops in temperature and chill winds may lead  to pneumonia and death.  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The water buffalo is usually found m areas where there is ready access to a wallow  or shower. This is not a necessity, but when temperatures are high the availability of  water is important for maintaining buffalo health and productivity. It seems clear,  then, that the buffalo is not suitable for arid lands.  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Increasing buffalo productivity through breed improvement is just now beginning.  Throughout Asia buffalo mating is almost completely haphazard, and so the animal  lacks the quality improvement through breeding that most cattle have had.  Therefore, most buffaloes are of nondescript heritage and genetic potential.  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">On poor quality feed water buffalo grow at least as well as cattle, but under intensive  conditions they probably won't grow as fast as the best breeds of cattle. In feedlots,  therefore, the buffalo is likely to be less productive than improved cattle. Weight  gains of about 1 kg per day have been recorded, some exceptional cattle may gain  at almost twice that rate.  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The buffalo has long been considered a poor breeder-slow to mature sexually,  and slow to rebreed after calving. Accumulated experience now shows, however,  that this is mainly a result of poor management and nutrition. Buffaloes are not  sluggish breeders. Nevertheless, their gestation period is about a month longer  than that of cows, buffalo estrus is difficult to detect, and many matings occur~at  night so that~ farmers are likely to encounter more problems breeding buffaloes  than cattle.  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Buffaloes are gentle creatures, but if roughly or inexpertly handled they can, through fear or pain, become completely unmanageable. Buffalo behavior sometimes differs from that of cattle. For example, most buffaloes are not trained to be driven. Instead, the herdsman must walk alongside or ahead of them; they then instinctively follow. Also, because of their innate attachment to an individual site or herd it is more difficult to move buffaloes to new locations or herds. In addition, buffaloes respect fences less than cattle do and when they have the desire to move they are harder to contain. (Electric fences, however, will stop them.)  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Despite their general good health, buffaloes are probably as susceptible as cattle to most infections. However, the buffalo seems to be peculiarly sensitive to a few cattle diseases and resistant to a few others (see chapter 7). Reactions to some diseases seem to vary with region, environment, and breed, and the differences are not well understood.  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Destruction of the environment is sometimes attributed to buffalo wallowing. This danger seems to have been overstated, except in cases where stocking rates were unreasonably high.(An ongoing study in Northern Australia of environmental degradation widely attributed to buffalo has now shown that the effects are caused by man and climatic changes and only very slightly by buffaloes. (information supplied by D. G. Tulloch.) ) However, buffaloes rub against trees more often than cattle do, and they sometimes de-bark the trees, causing them to die.  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Unfortunately, some of the best genetic stocks of water buffaloes exist in areas where certain infections and viral and other diseases sometimes occur. Thus, many countries are reluctant to permit importation of water buffaloes, despite the fact that modern quarantine procedures under conditions of maximum security can essentially eliminate the risk.  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Finally, it must be emphasized that because buffalo research has been largely neglected, most results reported in this and other buffalo writings cover small numbers of animals and short periods of time. Many are merely empirical observations that have not been subjected to independent confirmation.  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">Selected Readings</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Anonymous. 1972.Buffalo at the crossroads. World Farming 14(n:l0-l3.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Asian and Pacific Council. 1979. Priorities in buffalo research identified.ASPAC News letter No. 43.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Bowman, J. c. 1977. Animals for Man. Edward Arnold Publishers, Ltd., London, United Kingdom.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Buffalo Bulletin. Newsletter published by the Buffalo Research Committee of Kasetsart University, Bangkok' Thailand. (In English and Thai.)  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Buffalo World. Newsletter published by the National Dairy Research Institute, Karnal, 132001, Haryana, India.  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Chantalakhana, C. 1975. The buffaloes of Thailand-their potential, utilization and conservation. In: The Asiatic Water Buffalo. Proceedings of an International Symposium held at Khon Kaen, Thailand, March 31-April 6, 1975. Food and Fertilizer Technology Center, Taipei, Taiwan.  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Chantalakhana, C., and Na Phuket, S. R. 1979. The role of swamp buffalo in small farm development and the need for breeding improvement in Southeast Asia. Extension Bulletin No. 125. Food and Fertilizer Technology Center, Taipei, Taiwan.  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Cockrill, W. R. 1967. The water buffalo. Scientific American 217:118.  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Cockrill, W. R., ed. 1974. The Husbandry and Health of the Domestic Buffalo. Food and Agriculture Organization of the United Nations, Rome, Italy.  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Cockrill W. R. 1975. The domestic buffalo. Blue Book for the Veterinary Profession No. 25. Animal Production and Health Division, Food and Agriculture Organization of the United Nations, Rome, Italy.  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Cockrill, W. R. 1976. The Buffaloes of China. Food and Agriculture Organization of the United Nations, Rome, Italy.  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Cockrill, W. R., ed. 1977. The Water Buffalo. Food and Agriculture Organization of the United Nations, Rome, Italy.  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Cockrill, W. R. 1977. The water buffalo: domestic animal of the future. Bovine Practitioner 12:92-98.  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Cockrill, W. R. 1978. Domestic water buffaloes. In: The Care and Management of Farm Animals, edited by W. N. Scott. Bailliere TindaU, London, United Kingdom.  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Cockrill, W. R. 1980. The ascendant water buffalo-key domestic animal. World Animal Review 33:2-13.  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">DeBoer, A. J. 1972. Technical and economic constraints on bovine production in three villages in Thailand. Dissertation Abstracts International 33(5):1935.  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">DeBoer, A. J. 1975. Livestock and Poultry Industry in Selected Asian Countries. Report of Survey on Diversification of Agriculture: Livestock and Poultry Production. Asian Productivity Organization, Tokyo, Japan.  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">de Guzman, M. R., Jr. 1979. An overview of recent developments in buffalo research and management in Asia. Extension Bulletin No. 124. Food and Fertilizer Technology Center, Taipei, Taiwan.  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Documentation Center on Water Buffalo. 1978. Abstract Bibliography on Water Buffalo, 1971-1975. Documentation Center on Water Buffalo, University of the Philippines at Los Banos Library, College, Laguna 3720, Philippines.  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Fahimuddin, M. 1975. Domestic Water Buffalo. Oxford and IBH Publishing Company, New Delhi, India  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Fischer, H. 1975. The water buffalo and related species as important genetic resources: their conservation, evaluation and utilization. In: The Asiatic Water Buffalo. Proceedings of an International Symposium held at Khon Kaen, Thailand, March 31-April 6  1975. Food and Fertilizer Technology Center, Taipei, Taiwan.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Ford, B. D., and Tulloch, D. G. 1977. The Australian buffalo-a collection of papers. Technical Bulletin No.18. Department of the Northern Territory, Animal Industry and Agriculture Branch, Australian Government Publishing Service, Canberra, Australia.  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Gupta, H. C. 1977. Possibilities and realities of developing buffalo's performance, breeding and feeding. Indian Dairyman 29(6):337-346.  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Kartha, K. P. R.1965. Buffalo. In: An Introduction to Animal Husbandry in the Tropics edited by G. Williamson and W. J. A. Payne. Longman, London, United Kingdom.  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">McKnight, T. L. 1971. Australia's buffalo dilemma. Annals of the Association of American Geographers 61(4):759-773.  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Madamba, J. C., and Eusebio, A. N. 1979. Developments in the strengthening of buffalo research in Asia. Buffalo Bulletin 2(3):7-16.  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Mahadevan, P. 1978. Water buffalo research-possible future trends. World Animal Review 25: 2-7.  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Oloufa, M. M. 1979. Buffaloes as producers of meat and milk. Egyptian Journal of AnimalProduction 19:1-10. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Pant, H. C., and Roy, A. 1972. The water buffalo and its future. In: Improvement of Livestock Production in Warm Climates, edited by R. E McDowell. W. H. Freeman and Company, San Francisco, California, USA.  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Philippine Council for Agriculture and Resources Research. 1978. The Philippines Recommends for Caraboo Production, PCARR, Los Banos, Laguna 3732, Philippines.  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Ranjhan, S. K., and Pathak, N. N. 1981. Management and Feeding of Buffaloes. Vikas Publishing House, New Delhi, India  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Robinson, D. W. 1977a. Livestock in Indonesia. Research Report No. 1. Centre for Animal Research and Development, Bogor, Indonesia. (In English and Indonesian.)  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Robinson, D. W. 1977b. Preliminary Observations on the Productivity of Porking Buffalo in Indonesia. Research Report No. 2. Centre for Animal Research and Development, Bogor, Indonesia. (In English and Indonesian.)  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Sundaresan, D. 1979. The role of improved buffaloes in rural development. Indian Dairyman 31(2):73-78.  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Tulloch, D. G. 1978. The water buffalo, Bubalus bubalis, in Australia: grouping and home range.Australian Wildlife Research 5:327-34.  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Wahid, A. 1973. Pakistani buffaloes. World Animal Review 7:22~28. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<B><P ALIGN="CENTER">&lt;&lt;TOC2&gt;&gt; 2 Meat</P>
+</B><P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The water buffalo offers promise as a major source of meat, and the production of buffaloes solely for meat is now expanding.  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Because buffaloes have been used as draft animals for centuries, they have evolved with exceptional muscular development, some weigh 1,000 kg or more. Until recently, however, little thought was given to using them exclusively for meat production. Most buffalo meat was, and still is, derived from old animals slaughtered at the end of their productive life as work or milk animals. As a result, much of the buffalo meat sold is of poor quality. But when buffaloes are properly reared and fed, their meat is tender and palatable.  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Water buffaloes are exported for slaughter from India and Pakistan to the Middle East and from Thailand and Australia to Hong Kong. Demand for meat is so great that Thailand's buffalo population has dropped from 7 million to 5.7 million head in the last 20 years, a period in which the human population has more than doubled.  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">Carcass Characteristics</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">All buffalo breeds-even the milking ones-produce heavy animals whose carcass characteristics are similar to those of cattle.  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Despite heavier hide and head, the amount of useful meat (dressing percentage) from buffaloes is almost the same as in cattle. Mediterranean type buffalo and Zebu cattle steers in Brazil yielded dressing percentages of 55.5 and 56.6 percent respectively. Swamp buffalo dressing percentages have been measured in Australia at 53 percent. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Buffaloes are lean animals. Although a layer of subcutaneous fat covers the carcass, it is usually thinner than that on comparably fed cattle. Even animals that appear to be fat prove to be largely muscle. Australian research on Swamp buffaloes reveals that buffaloes with more than 25 percent fat are difficult to produce, whereas average choice-grade beef carcasses may contain  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">In general, the buffalo carcass has rounder ribs, a higher proportion of muscle, and a lower proportion of bone and fat than beef has.  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Buffalo hide is so thick that it can be sliced into two or three layers before tanning into leather.  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">Meat Quality</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Buffalo meat and beef are basically similar. The muscle pH (5.4), shrinkage on chilling (2 percent), moisture (76.6 percent), protein (19 percent), and ash (1 percent) are all about the same in buffalo meat and beef. Buffalo fat, however, is always white and buffalo meat is darker in color than beef because of more pigmentation or less intramuscular fat (2-3 percent "marbling," compared with the 3-4 percent in beef).  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">Eating Quality</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Taste-panel tests and tenderness measurements conducted by research teams in a number of countries have shown that the meat of the water buffalo is as acceptable as that of cattle. Buffalo steaks have rated higher than beefsteaks in some taste tests in Australia, Malaysia, Venezuela, and Trinidad.  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">In taste-panel studies in Trinidad, cooked joints from three carcasses Trinidad buffalo, a crossbred steer (Jamaica-Red/Sahiwal), and an imported carcass of a top-grade European beef steer-were served. The 28 diners all had experience in beef production, butchery, or catering and were not told the sources of the various joints. All the carcasses were held in cold storage for one week before cooking. The buffalo meat was rated highest by 14 judges; 7 chose the European beef; 5 thought the crossbred beef the best; and 2 said that the buffalo and crossbred were equal to or better than the European beef. The buffalo meat received most points for color (both meat and fat), taste, and general acceptability. There was little difference noted in texture.( Information supplied by P. N. Wilson.)</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Buffalo veal is considered a delicacy. Calves are usually slaughtered for veal between 3 and 4 weeks of age; dressed weight is 59-66 percent of live weight.  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">There is some evidence that buffaloes may retain meat tenderness to a more advanced age than cattle because the connective tissue hardens at a later age or because the diameter of muscle fibers in the buffalo increases more slowly than in cattle(Joksimonc, 1979) In one test the tenderness (measured by shearing force) of muscle samples from carcasses of buffalo steers 16-30 months old was the same as that from feedlot Angus, Hereford, and Friesian steers 12-18 months old. This gives farmers more flexibility in meeting fluctuating markets while still providing tender meat.  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">Selected Readings  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Anonymous. 1976. Livestock Production in Asian Context of Agricultural Diversification. Asian Productivity Organization, Tokyo, Japan.  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Arganosa, F. C., Sanchez, P. C., Ibarra, P. I., Gerpacio, A. L., Castillo, L. S., and Arganosa, V. G. 1973. Evaluation of carabeef as a potential substitute for beef. Philippine Journal of Nutrition 26(2).  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Arganosa, F. C., Arganosa, V. G., and Ibarra, P. I. 1975. Carcass evaluation and utilization of carabeef. In: The Asiatic Water Buffalo. Proceedings of an International Symposium held at Khon Kaen, Thailand, March 31-April 6, 1975. Food and Fertilizer Technology Center, Taipei, Taiwan.  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Bennett, S. P. 1973. The "buffalypso"-an evaluation of a beef type of water buffalo in Trinidad, West Indies. Paper presented at the Third World Conference on Animal Production, Melbourne, Australia.  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Borghese, A., Gigli, S., Romita, A., Di Giacomo, A., and Mormile, M. 1978. Fatty acid composition of fat in water buffalo calves and bovine calves slaughtered at 20, 28, and 36 weeks of age. In: Patterns of Growth and Development in Cattle: A Seminar in the EEC Programme of Coordination of Research on Beef Production, held at Ghent, October 11-13,1977. Martinus Nijhoff, The Hague, Netherlands.  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Charles, D. D., and Johnson, E. R. 1972. Carcass composition of the water buffalo (Bubalus bubalis). Australian Journal of Agriculture Research 23:905-911.  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Charles, D. D., and Johnson, E. R. 1975. Live weight gains and carcass composition of buffalo (Bubalus bubalis) steers on four feeding regimes. Australian Journal of Agriculture Research 26:407-413.  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Cockrill, W. R. 1975. Alternative livestock: with particular reference to the wafer buffalo (Bubalus bubalis). In: Meat. Proceedings of the 21st Easter School in Agricultural Science, University of Nottingham, edited by D. J. A. Cole and R. A. Lawrie. Butterworth, London, England.  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">El-Ashry, M. A., Mogawer, H. H., and Kishin, S. S. 1972. Comparative study of meat production from cattle and buffalo male calves. Egyptian Journal of Animal Production 12:99-107.  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">El-Koussy, H. A., Afifi, Y. A., Dessouki, T. A., and El-Ashry, M. A. 1977. Some chemical and physical changes of buffalo meat after slaughter. Agriculture Research Review 55:1-7.  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Johnson, E. R., and Charles, D. D. 1975. Comparison of live weight gain and changes in carcass composition between buffalo (Bubalus bubalis) and Bos taurus steers. Australian Journal of Agriculture Research 26:415- 422.  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Joksimovic, J. 1979. Physical, chemical and structural characteristics of buffalo meat. Arhiv za Polloprivredne Nauke 22:110.  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Joksimovic, J., and Ognjanovic, A. 1977. A comparison of carcass yield, carcass composition, and quality characteristics of buffalo meat and beef Meat Science 1:105 -110.  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Mai, S. C., and Wu, T. H. 1974. TSC's intensive feed-lot system for cow-calf and beef production program. Taiwan Sugar 21(6):198-211.  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Matassino, D., Romita, A., Cosentino, E., Girolami, A., and Cloatruglio, P. 1978. Myorheological, ohemical, and colour characteristics of meat in water buffalo and bovine calves slaughtered at 20, 28 and 36 weeks. In: Patterns of Growth and Development in Cattle: A Seminar in the EEC Programme of Coordination of Research on Beef Production, held at Chent, October 11-13, 1977. Martinus Nijhoff, The Hague, Netherlands.  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Mogawer, H. H., El-Ashry, M. A., and Mahmoud, S. A. 1976. Comparative study of meat production from cattle and buffalo male calves. II. Effect of different roughage concentrate ratios in ration on carcass traits. Journal of Agriculture Research {Tanta University) 2:6-12.  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Ognjanovic, A. 1974. Meat and meat production. In: The Husbandry and Health of the Domestic Buffalo, edited by W. R. CockrilL Food and Agriculture Organization of the United Nations, Rome, Italy. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Rastogi, R., Youssef, F. G., and Gonzalez, F. D. 1978. Beef type water buffalo of Trinidad-Beefalypso. World Review of Animal Production 14(2) :49 -56.  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Romita, A., Borghese, A., Gigli, S., and Di Giacomo, A. 1978. Growth rate and carcass composition of water buffalo calves and bovine calves slaughtered at 20, 28 and 36 weeks. In: Patterns of Growth and Development in Cattle: A Seminar in the EEC Programme of Coordination of Research on Beef Production, Held at Chent, October 11-13, 1977. Martinus Nijhoff, The Hague, Netherlands.  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Wilson, P. N. 1961. Palatability of water buffalo meat. Journal of the Agricultural Society of Trinidad 61:457, 459-460. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<B><P ALIGN="CENTER">&lt;&lt;TOC2&gt;&gt; 3 Milk</P>
+</B><P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">More than 5 percent of the world's milk comes from water buffaloes. Buffalo milk is  used in much the same way as cow's milk. It is high in fat and total solids, which  gives it a rich flavor. Many people prefer it to cow's milk and are willing to pay more  for it. In Egypt, for example, the severe mortality rate among buffalo calves is due in  part to the sale of buffalo milk, which is in high demand, thus depriving calves of  proper nourishment. This also occurs in India, where in the Bombay area alone an  estimated 10,000 newborn calves starve to death each year through lack of milk.  The demand for buffalo milk in India (about 60 percent of the milk consumed; over  80 percent in some states) is reflected in the prices paid for a liter of milk: about  130 paisa for cow's milk compared with about 200 paisa for buffalo milk.  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Twelve of the 18 major breeds of water buffalo are kept primarily for milk production  (although males may be used for traction and all animals are eventually used for  meat). The main milk breeds of India and Pakistan are the Murrah, Nili/Ravi, Surti,  Mehsana, Nagpuri, and Jafarabadi. The buffaloes of Egypt, Eastern Europe  (Bulgaria, Romania, Yugoslavia, and the USSR), and Italy are used for milk  production and there are also herds used principally for this purpose in Iran, Iraq,  and Turkey.  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">Composition</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Buffalo milk contains less water, more total solids, more fat, slightly more lactose,  and more protein than cow's milk. It seems thicker than cow's milk because it  generally contains more than 16 percent total solids compared with 12-14 percent  for cow's milk. In addition, its fat content is usually 50-60 percent higher (or more)  than that of cow's milk. Although the butterfat content is usually 6-8 percent,( An analysis of 7,770 records of Nili/Ravi buffaloes in herds at the Pakistan  Research Institute showed that average butterfat content was 6.40 (a mean based  on 10 tests over 10 months). of all the samples tested, 77 percent ranged between  5 and 8 percent butterfat and 12 percent were below 5 percent butterfat.  -information supplied by R. E. McDowell.)  it can  go much higher in the milk of some well fed dairy buffaloes and in the milk of  Swamp buffaloes (which are not normally used for milking). Cow's milk butterfat content is usually between 3 and 5 percent.  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Because of its high butterfat content, buffalo milk has considerably higher energy value than cow's milk. Phospholipids are lower but cholesterol and saturated fatty acids are higher in buffalo milk. Studies have shown that digestibility is not adversely affected by this. Because of the high fat content, the buffalo's total fat yield per lactation compares favorably with that of improved breeds of dairy cattle; it is much higher than that of indigenous cows.  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Normally the protein in buffalo milk contains more casein and slightly more albumin and globulin than cow's milk. Several researchers have claimed that the biological value of buffalo milk protein is higher than that of cow's milk, but this has not yet been proved conclusively.  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&lt;&lt;I&gt;&gt; p27.png Tables 1 and 2</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The mineral content of buffalo milk is nearly the same as that of cow's milk except for phosphorus, which occurs in roughly twice the amount in buffalo milk. Buffalo milk tends to be lower in salt.  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Buffalo milk lacks the yellow pigment carotene, precursor for vitamin A, and its whiteness is frequently used to differentiate it from cow's milk in the market. Despite the absence of carotene, the vitamin A content in buffalo milk is almost as high as that of cow's milk. (Apparently the buffalo converts the carotene in its diet to vitamin A. The two milks are similar in B complex vitamins and vitamin C, but buffalo milk tends to be lower in riboflavin.)  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">Milk Products</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Buffalo milk, like cow's milk, can provide a wide variety of products: butter, butter oil (clarified butter or ghee), soft and hard cheeses, condensed or evaporated milks, ice cream,yogurt, and buttermilk. It is of great economic importance in India in preparing "toned" milk-a mixture of buffalo milk and milk made by reconstituting skim milk powder.  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The richness of buffalo milk makes it highly suitable for processing. To produce 1 kg of cheese, a cheese maker requires 8 kg of cow's milk but only 5 kg of buffalo milk. To produce 1 kg of butter requires 14 kg of cow's milk but only 10 kg of buffalo milk. Because of these high yields, processors appreciate the value of buffalo milk.  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Buffalo cheese is pure white. It many countries it is among the most desirable cheeses (mozzarella and ricotta in Italy, gemir in Iraq, the salty cheeses of Egypt, and pecorino in Bulgaria, for example). In Venezuela all the cheese produced from the small La Guanota milking herd in the Apure River basin (about 100 kg a day) is bought by the Hilton Hotel and sells for 15 bolivars per kg compared with 8 bolivars per kg for cheese made from cow's milk.  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Although much in demand for making soft cheese, buffalo milk is less desirable for making hard cheeses such as cheddar or gouda. During cheesemaking it produces acid more slowly than cow's milk, retains more water in the curd, and loses more fat in the whey.  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Cheeses are becoming increasingly popular throughout the world. Demand is rising at a rate that is among the highest for any food product. Cheese offers particular benefit to areas where refrigeration is not widely available, where transporting high-protein foods to remote areas is difficult, and where seasonal fluctuations affect milk supplies. Buffalo milk may make cheesemaking profitable on an even smaller scale than conventional dairying; it is more concentrated than cow's milk and requires relatively less energy to transport and process (an increasingly important factor where fuels are limited).  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&lt;&lt;I&gt;&gt; p31.png Table 3 Highest Milk Yield (kg per Day) Recorded in the All India Milk Yield</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">Yield</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">In countries like India and Egypt, the milk yield of buffaloes is generally higher  (680-800 kg) than for local cattle (360-500 kg). However, since selection for  exceptional milk production is not conducted systematically, large variations in yield  occur between individual animals, and milk production of dairy buffaloes falls short  of its potential.  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Nonetheless, some outstanding yields have been recorded. On Indian government  farms, average yields for milking buffaloes range from 4 to 7 kg per day in  lactations averaging 285 days. Daily yields of 12 kg have been reported for some  Bulgarian buffalo cows and a daily production of over 20 kg has been reported for  some remarkable animals in India. A peak milk yield of 31.5 kg in a day has been  recorded from a champion Murrah buffalo in the All India Milk Yield Competition  conducted by the Government of India (see Table 3).  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">At Caserta, Italy, a herd of 1,600 machine-milked, pedigreed dairy buffaloes has  produced average yields of 1,500 kg during lactations of 270 days. In Pakistan an  analysis of over 6,000 lactations of Nili/Ravi buffalo cows showed an average yield  of 1,925 kg during lactations averaging 282 days(Average adjusted for year and  season and calving. Cady et al., in press.) . In India the average milks yield of  Murrah buffaloes in established herds is also reported to be about  1,800kg(*"Williamson and Payne, 1965.)Table 4 lists some outstanding lactation  yields reported from different parts of the world. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">As with cattle, the percentages of fat, protein, and total solids decrease as the milks yield increases.  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The Swamp buffaloes of Southeast Asia are usually considered poor milk producers. They are used mainly as draft animals, but it may be that their milk potential has been underestimated. In the Philippines Swamp buffalo cows with nursing calves have produced 300-800 kg of milk during lactation periods of 180-300 days(*Philippines Council for Agriculture and Resources Research (PCARR). 1978. The Philippines Recommends for Caraboo Production, PCARR, Los Banos, Philippines)In Thailand Swamp buffaloes selected and reared for milk production have yielded 3-5 kg per day during 305-day lactations.(Information supplied by Charan Chantalakhana.)</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&lt;&lt;I&gt;&gt; p32.png Table 4 Milk Production of Some Outstading Buffalo Cows and Dairy Herds</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The Nanning Livestock Research Institute and Farm in Kwangsi Province,which is representative of many others in South China, is upgrading the native  Swamp buffaloes (or Shui Niu) by selective breeding for size and weight and by  crossbreeding with dairy breeds such as the Murrah and Nili/Ravi. The crossbreeds  that are milked yield 4-5 kg daily.(*CockriH, W. R. 1976. The Buffaloes of China.  FAO, Rome.) </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">  </P>
+<P ALIGN="JUSTIFY">Dairy Management</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The characteristics of the dairy buffalo so closely approximate those of the dairy cow that successful methods of breeding, husbandry, and feeding for  milks production for the cow can be applied equally to the dairy buffalo. Buffaloes,  however, have not been bred for uniform udders and it is more difficult to milk them  by machine.(Some thousands of buffaloes are machine milked in Bulgaria and Italy, however. At  Ain Shams University in Egypt, buffaloes have adapted to machine milking. The  calves are separated from their dams immediately after birth and no problems of  milk letdown have been observed. -information supplied by M. El Ashry.)Also, some buffaloes have more of a problem with milks letdown than  dairy cows (although not as much of a problem as some native cattle breeds in the  tropics). Frequently, a calf is kept with the cow and is tied to her foreleg at milking  time. In India, Burma, and other countries a dummy calf may be provided; playing  music seems to work, too.  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">Selected Readings</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Addeo, F., Mercier, J. C., and Ribadeau-Dumas, B. 1977. The caseins of buffalo  milk. Journal of Dairy Research 44(3):455-468.  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Agarwala, O. P. 1962. Certain factors of reproduction and production in a water  buffalo herd. Indian Joumal of Dairy Science 15(2):45-51.  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Albourco, F., Mincione, B., Addeo, F., and Ameno, M. 1969. Buffaloes' milk. II.  Variations in composition during lactation of milk produced without change in  feeding. Industrie Agraria 7(5):210-219.  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Associazione Italiana Tecnici del Latter. 1970. Buffaloes' milk and cheese. Scienza  e Tecnica 21(3):175-196.  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Bhatnagar, V. K., Lohia, K. L., and Monga, O. P. 1961. Effect of the month of  calving on milk yield, lactation length and calving interval in Murrah buffaloes. Indian  Journal of Dairy Science 14(3): 102-108.  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Bhasin N. R., and Desai, R. N. 1967. Effect of age at first calving and first lactation  yield on life time production in Hariana cattle. Indian Veterinary Journal 44:684694.  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Cady, R. A., Shah, S. K., Schermerhorn, E. C., and McDowell, R. E. In Press.  Factors affecting performance of Nili-Ravi buffaloes in Pakistan. Journal of Dairy  Science.  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Castillo, L. S. 1975. Production, characteristics and processing of buffalo milk. In:  The Asiatic Water Buffalo. Proceedings of an International Symposium held at  Khon Kahn, Thailand, March 31-April 6, 1975. Food and Fertilizer Technology  Center, Taipei, Taiwan.  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Dassat, P. M., de Paolis, P., and Sartore, G. 1966. Environmental effects on milks  yield in Italian buffalo.Acta Medica Veterinaria 12(6):587-593.  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Dave, B. K., and Taylor, C. M. 1975. A study on relationship of persistency with other first production traits in Indian water buffaloes. Indian Journal of Animal Health 14(1) :77-80.  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Deshmukh, S. N., and Choudhury, P. N. R. 1971. Repeatability estimates of some economic characteristics in Italian buffaloes. Zentralblatt fuer Veterinaer-medizen 18:104-107.  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Ganguli, N. C. 1979. Buffalo milk technology. World Animal Review 30:2-10.  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Gomez, I. V. 1977. The manufacture of semihard cheese (Danish type) from carabao milk. Philippine Agriculturalist 61(3/4) :78-86.  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Gurnani, M., and Nagarcenkar, R. 1971. Evaluation of breeding performance of buffaloes and estimation of genetic and phenotypic parameters. Annual Report of the National Dairy Research Institute, Karnal, India.  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Katpatal, B. G. 1977. Dairy cattle crossbreeding in India. I. Growth and development of crossbreeding. World Animal Review 22: 15-21.  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Kay, H. D. 1974. Milk and milk production. In: The Husbandry and Health of the Domestic Buffalo, edited by W. R. Cockrill. Food and Agriculture Organization of the United Nations, Rome, Italy.  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Kohli, M. L., and Malik, D. D. 1960. Effect of service period on total milk production and lactation length in Murrah buffaloes. Indian Journal of Dairy Science 13(3): 105-111.  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Nascimento, C. N. B., Moura Carvalho, L. O. D., and Lourenco, J. B. 1979. Irnportancia do Bufalo para a Pecuarfa Brasileira. Agricultural Research Center for Humid Tropics (CPATU), Belem, Para, Brazil.  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Raafat, M. A., El-Sayed, Abou-Hussein, Abou-Raya, A. K., and El-Shirbiny A. 1974. Some nutritional studies of colostrum and milk of cows and buffaloes E:gyptian Journal of Animal Production 14(1) :137-148.  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Ragab, M. T., Asker, A. A., and Kamal, T. H. 1958. The effect of age and seasonal calving on the composition of Egyptian buffalo milk. Indian Journal of Dairy Science 11(1):18-28.  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Saudi Arabia Standards Institution. 1978. Raw milk. Saudi Arabia Standard 98.  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Sebastian, J., Panthulu, P. C, and Bhimasena, M. 1971. Composition of Surti buffalo milk. Annual Report of the National Dairy Research Institute, Karnal, India.  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Sekhon, G. S., and Gehlon, M. S. 1966. Repeatability estimates of some economic traits in the Murrah buffalo. Ceylon Veterinary Journal 14:18-22.  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Singh, B. B., and Singh, B. P. 1971. Comparative study of lifetime economics of Hariana versus Murrah buffaloes. Indian Veterinary Journal 48:485-489.  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Singh, R. P. 1966. A study of production up to ten years of age in buffaloes maintained at military farms. Indian Veterinary Journal 43:986-992.  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Singh, S. B., and Desai, R. N. 1962. Production character of Bhadawari buffalo cow. Indian Veterinary journal 39:332-343.  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Venkayya, D., and Anantakrishnan, C. P. 1957. Influence of age at first calving on the performance of Murrah buffaloes. Indian Journal of Dairy Science 10(1):20-24.  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Williamson, G., and Payne, W. J. A. 1965. An Introduction to Animal Husbandry in the Tropics. Longman, London, United Kingdom. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<B><P ALIGN="CENTER">&lt;&lt;TOC2&gt;&gt; 4 Work</P>
+</B><P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The water buffalo is the classic work animal of Asia, an integral part of that  continent's traditional village farming structure. Probably the most adaptable and  versatile of all work animals, it is widely used to plow; level land; plant crops; puddle  rice fields; cultivate field crops; pump water; haul carts, sleds, and shallow-draft  boats; carry people; thresh grain; press sugar cane; haul logs; and much more.  Even today, water buffaloes provide 20-30 percent of the farm power in South  China, Thailand, Indonesia, Malaysia, Philippines, and Indochina(Figures provided by A. J. de veer. In India water buffaloes contribute much less to  farm power (6-12 percent); bullocks are more commonly used. In Pakistan  buffaloes are little used for farm power (1-2 percent) but provide much of the road  haulage. Papua New Guinea has no tradition of using any work animal, but villagers  are increasingly using buffaloes for farm work and the government is employing  Fillipinos to train them) . Millions of  peasants in the Far East, Middle East, and Near East have a draft buffalo. For them  it is often the only method of farming food crops.  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">As fuel becomes scarce and expensive in these countries, the buffalo is being used  more frequently as a draft animal. ln 1979 water buffalo prices soared in rural  Thailand because of the increased demand.  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Although Asian farms have increasingly mechanized in the last 20 years, it has  often proved difficult to persuade the farmer to replace his buffalo with a tractor  since the buffalo produces free fertilizer and does not require diesel fuel. Now there  is renewed official interest in draft power. Sri Lanka has recently opened up large  new tracts of farmland in the Mahawali Valley, creating such a demand for work  animals that buffalo shortages have become a national development problem.  Indonesia's transmigration schemes are also handicapped by shortages of animal  power.  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">For many small farmers the buffalo represents capital. It is often the major  investment they have. Buffalo energy increases their productivity and allows them to  diversify. Even small farms have work animals that, like the farmer himself, subsist  off the farm. Tractors usually require at least four hectares for economical operation,  which precludes their use on most peasant farms. Further, the infrastructure to  maintain machinery is often not readily available.  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Buffaloes are also used for hauling. Buffalo-drawn carts carry goods between  villages where road surfaces are unfit for trucks. The animals easily traverse  ravines, streams, paddies, and narrow and rocky trails. In the cities carts can  compete economically with trucks where the road surface is unprepared, where  loading or unloading takes longer than the journey itself, or where the loads are too  small and distances too short to make trucking economical. For road haulage  buffaloes are generally shod: the shoes are flat plates fitted to each hoof.  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">Capacity for Work</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The water buffalo is a sturdy draft animal Its body structure, especially the  distribution of body weight over the feet and legs, is an important advantage. Its  large boxy hooves allow it to move in the soft mud of rice fields. Moreover, the  buffalo has very flexible pastern and fetlock joints in the lower leg so that it can bend  back its hooves and step over obstacles more easily than cattle. This water-loving  animal is particularly well adapted to paddy farming because its legs withstand  continual wet conditions better than mules or oxen(Australian animal scientists working in Bogor, Indonesia, found that the puddling  effect of buffalo hooves on the soil was critical for rice cultivation in the local soils.  Tractors produced fields so porous that they drained dry. (Information supplied by  A. F. GurnettSmith.) On one research station near Darwin, Australia, buffaloes were  used to prevent water draining from a dam. (Information supplied by D. G. Tulloch.). </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Although buffaloes are preferred by farmers in the wet, often muddy lowlands of  Asia, mules, horses, and cattle move more rapidly and are preferred in the dryer  areas.  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Water buffaloes do not work quickly. They plod along at about 3 km per hour. In  most parts of Southeast Asia they are worked about 5 hours a day and they may  take 6-10 days to plow, harrow, and grade one hectare of rice field. Their stamina  and drawing power increase with body weight.  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Because they have difficulty keeping cool in hot, humid weather (see next chapter),  it is necessary to let working buffaloes cool off, preferably in a wallow, every 2 hours  or so. Without this their body temperatures may rise to dangerous levels.  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">A pair of 3-year-old buffaloes costs about the same as a small tractor in Thailand.  But many farmers raise their own calves and there is no investment beyond labor.  The "fuel" for the animals comes mainly from village pastures and farm wastes such  as crop stubble and sugarcane tops. Buffaloes have an average working life of  about 11 years, but some work to age 20.  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">  </P>
+<P ALIGN="JUSTIFY">Harness</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The yoke used on working buffalo in Asia has changed very little in the last 1,500 years. It is doubtful that a working buffalo can exert its full power with it. The hard wooden yoke presses on a very small area on top of the animal's neck, producing severe calluses, galls, and obvious discomfort. The harness tends to choke the animal as the straps under the neck tighten into the windpipe. Since the traditional hitch is usually higher than the buffalo's low center of gravity, the animal cannot pull efficiently. Considerably more pulling power and endurance can be obtained by improving the harness. The situation is not unlike that in Western agriculture in the twelfth century when the horse collar-one of the most important inventions of the Middle Ages first appeared. Before that, horses were yoked like buffalo and the harness passed across their windpipes and choked them as they pulled. Use of the horse collar improved pulling efficiency and speeded the development of transportation and trade.  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The curved yoke now universally used on water buffalo contacts an area of the neck that is only about 200 cm2 (little more than half the size of this page). The entire load is pulled on this small area and causes the wood to dig into the flesh.  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">A horse collar is a padded leather device that encircles the animal's neck. One modified in Thailand for use on water buffalo (see page 43) had a contact area of 650 cm2, more than three times that of the yoke it replaced. The collar's padding pressed against the animal's shoulders, not its neck, and  therefore did not choke it. Attached to the collar were wooden hames with the traces for hitching the animal to a wagon or plow. In trials a buffalo pulled loads 24 percent heavier with the collar than with the yoke, and the horsepower it developed increased by 48 percent(These trials were conducted by J. K. Garner in Thailand in 1958. In the maximum-load test the yoked buffalo failed to move a load of 570 kg, but it moved a load of 640 kg when fitted with the horse collar. In an endurance test the yoked animal took 35 minutes to pull a load 550 m, but harnessed with the collar it took only 21 minutes). </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Another potentially valuable harness is the breast strap, a set of broad leather straps that pass over the animal's neck and back. One breast strap modified for water buffalo use had a contact area of 620 cm2, almost as much as that of the horse collar, and in trials the buffalo pulled a load 12 percent heavier than with a yoke and the horsepower it developed increased by almost 70 percent( The same animal used in the horse collar trials pulled 700 kg with the breast strap, in the endurance test it took 18.5 minutes to travel the 550-m distance). </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">These seem very good innovations. In the humid tropics, however, leather collars and breast straps may decay rapidly. To make them widely practical may require experimentation with, or development of, special leather treatments or more durable materials.  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">Selected Readings</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Cockrill, W. R. 1974. The working buffalo. In: The Husbandry and Health of the Domes tic Buffalo, edited by W. R. Cockrill. Food and Agriculture Organization of the United Nations, Rome, Italy.  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Cockrill, W. R. 1976. The Buffaloes of China. Food and Agriculture Organization of the United Nations, Rome, Italy.  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">de Guzman, M. R., Jr. 1975. The water buffalo-Asia's beast of burden and key to progress. In: The Asiatic Water Buffalo. Proceedings of an International Symposium held at Khon Kaen, Thailand, March 31-April 6, 1975. Food and Fertilizer Technology Center, Taipei, Taiwan.  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Garner, J. K. 1958 (Reprint 1980) Increasing the Work Efficiency of the Water Buffalo Through Use of Improved Harness. (Copies available from Office of Agriculture, Development Support Bureau, Agency for International Development, Washington, D.C. 20523)  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Kamal, T. H., Shehata, O., and Elbanna, I. M. 1972. Isotope Studies on the Physiology of Domestic Animals. International Atomic Energy Agency, Vienna, Austria.  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Robinson, D. W. 1977. Preliminary Observations on the Productivity of Working Buffalo in Indonesia. Research Report No. 2, Center for Animal Research and Development, Bogor, Indonesia.  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Vaugh, M. 1945. Report on a detailed study of methods of yoking bullocks for agricultural work. Indian Journal of Veterinary Science 15:186-198.  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Ward, G. M., Sutherland, T. M., and Sutherland, J. M. 1980. Animals as an energy source in Third World agriculture. Science 208:570. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<B><P ALIGN="CENTER">&lt;&lt;TOC2&gt;&gt; 5 Adaptability and Environmental Tolerance</P>
+</B><P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Heat Tolerance</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">While the buffalo is remarkably versatile, it has less physiological adaptation to extremes of heat and cold than the various breeds of cattle. Body temperatures of buffaloes are actually lower than those of cattle, but buffalo skin is usually black and heat absorbent and only sparsely protected by hair. Also, buffalo skin has one-sixth the density of sweat glands that cattle skin has, so buffaloes dissipate heat poorly by sweating. If worked or  driven excessively in the hot sun, a buffalo's body temperature, pulse rate, respiration rate, and general discomfort increase more quickly than those of cattle(Failure to appreciate this has caused many buffalo deaths in northern Australia when the animals were herded long distances through the heat of the day as if they were cattle).. This is particularly true of young calves and pregnant females. During one trial in Egypt 2 hours' exposure to sun caused temperatures of buffalo to rise 1.3°C, whereas temperatures of cattle rose only 0.2-0.3°C.  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Buffaloes prefer to cool off in a wallow rather than seek shade. They may wallow for up to 5 hours a day when temperatures and humidity are high. Immersed in water or mud, chewing with half-closed eyes, buffaloes are a picture of bliss.  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">In shade or in a wallow buffaloes cool off quickly, perhaps because a black skin rich in blood vessels conducts and radiates heat efficiently (Tests at the University of Florida have shown that buffaloes in the shade cool off more quickly than cattle. -Robey, 1976).  Nonetheless, wallowing is not essential. Experience in Australia, Trinidad, Florida, Malaysia, and elsewhere has shown that buffaloes grow normally without wallowing as long as adequate shade is available.  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">Cold Tolerance</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Although generally associated with the humid tropics, buffaloes, as already noted, have been reared for centuries in temperate countries such as Italy, Greece, Yugoslavia, Bulgaria, Hungary, Romania, and in the Azerbaijan and Georgian republics of the USSR. In 1807 Napoleon brought Italian buffaloes to the Landes region of southwest France and released them near Mont-deMarsan. They became feral and multiplied prodigiously in the woods and dunes of the littoral, but unfortunately the local peasants found them easy targets, and with the fall of Napoleon the whole herd was killed for meat(In the twelfth century Benedictine monks introduced buffaloes from their possessions in the Orient to work the lands of their abbey at Auge in northeastern France. In the thirteenth century a herd was introduced to England by the Earl of Cornwall, the brother of Henry III. Nothing is known about how well either herd survived). Buffaloes are also maintained on the high, snowy plateaus of Turkey as well as in Afghanistan and the northern mountains of Pakistan.  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The buffalo has greater tolerance of cold weather than is commonly supposed. The current range of the buffalo extends as far north as 45° latitude in Romania and the sizable herds in Italy and the Soviet Union range over 40° N latitude(Philadelphia and Peking are at comparable latitudes. In the Southern Hemisphere the 40° line of latitude easily encompasses Cape Town, Buenos Aires, Melbourne, and most of New Zealand's North Island).  Cold winds and rapid drops in temperatures, however, appear to have caused illness, pneumonia, and sometimes death. Most of the animals in Europe are of the Mediterranean breed, but other River-type buffaloes (mainly Murrahs from India) have been introduced to Bulgaria and the Soviet Union, which indicates that River breeds, at least, have some cold tolerance.  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">Altitude</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Although water buffaloes are generally reared at low elevations, a herd of Swamp buffaloes is thriving at Kandep in Papua New Guinea, 2,500 m above sea level. And in Nepal, River buffaloes are routinely found at or above 2,800 m altitude.  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">Wetlands</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Water buffaloes are well adapted to swamps and to areas subject to flooding. They are at home in the marshes of southern Iraq and of the Amazon, the tidal plains near Darwin, Australia, the Pontine Marshes in south-central Italy, the Orinoco Basin of Venezuela, and other areas.  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">In the Amazon, buffaloes (Mediterranean and Swamp breeds) are demonstrating their exceptional adaptability to flood areas. Buffalo productivity outstrips that of cattle, with males reaching 400 kg in 30 months on a diet of native grasses( Information supplied by C. Nascimento). </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The advantage of water buffaloes over Holstein, Brown Swiss, and Criollo cattle was demonstrated in a test at Delta Amacuro, Venezuela, when the cattle developed serious foot rot In the wet conditions of the Orinoco Delta and had to be withdrawn from the test. The area of Venezuela is flooded 6 months of the year and creates constant problems for cattle, yet the buffalo seems to adapt well(*Information supplied by A. Ferrer). </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">High humidities seem to affect buffaloes less than cattle. In fact, if shade or wallows are available, buffaloes may be superior to cattle in humid areas.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">In southern Brazil, trials comparing buffalo and cattle on subtropical riverine plains have favored the buffalo also. This work is being carried out on native pastures, mostly in  the State of Sao Paulo.  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">Selected Readings</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Hafez, E. S. E., Badreldin, A. L., and Shafei,M. M. 1955. Skin structure of Egyptian buffaloes and cattle with particular reference to sweat glands. Journal of Agricultural Science, Cambridge 46:19-30.  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Katyega, P. M. J., Masoud, A. J., and Kobo, E. 1980. Information on body and carcass characteristics of Egyptian water buffalo and Mpwapwa x Friesian steers raised in central Tanzania. Tanzania Veterinary Bulletin 2:86-90.  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Mason, I. L. 1974. Environmental physiology. In: The Husbandry and Health of the Domestic Buffalo, edited by W. R. Cockrill. Food and Agriculture Organization of the United Nations, Rome, Italy.  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Moran, J. B. 1973. Heat tolerance of Brahman cross, buffalo, Banteng and Shorthorn steers during exposure to sun and as a result of exercise. Australian Journal of Agricultural Research 24(5) :775 -782.  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Nair, P. G., and Benjamin, B. R. 1963. Studies on sweat glands in the Indian water buffalo. 1. Standardization of techniques and preliminary observations. Indian Journal of Veterinary Science 33:102.  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Pandey, M. D., and Roy, A. 1969a. Studies on the adaptability of buffaloes to tropical climate. I. Seasonal changes in the water and electrolyte status of buffalo cows. Indian Journal of Animal Science 39:367.  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Pandey, M. D., and Roy, A. 1969b. Studies on the adaptability of buffaloes to tropical climate. II. Seasonal changes in the body temperature, cardio-respiratory and hematological attributes in buffalo cows. Indian Journal of Animal Science 39:378.  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Prusty, J. N. 1973. Role of the sweat glands in heat regulation in the Indian water buffalo. Indian Journal of Animal Health 12(1):33-37.  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Robey, C. A., Jr. 1976. Physiological Responses of Water Buffalo to the Florida Environment. M.S. Thesis, University of Florida, Gainesville, Florida, USA.  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<B><P ALIGN="CENTER">&lt;&lt;TOC2&gt;&gt; 6 Nutrition</P>
+</B><P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Most buffaloes are located in countries where land, cultivated forage crops, and pastures  are limited. Livestock must feed on poor-quality forages, sometimes supplemented with  a little green fodder or byproducts from food, grain, and oil seed processing. Usually  feedstuffs are in such short supply that few animals have a balanced diet, but the buffalo  seems to perform fairly well under such adverse conditions.  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">Growth Rate</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Insufficient measurements have been taken to allow unequivocal state. meets about the  relative growth rates of cattle and buffaloes. However, many observations made in  various parts of the world indicate that the buffalo's growth is seldom inferior to that of  cattle breeds found in the same environments. Some observations are given below.  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">· Trials in Trinidad in the early 1960s involved buffaloes grazing pangola grass (Digitaria  decumbens) together with Brahman and Jamaican Red cattle. Over a period of 20  months the buffaloes gained an average of 0.72 kg per day, whereas the cattle on a  comparable nearby pasture gained 0.63 per day(Experiments performed by P. N. Wilson. -Information supplied by S. P. Bennett.).  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">· In the Orinoco Delta of Venezuela unselected Criollo/Zebu crossbred cattle gained  0-0.2 kg per day on Paspalum fasciculatum, whereas the water buffaloes with them  gained 0.25-0.4 kg per day(Cunha  et al., 1975).  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">· In the Apure Valley of Venezuela, 100 buffalo steers studied in 1979 reached an  average weight of 508 kg in 30 months, whereas the 30-month old Zebu steers tested  with them weighed 320 kg. The feed consumed was a blend of native grasses (25  percent of the diet) and improved grasses (such as pangola, pare, and guinea grass)( Information supplied by A. Ferrer). In  the same valley 200 buffalo heifers (air freighted from Australia) produced weight gains  averaging 0.5 kg per day over a 2-year period (and 72 percent of them calved). Government statistics for the area record average weight gains in crossbreeds between Zebu and Criollo cattle as 0.28 kg per day (with 40 percent calving).  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">· In the Philippines, buffaloes showed weight gains of 0.75-1.25 kg per day, the same as those of cattle. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">· Daily weight gains of over 1 kg have been recorded for buffaloes in Bulgaria and Yugoslavia.  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">· Liveweight gains of 0.80 kg per day have been recorded for buffaloes in Papua New Guinea. In a very humid, swampy area of the Sepik River coastal plains liveweight gains by males averaged 0.47 kg per day and females 0.43 kg per day for more than a year. The average weight of 30 4-year-old female buffaloes was 375 kg, while the average weight of 4-year-old female Brahman/ Shorthorn crossbred cattle was 320 kg.  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">· At the research station near Belem in the Brazilian Amazon weaned Murrah buffaloes, pastured continuously on Echinochloa pyramidalis (a nutritious grass), gained 0.8 kg daily and reached 450 kg in about 18 months. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">· Liveweight gains of 0.74-l.i kg per day have been obtained in Australia. Buffalo steers grew as fast or faster than crossbred Brahman cattle on several improved pastures near Darwin, but on one very poor pasture, 40-year-old buffaloes each weighed only 400 kg, whereas the Brahman crossbred steers reared with them weighed 500 kg. The reason for this is not clear.  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">Efficiency of Digestion</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Indian animal nutritionists have investigated water buffaloes intensively over the past two decades. Many have reported that buffaloes digest feeds more efficiently than do cattle, particularly when feeds are of poor quality and are high in cellulose.One trial revealed that the digestibility of wheat straw cellulose was 24.3 percent for cattle and 30.7 percent for buffalo. The figures for berseem (Trifolium alexandrinum) cellulose were 34.6 percent for cattle and 52.2 percent for buffalo. In another trial the digestion of straw fiber was 64.7 percent in cattle, 79.8 percent in buffalo.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Other nutrients reported to be more highly digested in buffaloes than in cattle (Zebu) are crude fat, calcium and phosphorus, and nonprotein nitrogen.  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Recent experiments in India suggest that buffaloes also are able to utilize nitrogen more efficiently than cattle. Buffaloes digested less crude protein than cattle in one trial but increased their body nitrogen more (and they were being fed only 40 percent of the recommended daily intake of crude protein).  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The ability of buffaloes to digest fiber efficiently may be partly due to the microorganisms in their rumen. Several Indian research teams have published data indicating that the microbes in the buffalo rumen convert feed into energy more efficiently than do those in cattle (as measured by the rate of production of volatile fatty acids in the rumen).  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Also, in laboratory studies samples of buffalo rumen contents produced volatile fatty acids more quickly from a variety of animal feedstuffs than did samples from the rumen of cattle  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">No single reason alone explains the buffalo's success in using poor quality forages. Rather, it is a combination of reasons that differ with the breed and conditions used. Studies by other researchers suggest that additional causes might include:  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">· Higher dry matter intake; </P>
+<P ALIGN="JUSTIFY">· Longer retention of feed in digestive tract;  </P>
+<P ALIGN="JUSTIFY">· Ruminal characteristics more favorable to ammonia-nitrogen utilization;  </P>
+<P ALIGN="JUSTIFY">· Less depression of cellulose digestion by soluble carbohydrates (e.g., starch or molasses);  </P>
+<P ALIGN="JUSTIFY">· Superior ability to handle stressful environment; and  </P>
+<P ALIGN="JUSTIFY">· A wider range of grazing preferences.  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">Calf Growth Rates</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Although the buffalo's gestation period is more than a month longer than that of cattle, the calves are born weighing 35-40 kg, or about the same as that of a newborn Holstein calf. But because buffalo milk has about twice the butterfat of cow's milk, the calves grow very quickly. They also suffer more shock at weaning and have to be slowly changed to their new feeding program. Buffaloes can be marketed as full-grown animals for beef at the age of 2-3 years, sometimes even earlier.  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&lt;&lt;I&gt;&gt; p59.png Table 5 Some Coarse Grasses and Forages Palatable to Buffaloes but Less Readily</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">For example, in Indonesia it has been found that buffalo steers can be marketed 6 months before Zebu steers because they may be 100 kg heavier. In Egypt some buffalo calves given feed supplemented with concentrates weighed 360 kg at 1 year of age. At Ain Shams University near Cairo, buffalo calves weaned at 7-14 days of age gained 0.7 kg per day from weaning to slaughter at 18 months of age and weighed 400 kg. Rice straw comprised 50 percent of the finishing diet.  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Buffaloes on Italian farms have reached 350 kg in 15-18 months and some year-old calves weighed 320 kg. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Grazing trials on native pasture (with mineral supplementation) in the Brazilian Amazon indicate that buffalo calves grew faster than cattle. At 2 years of age Mediterranean-type buffaloes averaged 369 kg, Swamp type, 322 kg, and Jafarabadi type, 308 kg. The Zebu cattle tested with them averaged 265 kg and the crossbred Zebu/Charolais, 282 kg. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">Feed Preferences</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Buffaloes graze a wider range of plants than cattle. During floods near Manaus in the  Brazilian Amazon when cattle become marooned on small patches of high ground,  many suffer from foot rot and many starve to death. Their buffalo companions on the  other hand-bodies sleek and full-swim out to islands of floating aquatic plants and eat  them, treading water. Also, they dive almost 2 m to graze beneath the floodwaters. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">University of Florida buffaloes in a lakefront voluntarily consumed vines, sedges, rushes, floating aquatic weeds, and the leaves and shoots of willows and other  trees along the water's edge. Few of these plants are voluntarily grazed by cattle. In  northern Australia water buffaloes graze the very pickily leaves of pandanus; they also  graze sedges, reeds, floating grass, and aquatic weeds. Hungry buffaloes will eat bark,  twigs, and other unpalatable vegetation.  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Because of the variety of their tastes they have been used in northern Queensland,  Australia, to clear pastures of woody weeds left untouched by cattle. In some countries  cattle are used to graze the palatable tops of pasture plants and are followed by  buffaloes to graze the less desirable lower parts.  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">Selected Readings </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Afifi, Y. A., El-Koussy, H. A., El-Khishen, S. S., and El-Ashry, M. A. 1977. Production of  meat from Egyptian buffaloes. I. The effect of using different sources of roughages on  rate of gain, gross and net efficiency during the growth and finishing periods. Egyptian  Journal of Animal Production 17(2).  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Appleton, D. c., Dryden, G., and Kondos, A. C. 1976. A comparison of the digestive  efficiency of the water buffalo and the Brahman and Banteng cattle. Proceedings of the  Australian Society of Animal Production 11.  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Bhatia, L S. 1967. The Study of Factors Affecting the Utilization of Low Grade  Roughages and Production of Volatile Fatty Acids in the Rumen of Indian Cattle. Punjab  Agricultural University, Ludhiana, India.  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Chalmers, M. 1.1974. Nutrition. In: The Husbandry and Health of the Domestic Buffalo  edited by W. R. Cockrill. Food and Agriculture Organization of the United Nations Rome,  Italy.  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Charles, D. D., and Johnson, E. R. 1975. Live weight gains and carcass composition of  buffalo (Bubalus bubalis) steers on four feeding regimes. Australian Journal of  Agricultural Research 26:407-413.  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Chaturvedi, M. L, Singh, u. B., and Ranjhan, 5. K 1973. Comparative studies on the  efficiency of feed unitization in cattle and buffaloes. Indian Journal of Animal Science  43(12):1034.  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Chutikul, K. 1975. Ruminant (Buffalo) nutrition. In: The Asiatic Water Buffalo. Proceedings of an International Symposium held at Khon Kacn, Thailand, March 31April 6, 1975. Food and Fertilizer Technology Center, Taipei, Taiwan.  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Cunha, E., Alvarez, F., Larez, O., and Bryan, W. B. 1975. Pasture and Livestock Investigations in the Humid Tropics: Orinoco Delta, Venezuela. 4. Beef Cattle and Water Buffalo Grazing Trials with Native and Introduced Grasses. IRI Research Institute, New York, New York, USA.  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Davendra, C. 1979. The potential value of grasses and crop by-products for feeding buffaloes in Asia. Extension Bulletin No. 126. Food and Fertilizer Technology Center, Taipei, Taiwan.  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">de Guzman, M. R., Jr. 1975. A summary of research into buffalo feeding in the Philippines. In: The Asiatic Water Buffalo. Proceedings of an International Symposium held at Khon Kaen, Thailand, March 31-April 6, 1975. Food and Fertilizer Technology Center, Taipei, Taiwan.  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Dunkel, R. 1981. Animal production using nutrient-deficient fodders in the tropics and subtropics. Animal Research and Development 13:32-39.  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">El-Ashry, M. A., Mogawer, H. H., and Kishin, S. S. 1972. Comparative study of meat production from cattle and buffalo male calves. I. Effect of roughage: concentrate ratio in ration for rate of gain and feed efficiency of native cattle, Friesian and buffalo calves. Egyptian Journal of Animal Production 12(2) :99 -107.  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Grant, R. J., Van Soest, P. J., McDowell, R. E., and Perez, C. B. 1974. Intake, digestibility and metabolic loss of Napier grass by cattle and buffaloes when fed wilted, chopped and whole. Journal of Animal Science 39(2):423.  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Ibrovic, M., Cvetkovic, A., Smrcek, A., and Janevski, K. 1972. A contribution to the knowledge of metabolism of carotene and seasonal dynamics of vitamin A in the buffalo. Veterinaria 21(4) :511.  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Ichhponani, J. S., Makkar, G. S., Sidhu, G. S., and Moxin, A. L. 1962. Cellulose digestion in water buffaloes and Zebu cattle. Journal of Animal Science 21:1001.  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Ichhponani, J. S., and Sidhu, G. S. 1966. Effect of urea on the voluntary intake of wheat skew in Zebu cattle and the buffalo. Indian Veterinary Journal 43:880-886.  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Ichhponani, J. S., Makkar, G. S., and Sidhu, G. S. 1969. Biochemical processes in the rumen. 111. Effect of different carbobydrates on in vitro digestion of cellulose and utilization of urea nikogen by rumen micro-organisms from zebu and buffalo. Indian Journal of Animal Science 39 :27-32.  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Ichhponani J. S., Makkar, G. S., and Sidhu, G. S. 1971a. Studies on the biochemical process in the rumen. Vl. In vivo digestion of cellulose in buffalo and cattle. Indian Veterinary Journal 48:267-271.  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Ichhponani, J. S., Makkar, G. S., and Sidhu, G. S. 1971b. Studies on the biochemical process in the rumen. VII. In vitro digestion of cellulose in cattle and buffalo. Indian Veterinary Journal 48:583-586.  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Ichhponani, J. S., Makkar, G. S., and Sidhu, G. S. 1972. Studies on the biochemical processes in the rumen. VIIL The significance of molar proportions of acetic and propionic acids in the rumen on the growth rate of buffalo and Zebu. Indian Veterinary Journal 49:995-1000.  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Ichhponani, J. S., Gill, R. S., Makkar, G. S., and Ranjan, S. K. 1977. Work done on buffalo nutrition in India-a review. Indian Journal of Dairy Science 30(3): 173-191.  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Langar, P. N., Sidhu, G. S., and Bhatia, I. S. 1969. Utilization of nitrogen and production of volatile fatty acids in the rumina of buffalo (Bos bubalis) and zebu (Bos indicus) at different time intervals, under a feeding regimen deficient in carbohydrates. Indian Veterinary Journal 46:593-598.  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Ludri, R. S., and Razdan, M. N. 1975. Effect of level and source of dietary nitrogen on water metabolism in cows and buffaloes. Indian Journal of Dairy Science 28:107109.  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Ludri, R. S., and Razdan, M. N. 1980. Efficiency of nitrogen utilization by Zebu cows and buffaloes. I. Nutrient utilization and nitrogen balances on preformed protein diets. TropicalAgriculture (Trinidad) 57:83-90. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Makkar, G. S., and Sidhu, G. S. 1964. The fractionation of carbohydrates in Indian feedstuffs and the digestion of different fractions in the rumina of cattle and buffalo. Journal of Research, Ludhiana 1:56-66.  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Misra, R. K., and Ranhoka, G. S. 1969. Influence of energy levels on the utilization of peanut protein-urea nikogen by cattle and buffalo. Journal of Animal Science 28: 107-109.  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Mullick, D. N. 1964. Review of the investigations on the physiology of Indian buffaloes. Indian Journal of Dairy Saience 17:45-50.  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Naga, M. A., El-Shazly, K., Deif, H. I., Abaza, M. A., and El-Faham, R. H. 1975. Relationship between nitrogen balance, digested nitrogen and dry matter digestibility in ruminants. Journal of Animal Science 40(2):366-373.  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Nangia, O. P., Aggarwal, V. K., and Singh, A. 1972. Studies on the utilization of dietary protein in cattle and buffaloes. Indian Joumal of Dairy &amp;ience 25: 1-5.  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Nascimento C. N. B., Moura Carvalho, L. O. D., and Lourenco, J. B. 1979. Importdneia do Bufaio para a Pecubria Brasileira. Agricultural Research Center for Humid Tropics (CPATU), Belem, Para, Brazil.  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Nascimento, C. N. B., and Velga, J. B. 1973. Weight gains in stabled buffaloes of the Mediterranean breed. Boletim Tecnico do Instituto de Pesqutsas e Experimentacao Agropecuarias do Norte 58:24-72.  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Ponnappa, G. G., Nooruddin, M. D., and Raghavan, G. V. 1971. Rate of the passage of food and its relation to digestibility of nutrients in Murrah buffaloes and Hariana cattle. Indian Journal of Animal Science 41:1026-1030.  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Punj, M. L., Kochar, A. S., Bhatia, I. S., and Sidhu, G. S. 1968. In vitro studies on the cellulolytic activity and production of volatile fatty acids by the inocula obtained from the rumen of Zebu cattle and Murrah buffalo on different feeding regimens. Indian Journal of Veterinary Science 38 :325-332.  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Raghavan, G. V., Kakkar, B., Rao, M. V. N., and Mullick, D. N. 1963. Effects of air temperature and humidity on the metabolism of food nutrients in cattle and buffalo bulls. Annals of Biochemistry and Experimental Medicine 23 :23-28.  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Ray, S. N., and Mudgal, V. D. 1962. Rumen metabolism studies in cattle and buffalo. Proceedings of the 16th International Dairy Congress, Copenhagen. A:105-l11.  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Sahai, L., Johri, P. N., and Kehar, N. D. 1955. Effect of feeding alkali and water-treated cereal straws on milk yield. Indfan Journal of Veterinary Science 25:201-212.  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Saini, B. S., and Ray, S. N. 1964. Comparative utilization of coarse fodders in cattle and buffalo. Annual Report of the National Dairy Research Institute, Karnal, India.  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Schottler, J. H., Boromana, A., and Williams, W. T. 1977. Comparative performance of cattle and buffalo on the Sepik Plains, Papua New Guinea.AustralianJournal of Experimental Agriculture and Animal Husbandry 17(87) :550 -554. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Sebastian, L., Mudgal, V. D., and Nair, P. G. 1970. Comparative efficiency of milk production by Sahiwal cattle and Murrah buffalo. Joumal of Animal Science 30:253256.  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Sharma, C. B., and Mugdal, V. D. 1966. Studies on the lignin and cellulose contents of fedder crops and effect of lignification of cellulose digestion. Indian Journal of Dairy Science 19:100.  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Sidbu, G. S., Kochar, A. S., and Makkar, G. S. 1967. Effect of supplementing Bajra stalks with lucerne and concentrates and their part replacement by urea on the production of volatile fatty acids in the rumen of cows and buffaloes. Journal of Research, Ludhiana 4:104-110.  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Singh, B. K., and Mudgal, V. D. 1967. The comparative utilization of feed nutrients from lucerne hay in buffalo and crossbred zebu heifers. Indian Journal of Dairy Science 20: 142-145.  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Tandon, R. N.' Sharma, D. D., and Mugdal, V. D. 1972. Effect of feeding urea with different levels of energy on the biochemical changes in the rumen of cows and buffaloes. Indian Journal of Animal Science 42: 174-179  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Upadhyaya, R. S., Singh, U. B., and Ranjhan, S. K. 19i3. Digestibilit of nutrients and VFA concentation in zebu cattle and buffalo calves fed on green cowpea and maize. Indian Journal of Animal Science 43 :5 83-s 88.  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Verma, M. L., Sidhu, G. S., and Kochar, A. S. 1968. Effect of frequency on the production of VFA in the rumen by zebu cattle and buffalo. Journal of Research, Ludhiana 5(3) :1 -6.  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Verma, M. L., Singh, N., Sidhu, G. S., Kochar, A. S., and Bhatia, I. S. 1970. The in vitro cellulose digestion and VFA production from some of the common Indian feeds using rumen inocula from Zebu cattle and buffalo. Indian Journal of Dairy Science 23:155 -160. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<B><P ALIGN="CENTER">&lt;&lt;TOC2&gt;&gt; 7 Health</P>
+</B><P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">When compared with other domestic livestock, the water buffalo generally is a healthy animal. This is particularly impressive because most of them live in hot, humid regions that are conducive to disease, and the buffalo is a bovine susceptible to most diseases and parasites that afflict cattle. Although the reasons are not specifically known, the effect of disease on the buffalo and its productivity is often less deleterious than on cattle.  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Antibiotics and vaccines developed for cattle work equally well on buffaloes. As a result, treatments are available for most of the serious diseases of buffaloes, although some are not very effective for either animal.  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The greatest buffalo losses are often among calves. Newborn buffalo calves, like bovine calves, can succumb in large numbers to viruses, bacteria, and poor nutrition. This is largely due to poor management during the calf's frst 2 months of life. For example, as noted previously, villagers in some countries often sell the valuable buffalo milk, thus depriving the calves.  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Buffalo calf losses are often similar to those of the cattle around them, but the animal's proclivity for wallowing exposes calves to waterborne diseases. Further, a young one occasionally drowns when an adult rolls on top of it.  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Reactions to some specific diseases and parasites are discussed below.  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Pasteurellosis- Probably the water buffalo's most serious disease, pasteurellosis, or hemorrhagic septicemia, is caused by the bacterium Pasteurella multocida (P. septica). Buffaloes are more susceptible to it than cattle and die in large numbers where pasteurellosis occurs. A vaccine against pasteurellosis is effective in protecting both buffaloes and cattle; it is cheap and easily made.  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Tuberculosis- Despite some claims to the contrary, the water buffalo is susceptible to the bovine strain of tuberculosis (Alycobacterium bovis). Scattered reports from different parts of India indicate no difference in the incidence of infection between cattle and buffaloes(Information supplied by S. K. Misra, Department of Veterinary Medicine, Punjab Agricultural University, Ludhiana, Punjab, India).  Other strains of mycobacteria have been isolated from feral buffaloes and cattle in northern Australia but seem to have little effect on the animals. Tuberculosis occurs among the buffalo herds of the world only because most are kept under unsanitary conditions(In 1905 buffaloes were introduced to Trinidad because the cattle herds (Zebu and srahman breeds) were infected with tuberculosis and, in those days, it was thought that buffaloes were resistant to the disease. Most were housed in muddy, ill-kept pens and forced to eat sugarcane tops off the ground; consequently, in 1949 over 30 percent of the buffaloes reacted to the tuberculin test. (The cattle herds had 80 percent reactors.) Tuberculosis was eliminated in Trinidad's buffaloes by improving the sanitary conditions: installing concrete floors and mangers and cleaning the pens regularly. This, together with regular tuberculin testing and removal of reactors, led to such a dramatic improvement that buffalo tuberculosis is now virtually unknown. -Information supplied by S. K. Bennett.) </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Brucellosis-Buffaloes and cattle are equally susceptible to brucellosis. Although seldom reported as a problem elsewhere, brucellosis in Venezuela is increasing more rapidly among buffaloes than among cattle. In India the disease is no more prevalent among buffaloes than among cattle.  As many as 57 percent of some Venezuelan herds are infected with the disease. It is a frequent cause of abortion in buffaloes. Serologic procedures and measures developed for the control of the disease in cattle are also effective means of curbing this infection in buffaloes. (Consumption of raw milk or contact with aborted fetuses may cause undulant fever in humans.)  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Mastitis- Among milking buffaloes mastitis is a problem as it is in dairy cows, but to a lesser extent. It is likely to increase, however, as the milk production per individual buffalo is increased. The bacteria that cause mastitis in the buffalo are similar to those in cattle. Treatment and control programs used for cattle are equally effective for buffaloes.  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Other Diseases -Among the epizootic diseases, rinderpest and piroplasmosis seem to affect buffaloes as much as cattle. Foot-and-mouth disease also affects buffaloes, but to a lesser degree than cattle, producing smaller lesions and having a lower incidence. In northern Australia buffaloes deliberately infected with bovine pleuropneumonia bacteria exhibited slight fever, but the disease never appeared. No naturally occurring eases have been reported in buffaloes. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Ticks -Buffaloes are notably resistant, although not immune, to ticks. In a tick-infested area of northern Australia only 2 engorged female ticks were found on 13 adult buffaloes during a 2-year test. Accordingly, healthy buffaloes are not commonly affected by diseases borne by ticks nor are the hides damaged by their bites. Since ticks are rarely found on buffaloes, anaplasmosis, theileriasis, and babesiosis, which are tick-borne, have little effect on buffaloes in the field. (Buffaloes and cattle are equally susceptible, however, if inoculated with East Coast fever, a form of theileriasis.) This is important because tick infestations in cattle are particularly troublesome in the tropics and the pesticides used to control them are becoming ineffective as the ticks develop resistance. The pesticides are also becoming expensive.  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The basis of the buffalo's tick resistance is not known, but wallowing and rubbing may play a role in it; animals kept in experimental concrete pens in Australia have developed heavy tick infestation. (rials carried out on Magnetic Island by R. H. V/harton, Commonwealth Scientiflc and Industrial Research Organisation, Townsville, Queensland, Australia). </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&lt;&lt;I&gt;&gt; p68to69.png Table 6 Some Infections and Parasites of Buffalo</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Screwworm- Larvae of the screwworm fly (Callitroge species), a major pest of livestock in Central and South America and some other tropical areas, do not affect adult water buffalo. In Venezuelan areas where cattle (Zebu type) are severely infested, adult water buffaloes are virtually free of screwworm larvae and the umbilicus of newborn calves seldom if ever becomes infected. ( Information supplied by A. Ferrer). </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The same is true in Papua New Guinea. It is thought that the mud plaster produced by wallowing suffocates the larvae, but in India screwworms do not affect water buffaloes either, and there they wallow in fairly clear water and the farmer usually washes them off. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Roundworm- The heavy losses of young buffalo calves throughout the world are caused, in large measure, by the roundworm Toxocara vitulorum. The calves seem more susceptible than mature animals and they become infected before birth or within 24 hours after birth through the mother's colostrum. The roundworm is the most serious buffalo parasite and in untreated calves the small intestine can get packed with worms to the point of complete occlusion. Although huge numbers of calves die each year, anthelmintic drugs that control roundworms are highly effective and widely available.  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The adult water buffalo appears to have a high degree of resistance to strongyloid nematodes. Being such excellent converters of rough fodders they do not suffer the nutritional deficiency and the resulting liability to these roundworms experienced seasonally by cattle.  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Liver Fluke- During wallowing, water buffaloes can easily become infected with the waterborne infective stages of liver fluke (Fasciola gigantica). Although the number of flukes in a buffalo may be phenomenally high, no clinical signs of the disease are usually evident. It seems likely that the resulting liver damage reduces the growth and the work and milk production of buffaloes more than is generally appreciated.  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Trypanosomiasis- The water buffalo is susceptible to trypanosomiasis and is reportedly more susceptible than cattle to Trypanosoma evansi.Experience with the animal in Africa is limited, but trypanosomiasis may be the reason why Egypt is the only African country that has traditionally employed water buffalo.  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Other Parasites- The wallow and its resulting mud cake seem to protect water buffalo from many biting flies, but the main ectoparasite in Australia and Southeast Asia is the buffalo fly (Siphona spp.). Pediculosis, caused by the sucking louse (Hematopinus tuberculatus), occurs widely among buffalo, and sarcoptic mange (Sarcoptes scabiei var. bubalus) is a serious disease, especially among calves and during dry seasons when wallowing opportunities are restricted. The lung worm Dictyocaulus ririparus thrives in warm, humid areas and sometimes infects buffaloes heavily, although its outward manifestations are rare.  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">Selected Readings</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Barlow, J. N. 1977. Toxicology and safety evaluation of Phosvel to Egyptian water buffalo. Pages 517-522 in: Pesticide Management and Insecticide Resistance, edited by D. L. Watson and A. W. A. Brown. Academic Press, New York, New York, USA.  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Bhowmik, M. K., and Iyer, P. K. R. 1977. Studies on the pathology of chronic lesions in the mammary glands of buffaloes (Bubalus bubalis). 1. Actinomycosis, nocardiosis and lesions simulating tuberculosis. Indian Veterinary Journal 54(5):342-346.  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Bhowmik, M. K., Singh, S. P., and Iyer, P. K. R. 1977. Studies on chronic mastisis in buffaloes (Bubalus bubalis). lndian Journal of Animal Health 16(2) :157-160.  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Cockrill, W. R. 1974. Aspects of disease. In: The Husbandry and Health of the Domestic Buffalo, edited by W. R. Cockrill, Food and Agriculture Organization of the United Nations, Rome, Italy.  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Dhar, S., Bhattacharyulu, Y., and Gautam, O. P. 1973. Susceptibility of Indian water buffalo (Bubalus bubalis) to Theileria annulata infection. Haryana Agricultural University Journal of Research 3(1):27-30.  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Dwivedi, S. K., Mallick, K. P., and Malhotra, M. N. 1979. Babesiosis: clinical cases in Indian water buffaloes. Indian Veterinary Journal 56(4):333-335.  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Griffiths, R. B. 1974. Parasites and parasitic diseases. In: The Husbandry and Health of the Domestic Buffalo, edited by W. R. Cockrill. Food and Agriculture Organization of the United Nations, Rome, Italy.  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Hafez, S. M., and Krauss, H. 1979. Detection of antibodies against some respiratory pathogens in the sera of domestic animals in Egypt. Bulletin of Animal Health and Production in Africa 27(3):209-214.  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Ho, T. M. 1976. Animal disease control program in Republic of China for better animal production. Korean Journal of Animal Science 18(4):317-321.  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Iannelli, D. 1978. Water buffalo (Bubalus bubalis Arnee) allotypes: identification of a multiple allelic system. Animal Blood Groups and Biochemical Genetics 9(2):105113.  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Kapur, M. P., and Singh, R. P. 1977. Diagnosis of mastitis: a comparative study of four indirect tests.Haryana Veterinarian 16(2):69-73.  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Leue, A. 1971. Buffaloes in Nepal. Tierartliche Umschau 26(4):173-178.  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Mohan, R. N. 1968. Diseases and parasites of buffaloes. I. Viral, mycoplasmal, and rickettsial diseases. II. Bacterial and fungal diseases. III. Parasitic and miscellaneous diseases. Veterinary Bulletin 38:567-576, 647-659, 735-756.  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Murthy, D. K., and Sharma, S. K. 1974. Studies on reactivity and immunogenecity of cell-culture rinderpest vaccine in different species of ruminants. Indian Journal of Animal Science 44(6):359-365.  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">San Agustin, F. 1973. Important diseases and parasites of Carabaos. Philippine Journal of Nutrition 26(2):68-79.  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Schneider, C. R., Kitikoon, V., Sornmani, S., and Thiachantra, S. 1975. Mekong schistosomiasis. III. A parasitological survey of domestic water buffalo (Bubalus bubalis) on Khong Island, Laos. Annals of Tropical Medicine and Parasitology 69(2):227-232.  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Sharma, K. N. S., Jain, D. K,, and Noble, D. 1975. Calf mortality in pure and crossbred Zebu cattle and Murrah buffaloes reared artificially from birth. Animal Production 20(2):207-211.  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Sharma, S. K., Banegee, D. P., and Gautam, O. P. 1978. Anaplasma marginale infection in Indian water buffalo (Bubalus bubalis). Indian Journal of Animal Health 17(2): 105-110.  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Shaw, J. J., and Lainson, R. 1972. Trypanosoma vivax in Brazil. Annals of Tropical Medicine and Parasitology 66(1):25-32.  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Shukla, R. R., and Singh, G. 1972. Studies on tuberculosis amongst Indian buffaloes. Indian Veterinary Journal 49(2):119-123.  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Soni, J. L. 1978. Suitability of different serological tests for diagnosis of brucellosis in buffaloes (Bubalus bubalis). Indian Journal of Animal Science 48(12) :873-881. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Tantawi, H. H., Fayed, A. A., Shalaby, M. A., and Skalinsky, E. I. 1979. Isolation, cultivation and characterization of poxviruses from Egyptian water buffaloes .Journal of the Egyptian Veterinary Medical Association 37(4):15-23.  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Thomson, D. 1977. Diseases of water buffalo in the Northern Territory of Australia. Australian Veterinary Practioner 7(1):50-52.  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Young, P. L. 1979. Infection of water buffalo (Bubalus bubalis) with bovine ephemeral fever virus. Australian Veterinary Journal 55(7):349-350. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<B><P ALIGN="CENTER">&lt;&lt;TOC2&gt;&gt; 8 Reproduction</P>
+</B><P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The water buffalo has a reputation for being a sluggish breeder, but the average animal is so poorly fed that its reproductive performance is unrepresentative of its capabilities. Without reasonable nutrition the animals cannot reach puberty as early in life or reproduce as regularly as their physiology or genetic capability would normally allow.  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Actually, adequately nourished buffaloes reach puberty at about the same age as cattle, as early as 18 months of age in buffalo bulls. In northern Australia Swamp females have conceived even as early as 14 months of age and feral buffaloes routinely conceive at 16 months of age. In the herd at Punjab Agricultural University in Ludhiana, India, 11 River buffalo heifers showed estrus at ages less than 18.5 months and a few came into heat when less than 15 months old. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The water buffalo also can calve at an age comparable to that of cattle. At the Ain Shams University in Egypt a well-fed Egyptian buffalo herd of several hundred animals has an average age at first calving of 27 months, 22 days(Information supplied by M. El Ashry. Because of nutritional uncertainties, El Ashry and his colleagues believe that body weight is a better indicator of sexual preparedness than age is. These researchers at Ain Shams University recommend mating heifers when they weigh 365 kg no matter what their age. Research at Punjab Agricultural University shows that buffalo heifers can be bred when they weigh over 270 kg and manifest estrus).Most animals in the Punjab Agricultural University River buffalo herd calved before 35 months, one at 28.3 months.! In one Venezuelan herd almost all heifers 20-24 months old were pregnant; virtually all calved before age 38 months, most by 30 months, and one at age 23 months. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">In trials in Queensland, Australia, and in Papua New Guinea buffaloes produced more calves over a 3-year period than the cattle tested with them. In the hot, humid Sepik Plains in northern Papua New Guinea it was noticed that female buffaloes (Swamp breed) came into estrus even while they were losing weight because of inadequate nutrition, whereas cattle did not. Under these stressful conditions the buffalo calves also reached sexual maturity earlier and the buffaloes had a higher calving percentage and a shorter calving interval because they came back into estrus more quickly than cattle(Information supplied by J. Schottler. The age at first calving of more than 60 nutritionally poor buffaloes was 38 months in one herd and 45 months for Brahman cross cattle) . Similar observations have been made in Florida, Trinidad, the Brazilian Amazon, Venezuela, and elsewhere. Although these are exceptions to the normal observations in Asia, where buffaloes seem to breed more slowly than cattle, they do demonstrate the buffalo's potential for improved breeding.  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Estrus in buffalo cows usually lasts about 24 hours, but duration varies and may range from 11 to 72 hours. It occurs on an average 21-day cycle. Determination of when a cow is in estrus is difficult because often the animal shows few outward signs of "heat." This increases the chances of missing a cycle, especially for artificial insemination. Unclean surroundings, poor nutrition, and poor management, cause a high death rate among calves; this also contributes to the buffalo's often low reproductive rate.  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">In many areas, calving is seasonal. This seems to be largely due to changes in nutrition. It may also be caused by heat stress, in either males or females, which results in a low breeding rate during the hot season. However, when buffalo cows are well fed, they come into estrus and will breed in any season.  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Many matings take place at night and are therefore unobserved. In one set of pregnancy diagnoses in northern Australia, the buffalo's conception rate (81 percent) was higher than that of the Brahman crossbreeds (70 percent) they were with. In India, artificial insemination of water buffaloes began in the late 1950s. Deep-frozen semen is now available and its use is spreading. Overall conception rates of 70-80 percent are obtained. It is estimated that some 100,000 buffaloes are now being artificially inseminated.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The water buffalo's gestation period is about one month longer and is more variable than that of cattle. Whereas cattle give birth after about 280 days (Angus, 279, Holstein, 279-280, Brown Swiss, 286), buffaloes take 300334 days (average 310) or roughly 10 months and 10 days (differences between breeds are unknown). In Punjab, India, River buffaloes have been observed to come into estrus as early as 40 days after calving. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Nonetheless, only under uncommon circumstances can a buffalo cow produce a calf each year. In one herd of 800 cows in Venezuela the average female buffalo over age 4 produces 2 calves every 3 years. In response to a recent questionnaire, the majority of Indonesian farmers estimated that the calving rate was between 3 and 4 calves in 5 years. A few claimed a calf a year, some only 1 or 2 calves In 5 years. In Florida it has been noted that some buffalo cows having just calved became pregnant more quickly than cattle, so that a calf may indeed be produced each year. Regular yearly breeding has been noted also in northern Australia.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The incidence of abortion, dystocia, retained placenta, and other parturition problems in buffaloes is similar to that in cattle. Twinning is very rare; probably no more than 0.01 percent of buffalo pregnancies produce twins.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Preliminary results in northern Australia indicate that weaning can be carried out as late as 12 months of age without any effect on conception time of the buffalo dam.  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">Selected Readings</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Bhattacharya, P. 1974. Reproduction. In: The Husbandry and Health of the Domestic Buffalo, edited by W. R. Cockrill. Food and Agriculture Organization of the United Nations, Rome, Italy.  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Chauhan, F. S., Singh, N., and Singh, M. 1977. Involution of uterus and cervix in buffaloes. Indian Journal of Dairy Science 30(4):286-291.  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Eusibio, A. N. 1975. Breeding, management and feeding practices of buffaloes in the Philippines. In: The Asiatic Water Buffalo. Proceedings of an International Symposium held at Khon Kaen, Thailand, March 31-April 6, 1975. Food and Fertilizer Technology Center, Taipei, Taiwan.  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">FAO Animal Production and Health Paper. 1979. Buffalo Reproduction and Artificial Insemination. Proceedings of the Seminar Sponsored by FAO/SIDA/Government of India, held at National Dairy Research Institute, Karnal, 132001-India, December 4-15, 1978. Food and Agriculture Organization of the United Nations, Rome, Italy.  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Ghanem, Y. S. 1955a. Environmental causes of variation in the length of gestation of buffaloes. Indian Journal of Veterinary Science 25 :301-311.  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Ghanem, Y. S. 1955b. Genetic causes of variation in the length of gestation of buffaloes. Indian Journal of Veterinary Science 25:307-311.  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Health, E., and Gupta, R. 1976. Ultrastructure of water buffalo (Bos bubalis) spermatozoa. Zentralblatt fuer Veterinaerrnedizin 23(2):106-120.  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Liu, C. H. 1978. The preliminary results of crossbreeding of buffaloes in China. Research Institute for Animal Science of Kwangsi, People's Republic of China.  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Matharoo, J. S., and Singh, M. 1980. Revivability of buffalo spermatozoa after deepfreezing the semen using various extenders. Zentralblatt fuer Veterinaermedizin 27(5): 385-391.  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Rao, A. V. N., Murthy, T. S., and Dutt, K. L. 1979. Effect of lunar cyclicity on oestrus rhythmicity in the Indian water buffalo. Livestock Advisor 4(7):29-30.  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Rawal, C. V. S. 1978. A study on correlations of weight of pituitary gland and reproductive organs in males of Indian water buffalo. Indian Journal of Heredity 10(3):11-12.  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Robinson, D. W. 1977. Livestock in Indonesia. Research Report No. 1. Centre for Animal Research and Development, Bogor, Indonesia. (In English and Indonesian.)  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Roy, A. 1974. Observations on the physiology of reproduction. In: The Husbandry and Health of the Domestic Buffalo, edited by W. R. CockrilL Food and Agriculture Organization of the United Nations, Rome, Italy.  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Sahai, R., and Singhal, R. A. 1977. The sex chromatin profile of water buffaloes of Murrah breed. Indian Journal of Animal &amp;Science 11(2):63-67.  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Sharma, A. 1978. Studies on the process of spermatogenesis and epididymal sperm reserve in water buffalo (Bubalus bubalis). Thesis Abstracts, Haryana Agricultural University 4(4):331.  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Singh, M., Matharoo, J. S., and Chauhan, F. S. 1980. Preliminary fertility results with frozen buffalo semen in Tris extender. Theriogenology 13(3):191-194.  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Singh, N., Chauhan, F. S., and Singh, M. 1979. Postpartum ovarian activity and fertility in buffaloes. Indian Journal of Dairy Sefence 32(2): 134-139.  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Sunkaporn Ratanadilok Na Puket. 1975. The improvement of buffalo production through breeding and management under Thailand conditions. In: Asiatic Water Buffalo. Proceedings of an International Symposium held at Khon Kaen, Thailand, March 31-April 6, 1975. Food and Fertilizer Technology Center, Taipei, Taiwan.  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Takkar, P. O., Chauhan, F. S., Tiwana, M. S., and Singh, M. 1979. Breeding behaviour of buffalo cows. Indian Veterinary Journal 56: 168-172.  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Toelihere, M. R. 1975. Physiology of reproduction and artificial insemination of water buffaloes. In: The Asiatic Water Buffalo. Proceedings of an International Symposium held at Khon Kaen, Thailand, March 31-April 6, 1975. Food and Fertilizer Technology Center, Taipei, Taiwan.  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Tulloch, D. G. 1968. Incidence of calving and birth weights of domesticated buffalo in the Northern Territory. Proceedings of the Australian Society for Animal Productlon 7: 144-147.  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Tulloch, D. G. 1979. The water buffalo in Australia: reproductive and parent-offspring behaviour of buffalo. Australian Wildlife Research 6:265-287. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<B><P ALIGN="CENTER">&lt;&lt;TOC2&gt;&gt; 9 Management</P>
+</B><P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Water buffaloes are adaptable and are managed in many ways. In general, they are raised like cattle. But in some operations they must be handled differently. This chapter highlights these differences.  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Millions of water buffaloes are managed in "backyards" in Asia. They exist on the resources of small holdings. Management and expenditures are minimal. Care of the family buffalo is usually entrusted to children, old people, or women not engaged in other farm duties; the buffalo allows them to be useful and productive.  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The buffalo fits the resources available on the farm, but it is also an urban animal. Thousands of herds of 2-20 buffaloes may be found in the cities and towns of India, Pakistan, and Egypt-all fed, managed, and milked in the streets.  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">In addition, the buffalo has important qualities as a feedlot animal; it can be herded and handled with relative ease because of its placid nature. The Anand Cooperative in India's Gujarat State, which daily contributes thousands of gallons of milk to Operation Flood (the world's largest nutrition project), involves more than 150,000 Surti buffaloes that are fed, managed, and milked by their owners under feedlot-like conditions in their villages. Many of Italy's 100,000 buffaloes are maintained under similar conditions.  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Water buffaloes can also be managed on rangelands. In Brazil, Venezuela, Trinidad, the United States, Australia, Papua New Guinea, Malaysia, Indonesia, the Philippines, and elsewhere there is rising interest in raising buffalo beef on the range. The production practices for raising them are similar to those used for range cattle.  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Water buffaloes in the humid tropics must be able to cool off. Shade trees are desirable, and although a wallow is not essential, it is probably the most effective way the animal has of coping with heat. Alternatively, water showers may be provided to wet down the animals 3-5 times during the hottest part of the day.  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Water buffaloes are intelligent animals. Young ones learn patterns quickly and often are reluctant to change their habits. Feral animals-even those born in the wild-tame down after a week or two in a fenced enclosure to the point where many can be handled, haltered, and hand fed(In one example, loo feral buffalo were captured in Northern Territory, Australia. With in 14 days all the animals-males and females, young and old-had become docile and amenable to handling. -Information supplied by D. G. Tulloch) . Among feral herds of northern Australia it has been observed that buffaloes have clans and families. A female calf seems to remain with its family and mother for many years (possibly for life). A male calf stays until it is about 2 years old, when it is driven from the group by an adult bull. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">It has also been noted in northern Australia that free-ranging buffaloes instinctively select clean water areas to drink from, other areas to wallow in, and still others as "toilet areas." In addition, China's buffaloes reportedly are being "toilet trained" to defecate only at specific sites to avoid contaminating waterways with schistosome eggs.  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Another interesting observation from northern Australia is that most buffalo dams readily adopt a calf that has been orphaned by the death of its mother. In fact, females will allow several calves to nurse (including calves of other mothers and sometimes even adults).  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Buffaloes are also self-reliant. For several months each year in Vietnam and Malaysia, for instance, they are turned loose in the forests to fend for themselves.  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Provision of adequate fencing is one of the great problems of buffalo management. The  animals have strong survival instincts and if feed runs short, such as in the dry season,  they will break through fences that would deter cattle who would remain and starve. They  will also break through fences if their family unit is split up. Barriers must be stronger  than those used for cattle and the wires closer together and lower to the ground because  buffaloes lift fences up with their horns rather than trample them down. In northern  Australia, Papua New Guinea, and Costa Rica it has been found that buffaloes are  particularly sensitive to electric fences (a single wire is all that is needed), and in Brazil a  special suspension fence has been devised(Moura Carvalho et al., 1979). Both of these  seem to be cheap and efficient answers to the fencing problem.  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Water buffaloes are easily handled from horseback and easily worked through a corral.  Actually, because of their docility they can be mustered on foot, even on ranges where  cattle require horses. Unless they come from different areas they tend to herd together  and can be mustered like sheep.  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">One of the major management adjustments to be made by cattlemen is understanding  and capitalizing on the buffalo's placid nature. Buffaloes are naturally timid and startle  easily; they must be handled quietly and calmly. Rough handling, wild riding, and loud  shouting make handling them more difficult and training them much harder.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Village buffaloes are led and managed by a ring threaded through the septum between  the nostrils. The technique is frequently applied crudely and cruelly, often resulting in a  ripped septum.  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The identification of individual buffaloes is difficult. Fire brands do not remain legible on  the skin for long. Cryobranding (freeze branding) is more durable. Most types of ear tags  are not very successful; the numbers wear off and mud covers up the tag's color. In  northern Australia ear tattooing has been the most successful identification technique,  with tattoos remaining legible for at least 8 years(Between 1958 and 1962 hundreds of  Australian buffalo were shipped on the hoof to the meat markets in Hong Kong without  trouble, despite crowded shipboard conditions and the long sea voyage. But in 1962 one  roughly treated bull went berserk in Hong Kong and killed a handler, and the Hong Kong  authorities stopped the trade as a result, although the problem was really one of  mismanagement. Buffalo have since been sent by air from Australia to Venezuela,  Nigeria, and Papua New Guinea and by barge to Papua New Guinea. No handling  problems have been experienced en route).  When they pasture together, cattle and  buffaloes coexist satisfactorily. They segregate themselves into their own groups and do  not interfere with one another. The buffaloes, however, usually dominate the cattle and  tend to monopolize the areas with the best feed supply.  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Feed troughs and mineral boxes used for cattle are suitable for buffaloes, but chutes and  crushes must be widened to accommodate the buffalo's broader body and, when  necessary, the Swamp buffalo's greater horn spread. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Water buffaloes are powerful  swimmers. In Brazil they have been known to escape by swimming down the Amazon River. An unusual management difficulty is caused by piranha in the rivers and swamps of Venezuela. In one herd of 100 heifer buffaloes, 40 have lost all or part of a teat to these voracious fish.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The horns of water buffaloes are seldom removed or prevented from growing, a  testament to the animal's docility. (When questioned, one Thai villager said that he wouldn't  allow it because it would be a disgrace to the buffalo.) However, the animals can be  dehorned as calves in the same manner as cattle. They are then easier to handle In  chutes and cause less accidental injury to neighboring animals, handlers, walls, and  trees.  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">Selected Readings</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Benya, E. G. 1972. Cattle and buffalo production in Vietnam. Dairy Science Mimeo  Report, Florida Agricultural Experiment Station, Gainesville, Florida, USA.  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Cockrill, W. R. 1974. Management, conservation and use. In: The Husbandry and Health  of the Domestic Buffalo, edited by W. R. Cockrill. Food and Agriculture Organization of  the United Nations, Rome, Italy.  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">De Boer, A. J. 1976. A further report on the Taiwan livestock industry: general policy  conclusions and further research needs. Journal of Agricultural Economics 19:116129.  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Lin, C. H. 1975. The breeding, management and feeding of water buffaloes in Taiwan. In:  The Asiatic Water Buffalo. Proceedings of an International Symposium held at Khon  Kaen, Thailand, March 31-April 6, 1975. Food and Fertilizer Technology Center, Taipei,  Taiwan.  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">McDowell, R. E. 1972. Improvement of Livestock Production in Warm Climates. W. H.  Freeman and Company, San Francisco, California, USA.  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Moura Carvalho, L. O. D., LouIenco, J. B., Nascimento, C. N. B., and Costa, N. A. 1979.  Cerca de Contencao pare Bubalinos e Bovinos. Comunicado Tecnico No. 28,  Agricultural Research Center for the Humid Tropics (CPATU), Belem, Para, Brazil.  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Rufener, W. H. 1975. Management and productive performance of water buffalo in  northeast Thailand. In: The Asiatic TVater Buffalo. Proceedings of an International  Symposium held at Khon Kaen, Thailand, March 31-April 6, 1975. Food and Fertilizer  Technology Center, Taipei, Taiwan.  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Tulloch, D. G. 1978. The water buffalo in Australia: grouping and home range. Australian  Wildlife Research 5:327-354.  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Tulloch, D. G. 1979. Redomestication of water buffaloes in the Northern Territory of  Australia. Animal Regulation Studies 2(1):5-20.  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<B><P ALIGN="CENTER">&lt;&lt;TOC2&gt;&gt; 10 Environmental Effects</P>
+</B><P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The grazing and wallowing habits of water buffaloes may have unexpected consequences when the animals are introduced to new, perhaps fragile environments. The presence of several thousand feral buffaloes on the coastal plains of northern Australia, for example, has become a very emotional issue among Australian environmentalists, some of whom foretell the complete destruction of the environment if the uncontrolled feral herds are not destroyed( It is not at all clear, however, that the buffaloes (which have existed in the area for 150 years) are causing the observed environmental degradation. Other possibilities include: fire, climatic stress, overgrazing, and a variety of farming, hunting, and other human activities, especially the use of four-wheel-drive vehicles. Thousands of wild pigs also share the area, along with crayfish that burrow into and weaken the levees that keep out the sea, something for which the buffaloes have been blamed). </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">Soil Compaction</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Water buffaloes have larger hooves than cattle of comparable size and thus they compact the soil less. But buffaloes often live in damp, boggy areas where their feet may compact soft soils. Also, buffaloes are creatures of habit and, when able, they set up fixed points for drinking, feeding, defecating, wallowing, and sleeping. Between the points they wear sharply defined trails in the vegetation and soil.  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">Wallowing</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Possibly the water buffalo's greatest environmental limitation is its propensity to build wallows. In hot climates every buffalo will wallow at some time during the heat of the day if water is available. When they can, buffaloes will make their own wallows, enlarging a mud puddle by rolling in it or even using their heads to flip water out of a drinking trough and muddying the ground nearby.  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The pasture in the immediate area of the wallow is usually damaged by trampling and waterholes may become fouled, but buffaloes return to the same wallow day after day and do not build new ones indiscriminately. Thus, the muddied area is not a large proportion of the location in which they graze unless a large number of animals are confined in a small space(At Gainesville, Florida (possibly because of its subtropical but not hot climate), a herd of 52 buffaloes concentrated in a one-hectare field did not attempt to build a wallow at ale -Information supplied by H. Popenoe.) . In addition, man-made wallows can be dug at safe sites and the animals will use them. The problem of wallowing is therefore not generally a serious one.  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">Damage to Waterways</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Because buffaloes often live near and enter water freely, they may cause erosion in ditches, river banks, canals, and levees. Also, their wallowing muddies the water, which may adversely affect some fish species and reduce the growth of algae. Buffaloes commonly urinate and defecate in the water, possibly creating a pollution hazard, although in most situations this contamination is likely to be minor.  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The presence of this herbivore in natural waterways may reduce the number of water plants. Some plants are trampled, some eaten, and some underwater species are suppressed because the muddied water transmits less light. This (and several other of the buffalo's environmental effects) can be turned to advantage (see picture page 85) when, as often occurs, aquatic plants grow out of control and become obnoxious weeds.  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">Damage to Pastures</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Water buffaloes have very strong jaws, and when forage is sparse they graze it close to the ground; this overgrazing can destroy a pasture. In addition, they eat virtually all available plant material (including many species that cattle shun), so that a densely stocked pasture can become completely defoliated. In northern Australia it has been found that, with time, buffaloes become accustomed to a given pasture, and unless fences are strong they will instinctively return to it until the forage has been depleted.  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The buffalo's inclination to eat many plants can be used to improve the environment and suppress growth of coarse weedy species of plants. On the Sepik Plains in Papua New Guinea buffaloes are being used to graze and suppress sedges (Cyperus species), as a result, the more desirable Paspalum species are beginning to appear. At Mount Bundy in northern Australia native pastures are being improved on a commercial scale by overstocking them with buffaloes. The animals reduce or completely eliminate spear grass and other weeds-even those with thorns-and thus foster the survival and growth of introduced forage legumes such as stylo (Stylosanthes guianensis). In Sri Lanka buffaloes have been used to graze out the vigorous tropical grass Imperata cylindrica.  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">Damage to Trees</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Buffaloes instinctively rub against trees (and walls and fences), eagerly browse leaves, and sometimes nibble bark, so they damage trees more so than cattle. In northern Australia it has been noted that each "family herd" of feral buffaloes selects one or two trees for rubbing against so that the rubbing damage is confined to them. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">Selected Readings</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Rajapske, G., 1950. Death of illuk. Ceylon Coconut Quarterly, 1:7-9.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Tulloch, D. G. 1969. Home range in feral water buffalo. Australian Journal of Zoology 17:143-152.  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Tulloch, D. G. 1970. Seasonal movement and distribution of the sexes in the water buffaloes in the Northern Territory. Australian Journal of Zoology 18:399-414.  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Tulloch, D. G. 1975. Buffalo in the northern swamplands. Proceedings III of the World Conference on Animal Production. Theme 1, Paper 7.  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Tulloch, D. G. 1977. Some aspects of the ecology of the water buffalo in the Northern Territory. In: The Australian buffalo-a collection of papers, edited by B. D. Ford and D. G. Tulloch. Technical Bulletin No. 18, Department of the Northern Territory, Animal Industry and Agriculture Branch, Australian Government Printing Service, Canberra, Australia. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<B><P ALIGN="CENTER">&lt;&lt;TOC2&gt;&gt; 11 Recommendations and Research Needs  </P>
+</B><P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">This report has outlined the water buffalo's apparent merits, but most of the statements made about the animal are based on empirical observations. Many of its most exciting and potentially valuable features have not been subjected to the careful scrutiny needed to confirm their validity.  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Despite the fact that there are 130 million or more water buffalo in the world, research on the animal is scanty and limited to only a few situations and sites. Quantitative information (especially for the various breeds), tests, trials, and comparison studies are needed.  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The research to be done on the water buffalo offers scientific challenges that can be undertaken in laboratories and experiment stations in most parts of the world and in many disciplines: breeding, physiology, microbiology, veterinary science, nutrition, food science, dairy science, and other fields. Water buffalo research is an area worthy of financial support by philanthropic institutions and international development agencies concerned with problems of food and resource shortages. The dominant role of the buffalo in the rural economies of Egypt and Asian countries offers the opportunity for buffalo research that can bring improvements quickly and easily to the rural poor. For other countries the water buffalo is an untapped resource, and they should test its productivity on native pasturelands, marshy lowlands, hot and humid areas where cattle do not thrive, and on areas prone to cattle diseases and parasites that are difficult to control.  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Specific recommendations follow.  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">Comparison with Cattle</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Animal scientists worldwide should undertake trials to compare growth rate, feeding, nutrition, breeding, and other aspects of buffalo and cattle performance.  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Cattle and water buffaloes are obviously different animals. Each has its own limitations and advantages, and each deserves to be studied in its own right. Perhaps the quickest way for animal scientists to experience for themselves the merits of the water buffalo is to conduct their own comparative trials with buffaloes and cattle in their areas. The results will provide local guidance and will help extend recognition of the buffalo's value, especially under difficult conditions where it may exceed cattle in productivity and profitability.  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">Germ Plasm Preservation</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Urgent action is needed, especially in Southeast Asia, to preserve and protect outstanding buffalo specimens.  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">In some countries (Thailand, Malaysia, and Indonesia, for example) buffalo populations are decreasing dramatically. High demands for meat are causing slaughter at younger and younger ages. Much of the meat is exported to restaurants and markets in Singapore and Hong Kong. Unfortunately, the largest and quickest growing animals are often selected for slaughter. This results in the loss of a major genetic resource, which is compounded by the practice of castrating the largest males to make them more tractable as work animals. Ten years ago in Thailand it was common to find buffalo weighing 1,000 kg; now it is hard to find 750-kg specimens. A similar situation exists in the Philippines where there is no dearth of good breeding stock, but butchers are paying such high prices that farmers are selling even quality animals for slaughter. In northern Australia, where some of the bulls weigh almost 1,200 kg, the largest animals are being shot for meat, hides, pet food, or sportsmen's trophies,  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">A large number of high-yielding buffaloes are taken each year to big cities in India (for example, Bombay, Calcutta, Madras) for milking. At the end of lactation many are returned to the villages, but many others are slaughtered, rather than being fed and retired. This creates a huge loss of valuable germ plasm. In many locations most of the largest animals have already been lost. Only urgent action will protect those remaining.  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">International Shipment</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Buffalo quarantine stations should be organized in "disease-free" areas to develop buffalo germ plasm pools for international exchange.  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The importation of buffaloes presents difficulties for any government, researcher, or farmer wishing to obtain the animals for the first time or for breeding purposes. Quarantine laws make it extremely difficult and expensive to exchange genetic resources.  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Australia is one of the few nations where there are large numbers of water buffalo in an area free of the major animal diseases. Papua New Guinea, </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Nigeria, Colombia, Venezuela, and other nations have taken advantage of this and have  imported Australian buffaloes. But Australian herds are all Swamp buffaloes(The island  of Guam is also a safe source of Swamp animals, although the feral herds there are  depleted, only 300 or 400 animals were left on Guam in 1978) and so breeding centers  should be set up also (in Sri Lanka and Italy perhaps) where importers can obtain  River-type (including Mediterranean) buffaloes.  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Genetic Improvement</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Worldwide efforts should be made to select superior buffalo bulls and cows for breeding.  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Performance testing, leading to the mass selection of superior animals, deserves high  priority. Virtually all buffalo breeding is haphazard and unplanned. Village animals graze  together and matings are usually not con" trolled, observed, or recorded. Thus, the full  genetic potential of the water buffalo is not being realized.  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">A massive selection program is needed to bring about genetic progress. For each breed,  bulls and cows with the potential for improving production of meat and milk and  increasing draft power should be identified and used for breed improvement. However,  the wide variations between the characteristics of individual animals may make  exceptional genetic advances difficult to achieve quickly.  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Important traits for culling and selection include behavior, temperament, reproduction  rate, easy milk letdown, average daily gain in weight or weight at a given age, carcass  quality (for example, large hindquarters), and milk production, as well as strength and  endurance for work.  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Crossbreeding of Swamp and River buffaloes is a potentially important route to genetic  improvement. The progeny reportedly show hybrid vigor (heterosis) in milking ability,  fertility, meat production, and working ability. Infusing genes for high milk production into  the Swamp buffalo, now used mainly for meat and work, creates the potential for a  triple-purpose animal.  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The use of artificial insemination and deep-frozen semen should be a major help in  upgrading the buffalo. Moreover, the transport of live embryos (rather than neonatal  animals) for implantation in the uterus of surrogate mothers could be important for water  buffalo. It seems unlikely, however, that buffalo embryos can be implanted in cattle.  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Most genetic selections should be made in Asia where 97 percent of the world's water  buffaloes are located. The improvements will depend on how accurately bulls can be  identified, selected, and mated. Performance and  progeny testing is sorely needed at research stations as well as "on the farm." Governments should also institute bull-loan or artificial-insemination programs as a means for upgrading the village herds.  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">Comparison of Breeds</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The relative merits of the various buffalo breeds should be determined,  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Little or no information is available on the comparative performance of the different buffalo breeds in various environments, especially the 17 or so River breeds in the Subcontinent and the Egyptian and Mediterranean breeds. Comparison trials of the breeds and breed-crosses are needed in a wide range of climates from the humid tropical to the temperate. In addition, the cytogenetic, immunogenetic, and inheritance relationships of breeds should be clarified.  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The panel encourages countries such as India and Pakistan that have a number of buffalo breeds (for example, Murrah, Surti, Jafarabadi, Mehsana, and Nili/Ravi) to set up experimental farms for scientific reproduction of superior specimens. Substantial research benefits as well as profitable economic returns from using and exporting some of them would be realized.  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">Meat and Milk Research</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Research and demonstration is needed to foster the widespread consumption of buffalo meat and milk.  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Buffalo milk, cheese, and other dairy products are considered outstanding foods in all locations where they are produced. Taste tests so far have indicated that buffalo meat is similar or slightly superior to beef produced under the same conditions.  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">A specific need is to feed the male calves and use them for meat. Many are now slaughtered at a young age and light weight. Research that provides either a partial or complete milk substitute for feeding calves would have a major impact on meat supplies and farmer income. Diets being developed for calves in Egypt incorporate such ingredients as whey, soybean meal, corn flour (corn starch), and yeast.  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Other research topics include:  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">· The effect of climate, thermoregulation, and wallowing on meat and milk production;  </P>
+<P ALIGN="JUSTIFY">· The meat characteristics of each of the breeds and the differences between them,  </P>
+<P ALIGN="JUSTIFY">· Milk production and quality for each of the breeds;  </P>
+<P ALIGN="JUSTIFY">· Adapting buffaloes to machine milking by genetic selection or by designing new milking  machinery;  </P>
+<P ALIGN="JUSTIFY">· Developing new or improved milk products (such as yogurt, cottage cheese, and hard  cheese); and  </P>
+<P ALIGN="JUSTIFY">· Banking genetically superior germ plasm for later use.  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">Work Research</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The panel recommends research on new harnesses to replace the omnipresent yoke.  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">As already noted, the wooden yoke, which has not changed in 1,500 years or more, is an  inefficient harness. Research is needed to adapt horse collars, hames, breast straps,  and other devices for the buffalo. Because much of the farm power in Asia comes from  buffaloes, the impact of improved harness could be dramatic, widespread, and of  enormous value to millions of small farmers there. If the experiments in Thailand  described earlier are an indication, the farm power in Asia could be increased by 25  percent overnight with the adoption of an improved harness. The buffalo will continue to  be the small farmer's "tractor," so the benefits from improved harnesses are likely to  continue for a long time.  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">There are 13 million buffalo and bullock carts in India and 20 million Indians are engaged  in the business of road haulage. Application of appropriate technology would eliminate  the archaic wooden wheels, axles, and heavy carts and substitute lightweight carts,  perhaps with such features as metal wheels, pneumatic tires, ball bearings, and fixed  axles. With such improvements, loads might be increased and hauled over longer  distances at greater speed and with less work.  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">Trials in New Areas</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Testing of water buffalo production is needed in many areas where the animal is not  known.  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">A seemingly adaptable animal, the water buffalo should be productive throughout the  earth's warm temperate, subtropical, and tropical zones. Different breeds may adapt  differently to extremes of heat, humidity, and cold, and this needs further study.  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The United States, the Mediterranean Basin of Europe, and some of the more temperate  European areas like southern England are worth considering for water buffalo trials. In the Southern Hemisphere River buffaloes are already found as far south as 25° latitude in Brazil's Sao Paulo State (where large herds are raised); an experimental herd of Swamp buffaloes has performed outstandingly in Brisbane, Australia (27°S); and there are a few Swamp buffalo in South Australia and Victoria (35°S or more). There is good reason to believe that water buffaloes may be productive in all of the states in Australia, New Zealand's North Island, South Africa, Argentina, and other warm temperate areas of the Southern Hemisphere.  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The biggest void in the water buffalo map is virtually the entire continent of Africa. It seems a paradox that the buffalo-Egypt's most important domestic animal-is not farmed commercially in any other African country. Experimental herds have been introduced to Nigeria, Uganda, Mozambique, Tanzania, and other countries in the past, and the initial success of three of them is described in Appendix A.  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The water buffalo, with its tolerance for heat, disease, poor-quality feed, and mismanagement, appears to have outstanding promise for African nations such as Sudan, Tunisia, Morocco, Senegal, and The Gambia as well as all nations south of the Sahara (Nambia perhaps being an exception).  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">More specific aspects of environmental tolerance deserving research attention are:  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">· The physiology of the buffalo's response to heat, cold, humidity, and other environmental factors;  </P>
+<P ALIGN="JUSTIFY">· The effect of climate on growth, reproduction, milk production, health, respiration rate, behavior, and carcass quality; and  </P>
+<P ALIGN="JUSTIFY">· Measurement of the calorific efficiency and chemical composition of all breeds of buffaloes and cattle to determine the environments best suited to each breed.  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">Nutrition Research</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Despite observations of the buffalo's ability to utilize poor quality forage, research is needed to learn how the animal does it.  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">This research should:  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">· Establish the buffalo's nutrient requirements by breed, sex, age, and weight for maintenance, growth, reproduction, lactation, and work;  </P>
+<P ALIGN="JUSTIFY">· Determine voluntary forage consumption and the nutrient utilization of different forages in various stages of maturity;  </P>
+<P ALIGN="JUSTIFY">· Examine rumen microbiology and fermentation, the rate of digestion, production, and absorption of volatile fatty acids produced in the rumen, and utilization of energy, nitrogen, vitamins, and minerals; </P>
+<P ALIGN="JUSTIFY">· Develop milk replacements for early~weaned calves;  </P>
+<P ALIGN="JUSTIFY">· Observe the current village-level feeding of low~uality forages to learn their nutrient requirements, nutrient deficiency diseases, and nutrient supplementation needed;  </P>
+<P ALIGN="JUSTIFY">· Study the utilization of concentrated, high-energy feeds (especially byproduct feeds) to determine the upper limits of buffalo growth and productivity (milk, meat, and work) and carcass quality;  </P>
+<P ALIGN="JUSTIFY">· Compare various breeds of water buffaloes and other ruminants to determine possible differences in nutritional requirements and performance; and  </P>
+<P ALIGN="JUSTIFY">· Apply economic research to production practices, including night feeding of cut forage and the use of improved pastures.  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">Management</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Research to improve management practices could benefit small farmers, ranchers, and feedlot feeders alike.  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Little is known about the farm management factors that influence water buffalo productivity. Studies and extension literature for farmers are needed on subjects such as:  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">· Proper fencing;  </P>
+<P ALIGN="JUSTIFY">· Procedures for dehorning and for preventing horn growth in calves;  </P>
+<P ALIGN="JUSTIFY">· Grazing management methods;  </P>
+<P ALIGN="JUSTIFY">· Preservation of forages;  </P>
+<P ALIGN="JUSTIFY">· Methods and effect of castration;  </P>
+<P ALIGN="JUSTIFY">· Methods and effect of spaying;  </P>
+<P ALIGN="JUSTIFY">· Breeding methods;  </P>
+<P ALIGN="JUSTIFY">· Milking methods;  </P>
+<P ALIGN="JUSTIFY">· Artificial insemination, methodology and use;  </P>
+<P ALIGN="JUSTIFY">· Methods of handling animals under grazing conditions or in feedlots;  </P>
+<P ALIGN="JUSTIFY">· Age for weaning under different conditions;  </P>
+<P ALIGN="JUSTIFY">· Mineral and protein supplementation methods;  </P>
+<P ALIGN="JUSTIFY">· Semen freezing;  </P>
+<P ALIGN="JUSTIFY">· Ova transplantation methods;  </P>
+<P ALIGN="JUSTIFY">· Cryobranding and other methods of animal identification;  </P>
+<P ALIGN="JUSTIFY">· Control of internal parasites; and  </P>
+<P ALIGN="JUSTIFY">· Disease prevention and treatments. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">Health</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Research is needed in areas where uncertainties about buffalo diseases are hindering  the animals' use.  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The research should:  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">· Develop control and management practices to prevent specific infections and parasites  for buffalo groups such as calves, yearlings, heifers, pregnant cows, newly calved cows,  and bulls;  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">· Elucidate the factors (genetic, nutritional,management, disease) causing losses of  newly born calves;  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">· Prevent and control the major diseases and parasites of the buffalo: hemorrhagic  septicemia, brucellosis, tuberculosis, foot-and-mouth disease, sarcoptic mange,  fascioliasis, nematode parasites, rinderpest and "rinderpestlike" diseases, nephritis, and  conjunctivitis;  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">· Develop herd-health programs and specific disease-control programs for the various  production systems;  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">· Determine the level of susceptibility to trypanosomiasis, a disease that might mitigate  against introducing the animal widely to Africa; and  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">· Define the buffalo's role in malarial ecology.  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">Reproduction</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Research is needed to improve water buffalo reproduction.  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Research topics should include:  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">· Physiology and deep-freezing of buffalo semen. (Although it is possible to freeze the  buffalo semen now, further improvements are needed to achieve higher conception  rates.)  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">· Incidence of sub-estrus and anestrus. This is fairly high in buffaloes. Work is needed to  determine the factors contributing to this problem and find solutions applicable in the  field. A simple, inexpensive test for the routine diagnosis of estrus is needed. It could  ensure that buffaloes are inseminated at the optimal time and could lead to the possible  synchronizing of estrus in groups of animals as well as the elimination of seasonal  breeding.  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">· Seasonality of breeding. Investigations are needed into seasonal effects on the intensity  and deviation of estrus in buffaloes. Most of the buffaloes in northern India and Pakistan,  for example, calve between July and December, causing scarcity of milk in the summer  season and a flush of production in the winter months (this phenomenon causes serious  marketing problems).  </P>
+<P ALIGN="JUSTIFY">· Low libido and low semen yield in buffalo bulls. Semen yield in buffalo bulls is less than half of the yield from cattle bulls.  </P>
+<P ALIGN="JUSTIFY">· Effect of season and other factors on semen quality.  </P>
+<P ALIGN="JUSTIFY">· Variation in the freezability of semen from different bulls.  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">Dissemination of Information</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The panel recommends that two water buffalo publications be produced.  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">These should be:  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">· An international water buffalo newsletter. It is important to maintain communication among researchers working with the water buffalo in far flung research stations, universities, missions, and villages. Research findings may not be widely shared if technical animal science journals and the one or two national newsletters now available remain the only source of water buffalo information. A newsletter would bring together results from different parts of the world. It would provide rapid exchange of information as well as a forum for informal opinions, observations, and preliminary experimental data that are usually not accepted by journals.  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">· A formal journal of water buffalo research.  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">In addition, other methods for disseminating water buffalo information are to be encouraged. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<B><P ALIGN="CENTER">&lt;&lt;TOC2&gt;&gt; Appendixes</P>
+</B><P ALIGN="JUSTIFY"></P>
+<B><P>&lt;&lt;TOC3&gt;&gt; Appendix A</P>
+</B><P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Water Buffalo in Africa</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">For the water buffalo, Africa is the unknown continent. Apart from Egypt, where the  "gamoosa" is a major livestock resource, there have been few recorded experiences  with the animal in Africa. While this may be attributed to disease, chances are it is  because of historical oversight.  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Small herds of buffaloes were recently introduced to Uganda, Tanzania, and Nigeria, but  because there were so few animals no firm conclusions can be drawn. Initial  observations, however, suggest that the water buffalo could have an important future role  in Africa, south of the Sahara. There seems little reason to believe that they won't thrive  there as they have done elsewhere in the tropics.  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The following statements were provided by researchers involved in the enterprises.  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">Uganda</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">"Uganda imported a herd of 12 buffalo cows and one bull in 1969. Grazed on poor-quality  unimproved pasture they received neither supplementary feeding nor any preferential  treatment over the East African zebus kept with them. The herd stayed 7 years at  Entebbe before being moved to another part of the country. They proved to be very  efficient converters of the low protein, high-fber fodder. During this time the herd grew to  40 adult cows and 2 bulls (all other steers were slaughtered). The cows calved every  year. The calves matured at 2 to 21/2 years; the zebu calves took at least 3 years to  mature. Buffalo calves were much heavier than the zebus of comparable age.  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">"The buffalo cows averaged 7 liters of milk per milking. In taste it was preferred to zebu  milk. Also, the quality of the meat after slaughter was much better than that of the zebus.  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">"A major advantage the buffaloes had over the cattle was that they were remarkably  unaffected by diseases endemic to the area. Apart from a few calves that died of  diseases that also killed cattle on the farm at Entebbe, the buffaloes resisted tick-borne  diseases, the biggest killers of cattle in Uganda, and were unaffected by the virulent  strains of East Coast Fever (Theileriosis), Uganda's most serious endemic animal  disease."(Information supplied by G. L. Corry, Director, Veterinary Research Services, Entebbe  Uganda)  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">Nigeria</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Early in 1976, 194 buffaloes aged 6-9 months were imported from the environs of Darwin in Australia's Northern Territory. The animals settled down quite well, and by the end of 1978 the stock population had risen to about 320, the adults weighing about 400 kg with about 80 percent fertility. The animals were in excellent health when an outbreak of streptothricosis occurred early in 1979. Because of the intractable nature of this rare disease of cattle, sheep, and pigs, the apparent spread of the disease in the confined area of the ranch, and the persistence of the organism, the animals were slaughtered(nformation supplied by Dr. J. E. Erhiaganoma, Chief Veterinary Officer, Ministry of Agriculture and Natural Resources, Benin City, Bendel State of Nigeria)..  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">Tanzania</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Tanzania introduced 21 buffalo heifers and 2 buffalo bulls from Egypt in 1968 and 1970. By 1977 the herd had grown to 150 animals. They were kept at the Livestock Production Research Institute at Mpwapwa, a site representative of central Tanzania(Mpwapwa is located at an elevation of 1,000 m. It receives an annual rainfall of 700 mm during a single season between late November and early May. Mean minimum temperatures of 13°C occur in June, and mean maximum temperatures of 26°C occur in November). </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Over a period of 10 years the buffalo were studied and compared with crossbreeds of local Mpwapwa cows and Friesian steers. On average, the buffaloes conceived and calved 4 months earlier than the cattle, their mean calving intervals were about a month shorter, their birth and weaning weights were 1.5 times higher, and their daily weight gain was about double that of the crossbred cattle. The milk yield from the buffaloes was only about two thirds that of the crossbred cattle, but their rnilk's high butterfat content meant that the overall butterfat production was higher in buffaloes.  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Figures reported are shown below:  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&lt;&lt;I&gt;&gt; p98.png Table</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">In a second study (Shoo, R A. 1980. A study of the performance of Egyptian water buffaloes. Student project, Animal Production Department, Faculty of Agriculture, Forestry and Veterinary Medicine, University of Dar-Es-Salaam, Morogoro, Tanzania.), 30 buffaloes and 34 Mpwapwa cattle (not the crossbreeds) were compared(Mpwapwa cattle are a Tanzanian breed with 55 percent Asian, 35 percent African, and 10 percent European blood). The calving intervals were 396 + 126 days for buffaloes and 437 + 109 days for cattle. The buffaloes first conceived at mean ages of 23-25 months (matings occurred in both wet and dry seasons), the cattle at 27-36 months. The buffaloes calved at 35 months, the cattle at 46 months.  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">On farms at Ruvu and Mabuki the calving rate was 63 percent, and the mortality rate 1.2-6.9 percent(Rakha, A. 1980. water buffalo Production, Tanzania. Report of the technical Cooperation Program TCP/URT/9002, Food and Agriculture Organization of United Nations, Rome, Italy). The buffalo's overall milk yields averaged 1,237 kg in 225 days, or 5.5 kg per day.  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The results of the introduction of buffalo to Tanzania are considered "quite encouraging and the future of buffaloes in Tanzania will be bright." (Oloufa, M. M. 1981. The future of water buffaloes in Tanzania Paper presented at the Tanzania Society of Animal Production Eighth Scientific Conference, Arusha, Tanzania May 26-29, 1981.) Future plans call for increasing the herd to about 200 animals with a view toward establishing another buffalo herd. In addition, 5 buffalo sires have been selected in Egypt for shipment to Tanzania.  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<B><P>&lt;&lt;TOC3&gt;&gt; Appendix B</P>
+</B><P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Research Contacts</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">A directory of names in buffalo studies and research is available from the International Buffalo Information Center, Kasetsart University Library, Bangkhen, Bangkok 10900, Thailand.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">Australia</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Animal Industry Branch, Department of Primary Production, P.O. Box 5160, Darwin, Northern Territory 5790 (D.R. Thomson, B. Ford)  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Berrimah Agricultural Research Station, Darwin, Northern Territory</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Coastal Plains Research Station, near Darwin, Northern Territory</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">D. G. Tulloch, P.O. Box 38841, Winnellie 5789, Northern Territory</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">University of Queensland, Department of Animal Husbandry, St. Lucia, Queensland (D.D. Charles)  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">Brazil</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Associacao de Criadores de Bufalos do Brasil, Cx Postal 832, Sao Paulo (President, Dr. Paulo Joaquim Monteiro da Silva)  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Centro de Pesquisa Agropecuaria do Tropico Umido (Agricultural Reseach Center of the Humid Tropics), Caixa Postal, 48, Belem, Para, 66000  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Faculdade de Medicina Veterinaria e Zootecnia (Faculty of Veterinary Medicine and Zootechnology), Universidade Estadual "Julio de Mesquita Filho," Campus de Botucatu, Estado de Sao Paulo  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Instituto de Zootecnia (Institute of Zootechnology), Nova Odessa, Sao Paulo (Prof. Alberto Alves Santiago)  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Dr. Geraldo Mosse, Rua Apinages 716-CEP, 05017, Sao Paulo, S.P.  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Dr. Walmore Muller Lacort, Ministerio de agriculture Explanada des Ministerios, Bloco 8-50 Andar Sala 518, 70.000 Brasilia, D.F.  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">Bulgaria</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Academy of Agricultural Sciences, Sofia (P. Ivanov, Z. Zahariev)</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Buffalo Basis, Livestock Breeding Research Institute, Shumen (Dr. D. St. Polikhronov, Director; Dr. A. Alexis)  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">China</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Department of Animal Husbandry and Veterinary Medicine, Nanking Agricultural College, Nanking (Professor Sieh Chen-Hsia)  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Kwangsi Agriculture College, Nanning, Kwangsi (Professor Wang Pei Chien</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Livestock Farm, Lu Hsu, Pinyang County, Kwasngsi Chang Autonomous Region</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Research Institute for Animal Science, Nanning, Kwangsi (Dr. Chou Chi-Sheng)</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Singchow Dairy Farm, Kwangtung Province</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">Costa Rica</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Jose Luis Pacheco, Director, Dept Formento, 8502 JAPDEVA, Puerto Limon</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">Egypt</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Ain Shams University, Kasr-EI-Zaafran, Abbasiyah, Cairo (M.A. El-Ashry, A.M. El-Serafy)</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Department of Animal Production, College of Agriculture, Cairo University, Cairo (Dr. M.T. Ragab)  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">University of Alexandria, 22 Al-Gueish Avenue, Shatby, Alexandria (K. El-Shazly)</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">Federal Republic of Germany</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Dr. R. Dunkel, Herzeleidstrasse 39, 5330 Konigswinter 41, Bonn</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Prof. Dr. H. Fischer, Insitut fur Tropische Veterinarmedizin, Wilhelmstr. 15, 6300 Giessen</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Gesellschaft fur Agrarentwicklung (GAE), Meckenheimer Allee 113, 5300 Bonn 1</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">Hungary</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">J. Kovacs, Department of Animal Husbandry, Agricultural University, Deak F. -u16, 8361Keszthely  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">India</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Andhra Pradesh Agricultural University, Hyderabad, A.P. (Director of Research)</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Animal Husbandry Commissioner, Government of India, Ministry of Agriculture and Irrigation, Krishi Bhavan, New Delhi  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Animal Sciences, Director General, Indian Council of Agricultural Research, Krishi Bhavan, New Delhi  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Central Buffalo Breeding Farm, Sambalpua, PO: Sunbeda, Distt. Kerapur, Orissa</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Central Frozen Semen Bank, Hessarghatta, Bangalore, Kamataka</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Central Murrah Breeding Farm, Almadi, Tamil Nadu</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Central Surti Buffalo Farm, Dhamrod, Gujarat</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Chief Superintendent, Govenment Livestock Farm, Hissar, Haryana</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">College of Veterinary and Animal Science, Chandra Sekhar Azad University of Agriculture and Technology, Mathura Campus, Mathura, U.P.  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Co-ordinator, All India Buffalo Improvement Project, Natioal Dairy Research Institute, Karnal, Haryana, (Dr. V. N. Tripathi)  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Director, Military Dairy Farm, Army Headquarters, Quatermaster, General Branch, DHQ PO New Delhi 11  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">G.B. Pant, University of Agriculture and Technology, Pantnagar, U.P.  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Government Livestock Farm, Anjora Distt: Durg, Madhya Pradesh</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Gujarat Agricultural University, Reproductive Biology Research Unit, PO Anand Agricultural Institute, Anand, Gujarat  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Haryana Agricultural University , Hissar, Haryana</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Indian Veterinary Research Institute, Izatnagar, Barcilly, V.P. (Dr. S.K. Ranjan)</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Jawaharlal Nehru Krishi Vishwa Vidyalaya, Jabalpur, 482004, M.P.  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Kaira District Cooperative Milk Producers Union Ltd., Anand, Gujarat (Dr. V. Kurien, Chairman)</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">National Dairy Development Board, Anand, Gujarat</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">National Dairy Research Institute (ICAR), Karnal 132002, Haryana (S.P. Arora, Dr. D. Sundaresan, Director)  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Punjab Agricultural University, Ludhiana, Punjab (Dr. J.S. Ichhponani, Dr. S.K. Misra)</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">University of Agricultural Sciences, Dharwar Campus, Dharwar, Karnataka</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">University of Udaipur, Udaipur, Rajasthan</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">Indonesia</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Balai Inseminasi Buatan Lembang, Jawa Barat (Dr. R.D. Simangunsong)</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Directorate of Animal Husbandry, Department of Agriculture, Jl Salemba Raya 16, Jakarta (Dr. Jaman Zailani)  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Pusat Penelitian den Pengambangan Ternak (Centre for Animal Research and Development), Bogor</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">Iraq</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Animal Rearing Station, Abu Ghraib, Baghdad</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">Italy</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Animal Production and Health Division, FAO,00100 Rome</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Associazione Provinciale Allevatori, via Redentare, Caserta (Professore de Franciscis,Presidente)</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Instituto de Ricerche soll'Adattamento Bovini e dei Bufali, Ponticelli, Napoli (Director: Pro£ Lino Ferrara)  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Instituto Sperimentale per la Zootecnica, via Onofrio Panvino, Rome (Prof. A. Pilla)</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Instituto Sperimentale per la Zootecnice di Roma, via Salaria 31, 00016, Monterotondo Scalo (Dr. Augusto Romita)  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Ugo Jemma, Torre Lupara, 81050 Pastorano, near Caserta</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">Japan</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">H. Shimuzu, The University of Tsukuba, Sakura-mura niihar gun ibaraki-ken 300-311</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">Malaysia</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Central Animal Husbandry Station, Kluang</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Faculty of Veterinary Medicine and Animal Science, University Pertanian, Serdang, Selangor</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Malaysian Agricultural Research and Development Institute, Serdang, Selangor</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">Nepal</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Artificial Insemination Project, Tfipureshwar, Kathmandu (Dr. A.C. Gupta)</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Livestock Division, Khumaltar, Lalitpur, Kathmandu (Dr. N.D. Joshi)</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">Pakistan</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">College of Animal Husbandry, Lahore (Dr. Mohammad Shafi Chaudhry)</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Department of Animal Reproduction, University of Agriculture, Faisalabad (Dr. Rashid Ahmad Chaudhary)  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Livestock Production Research Institute, Bahadurnagar District, Sahiwat, Punjab (Dr. S.K. Shah, Director)  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Punjab Veterinary Research Institute, Lahore 13</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">Panama</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Hugo Giraoud, Apartado 60-2745, El Dorado</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">Papua New Guinea</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Department of Primary Industry, ERAP, P.O. Box. 348, Lae (John H. Schottler)</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Sepik Plains Livestock Station, Ufimo via Wewak, E.S.P.  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">Philippines</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Animal Science Department, Central Luzon State University, Muiloz, Nueva Ecija</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">College of Veterinary Medicine, University of the Philippines Systems, Diliman, Quezon City Dairy Development Division, Bureau of Animal Industry, Sta. Mesa, Metro Manila (Dr. Conrado A. Valdez)  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Dairy Training and Research Institute, University of the Philippines at Los Banos, College, Laguna 3720  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Department of Animal Science, University of the Philippines at Los Banos, College, Laguna 3720 (Dr. V. C. Momongon)  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Documentation Center on Water Buffalo, University of the Philippines at Los Banos Library, College, Laguna 3720  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Philippine Council for Agriculture and Resources Research, Livestock Research Division, Los Banos, Laguna 3732 (Dr. Alfonso N. Eusebio)  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">Portugal</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">W. Ross CockriII, 591 Vale do Lobo, Almansil, Algrave 8100</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">Sri Lanka</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Department of Animal Production and Health, Peradeniya (Dr. K. Balachandran)</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">School of Veterinary Science, University of Sri Lanka, Peradenlya Dr. B.M.A.O. Perrera)</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">Taiwan</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Food and Fertilizer Technology Center, P.O. Box 22-149, Taipei City</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">Tanzania</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Animal Production Department, Faculty of Agriculture, Forestry and Veterinary Medicine, University of Dar es Salaam, Morogoro (M.L. Kyomo)  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">DAFCO Farm, Ruvu</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Director, Livestock Development Division, Ministry of Agriculture, Dar es Salaam</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">P.M.J. Katyega, Director, Livestock Production Research Institute, Private Bag, Mpwapwa M.M. Oloufa, FAO, Morogoro  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">Thailand</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Kasetsart University, Department of Animal Science, Bangkok (Dr. Charan Chantalakhana) Faculty of Veterinary Science, Chulalongkorn University, Henri Dunant Street, Bangkok 5 (Dr. Maneewan Kamonpatana)  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Department of Obstetrics, Gynecology and Reproduction, Faculty of Veterinary Science, Chulalongkorn University, Henri Dunant Road, Bangkok 10500  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">FAO Regional Office, Maliwan Mansion, Phra Atit Road, Bangkok 2 (Dr. B. K. Soni)</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Office of Livestock Development Project, Tha Phra, Khon Kaen</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">National Buffalo Research and Training Center, Surin</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">Trinidad</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Steve Bennett, 61 Mucurapo Road, Port-of-Spain</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">Uganda</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">G. L. Corry, Director, Veterinary Research Services, P.O. Box 24, Entebbe</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">S. Mugerwa, Faculty of Agriculture, MaKerere University, P.O. Box 7062, Kampala</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">United Kingdom</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">T. B. Begg, Resident Veterinary Surgeon, Howletts and Port Lympne Estates, Ltd., Port Lympne, Lympne, Kent CT21 4PD  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">P. N. Wilson, BOCM Silcock Ltd., Basing View, Basingstoke, Hampshire RG21 2EQ</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">United States</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Wyland Cripe, Asst. Dean for Public Services, College of Veterinary Medicine, Box J-125, JHMHC, University of Florida, Gainesville, Florida 32610  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">J. Harrington, IRI Research Institute, Inc. One Rockefeller Plaza, New York, New York 10020 James Hentges, Department of Animal Science, Room 2104 McCarty Hall, University of Florida, Gainesville, Florida 32611  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Jack Howarth, School of Veterinary Medicine, University of California, Davis, California 95616</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Nels M. Konnerup, 609 East Iverson Road, Camano Island, Washington 98292</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">A. P. Leonards, P.O. Box 1094, Lake Charles, Louisiana 70602</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">John K. Loosli, Department of Animal Science, Room 2103 McCarty Hall, University of Florida, Gainesville, Florida 32611  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Robert E. McDowell, Department of Animal Science, Frank B. Morrison Hall, Cornell University, Ithaca, New York 14853  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Hugh Popenoe, International Programs in Agriculture, 3028 McCarty Hall, University of Florida, Gainesville, Florida 32611  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">William R. Pritchard, School of Veterinary Medicine, University of California, Davis, California 95616  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">Venezuela</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Abelardo Ferrer D., Quinta Nueva Exparta, Avenida Jose Felix Rivas, San Bernardino, Caracas</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<B><P>&lt;&lt;TOC3&gt;&gt; Appendix C</P>
+</B><P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Advisory Committee on Technology Innovation</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">HUGH POPENOE, Director, International Programs in Agriculture, University of Florida, Gainesville, Florida, Chairman  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">Members</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">WILLIAM BRADLEY, Consultant, New Hope, Pennsylvania</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">HAROLD DREGNE, Director, International Center for Arid and Semi-Arid Land Studies, Texas Tech University, Lubbock, Texas  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">ELMER L. GADEN, JR., Department of Chemical Engineering, University of Virginia, Charlottesville, Virginia  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">ANDREW HAY, President, Calvert-Peat, Inc., New York, New York (member through 1980)  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">CARL N. HODGES, Director, Environmental Research Laboratory, Tucson, Arizona  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">CYRUS MCKELL, Institute of Land Rehabilitation, Utah State University, Logan, Utah  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">FRANCOIS MERGEN, Pinchot Professor of Forestry, School of Forestry and Environmental Studies, Yale University, New Haven, Connecticut  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">DONALD L. PLUCKNETT, Consultative Group on International Agricultural Research, Washington, D.C.  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">THEODORE SUDIA, Deputy Science Advisor to the Secretary of Interior, Department of Interior, Washington, D.C. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">Board on Science and Technology for International Development  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">GEORGE BUGLIARELLO, President, Polytechnic Institute of New York, Brooklyn, New York, Chairman  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Members  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">EDWARD S. AYENSU, Director, Office of Biological Conservation, Smithsonian Institution, Washington, D.C. (member through 1980)  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">PEDRO BARBOSA, Department of Entomology, University of Maryland, College Park, Maryland (member through 1979)  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">FLETCHER L. BYROM, Chairman, Koppers Company, Inc., Pittsburgh, Pennsylvania  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">HARRISON BROWN, Director, Resource Systems Institute, The East-West Center, Honolulu, Hawaii  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">DORIS GALLOWAY, Department of Nutrition Sciences, University of California, Berkeley, California  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">MARY E. CARTER, Associate Administrator, U.S. Department of Agriculture, Washington, D.C.  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">ELIZABETH COLSON, Department of Anthropology, University of California, Berkeley, California  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">BREWSTER C. DENNY, Dean, Graduate School of Public Affairs, University of Washington, Seattle, Washington (member through 1980)  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">ROLAND I. FUCHS, Chairman, Department of Geography, University of Hawaii at Manoa, Honolulu, Hawaii, ex-officio  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">HERBERT I. FUSFELD, Director, Center for Science and Technology Policy, Graduate School of Public Administration, New York University, New York, New York (member through 1979)  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">MARTIN GOLAND, President, Southwest Research Institute, San Antonio, Texas (member through 1979)  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">LINCOLN GORDON, Senior Fellow, Resources for the Future, Washington, D.C. (member through September 1980)  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">JAMES P. GRANT, President, Overseas Development Council, Washington, D.C. (member through 1979)  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">N. BRUCE HANNAY, Foreign Secretary, National Academy of Engineering, ax-officio  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">GEORGE R. HERBERT, President, Research Triangle Institute, Research Triangle Park, North Carolina  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">WILLIAM N. HUBBARD, JR., President, The Upjohn Company, Kalamazoo, Michigan (member through 1980)  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">ROBERT N. KREIDLER, Private Foundation Consultant, New York, New York  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">RICHARD LASTER, Executive Vice President, General Foods Corporation, White Plains, New York </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">JOHN LISTON, Director, Institute for Food Science &amp; Technology, College of Fisheries, University of Washington, Seattle, Washington  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">THOMAS F. MALONE, Foreign Secretary, National Academy of Sciences, ex-officio  FRANCOIS MERGEN, Pinchot Professor of Forestry, School of Forestry and Environmental Studies, Yale University, New Haven, Connecticut  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">RODNEY W. NICHOLS, Executive Vice President, Rockefeller University, New York, New York (member through 1980)  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">DANIEL A. OKUN, Department of Environmental Sciences and Engineering, School of Public Health, University of North Carolina, Chapel Hill, North Carolina  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">E. RAY PARISER, Senior Research Scientist, Department of Nutrition and Food Science, Massachusetts Institute of Technology, Cambridge, Massachusetts  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">NAMES BRIAN QUINN, Amos Tuck School of Business Administration, Dartmouth College, Hanover, New Hampshire (member through 1979)  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">PRISCILLA C. REINING, Director, Project on Desertification, International Division, American Association for the Advancement of Science, Washington, D.C. (member through 1980)  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">RALPH W. RICHARDSON, JR., Department of Horticulture, Pennsylvania State University, University Park, Pennsylvania (member through 1979)  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">FREDERICK SEITZ, President Emeritus, Rockefeller University, New York, New York  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">H. GUYFORD STEVER, Consultant, Washington, D.C.  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">BILL C. WRIGHT, Program Officer, Africa and the Middle East, International Agricultural Development Service, New York, New York  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">VICTOR RABINOWITCH, Director</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">MICHAEL G. C. McDONALD DOW, Deputy Director  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">JOHN G. HURLEY, Deputy Director</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P></FONT></BODY>
+</HTML>
Index: /main/tags/2.25/gsdl/collect/demo/import/bostid/b22bue/b22bue.htm
===================================================================
--- /main/tags/2.25/gsdl/collect/demo/import/bostid/b22bue/b22bue.htm	(revision 21064)
+++ /main/tags/2.25/gsdl/collect/demo/import/bostid/b22bue/b22bue.htm	(revision 21064)
@@ -0,0 +1,539 @@
+<HTML>
+<HEAD>
+<META HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=windows-1252">
+<META NAME="Generator" CONTENT="Microsoft Word 97">
+<TITLE>&lt;&lt;TOC1&gt;&gt; Butterfly Farming in Papua New Guinea </TITLE>
+</HEAD>
+<BODY>
+
+<B><FONT FACE="Arial" SIZE=2><P>&lt;&lt;TOC1&gt;&gt; Butterfly Farming in Papua New Guinea </P>
+</B><P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Managing Tropical Animal Resources</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">First Printing, June 1983 </P>
+<P ALIGN="JUSTIFY">Second Printing, May, 1985 </P>
+<P ALIGN="JUSTIFY"></P>
+</FONT><FONT FACE="Arial" SIZE=2 COLOR="#0000ff"><P ALIGN="JUSTIFY">&nbsp;</P>
+</FONT><B><FONT FACE="Arial" SIZE=2><P ALIGN="CENTER"><A NAME="Acknowledgements"></A>&lt;&lt;TOC2&gt;&gt; Acknowledgments</P>
+</B><P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Report of an Ad Hoc Panel of the Advisory Committee on Technology Innovation </P>
+<P ALIGN="JUSTIFY">Board on Science and Technology for International Development </P>
+<P ALIGN="JUSTIFY">Office of International Affairs </P>
+<P ALIGN="JUSTIFY">National Research Council </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">In Cooperation with the Insect Farming and Trading Agency, Bulolo, Papua New Guinea </P>
+<P ALIGN="JUSTIFY"> </P>
+<P ALIGN="JUSTIFY">NOTICE: The project that is the subject of this report was approved by the Governing  Board of the National Research Council, whose members are drawn from the Councils of  the National Academy of Sciences, the National Academy of Engineering, and the  Institute of Medicine. The members of the committee responsible for the report were  chosen for their special competencies and with regard for appropriate balance.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">This report has been reviewed by a group other than the authors according to the  procedures approved by a Report Review Committee consisting of members of the  National Academy of Sciences, the National Academy of Engineering, and the Institute  of Medicine.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The National Research Council was established by the National Academy of Sciences in  1916 to associate the broad community of science and technology with the Academy's  purposes of furthering knowledge and of advising the federal government. The Council  operates in accordance with general policies determined by the Academy under the  authority of its congressional charter of 1863, which establishes the Academy as a  private, nonprofit, self-governing membership corporation. The Council has become the  principal operating agency of both the National Academy of Sciences and the National  Academy of Engineering in the conduct of their services to the government, the public,  and the scientific and engineering communities. It is administered jointly by both  Academies and the Institute of Medicine. The National Academy of Engineering and the  Institute of Medicine were established in 1964 and 1970, respectively, under the charter  of the National Academy of Sciences.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The Board on Science and Technology for International Development (BOSTID) of the  Office of International Affairs addresses a range of issues arising from the ways in which  science and technology in developing countries can stimulate and complement the  complex processes of social and economic development. It oversees a broad program of  bilateral workshops with scientific organizations in developing countries and conducts  special studies. BOSTID's Advisory Committee on Technology Innovation publishes  topical reviews of technical processes and biological resources of potential importance to  developing countries.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">This report has been prepared by an ad hoc advisory panel of the Advisory Committee  on Technology I innovation, Board on Science and Technology for International  Development, Office of international Affairs, National Research Council. Program costs  for the study were provided by the Office of Technical Resources, Bureau for Asia,  Agency for International Development under Grant No. ASB-0249-SS-00-1026-00 and  the Office of the Science Advisor, Agency for International Development, under Grant  No DAN/5538-GSS- 1023-00.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">First Printing, June 1983 </P>
+<P ALIGN="JUSTIFY">Second Printing, May, 1985 </P>
+<P ALIGN="JUSTIFY"></P>
+</FONT><FONT FACE="Arial" SIZE=2 COLOR="#0000ff"><P ALIGN="JUSTIFY"><A NAME="Panel_on_Butterfly_Farming_in_P"></A></P>
+</FONT><B><FONT FACE="Arial" SIZE=2><P ALIGN="CENTER">&lt;&lt;TOC2&gt;&gt; Panel on Butterfly Farming in Papua New Guinea </P>
+</B><P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">ROBERT M. PYLE, Chairman, Lepidoptera Specialist Group, International  Union for Conservation of Nature and Natural Resources, Gland,  Switzerland, Chairman </P>
+<P ALIGN="JUSTIFY">EDWARD S. AYENSU, Director, Office of Biological Conservation, Smithsonian  Institution, Washington, D.C. </P>
+<P ALIGN="JUSTIFY">ARCHIE F. CARR, JR., Professor, Department of Zoology, University of Florida,  Gainesville, Florida </P>
+<P ALIGN="JUSTIFY">F. WAYNE KING, Director, Florida State Museum, C;ainesville, Florida </P>
+<P ALIGN="JUSTIFY">FRANCOlS MERGEN, Pinchot Professor of Forestry, Yale University, New  Haven, Connecticut </P>
+<P ALIGN="JUSTIFY">MICHAEL G. MORRIS, Head of Subdivision of Invertebrate Ecology,  Furzebrook Research Station, Institute of Terrestrial Ecology, Wareham,  Dorset, England </P>
+<P ALIGN="JUSTIFY">HUGH POPENOE, Director, International Programs in Agriculture, University  of Florida, Gainesville, Florida </P>
+<P ALIGN="JUSTIFY">SHELDON R. SEVERINGHAUS, Representative, The Asia Foundation, Taipei,  Taiwan </P>
+<P ALIGN="JUSTIFY"></P>
+</FONT><FONT FACE="Arial" SIZE=2 COLOR="#0000ff"><P ALIGN="JUSTIFY"><A NAME="Contributors_"></A></P>
+</FONT><B><FONT FACE="Arial" SIZE=2><P ALIGN="CENTER">&lt;&lt;TOC2&gt;&gt; Contributors </P>
+</B><P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Papua New Guinea </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">PETER CLARK, Manager, Insect Farming and Trading Agency, Bulolo </P>
+<P ALIGN="JUSTIFY">CAROLE GABARA, Wildlife Division, Department of Oro Province, Popondetta </P>
+<P ALIGN="JUSTIFY">WASAM GARARA, Wildlife Division, Department of Oro Province, Popondetta </P>
+<P ALIGN="JUSTIFY">KAROL KISOKAU, Director, Office of Environment and Conservation, Waigani </P>
+<P ALIGN="JUSTIFY">NAVU KWAPENA, Division of Wildlife, Department of Lands and  Environment, Konedobu </P>
+<P ALIGN="JUSTIFY">MIRO LAUFA, Crocodile Section, Department of Lands and Environment,  Konedobu </P>
+<P ALIGN="JUSTIFY">LEO NING, Division of Wildlife, East Sepik Province, Wewak </P>
+<P ALIGN="JUSTIFY">RODERICK ORARI, Butterfly farmer, Popondetta </P>
+<P ALIGN="JUSTIFY">MICHAEL PARSONS, Ecologist, Insect Farming and Trading Agency, Bulolo </P>
+<P ALIGN="JUSTIFY">BLU RAIRI, Butterfly farmer, Maprik  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Other Countries </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">K. S. BROWN, JR., Department of Zoology, State University of Campinas, Sao  Paulo, Brazil </P>
+<P ALIGN="JUSTIFY">N. M. COLLINS, Co-compiler, Invertebrate Red Data Book, International Union  for Conservation of Nature and Natural Resources, Cambridge, England </P>
+<P ALIGN="JUSTIFY">WAYNE GAGNE, Bishop Museum, Honolulu, Hawaii </P>
+<P ALIGN="JUSTIFY">ANGUS HUTTON, Garaina Farms, Gympie, Queensland, Australia </P>
+<P ALIGN="JUSTIFY">ASHLEY C. MORTON, Department of Biology, The University, Southampton,  England </P>
+<P ALIGN="JUSTIFY">FRED PARKER, Kirwan, Queensland, Australia </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">* * *</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">NOEL D. VIETMEYER, Professional Associate, Board on Science and Technology for International Development, Butterfly Study Director </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">National Research Council Staff </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">F. R. RUSKIN, BOSTID Editor </P>
+<P ALIGN="JUSTIFY">MARY JANE ENGQUIST, Staff Associate </P>
+<P ALIGN="JUSTIFY">CONSTANCE REGES, Administrative Secretary </P>
+<P ALIGN="JUSTIFY"></P>
+</FONT><FONT FACE="Arial" SIZE=2 COLOR="#0000ff"><P ALIGN="JUSTIFY"><A NAME="Preface_"></A></P>
+</FONT><B><FONT FACE="Arial" SIZE=2><P ALIGN="CENTER">&lt;&lt;TOC2&gt;&gt; Preface </P>
+</B><P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Butterfly farming is a growing new industry in Papua New Guinea, and by  turning irdwings, mauve swallowtails, and other insects into a cash crop  villagers are both earning money and practicing sound wildlife conservation.  In this unique program butterfly farming is being used to complement the  preservation of species and of habitats. In balancing the utilization of  common butterflies with the protection of the most threatened species, Papua  New Guinea is providing a model for other countries, particularly those in the  tropics. The program demonstrates how village development can become an  integral part of conservation.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The panel that produced this report convened in Papua New Guinea in  May 1981. Its purpose was to investigate the concepts underlying this  project and to assess their potential for application elsewhere. Panel members  met with staff of the government's Division of Wildlife in Port Moresby and  later visited butterfly farms in Popondetta and the insect trading agency in  Bulolo. The panel is grateful to Karol Kisokau, Navu Kwapena, and Miro  Laufa of the Division of Wildlife for arranging the itinerary in Papua New  Guinea and to Peter Clark and Michael Parsons for hosting the Bulolo and  Popondetta visits.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">This report is one of the National Research Council series, Managing  Tropical Animal Resources. Current titles in the series are:*</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">· Water Buffalo: New Prospects for an Underutilized Animal (  1981 ) </P>
+<P ALIGN="JUSTIFY">· Little-Known Asian Animals with a Promising Economic Future  (1983) </P>
+<P ALIGN="JUSTIFY">· Crocodiles as a Resource for the Tropics (1983)</P>
+<P ALIGN="JUSTIFY">· Butterfly Farming in Papua New Guinea ( 1983)</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">These activities have been conducted under the auspices of the Advisory  Committee on Technology Innovation (ACTI) of the Board on Science and Technology for International Development, National Research  Council (see page 29). The purpose of ACT}iS the assessment of  unconventional scientific advances that might prove especially applicable to  problems of developing countries. Since its founding in 1971, it has produced  about 30 reports covering subjects as diverse as ferrocement construction  materials, the winged bean (a high-protein tropical food crop), and techniques  to provide more water for arid lands. This study adds the dimension of  conservation and ecosystem protection to ACTI'S principal concerns of  promising but neglected resources.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">ACTI activities are supported largely by the U.S. Agency for International  Development (AID). Program costs for this study were supported by AID'S  Bureau for Asia, and staff costs by AID'S Office of the Science Advisor, which  also made possible the free distribution of this report.  </P>
+<P ALIGN="JUSTIFY"></P>
+</FONT><FONT FACE="Arial" SIZE=2 COLOR="#0000ff"><P ALIGN="JUSTIFY">&nbsp;</P>
+</FONT><B><FONT FACE="Arial" SIZE=2><P ALIGN="CENTER"><A NAME="BM1_Introduction_and_Summary_"></A>&lt;&lt;TOC2&gt;&gt; 1 Introduction and Summary </P>
+</B><P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The international demand for tropical butterflies is much greater than is  generally recognized. Each year millions of them are caught and sold  throughout the world. Many buyers are scientists engaged in research on  aspects of systematics, ecology, ethology, evolution, and conservation.  Others are individuals who like expensive curios that incorporate butterflies,  such as display cases, coffee tables, wall hangings, or other objects. But  increasingly, the fragile, iridescent creatures, mounted in plastic or glass, are  used to decorate less-expensive items such as purses, trays, platters, screens,  and other common objects in Europe, North America, and Japan. In addition,  amateur butterfly collecting, which reached a peak in Victorian times, is again becoming popular.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">All this has produced a strong and active market. The current trade is  estimated to be between US $10 and $20 million annually, and the demand is  rising.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Butterfly Farming in Papua New Guinea </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Remote regions of Papua New Guinea are benefiting from this burgeoning  interest in tropical insects, and several hundred villagers are rearing or  collecting butterflies, beetles, and other insects for export. The Papua New  Guinea government now considers insects a national resource, and it has  made butterfly farming part of the nation's village economic development. At Bulolo it has established an Insect Farming and Trading Agency (IFTA) to  handle the business details of a growing international trade. And Papua New  Guinea is the only country so far to specify insect conservation as a national  objective in its constitution.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Botanical research is the key to Papua New Guinea's butterfly farming  program. Local botanists and ecologists have identified the plants that the  various butterfly species use during their life cycle. The butterfly farmers  then build up their "livestock" by clearing small areas of ground  and planting leafy food plants for larvae, together with the nectar-producing  flowering plants that adult butterflies feed on. The combination of flowering  and leafy plants provides a complete habitat where butterflies find everything  they need to grow and reproduce. Therefore, most remain, and the farmer  retains his livestock without fences or walls.*</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">They are among the most unusual farms in the world. Around their edges  are hibiscus and bougainvillea that attract the adult butterflies, whose  mouthparts are adapted for drinking nectar from flowers. And inside are leafy  plants, such as the strange Dutchman's pipe vine (Aristolochia tagala), on  which the caterpillars of several birdwing butterflies feed.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The enriched butterfly habitat in the villager's garden attracts and holds a  breeding population that becomes a self-renewing resource. By varying the  plant species the farmer can even maintain colonies of different butterfly  species. And because insects are so prolific, some butterfly farmers are  beginning to have problems with overstocking and have had to shift larvae  from plant to plantrather like moving cattle from one field to the next as the  grazing runs out.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Economic Development </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The IFTA program started in 1974 with fewer than 30 Papua New Guineans  from villages in two provinces. By 1978, more than 500 villagers in 10  provinces had been introduced to farming or collecting butterflies for export.  Since then, business has been increasing about 40 percent a year.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Gram for gram, exotic butterflies are far more valuable than cattle. Prices  paid by dealers in Europe, North America, and Japan range from 30 cents for  individuals of common species to around $10 for the two birdwing species  whose export is allowed. A specimen of a rarer species (for example, a female  of the mauve swallowtail Graphium weiskei) may bring as much as $50.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The project is still an embryonic activity; it is not large, as development  programs go. IFTA has only one professional staff person and two local  technicians to handle the distribution of specimens. The agency's goal is to  export between 5,000 and 10,000 specimens a month, from which the villages  can expect a return of $10,000 or more.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The agency purchases butterflies from villagers and uses them to fill orders from overseas buyers. Colorful beetles, strange-looking stick and leaf insects, and some moths and cicadas are also caught in the wild and sent to Bulolo. The profits, less 25 percent, are returned to the villagers. At the time of the panel's visit, IFTA had received about 4,000 shipments of butterflies and other insects from the rural people and had paid out about US $180,000 to purchase them. In 1979, the average farmer or collector received about $37 per box of specimens. By 1980, this had risen to about $50 per box. In 1981 it was estimated that a diligent butterfly farmer could earn an annual income of about $1,200.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Even so small an annual income is substantial in rural areas where the mean annual per capita income may be only $50. In many remote areas it is difficult to create income-producing opportunities because of illiteracy, dispersed population, and, in some cases, resistance to foreign ways.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Through butterfly farming many rural Papua New Guineans are for the first time participating in a cash economy. The product is a highvalue, low-volume crop. It brings needed or supplementary income to the people of the predominantly rural areas. Compared with farming coffee, another possible industry in Papua New Guinea's rural regions, it requires far less effort or land, and it involves minimal costs to the producer. And where a few expatriate opportunists once made small fortunes exploiting Papua New Guinea's butterflies, the profits now go to the villagers.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Conservation</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Habitat loss is by far the most critical issue in butterfly conservation. If habitat changes, the animals must change, leave, or die. Usually they die, since alternative habitats are already occupied or too distant.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Nearly all the world's butterfly species have suffered diminished ranges, and an estimated half of the world's butterfly populations face threats from human development. From Britain to Bhutan, the insects' habitats have come under siege. In Europe, perhaps one-third of all butterfly species are threatened, owing chiefly to the reductions in their various habitats. In California, half-a-dozen coastal butterflies have been lost since the 1860s, and an equal number are now endangered. In Madagascar and Rwanda, swallowtails and some species that occur nowhere else are being sacrificed to the clearing of forests.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The losses are much more than aesthetic, for many butterflies benefit people. They pollinate crops, are a major link in the food chain, and serve as sensitive indicators of ecological health.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">A striking feature of the Papua New Guinea butterfly farming program is that it is designed to conserve and increase the species being traded. It is a pioneering conservation effort that has been endorsed by the Lepidoptera Specialist Group of the International Union for Conservation of Nature and Natural Resources. The program helps relieve pressure on endangered populations, because for successful butterfly farms the villagers must retain - and even foster - a healthy wild population on or near their land.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Insect farming also helps preserve habitats because it leaves the bulk of the land intact and it helps landowners earn money without requiring them to cut down the rain forest as they would for timber or for cocoa, coffee, or oil palm plantations. Similarly, villagers can retain their traditional hunting grounds while cropping the insects that rely on these grounds for survival.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The existence of the butterfly farming project has served to focus attention on the status of all butterfly species. In 1968 this led to a law banning the taking of even a single specimen of the seven birdwing species threatened with extinction in Papua New Guinea. These large, brilliantly colored creatures can bring as much as $1,000 each in international trade, but there is a stiff fine in Papua New Guinea for even possessing one.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Enriching habitats with butterfly food plants (notably the Dutchman's pipe vine, Aristolochia tagala) has greatly increased the numbers of Papua New Guinea's two common birdwing species, Ornithoptera priamus and Troides oblongomaculatus. Now the country is taking on the challenge of increasing the seven endangered birdwing species that are protected and banned from trade. Already the IFTA staff has found that at least one of these rare species (Ornithoptera victoriae) is easily reared on the Dutchman's pipe vine. Farms are now being designed and sited with a view to building up the populations of this giant endangered species.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Conclusions</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">At this stage, the importance of this pioneering activity lies not in its size, but in the new vistas it opens up for the use of tropical resources.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Village Development</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">In farming butterflies, Papua New Guinea is showing that indigenous wildlife resources (especially those being depleted because of their commercial value) can contribute to economic development and that the farming of indigenous animals can be fitted smoothly into traditional village life.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Providing employment in rural areas is a major problem of developing countries. And in a sense, butterflies are an "appropriate" livestock, particularly for remote areas of the tropics where other income-producing activities are difficult to establish or are harmful to traditional lifestyles and fragile environments.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Butterflies may seem unusual farm animals, but to villagers in the Papua New Guinea jungle it is cattle that are exotic. The villagers live in close contact with their local insects; invariably they know much about butterfly locations, behavior, habits, life cycle, and the food eaten by the caterpillars.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Farming butterflies is proving a business to which villagers quickly adapt. Butterflies do not require the equipment or financing of a conventional farm; no capital is required, except for postage on the first shipment of specimens. Insect farming allows people to participate in the cash economy without causing disruptive changes in traditional village life. The villagers can work long and hard if they wish or they can put in only enough time to produce a little cash for necessities, leaving plenty of time for raising crops and other village activities.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Habitat Conservation</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">It is often claimed that economic development is necessarily destructive to the environment and detrimental to conservation - that as rural societies develop, their natural surroundings must suffer. The Papua New Guinea butterfly farming project is an innovative program that demonstrates this need not be true.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The program also shows that where human needs are given attention, conservation can be successful. Elsewhere in the tropics, attempts to conserve habitat without considering the needs of the people who live nearby have often failed.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">In sum, the butterfly farming program demonstrates that certain natural resources can be used profitably in a way that protects the environment. The program offers a culturally appropriate use of the land; on a broad scale, it could become a force in preventing clear-felling of the forest for timber exports or the wholesale conversion of rain forest to cash-crop monocultures such as coconut, coffee, or oil palm. Most of Papua New Guinea is still covered by primary rain forest; exploiting the economic value of the insects that live there is helping safeguard this increasingly rare habitat, which is fast disappearing in most parts of the tropics.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Species Conservation </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The knowledge gained from farming Papua New Guinea's butterflies has already contributed to relieving the threat of extinction from seven endangered species of birdwings. This experience could be replicated in other places where there are endangered butterfly species. Indeed, the program provides a model for nations that could profitably farm butterflies while protecting their threatened butterfly species.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Extension to Other Organisms</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">This project has a strategy and organizational structure that could well be applied to plants, such as rare orchids, and animals, such as crocodiles, that are endangered because of their commercial value. Indeed, using similar concepts of combining village income and conservation, the Papua New Guinea Division of Wildlife is farming crocodiles,* ruse deer, wallabies, and two native birds, the megapode and cassowary.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Through such husbandry practices, many species elsewhere might be saved from extinction, while providing income to the local people who traditionally have used the resource. Other countries should look with interest at the way Papua New Guinea is handling its wildlife enterprises. </P>
+<P ALIGN="JUSTIFY"></P>
+</FONT><FONT FACE="Arial" SIZE=2 COLOR="#0000ff"><P ALIGN="JUSTIFY"><A NAME="BM2_Butterfly_Status_and_Conserva"></A></P>
+</FONT><B><FONT FACE="Arial" SIZE=2><P ALIGN="CENTER">&lt;&lt;TOC2&gt;&gt; 2 Butterfly Status and Conservation</P>
+</B><P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">About 100,000-150,000 species of butterflies have been described; perhaps half that number remain to be discovered. Although there are important concentrations in the Arctic and temperate regions, most species are found in the tropics. There, the diversity of colors and forms is dazzling; every imaginable combination of hue and color is displayed. And many tropical butterflies are enriched with "structural" colors, which cause the wings to flash iridescently in the sun as they bend the light they reflect.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Although butterflies have long been admired and often depicted in art, they have been seriously studied only since the end of the seventeenth century. Linnaeus, in his Systema Naturae, placed the small number of butterflies then known in the single genus Papilio. Today that genus is restricted to the true swallowtails, and more than 700 genera of butterflies are recognized.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The Butterfly Trade</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Last century, as knowledge of butterflies grew and methods of preserving them improved, they become popular collectors' items. Wealthy naturalists such as Rothschild and LeMoult dispatched collectors to all parts of the world for specimens. Today the trade in butterflies is even more extensive.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">There are three major kinds of butterfly and insect trade. In one, large numbers of common species are collected in the wild and processed for use in ornamental objects such as coasters, mats, and lampshades. This is a low-value, high-volume industry that is both labor- and capital-intensive. It frequently uses "chipped" or slightly damaged butterflies. It often sells butterflies with paper bodies and only the wings of actual insects, which seem to be acceptable to a large part of the buying public.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The Taiwanese butterfly trade is an example. It operates on a large scale. At least a dozen Taiwanese factories employ scores of workers to capture and process butterflies. Estimates of annual sales vary from 15 million to 500 million butterflies. Taiwanese butterfly wings pasted onto paper bodies with pig-bristle antennae are used in ornaments and household objects from wall hangings to clear-plastic toilet seats. The bodies are recycled as pig feed. Despite this massive trade, Taiwan's wild butterfly populations seem to be remaining steady.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Similar, though smaller, industries trafficking in common butterflies are found in Korea, Malaysia, Hong Kong, Brazil, Honduras, and several African nations. The famous blue morpho butterflies of the American tropics enter the trade at the rate of some 50 million per year. Nearly all of these are the brilliant iridescent males, and biologists believe the number sold could be doubled without harming the overall population.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The second type of trade involves higher value and lower volume. This produces a vastly different product from the paper-bodied butterflies bound for novelty stores. It is exemplified by the operation in Papua New Guinea where sales are to collectors, museums, and students, and the specimens are high-quality insects in good to perfect condition, usually bearing scientific data. Because of the relatively high value per specimen, this trade can be carried on by fewer individuals in a nonfactory setting, and it is well suited to village industry, provided there is supervision and a quality-control checkpoint.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The third type of butterfly trade is for high-quality, expensive ornamental items, such as glass cases, domes, wall mounts, or jewelry containing beautiful insects. Brazil, for example, has a thriving jewelry trade based on the iridescent blue morpho butterfly. This type of trade can also furnish high-paying outlets for village-farmed insects.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&lt;&lt;I&gt;&gt; p08.png Papua New Guinea.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">In all three divisions of the butterfly trade, dealers fulfill an essential role. Few collectors and scientists can travel the world collecting their own specimens. Some dealers have established reputations for honesty, some have not. Exploitation of suppliers and customers alike has been rife. Few dealers are careful to attach accurate locality data to their specimens; some make serious mistakes in identifying them. (To combat this problem, British insect dealers have formed an association to monitor conservation-related activities and improve professional practice.)</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Generally, dealers supply specimens bred from the caterpillar or chrysalis and described as "ex pupa." Unless butterflies are caught immediately after emerging from the pupa the fragile wings tear and the scales detach to produce "worn" specimens.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Butterfly Taxonomy</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Classifying butterflies is difficult. Their most obvious features, the color and pattern of the wings, vary greatly; individuals and populations of the same species often look quite different. This has led to the dubious naming of many species and subspecies. And the uncertainties it causes have led some biologists, especially those working in ecology and genetics, to name populations rather than species or subspecies. However, populations frequently evolve, and this introduces a further uncertainty. Much additional work on basic butterfly systematics is needed. The knowledge gained should contribute particularly to the conservation of endangered species.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Butterfly Conservation</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Butterfly conservation is still in an early state of development, bedeviled by scarce or incomplete information. The conservation status of even the most thoroughly studied butterfly species is known in only a few areas. The distribution and status of most species is essentially unknown, and proposals for conservation measures are largely based on guesswork. Nevertheless, some conservation programs have been enacted. Most have concentrated on designating endangered species and banning their collection.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The greatest threat to butterflies and other insects, however, is habitat alteration. On several continents some species have already become extinct or endangered when humans altered the special environment they require. The importance of protecting butterfly habitats should not be underrated. Many species are restricted to very small areas, particularly to individual islands (Corsica, Sardinia, Jamaica, Madagascar, Sumba, the Comoros, Fiji, the Solomon Islands, Manus, and the Duke of York Islands, for instance). Such species are vulnerable to extinction because nearly all island habitats are fragile and are changing rapidly.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Although it is uncommon for insect species to be dangerously reduced merely by the capture of specimens, renewed commercial interest in butterflies gives rise to concern for their conservation. Most insects reproduce rapidly, and their high fecundity enables them to replace such losses in a generation or two - provided the basic environment has not been altered.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">But there are certain species of butterfly that reproduce slowly and are therefore more threatened by collection. The unusual birdwing butterflies of New Guinea, for example, produce only small broods. Moreover, these rare species command higher prices. Because this makes them particularly vulnerable, legislation to protect birdwing butterflies has been instituted in both parts of New Guinea - Papua New Guinea and Irian Jaya.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Accordingly, to save Queen Alexandra's birdwing (the largest and most threatened of the birdwings) from extinction, several wildlife management areas have been set up in Popondetta on Papua New Guinea's north coast. The government is also setting up refuges, administered by village councils, to preserve and protect other birdwing butterflies and wildlife resources. This habitat conservation is an important adjunct to the butterfly farming program. </P>
+<P ALIGN="JUSTIFY"></P>
+</FONT><FONT FACE="Arial" SIZE=2 COLOR="#0000ff"><P ALIGN="JUSTIFY"><A NAME="BM3_History_and_Government_Policy"></A></P>
+</FONT><B><FONT FACE="Arial" SIZE=2><P ALIGN="CENTER">&lt;&lt;TOC2&gt;&gt; 3 History and Government Policy</P>
+</B><P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Soon after Europeans discovered New Guinea's remarkable insect fauna around the turn of the century, collectors began arriving, and they have been coming ever since. Many were reputable professional or amateur scientists, gathering modest numbers of specimens for study and for museums, including Papua New Guinea's own national collection. Others, however, were plunderers who carried away large numbers of rare butterflies, giving little or no compensation to the local people and showing no concern for survival of the species.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">In 1966 the Papua New Guinea government responded to excessive collecting by designating seven rare birdwing butterflies as protected species. It became illegal to collect these huge, colorful birdwings, and strong measures were instituted - fines for nationals, deportation of expatriates - to halt black market trade.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">In the late 1960s and early 1970s commercial collecting of the other butterfly species continued piecemeal and unsupervised. Income was erratic, and expatriate dealers often paid their Papua New Guinean suppliers only a few cents for specimens that retailed for several hundred dollars in Europe and Japan.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The Insect Farming and Trading Agency</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">When Papua New Guinea achieved independence in 1975, the new government decreed that only nationals should profit from the country's butterfly resource. Since that time only Papua New Guineans have been able to export butterfly specimens (nonprotected species) for profit. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">In 1978, to guarantee Papua New Guineans fair prices and stable sales, a marketing agency was established. Its purpose was to protect the resource, to foster butterfly farming, and to ensure a high-quality export product.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Modest in its beginnings, the Insect Farming and Trading Agency (IFTA) was organized by Angus Hutton, a former tea planter and amateur lepidopterist. The business side of the agency was later developed by Peter Clark, who had worked with Hutton. Identification and production of food plants was advanced by Michael Parsons, Robert Pyle, and others.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">IFTA provides a market for those Papua New Guinea nationals who farm and collect butterflies and other insects. The agency allows them to obtain fair and fixed prices, maintains quality control, and ensures that current data accompanies all specimens. It also pools the insects from many sources and fills large orders from overseas dealers. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Of the butterflies IFTA exports, about 30 percent are from village farms and 70 percent are collected in the field. However, more than 50 percent of the revenue is made up of the farmed butterflies because of their better quality.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Quality Control</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The agency strives to sell only highest-quality insects; it rejects many butterflies as substandard. Most specimens are sold as named subspecies and to identify and name them requires much skill. Staff members have been specially trained to do this. (To a large extent, the area of origin, particularly in the case of the offshore islands, defines the subspecies concerned.) Locality data, usually consisting of village, province, and month and year of collecting or emergence, is affixed to all butterfly envelopes before they are pooled at the agency.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">IFTA stores its collection by species, in simple wooden boxes kept in cupboards lit from below (to lure potential pests away from the insects and to warm the cupboards and prevent mold). </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Marketing</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The agency makes up orders and dispatches them (with the required export permits) to customers "on trust." Although this is open to abuse, most buyers pay promptly and the system is easy and convenient. Careful records are kept of all suppliers, customers, and species in stock.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">At the time of the panel's visit, about 80 percent of the agency's business consisted of responding to requests from dealers. However, less than 10 percent of the orders received from all sources could be filled.Some requests were too small and others too specialized; in some cases the agency simply didn't have the specimens on hand (for example, a request for all the subspecies of a given butterfly). Furthermore, the agency has neither the office staff nor space to cope with every order in a business whose volume is almost doubling every two years.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Field Extension</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Wildlife extension officers periodically visit clients and new villages to sustain or develop enthusiasm for insect farming. They explain and demonstrate the procedures of butterfly farming and collecting and teach potential farmers how to recognize a valuable species in each of its life stages. Above all, they demonstrate how to prepare specimens for sale. This is because it is often difficult to convince farmers of the need for extreme care and delicacy in handling, and many inexperienced farmers send in bruised or hopelessly damaged specimens. Although about 500 villagers were farming butterflies at the time of the panel's visit, fewer than 50 were supplying good material regularly.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">These contacts are also important because the butterfly farmers easily become discouraged if no interest is shown in their work. In the Papua New Guinea countryside there is often little need for cash; people can obtain all their food, clothes, shelter, and resources from their gardens or from the bush. Money received from one shipment of butterflies may last a subsistence farmer for months, making it difficult for the agency to sustain his interest in providing regular shipments.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The agency's extension officers have initiated a number of butterfly farming projects at primary, secondary, and vocational schools. These projects have proved most successful. Apart from the practical education they give students, they provide early insight into one of Papua New Guinea's most useful resources. Several vocational schools also provide training in mounting butterflies and beetles as souvenirs for tourists, as well as in the construction of hatching cages and solar driers. Beautiful wooden cabinets to hold butterflies have also been made by some teenage students.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Research and Monitoring</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">In addition to teaching Papua New Guineans to collect and farm insects, IFTA promotes research both to conserve species and to make them available in quantity. Success has already been achieved in farming the common birdwing butterflies by planting large numbers of the Dutchman's pipe (Aristolochia tagala) vines that they feed on.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The agency's staff includes an ecologist, indicating the importance of the scientific basis for conservation in this project. The ecologist is at hand to conduct research on life histories, farming methods, and management measures for rare species.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">IFTA staff are now identifying new food plants that will permit more species to be farmed. Research into the life histories of many butterflies with economic potential is well under way, so that an increasing number of species will become "farmable" and will be available in future in perfect ex pupa condition. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The sources of all specimens received by IFTA are recorded on a map so that a butterfly's range and rarity or abundance can be assessed and conservation measures implemented where necessary. In this way, even insects too damaged for sale at least have value to conservation efforts. All specimens of unusual scientific interest are lodged in the national insect collection for future study. </P>
+<P ALIGN="JUSTIFY"></P>
+</FONT><FONT FACE="Arial" SIZE=2 COLOR="#0000ff"><P ALIGN="JUSTIFY"><A NAME="BM4_Operating_a_Butterfly_Farm"></A></P>
+</FONT><B><FONT FACE="Arial" SIZE=2><P ALIGN="CENTER">&lt;&lt;TOC2&gt;&gt; 4 Operating a Butterfly Farm</P>
+</B><P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Planting the Farm</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The key to farming butterflies is to establish a garden of the plants the various species need for their life cycles. The ideal farm area is about 0.2 hectares. This is spacious enough for growing food plants for adults and larvae and small enough to keep the plants watered, weeded, pruned, and generally well tended. Such a farm can contain about 500 vines, grown like bean plants on poles or shade trees.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">It is important to surround the site with a thick hedge of hibiscus, bougainvillea, ixora, poinsettia, or other nectar-bearing plants whose flowers attract adult butterflies and encourage them to remain in the area. The hedges also keep out pigs and other livestock that may damage the leafy plants inside the farm.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">A good way to start a farm is to establish it in a vegetable garden. (Papua New Guinea butterfly farmers often plant butterfly vines between their rows of sweet potato or tarot) By the time the vegetables are ready to harvest, the area already has some thriving butterfly food plants and probably some winged livestock as well.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">One of the most successful butterfly food plants in Papua New Guinea is Aristolochia tagala, a vine on which the larvae of more common birdwing butterflies feed. Another is Evodea - a food plant of the large blue ulysses swallowtail and many colorful weevils.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Shade trees also can be food plants for butterflies other than birdwings and for beetles or weevils. Examples are species of Annona (such as soursop), Citrus (such as lemon), Cerbera, and Graptophyllum. Wallace's Longhorn Beetle feeds on breadfruit (Artocarpus communis). </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Normally, one area of the farm is kept aside for growing seeds or cuttings. (IFTA sells seed of some suitable species.) In this nursery the butterfly food plants are watered and cared for, and unhealthy ones are easily spotted and weeded out. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&lt;&lt;I&gt;&gt; p16.png Stylized diagram of a butterfly farm:</P>
+<P ALIGN="JUSTIFY">A Hedge of hibiscus, ixora, and poinsettia to keep pigs out and provide nectar.</P>
+<P ALIGN="JUSTIFY">B Fruits trees (such as lemon).</P>
+<P ALIGN="JUSTIFY">C The aristolochia vine grown on the branches of others trees (such as leucaena), to feed    caterpillar larvae.</P>
+<P ALIGN="JUSTIFY">D Nursery area.</P>
+<P ALIGN="JUSTIFY">E A hut for tools.</P>
+<P ALIGN="JUSTIFY">(Diagram courtesy IFTA, Bulolo)</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The Life Cycle</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Normally, each butterfly species has a preferred food plant for its larvae. After the female has mated she searches for the correct plant and lays her eggs on or near it. In a few days the eggs hatch, and the young caterpillars usually eat their own eggshells and begin feeding on the softer leaves and shoots of the food plant.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">As they grow, the caterpillars shed their skins. Each molt is called an instar, and five instars occur before a larva is big enough to pupate. Pupation is a resting stage during which the adult butterfly develops inside the hard, protective chrysalis. For pupation the larva selects the underside of a stem or leaf to protect it from rain and predators.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">After 10 days to 3 weeks, depending on the type of butterfly, the pupal case splits open and the adult insect emerges. This usually occurs before 9 o'clock in the morning. The freshly emerged adult then takes from 3 to 4 hours to expand and dry its wings before flying off to feed on nectar and to search for a mate to begin the life cycle once again. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Harvesting</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Once the farm is well established, pupae can be collected daily. Ideally, about 50 percent should be left or released. At least as many females as males should be released. Pupae that are too high to reach are usually left to emerge naturally and repopulate the farm. Others are left because they are not quite perfect.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The farmer can usually see that emergence will occur on the next day, since the pupa becomes darker in color as the adult wing and body colors develop. He then plucks off the stem or leaf to which the pupa is attached. (The soft, new pupae are not touched because this damages the adult.)</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">He pins the leaf to a board or puts it in a net or in a small cage. Often these are kept inside to protect the pupae against pests and large predators. However, some farmers construct small houses out of bush materials to hold pupae ready for hatching. Others keep their pupae in the open and count on being able to collect the adults before they have flown away.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Care is taken to protect the specimens from ants and rats. For example, the legs of the cage are placed in bowls of water to deter ants from climbing up. The pupae are sprayed with water 2-3 times a week to speed up the hatching process and to prevent them from drying out. (Only a light spray is used; otherwise the pupa develop mold.)</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The pupae are best kept in a shady place so the butterflies will remain calm after hatching and will not flap and damage their wings.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Processing</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">When the newly emerged butterfly has completely dried its wings, it is carefully caught by the thorax and injected with a small amount of a killing agent such as ethyl acetate or boiling water.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Small butterflies are particularly easily damaged if handled, so they are placed for about 10 minutes in a killing jar containing cotton (cotton wool) soaked with a little ethyl acetate. A layer of cardboard is placed above the cotton so that the butterflies are not stained by the solvent.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The farmer places the dead butterflies in paper envelopes, being careful at all times not to touch or damage the wings. The envelopes are easily made from grease-proof paper, which the agency supplies on request.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">To ensure that the butterflies will not mold, they are placed on a black plastic tray and dried in the sun, in their papers, for about 4 days. During this time they are protected from pests such as ants, and the drying trays have a screen on top to prevent the envelopes from blowing away or from being rained on.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Once properly dried, the insects, still in their envelopes, are stored in boxes, preferably airtight to prevent condensation and molding. When enough specimens have been collected, the villager packs them carefully in strong cardboard boxes (which the agency also supplies) with cotton or kapok. A few naphthalene crystals are added to keep away pests, and the box is wrapped and sent to Bulolo. </P>
+<P ALIGN="JUSTIFY"></P>
+</FONT><FONT FACE="Arial" SIZE=2 COLOR="#0000ff"><P ALIGN="JUSTIFY"><A NAME="BM5_Application_to_Other_Nations"></A></P>
+</FONT><B><FONT FACE="Arial" SIZE=2><P ALIGN="CENTER">&lt;&lt;TOC2&gt;&gt; 5 Application to Other Nations</P>
+</B><P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">As noted, the essence of the Papua New Guinea approach is the cultivation of food plants that the butterflies need to complete their life cycles. This is a process that could be replicated elsewhere, and the potential for butterfly farming exists in many countries. In fact, although Papua New Guinea is rich in butterfly species - some 700 of them - it is not unusually so. Other countries also have large numbers of species. There are, for instance 2,500 species known in Costa Rica.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">There are some 14,000 species of true butterflies in the world. Although there is possible competition, many countries have no overlap in species at all. As collectors and specialists usually want butterflies from many different parts of the world, the likely competition among countries exporting farmed or wild-caught butterflies is minimal.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Butterflies are supplied to the trade from nearly every part of the world. But because they are most diverse in the tropics, it is likely that the best chance for success in farming them lies there. However, some temperate countries also have an abundance of particular species, and in Europe, the United States, and Japan, butterfly farming is already established on a small scale. This is mainly because many collectors like to rear their own material and they purchase eggs, caterpillars, or chrysalids instead of killed adults. Many dealers in these countries supply a few tropical species that are easy to rear, such as the orchard swallowtail (Papilio aegeus). However, this trade is generally low in volume and value, and temperate-zone butterfly farms are little more than a sideline to normal dealerships.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Some general comments follow on the potential of butterfly farming in various parts of the world.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">· Temperate regions of the Old World (Palaearctic Realm). East palaearctic species are in great demand internationally and obtainable with great difficulty. China, in particular, has species of both Parnassius and Papilio that might be farmed. However, all Parnassius species are montane to some degree and none has been farmed yet. Eurasian arctic satyrids, lesser fritillaries, and sulphurs are also in great commercial demand and could perhaps be farmed. Swallowtails are few and are frequently protected.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">· Tropical Africa and associated islands (Afrotropical Region). The potential for butterfly farming has not yet been considered in Africa, although the diversity of desirable species is great and the potential market extensive. This area has important swallowtails and Charaxes species (Nymphalidae), but so far as is known, no farming enterprises exist. Experimental or trial farms for butterflies are needed in different parts of Africa.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">· Indian subcontinent and Southeast Asian tropics (Oriental Realm). Silk moths, such as Bombyx mori, are commercially farmed in Asia, and butterfly farming would seem to be a natural extension of this. Many Asian butterflies are supplied to dealers, especially from Taiwan and the Philippines, but there is little farming. A very large trade originates in Malaysia, especially for Rajah Brooke's birdwing (Trogonoptera brookiana). Farming is reputed to take place, but most specimens are actually collected. Desirable species of swallowtails, including the black and gold birdwings (Troides species), occur throughout the region. Species belonging to the families Nymphalidae and Pieridae are good candidates for farming, as they are in much demand from dealers.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">· Australia, New Guinea, and associated islands to the west (Australasian Realm). Australia is not rich in butterflies, but it has some important endemic species. At least one "farm" exists in Australia, but this appears to be an offshoot of a normal dealership, which rears a few local species to supply at early stages to collectors. Farming is to be encouraged here.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">New Guinea's most coveted butterflies, which it shares with Irian Jaya, are the Ornithoptera birdwings. But almost equally desired by collectors and specialists are the Troides birdwings, concentrated to the west of New Guinea.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">· Temperate regions of the Americas (Nearctic Realm). There is a considerable trade in New World butterflies from nearly every family (few Lycaenidae and Hesperiidae), but almost all are caught in the wild. There is a strong market for far-northern species (Boloria, Colias, Erebia, Oenesis). Farming these might be possible among Canadian and Alaskan Indian or Eskimo groups.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">· Tropical regions of the Americas (Neotropical Realm). This is a likely area for the development of butterfly farming, particularly as its species are completely different from those of the tropics elsewhere. The Morpho and Agrias species of South America are much desired by collectors. It is possible that some of the highly prized morpho butterflies are already farmed (as the law, in fact, requires), but evidence is conflicting, and most biologists believe that the major supply of specimens is from wild populations. Other groups that lend themselves to farming include the swallowtails, nymphalids (including Agrias), and certain members of the family Satyridae. There are large fauna of Riodinidae and Lycaenidae that are potentially suitable for farming.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">A dealer in preserved butterflies has recently set up business in the Dominican Republic, and butterfly farms have been established in Costa Rica.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">· General. Butterflies in the family Riodinidae and, especially, Lycaenidae seem to be a neglected resource. Many species are relatively small but brightly colored. A major difficulty is that many Lycaenidae have to live with ants for part of their lives and this complicates their rearing.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Butterfly Parks</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Some regions with tourist industries are showing interest in establishing "butterfly zoos" or "butterfly jungles." These displays have live butterflies (usually farmed or reared) in artificial habitats resembling the natural ones. Some species, such as the orchard swallowtail (Papilio aegeus), respond well to such conditions. One British dealer has a "tropical jungle" in an enclosed environment in which both temperature and atmospheric pressure are regulated. A large British butterfly zoo has been established and a smaller one has been proposed. The New York Zoological Society is developing a butterfly component in its Wild Asia Hall at the Bronx Zoo, and San Francisco, Portland, Cincinnati, and Tokyo all have thriving insect zoos. Also, the Colombo Zoo in Sri Lanka has a live display and a successful program of butterfly rearing. Similar enterprise could be shown in other places with tourist industries.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Starting a Butterfly Farm</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Butterfly farming is initially an ecological and botanical challenge. One must first observe, identify, and propagate the plants that the various species use for food.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Success for butterfly farmers rests on their choosing commercially attractive species. Unfortunately, ecological details of the life histories of suitable species are known in only a few cases. The prospective farmer will be largely on his own and must first develop this information.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Many of the most desirable species are native to primary tropical forests, and they may need protection because of the rate at which their habitat is being destroyed.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Any program to commercially exploit butterflies and other insects must either bypass the rarest, most restricted, and slowest reproducing species; farm them cautiously with a high percentage of adults released; or take them with the greatest of care. Further, there must be adequate habitat protection both in the natural state and in mixed land uses (rather than just agricultural croplands) to support the insects and furnish a continuing supply.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Some competition could occur if live butterflies were exported between countries and used to establish farming enterprises. In general, however, butterflies are easier to farm in their native habitats. </P>
+<P ALIGN="JUSTIFY"></P>
+</FONT><FONT FACE="Arial" SIZE=2 COLOR="#0000ff"><P ALIGN="JUSTIFY"><A NAME="Appendix_A"></A></P>
+</FONT><B><FONT FACE="Arial" SIZE=2><P ALIGN="CENTER">&lt;&lt;TOC2&gt;&gt; Appendixes </P>
+</B><P ALIGN="JUSTIFY"></P>
+<B><P>&lt;&lt;TOC3&gt;&gt; A Selected Readings</P>
+</B><P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Carvalho, J. C. M., and O. H. H. Mielke. 1972. The trade of butterfly wings in Brazil and its effect upon survival of the species. Proceedings 19th International Congress of Entomology (Moscow) 1 :486-488.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Fenner, T. L. 1976. Aspects of butterfly conservation in Papua New Guinea, Pp. 121-127 in Ecology and Conservation in Papua New Guinea, K. P. Lamb and J. L. Gressitt eds. Pamphlet 2. Wau Ecology Institute, Papua New Guinea.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Parsons, M. n.d. Insect Farming and Trading Agency Farming Manual. Insect Farming and Trading Agency, Division of Wildlife, P.O. Box 129, Bulolo, Morobe Province, Papua New Guinea.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Pyle, R. 1981. Butterflies: now you see them.... International Wildlife I I (1):4- 11.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Pyle, R., M. Bentzien, and P. Opler. 1981. Insect conservation. Annual Review of Entomology 26:233-258.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Pyle, R. M. and S. A. Hughes. 1978. Conservation and utilization of the insect resources of Papua New Guinea. Unpublished report, copies available from the author, see Research Contacts.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Severinghaus, S. R. 1977. The butterfly industry and butterfly conservation in Taiwan. Atala 5(2):20-23.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Unno, K. 1974. Taiwan's butterfly industry. Wildlife 16: 356-359.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Vietmeyer, N. D. 1979. Butterfly ranching is taking wing in Papua New Guinea. Smithsonian 10(2):119-135. </P>
+<P ALIGN="JUSTIFY"></P>
+</FONT><FONT FACE="Arial" SIZE=2 COLOR="#0000ff"><P ALIGN="JUSTIFY"><A NAME="Appendix_B"></A></P>
+</FONT><B><FONT FACE="Arial" SIZE=2><P>&lt;&lt;TOC3&gt;&gt; Appendix B</P>
+</B><P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Research Contacts</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Wayne Gagne, Bishop Museum, P.O. Box 6037, Honolulu, Hawaii, 96818 USA</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Angus Hutton, Garaina Farms, Scrubby Creek Road, Gympie 4570, Queensland, Australia</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Insect Farming and Trading Agency, P.O. Box 129, Bulolo, Morobe Province, Papua New Guinea (Peter Clark, Manager; Michael Parsons, Ecologist)</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Karol Kisokau, Director, Office of Environment and Conservation, Central Government Offices, Waigani, Papua New Guinea</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Navu Kwapena, Division of Wildlife, Department of Lands and Environment, Konedobu, Papua New Guinea</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Rudi Mattoni, 9620 Heather Road, Beverly Hills, California 90210, USA</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Michael G. Morris, Chairman, Butterfly Specialist Group, International Union for Conservation of Nature and Natural Resources, Furzebrook Research Station, Institute of Terrestrial Ecology, Wareham, Dorset BH20 5AS, England</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Ashley C. Morton, Department of Biology, Building 44, The University, Southampton S09 5NH, England</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Fred Parker, 717 Ross River Road, Kirwan, Queensland 4814, Australia</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Robert M. Pyle, Chairman, Monarch Project, Xerces Society, 369 Loop Road, Gray's River, Washington 98621, USA</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Sheldon R. Severinghaus, Representative, The Asia Foundation, 42, Chien Kuo North Road, Taipei 104, Taiwan, Republic of China </P>
+<P ALIGN="JUSTIFY"></P>
+</FONT><FONT FACE="Arial" SIZE=2 COLOR="#0000ff"><P ALIGN="JUSTIFY"><A NAME="Appendix_C"></A></P>
+</FONT><B><FONT FACE="Arial" SIZE=2><P>&lt;&lt;TOC3&gt;&gt; Appendix C</P>
+</B><P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Biographical Sketches of Panel Members</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">EDWARD S. AYENSU, Director of the Office of Biological Conservation, Smithsonian Institution, Washington, D.C., is currently the Secretary-General of the International Union of Biological Sciences. He received his B.A. in 1961 from Miami University in Ohio, M.Sc. from The George Washington University in 1963, and his Ph.D. in 1966 from the University of London. His research interests are in comparative anatomy and phylogeny of flowering plants, commercial timbers, histology of monocotyledons, economic botany, and tropical biology. An internationally recognized expert on tropical plants, he has published extensively in these areas and on topics relating to science, technology, and development, especially in developing countries. Dr. Ayensu was co-chairman of the Panel on Under exploited Tropical Plants of the Advisory Committee on Technology Innovation and chairs and serves as a member of many international bodies. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">ARCHIE F. CARR, JR., is Graduate Research Professor in the Department of Zoology, University of Florida, Gainesville. As Technical Director of the Caribbean Conservation Corporation, he has directed a seasonal research program at the breeding ground of the green turtle at Tortuguero, Costa Rica, since 1952, with continuous grants from the National Science Foundation from 1955 to 1980, and has carried out investigations of marine turtle ecology and navigation in various parts of the world. The author of numerous papers, articles, and books, he received the Daniel Giraud Elliot Medal of the National Academy of Sciences for Handbook of Turtles and the John Burroughs Medal for The Windward Road. He is Research Associate of the American Museum of Natural History; Affiliate Curator of Natural Sciences, Florida State Museum; Chairman of the Marine Turtle Specialist Group of the Survival Service Commission, International Union for the Conservation of Nature; Honorary Consultant of the World Wildlife Fund; Fellow of the Linnean Society of London; Fellow of the American Fisheries Society; and a member of Phi Beta Kappa and Sigma Xi.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">In 1973 he was awarded a gold medal from the World Wildlife Fund for the application of scientific findings to the conservation of marine turtles. In 1975 he received the Edward W. Browning Award for achievement in biological conservation. In 1978 Dr. Carr was awarded the Gold Medal of the New York Zoological Society for contributions to natural science and conservation; in 1978 he became Officer of the Order of the Golden Ark (The Netherlands).</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">F. WAYNE KING is the Director of the Florida State Museum, Gainesville. He received a B.S. in 1957 and an M.S. in 1961 from the University of Florida and a Ph.D. from 1966 from the University of Miami. His research interests are in wildlife conservation and habitat preservation, impact of international trade on wildlife populations, and ecology and behavior of reptile populations. He worked at the New York Zoological Society from 1967 to 1975. As an international wildlife consultant, Dr. King has received honors from the Dominican Republic, the American Association of Zoological Parks and Aquariums, and from H.R.H. Prince Bernhard of The Netherlands. He has served on committees advising the State Department and the International Union for Conservation of Nature and Natural Resources on policies regarding the trade of crocodile skins, turtle products, and other wildlife materials. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">FRANCOlS MERGEN, Pinchot Professor of Forestry and Professor of Forest Genetics, Yale University, was Dean of the School of Forestry and Environmental Studies at Yale from 1965 to 1975. He received a B.A. from Luxembourg College and a B.Sc.F. from the University of New Brunswick in 1950, an M.F. in ecology in 1951, and a Ph.D. in forest genetics from Yale in 1954. He is especially knowledgeable about francophone Africa and was chairman of the Sahel program of the Board on Science and Technology for International Development and a member of the Advisory Committee on Technology Innovation. From 1960 to 1965 he was research collaborator at the Brookhaven National Laboratory. In 1966 he was the recipient of the Award for Outstanding Achievement in Biological Research from the Society of American Foresters and in 1975 was Distinguished Professor (Fulbright-Hays Program) in Yugoslavia. Before joining the Yale faculty, he served as project leader in forest genetics for the U.S. Forest Service in Florida. He has served as a consultant to FAO, various foreign governments, and private forestry companies, and he has traveled extensively in the tropical countries of Asia, Africa, and Latin America. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">MICHAEL G. MORRIS is head of the Furzebrook Research Station of the Institute of Terrestrial Ecology (National Environment Research Council, U.K.). He received a B.A. in natural sciences (zoology) at the University of Cambridge of 1958, M.A. in 1962, and received his Ph.D. from London University in research on the integrated control of orchard pests. Dr. Morris worked at Monks Wood Experimental Station on the effects of grassland management on populations of invertebrates and developed a strong interest in community and applied ecology, particularly the conservation of insect populations. Recently he has become involved with problems of butterfly conservation and resource utilization. He is Secretary of the Joint Committee for the Conservation of British Insects, a Vice-Chairman of the Lepidoptera Specialist Group of lUCN'S Survival Commission, and Chairman of the Habitat and Species Protection Committee of SEL (Societal Europaea Lepidoptero-Logica). </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">HUGH L. POPENOE is Professor of Soils, Agronomy, Botany, and Geography and Director of the Center for Tropical Agriculture and International Programs (Agriculture) at the University of Florida. He received his B.S. from the University of California at Davis in 1951 and his Ph.D. in soils from the University of Florida in 1960. His principal research interest has been in the area of tropical agriculture and land use. His early work on shifting cultivation is one of the major contributions to this sytem. He has traveled and worked in most of the countries in the tropical areas of Latin America, Asia, and Africa. He is past Chairman of the Board of Trustees of the Escuela Agricola Panamericana in Honduras, Visiting Lecturer on Tropical Public Health at the Harvard School of Public Health, and a Fellow of the American Association for the Advancement of Science, the American Society of Agronomy, the America Geographical Society, and the International Soils Science Society. He is Chairman of the Advisory Committee for Technology Innovation and a member of the Board on Science and Technology for International Development. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">ROBERT MICHAEL PYLE, a writer and consulting lepidopterist based in Gray's River, Washington, has served since 1979 as Co-Compiler of the lUCN Invertebrate Red Data Book. In this capacity he is consultant to the Conservation Monitoring Centre in Cambridge, England. After receiving his B.S. and M.S. at the University of Washington, he took his Ph.D. through the School of Forestry and Environmental Studies at Yale University in 1976. He worked for the Government of Papua New Guinea on the conservation and utilization of insect resources and then with the Nature Conservancy as Northwest Land Steward. A </P>
+<P ALIGN="JUSTIFY">former Fulbright Scholar to the United Kingdom, Dr. Pyle subsequently founded the Xerces Society for conservation of beneficial insects and their habitats. He has been chairman of IUCN'S Lepidoptera Specialist Group (Species Survival Commission) since 1976. His publications include the Audubon Society Field Guide to North American Butterflies. A comprehensive book on insect conservation in his next project.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">SHELDON R. SEVERINGHAUS received his Ph.D. from Cornell University in 1977 in natural resources management. He has worked on various wildlife research projects in Asia since 1964 and is representative for the Asia Foundation in Taiwan. He has published articles on butterfly conservation and wildlife industries in Taiwan, where he has been studying the butterfly and wildlife farming projects. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">NOEL D. VIETMEYER, staff officer for this study, is Professional Associate of the Board on Science and Technology for International Development. A New Zealander with the Ph.D. in organic chemistry from the University of California, Berkeley, he now works on innovations in science that are important for developing countries. </P>
+<P ALIGN="JUSTIFY"></P>
+</FONT><FONT FACE="Arial" SIZE=2 COLOR="#0000ff"><P ALIGN="JUSTIFY"><A NAME="Advisory_Committee_on_Technolog"></A></P>
+</FONT><B><FONT FACE="Arial" SIZE=2><P ALIGN="CENTER">&lt;&lt;TOC2&gt;&gt; Advisory Committee on Technology Innovation</P>
+</B><P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">HUGH POPENOE, Director, International Programs in Agriculture, University of Florida, Gainesville, Florida, Chairman </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Members</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">WILLIAM BRADLEY, Consultant, New Hope, Pennsylvania </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">HAROLD DREGNE, Director, International Center for Arid and Semi-Arid Land Studies, Texas Tech University, Lubbock, Texas (member through 1981) </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">ELMER L.GADEN,JR., Department of Chemical Engineering, University of Virginia, Charlottesville, Virginia </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">CARL N. HODGES, Director, Environmental Research Laboratory, Tucson, Arizona </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">CYRUS MCKELL, Native Plants, Inc., Salt Lake City, Utah </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">FRANCOIS MERGEN, Pinchot Professor of Forestry, School of Forestry and Environmental Studies, Yale University, New Haven, Connecticut (member through 1982) </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">DONALD L. PLUCKNETT, Consultative Group on International Agricultural Research, Washington, D.C. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">THEODORE SUDIA, Deputy Science Advisor to the Secretary of Interior, Department of Interior, Washington, D.C. </P>
+<P ALIGN="JUSTIFY"></P>
+</FONT><FONT FACE="Arial" SIZE=2 COLOR="#0000ff"><P ALIGN="JUSTIFY"><A NAME="Board_on_Science_and_Technology"></A></P>
+</FONT><B><FONT FACE="Arial" SIZE=2><P ALIGN="CENTER">&lt;&lt;TOC2&gt;&gt; Board on Science and Technology for International Development</P>
+</B><P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">GEORGE BUGLIARELLO, President, Polytechnic Institute of New York, Brooklyn, New York, Chairman </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Members</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">SAMUEL P. ASPER, Educational Commission for Foreign Medical Graduates, Philadelphia, Pennsylvania </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">DAVID BELL, Department of Population Sciences, Harvard School of Public Health, Boston, Massachusetts </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">LEONARD BERRY, Professor, Graduate School of Geography, Clark University, Worcester, Massachusetts </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">ERNEST J. BRISKEY, Dean, School of Agriculture, Oregon State University, Corvallis, Oregon </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">HARRISON S. BROWN, Director, Resources Systems Institute, East-West Center, Honolulu, Hawaii </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">ROBERT H. BURRIS, Department of Biochemistry, University of Wisconsin, Madison, Wisconsin </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">CLAUDIA JEAN CARR, Associate Professor, Conservation and Resource Studies, University of California at Berkeley, Berkeley, California </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">NATE FIELDS, Director, Developing Markets, Control Data Corporation, Minneapolis, Minnesota </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">ROLAND J. FUCHS, Chairman, Department of Geography, University of Hawaii at Manoa, Honolulu, Hawaii </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">ELMER L. GADEN, JR., Department of Chemical Engineering, University of Virginia, Charlottesville, Virginia </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">JOHN HOWARD GIBBONS, Director, U.S. Congress, Office of Technology Assessment, Washington, D.C. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">N. BRUCE HANNAY, Foreign Secretary, National Academy of Engineering, Washington, D.C. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">WILLIAM HUGHES, Director, Engineering Energy Laboratory, Oklahoma State University, Stillwater, Oklahoma </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">WILLIAM A. W. KREBS, Vice President, Arthur D. Little, Inc., Acorn Park, Cambridge, Massachusetts </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">GEORGE 1. LYTHCOTT, University of Wisconsin, School of Medicine, Madison, Wisconsin </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">JANICE E. PERLMAN, Executive Director, Committee for a New New York, New York City Partnership, New York, New York </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">HUGH POPENOE, Director, International Programs in Agriculture, University of Florida, Gainesville, Florida </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">FREDERICK C. ROBBINS, President, Institute of Medicine, National Academy of Sciences, Washington, D.C. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">WALTER A. ROSENBLITH, Foreign Secretary, National Academy of Sciences, Washington, D.C. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">FREDERICK SEITZ, President Emeritus, The Rockefeller University, New York, New York </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">RALPH HERBERT SMUCKLER, Dean of International Studies and Programs, Michigan State University, East Lansing, Michigan </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">GILBERT F. WHITE, Institute of Behavioral Science, University of Colorado, Boulder, Colorado </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">BILL C. WRIGHT, Assistant Dean for International Programs, Oklahoma State University, Stillwater, Oklahoma </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">JOHN C. HURLEY, Director</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">MICHAEL G. C. McDONALD DOW, Associate Director/Studies </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">MICHAEL P. GREENE, Associate Director/Research Grants </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P></FONT></BODY>
+</HTML>
Index: /main/tags/2.25/gsdl/collect/demo/import/ecourier/ec158e/ec158e.htm
===================================================================
--- /main/tags/2.25/gsdl/collect/demo/import/ecourier/ec158e/ec158e.htm	(revision 21064)
+++ /main/tags/2.25/gsdl/collect/demo/import/ecourier/ec158e/ec158e.htm	(revision 21064)
@@ -0,0 +1,2381 @@
+<HTML>
+<HEAD>
+<META HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=windows-1252">
+<META NAME="Generator" CONTENT="Microsoft Word 97">
+<TITLE>&lt;&lt;TOC1&gt;&gt; The Courier N°158-July- August 1996 Dossier Communication and the media - Country report Cape Verde</TITLE>
+</HEAD>
+<BODY>
+
+<B><FONT FACE="Arial" SIZE=2><P ALIGN="JUSTIFY">&lt;&lt;TOC1&gt;&gt; The Courier N°158-July- August 1996 Dossier Communication and the media - Country report Cape Verde</P>
+</B><P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">AFRICA-CARIBBEAN-PACIFIC - EUROPEAN UNION</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Dossier</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Communication and the media</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Press freedom, regarded as a fundamental human right, is also a key component in the democratization process.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">With the help of experts in the field, we look at what various organizations are doing to combat censorship and promote a free press in ACP countries and elsewhere.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">We also highlight the new trend of donor support for projects aimed at promoting press freedom. These include, notably, provisions for the training of journalists. And as new means of communication, such as the World Wide Web, develop, we consider what is being done to prevent the opening up of a new divide - this time between the 'information rich' end the 'information poor'.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Country report</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Cape Verde</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Among the least-developed countries, Cape Verde is seen as a model of good governance and stable democracy. It is also admired for its perseverance in the struggle against the exigencies of history and climate. The country suffers from almost permanent drought and has virtually no regular supplies of fresh water.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Its history has been punctuated by serious famines and while the people are no longer hungry, they still face formidable economic difficulties.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Cape Verde produces just 10% of what it consumes and its exports are one fifteenth of its imports. The one bright spot is in services, where it enjoys a positive trade balance. This sector (in particular, international transport and tourism), together with the country's cultural industries, offer the best hope for future development.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<B><P ALIGN="CENTER">&lt;&lt;TOC2&gt;&gt; Meeting point</P>
+</B><P ALIGN="JUSTIFY"></P>
+<B><P>&lt;&lt;TOC3&gt;&gt; Robert M&eacute;nard, Director of 'Reporters sans fronti&egrave;res'</P>
+</B><P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">'Combating attacks on press freedom</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">'Reporters sans fronti&egrave;res' was founded in June 1985 in Montpellier where Robert M&eacute;nard was working as a journalist with Radio France. Now based in Paris, RSF has two main policy areas. In the first place it alerts international public opinion and the media to situations involving violations of press freedom (via publications such as 'RSF News letter' the Annual Report and specific books and reports). Secondly, RSF actively intervenes by sending letters of protest to official bodies and assisting victims. Last year RSF dealt with more than 350 cases involving the press throughout the world. The organisation's ambition, according to Mr M&eacute;nard, is to be a kind of Amnesty International in the press field. The interview began with Mr M&eacute;nard giving a detailed description of RSF's work.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY"> - We do two things - we report violations of press freedom and help journalists who are the victims of such violations. Take the former Yugoslavia, for example. It would have been unthinkable to monitor what was going on in that war-torn country without, at the same time, helping the media who were victims of the repression. So we sent over lawyers to help in trials involving the press, helped the families of imprisoned journalists and gave general assistance to the media. In the case of Oslabodenje, the Sarajevo daily, this went on for four years. We did similar work in Rwanda where RSF helped the media to get back on its feet after the genocide. In Algeria at the moment we are involved in aiding  journalists who are obstructed when doing their work. We also give help in Europe - currently to refugee journalists in Belgium, France, Spain, Switzarland and Germany. That's basically what we do; reporting violations of press freedom and helping those who are the victims of it.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">· Do you work with other organisations, for example the United Nations ?</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY"> - We work with various types of organisations. We have daily contact with other NGOs specialising in press freedom, such as Article 19 in London and the Committee for the Protection of Journalists in New York, to give just two examples. We also have contacts with NGOs involved in human rights issues in general and, above all, with Amnesty International.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Then there are our links with international organisations and, first and foremost, with the UN system. RSF has submitted reports in response to requests from various organisations, ranging from the UN Committee for Human Rights to UNESCO. We also work with the Council of Europe and the Organisation of African Unity. But our closest  relationship is with the European Union, or two reasons; firstly because it is RSF's main financial backer and secondly Because the EU enables us to do three things. It has helped us set up and has Financed a vast network of correspondents in 130 different countries and, to my mind, this is the most important thing in terms of defending human rights and press freedom. We also publish reports, which we write in response to EU requests, on press freedom in one country or another and which are made available to the EU and European Parliament. Our third \ink comes in the form of assistance. We manage an aid fund to help where the press is in difficulties, and the money is provided by the Union.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">-You have mentioned a network of correspondents which has been set up. How does it operate ?</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY"> - It is a network of people who are in daily contact with RSF and who tip us off when a situation requiring our attention arises. Whenever there is a violation of press freedom in a country where the network operates, our correspondent lets us know - that's the first priority. Then, they make enquiries at our request. The third stage is to set up events. For example May 3 was World Press Freedom Day and, on that day, in about 20 countries in Africa, our correspondents organised events on the theme of press freedom. A fourth aspect of our correspondents' work is that they are often responsible on the ground for helping journalists in difficulty. They also help the media in general because we give them documents and supply them with information which they distribute in their particular country. Their task, therefore, is to alert us to a situation, meet our requirements for information and, on our behalf, physically to assist people on the ground, set up events and disseminate information.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">-Are the correspondents all nationals of the countries in which they work ? </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY"> - Yes. Also, about 90% of them are joumalists and they are all paid for what they do. Their relationship with us is clear-cut. It is very important for them to be paid because this means that   we can ask certain things of them. If you   work as a volunteer no-one can give you  a deadline to produce such and such a   document. In our case, we pay them to   do this work for RSF.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">· Do you choose countries where the situation is already problematic ?</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY"> - Unfortunately, problems exist in many countries. Less than half the countries in the world show any degree of respect for press freedom and that means we have a great deal of work. In addition, information arriving at RSF from the correspondents is distributed to other organisations. We have set up a system called Infex which is an electronic mailbox.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">All RSF's information is put on a computerised system and immediately disseminated to all the organisations involved in the defence of human rights, and press freedom in particular.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">· So the technological revolution is a positive thing as far as you are concerned ?</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY"> - Absolutely. Both the Imais and Internet systems are unbelievably useful tools which have completely revolutionised our work. For example, RSF might protest about the situation in some country or other. Take China, for example - we regularly lodge protests against the lack of press freedom there. There are 17 journalists in jail, no freedom for the press and a great many problems. However, people in China are not aware of what we do and in order to get information they have to listen to international radio stations. On the Internet, RSF's services are available in French, English and Spanish and it is consulted by people the world over. It is thus one of their sources of information. Another example would be a case where we set up an operation and inundate a number of people in a particular country with faxes, in order to pass on the information. Modern technology enables us to break down the fortresses which totalitarian or dictatorial regimes attempt to construct around themselves.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">- RSF has just published its 1996 Report. What do you have to say regarding the current position of press freedom ? Has progress been made ? </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY"> </P>
+<P ALIGN="JUSTIFY"> - I would say two things. In the long term, the situation is improving. If you remember, 25 years ago, the regimes in half the countries in Latin America were dictatorships, communism dominated half of Europe and nearly all of Africa had single-party systems. Even in Europe, there were dictatorships - in Spain, Portugal and Greece. So we cannot deny that there has been progress. The problem is that, for three or four years now, there has been a noticeable rise in new threats to press freedom, and this is a great source of concern to us. Here I am thinking of the rise in power of fundamentalist movements, particularly religious fundamentalism. In a number of countries nowadays - the best example, or perhaps I should say the worst example, is Algeria - journalists are not only threatened by the state but are being killed by armed Islamic groups. The rise in religious fundamentalism is indeed a real danger.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The second type of threat confronting the press is the increased influence of mafia-type criminals. You will, of course, have heard about drug trafficking in places like Colombia or Peru. Nowadays, in some countries where communism has been overthrown, the big threat comes from these criminal gangs. Not so long ago in Russia, the star presenter on the main TV channel was killed because he got in the way of 'Mafia' interests.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The third threat comes from uncontrolled actions by groups fighting for autonomy or independence, like the Kurdish movement in Turkey (the PKK), and a number of separatist groups in India. The EU is no stranger to this either</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY"> - ETA poses a continual threat to the press, as do members of the FLNC in Corsica. It is only a few months since members of the latter group machine gunned a journalist's house. A fourth and new kind of threat, particularly in countries with a democratic system, comes from the rise of the extreme right.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Lastly, a point I draw particular attention to in our recent report is, in fact, a dual phenomenon. On the one hand there are states which pass laws under which any criticism is a crime and may lead to prosecution. An example of this is Egypt where the government has enacted a law which has led to charges being brought against some 60 journalists since summer 1995. On the other hand, there are states where justice simply does not operate and there is no will to make it function.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Last year, 51 journalists were killed and a number of others were attacked, but there has not been a single trial or conviction. It is a real culture of impunity. In some countries, the justice system either does not operate, or it is not independent. In such places, the authorities are reluctant to identify and prosecute those responsible for attacks on journalists.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">· RSFcurrently has project running in Rwanda, in collaboration with the EU. Could you tell us something about this ?</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY"> - The EU is helping us to meet a wide range of needs in Rwanda, as well as in Burundi, where sadly, the situation is rather similar. In Rwanda, there are those who governed the country before the genocide and those in power at the moment. There was a specific problem there in that nearly half of Rwanda's journalists were killed during the genocide - 49 out of about 100. We had virtually to reconstruct the press system and the EU gave us the means to do this.The press currently has difficulties vis-&agrave;-vis the authorities but it is attempting to do its job.  in Burundi, where our work is of a more conventional type, we see continuing attacks on press freedom. There, RSF is trying to resist the pressure, again supported by the EU. In fact, thanks to the EU, we are helping a   number of countries' media to survive despite difficult conditions.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Another quite new problem is that before and during the genocide in Rwanda, the media were used as vehicles for disseminating hatred. They issued calls for people to kill their compatriots, in this instance the Tutsis, and the language they used was unbelievably violent. On Radio Mille Collines, presenters would say - and I quote; 'The graves are not full yet'. They would give out the addresses of people who had to be killed and when the murders had been carried out they would actually say, 'You killed them too quickly - you should have killed them more slowly to make them suffer more', or, 'You didn't kill the children, go back and kill the childreni. We actually have recordings of statements like this.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">In such a situation, journalists must be made to answer for what they have done and be brought to justice.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The EU has helped us conduct a number of surveys which will enable the international criminal court in The Hague to charge Rwandan journalists with complicity or incitement to genocide. We expect this to take place in the very near future.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Of course in Rwanda, all that is in the past but the same thing is happening today in Burundi where there is a radio station called 'Radio Democracy' - what a joke! A number of journalists there are issuing calls for people to be killed and we have a copy of one of their newspapers whose front page offers a cash reward to anyone who kills such and such a person. This is not journalism. RSF has lodged complaints against these people and one of these 'journalists' has just been charged.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">We are doing three things in Rwanda and Burundi: denouncing violations of press freedom by the authorities, helping media victims and - something new - reporting what has come to be known as 'the media of hatred'. Unfortunately, this type of media is not restricted to Rwanda and Burundi. it is a phenomenon that we see in a number of African countries, in the former Yugoslavia, the Caucasus and the</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Middle East. Perhaps you are aware that the 50th anniversary of the Nuremberg trials has just passed ? But did you know that there were two journalists among the accused? The press has forgotten that journalists played a part in the rise of Nazism. RSF is pointing out that the same thing is happening today in many countries and we have to fight it.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY"> 'The EU is a  perfect partner</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">· Given what you have just said, should restrictions be placed on press freedom ?</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY"> - This is a very complex subject. You have to remember that international texts, particularly the convention on civil and political rights, place restrictions on press freedom. Article 19, which defines press freedom, stipulates that there are certain limits to this and Article 20 forbids any dissemination of racist or antisemitic ideas and any incitements to violence.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">RSF has two things to say. First, governments which have signed the agreements must ensure they are observed. These set limits. Journalists are not above the law and they must be punished when they say certain things. So states must face up to their responsibilities and apply the treaties they have signed. Second, I feel that the international community, and Europe in particular - when it signs agreements or gives aid to third countries - should demand that they respect press freedom but clamp down on the media of hatred.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">· RSF has just published a draft model legislation governing the press. In preparing this, were you influenced by your experience of the extremist media ?</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY"> - Perhaps we were influenced too much. I am my own worst critic. We sent a mission to Rwanda before the genocide but did not appreciate the full effects of the evil disseminated by the media of hatred, particularly Radio Mille </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Collines. We underestimated the situation and are concerned at what is happening. We believe there must be express limits on press freedom and this draft framework law is one way of formulating such restrictions. It is not necessarily the best way of going about things, but our profession has to ask itself questions regarding the definition of press freedom and the limits we must not exceed. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">· Are you satisfied with what the EU is doing in this area ?</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY"> - The EU is a perfect partner and has never exerted any pressure. With the Union, we are able to do things that would not be possible with individual Member-State government because the latter conduct foreign policy in defence of certain interests. Each country has its own cultural history linguistic links or links arising out of former colonial times which prevent it financing RSF's studies unconditionally. As far as our missions are concerned, RSF decides what it wants to do and we send our reports to the EU. They have also granted us a budget enabling us to give immediate aid to people in difficulty. This is the most positive action possible If the EU were not there, there would unfortunately be no-one else to finance an organisation like ours. 60% of our budget comes from the Union, 20%from various companies. We generate the remaining 20% ourselves through sales of books and contributions. Because the EU is a grouping of governments, the Commission has some room for manoeuvre. This is the only possible kind of support for organisations like RSF and, if it were not there, it would be the end for the people whom RSF supports.  interview by Dorothy Morrissey</P>
+<P ALIGN="JUSTIFY"></P>
+<B><P ALIGN="CENTER">&lt;&lt;TOC2&gt;&gt; ACP</P>
+</B><P ALIGN="JUSTIFY"></P>
+<B><P>&lt;&lt;TOC3&gt;&gt; The economy of Cameroon: Better prospects but still a long way to go</P>
+</B><P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">It is an astonishing sight to behold during the rainy season. As you drive along the road from Yaound&eacute; to Bamenda, you come to a point where human habitation starts - and it then continues unbroken for more than 100 kiLom&eacute;tres. Just before Bafoussam, and as far as the eye can see, every patch of land is cultivated. Bananas, oranges, mangoes, sugarcane, cassava, palm trees, groundnuts and maize grow luxuriantly in open fields and in the front and back gardens of many houses. This route, of course, takes you mainly through the western part of Cameroon, home to the Bamilelr&eacute;s, recognised as one of the country's most enterprising and industrious ethnic groups. The population density here is 200 per km2 as opposed to 1 per km2 in the East.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The impact of this widespread farming, carried out by a large number of smallholders, is visible in the local markets, whether in Bafoussam, Mbouda or Bamenda. There, the stalls overflow with fruits and vegetables and prices are very low - a virtual paradise for the middlemen whose unmistakable presence is signalled by the significant number of trucks loading the produce for distribution throughout the country.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">These scenes come as no surprise to the long-time observer of Cameroon's economy. The country achieved virtual self-sufficiency in food over 15 years ago. It is one of the few African countries to have been able to do this, thanks both to its physical  endowments and an early recognition of its agricultural vocation.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Cameroon is often described as a microcosm of Africa, not just in terms of its make-up of English- and French speaking communities, but because it enjoys almost all the continent's climatic conditions. The south is equatorial, with two rainy seasons and two dry seasons of equal duration, the centre is Savannah country with one rainy season and one dry season, while the extreme north (part of the Sahel) is hot and dry. The country has a very good supply of rainfall - from 5000 mm annually in the southwest to around 600 mm near Lake Chad.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Such varied climates favour the cultivation of a variety of crops. Timber is  produced mainly in the southern provinces while palm oil, tea, cocoa, coffee, rubber, timber and foodcrops are produced in the southwestern and western areas. The central and north provinces specialise in cattle and cotton production.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Concentration on agriculture</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Cameroon has, not surprisingly, concentrated on agriculture. Indeed the government has given top priority to the sector in all its development plans   since independence in 1960. It has been involved in the marketing of the main export crops and has provided subsidies to farmers in the form of low-priced fertilisers and pesticides for their cocoa, coffee, rubber, palm oil, etc. Almost three-quarters of the working population (the majority of whom are smallholders) are engaged in farming. And despite a low level of mechanisation, they are very efficient. The rate of growth in food outstrips the rate of population growth. Only a few largescale farmers or firms are involved in the production of cash crops.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Until the early 1980s, when oil came into the picture, these large scalefarmers and firms amounted for more than 70% of export earnings, 40% of state revenue and 32% of the Gross Domestic Product. The plan initially was to use oil revenues to further boost and transform agriculture. However, the dramatic increase in the country's oil production, combined with much higher world petroleum prices during the first half of the 1980s, made the sector not only Cameroon's biggest export earner, but also, in a certain sense, a 'spoiler' for agriculture. Increased revenues enabled the government to maintain the level of prices paid to farmers, even though world prices had slumped to disastrous levels. This created distortions in the market. (Later, when the oil price slumped, and revenues dropped sharply, producer prices were also reduced, bringing them closer into line with international prices.)</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Agriculture's contribution to GDP declined steadily to around 21 % in 1985, rose to 27% in 1989 and has hovered around 30% ever since. The sector's share of export earnings has also fallen to about 40% of total exports by value.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Despite this, Cameroon's agriculture remains, comparatively, in a much better shape than that of most African countries. Indeed, it contributed in large measure to the country's reputation as one of Africa's economic successes in the 1980s. During that decade, growth averaged 8% per annum. However, the period was also marked by dramatic increases in oil revenues which induced  significant policy changes as well as leading to maladministration. The government paid less attention to taxation and customs duties as sources of income and turned a virtual blind eye to smuggling which harmed the manufacturing sector. The civil service, on the other hand, expanded beyond reason, a phenomenon that some have attributed to patronage by the ruling single party.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Boom in public expenditure</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Protected somewhat against fluctuations in earnings from export crops, by a strong but overvalued CFA franc, the government embarked on a wide range of capital expenditure and imports. Then, in 1987, international oil prices fell as dramatically as they had risen earlier in the decade. At the time, public spending was running at CFAF 8 billion - well above the CFAF 5.6bn the country actually earned. Revenues from oil continued their downward slide to CFAF4.5 bn in 1988, CFAF 2.8 bn in 1991 and CFAF 2.5 bn in 1994. 1995 saw a modest rise to CFAF 3 bn.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">1987 thus marked the beginning of a rapid deterioration in Cameroon's financial situation. In the period which followed, civil servants' salaries were unpaid for months, several of the country's foreign missions were left without resources and both domestic and foreign debts worsened. In 1993, the government owed commercial banks around CFAF 3.3bn. Its external debt stood at around $7.5bn with a service ratio of more than 25% of foreign exchange earnings. The devaluation of the CFA franc in January 1994 improved the internal debt situation significantly. In February, the government signed a letter of intent with the IMF after agreeing to a series of reforms which included, among other things, rationalising the banking and insurance sectors, raising revenue from non-oil sources, bringing inflation down and reducing the budget deficit. In return the IMF provided a stand-by loan equivalent to CFAF 1.4bn. However, the agreement was suspended just a few months later when the Fund reached the conclusion that the government lacked the will to carry the reforms through. The 1994/95 budget foresaw a deficit of 4.5% of GDP - well above the IMF's guideline of 1.5%.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Meanwhile the country's financial situation had become so critical that it could no longer service its debts, most notably, those it owed to the World Bank. France, which had traditionally been ready to come to the rescue, refused to bail Cameroon out and it finally dawned on the authorities that structural adjustment was unavoidable. When, in September 1995, talks resumed with the IMF, the commitment to adjustment was no longer in doubt. The government agreed, in addition to fiscal reforms, to liberalise trade in cocoa, coffee and timber, to prune the civil service and to privatise state enterprises which dominate the industrial sector.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Commitment to reforms</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Since then the reform process has been in full swing. The first and most important task has been to improve the government's financial position. The civil service, which employs more than 175000 people, is gradually being reduced and salaries have been cut. Trade is also being liberalised and subsidies are being removed. The 1995/96 budget, unveiled in June last year, was welcomed by the IMF. It included, for the first time in a long while, increases in income tax and a widening of tax bands. A series of measures have also been introduced to combat tax evasion and fraud. External signs of wealth, water and electricity consumption, and telephone bills are now being used as means of assessing income tax.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Responsibility for the collection of customs duties has been removed from the Customs Department which was often accused in the past of corruption and inefficiency. The task has been given instead to a Swiss-based preshipment inspection company. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The donor community has responded positively. With French assistance, the government has been able to clear its outstanding debt to the World Bank. The IMF has provided a stand-by credit facility of $101 million in support of the adjustment programme for 1995/ 96 and debts to the Paris Club covering the same period have been rescheduled. In addition, now that Cameroon has been reclassified as a poor country, it is entitled to benefit from the terms of the Naples Agreement, which allow for up to 67% of debts to western govemments to be written off. A number of creditor nations have either forgiven the country its debts or have reduced them substantially. More loans have come from France and a number of other donors, including the World Bank and the European Community.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The EC is financing a series of projects within the framework of the adjustment programme, including the restructuring of the civil service and preparation of the ground for privatisation.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Lately though, the donor community has been showing signs of disenchantment, following allegations of misuse of funds and perhaps even outright embezzlement. Last March, an IMF mission to Yaound&eacute; failed to obtain an adequate explanation concerning the allocation of certain sums. The result, at the time The Courier went to press, was that an IMF loan for settlement of Cameroon's debt to the African Development Bank was being held up.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Dealing with the negative social impact</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&lt;&lt;I&gt;&gt; p07a.png Figure</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The sudden devaluation of the CFA franc in January 1994 halved Cameroon's purchasing power overnight. The government has since cut wages twice. The average salary of a top civil servant, which stood at around CFAF 300 000 before devaluation, is now less than CFAF 180 000 while the lowest paid government employees receive just CFAF 30 000. At the same time, prices, particularly of imported manufactured goods and inputs, have risen sharply. Increases of up to 150% have been  recorded. By way of example, the price of a baguette (french bread), which was only CFAF 80 in January 1994 had risen to CFAF 130 by March 1996.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Although there is considerable hardship, Cameroonians are a great deal more fortunate than fellow Africans in many other countries undergoing a similar adjustment process. Staple food remains cheap and affordable to the vast majority, thanks to the continuing strength of agriculture. As a result, there are few, if any, cases of malnutrition.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">A number of donors, including China, Belgium and the EC, are concentrating on health and education with the specific aim of reducing the negative social impact of adjustment. The EC, for example, has a project designed to strengthen health provision at the grassroots. This entails rehabilitating  infrastructures (health centres and district hospitals in particular) and establishing medical supply centres in areas that are not covered by other donors. The project is governed by the principle of cost-recovery to ensure viability and sustainability. But one area where the donors cannot do much is in the field of job creation. There is growing unemployment and job prospects in the formal sector, at least in the short term, are not good.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">In macro-economic terms, things are locking up slightly for Cameroon. After recording economic growth of 3% in 1994/95, the hope is for a 5% increase in 1995/96. However, Cameroon's main economic operators, grouped under the umbrella of GICAM (Groupement inter-patronal du Cameroun), expressed fears late last year   that the country would not achieve this level of growth.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Cameroon exports a variety of primary commodities, most of whose prices have recovered in recent years, and devaluation has had a positive impact on the country's balance of trade. Specifically, it has helped make exports more competitive and in 1994/ 95 the trade surplus was a healthy CFAF 349bn, almost double the CFAF 128bn recorded in the previous year. There was a noticeable slowdown in the export of timber in the latter half of last year and the qualities of coffee and cocoa being sold were not up to the usual standard, a situation that led to both crops being shunned in the world market. Bananas exported to France were also meeting stiffer competition from French Caribbean bananas. However, the fact that rubber production has risen by more than 10%, while aluminium output and sales have increased, should help Cameroon to record another positive trade balance when the figures are next published.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The forestry sector, which has huge foreign-exchange earning and employment potential, is being rationalised as part of the current structural adjustment programme. The Canadian Agency for International Development</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">(CAID) has a five-year project to conserve and regenerate some 30 000 hectares. In fact, half of Cameroon is covered by forest and less than 500 000 ha is currently being exploited. The objective is to ensure that forest resources are exploited in the future at a sustainable level.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The private sector</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Industry, which is still in its infancy, has been developed by the government since independence largely with a view to import-substitution, although with some gearing towards the regional market. It accounts for about 14% of GDP and is currently dominated by aluminium smelting. Although devaluation has lately improved the competitiveness of those enterprises that add value to locally available raw materials, the manufacturing sector as a whole faces two major challenges now that the government has accepted the idea that the economy is best driven by the private sector.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The first relates to private investments, which have been sluggish  over the past ten years; a clear illustration of a lack of confidence in the economy. This was amply demonstrated when Cameroonians with funds abroad failed to repatriate them to take advantage of the CFAF devaluation as was widely expected. This phenomenon puts the whole privatisation exercise in jeopardy as it means that the government is more likely to have to rely on foreign entrepreneurs. The best the authorities can therefore expect in the short term, some observers say, is to convert those state enterprises that are not already joint-ventures into ones where private investors become the majority shareholders. Complete divestment will then take place gradually over a longer timescale. Overall, 150 state enterprises have been earmarked for sale.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">According to Andr&eacute; Siaka, director of Cameroon's Brewery, who is also Chairman of GICAM, another reason for the lack of investment was high interest rates. These hovered around 20% for many years. Even now, after the reform of the banking sector, interest rates remain very high and there are no borrowers, he told The Courier. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Donors again have been conscious of this and some of their interventions have reflected this concern. For example, Canada is providing funds for the establishment in Douala (the commercial capital) of a centre for the development of private enterprises. Meanwhile, the Chinese have promised to provide CFAF 7bn to enable a line of credit to be opened for small and medium sized enterprises.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The government itself is puting in place a number of incentives, according to Minister of Trade and Industry Eloundou Mani Pierre. The liberalisation of the economy and the reform of the customs regime in collaboration with UDEAC, to which Cameroon belongs, are part of these. Mr Mani told The Courier that with a population of under 12 million, Cameroun's most important market was Central Africa. He also, perhaps surprisingly, has high hopes for the new World Trade Aareement. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Cameroon meanwhile is reviewing its plan for the establishment of export processing zones with the help of its main donors.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">It is also looking at other ways of attracting foreign investment, particularly in 'value-added' enterprises involved in the processing of locally available raw materials such as cotton, cocoa, coffee and timber.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Social and political peace</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The second, and by far the more serious challenge facing manufacturing, is the problem of large-scale smuggling by petty traders.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Evidence of this abounds in the booming central market of Douala, where goods of all kinds can be found at very reasonable prices. Ironically the measures which were being taken and judged to be relatively effective against smuggling in recent years have had to be abandoned under structural adjustment rules imposed on the government.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">As Mr Siaka pointed out, petty traders dealing in smuggled goods put pressure on enterprises, 'because they do not pay tax', and threaten to render domestic manufacturing uncompetitive. It is also widely acknowledged, however, that the small-scale traders, who dominate the informal sector, provide job opportunities to Cameroonians, which is important at a time of economic austerity. Indeed petty trading has arguably been the safety-valve, helping to ease the social pressures brought about by structural adjustment, and thus preventing civil unrest.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">But the extent to which that safety-valve can withstand the emerging political pressures is a different matter. Democratisation, understandably, was one of the conditions imposed by donors for assistance to Cameroon. After a series of elections - presidential, legislative and municipal - which were marred by violence and deaths, there are still doubts about the health of democracy in the country. Indeed, there are signs that tension is  mounting. And few would dispute that if Cameroon is to succeed economically, it needs both social peace and political stability. </P>
+<P ALIGN="JUSTIFY">Augustin Oyowe </P>
+<P ALIGN="JUSTIFY"></P>
+<B><P>&lt;&lt;TOC3&gt;&gt; Jacques Santer commends regional  initiative  </P>
+</B><P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">by Alex Kremer</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Commission President's visit to West Africa</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The European Union's commitment to regional development in sub-Saharan Africa is as strong as ever, but sustainable development can only come from Africa's own initiative. This was the message delivered by Jacques Santer, President of the European Commission, in his address to African heads of state at the UEMOA (Economic and Monetary Union of West Africa) summit in Ouagadougou, Burkina Faso, on May 10.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">'I wish to emphasise from the start,' Mr Santer declared to the Presidents of Benin, Burkina Faso, C&ocirc;te d'lvoire, Mali, Niger, Senegal and Togo, 'that the European Commission and the European Parliament are both determined to make our partnership even more dynamic and in tune with today's rapidly changing world.'</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The presence of the Commission President at the UEMOA summit marks a milestone in the European Community's support for regional integration in the developing world. With its own Commission, Council of Ministers and Court of Justice, the UEMOA appears to be consciously  following the supranational model of regional integration pioneered by the European Union.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The sequencing of UEMOA integration, however, is almost the reverse of the European model. Already linked by a single currency in the CFA franc, the West African Union's member states are now pressing ahead with plans for integration of their 'real' economies. The implementation timetable agreed in Ouagadougou covers freedom of establishment, free movement of capital, mutual macroeconomic monitoring and the first steps to customs union with the harmonisation of external tariffs and the lowering or removal of intra-regional barriers to trade.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">President Santer indicated that the European Commission is keen to discuss how the European Development Fund (EDF) can support these initiatives. Such aid could take the form of technical assistance and training as well as direct budgetary support to mitigate the short-term costs of customs union.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">UEMOA is not, however, an aid project. Its member states have designed it to stand on its own feet financially from the start. A 'community solidarity levy' was due to come into effect on 1 July 1996. The money will be used for a structural fund programme beginning in late 1997, as well as to finance the Union's operating costs.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Meeting with the President of Burkina Faso, Blaise Compaor&eacute;, Mr Santer said that it was particularly significant that his first official visit to Africa as President of the European</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Commission was to Ouagadougou. Not only was it a reaffirmation of the partnership between Africa and the EU, and a statement of the EU's willingness to support regional integration in the developing world. It was also a tribute to the determination of the people of Burkina Faso and other African countries to promote their own development.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The European Community is Burkina Faso's second largest donor, contributing 10% of total aid payments in 1994. Since 1991, the EC has committed an average of ECU 45 million each year to development cooperation with this country, rising to a peak of ECU 100m in 1995.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Mr Santer visited the EDF-financed road improvement site at Tougan, close to the frontier with Mali, and noted that intra-regional transport links were an essential complement to the legislative programme of the UEMOA. He concluded his tour of regional cooperation projects with a visit to a photovoltaic pumping system financed by the EC under its West African solar energy programme.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Finally, on a more personal note, the Commission President was able to drop in on a project managed by the charity Chr&eacute;tiens pour le Sahel. Mr Santer worked for this Luxembourg-based organisation before starting his career in politics and he was visibly pleased to see that it was still going strong - supporting home-grown African initiatives with a little financial help from the European Community.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">A.K. </P>
+<P ALIGN="JUSTIFY"></P>
+<B><P>&lt;&lt;TOC3&gt;&gt; CTA - moving with the times</P>
+</B><P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">When the Technical Centre for Agricultural and Rural Cooperation (CTA) was inaugurated 11 years ago in Ede, Prince Claus of the Netherlands - whose interest in development issues is well-known - attestded as guest of honour. On 19 April, he returned to take part in the official opening of the CTA's new building in neigh bouring Wageningen in the Dutch province of Gelderland. The siting of the purpose built premises is significant. The town of Wageningen has long been an important European centre for agricultural research and the Dutch, of course, are renowned for their commitment to cooperation with developing countries.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The CTA may only have moved a short distance from its previous headquarters, but the Centre's 38-strong staff are also aware of the need to move with the times when it comes to fulfilling  their role in the field of agricultural information. This point was particularly emphasised by CTA Director, Dr. R.D. Cooke in his presentation at the opening ceremony. Recalling the Centre's main tasks (see box) Dr Cooke spoke of the 'changing horizons and challenges' which they faced, and he focused on four specific aspects.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The first of these is the big change taking place in national agricultural systems, with the state withdrawing more and more in favour of the private sector and NGOs. This is being accompanied by a trend towards decentralisation with the result that the CTA has many more potential partners to cater for and work with.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Global liberalisation has also had an effect on the kind of information being sought by the CTA's 'customers'. In the past, demand was almost exclusively for scientific or technical information, notably aimed at increasing productivity. Dr Cooke reported that while this remained important, there was now  an increasing interest in marketing and socio-economic aspects to facilitate decision-taking.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">It came as no surprise to hear the Director highlight the challenge posed by new technologies such as electronic networking and digital storage. The key point here, he stressed, was to find ways of adapting these to ACP needs and realities. 'In the next century,' he argued, 'the haves and the heve-nots will be defined by their access to information.'</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Finally, Dr Cooke referred to the growing significance of regional linkages. He indicated that the CTA was locking at ways in which it could help its partners to devise regional development programmes.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The declaration signalling the official opening of the building was made in the preceding presentation by E.F.C. Niehe who is Deputy DirectorGeneral for European Cooperation at the Dutch Ministry of Foreign Affairs. In his speech, Mr Niehe emphasised the relevance of the CTA, pointing out that while the world food situation had improved, 'we are now on the threshold of structural food insecurity'. He also spoke in more general terms about the future of ACP-EU cooperation and acknowledged that 'partnership, sovereignty and equality had been somewhat neglected' by donors. However, he suggested that these concepts were now 'coming back'.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">From the ACP side, the Swaziland ambassador, CS. Mamba,who is co-President of the Committee of Ambassadors, took up the theme of food shortages in sub-Saharan Africa and identified some of the difficulties encountered by African producers, particularly in respect of new technologies and marketing. He also referred to the environmental challenges facing ACP countries, especially in the Caribbean and Pacific. He was keen, however, to stress that the picture was 'not entirely negative'. Thus, for example, new technologies and methods had had a positive impact on grain production in Zimbabwe, horticulture in Kenya, and cocoa and coffee in West Africa. Mr Mamba echoed Dr Cooke in stressing the advantages of regional markets, and concluded with a firm statement of support for continuing ACP-EU cooperation.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">'History,' he said, 'will show that the Lom&eacute; Convention played a central role in the momentum of development.'</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The final speaker was Steffen Smidt, Director-General for Development at the European Commission, who suggested that the CTA had played a pioneering role in developing a sectoral  approach at a time when the focus of development cooperation tended to be on individual projects. 'The Centre', he said, 'has become a well-respected international institution in the field of agricultural information.' The Director General focused on the need for ACP countries to develop their own capacities and on the gap that exists 'between potential and reality', because of capacity limitations. The Centre, he believed, could 'help bridge this gap.' Mr Smidt also reiterated a point made earlier that the information flow should not just be in one direction. 'Information from South to North is vital,' he argued, to ensure better targeting of programmes in future.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">After the speeches, guests had an opportunity to learn more about the CTA's work by speaking to the Centre's personnel and visiting a special exhibition illustrating the nature and purpose of the Centre's activities. _</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Simon Homer About the CTA </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The CIA's tasks are: </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY"> - to develop and provide services which improve access to information for agricultural and rural development ; </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY"> - to strengthen the Opacity of ACP countries to produce, acquire, exchange and utilise information in these areas. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Programmes are organised around three principal themes: </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Strengthening information centres - designing strategies for improving agricultural information services; - promoting use of new information technologies; - providing training; - donating books. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Promoting contact and exchange of: experience among CTA's partners in rural development - seminars; - study visits. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Providing information on demand - publication s; - radio and audiovisual materials; - literature services for researchers; - Question and answer service. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">(The address of the Technical Centre for Agriculture and Rural cooperation can be found in the CTA section towards the end of the white pages in   this issue.) </P>
+<P ALIGN="JUSTIFY"></P>
+<B><P>&lt;&lt;TOC3&gt;&gt; Bananas, Hamlet and the Windward IsIands</P>
+</B><P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">By Martin Dihm</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">What do the Windward Islands' banana industry and Hamlet have in common ? Both are intrigued by the same question: 'To be or not to be.' But unlike Hamlet, whose fete was decided rather quickly and tragically, the future of Windward Canibbean banana production is still open. And what is more, Windward producers have a distinct advantage over Hamlet. They can hire consultants to analyse their problem and come up with fresh solutions. That is what has happened. But before turning to the solutions, what have the problems been ? </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The four Windward Islands; Dominica, St Lucia, St Vincent and Grenada, have long enjoyed preferential market access to the UK. This first permitted the creation of the industry and then secured its survival, even with production costs that are much higher than those of other producers.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">A traumatic moment came when the European Community had to decide on a common market regime for bananas. Coming into effect in mid 1993 the regime maintained the principle of preferential access for traditional ACP producers. Nevertheless, it introduced a move towards greater market liberalisation. Fierce attacks on the regime by certain of the EU's trading partners have raised doubts about its viability. The system is due, in any case, to expire in 2002 when even further liberalisation seems likely.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">All this could cause great difficulties for the Windward Islands which still depend substantially on banana exports to the EU. A decline in prices since mid-1993 and the appearance of new competitors in the previously protected UK market have further underlined the need for the Windwards to compete in a more liberal arena. The Islands commissioned a study, funded by the UK and the EC, into the competitiveness of their industry and on ways of improving its position. It was not the first study of this type, but earlier ones had had no real impact on the industry which had always been sufficiently protected to avoid swallowing the bitter pill of adjustment. This time, it was clear from the outset that action would have to be taken if the industry were to master the new situation.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The study provided a wealth of interesting insights and recommendations. The first big surprise - at least for outsiders - was the discovery that the industry was wasting considerable amounts each year through certain deficiencies in governance, management and production methods. The second theme of the study was the poor banana quality resulting from an inappropriate pricing system. In effect, price differences paid to farmers were not sufficient to reward extra attention to quality aspects.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The study's recommendations pertaining to management, production and quality were all agreed in a meeting on 29 September 1995, which brought together the Prime Ministers, the EC and other donors. Prime Minister Mitchell of St Vincent labelled this chance for the industry to get its business right as 'the last train to San Fernando'.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">What has happened since then ? After some hesitation, the industry has indeed begun to 'take up arms against its sea of troubles' (to return to the Hamlet analogy). The EC, for its part, has taken the part of Horatio, the faithful friend. Its role is a delicate one though - for the EC has a lot of money available. Take, for example, the ECU 25m allocated to St Vincent in the 1994 STABEX exercise (roughly five times that  country's national indicative programme). How are such funds to be injected reasonably into the islands without undermining their own strength and sense of purpose in pursuing the right strategy.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">To answer this, one has to look at the actual requirements. Streamlining the banana industry is less a question of big infrastructure projects than of providing expertise to guide the necessary structural changes. It also means fewer people will be employed in the sector. Aid should, therefore, focus on technical assistance, promoting diversification, and social 'cushioning'.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The challenge, of course, remains considerable and the outcome will not be known for some time. But it is clear that the Windwards have taken bold steps in the right direction and that further steps are on the agenda. There is also little doubt that the islands small, sweet bananas can only be competitive in their market segment if they are produced and marketed professionally, and with dedication.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">So what could Hamlet have learnt from this experience ? In short - get sound analysis and fresh advice from outside - and then boldly implement. And stick close to your good old friend, Horatio! </P>
+<P ALIGN="JUSTIFY">M.D.</P>
+<P ALIGN="JUSTIFY"></P>
+<B><P>&lt;&lt;TOC3&gt;&gt; British beef overshadows Development Council</P>
+</B><P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The most recent meeting of the EC`s Development Council was one of the first to be hit by the non-cooperation policy adopted by the UK in protest at the export ban on British beef. The Overseas Development Minister, Linda Chalker, announced at the outset to her fellow ministers: 'I will not be able to agree today to the adoption of those texts... on which unanimity is required'. Britain is seeking agreement 'for a step-by-step lifting of the export ban', which was imposed after scientific evidence suggested a link between Bovine Spongiform Encephalopathy (BSE) - and its human 'equivalent', Creuzfeld Jakob Disease. Cases of BSE have been recorded across Europe, but the vast majority have been in the UK.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Texts which were approved included a regulation on refugees in non-Lom&eacute; developing countries. This makes available ECU 240 million over a four-year period (19961999) for longer term assistance to refugees and displaced persons - mainly in Asia and Latin America. Also agreed were two three-year programmes covering Aids control and environmental projects respectively. They will cover the period 1997-1999, and each has been allocated the sum of ECU 45m. In addition, ministers confirmed a regulation on the criteria for disbursing humanitarian aid.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">But the British stance meant that a number of important resolutions were blocked, including a text on mounting projects which link emergency, rehabilitation and longer-term aid. Rino Serri, Italy's Under Secretary of State for Foreign Affairs who presided the Council meeting, said that once adopted, this approach would represent a 'qualitative leap for the EU's development policy.'</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Other resolutions awaiting approval relate to the strengthening of coordination between Member States, evaluation of the environmental impact of development policies, decentralised cooperation, and migration and development. Since good headway was made on these subjects despite the British attitude, the texts are expected  to be speedily agreed once the UK lifts its veto. Ministers also had an initial discussion on a paper presented by Commissioner Pinheiro on preventing conflicts in Africa.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">As is customary at these biannual meetings, several delegations raised points of particular national concern. Belgium, for example, is worried about the Commission's proposal which would finally establish the single market in chocolate products while leaving Member States the choice of adapting their legislation to allow a vegetable oil content of up to 5% in chocolate. Belgium feels that this approach could ultimately prove harmful to cacoa-producing countries and claims that it will be difficult to control the exact percentage of oil used. Sweden, meanwhile, wants action to reform the UN institutions while Italy is keen to increase public awareness of development policies. Finland emphasised the need for better coordination between the European Community and its Member States on environmentally sustainable projects.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The Great Lakes region</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">There was backing for the June Round Table meeting on Rwanda organised by the UNDP, as well for the various diplomatic initiatives aimed at bringing stability to the Great Lakes region. On 27 May, the ministers dined  with Emma Bonino, the European Commissioner responsible for humanitarian issues, and with former US President, Jimmy Carter, who has played a major role in the search to find a solution to the region's problems. Others active in this effort include South Africa's Archbishop Tutu, and former Presidents Nyerere and Tour&eacute; of Tanzania and Mali respectively. Ministers also commended the efforts of the UN and the OAU.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Mr Serri said there was a 'desperate need for a ceasefire' in Burundi and called for a 'speeding up of the peace process and full deployment of available humanitarian and development aid.' He told journalists it was vital for the EU to make special efforts to strengthen the judicial systems in Rwanda and Burundi - 'so that the justice system can work properly and identify those responsible for the genocide.' He pledged that 'substantial resources' would be made available once peace is secured. Ministers also called for a control of arms sales to the region, although they have no power to legislate in this area, which remains the preserve of the Member States.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Outside the meeting place, Senegalese fishermen and NGOs joined forces to mount a protests against the effects of traditional EU fisheries agreements. These provide financial compensation to governments in exchange for access to their waters for EU vessels, but the protesters claim that they harm local fishing industries and disrupt food supplies. A significant number of agreements are due to come up for renewal later this year. NGOs are lobbying for a new and 'fairer' type of accord which provides for catch reductions, more selective fishing methods and the employment of locally-hired fishermen on EU boats. These proposals are all set out in a paper entitled 'The Fight for Fish: Towards Fair Fisheries Agreements,' published by Eurostep, a Brussels-based NGO. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">D.P.</P>
+<P ALIGN="JUSTIFY"></P>
+<B><P ALIGN="CENTER">&lt;&lt;TOC2&gt;&gt; Country report</P>
+</B><P ALIGN="JUSTIFY"></P>
+<B><P>&lt;&lt;TOC3&gt;&gt; Cape Verde </P>
+</B><P ALIGN="JUSTIFY"></P>
+<I><P>&lt;&lt;TOC4&gt;&gt; Making the best of history </P>
+</I><P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Cape Verde has been shaped by the harmattan, the hot dry wind which blows from Africa, strong ocean currents and five hundred years of Portuguese colonialisation. Portugal has been a constant presence in the archipelago's history since the fifteenth century, when it granted the colonists who were to settle on the islands of Cape Verde a monopoly over the slave trade. The country became an interface between Africa, Europe and the Americas, at the centre of the triangle of trade in slaves, hardware and gold. The intermingling of black populations of every origin who  passed through the islands meant that the country was unable to present a united face against the colonialist culture. The colonists were therefore able to impose their own culture, with their fervent and proselytzing Catholicism becoming the principal ingredientin the mixture that is Cape Verde. Strong, scorching winds from the desert have shaped the islands' landscape and inhospitable ocean currents mean that approaches to the islands are difficult, their rocky cliff faces plunging into the sea.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The mythical Portuguese colonial oasis</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Up to the eighteenth century, Cape Verde was no more than a commercial centre for Portugal, its population at the end of that century barely exceeding 50,000, to be halved by the great drought between 1773-75. Other periods of drought regularly decimated the population and the arrival of new colonists and slaves did not offset such losses or compensate for the massive exodus which began in the early nineteenth century with the arrival of American whalers in search of crew members for their ships. Seven hundred thousand Cape Verdians currently live abroad, half of these in the United States.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Only four hundred thousand  have stayed in their own country.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">At the beginning of the twentieth century, a period which signalled a turning point in the country's history, the population still numbered no more than 150 000. At the time, major sea voyages were being undertaken and Cape Verde's geographical location was highly valued. Mindelo, on the island of S&atilde;o Vicente in the north of the archipelago, developed as a coal-and-watersupply port for English vessels plying the route between India and the Americas, and England helped construct this port. However, Portugal's policy towards Cape Verde was double-edged. On the one hand, the islands were regarded as a natural extension of the home country, but as a competitor in terms of port activities. This led to Mindelo's slow development, although the trade in  skins, fishery produce, coffee and salt  could have made it a thriving centre. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">A</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The mixing of races in Cape Verde has often been held up as, so-to-speak, 'humane colonisation', but this opinion is not corroborated by the under-developed state of the country at the time of independence and the fact that Portugal implemented food security measures to combat the ravages of catastrophic famines only when under pressure from public opinion, at the end of the first half of the twentieth century. The island's colonists had always used slave labour to produce food or fabrics which enabled them to purchase more slaves and it was only when the slave based economy began to decline, which   resulted in the impoverishment of the colonists, that a major grouping of free Blacks and rebel or emancipated slaves came into being. That is when the intermixing of races began. Therefore, before the abolition of slavery (18641869-1878), the vast majority of the black population of the island was free; both unmarried and married colonists would generally emancipate their children born of a secret relationship with female slaves. The aristocracy and white upper-middle classes continued to live a cloistered, aloof life and did not mix with other races. A second factor which would suggest that Portuguese colonisation of Cape Verde was sympathetic in outlook is the reputation of this small country's intellectuals; although colonisation created only a small intellectual elite which was the product of a single institution, the Mindelo College, opened in 1917. In a quote by Michel Lesourd, Deirdre Meintel refers to this phenomenon as the mythical 'cultural oasis'. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">A nation born of a middle class in tatters</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Through its contradictions, it was this black, mulatto and 'petty white' middle class which was to forge the mixed-race culture and national identity, caught between its own privileges and its aspirations of aristocracy, between its rejection of African culture (they sought a 'lusotropical' culture) and the need to find allies amongst the lower classes who retained African cultural values. In order to acquire the wealth and attributes of power, this middle class was to take over the lands vacated by the decline of the slavebased economy and which were often much improved by the former slaves (renamed 'tenant farmers' without a major change in their living conditions) preventing a major economic upheaval which could have put an end to this iniquitous system. Their wholesale appropriation of land explains why, today, there is a very high proportion of landless farmers in Cape Verde, seasonal agricultural workers who survive only thanks to the State's welfare system.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">This petty bourgeoisie was to give birth to growing awareness which would lead to calls for independence. Officially, Cape Verde was not a colony but a province, and its inhabitants in theory had the same rights or lack of rights as Portuguese citizens in Salazar's 'New State', where the right to vote depended on social and cultural status. In other Portuguese territories, members of the petty bourgeoisie held the rank of colonial administrators and, from their ranks, the pro-independence movements emerged. Such was the case of the PAIGC (Guinea-Bissau and Cape Verde pro-lndependence Party), created by Amilcar Cabral, a symbolic figure in Africa's striuggles for independence and Cape Verde's national hero. He was assassinated in mysterious circumstances in Guinea-Conakry in 1973. His brother, Luiz Cabral, was to become president of Guinea-Bissau, and Aristides Pereira his successor as Party leader and Cape Verde's first president.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Cape Verde's uneventful transition to independence in July 1975 mirrored Portugalts Carnation Revolution and was quite unlike the fierce war entered into by Portugal in Mozambique and Angola. There was a clandestine struggle during which a number of combatants were imprisoned, but there was never any real guerilla warfare. The Portuguese governor remained at his post until he was replaced by an ambassador. The PAIGC was to govern both Guinea-Bissau and Cape Verde until the coup d'&eacute;tat against Luiz Cabral in Guinea-Bissau in 1980, when it adopted the name of PAICV in Cape Verde, thereby signalling the end to any dream of a union between the two countries.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Diplomatic ventures</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The new state pursued an even-handed diplomatic approach and accomplished the considerable diplomatic feat of remaining equidistant between the Cold wer's principal adversaries, adapting over time to all the changes which occurred on the world  scene. Post-independence, embassies were opened by the United States, China and the Soviet Union. Cape Verde, with its marxist leanings, maintained the former links created with apartheid South Africa by Portugal. The arrival in power of a liberal party had no effect on this diplomatic tightrope-walking act. It was South Africa which was to provide aid to build the international airport at Sal. Ironically, after the establishment of democracy in South Africa, it was at this very airport that President Mandela was to stress his desire for strengthened links with the archipelago. Latterly, Cape Verde has demonstrated this flexible in its recent decision to Join the group of, French-speaking countries whilst still regarding itself as a mouthpiece for the Portuguese-speaking world, enjoying a privileged relationship with Portugal, the Azores, Brazil and African countries where the official language is Portuguese. It is also a very active member of the CEDAO (Community of West-African States) and its President is currently chairman of the CILSS (Inter  national Commitee to Combat Drought). Cape Verde receives as much aid from China as from the US, from Russia and Sweden as from Cuba and Japan.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">This diplomacy is in keeping with the atypical 'Marxist' Party which first initiated it. With its interventionist approach to economics, its highly developed social policy which gives priority to education, health and combating unemployment through public welfare, this party could be regarded as a socialist party, yet it opted decisively for a market economy. Its single-party structure mirrored the example of would-be popular democracies, but it never set up a system of repression and terror: only one opposition member's death is said to have taken place in suspicious circumstances on the island of Santo Antao. The population was able to discuss politics at popular assemblies and held no fear of openly criticising the government and, in the case of the well-off, of displaying its wealth. A mudan&ccedil;a (change) was implemented calmly and collectedly by the PAICV when it was in power, sowing the seeds of its own downfall. With no pressure from street demonstrations and no insistent demands from political classes, the government of President Aristides Pereira and Prime Minister Pedro Pires adapted to the new situation created by the fall of the Berlin Wall. In early 1990, the PAICV gave up its privileged position as the single party and, one year later, at the legislative elections in January 1991 and presidential elections in February 1991, Africa witnessed the first democratic overthrow of a single-party government which had achieved independence. After the legislative elections, the PAICV, which had placed too great a reliance on being credited for its good governance, was silenced. The desire for change was too great and the position adopted by the Catholic church, anxious to punish a party which had dared to opt for a referendum on abortion, did the rest. President Aristides Pereira's personal prestige stood for little in the full face of this onslaught.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">What change?</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Prime Minister Carlos Veiga, who had founded the MPD only eight months before his overwhelming success in the 1991 elections, became the new figurehead in Cape Verde politics. His power sharing with Antonio Mascarenhas Monteiro was again successful at the most recent elections (December 1995 and January 1996). Shortly before the poll, the MPD experienced a near-fatal split, but the new party which emerged, the PCD, had only one representative as against 50 (an absolute majority) for the MPD and 21 for the PAICV, which continued to exist. Three other parties taking part in the elections fell by the wayside and the polarisation of Cape Verde's politics into two camps locks set to continue. This is the second time that the MPD has surprised its opponents - this time, the political adversaries had attacked the MPD's attempt to curry favour, but the majority of the electorate, concentrated on the island of Santiago, continued to show their appreciation of the visible signs of modernisation in their lives and also the government's seductive politics, particularly in the ran-up to the elections. The country had also had a good harvest and, although this was unconnected with the MPD, that party could only benefit from it.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Despite what MPD leaders might say, there has been no real ideological split, any political reorientation having been instigated in 1990 by the previous regime when it threw off its socialist trappings. Diplomacy remains  pragmatic and the new government's liberal rhetoric and social policy, particularly in the areas of education and health, has essentially been maintained. Suspension of the State's collective works programme, the symbol of the State's interventionist social policy, is only temporary, according to statements issued by the Prime Minister, counter to several rumours.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">More visible changes have taken place in the economy: partial liberalisation of the banking system; legislation relating to foreign investment; suspension of the requirement for preliminary import authorisation; despite the government's backtracking as regards certain basic products; privatisation of State assets, particularly in the hotel business, etc. Here, too, the PAICV government engineered the changes, but it can surely not be criticised for maintaining a delicate balance between the new demands of the global village and the social practices of a country which is very poor, but which is succeeding in putting an end to its poverty and creating a modest quality of life, but a secure one. Given its bleak geographical location, Cape Verde is simply  continuing to make the best of history. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">H&eacute;gel Goutier</P>
+<P ALIGN="JUSTIFY"></P>
+<I><P>&lt;&lt;TOC4&gt;&gt; The economy: too weak to worsen</P>
+</I><P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The arrival in Praia on 30 April of a throng of IMF officials cannot have failed to cause the government some concern, despite its air of calm. Ministers repeated publicly that Cape Verde had already carried out its own programme of structural adjustments, that they were on the same wavelength as the Bretton Woods institutions, and that they could not, therefore, see any reason why any further adjustments  should be imposed upon them. Nevertheless, the fact that the Cape Verde escudo has had rather a bumpy ride since last year's elections, trading sometimes by as much as 15% under its official rate on the parallel market, caused a certain degree of anxiety within financial circles, with the banks taking action by freezing certain credit facilities.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The government insists that this situation has by no means arisen because of a sudden anxiety raised by opposition parties as to the effects of possible devaluation The truth is that there is a genuine structural imbalance caused by the trade deficit, a disequilibrium which is only being partially offset by official development assistance and the transfer of currency by Cape Verde emigres. As a percentage of the GDP, the overall budgetary deficit has tripled between 1993 and 1994 (increasing from 3.3% to 13.6%). For a country which could always be relied upon to pay its debts promptly, Cape Verde is now, for the first time, in arrears with its payments (see the 1995 report of the Bank of Portugal). The servicing of external debts represents 25.7% of goods and services exported - although these are relatvely small compared with neighbouring countries - the country's total outstanding debt is now nearing $200 million.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Although Cape Verde is one of the LDCs (least developed countries) with a total GNP of approximately $850 per capita, out of a total of 174 States, it actually ranks 123 in the Human Development Indicator Tables, which take into account various factors such as life expectancy, education, etc. Its position near the middle of these tables clearly shows that, although the country is poor, its affairs are nevertheless being managed fairly efficiently. Boasting an adult literacy rate of 66% and a life expectancy of 64.7 years, Cape Verde is well ahead of those countries at the bottom of the list, which include a number of its Sahelian neighbours. Efficient administration of the State and the absence of rampant corruption are further feathers in the nation's cap. These achievements have earned Cape Verde much esteem from its sponsors, which goes to explain the prudence of the Bretton Woods institutions and their relative sympathies towards the country.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Unkind Mother Nature</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Cape Verde's history has been punctuated by great famines. Between the sixteenth and nineteenth centuries the country suffered no less than 30 famines, with this century seeing some of the cruellest: 16 000 people died in 1903-1904, the death toll in 1921 was 17000, in 1941-43 it was 25000 and between 1946-48 famine claimed 20 000 lives - a figure which at the time represented 20% of the total population of the archipelago. After the last famine, the colonial authorities, under pressure from international opinion, adopted food programmes which made the country more able to cope with the consequences of subsequent droughts. The last great famine ended 50 years ago. The nation may no longer be hungry, but the factors which make its inhabitants' lives so difficult remain. The  main reason lies in the country's geography. Cape Verde has virtually no permanent springs and the topography of most of the islands, which are very mountainous, means that heavy rain simply runs down to the sea, the parched soil being unable to absorb it sufficiently. What is more, these downpours simultaneously wash away the little arable land that do" exist, thereby aggravating erosion. The whole situation is further worsened by the fact that the winter in this Sahelian region is very short. Despite huge efforts by successive governments, barely half the population has access to drinking water, with this figure barely reaching 25% in rural areas.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">With a population of less than 400 000, there are just not enough people to pull off the miracle of making such an unforgiving soil bear fruit. Hence, although providing 50% of all jobs, agriculture represents only 17% of the nation's gross domestic product and produces only 10% of food consumed locally. The mountainous islands that make up Cape Verde are like teeth jutting out of the sea, and with virtually no continental shelf to speak of, small scale fishing is extremely difficult. Even with industrial equipment such as that installed on board large trawlers, catches are small - so small in fact that the country's fisheries agreement with the European Commission brings it only one million ECU over three years, one tenth of the proportional amount earned by neighbouring Senegal. Fishing thus represents less than 4% of the GDP.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Mere survival - a</P>
+<P ALIGN="JUSTIFY">Herculean task</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Transport difficulties are another handicap for the economy. The sheer force of the harmattan, the strong ocean currents and the fog which often covers the region, make journeying by boat between the islands frequently hazardous. In addition, the volcanic relief of the islands makes them difficult to reach and means that there are very few locations that make suitable har  bours. construction is both complex and costly due to the steep rocky barriers that seal off deep valleys. Those roads which have been built under the FAIMO scheme (Highly Labour-lntensive Projects) have sometimes turned into real labours of Hercules, and many areas, especially those on sparsely-populated islands, remain completely cut-off. The use of aeroplanes only partly solves the problem. Although competitive, the prices charged by the national airline, TAICV, are still too high for the average inhabitant.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Not only does the soil on Cape Verde contain very little water, it has virtually no natural resources: a few stones, lime, pozzolana and a little salt. Within the manufacturing sector (which makes up less than 20% of the GDP), only the construction and civil engineering industries, representing more than 10% of the GDP, contribute in any significant way to the economy, thanks partly to the transfer of currency from emigres who invest in the construction  sector and works with wide public interest. These works, known as FAIMO schemes, have to some extent given this impoverished country a gloss that masks its poverty. Launched after Cape Verde gained its independence, they employ more than 25 000 people for up to ten months of the year in the construction of paved roads or in reafforestation projects, and ensure the survival of one hundred thousand people - over one quarter of the population. The workers are on the whole recruited from among farm labourers, with another large section of the workforce being made up of 'Solteiras' or 'single women', numerous in a country where the male population is constantly emigrating. Unfortunately, the liberal option adopted by the present government has cast some doubt as to whether these projects will continue and this year, for the first time, work ceased in April - three months ahead of the usual termination date. Yet the poor wages which these seasonal jobs pay (ECU 2 per day) are sometimes the only source of income for some families.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Only the tertiary sector shows a healthy balance of trade, accounting for  more than 60% of the country's gross domestic production, with the biggest slice of the sector going to the hotel industry, followed by the transport industry. Although, overall, Cape Verde's balance of trade records a large deficit, the balance of trade for the services sector generally shows a profit, with the transport services provided by the international airport, Amilcar Cabral de Sal, alone accounting for 13% of exports.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY"> Barely 10% of commercial goods are domestically produced and this has at times fallen below 5%. Cape Verde is therefore genuinely dependent upon foreign aid. Official development assistance represents 27.8% of the GNP (1989 figures), having risen from 17.7% to 27.2% of the GNP between 1980 and 1986. Cape Verde also relies on a second source of income - its emigrant population. In 1990 the currency transfers of its emigres represented nearly 20% of the GNP. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The colonial heritage</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Contributing too to the country's poverty are relatively low educational standards. In this area too, successive governments have continued their predecessors' efforts to improve standards of education. However, at the time the country achieved independence, it was in a deplorable state. The reputation of a small intellectual elite of Cape Verdians had, over several decades, led the world to believe that Portuguese colonial rule had been 'enlightened'. This was a mere illusion. It was not until 1917, when the Mindelo grammar school was founded, that the country was able to claim an educational establishment of any cultural sophistication. The Mindelo school was the first state school in the country and it was to provide the nation with its first batch of 'home-grown' intellectuals. Until the middle of the nineteenth century, the Church, which was in charge of all matters educational, had provided basic primary education; then, at the end of the last century, it opened two secondary schools with the purpose of training students for positions in government and the civil service.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Even so, the Mindelo school remained an exception until the middle of this century. In 1950, no more than 5000 children received primary education and no more than 400 went to secondary school. Thirty years earlier, the figure was slightly higher, but Salazar, with his retrograde ideologies, saw education as dangerous and threatening and trimmed the number of schools on the islands from 150 to 60. True, Cape Verde was undoubtedly in a better state than other Portuguese colonies, but, with an illiteracy rate of 80% at the beginning of the 1960s, its position was nevertheless far from enviable. It was not until independence that any real progress was made, with 60% of children attending primary school in 1989 (the average for LDCs is 54%). However, this figure is still well below the average for developing countries, which stands at 90%, and even now, only 13 % of children have access to secondary education. As for higher education, this is virtually only available abroad; in Europe, Brazil, USA and Cuba, in particular.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Serious health problems still exist, exacerbated in particular by the scarcity of water. The cholera epidemic which has struck several African countries over the last two years has killed over 150 people in Cape Verde. The prevalence of AIDS exceeds the average for sub-Saharan Africa, with more than 2000 people being HIV positive and with some one hundred having developed the full-blown disease. According to official figures, 70 have died of the disease. The cholera epidemic which, unlike previous epidemics has affected towns much more than rural areas, is a sign of the deterioration of sanitary conditions in towns - particularly in Praia - affected by a lack of water, a dilapidated sewerage system and overcrowding.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Anchoring the country's economy in its culture</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Yet, through all the doom and gloom, a small miracle is taking place in Cape Verde. Despite such a heavy burden of poverty, the country has, since gaining independence 20 years ago, managed to clamber up the league tables notably in the essential areas of health and education. Life expectancy at birth, which was only 52 years in 1950,  had increased in 1992 to 64.7 years, better than the average for developing countries and 13 years more than the average for sub-Saharan Africa. The infant mortality rate which stood at 110 per thousand in 1960, had dropped drastically to 50 per thousand by 1992, while virtually all children now receive essential vaccinations. Malaria is also now rare. In 1988 the GDP of Cape Verde amounted to only C.V.Esc 20 billion ($289 million), in other words, 6.9% of the GDP of Trinidad and Tobago, and 16.6% of that of Mauritius. But it is growing steadily. From 1980 to 1988, it grew by 6% per annum, compared with 3% per annum for the Sahel, and since 1980 the GDP per capita has doubled.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The solution the nation's leaders should be seeking is greater integration in the global economy context by encouraging foreign investment. They do not need to create free zones but free enterprise, such as the shoe manufacturing concerns which, over the last two years, have contributed to achieving a considerable increase in exports. Various steps have been taken to attract investors, such as the adoption of the principle of tacit acceptance of applications for investment within 30 days. The Prime Minister, Carlos Veiga, and the 'Super-Minister' for Economic Coordination, Antonio Guelberto do Rosario, have highlighted the service, tourism and fishing industries as top government priorities. In order to develop these areas they intend to invest in infrastructures, with the aid, of course, of foreign backers. The modernisation of the port of S&atilde;o Vicente and of the international airport of Sal are currently underway, and the telecommunications project to link the islands by cable has also already been launched. The government's short-term plans also include the development of industries connected with the islands' culture. In the words of Mr Veiga: 'We in Cape Verde should develop our culture and use it as our anchor, to prevent our country drifting into oblivion. That way, our tiny country, which is fortunate enough to have a strong cultural identity, will be a Nation rather than a just a State'. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">H.G. </P>
+<P ALIGN="JUSTIFY"></P>
+<I><P>&lt;&lt;TOC4&gt;&gt; Interview with President Antonio Mascarenhas Monteiro</P>
+</I><P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">A wealth of culture and a realistic approach to diplomacy: Cape Verde's two major assets</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">- How the current government differ from the former administration which had Marxist leanings ?</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY"> - The two eras are distinct from each other in that, since 1990, the Cape Verde people have been able to choose a life of freedom and democracy. Before that, for the   first fifteen years after independence, there was a single-party system. So it is also valid to speak of a break - a break with the way in which institutions used to function at a political level.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">-The single-party era does not seem to have been as strict as in other countries and the current regime appears to be continuing along the same lines in some areas. Was the former administration not, to some extent, responsible for initiating the change which has taken place ?</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY"> - No, that's something else entirely. I often say that we had a civilised single party, and I assume that is what you are referring to. However, it is not possible to speak of continuity when formerly we had a single party and now we have moved on to a system where there is freedom of expression and new parties can be set up. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Admittedly, the single party did initiate a change when it created the conditions necessary for the advent of democracy. It removed the infamous Article 4 from the constitution, which seates that the PAICV was the guiding force of society and the state. In fact, it was the PAICV which drew up the country's first electoral laws whereby we were elected. When I say 'we', I mean the party which is in power and also myself, President of the Republic. The single party thus opened the way to  democracy here: that much is undeniable.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">-Am I also right in thinking that many of those who are in power today received their training in that single party ?</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY"> - You are quite correct. When a change such as this comes about, one has to appreciate, and I do not wish to be elitist here, that it is the higher echelons of a party which lead the move towards change. Such people were there, working in the administration.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">-Since politics gives direction to economic affairs, has there been a total turnaround in this sector, with a clear decision to opt for liberalisation and privatisation ?</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY"> - Before 1990, we had a staterun economy. After that, the country's economy was opened up with a number of privatisations, fewer import restrictions, and so on. The word 'break' is also applicable in this area in that we now have a market economy.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">-Do you feel that the economy has really shaken off state control given that the govemment still manages important sectors, such as the price of raw materials ?</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">That is necessary a market economy does not mean that the state is entirely absent. I am in favour of a market economy, but with state monitoring. As far as possible, the state has to correct the injustices which are necessarily generated by competition. This is not, as some would have it, ultraliberalism. The government is still entitled to monitor the economy, but the change has been greatest in terms of attitude, in terms of the way things are done.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">-Do you, like many leaders of developing countries, believe that the requirements set by international institutions as regards structure/ adjustment are too great ?</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY"> - We are not subject to compulsory adjustment - it is on a voluntary basis here. However, I do feel that adjustment, as implemented in Africa, sometimes has regrettable aspects. On occasion, it is asking a little too much to impose the same requirements on countries whose actual situations are very different. What is applicable to Nigeria is not necessarily suitable for S&atilde;o Tome.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">-The 1992 constitution switched Cape Verde over from a presidential system to a parliamentary system. As President of the Republic, do you fee/ trapped by this constitution ?</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY"> - Cape Verde's constitution was never a presidential one. The system under which I was elected is effectively 'semi-presidential'. Admittedly, the constitution which was approved by Parliament in 1992 reduced the powers of the </P>
+<P ALIGN="JUSTIFY">President, particularly as regards the right to dissolve Parliament - which was unrestricted in the 1980 text. The revision was made to permit democratisation and ensure the proper functioning of the institutions, and it was therefore fairly wide-ranging. Now, in order to dissolve Parliament, the President has to have the support of the Council of the Republic, which means that his hands are tied to some extent. Previously, the President could also dismiss the government, without too many restrictions. I would say that the President's prerogatives have undergone a substantial reduction in comparison with those exceptional powers. As for the rest, things are as they were. In a semi-presidential regime as that envisaged by the 1980 constitution, the President has no executive role.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">· You seem to have chosen to play the role of 'wise man' Some observers think you give the Prime Minister too much leeway.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY"> - They are wrong. The Prime Minister's post is conferred on him by the constitution. He is Head of Government and it is he who governs. I cannot govern in his place. What is true is that there is a great deal of ignorance - people do not restrict themselves to their own fields and attempt to teach lessons in subjects they are unfamiliar with. Germany has a parliamentary  regime like we do - what is the position of the President of the Republic in Germany? If you were to ask a Cape Verde intellectual for the name of the President of Germany, he would be unable to answer you. The parliamentary regime does not give the President of the Republic any powers to run the country. I do not know what the Prime Minister can have taken away from me because I have no power for him to take over. However, I would say that, here, the President of the Republic does have a fairly high profile, in spite of his reduced powers, because all the country's citizens know him. In terms of foreign policy, he plays a significant role in that he represents the country abroad. I attend international conferences like the Rio Summit, go to meetings of the OAU and sign international undertakings on behalf of my country.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">· The President is also the guarantor of the new democracy, which observers seem to regard as well-established. But there still seem to be some bad habits. For instance, I have heard criticism of MPD power and of the fact that state  resources are made available to one party at election time.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY"> - Look, this is criticism from the government's opponents - it is a normal state of affairs and happens everywhere. Any party, in any country, which has a parliamentary majority, can govern easily. This is possible, even when the majority is very small - and even in Europe. Look at Portugal when Cavaquo Silva was Prime Minister. There were people who said it was a PSD State. You will be familiar with France when Pompidou and even de Gaulle were in power, and Francis Mitterrand used to speak of a Gaullist state. As far as the election campaign is concerned, I am not aware of the government here having monopolised state resources and I don't believe this has happened.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">· Another important factor involved in democracy is the press. Several journalists from the private media sector are awaiting a decision from you on a number of points - for example the lack of pubic support for the private press - in contrast to thestate-run press which has access to all that it needs.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY"> - What decision are they waiting for ? Do they want me to decide in favour of resourcess being given to the private media ? I have already done that on a number of occasions. Recently, I had a meeting with the Prime Minister and I brought this matter up. He told me that it was something that was currently being considered. Sometimes, however, I get the impression that some of my critics want me to do the work of an opposition leader and to oppose the Government. That is not my job. I think that the President of the Republic, in a regime such as ours, ought to be a unifying force and not someone who foments political tension and instability. That is something I have always tried to avoid, but I do have sufficient courage to tell the government and the Prime Minister exactly what I think and I have actually dared to criticise them publicly several times. I am sole judge of the criticism I make, and I decide if it is appropriate and also when the time is right. Sometimes, people would have   me criticise the government according to a timetable.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">· A number of journalists in the private sector are currently being prosecuted and these actions nearly all originate from sources close to the government Surely if they were actually acting unprofessionally, we would see legal actions from parts of society, such as business, and not just from the political class.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY"> - The reason for this is very simple. It is the political class that they vilify. I myself have been insulted on a number of occasions and, despite having put up with it for five years, I have not instigated any lawsuits. There was one case which was taken seriously by the Attorney General's office and there  were other cases when the Prime Minister was called a thief. I would ask you, is this a normal state of affairs ? Does freedom of the press mean that it can call a Minister or the Mayor of Praia a thief? Is that what is meant by democracy ? You have to be aware of the background to these court cases - and there are a good many of them, some dating from 1991. They are not designed to 'get at' any particular newspaper. The reason many of these cases have been brought is because serious insults of the kind we are talking about are a crime. That is true of even the most advanced democracies.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">· In economic terms, Cape Verde does not appear too badly off. But some economic indicators do give rise to concern, notably the big gap between the export and import figures. How do you see your country's future when it no longer relies so much on international aid ? Do you believe in the dream of many of your fellow countrymen, that Cape Verde will be Africa's 'little dragon'?</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY"> - Unlike some people, I have never spoken of becoming a dragon. I don't like this expression. I do believe that, despite our enormous problems - Cape Verde has few resources and we have been in the grip of drought for many years - it does have a number of assets. We are capable of making progress and I believe that there are a number of promising areas which have already been identified: for example, fisheries, tourism and even 'foreign' investment. We have to be optimistic about Cape Verde's future. We are in a difficult situation, everyone knows that, but we are a hard-working and courageous people and our prospects are good. The country will be able to forge ahead.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">-On the diplomatic front, Cape Verde appears something of an expert at maintaining good relations with different regimes: for instance, with both Israel and the Arab countries, with China, and with South Africa before and after apartheid. How do you manage this ? </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY"> - There is no magic formula. Since independence, Cape Verde has tried to adopt a realistic and pragmatic foreign policy. We are a small country with no great influence on the international scene and we have to be on good terms with everyone. That is the principle on which we base our foreign policy.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">· Cape Verde and Guinea Bissau used to be fairly close - do you foresee any future rapprochement, perhaps in some form of federation ?</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY"> - It is difficult to say. I feel that there is already a degree of rapprochement in progress, particularly in economic terms. Recently, we signed a civil aviation cooperation agreement, and there are opportunities for similar achievements in the fisheries and shipping sectors as well. Relations between the Cape Verde and Guinea Bissau governments are excellent but, to my mind, the idea of our forming a federation is out of date. It would not be in our interests nor in those of Guinea Bissau. We do, however, intend to develop a closer economic relationship and our political relations are very good indeed. I would wager that our partners in Guinea Bissau would give you a similar analysis of the situation.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">-In cultural terms, can it be said that your country has succeeded in becoming a multi-ethnic state ?</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY"> - The important thing is that the Cape Verde people should have their own identity; that there should be a specific Cape Verde culture. What I would say is that all the citizens of Cape Verde are proud of their culture and citizenship. This constitutes a great source of strength for a country such as ours which has major challenges to overcome. Our culture is also an asset in our country's development.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Interview by Hegel Goutier</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Interview with Aristides Lima, leader of the Opposition</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">'The government owes its victory to abuse of the electoral system'</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">· As main leader of the Opposition, what are your views on the fact that the governing party has recently been reelected ?</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY"> - I believe the country's economy is in crisis. Growth rates are not very high, just like in the 1980s, for example, and there is a high level of structural imbalance. Unemployment has increased: in 1990, unemployment stood at approximately 25% and now it is 30%. There used to be 25 000 people who worked in what we call the high intensity labour sector and who had a job for about 10 months of the year. They were recently laid off early. Such jobs were part of a social programme which, amongst other things, enabled us to build roads. The prices of staple products, such as sugar, maize and rice, which were stable, have just gone up, and the price of cement, which was also controlled to promote economic growth, is no longer subject to the same control and I can foresee this giving rise to many problems in areas outside the towns and cities. In Praia, a 50-kg bag of cement used to cost 440 escudos and, although that price will stay more or less the same, on islands like Fogo, it will go up to about 660 escudos. This will generate problems for economic growth and a number of major projects in the tourism sector, for example, will suffer. The balance between exports and imports has also been adversely affected in that the level of coverage of imports by exports has fallen, despite announcements to the contrary made by the government.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">· From 1993 to 1995, exports tripled in volume, if the government is to be believed. What are your thoughts on that ?</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY"> - The problem is that, in this country, some exports rely on the import of considerable amounts of raw materials. For example, in S&atilde;o Vicente, there is a shoe-manufacturing plant which gets its supplies of raw materials from abroad. The same applies to fishing and a number of fisheries products, such as anchovies, which are still canned in S&atilde;o Vicente but which have to be imported from Chile or elsewhere. This causes great problems when it comes to managing the country's foreign currency reserves, which have fallen markedly. In 1990, reserves provided over 6 months' coverage for imports, but now we have to operate in terms of weeks or even days.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">· Nevertheless, the government could say that it is not responsible for the economic picture you have just painted because the world economic situation is hitting all small countries harder.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY"> - No, the government is responsible, because it has been unable to implement the appropriate liberalization policy. For example, this should have been applied gradually to the trade sector, but the government rushed in and has now had to backtrack on goods which needed import authorization. What happened was that it lifted this authorization requirement but has now  had to bring it in once again. And another thing, the policy of liberalization has not been accompanied by very high levels of foreign investment and, in addition, the country's skilled workers feel marginalised, all of which goes to make the situation worse. As for structural adjustment, the government has always supported the idea of 'less State equals a better State', but, in practice, we have seen spending on the State's everyday activities go up and up. Civil service staff levels have now risen to about 12 000, compared with the former 10 000. However, increased spending is also a result of a not always equitable wages policy - the difference between the highest and lowest salaries is huge and, in some public bodies, one worker might be earning 15 times as much as another.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">· According to the Minister for Economic Coordination, the currency is under pressure as a result of the Opposition's irresponsible scare tactics of announcing a future devaluation, leading to the stock-piling of currency and goods, a kind of artificial speculation.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY"> - That's a very good way of offloading one's responsibilities - the Opposition did no more than criticise the government's policy and point to the   facts of the situation. It was members of the government themselves who acknowledged the low levels of currency reserves and the State bank which suspended transfers abroad. The Minister would have people believe that the Opposition lacks any credibility so how could this same Opposition have any influence on peoples' behaviour? The problem is actually extremely basic: economic operators, society and foreigners are not really au fait with the country's real economic situation because the government does not issue information, which is one of our basic criticisms. Parliamentary representatives and political parties no longer receive the figures they need and the latter are sometimes forced to consult foreign sources or to rely on their personal links with people who are close to sources of information. I myself criticised the Prime Minister for adopting this attitude of regarding information as subversive. I asked the Prime Minister for a copy of the study on Cape Verde's economy by a Portuguese professor, which had been paid for with tax payers' money. I never received it. For our part, we hope that Cape Verde's partners will be able to recognise the true situation and persuade the government to act in a more equitable manner.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">· Nonetheless the people cannot be too disappointed, because they reelected the government for another term.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY"> - That could be explained in many ways - the government controls information and therefore holds the reins of power. It controls television, radio, part of the print media, and the private-press sector is fairly weak, so it has been able to manipulate information and give people the idea that the country is on the right track. The government did do things to change peoples' lives, but it exaggerated its achievements using the State social communication means available to it. In fact, it did not achieve the major objectives it set itself: firstly its fight against unemployment - a failure. Balancing foreign economic relations - another failure. Balancing the domestic  economic situation: differences between our various islands have become more acute. In matters of health, Cape Verde made major advances when our party was in power and, although, to all intents and purposes, the health sector is just as good when compared with other African countries, it has, in fact, deteriorated. Diseases which had been eradicated from the country are returning, like malaria, for example, cholera, etc. Health services are concentrated in the capital city, Praia, and there is no decentralisation, which has negative effects on even links between carers and patients. Humanism shows the effects of a situation such as this, and it applies not only to health: there is an unfair distribution of State financial resources between the central government and local government. The State has been unable to reform local finances and has politicised transfers of funds to those districts which are closest to it. The government has also profited from the structural problems encountered in the working of our democracy. One of these structural problems is Parliament's weakness: it sits only three times a year and the representatives do not work full-time - they are sometimes employed by the administration which they are supposed to monitor. Democracy has a price and although savings can be made in other spheres, when one is  seeking good governance, one of the conditions for which is a strong, functional and effective Parliament, this is not possible. The weakness of the private-press sector is yet another problem.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">-And are you continuing to work in the administration ?</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY"> - I am a 'full-time' parliamentary representative. There are now about 10 out of 79 representatives who work on a full-time basis. They are members of Parliament's office, chairmen of committees and parliamentary leaders.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">-The government says that it inherited a serious state of affairs when it took over power from the PAICV.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY"> - It is simply not true that the good life began with this government's accession to power. Here's a little history lesson: think back to colonial times. Admittedly, there were negative aspects to our time in power but you must remember that the PAICV did, in fact, leave in place the subjective.  physical basis for the new policy direction. When we achieved independence, Cape Verde had no ports or airports, apart from small-scale port facilities at S&atilde;o Vicente. We built the port at Praia, the port at Sal, the port at S&atilde;o Nicolau and a number of airports. The telecommunications system was also set up by the PAICV government and we implemented the initial educational reforms. In the 1980s, the GDP growth rate was 7%and the per capita income was one of the highest in Africa, more than $820.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">· The party in power describes the PAICV as marxist and non-democratic claiming that it was they, not the PAICV, who introduced democracy.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY"> - That is nothing more than rhetoric, because all of the current governing party's members were in the PAICV - they were radicals, more marxist than anyone. Everyone knows that here, in Cape Verde, we had a pragmatic party, not a marxist party, although marxism was a source of ideas for many people. The idea was not to build socialism here. In those days, we had an open, not a centralised economy and all trade was private. We always had a market economy and to describe us as non-democratic is idle rhetoric. The PAICV's ideology has always been one of national liberation based on political and economic independence, with power vested in the people. This was a normal state of affairs during a national liberation struggle and, although it would be true to say that we were influenced by a certain single-party model which had gained widespread acceptance in Africa, the single party here could not be compared with any other. Both the PAIGC and later the PAICV attempted to force people into taking part in citizens' assemblies in order to put forward suggestions to the candidates. The current Prime Minister, Mr Veiga, for example, was put forward by a militants' assembly - he was on the PAICV's lists and they used to sit one beside the other on the benches in Parliament. The regime was, I suppose, slightly paternalistic but it was the people themselves who were really responsible for national liberation, it was they who had an idea of justice, patriotism, of being African, which explains the total commitment of Cape Verde's people to our party in the struggle for independence and also the good results we achieved when in power.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">· Why, then, were you not re-elected ?</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY"> - The party had been in power for a long time, with the same president, the same prime minister, the same president of the national assembly and virtually all the same ministers. People were hungry for change because the ruling elite had been in place for so long. The international scene, also, did not favour the old single-party system. Another element, too, was the Church, which fought us over the question of abortion. Perhaps I should point out that, from the very beginning, a section of the Catholic church was not in favour of independence, but younger members of the clergy, with more sympathetic feelings towards the population, supported us and, thus, we changed peoples' attitudes. The Church in Africa is a phenomenon worthy of greater analysis, particularly in Cape Verde, where, I feel, the current government was able to take advantage of the Cape Verde peoples) essentially religious nature to criticise us and present us as an anticlerical party. In fact, the situation is quite different: most PAICV leaders and militants are Roman Catholics and some church" were damaged by opponents in an attempt to discredit the party. Another example of abuse of the electoral system, apart from taking advantage of the peoples' religious nature, is the country's poverty. During election campaigns, the government make it easier for people to obtain food, and it also creates more jobs, en masse, but these disappear again after the elections - precisely as is happening at the moment.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">· As it is governed at the moment, Cape Verde is regarded by other countries as a 'star pupil'. Surely this is another success for the government ?</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY"> - Cape Verde has always been regarded as a star pupil because, here, our society is fairly homogeneous and there are no major social or ethnic imbalances. However, in my opinion, the future depends on changes at a structural level and such changes cannot take place unless we have a functioning parliament and a strong private press. I cannot deny that the government has had some successes, but I also believe that the people will have an opportunity to judge how it keeps its promises.  interview by Hegei Gouger</P>
+<P ALIGN="JUSTIFY"></P>
+<I><P>&lt;&lt;TOC4&gt;&gt; A portrait of towns and cities with atmosphere</P>
+</I><P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">It suffices for an unruly little bird to escape</P>
+<P ALIGN="JUSTIFY">For, suddenly, Fire to spark, Night to dissolve</P>
+<P ALIGN="JUSTIFY">The walls of every prison to cave in</P>
+<P ALIGN="JUSTIFY">From the tidal-wave battering</P>
+<P ALIGN="JUSTIFY">Amassed, in its untamed heart,</P>
+<P ALIGN="JUSTIFY">By a tiny breathless bird.</P>
+<P ALIGN="JUSTIFY">(Mario Fonseca in 'La Mer a tous les coupe')</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Most cities in the Third World devote all their energy to mere survival and there are few imbued with the same atmosphere as Mindelo - the very air  appears to brim over with art and good taste, beauty and sensuality. Our guide to the city speaks slowly, measuring his words, his delivery not an indication that he is searching for a translation, although it could be interpreted as an affectation, but matching the modulation of the language which is closest to his heart: 'I believe the air in this city is imbued with hedonism. Here, we mix work and pleasure - today is a holiday, but I am working. However, my day is not so rigidly timetabled that I cannot do some work and, since you have invited me out for a drink, take some time off to accept'.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Antonio Firmino, director of the Craft Centre, continues to tell us about his favourite city in the same steady language, a dreamy look in his eyes and wearing a Che Guevara-style beret. The tale he tells is the story of a tiny country which has fallen in love with culture: the actual building housing the Craft Centre used to be a school, the 'Mindelo Technical College', founded in 1917, the first secular educational institution. It was to transform the city into a cultural haven. The story goes that a certain senator named Vera Cruz, who represented the island of S&atilde;o Vicente in the Portuguese Senate, wanted to establish Cape Verde's first college. His peers objected, arguing that Mindelo had no building worthy of housing an institution of such a high standing but</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Vera Cruz straight away replied: 'So, why not use mine?'. Thus, he casually handed over his private residence.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Art even in the fish market</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">How many inhabitants are there in Mindelo? According to Antonio Firmino, 'Just me and my friends'. How right he is. It would be impossible not to become part of such a captivating place. And so a long journey began, which included the creation of Claridade, a review (and cultural movement) established in 1938 by Balthasar Lopes, a writer and essayist of world renown who was born in S&atilde;o Nicolau but taught in Mindelo, and other great artists who were to make up the country's literary and artistic roll of honour. Claridade was to be followed by Certeza which was also to influence the cultural elite. Although historians and other commentators feel that Claridade did no more than praise Cape Verde's 'latinity', rejecting its African side, artists are unanimous in regarding it as the cradle of Cape Verdian intellectual culture and the soil which was to nurture Mindelo and make it such an extraordinary little town. The impression is that everyone here is interested in art - the local authorities encourage and help sculptors in their creative activities all over the town, making it a living museum: here, there is a painting by Antonio Concei&ccedil;&auml;o and, over there, a huge flat sculpture of couples in languorous embraces, by Ro and Anildo, an illustration of the marvellous hedonism evoked by our host.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The same assured but delicate touch of these two artists can be seen in the lobby of Fishpackers, an anchovy- and tunapacking company, this time in the form of a celebration of fishermen. One of the finest examples of this type of art, which can be seen everywhere in the streets and public places, is the sequence of four huge decorative-tile frescoes in the fish market. When Bela Duarte showed them to us, it was such a delight to see how much at ease this famous artist was in the company of the staliholders, to whom both she and her work seemed so familiar.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Over and above this hedonistic atmosphere, there is, in Mindelo, an eclecticism which can be detected just as widely in other towns and cities, which means that you can talk about painting with the President of the Republic, dancing with a factory manager and decorative tiles with the man in the street. And the latter is literally 'in the street' - the inhabitants of S&atilde;o Vicente, the capital, derive immense pleasure from strolling in its squares and narrow streets, and around the port. A little stall, looking like a sugar loaf in the middle of one of the city's many squares, opposite a grand hotel, opens up in the early evening just like a flower, attracting hundreds of people to it who come to quench their thirst, to converse or woo, and to dance to the music escaping from the terrace of the Porto Grande Hotel, which has just reopened after being privatised and modernised.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">It is as if a dress ball were taking place on two different levels, one in front of the other, dancing to the same music and with equal pleasure: above, in an enormous gallery open to the sky, elegant guests (who include a small gathering of government officials and pretty Brazilian actresses who are here to film television soaps) and, down in the square, the dancing promenaders, full of admiration, almost stimulating those above.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Cape Verdian nights</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Like all the island's intellectuals, Antonio Firmino has a number of different jobs. In addition to running the </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Craft Centre, he teaches 'nautical' English to would-be sailors, is an amateur painter and musician (he plays and composes for his wife, who is a singer). His spare time is devoted to writing a column. The Craft Centre exhibits, amongst other things, a large number of tapestries, an art form much prized in Cape Verde. These admirable examples are by Ju&auml;n Fortes, Juamo Pento, and a good many others, in particular Bela Duarte, Tchal&ecirc; Figueira, Lucia Queiros and Miguel Figueira, Mindelo's top artistic foursome who appear to be  involved in everything, including the frescoes at the fish market. Bela, who showed us her studio, her house and the fish market, does not conceal the joy she derives from colour and allusion in her pictures, tapestries or decorative tiles, ranging from the most distant abstraction to an anecdotal figuration, using her native land with its doleful nuances, soft cries and romantic strength as raw  material. Above all, there is convivial artistic writing: 'Resistencia', which is at first sight a tapestry and then a patchwork of colour and sinuous lines. Scarcely has the artist begun to explain her work than everything becomes clear: this is a story, in threads and colours, about drought, representing roots, energy, space and struggle, all part of the Cape Verdian soul. She is also paying homage to those weavers of traditional African loincloth (badiu) from Cape Verde from whom today's artists inherited their technique.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">So, where to meet Antonio's friends? To find them, look no further than the Cape Verdian nights (noite caboverdiana), those gatherings which take place everywhere and resemble both a nightclub and an artistic association, all those present sharing a fondness for Cape Verde mingled with nostalgia and yearning. One such place is the Piano Bar, which was closed on account of the departure of its owner Chico Serra, another notable in local society, who was accompanying a friend, C&eacute;saria Evora, in her attempt to conquer new lands. Mission accomplished, Chico Serra is back and will soon be open for business again, his club's atmosphere just as intimate and warm as before - just enough room for his piano, his musician friends and others who come to sample grog and music.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Africa nonetheless</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Mario Fonseca also adores Mindelo but he would not agree that that wind-blown city has a monopoly on art and culture. He is from an island in the lee of the wind, from Praia, capital of the island of Santiago and of the country. In his opinion, it is the whole of Cape Verde which is bubbling with creativity and he will enchant you with his tales of Praia and its old colonial district, the 'Plateau', which still retains much of the nostalgic character to be seen in the now yellowing photographs taken 50 years ago when the city was not so sprawling and the ambience of Sucupira market was almost tangible. He will also tell you everything about the island of Santiago, with Cidade Velha, the ancient capital  which was too difficult to defend against repeated pirate attacks. It bowed to Praia's supremacy and, today, has an old-fashioned feeling, nestling within a cove around the ruins of its castle, and dominated by the fort which perches above a cliff face. The architecture owes much of its charm to the predominant Creole style which is vaguely reminiscent of Portugal, in every pastel shade. Cidade Velha's central square is caressed by a gentle breeze and groups of young people can always be seen lazing around the monument to the slaves. Time seems to stand still. The pretty little white church whose walls are decorated with sheaves of bougainvillaea, Santa Maria do Rosario, is the oldest on the island and, indeed, along the entire West African coast. It was built in 1460 and the white marble paving in the central nave conceals the final resting place of grandees from colonial times, their epitaphs erased over five hundred years by the soles and knees of penitents.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The director of the INAC (National Cultural Institute), responsible for Praia National Museum (which is soon to open its doors), is Mario Alberto de Almeida Fonseca, who once taught French in Portugal; he is a former administrator who has worked in Mauritania and Turkey, a translator and also a former regional manager of the national airline. In addition he is a poet whose works have been translated into several languages, including Serbo-Croat and Russian. Above all, he is an amateur connoisseur of the art and artists of his country. As the INAC's director, he is responsible for cultural events, exhibitions, shows, publishing and also the compilation of an oral record of the country's history and the preparation of  a Creole dictionary. The INAC's work also involves a major history of Cape Verde, the first volume of which has already been published. He will show you the future National Museum's collection, moving from one painting to another, from an old photograph to an antique cimboa, a type of locally-manufactured violin from the 1 9th century, or to an old Massachusetts galleon, testament to the past explorations of his people. You will first of all discover the works of artists from Praia such as Mito and Kiki Lima, not on account of Fonseca's chauvinism but because he feels he has to 'convert' the visitor who may have left Mindelo with the impression that that city is Cape Verde's premier cultural centre. There is also the music from the island of Santiago - the funana, the batuque, the fina&ccedil;o - all more African than the languid style so influenced by the Portuguese fado of this island's musical groups (Fina&ccedil;on, Bulimundo, Tuvaroes, Kod&eacute; di Dona or the great traditional style singer Nha Inacia Gomes). Gomes is a 'women of the people' whose musical heritage consists of no more than local tradition.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">It was she who 'reinvented' jazz and whom Alberto Fonseca admires a great deal. Cesaria Evora, moreover, is not the first musician to publicise Cape Verdian music abroad: Fina&ccedil;on or Kod&eacute; di Dona, for example, have captivated many music-lovers, particularly musicians, in Europe and America.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The Chamber and the stage</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Daniel Brito is not from Mindelo either. He is from Sal but confesses to having to pay regular visits to Mindelo, to immerse himself in that city's hedonistic atmosphere. For three years he has been director of the National Cinematographic Institute which was established in 1967 and is currently exhibiting newfound dynamism on account of the 'production tax' (4% of the filming budget, paid to the Institute and generally converted into a holding, which the State supplements to make the sum up to slightly more than 10% in co-productions). There is also an agreement with Portugal which encourages co-productions between the two countries, thereby enabling Cape Verdian technicians to receive their training. Brito is working on a local video-film-production project (TV viewers are very fond of such things) and wants to set up a major production centre to be made available to lusophone African countries and, perhaps, others. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Daniel Spencer Brito is also Sal's parliamentary representative (10 000 inhabitants), musician, writer/composer and guitarist in his own group, Madrugada. His talents include the composition of morna and coladeira pieces, as well as jazz-rock. At the end of May, the MP was due to appear in his own production at the Cirque d'Hiver in Paris, as part of the lusophone music festival. You could say that he divides his time between the Institute, the Chamber and the stage; however, he is also involved in research into copyright protection in Cape Verde. Daniel (it would never occur to you to call him anything else, even five minutes after making his acquaintance) always gives the same advice to anyone wishing to discover Cape Verde, namely to get to know the atmosphere of a tocatinha, spontaneous jam sessions which take place at one location or another, usually even more intimate than the 'Cape Verdian nights'. By the way, I almost forgot - by training, Brito is a vet, having studied in Romania. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">H&eacute;gel Goutier</P>
+<P ALIGN="JUSTIFY"></P>
+<I><P>&lt;&lt;TOC4&gt;&gt; Cape Verd-EU Cooperation</P>
+</I><P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Sponsors are delighted at the full use of aid</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Cape Verde's physical characteristics - its small size, the fact that its territory is scattered over a number of islands and islets, its Sahelian climate (continually rendering it vulnerable to drought), the arid nature of the soil and its low population (under five hundred  thousand inhabitants) - might explain its high levels of poverty and mean that, in order to survive and develop, it requires considerable amounts of foreign aid. However, it is the effort made by this small country to stabilise its economy and to gain maximum profit from foreign aid which has attracted special attention from sponsors. Last year the European Commission decided to increase its contribution to Cape Verde's National Indicative Programme, within the framework of the Lom&eacute; Convention (tome IV, first protocol 199-95, seventh EDF) by 7%, i.e. an extra ECU 1.7 million. Cape Verde had already put virtually all the ECU 23 million allocated to it to good use, an indication of the government's desire to use the aid granted to the full.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">When realism is a luxury</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">It is difficult to imagine an island inhabited by 160 000 people - the island of S&atilde;o Vicente, where the country's second largest city, Mindelo, with its population of 70 000, is located - having no source of drinking water. In former times, water was shipped in from the neighbouring island of Santo Antao, but Mindelo now has a number of seawater desalination plants, most of these provided by Israel, which meet 100% of its supply needs. The supply of both water and electricity is managed by</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Electra, a publicly-owned company, which, within the framework of the EDF (European Development Fund), has received European Commission aid to increase its electricity-generating capacity. It has set up three wind pumps, of Danish manufacture, which alone supply 13% of the island's non-industrial requirements. Elsewhere, such solutions as sea-water desalination and wind pumps might appear to be unrealistic but, for 160 000 people with no indigenous supply, realism is sometimes a luxury.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Although the island of Santiago, which is home to Praia, the capital city, does have some natural water sources, these are far from sufficient for its needs. One of the projects recently financed by the European Union concerned improvements to water-distribution systems, water purity and rainwater drainage. Amongst other things, this work involves the recycling of waste water which the island cannot afford to let drain away. Cape Verde's Achilles' heel is definitely its lack of water, its strong point unquestionably the dynamic outlook of its population.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The Commission has an office on Cape Verde where the work done at Praia (water distribution and purity, support for poorer districts of the capital threatened with overpopulation) is regarded as symbolic of the EU's desire to take account of both weaknesses and strengths and represents the overall intention behind Community aid to this country. Generally speaking, such aid is geared towards infrastructures (water and electricity production and distribution, urban development) on the one hand and education and health on the other.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Praia's historic old town, the 'Plateau', with its wealth of fine colonial and neo-classical architecture, risks losing many of its buildings which have been abandoned by their owners who lack the means to maintain them. Community aid has also been provided to help save this part of the country's heritage. Funds are insufficient to finance a complete restoration of the 'Plateau', but, following the example of the Cape Verde government, which has maintained administrative buildings in good condition, the Commission will probably assume responsibility for renovation of a superb nineteenth-century building, the 'Case Cor-de-Rosa'. The purpose of this project is two-fold; not only will the building be restored, but also it will become the core of a more general project to train professionals in building techniques and restoration and it will serve as an example to motivate future purchasers, institutions, businesses and individuals to preserve the historic old town.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The Community has also funded a study into the preservation of the capital's historic old town, which has been used as a basis by Praia Town Council. A project is currently underway, costing 1 million ECU, to restore an islet. The principal aim of this project is to train Cape Verdian technicians. Other work in the field of training has induded the building of the Praia Technical College. The next phase of this project, worth almost ECU 1 million, will fund the supply of equipment and teacher training.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Still within the context of the overall project to develop Praia city, an EDF programme worth ECU 1.3 million has been created for the development of a designated area as an industrial site. A rural electrification project in the area around Praia was, at the end of 1995, granted a budget of ECU 1.5 million and will benefit a population of 7500 people living in the three most densely populated rural centres on the island of Santiago. The technical side of the works will be entrusted to Electra, with the private sector being responsible for supplying equipment and monitoring the works. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Cape Verde's 'essence' as a resource</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Cape Verde's leaders regularly point to the richness, which they term the 'essence', of Cape Verde, contrasting this with the fact that their country is so poor. Indeed, despite limited resources, this country devotes a great deal of energy and ingenuity to 'cultivating' its culture. Two projects, financed within the framework of the National Indicative Programme and amounting to ECU 500 000, concern two feature-length films and will play a part in lessening the island's isolation by publicising its culture and people abroad. The first film, made during 1995 and entitled 'llh&eacute;u de Contenda', is the first fiction-based feature film to be made in Cape Verde and is the work of Leao Lopes, a director who has drawn his inspiration from the work of another Cape Verdian citizen, Teixeira de Sousa, and which centres on the history of Cape Verde and the birth of its national identity. The EDF contribution (approximately ECU 250 thousand) amounts to 14% of the total production cost. The film is currently being shown in a number of European countries. Virtually the same amount of  money has been set aside to fund another production, this time by a Portuguese director, Francisco Manso, based on a novel by a Cape Verdian author, Germano de Almeida, and entitled 'O Testamento do Sr. Napuceno', which was being filmed on the island of S&atilde;o Vicente at the time of our visit. 50% of the finance for this film comes from Portuguese producers, the other co-producers being French and Belgian.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Others EDF projects recently completed or being completed include one for improving roads on the islands of Santiago, S&atilde;o Nicolau and Maio (ECU 3 million) and a micro-project programme (ECU 1 million). In addition to funds from the EDF, Cape Verde has received further finance under the Lom&eacute; Convention, including ECU 700 000 within the context of the Stabex transfer schemes to offset loses in the banana-production sector during 1994.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Design a micro climate</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Extemal food aid is essential in a country which cannot meet its own requirements and the Commission's most recent food-aid-budget contribution amounted to nearly ECU 2 million. Other special budget lines include funds provided under 'Human Rights and Democratisation in Developing Countries'.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">To an attentive foreign visitor, one of Cape Verde's most interesting achievements is the progress it has made in reforesting such an infertile soil. One of these reforested areas, covering 5000 hectares (1990-94) forms the basis of a regional project to disseminate knowhow accumulated in this sphere in Cape Verde. Training course. have enabled technicians and others involved in the reformtation of the Sahel countries to gain experience in methods which have proved succesful here. The production and distribution of teaching tools (books, posters, films, etc.) supplement the project. Since independence, Cape Verde has achieved a tenfold increase in the amount of land which is forested - admittedly there was little to start with, but since climatic conditions are so hostile this result can be regarded as a major accomplishment. There is even a hope that a micro-climate might form. On the island of Santiago, in some of these new green areas, wild duck which had long since disappeared have returned. It is nice to dream but the country cannot afford to rest on its laurels.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">H&eacute;gel Goutier </P>
+<P ALIGN="JUSTIFY"></P>
+<I><P>&lt;&lt;TOC4&gt;&gt; Profile</P>
+</I><P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">General information</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Area: 4 033 km2 Population: 390 000 (1990) Population density: 97 per km2 </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Population growth rate: 2.8 % (forecast for the period 19922000) </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Capital: Praia (pop. 75 000)</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Other main town: Mindelo (pop. 65 000) </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Languages: Portuguese, Creole</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Currency: Cape Verde Escudo (CVE). In May 1996,1 ECU was worth CVE 104 ($1 = CVE 83 approx.) </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Politics</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Government: Mixed presidential/parliamentary system. The President is not the head of the executive but he represents the country and is guarantor of national unity and the Constitution. Unicameral Parliament. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">President: Antonio Mascarenhas Monteiro (elected in 1991 and reselected at the beginning of this year) </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Prime Minister: Carlos Veiga (since 1991) </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Political parties represented in Parliament:</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Movimento pare a Democracia (MPD)</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Partido Africano pare a Independencia de Cabo Verde (PAICV)</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Partido da Convergencia Democratica (PCD) - formed as a result of a break away from the MPD</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Party representation in Parliament: MPD 50, PAICV 21, PCD 1 </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Economy</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">(1992 figures)</P>
+<P ALIGN="JUSTIFY">GDP: CVE 23.9 billion</P>
+<P ALIGN="JUSTIFY">GDP per capita: US $840</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Origin of GDP by sector: agriculture 13%, industry 17%, services 70% </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Real GDP growth (estimate 1995): 4% Balance of payments: deficit of CVE 11.9 billion </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Main trade partners: Portugal, Spain, Netherlands, Brazil. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Annual inflation rate: 9.1%</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Social indicators</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Life expectancy at birth: 64.7</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Infant mortality per 1000 live births: 56 Adult literacy: 66.4% </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Enrolment in education (primary, secondary and tertiary): 59% </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Human Development Index rating: 0.536 (123rd out of 174) </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Sources: UNDP Human Development Report, 1995; Economic Intelligence Unit 1995; 'Etat et soci&eacute;t&eacute; aux iles du Cap Vert, by Michel Lesourd. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&lt;&lt;I&gt;&gt; p32a.png Figure</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<B><P ALIGN="CENTER">&lt;&lt;TOC2&gt;&gt; Europe</P>
+</B><P ALIGN="JUSTIFY"></P>
+<B><P>&lt;&lt;TOC3&gt;&gt; The Lom&eacute; Convention in focus</P>
+</B><P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Poll results and new brochure launched in Brussels</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">A new poll of Europeans high lights a deficit of information about the European Community's development policies. A brochure just published on the Lom&eacute; Convention, available in all EU languages, seeks to fill some of the gaps.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">At a press conference on May 21, Development Commissioner, Joso de Deus Pinheiro, unveiled the findings of a survey commissioned from the Brussels consultancy, International Research Associates (INRA). The aim of the exercise was to sound out how Europeans perceive developing countries. The sample was 16 346 people, of 15 years and upwards, who were polled in the 15 Member States during December 1995.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The survey shows that since 1991, helping the poor in the developing countries has slipped in the 'league' of issues of most concern to Europeans. The subject now ranks eighth in a table topped by the fight against unemployment. But the better news is that Europeans believe development of these regions should be the fourth most important priority for joint actions between Member States. This comes just below combating terrorism, environmental questions and defending Europe's economic interests.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">While 82% of Europeans are favourable to development cooperation, 12% are against. The degree of support varies, as one would expect, from one EU country to another. Interestingly, the survey shows that Member States facing an economic squeeze are the most reticent, irrespective of their past track record in development aid. In Belgium, only 65% are in favour while in</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Austria and France, the figures are 69% and 72% respectively. At the other end of the scale, Greece comes out top with 97% just ahead of Spain on 96% and Ireland on 91%. INRA's explanation for this variation is that it reflects the economic problems which are increasingly being felt in northern states of the Community. It is also worth pointing out that nations on EU's southern flank may be more convinced of the effectiveness of aid since they themselves are recipients of EC structural funds allocated to modernise the Union's disadvantaged regions.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">But INRA's report also reveals some misconceptions about European development aid. These, says Commissioner Pinheiro, may be attributed to the lack of visibility of the relevant development policies.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">57% of those questioned believe that the bulk of the Community's assistance consists of emergency aid, rather than longer-term project support. The reverse is actually true. More people answer 'no' then 'yes' to the question: 'Does aid contribute to reducing poverty in developing countries'? And most consider that United Nations agencies (UNICEF, UNESCO etc.) do more in the  field of helping developing countries than the EC. Non-governmental organisations also have a high profile, with the EU Member States and Bretton Woods institutions (IMF and World Bank) trailing behind.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Other key findings from the poll - which Professor Pinheiro says will provide much food for thought in the coming months as thoughts turn to cooperation after Lom&eacute; IV - are highlighted in the box.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Mid-term review and beyond</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Professor Pinheiro feels that some of results, which signal the need to tighten up on the management of development aid, have already been addressed in the mid-term review of the Lom&eacute; Convention which will come on stream from the beginning of 1997. The programming of the eighth European Development Fund (EDF) is already well under way and, with a view to increasing the effectiveness of aid, just 70% of resources earmarked for each ACP state will be allocated at the outset (for a three year period). An analysis of how the remainder should be spent will take place at the end of the three years. In addition, Professor Pinheiro indicated that a 'strategic' document was being drawn up on each of the 70 ACP states prior to allocation of funds. This was being done in 'permanent consultation with Member States and Commission delegations, in the interests of achieving a real synergy between the two.'</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">More sweeping changes to the relationship are likely after the current</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Some key findings from the INRA report</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY"> - Aid must reach its intended destination and arrive where it is needed 93.2%</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY"> - Aid must meet the needs of the local people</P>
+<P ALIGN="JUSTIFY">90.7%</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY"> - The beneficiary state must raspect human rights</P>
+<P ALIGN="JUSTIFY">85.1%</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY"> - Transparency, effective public management and the fight against  corruption are essential</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY"> - The beneficiary state must respect an overall development plan put forward by an  international aid organisation</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">78.3%  plan  put  forward</P>
+<P ALIGN="JUSTIFY"> by an  internati onal  aid  organisa tion</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY"> - Aid must be used to fund action by local NGOs</P>
+<P ALIGN="JUSTIFY"> - The beneficiary state must have a democratic system of government</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">59.3%</P>
+<P ALIGN="JUSTIFY">56.0%</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Convention expires at the turn of the century. Professor Pinheiro indicated that a first draft (green paper) on the possible shape of the ACP-KU relationship after 2000 will be published by the Commission by the end of the year. This, however, is likely to offer more questions than answers about future cooperation. 'I am not sure if we should keep the Lom&eacute; structure for every country, in the third millennium,' the Commissioner told the assembled journalists, highlighting the different levels of development now apparent between Lom&eacute; nations. Mauritius, now well on the way to becoming the 'Singapore' of Africa, was a case in point. He also pointed out the small island states of the Caribbean are at a very different stage of development from countries such as the Central African Republic or Burundi. He added that, in deciding what to do in future it would also be necessary to take stock of regional developments.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Questions about Lom&eacute; answered</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">In the meantime, efforts are under way to boost the image of Community aid. With this in mind, the Information Unit of the Development Directorate-General has just published a brochure entitled 20 Questions and Answers about the Lom&eacute; Convention.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Besides explaining in a nutshell what the Convention is, it answers some of the questions most frequently asked by sceptics about the benefits of development aid and trade preferences, highlighting the positive aspects for developing and developed economies alike. It points out, for example, that for every ECU 100 spent on aid, the Community recovers ECU 48 in the form of projects, supplies and technical assistance purchased from European companies!</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The brochure provides a succinct explanation of how the Commission monitors aid to stop embezzlement and corruption. It highlights the right of the European Court of Auditors to check accounts of projects and fund transfers - and to investigate documents in the Lom&eacute; states, without the permission of the country concerned. Another precaution is that once a project is under way, financing is by banker's transfer. This involves a paper specifying that the holder of contract X, whose bank account number is Y. should be credited with Z amount of money.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">An explanation is given as to why the European Commission is involved in development aid when the Member States have their own bilateral development policies.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The brochure explains the advantages of EC assistance over bilateral arrangements and details how the Lom&eacute; system has been evolving in line with the increasing globalisation of the economy, in particular since the fall of the Berlin Wall.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">It also contains some pocket statistics on official development assistance (ODA) flows which help to underline the message that the European Union (Community plus Member States) digs deeper into its pocket than its industrialised competitors in providing development aid. In 1994, the Community and its then 12 member states (excluding Austria, Sweden and Finland), contributed an average of 0.40% of their gross national product in ODA. The individual percentages varied from 1.03% in the case of Denmark to 0.20% in Italy. This compared with figures of 0.29% and 0.15% for Japan and the United States respectively.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">In 1994, total ODA from the Twelve reached $26.59 billion. Of this, $4.83 billion came from the European Community in its own right. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">D.P. </P>
+<P ALIGN="JUSTIFY"></P>
+<B><P>&lt;&lt;TOC3&gt;&gt; The content of chocolate</P>
+</B><P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Months of heated debate in the EU over the maximum allowable content of vegetable fats in chocolate have culminated in a Commission proposal for a revised Directive which, claim officials, should be to the taste of most interested parties.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The Commission has proposed that the 'subsidiatity' principle should apply to the content of chocolate. This means leaving it to individual Member States to decide whether they will allow the use of vegetable oil - up to a maximum of 5% by weight - in their chocolate-making. The eight EU countries where this practice is currently prohibited  are free to modify their laws to take account of this 5% rule. The other cocoa butter and dry cocoa contents specified in the Directive - 18% and 35% respectively - may not be reduced.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The addition of up to 5% vegetable fats was authorised under Directive 73/241 for the UK, Ireland and Denmark when they first joined the EC. Other Member States who acceded later - Austria, Finland, Portugal and Sweden - also use these oils in chocolate production. The remaining EU countries have continued to prohibit the use of vegetable fats - and the sale of chocolate containing such fats. The result has been a partitioning of the EU market, in direct conflict with the Single Market principle.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">If the proposal is approved by the Council and the Parliament, all 15 Member States will be free to decide whether vegetable oil can be used in making chocolate. Whatever their individual decisions, however, the barriers will come down, thus opening up the 'pure' chocolate markets to competition from less expensive varieties containing vegetable oil. Stricter labelling rules will also be introduced, with the precise nature of any substitute oils being clearly indicated. The simple mention 'vegetable oil' will no longer suffice. Martin Bangemann, the Commissioner responsible for industry, stressed the significance of revising the Directive in allowing  chocolate products to circulate freely throughout the KU. This, he argued, would be in the interests of consumers.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Winners and losers</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Traditional cocoa producers such as Cote d'lvoire, Ghana, Nigeria and Cameroon are fearful that the proposal may prompt some of Europe's 'pure' chocolate countries to change their laws - and that they will lose trade as a result. On the other hand, sheanut exporters in Burkina Faso, Mali, Ghana, Togo and Benin are hoping for higher sales if the 5% rule is adopted by more EU countries. Sheanuts account for 20% of Burkinabe exports and 98% of these are used to make vegetable oil substitute for chocolate products. The sheanut price is just 10% of the cocoa bean price. The Commission calculates that the maximum saving a manufacturer could expect by substituting vegetable fat for cocoa butter is around 1.5% of the ax-factory price.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">In weighing up what to do, the Commission also considered the objectives of the International Cocoa Organisation (ICCO). These include taking 'all practical measures to increase the cocoa consumption in their countries by eliminating or reducing all obstacles to the growth of consumption in cocoa.' The ICCO estimates that if the 5% rule is applied in the remaining eight states - Belgium, Luxembourg, France, Germany, Greece, Italy, the Netherlands and Spain - it will lead to a reduction in cocoa butter usage of 36 000-50 000 tonnes, which amounts to a drop in demand for cocoa beans of between 88000 and 125000 tonnes. This represents between 9-12% of current consumption.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Some producers suggest that these estimates are too high since they assume that manufacturers will go for  almost full substitution, which is not necessarily seen as inevitable. In addition, there is a belief that overall demand for chocolate products may grow as a result of the legal change.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">This was not the view taken by NGOs who reacted promptly - and critically - to the Commission text. The Brussels NGO Liaison Committee issued a statement claiming that it would lead to a drop of between 6.25% and 12.5% in the main exporting countries' cocoa receipts - and an additional burden on the European Community's Stabex fund. But chocolate producers and others argue that this is speculative. The impact, they say, will depend on the legal response of the eight Member States, as well as on the reaction of manufacturers. There are signs that the latter may well stick to their traditional and distinctive methods. A spokesperson for the Belgian-based Cote d'Or/ Suchard, pointed out that the proposal had a long way to go before it was approved, and stressed that his company had no intention of changing their 'winning recipes which had served them well since 1883. At the same time, he admitted, vegetable oil could be useful in a more diversified range of chocolate products.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The vegetable oil 'lobby' argues that the addition of vegetable fat makes chocolate easier to mould and less likely to melt in warm climates. And for those who fear the elimination of 'pure' chocolate from the market, they point to manufacturers in Britain, where vegetable oil has traditionally been used, who still exclude such fats from some of their brands.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The proposal must now be debated by the Council and it is clear that the arguing is not over yet. But it is beginning to look as if the consumers may be the final arbiters. Through their purchasing habits, they are likely to be the ones who finally determine the winners and losers in the great chocolate debate. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">D.P.</P>
+<P ALIGN="JUSTIFY"></P>
+<B><P>&lt;&lt;TOC3&gt;&gt; Minority businesses in the UK</P>
+</B><P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">In no country in Europe are ethnic minorities more organised than in the United Kingdom - though they are still not adequately organised, in the opinion of many, to pool their considerable resources together and overcome stereotypes, racism and unenployment. But this may  change if the morale engendered by a recent exhibition of minority businesses in the UK is anything to go by.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The statistics speak for themselves. There are 3.3 million Asians, Africans and Afro-Caribbeans in Britain, about 5% of the population (and the figure is projected to double in the next 25 years). They have six elected Members of Parliament - five Labour and one Conservative - as well as numerous personalities in the world of sports and the media. According to the 1994 Labour Force Survey, 48% of ethnic minorities are graduates or are in full time studies and 55% earn salaries well over &amp;15 000 (ECU 18 000) annually. They have a combined gross annual income estimated at f42 billion and an annual spending power of at least f26 ten.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Over the past 15 years, ethnic minority-owned businesses have grown considerably. In the last two years alone, they were responsible for more than 30 000 new business concerns throughout the country, according to the Commission for Racial Equality (CRE). Although many are in the retail trade, the 10% or so involved in production or manufacturing are extremely dynamic,  particularly those connected with the clothing industry or operating franchises.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">There are considerable differences between Asians on the one hand and Africans and Afro-Caribbeans on the other. The former are more business oriented and account for well over 80% of all ethnic enterprises. This success in business is often attributed to Asians' industriousness, but there is another crucial and often neglected factor: Asians have a stronger sense of group solidarity and patronage than Africans and Afro-Caribbeans. Whereas the former spend virtually all their earnings within their community, the latter (who are mainly Christians and are known to make greater efforts at integration into the British society) spend theirs in the society at large.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Unemployment among the black population in general is 19% compared to 8% for whites (in London it is three times higher). They are much more likely to be turned down by employers even when they have better qualifications than their white counterparts. Often self-employment is the only way out. This explains why there has been a boom in business start-ups by ethnic minorities over the past two years.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Although several black profffsional associations have come into being in recent years, it has been clear for some time to black leaders that the community's energies are dispersed and that these needed to be harnessed for the benefit of ethnic minorities as a whole. Blacks clearly have political and business clout to be exploited.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The idea for an exhibition of black businesses in the United Kingdom was mooted by a black business couple who, were influenced by a similar event  held annually in the United States called 'Black Expo USA'. But the impetus came from the 'Race for Opportunity Campaign' launched in October last year by the Conservative Government through the Department of Trade and Industry. The campaign has so far seen more than 20 big British companies pledge to do business with ethnic minority enterprises. These include British Airways, British Gas, British Telecom, British Aerospace and several high-street banks and finance houses.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Held at the Barbican Centre in London on 4 and 5 May, the exhibition was aimed at creating awareness among ethnic minorities of their potentialities, showing the opportunities available to them not only in the UK but also in Europe, and at promoting networking amongst their businessmen and women. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Cross-party support</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The exhibition, which had a cross-party support, could not have come at a more favourable time. Both the Tory government and opposition Labour Party have expressed support for policies favourable to small and medium-sized enterprises, which means that there should be continuity in this area if Labour comes to power in the next general election.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">This was borne out by the enthusiasm with which the shadow minister for small business, Mrs Barbara Roche greeted the exhibition. To her, the event should be seen in the context of Labour's overall policy on small businesses. Speaking at one of the seminars which was run alongside the exhibition to discuss various aspects of minority business problems, Mrs Roche explained that there were three important reasons why her party was promoting small enterprises, especially those involved in exports.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The first was that large companies were downsizing, and job-creation towards the end of this century and into the next would be largely by small and medium-sized enterprises. The second was that small businesses were efficient distributors of wealth and the third was that they were good at innovation and using new technologies.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Because a large number of small businesses are folding, or are struggling to survive in the UK today (often as a result of late payment of bills by large companies), Mrs Roche said a Labour government would introduce a statutory limit of 30 days for the settlement of bills by large companies. The latter would then have to pay interest to small businesses for any late payments. Ethnic minority businesses, she also said, were part and parcel of Labour's strategy for economic growth and jobs in Britain.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The Barbican exhibition attracted more than 80 exhibitors mainly in retailing, finance, telecommunications, consultancy, arts and crafts, publishing, electronics and education. There were  very few exhibitors from the manufacturing sector (a disappointment considering the number of Asians in the clothing industry) and virtually none in engineering. Some of the big companies connected with the 'Race for Opportunity Campaign' like British Airways and British Gas, as well as the newly created government-backed Business Link, the Customs and Excise department, the Inland Revenue, the Army and the Metropolitan Police were there. Also present was Louis Farrakan's 'Nations of Islam', (not necessarily on a recruitment drive, though that must have been part of the game), but as a reminder of its campaign for greater self-reliance by the black community which culminated late last year in the 'Million-Man' march on Washington DC. Video tapes of the march and speeches by Farrakan and other black leaders in the United States were on sale.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Difficulties</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The seminar run concurrently with the exhibition attracted many notable speakers, among them Members of Parliament, Keith Vaz, Bernie Grant and Barbara Roche and Commissioner Dr Zaka Khan of the Commission for Racial Equality. Jessie Boseman, vice-president of 'Black Expo USA, who was also scheduled to speak, did not turn up.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">There was general agreement on the main factors inhibiting the growth of ethnic minority businesses, the most obvious being racism and  discimination. Ethnic businesspeople not only have difficulties obtaining public contracts, but they are often denied access to finance, market and even premises. Furthermore, they suffer from lack of management skills, networks and feedback. Dr Khan of the Commission for Racial Equality highlighted mounting racist attacks, mostly against Asianowned shops, which have claimed a number of lives in recent years.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Integration into mainstream economy</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">It is no longer a hidden fact that banks discriminate against black businesses. Surveys carried out by the NatWest and Midland banks have confirmed that fact. The latter though, it must be acknowledged, has a laudable Fellowship Programme, designed to encourage ethnic minority university students to take up careers in the Midland Bank on graduation. Lack of access to the market has effectively meant that black businesses have been left out of the mainstream of the British economy. Everyone agreed that it makes good economic sense to see them integrated into it. This was particularly   the position of both Barbara Roche and Zaka Khan. The question was: would it be possible ?</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Some of the issues raised on the floor by businesspeople revealed that many were sceptical that racism and discrimination could be overcome in multiracial Britain. The Commission for Racial Equality symbolises the fight against these two evils and Dr Khan had a hard time defending its role. The CRE was criticised for constantly quoting statistics on improvements in the living conditions of ethnic minorities which, it was argued, were totally removed from reality. Despite this, Dr Khan remained upbeat. To him the future promises great things for ethnic minorities. He promised to look into the grievances aired by some businespeopie during the seminar. Barbara Roche, for her part, promised that a Labour government would encourage the banks to offer packages of assistance to small enterprises, in particular, black-owned ones. They would also ensure that local councils offered minority enterprises a share of local government contracts.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Greater self-reliance and global trade</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">In view of the problems black businesspeople have had to contend with over the years, Bernie Grant, the Member of Parliament for Tottenham in North London, did not devote much time to the idea of integrating them into mainstream British economy. He felt that racism and discrimination were so prevalent that there was little chance of that happening. For him, the future for black businesspeople in Britain lay in greater self-reliance and entry into international trade.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">In a speech entitled 'political responsibility, and black import and export business', the M.P. set the Barbican exhibition in the context of the global economic situation - one where he said, 'the countries of the North are exploiting those of the South, in particular African countries.' Africa's heavy debts to the West should in fact be the other way round. He argued that the new world trade agreement, which  opens up the developing countries to competition, was unfair. 'This means that countries where minorities in the UK came from are going to have problems, and it is the duty of thee minorities to ensure that their countries have a fair deal,' he said. Mr Grant cited, by way of example, the EU's banana protocol under the Lom&eacute; Convention which gives preferential treatment to small Caribbean island producers and which is currently being 'unfairly' challenged by South American producers under the WTO rules. The role of multinationals, which are effectively acting es 'middleman', was, he believed, pernicious for developing countries. There was a need for black businessmen to step in.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Minority enterprises in the UK do not exist in isolation from the rest of the world, he elaborated. They should seek to engage in international trade and take advantage of their connection with their countries of origin. To facilitate this, Mr Grant said that a group under his chairmanship had set up a Global Trade Centre in his constituency in North London with the aim of helping black and minority enterprises establish direct trade links with Africa, the Caribbean and black America. The Centre was already in contact with a number of African countries which have expressed interest in the idea. Such a link would not only ensure a better deal for African producers but also favour the growth of minority businesses across the world. This was, he confessed, 'a political agenda' designed to reduce the excessive profits of multinationals, if not put an end to their 'outright exploitation' of Africa and the Caribbean. Mrs Roche expressed support for the Centre for the role it could play in boosting British exports.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">UK minorities and the</P>
+<P ALIGN="JUSTIFY">European Union</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">A self-confessed Eurosceptic, who would have preferred the UK to strengthen economic ties with the Commonwealth rather than with Europe, Mr Grant displayed an extraordinary understanding of the European</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Union's affairs. What worried him most about greater European integration, he said, was racism and the fact the UK job market, where black and ethnic minorities are already heavily disadvantaged, will be exposed to further competition from other Europeans most of whom speak several languages. However, he had no alternative but to support the Labour Party's line on Europe and work to secure the best advantage of British membership for ethnic minorities. He contrasted Tory 'divisions' on Europe with Labour's 'united' policy and condemned the British Government's attitude generally towards the Union.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The development of the Union, Mr Grant said, was of great significance to black people. He was sure the Government's Immigration and Asylum bill, which had come up against strong opposition in the House of Lords, was aimed at harmonising immigration laws with other countries in the Union. The bill, if passed, will change the UK's visa regime and have serious implications for ethnic minorities and their businesses in Britain. He revealed that, with the support of ethnic minority members of the British Parliament, Bill Morris, the black General Secretary of the Transport and General Workers Union (the second biggest trade union in the UK) and other European trade union leaders, the Intergovernmental Conference was being lobbied for the inclusion of a stronger clause against racism in the Treaty of Rome. The aim, ultimately, is to see measures in line with the UK's laws against racism and discrimination enacted at the Union level. This would include the establishment of a European equivalent of the Commission for Racial Equality - with similar powers - so as to establish a level-playing field for ethnic minorities in competition for jobs and in business throughout Europe. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Augustin Oyowe</P>
+<P ALIGN="JUSTIFY"></P>
+<B><P ALIGN="CENTER">&lt;&lt;TOC2&gt;&gt; Dossier</P>
+</B><P ALIGN="JUSTIFY"></P>
+<B><P>&lt;&lt;TOC3&gt;&gt; Communication and the media</P>
+</B><P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">(Dossier coordinated by Debra Percival)</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Press freedom is widely acknowledged as the cornerstone of democracy with a clamp-down anywhere in the world frequently interpreted as a sign of government repression. The rash of multi-party elections in African nations at the beginning of the</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">1990s brought new publications to news-stands. Many of these have since folded - often because of a lack of funds and sometimes because of government censorship.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Many organisations are campaigning vigorously in the public eye for a free press in developing nations. These include Reporters Sans Frontieres, Article 19 and the International Federation of Joumalists - all of which are featured in this Dossier. The US-based Freedom House has also been monitoring the state of press freedom worldwide since 1979. In its recently published 1996 survey, it says that even today, only 22% of the world's population live in countries with a free press. 38% have a press sector that is 'partly free' while the description 'not free' is applied to the remaining 40%.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">There are also regional organisations such as The Media Institute of Southern Africa (MISA), which are playing a part in keeping media issues to the fore. David Nthengwe, a researcher with MISA, highlights the fact that democratisation does not necessarily guarantee a free media or free expression more generally. He also draws attention to the difficulties faced by private and community organisations in obtaining adequate finance. These are  typical of the problems facing the media in many countries, both in the ACP group and elsewhere in the developing world.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">In seeking to tackle these issues, donors are showing increasing interest in backing media programmes with development finance (linked to democratisation and human rights). The European Union, UNESCO and a number of bilateral donors have expanded their activities in this area with a variety of projects.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">One big change has been the rapid growth of the 'Information Superhighway'. This has prompted fears that the developing countries may fall further behind, although donors have indicated a willingness to help ensure this does not happen. One NGO closely monitoring the development of the Internet for the South is the PANOS Institute. Meanwhile, multilateral donors (notably the World Bank, through its INFODEV programme) are also becoming involved. A number of EU personalities lent their support to the development of the information society in the developing world, at a major conference staged in South Africa in May on the initiative of the country's Vice President, Thabo Mbeki. A work programme of projects was drawn up with the aim of making sure, in the words of European Commissioner, Martin Bangemann, that there is no divide between the 'information-poor' end the 'information-rich'.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">Finally, although the world is undergoing an information revolution, the more traditional media (the press and above all, radio) will, for the foreseeable future, continue to have a central part in informing, educating and entertaining people in many developing  countries. It is important that those of us who increasingly communicate via our computer screens do not lose sight of this essential fact.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">In this Dossier, we examine a number of the key issues affecting the media and highlight some innovative projects in this area - with the help of a series of experts. The subject has clearly moved higher up the development agenda, but there is still a long way to go, as the figures cited above show. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">D.P. </P>
+<P ALIGN="JUSTIFY"></P>
+<I><P>&lt;&lt;TOC4&gt;&gt; Aidan White of the IFJ</P>
+</I><P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Confronting the age-old problem</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Given the chance, 'governments would like to run and manipulate the media'. This is the view of Aidan White, General Secretary of the Brusselsbased International Federation of Journalists (IFJ), who says it is an 'ageold problem'. And the Federation, which has member organizations in 93 countries, works to prevent it from happening. It also provides a range of services to journalists throughout the world. We recently spoke to Mr White, who used to write for the British daily, The Guardian. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">He began by outlining to us the Federation's key areas  of activity which include, in particular, the professional conditions in which journalists work and the defence of human rights. On the first of these, Mr White focused on the problem of economic pressures and difficult social conditions. 'We take a strong view that you can't have press freedom if journalists work in conditions of poverty or technical deprivation. It is a nonsense,' he stressed, 'to talk about a free press in a situation where journalists aren't paid, or if they are unable to function properly.' In seeking to tackle this, he spoke, in particular, of the 'need for independent organisations of journalists defending professional and social interests.'</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">As regards human rights, the IFJ is active in the international community, working with bodies such as UNESCO and the UN Human Rights Commission. 'We are very interested in issues such as the legal environment in which journalists and the media operate, and are extremely active in the defence of physical safety.'</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Mr White went on to give more detailed information about the IFJ's work in Algeria, where many journalists have been killed in recent years. This country clearly has a bad international reputation and the General Secretary was anxious to offer a more balanced picture of the situation. 'In my view, there is a real malformation of Alaeria's  image in Europe and elsewhere. The view we get is of a paralysed society where nothing can function properly - a kind of international basket case. It is not like that. In Algeria, life continues. There is a form of democracy. There are a dozen newspapers which appear every day. The streets are full of traffic and people walking about. The reality is that there is a particularly horrifying and barbaric form of terrorism which is targeted against intellectuals including journalists. This means that the media has a terrible problem.'</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Aidan White explained the strategy of the IFJ in seeking to confront this. 'We began by going to Algeria to investigate what was going on. Then we established an international office on the spot. This is a direct contact point of solidarity for local journalists and the local media. So we don't report Algeria through Paris. We don't see the need to go through some sort of middleman in order to find out what's going on in the country or have contact with Algerian journalists.'</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">'And then we have two specific programmes which are very important', he continued. One involves providing humanitarian assistance to journalists and their families. The other is a series of practical activities in Algeria. Thus, for example, we are organising a round table on terrorism and information.' He pointed out that the Algerian government had resorted to the traditional method of press censorship in the face of ,the terrorist threat and stressed the 'need to counter this. 'We are also organising a practical seminar on personal safety, as well as one on professional social rights, the need for ethical standards and better social conditions.'</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The point, he emphasised was that events were being organised on the spot. Algeria may pose terrible difficulties 'but it doesn't mean we walk away from it.' The IFJ's emphasis was firmly on being a 'functional organisation working directly with the people who need help.'</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Funding and the EU link</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Tuming to the issue of the IFJ's funding, Mr White explained how the core activities - his own salary and administrative costs - are paid for by the subscriptions of member organisations, which amount to roughly $1 million. On top of that, the Federation carries out projects with the EU and other donors. They also distribute funds, offering their expertise as a representative body to help other organisations that want to undertake work.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Asked in what way the EU could do more, the General Secretary stressed the political dimension. 'It should intervene,' he argued, 'to establish certain standards in international relations. We say, for instance, that political, economic and military cooperation with any state outside the Union should be based on a commitment to and respect for freedom of expression and opinion.' He underlined the 'responsibility' of the EU to take a stand against countries that locked up journalists, implicitly criticising those who argued that freedom of expression was very important but who then shelved the issue when economic relations were involved.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">He also urged a more proactive approach 'moving away from the strategy of counting bodies, complaining, and making reports about how bad the situation is' towards one based on comprehensive programmes of assistance. He described the IFJ's Media for Democracy programme in Africa as a 'first attempt' in that direction. Mr </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">White highlighted what he saw as a difficulty with existing projects. 'The problem is that the EU is confronted by all sorts of different NGOs who come and say: 'we have got this good project - give us support for it'. This is fine but it inevitably means that resources are spread very diffusely and often to no effect.' A lot of activities, he suggested, such as one-off seminars and conferences, were 'like fireworks in the night sky: they glow bright for a brief period and then they disappear.'</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">He went on to plead for an integrated, comprehensive strategy. 'Until that exists, you will not be able to solve the fundamental problems facing journalists.'</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Training and status</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The discussion moved on to the subject of training. Perhaps surprisingly, Aidan White did not see this as an important priority in itself. As he explained: 'It's no use training journalists to be very high quality if they go off to work in a country where the legal environment does not allow them to function properly. And it's no use training them to be ethical if they go somewhere that is steeped in political or financial corruption, and where there is no culture which appreciates the media's role in democratic society.'</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">With this in mind, he believes that training should be directly related to the strategic approach he referred to earlier. 'Yes, we need professional, well trained journalists, but it should be part of a range of programmes. And professional training is not just important for journalists. It should also be provided for managers, editors, advertisers... and perhaps even for politicians!'</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The General Secretary noted that the status of journalists in most countries was quite high. They are seen as a filter for information 'coming from the government to the governed'. This was important, he thought, but 'tine real question is how the filter functions. On the one hand journalists have a relatively high status, and what they do is extremely important, but they work close to the political elites, which means they  are subject to pressure. They must retain their independent role, scrutinising and investigating what governments are doing.'</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">On the subject of access to information in developing countries, Aidan White observed that the situation is now better than it was ten years ago but pointed to the 'age-old problem of people in power wanting to control the media.' He gave the example of journalists in Indonesia, 'who really want to speak independently of the government, but who are being killed because they represent independent strands of opinion.' Overall, however, he believes the situation has been improving. 'This is partly due to changes in information technology. A government can no longer simply take a journalist out and beat him up. There are half a dozen press freedom organisations around the world watching for and reporting on such events.'</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">There is a tendency in Europe to assume that 'everything in the garden is rosy' in terms of press freedom, and we were interested to hear what the Secretary General thought of this proposition. He was quick to offer a less complacent view. 'We have just issued a very strong statement against the EU about their secrecy policy,' he pointed out. 'You cannot claim the moral high ground for democracy in Africa or elsewhere if you have a system of secrecy in Europe which operates at the highest political level and which denies citizens access to information.'</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">He was also concerned about the concentration of the media in enormous congLom&eacute;rates. This trend, he argued, 'is actually profoundly damaging to the culture of information.' He cited, in this context, the action of the Murdoch organisation 'in banning all news from his cable channels going into China.' Mr White continued: 'They banned the BBC and they banned news coverage in the Chinese language in order to make a business arrangement with the Beijing government. That sort of activity, in our view, is direct censorship from the heart of western democracy.'</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">In conclusion, Aidan White gave some more detailed information about the Media for Democracy programme in Africa which he described as 'ground-breaking.' The Federation has used it to develop key themes, including the coverage of elections. 'The real test of press freedom,' he continued, 'is at an election, because that is when the political pressure is toughest and the professional quality of journalism is exposed. For Africa, we developed a manual on election reporting and, interestingly, it has become the source document worldwide for election reporting.' He explained how it formed the basis for developing a text which is universal. This has been translated into various European languages, and Arabic, and has been employed in Poland, Romania, Albania and Latin America.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">In the first phase of the Media for Democracy programme, the Federation held a serf. of seminars and conferences on how the media covered elections. As Mr White stressed, this was a crucial time in Africa. Political change was taking place, multi-party democracy was being introduced and there was a need to clarify how elections operated and how they should be reported. 'People didn't have the experience. They wanted the information, and to discuss how things should be done.' The seminars covered aspects such as financial corruption, the organisation of journalists and the role of ethics. And what the IFJ found was that the same kind of things happen in Kenya, Tanzania, Mozambique and South Africa - and indeed across the world. In the words of the Secretary General, 'they have an echo everywhere because, at its root, the problem is the same - those in power want to manipulate the media and use whatever pressures they can.' The lesson learnt from the IFJ's experience in Africa is that common solutions are also valid. Or as Aidan White put it, 'there is no part of the world that can't teach the rest of the world something.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">D.M. &amp; S.H.</P>
+<P ALIGN="JUSTIFY"></P>
+<I><P>&lt;&lt;TOC4&gt;&gt; Freedom of expression: the first freedom  </P>
+</I><P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">by Frances d'Souza</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Frances d'Souza who is Executive Director of AROSE 19, a nom governmental organization which campaigns against censorship globally, explains why Freedom of Expression is for her the most important human right</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">In the absence of freedom of expression, it is almost impossible to protect other rights, including the right to life. Once governments can draw a cloak of secrecy round their actions and remain unaccountable, massive human rights violations can, and do, take place. For this reason alone, the right to free expression, specifically protected in international human rights treaties, must be considered a primary right. It is significant that one of the first indications of a government's intention to depart from democratic principles is when it increases its control over information, usually by gagging the media. At the one end of the spectrum, supposedly minor infringements of this fundamental right occur daily in western democracies; for example the abuse of national security laws to prevent publication of information which might embarrass the authorities. At the other end of the scale are regimes of terror which brutally suppress opposition, information and even the freedom to exercise religious beliefs. Without free speech and an independent media, it is easier for governments to employ propaganda to promote ethnic conflict, war and genocide.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The right to freedom of expression is formally protected in major international treaties including the Universal Declaration of Human Rights, the International Covenant on Civil and</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">* This text is an abridged version of a submission made by the author to a public hearing hosted by the European Parliament's Committee on Foreign Affairs, Security and Defence and the Sub-Committee on Human Rights and the Committee on Culture, Youth, Education and the Media, April 25, 1996.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Political Rights (Article 19), and the European Convention on Human Rights (Article 10). It is also enshrined in many national constitutions, although this does not always guarantee its protection. Freedom of expression is something which applies even in countries which have not ratified the relevant international treaties. This is because the Universal Declaration is so widely accepted that its provisions now form part of customary international law.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">While it is generally agreed that freedom of expression is the cornerstone of democracy, international treaties permit certain restrictions. Unlike the American First Amendment rights which allow few, if any, checks on free speech, the international treaties aim for a balance between competing rights. Thus, for example, free speech may be limited where it impinges on the individual's right to privacy, or where it involves incitement to violence or hatred. Given that the permitted restrictions are necessarily broad, the limits of free speech are constantly being tested in national courts and in regional tribunals such as the European Commission and Court of Human Rights. In recent years, several landmark cases have helped define what restrictions may be imposed by governments and under what circumstances. In particular, it has been emphasised by the European Court that any restriction should 'pass' a threepart test; it should be prescribed by law (and thus not be arbitrarily imposed), it should be proportionate to the legitimate aims pursued, and it should be demonstrably necessary in a democratic society in order to protect the individual and/or the state.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Who censors what?</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Despite the rules governing restrictions on free speech, many justifications are still invoked by governments in suppressing information which may be inimical to their policies or interests. These include arguments in defence of national security or the 'public interest'. The mechanisms used to restrict the free flow of information range from subtle economic pressures, and devious methods of undermining political opponents and the independent media, to the enactment of restrictive press laws and rules for licensing journalists. In extreme cases, they may involve the illegal detention, torture and disappearance of journalists and others associated with the expression of independent views.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The right of free speech may appear less important than, for example, freedom from torture or extrajudicial killing. It is also sometimes difficult to persuade the public that censorship, generally associated with banning obscene materials, is a bad thing! It requires a recognition of some of the fundamental principles of democracy to understand why censorship is so dangerous. Democracy implies that people can make choices about the issues that affect their lives, including what they wish to see, read, hear or discuss. While this may seem a luxurious freedom, mainly preoccupying the wealthy West, it is a comparatively short distance between state censorship of an offensive book to the silencing of political dissidents. And the distance between this and the use of violence to suppress opposition is even shorter. Censorship tends to grow rapidly from small beginnings. Allowing a government the power to deny people information, however trivial, not only leads to laws and procedures which can and will be used by those in authority against those with less authority. It also denies people the information they need to render their governments accountable.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">There have been some terrible examples of the role of censorship in recent years. We have seen it in the republics of the former Yugoslavia   where the media were manipulated for propaganda purposes. We have seen it in Rwanda where the government associated radio incited citizens to kill each other in the name of ethnic supremacy. And we have seen it in Iran which maintains the threat of murder against a citizen of another country because he wrote a book which displeased the authorities.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">There are clear links between access to information (or rather the lack of it), and war. Democracy empowers people by increasing participation in decision-making at all levels. The poor, who are denied access to information on decisions which deeply affect their lives, are powerless and have no voice. They cannot influence the ruling elites whose interest in consolidating their own power and position may be served by initiating conflict.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">It is significant that of the 126 developing countries listed in the 1993 Human Development Report, wars were being waged in 30 and a further 33 were suffering severe civil conflicts. 55 of these 63 countries were to be found at the lower end of the Human Development Index which is an indicator of poverty. It is reasonably safe to assume that most people never welcome war. They may be coerced into supporting 'their' side in a conflict by their governments, using propaganda designed to whip up fear and extreme nationalist sentiment. If the majority had a democratic voice, they would undoubtedly object to war. But voices are silenced. Thus, the freedom to express one's views, to challenge government decisions and to insist upon political rather than violent solutions, are necessary aspects of democracy which can, and do, avert war.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">State-sponsored propaganda in Rwanda, as in the former Yugoslavia, succeeded because there were no ways of challenging it. One can conclude that it is impossible for a country to wage war in the absence of a compliant media willing to indulge in government propaganda. Governments needs civilians to fight wars for them and the media is needed to reinforce government policies and intentions at every turn. In a  totalitarian state where the expression of political views, let alone the possibility of political organisation is suppressed, one has to ask what other possibilities are open to a genuine political movement intent on introducing justice. All too often, terrorism and violence are the only perceived options available to communicate the need for change.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">What NGOs can do</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The work of human rights organizations has to become much more proactive and should be concerned with providing early warning and preventive action. Monitoring freedom of exprmsion, especially freedom of the press, offers an excellent context because it is widely recognised that would-be dictators always seek to silence people's voices through banning newspapers or other methods of censorship. One has to assume that when censorship begins in earnest, worse human rights abuses will follow and this should be the point for action. Had there been a greater international lobby for an independent media, for access to information and for participation in decision-making in the former Yugoslavia, Rwanda, Nigeria, Burma and many other countries, some of the gross violations which continue to occur, could have been prevented.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Censorship is the first instrument of a government intent on departing from democratic procedures. In this sense it is an early warning signal and at ARTICLE 19, we believe we have a special responsibility to understand better how democracy is destroyed through censorship and how we can alert the international community to act to prevent it.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">By way of conclusion, anything which can build strong and sound media infrastructures, at the earliest to pportunity, in transitional democracies, is both a gift and a great investment. A crusading press, prepared to separate fact from opinion and to verify its sources, can create a level playing field in which all sectors of society have a voice. This would preclude political control and manipulation for nationalistic power purposes. There is also a need to strengthen local monitoring groups which have the capacity to verify information. International organisations should amplify the voices of local organisations and bring them to the attention of the international community. It is only where there is a strong human rights culture in a given country, whether it has achieved democracy or not, that political changes can be seized upon and shaped into the democratic process.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">To achieve these objectives, NGOS need to work with governments which are obliged by international law to uphold fundamental rights. We need organisations such as the KU, the UN, ASEAN, and others, to insist on respect for human rights in their dealings with third countries. We also need the general public to be aware of what fundamental rights are, what are the consequences of infringement, and how they can, as individuals, successfully challenge restrictionss imposed on them by their governments. Above all, NGOS need to work with multilateral organisations to determine where slender resources can most fruitfully be targeted.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">F.d'S.</P>
+<P ALIGN="JUSTIFY"></P>
+<I><P>&lt;&lt;TOC4&gt;&gt; Commission support for democratisation through the media</P>
+</I><P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">by Mark Leysen</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Amongst the many cooperation activities in which it is involved, the Lom&eacute; Convention covers cultural cooperation, which includes information and communication, yet European Development Fund support for the media in ACP countries is negligible. Although considerable and increasing amounts of aid are granted for the cinema in such countries, EU support for TV, radio and the printed media is small.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">On the other hand, for some years now, the Commission has provided considerable aid to the printed media and radio in ACP countries under its 'Support for democratisation and respect for human rights' budget, which heralds a new approach to media questions. The EDF does not participate in the vast majority of big communications projects in Africa, namely PANA (Panafrican News Agency), URTNA (African National Television and Radio Union, the African equivalent of the European Broadcasting Union), the Programme Exchange Centre, Afrovision, Cierro, etc. The reluctance of EU and ACP partners to embark on such media projects can be explained both by EDF procedures and by the worldwide political context including the situation in most African countries.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Until recently, the media was a matter for the State in Africa. The 'New World Information and Communications Order', announced in the 1 970s, foresaw the participation of not only African citizens, but also of their governments in the world information highway. However, the democratic credentials of such governments were open to question - they controlled the printed media, radio, television and press agencies and any support for such media amounted to a strengthening of the State monopoly and this is why the EDF did not take part.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Moreover, aid to the independent media was impossible because such entities did not exist in most African countries and the authorities were not prepared to back a request for aid to the press which they regarded as contrary to their country's interests. If support for the media did exist, it was indirect and restricted to backing of means of communication servicing development projects: literacy campaigns, the fight against AIDS, increasing awareness of ecological problems, etc.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">It was not until the advent of the democratisation movement and the support that Europe decided to grant to it that a media-aid strategy was to take root. As a kind of 'Fourth Estate', the media monitor executive power and report any abuse of it. In parallel, they play a key role in strengthening civil society by providing information (if not objective information, then at least information from many sources) on current political, social, economic and cultural issues and by providing a medium which offers an opportunity to speak out on matters of importance to society.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The European Commission focuses its media support in five areas in agreement with representatives of African press and specialist European . organisations in this area. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Freedom of expression It provides direct aid to national, regional and international organizations to defend freedom of expression, specifically financing monitoring, surveys and the reporting of any violation of press freedom (censorship, intimidation, arrests and arbitrary trials, etc.), and direct assistance to the media and any journalists who are victims of such attacks on press freedom. This direct aid is channelled to, inter alia, the activities of Reporters sans frontieres (see 'Interview with Mr Robert Menard', in this issue), 'Article XIX' and Index on Censorship, all organisations which operate like an Amnesty International for the press.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Training</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The new independent press is often run by journalists who have had no journalistic training and the former State media often require being updated after many years of professional 'distortion' responding to 'his master's voice'. The Commission hence finances programmes offering training in basic journalistic techniques, election coverage; professional codes of ethics, etc. In this area, it is working with a number of European and African organizations, giving priority to long-term actions which are likely to spawn others and to programmes aimed at achieving a higher level of professionalism.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Aid for vocational organizations</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Vocational organizations for journalists have a role to play in improving the profession's social standing, in strengthening its cohesion in the face of political division, in defending its interests and in coming to the aid of journalists who have been victims of repression. The Commission finances a vast 'Media for Democracy' programme conducted by the International Federation of Journalists and its affiliated regional and national organisations (see interview with Aidan White, in this issue). The programme aims to strengthen or create national and regional associations of journalists, but is also involved in more general actions to   increase the professional standing of the media.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Access to sources of information</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">A credible and responsible press requires sources of information which the new and financially precarious press cannot allow itself. The Commission supports the creation or updating of documentation centres, North/South  and South/South exchanges between publications and radio stations, access to international press agencies or photographic libraries, etc., being shared between several media bodies. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Legislative framework and code of ethics</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">It is not enough merely to guarantee freedom of expression in the   constitution. This principle must be embodied in all legislative and regulatory texts to prevent a journalist being prosecuted arbitrarily for 'defamation' or 'a breach of State security'. Moreover, to appear credible, the profession must observe a code of ethics. The Commission backs the drafting of press codes, codes of ethics and regulations to govern the air waves. It also backs the creation of press and air wave regulatory bodies as well as the provision of training in journalistic ethics.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">It is obvious that the 'Democracy and Human Rights' budget cannot alone meet the needs of Africa's multi-faceted media scene. Moreover, although the media are a key element in any democratisation process, they are also much more than that - as a means of information and recreation, they have a role to play in the human development of society; as an instrument to create greater awareness, they can contribute to the strengthening of a civil society which is gradually taking charge; and as an economic sector in the full throes of development, they can make a contribution to the GDP and create jobs. All the more reason for national sponsors and the EDF to take more of an interest. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">National television, victim of  democracy </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">More than the other media, television in Africa is controlled by the State and serves, first and   fore most, to disse minat e news about the leade r and his govern ment. The state of equip ment depen ds on when it was suppl ied by a friend ly count ry from the North, and as it was almos t certai nly offere d to the count ry's leade rs 'as a perso nal gift', it usual ly consi sts of oversi zed equip ment which the nation al televis ion statio n canno t maint ain correc tly owing to a lack of resou rces. Whils t Europ e is movin g over to digita l Betac am and 1619 forma t, many Africa n TV statio ns are still opera ting with Umat ic and with mach ines that are impos sible to maint ain. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">With such deriso ry mean s, nation al TV statio ns have to conte nd with unfair comp etition from the intern ationa l statio ns which, from their satell ites, are inund ating the contin ent with their broad casts . The worldbroad castin g chann els of Europ ean statio ns are receiv ed clearl y (CFI, TV5 Afriqu e, BBC World Telev ision, Deut sche Welle, etc.). The numb er of religio us statio ns (gene rally Islam ic) contin ues to increa se and comm ercial televi sion is develo ping apace - CN N, MTV, Cana l Horizo ns, M-Ne t and others can be picke d up just about every where and can thus cream off the best of a comm ercial mark et which is still virtual ly non-e xisten t and awaiti ng better days . </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The URTN A is unabl e to defen d the intere sts of its memb ers, prope rly and its initiat ives (which are, nevert heles s, lauda ble) are stagn ating: the -progr amme rexch ange centre in Nairob i does not excha nge very much at all and Afrovi sion, . the syste m for excha nging news betw een   nation al TV statio ns via satell ite, is strugg ling to Get off the aroun d. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Never theles s, Africa n TV statio ns do not lack talent or motiva tion and many of them are capab le of produ dng more qualit y progra mmes . What can be done to help them ? Firstly, a decis ion has to be made regar ding who is to be helpe d. Certa inly not intern ationa l TV statio ns' be they private or public, which have their own strate gy (comm ercial or politic al and produ ce televis ion progra mmes for impor t which make only a very margi nal contri bution to the expre ssion of Africa n talent . It would also be wrong to rely or, privati sation and comm ercial statio ns in order to obtain quali ty televis ion - t his much has been demo nstrat ed by the Europ ean exper ience . As for direct aid to nation al televis ion, this would mere ly reinfo rce the State mono poly over inform ation. Wha t is requir ed is greate r suppo rt for the transi tion of State televi sion into a genui ne public servic e. with the benef it of an indep enden t statut e and also true editor ial indep enden ce. Conse quent ly, as things curre ntly stand, aid for trainin g teievis ion' profes siona ls, suppo rt for qualit y progra mme produ ction and any aid aimed at draftin g a public -servic e televis ion Statu te, are usefu l forms of suppo rt which are neutra l with regard to State -medi a contro l. Any direct aid to nation al </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY"> televis ion statio ns in the form of   hardw are and equip ment shoul d be </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY"> subje ct to their conve rsion into an auton omou s public servic e. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">M.L. </P>
+<P ALIGN="JUSTIFY"></P>
+<I><P>&lt;&lt;TOC4&gt;&gt; Images of Africa in the Western media </P>
+</I><P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY"> by Geoff Mungham</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">It seems difficult to find an African leader or African journalist who has not, at some time, been either fiercely critical or quietly despairing of the way in which the continent is depicted by the western media. Their grievances have come to form part of a now familiar litany. Claims are made that the reporting of Africa is now almost entirely in terms of what has been called a'coup, crisis and famine syndrome', and that the western media focus only on 'bad news' out of Africa and ignore the 'positive' achievements of many African countries. These criticisms go hand-in-hand with accusations that Africa cannot ' tell its own story, in its own way', because the global news market is dominated by powerful, westerr-owned corporations, who have their own agenda for reporting Africa. For many Africans, their continent is becoming increasingly invisible in the trade in global news. For them, Rupert Murdoch's cynical remark that 'the Third World sells no newspapers' would appear to have been uttered with Africa specifically in mind. Finally there are those Africans who are concerned about 'western cultural imperialism' undermining traditional African values and culture.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">How true are these claims? Is Africa becoming once again a dark continent; one largely excluded from the glare of western media coverage? Are some of the correctives suggested by different African leaders worse than the problems they are complaining about? And if Africa is in danger of becoming a 'disappearing world' for news, to what extent are many African countries themselves to blame?</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">To begin with, there is no doubt that African critics have a case. First and most obvious, is the undeniable brute fact that global news and information flows are dominated by a small number of multinational operators, nearly all of whom - especially since the end of the Cold War - are western owned and controlled. This is true of the great international news agencies, whether the traditional wire services like Reuters or Agence France-Press, or the newer global television news services represented by WTN and CNN, among others. The major clients for their output are western news organizations.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">At the same time, most African countries are in no position to mount a challenge to this world news order. The continent has recently been described as one of the 'least dynamic regions in the global economy, where buying power of consumers is low' and in which many countries are burdened with crippling debt payments. In the same vein, a 1991 World Bank report not only pointed to the increasing 'communications gap' between Africa and the developed world, but went on to suggest that most of the continent offered poor prospects for those wanting to invest in telecommunications projects. These are among the reasons why Africa scores so poorly in terms of putting in place viable national communications infrastructures, let alone being able to take on the global market leaders in securing a higher profile for Africa in the world's news rooms. The same factors also help explain why most African countries remain so dependent on western-controlled news sources.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">This dependency is not simply a question of the easy availability of copy or other material from the western news agencies. Puri (a Tanzanian journalist and Managing Editor of Newslink Africa)  presents other reasons why African editors are interested in what's happening in the West. These include the links between many African countries and their former colonial rulers, the realities of global and economic relations and his claim that African editors often have little interest in other parts of the continent. As he puts it, '...a newspaper reader in Botswana, for example, is not much interested in reading detailed reports from Morocco.'</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">At the same time, there is plenty of evidence to support the criticisms of the 'coup, crisis, famine' coverage. Examples are too numerous to cite here, but the following small selection is fairly representative of the broader picture.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Introducing the findings of a 'Global News Agenda Survey', Malik and Anderson noted: 'For the rest of the world, Africa means coupe, and largescale killings (covered usually only in the first few days), almost ritualistic famine relief... and the occasional travelogues in the guise of saving something or other'. Similar claims were made by Okigho when he wrote that while CNN and other satellite organisations have 'revolutionised international news coverage', the most common images of Africa still depict internecine warfare (in Angola, Liberia, Somalia), pogroms in Rwanda, political violence in Sierra Leone and ethnic conflicts in Kenya and elsewhere in Africa. In contrast, says Okigho, the 'many positive developments' are routinely ignored.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">A limited review that I made of wire service copy from the main international news agencies during the week of 13-20 May 1996, produced findings that seemed to echo some of these complaints. In this period, hard news stories were concentrated on a handful of the 50 plus countries of Africa; Burundi, the Central African Republic (C.A.R.), Egypt, Liberia, Somalia, Sudan and South Africa - together with stories of alleged financial irregularities in the World Health Organisation in Africa.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Copy about Burundi dealt with ethnic violence and attacks inside Zaire   on Burundi by Hutu 'rebels'. Reports from the C.A.R. focused on an army mutiny, street battles and looting, but were angled on the mediating role of French troops (the C.A.R is a former French colony) and the fate of 100 Americans trapped in the capital, Bangui. Egypt was featured after its government accused Sudan of harbouring a 'vipers' nest of terrorists'. Out of Liberia came a torrent of wire copy about fighting in Monrovia along with assorted atrocity stories, but pinning the emphasis on the plight of foreign nationals (especially Britons and Americans) and the role being played by the USS Guam in air-lifting them to safety. Somalia rated a mention because of the release of two foreign aid workers (British and German) held by an unidentified 'rebel faction'. On South Africa, the wire services were fixed on further violence and killings in KwaZuluNatal, the result of ongoing struggles between rival supporters of the A.N.C and the Inkatha Freedom Party.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The 'agenda for Africa' sent out by the wire agencies, was replicated by  the menu offered by Reuters TV and APTV. For instance, on one day during the study period, the former was offering ten picture feeds; only one was from Africa (on the C.A.R.) while the rest included such compelling visuals as the British Queen's visit to the Chelsea Flower Show. For the fifteen picture feeds being touted by the APTV on a single day, one featured Africa ('news pictures to offer on the airlift by US marines'), which competed for the attention of western news rooms alongside visuals of a US woman who collected hubcaps (140 000 of them, no less!), Hugh Grant arriving by boat at the Cannes Film Festival, footage of the Monaco Grand Prix and a 'fun run' in Sarajevo (whether or not pictures are available, the idea of a 'fun-run' in Bosnia still seems a difficult concept to grasp) But what these studies show is not the whole picture about Africa which circulates in the West. Nor should they necessarily be used to support the usual criticisms about the performance of the western media in relation to the continent. In the first place, not all news  out of Africa fits into the syndrome the critics complain about. For example, a great deal of the coverage of South Africa has been 'positive' (if we trace the reporting of that country's transition to majority rule). So, too, have the moves towards multi-party politics in African states like Zimbabwe. Similarly, there is plenty of reporting of Africa's sporting successes (such as South Africa's Rugby World Cup triumph). Nor is the West unaware of the work of certain African musicians and film makers - indeed, it has been influenced by them.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">And even if 'positive' coverage is sometimes hard to find, the critics may still be missing some key points. The first is to do with western 'news values' or rather a failure to appreciate how they work - whether in relation to Africa or anywhere else. The staple diet of much of the global news flow is about 'bad news' and, in this respect, Africa prob  ably fares no worse or better than other parts of the developing world.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Second, a more 'systematic' reporting of much of Africa is still difficult. My point here is about a lack of efficient and developed communication infrastructures, but also a reluctance by many African leaders to tolerate - let alone actively encourage - free and honest open reporting. Too many African journalists have been, and are being, harassed, imprisoned or killed by their own governments. Much of the media in Africa - especially the broadcast media - remains under state control. Newspapers that show a 'lack respect' for the ruling party are frequently shut down. These realities help explain why some of the maligned western media are turned to by those Africans who want something more than state propaganda from their newspapers or broadcasters. This is why the BBC World Service has come to enjoy such a high reputation in many parts of Africa.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Third, the attempts made by the African states to try and take on western dominance of global news and information flows, have been misjudged. Two failed initiatives in particular are worth mentioning in this context; the launch in 1983 of the Pan African News Agency (PANA) and the long-time obsession with setting up a 'New World Information Order' (NWIO).</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">From the start, PANA has been dogged by financial and management problems. African governments owe $18 million, journalists have gone unpaid, lines have been disconnected and in 1992 a UNESCO-funded audit found evidence of financial mismanagement. The main source of information PANA traded in was material from the domestic news agencies of OAU member states. Since most of these are state-controlled, the 'news' they were offering was never likely to attract many western users. To try and give PANA a new lease of life, UNESCO are backing a rescue package, which would allow for private investors to be shareholders along with state-owned African national news agencies. But the pro  posed partnership funding is unlikely to work, especially in one-party states where the ruling groups have always been suspicious of any media not under their direct ownership.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The NWIO project has chased even more impossible dreams. Any attempt fundamentally to change the global news order was always going to be beyond countries with severe national communication 'deficits'. Most African countries, with weak and undercapitalised information infrastructures were never in a position to take on the market leaders in the global news business. In pursuit of the NWIO idea, endless international conferences were held, declarations passed and ritual attacks made on ' western media dominance'. Nothing came of it all. If the sense of frustration which kept the concept alive was understandable, less easy to grasp was why African leaders focused on the NWIO idea, while their own grassroots communication systems remained impoverished and under-resourced.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The most recent attempt to develop 'top-down' communications facilities in parts of Africa comes with the attempts to push satellite-delivered payTV on the continent. Among the 'players' here are Multi-Choice (which will be offered to subscribers in over 30 countries in sub-Saharan Africa), Canal Horizons (targeted on North Africa and Francophone West Africa) and Panafnet (also aimed at buyers in Francophone West Africa). Because these enterprises are subscription-based there will be a clear bias in take-up towards upperincome groups; and - certainly in the case of Multi-Choice - the output will have a 'strong UK/USA programming flavour'. It is hard to see how these initiatives will ever meet the real news and information needs of the vast majority of African consumers, who have limited spending power and are often deprived of the most basic communication tools.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">As Hans Dieter Klee (former Head of the Africa Service of Deutsche Welle) has rightly argued, what Africa urgently needs is large-scale international media aid to help strengthen its own media. This aid should not be targeted at projects designed somehow to allow Africa to 'compete' with Western media congLom&eacute;rates. It should, instead, be aimed at building up diverse, viable and professional local and national media enterprises in African countries themselves. In this, the EU can play a leading role, working through the links established under the Lom&eacute; Convention.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Robust national communication structures in Africa will not, of course, alter the balance of global media power. They will be able to do little to stop the international news agencies reporting Africa in the way they have done in the past. And it will be a long time before most Africans becomes travellers on the 'information superhighway', since this, in essence, is an extension of existing computer and telephonic communications, which the continent lacks. But a vigorous local and national media, Africa-wide, would be good for Africa and the best barrier for resisting outside media influences. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">6.M.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">References</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Okigho: 'National Images in the Age of the Information Super Highway </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">African Perspectives', African Media Review, vol. 9,1995.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">R. Malik and K. Anderson: 'TV: The Global New Agenda Survey', intermedia, January-February 1992. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">B. Hicks 'North of the Limpopo', Cable and Satellite Europe, April 1996. </P>
+<P ALIGN="JUSTIFY"></P>
+<I><P>&lt;&lt;TOC4&gt;&gt; A message of hope on the Burundi airwaves</P>
+</I><P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The European Parliament may seem an unlikely launch pad for a radio station, but two members of this elected body, who are committed to a free and fair press as one of the cornerstones of democracy, have set up Radio Espoir (Radio Hope) in Burundi with backing of the European Community Humanitarian Office (ECHO).</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Parliamentarians, Pierre Pradier (ERA-F) and Bernard Kouchner (PSE-F) are co-founders of Radio Espoir (Radio Umwizero, in Kirundi) which brings together a French association and a local Burundi radio station. Three expatriates are working on the Bujumbura-based project; an editor, a radio technician and an administrator. They have teamed up with local journalists who, for the moment, are providing their services free of charge.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The station, which broadcasts in Kirundi, is targeted at an audience in the 15-25 age group. In a country with an 80% illiteracy rate, radio is the only way of reaching the population. 'The idea came to us in 1994, with Rwanda and Radio Libre des Mille Collines' says Pierre Pradier. 'If so much harm could be done with radio, then why equally could good not be achieved.' RLMC was the radio set up in July 1993 on the eve of the genocide in Rwanda. It became a mouthpiece  for the Akazu, a clan of Hutu extremists grouped around the then President's wife, Agathe Habyarimana, and it undermined the Arusha agreements by whipping up ethnic conflict in Rwanda.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Mr Pradier explains that Radio Hope journalists intentionally avoid speaking about Hutus and Tutsis. He also highlights the problems encountered in providing news coverage when local conditions are so difficult. As he points out; 'When you speak about the situation of a woman who has lost her husband in Burundi, you are talking politics.' Security considerations are important too while the MEP stresses that a proper analysis of events can only come with time: 'At the moment we are limited to reporting the facts. And it is only when the facts are verified that one can begin to interpret them.' The news items broadcast by the station rely on agency dispatches confirmed by a network of local people who call in.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Because of such sensitivities and in an effort to find as much common ground as possible, the radio station gives music top billing. This has the added advantage of helping to attract listeners. It also offers general programmes on African roots, sport, culture and educational themes, in addition to its news items. It is currently broadcasting for six hours a day.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Pierre Pradier says he would like to see an end to the 'navel gazing' of Burundi's population. 'We want to show that peace is possible, by showing how it is progressing elsewhere: in Haiti, for example, where there is a legitimate President now, and amongst the Chiapas in Mexico.'</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">But, like many fledgling stations, finding enough funds from donors to guarantee its future is a worry. The station's current ECHO grant runs out in September 1996. Indeed, the project, classified under emergency aid, was atypical for the humanitarian aid office. But Mr Pradier is hoping that continued support will come from one of the EU's budget lines. He believes that the Union is a particularly suitable donor because it tends to be less 'colonialistic' than some others. He also raises the possibility of seeking funds from private donors such as the Fondation de France. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Looking to the future of the station, Pierre Pradier argues that they cannot let the project 'drop' and hopes eventually to see it being handed over to local broadcasters, assuming 'they are people we can depend on'. The signs so far are encouraging. He would also like to see Radio Hope's programme content broadened to include game shows, with radios offered as prizes for the winners. As far as he is concerned, the more people who tune in, the better! _</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">D.P.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Joint Assembly resolution</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The ACP/Ku Joint Assembly is pushing for EC institutions and Lom&eacute; signatories to be more supportive of media issues. A resolution on the role of communications media in the development and consolidation of democracy in ACP states. passed by the Assembly in March, contained the following points:</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY"> - freedom of expression and free communications and media are vital to the development of a democratic society;</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY"> - more ACP countries should give opposition parties access to the media' notably where this is controlled by the state;</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY"> - all candidates and political parties should be given access to the media in a 'balanced and fair manner'; </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY"> - laws which restrict press freedom and the electoral process should be repealed;</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY"> - any threat of physical attack against media organisations or their employees should be investigated by the authorities, with those responsible being brought to justice;</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY"> - the media should be impartial, providing accurate information during elections, helping to educate the electorate, explaining the importance of elections, giving information on where, when and how to vote, and explaining the secret ballot;</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY"> - EU assistance for free and a fair elections - and a free media sector in ACP countries - should be increased. </P>
+<P ALIGN="JUSTIFY"></P>
+<I><P>&lt;&lt;TOC4&gt;&gt; Catholic radio in Southern Africa </P>
+</I><P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">by Antonio Pacheco</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">In this abridged article, the author, who is a Portuguese journalist, gives details of two church-supported local radio projects in Southern Africa.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">At the end of the 1980s, the Social Communication Department of IMBISA, the conference of Catholic bishops in Southern Africa (a kind of SADC for Roman Catholics) embarked on a local radio project. It had a two-pronged approach. First, it involved setting up a network of small community radio stations. The local population were involved, sharing responsibility for making programmes and broadcasting information and news about everyday life in the remotest places. In some cases, the programme content was retransmitted at a provincial or even national level. The second aspect was that it was supplemented by the creation of flexible and independent associations of journalists/presenters. They formed information agencies operating as a network to link up local radio stations.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">At that time, the main concern in Southern Africa was to rid South Africa of apartheid. There was also a desire to promote freedom of expression in Angola and Mozambique. Given that radio was (and still is) the most important means of communication in the region, the idea was to set up a regional network capable of overcoming all the constraints ranging from legal bans and restrictions on broadcasting to widespread illiteracy. The ultimate objective was to set up a Catholic radio station based in Swaziland. This project did not go ahead, however, because it was too expensive to finance and, above all, because it was dependent on the regional Catholic hierarchy. It proved difficult to reconcile the various ideological views and sensitivities of bishops in the various countries of the region. There was also a growing feeling amongst the Christian communities that the underlying need was not for a radio station which would be a vehicle for bishops' views, but rather a media system that served the people, offering recreation, training and information.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Radio Pax</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Another local radio project of interest, which is now up and running, involved reviving Radio Pax, the private Catholic radio station which made a significant contribution during the 1 960s to the struggle for a free Mozambique. The operation closed down in 1977 but the experience was not forgotten and 16 years later, the decision was made to bring the station back on air. Those behind the new project took advantage of the trend towards greater political openness in the country. Their aim was to offer a credible and informative alternative, which, they hoped, would be up and running in time for the elections scheduled for October 1994. A course was run between July and September 1994 which brought together young presenters chosen by small communities on the outskirts of Beira, Chimoio, Nampula, Quelimane and Maputo. The course involved honing the participants' presentation skills and providing practical training in technical subjects, and programme and information preparation. This was how the first association of young independent Christian journalists came into being.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">For various reasons, including red-tape and customs regulations, the  new Radio Pax was unable to broadcast in the run-up to the general election. However, the young journalists, who received their training at various locations, were able to act as important independent sources of information. This was channelled to Maputo and used as backup for a number of international press officials and observers. The information relayed by the young presenters in the provinces made it possible to publish a newsletter which was circulated throughout the country, using fax, religious channels and a variety of other means.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Radio Pax is now in operation, although it faces major technical problems. It is based in a community centre in Inhamizua, 20 km from Beira. The station has already done important work in gathering information about local traditions, and has broadcast programmes aimed particularly at women and young people in suburban areas. The network also incorporates Mozambique's Radio Encontro, which broadcasts from Nampula in conjunction with the Anchilo training centre. There are plans for further local radio stations in Maputo in the south, Quelimane and Chimolo in the centre and Pemba in the north.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Radio Pax is managed entirely by the Association of Independent Young Christian Journalists in Beira. In terms of training, the current preoccupation is to teach the young people involved how to manage the small radio stations which have been made available to them, and to set up local self financing systems. Although equipment is important, what really counts in this project is the training of the presenters. Working in close collaboration with the community, it is they who are in the front linepromoting the inalienable right of free expression.</P>
+<P ALIGN="JUSTIFY">A.P.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<I><P>&lt;&lt;TOC4&gt;&gt; The Voice of the Disabled in Chad! </P>
+</I><P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY"> by Mand Rya&iuml;ra Ngarara</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The Support Group for the Disabled in Chad (AEHPT) was set up in 1987 with the assistance of the International Christian Service for Peace (EIRENE), which has its headquarters in Germany. By coming together to form a group, disabled people hoped to take charge of their lives and break down the wall of silence that surrounds them. However, despite setting up various workshops (welding workshops, small printing works, musical groups) and publishing an information newsletter, entitled 'Perspectives'. the AEHPT has been unable to improve the image of disabled people within Chad society and has failed to  raise awareness that the work done by the disabled is not only of value, but deserves due recognition. From this status quo sprang the idea of broadcasting a national weekly radio programme called 'The Voice of the Disabled'. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">There are two reasons why radio was chosen as the communication medium: firstly, the very strong oral tradition of the country, together with the population's weak purchasing power, which make access to newspapers difficult, means that radio remains the most appropriate medium for reaching a wide audience; and secondly, radio programmes are not difficult to produce, since they do not require vast technical, financial or human resources.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Letting the disabled have their say</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Initially launched by the AEHPT, The Voice of the Disabled is now jointly produced and broadcast by four associations actively involved in defending the interests of those with disabilities. It is broadcast nationwide every Monday at peak listening times.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The programme is not, however, aimed solely at those with disabilities but, on the contrary, seeks to increase awareness in Chad society as a whole. It also acts as a platform from which to urge the authorities to take concrete measures to help this section of the population.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Today, more than a year after its launch, The Voice of the Disabled is enjoying tremendous success, with ever larger numbers of people, from all walks of life, tuning in. For the disabled themselves it provides a vast source of information, explaining the facts behind the causes of their disabilities and giving advice on how to prevent such disabilities and what can be done to treat them, and it keeps people informed about  what is happening within the various associations for the disabled, giving information about the activities, projects and special events that are taking place. As far as the rest of the population is concerned, The Voice of the Disabled has helped to raise the profile of disabled people in Chad. Slowly but surely, people's preconceptions are beginning to change and one of the programme's greatest achievements has been to eradicate gradually the negative image which people used to have of disabilities.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Nevertheless, the lamentable fact remains that this programme is broadcast solely in French, and this is why plans are now in the pipeline to broadcast The Voice of the Disabled in both Arabic and Sara - Chad's two national languages.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">M.R.N. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<I><P>&lt;&lt;TOC4&gt;&gt; TV documentaries and development</P>
+</I><P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The Africa Express experiment</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">By Richard Synge</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The 'Africa Express' documentory series mounted by Channel4, an independent British TV station, has done more than just put a new slant on news provided by state-run African channels. it has also created jobs for African producers and reporters.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Television viewers in Africa will soon get the chance to see documentaries on African current affairs and development topics which have hitherto only been seen on British TV sets.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Channel Four's Africa Express programme has recently concluded its third series to much critical acclaim in Britain. it included items on a surprisingly diverse range of topics. One film showed how a cash-strapped Congolese prison saves money by sending its prisoners home one day in every month, and included lively interviews with the governor and the prisoners themselves as well as footage of the grim prison conditions. Others focused on the flourishing free currency market in Zaire, the spread of South Africa's 'shebeen' culture into the country's upmarket suburbs, political battles in Namibia over the rights to manage historic tourist sites and the Nigerian military government's blatant attempts to censor television reporting.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The latest series supplemented the work of British film crews by incorporating several documentaries that were made entirely by African production teams. Special funding for this element of the Africa Express project came from the environmental television distribution agency TVE. As a result, Africa Express hired four African directors and used African-based crews to film half of the 24 films in the series.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The other innovative part of the project was that the programmes are now becoming available to viewers in Africa at the lowest possible cost. To promote this concept of 'media feedback', TVE has been actively marketing the series to non-governmental organisations and facilitating arrangements for the distribution of the cassettes to African broadcasting stations, both state-owned and private.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">'It is a way forward for us, because nothing like this has been done before,' says Raphael Tuju, a Kenyan film producer who runs a video resource centre in Nairobi, marketing documentaries to local broadcasting stations and the educational sector. 'There are too few opportunities for producers in African countries to break into the international networks. The subjects we cover are rarely of interest to the distribution companies, the differences in technology are too wide and getting wider, and there are not enough African producers who have reached the professional level to compete with their counterparts abroad.'</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Peter Gill, who edited Africa Express for Channel Four, welcomed the opportunity to help promote the independent film industry in Africa. 'It was thoroughly stimulating,' he says, adding that one of the constant challenges was 'finding ways to bridge the gap between what is technically possible in Africa and the standards required for a European television production.' The four African directors hired for the series were two South Africans, Eddie Mbalo and Teddy Mattera, a Zimbabwean, </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Albert Chimedza, and a Namibian, Bridget Pickering. They all worked directly under Peter Gill's management and in contact with a producer in the field. Gill was impressed with the level of journalistic and technical expertise available in Africa and the dedication of the teams working in difficult situations. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Even where the production teams were British, all the 24 films in the latest Africa Express series used African journalists and presenters. They researched and organised most of the films in advance of the actual shoot by the visiting film crews. Cameroonian journalist, Emmanual Wotany, played a prominent role in the films on Congo and Zaire. Kenyan reporter Joseph Warungu proposed and presented a film on the hazards of skin-bleaching in The Gambia. The presenter of the programme on Nigeria, Toyin Fane-Kayode, bravely challenged the censorship of the country's military regime.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">An all-African camera and sound team led by Lawrence Mbada and Mandla Mlambo was responsible for the four films in the series that were shot by the South African Broadcasting Corporation (SABC). In the extremely difficult conditions of Angola and Namibia, an experienced SABC cameraman was used. Here there was a need to ensure that the less experienced directors were not further challenged by having to work with an inexperienced crew.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">For TVE's Robert Lamb, one of the main breakthroughs made by Africa Express was in the agreement of Channel Four to collaborate both with the SABC and with TVE itself, which insisted on the involvement and participation of African journalists, film-makers and technicians. He was impressed by the results and hopes that thee could be 'an even greater African involvement in another series, if one is commissioned.'</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The latest series was a success, being regularly watched by up to two million viewers.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Channel Four granted broadcasting rights for the series in lowincome countries to TVE and Worldview International Foundation as well as the non-broadcast rights to TVE and its partners in the third world. These   agreements allow TVE to provide the tapes at nominal cost to a network of video resource centres, similar to that run by Raphael Tuju in Nairobi. Such centres seek to get development-oriented documentary films shown by the local broadcasting stations but survive by supplying the needs of schools, colleges, non-governmental organisations and other categories of 'multipliers'.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">One of the most successful documentary centres is the Film Resource Unit (FRU) in Johannesburg. From its origins as a way of sharing bootlegged foreign films and TV programmes during the political repression of the 1980s, FRU is now a major distributor of educational and documentary films.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">To overcome the inexperience of state-owned African broadcasting networks in showing programmes of developmental relevance to their societies, video resource centres have to provide their own sponsorship. 'It is difficult for us to compete with the likes of Coca Cola, which will sponsor programmes like soap operas,' says Raphael Tuju, 'but one way round this obstacle is to sponsor a programme and at the same time advertise our services. The business we generate this way usually means that we can at least break even.'</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Film-making capacity in Africa has been severely limited by most governments' domination of the broadcasting media and a deep and institutional reluctance to encourage independent local productions. The mainly government-owned television stations rarely have a policy to buy in locallymade programmes and tend to look to Britain, France or the US for outside material, which is often dumped on the market at low prices, making it an even harder challenge for local producers to generate the funds to make their own programmes.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The decline of the once-active film industry in Nigeria, in particular, means that in English-speaking Africa, the field is now dominated by South Africa and Zimbabwe. In French-speaking Africa, the continuation of subsidies  has kept an 'art house' tradition alive, especially in Senegal and Burkina Faso. In most of the continent, however, the only development-oriented programmes shown to the public tend to be made by the governments' own propaganda departments rather than by independent film-makers.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Where there is a lack of access  to local broadcasting media, African film-makers continue to experiment with making their own dramas and documentaries, showing their work on video in village halls and schools. 'At the grassroots, African film-making can be stimulated simply by consumer demand,' says Russel Honeyman, who publishes the African Film and TV Yearbook in Harare. 'But local products do not usually translate into international products. Film and television is a global industry and film-makers should not insist on being too parochial. There is room for greater international collaboration.'</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Based on the experience of the latest Africa Express series, TVE now plans to build on its achievements. In May 1996, it exhibited the series to the directors of African television stations at a conference in Windhoek, Namibia, and discussed arrangements for distribution of the cassettes. It is also planning to  participate in a workshop for French speaking West African nations in Senegal under a grant from the European Union's human rights division. The consultative process will continue with a meeting of the African video resource centre network at the end of 1996.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">TVE's Robert Lamb hopes that the success of Africa Express might encourage international funding agencies in Europe to take up the challenge of funding films made in Africa for African consumption. He doubts that Channel Four on its own would take such a risk. Constraints are, perhaps inevitably, imposed on TVE's concept by the fact that programmes produced for European audiences use a production and editorial structure that requires 'post production' in European capitals. 'Although we came out owning the rights to the programmes in Africa, Channel Four still had 80% of the control over the production and editorial decisions,' he acknowledges.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Robert Lamb is fully aware of the challenges that lie ahead. 'National broadcasters are in a parlous financial position and are still, for the most part, stifled by government controls,' he notes. 'Africans who have received formal training rarely find the funds to apply their newly-acquired skills.' But Mr Lamb and his TVE organisation are convinced that there will be increasing demand for more programmes like Africa Express, as much from Africa itself as from European audiences. </P>
+<P ALIGN="JUSTIFY">R.S. </P>
+<P ALIGN="JUSTIFY"></P>
+<I><P>&lt;&lt;TOC4&gt;&gt; The Internet and the South</P>
+</I><P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY"> by Renaud de la Brosse</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The author, who works at the Panos Institute in Paris, reflects on the pros and cons of new information technology for countries in the South and on their chances of success.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The Internet has become such a craze amongst users in Third-World countries (researchers, teachers, businesses,, liberal professions, etc.) that it amply demonstrates that a real and genuine need is being met, despite adverse comments from its detractors. The rapid increase in the number of connections to the network in the North is mirrored by an exponential growth in the South. Africa is a good example of the possibilities offered by access to the global network whilst at the same time revealing the technical and financial restrictions facing countries in the South.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Almost all of Africa's 55 countries are today connected to the network, from South Africa, which has over 800.000 computers, to Uganda, which has just a few thousand. The importance of the Internet in Africa must be viewed less in terms of the number of computers (means of access to the Internet) and more in terms of the constant increase it represents in numbers of subscribers to the network. In the last six months alone, the number of subscribers increased by over 50%, whilst the increase in France, for example, was only 20%. Another telling figure is the number of host computers per 1.000 inhabitants, which rose by 147% in South Africa between 1994 and 1995 whereas the increase for Taiwan and Australia was 83% and 50%, respectively!</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Because it is under-supplied in communications equipment, Africa is starting out with a disadvantage compared with other continents. However, the recent G7 Conference on Information and Development, which took place in mid-May in Midrand in South Africa, brought together 40 countries and 18 intergovernmental organizations and made it possible 'to build a bridge between developed countries and developing countries' so that the latter are not excluded from the world of new information technologies. The benefit to be gained from the Net for the Black Continent lies in the fact that African surfers are anxious to break free  from their scientific, cultural or economic isolation which comes not only from relationships between Africa and the rest of the world, but often from relationships between regions and countries on the African continent itself.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Precursors</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">As in Europe and the United States, scientists and researchers in Africa are the first to have understood the importance of the Net and there are now - in French speaking Africa - networks such as the Intertropical Computer Network, which groups together approximately 3000 surfers in 11 countries. The importance of the Internet for these researchers is manifold; in most countries, the education system is in grave crisis, essentially because of diminishing budget resources which for years, on account of structural adjustment measures, have been melting away. This explains the absence of libraries or documentation centres. The Internet is therefore becoming a stopgap measure, offering access to all current scientific production and giving African researchers the chance to publicise and gain recognition for their work outside their own continent.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Interesting experiments in North/South cooperation are also being set up, with the French-speaking Agency for Higher Education and Research currently establishing what it calls a 'virtual French-speaking campus', a kind of vast library to which affiliated universities will be connected. The project is also justified in economic terms since, through the medium of electronic mail (e-mail), which goes hand in hand with the Internet, exchanges of information will be cheaper than by fax, for example, which costs at least five times as much for the same amount of information transmitted. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Outside the academic community, heads of African businesses are also launching themselves into cyberspace, particularly in the case of several hundred of them who have grouped together within a West-African Business Network. Internet's financial viability in the South is dependent on membership of African businesses and multinational companies established in Africa. The cost of subscription is still beyond the means of private individuals and only 'institutional' subscribers are currently able to guarantee payment in the short term.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">A useful tool</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Many of the possibilities on offer remain to be explored, so the Internet can therefore be an important medium for promoting African culture - Niger has set up a Web via which it is possible to visit its archaeological sites and Benin has just set up a server dedicated to voodoo. In general terms, there is the challenge of mastering content, in other words the African suffers should not restrict themselves to a  passive use (sleeking information from the North) but should, on the contrary, move progressively as players providing content and information. For the countries of the South, it is a matter of mastering information and preserving their culture.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The range of possibilities offered by the Net is limitless. Its development in Africa or in the South in general does, however, run up against a number of obstacles, including those of both a technical and financial nature. The importance of the Internet lies in being able to transmit greater quantities of information more cheaply than by using other communications techniques. However, the required technology is expensive and therein lies the principal difference between the North and the South.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The infrastructure which would permit rapid, longterm expansion of the Internet is nowhere near being installed in Africa, just as in the other developing countries. The continent is still under-equipped in terms of telephone lines; according to a survey by the BDT (Telecommunications Development Office), the number of main telephone lines per 100 inhabitants is less than 0.5 in sub-Saharan Africa, and in terms of equipment providing access to the Net (computer, modem, etc.). In real terms, this makes access to the network much more expensive for a user in the South than for one in the North. All these imported electronic goods are much more expensive than in the West, and this is without taking account of the additional cost, in most African countries, imposed by tariff barriers on IT goods, which are regarded with great suspicion by the authorities who perceive them as a potential danger more than as essential development tools.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The fear is that the remote transmission of data might pose a threat to less than democratic regimes. Under the pretext of 'the control of information-based wealth', a State may decide to interfere with the 'consent' or even 'suppress' a site for producing and exchanging information deemed contrary to its interests. Once more, the question of freedom of expression arises in different terms in the South and North. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The Panos Institute</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The Panos Institute is a non-profit-making association set up in 1988. Together with its counterparts in London and Washington, the Paris Panos Institute founded Panos International The Institute's aim is to strengthen, particularly in Africa, local expression and information capabilities. Within the context of sustainable and  better-shared development, it aims to promote the emergence of a more democratic culture and of more democratic debate. To this end, the Panos Institute runs two main programmes in west Africa from Paris and its branch offices (Senegal, Mali, Chad and Ghana).</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The programme to support pluralism in matters of information, which has four major objectives: - to expand and consolidate the legal, institutional and statutory framework of pluralist-type information - to increase professionalism in the media - to give institutional support to authors in west Africa who promote pluralism in information - to contribute to the production and circulation of more diversified and more qualified information on certain priority topics such as the environment, human rights, management and prevention of conflict, etc.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The migration and cooperation programme seeks to enhance the value of the contribution made by citizens from Third World countries residing in the rich nations to development in their countries of origin. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The European Union, UNESCO and the ACCT, American foundations (Ford, Rockefeller) or German foundations, and bilateral cooperation agreements (Denmark, Netherlands, Norway, Germany, France) support the actions of the Panos Institute. </P>
+<P ALIGN="JUSTIFY"></P>
+<I><P>&lt;&lt;TOC4&gt;&gt; The press in Africa as a tool in the democratic  process  </P>
+</I><P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">by Florence Win&eacute;ry</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Although radio is 'king of the media' in Africa, the press is increasingly becoming an active player in the democratic process.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">This has been seen particularly over the last six years in the French-speaking African states where a burgeoning of political parties has been matched by the appearance of an unusually large number of  newspapers. In these countries, the press still requires rudimentary political stability - in contrast to English-speaking countries, where it has a much longer tradition and can nowadays be generally regarded as the 'Fourth Estate'.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Nigeria is a good illustration of this. One need only cite the press campaigns mounted there to protest against the Federation's membership of the Islamic Conference Organisation in 1986, and more recently, the support given to Moshood Abiola. The vitality of the Nigerian press is something that deserves to be emphasised. Despite a series of measures over the years aimed at suppressing it (not exclusively by the military authorities) it is still much in evidence. There are demonstrations to support it, and it has 'gone underground' at times, continuing to publish clandestinely. The journalists' struggle intensified in June 1993, when it was recommended that they should exercise 'discretion and self-regulation'. In spite of the problems, the Nigerian press endeavours to remain a source of pressure in Nigeria's political and social arena.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Returning to the French-speaking media, we see that the pace of expansion varies considerably from one country to another. In Benin, for example, current discussions are centred  strongly on opening up the country's airwaves.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Is a private press a partisan press?</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">It is debatable whether the private press is truly independent. In the political sphere, it is often highly partisan while 'economic' independence - in the sense of access to the materials needed to produce a newspaper - is not always possible. Printing and distribution are often subject to monopolies which may constitute a form of disguised censorship for the publishers.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Initiatives aimed at setting up press associations in one form or another have been launched in an attempt to overcome these problems. This helps explain why the SEP (publishers' Society) was established. This group, which hopes to extend its activities throughout the region, is based in Benin where the democratisation process (and the proliferation of press titles) first begun. In many countries, media associations have already been formed covering specific areas such as radio, the press and publishing. There are plans for similar organisations in the field of television. Sometimes, they have printing facilities which are available to other private publications.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The principal challenge facing a general information-based newspaper is that it should appear regularly and on time. The next stage, ideally, is for it to be able to increase its distribution. Initially, a number of newspapers only came out monthly or even every two months. After appearing regularly for several months - and thereby achieving  relative financial stability - they then moved to weekly publication.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">In most countries, a new legal framework was also adopted, although the application of the legislation has often proved laborious. This is particularly true of the setting up of regulatory authorities. In Senegal, where the media was previously governed by a law passed in 1979 (and amended in 1986), new legislation was enacted at the beginning of 1996. The measure was prompted by concerns over ethical standards, a demand for a more 'responsible' approach, a desire to prevent monopolies developing, and fears of excessive foreign involvement. This year has also seen the implementation of media law amendments in Cote d'lvoire.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The focus of the work of many newly-formed organisations has been the drawing up of a professional code of ethics, with a view to defining the basis of the journalist's profession. In Cote d'lvoire, the OLPED (Press Freedom and Professional Ethics Monitor) was created in September 1995 in Yamoussoukro at a seminar on journalists' responsibilities during elections. The OLPED is made up of 13 members representing publishers, civil society and the nation's journalists. Although the 'Monitor' has only moral authority, it has had considerable influence on journalists' professional consciences.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The OLPED held weekly working sessions up to March 1996 and now meets every two months. One of its main achievements has been to define the criteria whereby a responsible attitude can be guaranteed.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Vigilance</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The press can expect to be subject to rigorous supervision during an election campaign - as happened recently in Benin. Indeed, Benin's press has attracted special attention from various national institutions including, most notably, the NGO community. This interest resulted In the organisation of seminars on journalism during an election period, designed to avoid incitements to violence. The HAAC (Audi  ovisual and Communications High Authority), responsible for statutory control of the media in the run-up to and during the campaign, took part in these meetings which were aimed at increasing awareness and highlighting the heavy responsibility carried by the media.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Despite a number of incidents during the campaign (which were immediately reported) and although the situation threatened to get out of hand while the country was obliged to wait for the publication of the results of the second round, the press conducted itself in a fairly moderate manner. It should be recalled that there was a great deal of apprehension in Benin before the results were announced with a widespread fear that violence might break out. These fears were given extensive coverage by the media.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The HAAC proved to be central to the electoral process and, ultimately, the press was congratulated by most political leaders in Benin, and by those from abroad who were involved in organising and observing the poll, for the role that it played in the process. By and large, it concentrated on portraying popular expectations.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">During an election period, the print media is an essential vehicle of opinion and power, justifying the creation of special titles.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">At present, the private press is playing an increasingly important role in the democratic process and the question of its survival appears to have attracted more serious attention from the authorities. In Senegal, a subsidy has been granted to a number of newspapers, subject to certain conditions, and Mali set an example this year by establishing a private press aid fund, with Cote d'lvoire about to follow suit.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The political context which has favoured this flourishing of the private press has had a marked influence on the way it has developed and on the editorial content of most journals - which is strongly focused on politics and 'national' issues. The press has barely had a chance to find its feet on the media scene and in the political process, and it has had to contend with huge  economic constraints. Low circulation figures are one key reason for its precarious position - newspapers are read only by an educated, urban minority. However, the press is now embarking on a new course, attempting to establish a loyal readership with a view to guaranteeing its long-term survival.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Independence and integrity ought, of course, to be the hallmark of journalism, although currently it is not  possible to say that the profession is dissociated entirely from political militancy. In the past, the press has played  a part in undermining the national consensus by promoting division and, on occasion, fomenting exclusion and confrontation. The issue today is whether the sector can now take its place in states governed by the rule of law, representing public opinion and helping to bring about a rapprochement of ideas. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">F.M. </P>
+<P ALIGN="JUSTIFY"></P>
+<I><P>&lt;&lt;TOC4&gt;&gt; Benin's press on parole?  </P>
+</I><P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">by Richard Lawson T&egrave;vi</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">When President Mathieu K&eacute;rekou of Benin granted permission to set up private newspapers in his country, the result was an upsurge of new titles. The following article is written by a journalist who works on  one of these publications ('Tam-Tam Express'). He offers an assessment of the way the private press has developed in Benin, and in particular of the ethical and economic challenges it needs to overcome in the new democratic order.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">In 1988, President K&eacute;r&eacute;kou's revolutionary regime authorised the setting-up of private newspapers in Benin. At the beginning, only a limited degree of freedom was granted to new publications but things have evolved quickly. 'La Gazette du Golfe' and 'Tam-Tam Express', the first independent weeklies to be set up (two years prior to the 1990 national conference), went beyond what the Marxist regime had in mind and effectively achieved press freedom in the face of opposition from the Ministry of Information and Propaganda.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Journalists took advantage of their initial limited freedom to publish reports about political and financial scandals and this, not surprisingly, gave a new lease of life to the media more generally in Benin. In particular, journalists from the national radio and television  channels were quick to switch their style of reporting, dispensing with the stereotyped formal language which had previously characterised the public-service media.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Meanwhile, several politically oriented publications came into being ('L'Opinion', 'La Recade', 'Le Canard du Golfe'). This development gave newfound dynamism to the emergence of a free and independent press in the crucial period prior to Benin's national conference, which was held in February 1990.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">To date, 170 titles have been registered with the Ministry of the Interior, although barely half of these have been published more than five times. Some appeared only once and many have existed in name only. Publications which have had only a sporadic existence are legion and, in the years between 1991 and 1996, when political power alternated between Presidents Soglo and Kerekou, independent privatepress titles flourished. Unfortunately, they faced a number of problems - such as prohibitive paper and printing costs and poor distribution networks. The result was that many operators were financially ruined as a result of their decision to venture into this area of publication.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Currently, the Benin market has only 20 or so titles which appear on a   reasonably regular basis. For the most part, these are two-weekly and monthly publications which concentrate their activities in Cotonou. The audiovisual media are conspicuous by their absence, despite the provisions of the Constitution adopted in December 1990, which gave special powers to the HAAC (Audiovisual and Communications High Authority), particularly as regards guaranteeing 'press freedom' and 'opening up the audiovisual sector'. No one knows when this law will actually be implemented, but it does appear that the Benin Parliament, which sits in Porto Novo, has been giving more attention to this issue since General K&eacute;r&eacute;kou's accession to power.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The relationship between the press and the state</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Governmen/press relationships are not particularly healthy at the moment. The usual reflex of authorities in any country is to control or manipulate the press wherever possible. At the ORTB (Benin Broadcasting and Television Office), a branch of the public sector, journalists often complain of the pressures they face in processing information. The same is said at the national daily, 'La Nation'. Fortunately, such pressures have not always shaken the resolve of the professional journalists.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The private press has a different problem. In this case, it is the newspaper proprietors who look to collaborate with the political parties. As one publishing editor has said, 'Our problem is more one of allegiance than of harassment'. Virtually all publications are political vehicles for one or other group - which makes nonsense of the code of ethics that is supposed to govern the profession. This phenomenon was most marked during the election period. All the titles that had been in 'hibernation' came to life again and new titles were born, only to disappear once the poll was over. This is also a reflection of the very meagre resources available to most private publishers. Those who do have sufficient means are usually quick to offer allegiance - for example to particular businesses - in order to position themselves more favourably from an economic  standpoint. Thus, some of the press rather overtly promotes particular economic interests. Others assiduously woo politicians and, in some cases, use blatant blackmailing techniques. In the latter situation, the 'market' operates on the basis that a file (sometimes assembled from a number of documents) will not be published if an endorsement is given or - what is worse - in return for hard cash. The justification for this shameful practice is that the market is highly restricted, sales of newspapers bring in very little income and advertising is non-existent but the newspaper has to keep going nonetheless. This situation also explains why defamation actions are frequently settled 'out of court' by the parties to the dispute.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">A profession fraught with difficulties</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Another explanation for the existence of blackmail is the lack of training. The majority of journalists working for private publications come into the profession for want of something better to do, after they have finished their university courses. One experienced journalist refers to these people as mere 'hirelings'. It is only once they have entered the profession that they learn the basics through joining journalists' associations and by receiving support from some of the bilateral-cooperation missions and foundations that are operating in Benin. The country does not, itself, have any colleges of journalism to speak of. Only recently, the national daily newspaper inaugurated a course for young journalists receiving their training on the country's various publications. This course will be spread over one year.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Young journalists working at the national agency, the Benin Press Agency, are trained by WANAD (the West-African National Agencies Development) centre, under the auspices of UNESCO, which is subregional in vocation. The 20 or so trainees have no clear idea of what awaits them when they finish their course - whether all, or just some of them, will be taken on full-time by the agency. Those who are not kept on at the end of their training period are likely to  swell the ranks of the 'hirelings' - who seem fated to remain at that level.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The new administration will have to tackle the more general question of aid to the press in order to give a fresh boost to the private sector. This has been facing a real struggle since the devaluation of the CFA franc. The effect of the devaluation was to increase the cost of all the inputs needed for publishing newspapers. A new initiative of the part of the authorities would make it possible to offer more work to journalists and to improve considerably the quality of work they produce. To quote the publisher of a private newspaper: 'The influence of money must be curbed. To do this, the state must grant genuine aid to the press so that the profession can be genuinely free and objective and thereby fulfil the important role it has to play in the consolidation of democracy'. R.L.T. </P>
+<P ALIGN="JUSTIFY"></P>
+<I><P>&lt;&lt;TOC4&gt;&gt; Current media in the English-speaking Caribbean </P>
+</I><P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">by Dr Marjan de Bruin</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The author of this abridged article, who leaches et the Caribbean institute of Media and Communication (CARIMAC) at the Mona (Jamaica) Campus of the University of the West Indies, focuses on some of the peculiarities of press and media development in small island Caribbean states.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The English-speaking</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Caribbean comprises thirteen independent nations that are members of Caricom (the Caribbean Community) and a few  remaining small dependent territories. The total population is about six million. In most of these countries, the majority of the population is of African descent although in Trinidad and Guyana, about half the people are of Asian (Indian) origin.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The sea, whose name unites the islands, is a serious barrier to communication and social interchange between them. it takes as long to go by plane from Barbados to Jamaica (1200 miles direct, but 2000 miles via Miami) as it takes to cross the Atlantic from Paris to New York (3600 miles) - and the latter journey is usually cheaper! And until fairly recently, telephone calls from neighbouring Caribbean countries without a common language were routed through London, Paris or Miami.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The distances make communications difficult. Mail can take weeks, telephone circuits are often overloaded and, in some countries, unscheduled power cuts often disrupt computer systems at the most inopportune moments.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Communication and the media</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The Caribbean has a strong oral tradition. This, together with poverty and an estimated general literacy rate of about 80%, makes radio the most popular medium. Recent studies show,  for instance, that 99% of Jamaican households reported having at least one radio at home. In Jamaica alone, three large national radio stations between them broadcast nine hours of prime time call-in radio.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">In all Caribbean countries, alongside the mass media, 'alternative' medias play an important role in communication for social change. In some countries, the term simply connotes non mainstream operations. In others it refers to alternative formats which are found in the mainstream media. The term also represents the use of other communication behaviour - popular theatre, dance, music, oral history, story telling. It has been suggested that the increased use of alternative media and alternative uses of mainstream media are an indication of the audience's dissatisfaction with the mainstream mass media.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">In most English-speaking Caribbean countries, the government owns some of the major mass media, especially electronic. Only recently has the private sector developed its own strongholds in radio and television. Print has always been an area of mainly private ownership. Only the larger countries have daily newspapers; morning or evening papers - although usually not more than two or three. In the smaller countries the press consists of weeklies, or bi-weeklies.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Government ownership</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Ownership or control of media houses by governments is recognised as  a serious obstacle to true investigative journalism.The economies of all Caribbean countries are heavily dependent on tourism. Stories on environmental hazards and crises which might affect this essential source of income are subject to explicit or implicit (selfl censorship.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Government ownership in some instances means policy discontinuity over time; each new regime imports its own set of administrators and sometimes even entire newsroom staffs. In other instances, where the same party has ruled for a long time, positions within the media are very stable because they are tied to political loyalty.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Private ownership, however, does not mean an absence of potential pressure or political influences. In Trinidad &amp; Tobago, the country's oldest daily - The Trinidad Guardian - recently lost its Managing Director, its editor and six of its top editorial executives, after the owners - a supermarket chain - pressurised the editor to moderate criticisms of the country's new administration. The owners also tried to convince the managing director and editor to dismiss a columnist who was a disaffected and now hostile former member of the new ruling party. In apparent justification, the owners produced a document which suggested that it was the policy of the Guardian not to endanger the commercial prospects of its owners by injudicious criticism of the powers that be. Caribbean journalists attacked the Guardian ownership for what some saw as an attempt to turn a respected newspaper into the public relations arm of a commercial congLom&eacute;rate. Despite the protests, the Guardian's new editor, a veteran of forty years in journalism, argued that the proprietors had good reason to interfere with his predecessors.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The region's oldest daily, The Jamaica Gleaner (established in 1834) went even further. In an editorial it said: 'In our view the owners have a right to oppose the way in which the judgment of the Editor and others is exercised. The right of the Guardian Board to query content cannot be questioned. It is impossible for a newspaper to be run   without the input of the Board of Governors.'</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Small markets</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Most English-speaking Caribbean countries are relatively small in population as well as area. The number of media organizations is limited. The limited size of the market has important implications for the financial basis of the media, especially the part that is privately-owned. It limits the horizontal mobility of media workers - there are simply not that many options - and it makes the relationship between media and sources extremely vulnerable. There are not that many sources either. It also means that most Caribbean media houses have very limited resources. Many reporters have to cover a wide range of topics. Specialised reporting for instance on the environment, or health, is usually not feasible.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">One of the major problems in the Caribbean media is the high proportion of imported television programming. The region is geographically close to the United States and satellite broad  casting makes access to the Northern networks even easier. In the ten years from 1976 to 1986, the imported content of four large television stations in the region moved from an average of 78.5% to 87%. When the amount of imported content carried by the smaller stations was included, the average increased to 90% of all material televised.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Privatisation and new technologies</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Several of the larger Caribbean countries have seen an explosive growth in the electronic media. Jamaica, which has a population of about 2.5 million living in some 620 000 households, and per capita GDP of $1563, has seen the number of radio stations grow from three to nine and TV stations from one two, in a period of just five years.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Trinidad &amp; Tobago, with 1.2 million inhabitants in 300 000 households, and per capita GDP of $4049, went through a similar process, with seven new radio stations and two new, privately-owned TV stations being set up over the last five years.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Barbados, with a population of 260000 living in about 50000 households has long supported two daily newspapers. There are also two TV stations on the island, while viewers can receive television signals from neighbouring islands. This country has the highest per capita GDP in the region ($5562) after The Bahamas ($10,308).</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">One positive effect of this intensive growth is certainly to be found in the increased employment opportunities for broadcasters. In the past, journalists risked their careers if they disagreed with their employers. Now people have more options. However, increased competition in a relatively small market also enlarges the risk of commercialisation and a lowering of standards. One does not need to undertake in-depth research to discover that locally-produced television is scarce and not always of the highest standard. It is cheaper to buy foreign programming than to produce original content. Some   of the graduates of the Caribbean Institute of Media and Communication, who performed above average during their training and education in print journalism, can be seen sliding down the standards scale once they enter the mass media as working journalists. Similarly, the standards of newsrooms are not always high. In fairness to the professionals, it must be said that the decline in standards is partly due to the lack of resources in editorial departments. The major newsrooms in radio and television in Jamaica, still depend on typewriters.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Development of new technologies has contributed to two almost opposite movements. On the one hand, greater access to worldwide networks has widened horizons. On the other, the introduction of cable TV offers, at least in principle, the possibility for small-scale communication initiatives, such as community radio stations either for geographical communities or communities of interest (for example, people or groups interested in the environment).</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Satellite dishes, VCRs and computers are breaking down traditional communication borders. In the Jamaican capital, Kingston, 28% of households have a dish and 21% a computer. The picture is very different just 20 miles away, in the neighbouring but rural parish of St Thomas, where the figures are just 1% and 2% respectively. New technologies are affordable for the happy few and are increasing the gap between the 'haves' and 'have-nots' of information.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">In all of these societies, computers sit uneasily in otherwise nondigital environments. The information that one works with is usually not computerised. Many records are still handwritten, with data kept on index cards. Computerisation is a costly process for which there is rarely a budget.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Once the hardware is available, it is easy to retrieve data from non Caribbean sources. At the same time, it is barely possible - at least at the moment - to tap into Caribbean data sources. There is no commercial Caribbean software. Page make-up and layout programmes, for instance, rely on  non-Caribbean electronic clip-art-images and symbols. It may simply be a matter of time before local products develop, but currently, the main constraints are to do with lack of funds.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Journalism</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">How is journalism faring in this environment ? The Caribbean context gives journalism a special professional profile. The small size of Caribbean societies has implications for the use of sources. Access is easier, but it also creates sharper dilemmas where loyalty is concerned: most sources are people you know personally and who know you. Anonymity is almost impossible.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Because the societies are so small, you will meet many of the same people in different roles on different occasions. The small scale of the market makes all enterprises in media and journalism very vulnerable to market forces: the withdrawal of one or two major advertisers would endanger the chances of survival of some media houses.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The situation of the press is most marginal in the smaller countries. In Antigua (population 66000), radio and television are controlled either by the Government or by people with close links to those in power. One opposition paper, a trade union publication, has survived several legal assaults by the authorities over the years. The other, little more than a newsletter, has managed to survive into its second year.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">In Grenada (population 91000), journalists complain about police harassment of reporters on duty, and in most of the smaller countries, journalists are uneasily aware of the continuing hostility of long-ruling political parties.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The working environment of journalists in Caribbean media organisations is usually more modest compared to that of journalists in rich countries. There is less technology, smaller staffs and lower salaries. In the smaller Caribbean countries, it is not unusual for journalists to have to combine two jobs. Journalism alone cannot pay the bills.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">There is a sharp difference between rich and poor in most developing countries. For large sections of the population, the big decisions will have nothing to do with buying a second or a third television set.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">It is more likely to be a simple matter of whether there is food on the table tonight. These different priorities obviously influence a journalist's agenda.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">In developing economies, this can create serious dilemmas for the journalists: if you know your story is likely to hurt the tourist industry - which happens to be the main national income earner of your country - will pursuing it be a waste of valuable time ? And how do you decide on the relevance of a scoop when people - some of whom are your friends - could lose their jobs ? </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">M.d.B.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY"> Sources</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Hilary Brown (1995): American Media Impact on Jamaican Youth: The Cultural Dependency Thesis in 'Globalization, Communications and Caribbean identity', Edited by Hopeton S. Dunn, Kingston, Jamaica, lan Randle Publishers. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Aggrey Brown and Roderick Sanatan !1987). Talking With Whom ? A Report a the State of the Media in the Caribbean. Caribbean Institute of Media and Communication (Carimac), Kingston, Jamaica. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Aggrey Brown (1995). Caribbean Cultures and Mass Communication Technology: Re-examining the Cultural/ Dependency Thesis, in 'Globalization, Communications and Caribbean Identity'. </P>
+<P ALIGN="JUSTIFY"></P>
+<I><P>&lt;&lt;TOC4&gt;&gt; 'Doctoring' the image</P>
+</I><P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">With modern computer technology, it is now very easy for publishers (and film-makers) to dabble with reality. Whereas in the past, you could be reasonably sure that what you saw was a fair representation of what actually happened, today there is no such guarantee.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Recently in the United Kingdom, one of the country's regional newspapers came in for criticism when it published a 'doctored' photograph of a well-known opposition politician. He was captured on  film at a social function sitting at a table with a glass of beer in front of him. By the time the paper's computer experts had finished with the photo, it looked as if he was drinking champagne ! When the story broke, the journal thought it expedient to issue an immediate apology. For while  this kind of misrepresentation may appear trivial, in the modern age, image is crucial for those who are involved in public life. Put simply, voters' are more likely to look kindly on beer-drinking politicians than on those whose favourite tipple is champagne.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">There was a similar case involving an advertisement issued by a well-known car manufacturer. For their publicity in Britain, the company used a landscape photo portraying a selection of their employees. In Poland, the same picture was used but black and Asian workers were no longer to be seen. Their places in the line-up were miraculously taken by people of Caucasian appearance. The advertisers' rather surprising explanation was that this had been a 'mistake'!</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Other recent victims of 'doctored' pictures or socalled 'photo collages' have included members of the European Parliament and a senior EC official, although these particular misrepresentations received very little publicity.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Should consumers of printed or broadcast material be entitled to assume that images are never tampered with ? And if some doctoring is acceptable, where do you draw the line ? The answer to the first question is clearly no. There are certain situations where photo or film enhancement techniques are unobjectionable. We sometimes use them on The Courier cover pages to remove blemishes or fill in gaps which may detract from the main image. In fashion  advertising, it is common for the 'look' of the model to be altered. The aim here is to draw the reader's eye to the page so that their attention can then be focused on the product. More dramatic alterations may even be acceptable if it is evident to the reader that a change has been made. Satirical articles, for example, can sometimes be amusingly illustrated with obviously altered images.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Where the practice is reprehensible is where the picture has been changed in a way that leads the reader to draw false conclusions about what he or she is observing. The  classic example of this is where the image of a person captured in one setting is placed against a different backdrop, without the reader being informed. This may be done to give either a more positive or a more negative impression (the latter approach is more usual) but in either case, it is dishonest. If a politician allows himself to be photographed on a Caribbean beach while on mission at the taxpayers' expense, even if he was only there during the lunch break for a quick dip, then he can't really complain. But if the picture was actually taken when he was on holiday in Majorca, and superimposed against a more exotic back  ground, then both the 'victim' and the reader are being cheated.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">There will always be borderline cases, but in principle, it ought to be possible to draw a reasonably clear distinction between 'right' and 'wrong' in this area.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Nonetheless, it is likely that distorted images will continue to be presented to us in the future. In pluralist societies, newspapers and broadcasters operate in a fiercely competitive environment and in theory, this should provide a deterrent. If one media organisation is found to have doctored images in a dishonest way, there will always be plenty of others willing to expose the misbehaviour.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">In practice, however, the only real deterrent is the likelihood of a drop in circulation, or lower viewing figures. And while consumers may say they disapprove of journalistic dishonesty (whether in photographs or the written word), there is little evidence to suggest that they react by taking their custom elsewhere. Indeed, in some developed countries, the closer a journal sails to the wind, the more likely it is to enjoy a high circulation!</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">It used to be said that 'the camera never lies'.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Nowadays, we can't be so certain.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">S.H.</P>
+<P ALIGN="JUSTIFY"></P>
+<B><P ALIGN="CENTER">&lt;&lt;TOC2&gt;&gt; Analysis</P>
+</B><P ALIGN="JUSTIFY"></P>
+<B><P>&lt;&lt;TOC3&gt;&gt; Broadening the debate</P>
+</B><P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">In issue 156 of The Courier, we announced the launch of a programme by the European Centre for Development Policy Management on the future of KU-ACP relations beyond Lom&eacute; IV. Here, we publish an abridged text supplied by the ECDPM reporting on progress.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">After 20 years, the Lom&eacute; Convention is thought by some not to have lived up to expectations and now that East West rivalry is no longer an issue, many doubt its continued relevance. Questioning, as such, is no bad thing, provided it takes place in a fair and unbiased manner and is not used as a pretext to abandon the acquis  of more than 20 years of cooperation. This is the rationale behind a number of private and official initiatives to redefine KU-ACP cooperation.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Consultations</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The ECDPM's post-tome IV exercise has now been up and running for more than a year. Consultations have been held in more than 20 ACP countries, involving representatives from the private and non-governmental sectors, officials in the National Authorising Offices, EC delegations, regional organisations and research centres. A number of strong impressions have emerged from these interviews. In the first place, the initial comment of many NGOs and private sector representativ  was essentially 'what is in it for us ?'. This points to a lack of knowledge of the Convention in non-governmental circles and suggests that this complicated instrument is not entirely 'user-friendly'. Its government to government character was also criticised. There were calls for ACP-KU relations to be opened up to the private sector and civil society. In this context, experience with decentralised cooperation was seen as encouraging.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Second, the benefits of the Lom&eacute; trade provisions were highlighted with fears being expressed about what would happen after the year 2000. It was felt that at a time when many ACPs  are undergoing structural adjustment, and the private sector is getting its act together, a clearer European commitment in this area would benefit both sides.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Various actors from the private, NGO and research communities indicated a willingness to engage in debate on redefining mutual ACP-KU interests and on the design of a new cooperation contract. Some of them had an opportunity to present their views at an ECDPM conference on the future of KU-ACP relations held on 12-14 June.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">It is clear that the process of reflection is now firmly under way. At the institutional level, the Joint Assembly began as far back as February 1995, when it launched an action plan to revitalise KU-ACP cooperation. This year, it asked Senator Jean-Louis Firmin of Haiti to draw up a report on the future of the Lom&eacute; Convention. It also requested the Social Partners to tackle the issue at their next annual meeting in November 1996. On the European side, the Commission will present a Green Paper later this year while the ACPs are also studying the question. Last November, the ACP Council resolved that Heads of State should meet before the end of 1997 to agree on a joint position.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Obstacles</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">All this activity suggests a real awareness of what is at stake. Many obstacles have to be overcome, however, if a new type of partnership is to emerge. The main pillars of Europe's commitment to the ACP countries - aid and trade - both appear under threat. It will be necessary to redefine mutual interests - beyond the negative interdependencies - so that they can serve as a basis for a more modern and effective partnership. Greater creativity  will also be required to find new forms of EU support on ACP trade issues that are compatible with World Trade Organisation obligations.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">An in-depth rethink of ACP-KU cooperation will significantly benefit from inputs by actors traditionally excluded from the discussions - who are anxious to participate in redefining cooperation ties. For instance, in Namibia, NGOs called for formal consultation mechanisms for non-governmental actors. Similarly, economic operators meeting in Trinidad in November called for a new Europe-Caribbean partnership. There should also be a role for applied research conducted in ACP centres. There is already a joint research project on the future of West Africa Europe relations and similar initiatives are being formulated elsewhere.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The plea for a debate that is open to the key ACP actors should be taken on board by decision-makers and negotiators - and thus far, they have proved receptive. However, two conditions are needed to maintain this fruitful exchange. First, ACP stakeholders need to be able to base their views on full knowledge of the facts and issues. It is essential that the Convention's authors make a major effort to provide more and better information. The ECDPM is willing to play a part in this. Initiatives already under way include the development of EUFORIC - a Forum on the Internet for specialised information on European development cooperation - and the preparation of practical guides to the Lom&eacute; Convention. Enhanced access to information can help all partners move towards a real dialogue. Second, forms and channels for dialogue. need to be devised to ensure that an open debate is sustained beyond the initial reflections taking place within the EU and ACP groups.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">ECDPM</P>
+<P ALIGN="JUSTIFY"></P>
+<B><P>&lt;&lt;TOC3&gt;&gt; 'Re-compromising' development aid for the future </P>
+</B><P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">by Jos Jonckers</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The author of this article offers an academy critique of *e challenges facing the global system of development cooperation in the post-cold War era. He argues that the old compromises that have shaped development assistance since the Second World War have broken down and pleads for a radical re-think of the strategy in order to 'enable' fess affluent societies to gain from the advent of global 'free market democracy'</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Let us face it. International development early 50 years, the developed world has taken aid for granted. It no longer does. In real terms, it has started to give less. The expected 'peace dividend' has not materialised and scepticism is rising. Aid and solidarity are considered old-fashioned concepts. Progress and development, it is increasingly argued, must come from cooperation based on mutual interest and a businesslike approach.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Aid scepticism is at its highest in the USA. A conservative majority in Congress promotes radical 'winner' recipes and aid has been slashed. Slowly but surely, America is getting out of the development business. Lacking domestic support, the Clinton administration seeks to 'rescue' the country's aid programme by seeking more cooperation with other donors - particularly the KU, whose solidarity horizons do not yet stop at its own borders. But even here, horizons are shrinking. European aid to its immediate neighbours in the East and the southern Mediterranean basin has risen. Happy and prosperous neighbours suddenly seem more important than distant friends in need.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Has the end of the cold war marked the beginning of a cold world - where international solidarity is being dismantled together with the nuclear warheads ? Or could we be experiencing the beginning of a fundamental reshaping of international solidarity and aid between nations?</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Beyond altruism - self interest</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">International aid has always involved a compromise within affluent society. People and nations are not normally disposed to give something away unless they receive something in return. Any attempt at understanding and reshaping the future of development aid must therefore start from the premise that those providing development aid do so as a result of a complex and evolving compromise between altruism and self-interest.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Affluent countries are usually only interested in assisting poorer ones when the effect is to strengthen their international leadership, and in some way to enhance their security and material wellbeing. Looked at in this context, we must recognise that development aid, whatever its altruistic aims, will only exist if it also serves the legitimate, albeit more selfish agenda of the donor. It also means that the compromise which gives aid its rationale in affluent society changes over time: aid is regularly 'recompromised'. In secure and prosperous times, donors are  more inclined to forego self-interest and to cooperate in the interest of less affluent countries. In times of insecurity, the altruistic dimension is likely to diminish in importance.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">In colonial times, systematic aid flows first emerged as a result of a compromise between expansionist Northern governments and Christian society with its own 'colonizing' clergy. Decolonisation had the effect of increasing insecurity in most former colonial powers. In an attempt to safeguard the capital they had 'invested' in their overseas territories, following the latter's independence, they increasingly shaped aid with a view to 'buying' goodwill from the new rulers. This process, which 'recompromised' aid from a colonial into a neocolonial form, resulted in the secular, institutionalised arrangement now known as 'bilateral aid'. In addition, during the Cold War, Western aid was used increasingly as a device to stop the Third World joining the Second World (the communist bloc). The result was an aid system which was both more internationalised and more politicised.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The next stage came with the end of the Cold War. Communism had joined colonialism and fascism in the dustbin of history. Affluent Western society had emerged as the winner. With it came the Western vision for stability, peace and progress: a world of sovereign nations, organised on the basis of democratic and capitalist market principles and committed to respect for each other's territory and for basic human rights. Today, capitalism has become the norm in most nation states. Long-time sceptics such as India, and even convinced opponents such as China and Vietnam, have embraced it. Democracy has not yet achieved the same coverage, but it is sailing forward under favourable conditions. Political pluralism is steadily being consolidated in much of East and Central Europe, while dictatorial regimes in Africa, Asia and Latin America are now the exception.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The effect of all of this has been a speedy erosion of the terms of the compromise on which development aid thrived for so long. In a rapidly globalis  ing,multi-polar world, the old approaches appear increasingly redundant. From this perspective, the current aid crisis is not surprising and is not necesarily a bad thing. Western affluent society is essentially trying to come to terms with the demystification of its development aid, as part of a process of reshaping it for the future.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Three 'recompromising' strategies</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">As in the past, the recompromising process is influenced by both self-interest and altruism in affluent society. Three trends can be identified.. The first, which is the most idealistic, involves restoring altruism. This approach seeks to 'purge' aid of the perverse political and economic compromises and contradictions caused by decades of neocolonial and Cold-War self-interest. It has impacted on aid in several ways. First, it has given a significant boost to humanitarian aid - the most altruistic form - at the expense of development assistance. Second, it has led to a 'decentralisation' of aid - with more assistance being channelled through organisations such as NGOs, that have an 'uncompromised' altruistic profile. Third, it has led to a 'deconstruction' of development aid along idealistic-altruistic lines. 'Women in development', 'child health', 'environment'and 'poverty alleviation' are all examples of deconstructed labels around which aid is increasingly being structured and justified. Finally, it has prompted an 'intellectualisation' of development aid with the particular purpose of tightening its altruistic aims. For example, the Logical Framework Approach, the concept of 'sustainable development', the UNDP's Human Development Index and various experiments with more 'accountable' project management systems, have all essentially been devised as ways of encapsulating and supporting the altruistic intentions that lie behind aid.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The second recompromising strategy, which may be summed up in the expression be businesslike, approaches development cooperation  much more skeptically. Aid, it is argued, only makes sense if it leads to real progress and development - and the prevailing view is that this is not happening. The approach is fueled by the obsession of trying to measure progress with the help of business tools such as 'output', 'impact', 'efficiency', 'rates of return' and so on. This has led to burgeoning aid 'evaluation'. It has also probably contributed to the discovery of aid failures which, in turn, has prompted growing criticism of aid agencies and operators. The businesslike strategy has gained further ground because of the failure of many countries to achieve any real progress in recent decades. Its advocates argue that the compromises which undermined aid's development impact in the past are inherently linked with its altruistic nature. The conclusion is that altruistic aid will seldom or never work. The strategy has impacted on aid in a number of ways being, for example, the major cause of so-called 'aid fatigue'. It has also prompted a search for ways to enhance cooperation for mutual benefit, indeed transforming the narrow, pre Cold War trade cooperation link with developing countries into a much broader and rapidly growing economic cooperation approach. Finally, it has sought to enhance aid's impact on the economic conditions and growth prospects of developing countries through more ambitious, structural-oriented forms of aid.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Regionalism, the third major strategy, is linked to globalisation. Rooted in human survival psychology, this approach prompts nations in close proximity to form 'strategic' coalitions. In the post-Cold War era, development aid is one of the instruments used by affluent regions to strengthen their position in a 'globalising' environment. The strategy entails promoting 'open' regionalism elsewhere in the world and capitalising on this to create linkages and interactions which enhance their own influence or hegemony. From the point of view of the international political economy, this makes perfect sense. Having succeeded in making the 'world of nations' accept capitalism and democracy, it is through the consolidation   process of free market democracy in other countries and regions that powerful affluent nations will seek to gain maximum advantage.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Need for a vision</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">With this improved insight into the dynamics that have been reshaping development aid, is it now possible to go further and develop a more political vision of relations between affluent and less affluent nations in future ?</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Free market democracy, having endured the 'crises' of decolonisation, fascism and communism, has succeeded in promoting stability and peace within and between nations. Its main strength has probably been its crucial enabling function, with an increasing number of people and nations now in a position to 'earn' a better future. It appears that the model has the capacity to generate fairly equitable growth and progress, which is presumably why more and more countries are turning to it. As is so often the case, however, the strength of the system also contains the seeds of its weakness. Conceived as an 'enabling' mechanism, it results in the categorisation of those who fail to 'be enabled' as 'unable'. Marginalised because they cannot participate and perform in the   system, the excluded (whether individuals or states) are dubbed 'losers'. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">They are seen as a burden and a threat by the 'winners'. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The result is disparity in society.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Experience in most affluent nations suggests that despite the enabling environment created by free market democracy, up to a quarter of the population finds itself unable to perform effectively, and is marginalised as a result. Moreover, there seems to be an upward trend in the numbers affected by unemployment, underemployment and poverty. Disparity never occurs without some cost to society, which is a good reason why it ought to be minimised. The costs come mainly in the form of internal transfers earned (but foregone) by the active, 'winning' section of society. In more sociallyinspired, free market democracies, it is accepted that marginalisation resulting from the model's shortcomings must be minimised and/or adequately compensated for. In more conservative free market democracies, exclusion is seen more as a weakness of individuals than of the system. Compensatory transfers are generally kept to a minimum to induce people to 'break out' of their situation. But while such societies may save on 'empathetic' transfers, they will generally need to spend much more of their wealth defending against threats posed by growing disparity, such as crime, drug-trafficking and political extremism.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The costs of disparity are political as well as financial. Genuine democracy is based on the participation of a representative majority of citizens. In affluent societies, however, a growing minority no longer participates. The real danger stems from the fact that this is highly skewed. It is the same, growing, marginalised minority that is 'unable' to participate which is also withdrawing from democratic involvement. The result is alienation from the political system and an erosion of democracy to the extent that its very survival may be threatened.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">What is really at stake </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Having conquered most of the world's nations, free market capitalism is now set to conquer the world of nations, helped by technological advances in communications, transport and computer technology. Economists have amply shown that the interdependence resulting from free international competition need not be detrimental. Indeed, because global capitalism ensures that ideas, initiatives and resources can be 'put to work' anywhere in the world - wherever they generate most profit - interdependence is usually seen as mutually beneficial. In essence, it confirms what might be called the global enabling effect of free-market capitalism. The basic thesis is that the adoption by less affluent nations of free market democracy should 'enable' many more of them to improve the lives of their people in the coming decades. The boost engendered by this 'enabling effect' will, in turn, help to sustain progress in the more affluent countries.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">If this is the aim, then a new vision should progressively inspire future cooperation between the affluent and less affluent countries. The first concern should be to define 'purpose' and 'interest' much more in terms of system and process, than of output. What really matters is the 'enabling potential' of free market democracy in the specific context of the less affluent countries. How something is achieved and by whom should take precedence over what is achieved. The ultimate aim must be to ensure that free-market democracy 'takes root' in less affluent nations and is able to determine who does what and how.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">A second major concern should be to maximise the 'enabling potential' of free market democracy for the most vulnerable sections of individual populations. As mentioned earlier, up to a quarter of the people in affluent societies are excluded. In poorer countries, the figure is much higher. If free market democracy fails to enable a significant proportion of this marginalised group, then it will not take root. And if the poor cannot be mobilised, the  growth that does occur will be highly skewed, leading to growing disparity.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">A third point is to ensure that the 'global enabling' effect of free market capitalism does not become the exclusive preserve of deregulated capital and the 'winners' who control it, leading to new forms of exploitation and disparity. The concern must be to find a way of directing the combined forces of 'capitalism without borders' and 'democracy within borders' in such a way that it leads to a genuinely better world in which the number of 'losers' is dropping and disparities are diminishing.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">A historic perspective</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">It is useful at this stage to take a look at the history of capitalism. Freemarket democracy delivered affluence to about a third of the global population over the last century mainly because of the 'accommodation' between labour and capital in an enabling environment created by 'Fordist' mass-production and consumption. A similar accommodation is now needed to enable global free market democracy to extend material wellbeing to the remaining two thirds of the (continually growing) world population, while at the same time sustaining it among the existing affluent third. It is no longer an accommodation between capitalists and workers that is required, however, but one between the affluent and the less affluent.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Fordism basically transformed the 'interdependent' stake of capital and labour in the economic pie, into a 'joint stake' - leading to the production of a larger pie. By analogy, what is needed today is to ensure that affluent and less affluent societies develop a joint stake in the production of a larger 'global pie' as a result of new technologies and more efficient, globalised modes of production. Attracting and sustaining capitalist investment in such modes will increasingly depend on demand and consumption structures which guarantee that poorer societies share with affluent ones the benefits of such global production systems. In the same way that a larger 'mess-produced pie' was dependent on higher and more   equitable mass consumption, so will a larger 'globally-produced pie' depend increasingly on higher and more equitable global consumption. In this context, the principal policy aim of development cooperation should be to ensure that growth resulting from globalisationis both enabling and disparity-reducing.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The disabling effect of</P>
+<P ALIGN="JUSTIFY">'poor' competition</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Driven by the powerful motive of capital accumulation, globalisation has the tendency to promote competition. In principle, this should be a good thing, but left unchanneled, it can have negative effects. One might draw an analogy between the conquering of the global market and the spread of water during a flood. The water always takes the easiest route, entering the most vulnerable areas first where it causes the most damage. Likewise, globalization, fueled by 'deregulated' capital, often tends to promote competition where it is easiest, but where it is not necessarily beneficial. This is the case, for example, in less affluent countries, where poverty is exploited to achieve what might be dubbed a 'poor' competitive advantage - in the sense that it is based on disparity, but also in that, far from 'enabling', it may actually have the opposite effect. Child labour, sex tourism, environmentally destructive tourism, tropical forms logging, the export of industrial pollution and misuse of intellectual property are all examples of 'disabling' competition resulting from global disparity. In a rapidly globalising world this is ultimately damaging to all concerned, which is why both affluent and less affluent nations have an interest in reducing the gap.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">All of this points to the need for a major redefinition of society's role in general and of aid in particular. During the colonial and Cold War periods, development cooperation was progressively uprooted and alienated from society. Serving an increasingly complex and non-transparent agenda, it became more and more a 'cockpit' affair, piloted by a small specialised crew - and it  found itself flying higher and higher above society. In short, affluent society lost touch with development cooperation and aid. Occasionally, the media intervened to 're-establish contact' but the result was that development aid usually only attracted mainstream public attention when things had gone terribly wrong.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Turning vision into action</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">If the aim is to have affluent and less affluent society working together to ensure that the latter adopts 'free market democracy'- and can adapt it in a way which benefits both - it is vital that the former be reconnected to the business of development cooperation. The affluent must be challenged to help transform their less affluent partners, in the interested and creative manner of a minority stakeholder. They must be ready to share the wealth of knowledge and experience generated in their own process of development. Representatives of all walks of affluent life should therefore be provided with greater opportunity for dialogue and cooperation with their less affluent counterparts. Increasingly easy and cheap communications and transport should facilitate this. This new form of stakeholdership will not happen, however, unless affluent society can be imbued with the new vision.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Donors should actively support the process. Instead of spending most of their time and resources determining the scope and content of development cooperation, they should step down from their cockpit. Their new role should be as brokers and facilitators of cooperation. An initial priority must be to extol the vision itself. As this gathers momentum, they should then turn to 'brokering' it in practice - acting as a catalyst between the affluent and less affluent in order to facilitate 'enabling' cooperation between them. The development of an effective brokerage profile and methodology will probably entail important changes in the way that donors work. They need to move much closer to their  constituency, and to be made democratically accountable again.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">As mentioned earlier, the concept of enabling cooperation concentrates on who does what, and how. Essentially, therefore, it should be seeking to mobilise democratic and free market forces in less affluent societies. The advantage of working this way is that change and progress will be determined primarily from within the society in question - with cooperation as a source of encouragement. Such an approach also entails acceptance of the fact that the pace of progrms must be left much more to the enabling forces of the maturing democracies and free markets, however weak and imperfect these may still appear. Indeed, the central purpose of cooperation should be to help these fore" become stronger. To achieve this, cooperation will need to move away from an emphasis on engineering outputs to one which involves 'messaging' the system and process. And it is not just methodologies that need to be altered; there must also be a radical change in cooperation mentality. Thus, for example, donors should attempt to broker cooperation which is 'small but smart'. Advancing 'best practice' might be another creative way to pursue cooperation which is enabling. And while some output-related decision techniques can still be used, these must be creatively reshaped to support a more 'enabling' approach.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">In conclusion, this enabling vision entails an awareness of the imperfections of free-market democracy, combined with a conviction that it offers enormous potential for the less affluent countries of the world. 'Recompromising' development aid for the future will mean reshaping it to support a process of adoption and adaptation of free market democracy in less affluent countries which is highly 'enabling'. The result should be a system of international solidarity which is working for free-market democracy, rather than as a substitute for it.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">J.J.</P>
+<P ALIGN="JUSTIFY"></P>
+<B><P>&lt;&lt;TOC3&gt;&gt; The effects of corruption on development</P>
+</B><P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY"> by Dieter Frisch</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Corruption - defined as 'the abuse of public power for personal ends' - has always existed. During recent decades, however, it has grown both in terms of geographic extent and intensity. Since the mid 1970s, it has infiltrated virtually every country in the world.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">It was hoped that the easing of political and economic restrictions that characterised the 1990s after the end of the Cold War would have gone some way to reducing this phenomenon. Through increased openness resulting from political pluralism and the freedom of the press, the process of democratisation should, under normal circumstances, mobilise efforts to overcome corruption. However, emergent democracies are still fragile and seem to find the task of tackling established self interests a formidable one.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">By reducing state intervention and therefore the opportunities for corruption, economic liberalisation should improve matters. In the short term, however, the opposite would appear to be true. Weakened state structures, a lack of appropriate legislation, powerlessness on the part of the judicial system to combat corruption, the pursuit of easy money - mistakenly perceived by some as being equivalent to a market economy - all these factors together contribute to aggravating the phenomenon, at least in the transitional stages. Such a state of affairs cannot fail to have some effect on those who are involved in and concerned by development issues.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Needless to say, corruption and its effects can be seen from a multitude of viewpoints. There is always the ethical angle - but how can we possibly presume to preach to countries of the South and East when bribery is just as rife in the North and when, as far as corruption within international economic relations is concerned, it is in fact, virtually by definition, the North who is the corrupter and the South and East who are the corrupted ? The only possible reply to such an argument - and one which is morally disputable even though economically valid - would be that the rich North can afford the luxury of wasting some of its wealth whereas in the case of developing countries, their sparse financial resources need to be used in the best way possible! Other lines of reasoning emphasise the distortions that corruption causes in the fair application of conditions of competition by penalising successful, yet honest, undertakings.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">A major obstacle in the path of development</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">In my opinion, corruption should be approached from the point of view of the effects it has on development. I say this because long professional experience has taught me that corruption is one of the major obstacles to progress, and that its effects on development are disastrous.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Some people would no doubt counter this assertion with the 'cultural' argument whereby they would have us believe that, in certain cultures, corruption is quite normal and morally acceptable. Well I do not know of a single place on earth where growing rich through taking bribes is considered lawful or morally acceptable! I should like to quote Olusegun Obansanjo,  former President of Nigeria, on the subject: 'In the African concept of appreciation and hospitality, a gift is a token. It is not demanded. The value is in the spirit of the giving, not the material worth. The gift is made in the open for all to see, never in secret. Where the gift is excessive, it becomes an embarrassment, and is returned. If anything, corruption has perverted the positive aspects of this age-old tradition'.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Then there are the cynics - including renowned professors - who claim that corruption oils the wheels of progress and enables development to take place. In this respect again, and putting all ethical aspects aside, it would be worthwhile distinguishing between the small baksheesh which 'helps' certain administrative procedures along ('acceleration fees') and large-scale corruption which perverts the course of de  velopment. This does not of course mean that we should underestimate the destructive effects that even small-scale corruption can have on society!</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Yet others have simply resigned themselves to the situation. For them, corruption is intrinsically linked to underdevelopment. As long as a person's normal income does not provide him with a decent living, the door will always be open to bribes. It is, therefore, through development that we should be attempting to eradicate corruption. Yet this argument is reminiscent of the debate on the population explosion. It is only through development, some say, that the problems of population growth will be resolved. But by then, the planet will be inexorably overpopulated! In my opinion, the same argument is just as valid as far as corruption is concerned. We simply cannot wait for it to be stamped out through development. (In any case, development is hardly a miracle cure: true, we have the examples of Singapore and Hong Kong where corruption is extremely uncommon, but we could also mention Italy, where it was precisely at the height of the country's development that corruption became the norm). We must act therefore, and without delay, focusing our efforts on eradicating large-scale corruption.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">If we analyse some of the effects that corruption has on development, the first thing we notice is that it increases the cost of goods and services, and not insignificantly either. Although a 5% reduction in the profit margin might, at a pinch, be absorbed by the supplier, corruption levels of 10% to 20%, which have become commonplace, will inevitably be reflected in the price and will, consequently, be paid for through the national or foreign (in the case of foreign aid) resources of a country. It is therefore the national economy that ultimately suffers the consequences of an unjustified surcharge on the goods or services, with the difference being pocketed by some government official or politician who has abused his power for his own personal gain. Given that such operations are generally financed by bank  loans or, in the case of foreign aid, by concessional loans, these surcharges inevitably bring about a proportionate increase in that country's debts. In fact it is now assumed that the exchange value of sums paid out in backhanders makes up a considerable proportion of the foreign debts of developing countries.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">However, the damaging effects of such practices do not stop there. The corrupt decision-maker may well be tempted to accept a substandard quality of service which will make his personal profit all the greater. Thus, with a road building project for example, complicity between government departments and contractors may result in corner-cutting with regard to agreed standards of quality so that the savings made may be shared out between the two parties.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">At their very worst, the disastrous effects of corruption mean that the conception of a project, and ultimately its very choice, are determined by corruption. As far as conception is concerned, a good example would be the purchase of a technology which is wholly unsuited to the particular needs of a country or the choice of a capital intensive project - more lucrative in terms of corruption - rather than a labour-intensive one which would nevertheless be far more beneficial to that nation's development.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The absolute peak of perversion, however, is when the very choice of priorities - and therefore of projects - is determined by corruption. What we are referring to here are those situations in which the real development priorities of a country are neglected in favour of operations which generate the greatest personal gain for the decision-makers. At this point I would like to quote R&eacute;mi Godeau, writing in Jeune Afrique: 'These currency-guzzling abortive projects have become a graveyard of white elephants. Africa is littered with vast deserted motorways which are being eroded by the Savannah, with fully functional but empty factories which have been left to fall into ruin only a few years after they were opened, with railway lines which are now impassable  through a lack of maintenance, and with hydroelectric dams abandoned because they cost too much to run'. Let us pick up on the point about empty factories. These 'follies of development' are to be found in many developing countries and in Africa in particular. Some have never produced, others have failed to reach full production capacity while others still face such prohibitive costs that big state subsidies are needed to keep them going. If we follow the thread right back to the beginning we find, more often than not, that factories have been sold without ensuring real competition between suppliers. Admittedly, such projects usually have only private-sector backing (they are rarely financed through official aid), but the funding is nonetheless backed by state-controlled bodies. The existence of corruption in such cases must be more than mere presumption - what other reason could there be for making decisions which run so counter to the interests of development ? In his work 'Grand Corruption in Third World Development', George Moody-Stuart identified those areas which are especially vulnerable to corruption. These are most notably, the procurement of military and other   technically sophisticated equipment, and large-scale works (in other words, any major, capital-intensive project and any scheme where objective valuation and comparison is hampered because of the technical sophistication involved).</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">It is worthwhile mentioning at this point that a country which borrows money to finance projects that do not satisfy its real needs, and which may indeed be considered economically futile or absurd, will see its debt burden increase - and not simply by the 10% to 20% that is used to fund 'backhanders'. The loss will ultimately be 100% if one views it in terms of the cost of the unproductive investment to the national economy. Discussions about the debts of developing countries rarely focus on the mechanisms which have produced these debts. Yet in most cases, they have become unserviceable on account of the ineffective use of overseas aid - the sort of bad management to which corruption contributes considerably.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">What is more, by deflecting the sparse resources which do exist towards non-priority or low-priority areas, corruption contributes to a large extent to ensuring that fundamental needs such as food, health and education, are not met. It is therefore one of the causes of under development and of poverty in general. Needless to say, official aid is often called upon to make good the deficit left by the irresponsible management of otherwise available resources. Is it any surprise if, in the long run, public opinion in the countries of the North begins to grow weary of bridging gaps which efficient management of resources should never have allowed to appear in the first place ? How are we to convince European taxpayers that it is they who need to provide the money to fund bush clinics in countries which put their funds in prestige projects, if not directly into Swiss bank accounts?</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">A vicious circle that must be broken</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Effectively, we find ourselves in a 'catch-22'situation. Corruption is one of the causes of under development and poverty, yet poverty is in part responsible for its continuation. If a person cannot earn an honest living for himself and his family, then he is more or less forced into earning it by less honest means. Hence corruption is both the cause and the consequence of under development. In order to break the pattern we must therefore combat large-scale corruption inasmuch as it is a significant cause of underdevelopment and we must work gradually to eradicate the reasons for its propagation in society, and in particular to remedy the notorious lack of adequate income to ensure a decent standard of living.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">In general terms, we can say that corruption also kills off the spirit of development. Nothing is more destructive to a society than the pursuit of 'a fast and easy buck' which makes honest people who work hard appear naive or foolish. That is why, in the context of economic reforms under the heading of 'structural adjustment', it is vital that the model advocated be one of a market economy based on a sound framework of legislation and on an efficient state. It should not allow free rein to the sort of ruthless capitalism which is aimed at immediate profit at all costs. The example of certain transition countries in the East, where a market economy has become synonymous with the law of the jungle, the Mafia and corruption, really should make us stop and think.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">In the final analysis, an economy undermined by corruption has the effect of discouraging potential foreign investors and public donors. Yet if development is to succeed, countries have to be able to attract a flow of capital. As Serge Michailof put it: 'Success attracts money. Waste, failure and chaos drive it away'. And although investors are very keen to do business, with the exception of a few opportunists, they all look for host countries that have a stable and predictable climate. Entrepreneurs have been known to withdraw from certain African countries - which are nevertheless rich in resources - because of the constraints imposed on them by corruption on a scale which they considered to be unacceptable. As for public donors, they are increasingly reluctant to offer financial aid to those countries that manage their own resources poorly. It is precisely this failing which is one of the causes of what we now refer to as 'aid fatigue'. Financial aid institutions should go as far as suspending their cooperation in blatant cases of corruption and bad management, just as they do in cases of serious violation of human rights. Conversely, 'good governance' should be the determining factor when allocating aid, and it would appear that Article 5 of the revised Lom&eacute; IV Convention does in fact foresee such an approach.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">In conclusion, far from reserving the foregoing criticisms for countries of the South, I believe that the partners of the North have their part to play in the ravages wrought by corruption, be it only as a result of the inconsistencies between their development cooperation policies and their export promotion policies. Basing our assumptions on the principle that cooperation efforts are genuinely motivated by concerns for development - and I can attest that this is precisely the motivation behind the policies of the European Union, which I have served for a great many years - we should not forget that Western countries have a tendency to promote exports, by other means, without any consideration for the effects this has in terms of development. They thus contribute to the dishonest practices which we have been discussing. The fact that they tolerate, or even go as far as to encourage corruption as a means of promoting exports - restricting the application of the criminal law to acts committed on their own territory and allowing corruption to be taxdeductible under the heading of 'necessary expenses' - seems to me to be absolutely scandalous. In the AlortR too, the battle against the canker of international corruption is a formidable one. But it is a fight to which we are committed in the context of 'Transparency International' This NGO, which was created in 1993, makes its services available to any country which genuinely wishes to eradicate the scourge of corruption. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY"> D.F. </P>
+<P ALIGN="JUSTIFY"></P>
+<B><P ALIGN="CENTER">&lt;&lt;TOC2&gt;&gt; Close-up</P>
+</B><P ALIGN="JUSTIFY"></P>
+<B><P>&lt;&lt;TOC3&gt;&gt; National park  restoration in Chad: luxury or necessity ?  </P>
+</B><P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">by Phllippe Dejace</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Terms like 'democracy' and 'sustainable development' are increasingly used to keep donors happy, and to present new development projects in the most favourable possible light. With this in mind, it is interesting to look at an example from 'the field' to see how genuine the commitment actually is. Adherence to these concepts has undoubtedly made a positive contribution to environmental protection, but there is also a negative side</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Since 1989, the Zakouma National Park in south-east Chad has been undergoing restoration in a   programme supported by the KU. Devastated by a decade of conflict, this wildlife sanctuary of nearly 3000 square kiLom&eacute;tres was little more than a huge graveyard in 1986 when Pierre Pfeffer of the Paris Natural History Museum visited it and decided to campaign for its restoration. Today, this is recognised to have been a sensible decision. It is acknowledged that wildlife are better off when they have a reasonably large area in which to live, away from human activity. Aerial counts made in 1986, 1991 and 1995 confirm that animal numbers are on the increase in the park and that irreversible destruction has been averted. Currently, Zakouma is the only area effectively being protected in Chad. The other designated sites (one park and seven reservations) remain impoverished and in a state of near devastation.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Recognising the challenge</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">One should not be lulled into complacency. Even when a process involving local village communities is initiated, the low standard of living of the inhabitants, their educational level, and the progressive deterioration of vegetation around protected areas in  variably make the latter a tempting 'target'. In these circumstances, it is very hard to preserve their integrity. At Zakouma, a busy time lies ahead. The local people must be educated and informed as quickly as possible. This presents us with the first hurdle given the inadequacy of the education sector. The Ministry of Education is underfunded and with growing numbers of pupils in the system, it is virtually impossible to plan special programmes aimed at increasing awareness of this particular problem.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">There are other reasons why there should be short-term investment in this sector. There are good arguments for preserving a few control sites while the awareness programme is under way, since these will one day serve to illustrate what can be achieved. It is also much less difficult to preserve an area than to try to reconstitute it, once desertification has set in. The site is part of the national heritage whose value can only increase. Moreover, in most cases, the protected areas ensure the survival of fish stocks in lakes and rivers downstream and act as a reservoir for game: many of the animals which breed there provide food for the people living at the zone's edges. Even frequent wholesale slaughter of wildlife, as happens during a war, is reversible if the vegetation remains intact.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Although the park is cut off from human activity (the area is flooded and therefore closed, to all intents and purpose, for four months of the year), it has an uncertain future. It faces pressure  from itinerant herdsmen and poachers, the latter tracking giraffe right up to the outskirts of Zakouma village, which is in the middle of the park. Although located in a wildlife reserve of 20 000 km2 - which is supposed to be a buffer zone - the park is not truly protected because human activity inside the reserve is not controlled. In the dry season, the park teems with wildlife. A clear density gradient has been identified with the animal population dropping as you move from the centre to the periphery. Indeed, only about a third of the 3000 km2 is intensively exploited by the wildlife which lives there - and even this area is relatively insecure.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Enclosure would give those who are keen to defend the park a grace period in which to set up long-term awareness strategies. Ironically, one danger results from the striking democratisation that has taken place in Chad. To win votes, some politicians have called for the bans applying to the park to be lifted. This approach has the potential to succeed because, owing to shortfalls in the education system, the electorate is insufficiently mature in political terms. Another factor is that traditional leaders, seeing their power progressively diminish, are inclined to 'revolt'. Thus, they may fail to intervene when stockmen deliberately invade the park, encouraged by demagogues in search of votes. When the grasslands are invaded by cattle, few wild animals can compete and they are forced to retreat to the central area of the park. Against this background of a need for urgent action, the Zakouma Park team is concentrating its awareness-raising efforts on traditional leaders and the administrative authorities - rather than on teaching schoolchildren about environmental protection (although such a campaign is also envisaged).</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Participation ?</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Some argue that setting up a 'sustainable and participation-based development' strategy would make it possible to avoid the situation that now exists in Zakouma. The idea behind such a strategy - which clearly has its   attractions - is that man is perfectly capable of managing his native territory. All that is needed is for him to be granted land and to receive support for his initiatives. Many who espouse this approach continue to despatch teams to demonstrate that this is the ideal response. Unfortunately, in the particularly complicated case of managing the environment on the fringes of a national park, the local people are usually reluctant to make the investment. The more normal inclination is to reap a short-term profit from resources that are within reach. The inhabitants are also tired of the lectures they get from specialists who visit for just a few hours. The scope of the problem is such that expertise needs to be available on an ongoing basis. Considerable resources are also needed to ensure.that the effort is sustained.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">It is not easy to halt environmental destruction in a market economy which has overturned traditional values and gives priority to increasing personal wealth and consumption. A natural environment's potential for exploitation is always limited. Yet stock-rearing involves the use of animals 'selected' over thousands of years to take maximum advantage of the least scrap of vegetation. By contrast, a wild animal is much more selective and never ruins the environment it exploits. It may even be able to adapt its reproductive cycle to the available food resources! We are nowhere near this situation in domestic stockbreeding!</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">This is where 'sustainable development', which sounds highly reassuring, appears at odds with reality. Beyond a certain threshold, one cannot avoid depleting the resource. If one is to adopt an approach that involves the population actively, one must acknowledge that their response may fall short of what is needed. Indeed, they may do things which provoke migration, and are thus damaging. Thus, for example, the opening-up of a water source may attract more nomadic herdsman, thereby undermining rather than enhancing the surrounding area.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Awareness programme</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The single most significant step towards protecting the park would be to ease population pressure, but progress in this area is very limited. We can only wait for the birthrate to decrease; something which invariably happens as a country develops. But what will become of the national parks in the meantime ? In Zakouma, an eco-development team is currently listening to the villagers' claims. As elsewhere, an attempt is being made to gain time. Unfortunately, the current climate of transparency in Chad, which is one of the positive aspects of democratisation and should be a major asset, has not had much impact in this area. The awareness programme suffers from a serious lack of trained workers and when meetings are held, they usually turn into interminable discussions, simply increasing the level of frustration. On the other hand, a convincing discussion-leader can advance matters considerably and discussion is surely the right approach to adopt. Furthermore, the process must lead to concrete results. Otherwise, decisions taken may end up being postponed indefinitely because they conflict with the interests of political decision-makers.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Despite the difficulties, the Zakouma team is placing heavy reliance on this desire for transparency. Although the project's initial aims have essentially been to restore infrastructures and thereby promote an increase in wildlife, the addition of an ecodevelopment aspect and ecological monitoring has made it possible to create an important 'reservoir' of knowledge. A computerized map of the vegetation has been produced with the help of a microlight equipped with a GPS (satellite positioning) system. There have also been aerial inventories tracking the seasonal density and distribution of wildlife, as well as in-depth sociological surveys in the villages most hostile to the park's existence. This major database makes it possible to organise meetings, conferences and discussions to demonstrate that the park's contribution is greater than it seems. One big frustration for local people living on the  park's fringes concerns the redistribution of the income it generates. Looking first at tourism, Chad hardly qualifies as a major holiday destination and those who do visit the park are too few to make a significant contribution (the income raised barely covers the cost of replacing their bedlinen !)</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">One interesting conclusion has been drawn from studies of the animal distribution in the different seasons. It appears that when pressure from nomadic herdsman is at its strongest, during the dry season, the wildlife take refuge in the park and numbers multiply in safety. When the stockmen return northward, the wild animals then go beyond the park boundaries where they are hunted and eaten by villagers. This is surely a form of income redistribution! Moreover, many young fish in the park's only river (the bahr Salamat), take advantage of the flooding of the area during the rains. This releases huge volumes of nutrients back into the ecosystem. In the park, the fish are safe from the fishermen who work downstream and they can swim back to their spawning grounds. This guarantees the renewal of stocks depleted during the dry season. The level of fish stocks in Lake Iro - and probably in the River Chari as well - is thus linked to the existence of the Zakouma Park! When this version of income redistribution is explained, it often helps to convince traditional leaders who then use their influence to limit incursions by stockmen or poachers. However, a lot remains to be done because demographic pressure and standards of living both make it more difficult to get the message across.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">We know that excessive human activity always results in environmental deterioration. Zakouma, although under pressure, has been 'spared' to some extent, and as such, it represents an important resource. But some see it as a luxury and it faces a suspended death sentence. If people stop regarding its conservation as something that is necessary, the sentence will end up being carried out. In my opinion, the most reliable way of guaranteeing its preservation would be to enclose it completely.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">P.H.D. </P>
+<P ALIGN="JUSTIFY"></P>
+<B><P ALIGN="CENTER">&lt;&lt;TOC2&gt;&gt; Developing World</P>
+</B><P ALIGN="JUSTIFY"></P>
+<B><P>&lt;&lt;TOC3&gt;&gt; European NGOs look ahead at annual meeting in Brussels </P>
+</B><P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY"> by Agostino Ambrogetti</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The 22nd annual General Assembly of European Development Non-Governmental Organisations (NGOs), and a thematic conference entitled 'A Europe open to the world', were held in Brussels from 18 - 20 April. Representatives of more than 800 NGOs attended, with the Assembly adopting 14 resolutions as well as issuing specific appeals on the European Union's Intergovernmental Conference (IGC) and on Lebanon. The Assembly renewed its approval of the development NGOs' 'Strategic Priorities', adopted the Work Plan for the 1996-98 period, and looked at the overall impact of the Lom&eacute; Convention with an eye to likely future developments. The subsequent Conference focused, among other things, on the issue of coherence between the EU's development cooperation and its other policies (notably trade and agriculture). </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">A general impression that emerged from the two events was that the NGO movement was attaching increasing importance to its role as advocate for the developing countries. A fundamental aspect of this is the ongoing dialogue that NGOs have with the European institutions, and the lobbying they carry out on policy issues. Commission representatives who spoke at the Assembly indicated their understanding and appreciation of this. For example, Development Commissioner, Jao de Deus Pinheiro, referred warmly to 'the very active role played by the NGO community in the debate on the mid-term revision of the Lom&eacute; Convention,' and acknowledged that the NGOs had mounted an 'important political lobby' in favour of increased funding for the next five-year period.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The Commissioner was keen to emphasise the complementarily that existed between the European Commission and the NGO movement in support of emerging societies in the South. He also urged his audience to continue in their task of challenging the general apathy towards development cooperation. This, he said, entailed appealing directly to public opinion in order to influence political leaders.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">A similar tone was adopted by Bernard Ryelandt, who heads the unit responsible for cofinancing NGO projects in the Commission's development directorate-general (DG VIII) He spoke of the 'decisive' action of European NGOs in balancing other lobbies such as the agricultural one. This, he believed, had the effect of improving the coherence of EU policies.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Delegates from a number of countries set out their views on the advocacy issue, and what they saw as the growing NGO role in this area. Andy Rutherford from the United Kingdom said that he saw increased lobbying as necessary, complementing the work carried out in the field through development projects. He pointed out that Southern NGOs had themselves requested their Northern partners to pressurise European governments in the hope that the latter would adopt external policies more favourable to the developing world. Mr Rutherford also raised the thorny question of structural adjustment. The view that adjustment policies were not succeeding in eradicating poverty, had, he said, been acknowledged by the EU's Development Council in its resolution adopted in June 1995. With this in mind, the NGOs would be raising the issue with the World Bank and the IMF - where the EU Member States are among the most substantial contributors.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Guido Barbera, who headed the Italian delegation to the Assembly, took up this point, calling for more pressure to be exerted on the Bretton Woods institutions by European NGOs and indeed, by the European Commission itself. This was necessary, he believed, to promote coherent macroeconomic policies favouring the development of economic relationships with the less-developed countries. In more general terms, Mr Barbera applauded the growing NGO participation in the political arena, stating that this was both 'positive' and fundamental'. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Evaluation of the Liaison</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Committee's work</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">A document was presented to the Conference by the NGDO-EU Liaison Committee containing an evaluation of its activities. The aim, in drawing up the document, was to 'review and critically assess the work and organization of the Committee, and evaluate whether it meets the expectations of its stake holders.' In order to do this, NGO members were consulted through questionnaires.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The evaluation revealed that support for the Liaison Committee as the representative umbrella organization of European NGOs remains strong, although there is widespread uncertainty about the future. This is reflected in the perception that the Committee has   gradually been losing momentum. There were also some doubts expressed about its representativeness. Large NGOs, it was noted, were able to spread their efforts across different networks. The fact that small NGOs tended not to be involved in the Committee emerged as one of the critical issues for discussion.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Attention was also focused on the alleged weakness of many national platforms (the documents containing proposals drawn up by the various national NGO assemblies) in representing the aspirations of their member organizations. This issue, and the question of voting on resolutions without debating the documents in question gave rise to controversy. Some delegates boycotted the vote while others submitted a written protest and there is clearly some demand for reforms designed to make the Assembly's procedures more democratic.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">General conditions of cm  financing</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Another highly topical subject on the Assembly's agenda was the proposed revision of the General Conditions for the Co-financing of NGO </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Projects in Developing Countries. Commission speakers who touched on this subject included Professor Pinheiro and Jacob Houtman who is a Director in DG VIII Both referred to the revision process that was currently under way, and emphasised the higher priority that would be attached to capacity building for Southern NGOs. This involves providing support to strengthen the organisational structure of the bodies in question, and to improve the skills of their staff in managing and implementing projects. Such an approach is now recognised as essential for the long-term sustainability of NGO activities. As Mr Houtman was keen to stress, the principles underpinning the KU-NGO relationship (recognition of NGO independence and specificity, freedom of initiative for European NGOs in cooperation with their Southern partners) would be safeguarded in the revised conditions. Other priorities to be set out in the conditions would include the promotion </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Notice at the site of a non governmental organisation in</P>
+<P ALIGN="JUSTIFY">Zimbabwe devoted to improving agricultural productivity</P>
+<P ALIGN="JUSTIFY">'Crucial to provide more institutional support for Southem</P>
+<P ALIGN="JUSTIFY">NGOs' of democracy and human rights through reinforced structures of civil society, and a greater emphasis on the fight against poverty, income-generating activities and social development programmes. With these objectives in mind, it was all the more crucial to provide more institutional support for Southern NGOs. They, unlike their Northern partners, had a permanent presence in society in the developing countries.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The revised general conditions would also reflect the new orientation which favours a long-term programme approach over the traditional project by-project method. This should lead to a reduced administrative burden, and benefit long-standing NGO partners who have demonstrated viable approaches in working with their Southern counterparts, as well as good management and accountability.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">'A Europe open to the world'</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The Conference which took place following the NGO General Assembly focused on assessing the coherence of different EU policies and on ways of achieving coherence where it might be lacking. As the title of the Conference suggests, the question which was never far from participants' minds was 'what sort of Europe is being created.' Is it a Europe which stands in solidarity with the South (and East), or is it one which retreats into its fortress, concerned only with its own prosperity ?</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">At the outset, EU policy - or rather its mode of implementation - came in for criticism. It was claimed, on the bask of the experience of both European and Southern NGOs, that the principles of development cooperation set out in the Maastricht Treaty (Title XVII) were not being applied universally and consistently. These principles include the sustainable economic and social development of developing countries, their integration into the world economy, the fight against poverty, and the development and consolidation of democracy, human rights and the rule of law.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">In this connection, three specific discussion topics were selected: the EU's common foreign and security policy (CFSP), its common commercial and agriculture policies (CCP and CAP) and its immigration and asylum policy.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Regarding the first of these, it was suggested that the EU's definition of 'security' tended to be viewed solely in terms of common defence, and that the concept of 'human security' drawn up by the UNDP had been neglected. The latter seeks to define the concept on a broader basis including aspects such as equitable and sustainable development, as well as human rights and democracy. The view was also expressed that a more firm and coordinated CFSP was needed.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">On the second topic - trade and agriculture - there was a strong feeling that the policies of the EU (and the USA) were heavily weighted in favour of 'home' producers and that this had the effect of undermining local production and food security in the</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Developing countries. The Union was urged to remove the policy 'contradictions' that allowed this situation to arise bearing in mind the specificity and sensitivity of the food trade.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Finally, several speakers were highly critical of what they viewed as negative trends in the approach to immigration and asylum adopted by the EU and its Member States, with increasingly strict rules being implemented. There were also calls for measures designed to integrate resident migrants into society.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Indeed, integration may well be seen as the key message to have emerged from the NGOs' gathering. The call was for the people and governments of the European Union, acting in the Intergovernmental Conference (IGC), to integrate the needs of the rest of the world's people into their actions and programmes. The talk was of common values of human rights and solidarity, in both internal and external polices. And it was clear from the commitment of those who attended that the NGOs are determined to maintain and strengthen their role - as active partners in the development of the South, as advocates for the developing countries and perhaps indeed as keepers of the European conscience.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">A.A.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Workshops</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">As part of the proceedings of the NGO General Assembly, three workshops were organised dealing with specific themes.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Workshop 1 was entitled Beyond Lom&eacute; IV. There was a general consensus among those taking part that the Convention's underlying philosophy helped to protect developing countries in today's global commercial environment. Without the Lom&eacute; system, it was felt that the ACP countries would have suffered even more from the deterioration in their terms of trade. With this in mind, the World Trade Organisation came in for criticism for its stance against regional preferential agreements (even if this does not apply to the least developed countries).</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The major finding of Workshop 2, which dealt with Poverty in the North and the South, was that  poverty is the result of interactions at a global level - and is not 'nation specific'. It was therefore important to adopt a global approach in  seeking to tackle the causes of poverty, and to develop further North-South exchanges of experience for the benefit of both sides.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The third workshop was devoted to making the most of EU Presidencies. Here, the aim was to evaluate past experience of lobbying undertaken by the NGO community in those countries holding the EC Council Presidency, during the six-month period in question. The main recommendation to emerge was that more needed to be done in establishing contacts and exchanging information between the relevant national NGO communities. Such exchanges, it was felt, were needed before, during and after the six month Presidency period, in order to facilitate continuity of lobbying on key themes. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Resolutions </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">In the Resolutions adopted by the NGO General Assembly, considerable emphasis was placed on human rights</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY"> issues, with texts being agreed on Nigeria, the peoples of the Western</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Sahara and the child sex 'industry'.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Trade (in the widest sense of the word) also featured prominently. In addition to a general resolution on world trade, representatives passed motions on the arms trade, traffic in landmines and the production of the drug coca.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Also adopted were resolutions on preventive diplomacy, cooperation with Cuba, the Euro-Mediterranean partnership and the 'deterioration' of the situation in the Great Lakes region of Africa. </P>
+<P ALIGN="JUSTIFY"></P>
+<B><P>&lt;&lt;TOC3&gt;&gt; Africans seek bigger share of tourist dollar  </P>
+</B><P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">by Godfrey Karoro</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Zimbabwe's government is under pressure to encourage greater African involvement in the predominantly white-run tourism industry, which is facing intense competition from neighbouring South Africa. 'Black participation in all sectors of tourism is a priority,' says Environment and Tourism Minister Chen Chimutengwende. 'Blacks have waited in the wings long enough,' he adds, 'and their entry on to centre stage is inevitable. The solution lies in nurturing black entrepreneurship and giving it the material and technical backup to ensure its growth.'</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Only 38 of the country's 436 tour operators are indigenous, and most focus on provision of goods and services, particularly transport. African interest in the business was kindled last year when the government identified tourism as one of the sectors which could benefit from an international $74 million credit facility. This prompted enquiries from  about 500 potential entrepreneurs. Interest was heightened during the election campaign earlier this year, when President Mugabe's government made an issue of the continuing economic domination of the white community which constitutes  less than 1% of the country's 11 million population.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Mr Chimutengwende pledged support for greater black participation, but the government itself is under fire for not doing enough. 'We have a time-bomb and the government should do something about it quickly before it explodes,' says Colin Blythe-Wood, managing director of a tour company and chairman of the Zimbabwe Association of Tour and Safari Operators (ZATSO), referring to the black-white imbalance in the whole economy. 'We are indeed fortunate that this industry, which has perhaps the greatest potential in our economy, is still in its infancy,' he says. He argues that the government holds the trump card, through its ownership of vast tracts of land in national parks, forests and communal areas.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">A 1994 Zatso report identified more than 100 sites on state-owned land suitable for development by African tourism ventures. At least half, says Mr Blythe-Wood, were in areas of abundant wildlife, including the 'big five' - elephant, lion, rhinoceros, hippopotamus and buffalo. Other opportunities could be provided he suggests, if the National Park service got out of the accommodation business and concentrated on flora and fauna conservation. 'The government cannot be a referee and a player at the same time. It should sell off its shares in the Rainbow Tourism Group' - a wholly-owned government company which is the third largest operator in the tourism sector.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">One of the industry's problems is that South Africa, too, has found tourism to be an unexpectedly good economic performer. Arrivals there rose by 50% in 1995, and a new government discussion document suggests that tourism could double its foreign exchange earnings by the year 2000 and triple its contribution to national income. South Africa's parks and beaches are well developed, but entrepreneurs are also fostering attractions such as Boer War battle sites and 'Road to Freedom' tours in which visitors have breakfast with former freedom fighters.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The fear is that South Africa will be the regional hub for visitors, siphonino off  most of the earnings, with</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Zimbabwe merely getting the overspill from short side-trips.</P>
+<P ALIGN="JUSTIFY">Zatso chief executive, Elias Nyakuni, points out that South</P>
+<P ALIGN="JUSTIFY">Africa is already using Zimbabwe's top attraction to lure visitors, urging them 'to come to South Africa to see the</P>
+<P ALIGN="JUSTIFY">Victoria Falls'! Efficient train, luxury bus and air services connect several South African cities to the Falls, which are on the Zimbabwe-Zambia border. Mr Nyakuni says that Zimbabwe  could also lose out if things go wrong in their southern neighbour. 'Violence in South Africa could deter people from coming to Zimbabwe.' He accuses the government of not taking marketing in Europe and North America sufficiently seriously. 'The 4-5% annual growth is, in essence, through word of mouth. We need to investt more in marketing.' He says that the Zimbabwe Council for Tourism is underfunded and that it operates 'without brochures or pamphlets.' Neverthelms,  with 1.25 million visitors last year spending $252m (up from 1.04m spending $203m in 1994) - tourism is a growth area in which black people could take a bigger share - and not just, as at present, as guides, drivers, mechanics and cooks.</P>
+<P ALIGN="JUSTIFY">Lovemore Chihota, who runs a booming Victoria Falls safari business, has shown the way. He admits that there is a lot of money to be made from tourism, but warns that careful preparation is needed, as well as determination, commitment and, a realisation that there are no quick returns. He also points to the need to have some equity. 'The promoter,' he stresses, 'must put his money where his mouth is.'</P>
+<P ALIGN="JUSTIFY"> G.K.</P>
+<P ALIGN="JUSTIFY"> </P>
+<B><P ALIGN="CENTER">&lt;&lt;TOC2&gt;&gt;  Culture and society</P>
+</B><P ALIGN="JUSTIFY"></P>
+<B><P>&lt;&lt;TOC3&gt;&gt; Dak'Art 96</P>
+</B><P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">One of the most important exhibitions of African art, the Biennial Festival of Conternporary African Art, opened its doors to the public in Dakar, Senegal, on 8 May 1996. The 'Pan-African Art Exhibition', as it is still called, was being staged for the third time although it almost failed to take place at all, having been postponed several times over the last four years. All those who participated - from the artists who exhibited to the directors of art galleries and cultural  institions - were pleasantly surprised. The next edition of me Courier will include a more comprehensive account of the exhibition.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">President Abdou Diouf of Senegal inaugurated the event at the Daniel Sorano National Theatre in the company of a number of VlPs, including BartoLom&eacute; Amat Armengol who represented the European Commission. The Commission was Dak'Art 96's main financial partner providing support to the tune of CFAF 200 million (ECU 300 000 approx). The Biennial Festival aims to be a showcase for African artists allowing them to break into the international plastic arts market. Hitherto, this has remained relatively closed to them despite the general recognition that Africa has a contribution to make to the art world in this area. Mr Ousmane Sow Huchard, chairman of the Festival's scientific board, stressed that success lay first in stimulating the art market in Africa itself. He gave the example of his own country which had voted the so-called '1 % law', which stipulated the proportion of works of art that should be used to decorate all new public buildings.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The Festival's main exhibition, at the Ifan Museum of African Arts, was devoted to major trends in African sculpture. 42 artists selected by an international panel took part and, despite some criticism, their choice was a  judicious one. The same cannot be said, unfortunately, of the second major exhibition, at the National Art Gallery. This was devoted to contemporary Senegalese art and the skill involved in producing the exhibits was not of a consistently high standard.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">There were also five individual exhibitions featuring artists chosen by internationally famous judges. These might be expected to have a dynamic effect in setting standards on the market. Zeribun Yempeta of Ethiopia offered a quite original style, working on a support of leather straps fastened to a trellis of fine strips of wood. He draws his inspiration from a combination of African design, Coptic and Greek influences, and ancient Egyptian art. Ethiopian painting was one of the major revelations of the 'Africa 95' exhibition in London last year and the Festival gave a further opportunity for such art to be displayed. Another display presented work by the Moroccan painter, Mohamed Kacimi, whose pictures have been hung in various exhibitions - although the term 'pictures' is not always appropriate to this artist's work. It is perhaps more fitting to say that he 'occupies space'. In Dakar, he covered three walls of a large room with 'rolling art'. His skill, particularly in monumental works, is to offer excitement and calm simultaneously, through the use of animated forms and soft, rhythmic harmonies. Ezrom Legae of South Africa, Moustapha Dime of Senegal and Pascale Martine Tayou of Cameroon were the three other artists granted individual exhibitions.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">One of the trends which came to the fore at Dak'Art was the use of alternative media and recycled material. The latter, in a sense, is the man in the street's legacy to art. Initially, recycling was used predominantly in the informal sector to produce utilitarian objects. The 'Biennial Festival Village' was set aside for informal sculptors, and in an open area beside the Village, both inside a marquee and outdoors, one of the most individually striking exhibitions was presented. This combined a variety of artistic forms ranging from painting to video, not to mention Adeagbo's unusual montages, including 'African artists and AIDS'. This had already been exhibited in a number of countries and was staged by the Revue Noire team in parallel with its 'AIDS' issue.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The Festival included dozens of on-site exhibitions as well as all the 'fringe' presentations. The AIDS exhibition was one of the boldest but the display entitled 'Love' offered the greatest degree of unity and uniformity of design. Dak'Art 96 also made an attempt to integrate other forms of creativity such as dance, design and fashion. The latter two, for example, were presented at the Espace Vema, a fine metal structure where the creations of the Senegalese designer Claire Kane were in perfect harmony with the highly original furnishings. The European Union's prize for creativity, one of the Festival's four major prizes, was awarded to Vincent Namien, a designer from Cote d'lvoire.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Hege'Goueier</P>
+<P ALIGN="JUSTIFY"></P>
+<B><P>&lt;&lt;TOC3&gt;&gt; On creativity... in Africa and elsewhere </P>
+</B><P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY"> by Alain Nicolas</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The author of this article is head curator and director of the Museum of African, Oceanic and Amerindian Arts in Marseilles. Here he offers his thoughts on the (partially unconscious) reluctance of the 'official' art world in the West - museums, critics and art historians - to accept contemporary African artists. Even now, they tend to be relegated to the sphere of 'alternative' art. However, he believes that the abundance of creative Africans, and the pressure they are exerting on the art world and market will, sooner or later, generate a 'new revolution' in the museums. This iswhat happened in the early20th century when traditional African art first arrived in the West. This article is linked to the dossier on African creativity published in our previous issue.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">When I was asked to make this small contribution on African creativity, I was happy to oblige since, as a non-specialist, I am able to content myself with a few generalisations. I believe that there are still barriers, sometime not very visible, but nonetheless real, which have to be broken down.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Unfortunately, writing just a few lines on creativity is a difficult exercise given the amount of literature on the subject and so many divergent opinions. So, what line should I adopt? About 15 years ago - in the wake of hordes of specialists in the humanities from sociology, psychology, ethnology, anthropology and so on - a rational approach, known as 'the anthropology of art', was at last proposed. The term 'rational' should be seen here in the context of the distinction between exact or 'hard' sciences such as mathematics, physics and astronomy, and the humanities, which are essentially inexact or 'soft' disciplines. And in brief, the West tends to take a scientific approach, relying on empirical evidence, even when it seeks to study such subjects as human creativity.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Creativity obviously is to be found in many different spheres. It is needed in technology, it is fundamental to story-telling, it underpins all forms of social organisation and has a part to play in religion. Similarly, what we term 'art'  is one of the spheres of creative endeavour. The anthropology of art seeks to document artistic creativity and to analyse the conditions surrounding its expression in various cultures. This is a laudable enterprise insofar as art is regarded as another means of expression, used in one form or another by all human groups.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The creative function is universal</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The basic postulate is that any society - and any individual - possesses creative potential which may be expressed in any way. The first thing to examine, therefore, is the context of choice. There are various modes of artistic expression ranging from music, poetry, prose and dance to architecture, painting and fashion. Some individuals or societies may have no choice, perhaps because of socio-economic constraints. Others may favour a particular mode of expression while nonetheless dabbling in more than one area. The expression of creativity is, therefore, like an identifying mark, claimed by the group or by the individual. The concept of 'style' now comes into play. The expression of one group is different from that of another and no two can ever be the same. Fundamental elements are at work in this materialisation of creativity. Some  are due to the natural environment. Thus, for example, a society located in a place where wood is abundant may favour sculpture. Others come from the group or individual themselves. And in the final analysis, it is the groups or individuals that decide what to portray (or not) on the basis of their own social norms and what they want to express.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">These few limited thoughts should be supplemented by the observation that sculpture or the plastic arts more generally can also be examined from at least two angles: as a means of conveying information, and as a form of linguistic expression.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">As regards the former, some have proposed analysing any work of art, from whatever culture, as a message. Analysis of the work therefore includes an examination of the conditions surrounding the production and transmission of the message. What message is broadcast ? How does it function ? What does the addressee gain from it? This approach is fine in hypothetical terms but does not allow one to go beyond theoretical and formal data, teaching us nothing about the content of the message under study. It refers back to the originator who holds the keys to the way in which it was sent and thus to its form and meaning.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Linguistically speaking, we assume that all expression through sculpture is a language and that the techniques for studying language can therefore be applied to the work of art. This approach is more rewarding because it brings us closer both to the sources and to the function of communication.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Be that as it may, all methods involve knowledge of the group or of the individual (but also of the relationships between them) and thus of any organised knowledge. Art cannot be separated from perception. This is the position of the majority of scientists. Yet we are not completely certain of this. Briefly, we are led to imagine that art could be irreducible at a certain level. When we look at a sculpture or listen to a piece of music, aside from the emotional content which is at least   partly quantifiable, what are we able to understand about the culture which produced them ?</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Having travelled widely throughout the world and kept my eyes open, without having become the 'observer-participant' which the ethnologist should be, I am certain that the same creative function can be seen everywhere, and it is not difficult to identify.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Frequent visits to the world's museums and, perhaps above all, to their vaults, further reinforces the impression that constants do exist and are worthy of more and better investigation. Art, and more particularly the art of others, from other continents, is still the domain of a happy few.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">They are usually highly literate people, and are seldom activists expounding a cause.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Contemporary African art must find its niche</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The above statements relate as much to contemporary art as to what we term 'traditional' art. How many of the world's museums really show contemporary art from Africa ? It is as if this sector were cut off from current cultural reality. This is despite the fact that each week, new artists, musicians, designers, painters, sculptors, dancers, film-makers, stylists and photographers emerge from Africa, to be 'recognised' in the West (if anyone knows what 'recognition' really means!). The museums are, in fact, confused by this burgeoning of talent because they have no idea how to manage it.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">It has been said that contemporary African art is an urban phenomenon aimed at those living in towns and cities - and that it rebels against essentially rural, traditional art.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The argument is that the usual methods for analysing traditional art cannot be fully mobilised because 'urban civilisation' conforms to a set of universal norms (more or less), which are distinct from those studied by ethnologists. It would, therefore, be more appropriate to consider contemporary art in the context of sociology and aesthetics. This may be true, but it still comes down to a matter of observation. Confusion reigns.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">When we staged an exhibition in Marseilles by the Senegalese sculptor, Ousmane Sow, the first individual showing of his works came as a major shock to many people, including the specialists. I can remember the reactions of at least   two colleagues from museums of contemporary art. What they said was almost identical, and was along the following lines:</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">· What's the name of this sculptor ? I am not familiar with him...</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">A N. Do you like his work ? </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">· Yes, I do, but what's his name ?</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">A.N. Ousmane Sow </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">· I don't know him. Astonishing! Where's he from ?</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">A N. Senegal - he lives in Dakar. Are you interested in his sculptures ? </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">· Yes, but..</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">A N. You can buy one of his works - he's not very expensive yet and it would be good for your museum. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">· The problem is he's African.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">AN. I see... </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">· His works are more your sphere.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">A.N. But they don't have anything to do with traditional art which is what I have in my museum. Ousmane Sow is a contemporary artist, isn't he ? </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">· Yes, but he's African, and your museum is a museum of African art.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">A N. You're correct, I would love to buy one of his works. But it would be the only example of contemporary art in my museum and would represent a change of policy for me. You wouldn't have anything by Ousmane Sow. And we would then be rivals! </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Critics, artists and art historians have begun discussing contemporary African art, more and more good reviews of it are being published, talks are being given and some major exhibitions have been mounted. There are pioneers and supporters in France, Germany and elsewhere, and there is even a great museum - Washington's Smithsonian - which took it on board several years  ago - but we still seem to be a long way from a commitment from most institutions.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">I hope this statement will soon be proved wrong. Institutions do not like taking risks. Either they create 'ghettos' ('let's set up a museum of contemporary African art'), or they set up committees to consider the subject. It is up to us to set our houses in order, but we must not be too naive. This is the art market, after</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Although we tend to cling to this somewhat short-sighted administrative view that there should be different institutions depending on whether we are dealing with heritage or contemporary creativity, museums of contemporary art must integrate all the world's sculptural expression. If not, they will be in conflict with the above; postulate which claims that creative  potential is the same everywhere.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">As for so-called museums of anthropology and also a few rare museums such as the Museum of African, Oceanic and Amerindian Art in Marseilles, the systematic exhibition of contemporary art does generate a number of problems.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">When I have wanted to do this in the past, I have been reminded of the 'museographic landscape' and advised to consult the authorities, to organise a major debate on the topic: who, what, where ? That is the rational approach, we are told. There is no great hurry!</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">In fact, the recent arrival of African artists comes at a moment in our history when we are questioning the existence of our museums. When I say 'we', I mean the West in general.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">So, what might happen ? Traditional African art caused an explosion in Western art and traditional art history at the very beginning of the 20th century, with the cubists and their research which led them to develop a passion for African sculpture. We are all aware of what we owe to Africa and its traditional artists.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Contemporary art from Africa is knocking on the closed door of Western museums, but the arrival of contemporary African artists and the pressure they exert on the art world and  market might trigger a new revolution in the museums, which are also the archives. Certainly, all the usual followers are ready to take up the cause, and that is how it should be. Let's be optimistic.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">A.N. </P>
+<P ALIGN="JUSTIFY"></P>
+<B><P>&lt;&lt;TOC3&gt;&gt; The works of Ainsley Yearwood: Bombarded with colour </P>
+</B><P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">by Claude Smets</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Ainsley Yearwood is a Trinity dadian artist based in London. me Courier had the opportunity to meet him recently when an exhibition of his works was staged at his country's embassy in Brussels. Brought up in Trinidad, he moved to London to study fine arts at the Chelsea Art School. Feeling unable to express himself fully in this discipline, he ended up taking a degree in graphic design. Mr Yearwood is still based in the UK capital where, in addition to his work as a painter, he also designs costumes for the Notting Hill Carnival, a cousin of the famous Trinidad Carnival.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The artist is fortunate to be able to live from his work. Besides the present exhibition which is touring Europe (Manchester, Brussels, Geneva and London), he has other works currently on show at three galleries in the US. He finds that the reaction of the American public is different from the European one. Americans, he believes, are more spontaneous and openminded. 'Europeans tend to stick more to things they already know; to which they are more accustomed.' The titles he gives to his art pieces are for him 'a basis for artistic conversation' with his audience. They express his emotions, feelings, and thoughts, but do not try to impose a specific interpretation of the painting on the viewer. Ainslie Yearwood dislikes the idea of being labelled or categorised - or as he describes it, 'to  be put into a box'. As such, he rebels against people who try to make him conform.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">A world citizen</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Although Ainsley Yearwood recognises his African roots within Trinidadian society, he sees himself as 'a world citizen'. The influences in his paintings are many and varied - deriving from the multicultural background of Trinidad and Tobago, European art and graphic design, the memories of his own childhood and his recent experiences. 'I am like a sponge', he says. 'Everything influences me in my work... people, places and all that I see around me. They help me to view things from a different perspective.' These all then flow together to be visualised through his 'inner eye' (expressed, for example, by two blue dots in his work In the Company of Nature which represents the Grand Canyon). By paying particular attention to what he sees, his 'visual view' is transformed into an 'emotional view'. Thus, for example, his painting Evolution appears to be a landscape. A :loser look reveals that the rocks are in the shape of hands.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The artist also uses symbols in dome of his work, as a personal means 'or him to express life. The butterfly :rapped in a jar, for example, in Love lost, is a symbol of the fragility of life. The glass of water in Soul of a Mother symbolises the way a child looks at the world as something exciting and new. he also draws strongly on the imagery of candles, inner eyes and doorways.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Strong colours, strong emotions</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">What unifies Mr. Yearwood's work, is his use of colours. As he says, they are 'strong colours to express strong emotions'. In this, he has been inspired by his childhood in Trinidad which, in his own words, 'was an environment that constantly bombarded you with colour - from crystal to aquamarine, sapphire and emerald - a perpetual rainbow of red, yellow, green and blue'. One painting where colour is used to striking effect is Carnival Bacchanal. This depicts Trinidad's Carnival and reflects both the island's multicultural society and its vividness.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Ainsley Yearwood has also produced more surrealist and psycho-biographical works, under the influence of artists such as Salvador Dali and Francis Bacon. Emotions are revealed through the use of darker though still vivid colours. These works (such as Evolution, </P>
+<P ALIGN="JUSTIFY">Translucent State and Suspended in Limbo) show a fragmented self, stuck between past, present and future, looking for a way forward. They come in stark contrast to the brighter mood of paintings of island scenes - which are in a more African style - or of jazz musicians (such as Soul of a City or The Musician). According to the artist, this is being realistic. If he wants to paint life, he must show the different and contrasting emotions a human being experiences. 'You get up in the morning and you are feeling a little bit happy. You come home in the evening and you are feeling a little bit down. So emotions are continuously changing. If I said that I was always happy, that wouldn't be true.' </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">As mentioned above, a number of Ainsley Yearwood's pieces portray jazz players. He enjoys going to New Orleans to listen to jazz bands and in Soul of a City he portrays one of the musicians. The title underlaines the importance of performers in a place like New Orleans - where indeed, they form an integral part of city life. In A Musical Love affair, the painter uses techniques learned as a graphic designer to help him express his feelings. By drawing graphic lines, the cello player and the instrument flow into one another. He explains: 'The cello player was not just playing the instrument. She was actually part of it. It is as if she were making love to the cello.'</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">It is clear from the foregoing that Mr. Yearwood's art is primarily visual. The onlooker is bombarded with strong colours - which are used, together with abstraction and symbolism, to express both optimistic and pessimistic feelings. The artist uses his multicultural background to great effect, drawing on influences from Trinidad, Africa and Europe, to create different modes of expression. These are the essential factors which make his paintings interesting and refreshing to look at.  c.s. </P>
+<P ALIGN="JUSTIFY"></P>
+<B><P ALIGN="CENTER">&lt;&lt;TOC2&gt;&gt;  CTA-Bulletin</P>
+</B><P ALIGN="JUSTIFY"></P>
+<B><P>&lt;&lt;TOC3&gt;&gt; Fairness on the livestock field of play  </P>
+</B><P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">by Sarah Reynolds</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">In the town of Thies one of Senegal's regional capitals, there is an abattoir where nothing goes to waste. Even the horns of cattle are sold for making carvings for sale to tourists while the tips of the horns are exported to Japan. In a rural area of Chad, small-scale livestock farmers are preserving meat by the age-old process of cutting it into strips and drying it in the sun. Careful attention to hygiene and quality control has resulted in a product so consistently good that it has found an export market as far away as Gabon. Livestock producers in sub-Saharan Africa are responding to market opportunities, not because they recognise the need to improve national food requirements, but in pursuit of profit. Therein lies the best chance for stimulating the livestock sector's production capacity. The challenge is to design policies that protect consumers without crushing entrepreneurial potential for producers.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">More than half the population of sub-Saharan Africa is likely to be living in a town or city within the next 30 years. These city dwellers will have neither the skill, the time nor the space to raise livestock. There are indications on present trends that their demand for food of animal origin will increase. Where will they get it from ? Imported meat is more expensive than it used to be, largely as a result of the change in policies of the European Union. These have also affected the supply of low-cost milk powder and butter oil. Imports from countries outside the continent will  undoubtedly continue but intra-African   trade and local production will become   far more significant.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">It has been estimated that the production of animal products in sub-Saharan Africa would have to increase by 4% per year to ensure an adequate supply of animal protein for the region's growing population, and to end the need for imports. This presents a major challenge to policy-makers. Already, the current pressure on land resources is causing conflict in some areas and the prospect of more people, more animals, and more strain on already inadequate resources, is perturbing.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Information vacuum  in developing countries.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The concept of value</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Decisions on how to achieve sustainable and yet more productive land-use, while at the same time ensuring fair access to resources for other interested users, cannot be soundly based if made in an information vacuum. It was in recognition of the lack of information about the livestock sector that the CTA organised and sponsored a seminar on Livestock development policies in the humid and sub-humid zones of sub-Saharan Africa. This was held in Abidjan, Cote d'lvoire on 5-9 February 1996. It was attended by participants from 17 countries within the region and by representatives from international institutions and from Europe. The objective was to contribute to the ongoing debate on policies aimed at bringing about sustainable livestock development while respecting natural resources in developing countries.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The concept of value</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Effective planning of government action on issues such as import policy, provision of inputs and services, marketing and research priorities requires quantitative information on livestock production systems. Why is this information lacking when it is estimated that livestock products contribute about 25% of total agricultural GDP in subSaharan Africa? The livestock sector is too important to ignore and yet it is consistently undervalued. The reason is that economists and statisticians like to deal with a tangible unit that can be counted. Ideally, this should be a monetary unit but, failing that, it should at least be a unit that can be easily converted to money, such as the number of animals potentially available to the market. But if animals are used to sustain a traditional way of life, for people who do not have to pay before they can eat, it is difficult to put a monetary value on the food they consume. Similarly, if a herd of animals is sustained by forage that has no other use, on land that can be used for no other purpose, the cost of feeding cannot easily be measured in financial terms. Indeed producers have little to gain from allowing government   departments to acquire information about their assets.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Livestock owners have their own objectives when deciding whether and how to increase production. Livestock provide energy in the form of draught power, and dung for fuel or biogas. Their manure restores structure and fertility to the soil. Social prestige may be measured in the quantity and quality of the animals one possesses. For some livestock owners, their animals are their 'barking' system. They represent a deposit account for accumulated wealth and a current account when an animal is sold to raise cash. Indeed it may be impossible to obtain credit from an orthodox bank. There is an added advantage in that there are no interest charges to pay when you raise cash by selling your own animals as opposed to taking out a loan from a bank. It may be difficult to measure real production when animals are treated as a capital reserve. For example, an increase in meat prices, perhaps as a response to a change in economic policy, may result in a short-term reduction rather than increase, in the number of animals being marketed. This is because producers are able to maintain their income by selling fewer animals and can simultaneously  increase their breeding herds. Alternatively, there may be little incentive to producers to sell more animals if they have no use for the extra money they earn. It is of course true that more people are joining the cash economy as they become aware of the desirability of consumer goods, or of services such as schooling. Governments may aspire to design policies which will develop the livestock sector for the economic welfare of society as a whole, but if these policies ignore the objectives of livestock owners, they will fail.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Fair play</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">In a football match, the referee is there to see fair play. In the livestock sector, governments have to ensure fair play between the 'demand team' and the 'supply team', in other words the -consumers and the producers. Governments often make two mistakes. Either they help one team at the expense of the other, or else they join in the game themselves. The role of the authorities should be to make the rules that protect both teams from unfair or unsafe practices. For example, health and hygiene regulations must be in place, and  enforced, but not be so onerous that illegal and totally unregulated marketing channels are established.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Private traders have considerable power to manipulate markets if they collude to form cartels and prevent outsiders from entering their ring. Governments should ensure that this is not allowed to happen, that markets are open and that traders are free to operate provided that they observe health and hygiene regulations.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Veterinary services</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Most countries are no longer able to supply even minimum standards of veterinary support to their livestock producers. The efforts that have been made in recent years have been largely in the form of donor-funded projects where continuity is rarely guaranteed. The only viable alternative seems to be to transfer activities of this kind to service providers in the private sector. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The work that they do under contract to the government, for example relating to the control of epidemic diseases, must be funded by government or other central agencies since cost-recovery from individual livestock owners is not feasible when participation has to be compulsory. The work that they do on behalf of individuals, or associations of livestock owners, should, however, be paid for by those who benefit directly from the increased productivity that should result - the farmers. The greatest difficulty lies in managing what will be a long and difficult transition period. The success of ventures to privatise veterinary services depends on whether the profession can deliver a decent living in the private sector, particularly in rural areas where the need is undoubtedly greatest.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Rural development</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">It is in the rural areas that livestock production needs to be intensified. On the outskirts of Africa's major cities, intensive pig and poultry production is already being supported by commercial, joint venture capital. Dairy units, in which exotic, high performance cattle breeds are managed in a controlled environment, are producing fresh milk for cash-paying consumers in nearby towns and cities. Urban areas create the demand but it is the rural areas that need the development.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Animal products are seasonal and prices fluctuate accordingly. However, consumers are more likely to develop the habit of using products that are consistently available at stable prices. Government intervention to stabilise  prices risks favouring the consumer at the expense of the producer. For example, if imports are used to counter temporarily high prices during periods of drought, then producers will receive less for their reduced output at the very time when they need support. The most effective policy of price stabilization is to encourage the adoption of production systems that are less vulnerable to seasonal changes. Processing achieves this to some degree and brings benefits to both producers and consumers. Furthermore, because animal products are perishable, and dangerous to human health when they deteriorate, processing extends storage life, and may even have an effect in improving food security.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">In most countries, the time of greatest food shortage is at the beginning of the rainy season. This is also the time when milk production soars because cattle have good feed; and yet much of that milk is wasted because there is more than required for home consumption. If that surplus milk can be fumed into cheese, potential customers in more distant markets may be reached. Provided that the product is acceptable to the consumer, cheese-making reduces wastage, diversifies the producer's source of income and may also provide employment, and therefore income, to those brought in to help with the production.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">A technology that has been exhaustively tested by FAO for its suitability for use in Africa is lactoperoxydase. This is an enzyme which extends by three hours the length of time before milk begins to curdle and clot. This effectively doubles the time available for milk to reach the cooling centre, and thereby extends the catchment areas for producers wishing to supply fresh milk to urban markets. The trials that have been conducted show that it is entirely safe. When milk is brought to rural collecting points, it is the responsibility of the cooling centre employee, not the farmer, to add the enzyme at the prescribed rate as the milk is transferred into cans.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">On current trends, it seems probable that there will be more than 20 capital cities in Africa that have a population of 10 million people by the year 2010. How many other cities and towns will have developed by that time ? There are so many people migrating to the urban areas, and they are doing so because the type of activities that ought to be taking place in the countryside do not exist. If the livestock industry, both primary production and processing, can be encouraged in rural areas, and if the infrastructure is in place to ensure that animal products, in whatever form, can reach urban markets, rural dwellers will find it more comfortable to stay where they are rather than going to the cities to look for jobs that do not exist.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The challenge for policy-makers is to deal even-handedly, not only in the interests of the livestock sector, but in the interests of other farmers, consumers, the national economy and the long-term sustainability of the nation's natural resources. For this task, reliable information, which is accessible to all countries within the region, is essential. The database structure of this information should be standardised so that it can form the basis of regional cooperation on trade and the sustainable use of land resources.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">S.R. </P>
+<P ALIGN="JUSTIFY"></P>
+<B><P>&lt;&lt;TOC3&gt;&gt; The Couriers Mailbag</P>
+</B><P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">WCL seeks a wider  expression views</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">We refer to the article published by The Courier in issue no 156 (March-April 1996) entitled The changing face of trade unionism in Africa, which reflects the views of the ICFTU (AFRO) and OATUU.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">We are surprised that you have not taken pains to solicit the views of the World Confederation of Labour (WCL) and its regional organisation, the Democratic Organisation of African Workers Trade Unions (DOAWTU) - which participated on the same footing as the two other trade union organisations at the ACP-KU Social Partners meeting in December last year. We strongly believe this omission on your part should be corrected in future in order to allow a wider expression of the views and stands of all representative trade unions in Africa on such important issues as structural adjustment programmes, the social clause, labour standards and working conditions.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Carlos L. Custer, Secretary-General, World Confederation of Labour, Brussels, Belgium</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Linked destinies</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The continuing dialogue between the ACP and EC Groups has exposed many mutual concerns about world affairs and has promoted a more complete understanding of the problems of both advanced and developing  nations. I am confident that in the future, we shall see further progress in our efforts to create a favourable financial climate for the resolution of our economic problems.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Global political and economic events have brought home to all of us how inextricably our social and economic destinies are linked. This is true of a whole range of subjects from human rights and political reform to economic development, conservation, health education and industrial promotion. None of these subjects can be put into independent boxes. We must seek more effective integration of our social and economic policies - both internally and internationally - if we are to serve the welfare of the people.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">I rejoice in your initiative in publishing The Courier. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Teddyiniovo, International institute for Global Cooperation, Benin City, Nigeria</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Scope for energy selfsufficiency</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">May I congratulate you on the new layout of The Courier, which is a great deal clearer and which you have instituted as a result of comments made by a number of your readers.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">I am surprised to discover that you have not said anything about the question of energy dependence in the Lom&eacute; Convention countries. Energy self sufficiency is an extremely important issue. ACP countries face a famine in this area which is rarely mentioned. Most are majors exporters of petroleum, which is  costly and absorbs a significant proportion of their foreign exchange earnings.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Practically all the Lom&eacute; countries are in a position to produce alcohol from crops such as sugar cane and manioc without any negative impact on their food resources. These crops could be distilled to produce big-ethanol which is an excellent fuel. All that is needed - and it is a major challenge admittedly - is for production to be organised in each country, and for the required national and international financing to be set up.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Also required is the political will in these countries to overcome the various obstacles, including those lobbies who oppose this kind of production because they want petrol imports to be maintained.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Pierre Mariotte Consultant, Paris, France </P>
+<P ALIGN="JUSTIFY"></P>
+<B><P>&lt;&lt;TOC3&gt;&gt; Bibliography</P>
+</B><P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Jean Monnet - 1888-1979  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">by Eric Roussel. Published by Fayard, Paris. 1996. 1004 pages. FFR 198.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Jean Monnet was almost 91 years old when he died and, despite the fact that he had no higher education qualifications and at times did not hold any official post, his public role was legendary. From the very first page of his book, Eric Roussel stresses the fact that, from the moment Jean Monnet met the Prime Minister, Rene Viviani, in September 1914 until 9 May 1975, the day the Action Committee for a United States of Europe was dissolved, he worked constantly for the European cause.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">He applied the same tireless enthusiasm to all his duties, in whatever sphere of activity he was involved - and these were many and varied. Despite his provincial origins, Jean Monnet was, among other things, a cognac merchant, an advocate of the Allied coordination effort during the First World War, Deputy Secretary General of the League of Nations (for a short time), a banker in America and China during the 1930s and in charge of the Victory Program in the USA in 1941. From 1947 to 1952, he was the first Commissioner-General of the Economic Plan in France. He and Robert Schuman were the architects of the famous Declaration of 9 May 1950 which was to form the basis of European construction. He went on to become the first President of the ECSC's High Authority and, until 1975, he was the driving force behind the Action Committee for a United States of Europe. And that is just to highlight his renowned roles.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">In addition, Jean Monnet was both a visionary and a pragmatist, who was to become adviser to some of the greatest names of his day. General de Gaulle, another great visionary, albeit with a very different ideology, called him 'the inspiration' behind European integration, although such an accolade was not completely devoid of irony given that the two men could hardly be said to see eye to eye.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Jean Monnet was a purveyor of new ideas, but also an eternal realist who never failed to recognise the importance of the status quo. Indeed, he could have stepped right out of the pages of a Paul Morand novel. And yet, despite the fact that he was held in the highest esteem by world political heavyweights (Clemenceau, Roosevelt, Churchill, Adenauer, de Gasperi, Brandt, Pompidou, John Kennedy, Henry Kissinger, Heath and Giscard d'Estaing, to name but a few), in his private life he was a simple man, of modest disposition - in fact a bourgeois in the best sense of the word.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">A 'workaholic', like many great men, Jean Monnet defied categorization. He has recently been described as 'a man of fringe ideologies who was nevertheless always at the centre of things'. During the latter part of his life, he settled comfortably into his role as 'rather' of Europe. His fundamental thoughts on that topic could be summed up in one line from the Declaration of 9 May 1950, (now a public holiday in the European institutions). 'Europe will not be built in a day, nor as a single structure, but will come about through concrete actions which, first and foremost, create a de facto solidarity'.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">For Monnet, nationalism meant only war and, from 1942 onwards, he set his sights on preparing for the future, surrounding himself with a team of extraordinary talent - people such as Etienne Hirsch, Herve Alphand, Rene Mayer and Robert Marjolin. These men strove to find ways to avoid war between the countries of Western Europe, to define the objectives of European unification and to establish European institutions which would be equal to such a task.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Eric Roussel is a journalist with an arts degree and a doctorate in law, and this is an outstanding work on the 'pragmatic visionary' that was Jean</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Monnet. The book is comprehensive, extremely well-written and impressively documented. Most notably, the author had access, for the first time, to the famous journal kept by Jean Monnet in which he recorded his countlles conversations with the key players and set out his own thoughts. Today, his dream of 'a united Europe complemented by a partnership with the United States' is still one of the big issues. And as the arguments rage, we should perhaps recall some other famous words from Jean Monnet's Memoires: 'We do not seek to form a coalition of States, we seek to unite men . </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Alain Lacroix </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Le Choix de l'Europe</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">(Opting for Europe)  by Laurent Cohen-Tanugi. Pub/ished by Fayard, Paris. 225 pages. FFR 110 - BFR 748.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">'Laurent Cohen-Tanugi successfully reminds us of the modernity of the European project; that there are aspects of it that are essential to our independence and our prosperity, to preserving our model of society and maintaining our influence on the international stage. By urging Europeans and European leaders to look to the future so as to be better able to manage the risks and seize the opportunities that it offers and, ultimately, to be in a better position to change things, he brings us all hope'.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">This was how Jacques Delors described this book, and, basically, there you have it in a nutshell. It would, however, be worthwhile adding that 'opting for Europe' is not quite as simple as it sounds - a fact which has not escaped the attention of the author, who is a graduate of France's elite Ecole normale superieure and of the Harvard Law School. He is also a barrister and member of a renowned firm of international lawyers.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Since the Treaty of Rome, European progress has very often come about because Member States have set themselves deadlines for achieving particular objectives. 1996 sees the opening of the Intergovernmental Conference, an event of major importance, which is expected to continue at least until the spring of 1997 (with parliamentary elections planned in several Member States in 1997 and 1998). Among the items on the agenda for the IGC is the need to adapt the European institutions - which in essence have hardly changed since 1958 - and to open up the way for the third phase of Economic and Monetary Union in 1999 for those States which have fulfilled the economic convergence criteria set out in the Maastricht Treaty.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">However, besides the technical and financial problems involved, there are also differences between certain Member States about the political future of Europe. The author rightly stresses, in this respect, that the situation has become even more complex since the demise of the Soviet Union. In particular, some politicians support an expansion of the EU towards Central and Eastern Europe, so as to avoid strengthening European integration. The author believes that, broadly speaking, there are two distinct positions. On the one hand, there is the United Kingdom, which would be happy with a large free trade area guided by a 'Secretariat-Commission'and with flexible and relatively loose inter-State cooperation structures at a political level. On the other hand, there is Germany, which wants expansion of the Union towards the East as well, but also wants a swift and concrete consolidation of a common monetary and political 'hard core'.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">In his book, the author expresses his view that France will play a vital role in maintaining and advancing the essential elements that form the basis of the European enterprise. And he nails his own colours firmly to the mast as someone who hopes to see the continent moving towards some form of federal structure. As one observer commenting   on the work has noted, 'This little Bible, brimming with faith in the concept of a unified Europe, will be invaluable - even to the doubting Thomases among us'. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Publications received</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Et.... qu'en pensent les villageois? Projets de developpement durable et be veins de base b&eacute;n&eacute;ficiaires</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">(But... what do the villagers think about it ? Sustainable development projects and basic needs of aid recipients)  by Myriam Bacquelaine. Published by Ured (Research, Education and Development Unit) of the K.U. Brussels (17, avenue de la Liberte, B- 1080 Brussels). 1995. 3Z2 pages.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Les problemes du monde rural vus par les habitants - Portraits de villages de Haute-Guinee</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">(me problems of rural life as seen by the inhabitants - Profiles of villages in Upper Guinea)  by Myriam Bacquelaine. Published by Ured (Research, Education and Development Unit) of the KU. Brussels (17, avenue de la Liberte, B- 1080 Brussels). 1995. 222 pages.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The author, who has a PhD in educational sciences and is a researcher at Ured, has written these two works on the basis of a study she carried out on behalf of the European Commission in Guinea (Conakr,v). This aimed at identifying the most urgent priorities of village communities within the context of an environment restoration project.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The conclusion of the first book underlines research results which point to the adoption of a different approach to development at local level: one which respects the wishes of the recipients and which finally breaks free from western ethnocentrism.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">In the second volume, the author presents the results of the survey conducted in the villages of Upper Guinea. Six villages with varying characteristics in terms of size, geographical location and administrative status are featured in more detail. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY"> </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Informations pour le Developpement: Agriculture</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">(Information on development: Agriculture)</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Published by Ibiscus (ibis, rue du Havre, F-75008 Paris) and by the Agency for Cultural and Technical Cooperation. 1995. 271 pages. FFR 150.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">More than just an index, this publication is a useful working tool for anyone seeking reliable information about development in the agricultural sector. It includes a list of the main organisations specialising in agriculture in 40 French-speaking countries and a list of the principal places and means from which to obtain information (documentation centres, data banks, optical discs, CDs and on-line data services). There is also a selection of periodicals, a bibliographic section (with more than 300 references, including abstracts) and contributions by specialists relating to major topics connected with rural development: landownership systems, links between cash crops and food crops, agricultural funding, etc.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Rwanda - Trois jour qui ont fait basculer l'histoire</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">(Rwanda - Three days that shook history)  by Filip Reyntjens. Published by L'Harmattan (5-7, rue de l'Ecole-Polytechnique, F75005 Paris). Cahiers africains no. /6! 1995. 148 pages FFR 9O. ISBN 2-738437044.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Although much has been written about the tragic events in Rwanda, this work examines an aspect of the story which is still largely a mystery: the brief period which began on 6 April with the missile attack on the presidential jet and ended on 9 April, when the 'caretaker government' was swam into office. According to the author, these 72 hours were of critical importance since it was during  this time that the country's killing machine was set in motion.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Essentially based on eye-witnffs accounts, it is a tale which is far from complete. The book, however, does provide some hitherto undocumented information which allow us to delve deeper in search of the truth behind one of the darkest pages of recent human history.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Les refugies rwandais a Bukavu au Zaire - De nouveaux Palestiniens?</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">(The Rwandan refugees in Bukavu, Zaire - the new Palestinians ?)  by Philippe de Dorlodot Published by L'Harmattan (5-7, rue de l'Ecole-Polytechnique, F-75005 Paris) and by the Jeremie Group. 1995. 253 pages. FM 150. ISBN 2-7384-3698-6.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The author has brought together various stories, appeals, communiques, analyses and thoughts to write this book about the crisis facing the Rwandan refugees. The accounts cover the period from April 1994 to October 1995 and relate to the situation in South Kivu, Zaire, where an already volatile position has been greatly exacerbated by the arrival of the refugees. The people living in the regional centres of Goma and Bukavu are having to live with the tragedy of gross overcrowding and all its consequences - environmental deterioration, price increases, general insecurity and the threat of war on the border between Rwanda and Burundi.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Zaire now wants the refugees to leave as quickly as possible, but their return to Rwanda is still problematic. Rejected at every turn, are these Rwandan refugees set to become the new Palestinians? In the postscript to the work, Filip Reyntjens (the author of the book reviewed previously) states that 'These new refugees will not accept eternal exile. H voluntary repatriation is not possible, and if forced repatriation is unacceptable, the only way left open to them may be armed repatriation... The civil society of South Kivu... is well aware of this, and the international community would do well to listen to their cries of alarm... If  it does not, the tragic events of the past year will have been merely a prelude, with the worst still to come'.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">La tragedie rwandaise - Historique et Perspectives</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">(The Rwandan tragedy - historical background and future prospects)  by Emmanuel Nkunzumwami. Published by L'Harmaffan (5-7, rue de l'Ecole Polytechnique, F-75005 Paris). 1995. 480 pages. FFR 250. ISBN 2-7384-3697-8.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The author, a teiecommunications engineer and economist, was born and raised in Rwanda. He now lives in France and has had several articles about the situation in his country published. In this work, he seeks to Reconstruct the machine of central Rwandan power which first appeared in the eleventh century, seeking answers to questions such as: Who ruled the country and how? What alliances were forged and according to what criteria? What kinds of social structure existed and what forms did conflict take? He then goes on to describe the trauma of colonial rule which 'deliberately' fanned the flames of socio-ethnic conflict so that the people could be more easily controlled. From there, he takes us through the era of an 'independent' Rwanda under a dictatorial regime. Its power was progressively stripped away, initially under the pressure of internal calls for democracy, and then by the demands of Western aid donors. Finally, he recounts the events since April 1994.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Having given the historical background, the author examines the country's future prospects. He believes that the 'siege mentality' of the new government does nothing to induce the return of the 2 million refugees who shuffle back and forth across the border and who find themselves stuck between a 'rock and a hard place'. Finally, the author poses a straightforward question - but one which has yet to be answered: How can we rebuild a country that has witnessed genocide on such a scale ? </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<B><P>&lt;&lt;TOC3&gt;&gt; News round-up</P>
+</B><P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">In brief</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">UNCTAD Report on the least-developed countries (LDCs)</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">According to the annual report of UNCTAD (The UN Conference on Trade and Development), the 48 least developed countries of the planet, after several years of stagnation - and indeed, decline in some cases - enjoyed an average growth rate of 3% in Gross Domestic Product (GDP) in 1994-95. The figure was 4.6% for LDCs in Asia and 2.2% for those in Africa (33 out 48).</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">UNCTAD says that the renewed grovvth rate for Africa's least developed nations is due to an increase in commodity prices, to improved political and social stability in certain countries and to economic reforms which have been implemented. If these favourable conditions are maintained, further modest progress can be anticipated for 1996.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Despite the positive impact of these factors on the development of countries, notably in Asia, UNCTAD believes that there is still a short-term danger that the world's weakest economies will suffer further marginalisation. It is pointed out, in this context, that the LDCs' share of total world trade - which stood at 1.7% in 1970 - had fallen to 0.4% for exports and 0.7% for imports, by 1994.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">In the longer term it is thought that the LDCs, with their reliance on basic commodities for export receipts, may benefit from the globalization of their economies. This should happen notably through the regional trade agreements to which they are parties, alongside other developing countries. These regional markets, which are more attractive for investors, offer an opportunity for LDCs to try out their products and can, in time, help improve their competitiveness. In the  meantime, however, UNCTAD has noted that the immediate effects of the Uruguay Round have tended to be more negative, with reductions in the preferences enjoyed by LDCs in export markets and increases in the price of foodstuffs.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">In addition, because they are dependent on official development aid (ODA) to finance investment, and even for their national budgets, LDCs are faced with possible further marginalisation as such aid flows are reduced. The figures show that, in terms of total resource flows, the amount of ODA provided by the Development Assistance Committee (DAC) of the OECD fell to 23% in 1994 from a figure of 27% a decade previously.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Likewise, the amount of aid, expressed as a proportion of the GDP of the donor countries, has been falling.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">UNCTAD suggests a bolder policy as regards external debt - which, in 1994, amounted to 73% of the entire Gross Domestic Product of the LDCs. The organisation believes that the establishment of a new mechanism with sufficient resources to reduce multilateral indebtedness, combined with the expansion of existing mechanisms, could have the effect of reducing the overall debt burden to a more reasonable level.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">On the subject of globalisation, UNCTAD argues that the international community should work to ensure that the LDCs' export markets do not become blocked by protectionist measures. It also believes that extensions to regional trade agreements, taking in the main industrialised countries, should not be allowed to have a damaging effect on the commercial interests of the LDCs. It points out that these countries have only limited scope for pursuing independent, national economic policies and that</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">No agreement over banning landmines</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Humanitarian organisations have expressed disappointment over the outcome of a recent United Nations conference, convened in Geneva to draw up a convention on 'Inhumane weapons). Both NGOs, and public agencies such as UNICEF, are particularly unhappy that state representatives at the meeting were unable to agree to an immediate and comprehensive ban on anti-personnel mines. These devices, which often lie hidden in the soil for many years, kill and maim thousands of civilians in current (and former) conflict areas across the globe</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Diplomats attending the Geneva conference were keen to emphasise what had been achieved. So-called 'dumb' mines, which do not self-destruct after a certain time will eventually be phased out.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Seif-destructing devices, which are still permitted under international law, will be subject to strict new standards, designed notably to ensure that they can be detected. And there will be new rules to ensure that minefieids are properly marked.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Critics point out that signatories to the Convention will not be obliged to phase out 'dumb' mines immediately and that their use will remain legal for a further nine years after the agreement enters into force.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">There is also an exception to the rule about marking the location of mines, 'where direct military action makes its impossible to comply' - a not uncommon circumstance in conflict situations.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Since the Geneva Conference, a number of countries, including the United States, have announced their intention to reduce their stockpiles of mines. Few nations, however, seem willing to renounce their use altogether. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">S.H.  their governments have little choice but to adopt the prevailing market oriented approach.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Long-term food security</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">A seminar on 'Long-Term Food Security Policies' was held in Brussels on 1-3 April at the initiative of the European Commission. The meeting, which was opened by Professor Pinheiro, Commissioner with responsibility for relations with the ACP countries, brought together about a hundred participants representing Member States, third countries, international organisations and major cooperation agencies. It was also attended by experts and researchers in the field of food security.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Fulfilling a promise made by the Commission, the aim of the seminar was to clarify the long term strategic issues and take a closer look at food security policies with a view to preparing a European position for the World Food Summit scheduled for Rome in November under the auspices of the UN Food and Agriculture Organisation (FAO).</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The European Community and its Member States are the world's main donors of food aid having spent ECU 1.089 billion on this in 1994. This amounted to 53% of the global total with the United States providing 44% and Japan 3%. Despite the large amounts being given, the FAO, the International Food Policy Research Institute (IFPRI) and the World Bank are all predicting that unless global food donations are boosted significantly, certain Asian and African countries will face an alarming food deficit by the beginning of the next century.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Between 600 million and 800 million people are likely to be facing hunger by the year 2010 and the cereal needs  of the developing countries could well double between now and then.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">This projected scenario coincides with a period of market difficulty. World stocks are low and grain prices have risen by 40% in just one year. Whether or not this is a portent of future food shortage, it has given rise to renewed debate on the ability of certain countries and regions of the world to supply themselves and the extent to which they will have to have recourse to the international markets. Closer attention is also being paid to the wider strategies that need to be implemented to ensure food security in the future.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">If one looks at the issue solely in terms of increasing supply, the projections are gloomy. Experience shows that the 'right' of access to a sufficient food supply for each of the planet's inhabitants cannot be guaranteed whether through world economic growth, food self-sufficiency at the national level, or the international markets and trade liberalisation. There is, therefore, a need for food security policies, in the developing countries in particular, which act on the conditions of demand as well as supply.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">In his presentation opening the seminar, Commissioner Pinheiro stressed the fact that of the ECU 7 billion allocated by the EU for development cooperation last year, ECU 1 billion was in the form of food aid. He also noted that this aid 'category' had evolved over the last decade in the context of the search for food security and explained how the Commission, in revising the policy towards the end of 1994, had set out three essential aspects:</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY"> - the use of food aid as a policy instrument designed to achieve longterm food security with the emphasis on local purchases and 'triangular' operations - thereby encouraging the growth of the agricultural sector in the developing countries: this entailed developing a new aid instrument in which funds are available to import basic food products (as a way of encouraging the private sector to  take a more active part in the economic life of those countries facing a structural food deficit);</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY"> - the integration of aid instruments into the actual development efforts of the beneficiary countries;</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY"> - improved access for the people who suffer most from food shortages.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Professor Pinheiro indicated that the Commission would shortly be presenting a communication on the strengthening of the link between development aid on the one hand and emergency, rehabilitation and food aid on the other.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">He stressed the important role that food aid operations could play in preventing conflicts and easing social tensions.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">According to the Commissioner, the challenge in this area have been clearly identified but he believes that additional thinking is needed, notably on the impact of events in China and the countries of the former Soviet Union, and on the effect of US and EC agricultural policies on the world markets.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">In conclusion, Professor Pinheiro expressed the view that food security was, above all, a national responsibility with all civil society actors having a role to play.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Citing the rise in the price of cereals during the second half of 1995 - which had prompted concerns about the availability of food aid and its impact on the balance of payments (notably in sub-Saharan Africa and the Indian sub-continent) - he gave an assurance that the Commission would remain vigilant about this. At the same time, he was concerned not to see a return to situations where aid in the form of straightforward transfers of food increased. These, he observed,</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">· had at least partly contributed to food costs, the destabilisation of local production and constraints on intra-regional trade. As such, they had set   back or undermined the reforms in this sector in the countries concerned.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Caribbean rice exporters fear changes in OCT . rules</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Guyana and Suriname, together with a number of Overseas Countries and Territories (OCTs), have expressed concern over the European Commission's recently announced intention to change the shape of its relations with the OCTs. In particular, they are worried that proposed new rules could harm their rice sales to the 15 European Union nations.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Guyana currently exports 180 000 tonnes of rice (80% of its exports) to the KU. This is shipped initially to the Netherlands Antilles (Cura&ccedil;ao, Aruba and Bonaire) to be partially milled. It then enters the EU market duty-free by virtue of the Union's existing trade rules with the OCTs. But Caribbean exporters fear that this 'OCT route' could soon be blocked by changes currently being considered in Brussels.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">As already announced in issue no 157 of The Courier (May-June 1996), in the context of the mid-term review of the association with the OCTs, the Commission published a text on February 14 proposing some fine tuning to the trade preferences it grants to these territories. This has now gone forward to the Council of Ministers for decision. The Commission proposal is that while agricultural produce may continue being processed in the OCTs - and hence still benefit from the more relaxed rules - this should happen in future on a case-by-case basis, and only if priority is given to the least developed OCTs and the operations are economically justified.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">In fact, preferential arrangements do apply to direct rice exports from Guyana and Suriname to the KU, but it is argued that the levies are still too high to make the trade viable.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">According to Yesu Persaud, who is Chairman of Guyana's Institute of Private Enterprise; 'it is only via the OCTs that we can export to the European Union.' Mr Persaud was speaking to journalists during a lobby visit to Brussels on April 16. He was accompanied by Charles P Kennard, Chairman of the Guyana Rice Development Board and David Jessop, director of the London-based Caribbean Council for Europe.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Justifying the need for derange, some EU officials point to evidence that non-tome developing countries are 'abusing' the OCT rice route. Rice is a sensitive product for some EU nations such as Spain and Italy, who grow their own.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Mr Persaud said that Guyana and Suriname were lobbying either for their own duty-free quota under the Lom&eacute; trade rules, or for 'a more reasonable levy'. At the same time, however, he indicated that the Caribbean rice growers were keen on keeping the route open via the Dutch and other OCTs (such as Montserrat and the Turks and Caicos) where major investments have been made on the  strength of the existing arrangements. A representative of the Turks and Caicos told reporters that his country earned half a million dollars a year from the trade, and that a new jetty had been built with British government support.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Guyana's rice exports have climbed from less than 39 000 tonnes in 1986 to more than 200 000 tonnes in 1995. And as Mr Persaud also stressed, the trade has done so well that Guyana is now investing in high-yielding varieties. </P>
+<P ALIGN="JUSTIFY">D.P.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Fight against locusts</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Fipronil, a recently developed pesticide, is said to be 10 times more effective than other products on the market in the control of locusts, according to representatives of the pharmaceutical giant, Rhone-Poulenc who organised a seminar on locust control </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Links between emergency, rehabilitation and development aid </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The European commission has recently approved a communication </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY"> (COM(96) 153) which was due to be presented to the Development Council on 28 May. The document seeks to respond tO the challenge of I maintaining and improving the effectiveness of emergency aid  rehabilitation assistance and development cooperation with third countries - in the face of a wide variety of political, economic and social circumstances.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The Communication suggests ways of strengthening the links between the three types of aid within a strategic planning framework which includes intensified dialogue and political cooperation.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">This initiative follows extensive consultations, both within the Commission (i_ service groups) and with representatives of numerous outside bodies (Member State experts, USAID, UN agencies, NGOs, academic institutions etc.). </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">While the key phrase in the Communication may be 'strategy and global planning', emphasis is also placed on 'coordination' end 'opportunity'. This underlines a commitment to adapting procedures, where necessary, so that measures can be taken at the right time and the transition from emergency aid, to rehabilitation and subsequently to development cooperation can take place in the best possible conditions.  with the 70-member African, Caribbean and Pacific group. The event took place in Brussels in April.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The new product, claims the company, fills a big gap that was left in the war against locust infestation when DDT was banned in 1986 (toxic residues from the chemical having been found to enter the food chain and damage the ecosystem).</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">It is stated that Fipronil causes 99% mortality among locusts and gives complete protection for up to three weeks when applied in doses of six grammes per hectare.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Its developers claim that it is three times cheaper than any other form of anti-locust pesticide used between 1987-1995, a calculation which includes the logistical costs involved in distributing the pesticide. It is said to be very effective in preventing locust infestations in countries in the Sahel that are particularly at risk.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The Sahel has some 250 acridian species. Of these, about 15, are known regularly to attack crops in large numbers, according to Michel Launois, who heads the French agricultural research body, CIRAD-GERDAT-PRIFAS.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">At the Brussels seminar, emphasis was placed on the need for donors to set aside more funds for the prevention of locust infestations. It was also stressed that locust control must be at a regional level because of the migratory nature of the species, and the link between locust control and food security was underlined.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">CIRAD-GERDAT-PRIFAS has just published an educational cartoon strip entitled 'Les Dents du Ciel 11' (available from Cirad-Gerdat-Prifas, B.P. 5035, F34032 Montpellier Cedex 1). This is intended to explain to a wide audience the need for an integrated approach to locust control.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">I New fishing agreement between Angola and the EU</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">A new fisheries agreement between Angola and the EU was initialled on 2 May. It is due to run for three years (as opposed to two years for the previous one) and should ensure greater stability and better programming of the Community fleet's fishing activities in Angolan waters. The EU will pay Angola the sum of ECU 13.35 million per annum in exchange for improved fishing rights for European fishermen.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">It is worth noting that the agreement contains certain innovations. These concern, for example, the legal status of catches (which are given Community origin). This should help to avoid the kind of dispute that has arisen in the recent past. There is also the possibility of imposing an annual biological 'rest-period' for shrimp fishing.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">I African conference on consumer protection</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The first African conference on consumer protection was held in Harare, Zimbabwe from 28 April to 2 May. This resulted from a joint initiative by the organization Consumers international and the United Nations, and it was supported financially by the European Commission. The latter was represented at the event by Mrs Emma Bonino, the Commissioner responsible for Consumer Policy.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The aim of the conference was to lay down the basis for a genuine consumer policy in Africa. Representatives of 45 African governments attended, together with officials from various regional and sub-regional organizations and delegates from a large number of</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">African consumer bodies. Coinciding with the tenth anniversary of the adoption by the UN of the guiding principles for the protection of consumers, the Conference offered an opportunity to track progress on the application of these principles in African countries. It also saw the adoption of 'model' legislation setting out the essential rights which should be guaranteed to consumers.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">In her speech, Mrs Bonino stressed the Commission's commitment to supporting the efforts of African governments and consumer organisations in seeking to establish, in a clear and pragmatic way, the link between consumption and development. Evidence of this commitment, she pointed out, was to be seen in her very presence at the conference. She also lent her support to the broad application of the UN's guiding principles in Africa. This would ensure that the health, security and economic rights of African consumers could be protected.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">But the European Commissioner stressed that legislation, while important, was not enough in itself to tackle the fundamental problem - which was the satisfaction of basic needs. She appealed for global action in Africa deigned to break the vicious circle of poverty - based on voluntary action at all levels.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Mrs Bonino added that the Commission would seek ways of supporting projects, in particular in the fields of food and health. This should assist citizens to meet their essential needs - with the opportunity to consume products which were different, 'local' and of better quality, and with risks to health and security minimised. The approach should avoid the exhaustion of scarce resources and respect nature. She indicated that an action plan would be drawn up by the Commission in collaboration with Consumers International. This, it was hoped, would allow financing of pilot programmes under a separate budget line which would be sought from the European Parliament for 1997. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">THE INSTITUTIONS</P>
+<P ALIGN="JUSTIFY">AT WORK</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">COMMON FOREIGN</P>
+<P ALIGN="JUSTIFY"> AND SECURITY POLICY</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Within the framework of its Common Foreign and Security Policy (CFSP), the European Union has recently issued a number of statements, details of which are set out below:</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Towards national reconciliation in Angola</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Declaration of 4 April 1996</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The Troika of the European Union Ambassadors in Luanda made a formal demarche with both the Government of Angola and UNITA in order to welcome the positive outcome of the Libreville Summit between the President of Angola, Jose Eduardo dos Santos, and the President of UNITA, Jonas Savimbi, and in particular their commitment to establish an integrated national army by June and the creation of an appropriate institutional structure, including the formation of a government of unity and national reconciliation by June/July. The Government and UNITA were encouraged to continue to refrain from military activity and hostile propaganda and to provide for free circulation of persons and goods as soon as possible. The EU Ambassadors underlined also the importance of securing human rights as well as transparency in financial management, economic stabilisation and reforms. Having recalled the terms of reference of the EU Joint Position adopted on 2 October, 1995, the Ambassadors underlined that the Union will continue to monitor, with the greatest attention, the development of the situation particularly as regards respect for the implementation of the calendar agreed in Libreville. Welcoming the recent steps taken by UNITA, the EU expressed concern at the slow pace of the quartering and disarming of UNITA troops and urged UNITA to proceed with its commitments, in full cooperation with UNAVEM ill. The EU encouraged the Government to continue the quartering of the rapid intervention police and the disengagement and pulling back of the FAA to the nearest barracks. The importance of disarming the civilian population was also emphasised. The EU also reiterated their call to the Government and UNITA to refrain from acquiring lethal material and to cooperate fully with the de-mining process.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The EU has reiterated its full support to the Special Representative of the UN Secretary-General, Maitre Blondin Beye, to the Joint Commission and to the United Nations Angola Verification Mission (UNAVEM).</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Cyprus, Estonia, Latvia and Malta align themselves with this declaration.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Free elections in Sierra Leone</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Declaration of 4 April 1996</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The European Union welcomes the fact that presidential and parliamentary elections took place in Sierra Leone in a free and fair atmosphere and in fulfilment of the established timetable for the return to democracy.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The results reflect the will of the people of Sierra Leone to achieve a democratically elected civilian government despite attempts at intimidation by armed elements and the ongoing fighting in various parts of the country.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The EU welcomes the peace talks between the Revolutionary United Front (RUF) and the Freetown authorities as well as the intention expressed by President Kabbah to meet Mr Sankoh at the earliest possible opportunity. The EU calls on all the parties to work for peace and national reconciliation.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Serious threat to peace process in Liberia</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Declaration of 11 April 1996</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The European Union expresses its deep concern at the outbreak of fighting in Monrovia, which represents a serious threat to the peace process in Liberia. The EU is firmly convinced that the AbuJa agreement provides the right framework for resolving the crisis and calls upon the Council of State, the Liberian national transitional government and the Liberian factions to implement it, and to put the peace process back on track, in order to avoid further deterioration of the situation, and the violation of human rights. The EU condemns the loss of human life and the harassment of the civilian population and humanitarian workers. All parties concerned should prove their willingness to re-establish and maintain the ceasefire which represents the necessary prerequisite to disarmament and demobilization. The relevant measures and the necessary preparations can no longer be delayed. The EU asks the factions to return all weapons seized during the fighting to ECOMOG. The EU will base its attitude to Liberia on the concrete steps taken by all parties concerned to implement the Abuja agreement and bring the conflict to an end.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Treaty of Pelindaba on a nuclear weapon-free zone in Africa</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Declaration of 12 April 1996</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The European Union welcomes the signature in Cairo on 11 April 1996 of the Pelindaba Treaty establishing the African Nuclear Weapon Free Zone. The Treaty is in line with the Decision on Principles and Objectives for Nuclear Non-Proliferation and Disarmament issued by the 1995 NPT Review and Extension Conference which   recognised that the creation of Nuclear Weapon Free Zones enhances global and regional peace and security.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The EU considers that Nuclear Weapon Free Zones are welcome complementary instruments to the Treaty on the Non-Proliferation of Nuclear Weapons, the universality of which the EU continues to promote.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The Central and Eastern European countries associated with the EU and the associated countries Cyprus and Malta align themselves with this declaration.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Appeal for the 'boat people' of Liberia</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Declaration of 14 May 1996</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The European Union expresses its deep concern at the grave humanitarian situation caused by the ongoing fighting in Monrovia and condemns the violence against the civilian population and the harassment of aid operations.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">While recognising the enormous efforts already made by neighbouring countries to assist the hundreds of thousands of existing Liberian refugees, the Council deplores the fact that the thousands of people crammed in precarious conditions on ships in the area are still in search of a friendly port.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">It appeals on humanitarian grounds to the neighbouring countries to give at least temporary shelter to these victims of the fighting and affirms its own willingness to give humanitarian aid to cover their most urgent needs.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The Council calls on all the Liberian factions to stop the fighting immediately and put the peace process back on track in order to avoid further suffering.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">VISITS</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The Prime Minister of Rwanda</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The Prime Minister of Rwanda, Pierre Celestin Rwigema, visited Brussels from 26 to 29 March in the course of a tour aimed at informing the main donors about the work undertaken by his government in recent months and about the policies which would be implemented in the future. He was accompanied by the Minister of Planning and the Minister for Rehabilitation. The Prime Minister was received by Commissioner Pinheiro, who is responsible for relations with the ACP countries and by Mrs Bonino, the Commission member in charge of humanitarian actions. He also spoke at meetings of the External Relations and Development Committees of the European Parliament. Professor Pinheiro took the opportunity to highlight to the Prime Minister his concerns about the current situation in Rwanda, reiterating the Commission's commitment to the country and its people. He also spoke of the need for the authorities to pursue policies and implement measures leading to the restoration of normality. He said it was essential to have a dialogue with the Rwandan refugees in neighbouring countries (there are now about 1.7 million) and to pursue the pacification process under the auspices of the United Nations and the Organisation of African Unity, with the involvement of all the heads of government in the Great Lakes region. Mr Rwigema's visit came at a crucial time for Rwanda. Even if the immediate crisis had passed, there was still a dire need for rehabilitation and development assistance, on top of the existing emergency aid programmes. The political situation remained delicate and the future was by no means secure, notwithstanding some encouraging signs of a progressive improvement as exemplified by the Tunis summit. The recent nomination of</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Aldo Ajello as the EU's special envoy to the Great Lakes region underlined the political and moral dimension of the EU's commitment to the peace process in this troubled part of Africa.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">SUPPORT FOR HUMAN</P>
+<P ALIGN="JUSTIFY">RIGHTS</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The Commission has recently decided to provide the following financing for projects under the budget line 'Support for. democratisation and human rights'. Non-ACP countries </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Central America: ECU 180.000 to support seven national and one regional fore aimed at providing training in the field of human rights for instructors. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Central America: ECU 100.000 for a democracy consolidation training programme for 30 teams from various organisations in Nicaragua, Guatemala and El Salvador. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Central America/Colombia: ECU 263.000 for a series of actions, notably in Colombia, involving the provision of information on human and citizens' rights. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Brazil: ECU 190.000 for a project designed to boost the civil rights of black people in the country, through the training of judicial personnel and the strengthening of legislation against race discrimination. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Brazil: ECU 145.000 for a training programme for magistrates, prosecutors and the police aimed at facilitating the uniform application of the law in the State of S&atilde;o Paulo. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Brazil: ECU 290.000 for a training programme in the sphere of democratic municipal management, in the cities of Recife, Porto Alegre, Santos and Fortaleza. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Guatemala: ECU 308.000 for a project to collect and make available the case law of the Constitutional Court, and  to train officials and members of civil society.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Honduras: ECU 326.000 to support the National Human Rights Commission with a view to promoting such rights in the Departments of Comayagua and Olancho. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Honduras: ECU 131.000 for an education programme dealing with civic and electoral issues and the rights of children. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Mexico: ECU 20.000 to support an initial Latin-American colloquium on the subject of the Ombudsman (in the face of the objectives and challenges of the region). </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Nicaragua: ECU 285.000 to support the social rehabilitation of minors in custody. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Panama: ECU 125.000 for a training action in the field of the defence of human rights. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Panama: ECU 250.000 to support a communication campaign designed to strengthen the image of the 'people's ombudsman'. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Venezuela: ECU 160.000 to strengthen the institution of Justices of the Peace in the country's municipalities.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Venezuela: ECU 100.000 ECU for a training and promotion action in the field of human rights and the strengthening of civil society. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">EUROPEAN</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">DEVELOPMENT FUND</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Following, where required, favourable opinions from the EDF Committee, the Commission has decided to provide grants and special loans from the 5th, 6th and 7th EDFs to finance the following operations (grants unless otherwise stated). Major projects and programmes are highlighted.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Economic and social infrastructure</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Cameroon: ECU 7.3 million for a programme aimed at protecting the urban boundary of the city of Kousseri from the encroachments of the Logone river, to improve sanitation and for the upgrading of an urban access route towards Chad. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Ghana: ECU 54 million for a transport infrastructure programme aimed at facilitating the social and economic development of the people living in the recisions in question (Western region, Brong Afaho, the Ashanti region). </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Ghana: ECU 3.8 million for a human resource development programme designed to achieve better planning, management and implementation of development projects. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Kenya: ECU 1.9 million for a project to support the development of tourism. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Mozambique: ECU 385 000 to extend the water supply system in the town of Mantola </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Chad: ECU 13.5 million to upgrade the Ere-Kelo road </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Trade promotion/ structural adjustment</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Benin-Cameroon C&ocirc;te-d'lvoire-GhanaGuinea-Togo: ECU 1.99 million for a regional programme of trade activities and training with a view to relaunching the pineapple business in West and Central Africa. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Burkina Faso: ECU 180 000 for the construction of an 'export and creativity' pavilion at the Salon international de l'artisanat in Ouagadougou. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Papua-New Guinea: ECU 5.3 million for the fourth structural adjustment support programme. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Agriculture</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Madagascar: ECU 1.9 million for a rice irrigation project. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Enterpris</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Botswana: ECU 33.7 million from the Sysmin fund, to support the work of the BCL, Tati and FEB mining companies in the SelebiPhikwe region. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Health</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Dominican Republic: ECU 1.3 million to support the STD-HIV-AIDS prevention programme. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Education</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Madagascar: ECU 1.9 million for a decentralised training project in favour of regional tourism operators. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Tuvalu: ECU 300 000 for the rehabilitation of primary schools on the islands of Nukutetau and Nanumea. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Environment</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Central Africa (Cameroon-Central African Republic-Congo-GabonEquatorial Guinea): ECU 16 million for phase 2 of the ECOFAC project (Conservation and rational utilisation of forest ecosystems in Central Africa). </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Institutional support</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Malawi: ECU 1 million towards a study aimed at allowing the government to implement its land reform policy. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Eritrea: ECU 4.5 million for a study aimed at allowing the government to undertake proper planning in the area of water resources and irrigation. </P>
+<P ALIGN="JUSTIFY">Miscellaneous</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Pacific region: ECU 4.9 million for a project designed to improve the efficiency and security at certain airports. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">HUMANITARIAN AID</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">ACP countries</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Mali: ECU 1 million towards the reintegration of some 200 000 Malians who fled to Algeria and Mauritania during the rebellions of the 1980s. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Mozambique: ECU 317 000 for victims of the severe floods that struck the centre and south of the country recently. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Nigeria: ECU 850 000 to help fight the meningitis epidemic affecting seven provinces of the country. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Sierra Leone: ECU 700 000 in urgent food and medical assistance for some 250 000 refugees who fled to the areas around the towns of Bo and Kemena following the fighting. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Chad: ECU 200 000 to help fight the meningitis epidemic. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Zaire: ECU 145 000 to help victims of the cholera epidemic and to assist in preventing its further spread (following the course of the Zaire river). </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Non-ACP countries</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Colombia: ECU 60 000 to help fight cholera in the municipality of Silvia, where some 40 000 are under threat due to a lack of drinking water and deficiencies in basic hygiene. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Guatemala: ECU 1.52 million to provide food aid and basic essentials to returnees from other parts of the country, and from Mexico, following years of civil war. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Armenia/Azerbaijan: ECU 11.57 million (ECU 4.07m for Armenia and ECU 7.5m for Azerbaijan), for food and medical assistance, targeted at the most vulnerable sections of the population, and for the provision of agricultural materials with a view to reducing progressively the dependence of the refugees, who are victims of the conflict in Nagomo-Karabakh.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Caucasus-Georgia-Tadilkistan: ECU 3.2 million for food aid to be targeted at the most vulnerable sections of the population. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Georgia: ECU 7.43 million for victims of the internal conflict in this country where the loss of the Russian market has seriously undermined the rural economy. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Lebanon: ECU 600 000 for displaced people, to allow for the purchase of basic essentials including food, medicines, shelter and blankets. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Afghanistan: ECU 600 000 for health infrastructures in the refugee camps   around Jalalabad, and for medical aid to refugees in the town of Herat. Indonesia: ECU 120 000 for toots and materials to construct shelters for the victims of the earthquake that struck in February. China (Tibetan nomads): ECU 550 000 for food aid, medicines and blankets for some 72 000 people living in the mountainous regions who have been badly hit by severe weather and a food shortage.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">FOOD AID </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&lt;&lt;I&gt;&gt; p95a.png The Commission has recently taken decisions to finance food aid as set out in the chart which follows: </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<B><P ALIGN="CENTER">&lt;&lt;TOC2&gt;&gt; Aknowlegments</P>
+</B><P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The Courier</P>
+<P ALIGN="JUSTIFY">Africa - Caribbean - Pacific - European Union</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Address: Postal address (mail only) 'The ACP-KU Courier' Commission of the European Communities 200, rue de la Loi 1049 Brussels Belgium</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The Courier office address (visitors) First floor Astrid Building 1, rue de Geneve Evere - Brussels Belgium</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Publisher Steffen Smide commission of the European Communities 200, rue de la Loi 1049 - BRUSSELS (Belgium) Tel. 00-32-2-299 11 11 </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Director of Publications</P>
+<P ALIGN="JUSTIFY">Dominique David</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Editor</P>
+<P ALIGN="JUSTIFY">Simon Homer</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Assistant editors</P>
+<P ALIGN="JUSTIFY">Augustin Oyowe</P>
+<P ALIGN="JUSTIFY">Jeanne Remade</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Associate assistant  editor</P>
+<P ALIGN="JUSTIFY">Hegel Goutier</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Joumalist:</P>
+<P ALIGN="JUSTIFY">Debra Percival</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Production Manager:</P>
+<P ALIGN="JUSTIFY">Dorothy Morrissey</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Secretariat:</P>
+<P ALIGN="JUSTIFY">Carmela Peters</P>
+<P ALIGN="JUSTIFY">Fax: 299-30~02</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Circulation:</P>
+<P ALIGN="JUSTIFY">Margriet Mahy-van der Werf</P></FONT></BODY>
+</HTML>
Index: /main/tags/2.25/gsdl/collect/demo/import/ecourier/ec159e/ec159e.htm
===================================================================
--- /main/tags/2.25/gsdl/collect/demo/import/ecourier/ec159e/ec159e.htm	(revision 21064)
+++ /main/tags/2.25/gsdl/collect/demo/import/ecourier/ec159e/ec159e.htm	(revision 21064)
@@ -0,0 +1,2428 @@
+<HTML>
+<HEAD>
+<META HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=windows-1252">
+<META NAME="Generator" CONTENT="Microsoft Word 97">
+<TITLE>&lt;&lt;TOC1&gt;&gt; The Courier - N°159 - Sept- Oct 1996 Dossier Investing in People Country Reports: Mali ; Western Samoa</TITLE>
+</HEAD>
+<BODY>
+
+<B><FONT FACE="Arial" SIZE=2><P>&lt;&lt;TOC1&gt;&gt; The Courier - N°159 - Sept- Oct 1996 Dossier Investing in People Country Reports: Mali ; Western Samoa</P>
+</B><P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">AFRICA-CARIBBEAN-PACIFIC - EUROPEAN-UNION</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">Country report</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Mali</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Mali, which used to be the centre of great appears hemmed in by its frontiers, colonisation having culminated in the break-up of the old 'French Sudan'. Following the marxist regime of Modibo Keita (the 'founder' of the nation) and the dictatorship of Mousse Traor&eacute;, Mali has discovered democracy. It is still one of the world's poorest countries but recent macro-economic trends are highly encouraging and there is a new dynamism. It seems that the ending of the Tuareg conflict has provoked a surge of optimism- even among ordinary citizens whose wallets have yet to feel the effects of an improving national economy.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Country report</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Western Samoa</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Pacific island nations have a reputation for idyllic scenery and rich cultural traditions. Western Samoa has both of these assets in abundance, but it also faces many development challenges. With a population of just 165 000, the country has a limited local market, and it is a very long way from potential overseas customers. It is also susceptible to destructive tropical storms. Despite these constraints, there have been some promising signs of economic progress in recent years.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Dossier</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Investing in people</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">To say that investing in people makes economic sense is to state the obvious. But to what extent are the implications of this statement fully understood in the developing countries, especially in sub-Saharan Africa, in these days of constantly shifting development theories? We look at this subject in our Dossier. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<B><P ALIGN="CENTER">&lt;&lt;TOC2&gt;&gt; Acnowledgements</P>
+</B><P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The Courier</P>
+<P ALIGN="JUSTIFY">Africa - Caribbean - Pacific - European Union</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Address: Postal address (mail only) </P>
+<P ALIGN="JUSTIFY">'The ACP-EU Courier' Commission of the European Communities 200, rue de la Loi </P>
+<P ALIGN="JUSTIFY">1049 Brussels </P>
+<P ALIGN="JUSTIFY">Belgium </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The Courier office address (visitors) </P>
+<P ALIGN="JUSTIFY">First floor Astrid Building 1, rue de Gen&egrave;ve </P>
+<P ALIGN="JUSTIFY">Evere - Brussels </P>
+<P ALIGN="JUSTIFY">Belgium</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Publisher Steffen Smidt </P>
+<P ALIGN="JUSTIFY">Commission of the European communities </P>
+<P ALIGN="JUSTIFY">200, rue de la Loi </P>
+<P ALIGN="JUSTIFY">1049 - BRUSSELS </P>
+<P ALIGN="JUSTIFY">(Belgium) </P>
+<P ALIGN="JUSTIFY">Tel. 00-32-2-299 11 11 </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Director of Publications</P>
+<P ALIGN="JUSTIFY">Dominique David</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Editor</P>
+<P ALIGN="JUSTIFY">Simon Homer</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Assistant editors</P>
+<P ALIGN="JUSTIFY">Augustin Oyowe</P>
+<P ALIGN="JUSTIFY">Jeanne Remacle</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Associate assistant editor</P>
+<P ALIGN="JUSTIFY">H&eacute;gel Goutier</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Journalist:</P>
+<P ALIGN="JUSTIFY">Debra Percival</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Production Manager:</P>
+<P ALIGN="JUSTIFY">Dorothy Morrissey</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Secretariat:</P>
+<P ALIGN="JUSTIFY">Carmela Peters</P>
+<P ALIGN="JUSTIFY">Fax: 299-30-02</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Circulation:</P>
+<P ALIGN="JUSTIFY">Margriet Mahy-van der Werf</P>
+<P ALIGN="JUSTIFY">(299-30-12)</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Cower page:</P>
+<P ALIGN="JUSTIFY">Cover photo by</P>
+<P ALIGN="JUSTIFY">John and Penny Hubley</P>
+<P ALIGN="JUSTIFY"></P>
+<B><P ALIGN="CENTER">&lt;&lt;TOC2&gt;&gt; Meeting points</P>
+</B><P ALIGN="JUSTIFY"></P>
+<B><P>&lt;&lt;TOC3&gt;&gt; Ieremiah Tabai, Secretary General of the Forum Secretariat</P>
+</B><P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">South Pacific Forum: 'responding to the needs of the Member States'</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Although an accountant by training, leremiah Tabai has never had the opportunity to practise his profession, having pursued a successful political career instead since 1974. In 1978, he was annointed head of government in Kiribati and a year later he became his country's first President, when it achieved independence. He held this position for 12 years. In 1991, he took up the top post in one of the South Pacific's key regional bodies, the Forum Secretariat, which is based in Suva, Fiji. During a recent Courier visit to the region, we had the opportunity to interview the Secretary General. Our discussion was wide-ranging, covering issues such as the Forum Secretariat's role, the economic challenges facing the South Pacific, and the development of regional links with Australia, New Zealand and Asia. We began by asking Mr Tabai to outline the objectives of the organisation that he heads.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">- Like many other organisations in the region, the Forum was established essentially to try and assist the development process of the Member States. At the time it was set up, there was already an organisation in existence - the South Pacific Commission - which dates back to 1947. But there was a feeling that we needed an organisation that was not just restricted to economic issues; that could talk about other matters with a bearing on the development of the region.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">In the early years, when the organisation was called the South Pacific Bureau for Economic Cooperation (SPEC), the focus was heavily on trying to assist the trade and economic development of the member countries. Later, the name was changed to the Forum Secretariat and its role evolved.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">· In what way ?</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">-It has evolved in seeking to respond to the needs of the Member States. It started as a very small bureau essentially dealing, as I said, with trade and economic issues. Subsequently, it moved into areas like energy, civil aviation, maritime questions and telecommunications. It also became more involved in political issues. We have a division which deals specifically with these.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">1995 was a very important year in the history of the Forum. We had a review of the organisation, looking at ways we could perform better and taking account of the changes in the region and the world at large. The fundamental recommendation in the report which came out of that review was that the Secretariat should focus mainly in future on poliy-related issues, in the areas of trade and investment, economics and international relations. This report was discussed and endorsed at the last Forum in Madang, Papua New Guinea. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">· Does this mean, in practice, a withdrawal from project activity ?</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">-It may. The essential focus of the work will be providing policy advice to countries. Having said this, there should still be some project work. For instance, we will be engaged in a programme to provide assistance for importers, particularly in the small island countries. The idea is to help people- who may not be familiar with all the legal requirements-to learn how to get into the business. This will involve running a workshop and inviting people with expertise to pass on their knowledge. So even though the focus will be on policy issues, there will still be room for project-type activities where needed -so long as these fit in with the policy priorities. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">· You mentioned the fact that the Forum now deals with political questions. Although the issue may now be seen as 'water under the bridge' to what extent was the Forum Secretariat involved in the diplomatic disagreement over French nuclear testing ?</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">- We were very much involved from the beginning. In 1991, when the French testing was not underground but atmospheric, the region, at a Forum meeting, came out strongly in opposition to the tests. Right up to our last meeting in Madang, the subject was always a major item on the agenda, and we left France in no doubt as to the resolve of our region.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">When the new President took the decision to resume testing after a gap of several years, I was in the group from the South Pacific that went to France to express our views to French ministers, face-to-face. Our team was led by the then Australian Foreign Minister, Gareth Evans, who was President of the Forum. And when the tests began again, the Chairman took a decision suspending the dialogue and partner status of France with the Forum. So, as you see, we have been heavily involved in the issue.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">· What resources does the Forum have at its disposal and where does the money come from ?</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">- An important source of funds is our members' contributions. These tend to be used to cover the operational costs of the organisation. Then of course, there are the funds made available by our donors. The main ones are obviously Australia and New Zealand but there are many other countries and international organisations who provide assistance. The EU, of course, is an important partner. There was also a private donor who funded our conference centre.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">· How many people are employed in the Secretariat ?</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">-Around 80, all based here in Suva. Most of these are support staff.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">· What is the current state of relations between the Forum Secretariat and the main donors ?</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">-I would say our relations are good. We have an extensive mechanism for consultation with the donors. Every two years, we invite them here for a dialogue. We talk about the key issues and discuss ways in which they can assist us. There is also usually a dialogue associated with the Forum (ministerial) meetings. In September this year, after the Forum meeting, we will have more discussions with our main partners such as the EU, Canada, France, Japan and the UK. I should mention too the close links we have with international organisations like the Asian Development Bank, the World Bank and the IMF.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">I think it is fair to say that the Forum Secretariat is seen as a particularly important organisation in the region. That is why donors are quite keen to be seen assisting us in what we do.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">· What are the key development issues facing the South Pacific nations ?</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">- Development is quite a difficult process for our region. There are various international reports (particularly from the World Bank) - that describe how we have fared over the last few years. If you compare our performance with the Caribbean countries, for example, you find that we have not done nearly so well.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">We face a number of problems. First, there is the fact that we are so small. Small communities find it much more difficult than large ones to achieve development. You need to have the market and the critical mass to do all the things that are needed and we lack these. A second, related point is that our countries are very isolated from the rest of the world. It is true that here in Fiji, there are quite good connections, but if you go to Tuvalu, Kiribati or Niue, you will soon discover how difficult it is to get out. And if you are so isolated in terms of communication, how can you hope to increase your exports ? How can you airfreight your fish to Japan when there is no aircraft available-or the one that is available is not fast enough to ensure that the product is still fresh when it arrives?</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">On this question, one of the things we are increasingly realising is the need to do more in terms of human resource development. We all recognise that, without an educated population and workforce, it is very hard to achieve the development that we are aiming for. To be fair, if you compare the literacy rates here with those of many other countries, say in Africa, they are not at all bad. Our literacy levels are quite high. But I think we have a long way to go in acquiring problem-solving skills of the type needed to compete internationally. We are now talking with the EU about how we can utilise funding from the second protocol of Lom&eacute; IV. And I suspect that human resource development will remain high on the agenda.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">· Is that view shared by the European side ?</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">-I think so. l have a feeling that they will support it because it is so obvious. If you develop human skills, you are better placed when it comes to problem-solving.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Going back to the key development issues, another point is the lack of natural resources. This is less of a difficulty for countries like Fiji or Papua New Guinea, but it certainly affects the small island states. It hardly needs saying that if you don't have the resources in the first place, it is much harder to develop.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Finally, I think there is a question of how the Pacific region can get a better return on the resources it does have. This theme of 'managing our resources' was discussed by the Forum in Brisbane two years ago. Fisheries is probably the most important area here. The question is how we can earn more from this than we are currently doing- and there is no easy answer. Likewise in the forestry sector. We have to ensure that logging is done on a sustainable basis. But we must also recognise that leaders of the Pacific nations are under pressure. On the one hand, they are trying to take a lona-term view. but they are also striving to tackle the immediate problems. In an ideal world, our region would obtain a far better return on our resources, and that is something that we have to work on.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Having said all this, I don't think one should be too pessimistic. This region is still a very good place to live in. That is clearly reflected in the number of visitors we get. The 'South Seas' still have a special connotation that draws people here.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">· You effectively have two 'genera/' regional organisations, with overlapping memberships, covering the South Pacific -the Forum, and the South Pacifc Commission (SPC). Do you think there is room for bath ? Do you complement each other or is there a rivalry ?</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">-We have more than two regional organisations. We also have SPREP (South Pacifc Regional Environment Programme), the FFA (Forum Fisheries Agency)....</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">· Yes, but these are specialist bodies with distinct sectoral responsibilities.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">-Yes, that's true. In answer to your question, my view is that we have no problem with things as they stand. I was very involved in the debate some years back on the question of what we called an SRO - a single regional organisation. There was a strong push to try and achieve an SRO. The subject was debated for a few years and, in the end, it was possible to resolve the question.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">· You mean it was resolved by the idea being abandoned ?</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">-I suppose it depends on the way you look at it. The outcome was a decision to leave the regional organisations as they are but with the establishment of a mechanism to ensure they work together more effectively. This mechanism is called SPOCC-the South Pacific Organisations Coordinating Committee. It is a meeting of heads of regional organisations which happens at least once a year. We talk about the issues that are common to our mandate and work out ways of doing things better. SPOCC has been operating for six or seven years now and I think it works fairly well. There is, after all, no conflict in our underlying objectives. So my answer here is no, I don't see any problem. I don't see any rivalry between us. It is a question of seeing how we can work together to achieve the goals that we share.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">· In the European Union, the fundamental goal, set out in the Treaty, is to move towards 'ever-closer union' We have been doing this in fits and starts over the past 35 years. Do you see the Forum perhaps taking on a similar role here-as the focus for economic, and perhaps ultimately, political integration in the South Pacifc ?</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">- I think it is too early to speculate. We already have a number of sub-groups in the region like the MSG, the Melanesian Spearhead Group, whose members are the Solomon Islands, Papua New Guinea, Vanuatu and Fiji (admitted last year). Further north, we have the Micronesian grouping which brings together Nauru, Tuvalu, the Marshall Islands and Kiribati. These groups meet outside the Forum framework and they essentially have a common aim which is to work more closely together. I think they feel it is easier to do it at this level because they are closer to each other and have more in common.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">As for the Forum Secretariat, you can never tell what may come in the future. On balance, however, I think at the moment that integration is a long way off. Having said this, you do sometimes hear people putting the idea forward. There is, for example, something called the CER system, which stands for 'closer economic relations' between Australia and New Zealand. There have been suggestions that it might be possible to enlarge this grouping.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Looking at closer economic cooperation, and the general dismantling of trade barriers, we also need to recognise the growing importance of APEC (Asia-Pacific Economic Cooperation) for the region. We are trying strengthen our links with the APEC countries and in October, we will be establishing a trade office in Japan.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">· You mean a Forum Secretariat office ? </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">-Yes, in Tokyo. We are also talking with the Chinese and will probably end up with an office in Beijing. This is all part of our attempt to integrate ourselves with the Asean region. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Interview by Simon Homer</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Mission statement of the Forum Secretariat</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The mission of the Forum Secretariat is to enhance the economic and social well being of the people of the South Pacific, in support of the efforts of the national governments. The Secretariat has particular responsibility to facilitate, develop and maintain cooperation and consultation between member governments. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The Secretariat must pursue its mission in accordance with the directives of the Forum and within its mandated areas of operation. it undertakes political and economic activities, regional in nature and complementary to the activities of the member governments. Its role requires it to act as the secretariat to the Forum and to disseminate the Forum's views, to coordinate activities with other regional institutions in particular through the SPOCC process, and to represent the Forum's interests intemationally, as required. </P>
+<P ALIGN="JUSTIFY"></P>
+<B><P ALIGN="CENTER">&lt;&lt;TOC2&gt;&gt; ACP</P>
+</B><P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Investment symposium</P>
+<P ALIGN="JUSTIFY"></P>
+<B><P>&lt;&lt;TOC3&gt;&gt; A success story for African mining</P>
+</B><P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The MIGA (Multilateral Investment Guarantee Agency) symposium was held in Montreal from 22-24 May. It brought together some 40 African mining ministers, most of the important donor agencies and representatives of around 25 mining companies. MIGA, which is a specialised agency of the World Bank, promotes the flow of private investment to developing countries. It provides insurance against political risks and assists member countries in attracting foreign investment.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The purpose of the symposium was to attract investors from all over the world in order to exploit the rich mining possibilities offered by many African states. Several of the countries that attended went to considerable effort to present themselves well, and it was evident that some are quickly learning what it takes to attract foreign investors.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The climate for mining investment in most African states has improved tremendously over the last two to three years. Most countries have introduced new mining codes, clearly defining the rights and obligations of foreign investors. State-owned companies are also being privatised, taxation has been made more reasonable and institutions in the mining sector, such as geological surveys, are becoming more efficient.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">All this has led to a big increase in exploration for new deposits and a substantial increase in investment. At present, the activity is particularly heavy in West Africa, where many countries have very good gold potential. The European Community is contributing to this development in several ways. The biggest success so far has been the exploration campaign in Mali, funded under that country's Lom&eacute; National Indicative Programme (NIP), which led to the discovery of the Sadiola gold deposit. A world-class gold mine will be built here, bringing substantial benefits to the country.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The World Bank has also supported many African countries in their efforts to reform the legal and administrative framework for the mining industry. An important element, however, in attracting mining companies is the availability of good geological data. This is a very expensive activity, which does not bring immediate returns, if at all. So it is not appropriate to finance this through bank loans. The NlPs and SYSMIN Fund, on the other hand, are instruments that are well-suited to this kind of work. The Community has already financed a series of airborne geophysical surveys in Botswana and Namibia -to mention just two examples-and a new Sysmin project is currently being prepared for Burkina Faso.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The Commission Unit responsible for Mining Cooperation and Sysmin (VIIIl.B.5) was represented at the symposium. Its main purpose for being there was to present the functioning of Sysmin and the Community's cooperation in the field of mining to ACP ministers, mining companies and other donor agencies.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Current state of the mining sector</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The mining sector is currently very active. Exploration in West Africa doubled between 1993 and 1995 and new mines are being opened all the time. A lot of this new activity is to be found in the gold sector. This is mainly due to the development of cheaper production methods combined with a much more positive investment climate in many African countries. A gold mine takes less time to reach the production stage than, for example, a copper mine, with the former being far less dependent on good infrastructure. Outside the gold sector, activity is much more subdued. While base-metal prices are at a reasonable level, the pay-back period is much longer and the lack of suitable infrastructure kills many projects.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">For many countries, mining is a key area in the growth of the private sector. State-ownad mines are being privatised and the new mines that are being opened have little or no state participation. Foreign investors are bringing in the most up-to-date mining technologies and business methods, and they are faced with the need to train local people in technical and business skills. Supporting the mining sector is clearly an efficient way of supporting private sector development.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">SYSMIN's future role</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Given that most metals are currently fetching quite high prices, it is probable that relatively few ACP countries will be eligible for SYSMIN assistance over the next two to three years. The viability of most existing mines is not thought to be under threat and they should continue to be profitable. Thus, countries that are heavily dependent on mining should not experience severe losses in export income, which in turn means that relatively few SYSMIN requests are expected during the period of Lom&eacute; IV's second financial protocol. At the same time, the financial allocation for SYSMIN has been increased from ECU 48Om to ECU 575m.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">When trying to attract new mining investors, it is essential for a country to have good geological information. Private companies are normally unwilling to undertake much general prospect ion, such as airborne geophysical surveys, because it is very expensive and, if they do, it is usually limited to very small areas.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">At present, companies are tending to restrict their activities to areas for which general information is already available. These points were raised by several of the mining companies that attended the symposium.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">But the present mining boom is not going to last for ever. Metal prices are volatile and, with the next downturn in the business cycle, a decline in metal prices will surely follow. So it is essential to prepare the basis for future mining activities by collecting general data. Given that a significant part of the SYSMIN allocation may remain unused because of a lack of requests, it would be worthwhile to consider whether a part could be reallocated to prepare general geological data for mining activities in the next century. </P>
+<P ALIGN="JUSTIFY">F. B.-H.</P>
+<P ALIGN="JUSTIFY"></P>
+<B><P>&lt;&lt;TOC3&gt;&gt; Joint Assembly to consider climate problem </P>
+</B><P ALIGN="JUSTIFY">by Hans van de Veen</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Can the EU-ACP relationship be used to strengthen the dialogue between Europe and the main victims of climate change ? And can the Lom&eacute; Convention be one of the tools to promote climate protection measures, as well as the implementation of the Climate</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Treaty? These questions will be considered in depth at a hearing on climate derange scheduled for the next ACP-EU Joint Assembly, to be held in the last week of September 1996.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Periods of heavy rain have always been part of normal life in Fiji. But the latest rains were different, says counsellor Taina Tudau of the Fiji Embassy in Brussels. 'They were much more extreme than what we were used to, and caused heavy damage. Normally it took several days of heavy rain before the floods came up. This time, the water flooded the islands almost immediately the rain began to fall.' Mrs Tudau sees two main causes for the recent flooding. First, there is heavy deforestation on the islands, causing widespread erosion. But she is sure there was another reason for the recent damage: 'In the Pacific we know the local climate is changing. We see that the sea is rising. We are experiencing more extreme weather events. There can be no doubt that global warming is already going on.'</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Fiji is a prominent member of the Alliance of Small Island States (Aosis), the group of 36 nations which feel particularly threatened by global warming. At the first Conference of Parties to the UN Framework Convention on Climate Change, held in Berlin in March 1995, Aosis called for industrialised nations to reduce their C02 emissions by 20% by 2005 (based on 1990 levels). At the end of the conference, the 150 national delegations agreed to begin negotiations on targets for industrialised nations to cut emissions in the early years of the next century.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">So intentions may be good, but in practice not much has been done yet. The EU, for its part, risks losing credibility if firm action is not taken soon. According to a recent Commission White Paper on energy policy, the use of energy within the Union will increase by 1% a year up to 2020. Failing 'any strong policy interventions', the paper says, emissions of carbon dioxide are likely to show a 'substantial increase' during this period. Says Fiji-counsellor Tudau: 'As small island states we know what's at stake, but there seems to be no feeling of urgency in the rest of the world. We really wonder how long it will take before there is a definite move towards reduction of greenhouse gases.'</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">EU-ACP cooperation</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">At the Berlin conference, the ACP countries-led by Aosis but with support from most of the African states -took a constructive and moderate position in the G77. The position adopted by the EU could also be described as moderate, certainly compared to that of other OECD countries. Several observers have pointed to the fact that these two moderate approaches by important blocks within the Climate Convention negotiations offer possibilities for some form of cooperation.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">'No doubt the EU represents the most progressive group of countries</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">within the OECD, although its position is far from sufficient', says Sible Schone, a representative of the World Wide Fund for Nature. 'Besides that, the EU has a special relationship with a large group of developing countries. Quite obviously it will be significant to get a dialogue started between the EU and the ACPs on the subject of climate change.' Currently, there is no such dialogue. 'At the moment we are not in a dialogue with ACP countries on climate change', says Bertil Heerink of the European Commission's Environment Directorate-General who is a member of the EU delegation to the climate negotiations. 'I'm convinced this will happen some day, but first we have to agree on our own goals and measures. I am sure developing countries want us to give priority to this too.'</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The special ACP subcommittee to deal with tropical timber, the environment and fisheries, formed after the signing of the revised Lom&eacute; IV, only recently started its work. With respect to the global warming issue, it is waiting for the Joint Assembly hearing, according to ambassador Michael King of Barbados, who is a committee member. 'The specific interests of the different regions have to be articulated there, and then some kind of sustained effort has to be initiated.'</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The unit for Sustainable Development and Natural Resources in the Development Directorate-General of the Commission (DG VIII) not at present dealing with the subject of climate change. Says Head of Unit, Amos Tincani: 'We have worked on biodiversity and desertification, and we want to do more on the specific environmental problems of small island states. But we have done nothing similar on climate change. This is partly because it is so much a global problem, but the main reason is we simply lack the people and the time to go into it.'</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Assembly hearing</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">At its meeting in Windhoek in March this year, the Joint Assembly adopted a resolution which had been proposed by representatives of 13 small island states. This urged the EU to take the lead in combating climate change and the adverse effects thereof. More specifically, the Commission is being asked to update its climate change strategy for the period post-2000 and to achieve significant reductions in emissions of greenhouse gases over the coming decade and thereafter. The resolution riches on to call for extra assistance to ACP countries in the Caribbean, Pacific and Indian Ocean to help them improve their disaster preparedness. The Commission is also urged to accelerate the transfer of appropriate technologies and practices, to enable ACP states to develop coastal zone management strategies and to rehabilitate and protect areas stricken by drought and desertification as well as by hurricanes and floods.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Two representatives of the European Parliament, Maartje van Putter (PES) and Peter Liege (EPP), have been active on the situation of the small island states and climate change for several years. According to Mrs Van Putten, the main effect of the coming Assembly hearing should be to put extra pressure on the Commission to take its responsibility seriously. 'Talking about climate change,' she says, 'one should never forget who is to blame and who, therefore, must take decisive action. A European tax on energy or carbon dioxide would be an important first step, but no more than that.'</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Besides influencing the Commission's energy policy, Mrs Van Putten hopes the Assembly hearing will raise public awareness on the climate problem in those ACP countries which are not in the 'small island' category. 'If you are talking about rising sea levels, the African states with low-lying coastal zones face the same problems as the small island countries,' she points out. 'And they also face the problem of desertification and declining food production.'</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Integrating the climate dimension</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">In a recent briefing paperto the Commission, the International Institute for Environment and Development (IIED) concluded that, hitherto, the aid community (including the EU) had not incorporated measures on global warming into their strategic thinking on sustainable development. 'Indeed, the possibility of climate change has been considered of minor importance in comparison to other environmental concerns.' This is hardly surprising, says the London-based institute, as the climate issue has only recently been placed on the international agenda. Moreover, the long-term threat of global warming raises some difficult questions regarding priorities in circumstances where resources are limited. In other words: who wants to spend scarce funds on problems the full effects of which will probably not be felt for another 25 to 50 years? The best way forward, suggests the IIED, is to tackle the apparent conflict between shortterm development priorities and longterm climate protection, by 'integrating the climate dimension' rather than considering climate change as an issue in isolation.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Technology transfer could be a central point, according to WWF's Sible Schone. 'Developing countries see technology transfer as a central theme in the Climate Convention, but the industrialised countries don't give enough weight to these There are a lot of paragraphs about technology transfer in the Convention as well as in Lom&eacute;. Now it's time to fill in these commitments.'</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Strangely, there are hardly any Lom&eacute; projects currently under way in the field of energy efficiency. It is strange because experts have pointed to the large potential in developing countries for cost-effective energy improvement and energy conservation. Improved management could save at least 25% of the energy now being consumed. Quick realisation of this potential would significantly contribute to alleviating environmental &agrave;nd development problems.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Henri Martin, energy specialist in DG VIII, agrees a lot more could be done in this field, but he points out: 'We are dependent on requests. If you look at the wording of the Convention, everything has already been said. There are chapters on energy and technology transfer. The problem is that we don't get enough signals back from the ACP countries that these items are a priority for them. I'm afraid sustainable energy or energy efficiency is not high on the agenda of most countries.' Taina Tudau disagrees strongly: 'Our experience is that the projects that could make a difference and contribute to sustainable development, protection of the environment and local sustainable energy production, are found to be too small. It is the donor that sets the conditions for the projects, not us, the small island states.'</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">New funding?</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Can the EU build a credible policy linking climate and development cooperation, without reserving extra money? Not surprisingly, there is disagreement on this question. In Brussels, officials are inclined to point to possibilities that are already there but not being used. Amos Tincani, for instance, observes that 'there are budgets for this kind of problem under Lom&eacute;. We have provisions specially targeted for the islands'. He mentions regional budgets in particular: 'A lot can be started at the regional level which then trickles down to the national level. But after producing fine resolutions, everybody seems to forget the work still needs to be done. The idea is: 'oh yes, we can do it, provided it is with fresh money'. We say: a lot more can be done with existing budgets and instruments.'</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Maartje van Putten, from the Parliament, says the discussion should not be 'dominated by southern demands for additional money'. She agrees that ACP countries could make better use of existing funds and possibilities, such as, for instance, the funds for intra ACP cooperation. But counsellor Tudau points to the fact that the Climate Convention urges industrialised countries to support the response of developing countries to climate problems through 'new and additional' money, besides the transfer of environmentally sound technologies and expertise.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">There is a financial mechanism built into the Climate Convention, which is administered by the Global Environmental Facility, to cover additional costs of appropriate measures. But much more could be done by the aid community, including the EU, according to Mrs Tudau. 'Most European countries will not succeed in stabilising, let alone reducing, their emissions. In reaction to this, as ACP countries we should say: European Union, you are not fulfilling your obligations. You have to try harder and you have to set extra money aside to compensate for the damage this is doing to us. </P>
+<P ALIGN="JUSTIFY">H.v.d.V.</P>
+<P ALIGN="JUSTIFY"></P>
+<B><P>&lt;&lt;TOC3&gt;&gt; ACP-EU Council in Apia</P>
+</B><P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">There were no real surprises or unexpected developments at the ACP-EU Council meeting which took place in Apia, Western Samoa, on 27 and 28 June, 1996. The session was preceded by an ACP Council, which saw the adoption of three important decisions. The first of these was the appointment of a new ACP Secretary-6eneral, Mr Ng'andu P. Magande of Zambia. The post had been vacant for some time, following deadlock within the ACP Group over a successor to Berhane Ghebray (see issue 155 of The Courier, p.6). The ministers also agreed to hold a summit of ACP heads of government in Libreville, Gabon, during the second half of 1997. This meeting is expected to focus heavily on the future of ACPEU relations once the present Lom&eacute; Convention has expired.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">In the substantive area, the ACP Council adopted a resolution deploring the suspension of cooperation with Equatorial Guinea. Ministers urged the European Union to make use of the procedure in Article 366a of the revised Lom&eacute; Convention, and to set in train the consultation procedure envisaged in this provision.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">This issue was raised again by the ACP side at the subsequent ACP-EU Council. This meeting, which was presided over by Mrs Toya (Italian Under Secretary for Foreign Affairs) and Mr Syamujaye (Zambia's Trade Minister) had a relatively light agenda. There was a discussion about the Commission proposal for a directive on the use of vegetable fats, other than cocoa fat, in chocolate (see issue 158 of The Courier, p.35). Somalia also featured in the debate, with representatives agreeing on the need to find ways of allowing this country to benefit from Lom&eacute; Convention provisions. The civil conflict in Somalia, and the absence of an effective central administration have prevented the deployment of regular development aid for many years, although significant amounts of emergency assistance have been and are still being provided.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">In addition, the ACP-EU Council approved two reports drawn up by the development finance cooperation subcommittee and commodities sub-committee respectively. Representatives were able to reach a compromise on two outstanding points of contention in the resolution on development finance relating to tenders and the dissemination of the user's guide.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Note was taken of the number of countries that have so far lodged instruments of ratification for the revisad Lom&eacute; Convention (Mauritius agreement). At the time of the Apia meeting, only nine countries had ratified: seven on the ACP side (Barbados, Dominica, Equatorial Guinea, Jamaica, Malawi, Mauritius and Solomon Islands) and two EU Member States (Denmark and Sweden). Appeals were made for the contracting parties to speed up their ratification procedures so that the Eighth European Development Fund can come on stream as speedily as possible.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The next ACP-EU Council meeting will take place in Luxembourg on 24 and 25 April 1997.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The government of Western Samoa deserves a special mention for the warmth of their hospitality and the efficient way in which they organised the Council meeting. Delegates from all sides were keen to express their appreciation of the host country's efforts, which ensured the smooth running of the various meetings and gave the visitors a real taste of this Pacific country's unique culture. ed. S.H.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">New ACP Secretary-General</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Ng`andu Peter Magande, is no stranger to the challenge of development at the grassroots. The new Secretary-General of the ACP Group, who was born in 1947, began his working career as a provincial development officer, planning and supervising projects in the Southern Province of his native Zambia. He is an economics graduate of the University of Zambia and also holds a master's degree in agricultural economics from Makerere university, Uganda.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">From working in the field, he moved into government administration, rising to the position of Permanent Secretary-a post which he held in a number of ministries. Since the mid-1980s, he has had key jobs in a number of Zambian enterprises (including Managing Director of the Zambia National Commercial Bank) His most recent work has been on a project to develop private sector participation in agricultural input and produce marketing.</P>
+<P ALIGN="JUSTIFY"></P>
+<B><P>&lt;&lt;TOC3&gt;&gt; Kenya's economy in the 1990s</P>
+</B><P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">by Elisabeth Pape</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Kenya has enjoyed rare political stability since independence in 1963. It is one of the most famous holiday destinations in Africa, with abundant wildlife, fine beaches and stunning scenery. But despite having the most advanced economy in East Africa, it is still one of the world's poorest countries. Over 11 million Kenyans live below the poverty line. But better times may be ahead. The Government has embarked on an ambitious reform programme which promises to lay the foundations for strong growth.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The early 1990s marked the worst time in Kenyan history, in economic development terms. Real GDP growth dropped from 4.3% in 1990 to 2.1% in 1991 and was almost zero in 1992 and 1993. This poor performance was due to drought, structural rigidities, lack of monetary discipline, non-enforcement of banking regulations, and reduced donor assistance. While Kenya was used to receiving substantial foreign aid inflows, the present decade began with growing tensions between Government and donors. In the new post-Cold War atmosphere, the latter wanted to see political and economic reforms, and in November 1991 they decided to halt guick-disbursing aid.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Multi-party elections in December 1992 did not immediately restore relations with the donors, in particular as they were accompanied by a lack of fiscal and monetary discipline whose effects threatened economic ruin. Monetary expansion was fuelled, among other things, by discretionary exemptions to Banking Act provisions, which enabled over-borrowing by certain 'political' banks from the Central Bank. In early 1993, things came to a head. Foreign currency reserves were down to just a few weeks of imports, the banking system was on the verge of collapse, and consumer prices had shot up. Against this background, the Government went for a comprehensive, IMF-supported structural adjustment programme.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">A number of far-reaching reforms were implemented with unprecedented speed. Exchange restrictions were removed, import licensing was ended, import procedures were made easier and tariffs were reduced. The export license requirement was also lifted and price controls were abolished. In March 1993, the Central Bank (CBK) began to tighten monetary policy. By issuing large amounts of treasury bills, it soaked up most of the excess liquidity which had been injected the previous year. There was also stricter bank supervision and a number of weak financial institutions were closed.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Structural reforms</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The Government began structural reforms aimed at reducing its own role in the economy in favour of the private sector. The privatisation programme, begun in 1991, was accelerated. By the end of 1995, the authorities had divested more than half of the 211 non-strategic parastatals-though critics complained the process often lacked transparency. The Government also substantially reduced its fiscal deficit through, above all, an improved revenue policy. The deficit fell from 11.4% of GDP in 1992/93 to 2.5% in 1994/95. The number of civil servants was reduced, mainly through voluntary early retirement, so that, by the end of 1995, the service had been trimmed by more than 30 000 (10% of the payroll).</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">In 1995, the reform programme lost momentum as proponents of the old and the new systems locked horns. Vested interests stood in the way of more radical reforms. Temporary import bans on maize and sugar were reimposed, key parastatal reforms were delayed and expensive but economically dubious projects were approved outside normal budgetary procedures. These included an international airport in Eldoret, a presidential jet and an identity card project. These further delayed the resumption of balance of payments support by the Bretton Woods Institutions and contributed to the frustration of efforts to improve relations with donors.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The economic crisis peaked in early 1993 and the shilling was sharply devalued. The official rate went from about KSh 36 to the dollar at the end of 1992 to KSh 60 in April 1993. On the market, the currency was being traded at a premium of more than 30% and that continued until July-i.e. about two months after the removal of exchange restrictions. The market premium then started to decline and the two rates converged in mid-October when the shilling stood at 69 to the dollar.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The high interest rate on treasury bills under the liberalised foreign exchange regime was the main reason behind strong currency inflows which began in October 1993. Other factors, whose exact impact is difficult to gauge, included capital flight from neighbouring crisis-torn countries, the international money laundering one normally finds in places with newly liberalised foreign exchange regimes, and a surplus in the current account position. The shilling then started to rise, despite the CBK's massive currency purchases which led to a build up of reserves to the equivalent of six months of imports. The appreciation continued up to October 1994: indeed, at one point, the shilling reached a high of 35 to the dollar.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">That was the turning point. Strong import demand, fuelled in particular by a surge in oil imports in the wake of petroleum market liberalisation, and an outflow of portfolio investments due to lower interest rates, weakened the currency. By mid-1995, after two sharp falls, it reached a rate of 56 to the dollar. Since then, it has been relatively stable.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Economic recovery</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Real GDP grew by 3% in 1994 and an estimated 5% in 1995. Good weather certainly helped, but the economy also benefited from the Government's reforms. Agriculture, the mainstay, grew by 2.8% in 1994 and by more than 5% in 1995. This compares with negative growth rates in 1992-93, when the sector was hard hit by bad weather. Elsewhere, the trends were more mixed. Many producers for the local market were affected by trade liberalisation and, in 1994, by the strong shilling. The former created a highly competitive environment almost overnight-after years of cosy protectionism. For cloth manufacturers, the liberalisation of imports of second-hand clothing further aggravated the problem. In 1994, the clothing sector's output dropped 35%. Tourism, the main foreign exchange earner, fared quite well in volume terms in 1994 despite the strong shilling. But while turnover may have gone up, it is likely that many operators did not earn enough extra to cover their increased local currency costs. In 1995, visitor arrivals fell by 20% to the lowest figure since 1988. In consequence, tourism earnings fell by a quarter.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">As intended, liberalisation led to higher trade volumes. In 1994, exports ( + 16%) rose by more than imports ( + 13%) in value terms, but the position was reversed in 1995 when the latter jumped by 35% while the former were 14% lower. One good sign was that the highest import growth was in industrial supplies and machinery (60% up) but the fact that the deficit almost doubled to reach record levels was obviously a cause for concern.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">A major revolution has also taken place in trade flows. In 1994, for the first time, Uganda overtook the UK as the biggest importer of Kenyan goods. In the same year, the value of Kenya's exports to African countries moved ahead of its combined exports to Europe and North America.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">During 1994, the Nairobi Stock Exchange proved to be one of the worid's best-performing stock markets, the value of shares rising by 80%.1995 was disappointing, however. Although foreigners were allowed to invest for the first time, the index nonetheless fell by 25%.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Fighting inflation has been the CBK's main objective since 1993 and a tight monetary policy has brought the problem under control. Inflation dropped from 46% in 1993 to 29% in 1994 and to below 2% in 1995. Recently, however, an upward trend has bean observed. This follows a money supply increase far in excess of the expansion of economic activity, and is mainly due to a substitution of treasury bills for borrowing from the Central Bank since the end of 1994. If inflation is to remain within the 5% target for 1996-which already seemed highly unlikely by the middle of the year - the trend needs to be speedily reversed.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Initially, the main way of mopping up excess liquidity was through the sale of treasury bills. When the sales began in March 1993, there was a huge liquidity overhang and high interest rates had to be offered to take money out of the market quickly. The rate earned on 90-day bills-which became the lead interest rate in the economy- rose from 17% to 80% between March and July 1993. It then declined steadily, reaching 18% at the end of 1994. This prompted an outflow of short-term capital, leading to currency depreciation and lower foreign reserves. Since mid 1995, treasury bill rates have been back above 20% and this seems to have stabilised the foreign exchange situation. It is generally believed that the high prevailing real interest rates are a major obstacle to investment and economic growth.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Interest on domestic debt is still a big item in the state budget, although, the situation is much improved, thanks to the reduction in the stock of treasury bills and lower interest rates. In fiscal year 1993/94, interest payments on domestic debt alone swallowed one third of total gavernnnent expenditure.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The agriculture sector employs 70% of the total labour force and generates more than a quarter of Kenya's GDP. Much of industry is linked to agricultural processing, and tea, coffee and horticultural products are Kenya's major foreign exchange earners after tourism. The marketing of key farm products is dominated by large parastatals and cooperatives which are often run like parastatals. Most marketing organisations have been hard hit by the liberalisation, which brought both inefficiency and corruption to light. Tea growers have complained about improprieties at the Kenya Tea Development Authority. Imported sugar flooded the local market, often without paying import duties, leaving the mills with huge stocks. This, in turn, created severe cash flow problems. Most sugar farmers have not been paid for months. Kenya Cooperative Creameries was not able to pay farmers for milk deliveries for up to half a year, and could only start servicing the arrears when the Government came to its rescue with KSh 800 million in January 1996.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Formidable challenges</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Kenya's labour force, around 12.5 million in 1996, is growing at more than 4% a year. This means that at least half a million people enter the job market annually. The challenge of absorbing the new workers is formidable. Studies show that any strategy to deal with this must be based on three pillars: smallholder agriculture (to absorb most of the growth in the rural labour force), continuing substantial job creation in the informal sector, and high real GDP growth (+8% per year is needed to ensure that the modem sector absorbs a significant number of workers).</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Informal sector employment has risen rapidly (up by 15-20% a year since 1991). By 1994, for the first time, there were more people working here than in the modern economy. The informal sector covers semi-organised and unregulated activities largely under taken by self-employed people or employers with just a few workers. Typically, they do not comply fully with tax, registration, and licensing rules, and this sometimes leads to conflict with the authorities. Workers are often paid below the minimum wage and have no social security. For many, the informal sector is, therefore, an 'employer' of last resort.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">It is estimated that almost 50% of rural people and 30% of urban residents live in absolute poverty- unable to meet their minimum requirements for food and essential non-food items. While the percentage has remained fairly stable in recent decades, the increase in the number of 'absolute' poor is alarming. So too is the extent of the poverty: the gap between these people's minimum needs and their actual disposable income has reportedly increased over the last ten years. The bulk of the poor live in the central and western parts of the country, which have the best agricultural potential, the rich soils having always attracted settlers. For decades there was enough land to go around, but demographic trends have finally started to take their toll. The size of landholding has declined continuously, in many cases reaching levels which are no longer capable of sustaining a family.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">There has been some progress in restructuring parastatals, but much remains to be done. The performance of key parastatals has been unsatisfactory by international standards and this has constrained growth. At Mombasa port, which is managed by the Kenya Ports Authority, handling charges are 50% higher than the global average, while container turnover is three times slower. Rail transport is unreliable, slow and more expensive than road haulage. The Kenya Power and Lighting Company has a shortage of generating capacity which means periodic power cuts. And intervention in the maize market by the National Cereals and Produce Board- at above-market prices-has prevented private sector involvement as well as placing a heavy burden on government finances. The Board has posted annual operating losses of between KSh 1.8bn and KSh 2.5bn each fiscal year since 1992/93.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Corruption, misuse of funds, and the politics of patronage remain endemic and these clearly distort development. Elimination of corruption has been an aim of most reform programmes but it seems that the effect so far has only been to change its form. Trade liberalisation has killed cash cows such as import and foreign exchange licences, and the commercialisation of parastatals has stopped them from doing deals with cronies which were profitable only for the latter. But other forms of non-acceptable wealth accumulation have emerged. In the early 1990s, alleged exports of gold and diamonds are thought to have resulted in a loss of KSh 7 billion of public funds. Land grabbing has also become widespread. This either involves land being sold to individuals or companies with well-established political connections at well below market prices, or the purchase of land by public institutions from the same individuals or companies at inflated prices.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">After delays because of political differences, cooperation between the three states of the former East African Community (Uganda, Tanzania and Kenya) was revived in early 1996. The EAC Secretariat, based in Arusha, is headed by a Kenyan, Francis Muthaura, a former ambassador in Brussels. For the three countries, the new cooperation aims at facilitating movements of people, capital and trade within the region, and harmonisation of external tariffs and investment regulations. Currencies will be fully convertible. This revived cooperation is expected to have a major growth impact. The Nairobi Stock Exchange is currently assisting Kampala and Dar es Salaam to set up their own exchanges. And the NSE Chairman, Jimnah Mbaru, sees the future not only in a cross-listing of companies in the three places, but in a regional stock exchange.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Policy framework</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The Policy Framework Paper (PFP) for 1996-1998, which was published in February ahead of the donors' Consultative Group (CG) Meeting, was highly applauded for both its content and form. The programme, which the media has dubbed 'the big push', promises finally to crack most of the 'hard nuts' of previous reform agendas, in particular in the parastatal and public sector. It also lays down measures aimed at supporting fiscal and monetary discipline through the next elections. These include cutting the budget deficit to 1.5 % of GDP by 1997/98, a tight monetary policy, and more autonomy for the Central Bank. In addition, it tackles some areas'that have emerged as avenues of corruption in recent years, such as the National Social Security Fund. While previous PFPs were highly confidential, this one was published, and the President appointed a Commission chaired by himself to oversee its implementation. These are seen as important steps in bridging the credibility gap which threatened to open up again in 1995. Donors are prepared to support the reform agenda and are eager to see it implemented speedily. Shortly after the positive outcome of the CG meeting, the IMF approved a three-year Enhanced Structural Adjustment Facility programme for a total of $220m. The World Bank is expected to follow suit with a credit of $85m.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">An increasing number of donors, however, have pointed to the link between democratic governance/ human rights issues on the one hand, and aid and investment flows on the other. If Kenya is to meet its ambitious targets and turn into a newly-industrialising country by 2010, foreign inflows will be vital. The point was succinctly put by a delegate to the CG meeting. 'If its (the Government's) economic successes are matched by a commitment to democracy and human rights, Kenya may yet prove that surging economic growth is not just for Asian tigers, but for African lions, too.' The period leading up to the next general election will be the acid test. </P>
+<P ALIGN="JUSTIFY">E.P. </P>
+<P ALIGN="JUSTIFY"></P>
+<B><P ALIGN="CENTER">&lt;&lt;TOC2&gt;&gt; Country report</P>
+</B><P ALIGN="JUSTIFY"></P>
+<B><P>&lt;&lt;TOC3&gt;&gt; Mali : An omnipresent sense of history</P>
+</B><P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Some countries have a strong folk memory. Despite its size, Mali appears hemmed in by its frontiers. For more than a thousand years, this state was a splendid empire, constantly spreading outward and reflecting the history of the African continent with its conquests and alliances, reversals of fortune and moments of glory. At its height, it extended from the Atlantic to the Sudanese border, from the south of Morocco to the north of Nigeria. Mali's history rests in the minds of its people rather than in any structures inherited from the past. This acts as an antidote to the 'amnesia' often brought on by colonisation, which has the effect of paralysing the future. Although poor, the country has a well-established sense of its place in the world.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">A racial melting pot</P>
+<P ALIGN="JUSTIFY">`</P>
+<P ALIGN="JUSTIFY">On the eve of colonisation, Mali was known es 'west Sudan'. In 1924, the territory then known as 'French Sudan' was split up and small portions of the Malian nation were incorporated into the seven states bordering it-a move certainly not calculated to have a cohesive effect on the remnants of the old empire. Mali has long been a melting pot of races, ethnic groups and cultures. They have learned to live together- intermingling, sometimes forming unexpected alliances, and occasionally fighting one another. The result today is a potpourri where true racial or ethnic confrontation is difficult to imagine. The interplay of history and the mixing of ethnic groups, families and individuals, has created what one intellectual de scribed to us as 'the anti Rwanda vaccine'. Historical mythology offers, perhaps, further evidence of the fusion of cultures in this country. As in ancient Greece or Rome, to take European examples, each ethnic group and each Malian empire, was 'backed' by a host of gods, spirits and totems. In this nebulous world, where dreams beget history and where vastly differing ethnic groups can trace themselves back to a common ancestor, the result was a multiplicity of interrelationships. Under various names, the python totem belongs to many different peoples, including the Peal, Ma/inke and Sarakolle. A study of the migrations of the peoples who make up Mali also reveals a great many relationships - for example, between the Dogon, who are black, and the Shongoi; who are more half-caste. They regard one another as cousins, originating from Aswan in Egypt.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Malians appear to share a genuine sense of belonging in keeping with their shared culture. The 'people' of Mali came into being long before the state of the same name. The guerilla war fought in recent years by the Tuaregs (this is the English plural, Tuareg already being the plural form of Targul) against the Malian army, is often viewed abroad as a struggle between whites (or Arabs) and blacks. But this is an illusion. Although the Tuaregs are probably the only 'white' minority in the country, they are an integral ingredient in the melting pot. They are also known as 'Kel-Tamasheq' - those who speak Tamashek, which was originally the language of their Bella slaves. Like all the country's ethnic groups, they have dominated and have in turn been dominated. They have forged alliances with one another, and, more commonly, have united against Arab or Berber invasions. The relative absence of bitterness overall is probably due to the fact that each of Mali's peoples has had its era of glory and imperial dominance.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Mali is lucky to have such knowledge of its history. For centuries, the most precise details have been collected by the griots. The same role has also been played by the many secret societies which have initiation periods lasting, in some cases, up to 50 years. They were, and sometimes still are, repositories for the secrets of history, magic, astrology and science, and also for the symbols of power-the religious objects and artefacts of the former emperors. There are written sources as well, something which is quite rare in Africa. These have been transcribed since the beginning of the millennium and, in recent decades, close collaboration between historians, griots and members of traditional societies has enabled a deeper knowledge to be gained of Mali's history.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">A rich empire</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Asselar Man, discovered near Timbuktu in the centre of Mali, was a contemporary of Cro Magnon Man. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Cave paintings from five thousand B.C. reveal similarities with those in Egypt and are probably the work of migrant populations from the east, who moved into Mali as the Sahara Desert expanded. Less reliable sources state that interbred populations of Jews and Egyptians under the command of an officer of the Pharaoh Dinga created the Soninke dynasty (originating from Aswan). These people probably laid the found ations of the first great Malian empire, that of Ouagadou. Other sources, equally unreliable, report that they were probably Judaeo-Syrians who arrived at the end of the third century A.D. and found a population already in place. What is more or less certain is that, during the first millennium, a Soninke dynasty was installed around the current frontier between Mauritania and Mali and that 40 princes ruled it in succession in the period prior to 750 A.D. Initially, these rulers were white but, with increasing intermarriage, their skins became darker and darker. To Arab chroniclers, Mali came to be known as Bafour or Bilad es-Soudan (the country of the blacks). At the beginning of the second millennium, the Ouagadou empire held sway over several kingdoms in the south, including the Nigerian delta and a number of Berber principalities. Documents dating from this period have replaced the name Ouagadou with that of Ghana, by analogy, perhaps, with the emperor's title. The empire was already very rich, the richest in the world according to an Arab chronicler who visited it in 970. A work by the writer A/ Bakri, which appeared a century later (1087) went into great detail about the empire's organisation-the system of matrilinear succession, the role of councils of dignitaries, and the capital, Koumbi (whose foundations were discovered in 1914 in southern Mauritania). This city was divided into two districts, one of these being the sacred, imperial city, home to the empire's python totem to which a young girl was sacrificed every year.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">A story of courage</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The killing of the snake totem is the most significant myths in the country's history. The hero of the story is Amadou Sefedokete whose love for his beautiful fiancee Sia (who was about to be offered in sacrifice), prompted him to descend into the monster's lair and confront it. By killing the totem, he broke the thread of countless generations before him, who had carried out the ritual sacrifice. He is still remembered for this magnificent action, based on love and a sense of nobility, and he remains a subject for artists of all types. His brave action still causes young lovers in Africa to shudder in admiration. However, this act of deicide brought about a reversal of fortunes. The monster's seven heads, which the young hero is said to have cut off one after the other, are reputed to have been scattered to the four comers of the earth, thereby dispersing the empire's riches and leaving it penniless. The true story is more prosaic. Ghana's wealth was eyed greedily by the Arabs and Berbers who had long traded with it. The empire's resistance in the face of Islam gave Moroccan religious fanatics a pretext for organising a jihad. It was invaded by an army of 30000 devotees supported by forces from some of the empire's black vassal states. The 'holy war' began in 1042 ending 34 years later with the occupation of Koumbi.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The occupation did not last long but was followed by internal clan wars which brought about the end of an era. Restoration came about at the end of the 72th century , in the small Sosso kingdom, south of Ouagadou (also set up by a small group of Sonink&eacute;). One of the minor kings called Soumangourou Diarasso dreamed of recreating Ghana's empire, and, in 1203, he succeeded in sacking the ancient capital of Koumbi in a move designed to establish his own dynasty. This was an important symbolic act and in the fierce war which followed, Soumangourou subjugated Mand&eacute;, a region which was overflowing with wealth. One of Africa's greatest heroes, Soundjata, rose up against him. He was supposedly the legitimate heir to the Mandingo throne, but was unable to walk, having been born an invalid of a deformed mother who had been married at the recommendation of the king's sorcerer. His young half-brother took his place on the throne and sent the paralysed prince into exile. At the age of 18, Soundjata decided to seize his own place in history and a 'giant' was thus bom. In 1235, his army fought that of the bloodthirsty Sosso monarch whom he himself is said to have cut down in an extraordinary battle. It was a fight which, according to the legends, saw the use of all types of weapon, including magic. Soundjata had forged a grand alliance in order to gain victory. Rather than reducing to vassalage the small kingdoms which had allied themselves with him, the new emperor decided to form them into a federation-although he wisely declared that from Niani (his capital), 'I shall see all'. His empire took the name of 'Mali' (the hippopotamus) on account of that animal's strength and mastery of bath water and land. For 20 years, the empire was to stretch as far as the Atlantic Ocean. Its structure, based on a number of warrior clans, craftsmen, freemen and marabous, is still characteristic of Mali and neighbouring countries today. The empire was rich in gold once again but also in terms of agricultural organisation with the development of cotton and groundout farming. Soundjata disappeared mysteriously in 1255, leaving a prosperous empire.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">'Conquest' of America?</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">In 1285, there was a struggle for succession between two princes and a third, Prince Sakoura (a freed slave), took advantage of the quarrel to take power for himself. Sakoura expanded the empire by subjugating the Timbuktu Tuaregs and the Gao Shongoi: After his short reign, a genuine heir of Soundjata, Aboubakar II, ascended the throne. He had his eye on conquests over the seas and, according to the story, he set sail westwards leading a fleet of 2000 vessels. He was never seen again. However, recent studies favour the hypothesis that he was not lost at sea as had always been supposed' but did, in fact, reach the Americas. A series of ineffective monarchs succeeded this 'conqueror of the impossible', who preceded Christopher Columbus by 200 years, leaving little real impression on history other than the records of their exuberant behaviour. One of them, for example, went on a pilgrimage to Mecca in 1324 with a reported retinue of 60 000 and distributed considerable amounts of gold to all the dignitaries he encountered in that holy place. These kings, however, are acknowledged as having preserved the empire's unity, guaranteeing order without repression and allowing wide religious, moral and sexual tolerance, even for married women. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The kingdom centred on Gao dates back to at least the first millennium but it was usually a vassal of the Ouagadou empire and of Mali. One of its kings, Sonny Ali Ber (known as Sonny the Great), came to the throne in 1464, profiting from the decay of the Mali empire. His reign was marked by a bitter struggle against the Ul&eacute;mas of Timbuktu who, over a period of four centuries following the Almoravid conquest, had converted a large portion of the empire to Islam. The circumstances of Sonny's disappearance are uncertain, but he is thought to have drowned in 1492, the year when a certain Genoese navigator was to achieve the ancient goal of 'discovering' the Malian empire.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Sonny Ber's successor did not last long in the face of Islamic expansion. The new Askia dynasty was installed to lead the Shongoi empire, and this expanded with the annexation of Dahomey and part of Nigeria. However, a small part of the former Mali empire never passed under their rule. The Askia dynasty blew hot and cold in terms of religious fervour. Tyrannical at first, it later took a softer line. Under the reign of one monarch, the Gao court based in the university city of Timbuktu became a place of exceptional refinement-only to slide once again into a state of intolerance. One of the Askias, having destroyed the last symbols of the former Mali empire, the city of Niani, set upon his former Moroccan allies. Another emperor, Askia Daoud (1549-1582), turned out to be a fine administrator. He developed agriculture and set up a genuine bank in Gaol War with Morocco continued throughout his reign and beyond. In 1584, imperial force defeated 20 000 Moroccan soldiers, winning a victory which might have been decisive had it not been for internal dissent. This weakened the Askia side and enabled Morocco, with a band of Spanish mercenaries, to take over the empire, following a battle in April 1591. Success was due, above all on this occasion, to the firearms deployed by the winning side. Such weapons were unknown to the 45 000 Malian cavalry and infantry who were engaged. It also turned out to be a Pyrrhic victory. The occupying troops sent the great scholars from Timbuktu University to Morocco, where their peers took up their cause. Moreover, the foreign soldiers were won over by the easy life in Mali-and one of the first results of their presence was a big increase in the half-caste population. In 1612, the troops rejected the Moroccan command: the occupation was at an end and the last few Moroccans were later expelled from Timbuktu by the Tuaregs.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Black religious proselytism and colonisation</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">To each dog his day. In the 17th century, the Bambaras set up an empire around Segou, but the debauched lifestyle of several of the sovereigns and disapproval of the part they played in the slave trade proved to be their downfall. Once again, the history of the country was to be shaped by a slave- Ngolo Diarra-who founded his dynasty in 1766. He was able to restore a degree of prestige to the kingdom, but his efforts were undermined after his death. As a reaction, a proselytising Black Islam then began to evolve.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Massina became a theocratic state around the beginning of the 19th century, in common with other kingdoms which appeared at the same time. One of their most famous rulers, the conqueror El Hadj Oumar, was defeated by the troops of the French General Faidherbe who forced him to give up West Senegal. The days of Malian independence were now numbered. The courage of his successor only delayed the progress of French colonisation, which finally prevailed at the end of the century.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Resistance fighters carried on the war from other points in the old empire, particularly from what is now Guinea. The country was dismantled by the colonial system and pacified, but the end of the Second World War and the return of African soldiers brought a renewed desire for independence. French Sudan became the rallying point for freedom fighters in the French colonies-the old dream of reunification was not dead and buried. In 1946, the Rassemblement Democratique Africain was set up, later to become the USRDA (Union soudanaise-Rassemblement democratique africain). In 1956, the future architect of Mali's independence, Modibo Keita, was appointed leader of the movement and elected to represent the 'Sudan' in the French Assembly. A 'Malian Federation' project was drawn up to include Dahomey (Benin), Upper Volta (Burkina Faso), Senegal and 'Sudan' (Mali). A constituent assembly of independence movement representatives was set up in 1959. However, the constitution adopted by the local Malian and Senegalese assemblies was rejected by the other two. The Federation now had only two members but was nonetheless proclaimed independent on 20 June 1960. In the event, the spirit of unity was lacking and, on the pretext of a rivalry between the two leaders (the 'Sudanese' Modibo Keita and the Senegalese Mamadou Dia), Senegal withdrew from the union in August. On 22 September 1960, the 'Sudan', now without an outlet to the sea, adopted one of the most prestigious names in its history: Mali.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The new state was landlocked not only geographically but also, very soon, politically. Modibo Keita's socialist agenda prompted foreign investors to pull out, and the country was organised increasingly as a 'people's democracy'. Fortunately, the repression was not excessive but a sizeable proportion of the population disapproved of the system that had been chosen. Mali and Guinea still had modest aspirations to their old dream of unification. The founder of the Republic, Modibo Keita, was overthrown by a military coup on 19 November 1968. More than the break-up by colonisation, which left dreams of Sudan being reconstituted, this military putsch sounded the knell of the old empire. Mali became just another state whose colonial and post-colonial eras have been marked by a lack of success. Nevertheless, a sense of history is still omnipresent. </P>
+<P ALIGN="JUSTIFY">Hegel Goueier</P>
+<P ALIGN="JUSTIFY"></P>
+<I><P>&lt;&lt;TOC4&gt;&gt; Three republics to create one democracy</P>
+</I><P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">It is just something you have to get used to-in French-speaking Africa, virtually all countries have imitated France in assigning a number to each republic formed under a new constitution. At the time of its independence on 20 June 1960, Mali was a federation of two states; Senegal and the former 'French Sudan'. It was an alliance which failed after only a few weeks'existence end 'French Sudan' then adopted one of its most prestigious former names- Mali. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The first regime, under Modibo Keita, became increasingly unpopular as its form of 'tropical' marxism caused it to become more and more isolated. One of its main shortcomings was its unrealistic five-year plans, none of which were ever implemented. Discontent became rife among various social groups. including the farmers who, opposed collectivisation and were adept at passive resistance which they employed to disrupt the supply of produce. The regime also modelled itself on the so-called 'people's democracies' in certain respects. For instance, it made a determined effort to improve education, health and social justice, while refraining from the more dictatorial excesses that often characterised such systems.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Initially welcomed by some sections of the population, the November 1968 putsch, by Lieutenant Moussa Traore quickly fumed into dictatorship although it was to be more than 10 years before there were any significant anti-government protests. At the end of 1990, opponents of the regime openly set up organisations which claimed opposition-party status. One of these was ADEMA (the Alliance for Democracy in Mali), formed by the current President of the Republic, Alpha Oumar Konare. Marches calling for a multi-party state attracted the support of tens of thousands of people.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The dictator then sought to neutralise the opposition, beginning with the Tuaregs in the north who had been waging a guerilla war. This conflict was viewed by many as the 'front line' in the people's struggle against dictatorship, and the Tuareg cause was supported by opposition movements. The government, which had for some time opted for 'soft' repression, now revealed its claws and in January 1991 it began to imprison student leaders. The streets were filled with armoured vehicles and the first death amongst the students brought condemnation. Repression reached its height on 22 March 1991, when several dozen students were killed.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Prior to this, in February 1991, Moussa Traore's UDPM (Democratic Union of the Malian People) came out in support of a multi-party system - a move which marked the beginning of the end of the regime. The day after the students were killed, a democracy coordination committee launched an appeal for a general strike, to last until the dictator was overthrown. This began on 26 March, and amounted, in effect, to a 'democratic' coup d'etat. Its instigator was Lieutenant Colonel Amadou Toumani Toure, who took charge of the transition to-tether with the democratic movements.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The former dictator was arrested and put on trial for his crimes. He was later condemned to death but his sentence was recently commuted by President Konare.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The Tuareg guerilla war continued despite the government's conciliatory attitude. The new administration also had to deal with a number of social claims which had long been stifled by the dictatorship. However, popular support for the regime remained firm. The new constitution was adopted virtually unanimously in a January 1992 referendum and, a week later, ADEMA won the municipal elections, the first in a series of electoral victories for Alpha Oumar Konare. He went on to win the Presidential election (for the Third Republic) in April, with almost 70% of the vote. Meanwhile, negotiations with the Tuareg rebels resulted only in signatures on agreements which were not observed. The situation grew worse with the Ghanda Koy counter-offensive, but this in turn led to a seemingly viable accord between the Azawad Arab Islamic front, the most important guerilla movement, and the Malian government. Last March, President Konare presided over an enormous bonfire of weapons seized from the former guerilla fighters. The flames lit up the skies above Timbuktoo, the symbol par excellence of rapprochement between the peoples of Mali.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">At the beginning of January 1994, the regime suffered the effects of the devaluation of the CFA franc. Economic liberalisation had enabled Mali to improve its macroeconomic position, but social discontent, particularly in the towns and cities, demonstrated that the average citizen was continuing to suffer economic hardship. The President still enjoys considerable support, and political democracy is greatly appreciated. Obviously, the government cannot be blamed for all the difficulties facing the country. There is, for example, a lack of professionalism in the press. However, it could have given a lead in the case of the State media, which still studiously avoids criticising the government's actions. The administration has also been taken to task for its apparently lax attitude towards 'economic' misdemeanours.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Next year will see a series of elections. The government views these with apprehension, although it has stolen a march over its rivals by signing a political accord with several small parties. Opposition is centred around the MPR (Patriotic Movement for Renewal), the revamped former party of the dictator Moussa Traore. This has undergone a 'facelift, and now seems to be regaining support. lts trump card is decentralisation. Its former leaders, who held total power for a quarter of a century, can take advantage of the network of contacts they built up. The US-ADA, the party of the Republic's founder, Modibo Keita, which until recently appeared to be the herald of change, seems lately to have restricted its role to that of arbiter. Surprises are in the offing, but one thing is certain: the Third Republic's constitution will remain the guarantee of democracy in Mali. </P>
+<P ALIGN="JUSTIFY">H.G.</P>
+<P ALIGN="JUSTIFY"></P>
+<I><P>&lt;&lt;TOC4&gt;&gt; Interview with Ali N. Diallo, President of the National Assembly</P>
+</I><P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">In Mali, the army has learnt if from the past</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Mali's institutions were radically remodelled in the wake of the recent vote on decentralisation. This is aimed at allowing, among other things, a degree of autonomy for the north of the country-which is essential to guarantee national reconciliation. The sudden growth in the number of small towns and villages may result in some political surprises during the long e/ection campaign period which is due to begin early next year. The President of the National Assembly, Ali N. Diallo, finds himself in a pivotal position: his Adema (A/fiance for Democracy in Mali) party current/y holds a comfortable majority in Parliament. With democracy being consolidated in Mali, he must find this an exhilarating time. Our frst question touched on this</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">-This is certainly an excellent time to be in Mali, but freedom is the most difficult of man's needs to satisfy. Our National Assembly has 12 parties and most people in our country are inspired by ideas based on tolerance and respect for the right to be different. The main concern of those of us who lead the party currently in the majority, is to question constantly whether we are necessarily always right. We have a comfortable majority-72 members out of 115-but this certainly doesn't mean that the National Assembly is just a rubber stamp.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">· There is, of course, another stumbling block when one has such a large majority, which is the possibility of internal divisions.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">-Yes, I would agree with you there. Mali's MPs have to realise that they came into this business after a three-stage process. First there was a popular uprising, then the army intervened to put an end to the bloodbath.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Finally, we had the high level national conference to draft the constitution, the electoral code and the charter for the country's parties. MPs, therefore, must always bear in mind that, though they can claim legitimacy on the basis of the revolution, there is also a republican legitimacy they ought to respect.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">· The second phase in the process was the intervention of the army-are you not a*aid that the 'Niger syndrome'will raise its ugly head in Mali, too ?</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">- Naturally, MPs have seen what happened in Niger and elsewhere, but fear is tempered here because officers in Mali's forces have also given a great deal of thought to the effects of military dictatorship. Democrats and republicans within the armed forces are very aware that only a minority of men in uniform profited to any degree from the previous regime.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">· Do you think that because Mali had what might be called a 'moderate' dictatorship, it is now in a better position than it would have been had the previous administration been more repressive ?</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">-Let me put it this way. The military dictatorship went through three different stages. During the first stage, just after the coup on 19 November 1968, the junta chose Mao Tse Tung as a model, hammering home the idea that power could be won by force of arms-and it was carried away by the popular acclaim it initially received. Subsequent popular resistance then took them by surprise. People wanted more freedom, but they also wanted to keep what they had gained in social matters. Army officers asked the protestors to abandon their action so that normal constitutional life could be resumed, but the trade unions had their own ideas. They advocated things which the people in power opposed. The ensuing repression was therefore fierce.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">There was a second phase during which the military were at odds with one another over the leadership question. The popular view was that the country had fourteen different heads of state at that time. This went on until 28 February 1978 when there was a brief Iuli and they were tempted to return power to the civil authorities.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Then came the third phase when, despite appearances, poverty was on the increase. At first, Malians said that there were two 'IMFs' on the loose in Mali-the International Monetary Fund and the intimate circle surrounding the Moussa family. When the social foundation of the regime contracted, and all the country's business became concentrated in the hands of Moussa, his wife and her relations, the popular forces went on the offensive. This was a period of vociferous protest. Moussa Traore reacted with brutality: hence the 200 dead amongst the schoolchildren and students who were protesting- we will never know the exact number.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">· Yet, the former regime could be said to have made the crucial economic choices which your government has continued with. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">-I wouldn't agree with that. There was a half-hearted discussion at the time about liberalising the economy but, in reality, bureaucracy got in the way. It is the economic laws voted in by ourselves which form the true basis of a liberal economy. However, if you really want to look to the past, I would say that it was the February 1967 accords signed between Mali and France, when we came back into the franc zone, which set the whole process rolling.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">· The Tuaregs and the government have just signed an agreement but the question of the north of the country is still a sensitive one. What are your views on this subject ?</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">-The problem in the north of Mali is extremely complex. First, the Malian nation is made up of a patchwork of minorities, the largest being the Ban Mana (Ed. 'Bambara' in the colonial vocabulary), but no ethnic group is larger than all the others put together. Second, all groups have, at one time or another, held supremacy. But the fact is that the peoples involved have all lived in the same area throughout history- they have shared joys and sorrows, and their blood has mingled on Malian soil. l would accept that the Malian nation is not as well consolidated as it should be, but it is arguably one of the most advanced in the sub-region in terms of its constitution-though I don't mean to sound chauvinistic here.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Anyway, the problem in the north of the country seems to me to be one of development. The various regions have not all developed at the same rate on account of climate differences. In addition, the dictatorship did not show any great respect for minorities - although it did not direct its actions solely against the Tuaregs, who resorted to arms. The Tuaregs exaggerated the mistreatment they had suffered because they were unfamiliar with what was happening in the rest of the country. In fact, Moussa Traore oppressed everyone: the French-style Jacobin state we inherited did not allow for regional differences. After independence, the regime redoubled its efforts to centralise the state. both because it was Jacobin in outlook and because of Modibo Keita's communist leanings. In 1959, the French forced the Tamashek (ea. 'Tuaregs') to secede-Max Lejeune and Houphouet Boigny were mixed up in all that. This was when oil was first discovered in Algeria and the war with Algeria had been in full swing since 1954. Modibo Keita set up the Malian Federation and declared in 1959 that, upon independence, he would withdraw all soldiers from the Algerian front. Since the Malian Federation was dismantled, Gao virtually became an Algerian willaya, a base camp for its fighters. Mali did not accept this. Moreover, Algeria, around the time it achieved independence, took retaliatory measures and sealed off its borders, mercilessly sending back huge numbers of refugees. It mobilised them through humiliation, telling them that they were the last members of the white race-the only ones to allow themselves to be under black rule.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">· But when Ganda Koy's militia halted the Tuareg movement, they appeared to have been supported by the black population. Doesn't that also suggest a racist attitude ?</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">-I addressed the Tuaregs in October 1992, and pointed out that their wish to regard themselves as overlords and the other peoples in Mali as vassals who ought to pay tribute would provoke a general uprising, with the risk of a slide into civil war. I told several of the Tuareg chiefs seated around me the legend of Ouagadou- about the serpent of the well who each year demanded that the Soninke people should sacrifice an 18-year-old girl in its honour. Then the day came when a young man refused to accept the sacrifice of his fiancee. He went down into the monster's lair, watched by a horrified crowd who saw his recklessness as folly, and cut off the serpent's head. In the beginning, the Malian people's sympathies in fact lay with the rebellion. On 26 March, when the rebellion against the dictatorship took place, the president at the time, Konare, asked for all the Tuareg chiefs to be brought to him so that they could set up a transition body. He got a nasty surprise when the Tuaregs resorted to arms.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">· Was the government, as rumoured, behind the Ganda Koy ?</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">-Not the government as such. To my mind, it would be wrong to applaud when one faction of the people one governs wants to exterminate another faction.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">· It appears that some of the people are unhappy with the concessions that have been made to the Tuaregs.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">-This is a myth. The idea that we are frustrated because the Tuaregs were once our masters, is a story put about by Europe. The situation is quite the reverse. At the time of colonisation, they were unwilling to ream, like other nomads, such as the Peul people, for example. There were splits with them, of course, but no actual, all-out war. Forging a nation always requires tears, sweat and mourning. Those who return will find what they left broken or stolen and will want land which is less barren than that impoverished by the encroaching desert. However, those who stayed put in the face of rebel attacks had their houses smashed and their animals taken away. There will be problems when some Peals, for example, identify their cows which were stolen. We will have to negotiate, but I have confidence in the people. Just as they ended the war, they will be able to heal the wounds-of this I am sure. And the process has already started.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">· I gather that you continue to practice as a doctor, on top of your political duties. Is this to teach a moral lesson to your political colleagues ? </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">-I would say that it is more of a weakness, an inability to abandon a passion, even for supposedly good reasons. l am an 'internalist' and I have a passion for mechanisms. If you cure an infection and it returns, you have to look elsewhere to solve the problem. There are those in authority who spend money on trying to tackle problems without troubling to locate the cause. I would like to think that the analytical rigour of clinical science might also be put to good use in promoting understanding in politics. </P>
+<P ALIGN="JUSTIFY"></P>
+<I><P>&lt;&lt;TOC4&gt;&gt; Profile</P>
+</I><P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">General information</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Area: 1 240 190 km²</P>
+<P ALIGN="JUSTIFY">Population: 10 million</P>
+<P ALIGN="JUSTIFY">Population density: 8.15 per km²</P>
+<P ALIGN="JUSTIFY">Population growth rate: 3.1 % </P>
+<P ALIGN="JUSTIFY">Capital: Bamako (pop.700 000) </P>
+<P ALIGN="JUSTIFY">Other main towns: S&eacute;gou (65 000), Mopti (52 000), Sikasso (50 000), Koutiala (37 000) </P>
+<P ALIGN="JUSTIFY">Languages: French (official language), Bambara, Peul, Shongoi, Tamashek </P>
+<P ALIGN="JUSTIFY">Curreny: CFA franc. In July 1996,1 ECU was worth CFAF 647.5 ($1 = CFAF 515) </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Politics</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Government: Mixed presidential and parliamentary system. Greater powers are due to be transferred to the regions after the next elections. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Head of State: Alpha Oumar Konar&eacute;</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Prime Minister: Ibrahim Boubacar Keita Political parties represented in Parliament: ADEMA (absolute majority). 'Opposition' - CNID, USRDA and numerous other smaller groupings. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&lt;&lt;I&gt;&gt; p021.png Map</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Economy</P>
+<P ALIGN="JUSTIFY">(1993 figures unless otherwise stated) GDP: CFAF 753.8 billion</P>
+<P ALIGN="JUSTIFY">GDP per capita: $530</P>
+<P ALIGN="JUSTIFY">Origin of GDP by sector: agriculture 42%, industry 11 %, services 47% </P>
+<P ALIGN="JUSTIFY">Real GDP growth: 2.4%</P>
+<P ALIGN="JUSTIFY">Balance of payments: deficit of CFAF 84.1 billion (estimated) </P>
+<P ALIGN="JUSTIFY">Main trade partners (% of total trade) </P>
+<P ALIGN="JUSTIFY">Exports: Thailand (24.2%), Brazil (19.1%), Ireland (9.7%), Belgium/Luxembourg (9.7%) </P>
+<P ALIGN="JUSTIFY">Imports: C&ocirc;te d'lvoire (22.2%), France (14.5%), Senegal (9.7%), Hong Kong (4.6%)</P>
+<P ALIGN="JUSTIFY">Main exports: cotton 40%, livestock 28%, gold 17.5%</P>
+<P ALIGN="JUSTIFY">Annual inflation rate: 3%</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Social indicators</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Life expectancy at birth: 46.2 </P>
+<P ALIGN="JUSTIFY">Infant mortalityper 1000 live births: 158 </P>
+<P ALIGN="JUSTIFY">Adult literacy: 28.4% </P>
+<P ALIGN="JUSTIFY">Enrolment in education (primary, secondary and tertiary): 16% </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Human Development Index rating: 0.223 (171st out of 174)</P>
+<P ALIGN="JUSTIFY"></P>
+<I><P>&lt;&lt;TOC4&gt;&gt; Interview with Amadou Seydou Traor&eacute;, opposition leader and USRDA spokesman</P>
+</I><P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">'Macro-economic indicators tell you nothing about the distribution of the country's resources'</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">· It cannot be easy to be in opposition when Parliament is dominated by a majority which is given a good press and is regarded abroad as a good pupil.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">-We do not really find it a problem. If one is familiar with Mali's current situation, the people's views, reactions and judgments count for more than outside opinion, despite the fact the latter may seem important. However, we do take account of others' opinions. We are pleased to be able to speak to you-to express our ideas and points of view- so that outsiders can see that the USRDA offers a credible alternative for Mali. We feel quite secure in our current position because the principles and values we stand for are those closest to the Malian people. So we have no problem in being the opposition party. We are not the kind of hysterical opposition which resorts to foul means as well as fair ones.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">· Given that most Malian political trends stem from the revolutionary democratic movement, what are your party's special features ?</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">-Our party's origins are in the movement which dates from 26 March 1960-which itself grew out of an underground movement. The main component of this was the USRDA whose government was overthrown by a reactionary military putsch. Adema won the last elections, and we do not contest this fact despite a number of irregularities. Indeed, we supported the Adema government's initial actions. We were one of seven parties who regarded the Third Republic as our own offspring. Between 1992 and 1994, even when we faced grave difficulties and they were asking for suggestions, the government ignored our proposals. This happened, for example, at the time the World Bank threatened to pull out. As it functions at the moment, the government is not meeting the Malian people's basic aspirations. They want to see a change from the previous regime.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">· What are your essential criticisms of the way Adema works ?</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">-We are critical on a number of fronts. Looking at it first from an institutional standpoint, when the Malian people rejected the old regime, they wanted the existing set-up to be changed into a democratic one. The few institutions that have been established since then do not reflect this desire. They are virtually no different from what we had under the single-party system. True, we have an opposition party, but its views are ignored. Second, in terms of the management of democracy, a number of bodies, such as the State Commission on the public media, simply do not function. You have been in Mali for a week now, so you must have heard Adema spokesmen on the TV or radio. But you will never hear a member of the opposition. The space reserved for that -formerly an open forum for free political discussion-has been removed and the state-controlled TV and radio stations do not allow political parties to have a say. In the economic sphere, our approach is also completely different. We believe that support for the development of the private sector means that the state has to act as regulator. Economic development cannot simply be left to run its course as a kind of 'rat race'.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">· Could you give us a few practical examples of what you describe as Use selling-off of the family jewels ?</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">-With pleasure. Before the 26 March revolution, there was a general consensus that, in the process of privatisation, the state sector should be managed in a way that benefited the Malian economy. But the reality is that privatisation methods have not changed. They are no different from what they were in Moussa Traor&eacute;'s time. The electricity sector, for example, which has not yet really been privatised, is now managed by the Bouyges group of France. And it costs more, which will hardly help the country's economic development. The state airline has simply been absorbed by Air Afrique. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">· If you were in power, how much economic scope do you think you would have, given the prevailing trend towards international liberalisation ?</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">-I recognise that there is a dominant international lobby which has drawn up its own conditions, laws and principles. Even if one does not agree with this approach, one has to take it into account. However, it should be feasible to achieve privatisation in a different way. We know what we are talking about because we used to run this country. Indeed, we set up the national economy. Before 1960, there was no economic system to speak of. l am currently completing the text of a work which looks at our economic position at the time of independence. The plain fact is that we had nothing at the time of independence. There were only three pharmacists, fewer than ten doctors, and about ten people qualified to teach in our grammar schools-not much to write home about after 70 years of colonialism! After 1960, we had to set everything up from scratch. If you trace the history of every country in the world, whether under a monarchy or a republic, you see that the state has always made the first move in bringing about industrialisation, developing the maritime sector, and stimulating imports and exports. If you think about it, at the outset, the main manufactured activities were the domain of royalty.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">· You claim that your party left a legacy, but some might say that the highly interventionist regime of your hero, Modibo Keita, who brought about independence, contained the seeds of Moussa Traore's dictatorship.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">-These are just fairy stories. When a regime is overthrown by a coup d'etat, it always becomes the victim of systematic defamation campaigns in the press. We were maligned for 23 years with no right of reply and no right to issue a statement to set the record straight. In a way, we are talking today about a past which did not exist. You know the saying 'you are not only what you are but also what people say you are'. This reference to dictatorship is one of the most serious calumnies. But no matter what lies are told, something of the truth will always remain. If our regime had been dictatorial or inquisitorial, a coup d'etat would not have been possible. Before the 1968 coup, Modibo Keita was given a file by the security services warning him of the plot by Moussa Traore, and giving a list of his accomplices. He was advised to arrest the conspirators and put them on trial. His response was that he would not agree to a Malian citizen being deprived of his liberty without a scrap of evidence. I knew Keita very well. It will be a long time before we have another head of state with such democratic convictions.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">· The ordinary people, the farmers, say that they did better under Traore, than under Keita.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">-Yes, but it depends who you talk to. With Traore, there was an atmosphere of moral decline. We were free to plunder, steal and murder, but it was not real freedom. The farmers see it from a different perspective. However, l can still show you a copy of the 'Summary Report on the Seminar on Cooperation in the Rural Environment' which we drew up in 1968, just a few months before the coup d'etat. This highlighted the fact that socialism had not penetrated into the countryside during the seven or eight years we were in power. So you see our own self criticism appeared in a document published in May 1968. This demonstrates the fact that we were not complacent.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">· What is your view of the compliments the current government is receiving from many foreign observers, and the good marks it has been given in the macro-economic field by international institutions ?</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">- Good macro-economic results which are due to good management of public finances are beneficial for the country. However, such management must be accompanied by greater welfare and an improved standard of living for the people. There is no point hailing a GDP increase of 3-4% if more than 10% of the population does not have enough to eat. You have been through Bamako and other towns and cities and you have seen the construction sites and big buildings. But in their daily life, people are now more ill at ease. They have been disappointed by the Adema regime. The welfare of the ordinary citizen cannot be defined by reference to the personal wealth of someone who is having a seven-storey building put up. All of this new construction is reflected in the higher GDP. But the macro-economic indicators tell you nothing about the distribution of the country's resources-and the scales are currently tipped towards injustice. Those who are working are earning less but those who do not work are earning more. Embezzlement and corruption are currently worse than under Moussa.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">· What is the likelihood of a changeover of political power given that the opposition groups are at odds? The union between yourselves and Parena appears to have been suspended.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">-We are capable of winning the forthcoming elections without entering into an agreement with any other party. Having said this, we are the party to which most groupings in Mali are now turning and we are currently in the process of forming an alliance which will carry a great deal of weight. l am not one to speculate but I am sure that Parena's supporters will, in time, reach the same conclusions as ourselves regarding the timeliness and suitability of an alliance between us. We have contacts with a number of other parties but we do not want to form an electoral pact in the way one would make preparations for a coup-forming a group, ousting the regime and then shooting at each other! Moreover, it is important not to confuse change with restoration. There are those who advocate the restoration of Moussa's regime. Opposition of that kind would suit the current government very well because it would allow them to raise the spectre of our former dictator in the hope of attracting support from those who are frightened by such a pro spect. </P>
+<P ALIGN="JUSTIFY">Interview by H.G.</P>
+<P ALIGN="JUSTIFY"></P>
+<I><P>&lt;&lt;TOC4&gt;&gt; The magnetism of the unfamiliar... but unexotic</P>
+</I><P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">In West Africa, there is a dry, desert-like region which a river tried to bring under its sway. Instead of flowing seawards, the river's path went in the opposite direction to find this region, impulsively tracing a majestic loop of 2000 kiLom&eacute;tres before heading seawards. The Niger may not have provided an ideal site for Mali's major towns and villages, but it was considerate enough to form a major waterway between them which is navigable over almost its entire course. Its network of tributaries has resulted in the formation of large landlocked lakes whose waters are full of fish-a reminder of the times when the Sahara was one huge expanse of water. It has also resulted in the extraordinary Niger basin, a central delta area the size of Belgium, criss-crossed by lesser tributaries which reach into the smallest valleys. The river has created a diverse landscape which entices the visitor back. The land is steeped in history and if one wishes to learn its secrets, one has no choice but to study the empires of the past, forged it is said, by mythological deities and heros.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">During the dry season, visitors marvel at the beauty of the plains, which stretch as far as the eye can see. They will be tempted to return to view the waters that will cover them for just a few months during the rains. This is when the towns and villages appear as islands in the flooded landscape. Later in the seasonal cycle, Nature divests itself of its watery raiment and prepares to welcome the egrets, pink flamingos and all the other richly coloured birds which have flown in from afar. The cultural life of this region is also imbued with a rare richness, combining mystery and individuality. Mali has a distinctive character: it is accessible but not adulterated by frippery, welcoming but not taken over, affable but able to treat everyone as its equal. There is no need to make constant reference to the past which existed before colonial times-the past simply exists, eloquent in its tranquil humility.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">A survey of Mali should logically begin in Bamako, the likely port of arrival. But if one immediately journeys to the towns and villages that were the cradles of empire, one is better able to appreciate this young capital, barely 250 years old, whose history owes much to its smaller forebears. We arrived in the evening and departed at dawn the next day. So Bamako was no more than a blur. The River Niger, still known as the Djoliba in the capital, is crossed by two long bridges which offer a view over the wild river banks. Most of the constructions are brand-new and some have a style borrowed from their thousandyear-old 'Sudanese' architectural heritage. It would have been more romantic to travel by river to the central part of the delta but, despite the welcoming nature of the Niger as it flows through Mali, it is difficult to navigate over the Sotuba rapids, between Bamako and Koulikoro approximately 50 km away. When the waters are in spate from July to December, it takes no more than two days to reach Segou, three to reach Mopti, five to reach Gao and an extra day to arrive in Timbuktu.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Segou, the rebel</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Our first stop after Bamako is Koulikoro, the departure point for Niger cruises. After the unusual houses of the bazo fisherman on the banks of the river, as one leaves Bamako, it is the river itself which is a source of curiosity, transforming the voyage into a wonderful promenade through a forest abounding in game. Then there are the thatched, circular mud huts. Those without a roof are built on piles and are often ovens for preparing karite-nut oil whose bitter-sweet fragrance mingles with the fruity scent of the mango trees which line our route. In Koulikoro, every day is market day. The market spills out into the road and then shrinks back to allow vehicles to pass. It is also a centre for hunters and poachers who come here to seek customers. Above all, it is the centre for the guilds of masons who jealously guard the secrets of traditional Sudanese building skills. For the visitor who cares to linger, the griots will sing the praises of the old magician-king Soumangourou whose spirit has haunted this small town for eight-and-a-half centuries. When he was overthrown by the hero Soundjata, he just vanished into thin air-in the land of mystery that is Mali, great kings do not die, they simply disappear.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The first 250 kiLom&eacute;tres of the river's course from Bamako are enchanting. One's first real encounter with Mali's past come at Segou-when the balanzans come into view. The charming, independent city is close by. Segou, the Bambara capital, did not form part of most of Mali's empires. Indeed, the word Bambara comes from 'Ban-Mane', which means 'those who reject a master'. There are 4444 + 1 balanzans to announce the city, all of which are numbered except the last one, which still guards its secret. The balanzans conceal another secret: during the dry season they are covered with leaves, which they lose during the winter. A curious traveller might arrive at Segou with memories of Maryse Conde's fine prose (Segou, Robert Laffont, France, 1984). Her work is an epic fresco of life at the court of the Bambara kingdom in the nineteenth century. The city itself stretches for eight kiLom&eacute;tres along the river bank, with a promenade high above the river on an embankment from where there is an uninterrupted view over the water to the horizon. The richly coloured fabrics of the washer women create a dreamlike atmosphere, giving an impression of the shimmering tunics worn by princes, and the women who swim in the river are not given to excessive prudishness, another reminder of the city's enduring rebellious nature. The charm and cleanliness of the town are striking, its administrative buildings stretching along a grand boulevard lined with modern structures. We see in their profiles, the traditional architectural styles as well as a variety of colours. The whole scene is shaded by gardens full of flowers. It is easy to forget that Segou has retained none of its former architectural wealth. This was all destroyed by the organisers of a jihad who sacked this city of infidels who had never been won over to Islam or, later, to Catholicism. The city walls and the regal courtyards are all gone, so what remains is jealously protected: the sceptre and regal symbols of King Diarra, the kingdom's treasures and its secrets. On Mondays, market day, it is possible to see people kneeling at the feet of an old man. He is the custodian of the town's remaining riches, but will never reveal where they are held. Oumar Santara, one of Segou's intellectuals, is attempting to gain an insight into these mysteries in order to protect them better because, he says, the pillage is still going on. Mali's cultural heritage is being ransacked by outsiders. In some villages on the opposite bank of the river, it is still possible to find 13th-century coins in the village squares.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Trial marriage</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Nearly 500 kiLom&eacute;tres separate Segou from Mopti. Midway between the two is San, barely more than a large village. San is bathed by the waters of the Bani, a major tributary of the Niger which it flows into it at Mopti. In the market, fine cotton fabrics can be bought, as can the skills of the blacksmiths. Here, however, there is above all an air of secrecy. The town's inhabitants are members of the Bobo people. The name translates es 'stammering', 'mute' being implied. This is the town which holds the secrets of fatal poisons- cocktails of poisonous plants and snake venom. There are also unguents of all kinds to relieve pain, alleviate scarring, and so on. San has another reputation, that of handing out severe punishment to adulteresses. This seems paradoxical when one discovers that women here enjoy exceptional sexual freedom during adolescence and up to the time of their marriage, and even afterwards. They enter into a trial marriage for three or four years, during which time they are free to 'play the field'. At the end of this period, on the occasion of a feast, they reveal whether or not they will accept their 'provisional' husband. If not, the woman regains her freedom and can start all over again as many times as she wishes. If she decides to become the man's wife, she chooses some of her husband's friends with whom she may 'have a fling' for two weeks, the aim being that she thereby lays to rest her unmarried freedom. She will then swear an oath of fidelity to her husband which she breaks on pain of being cast out of society and even, it would appear, at the risk of losing her life.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">A 1 2-kiLom&eacute;tre dyke, which seems to float on the water during the winter season, links Sevare, the crossroads of the major routes across Mali, to Mopti. Situated below water level, Mopti owes its existence to the embankments which protect it. The dyke offers a fine promenade which opens out onto the quayside of this bustling town. The streets are crowded and the settlement has a vitality and beauty, with coloured lights mirrored in the water. On land, the crowds drift in much the same way as the multitude of boats anchored in staggered rows along the riverbank. These stretch for hundreds of metres- as far as the eye can see. All this wealth of detail forms a tableau punctuated by the outlines of the slender fishing smacks (pirogues or dugout canoes). Despite their size, these vessels retain their uncluttered lines, always giving the impression that they are slicing through the water. The biggest of them are perhaps 50 metres long, carrying cargoes of up to 150 tonnes. This strange, animated scene, which resembles no other in the world, seems to have been staged as a way of reviving the buried images of the Mali of legend-provoking a memory of things unseen and prompting new sensations. Despite the fact that it is replete with Malian influences, Mopti did not develop until colonial times. Like Segou, it never really belonged to any of Mali's great empires, although it became their meeting point. It is a place where all the country's languages are spoken. Indeed, the word 'mopte' in Peal means 'place of assembly'. At Zigui's restaurant or in a cafe down by the port, one find groups of beribboned Tuareg artisans still with their belle servants (former slaves) in tow. One can watch the Peals, also followed by their servants, negotiating their deals. Some trade in gold jewellery, dogon or other ethnic sculptures. Others buy and sell the magnificent Segou carpets or cotton fabrics. Others still dabble in ancient archaeological artifacts (which it is forbidden to sell) and in sacred objects from all over the country. The town itself is an artifact: the apparent hotchpotch is regulated by an internal, almost natural organisation. The hundreds of boats, fishing smacks and other small craft are arranged along the river banks according to the goods they are importing. There is one place for fishing boats, another for furniture imports, and so on.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Mopti merits an overnight stay. In the curve of the great arc which forms the port, a soft light lingers on the congested river banks. It is not just the people who seem to tire of the day's hustle and bustle. The biggest boats with their gentle backwash, anchored in the mud until the next incoming tide, grow too lazy for their images to be reflected in the water and they seem to hold on to the last of the sun's glow, awaiting the first glimmers of moonlight</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The Dogon region, poetry in stone</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">As one approaches Bandiagara, on the threshold of the cliff faces which bear the name of this town, the landscape changes. Most of Mali is flat, but here, we find ourselves in the high land. In fact, the altitude is only a few hundred metres, but the landscape is dominated by sheer and rugged rock faces. This is Dogon country where everything seems to be made of stone: the roads, houses and hills appear in matching tones of salmon pink. The inhabitants, too, seem to have been hewn from the very rock. At first glance, the landscape is unremarkable apart from the sight of all this rock, but as one's perception grows keener, shapes can be made out. At the foot of the slopes are caves that are still lived in. And in the most vertical part of the cliff faces, we can pick out regular, sculpted barrel shapes, combining to form an impressive design. These stone cylinders are the ancient dwellings of the Telems, a mysterious people who preceded the Dogons and were conquered by them. Nothing is known about their disappearance. Today, the cylinders are used as Dogon graves. Access is gained to them during funeral services, by means of a system of ropes. At the top of the cliff is Shanga, the beauty of the Dogon region. It stands atop a 400metre sheer drop which extends over a length of 200 kiLom&eacute;tres. Reaching Shanga from Bandiagara involves picking one's way through the rocky landscape and sliding over sandstone scree.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Before the Europeans arrived to colonise the country, no one had succeeded in subjugating the Dogon region. Was it really ever under the sway of the colonists ? This region, whose beauty lies in its harshness, has no embellishments. And its language is as hard on the ears as the rock is underfoot. As everywhere, to feed themselves, the Dogons till the soil. But this must be carried on the backs of men and women over distances of several kiLom&eacute;tres and then deposited on the rock. Every onion bulb and every root pulled from this thin layer is a testament to the tenacity of humankind.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The Dogon region is like a magnet-it attracts pilgrims from afar who come to venerate El Hadj Oumar, the founder of the Islamic brotherhood of the African Tidjani-a military and religious leader whose life and disappearance are shrouded in mystery. It also attracts people because of the beauty of its works of art. Some of these, apparently of recent manufacture, are actually centuries old. For the custodians of the sacred objects, the interest of outsiders is viewed as a catastrophe. The artefacts are constantly pilfered and sometimes, their keepers commit suicide in their horror at such desecration.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Fine regalia</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Djenne translates as 'the beloved of the waters' and is surrounded by two strekhes of the Bani river. Thus, apart from a short time in the dry season, when the river can be forded, it is an island accessible only by boat. The town has always been a rival of Timbuktu, the 'daughter' of the desert. Before Mopti was created, Djenne was the country's meeting point. The town is dominated by its mosque which is a masterpiece of Sudanese architecture. This imposing clay structure has been a magnet for the faithful since the thirteenth century. It has always been rebuilt in the same style, each version scrupulously identical to the previous one. The most recent reconstruction dates from the early 1900s.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Centre of the Malian empire, Djenne has retained all its finery, magnificence and prestige. It was annexed by the Shongoi empire at the end of the Middle Ages and its conquerors have always been seduced by the town's beauty. The mosque has been designated a World Heritage Site, and the entire town has protected status. For centuries, its architecture influenced other towns and cities in the Sahel and it continues to do so. The secrets of the knowledge and skills of its master masons are still jealously guarded, passed on only reluctantly to the initiated. The whole town is built around the mosque, revealing an interplay of balance and power. There are magnificent inner courtyards to which entry is gained through massive, ornate studded gates. The elaborate and finely carved windows, the intertwined leaves and scrolls of the arabesques and the moucharabies, all bear witness to the Moroccan influence. This has, however, been toned down and it now blends in with Djenne's indigenous forms of decoration and architecture. Whilst all Mali's former great towns and cities were known for their power and military glory, Djenne takes pride in having dispensed with brute force, its spirit protecting it from subjugation. All those who pass through take something of Djenne's spirit away with them.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Coca Cola kept at bay</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Returning to the capital from where we started, we discover that it was colonisation that turned Bamako from a village into the large city that it is today. It inhabitants now number approximately one million. Although a city of recent origin, the site on which it is built dates back to the dawn of time. The hills overlooking the city are home to cave paintings and the underground tombs provide more evidence of a human presence dating from ancient times. There is then a gap of several thousand years in Bamako's history. In early colonial times, just two centuries ago, the village had no more than 700 inhabitants. Bamako began to be developed at the beginning of the 1900s and it is the only city in Mali to have a colonial atmosphere. It has not, however, lost out to change. The ministerial buildings at Koulouba hill, one of five dominating the city, or the Point G houses in the National Museum area, may not equal the beauty of Sudanese architecture, but they are elegant nonetheless. Their plain style is softened by their leafy gardens. The administrative buildings in the lower part of the city are often a fusion of colonial or modern styles and traditional architecture. These edifices are also made more attractive by fine gardens, which lend originality to the city. One of the most successful combinations is the great market, unfortunately in the process of restoration at the time of our visit and whose beautiful interior we were unable to appreciate. It is interior beauty which characterises this city in comparison with other African capitals. Despite its congestion and the density of its population, Bamako still has the atmosphere of a lively village. There is little of what one might term a 'social scene', but it is enough to be invited into the 'squares' or respectfully to visit the block-shaped houses which are still home to entire families and where discussion sessions (grins) last into the small hours. These sessions are enhanced with food and the omnipresent cup of tea. Bamako still prefers tea to imported beverages and to receive guests in the family home rather than joining in the social round in the hotel foyers so characteristic of major capital cities.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">For those hesitant to venture into the traditional life of Bamako (although they would be assured of a welcome), there are many restaurants which make a good attempt at recreating a homely atmosphere. One is not, however, required to take part in the conversations. Two restaurants (the Djenne and the Santoro), which have opened recently, allow one to enjoy the pleasures of art and history. They are part of a wider project to promote Malian art and set up an organisation for artists and craftsmen. They contain areas modelled on the refinement of former imperial furnishing, interior design and architecture, as well as exhibits by Mali's greatest artists. Their creator, Aminata Traore, is an intellectual, art connoisseur and international expert. In Dakar or Abidjan, patrons of such establishments would probably be expatriates with perhaps a few local dignitaries. But at the Santoro and Djenne, prices have been kept reasonably low (no account having been taken of the 50% devaluation in the CFA franc) and the art remains accessible to middle-class Malians. Thus, the spirit of the 'grins' is preserved. The preferred beverage is still a cup of fragrant tea or perhaps a glass of refreshing juice. Whisky will never replace tea, nor will Coca Cola replace fruit juices. Mali is not a country which rejects other people, but it resists cultural encroachment, preferring the </P>
+<P ALIGN="JUSTIFY">familiar to the exotic. </P>
+<P ALIGN="JUSTIFY">Hegel Goutier</P>
+<P ALIGN="JUSTIFY"> </P>
+<I><P>&lt;&lt;TOC4&gt;&gt; Mali-EU cooperation</P>
+</I><P ALIGN="JUSTIFY">Roads and adjustment</P>
+<P ALIGN="JUSTIFY">by Theo Hoorntje</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">For 1990-95, ECU 151.7m was allocated (mainly in project aid) under the seventh EDF National Indicative Programme (NIP). This is equivalent to about 1.5% of Mali's GDP and 13% of its public-sector investment programme for the period in question. European funds from sources other than the NIP-emergency aid, Stabex, European Investment Bank (EIB) venture capital and resources from the structural adjustment facility- reached ECU 87.2m over the same five-year period.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">In 1995, support for the structural adjustment programme represented 5.4% of the balance of payments deficit and 7.8% of the budget deficit. Looking at all instruments together, the amount involved in financing decisions taken by the Commission last year was ECU 42m, with the disbursement figure rising to ECU 40m.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The NlP's primary commitment level under the 7th EDF rose from 76% at the beginning of the financial year to 92% at the end, which means that virtually all available programmable resources are now allocated to projects and programmes. The secondary commitment level, which involves the conversion of proposals into concrete agreements and contracts, rose from 33% to 45% by the end of the financial year. Disbursement rates remain relatively low (32% of available resources).</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Allocations</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Aid is distributed to the various sectors, as follows:</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">- Roads (29% of the total);</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">- Support for structural adjustment (20%);</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">- Rural development / Environment (1 4%);</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">- Support for the private sector (12%);</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">- Decentralisation (9%); </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">-Public health (9%); </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">-Water supplies (4%); </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">-Education/Culture (3%).</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">It is clear that Community aid concentrates mainly on road infrastructures-covering both maintenance and the opening-up of remote regions. Support for structural adjustment, which comes second, is used to finance the State budget's current expenses, particular emphasis being placed on improvement of fiscal and customs income and greater efficiency in health-policy matters.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">In other areas, such as rural development, Community aid also makes an attempt to consolidate gains from previous actions, particularly through the development of rice growing and stock rearing, which should improve supplies to the domestic market and offer further export potential. As far as the environment is concerned, the aim is to contribute to the sustainable management of natural resources on the part of basic users, such as farmers, breeders, etc.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The private sector is supported by actions in key areas and by a programme that was recently set up which involves directing resources through a financial institution (Credit Initiative SA). The objective is to promote lending to SMEs, which is in keeping with the general aim of achieving economic growth.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">In the context of administrative reform, priority is given to the decentralisation process which aims to promote the emergence of new local decision making centres (which should, in the long term, become key players in project development and implementation), and to give such decentralised bodies the means they require to fulfil these new public-sector missions.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">As for health, Community aid has contributed to the PSPHR project financed by other donors. Its main focus is initially on infrastructures and on the policy relating to the supply of essential medicines.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">In the water-supply sector, actions are aimed at strengthening village infrastructures, particularly in the Bankass and Koro areas. A solar-pump programme has also been set up in the Mopti and Koulikoro regions.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">In addition to a school reconstruction programme in the north of the country, the Commission has been able to support education and culture through a dozen or so film projects.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Under the general 'heading' of non-programmable resources, there have been a number of interventions. These include extra support for structural adjustment, Stabex transfers, deployment of the balance from the 5th EDF and EIB projects. Emergency aid has been deployed in the north of the country where, despite difficult conditions, programmes have been able to continue without interruption.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Finally, Community regional aid is helping to combat rinderpest, as well as being directed towards road maintenance, and the provision of training and information on environmental protection. </P>
+<P ALIGN="JUSTIFY">T.H. </P>
+<P ALIGN="JUSTIFY"></P>
+<I><P>&lt;&lt;TOC4&gt;&gt; NGOs finally achieve tangible results</P>
+</I><P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Catherine Beauraind and her five colleagues in the small team of foreigners and Malians, woke early. It had been a short night: our fault, since we had arrived at Bandiagara on the edge of the Niger valley much later than expected having taken the Sevare route. This is the gateway to the rocky Dogon region and travellers on the road occacionaliy fall victim to bandits-which probably made our hosts somewhat apprehensive about our late arrival. The people we had come to see are road builders, working without sophisticated equipment in a region of rocks and cliffs. They seem very youth froml, particularly those who have come from afar.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">These are 'Progress Volunteers', the name given to the many young people who come to this very poor African country to offer their commitment and dynamism, if not perhaps their experience. On this particular morning, still feeling fatigued, Catherine was having to coordinate the departure of escorts for seasonal workers who were being dispatched to various locations. Their job is to ensure the upkeep of the rocky roads, and the equipment they use is rudimentary to say the least. The Bandiagara-Dourou stretch is maintained by the AFVP (French Association of Progress Volunteers) and is one in a long list of NGO projects. In 1995 alone, the European Commission supported over 50 NGO schemes, to the tune of ECU 1.5 million. Most EU countries and a number of others also have their own projects. On top of this, there is the emergency help provided by the European Commission Humanitarian Office (ECHO), which has just approved a grant of ECU 1 million for the north of Mali. Now that a peace accord has been signed between the government and the Tuareg rebels, this region is likely to see a huge influx of refugees returning to villages that are ill prepared to receive them.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Mali is a least-developed nation and one of the most highly subsidised countries in terms of per capita aid, though recently, its political fortunes have been boosted by the democratisation process. And the efforts of the NGOs now seem to be paying off. The recent times of famine have faded in people's memories even in the Dogon region, where many families ate calabashes in desperation before succumbing to starvation. Mother nature is playing a part in the country's renewal: there has been ample rain over the last Many NGO projects are aimed at helping the population use its meagre resources to exploit the natural wealth of the River Niger and its tributaries. At Konna, for example, a striking village at the confluence of two rivers, the Regional Literacy and Self-Management Project is up and running. Financed, among others, by the European Development Fund, this is being implemented at a number of localities, and it has played a part in the renewal which can now be seen. Fresh coats of paint, repairs to houses, fewer starving children and the return of many migrants all underline this new vitality. Each of the 17 small cultivated areas in the village that are covered by the project (worked by about 60 people), receives no more aid than a motorised pump, a few cereals and a small amount of cash in the first year. A basic course in management is also provided. It is up to the villagers to use these resources to yield a profit. Results tend to be good, proof of success being the growing number of such schemes which are being set up without aid from the organisation. The project is now in its seventh year. It did experience one bad year-1992-when, despite bumper harvests, rice imports into Mali were excessive and prices dropped. The village has therefore made an attempt to diversify its crops. Its objective is to sell onions in Cote d'lvoire, where the inhabitants are very fond of this vegetable.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Most villages have been able to save money which was initially placed in banks and then invested elsewhere in the wake of devaluation's harsh lessons. Konna opted for purchasing livestock. In nearby Kotaka, surpluses partially funded the construction of an impressive mosque. Kotaka was one of the places most affected by the recent meningitis epidemic, but a hospital would probably have been too expensive. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Hegel Goutier </P>
+<P ALIGN="JUSTIFY"></P>
+<B><P>&lt;&lt;TOC3&gt;&gt; Western Samoa</P>
+</B><P ALIGN="JUSTIFY"></P>
+<I><P>&lt;&lt;TOC4&gt;&gt; A new spirit of enterprise</P>
+</I><P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Small countries with a limited resource base are frequently buffeted by economic forces over which they have no control. If you live in Western Samoa, however, you are likely to be preoccupied by forces of a different kind. For while most of the time, Mother Nature presents a benign face in this attractive and fertile Pacific state, every once in a while, she loses her temper.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Tropical storms are an unavoidable reality in much of the Pacific and they breed a special form of resilience which should impress the inhabitants of more temperate climes. The people of Samoa, and other cyclone prone countries in the region, are adept at picking themselves up and, if necessary, starting all over again, once the winds have passed. But between 1989 and 1993, the Samoans' capacity for renewal was to be tested more than ever before. Like a plucky boxer facing a much stronger opponent, the country would just be struggling back to its feet when another hammer blow would send it reeling.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The closest to a knock-out punch came in December 1991 in the shape of Cyclone Val-the worst storm to hit the islands in more than a century. This brought death and injury, as well as widespread economic devastation. The coconut and coffee trees on which the country depends for much of its export income were either swept away or stripped bare. Many homes were also destroyed and infrastructures were severely damaged. (The 1993 cyclone, although less powerful, caused further crop destruction.)</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Over the last five years, virtually all the damage has been repaired. Indeed, a great many facilities have been upgraded with plans for further improvements in the pipeline. To some extent, the credit for this remarkable recovery must be shared. Overseas donors played an important part in restoring key infrastructures while expatriate Samoans, whose remittances are an important 'invisible' earning for the country in normal times, also rallied round. But the key players, of course, were the people themselves, who rose to the challenge of reconstructing their country.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Today, Western Samoa - which has a population of 165 000-is experiencing an economic mini-boom. Growth during 1996 is expected to be between 5% and 6% for the second consecutive year and there are encouraging signs of a new, home-grown entrepreneurial spirit. This is not to say that everything in the garden is rosy. The latest growth figures need to be set against the unavoidable recession caused by Cyclones Val and Ofa (which struck in 1990) and a mediocre economic performance throughout the 1980s. And while there is some evidence of diversification, the economy is still very narrowly based. There is also considerable room for improvements in health care and education provision. Doubts have been expressed, for example, as to the accuracy of the official literacy figures. Finally, there is a high level of dependence on foreign aid (the country's main donors are the Asian Development Bank, Japan, Australia and the European Community).</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Economists will tell you how notoriously difficult it is to express the wealth of a developing nation in statistical form. GDP figures can offer a pointer, but they do not present the whole picture as they take no account of the informal economy. Western Samoa provides a particularly good illustration. At US $950, the estimated per capita GDP is very low by Pacific standards. Yet there is clearly no starvation. A great deal of the food consumed by the Samoans simply does not 'show up' in the cash economy. The term subsistence agriculture seems peculiarly inappropriate here since locally available food sources are many and varied.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Similarly, many of the materials used to build the 'fares' (traditional houses) in the villages are obtained without recourse to builders' merchants. And when a Samoan wants a new house, he builds it himself-with the help of his family and neighbours. This involves skilled carpentry work-for which people would pay highly in industrialised societies - and which does not register either in the country's economic statistics. So it is clear that the basic GDP figures do not paint a complete picture. Nonetheless, they illustrate the relatively underdeveloped state of the formal economy.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Agriculture</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Looking at exports, Western Samoa's traditional agricultural sector has gone through some rough times, for a variety of reasons. In the past, the mainstays were copra and coconut products (oil and cream), cocoa and tarot</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The storms destroyed or damaged many of the coconut and cocoa trees, wiping out exports for a number of years until new plantings could reach maturity. The market in food products derived from the coconut had been depressed in any case. One reason for this was negative publicity over the high cholesterol content of coconuts, although more recent research, suggesting that not all types of cholesterol are bad for you, has at least partly restored the reputation of this highly flexible crop.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Taro, which is Western Samoa's staple food crop, was exported in ever increasing quantities during the 1980s but the trade has suffered badly in recent years because of an outbreak of taro leaf blight.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Today, Western Samoa's most important primary exports are, once again, coconut-based (oil and cream). With the new trees reaching maturity, production recommenced on a small scale towards the end of 1994. The following year saw a big jump in exports and the figures for 1996 are expected to - come close to pre-cyclone levels,The marketing situation has also improved as a result of privatisation. The old Copra Board, a parastatal with a reputation for inefficiency, was abolished in 1990, its assets being bought for a nominal sum by a Samoan businessman who has invested heavily in refurbishment. This has all been achieved despite continuing low prices for coconut products in the world markets.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Cocoa takes longer to recover but harvesting of the first new crop is due to take place this year with the emphasis on a high value, fine tasting variety. A new chocolate factory (Wilex C.C.P. Ltd), also masterminded by a local entrepreneur, Eddie Wilson, has been built with assistance from the EU's Centre for the Development of Industry (CDI) and a credit from the European Investment Bank (EIB) channelled through the Development Bank of Western Samoa (DBWS). This is a particularly significant venture since it aims to maximise added value before export. The factory is currently operating well below full capacity, awaiting the arrival of the first local crop, but there are high hopes for its long term success.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The other main crops exported are bananas and kava. The latter is a mild narcotic based on the root of the pepper plant, which is used in pharmaceutical preparations. It also has an important place in Samoan (and wider Pacific) culture, being drunk in diluted form on ceremonial occasions.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">With a view to achieving further export diversification, a number of other agricultural/horticultural export possibilities have also been identified. These include asparagus, mangos and cut flowers. The most likely potential market for new tropical production is New Zealand-already the destination for more than half of Western Samoa's exports. However, this country has stringent health rules with rigorous controls on the import of plant and animal material. The understandable aim is to protect the local farming sector from diseases introduced from outside, but it creates an additional hurdle for potential exporters in the developing countries of the Pacific. In particular, Western Samoa needs to come to grips with the fruit fly problem, if it wishes to make inroads into the New Zealand market.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Timber also once featured prominently in the trade statistics before declining at the end of the 1980s. There are hopes for a revival here with the authorities keen to encourage value added processing of wood products within the country.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Despite its obvious association with the sea, Western Samoa has never really gone in for commercial fishing. While the Exclusive Economic Zone is small by Pacific standards, the country being 'hemmed in' by other island nations and territories, it is still more than 40 times the land area. The government would particularly like to attract foreign investment in fish processing and canning.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Industry</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">It is probably unrealistic to expect a small and geographically isolated nation such as Western Samoa to develop a highly diversified industrial base but there have been one or two notable ventures which show signs of potential. The above-mentioned chocolate factory is one such. The country also has a highly successful brewery. It is not uncommon for developing nations to produce their own local beer but Western Samoa's Vailima brand has managed to break out successfully into the regional market, bringing in useful foreign exchange in the process.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The biggest industrial success story-dwarfing all other manufacturing ventures-has been the establishment of a factory by the Japanese company Yazaki to produce wire harnesses for cars. The business employs some 2500 people (mainly women) in a highly labour-intensive operation-and it makes a significant contribution to the trade balance. The value-added electrical components are re-exported for incorporation into cars sold mainly in Australia.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The company was attracted by a number of factors including low labour costs in this non-unionised society, and the political stability of Western Samoa. Perhaps most important, however, were the incentives offered by the government. These went well beyond the usual tax holidays provided by developing countries to attract foreign investors. Indeed, it was the government that built the factory and the company was allowed to occupy it rent-free. Some observers have expressed concern at such largesse but the authorities are insistent that it was still a good deal. They point to the jobs that were created (a huge number by Samoan standards) at a time when many people's livelihoods were threatened by taro blight. They also argue that the profits of the operation are retained in Western Samoa, thereby helping to boost the wider economy.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Services</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The service sector offers perhaps the best potential for expansion of Western Samoa's formal economy. Top of the list here comes tourism (featured in a separate article), which has been expanding much faster than the underlying rate of economic growth. Despite the increase in both visitors and income, tourism is still underdeveloped. The government (supported by the opposition) believes that this is one field where Western Samoa definitely has a 'comparative advantage'.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Linked to tourism, of course, is the air transport business. Although it might still be possible to obtain passage on a merchant ship bound for the South Sea islands, the vast majority of visitors arrive by plane, and good air connections are obviously essential. The history of the country's national carrier, Polynesian Airlines, offers two object lessons. The first is how not to run an airline and the second, more recent and encouraging one, is how to grasp the nettle when the crisis finally breaks. In 1992, with tourism in mind, the government owned airline decided to expand its operations substantially. It leased three long-haul aircraft which it hoped to fill with visitors in search of a new tropical haven. The market research was clearly inadequate and the planes flew with many empty seats. Other aspects of the company's management proved deficient and there was a chronic lack of financial. Debts mounted at such a frightening rate that the budgetary position of the entire country was threatened.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">In 1994, the government took decisive action, bringing in Richard Gates, the experienced airline entrepreneur, who is credited with having turned Air New Zealand around. Relatively small airline businesses in the Pacific are not likely to make a.fortune for anyone, but with proper management, they should at least be able to break even and perhaps even turn in a small profit. This was not something that even the prodigious talents of Mr Gates could achieve, however, with the crushing burden of debt accumulated by Polynesian Airlines. So the government assumed responsibility for the debts and then gave the new manager a free hand, on the firm understanding that the taxpayer would not come to the rescue again.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">On the airline side, the operation was drastically slimmed down. The leases on the large aircraft were terminated, staff 'down-sizing' took place and bath ticketing and financial management were tightened up. The positive impact of these measures was soon evident, with a small operating profit registered in 1995.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Left with huge debts, the action of the authorities was equally impressive, although it entailed discomfort for most Western Samoans. In order to restore its own financial position, the government instituted 15% public expenditure cuts across the board. In macro-economic terms, it is generally acknowledged that this strong medicine was needed, but the social consequences were all too clear as well: reduced funds for health and education, and pressure on important capital investment budgets. Perhaps fortuitously for the country, the financial crisis caused by the Polynesian Airlines debacle coincided with the payment of a substantial Stabex payment from the European Community. The country's was eligible for Stabex funds because of the collapse in agricultural export receipts following the cyclones, and the money-which was directed mainly into infrastructure projects-could hardly have come at a better time. Meanwhile, the government has paid off a large portion of the airline's debt with the residue rescheduled for payment over a five-year period.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The government has taken a number of steps aimed at attracting offshore finance business to the country. Western Samoa now has a comprehensive legal framework governing such activities, including crucial provisions guaranteeing secrecy. Another vital factor in attracting offshore funds, which has already been mentioned, is political stability. There is even the suggestion that the country's time zone, which puts it almost a day behind Australia and New Zealand, might somehow be turned to its advantage in global financial dealings (although it is not clear how the benefit would be derived in otherwise legitimate transactions).</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The last three years have seen a big increase in company incorporations and there are now more than 2500 offshore companies (including 15 banks and eight insurance companies) registered. It is difficult to imagine Western Samoa ever challenging the likes of Liechtenstein, the Bahamas or Jersey in this market, given its geographical distance from the main industrialised nations, but even a successful 'niche' operation could bring some useful income to the country.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Politics</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Five years ago, when the Courier last covered Western Samoa, the emphasis was heavily on recent constitutional changes and most notably, the introduction of universal franchise. At the time, there was a lot of interest in how the traditional Samoan way of life (faa-Samoa) would be affected. This is based on the village structure and the matai system which vests considerable authority in family heads. There is also a strong attachment to the Christian faith, as exemplified by strict Sunday observance rules (also found in Tonga and other Pacific countries).</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">In fact, the Samoans appear to have embraced their more 'westernised' system of government without any difficulty. Although everyone over 21 has a vote, one still has to be a matai to be eligible to stand for Parliament. In contrast to hierarchical structures elsewhere in the Pacific, however, the system here seems to be based largely on merit and it is not particularly exclusive (there are an estimated 19 000 matai). The matai, nonetheless, exercise considerable authority in village affairs, most notably over the use of customary land.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">In short, the change seems to have caused few problems because Western Samoa already had its own decentralised form of democracy. It was not a question of educating people about hitherto alien concepts.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The fact that change in Western Samoa is slow and progressive rather than sudden and violent, is recognised by most observers to be a good thing. An illustration of this evolutionary approach is the arrangement governing the position of Head of State. The post, which is held by His Highness Malietoa Tunamefili 11, currently appears to be a cross between a presidency and a monarchy. Under the 1962 independence constitution, two of the country's four paramount chiefs were given the position, to be held jointly, for life. With the death of Tupua Tamasese Meaole in 1963, the surviving incumbent became sole Head of State. There will be no automatic succession, however, and Parliament will decide who should have the post in future, with the term of office limited to five years. There is obviously a great deal of respect for the Head of State and his office among Western Samoans, although it should be stressed that his role is largely ceremonial, with political authority being vested in the elected government. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">As for party politics, there are two groupings represented in Parliament, the ruling Human Rights Protection Party and the opposition Samoa National Development Party. The party system is not particularly strong, however, being based more on personalities than ideology. Corruption is not seen to be a major problem although a major row did blow up recently over a critical report issued by the Auditor-General for 1994. This led to him being suspended and this issue had not yet been resolved at the time The Courier went to press.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Western Samoa is not unique in having to adapt to a rapidly changing world. The phenomenon affects all societies, with modern communications technology increasingly breaking down the 'protection' that geographical isolation used to afford. In Westem Samoa, as elsewhere, there must be concern about the impact of this on the country's traditional way of life. Yet the indications are that this Pacific nation is managing the transition rather better than many other developing countries. The people seem to combine an unselfconscious pride in their traditions and cultural assets with a pragmatic welcoming of ideas from outside which help to improve their material wellbeing. The hope must be that this process can continue as we approach the third millennium. S'imon Homer</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Historical summary</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">According to archaeological evidence, the islands of Samoa were first settled about 3000 years ago, after gradual migration within the Pacific from people originally from South East Asia. Samoa, it seems, was the cradle of the Polynesian culture, and settlers from there spread to other islands of Polynesia in the east, north and south.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The first European to sight the group in 1722 was Jacob Roggeveen, and although there was intermittent contact between European sailing vessels and the islanders during the 18th century, more permanent contact was established with the arrival of the European missionaries in the early 1980s. They were soon followed by traders looking for copra, beche de mer, sandalwood and other products. Later, some of the trading firms, notably German, fumed to large-scale production of copra and other products such as cotton, cacao and rubber, which also led a corresponding increase in interest on the part of colonial powers. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">In the late 1800s, the Samoan group became the focus of colonial rivalry between Great Britain, the USA and Germany, leading, in 1900, to the partitioning of the islands between Germany and the United States. The eastern part of the group came under American control and has remained so to this day, while Germany controlled the western islands. Britain received territorial concessions elsewhere in the Pacific. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">At the outbreak of World War I, New Zealand took over what had come to be known as German Samoa, and became the administrative power there under the League of Nations and later the United Nations until Western Samoa became the first Patific island nation to become an independent state in 1962.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">(Source: Government of Western Samoa. this text is taken from the information brochure prepared by the authorities for distribution to delegates at the recent ACP-EU Council of Ministers meeting). </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Dream ticket ?</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Depart Nuku'alofa-12.00, January l 2000 Arrive Apia - 14.00, December 37 1999</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">People with cash to burn are often ready to spend surprising amounts of money in their pursuit of the unusual. Tonga has already recognised this as it begins preparing for the third millennium Lying just to the west of the International Dateline, it believes it will the first country to see the sun rise on the new millennium, although other Pacific territories have also made the claim. (For this purpose, we ignore the purists who point out that the third millennium will not actually begin until January 1, 2001.) Celebrations are planned and bookings are already being taken.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Westem Samoa is obviously not in the running for this distinction since it is east of the dateline, but what this means is it will be the last nation in the world to say goodbye to the old millennium. This surely presents an opportunity for the local tourist industry.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">And what about those intrepid voyagers who fancy greeting the year 2000 in Tonga and then 'seeing out' the old millennium 24 hours later in Samoa. If i were an airline manager, I would be examining the possibility of extra flights from Nuku'alofa on the big day. (Let's hope it's not a Sunday I)</P>
+<P ALIGN="JUSTIFY"></P>
+<I><P>&lt;&lt;TOC4&gt;&gt; An interview with Tuilaepa Sailele Malielegaoi, Deputy Prime Minister and Minister of Finance</P>
+</I><P ALIGN="JUSTIFY">'Economic future in tourism end manufacturing'</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The Courier visited Western Samoa at the end of June while the country was hosting the ACP-EU Council of Ministers meeting. At the time, veteran Prime Minister, Tofilau Eti Alesana, was recovering from an operation, and his duties were being carried out by his deputy, Tuilaepa Sailele Malielegaoi, who is also the Minister of Finance. Despite a hectic schedule, the Deputy Prime Minister kindly managed to find a slot for a keynote interview with The Courier.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">· There is growing evidence of a new economic dynamism in this island nation, which has managed to find its feet remarkably speedily after the destruction wrought by cyclones in 1989 and 1990. With this in mind, we began by asking the Minister about the economic prospects for the country ?</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">-I think they are excellent. Our country suffered a major catastrophe as a result of the cyclones, coming, as they did, in two successive years. There was major damage to our infrastructure and forestry resources- coconuts and cocoa. At the time, we estimated the bill at more than $600m. But the rehabilitation of the infrastructure went ahead quickly, thanks to the major support provided by bodies like the World Bank, the Asian Development Bank, and of course, the European Union, not to mention the bilateral donor countries who answered our call for help. So in some ways, it was a blessing in disguise. We suffered badly, but with the assistance that came, we have been able to improve our roads and electricity supply, and the protection of our foreshore. It also encouraged us to embark on replanting to replace the trees-mainly cocoa and coconut -that had been destroyed. Last year, for the first time since the cyclones, our copra exports came back in strength. We have, at last, started to approach the pre-cyclone export levels.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">· What are likely to be the key sectors for future economic activity ?</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">-We believe that the economic future of our country now lies more in tourism and in manufacturing industries. Dealing with the latter first, we have already succeeded in attracting some industries. The major investment so-far has come from Yazaki, a Japanese company that produces wire harnessing systems (electrical components) for vehicles. This employs almost 3000 people in Western Samoa. In fact, the company set up here before the cyclones and it did not take long for us to see the benefits. The value added equivalent provided by just that one plant is roughly equivalent to our total agricultural exports for last year. So you can see the importance of manufacturing industry for us. We have provided very generous incentives and have also allocated sufficient government land to provide space for factories.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The other industry which is now in the forefront, in terms of foreign exchange earnings, is tourism. We now earn four times more from this sector than we do from agriculture-and agriculture is supposed to be the mainstay of our economy.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Of course, we mustn't reduce the priority that we give to agriculture. It is one area where we have the resources. More specifically, I think that we have great potential for beef production. If we should have another cyclone, the trees will be damaged but cattle should not be affected. So I think we should look more towards beef production and other forms of agricultural diversification. We do have some good commercial farming in place at the moment, but it is not enough. We need to do more.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">· What about the chocolate industry ? You have traditionally grown cocoa but you now also have a factory to process the raw material right up to the end product.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">-This is a direct result of our drive to promote more manufacturing - whether it is export-oriented or geared towards import substitution. The chocolate venture is a new one and I think there are good, prospects here as well.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">An important point is that we are moving back into growing the fine flavour variety of cocoa here. We used to be one of the 14 producers of fine flavoured cocoa in the world, and we got premium prices for it. But somehow, over the years, we switched to producing inferior quality bulk cocoa. We regretted doing that and are now switching back to the higher quality variety-which is just coming back into production following the cyclones. So here we have another potential area for exports. On the other hand, taro which used to be our major export prior to 1993 is facing difficulties. It is affected by a disease, the taro blight, which seems to be uncontrollable.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">· Thinking in particular of the impact of tourism, are you concerned that an influx of foreign visitors might damage Western Samoa's unique and very special culture ? I see, for example, that you now have a 'McDonalds' restaurant in the centre of Apia.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">- No. I am not really concerned. In 1992, we set up our own tourism festival. This takes place in the first week of September and is quite clearly intended to be a feature event with an emphasis on promoting tourism. All the activities at the festival focus on the various aspects of our culture-the arts, the dances, the preparation of food, the singing and so on. It seems to me that our drive for tourism is actually helping to revive some of the cultural aspects that would otherwise have been dvina out. So I believe there is a complementarily between culture and tourism, so long as we ensure that the relationship between the two is maintained. I think this point is backed up, if you look at the growing popularity of ecotourism nowadays. This is very much concerned with preservation-of both the environment and of local cultures.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">· In international circles, Western Samoa is deemed to be a least-developed country on account of its low GDP per head figures. Yet nobody is starving here and you appear to have a very 'rich' lifestyle, even if people don't have a great deal of cash in their pockets. Do you think the international classification is a fair one ?</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">- I think the first point to emphasise is that a lot of the signs of development you see here are of recent origin. They date back only to 1992-93. Infrastructures have improved considerably over a very short time and this could well create a certain impression about the people's standard of living. On the other hand, it is true that our economy is not completely based on cash. And, of course, our earnings are in Tala which go a lot further here than their dollar equivalent in the United States.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">· Presumably, it is to your benefit to be classified as an LDC because it gives you access to more sources of foreign funding ?</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">-I am happy to leave the classification to the experts. They are the ones who come and estimate our average per capita income, which is then used as the yardstick for placing a country in one or other category. I think it is ironic though, that if you go to a country like the USA, which is supposed to be very rich, you find beggars on the street. It certainly makes you wonder. Perhaps it is not really the statistical wealth of a country that is important, but its social system. And our social system here ensures that no-one goes hungry.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">· That leads on rather neatly to my next question. What do you think are the main social challenges that need to be tackled here ?</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">-We still have quite a lot of 'service care' needs in the villages that we need to attend to. That is why we have placed the highest priority on social services over the next five years. I am talking here in particular about health, education and water supplies. There are still a lot of villages that need to have piped water brought into the home. Education-wise, we have reasonable access, but we need to improve the teaching material that is available in the classes and upgrade the general level of village schooling. We need to dissuade families from moving to the capital in the belief that they can get better education for their children here. So we still have a lot of work to do to ensure that the primary schools in the villages are upgraded. It is not simply a question of ensuring that competent teachers are available, but also as I say, providing good teaching materials and laboratory equipment for science subjects.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">· All of this obviously needs to be paid for, which entails healthy government finances. You recently had a serious problem over the debts run up by Air Polynesia, and you took very stringent measures to tackle this which resulted in expenditure cuts. What do the figures look like today ?</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">-They are OK. We are running a budget deficit which means we have to borrow both overseas and locally, but we try to keep the deficit at a reasonable level.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">· What has been the effect of introducing the Value Added Goods and Services Sales Tax (VAGST) ?</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">-It has helped enormously. Of course, in order to sell the idea, we had to reduce other taxes and duties. As you know, there is an international trend towards removing customs duties and shifting revenue-raising in the direction of consumption taxes. Customs levies, which are the traditional source of revenue are diminishing. So what we have done is to lay the foundation for the eventual shift in our revenue base. Also, we promised to cut income taxes even more-from 38% to 25% within two years.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">· Has this measure been implemented yet ?</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">-No, it is due to be introduced in 1998.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">· Finally, I would like to turn to a constitutional question. Western Samoa introduced universal franchise some five or six years ago, but you still have a system in which only matai (family heads) are entitled to stand as candidates in elections. Do you envisage any further changes to the system ?</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">-I cannot really see that we will ever change again. The Constitution stipulates that our government is based on Samoan traditions and Christian principles. When we introduced universal suffrage, we were applying something that had always been there in any case. Samoans have always taken part in the process of choosing their leaders and voting is simply another way of doing this. The only difference is that we would arrive at a decision by getting together through our village structures and talking, whereas your system involves marking a ballot. So the change was quite in accordance with our customs.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Let me say something about the way villages choose their matai. When there is a question of succession, everyone has a right to take part in the process. There is no age limit. So in that sense, you could argue that we are more advanced. And we always had female matai, even before the arrival of the Europeans.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">In this respect, I believe we are quite different from Fiji and Tonga. In Tonga, the dividing line is quite clear. If you are born a noble, you remain a noble and if you are born a commoner, you will always be a commoner. It is the same in Fiji. There, you are automatically a ratu K your father was one. By contrast, here in Samoa, my son cannot automatically succeed to my title. So to become a matai, a person has to earn it, and to put his case at the family meeting which is convened to choose a successor. Usually, the person chosen is the one who displays the best leadership qualities. I think I should also point out that becoming a matai is not that difficult. If you want to be one, you inform the family and if they think you have matured sufficiently, you will generally get the position and then become eligible to be a parliamentary candidate. It is typical that when a family sees a fellow has matured, he becomes a matai.</P>
+<P ALIGN="JUSTIFY"></P>
+<I><P>&lt;&lt;TOC4&gt;&gt; Profile</P>
+</I><P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">General information</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Area: 2934 km² (Exclusive Economic Zone of 130 000 km²)</P>
+<P ALIGN="JUSTIFY">Population: 165000</P>
+<P ALIGN="JUSTIFY">Population density: 57 per kiLom&eacute;tres</P>
+<P ALIGN="JUSTIFY">Capital: Apia (situated on the island of Upolu)</P>
+<P ALIGN="JUSTIFY">National language: Samoan (English is the business language)</P>
+<P ALIGN="JUSTIFY">Currency: Tala (WS$) made up of 100 sene. In June 1996, 1 ECU was worth approximately WS$ 3. (US$1 = WS$ 2.3)</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Politics</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">System of government: A unicameral constitutional democracy with strong traditional elements. The current Head of State is one of the country's four paramount chiefs, and he holds the office for life. Thereafter, the Fono (Legislative Assembly) will elect the Head of State for five-year terms.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">There is universal franchise (introduced in 1991) but in order to be a Parliamentary candidate, one has to be a matai (family head). Western Samoa is said to have about 19000 matai. The minimum voting age is 21.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Head of State: HH Malietoa Tanumafili II</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Prime Minister: Tofilau Eti Alesana</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Main political parties: Human Rights Protection Party (HRPP), Samoa National Development Party (SNDP)</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Party representation in Parliament: HRPP 35, SNDP 11, Independent 3. (The HRPP total includes 11 members elected as independents in the April 1996 election who subsequently joined the governing party).</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&lt;&lt;I&gt;&gt; p038.png Map</P>
+<P ALIGN="JUSTIFY"> </P>
+<P ALIGN="JUSTIFY">Economy (1995 figures unless otherwise stated)</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Annual GDP per capita: approx US$ 950</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">GDP growth rate: 7%. The target for 1996 is 34%</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Principal exports: coconut oil (WS $8m), coconut cream (WS $4.8m), copra (WS $2.2m).</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Balance of payments: exports - WS $21.7m, imports - WS $228.1m. 'Invisible' earnings, officially described as 'net foreign earnings' amounted to WS $171m, leaving a current amount deficit of WS $36.8m in 1995 (20%lower than the previous year). The main 'invisibles' are private transfers (remittances from Western Samoans living abroad), tourism, income from services and the value added trade of the Yazaki electrical components firm.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Inflation rate (end 1995): 1 %. Inflation tends to fluctuate a great deal. The figure for 1994 was 18.4%.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Government budget (projected for 1996/97): revenue WS $288.4m, expenditure WS $312.7m, deficit WS $24.3m.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Accumulated government debt: WS$ 389 m</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Social indicators</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Life expectancy at birth (1993): 67.8 years</P>
+<P ALIGN="JUSTIFY">Adult literacy (1993): 98% (A UNESCO report in 1994 suggested that real literacy levels were significantly below those indicated in official figures) </P>
+<P ALIGN="JUSTIFY">Enrolment in education: all levels from age 6-23: 74%</P>
+<P ALIGN="JUSTIFY">Human Development Index rating: 0.700 (88th out of 174) </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<I><P>&lt;&lt;TOC4&gt;&gt; Marketing a tropical idyIl</P>
+</I><P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Folasaito Joe Annandale and his wife Tui are the brains behind Western Samoa's latest tourist facility- the Sinalei Reef Resort, which has just opened on the beautiful south coast of Upolu island. They are among a growing number of Samoan entrepreneurs who are injecting new dynamism into the country's economy although they are somewhat unusual in the tourist trade. With the notable exception of the famous 'Aggie Grey's Hotel' in Apia, tourist accommodation in Western Samoa has tended to be the preserve of foreign investors, including some of the major international hotel chains.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">At first sight, it is surprising to discover how underdeveloped the tourism sector is in Western Samoa. Tour operators may be inclined to use the phrase 'tropical paradise' a little too freely but this island nation certainly seems to meet most of the essential criteria. It has the obligatory golden beaches fringed with palm trees, extensive coral reefs and striking mountain scenery overlaid with lush vegetation. The vivid colours leave a particularly strong impression. Greens predominate but there are also many copper-leafed trees and bushes, and an abundance of red, orange and yellow flowers. Western Samoa can also offer a number of special features which are important in marketing terms. There is, of course, the legendary hospitality of the Samoans and their distinctive and vibrant traditions. This must be one of the most musically 'literate' populations in the world, a talent which is reflected in the numerous choirs/dance groups. The harmonies are impressive and the traditional dances are both expressive and entertaining. There is also the unique 'fare' architecture which is a particular source of fascination to outsiders, not to mention the Robert Louis Stevenson connection. The famous author spent the last four years of his life in Western Samoa and the house where he lived- which used to be the Head of State's residence - has recently been converted into a museum.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Good prospects</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The potential for expanding tourism is something that has not escaped the government. In today's highly competitive free-market world, countries are being urged to exploit their 'comparative advantage' and the Western Samoan authorities recognise that this sector offers some of the best prospects for future growth.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Like most other economic activities, the tourist trade was badly hit as a result of cyclone devastation in 1989 and 1990. However, visitor numbers have increased substantially since then. Indeed, looking at year on year earnings, the tourist sector is performing better than any other area of the economy. In 1994, income was WS$.58 million (50 000 + visitors). The following year, it reached WS$.78m and there are hopes that it could top WS$.100m in 1996. Of course, no-one in Samoa is talking about 'mass' tourism. The country is too far from the main industrialised nations to be able to offer traditional package holidays (perhaps fortunately !), and too small to absorb the cultural and environmental impact without lasting damage. Having said this, the market can be divided into two very distinct portions. At one end of the scale are the low spending 'back-packers'-often taking advantage of relatively cheap 'round the world' airline tickets to stop off and sample the pleasures of Western Samoa. These tourists may not spend very much on a daily basis but they are reasonably significant from a financial standpoint because they tend to stay for quite lengthy periods.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">At the other end, you find the high-spending, 'exclusive' customer willing to pay for high quality accommodation and catering. Perhaps not surprisingly, the Government is more interested in attracting the latter, which is why they are keen to encourage investors such as the Annandales.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The Courier spoke to Joe Annandale about his business strategy when we recently visited the country. The Sinalei Reef Resort, which has received EIB loan financing channelled through the Development Bank of Western Samoa, has just 20 rooms (including four suites) giving it a capacity of less than 50. Customers will be offered a tropical idyll and a chance to escape completely from the pressures of modern living. The long term aim, according to Mr Annandale, is to entice Europeans in general and Germans in particular. The latter, it is said, have a preference for environmentally-friendly, 'escapist' vacations and, of course, there is a historical link between Germany and Western Samoa. Until a European clientele can be built up, the focus will be on attracting guests from Australia and New Zealand. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Culture clash?</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Although there is no question of Western Samoa being swamped by visitors from overseas, even a modest increase in tourist numbers is bound to have an impact in this country of just 165000 inhabitants. On the negative side, the Samoan system of customary (village) land ownership sometimes appears at odds with entrepreneurship founded on individual ownership of property and resources. In the early stages, Joe and Tui Annandale encountered local difficulties-including squatters-when they bought the land to develop the resort. The usual arrangement is for overseas tourism operators to lease customary land, a process which may involve protracted and ultimately fruitless negotiations with the matai (village heads) who have traditionally used the land for other purposes. Of course, the clash between traditional land tenure systems and 'modern' capitalism is not restricted to tourist ventures-as mining operators in Papua New Guinea have discovered. But while one understands the frustrations for developers, who may find themselves embroiled in complex and interminable land disputes, we should also recognise the concerns of local people who see a possible threat to their way of life.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">On the positive side, new tourism developments mean jobs and trading opportunities. In the building of the Sinalei Resort, the Annandales drew heavily on local labour, employing 35 people from the neighbourhood. As Mr Annandale pointed out, this was essential for a complex designed to fit in with the local environment. The Samoans have always built their own houses and only they had the required carpentry skills. The resort also employs 35 regular staff for catering, housekeeping etc. and again, the majority are local people.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Finally, there is one criticism often levelled against tourist ventures which certainly does not apply at the Sinalei Reef (or other Samoan hotels). This is that most of the food and drink consumed by visitors is imported. The Annandales make a point of purchasing their fish, meat and fruit locally, thereby ensuring that some of the financial benefits of their venture flow back to their own community: in short, a happy combination of astute public relations and good economics. </P>
+<P ALIGN="JUSTIFY">S.H.</P>
+<P ALIGN="JUSTIFY"></P>
+<I><P>&lt;&lt;TOC4&gt;&gt; Interview with opposition leader Tupua Tamasese Efi</P>
+</I><P ALIGN="JUSTIFY">'Revive the agricultural base'</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Tupua Tamasese Efi a former Prime Minister of Western Samoa, is leader of the opposition Samoa National Development Party which won 11 of the 49 seats in the parliamentary elections held in April 1996. In this interview, he outlines his own and his party's views on some of the key political and economic issues in his country.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">· In what ways does your party offer a different agenda from that of the governing HRPP ?</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">-I think the differences are mainly of emphasis. The present government tends to focus on law-making and exploiting the country's least developed status. Our focus would be more on developing our indigenous agricultural industries. If you scrutinise the economic picture in Samoa, you will find that there has been a very substantial decline in agricultural exports in the last fifteen years. Our economy, if you can call it that, is increasingly sustained by largesse-the donations that we get from overseas. This has complicated our situation. Our relative economic independence has been sabotaged to a point where, suddenly, we are getting a proletariat. That might be unavoidable in a lot of places, but it doesn't have to happen in a small country like ours which has self-sustaining village units, and a potentially secure agricultural base supported by products like cocoa, copra and bananas. If you look at what is happening today, you see that, all of a sudden, we have a new class of under-privileged people with absolutely no income at all. And the tragedy is that it has happened without anyone really noticing.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">So our emphasis is to try and revive our agricultural base, and to seek out exports. In the past, our economy was sustained by cocoa and copra exports, and a lot of our food was sold to New Zealand. Now, you find that there are hardly any exports.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">· So your focus would be more on boosting the traditional aspects of the Samoan economy.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">-Not necessarily traditional. Our party is not bound to cocoa, or copra or whatever. But we are committed to improving our agriculture. It matters little whether it is traditional or other crops. But we need to break back into the New Zealand market. This is the best place to aim for. Australia has its own tropical sector and nothing that we can produce is needed by them. New Zealand is different. One of the biggest challenges we have to overcome in getting back into that market is our fruit fly problem. It would seem sensible for us to channel substantial resources into overcoming this hurdle so that we can sell to New Zealand again. There is a tremendous potential market-and not just for copra. There are also products such as flowers, and a whole number of other possibilities.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">· Given what you have just said,what emphasis would you place on sectors like manufacturing and tourism ?</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">-I think that tourism is an obvious way to go and this is where we are in agreement with the government. Of course, you will have heard of the debacle of the Air Polynesia finances. When you compare the losses that were run up with our foreign exchange reserves you get some idea of how enormous the problem was. It was a situation that went badly awry.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">This issue aside, we agree that we need to get into tourism-but it must be within reason. Part of the explanation for people gravitating towards tourism is that they see it as the only available avenue-or at least the most visible way of making money.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Another economic point I want to raise concerns debt. Loans can be a quick fix, but when your whole economy is tied to indebtedness, you are creating something that is built on sand. You end 'A potentially secure agricultural base' up acquiring more and more capital items that are totally unrelated to your present or likely future resources. This is one of the most destructive things that can happen to a society, and it is very clearly happening here.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">· You have a rich and vibrant living culture here in Western Samoa. Are you concerned that globalisation could ultimately pose a threat to this ?</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">-No, I am not worried. You have to accept it as a natural development. The things that are distinctive in our culture have to find their place in adapting to the new realities. There is no point putting your head in the sand.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">· Turning to political aspects, you now have universal franchise, but you still have to be a matai to be eligible to stand for Parliament Does your party have any plans to change this ?</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">-Some years ago, we had a constitutional convention which led to changes in the system. Attached to that was a provision requiring a further constitutional convention to be convened in 20 or 25 years (I can't remember the exact period). So we are committed to that. We have to sit down and look at the overall picture. We have gone a long way in terms of universal franchise and it is possible that we need to go even further.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">But if one takes the United Kingdom as a model, I think the important lesson is that you should 'make haste slowly'. The genius of the Westminster model is that it involves careful evolution. I hope that this tradition will be followed by our country. The constitution, as it was put together some 30 or 40 years ago, has served its purpose very well but there are quite a few anomalies appearing now.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">· What is your view about regional cooperation in the South Pacific What future do you see in working together with the other countries of the region- perhaps presenting a more united front to the outside world ?</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">-There is a lot of sense in the SAS approach-I am referring here to the Scandinavian countries getting together to form an airline. It is sensible to take a common stand where we have a common interest. But there are obviously intricacies resulting from historical, economic and social factors. At the moment I am reading a book on lain Macleod, the British Conservative statesman. His experience in the failed attempt to form a federation in the Caribbean is very revealing.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">When you enter a common endeavour, there is always the pull of your own particular interests. And there can be a suspicion that the 'bigger boys' will use the others to promote their own interests. A lot of this may be perception rather than reality. Also, traditional rivalries can intrude. Sometimes you need to fall flat on your face before you Let me give you an example from the world of rugby. It took Rupert Murdoch to get Fiji, Tonga and Western Samoa to realise that our fates are intertwined. He has come in with a commercial package that has taken over the entire rugby scene in the region- with a heavy emphasis on Australia and New Zealand-and this has hit us in a big way. For example, we find ourselves being cut out of traditional rugby tours. There is no point in us trying to claim that we are self-sufficient in this area. The big lesson is that we need to cooperate a lot more with the Tongans and Fijians in order to make an impact on the wider rugby scene._ </P>
+<P ALIGN="JUSTIFY"></P>
+<I><P>&lt;&lt;TOC4&gt;&gt; Western Samoa-EU cooperation</P>
+</I><P ALIGN="JUSTIFY">Focus on utilities</P>
+<P ALIGN="JUSTIFY">by Mylanwy van de Velde</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">Western Samoa's cooperation with the European Community began in 1975 with its accession to the Lom&eacute; Convention. From the start, the sector to benefit most from programmable funds (ECU 4.6 m under Lom&eacute; I and ECU 6m under Lom&eacute; II) was the energy sector, with the financing of the Samasoni Hydroelectric Scheme in the late 1970s and the Sauniatu Hydropower Scheme in the early 1980s.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">In parallel, a programme of 260 microprojects was funded involving the development of poultry and pig farming, and fisheries, covering 96 villages on the main islands of Upolu and Savai'i. A further ECU 890 000 was allocated to the Western Samoa Development Bank, in the form of a credit line, to increase the Bank's lending capacity. In addition, at a time when copra exports were still considerable, the Community financed storage and handling facilities for coconut oil and copra pellets (ECU 900 000).</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">On top of programmable aid, Western Samoa received 12 Stabex transfers totalling ECU 9.3m for export losses on copra, wood, bananas and cocoa in the period 1975-84.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Under Lom&eacute; III, the development of the country's substantial hydroelectric power potential continued, and Western Samoa began to make considerable steps towards self-sufficiency in energy needs. While in 1980 some 78% of the electricity generated came from diesel plants, by 1986 this percentage had dropped to 26%. The volume of petroleum imports for electricity generation dropped to 36% in the period 1982-86. With the building of the Afulilo Hydropower Plant (Lom&eacute; III and IV), these volumes have decreased further, with positive benefits in terms of foreign exchange savings. The scheme (which was co-funded by the Asian Development Bank, the EIB, the World Bank and the Western Samoa Electric Power Corporation) involved the construction of a 10 million cubic metre reservoir, a penstock, a powerhouse, and the installation of mechanical equipment and transmission lines, and has contributed substantially to the quality of electricity supply on the island of Upolu.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&lt;&lt;I&gt;&gt; p043.png Community aid to Western Samoa</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Additional work has been done with Lom&eacute; IV funds to address the question of rural water supply: a water master plan and design study for a number of rural areas have been completed, and a public awareness programme on the rational use of water resources has been designed for implemention at such time as planned infrastructural work goes ahead.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Finally, an ECU 1 m microprojects programme has been initiated with the aim of financing the renovation of infrastructure for rural communities in the fields of water supply, health, education, tourism, agriculture and fisheries.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Stabex payments under Lom&eacute; 111 (1985-1989) and Lom&eacute; IV (1990-1994) amounted to ECU 11.1 m and ECU 5.7m respectively. These were paid to compensate for losses in coconut oil and copra products, especially, but also for losses on exports of cocoa beans and of wood in the rough.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">In addition to the above grant aid, the EIB has provided a total of some ECU 9m in risk capital in the years since 1981, the bulk of which was used in connection with the Sauniatu and Afulilo Hydropower Schemes.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">A further total of ECU 660 896 has been allocated in emergency aid to Western Samoa, in 1983 after a serious fire on Savai'i, and in 1990 and 1991 after the disastrous cyclones Ofa and Val.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Programming of the next tranche of EC funding under the eighth EDF has still to be completed, but the indications are that prominence will be given to extending and upgrading the water supply network. </P>
+<P ALIGN="JUSTIFY">M.v.d.V.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">A new health-centre for Tafua</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The sight that greeted the people of Tafua when they emerged from shelter in 1990, following the passage of Ccyclone Ofa,was one of complete devastation. The tropical storm had been one of the worst in living memory and this village community on the island of Savai'i, together with many others in the Samoas, found themselves having to start almost from scratch. Homes had been swept away' crops destroyed and much of the essential infrastructure Iay in ruins.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">It is a testament to the resilience and determination of the people in these communities that there are few signs today of the havoc wrought by the winds just six years ago. In some places, rows of dead trees still stand in silent witness to the power of Mother Nature, although the scene is softened : by the new crops and lush vegetation growing beneath. But the villagers have rebuilt their houses and, with some help from outside, they have been able to re-establish i the essential community facilities as well. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Through its micro-projects programme, the EC was able to offer a helping hand in the task of reconstruction. For the modest sum of just ECU 10 000, Tafua now has a new community health clinic adjacent to the site of the old one which was swept away by Ofa. In keeping with the rules of the scheme, the villagers were obliged to contribute 25% of the cost-which they provided in kind, in the shape of the labour for rebuilding the clinic. The Courier visited Tafua in June and was shownaround the facility by Nurse Agata Leuelu who provides primary health care for the 600 villagers. We also met local Methodist minister, the Rev. Siaosi Selesele, who explained how the people had taken shelter in the neighbouring school when the storm reached Samoa. It turned out to be the right choice as it was one of very few structures left standing in the neighbourhood. Villagers are obviously hoping that there won't be another 'Ofa' for a very long time' but if and when the next big wind does strike, the new ctinic-which has been built to withstand a lot more strain-should hopefully be able to weather the storm. In the meantime, it provides an important service in the delivery of health care to the people of the area. The European Community has also provided micro-project funding to help rebuild the health clinic at Taga on Savai'i. </P>
+<P ALIGN="JUSTIFY">S.H.</P>
+<P ALIGN="JUSTIFY"></P>
+<B><P ALIGN="CENTER">&lt;&lt;TOC2&gt;&gt; Dossier</P>
+</B><P ALIGN="JUSTIFY"></P>
+<B><P>&lt;&lt;TOC3&gt;&gt; Investing in people</P>
+</B><P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">(Dossier coordinated by Augustine Oyowe)</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Previous editions of The Courier have dealt, separately and at length, with various aspects of human resource development, especially in the context of recent dossiers on population and social development, education and training, public health, women, and poverty. Our current dossier looks at the issue from the investment perspective.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">To say that investing in people makes economic sense is to state the obvious. But to what extent are the implications of this statement fully understood in the developing countries, especially in sub-Saharan Africa in these days of constantly shifting development theories?</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Labour or 'human capital' has long been recognised as a key factor of economic growth. As opposed to sustainable human development, which places human beings at the centre of economic activities (the recipient of the fruits of economic progess), 'human capital' places them at the beginning of the process. The difference of approach is thus evident even though the objective is the same. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Investing in people is a concept which simultaneously combines 'human welfare' with the 'human capital' approach at the beginning of the economic development process. It encompasses nutrition, health and education, and should, under the right investment climate or conditions, enable any investor, whether State or individual, to reap an adequate return .</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">After three decades of considerable efforts at investment in health and education by sub-Saharan African countries, the returns in terms of standards of living, economic grovvth and rate of development have been extremely disappointing. The conclusion which can be drawn is that the conditions necessary for adequate returns on these investments have been absent.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Colonial legacy</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Sub-Saharan Africa inherited from the colonial regimes, infrastructures in health delivery and education that were not only alien to its culture and traditions, but also totally inadequate for nation building. It is a well known fact that in 1960, there were no more than 1200 university graduates in Capital redefined</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">It is important when thinking of investnent in human resources to understand the real concept of capital. Below is an extract of a definition given by Stefan de Vylder (taken from his UNDP discussion paper: 'Sustainable Human Development and Macroeconomics strategic links and implications' . </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">A child in the North is born wealthy. His or her share of the capital accumulated by earlier generations is worth a fortune. The higher wages and salaries in the North, compared with those in the South, largely reflect differences in endowment of the country, rather than of the individual. The fact that, for example, a nurse in Germany earns 30 times more than one in Bangladesh or Zambia has little to do with individual differences in training or skills; the higher salaries in the North simply reflect the higher dividend on the capital bestowed from the past. Part of this wealth or heritage is easily visible: factories, roads, schools hospitals, universities, telecommunications, and other infrastructure.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">However, there are other, less tangible, forms of capital that constitute a crucial complement to physical and infrastructural capital; parliamentary democracy, a free press, respect for human rights' norms for social interaction, systems of rapid dissemination of new ideas, trade unions and a myriad of other large or small social organisations, a judiciary system which, by and large, defends law and justice, and other institutions. This latter form of capital may be called institutional or social capital. It is also highly unevenly distributed in the world, with large differences both between the North and the South and within individual countries of the North as well as in the South the region as a whole. Indeed, some countries had no graduates at all and in others, they could be counted on the fingers of one hand. In what was effectively a race against time, African leaders understandably responded by investing massively in human resource development. This was made possible partly by small, but steady rates of economic growth and partly by sustained foreign assistance. Between 1960 and 1980, sub-Saharan African governments consistently allocated high proportions of their annual budgets to health and education. Households and individuals made similar efforts (accounting for nearly 75% of all spending on health). They made sacrifices and gave a high premium to the education of their children.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The results were tangible and very significant. By the late 1980s, sub-Saharan Africa was producing over 70 000 graduates a year. Major cities had hospitals and health centres and the rural areas, clinics and dispensaries. Amid a general improvement in nutrition and health-care delivery, the incidence of infectious disease, and maternal and infant mortality were considerably reduced.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Despite these achievements, the approach to manpower building by the post-independent African leaders was, to say the least, haphazard. As a result, a number of problems, such as the appropriateness of school curricula, under staffing and the long-term budget implications of recurrent expenditures, were overlooked (although reform efforts have since been attempted in some countries with varying degrees of success).</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The consequences were felt in the 1980s when Africa's economic crisis was only just beginning. Health and school infrastructures deteriorated for lack of maintenance. There were shortages of qualified teachers and teaching materials leading to falls in educational standards as well as in primary school enrolments. And health systems failed for lack of personnel and drugs.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The situation has worsened as the continent's economic crisis has deepened-a crisis characterised by huge budget deficits, high inflation rates, sluggish growth rates and a heavy debt burden. Structural adjustment programmes (SAPs), introduced in response to this, have only served to undermine further the gains made in human resource development. SAPs have been aimed mainly at macroeconomic stabilisation, deregulation and privatisation of state enterprises, and the social sectors have lost out in the process. Subsidies on basic commodities, especially food, have been removed, civil servants and employees of state enterprises have been made redundant and cost-recovery has become the standard practice in medical services. These measures have all combined to produce a level of poverty never before seen in the region, a situation which has adversely affected nutritional standards, provoked malnutrition in many countries and reduced resistance generally to infectious diseases. Because of the rise in unemployment, large sections of the educated population have been rendered unproductive, a waste of several years investment by both the state and the individuals in question.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Appropriateness of skills</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Although sub-Saharan Africa produced a large number of graduates before the economic crisis began, few had the kinds of skills needed for industry and agriculture. The evidence of this lies in the unsuccessful attempts by some governments in the late 1970s to indigenise executive positions, most of which required high levels of technological knowledge or experience. The 1980s saw a dramatic increase in the number of foreign technical assistants working on the continent and, paradoxically, in the number of qualified African professionals leaving, mainly for Western Europe, the United States and Canada.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">International technical assistance to, or cooperation with, subSaharan Africa has intensified. Organisations such as the World Bank, IMF, UNDP, UNCTAD, UNESCO, European Union and Commonwealth are all involved in one form or another. The effectiveness of this assistance varies, however. This dossier features articles on the work of three of these bodies (the Commonwealth, UNDP and VNESCO). The Commonwealth Fund for Technical Cooperation was set up more than 25 years ago to mobilise Commonwealth skills to meet the needs of member states as required. The UNDP's TOKTEN programme is designed to reduce the negative impact of the brain drain by getting highly qualified developing country expatriates to contribute their skills to the development of their home countries without necessarily having to return permanently. Finally, UNESCO's university twinning programme is designed as a mechanism for the rapid transfer of technology and sharing of knowledge. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">While international assistance or cooperation is indispensable, it is surely no substitute for Africa's own efforts at human resource development. Three years ago, Edward Jaycox, then World Bank Vice-President for the Africa Region, announced what appeared to be a change of policy at the annual conference of the African-American Institute in Washington DC. He said that the Bank would no longer pay for foreign technical assistants to help resolve African economic problems but would instead help African governments build their own capacity. Although the Bank has traditionally had enormous influence on development thinking and policy worldwide, the apparent policy change does not appear to have influenced other donors. Nor, indeed, is there any evidence that the Bank itself is implementing it vigorously. The number of foreign experts being sent to Africa continues to grow. There were over 100 000 in 1988.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Rationality of investing in people</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">In addition to the negative social impact, ten years of structural adjustment have not produced the sought-after stabilisation or the economic growth that was initally anticipated. Even the World Bank and IMF, who spearheaded the structural adjustment idea, have admitted that it has flaws and the need for a new approach to sub-Saharan Africa's economic problems could hardly be more urgent. In the Dossier, Giovanni Andreas Cornia argues for a new focus for structural adjustment, based on restoring adequate levels of public spending on health, education, social welfare and water supplies, so as to enable sub-Saharan Africa to restore and develop its human resources.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Evidence of the impact of a healthy and educated population on economic growth and development abound. Studies on the economies of the East Asian 'tigers' have all concluded that big investments in education in the late 1950s and 1960s were largely responsible for the rapid growth they have experienced in recent years. Malaysia, although a latecomer, appears to be following in the footsteps of its neighbours. After nearly two decades of investment in human resource development, and the introduction of a foreign investment policy which requires some technology transfer, the Government now predicts Malaysia will achieve 'fully developed' status by 2016-twenty years from now.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">A relatively well-educated workforce and a certain amount of physical capital or natural resources are all a country needs to succeed economically. Sub-Saharan Africa has sufficient natural resources as is often pointed out. The other side of the equation-a relatively well-educated workforce-is missing.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Sub-Saharan Africa lags behind other regions in human resource development for a complex variety of reasons. The natural and political environment are not conducive to the delivery of social services: low population density and weak transport infrastructures make such delivery expensive and the achievement of economies of scale impossible. The region's climate favours a variety of diseases (such as malaria and sleeping sickness) and many areas have little or no access to natural water sources. Political instability and weak institutions also continue to cast a long shadow. Although these constraints are long-term, appropriate policy measures could reduce their negative impact significantly.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Giovanni Cornia analyses the distributive effects of appropriate health care, nutrition and education on economic growth. He suggests ways of making rational use of available resources for maximum returns and of mobilising funds through taxation, foreign aid and other sources.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">In an age of increasing globalisation, where technology is more easily transferable across borders, a healthy and educated population is essential, not only for the absorption and use of new technology but also for meaningful participation in international trade.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">It is insufficient, however, to have an educated workforce. Sub Saharan Africa must acquire the institutional and managerial capacity to make the right decisions, both in the public and private sectors. This is essential in the quest to eliminate poverty, achieve sustained and sustainable economic growth and ensure a realistic integration of the region into the global economy. </P>
+<P ALIGN="JUSTIFY"></P>
+<B><P>&lt;&lt;TOC3&gt;&gt; A much needed new focus for SAPs</P>
+</B><P ALIGN="JUSTIFY">by Giovanni Andrea Cornia </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Over the past two decades, a clear consensus, supported by a growing amount of empirical evidence, has emerged on the growth and distributive effects of appropriate health care, nutrition and education, and on the rationality of investing in human resources to promote development in low-income economies, and in sub-Saharan Africa in particular. It is now clear that public and private rates of return on investment in primary and secondary education are substantially greater than those in most industrial sectors. Similarly, it is now well demonstrated that nutritional interventions in favour of workers at low levels of food intake has a very large impact on labour productivity. Also, provision of simple but adequate nutrition and health care at an early age has been shown to spare substantially greater health outlays over the longer term. While the number of these examples can be multiplied, the lesson is overwhelmingly clear: investing in people is a sound development policy.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">During the same two decades, a broad political consensus has also emerged on the need to establish realistic targets in these areas and mobilise adequate resources to achieve them. The latter decade, however, has also been characterised by a widespread and acute recession which has reached its lowest point in the African continent.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">While there has been a general recognition of the link between the deterioration of the social sector and Africa's economic decline, the interpretations of the causes of this decline and how best to address them vary considerably.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The 1980s also witnessed the advent of structural adjustment, an approach aiming at revitalising economies affected by severe crises and which calls, amongst other things, for a reduction in public spending, including on social services. With sharp falls in revenues, it was argued, African governments could no longer afford to provide health and education free of charge.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Governments were to encourage instead the role of the private sector (since competition between state, private and non-governmental agencies fosters efficiency and enhances quality) and make households bear a greater share of the cost of publicly provided social services (as-it was alleged-households had a strong 'willingness to pay' for better quality health care and education).</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">In a debate characterised by an overwhelming concern for expenditure reduction, little thought was given to protecting the provision and effectiveness of basic health care and education for all. Nor was sufficient attention paid to the mobilisation of additional revenue through taxation, foreign aid or other measures Even the introduction of rationalisation measures, which would have allowed for use and preservation of limited resources, received scant attention. During this period, public policies often ignored a number of well-known public finance arguments concerning market failures, externalities, natural monopolies, etc. typical of basic health and education. It was all too often forgotten, for instance, that the market systematically undersupplies 'quasi-public goods' like education, safe water, immunisation and collective infrastructure (i.e. goods which produce benefits not only for consumers but also for society as a whole); that incomplete or non-existent markets alone are unable to provide complete insurance coverage against the risks of sickness and disability; that the free play of market forces can generate levels of poverty that are socially unacceptable, and that competition among many small providers does not allow for the realisation of the economies of scale which only the public sector can realise because of its size, administrative infrastructure and revenue raising ability.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Greater and better government involvement</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">In this paper, I will attempt to point out the main distortions in the social sector in sub-Saharan Africa and the major reforms, part of an alternative policy paradigm to the standard approach focusing on large expenditure reductions. My main line of argument is for more efficient and renewed but, in most cases, greater rather than less government involvement. I do not deny the important role of communities, nongovernmental bodies and private providers of social services, but the retreat of the state, which has been underway for several years in most of Africa, is palpably wrong: it may be a good survival strategy, it is definitely not a good development strategy.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Any approach to revitalisation of the social sector in Africa must aim at increasing both the quality and the relevance of services to the life, health and productivity of the population; enhancing efficiency; reducing distributive biases in the use of public expenditure, and improving the flow of both public and private resources to the social sector. These sets of measures are briefly discussed here.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Raising relevance, reducing unit costs and enhancing quality</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Two basic initiatives are essential to the achievement of this goal. Firstly, it is necessary to adapt the content of services to the demands placed on the child, the adolescent and the family by the external environment. Secondly, in doing so, it is necessary to provide minimum resources, particularly recurrent inputs, for every unit of service offered.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Much can be done to improve the relevance of education in Africa. A key element in this is the wider use of African languages in the educational system. Admittedly such a step would probably encounter obstacles, but the results of pilot projects in the continent and experiences in several English speaking countries have been encouraging. The use of African languages should be expanded throughout primary and at least part of secondary schooling. And the curriculum of basic education should include basic health science, agriculture, food and nutrition, basic technological science, ecology and environmental studies as well as reading, writing, arithmetic, history, geography and elementary civics.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">While responding more appropriately to the life and developmental needs of children and adolescents, these measures offer the potential to improve substantially the cost effectiveness of the educational system by reducing the number of drop-outs and repeaters, particularly if the measures are accompanied by school-based nutritional support programmes and by steps to ensure a steady, if basic, supply of teaching materials such as books, chalk, slates, pens, exercise books and so on. Minimum expenditures for the latter, estimated at $5-10 per child per year, have been shown to have a profound impact on the quality and attractiveness of education.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Improving the relevance and quality of African secondary and higher education will require an increase in the number of courses in science, engineering, agronomy, management and other fields. Given the limited success of vocational training and yet the profound need for this type of education, a more flexible approach may be appropriate. Business associations and ministries of labour, rather than ministries of education, for example, could organise the type of vocational training that responds more closely to labour market conditions. Much needs to be done to gear university research to local and national needs. Rather than maintaining the model of independent residential universities, faculties could interact more with and rely upon local institutions and non-governmental organisations.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">In the health sector, a more vigorous approach is necessary to implement the 'Health for All' strategy. In particular, more attention must be paid to the quality of the training imparted to village health workers, the provision of minimum supplies of essential drugs, adequate supervision, the mobilisation of communities and the strengthening of family planning services in the first tier of the primary health care pyramid.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Greater efforts are needed to contain unit costs through the mobilisation of community resources (such as materials and time) and the introduction of 'product standards' and 'production techniques' more in line with local factor endowments. With respect to capital expenditure, one major source of potential savings is the substitution of imported materials with local ones in the construction of schools, clinics and other public health facilities. Through this approach, capital costs per student could be more than halved.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">In health care, savings are also possible, in some cases, in wages and other recurrent expenditures. The potential for savings through increased efficiency in the procurement, management, storage, distribution and prescription of pharmaceuticals is substantial. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">And there is a need for more carefully articulated manpower policies, with recognition of the cost implications of alternative skill mixes. Many tasks carried out by senior professionals can be performed by auxiliary personnel. In this regard, there is substantial scope for the application of nominal fees as a tool to guide demand for health care and thus increase efficiency.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Similar considerations are valid in the education sector. Despite considerable declines during the 1980s in both French-speaking and Eastern and Southern Africa, teacher salaries in the late 1980s were still considerably higher than per capita GNP in several countries. While a cutback may be possible in some countries, reductions below the 'efficiency wage' should be avoided as they affect the quality of teaching.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">There are, of course, other approaches to reducing unit costs such as using teachers trained on crash courses and- paid salaries lower than that of fully trained ones, multi shift education to increase teaching hours, multigrade classes to increase class sizes and the creation of regional training centres with donor support. In addition, in most of sub-Saharan Africa, all university students receive fellowships to cover living expenses while at school. In many cases these fellowships represent a substantial proportion of total unit costs at the tertiary level. They add, in effect, to the regressive nature of educational subsidies and should be suppressed for all except for those who are least able to pay.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Improving distribution</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Substantial improvements in the distribution of benefits of public expenditure could be obtained through its restructuring towards basic services which benefit the poor more than they do the rich. This would mean, typically, the reallocation of part of the expenditure on hospitals to primary health care activities and part of the expenditure on universities to primary education. It would also mean that a greater share of investments in water supply and sanitation should be assigned to rural areas.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Correcting existing misallocation, however, is not simple, as capital and labour resources are only partially mobile. This is particularly true of capital expenditure which has already been invested in physical infrastructure. Inter sect oral reallocation is easier for recurrent expenditure, particularly when budgets are expanding, and it can lead to the achievement of more efficient and distributive gains.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Government subsidies need to be improved through effective targeting on 'merit goods' (such as food and shelter). Targeting is distributionally and administratively more effective when it is accomplished according to some objective criteria such as geography (the poorest areas), type of commodity ( low quality foods not consumed by the rich), easily identifiable population group (like pregnant women, young children, children in elementary school in poor areas, etc.) or season. It is less effective when carried out by means-testing or by targeting individuals.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The decentralisation of health care and education in the African context is likely to improve the geographical distribution of services. Poor communications and transport systems, population dispersion and the fact that the supervision of personnel, resource distribution and operations is easier at lower levels of administration, are all arguments in favour of such decentralisation. Nonetheless, where it means loss of control over the implementation of national policies (in curriculum development, manpower training, drug procurement and so forth) and excessive additional financial burdens on households and communities, decentralisation is potentially damaging. This was the experience of Kenya when the purchase of drugs was decentralised at the district level. It subsequently had to reverse this policy because of the problems.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Increasing the flow of resources to basic social services.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Despite the considerable scope for protecting and, in some cases, expanding the delivery of cost-effective and high-impact social services, even during periods of declining resources, there are limits to what can be achieved through the measures discussed above, particularly in countries where the share in GDP of public health and education expenditure is already low. Indeed in most African countries, the flow of resources to these sectors must be vastly increased. The options available include:</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">-Increasing the share of government expenditure on key social services.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Top priority should be given to a radical restructuring of government expenditure involving the shifting of resources towards those sectors with high social rates of return. Expenditure on defence can be cut substantially, while subsidies to chronically lossmaking public and private enterprises and interest payments on debt (the relief effect on foreign-debt interest payments of current provisions is utterly inadequate) should be reduced. If realistic expenditure restructuring like that proposed here were implemented, 1015% of overall public spending in many countries could be redirected to social activities with high rates of return. One half to two-thirds of these savings could be allocated to health care, nutrition, training, education and welfare, thus raising the share of these activities to about 30-35% of total expenditure.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">-Increasing taxation.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Between the late 1970s and the mid-1980s, the average tax to GDP ratio for sub-Saharan Africa fell from 18% to 16-17%. (Only recently are there signs of recovery, but these are confined to only a few countries). This resulted mainly from the recession affecting the region and from the limited priority attached to revenue collection in most adjustment programmes implemented during the first part of the 1980s. In these 'first generation' programmes, the stabilisation of deficits was achieved mainly by cutting expenditure and raising excise duties. Increases in income taxes and progressive indirect taxes were far less frequent and land and property taxes were almost never introduced.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">While taking effect rapidly, the measures implemented led to excessive drops in public expenditure on 'quasi public goods' and have had a regressive distributive impact. It is now widely recognised that a more active tax policy is needed. Such a policy should aim at improving revenue generation and enhancing the efficiency and equity of the overall tax system. This would permit a controlled rise in specific 'socially efficient' public expenditures, particularly basic health, primary and secondary education and public infrastructure.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">In the 1980s, a number of countries, including Burkina Faso, Kenya, Malawi and Zimbabwe, initiated efforts to reform their tax systems. While the choice of optimal tax instruments has depended on specific country conditions, a few general principles of tax reform apply to all countries. First, colonial type tax systems emphasising the taxation of exports (and to some extent, of imports) should evolve towards systems which focus on income taxes, progressive and efficient indirect taxes and increases in the prices of such public utilities as telephone and electricity which benefit mainly the wealthier sections of society. Second, purchases of goods and services consumed by the poorest should be exempted from indirect taxes. Third, efforts should not concentrate on raising marginal tax rates but rather on broadening the tax base by reducing tax evasion and tax elusion, and fourth a low, uniform and broad-based tax on wealth (such as on land or other assets) should be introduced.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">A non-distortionary and equitably-spread increase in the tax ratio equivalent to 2-3% of GPD is technically feasible in a good number of African countries and would by itself add to the real flow of resources to health care and education by about 15%, even assuming no growth and no shift in priorities towards the social sector.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">-Introducing 'earmarked' taxes or raising local ones.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The flow of tax resources to the social sector could be augmented more readily if the new tax revenue thus generated, or at least part of it, were directly earmarked for specific health and education activities (for which there are guarantees that tax money is spent efficiently), or if these taxes were raised directly by district and provincial authorities, who are usually entrusted with responsibility for social services at the local level.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">-Mobilising additional resources from households and communities.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">In sub-Saharan Africa, as in most other developing regions, households have long borne a substantial share of the national expenditure on health, education, water supply and so on by contributing resources (in kind, cash and time) for the construction of health and education facilities, covering direct and indirect costs (transport uniforms, fees, drugs etc.) associated with the provision of public services and making payments to private providers. Despite these already considerable contributions, user charges have been introduced or raised on a large scale in recent years in many countries to alleviate the burden on public expenditure imposed by the economic crisis.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">However, while the small but significant contribution of user charges to health and education budgets should be acknowledged, the negative effects of the indiscriminate application of these charges should also be emphasised. Indeed, in many African countries the need for health care, education and other social services rarely coincides with the ability to pay. The implementation of user charges can have adverse effects in three ways. First, it may lead to a contraction in the demand for services. Second, in the health sector, it tends to discourage the use of preventive services for which potential patients may not see an immediate relevance (such as ante natal care and immunisation). Third, it may adversely affect a household's ability to meet other basic needs, such as the purchase of food, particularly if fees are charged simultaneously for health, education and other services and if the household's income declines. In addition to these problems, there is little evidence that the revenue from user charges is actually reinvested to improve the quality or expand the coverage of local services, as those who promote user charges argue. Despite recent attempts at keeping a share of the user fees at the local level (e.g. at the collecting facilities), in most cases revenue merely flows to the public treasury. Moreover, user charges usually generate a relatively small proportion of the total operating cost of the health care sector, with gross yields at around 5%. If the costs of fee collection are included, the yields are lower and, in some cases, negative.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">However, health care, education and the provision of water include different types of services, some clearly geared to the needs of the poor and others catering more for middle and upper-income groups. While user charges are not well suited to primary education, disease control programmes, basic curative services and communal water supply, the same cannot be said of university education and other 'income elastic' services. For the latter, cost recovery measures would be advisable, although subsidised access for the deserving poor must be assured. For the intermediate category, which includes most curative health services and secondary education, selective cost-recovery measures might be desirable, with low income individuals exempted or charged only a nominal fee.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">While direct user fees (levied on patients at the moment of their treatment) are problematic from several perspectives, there are other indirect ways to mobilise resources from communities (generally before episodes of illness), such as various kinds of prepayment schemes, health insurance, lotteries, mutual funds and the sale of produce from community fields, in addition to their contributions in kind. These schemes have two main features which are attractive for health-care: they shift the moment of payment, so that individuals are not burdened with relatively more significant expenditure at the time of illness, and they spread the burden of costs (e.g. for drugs) over a larger group.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">-Increasing the volume of international aid.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">There has been a considerable shift in official development assistance (ODA) in favour of Africa over the past two decades. Africa's share in total ODA rose from 19.4% in 1975/6 to 25.1% in 1980/1, and to 34.2% in 1988/9. However, the share assigned to human resource development has dropped, while- debt-service obligations have often absorbed a growing share of ODA. Greater flows are therefore needed. In the late 1980s, the World Bank estimated that additional annual aid of about $1 billion was required during the 1990s to halt social retrogression and ensure reasonable progress. But this flow of aid has not materialised on any appreciable scale. Indeed the trend in the 1990s has been towards an absolute decline in aid flows. The simplest and the most cost-effective way to effect such aid transfer would be through debt relief, although some increases in ODA are needed. Improvement in the quality of aid, including substantial shifts to programme aid, greater participation in the financing of recurrent costs and more focus on primary health care and education and on rural water supply are also required.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">What role for NGOs and private providers?</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">While private providers, including church missions, have always been important in Africa, much of the market oriented literature tends to be very optimistic about the scope for expanding private services in order to replace government ones. Although a multiplicity of providers is desirable (and frequently unavoidable), there are several reasons why such optimism should be tempered. First, private sector services in Africa are typically concentrated in urban areas, and because of their cost, cater for upper-income groups. Although non-governmental providers (especially missions) are often located in rural areas, and they generally provide valuable services, they are seldom able to guarantee extensive coverage and in some cases may duplicate government services. Second, private providers are not without costs to governments; they often receive subsidies or preferential treatment in the allocation of foreign exchange and typically offer higher salaries and better working conditions which draw manpower away from the public sector. In Zambia, for instance, a teacher in a primary school run by the Consolidated Copper Mines can earn more than a lecturer at the University of Zambia. In countries with extremely limited numbers of doctors, certified nurses, qualified teachers and so on, greater privatisation would exacerbate the 'brain drain' from the public to the private sector and the undersupply of 'quasi public goods' for the majority, leading to harmful social differentiation. Third, quality is not necessarily an important incentive in the private sector in developing countries. The view that private institutions in health care and education are more efficient tends to be based largely on analyses in developed countries. Fourth, the growing pressure for pluralism in social service provision often gives scant attention to the problems of central coordination and planning and the development of an adequate 'regulatory framework' for private sector activities. While playing an important complementary role, the private sector and, to a lesser extent, the NGO sector, are thus affected by important objective limitations. Indeed, ironically, their proper functioning and social utility depends crucially on the existence of a stronger, not weaker, state able to regulate, coordinate and ensure that basic social services are provided - possibly through a multitude of public, NGO and private providers-to all citizens of a nation. G.A.C</P>
+<P ALIGN="JUSTIFY"></P>
+<B><P>&lt;&lt;TOC3&gt;&gt; Capacity building for management and development</P>
+</B><P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">by Franklyn Lisk</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The development experience of much of sub-Saharan Africa in past decades provides ample illustration of the importance of capacity building in the development process. The importance is related to the ability to manage economic and social processes, including the analysis and formulation of policy options, for attaining development objectives such as employment generation and poverty reduction. The consequences of failures in domestic economic management, compounded by the effects of a prolonged economic crisis in the region have, inter alla, contributed to high and rising levels of open unemployment and underemployment, declining per Capita incomes and real wages, and an increase in the incidence and intensity of poverty in a number of African countries. The persistence of these adverse consequences, which represent a serious threat to economic growth and sustainable development, are somehow linked-either as a cause or an effect -to weaknesses and instability in the institutional framework for management and public administration.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The problem of weak institutional and general capacity for management in Africa today can be traced to the colonial legacy. This left many countries in the region, at the time of independence, with insufficient institutional and human capacity to cope with the transition from colony to independent sovereign state, particularly with respect to the responsibility for economic management. More specifically, this related to the unequal and disadvantageous manner of Africa's incorporation into the international economic system in the late 1950s and the early 1960s. Lack of technological know-how, inadequate infrastructure and limited investment resources compounded the immediate post-independence problem of weak institutional capacity, and left many African countries highly vulnerable to external shocks.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">It was extremely difficult for the majority of African countries to break out of the old 'protected' colonial production and trade systems and rapidly to diversify their economies in line with the requirements of participating effectively in a competitive world economy. Since independence, institutional and human capacity for management in many African countries has not grown fast enough to keep up with the requirements of changing socioeconomic circumstances at the national level and to face the challenge of increasing globalisation. Critical skill shortages in public administration and private sector management in Africa can hardly be addressed in the context of the current economic crisis. The consequences of this crisis can be seen, for example, in underfunded and poorly equipped training and management development institutions, and in low-paid and demoralised civil services. At the same time, the 'brain drain' from the continent, partly as a consequence of poor pay and career prospects, has further undermined capacity in Africa. The interaction of foreign donors and African governments has not always served the interest of capacity building. It has been admitted, even by the World Bank that 'aid has done much less than one might have hoped to reduce poverty (in Africa)'. There is now more or less a consensus in the international donor community that expatriate technical assistance does not and cannot solve all kinds of development problems in the region. Far from solving problems, the imposition of foreign technical assistance has, in some cases, become a destructive force which undermines the development of domestic capacity that is critical to solving local development problems. Where donor assistance is inappropriate in terms of project concept and design, or there is a mismatch between design and domestic implementation and management capacity, technical assistance could end up becoming part of the problem rather than the solution.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Conceptual issues</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Before examining the requirements for institutional capacity building in developing countries, and particularly African countries, it is necessary to clarify salient issues pertaining to the concept. Broadly speaking, capacity building in a development context refers to a comprehensive process which includes the ability to identify constraints and to plan and manage development. The process usually involves the development of human resources and institutions, and a supportive policy environment. Ideally, it aims at improving on existing capabilities and resources and using them efficiently to achieve sustainable economic and social development.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Narrowing the concept to focus on institution-building, the emphasis will be on the development of particular institutions, their human and material resources, their organisational management and their administrative capacities. More specifically, the aim of institutional capacity building is to improve significantly the outputs and impacts of institutions concerned with economic management, public administration (including project management), enterprise development and so on-in both the public and private sectors. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">It is obvious that relevant development-oriented institutions within an economy can exert a decisive influence on economic growth and employment prospects, and indeed on the attainment of sustainable economic and social development. From a macro standpoint,planning and similar development institutions are required for better management of the economy including, more crucially, the ability to mobilise, allocate and utilise human and material resources in an efficient and productive manner. At the micro level, human and institutional capacity is critical to sound project management and public administration.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The framework</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The general situation in Africa today suggests that capacity building is required in relation to the following priority areas:</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">- good governance, to ensure stability;</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">-economic management, to maximise resource mobilisation and promote sustainable development;</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">- human resource development, to support employment creation and income generation, and reduce poverty;</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">- science and technology, to increase the efficiency of the population and facilitate infrastructural development;</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">-enterprise development, to enhance the critical role of the private sector in overall development.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The degree of emphasis given to each of the above in a given context would vary according to the level and complexity of existing human and institutional capacities, the economic and financial means to support capacity, the relative roles of the public and private sectors, and the degree of involvement of civil society in the decision-making process.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The policy context for institutional capacity building should be multi-sectoral and flexible, but coherent in relation to the desired objectives of development. This is to ensure that the process of capacity building is adaptable to changing circumstances-an issue that is particularly relevant in the context of countries undertaking structural adjustment and economic reform programmes when there is a need effectively to nurture and utilise local skills and to mobilise investment resources efficiently.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">In the light of the development challenge facing African countries, the process of capacity building in the region requires, above all, appropriate and adequate human and institutional capabilities to plan and manage economic and social development processes. These capabilities should include the means of assessing the achievements and impact of capacity building on poverty reduction, employment creation, etc. Existing public sector institutions for development planning and management could provide the operational framework for national capacity building, but the process should also include the participation of diverse social forces, the private sector and non-governmental institutions.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Regarding the role of external donors and technical assistance agencies, the approach should be based on the concept of 'partners in development', which implies consultation and dialogue between donor and recipient on all aspects of project planning, design and implementation- with project 'ownership' resting with national authorities. Technical assistance from foreign donors should therefore go mainly towards developing the necessary domestic capacity, rather than contributing to the undermining of existing or potential capacity. Furthermore, assistance provided by external donors should be directed towards the building of capacity for promoting regional economic cooperation and integration through support for the development of viable African regional and sub-regional development organisations.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Support initiatives</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The issue of domestic capacity building in Africa has more recently been the focus of attention by the international community as a whole. Indeed, the former World Bank vice-president for Africa, Edward Jaycox, has described 'capacity building' es the 'missing link in African development' which is 'critical to the development effort (of the region) and the chances of success'. UN agencies, spearheaded by the UNDP, have been active in promoting capacity building as a major requirement for attaining sustainable development. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">In 1991, the UNDP Governing Council took a decision which resulted in the development of guidelines covering assistance to governments in the formulation and implementation of national capacity building strategies relating to all stages of the project cycle in the developing countries. The decision coincided with the introduction of the 'programme approach' by the UNDP which emphasised the centrality of national development programmes as the hub for the integration of UN technical assistance activities with national efforts. Emphasis on the use of national skills in the development process was consolidated within the general operational framework for 'national execution', which implied that overall responsibility for management of UN operational activities and accountability remained with the government and other national institutions and beneficiaries who 'owned' these activities. Under these new arrangements, a high priority was thus placed on the strengthening and sustaining of development management and administrative capacities on a long-term basis as an integral part of UNDP technical assistance.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The World Bank's interest in capacity building in Africa has been more closely linked to the need for administrative and technical capacity at the national level to carry out policy analysis and economic management in the context of on-going structural adjustment and economic reform programmes. In a trailblazing address to the African American Institute Conference in 1993, Mr Jaycox came out strongly in favour of a new approach to lending to African countries which gave top priority to the development of critical human and institutional capacity. He admitted that the Bank's $4 billion a year lending programme in sub-Saharan Africa had not had the desired impact on development in the region because not enough attention had been paid to national capacity in the past. He went on to criticise the international donor community and financial institutions, including the World Bank itself, for designing and carrying out technical assistance activities which not only fail to solve problems but end up undermining the development of capacity in Africa. Mr Jaycox accordingly pledged to give direct support to capacity building in the Bank's lending programmes, mainly through human resource development and the creation of a 'demand for professionalism in Africa.'</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The UNDP, the African Development Bank and the World Bank, collaborated in the early 1990s to set up the 'African Capacity Building Foundation' (ACBF), based in Harare, Zimbabwe, with initial seed money of about $30 million and another $70 million attracted from bilateral donors and African governments themselves. The fund is to be used by the Foundation to support capacity building in Africa through training and institution building. Particular attention will be paid to the rehabilitation and strengthening of selected research and training institutions to meet the challenge of indigenous capacity building. Another initiative set up with foreign donors and African support, the Africa Research Consortium in Nairobi, is a good example of collaboration at regional level that is contributing to capacity building in the critical area of economic policy analysis and management. Similarly, the African Development Bank helped establish the African Business Round table which promotes entrepreneurship and enterprise development based on African ownership and control.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Role of the ILO</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">For well over three decades the ILO, as part of its technical cooperation programme in Africa, has been involved in a wide range of management development, productivity and institution building initiatives at both national and regional levels. This is consistent with the need to strengthen African training institutions to play a crucial role in providing development managers with the necessary skills to analyse and formulate policy options and manage public and private enterprises efficiently.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">One of the most successful initiatives undertaken by the ILO, in collaboration with the UNDP and the Economic Development Institute (EDI) of the World Bank, is the UNEDIL programme for strengthening management training in Africa. Since its inception in 1987, the UNEDIL programme has proven to be a worthwhile initiative in institutional capacity building in the management field. Support for the programme has also come from national and regional management development institutes (MDIs) in Africa, regional and sub-regional organisations such as SADC and the Commonwealth Secretariat, and major bilateral donors such as USAID, CIDA, NORAD, the Netherlands and France.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Apart from aiming at strengthening institutional capacity, the UNEDIL programme has been instrumental in fostering networking among African development institutes and promoting professional contacts and the exchange of experience. One outcome of the programme has been the revival of three subregional MDI associations which enjoy the direct support of UNEDIL and serve as focal points for UNEDIL's subregional networking arrangements.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Networking on a subregional basis has made it possible to optimise the use of scarce resources and talents, and this has helped to increase managerial capacity in the region as a whole. Collaboration has also permitted an exchange of experience among African institutions, and has brought together expertise both from within Africa and from outside to assist in the development of managerial capacity across the continent. This fits in with the goals of technical cooperation in general, and of South-South cooperation in particular. </P>
+<P ALIGN="JUSTIFY">F.L. </P>
+<P ALIGN="JUSTIFY"></P>
+<B><P>&lt;&lt;TOC3&gt;&gt; The role of international academic cooperation</P>
+</B><P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Increasing demands and diminishing resources in higher education</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">by Professor Dumitru Chitoran</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">As we approach the end of the millennium, higher education world-wide finds itself in a paradoxical situation. On the one hand, it is witnessing unprecedented growth. Enrolments are on the increase and so are the expectations placed on it by society. The correlation between investment in higher education and research, and the level of social, economic and cultural development of nations is well-established and is gaining increasing ground at a time when all development has become knowledge-intensive. On the other hand, higher education is in a state of crisis in practically all countries of the world, under the pressure of serious financial constraints. It has to compete for public funds with many other sectors and very often it is among the first to undergo severe cuts. These cuts have reached a dramatic threshold in the developing countries. As a result, the gap between the developing and the developed countries with regard to higher learning and research is wider than ever and it continues to grow.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Inter-university cooperation has emerged as a major tool for the support of higher education in the developing countries and as a flexible mechanism for the rapid transfer and sharing of knowledge, channelled via university links and exchanges. As emphasised in the Policy Paper for Change and Development in Higher Education issued by UNESCO in 1995, 'the most pressing need for international cooperation in higher education is to reverse the process of decline of institutions in the developing countries, particularly in the least developed.' The internationalisation of higher education has advanced steadily, reinforced by current processes of economic and political integration and facilitated by the steady advances in information and communication technologies. But, as indicated in the UNESCO World Education Report (1993), it is increasingly subject to the competitive laws of the market. Universities have been urged to develop an entrepreneurial, commercial attitude and to regard international cooperation mainly as a source of additional income. Fees for foreign students have risen considerably in many countries. As a result, academic mobility is becoming more North-North and less South-North or South-South. The benefits of study abroad, of exchanges, networking and access to data are recognised, but the costs involved render them increasingly a privilege, restricted to those who can afford it.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">An innovative programme</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">UNESCO's response to these trends was the UNITWIN/UNESCO Chairs Programme, launched in 1991. While serving as an instrument to foster overall inter-university cooperation, it was aimed at giving a clear direction and goal, namely to support higher education in the developing countries. It was meant to mark a return to the spirit of international academic solidarity, through twinning, networking and other linking arrangements among universities. The programme was also designed as an innovative form for the rapid transfer of knowledge, and for institutional development in higher education, including the establishment of transnational centres for advanced studies and research, as a means of redressing the widening knowledge gap between industrially developed and developing countries. One other aim of the Programme was to alleviate the negative effects of the brain drain.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The UNITWIN/UNESCO Chairs Programme has seen steady and dynamic development from the very beginning, and has emerged as the major thrust of UNESCO's action in the field of higher education. The favoured institutional framework for carrying out activities is a UNESCO Chair. The programme's activities are extremely diverse. They include the appointment of visiting professors, provision of scholarships and fellowships, facilitating of staff and student exchanges and undertaking of joint research. The 'chairs' are typical of basic units of research and training, with a strong international dimension, since either the chairholder, or some of the professors or researchers associated with its programme come from abroad. Other projects involve complex inter university networks, varying in size from three to more than 50 institutions. Within networks, certain institutions serve as focal points, responsible for initiating activities and securing broad participation in their execution. Also included are cooperation programmes established by UNESCO with major university associations and networks in order to carry out UNITWIN-related activities.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">At present, there are 163 established UNESCO Chairs (a further 84 are under consideration) and 34 largescale networks (18 more are being developed). A total of over 750 teachers, researchers and other support staff are involved in their activities. It is estimated that 350 courses (mainly at the graduate level), attended by more than 7500 students, were organised by the established UNESCO Chairs during the 1992-1996 period. Also, 120 seminars, training workshops, symposia and colloquia were staged over the same period, attended by more than 6000 participants. Some 580 academics from developing countries spent short periods of time at partner universities in the developed countries to upgrade their training. In addition, 355 scholarships have been granted to students and young academics from developing nations within the framework of the Programme. Research has been encouraged through 240 projects (mainly joint ones) resulting, according to progress reports received so far, in the publication of 55 volumes, some 100 published articles and over 150 monographs and progress reports.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The ACPs in the programme</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">A large number of these projects (UNESCO Chairs and networks) concern ACP countries. Africa has been given top priority. Over 30 of the established Chairs are located there and 18 more are under consideration for subSaharan Africa, in order to reinforce the contribution of the programme to the development of higher education in this region. In addition, certain projects located at institutions in Europe and North America carry on activities which are designed to support African universities. A few examples illustrate this. Starting from its bilateral links with several African universities, the University of Utrecht proposed developing these into a broader, multilateral project under the umbrella of UNITWIN. For this purpose, it joined forces with three other European institutions: the University of Lund in Sweden, the Ruhr University in Bochum, Germany and the University of Porto in Portugal. The result was the establishment of the Utrecht/Southern Africa/UNITWIN (USU) network. It includes, at its southern pole, the universities of Harare, Maputo, Namibia, and Western Cape, where UNESCO Chairs have been established in different fields. The aim is to develop each of them into (sub)regional centres of advanced study and research. This is well under way in the case of the UNESCO Chair in Mathematics and Science Education at Western Cape University in South Africa. A first step was to link its activities to those of the MESA (Mathematics Education in South Africa) project, a cooperation project between the Utrecht-Freundenthal Institute for Mathematics Education and the University of the Western Cape. A school for Science and Maths Education is to be established at the University of Western Cape.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Another large scale project is the Network of African Teacher Training Institutions, built around a UNESCO Chair at the Ecole Normale Superieure in Dakar. This is designed to serve as a regional centre for postgraduate training and research in the field of education. After several years preparation, activities were launched in 1995. The strength of networking is illustrated by a number of other linking arrangements in support of African higher education institutions. These include the network initiated by the NATURA Group of European universities in the field of agriculture, the ORBICOM Network in the field of Communication, which is a global network but pays particular attention to the needs of African universities, and the UNESCO/John Hopkins University Networking and Partnership in Adolescent Youth Health and Development. The last-mentioned focuses on HlV/AIDS-related research, and includes institutions such as Addis Ababa and Makerere Universities.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The agreement signed by UNESCO with the Association of African Universities (AAU) within the framework of UNITWIN provides for support of the latter's staff development and management programme. A UNESCO Chair in Educational Management and Administration is to be established. It will function on a rotating basis at several universities in South Africa, Botswana and Malawi. There are also a number of 'tailor-made' chairs which respond to more specific needs of institutions, notably to develop training and research capabilities in areas such as human rights, democray and peace (at the Universities of Namibia, Addis Ababa and Fianarantsoa in Madagascar), or in the field of Water Resources and Water Culture (at the Universities of Malawi and Omdurman in Sudan). In the latter field, an interesting example is the UNESCO Chair established at the University of Nice, which, although located in France, carries out its activities in Mauritania and has produced the most comprehensive study so far on water resource management in that country.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The programme has also made a good start in the Pacific and the Caribbean, even if achievements there are on a more modest scale. There are already 22 established chairs with 14 more under consideration. They cover a wide spectrum of priority fields, including the sustainable use of rain forest resources at the University of Guyana, higher education management and information technology at the University of Havana in Cuba, educational sciences in Fiji, and the use of drugs in Chulalongkorn University in Thailand.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">UNESCO works closely with the University of the South Pacific and the University of the West Indies, with which it has established four UNESCO Chairs. Moreover, it has signed a cooperation agreement, in the framework of UNITWIN, with the Commonwealth Secretariat and the Association of Commonwealth Universities for activities in both regions. There is great potential for the further development of the Chairs programme in the Pacific and Caribbean, given the existence of the two regional universities mentioned above and the strong interest of universities in a number of developed countries (such as Australia, Canada, Japan and Spain) in supporting the programme. It appears to be particularly well suited for the systems of higher education in the two regions.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Funding</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The cost of international cooperation in higher education has risen steadily and this is currently one of the major obstacles preventing the full use of the potential of academic links. New information and communication technologies help reduce costs, but universities in the least-developed countries would first need considerable investment in order to procure and maintain the necessary equipment. That is why UNESCO has based the Chairs programme on funding principles aimed at lowering costs and sharing them in a genuine spirit of academic solidarity.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">At the outset, UNESCO made it very clear that, since it was not a funding agency, it could not, by itself, assume the financial burden of such an ambitious programme, involving several hundred institutions and thousands of university teachers, researchers and students. However, it decided to make a commitment by providing some initial funds. Rough estimates indicate that, over the 1992-1995 period, UNESCO has contributed some $2.5 million (from its Regular and Participation Programmes, Fellowship Bank and Funds-in-Trust) to the UNITWIN/UNESCO Chairs Programme. At the same time, it has pressed for increased international development aid for higher education, particularly from the developed countries, and from international organisations, including the UN specialised agencies. A strong case is made for the benefit of pooling resources and for involving directly the higher education institutions themselves </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">UNITWIN-based projects, including UNESCO Chairs, are usually initiated through the direct contributions of UNESCO (the range is generally between $15 000 and $25 000 per individual project). This is meant to help prepare and launch projects and to secure further funding from other sources. The institutions themselves must include allocations for the respective projects in their own budgets and request their appropriate national authorities to make contributions. This applies equally to universities in the developing countries, however poor their resources may be. It serves to indicate that the project in question is indeed seen as a priority by them and by their national authorities.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Experience of the UNITWIN funding formula so far gives cause for cautious optimism. Many projects have been able to secure funds by having recourse to the various sources mentioned above. Thus, the Utrecht/ Southern Africa/UNITWIN Project received a first UNESCO allocation of $50 000 in 1993, in order to launch its activities. The fact that it concerned a large-scale project (a network of eight universities, with four chairs established at four African universities and one at the University of Utrecht) explains the larger UNESCO allocation. This was followed by a second allocation of $70 000 in 1994 for the actual implementation of activities in Africa. The UNESCO seed money led to additional funding-$600 000 annually, for the 1992-1995 period, from various Dutch donors (mainly the Ministry of Development Cooperation, through NUFFIC) and from the European Union, and $450 000 from the University of Utrecht budget, including the total cost for the functioning of the UNESCO Chair on African Studies established at that university. The other three European universities participating in the network (Bochum, Lund and Porto) have also made contributions and are now looking for donor funding in their countries. It is important to mention that the four African universities belonging to the network have also allocated funds from their own budgets to the UNITWIN projects and are actively seeking additional resources from aid and development programmes established for their countries by various donor agencies.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">It can be fairly argued that in terms of cost-effectiveness, efficiency and the ability to generate funding from various sources, UNITWIN compares favourably with existing cooperation schemes in higher education and research. But it is still too early to conclude that the Chairs Programme can continue and develop further on the basis of the present funding arrangements. The needs are arguably too big for the institutions and individuals involved, who may find themselves in a perpetual search for funds. An evaluation of the programme is under way and this will be submitted to the Member States for their decision. UNESCO is hoping that its efforts to revive academic solidarity, and its campaign in favour of higher education in the developing countries will receive the support of the international community. More than ever before, these countries need to develop their capacity for advanced training and research in order to achieve self sustainable development. The academic community has already indicated its willingness to join forces with UNESCO in this undertaking. </P>
+<P ALIGN="JUSTIFY">D.C.</P>
+<P ALIGN="JUSTIFY"></P>
+<B><P>&lt;&lt;TOC3&gt;&gt; Brain drain : Colossal loss of investments for developing countries</P>
+</B><P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">When a highly qualified professional chooses to leave his own country for another, he does so for one or several legitimate political or economic reasons: peace and security for himself and his family, job satisfaction, better pay and conditions. a higher standard of living, etc. Throughout history, countries and centres of academic excellence which offer these attractions have received the largest numbers of professional migrants and these have, in turn, made substantial contributions, not only to the economic growth of their host countries, but also to the scientific and technological advancement of humanity. The wave of German scientists who moved to the United States after the Second World war, and their discoveries and inventions, come readily to mind. On a global level, therefore, the free movement and interaction of highly skilled people is a positive thing. But the costs to the home countries of losing their professionals is incalculable-in terms of both development opportunities and loss of investment.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Whereas Western Europe was the main loser, especially to the United States, up until the 1960s, the developing countries have emerged in recent years as the biggest suppliers of qualified professionals to the industrialised world as a whole. Today there are more than a million and a half skilled expatriates from the developing countries settled in Western Europe, the USA, Japan and Canada. The USA's educational system and its research institutions are heavily dependent on them. These migrant professionals contribute in no small way to increasing the disparities between the world's rich and poor nations. And it is the developing countries that need them most.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Africa, which has serious shortages of manpower, has been worst hit. It is said to have lost 60 000 professionals (doctors, university lecturers, engineers, surveyors, etc) between 1985 and 1990 and to have been losing an average of 20 000 annually ever since.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">There are more than 21 000 Nigerian doctors practising in the United States alone. Meanwhile, Nigeria's own health system suffers a cruel lack of medical practitioners. 60% of all Ghanaian doctors trained locally in the 1980s have left the country, according to the UNDP's 1992 Human Development Report, while, in Sudan, 17% of doctors and dentists, 20% of university lecturers, 30% of engineers and 45% of surveyors have gone to work abroad.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Although it is difficult to calculate the cost of an expatriate professional in terms of the nutrition, health care and education provided by households and the State, it is clear developing countries are losing colossal amounts of investment annually to the developed countries.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The US Congressional Research Service, for example, computed in 197172 that the USA gained $20 000 annually on each skilled migrant from the developing countries. If this rather conservative amount is extrapolated for Africa, then the continent lost more than $1.2 billion of investment between 1985 and 1990 on the 60 000 or so African professionals who emigrated during that period. Much closer perhaps to the truth today would be the estimate made by the United Nations Conference on Trade and Development (UNCTAD), using 1979 prices, which put a cash value of $184 000 on each African professional migrant (and this only for those between the ages of 25 and 35).</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">On the other hand, expatriate remittances, particularly from skilled workers who earn higher salaries than the average migrant, constitute an important source of funds for development in their home countries. Throughout Africa, households are being maintained by remittances from relatives working abroad. Also, fine buildings are being put up and small-scale projects are financed in villages and cities across the continent with funds sent from overseas. But taken together, these will never be large enough to compensate Africa for the loss of investment suffered as a result of the 'brain drain'.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Serious flaw in international cooperation</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The migration of highly qualified professionals from the developing countries is an extremely complex problem which presents the international community with a major dilemma. First, the 'brain drain' cannot be stopped by force nor can it be legislated against. It is linked to fundamental human rights- the right of individuals to move from one country to another, although the exercise of that right is governed by the immigration policies of individual countries. Second, it is fundamentally a national problem which can only be resolved at the national level by providing enough incentives for qualified nationals to remain at home. Third, some industrialised countries like the USA and Canada, have historically operated liberal immigration policies. Even European states, whose immigration policies tend to be more restrictive, have a good number of third world professionals, but there are over a million in the USA and Canada. It is arguable whether, under the circumstances, the liberalisation of the international labour market under the World Trade Organisation, as is being suggested (even by some developing countries), will actually be in Africa's interests.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The reasons for Africa's brain drain problem are legion and easily identifiable, being both structural and economic. The most often cited cause is the continent's school curricula which many see as still largely modelled on the systems of the former colonial masters. This, it is argued, has led to the production of graduates in disciplines that have little or no relevance to the socio-cultural and economic milieux of the continent. This is a highly debatable assertion, given the large numbers of the technical assistants currently working in Africa who are products of the educational systems of the former colonial powers-at least some of whom are having a positive impact on the continent's development. This, however, must not distract from the fact that African higher schools systems are illequipped to produce the right skills for Africa's development needs. Because of shortages of both science equipment and teachers, the system instructs the vast majority of pupils in arts rather than in science and technology-and it is the latter which hold the key to economic growth and development. Thus, there is overproduction of graduates in areas where there are few employment opportunities. This results in high levels of migration, even, paradoxically among the few trained scientists because of the absence of an environment conducive to full professional expression and satisfaction. It is not uncommon for things as simple as electricity and water supply to provide reasons for emigration. Examples abound of frustrated African scientists who have had their experimental work of several years destroyed overnight through power failures.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Powerful factors in the brain drain include Africa's poor rates of economic growth over the past 30 years (worsened by structural adjustment measures which have resulted in dramatic falls in living standards) and political instability (disturbances in Nigeria and Zaire, civil war in Liberia, Sierra Leone and Somalia etc). Thousands of qualified professionals have been forced unwillingly into exile, and the majority of those left behind, in these times of serious economic crisis, are engaged in unskilled pursuits-in petty trading and taxi driving-far removed from their professional training. The loss of investment associated with this situation cannot be underestimated.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Sub-Saharan Africa is in the paradoxical situation today of having large numbers of graduates in various disciplines -from medicine and engineering to architecture and accountancy-who have either emigrated or are simply unemployed, while it hosts a large army of foreign technical assistants. Indeed, Africa receives more advice per capita than any other continent. In 1988, there were more than 80 000 technical assistants, and today the figure is well over 100 000. These experts are believed to cost donors a total of $4bn annually to maintain, a figure which represents nearly 35% of Africa's total official development aid. This situation reveals a serious flaw in the operation of international development cooperation. Would it not be more efficient and cost effective to employ qualified African expatriates in the place of many of these foreign technical experts. The former, after all, have both linguistic and cultural links with the continent. The United Nations Development Programme (UNDP) has a programme in this area which points to a possible way forward. The article on that programme, TOKTEN, follows. </P>
+<P ALIGN="JUSTIFY">A.O.</P>
+<P ALIGN="JUSTIFY"></P>
+<B><P>&lt;&lt;TOC3&gt;&gt; 'Brain gain' : A cost - effective UNDP programme</P>
+</B><P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">On the scale of the brain drain problem facing the developing countries, the UNDP's Transfer of Knowledge Through Expatriate Nationals (TOKTEN) project may not amount to much, but it has proved, in its 19 years of existence, to be a cost-effective way of getting highly qualified expatriates from the developing countries to contribute to the development of their countries of origin.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">It all started in Turkey in 1977 by pure accident. A Turkish mineral expert in Alberta, Canada, was asked by a compatriot if he would be kind enough to come over to Turkey and explain his innovative coal cleaning process to the staff and students of his old university in Ankara-the Middle East Technical University. He expressed his interest in the project. Soon afterwards he was contacted by the UNDP which offered to fund part of his trip to Ankara. The expert spent one month in Turkey giving a series of seminars, not only at the Middle East Technical University, but also at the Istanbul and Dokuz Eylul Universities. During these lectures, he made recommendations on resolving Turkey's specific coal utilisation problems. His impact was immense and such that the UNDP was inspired to set up the TOKTEN project along similar lines to help developing countries gain from the knowledge of their expatriate professionals.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The system is simple. Member States of the United Nations can apply to join the project. The latter is administered in each country by a National Working Commitee (NWC) which is made up of representatives from the government, local organisations, the private sector and the UNDP. Institutions of that country (government ministries and agencies, private and public sector enterprises, universities, research and development institutions, hospitals, etc) can apply for assistance in a variety of areas.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Applications are processed by the NWC and recruitment of experts is usually in one or more of the following ways:</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY"> through consultants with lists of experts recognised by the Government as having extensive contacts within their expatriate communities;</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY"> through embassies and missions, alumni associations and research institutions;</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY"> through prominent members of the country's expatriate community who identify and alert other high level expatriates of the opportunities to return home and serve their countries.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">When the Working Committee chooses a consultant, an offer of assignment is made. The beneficiary organisation and the consultant will then determine the timing of the mission and inform the UNDP.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">TOKTEN assignments last between one and three months depending on the ability of the consultant and the needs of the beneficiary'. They are not meant to be highly remunerative. Consultants are only entitled to round trip economy fare tickets (by the most direct route) and a daily subsistence allowance at the prevailing UN rate. The costs are paid out of the beneficiary country's 'Indicative Planning Figure'(IPF) which is the amount of assistance the UNDP makes available to a developing country over a five-year programming cycle. Health insurance cover and accommodation is not provided. Usually these are the responsibilities of the beneficiary government or organisation. The salaries of the consultants during their absence are paid by their affiliated employers whose agreement is often necessary for the projects to go ahead.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">TOKTEN consultants are thus not motivated by money but by a genuine desire (with a modicum of patriotism) to contribute to the development of their countries of origin to which they retain strong cultural and linguistic ties. And their impact on the ground is usually immediate and measurable. Pressures are not put on volunteers to return permanently to their countries, although many have chosen to do so since the programme began in 1977.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The system is not only low-cost and cost-effective. It covers a great variety of specialised fields and enables programmes to be implemented with speed.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Conditions for success</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">A UNDP assessment of the programme in 1987, ten years after it began, concluded that regular monitoring of its operation had enabled information garnered to be applied to increase its effectiveness. It had been found, for example, that short-term expatriate consultancies were especially beneficial when the problem tackled was specific and the consultant selected was of international standing, when both the requesting organisation and the expatriate were well prepared in advance, and when the initial mission was followed up by a series of measures, often including a return visit.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">By 1992, 35 countries were participating in the programme and over 3800 consultancies had been run. Since then, the number of countries has increased dramatically to 51 and con</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">sultancies to 5000. In 1994 and 1995 alone, 28 countries reported over 700 consultancies.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">It has also become clear that, whereas the main recipient institutions have been government agencies, science and technology research institutions, universities and organisations, the private sector is increasingly showing interest in the programme. The number of female specialists is also increasing: in 1991, 40 consultants were women and last year this figure rose to over 100.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">So far, the ACP countries participating in the programme are; Benin, Cape Verde, Central African Republic, Chad, Dominica, Ethiopia, Fiji, Guinea, Guyana, Haiti, Liberia, Nigeria, Sao Tome &amp; Principe, Sierra Leone, St Lucia, Trinidad &amp; Tobago and Uganda.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Success stories include a highly skilled Guyanese medical practitioner in the United States who returned home after 17 years to assume the post of minister of health. He had been sent to oversee the introduction of certain aspects of health care such as preventive medicine (immunisation, general child care and nutrition), treatment of trauma (victims of accidents and violence etc) and the establishment and management of the physical facilities for emergency patients. During his stint, his recommendation on the upgrading of the emergency room facilities was rapidly implemented and this contributed significantly to improving patient care. Another story involved a Guinean banker who, after a consultancy stint in Guinea, abandoned a lucrative job in France to return home permanently to work at the Central Bank of Guinea, helping to set up a new loan system for commercial imprt and export businesses. Guinea, in fact, has been one of the greatest beneficiaries of the TOKTEN programme with numerous consultancies involving the University of Conakry, covering more than 20 disciplines.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">For very small sums the programme is ensuring that developing countries which have invested enormously in the education of their expatriate nationals have a return, at least, in the form of the knowledge they oquired.</P>
+<P ALIGN="JUSTIFY">A.O </P>
+<P ALIGN="JUSTIFY"></P>
+<B><P>&lt;&lt;TOC3&gt;&gt; Mobilising Commonwealth skills for Commonwealth development</P>
+</B><P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The role of the Commonwealth in the economic and social progress of its member states is neither widely known nor widely publicised. Yet for over 25 years, the Commonwealth Fund for Technical Cooperation (CFTC) has made significant contributions to the efforts of its developing member countries to accelerate the pace of their economic development.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The recognition by the Commonwealth that people are its greatest resource forms the basis of its approach to development assistance-providing, in the short term, specialist technical skills which are either not available or are in short supply to governments to enable them to fill key positions in areas as diverse as export and industrial promotion, high-level economic and legal services etc, and in the longer term, a wide range of training programmes in areas that are crucial for economic development.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The Commonwealth Fund for Technical Cooperation is funded by voluntary financial contributions from member governments which, as has just been mentioned, can also draw on it according to their needs and priorities. As a pioneer of technical cooperation between developing countries, the Fund recruits its experts from these countries and encourages South/South cooperation. It is thus not uncommon to see West Africans serving, on short-term contracts, as legal officers in remote Pacifc island states or Sri Lankans or Indians advising on new agricultural techniques in Africa. The Fund is administered by four separate divisions within the Commonwealth Secretariat: the management and training division; the general technical assistance division; the export and industrial development division, and the economic and legal advisory services division. In 1994-95 the CFTC's financial resources stood at around f23.6 million (ECU 30m).</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Human resource development</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Nearly one-third of the CFTC's budget is spent on human resource development, helping enhance people's skills through a mix of training workshops, study visits and individual attachments.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Some 4000 training fellowships were awarded in 1993-95 to enhance technical skills. These were given to middle and senior professional, technical and administrative managers to study at some of the Commonwealth's best institutions or to take up work attachments (63% of training takes place in less-developed countries).</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The Fund also enables universities and other institutions to become centres of excellence and upgrade the tuition they offer by appointing academic and technical specialists. In 1993-95, for example, it helped five universities in Africa and the Caribbean to run applied Masters courses through collaboration with other Commonwealth universities.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">As the CFTC is usually able to meet only 60% of the requests it receives for specialised training, its programmes are held on a regional and pan-Commonwealth basis to maximise impact, especially in topics such as administrative reform, financial management and strategic planning.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The Fund's training priorities include:</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">- first and foremost, identifying needs (consultants are sent to countries to examine their development plans and help them to prioritise training needs).</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">- providing education and training in key areas that reflect CFTC concerns such as well-managed economic and financial reform by government, sustainable development, participation of women and application of technology.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">- ensuring an integrated package of consultancy, advice and training to help managers in government, and public and private sector enterprises to coordinate and manage reforms and restructuring.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">- organising policy workshops and seminars that bring together senior government officials, executives and academics from Commonwealth countries to pool experiences, learn examples of best practice, discuss problems and reflect on emerging issues.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">- giving support to institutions to offer new and specialised education and training programmes.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">- providing technical and vocational training under the Commonwealth Industrial Training and Experience Programme (between 1993 and 1995, workshops were held in hospital equipment repairs, railway repairs and maintenance and computer-assisted manufacturing).</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">- providing training in information systems, new technologies and environmental issues (governments are helped to develop management information systems and apply information technology). </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">-setting up programmes for women with a particular focus on entrepreneurs and community managers (among other initiatives, the CFTC is helping three African universities develop specialised programmes in entrepreneurship for women in non-traditional sectors).</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">-coordinating wider linkages among professional networks to facilitate exchanges of information and examples of best practice (the CFTC recently helped to set up the Commonwealth Association for Public Administration and Management to assist in improving public service performance and in raising ethical standards).</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Expertise on tap</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Shortage of skills is one of the biggest stumbling-blocks facing countries trying to raise the living standards of their people. Providing experts accounts for about one-third of the CFTC's budget.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Because its assistance is relatively small and carefully targeted, it avoids the potential waste associated with larger scale projects and poor technical planning. In 1993-95, the cost both of a typical long-term expert and an average project was around £50 000 (ECU 62 000) a year. Experts can be in place within three or four weeks of project approval.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">During the same period, over 200 long- and short-term experts were provided to 43 developing Commonwealth countries, six dependent territories and 18 regional organisations. The expertise requested is extremely diverse, from hydrography and agroforestry to tourism, statistics, legal affairs, health, social planning and computer science.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Assignments for short-term experts can range from a few days to six months. Their role is advisory, helping governments to introduce new systems or technologies. Long-term experts stay usually from six months to two years; others may stay up to four years. Experts assist in the development and implementation of policies or in the provision of managerial skills and the training of counterpart staff to take over in due course. Some long-term experts are trainers in specialist fields.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The CFTC makes every effort to appoint women experts. In 1993-95, they made up 13% of experts that were sent to the field. These included a consultant anaesthetist in Ghana, an agricultural economist in Mozambique, an information specialist in Barbados, a fisheries development officer in Papua New Guinea and an environmental lawyer in Seychelles.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">A scheme to allow suitably qualified and experienced people to volunteer as short-term experts for a maximum of three months was launched in mid-1995. The scheme draws on experts from the Commonwealth who are willing to give their services on a voluntary basis to developing countries.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Entrepreneurs come first</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">In its help to small businesses, the CFTC focuses on those who manage the businesses and identify new entrepreneurial talent. Most assistance is given to small states, especially in the Pacific. The programme has three phases: the first relates to 'surveys of opportunity' which is aimed at identifying suitable entrepreneurs, investment opportunities and potential for expansion as well as specific problems. Next comes 'workshops on entrepreneurship development' during which business owners and operators are helped to think creatively, to become more aware of opportunities that are available and to act strategically when planning expansion. And the last are what we call 'business clinics' in which one-to-one counselling is provided to an entrepreneur at his or her business. This personal support has proved very successful in helping individual entrepreneurs to become more efficient and competitive and, by implication, adapt to changing world economic conditions.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Developing exports</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The CFTC has pioneered the use of Contact-Promotion programmes and 'Buyer-Seller Meets' forums to help small exporters. These forums allow company representatives, often from small Commonwealth countries, to display their wares and meet prospective buyers from other countries. CFTC consultants plan these activities well ahead, short listing producers that are likely to succeed, identifying suitable foreign markets and advising on redesigning of products. Sometimes exporters and factory staff also receive training.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The CFTC funds a special 'export development programme' for women entrepreneurs. This includes detailed country studies of women engaged in exporting as well as sales promotions abroad. Studies of this type have recently been conducted in Cyprus, Sri Lanka and Zambia.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Women are helped, under the programme, to adapt their handicrafts for export, improve their manufacturing techniques and undertake sales missions abroad. Training is also given in export marketing, product development, costing and pricing. If necessary, changes to government policy are recommended. In 1994, the assistance given to Ghanaian women to develop markets for their basket ware and handicrafts is estimated to have helped generate sales worth US$3.1 million (ECU 2.4m). </P>
+<P ALIGN="JUSTIFY"></P>
+<B><P>&lt;&lt;TOC3&gt;&gt; EU's investments in education and training in the ACP states</P>
+</B><P ALIGN="JUSTIFY">by Digby Swift</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The European Community's investments in human resource development-health, nutrition and education-in ACP states have regularly been covered in the pages of this magazine whether in the context of dosiers or of country resorts. Here we present a brief description of how the EU's policy in education and training evolved under the Yaounde and Lom&eacute; Convemntions.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Educating all the people. This is not just a slogan. In a poor, underdeveloped country, there may be some short-term gains from supplying high quality education and training to an elite few. But, as the 'Asian Miracle' has proved, major long-term gains in development and wealth are possible only if the entire population possesses a reasonable level of education.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Now for the problem. For many countries, notably those of sub-Saharan Africa, a large proportion of school age children receive no education at all. Of those who do attend school, many receive little benefit from their education because of the very low quality of provision. Only a small minority reach secondary education. And yet a higher proportion than ever of national budgets is now going to the education sector.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The problem is urgent because of the time it will take to resolve. Even if we could wave a magic wand to provide all children with a good primary education, it would take a decade to see the benefits.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">How is European aid helping to tackle this problem? What have been the guiding principles of European aid to education in the past? And why is the problem still acute in, for example, subSaharan Africa, despite decades of investment in aid to education ?</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Aid mirrors developments</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Aid to education has mirrored developments in the education sectors of the countries concerned. For example, the low-income countries of Africa, which account for 73% of Africa's population, have seen a rapid expansion in their education systems followed by a collapse of funding. This has resulted in a serious decline in standards of provision. European aid, which began by providing piecemeal assistance to infrastructure and manpower, shifted to a 'project approach' to tackle these emerging problems and is now moving towards a coordinated sectoral approach to help tackle the reform of whole education systems.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">From 1970 to 1980, the number of pupils enrolling in the primary schools of developing countries more than doubled, and the numbers in secondary and tertiary education quadrupled. Even relative to the increasing population, there was a 90% increase in the proportion of primary-aged children in school, and a large increase in the proportion of girls. This growth was accompanied by a doubling of government budgetary resources made available to education.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">In the massive general economic decline between 1980 and 1985, the money made available for education from the public purse fell by 40%, yet the education systems continued to grow. The result was that teachers' salaries plummeted, and funds for non-salary recurrent costs such as teaching materials and maintenance virtually dried up.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Since 1985, the financial situation has somewhat improved and funding is now at an all-time high. Nevertheless, for many African states, the education sector is in a state of crisis. Buildings are crumbling and inadequate; teachers are untrained or undertrained and often absent because of low incentives and weak supervision. There are few books and other teaching materials. Consequently, many pupils leave school virtually illiterate and innumerate. Moreover, because of the low quality of instruction and increasing costs to parents, many parents are no longer bothering to send children to school even when places are available. Primary enrolment fell by around 10% between 1990 and 1992. Thus in many countries, a fundamental reform of the sector is seen as the only way forward.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Evolution of aid</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">In the early days of European aid, education and training were seen as suppliers of manpower for countries to modernise their economies. The priority themes of the 1970 Yaounde Convention for European Community aid were industrialisation, regional cooperation and international trade. Community support to education and training focused on the construction of colleges and university faculties to serve industrialisation and regional cooperation.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The 1975 Lom&eacute; I Convention referred specifically to 'the establishment of regional institutions of advanced technology, in the context of training programmes to enable nationals to participate fully in economic development'.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The 1980 Lom&eacute; II Convention introduced multiannual training programmes, and support in the form of training awards and courses/seminars; experts and instructors; teaching equipment; collaboration between training or research establishments and universities. The emphasis was still on vocational training for other sectors.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">A significant proportion of European bilateral aid to education and training took the form of European teachers for secondary schools, colleges and universities. These helped to cover the shortage of locally trained teachers, whilst educating an elite able to fill senior and middle positions in the public and private sectors.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">By 1985, problems were becoming all too apparent within the education systems being supported. As in other sectors, there was increased emphasis on the 'project approach' towards tackling these problems. Thus the Lom&eacute; Ill Convention includes support to education and training 'in the form of integrated programmes aimed at a well defined objective'. This could include, for example, 'assisting the ACP States' own efforts to restructure their educational establishments and systems and to update curricula, methods and technology employed, in order to step up the effectiveness and cut back the cost of all types of training'. A concern for under-represented groups, particularly women, was also becoming explicit.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">By 1990, the concept of investing in people through education and training had moved high on the donor agenda, and alongside it, a growing concern for sectoral reform. According to the 1989 Lom&eacute; IV Convention, 'Cooperation shall be aimed at supporting development in the ACP States, a process centred on man himself and rooted in each people's culture. It shall back up the policies and measures adopted by those States to enhance their human resources, increase their own creative capacities and promote their cultural identities. Cooperation shall also encourage participation by the population in the design and execution of development operations.' In a chapter entitled Operations to enhance the value of human resources, a section on Education and Training refers to supporting the ACP State's efforts to 'reform their basic education institutions and systems, in particular by providing overall primary education coverage and adjusting imported systems as well as building them into development strategies'.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">In the late 1980s and early 1990s, European states and the Community joined the World Bank in support of structural adjustment. In a 1991 communication to the European Development Council, the Commission stated that it 'will give absolute priority to the social dimension of adjustment, in particular ensuring that the health and education sectors are adequately covered, in conjunction with sectoral reforms introduced or planned in these two areas.'</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Balancing this concern for system reform has been a growing appreciation of the importance of decentralised cooperation. An example is the cost-sharing microprojects for grassroots development first introduced in Lom&eacute; I with explicit mention of support to primary schools. Another example is the need to support the activities of nongovernmental organisations.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">A new policy</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Two events in the early 1990s have had a profound impact on European support for education and training. The first was the World Conference on Education for All: Meeting the Basic Learning Needs held in Jomtien in 1990. This emphasised the need for universal</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">primary education and adult literacy to be firmly placed on the political agenda, and has resulted in a profound swing of donor support away from higher education and towards primary education. The second important event was the 1992 Treaty of European Union which requires the coordination of Member States' policy and operations, particularly in the social sectors. Guidelines are contained in the 1994 Council Resolution on support to education and training in developing countries in which 'the Council emphasises that education, in particular basic education, is a fundamental right'.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">According to the Resolution, 'the priority for the Community and the Member States must be both to maximise access to education within the limits of the resources available and to ensure that the quality of education provided is suited to the needs of the majority of students. 'This is to be achieved through 'a balanced, programme-based strategy, tailored to the specific circumstances of the individual developing country', with pride of place accorded to basic education. It should provide 'support to the developing countries' own policies and efforts', not acting as a substitute for local initiative, and should involve better integration of action under structural adjustment with education sector priorities and aid activities. The Council also recommends a special emphasis on coordination in a number of pilot countries.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">From the outset, Community aid to education and training in African, Caribbean and Pacific countries has been in response to requests from the ACP states with an emphasis on ownership of the resulting programme by those states. What the new policy introduces into this process is a dialogue between government and all donors on needs, priorities and approaches set in the context of the education sector as a whole. Only through such a comprehensive approach can developing countries and European states reach a true partnership in realising the education and training needs of all citizens on which the future of their countries so crucially depends. </P>
+<P ALIGN="JUSTIFY">D.S.</P>
+<P ALIGN="JUSTIFY"></P>
+<B><P ALIGN="CENTER">&lt;&lt;TOC2&gt;&gt; Analysis</P>
+</B><P ALIGN="JUSTIFY"></P>
+<B><P>&lt;&lt;TOC3&gt;&gt; EU-ACP relations : Building for tomorrow</P>
+</B><P ALIGN="JUSTIFY">by Kenneth Karl</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">1989 saw the end of the Yalta inspired twin-superpower dominance. Nations had to examine their priorities in their desire for integration in an international environment in which geostrategic and economic realignment would be unavoidable. The philosophy which had served as a basis and reference point for North/South relations throughout the Cold War period is now being called into question and necessary adjustments in ideas have been triggered.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The Lom&eacute; Convention, which governs the development-cooperation relationship between the EU and the 70 ACP countries, is a unique North/South cooperation agreement on account of its contractual nature, its durability, the funds it allocates and the fact that it provides for a permanent dialogue. But it is also now at a decisive point in its history.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Those who regard the Convention as out-of-date and in need of renovation, and those more radical critics who believe that it no longer serves any useful purpose and must be phased out, both argue that a new direction is needed.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">- Beyond all the criticism formulated against this system, the fundamental question remains as to whether the Lom&eacute; Convention will be able, given the necessary changes, to carry on after its fourth version expires.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The years between now and the end of the century will, naturally, see the application of the revised Lom&eacute; IV, including the substantial improvements made to it. However, this same period must also be used to prepare the ground for ACP/KU development cooperation in the future, whatever form it might take.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Shortly after his nomination as European Commissioner for relations with the ACP countries and South Africa, Professor Pinheiro commented, realistically, that the ACP countries are no longer 'in fashion'. The change of emphasis can be seen clearly if one looks at the EU's burgeoning relations with its eastern neighbours from the former Communist bloc (illustrated by the wide range of European programmes now benefiting these countries). One might also cite the strengthening of ties with countries in the Mediterranean basin. Economic and security concerns underpin this development, but it undoubtedly reduces the significance which was once accorded to the ACP states.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Moreover, the economic objectives of virtually all EU countries, as they seek to reduce budget deficits and deal with increasing internal social problems inevitably put pressure on the amount of development aid being granted to the Third World.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">This situation is, of course, not restricted to the European Union - which in fact remains the world's main contributor of official development aid. At the instigation of a Republican dominated Congress, the United States is planning much more swingeing cuts in its contribution, both to certain international agencies and to certain regions (including Africa).</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">This undeniable cutback in public development aid has been offset in recent years by net increases in private capital flows, but the geographical distribution is highly skewed. Only a few of the poorest developing countries have benefited from the trend, the main 'winners' being the emerging states of Asia. These include countries such as China, India and Indonesia which, it is worth noting in passing, do not have particularly good human rights records, in the sense that the term is understood in Europe. Despite the fact that ACP countries have identified potential for attracting foreign investment, they have not actually benefited from this change in resource flows.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">In this climate, with official development aid in inaeasingly short supply, innovative methods for making optimum use of the available resources must be devised within the context of the Lom&eacute; Convention.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">On current indications, it is quite possible that in the year 2000, the Lom&eacute; Convention will be filed away in the archives. ACP/KU relations will certainly have to be more in step with recent developments on the international scene. The initial reasons for the establishment of a cooperative relationship between Europe and the ACPs, following the signature of the Rome Treaty, are now outmoded. As Paul Valery has commented: 'One of the worst mental aberrations is to think that things can survive when the reasons for their existence have gone'. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">So, what type of development cooperation should the countries of the European Union and their ACP partners aim for in the future ?</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Alternative trends</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The EU has stated that it is in favour of a globalisation of aid within an innovative framework. One of the first questions to be asked is whether uniform cooperation with regions whose monolithic character is being increasingly called into question is still desirable.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Variable geometry in development cooperation relations is increasingly being seen as the trend to be followed.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">If this option is chosen, there is a risk of the following scenario being created: The EU's relationship with the Caribbean could become diluted within its relationship with Latin-American countries and links with the Pacific countries could become confused with economic relations with Asia. What would then become of Africa, the continent needing most attention on account of the wide range of its difficulties and its increasing marginalisation ?</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">In 1990, the United Nations General Assembly, aware of the African question, adopted a new agenda on development in Africa, thus making that continent its number-one priority. Europe, on the other hand, must not simply focus on Africa but must invent new modes of action which are more concrete and more effective.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Secondly, recent trends imply greater conditionality. This has been taken on board not just by EU Member States. A number of multilateral aid agencies have also included it in their strategy. The OECD's Development Aid Committee believes that future relationships between North and South will be greatly influenced by conditionality and, indeed, the Organisation goes so far as to advocate this approach.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">However, conditionality in terms of development is a strategic element which must be handled with extreme caution. If cooperation, whether today or in the future, is to be based on conditionality, then it can only be rendered effective if aid recipients (both governments and the governed) are genuinely committed to the idea. They must be convinced, in a climate of resource-scarcity, than the approach is motivated above all by a desire for greater success.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The European Union thus has a vital role to play, making full use of its advantages in terms of dialogue and consultation in order to prevent conditionality being perceived as a condescending mechanism. Thereby, it can help to prevent conditionality from generating the well-known perverse effects of 'tied' aid.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Of course, conditionality raises the thorny question of national sovereignty, but it is important to observe that modern international relations have moved on, both de jure and de facto, from a concept of absolute sovereignty to one of relative sovereignty. This is illustrated by the trend towards humanitarian intervention as a right, the requirements of the Bretton Woods institutions, supranationality in certain regional international organisations, and the very fact of world economic interdependence.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">This does not mean that the developing states should sell off their sovereignty to the highest bidder but that conditionality should be the subject of negotiation. Donors must be more flexible in their demands and thereby give the country in question such room to manoeuvre as is necessary for programmes to succeed.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Thirdly, development of the private sector appears now to be approved by all parties. Since independence, the State has been omnipresent and omnipotent in most productive areas of ACP economies. Given the failures of the public sector, private enterprise is now being called in to help. Its development is one of the sector specific policies which will and must receive most support.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The development of the private sector must permit better distribution of the fruits of the growth that it generates and promote integration of the ACP countries into the market economy. There can be no question of pitting private enterprise against the public sector, because any Manichean approach in this sphere might prove to be risky. It is important also to stress that free market development cannot take place overnight and that it is subject to inescapable macro and microeconomic preconditions.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Indeed, the birth and expansion of a dynamic private sector depends on the politico-economic fabric. This includes reliable financial bodies, functioning financial intermediation, adequate infrastructures, technical qualifications and training, a suitable legal/ regulatory framework, institutions to support private businesses, the channelling of the informal sector and a public sector which is prepared to play fair, aware of its regulatory role. These, in short, are the necessary ingredients for the adjustment of the private sector to permit the development of a true enterprise culture.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The development of a harmonious private sector will make it possible more easily to achieve the transformation and export objectives required by international competitiveness. It should, therefore, help to counteract the erosion of commercial preferences generated by the Uruguay Round. The latter's time limits should, in any case, be extended, because it seems clear that the ACP countries will be unable to fulfil their obligations by the end of the moratorium obtained by the EU during the negotiations.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The notion of compensating for inequality that is found in international development law, implies the adoption of a normative system to counteract the weak trading position of developing countries vis-a-vis their competitors in the North. But in recent times, this idea has been losing ground and it is unlikely to cut much ice with the WTO authorities. Legal equality in a situation where there is structural inequality is not, in fact, equitable, and it is therefore necessary to find some other way of mitigating the adverse effects, looking at it in a global context.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Promotion of domestic and foreign investment should be better supported. People talk of the 'risk/ country' threshold that deters foreign investors. It may be that this can be measured objectively by looking at economic and other indicators, but even if this is not possible, it clearly exists as a psychological barrier. This is a problem for many ACP countries and it needs to be crossed, using measures which tackle the many obstacles to investment.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Changing the culture of development cooperation</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Besides all the technical aspects, one could argue that the shortcomings of the Lom&eacute; Convention stem also from the perceptions of those involved in development cooperation. In short, it is the actual concept and culture of development aid which must be changed.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">On the European side, the colonial legacy has conditioned attitudes, imprinting on them a dominant patemalism which is prejudicial to the aim of development. This European concept of cooperation must be overturned. Moreover, development cooperation must not be seen as the art of the possible but as the art of making possible what is strictly necessary, by virtue of genuine negotiation with the countries which have resolved to move forward.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Moreover, it is desirable to have a better developed policy of informing European public opinion about development cooperation. An effort is needed to counter false impressions, such as the one left by the French journalist who wrote: 'Official development aid is like taking money from the poor in rich countries to give it to the rich in poor countries'. Better information is needed to ensure that the public can decide such matters for itself.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Coordinating the Union's policies with those of the Member States now presents an enormous challenge. The political obstacles are huge and development cooperation may well suffer as a result of them if the objectives of coordination, coherence and complementarity contained in the Maastricht Treaty are not achieved.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">As for the ACP countries, success in their economic development depends on many factors, cooperation being only one of them. Many political leaders in these nations have too often described cooperation with the North as the only way in which they can develop. In fact, this should be seen as nothing more than an additional factor - supporting the national effort and a genuine desire for development. It is pure fantasy to believe that development can be set in motion solely on the basis of an external impetus. To succeed, it must come from within a country. This is why future cooperation between the EU and the ACP countries must progress towards reinforcing the aptitude of the latter to devise, master and control their own development process.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">In the future, the ACP countries must propose concrete and responsible solutions to their partners, doing so by means of the dialogue system. They must also promote development based on participation, particularly with the involvement of young people and women.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The fact that the ACPs can offer a credible prospectus for development must be acknowledged. It is undoubtedly a challenge, but it can successfully be overcome if a climate of stability, security and confidence is created, matched by an unambiguous political will.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">In KU/ACP relations, programmes must include the long-term vision necessary for sustainable development. Too often in the past, the strategy has been aimed at an immediate and ostentatious result. Successful development in the future will depend crucially on a change in such attitudes. </P>
+<P ALIGN="JUSTIFY">K.K. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Let us know what you think</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The debate about the future of cooperation between the European Union and the ACP states is now beginning to gash' pace. Last year, we established the 'Analysis' section in The Courier to report on this debate-and give readers an opportunity to express their own views on the subject.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The response so far has been encouraging, but it has come mainly from the European side. We are keen to receive contributions from ACP readers as well. If you have you own ideas or opinions about what should happen after Lom&eacute; IV expires, why not put them on paper and send them to us. Our address is on the inside front cover of the magazine. </P>
+<P ALIGN="JUSTIFY"></P>
+<B><P>&lt;&lt;TOC3&gt;&gt; The view of civil society on the future after Lom&eacute; IV</P>
+</B><P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">This was the subject of a conference which took place in Maastricht from 12-14 June, under the auspices of the European Centre for Development Policy Management (ECDPM). It brought together participants from ACP countries and Europe, including representatives of civil society (NGOs, the private sector, etc.). Four major topics were addressed:</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">· How can a new KU/ACP commercial relationship be constructed ?</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">There was agreement that some form of preferential trade regime should continue after 2000. Some participants stressed the need to Promote 'fair trade', which would contribute not only to growth but also to development. The impact of individual trade preferences is not always clear-cut, but obviously there cannot be a single solution covering all problems in all ACP countries. An analysis of negative constraints demonstrated the difficulties involved in reconciling the rules of the Lom&eacute; Convention and those of the World Trade Organisation.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">· How can the private sector become involved in development ?</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The most important aspect of this topic is knowing how to create a favourable and business-friendly environment which will enable the private sector to play its part-and the role the European Union could play in this process. The private sector was defined as both formal and informal, encompassing large, medium and small enterprises, whether local or foreign. The importance of a strong local private sector in guaranteeing long-term stability was particularly emphasised. In this respect, the view was expressed that the role of the state and its relationship with the European Commission should be redefined. There was also a call for time to be set aside time for effective dialogue, and to create the space for a partnership between the public and private sectors. It was felt that the role of Economic and Social Councils should be expanded and specified more clearly. As for the specific issue of privatisation, the point was made that this should not be seen as a panacea and that it should be approached on a country-by-country basis.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">As regards current instruments, it was noted that their objective is essentially to meet public-sector requirements. The role of the Centre for the Development of Industry (CDI) attracted some criticism. Speakers felt that the private sector should be more involved in the preparation and implementation of cooperation programmes with the European Community. Direct financial support to the private sector was seen as desirable, including backing from the European Investment Bank.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">· What partnership ?</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The partnership concept was seen to have been eroded over the past two decades, with the pretext of efficiency resulting in a more paternalistic approach. Mechanisms needed to be found to enable EU priorities and the prerogatives of ACP countries to be reconciled. Reference was made to the political nature of the origin of the partnership and the need to find a new political raison d'etre for this type of relationship. The problems of cohesion within the ACP group and its relations with the EU were also raised, and there was a discussion about the possibility of giving the Convention a regional character-although a number of speakers expressed reservations about this.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">On the European side, two lacunae emerged, namely coordination between donors, and consistency between Lom&eacute; and other Community policies (including relationships with the Bretton Woods institutions).</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">In addition to the principle of partnership, some participants were keen to stress the motives of solidarity and common interest that lay behind cooperation. It was not simply a matter of 'negative' interdependence. The appropriateness of the term 'partnership' was questioned, if this was only to mean financial and technical cooperation. The politicisation of Lom&eacute; appears to be on the agenda, involving a move from the current partnership to a genuine 'contractual approach' through political dialogue.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">As for the role of partnership in cooperation policy management, it was felt essential that civil society and the private sector be involved. There was also a discussion of the debt problem.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">· How can financial and technical cooperation be improved ?</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">As usual, reference was made to the need to simplify and differentiate management of Lom&eacute; Convention instruments, particularly in the context of the programming process. As regards the role of non-state actors, a cautious approach was recommended. Finally, new instruments were called for to prevent conflict.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">· Conclusions</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">This conference, coming after several others of the same type, was characterised essentially by private sector and NGO calls for greater participation in Community cooperation policy. Moreover, the need for 'politicisation' of the Lom&eacute; policy, shifting from purely financial and technical aid to a genuine cooperation contract, seems to have attracted the support of all participants. These questions are sure to figure in the 'Green Paper' on 'tome after 2000', which the European Commission plans to publish before the end of 1996. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Dominique David</P>
+<P ALIGN="JUSTIFY"></P>
+<B><P>&lt;&lt;TOC3&gt;&gt; 'Democratising democracy'</P>
+</B><P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">On 6 and 7 June, the Belgian Par/iament hosted a UN seminar on 'me future of international development cooperation: new communication challenges' 'Democratising Democracy' was the succinct, journalistic way in which one of the speakers at the meeting summed up his solution to the problem of underdevelop meet. He was Jean-Bertrand Aristide, former President of Haiti, who observed that democracy, as advocated by the developed world, and increasingly accepted by developing countries, does not prevent the latter's slide into even greater poverty. The Courier had the opportunity to interview Mr Aristide. We began by asking him whether his statement implied that democracy is failing in a world striving to 'globalise' it J-B.A.-The word democracy comes from the Greek words 'demos', meaning people and 'kratein', meaning to govern. In other words, it signifies government of the people, for the people by the people-but if we take a look at the world today, the impression we get is that not all so-called democratic governments are in fact what they purport to be. Hence the need to 'democratise democracy', so as to create a situation in which all citizens can help set governments on a course towards such a model.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Concepts usually generate conflict and, therefore, when speaking of revolution, democracy or globalisation, it is necessary to be au fait with the subject matter so as not to become involved in a dialogue of the deaf. In the specific case of globalisation, my opinion is that this has a tendency to make what is an already precarious situation even more unbalanced. Concepts cannot be applied everywhere without thought being given to their harmful consequences. This does not mean to say that we should give up completely. It's one thing to speak of the globalisation of peace, as if an ineluctable need existed to promote peace on a world scale, but I'm not sure that everyone would define the globalisation of peace in the same way as I do.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">· Could we turn now to your own country, Haiti. How do you view the future of democracy there, bearing in mind the economic circumstances ? At the seminar, you mentioned several factors which demonstrate democracy's *agility.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">-Democracy is indeed fragile. 1% of Haiti's population owns 48% of the country's wealth and it is estimated that about 65% of the working population is employed in agriculture as against 5.1% in the 'industrial' sector. But is this really the true picture ? Reality for most people is poverty-unacceptable and sub-human poverty. A man needs work to earn his daily crust by the sweat of his brow, but unemployment has reached catastrophic proportions. When people are unable to earn their living, there is little point in discussing the positive influence of democracy. What is needed is for those with a great deal of wealth and those with less wealth to talk to each other; a dialogue between the private and public sectors, so that we can head off futile conflicts and devote all our efforts to economic growth coupled with human development. I do believe that this is possible.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">· Yet, the rich are so rich and the poor so poor. Is it not fantasy to think that the gulf which separates them, and their mutual mistrust, can simply be set aside so that genuine dialogue can take place ?</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">-This is one of the challenges we have faced ever since 1960 and, although we have not yet reaped the harvest of this process, we have to carry on. It's not too late. We just have to approach the subject logically and with all the facts to hand, and we must have the intelligence to be patient. If we continue with dialogue, we will achieve real results. Only the citizens of Haiti can play a part in Haiti's development-this is not a task for outsiders. We, on the other hand, have to be more receptive to international cooperation, while maintaining mutual respect and dignity. But what we also need is for our own people to act together in order to enhance our own growth. This is not to say that geopolitical reality can be disregarded. Other countries have to be taken into account, but, as a starting point, we have to consider Haiti's human and material resources.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">· Thereisdialogueata world level, but there are rules to be applied. I am thinking, here, of free competition. Haiti has to play by the rules, just like any other country.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">-Since we gained independence, our history has seen a succession of coups d'etat and people have been over-eager in brandishing weapons to solve economic, political or social problems. Now that democracy has been restored in Haiti, weapons are not the solution to our problems-I cannot stress this enough. What we need is for those with money to sit down and negotiate with those who have none: for the government to get people round the table and devise a common plan to accommodate all interested parties- looking at both the nation's interests and the interests of investors. I do believe that it is possible to achieve this. We have, in fact, already begun to prepare the ground. I am not basing my words, here, on pure theory, but am speaking from experience. In concrete terms, we have to transcend class and racial differences to recognise that Haitian men and women, regardless of their colour and the country they might live in outside Haiti, regardless of their nationality, even, are still part of Haiti's indigenous population. The way must be kept open for dignified and balanced cooperation.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">· The other point you mentioned today was that there can be no development without the effective involvement of the population. Are you not leaving yourself open to accusations of having socialist or even communist tendencies ?</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">-As I have just said, we have to be scientific in our approach and check our facts over and over again. I fail to see how anyone can claim to be working towards peace without looking at poverty which is the greatest threat to social cohesion. Of course, there are those who would deny this assertion, and that is their right. However, rational analysis of the situation can help us alleviate poverty and promote security. It needs to be underlined that security is also one of the essential factors in economics. The UN Security Council is called in to prevent or resolve conflicts. To my mind, we should also be talking about an economic security council to deal with the economic realities. The deeper one plunges into poverty, the greater one's feelings of insecurity-the two always go hand in hand. And insecurity can crop up anywhere in the world. Nor is it a question of charity. It is a real, rational question which must sharpen our awareness, stimulate our common sense and set us on a course to protect the world by alleviating poverty. That, at least, is one approach.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">At the same time, you have to recognise that politics is essentially a question of power while economics is influenced by interests. Everyone uses the means at their disposal to defend their personal interests and we know perfectly well that there are no free gifts. The so-called developed countries allocate just 0.3% of their GDP to development aid, yet we are losing our tropical forests at the rate of the area of a football pitch every second. In Haiti, forests now cover only a small area of the country. But in the final analysis, environmental catastrophe threatens us all, rich and poor alike, even if certain countries do not face specific ecological risks. We either deal with it as reasonable people, or we close our eyes to the 'cause and effect' realities.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">· Yes, but are we reasonable people ?</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">-The crisis of ethics is indeed a reality and a great many values are now being called into question. These days, we have to love in order to prove we are not contradicting ourselves. If we believe in God, we might call this love 'God', just as we might call it 'justice'. It all depends on your philosophy, religion or beliefs. If I feel love, I cannot be indifferent to the situation of victims of injustice, both in Haiti and elsewhere. If a man is humiliated, crushed, exploited or marginalised, then 1, too, am humiliated, crushed and marginalised. It is love which makes us fight for justice everywhere. Either one is a demagogue revelling in big words or one is sincere and ready to die so that another might live-this brings immortality.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">· One final question. You were speaking just now of insecurity and economics. Is there a link, here, with one of your most recent decisions, the abolition of Haiti's army ? Could you tell us how you were able to pull off this 'coup'? </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">- I am perfectly happy to answer such an important question and would like to be able to give a clear and direct reply. But given that the struggle is still going on, I don't think I should go into too much detail. A decision was made. The Haitian people opted to rid themselves of the army. Supporting their democratic wish, it was our job to help bring about this dissolution. The army, it is worth recalling, had about 7000 men, absorbed 40% of the national budget-and had killed many of our compatriots. We have had to be logical and patient in achieving this goal, bearing in mind that the guarantors of the agreement which led to my return had their own views, which were different from ours. We also needed courage and wisdom and, above all, the determination of the people. My motto has always been that it is better to fail with the people than to succeed without them, and in this we did not fail. Our task now is not to bask in our own glory but to continue the work of structuring the police force, to prevent it becoming another army. To achieve this, we have to make steady progress and use sound judgment. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Interview by Hegel Goutier</P>
+<P ALIGN="JUSTIFY"></P>
+<B><P ALIGN="CENTER">&lt;&lt;TOC2&gt;&gt; Close-up</P>
+</B><P ALIGN="JUSTIFY"></P>
+<B><P>&lt;&lt;TOC3&gt;&gt; Growing rice at high altitude in Burundi</P>
+</B><P ALIGN="JUSTIFY">by Jean-Pierre Tilquin and Miguel Amado</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">This tiny country tucked away at the heart of Africa has, as is well known, been convulsed over the last three years by an acute socio-political crisis. The tragic consequences have included loss of human life, damage to the economic and social infrastructure, and a movement of refugees to neighbouring countries. Burundi, already one of the most densely populated nations in Africa, also has high population growth. It could be argued that it is only thanks to the hard work and perseverance of the farmers (admittedly, 90% of the population) that the country manages to keep going at all.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Agriculture in Burundi follows traditional lines and is based on a farming system divided between food crops for consumption by the farmer and his family, and cash crops (mainly coffee, tea and cotton). Although at the beginning of the decade the crops grown for food were sufficient to meet the population's needs, today demographic pressures are forcing farmers to increase food-crop production. It is these pressures that have prompted them to descend into the marshlands which cover approximately 110 000 hectares (8% of cultivable land in Burundi). These marshes are flooded during the rainy season and so allow rice to be cultivated.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Population growth has also meant that fields cannot be left fallow for long periods. This has resulted in more intensive use of marginal land and an increase in forest clearing. Such practices exacerbate erosion of cultivated areas. The loss of organic matter and nutrients leads to reduced soil fertility and lower yields. Although rainfall in Burundi is high, the soil is only moderately fertile, because of factors such as acidity, aluminium toxicity, and phosphorus immobilisation.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">While 20% of land suitable for cultivation is currently given over to growing dry beans-a staple in the Burundi diet - various factors now point towards farming the low-lying marshlands, with a particular emphasis on rice. This is one way of increasing the useful agricultural surface area of the country.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The events of 1993 (democratic elections, followed by the assassination of President Ndadaye), have created a period of instability which has been highly damaging for the country's agriculture. Some people lost their property and livelihood, and are only now slowly re-establishing themselves. The environment has also suffered as a result of the sheer numbers of displaced people. They occupy areas, both urban and rural, which were completely unprepared for the flood of people. it is estimated that 50 000 hectares of forest have been destroyed as a result-with devastating consequences for the country's ecosystem. What is more, the rate of demographic growth has led to overfarming and to a reduction in the average surface area of farms (to 0.7 ha per household).</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Rice-a crop for the future</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Against this background, the prospect of farming low-lying marshland offers some hope for the people of Burundi. In fact, the marshy valleys have long been used to grow beans, maize and sweet potatoes during the long dry season for later consumption during the short dry season. This practice, which was environmentally sound, provided a regular harvest, but also ensured the preservation of the marshlands.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The practice of growing rice during the rainy season, followed by a crop of maize and beans during the dry season, is a form of integrated agriculture. It should be economically viable and environmentally sustainable while ensuring product quality, delivering a good yield, limiting any risks involved and allowing a high degree of social integration. These are the criteria which need to be examined in determining whether high-altitude rice cultivation in Burundi succeeds or fails.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Rice crops have been grown in this region, on the shores of Lake Tanganyika and in the Ruzizi valley (altitude 800 m), for more than 200 years, having been introduced by successive migrations of people travelling along the old slave route from Zanzibar. Certain varieties, known as 'pandabilima' (which in Swahili means 'he who climbs the mountain') can be grown on land up to a height of 1300 metres. They cannot, however, be planted on the higher central plateau because low temperatures at night render them completely infertile.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">It is not surprising that the new scheme to grow rice at high altitudes was greeted with interest. Indeed, it became almost a craze among farmers -to the extent that in 1990, rice crops covered more than 20 000 ha of Burundi. The area planted with rice fell subsequently, and in some regions the crop disappeared altogether. This was due largely to the appearance of the fungal 'rice blast disease', which can wipe out an entire crop, and to inadequate planning and misguided husbandry. The extensive planting of only one variety left the crop particularly vulnerable and once the disease did take hold, it was virtually impossible to eradicate. Needless to say, in a country where access to pesticides is non-existent, the introduction of a new crop cannot be based on a single variety; if it is to establish itself successfully, varietal diversification is vital. We should point out here that attempts were made in 1984 to improve varietal diversification </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">in the framework of the EU's Scientific and Technical Programme run by DG XII of the Commission. At that time, it was necessary to familiarise farmers with the techniques for growing the new crop and this aspect of the programme was funded by the EDF, in particular through three integrated projects. These related to agriculture and pastoral forestry and were initiated during 198889 in three provinces of Burundi.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Without going into the technical details of the programme, it suffices to say that growing rice at high altitude in the tropics differs from rice-growing in temperate regions. The low night-time temperatures characteristic of high altitudes mean that the crop is subject to constant stress. In temperate regions, the stress caused by cold weather is a problem only at the beginning and end of the growing cycle. As for selection methods, rice varieties have been produced that are resistant to rice blast disease - which remains the main problem. Also, by mixing the varieties grown, the farmers have created a wide diversity which offers a stable basis for a sustainable crop.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Transformation of an ecosystem</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">From the viewpoint of development aid specialists, turning marshland into cultivable land means draining it (digging a ditch and fitting pipes). But this leaves the land open to erosion, causes silting in rivers and ultimately leading to desertification. By changing water levels in a region and disturbing the thermal equilibrium, marshlands cease to be marshlands. The method may have been justifiable before rice growing became possible. Indeed, it was employed in the natural marshlands of Buyenzi by some experts who specialised in upland rice. But it also resulted in large-scale destruction of one ricevariety-Yunnan 3-by rice blast disease in 1990.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Development projects which set themselves spectacular objectives can involve major alterations to the landscape. More often than not, these need to be rectified later. Thus, when it was decided to cultivate vast expanses of papyrus, the plants were moderately successful only thanks to constant artificial assistance. Put simply, the land could not sustain the crop on its own. In the process, the marshes were turned into floating peat bogs.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The option chosen here was to adapt the small valleys for rice cultivation and teach the farmers the relevant techniques. Together with their families, they have eagerly embarked on the work needed to prepare the terrain for cultivation, although there are still some land tenure issues that need resolving. (Some people have refused to commit themselves to marshland reclamation projects as long as the land does not belong to them). It should be stressed that growing rice along a strip of water is an option which is in harmony with environmental needs. It promotes percolation of the water, thereby restoring underground water levels and preventing pollutants from being washed down towards the Nile or Zaire basins. It is therefore in keeping with global strategies for conserving resources and ensuring sustainable development.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">In the marshlands, farmers traditionally plant beans and maize in banked-up beds during the dry season (from June to November). By skilfully selecting and growing different bean varieties, the farmer can stagger his crops and thereby ensure a continuous harvest from September until the time the maize is harvested. The marshes are then left fallow during the heavy rains which reach their peak in April. A rice variety which can be harvested in six months could thus be fitted in during this perriod with out disturbing the traditional hill-farming work schedule.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Since farmers on the high plateaux had not traditionally grown rice, it was necessary to teach them the techniques needed to produce a successful crop. They were also informed of the benefits that improvements such as dykes, water supply pipes and drainage pipes could have on crop productivity. They have since applied this knowledge in their cultivation. During the dry season, without disrupting the infrastructures on which their rice cultivation is based, they have rebuilt banked-up beds and grown the traditional bean and maize crop. The system has been in place for about ten years and no drop in yield has been recorded. The yield averages 4.5 t/ha for rice, 1 t/ha for beans and 0.4 t/ha for maize-figures which are quite remarkable when compared with the yields of crops grown on the hills in acid soil with increasing levels of aluminium toxicity.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">By alternating two different farming systems, the problem of weeds -and therefore hoeing-and of pests is greatly limited. The extensive mixing of the soil that takes place accelerates the recycling of biogenic material-and the marshlands stay as marshlands!</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Manageable land development</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">There are three main types of marshy valley, each requiring specific programmes. The first consists of valleys lying above 1400 m with a rainfall in excess of 1500 mm. These areas are characterised by a clay soil, are constantly fed with water (with a high iron content) from the mountains, and are often very rich in organic matter. They require drainage using ditches and filtration channels, with changes of gradient so that the mountain water tables can be tapped and the water levels controlled. This is important to prevent a build-up of ferrous toxicity in the soil, which is extremely harmful to rice. A farming system involving paddy fields and banked-up beds can be accommodated perfectly in these types of valleys. Then there are the valleys lying between 800 and 1400 m with a rainfall of between 1100 and 1500 mm. These are known as 'dambos' in Swahili, and they extend from Northern Kenya right down to Southern Zimbabwe. Strewn with giant termite nests, the land here is well-suited to rice cultivation as long as water levels are carefully controlled. All the available water needs to be harnessed via filtration canals dug into the hillside. These allow the paddies to be irrigated speedily and, during the dry season, they can also be used to irrigate between the rows of ridgeplanted crops. It would, however, be very difficult to irrigate the entire valley during the dry season and so it is pointless digging a drainage ditch. The third and final type consists of small alluvial plains tucked away between the hills and stretching along the escarpments. Here, the level of soil fertility is determined by the heavy erosion resulting from farming on burnt land, and the practice of setting fire to the hills in order to 'regenerate' pastures. To grow rice in such locations, a filtration canal needs to be dug into the hillside, into which water then collects from the water table. The paddy fields also need to be terraced. These alluvial plains lend themselves perfectly to a farming system in which paddy fields are alternated with banked-up beds. All these land-adaptation schemes can be easily implemented and maintained by the farmers themselves.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">A sociological revolution</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Although rice grows quickly, it is highly labour-intensive. Thus, when</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">the young rice plants need to be planted out-which happens to coincide with the end-of-year school holidays-the whole family takes part. What is more, rice has become extremely important in sociological terms: reserved in days gone by for special occasions, it now forms part of the nation's staple diet, being mixed together with beans and dressed with palm oil and tomato sauce. The rice harvest is also a time for merrymaking and festivities which go on for the best part of a week.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Rice cultivation has also engendered a vital sense of solidarity among farmers as far as sharing water is concerned, and rice-growing cooperatives have been a runaway success. These enable farming operations to be synchronised and running costs to be reduced, in particular by reducing the number of bird scarers needed. The crop, furthermore, can be harvested when fully ripe. On individual plots, farmers usually only allow the rice to mature to 75% before harvest for fear of theft. Finally, the cooperative helps to ensure that infrastructures such as drains and canals are properly maintained and that water supply installations are treated with respect. Each cooperative is run by a representative appointed by the group of farmers. These supervisors are then responsible for organising all operations: choosing and storing seed for the following season's crops, getting information about new varieties, consulting each other and pointing out any problems they may have to those in charge of research and advisory services. The area allotted to each cooperative depends on the number of households in the group and also takes into account the area available, with 10 ares per family being the usual maximum for planted-up paddy fields. Cooperatives may range in size from 5 to 25 families.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Cooperatives like this are just the beginning. Networks of rural organisations, in which the farmers club together to buy equipment and fertilisers, need to be developed on a larger scale and they could provide a springboard for the development of the secondary sector, which is vital to the development of the country as a whole.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">We would do well to recall that the cassava mills which have been so successful in Burundi and which still run today without any 'technical assistance' had equally humble beginnings.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The future</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">It must be acknowledged that the people who migrated to this 'wild frontier' of rice cultivation in Burundi also introduced into these regions diseases such as bilharzia and malaria (the mosquitoes carrying the parasite were transported in the luggage of people travelling from the capital to the provinces). Despite this, rice cultivation at high altitude has proved a veritable lifesaver for Burundi. In the year that the FAO plans to stage a summit on famine, it is appropriate to highlight the important role of rice-growing in the food production strategy of this country.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Until recently, Burundi ensured that it had enough to feed its people through a delicate balancing act between growing food crops, leaving land fallow and rearing livestock which produced manure. At present, however, increased agricultural production is only possible by increasing the surface area of the country under cultivation-at the expense of fallow land and livestock farming. Such a move risks reducing soil fertility and could lead to the substitution of crops of high nutritional value, such as beans, with higher yield crops such as cassava or sweet potatoes which suck the subsoil dry of minerals and nutrients.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">In short, traditional farming methods in Burundi are arguably now out of balance and the situation is getting worse. This may, indeed, be a root cause of the ethnic crisis. A systematic policy of re-establishing marshlands and organising rural communities around high-altitude rice cultivation would allow the country to look ahead with optimism to the next 20 years. Suitable varieties are currently available and the altitudes at which rice can be grown have been pushed back in Burundi as far as 1700 m. What is now needed is the funds! </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">J-P.T. &amp; M.A.</P>
+<P ALIGN="JUSTIFY"></P>
+<B><P ALIGN="CENTER">&lt;&lt;TOC2&gt;&gt; Developing world</P>
+</B><P ALIGN="JUSTIFY"></P>
+<B><P>&lt;&lt;TOC3&gt;&gt; Freedom of expression: the heartbeat of democracy</P>
+</B><P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">A view from UNESCO.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The article which follows is an abridged version of a text compiled by Carlos Amaldo, who heads UNESCO's research into communication and the free flow of information. Mr Arnaldo highlights some of the main aspects of the UN agency's support for the development of a free press in the African, Caribbean and Pacific regions.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The resolution passed by the ACP/KU Joint Assembly in March 1996 in Windhoek, Namibia, reflected the spirit of many of UNESCO's communication programmes in these regions. Echoing the principal tenets of the Universal Declaration of Human Rights, the resolution declares: 'freedom of expression is a precondition for holding free and fair elections'; 'the monopoly of information media is a barrier to the development of democracy,'; 'there is a need to create a climate in which all part)" can participate fully in political life.' It further holds: 'communication media must not only inform the electorate in an impartial and objective manner' but also; 'freedom of expression and the existence of free communications media are vital preconditions for the development of a democratic society.'</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The resolution was timely, responding to a need to remind political leaders, as well as civic society, of the relation between free communication media and truly democratic practices. Just five years ago, on 3 May 1991,</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">African journalists and media adopted the Windhoek Declaration at the UN/ UNESCO seminar on promoting an independent and pluralistic African press. Likewise, journalists and media practitioners of each major region adopted the Declarations of Alma Ata (October 1992), Santiago (May 1994) and Sana'a (January 1996), all of which affirmed the unwavering belief of professional communicators in freedom of expression, press freedom, independence and pluralism of the media, and the contribution of such freedoms to democratic processes. At their 28th General Conference, UNESCO Member States further declared that, 'press freedom is an essential component of any democracy.' All these declarations contain action programmes to strengthen press freedom in these regions.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Africa</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Turning to look at some practical initiatives, a media project entitled 'Independent Press in Africa', which was put in place after the signing of the Windhoek declaration, soon attracted the interest of a number of donors (Italy, USA, France). Under this project, the International Programme for the Development of Communication (IPDC) organised four sets of courses for journalists in 1994. In April 1995, IPDC arranged a multi-theme workshop for 33 English-speaking journalists and editors from Central and West Africa on marketing, distribution techniques, managing mass media enterprises in Africa, new communication technologies, journalism and ethical issues.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">There are now plans afoot to study the situation of the press in Mauritius, Madagascar and Comoros, and to publish several handbooks about press enterprises. Efforts will also be made to attract increased donor contributions so that the successes achieved by these initial training activities can be strengthened and shared with other regions.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">A further example of positive action in support of the media is the work of MISA (the Media Institute of Southern Africa-featured in more detail in the following article). This organisation has been receiving UNESCO support since 1994 under a funding arrangement with the Danish International Development Agency. The project seeks to strengthen links among the region's independent media so as to enhance the free flow of information. It also aims to boost cooperation and information-sharing with similar groups in developing and developed countries worldwide, to strengthen the ability of the region's independent media to stand on its own feet and to improve professional standards.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">MlSA, which was set up in 1992, has been monitoring and safeguarding press freedom in the region, facilitated by an electronic network for distribution of information on press freedom issues. It has mounted seminars and training workshops for professional journalists on computer-aided design, strategic financial management, journalism ethics and advertising management. MISA's campaigning material includes a bi-monthly magazine, Free Press: the Media Magazine of Southern Africa and a booklet, So this is Democray, which is a compilation of its 'action alerts' curing 1994 and 1995.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Another UNESCO initiative is the 'Communication and Good Governance in West and Central African Countries' project, supported by Germany. This aims to strengthen the human and technical capacity of the media in these regions so that they can make a contribution to good governance. The three year project is to be implemented in 10 countries - Benin, Chad, Equatorial Guinea, Gambia, Ghana, Guinea Bissau, Liberia, Mali, Sao Tome &amp; Principe and Togo.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Together with other institutions such as legislatures, the judiciary and civic organisations, media bodies like MISA have a useful role to play. They can enhance transparency and accountability by systematic analysis and reporting of government programmes, policies and pledges, and by encouraging public discussions which help people to make informed decisions about public issues and about how their leaders discharge the power vested in them. Fulfilment of these functions requires access to the media, and qualified, well-trained practitioners who can effectively use the media for information, education and communication on good governance issues.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Caribbean</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Turning our attention now to the Caribbean, the question of media freedom recently came to the fore in Trinidad and Tobago when 13 editors and journalists on The Guardian lost their jobs following publication of a number of controversial articles (some reports said they 'constructively resigned'). The events cast a shadow over the famous Carnival. Indeed, as one journalist put it, the Carnival quickly ceded to the 'sacrificial rites' of Holy Week. Six of the paper's youngest reporters were among those who lost their jobs-but out of the furore, a new newspaper was born.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">A 'Comparative Study of Media Laws in the CARICOM countries' by Ainsley Sahai, commissioned earlier by UNESCO, became a reference in the debates that followed. The study highlighted that all Caribbean countries guaranteed freedom of expression in their national constitutions. Indeed, Trinidad and Tobago's constitution explicitly guarantees press freedom as well. The Media Association of Trinidad and Tobago (MATT) organised two meetings. The first of these, on 10 April 1996, was a public forum on issues of press freedom. Although a full cross-section of society was not present, and not all the issues at stake were fully debated, it was nevertheless a start. Those who took the floor came from many sectors of society -women, the unemployed, workers, community organisations and at least three different religious groups. About a quarter of those who contributed spoke as individuals. While many criticised the press for errors in reporting, all confirmed the need to uphold a free press vis-a-vis both political pressures and economic and financial interests.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The public gave strong support to MATT and demanded that the forum be replicated in other parts of the country. It was the first time that the public had been given the opportunity to speak out on these issues. It was not so much the content of the discussion which counted, but the very fact that the event took place, bringing the media closer to its 'customers'. The meeting gave the public an opportunity to put over their own perceptions of press freedom, impartial reporting and the strengthening of democratic processes.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Two days later, with support from UNESCO, the Media Association staged a journalists' symposium, moderated by George John, consulting editor at The Guardian. David de Caires, publisher of Guyana's Stabroek News was invited by MATT as an external consultant. Drawing on past and more recent examples of uneasy relations between a free press and governments, Mr de Caires concluded with a headlinehitting statement; the relations of the press with government should not be too cosy, the press must maintain its adversarial position.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Many journalists took the floor to stress Trinidad and Tobago's constitutional guarantees for both freedom of expression and press freedom. They also stressed the need to safeguard editorial independence, not only in the printed press, but also in broadcasting, and urged the repeal of 'antiquated' libel laws-a point also made in the Sahai study. The preparation of a Freedom of Information Act was strongly urged to ensure access to public information.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">These events appear to have strengthened the resolve of the jobless journalists. They grouped together to set up a new weekly newspaper, called The Independent. The new publication focuses on investigative articles, comment and reviews. In addition, a monthly called The Formatt was launched by MATT to disseminate specialised news on press freedom issues and to provide print support for future public fore. Both newspapers brought out their first editions in early May amidst the celebrations of World Press Freedom Day.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Pacific</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">In the Pacific, issues of freedom of expression and press freedom are no less salient, although a key issue for practitioners there is the modernisation of infrastructures. This is needed to ensure that this vast island region does not find itself in the slow lane of the information highway.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The computerisation of radio newsrooms, in places such as the Cook Islands, Vanuatu, Fiji, Solomon Islands and Tonga, is a priority. The Cook Islands already has a fully computerised newspaper operation. Indeed, this is the first newspaper in the Pacific with the capacity to transmit photographs from various parts of the country to the newsroom electronically by phone.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Considerable concern has been expressed about the inadequacy of national television programming. There is a need for the people of the Pacific to see themselves and their culture, and not just the imported fare distributed by most international TV services. With UNESCO support, women media producers from seven island countries were able to meet to work out ways of cooperating on a series of television documentaries that they themselves produced and exchanged within the region. Preparations are now under way for the annual evaluation and awarding of prizes at the end of 1996. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">C.A.A. </P>
+<P ALIGN="JUSTIFY"></P>
+<B><P>&lt;&lt;TOC3&gt;&gt; Campaigning for free expression in the SADC region</P>
+</B><P ALIGN="JUSTIFY">by David Nthengwe</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The Media Institute of Southern Africa</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Officially launched in September 1992, the role of the Media Institute of Southern Africa is primarily that of coordinator, facilitator and communicator in the promotion of media freedom and diversity, (as envisaged in the 1991 Windhoek Declaration). MISA operates in 11 of the 1 2 SADC countries and is currently investigating setting up a chapter in the twelfth-Mauritius- which joined the Community 1995.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The chapters are serviced by a regional secretariat based in the Namibian capital, Windhoek. The secretariat is accountable to a policy-making governing council of elected representatives from each national chapter, while funding for MISA and its projects is channeled through the MISA Education and Production Trust, overseen by a board of independent trustees. The organisation is currently almost entirely donor-funded, with UNESCO, NORAD, SIDA, the KU, the Friedrich Ebert Stiftung, IBIS, and the Australian and German governments being the main contributors. Other income is generated through the sale of subscriptions to MISA publications and services.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The Institute's main work is in the field of advocacy; highlighting violations of media freedom and free expression, and exploring ways of ensuring that these fundamental freedoms become entrenched throughout Southern Africa. In 1994, MISA became a member of the International Freedom of Expression Exchange (IFEX) network in a bid to increase international awareness of media freedom violations in Southern Africa. Membership of IFEX has enabled MISA to distribute as well as receive information on media freedom issues in a quick and relatively cheap way via the Internet.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">'Action alerts'</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">In 1994 and 1995, MISA issued via IFEX and its own electronic mail network, the MISANET (see below), more than 190 'action alerts' relating to media freedom infringements in Southern Africa, and effective campaigns against some of these violations have resulted. In August 1994, Lesotho journalist, Rabuka Chalatse, was shot by soldiers while covering a demonstration. An alert issued by MISA triggered a swift response, and within 24 hours, funds had been raised to pay for emergency treatment which saved the young journalist's leg. In November 1995, Angolan freelance journalist, Mario Paiva, had his life threatened by people who, it was alleged, were state security agents. MlSA's alert prompted protest from throughout the world, and resulted in several governments offering Paiva sanctuary in their embassies in Angola. The threat against the journalist was subsequently lifted.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">MlSA's advocacy work has also shown that democratisation does not necessarily result in guaranteed media freedom and free expression. In Zambia, for example, which had a multi-party election in 1991, arcane laws inherited from previous regimes have been used against the private media in particular, and free expression, in general. As this article was being written, Fred M'membe, the Editor-in-Chief of Zambia's privately-owned daily 'The Post', and two of his colleagues, were starting an indefinite prison term for contempt of Parliament. The sentence was passed not by a court of law, but by the Speaker, under legislation inherited from British colonial rule. Their 'crime' was to comment on criticism made in Parliament of a Supreme Court decision which declared unconstitutional, laws requiring anyone wishing to stage a demonstration to obtain police permission first.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Five months prior to his arrest, M'membe received the MISA Press Freedom Award, which is presented annually to individuals or institutions considered to have made an outstanding contribution to the advancement of media freedom in Southern Africa. M'membe was the third recipient of the award.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Free flow of information essential</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">As the Windhoek Declaration points out, 'the establishment, maintenance and fostering of an independent, pluralistic and free press' is essential to economic development, as well as for the growth of democracy. Accordingly, MISA argues that the free flow of information is vital to the development process. Effective communication within SADC-a 'development community'- has been hampered by the region's poor postal and telecommunications services. MISA considers that these logistical barriers to the free flow of information are a form of censorship. In a bid to break through the information voids which have kept Southern African media workers and their audiences isolated from each other for so long, it has made particular use of advances in information technology, including, most notably, the Internet.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Over the past two years, MISA has been linking member organisations up to electronic mail (e-mail). This allows members throughout the region to exchange news, photographs and other information. To date, 25 MISA member organisations are linked to this network, called the MISANET, although further growth has been hampered by members' unfamiliarity with e-mail, and the lack of local technicians to train people and provide user support. Nonetheless, computerised communications have proved to be an appropriate technology, and development of the MISANET remains a top priority. By making some services available to non-MISA subscribers, MISA also intends to generate income and thus reduce its current dependency on donor funding.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Focus on training</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The coordination of training and material support to independent media is another area where MISA looks to develop media freedom and diversity. The region's independent media sometimes operates in politically and economically hostile environments. Its survival-and thus the sustenance and growth of media diversity-hinges on these organisations becoming highly professional, well-managed concerns.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Working through training institutions based primarily in the region, MISA coordinates workshops and other training programmes aimed at improving the skills of media workers, particularly in the fields of management and finance. Workshops in strategic and financial management, project management, advertising, marketing, sales and subscription management, ethics, subediting, and computerised design were staged during 1994 and 1995. For 1996, training is scheduled in economic reporting, project management, photography, advertising sales, circulation and sales management, computer-aided design, developing world and financial and strategic management. Instruction will also be provided to media workers without formal training. Meanwhile, research is to be carried out into setting up a media ombudsman for Southern Africa, printing press initiatives, media training needs, and the difficulties faced by women media workers in the region. The last-mentioned is in line with MlSA's policy of encouraging gender awareness and equality within the Southern African media.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Private and community-based media organisations face constant problems securing adequate finance. As businesses, they often do not qualify for donor support, while banks are reluctant to lend them money. Therefore, MISA is looking to set up of a Media Development Fund to which independent media can apply for loans, credit guarantees and grants. A study is currently being conducted into the feasibility of such a fund, which MISA hopes to have up-andrunning by early 1997.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Broadcasting in Southern Africa is still largely state-controlled. Moves by some of the region's governments to 'deregulate' broadcasting have been erratic, and many private broadcasting licenses granted in the process have gone to organisations or individuals closely linked to the authorities. MISA is now drawing up a policy aimed at seeking the effective liberalisation of broadcasting legislation covering public, private and community broadcasting throughout the region.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">As part of this process, MISA will, this year, stage a conference on broadcasting and community media, to coincide with its Annual General Meeting-which has become one of the largest gatherings of media workers on the African continent. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">D.N.</P>
+<P ALIGN="JUSTIFY"></P>
+<B><P>&lt;&lt;TOC3&gt;&gt; Volunteers show their worth</P>
+</B><P ALIGN="JUSTIFY">by Thomas M. Neufing</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Volunteers have become a major component in international development efforts. They make up a significant proportion of the total human resources available for development cooperation (up to a fifth of the skilled international personnel serving in developing countries). In the early days, volunteer service was strongly influenced by the idea of oneway technical assistance. Specialists, mainly from the North, served in developing nations where their expertise was desperately needed but not yet found among local citizens. Much has changed since.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">After the US Peace Corps, the UN Volunteers Programme (UNV) ranks as the second largest volunteer-sendina agency with some 4000 professionals in the field every year. Its universality and internationality is reflected in the high number of UNV specialists (74%) who come from developing countries. The scope and size of the international volunteer contribution to development cooperation (notably areas such as HIV/AIDS and the environment), has increased significantly over the years as a result of the changing development challenge. The re-thinking of the role of technical cooperation is equally central to the volunteer debate and this has led to much greater flexibility in the ways in which volunteer services are provided. The important role volunteers can play in peace building efforts with a long-term development dimension, complementary to humanitarian relief, is increasingly being recognised.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Working with rather than for people</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">With the UNV's 25th anniversary, and the relocation of its headquarters to Bonn this summer, it is an appropriate time both to assess and to acknowledge the contribution made by these volunteers. Since the programme began in 1971, some 14 000 professionals have dedicated a period of their lives to serve as a UNV. The programme is administered by UNDP, and is therefore intimately linked to its structures, particularly in the field. Regarding community-based initiatives, the comparative advantage of UNVs is that of working with rather than for people over an extended period, thus facilitating their initiatives. The experience of many development agencies shows that in promoting socio-economic change at the village level, the type of person needed is one who-through long-term commitment and sensitivity -can learn as much from local partners as offer advice to them.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">International volunteers are engaged mainly in rural development tasks. Those working through specialised NGOs such as the Red Cross, and Medecins Sans Frontieres have proved to be highly effective agents, supporting governments faced with disaster situations. In the case of UNV, the value of using volunteer specialists from other developing nations, as a way of encouraging technical cooperation amongst developing countries, is particularly recognised. Most volunteers- perhaps two-thirds - serve in least developed and small island countries. And about three-quarters serve in rural areas, working mostly in programmes of agricultural and community development, health, education and the supply of basic services. Since the end of the Cold War, a growing number have been deployed in emergency relief, refugee and rehabilitation programmes. UNVs make up 10% of the UN's civilian component in Cambodia; 4096 of the field staff of the World Food Programme and almost 100% of outreach workers attached to the UN Mission in Guatemala. UNVs are increasingly involved in human rights promotion, the organisation of elections and conflict resolution.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">There is a consensus among the main international humanitarian and development actors that their programmes should be mutually supportive. For example, development efforts must respond to humanitarian crises by remaining on the scene and supporting immediate needs, as well as aiding in the prevention of crises which are known to be looming. Emergency humanitarian assistance should also pave the way for longer term development by viewing the immediacy of the moment through the lens of future sustainable rehabilitation. Both sets of activities should, ideally, be launched and implemented in tandem with local bodies.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">External assistance efforts must include strengthening local capacity to cope with problems. Empowerment strategies which inform, educate and facilitate the people's own vision of peaceful and sustainable living environments (including respect for human rights) are fundamental to the future of communities coping in the aftermath of crisis.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Relief, rehabilitation and development?</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The UNV programme has been active in exploring the efficacy of volunteer support to communities in crisis in order to bridge the gap between immediate needs and longer term developmental goals. In 1994, the UNV held its 4th Special Consultation, entitled, Between Crisis and Development - Volunteer Roles and UNV's Contribution. At this event, donor governments, UN agencies and cooperating partners from civil society had an indepth discussion of the issues surrounding volunteer efforts, and the complementary nature of emergency interventions and follow-up measures. The participants reconfirmed the need for local capacity building. They also affirmed the usefulness of the UN Volunteer contribution in crisis prevention, emergency rehabilitation and 'building bridges' to sustainable development. The work of UNVs in preventive action and promoting post-conflict development was highlighted. There has been a significant increase in demand for specialist volunteer services in all types of crisis. These may be economic, natural or man-made, but they all have in common the need to provide essential relief and rehabilitation services for basic survival (to refugees and resident populations). In many countries, disasters and internal strife have put so much pressure on essential public services that the longterm capacity of the people to recover may be threatened. Governments in developing countries and donors both believe it is fully justified to use volunteer specialists to help provide such services during the adjustment period.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">'Mixed' teams</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The contribution of both international and national volunteers is often essential to link immediate relief efforts to future long-term development. National volunteers-people working in their own countries within the UN framework-complement the international approach by providing the key grassroots perspective. UN Volunteers who speak local languages, live and work in remote communities, are familiar with community structures and are known to local leaders, play a key part in facilitating preventive action and providing follow-up in the aftermath of a crisis. UNV specialists are well-placed to build effective partnerships with national and local actors. In the last two years, some 2000 UN Volunteers have worked in various parts of the world in prevention and preparedness, peacekeeping, electoral support, human rights, rehabilitation and reconstruction, and humanitarian relief.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Burundi offers an example of an initiative designed to stem a crisis through local capacity-building. The UNV is financing a project there which supports the mediation and dialogue efforts of the UN Secretary General's Special Representative (SRSG) through the recruitment of UNV peace advisers and conflict resolution facilitators. This project is being run successfully out of the SRSG's office, extending public awareness of the reconciliation process. It includes use of the mass media to promote understanding, and brings local actors together to work for peaceful solutions.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The tasks undertaken by UN volunteers all fit into the spectrum which has 'crisis' et one end end 'development' at the other. The work, moreover, is undertaken in partnership-with civil society (NGOs and community-based organisations), government departments, UN agencies and regional international organisations (such as the KU).</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Through efforts that aim to link relief, rehabilitation and development, new productive partnerships are emerging to enhance coherence, coordination and complementarily.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The growth of professionalism</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">30 years ago, the typical profile of an international volunteer was that of a generalist graduate from an industrialised country seeking first-time experience abroad before settling down to a career. Over time, the governments of developing countries made clear their need for practical and often specialised skills aimed at giving them the ability to manage their own programmes. They increasingly expressed impatience at hosting untrained volunteers. Professionalism became the key word. Unfortunately, the word 'volunteer' is still a source of confusion: it is often equated with 'amateur'. This is a perception that now needs to be corrected. The personnel sent out by most agencies that supply volunteers are likely to be in their thirties, with post-graduate qualifications and several years' practical experience in their fields. The typical UNV specialist is an example par excel/ence of this trend: 39 years of age, holding a Master's degree and with more than ten years of experience in a particular discipline.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">It was not just the dedication, but also the professionalism of the hundreds of UN Volunteers serving in Mozambique that impressed Aldo Ajello, the former UN Special Representative in Mozambique (now EU Special Envoy for the Great Lakes Region). 'If I were to run another mission,' he said, 'I would ask immediately for volunteers.' In terms of monitoring-which was vital in building up the trust and confidence needed to ensure the election results were accepted-'UNV electoral officers were our only real presence and they proved to be extremely professional.' ~ T.N. </P>
+<P ALIGN="JUSTIFY">Study by the World Wide Fund for Nature</P>
+<P ALIGN="JUSTIFY"></P>
+<B><P>&lt;&lt;TOC3&gt;&gt; Structural adiustment, the environment, and sustainable development</P>
+</B><P ALIGN="JUSTIFY">by David Reed</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">On 29 May, David Reed of the World Wide Fund for Nature (WWF) was in Brussels to present the results of a study undertaken by the WWF, with the support of the European Commission, the longterm consequences of structural adjustment programmes (SAPs) on the environment and the use of nature/ resources. Conclusions were drawn from nine country case studies from Cameroon, Mall Tanzania, Zambia, El Salvador, Jamaica, Venezuela, Vietnam and Pakistan. We publish here an abridged version of Mr Reed's general presentation.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">SAPs, often implemented at the instigation of the international financial institutions, have responded to the pervasive economic problems of the 1980s and to profound changes in the economy in recent decades. The programmes have generally been successful in improving macroeconomic indicators in developing countries. The marketorientation of economies has been increased through liberalised trade and capital flows, privatisation, reductions in regulation and price setting, and cuts in government budgets and programmes. For most developing countries, these changes were essential to economic recovery and adjustment to the new global marketplace.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Sustainable development in the social, economic, and environmental sense, has, however, been ignored in SAPs. Many reform programmes have been accompanied by increases in poverty and unemployment, worsening income distribution, and the collapse of social services, environmental protection and state institutional capacities. These immediate costs of adjustment inhibit countries' long-term ability to expand productivity and employment opportunities, as natural resources are exploited indiscriminately to meet short-term needs.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Environmental impacts</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The environmental effects of structural adjustment vary from country to country depending on the specific components of the reform package, the structure of the economy, and the implementation process. The WWF's country case studies reveal particular mechanisms through which structural adjustment has altered resource-use patterns. Some more general patterns also emerge from the studies. Everywhere, cuts in government institutions and funding have reduced the state's capacity to facilitate the transition process, to compensate for market failures, and to provide for long-term and social sustainability.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Many reforms associated with structural adjustment have the potential to improve both environmental and economic outcomes. However, the failure to implement complementary environmental policies or strengthen institutions and regulations, has created a very mixed environmental record. Increases in poverty, greater production incentives, and the loss of government regulatory capacity, have all aggravated patterns of poor resource use.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Extractive and agricultural economies generally increased production in response to greater exposure to global markets. Without proper policies in place, this increase has put a strain on fragile ecosystems. Environmental pressures include increased land degradation and deforestation for agriculture, livestock and timber production; increased production of non-renewables without long-term investment of the proceeds or environmental safeguards; and increased pollution and damage to the ecosystem from unregulated tourism.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The burden of fiscal retrenchment and price changes under structural adjustment have fallen most heavily on the poor, particularly women. The strong association between poverty and environmental degradation has been revealed, as efforts to maintain livelihoods have led to deforestation, land degradation, overhunting and other pressures on endangered species, as well as the unmanaged extraction of nonrenewable resources. Increasing poverty and unemployment associated with adjustment has also added to population pressures in urban areas with insufficient infrastructure exacerbating problems of pollution, disease and congestion.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The implications of disregarding the environmental and social impact of adjustment are examined in the various case studies. Structural adjustment has been sustained by the promise that market-orientation and export-led - growth will raise living standards. Evidence from the studies, however, strongly suggests that long-term productive capacity is being destroyed by short-term exploitation of natural resources. Not only environmental but also economic and social sustainability are threatened by the loss of environmental goods and services. Drawing down natural capital has been encouraged by government policies that promote exports and open resources up to international markets. And the process is accelerated by the growing population of poor and unemployed who rely on natural resources for survival.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Recommendations</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Following its study, the WWF offers a series of recommendations to reduce the environmental costs of structural adjustment and economic integration, and to reorient structural adjustment aims towards sustainable development. Most urgently, environmental issues must be integrated into structural economic reforms - environmental assessments must become part of the programmes. A strategic vision of the role that natural resources and environmental goods and services could play in the transformation of developing economies is essential to designing appropriate strategies. Efforts to industrialise economies must include consideration of the environmental implications. Social services and environmental institutions must be maintained during the adjustment process to prevent increases in poverty and environmental degradation that have both short-term and long-term consequences for development. Essential services include credit and marketing support to small farmers, income-generating opportunities for women, food-assistance programmes, and promotion of distributional equity. The state's role in providing services which neither the private sector nor civil society can provide, must be maintained.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Given the great variety in economic structures and in the capacity of markets and civil society among developing countries, adjustment strategies and government roles must be tailored to each case. Everywhere, countries must implement national institutional reforms for environmental management. Civil society must be strengthened to allow participation in the adjustment process. International financial institutions promoting and designing SAPs must reform their policies and approaches to implementation in the light of the clear evidence that macroeconomic reforms are having a profound effect on the environment and on the possibilities for sustainable development. Continuing failure to correct these problems on a national level accentuates the concern for addressing issues of sustainability on a global level. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">D.R. </P>
+<P ALIGN="JUSTIFY"></P>
+<B><P ALIGN="CENTER">&lt;&lt;TOC2&gt;&gt; Culture and society</P>
+</B><P ALIGN="JUSTIFY"></P>
+<B><P>&lt;&lt;TOC3&gt;&gt; Why a Biennial Festival of Contemporary African Art?</P>
+</B><P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Dak'Art 96</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The first World Festival of Negro Art, held in 1966, was essentially a political exercise. In the post-independence period, it was felt necessary to show the world that the people of Africa (both the continent and the diaspora), had a rich culture which had long been suppressed. The festival - which has never been repeated-is viewed with a great deal of nostalgia by supporters of modern African art and black intellectuals. The better, brighter future, which seemed at the time to be just over the horizon, never quite lived up to expectation. Even before financing problems had surfaced, the festival's fate had already been sealed by petty political rivalries and a greedy pursuit of the limelight. Years later, attempts to relaunch the event met with a lukewarm reception. It was already the beginning of the end as far as ideologies were concerned. In complete contrast, Dak'Art 96 (Dakar, 915 May 1996) set its sights firmly on the market place, nowadays the yardstick by which all success is measured. Its goals were simple: to break into the art market and overcome the generally held prejudice that contemporary African art lacks modernity.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">An international market for African art does exist, but it concerns itself solely with ancient art- and Africa itself profits little from such trade. Indeed, it would be more accurate to speak of plundering than of trade. The seminar, organised last year by the Terveuren Museum in Brussels on the looting of African works of art, revealed the true extent of the phenomenon. Despite the fact that pirated works fetch considerable sums on the black market, contemporary African artists are faced with a 'Catch-22' situation. Major galleries in Europe, America and Japan do not exhibit their work because African art is ignored by the leading art periodicals; and their work never appears in these publications because it is never exhibited. One reason for the fact that African art is not put on show is that virtually no funds are allocated by international institutions to sponsor exhibitions by the artists in question.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Many third-world governments do not dare, are unwilling or are unable to include culture on their list of priorities within international cooperation agreements. One exception is Burkina Faso which now boasts a cinema industry as a result. Senegal is trying to follow in its footsteps. But there are not many places in Africa where artists are promoted for the quality of their creative output. The majority of initiatives have, in fact, been on a voluntary basis. The magazine Revue Noire is one of the most significant examples of this approach. A group of aficionados of contemporary African art - indeed with a passion for art pure and simple, whether African or European-decided to try and break the vicious circle. They looked at two options: the establishment of an art gallery of worldwide renown or of an equally prestigious arts publication, and came down in favour of the latter. Thus Revue Noire was born. However, its success was generally given very slim odds: it was seen as too glossy, too expensive and too intellectual. The sub-text here of course, is that a publication about African art had no right to be glossy, expensive or intellectual, especially since the money could have been used for something far more 'useful' to the development of these countries.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Others, such as Marie-Claire Mwanza from l'Espace Alizes in Brussels, have attacked the problem from a different angle-by exhibiting contemporary African art. Prior to her initiative, there was not a single gallery in Brussels that specialised in this sector of the market, and there are still none that figure on the shopping lists of the world's great collectors. Whatever the price set for a contemporary African work, it is generally perceived as being too high. The contrast with the prices demanded for works by even the youngest European or American artists, even for their very first exhibitions, speaks volumes. African art is too expensive in relation to what exactly ? The answer is in relation to the status accorded to it, which is of course determined by the art world. In other words, a big fat zero if one considers the fact that African art is never exhibited.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Thanks to Revue Noire, African art has been brought to the major galleries of the Western world. Similar projects have been launched or are in the process of being launched in various countries of the West, such as the magazine NKA in Brooklyn, for example. Exhibition organisers, museums, galleries and those looking to stage art festivals now know on whose door to knock, and the last few months have proved extremely promising. The Guggenheim Museum in New York is currently hosting a major exhibition of African art, and Africa 95, held in London, was swiftly followed by Copenhagen 96. The Guggenheim Museum, moreover, is in a completely different league to the Museum of African and Oceanic Art in Paris or the Museum of Central Africa in Tervueren, Belgium (formerly the Colonial Museum)-it is one of the world's most prestigious temples of modern art. What is more, London's Africa 95, which was so disparaged by African art specialists, who considered it nothing more than a meeting place for traders, did, whether we like it or not, act as a significant catalyst. And what about pirated works of art, such as those plundered from the Niger Valley ? These have found a 'home' in public as well as private collections, pointing to a real need to 'clean out the Augean stables'.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">A few African artists are beginning to get themselves known within 'the market', but there are still not enough of them. It was with great foresight that the organisers of Dak'Art placed these artists at the top of their invitation list. Another shrewd move was to invite the art market's arbiters of taste to select those African artists who should present solo exhibitions, and to ask celebrated art critics and collectors to form part of the international panel of judges.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">It is probably true to say that Africa has rarely known such a dynamic period of creativity which places it at the forefront of global aesthetic trends. The aim of the Biennial Festival was to underline this fact beyond any doubt. Among those artists who are currently in a position to break into the market, the Senegalese sculptor, Ousmane Sow, probably heads the list. Paradoxically, however, Ousmane Sow's work was not presented at Dakar although he himself was there, his tall, striking figure standing out from the crowd. Despite the fact that he lent his support to Dak'Art 96 and that the opening gala was partly dedicated to him with the magnificent film of Beatrice Soule, Ousmane Sow resolutely refused to display his own work. He has no wish to take part in gatherings of 'African artists'. He is an artist and he is African, but he is not an 'African artist'. 'A Japanese artist is a contemporary artist in this universal world', he argues, 'so why should I allow myself to be pigeon-holed in a ghetto ?' No matter how satisfied and pleased champions of contemporary African art may be with the organisation behind the Biennial Festival, they cannot deny that Ousmane Sow has a point. Having said this, there is no contradiction here, but rather a complementary vision. Sow's stance and the idea behind Dak'Art are part of a two-pronged attack, to borrow a military term. The organisers of the Biennial and Sow himself doubtless saw it in this way, and decided to join forces.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Each time Beatrice Soule tackles the work of an artist, she explores it in a very unusual way, reinventing the arts documentary. Her films are reminiscent of the music of Nino Rota in Fe//ini's films, Rota subjugating himself to the service of the director's work, sublimating his own originality through this extreme humility. It is impossible to picture the images of Federico Fellini without Rota's haunting music. Beatrice Soule saw in Sow's work a love affair between an artist and his sculpture, coming up with the idea of placing Sow's sculptures in the savannah and imagining the intimate interaction between Africa's natural world, which is at the heart of the artist's inspiration, and his works, which the natural world is able to absorb back into itself. The result of this juxtaposition is that the physical work of art is eclipsed by sheer creative force and spirit. The genius behind the work becomes the work, merges with it and is reincarnated in it. The one thing that Soule did not film was Ousmane Sow himself, her images concentrating solely on the creative act. It would be illusory to attempt to explain a Beatrice Soule film, especially this film. When she unveils how the artist tames physical matter, reinventing materials in order to create a work of art, technique simply recedes into the background, becoming blurred and intangible. Whereas others would have adopted a scientific or factual approach, her camera perceives the abstract aspects of the piece-and its gestation. The film was due to be broadcast on the international FrancoGerman arts channel Arte. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">If Ousmane Sow's sculptures are characterised by their gigantic proportions, then those of Georges Adeagbo, a Beninois artist whose name is also beginning to be heard in the commercial art establishment, are characterised by their 'fugacity'. Adeagbo's artistic constructions are as fleeting as puffs of smoke, like voodoo symbols scratched out in the sand. His art is symbolic and ephemeral. Once one of his works has been exhibited, all that remains of it is a hollow shell which he has to reinvent over and over again. Adeagbo constructs ideas, using a host of assorted materials which he painstakingly selects over months, even years. Yet despite the meticulous care with which they are put together, as far as the artist is concerned, the materials per se are of no importance. He could convey exactly the same idea using other elements. An Adeagbo piece is not merely a pile of objects. It is neither conceptual art, nor scrap art. It consists rather of 'installations' which rise and spread outwards. Sometimes, he uses specially constructed sculptures. At other times he employs everyday objects- shoes, saucepans, stones, spectacles or footballs. He also works with written material; manuscripts, parchment, pieces of newspaper and books, portraying the written word as both a creative force and a deceptive screen. Adeagbo himself is a man of few words. Perpetually crouched on the ground, he constructs, modifies, touches and observes his creations. Why should these constructions remind us so much of paintings? They are as much a pile of objects as a painting is an accumulation of layers of paint. It is by forgetting the paint that we are able to admire the picture and it is by looking beyond the materials used by Adeagbo that his work truly reveals itself. Indeed, it is a sign of his genius as an artist that the materials never intrude upon our contemplation of his work. In Dakar, Adeagbo's work was shown in the AIDS exhibition organised by Revue Noire. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Another artist who took part in the AIDS exhibition, and whose art could well be the impetus behind the new universal aesthetic, the avant-garde (if such a concept has a meaning), is Pascale Marthine Tayou from Cameroon. He was given the honour of presenting one of the five solo exhibitions. Tayou was sponsored by Yakuyi Kawagushi, the curator of the Setagaya Museum in Tokyo, who exhibited his work at the forum organised within the overall framework of the exhibition. While the term 'installation' may best describe the works of Georges Adeagbo's, Tayou's work falls unquestionably under the heading of sculpture. This is despite the fact that the two artists use virtually identical materials. Tayou sculpts from wood, covering his pieces with all manner of manufactured and salvaged objects such as shoes, nails, plastic bags and enormous condoms, or with natural objects such as bits of roots and stones. He then paints the arrangement. The work is dense, unyielding and mesmerising, often etching itself into the onlooker's mind. His sculpture lacks heavy ornamentation, yet its starkness has a rich quality, the theme encompassed by a jumble of material standing out clearly, like the outline of a silhouette. Take his work 'Fight against AIDS'. The piece consists of a wooden frame in the shape of figure-of-eight, with each horizontal line doubled, defining a key element in a tragic body with bulging eyes and a Pere Ubu belly. In contrast to this suffocatingly tragic figure, the brightly-coloured shoes of a Harlequin with a faded costume offer a comical note.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">There were other creators who could well ruffle a few feathers in the art market that ultimately makes or breaks an artist: Tamsir Dia of Cote d'lvoire (whose screaming figures are reminiscent of Munch), Cheikh Niass of Senegal, Mathilde Moro of Cote d'lvoire and Abdoulaye Konate of Mali. The last mentioned was honoured with the highest award of the festival.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">A decision was taken that Dak'Art 96 should encompass other areas of creativity, such as music, design and fashion, in addition to the visual arts. At the gala evening held to inaugurate the Festival, there was a fashion show choreographed in the manner of a ballet. The staging of this can only be described as mawkish. The audience were treated neither to a real performance, nor to a good fashion show. The second fashion spot, which was supposed to present an overview of African design, was also quite pitiful. If the event's organisers decide to keep these parallel areas of creativity in the Festival, then their decision will be solely thanks to the success of the International Design Exhibition. Apart from two or three 'exotic' pieces, this was generally of a very high standard.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The European Community's choice in awarding the prize for creativity to a designer, Vincent Amian Namien from the Cote d'lvoire, was particularly revealing. This artist strips everything down to its bare essentials, creating a line that is so purified as to leave only the quintessence of form. Thus, he creates a chair that is nothing more than a perfect metal triangle, with four boards and four metal wires-and yet offers perfect comfort.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Claire Kane, a fashion designer of Franco-Senegalese descent, had the verve to go it alone and show her collection at the prestigious Salon of Design. Her clothes are characterised by the rejection of all superfluous detail, achieving a fluid line that stylises movement. Following an aesthetic code that has been decanted from the melting pot of the collective costume heritage of the entire continent, Claire Kane is directly involved in the creation of her designs, from the weaving of the cloth to the last finishing touches. In fact, she admits that her true passion is fabric rather than fashion, her favourite material being woven pagne. She often uses silk-screen printing to introduce pattern. She then adds words to the patterns in her designs and, abracadabra, one would think that this is the way it has always been done in Africa. A subtle modernity, combining both past and future, seems to be a recurring motif in African creativity. International artists, still few in number, travel from Dakar to be dressed by her.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">If, in the future, the Festival's organisers decide to concentrate solety on the visual arts, this would come as no surprise. On the other hand, it would also make sense to continue to include design and fashion. A country's cultural heritage should be considered one of its raw materials and a source of economic wealth, and unimaginative accountants may have to resign themselves to this fact. Herein lies a possible answer to the question: 'why hold a Biennial Festival of Contemporary African Art?'</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Hegei Goutier</P>
+<P ALIGN="JUSTIFY"></P>
+<B><P>&lt;&lt;TOC3&gt;&gt; Acting against AIDS</P>
+</B><P ALIGN="JUSTIFY">by Robert Rowe</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Many ways of raising money to fight AlDS have been tried, but one of the most unusual must surely be the approach taken by an official of the European Commission. Robert Rowe, who until last year was an assistant editor on The Courier, put on a oneman show in Brussels and then rook it to the other side of the world to raise money for a voluntary organisation working on AIDS prevention and care in Malaysia. Here is his story of fighting the virus with the power of the theatre.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">'By the year 2000, South-East Asia will be host to the majority of the world's AIDS cases.' So runs a stark prediction from the World Health Organisation, quoted in a recent paper from a grouping of NGOs affiliated to the Malaysian AIDS Foundation. It goes on to predict that 'the region faces a potential HIV spread of titanic proportions.' In Thailand, a country with a large population and a sad reputation for prostitution, the HIV threat was recognised relatively early and effective public awareness campaigns have successfully reversed the rise in the incidence of infection. But in neighbouring Malaysia, where stricter religious and social attitudes have inhibited wide public discussion of the disease and its methods of transmission, over 13000 people were HIV-positive at the last count-and that is just the figure derived from the small percentage of the population who have been tested. Activists say the true number is certainly higher and it is growing every day.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The first cases of HIV in Malaysia were found among intravenous drug users and sex workers, and one of the earliest organisations to begin working with people engaged in these high-risk activities was Pink Triangle. This is a voluntary, non-profit-making body which started up in 1987 by setting up AIDS prevention and support programmes for and with the general public and the gay community. Its name, in fact, refers to the pink triangle badge which men sent to concentration camps in Nazi Germany for homosexuality were made to wear. The group has always depended heavily on volunteers to plan and carry out its programmes, which now also involve running a support group for people with HIV or AIDS and a street outreach programme and drop-in centre providing AIDS information, basic medical care, temporary shelter and food for sex workers, injecting drug users and transsexuals. The centre can also provide legal referrals for members of these groups summonsed to appear in court. For the general public, talks, workshops and poster and photo exhibitions are held in schools, hospitals, factories, youth and corporate organisations and other NGOs. Pink Triangle trains its volunteers, too, to provide counselling and information about AIDS and sexuality to anyone who calls up on a confidential telephone line.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The work is serious and vital, but the atmosphere is far from gloomy in Pink Triangle's premises in a lively part of the Malaysian capital, Kuala Lumpur. Though funding comes from several sources at home and abroad, including the European Union, the organisation still has to generate a lot of its own money, and one successful method they have used is to put on imaginative events where fund-raising can be combined with an opportunity to raise public awareness. Last December, for example, they marked the week surrounding World AIDS Day with a string of shows, dance parties, talk-ins and street activities called Pinkfest '95. In venues all over the town, and on television and radio, well-known personalities joined a hundred of Pink Triangle's own speakers and performers to provide education without moralising. The aim was to personalise the issue of AIDS by showing how anyone could be at risk, but at the same time dealing in facts, not fear. Thousands of attractively designed and very frank leaflets and posters put across the virus-busting message in catchy graphics and pithy phrases in several languages.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">I happened to be in Kuala Lumpur around New Year and saw a video of some of the Pinkfest highlights which set me thinking how admirable an impression of solidarity and self-help the anti-AIDS struggle in Malaysia conveys, and to wondering whether, back in Brussels, it might not be possible for us in Europe to do something to help. It particularly impressed and touched me that while Pink Triangle delivers its message to every single member of Malaysian society, it makes quite clear, even by its name, that it has a special care for some of that society's most downtrodden members, people for whom no one else had ever ventured to speak. Public silence, opprobrium and ridicule make it especially hard to get the safe-sex message through to gay men, especially the young, to transsexuals and sex workers, and as long as there is no cure the only way of containing the spread of infection is by education- and by changing social attitudes. The many women whose husbands or partners are careless about infection also stand to benefit from greater openness and more factual information. But organising all this takes money.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">It happens that among the multinational English-speaking expatriate community in Brussels there is a thriving amateur theatre scene-in fact they say that if two British people found themselves on an otherwise deserted island, one would immediately put on a play for the other, and the same seems to hold true of the Irish and the North Americans. However, it was less certain that anyone apart from me would want to exert themselves, for the many weeks required to stage a production, on behalf of an AIDS charity in a remote Asian country, so l decided to go ahead by myself and perform a one-man comedy. The play was Brief Lives; it has nothing whatever to do with AIDS, but in its day it was a huge success in London and New York. Adapted in the 1960s by the British actor Patrick Garland from the dusty old memoirs of a real historical figure, John Aubrey, it depicts a day in the life of this 1 7th-century English scientist, historian and wit. As he potters about, an extremely old man, in a garret full of manuscripts and curios, he reminisces about his contemporaries in hilarious and touching vignettes, the potted biographies which give the play its name. Aubrey died in penury, but the picture he gives of a vanished age is now reckoned to be the equal of the record we find in the diary of the better-known Samuel Pepys.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">It is also a great deal funnier, and when I showed the script to various friends I was astounded and moved to discover how many of them wanted to be involved in the project. Eventually we put together a team headed by the director, Anne Wilkinson, a music impresario married to a coal expert from the European Commission, with production, design, stage management, lighting, sound effects, costume, music and offstage voices-not to mention publicity and box office-provided by other friends from the European institutions or the private sector. The five performances were given in June in a small theatre just adapted from a pottery workshop, and altogether the Brussels showing made a profit of some 110 000 Belgian francs.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">We had expected just to send this donation to Pink Triangle through the post, but to our immense pleasure they said they would like to see not just the money but, if possible, the play too. By ingenious compression the designer, Burt Baum, managed to cut the essentials of the set down to three sheets painted to give a three-dimensional effect, we put the voices and music on cassette, rolled up the costume tightly and worked out that the whole play, thus reduced, could be got into one suitcase. There is a little theatre company in the Pacific ACP state of Vanuatu called Wan Smol (One Small) Bag which actually gave me this idea. So off I went to Kuala Lumpur with this bag, and did the play another five times there.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The staging in Malaysia was done by an adventurous outfit called Instant Cafe Theatre. This young company has a reputation for pushing forward the boundaries of public discussion with topical plays and supports Pink Triangle's aims and work. Brief Lives was well outside their usual repertoire, as well as being spoken in the English of 300 years ago. My worry was that bringing such a Western and Eurocentric entertainment might be resented as cultural imperialism in a country with three great and fascinating cultures of its own, Malay, Chinese and Indian, each with its own style of drama. But it turned out there was a local tradition of amateur dramatics in English, particularly Shakespeare, and that English is the usual lingua franca for speakers of different Asian languages. What went down unexpectedly well was the depiction of an old man nearing death and reviewing the best moments of his life; as the character puts it in the play, 'When a boy, I did always love to converse with old men, as living histories,' and Maiaysians have a particular regard and affection for the elderly. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">I came away from Kuala Lumpur with many charming memories: the unfailing, sweet-natured enthusiasm of the audience; the relief on the first night as I stood on stage in a floor-length costume of three layers, designed to suggest London in midwinter rather than to cope with the equatorial heat of the Malay peninsula, and realised that the stage was air conditioned. The night when this air conditioning blew out a vital candle on the stage, and a man in the front row lent me his highly un-17th-century lighter to get my clay pipe going. The Chinese friend who gave me a genuine antique opium pipe to add to John Aubrey's collection of exotic curios. The delicious succession of Asian chicken dishes which the stage manager produced for me to eat on stage, cooked in very un-English coconut milk or glazed with rice wine. The work permit which specified I could perform as an artiste but must not 'sit out' or dance with the audience! The theatre's resident singer asking if she could add the play's Elizabethan theme song, with lute accompaniment, to her repertoire.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Taking this play to another continent was a fascinating cultural experience for me as a European, and I hope for the audiences too it was something more than just a painless way of being relieved of money in a deserving cause. At any rate the theatre asked if they could have another play soon, one in which Malaysian actors could be incorporated as well. As for Pink Triangle, some of its leading lights were packing their bags to go to Vancouver for this year's International AIDS Conference, but before they left it was a pleasure to hand over the proceeds of the whole venture and to hear that the organisation will use the money to develop a drop-in centre for people approaching them in person for the first time. Some first-timers are understandably timid about coming to the unfamiliar (and clearly signposted) premises for help or information, and a private space where they can talk in confidence is something Pink Triangle has always wanted to provide but could never find the funds for, as the project or programme money they get from their regular donors is invariably tied to what outsiders might think were more urgent priorities. It is not only the headline grabbing schemes which have useful effects: a quietly welcoming space where someone can be himself or herself may do more to dispel an individual's fear and ignorance than publicly visible campaigning, especially where religious and social pressures against certain types of nonconformity are strong. In fighting HIV/AIDS, we must try whatever works. And empowerment must begin with the self. It was a great privilege to be welcomed in like any other volunteer wanting to help bring about a necessary change. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">R.R. </P>
+<P ALIGN="JUSTIFY"></P>
+<B><P ALIGN="CENTER">&lt;&lt;TOC2&gt;&gt; CTA-Bulletin</P>
+</B><P ALIGN="JUSTIFY"></P>
+<B><P>&lt;&lt;TOC3&gt;&gt; Earthen architecture</P>
+</B><P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Materials, techniques and knowledge at the service of new architectural applications</P>
+<P ALIGN="JUSTIFY">by Hugo Houben and Hubert Guilland.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">A major building material</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The importance - both in quantity and quality- of unbaked earth constructions in the world is very little known. Believed to be of ancient origin, (it is associated with the early civilisations of the Nile, Tigris and Euphrates, Indus and Huang He), nowadays, earth is not usually regarded as a major building material. This is despite the fact that it continues to leave an undeniable and distinctive imprint on the architectural landscapes, both rural and urban, of many countries. Unbaked earth is still, in fact, a major building material, being used extensively by people to erect homes and other buildings. Although sites of human occupation have seen constant regeneration with the passage of time, unbaked earth construction has persisted. Excavated from the soil itself, and moulded by the hand of man (or trampled by beasts of burden), the result is a building material which is used in all forms of construction-from simple huts and modest homes, to farm buildings, large houses, urban blocks, religious edifices, castles and palaces. The skills employed are based on knowledge acquired and refined over a long period of time.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">A contemporary building material</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">While the use of earth in so called 'advanced' countries has declined in the 40 years since the end of the Second World War, in the developing countries it has continued unabated. In the former, the industrialisation of construction and other sweeping changes have rendered obsolete ancient techniques based on the use of local skills and materials, and on mutual help within communities. In the latter, various factors have dictated the continuing use of locally available solutions, materials and knowledge. These include shortages of processed materials (which are costly in both foreign currency and imported energy terms), the widening of the development 'gap', the accumulation of debt contracted within the international monetary system and the survival of local life-styles in which people are accustomed to coming to get her for mutual help for survival. In these countries, which have no industrial means, and which are to be found in various latitudes across the world, earth remains the main-if not the only- building material. Do these circumstances mean that it is a poor material, fashioned using outmoded techniques and unsuitable for promoting the development which is so necessary? The answer to this question is a clear 'no'. On the contrary, the materials and techniques involved are generally of a high standard. They can ensure true architectural quality, allowing communities to continue creating their private or public living environments, and to integrate their buildings into a coherent framework of self-generated development which makes the most of the resources available, both human and material. In fact, scientific and architectural research into earth as a building material, and on related building techniques, has made considerable progress in recent decades. Combined with investments made by industrialists and construction companies, the result is that we now have a wide range of properly mastered production procedures and technical solutions available. These offer great flexibility in meeting a wide range of possible applications.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Making a mark on world architecture</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Recent global surveys, although partial (covering about 30% of the world's housing), have given us an indication of how extensively earth is used in construction. In developing countries alone, 50% of the rural population and 20% of those living in urban areas are believed to be concerned. The figures, which are drawn from the combined data of statistical surveys in various areas, and from bibliographical information, almost certainly underestimate the true position. They show, for example, that 60% of the housing in Peru is in moulded bricks or rammed earth. 83% of the houses in Kigali, the capital of Rwanda, are made of earth. More than 70%of India's housing stock is constructed out of moulded earth bricks or using successive layers of earth, and these buildings provide shelter for nearly six hundred million people. In France, many rural dwellings are built from unbaked earth and one finds, for instance, that in the Dauphine region, up to 90% of the buildings in certain villages are made out of rammed 'pise' earth. Finally, in California, there were estimated to be almost 200 000 'adobe' (sun-dried earth brick) dwellings by 1980 and the use of this material was growing at the rate of 30% a year.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Closer examination reveals that the whole world bears the indelible stamp of earthen architecture. Earth is used in Africa-in humble shelters built on leased land and in the great granaries of the continent. It is found in the palaces of the Hausa emirs of Nigeria, the ksours and kasbahs of Morocco and the mosques of Mali. In the Middle East, you come auoss it in the tightly-packed neighbourhoods of Ispahan and Iran, the fortified dwellings of Najran in Saudi Arabia, the multi-storey earth blocks of Shibam and the valley of the Hadramaut in Yemen. In Europe, there are the mouded brick farms of Aquitaine and the baroque and neo-classical castles of the Saone valley. And bringing in other parts of the world, we might mention the pueblos of the New Mexico Indians, and the houses built by the Hakkas in the Chinese province of Fujian, laid out in their characteristic concentric circles. The use of unbaked earth in building may be seen as a vestige of past history, but it is actually a living framework for history in the making.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Realistic uses for the future</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Confronted with the energy crisis of the 1970s, oil-dependent industrialised countries were forced to look again at tried and tested technical solutions which were now proving to be too 'energy-greedy'. The building sector did not escape this reappraisal and the search began for ways of reducing energy consumption both at source (covering the production and use of building materials) and further down the production chain (maintenance). Research on biomass and solar energy ran in parallel with experiments to update traditional materials and to attempt to rationalise the production process. Earth again became a focus of interest, with government institutions supporting a considerable amount of new research and experimentation. This covered applications in both the industrialised world and in developing countries, research for the latter being undertaken in the context of bilateral or multilateral cooperation. With the threat to the ecological balance posed by pollution, degradation and the plundering of natural areas, this interest in developing materials and techniques that are inherently friendly to the environment has not lessened. In many places, people are becoming increasingly involved in controlling and managing their living environment. The field has been opened up by qualitative research, a new awareness of the available options and an increase in leisure time. With techniques now at hand that are easy to use and economical, a greater measure of (partial or complete) selfhelp building is now possible. The USA, Australia and Germany all encourage new forms of intervention in building which give greater responsibility to the occupier in the creation of his living environment. Viewed from this perspective, earth as a building material has definite advantages and plays an important role.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">In developing countries, burdened by debt and confronted by an urgent need to build on a scale unprecedented in history, imported materials, techniques and energy are largely inaccessible to the majority of people, and their use may contribute to promoting 'bad' development. Building with earth emerges as an efficient shortterm way of producing houses or public buildings such as schools, which are both economical and of high quality (being culturally and climatically suitable). Decision-makers in these countries are well aware of this and have mobilised 'upstream' feasibility studies in their education and public housing programmes. The research covers local resources and knowledge, and the use of labour intensive techniques that generate employment and enable the population gradually to become 'monetarised'. The days of costly experimentation, often with no practical result, are now over. A new confidence in the resources that are available must be encouraged. There needs to be an increase in building completions and those who built them need more training. Today, this is happening in Mexico (850 earthen houses recently built in the state of Zacatecas) and in Burkina Faso (6000 school classrooms constructed by 1995.) No fewer than forty million homes will have to be built between now and the year 2000 for the urban population of Africa alone.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Studies show that for most of the people involved, there is no choice but to employ local materials, most often earth. One can thus predict that at least 20% of urban and pert-urban housing in African countries (about eight million units), will be built in earth over the next ten years, at a rate of eight hundred thousand units per year. If demand from rural areas is added to this, one gets some idea of the scale of the task facing decision-makers and builders. The use of earth and other locally available materials is unavoidable, and should be encouraged.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Environmental advantages</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">It is particularly important to enumerate the many advantages of building in unbaked earth from the point of view of the environment. This issue, one of the contemporary problems facing society, is increasingly moving centre-stage, and in the future, it is sure to play a greater part in political, economic, social and cultural strategies linked to the planning and improvement of the quality of life. Here we refer to the concept of the environment in the widest sense of the word, ecological, economic, technical, health-wise and psychological, cultural and human.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">From the point of view of the ecological environment</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">In terms of pollution and degradation, unbaked earth offers a highly positive picture:</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">- It does not contribute to the deforestation which results, for example, from the use of organic resources for firing baked earth materials.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">- It does not consume any nonrenewable energy (oil, gas, etc.) at source for the processing and production of materials, or further down the production line in their application. This is in sharp contrast to the production of cement, lime and other conventional binding materials, and steel.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">- By exploiting strata on construction sites, it allows a considerable saving in energy for the transport of materials.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">- It does not contribute to a degradation of the landscape as does the extraction of minerals and ores which hollows out hillsides and creates open cast sites. A great deal of the earth excavated in the course of large public works (notably roads and motorways) can be recycled and used in building (allowing very easy decentralised distribution).</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">- It does not contribute to the diminution of resources of aggregates such as gravel and sand, excavated either from quarries or from water courses, in insular sites or lagoons. The latter can endanger the ecological balance of these natural environments.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">- It uses very little water which is essential for the life of the people.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">- It produces no industrial or chemical waste and has the additional advantage of being almost entirely recyclable.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">From the point of view of the economic environment</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">- It is often comparable in cost with, or indeed more economic than competing technologies and requires no major financial mobilisation for its generally light production infrastructure. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">- It guarantees rapid amortisement thresholds for bankable investments thanks to its low infrastructure requirements for usable production.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">- It contribution to local flexibility, being readily susceptible to a decentralised approach.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">- Throughout the production process, it creates employment and monetary added-value which can be injected for development purposes into other sectors of the economy.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">- By allowing savings in energy and foreign currency, it contributes at the macro and micro economic levels of the building sector, to a considerable reduction in developing countries' debt and to the balance of payments.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">From the point of view of the technical environment</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">- It has thermophysical and hydric properties (good conductivity, energy retention capacity, thermal differential, delayed temperature differences etc.) which help ensure comfortable temperatures:</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">- It normally only requires simple production and application tools (moulds, presses, light shuttering, normal masonry tools, etc.) which are widely accessible to masons and self-help builders.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">From the point of view of health and the psychological environment</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">- Not only non-polluting in its use, it also guarantees the absence of harmful effects in the context of daily life (no gaseous emissions or other toxic chemical components, radioactive emissions etc.)</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">- It contributes to psychological wellbeing by the architectural exploitation of its inherent characteristics; these include the surface texture, colour, form and luminosity of the material. It thus makes an active contribution to the beauty of the living environment.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">From the point of view of the cultural and human environment</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">-It maintains the traditional architecture heritage of the area in question through the use of local materials and thus plays a part in the respect for, as well as the survival and updating of, cultural, architectural and urban environments.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">- It allows local populations to take charge of the production of their built environment and thus contributes to the expression of the democratic rights of all to control their living environment.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The future of earth on the move</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">In her work entitled 'A Fate Worse than Debt' (Penguin Books, 1988), the famous political commentator, Susan George, analysed the debt situation of developing countries and attempted to determine the basis for a positive resolution of the problem. Her approach focused in particular on solutions involving repayment in creative values or 'in kind' rather than in strictly monetary means. At the end of her analysis, she put forward eleven potential solutions to allow this repayment in kind and to launch a coherent approach for the development of less advanced societies. One of these recommendations was that it would be necessary to develop 'the study and survey (and if necessary the improvement) of local building techniques, in particular earth architecture ('pise' or 'banco').' Ms George argued that new buildings, particularly public ones, should be constructed using these techniques.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">It is clear that various solutions are being considered for the future: one in which building with earth, using a wide range of local techniques, will have a new technological, social, cultural, ecological, economic and political role of paramount importance.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Various methods of utilisation</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The technical, constructional and architectural possibilities of earth are very extensive. The study of popular traditions and of traditional knowledge throughout the world has enabled some 18 different methods of utilisation of the material to be identified, each in itself capable of being applied in a wide variety of ways. This wide construction potential has enabled the building of modest shelters, village houses, urban blocks, religious edifices and palaces. This is not to say that other traditional materials do not have an important role, but the sheer diversity and flexibility of earthen architecture probably cannot be equalled.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">As was indicated earlier, the use of earth as a building material has given rise to numerous applications using a wide variety of production and construction techniques. Some of these techniques are still used in traditional construction many countries, some have been abandoned, while others have only recently been the subject of developmental experimentation. It is worth noting that there is a register of the principal techniques, mainly associated with processes using moulds, shuttering and direct shaping. The six most widely used techniques are: 'adobe', 'rammed earth', 'straw clay', 'wattle and daub', 'cob' and 'compressed blocks'.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Of these six, three (wattle and daub, straw clay, and cob), are highly traditional, while the others (adobe, rammed earth and compressed earth blocks) have recently been the subject of spectacular evolution linked to the modernisation of production machinery and methods of application. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&lt;&lt;I&gt;&gt; p094.png The use of earth</P>
+<P ALIGN="JUSTIFY"></P>
+<B><P>&lt;&lt;TOC3&gt;&gt; The couriers mailbag</P>
+</B><P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Plea for African solidarity</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Thank you sincerely for your report on the second plenary of the Global Coalition for Africa which appeared in the March-April 1996 edition. As a 'displaced' Liberian, I would like to comment on some of the issues reported in the article.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">First, I hope that Africans recognise and appreciate all that former President Jimmy Carter has done and continues to do for our beloved continent.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Second, I support the view of Ms Johnson-Sirleaf and President Afwerki of Eritrea that we, as Africans, must invest in ourselves and in productive endeavours in our own countries. However, given the number of civil wars, that have resulted in displacement of our peoples and migration of the labour force, it is imperative that we also begin to think of and recognise each other as Africans first - and only then as members of whatever ethnic group we belong to. As a Liberian with professional qualifications who relocated to Ghana in 1992, I met with opposition and resentment because of my nationality and sex. I subsequently went to the Caribbean where my acceptance as an African was easier.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">When there is a population movement, the psychological impact associated with feelings of rejection and intimidation is severe. Sub-Saharan Africa will never develop or reach its fullest potential until we begin to think and act as a united, yet diverse group of people.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">I agree that it is important to develop our homelands first, but in the case of Liberia, Burundi or Rwanda, where no one seems to understand the concept of peace or the idea of having a future, it is crucial that the displaced be respected and accepted as fellow Africans. It would be even better if we were afforded the opportunity to integrate and assimilate into society.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Ciata A. Bishop, Grand Cayman.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">What about Guinea-Bissau ?</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">I am a student from Guinea-Bissau reading international law and political science at the Social Science University in Toulouse. I have also been a faithful Courier reader for more than seven years. In the March-April issue of 1996, you published an article on fisheries by Anthony Acheampong entitled 'A vital food source in West Africa'. You gave the figures for fish production in 16 West African countries-but did not mention my native country! I should point out that Guinea-Bissau consumes and exports a great deal of fish, and the product is an important source of foreign exchange to the country.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">F.J. Alves d'Almada, Toulouse, France.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Media and democracy in Southern Africa</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">I refer to the article with the above title by Francis Caas which appeared in issue no. 154 of The Courier (November-December). I enjoyed reading the text which examined the emergence of a free press due to the advent of political liberalisation in the Southern African region. However, I wish to make a correction as to what I think is a misrepresentation of fact. The author said, and I quote: 'The installation of a democratic regime in 1994 (in Malawi) enabled the MBC to begin broadcasting in all languages spoken in the country'. This is not actually correct although the Malawi Broadcasting Corporation, apart from broadcasting in English and Chechewa, has since introduced Tumbuka on the radio. I felt it was important to put the record straight on this.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Disher G.DJ. Pindani Lecturer in Public Administration, Chancellor College, Zomba, Malawi.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Corrigenda </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">In issue no 157, a number of 'author' footnotes were inadvertently omitted.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Pascal Dotchevi, author of 'Togo: the victory of the taxi. bikes' (p.11) is a journalist on Kpakpa Desenchante, a satirical weekly published in Lom&eacute; </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Piritta Sorsa, author of 'Banking and securities' (p.13) works at the IMF office in Geneva.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Yves Delafon, author of 'Developing consultancy work in the ACP countries' (p.15) is the director of a consultancy and President of the Federation of External Trade Associations in Provence/ Cote d'Azur.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">N'Gone Fall, author of 'Fashion; Out of Africa.. the breath of inspiration' (p.53) is a journalist.</P>
+<P ALIGN="JUSTIFY">Also in issue 157, some errors appeared in the article entitled 'Sparks fly in Namibia'. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">In the introductory section it was stated that secret harlots were held on resolutions relating to Nigeria, Niger and Sudan. This should have read Nigeria, Niger and Equatorial Guinea; a resolution on Sudan was passed by normal, open vote procedure.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Under the heading 'The future of Lom&eacute;' the ACP Generai Rapporteur vvas refered to as Mr Firmin, which is the forename. The General Rapporteur's surname is Mr Jean-Louis.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">In the fifth paragraph under the same heading, there was a reference to Helena Torres Couto. This should have read Mr Jose Manuel Torres Couto. </P>
+<P ALIGN="JUSTIFY"></P>
+<B><P>&lt;&lt;TOC3&gt;&gt; Bibliography</P>
+</B><P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">L'Afrique est-elle protectionniste- Les chemins buissonniers de la liberation exterieure</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">(Is Africa protectionist ? Greater economic freedom via the maze)</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">by Beatrice Hibou. Karthala Publications (22-24, boulevard Arago, F-75013 Paris). 1996. 334 pp. ISBN 286537-633-8.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">This volume offers a clearsighted analysis of the foreign trade policies of African states, fraud, smuggling and the way in which the franc zone operates, giving a definitive, reformulated account of structural adjustment.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">In her approach, the author is critical of both the liberal political economy and the new trends (the 'new political economy' end the neoinstitutionalist trends) which perpetuate the division between the economy and society. She refers to K Polanyi for whom Man's social relationships include economics and in whose opinion the economic system is managed as a function of non-economic motives.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">From this starting point, Beatrice Hibou demonstrates the part played by the unexpected and the unintentional in economic policies as they currently exist, revealing that coherence in foreign-trade policies on the part of African countries is not an economic priority but a socio-political one. In this connection, she shows that structural adjustment programmes have been unsuccessful in making any real impact on protectionist practices, at least in terms of their political and historical bases.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">After an overview of (legal or illegal) foreign-trade practices in contemporary Africa, protectionism is clearly alive and well, although much less widely applied and effective than about a decade ago. The reduction in the State's legal powers has meant increased freedom for 'informal networks', various types of dispensation, and an increase in fraud and smuggling.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">On the basis of Jean-Francois Bayart's opinion, dating from 1989, the author suggests that the explanation is to be found in the specific nature of Africa's economic history, which is one of independent means, a lack of production and management of dependency without the way in which it operates being affected. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Dominique David</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The Reality of Aid</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Independent review of international aid. Pub.: J. Randel and T. German. Earthscan Publications Ltd. (120, Pentonville Road, UK London N1 9JN). 1996. 244 pp. ISBN 1 85383 292 8.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The Reality of Aid (now an annual publication) compiled by two NGOs; Eurostep and ICVA, aims to highlight the extent to which donor aid helps developing nations, looking beyond the official publications of governments, banks and inter-governmental bodies. It contains a useful critique of the European Union's various aid policies and the respective bilateral policies of each of its 15 member states, as well as those of other Western nations like Australia, New Zealand, Switzerland and the United States. This year's review highlights, in particular, the need to mount more projects to alleviate poverty, despite aid commitments becoming more scarce.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">It says, for example, 'Too much aid is being squandered by governments on projects which have more to do with commercial and political advantage than poverty eradication. Rigorous evaluation needs to identify those programmes which can make an impact -and aid must increasingly be directed only to these areas.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">International aid to developing nations has fallen off over the years. In 1994, members of the OECD's Development Assistance Committee-21 of the world's richest countries-allowed their aid to fall to just 0.3 % of GNP, the lowest level for more than 20 years. The review stresses the need for donors to address in particular; policy coherence (environment, agriculture and consumption policies are all linked to poverty), the effectiveness of aid, the failure thus far to invest in people and the fact that the amount of assistance going to health and education is stagnating.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The review also features analytical case studies of various donor activities in selected developing nations (India, Fiji, Cambodia, Peru, Zimbabwe) and looks at Western assistance to post communist countries in transition.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">A chapter on the European Union's current development policies, edited by Mirjam van Reisen, a Brussels-based Eurostep researcher, criticises the lack of coherence of EU aid with its Member States bilateral programmes-an issue which is likely to come more to the fore as other European nations join the Union in the next millennium. Ms van Reisen also claims that there are too few staff running the EU's development policies and suggests, in particular, that there is a lack of expertise in the social and poverty areas. She stresses the importance for the EU's political leaders of giving more political clout to the EU's development policies at the Intergovernmental Conference (IGC), which is currently engaged in revising the EU's treaties. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Debra Percival</P>
+<P ALIGN="JUSTIFY"></P>
+<B><P>&lt;&lt;TOC3&gt;&gt; News round-up</P>
+</B><P ALIGN="JUSTIFY"></P>
+<I><P>&lt;&lt;TOC4&gt;&gt; In brief</P>
+</I><P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Trafficking of women</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">European Commissioner for immigration policy and legal affairs, Anita Gradin, will set to work with fellow Commissioners over the coming months to draw up a European Union action programme to clamp down on the trafficking of women which she describes as, 'the modern slave trade'. This comes hot on the heels of the Vienna European conference on trafficking of women, held on June 10 and 11, which was co-hosted by the European Commission, the Austrian government and the International Organisation for Migration.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Ms Gradin told journalists on June 12: 'I will put forward to the Council and the European Parliament a communication on the trafficking in women for sexual exploitation. This will cover migration policy, police and judicial cooperation, and social aspects to support and protect the victims. It will also consider European relations with the source countries, where the women are recruited.'</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The Vienna conference highlighted the need for cooperation between Member States and third countrie from which women are lured into prostitution in Western Europe. Recommendations, which are expected to be part of the EU policy, include setting up central national units in each Member State to exchange information.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The Commissioner told the participants in Vienna: 'The slave trade in women is growing, a slave-trade that aims at sexual exploitation. No part of the world seems to be free from this degrading treatment of women. Women are bought and sold like cattle or commodities. They are deprived of their rights and their dignity. And the direction of the trade is the same all over-it is women from poor conditions that are forced into a deplorable life by men in richer countries.'</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">She cited a typical case of one woman from the Dominican Republic from the book 'Stolen Lives' by Sietske Altinks: 'One day I went to visit a friend who was going to discuss job opportunities in Europe. I went with her and met a schoolteacher who knew somebody called Juan who could get me a job in the Netherlands. When I went to see him, his associates told me that I would easily find employment in a beauty parlour.' She ended up in prostitution.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Ms Gradin continued: 'The consequences for the women are dreadful. Often, they find themselves deprived of their freedom to move and decide for themselves; they are often locked up and subjected to violence and sexual exploitation. And should they be able to free themselves, they are regarded as illegal residents and expelled.'</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Debra Percival</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY"> Aid for development in the field of communication</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">A seminar was held under the auspices of the United Nations in the Belgian Parliament on 6 and 7 June, on 'the future of international development cooperation: new challenges for communication'.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The European Union was represented at the event, among others, by Colette Flesch and Steffen Smidt, the directors general respectively of DG X and DG VlII of the Commission. Mrs Flesch gave a presentation at the opening session in which she highlighted the various communication approaches adopted by the European Community in its efforts to counter what appears to be a growing lack of interest in development aid on the continent.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Mr Smidt, who spoke in the second session of the seminar, began his presentation with an anecdote, citing a text displayed at the entrance to a Federal building in Washington. This states: 'Taxes are what we pay to have a civilised society'. Paraphrasing this sentiment, the Director-General argued that, 'development assistance is what we pay to have a civilised European Union.' The question, he went on to pose, was whether we were paying enough ?</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">A number of the participants painted a discouraging picture of the situation facing the world's poorest countries in a world of advanced communications and increasing globalisation. Almost all were pessimistic about the impact of the socalled 'information super highways' on the least-developed nations.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">One of the most striking interventions came from Mabbub Ul Haq, the former Finance Minister of Pakistan, who spoke just after Mr Smidt in the plenary meeting, as well as at one of the discussion workshops. Mr Ul Haq urged the creation of a UN Economic Security Council, arguing that the main risk of global conflagration lies in the disparity that exists between rich and poor, now that the dangers associated with the Cold War have receded. One of the most acute issues under discussion was the growing challenge to the received wisdom that technical assistance is essential for consolidating national capacities. The evidence of 40 years of technical assistance would suggest otherwise (with 95% of funds set aside for this purpose going to foreign experts). Indeed, it was argued that those countries receiving most technical assistance per capita, had 'benefited' least from the system.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">In his second contribution, Mr Ul Haq painted a somewhat more encouraging picture, pointing out that the shaky 0.3% share of GNP allocated to development aid by the industrialised countries had achieved miracles in terms of increased life expectancy (up by 17 years) and the doubling of school enrolments in the countries of the South.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Hegel Goutier</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Round one of the South Africa-EU talks</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">South Africa gave no immediate response to the European Union's proposals for a bilateral trade agreement at the first round of high level negotiations in Brussels on June 20. The talks were headed by Dr L. T Links who is South Africa's new Ambassador in Brussels and for the KU, by the Director General for Development, Steffen Smidt. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The most difficult subject to negotiate will be future terms of access for South Africa's farm produce. The European mandate, which was agreed by EU Member States on March 25, foresees the exclusion of 39% of South Africa's farm produce currently sold to the EU from the planned free trade area. Applying World Trade Organisation (WTO) rules, the EU wants a scaled dismantling of barriers to trade in both farm and manufactured goods over a 10-year period, with a maximum of 12 years for a few highly sensitive items. But the EU has agreed to 'asymmetry' whereby, in some areas, it will open up its market to South Africa at a faster pace than vice versa. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Abdul Minty, deputy Director General at the Foreign Affairs Department in Pretoria, who is one of ,the chief negotiators, explained that South Africa had not yet responded to the terms because it is still consulting internally with the National Economic Development and Labour Council and with its partners of the Southern African Customs Union (Botswana, Swaziland, Namibia and Lesotho). </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">During a recent visit to Brussels, South Africa's former agriculture minister, Dr Kraai van Niekerk and his deputy, Mrs Thoko Didiza, told reporters that as it stood, the EU's mandate was 'anti-developmental'. Dr van Niekerk said he would like to see citrus fruit, in particular, removed from the list of exclusions. He also sought to dispel the fears of some EU Member States who wish to omit a larger proportion of South Africa's farm produce from the FTA, for fear of competition with equivalent EU produce.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Dr van Niekerk stressed the 'complementary' nature of South Africa's farm production. He pointed out that his country's growing season was at the opposite time of year to that of the EU and noted that South Africa's output of farm produce could only increase by about 2%.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">EU spokesman, Joao Vale de Almeida, said that progress had been made during the Brussels talks on aspects of South Africa's 'tome protocol'. This is aimed at giving South Africa certain benefits from the Lom&eacute; Convention- some eligibility for South African companies to tender for Lom&eacute; contracts and the partial extension of the Lom&eacute; rules of origin to South African exports. It was originally planned that the Lom&eacute; protocol should be implemented at the same time as a bilateral trade accord, (on January 1 1997). Mr Vale de Almeida spelt out that although it would not be technically and legally impossible for the Lom&eacute; protocol to come on stream without the bilateral pact, it would be more practical if the two could be implemented at the same time. A second round of talks is expected to take place in the autumn.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">D.P</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Echo Media Awards</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">On 29 June, the European Community Humanitarian Office (ECHO) launched a Television and Radio awards scheme to reward high-quality coverage of humanitarian affairs. Prizes will go to programmes produced or co-produced by independent production companies and/or broadcasting stations in the 15 EU countries which have been transmitted in a Member State on terrestrial or satellite television or radio between January 1 1995 and September 1 1996.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Judging by a panel made up of NGOs, environmentalists, politicians and the media will be in six categories:</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">People on the move-a television documentary on the humanitarian consequences of sudden or forced population movements; </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">In the minds of the people-a TV documentary on the psychological trauma in crisis situations; </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Forgotten conflicts-TV coverage of a long-running crisis forgotten by the mainstream; </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Vulnerable groups-TV coverage of the hazards encountered by women, children and the elderly in rebuilding their lives; </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Broadcast commitment-to a radio or TV station for consistent, high-quality coverage of humanitarian issues; </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Radio award-for the most incisive and analytical coverage of an emergency or humanitarian crisis. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Announcing the scheme, EC Commissioner, Emma Bonino, said: 'These awards give us an opportunity to acknowledge the vital role that broadcasters play in raising awareness of the issues at stake in imaginative, accurate and moving ways. They also serve to remind us of some of the basic European values such as solidarity and humanitarianism that have sometimes been eclipsed by barrages of headlines about mad cows and fish wars.' </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Entries for this inaugural year must be submitted by September 19, 1996. Details can be obtained from: Mandy Duncan-Smith, Media Natura (UK), tel: (44 171) 240 4936 fax: (44171) 240 2291 E-mail: medianatura@gn.apc.org</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Posters featuring contemporary Bantu art</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">In the framework of its cooperation programme with the Commission, CICIBA (Centre international des civilisations bantu-B.P. 770-Libreville- Gabon) has recently launched a series of large format reproductions featuring contemporary Bantu art. Thirteen works have been chosen, displaying a representative selection of art forms-painting, sculpture, engraving and moulded leather. The posters, more than 5000 of which have been printed in quadrichromic colour, have a 40 x 60 format. They are also available as postcards.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The artists featured are Marcela Costa (Angola), Assouambo (Cameroon), Daikou (Central African Republic), Mouanga Nkodia (Congo), Abdou Moeou (Comoros), Pambou Boulaz (Gabon), Jose Menan (Equatorial Guinea), Protais Hakizimfura (Rwanda), Protasio Pina (Sao Tome &amp; Principe), Silu Kinanga and Munyenz Tshibangu (Zaire) and Mulenga Chafilwa (Zambia).</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">CICIBA has also put together a similar series on ancient Bantu art. The fourth bi-annual exhibition of contemporary Bantu art, which has received some support from the European Commission, was due to be staged in Luanda (Angola) during July and August.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Links between technology and society</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">For more than 50 years, technological innovation has been regarded by many writers in the field as the motor of economic development.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Today, with rapid developments in the media sector and the emergence of 'information super-highways', the whole world is talking about the emergence of a new society dominated by 'smart' technology linked with research and creativity. This trend gives rise to many questions. Will the information be made available to all, and if so, when ? Will it lead to a change in North-South relations? Can we imagine what a world of 'tale-working', 'tale-education' and video on demand will be like ? What will the cost of all this be? Will biotechnology rescue the world or be the cause of its downfall ? What will the consequences be for the environment ? And in a globalised world, what standards and norms will be used ?</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">In short, what is the real nature of the relationship between technology and society; between science and humankind ?</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Fifteen universities of the EEA (European Economic Area) from Oslo to the Basque country and from London to Athens (taking in Roskilde, Maastricht, Louvainla-Neuve, Namur, Strasbourg, Lausanne, Sienna, Bari, Madrid, Valencia and Lisbon), have come together to offer a multidisciplinary course focusing on these key questions. During the first term, classes in theory and seminars are offered (in the local language of the institution) by experts from the academic world and the public and private sectors. Visits are also planned to multinational companies and laboratories. For the second half of the course, the students gain a wider European dimension by 'changing' university (with grants from the Socrates programme). The bulk of their time at this stage will be spent preparing a research dissertation in English on a topic which fits in with the specialisation of the host institution.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">For further information on the ESST</P>
+<P ALIGN="JUSTIFY">programme, contact:</P>
+<P ALIGN="JUSTIFY">Prof. E Lints (UCL-Belgium)</P>
+<P ALIGN="JUSTIFY">Tel. (32) 01047.82.60</P>
+<P ALIGN="JUSTIFY">Prof. T. Nguyen (FUNDP-Belgium)</P>
+<P ALIGN="JUSTIFY">Tel. (32) 081-72.49.09</P>
+<P ALIGN="JUSTIFY"></P>
+<I><P>&lt;&lt;TOC4&gt;&gt; The institutions at work</P>
+</I><P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Common foreign and security policy</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Within the framework of its Common Foreign and Security Policy (CFSP), the European Union has recently issued a number of statements, details of which are set out below:</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Antipersonnel mines</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Declaration of 13 May 1996</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">At the closure of the Review Conference of the States Parties to the Convention on Certain Conventional Weapons, the European Union recalls that it has, in recent years, redoubled its efforts to combat the severe consequences caused to civilians by the indiscriminate use of land mines, in particular anti-personnel mines.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The KU, which adopted joint action in May 1995 in order to reconfirm its commitment to the objective of an overall strengthening of Protocol 11 of the CCW, considers that the achievements of the Review Conference (such as the extension of the scope of Protocol II; the strengthening of restrictions on the use of mines; the new and immediate prohibitions regarding transfers; the provisions on technological cooperation and assistance; the regular review mechanism, etc), taken together, are significant steps forward, both in terms of the land mines protocol itself and of the development of international humanitarian law.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The KU, however, underlines that the resuits of the Review Conference fall short of its expectations and of some of the goals set out in its joint action. In particular, the EU should have liked an effective and binding verification mechanism and no periods of deferral of compliance, or at least much shorter ones.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The EU is convinced that the conclusion of this Review Conference is only the beginning of a challenging process which requires constant and widespread efforts and persistence in order to fully achieve its basic humanitarian objectives. The EU will continue to seek solutions to the problems caused by antipersonnel land mines and will strive towards the goal of their eventual elimination as stated in UN Resolution 50/70 (O). In the meantime, the Member States of the EU will seek early ratification of the amended Protocol II, as well as of the new Protocol IV on blinding laser weapons, and will take urgent steps to ensure their compliance with all the provisions of these two protocols pending their entry into force.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The EU will also continue to make active efforts with a view to achieving universal adherence to the CCW, since its objectives can only be effectively attained through implementation of its provisions by the widest number of states and parties to conflicts.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Furthermore, the EU recalls its determination to pursue its contribution to the international mine clearance efforts. The EU has already contributed to the UN Voluntary Trust Fund, financing, in particular, projects in Angola and Mozambique as well as in Bosnia-Herzegovina and Croatia. In addition, the EU will consider the possibility of conducting specific demining actions and will continue to seek to that effect the contribution of the WEU to the elaboration and implementation of such actions.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The Central and Eastern European countries associated with the EU (Bulgaria, the Czech Republic, Estonia, Hungary, Latvia, Lithuania, Poland, Romania and Slovakia) and the associated countries Cyprus and Malta, as well as the EFTA country members of the EEA, Iceland, Liechtenstein, and Norway, align themselves with this statement.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The Great Lakes region and the situation in Burundi</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Declaration of 24 June 1996</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The EU's objectives and priorities with regard to the Great Lakes region are to secure peace, to consolidate the process of national reconciliation in the countries concerned, to facilitate a return to normal democratic life, in particular by restoring the rule of law, and to encourage economic and social recovery.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Aware as it is of the close links between the various political, economic and humanitarian problems in the region and of the serious risk of destabilisation which remains, the EU would emphasise the need for a comprehensive approach and a regional dimension in the search for lasting solutions to the crisis.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">It considers that the presence of over a million and a half refugees in the region constitutes a major factor of destabilisation and that their return to their countries of origin in safety and with dignity is essential if peace is to be restored.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">It appeals to the Heads of State who signed the Cairo and Tunis Declarations to comply with the undertakings they gave, so as in particular to stop trafficking in arms and the training of the various militia and armed groups which serve only to increase insecurity in the region. It would point to United Nations Resolution 1053 in this regard and also the measures in the plan of action adopted by the Bujumbura Conference (12 to 17 February 1995) for the prevention of subversive activities in countries of asylum. The EU also emphasises the importance of deploying United Nations observers in airports and at frontiers.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The EU is increasingly concerned at the deteriorating political and human rights situation in Burundi and at the increase in violence. The persistent clashes, spreading over different parts of the country, and the killings and atrocities committed against the civilian population could well involve Burundi in a spiral of permanent conflict.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The EU strongly condemns all recourse to violence, which will never bring about a solution to the country's problems, and appeals to all the factions in the country to begin negotiating a resolution of their differences and to agree on an immediate, general cessation of violence. It supports the initiatives taken by the United Nations and the Organisation of African Unity to restore peace, as well as former President Nyerere's current efforts in this area.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">It fervently hopes that the talks taking place will result in a national dialogue open to all factions within the country. It also expresses its support for the ongoing efforts made by various bodies and eminent figures such as former Presidents Carter and Toure, and Archbishop Tutu.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The EU would point out that it too has taken initiatives aimed at resolving the crisis and recently appointed a special envoy for the Great Lakes region, Mr Aldo Ajello, to assist the current efforts of the United Nations, the Organisation of African Unity and other bodies and individuals, and specifically to lend support to the organisation of a regional conference under the joint aegis of the UN and the OAU to examine and resolve the deep-rooted causes of the crisis.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The EU remains convinced that such a conference must be convened as soon as possible.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The EU reiterates that it is prepared to assist with specific measures to promote peace and reconciliation in Burundi, in particular the organisation of a national dialogue, support for action to promote human rights and the restoring of the rule of law. It is furthermore willing to continue funding the presence of OAU observers and United Nations human rights observers in the country. It is also prepared to help with the economic and social recovery of Burundi as soon as political and security conditions allow rehabilitation programmes to be set up in the country.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Niger: progressive restoration of aid</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Declaration of 28 June 1996</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The European Union takes note of the fact that the regime in Niger has announced the results of the country's constitutional referendum and has lifted the state of emergency and the ban on political parties.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The EU takes the view that Niger has thus met the conditions set out by the Council on 13 May 1996 for the progressive restoration of cooperation. In the first instance, this will take the form of: -support for the electoral process; -aid for structural adjustment which, at present, needs to be focused exclusively on the most pressing needs in the social sectors.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The Council will continue to follow closely the situation in Niger, in particular as regards the preparation and conduct of the presidential and legislative elections.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Arusha summit on Burundi</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Declaration of 5 July 1996</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Recalling its declaration of 25 June 1996, the European Union congratulates President Mkapa on the organisation of the Arusha regional summit, which has produced constructive proposals on the conflict in Burundi. It expresses appreciation for the untiring efforts of former President Nyerere and reiterates its support for his peace initiative.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The EU encourages the region's Heads of State and the Organisation of African Unity to commit themselves resolutely to supporting and giving substance to the Arusha recommendations and to contribute to the restoration of security in Burundi.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The EU expects the President and the Prime Minister of Burundi to fulfil the undertakings they gave at the Summit to overcome the crisis in Burundi and, with the help of the countries of the region, to put an end to the violence which is destroying the people of Burundi.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The EU calls on all the political forces of Burundi to seek a political solution and to give a favourable reception to regional initiatives to restore peace to their country. It calls the attention of all the parties to the conflict in Burundi to the fact that it condemns all forms of violence and that it will not recognise a government that has taken power by force of arms. Only peace, a peace consolidated at regional level, can guarantee the security of all and lay the foundations for economic and social development.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The EU is prepared to support the realisation of the Arusha objectives with a view to restoring peace and security in Burundi. It reiterates its readiness to help Burundi in its economic and social recovery when political and security conditions make it possible to begin its rehabilitation.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The EU reiterates the need to convene the Conference on Peace, Security and Stability in the Great Lakes Region under the joint aegis of the United Nations and the OAU.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Burundi: support for the OAU Resolution</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Declaration of 15 July 1996</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Recalling its previous Declarations and Common Position on Burundi and, in particular, the Declarations of 25 June 1996 and 5 July 1996, the European Union warmly welcomes the Resolution on Burundi adopted by the Organisation of African Unity's Assembly of Heads of State and Government in Yaounde on 8 -10 July 1996.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The Union particularly welcomes the reaffirmation by the OAU of its support for the Mwanza Peace Talks under the facilitation of former President Nyerere and its encouragement to him to continue with his efforts based on and incorporating the principles of sustainable democracy and security for all the people of Burundi and an all-inclusive negotiation process. The Union reiterates its appreciation of the untiring efforts of former President Nyerere and its support for his peace initiative in this context.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The declaration in the Resolution of the OAU's full support for the outcome of the Arusha Summit of 25 June 1996, especially the acceptance of the request by the Government of Burundi for security assistance in order to complement and reinforce the Mwanza peace talks, as well as creating conducive security conditions for all parties to freely participate in the Mwanza process is also welcomed by the Union.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The EU reaffirms its willingness to support the realisation of the Arusha objectives with a view to restoring peace and security in Burundi. It remains ready to help Burundi in its economic and social recovery when political and security conditions make it possible to begin its rehabilitation.</P>
+<P ALIGN="JUSTIFY"></P>
+<I><P>&lt;&lt;TOC4&gt;&gt; Visits</P>
+</I><P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The President of Haiti</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The President of the Republic of Haiti, Rene Preval, visited the Commission on 11 June. He met with President Jacques Santer, Commissioner Joao de Deus Pinheiro (responsible for relations with the ACP States) and Commissioner Emma Bonino (responsible for humanitarian aid).</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">President Preval thanked the European Union for all the support it had provided both for the restoration of democracy in Haiti and for the country's economic development. He spoke in particular of the discussions that are currently under way with the Bretton Woods institutions aimed at restoring Haiti's economy. The President indicated that an economic recovery programme would need balance of payments support to the tune of $119m during 1996, as well as assistance for a range of economic sectors amounting to a billion dollars over a three-year period.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">For his part, Professor Pinheiro expressed satisfaction at being able to welcome the President at a time when the democratic process in Haiti was functioning normally and institutional consolidation was taking place. In a statement to the press, he said it was an appropriate moment 'to evaluate our cooperation and to strengthen it in a way that will contribute to economic and social development' in Haiti. He added that it was essential for the Haitian people to recognise that democracy was worthwhile. Professor Pinheiro also welcomed the normalisation of relations between Haiti and its neighbour, the Dominican Republic.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The President of the Dominican Republic</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The newly-elected President of the Dominican Republic, Leonel Fernandez Reyna, had a working session at the Commission on 15 and 16 July.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">This trip to Brussels was the President's first overseas visit in his new capacity, following his election on 30 June. Indeed, he had not yet formally assumed office at the time of his visit. His inauguration was due to take place on 16 August and the President-elect extended an invitation to the Commission to attend the ceremony. Mr Fernandez Reyna's subsequent itinerary included visits to Spain, France and the United States.</P>
+<P ALIGN="JUSTIFY"></P>
+<I><P>&lt;&lt;TOC4&gt;&gt; Support for human rights</P>
+</I><P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The Commission has recently approved the financing of the following projects under the budget line 'Human Rights and Democracy in the Developing Countries):</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">ACP countries</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Guinea: ECU 120 000 for a project aimed at actively involving members of the National Assembly in the institution's functioning, and in the democratisation process taking place in the country.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Niger: ECU 72 000 for a human rights training programme in schools in both urban and rural areas.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Nigeria: ECU 118 000 for a human -rights training programme to be run in educational establishments and through itinerant projects in regions lacking education infrastructures. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Fiji: ECU 119 000 for a project to support a non-partisan, multi-ethnic civic forum, aimed at contributing to the achievement of a consensus among various social groups.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Non-ACP countries</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Nepal: ECU 59 112 to safeguard texts which are essential to the preservation of Tibetan culture. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Nepal: ECU 30196 for the archiving of slides and photographs depicting art objects in order to preserve the culture and traditional techniques of Tibet. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Philippines: ECU 61 750 for a mission to identify the areas in which strategies for human rights and democracy could lead to positive and lasting changes. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Sri Lanka: ECU 84 314 for a programme of information in the field of promoting equal opportunities and non-discrimination </P>
+<P ALIGN="JUSTIFY"></P>
+<I><P>&lt;&lt;TOC4&gt;&gt; Aid for rehabilitation</P>
+</I><P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The Commission has recently decided to finance the following projects in developing countries affected by serious civil disturbances or natural disasters:</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Angola: ECU 847 000 for an integrated programme covering the rehabilitation of agriculture and basic infrastructures, training in demining, hygiene and self sustaining development in Kipungo. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Angola: ECU 185 000 for the rehabilitation of basic infrastructures (water, health, education and housing) In the province of Luanda. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Eritrea: ECU 353 947 to support the rehabilitation and development of basic </P>
+<P ALIGN="JUSTIFY">health care services in the south-west of the country.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Eritrea: ECU 575 197 for the rehabilitation of water supplies and community development in the town of Hagaz. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Ethiopia: ECU 515.685 for the rehabilitation of primary care and water supplies in the Warder area. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Ethiopia: ECU 455 630 to help the rehabilitation of repatriated people and displaced persons in the Borena area. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Ethiopia: ECU 308 475 for the rehabilitation of health care and water supplies in the Hararghe area. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Mozambique: ECU 848 000 for a programme of support to upgrade medical infrastructures. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Mozambique: ECU 590 000 to consolidate the water sector and rehabilitate livestock infrastructures in Maputo and Gaza provinces. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Mozambique: ECU 500 000 for the second phase of a programme to help reestablish and reintegrate displaced people in Milange. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Rwanda: ECU 241 259 for a project designed to revitalise livestock producer groups, make available essential veterinary products and support cattle production in the landward prefecture of Kigali. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Rwanda: ECU 411 751 to provide professional training in primary health care. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Rwanda: ECU 805 475 for an environment rehabilitation project in the prefecture of Kibungo. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Rwanda: ECU 437 622 for the rehabilitation of primary schools in the southwest of the country. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Rwanda: ECU 94 650 to train laboratory technicians. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Somalia: ECU 626 439 for the rehabilitation of wells and water points in the Nugal region. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Zaire: ECU 423 687 for the creation of enterprises involved in making bricks and earth blocks in order to assist in the rehabilitation of rural habitats. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Zaire: ECU 1 491 117 for a tree-planting project around the Virungas National Park as part of a rehabilitation programme directed at Rwanda's immediate neighbours.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Haiti: ECU 213 536 for operational and methodological support for rural development projects. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Haiti: ECU 645 120 for technical assistance in the follow-up and evaluation of rehabilitation projects. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Haiti: ECU 551980 for a programme to rehabilitate schools and provide support for the education sector. </P>
+<P ALIGN="JUSTIFY"></P>
+<I><P>&lt;&lt;TOC4&gt;&gt; European development fund</P>
+</I><P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Following, where required, favourable opinions from the EDF Committee, the Commission has decided to provide grants and special loans from the 5th, 6th and 7th EDFs to finance the following operations (grants unless otherwise stated). Major projects and programmes are highlighted.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Economic and social infrastructure</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Malawi: ECU 1.9 million for the rehabilitation and construction of customs facilities. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Zambia: ECU 11 million for resurfacing and improvements to the runway at Lusaka international Airport. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Fiji ECU 1.8 million for the rebuilding of three bridges.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Trade promotion/ structural adjustment</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Member states of SADC (Southern Africa), ECOWAS (West Africa) and ECOCAS (Central Africa): ECU 500 000 for a follow-up pilot project relating to industrial fore in different sectors. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Botswana: ECU 1.9 million for a tourism development programme. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Djibouti: ECU 4.1 million to support the 1996-97 structural adjustment programme. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Netherlands Antilles/Aruba: ECU 5 million for a tourism promotion programme. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Agriculture/ rural development</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Madagascar: ECU 1.9 million to support professional organisations in the field of rural credit. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Swaziland: ECU 1.4 million to build a bridge at Maphobeni, to facilitate rural development in this area. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Swaziland: ECU 1.5 million to improve the storage and commercialisation of maize. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Health</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Benin: ECU 700 000 to enhance the security of blood supplies in the Oueme, Mono and Atlantique departments. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Education/training</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Botswana: ECU 15 million for a training programme directed at SMEs, independent operators and the unemployed. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Ethiopia: ECU 1.05 million for a programme designed to strengthen training and research capacity in the economic field. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Member states of IGAD (Djibouti, Eritrea, Ethiopia, Kenya, Somalia, Sudan, Uganda): ECU 1.9 million for a training programme for the commercialisation of cereals. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Environment</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Lesotho: ECU 1.3 million for a community reforestation programme in the Lesotho Highlands. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Institutional support</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Djibouti: ECU 250 000 to provide technical support for the computerisation of the National Bank's accounting system. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Niger: ECU 1.8 million to support the electoral process.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Kenya: ECU 1.7 million for an assistance programme for the National Authorising </P>
+<P ALIGN="JUSTIFY">Officer covering the management of funds allocated by the European Community.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Zambia: ECU 1.5 million for the first phase of a tourism development programme. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Cariforum countries-Antigua &amp; Barbuda, Barbados, Belize, Bahamas, Dominica, Dominican Republic, Grenada, Guyana, Haiti, Jamaica, St Kitts &amp; Nevis, St Lucia, St Vincent &amp; the Grenadines, Suriname, Trinidad &amp; Tobago): ECU 725 000 in technical assistance for the programming unit of the Cariforum General Secretariat. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Miscellaneous</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">All ACPs: ECU 5 million to strengthen fisheries management and biodiversity. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Ghana: ECU 1.5 million for a pilot project in the field of decentralised cooperation. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Kenya: ECU 12.5 million for a community development programme in the battle against poverty. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Somalia: ECU 47 million for the second rehabilitation programme. The focus will be on productive activities (livestock, agriculture and fisheries), the social sectors (health, water, sanitation systems and education), the private sector (revenue generation, job creation, SMEs), the public sector (training, establishment of institutions), demobilisation, and the integration of former combatants </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Zambia: ECU 1.6 million for a programme to combat poverty including, in particular, the provision of credit to micro-enterprises. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Zaire: ECU 2 million to support the integration of displaced people in Kasai. </P>
+<P ALIGN="JUSTIFY"></P>
+<I><P>&lt;&lt;TOC4&gt;&gt; European investment bank</P>
+</I><P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">South Africa: A loan of ECU 56 million for Eskom, the public electricity company, for the modemisation of part of its electricity distribution network.</P>
+<P ALIGN="JUSTIFY"></P>
+<I><P>&lt;&lt;TOC4&gt;&gt; Humanitarian aid</P>
+</I><P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">ACP countries</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Angola: ECU 14 million for a global assistance programme covering food and medical aid, the distribution of equipment and demining operations. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Chad: ECU 500 000 for the distribution of essential food products and to meet the special nutritional needs of children in the north of the country.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Cote d'lvoire: ECU 340 000 to help combat cholera and yellow fever among refugees from Liberia. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Ghana: ECU 140 000 towards the setting up of a camp for 'boat people' arriving from Liberia. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Guinea: ECU 160000 for the distribution of food to refugees from Liberia and Sierra Leone. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Senegal: ECU 250 000 towards the fight against cholera, notably in the town of Touba.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Sierra Leone: ECU 4.2 million for food and emergency medical aid (to combat cholera) for people displaced by the civil war. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Somalia: ECU 1.5 million for a measles vaccination programme and for medical and food aid for victims of the internal conflict. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Southern Sudan: ECU 13 million to finance ECHO flights, and for food, medical aid and the provision of water supplies, for civilian victims of the conflict, notably in Khartoum and its environs and in the refugee camps in the north of Uganda.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Non - ACP countries</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Nicaragua: ECU 1.5 million for medicines, essential provisions, drinking water supply equipment and training actions in the area of epidemic prevention. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Peru: ECU 800 000 for shelters and medical assistance to people in the process of reestablishing their homes having fled from the violence that has occurred over the past ten years.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Ex-Yugoslavia: ECU 102 million for various emergency operations. The breakdown of this aid, by country, is as follows: Bosnia-Herzegovina-ECU 77.45 million; Croatia-ECU 11.95 million; Serbia-Montenegro-ECU 12,6 million.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Russian Federation: ECU 900 000 for street children in St Petersburg and homeless people in Moscow. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Afghanistan: ECU 7 million for a coordinated aid programme covering public health measures, the provision of drinking water, hygiene and refuse collection. The aid will be directed both at the people of Kabul and at other provinces of the country. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Kirghizistan: ECU 3.6 million for the purchase and distribution of food. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Tadilkistan: ECU 8.9 million for a food and medical programme. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Bangladesh: ECU 300 000 to help victims of the tropical storm that struck in the middle of May. </P>
+<P ALIGN="JUSTIFY"></P>
+<I><P>&lt;&lt;TOC4&gt;&gt; Food aid</P>
+</I><P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Angola: 15 000 tonnes of cereals, 2000 tonnes of oils and 3000 tonnes of beans amounting to a total value of ECU 20.075 million. </P>
+<P ALIGN="JUSTIFY"></P></FONT></BODY>
+</HTML>
Index: /main/tags/2.25/gsdl/collect/demo/import/ecourier/ec160e/ec160e.htm
===================================================================
--- /main/tags/2.25/gsdl/collect/demo/import/ecourier/ec160e/ec160e.htm	(revision 21064)
+++ /main/tags/2.25/gsdl/collect/demo/import/ecourier/ec160e/ec160e.htm	(revision 21064)
@@ -0,0 +1,2358 @@
+<HTML>
+<HEAD>
+<META HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=windows-1252">
+<META NAME="Generator" CONTENT="Microsoft Word 97">
+<TITLE>&lt;&lt;TOC1&gt;&gt; The Courier - N°160 - Nov - Dec 1996 - Dossier Habitat - Country reports: Fiji , Tonga</TITLE>
+</HEAD>
+<BODY>
+
+<B><FONT FACE="Arial" SIZE=2><P>&lt;&lt;TOC1&gt;&gt; The Courier - N°160 - Nov - Dec 1996 - Dossier Habitat - Country reports: Fiji , Tonga</P>
+</B><P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">Africa - Caribbean - Pacific - European Union </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Country reports</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Fiji</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Fiji is home to people of a variety of cultures but it would not be accurate to describe this Pacific island country as a 'melting pot'. Politics here are dominated by the difficult relationship between indigenous Fijians and the descendants of indentured Indian labourers brought in to work the sugar cane fields. We look at how this situation affects the economy -  which everyone acknowledges has considerable potential, and examine the prospects for ethnic rapprochement as the nation begins a 'great debase' on the future shape of its Constitution. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">Tonga</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Tonga appears like a haven of tranquility in a turbulent world. A society which respects hierarchies and is strongly attached to 'traditional values', it is also one of the few remaining places with a hereditary ruler who wields substantial power. But outside influences cannot be ignored altogether and nations everywhere are having to adapt to living in the 'global village'. Our report focuses on the possible consequences of this for the 'Friendly Islands' as the new millenium approaches. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">Dossier</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Habitat</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The concept of 'habitat' conjures up different things to different people - from the right to a roof over one's head to the way in which we manage the flora and fauna of the planet. In our dossier, we consider the legacy of the United Nations 'Habitat' Conference held in Istanbul earlier this year. We also highlight some of the initiatives being taken to improve the quality of people's living environment. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<B><P ALIGN="CENTER">&lt;&lt;TOC2&gt;&gt; Acknowledgements</P>
+</B><P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">The Courier: Africa  - Caribbean - Pacific - European union</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Address: Postal address (mail only) 'The ACP-EU Courier' Commission of the European Communities 200, rue de la Loi 1049 Brussels Belgium </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The Courier office address (visitors) First floor Astrid Building 1, rue de Geneve Evere- Brussels Belgium</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Publisher Steffen Smidt commission of the European communities 200, rue de la Loi 1049 - Brussels (Belgium) Tel. 00-32-2-299 1111 </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Director of Publications</P>
+<P ALIGN="JUSTIFY">Dominique David</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Editor</P>
+<P ALIGN="JUSTIFY">Simon Homer</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Assistant editors</P>
+<P ALIGN="JUSTIFY">Augustin Oyowe</P>
+<P ALIGN="JUSTIFY">Jeanne Remacle</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Associate assistant editor</P>
+<P ALIGN="JUSTIFY">Hegel Goutier</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Journalist:</P>
+<P ALIGN="JUSTIFY">Debra Percival</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Production Manager:</P>
+<P ALIGN="JUSTIFY">Dorothy Morrissey</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Secretariat:</P>
+<P ALIGN="JUSTIFY">Carmela Peters</P>
+<P ALIGN="JUSTIFY">Fax: 299-30-02</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Circulation:</P>
+<P ALIGN="JUSTIFY">Margriet Mahy-van der Werf (299-30-1 2)</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<B><P ALIGN="CENTER">&lt;&lt;TOC2&gt;&gt; Meeting point</P>
+</B><P ALIGN="JUSTIFY"></P>
+<B><P>&lt;&lt;TOC3&gt;&gt; Jacques Bugnicourt, Executive Secretary of Enda Tiers Monde</P>
+</B><P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The main development battle must be fought in the towns and cities</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Founded in 1972, Enda Tiers Monde ('Enda' stands for 'environment and development') is one of the few large international NGOs to be based in a developing country. It has a presence in a number of states in Africa, Latin America and Asia and has been concentrating its efforts on towns and cities, in the belief that this is where deprived populations can be best assisted. Jacques Bugnicourt, who is Enda's Executive Secretary, has some strong views about what needs to be done to tackle the problem of urban deprivation. When we interviewed him at the Enda headquarters in Dakar, Senegal, we began by asking him about the history of the organisation that he heads.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY"> - When we launched Enda, I am not sure that we had any particular goal in mind. You would have to go back to the end of the 1950s, with the war in Indochina, the approaching conflict in Algeria, the independence of countries in Africa and the last-ditch struggles of the colonial powers, notably France. It was in Paris that links were forged between activists from many Third-World countries - in particular, we all took part in the street demonstrations mounted by people from the French colonies. There were some very strong groupings like the Federation of Students from Black Africa, and its equivalents set up by students from the Maghreb, Latin America and Asia. Ten years later, in the 1970s, we could see that the independence experiment was turning sour and the hopes we vested in the actions of determined and brilliant people had come to nothing. The United Nations was becoming increasingly bureaucratic. Some of our friends and colleagues who had government posts had their hands tied, while others were in prison and were equally powerless. In addition, the communists were disappointed at not being able to apply their doctrine to local conditions. Some did, in fact, manage to achieve small-scale results locally when working at the grass-roots, but by and large, their efforts were not successful. I came to Dakar, where I taught in a United Nations institute.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">A lot of people had theories. But you cannot take up the battle for the poor without the poor themselves, or for those under the yoke of colonial rule without the participation of the subjugated population. To begin with, you have to appreciate the diversity of the various peoples in developing countries, and be aware of their daily life and struggle. Cesaire wrote that you had to ask questions about the soil, about cities, about men and about the sun. Later, once you have done this, you can act.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">We need to dismantle the barriers. There can be no agronomy without economics, and no economics without sociology. If you are talking about jobs in Senegal, you also must talk about jobs in Mali and Guinea - treat Africa as a whole. Another thing is that you have to stand up for yourself and not allow yourself to be manipulated by people from the developed countries. One of the major problems we have noticed is that part of Africa's elite is out of touch with the general population.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">These are the underlying reasons for the foundation of Enda. Nowadays, it is a non-profit-making international organisation working with various communities - an 'INGO', if you like, with the 'I' standing for 'international'. We have bases almost everywhere in the Third World, from Ho Chi Minh City to La Paz.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">· Is each section of Enda independent, then ?</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY"> - Yes. We took the view that there was a danger of becoming too centralised and acting like a small-scale UNICEF or UNESCO, so we decided to guard our independence very carefully. We opted for the widest-ranging autonomy possible. This has its drawbacks of course, but these are far outweighed by the advantages.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">· You mention drawbacks. Would it be true to say that the original enthusiasm which greeted the creation of Enda has fallen off somewhat ?</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY"> - That's something we are always concerned about. It is not structures which maintain cohesion, but the sharing of goals and the channelling of our actions towards the common good.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">When the various sections get together, we find that we have a great many things in common. But there is no good reason why those of us in Dakar should try to influence the way people work in working-class districts in Santo Domingo, for example, where they are trying to tackle problems like AIDS and unemployment. We simply tell them what we are doing here and vice versa. If you want to serve the people, you have to have a decentralised set-up. It would be wrong to deal with a problem centrally, and to do so would be against our instincts. Most of us have no particular liking for institutions. An institution must be of service in the battle, not the other way round.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">· How do you guarantee cohesion in practice ?</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY"> - It costs a great deal to travel of course, but we do have a lot of joint programmes. For example, the cities programme includes people from Bogota, Santo Domingo, Rabat, Dakar, Ho Chi Minh City and Bombay, all working together. They meet from time to time and, when they do, it is to get down to practical work. Together, their work is, say, three-quarters practical and one quarter reflective. Nevertheless, there is ongoing tension, particularly in the relationship between overall policy and local demands. Another conflict arises between grass-roots action and reflection.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">· The impression one gets is that you yourself are the 'cement' between the various groups which make up Enda. Could this not be seen as a weakness which may make things difficult in the future ?</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY"> - That's what other people say, not what I think. I try to make my presence useful and those who come after me will do the same. What really holds us together is our belief in what we are doing. It is not a question of adhering to some kind of 'monolithic' faith. We simply believe that we can be of use, recognising that there are many limitations. Let me give you a practical example. If someone involved in recycling in Bogota were to meet up with someone from a poor district in Dakar who works at the rubbish tip, they would have a great deal in common and would find it useful to compare their problems and consider practical ways of solving them together.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">· What are your most important activities in Senegal ?</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY"> - By far the most important is the one covering the city of Dakar. As well as being a focus for the country itself, Dakar is a metropolitan centre for the entire sub-region, with influence over Bamako, Conakry, Bissau and perhaps even Praia in Cape Verde and Nouakchott in Mauritania. What happens here has repercussions in all those cities. I do not want to sound too dramatic, but the decisive factor in our destiny will be the fate of young people and the poor in the major cities. Two-thirds of these people are facing chronic problems. Those under twenty make up more than half the population and their lives are continuing to spiral down into poverty.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Enda should obviously be operating in those areas where it can be of most use. And in the context of towns and cities, we have completely reviewed our strategy. For some years we gave priority to the countryside. For a long time, in fact, we believed that rural development would permit a much improved urbanisation process. There was even the view that people in developed countries would not object to paying a little more for agricultural produce, because they could be certain that the money was going to those who actually grew the cotton, groundnuts, cocoa or whatever.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Over the last fifteen years or so, though, we have come round to the view that our actions must be directed principally at towns and cities. We found initially that there were some interesting projects involving small groups - working to improve the position of children or banding together in cooperative savings ventures. It was good, long-term work which gave results. But that is all out of date now. We have to speak in terms of much larger numbers  -  tens of thousands and not tens or hundreds. Otherwise, there is no chance of making a real difference. That is why we have considerably altered our strategy. Three years ago, approximately two thousand children were able to go to holiday camps. Most of these holidays were paid for by companies, but fewer than 10% of the beneficiaries were genuinely poor. Last year, no fewer than 10 000 children were sent away on five days' holiday -  to the coast near Dakar. Enda was involved in this programme working with 200 local cultural and sports associations. The idea was to give the children the chance to splash about in the sea, but also to use African resources to help them become full citizens and learn that our diversity is the source of our wealth. There are at least 100 000 children living in misery and many of them could end up joining the ranks of the street children. If you can give these youngsters five days holiday plus a bit of follow-up, you allow friendships to be built. It offers a brief escape from everyday reality. It may not be paradise, but it is something tangible.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Another example is the tontines that have been formed into a federation. We currently have nineteen thousand women participating in these and if you bear the large family sizes in mind - there are perhaps ten people in every family - that represents a lot of people. The women pay into the tontines and the money is used, not just for the security of their immediate family, but also to help young people set themselves up.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Then there is rubbish collection. Enda runs its own scheme but there are also a number of groups that have turned rubbish collection into a profession. The young people collect the rubbish and recycle it. There are about 50 000 people in the biggest district where we are involved in rubbish collection. There are also some young people in that district who are engaged in water recycling and although it only involves supplying about a hundred people at the moment, I believe this scheme will grow. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">We also organise schools and are currently involved in making films for schools on the subjects of the environment, hygiene and solidarity.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">· Enda has just opened an 'eco-centre'. If I understand it correctly, this is a showcase to promote a horizontal link between Enda's various activities.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY"> - That is right. We want it to be a place of passage, meeting, exhibition, permeation and redistribution. We hope people will feel comfortable there, and that it will be a tool symbolising a new way of working. So the centre offers an experience, but we also want it to be used to promote activity. A variety of events have been organised there simultaneously - recently for example, a meeting of shoe-shiners, a gathering of teachers from a long-standing educational centre, an exhibition for the Biennial Festival of Contemporary African Art, and a local-community meeting about setting up a small production facility. Two days earlier, there was a preliminary holiday-camp meeting where the instructors got together to look at the best available teaching methods designed to make children more aware of the importance of solidarity. We believe that solidarity is essential in tackling problems.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">So the centre has a multitude of uses, all of which contribute to the vitality of the local economy. You have to understand the crucial importance of the local economy. It responds to all the basic needs of the poorest people, who want to live their lives just like the rest of us.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">· You talk of depending on the local (what some would call the informal) economy to live - or at least survive. But this sector is not viewed with enthusiasm by the international authorities ?</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY"> -  Their policy is based on domination and fear: fear of those who accumulate assets. To see these hordes of people in the developing countries frightens them. It's a bit like the horror of the wealthy classes at the end of the nineteenth century when faced with a working class which dared to aspire to wealth. They will give to charity but are not prepared to make a long-term investment. The lack of support for the local economy stems from the fact that foreign aid is geared, first and foremost, towards major projects or emergency aid. Four or five years ago, the UN conducted a survey in 10 towns and cities in West Africa, but the results were not published because they showed that the average rate of growth of the local economy was 7.5%. So, you see, we are far from just muddling along. Great things could be achieved if only there were a change in attitude. It also requires a change of terminology. How can one justify the use of the word 'informal' and, worse still, treat the work of the poorest people and fraudulent activities under the same heading. Fraud may be formal or informal. Knowing African society as I do, I am aware that fraud is statistically more widespread amongst the prosperous and highly respected. So we must not cast stones at the little man selling socks who has no trading licence because he cannot afford one, or at the woman who sets up a stall at a school entrance without complying with the law which requires a recent certificate stating that she does not have tuberculosis. What is the bottom line here ? Must we respect the law or the people who want to live without being thieves, beggars or prostitutes ? It is unacceptable for force to lie with the law and for the majority to be cast into wretchedness.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">In Senegal, there used to be fixed prices for milk. The World Bank protested, declaring that this was a restriction on free competition. Now we have to pay much more and many people can no longer afford to give their children-milk every day.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">To put it in perspective, Senegal's economy is about the same size as that of the city of Bordeaux. So we must use all the available potential. Highly qualified managers should do their job looking after the high-tech sectors. But, at the same time, we should not be driving out the poor people who are just trying to eke out a living. The informal sector creates services for a very small investment, and people also require services. Economic policy must allow society to walk on two legs, not just one. What that means is that we need a great deal of flexibility, and perhaps a complete review of the law. Contraceptive implants have to be licensed so that there are no more back-street abortions. And it must be possible for girls to attend school even if they do not have a proper birth certificate - why should they be excluded from education for want of a piece of paper. It should be possible to trade with a simple one-day ticket which people should be able to buy in post offices or cinemas. What would be wrong with that? And we should have a moratorium on a number of regulations. We need to wage war on the destitution that we are suffering and that means taking decisive measure.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<B><P ALIGN="CENTER">&lt;&lt;TOC2&gt;&gt; ACP</P>
+</B><P ALIGN="JUSTIFY"></P>
+<B><P>&lt;&lt;TOC3&gt;&gt; Joint Assembly begins discussions on future ACP-EU relations</P>
+</B><P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Although the agenda was, as usual, heavily laden with a variety of long-standing issues ranging from regional cooperation, fisheries, the cocoa content of chocolate and bananas to the situation in several ACP states (in particular Rwanda and Burundi), the future of ACP-EU relations was at the forefront of discussions at the ACP-EU Joint Assembly, which was held in Luxembourg from 23-26 September 1996.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Opened in the presence of the Grand Duke and Grand Duchess of Luxembourg, the Assembly's general attitude was not one of speculation as to whether or not the European Union would abandon the ACP states when the Lom&eacute; IV Convention expires in the year 2000 - a feeling that was rife shortly after the signing of the revised version in Mauritius in November 1995. Instead, it was one of positive thinking and of exploring the kind of agreement that would succeed it. 'There is no question of the European Union getting out of a relationship which took decades to build', Luxembourg's Prime Minister Jean-Claude Junker, told participants in his welcoming address.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">As pessimism gives way to guarded optimism, ACP-EU parliamentarians have taken an important initiative, even before the Commission's Green Paper is published, in what is bound to be a long and passionate debate. A special summit of ACP Heads of State is planned for Gabon later in 1997 to discuss the issue.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Options for the future</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">A general report, introduced by Mr Firmin Jean-Louis (Haiti), provided the main platform for the Joint Assembly's deliberation. Although presented too late for representatives to have the opportunity to examine it in detail, the exchange of views on the floor was wide-ranging and reflected the report's content to a considerable degree.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The report encapsulates all the ideas that have emerged so far in various fore. It analyses framework options for future ACP-EU relations  -  bilateral, regional and multilateral - and raises pertinent questions and concerns. Noting that international cooperation is increasingly dictated by economic and security considerations, and that North-South solidarity is, as a result, being pushed to the background, it regrets the fact that certain EU member states appear to indicate a preference for bilateral over multilateral cooperation. The author of the report warns that this trend would not only diminish the credibility of the Union but also its international influence.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Any instrument of cooperation, the report says, should take into account the different levels of development among ACP states as well as the regional vocation of many others. Its objective must be poverty eradication, sustainable economic and social development, and the harmonious integration of the ACP states into the global economy.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">It recognises the need to secure the support of European public opinion which is largely unconvinced that EU aid to ACP states has been effective over the past 20 years. Not enough publicity; it says, has been given to its positive aspects. The report goes on to warn that solidarity and development are at stake and that the debate on the future of ACP-EU relations should not be left to politicians and technocrats. It should also involve wider civil society.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">In the Joint Assembly debate, the commitment of EU political leaders to the development of the ACP states was often called into question. Francis Wurtz (EUL-F) summed it up when he said there were worrying signs that the EU intends to downgrade its relationship with the ACP states - signs which go back to the negotiations on the Lom&eacute; IV second financial protocol, when several countries refused to increase their contributions to the 8th EDF. The EU draft budget for 1997, which he said revealed a substantial reduction in the funds allocated to the developing countries outside the Mediterranean region, provided further evidence of this. 'We must be vigilant,' he told his colleagues, 'and must not allow the Lom&eacute; Convention to be revised downwards.' Mr Wurtz agreed that greater efforts were needed to create awareness and mobilise European opinion in favour of development. The European public should know that EU development policy was not based on charity but on self-interest. 'Without Africa developing, Europe has little chance of maintaining growth in the long run.'</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Lord Plumb (EPP-UK), the European Co-President of the Joint Assembly, admitted that it would not be easy to influence European public opinion. 'One of the roles of the Joint Assemby,' he said, however, 'must be to ensure that the peoples of Europe have confidence in the progress being made by the countries of the South. We must all help in this task of confidence-building.' </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Glenys Kinnock (PES-UK) urged that there should be as much participation as possible in the ongoing dialogue over future ACP-EU relations in order to bridge what she saw as 'the gap between rhetoric and reality.' Equity, she argued, should be the main objective.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">ACP Co-President, Sir John Kaputin (Papua New Guinea), said there was no doubt that the EU was forging closer ties with the former Eastern bloc countries at the expense of the ACPs. He pointed out, however, that the Lom&eacute; Convention had always encouraged a 'forward-looking' approach and argued that whatever succeeded the current ACP-EU relationship should be 'the most important' agreement ever.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The representative from Barbados, Dr Richard Cheltenham, was of the opinion that whatever the outcome of the discussions, efforts were needed to avoid 'chaos'. There should, for example, be no immediate abandonment of the trade preferences that ACP states had acquired. Transformation must be gradual to enable them to adjust and restructure.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">European Commissioner, Professor Pinheiro, chose, first of all, to underline the importance of the role of 'the state and civil society' in development. He indicated that he saw this as growing more and more in importance. This was reflected in the agreement signed in Mauritius -  an agreement which seeks to encourage the consolidation of democracy, the rule of law, good governance and transparency, and which emphasises decentralised cooperation and the role of the private sector. the Commissioner spoke about the current programming exercise, reminding the Assembly that resources were being allocated in two tranches in accordance with the provisions of the revised Convention, to take account of each ACP state's development strategy and the objectives and priorities of the Community's development policy. He revealed that only 16 ACP countries and two EU Member States had ratified the revised Convention and urged those that have not done so to accelerate the process.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">He welcomed the Joint Assembly's initiative in debating future ACP-EU relations. The Commission's Green Paper, he told representatives, will be published in November. He was, therefore, not in a position to enter into detailed discussions with members on the subject at this stage. He stressed, nonetheless, that the document 'will not be a blueprint for future EU strategy towards the ACP countries. It will be a discussion paper.' there were a number of key questions that needed to be addressed regarding strategy, the scope of future relations and the use of the traditional instruments of aid and trade. 'This is not to say that we should start afresh', he argued. 'We should build on what has been achieved so far, and adapt where necessary.' Professor Pinheiro was certain that whatever the outcome of the discussions, there were a number of 'unchallengeable principles' on which ACP-EU relations should continue to be based. These were: partnership, ownership by ACP countries of their development policies, security in terms of EU support and predictability of relations.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">New areas of concern</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">This session of the Joint Assembly saw the emergence of two new areas of concern: urban development, and the effects of climate change on small island states. An initial report on the former was presented by the rapporteur, Daby Diagne (Senegal). It did not give rise to much debate. The report emphasises the pivotal role towns play in economic development and urges the Community to adopt an integrated policy on urban development (See our interview with Mr Daigne in the Dossier). The latter was the subject of a full morning hearing, involving a panel of ACP-EU experts who are closely involved with the problem. They warned of the threat posed by global warming to the survival, and even existence, of many islands in the Caribbean and the Pacific. The emission of greenhouse gases, the Assembly was told, has reached levels never before experienced (see the article which follows). Representatives agreed on the need to integrate climate change considerations into sustainable development strategies. A Working Group on the issue was set up with Karin Junker (PES-G) as general rapporteur.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Cocoa and babanas</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">There was no avoiding the intractable problems of cocoa and bananas. On cocoa, opinions were divided as usual. There were those who felt that the Commission's proposed new directive allowing chocolate to contain vegetable oils (up to 5% of total volume) in place of cocoa butter, was reasonable. The proposal also involves a labelling system to ensure that the exact contents of the product are clearly indicated Advocates of this strategy argued that it would not only widen consumer choice but would also promote the export of shea-butter and other vegetable oils which a number of ACP countries produce. Opponents were worried that if implemented, the directive could lead to a big fall in cocoa exports and a commensurate loss of earnings for ACP cocoa producers. Magda Aelvoet (Greens-B) argued in favour of maintaining the status quo, saying that this was preferable to what was being put forward in the draft directive. She warned that the Commission propose' would almost certainly result in everyone (cocoa producers, shea-butter producers and consumers) losing out. There was no guarantee that menu facturers would choose shea-butter given that they would be free to use whatever vegetable oils they liked She was certain they would go for the cheapest substitute or even for synthetic products. Accordingly, Mrs Aelvoet proposed a 'freeze' on all proposals. This view was reflected in the resolution passed by the Assembly, which called on the Council to reject the proposed directive. It also requested the sever member countries which currently authorise the use of vegetable oil to comply gradually with the existing directive  -  which bans their use altogether.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The banana issue proved even thornier. There is a dispute at the World Trade Organisation, where the Lom&eacute; Protocol is being challenged by the United States and Latin American banana producers. Mrs Kinnock expressed anger at the fact that the arbitration panel set up by the WTO is made UP of three countries known to advocate free trade. The panel, she said, is chaired by Hong Kong - which the Organisation told her was representing the 'developing countries!' The general feeling among representatives was that the odds were stacked against the European Union and the ACPs. The Assembly passed a resolution asking the Union to stand firm in defence of the banana regime.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Democracy, human rights, peace and security</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Twenty-seven questions were addressed to the Council of Ministers and a further 28 to the Commission. More than a third of these dealt with issues relating to emergency relief operations, democracy, human rights, peace and security  -  recurring themes throughout the four-day meeting. The emphasis, in this context, was on Burundi, Rwanda, Liberia and Nigeria, all of which were considered individually under the agenda item 'the situation in ACP states'.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">In addition to the detailed answers given by Commissioner Pinheiro to questions on Burundi and Rwanda, the Assembly had a long session with Aldo Ajello, the EU's Special Representative to the Great Lakes. The discussion focused on efforts to restore democracy and legitimate government in Burundi, national reconciliation, and the repatriation of refugees from neighbouring countries to both Burundi and Rwanda. Mr Ajello gave members a comprehensive picture of the complex political and humanitarian situation in the region. He spoke of the sanctions imposed on Burundi by neighbouring countries and the efforts of the former Tanzania President, Julius Nyerere, to bring about dialogue and a just political settlement in Burundi.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Nigeria was again in the dock. Its representative, Dada Olisa, acting Charge d'affaires at the Embassy in Brussels, gave an account of what he considered was the progress made by the Abacha regime on human rights and democracy since the Joint Assembly met in Windhoek last March. He mentioned the repeal of the decree under which Ken Saro-Wiwa and other minority activists were executed, the release of detainees and the transitional programme for a return to democracy by 1998. He pleaded for the Assembly's understanding.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">His explanation cut no ice with any of the seven political groupings in the European Parliament, who came together to present a compromise draft resolution on Nigeria. They wish to see all political prisoners released immediately, and the restoration of civil and political rights, as well as a democratically elected civilian government, by the end of 1996.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The resolution on Nigeria was again passed by secret ballot - the very last act of the session. It calls, among other things, for a total arms embargo (preventing the trade in future but also covering existing supply agreements) and for the financial assets of the Nigerian government and of members of the country's ruling councils (and of their families), to be frozen.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The resolution does not differ very much from the previous one. Mrs Junker, Johanna Maij-Weggen (EPP-NL) and Mrs Kinnock all expressed disappointment that the EU Council had failed to implement this fully. However, by repeating the demand for sanctions, they said, the Assembly was sending a very strong message to the Council that it was determined to see Nigeria return to democracy as quickly as possible. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<B><P>&lt;&lt;TOC3&gt;&gt; Alarm bells sound on small island states</P>
+</B><P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Climate change</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">A morning session of the ACP-EU Joint Assembly was devoted to a public hearing on the effects of climate change on small island states. It was appropriate that the issue should be brought to the attention of the Assembly by Maartje van Putten (PESNL). Representing a country much of which lies below sea-level. she is familiar with the devastating effects of sea flooding. At the hearing, which was very well attended, a panel of invited ACP-EU experts was on hand to enlighten the audience on the extent of the problem.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Although global warning has been on the international agenda for more than 10 years, the seriousness of the threat it poses to the survival of small island states is only now beginning to be taken seriously - and it might already be too late, if some of the most apocalyptic scientific predictions are to be believed.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">There is now growing evidence that global warming is taking place. In recent years, we have experienced more extreme weather conditions - heatwaves, floods and increasingly destructive tropical storms - while there are signs that icecaps are melting and sea levels rising. The increasing incidence of malaria in Africa has been linked to these changes. And it is all happening because of the influence our style of living is having on the planet - in particular the huge emissions of greenhouse gases such as carbon dioxide and methane, from our factories, vehicles and so on.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">That the public hearing attracted a large audience was not only a reflection of the interest the problem is now commanding. It also symbolised the mounting international pressure for reductions in CO2 levels in the atmosphere, and for the adoption of more realistic strategies of sustainable development.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The panel of experts comprised Dr Leonard Nurse, Manager of the Coastal Conservation Project in Barbados, Donald Stewart, Acting Director of the South Pacific Regional Environmental Programme (SPREP), Dr Robert Watson, Senior Scientific Adviser at the Environment Department of the World Bank and Chairman of the second Working Group of the Intergovernmental Panel on Climate Change (IPCC), and Neroni Slade, Vice-Chairman of the Association of Small Island States (AOSIS) and AOSIS Coordinator on Climate Change. A separate workshop on climate change was also organised on the same afternoon outside the formal Joint Assembly setting.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">According to Dr Nurse, current estimates based on most reliable models, suggest sea level is rising at the rate of 5mm a year (the 'range of uncertainty' is between 2mm and 9mm). This is two to five times the rate experienced in the last 100 years. This rise is expected to continue beyond the year 2100 even if greenhouse gases are stabilised. The implications for small island states, particularly the low-lying ones, would be severe. 'Atolls such as Tokelau, Marshall Islands, Tuvalu and the Maldives could possibly disappear', he said. 'Major population displacement would be experienced in Micronesia, Palau, Nauru, French Polynesia, the Cook Islands and Tonga.' Meanwhile, small islands with extensive coastal plains and limited upland areas such as Barbados, the Bahamas and Antigua, 'would be highly vulnerable to social and economic disruptions', as major cities, ports and tourist facilities, industries, freshwater sources, fertile agricultural lands and even coral reefs are destroyed by typhoons and cyclones, or washed away in floods. 'Given the limitations of climate models,' Dr Nurse said, 'it is not possible to state with certainty at this stage whether there will be a change in the behaviour of tropical storms and hurricanes. However, it is highly probable that an increase in the frequency and intensity of these phenomena could occur in a 'warmer world'. One study, he claims, predicts tropical storms would have a potential destructive force at least twice what they have today.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Dr Watson, similarly, struck a pessimistic note when he said that the potential for irreversible damage was great. He agreed with Dr Nurse that even if we took measures now to reduce CO2 emissions, stabilisation of the situation will take centuries. He pleaded for climate change to be taken into consideration 'in our everyday decisions.' Governments must not wait for cause and effect to be established before taking action. 'It is,' he said, 'economically feasible to reduce CO2' by introducing appropriate policy measures: looking at supply of and demand for energy, resorting to new and renewable energy sources, nuclear power, etc. and ensuring more efficient land management.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The question of 'burden-sharing' in the reduction of emissions between the industrialised world and the developing countries was debated at length. It was noted, for example, that small islands states are responsible for a very small proportion of the emissions, yet they bear the brunt of the consequences. There was a general consensus that burden-sharing should be based on equity and justice.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">It should be noted that the Alliance of Small Island States (which was formed during the Second World Climate Conference in 1990) has called on the industrialised world to achieve a 20% reduction in their greenhouse gas emissions by the year 2005 (The 'Toronto objective'). This, it hopes, would bring CO2 in the atmosphere down to 1990 levels. Whether this is realistic is debatable.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">However, a number of strategy options are being closely examined by the European Commision and the Council with a view to adopting Community-wide measures to reduce emissions significantly by 2005-2010. Member States have made phasing-out proposals with targets of 5-10% by 2005, 15-20% by 2020 and 50% by 2030. This works out at an average reduction of 196 2% annually from the year 2000.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Several parliamentarians wanted to know what the Commission, in particular, had done and will do to help small ACP island states overcome the effects of climate change. It was soon discovered during the discussion that a number of African countries were equally concerned. A Commission representative referred the Assembly to the provisions in the Convention which covered global warming and the special problems of island states. Although there is no specific reference to climate change, the Commission had dealt and would continue to deal with the issue in the broader context of its environmental action. Studies, projects and programmes are being implemented in the Caribbean and Indian Ocean in particular. Furthermore, DG VIII has drawn up internal briefing papers aimed at making departments aware of the issues of climate change and the environment. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<B><P ALIGN="CENTER">&lt;&lt;TOC2&gt;&gt; Country reports</P>
+</B><P ALIGN="JUSTIFY"></P>
+<B><P>&lt;&lt;TOC3&gt;&gt; Fiji</P>
+</B><P ALIGN="JUSTIFY"></P>
+<I><P>&lt;&lt;TOC4&gt;&gt; Political stability is the key to economic success</P>
+</I><P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">In most of the ACP states featured in our Country Reports, the vital issues are usually economic and social ones. How is a nation with a poor natural resource base to achieve lasting development ? What can be done to improve the skills of the people? How can a vibrant private sector be created ? Can better health care be delivered and how should it be paid for? Some of these questions might well be valid for Fiji but the visiting journalist soon discovers that they are all secondary issues. For this is a country whose political system itself dominates the agenda. The fundamental issue here is the relationship between the indigenous people of Fiji and the descendants of indentured Indian labourers brought in by the British between 1879 and 1916 to work in the sugar cane fields.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Fiji, in fact, is home to people of a variety of cultures. On the indigenous side, the majority are Melanesians but there are also some Polynesians (living on the island of Rotuma). The country even plays host to Banabans, from Kiribati, who were displaced from their homes on Ocean Island to make way for the phosphate diggers. They hold a freehold to the island of Rabi and enjoy a special self-governing status. And while the Indians form the bulk of the non-indigenous population, there are also small Chinese and European communities as well as a number of inhabitants of mixed race.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Despite this diversity, it would be inappropriate to describe Fiji as a melting pot. Ever since the rapid expansion of the Indian population, official policy has tended to accentuate the divisions. In the early days, it was the British who were responsible for this, although one has to be careful to avoid value judgments. The colonial administrators, it seems, were aware of the tensions that would arise by bringing in large numbers of people of a different culture, language and religion. Their eventual response was to provide guarantees for the local population, notably as regards land rights. The effect was to preserve the traditional land tenure system which was based on villages and families. At the time, it seemed a logical thing to do, but several generations on, the country now has a settled population of Indian origin (43% of the total) who have limited opportunities to own land - even though many of them work on it.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">As the economy has developed, each of the two main communities has found itself 'specialising' in different fields. For example, cane farmers and retailers tend to be of Indian origin while the public service has traditionally attracted more native Fijians. Significantly, the army is almost exclusively filled by indigenous people - a crucial factor in the 1987 military coup.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">On the political front, as Fiji moved towards independence, the idea of providing separate representation for each ethnic group also took hold. The independence constitution of 1970 reflected this with the two main communities being given parity (22 seats each) in the House of Representatives.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Shattered illusion</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Although there was no real assimilation between 1970 and 1987, Fiji was seen by many as a model of a successful multiracial society. It was only when the country got its first Indian-dominated administration (sustained in power by a smaller native Fijian party) that this illusion was shattered. There was a military coup led by Lieutenant-Colonel Sitiveni Rabuka, who is now the elected Prime Minister,. Shortly thereafter, Fiji became a republic (Queen Elizabeth was formerly Head of State) and in 1990, a new Constitution was adopted giving political primacy to the indigenous Fijians. Needless to say, it was a time of greatly heightened communal tension.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The 1987 coup and the events that followed have been well covered elsewhere (including our previous Country Report which was published in 1991). It suffices to say here that while the last few years have been a lot less turbulent, tensions remain. In 1997, the country must adopt a new set of constitutional proposals and a big debate is currently under way about the shape of the system of government for the 21st century. This subject is covered in a later article and also features prominently in our interviews with the Prime Minister and Opposition Leader.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The main focus of this article is therefore on economic and social aspects although, as one soon discovers, this frequently leads us back to the ethnic question. This is particularly the case when one considers the overall economic performance of the country. Fiji is not poor by developing nation standards and it has enjoyed modest growth during 1995 and 1996, but there is a widespread view that it could be doing a great deal better were it not for the political uncertainties. The problem is summed up by the Economic Intelligence Unit in its Fiji Country Report for the first quarter of 1996: 'Political instability will continue to deter investment, other than that on highly favourable tax terms.' In other words, Fiji is paying a high economic price for its internal difficulties.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">General unease about the future and, in particular, the outcome of the constitutional review process is compounded by specific concerns over land tenure. The long-term leases granted to (mainly Indian) farmers are approaching their end and the government must soon decide what it should do next. Will any of the sugar cane farmers be evicted and if so, how many ? What alternative arrangements will be made for them? These questions remained to be answered when The Courier visited Fiji in July although, as our keynote interviews show, the subject was clearly exercising the minds of the politicians.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">A long-term strategy for agriculture?</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The way in which the land question is dealt with will have a crucial impact on the sugar industry - still the country's most important product in terms of its contribution to GDP and the jobs that it generates (see the article entitled 'Sugar definitely has a future'). With other uncertainties facing this sector - in particular, the process of global liberalisation - there is a growing recognition of the need for a long-term strategy. The government has a two-pronged approach  -  improving efficiency within the sector and diversifying into other agricultural products. To learn more about this, we spoke to Luke Ratuvuki, who is the Permanent Secretary for Agriculture, Fisheries and Forests.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Mr Ratuvuki began by stressing the scope for increasing the sugar yield per hectare by as much as 75% (and by even more with irrigation). If productivity could be boosted on this scale, Fiji sugar would be in a much better position to compete in open world markets. He admitted, however, that the country would still face a struggle in maintaining market share and, looking ahead ten years, foresaw a slimmed down industry providing high quality sugar with more of a focus on niche markets. This inevitably meant looking at other agricultural products as possible long-term substitutes. The coconut (or as the Permanent Secretary dubbed it, 'the tree of life') is traditionally grown here and seems poised to enjoy a new lease of life following a period of decline. Fiji has also picked up the taro trade at the expense of Western Samoa, which is affected by taro blight, while there are significant exports of ginger to Australia, New Zealand, Canada and Europe. Mr Ratuvuki spoke enthusiastically about branching out into other areas such as pawpaws, mangoes, bananas and aubergines.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Fiji has potential for growth in a range of non-agricultural sectors, but farming is sure to play a vital part in the economy for many years to come. Currently, sugar represents almost three quarters of all crops by value (excluding subsistence growing) and the Fijians are only too aware that this makes the country particularly vulnerable to external shocks.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The other primary sectors are all present in Fiji, albeit on a more modest scale. There is some deep-sea fishing backed by Asian investors. This provides useful employment although perhaps not the best possible financial return to the country. As one would expect in a nation of three hundred islands, there is also extensive artisanal and subsistence fishing in the inshore areas.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The forestry sector divides into two parts: artificial softwood plantations which are said to be managed sustainably and the naturally growing hardwoods. As regards the latter, the EU is helping with a mapping project. Although Asian loggers do not operate in Fiji, there is considerable land clearance taking place, leading to problems of erosion and silting.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Prospects for mining</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Gold is the main mineral being exploited with important deposits around Vatukoula. The sector has had its ups and downs but the Emperor Gold Mining Company has now embarked on an expansion project aimed at raising production from the current level of about 4000 kilos per annum to 6000 kilos by the year 2000. A huge copper and gold mine is also planned for Namosi, some 35 km from Suva. Other minerals discovered but not exploited include bauxite, iron, lead, zinc, phosphates and marble. Mining currently makes a modest contribution to overall GDP but represents an important component in the export earnings figures.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">With one key exception, manufacturing is on a fairly small scale with an emphasis on staple items (butter, beer, soft drinks, paint, soap etc.) for the local market. The exception is the garment industry which provides some 20% of the country's export income and a considerable amount of employment.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The investments in garment manufacturing and mining have been important in jobs terms and in improving the trade figures, but there are those who criticise the fact that the government appears to derive little revenue from the operations. The exact fiscal benefits are not easy to determine, prompting some observers to suggest that official secrecy should be eased (see the article on the Constitutional Review later in this Country Report).</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">In the service sector, long-term growth is foreseen in the key area of tourism. The number of holidaymakers choosing Fiji dipped sharply at the time of the coup, illustrating the importance of political stability in attracting visitors. Tourist arrivals bounced back once Fiji's internal difficulties had receded from the international headlines. The politicians must be hoping that nothing will occur during the current period of constitutional discussion and negotiation to put Fiji back on the front pages. It is worth mentioning here that Fiji's national carrier, Air Pacific, is an example of a relatively rare bird - an airline that makes money ! According to journalist Avin Rahish, writing in the July 1996 issue of The Review (the news and business magazine of Fiji): 'It is one of the few government investments that is profitable on its own.'</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">If tourism is a success story, there is something of a shadow over the financial services sector, which is more extensive here than in most developing countries. The reason is the collapse last year of the National Bank of Fiji with losses of US$ 142m (equivalent to 10% of the annual GDP). The authorities were accused of a failure in supervision and the taxpayers have had to pick up some of the bill. More serious, however, is the undermining of confidence in the system and it will take time for this to be restored.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Social challenges</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">As a middle-income country, Fiji has relatively favourable social indicators in the areas of health and education. Medical facilities are provided by the government but it is said that the public health system is not as good as it once was. This is attributed, among other things, to the emigration of highly qualified staff in the aftermath of the events of 1987. Nonetheless, the country does have 27 hospitals and one doctor for approximately every 1900 people. At 72 years, life expectancy is high compared to the ACP average.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The education sector is well-developed with more than 800 primary and secondary schools (for a population of less than 800 000) and 41 technical or vocational institutions. As a result, primary school enrolment is close to 100% while the 1986 census revealed that 60% of 15-year olds were still in education. On the other hand, there are concerns over the proportion of teachers lacking qualifications, notably in the primary school system. In practice, there is considerable racial segregation at both primary and secondary levels, although there is no official policy to this effect.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Educationally, the jewel in the crown is almost certainly the University of the South Pacific whose main campus is in Suva. This regional institution, which has departments in a number of other countries of the South Pacific, draws students from various island nations. Dr Vijay Naidu, who is the USP's Pro-Vice Chancellor, outlined some of the special features of this unique university which has to cater for a highly dispersed population. Like traditional tertiary institutions, it provides a wide range of degree programmes on campus, catering for 3500 students. It has a further 9000 who are being educated using the 'distance mode'. Distance learning is organised through centres in each of the participating countries. Students can attend these centres from time to time but much of their work is done through radio and telephone linkages and, increasingly nowadays, by e-mail and satellite communications. The University, Dr Naidu stressed, also provides continuing education at non-degree level 'in everything from computing to basket-weaving'.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Like the health sector, the USP suffered a loss of highly qualified staff after 1987  -  and not just among employees of Indian origin. As the Pro-Vice Chancellor pointed out, the coup created 'a new sense of insecurity' all round and teachers who decided to emigrate were quickly accepted in Australia and New Zealand. The loss has been particularly serious in the scientific disciplines.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">90% of the USP's recurrent expenditure is covered by member government contributions with the remainder coming from Australia and New Zealand. For capital investments, there is heavy reliance on external donors.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">In both of Fiji's main ethnic communities, a strong commitment to the family ensures that there is relatively little absolute poverty although things may be changing as the country become more urbanised. It is rare to see beggars in the streets in the South Pacific but Suva, sadly, has a number of these.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The overall picture is of a country with very considerable potential in both human and natural resource terms which needs to overcome a number of challenges to secure a more prosperous future. Some of these challenges - adapting to the world of free markets, tackling bureaucratic impediments, bringing development to rural villages, improving the infrastructure, and so on - are familiar to all developing countries. The single most important constraint, however, is the big ethnic divide, and the political uncertainty which flows from this. And this is something which can only be solved by the people of Fiji themselves. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<I><P>&lt;&lt;TOC4&gt;&gt; Interview with Prime Minister Sitiveni Rabuka</P>
+</I><P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">'The last ten years have been very educational for me'</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">It is almost ten years since Sitiveni Rabuka led the military coup which toppled the newly-electerl coalition government The stormy events of 1987 are long gast end Fiji has returned to more peaceful ways, but the country is arguably not yet at peace with itself. Major-General Rabuka is now the erected Prime Minister, having led the SVT to victory at the polls in 1992 and 1994. But the gulf between the native Fijians end citizens of Indian descent remains -  indeed, it is institutionalised in a political system which ensures a parliamentary majority for the former. A constitutional review is currently under way end a new text must tee adopted by July 1997. For both sides, the stakes are high. In this interview, Prime Minister Rabuka speaks frankly about the crucial issues facing Fiji as the nation gears up for the great constitutional debate.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Fiji also faces some formidable economic challenges and we began by asking the Prime Minister about these.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY"> - The main challenge is the one that everybody faces: achieving an acceptable rate of growth to ensure job creation and address the unemployment problem. We also want to improve the standard of living of the people, to upgrade our infrastructure, and to develop both the urban and rural areas.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">· What sectors do you see as offering the best hope for future growth ?</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY"> -  We are looking particularly at tourism and the agro-based industries. In the international sphere, we are aiming to boost trade, particularly with our traditional trading partners, Australia and New Zealand, and with new partners that we are trying to cultivate in Asia.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">We are very grateful for the Lom&eacute; Convention and the various arrangements associated with it - particularly as regards access to the EU market for our sugar products. Although it would be desirable for us not to have to rely on preferential pricing for sugar, for the moment, there is no alternative. And while we are looking for alternatives and seeking to diversify our economy, we will need that system to remain in place. We would like to continue the dialogue to ensure that this happens. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">In the area of trade, as I say, our focus is on Australia and New Zealand, and the regional trade agreement that the Pacific island territories have with them. This agreement is currently under review. One important aspect is the clause governing the rules of origin. If we can convince Australia and New Zealand to reduce the local input requirement from 50% to 35%, then we won't need any aid from them. The effect will be to secure existing jobs and, indeed, to increase employment, particularly in the garment industry. At the moment, most of the textiles we import for further processing come from Australia. Because of the market we have to sell to, it is very good quality material. This means the costs are high, in comparison with the local input needed to turn it into finished products, and this makes it difficult for us to get up to the required 50%.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">If we don't get that reduction, things could go in the opposite direction. Manufacturers might relocate and we could be facing jobs losses. You have to remember that we are competing with Asian producers who have very low wage costs. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">· Is this proposal for a reduction in the local input requirement on the agenda with the Australians and New Zealanders ?</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY"> - The review actually excludes the clause on the rules of origin. Having said this, we have effectively raised the calculation of our local input in negotiations on a series of other points. On paper, the 50% figure is unchanged but in fact, there has been a reduction of about 5%, thus giving us a little margin.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">· On the sugar issue you said you were hopeful that some form of preferential access to the EU market would be maintained. Isn't there a concern that this may not last beyond the year 2000, particularly given the increasingly liberal world trading system ?</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY"> - Yes, and we are looking at that. We should be gearing ourselves up for what happens at the end of the current Lom&eacute; agreement. It remains to be seen whether, with the WTO and the new trends, the curtain will suddenly be brought down on 1 January 2000, or whether there will be a grace period in which we are given time to consolidate our diversification.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">· The other big issue in the sugar sector concerns the impending expiry of the land leases.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY"> - That is a local issue and a very important one. It has high priority on our government agenda. We are currently talking to the landowners and lessees, explaining what will happen. The legislation (the Agricultural Landlord and Tenant Act) makes no provision for further extensions to the leases, which are now nearing their end. Do we need a new act or should we amend the present law to allow extensions beyond the 50 years originally allowed for ? And if we are to do that, what happens to the compensation provisions? At the moment, these are viewed in a rather one-sided way. The emphasis is on the situation where the landlord compensates the tenant for improvements made to the land. But the rules also provide for compensation in the other direction where the value has been reduced. This may be due to constant cultivation over 50 years. What if the owner wants to return the land to its original use, planting taro, yams or cassava, as his father may have done fifty years ago, and finds he can no longer do so ? There has to be a balancing act here.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Hopefully, most of the land will be leased again under a new agreement or under an amendment to the existing law - because we will need to continue sugar production. It is also worth noting that some sugar farmers are beginning to diversify into other crops, both subsistence and commercial.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">· What arrangements do you envisage for those farmers who do not have their leases renewed ? Will they be relocated ?</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY"> - Right now, we are looking at the use of state land. There are two basic categories here - what used to be known as 'Crown Land under Schedule A' and 'Crown Land under Schedule B'. Schedule A covers the land not claimed by anybody during the Commission that was set up to determine the ownership of land in the very early colonial years. Schedule B is land that belonged to a community or landholding unit that has since died out: in other words, where there is no surviving member of the land-owning unit. So we have those parcels of land available. My party's policy is to restore land to the traditional owners where possible, but in those cases where you cannot identify the original owners, there will be land available for resettlement - although resettlement is perhaps not a very good term to use. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">· It is somewhat emotive.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY"> - It implies taking a person, family or community from somewhere and planting them somewhere else -  and I hope we can avoid that. On the other hand, if you look at what people are doing nowadays, everybody's relocating. People are always resettling, moving away from home and setting up elsewhere. In this case it is perhaps a necessity, in the sense that the legislation has caught up with us. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">· Can I turn now to the sensitive issue of the constitution. This is another area where decision day is looming. You currently have a constitutional review under way with the Commission's report due out soon. What do you think will emerge from this process over the next 12-18 months ?</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY"> - I don't feel that the constitutional issue is a sensitive one and do not think anyone should feel restrained in asking questions about it. It reflects the reality of the situation in Fiji. There is a requirement that the 1990 Constitution be reviewed and we have a Review Commission chaired by Sir Paul Reeves. He is a very capable man who is a former Governor-General of New Zealand and a very eminent constitutional lawyer. Assisting him, we have two party nominees - one from the main Fijian party and one nominated jointly by the Indian parties in Parliament. I have total confidence in that Commission. I believe they will come up with very objective observations and recommendations.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Let me explain the timetable to you. The report is expected by the end of August. It will be presented first to the President and then to me for submission to Cabinet. I envisage it being tabled in Parliament towards the end of September. We cannot debate it until three months have elapsed from the date it was tabled - which takes us to the end of the year. A lot of work will be needed during the first half of 1997. The Joint Parliamentary Select Committee, made up of members of both the upper and lower houses, will have to work on the report and try and build consensus on the various issues.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Given that the house is racially divided, and the possibility that a premature discussion on the floor of the house may raise the temperature, I would prefer not to have a full parliamentary sitting in the early part of next year. Instead, we should go into committee and deal with it there. And then when we are satisfied that the issues can be brought out into the open, we will debate them fully in Parliament. As soon as we start talking next year, the legislative craftsmen should begin their work. On the basis of this programme, I believe we can meet the deadline to the day, promulgating a new Constitution which has been accepted by both houses on 25 July 1997. So I am very hopeful.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">· Without prejudging the final outcome, do you envisage a move away from strict communal separation ? I am thinking here, in particular, of the separate voting lists ?</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY"> - I think there may be provision for some cross-communal voting. There was something like this in the 1970 Constitution which had both communal and national rolls.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">· What about the longer term. Do you foresee a political system developing in Fiji where ethnic origin is irrelevant -  perhaps a 'right-left' divide, if that is still a meaningful concept ?</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY"> - I am not bold enough to say that that will happen. I have seen the darkest side of Fijian nationalism. I have seen the fear that was in the Indian population in 1987. But if we move too quickly to remove the racial safeguards that are in the Constitution, we may run the risk of prolonging the bad relationship between the races that we now have. So I would say we should proceed very cautiously and let the natural healing process take its course. We also need to look beyond the Constitution at aspects such as our education system and enhancing the ability of the Fijians to compete.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">· I believe the education system is also very divided.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY"> - Some schools are reserved for Fijians although, slowly, there are Indians from families close to the schools who are beginning to enter them.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">· Do you think that this is a promising sign for the future ?</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY"> - I think so. I went to a purely Fijian school and when I came out of that, everything was Fijian for me. I went straight into the army which is another Fijian-dominated institution. It was not planned that way. It is just the way it happened. My tolerance level of other races was very low. But you cannot expect somebody who gets to this level of leadership to have a low racial tolerance level. I must admit that the last ten years have been very, very educational for me - very good for my own being. I consider what I used to think before and the way I used to feel before. I have never been threatened by an Indian, but I had always been in Fijian 'safe' areas - a Fijian school and then in the army. But since coming out of that sort of cocoon, I have managed very well to accept that I have to compete with them, I have to look after them, and I have to devise policies and programmes that will be good for them as well as being good for us.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">· One final question. Do you envisage Fiji seeking to rejoin the Commonwealth in the near future ?</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY"> - I think seeking is the wrong word. We will do what we feel is good for Fiji and its people. The people of Fiji are those who are here now but it will include some of those who have moved on looking for greener pastures and who are willing to come back. We were not expelled from the Commonwealth; our membership lapsed. It is up to the Commonwealth to say whether they are prepared to reconsider our member ship. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<I><P>&lt;&lt;TOC4&gt;&gt; Profile</P>
+</I><P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">General information</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Area: 18 272 km². Fiji has two main islands (Viti Levu and Vanua Levu) and about 300 smaller ones. It has an Exclusive Economic Zone of approximately 1.3 million km²). </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Population: 790 000</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Population density: 43 per kilometre² </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Capital: Suva (situated on the island of Viti Levu) </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Main languaqes: English, Bauan </P>
+<P ALIGN="JUSTIFY">(main Fijian language)</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Currency: Fiji dollar (F$). In June 1996, 1 ECU was worth approximately F$ 1.80. (US$1 = F$ 1.40) </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&lt;&lt;I&gt;&gt; p15.png Fiji</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">Politics</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">System of government: A bicameral parliamentary system consisting of an appointed Senate and an elected House of Representatives. The President is a non-executive head of state chosen by the Great Council of Chiefs. The President appoints the Prime Minister. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Under the Constitution, adopted in 1990, the Parliament is divided along racial lines. The Senate has 34 members, 24 of whom are indigenous Fijians. In the 70-member House of Representatives, 37 seats are reserved for native Fijians, 27 for Indo-Fijians, 5 for 'general voters' (other ethnic groups) and 1 for Rotuma Island (whose inhabitants are Polynesian). The 1990 Constitution provides for a review within seven years and discussions are currently under way with a view to amending the Constitution by the 1997 deadline.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">President: Ratu Sir Kamisese Mara</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Prime Minister: Major General Sitiveni Rabuka </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Main political parties: Soqosoqo ni Vakavulewa ni Taukei (SVT - Fijian), National Federation Party (NFP  -  Indian), Fiji Labour Party (FLP - Indian),  Fijian Association (FA - Fijian), General Voters Party (GVP).</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Party representation in Parliament (1994 election result): SVT 31, NFP 20, FLP 7, FA 5, GVP 4, Others 3. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Economy</P>
+<P ALIGN="JUSTIFY">GDP: (1995) F$ 2.85 billion</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Annual GDP per capita: approx US$ 2600 </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">GDP growth rate (1995): 2.2% (2.9% predicted for 1996) </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Principal exports (1994): Sugar (US$ 182m), Garments (US$ 96m), Gold (US$ 43m), Fish (US$ 38m), Timber (US$ 21 m) Main trading partners (in order of importance):</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Exports - Australia, UK, USA, Japan, New Zealand.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Imports - Australia, New Zealand, USA, Japan, Singapore.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Trade balance (1994): exports - US$ 547m, imports - US$ 826, deficit - US$ 279m. The current account figures also usually reveal a deficit but this is much smaller due to tourism earnings and official transfers.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Inflation rate (1995): 2.2%</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Government budget (1996): revenue -  F$ 759m, expenditure  -  F$ 851 m, deficit - F$92 (about 3.5% of GDP) </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Forma/sector employment: 98 112 (out of a total economically active population of about 265 000) </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Social indicators</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Life expectancy at birth (1993): 71.6 years </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Adult literacy (1993): 90.6%</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">Enrolment in education: all levels from age 6-23: 79% </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Human Development Index rating: 0.853 (47th out of 174) </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Sources: Economic Intelligence Unit, UNDP Human Development Report, 1996, EC Commission. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<I><P>&lt;&lt;TOC4&gt;&gt; An interview with opposition leader Jai Ram Reddy</P>
+</I><P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">'We need to move to a more racially neutral system'</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Fiji is not unique in having a political system that is heavily influenced by racial or communel issues In places as diverse as Northern Ireland, Belgium, Guyana and Trinidad - not to mention many parts of Africa - people vote for parties which claim to represent the particular ethnic, religious or linguistic group to which they belong. Where Fiji is different, however, is in having a Constitution that gives primacy to one particular community. Since the 1987 coup, native Fijians have held the upper hand with a guaranteed majority in Parliament and a firm grip on the levers or power.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The 1990 Constitution, adopted when communal feelings were still running high, contained a requirement for a constitutional review within seven years. When The Courier visited Fiji (July 19961 the work of a three-member Commission appointed to carry out the review and make recormmendations was nearing completion. All sides seem to accept the need for reforms designed to help bridge the sharp racial divide.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The big question is how radical these reforms are likely to be. We sought the views of Jai Ram Reddy, the leader of the opposition National Federation Party (NFP) which has the support of most of the country's Indian (Indo-Fijian) community.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">· You are the first opposition leader I have met who cannot, constitutionally, become Prime Minister. How do you feel about that ?</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY"> - It is something that rankles with me - the mere thought that I am not equal with my fellow citizens of other races. I think that's generally the way the Indians feel here. All the constraints and limitations, the denial of basic human rights, are the source of a great deal of unhappiness.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">· You talk about basic human rights. Obviously, the political aspects are very important but I get the impression that, in other respects, this is a fairly free and easy society: there is free expression, for example.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY"> - Yes, but free expression is only one aspect of human rights. The fact is that discrimination based on race is widespread and institutionalised. About 45% of the population is Indo-Fijian but you will find they are not fairly represented in the higher levels of the public service. At the Permanent Secretary level, there is definitely a government policy to have a limited number of Indians - and there are hardly any in the more crucial ministries. The same is true of managerial positions throughout the public sector. In the statutory bodies and major public undertakings, there is a deliberate policy of excluding Indians. So we are very much a marginalised community in the public sector.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">· Wouldn't it be true to say that Indians have quite a lot of economic power ?</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY"> - No, I don't agree. There is a tendency for people who come here, end for some people in Fiji, to project this image of Indians controlling the economy. It is a fallacy. It all boils down to how you define economic power.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Let's take natural resources. The land, and therefore the forests, are almost exclusively owned and controlled by native Fijians. Even in the corporate sector, the largest business undertaking is the manufacture of sugar, and 80% of the shares are owned by the government. The Indians don't own this industry. They are the small sugar cane producers working on ten-acre plots. And who controls banking and insurance ? Certainly not the Indians. Most of the financial services companies are foreign-owned.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The area where the Indians are most visible is in the retail sector. But those little shops you see in the towns are small family businesses. The shopkeepers work up to 15 hours a day, and you will discover that many of them do not even own their premises; they are tenants. So the idea that Indians control the economy is a bit of a myth. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">· The Constitution, and in particular the system of racial differentiation for voting and holding certain offices, is obviously a key issue for you. With the Constitution currently under review, what is your party's policy in this area ?</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY"> - The first elections under the current Constitution took place in 1992 and we took part in them under protest. We made clear that our participation should not be construed as acceptance of the system. Indeed, the sole issue on which we campaigned was our rejection of the Constitution. But we accepted the fact that we needed to get into the system as it was, and to try and create an environment where there would be widespread appreciation that it had to change. The 1990 text, in fact, laid down that it had to be reviewed by the seventh anniversary of its promulgation. I think the architects of the Constitution realised themselves that it was deficient. And we laid great emphasis on the need for dialogue; a general recognition that the country would be much better off with everybody working together and that there was nothing to be gained by oppressing or marginalising a community. And that is the kind of environment we have tried to create.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">· The Constitutional review will shortly be published. What do you hope will come out of that exercise ?</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY"> - I am reasonably optimistic. I think the environment is more favourable now and there is a general recognition that the system has to change. I am sure you will get confirmation of this when you talk to the government side. We need to move away from this very polarised, compartmentalised political system to a more racially neutral one. I think views may diverge as to how far we should go. That will be the contentious issue. But I believe we will make progress.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">I certainly think we will get a good report from the Constitutional Review Commission. One of our fears, when we started on this journey, was whether it would be independent and be given fair terms of reference. Largely because of the cooperative and accommodating attitude that we ourselves adopted, and to which the government responded, we were able to get a Commission that was well-balanced. We are very fortunate to have Sir Paul Reeves, a former Governor-General of New Zealand. His independence is taken for granted. The Commission also has one nominee from the indigenous side and one from the Indo-Fijian side. So we certainly expect a good report. There is already a kind of acceptance I think on all sides that political parties need to prepare themselves for a more multiracial approach to governance in the future.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">· On this point, I see that the SVT (the governing party) is looking at the idea of opening up its membership to other groups.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY"> - That's right.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">· Do you think there will be many nonnative Fijians interested in joining ?</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY"> - Not straight away but at least it is a beginning. It is an acceptance that they can't remain racially exclusive. If, for example, the Commission recommends a move toward a racially neutral system - at least for a certain number of seats - then it would be important for the SVT to have non-Fijians in their party.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">· Can I turn to economic issues, which I presume cannot be divorced altogether from political ones ? There is a lot of discussion about the future of the sugar industry which is tied in with the question of renewing the land leases This is an issue which is due to be resolved soon. How concerned are you about the impending decision on the leases ?</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY"> - This is something that concerns us very deeply. As you correctly observe, you can't separate the political and economic aspects. The two are very closely interlinked here - perhaps more so than in other countries - because of the land situation. The bulk of Indian peasant farmers, both within and outside the sugar industry, are on leases that will begin to expire next year. If these are not renewed, the problem will not just be an economic one but an enormous human one. What do we do with these people who all belong to a particular racial group. It really boils down to our very survival. Despite the growth in the towns, the bulk of the people are still rurally based. They are small subsistence farmers, living in the country areas with no more than 10 or 12 acres to cultivate. So the social implications of non-renewal in terms of poverty, dispossession and hardship are enormous.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">· But how real is the concern ? Surely, the overwhelming economic logic is for the leases to be renewed. After all the land is being put to productive use at the moment</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY"> -  Yes, but unfortunately, when you have a communal dimension to the problem, logic does not always prevail. If you think about it, there was no logic in the events of 1987. The trouble is that every issue here has a racial twist. After the coup, communal sentiments were aroused and sharpened. There was a prolonged period of anti-lndian propaganda and in that environment of anger, a highly racial constitution was adopted. There were people in positions of influence openly advocating non-renewal, threatening to take all the land back. Now they need to undo all this and it will not be easy, given the enormous strength of feeling that has been aroused. Having said this, I believe that we are now in the process of restoring sanity to our public life. It is also beginning to dawn on everybody that the sugar industry is vital for Fiji and it will continue to be so for some years to come.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">· I have heard that view expressed on all sides, but I wonder if people are sufficiently aware of the implications of global liberalisation. It has been suggested that this will make sugar increasingly unviable.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY"> - I think a lot of people are unaware of the implications, because there has been very little public education in this field. But amongst those 'in the know', there is certainly an appreciation. I am a member of the Parliamentary Select Committee on Sugar and we were recently addressed by the head of the marketing company and the head of the Sugar Commission. At that level, there is an awareness, but if you speak to the average farmer who has been growing and selling sugar for many years, he will probably assume that life will just go on as before.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Isn't it true to say that sugar depends heavily on the Lom&eacute; Convention arrangement with the European Community ?</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY"> - Very much so. In my view, the sugar industry is run so inefficiently that but for the huge subsidy we get from the European Community, it would not be viable.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Presumably, this means that measures must be taken to improve efficiency ?</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY"> - Yes, absolutely. But the first issue to resolve is the land question.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">There is no point talking to the farmers about efficiency  -  asking them to improve their husbandry and focus on sugar content rather than the quantity of cane produced - when they don't know if they will have land to cultivate after next year. So you see all other issues have become completely subsidiary to the tenure question. At the moment, we are in a limbo. The government and the people urgently need to resolve this problem. Then we can put it behind us and address the other concerns.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Are there any other economic sectors which you feel offer promise for the future of the country ?</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY"> -  Any growth outside of tourism will, I think, have to be centred on the agricultural sector. We need more agro-based industries and more diversification. We could grow a lot of other crops here - mangoes for example. We also need to improve extension services to farmers, and make an aggressive effort to identify markets. The farmers will grow the crops but they must be sure that somebody will buy them. Every year, for example, we have a glut of tomatoes - so many that they can't even give them away in the markets. This kind of problem kills the incentive to produce.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">There is obviously heavy state involvement in the running of agriculture. Do you see scope for more privatisation or 'corporatisation' in line with global trends ?</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY"> - I think that growth, even in the agricultural sector has to be private-sector driven. At the same time, you have got to create the right environment and infrastructure for this to happen. Unfortunately, it keeps coming back to this question of land. If big investors, for instance, want to come here and invest in agriculture, they need to know what sort of tenure they are going to get and whether they can buy the freehold. I am sure there are people, particularly now from the Asian region, who would be interested in investing in agriculture, but the land problem is a big constraint.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Do you think Fiji will rejoin the Commonwealth at any point ?</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY"> - Well, we hope so. You know we are all very strongly in favour of rejoining. One of the things that I personally feel very strongly about is the unfortunate severance of our link with the Queen. I don't know, constitutionally, whether it can be restored. Obviously, there are difficulties in that area, but I think a large majority of ordinary people in this country would like at least to see Fiji back in the Commonwealth. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<I><P>&lt;&lt;TOC4&gt;&gt; Seeking a lasting constitutional settlement</P>
+</I><P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">When The Courier visited Fiji in July, the report of the Constitutional Review Commission headed by Sir Paul Reeves (former Governor-General of New Zealand) had not yet been completed  -  and what it would contain was a major topic of speculation. As readers will see from the interview we publish with the Prime Minister and Opposition Leader, the impartiality of the three-member Commission was not in question  -  at least within the political mainstream on both the native Fijian and Indian sides. Nonetheless, there were doubts about whether a consensus could be found. For the Indo-Fijians, a scaling down of the 'racial' features in the Constitution was seen as a prerequisite. Yet the ruling SVT, in its own submissions to the Commission, had effectively supported the status quo. In view of this apparently unbridgeable gulf, could the compilers of the Report come up with recommendations capable of forming the basis for a lasting constitutional settlement ? </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The long-awaited Report was formally transmitted to President Ratu Mara on 6 September and a few days later, it was tabled to a joint session of the Senate and the House of Representatives. It now falls to a joint select committee of the two Houses to thrash out a new set of constitutional proposals. These will be presented to Parliament for debate and decision in the first half of next year with a view to meeting the July 1997 deadline foreseen in the 1990 Constitution.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The Report of the Review Commission is lengthy (almost 800 pages) and contains no fewer than 697 separate recommendations. The key ones, however, relate to the system for electing members of the House of Representatives. Currently, separate electoral lists based on race are used to fill all 70 seats (37 native Fijians, 27 Indo-Fijians, 1 Rotuman and 5 'General Electors', covering all other races). It was widely expected that the Commission would propose a mixture of 'reserve' seats and 'open' ones, with the latter, as their name implies, being chosen by the whole electorate.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">45 'open' seats proposed</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">This is precisely what they have done - but the suggested breakdown may have come as a surprise to some. The proposal is for 45 open seats (15 three-member constituencies) and 25 single-member 'reserve seats (12 native Fijian, 10 Indo-Fijian, 1 Rotuman and 2 'General Electors'). If adopted, the new system would no longer legally guarantee a majority for people of Fijian origin in the country's legislature. What would happen in practice would depend on a number of factors including the nature of the voting system in the three member open constituencies, the willingness of people to cast their ballots across the ethnic divide and the actual turnout of voters from the different communities. It should be pointed out, however, that native Fijians now constitute half the population, large numbers of Indians having emigrated over the past nine years. So long as communal voting patterns persist, this will presumably be reflected in the Parliamentary arithmetic.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">It is also proposed that the bulk of the 35-member Senate (Bose e Cake) should be made up of elected representatives of Fiji's provinces. In the field of local government, it is suggested that the present system based on villages and provinces, which applies only to native Fijians, might be replaced by an arrangement applicable to all races. In this context, the rote of the Council of Chiefs (Bose Levu Vakaturaga) would be reduced.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Although the sections of the Report relating to representation are bound to attract most attention, the Commission also put forward a series of other proposals aimed at improving the governance of Fiji. One idea, which appears designed to alter the political culture, is for the 'Official Secrets Act' to be replaced by a 'Freedom of Information Act'. The presumption of secrecy would be replaced by a rule that official information should be accessible to the public except where there is good reason to withhold it. In a similar vein, the Report recommends an 'integrity code' to govern the behaviour of holders of public office.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Initial reactions to the outcome of the Commission's work were mixed. Key players, including the President, Prime Minister and opposition spokespersons broadly welcomed the Report but more nationalistic elements were quick to reject it and one group even mounted a ceremonial burning of the document.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">It is obvious that a great many more words will be exchanged - and some of them will no doubt be heated  - in the coming months. It is difficult to see how everyone can be 'brought on board' but the hope must be that a compromise can be crafted that is acceptable to the majority on both sides of the communal divide. The people of this Pacific island nation are well aware that prosperity and stability go hand in hand. The single most important achievement in ensuring stability for the longer term would be to secure a satisfactory settlement of the constitutional issue. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<I><P>&lt;&lt;TOC4&gt;&gt; 'Sugar definitely has a future'</P>
+</I><P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">This was the key sentiment expressed by Isimeli Bose, Fiji's Trade Minister, when he spoke to The Courier earlier this year. Mr Bose insisted that 'no matter what anybody says, sugar will be the backbone of this country's economy for years to come.'</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">When we discussed Fiji's current economic situation and future prospects with the Minister, it was not surprising that sugar should have featured so prominently. The sector faces a difficult future for both internal and external reasons. At home, the long-term leases granted to the farmers (mainly Fiji Indians) under the Agricultural Landlord and Tenant Act are due to expire over the next few years. No provision was made for their renewal and the resulting uncertainty has provoked widespread concern, not least among the leaseholders themselves. The external 'threat' comes from new international trade rules administered by the World Trade Organisation. At present, Fiji's sugar industry is heavily dependent on the preferential access to the EU market which was granted under the Lom&eacute; Sugar Protocol. No one is quite sure what will happen when Lom&eacute; IV expires at the turn of the century but it is clear that the stakes are high.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Mr Bose was quick to acknowledge the importance of ending the uncertainty facing the sugar farmers. 'But the real challenge', he said, 'is to ensure the maintenance of our markets for sugar.' He was aware of the encroachment of global trade liberalisation but stressed that the industry's leaders and the government were 'doing the work now and planning for the future.' At the same time, the authorities are clearly hoping that the European Union will be able to continue with some form of preferential arrangement after the year 2000, if only to buy time so that the industry can adapt and farmers can diversify.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">On the subject of trade diversification, Mr Bose pointed out that 'the field is very limited'. He continued; 'However, since 1988, we have seen garment production picking up from very humble beginnings. By 1995, we had about F$185 million-worth of exports in this area.' He also spoke enthusiastically about the government policy of encouraging manufacturing in tax-free factories and zones. 'This developed well between 1989 and 1992 and then there was something of a slowdown.' Tax-free factories have been established in a number of locations and the first real tax-free zone is now being set up in Kalabo. Mr Bose indicated that EU assistance was being provided in this area.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Privatisation</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Our conversation then turned to the changing economic role of governments - throughout the world, they are withdrawing from active involvement in industrial and commercial operations. We asked how far this process had occurred in Fiji and, in particular, whether there was a privatisation policy. The Minister replied in the affirmative, pointing out that government departments 'do not usually make very good businesspeople.' The policy, therefore, was to 'corporatise' and 'privatise', although the process is still in its early stages. The Trade and Commerce Ministry has a public enterprise unit which is responsible for drawing up a policy framework for the government. In 1995, Mr Bose explained, a public enterprise bill was presented to Parliament, 'but there were so many concerns expressed to the previous Minister that it was referred to a select committee -  which, in fact was chaired by me before I took up my present poet.' The committee had now completed its work and the Minister indicated that the issue would go back to Parliament in September.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Despite the legislative delay, Mr Bose was keen to stress that his department was already working on individual programmes. The post and telecoms business, for example, had just gone through another stage towards privatisation.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">There is, of course, an important distinction between 'corporatisation' and 'privatisation' - the former implies staying within the state sector but at arms-length from the administration. This point was acknowledged by our interviewee who explained that the approach was a step-by-step one. The first stage was to reorganise a department along commercial lines. Corporatisation came next 'and then finally you have privatisation by disposing of shares.'</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">He stressed that the most important aim was to ensure an element of competition wherever possible. 'There is no point simply moving from a government monopoly to a private monopoly', he insisted, 'although obviously, there are utilities like water, electricity and even telephones where this may not be easy.' The minister concluded; 'Where they are natural monopolies, we will regulate them.'</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Our final topic of discussion was the possibility of regional integration in the Pacific.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">How far had the South Pacific countries gone in this direction and did the Minister think there was a need for closer economic cooperation? Mr Bose replied that he thought economic integration was a good thing. He pointed to a document on his desk containing a draft proposal for a bilateral trade agreement with Papua New Guinea. 'We will soon be holding negotiations with them, and have also just signed an agreement with Tonga.'</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The focus on bilateral trade arrangements at this stage suggests that the region still has some way to go on the regional integration path.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">But the Minister nonetheless insisted that it was something 'that can and will happen'. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<I><P>&lt;&lt;TOC4&gt;&gt; Our daily bread - courtesy of a remarkable Fijian businesswoman</P>
+</I><P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">How can a businesswomen succeed in Fiji's patriarchal society? Mere Samisoni, the entrepreneur behind the 'Hotbread Kitchen' gave us an appropriate answer when she said 'I roll with it', although the pun was probably unintentional In fact, it is difficult to imagine this dynamic lady being pushed around. Anybody who manages to build up a chain of bakeries from scratch, capturing 35% of the country's urban consumer market in the process, must have a lot of determination. At the same time, Mrs Samisoni displays a strong sense of social commitment. She believes in community values, advocates group decision-making and consensus, and even describes the tax system as 'reasonably fair'. In short, she contradicts the widely-held view propagated by lurid American TV series, that a dogeat-dog attitude is needed for business success.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">In fact, Mrs Samisoni started out with the idea of working with one of the caring professions. Trained in nursing administration in Australia and New Zealand, she returned to Fiji only to find that there were no openings available. That was when she decided to go into the private sector, establishing 'Samisoni Enterprises'. And over the years, she has succeeded in building up one of the largest bread-making operations in the country. The Hotbread Kitchen operation is highly decentralised with the bread being baked in different locations for sale through the company's local outlets. Her business is also the first Fijian one to franchise out its operations. And having already won a big chunk of the urban market, she is now looking to expand operations in the rural areas.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Samisoni Enterprises, of course, is not simply a bread-making operation. The company now offers a line of 62 separate bakery products, with some local adaptations to suit varying tastes. It employs some 275 staff with perhaps another 50 working in the related franchise operations. And the business had an important breakthrough when it won the contract for 'MacDonalds' in Nadi. With branches of the famous hamburger chain likely to open in other parts of Fiji, this could be the start of something big. In fact, there is even a suggestion that Fiji could be used to source Macdonalds' operations in New Zealand, the rolls (or buns, as the Americans like to call them) being exported frozen.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Constant quality</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">For Mrs Samisoni, the key to a successful and profitable operation is 'constant quality' and unfailing attention to customer service. As she puts its, 'if you let quality slip just once, you can end up losing customers for a very long time.' Baking is a labour-intensive business and she is keen to stress the importance of developing people's abilities - in particular, the human relaitons skills of those who deal direct with the customer.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">As if running a business wasn't enough, Mere Samisoni is also busy completing a Masters in Business Administration (MBA) at the University of the South Pacific, with a thesis on indigenous business. From what we discovered, speaking to this remarkable Fijian entrepreneur, she should have been helping to teach the course! </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<I><P>&lt;&lt;TOC4&gt;&gt; Viti Levu - island of contrasts</P>
+</I><P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Anyone from overseas who is travelling to the Fijian capital, Suva, will soon discover that the country's largest island is a very diverse place. Roughly circular in shape, Viti Levu provides more than half of Fiji's total land area and is home to about three-quarters of the population.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The journey to Suva on the south-east coast will almost certainly involve transiting through Nadi International Airport (pronounced Nandi) which is situated in the west. This is the country's only major international gateway and while it is ideal for tourists heading for the resort hotels, it is less convenient for business travellers whose destination is Suva. Their journey has to be completed either by road (which takes several hours) or on one of the small commuter planes which ply regularly between Nadi and Nausori (itself a half-hour drive from the capital).</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The biggest surprise to those who are unfamiliar with the country is that the west and the south-east have very different weather patterns. When your aircraft lands at Nadi, the chances are high that the sun will be shining. On reaching Suva, you are more likely to encounter rain. This part of the country enjoys - if that is the correct term - a micro-climate which is good for tropical vegetation but less appealing to human beings. The 'blame' for locating the Fijian capital in such a spot is said (not too seriously) to lie with the country's former colonial rulers. According to the story, a British envoy visited Suva on one of its rare sunny days and, on the strength of this, designated it as the seat of administration. The British can hardly deny their involvement since it was in 1882, during the early years of colonial rule, that the capital moved from Levuka (situated on the much smaller island of Ovalau). But the key reason was almost certainly the fact that Suva, with its large bay, could be developed as a port. Whatever the explanation, one must have some sympathy with the foreign diplomats who keep a raincoat or umbrella to hand at all times, and yet are viewed with envy back home because they have a 'paradise' posting.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">To be fair, Suva has attributes other than its weather which make it an interesting place. It has, for example, some very attractive architecture, both local and colonial. The views across the bay can be dramatic - and, in this respect, the rolling cloud formations may actually enhance the picture. And the centre of the city buzzes with activity (except on Sunday because of the Sabbatarian influence).</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The population of the greater Suva area is about 160 000. This may not be enormous, but it is the largest concentration of humanity to be found between Hawaii and Australia. In some ways, it is the 'capital' of the South Pacific - a point which is underlined by the fact that the Forum Secretariat is based here. It is also the site of the University of the South Pacific's main campus. The local population is mainly ethnic Fijian but there are Indo-Fijians as well as citizens of Chinese and European extraction. Add to this the diplomatic corps, foreign businesspeople and students from other parts of the region, and you get a very cosmopolitan mix. This is reflected in the variety of cuisines available in the local restaurants.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The western part of Viti Levu is also cosmopolitan but in a very different way, with a stronger Indian influence and, of course, a constantly changing tourist population.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Most of the island's inhabitants live a relatively short distance from the sea. Thus, in demographic terms, Viti Levu is like a doughnut with a thick layer of humanity around the edge and a hole in the middle. The analogy may not be entirely apt since the 'hole' is, in fact, a spectacular mountainous area. This makes the road that runs round the island a key arterial route. Meanwhile, those who choose to fly from Nadi to Suva, assuming they are not of a nervous disosition, can enjoy the experience of travelling below the height of the surrounding peaks.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The few people who do occupy the central region live in traditional Fijian villages and have a lifestyle far removed from either the town dwellers or the sugar cane farmers. Its size may be little more than ten thousand square kiLom&eacute;tres but Viti Levu is truly an island of contrasts. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<I><P>&lt;&lt;TOC4&gt;&gt; Fiji-EU cooperation: comprehensive package</P>
+</I><P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">by Ernst Kroner</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Fiji was a signatory of the first Lom&eacute; Convention in 1975 and, to date, the country has been allocated some ECU 190m in EU development cooperation funds.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Starting with a relatively modest ECU 9.9m under Lom&eacute; I, the national indicative programme rose to ECU 13m under the following Convention. Without neglecting rural development (feeder roads in Vanua Levu), under Lom&eacute; I most of the resources were devoted to transport infrastructure (a main road on Vanua Levu). Under Lom&eacute; 11, cooperation concentrated clearly on agriculture and rural development, in particular by means of the funding of microprojects, with infrastructural programmes (the extension of the Vanua Levu road, social infrastructure) taking second place. Under this Convention, a new field of action was also addressed: trade development.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Tax free zone</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Trade development was addressed further under Lom&eacute; III (6th EDF, ECU 20m, of which ECU 5m in special loans), with support given to an Investment and Trade Development Programme. The longer-term objective of the project was to widen the economic base of Fiji and to create employment. The more immediate objective was the i establishment of a Tax Free Zone near Suva. In order to promote this scheme and to secure markets for exporting the goods which would eventually be produced, the project included a programme of trade and investment promotion to be implemented by the Fiji Trade and Investment Board. Due to problems linked with identifying an appropriate site, the project, which had been given the go-ahead in 1990, only came on stream in 1995.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Rural and agricultural development continued to be one of the main sectors of cooperation, with the funding of three major projects. The first was a coconut rehabilitation and development project, situated on the island of Taveuni, which aimed at improving the productivity of coconut plantations through the introduction and multiplication of high yield hybrids. The project also provided for the establishment of a 30 hectare coconut nursery centre, which was expected to finance itself through the sales of seedlings. EC support for this project ended in 1992, since when the scheme has been taken over by the Government. A second project (a large-scale microprogramme divided into two sub-programmes) aimed on the one hand at the construction of access roads to facilitate the development of cocoa plantations, and on the other at the introduction and development of pineapple plantations in Vanua Levu. The first component was closed after disappointing results. The second component, however, produced very interesting and promising results, which will, however, need private and governmental support in order to become sustainable. A rural electrification project involving 28 rural electrification schemes and the supply and installation of a small power plant is still ongoing.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Developing human resources</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Under Lom&eacute; III, the formerly prominent transport infrastructure sector lost some importance. The Kubulau Peninsula road project on Vanua Levu brought to an end the work started under previous Conventions. This road, which filled the last gap in the circuminsular road, was opened on in July 1994. Lom&eacute; III also saw the beginning of human resources development as a new theme of cooperation, with Technical Assistance funded for the logging school. This area, embodying strong links with forestry and environmental issues, has been further developed under Lom&eacute; IV with the reconstruction of the school burnt down in 1993, and the enlargement of the training and education provided to what now constitutes a Forest Training Centre.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The national indicative programme relating to the first protocol of Lom&eacute; IV (7th EDF, ECU 22m in grant aid) identifies rural development and social infrastructure as the sectors of concentration to which 65% of resources are to be devoted. The remaining 35% will be used for non-focal activities, including trade and services, tourism, cultural cooperation, training and technical cooperation.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Building bridges</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Unfortunately, it was only following the very destructive cyclone Kina in January 1993 that cooperation activities could start in the form of the rebuilding of four bridges either severely damaged or completely destroyed by the post-cyclone floods.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Work on two smaller bridges of major importance to Viti Levu (Korovou and Vunidawa, ECU 1.135m) was started in 1994 by the Public Works Department and completed in January 1995.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The Financing Agreement for the two major bridges (ECU 10.24m) was signed in June 1994 and provides for the rebuilding of the bridges of Ba and Sigatoka. These form part of the main road around the island of Viti Levu and are therefore vital for the movement of people and goods on Fiji's main island. The new bridges, 190 and 182 metres long respectively, will be two-lane, and will provide for footpaths and utilities. To enable the traffic to by-pass the often congested towns of Ba and Sigatoka, new sites for both bridges have been chosen, which also call for the building of new approach roads. Building works were under way in early 1996 and completion is expected by April 1997.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Non programmable aid for Fiji has been considerable over the years. While Stabex transfers for losses on coconut oil (totalling ECU 5.4m under Lom&eacute; I - Lom&eacute; III) came to a halt under Lom&eacute; IV (because levels of exports fell below the required dependency threshold), emergency aid (total ECU 9.5m) has continued, unfortunately, to be needed. Time and again the islands have been hit by cyclones (the most recent occasion being in January 1993, when the EU made available ECU 1 m for food rations following cyclone Kina).</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">In the past, a significant feature of EU-Fiji cooperation was the credits provided by the European Investment Bank. It was very active under Lom&eacute; I to Lom&eacute; III, providing loans from its own resources to a total value of ECU 87.5m with a further ECU 6.1 m allocated in risk capital. Loans went to the energy sector (hydropower scheme), industry (wood processing) and services (telecommunications, sea and air transport). Considerable interest rate subsidies (totalling ECU 14.1m) have also been made available under the various EDFs in support of these loans. More recently, the EIB has financed an aircraft maintenance centre (1991) and a telecommunications project (1995).</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Trade cooperation</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Over and above financial cooperation, Fiji benefits from the second largest quota (165348 tonnes per annum) under the Sugar Protocol annexed to the Lom&eacute; Conventions. This covers some 45% of its total sugar exports. The yearly benefit from this provision is estimated at between ECU 45m and ECU 55m - in other words, only slightly less than the total of all programme aid granted since Lom&eacute; I (ECU 64.9m). About two-thirds of these benefits reach the farmers, so that the EU subsidises every sugar smallholder, on average, to the extent of some ECU 1500 a year.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Recently, Fiji's quota under the Sugar Protocol was increased by 881 tonnes, as a result of the reallocation of the shortfall of deliveries by Barbados. Furthermore, Fiji benefits from an annual special tariff quota to the tune of some 30 000 tonnes up to the year 2001.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Industrial development and external trade have been supported by the relaxation of the rules of origin for exports to the EU of canned tuna to the extent of 500 tonnes a year from 1993 to 1996. A similar arrangement, applicable for certain quantities of garments up the end of 1993 was recently extended to the end of 1996.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Fiji's main exports to the EU (sugar, fish and garments) - and the resulting surplus in its trade relations with the EU - are consequently highly dependent upon the continuity of these preferences.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Support for tourism</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">In the field of services, and specifically in tourism, the EU - through its support of the Tourism Council of the South Pacific - has contributed to the fact that every sixth tourist or so arriving in Fiji comes from a member country of the Union. Tourism being by far Fiji's most important source of foreign exchange earnings, receipts from European tourists amount at present to some ECU 30m, and are greater than those from the export of fish and fish products</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Taking the Sugar Protocol into consideration, the EU is by far the most important of Fiji's development partners, followed by Australia. The country also benefits from bilateral cooperation arrangements with EU Member States (UK, France, Germany). </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<B><P>&lt;&lt;TOC3&gt;&gt; Tonga</P>
+</B><P ALIGN="JUSTIFY"></P>
+<I><P>&lt;&lt;TOC4&gt;&gt; Hoping to maintain harmony</P>
+</I><P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">'None of the most civilised nations have ever exceeded these islanders in the great order and regularity maintained on every occasion, in ready and submissive compliance with the commands of their chiefs, and the perfect harmony that subsists among all ranks.'</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">These were the words of Captain Cook who visited the Tonga archipelago several times on his voyages around the world in the eighteenth century. The famous explorer was obviously impressed by the social organisation of this island nation and, although it is more than two centuries since he undertook his Pacific voyages, many of his observations hold true today. Talk of submissive compliance may no longer be appropriate, but in contrast to the turbulence of much of the outside world, Tonga certainly ranks as a peaceful society, which is respectful of hierarchies and strongly attached to 'traditional values'.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The reference to harmony is particularly apposite, as The Courier discovered when we visited Tonga earlier this year. It was fortunate that our trip coincided with the King's birthday celebrations and we had the opportunity to enjoy the superb choral music which plays a central part in many important ceremonies here. Like their Polynesian cousins in Western Samoa (featured in our last issue), the Tongans seem to have a natural flair for music and a talent for spontaneous harmony. The question is whether these 'Friendly Islands' - a name they certainly deserve  -  can maintain their reputation for social harmony into the third millenium.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">In order to answer this, one has to identify where discordant notes could creep in. The biggest challenge appears to come from the process of globalisation. New technologies, particularly in the field of communications, are rapidly breaking down barriers. The tide of the international economic system, with its emphasis on mass production, con sumerism and free trade, is lapping at the islands' shores And political systems everywhere are under pressure to con form to a 'democratic' model which some would argue places the individual above the community. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Of course, external influences can be both positive and negative Cultural exchanges can be enriching, and new ideas and techniques may offer opportunities for improving the quality of life. The key is to adapt without undermining the social fabric. And in Tonga, as in other countries, a harmonious future will ultimately depend on the way the country evolves both politically and economically.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Looking first at the current political set-up in Tonga, one cannot fault the use of the term constitutional monarchy which is the preferred description locally. It is important, however, to recognise that the constitution - which dates back to 1875 - gives considerable power to the monarchy. There is a measure of democracy in that all adults over 21 have a vote, but they only elect nine of the 30 Members of Parliament A further nine are chosen by the country's 30+ nobles while the twelve Cabinet Ministers, who sit in the House ex officio are nominated by the King. Tonga may' be small (it has fewer than 100 000 inhabitants) but it nonetheless attract: the interest of political scientists as one of the few remaining states with a hereditary ruler who wields substantial power.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Critics of the system view it as an anachronism, although their emphasis is on reform rather than revolutionary change. Defenders argue that the arrangement works well in a small, homogenous nation which values its unique culture and traditions (even if the constitution contains many 'British' elements). The latter also point, with some justification, to the attitude of the population. There are dissenting voices but the majority appears to be happy with the existing set-up, thereby lending it democratic legitimacy  -  at least indirectly.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">There may not, at present, be any overwhelming demand for constitutional reform but things can change. In particular, a people's view of their political system and how it might evolve is likely to be influenced by the prevailing economic conditions.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Economic outlook</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Tonga's economy is not exactly booming with the most recent estimates suggesting a 2% GDP drop in 1995-96. Several of the traditional problems faced by developing countries are to be found writ large here. The local market is not just small but tiny by global standards, and this makes it exceptionally difficult to achieve economies of scale. There is heavy demand for imported manufactured items and few viable export opportunities to balance the equation.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The education system compares favourably with those of other developing nations but the pool is so small that Tonga inevitably suffers from human resource shortages. This is exacerbated by a steady 'brain drain'. Qualified Tongans, who may already have experienced life abroad at college or university, are tempted by a range of attractions including higher salaries, better housing and more extensive career prospects. The skills shortage is particularly severe in the medical profession. In a recent issue of Matangi Tonga (the 'national news magazine'), it was reported that the country would only have one anaesthetist by 1997 - with a local doctor observing wryly that there was no need for one since the main hospital's only specialist surgeon had recently left to take up a post abroad.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Although it would be better for Tonga to retain its qualified people, the fact that the country 'exports' labour does have its positive side. Tongans have a strong sense of family and community, and overseas workers send significant amounts of money back home. This injection of 'foreign' funds boosts the local economy and reduces the overall balance of payments deficit.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Agriculture</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Agriculture is by far the most important economic sector, with most crops being grown for local consumption. The islands benefit from a fertile soil and a tropical climate, allowing the cultivation of a wide variety of fruit and vegetables. All land is vested in the Crown, with estates allocated to the nobles. By law, each adult male is also supposed to be allotted three hectares although there is not enough land to go round. Despite this difficulty, which means that some people do not receive their allocation, the result is that most Tongans are involved in farming. The advantage of the arrangement is that it guarantees a living for the bulk of the population even if their cash income is low. On the other hand, it is obviously a feudal system which favours the upper echelons of Tongan society. In addition, it tends to hinder the development of larger units which could benefit from economies of scale. While anxious to make farming more efficient (and export-oriented), the government currently has no plans to introduce land reform.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">In export terms, the main crop is squash (pumpkins). Production increased dramatically in the early 1990s when a market niche was identified in Japan and it soon became the country's biggest foreign exchange-earner. More recently, income has been depressed, with overproduction in 1994 leading to a drop in prices, and poor rainfall the following year reducing yields. The November export figures for the last three years (November is the month when squash deliveries peak) illustrate the extent of Tonga's reliance on this single product. In November 1993, the country's overall export income was T$15m - more than half of the annual total. Twelve months later, the figure had dropped to T$9m and last year, it fell below T$6m. When The Courier visited Tonga, the authorities were talking about limiting the amount of squash exported to Japan this year to 15 000 tonnes, in the hope of maintaining premium prices.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The government is also acutely aware of the risks of mono-dependence and is looking for other outlets for its agricultural produce. Demand for copra, Tonga's traditional export, has apparently been reviving, but the price has not been high enough to attract local farmers back into the market. Other crops sold abroad include vanilla, cocoa, coffee, black pepper and ginger.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">One farmer who is doing his bit in the quest for export diversification is Masao Soakai, a former general manager of the Copra Board. He is now the managing director of a company that specialises in the import and export of produce. This energetic 73 year-old gave us a guided tour of the plots he had rented. He cultivates an astonishing range of different crops which include potatoes (for Fiji), cassava, taro, yams, carrots, broccoli, cauliflowers, strawberries, bananas and capsicums. He also rears cattle and pigs (a Tongan tradition). Masao Soakai stresses the importance of rotation in maintaining yields and believes strongly in planting for the future.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Other sectors</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Wherever you happen to be in Tonga, the Pacific Ocean is never far away. Evidence of the country's maritime tradition can be found in accounts of the appropriately named William Mariner (see box article on this page). But while, in the past, Tongan vessels sailed far and wide, and the country has a huge exclusive economic zone (EEZ), the fishing industry is relatively undeveloped. The sector generates about 5% of GDP. A project sponsored jointly by the FAO and the UNDP revealed that there was considerable scope for expansion, both in the inshore and reef zones and in the deep sea area. The main species which could be exploited commercially are albacore, skipjack and yellowfin tuna. Tonga has received assistance to develop its fisheries from the USA and Japan, and the government has offered tax advantages in the hope of promoting investment, but there is still a long way to go before the country realises its full potential in this area. Hitherto, the country has not licensed foreign vessels to fish in its waters but there is talk of this policy changing.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Tourism could also generate a lot more income although it currently faces a number of infrastructural and practical constraints. The government is committed to expanding the sector but Mrs Papiloa Bloomlield Foliaki, the owner and manager of Nuku'alofa's third largest hotel (the 'Friendly Islander') feels that a lot more could be done. She pointed out to The Courier that a healthy tourist sector would provide employment as well as stimulating new business for food producers, builders and craft industries. She focused, in particular, on deficiencies in training and marketing, and suggested that some of the resources allocated to agriculture might be better spent in tackling these.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Tonga's natural assets make it a 'dream' location for visitors looking for a complete change of scene - particularly if they happen to be keen on sailing, snorkelling or scuba diving. The problem is that the country is so far off the beaten track that it is expensive to get to (some would see this as an advantage in deterring mass tourism). Nothing much can be done to change this but it does mean that they have to aim at the upper end of the market. This requires top quality accommodation  -  of which there is a distinct shortage at the moment. As regards marketing, Mrs Foliaki was hopeful that the recent formation of a hotel association would enable the Tongan tourist industry to raise its profile abroad. Despite her optimism - echoed by all those we spoke to in official circles - the latest figures for visitor arrivals show a downturn.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">In the manufacturing sector, the story is, sadly, one of long term decline. Clothing production ceased in 1994 and the output of leather items has been falling. There are very few industrial activities in which Tonga has a comparative advantage (whether actual, or potential) and this is something which is recognised locally. There may be some scope for adding value to agricultural products through processing but it is unlikely that industry will take off in a big way in the foreseeable future.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The sale of passports (see the interview with Prime Minister Baron Vaea) is an issue which attracted publicity - not all of it favourable - some years ago, when the government launched the TPPP (Tonga Protected Person's Passport). This was designed to be a travel document which did not confer the right of residence in the country. The authorities adopted the scheme with an eye firmly on Hong Kong, a British colony which is due to be transferred to China in 1997. Some passports were sold but the project never really took off as the immigration authorities of other countries refused to accept the document. Now there are suggestions that the idea may be revived, although this time involving normal passports.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The foregoing survey of Tonga's economy does not paint a particularly happy picture but it should be stressed that there is very little real poverty in the islands. In many ways, the informal economy is more important, and subsistence agriculture and fishing ensure that people do not go hungry. With their traditional family structures and strong attachment to the Christian faith, the Tongans have not yet encountered many of the social problems associated with more consumption-oriented societies. But to paraphrase a famous saying, 'no nation is an island' nowadays - even if it happens to be surrounded by water! In an era of increasing globalisation, the key question is how to manage change. Let us hope that the people of Tonga can find the right answer. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<I><P>&lt;&lt;TOC4&gt;&gt; Interview, Prime Minister Baron Vaea</P>
+</I><P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">'Constrained by our geography'</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">No-one can accuse Tonga's Prime Minister of being a starry-yed optimist. As the following interview reveals, Baron Vaea, who heads a twelve-member ministerial team, is refreshingly honest about the economic difficulties facing his small island country. The Courier interviewed him in July, at his office in Nuku'alofa.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">· You have suffered a GDP drop and a general slowdown of activity in recent years. What is the government doing to restore the situation ?</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY"> - It is true that the economy has been declining. The main cause is the excessive demand from the private sector for imports from New Zealand and Australia, combined with diminishing exports. Our exports fell when the price of copra dropped. Another problem is New Zealand's quarantine rules. New Zealand is very particular on quarantine against insects, notably fruit flies, which may damage their own export trade. We have endeavoured to balance this out by selling squash to Japan and indeed, it has been a saviour as far as our economy is concerned. Squash is something our farmers know how to grow. Of course, the market goes up and down. Recently, we made the mistake of over-producing and quite a lot of the crop could not be sold abroad. I think our farmers are now realising this, and that they have to plant according to the quota that we ourselves have imposed. Tourism is another important area although levels of room occupancy are very dependent</P>
+<P ALIGN="JUSTIFY">on the economic situation in other countries. Then there are passport sales.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">· Is this something you are still doing ?</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY"> - Yes, but it has been hit by technical difficulties. A number of Hong Kong Chinese bought our Tongan Protected Persons Passport (TPPP) in the hope that they could travel. The immigration authorities in other countries decided they would not accept the document so this source of income dried up. We have changed to national passports which people can use to travel. We are hoping to revive this in order to suit the conditions of the Hong Kong people.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">· Is this being done on the assumption that the people who purchase such a passport would not ultimately settle here ?</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY"> - Yes. The main reason people in Hong Kong want a passport is to keep open the option of leaving after the changeover.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">· Has this policy prompted any criticism from other countries ?</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY"> - No. The main problem is the Chinese themselves who are due to take over Hong Kong next year. It is possible that they will not recognise these passports. We are planning to have discussions with the Chinese on this.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">· Going back to the agricultural sector, are you not putting too many eggs in one basket in focusing so heavily on squash. What efforts are you making to diversify ?</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY"> - We have just signed a trade agreement with Fiji. They are such a close neighbour yet we have had virtually no trade with them. This should change with the agreement, to the benefit of our economy.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">· What products are we talking about here ?</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY"> - Mainly vegetables, particularly those that are favoured by the Indian community, such as chills and spices. A trade mission has just returned from Fiji where they picked up a number of orders. The representative of a group of growers also recently returned from Japan. He took a sample of dried pawpaw, a crop which is popular with the Japanese, and apparently received an excellent response. This is an area which is promising.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The key issue, however, is the amount of space available in the aeroplane. You can't ask everyone to grow pawpaw when the airline tells us that they can only take eight tonnes at a time. Only a limited number of farmers can be involved, so that we can continue to supply the tonnage that the airline can handle. We will encourage the rest of the farmers to concentrate on other products.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">· What is your policy regarding foreign investment ? </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY"> - We encourage overseas investors to engage in activities that local people are not involved in. Land leases are available for anything they want to do which fits in with this policy.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Tonga has an extremely limited manufacturing sector and there appears to have been a long-term decline. What prospects are there for reversing this trend ?</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY"> - For many years, the policy of the government has been to encourage exports. We have had entrepreneurs here who have exported things like woollen garments, small boats, horse saddles and so on - but it didn't last. The sad fact is that hardy anything is exported from Tonga. The main reason is that we are constrained by our geography. We are so far away from the main markets. The raw materials have to be brought in and by the time the article is finished, there is no way that it can compete in price terms. This has always been our problem. We are always looking for new markets but it is not easy.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">A second limitation is the private sector in Tonga. This is weak in terms of technology, marketing and product quality.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">· What about further processing of local products - perhaps value-added agricultural activity ? </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY"> - Yes, this is something that we would hope to do, though the same kinds of problem arise. People don't set up the processing plant because they say there isn't enough local cultivation to make it worthwhile. And the farmers don't grow the crop because they say there is no market.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">· So it is 'chicken and egg' situation ?</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY"> - Yes. The result is that people only grow for home consumption.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">I should mention here that there are other resources we have yet to exploit, notably in our waters. We have reserved these for ourselves and do not allow foreign fishing vessels. So we are trying to recover resources from the sea.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">There is also the possibility of drilling for oil. Research ships operating in the Pacific have found a limited number of locations where it would be worth looking for oil reserves and two of them are in our waters. We have been publicising this with a view to encouraging further exploration.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">· This would presumably involve drilling licences for oil multinationals.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY"> - Yes. Some companies have done this in the past although only on a small scale. The answer we got from the oil companies is that they are interested in exploitation - but not now because of the low oil price. When the price goes up, I think we may attract interest again but that is clearly only a long term possibility.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">· A lot of young Tongans leave the islands to work overseas. What is the explanation for this ?</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY"> - It is true that a high percentage of our population migrates. These are people in search of a better life, who seek to reap the benefits of their abilities by working overseas. They can have a nice house and get a good education for their children.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">I should stress that we have a good education system here but there is a heavy emphasis on gaining qualifications in order to get into the civil service. Where we are lacking is in the field of technical education. We have some facilities of course - an Institute of Science and Technology and a Marine Institute to train people to go to sea. This is very much in its infancy and we hope it will help for the future. But even some who have gone through this system end up looking for jobs overseas.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">· Turning to political issues, you have a monarchy here which is still very powerful. Do you anticipate any changes in the system ?</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY"> - There has been some public pressure for change. I don't think people want a radical upheaval but there is a feeling in certain quarters that the present system could be improved upon. As you probably know, Parliament has nine members elected by the people and a further nine selected by the 28 nobles from among their own number. The third component is the government -  12 ministers who are appointed by the King. It has been suggested that qualified people who don't presently sit in Parliament should be there to help deal with the economy. One idea is to change the Constitution so that whole population elects 30 members. The King would then choose his ministers from these 30.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">· Has this idea made any headway ?</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY"> -  No, not so far. We are maintaining the old system. The proposal has been aired but it hasn't been passed in the House. There are a lot of people, I think, who prefer the present system because they feel the monarchy works for the benefit of all the people. Would a new team necessarily stick to this principle? There must be a danger that they would tend to favour just one section of the population.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">· Can you comment, finally, on Tonga' relations with its partners in development cooperation ?</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY"> - As you know, we have good relations with the EU through the Lom&eacute; Convention. We also have strong bilateral links with Australia and New Zealand which have been giving us assistance. But I think we have to face up to the fact that the aid cannot continue. The UK, for example, used to provide us with our judges. That has been taken over by Australia and New Zealand -  but for how long ? I think it is bound to be phased out.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">So we will continue to have relations with our partners, but we need to recognise that they are concentrating their efforts now and adapt accordingly. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<I><P>&lt;&lt;TOC4&gt;&gt; Profile</P>
+</I><P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">General information</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Area: 669 km². Tonga has about 170 small islands and four main island groups (Tongatapu, Ha'apai, Vava'u and the Niuas). It has an Exclusive Economic Zone of approximately 700 000 km,). </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Capital: Nuku'alofa (situated on Tongatapu) </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Population: 99 000 (1994 census) </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Population density: 149 per kilometre² </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Life expectancy at birth (1992): 68 years Official languages: Tongan and English Currency: Pa'anga (T$) made up of 100 seniti. The currency is pegged to the Australian dollar. In September 1996, 1 ECU was worth T$ 1.57 (US$1 T$ 1.22)</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&lt;&lt;I&gt;&gt; p32.png Tonga</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">Polities</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">System of government: Constitutional monarchy based on the Constitution promulgated in 1875. Considerable powers remain vested in the King. The Parliament has 31 members  -  the Speaker, 12 ministers (including the Governors of Vava'u and Ha'apai) who are appointed by the King, 9 nobles chosen by the 33 members of the nobility and 9 People's Representatives elected by universal suffrage. There are no political parties although there has been talk of setting up a 'people's Party'. The twelve cabinet ministers hold office until they reach retirement age.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Head of State: King Taufa'ahau Tupou IV</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Prime Minister: Baron Vaea of Houma</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Economy (estimated 1995 figures unless otherwise stated) </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Annual GDP per capita: approx US $1900</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">GDP growth rate: -2% (1995/96)</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Principal exports: squash, vanilla, manufactured goods and fish. In the early 1990s, squash accounted for more than half the country's total export income. In 1995, however, the harvest was affected by drought and exports dropped significantly.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Balance of payments: A trade deficit of US $38.8m (exports  -  US $18.3m, imports  -  US $57.1 m). The current account deficit is much smaller thanks to 'invisible' earnings, notably from tourism and remittances from Tongans living overseas. Inflation rate (April 1995): 4.5%. Total external debt: T$ 44m (1993)</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Sources: Tonga in Profile (on the Internet -  http: 11l www. netstorage. com/kami/ tonga) Economic Intelligence Unit Country Report 1996. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<I><P>&lt;&lt;TOC4&gt;&gt; Interview with peoples representative, Teisina Fuko </P>
+</I><P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">'There is much more political awareness'</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">People's representative, Teisina Fuko offers an alternative view</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">While Tonga has no political parties, and the main levers of power remain in the hands of the monarch, it would be a mistake to conclude that there is no questioning of the status quo in this small Pacific kingdom. As The Courier discovered on its recent visit, Tongans are happy to speak openly about their political system and to criticise (or praise) aspects of it me local media may not be particularly extensive but it nonetheless allowe for different viewpoints to be expressed, including criticism of the authorities. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Those who advocate political reforms in Tonga face something of an uphill struggle. There is no overwhelming demand for change and although the lever of popular support for the current system is not easy to judge, there appears to be widespread acquiescence  -  which effectively amounts to the same thing.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">In recent years, the focus of 'opposition' has tended to be within the ranks of the people's representatives who sit in Parliament We spoke to one of these elected members, Teisina Fuko, who comes from the Ha'apai island group and began by asking how democratic the thought the system was.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY"> - I would say about 50%. Up until the 1970s, the system was very traditional but we now seem to be westernising quite quickly. People are returning from overseas with different ideas and this is having an impact on the way we are governed.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">· Do you think you will ultimately have a Parliament whose members are all elected by universal franchise ?</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY"> - I would say it is more certain now than ever before. There is much more political awareness. We see it in the schools, where children are being taught to think independently. There are also the new economic trends -  commercialisation and the focus on foreign earnings which imply the need for modernisation.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">· You sound quite enthusiastic about the 'westernisation' process. Are you not concerned about the possible negative aspects in terms of the survival of your traditional culture ?</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY"> - I think we have to strike a balance. We mustn't go to extremes. Our culture and traditions are important but there are new things we need to take on board and some old habits we should drop. Take business opportunities: we have to be more democratic in this area. If one group has all the power then they will tend to favour their friends which isn't necessarily efficient. What it boils down to is a lack of checks and balances.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Given the present economic difficulties, I also think we need to move quite quickly. I recently wrote an article arguing that the King should transfer his power to appoint ministers to the people. Ministers should be elected so that they can be accountable to the taxpayer. We are a close-knit family here and there is no question of getting rid of the monarchy. But we need to sit down and hammer out a compromise which will allow us to improve our economy and make it more competitive.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Let me give you a practical example. Defence is now third on our list of priorities. That doesn't make sense to me. We would be better spending the money on economic development. We also need to boost the private sector so it can create jobs, instead of tying its hands. At present, 50% of our revenue goes on paying civil servants. What for 7 It may create employment, but it is not productive. So the government has to be minimised. Having said this, there are some positive signs. I am glad, for example, to see new blood being brought into the ministerial team.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">· Parliament is currently composed of three groups - twelve ministers, nine nobles and nine people's representatives. On paper, that suggests that no group can dominate ?</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">- Yes, but the ministers and nobles often work together and we are  outvoted. It is difficult to imagine the nobles saying 'no' to the King although, to be fair, they do sometimes abstain and some of them recognise the need for certain reforms to the system.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">· Turning to the economy, which areas do you think offer the best development prospects ?</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">-  Tonga's potential lies in fishing. We are an island nation that has always depended on the resources of the sea and we have the necessary labour force. What the people need is the know-how  -  advanced technologies to develop this sector. We also have to set up credit programmes so that people can invest in boats and equipment. I believe we should spend a lot more on fishing.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Unfortunately the government does not take the same view. It has put a lot of resources into small industries, airlines and so on. Yet the reality is that these sectors are in decline. Manufacturing has fallen and so have agricultural exports. Fishing is the only sector that is expanding.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">· What about the prospects for agriculture ?</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY"> - I think we have reached the limit in this sector. There is very little scope for expansion. I also believe we should be concentrating on what we can produce to use locally. There is very little more we can do in terms of commercial exploitation. Tonga is somewhat overcrowded and we cannot use too many chemicals because the water table is so low.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">· One local issue, which presumably has economic implications, concerns the possible expulsion of foreigners who have been here for a certain amount of time. Apparently, the decision has been taken not to renew certain residence permits. What is your view on this ?</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY"> - I think Tonga should encourage skilled people who are here to stay. We should use make use of their skills, particularly where they have expertise that is lacking locally. At the same time, there are some people here who just came for a visit and ended up staying without doing anything very productive. There are also a number who came after the coup in Fiji and I think we should give them some leeway.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">On the whole, I don't think it is a big problem. Tonga has traditionally been very liberal in the application of its immigration law. We have never been colonised so we tend not to have a suspicion of foreigners. And whatever we do must be in accordance with the law.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">· Could you sum up your vision for the future ?</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY"> -  You only need to look around you to see that we have a youthful population here: a lot of young people who need to be catered for. We are investing heavily in education which I think is good but we need to do more to adapt to the changing world. We were peaceful in the past because most Tongans were on roughly the same level in terms of wealth. Now the poor are getting poorer while the rich get richer. This could lead to an increase in social tensions. With a more democratic system, we should be able to close the gap and work for a peaceful and more prosperous future. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<I><P>&lt;&lt;TOC4&gt;&gt; Seeking business overseas</P>
+</I><P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">New Minister outlines economic strategy</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">If the policy of appointing Ministers for life - or at least until retirement age - is maintained, then Dr Giulio Masasso Tu'ikolongahau Paunga can look forward to a long career in the Tonga Cabinet. At just 32, he has recently been been given the job of Minister for Labour, Commerce and Industries (with responsibility also for tourism). He may be relatively young, but the new minister has impressive academic credentials. He took a master's degree in Japan (in Japanese) and as we soon discovered, he has some new ideas about how to achieve economic development in his country.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Dr Masasso's portfolio covers a wide range of economic activities and we began by asking what he thought the main focus of his work would be. He identified three areas  -  agriculture, which is the single most important sector; fisheries which has potential for growth; and tourism. He would also like to see more manufacturing, particularly for export, but acknowledged that the current prospects in this area were very limited.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Looking first at agricultural production for export, we noted that a significant change had taken place over the last decade. Coconut-related products had been largely replaced by squash, a 'gap' in the Japanese market having been identified when other sources of supply were not available. Tonga may have been the first to spot the opportunity but was there not a danger that other countries might 'muscle in'? The government was 'very aware of this danger', said the Minister and was trying very hard to diversify its export products. He mentioned vanilla, papaya, beans and, in particular, carrots. The last-mentioned crop grows well in the islands and there is apparently a growing taste for carrot juice in Japan. A list of products with export potential, which could be grown successfully in Tonga, had been drawn up in cooperation with the Ministry of Agriculture, and Dr Masasso's department would be actively seeking new business overseas.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The government is obviously interested in developing trade with Japan and other countries in Asia, but the Minister felt that New Zealand and Australia were likely to remain the principal markets for Tongan farm products in the future. He was looking forward to easier access to New Zealand once new quarantine facilities had been set up at the international airport on Tongatapu. This, he said, should allow for a larger throughput of export crops.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Efficiency, of course, is the key to winning and keeping overseas customers. With this in mind, our discussion turned to the land tenure system. The allocation (at least in theory) of parcels of land to all male Tongans discourages the development of larger farms or plantations. Was this the most effective way of exploiting the country's fertile lands? Dr Masasso acknowledged that the system hampered efficiency but stressed that the question was a very sensitive one. The right to cultivate a plot of land is deeply rooted in Tongan culture, and radical changes to the property laws are not on the agenda. As the Minister put it; 'We are trying to maximise our efficiency under the present system of land tenure.'</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Turning to tourism, Dr Masasso observed that 'this has been the most stable industry over the past ten years,' bringing an average of T$ 12 million into the country every year. In looking at possible growth, however, he stressed the need to take account of the environmental and cultural impact. 'Tonga is a very small country, and it would not be right to build too many hotels and related facilities. It might be possible, but the long-term effects would be a little too much for the country.' Dr Masasso said he favoured tourism which has 'e closer relationship with people -  a cultural exchange, targeting people who really wish to understand our country.'</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Fishing is a sector which appears to have huge potential given the size of Tonga's exclusive economic zone. Dr Masasso explained how Japanese assistance was being used in a boat building scheme designed to produce vessels that local people could afford. He also spoke enthusiastically of the research that had been carried out to determine the nature and size of the fish stocks. He recognised, however, that while most of Tonga's fishing was inshore, there was scope for a great deal more revenue from deep-sea fishing. In this connection, negotiations were underway with the United States, Taiwan and Japan, to allow vessels from these nations to fish in Tongan waters. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The conversation then moved on to the more general issue of entrepreneurship and the role of the state in the economy. The Minister indicated that the government believed in privatisation but stressed that this was not simply 'because other countries are doing ft.' The main issue at this stage, he said, was to create a sufficiently large pool of well-trained people to take over activities currently run by the authorities. 'The government wishes it didn't need to get involved but we are a small developing nation, and to get things started, you need capital and know-how  - which locals sometimes don't have access to.' In these circumstances, the state had to activate projects which could later be privatised once the necessary skills had been built up. Another 'major strategy' was to develop a much closer relationship between the Ministry and the private sector.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">This led us into a discussion about Tonga's attitude to foreign investors who might also be in a position to supply capital and know-how. The authorities had recently threatened that a number of residence permits would not be renewed. Was this not a disincentive to potential overseas investors ? Dr Masasso was keen to offer clarification. 'The media makes it look as if Tonga doesn't like investors but they have misinterpeted the situation. He insisted; 'we want the foreign investment here and are encouraging it in those areas where locals cannot get involved.' Defending the actions of the immigration authorities, the Minister stressed that what they were doing was normal practice. 'Those who stay here illegally and do not extend their visa have to be deported.' The action, he argued, was not directed against foreign investors and indeed, the latter should be encouraged by the government's commitment to upholding the law.' </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<I><P>&lt;&lt;TOC4&gt;&gt; Tonga-EU cooperation</P>
+</I><P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Developing the Vava'u islands</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">by Myfanwy van de Velde</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">EC-Tonga cooperation began in 1975 with the first Lom&eacute; Convention, soon after Tonga gained full independence in 1970. Grant aid totalling ECU 19.8m (Lom&eacute; I - Lom&eacute; IV) has been allocated to the country during its 20-year membership of the Convention.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Under Lom&eacute; I, funds were directed principally towards two main projects: the construction of the wharf at Neiafu, Vava'u, and funding for the Ministry of Works to procure road maintenance equipment and build schools, rural health centres and small wharves at Ha'apai and Vava'u. Remaining funds were used to finance studies involving dredging, trade promotion and designs for Vava'u and Faua fisheries harbours. The EIB also financed a line of credit of ECU 130 000, under Lom&eacute; I, to the Tonga Development Bank.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Lom&eacute; II funds focused on the fisheries sector, and on initiating works relating to the upgrading of the Vava'u airport. There were also projects in the fisheries sector, aimed at encouraging fishermen to undertake commercial fishing to meet local demand. To this end, the Faua Fisheries Harbour for small boats was built, and marketing and cold storage facilities were provided.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">By the time Lom&eacute; III funds came on stream, Tonga had adopted a regional development approach with regard to its various island groups. The aim was to have a coherent development programme taking account of the specific constraints and potential of each. The Vava'u group of islands became identified as the focal area for the use of EC assistance, and Lom&eacute; III resources (ECU 6.5m in grants and ECU 0.5m in the form of risk capital to be managed by the EIB) as well as Lom&eacute; IV funds (ECU 6m and ECU 1 m respectively) have duly focused on its development.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Located in the north of the Kingdom, Vava'u is the second group of islands both in terms of population (16 000) and land area. With an abundance of natural resources, the group is thought to have greater potential for agriculture and tourism than other parts of the Kingdom. However, this potential was largely untapped at the time Lom&eacute; III was initiated. This was due to a variety of constraining factors including relatively low productivity, undeveloped marketing infrastructures, substantial import levels and poor distribution of utilities and other public services. One particular constraint preventing the development of tourism was limited access caused by a lack of transport infrastructures.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Two main projects aimed at addressing these problems have been implemented. The first, costing ECU 1.24m, involved completing the upgrading of the local airport at Lupepau'u (begun under Lom&eacute; II). In addition to runway improvements, a new terminal building was provided, complete with safety and navigational equipment. Passengers began using the new facilities in early 1995. The second project, entitled the 'Vava'u Development Programme', was allocated the sum of ECU 5m. This money is being used to pay for a series of activities including road upgrading, the provision of photovoltaic equipment for household energy needs and the supply of equipment for vocational training colleges. New buildings being funded include health clinics, a market and an agricultural quarantine building. The funds also cover the cost of establishing the Vava'u Development Unit as the monitoring and implementing agency for the programme.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The Programme continues under Lom&eacute; IV, with about 85% of programmable resources for Tonga (approximately ECU 5m) set aside for activities in the focal area. Funds will be directed towards developing the Neiafu urban area, in recognition of the need to upgrade access and services in the commercial centre of Vava'u. The projects envisaged include upgrading the town centre and urban roads, port improvements, and measures to increase the capacity and improve the distribution of piped and rain water to households. In addition, a multi-annual micro-projects programme will lead to the construction of jetties on the inhabited outer islands of Vava'u, thereby improving access to Neiafu which is the main centre of the archipelago.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">In addition to the above grant aid, Tonga has received funds in the form of Stabex transfers for losses in export earnings in respect of coconut products, bananas and vanilla. It also received emergency aid in 1977, following an earthquake, and in 1982 following Hurricane Isaac.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">EIB interventions have contributed to the share capital of the Tonga Development Bank and have increased the Bank's lending capacity to small and medium-sized enterprises. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<I><P>&lt;&lt;TOC4&gt;&gt; Switching on the Iights</P>
+</I><P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Uelingatoni Tevita Vaea (known as 'T' to his friends), proved to be a mine of information for The Courier, when we visited the Vava'u island group in northern Tonga recently. 'T' is a Tongan engineer who returned to his native land from Australia to work as assistant project manager in the Vava'u Development Unit. His help was particularly useful during the highlight of our visit - a traditional celebratory feast laid on by the villagers of Nuapapu. This is one of Vava'u's inhabited outer islands and the celebration was staged to mark the installation of solar powered lighting, courtesy of Lom&eacute; Convention funds.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Nuapapu is one of a number of outlying villages to receive solar installations under the Vava'u Development Programme. In all, some 350 homes have been wired up. Units attached to individual buildings collect the power and convert it into electricity which is stored in a battery. When night falls, the lights can then be switched on. Although the bulk of the installation costs are covered by the project, each participating household is required to pay a lump sum to have a unit fitted. They are also contracted to pay a modest amount each month towards maintenance of the system.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">It may all seem rather prosaic to those of us accustomed to electrical power at the flick of a switch, but for the people of the villages in the Vava'u group, the project is little short of revolutionary. For centuries, their daily rhythm has been governed largely by the rising and setting of the sun. The only 'artificial' light available after darkness came from fuel-burning (and more recently, battery) torches or lamps  - enough perhaps to reveal a path or highlight the position of an object, but certainly not to read or do intricate work with one's hands.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The formal 'switching on' ceremony was performed by the Dutch Ambassador, Mr van Thessen and Jonathan Rodwell, who is the European Commission's resident advisor in Tonga. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">This was preceded by a courtesy visit to the village chief and the above-mentioned feast, which gave the European visitors an authentic and memorable taste of traditional Tongan hospitality.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The food was brought from all quarters of the village on long rectangular trays covered with leaves. Each was laden with food.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The fare was predominantly local: the famous roast pigs featured prominently along with fish, chicken, bananas, coconuts and a variety of root and tuber vegetables.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">There were also some 'imported' items: the corned beef which is so popular here, some packets of crisps to add colour to the guest 'table' and boiled sweets woven into garlands.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The trays were laid end to end, stretching perhaps 20 metres and woven mats were placed all around. Having received our garlands of flowers, we were invited to sit down.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The feast was interspersed by various speeches and 'T' helped out with a translation and explanation of the proceedings. We began with a prayer in Tongan, delivered by the local minister. This was followed by a speech of welcome and thanks by the matapule (spokesman) of the village chief.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">High ranking people in Tonga always have a matapule to speak on their behalf on such occasions. Ambassador van Thessen and Mr Rodwell then replied on behalf of the guests, (in English, with consecutive translation provided).</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">They expressed thanks to the people of Nuapapu for their hospitality and wished them success with their new electric lighting. There was then a short discourse by the District Officer followed by a closing prayer.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">References to all this speechmaking could leave a false impression that this was a formal and stilted affair.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">In fact the reverse was very much the case: the mood was relaxed throughout and there is no doubt that the villagers know how to enjoy themselves. Music was supplied by a group of men playing a variety of instruments and the women joined in the festivities with what appeared to be spontaneous bursts of dancing.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">There were also special solo dances performed by two young ladies whose bodies had been smeared with coconut oil.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">As tradition dictates, once their performances (involving highly expressive hand and finger movements) were complete, the audience expressed their appreciation by slapping banknotes on the oily exposed surfaces of the dancers' bodies.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The light was fading as the feast ended and we moved to the brief 'lighting up' ceremony, carried out to the accompaniment of applause.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The guests (including the staff of the Vava'u Development Unit who have guided the project through its various stages) then took their leave of this hospitable community and set off by boat on the return journey to Neiafu. As the vessel drew away from the shore, we were able to look up and see, for the first time, the twinkling lights of Nuapapu. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<B><P ALIGN="CENTER">&lt;&lt;TOC2&gt;&gt; Dossier</P>
+</B><P ALIGN="JUSTIFY"></P>
+<B><P>&lt;&lt;TOC3&gt;&gt; Habitat</P>
+</B><P ALIGN="JUSTIFY"></P>
+<I><P>&lt;&lt;TOC4&gt;&gt; Livable cities and rural rights</P>
+</I><P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">(Dossier coordinated by Debra Percival and  Claude Smets)</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The United Nations Conference, Habitat 11, on human settlements (Istanbul, June 3-14 1996) exposed the Herculean task of addressing the problems of ever-growing cities and called for 'shelter for all.' The special contribution of civil society in making cities more liveable was acknowledged at the conference - but the big question is, who will foot the bill ? The meeting also spoke of improving dwellings in rural areas to keep people on the land and halt the mass exodus to the cities. But the right to remain and prosper from one's habitat can be at odds with outside pressures for environmental conservation. The dossier looks at some of the issues raised by the conference, and the wider significance of 'Habitat II' </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The second UN gathering on the theme of 'habitat', staged two decades after the first conference in Vancouver, took place against a backdrop of rapid and alarming urban growth. In 1900, one person in ten lived in a city. By 1948, the ratio was three in ten and by the year 2000 half the world's population are expected to be urban dwellers. 25 years after that, the figure is expected to have climbed to 60%. Africa is the region that currently has the highest rate of urban growth. In 1950, it had only one city with a population of one million. By the end of this decade there could be 60 cities of this size, according to UN figures.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The focus on human settlements and liveable cities inevitably meant that Habitat II covered some of the same ground as other UN conferences convened during the 1990s to explore the big issues facing mankind: the 1992 'Earth Summit' on environmental matters in Rio de Janeiro, the 1994 Population Conference in Cairo, the 1995 Social Summit in Copenhagen and the 1995 Women's Conference in Beijing. Issues common to all the agendas included rapid population growth, environmental degradation, access to clean water, poor sanitation, lack of infrastructures, and women's issues.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The rallying calls of Habitat II, set out in the Conference's conclusions, were 'shelter for all' and 'sustainable human settlements in an urbanising world.' The Nairobi-based Centre for Human Settlements is to be the focus for the follow-up. But as delegates dispersed, one of the pressing questions was where the money will come from to meet the host of agreed objectives -  which include clean water with improved technology, conservation and protection of the environment, and better health and education. In this dossier, European Commission officials from the Development Directorate General, who attended the conference, reflect on Istanbul and its likely followup.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Whereas in the past, cities were associated with economic development, innovation and the diffusion of new ideas, nowadays they conjure up the vision of urban poverty, environmental degradation, poor sanitation and a host of health hazards. Urbanisation is the direct consequence of rapid population growth, according to the 1993 Human Development Report. In 1965, agriculture provided 77% of employment in developing countries and represented more than 41 % of Gross Domestic Product. By 1985, this sector was contributing a lot less to GDP but was still providing 72% of all employment. So a large number of people continue to depend on agriculture although its share of the global economy is declining. In these circumstances, it not surprising that many of the world's poorest people are migrating to cities - the annual estimate is 20-30 million.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The dossier looks, in particular, at the environmental cost of rampant urbanisation and at the problems of city living for more vulnerable groups such as women. They are often among the poorest urban dwellers and can fall victim to exploitation and crime.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Paradoxically, poor people in cities are becoming even poorer as economies improve. Additional pressures on these marginalised groups living in cities are neatly summed up by Jeremy Seabrook, author of 'In the Cities of the South.' In a recent article for Gemini news agency: 'Tougher Struggle for Survival in the Concrete Jungle,' he writes; 'As the pace of development quickens, with high economic growth and increased migration to urban areas, land price in most big cities have soared. Poor people are being increasingly removed from their hoary" - by mysterious fires, explosions and 'accidents'. Meanwhile, the urban poor's ability to mobilise and achieve has been used against them. The capacity of people to create homes and secure local communities has been used as a justification for the withdrawal of government services.'</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">He continues: 'As inequalities become more glaring, enclaves of prosperity are sealed off from the slums by checkpoints, guards and fences - like frontiers to another country. Despite this, people are still flocking to the city  -  often refugees from intensifying, industrialised agriculture and.. megaprojects in the countryside...' Mr Seabrook points out that without decent jobs, they fall prey to sub-contractors, who exploit them, offering them low pay and demanding that they work long hours.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Civil society</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">In the cities of many developing nations, 'civil society' is taking a lead, with projects to bridge the gap between the 'haves' end the 'have note'. Numerous participants at the Istanbul conference applauded the urban programmes undertaken by various elements of civil society, which include NGOs, community groups and individuals. Their significance was recognised in Istanbul, where their voice came through loud and clear. Nigerian journalist, Paul Okunlola, writing in this dossier notes a move towards 'bottom up' projects in Lagos as a result of the tough times.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Agostinho Jardim Gon&ccedil;alves, the President of the NGO-EU Liaison Committee, was particularly pleased at the input of civil society to the conference's committees and conclusions. The debate, he said, had not just been about the macroeconomic aspects. Instead, it had come 'within the reach of the populations themselves.' The people, he argued, were both victims of the anomalies of inhumane settlement and the key players in efforts to construct a humane, dignified habitat.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Jeremy Seabrook describes some of the inspiring international initiatives undertaken by civil society. Examples include the Society for the Promotion of Area Resource Centres (SPARC) in Bombay, which works with pavement dwellers; the Association of Basic Needs (ARBAN), and 'Health for All' in Dhaka; the Eddie Guazon Foundation in Manila, which seeks to protect the poor against private interests; and the Foundation for Women, which is trying to tackle the trafficking of girls for Bangkok's brothels. But Mr Seabrook also warns against overestimating the strengths of popular organisation. As he points out: 'They require an enabling and positive framework, which the free market can never provide. Government intervention, of a more benign and positive kind than hitherto, is vital if people are to help themselves. As it is, too often they are forced to struggle against the people elected to govern them.'</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The chair of the Habitat Conference, Wally N'Dow, emphasised local solutions. The conference, he said, 'recognised the changing global patterns of life' and that solutions must be found at the local level. 'National governments and international agencies', he argued, were not in a position to solve massive urban problems or to pay to put them right.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">There were a number of donor pledges at the conference. The European Union countries, for example, reiterated their long-standing commitment to provide 0.7% of GNP for development by the year 2000  -  though many of the 15 member states are still well short of this target.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">One scheme which has attracted the particular interest of donors is South Africa's Reconstruction and Development Programme (RDP). To a considerable extent, the success of President Mandela's government is likely to be judged on the success of this programme. It aims, among other things, to improve health, education, housing and sanitation and as such, it mirrors many of the 'Habitat II' goals. Launched in 1994, it is the centrepiece of the South African government's efforts to create a more democratic, prosperous, non-racial and non-sexist society. In the dossier, we look at the RDP's objectives, how it is faring and what sort of support the EU is giving.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Rural rights</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Beyond the city, the dossier looks at what is happening to some rural dwellers who have not taken flight to the city. Although, largely focused on the city, Habitat II acknowledged the importance of urban and rural linkages in its conclusions: 'Rural and urban settlements are interdependent... governments must work to extend adequate infrastructure and opportunities to rural areas to increase their attractiveness and thereby minimise... migration.' There was mention too of the need for more jobs and housing for rural areas.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">But in some rural areas, the inhabitants have found themselves in dispute with conservationists. The latter seek to protect wildlife and the rural habitat by setting up national parks - a solution which is not necessarily in the interests of local people struggling to maintain their livelihood. We take a look at such dilemmas and the possible solutions being developed so that rural dwellers can continue to make the most of their habitat. This rural struggle, where solutions are also being called for at a local level, is not unlike the battle being waged for a better quality of life in the cities. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<I><P>&lt;&lt;TOC4&gt;&gt; Towards a global concept of urban development - an interview with Daby Diagne</P>
+</I><P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Deputy mayor of the city of Louga, Daby Diagne is also President of the Finance Committee of Senegal's National Assembly, General Secretary of the Association of Mayors of Senegal and President of the World Federation of United Cities. He is the ACP-EU Joint Assembly's General Rapporteur on urban development and The Courier had the opportunity to interview him in September at the Assembly's meeting in Luxembourg.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">· You have just submitted an initial report on urban development to the Joint Assembly. In it, you recommend that the Community adopt a specific and consistent global policy in this field, notwithstanding the fact that successive Lom&eacute; Conventions have contained a number of significant provisions relating to the subject. What is the reasoning behind your recommendation ?</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY"> - There are several reasons. First, there is the fact that, in the past, cities were often viewed solely in terms of infrastructures and sectors. Experience shows that this approach is not effective. Specialists are increasingly opting for a more global 'city' concept. The Commission must therefore adapt itself to the new situation. It is true that it has financed infrastructures and launched health and clean-up programmes, but the problem is that this has been done in a somewhat unsystematic way without being linked to long-term regional development or a zonal policy. There is now an increasing need for an integrated regional development approach. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">· Do you think ACP countries are aware of the importance of cities ?</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">That's another question altogether. Obviously, the ACP countries are in the process of changing their views on this subject and a number have appointed ministers to look after urban affairs. The reality of city life has to be taken into account. The rate of urban growth in the ACPs far exceeds that in other parts of the world and it is in the towns and cities that one sees the most glaring instances of poverty and under-development. People have therefore been forced to take the 'city' phenomenon into account in the ACP countries.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">· The political will must exist for a policy to be successful. Do the ACP countries have a genuine will to implement an urban policy ?</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY"> - I don't think it is possible to speak of a uniform trend in all ACP states. However, in certain regions - for example in West Africa, which I know well - a municipal culture is beginning to take shape. There is a growing political will, which is illustrated by the discussions on decentralisation, and people are increasingly recognising that central government cannot do everything by itself. One can find regional development and planning policies designed to create the fabric of mediumsized cities. Not everyone has them but it is something we are seeing more and more of.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">· ACP countries face complex challenges and there are people who say that the actions of the European Community are too dispersed owing to the number of sectors it is involved in. Doesn't your recommendation simply add to this problem ?</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY"> - On the contrary. I regard my recommendation as being pro-integration and therefore pro-globalisation  - which is not the complete opposite of a sectoral, diversified approach. I believe it would allow the Union's activities in certain fields to be better interlinked. I am thinking here of water, health, clean-up operations and infrastructures  - all of which are major problems for society. Naturally, a more global concept will require greater dedication, and if there are additional resources, so much the better, but, in my view, the situation could be improved even with what we currently have available.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">· The rate of urbanisation in Africa is higher than elsewhere and the living conditions of city dwellers - particularly those in the shanty towns  -  are becoming increasingly difficult in terms of health, education, environment and so on. What, in your opinion, would be the optimum strategy for reversing the decline, at least in the short-term ?</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY"> - First of all, I think we have to make a distinction here. Let's take the actual rate of urbanisation. Contrary to what is generally thought, this is lower than in the rest of the world. In other words, Africa has fewer towns and cities than the rest of the world. It is the rate of growth in the urban population that is higher. Populations are becoming increasingly concentrated in the cities, with the drift of people from the countryside. In addition, the phenomenon is being fed by demographic trends. You ask me if there is anything we can do to halt this. There are actions that can be taken to restore some balance. For example, we could make investments in the rural environment to keep people in the countryside, and we could implement suitable agricultural policies.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">But we must not labour under too many illusions, because life in towns and cities will be an inevitable characteristic of the next century. Economists and urban planners have been considering the phenomenon for a long time now - perhaps 30 or 40 years. It is  something that cannot be halted, because it is a fact of civilisation. So, what should we do? Above all, we should devote our efforts to regional development, achieving a balanced distribution of human resources, and a more equitable exploitation of natural resources. Power has to be decentralised so that people do not abandon their roots but face up to local challenges. And we have to implement urban policies which are satisfactory in terms of investment, management and popular participation. In simple terms, urbanisation has to be managed. We cannot hope to reverse the trend overnight, particularly in the case of a continent like Africa where everything happens quickly. Africa is enormous and its population has not yet reached its maximum levels. We have to take all this into account.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">We must acknowledge that scientific progress and improvements in the field of health have contributed to population growth, and a reduction in mortality rates. This means that urban civilisation is a reality that we have to manage. There is a risk of uncontrolled growth in urban centres. When infrastructures are lacking, when there is no water, when hygiene cannot be guaranteed and when there is no work, a country's security is threatened.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">· You have mentioned democracy end the decentralisation of government This also requires adequate financial resources. Where do you think the ACP countries will find the money to implement decentralisation strategies ?</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY"> - Democracy involves a search for freedom - freedom of opinion and expression, independent of material or financial problems. The problem with decentralisation lies in administrative method. It is not purely a matter of money. In the first instance, it is a question of choosing the right approach. It has been demonstrated that without any extra resources, one can still act differently by delegating and decentralising. And success is much more likely because the people are involved in the process. Admittedly, it requires an internal reallocation of resources. A proportion of everything that was formerly centralised has to be allocated to development and to basic needs.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">To answer your question more directly, there is a great deal of talk of this alternative method of governing. It is inspiring new hope and a thirst for something better. It is even being viewed as an 'ideal' solution - which it cannot be entirely. However, by decentralising human and economic resources, and by allowing people to participate, hope can be inspired at local level. This should make for better administration and support, which is an improvement in itself. Of course, this may make people more demanding. Will it satisfy their requirements? As I have already said, internal resources will have to be reallocated, but resources must also come from outside. One cannot make an allout effort for decentralisation without doing something to improve international cooperation. This cooperation, however, must be adaptable, and the state must retain its pre-eminent position and its role as guarantor and arbiter. But in addition, local communities should have access to international cooperation either directly or indirectly through their organisations, municipal structures and so on.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">· In this context, what role do you see for international organisations - not just in terms of financial resources, but also of human resources ?</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY"> - I think what we now need to do is build up a pool of skills in each municipal area. The developed countries have experience in this field. We have to take their processes as a model without necessarily copying their experience. This is something which will be discussed. Secondly, in the context of relationships between towns and cities, I believe it is possible to make access to experts more flexible and that this can take place very quickly, with the provision of training and fairly basic technology transfers. General training is also extremely important. In order to build up a pool of skills in towns and cities, local government must form a dynamic, management-oriented team. The approach has to be one of business-like management and objectives have to be targeted using private-sector methods, although public-service requirements always have to be borne in mind. A great deal, therefore, can be done at international level, in terms of support for networks of associations and committees of locally elected representatives, enabling them to discuss matters.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">We could, for example, carry out a comparative study of legislation in a particular area, thereby gaining access to other types of experience. Internationally, aid can be given to associations to help them buy equipment and attain a degree of freedom of manoeuvre vis-&agrave;-vis the authorities. In the field of decentralised cooperation, the international community can help elected representatives to implement their projects through partnerships, conducting studies, and providing personnel. Cooperation is possible in all spheres -  implementation, management, financing and so on. I believe that a new type of cooperation will gradually come into being. It is not a question of creating 'white elephants', but rather small and medium-scale projects which are of genuine use to the population. And I am not talking here about acts of charity, such as the donation of medicines, but sustainable projects. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<I><P>&lt;&lt;TOC4&gt;&gt; Habitat II: taking stock</P>
+</I><P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">by Christian Cure'</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The future of towns and cities is not what it was. In the 20 years between the first United Nations conference on human settlements (1976) and Habitat II which took place in Istanbul in June 1996, the situation has changed a good deal. The significance of urbanisation  - and its irreversible nature -  are now acknowledged, as is the powerlessness of the authorities to deal single handedly with the complex phenomena which result The author of this article points out that civil society has suddenly broken into a field hitherto the preserve of official agencies and qualified experts, claiming a 'right to the city' based on research into more equitable development models.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Vancouver to Istanbul: two symbols for two eras</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Vancouver was the 1976 host of the first conference on human settlements organised by the United Nations. At that time, the UN was celebrating 30 years of existence and Vancouver, a model of urban development and modernity, provided inspiration for the developers and experts needed to plan the cities of the future. 'Appropriate technologies' heralded the possibility of mass-produced, cheap housing for everyone.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Twenty years later, the UN chose Istanbul as the host city for the Habitat II conference on human settlements, forcing us to face up to a quite different situation: uncontrollable urban growth (400 000 migrants arrive there every year), social and environmental problems, and intercultural and political tensions (amply illustrated by the Turkish politicians' inability to form a government at the very time the Conference was taking place). In brief, Istanbul presents us with the usual list of problems facing most of the world's major cities - and those of developing countries in particular.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Against this backdrop, the international community  -  180 countries, 500 local dignitaries, a few thousand professionals and even some ordinary citizens - came together from 3 to 14 June to discuss a 'settlement action plan'. This document, which had been in preparation for two years, contains 183 articles. It sets out a series of goals, principles and undertakings as well as providing an action plan for cities, the initial results of which should begin to be seen by the year 2001.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The preparatory committee selected two basic topics for discussion: securing adequate shelter for all, a basic but nonetheless controversial theme; and sustainable urban development The latter encompasses housing, demographic factors, infrastructure, services, the environment, transport, energy, social and economic development, the future of underprivileged groups and combating exclusion.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The cycle initiated at the Rio Earth Summit in 1992 (followed by the Copenhagen, Beijing and Cairo meetings) was continued by Habitat II. Two major handicaps had to be overcome - 'conference fatigue' (with the resulting fact that there were fewer delegates than anticipated) and ensuring that what had been accomplished at earlier conferences was not undermined. Given that the subject of the meeting was human settlements, it was inevitable that sensitive issues already debated at previous summits, relating to the environment and social aspects, would keep recurring.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Civil society as an active force</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">A number of conclusions arose from the official sessions (hearings, dialogues and various forums) which took place over the two weeks of the conference.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">First, Habitat II represented a recognition of the fact of urbanisation. In the past, there was a tendency on the part of the international community to play down, or even ignore, the phenomenon of urban growth and this was reflected in the meagre resources allocated to this area by donors. Today, the issue is better understood than it was 10 or 20 years ago, and it is acknowledged that the growth trend is unstoppable. Statistical studies and a set of 'urban indicators' drawn up for Habitat II confirm the scale of the problem. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Second, the Istanbul summit was a lesson in modesty. The obvious powerlessness of public authorities to deal single-handedly with the challenge of burgeoning towns and cities is recognised. The result was an understanding that a more pragmatic view is needed -  one which pays more attention to the complexities of urbanisation, to the wide variety of possible responses and, above all, to the multi-faceted nature of the players involved.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The Conference therefore became a genuine forum for debate. One of its most significant aspects was the emergence of 'civil society' as an active force. Hitherto, the field has largely been the preserve of official agencies and qualified experts. For the first time in a UN forum, local authorities, community leaders, private sector representatives and other dynamic forces in civil society were invited to give their views and take part in discussion groups. Whereas in the past, the debate was dominated by macroeconomic and technical questions, in Istanbul, the political and social aspects were given prominence as well.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The effect of this was to improve the quality of the debate. The outlines of a new relationship between governments and civil society (NGOs, ordinary citizens and popular urban groups) were defined - with the local authorities slotting in somewhere in the middle. And there was a particular focus on the question of dimension or scale: what should be the basis for urban democracy and citizenship. Both of these are seen as essential if one is to have successful and sustainable urban development policies.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">A right to the city?</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The first stage of the analysis is to look at urban life from a macroeconomic standpoint. Urban growth is determined by the evolution of the world economic system and, in particular, by the globalisation of markets. This has generated increased competition, including competition between cities themselves. Since the end of the 1980s, cities have been responsible for between 50% and 80% of the GDP of most countries. In other words, they represent more than mere links in the global economy; they are, in fact, pivotal points.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Hence the principles which broadly underpin the Habitat 11 programme. In fundamental terms, public policies must promote the capital, housing, property and employment markets, with a view to improving the efficiency of urban management (living conditions, infrastructures, services, environment, etc.). This is not just desirable in human terms but also essential if urban productivity is to be improved. Many decision-makers at the meeting agreed that privatisation of services, partnerships involving the authorities, the community and the private sector, and decentralisation were all part and parcel of a new standard for good local governance.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Representatives of 'social' interests, on the other hand, were successful in focusing the debate on fundamental rights and principles, including individual and social rights. Indeed, these issues dominated the Conference and gave rise to the most difficult negotiations.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">There were prolonged talks, for example, on the central issue of the right to a roof over one's head. The outcome was a commitment by governments to promote 'the full and progressive acceptance of the right to adequate shelter'. The NGOs had been hoping for a more clear-cut undertaking. Questions relating to the status of vulnerable groups, women's rights and their equal access to land, and protection against eviction, were also the subject of heated exchanges.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Perhaps the most important step forward, however, was the success of civil society representatives in sowing the seeds of a new idea - the 'right to the city'. This concept has been devised on the basis of research into more equitable and soundly-based development models to which local authorities are increasingly giving practical support. Thousands of individual experiences and issues were highlighted in Istanbul by NGOs and community groups. Thus, there is a mass of evidence that populations are capable of responding through local initiatives and of taking responsibility for improving their living and housing conditions. If this 'resource' is to be exploited to the full, urban politicians must develop a deeper understanding of the scale of micro-territories and local societies within cities. They also need to promote and coordinate their decision-making in a way which involves consulting and involving the local populations. In the modern era, this is the key to ensuring social cohesion.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Beyond Istanbul</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">There may have been a lot of new thinking on the basic principles, but there was no reference to financial undertakings in the Habitat 11 programme. On the latter issue, the international community was highly circumspect.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The World Bank took the initiative, announcing the launch of an 'urban compact', involving an additional $15 billion in loans for urban projects over the next five years. It also revealed that it would triple its aid to NGOs involved in the urban environment. Recent World Bank estimates suggest that just 0.2% to 0.5% of a country's GDP would need to be set aside for the poor to gain access to basic urban services.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">As regards monitoring, the NGOs and local authorities won the right to sit on the Human Settlements Committee which will be responsible for implementing the habitat programme.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The most important points to emerge from Istanbul, however, were that local authorities were given both formal recognition, and a major practical role - in keeping with their current responsibilities. The habitat programme is, in fact, a powerful call for decentralisation and increased local autonomy, its action plan being built on the implicit principles of 'subsidiarily' and 'proximity'. To a large extent, the successful implementation of the programme will depend on the mobilisation of municipal politicians and officials - and on the policies they adopt at local level. The agenda for cities in the 21 st century that was adopted at the Rio Summit must now be fleshed out and become the future reference for action by local authorities, NGOs and citizens' associations. Finally, the importance of decentralised cooperation and the role of local councils in international cooperation have been reconfirmed.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Local authorities and their international organisations decided to form a worldwide coordinating group to continue structured dialogue with the international community and to guarantee that the Istanbul resolutions are followed up.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Some people predicted that Habitat 11 would be 'the revenge of the cities'. To quote P. Maragall, chairman of the Committee of the Regions, the conference at least provided the opportunity to build, and to give a wider audience to 'the voice of the United Cities within the United Nations'. That itself is a major step forward. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<I><P>&lt;&lt;TOC4&gt;&gt; 'A house to call my own'</P>
+</I><P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Tackling violence against women</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">by Rosemary Okello</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The author of this article is a journalist with the Nairobi-based Women's Feature Service (WFS) She contends that the Habitat 11 conference skirted around some of the issues affecting women city dwellers in Africa, such es violence and sexual abuse. Improving their lives, she argues, starts with a roof over their heads</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The lofty ideals set during this year's UN Conference on Human Settlements in Istanbul meant little to African women like Catherine Kaberu. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">As she recalls the misery of living on the streets of Nairobi, she is just happy now to have a safe, secure room for her family. 'I thought by running away from home and coming to Nairobi, I would find a better life" says Ms Kaberu. Instead, the streets became her home and her life was defined by the fear of violence against her. Her two children were born during that difficult period, following rapes. She cannot identify their father. There are an estimated 30 000 street people in Nairobi and Catherine Kaberu says that all street women and girls are regularly abused.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">'Every day we had to look for a place to sleep and we bribed the watchmen to guard us.' Often it was the same watchmen, employed to guard office blocks in the city's central district, who took advantage of the women's desperate situation. Not even age could protect them says 63-year old Felista Nyambura, herself a veteran of the streets. 'I suffered all manner of humiliation,' she states, referring to ten years spent on the streets with her seven children. 'The watchmen would rape me if I refused to give in to them - after they had offered me a place to sleep for the night with my children. I am just so happy to be off the streets. I will never go back,' she states firmly.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The confidence of the two women comes from their new security as owners of simple one-roomed houses.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">'Having a house to call my own is the most important thing that ever happened to me,' says Ms Nyambura as she explains how she ended up on the street after the piece of land her husband left in their rural home was taken over by her in-laws.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The two women are part of a group of 114 who have benefited from the Urban Destitute Programme, a project of the African Housing Fund which is involved in participatory community development with the homeless women of Nairobi.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Catalina Trujillo, the 'Women in Development' coordinator for the Habitat conference stresses: 'If a woman's place is in the house, we had better make sure she owns it.' These sentiments were supported in Istanbul by the conference Secretary General, Wally N'Dow: He stated: 'By conviction, by analysis and even by instinct, women's rights to ownership and inheritance of property is right. If Habitat II... does not also contribute to social progress by addressing some of the issues like property rights for women, then it will have failed.' </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">For the women of-Africa in particular, the most important thing that should have come out of Istanbul was an affirmation of their right to own and inherit property, and to security.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">These issues affect most African women regardless of their status and they were presented to ministers concerned with shelter and settlements when they met in Johannesburg last year to prepare an African agenda for the Istanbul meeting.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Most African countries accept the theoretical premise that women must have access to land, credit and inheritance, and recognise that certain types of violence are targeted primarily at women. South Africa's President Mandela affirmed: 'When we talk about people-centred development, we should understand that the involvement of women is often the difference between success and failure.' Yet in reality, customary law and insensitivity to gender concerns continue to predominate. Unfortunately, when the African ministers adopted their declaration, the point on the "unencumbered access of women to credit and land ownership' appeared in only 20th place. And while forced evictions were highlighted in Istanbul, violence against women did not feature at all among the 'key priorities'.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Yet in parts of Africa these are major concerns affecting women every day. 'In South Africa, a women is raped every 83 seconds and in some areas, a girl can expect to be raped four times in her life,' says Emelda Boikanyo of the Johannesburg-based Women's Health Project. Idah Matou remembers how one Sunday morning in 1992, five men stormed into her shop in Alexandria township. They seized the day's earnings and anything else they could carry away before raping her 1 5-year old daughter. A few weeks earlier, they had called to demand protection money.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Violence in the home is also a growing problem. Mmatshilo Motsei, Director of Agisanang Domestic Abuse Prevention and Training, an NGO based in Alexandria, South Africa, says the problem is so pervasive, 'it must be raised as a national concern.' Habitat II turned a deaf ear on these women's concerns. This was not their forum. Shawna Tropp of the NGO Women's Caucus criticised those attending the conference who claimed that it was not about women but cities. 'Women live in cities,' she says and adds: 'By and large, human settlements are still very much seen in terms of bricks and mortar'. She calls for greater understanding of the role played by women, usually in an unpaid capacity, in the management of communities. 'Everything begins with having a house in a secure neighbourhood where the dignity of women is protected.'</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<I><P>&lt;&lt;TOC4&gt;&gt; Megacities</P>
+</I><P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The megacity personifies human misery for many in developing nations. As agglomerations proliferate in the twenty-first century, the United Nations Population Fund's 1996 report - The State of the World Population  -  considers how one might go about remedying the ills of city dwelling.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The UNFPA's figures for urban growth make worrying reading. Over half the world's people will live in cities within ten years (3.3 billion out of a total of 6.59 billion). Between 1970 and 2020, the urban population will have risen by more than two billion - and 93% of these will be in developing nations. These increases will add to the strain of an estimated 600 million people already living in urban areas of developing nations without the resources to meet their basic housing and health needs.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Back in 1950, New York was the only city with more than 10 million inhabitants. Today, there are 14 in this category. Tokyo, which is home to 26.5 million people, is the largest. And by 2015, many others are expected to join the megacity 'club'  -  Djakarta (Indonesia), Karachi (Pakistan), Dhaka (Bangladesh), Delhi (India), Tianjin (China), Manila (Philippines), Cairo (Egypt), Istanbul (Turkey), Rio de Janeiro (Brazil), Lahore (Pakistan), Hyderabad (India), Bangkok (Thailand), Lima (Peru), Teheran (Iran) and Kinshasa (Zaire).</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">While the majority of the world's people will be living in cities by 2005, it will take a little longer for the 50% threshold to be crossed in the less developed regions. However, this is expected to happen before 2015. Looking specifically at Africa, the current estimates reveal significant regional variations. In Southern Africa the rate of urbanisation is 48%. The figures for North, West, Central and East Africa are 45%, 36%, 33% and 21 % respectively.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Expanding populations are likely to add to the widely reported list of horrors emanating from cities that are bursting at their seams. Problems include the collapse of basic services such as water and waste management, escalating social conflict, millions of urban children open to labour exploitation, sexual exploitation, environmental degradation, traffic congestion and environmental hazards such as increased air pollution.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">On the other hand, the UNFPA report acknowledges that cities are also 'concentrations of human creativity and the highest form of social organisation'. It continues: 'Cities provide capital, labour and markets for entrepreneurs and innovators at all levels of economic activity'. Indeed, between 60% and 80% of developing countries' GNP is generated by their major conurbations. Social transformation occurs at a faster pace in urban areas. Thus, health indicators tend to be better, literacy is higher and there is more social mobility. And there are more opportunities for women. The city presents fewer obstacles for women's education and female city dwellers are less likely to be constrained by traditions which may stifle their creativity.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">But harnessing this potential is no easy task. The final chapter of the UNFPA report, entitled 'Policies, strategies and issues for improving cities', argues that urban dwellers in developing nations have been badly affected by structural adjustment policies. These have resulted in the elimination of subsidies on food and other commodities, increases in school fees and job losses in the public sector. Cities will also be required to adapt to the 'mass global experience in decentralisation' involving the shifting of local decisions from central government to municipal authorities, parastatal bodies and the private sector.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&lt;&lt;I&gt;&gt; p48.png Regional distribution of urban population</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">Women - a priority</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The report stresses the importance of improving education and health, with a particular focus on women. As Dr Nafis Sadik, who is Executive Director of the UNFPA, observes; 'If urban centres are to be made liveable, and the quality of life of the poorer members of society is to be improved, women should be given the chance to play their role in the process.'</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The report reiterates the specific targets for improving the lives of women that were drawn up by the 1994 International Conference on Population and Development held in Cairo.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">In the field of education, these include 100% primary school enrolment (for both girls and boys) by 2015, improving access for girls and women to secondary, tertiary and vocational education, and closing the gender gap in the primary and secondary sectors by 2005.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Other goals include a progressive reduction in infant and maternal mortality, making reproductive health services accessible to all through the primary health care system by 2015, greatly improved provision for family planning (allowing couples to make free and informed decisions on the number, spacing and timing of births) and providing better protection against sexually transmitted diseases.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The State of the World Population Report concludes: 'A successful urban future depends, as much as anything else, on engaging all members of the community - especially women and the poor  -  in a constructive political process.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">There will have to be partnerships struck between governments, nongovernmental organisations, the private sector, and local and community organisations.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">And global urbanisation will require that the international community  -  governments, NGOs and international institutions - act to exploit the potential of cities to improve the lives of the world's people and to establish the foundations of sustainable development in the 21st century.'</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<I><P>&lt;&lt;TOC4&gt;&gt; Lagos under stress</P>
+</I><P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">by Paul Okunlola</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">With a present population of some 7.5 million, the new millenium will propel Lagos to megacity status. The United Nations Population Fund predicts that 24 million people will live in the city by 2015, making it the third most populous conurbation on the globe. Whilst the donor community has supported urban projects in the past, tough times mean more reliance on 'bottom up' schemes backed by N60s and community-based groups.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">When it began to rain in the small hours of Thursday 18 July 1996, residents of Lagos -  Nigeria's largest city and economic nerve centre -  merely stirred in their slumber. The gentle, but persistent showers, didn't rank among the heaviest downpours experienced by this coastal city, which gets rain on average for eight months in every year. Nor are Lagosians unfamiliar with spells of rain lasting up to seven days without break.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">But by the time of the early morning 'rush hour', the traffic-laden streets of metropolitan Lagos were being swept with rampaging floods. Until well after noon, the city's social and economic life was at a standstill. Already difficult road conditions were rendered impossible for motorists, marooned at the wheel for hours. Exhausted school children eventually made it back home after spending the better part of the day in traffic. Crowds of commuters waited interminably at bus-stops for vehicles that never came.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The economic toll was expected to be heavy, with offices in both government and the private sector remaining empty all day. Commercial activities were put on hold as shops remained shuttered until well after noon. The communications network and electricity supply to key areas of the city were shut down for hours, to protect equipment. One state government official commented: 'It has never been so bad.' By the time the water receded and life had returned to normal, both government engineers and private sector consultants were in agreement: the main reasons for the flooding were illegal development along the natural courses of inner-city waterways, and the reduced drainage capacity of the overdeveloped metropolitan area.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Exploding metropolis</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Both the flood itself, and the acknowledgement of the human limitations of the city officials, illustrate the frustrations that have attended the management of this exploding metropolis over the last three decades. In the months leading up to the July flooding, a major controversy erupted over plans to landfill the inland Kuramo lake in the highbrow Victoria Island district and develop it as a housing estate. This pitted state government officials and a firm of developers on the one hand, against a motley band of citizens groups, non-governmental organisations and concerned environmentalists on the other.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The unusual strength of local feeling against the project reflects growing fears that the island itself could be submerged. Five years ago, this was thought to be a remote prospect but today it is seen as a real threat, given the increasing frequency of flooding incidents and ocean surges along the coastal area.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">More and more people are arguing that there is a correlation between the growing frequency of flooding incidents and the massive sandfilling activity that has taken place over the years. The Kuramo issue remains contentious but it is just one example of the wider dilemma facing the city's development planners. They have the daunting task of providing for legions of migrants to Lagos - whose swelling numbers are placing great stress on the failing infrastructure. The problem may be particularly acute in the Nigeria's largest city, but it reflects a wider trend of urbanisation in the country over the past half century, as the overall population has increased.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">In 1921, Nigeria had just 18.7 million inhabitants. Current estimates put the population in the region of 103.5 million. And the growth in the proportion of urban dwellers has been equally dramatic. In 1931, fewer than 7% of the people lived in urban centres. The figure had risen to 10% by 1952,19% by 1963, 33% by 1984, and 42% at the last count, in 1991. Current figures suggest that there are now seven Nigerian cities with more than a million inhabitants and no fewer than 78 whose population exceeds 100 000.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The changing structure of the country's human settlement profile has been linked to broader economic and social changes. The situation has been exacerbated by the economic depression of the last two decades. Analysts have noted a trend of declining primary production in such areas as agriculture, mining, quarrying and exploitation of natural resources. This has resulted in greater attention being paid to secondary and tertiary economic activities -  which are generally city-based. The figures illustrate the dramatic nature of the change that has taken place. In 1952, the ratio of primary to secondary/ tertiary economic activity, as measured in Nigeria's GDP, was 68:32. Four decades later, the ratio was 38:62.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">According to World Bank consultant, Prof. Akin Mabogunje, the trend is exemplified by the expansion of a whole range of activities located in urban centres -  large, medium and small-scale enterprises in manufacturing and construction, utilities, transport and communications systems, wholesale and retail outlets, hotels, restaurants, finance and insurance companies, and estate agencies. Then there is the whole range of government activity. Until 1991, Nigeria's huge federal bureaucracy was located in Lagos, operating alongside a state administration and some 15 local authorities. Add to this the major docks and airports of Lagos, and you get an urbanisation phenomenon which has, to say the least, been intimidating.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Lagos, which only occupies 0.4% of the country's land area, gains an extra 300 000 inhabitants every year on top of its natural growth rate. That the city is a 'pole of attraction' is hardly surprising. It is clearly the economic nucleus of the country, reputed to account for about 57% of total value added in manufacturing and about 40% of the nation's most highly skilled manpower.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Urban toll</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The costs have also been high. Professor Poju Onibokun, a human settlements expert, enumerates these: grossly inadequate housing and infrastructure with millions dwelling in slums; social amenities under enormous pressure with a shortage of schools and poor health facilities; endemic crime and juvenile delinquency; the breakdown of traditional values, family cohesiveness and community spirit. The capacity of law enforcement institutions is also increasingly hampered by technological and resource limitations.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Of these ills, the shortage of housing and lack of infrastructure are seen as the most acute. This is borne out by a recent World Bank study which notes that:</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY"> - the quality of life and living conditions have deteriorated;</P>
+<P ALIGN="JUSTIFY"> - economic production has plunged;</P>
+<P ALIGN="JUSTIFY"> - the inadequate provision of infrastructural services has negatively affected the operations of most private sector investors, who now need to spend between 22% and 25% of their capital outlay on providing their own infrastructure.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Over 90% of the city's housing is provided by the private sector. But this has been handicapped in recent times by spiralling development costs and a general shortage of funds. New private housing has consisted largely of thousands of individual units, built mainly in areas of existing large scale developments. The authorities have made their own efforts to plug the gap and over the last 15 years, no fewer than 6000 hectares of marshland have been sandfilled and reclaimed in six separate development schemes (some of which have proved controversial). The Land Use Act of 1978 vested all urban land in the state authorities, although the administration of the legislation has not always proved satisfactory.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Public transport is another problem for Lagos residents. There is no integrated system of mass transport and the sector is essentially made up of hundreds of privately operated buses and a dwindling taxi fleet. Massive currency devaluations have meant that the purchase price of new vehicles has rocketed. Maintenance costs for the increasingly dilapidated fleet have also spiralled. As a result, the system is stretched to beyond its capacity and it is the commuters who bear the brunt.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Public sector spending obviously has an important part to play in maintaining urban structures. The downturn in international aid flows has, therefore, had a visible impact with decline in infrastructure provision and maintenance, leading to a less favourable operating environment for private investors.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">In the past, Lagos has been a notable beneficiary of urban support programmes with multi-million dollar schemes for water supply, storm water drainage, and infrastructure. Most of these have been World Bank-led but the support of the European Union and its Member States in this area is also considered crucial.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">On the positive side, adversity has proved a catalyst for greater community-based and NGO activity in environmental and human settlement issues over the last decade. This is a fresh approach, based on 'bottom-up' strategies, which should open up muchneeded new avenues to urban management in Nigeria more generally and in Lagos in particular. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<I><P>&lt;&lt;TOC4&gt;&gt; A Eurocrat in Istanbul</P>
+</I><P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">by Gilles Fontaine</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The author, a specialist in urban development, offers us his thoughts on the Istanbul conference. This event, he believes, was a landmark in the collective process of raising awareness which was begun at the Rio Conference on the environment.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">14 June 1996 - last day of Habitat II</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Night fell a long time ago. A feeling of hope permeates the hall. Most of the work is completed but there are still disputes over a few paragraphs of the text of the Habitat 11 Agenda. Some delegates have not slept for two days and they can be seen standing around, afraid they might fall asleep. The sense of fatigue increases further when, at midnight, the symbolic 'stopping of the clocks' (to permit a successful outcome of the final negotiations) is announced over the PA system.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">At two in the morning, the wait has become almost unreal. It is virtually unimaginable that the Conference should come to nothing, after two years of intense work. Since Wednesday evening, the general atmosphere has been almost euphoric. Agreement has been reached on all the essential points within the allotted time and the Conference is already being heralded as another success story. All that remains to be done is to finalise the 'Istanbul Declaration', a four-page policy text broadly summarising the work of the Conference. The Conference would finally close about two hours later, amid general relief - but why the impasse?</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Breaking new ground... and remaining steadfast</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Some problems arose where they were least expected! To everyone's surprise, 'informal' working sub-groups had to be set up to discuss nuclear testing and anti-personnel mines! These themes were a far cry from the Habitat Agenda, but this sort of thing inevitably happens at major international conferences.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Other stumbling blocks appeared without any real warning, when some delegates attempted to renegotiate the conclusions of the Beijing and Cairo conferences. The negotiators had to stand firm on two counts. The hard-won recognition of women's rights needed to be defended all over again. And, more importantly, the attempt in Istanbul to reopen the debate on everything that had been gained at previous conferences had to be avoided. The European Union's negotiators took an aggressive stance on both these issues.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The fact that so much negotiating effort is expended is a good illustration of the political significance governments attach to the topics debated on such occasions. A conference may be seen as resembling the proverbial half-bottle of water  - some regard it as half empty and others as half full. One's viewpoint depends on one's expectations  -  and much disappointment is caused by a misunderstanding of how such conferences operate.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Meeting the delegates</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Although I am no anthropologist, I think I was able to identify three major groups of participants. First, there were the 'negotiators', who have built up a common language from conference to conference. I was surprised at the extent to which reference was constantly made, in the negotiating groups, to the 'Languages' of Rio, Copenhagen or Beijing. This is not just a question of vocabulary or syntax, but represents a genuine revolution in thought at international level.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The second group, to which I myself belonged, was made up of national and international officials. These are the people who, to a greater or lesser extent, prepare the conference. They then attend it and, ideally, write a mission report on returning to their offices (bemoaning the fact that few people will read their words of wisdom !)'These delegates tend to offer the harshest judgments. A common refrain is: 'We have long argument about words in parenthesis in a huge document that no one will ever read!'.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The third group, which nowadays is the largest, consists of representatives of so-called civil society. Since Rio, every United Nations conference has seen the parallel organisation of an NGO Forum, and the latter's influence has constantly increased. At Beijing, the authorities banished the NGO Forum to a site 60 km from the capital, but Istanbul welcomed it with open arms on the same footing as the 'Cities Summit' and the meetings of researchers and industrialists. A more fundamental development was the invitation to NGOs and local authorities to take an active part in the working groups and at meetings. This was a 'first' in international conference history and I was struck by the motivation and competence of many of the participants, as well as by the ease with which they have adapted to the information society. Gone are the days when addresses are exchanged on scraps of paper, accompanied by the ritual 'We must keep in touch!'. These days, your business card must include your Internet Email address. Contacts are organised through networks connected to databases, and people swap CD ROMs with each other.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">What did Habitat II achieve?</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The 'official' end most visible result of the Conference was obviously the adoption of the Habitat Agenda - the final fruit of long hours of work within the national committees set up for the occasion. This document, over a hundred pages in length, contains a 'World Action Plan', accompanied by the 'Istanbul Declaration'.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">What is not so well-publicised is the fact that many countries  -  including a number of ACPs  -  took the opportunity to publish their own national reports containing individual action plans. The amount of preparation that went into these reports revealed a high degree of motivation.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Having looked at them more closely since, I have gained a somewhat better understanding of the months of work put in tens of thousands of people across the world. This reassures me that the majority of state participants will monitor the Habitat 11 follow-up very closely.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">One has to recognise that the mere adoption of a text, however significant it may be, cannot be regarded as a magic formula which will change the face of the world overnight. To the impatient among us who want everything straight away, and to unrepentant sceptics, I would say this. In environmental matters there are two major periods in our recent history - the period before Rio and the period after Rio. The Rio meeting, and each subsequent conference, have been milestones in a long, coherent process of collective reflection and growing awareness. Istanbul did, in fact, keep its promises: the right to adequate shelter is now recognised internationally as the fundamental right of every human being.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<I><P>&lt;&lt;TOC4&gt;&gt; The exploding city</P>
+</I><P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">by Stephane Yerasimos</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Istanbul. Ten million inhabitants - with double that number expected in 20 years time. Financial irregularities, a chaotic house-building sector, a lack of infrastructure and rampant speculation. One needed to look no further than the host city to find the key issues facing the Habitat Conference.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Istanbul is a city steeped in history. It is also one of the Third World's biggest conurbations. Over the last 16 centuries, it has been the capital of two great empires - the Byzantine and the Ottoman - resulting in a rich legacy of monuments and a historic centre on a par with that of Rome. From the Middle Ages to the beginning of the modern era, it was regarded as Europe's largest city. On the eve of the Second World War, it had a population of one million, but that figure has now multiplied tenfold. Almost half of its ten million inhabitants are living on a knife edge, and many are in 'illegal' housing.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The first big transformation of the city came in the middle of the 19th century when the Ottoman authorities opted for westernisation and embarked on an extensive management programme. By the time the Empire collapsed in 1922, much of the ancient fabric - and traditional housing -  of the city had already been lost. Under the new republic, the capital was transferred to Ankara, and the authorities stepped up their efforts at modernisation. In 1937, Ataturk gave Frenchman Henri Prost, a city planner who had helped preserve the old centres of a number of Moroccan towns, the job of devising major public works in the heart of the old city. The infrastructure was also updated and taken together, these works (which were completed during the 1950s) transformed the old walled city and its ancient suburbs (Galata and Uskudar) into a modern aggLom&eacute;ration, interspersed with ancient monuments.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Mass immigration</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Unlike the colonial powers who attempted to preserve the traditional character of old city centres around the Mediterranean rim and in the rest of the Islamic world, the desire of successive Turkish governments to modernise the country resulted in the disappearance of most of Istanbul's ancient fabric, and the city no longer has a compact area of old districts.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The transformation of the city centre was matched, after the Second World War, by an explosion of building on the outskirts - a phenomenon characteristic of Third World countries. Improved sanitation and hygiene standards led to a natural population increase of between 2.5% and 3% per year. Meanwhile, the modernisation of agricultural practices caused a mass rural exodus. Marginalised in both economic and social terms. the people who flooded into Istanbul soon over whelmed the resident population. Today, the bulk of the people living in the city have rural origins.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The new residents began by occupying the edges of the old quarters and taking over the open spaces which remained after the ravages of an earlier fire. They then began to settle in ever-increasing circles around Istanbul, establishing the first gecekondu districts (groups of huts constructed overnight). These have been incorrectly described as shanty towns. In fact, most buildings are permanent structures and they rapidly develop into multi-storey dwellings. Most of the land on which these illegal buildings have sprung up was originally privately owned. But the elected multi-party government in power at the time was quick to spot the electoral possibilities in these areas. Each district was a reservoir of potential voters and, on the eve of each election, the parties in power would distribute property titles to the illegal occupants. They, in turn hastened to consolidate and increase their assets. This explains the emergence of increasingly densely populated districts without infrastructure during the 1950s and early 1960s</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Industrialisation, and the arrival in the city of people who used to be rural landowners (driven out by the new market economy) later created a demand for housing which the normal market was unable to meet. This has given rise to a new phenomenon of urban marginalisation, involving the illegal division of land into plots. The system involves the purchase of agricultural properties by developers and speculative builders. These are divided into small plots and resold, quite legally, to purchasers  -  who then build unauthorised structures in contravention of the normal planning rules. Often, benefiting from political alliances, the developers take control of these districts and 'convert' the votes of the people living there into cash, in return for urban investments. This enables them to consolidate their power and increase the value of their remaining stock of plots.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">An uncontrolled population increase</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Finally, a third phenomenon, linked to the growth of a middle class, began to occur in the mid-1980s, when building cooperatives came into being. Their predecessors were the corporate associations which grouped together public officials (beginning with the army and the police). These developed into ad-hoc associations enabling a group of developers to tap people's savings, thereby dispensing with the need for loans in a country where chronic inflation makes credit prohibitive. Several thousands of dwellings are often constructed at the same time, in the form of tightly packed, multiple-occupancy blocks. The requirements of multi-storey construction mean that these buildings are of acceptable quality, but the related infrastructures are sorely lacking. Entire districts are built 'in the wilds' without any infrastructural investment by the developers or local authorities.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The city is continuing to expand, without reference to any development plan. The fifteen or so major urban schemes drawn up since the 1950s have all remained in desk drawers and the only significant construction work has been on roads (notably bridges and ring roads). These generate further uncontrolled population increases on the outskirts of the city.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Although the natural rate of demographic growth is slowly declining - it has just dropped to under 2% per year -  the most recent census (in 1990) reveals that Turkey now has more people living in its cities than in its rural areas. Yet the statistics also show that half of the country's people are still involved in agriculture. Given the continuing natural growth, and the fact that in semi-industrialised countries, the rural population tends to settle at around a third or even just a quarter of the total, we can assume that the drift to towns and cities will continue for the next 30 or 40 years. This trend will affect all Turkish towns and cities, be they large, small or medium-sized. But Greater Istanbul, where the majority of the country's economic and social activity is concentrated, is set to experience a doubling of its population within the next twenty-five years.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Dilemma for urban planners</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The problem caused by demographic changes is exacerbated by economic constraints. For a number of years now, Turkey has suffered a high (albeit stable) inflation rate of about 70% per year. This situation discourages investment in industry, and makes people take refuge in ownership of land that they can build on. Land has thus become the target of speculation by people in all social classes. Against this background, it is virtually impossible to regulate the use of land  - something which must be at the heart of any urban-development programme. An alternative is to discuss the possibility of developing a social consensus involving a more liberal approach to property speculation, recgnising that land is a source of revenue at all levels. This might entail releasing central and local authorities from any responsibility to provide services or other infrastructural investment.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">In the present circumstances, however, any scheme to redevelop Istanbul effectively would seem doomed to failure. The only intervention which might succeed would be at the 'cleaning-up' stage - coming in after the construction of the dwellings under the conditions described above. It is only once the new inhabitants' dream of having a roof over their heads is realised that they come face to face with the harsh daily realities of living in a self-built city of nearly ten million people. They may then be prepared to make some sacrifices in order to improve their living conditions. The moment when harsh reality replaces emotion, is the only time the urban planner has the slightest chance of being listened to. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<I><P>&lt;&lt;TOC4&gt;&gt; Adequate housing in the EU: rights and realities</P>
+</I><P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">by Misia Coghlan</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">There are 2.7 million homeless people in the European Union and many millions more are badly housed. But the EU is said to be lagging in taking measures to provide adequate housing - one of the internationally recognised human rights. An expert from a leading campaign group for the homeless explains.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Rights</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">In the weeks and months leading up to the Second United Nations Conference on Human Settlements (Habitat II), much argument and debate centred around the existence of the right to adequate housing. The legal basis of this right was challenged by a handful of delegates and the arguments continued right through the Conference itself. The outcome is that the final Declaration includes a reaffirmation of states to a 'commitment to the full and progressive realisation of the right to adequate housing as provided for in the international instruments.' (see first box)</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The political impact of Habitat II as the culmination of the recent series of UN Conferences has been disappointing. The Istanbul Conference was originally heralded with the catch-phrase 'housing for all'. In the course of the preparatory process, this was watered-down to become 'shelter for all' and, as has been seen, the wording of the final Declaration simply refers to existing international commitments and allows for the 'full and progressive realisation of the right.' This of course begs the question of how such a right was ever supposed to have been achieved other than 'progressively' and how meaningful such a commitment can be in the absence of parallel undertakings as to implementation and enforcement. In short, very little has been achieved in progressing international commitment to the realisation of the right.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The right to adequate housing has in fact been recognised for some time now by the Member States of the European Union, all of whom have ratified the 1966 International Covenant on Economic, Social and Cultural Rights (the most important legal basis of housing rights found in international law). Under article 11(1), the parties to the Covenant recognise, 'the right of everyone to an adequate standard of living for himself and his family, including adequate food, clothing and housing...'</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The concept of 'adequacy', it is generally acknowledged, is determined at least in part by social, economic, cultural and climatic factors. Adequate housing can be understood as including the following components: legal security of tenure, affordability, habitability, accessibility, location and availability of services, materials, facilities and infrastructure.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">It hardly needs pointing out that commitments in international law, whether legally binding or not, remain statements of intent and are of limited practical use unless accompanied by a comprehensive legislative framework in domestic law which will secure both the access to the right as well as providing enforcement mechanisms. What, then, is the reality ? Has the right to adequate housing been enacted into national legislation and, most importantly, is the right actually being respected across the European Union?</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Realities</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">FEANTSA, the European Federation of National Associations Working with the Homeless, has been conducting the European Observatory on Homelessness with the support of the European Commission since 1991. FEANTSA's research findings have increasingly demonstrated both the extent and the gravity of the housing crisis in Europe: in what is one of the wealthiest subregions of the world, a large and growing group of the population is being excluded from adequate housing. (see box on next page)</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Moreover, FEANTSA's 1995 transnational research report (Home/essness in the European Union) has found that the right to housing does not exist in any Member State as a legally enforceable claim. Although the right is recognised in the constitution of several Member States, this remains a statement of intent and does not create any entitlement. Other Member States have adopted a different approach - housing legislation in the United Kingdom, for example, does create an obligation on the local authorities to provide housing for those homeless people assessed to be in priority need and found to be unintentionally homeless. There is no sign of convergence in the ways EU Member States address the right to housing and housing exclusion in their national legislation.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The right to housing is not addressed in EU legislation as a legal principle and Member States have exclusive competence to deal with housing issues themselves. There is thus no overall European housing policy, nor is there yet any European policy on homelessness. FEANTSA has, however, identified common trends throughout Europe which have contributed to the escalation of homelessness and the lack of adequate housing provision.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The overall European trend has been an increased reliance on the competitive market to meet all housing needs, with an unwillingness on the part of government to commit public resources to assist lower income groups, who are therefore confronted with the limited choice available to them on the open housing market.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The supply of housing has been undergoing change throughout Europe. In all countries, owner-occupation is on the increase, with tax relief generally being offered as an incentive. The private rented sector, on the other hand, has continued to decline. Social housing has generally suffered from cuts in funding. The result is that there is a shortfall in the supply of affordable housing for rent and rents have become correspondingly higher. It is clear that the competitive housing market cannot and will not meet the needs of the increasing numbers of people without the resources to afford market rents.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The type of housing required has also changed: demographic trends have meant that households are getting smaller but more numerous - thus, there is a need for more but smaller dwellings.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The problem has been exacerbated by the lack of an overall strategy either at European level or, indeed, often at national level, to meet the realities of structural changes on the labour market. Indeed, in some countries, the increase in long-term unemployment has been accompanied by an erosion of social protection systems. Faced with escalating demand for longterm welfare assistance, the authorities have often responded by tightening up on eligibility criteria in an attempt to cut or limit benefit payments, with shortterm palliative measures to deal with emergency cases. Thus, increasing numbers of people living on or under the poverty threshold, coupled with the deregulation of the housing market, have led to severe housing stress and increased vulnerability to homelessness.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Finland sets an example</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Finland is one EU country tackling the housing problem. In 1987, the International Year of the Homeless, the Finnish government announced its intention to eliminate homelessness. At that time, the number of homeless people was put at close to 20 000. The programme for the development of housing set the objective of making 18 000 homes available for the homeless over a period of five years. Special funds were set aside in the national budget to permit the local authorities and other organisations to purchase housing for the homeless. State loans for the construction of housing for rent were made available to municipalities with a large homeless population. In under ten years, the number of homeless people in Finland has been reduced to half what it was in the mid-1980s. Finland now enjoys a comprehensive system of carefully targeted housing supply, housing subsidies, benefits and allowances and housing is seen as an integral part of a multi-dimensional strategy to combat poverty.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">For one in twenty citizens of the European Union, the criteria which, as a whole, constitute adequate housing remain inaccessible. Yet at Istanbul, the EU voiced its determination to make an important and constructive contribution to the implementation of the Habitat objectives. This included an acknowledgement that increased attention should be paid to people living in poverty and that appropriate action should be taken by governments at all levels.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The European housing ministers were due to meet informally in Dublin, on 24 and 25 October of this year, specifically to tackle the question of 'housing for socially excluded people'. The time has come to devise and implement coherent strategies to prevent housing exclusion for low income groups. The market has neither the ethics nor the long-term planning capacity to do this; it remains the responsibility of the state. It can only be hoped that the housing ministers will recognise this and agree on the necessity of protecting housing as a product and as a service from the competitive market, at least for vulnerable groups. The housing ministers have been holding informal meetings since 1989. This year's meeting provides the opportunity, particularly in the light of the Habitat II debate, to exchange information on effective measures to help low income groups access and maintain a home. The result should be the drafting of a number of concrete goals to be achieved within a realistic time-scale.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Homelessness in Europe is not on the scale seen in other regions of the world - with the development and reinforcement of effective preventive policies, based on proven and cost-effective welfare models existing in some Member States, the housing crisis can still be contained. In short, where there is a political will, there is a way. Europe has the potential to serve as a model of good practice to the rest of the world and should do so, more especially in the light of all that was - and wasn't  - achieved at Istanbul. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">References</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Is the European Union Housing its Poor ? Dragana Avramov, Catherine Parmentier and Brian Harvey, FEANTSA, Brussels 1995 </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Homelessness in the European Union, Dragana Avramov, FEANTSA, Brussels 1995</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The Invisible Hand of the Housing Market, Dragana Avramov, FEANTSA, Brussels 1996</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<I><P>&lt;&lt;TOC4&gt;&gt; Cities of the Third World</P>
+</I><P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">by Francis Cass</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">In ten or so years' time, more than half the world's population will be living in built-up areas and, according to UN figures, by 2025 nearly two thirds of us will live in towns and cities. This is not a complete surprise -  over the last few decades, the ratio of city dwellers to rural people has consistently moved in 'favour' of the former. In 1950, 29% of people were city dwellers. Since 1985, the urban population has exceeded 40% of the global total.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Today, we are witnessing an acceleration in demographic growth, especially in developing countries. Of the 2.6 billion people who currently live in towns, 1.6 billion live in the world's least developed regions. By 2025, the urban population of the Third World will have risen to 3.2 billion, out of a global urban population of just over 4 billion. On the basis of these figures, it is estimated that the number of urban dwellers in developing countries is increasing by approximately 150 000 people each day! In Cape Town in South Africa, for example, as in many towns and cities of the Third World, this demographic explosion can actually be seen happening. All you need to do is drive regularly along the N2 motor way  - which passes through the shanty towns of Khayelitsha and Guguletu -  to see how, week by week, the makeshift dwellings are spreading - gradually expanding to every available plot of land. The same scene is repeated in all of Africa's large towns. In Cot&eacute; d'lvoire, the population of Abidjan rises by 400 inhabitants a day on average. In Gabarone, the capital of Botswana, whose population was barely 3000 at the time of independence in the 1960s, the population is increasing by 18% each year and today 160 000 people live there. Such growth is often accompanied by widespread indifference on the part of local authorities. Such indifference is due, in particular, to a shortage of financial resources, but it also reflects an absence of political will to do anything to tackle the problem.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Demography and poverty</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The demographic explosion which has taken place in the urban areas of developing countries is due to three main factors: natural population growth, rural emigration to towns and cities, and (less importantly) the redefinition of the administrative boundaries of built-up areas. The first two factors are equally to 'blame' but in future, it is predicted that rural depopulation in Africa will become the single most important element in urban population growth. This will be especially true of countries where there is rampant rural poverty. In this context, we need to recognise other circumstances, such as famine, desertification, a shortage of cultivable land and conflicts, which serve to exacerbate the phenomenon. If people living in the countryside decide to migrate to towns, it is because they are looking for a better life and hope to improve their standard of living. Few succeed. According to a World Bank study, 50% of people in abject poverty will be living in urban areas by the year 2000.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The effects that urban poverty has on the environment are often dramatic. The reverse is also true. A damaged environment constitutes a daily hazard for town and city dwellers, in particular the most destitute. The precarious nature of their living conditions means that only in extremely rare cases are these people able to guard against the degeneration of their immediate surroundings. Driven to the outer limits of the towns - where even basic infrastructures such as sewers and the collection of household waste are often lacking, the poorest sections of society are left to fend for themselves. Local authorities have neither the means nor (often) the inclination to do anything to help them. Even those who are comfortably off and who can afford to give part of their income to safeguard their immediate environment (thereby protecting themselves to some extent) cannot escape the consequences of more general ecological problems such as air pollution and the contamination of water supplies. Living in a modern house in a well-to-do district is simply not enough. It is not possible to shield oneself completely from the problems created by environmental destruction. For example, even an unofficial rubbish tip, located several kilometres away from a residential area, can have disastrous effects on groundwater - meaning that sooner or later, the quality of the drinking water will suffer.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Towns gasping for water...</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">At present, the vast majority of Third World towns are facing a series of ecological problems which directly or indirectly, affect the lives of their inhabitants. According to the World Health Organisation (WHO), 220 million city dwellers have no access to drinking water and 420 million have no latrines. It does not take much to imagine the potentially catastrophic health consequences of such a situation - in which people are forced to drink and irrigate their land with water from contaminated sources. The WHO has estimated that three million children died during 1993 as a direct result of diarrhoea, and that nearly two million of these victims had consumed drinking water contaminated with faecal matter. In developing countries, 90% of waste water is poured, completely untreated, into rivers, lakes and coastal waters. Again, one can easily imagine the impact on marine flora and fauna, and on the health of those who eat the products fished from these waters.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">...and gasp for breath</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">As far as air quality is concerned, the WHO intimates that more than a billion city dwellers throughout the world breathe highly polluted air. For the most part, this pollution is generated by industry and motor vehicles. A small improvement has been recorded in the urban areas of developed countries, but air quality in the towns and cities of the South has deteriorated considerably during recent years.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">There are many reasons for this. First, there has been an increase in industrial activity, mainly concentrated around towns and cities. This is a result of economic development, but also of the fact that many factories - including some with the worst pollution records  - have relocated from the North to the South, where legislation governing emissions is less stringent. Second, in contrast to the trends seen in developed countries - where cars are usually well-maintained, (running on unleaded petrol and rarely more than five years old) motor vehicles in the Third World -  whose numbers are increasing significantly  -  are frequently old, badly maintained and run on leaded fuel. According to the World Bank, 95% of the lead polluting the air in the towns and cities of developing countries comes from vehicles which run on leaded petrol and studies carried out on the subject have revealed concentrations of up to 1.5 microgrammes of lead per cubic metre of air. In North America and Europe the concentration varies between 0.2 and 0.8 microgrammes per cubic metre.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Another problem facing towns and cities in the southern hemisphere arises from the enormous amounts of waste they produce and from the fact that they have few treatment facilities. In many cases, the rubbish is not even collected and is left to accumulate into the piles which can often be seen on the edges of shanty towns. This accumulation of refuse encourages the proliferation of certain diseases and poses a real threat to the health of residents both nearby and further away. In addition to this ordinary, everyday waste, the countries of the Third World have to deal with problems generated by toxic waste  - not just their own, but also that which is 'exported' there by industrialised countries. Needless to say, the towns which actually have the means and facilities needed to treat this highly polluting waste are few and far between.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Linking development with environmental protection</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">While environmental problems have a direct impact on human health and on the natural world, they also entail huge economic costs. The effect of pollution on human health translates into ever-increasing health costs and a decline in productivity. And it is not only city dwellers who suffer the consequences of a deteriorating urban environment. Depending on their size, the degree of industrial activity and population concentration, towns and cities pollute and destroy areas well beyond their own administrative boundaries. They swallow up enormous amounts of natural resources, suck their hinterlands dry and spit out 'what is left'.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Nowadays, there is an increasing global consensus over the need to tackle these growing problems rapidly. This was seen clearly at the Habitat II Conference in Istanbul. Most cities of the southern hemisphere urgently need to get to grips with their numerous ecological problems - the alternative is to sink further into chaos. In a similar vein, it has become obvious that some sort of balance must be found between economic development and safeguarding the environment - and that considerable investments are needed to achieve this.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Solutions do exist. Recycling projects, for example, could provide jobs for large numbers of town and city dwellers, as well as cleaning up the environment. Governments of industrialised nations should take the necessary steps to ensure that their toxic waste does not end up in the rubbish dumps of the countries of the South. Authorities in urban areas in the Third World should set aside more of their budgets to help the most underprivileged sections of their populations, so that they can manage their own environment. Local authorities should also respond more efficiently to the basic needs of impoverished districts, not least by building roads and sewer systems, by ensuring that rubbish is collected and by guaranteeing all people access to drinking water.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Last but not least, a concerted effort - especially a concerted financial effort - should be made by decision-makers at the local, national and international levels. We need to recognise that environmental damage is a phenomenon which rarely confines itself to the local level. Sooner or later, it becomes a problem for all of us. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<I><P>&lt;&lt;TOC4&gt;&gt; When conservation is at odds with the local population</P>
+</I><P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">by Hendrik Smets</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The clash between the interests of people living on the edges of the Zakouma National Park in Chad and the authorities' attempts at conservation illustrates the situation facing many other nature reserves in Africa. This article argues in favour of a form of eco-development to suit everyone.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">When the Zakouma National Park (PNZ) WAS officially set up in 1963 (it had been at the planning stage since 1956), the area it covered meant that local people had to be moved -  but the promised compensation was never paid. During the second phase of the PNZ's relaunch, financed by the European Development Fund (EDF), a perimeter path following the 1963 boundaries was marked out, but local villagers opposed this, regarding it as an extension of the Park's area. Subsequently, they rejected a move to build a dispensary in a village located at the edge of the park on the pretext that such a structure would again constitute an extension to the reserve's land.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Conflict between the itinerant stockbreeders of the region and the authorities has simmered for many years. The latter have shrunk from enforcing the 1963 law on transhumance corridors which applies to the fringes of the national park. Under this law, it is prohibited (in principle) to gather wood, hunt for game, fish, or gather honey and other natural produce. The result is a tendency among locals to view the PNZ as an adversary rather than a potential partner in development. Safari tourism is developing too slowly and is not leading to sufficient benefits for example, from a craft industry, or more general redevelopment.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">When the second phase of the project was at the planning stage, its organisers recognised that, in order to guarantee the park's future, support had to be given to the people living on its edges. A high-level 'cooperation committee' was therefore proposed. The membership of this committee, which would sit in N'Djamena, was to include ministers, directors-general, park authorities and Commission representatives. Unfortunately it has not yet been brought into operation. By contrast, the local authorities and park management have been able to set up their own committee which met for the first time in January 1996. This body has helped to tackle some of the most sensitive problems.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The second phase also saw the implementation of a series of microprojects. - school renovations, a dispensary, a bridge, the sinking of wells, a dam, a mill and a nursery. But these were set up without preliminary study, and no arrangements were made to sound out the views of the local people, or the form of development they would like promoted. Understandably, local hostility was encountered and the projects cannot, in any real sense, be viewed as offshoots of the wider PNZ scheme.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The future</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The project has not been extended to a third phase. Because of this, there is a risk that the capital invested -  and the positive results that have been achieved - could be lost altogether. Should any donor choose to 'pick up the baton' in future, they will need to recognise the key imperative of creating a symbiotic relationship between the park and the local population. To do this, there must be an awareness-raising effort, undertaken in parallel with any eco-development programme.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">In the first instance, a higher profile should be given to institutional issues. In particular, the cooperation committee in N'Djamena must be able to act, where necessary, as an appeal or arbitration chamber to deal with any disputes which cannot be resolved by the local authorities' committee. The latter, of course, would continue to meet on a regular basis to discuss any problems encountered.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">At the same time, there should be campaigns to disseminate information and train local people who are in daily contact with the park's environment. The aim here would be to make them progressively more accountable for conservation and the exploitation of natural resources (cutting wood, gathering produce, hunting, fishing, and so on). They must also gain a better understanding of the effects of poaching and desertification. Above all, such campaigns should seek to convince the people of the benefits they stand to gain from the park, if they continue to respect its integrity.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">In this context, some lessons might be drawn from a regional project dating from April 1987 (which was never fully implemented). This was aimed at halting the advance of the desert in the northern Central African Republic and southern Chad. The component of the project which is of interest to the present discussion was its programme to increase public awareness  -  which involved training organisers, preparing and disseminating information (posters, videos, films), organising information tours and giving support to the Training and Environmental Information Programme of the CILSS (Inter-State Committee to Combat Drought in the Sahel), of which Chad is a member.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">One could also learn something from the approach adopted by the Manda National Park which is situated 270 km from Zakouma. This has 'volunteer villagers' appointed by the chiefs of the four cantons making up the park zone, who know the territory well. The volunteers take part in information, awareness and monitoring operations alongside national park and animal reserve employees. Dressed in pale olivegreen uniforms, they cycle between the villages and encampments, providing a link between the villagers and officials in N'Djamena. They have an invaluable role in convincing village people of the advantages of cooperating in the development of the park and its surrounding areas. And the cost of a volunteer is just CFAF 5 000 (ECU 7.5) per month.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Eco-development</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Returning to the PNZ, it is true that a small proportion of the population already benefits from the park's existence. Wages are paid to the patrols, and the permanent and seasonal workforce, while micro-projects have been set up. The park pays traders, artisans, farmers and stockbreeders for certain services and there are some tourists. But the bulk of the population does not see these advantages having been largely excluded up to now.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Any future eco-development programme should therefore aim at reducing pressure on the park in order to guarantee its long-term integrity. This would obviously need to be preceded by a clear definition of the action to be undertaken, but in the meantime, it might be useful to offer a few guidelines. The programme should include:</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY"> - a series of flanking or support activities providing infrastructure and equipment, such as a dispensary, a school, paths, wells and carts;</P>
+<P ALIGN="JUSTIFY"> - a food-security programme providing for the conservation of agricultural areas, as well as measures to prevent erosion and safeguard harvests (cereal banks, stores, gardens, agro-forestry systems and pest control);</P>
+<P ALIGN="JUSTIFY">- a project to promote natural resources such as fisheries, gum arable, honey, and straw fodder;</P>
+<P ALIGN="JUSTIFY">- a wood/energy management programme providing improved hearths and brick ovens, and the organised gathering and use of supplies;</P>
+<P ALIGN="JUSTIFY">- development of the craft industry and training of tourist guides.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">If, in a third phase, an awareness and eco-development programme could be successfully implemented, the Zakouma National Park should be able to look forward to a brighter future. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<I><P>&lt;&lt;TOC4&gt;&gt; A new 'eco-centre' in West Africa: Two Presidents amid the dust</P>
+</I><P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">In April, on the eve of the International Conference on Human Settlements, the first West-African eco-centre ('Ecopole`) was opened in Dakar. It was set up by Enda, one of the few international non-governmental organisations of significant size based in a developing country. The 'eco' refers to two things - the economic life of the ordinary people and the ecological aspect of the centre. One of the most memorable images of the opening ceremonies was the sight of two Presidents  -  Abdou Diouf of Senegal and his Malian counterpart, Alpha Oumar Konare  -  striding through the dust in a working-class district of the Senegalese capital. For supporters of the 'Ecopole', the event epitomised the fight back of the popular urban economy. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The dust which settled on the Presidents' fine clothes was that of the Rail district, so called on account of the railway which cut through it in former times. Built in an old, disused factory, the airy, clean 'eco-complex' adds a touch of style to this semi-industrial, semi-shanty town district. The old buildings were redeveloped with the help of members of some two hundred cultural and sports associations, working in partnership with the NGO. They used recycling techniques of which they are past masters.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The complex had, in fact, been in operation for some time prior to its formal inauguration, but the ceremony  -  which attracted the interest of international press agencies - provided an opportunity to publicise the venture. Since its formation in 1972, Enda has been working to give a higher profile to the 'popular' economy (they eschew the term 'informal') in Senegal and elsewhere. The NGO has focused, in particular, on trying to encourage those involved in the popular economy to collaborate more closely and integrate their activities, as well as on boosting awareness of what is happening in similar communities elsewhere. The opening of the 'Ecopole' provided a showcase for the achievements of the popular economy in West Africa, as well as a forum for dialogue. And it now has the seal of approval of two Heads of State, not to mention other VlPs who made supportive statements at the opening.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The popular economy fights back</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">For the inaugural ceremony, the former sheds - now converted into airy vaults clustered around a central structure - hosted a major presentation of the popular economy in a series of exhibitions. It is a kind of 'eco-museum' with pride of place going to recycling. Exhibits ranged from 'fabrics' made of old plastic bags crocheted together, to toy sports cars fashioned from wire and tin cans. And the reaction to the exhibition went beyond the usual, somewhat condescending appreciation of 'the skill of these people'. There were, of course, some curios of interest to tourists such as the aforementioned children's toys, small metal suitcases and papier-mache boxes. But there were also works of art, masks and sculptures, which captured something of the nature of this 'recycling culture'. Indeed, international art critics at the Biennal Festival of Contemporary African Art, taking place in Dakar, were talking of a new artistic trend, also seen in the work of artists from other regions, based on reclamation. This, of course, begs the question: 'Has art not always been based on reclamation?'</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Interesting though the subject may be, the artistic and aesthetic qualities of the fruits of recycling are of only secondary importance when one is dealing with everyday objects. The important thing is for deprived populations to use what means they have to survive and to improve the quality of their lives. Tourists may choose to buy decorative and unusual objects on the reclamation market, but more significantly, families can obtain essential items such as kitchen utensils, ploughing implements, carpentry tools and stoves  - all cast from vehicle wheels and bits of scrap metal. They are made using small forges and furnaces the size of a large saucepan, or cut from otherwise unusable pieces of metal sheet. The craftsmen can also supply somewhat more sophisticated equipment: ploughs, brick-moulding machines or soldering irons. One of the exhibitions staged at the 'eco-centre' was a co-production with the Quebec Museum of Civilisation and the Canadian Embassy in Senegal, which had previously toured Canada and four African countries. Entitled 'Africa's ingenuity', it covered a wide variety of styles, ranging from the utilitarian to the artistic. It will, in due course, form the eco-museum's centrepiece. Another temporary exhibition was called 'Antuka: Kinshasa, the art of living in the city', and this paid homage to the Zairean capital - a place which, of necessity, has become one of the 'capitals' of resourcefulness. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Jet engines and donkeys</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">One hopes that the two Heads of State found time to admire the jet engine constructed by a young Zairean from nothing but reclaimed materials: parts taken from cars, mopeds and unwanted metal sheet. And it works -  not on an aircraft, naturally, but on the bench. This engine is now a legend. Its constructor has apparently already been spotted by a European head-hunting company and offered a job in France. This is part of the 'fight-back' referred to by Enda officials, in which some recognition is finally being given to the economies of the world's poorest populations. During his visit, the President of Senegal issued a plea for greater integration of the informal sector into the overall economic fabric. His remarks were revealing: the West-African 'Ecopole', as its name implies, covers an entire region, and assumption of responsibility by the local people for the shanty towns and poorer districts has lifted a significant burden from central government.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Another example of this trend is found in the Malian capital, Bamako, where a hundred or so local community associations have banded together to take over full responsibility for the collection of domestic waste. This organisation, whose initial efforts were ridiculed, is now fully operational. One wonders whether the authorities in other cities have heard about Bamako's scheme. What about Port-au-Prince in Haiti, for example, where they are struggling with mountains of rubbish which they cannot deal with owing to a lack of resources ?</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Since their inception, economic interest groupings (ElGs) such as the one in Bamako have helped bridge the gap between the 'formal' and 'informal' economies. They rely on collaboration and their enterprise is exemplary. At the outset, the inhabitants of poor districts, acting on the initiative of the ElGs, expressed the desire to improve their neighbourhoods by organising refuse collection. They used whatever means were available - which in most cases meant donkeys and carts. In more central districts, delivery tricycles were employed for collection. Specially constructed, tipper-style carts, each costing CFAF 200 000 (ECU 300) have since been brought into service. The price of a donkey, by contrast, is about CFAF 50 000 (ECU 75). The animals and equipment belong to the ElGs and are looked after and maintained by them, with carters receiving a monthly income and social security benefits. A number of groups were set up eight years ago, promoted by young technicians, academics, architects and economists. Those who benefit are known as 'subscribers', with each family paying a contribution towards the service. Managing equipment and collecting contributions both require a well-structured administrative department, but the administrators are not confined to their offices. As employees of the business, they see nothing wrong in lending a hand and assisting the carters. In short, it is an enterprise based on a whole new approach. The contribution made by families varies according to the EIG and the district in question, but it is generally set at around CFAF 750 (ECU 1.2) per family per month. The price of the service may be up to twice this sum in the so called 'quartier des Blancs' (the 'white' district). In theory, the state ought to be subsidising the ElGs, but in practice, this does not happen. The authorities do not even fulfil the task allocated to them under agreements signed with the ElGs, which is to transport the refuse from temporary dumps to a final site. According to local people, the problem is not that the local authorities do not have the trucks available for the task. The vehicles, they allege, are used instead for the officials' own private purposes. The ElGs are forced to plug the gap as far as possible. At present, they appear to be the only ones taking any interest in waste recycling, aware as they are of the risk to the environment posed by permanent dumping grounds, and of the specific danger that the water table will be polluted.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">A modern concept of the 'informal' economy</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The 'informal' economy is increasingly becoming the norm. According to an Enda survey, 90% of businesspeople in Senegal started out in the informal sector. The conclusion would seem to be that the necessary training for dealing with current conditions is not to be found in the formal education system. The popular economy is not out of step with the modern economy as some would claim. Indeed, one could argue that it is the modern economy, as adapted to today's conditions. The increasing involvement of ordinary people in the economic circuit, which they enter via parallel routes, should also guarantee the continuation of Africa's experiment with democracy. We have seen attempts by former dictators to backtrack in this respect. They cite as evidence, the failure of technicians trained abroad - the 'darlings' of the West who, they claim, are at the beck and call of international institutions. But a return to the past, as exemplified by the regime of Nicephore Soglo, strikes fear into many people. Their response is to generate productivity, social cohesion and political stability through the popular economy, by way of compensation.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">It is suggested that small-scale traders, who distribute hardware from south-east Asia, constitute an obstacle to the development of local production. But there is a confusion here between cause and effect. In fact, the popular economy appears more as a response to the lack of consumer goods. The problem lies with the so-called 'major' local entrepreneurs who favour the import/ export business over production, and with the banks that prefer to focus on larger businesses (influenced by anonymous officials or major economic interests) and have no time for small-scale operators.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The Rail district in Dakar has a long history. It is overpopulated, having been settled by workers and artisans, and their influx made it the most expensive poor district. It is a place where the rents, for even the humblest hut without water or electricity, accounted for most of the inhabitants' meagre income. This situation led to the appearance of squatters who built their own shacks on waste ground. For these people, the threat of eviction loomed constantly like a sword of Damocles. The district is also home to a large number of maids and other household employees. Two thousand of these people (from Rail and other parts of the city) set up their own friendly society to which they pay regular contributions.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">It is a world which has always teemed with good ideas: artisans recycling materials, blacksmiths working at the forge and so on. In this sense, nothing much has changed, but the big difference now is that the people have organised themselves. In so doing, they have been able to provide training for adults and children in makeshift schools, and to purchase and renovate old huts  - having extracted a guarantee from officials that such moves would not be opposed. Nowadays, those who live in the district no longer pay rent. However, it will only be possible to measure the true success of the Rail district when there is no longer a need for an organisation like Enda to ensure that it operates effectively.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Some years ago, a former sailor, who always dreamed of being a teacher, set up his own school in the main street which runs through the district. He worked on the pavement and in the car park in front of a furniture store, teaching children in the morning before the offices opened and adults in the evening after they had closed. Enda recently offered him a few pieces of furniture, but for many years, he received no help other than a few pieces of chalk, worn-down pencils and the remains of exercise books from his 'colleagues' in regular education. This is a man who has to supply his pupils not just with teaching materials but also sometimes with food. This year, with his voice catching in his throat, he told us that one of his former 'street pupils' is going to college. How can the learned economists calculate the value of this devoted 'academic'? </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<I><P>&lt;&lt;TOC4&gt;&gt; The RDP challenge</P>
+</I><P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">by Professor Willie Esterhuyse</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The cornerstone of South Africa's Reconstruction and Development Programme (RDP) announced by President Nelson Mandela on May 24 1994, shortly after taking office, is people-centred development with an accent on modern infrastructure, health, education, housing and sanitation.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Lessons have already been learnt from teething troubles.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The RDP is the government's response to the massive socio-economic needs of the bulk of the South African population. It is foremost a strategic framework aimed at human development and restructuring the country's economy. It involves housing projects and programmes to improve the socioeconomic infrastructure covering clean water, electricity, public works, schools, urban renewal and primary health care. Empowerment programmes have been developed, for example; micro and small businesses, support for emergent farmers and skills training.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">One of the main achievements of the RDP has been to sensitise South Africans to the plight of the poor. Apartheid, amongst other things, succeeded in keeping this out of sight, effectively locking the poor out of the system. A veil of ignorance prevailed among the privileged class. The RDP tore away the veil and has led to a willingness to participate in development and reconstruction programmes, especially in private sector circles. It is succeeding in prioritising South Africa's socio-economic challenges, as well as mobilising funding and organising a common and sustainable approach. Its most important achievement to date is probably the idea of partnerships in development between the state, private sector institutions and non-governmental organisations. Through the RDP, South Africans have accepted that they will have to 'run with the development ball'. They are also aware that the state cannot go it alone, nor should it act as a 'super' development agency. Thus, a very high premium is put on involving the private sector and other actors.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Problems</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">But many problems have already been encountered. Unfortunately, the RDP was seen by some as a quick-fix solution to South Africa's socio-economic difficulties. Expectations over delivery were too high. Red tape and a growing bureaucracy stifled the initiative early on. Frustrations among the poor quickly surfaced. Many of those who wanted to participate, and applied for RDP funding, were unable to develop viable business plans - a strict requirement to get funds. The launch of projects was further complicated by the absence, at one stage, of legitimate local and governmental structures.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">But important lessons were learnt from the initial phases, in particular the need to involve people on the ground from day one - starting with the identification of needs, the design of a specific project and its execution. It was accepted that process is more decisive than the product. A second lesson was that a separate RDP office, with its own Ministry, complicated matters as far as delivery was concerned, tending to centralise development. This led to the announcement by President Mandela on March 28 1996 that the RDP office would be closed down. RDP programmes were thereafter integrated into the main budget administered by functional government agencies.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Another very important lesson was that socio-economic development and reconstruction had to go hand in hand with a dynamic macro-economic strategy - made public earlier this year. It was realised that one cannot have good projects in a bad policy environment - to quote a World Bank report.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">In fact, it is generally accepted that the RDP, on its own, cannot launch South Africa on a road to sustainable and vigorous economic growth. We needed a twin-track approach.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Progress</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The RDP has notched up a number of successes. The provision of clean water to rural and urban communities has gone a long way under the leadership of Minister Kadar Asmal -  highlighting the fact that leadership strengthened by solid management, does make a difference. The electrification programme for low-income households, involving the parastatal, Eskom (Electricity Supply Commission), is another success story. The same goes for the Presidential projects, such as free health care for expectant mothers and infants, and some of the nutrition programmes. But the provision of housing for low-income groups has been less successful than anticipated. Rent and services boycotts, as well as unemployment, are some of the reasons for slow progress. Job creation is another problem area. It is envisaged that visible progress in these areas will emerge in the course of next year. Establishing a culture of learning is another great challenge. A restructuring of the educational system is underway, but progress is restricted by severe financial constraints.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Implementation of the RDP, the best strategic framework for socioeconomic development South Africa has ever had, will be a long process. Courage and sustainability are key issues. How to lead and manage expectations, without undermining hope, is a great challenge. The meaningful involvement of donors is another issue. Joint ventures between donors, the private sector, government agencies and communities are happening. Most of these, having been carefully negotiated and executed, are already making a significant difference.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">But spectacular progress should not be expected. Development, reconstruction, and growth of the kind that South Africa needs, will take time. However, the lessons and achievements of the past two years have put South Africa in an excellent position to change the country's socio-economic environment. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<I><P>&lt;&lt;TOC4&gt;&gt; Targeting South Africa's poor</P>
+</I><P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">by Christine Thompson</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The provision of basic amenities for the urban and rural poor rank high on the agenda of the EU's aid policy towards South Africa. In this respect, European cooperation has been tailored to fit with the government's own Reconstruction and Development Programme.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The European Programme for Reconstruction and Development (EPRD) is the name of the current EU development assistance package to South Africa and it seeks to help improve living conditions for all South Africans. The programme earmarks ECU 125 million a year until 1999. It has evolved from the so-called 'positive measures' programme launched in 1985 to help counter the negative effects of sanctions and to help the victims of apartheid.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Under a Declaration of Intent drawn up with Minister Jay Naidoo, then at the helm of South Africa's Reconstruction and Development Programme, it was decided that EU aid should be channelled to the key sectors of education and training, health, rural development, water supply, urban development, economic cooperation, trade and investment promotion, and the promotion of good governance and democracy. In each of these areas, the EU actively encourages a partnership effort between governmental structures and NGOs.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">2.5 million homes wanted</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Over 60% of South Africa's population is urbanised. The apartheid government's restrictions on home ownership in urban areas for the past four decades resulted in a housing backlog estimated at 2.5 million units, with demand growing by 200 000 units per year. Estimates vary, but approximately seven million people are believed to be living in informal settlements throughout South Africa on land occupied both legally and illegally.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Improved housing and sanitation are seen as priority areas in urban and rural development. Between 1991 and 1996, the EU has funded 18 projects in the urban development sector valued at approximately R303.1 m (ECU 52m). The Urban Sector Network (USN) and the Cato Manor Development Programme are typical.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The EU is providing the USN with a total of R26.2m (ECU 4.5m) between 1995 and 1998. The USN is a national network of nine affiliate NGOs, and its aim is to improve living conditions for the urban poor. The beneficiaries of the programme are city dwellers earning less than R2000 (ECU 344) a month and there is a particular emphasis on households with monthly incomes of under R800 (ECU 137) a month.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Through integrated, community-based development, the USN and its affiliates provide technical support and service provision to urban development projects, focusing on housing, local government transformation, skills transfer, project planning, facilitation, information dissemination, education and training.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The Cato Manor Development Programme received funding in 1995, also for a three year period. The EU has contributed R117.6m (ECU 20.2m) to the project. Cato Manor, an area in Natal near Durban, was the location of the largest forced resettlement scheme implemented under apartheid. Today, it is the first area targeted for integrated housing in a former white township.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The overall objective of the programme is to improve living conditions through a policy that strengthens the delivery system for infrastructure and housing. The programme anticipates providing the community with primary and secondary schools, sports fields, community halls, libraries and a community health centre. Access to housing finance will be improved and opportunities for income generation provided through a vocational training centre and small-scale industry workshops. In addition, provision is being made to improve management and general policy-making capabilities. By continuing to fund such projects, the EU is working with the South African government to improve the living conditions of the urban and rural poor. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<I><P>&lt;&lt;TOC4&gt;&gt; 'Guardians of Eden'</P>
+</I><P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Theatre for Africa, a performing group from Southern Africa, went on tour this autumn to put across the message that the exploitation of Africa's fauna should remain in the hands of rural communities. They did this with a powerful mix of words, dance, mime and song, in a play entitled Guardians of Eden '. The Courier met the author and cast on the Brussels leg of their tour. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The setting for the Brussels' performance was the 'Grand Place' (Grote Markt). With its ornate mediaeval architecture, this famous square in the centre of the Belgian capital could hardly have been more removed from the theme of the play - which is about conservation and development problems in Africa and empowering rural people to manage, use and benefit from the wildlife around them.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The play was commissioned by the Southern Africa Sustainable Use Specialist Group (SASUSG) and the idea was that it should reach as many people as possible in the run-up to the World Conservation Congress planned for Montreal in October 1996. South African writer and former economist, Nicolas Ellenbogen, travelled throughout Southern Africa to recruit the all-African cast. Many examples of cultural imperialism leading to the destruction of habitat, highlighted in the production, were actually encountered by Mr Ellenbogen as he travelled through the region.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The play opens with a spirit medium summoning representatives from villages in several African countries to discuss the threat to their survival. The actors display their athletic skills performing mimes of the abundant wildlife with simple props, as the history of Africa is recalled from the dinosaurs to the present day.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">A parable is then told. An old chief informs his three sons that to prosper in the 21st century, the village must change. He instructs them to return a year later with ideas for prosperity, which will be discussed in an indaba (debate). Each chooses a different path. The wheeling and dealing first son seeks out quick fix schemes with NGOs and various city authorities. The second son learns from the difficulties of city life and comes up with a blend of simple wisdom and new ideas. The third spends his time in beer halls -  and his revelry provokes roars of laughter throughout the performance.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Arriving back in his village after almost a year has elapsed, the second son finds that his older brother returned several months earlier to implement his money raising projects. Enjoying the cash benefits of the scheme, the men of the village do not want to hold an indaba. They are forced to do so by the women and Midzimu - the old chief. The audience is then asked to vote and there is a unanimous show of hands for the second son who symbolises the sustainable use of natural resources. The dissolute third son, meanwhile, is eaten by a crocodile.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Ivory ban fury</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">While the message goes out to developers and donors to respect rural autonomy, the play also raises serious questions for Europe's politicians. The frequent appearance of the destructive elephant, in the course of the play, allows Mr Ellenbogen to vent his anger at the ivory import ban imposed by many European states. 'I am furious about the ban', be told The Courier, 'as it is having a profound effect on the daily needs of the people.' He rejects the argument that it helps conservation, insisting that; 'with a stroke of a pen, you reduced the value of the elephant.' The playwrite argues that local people need to see wildlife as economically and socially valuable. Otherwise, they will adopt new forms of land use which will result in the extinction of the species. He also draws attention to the growing black market in ivory in Southern Africa since the ban was introduced.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The 'token' South African - symbolically played by the only woman in the cast - is given a 'rough time as the baby of Africa', says Ellenbogen. The play also contains numerous swipes at the donor community which frequently gives grants, without, it is said, any respect for local traditions. The Swiss doctoral student researching the potential for producing goat's cheese in Africa exits the stage squealing after asking a goat herder what he does with his animals. 'We slit their throats', is his reply.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Guardians of Eden was first launched at the Grahamstown Arts Festival in South Africa in July. It was performed in Zimbabwe and Kenya, and won a prize at the Edinburgh Festival 'Fringe' in August. From there, it moved to Frankfurt and Geneva before reaching Brussels. It was due to be performed in Antwerp, London and several American cities before a final staging at the Montreal Congress in October.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The play is in English and the languages of Southern Africa, but Nicolas Ellenbogen believes it can be readily understood by his multinational audiences. For him, the message - that local people must have the power to manage their own wildlife on their own land - needs no translating. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<B><P ALIGN="CENTER">&lt;&lt;TOC2&gt;&gt; Analysis</P>
+</B><P ALIGN="JUSTIFY"></P>
+<B><P>&lt;&lt;TOC3&gt;&gt; Europeans and development cooperation: there are opportunities too!</P>
+</B><P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">by Stelios Christopoulos</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">If politicians in Europe see jobs as their primary concern, it is probably because the citizens regard unemployment as their most serious problem. In the Europe of the Fifteen, the average unemployment rate was about 10% in 1985 dropping to 7.5% in 1990. By 1994, it had risen to a record high of more than 11%. By contrast, unemployment in the United States fell below 6.5% in 1994 and the figures for 1995 reveal a continuing downward trend. In Japan, the proportion of people without work remained below 3% in 1994. Assuming there is no change in current trends, the most recent demographic projections suggest that there will be 70 million people over the age of 65 in the EU by the year 2020, out of a total population of 348 million. This is 18 million more than there are today. The proportion of over-65s is, thus, projected to rise from 15% at present to 20% in less than 25 years. These two elements  -  an ageing population and ongoing structural unemployment - clearly reveal that European society lacks a degree of dynamism compared with its competitors.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">In an attempt to address this problem, albeit partially, the President of the European Commission, Jacques Santer, launched a European employment pact in April 1996. There are three underlying reasons for this initiative -  Europe's endemic unemployment, the need to reestablish a climate of confidence as a prerequisite for renewed investment and consumption, and the need to fit the creation of the single currency into an overall economic strategy aimed at increasing growth, competitiveness and employment in Europe.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">'I'm young, help me find a job', is the heartfelt plea of many of young Europeans. But what chance is there that their cry for help will be answered in a difficult global environment?</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">We have seen the globalisation of strategic relationships in a range of key areas including the environment, the management of energy resources, health, demography and security. The trend has been accelerated by rapid technical progress in the fields of transport and telecommunications. This process has not taken the big multinational companies by surprise - they were already free of the constraints of sovereignty or space, and were quick to globalise their structures. These enterprises have become more competitive by taking advantage, wherever possible, of the most favourable production conditions, particularly regarding raw materials and employment conditions. More spectacular still has been the growth of international trade: in 1990, the volume of world trade was 11.5 times as great as it had been 40 years earlier. During the same period, global production only increased fivefold.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">What this means nowadays is that employment in the EU Member States is directly affected (and some would say threatened) by the world situation. Productivity and growth conditions in Europe are no longer sufficient to ensure full employment. Competition from developing countries, with their low wage bills and undervalued currencies, is too great for countries in the EU. Their position is not the same as that of the multinational companies. They do not have the structures to deal with swiftly evolving events, nor are they capable of controlling the process of globalisation. This is demonstrated, inter alia, by their inability to respond to the financial speculation which turns capital away from productive investment. Today, for example, for every US dollar in circulation, there are at least 30 dollars which are the product of financial speculation. This is not money from productive work by any particular person, but money which is the product of a financial 'virtual reality' and which is usually reinvested in financial speculation.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Countries are beginning to realise the need to pool their national skills and cooperate at a regional level, in order to enhance their business competitiveness and take on the challenges of the globalised trading system. But the level of integration implied by this strategic choice must be sufficiently comprehensive if it is to make up for the reduced capability of countries to respond on an individual basis. This process of regionalisation may well be a prerequisite for regulating the world economy in such areas as exchange parities and financial speculation.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">And what of Europe in particular? Despite having a head-start on other regional groupings (such Asean, Nafta and Mercosur), the situation is not too rosy. Owing to the lack of a full internal market, Europe is unable to compete on equal terms with the United States or Japan. The internal market still comes up against blocks in important areas, as evidenced by problems over the European employment pact. And there are a number of other defects which make the internal market insufficiently competitive in the context of globalisation. It is true that a more coherent environment has been created for European companies, with common regulations and rules of competition enabling them to distribute their goods and services among the EU's consumers. But despite the appearance of a domestic, or single, market, it is one which is devoid of a genuine internal policy in keeping with its size. This is what distinguishes it from the internal markets of the United States or Japan.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The explanation for the disparity may lie in the fact that the most recent moves towards the single market, through 'Single Act', date from 1987. This was before the upheavals which so decisively signalled the globalisation trend. Despite the criticisms sometimes levelled at it, it is a genuine single market which is largely open to the outside world (with only a few exceptions, notably as regards the Common Agricultural Policy, where it is recognised that there is a need for progressive adaptation). But there is still no single currency, nor is there a genuine common commercial and economic policy. The EU is unable to react to change at world level in the same way as its competitors. The common customs tariff, together with protective measures such as the anti-dumping regulations, are still not sufficient to solve all the Union's problems. What is needed on top of this is an active common policy component.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Yet, as the European employment pact makes clear, the EU holds a trump card in an increasingly interdependent world. The proviso is that it must speak with one voice, enforce multilateral rules and open up new markets for itself, because, as the document points out 'exports create jobs...'</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">In 1994, the developing world received 37% of global direct foreign investment ($84 billion) as against less than 20% at the beginning of the 1980s (the flow of foreign exchange is regarded nowadays as the principal factor influencing development). This is a spectacular increase but the resources are not 'fairly' distributed from the point of view of either the investing countries or the recipients. For example, southeast Asia is currently the world's most dynamic region. Yet, not to put too fine a point on it, it is virtually ignored by European investors. Only 3% of European overseas investment is directed towards this zone. Likewise, Europe's market share in the region is no more than 5%. The US has invested between two and three times more in south-east Asia while Japanese investment is four times higher.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">In 1994, sub-Saharan Africa attracted just 0.8% of direct foreign investment ($1.8 billion). And there is no evidence that Europeans have invested more than the Japanese or Americans in this region. This is despite the highly optimistic outlook for the situation in Africa offered by the late Ron Brown, the former US Trade Secretary. On returning from a tour of Africa with American businesspeople in February 1994, he remarked that major opportunities were opening up in that continent, with spectacular returns on investments  - at the time, the best in the world. His regret was that so few people were aware of the situation. Undoubtedly more significant still was the declaration made in Washington before his departure for Africa to the effect that the United States would no longer leave African markets exclusively to the former colonial powers.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">So although others are beginning to explore the possibilities offered by Africa, Europe is still sceptical. A similar scepticism prevailed during the 1960s when it was assumed that the lot of south-east Asia would be famine, and few development prospects. Given the historical links between Europe and Africa, the geographical proximity of the two continents, and the pressing problems faced by the 'old' continent vis-&agrave;-vis its competitors, such an attitude appears difficult to explain. In the years since the former European colonies in Africa gained independence - and despite the creation of an institutional cooperation framework (the Lom&eacute; Convention, which many regard as a model of development cooperation)  -  many Europeans clearly no longer wish to be involved in Africa. The explanation for this lack of interest may be the difficult conditions within African countries -  obstacles preventing access to markets, the lack of liberalisation or political instability.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">But this analysis in not entirely convincing. More ACP countries are democracies than ever before in the post-independence era. As for Africa - a much-debated ACP region  -  it is wrong to talk purely in terms of internal conflict, famines or the AIDS epidemic. There are countries in this continent with growth rates of between 5% and 6%, and several examples of where European companies have successfully penetrated local markets.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The need to highlight the existence of genuine business opportunities in ACP countries and to make the European public aware of development aid success stories, were among the main conclusions to come out of the first meeting of a television delegates' network, organised by the European Commission's Development Directorate-General on 31 January 1996.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Any European company chairman interested in expanding into an ACP country - thereby enlarging the company's market and enhancing its competitiveness - is likely to acknowledge the possibilities, if offered back-up from the EU or from national governments. But they will then probably point to the complications which remain -  and with some justification.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">With this in mind, it is worth reiterating the fact that specialised institutions exist for facilitating contact with the ACP countries. In 1995, for example, the Centre for the Development of Industry (CDI) was involved in 367 projects, assisting, free of charge, in the expansion or rehabilitation of industrial companies in ACP countries, in partnership with European business. Although the number of such projects is constantly increasing (190 in 1993,229 in 1994), it is still a long way short of what is needed. But it should be stressed that the CDl's approach, which involves promoting the creation of networks, appears to work. The establishment OF ACP contact networks in ACP countries makes it easier to identify potential areas for involvement and to prepare better for European institutional and sectoral networks. There are several successful projects which have led to the creation or safeguarding of jobs in Europe.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Also in 1995, the European Investment Bank (EIB) granted ECU 430 million in loans to businesses in various sectors in 29 ACP countries. This includes an increase in the Bank's activity in Africa over previous years.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">What, then, of the effect of Europe's development cooperation policies on the European market ? According to the most conservative estimates, for every ECU 100 granted in aid, the Community 'gets back' ECU 48 in the form of jobs, supplies and technical assistance. This figure does not take account of additional 'secondary' business generated by, for example, the supply of spare parts or the provision of technical advice. This business can be quite significant given the degree of penetration achieved by European companies in the markets of many developing countries. Nor does the estimate include any new business opportunities directly arising from the links established between the companies involved in aid projects and the recipient countries. Thus, it is clear that when a project is set up, it may well have extra beneficial effects for Europe through additional flows of goods and services.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The 'return' on aid is even greater in Member States' individual bilateral programmes. For example, tied aid from countries such as Belgium, Italy and the United Kingdom leads to a payback of more than 70%. Another point is that as Europe's industrial rules are harmonised, the success of a single European company in penetrating a particular developing country market may pave the way for companies in other EU Member States, thus benefiting the Union as a whole. Tied aid creates favourable conditions for setting up European companies and for placing European goods and services in other markets. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">While the return on aid may be described as satisfactory, the same is not true of the number of companies that benefit or of the actual turnover involved. One wonders whether this weakness is due to a lack of information about existing resources and facilities, or whether there still a lack of confidence about countries which, despite the progress they have made, are still politically unstable and therefore unpredictable.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">One might also wonder whether the time is right for investment. Our answer would be that, even though financial speculation is currently governed by global economic considerations, which prevent productive targeting of capital, this situation cannot last. There is a worldwide move to rectify the situation.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">We all need to be aware that time is no longer on our side. In many sectors, European companies still have a competitive edge over businesses from third countries, owing to their degree of specialisation and technological expertise. But if they are to survive, they must take on a worldwide dimension. In particular, they should pay attention to the comparative advantage that they have in the ACP countries on account of their special skills, historic links, geographical location and, above all, the institutional connections between these developing nations and the 'old' continent.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Although problems do exist and although both European and ACP bureaucracy can sometimes discourage private operators from exploring the potential of the developing world (and more particularly the ACP region), they should not give up. Europe's challenge is to help them to exploit this potential whilst not raising false hopes.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Nothing can take the place of the shared experience and confidence which arises spontaneously in full knowledge of the facts. In this regard, we feel, there is still much to be done. In both Europe and the ACP countries, one way to succeed is to increase the number of networks representing industrial, economic and financial interests at various levels, and to assist them in identifying opportunities more effectively. This would help to create a new dynamism and renewed vigour in Europe. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<B><P ALIGN="CENTER">&lt;&lt;TOC2&gt;&gt; Close - up</P>
+</B><P ALIGN="JUSTIFY"></P>
+<B><P>&lt;&lt;TOC3&gt;&gt; Eritrea: the start of a renaissance ?</P>
+</B><P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">In the Courier's issue of July-August 1994, we published a country report on Eritrea. This country became independent in 1993 after almost 30 years of fighting which had bled the county white. Loss of human life, displaced persons, socio-economic disruption and environmental damage have been Eritrea's sad fate in recent times. However, there has now been peace for three years and the Eritrean people are attempting to pick up the threads. Alfonso Artico, a freelance journalist who recently travelled to Eritrea, now offers us a few on-the-spot impressions of his trip, focusing on some current projects which offer hope to this sorely afflicted people</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Fisheries at Massawa</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The port of Massawa is located on the Red Sea, whose blue waters are teeming with fish. In 1986, the European Union suggested that it would be a suitable place for fisheries development. At the time, the city was a maze of back streets, baking in the sun. Few could have predicted the fate that would befall it five years later. For in 1991, war came to Massawa and 80% of the city was destroyed.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The Italians, it is said, have 'always' been here, and they once had great plans for the city. Together with Assab, further to the south, Massawa was to be a key point of access to the sea, and a potential launch pad for the, country's struggling economy. The colonial days are long past but, when the Eritrean Popular Liberation Army took over the country after the recent war, the Italians came back to help tackle an immense task. The city, by then, was little more than a pile of rubble.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Help also came from somewhat further afield, in the shape of Professor Seichi Etoh, a Japanese specialist in marine biology. He had made a study of the city in 1989 and he chose to return in 1992 to help in fisheries development. At the outset, his working methods disconcerted the Eritreans who were used to a slightly more relaxed attitude to labour, under the hot sun and eternally blue sky.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Armed with the experience of working in Kenya and a number of other developing countries, Professor Etoh arrived in Massawa and installed himself in a house looking over the sea. After a period of adaptation, to gain his bearings, he took up his new challenge.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The challenge in question is a fisheries project whose main funders are the UNDP, Japan, Italy and the African Development Bank. A total of $7 million has been committed with payments spread over a five-year period. The project began operating in January 1993.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The main problem at the outset was one of skills and qualifications. Important posts were often filled by high-ranking former solders, whose administrative skills were less than satisfactory. Conversely, those with the right qualifications - some of whom were criticised for spending the war years in the lecture theatres of European universities  -  had problems finding work. This was particularly true in the closed and conservative world of the fisherman. After a few teething troubles, Etoh was able to announce that he had the confidence of the government, and his efforts rapidly bore fruit thereafter. He set about reorganising the fishermen's cooperative - a task which entailed overcoming the reluctance of members to adopt new practices. He also arranged for the construction of jetties where vessels could take on supplies. Fish were to be unloaded at one spot, and their diesel tanks would be refilled at a different location. The cost of diesel is 1.41 birr (ECU 0.17) per litre. The fishermen's cooperative, which has 440 members, has 35 000 birr (ECU 4000) in its funds. It is also making repayments on a 1.8 million-birr (ECU 200 000) loan.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">'In the beginning, there was frenzied activity, which some regarded as chaos', Seichi Etoh recalls. However, in less than two years, the jetties have been completed and the ice plants -  essential for preserving the fish - are running flat out. Now they are producing eight tonnes of ice a day. The daily catch is about two tonnes of fish.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The real revolution occurred when Seichi Etoh decided to try and organise cooperatives for women, who represent 25% of the workforce in the production chain. He followed up with an even more radical scheme, offering them paid work in the relatively unrewarding but essential field of ship maintainance and repair. This freed the fishermen, most of whom had no remunerative activity outside the fishing season (November to March), to seek work elsewhere during the other seven months of the year. Eritrea, a country where women's potential has not traditionally been acknowledged (or tapped) had never seen the like before. Nowadays, of the 200 who fish out of Massawa, 50 are women who have formed their own organisation - and they generate a considerable profit. They have even opened up a fish restaurant!</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The overall standard of living has increased considerably. This year, fisheries-related production has risen 120% compared with 1995. And the port is doing reasonably well in quality terms. Using the international scale, which ranks the catches from 0 to 10, the quality of fish landings by the Massawa fishermen is rated 6 overall - as against 8 for Japan. 5 for China and 6.5 for Europe. The local market has expanded as a result of efforts to modify local eating habits. People have been taught to grill fish instead of frying it in expensive (and somewhat unhealthy) oil. The message - 'eat grilled fish' - is going out daily on national radio, and women are going into the schools and villages to teach this 'latest' cooking technique.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The local market may be important, but the main target for the increased production is Ethiopia. With the purchase of four refrigerated lorries, it is now possible to transport fish products over long distances. Another important customer is Italy, which currently takes about a third of the total production. Seichi Etoh is hopeful that, following this example, new markets can be found in other parts of Europe.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The success of the Massawa project has exceeded all expectations and, although he downplays the achievement with typical oriental modesty, it is clear that Etoh's bet has paid off. The fishermen have come to understand the advantages to be gained in reorganisation and maintaining their 'tools' of production. And as anticipated, the bulk of the profit from the project is going back to the fishermen. The government has taken care not to cream off too much for itself.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Other projects are now under way. Etoh is attempting to persuade the fishermen to give up their wooden craft in favour of ferro-cement vessels but after centuries of doing things in a certain way, it will take more than a few months for the new plans to be adopted. The monthly meetings with representatives from the cooperatives are stormy and animated. However, two vessels are already being built, on the assumption that a practical demonstration is worth far more than a long speech. The 60 people working directly on the project are awaiting the outcome.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">This change has become necessary owing to the cost of wood - which is one of the reasons why the fishermen have grown progressively poorer. Timber prices have been rising sharply for some years, particularly in Dubia, the regional centre of the wood trade. The war, in the meantime, sent incomes spiralling downwards.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Overall, the Eritrean fishing fleet has 500 vessels, all made of wood, of which 250 have Massawa as their home port. In previous years, the wood (known as tengi in Eritrean) came from Ethiopia. But this country is facing ecological problems and fishermen have been forced to search elsewhere for building and maintenance materials for their unstable and costly vessels (a 13-metre boat requires 8 m³ of wood). Etoh explains that the new boats, while slower, glide more easily over the water on account of their stability. However, the first attempts at change have not been easy. Indeed, things got so bad that Etoh went on holiday 'for longer than expected', he said, though he took advantage of the break to visit Singapore and buy Chinese tricycles  -  which can now be seen in the streets of Massawa. The reign of the bicycle with a simple wicker basket which could carry just 20 kilos is over. Now, each tricycle can deliver 100 kg of fresh fish, packed in ice. All in all, the programme is running smoothly. Etoh has only to check it from time to time. After all this labour, will the smiling Japanese professor be taking a well-earned rest? 'Probably not,' he says, adding 'I am currently thinking about a chain of restaurants. Fish restaurants of course !'. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">An unusual 'bank'</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The road leading to Gersteti village is so beautiful that it takes your breath away. Multicoloured birds fly lazily above the vehicle carrying the journalists and humanitarian aid workers - who are deep in discussion about the kind of world they wish to create. However, there is a switch in the conversation once they reach the Seraye plateaux. Their attention is drawn to the fields which stretch as far as the eye can see. It doesn't take long to discover that demand for land here far outweighs supply. The situation, which is already critical, has not been helped by the influx of refugees returning from neighbouring countries.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">When the war ended in 1991, everyone's prime concern was to relaunch an agricultural sector ruined by 28 years of combat. Farmers and farming communities, the lifeblood of the countryside, had been mobilised to fight on the front line. In 1990, agricultural production was at such a low level that the word 'negligible' featured prominently in the Ministry of Agriculture's statistics.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Oxfam, which first came to Eritrea in 1978, has been running an unusual project on the Seraye plateaux. Located to the south of Asmara, the capital, this region is the second most densely populated part of the country. Five districts containing 65 villages and 17000 families, were chosen for the project  -  on account of their low rainfall and the fact that it is difficult, and in some cases, impossible, to cultivate the exhausted soil. Local communities, village leaders and politicians all understood that only full-scale collaboration could prevent a food-supply disaster in the province. An organisation was therefore created: the villagers elected 13 representatives (12 men and one woman) and began by setting up a seed bank. There was a severe shortage of seed materials in this devastated country. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The project got off the ground in November 1995 and is set to run for three years. Its objective is simple: to guarantee self-sufficiency in seeds and to provide a reserve during hard times. The 'Seed Bank Committee' has also given training to 40 farmers in seed conservation, terracing and basic agricultural economics. Two wells have been sunk, but these are insufficient for the 40 square kiLom&eacute;tres that require irrigation. Oxfam is putting up the money for the various initiatives while the local community is providing the labour force. It is worth noting that a bag of averagequality cement costs 35 birrs (ECU4), equivalent to one third of a worker's monthly wage. Fourteen different varieties of seed have been stored in sheds - which the locals visit to obtain their supplies. The purchase of 230 quintals of local seeds and the donation of 70 quintals from elsewhere have started the programme off. Next year, Individual farmers will have to repay this 'loan' in kind, with a 10% 'interest payment', also in the form of seeds. The surplus generated will be retained by the bank as a resource to be drawn upon, if necessary, when times are hard.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Advantages</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The local community was quick to understand the advantages to be gained from this system. They were all too aware of the low productivity of their land and up to then, were powerless to resolve the situation. The possibility of falling back on traditional resources to offset production difficulties no longer existed. And the skills they had acquired over the generations were now insufficient, given the poor condition of the soil. In these circumstances, one can well understand their enthusiasm when they saw that 100 kg of seeds per hectare yielded a harvest six times larger than previously. Other elements which contributed to a progressive improvement in conditions were the sinking of new wells, a reduced influx of refugees from Sudan, and a slow but appreciable improvement in the country's general economic situation.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">As well as being involved in this project, Oxfam is an active member of Acord, an NGO association which extends cash loans at rates much lower than those demanded by the banks. (Acord's rate is 12% per annum with a minimum repayment of 5 birrs per month). Targeted mainly at the most deprived sections of the population, the loans enable the poor to set up small businesses or, more commonly, to purchase agricultural implements, repair irrigation channels and buy cattle. Once again, a village committee manages the transactions. The scheme has brought renewed hope to the most deprived groups. Individual loans have been available since 1994 and the association currently has 163 clients. The total amount lent so far is 878 000 birrs (ECU 110 000).</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The combined effects of these programmes - seed banks and preferential loans - are already visible. It would take months to visit all the farms and fields, workshops and stores, where men and women have invested their energies and hopes. Seraye province now produces a third of Eritrea's cereals, a telling illustration of the fact that one does not need billions of dollars for development and humanitarian aid for the work to be effective. In the final analysis, a country's wealth lies in its citizens. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">An up-to-date printing plant</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">As one strolls down Liberation Avenue, which cuts the city of Asmara in two, one might be forgiven for thinking that 28 years of war have already been forgotten. Surveying the multi-coloured neon signs of the shops, it certainly appears as if the country has turned the corner and the wounds are healing rapidly. One building whose restrained frontage stands outs in sharp contrast is the Adulis printing-works. Adulis was the name of a semi-mythical city founded by the Greeks on the Red Sea in the third millennium before Christ. 'But there is nothing insubstantial about this place', comments Mohamad Shiffa Osman, with a smile. He is one of three expert typesetters who went on a training course in Belgium earlier this year.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY"> The Adulis printing works has its own particular memories of the Eritrean people's struggle for independence. As far back as the 1960s, when the first shots were being fired, the resistance recognised that their fighters and the civil population both had to have access to information. However, it was not until the 1980s that a true propaganda structure came into being. During the war, the Eritrean People's Liberation Army ran a clandestine ministry of information. In Eritrea and elsewhere, this became the channel for conveying practical information, and providing the latest news from the front. It was also used to transmit personal messages, which were delivered to the heart of areas occupied by the Ethiopian Army. 'Our presses were hidden in caves, up in the mountains, and everything was run on generators', Mohamed remembers. The initial amateur approach was quickly replaced by a more professional one. 'We did have professional printers working for us, but it was mainly self-taught comrades'. On-the job apprenticeships had to be fitted in between bouts of fighting!</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">'At the time of liberation, in 1991, we set about restoring this printing works, which was founded in 1896 by the Italians', Mohamed explained as he gave us a guided tour of the works. The effort put into relaunching this essential activity soon bore fruit. Within the year, the printing operation was running at a profit - indeed it had a virtual monopoly of printing in the country. The presses were brought down from the mountains on the backs of camels and then taken to Asmara by truck. 'You see this Aurelia 48?', asks Mohamed, pointing to a machine. 'Well, it was up in the north, hidden away in a village'. Throughout our visit, Mohamed draws attention to equipment from an earlier age  -  candidates for the museum which are still in operation.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Some items have their own story to tell, like the press donated years ago by Oxfam which still churns out thousands of sheets every day. During the war, it was taken from cave to cave, following the army's advance as it conquered new terrain. Most of the Adulis machines, however, were already there, when the decision was taken to restart the operation.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The initial budget for the works was a tidy five million birr (ECU 620 000). Today, Adulis has an annual turnover of 20 million birr. Monthly salaries range from 400 birr (ECU 50) for maintenance staff to 1800 birr (ECU 225) for the director, Michael G. Bakhli. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The printing works also acts as a testing ground for workers' social progress. According to Mohamed and the director, the 350 or so people employed at the works benefit from exceptional social cover. If a worker falls ill, his wage is guaranteed for one month, then it drops to 50% in the second month and stops altogether at the end of the third. if a woman is pregnant, she has to take a month's statutory leave and is granted a further two months on full pay. In the event of dismissal, an employee receives two months' wages, although this latter arrangement is gradually changing to one month's wages for each year of service.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Far from resting on the laurels of their success, the Adulis works' directors have appealed for assistance. In order to be at the cutting edge of technology and to have the resources to break into new markets, they need to supplement their knowledge. Therefore, three 'volunteers' spent the three months from January to March this year working in Belgian companies, to the satisfaction of everyone, both hosts and visitors.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Under Mohamed's gaze, the walls of the workshop have been brightened up with posters which provide a splash of colour. Although the noise from the presses often drowns out conversation, you cannot escape the feeling of hope here. It is like a breath of fresh air, and one leaves with the strong impression of a country that is rising from the ashes. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<B><P ALIGN="CENTER">&lt;&lt;TOC2&gt;&gt; Developing world</P>
+</B><P ALIGN="JUSTIFY"></P>
+<B><P>&lt;&lt;TOC3&gt;&gt; ECHO fine-tunes disaster preparedness strategy</P>
+</B><P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">by Eva Kaluzynska</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">When a cyclone strikes in the Caribbean, beware of giant flying razorblades - airborne sheets of corrugated iron that kill and maim unsuspecting victims every time. 'The use of galvanised iron sheeting for roofing is extremely dangerous in cyclone-prone areas,' says Professor Debarati Guha-Sapir, Director of the Centre for Research on the Epidemiology of Disasters (CRED) at the Universite Catholique de Louvain. 'We know this, and we need to encourage the use of lighter materials, such as thatching, which doesn't kill if it flies off in a gale,' she adds.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">That is the kind of issue facing people exposed to unavoidable natural disasters  -  in the Caribbean's case, every year. In 1995, there were 27 tropical storms in the region. CRED has been in the vanguard of monitoring natural disasters and in coming up with solutions to the problems they create since it was set up in 1973. Now it is assisting the European Community Humanitarian Office (ECHO) in developing its new Disaster Prevention, Mitigation and Preparedness Programme (DIPECHO) to cover the next two years.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Since 1994, ECHO has spent almost ECU 7 million on 50 disaster prevention operations, at both national and regional levels. Now, instead of just responding to requests for funding from non-governmental organisations, international organisations and governments, ECHO has decided to fine-tune its strategy. It will concentrate its efforts on specific regions known to be particularly vulnerable and prone to natural disasters. We may not know exactly when disasters will strike, but we certainly know where to expect them. The regions selected at present are: the Caribbean, Central America, South East Asia and Bangladesh.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">All of them are exposed to repeated emergencies. All of them have a struggle to develop when their efforts are disrupted so frequently. They cannot just pick up where they left off. Loss of life and property is just the most visible aspect of what happens when disaster strikes.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The infrastructure, such as it is, takes a hammering. Road and rail links are severed. Communications, electricity and water supplies break down. Add loss of health care and sanitation, and you get populations exceedingly vulnerable to epidemics. Add loss of education facilites, and a vicious spiral of poverty sets in.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">An expert in emergency aid cites the sad example of the Aetas, a tribal group that used to live a secluded life on the remote slopes of Mount Pinatubo, the volcano that erupted spectacularly in 1991 in the Philippines. Though the volcano was known to be menacingly active, the Aetas were not evacuated and resettled in time. They fled in panic as disaster struck, to the plains, where they faced a deadly, invisible enemy: measles, a disease to which they had never been exposed. Measles claimed more victims than the volcano itself did in the months that followed. They could have been resettled earlier. And they could have been immunised years before, but weren't.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">It's easy to be wise after the event. DlPECHO aims to encourage action before it's too late. The idea behind ECHO's new policy is to take each region, and to identify its hazards and capacity for dealing with disasters. This will help to pinpoint the gaps. Then it will draw up Action Plans that slot into the wider picture of potential development in each case.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">DIPECHO projects will involve training personnel in the regions affected to handle disasters, and to strengthen the institutions that can contribute to effective prevention, preparedness and mitigation.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Some of the solutions are ingenious, low-cost, low-tech ideas. Take, for instance, the use of light, widely-available, inexpensive materials for roofing in earthquake or cyclone-prone zones - an idea poorer countries could adapt from wealthy Japan's experience. Or the construction of safe, raised 'islands' that will stay above the waterline amid flooding in Bangladesh to offer shelter. Or adapting drainage, and changing cropping patterns in Andhra Pradesh, India, to mitigate the effects of cyclones.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">In earthquake-prone Central America, protecting roads and bridges, or building schools less prone to collapse is very important. Using the radio or even neighbourhood watch systems to sound the alarm when disaster is imminent can make a big difference to its impact in terms of injuries. Drilling all at risk, from school-age up, to know what to expect and to know what to do is vital.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">DIPECHO did not include Africa in its first selection of regions for Action Plans. This is not to underestimate the gravity or scale of the disasters experienced there, says Professor Guha-Sapir: 'Floods, drought and famine are very frequent events there.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">They are often killers.' Overexploitation of scarce resources and political turmoil compound situations that lead to disasters which seem less dramatic than a volcano eruption, but are no less far-reaching in impact.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The instability in many of the areas worst affected means that African countries lack the institutions needed to prepare for disasters in an organised way, she says. 'There are limits on ECHO's ability to intervene. It's unrealistic to expect the kind of grassroots, technical preparedness we are talking about in the current situation.'</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">ECHO's Jean-Claude Heyraud sums up the new policy: 'As far as preventing, mitigating and preparing for catastrophes goes, the new proactive approach reflects the importance ECHO attaches to this type of action. The DIPECHO programme meets the growing need to evaluate risks in order to reduce loss of life and damage to property. If and when emergency aid is needed, preparation and prevention can help to reduce the scale and cost of such actions.' </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<B><P ALIGN="CENTER">&lt;&lt;TOC2&gt;&gt; Culture and society</P>
+</B><P ALIGN="JUSTIFY"></P>
+<B><P>&lt;&lt;TOC3&gt;&gt; African reflections</P>
+</B><P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">by Seydou Sarr</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The third Festival of African Cinema was held in Brussels on 15-22 June. For one week, film-goers in the Belgian capital filled the auditoria of the Palais des Beaux-Arts, where they discovered new images of an alternative Africa. And as always, when the time came to assess how the Festival had gone, professionals and organisers alike were left pondering the problems facing the African film industry.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Organised for the first time in 1994, on the initiative of Diaspora Productions, the Festival had a number of objectives, including that of bringing Africa's finest films to wider public notice. The initiative stemmed from two observations. In the first place, the European public's opinion of Africa is based on what it sees on television -  and that image is of a continent so ravaged by famine, misery and strife that it is incapable of progress. Second, from a professional standpoint, there is no effective distribution network in Belgium for African films. Samba Traore by Burkina Faso's Idrissa Ouedraogo and Hyenes by the Senegalese Djibril Diop Mambety were two rare exceptions in succeeding in getting on to the circuit.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">A forum for reflection</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">In setting up film-industry meetings, the organisers of the Brussels Festival wanted the event to be a forum for reflection on the problems facing African cinema. In the 40 years it has existed, there has undoubtedly been some progress. It is even possible to speak of genuine mastery of images and cinematographic language. But there are also many problems -  involving production and distribution, a lack of official support, a shortage of private capital and limited access to international markets. At home, meanwhile, African firms face fierce competition from multi-million dollar productions coming out of the USA, Europe and Asia. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Europe has traditionally offered the only feasible route for those seeking technical and financial resources. The principal donors are the European Union, the ACCT (Cultural and Technical Corporation Agency) and the French Ministry of Cooperation. There are, of course, many instances of African directors producing films without taking this route, but these ventures usually have smaller budgets, and insufficient funds to devote to promotion (press releases, trailers etc). As regards distribution in Belgium, directors face an additional difficulty - they have to take the language issue into account (particularly when films are shown in Flanders).</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">African professionals are looking at various ways of solving these problems, including the possibility of coproduction with European operators. For some years now, public and private bodies have also been considering the idea of establishing combined co-production teams in a form of partnership, as a way of supporting African cinema. This topic has been on the agenda of other African film festivals (notably in Amiens) and it came up for discussion in Brussels as well.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">A colloquium on the subject of ACP/Europe co-production was staged on the fringe of the Brussels event. This served to highlight a number of successful experiments in North/South collaboration. One example was the Cape Verdian film Ilheu de Contenda, by Leao Lopes which was made with support from a Belgian production company, Saga Films. This film was screened at the Festival. It also gave an opportunity to discuss a range of other topics. African journalists accredited to the Festival were given the task of drafting a resolution whose conclusions will be submitted to various contributors including FEPACI (the Pan-African Federation of Film-Makers), the European Union, producers and other donors.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">There was general agreement that a coherent legal framework for organising relationships between directors and producers, on the basis of mutual trust, was badly needed.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Positive results</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">It is worth making a brief assessment of the efforts made by the organisers of the Brussels Festival to offer an improved programme. The showing of shorts at the beginning of a performance is undoubtedly a formula they should employ again. These works are a specialised genre which give young directors the chance to present their first work. The bulk of the shorts that were screened this year were in the form of 'documentaries' based on fiction - but with one foot in the real world. They dealt with people's lives, their daily concerns, and a variety of social phenomena. Thus, we were presented with films dealing with Aids, urban delinquency, the role of women in society and so on.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Another positive point the organisers should concentrate on is the space resewed for English and Portuguese-language films. There were eight performances in this category including four feature films in English and two in Portuguese. A further worthwhile element was the space allocated to African women (from Nigeria, Kenya, Zimbabwe and Burkina Faso) who have chosen to use the cinema as a means of expression.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Diaspora Productions' managers are said to be reasonably satisfied with the way the Festival went. They hope it can continue to be held at the Palais des Beaux-Arts, since they see this as one way of liberating African cultural events from the Afro-Brussels 'ghetto' where they have often been held. They are also keen, in future years, for African films to be shown in Brussels cinemas while the Festival is under way. If this happens, film-goers in Brussels will have the pleasure, from next year, of seeing quality works in their usual cinemas. The timing is appropriate since the 1997 Brussels event will follow the Ouagadougou Festival (Fespaco) which traditionally sees the launch of a number of new films.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Family meeting</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The organisers chose to close the 1996 Festival with a fashion parade which gave Pathe 'O, the designer from Cot&eacute; d'Ivoire, the chance to present his collection to the Brussels audience.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">On the fringes of the Festival, there was also a musical offering in the shape of the Toure Kunda brothers who came to lend their support to filmmakers and other African artistes.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">There are those who would argue that the Brussels Festival has now entered the category of a 'not-to-bemissed' event. Every year, it attracts significant numbers of film-makers from Africa and the diaspora, even when they have no current projects or films to present. There was a real family atmosphere in the corridors of the Palais des Beaux-Arts, due in no doubt to the absence of competition. From the outset, the Diaspora Productions team chose to stage an event at which prizes were not awarded, thereby promoting reflection and contact with the public. It is generally agreed that the Brussels Festival offers a rare opportunity for film-makers to meet and discuss their productions and projects in a relaxed atmosphere.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The credit for this, in the view of many of the participants, lies with Pape Mbaye Sene, one of the guiding lights of the event, who has also been dubbed the 'high priest' of African cinema. It has, in fact, been suggested tongue-in-cheek that 'in Brussels, they award a Pape, not an Oscar'. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<B><P>&lt;&lt;TOC3&gt;&gt; 'We make films... but we do not exist!' - interview with Souleymane Cisse</P>
+</B><P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The future of African cinema seen through the eyes of the Malian film maker, </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">In April, The Courier had the opportunity of meeting Souleymane Cisse, one of Africa's most celebrated film-makers, who has won several awards at major international film festivals. His films, such as Yeelen, which was awarded the Prix du Jury in Cannes in 1987 (the first African film to receive such a prestigious accolade), Waati, which was entered at the same festival, and Finye, have already become classics. Cisse is not just a director, he also produces his own films. In 1972, he impressed international critics by single-handedly producing a short film of exceptionally high quality Cinq jours d'une vie -  which won an award at the Carthage Film Festival. By relying, above all, on his own limited resources, combined with a powerful determination to develop and promote Africa's film industry, Souleymane Cisse has an implied but powerful message for the entire African continent. When he went on stage at the Palais des Festivals in 1987 to receive his award for Yeelen, he said that he was accepting it on behalf of all those who did not have the opportunity to speak for themselves. In particular, he dedicated the film to all the South African technicians who had worked together with him on the project. His has made spirited efforts to boost the African film industry and it was in this context that he helped set up the 'Union of African cinema and audiovisual producers and entrepreneurs' last March. This organisation aims to encourage African countries (especially in West Africa), to take the necessary political decisions to ensure the survival and grouwth of African cinema. When we spoke to Souleymane Cisse, our discussion ranged far and wide. We began by asking the film director whether African art gets the recognition it deserves in Europe? He seemed surprised at the question but then, without hesitation, proceeded to explain his own approach - with the emphasis on the political rather than the aesthetic.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY"> - The recognition that African art gets in the West has more to do with politics than aesthetic discernment. Such recognition evolves from the spirit of Africa's relations with the other continents, a spirit which is often devoid of all honesty. We stand at the threshold of the 21st century. We should be looking to develop ways of communicating with each other and finding common ground. We should be able to look each other in the eye. When, for example, people in France debate whether or not the Louvre should have a gallery of African art, it begs the question, 'who is asking for what ?'. When some people wonder whether or not African art really is art, they are asking themselves a pointless question. African art is. Nothing more, nothing less. In any case, the West has some highly contradictory views as far as the whole idea of art in Africa is concerned. On the one hand they dispute the fact that the culture of the Ancient Egyptians was, in essence, an African one, and yet on the other hand the characters of Ancient Egypt - in films for example - are always portrayed as dark-skinned. African art is the 'in' thing at the moment, despite the current tendency to belittle Africa. They think that today's Black Americans and Afro-Caribbeans can be made to forget their African roots, but that just will not happen.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">· Generally speaking, do you think that African politicians should devote time and energy to this battle to defend African culture when their countries face such insurmountable material problems ?</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY"> -  Once they have gained power, the obsessive preoccupation of our politicians has been to concentrate on economic policies, neglecting their countries' cultural needs. But without a deeply-rooted culture, you cannot discuss matters on equal terms with representatives of other nations. In their heart of hearts, they will not respect you fully. There have been two or three countries which have tried to combine economic development with cultural development - I'm thinking of Guinea under Sekou Toure, Mali under Modibo Keita and Ghana under Kwame Nkrumah, but in one way or another, all three have been thwarted, for their perceptiveness. I am not now commenting on, or necessarily agreeing with, their domestic policies, but rather with the broad vision they shared for Africa as a whole. The fact that Europe is currently in the process of forging the European Union will be an instrumental force in the opening up of other regions of the globe. It was Europe, after all, which divided much of the world into English speakers, French speakers, Portuguese speakers, Spanish speakers and so on. Now that Europeans are themselves seeking to unite their countries, how could they possibly object to a similar union in Africa - for the sake of its cultural identity. This idea of a United Europe is, therefore, a welcome one. What is more, I believe that the issue has already been tackled within relations between the European Union and ACP countries. Not only is Africa the continent closest to Europe; it is in helping to develop the African continent that Europe has most to gain.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">· The cultural aspect has already been incorporated into Lom&eacute; IV, but it seems that ACP countries do not attach as much importance as they should to such matters when drawing up their lists of priorities.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY"> - Many of the politicians in charge of these countries themselves lack any sort of culture. Alternatively, stripped of their own culture, they flaunt that of a foreign land. They say that health care is a priority, that food is a priority, but cultural needs do not figure on their list. Yet culture forms part of an urgent need. You'll see - as soon as any sort of cultural development takes place in a country, or wherever a country already has a viable, thriving culture, its economy will also flourish; of that there is no doubt. A nation which has a highly developed culture will always be able to stand on its own two feet economically. Take, for example, the nations of the former Soviet Union  - their economies may be unstable at the moment. It's only natural that they have to start from scratch, but as long as they manage to hold on to their cultures, they will pull through. These countries will not lag behind as Africa has done.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">· It costs money to operate a film industry. Have you found that your reputation as a director has made the financial side of things any easier for you ?</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY"> - I don't honestly think much has changed in the way we finance our films. Perhaps I should only speak for myself, but I do not believe it is any easier for me than it is for young filmmakers. Mali has no film production facilities, so we are all in the same boat. That is why we organised a colloquium in March this year, aimed at getting a picture of the exact state of West Africa's film industry. What we learned was that it is in pretty bad state. We make films but, in a certain sense, we don't really exist as a film industry. I would dearly like my works to be screened, for example, in Mali, Guinea and Senegal, but that is not possible because the distribution and screening networks are no longer there. Even the most liberal Western countries have passed laws to promote and protect their local film industries, so why don't we do the same ? I cannot make films in the United States without first going through various unions and other professional associations. In France, I cannot distribute my films the way I want, and if I want to make a film, I have to make it through French producers. If people come to work here, they should have to use national producers. The relevant laws were drawn up three or four years ago, but they still haven't been passed. We want all those involved in the film industry to have the opportunity to be true professionals. There should be assistance available to modernise projection rooms and theatres. We are currently in the process of setting up the 'Union of African cinema and audiovisual producers and entrepreneurs' which should help to persuade governments to take our requests into account.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">· Isn't African cinema also a victim of television ? </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY"> - The problem in Mali is a very simple one. We live in a country where people like to get out and about. The cinema is somewhere they can do that quite easily. So people use it as a place where they can meet up in the evening, just as they like to congregate around the fire to sing and dance. So why are our cinemas empty ? Because when people do go to the cinema, they cannot see the screen properly or they cannot hear the soundtrack, or they are uncomfortable sitting on broken and rickety chairs. If you can provide a suitable and comfortable environment for them, people will start going to the cinema again. That doesn't mean that television doesn't have its place, but people like to go out. This is especially the case with our open air cinemas, which are the perfect places for people to come together, have a chat, enjoy each other's company and relax. A nice auditorium, a good film, and you'll see how the queues will form. All we need to do is upgrade the auditoria, re-equip the projection rooms, overhaul the sound systems, put new chairs in - just a few basic comforts. When people go out to the cinema, it's because they want to escape from their humdrum routine for a while, to dream and unwind.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">African governments should do what they can to enable people to relax and enjoy themselves like this. Going to the cinema is like going to school. People go there to learn something - whether consciously or subconsciously - and to see something different. We really must get rid of this purely commercial vision of the cinema, especially in Africa. It should, first and foremost, be a cultural experience, and only subsequently a commercial exercise. But we also need to be realistic. When helping those involved in promoting the film industry, the government should lay down a precise set of conditions, specifying how and when the loans should be repaid and requiring something in return for their subsidies.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">· So you think that if the Ministries of Culture in African countries were given greater powers, they would be in a position to carry out this task ?</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY"> - It is not something solely for the Ministry of Culture. This is the type of approach which should be adopted by the state as a whole, in each country. For example, the government should provide a support fund for the film industry and certain other branches of the arts. Even if they were increased substantially, the meagre budgets allocated to the Ministry of Culture in our countries would still represent paltry sums. In Africa, the department of culture is at the bottom of everybody's list.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">· But if you look at the number of African films that have been shown in recent years at Cannes and other international festivals, surely one can afford to be a little more optimistic than you are ? More and more young African filmmakers are releasing films.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY"> - True, but as I said earlier, no progress has been made as far as film production is concerned. In that respect, contrary to what people may think, we are still at square one. Young filmmakers are put off and, as more and more avenues are closed to them, they gradually lose their fighting spirit. A film director has no choice but to be his own producer, his own manager - to do everything himself in fact. The result is that he becomes a jack of all trades and a master of none. During our recent colloquium, we decided to set up smallscale facilities which will deal solely with film production and where young people can go and use their services, thus leaving them free to channel their energies into actually directing their films. In the same way, we intend to set up other structures which will deal exclusively with other aspects of the cinema industry. The goal we have set ourselves is that of fostering professionalism in the West African film industry. Maybe then our governments will listen to us.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">· Do you think there is any difference between African countries as far as opportunities are concerned ? For example, Burkina Faso would appear to be the cinema capital of Africa.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY"> - Yes, and no. More often than not, it is African film-makers who have chosen Burkina Faso to stage events connected with the cinema industry because it is a landlocked country. This is what has made it the film capital of Africa, not any deliberate move on the part of the politicians. Having said this, the government in Burkina Faso is also making great efforts, despite its limited resources. But each country has its own potential. We must stop trying to tear this continent apart.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">· You mentioned the former President of your own country, Modibo Keita, as one of those far-sighted enough to appreciate the importance of nurturing African culture. Where does Mali stand at the moment in terms of strengthening its own cultural heritage identity ?</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY"> - After independence, in the years from 1960 to 1968, there was a time when young people would get together and become involved in various biennial art festivals. We had a series of events which encouraged a kind of a 'cultural vision' nationwide. They were so successful that other countries were soon following our example. After the coup in 1968, however, everything fell apart. In the following 23 years there was a total cultural vacuum, in which young people felt completely disorientated, despite superficial attempts to relaunch the festivals. We are now only just trying to rediscover our cultural roots after a long period of upheaval. What we in Mali do have working in our favour, is the fact that our country is a harmonious patchwork of different peoples, all living together without the slightest trace of bitterness or hatred. We are lucky here because our rulers rarely tried to manipulate our ethnic loyalties to set one group against another. A Malian, irrespective of his roots, will always rejoice in the success of his fellow countrymen, whatever tribe they happen to belong to. We owe our good fortune to a heritage in which our peoples have always respected one another - even when they have faced each other as enemies. It is only as a result of this historic mutual respect that we can now speak of a Malian culture where each individual group of people has its own idiosyncrasies, its own customs, is sensitive towards other cultures and actually rejoices in their differences. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<B><P ALIGN="CENTER">&lt;&lt;TOC2&gt;&gt; CTA Bulletin</P>
+</B><P ALIGN="JUSTIFY"></P>
+<B><P>&lt;&lt;TOC3&gt;&gt; CTA and the promotion of rural development through book distribution</P>
+</B><P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">One of CTA's tasks is to provide information on request to researchers, extension workers, planners, farmers' organisations, trainers and information specialists involved in agricultural development in ACP states. In addition to requested publications, CTA also distributes publications on its own initiative to its target groups. These publications, some 550 titles, are also supplied free of charge and consist of books published by CTA, co-published, or purchased specially because of their relevance. In 1995, almost 65 000 books were posted to ACP countries.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The people who receive the publications to some extent select themselves, because they write to CTA with requests for information. They find out about its existence through attending CTA seminars held in ACP countries or in Europe, or through seeing copies of Spore (CTA's bi-monthly bulletin in English, French and Portuguese which goes to around 50 000 addresses and is seen by many more), or by word of mouth. Over the years, CTA has built up a mailing list of 42 500 addresses of people and organisations active in some way in agriculture and rural development. Of the total, 37 800 are in ACP countries.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">But there are questions. Are our books getting to those who need them and is the targeting accurate enough? And, most importantly, is this the best way of doing things ? For CTA does not - and cannot - satisfy the total demand for books on agriculture and rural development.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">What is the best way?</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Despite the number of addresses on the mailing list, many more people could in theory still be added. Should CTA even try to satisfy this demand ? The publications are free and, if CTA increased its coverage of the demand, it might in some countries hold back the development of local bookselling with a consequent detrimental effect on local publishing.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The majority of those now on the mailing list are 'individuals' rather than institutions, libraries, documentation centres, associations, organisations, etc. On the face of it, more people could be reached by sending CTA publications to groups rather than to individuals, but it's not always clear who is an individual in the sense of information not being shared with others. Some individuals are teachers, some are extension agents, some receive publications on behalf of a cooperative, for example.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Because of the importance of information - the driving force behind development  -  CTA has been investigating and giving support to technical publishing and book distribution in Africa over the last few years and is currently examining its own policy on book distribution over the ACP countries as a whole. Part of the context for this policy re-appraisal is the state of bookselling.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Difficulty of book distribution</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Everyone involved in the books business in and for the ACP countries knows that getting books where you want them to go, book distribution, is not straightforward. The reasons for the difficulty are not straightforward either. One development officer remarked of Papua New Guinea that the lack of books outside the capital, Port Moresby, couldn't simply be explained by lack of roads, because in the most out of the way places you could be sure of finding Coca Cola. Is it, then, that the Coca Cola company has superior marketing and distribution arrangements ? Probably so, but it is the nature of the two products which also determines how far they get. Traders will more readily take goods which they know they will be able to sell easily and the immediate satisfaction given by cigarettes or Coca Cola tends to put them before books in the list of priorities for purchase.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Among the ACP countries where CTA sends books and information, many have under-developed road and rail networks while the postal facilities provide a reliable service only to a relatively small part of the country. The local book publishing and bookselling industries are often themselves developing. Potential readers often cannot afford to buy the books and consequently book distribution is the weak link in the chain from writing and publishing a book to selling it. If books can't be sold, new ones can't be published, for the investment finance for a new publishing project has to come from somewhere.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">In Africa, the lack of a strong local book sector was attributed in part to the traditional oral culture of the continent which left little need for reading. The majority of students would read in order to pass their exams, after which they hardly sought books again to buy or to read.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The main books distributed were therefore textbooks for schools, colleges and for higher education. As long as these were distributed through booksellers, a forum still existed for displaying and raising interest in other books.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Booksellers could also function as sources and conduits of information about the variety of books in print and of their interest to particular groups.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">This development was stunted because of the low purchasing power of many people, lack of foreign exchange (except in the CFA franc states), high cost of importing (either books or the raw materials, print machinery and spare parts to manufacture books) and, consequentially, shortage and lack of variety of locally-published books.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">In addition, in some countries the state intervened in school book publishing and supply (for example in Tanzania), so that the bread and butter of the bookselling business disappeared.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Booksellers then either diversified their stock so that they became bookseller-stationers or worse - books came after groceries, footballs, hats, etc., or the booksellers ceased trading in books or closed down.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The publishing-distribution chain in Africa</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Book distribution is part of a chain of activities in the book sector which depend on each other and support each other. The chain starts with an idea for a book which may come from an author or from potential readers who make known their needs and it ends with the published books being bought. The lack of a good book distribution infrastructure in Africa is linked to the lack of a wide variety of books from a good number of publishers and the lack of a market for the books.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">At least until South Africa became a democracy, Nigeria probably had the most active publishing industry in Africa with a high level of publishing professionalism. In such a huge country this may not be surprising: there is a large market, state administrations with urban headquarters, and a variety of arrangements for publishing and distributing books. But publishers suffer from a scarcity of investment funds, with high costs of borrowing, which affects their ability to keep books in print and to start new publishing projects. Relatively few technical books are published locally because of the risks when compared with, for example, publishing school textbooks.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">In such a vast country, the state of book distribution varies from place to place, with cities and large towns obviously having a greater variety of books available for sale than small towns and rural areas. Small traders carry books to the latter; they do not take orders and the books they carry are those that they can get hold of which they think will sell. Would-be readers are frustrated unless they or their friends visit a city. Mail order is not a possibility because the domestic postal service is not trusted.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">In the urban areas, where there are booksellers, an indeterminate number of potential readers cannot afford to buy books, especially those that have been imported. Book piracy is a consequence of this. Booksellers' sales have declined, their turnover has been reduced as has their ability to stay in business. Some institutions in the country buy direct from publishers or from overseas suppliers rather than from booksellers, which further damages them. Booksellers buy books from publishers in small quantities for a fast turn-round which affects publishers' ability to build up investment funds for the next publishing project or for a large reprint with its possibility of reducing unit book costs.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">This is not to say that technical books are totally unavailable from Nigerian booksellers, but it is clear that only specialised outlets which know their book-buying customers well can risk stocking some of them. Rural dwellers have no chance of buying them without making a big effort in time and money.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">In contrast, Senegal has a less developed publishing and bookselling industry than Nigeria, with about a dozen professional publishers and a small network of booksellers, mostly in Dakar and the larger towns in the regions. The most important publishing opportunities in Senegal are in the field of primary school textbooks - where there is competition both within the country, with publishers from other developing states, and from the North. Senegal being a lot smaller than Nigeria, there is only room for one textbook, and primary school book production is not therefore the mainstay of local publishers. The publisher which used to supply all primary and secondary school textbooks for the Ministry of National Education is an exception and is still probably dependent upon educational publishing for its turnover. Few technical books are published; as with books for higher education, they are imported.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The network of booksellers has been decreasing and it is difficult to make a living just by selling books without the back-up of other products to sell. Thus there are bookseller-stationers, bookseller-grocers, kiosks and street sellers, especially of secondhand books. Booksellers tend to order titles in small quantities because they cannot risk being left with unsold stock which ties up their capital. They order little and often. Most school textbooks are distributed through the Ministry of National Education, but booksellers still sell a variety of textbooks, some official and approved and some not. Before the devaluation of the CFA franc, booksellers ordered more from abroad. These books have now doubled in price, making them unaffordable, with a consequent opportunity opened for local publishers to fill a gap.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Apart from the professional publishers, various sorts of publications are being produced and distributed by literacy and post-literacy organisations and a delegated literacy ministry. Some organisations promote literacy for its own sake, while others use the attainment of literacy as the means through which development can spread in rural areas. The publications concern rural development, agriculture, health and nutrition, and rural democracy, amongst others. There is a good variety of different titles and a good supply of cheap and affordable books. Some are sold through booksellers, but most people buy them when they take their literacy courses, while small traders carry them up-country to sell and buy more copies from the publishers with the proceeds.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Book aid schemes</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">A whole literature exists on book aid schemes. Briefly, book aid comes in two forms, one using the local book sector and the other not to any great extent. The British Government's Educational Low Prices Books Scheme (sadly scheduled to end, at least in its present form, in April 1997) and the French Government's Programme Plus both use the local bookselling industry to make available standard tertiary textbooks and others at subsidised rates. Not all students could afford to buy them, but the two schemes nonetheless promote bookselling and commercial life within ACP countries and beyond. To some extent they safeguard the continuation of fore where up-to-date books can be seen.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">CTA's books aid scheme does not use the local book sector in terms of book distribution, although cooperation in co-publishing is beginning. The FAO, in distributing publications to ACP and other developing countries, is similar. Books supplied under multilateral and bilateral agencies' projects have tended to sidestep the local book sector, although this has been changing.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">As with food aid, the question to be answered is whether continuing the aid prolongs the condition ? Or does the analogy with food aid break down in certain circumstances because books are different ?</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Improving book distribution in Africa</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Various efforts are being made to improve book markets for African publishers. For example, the African Books Collective, based in Oxford, UK, markets and sells both anglophone and francophone African publishers' selected books in the North and also to other African countries. It is often easier for publishers in the North to sell their books in Africa than it is for African publishers to sell their books across frontiers and in the continent.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Publishers Associations have been formed in about a dozen countries with APNET, the African Publishers' Network, celebrating its fourth year as a continental association. CTA supported APNET in the production of the first catalogue of agricultural books published by African publishers. Very recently, an Africa-wide booksellers association has been created.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">CTA and future book distribution</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Since CTA started distributing books on agriculture and rural development, publishing and bookselling activities in many ACP countries have multiplied and the context has changed somewhat. As noted at CTA's Montpellier conference in 1995, there is now much information and many documents going from North to South, suited to the planners, research workers and extension agents who process the information and pass it down to the small-scale farmers. Rather, a two-way information route would be more efficient, between farmers who have information to offer as well as information needs and information providers. The growth in requests to CTA for publications from co-operatives and farmer associations and from non-academic libraries and documentation units is evidence that the publications distribution service is fulfilling a need. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<B><P>&lt;&lt;TOC3&gt;&gt; The Couriers mailbag</P>
+</B><P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Earthen architecture</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">I read your article on 'Earthen Architecture', published by the CTA Bulletin in the September-October 1996 issue of The Courier (n° 159) with a great deal of interest.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The article presents such traditional products as rammed earth and adobe which have been used by man since time immemorial as witnessed by constructions and monuments to be found in the countries cited by the authors of the article, as well as industrial products such as the compressed earth block (CEB), which have provoked much interest in many parts of the world.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The authors also demonstrate that the use of the compressed earth block has a distinct advantage in that it valorises local raw materials, encourages the setting up of local enterprises and creates employment.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">In this regard, I would particularly wish to inform you that the Centre for the Development of Industry (CDI) has, for the last ten years, been working on the industrial development of the CEB sector through support to ACP promoters at various levels:</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY"> - diagnostic studies of projects and setting-up of production units;</P>
+<P ALIGN="JUSTIFY"> - search for EU technical partners who have economically advantageous technologies and are ready to transfer their know-how;</P>
+<P ALIGN="JUSTIFY">- training of enterprise personnel in CEB production and in the utilisation of this product;</P>
+<P ALIGN="JUSTIFY">- support in the manufacturing of brick presses such as is currently the case in Nigeria.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Some 100 small and mediumsized enterprises and non-governmental organisations in ACP countries involved in the CEB sector have benefited from direct CDI assistance. This assistance has, notably, led to the improved technical and economic performance of these enterprises.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Beyond support to projects, the CDI in collaboration with CRATerre actively participates in the industrial promotion of this technology. The Centre recently disseminated 2000 copies of a technical guide entitled 'CEB: Production Equipment' throughout the ACP countries. An exhibition on the compressed earth block and its application took place during the Industrial Mining Forum held in Lusaka, Zambia, in December 1994. Similar exhibitions were held during the Matconstruct Forum (Libreville, Gabon, October 1995) and at the Industrial Partnership event (Bordeaux, France, February 1995). </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The standardisation of the compressed earth block is a prerequisite for the development of this sector. The Centre therefore organised a workshop on this topic in Yaounde in 1996 as a follow-up to the Matconstruct Forum. This seminar brought together some 40 ACP and EU participants to discuss the 'CEB: Standardisation' guide currently being prepared by CRATerre for publication in December 1996.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The main objective of the guide is to encourage ACP promoters to manufacture products in conformity with accepted norms and thus facilitate CEB integration in the industrial construction market.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Efforts made by the CDI, in collaboration with CRATerre, to develop the CEB sector deserve to be better known. We would therefore look forward to an opportunity to present the Centre's activities in this sector in a future issue of me Courier. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Surendra Sharma, Director, Centre for the Development of Industry,</P>
+<P ALIGN="JUSTIFY">Brussels, Belgium.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">Map insets</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Thank-you for your informative magazine. I wish you all the best in your endeavours to improve me Courier further. May I suggest that in the Country Report profiles, you include an inset map of the region highlighting the country in question for those readers who may not be familiar with the area.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Andrew Frederick Meya, Kampala, Uganda.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">A number of readers have raised this point with us since we have rearranged the cover pages and transferred the ACP and Europe 'regional' maps to the inside back cover. In future, we will endeavour to ensure that there is a cross-reference to this page in the Country Report profile. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<B><P>&lt;&lt;TOC3&gt;&gt; Bibliography</P>
+</B><P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Publications received</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">La politique etrangere du Cameroun (Cameroon's foreign policy) </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">By Narcisse Mouelle Kombi. Pub. L'Harmattan, Collection «Points de vue» (5-7, rue de l'Ecole Polytechnique, F-75005 Paris). 1996. 238 pp. ISBN 2-73843701-X.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Cameroon belongs to the zone formerly called the 'Third World' which is nowadays labelled the 'South'. This region of great diversity currently faces major socio-economic and political conflict, and receives 'multiform' and 'tied' aid from the developed countries.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">This does not, however, prevent it from having a degree of freedom of action in diplomatic terms.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The author, who is a specialist in international law, believes that as a player on the world scene, Cameroon puts its foreign-policy skills to good advantage and has acquired a certain respect in international relations and in global institutions.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">He argues that Yaounde is attempting to implement a realistic and pragmatic foreign policy, reflecting its own sovereign status and the imperatives of development.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">At the same time, the country is endeavouring to implement the changes forced upon it by modern circumstances.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Le developpement institutionnel - Les organisations a l'epreuve de la specificite et de la concurrence (Institutional development - Organisations based on specificity and competition) </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">By Arturo Israel. Translated from the English by Alain Claisse. Pub. L'Harmattan (5-7, me de l'Ecole Polytechnique, F-75005 Paris). 1996. 235 pp. 140 FF. ISBN 2-73844322-2.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">A graduate of the University of Chile and the London School of Economics, the author has devoted most of his career (particularly within the World Bank) to examining the problems of economic and social development.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">He has been one of the pioneers of institutional development, a field which is nowadays seen as essential to all development strategies.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">He argues that institutional development requires not bureaucratisation but the promotion and recognition of two principles in both public and private organisations. These are competition and specificity. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The former induces those involved to improve the quality of their work, whilst forcing them to listen to the 'consumer'. The latter involves qualifications, specialisation and a precise definition of objectives, tasks, resources and results.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">After a critical review of assessment reports produced over a 15-year period by the World Bank in the field of institutional development, Arturo Israel tells us why such development is one of the keys to success in development projects. He demonstrates that a good project being implemented in an unfavourable institutional environment has little chance of achieving positive long-term effects.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">La justice internationale face au drame rwandais (International justice confronted by the Rwandan crisis) </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Under the direction of Jean-Fran&ccedil;oise Dupaquier, with William Bourdon, Pierre-Serge Heger, Frederic Mutagwera, Fran,cois-Xavier Nsanzuwera, Rakiya Omaar, William A. Schabas and Anne-Marie Swartenbroekx. Pub. Karthala (22-24, boulevard Arago, F-75013, Paris). 1996. 248 pp. FF 130. BF. 715. ISBN 2-86537-662-1.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">It is two years since the genocide and political massacres which resulted in the death of a million people in Rwanda. In this work, the authors describe and analyse the progress made in various legal proceedings in Rwanda itself, in the international arena and in the jurisdictions of Belgium, France, Canada and Switzerland.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Some countries have been slow and apparently reluctant to fulfil their international obligations and this has resulted in disappointment and impatience on the part of the victims' families, jurists and human rights activists.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Given the example of the Nuremberg trials, the authors suggest there are good grounds for concluding that international human rights have become less important over the last 50 years. This work allows one to reach a considered opinion. Modern legal instruments provide for the punishment of those responsible for the appalling tragedy in Rwanda. These instruments could be seen as a significant advance in the recognition of human rights by the international community. But what is missing at the moment is the political will (and public pressure) to implement them.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Methodologies d'analyse de la mortalite des enfants - Applications au Cameroun (Analytical methodologies in child mortality as applied to Cameroon) </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">By Amadou Noumbissi. Pub. Braylant-Academia (25, Grand Rue, B-134B Louvainla-Neuve) and L'Harmattan (5-7, rue de l'Ecole Polytechnique, F-75005 Paris). 1996. 305 pp. ISBN 2-87209389-3 (Academia-Braylant) and ISBN 2-7384-3722-2 (L'Harmattan).</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Child mortality, always very high in sub-Saharan Africa, varies according to social class, habitat and region. The identification of the social, economic and cultural factors which influence the survival of children depends on the quality of data, and on the relevance of the indicators and statistical models used.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">With the aid of specific examples, this work attempts to demonstrate the origin of a number of sources of bias in so-called classical approaches and the distortion of the truth which a poor choice or detrimental manipulation of statistical models can give rise to.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">A teacher and researcher at the Demographic Institute of the Catholic University of Louvain (Belgium), the author proposes methods to take account of the interdependence and synergy which exist between the factors which affect the risk of mortality. He applies these methods to the data gained in two national surveys which were carried out in Cameroon in 1978 and 1991.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Revue Region et Developpement (Region and Development Journal)</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Pub. L'Harmattan (5-7, rue de l'Ecole Polytechnique, F75005 Paris). 1995. 238 pp. ISBN 2-7384-4125-4</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">This half-yearly journal, first launched in 1995, deals with the various socio-economic aspects of regional development. The second issue contains articles which may be of interest to our readers, including: 'Regionalisation, globalisation and polarisation of the world economy: is there room for developing countries?', and 'Housing models in developing countries'.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Structural adjustment and ethnicity in Nigeria</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">By Eghosa E. Osaghae. Pub. The Nordic Africa Institute (P.O. Box 1703, S-751 47 Uppsala, Sweden). 1995. 66 pp. ISBN 91-7106373-0.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The author is a lecturer who heads the politics department at the University of Transkei in South Africa. A significant conclusion from his study, undertaken at the Nordic Africa Institute, is that from the ethnic standpoint, the implementation of structural adjustment (with its corollary of reduced state involvement in public life), has had positive effects in Nigeria. This contrasts with the usual perception of the structural adjustment process.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The migration experience in Africa</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Collection prepared under the direction of Jonathan Baker and Tade Akin Aina. Pub. The Nordic Africa Institute (P.O. Box 1703, S-751 47 Uppsala, Sweden). 1995. 353 pp. ISBN-91-7106366-8.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">This volume aims to take stock of migration in Africa. The causes of the phenomenon are varied and complex, and the authors have chosen an approach which illustrates the diversity of the theories, and methodological and analytical trends involved.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The book offers an empirical assessment of migration in contemporary Africa, focusing particularly on the problem of women migrants. Migration is an important element in the wider development equation and this work fills a gap in the literature.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Challenges to the Nation-State in Africa</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Collection prepared under the direction of Adebayo O. Olukoshi and Liisa Laakso. Pub. The Nordic Africa Institute (P.O. Box 1703, S-751 47 Uppsala, Sweden) in collaboration with the Institute of Development Studies, University of Helsinki. 1996. 213 pp. ISBN 91-7106381-1.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The challenge confronting the nation state in contemporary Africa are of great interest to specialists attempting to understand how deconstruction and recomposition of the political identity of populations affects the post-colonial unitarian project. The studies offered in this volume show that this process has often taken ethno-regionalist, religious or separatist forms -  reinforced by economic crisis and the negative effects of structural adjustment, not to mention the legacy of years of political authoritarianism and exclusion dating from the colonial period.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The authors believe that in order to promote national unity and a sense of citizenship in Africa, priority should be given, inter alia, to more representative forms of government, power-sharing and decentralisation, multi-party elections, the reinvention of the post-colonial social contract and cultural autonomy for minority groups.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Agenda for Africa's economic renewal</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Collection prepared under the direction of Benno Ndulu and Nicolas van de Walle. Pub. Overseas Department Council (1875 Connecticut Avenue, NW, Suite 1012, Washington, DC 20009, USA). 1996. 246 pp. ISBN 1-56000900-4.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">For 20 years, sub-Saharan Africa has been experiencing a severe economic crisis. Growth has been stagnant and the result has been reduced living standards for much of the population, and ever-increasing pressure on the continent's political structures. Structural adjustment, advocated by international organisations in an attempt to restore growth in Africa, has not had the anticipated results and has given rise to a number of disputes.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">In this book, 10 African, US and European experts attempt to look beyond the immediate horizon and identify strategies which could be implemented to give renewed vigour to the African economy. They analyse the choices which should be made in key areas such as agriculture, trade and industry, the role of the state and the social sectors. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<B><P>&lt;&lt;TOC3&gt;&gt; News round - up</P>
+</B><P ALIGN="JUSTIFY"></P>
+<I><P>&lt;&lt;TOC4&gt;&gt; In brief</P>
+</I><P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">World congress against the sexual exploitation of children</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The first international congress dealing with the problem of the sexual exploitation of children for profit was held in Stockholm from 27 to 31 August. The initiative for the meeting came from ECPAT (End Child Prostitution in Asian Tourism), working in collaboration with the Swedish government, the United Nations Children's Fund (UNICEF) and a group of NGOs supporting the Convention on the Rights of the Child. The congress was attended by government representatives from most of the UN countries, participants from various international and regional organisations (including the UN Centre for Human Rights, the International Labour Organisation, the World Health Organisation, UNESCO, UNHCR and Interpol), NGOs, health professionals and media representatives from across the globe.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The aim of the congress was to draw the international community's attention to the issue of the sexual exploitation of children and to promote the development of national plans to tackle all forms of abuse in this area. It focused particularly on three aspects: child prostitution, the 'trade' in children for sexual purposes, and child pornography.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Although there are a number of legal instruments which refer to these problems, the key one for the purposes of the Stockholm meeting was the Convention on the Rights of the Child. In Article 34 of this multilateral treaty, which has been ratified by 186 countries, the signatory states commit themselves to protect children against all forms of exploitation and violence of a sexual nature. For the purposes of the Convention, a child is defined as any human being less than 18 years old, except where the age of majority is lower than 18 in the relevant local legislation (Article 1).</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The committee that was responsible for planning the Congress drew up documents on a number of themes including: the revision and application of laws; psycho-social prevention; tourism and child prostitution; those who engage in abuse; hygiene and health; the role of the media; child pornography; education; and human values. These subjects were all examined by working groups during the two-day session.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The congress was addressed by Anita Gradin, Member of the European Commission with responsibility for internal and judicial affairs, and matters relating to immigration. She took the opportunity to underline the point that the traffic in women and children was international. Organised crime, she said, lay at the heart of the 'trade' and it was closely linked to a whole range of other criminal activities. She cited, in this context, kidnapping, forging of documents, 'false' marriages and adoptions, clandestine immigration, violence and forced labour. these, in turn were associated with the drug trade, extortion and murder. The conclusion was that a global action plan and more international cooperation were needed. Ms Gradin acknowledged that existing arrangements had been successful in exposing the existence of paedophile networks but she was convinced that international cooperation should be strengthened further, and that organisations such as Interpol and Europol would be called upon to play a bigger part in the future. The European Commissioner went on to declare that a commitment to the protection of children ought to be a priority. The UN Convention on the Rights of the Child - which is now eight years old -  should not merely tee 'adopted' by all countries. It should, rather, be applied in full and integrated into the legislation of every nation. There was no point, she suggested, in enacting new laws, if the existing ones were not being implemented and the financial resources had not been provided. Ms Gradin reaffirmed the European Commission's commitment to the fight against the exploitation of children. This would be reflected in communications to be drawn up by the Commission for presentation to the Council of Ministers and European Parliament, on the following subjects:  - the treatment of women (on the basis of the recommendations made by the Vienna Conference on this subject, which was held in June 1996);  - sex tourism, notably in certain countries in Asia and Latin America;  - actions designed to eliminate paedophile rings and child pornography networks which make use of new information technologies such as the Internet. During the congress, the Belgian Minister of Foreign Affairs announced that his country would be launching an initiative at the EC's Justice and Internal Affairs Council meeting scheduled for 26 and 27 September. They would be proposing common action designed to strengthen police and judicial cooperation in the fight against the sexual exploitation of children for profit. He believed that it should be possible to take measures both within the framework of the Europol Convention, and by means of new and specific cooperation instruments. The culmination of the Stockholm congress was the adoption of a declaration and an action plan. These foresee strengthened cooperation and coordination among local and national authorities, and a series of measures to protect children, prevent abuse and provide rehabilitation. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">1997: European year against racism </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">In a resolution adopted on 23 July, the Council of Ministers formally designated 1997 as the European year against racism. The aims, set out in the resolution, include:  - highlighting the threat posed by racism, xenophobia and antisemitism, in terms of both respect for fundamental rights, and in ensuring the economic and social cohesion of the European Community;  - encouraging reflection and discussion of the measures needed to tackle racism, xenophobia and antisemitism in Europe;  - promoting a sharing of experiences, best practice, and effective strategies drawn up at the local, national and European levels;  - disseminating information on the aforementioned best practice and strategies amongst those most closely involved in the fight against racism, xenophobia and antisemitism, with a view to enhancing the effectiveness of their actions in this area;  - highlighting the advantages of integration policies implemented at the national level, in particular in the fields of employment, education, training and housing;  - taking account, wherever possible, of the experiences of victims of racism, xenophobia and antisemitism, and promoting the participation of these people in society. ECU 6 million will be spent on a series of activities designed to help achieve these objectives during the 'year against racism'. A logo and slogan will be devised, and seminars and conferences will be staged with the aim of strengthening international cooperation (themes will include the role of education in eliminating racism, ways of establishing dialogue, and establishing mutual respect between different communities living in towns and cities). Documents and audiovisual material will be distributed, and an effort will be made to get the message across in the media. There will also be action to encourage information exchanges on best practice, and to increase public awareness of the issue. Prizes will be awarded to media organisations which safeguard the quality of the information they put out and which seek to promote tolerance. A specific effort will be made to counter the racist propaganda now appearing on the Internet.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">WTO banana challenge</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The European Union has set out its legal defence of duty-free preferences for African and Caribbean banana producing countries that are members of the Fourth Lom&eacute; Convention. This took place in September at an initial hearing of a World Trade Organisation (WTO) panel  - convened at the request of a number of competing banana producer nations. African and Caribbean states were permitted to voice their opinion as third part)" in the case, despite an objection from the United States. The EU's banana market arrangements  - notably Protocol 5 of the Lom&eacute; Convention, which sanctions duty-free access  - have twice before come under attack in the Geneva body. Two earlier hearings in the WTO's forerunner, the General Agreement on Tariffs and Trade (GATT), concerned the EU's previous state-to-state regime, and the new single market arrangements which have been in operation since July 1993. The present panel was set up at the request of four Latin American banana producer nations - Ecuador, Honduras, Mexico and Guatemala - together with the United States which is arguing that its domestic banana companies are losing out. The complainants jointly claim that the tariff quota for Latin American nations, the core of regulation 404/93 establishing the EU regime, discriminates against them. They also challenge the licensing arrangements of the so-called 'framework agreement' made under the GATT framework in 1994 with four Latin American nations (Colombia, Costa Rica, Nicaragua and Venezuela). In return for a bigger share of the EU market, these four agreed to refrain from further challenges in the WTO against the EU's banana arrangements.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The panel is expected to give its verdict in March 1997. The hearings are taking place behind closed doors, but it is understood that EU and ACP nations can count on the support of Japan - which currently imposes its own quotas on imports of other items and does not want to be challenged for these - and that of India which wants to show solidarity with the ACP countries.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Speaking in Geneva, Cot&eacute; d'lvoire's Commodities Minister, Alain Gauze, stressed the heavy dependence of many African and Caribbean states on banana growing. 90% of Dominica's commodity exports are bananas and the crop accounts for 70% of its export receipts and 25% of its Gross Domestic Product.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">One ACP representative in Brussels described the task ahead es 'convincing them (the panel) that the banana regime and regulation 404/93 are required to fulfil the obligations of the EU under the Lom&eacute; Convention and the subsequent waiver.'</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The waiver to which he referred was accorded by GATT to the Lom&eacute; Convention's various non-reciprocal trade preferences in 1994, but it is up for renewal at the end of the year.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The EU has already put in a request for its extension until February 29, 2000, coinciding with the expiry date of Lom&eacute; IV.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The WTO was expected to rule on the renewal of the waiver in mid-October ahead of the panel's decision. If the renewal of the waiver were to be disallowed, the EU and ACP 'defendants' at the panel could find themselves on shaky legal ground.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">In the meantime, the EU has fixed its 1996 tariff quota, allowing a maximum of 2.553 million tonnes of Latin American bananas to be imported into the Union with a tariff of ECU 75 per tonne.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">A further quota of 72 440 tonnes has been allocated to this region following tropical storms Iris, Luis et Marilyn. The damage caused by these storms led to the suspension of supplies of bananas from several Caribbean islands. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">EU banana production is expected to reach 750 000 tonnes in 1996, while preferential imports from the African and Caribbean members of the ACP group have been fixed at 680 000 tonnes. According to latest predictions, the total consumption of this fruit in the European Union in 1996 will be 4030440 tonnes. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">D.P.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">Trade and labour standards</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Ahead of the first ministerial meeting of the World Trade Organisation (WTO) to be held in December in Singapore, the European Commission has published a discussion paper (COM (96) 402 final) on whether labour standards should be linked to trade - which could mean sanctions for nations which do not comply with globally recognised labour clauses. What is at stake is to draw up globally recognised criteria and implement them without accusations of protectionism from some developing nations.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">At an informal meeting of EU trade ministers in Dublin on September 18, EC Trade Commissioner, Sir Leon Brittan, said that, in supporting an international code, the European Union had no intention of damaging the competitive advantage of developing nations.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Many Asian countries, who view the move of the EU and of other industrialised nations as veiled protectionism, do not even want the subject broached at the Singapore meeting. However, mention was made of the link between trade and internationally recognised labour standards in the conclusions of the Uruguay Round of GATT in Marrakesh in 1994, which requested that the WTO do more work on this issue.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The recent Commission paper advances the reasons for an international code: 'Workers in certain sectors in particular perceive that their jobs are under threat from imports from countries which allow unfair or unacceptable working practices.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">These concerns cannot be ignored and should be addressed by the world trading system. Otherwise the perception will be - wrongly - that trade liberalisation is the problem and not the solution to the challenge to all societies to create a higher standard of living for all their citizens.'</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">It further makes the point that such a policy is in line with others such as the promotion of democracy, respect for human rights and adherence to the rule of law. The EU has always upheld the view that there is a positive correlation between social progress, economic growth and trade liberalisation. According to the paper: 'There is no question of imposing on developing countries the higher wage levels and better working conditions which pertain in the industrialised world. Nor is this an action designed to re-erect new barriers to trade under cover of a social agenda.'</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The EU and international bodies are already looking at the kind of global criteria that might be adopted. A report of the International Labour Organisation (ILO), published in 1994, as well as the conclusions of the 1995 World Social Summit in Copenhagen, both suggest that freedom of association, collective bargaining, prohibition of forced labour and the elimination of child labour are top of the list.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">A report entitled: 'Trade, Employment and Labour Standards - a study of core workers' rights and international trade', produced this year by the Paris-based Organisation for Economic Cooperation and Development (OECD), looks at the options in depth.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Jeff Atkinson, trade policy advisor for the NGO, Oxfam UK, suggests that initial negotiations should be limited to matters covered in ILO Conventions 87 and 98. The former deals with freedom of association and protection of the right to organise, while the latter is on the right to organise and collective bargaining. He argues that other Conventions, covering such matters as the right to equal renumeration for men and women workers, freedom from discrimination and the abolition of forced labour, depend on the first two. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">A notable omission from Jeff Atkinson's list is ILO Convention 138 on child labour. He does not feel that this Convention adequately addresses the issue. While international concern has focused on the most abusive forms of child labour such as slavery and prostitution, he points out not all child labour is so grossly abusive. Some forms can bring in money for food and shelter, which would otherwise not be available.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">He argues that if conditions are right, employment (say on a family farm or business) can contribute positively to a child's development, by providing an informal learning environment in which social and physical skills can develop.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">'To tackle the symptoms, for example by banning child labour, without addressing the underlying cause is likely to be counterproductive', says Mr Atkinson. He argues that it might induce children to seek illegal work in order to survive, or alternatively that they may end up becoming destitute.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Some bodies are already trying to enforce improved standards. Although the ILO cannot implement sanctions, if an ILO member fails to comply with Conventions, a dialogue can be instituted with the defaulting country. It is also running an extensive public campaign against child labour and is assisting the development of social labelling for goods produced which fully respect ILO Conventions.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Under its new Generalised System of Preferences (GSP), the EU can remove some trade preferences if goods imported from non-Lom&eacute; developing nations are found to have been made with forced or slave labour. And from January 1, 1998, extra preferences can be given to countries which so request and comply with Conventions 87, 98 and 138. But if the enforcement of a socalled 'Social Clause' does reach the WTO level, some voices are already calling for joint monitoring involving the WTO and that long-time champion of human rights, the ILO. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">The 1996 UNCTAD Report</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">A slow world growth rate is revealed in this year's annual report of the United Nations Conference on Trade and Development (UNCTAD), published in September. The global economy expanded by only 2.4% in 1995 compared with a 2.8% increase in 1994. And production is below what it could be, says the report. On the whole, developing nations achieved higher growth rates than their industrialised counterparts in 1995.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">In 1996, world growth is expected to slow further although there will still be 'star performers' in some regions, and particularly slow movers in others. Asia is the continent currently doing best and China has the fastest expanding economy - despite this having slackened in recent years.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">In 1995, Africa recorded higher growth than Latin America, according to the Rubens Ricupero, UNCTAD Secretary General. It also managed the first real increase in average per capita income for a long time. This was partly due to commodity prices picking up - they rose 10% on average.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">But not such good news for the continent was a drop in private capital flows, notably direct investment. And the growth rate was highly variable across Africa. In some countries it was above 5% but in others, the economic situation was hit badly by political and armed conflicts.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Meanwhile, drought led to lower production in the Sahel. The prospects for 1996 are uncertain according to the report. It noted that even countries whose economies have expanded during 1995 and 1996 will need another ten concurrent years of good economic results to get back to the per capita income they enjoyed 20 years ago.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The report highlights the tremendous difficulties facing many of the heavily-indebted, least developed nations. This is despite the fact that a number of donors have recently written off substantial amounts of some countries' public debts while the Paris Club has rescheduled repayments from other nations. Even if the new arrangements are followed through, UNCTAD is predicting that debt will remain a major burden for many countries.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">One worrying factor is the weight of their multilateral debt and bilateral obligations to creditors other than the Paris Club. Multilateral institutions have implemented a number of measures, but these are of very limited scope. The UNCTAD Secretary General is encouraging multilateral creditors in particular, to put more muscle behind their debt relief plans.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The authors of the report are also recommending the establishment of an agency, within UNCTAD itself, to help developing nations achieve trade diversification and industrialisation strategies for economic growth. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">Seminar on NGOs and government relations in humanitarian emergencies</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The British Council is organising an international seminar on the above subject in Oxford, UK, from 12-17 December 1996. The main themes to be covered at the meeting will include:</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY"> - the actors in humanitarian assistance;</P>
+<P ALIGN="JUSTIFY"> - funder and donor policy;</P>
+<P ALIGN="JUSTIFY">- government sovereignty;</P>
+<P ALIGN="JUSTIFY">- rights and obligations of intervention;</P>
+<P ALIGN="JUSTIFY">- the role of the beneficiary;</P>
+<P ALIGN="JUSTIFY">- conflicts of interest and areas of cooperation between donor NGOs and host governments, and;</P>
+<P ALIGN="JUSTIFY">- accountability and evaluation.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Further information can be obtained from the Marketing Manager, International Seminars, The British Council, 1 Beaumont Place, GB-Oxford, OX1 2PJ.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Tel. (44) 1B65 316 636, Fax. (44) 1865 57368.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">E-mail: International. Seminar@britcoun.org </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<I><P>&lt;&lt;TOC4&gt;&gt; The institutions at work</P>
+</I><P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">COMMON FOREIGN AND SECURITY POLICY</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Within the framework of its Common Foreign and Security Policy (CFSP), the European Union has recently issued a number of statements, details of which are set out below:</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Burundi: condemnation of the massacre on 19 July</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Declaration of 23 July 1996</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The European Union expresses grave concern at the deteriorating situation in Burundi especially at the killing of civilians and other gross violations of human rights which continue to be perpetrated in that country. It vehemently condemns the massacre of civilians in the Bugendana camp for displaced persons on 19 July last and deplores the expulsions of Rwandan refugees against their will. This massacre, following as it does those at Gishubi, Kivyuka, Teza, Mutoyi, Songa and Kamenge, represents a new stage in the vortex of violence, action and reaction putting Burundi at risk of being drawn ever further into a full civil war, the effects of which would be catastrophic for the people of Burundi.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The EU calls on all Burundians to turn away from violence and move singlemindedly along the road to a peaceful and negotiated solution of their problems. It would point to the undertakings given on 25 June 1996 at Arusha during the Summit of Heads of State of the region in favour of dialogue open to all sectors of Burundi's population together with provision of the security measures needed to create the conditions for such dialogue. It would also point out that these undertakings were given formal backing by the Heads of State and Government of the entire continent of Africa when they met from 8 to 10 July at Yaounde under the aegis of the Organisation for African Unity.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The EU believes that only compliance with the undertakings given at Arusha and their swift implementation can restore a climate of confidence and prevent Burundi becoming embroiled in a generalised conflict. As it has already stressed in the Council's statement of 15 and 16 July, the EU reiterates that it is prepared to assist in pursuit of the Arusha objectives in order to restore peace and security in Burundi and it supports the efforts of former President Nyerere and the countries of the region to achieve this.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Burundi: appeal for reconciliation following the coup d'Etat </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Declaration of 26 July 1996</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The European Union shares the deep concern of the Secretary General of the United Nations, and others, about yesterday's military coup in Burundi.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The EU urges all sides to avoid recourse to violence and to take all steps to resolve the crisis by exclusively peaceful means.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The EU believes that the main immediate priority is the humanitarian situation. There must be no further loss of life.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">An immediate beginning of a national debate is essential, leading to a real process of national reconciliation, founded on democracy and security for all sections of society.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">In this regard, the EU commends the efforts of former President Nyerere and regional leaders to broker an all-inclusive, negotiated settlement in Burundi, in peaceful conditions, and urges them to examine the possibility of continuing their efforts in this respect.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The EU reiterates its firm commitment to the re-establishment of peace in Burundi. The Union is following developments in the country closely, in active consultation with partners in the UN, with the OAU and others, towards the goal of restoring peace and security in Burundi. The EU Special Envoy, Mr Ajello, who is in the region, is actively assisting in this process.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Niger: doubts about the first round election results</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Declaration of 1 August 1996</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The European Union expresses deep concern about the way in which the first round of the presidential elections in Niger on 7-8 July was conducted. In particular, it deplores the decision taken by the Niger authorities to dissolve the independent national electoral commission during the voting process and to replace it with an alternative body. It is the view of the EU that this decision, by the Niger authorities, casts serious doubts on the credibility of the election results. It requests the Niger authorities to explain this decision and why observers found it impossible to assist in gathering and collating the election results.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The EU urges the Niger authorities, in dealing with the critical situation which has resulted from their decision, to respect fully the fundamental freedoms of movement, expression and association of the Niger people. It attaches great importance to the restoration of all civil rights.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The EU will examine, in the light of recent developments, its policies of economic and development cooperation with the Niger authorities.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The EU calls for the full restoration of democratic civilian government in Niger through transparent processes. Free and fair elections will be crucial in this respect. The EU will continue to follow the situation in Niger closely and in particular the preparation, holding and transparency of the forthcoming legislative elections on 22 September. Iceland, the Central European countries associated with the EU and the associated countries Cyprus and Malta align themselves with this declaration.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Swaziland: revision of the Constitution</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Declaration of 6 August 1996</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The European Union welcomes the announcement by King Mswati III of the names of the new Prime Minister of Swaziland and of the Constitutional Review Commission and is pleased that its membership represents all shades of political opinion in Swaziland.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The EU wishes to encourage all members of the Constitutional Review Commission to participate fully in its work and expresses confidence that their endeavours will bring about the adoption of a draft democratic constitution acceptable to the people of Swaziland as a whole. It hopes that the Commission will pursue its task energetically and is ready to offer appropriate assistance to the Commission if it so wishes.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Burundi: appeal for talks and reconciliation</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Declaration of 19 August 1996</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Recalling its declarations of 25 June and 5, 15, 23 and 26 July 1996, the European Union reiterates its deep concern about the situation in Burundi. It urges all sides to refrain from violence and to commit themselves to, and work actively towards, a negotiated and peaceful resolution of the crisis.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The EU wishes to express its support for the regional leaders, the Organisation of African Unity and the former President of Tanzania, Mr Julius Nyerere, in the efforts which they have been making to assist Burundi to overcome peacefully the grave crisis which it is experiencing, and encourages them to continue their efforts to facilitate the search for a political solution.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The EU considers it essential for a dialogue to be organised without delay, bringing together all of Burundi's political forces without exception, including representatives of civil society, in order to negotiate a democratic, institutional consensus ensuring security for all.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The EU is convinced that national reconciliation and civil peace in Burundi can be restored on a lasting basis only through the participation of all sections of society in the principal institutions and bodies of the State.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The EU urges all sides in Burundi to call an immediate halt to the violence and respect the safety of all Burundians.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">It reaffirms its willingness to support Burundi's recovery efforts, once the necessary national reconciliation is embarked upon with all the resolve required.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">AID FOR REHABILITATION</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Within the framework of the 'European Programme for Reconstruction and Development in South Africa', the Commission has recently decided on financing for the following ten projects:</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY"> - ECU 19.2 million for a development programme covering the management of the public service;</P>
+<P ALIGN="JUSTIFY"> - ECU 17.2 million for technical assistance to the Ministry of Education;</P>
+<P ALIGN="JUSTIFY"> - ECU 16 million for a support programme for Parliament;</P>
+<P ALIGN="JUSTIFY"> - ECU 15 million for the electrification of rural schools;</P>
+<P ALIGN="JUSTIFY"> - ECU 9 million to support the reform process in the police services of the Eastern Cape province;</P>
+<P ALIGN="JUSTIFY"> - ECU 8.9 million for a financing and investment development programme for SMEs;</P>
+<P ALIGN="JUSTIFY"> - ECU 5 million for a programme of rural water supply and sanitation projects to be implemented </P>
+<P ALIGN="JUSTIFY">by the NGO Mvula Trust; </P>
+<P ALIGN="JUSTIFY"> - ECU 4.3 million to support the trade union movement;</P>
+<P ALIGN="JUSTIFY"> - ECU 2.3 million for the 'Soul City 1996' project designed to make full use of the mass media to promote health and development issues;</P>
+<P ALIGN="JUSTIFY"> - ECU 1.9 million to support the 'Truth and National Reconciliation Commission'.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">EUROPEAN DEVELOPMENT FUND</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Following, where required, favourable opinions from the EDF Committee, the Commission has decided to provide grants and special loans from the 5th, 6th and 7th EDFs to finance the following operations (grants unless otherwise stated). Major projects and programmes are highlighted.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Economic and social infrastructure</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Burkina Faso: ECU 4.125 million for studies relating to certain road infrastructures. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Mauritius: ECU 9 million for an irrigation programme in the northern plains. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Dominica: ECU 1.65 million towards the establishment of refuse treatments systems.  Trade promotion/ structural adjustment</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Cot&eacute; d'lvoire: ECU 25.5 million to , support the structural adjustment programme. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Lesotho: ECU 8.6 million for the fourth structural adjustment programme. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">Agriculture/rural development</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Ethiopia-Kenya-Uganda: ECU 20 million for a programme to coordinate national activities aimed at achieving sustainable rural development in the region (notably involving the fight against the Tsetse fly)</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">Education/training</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Caribbean region: ECU 5.9 million towards a post-secondary education training programme in the countries of the OECS (Organisation of Eastern Caribbean States - Antigua &amp; Barbuda, British Virgin Islands, Dominica, Grenada, Montserrat, St Kitts &amp; Nevis, St Lucia, St. Vincent &amp; the Grenadines). </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">Environment</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Malawi: ECU 4.4 million for a social/ participatory programme in the forestry sector as part of the implementation of a national forestry policy. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">Institutional support</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">SADC member states: ECU 1.7 million to support the SADC (Southern African Development Community) secretariat in order to strengthen the SADC-EU regional programme. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">UEMOA (West Africa Economic and Monetary Union): ECU 12 million to support the regional integration process in the member states (Benin, Burkina Faso, Cot&eacute; d'lvoire, Mali, Niger, Senegal and Togo) </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Zambia: ECU 1.5 million for a support programme for the Ministry of Finance and Economic Development.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">EUROPEAN INVESTMENT  BANK</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">During the first half of 1996, the Bank has provided the following loans from its own resources or in the form of risk capital:</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Africa/Madagascar: ECU 30 million for ASECNA (I'Agence pour la securite de la navigation aerienne en Afrique et a Madagascar) for the renewal and modernisation of air safety equipment. Botswana: ECU 6.6 million to the Botswana Power Corporation to help increase electricity-generating capacity.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Burkina Faso: ECU 6 million to SOFITEX (Societe burkinabe des fibres textiles) for the renewal and extension of its cotton ginneries facility. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Mali: ECU 5.3 million to the Societe Energie du Mali for the financing of the Balingue thermal power station. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Mauritania: ECU 2 million to SNIM (Societe rationale industrielle et miniere) for the setting up and operation of a mechanical workshop. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Mauritania: ECU 1.4 million to the Societe arabe du fer et de l'acier (Arab iron and steel company) for the construction of a foundry.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Mozambique: ECU 500 000 to Grafites de Ancuabe for the exploitation of a graphite mine.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Zambia: ECU 2 million to the Zambia Venture Capital Fund, set up to subscribe for minority equity stakes in SMEs. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Jamaica: ECU 40 million to Telecommunications of Jamaica Ltd for expansion and modernisation of the domestic and international telecommunications network. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">British Virgin Islands: ECU 600 000 to the government for the design and feasibility study of the main airport at Beef Island, Tortola. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Tonga: ECU 3.7 million to the Tonga Telecommunications Commission for the development of the country's domestic telecommunications network.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">HUMANITARIAN AID</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">ACP countries</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Ethiopia: ECU 5 million for the purchase and distribution of vegetable oils and cereals to refugees living in the country. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Kenya: ECU 420 000 for emergency medical assistance in the fight against cholera in the Mandera region.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Somalia: ECU 1.9 million for emergency food aid to the victims of the continuing factional fighting. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Sudan: ECU 2.5 million for the purchase and distribution of maize in a transit camp close to the capital (154 000 people) and in the south of the country (1 million people), and for the distribution of sorghum to Ethiopian and Eritrean refugees in the east (200 000 people). </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Chad: ECU 150 000 to help tackle the cholera epidemic. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Haiti: ECU 10 million for a programme to counter malnutrition and improve basic health care, in particular for women and children in isolated locations.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Montserrat: ECU 380 000 to help evacuees in the wake of the recent volcanic eruption. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Non-ACP countries</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Colombia: ECU 1 million for people displaced as a result of drug terrorism and the fighting that has been taking peace between government forces and guerillas. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Costa Rica: ECU 400 000 for the victims of Hurricane Cesar. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Guatemala: ECU 220 000 to train teachers in order to improve education among repatriated communities in the department of Alta Verapaz. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Nicaragua: ECU 440 000 to improve conditions for the social and economic reintegration of uprooted populations (people who have been repatriated, displaced or demobilised) in the department of Rio San Juan. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Northern Caucasus: ECU 4.18 million for civilian victims of the war in Chechnya and for refugees in Ossetia and Dagestan. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Iraq: ECU 9 million for food aid, medical provisions, rehabilitation of drinking water systems, sanitary equipment and educational material to assist 3 million people in the north and centre of the country.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Yemen: ECU 150 000 for flood victims. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Cambodia: ECU 290 000 for a programme to construct and distribute artificial limbs to land-mine victims. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Thailand (Burmese refugees): ECU 220 000 for 'Mon' refugees from Burma (Myanmar) who have fled the violence in their country. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Thailand (Burmese refugees): ECU 500 000 for medical aid in favour of 'Karen' refugees from Burma (Myanmar). </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">FOOD AID</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The Commission has recently decided to allocate the following aid: </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&lt;&lt;I&gt;&gt; p90.png Table</P></FONT></BODY>
+</HTML>
Index: /main/tags/2.25/gsdl/collect/demo/import/faobetf/fb33fe/fb33fe.htm
===================================================================
--- /main/tags/2.25/gsdl/collect/demo/import/faobetf/fb33fe/fb33fe.htm	(revision 21064)
+++ /main/tags/2.25/gsdl/collect/demo/import/faobetf/fb33fe/fb33fe.htm	(revision 21064)
@@ -0,0 +1,654 @@
+<HTML>
+<HEAD>
+<META HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=windows-1252">
+<META NAME="Generator" CONTENT="Microsoft Word 97">
+<TITLE>&lt;&lt;TOC1&gt;&gt; Farming snails 1: Learning about snails; Building a pen; Food and shelter plants</TITLE>
+</HEAD>
+<BODY>
+
+<B><FONT FACE="Arial" SIZE=2><P>&lt;&lt;TOC1&gt;&gt; Farming snails 1: Learning about snails; Building a pen; Food and shelter plants</P>
+</B><P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">FOOD AND AGRICULTURE ORGANIZATION OF THE UNITED NATIONS</P>
+<P ALIGN="JUSTIFY">Rome 1986</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">P-69</P>
+<P ALIGN="JUSTIFY">ISBN 92-5-102396-4</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&copy; FAO 1986</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<B><P ALIGN="CENTER">&lt;&lt;TOC2&gt;&gt; Introduction</P>
+</B><P ALIGN="CENTER"></P>
+<P ALIGN="JUSTIFY">1. Did you know that many kinds of snails are good to eat?</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">2. Snail meat tastes good and it is also good for you. If you have snail meat to eat, it will help to keep you and your family strong and healthy.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&lt;&lt;I&gt;&gt; f33p60a.png Family kept strong and healthy</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">3. If you want to have snails to eat you can get them in different ways.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">4. Many people gather wild snails that live nearby. Sometimes you can buy snails at the market or from people who gather them to sell to others.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">5. You can also raise your own snails. This is called snail farming. Today, a great many people all over the world farm snails.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">6. If you farm your own snails, you will always have a supply of fresh snail meat whenever you want it.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">7. Then, if your family is not too big and you grow more snails than you need to eat, you can sell what you do not use to your neighbours or at the market.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&lt;&lt;I&gt;&gt; f33p61a.png Selling snails at the market</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">8. With more food to eat and the money you get by selling snails, you and your family can live better.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">9. However, if your family is big you will need to grow many more snails if you are going to have enough to eat and to sell at the market.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&lt;&lt;I&gt;&gt; f33p61b.png You need to grow more snails if your family is big</P>
+<P ALIGN="CENTER"></P>
+<P ALIGN="CENTER">&nbsp;</P>
+<B><P>&lt;&lt;TOC3&gt;&gt; What do you need to start?</P>
+</B><P ALIGN="CENTER"></P>
+<P ALIGN="JUSTIFY">You will need</P>
+<P ALIGN="JUSTIFY"></P><DIR>
+
+<P ALIGN="JUSTIFY"> enough snails to start your snail farm</P>
+<P ALIGN="JUSTIFY"></P></DIR>
+
+<P ALIGN="JUSTIFY">&lt;&lt;I&gt;&gt; f33p61c.png Snail</P>
+<P ALIGN="JUSTIFY"></P><DIR>
+
+<P ALIGN="JUSTIFY"> a place near your house with the right kind of soil and the right amount of water for snails to live and grow</P>
+<P ALIGN="JUSTIFY"></P></DIR>
+
+<P ALIGN="JUSTIFY">&lt;&lt;I&gt;&gt; f33p61d.png A place near your house</P>
+<P ALIGN="JUSTIFY"></P><DIR>
+
+<P ALIGN="JUSTIFY"> the kinds of plants that snails need for food and shelter</P>
+<P ALIGN="JUSTIFY"> the materials to build a pen for the snail</P>
+<P ALIGN="JUSTIFY"></P></DIR>
+
+<P ALIGN="JUSTIFY">&lt;&lt;I&gt;&gt; f33p62a.png Plants that snails need; The materials to build a pen</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">10. If you have or can get all of these things, you can raise snails.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="CENTER">&nbsp;</P>
+<B><P ALIGN="CENTER">&lt;&lt;TOC2&gt;&gt; Learning about snails</P>
+</B><P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">11. To farm snails is not hard; however, it is quite different from keeping chickens or ducks or from growing crops such as maize, rice, cassava or groundnuts.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">12. Since farming snails is so different from other kinds of farming, you will have to learn a lot of new things.</P>
+<P ALIGN="JUSTIFY">13. One way to learn about snails so that you will be able to farm them is to watch the wild snails that live near you.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&lt;&lt;I&gt;&gt; f33p62b.png Watch the wild snails</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">14. Try to see how they live, how they move and where they go, what plants they like best and what they eat.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">15. You can learn many things by watching wild snails that will help you later if you decide to start a snail farm.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&lt;&lt;I&gt;&gt; f33p63a.png Wild snail</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">16. Another way to learn about snails is to ask an older farmer who knows a lot about your area. If there are people near you who gather snails to sell to others, they may be able to help you.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">17. In the next part of this booklet, you will begin to learn some things that you need to know to farm snails.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<B><P>&lt;&lt;TOC3&gt;&gt; What kind of snails can you farm?</P>
+</B><P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">18. The kind of snails that you can farm are snails that live on land, and there are many kinds of land snails that are good to eat.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">19. However, some kinds of land snails are not good to eat and they may even make you very, very sick.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">20. So, you must be very careful when you choose snails to farm. If you are not sure that a snail is good to eat, do not use it.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&lt;&lt;I&gt;&gt; f33p63b.png Do not use snail unless you are sure it is good to eat</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">21. Now look at the drawings on pages 8 to 11 and you will see four kinds of good snails that live in different places.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">22. You may be able to find one of these kinds of snails where you live. Notice that two of them are small and two of them are large.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">23. The smaller kinds of snails, shown on pages 8 and 9, can often be found in places where part of the year is warm and part of the year is cold.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">24. The larger kinds of snails, shown on pages 10 and 11, can often be found in places where it is warm all year round.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&lt;&lt;I&gt;&gt; f33p64a.png Helix pomatia</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">This kind of small snail</P>
+<P ALIGN="JUSTIFY">1 can be found in places where part of the year is warm and part of the year is cold</P>
+<P ALIGN="JUSTIFY">2 weighs from 15 to 25 grams and measures from 40 to 50 millimetres</P>
+<P ALIGN="JUSTIFY">3 has a strong shell which is pale brown and off- white</P>
+<P ALIGN="JUSTIFY">4 grows to full size in two to three years if it is well fed</P>
+<P ALIGN="JUSTIFY">5 lays from 30 to 50 eggs each growing season</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&lt;&lt;I&gt;&gt; f33p64b.png Helix Pomatia - 30 to 50 small eggs</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&lt;&lt;I&gt;&gt; f33p64c.png Helix aspersa</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">This kind of small snail</P>
+<P ALIGN="JUSTIFY">1 can often be found in places where part of the year is warm and part of the year is cold</P>
+<P ALIGN="JUSTIFY">2 weighs from 4 to 20 grams and measures from 30 to 45 millimetres</P>
+<P ALIGN="JUSTIFY">3 has a weak shell with broken stripes which are light brown to black</P>
+<P ALIGN="JUSTIFY">4 grows to full size in one year if it is well fed</P>
+<P ALIGN="JUSTIFY">5 lays from 40 to 170 eggs one to three times each growing season</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&lt;&lt;I&gt;&gt; f33p64d.png Helix aspersa - 40 to 170 small eggs</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&lt;&lt;I&gt;&gt; f33p65a.png Achatina achatina</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">This kind of large snail</P>
+<P ALIGN="JUSTIFY">1 can often be found in places where it is warm all year round</P>
+<P ALIGN="JUSTIFY">2 weighs from 150 to 200 grams or more and measures from 90 to 130 millimetres</P>
+<P ALIGN="JUSTIFY">3 has a very strong brown shell</P>
+<P ALIGN="JUSTIFY">4 grows to full size in two years if it is well fed</P>
+<P ALIGN="JUSTIFY">5 lays from 100 to 300 eggs one to two times each growing season</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&lt;&lt;I&gt;&gt; f33p65b.png Achatina achatina - 100 to 300 small eggs</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&lt;&lt;I&gt;&gt; f33p65c.png Archchatina marginata</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">This kind of large snail</P>
+<P ALIGN="JUSTIFY">1 can often be found in places where it is warm all year round</P>
+<P ALIGN="JUSTIFY">2 weighs from 150 to 200 grams or more and measures from 90 to 130 millimetres</P>
+<P ALIGN="JUSTIFY">3 has a very strong brown shell</P>
+<P ALIGN="JUSTIFY">4 grows to full size in two years if it is well fed</P>
+<P ALIGN="JUSTIFY">5 lays from five to ten eggs four to eight times each growing season</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&lt;&lt;I&gt;&gt; f33p65d.png Archchatina marginata - five to ten large eggs</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">25. If you cannot get one of these snails, you may be able to get others very much like them where you live.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">26. There are many other kinds of good snails. There may even be several kinds of good snails that are eaten where you live.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">27. If snails are eaten where you live, you can farm one of these. Then you will be sure that it is good to eat.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<B><P>&lt;&lt;TOC3&gt;&gt; Where can you get snails?</P>
+</B><P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">28. When you are ready to get snails, perhaps you can get them by gathering wild snails that live near you.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&lt;&lt;I&gt;&gt; f33p66a.png Gathering wild snails</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">29. Perhaps you can buy them from people who gather wild snails to sell to others.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&lt;&lt;I&gt;&gt; f33p66b.png Buying from one who gathers wild snails</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">30. You may even be able to buy them from another snail farmer.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&lt;&lt;I&gt;&gt; f33p66c.png Buying from another snail farmer</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Note</P>
+<P ALIGN="JUSTIFY">Never term snails that you buy at the market. Snails at the market may have been washed, kept too cold or hurt and they may die soon.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<B><P>&lt;&lt;TOC3&gt;&gt; Where can you farm snails?</P>
+</B><P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">31. A good place for a snail farm is one where there already are snails. If there already are snails, you will know that the soil and the water in the soil are right for snails to live and grow.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">32. However, if there are no snails near where you live it does not mean that you cannot raise snails there.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">33. If you have the right kind of soil with the right amount of water, you can bring good snails from another place to start your snail farm.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<B><P>&lt;&lt;TOC3&gt;&gt; The soil and the water in the soil</P>
+</B><P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">34. Soil is important for snails. Part of the time they live on the soil and part of the time they live in the soil, and to live well, snails need good soil.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&lt;&lt;I&gt;&gt; f33p67a.png Snail on the soil; Snail in the soil</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">35. When snails are not on the soil or in the soil, they are on plants which grow in the soil. So, the soil must also be good for the kinds of plants that snails need.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&lt;&lt;I&gt;&gt; f33p67b.png Snail on plant</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">36. When snails are in the soil, they are resting or laying their eggs. If the soil has the right amount of water, snails will live well, the eggs they lay will hatch well and the baby snails will come out of the soil easily.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">37. Snails cannot live in hard soil such as heavy clay soils. When heavy clay soil is too dry, snails cannot dig into it to rest and lay their eggs. When heavy clay is too wet, snails and the eggs they lay may die.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">38. Snails cannot live in loose soil such as soils that have a lot of sand. Sandy soils do not hold enough water for snail eggs to hatch.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">39. The drawings on the next page show how a snail digs a hole, lays its eggs, closes the hole and how the baby snails come out when they have hatched.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">40. Snails need calcium from the soil to make their shells. All snails grow better and have stronger shells when there is a lot of calcium in the soil.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">41. So, if you are going to farm snails, you must have a good medium soil that has neither too much clay nor too much sand. It must also have enough calcium and the right amount of water for your snails to live and grow.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Note</P>
+<P ALIGN="JUSTIFY">If you have a garden, you can easily tell if your soll is good for snails. If your green leafy vegetables grow well, snails will also grow well in the same kind of soil</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&lt;&lt;I&gt;&gt; f33p68a.png Snails will grow well in a garden</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">1 snail digging a hole</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&lt;&lt;I&gt;&gt; f33p68b.png 1 snail digging a hole</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">2 laying the eggs and closing the hole</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&lt;&lt;I&gt;&gt; f33p68c.png Snail laying eggs</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">3 baby snails hatching and coming out of the hole</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&lt;&lt;I&gt;&gt; f33p68d.png Baby snails hatching and coming out of the hole</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<B><P>&lt;&lt;TOC3&gt;&gt; Plants for food and plants for shelter</P>
+</B><P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">42. Snails need plants for both food and sheller. Most kinds of snails use several kinds for food and several other kinds for shelter.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&lt;&lt;I&gt;&gt; f33p69a.png Plants for food and plants for shelter</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">43. They may also use different plants for food and shelter at different times of the year. Sometimes during the growing season snails eat and find shelter on the same plants.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">44. Snails usually hide on shelter plants during the day when it is dry and move to food plants to eat at night or early in the morning when they are wet with dew. However, sometimes snails do eat during the day after it has rained.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">45. If you live in a place which has a season when plants do not grow, snails will dig into the soil to rest and they do not eat then.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">46. During the growing season snails will eat a lot and grow very fast if they have food plants that they like.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">47. So, before you begin you will have to find out exactly what plants they like to eat. To do this you will have to watch snails at night when they eat.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&lt;&lt;I&gt;&gt; f33p69b.png See what snails eat at night</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">48. You can tell that snails are eating when you see their heads moving as they scrape food into their mouths. You can also tell when a snail has been eating by the holes it makes in the leaves.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&lt;&lt;I&gt;&gt; f33p69c.png Snail on leaf</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">49. You will also have to find out what plants they like for shelter. To do this you will have to watch snails during the day when they rest.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&lt;&lt;I&gt;&gt; f33p70a.png See where snails rest during the day</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">50. It is often difficult to find snails on shelter plants because they are hiding. So, you will have to look very carefully.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&lt;&lt;I&gt;&gt; f33p70b.png Snails are hiding on shelter plants</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">51. In addition to the food plants, there are many other kinds of foods that you can put into a pen for your snails to eat. You will learn about these foods and when you should use them in the next booklet in this series.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<B><P>&lt;&lt;TOC3&gt;&gt; Dew and rain</P>
+</B><P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">52. Dew at night in the growing season helps the plants to grow and makes the leaves and the ground wet so that snails can move about.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">53. Rain in the growing season also helps the plants to grow and it cleans the plants of dust and the dirt that snails leave when they move about. The dirt that snails leave may make them sick.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">54. So, it is very important that the food and shelter plants are wet and clean.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">55. When the leaves are wet, snails move easily, eat more and grow well. When the leaves are dry, snails move very little, or not at all, and they grow poorly.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&lt;&lt;I&gt;&gt; f33p70c.png Wet leaves are good for snails</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">56. When it rains and the plants are clean, the snails will be healthy. When it does not rain and the plants are dirty, the snails may get sick.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">57. Dew and rain also keep the ground moist so that the snails can move easily and dig into it to rest and to lay their eggs.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">58. In the next booklet, you will be told how to wet the leaves of plants and moisten the ground when it is too dry.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<B><P>&lt;&lt;TOC3&gt;&gt; Land that is wet</P>
+</B><P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">59. Land that is very wet, low land that does not drain well or land that floods in the rainy season is not good for snail farming.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&lt;&lt;I&gt;&gt; f33p71a.png Low, wet land is bad for snails</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<B><P>&lt;&lt;TOC3&gt;&gt; Wind</P>
+</B><P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">60. Wind during the growing season is bad because it dries the dew and dries out the snails.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&lt;&lt;I&gt;&gt; f33p71b.png Wind is bad for snails</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">61. If you decide to farm snails, try to keep them in a place that is protected from the wind.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&lt;&lt;I&gt;&gt; f33p71c.png Snails should be farmed in a place protected from the wind</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<B><P>&lt;&lt;TOC3&gt;&gt; Where do you keep snails when you farm them?</P>
+</B><P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">62. If you decide to farm snails you must keep them in a pen. Snails kept in a well- built pen will not get away easily and you can watch them and take care of them well.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">63. After the first year you will need at least two pens. If you decide to farm more snails you may want even more pens. You will learn how to use two or more pens in the next booklet.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&lt;&lt;I&gt;&gt; f33p72a.png Two pens the second year</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">64. In each pen you can give your snails the right kinds of plants for them to eat and to use as shelter.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">65. In each pen you can put the food and shelter plants near each other so that the snails can move easily from one to the other.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">66. Each pen you build must also keep the snails safe from their enemies. Snails have many enemies. You must be careful to protect them from</P>
+<P ALIGN="JUSTIFY"></P><DIR>
+
+<P ALIGN="JUSTIFY"> mice and rats</P>
+<P ALIGN="JUSTIFY"> shrews and moles</P>
+<P ALIGN="JUSTIFY"> walking insects that live on the ground such as ants and beetles</P>
+<P ALIGN="JUSTIFY"> slugs and other snails that eat snail meat</P>
+<P ALIGN="JUSTIFY"> birds that eat snails</P>
+<P ALIGN="JUSTIFY"> frogs and toads</P>
+<P ALIGN="JUSTIFY"> thieves</P>
+<P ALIGN="JUSTIFY"></P></DIR>
+
+<P ALIGN="JUSTIFY">&lt;&lt;I&gt;&gt; f33p72b.png Protect them from
+</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">67. A snail pen can be small or large depending on how many snails you want to raise. However, when you first begin, start with a small pen. You will need fewer materials. It will be easier to take care of.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">68. In addition, with a small pen you will need fewer snails to begin. When you know more about raising snails, you can build a bigger pen and get more snails to raise.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">69. A good size for a pen is 5 x 5 metres. Later in this booklet you will learn how to build a small pen of this size.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<B><P>&lt;&lt;TOC3&gt;&gt; How many snails will you need when you first begin?</P>
+</B><P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">70. If you are using small snails like those you have seen on pages 8 and 9 in this booklet, you will need more snails to begin.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">71. If you are using large snails like those you have seen on pages 10 and 11 in this booklet, you will need fewer snails to begin.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">72. With a pen of 5 x 5 metres (25 square metres) you will need</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY"> 150 snails if you use the small kind (6 for each square metre)</P>
+<P ALIGN="JUSTIFY"> 25 snails if you use the large kind (1 for each square metre).</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&lt;&lt;I&gt;&gt; f33p73a.png 150 small snails; 25 large snails</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<B><P>&lt;&lt;TOC3&gt;&gt; How much snail meat can you expect to get?</P>
+</B><P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">73. The amount of snail meat that you will get from small snails will be about the same as what you would get from large snails. This is because you will use many more small snails than large snails and the meat will be about equal.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">74. With one 5 x 5 metre pen you will get 12 to 13 kilograms of snail meat each year and with two 5 x 5 metre pens you will get 24 to 26 kilograms each year.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&lt;&lt;I&gt;&gt; f33p73b.png 12 to 13 kilograms each year; 24 to 26 kilograms each year</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<B><P>&lt;&lt;TOC3&gt;&gt; Now you must decide</P>
+</B><P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">75. In the first part of this booklet you have learned many things about snails and farming snails. You have learned</P>
+<P ALIGN="JUSTIFY"></P><DIR>
+
+<P ALIGN="JUSTIFY"> why it is good to farm snails</P>
+<P ALIGN="JUSTIFY"> what you need to farm snails</P>
+<P ALIGN="JUSTIFY"> what kinds of snails you can farm</P>
+<P ALIGN="JUSTIFY"> how to find plants near you that are good for food and shelter</P>
+<P ALIGN="JUSTIFY"> what kind of soil and how much water in the soil snails need</P>
+<P ALIGN="JUSTIFY"> where to keep snails and how many you need to start</P>
+<P ALIGN="JUSTIFY"></P></DIR>
+
+<P ALIGN="JUSTIFY">76. You may also have been able to learn a lot about snails by watching the wild snails near where you live.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">77. An old farmer may have told you what he knows about snails. Someone who gathers snails to sell to others or another snail farmer may have helped you to learn.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">78. So, now that you know a lot about snails it is time to decide if you would like to start your own snail farm.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">79. If you would like to begin you will learn exactly what to do in the rest of this booklet and in the next booklet.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<B><P ALIGN="CENTER">&lt;&lt;TOC2&gt;&gt; How to begin</P>
+<P ALIGN="CENTER"></P>
+<P ALIGN="CENTER">&nbsp;</P>
+<P>&lt;&lt;TOC3&gt;&gt; Choose a place on your land to put your snail farm</P>
+</B><P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">80. Try to choose a place that is close to your house. That way you will be able to watch your snails, protect them from their enemies and take care of them easily</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&lt;&lt;I&gt;&gt; f33p74a.png Close to your house</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">81. In Items 34 to 41 you were told that to farm snails you must have the right kind of soil with the right amount of water.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">82. Remember, if green leafy vegetables grow well in your soil, snails will also grow well in the same kind of soil.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&lt;&lt;I&gt;&gt; f33p74b.png If your garden grows well, so will your snails</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">83. In Items 59 to 61 you were told that low, wet land and wind are bad for snails. So, avoid low, wet places and try to put your snail farm where it is protected from the wind.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&lt;&lt;I&gt;&gt; f33p75a.png Avoid low, wet land; Find a place protected from wind</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">84. In Item 63 you were told that after the first year you will need at least two pens and later you may want even more. In Item 69 you were told that it is best to start with a small pen of 5 x 5 metres.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">85. So, try to find a place where you can put at least two or three 5 x 5 metre pens.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&lt;&lt;I&gt;&gt; f33p75b.png two or three 5 x 5 metre pens</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<B><P>&lt;&lt;TOC3&gt;&gt; Clean the site and prepare the ground</P>
+</B><P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">86. Clean the site and prepare the ground a little before the growing season so that you can build the pen in time to plant the food and shelter plants.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">87. First, mark out a square of 8 x 8 metres on the place that you have chosen.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&lt;&lt;I&gt;&gt; f33p75c.png Mark and clear the 8 x 8 metre square</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">88. That way, with a pen of 5 x 5 metres in the centre of the square, you will have a path of 1.5 metres all the way around it (see Item 92). If you have enough land, the path can be even wider.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">89. Clear the square of trees, bushes grass, creeping grass and weeds. Take away all of the roots and the big stones that you can.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&lt;&lt;I&gt;&gt; f33p76a.png Take away roots and big stones</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">90. Spread the plant material that you have cleaned evenly on the ground and cover the whole square. If there is not enough, bring more plant material from another place.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&lt;&lt;I&gt;&gt; f33p76b.png Cover the square with plant materials</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">91. When the plant material is dry, burn it. This will kill the insects, the weed seeds and the roots of creeping grass, and rid the ground of mice, rats and shrews.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&lt;&lt;I&gt;&gt; f33p76c.png Burn the plant materials</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Note</P>
+<P ALIGN="JUSTIFY">Insecticides and poisons can also be used to rid your pen of insects, mice, rats and other enemies of snails. However, if you use them, do not use them by yourself because they are very dangerous. Ask someone who knows how to use them, such as your extension agent.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">92. Now mark out a smaller square of 5 x 5 metres inside the big square. This is for your first snail pen.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&lt;&lt;I&gt;&gt; f33p77a.png Mark the 5 x 5 metre square</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">93. Dig the ground in the smaller square to a depth of 20 centimetres and turn it over well. As you dig, remove any rubbish or roots that you find.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&lt;&lt;I&gt;&gt; f33p77b.png Dig in the ground</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">94. While you are digging, if you see any more insects or any of the enemies of snails, bring more dry plant material and burn the ground again. To farm snails, the area must be free of insects, mice, rats and other enemies.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">95. When you have finished digging, the ground in the 5 x 5 metre square should be as smooth and well worked as it would be if you were planting a vegetable garden.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&lt;&lt;I&gt;&gt; f33p77c.png The 5 x 5 metre square should be smooth</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">96. However, do not use any fertilizer, animal manure or compost as you might with a vegetable garden. Fertilizers may burn the snails and animal manure or compost may bring in insects and weed seeds.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<B><P ALIGN="CENTER">&lt;&lt;TOC2&gt;&gt; Building a pen</P>
+</B><P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">97. Build a pen for your snails as soon as you can after you have burned the plant material. This is to keep other insects, mice, rats or shrews from getting into your pen.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">98. A snail pen is a simple fenced- in area and you can build a fence using</P>
+<P ALIGN="JUSTIFY"></P><DIR>
+
+<P ALIGN="JUSTIFY"> corrugated sheet metal or plastic sheets</P>
+<P ALIGN="JUSTIFY"> woven plant material</P>
+<P ALIGN="JUSTIFY"> woven plant material with chicken wire</P>
+<P ALIGN="JUSTIFY"></P></DIR>
+
+<P ALIGN="JUSTIFY">&lt;&lt;I&gt;&gt; f33p78a.png Materials for fence</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Using corrugated sheet metal or plastic sheets</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">99. A fence of corrugated sheet metal or plastic sheets makes the best pen for snails because it keeps out their enemies very well. However, sheet metal or plastic costs a lot of money.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&lt;&lt;I&gt;&gt; f33p78b.png A fence of corrugated sheet metal</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">100. If you are going to build a pen using corrugated metal or plastic, you must build it in such a way that the enemies of snails cannot get in between the sheets.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">Using woven plant material</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">101. To save money, you can build a fence of woven plant material such as split bamboo. If the woven material is tight, it will keep out enough of enemies for you to farm snails.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&lt;&lt;I&gt;&gt; f33p79a.png Woven material</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Using woven plant material with chicken wire</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">102. If you can get fine- mesh chicken wire, you can improve a fence that is made of woven material.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&lt;&lt;I&gt;&gt; f33p79b.png Chicken wire</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">103. To do this, first make the fence of chicken wire and then cover it with woven material.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&lt;&lt;I&gt;&gt; f33p79c.png First use chicken wire then cover it with woven material</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">104. The chicken wire will keep out rats and other small animals. The woven plant material will keep most of the insects out and keep the snails in.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&lt;&lt;I&gt;&gt; f33p79d.png Keep out small animals</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Note</P>
+<P ALIGN="JUSTIFY">With any kind of pen animals such as rats may get in, and this is especially true with pens made only of woven plant material. So, you must always watch for rats and other animals and keep them out.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">How to build the fence</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">105. Build the fence as you would any fence, by driving posts into the ground. Use posts 1.40 metres long. When the posts are in place they should be 1.00 metre above and 0.40 metre below the ground.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&lt;&lt;I&gt;&gt; f33p80a.png Drive posts into the ground</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">106. Whatever material you use for the fence of your pen, it should be buried 0.40 metre below the ground.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">107. If you are using woven material you will have to change the bottom of the fence when it rots.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">108. This can be done more easily by making the woven material in two parts, one for the top and one for the bottom. When the bottom part rots, you can change it without having to change the whole fence.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&lt;&lt;I&gt;&gt; f33p80b.png Attach top parts first; attach bottom parts second</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Keeping your snails in the pen</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">109. Many of your snails may crawl over the fence and get out of the pen. If you build a flap on the inside at the top of the fence, it will be more difficult for your snails to get out.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">110. However, even with a flap some snails may get out, and for this reason many snail farmers put two flaps on their fence. With two flaps they find that fewer snails get out.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&lt;&lt;I&gt;&gt; f33p81a.png With two flaps, your snails will not easily crawl out of the pen</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Note</P>
+<P ALIGN="JUSTIFY">If you make your pen using galvanized sheet metal, you will not need flaps. Snails will not crawl on galvanized sheet metal.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">111. The drawings show you how to build a 5 x 5 metre pen using woven plant material, with and without chicken wire and how to build flaps to keep your snails in.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&lt;&lt;I&gt;&gt; f33p81b.png How to build a 5 x 5 metre small pen</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">3 if you are using woven material only, attach it as you were told to do in Item 108</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&lt;&lt;I&gt;&gt; f33p82a.png Attach woven material</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">4 If you are using chicken wire and woven material, attach the chicken wire first and then the woven material</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&lt;&lt;I&gt;&gt; f33p82b.png Attach the chicken material first</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">5 be sure that the fence cover goes all the way to the bottom of the 0.40- m trench</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&lt;&lt;I&gt;&gt; f33p82c.png 0.40- m trench</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">6 fill in the trench</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&lt;&lt;I&gt;&gt; f33p82d.png Fill in the trench</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">7 attach the flaps to the inside of the pen</P>
+<P ALIGN="JUSTIFY">Note: use woven material 0.25 m wide for the flaps</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">8 first attach the bottom flap using heavy cord</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&lt;&lt;I&gt;&gt; f33p83a.png Use heavy cord</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">9 then attach the top flap</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<B><P ALIGN="CENTER">&lt;&lt;TOC2&gt;&gt; Plant the food and shelter plants</P>
+</B><P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">112. You have already been told that you should clean and prepare the site and build your snail pen in time for the planting season.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">113. If it has been only a short time since you dug the ground and worked the soil in your pen, you can begin to plant.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">114. If it has been a long time, dig and work the soil again before you plant. However, as you were told in Item 96, do not use fertilizer, animal manure or compost.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">115. Now you can begin to plant the food and shelter plants. Remember that you should use</P>
+<P ALIGN="JUSTIFY"></P><DIR>
+
+<P ALIGN="JUSTIFY"> plants that grow well where you live</P>
+<P ALIGN="JUSTIFY"> plants that last a long time</P>
+<P ALIGN="JUSTIFY"> plants that snails like</P>
+<P ALIGN="JUSTIFY"></P></DIR>
+
+<P ALIGN="JUSTIFY">116. The drawings, show you two ways to plant food and shelter plants in a 5 x 5 metre pen.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">117. On pages 50 to 55 you will see some food and shelter plants that snails are known to like. Look at them carefully. Perhaps you can find some of them where you live.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Two ways plant food and shelter plants</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">1 if your shelter plants are small, plant your pen like this</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&lt;&lt;I&gt;&gt; f33p84a.png Mark three places for small shelter plants</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">2 plant the shelter plants first and then plant the food plants all around the shelter plants</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&lt;&lt;I&gt;&gt; f33p84b.png First plant the shelter plants</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">3 if your shelter plants are large, plant your pen like this</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&lt;&lt;I&gt;&gt; f33p84c.png Mark only one place for large shelter plants</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">4 plant the shelter plants first and then plant the food plants all around the shelter plants</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&lt;&lt;I&gt;&gt; f33p84d.png Leave a path inside the fence</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">RAMPE</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&lt;&lt;I&gt;&gt; f33p85a.png Some plants for food</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Rape is one of many kinds of smooth- leaved cabbage. It grows from seed and lasts a number of months. Rape is the best food plant for Helix snails (see pages 8 and 9 in this booklet). Many of the other kinds of smooth- leaved cabbage also make good food plants for snails.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&lt;&lt;I&gt;&gt; f33p85b.png Rape</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">AFRICAN SPINACH (Amaranthus)</P>
+<P ALIGN="JUSTIFY">This green leafy vegetable is a good food plant for young Achatina and Archachatina snails. However, if you plant African spinach for your snails, they will need other kinds of food plants as well.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&lt;&lt;I&gt;&gt; f33p85c.png African spinach</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">PAPAYA</P>
+<P ALIGN="JUSTIFY">You have already been told that snails can be given food to eat other than the food plants that you have planted in the pen (see also Items 175 to 179 in the next booklet). The tender green leaves and cut- up fruit of the papaya tree are very good for Achatina and Archachatina snails. However, the papaya should not be planted inside the pen.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&lt;&lt;I&gt;&gt; f33p86a.png Papaya</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">HORSE- RADISH</P>
+<P ALIGN="JUSTIFY">Horse- radish is a good food and shelter plant for young Helix snails. However, when they are older they will need other kinds of food plants as well.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&lt;&lt;I&gt;&gt; f33p86b.png Horse- Radish</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">LEAF BEET</P>
+<P ALIGN="JUSTIFY">Leaf beet grows well from seed and lives for one year. It can be used with He/ix snails for both food and for shelter. As a food plant alone it is not the best and you will have to give your snails other food plants as well. However, as a shelter plant it is very good for Helix snails. These snails lay eggs under the beet plants and find shelter around the roots in cold weather.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&lt;&lt;I&gt;&gt; f33p86c.png Leaf Beet</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">BURDOCK</P>
+<P ALIGN="JUSTIFY">Burdock grows from seed and lives for more than a year. It grows very slowly and you should plant it as soon as you can so that it can grow big enough for your snails. However, once it has grown it makes a good food and shelter plant for almost any kind of snail.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&lt;&lt;I&gt;&gt; f33p87a.png Burdock</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">BANANA and LOOFAH</P>
+<P ALIGN="JUSTIFY">Banana and loofah plants together provide both food and shelter for Achatina and Archachatina snails. Ripe bananas can be cut up and fed to the snails and they can use the loofah plant for food and for shelter. However, your snails will need other food plants as well.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&lt;&lt;I&gt;&gt; f33p87b.png Banana and Loofah</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">PLANTAGO</P>
+<P ALIGN="JUSTIFY">Plantago grows well from seed and lasts about two years. It is the best shelter plant for Helix snails.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&lt;&lt;I&gt;&gt; f33p87c.png Plantago</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">ASPARAGUS</P>
+<P ALIGN="JUSTIFY">Asparagus lives for many years and it is a good shelter plant for young Achatina and Archachatina snails. However, it is not good for older snails because they are too heavy for asparagus plants.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<B><P>&lt;&lt;TOC3&gt;&gt; When are the plants big enough for food and for shelter?</P>
+</B><P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">118. The food plants must be big enough to feed your snails and the shelter plants tall enough to cover them and to protect them from the sun.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">119. Depending on the kind of snails that you are raising, most plants will be big enough after they have been growing for about five to six weeks or when they have reached a height of 10 to 20 centimetres.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&lt;&lt;I&gt;&gt; f33p88a.png Plants will grow to a height of 10 to 20 cm.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">120. When you are sure that the plants are big enough to provide food and shelter, you can begin to collect the snails and put them into the pen.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">121. In Booklet No. 34, Farming snails 2, you will learn</P>
+<P ALIGN="JUSTIFY"></P><DIR>
+
+<P ALIGN="JUSTIFY"> how to choose good snails and how to put them in the pen</P>
+<P ALIGN="JUSTIFY"> how to take care of your snails</P>
+<P ALIGN="JUSTIFY"> when and how to harvest snails</P>
+<P ALIGN="JUSTIFY"> how to prepare snails for cooking</P>
+<P ALIGN="JUSTIFY"></P></DIR>
+
+<P ALIGN="JUSTIFY">122. You will also be told some things that you can do to improve your snail farm so that later when you have more experience you can raise more and better snails.</P></FONT></BODY>
+</HTML>
Index: /main/tags/2.25/gsdl/collect/demo/import/faobetf/fb34fe/fb34fe.htm
===================================================================
--- /main/tags/2.25/gsdl/collect/demo/import/faobetf/fb34fe/fb34fe.htm	(revision 21064)
+++ /main/tags/2.25/gsdl/collect/demo/import/faobetf/fb34fe/fb34fe.htm	(revision 21064)
@@ -0,0 +1,469 @@
+<HTML>
+<HEAD>
+<META HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=windows-1252">
+<META NAME="Generator" CONTENT="Microsoft Word 97">
+<TITLE>&lt;&lt;TOC1&gt;&gt; Farming snails 2: Choosing snails; Care and harvesting; Further improvement</TITLE>
+</HEAD>
+<BODY>
+
+<B><FONT FACE="Arial" SIZE=2><P>&lt;&lt;TOC1&gt;&gt; Farming snails 2: Choosing snails; Care and harvesting; Further improvement</P>
+</B><P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">FOOD AND AGRICULTURE ORGANIZATION OF THE UNITED NATIONS</P>
+<P ALIGN="JUSTIFY">Rome 1986</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">P-69</P>
+<P ALIGN="JUSTIFY">ISBN 92-5-102397-2</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&copy; FAO 1986</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<B><P ALIGN="CENTER">&lt;&lt;TOC2&gt;&gt; Preface</P>
+</B><P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The first twenty- six volumes in FAO's Better Farming Series were based on the Cours d'apprentissage agricole prepared in C&ocirc;te d'Ivoire by the Institut africain de d&eacute;veloppement &eacute;conomique et social for use by extension workers. Later volumes, beginning with No. 27, have been prepared by FAO for use in agricultural development at the farm and family level. The approach has deliberately been a general one, the intention being to constitute basic prototype outlines to be modified or expanded in each area according to local conditions of agriculture.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Many of the booklets deal with specific crops and techniques, while others are intended to give the farmer more general information which can help him to understand why he does what he does, so that he will be able to do it better. Booklets No. 33 and 34 were added to the series owing to a growing interest in small- scale snail farming for food and profit in many countries where FAO's Better Farming Series is widely used.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Adaptations of the series, or of individual volumes in it, have been published in Amharic, Arabic, Bengali, Creole, Hindi, Igala, Indonesian, Kiswahili, Malagasy, SiSwati, Thai and Turkish.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Requests for permission to issue this manual in other languages and to adapt it according to local climatic and ecological conditions are welcomed. They should be addressed to the Director, Publications Division, Food and Agriculture Organization of the United Nations, Via delle Terme di Caracalla, 00100 Rome, Italy.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<B><P ALIGN="CENTER">&lt;&lt;TOC2&gt;&gt; The snails</P>
+<P ALIGN="CENTER"></P>
+<P ALIGN="CENTER">&nbsp;</P>
+<P>&lt;&lt;TOC3&gt;&gt; Choosing your snails</P>
+</B><P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">123. All of the snails that you choose for your pen must be of the same kind.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&lt;&lt;I&gt;&gt; f34p093a.png All of the snails that you farm must be the same kind</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">124. You may have found one of the kinds of snails shown on pages 8 to 11 in the last booklet living in your area. You may also have found a different kind of snail.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">125. Now you must learn to choose the beat of the kinds of snails that you have found. When you first begin you will need fully grown snails.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">126. Remember, that all snails are both male and female and all snails lay eggs. So, when you are looking for snails, you can choose any one that is fully grown.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">127. You can tell that a snail is fully grown because it has a lip on the mouth of its shell. The drawings below show two fully grown snails with lips.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&lt;&lt;I&gt;&gt; f34p094a.png Snails which fill and which does not fill their cells</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">128. Look at the drawings again. Notice that although both snails are fully grown, one of them fills its shell and one of them does not.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">129. The snail that does not fill its shell may be sick or it may have lost its water because of dry weather. This snail may not grow well.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">130. Choose only snails that fill their shells. Snails that fill their shells will usually grow well.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">131. Choose snails that have good, strong shells. Strong shells protect snails from their enemies, and snails with strong shells sell better at the market.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">132. Choose the largest of the fully grown snails that you can find from the kind of snail that you are going to farm.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&lt;&lt;I&gt;&gt; f34p094b.png Choose the largest snails</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">133. The larger snails of any kind of snail will be better and healthier and lay more eggs than a snail that is smaller.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">134. In addition, the eggs of large, healthy snails hatch better and the baby snails grow bigger and faster.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">135. Later, when you have more experience in choosing snails, you will learn just how large a fully grown snail should be. You will also learn the different colours of the kind of snail that you are farming.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">136. Then you can choose snails that are the same size and colour that you want your baby snails to be.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Note</P>
+<P ALIGN="JUSTIFY">As you collect your snails, handle them very gently and put them carefully into a container such as a basket so that you can carry them to the pen without hurting them.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&lt;&lt;I&gt;&gt; f34p095a.png Handle your snails carefully</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<B><P>&lt;&lt;TOC3&gt;&gt; Putting your snails in the pen</P>
+</B><P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">137. Just before you put your snails in the pen, take out all the grass, the creeping grass and the weeds that may have grown while the food and shelter plants were growing.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&lt;&lt;I&gt;&gt; f34p095b.png Take out all grass, creeping grass and weeds</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">138. Never put snails in a pen in the morning or during the day when the sun is hot. Always put them in the evening when it is cool. This is when they begin to move about and to eat.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&lt;&lt;I&gt;&gt; f34p095c.png Always put snacks in the pen in the evening</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">139. If there is no dew and leaves of the plants and the ground are dry, wet them. Items 160 to 165 in this booklet will tell you how.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&lt;&lt;I&gt;&gt; f34p096a.png Wet the plants</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">140. When you put snails in the pen, put an equal number of them in four different places.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">141. In the last booklet you were told that for a 5 x 5 metre pen you would need 150 snails if you use the small kind, and 25 snails if you use the large kind. So, if you need</P>
+<P ALIGN="JUSTIFY"></P><DIR>
+
+<P ALIGN="JUSTIFY"> 150 snails, put 35 to 40 snails in four places</P>
+<P ALIGN="JUSTIFY"> 25 snails, put 6 snails in three places and 7 snails in one place.</P>
+<P ALIGN="JUSTIFY"></P></DIR>
+
+<P ALIGN="JUSTIFY">142. The arrows in the drawing at the top of the next page will show you where to put snails in a 5 x 5 metre pen.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&lt;&lt;I&gt;&gt; f34p096b.png Where to put the snails</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Note</P>
+<P ALIGN="JUSTIFY">When you put snails in a pen, never put them near the fence or in a corner of the fence. If you put them near the fence it is easier for them to get out than it is if you put them near the centre of the pen.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&lt;&lt;I&gt;&gt; f34p096c.png Do not put snails in the corner or near the fence</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">143. The morning after you have put your snails in the pen, look to see that they have all moved. If any of them have not moved, put them under shelter plants.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">144. If any snails die, take them out and put in the same number of new snails.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&lt;&lt;I&gt;&gt; f34p097a.png Take out the dead snails</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">145. At first your snails will try to crawl out of the pen. During this time, go around the pen each morning and put them back.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">146. After about two weeks your snails will become used to their new home and most of them will not try to crawl out.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">147. However, it is a good idea, even after the first two weeks, to check from time to time and put back any of the snails that may have got out of the pen.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<B><P>&lt;&lt;TOC3&gt;&gt; When to take out the fully grown snails</P>
+</B><P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">148. When you see a lot of baby snails in your pen, you will no longer need to keep the fully grown snails.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">149. So, take out all of the fully grown snails that you first put into your pen. You can either eat them or sell them at the market.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&lt;&lt;I&gt;&gt; f34p097b.png Take out all fully grown snails</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">150. Now, with only the baby snails left, the food plants in the pen will be more likely to last until the baby snails are big enough to harvest.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">151. Later in this booklet, you will be told when the baby snails are big enough to harvest and how to harvest them.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<B><P ALIGN="CENTER">&lt;&lt;TOC2&gt;&gt; Taking care of your snails</P>
+</B><P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">152. After you have put your snails in their pen, watch them carefully to see that they are eating well.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">153. If you have given them enough of the right kinds of food plants, they will eat a lot and you will have very little to do for them.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">154. However, here are some things that you must do</P>
+<P ALIGN="JUSTIFY"></P><DIR>
+
+<P ALIGN="JUSTIFY"> wet the plants and moisten the ground</P>
+<P ALIGN="JUSTIFY"> take care of the plants</P>
+<P ALIGN="JUSTIFY"> take away the weeds and the creeping grass</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P></DIR>
+
+<B><P>&lt;&lt;TOC3&gt;&gt; Wet the food and shelter plants and moisten the ground</P>
+</B><P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">155. You have already been told that the leaves of the food and shelter plants must be wet and clean and that the ground must be moist (see Items 52 to 58 in the last booklet).</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">156. If there is too lime dew and not enough rainfall during the time when the plants and the snails are growing, you will have to water the plants and the ground yourself.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">157. If it is dry, you should water the plants and the ground at least every second day. However, if it is very dry, you may have to water them every day.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">158. Never water in the morning or during the day when the sun is hot. Always water in the evening at about sunset.</P>
+<P ALIGN="JUSTIFY">159. If you water when the sun is hot, the snails will begin to move away from the shelter plants and the hot sun may kill them before they can find shelter again.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">160. An easy way to wet the plants and moisten the ground is by hand. First fill a bucket with water and wrap a piece of cloth around your hand.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&lt;&lt;I&gt;&gt; f34p098a.png Wrap a cloth around your hand</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">161. Then, dip your hand with the cloth into the bucket of water and gently splash the plants and the ground.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&lt;&lt;I&gt;&gt; f34p099a.png Gently splash plants and ground</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">162. Continue to splash the plants and the ground gently until you have watered the whole pen.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">163. When you have finished, the leaves of the plants should be wet and the ground should be moist.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">164. You can tell when the plants are wet enough and the ground is moist enough when you can see your snails moving about easily.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&lt;&lt;I&gt;&gt; f34p099b.png Snails move about easily</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">165. Remember: the soil must be moist and not wet in order for snail eggs to hatch.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Note</P>
+<P ALIGN="JUSTIFY">You have already been told that if you live in a place that has a dry season when the plants do not grow, snails dig into the ground to rest. Never water at this time or your snails may come out of the ground when they should not.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<B><P>&lt;&lt;TOC3&gt;&gt; Tend the food and shelter plants</P>
+</B><P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">166. Watch all of your plants to see that they are growing well and that they do not get too tall or too thick.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">167. Plants that are too tall or thick stop the dew from reaching the leaves and stop the rain from washing away the dust and the dirt that snails leave when they move about.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">168. If you see that the plants are not being wet or washed by dew or rain, cut them back.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&lt;&lt;I&gt;&gt; f34p101a.png Cut back the plants</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<B><P>&lt;&lt;TOC3&gt;&gt; Take away the weeds and creeping grass</P>
+</B><P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">169. After your snails are in their pen you must be sure to take away all weeds and especially creeping grass as soon as you see them.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">170. Creeping grass grows very fast and so thick that it can kill the food and shelter plants. If this happens, your snails will have no food and no place to find shelter.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">171. Taking away weeds and creeping grass when snails are in the pen is very difficult. So, you must be very careful not to hurt them or step on them.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">172. If the weeds and creeping grass get too thick, it may be better to move the snails before you take weeds and creeping grass away (see Item 183 in this booklet).</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">173. Keep the path around the pen clear of weeds, grass and creeping grass. This will help to keep weed seeds and unwanted plants out of the pen.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&lt;&lt;I&gt;&gt; f34p101b.png Keep the path clean</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">174. If the path is clean, insects will be less likely to cross it to get into the pen and you will be able to see signs of mice, rats and shrews.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<B><P>&lt;&lt;TOC3&gt;&gt; Feeding your snails other kinds of food</P>
+</B><P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">175. There are a number of reasons for giving your snails other kinds of food. Here are a few</P>
+<P ALIGN="JUSTIFY"></P><DIR>
+
+<P ALIGN="JUSTIFY"> when you have not planted the right kinds of food plants</P>
+<P ALIGN="JUSTIFY"> when you have too many snails for the number of food plants that you have planted</P>
+<P ALIGN="JUSTIFY"> when most of the food plants in the pen have been eaten by the snails</P>
+<P ALIGN="JUSTIFY"></P></DIR>
+
+<P ALIGN="JUSTIFY">176. If you decide for any of these reasons that you must give your snails other kinds of food, here are some foods that snails like to eat</P>
+<P ALIGN="JUSTIFY"></P><DIR>
+
+<P ALIGN="JUSTIFY"> the outside leaves of vegetables such as cabbage or cauliflower</P>
+<P ALIGN="JUSTIFY"> the tops of vegetables such as carrots or beets</P>
+<P ALIGN="JUSTIFY"> ripe banana fruit</P>
+<P ALIGN="JUSTIFY"> most waste fruit and vegetables</P>
+<P ALIGN="JUSTIFY"> cut- up papaya, melon or squash</P>
+<P ALIGN="JUSTIFY"></P></DIR>
+
+<P ALIGN="JUSTIFY">&lt;&lt;I&gt;&gt; f34p102a.png Food snails eat</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">177. There are many other foods that snails like to eat. If you have some food that you think might be good, try it with your snails and see if they like it.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">178. If your snails are not eating their food plants well, you also can try some others. Cut pieces from the plant that you want to try and put them in the pen.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">179. If you see that your snails like the new food plants better, you can use these plants when you build the second pen.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<B><P ALIGN="CENTER">&lt;&lt;TOC2&gt;&gt; Building the second pen</P>
+</B><P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">180. In the last booklet you were told that to farm snails you will need at least two pens.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&lt;&lt;I&gt;&gt; f34p103a.png Two pens needed</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">181 . With two pens you can move your snails from one pen to the other to get rid of any enemies that may have got in.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">182. You can also move your snails to dig the ground and work the soil so that they can dig into the soil to rest and can lay their eggs easily.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">183. With two pens you can move your snails from one pen to the other if the weeds and creeping grass get too thick to take away with snails in the pen.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">184. You can also plant new food plants when the old ones have been eaten. When you are moving the snails, you can get rid of any of them that have not grown well.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<B><P>&lt;&lt;TOC3&gt;&gt; When to build the second pen and how to build it</P>
+</B><P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">185. Build your second pen a little before the growing season and exactly one year after you built the first pen.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">186. Begin just as you did before, by cleaning and preparing the ground (see Items 86 to 96 in the last booklet).</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">187. However, if you put your second pen near your first pen, be very careful when you burn the plant material not to burn your first pen or harm the snails in it.</P>
+<P ALIGN="JUSTIFY">188. For this reason it is best to leave an open space of at least 3 metres between your first and second pens.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&lt;&lt;I&gt;&gt; f34p103b.png Be very carefull when you burn the plant material</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">189. Now you are ready to build the second 5 x 5 metre pen and to plant the food and shelter plants (see Items 97 to 117 in the last booklet).</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<B><P>&lt;&lt;TOC3&gt;&gt; Putting snails in your second pen</P>
+</B><P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">190. When the plants in your second pen have grown big enough to provide food and shelter, you can put in the snails.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&lt;&lt;I&gt;&gt; f34p104a.png When the plants are grown, you can bring the snails</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">191. If the snails in your first pen have grown well, you can use some of them for your second pen. So, collect the right number of the biggest and best snails from your first pen to put in your second pen.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">192. If the snails in your first pen have not grown well, you will have to begin again with new fully grown snails for your second pen.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">193. Remember, with your first pen you put in 150 snails if you used the small kind and 25 snails if you used the large kind.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">194. However, different snails lay different amounts of eggs. So with your second pen you may want to change the number of snails that you put in.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">195. If there were too many baby snails for the food plants in your first pen, put fewer fully grown snails in your second pen.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">196. If there were too few baby snails for the food plants in your first pen, put more fully grown snails in your second pen.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">197. If you are not sure how many snails to use, it is best to continue to put in 150 if you use small snails and 25 if you use large snails.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&lt;&lt;I&gt;&gt; f34p104b.png 25 Large snails; 150 small snails</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">198. Later, when you have learned more about the kind of snails that you are using and how many baby snails they have, you will be better able to judge just how many fully grown snails that you should use.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Note</P>
+<P ALIGN="JUSTIFY">Do not forget to take out all of the fully grown snails that you have put in after you see a lot of baby snails in your second pen (see Items 148 to 151 in this booklet).</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<B><P ALIGN="CENTER">&lt;&lt;TOC2&gt;&gt; Harvesting your snails</P>
+<P ALIGN="CENTER"></P>
+<P ALIGN="CENTER">&nbsp;</P>
+<P>&lt;&lt;TOC3&gt;&gt; When to harvest your snails</P>
+</B><P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">199. If your snails have grown well, some of them will be big enough to harvest about one year after you have first put snails in the pen.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">200. If you need any snails to put in another pen, collect them first. So, choose the right number (see Items 193 to 198 in this booklet) of the biggest and best snails.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">201. Carefully put these snails into a container so that you can carry them to the other pen without hurting them.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&lt;&lt;I&gt;&gt; f34p105a.png Put snails into a container</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">202. Now you are ready to harvest the rest of your biggest snails. Remember, the best way to harvest is a few snails at a time when you want some to eat or to sell at the market.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">203. However, harvest all of the snails by the end of the second year so that you can plant the pen in time for the next growing season.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<B><P>&lt;&lt;TOC3&gt;&gt; How to harvest your snails</P>
+</B><P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">204. Harvesting snails is done by hand. It is often hard work to find them because they may be hiding.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&lt;&lt;I&gt;&gt; f34p105b.png Harvesting snails</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">205. The easiest time to find the snails is when the plants are wet, after it has rained or at night when there is dew and they are moving about or eating.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">206. You can also put out some of the food that snails like and when they come to eat it, you can collect them easily.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&lt;&lt;I&gt;&gt; f34p105c.png Put out some food</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">207. When you are harvesting, handle your snails carefully and put them into a container such as a box or basket or a net sack. However, do not put more than 10 kilograms in a container or you may hurt them.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&lt;&lt;I&gt;&gt; f34p106a.png Put snails in a container</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<B><P>&lt;&lt;TOC3&gt;&gt; What to do with the snails you harvest</P>
+</B><P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">208. If you are going to sell the snails, you can carry them to the market in containers like the ones above. However, you must be very careful not to hurt them or break their shells.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">209. Remember, snails with clean shells and well- cared- for snails will sell better at the market.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">210. If you want to keep the snails for you and your family to eat later, you can store them alive in containers filled with material such as sawdust or chopped maize husks.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">211. That way you can keep them for as long as six to eight weeks before you use them. The drawings below show you how to store snails this way.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">1 a box is a good container to store snails in</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&lt;&lt;I&gt;&gt; f34p106b.png A box</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">2 cover the bottom of the box with about 5 cm of sawdust or chopped maize husks</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&lt;&lt;I&gt;&gt; f34p106c.png Cover the bottom of the box with sawdust</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">3 carefully put in a layer of snails</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">4 cover the snails with about 3 cm of sawdust or chopped maize husks</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&lt;&lt;I&gt;&gt; f34p106d.png Cover the snails</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">5 continue to do this until the box is full</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Note: be sure that the top layer of snails is covered</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<B><P ALIGN="CENTER">&lt;&lt;TOC2&gt;&gt; Preparing snails for cooking</P>
+</B><P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">212. Before snails can be used you must be sure that there is no food in them. They must be clean inside.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">213. Snails that have been stored in a container (see Items 210 and 211 in this booklet) for more than four days will have no food left in them. They are clean inside.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">214. However, snails which have just been taken from the pen have been eating and are usually full of food.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">215. So, before you can use them you must wait for them to become clean inside. To do this you need only to keep them from eating.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">216. Put them in a container where they can get no food but plenty of air. You can use a covered basket or a net sack.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&lt;&lt;I&gt;&gt; f34p107a.png Use a covered basket or a net sack</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">217. Put the basket or sack in a cool place away from the sun. After four days the snails will be clean inside.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&lt;&lt;I&gt;&gt; f34p107b.png Put the container away from sun</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">218. All snails must be washed and boiled just before cooking them.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">219. First, put them in clean, cool water with a little salt and vinegar.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&lt;&lt;I&gt;&gt; f34p107c.png Put them in clean water</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">220. After a short time the water will begin 10 turn white and you will know that the snails are being washed inside.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">221. When the water is very white, take the snails out and empty out the old water. Then put them again in clean, cool water with a little salt and vinegar.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&lt;&lt;I&gt;&gt; f34p108a.png Empty out dirty water; wash snails again</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">222. Continue to wash them this way until the water no longer turns white. Then you will know that the snails are completely washed.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">223. Now put the snails in boiling water, again with salt and vinegar, and boil them at least five minutes. The snails are now ready to be cooked.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&lt;&lt;I&gt;&gt; f34p108b.png Boil snails with salt and vinegar for five minutes</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Note</P>
+<P ALIGN="JUSTIFY">Snail meat can be cooked like any meat or it can be cut into pieces and added to a stew or vegetables. If snails are eaten where you live, there will be many ways to cook them.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<B><P ALIGN="CENTER">&lt;&lt;TOC2&gt;&gt; Further improvement</P>
+</B><P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">224. After you have been farming snails using two pens for some time, you may find that you and your family could eat or sell more snails if you had them.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">225. You can raise more snails by building another pen. You can either build another 5 x 5 metre pen or you can build a still bigger pen.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">226. You can also raise more snails by taking better care of the snails that you have. If you take better care of your snails, year after year they will become bigger, healthier and stronger and produce more baby snails.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<B><P>&lt;&lt;TOC3&gt;&gt; Building the third pen</P>
+</B><P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">227. Perhaps the most important thing that you can do to improve your snail farm is to build a third pen.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&lt;&lt;I&gt;&gt; f34p109a.png Build a third pen</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">228. Up until now, using only two pens, you have had to use both of them all of the time so that you could take fully grown snails from one after you had harvested the other.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&lt;&lt;I&gt;&gt; f34p109b.png Using two pens</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">229. Today, farmers know that it is not good to grow the same crops in the same place all of the time.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">230. This is also true if you grow the same food and shelter plants in the same pen all of the time.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">231. However, if you plant vegetables in one of your three pens for a year, the vegetables will grow well because of the snail manure in the soil. Afterwards, your food and shelter plants will also grow better because the soil has had a rest.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">232. Also, if you raise snails in the same place all of the time, the sicknesses that they may get would do more harm year after year.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">233. So, if you plant something else for a year or two and then start with snails again, they will be less likely to get sick.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">234. The diagram below shows you how to improve a snail farm by planting a vegetable garden in each pen from to time.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&lt;&lt;I&gt;&gt; f34p110a.png Diagram</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<B><P>&lt;&lt;TOC3&gt;&gt; Building a bigger pen</P>
+</B><P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">235. You may want to build a still bigger pen for your third pen so you can grow many more snails.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">236. If you build a 5 x 10 metre pen, you can grow two times as many snails. If you build a 10 x 10 metre pen, you can grow four times as many snails as you did in a 5 x 5 metre pen.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&lt;&lt;I&gt;&gt; f34p110b.png Pens</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">237. However, building a bigger pen is a lot more work and you will need</P>
+<P ALIGN="JUSTIFY"></P><DIR>
+
+<P ALIGN="JUSTIFY"> more land</P>
+<P ALIGN="JUSTIFY"> more materials to build it</P>
+<P ALIGN="JUSTIFY"> more food and shelter plants</P>
+<P ALIGN="JUSTIFY"> more fully grown snails to begin</P>
+<P ALIGN="JUSTIFY"></P></DIR>
+
+<P ALIGN="JUSTIFY">238. You must also be sure that you and your family have enough time to take care of a bigger pen.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">239. If you do decide to build a bigger pen, build it exactly the same way that you built your first 5 x 5 metre pen (see pages 43 to 46 in the last booklet).</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&lt;&lt;I&gt;&gt; f34p111a.png Building a bigger pen</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<B><P>&lt;&lt;TOC3&gt;&gt; Taking better care of your snails</P>
+</B><P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">240. The better you understand the snails that you are farming, the better you can take care of them. So, you should always watch them and learn as much as you can.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">241. When you have learned the exact kinds of food plants that your snails like to eat, you will see that they grow well.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">242. Then, if you always choose the biggest and best snails each time you begin, you will improve the quality of the snails that you are farming.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">243. So, with bigger and better snails and with more pens or bigger pens, you will be able to raise many more snails to eat or to sell and you arid your family will be able to live better.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&lt;&lt;I&gt;&gt; f34p111b.png Your family will be able to live better</P></FONT></BODY>
+</HTML>
Index: /main/tags/2.25/gsdl/collect/demo/import/index.txt
===================================================================
--- /main/tags/2.25/gsdl/collect/demo/import/index.txt	(revision 21064)
+++ /main/tags/2.25/gsdl/collect/demo/import/index.txt	(revision 21064)
@@ -0,0 +1,12 @@
+key: Subject Organization Howto Magazine
+bostid/b22bue	16.11	bostid	"start a butterfly farm"
+faobetf/fb33fe	14.12	faobfs	<Subject>16.11
+faobetf/fb34fe	14.12	faobfs	"farm snails"	<Subject>16.11
+bostid/b18ase	16.11	bostid	"introduce little-known Asian farm animals with a promising future"
+bostid/b20cre	16.11	bostid
+bostid/b17mie	16.11	bostid	"introduce small animals and micro-livestock in your farm"
+bostid/b21wae	16.5	bostid	"utilize the Water Buffalo more effectively"	<Subject>16.11
+ecourier/ec158e	23.15	ecc	<Subject>8.1                               "<Magazine>The Courier"
+ecourier/ec159e	23.15	ecc	<Subject>6.1                               "<Magazine>The Courier"
+ecourier/ec160e	23.15	ecc	<Subject>21.1                              "<Magazine>The Courier"
+wb/wb34te	6.4	wb	"achieve gender equality"
Index: /main/tags/2.25/gsdl/collect/demo/import/wb/wb34te/wb34te.htm
===================================================================
--- /main/tags/2.25/gsdl/collect/demo/import/wb/wb34te/wb34te.htm	(revision 21064)
+++ /main/tags/2.25/gsdl/collect/demo/import/wb/wb34te/wb34te.htm	(revision 21064)
@@ -0,0 +1,1575 @@
+<HTML>
+<HEAD>
+<META HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=windows-1252">
+<META NAME="Generator" CONTENT="Microsoft Word 97">
+<TITLE>&lt;&lt;TOC1&gt;&gt; Development in practice: Toward Gender Equality </TITLE>
+</HEAD>
+<BODY>
+
+<B><FONT SIZE=2><P>&lt;&lt;TOC1&gt;&gt; Development in practice: Toward Gender Equality </P>
+</B><P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The Role of Public Policy</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">@ 1995 The Intentional Bank for Reconstruction and Development / THE WORLD BANK</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">All rights reserved Manufactured in the United States of America First printing July 1995</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The Development in Practice series publishes reviews of the World Bank's activities in different regions and sectors. It lays particular emphasis on the progress that is being made and on the policies and practices that hold the most promise of success in the effort to reduce poverty in the developing world.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">This book is a product of the staff of the World Bank. and the judgments made herein, do not necessarily reflect the views of its Board of Executive Directors or the countries they represent.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Photo credits: Maurice Asseo</P>
+<P ALIGN="JUSTIFY">Library of Congers Cataloging-in-Publication Data</P>
+<P ALIGN="JUSTIFY">Toward gender equality: the role of public policy.  p. cm-(Development in practice)</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Includes bibliographer references (p. 70)</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">ISBN 0-8213-3337-2</P>
+<P ALIGN="JUSTIFY">1. Women-Government policy. </P>
+<P ALIGN="JUSTIFY">2. Women's rights. </P>
+<P ALIGN="JUSTIFY">3. Sex discrimination against women. </P>
+<P ALIGN="JUSTIFY">4. Economic development.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">1. Series:</P>
+<P ALIGN="JUSTIFY">Development in practice (Washington. D.C.)</P>
+<P ALIGN="JUSTIFY">HQ 1 236.T68; 1995</P>
+<P ALIGN="JUSTIFY">305.4-dc20 95-631</P>
+<P ALIGN="JUSTIFY">CIP</P>
+<P ALIGN="JUSTIFY"></P>
+<B><P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="CENTER">&lt;&lt;TOC2&gt;&gt; Foreword</P>
+</B><P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">TWENTY years ago in Mexico the First World Conference on Women inspired a movement that has helped to reduce gender inequality worldwide. Illiteracy among women is declining, maternal mortality and total fertility rates are beginning to fall. and more women are participating in the labor force than ever before. However. much remains to be done.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">In low-income countries women are often denied health care and basic education. Worldwide. women face limited access to financial services, technology. and infrastructure. They are locked into relatively low-productivity work. In addition to performing household tasks and child-rearing duties, women work longer hours for lower pay than most men. And. most discouraging of all. hundreds of thousands of women each year are subject to gender-related violence.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Persistent inequality between women and men constrains a society's productivity and, ultimately slows its rate of economic growth. Although this problem has been generally recognized evidence on the need for corrective action is more controlling today than ever.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">This report written for the Fourth World Conference on Women is intended as a reference to strategies for promoting gender equality and. consequently enhancing economic efficiency. It pulls together evidence, including case studies, that demonstrates the need for governor action to improve the economic status of women. It points out how public policy can and should support services and infrastructure that provide the highest social returns and that are most heavily used by women. The report also aims to stimulate creative solutions to the problem of gender inequality by high lilting innovative and sometimes not obvious strategies that have proved successful. A study in Morocco, for instance, shows that paving public roads to schools increases by 40 percent the probability that local girls will attend classes.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Policy reform that provides an enabling environment for economic growth goes hand in hand with investing in people. The success of one strategy draws on the success of the other. No efforts at gender equality. however, can be successful without the participation of women themselves.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">As the international community gathers in Beijing for the Fourth World Conference on Women, the World Bank stands ready to assist client governments in response to the challenges ahead. The Bank believes that by advancing gender equality, governments can greatly enhance the future well-being and prosperity of their people.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Armeane M. Choksi Vice President Human Capital Development and Operations Policy The World Bank</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<B><P ALIGN="CENTER">&lt;&lt;TOC2&gt;&gt; Acknowledgments</P>
+</B><P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">THIS REPORT was prepared by a team led by Kei Kawabata and comprising Alison Evans, Zafiris Tzannatos. Tara Vishwanath, and Rekha Menon. The work was carried out under the direction of Minh Chau Nguyen and the overall guidance of K. Y. Amoako. Valuable contributions were made by Joyce Cacho, Lionel Demery, Shahid Khandker, and Kalanidhi Subbarao.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Background papers for the report were prepared by team members and by Anjana Bhushan; Lynn Brown and Lawrence Haddad; Florencia Castro-Leal, with Ignacio Tavares and Ramon Lopez; Roberta Cohen; Monica Fong: Roger Key, with Beverly Mullings; Andrew Mason; and Veena Siddharth.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">An external review group and a Bankwide advisory committee provided valuable guidance at all stages of the report's preparation. Kalpana Bardhan. Pranab Bardhan, Nancy Folbre. and T. Paul Schultz were the external reviewers. Harold Aldennan, Jean-Jacques Dethier, Louise Fox, Sunita Gandhi, Chris Grootaert, Jeffrey Hammer, Tariq Husahl, Elizabeth King, Augusta Molnar, Helena Ribe, and Paula Valad made up the advisory committee. The report was edited by Jo Bischoff, Richard M. Crum, and Fiona Mackintosh; Benjamin Crow provided word-processing and graphics support.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The report also reflects the contributions of the participants in consultations held with nongovenamental organizations on March 1S, 1995, in New York. Data supplied by the United Nations and its agencies. particularly the International Labour Organization, the United Nations Educational, Scientific, and Cultural Organization (UNESCO), the United Nations Statistical Office, and the World Health Organization, were invaluable for the preparation of the report.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The production of the report was made possible by the assistance of the Norwegian Ministry of Foreign Affairs, which has given unwavering support to the protnotion of gender equality.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<B><P ALIGN="CENTER">&lt;&lt;TOC2&gt;&gt; Definitions and Data Notes</P>
+</B><P ALIGN="JUSTIFY"></P>
+<B><P>&lt;&lt;TOC3&gt;&gt; Definitions</P>
+</B><P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Expected number of years of formal schooling The total number of years of schooling that a child of a certain age can expect to receive if current enrollment patterns remain unchanged.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Literacy rate. The proportion of the adult population that can read or write. This indicator is not always accurate because it is self-reported and represents past investments in schooling. It is often defined only with respect to selected languages and may not take into account the progress being made in many countries through literacy campaigns.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Life expectancy AT BIRTH The number of years a newborn infant would live if prevailing patterns of mortality at the time of birth were to remain unchanged throughout the child's life.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Maternal mortality ratio. The number of women who die in pregnancy and childbirth per 100,000 live births: A measure of the risk that women face of dying from pregnancy-related causes.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<B><P>&lt;&lt;TOC3&gt;&gt; Data Notes</P>
+</B><P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Unless otherwise specified, dollar amounts are current U.S. dollars. A billion is a thousand million.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The data used in this report cover a range of time periods and are from more than 100 countries (both developing and industrial).</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Unless otherwise specified, geographic regions are those used by the World Bank in its analytical and operational work and are defined as follows:</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">sub-Saharan  Africa countries south of the Sahara except Africa.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">East Asia and the Pacific: low- and middle-income economies of East and Southeast Asia and the Pacific.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Europe and Central Asia. middle-income European countries and the countries that formed the former Soviet Union.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Latin America anti the Caribbean all American and Caribbean economies south of the United States.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Middle East and North Africa all the economies of North Africa and the Middle East.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">South Asia: Bangladesh, Bhutan, India. Myantnar, Nepal, Pakistan. and Sri Lanka.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<B><P>&lt;&lt;TOC3&gt;&gt; Summary</P>
+</B><P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">THREE messages echo throughout this document:</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY"> The causes of gender inequality are complex, linked as they are to the intrahousehold decisionmaking process. However the decisions are made. the intrahousehold allocation of resources is influenced by market signals and institutional norms that do not capture the full benefits to society of investing in women. Low levels of education and training. poor health and nutritional status, and limited access to resources depress women's quality of life and hinder economic efficiency and growth.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY"> It is therefore essential that public policies work to compensate for market failures in the area of gender equality. These policies should equalize opportunities between women and men and redirect resources to those investments with the highest social returns. Of these investments. female education, particularly at the primary and lower-secondary level, is the most important, as it is the catalyst that increases the impact of other investments in health, nutrition, family planning, agriculture, industry, and infrastructure.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY"> Women themselves are agents for change because they play a key role in shaping the welfare of future generations. Public policies cannot be effective without the participation of the target group-in this case. women, who make up more than half the world's people. Their views need to be incorporated into policy formulation.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<B><P>&lt;&lt;TOC3&gt;&gt; Progress to Date</P>
+</B><P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Over the past two decades considerable progress has been made in reducing the gender gap world wide.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY"> In 1960. for every 100 boys enrolled in primary school. there were 65 girls. In 1990 the ratio had risen to 85.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY"> In 1980 an average six-year-old girl in a developing country could expect to attend school for 7.3 years. By 1990 this figure had Increased to 8.4 years.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY"> Since the 1950s the female labor force has grown twice as last as the male labor force. Worldwide, more than 40 percent of women over 15 years of age are now in the labor force; in developing countries women account for 30 percent of the labor force (These figures. it should be noted, do not fully reflect women's participation in the informal sector as unpaid family members in agriculture.)</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Nevertheless. inequalities between men and women persist in many important areas.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY"> Despite women s biological advantage, their mortality and morbidity rates frequently exceed those of men, particularly during childhood and the reproductive years.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY"> Traditionally women are employed in lower-pay jobs and in a narrower range of occupations than are men. Women's wages are typically only 60-70 percent of wages earned by men.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY"> Whether in private sector employment or public sector decisionmaking, women are less likely to be in positions of responsibility than are men.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<B><P>&lt;&lt;TOC3&gt;&gt; Why Do Gender Inequalities Persist?</P>
+</B><P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The causes of the persistent inequality between men and women are only partially understood. In recent years attention has focused on inequalities in the allocation of resources at the household level. as seen in the higher share of education, health. and food expenditures boys receive in comparison with girls. The decisionmaking process within households is complex and is influenced by social and cultural norms market opportunities, and institutional factors. There is considerable proof that the intrahousehold allocation of resources is a key factor in determining the levels of schooling. health. and nutrition accorded household members.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Inequalities in the allocation of household resources matter because education, health. and nutrition are strongly [hiked to well-being, economic efficiency. and growth. Low levels of educational attainment and poor health and nutrition aggravate poor living conditions and reduce an individual's capacity to work productively. Such economic inefficiency represents a significant loss to society and hampers future economic growth.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Social returns to investments in women's education and health  a? e significantly greater than for similar investment in men.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The social and economic losses are greatest when women are denied access to basic education and health care. Data from around the world show that private returns to investments in education are the same for women as for men and may even be marginally higher (Psacharopoulos 1994). More importantly. social returns (that is, total benefits to society) to investment in women's education and health are significantly greater than for similar investments in men, largely because of the strong correlation between women's education, health, nutritional status. and fertility levels and the education. health, and productivity of future generations. These correlation are even stronger when women have control over the way resources are allocated within the household.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Wage differentials between women and men in the market are closely linked to educational levels and work experience. since on average. women earn 30-40 percent less than teen' it is not surprising that fewer women than men participate in the labor force. This wage disparity, reinforced by discriminality institutional norms, in turn influences the intrahousehold division of resources. A vicious circle ensues as households invest less in daughters than in sons in the belief that investment in girls yields fewer benefits. As a result. many women are unable to work outside the household because they lack the education or experience that men have.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The decision not to participate in the labor force does not necessarily reflect a woman's own choice, no' does it always correspond to the optimum use of household resources. Furthermore. the market wage does not take into account the social benefits of educating and hiring women. Discrimination in households and in the market carries not only private costs for individuals and households but social costs for society as well.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Public policies for reducing gender inequalities are therefore essential for counteracting market failure and improving the well-being of all members of society. Investing in women's education and health expands their choices in labor markets and other income-generating activities and increases the rate of return on a household's most valuable asset-its labor.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The decision to allocate women's time to the type of non wage work women typically carry out within the household. such as child care. food preparation, and, in low-income countries especially, subsistence farming and the collection of fuel wood and water, has less to do with economics than with social conventions and norms. These nones can have a strong influence on the household division of labor, even in industrial economies, where women's levels of human capital are equal to-and some times higher than those of most men</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The economy pays to this inequality in reduced labour productivity today and diminished national output tomorrow</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Whether this division of labor is appropriate is, essentially, for society to decide. However. there is no doubt that women's entry into the labor market and other spheres of the economy is directly affected by the extensive amounts of time they traditionally devote to household maintenance and family care. Most men do not make similar allocations of time in the home. Such inequality constrains women's employment choices and can limit girls' enrollment in schools. The economy pays for this inequality in reduced labor productivity today and diminished national output tomorrow. Public policy can address inequalities in the household division of labor by supporting initiatives that reduce the amount of time women spend doing unpaid work. Examples of such interventions include improved water and sanitation services, rural electrification, and batter transport infrastructure.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Constraints on female employment opportunities arising from the household division of labor are compounded by institutional norms operating within the labor market. Although overt wage discrimination is illegal in many countries, employers frequently segregate jobs or offer less training to women workers. Employers often perceive the returns to investing in women workers as lower than those for men mainly because of women's primary role in childbearing.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Lack of access to financial services, to land, and to intonation and technology compounds the unequal treatment of women. Requirements for collateral, high transaction costs, and limited mobility and education contribute to women s inability to obtain credit. When women do have access to credit, the effect on household and individual well-being is striking. Bon-owing by women is linked to increased holdings of non-land assets, to improve in the health status of female children, and to an increased probability that girls will enroll in school. Independent access to land is associated with higher productivity and. in some cases, with greater investments by women in land conservation.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<B><P>&lt;&lt;TOC3&gt;&gt; Strategies for the Future</P>
+</B><P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">If the benefits from investing in girls and women are so great and can be quantified. why do households and employers underinvest in women? The main reason is that. as discussed above. markets fail to capture the full benefit to society of' investing in women and girls. Where the market fails or is absent. government must take the lead Public policy can contribute directly and indirectly. to reducing gender inequalities by, for example:</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY"> Modifying the legal and regulatory framework to ensure a opportunities </P>
+<P ALIGN="JUSTIFY"> Ensuring macroeconomic stability and improving, microeconomic incentives</P>
+<P ALIGN="JUSTIFY"> Redirecting public policies and public expenditures to those investments with the highest social returns</P>
+<P ALIGN="JUSTIFY"> Adopting targeted interventions that correct for gender inequalities at the micro-level.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Modifying the law to eliminate gender discrimination and equalize opportunities for women and men is an important first step. However. legal reform by itself does not ensure equal treatment. Further public action is required to make sure that gender-neutral laws are enforced at the national and local levels.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Sound economic policies and well-functioning markets are essential for growth, employment generation, and the creation of an environment in which the returns to divesting in women and owls can he fully realized. Economic instability and price distortions can hinder the process. Consequently. sound macroeconomic management is critical. In general. two sets of policies are necessary: one emphasizing macroeconomic stability and the elimination of price distortions. the other focusing on labor-demanding growth and a reorientation in public spending toward basic services with high social returns- such as education. health care and water supply.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Gender inequalities in the distribution of the benefits of public spending frequently arise because of a bias within households that limits women's access to publicly provided services. In addition, the services provided by public spending often are of less benefit to women than to men. Public policy can help remedy this problem by rearranging expenditure priorities among sectors and within the social sectors. It can ensure support for those services and types of infrastructure that offer the highest social returns to public spending and that are most heavily used by women and children. such as water supply anti sanitation services and rural electrification.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Finally general policy interventions may not be enough. and programs that specifically target women and girls may be required. Targeting is justified. Governments can no longer afford not to invest in women gable on two grounds. First. because women are disproportionately represented among the poor. targeting women can be an effective strategy for reducing poverty (broadly defined to include limited access to services. re sources, and other capability-enhancing factors). Second. where gender differences are wide, targeting-for example. the provision of stipends so that girls can attend school-they be needed to capture social gains and increase  internal efficiency</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<B><P ALIGN="CENTER">&lt;&lt;TOC2&gt;&gt; Conclusion</P>
+</B><P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Governments can no longer afford not to invest in women. The evidence on the high private and social returns to investments in women and girls cannot be ignored. By directing public resources toward policies and projects that reduce gender inequality. policymakers not only promote equality but also lay the groundwork for slower population growth, greater labor productivity, a higher rate of human capital formation, and stronger economic growth However, none of these developments can be sustained without the participial of women themselves. Governments and collaborating institutions must listen more carefully to the voices of individual women. including policymakers. and to women's groups. By working with others to identity and implement policies that promote gender equality, governments can make a real difference to the future well-being and prosperity of their people.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<B><P ALIGN="CENTER">&lt;&lt;TOC2&gt;&gt; Chapter one</P>
+</B><P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<B><P>&lt;&lt;TOC3&gt;&gt; Gender Inequalities Persist</P>
+</B><P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">ALTHOUGH the gap between opportunities for men and women is narrowing. inequalities persist, especially in certain regions. This report examines four major development indicators: educational attainment, maternal mortality. life expectancy. and economic participation outside the household. All four are closely related to each other and in turn are closely correlated with individual well-being. These indicators provide a broad picture of trends in gender inequality and their impact on the relative well-being of women and of men.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<B><P>&lt;&lt;TOC3&gt;&gt; Education</P>
+</B><P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Despite the progress in raising educational enrollment rates for both males and females across all regions in the past three decades, growth in educational opportunities at all levels for females lags behind that for males (figure 1.1). In 1990 an average six-year-old girl in a developing country could expect to attend school for 8.4 years. The figure had increased from 7.3 years in 1980-but an average boy of the same age in a developing country could expect to attend school for 9.7 years The gender gap in expected years of schooling is widest in some countries in South Asia, the Middle East, and Sub-Saharan Africa (see figure 1.2). Gender differences in access to education are usually worse in minority populations such as refugees and internally displaced persons. of which only a few children go to school.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&lt;&lt;I&gt;&gt; p16.png School enrollment ratios in developing countries </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The latest available figures show that 77 million girls of primary school age (6-11 years) are not in school, compared with 52 million boys (figure 1.3). Moreover, even these gross enrollment rates often mask high absenteeism and high dropout rates. Dropout rates are notably high in low-income countries but vary by gender worldwide and within regions. The rates for girls tend to be linked to age, peaking at about grade 5 and remaining high at the secondary level (Herz and others 1991) Cultural factors, early marriage, pregnancy, and household responsibilities affect the likelihood that girls will remain in school.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Although the gross enrollment rate is an acceptable indicator of progress in education, most studies use literacy rates as an indicator of well-being. Overall illiteracy rates have decreased among adults in low- and middle-income countries, but the percentage of illiterate women in the world is still higher than the percentage of illiterate men. Older women constitute the largest share of the illiterates in the world today, a consequence of past inequalities in access to education. In Sub-Saharan Africa, the Middle East, and South Asia more than 70 percent of women age 25 and older are illiterate (United Nations 1991).</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">At post-secondary levels. where the gap in enrollment between women and men is wider, there is implicit "gender streaming," or sex segregation, by field of study, even in areas with snore female than male enrollees. Gender streaming. which is widespread in both developing and industrial countries, prevents women from acquiring training in agriculture, forestry, fishing, "hard" sciences, and engineering (figure 1.4).</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&lt;&lt;I&gt;&gt; p17.png Expected years of schooling </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<B><P>&lt;&lt;TOC3&gt;&gt; Health</P>
+</B><P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Over the past two decades life expectancy at birth has increased for both men and women in all regions of the world. In industrial countries women tend to outlive men by six to eight years on average: in low-income countries gender differences are much narrower (two to three years). Despite women's biological advantage, female mortality and morbidity rates frequently exceed those of men, particularly during early childhood and the reproductive years.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">During the reproductive period the most Important causes of morbidity and mortality among women are high fertility and abortion rates, vulnerability to sexually transmitted diseases (STDS), genital mutilation. and gender violence. Each year, about 500,000 women worldwide die from the complications of pregnancy and childbirth. Maternal mortality ratios for developing and industrial countries vary greatly: the rates in parts of South Asia are among the world's highest, in some cases exceeding 1,500 per 100.000 live births. In Sub-Saharan Africa where the ratio is 700 maternal deaths per 100.000 live births, a woman runs a 1 in 22 lifetime risk of dying from pregnancy-related causes, but in northern Europe the risk falls to 10 in 100,000 (United Nations 1993). In the transition economies of Eastern Europe and the former Soviet Union, the rates are around 40 to 50 per 100,000 live births</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&lt;&lt;I&gt;&gt; p18.png Figure 1.3 children not in school 1990 </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">A major cause of maternal deaths is complications from unsafe abortions. Abortion-related deaths are highest in South and Southeast Asia. followed by Sub-Saharan Africa and Latin America and the Caribbean. Lack of access to contraceptives can mean that abortion, is used as a form of birth control. For example, in parts of Eastern Europe and Central Asia abortions are more numerous than live births (World Bank 1994b), and abortion rates were as high as 1.76 per live birth in Russia prior to the transition.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">As increasing numbers of women become aware of and learn to use contraceptives, total fertility rates are falling worldwide. The exception is Sub-Saharan Africa where the total fertility rate averaged 6.4 between 1985 have been infected by HIV. The World Health organization (WHO 1994) estimates that more than 13 million women will have been infected by HIV by 2000 and that about 4 million of that number will have died (figure 1.5 In Atrica, where 10 million adults are infected with the virus, ode-half of all newly infected adults are women, and more than 5 million are women of childbearing age. In Asia almost half of all adults newly infected with the virus are women, compared with less than 25 percent just six years ago.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&lt;&lt;I&gt;&gt; p19.png Figure 1.4 fields of study</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&lt;&lt;I&gt;&gt; p20.png  Figure 1.5 HIV infected women 1995 </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The mortality risk for females is high during the reproductive years. but it is even higher during infancy and early childhood. Between 1962 and 1992 INFANT mortality in the developing world decreased by 50 percent (UNICEF 1993 However, in seventeen of the twenty-nine developing countries for which recent survey data are available, female children age 1-4 were found to have higher mortality rates than male children. despite girls? biological advantage (World Bank 1994b). In many of these countries the underlying cause of high mortality among girls is the parents' bias toward boys, who receive the best food and medical care.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Genital mutilation, prevalent in twenty-eight countries, is performed on 2 million young girls yearly. The practice leads to long-term morbidity, complications during childbirth, mental trauma, and even death. Table 1.1 summarizes the best available statistics on this practice for selected countries.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<B><P>&lt;&lt;TOC3&gt;&gt; Employment Work</P>
+</B><P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The time women spend on paid and unpaid work is typically greater than the time men spend in the labor market (see table 1.2 for an example). Unpaid family work is rarely recorded in official statistics. It manifests itself only indirectly in the labor market in the form of gender differences in labor force participation rates. sector of employment, hours of work, and wage level.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">On the whole. labor force participation rates for women are lower than those for men (figure 1.6). However. these differences are often exaggerated because the definition of the participation rate fails to capture many aspects of women's work, particularly time spent on childbearing, childbearing. and other household tasks. Men are usually in the labor force throughout the prime working years (age 20-60), and their participation rates are typically more than 90 percent in virtually every country. Female participation rates vary widely across countries. In 1990, for every ten men in the labor force there were two women in the Middle East and North Africa, three in South Asia. six in Sub-Saharan Africa, and seven in Southeast Asia (United Nations 1991). Worldwide, 41 percent of women age 15 years or over are in the labor force, but in developing countries the corresponding figure is 31 percent.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">These numbers are deceptive, however, because they do not take into account the agricultural work for which women in developing countries are responsible within the family For example, the Dominican census of 1981 reported that only 21 percent of rural women participated in the labor force, but just three years later a special study suggested a figure of 81 percent. The census had omitted such activities as cultivating gardens and caring for domestic animals In India different definitions of what constitutes "work" have resulted in estimated participation rates as low as 13 percent and as high as 88 percent (Beneria 1992).</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Tens of Millions of Women Suffer Female Genital Mutilation.</P>
+<P ALIGN="JUSTIFY"></P>
+<B><P ALIGN="JUSTIFY">Table 1.1 female genital mutilation</P>
+</B><P ALIGN="JUSTIFY"></P></FONT>
+<TABLE BORDER CELLSPACING=2 CELLPADDING=7 WIDTH=468>
+<TR><TD WIDTH="26%" VALIGN="TOP">
+<B><FONT SIZE=2><P ALIGN="JUSTIFY">Country</B></FONT></TD>
+<TD WIDTH="38%" VALIGN="TOP">
+<B><FONT SIZE=2><P ALIGN="JUSTIFY">Estimated prevalence (percent)</B></FONT></TD>
+<TD WIDTH="36%" VALIGN="TOP">
+<B><FONT SIZE=2><P ALIGN="JUSTIFY">Estimated number of women affected (millions)</B></FONT></TD>
+</TR>
+<TR><TD WIDTH="26%" VALIGN="TOP">
+<FONT SIZE=2><P ALIGN="JUSTIFY">Djibouti</FONT></TD>
+<TD WIDTH="38%" VALIGN="TOP">
+<FONT SIZE=2><P ALIGN="JUSTIFY">98</FONT></TD>
+<TD WIDTH="36%" VALIGN="TOP">
+<FONT SIZE=2><P ALIGN="JUSTIFY">0.2</FONT></TD>
+</TR>
+<TR><TD WIDTH="26%" VALIGN="TOP">
+<FONT SIZE=2><P ALIGN="JUSTIFY">Egypt</FONT></TD>
+<TD WIDTH="38%" VALIGN="TOP">
+<FONT SIZE=2><P ALIGN="JUSTIFY">50</FONT></TD>
+<TD WIDTH="36%" VALIGN="TOP">
+<FONT SIZE=2><P ALIGN="JUSTIFY">13.5</FONT></TD>
+</TR>
+<TR><TD WIDTH="26%" VALIGN="TOP">
+<FONT SIZE=2><P ALIGN="JUSTIFY">Eritrea</FONT></TD>
+<TD WIDTH="38%" VALIGN="TOP">
+<FONT SIZE=2><P ALIGN="JUSTIFY">90</FONT></TD>
+<TD WIDTH="36%" VALIGN="TOP">
+<FONT SIZE=2><P ALIGN="JUSTIFY">1.5</FONT></TD>
+</TR>
+<TR><TD WIDTH="26%" VALIGN="TOP">
+<FONT SIZE=2><P ALIGN="JUSTIFY">Ethiopia</FONT></TD>
+<TD WIDTH="38%" VALIGN="TOP">
+<FONT SIZE=2><P ALIGN="JUSTIFY">90</FONT></TD>
+<TD WIDTH="36%" VALIGN="TOP">
+<FONT SIZE=2><P ALIGN="JUSTIFY">22.5</FONT></TD>
+</TR>
+<TR><TD WIDTH="26%" VALIGN="TOP">
+<FONT SIZE=2><P ALIGN="JUSTIFY">Kenya</FONT></TD>
+<TD WIDTH="38%" VALIGN="TOP">
+<FONT SIZE=2><P ALIGN="JUSTIFY">50</FONT></TD>
+<TD WIDTH="36%" VALIGN="TOP">
+<FONT SIZE=2><P ALIGN="JUSTIFY">6.3</FONT></TD>
+</TR>
+<TR><TD WIDTH="26%" VALIGN="TOP">
+<FONT SIZE=2><P ALIGN="JUSTIFY">Nigeria</FONT></TD>
+<TD WIDTH="38%" VALIGN="TOP">
+<FONT SIZE=2><P ALIGN="JUSTIFY">50</FONT></TD>
+<TD WIDTH="36%" VALIGN="TOP">
+<FONT SIZE=2><P ALIGN="JUSTIFY">29.2</FONT></TD>
+</TR>
+<TR><TD WIDTH="26%" VALIGN="TOP">
+<FONT SIZE=2><P ALIGN="JUSTIFY">Sierra Leone</FONT></TD>
+<TD WIDTH="38%" VALIGN="TOP">
+<FONT SIZE=2><P ALIGN="JUSTIFY">90</FONT></TD>
+<TD WIDTH="36%" VALIGN="TOP">
+<FONT SIZE=2><P ALIGN="JUSTIFY">2.0</FONT></TD>
+</TR>
+<TR><TD WIDTH="26%" VALIGN="TOP">
+<FONT SIZE=2><P ALIGN="JUSTIFY">Sudan</FONT></TD>
+<TD WIDTH="38%" VALIGN="TOP">
+<FONT SIZE=2><P ALIGN="JUSTIFY">89</FONT></TD>
+<TD WIDTH="36%" VALIGN="TOP">
+<FONT SIZE=2><P ALIGN="JUSTIFY">118</FONT></TD>
+</TR>
+</TABLE>
+
+<FONT SIZE=2><P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">In Sri Lanka's Dry Zone, Women Work Longer Hours than Men.</P>
+<P ALIGN="JUSTIFY"></P>
+<B><P ALIGN="JUSTIFY">Table 1.2 distribution of monthly work hours per month)</P>
+</B><P ALIGN="JUSTIFY"></P></FONT>
+<TABLE BORDER CELLSPACING=2 CELLPADDING=7 WIDTH=451>
+<TR><TD WIDTH="40%" VALIGN="TOP">&nbsp;</TD>
+<TD WIDTH="31%" VALIGN="TOP" COLSPAN=2>
+<B><FONT SIZE=2><P ALIGN="JUSTIFY">Peal. Season</B></FONT></TD>
+<TD WIDTH="29%" VALIGN="TOP" COLSPAN=2>
+<B><FONT SIZE=2><P ALIGN="JUSTIFY">Slack season</B></FONT></TD>
+</TR>
+<TR><TD WIDTH="40%" VALIGN="TOP">
+<B><FONT SIZE=2><P ALIGN="JUSTIFY">Activity </B></FONT></TD>
+<TD WIDTH="15%" VALIGN="TOP">
+<B><FONT SIZE=2><P ALIGN="JUSTIFY">Male</B></FONT></TD>
+<TD WIDTH="17%" VALIGN="TOP">
+<B><FONT SIZE=2><P ALIGN="JUSTIFY">Female</B></FONT></TD>
+<TD WIDTH="10%" VALIGN="TOP">
+<B><FONT SIZE=2><P ALIGN="JUSTIFY">Male</B></FONT></TD>
+<TD WIDTH="18%" VALIGN="TOP">
+<B><FONT SIZE=2><P ALIGN="JUSTIFY">Female</B></FONT></TD>
+</TR>
+<TR><TD WIDTH="40%" VALIGN="TOP">
+<FONT SIZE=2><P ALIGN="JUSTIFY">Agricultural production</FONT></TD>
+<TD WIDTH="15%" VALIGN="TOP">
+<FONT SIZE=2><P ALIGN="JUSTIFY">298</FONT></TD>
+<TD WIDTH="17%" VALIGN="TOP">
+<FONT SIZE=2><P ALIGN="JUSTIFY">299</FONT></TD>
+<TD WIDTH="10%" VALIGN="TOP">
+<FONT SIZE=2><P ALIGN="JUSTIFY">245</FONT></TD>
+<TD WIDTH="18%" VALIGN="TOP">
+<FONT SIZE=2><P ALIGN="JUSTIFY">235</FONT></TD>
+</TR>
+<TR><TD WIDTH="40%" VALIGN="TOP">
+<FONT SIZE=2><P ALIGN="JUSTIFY">Household tasks</FONT></TD>
+<TD WIDTH="15%" VALIGN="TOP">
+<FONT SIZE=2><P ALIGN="JUSTIFY">90</FONT></TD>
+<TD WIDTH="17%" VALIGN="TOP">
+<FONT SIZE=2><P ALIGN="JUSTIFY">199</FONT></TD>
+<TD WIDTH="10%" VALIGN="TOP">
+<FONT SIZE=2><P ALIGN="JUSTIFY">60</FONT></TD>
+<TD WIDTH="18%" VALIGN="TOP">
+<FONT SIZE=2><P ALIGN="JUSTIFY">220</FONT></TD>
+</TR>
+<TR><TD WIDTH="40%" VALIGN="TOP">
+<FONT SIZE=2><P ALIGN="JUSTIFY">Fetching water and firewood</FONT></TD>
+<TD WIDTH="15%" VALIGN="TOP">
+<FONT SIZE=2><P ALIGN="JUSTIFY">30</FONT></TD>
+<TD WIDTH="17%" VALIGN="TOP">
+<FONT SIZE=2><P ALIGN="JUSTIFY">50</FONT></TD>
+<TD WIDTH="10%" VALIGN="TOP">
+<FONT SIZE=2><P ALIGN="JUSTIFY">:30</FONT></TD>
+<TD WIDTH="18%" VALIGN="TOP">
+<FONT SIZE=2><P ALIGN="JUSTIFY">60</FONT></TD>
+</TR>
+<TR><TD WIDTH="40%" VALIGN="TOP">
+<FONT SIZE=2><P ALIGN="JUSTIFY">Social and religious duties</FONT></TD>
+<TD WIDTH="15%" VALIGN="TOP">
+<FONT SIZE=2><P ALIGN="JUSTIFY">8</FONT></TD>
+<TD WIDTH="17%" VALIGN="TOP">
+<FONT SIZE=2><P ALIGN="JUSTIFY">12</FONT></TD>
+<TD WIDTH="10%" VALIGN="TOP">
+<FONT SIZE=2><P ALIGN="JUSTIFY">15</FONT></TD>
+<TD WIDTH="18%" VALIGN="TOP">
+<FONT SIZE=2><P ALIGN="JUSTIFY">15</FONT></TD>
+</TR>
+<TR><TD WIDTH="40%" VALIGN="TOP">
+<FONT SIZE=2><P ALIGN="JUSTIFY">Total work hours</FONT></TD>
+<TD WIDTH="15%" VALIGN="TOP">
+<FONT SIZE=2><P ALIGN="JUSTIFY">426</FONT></TD>
+<TD WIDTH="17%" VALIGN="TOP">
+<FONT SIZE=2><P ALIGN="JUSTIFY">560</FONT></TD>
+<TD WIDTH="10%" VALIGN="TOP">
+<FONT SIZE=2><P ALIGN="JUSTIFY">350</FONT></TD>
+<TD WIDTH="18%" VALIGN="TOP">
+<FONT SIZE=2><P ALIGN="JUSTIFY">530</FONT></TD>
+</TR>
+<TR><TD WIDTH="40%" VALIGN="TOP">
+<FONT SIZE=2><P ALIGN="JUSTIFY">Leisure and sleep</FONT></TD>
+<TD WIDTH="15%" VALIGN="TOP">
+<FONT SIZE=2><P ALIGN="JUSTIFY">294</FONT></TD>
+<TD WIDTH="17%" VALIGN="TOP">
+<FONT SIZE=2><P ALIGN="JUSTIFY">160</FONT></TD>
+<TD WIDTH="10%" VALIGN="TOP">
+<FONT SIZE=2><P ALIGN="JUSTIFY">370</FONT></TD>
+<TD WIDTH="18%" VALIGN="TOP">
+<FONT SIZE=2><P ALIGN="JUSTIFY">190</FONT></TD>
+</TR>
+</TABLE>
+
+<FONT SIZE=2><P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Women are usually employed in different sectors than men. Most of women's nonagricultural employment is in the service sector. but in developing countries female employment in manufacturing has been increasing and is catching up with female employment in services (ILO/ INSTRAW 1985). Women in manufacturing tend to be concentrated in only a few sub sectors: more than two-thirds of the global labor force in garment production is female. and this subsector absorbs almost one-fifth of the female labor force in manufacturing (UNIDO 1993). Men's employment is more evenly distributed across other sectors such as mining manufacturing, construction, utilities, and transport.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Over their lifetime, women change their employment status more often than do men. They are also more likely to be self-employed or employed in occupations with flexible house such as subcontracted home work. Regardless of the sector in which they are employed, women tend to work in a narrow range of occupations. Only a few women are in high-paying jobs or in positions with significant responsibility. Nearly two-thirds of the women in manufacturing ate laborers, machine operators. and production workers; only 5 percent ate professional and technical workers and only 2 percent are administrators and managers (UNIDO 1993). However. there are regional differences: women occupy nearly 60 percent of clerical, sales. and service jobs in Latin America and the Caribbean but fewer than 20 percent of similar positions in South Asia North Africa. and the Middle East (figure 1.7).</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&lt;&lt;I&gt;&gt; p23.png Figure 1.6 rates of participation in the labor force by gender</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Wages paid to women are typically about 60-70 percent of those paid to men. About one-quarter of the gender wage gap is explained by differences in educational levels, labor market experience, and other human capital'' characteristics (Psacharopoulos and Tzannatos 1992 Horton 1994). The gender wage gap can also be explained in part by women's lower participation in the labor market-a consequence of domestic and other demands on their time and, possibly, of discriminatory employment practices.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Significant changes in the global economy have affected patterns of employment and working conditions for men and women worldwide. "Globalization" is associated with the deregulation of product and labor markets, with regionalization. and with the liberalization of international trade. In turn. these processes at-e associated with increased female participation in the labor force and with the at-owing "casualization'' of employment, as seen in the growth of part-time work in industrial economies. However, the net effect of globalization on women workers is not yet clear. Growth in the international traded service sector (for example, banking and telecommunications) seems to have offered women in developing countries greater employment opportunities. In addition, the participation rate of women in manufacturing jobs has increased faster than that of men. Women's average participation in the manufacturing labor force is now around 30 percent for both developing and industrial countries.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&lt;&lt;I&gt;&gt; p24.png Figure 1.7 types of jobs held by women </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Worldwide, the number of women employed in export manufacturing has been increasing rapidly, even though this sector employs only a small fraction of all women workers. In Mexico, for example, the number of women employed in export manufacturing rose by nearly 15 percent a year in the 1980s (Jurisman and Moreno 1990). However, employment in this sector has been increasing more rapidly for men than for women, partly because of</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">technological upgrading over time and partly; because women are less educated and tend to remain in low-skill occupations (Baden 1992).</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Women now account for a growing share ret wage employment they tend to stay longer in the labor force than ever before</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Despite persistent gender inequalities in the labor market. some recent trends  are encouraging. Increasing educational opportunities and decreasing fertility  rates have fed to an increase in the number of women entering the labor market. since the 1950s the female labor force has expanded twice as fast as the male  labor force. Women now account for a growing share of wage employment. and they tend to stay longer in the labor force than ever before The narrowing of the gender gap in labor force participation is enabling women to accumulate the work experience necessary tot- improving their job opportunities and increasing their amines. In the formal sector more and more women are working in occupations and sectors once dominated by men. and in many countries women s wages relative to men s have increased over time</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The data in this chapter illustrate some aggregate trends but they cannot tell US anything about the processes behind the persistence of gender inequality. For a more detailed look at these processes. We turn in the next chapter to a growing body of empirical evidence generated at the household and enterprise level. These studies provide a telling insight into the way in which gender inequalities are being challenged particularly by women At the same time these inequalities are reinforced by economic, legal. and cultural incentive systems that discriminate against women Discrimination continues despite compelling evidence showing that less inequality especially within the household. is associated with heftier welfare outcomes for children and better economic outcomes for the household as a v hole.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<B><P ALIGN="CENTER">&lt;&lt;TOC2&gt;&gt; Chapter two</P>
+</B><P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<B><P>&lt;&lt;TOC3&gt;&gt; Gender Inequalities Hamper Growth</P>
+</B><P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Inequality women and men limits productivity ultimately slows economic growth. early empirical studies (for example, Kuznets 1955) suggested that income inequality would increase with economic growth during the initial phases of development. This chapter, however. starts with the hypothesis that there is not necessarily a tradeoff between inequality and growth and. indeed that high inequality especially as it affects human capital. hampers growth (Fields 1992: Birdsall and Sabot 1994).</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Both theory and empirical evidence point to the importance of human capital in creating the necessary conditions for productivity growth and in reducing aggregate inequality in the future. In addition. women s human capital generates benefits for society in the form of lower child mortality.  higher educational attainment improved nutrition. and reduced population growth. Inequalities in the accumulation and use of human capital at-e related to lower economic and social well-being for all.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<B><P>&lt;&lt;TOC3&gt;&gt; Household and Intrahousehold Resource Allocation</P>
+</B><P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">In recent years, attempts to explain persistent gender inequalities in the accumulation and use of human capital have focused on the key role of household decisionmaking and tile process of resource allocation within household Households do not make decisions in isolation. however: their decision are linked to market prices and incentives and are influenced by cultural legal and state institutions. These institutions indirectly affect not only the returns on household investment but also access to productive resources and employment outside the house hold.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Household decisions about the allocation of resources have a profound effect on the schooling, health care, and nutrition children receive. The mechanisms used to make these decisions and the effect of the decisions on the well-being of individual household members are not fully understood. Two frameworks for thinking about household decisions are the unitary household model and the collective household model (see box 3.1)</P>
+<P ALIGN="JUSTIFY"></P></FONT>
+<TABLE BORDER CELLSPACING=2 CELLPADDING=7 WIDTH=590>
+<TR><TD VALIGN="TOP">
+<B><FONT SIZE=2><P ALIGN="JUSTIFY">BOX 2.1 </P>
+</B><P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Two models of household members having their own prefer decisionmaking encase. Decisions on allocating resources reflect market rates of return. The unitary household model assumes but they also mirror the relative bar that household members pool regaining power of household members sources and allocate them according within the collective (Manser and to a common set of objectives and Brown 1980: McElroy and Homey goals. Households maximize the joint 1981). Bargaining power is a function welfare of their members by allocating of social and cultural norms. as well income and other resources to the in as of such external factors as opposed individuals and enterprises that promise "unities for paid work, laws governing the highest rate of return as reflected inheritance, and control over producing prices and wages. An increase initiative assets and property rights. These household income increases the well factors influence the terms governing being of all household members.</FONT></TD>
+</TR>
+</TABLE>
+
+<FONT SIZE=2><P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Policy interventions based on the sources and decisions about how unitary household model aim to in those resources are used within the crease household welfare, but they household. Thus, an increase in do not necessarily affect all household income may benefit some hold members in the same way. Some household members but leave others household members may be worse unaffected or worse off. The outcome off, for example, if they lose control depends on a member's ability to exover certain resources; others may excise control over resources both in be better off. in which case house-side and outside the household, and it hold welfare is not maximized. cannot be assumed that individual well</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Under the collective household being increases as household income model. the welfare of individual house-rises. (Collective household models do hold members is not synonymous with not exclude the possibility that the universal household welfare. Resources unitary model may be the best approximate not necessarily pooled, and the motion of household decisionmaking household acts as a collective, with in some contexts.)</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The collective household model helps explain why gender inequalities persist even though household becomes increase over time The next sections adopt a collective household framework to explain how these inequalities exact costs in forgone productivity, seduced welfare for individuals and households, encl. ultimately. slower economic growth.(fender Inequalities in Human Capital )</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">There are strong complementaires between education. health. and nutrition on the one hand, and increased well-being, labor productivity, and growth. On the other. Inequalities in resource allocation that limit household members' educational opportunities. access to health care, or nutrition are costly to individuals, households, and the economy as a whole.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<B><P>&lt;&lt;TOC3&gt;&gt; Linkages between Education Health, and Nutritious</P>
+</B><P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">At the household level. gender differences in access to education are closely related to inequalities in the shares of household education expenditures allocated to boys and to girls This finding stands even though private returns to girls' schooling are similar to or marginally higher than. those to boys' schooling (figure 2.1; see also Schultz 1988: Mwabu 1994). In this case. parental choice reflects the relatively greater restrictions on educational opportunities and employment choices for girls. in comparison with boys. and cultural norms on the appropriate role for girls within the household.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&lt;&lt;I&gt;&gt; p28.png Figure 2.1 private returns to education</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&lt;&lt;I&gt;&gt; p29a.png Figure 2.2 education, fertility. and child mortality (a)</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&lt;&lt;I&gt;&gt; p29b.png Figure 2.2 education, fertility. and child mortality (b)</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">More importantly. the social externalities linked to female education are crucial. Evidence from a large number of countries shows that female education is linked with better health for women and their children and with lower levels (figure 2.2). This link stems from the direct effect of education on the value of a woman's time and consequently. on private returns to her labor. It also stems from the indirect effect of education on the average age at which women marry on their knowledge of basic health care and nutrition, and on reproductive choices (Rosenzweig and Schultz 1982, 1987).</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Educating girls and women reduces maternal mortality and fertility rates and increases the demand for health services. A simulation study of seventy two developing countries shows that, with all other factors held constant, a doubling of female secondary school enrollments in 1975 would have reduced tile average fertility rate in 1985 from 5.3 to 3.9 children per household and would have lowered the number of births by 29 percent (Subbarao and Raney 1992. Studies for individual countries have found that one additional year of female schooling can reduce the fertility rate. on average, between 5 and 1 (i) percent (Summers 1994)</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Women are more vulnerable than men to micronutrient deficiencies that aggravate poor health (World Batik 1994b). Poor health and nutrition reduce productivity and the chances of reaping gains from investment in education. Intrahousehold inequalities in consumption and nutritional allocations can therefore be a signal of inefficiency Recent estimates suggest that the com effects on morbidity and mortality of just three types of deficiency-in vitamin A, iodine. and iron-could waste as much as 5 percent of gross domestic product (GDP), yet correcting these deficiencies would cost less than 0.3 percent of low-income countries' GDP (World Bank 1994c, pp. 50-51). Studies of women tea producers in Sri Lanka and of women workers in Chinese cotton mills document the reduction in productivity associated with iron deficiencies and the positive effects of in-on supplementation on work and output (Edgerton and others 1979). A study of six villages in Andhra Pradesh, India, found that disabling conditions caused by malnutrition and the prevalence of diseases reduced female labor force participation by 22 percent (Chatterjee 1991).</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Physical anti mental abuse can also have deleterious effects on the well-being and productivity of women (table 2.1). Violence against women is widespread in all cultures and cuts across all age and income groups Its consequences. include unwanted pregnancy. infection with STDs, miscarriage partial or permanent disability. and psychological problems such as depression anti low self-esteem. Recent World Bank estimates indicate that in both industrial and developing countries domestic violence and rape cause women of reproductive age to lose a significant percentage of really days. Domestic violence appears to be an example of how the relatively weaker bargaining power of women and the paucity of options for them outside the home can affect the intrahousehold distribution of welfare.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Violence against Women Starts in the Womb and Continues  trough Life</P>
+<P ALIGN="JUSTIFY"></P>
+<B><P ALIGN="JUSTIFY">Table 2.1 Violence against women through the life cycle</P>
+</B><P ALIGN="JUSTIFY"></P></FONT>
+<TABLE BORDER CELLSPACING=2 CELLPADDING=7 WIDTH=590>
+<TR><TD WIDTH="22%" VALIGN="TOP">
+<B><FONT SIZE=2><P ALIGN="JUSTIFY">Phase</B></FONT></TD>
+<TD WIDTH="78%" VALIGN="TOP">
+<B><FONT SIZE=2><P ALIGN="JUSTIFY">Type of violence</B></FONT></TD>
+</TR>
+<TR><TD WIDTH="22%" VALIGN="TOP">
+<FONT SIZE=2><P ALIGN="JUSTIFY">Pre birth</FONT></TD>
+<TD WIDTH="78%" VALIGN="TOP">
+<FONT SIZE=2><P ALIGN="JUSTIFY">Battering during pregnancy (emotional and physical effects on the ottoman) effects on birth outcome</FONT></TD>
+</TR>
+<TR><TD WIDTH="22%" VALIGN="TOP">
+<FONT SIZE=2><P ALIGN="JUSTIFY">Infancy</FONT></TD>
+<TD WIDTH="78%" VALIGN="TOP">
+<FONT SIZE=2><P ALIGN="JUSTIFY">Female infanticide: emotional and physical abuse</FONT></TD>
+</TR>
+<TR><TD WIDTH="22%" VALIGN="TOP">
+<FONT SIZE=2><P ALIGN="JUSTIFY">Girl hood</FONT></TD>
+<TD WIDTH="78%" VALIGN="TOP">
+<FONT SIZE=2><P ALIGN="JUSTIFY">Sexual abuse by family members and strangers: forced child prostitution</FONT></TD>
+</TR>
+<TR><TD WIDTH="22%" VALIGN="TOP">
+<FONT SIZE=2><P ALIGN="JUSTIFY">Adolescence</FONT></TD>
+<TD WIDTH="78%" VALIGN="TOP">
+<FONT SIZE=2><P ALIGN="JUSTIFY">Dating and courtship violence: economically coerced sex: sexual abuse in the workplace: rape: farce prostitution and trafficking in women</FONT></TD>
+</TR>
+<TR><TD WIDTH="22%" VALIGN="TOP">
+<FONT SIZE=2><P ALIGN="JUSTIFY">Reproductive</FONT></TD>
+<TD WIDTH="78%" VALIGN="TOP">
+<FONT SIZE=2><P ALIGN="JUSTIFY">Coerced pregnancy: rape: abuse of women by male partners: down abuse and murder partner homicide psychological abuse sexual abuse of unmarried and childless women: abuse of women with disabilities</FONT></TD>
+</TR>
+</TABLE>
+
+<FONT SIZE=2><P ALIGN="JUSTIFY">Source: Heise 1993 </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Prospects for gainful employment. as well as the availability of basic social services such as water supply and sanitation. also influence women's well-being. The survival chances of female children in India appear to increase as the employment rate for women rises and the earnings differential between men and women decreases Battilan 1988 Dowry and marriage practices. along with household ownership of land are closely linked to women's chances of survival The effect of such practices cannot be over late. Sen's (1990) comparison of female-male mortality rates in China. India. and Sub-Saharan Africa suggest that more than 100 million women are "missing"</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Public spending on social services affects the ability of individuals and households to benefit from their own private spending on human capital. In most industrial countries mortality rates decreased even before modern medical care became widely available, mainly because of improved water supplies and sanitation. The same is likely to hold for the developing world. Public interventions that address market under provision of water and sanitation facilities and shortages of health set-vices such as immunization and family planning-have a significant effect. and one that is probably greater for women than for men.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Lack of data makes it difficult to evaluate the effects of public spending on the educational attainment and health of women and men Very little empirical evidence in this area exists, but there is some indication that the proportion of public subsidies for education that benefits females is lower than the proportion that benefits males. In Kenya in 1992-93. for example. public spending on education amounted to the equivalent of an annual subsidy of 605 Kenyan shillings per capita: males received. on average. 670 shillings and females only 543 shillings. In Mexico the gender difference in public education subsidies was somewhat less: in Pakistan males received almost twice the female subsidy. Gender inequalities in the distribution of subsidies are greater at high than at primary levels. In Pakistan girls receive, on average. only 96 rupees a year for secondary school bag. compared with 58 rupees for boys. Box 2.2 explains how these figures are calculated.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Supply-side differences are partly a function of poorly targeted resources (as. for example, when more is spent on tertiary than on primary schooling). More importantly. they reflect differences in household demand for education for girls and boys. If more girls attended anti stayed in school. the proportion of public subsidy going to girls would he greater.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">In health care assessing the incidence of public spending by gender is particularly difficult because of the marked differences in the health needs of women and men. These differences are related to different biological re</P>
+<P ALIGN="JUSTIFY"></P></FONT>
+<TABLE BORDER CELLSPACING=2 CELLPADDING=7>
+<TR><TD></TD>
+</TR>
+</TABLE>
+
+<FONT SIZE=2><P ALIGN="JUSTIFY">The main advantage of this type of analysis is that it measures how well public  services are targeted to certain groups in the population, including women, the  poor, and residents of regions of interest.  Requirements anti to women's reproductive and childbearing roles. Some evidence suggests that because of these differences. per capita health cat-e subsidies to women are the same as and sometimes larger than those to men What is clearer is that women are less likely than men to seek health care. including in many countries. hospital care when it is netted and ate mote likely to consult a non medical health cat-e worker (lather than a qualified medical practitioner). Education tends to increase the likelihood that women will seek health care. whether public or  ace the likelihood that women will seek health care. whether public or private (World Bank 1994b). </P>
+<P ALIGN="JUSTIFY">The importance of private and public investments in education and health services that will improve women's well-being is cleat. These services at-e also important for another season: these is important evidence that increases in women's well-being yield important intergenerational benefits and productivity gains in the future World Bank Living Standards Measure Study (LSMS) surveys car-tried out in Nicaragua (1993 Viet Nam 1993) Pakistan (1991), and Cote (1988) suggest that the probability of children being enrolled in school increases with their mother's educational level and that (controlling, for income and household size) girls. particularly those in non poor households. are mote likely to attend school if their mothers attended school. Other studies show that households with educated mothers lend to provide children with greater quantities of mote nutritious food often at a lower cost. than households with poorly educated mothers (Thomas 1990b)</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Data from Brazil show that giving women more control over nonlabor income has a larger impact on child measures, nutritional intakes, and the proportion of the household budget devoted to human capital inputs than if men had control of this income (Thomas 1993) Other studies indicate that women spend proportionately mote of the income they control on health care for children than do men. Women also spend more on food products (as opposed to such goods as alcohol and tobacco) than men do (Duraiswamy 1992: Hoddinot and Haddad 1992) But fathers education is also important especially in interaction with mothers' education (Thomas 1990a) </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Other studies have shown that children's educational attainment is lowest in households whet-e the male head has no schooling In Ghana the impact of a mother's education on her children's schooling is reduced when  their father has no schooling. even after controlling for income and household size (Lavy 1992).</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Material health (which is linked to education) also has important intergenerational effects. Children of mothers who are malnourished or sickly or receive inadequate prenatal and delivery cat-e face a greater risk of disease and premature death. Iodine-deficient mothers run a greater risk of giving birth to infants with severe mental retardation and other congenital abnormalities than do healthy mothers. Reduced fertility and improved health for women can increase individual productivity and improve family well-being. When good health is combined with education and access to jobs. the result is higher rates of economic growth.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<B><P>&lt;&lt;TOC3&gt;&gt; Household and Labor Market Linkages</P>
+</B><P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The link between the household and the labor market is particularly important. Specialization of labor within the household-whether individually chosen. socially determined. or legally induced-can accentuate gender inequalities in the formal and informal labor markets by leaving most of the unpaid work to women. This situation arises from convention rather than  from comparative advantage Inadequate public and community services.  transport. and housing also often have an uneven effect on the way men and women spend their time and can increase the demand for goods produced at home using unpaid labor (Moser 1994) Thus women may spend its much (or more time on unpaid work as on market work. In some countries this unpaid work contributes as much as one-third to the economy recorded GDP-and even mote to the welfare of poor families.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The amount of time women contribute to household production and maintenance, direct income generation. and family care combined is widely held to exceed that of men Analysis of data from Bangladesh. Botswana. Ghana. Kenya. Pakistan. the Philippines. and Zambia on how rural women spend their time confirms that, although use of time by women, and by different generations of women varies according to location. available technology. household characteristics. and cultural norms. gender bias in time use is widespread.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Women are generally responsible for collecting fuelwood and carrying water. Girls and alder women often do most of this work, although cultural norms in some countries affect women s mobility. The amount of time allocated to these activities is influenced by seasonal patterns of agricultural activity. the availability of substitute goods and services. and environmental changes. A study in Nepal, for instance, found that deforestation associated with a 75 percent rise in the time per trip would increase the time spent gathering fuelwood by 45 percent for all adults and by 50-60 percent for women.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">In addition to fuel and water collection, child care is another activity that dominates women s time-although. considering the importance of children to future household welfare, the amount of direct time spent with children is limited. The seven-country study suggests that more time is spent on child cat-e in female-headed households. Female-headed households tend to have high dependency ratios and relatively large numbers of children, Implying more child-care time overall, but not necessarily on a per child basis. (Kumar and Hotchkiss 1988).</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">When a large proportion of women's use of time goes unrecorded the design of projects and policies can yield false evaluations of costs and benefits. For example, women's unpaid work may be assumed to have zero value. As a result, women's response to changing incentives may be predicted as being higher than their time constraints actually allow. Project benefits-such as the time saved by locating piped water close to homes or by expanding rural electrification-may also be undervalued. Conversely, the benefits of treeing up time may be far more significant than might have been thought. A study in Tanzania, for example. shows that relieving certain time constraints in a community of smallholder coffee and banana growers increases household cash incomes by 10 percent, labor productivity by 15 percent, and capital productivity by 44 percent (Tibaijuka 1994).</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<B><P>&lt;&lt;TOC3&gt;&gt; Formal Sector Employment</P>
+</B><P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Unpaid work and family responsibilities. as well as lack of investment in women's education. are strongly associated with women's relatively low rates of participation and their limited earnings in formal sector labor. Women's participation rates usually dip in the childbearing years, and earnings tend to decline following an interruption in employment. Younger on average, work more hours than older women, and married women with young children tend to work less than childless women and mothers of grown children. The correlation of marriage and childbearing with labor market outcomes can be seen even in industrial countries, where wage differences between married women and men are larger than those between single women and men Similarly, in some developing countries relative earnings decline with age (table 2.2) Children are not the only treason for interruptions in women's labor force participation; caring for ill or aged family members is often a womans responsibility. A study from Hungary estimates that half of all absenteeism by women workers is the direct result of the need to care for sick relatives (Einhorn 1993).</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">In Countries, Single Women Earn More Than Married Women and Younger Women More Than Older Women.</P>
+<P ALIGN="JUSTIFY"></P>
+<B><P ALIGN="JUSTIFY">Table 2.2 female-male earnings (adjusted for hours worked) by marital status and age (percent)</P>
+</B><P ALIGN="JUSTIFY"></P></FONT>
+<TABLE BORDER CELLSPACING=2 CELLPADDING=7 WIDTH=345>
+<TR><TD WIDTH="38%" VALIGN="TOP">
+<B><FONT SIZE=2><P ALIGN="JUSTIFY">Country</B></FONT></TD>
+<TD WIDTH="27%" VALIGN="TOP">
+<B><FONT SIZE=2><P ALIGN="JUSTIFY">Female-male</B></FONT></TD>
+<TD WIDTH="35%" VALIGN="TOP">
+<B><FONT SIZE=2><P ALIGN="JUSTIFY">Earnings ratio</B></FONT></TD>
+</TR>
+<TR><TD WIDTH="38%" VALIGN="TOP">
+<FONT SIZE=2><P ALIGN="JUSTIFY">By marital status</FONT></TD>
+<TD WIDTH="27%" VALIGN="TOP">
+<FONT SIZE=2><P ALIGN="JUSTIFY">Married </FONT></TD>
+<TD WIDTH="35%" VALIGN="TOP">
+<FONT SIZE=2><P ALIGN="JUSTIFY">Single</FONT></TD>
+</TR>
+<TR><TD WIDTH="38%" VALIGN="TOP">
+<FONT SIZE=2><P ALIGN="JUSTIFY">Australia</FONT></TD>
+<TD WIDTH="27%" VALIGN="TOP">
+<FONT SIZE=2><P ALIGN="JUSTIFY">69</FONT></TD>
+<TD WIDTH="35%" VALIGN="TOP">
+<FONT SIZE=2><P ALIGN="JUSTIFY">91</FONT></TD>
+</TR>
+<TR><TD WIDTH="38%" VALIGN="TOP">
+<FONT SIZE=2><P ALIGN="JUSTIFY">Austria</FONT></TD>
+<TD WIDTH="27%" VALIGN="TOP">
+<FONT SIZE=2><P ALIGN="JUSTIFY">66</FONT></TD>
+<TD WIDTH="35%" VALIGN="TOP">
+<FONT SIZE=2><P ALIGN="JUSTIFY">97</FONT></TD>
+</TR>
+<TR><TD WIDTH="38%" VALIGN="TOP">
+<FONT SIZE=2><P ALIGN="JUSTIFY">Germany</FONT></TD>
+<TD WIDTH="27%" VALIGN="TOP">
+<FONT SIZE=2><P ALIGN="JUSTIFY">57</FONT></TD>
+<TD WIDTH="35%" VALIGN="TOP">
+<FONT SIZE=2><P ALIGN="JUSTIFY">103</FONT></TD>
+</TR>
+<TR><TD WIDTH="38%" VALIGN="TOP">
+<FONT SIZE=2><P ALIGN="JUSTIFY">Norway</FONT></TD>
+<TD WIDTH="27%" VALIGN="TOP">
+<FONT SIZE=2><P ALIGN="JUSTIFY">72</FONT></TD>
+<TD WIDTH="35%" VALIGN="TOP">
+<FONT SIZE=2><P ALIGN="JUSTIFY">92</FONT></TD>
+</TR>
+<TR><TD WIDTH="38%" VALIGN="TOP">
+<FONT SIZE=2><P ALIGN="JUSTIFY">Sweden</FONT></TD>
+<TD WIDTH="27%" VALIGN="TOP">
+<FONT SIZE=2><P ALIGN="JUSTIFY">72</FONT></TD>
+<TD WIDTH="35%" VALIGN="TOP">
+<FONT SIZE=2><P ALIGN="JUSTIFY">94</FONT></TD>
+</TR>
+<TR><TD WIDTH="38%" VALIGN="TOP">
+<FONT SIZE=2><P ALIGN="JUSTIFY">Switzerland</FONT></TD>
+<TD WIDTH="27%" VALIGN="TOP">
+<FONT SIZE=2><P ALIGN="JUSTIFY">58</FONT></TD>
+<TD WIDTH="35%" VALIGN="TOP">
+<FONT SIZE=2><P ALIGN="JUSTIFY">94</FONT></TD>
+</TR>
+<TR><TD WIDTH="38%" VALIGN="TOP">
+<FONT SIZE=2><P ALIGN="JUSTIFY">United Kingdom</FONT></TD>
+<TD WIDTH="27%" VALIGN="TOP">
+<FONT SIZE=2><P ALIGN="JUSTIFY">60</FONT></TD>
+<TD WIDTH="35%" VALIGN="TOP">
+<FONT SIZE=2><P ALIGN="JUSTIFY">95</FONT></TD>
+</TR>
+<TR><TD WIDTH="38%" VALIGN="TOP">
+<FONT SIZE=2><P ALIGN="JUSTIFY">United States</FONT></TD>
+<TD WIDTH="27%" VALIGN="TOP">
+<FONT SIZE=2><P ALIGN="JUSTIFY">59</FONT></TD>
+<TD WIDTH="35%" VALIGN="TOP">
+<FONT SIZE=2><P ALIGN="JUSTIFY">96</FONT></TD>
+</TR>
+<TR><TD WIDTH="38%" VALIGN="TOP">
+<FONT SIZE=2><P ALIGN="JUSTIFY">Age</FONT></TD>
+<TD WIDTH="27%" VALIGN="TOP">
+<FONT SIZE=2><P ALIGN="JUSTIFY">A 25 </FONT></TD>
+<TD WIDTH="35%" VALIGN="TOP">
+<FONT SIZE=2><P ALIGN="JUSTIFY">B 45</FONT></TD>
+</TR>
+<TR><TD WIDTH="38%" VALIGN="TOP">
+<FONT SIZE=2><P ALIGN="JUSTIFY">Brazil</FONT></TD>
+<TD WIDTH="27%" VALIGN="TOP">
+<FONT SIZE=2><P ALIGN="JUSTIFY">75</FONT></TD>
+<TD WIDTH="35%" VALIGN="TOP">
+<FONT SIZE=2><P ALIGN="JUSTIFY">63</FONT></TD>
+</TR>
+<TR><TD WIDTH="38%" VALIGN="TOP">
+<FONT SIZE=2><P ALIGN="JUSTIFY">Colombia</FONT></TD>
+<TD WIDTH="27%" VALIGN="TOP">
+<FONT SIZE=2><P ALIGN="JUSTIFY">94</FONT></TD>
+<TD WIDTH="35%" VALIGN="TOP">
+<FONT SIZE=2><P ALIGN="JUSTIFY">70</FONT></TD>
+</TR>
+<TR><TD WIDTH="38%" VALIGN="TOP">
+<FONT SIZE=2><P ALIGN="JUSTIFY">Indonesia</FONT></TD>
+<TD WIDTH="27%" VALIGN="TOP">
+<FONT SIZE=2><P ALIGN="JUSTIFY">81</FONT></TD>
+<TD WIDTH="35%" VALIGN="TOP">
+<FONT SIZE=2><P ALIGN="JUSTIFY">60</FONT></TD>
+</TR>
+<TR><TD WIDTH="38%" VALIGN="TOP">
+<FONT SIZE=2><P ALIGN="JUSTIFY">Malaysia</FONT></TD>
+<TD WIDTH="27%" VALIGN="TOP">
+<FONT SIZE=2><P ALIGN="JUSTIFY">82</FONT></TD>
+<TD WIDTH="35%" VALIGN="TOP">
+<FONT SIZE=2><P ALIGN="JUSTIFY">61</FONT></TD>
+</TR>
+<TR><TD WIDTH="38%" VALIGN="TOP">
+<FONT SIZE=2><P ALIGN="JUSTIFY">Venezuela</FONT></TD>
+<TD WIDTH="27%" VALIGN="TOP">
+<FONT SIZE=2><P ALIGN="JUSTIFY">92</FONT></TD>
+<TD WIDTH="35%" VALIGN="TOP">
+<FONT SIZE=2><P ALIGN="JUSTIFY">70</FONT></TD>
+</TR>
+</TABLE>
+
+<FONT SIZE=2><P ALIGN="JUSTIFY">Sources: Blau and Kahn 1992 Sedlacek Gutierrez. and Mohindra 1993 </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Thus. women s labor market outcomes can be substantially poorer than those of men because women's employment opportunities are constrained by social arrangements at the family or household level. These social demands are reinforced by legal conventions. Within the labor market itself, social or employer discrimination can affect women and men differently. and these differences are reflected in the resource allocation decisions taken within the household. Although wage discrimination is illegal in many countries, employers may respond to an increase in the supply of workers by segregating jobs by gender or offering less training to women who they perceive as being temporarily attached to the labor force (even if in fact most women never drop out). For example, women in the former Soviet Union are fairly well educated and have high labor force participation. but they are concentrated in occupations requiring fewer skills and less vocational training than men, and, on average. they earn less than men (Fong 1993).</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Female Wages Are Lower than Male Wages, but This Is Changing.</P>
+<P ALIGN="JUSTIFY"></P>
+<B><P ALIGN="JUSTIFY">Table 2.3 female-male earnings ratio over time Female-male earning 1 ratio (percent) </P>
+</B><P ALIGN="JUSTIFY"></P></FONT>
+<TABLE BORDER CELLSPACING=2 CELLPADDING=7 WIDTH=496>
+<TR><TD WIDTH="21%" VALIGN="TOP">
+<B><FONT SIZE=2><P ALIGN="JUSTIFY">Country</B></FONT></TD>
+<TD WIDTH="26%" VALIGN="TOP" COLSPAN=2>
+<B><FONT SIZE=2><P ALIGN="JUSTIFY">First observation</B></FONT></TD>
+<TD WIDTH="25%" VALIGN="TOP" COLSPAN=2>
+<B><FONT SIZE=2><P ALIGN="JUSTIFY">Second observation</B></FONT></TD>
+<TD WIDTH="28%" VALIGN="TOP">
+<B><FONT SIZE=2><P ALIGN="JUSTIFY">A v Average annual percentage change</B></FONT></TD>
+</TR>
+<TR><TD WIDTH="21%" VALIGN="TOP">
+<FONT SIZE=2><P ALIGN="JUSTIFY">Brazil</FONT></TD>
+<TD WIDTH="11%" VALIGN="TOP">
+<FONT SIZE=2><P ALIGN="JUSTIFY">50.2</FONT></TD>
+<TD WIDTH="15%" VALIGN="TOP">
+<FONT SIZE=2><P ALIGN="JUSTIFY">(1981) </FONT></TD>
+<TD WIDTH="11%" VALIGN="TOP">
+<FONT SIZE=2><P ALIGN="JUSTIFY">51.6</FONT></TD>
+<TD WIDTH="13%" VALIGN="TOP">
+<FONT SIZE=2><P ALIGN="JUSTIFY">(1990)</FONT></TD>
+<TD WIDTH="28%" VALIGN="TOP">
+<FONT SIZE=2><P ALIGN="JUSTIFY">0.7</FONT></TD>
+</TR>
+<TR><TD WIDTH="21%" VALIGN="TOP">
+<FONT SIZE=2><P ALIGN="JUSTIFY">Colombia</FONT></TD>
+<TD WIDTH="11%" VALIGN="TOP">
+<FONT SIZE=2><P ALIGN="JUSTIFY">67.2</FONT></TD>
+<TD WIDTH="15%" VALIGN="TOP">
+<FONT SIZE=2><P ALIGN="JUSTIFY">(1984)</FONT></TD>
+<TD WIDTH="11%" VALIGN="TOP">
+<FONT SIZE=2><P ALIGN="JUSTIFY">70 2</FONT></TD>
+<TD WIDTH="13%" VALIGN="TOP">
+<FONT SIZE=2><P ALIGN="JUSTIFY">(1990)</FONT></TD>
+<TD WIDTH="28%" VALIGN="TOP">
+<FONT SIZE=2><P ALIGN="JUSTIFY">0.7</FONT></TD>
+</TR>
+<TR><TD WIDTH="21%" VALIGN="TOP">
+<FONT SIZE=2><P ALIGN="JUSTIFY">C&ocirc;te d'Ivoire</FONT></TD>
+<TD WIDTH="11%" VALIGN="TOP">
+<FONT SIZE=2><P ALIGN="JUSTIFY">75.7</FONT></TD>
+<TD WIDTH="15%" VALIGN="TOP">
+<FONT SIZE=2><P ALIGN="JUSTIFY">(1985)</FONT></TD>
+<TD WIDTH="11%" VALIGN="TOP">
+<FONT SIZE=2><P ALIGN="JUSTIFY">81.4</FONT></TD>
+<TD WIDTH="13%" VALIGN="TOP">
+<FONT SIZE=2><P ALIGN="JUSTIFY">(1988)</FONT></TD>
+<TD WIDTH="28%" VALIGN="TOP">
+<FONT SIZE=2><P ALIGN="JUSTIFY">2.4</FONT></TD>
+</TR>
+<TR><TD WIDTH="21%" VALIGN="TOP">
+<FONT SIZE=2><P ALIGN="JUSTIFY">Indonesia</FONT></TD>
+<TD WIDTH="11%" VALIGN="TOP">
+<FONT SIZE=2><P ALIGN="JUSTIFY">55.6</FONT></TD>
+<TD WIDTH="15%" VALIGN="TOP">
+<FONT SIZE=2><P ALIGN="JUSTIFY">(1986)</FONT></TD>
+<TD WIDTH="11%" VALIGN="TOP">
+<FONT SIZE=2><P ALIGN="JUSTIFY">60.0</FONT></TD>
+<TD WIDTH="13%" VALIGN="TOP">
+<FONT SIZE=2><P ALIGN="JUSTIFY">(1997)</FONT></TD>
+<TD WIDTH="28%" VALIGN="TOP">
+<FONT SIZE=2><P ALIGN="JUSTIFY">1.3</FONT></TD>
+</TR>
+<TR><TD WIDTH="21%" VALIGN="TOP">
+<FONT SIZE=2><P ALIGN="JUSTIFY">Philippines</FONT></TD>
+<TD WIDTH="11%" VALIGN="TOP">
+<FONT SIZE=2><P ALIGN="JUSTIFY">70.9</FONT></TD>
+<TD WIDTH="15%" VALIGN="TOP">
+<FONT SIZE=2><P ALIGN="JUSTIFY">(1978)</FONT></TD>
+<TD WIDTH="11%" VALIGN="TOP">
+<FONT SIZE=2><P ALIGN="JUSTIFY">80.0</FONT></TD>
+<TD WIDTH="13%" VALIGN="TOP">
+<FONT SIZE=2><P ALIGN="JUSTIFY">(1988)</FONT></TD>
+<TD WIDTH="28%" VALIGN="TOP">
+<FONT SIZE=2><P ALIGN="JUSTIFY">1.2</FONT></TD>
+</TR>
+<TR><TD WIDTH="21%" VALIGN="TOP">
+<FONT SIZE=2><P ALIGN="JUSTIFY">Thailand</FONT></TD>
+<TD WIDTH="11%" VALIGN="TOP">
+<FONT SIZE=2><P ALIGN="JUSTIFY">73.5</FONT></TD>
+<TD WIDTH="15%" VALIGN="TOP">
+<FONT SIZE=2><P ALIGN="JUSTIFY">(1980)</FONT></TD>
+<TD WIDTH="11%" VALIGN="TOP">
+<FONT SIZE=2><P ALIGN="JUSTIFY">79.8</FONT></TD>
+<TD WIDTH="13%" VALIGN="TOP">
+<FONT SIZE=2><P ALIGN="JUSTIFY">(1990)</FONT></TD>
+<TD WIDTH="28%" VALIGN="TOP">
+<FONT SIZE=2><P ALIGN="JUSTIFY">0.8</FONT></TD>
+</TR>
+</TABLE>
+
+<FONT SIZE=2><P ALIGN="JUSTIFY">Note: Monthly earnings for Indonesia and Thailand rural and urban: for all others urban only</P>
+<P ALIGN="JUSTIFY">Source: Tzanntors 1995</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Women's earnings relative to men's tend to increase over time. A study of six developing countries shows that female earnings relative to male earnings increased by 1 percent a year in the 1980s (table 2.3). There were two reasons for this increase: over the years women entered higher-paying sectors. and within sectors, their pay increased in relation to that of men. This gain would have been even greater had it not been for the effect on wages of increased female participation in the labor force. However, the most visible dimension of gender inequality in the formal labor sector remains the wage difference between men and women. Women's wages are. on average lower those of men by about 30 to 40 percent.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Social or employer discrimination can affect women and men difference and these difference are reflected i/? the resource allocation decisions taken within the household</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">A recent study of the gender wage gap in Russia shows that after controlling for education differences, the ratio of women's to men's average hourly earnings stands at just over 71 percent: it has remained at that level since the 1960s. Part of the reason for women s lower hourly earnings in Russia and many other countries lies in patterns of occupational segmentation by ,gender. Some analysts argue that women-who do most of the household work in Russian households and also have high participation in the formal labor market cope with the burdens imposed on them by taking less demanding work and devoting less time to advancing their careers (Newell and Reilly 1994).</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<B><P>&lt;&lt;TOC3&gt;&gt; Informal Sector </P>
+</B><P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">One difficulty analysts face in interpreting trends in women's labor force participation and employment in developing economies is the large number of women engaged in informal sector activities, many of which overlap with subsistence - orientated household or community-based activities. Informal sector employment in most developing countries. whether in microentreprises or in casual work, is an important source of livelihood for women and their households.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The L competitiveness of women's informal sector activities is  constrained by women's limited mobility and lack of access to financial and public sectors.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">A recent study in Mexico estimates that 41 percent of the work force in Mexico's major-cities is employed in the informal sector (World Bank 1995c). Data from a 1989 survey show that 60 percent of men working in the sector are salaried workers' compared with only 18 percent of women. By contrast. 80 percent of women working in the sector are unpaid family members, as against 27 percent of men. By far the most common activity in the informal sector is commerce (fixed-location or itinerant), followed by repair works food preparation. and sales, and small-scale manufacturing. The sectoral distribution of informal employment reflects the hey role informal workers play in supplying goods and services to low-income consumers. Women tend to be concentrated in commerce and men in services and manufacturing, although the percentage differences are relatively small. Two generalizations can be made on the basis of this study: informal sector workers earn less than workers in large firms and women earn less than men.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Another recent study of tour communities in Lusaka. Guayaquil (Ecuador), Metro Manila, and Budapest shows that informal sector activities ate especially important for during periods of economic reform Although the numbers both of men and of women in the labor force tend to increase during these times women rely more on the informal sector than men clot The competitiveness of womens informal sector activities is informal by women's limited mobility and lack of access to financial and public services. Women also tend to specialize in non traded goods and services that show relatively low average returns to labor. Across the tour cities in the study, women earn between 46 and 68 percent of men's wages (Moser 1994)</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The ability of informal sector workers to increase their returns depends on access to physical and human capital and their relationship to the institutional and regulatory environment. Contrary to the common belief, many microenterprises face considerable costs associated with the regulatory environment, including registration and licensing fees, as well as outlays for contracts with public authorities concerning zoning regulations and use of public utilities. In Argentina regulatory costs are estimated to absorb as much as 21 percent of the average microfirm's operational expenses. In some sectors, such as manufacturing and construction, the costs of regulation are about 44 percent (World Bank 1994d). In Mexico real regulatory costs. including the costs of compliance and evasion, are about 20 percent of total costs.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Regulatory costs also inhibit Job creation in the informal sector. In Argentina across-the-board deregulation could generate as many as 170,000 jobs in small-scale manufacturing alone. Furthermore. poor workers in family-based firms or micro enterprises and particularly women entrepreneurs-often lack access to such basics as water and power. Targeting infrastructure investments to the poor, which takes account of the needs of women entrepreneurs s. can significantly enhance their productivity and earnings.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">In rural area where formal markets often are not well developed. informal employment activities play a vital role. In Asia the proportion of female rural wage laborers increased sharply in the 1960s and 1970s. In India women make up a larger proportion of rural wage laborers than of the entire labor force, probably because of growing landlines and poverty among rural households. Rural household labor accounts for a disproportionately large share of employment among the poor and an even larger share among women. Furthermore, a larger proportion of female than male laborers are hired on a casual basis, largely because family arrangements, especially lack of control over property, limit women's ability to work (Hart 1986: Bardhan 1993). Low status in the labor market is also linked to low female indicators in education, health, and nutrition.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Providing credit directly to women has a positive effect on  household and individual welfare and improved gender equality.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Social norms affecting decisions within the family about occupational choices or migration can also lead to differential patterns of male and female earnings in informal markets (Bhiswanger and Rosenzweig 1984). Family responsibilities hinder women's geographic mobility, constraining their ability to command high wages and limiting them to certain areas or industries. The concentration of women in certain sectors, especially nontraded goods and set-vices. intensifies competition between women entrepreneurs and wage workers and lowers the returns to female labor. These effects are compounded by women's lack of access to credit. training, and technology.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">(fender Inequality in Access to Assets and Services )</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<B><P>&lt;&lt;TOC3&gt;&gt; Access to Financial Markets</P>
+</B><P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The availability of financial services and access to them are considered important for several reasons. First. savings provide a kind of self-insurance. Second, credit helps households maintain a certain level of consumption at those times when their income fluctuates temporarily. Third, credit can be used to fund investments in capital or other inputs that will yield relatively high returns to production. if households cannot finance such investments from their own savings. A fourth and no less important reason is the role of savings and credit in increasing household members' options outside the home.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Inequalities between women and men in access to financial services- particularly credit--are widely documented. Collateral requirements, high transaction costs. limited mobility and education, and other social and cultural barriers contribute to women's inability to obtain credit (Holt and Ribe 1991). The implications tot household efficiency and individual well-being differ, however, depending on whether the household pools its financial resources. If, as the unitary household model assumes. a household pools its resources the characteristics of individual borrowers are less important than if there is little or no pooling. In the first case. credit resources will be used to meet household needs that have been jointly determined, regardless of who the borrower is. In the second case, the use credit is put to and the needs it then satisfies depend on which household member is borrowing.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">A recent study of credit programs in Bangladesh sponsored by the World Bank shows that providing credit directly to women has a positive effect on variables typically associated with household and individual welfare and improved gender equality (Pitt and Khandker 1995). The study looks at three programs in Bangladesh: the Grameen Bank. the Bangladesh Rural Advancement Committee (BRAC), and the Bangladesh Rural Development Board (BRDB). in 1992, women accounted for 94 percent of Grameen Bank members. 82 percent of BRAC members. and 68 percent of BRDB members (Khandker and Khalily 1995; Khandker, Lavy, and Filmer 1994). Only the results for the Grameen Bank are presented here.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Table 2.4 presents the impact of credit obtained by women and men on a variety of social and economic indicators. The results show a clear and positive impact of both male and female borrowing on all indicators of Toward gender equality family welfare especially through an increase in per capita expenditures increases in both boys' and girls schooling, anti a reduction in fertility. Females borrowing has a greater effect on girls' schooling anti per capita expenditure than does male loot-rowing: male borrowing has a greater effect on boys' schooling and fertility than does female borrowing. Interestingly. female borrowing also results in mote female ownership of nonoland assets and an increased supply of female labor to cash - income -earning activities (Pitt and Khandker 1995).</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Loans to Women and Men Have Important Welfare Implications.</P>
+<P ALIGN="JUSTIFY"></P>
+<B><P ALIGN="JUSTIFY">Table 2 4 welfare effects of Grameen Bank loans (percentage increase)</P>
+</B><P ALIGN="JUSTIFY"></P></FONT>
+<TABLE BORDER CELLSPACING=1 CELLPADDING=7 WIDTH=545>
+<TR><TD WIDTH="47%" VALIGN="TOP">
+<B><FONT SIZE=2><P ALIGN="JUSTIFY">Welfare e change</B></FONT></TD>
+<TD WIDTH="28%" VALIGN="TOP">
+<B><FONT SIZE=2><P ALIGN="JUSTIFY">Effect of male borrowing</B></FONT></TD>
+<TD WIDTH="26%" VALIGN="TOP">
+<B><FONT SIZE=2><P ALIGN="JUSTIFY">Effect female borrowing</B></FONT></TD>
+</TR>
+<TR><TD WIDTH="47%" VALIGN="TOP">
+<FONT SIZE=2><P ALIGN="JUSTIFY">Increase in boys' schooling</FONT></TD>
+<TD WIDTH="28%" VALIGN="TOP">
+<FONT SIZE=2><P ALIGN="JUSTIFY">7.2</FONT></TD>
+<TD WIDTH="26%" VALIGN="TOP">
+<FONT SIZE=2><P ALIGN="JUSTIFY">6.1</FONT></TD>
+</TR>
+<TR><TD WIDTH="47%" VALIGN="TOP">
+<FONT SIZE=2><P ALIGN="JUSTIFY">Increase in girls schooling</FONT></TD>
+<TD WIDTH="28%" VALIGN="TOP">
+<FONT SIZE=2><P ALIGN="JUSTIFY">3.0</FONT></TD>
+<TD WIDTH="26%" VALIGN="TOP">
+<FONT SIZE=2><P ALIGN="JUSTIFY">4.7</FONT></TD>
+</TR>
+<TR><TD WIDTH="47%" VALIGN="TOP">
+<FONT SIZE=2><P ALIGN="JUSTIFY">Increase in per capital expenditure</FONT></TD>
+<TD WIDTH="28%" VALIGN="TOP">
+<FONT SIZE=2><P ALIGN="JUSTIFY">1.8</FONT></TD>
+<TD WIDTH="26%" VALIGN="TOP">
+<FONT SIZE=2><P ALIGN="JUSTIFY">4.3</FONT></TD>
+</TR>
+<TR><TD WIDTH="47%" VALIGN="TOP">
+<FONT SIZE=2><P ALIGN="JUSTIFY">Reduction in recent fertility</FONT></TD>
+<TD WIDTH="28%" VALIGN="TOP">
+<FONT SIZE=2><P ALIGN="JUSTIFY">7.4</FONT></TD>
+<TD WIDTH="26%" VALIGN="TOP">
+<FONT SIZE=2><P ALIGN="JUSTIFY">3.5</FONT></TD>
+</TR>
+<TR><TD WIDTH="47%" VALIGN="TOP">
+<FONT SIZE=2><P ALIGN="JUSTIFY">Increase in women's labor supply to cash-income earning activities</FONT></TD>
+<TD WIDTH="28%" VALIGN="TOP">
+<FONT SIZE=2><P ALIGN="JUSTIFY">0</FONT></TD>
+<TD WIDTH="26%" VALIGN="TOP">
+<FONT SIZE=2><P ALIGN="JUSTIFY">10.4</FONT></TD>
+</TR>
+<TR><TD WIDTH="47%" VALIGN="TOP">
+<FONT SIZE=2><P ALIGN="JUSTIFY">Increase in women nonland assents</FONT></TD>
+<TD WIDTH="28%" VALIGN="TOP">
+<FONT SIZE=2><P ALIGN="JUSTIFY">0</FONT></TD>
+<TD WIDTH="26%" VALIGN="TOP">
+<FONT SIZE=2><P ALIGN="JUSTIFY">19.9 </FONT></TD>
+</TR>
+</TABLE>
+
+<FONT SIZE=2><P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The introduction of programs such as the Grameen Bank in a village has a positive effect on agricultural and nonagricultural production (Khatidketati Chowdhuty 1994: Rahman and Khandke 1994 The probability that women will be self-employed rather than work for wages increases by 52 percent. The latter finding is important because much of the wage employment open to women in rural areas is very poorly remunerated and can be quite exploitative. Self employment can bring the opportunity of higher returns for women, plus the freedom to integrate their earning activities into other work as they see fit.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Access to financial services alone cannot reduce gender inequalities in the allocation of household resources. A qualitative study reviewing several targeted credit programs in Bangladesh cautions against overgeneralizing about the benefits of giving women access to credit. The study finds that it is difficult to infer that increased borrowing alone improves women's bargaining power because in many rural Bangladesh households the question of who controls the resources is quite complex (Goetz and Sen Gupta 1994). Nevertheless. the possibility of receiving credit (or similarly of working for wages) may give women greater bargaining power within the household. This bargaining power can be used to improve child health and nutrition and may increase the likelihood that children will attend school.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<B><P>&lt;&lt;TOC3&gt;&gt; Access to Lund and Property</P>
+</B><P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The ownership of land and the distributions of land rights influence the productivity of labor and capital resources and the incentive to invest in resource management Private property rights. in particular. are associated with increased access to product and factor markets. especially credit markets. and to public services such as public utilities and agricultural extension. However. relatively little direct evidence exists to link independent owner of land by women with increased access and productivity. One obstacle to empirical work is that women s access to land and property is often mediated trough marriage (A married woman land rights are frequently limited to use rather than ownership.) Future more. complex systems of land tenure make it difficult to generalize about the effects of owner ship on productivity. None some evidence suggests that independent land rights for women could enhance both the efficiency with which resources are used and the well-being of women and their households: (Agarwal 1994).</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The possibility of receiving credit may give e women   greater bargaining power within the  household which  can be used to improve child health and nutrition.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">While independent land rights may increase efficiency and household welfare, lack of secure land  appears to be associated with low investments by women in land conservation. In Zimbabwe's communal areas, land that a women acquires is often allocated to her only temporarily: for example, the location of land allotment received from husbands or borrowed from neighbors is usually subject to periodic change (Jackson 1993). The same is true in parts of West Africa (David 1992 Jackson 1994). Uncertainly about the permanence of their control over the land means that women may be reluctant to invest in improvements that will benefit the landowner rather than the user.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">A significant trend in recent decades in developing countries has been the move toward private ownership In some countries this trend has been encoulagecl by reforms dealing with land redistribution tenancy or land titling Such reforms are considered important for promoting long-term investments and the adoption of the latest technology They also provide the collateral people need to gain access to credit and other factor markets Ironically, evidence also suggests that perform inequalities in male and female land rights are reinforced by land reform programs For example, in Latin America most reforms are based on the premise that the man of the household its the household head. This presumption means that women (except for widows  and ownership. Even where women and men benefit equally from land reform differences exist between nominal and real land rights (see box 2.3).</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">In the central part of European Russia and in Moldova the lands and assets of state and collective farms are being parceled out in allotments as part of wider economic reforms. Every person who lived and worked on a collective farm receives a share of the land Data show that although on average, women have received a slightly higher proportion of land shares than men, the nonland capital assets of the old farms ale being distributed as property shares on the basis of a formula heavily weighted toward an individual's wage rate and years of employment. Such criteria favor men over women and give men more valuable property chares. Dividends paid on these property shares also tend to be higher than those paid 011 land shares Holt 1995).</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Land reform programs that fail to account for gender differences in rights</P>
+<P ALIGN="JUSTIFY"></P></FONT>
+<TABLE BORDER CELLSPACING=1 CELLPADDING=7 WIDTH=590>
+<TR><TD VALIGN="TOP">
+<B><FONT SIZE=2><P ALIGN="JUSTIFY">Box 2.3 who gets access to land? Honduras and Cameroon</P>
+</B><P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Honduras' Agrarian Modernization Law of 1974 includes a provision giving men age 16 or older the right to access to land, independent of any other qualification. For women. however, this right is restricted to unmarried mothers or widows with dependent children. Furthermore. if a male beneficiary dies or becomes incapacitated. the law gives preference in inheritance rights to a male child over the child's legally married mother. Some 30 percent of rural Honduran households are headed by women at least part time because of the seasonal migration of men to look for work (Saito and Spurling 1992). </FONT></TD>
+</TR>
+</TABLE>
+
+<FONT SIZE=2><P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">In the northwest and southwest provinces of Cameroon. an estimated 50 percent or more of those who claimed land within the first ten years of land registration (1974-85) were classified as public servants. Over 32 percent of all the remaining land titles went to businesses.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Women make up more than 51 percent of Cameroon s population and do more than 75 percent of the agricultural work. but they are virtually absent from land registers. Only 3.2 percent of all land titles issued in the Northwest Province were given to women; in the Southwest Province the figure was 7.2 percent. For the country as a whole. it is estimated that women obtained under 10 percent of all land certificates (World Bank 1995a).  to own. use, and transfer land may actually exacerbate the insecurity of women's land claims and. as a result, harm household welfare. For example, there is evidence that land titling focused on male household heads has adversely affected women's ability to farm independently. Moreover. intrahousehold inequalities in income and decisionmaking have increased (FAO 1993) In Africa some titling programs have allowed men to take advantage of their control over land to redesignate land formerly cultivated by women as household land. This switch provided the opportunity for men to increase the amount of work they expect from women on household plots. In other cases women have received smaller and less fertile plots than they had before for their personal crops (FAO 1993).</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Recognizing women's independent claims to land is therefore an important issue in property reform. In poor households. having rights to land could alleviate both women's own poverty and the household's risk of remaining poor. The season is mainly that women s access to economic resources has a positive effect on household welfare (Agarwal 1994). From the point of view of efficiency, secret land tenure increases the incentive to manage resources efficiently and expands access to formal credit markets. Because secure land tenure can mean greater productivity, it may also increase the household's incentives to invest in women's human capital.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<B><P>&lt;&lt;TOC3&gt;&gt; Access to Extension Services </P>
+</B><P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Agricultural extension services provide information training and technology to agricultural producers. Extension services have always been regarded as necessary for agricultural modernization. Given the importance of women's labor to agriculture in most regions, providing women with access to agricultural extension services is essential for current and future productivity. Types of agricultural extension services vary, hut in most countries publicly provided services dominate. Evidence suggests that women have not benefited as much as men have from publicly provided extension services.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Given the importance of women's labor to agriculture it is in most regions providing women with access to agricultural extension services is essential for current  and future of productivity.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">A review of five African countries shows that extension agents are most likely to visit male farmers than female farmers (table 2.5) The impact of this inequity on female productivity depends in part on whether women and men within households pool information. There is, however. little evidence to suggest that this happens (see box 2.4). It is important to ensure that extension services reach omen directly, not only to redress gender inequalities but also to maximize productive efficiency. omen play a critical role in production of food and cash crops for the household. in postharvest activities. and in livestock care Men and omen perform different tasks they can substitute for one another only to a limited extent. and this imitation creates different demands for extension information Also, as men leave farms in search of paid employment ill urban areas. women are increasingly managing and operating farms on a regular and full-time basis. Hence. omen are becoming a constituency for extension and research services in their own right (World Bank 1994e)</P>
+<P ALIGN="JUSTIFY"></P>
+<B><P ALIGN="JUSTIFY">Table 2.5 visits by agricultural extension agents (percentage of households visited)</P>
+</B><P ALIGN="JUSTIFY"></P></FONT>
+<TABLE BORDER CELLSPACING=1 CELLPADDING=7 WIDTH=439>
+<TR><TD WIDTH="37%" VALIGN="TOP" COLSPAN=2>
+<B><FONT SIZE=2><P ALIGN="JUSTIFY">Country and year</B></FONT></TD>
+<TD WIDTH="32%" VALIGN="TOP">
+<B><FONT SIZE=2><P ALIGN="JUSTIFY">Households with female head</B></FONT></TD>
+<TD WIDTH="32%" VALIGN="TOP">
+<B><FONT SIZE=2><P ALIGN="JUSTIFY">Households with male head</B></FONT></TD>
+</TR>
+<TR><TD WIDTH="37%" VALIGN="TOP" COLSPAN=2>
+<FONT SIZE=2><P ALIGN="JUSTIFY">Kenya. 1989</FONT></TD>
+<TD WIDTH="32%" VALIGN="TOP">
+<FONT SIZE=2><P ALIGN="JUSTIFY">112</FONT></TD>
+<TD WIDTH="32%" VALIGN="TOP">
+<FONT SIZE=2><P ALIGN="JUSTIFY">9</FONT></TD>
+</TR>
+<TR><TD WIDTH="37%" VALIGN="TOP" COLSPAN=2>
+<FONT SIZE=2><P ALIGN="JUSTIFY">Malawi, 1989</FONT></TD>
+<TD WIDTH="32%" VALIGN="TOP">
+<FONT SIZE=2><P ALIGN="JUSTIFY">70</FONT></TD>
+<TD WIDTH="32%" VALIGN="TOP">
+<FONT SIZE=2><P ALIGN="JUSTIFY">58</FONT></TD>
+</TR>
+<TR><TD WIDTH="37%" VALIGN="TOP" COLSPAN=2>
+<FONT SIZE=2><P ALIGN="JUSTIFY">Nigeria 1989</FONT></TD>
+<TD WIDTH="32%" VALIGN="TOP">
+<FONT SIZE=2><P ALIGN="JUSTIFY">37</FONT></TD>
+<TD WIDTH="32%" VALIGN="TOP">
+<FONT SIZE=2><P ALIGN="JUSTIFY">22</FONT></TD>
+</TR>
+<TR><TD WIDTH="37%" VALIGN="TOP" COLSPAN=2>
+<FONT SIZE=2><P ALIGN="JUSTIFY">Tanzania, 1984</FONT></TD>
+<TD WIDTH="32%" VALIGN="TOP">
+<FONT SIZE=2><P ALIGN="JUSTIFY">40</FONT></TD>
+<TD WIDTH="32%" VALIGN="TOP">
+<FONT SIZE=2><P ALIGN="JUSTIFY">20</FONT></TD>
+</TR>
+<TR><TD WIDTH="37%" VALIGN="TOP" COLSPAN=2>
+<FONT SIZE=2><P ALIGN="JUSTIFY">Zambia</FONT></TD>
+<TD WIDTH="32%" VALIGN="TOP">&nbsp;</TD>
+<TD WIDTH="32%" VALIGN="TOP">&nbsp;</TD>
+</TR>
+<TR><TD WIDTH="4%" VALIGN="TOP">&nbsp;</TD>
+<TD WIDTH="33%" VALIGN="TOP">
+<FONT SIZE=2><P ALIGN="JUSTIFY">1982</FONT></TD>
+<TD WIDTH="32%" VALIGN="TOP">
+<FONT SIZE=2><P ALIGN="JUSTIFY">57</FONT></TD>
+<TD WIDTH="32%" VALIGN="TOP">
+<FONT SIZE=2><P ALIGN="JUSTIFY">29</FONT></TD>
+</TR>
+<TR><TD WIDTH="4%" VALIGN="TOP">&nbsp;</TD>
+<TD WIDTH="33%" VALIGN="TOP">
+<FONT SIZE=2><P ALIGN="JUSTIFY">1986</FONT></TD>
+<TD WIDTH="32%" VALIGN="TOP">
+<FONT SIZE=2><P ALIGN="JUSTIFY">60</FONT></TD>
+<TD WIDTH="32%" VALIGN="TOP">
+<FONT SIZE=2><P ALIGN="JUSTIFY">19</FONT></TD>
+</TR>
+</TABLE>
+
+<FONT SIZE=2><P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P></FONT>
+<TABLE BORDER CELLSPACING=1 CELLPADDING=7 WIDTH=590>
+<TR><TD VALIGN="TOP">
+<B><FONT SIZE=2><P ALIGN="JUSTIFY">Box 2.4 do women farmers learn from their husbands?</P>
+</B><P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">A survey of women farmers in Burkina Faso found that 40 percent had some knowledge of modern crop and livestock production technologies. For most of these women, relatives and friends were the source of information; nearly one-third had acquired their knowledge from the extension service, and only 1 percent had heard of the technologies from their husbands.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Men are less likely to pass information on to their wives when crops and tasks are gender specific. In Malawi women claimed that their husbands rarely passed on advice to them: if their husbands did tell them something. the women did not find it relevant to their needs. In India women learned from friends, relatives. neighbors. and sometimes from their husbands. but this second-hand information seldom changed their production patterns (Saito and Spurling 1992). </FONT></TD>
+</TR>
+</TABLE>
+
+<FONT SIZE=2><P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The expansion of agricultural services beyond the public sector is a growing phenomenon in developing economies. The inadequacies of public funding plus the need to provide snore client-oriented services, suggest that the private sector has an important role to play However, women's limited access to land and credit put the many potential benefits offered by extension services out of reach. For example in Kenya's Meru and Maranga areas more than half the women surveyed cited a shortage of cash as their reason for not adopting, technologies that would maximize their output and increase their efficiency. The amount of education omen receive and the efficiency with which they run their farms are also closely linked This tie is particularly significant in light of the fact that one purpose of extension services is to advise farmers on use of modern technology.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Three studies of Kenya found that the gender of the farm manager was, by itself. an insignification factor in output per hectare but that the manager's educational level had a significant effect on farm productivity (Moock 1976: Saito and Spurling 1992: Bindlish and Evenson 1993). Simulations based on these studies suggest that significant gains could accrue to increased investment in women's physical and human capital. As the data in table 2.6 show, if women and men shared the same educational characteristics and input levels. farm-specific yields would increase between 7 and 22 percent. Giving women primary schooling, by itself. would increase yields by 24 percent. Thus under investment in women's education limits growth of agricultural productivity. Well-targeted extension services can help to narrow the differences in productivity that arise from educational inequalities (Schultz 1988)</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Increasing Human Capital and Input Levels Would Increase tile Yield for Women Farmers.</P>
+<P ALIGN="JUSTIFY"></P>
+<B><P ALIGN="JUSTIFY">Table 2.6 effects of increasing women farmers' human capital and input levels Increase  yields</P>
+</B><P ALIGN="JUSTIFY"></P></FONT>
+<TABLE BORDER CELLSPACING=1 CELLPADDING=7 WIDTH=590>
+<TR><TD WIDTH="82%" VALIGN="TOP">
+<B><FONT SIZE=2><P ALIGN="JUSTIFY">Policy experiment </B></FONT></TD>
+<TD WIDTH="18%" VALIGN="TOP">
+<B><FONT SIZE=2><P ALIGN="JUSTIFY">(percent)</B></FONT></TD>
+</TR>
+<TR><TD WIDTH="82%" VALIGN="TOP">
+<FONT SIZE=2><P ALIGN="JUSTIFY">Maize farmers Kenya, 1976</FONT></TD>
+<TD WIDTH="18%" VALIGN="TOP">&nbsp;</TD>
+</TR>
+<TR><TD WIDTH="82%" VALIGN="TOP">
+<FONT SIZE=2><P ALIGN="JUSTIFY">Effects of giving female farmers sample mean characteristics and input levels</FONT></TD>
+<TD WIDTH="18%" VALIGN="TOP">
+<FONT SIZE=2><P ALIGN="JUSTIFY">7</FONT></TD>
+</TR>
+<TR><TD WIDTH="82%" VALIGN="TOP">
+<FONT SIZE=2><P ALIGN="JUSTIFY">Effects of giving female farmer s men's education and input levels</FONT></TD>
+<TD WIDTH="18%" VALIGN="TOP">
+<FONT SIZE=2><P ALIGN="JUSTIFY">9</FONT></TD>
+</TR>
+<TR><TD WIDTH="82%" VALIGN="TOP">
+<FONT SIZE=2><P ALIGN="JUSTIFY">Effects of giving women primary schooling</FONT></TD>
+<TD WIDTH="18%" VALIGN="TOP">
+<FONT SIZE=2><P ALIGN="JUSTIFY">24</FONT></TD>
+</TR>
+<TR><TD WIDTH="82%" VALIGN="TOP">
+<FONT SIZE=2><P ALIGN="JUSTIFY">Food maize (maize beans and cow pears) farmers</FONT></TD>
+<TD WIDTH="18%" VALIGN="TOP">&nbsp;</TD>
+</TR>
+<TR><TD WIDTH="82%" VALIGN="TOP">
+<FONT SIZE=2><P ALIGN="JUSTIFY">Effects of giving female farmer men's education and input levels</FONT></TD>
+<TD WIDTH="18%" VALIGN="TOP">
+<FONT SIZE=2><P ALIGN="JUSTIFY">2.0</FONT></TD>
+</TR>
+<TR><TD WIDTH="82%" VALIGN="TOP">
+<FONT SIZE=2><P ALIGN="JUSTIFY">Effects of increasing land area to male farmers' levels</FONT></TD>
+<TD WIDTH="18%" VALIGN="TOP">
+<FONT SIZE=2><P ALIGN="JUSTIFY">10.5</FONT></TD>
+</TR>
+<TR><TD WIDTH="82%" VALIGN="TOP">
+<FONT SIZE=2><P ALIGN="JUSTIFY">Effects of increasing fertilizer to male farmers' levels</FONT></TD>
+<TD WIDTH="18%" VALIGN="TOP">
+<FONT SIZE=2><P ALIGN="JUSTIFY">1.6</FONT></TD>
+</TR>
+</TABLE>
+
+<FONT SIZE=2><P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<B><P>&lt;&lt;TOC3&gt;&gt; Conclusion</P>
+</B><P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Analysts must look beyond market outcomes to identity the sources of persistent inequality between women and men. The search must focus on the household and its role in the formation of present and future human capital and on institutions beyond the household that reinforce and perpetuate gender inequalities. Gender inequalities within the household affect market outcomes, and these feed back; into household decisionmaking. This process is reinforced by inequalities in access to assets and services beyond the household. Improving the relative status of women within the household and increasing their access to assets and services will increase the returns to investment in human resources and improve the prospects for sustainable economic growth.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">We must look for that which we have been trained not to see  Ann Scales, Yale Law Journal 1986</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<B><P ALIGN="CENTER">&lt;&lt;TOC2&gt;&gt; Chapter three</P>
+</B><P ALIGN="JUSTIFY"></P>
+<B><P>&lt;&lt;TOC3&gt;&gt; Public Policies Matter</P>
+</B><P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">As CHAPTER 2 has shown underivesting in girls and women is inefficient for society as a whole. Correcting for past underinvestment will require a "genders" approach to public policy. How this can be concretely achieved is the topic of this chapter.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<B><P>&lt;&lt;TOC3&gt;&gt; Equalizing Opportunities by Modifying, the Legal Framework</P>
+</B><P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Laws form tile functional framework of the economy and of civil society. Equality in the legal treatment of men and women creates the legitimacy policymakers need to seek change. Legal and regulatory provisions that discriminate against women-that. for example bar married women from seeking employment or prevent women from holding legal title to land-perpetuate gender inequalities and severely restrict women's ability to participate fully in social and economic development.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Modifying the legal framework to  eliminate discrimination and equalize opportunities for women and men is an important goal for public policy at the national and international levels. A supportive legal environment is also vital for other aspects of public policy that have a direct bearing on the opportunities available to women. such as regulations affecting the formal and informal sectors.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Four areas of the law are particularly important for equalizing the opportunities available to men and women: land and property rights; labor market policies and employment law: family law: and financial laws and regulations.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<B><P>&lt;&lt;TOC3&gt;&gt; Land and Property Rights</P>
+</B><P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Policymakers should ensure that women and men are treated equally in the public allocation of land. Eligibility for land reform programs, for example. should not discriminate against women's perform claims whether the women are heads of households or members of households headed by men. When communities have been resettled or when a project allocates land to participating producers, women should have the same rights to land as men For refugee and displaced women returning to their homelands. often as de facto heads of households. need fair and equal treatment to allow them to establish a Farming or enterprise base as soon as possible. Whet-e land is in short supply, it may be necessary to recognize the land rights of certain groups, as well as their individual rights. The Indian National Sericulture Project is an example; it has leased land to women's groups and promoted women's access to land under state land-grant schemes (Quisumbilig 1994).</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Some countries have enacted legislation to ensure gender equality in property and contractual rights. Under China's Law of Succession, for example males and females have equal rights to inheritance. Complementary measures are needed to ensure that women know their rights. Such measures include legal programs and campaigns to make judges and administrators sensitive to gender issues in the area of property rights (see box 2.1)</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<B><P>&lt;&lt;TOC3&gt;&gt; Labor Market Policies and Employment Law</P>
+</B><P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Discriminatory labor market policies and employment laws are widespread: examples are bans on hiring married women and restrictions on the type of work pregnant women may pet-form. Labor laws may also restrict female participation in jobs and deny women access to work settings. Even legislation that seeks to promote equal opportunity can have outcomes tot women workers. For example, generous maternity and child-care benefits tot women workers may make hiring women relatively mote costly than hiring men. perpetuating the gender wage gap.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The main issue for public policy its to ensure that fair and equal employment laws exist and are enforced.</P>
+<P ALIGN="JUSTIFY"></P></FONT>
+<TABLE BORDER CELLSPACING=1 CELLPADDING=7 WIDTH=590>
+<TR><TD VALIGN="TOP">
+<B><FONT SIZE=2><P ALIGN="JUSTIFY">Box 3.1 some NGO efforts to promote women's legal literacy</P>
+</B><P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Schuler and Kadirgamar - Rajasingham (1992) describe innovative approaches by  non governmental organizations to provide women with useful legal knowledge and tools.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The Caribbean Association for Feminist Research and Action (CAFRA) has launched "women and the law" projects in five English-speaking Caribbean countries. Using a participatory methodology. the projects aim to create awareness of the law. provide women with legal information that will be useful to them in their daily lives, identify specific areas for action, and influence overall legislative policy. The projects develop educational materials for legal literacy and offer topic specific paralegal training for women's organizations.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The legal literacy program of the Ugandan Women Lawyers' Association (FDA-Uganda) conducts legal literacy campaigns on specified dates each month in different districts. Pairs of FIDA volunteers conduct sessions, using role playing and discussions, on legal topics of relevance to women's lives and provide advice on contacting the FIDA legal clinic for advice and representation. In addition, FIDA and Action for Development broadcast regular radio and television programs on women and the law and publish pamphlets on legal issues of interest to women. </FONT></TD>
+</TR>
+</TABLE>
+
+<FONT SIZE=2><P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">In India the Self - Employed Women's Association (SEWA) holds worker education meetings to provide members with legal information and offers one day training sessions on specialized legal information for community leaders. Members of SEWA paralegal staff research cases, prepare briefs, and argue all cases in labor courts for members. SEWA'S legal literacy efforts are part of its overall strategy of action for supporting self-employed women and women in the informal sector.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">In this regard. the main issue for public policy is to ensure that fair and equal employment laws exist and are enforced. Such laws should cover employment and employment-related benefits and should not be applied in a way that restricts women's access to the labor market.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">In many countries women are protected by special standards in the workplace. These safeguards are of two types. The first includes measures intended to end discrimination in the labor market by requiring equal pay for work of equal value or by prohibiting the exclusion of workers from certain jobs because of gender. The second type protects women in their role as mottles by requiring employers to pay the full cost of maternity leave and provide childcare facilities. restricting night work, and limiting work categorized as dangerous or hazardous.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The first type of labor standard is often difficult to enforce. although nearly 120 countries have enacted equal opportunity laws. In most cases the law is in place but is not enforced. Furthermore. it often applies only to the formal sector of the labor market. leaving large number of women in the informal sector with little protection. More concerted public and private action is required to devise appropriate for enforcement. In additions complementary measures are needed to increase womens chances of entering the labor force. Such measures would include mote met-it-based hiring of women in the public sector and the creation of an appropriate regulatory framework that encourages the establishment of day-care centers private nursery schools. and kindergartens for the children of workers in both the formal and informal sectors. (Box 3.2 describes a day-care projects in Bolivia)</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Many countries have laws that limit night work. over theme and the use of heavy machinery by women. While well intentioned. these laws. too. can reduce women's employment options by raising the employer's cost of hiring women and perpetuating the notion that women workers are less flexible than male workers. This adverse result occurs because women already tend to have lower levels of capital than men and are limited by traditional notions of what womens work. Devising effective protective legislation for women is thus a difficult balancing act.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Effective laws to protect women must honor the fine line between ensuring sate working conditions for all workers, including women in the informal sector. and providing equal opportunities for all workers seeking employment. Standards relating to maternity leave and child-care benefits are common in the formal sector. To ensure that such standards do not raise the costs of female labor unnecessarily employment legislation should avoid having employers pay benefits directly. Maternity benefits should be funded through general revenue taxes</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Box 3.2 day-care center in Bolivia to enhance the status of women by increasing their employment opportunities in other Latin American countries, and their knowledge of women in Bolivia are over represented , health, and nutrition. The project among the poor, and many live in will establish day-care centers to proficult circumstances. They are twice vice non formal,  home-based, integrals likely as men to be illiterate, their child development for children unaccess to child care is limited, they the age of 6 in thirty-four poor subject to discrimination in hiring ban and purebred areas. Women and wages, and they are restricted benefit from the project either as by law from engaging in certain procure givers employed at the minimum ductive activities. wage or as clients of the centers. The Integrated Child Development children in day care gives women Project, financed by a credit from the more time to search for jobs or to in World Bank's International Development their current situations (Winkler opponent Association designed and Guedes 1995).</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Or social security systems rather than by direct contributions from individual employers. In Eastern Europe and Latin America, however, this method of funding benefits has imposed a significant cost on the treasury, raising the question of how much should be paid and for how long.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">One way of addressing this issue is for governments to encourage women and men to share the responsibility for childrearing by adopting legislation allowing either parent to qualify for the leave and benefits associated with having a child (Folbre 1994). Such legislation can be supported by changes in the tax system to ensure equal treatment of workers within the household and a margin tax rate on the earnings of additional workers in the household low enough to avoid creating a disincentive to women's participation in the labor force (Mac Donald 1994). These tax changes can be complemented by legislation that encourages absent to pay child support. Such laws are in place in many Latin American and Caribbean countries. but none systematically monitors transfers (Folbre 1994). Greater efforts to enforce the law are needed.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<B><P>&lt;&lt;TOC3&gt;&gt; Family Law</P>
+</B><P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Gender inequality in family law can worsen women's bargaining position within and outside the household and affect household welfare and efficiency. As noted in chapter women's bargaining position in relation to Household resource allocation is often a key factor in determining the wellbeing of household members. particularly children. Reforms of family law can enhance women's economic and social opportunities while still respecting cultural norms. For instance the minim age of marriage for women  should be set high enough so that girls can complete secondary schooling: this would help lower fertility rates. (Allowing for exceptions such as parent consent negates the potential fertility benefit.) Marriage contracts should include stipulations guaranteeing the wife's rights. especially on separation</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<B><P>&lt;&lt;TOC3&gt;&gt; Women's bargaining position in relation to household</P>
+</B><P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Legal and policy measures can have a direct bearing on the health of women. The law and its enforcement are essential for combating domestic violence against women. If the laws on violence against women are to be enforced, women need to be made aware of the legal recourse available to them and the judiciary and police need to be sensitized to the existence and</P>
+<P ALIGN="JUSTIFY"></P></FONT>
+<TABLE BORDER CELLSPACING=1 CELLPADDING=7 WIDTH=590>
+<TR><TD VALIGN="TOP">
+<B><FONT SIZE=2><P ALIGN="JUSTIFY">Box 3.3 innovative approaches to combating gender violence</P>
+</B><P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Brazil's women-only police stations are an innovative approach to the problem of violence against women. They have been so successful that other countries-including Argentina, Colombia, Costa Rica, India, Peru, and Uruguay-have emulated them. The police stations have made it easier for women to report gender based crimes of violence, and, with that experience, women are now demanding more support from the police, such as legal counseling and advice. Despite the program's success, the number of convictions for gender-based crimes has not increased, largely because similar innovations have not been made in the  judicial system (Heise, Pitanguy, and Germain 1994). </FONT></TD>
+</TR>
+</TABLE>
+
+<FONT SIZE=2><P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">In Zimbabwe the Mussasa project provides support and counseling to abused women and sensitizes police and prosecutors to the issues of domestic violence and rape. To ensure the credibility and acceptability of the training, legal professionals are involved in the program. One branch of the criminal justice system-the police department, for example-often hosts training for another, such as prosecutors (Stewart 1992).</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">In Costa Rica El Instituto Legal de las Naciones Unidas y Desarrollo runs gender sensitization training for prosecutors, judges, lawyers, and other professionals who deal with crimes of violence against women (Heise, Pitanguy, and Germain 1994).</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Implication of violence against women. Affirmative action policies can increase the number of women police officers lawyers, and judges. Trading police, lawyers, and judges can increase their gender sensitivity. making the legal system more responsive to women's needs. Legal literacy efforts can make women aware of their rights and show them how to use these rights to mobilize for change. Some approaches to dealing with domestic violence are illustrated in box 3.3</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<B><P>&lt;&lt;TOC3&gt;&gt; Financial Laws and Regulations</P>
+</B><P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Access to credit is vital for women, allowing them to manage fluctuations in income and expenditures and to expand their businesses. As we saw in the preceding chapters, credit can be an important source of economic empowerment for women within the household. But in many countries. underdeveloped financial markets, controlled interest rates, and overly rigid backings regulations have led to systems of credit that tend to shut out the pool. many of whom are women If financial institutions are to lend to those unable to obtain credit in the current environment. interest rates must be liberalized. Positive interest rates have important effects on informational money markets, which tend to be more exploitative when formal sector credit is rationed.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Changes in the laws governing access to credit are also vital because women's business profiles often differ from men's. Compared with men. women are more likely to work in low-risk small, and home-based businesses (Rhyne and Holt 1994). This situation creates a demand for small loans that can be obtained without formal, legally secured collateral and that offer relatively flexible repayment terms. Legislation that encourages broad access to financial institutions can increase the availability of these types of loans. but legal changes may also be needed to extend the range of acceptable collateral.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">In many countries the regulatory framework contains provisions that are especially punitive to small firms. This adds an additional constraint on women, whose businesses are concentrated at the small end of the size The deregulation of the microentreprise sector would remove implicit disincentives to small-film activity and would relieve some of these Such action would enhance women entrepreneurs' prospects of benefiting from training or credit programs targeted to the microentreprise sector (World Bank 1994d. 1995c).</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Redirecting Public Policies and Expenditure to Promote (tender Equality)</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">It is unlikely that legal reform by itself will be sufficient to ensure that women and men ate treated equally. Further public action may be required to guarantee that gentler-neutral laws are enforced at both national and local levels.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<B><P>&lt;&lt;TOC3&gt;&gt; Macroeconomic: Policies</P>
+</B><P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Many developing countries are implementing important policy and institutional reforms to address changing economic conditions on both the domestic and international fronts. These reforms are often supported by international financial institutions and bilateral donors. The pace of reform has varied across countries Those countries that have implemented reforms early on, carried them out consistently, and received adequate financial support have generally enjoyed faster and stronger economic growth than count ties that have undertaken reforms too slowly, too intermittently, or not at all. Where implementation has been slow or the government's commitment weak, economic distortions have tended to multiply and economic trowels to slow. limiting the government's ability to invest in physical and human capital for the future.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">It is often the poorest groups in society that stand to lose the most from economic distortions. High and rising inflation places a disproportionate tax burden on the poor including low-paid wage workers and those with fixed incomes. For this and other reasons, inflation tends to hit women harder than men. An overvalued currency is also regressive; it keeps the price of goods artificially low. crowding out many locally produced goods. Women's businesses. which ate often concentrated in the informal sector, can be particularly vulnerable to competitions from cheap snorts. An overvalued currency reduces international competitiveness. limiting the availability of foreign exchange for domestic entrepreneurs and constraining business expansion and employment creation. A firm commitment to policy refortify is therefore essential to economic growth and sustainable initiatives for alleviating poverty.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<B><P>&lt;&lt;TOC3&gt;&gt; Inflation tends to hit women harder than men.</P>
+</B><P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Such reforms generally include two kinds of necessary policies. The first emphasizes macroeconomic stability and the removal of price distortions: the second promotes labor-demanding growth in agriculture and industry and better. mote accessible basic social services. mightily in education, health care and water supply. Macroeconomic stability can be achieved by reducing large current account and government budget deficits and by curtailing excessive money and credit expansion. Correct pricing of foreign exchange and of domestic goods and services facilitates trade and investment and promotes growth Reforms of trade and price incentives encourage job creation and higher earnings.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">In shots. broadly based economic reforms benefit the poor, as the experiences of diverse countries have shown. Data from the LSMS and similar studies confirm that in Costa Rica, Ethiopia. Than Indonesia, Peru, the Philippines, and Tanzania, declines in poverty rates have accompanied economic reforms. Because of underlying gender inequalities, reductions in poverty do not necessarily improve the economic status of women. Nonetheless. although empirical evidence on changes in women's welfare following reforms is scarce, data from the Philippines suggest that for women. economic reform is by improvements in social indicators and important employment gains (box 3.4). An analysis of household data from Peru indicates that reforms there have not only led to renewed growth and reduced poverty but have also improved the status of female-headed households (box 3.5).</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Despite their seminal role in encouraging sustainable. long-term growth. some economic reforms involve transitional costs. for two reasons: the need to implement radical shifts in government policy, and the lag. perhaps of years, between acceleration of economic growth and the realization of the 
+</P>
+<P ALIGN="JUSTIFY"></P></FONT>
+<TABLE BORDER CELLSPACING=1 CELLPADDING=7 WIDTH=590>
+<TR><TD VALIGN="TOP">
+<B><FONT SIZE=2><P ALIGN="JUSTIFY">Box 3.4 social progress and labor force gains for women in the Philippines</P>
+</B><P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The Philippines began implementing economic reforms in the early 1980s. While political turmoil and some policy slippage have weakened GDP growth over the period and led to the need for further reforms, quality of life indicators have improved during adjustment. For example, by 1990 the incidence of absolute poverty had declined by about one-third (to approximately 20 percent of the population). Maternal and infant mortality rates also declined over the period: in 1980 the infant mortality rate was 52 per 1,000 live births, but by 1990 it had fallen to 41 per 1,000 births (Johansen 1993). </FONT></TD>
+</TR>
+</TABLE>
+
+<FONT SIZE=2><P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The percentage of the population with access to safe drinking water increased between 1980 and 1990, from 65 to 93 percent of the urban population and from 43 to 72 percent of the rural population. The figures for sanitation services showed the same increase, climbing from 81 percent with access in 1980 to 98 per  cent in 1990 among urban dwellers and from 67 to 85 percent among those in rural areas. Secondary school enrollment rates for boys and girls also showed gains. Girls and boys have traditionally reached similar educational levels in the Philippines, a trend that contributed to women's gains in the labor market during adjustment in the 1980s. While labor force participation rates for men rose only slightly, the rates for women increased dramatically, from 23 to 37 percent.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">At the same time, women's wages as a percentage of men's grew from 71 to 80 percent between 1978 and 1988 (Tzannatos 1995). A recent study of a low-income community in Manila found that in some private sector jobs women earn more than men, reflecting in part the high educational level among women in the sector. Earnings in the informal sector are generally low for both women and men. although some women have been so successful in their informal sector businesses that their spouses have opted to leave low-paying jobs in the formal sector to participate in their wives enterprises (Moser 1994).  benefits of growth by large segments of the population. The short-term costs can include increases in food prices as subsidies are removed temporary restrictions on credit to control monetary expansion, and cuts in public spending as governments attempt to control budget deficits and reorient spending toward the most important public services. Moreover, inequalities in access to and control over resources and in entry into markets hamper some groups in taking advantage of the opportunities created by economic reform For example, people who are unable to acquire new skills may remain for some thee. Gender inequalities in access to and control over land in rural areas can keep women farmers from taking advantage of changes in the relative prices of tradable and non tradable crops.</P>
+<P ALIGN="JUSTIFY"></P></FONT>
+<TABLE BORDER CELLSPACING=1 CELLPADDING=7 WIDTH=590>
+<TR><TD VALIGN="TOP">
+<B><FONT SIZE=2><P ALIGN="JUSTIFY">Box 3.5 macroeconomic reform and improved living standards in Peru</P>
+</B><P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Between 1985 and 1990 Peru's economic regime was marked by expansionary monetary and fiscal policies and high levels of government intervention in most areas of the economy. Although these policies led to an initial period of growth, the approach proved unsustainable: by late 1987 growth had given way to hyperinflation and deep recession. During 1988-90 real GDP dropped by an average of 8 percent a year. Real wages and consumption expenditure also fell sharply as inflation soared to 7,600 percent a year in 1990.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">In 1990 the new government of President Alberto Fujimori introduced macroeconomic reform measures designed to stabilize the economy, reduce fiscal deficits and inflation, increase market efficiency, and improve the country's competitiveness. Under this reform program inflation declined dramatically, falling to 57 percent in 1992 and to 17 percent in 1994. Real GDP grew by about 20 percent between 1991 and 1994, while real per capita consumption expenditure grew by more than 18.5 percent. LSMS data show that poverty declined by 11 percent-from 55 percent of the population in 1991 to 49 percent in 1994. Although the country experienced a brief contractionary period following the introduction of reform measures, household data from Lima for 1990, 1991, and 1994 indicate that in 1994 per capita expenditure was well above, and the incidence of poverty well below, 1990 levels. </FONT></TD>
+</TR>
+</TABLE>
+
+<FONT SIZE=2><P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Improvements in living standards have been widespread, and the largest gains have been made in some of the country's poorest regions, such as the urban and rural sierra (mountain areas). In most parts of the country, increases in per capita expenditure among households headed by women have been above the national average. In the urban and rural sierra, for example. consumption expenditure by these households increased by 47.7 and 44.8 percent. respectively-figures that compare favorably with increases in per capita expenditure among households headed by men (35 and 28 percent for the same regions).</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Although both women and men are expected to gain from economic reform in the long run. gender inequalities at the household and market levels can mean that the benefits of reform reach women, especially poor women. only slowly. Reforms must incorporate measures aimed at counter acting shot-term transitional costs. Among the most important are safety nets specifically targeted to vulnerable groups. For example, in fiscal 1994 seventeen of the twenty-three reform programs supported by the World Bank included components aimed specifically at reducing poverty: fourteen of them targeted programs or safety net measures such as labor-intensive public works projects. targeted and social assistance programs, and unemployment and social security schemes (see box 3.6).</P>
+<P ALIGN="JUSTIFY"></P></FONT>
+<TABLE BORDER CELLSPACING=1 CELLPADDING=7 WIDTH=590>
+<TR><TD VALIGN="TOP">
+<B><FONT SIZE=2><P ALIGN="JUSTIFY">Box 3.6 food coupons improve nutrition in Honduras</P>
+</B><P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The food coupon program in Honduras, part of a social safety net supported by the World Bank and financed by IDA and other donors, was put in place in 1990 to protect the country's most vulnerable people during economic reforms. Starting with about 182,000 participants, by 1994 the program had expanded its coverage to 345.000 of the estimated 430,000 children at risk of malnutrition. The effort also supports nutrition education for health workers, community groups, and mothers. Because coupons are used instead of food. the government saves some 30 percent over traditional food distribution costs, and the beneficiaries are able to choose the food  they will consume. Beginning in 1995, an adjustment for inflation will maintain the value of the coupons, enabling participants to satisfy a constant proportion of their food needs.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The project also supports the development and implementation of a long-term nutrition assistance strategy for Honduras. Although attempting to measure changes in malnutrition is difficult in the short term, there have already been noticeable benefits. Between 1990 and 1993 the number of first-graders with severe or moderate malnutrition dropped by 4 percent. Organizers are now trying to graduate women participants from the program by offering training in basic skills such as food processing and helping them find assembly work in local factories (World Bank 1995b). </FONT></TD>
+</TR>
+</TABLE>
+
+<FONT SIZE=2><P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">However, safety nets are not a substitute for a mote integrated approach to economic and social policy that includes appropriate levels of harvest in social services and infrastructure. Recognizing this fact, governments and donors are increasingly incorporating into their reform packages antipoverty initiatives and measures to reduce gender inequality. In Pakistan, for example, the FIDA-financed Public Sector Adjustment. Program provides much needed the financial support for the balance of payments account and reinforces the emphasis on government investment in the social sectors. The program promotes increased access to and improvements in basic education. health. and water supply services that benefit girls and rural areas. It also supports a shift it government education and health spending toward the primary level.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">In fiscal 1994 twelve of twenty-three World Bank economic reform pro emphasized the restructuring public expenditure, primarily to and increase spending on education. health care, and other areas important to poverty reduction such as water supply and sanitation. The Burkina Faso reform program is typical; it supports an increase in the total budgeted amounts for primary education and health services, which are particularly beneficial to the poor and to women. Uganda s program seeks to protect and enhance public expenditures for basic social services. including water supply primary health care and primary education. In the long term, the reform of public spending-especially in the social sectors, physical infrastructure and agricultural research and extension-promises significant benefits) trot women.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<B><P>&lt;&lt;TOC3&gt;&gt; Sectoral Investments </P>
+</B><P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">In principle. public expenditures on social services and infrastructure are allocated on a gender-neutral basis; in practice men and women use these services differently. The resulting inequalities frequently perpetuate gender based differences in the accumulation and distribution of human capital within households. Public policy can address this problem by public expenditure priorities between secrets and within social sectors. Further it can support services and types of infrastructure that provide the highest social returns to public spending and are most heavily used by women  and children.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">EDUCATION. Estimations of the private returns to education for a number of countries (Psachatopoulos 1994) show that returns are at least equal for girls anti boys and are often higher for girls. Moreover, these rates do not capture the externalities generated by providing education to girls. The combination of private and social returns provides a clear signal for restructuring the allocations of public resources so as to support female education. Yet incidence analysis for a number of countries for which the necessary data are available reveals that educational subsidies per capita are higher for males than for females This difference is partly a result of the bias in allocation of subsidies toward higher levels of education, where female enrolled is lowest. Distortions in the allocation of public resources, such as the provision of mote money foe male-dominated tertiary institutions than for education that benefits girls, should be corrected by reallocating spending toward basic (primary and lower-secondary) schooling. Targeting these educational levels will have the maximum effect on girls' education and will yield higher social returns for society as a whole. In countries where universal basic education has been achieved and capital markets are unable to help households finance higher education, continuing subsidize higher education may be warranted. The rationale for the subsidy would be the productivity gains associated with a better-trained labor force.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">To correct the bias against enrollment of girls more targeted interventions are need to influence household (see decisionmaking)</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">However reallocating public spending toward primary education and later toward higher levels is not sufficient to erase the gender gap in education The bias against enrolling girls in school is evident in both poor and no poor households and applies even at the primary level. To correct this bias, more targeted interventions are needed to influence household decision making</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">HEALTH. Correcting the gender bias in the public financing of health care IS a more complex process than correcting the bias in education. for two main reasons: the marked differences between the health needs of men and women, and the unreliability of household data on demand for health services in comparison with the data on demand tot education). However it is cleat that targeting health services to women implies provision of adequate funding for prenatal care. infant immunization, and mother and child health services. Because of the significant social benefits of providing women with appropriate health care, governments should make basic services ices that benefit women a top priority among, public health care expenditures.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">There is a critical link between the public provision of health care and women's access to educational opportunities. A mother educated to seek preventive care and early treatment of illness for herself and her children (particularly girls) will reduce the cost of health care and in many cases. prevent premature death. Most of these highly cost-effective services can be supplied in rural clinics and health centers. Public spending should be so allocated as to ensure sufficient funding for these primary health facilities.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">AGRICULTURAL EXTENSION SERVICES. Agricultural extension and research services are widely considered vital to increasing and sustaining agricultural productivity. Many of these services are being provided by the private sector. but in some countries private services need public support, either because certain markets have not yet been developed or because the infrastructure is poorly developed. However. women farmers and small holders are often not served as effectively by public agricultural extension systems as ate and male farmers (FAO 1993). This disparity stems paltry from expend priorities within agricultural extension services. which concentrate resources on the crops and the technology controlled primarily by male commercial farmers. Reallocating public spending on agricultural extension and research services toward crops and technology raised by or used by small holders and women farmers could yield high social returns to public investment and could increase private returns by improving the skills and productivity of small agricultural producers.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Reallocating public spending on agricultural extension  and research services toward crops and technology </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Techniques for small holders and women farmers should take into account the need for quality and cost-effectiveness in public services, Economies of scale can be achieved if extension agents deal with groups of farmers instead of with individuals. This approach also provides a valuable forum for exchanging information. fostering peer learning. sharing expensive equipment. and pooling resources for- credit. Mobile trailing units and flexible hours that fit the crowded schedules of women farmers should also be considered. and more female extension agents should be trained to deal directly with female farmers. Such measures can be introduced without large additional resources if existing expenditures are carefully reallocated.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">INFRASTRUCTURE, Public investment in economic and social infrastructure is vital in facilitated individual and household investment in physical and human capital. However, public expenditures on roads, water supply, and sanitation infrastructure frequently do not meet the needs of those who use the services most heavily. Women are the main users of water services, and it is essential to involve them in designing and implementing water projects. For example. in areas where transport is inadequate and water collection is a daily burden for women and children, the population tends to use the closest available facility rather than the safest one. In such cases. projects that ensure a safe water supply and take into account the specific needs and constraints of the users often have a significant effect on users' health. In two villages in Zaire where a piped water network was installed to provide safe drinking water, the median incidence of diarrhea was halved among children in households located less than a five-minute walk from a public standpipe. Spending allocations that favor public water supply and sanitation improve the general health of the population, save time for women and children. and increase school attendance. A study from Morocco chows that access to tap and well water instead of pond or river water raised school enrollment for both boys and girls (Khandker, Lavy, and Filer 1994).</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Women are the main users of water services and it is essential  to involve them in designing and implementing water projects.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Public spending on roads and energy-related facilities (for instance electrification or energy conservation) or other infrastructure is usually assumed to be gander neutral. Yet women and men use these facilities differently The Morocco study cited above found that the availability of electricity increased the rate for girls substantially more than for boys. The study also showed that the presence of a paved road increased by 40 percent the probability that girls would attend school and reduced by 5 percent their probability of dropping out. Overall, improved road conditions increased the probability of school attendance for girls by 32 percent and for boys by 20 percent.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Rural electrification can also ease the time constraints on women who must balance household and productive work. Lack of time is often a primary season for women's weak response to economic incentives. especially in rural areas. The case for making public investments in infrastructure would be stronger if gender differences in the use of projects and services, as well as the potential effect of such investment on productivity and social development. were taken into account.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<B><P>&lt;&lt;TOC3&gt;&gt; Using Targeting Measures to Narrow the Gender </P>
+</B><P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">As we have seen. policies that specifically target women or girls can address the needs or this group more efficiently and with greater cost-effectiveness than general policy measures. Female household members tend to allocate resources more directly to children. while men tend to allocate more resources to adults. In households in which resources are not pooled. targeting programs to the household as a where will not necessarily benefit all members equally.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Targeting women directly is justifiable on two grounds. First, to the extent that gender inequalities prevent an economy from realizing its full potential. targeting to women can be an effective strategy for increasing productivity and output Second, where gender differences are wide, targeting may be needed to capture social gains and to increase internal efficiency.</P>
+<P ALIGN="JUSTIFY"></P></FONT>
+<TABLE BORDER CELLSPACING=1 CELLPADDING=7>
+<TR><TD></TD>
+</TR>
+</TABLE>
+
+<FONT SIZE=2><P ALIGN="JUSTIFY">Targeting women is especially when doing so contributes directly to reducing poverty; or when women have particular needs-for example. when maternal mortality is very high. The exceptionally high gender gap in educational enrollments in some countries can be reduced only by policies (including subsidies) that target girls. An obvious example would be policies that affect the private costs of schooling. </P>
+<P ALIGN="JUSTIFY">Female household members tend to allocate resources more  directly to children it while men</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Reducing these direct costs to households Will mean setting new public spending priorities. For example. education institutions for girls especially at the primary level, might be exempted from cost recovery measures. thus increasing the implied public spending subsidy to girls. Similarly. a far; number of publicly funded scholarships can be provided for girls' as has been done in and Guatemala.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Opportunity and travel costs can discourage parents from enrolling especially daughters in school. Some counties have tried to overcome the constraints imposed by opportunity costs by introducing flexible school hours and calendar years and providing child care for younger siblings (box 3.7). In some cases girls who are responsible for looking after their younger brothels and sisters ate allowed to bring them to school.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">In countries where cultural values may prevent girls from traveling alone to school. measures are needed that will increase access to safe transport.</P>
+<P ALIGN="JUSTIFY"></P></FONT>
+<TABLE BORDER CELLSPACING=1 CELLPADDING=7>
+<TR><TD>
+<B><FONT SIZE=2><P ALIGN="JUSTIFY">Box 3.8 economic reforms and gender targeting in Mongolia</P>
+</B><P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Since Mongolia began its transition to a market economy in 1990, the living conditions of the population have deteriorated dramatically. According to the government's estimates, a quarter of all Mongolians are now living below the poverty line. Single women with young children are among the "new" vulnerable groups that have emerged in the wake of the transition. As of December 1993 nearly 72 percent of households headed by single persons, usually women, were estimated to have incomes below the poverty line. (About 28 percent of all households in Mongolia are headed by women). The Mongolian Women's Federation reports that the divorce rate is rising among jobless low-income couples, increasing the number of single-parent households. </FONT></TD>
+</TR>
+</TABLE>
+
+<FONT SIZE=2><P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Along with job loss women are affected by the decline in services such as day care and maternity homes.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Mothers now have to look after their children at home, which restricts their ability to participate in the labor market and, ironically, increases their dependence on welfare. When herds were privatized, priority was given to people who, according to the government, could take better care of the animals. Unfortunately, this policy adversely affected female-headed households.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The maternal mortality rate has doubled over the past three years. in part because many more babies are being delivered at home. Other factors that have contributed to the rising maternal mortality rate include a decrease in the number of ambulances and the need for patients to pay for the food they consume while they are hospitalized.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">In Mongolia, targeting female-headed households, pregnant women, and children is essential for reducing poverty. Social assistance, health care. education, and help in finding employment are particularly important (Subbarao and Ezemenari forthcoming).  change the geographic distribution of primary schools, of provide more boarding facilities. Projects in Pakistan are using school mapping techniques to establish criteria for placing new schools in currently underserved areas. Such programs benefit both girls and boys.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">It may be necessary to target women when economic reforms of systemic transitions are occurring. For example, in Mongolia, as well as in other countries making the transition from a socialist to a market economy, women are disproportionately represented among the unemployed and otherwise disadvantaged (box 3.8). Thus, in designing safety nets to mitigate the short negative effects or economic transitions. policymakers need to recognize and evaluate the specific adverse effects on women</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">It is not always necessary to restrict a particular program of benefit exclusively to women: the objective can sometimes be achieved indirectly.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Techniques based on self-selection appear to be particularly efficient. In Zambia. where men have a strong preference for cash wages, offering wages in kind (food) attracted more women workers than men to public works programs.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">In the financial sector. women entrepreneurs are enabled to borrow at market rates of interest when banking institutions adopt innovate collateral requirements, reduce transaction costs, and offer small loans at repeated intervals The Grameen Bank in Bangladesh and Badan Kredit Kecaman in Indonesia do not reserve loans for women specifically: instead. they adopt innovative lending policies the result of which is that women snake up the majority of participants-is 96 percent in a new branch of the Grameen Bank.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<B><P>&lt;&lt;TOC3&gt;&gt; Involving Beneficiaries in Public Policy</P>
+</B><P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Until recently. the absence of input from beneficiaries often let's ignorant about how the costs and benefits of policy changes would be distributed among the population Today the views and needs of potential beneficiaries are being taken into account at both the macroeconomic and sectoral levels. This trend should make it possible to determine who benefits. who does not, and why. A good example of a situation in which a beneficiary's point of view can make a significant difference is in public expenditure reviews. Governments with unsustainable budget deficits must make difficult decisions about the allocation of public resources. Their task can of ten be facilitated by suggestions from the potential beneficiaries themselves, since one of the key questions policymakers face is whether investments as presently allocated are reaching the intended populations efficiently and effectively</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Three broad approaches can be used to guarantee that the views of women and other intended beneficiaries are adequately reflected in policy and project formulation. First. surveys and other methods of collecting statistical data can be designed to ensure that gender-desegregated data are properly collected and analyzed. Second, beneficiary assessments, which use a range of qualitative research methods such as direct observation. selected individual of group interviews. and case studies. can be used to ensure that the views of all groups are adequately represented.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">A third approach involves a range of participatory planning and management techniques that reflect a significant transfer of control to the community and local levels. Participatory evaluations use innovative research that allow illiterate and otherwise voiceless groups to express their concerns and priorities. Small grants and credits managed at the local level by NGOs or governments agencies permit a community to choose the projects that best reflect its OWN priorities. Social funds. whereby resources are channeled to demand-driven projects, are one such mechanism While these participatory approaches have been implemented primarily at the local level, they are also beginning to be used to involve the community in regional and national planning. Participatory methods, by helping to create local capacity. ensure the sustainability of projects and programs. They also help establish rational criteria for making public investment choices that incorporate both social and efficiency objectives.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<B><P>&lt;&lt;TOC3&gt;&gt; Generating and Analyzing Gender-Desegregated Data</P>
+</B><P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Gender-desegregated data and the capacity to analyze these data provide public policymakers with essential information and enhance the dialogue with agents outside government. One of the most valuable instruments for collecting desegregated data is the household survey. which can provide detailed information that is invaluable in policymaking. Obtaining full gender information in many instances entails only a small increase in costs. since the desegregation itself involves little extra work. However additional resources ate often needed to analyze the data and make it useful to policymakers. Public statistical agencies might analyze gender-desegregated information in partnership with private and academic institutions in order to share the costs.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">There are several important steps in collecting useful and accurate data. First. in places where gender -desegregated household data have not yet been collected. special efforts should be made to obtain them. At a minimum data on how individuals use health and educational services should be collected routinely as part of national consumption and expenditure surveys. If household consumption. income or production surveys have already been carried out but little or no gender--desegregated data have been collected, the marginal cost of collection is likely to be quite modest-perhaps on the order of 10 percent of total costs.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Participatory methods help establish rational criteria  for making public investment choose that incorporate  both social and efficiency objectives. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Second. in places where basic gender-desegregated data have already been collected, it is important to gather more data from individuals on consumption and. as much as possible. on income and the ownership of assets. Such data ate vital for developing a deeper understanding of how access to and allocation and control of resources are determined within households. More data on men's and women's access to credit and information services, such as agricultural extension programs, are needed for an understanding of women's limited access to important production inputs. The data also indicate the effectiveness of projects and programs in providing such services to women.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Third, there should be an increased emphasis on collecting panel data (thee series) to facilitate snore detailed analyses of changes in household behavior over time. Because full panel surveys are costly, it may be necessary to adopt less-expensive panel methods and combine them with flexible data collection. Anthropological and participatory research methods can be used to enhance the quality and relevance of formal survey questions, as well as to provide a "reality check" on formal survey responses.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Finally, greater priority needs to be given to gender-disaggregated analysis of existing data sets. This analysis should be carried out not only in social sectors such as health and education but also on such issues as the intrahousehold allocation of time and labor and access to and use of productive resources.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<B><P>&lt;&lt;TOC3&gt;&gt; Working in Collaboration</P>
+</B><P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Governments' ability to identify and implement policies that promote gender equality is greatly enhanced by the active participation of other players from the development community and civil society. These agents include individual women and men, community-based groups, private-for-profit firms, trade unions, non governmental organizations, and multilateral and bilateral agencies. Interaction between public institutions and other actors provides the basis for a more informed policy dialogue on gender issues. It also lays the foundation for operational collaboration and for broadly based support for public policy measures.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Over the past several decades NGOs have become major players in international development. NGOs are by no means homogenous. In the field of development, they range from large volunteer and charity organizations, many of them based in industrial countries, to community-based self-help groups. They also include research institutes, volunteer-sending agencies, religious organizations, professional associations, and lobbying groups.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">NGOs concerned with gender issues have had a particularly important role in designing and implementing gender programs, especially at the grassroots level, and in advocating policy change at the national level NGOs have been effective in providing information and education to women and in helping community-based women's organizations lobby for change. In many countries collaboration between NGOs and governments is still relatively new. Nonetheless, it is growing rapidly-most visibly in the delivery of social and financial services.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">For example, in Peru a proposed basic health and nutrition project aims to improve the quality and accessibility of health and nutritional services, with an emphasis on poor women and children. NGOs are expected to play a major role in implementing the project and will be responsible for 75 percent of training and research, 40 percent of education, and 20 percent of service delivery (World Bank 1994g). In Africa many HIV/AIDS support programs are managed by NGOs with assistance from governments and funds from international donors.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">In the long run choices made by private sector agents are profoundly important for the persistence  or reduction of gender inequalities </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">In the financial services sector NGOs have found innovative ways of overcoming barriers that women face in access to credit and savings facilities. Among the better-know programs are the Grameen Bank in Bangladesh, ACCION International in Latin America, and the NGO consortium ACCORD in Africa. NGOs have been very successful in organizing village banks and mobile banking systems to reach the rural poor. These credit programs provide women not only with the funds to finance income-generating activities but also with opportunities to acquire basic business skills and to assume leadership positions within their peer groups.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Governments also seek to collaborate with a range of institutions from the private sector. In the long run the choices made by private sector agents- whether households, firms, or trade unions-are profoundly important for the persistence or seduction of gender inequalities. Joint public-private sector initiatives can be vital in changing peoples perceptions about the benefits of investing in or hiring women. The private sector has a comparative advantage in providing certain kinds of services to women-for example, vocational education and training. Collaboration with the private sector- often means that public resources can be reallocated to those investments that offer the highest rate of social return. such as basic education and health care.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<B><P>&lt;&lt;TOC3&gt;&gt; Strengthening International Policies to Meet New Challenges</P>
+</B><P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Not all issues that bear on gender equality can be effectively addressed by individual nations. For example, refugee and displaced women and children account for up to 80 percent of the 50 million refugees and displaced persons worldwide. The sheer numbers of refugee and displaced women and children highlight the urgent need to devise international strategies for dealing with this problem.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The sheer numbers of refugee and displaced women and  children (estimated at 4 million) </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The constraints that refugee and displaced women lace are similar to those faced by other women, only magnified many times. They lack access to health services, even though their health risks are high. Girls often have less access to basic education than in their home countries. With little access to family planning, women s fertility rates may be extraordinarily high at a time when the burden of additional children hinders the chances of survival for both mothers and infants. In the absence of professional abortion services, women may rely on self-induced and unsafe abortions. The proportion of female-headed households is highest in refugee situations, yet the women's income-generating activities and skills are minimal</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The international response to this type of crisis is usually limited to emergency relief measures. Although vital, these measures often fail to recognize the long-term economic and social costs involved in restructuring the lives of displaced women when they return to their home countries. International public policy has an important role in preparing refugee and displaced women for their future role in rebuilding their societies. Long-term repatriation and development on a regional basis along the lines of the International Conference on Central American Refugees (CIREFCA) in Central America is one approach to involving governments, NGOs and development agencies in a coordinated response to refugee problems. Governments and agencies must make every effort to collaborate in making repatriation viable by establishing development programs that explicitly take account of refugees' needs. Otherwise, chances are high that people will once again be forced to leave their countries. putting at risk national reconciliation efforts.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Another area that demands an international response is the establishment of legal conventions for the enforcement of social justice and human rights. Equality under the law creates the legitimacy policymakers and private individuals need to seek change that will increase well-being and encourage economic opportunity. In certain instances, legitimacy needs to be established at the international level. For this reason it is vitally important that governments ratify the Convention on the Elimination of All Forms of Discrimination against Women. This convention. adopted by the United Nations General Assembly in 1979, provides a framework for action by countries to reduce discrimination against women in political and public life, law and education, employment, health care. commerce. and domestic relations. International conventions of this type provide an important policy lever for women's organizations and other groups in civil society.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<B><P>&lt;&lt;TOC3&gt;&gt; Conclusions </P>
+</B><P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">This chapter has presented the rationale for public interventions to promote gender equality. Such interventions are needed because of market failures and social externalities that extend beyond the individual household to affect society in general. For resources to be allocated efficiently, public spending should focus on those investments with the highest social returns. Given the evidence of high social and private returns to investments in women's human capital, public expenditures should give priority to the investments that have the largest impact on the welfare of girls and women, especially in basic education and reproductive and other health care services. Policymakers also need to identify areas in which actions can be taken that would have gender neutral outcomes, including sectoral programs addressing transport and infrastructure, water supply. and sanitation</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">BY directing  public resource toward policies and projects  that reduce gender inequality policy markers are promoting  not only equality today but also higher labor productivity </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Governments can no longer afford not to invest in women. The evidence on private and social returns to investments in women and girls cannot be ignored. By directing public resources toward policies and projects that reduce gender inequality, policy makers are promoted not only equality today but also higher labor productivity, a higher rate of human capital formation, slower population growth. and stronger economic growth tomorrows However, none of these goals can be reached without the participation of women  themselves. Governments and collaborating institutions must listen carefully to the voices of individual women, to women s groups, and to woman policymakers By working with others to identify and implement policies for greater gander equality, governments can take actions that will make a real difference to the future well-being and prosperity of their people.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<B><P ALIGN="CENTER">&lt;&lt;TOC2&gt;&gt; Notes</P>
+</B><P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">1. Birdsall and Sabot (1994) use earlier findings by Barro (1991) to test the relationship between inequality and growth. They find that in Latin America unequal distribution of education. in terms of both quality and quantity, constrained economic growth in the region by reducing opportunities for increasing labor productivity. In East Asia open and relatively equal access to high-quality basic education led to a virtuous circle of high educational performance that stimulated growth and reduced inequality</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">2. Subbarao and Raney (1993) estimate that a doubling of family planning services in 1982 would have reduced the fertility rate from 5.5 to 5 0 and the number of births by 3.5 percent</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">3. The Living Standards Measurement Study (LSMS) is a series of multitopic surveys designed to study multiple aspects of household welfare</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">4. Deforestation is represented by the time required to collect a standard load of fuelwood</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">5. It would be more illuminating to compare wage differences across three categories of women workers: women without children: women with children but with no interruption in employment except for statutory maternity leave: and women with children and with interrupted employment</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">6. Among women workers. 53 percent are in commerce. compared with 33 percent of men. In manufacturing. 16 percent of the workers are men. compared with 14 percent for women. In services, 37 percent are men anti 33 percent are women (World Bank 1995c)</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">7. In Bolivia informal moneylenders require borrowers to write postdated checks. If borrowers tail to make timely repayments, these checks are deposited and, as the lender knows will bounce for lack of funds A bounced check is a criminal offense in Bolivia. and the lender can have the borrower arrested The World Bank estimates that about 20 percent of all Bolivian prison inmates-and 40 percent of female inmates imprisoned for 'bouncing' checks and for other collateral-related crimes. In many cases children must live in prison with their mothers (winkler and Guedes, 1995)</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">8. The International Conference on Central American Refugees (CIREECA) was held in Guatemala City in May 1989 A total of 126 projects in seven countries were introduced. with an overall investment of $365 million Areas with high densities of returnees were targeted. and special attention was given to projects to support displaced women</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<B><P ALIGN="CENTER">&lt;&lt;TOC2&gt;&gt; References</P>
+</B><P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Agarwal. Bina. 1994. "Gender and Command Over Property: A Critical Gap in Economic Analysis and Policy in South Asia." World/Development 22(10) 22(10): 145578.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Baden. Sally. 1993. "The Impact of Recession and Structural Adjustment on Women's Work in Developing and Developed Countries." Working paper. International Labour Office. Geneva</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Bardhan, Kalpana 1993. "Women and Rural Poverty: Some Asian Cases" In M G Quibria, ea., Rural Poverty in Asia Priority Issues and Policy Options. New York: Oxford University Press.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Bardhan, Pranab. 1988. "Sex Disparity in Child Survival in Rural India In T. Srinivasan and Pranab Bardhan. eds., Rural Poverty in South Asia. New York: Columbia University Press.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Barro. Robert 1991 "Economic Growth in a Cross-section of Countries' Journal of Economics 106 (May):407 43.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Beneria. Lourdes. 1992. 'Accounting for Women's Work: The Progress of Two Decades.'' World Id Development 20(11): 1547-60.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Bindlish. Vishva. and Robert Evenson. 1993. Evaluation of the Performance of T and V Extension it? Kenya. World Bank Technical Paper 208. Washington. D.C.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Binswanger. Hans, and Mark R. Rosenzweig, eds. 1984 Contractual Arrangements Employment and Wages in Rural Labor Markets m Asia. New Haven. Conn.: Yale University Press.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Birdsall, Nancy, and Richard Sabot 1994 ''Inequality as a Constraint on Growth Working Paper. Manila: Asian Development Bank.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Blau. Francine. and Lawrence N. Kahn. 1992 " The Gender Earnings Gap: Learning from International Comparisons" America Economic Review 82 (2):533-38.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Bouis Howarth E., and Eileen T. Kennedy. 1989. "Traditional Cash Crop Schemes' Effects on Production, Consumption and Nutrition: Sugarcane in the Philippines and Kenya." Prepared for IFPRI-INCAP Policy Workshop. Antigua. Guatemala</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Chatterjee. Meera 1991. Indication Women Their Health and Productivity World Bank Discussion Paper 109. Washington. D.C.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">David, Rosalind 1992 The Effects of Male Out-migration on Women's Management of the Natural Resource Base of the Sahel. SOs International, London.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Donors to African Education. 1994. A Statistical Profile of Education in Sub Saharan Africa in the 1980s. Paris.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Duraiswamy. P. 1992. "Child Survival. Preventive Health Care and Schooling in Rural Households of Tamil Nadu: India." Yale University, New Haven, Conn.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Edgerton, V. R. G. W Gardner, Y Ohira. K. A Gunarwardena, and B. Senewiratne 1979 'lron Deficiency Anaemia and Its Effects on Worker Productivity and Activity Patterns' British Medical Journal 2:1546-49.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Einhorn. Barbara. 1993 Citizenship. Gender and Women's Movements in East Cent/al Europe London: Verso</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">FAO (Food and Agriculture Organization) 1993 Rural Poverty Alleviation Polices and Trends Economic and Social Development Paper 113 Rome</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Fields, Gary S. 1992 ''Changing Poverty and Inequality in Latin America" Public Finance 47 (Supplement): 59-76.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Folbre. Nancy. 1994. Who Pays for the Kids:' Gender and the Structures of Constraint. London: Routledge</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Fong, Monica 1993. The Role of Women in Rebuilding the Russian Economy. Studies of Economics in Transformation 10 Washington, D.C.: World Bank.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Goetz. Anne Marie. and Rina Sen Gupta. 1994 'Who Takes the Credit'? Gender. Power and Control over Loan Use in Rural Credit Programmes in Bangladesh." Draft University of Sussex, Institute of Development Studies. Brighton, U.K.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Hart, Gillian 1986 Power Labor and Livelihood: Processes of Change in Rural Java San Francisco: University of Berkeley Press.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Heise, Lori. 1993 ''Violence Against Women: The Missing Agenda." In Marge Koblinsky. Judith Timyan. and Jill Gay. eds.. The Health of Women A Global</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Perspective Boulder. Colo: Westview</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Heise. Lori. Jacqueline Pitanguy, and Adrienne German. 1994 Violence Against Women The Hidden Health Burden World Bank Discussion Paper 255. Washington, D.C.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Herz, Barbara. and Shahidur Khandker. 1991 Women Work Education and Welfare in Peru. World Bank Discussion Paper 116. Washington. D C</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Herz Barbara, K Subbarao, Masooma Habib. and Laura Raney 1991 Letting Girls Lea/n. Promising Education. World Bank Discussion Paper 1. Washington, D C</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Hoddinot, John, and Lawrence Haddad 1992. Does Female Income Insentience Household Expenditures  Evidence from C&ocirc;te d'Ivoire Trinity College. Oxford University, Oxford. U K</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Holt, Sharon. 1995 Gender and Property Rights: Women and Agrarian Reform in Russia and Moldova.' World Bank, Europe and Central Asia Region, Washington, D C.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">Horton, Susan 1994. "Women and Industrialization in Asia" University of Toronto. Institute for Policy Analysis</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Hosken, Fran P., ed 1992. Women's International Network News 18(4).</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">ILO/INSTRAW. 1985. Women in Economic Activity: A Global Statistical Survey 1950-2000 Geneva</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Jackson. Cecile 1993 "Doing What Comes Naturally? Women and Environment in Development." World Development 21 (12): 1947-63.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Johansen. Frida 1993 Poverty Reduction in East Asia. World Bank Discussion Paper 203. Washington. D C</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Jurisman. Clara, and Araceli Moreno. 1990. ''Women, Labour and Crisis: Mexico." Prepared for International Center for Research on Women (ICRW) project on Weathering Economic Crises: Women's Economic Responses to Recession in Latin America and the Caribbean. ICRW, Washington. D.C.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Kalima Rose. 1992. Where Women are Leaders The Sewa Movement in India. London Zed Press</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Khandker. Shahidur R. and Osman H. Chowdhury 1994 "Targeted Credit Programs and Rural Poverty in Bangladesh." World Bank, Education and Social Policy Department. Washington, D.C. and Bangladesh Institute of Development Studies, Dhaka.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Khandker, Shahidur R. and Baqui Khalily. 1995. "Designing a Sustainable Poverty Alleviation Program: The BRAC Strategy in Bangladesh." World Bank, Education and Social Policy Department. Washington, D.C., and Bangladesh Institute of Development Studies, Dhaka</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Khandker, Shahidur R. Baqui Khalily. and Zahed Khan 1993 ''Sustainability of Grameen Bank: What Do We Know ? World Bank. Education and Social Policy Department. Washington. D C, and Bangladesh Institute of Development Studies, Dhaka</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Khandker, Shahidur R., Victor Lavy, and D Filmer. 1994. Schooling and Cognitive in World Bank Discussion Paper 264. Washington. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Kumar, Shubh K. and David Hotchkiss. 1988 Consequences of Deforestation for Women's Time Allocation Agricultural Production and Nutrition in Hill Areas of Nepal International Food Policy Research Institute Research Report 69 Washington, D.C.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Kuzoets. Simon. 1955 Economic Growth and Income Inequalities." American Economic Review 45 (March): 1-28.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Lavy, Victor. 1992. Investment in Human Capital Schooling Supply in Rural Ghana Living Standards Measurement Study Working Paper 93 Washington, D C: World Bank.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">MacDonald, Martha. 1994. 'Panel Presentation at the Gender Symposium" World Bank. Poverty and Social Policy Department, Washington. D.C.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Manser Marilyn, and Murray Brown 1980 "Marriage and Household Decision making: A Bargaining Analysis " International Economic Review 21:11 44</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">McElroy, Marjorie, and Mary Jean Homey. 1981. "Nash-bargained Household Decisions: Towards a Generalisation of the Theory of Demand" International</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Economic Review 22 (June):333 49</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Moock, Peter R 1976 "The Efficiency of Women as Farm Managers: Kenya." American an Journal of Agricultural Economic 58(5):831-35.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Moser, Caroline O. 1992 "Adjustment from Below: Low-income Women, Time and the Triple Role in Guayaquil. Ecuador" In Haleh Ashar and Carolynne Dennis, eds., Women and Adjustment Policies in the Third World. New York: St. Martin Press</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">1994. "Urban Poverty and Social Policy in the Context of Adjustment" World Bank, Urban Development Division, Washington, D.C.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Mwabu, Germano. 1994 "Household Composition and Expenditures on Human Capital Inputs in Kenya" Presented at Northeast Universities Development Conference, Economic Growth Center Yale University, New Haven, Conn</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Newell, Andrew and Barry Reilly 1994. "Pine Gender Wage Gap in Russia. ' World Bank, Europe and Central Asia Country Department 3, Washington. D.C.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Pitt, Mark, and Shahidur Khandker. 1995 "Household and Intrahousehold Impacts of the Grameen Bank and Similar Targeted Credited Programs in Bangladesh " World Bank, Education and Social Policy Department, Washington. D.C.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Population Reference Bureau 1994. The Wood'. Youth 1994 A Special Focus on Reproductive Health Washington. D.C.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Psacharopoulos George 1994. "Returns to Investment in Education: A Global Up-date ' World Development 22(9):1325 43</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Psacharopoulos. George, and Zafiris Tzannatos. 1992 Women's Employment and PUN in Latin America Overview and Methodology. A World Bank Regional and Sectoral Study Washington, D.C.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Agnes. 1994. ''Improving Women's Agricultural Productivity as Farmers and Workers." Education and Social Policy Department Discussion Paper 37. World Bank, Washington. D C</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Rahrnan. Rushidan I. and Shahidur Khandker 1994 "Role of Targeted Credit Programs in Promoting Employment and Productivity of the Poor in Bangladesh." World Bank, Education and Social Policy Department. Washington, D.C. and Bangladesh Institute of Development Studies. Dhaka</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Rhyne, Elisabeth. and Sharon Holt 1994 ''Women in Finance and Enterprise Development'' Education and Social Policy Department Discussion Paper 40. World Bank. Washington, D.C.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Rosenzweig, Mark. and T. Paul Schultz. 1982 'Market Opportunities. Genetic Endowments, and Intrafamily Resource Distribution: Child Survival in Rural India'' American an Economic Review 72:4:803-15.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">. 1987. 'Fertility and Investments in Human Capital: Estimates of the Consequences of Imperfect Fertility Control in Malaysia.' Journal of Econometrics 36: 163-84</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Saito, Katrine, and Daphne Spurlirio 1992 Developing Agricultural Extension to/ Women Farmers World Bank Discussion Paper 156 Washington. D.C.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Scales, Ann 1986 "The Emergence of Feminist Jurisprudence'' Yale Law Journal 95(7): 1373-1403.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Schuler, Margaret, ed. 1986 Empowerment and the Law Strategies of Third World Women  Washington, D.C.: OEF</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Schuler, Margaret. and Sakuntala Kadirgamar-Rajasingilam. eds 1992 Legal Literary. A TOOL for Women's Empowerment New York: United Nations Development Fund for Women (UNIFEM)</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Schultz. T. Paul 1988 ''Education Investments and Returns'' In Hollis Chenery and T.R. Srinivasan. eds. Handbook of Development Economics Amsterdam: North land.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Sedlacek, Guilhemie, Leah Gutierrez, and Amit Mohindra 1993. "Women in the Labor Market" World Bank. Education and Social Policy Department Washington, D C</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Sen, Amartya 1990 'More Than One Hundred Million Women Are Missing: Women's Survival as a Development Problem." New York Review of Books (December 20):61-66.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Sivard, R L 1985. Women: A World Survey. Washington, D.C.: World Priorities</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Stewart, Sheelagh. 1992. ''Working the System: Sensitizing the Police to the Plight of Women " In Margaret Schuler. ed. Freedom from Violence e: Women Strategies from around the World. New York: United Nations Development Fund for Women (UNIFEM)</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Subbarao Kalanidlli. and Kene l Ezemenari Forthcoming "Transition. Poverty and Social Assistance in Mongolia.'' World Bank. Education and Social Policy Department Washington, D C</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Subbarao Kalanidhi. and Laura Raney 1993 Social Gains from Female Education: A Cross-National Stud!. World Bank Discussion Paper 194. Washington! D.C.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Summers, Lawrence H. 1994 Investing in All the People Education Women in Developing Countries ED' Seminar Paper 45 Washington, D.C: World Bank</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Thomas, Duncan 1990a "Household Resources and Child Health in Zimbabwe." Working Paper. Yale University, Economic Grow Center, New Haven, Conn.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">. 1990b Intrahousehold Resource Allocation: An Inferential Approach of Human Resources 25(4):635-64.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">. 1991 Gender Differences in household Resource Allocation. Living Standards Measurement Study Working Paper 79 Washington. D C: World Bank</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">. 1993. "The Distribution of Income and Expenditure within the Household." A Annals of Economics and Statistic 29: 109-35.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Tibaijuka, Anna 1994 ''Cost of Differential Gender Roles in African Agriculture: A Case Study of Smallholder Banana-Coffee Fames in the Kagera Region, Tanzania." Journal of Agricultural Economics (U K) 45(1):69-81</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Toubia, Nahid 1993. Female Genital Mutilation: A Call for Global Action. New York: United Nations</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Tzannatos, Zafiris 1995. "Growths, Adjustment, and the Labor Market: Effects on Women Workers." World Bank, Poverty and Social Policy Department, Washington. D.C.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">UNESCO (United Nations Educational, Scientific, and Cultural Organization). 1991. 1991. Paris</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">. 1993b Trends and Projections of Enrollment by Level of Education by Age and Sex, 1960-2025. Paris</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">UNICEF (United Nations Children's Fund! 1993. The Progress of Nations. New York</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">UNIDO (United Nations Industrial Development Organization). 1993 11 Women in Manu</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Other Recent Development in Practice Books</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Priorities and Strategies for Education: A World Bank Review (also available in French and Spanish)</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Better Urban Services: Finding the Right Incentives (also available in French and Spanish)</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Strengthening the Effectiveness of Aid: Lessons for Donors</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Enriching Lives: Overcoming Vitamin and Mineral Malnutrition in Developing Countries (also available in French and Spanish)</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">A New Agenda for Women's Health and Nutrition (also available in French)</P>
+<P ALIGN="JUSTIFY">Population and Development: Implications for the World Bank</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">East Asia's Trade and Investment: Regional and Global Gains from Liberalization</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Governance: The World Bank's Experience</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Higher Education: The Lessons of Experience (also available in French and Spanish)</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Better Health in Africa: Experience and Lessons Learned (also available in French)</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Argentina's Privatization Program: Experience, Issues, and Lessons Sustaining Rapid Development in East Asia and the Pacific</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">THE WORLD BANK A partner in strengthening economies and expanding markets to improve the quality of life for people everywhere, especially the poorest</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Gender equality is not only a matter of social justice but also good economics. It is of foremost importance to women's wellbeing and development. Discrimination means losses in productivity and lower welfare of women, their families, and society at large.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Although the gender gap is narrowing in education, health, and many other areas, women are still less educated than men, work more hours, and are paid less. The reasons why gender disparities persist are complex, having to do with social and institutional norms, relationships within households, and even lack of information about the benefits of educating and employing women. Despite the weight of social and cultural factors, public policy can influence women's status and well-being. Governments have a leading role in widening the opportunities available to women and extending the services that are vitally important to them.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">This report outlines what governments and development agencies can do to work toward greater gender equality- one of the best investments a society can make. Public policy can affect investments in health, education, and infrastructure through laws and regulations. It can also affect land ownership, financial services, and access to employment. Not least important, public  policies can affect macroeconomic performance and create a favorable climate for economic development.</P>
+<P ALIGN="JUSTIFY"></P></FONT></BODY>
+</HTML>
Index: /main/tags/2.25/gsdl/collect/modelcol/etc/collect.cfg
===================================================================
--- /main/tags/2.25/gsdl/collect/modelcol/etc/collect.cfg	(revision 21064)
+++ /main/tags/2.25/gsdl/collect/modelcol/etc/collect.cfg	(revision 21064)
@@ -0,0 +1,16 @@
+creator       **creator**
+maintainer    **maintainer**
+public        **public**
+beta          **beta**
+
+indexes        document:text
+defaultindex   document:text
+
+**plugins**
+
+classify       AZList metadata=Title
+
+collectionmeta collectionname    "**title**"
+collectionmeta iconcollection    ""
+collectionmeta collectionextra   "**about**"
+collectionmeta .document:text    "documents"
Index: /main/tags/2.25/gsdl/config.h.in
===================================================================
--- /main/tags/2.25/gsdl/config.h.in	(revision 21064)
+++ /main/tags/2.25/gsdl/config.h.in	(revision 21064)
@@ -0,0 +1,192 @@
+/* config.h.in.  Generated automatically from configure.in by autoheader.  */
+
+/* Define if on AIX 3.
+   System headers sometimes define this.
+   We just want to avoid a redefinition error message.  */
+#ifndef _ALL_SOURCE
+#undef _ALL_SOURCE
+#endif
+
+/* Define if using alloca.c.  */
+#undef C_ALLOCA
+
+/* Define to empty if the keyword does not work.  */
+#undef const
+
+/* Define to one of _getb67, GETB67, getb67 for Cray-2 and Cray-YMP systems.
+   This function is required for alloca.c support on those systems.  */
+#undef CRAY_STACKSEG_END
+
+/* Define if you have alloca, as a function or macro.  */
+#undef HAVE_ALLOCA
+
+/* Define if you have <alloca.h> and it should be used (not on Ultrix).  */
+#undef HAVE_ALLOCA_H
+
+/* Define if you don't have vprintf but do have _doprnt.  */
+#undef HAVE_DOPRNT
+
+/* Define if you have the vprintf function.  */
+#undef HAVE_VPRINTF
+
+/* Define if on MINIX.  */
+#undef _MINIX
+
+/* Define to `long' if <sys/types.h> doesn't define.  */
+#undef off_t
+
+/* Define if the system does not provide POSIX.1 features except
+   with this defined.  */
+#undef _POSIX_1_SOURCE
+
+/* Define if you need to in order for stat and other things to work.  */
+#undef _POSIX_SOURCE
+
+/* Define as the return type of signal handlers (int or void).  */
+#undef RETSIGTYPE
+
+/* Define to `unsigned' if <sys/types.h> doesn't define.  */
+#undef size_t
+
+/* If using the C implementation of alloca, define if you know the
+   direction of stack growth for your system; otherwise it will be
+   automatically deduced at run-time.
+ STACK_DIRECTION > 0 => grows toward higher addresses
+ STACK_DIRECTION < 0 => grows toward lower addresses
+ STACK_DIRECTION = 0 => direction of growth unknown
+ */
+#undef STACK_DIRECTION
+
+/* Define if you have the ANSI C header files.  */
+#undef STDC_HEADERS
+
+/* Define if you can safely include both <sys/time.h> and <time.h>.  */
+#undef TIME_WITH_SYS_TIME
+
+/* Define if your <sys/time.h> declares struct tm.  */
+#undef TM_IN_SYS_TIME
+
+/* Define to the name of the distribution.  */
+#undef PACKAGE
+
+/* Define to the version of the distribution.  */
+#undef VERSION
+
+/* Define to 1 if you have the valloc function.  */
+#undef HAVE_VALLOC
+
+/* Define to 1 if ANSI function prototypes are usable.  */
+#undef PROTOTYPES
+
+ 
+/* Define to 1 for better use of the debugging malloc library.  See
+   site ftp.antaire.com in antaire/src, file dmalloc/dmalloc.tar.gz.  */
+#undef WITH_DMALLOC
+
+ 
+/* Define to 1 if GNU regex should be used instead of GNU rx.  */
+#undef WITH_REGEX
+
+/* Some braindead header files do not have the requ'd function declarations */
+#undef HAVE_FGETC_DECL
+#undef HAVE_FREAD_DECL
+
+/* See if have this field in the prstatus_t structure */
+/* It stores the size of the process heap */
+#undef HAVE_PR_BRKSIZE
+
+/* Define FASTCGI if needsbe */
+#undef USE_FASTCGI
+
+/* Define if you have the ftime function.  */
+#undef HAVE_FTIME
+
+/* Define if you have the ftruncate function.  */
+#undef HAVE_FTRUNCATE
+
+/* Define if you have the getpagesize function.  */
+#undef HAVE_GETPAGESIZE
+
+/* Define if you have the getrusage function.  */
+#undef HAVE_GETRUSAGE
+
+/* Define if you have the mallinfo function.  */
+#undef HAVE_MALLINFO
+
+/* Define if you have the select function.  */
+#undef HAVE_SELECT
+
+/* Define if you have the setbuffer function.  */
+#undef HAVE_SETBUFFER
+
+/* Define if you have the strcasecmp function.  */
+#undef HAVE_STRCASECMP
+
+/* Define if you have the strerror function.  */
+#undef HAVE_STRERROR
+
+/* Define if you have the strftime function.  */
+#undef HAVE_STRFTIME
+
+/* Define if you have the strstr function.  */
+#undef HAVE_STRSTR
+
+/* Define if you have the strtol function.  */
+#undef HAVE_STRTOL
+
+/* Define if you have the times function.  */
+#undef HAVE_TIMES
+
+/* Define if you have the valloc function.  */
+#undef HAVE_VALLOC
+
+/* Define if you have the <crypt.h> header file.  */
+#undef HAVE_CRYPT_H
+
+/* Define if you have the <dirent.h> header file.  */
+#undef HAVE_DIRENT_H
+
+/* Define if you have the <fcntl.h> header file.  */
+#undef HAVE_FCNTL_H
+
+/* Define if you have the <limits.h> header file.  */
+#undef HAVE_LIMITS_H
+
+/* Define if you have the <memory.h> header file.  */
+#undef HAVE_MEMORY_H
+
+/* Define if you have the <ndir.h> header file.  */
+#undef HAVE_NDIR_H
+
+/* Define if you have the <string.h> header file.  */
+#undef HAVE_STRING_H
+
+/* Define if you have the <sys/dir.h> header file.  */
+#undef HAVE_SYS_DIR_H
+
+/* Define if you have the <sys/ndir.h> header file.  */
+#undef HAVE_SYS_NDIR_H
+
+/* Define if you have the <sys/procfs.h> header file.  */
+#undef HAVE_SYS_PROCFS_H
+
+/* Define if you have the <sys/time.h> header file.  */
+#undef HAVE_SYS_TIME_H
+
+/* Define if you have the <unistd.h> header file.  */
+#undef HAVE_UNISTD_H
+
+/* Define if you have the crypt library (-lcrypt).  */
+#undef HAVE_LIBCRYPT
+
+/* Define if you have the g library (-lg).  */
+#undef HAVE_LIBG
+
+/* Define if you have the gdbm library (-lgdbm).  */
+#undef HAVE_LIBGDBM
+
+/* Define if you have the m library (-lm).  */
+#undef HAVE_LIBM
+
+/* Define if you have the stdc++ library (-lstdc++).  */
+#undef HAVE_LIBSTDC__
Index: /main/tags/2.25/gsdl/configtest.pl
===================================================================
--- /main/tags/2.25/gsdl/configtest.pl	(revision 21064)
+++ /main/tags/2.25/gsdl/configtest.pl	(revision 21064)
@@ -0,0 +1,1 @@
+print $]
Index: /main/tags/2.25/gsdl/configure
===================================================================
--- /main/tags/2.25/gsdl/configure	(revision 21064)
+++ /main/tags/2.25/gsdl/configure	(revision 21064)
@@ -0,0 +1,3683 @@
+#! /bin/sh
+
+# Guess values for system-dependent variables and create Makefiles.
+# Generated automatically using autoconf version 2.13 
+# Copyright (C) 1992, 93, 94, 95, 96 Free Software Foundation, Inc.
+#
+# This configure script is free software; the Free Software Foundation
+# gives unlimited permission to copy, distribute and modify it.
+
+# Defaults:
+ac_help=
+ac_default_prefix=/usr/local
+# Any additions from configure.in:
+ac_help="$ac_help
+  --with-dmalloc          use dmalloc, as in
+                          ftp://ftp.letters.com/src/dmalloc/dmalloc.tar.gz"
+ac_help="$ac_help
+  --with-regex            use older regex in lieu of GNU rx for matching"
+ac_help="$ac_help
+  --with-dmalloc          use dmalloc, as in
+                          ftp://ftp.letters.com/src/dmalloc/dmalloc.tar.gz"
+ac_help="$ac_help
+  --with-regex            use older regex in lieu of GNU rx for matching"
+
+# Initialize some variables set by options.
+# The variables have the same names as the options, with
+# dashes changed to underlines.
+build=NONE
+cache_file=./config.cache
+exec_prefix=NONE
+host=NONE
+no_create=
+nonopt=NONE
+no_recursion=
+prefix=NONE
+program_prefix=NONE
+program_suffix=NONE
+program_transform_name=s,x,x,
+silent=
+site=
+srcdir=
+target=NONE
+verbose=
+x_includes=NONE
+x_libraries=NONE
+bindir='${exec_prefix}/bin'
+sbindir='${exec_prefix}/sbin'
+libexecdir='${exec_prefix}/libexec'
+datadir='${prefix}/share'
+sysconfdir='${prefix}/etc'
+sharedstatedir='${prefix}/com'
+localstatedir='${prefix}/var'
+libdir='${exec_prefix}/lib'
+includedir='${prefix}/include'
+oldincludedir='/usr/include'
+infodir='${prefix}/info'
+mandir='${prefix}/man'
+
+# Initialize some other variables.
+subdirs=
+MFLAGS= MAKEFLAGS=
+SHELL=${CONFIG_SHELL-/bin/sh}
+# Maximum number of lines to put in a shell here document.
+ac_max_here_lines=12
+
+ac_prev=
+for ac_option
+do
+
+  # If the previous option needs an argument, assign it.
+  if test -n "$ac_prev"; then
+    eval "$ac_prev=\$ac_option"
+    ac_prev=
+    continue
+  fi
+
+  case "$ac_option" in
+  -*=*) ac_optarg=`echo "$ac_option" | sed 's/[-_a-zA-Z0-9]*=//'` ;;
+  *) ac_optarg= ;;
+  esac
+
+  # Accept the important Cygnus configure options, so we can diagnose typos.
+
+  case "$ac_option" in
+
+  -bindir | --bindir | --bindi | --bind | --bin | --bi)
+    ac_prev=bindir ;;
+  -bindir=* | --bindir=* | --bindi=* | --bind=* | --bin=* | --bi=*)
+    bindir="$ac_optarg" ;;
+
+  -build | --build | --buil | --bui | --bu)
+    ac_prev=build ;;
+  -build=* | --build=* | --buil=* | --bui=* | --bu=*)
+    build="$ac_optarg" ;;
+
+  -cache-file | --cache-file | --cache-fil | --cache-fi \
+  | --cache-f | --cache- | --cache | --cach | --cac | --ca | --c)
+    ac_prev=cache_file ;;
+  -cache-file=* | --cache-file=* | --cache-fil=* | --cache-fi=* \
+  | --cache-f=* | --cache-=* | --cache=* | --cach=* | --cac=* | --ca=* | --c=*)
+    cache_file="$ac_optarg" ;;
+
+  -datadir | --datadir | --datadi | --datad | --data | --dat | --da)
+    ac_prev=datadir ;;
+  -datadir=* | --datadir=* | --datadi=* | --datad=* | --data=* | --dat=* \
+  | --da=*)
+    datadir="$ac_optarg" ;;
+
+  -disable-* | --disable-*)
+    ac_feature=`echo $ac_option|sed -e 's/-*disable-//'`
+    # Reject names that are not valid shell variable names.
+    if test -n "`echo $ac_feature| sed 's/[-a-zA-Z0-9_]//g'`"; then
+      { echo "configure: error: $ac_feature: invalid feature name" 1>&2; exit 1; }
+    fi
+    ac_feature=`echo $ac_feature| sed 's/-/_/g'`
+    eval "enable_${ac_feature}=no" ;;
+
+  -enable-* | --enable-*)
+    ac_feature=`echo $ac_option|sed -e 's/-*enable-//' -e 's/=.*//'`
+    # Reject names that are not valid shell variable names.
+    if test -n "`echo $ac_feature| sed 's/[-_a-zA-Z0-9]//g'`"; then
+      { echo "configure: error: $ac_feature: invalid feature name" 1>&2; exit 1; }
+    fi
+    ac_feature=`echo $ac_feature| sed 's/-/_/g'`
+    case "$ac_option" in
+      *=*) ;;
+      *) ac_optarg=yes ;;
+    esac
+    eval "enable_${ac_feature}='$ac_optarg'" ;;
+
+  -exec-prefix | --exec_prefix | --exec-prefix | --exec-prefi \
+  | --exec-pref | --exec-pre | --exec-pr | --exec-p | --exec- \
+  | --exec | --exe | --ex)
+    ac_prev=exec_prefix ;;
+  -exec-prefix=* | --exec_prefix=* | --exec-prefix=* | --exec-prefi=* \
+  | --exec-pref=* | --exec-pre=* | --exec-pr=* | --exec-p=* | --exec-=* \
+  | --exec=* | --exe=* | --ex=*)
+    exec_prefix="$ac_optarg" ;;
+
+  -gas | --gas | --ga | --g)
+    # Obsolete; use --with-gas.
+    with_gas=yes ;;
+
+  -help | --help | --hel | --he)
+    # Omit some internal or obsolete options to make the list less imposing.
+    # This message is too long to be a string in the A/UX 3.1 sh.
+    cat << EOF
+Usage: configure [options] [host]
+Options: [defaults in brackets after descriptions]
+Configuration:
+  --cache-file=FILE       cache test results in FILE
+  --help                  print this message
+  --no-create             do not create output files
+  --quiet, --silent       do not print \`checking...' messages
+  --version               print the version of autoconf that created configure
+Directory and file names:
+  --prefix=PREFIX         install architecture-independent files in PREFIX
+                          [$ac_default_prefix]
+  --exec-prefix=EPREFIX   install architecture-dependent files in EPREFIX
+                          [same as prefix]
+  --bindir=DIR            user executables in DIR [EPREFIX/bin]
+  --sbindir=DIR           system admin executables in DIR [EPREFIX/sbin]
+  --libexecdir=DIR        program executables in DIR [EPREFIX/libexec]
+  --datadir=DIR           read-only architecture-independent data in DIR
+                          [PREFIX/share]
+  --sysconfdir=DIR        read-only single-machine data in DIR [PREFIX/etc]
+  --sharedstatedir=DIR    modifiable architecture-independent data in DIR
+                          [PREFIX/com]
+  --localstatedir=DIR     modifiable single-machine data in DIR [PREFIX/var]
+  --libdir=DIR            object code libraries in DIR [EPREFIX/lib]
+  --includedir=DIR        C header files in DIR [PREFIX/include]
+  --oldincludedir=DIR     C header files for non-gcc in DIR [/usr/include]
+  --infodir=DIR           info documentation in DIR [PREFIX/info]
+  --mandir=DIR            man documentation in DIR [PREFIX/man]
+  --srcdir=DIR            find the sources in DIR [configure dir or ..]
+  --program-prefix=PREFIX prepend PREFIX to installed program names
+  --program-suffix=SUFFIX append SUFFIX to installed program names
+  --program-transform-name=PROGRAM
+                          run sed PROGRAM on installed program names
+EOF
+    cat << EOF
+Host type:
+  --build=BUILD           configure for building on BUILD [BUILD=HOST]
+  --host=HOST             configure for HOST [guessed]
+  --target=TARGET         configure for TARGET [TARGET=HOST]
+Features and packages:
+  --disable-FEATURE       do not include FEATURE (same as --enable-FEATURE=no)
+  --enable-FEATURE[=ARG]  include FEATURE [ARG=yes]
+  --with-PACKAGE[=ARG]    use PACKAGE [ARG=yes]
+  --without-PACKAGE       do not use PACKAGE (same as --with-PACKAGE=no)
+  --x-includes=DIR        X include files are in DIR
+  --x-libraries=DIR       X library files are in DIR
+EOF
+    if test -n "$ac_help"; then
+      echo "--enable and --with options recognized:$ac_help"
+    fi
+    exit 0 ;;
+
+  -host | --host | --hos | --ho)
+    ac_prev=host ;;
+  -host=* | --host=* | --hos=* | --ho=*)
+    host="$ac_optarg" ;;
+
+  -includedir | --includedir | --includedi | --included | --include \
+  | --includ | --inclu | --incl | --inc)
+    ac_prev=includedir ;;
+  -includedir=* | --includedir=* | --includedi=* | --included=* | --include=* \
+  | --includ=* | --inclu=* | --incl=* | --inc=*)
+    includedir="$ac_optarg" ;;
+
+  -infodir | --infodir | --infodi | --infod | --info | --inf)
+    ac_prev=infodir ;;
+  -infodir=* | --infodir=* | --infodi=* | --infod=* | --info=* | --inf=*)
+    infodir="$ac_optarg" ;;
+
+  -libdir | --libdir | --libdi | --libd)
+    ac_prev=libdir ;;
+  -libdir=* | --libdir=* | --libdi=* | --libd=*)
+    libdir="$ac_optarg" ;;
+
+  -libexecdir | --libexecdir | --libexecdi | --libexecd | --libexec \
+  | --libexe | --libex | --libe)
+    ac_prev=libexecdir ;;
+  -libexecdir=* | --libexecdir=* | --libexecdi=* | --libexecd=* | --libexec=* \
+  | --libexe=* | --libex=* | --libe=*)
+    libexecdir="$ac_optarg" ;;
+
+  -localstatedir | --localstatedir | --localstatedi | --localstated \
+  | --localstate | --localstat | --localsta | --localst \
+  | --locals | --local | --loca | --loc | --lo)
+    ac_prev=localstatedir ;;
+  -localstatedir=* | --localstatedir=* | --localstatedi=* | --localstated=* \
+  | --localstate=* | --localstat=* | --localsta=* | --localst=* \
+  | --locals=* | --local=* | --loca=* | --loc=* | --lo=*)
+    localstatedir="$ac_optarg" ;;
+
+  -mandir | --mandir | --mandi | --mand | --man | --ma | --m)
+    ac_prev=mandir ;;
+  -mandir=* | --mandir=* | --mandi=* | --mand=* | --man=* | --ma=* | --m=*)
+    mandir="$ac_optarg" ;;
+
+  -nfp | --nfp | --nf)
+    # Obsolete; use --without-fp.
+    with_fp=no ;;
+
+  -no-create | --no-create | --no-creat | --no-crea | --no-cre \
+  | --no-cr | --no-c)
+    no_create=yes ;;
+
+  -no-recursion | --no-recursion | --no-recursio | --no-recursi \
+  | --no-recurs | --no-recur | --no-recu | --no-rec | --no-re | --no-r)
+    no_recursion=yes ;;
+
+  -oldincludedir | --oldincludedir | --oldincludedi | --oldincluded \
+  | --oldinclude | --oldinclud | --oldinclu | --oldincl | --oldinc \
+  | --oldin | --oldi | --old | --ol | --o)
+    ac_prev=oldincludedir ;;
+  -oldincludedir=* | --oldincludedir=* | --oldincludedi=* | --oldincluded=* \
+  | --oldinclude=* | --oldinclud=* | --oldinclu=* | --oldincl=* | --oldinc=* \
+  | --oldin=* | --oldi=* | --old=* | --ol=* | --o=*)
+    oldincludedir="$ac_optarg" ;;
+
+  -prefix | --prefix | --prefi | --pref | --pre | --pr | --p)
+    ac_prev=prefix ;;
+  -prefix=* | --prefix=* | --prefi=* | --pref=* | --pre=* | --pr=* | --p=*)
+    prefix="$ac_optarg" ;;
+
+  -program-prefix | --program-prefix | --program-prefi | --program-pref \
+  | --program-pre | --program-pr | --program-p)
+    ac_prev=program_prefix ;;
+  -program-prefix=* | --program-prefix=* | --program-prefi=* \
+  | --program-pref=* | --program-pre=* | --program-pr=* | --program-p=*)
+    program_prefix="$ac_optarg" ;;
+
+  -program-suffix | --program-suffix | --program-suffi | --program-suff \
+  | --program-suf | --program-su | --program-s)
+    ac_prev=program_suffix ;;
+  -program-suffix=* | --program-suffix=* | --program-suffi=* \
+  | --program-suff=* | --program-suf=* | --program-su=* | --program-s=*)
+    program_suffix="$ac_optarg" ;;
+
+  -program-transform-name | --program-transform-name \
+  | --program-transform-nam | --program-transform-na \
+  | --program-transform-n | --program-transform- \
+  | --program-transform | --program-transfor \
+  | --program-transfo | --program-transf \
+  | --program-trans | --program-tran \
+  | --progr-tra | --program-tr | --program-t)
+    ac_prev=program_transform_name ;;
+  -program-transform-name=* | --program-transform-name=* \
+  | --program-transform-nam=* | --program-transform-na=* \
+  | --program-transform-n=* | --program-transform-=* \
+  | --program-transform=* | --program-transfor=* \
+  | --program-transfo=* | --program-transf=* \
+  | --program-trans=* | --program-tran=* \
+  | --progr-tra=* | --program-tr=* | --program-t=*)
+    program_transform_name="$ac_optarg" ;;
+
+  -q | -quiet | --quiet | --quie | --qui | --qu | --q \
+  | -silent | --silent | --silen | --sile | --sil)
+    silent=yes ;;
+
+  -sbindir | --sbindir | --sbindi | --sbind | --sbin | --sbi | --sb)
+    ac_prev=sbindir ;;
+  -sbindir=* | --sbindir=* | --sbindi=* | --sbind=* | --sbin=* \
+  | --sbi=* | --sb=*)
+    sbindir="$ac_optarg" ;;
+
+  -sharedstatedir | --sharedstatedir | --sharedstatedi \
+  | --sharedstated | --sharedstate | --sharedstat | --sharedsta \
+  | --sharedst | --shareds | --shared | --share | --shar \
+  | --sha | --sh)
+    ac_prev=sharedstatedir ;;
+  -sharedstatedir=* | --sharedstatedir=* | --sharedstatedi=* \
+  | --sharedstated=* | --sharedstate=* | --sharedstat=* | --sharedsta=* \
+  | --sharedst=* | --shareds=* | --shared=* | --share=* | --shar=* \
+  | --sha=* | --sh=*)
+    sharedstatedir="$ac_optarg" ;;
+
+  -site | --site | --sit)
+    ac_prev=site ;;
+  -site=* | --site=* | --sit=*)
+    site="$ac_optarg" ;;
+
+  -srcdir | --srcdir | --srcdi | --srcd | --src | --sr)
+    ac_prev=srcdir ;;
+  -srcdir=* | --srcdir=* | --srcdi=* | --srcd=* | --src=* | --sr=*)
+    srcdir="$ac_optarg" ;;
+
+  -sysconfdir | --sysconfdir | --sysconfdi | --sysconfd | --sysconf \
+  | --syscon | --sysco | --sysc | --sys | --sy)
+    ac_prev=sysconfdir ;;
+  -sysconfdir=* | --sysconfdir=* | --sysconfdi=* | --sysconfd=* | --sysconf=* \
+  | --syscon=* | --sysco=* | --sysc=* | --sys=* | --sy=*)
+    sysconfdir="$ac_optarg" ;;
+
+  -target | --target | --targe | --targ | --tar | --ta | --t)
+    ac_prev=target ;;
+  -target=* | --target=* | --targe=* | --targ=* | --tar=* | --ta=* | --t=*)
+    target="$ac_optarg" ;;
+
+  -v | -verbose | --verbose | --verbos | --verbo | --verb)
+    verbose=yes ;;
+
+  -version | --version | --versio | --versi | --vers)
+    echo "configure generated by autoconf version 2.13"
+    exit 0 ;;
+
+  -with-* | --with-*)
+    ac_package=`echo $ac_option|sed -e 's/-*with-//' -e 's/=.*//'`
+    # Reject names that are not valid shell variable names.
+    if test -n "`echo $ac_package| sed 's/[-_a-zA-Z0-9]//g'`"; then
+      { echo "configure: error: $ac_package: invalid package name" 1>&2; exit 1; }
+    fi
+    ac_package=`echo $ac_package| sed 's/-/_/g'`
+    case "$ac_option" in
+      *=*) ;;
+      *) ac_optarg=yes ;;
+    esac
+    eval "with_${ac_package}='$ac_optarg'" ;;
+
+  -without-* | --without-*)
+    ac_package=`echo $ac_option|sed -e 's/-*without-//'`
+    # Reject names that are not valid shell variable names.
+    if test -n "`echo $ac_package| sed 's/[-a-zA-Z0-9_]//g'`"; then
+      { echo "configure: error: $ac_package: invalid package name" 1>&2; exit 1; }
+    fi
+    ac_package=`echo $ac_package| sed 's/-/_/g'`
+    eval "with_${ac_package}=no" ;;
+
+  --x)
+    # Obsolete; use --with-x.
+    with_x=yes ;;
+
+  -x-includes | --x-includes | --x-include | --x-includ | --x-inclu \
+  | --x-incl | --x-inc | --x-in | --x-i)
+    ac_prev=x_includes ;;
+  -x-includes=* | --x-includes=* | --x-include=* | --x-includ=* | --x-inclu=* \
+  | --x-incl=* | --x-inc=* | --x-in=* | --x-i=*)
+    x_includes="$ac_optarg" ;;
+
+  -x-libraries | --x-libraries | --x-librarie | --x-librari \
+  | --x-librar | --x-libra | --x-libr | --x-lib | --x-li | --x-l)
+    ac_prev=x_libraries ;;
+  -x-libraries=* | --x-libraries=* | --x-librarie=* | --x-librari=* \
+  | --x-librar=* | --x-libra=* | --x-libr=* | --x-lib=* | --x-li=* | --x-l=*)
+    x_libraries="$ac_optarg" ;;
+
+  -*) { echo "configure: error: $ac_option: invalid option; use --help to show usage" 1>&2; exit 1; }
+    ;;
+
+  *)
+    if test -n "`echo $ac_option| sed 's/[-a-z0-9.]//g'`"; then
+      echo "configure: warning: $ac_option: invalid host type" 1>&2
+    fi
+    if test "x$nonopt" != xNONE; then
+      { echo "configure: error: can only configure for one host and one target at a time" 1>&2; exit 1; }
+    fi
+    nonopt="$ac_option"
+    ;;
+
+  esac
+done
+
+if test -n "$ac_prev"; then
+  { echo "configure: error: missing argument to --`echo $ac_prev | sed 's/_/-/g'`" 1>&2; exit 1; }
+fi
+
+trap 'rm -fr conftest* confdefs* core core.* *.core $ac_clean_files; exit 1' 1 2 15
+
+# File descriptor usage:
+# 0 standard input
+# 1 file creation
+# 2 errors and warnings
+# 3 some systems may open it to /dev/tty
+# 4 used on the Kubota Titan
+# 6 checking for... messages and results
+# 5 compiler messages saved in config.log
+if test "$silent" = yes; then
+  exec 6>/dev/null
+else
+  exec 6>&1
+fi
+exec 5>./config.log
+
+echo "\
+This file contains any messages produced by compilers while
+running configure, to aid debugging if configure makes a mistake.
+" 1>&5
+
+# Strip out --no-create and --no-recursion so they do not pile up.
+# Also quote any args containing shell metacharacters.
+ac_configure_args=
+for ac_arg
+do
+  case "$ac_arg" in
+  -no-create | --no-create | --no-creat | --no-crea | --no-cre \
+  | --no-cr | --no-c) ;;
+  -no-recursion | --no-recursion | --no-recursio | --no-recursi \
+  | --no-recurs | --no-recur | --no-recu | --no-rec | --no-re | --no-r) ;;
+  *" "*|*"	"*|*[\[\]\~\#\$\^\&\*\(\)\{\}\\\|\;\<\>\?]*)
+  ac_configure_args="$ac_configure_args '$ac_arg'" ;;
+  *) ac_configure_args="$ac_configure_args $ac_arg" ;;
+  esac
+done
+
+# NLS nuisances.
+# Only set these to C if already set.  These must not be set unconditionally
+# because not all systems understand e.g. LANG=C (notably SCO).
+# Fixing LC_MESSAGES prevents Solaris sh from translating var values in `set'!
+# Non-C LC_CTYPE values break the ctype check.
+if test "${LANG+set}"   = set; then LANG=C;   export LANG;   fi
+if test "${LC_ALL+set}" = set; then LC_ALL=C; export LC_ALL; fi
+if test "${LC_MESSAGES+set}" = set; then LC_MESSAGES=C; export LC_MESSAGES; fi
+if test "${LC_CTYPE+set}"    = set; then LC_CTYPE=C;    export LC_CTYPE;    fi
+
+# confdefs.h avoids OS command line length limits that DEFS can exceed.
+rm -rf conftest* confdefs.h
+# AIX cpp loses on an empty file, so make sure it contains at least a newline.
+echo > confdefs.h
+
+# A filename unique to this package, relative to the directory that
+# configure is in, which we can look for to find out if srcdir is correct.
+ac_unique_file=lib/text_t.h
+
+# Find the source files, if location was not specified.
+if test -z "$srcdir"; then
+  ac_srcdir_defaulted=yes
+  # Try the directory containing this script, then its parent.
+  ac_prog=$0
+  ac_confdir=`echo $ac_prog|sed 's%/[^/][^/]*$%%'`
+  test "x$ac_confdir" = "x$ac_prog" && ac_confdir=.
+  srcdir=$ac_confdir
+  if test ! -r $srcdir/$ac_unique_file; then
+    srcdir=..
+  fi
+else
+  ac_srcdir_defaulted=no
+fi
+if test ! -r $srcdir/$ac_unique_file; then
+  if test "$ac_srcdir_defaulted" = yes; then
+    { echo "configure: error: can not find sources in $ac_confdir or .." 1>&2; exit 1; }
+  else
+    { echo "configure: error: can not find sources in $srcdir" 1>&2; exit 1; }
+  fi
+fi
+srcdir=`echo "${srcdir}" | sed 's%\([^/]\)/*$%\1%'`
+
+# Prefer explicitly selected file to automatically selected ones.
+if test -z "$CONFIG_SITE"; then
+  if test "x$prefix" != xNONE; then
+    CONFIG_SITE="$prefix/share/config.site $prefix/etc/config.site"
+  else
+    CONFIG_SITE="$ac_default_prefix/share/config.site $ac_default_prefix/etc/config.site"
+  fi
+fi
+for ac_site_file in $CONFIG_SITE; do
+  if test -r "$ac_site_file"; then
+    echo "loading site script $ac_site_file"
+    . "$ac_site_file"
+  fi
+done
+
+if test -r "$cache_file"; then
+  echo "loading cache $cache_file"
+  . $cache_file
+else
+  echo "creating cache $cache_file"
+  > $cache_file
+fi
+
+ac_ext=c
+# CFLAGS is not in ac_cpp because -g, -O, etc. are not valid cpp options.
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='${CC-cc} -c $CFLAGS $CPPFLAGS conftest.$ac_ext 1>&5'
+ac_link='${CC-cc} -o conftest${ac_exeext} $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS 1>&5'
+cross_compiling=$ac_cv_prog_cc_cross
+
+ac_exeext=
+ac_objext=o
+if (echo "testing\c"; echo 1,2,3) | grep c >/dev/null; then
+  # Stardent Vistra SVR4 grep lacks -e, says ghazi@caip.rutgers.edu.
+  if (echo -n testing; echo 1,2,3) | sed s/-n/xn/ | grep xn >/dev/null; then
+    ac_n= ac_c='
+' ac_t='	'
+  else
+    ac_n=-n ac_c= ac_t=
+  fi
+else
+  ac_n= ac_c='\c' ac_t=
+fi
+
+
+
+if test "$program_transform_name" = s,x,x,; then
+  program_transform_name=
+else
+  # Double any \ or $.  echo might interpret backslashes.
+  cat <<\EOF_SED > conftestsed
+s,\\,\\\\,g; s,\$,$$,g
+EOF_SED
+  program_transform_name="`echo $program_transform_name|sed -f conftestsed`"
+  rm -f conftestsed
+fi
+test "$program_prefix" != NONE &&
+  program_transform_name="s,^,${program_prefix},; $program_transform_name"
+# Use a double $ so make ignores it.
+test "$program_suffix" != NONE &&
+  program_transform_name="s,\$\$,${program_suffix},; $program_transform_name"
+
+# sed with no file args requires a program.
+test "$program_transform_name" = "" && program_transform_name="s,x,x,"
+
+
+PACKAGE=gsdl
+VERSION=2.1
+cat >> confdefs.h <<EOF
+#define PACKAGE "$PACKAGE"
+EOF
+
+cat >> confdefs.h <<EOF
+#define VERSION "$VERSION"
+EOF
+
+
+
+
+USE_FASTCGI=0
+if test USE_FASTCGI = 1; then
+cat >> confdefs.h <<\EOF
+#define USE_FASTCGI 1
+EOF
+
+
+fi
+
+LDFLAGS=
+CFLAGS=-O2
+
+
+# Extract the first word of "gcc", so it can be a program name with args.
+set dummy gcc; ac_word=$2
+echo $ac_n "checking for $ac_word""... $ac_c" 1>&6
+echo "configure:585: checking for $ac_word" >&5
+if eval "test \"`echo '$''{'ac_cv_prog_CC'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  if test -n "$CC"; then
+  ac_cv_prog_CC="$CC" # Let the user override the test.
+else
+  IFS="${IFS= 	}"; ac_save_ifs="$IFS"; IFS=":"
+  ac_dummy="$PATH"
+  for ac_dir in $ac_dummy; do
+    test -z "$ac_dir" && ac_dir=.
+    if test -f $ac_dir/$ac_word; then
+      ac_cv_prog_CC="gcc"
+      break
+    fi
+  done
+  IFS="$ac_save_ifs"
+fi
+fi
+CC="$ac_cv_prog_CC"
+if test -n "$CC"; then
+  echo "$ac_t""$CC" 1>&6
+else
+  echo "$ac_t""no" 1>&6
+fi
+
+if test -z "$CC"; then
+  # Extract the first word of "cc", so it can be a program name with args.
+set dummy cc; ac_word=$2
+echo $ac_n "checking for $ac_word""... $ac_c" 1>&6
+echo "configure:615: checking for $ac_word" >&5
+if eval "test \"`echo '$''{'ac_cv_prog_CC'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  if test -n "$CC"; then
+  ac_cv_prog_CC="$CC" # Let the user override the test.
+else
+  IFS="${IFS= 	}"; ac_save_ifs="$IFS"; IFS=":"
+  ac_prog_rejected=no
+  ac_dummy="$PATH"
+  for ac_dir in $ac_dummy; do
+    test -z "$ac_dir" && ac_dir=.
+    if test -f $ac_dir/$ac_word; then
+      if test "$ac_dir/$ac_word" = "/usr/ucb/cc"; then
+        ac_prog_rejected=yes
+	continue
+      fi
+      ac_cv_prog_CC="cc"
+      break
+    fi
+  done
+  IFS="$ac_save_ifs"
+if test $ac_prog_rejected = yes; then
+  # We found a bogon in the path, so make sure we never use it.
+  set dummy $ac_cv_prog_CC
+  shift
+  if test $# -gt 0; then
+    # We chose a different compiler from the bogus one.
+    # However, it has the same basename, so the bogon will be chosen
+    # first if we set CC to just the basename; use the full file name.
+    shift
+    set dummy "$ac_dir/$ac_word" "$@"
+    shift
+    ac_cv_prog_CC="$@"
+  fi
+fi
+fi
+fi
+CC="$ac_cv_prog_CC"
+if test -n "$CC"; then
+  echo "$ac_t""$CC" 1>&6
+else
+  echo "$ac_t""no" 1>&6
+fi
+
+  if test -z "$CC"; then
+    case "`uname -s`" in
+    *win32* | *WIN32*)
+      # Extract the first word of "cl", so it can be a program name with args.
+set dummy cl; ac_word=$2
+echo $ac_n "checking for $ac_word""... $ac_c" 1>&6
+echo "configure:666: checking for $ac_word" >&5
+if eval "test \"`echo '$''{'ac_cv_prog_CC'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  if test -n "$CC"; then
+  ac_cv_prog_CC="$CC" # Let the user override the test.
+else
+  IFS="${IFS= 	}"; ac_save_ifs="$IFS"; IFS=":"
+  ac_dummy="$PATH"
+  for ac_dir in $ac_dummy; do
+    test -z "$ac_dir" && ac_dir=.
+    if test -f $ac_dir/$ac_word; then
+      ac_cv_prog_CC="cl"
+      break
+    fi
+  done
+  IFS="$ac_save_ifs"
+fi
+fi
+CC="$ac_cv_prog_CC"
+if test -n "$CC"; then
+  echo "$ac_t""$CC" 1>&6
+else
+  echo "$ac_t""no" 1>&6
+fi
+ ;;
+    esac
+  fi
+  test -z "$CC" && { echo "configure: error: no acceptable cc found in \$PATH" 1>&2; exit 1; }
+fi
+
+echo $ac_n "checking whether the C compiler ($CC $CFLAGS $LDFLAGS) works""... $ac_c" 1>&6
+echo "configure:698: checking whether the C compiler ($CC $CFLAGS $LDFLAGS) works" >&5
+
+ac_ext=c
+# CFLAGS is not in ac_cpp because -g, -O, etc. are not valid cpp options.
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='${CC-cc} -c $CFLAGS $CPPFLAGS conftest.$ac_ext 1>&5'
+ac_link='${CC-cc} -o conftest${ac_exeext} $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS 1>&5'
+cross_compiling=$ac_cv_prog_cc_cross
+
+cat > conftest.$ac_ext << EOF
+
+#line 709 "configure"
+#include "confdefs.h"
+
+main(){return(0);}
+EOF
+if { (eval echo configure:714: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+  ac_cv_prog_cc_works=yes
+  # If we can't run a trivial program, we are probably using a cross compiler.
+  if (./conftest; exit) 2>/dev/null; then
+    ac_cv_prog_cc_cross=no
+  else
+    ac_cv_prog_cc_cross=yes
+  fi
+else
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  ac_cv_prog_cc_works=no
+fi
+rm -fr conftest*
+ac_ext=c
+# CFLAGS is not in ac_cpp because -g, -O, etc. are not valid cpp options.
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='${CC-cc} -c $CFLAGS $CPPFLAGS conftest.$ac_ext 1>&5'
+ac_link='${CC-cc} -o conftest${ac_exeext} $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS 1>&5'
+cross_compiling=$ac_cv_prog_cc_cross
+
+echo "$ac_t""$ac_cv_prog_cc_works" 1>&6
+if test $ac_cv_prog_cc_works = no; then
+  { echo "configure: error: installation or configuration problem: C compiler cannot create executables." 1>&2; exit 1; }
+fi
+echo $ac_n "checking whether the C compiler ($CC $CFLAGS $LDFLAGS) is a cross-compiler""... $ac_c" 1>&6
+echo "configure:740: checking whether the C compiler ($CC $CFLAGS $LDFLAGS) is a cross-compiler" >&5
+echo "$ac_t""$ac_cv_prog_cc_cross" 1>&6
+cross_compiling=$ac_cv_prog_cc_cross
+
+echo $ac_n "checking whether we are using GNU C""... $ac_c" 1>&6
+echo "configure:745: checking whether we are using GNU C" >&5
+if eval "test \"`echo '$''{'ac_cv_prog_gcc'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  cat > conftest.c <<EOF
+#ifdef __GNUC__
+  yes;
+#endif
+EOF
+if { ac_try='${CC-cc} -E conftest.c'; { (eval echo configure:754: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }; } | egrep yes >/dev/null 2>&1; then
+  ac_cv_prog_gcc=yes
+else
+  ac_cv_prog_gcc=no
+fi
+fi
+
+echo "$ac_t""$ac_cv_prog_gcc" 1>&6
+
+if test $ac_cv_prog_gcc = yes; then
+  GCC=yes
+else
+  GCC=
+fi
+
+ac_test_CFLAGS="${CFLAGS+set}"
+ac_save_CFLAGS="$CFLAGS"
+CFLAGS=
+echo $ac_n "checking whether ${CC-cc} accepts -g""... $ac_c" 1>&6
+echo "configure:773: checking whether ${CC-cc} accepts -g" >&5
+if eval "test \"`echo '$''{'ac_cv_prog_cc_g'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  echo 'void f(){}' > conftest.c
+if test -z "`${CC-cc} -g -c conftest.c 2>&1`"; then
+  ac_cv_prog_cc_g=yes
+else
+  ac_cv_prog_cc_g=no
+fi
+rm -f conftest*
+
+fi
+
+echo "$ac_t""$ac_cv_prog_cc_g" 1>&6
+if test "$ac_test_CFLAGS" = set; then
+  CFLAGS="$ac_save_CFLAGS"
+elif test $ac_cv_prog_cc_g = yes; then
+  if test "$GCC" = yes; then
+    CFLAGS="-g -O2"
+  else
+    CFLAGS="-g"
+  fi
+else
+  if test "$GCC" = yes; then
+    CFLAGS="-O2"
+  else
+    CFLAGS=
+  fi
+fi
+
+for ac_prog in $CCC c++ g++ gcc CC cxx cc++ cl
+do
+# Extract the first word of "$ac_prog", so it can be a program name with args.
+set dummy $ac_prog; ac_word=$2
+echo $ac_n "checking for $ac_word""... $ac_c" 1>&6
+echo "configure:809: checking for $ac_word" >&5
+if eval "test \"`echo '$''{'ac_cv_prog_CXX'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  if test -n "$CXX"; then
+  ac_cv_prog_CXX="$CXX" # Let the user override the test.
+else
+  IFS="${IFS= 	}"; ac_save_ifs="$IFS"; IFS=":"
+  ac_dummy="$PATH"
+  for ac_dir in $ac_dummy; do
+    test -z "$ac_dir" && ac_dir=.
+    if test -f $ac_dir/$ac_word; then
+      ac_cv_prog_CXX="$ac_prog"
+      break
+    fi
+  done
+  IFS="$ac_save_ifs"
+fi
+fi
+CXX="$ac_cv_prog_CXX"
+if test -n "$CXX"; then
+  echo "$ac_t""$CXX" 1>&6
+else
+  echo "$ac_t""no" 1>&6
+fi
+
+test -n "$CXX" && break
+done
+test -n "$CXX" || CXX="gcc"
+
+
+echo $ac_n "checking whether the C++ compiler ($CXX $CXXFLAGS $LDFLAGS) works""... $ac_c" 1>&6
+echo "configure:841: checking whether the C++ compiler ($CXX $CXXFLAGS $LDFLAGS) works" >&5
+
+ac_ext=C
+# CXXFLAGS is not in ac_cpp because -g, -O, etc. are not valid cpp options.
+ac_cpp='$CXXCPP $CPPFLAGS'
+ac_compile='${CXX-g++} -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext 1>&5'
+ac_link='${CXX-g++} -o conftest${ac_exeext} $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS 1>&5'
+cross_compiling=$ac_cv_prog_cxx_cross
+
+cat > conftest.$ac_ext << EOF
+
+#line 852 "configure"
+#include "confdefs.h"
+
+int main(){return(0);}
+EOF
+if { (eval echo configure:857: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+  ac_cv_prog_cxx_works=yes
+  # If we can't run a trivial program, we are probably using a cross compiler.
+  if (./conftest; exit) 2>/dev/null; then
+    ac_cv_prog_cxx_cross=no
+  else
+    ac_cv_prog_cxx_cross=yes
+  fi
+else
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  ac_cv_prog_cxx_works=no
+fi
+rm -fr conftest*
+ac_ext=c
+# CFLAGS is not in ac_cpp because -g, -O, etc. are not valid cpp options.
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='${CC-cc} -c $CFLAGS $CPPFLAGS conftest.$ac_ext 1>&5'
+ac_link='${CC-cc} -o conftest${ac_exeext} $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS 1>&5'
+cross_compiling=$ac_cv_prog_cc_cross
+
+echo "$ac_t""$ac_cv_prog_cxx_works" 1>&6
+if test $ac_cv_prog_cxx_works = no; then
+  { echo "configure: error: installation or configuration problem: C++ compiler cannot create executables." 1>&2; exit 1; }
+fi
+echo $ac_n "checking whether the C++ compiler ($CXX $CXXFLAGS $LDFLAGS) is a cross-compiler""... $ac_c" 1>&6
+echo "configure:883: checking whether the C++ compiler ($CXX $CXXFLAGS $LDFLAGS) is a cross-compiler" >&5
+echo "$ac_t""$ac_cv_prog_cxx_cross" 1>&6
+cross_compiling=$ac_cv_prog_cxx_cross
+
+echo $ac_n "checking whether we are using GNU C++""... $ac_c" 1>&6
+echo "configure:888: checking whether we are using GNU C++" >&5
+if eval "test \"`echo '$''{'ac_cv_prog_gxx'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  cat > conftest.C <<EOF
+#ifdef __GNUC__
+  yes;
+#endif
+EOF
+if { ac_try='${CXX-g++} -E conftest.C'; { (eval echo configure:897: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }; } | egrep yes >/dev/null 2>&1; then
+  ac_cv_prog_gxx=yes
+else
+  ac_cv_prog_gxx=no
+fi
+fi
+
+echo "$ac_t""$ac_cv_prog_gxx" 1>&6
+
+if test $ac_cv_prog_gxx = yes; then
+  GXX=yes
+else
+  GXX=
+fi
+
+ac_test_CXXFLAGS="${CXXFLAGS+set}"
+ac_save_CXXFLAGS="$CXXFLAGS"
+CXXFLAGS=
+echo $ac_n "checking whether ${CXX-g++} accepts -g""... $ac_c" 1>&6
+echo "configure:916: checking whether ${CXX-g++} accepts -g" >&5
+if eval "test \"`echo '$''{'ac_cv_prog_cxx_g'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  echo 'void f(){}' > conftest.cc
+if test -z "`${CXX-g++} -g -c conftest.cc 2>&1`"; then
+  ac_cv_prog_cxx_g=yes
+else
+  ac_cv_prog_cxx_g=no
+fi
+rm -f conftest*
+
+fi
+
+echo "$ac_t""$ac_cv_prog_cxx_g" 1>&6
+if test "$ac_test_CXXFLAGS" = set; then
+  CXXFLAGS="$ac_save_CXXFLAGS"
+elif test $ac_cv_prog_cxx_g = yes; then
+  if test "$GXX" = yes; then
+    CXXFLAGS="-g -O2"
+  else
+    CXXFLAGS="-g"
+  fi
+else
+  if test "$GXX" = yes; then
+    CXXFLAGS="-O2"
+  else
+    CXXFLAGS=
+  fi
+fi
+
+for ac_prog in mawk gawk nawk awk
+do
+# Extract the first word of "$ac_prog", so it can be a program name with args.
+set dummy $ac_prog; ac_word=$2
+echo $ac_n "checking for $ac_word""... $ac_c" 1>&6
+echo "configure:952: checking for $ac_word" >&5
+if eval "test \"`echo '$''{'ac_cv_prog_AWK'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  if test -n "$AWK"; then
+  ac_cv_prog_AWK="$AWK" # Let the user override the test.
+else
+  IFS="${IFS= 	}"; ac_save_ifs="$IFS"; IFS=":"
+  ac_dummy="$PATH"
+  for ac_dir in $ac_dummy; do
+    test -z "$ac_dir" && ac_dir=.
+    if test -f $ac_dir/$ac_word; then
+      ac_cv_prog_AWK="$ac_prog"
+      break
+    fi
+  done
+  IFS="$ac_save_ifs"
+fi
+fi
+AWK="$ac_cv_prog_AWK"
+if test -n "$AWK"; then
+  echo "$ac_t""$AWK" 1>&6
+else
+  echo "$ac_t""no" 1>&6
+fi
+
+test -n "$AWK" && break
+done
+
+for ac_prog in 'bison -y' byacc
+do
+# Extract the first word of "$ac_prog", so it can be a program name with args.
+set dummy $ac_prog; ac_word=$2
+echo $ac_n "checking for $ac_word""... $ac_c" 1>&6
+echo "configure:986: checking for $ac_word" >&5
+if eval "test \"`echo '$''{'ac_cv_prog_YACC'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  if test -n "$YACC"; then
+  ac_cv_prog_YACC="$YACC" # Let the user override the test.
+else
+  IFS="${IFS= 	}"; ac_save_ifs="$IFS"; IFS=":"
+  ac_dummy="$PATH"
+  for ac_dir in $ac_dummy; do
+    test -z "$ac_dir" && ac_dir=.
+    if test -f $ac_dir/$ac_word; then
+      ac_cv_prog_YACC="$ac_prog"
+      break
+    fi
+  done
+  IFS="$ac_save_ifs"
+fi
+fi
+YACC="$ac_cv_prog_YACC"
+if test -n "$YACC"; then
+  echo "$ac_t""$YACC" 1>&6
+else
+  echo "$ac_t""no" 1>&6
+fi
+
+test -n "$YACC" && break
+done
+test -n "$YACC" || YACC="yacc"
+
+ac_aux_dir=
+for ac_dir in $srcdir $srcdir/.. $srcdir/../..; do
+  if test -f $ac_dir/install-sh; then
+    ac_aux_dir=$ac_dir
+    ac_install_sh="$ac_aux_dir/install-sh -c"
+    break
+  elif test -f $ac_dir/install.sh; then
+    ac_aux_dir=$ac_dir
+    ac_install_sh="$ac_aux_dir/install.sh -c"
+    break
+  fi
+done
+if test -z "$ac_aux_dir"; then
+  { echo "configure: error: can not find install-sh or install.sh in $srcdir $srcdir/.. $srcdir/../.." 1>&2; exit 1; }
+fi
+ac_config_guess=$ac_aux_dir/config.guess
+ac_config_sub=$ac_aux_dir/config.sub
+ac_configure=$ac_aux_dir/configure # This should be Cygnus configure.
+
+# Find a good install program.  We prefer a C program (faster),
+# so one script is as good as another.  But avoid the broken or
+# incompatible versions:
+# SysV /etc/install, /usr/sbin/install
+# SunOS /usr/etc/install
+# IRIX /sbin/install
+# AIX /bin/install
+# AIX 4 /usr/bin/installbsd, which doesn't work without a -g flag
+# AFS /usr/afsws/bin/install, which mishandles nonexistent args
+# SVR4 /usr/ucb/install, which tries to use the nonexistent group "staff"
+# ./install, which can be erroneously created by make from ./install.sh.
+echo $ac_n "checking for a BSD compatible install""... $ac_c" 1>&6
+echo "configure:1047: checking for a BSD compatible install" >&5
+if test -z "$INSTALL"; then
+if eval "test \"`echo '$''{'ac_cv_path_install'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+    IFS="${IFS= 	}"; ac_save_IFS="$IFS"; IFS=":"
+  for ac_dir in $PATH; do
+    # Account for people who put trailing slashes in PATH elements.
+    case "$ac_dir/" in
+    /|./|.//|/etc/*|/usr/sbin/*|/usr/etc/*|/sbin/*|/usr/afsws/bin/*|/usr/ucb/*) ;;
+    *)
+      # OSF1 and SCO ODT 3.0 have their own names for install.
+      # Don't use installbsd from OSF since it installs stuff as root
+      # by default.
+      for ac_prog in ginstall scoinst install; do
+        if test -f $ac_dir/$ac_prog; then
+	  if test $ac_prog = install &&
+            grep dspmsg $ac_dir/$ac_prog >/dev/null 2>&1; then
+	    # AIX install.  It has an incompatible calling convention.
+	    :
+	  else
+	    ac_cv_path_install="$ac_dir/$ac_prog -c"
+	    break 2
+	  fi
+	fi
+      done
+      ;;
+    esac
+  done
+  IFS="$ac_save_IFS"
+
+fi
+  if test "${ac_cv_path_install+set}" = set; then
+    INSTALL="$ac_cv_path_install"
+  else
+    # As a last resort, use the slow shell script.  We don't cache a
+    # path for INSTALL within a source directory, because that will
+    # break other packages using the cache if that directory is
+    # removed, or if the path is relative.
+    INSTALL="$ac_install_sh"
+  fi
+fi
+echo "$ac_t""$INSTALL" 1>&6
+
+# Use test -z because SunOS4 sh mishandles braces in ${var-val}.
+# It thinks the first close brace ends the variable substitution.
+test -z "$INSTALL_PROGRAM" && INSTALL_PROGRAM='${INSTALL}'
+
+test -z "$INSTALL_SCRIPT" && INSTALL_SCRIPT='${INSTALL_PROGRAM}'
+
+test -z "$INSTALL_DATA" && INSTALL_DATA='${INSTALL} -m 644'
+
+echo $ac_n "checking whether ln -s works""... $ac_c" 1>&6
+echo "configure:1100: checking whether ln -s works" >&5
+if eval "test \"`echo '$''{'ac_cv_prog_LN_S'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  rm -f conftestdata
+if ln -s X conftestdata 2>/dev/null
+then
+  rm -f conftestdata
+  ac_cv_prog_LN_S="ln -s"
+else
+  ac_cv_prog_LN_S=ln
+fi
+fi
+LN_S="$ac_cv_prog_LN_S"
+if test "$ac_cv_prog_LN_S" = "ln -s"; then
+  echo "$ac_t""yes" 1>&6
+else
+  echo "$ac_t""no" 1>&6
+fi
+
+echo $ac_n "checking whether ${MAKE-make} sets \${MAKE}""... $ac_c" 1>&6
+echo "configure:1121: checking whether ${MAKE-make} sets \${MAKE}" >&5
+set dummy ${MAKE-make}; ac_make=`echo "$2" | sed 'y%./+-%__p_%'`
+if eval "test \"`echo '$''{'ac_cv_prog_make_${ac_make}_set'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  cat > conftestmake <<\EOF
+all:
+	@echo 'ac_maketemp="${MAKE}"'
+EOF
+# GNU make sometimes prints "make[1]: Entering...", which would confuse us.
+eval `${MAKE-make} -f conftestmake 2>/dev/null | grep temp=`
+if test -n "$ac_maketemp"; then
+  eval ac_cv_prog_make_${ac_make}_set=yes
+else
+  eval ac_cv_prog_make_${ac_make}_set=no
+fi
+rm -f conftestmake
+fi
+if eval "test \"`echo '$ac_cv_prog_make_'${ac_make}_set`\" = yes"; then
+  echo "$ac_t""yes" 1>&6
+  SET_MAKE=
+else
+  echo "$ac_t""no" 1>&6
+  SET_MAKE="MAKE=${MAKE-make}"
+fi
+
+# Extract the first word of "ranlib", so it can be a program name with args.
+set dummy ranlib; ac_word=$2
+echo $ac_n "checking for $ac_word""... $ac_c" 1>&6
+echo "configure:1150: checking for $ac_word" >&5
+if eval "test \"`echo '$''{'ac_cv_prog_RANLIB'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  if test -n "$RANLIB"; then
+  ac_cv_prog_RANLIB="$RANLIB" # Let the user override the test.
+else
+  IFS="${IFS= 	}"; ac_save_ifs="$IFS"; IFS=":"
+  ac_dummy="$PATH"
+  for ac_dir in $ac_dummy; do
+    test -z "$ac_dir" && ac_dir=.
+    if test -f $ac_dir/$ac_word; then
+      ac_cv_prog_RANLIB="ranlib"
+      break
+    fi
+  done
+  IFS="$ac_save_ifs"
+  test -z "$ac_cv_prog_RANLIB" && ac_cv_prog_RANLIB=":"
+fi
+fi
+RANLIB="$ac_cv_prog_RANLIB"
+if test -n "$RANLIB"; then
+  echo "$ac_t""$RANLIB" 1>&6
+else
+  echo "$ac_t""no" 1>&6
+fi
+
+
+
+echo $ac_n "checking how to run the C preprocessor""... $ac_c" 1>&6
+echo "configure:1180: checking how to run the C preprocessor" >&5
+# On Suns, sometimes $CPP names a directory.
+if test -n "$CPP" && test -d "$CPP"; then
+  CPP=
+fi
+if test -z "$CPP"; then
+if eval "test \"`echo '$''{'ac_cv_prog_CPP'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+    # This must be in double quotes, not single quotes, because CPP may get
+  # substituted into the Makefile and "${CC-cc}" will confuse make.
+  CPP="${CC-cc} -E"
+  # On the NeXT, cc -E runs the code through the compiler's parser,
+  # not just through cpp.
+  cat > conftest.$ac_ext <<EOF
+#line 1195 "configure"
+#include "confdefs.h"
+#include <assert.h>
+Syntax Error
+EOF
+ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out"
+{ (eval echo configure:1201: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }
+ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"`
+if test -z "$ac_err"; then
+  :
+else
+  echo "$ac_err" >&5
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -rf conftest*
+  CPP="${CC-cc} -E -traditional-cpp"
+  cat > conftest.$ac_ext <<EOF
+#line 1212 "configure"
+#include "confdefs.h"
+#include <assert.h>
+Syntax Error
+EOF
+ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out"
+{ (eval echo configure:1218: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }
+ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"`
+if test -z "$ac_err"; then
+  :
+else
+  echo "$ac_err" >&5
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -rf conftest*
+  CPP="${CC-cc} -nologo -E"
+  cat > conftest.$ac_ext <<EOF
+#line 1229 "configure"
+#include "confdefs.h"
+#include <assert.h>
+Syntax Error
+EOF
+ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out"
+{ (eval echo configure:1235: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }
+ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"`
+if test -z "$ac_err"; then
+  :
+else
+  echo "$ac_err" >&5
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -rf conftest*
+  CPP=/lib/cpp
+fi
+rm -f conftest*
+fi
+rm -f conftest*
+fi
+rm -f conftest*
+  ac_cv_prog_CPP="$CPP"
+fi
+  CPP="$ac_cv_prog_CPP"
+else
+  ac_cv_prog_CPP="$CPP"
+fi
+echo "$ac_t""$CPP" 1>&6
+
+echo $ac_n "checking for AIX""... $ac_c" 1>&6
+echo "configure:1260: checking for AIX" >&5
+cat > conftest.$ac_ext <<EOF
+#line 1262 "configure"
+#include "confdefs.h"
+#ifdef _AIX
+  yes
+#endif
+
+EOF
+if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
+  egrep "yes" >/dev/null 2>&1; then
+  rm -rf conftest*
+  echo "$ac_t""yes" 1>&6; cat >> confdefs.h <<\EOF
+#define _ALL_SOURCE 1
+EOF
+
+else
+  rm -rf conftest*
+  echo "$ac_t""no" 1>&6
+fi
+rm -f conftest*
+
+
+echo $ac_n "checking for POSIXized ISC""... $ac_c" 1>&6
+echo "configure:1284: checking for POSIXized ISC" >&5
+if test -d /etc/conf/kconfig.d &&
+  grep _POSIX_VERSION /usr/include/sys/unistd.h >/dev/null 2>&1
+then
+  echo "$ac_t""yes" 1>&6
+  ISC=yes # If later tests want to check for ISC.
+  cat >> confdefs.h <<\EOF
+#define _POSIX_SOURCE 1
+EOF
+
+  if test "$GCC" = yes; then
+    CC="$CC -posix"
+  else
+    CC="$CC -Xp"
+  fi
+else
+  echo "$ac_t""no" 1>&6
+  ISC=
+fi
+
+ac_safe=`echo "minix/config.h" | sed 'y%./+-%__p_%'`
+echo $ac_n "checking for minix/config.h""... $ac_c" 1>&6
+echo "configure:1306: checking for minix/config.h" >&5
+if eval "test \"`echo '$''{'ac_cv_header_$ac_safe'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  cat > conftest.$ac_ext <<EOF
+#line 1311 "configure"
+#include "confdefs.h"
+#include <minix/config.h>
+EOF
+ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out"
+{ (eval echo configure:1316: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }
+ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"`
+if test -z "$ac_err"; then
+  rm -rf conftest*
+  eval "ac_cv_header_$ac_safe=yes"
+else
+  echo "$ac_err" >&5
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -rf conftest*
+  eval "ac_cv_header_$ac_safe=no"
+fi
+rm -f conftest*
+fi
+if eval "test \"`echo '$ac_cv_header_'$ac_safe`\" = yes"; then
+  echo "$ac_t""yes" 1>&6
+  MINIX=yes
+else
+  echo "$ac_t""no" 1>&6
+MINIX=
+fi
+
+if test "$MINIX" = yes; then
+  cat >> confdefs.h <<\EOF
+#define _POSIX_SOURCE 1
+EOF
+
+  cat >> confdefs.h <<\EOF
+#define _POSIX_1_SOURCE 2
+EOF
+
+  cat >> confdefs.h <<\EOF
+#define _MINIX 1
+EOF
+
+fi
+
+echo $ac_n "checking for ${CC-cc} option to accept ANSI C""... $ac_c" 1>&6
+echo "configure:1354: checking for ${CC-cc} option to accept ANSI C" >&5
+if eval "test \"`echo '$''{'ac_cv_prog_cc_stdc'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  ac_cv_prog_cc_stdc=no
+ac_save_CFLAGS="$CFLAGS"
+# Don't try gcc -ansi; that turns off useful extensions and
+# breaks some systems' header files.
+# AIX			-qlanglvl=ansi
+# Ultrix and OSF/1	-std1
+# HP-UX			-Aa -D_HPUX_SOURCE
+# SVR4			-Xc
+for ac_arg in "" -qlanglvl=ansi -std1 "-Aa -D_HPUX_SOURCE" -Xc
+do
+  CFLAGS="$ac_save_CFLAGS $ac_arg"
+  cat > conftest.$ac_ext <<EOF
+#line 1370 "configure"
+#include "confdefs.h"
+#if !defined(__STDC__) || __STDC__ != 1
+choke me
+#endif	
+
+int main() {
+int test (int i, double x);
+struct s1 {int (*f) (int a);};
+struct s2 {int (*f) (double a);};
+; return 0; }
+EOF
+if { (eval echo configure:1382: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
+  rm -rf conftest*
+  ac_cv_prog_cc_stdc="$ac_arg"; break
+else
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+fi
+rm -f conftest*
+done
+CFLAGS="$ac_save_CFLAGS"
+
+fi
+
+echo "$ac_t""$ac_cv_prog_cc_stdc" 1>&6
+case "x$ac_cv_prog_cc_stdc" in
+  x|xno) ;;
+  *) CC="$CC $ac_cv_prog_cc_stdc" ;;
+esac
+
+
+echo $ac_n "checking for function prototypes""... $ac_c" 1>&6
+echo "configure:1403: checking for function prototypes" >&5
+if test "$ac_cv_prog_cc_stdc" != no; then
+  echo "$ac_t""yes" 1>&6
+  cat >> confdefs.h <<\EOF
+#define PROTOTYPES 1
+EOF
+
+  U= ANSI2KNR=
+else
+  echo "$ac_t""no" 1>&6
+  U=_ ANSI2KNR=ansi2knr
+fi
+
+echo $ac_n "checking for working const""... $ac_c" 1>&6
+echo "configure:1417: checking for working const" >&5
+if eval "test \"`echo '$''{'ac_cv_c_const'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  cat > conftest.$ac_ext <<EOF
+#line 1422 "configure"
+#include "confdefs.h"
+
+int main() {
+
+/* Ultrix mips cc rejects this.  */
+typedef int charset[2]; const charset x;
+/* SunOS 4.1.1 cc rejects this.  */
+char const *const *ccp;
+char **p;
+/* NEC SVR4.0.2 mips cc rejects this.  */
+struct point {int x, y;};
+static struct point const zero = {0,0};
+/* AIX XL C 1.02.0.0 rejects this.
+   It does not let you subtract one const X* pointer from another in an arm
+   of an if-expression whose if-part is not a constant expression */
+const char *g = "string";
+ccp = &g + (g ? g-g : 0);
+/* HPUX 7.0 cc rejects these. */
+++ccp;
+p = (char**) ccp;
+ccp = (char const *const *) p;
+{ /* SCO 3.2v4 cc rejects this.  */
+  char *t;
+  char const *s = 0 ? (char *) 0 : (char const *) 0;
+
+  *t++ = 0;
+}
+{ /* Someone thinks the Sun supposedly-ANSI compiler will reject this.  */
+  int x[] = {25, 17};
+  const int *foo = &x[0];
+  ++foo;
+}
+{ /* Sun SC1.0 ANSI compiler rejects this -- but not the above. */
+  typedef const int *iptr;
+  iptr p = 0;
+  ++p;
+}
+{ /* AIX XL C 1.02.0.0 rejects this saying
+     "k.c", line 2.27: 1506-025 (S) Operand must be a modifiable lvalue. */
+  struct s { int j; const int *ap[3]; };
+  struct s *b; b->j = 5;
+}
+{ /* ULTRIX-32 V3.1 (Rev 9) vcc rejects this */
+  const int foo = 10;
+}
+
+; return 0; }
+EOF
+if { (eval echo configure:1471: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
+  rm -rf conftest*
+  ac_cv_c_const=yes
+else
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -rf conftest*
+  ac_cv_c_const=no
+fi
+rm -f conftest*
+fi
+
+echo "$ac_t""$ac_cv_c_const" 1>&6
+if test $ac_cv_c_const = no; then
+  cat >> confdefs.h <<\EOF
+#define const 
+EOF
+
+fi
+
+echo $ac_n "checking for ANSI C header files""... $ac_c" 1>&6
+echo "configure:1492: checking for ANSI C header files" >&5
+if eval "test \"`echo '$''{'ac_cv_header_stdc'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  cat > conftest.$ac_ext <<EOF
+#line 1497 "configure"
+#include "confdefs.h"
+#include <stdlib.h>
+#include <stdarg.h>
+#include <string.h>
+#include <float.h>
+EOF
+ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out"
+{ (eval echo configure:1505: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }
+ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"`
+if test -z "$ac_err"; then
+  rm -rf conftest*
+  ac_cv_header_stdc=yes
+else
+  echo "$ac_err" >&5
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -rf conftest*
+  ac_cv_header_stdc=no
+fi
+rm -f conftest*
+
+if test $ac_cv_header_stdc = yes; then
+  # SunOS 4.x string.h does not declare mem*, contrary to ANSI.
+cat > conftest.$ac_ext <<EOF
+#line 1522 "configure"
+#include "confdefs.h"
+#include <string.h>
+EOF
+if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
+  egrep "memchr" >/dev/null 2>&1; then
+  :
+else
+  rm -rf conftest*
+  ac_cv_header_stdc=no
+fi
+rm -f conftest*
+
+fi
+
+if test $ac_cv_header_stdc = yes; then
+  # ISC 2.0.2 stdlib.h does not declare free, contrary to ANSI.
+cat > conftest.$ac_ext <<EOF
+#line 1540 "configure"
+#include "confdefs.h"
+#include <stdlib.h>
+EOF
+if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
+  egrep "free" >/dev/null 2>&1; then
+  :
+else
+  rm -rf conftest*
+  ac_cv_header_stdc=no
+fi
+rm -f conftest*
+
+fi
+
+if test $ac_cv_header_stdc = yes; then
+  # /bin/cc in Irix-4.0.5 gets non-ANSI ctype macros unless using -ansi.
+if test "$cross_compiling" = yes; then
+  :
+else
+  cat > conftest.$ac_ext <<EOF
+#line 1561 "configure"
+#include "confdefs.h"
+#include <ctype.h>
+#define ISLOWER(c) ('a' <= (c) && (c) <= 'z')
+#define TOUPPER(c) (ISLOWER(c) ? 'A' + ((c) - 'a') : (c))
+#define XOR(e, f) (((e) && !(f)) || (!(e) && (f)))
+int main () { int i; for (i = 0; i < 256; i++)
+if (XOR (islower (i), ISLOWER (i)) || toupper (i) != TOUPPER (i)) exit(2);
+exit (0); }
+
+EOF
+if { (eval echo configure:1572: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext} && (./conftest; exit) 2>/dev/null
+then
+  :
+else
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -fr conftest*
+  ac_cv_header_stdc=no
+fi
+rm -fr conftest*
+fi
+
+fi
+fi
+
+echo "$ac_t""$ac_cv_header_stdc" 1>&6
+if test $ac_cv_header_stdc = yes; then
+  cat >> confdefs.h <<\EOF
+#define STDC_HEADERS 1
+EOF
+
+fi
+
+echo $ac_n "checking for off_t""... $ac_c" 1>&6
+echo "configure:1596: checking for off_t" >&5
+if eval "test \"`echo '$''{'ac_cv_type_off_t'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  cat > conftest.$ac_ext <<EOF
+#line 1601 "configure"
+#include "confdefs.h"
+#include <sys/types.h>
+#if STDC_HEADERS
+#include <stdlib.h>
+#include <stddef.h>
+#endif
+EOF
+if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
+  egrep "(^|[^a-zA-Z_0-9])off_t[^a-zA-Z_0-9]" >/dev/null 2>&1; then
+  rm -rf conftest*
+  ac_cv_type_off_t=yes
+else
+  rm -rf conftest*
+  ac_cv_type_off_t=no
+fi
+rm -f conftest*
+
+fi
+echo "$ac_t""$ac_cv_type_off_t" 1>&6
+if test $ac_cv_type_off_t = no; then
+  cat >> confdefs.h <<\EOF
+#define off_t long
+EOF
+
+fi
+
+echo $ac_n "checking for size_t""... $ac_c" 1>&6
+echo "configure:1629: checking for size_t" >&5
+if eval "test \"`echo '$''{'ac_cv_type_size_t'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  cat > conftest.$ac_ext <<EOF
+#line 1634 "configure"
+#include "confdefs.h"
+#include <sys/types.h>
+#if STDC_HEADERS
+#include <stdlib.h>
+#include <stddef.h>
+#endif
+EOF
+if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
+  egrep "(^|[^a-zA-Z_0-9])size_t[^a-zA-Z_0-9]" >/dev/null 2>&1; then
+  rm -rf conftest*
+  ac_cv_type_size_t=yes
+else
+  rm -rf conftest*
+  ac_cv_type_size_t=no
+fi
+rm -f conftest*
+
+fi
+echo "$ac_t""$ac_cv_type_size_t" 1>&6
+if test $ac_cv_type_size_t = no; then
+  cat >> confdefs.h <<\EOF
+#define size_t unsigned
+EOF
+
+fi
+
+echo $ac_n "checking whether time.h and sys/time.h may both be included""... $ac_c" 1>&6
+echo "configure:1662: checking whether time.h and sys/time.h may both be included" >&5
+if eval "test \"`echo '$''{'ac_cv_header_time'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  cat > conftest.$ac_ext <<EOF
+#line 1667 "configure"
+#include "confdefs.h"
+#include <sys/types.h>
+#include <sys/time.h>
+#include <time.h>
+int main() {
+struct tm *tp;
+; return 0; }
+EOF
+if { (eval echo configure:1676: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
+  rm -rf conftest*
+  ac_cv_header_time=yes
+else
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -rf conftest*
+  ac_cv_header_time=no
+fi
+rm -f conftest*
+fi
+
+echo "$ac_t""$ac_cv_header_time" 1>&6
+if test $ac_cv_header_time = yes; then
+  cat >> confdefs.h <<\EOF
+#define TIME_WITH_SYS_TIME 1
+EOF
+
+fi
+
+echo $ac_n "checking whether struct tm is in sys/time.h or time.h""... $ac_c" 1>&6
+echo "configure:1697: checking whether struct tm is in sys/time.h or time.h" >&5
+if eval "test \"`echo '$''{'ac_cv_struct_tm'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  cat > conftest.$ac_ext <<EOF
+#line 1702 "configure"
+#include "confdefs.h"
+#include <sys/types.h>
+#include <time.h>
+int main() {
+struct tm *tp; tp->tm_sec;
+; return 0; }
+EOF
+if { (eval echo configure:1710: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
+  rm -rf conftest*
+  ac_cv_struct_tm=time.h
+else
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -rf conftest*
+  ac_cv_struct_tm=sys/time.h
+fi
+rm -f conftest*
+fi
+
+echo "$ac_t""$ac_cv_struct_tm" 1>&6
+if test $ac_cv_struct_tm = sys/time.h; then
+  cat >> confdefs.h <<\EOF
+#define TM_IN_SYS_TIME 1
+EOF
+
+fi
+
+
+if test "$ac_cv_prog_cc_stdc" = '-Xc'; then
+cat > conftest.$ac_ext <<EOF
+#line 1733 "configure"
+#include "confdefs.h"
+#include <stdio.h>
+
+int main() {
+ FILE *rubbish = popen("yes", "r"); 
+; return 0; }
+EOF
+if { (eval echo configure:1741: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
+  :
+else
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -rf conftest*
+  CC="`echo $CC | sed 's/-Xc/-Xa/'`"    ac_cv_prog_cc_stdc='-Xa'
+fi
+rm -f conftest*
+fi
+
+
+echo $ac_n "checking for main in -lg""... $ac_c" 1>&6
+echo "configure:1754: checking for main in -lg" >&5
+ac_lib_var=`echo g'_'main | sed 'y%./+-%__p_%'`
+if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  ac_save_LIBS="$LIBS"
+LIBS="-lg  $LIBS"
+cat > conftest.$ac_ext <<EOF
+#line 1762 "configure"
+#include "confdefs.h"
+
+int main() {
+main()
+; return 0; }
+EOF
+if { (eval echo configure:1769: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+  rm -rf conftest*
+  eval "ac_cv_lib_$ac_lib_var=yes"
+else
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -rf conftest*
+  eval "ac_cv_lib_$ac_lib_var=no"
+fi
+rm -f conftest*
+LIBS="$ac_save_LIBS"
+
+fi
+if eval "test \"`echo '$ac_cv_lib_'$ac_lib_var`\" = yes"; then
+  echo "$ac_t""yes" 1>&6
+    ac_tr_lib=HAVE_LIB`echo g | sed -e 's/[^a-zA-Z0-9_]/_/g' \
+    -e 'y/abcdefghijklmnopqrstuvwxyz/ABCDEFGHIJKLMNOPQRSTUVWXYZ/'`
+  cat >> confdefs.h <<EOF
+#define $ac_tr_lib 1
+EOF
+
+  LIBS="-lg $LIBS"
+
+else
+  echo "$ac_t""no" 1>&6
+fi
+
+echo $ac_n "checking for main in -lgdbm""... $ac_c" 1>&6
+echo "configure:1797: checking for main in -lgdbm" >&5
+ac_lib_var=`echo gdbm'_'main | sed 'y%./+-%__p_%'`
+if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  ac_save_LIBS="$LIBS"
+LIBS="-lgdbm  $LIBS"
+cat > conftest.$ac_ext <<EOF
+#line 1805 "configure"
+#include "confdefs.h"
+
+int main() {
+main()
+; return 0; }
+EOF
+if { (eval echo configure:1812: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+  rm -rf conftest*
+  eval "ac_cv_lib_$ac_lib_var=yes"
+else
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -rf conftest*
+  eval "ac_cv_lib_$ac_lib_var=no"
+fi
+rm -f conftest*
+LIBS="$ac_save_LIBS"
+
+fi
+if eval "test \"`echo '$ac_cv_lib_'$ac_lib_var`\" = yes"; then
+  echo "$ac_t""yes" 1>&6
+    ac_tr_lib=HAVE_LIB`echo gdbm | sed -e 's/[^a-zA-Z0-9_]/_/g' \
+    -e 'y/abcdefghijklmnopqrstuvwxyz/ABCDEFGHIJKLMNOPQRSTUVWXYZ/'`
+  cat >> confdefs.h <<EOF
+#define $ac_tr_lib 1
+EOF
+
+  LIBS="-lgdbm $LIBS"
+
+else
+  echo "$ac_t""no" 1>&6
+fi
+
+echo $ac_n "checking for main in -lm""... $ac_c" 1>&6
+echo "configure:1840: checking for main in -lm" >&5
+ac_lib_var=`echo m'_'main | sed 'y%./+-%__p_%'`
+if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  ac_save_LIBS="$LIBS"
+LIBS="-lm  $LIBS"
+cat > conftest.$ac_ext <<EOF
+#line 1848 "configure"
+#include "confdefs.h"
+
+int main() {
+main()
+; return 0; }
+EOF
+if { (eval echo configure:1855: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+  rm -rf conftest*
+  eval "ac_cv_lib_$ac_lib_var=yes"
+else
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -rf conftest*
+  eval "ac_cv_lib_$ac_lib_var=no"
+fi
+rm -f conftest*
+LIBS="$ac_save_LIBS"
+
+fi
+if eval "test \"`echo '$ac_cv_lib_'$ac_lib_var`\" = yes"; then
+  echo "$ac_t""yes" 1>&6
+    ac_tr_lib=HAVE_LIB`echo m | sed -e 's/[^a-zA-Z0-9_]/_/g' \
+    -e 'y/abcdefghijklmnopqrstuvwxyz/ABCDEFGHIJKLMNOPQRSTUVWXYZ/'`
+  cat >> confdefs.h <<EOF
+#define $ac_tr_lib 1
+EOF
+
+  LIBS="-lm $LIBS"
+
+else
+  echo "$ac_t""no" 1>&6
+fi
+
+echo $ac_n "checking for main in -lstdc++""... $ac_c" 1>&6
+echo "configure:1883: checking for main in -lstdc++" >&5
+ac_lib_var=`echo stdc++'_'main | sed 'y%./+-%__p_%'`
+if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  ac_save_LIBS="$LIBS"
+LIBS="-lstdc++  $LIBS"
+cat > conftest.$ac_ext <<EOF
+#line 1891 "configure"
+#include "confdefs.h"
+
+int main() {
+main()
+; return 0; }
+EOF
+if { (eval echo configure:1898: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+  rm -rf conftest*
+  eval "ac_cv_lib_$ac_lib_var=yes"
+else
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -rf conftest*
+  eval "ac_cv_lib_$ac_lib_var=no"
+fi
+rm -f conftest*
+LIBS="$ac_save_LIBS"
+
+fi
+if eval "test \"`echo '$ac_cv_lib_'$ac_lib_var`\" = yes"; then
+  echo "$ac_t""yes" 1>&6
+    ac_tr_lib=HAVE_LIB`echo stdc++ | sed -e 's/[^a-zA-Z0-9_]/_/g' \
+    -e 'y/abcdefghijklmnopqrstuvwxyz/ABCDEFGHIJKLMNOPQRSTUVWXYZ/'`
+  cat >> confdefs.h <<EOF
+#define $ac_tr_lib 1
+EOF
+
+  LIBS="-lstdc++ $LIBS"
+
+else
+  echo "$ac_t""no" 1>&6
+fi
+
+echo $ac_n "checking for main in -lcrypt""... $ac_c" 1>&6
+echo "configure:1926: checking for main in -lcrypt" >&5
+ac_lib_var=`echo crypt'_'main | sed 'y%./+-%__p_%'`
+if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  ac_save_LIBS="$LIBS"
+LIBS="-lcrypt  $LIBS"
+cat > conftest.$ac_ext <<EOF
+#line 1934 "configure"
+#include "confdefs.h"
+
+int main() {
+main()
+; return 0; }
+EOF
+if { (eval echo configure:1941: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+  rm -rf conftest*
+  eval "ac_cv_lib_$ac_lib_var=yes"
+else
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -rf conftest*
+  eval "ac_cv_lib_$ac_lib_var=no"
+fi
+rm -f conftest*
+LIBS="$ac_save_LIBS"
+
+fi
+if eval "test \"`echo '$ac_cv_lib_'$ac_lib_var`\" = yes"; then
+  echo "$ac_t""yes" 1>&6
+    ac_tr_lib=HAVE_LIB`echo crypt | sed -e 's/[^a-zA-Z0-9_]/_/g' \
+    -e 'y/abcdefghijklmnopqrstuvwxyz/ABCDEFGHIJKLMNOPQRSTUVWXYZ/'`
+  cat >> confdefs.h <<EOF
+#define $ac_tr_lib 1
+EOF
+
+  LIBS="-lcrypt $LIBS"
+
+else
+  echo "$ac_t""no" 1>&6
+fi
+
+
+
+ac_header_dirent=no
+for ac_hdr in dirent.h sys/ndir.h sys/dir.h ndir.h
+do
+ac_safe=`echo "$ac_hdr" | sed 'y%./+-%__p_%'`
+echo $ac_n "checking for $ac_hdr that defines DIR""... $ac_c" 1>&6
+echo "configure:1975: checking for $ac_hdr that defines DIR" >&5
+if eval "test \"`echo '$''{'ac_cv_header_dirent_$ac_safe'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  cat > conftest.$ac_ext <<EOF
+#line 1980 "configure"
+#include "confdefs.h"
+#include <sys/types.h>
+#include <$ac_hdr>
+int main() {
+DIR *dirp = 0;
+; return 0; }
+EOF
+if { (eval echo configure:1988: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
+  rm -rf conftest*
+  eval "ac_cv_header_dirent_$ac_safe=yes"
+else
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -rf conftest*
+  eval "ac_cv_header_dirent_$ac_safe=no"
+fi
+rm -f conftest*
+fi
+if eval "test \"`echo '$ac_cv_header_dirent_'$ac_safe`\" = yes"; then
+  echo "$ac_t""yes" 1>&6
+    ac_tr_hdr=HAVE_`echo $ac_hdr | sed 'y%abcdefghijklmnopqrstuvwxyz./-%ABCDEFGHIJKLMNOPQRSTUVWXYZ___%'`
+  cat >> confdefs.h <<EOF
+#define $ac_tr_hdr 1
+EOF
+ ac_header_dirent=$ac_hdr; break
+else
+  echo "$ac_t""no" 1>&6
+fi
+done
+# Two versions of opendir et al. are in -ldir and -lx on SCO Xenix.
+if test $ac_header_dirent = dirent.h; then
+echo $ac_n "checking for opendir in -ldir""... $ac_c" 1>&6
+echo "configure:2013: checking for opendir in -ldir" >&5
+ac_lib_var=`echo dir'_'opendir | sed 'y%./+-%__p_%'`
+if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  ac_save_LIBS="$LIBS"
+LIBS="-ldir  $LIBS"
+cat > conftest.$ac_ext <<EOF
+#line 2021 "configure"
+#include "confdefs.h"
+/* Override any gcc2 internal prototype to avoid an error.  */
+/* We use char because int might match the return type of a gcc2
+    builtin and then its argument prototype would still apply.  */
+char opendir();
+
+int main() {
+opendir()
+; return 0; }
+EOF
+if { (eval echo configure:2032: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+  rm -rf conftest*
+  eval "ac_cv_lib_$ac_lib_var=yes"
+else
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -rf conftest*
+  eval "ac_cv_lib_$ac_lib_var=no"
+fi
+rm -f conftest*
+LIBS="$ac_save_LIBS"
+
+fi
+if eval "test \"`echo '$ac_cv_lib_'$ac_lib_var`\" = yes"; then
+  echo "$ac_t""yes" 1>&6
+  LIBS="$LIBS -ldir"
+else
+  echo "$ac_t""no" 1>&6
+fi
+
+else
+echo $ac_n "checking for opendir in -lx""... $ac_c" 1>&6
+echo "configure:2054: checking for opendir in -lx" >&5
+ac_lib_var=`echo x'_'opendir | sed 'y%./+-%__p_%'`
+if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  ac_save_LIBS="$LIBS"
+LIBS="-lx  $LIBS"
+cat > conftest.$ac_ext <<EOF
+#line 2062 "configure"
+#include "confdefs.h"
+/* Override any gcc2 internal prototype to avoid an error.  */
+/* We use char because int might match the return type of a gcc2
+    builtin and then its argument prototype would still apply.  */
+char opendir();
+
+int main() {
+opendir()
+; return 0; }
+EOF
+if { (eval echo configure:2073: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+  rm -rf conftest*
+  eval "ac_cv_lib_$ac_lib_var=yes"
+else
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -rf conftest*
+  eval "ac_cv_lib_$ac_lib_var=no"
+fi
+rm -f conftest*
+LIBS="$ac_save_LIBS"
+
+fi
+if eval "test \"`echo '$ac_cv_lib_'$ac_lib_var`\" = yes"; then
+  echo "$ac_t""yes" 1>&6
+  LIBS="$LIBS -lx"
+else
+  echo "$ac_t""no" 1>&6
+fi
+
+fi
+
+echo $ac_n "checking for ANSI C header files""... $ac_c" 1>&6
+echo "configure:2096: checking for ANSI C header files" >&5
+if eval "test \"`echo '$''{'ac_cv_header_stdc'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  cat > conftest.$ac_ext <<EOF
+#line 2101 "configure"
+#include "confdefs.h"
+#include <stdlib.h>
+#include <stdarg.h>
+#include <string.h>
+#include <float.h>
+EOF
+ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out"
+{ (eval echo configure:2109: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }
+ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"`
+if test -z "$ac_err"; then
+  rm -rf conftest*
+  ac_cv_header_stdc=yes
+else
+  echo "$ac_err" >&5
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -rf conftest*
+  ac_cv_header_stdc=no
+fi
+rm -f conftest*
+
+if test $ac_cv_header_stdc = yes; then
+  # SunOS 4.x string.h does not declare mem*, contrary to ANSI.
+cat > conftest.$ac_ext <<EOF
+#line 2126 "configure"
+#include "confdefs.h"
+#include <string.h>
+EOF
+if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
+  egrep "memchr" >/dev/null 2>&1; then
+  :
+else
+  rm -rf conftest*
+  ac_cv_header_stdc=no
+fi
+rm -f conftest*
+
+fi
+
+if test $ac_cv_header_stdc = yes; then
+  # ISC 2.0.2 stdlib.h does not declare free, contrary to ANSI.
+cat > conftest.$ac_ext <<EOF
+#line 2144 "configure"
+#include "confdefs.h"
+#include <stdlib.h>
+EOF
+if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
+  egrep "free" >/dev/null 2>&1; then
+  :
+else
+  rm -rf conftest*
+  ac_cv_header_stdc=no
+fi
+rm -f conftest*
+
+fi
+
+if test $ac_cv_header_stdc = yes; then
+  # /bin/cc in Irix-4.0.5 gets non-ANSI ctype macros unless using -ansi.
+if test "$cross_compiling" = yes; then
+  :
+else
+  cat > conftest.$ac_ext <<EOF
+#line 2165 "configure"
+#include "confdefs.h"
+#include <ctype.h>
+#define ISLOWER(c) ('a' <= (c) && (c) <= 'z')
+#define TOUPPER(c) (ISLOWER(c) ? 'A' + ((c) - 'a') : (c))
+#define XOR(e, f) (((e) && !(f)) || (!(e) && (f)))
+int main () { int i; for (i = 0; i < 256; i++)
+if (XOR (islower (i), ISLOWER (i)) || toupper (i) != TOUPPER (i)) exit(2);
+exit (0); }
+
+EOF
+if { (eval echo configure:2176: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext} && (./conftest; exit) 2>/dev/null
+then
+  :
+else
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -fr conftest*
+  ac_cv_header_stdc=no
+fi
+rm -fr conftest*
+fi
+
+fi
+fi
+
+echo "$ac_t""$ac_cv_header_stdc" 1>&6
+if test $ac_cv_header_stdc = yes; then
+  cat >> confdefs.h <<\EOF
+#define STDC_HEADERS 1
+EOF
+
+fi
+
+for ac_hdr in fcntl.h limits.h sys/time.h unistd.h crypt.h string.h memory.h sys/procfs.h
+do
+ac_safe=`echo "$ac_hdr" | sed 'y%./+-%__p_%'`
+echo $ac_n "checking for $ac_hdr""... $ac_c" 1>&6
+echo "configure:2203: checking for $ac_hdr" >&5
+if eval "test \"`echo '$''{'ac_cv_header_$ac_safe'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  cat > conftest.$ac_ext <<EOF
+#line 2208 "configure"
+#include "confdefs.h"
+#include <$ac_hdr>
+EOF
+ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out"
+{ (eval echo configure:2213: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }
+ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"`
+if test -z "$ac_err"; then
+  rm -rf conftest*
+  eval "ac_cv_header_$ac_safe=yes"
+else
+  echo "$ac_err" >&5
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -rf conftest*
+  eval "ac_cv_header_$ac_safe=no"
+fi
+rm -f conftest*
+fi
+if eval "test \"`echo '$ac_cv_header_'$ac_safe`\" = yes"; then
+  echo "$ac_t""yes" 1>&6
+    ac_tr_hdr=HAVE_`echo $ac_hdr | sed 'y%abcdefghijklmnopqrstuvwxyz./-%ABCDEFGHIJKLMNOPQRSTUVWXYZ___%'`
+  cat >> confdefs.h <<EOF
+#define $ac_tr_hdr 1
+EOF
+ 
+else
+  echo "$ac_t""no" 1>&6
+fi
+done
+
+cat > conftest.$ac_ext <<EOF
+#line 2240 "configure"
+#include "confdefs.h"
+#include <stdio.h>
+EOF
+if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
+  egrep "fread" >/dev/null 2>&1; then
+  rm -rf conftest*
+  cat >> confdefs.h <<\EOF
+#define HAVE_FREAD_DECL 1
+EOF
+
+fi
+rm -f conftest*
+
+cat > conftest.$ac_ext <<EOF
+#line 2255 "configure"
+#include "confdefs.h"
+#include <stdio.h>
+EOF
+if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
+  egrep "fgetc" >/dev/null 2>&1; then
+  rm -rf conftest*
+  cat >> confdefs.h <<\EOF
+#define HAVE_FGETC_DECL 1
+EOF
+
+fi
+rm -f conftest*
+
+cat > conftest.$ac_ext <<EOF
+#line 2270 "configure"
+#include "confdefs.h"
+#include <sys/procfs.h>
+EOF
+if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
+  egrep "pr_brksize" >/dev/null 2>&1; then
+  rm -rf conftest*
+  cat >> confdefs.h <<\EOF
+#define HAVE_PR_BRKSIZE 1
+EOF
+
+fi
+rm -f conftest*
+
+
+# The Ultrix 4.2 mips builtin alloca declared by alloca.h only works
+# for constant arguments.  Useless!
+echo $ac_n "checking for working alloca.h""... $ac_c" 1>&6
+echo "configure:2288: checking for working alloca.h" >&5
+if eval "test \"`echo '$''{'ac_cv_header_alloca_h'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  cat > conftest.$ac_ext <<EOF
+#line 2293 "configure"
+#include "confdefs.h"
+#include <alloca.h>
+int main() {
+char *p = alloca(2 * sizeof(int));
+; return 0; }
+EOF
+if { (eval echo configure:2300: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+  rm -rf conftest*
+  ac_cv_header_alloca_h=yes
+else
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -rf conftest*
+  ac_cv_header_alloca_h=no
+fi
+rm -f conftest*
+fi
+
+echo "$ac_t""$ac_cv_header_alloca_h" 1>&6
+if test $ac_cv_header_alloca_h = yes; then
+  cat >> confdefs.h <<\EOF
+#define HAVE_ALLOCA_H 1
+EOF
+
+fi
+
+echo $ac_n "checking for alloca""... $ac_c" 1>&6
+echo "configure:2321: checking for alloca" >&5
+if eval "test \"`echo '$''{'ac_cv_func_alloca_works'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  cat > conftest.$ac_ext <<EOF
+#line 2326 "configure"
+#include "confdefs.h"
+
+#ifdef __GNUC__
+# define alloca __builtin_alloca
+#else
+# ifdef _MSC_VER
+#  include <malloc.h>
+#  define alloca _alloca
+# else
+#  if HAVE_ALLOCA_H
+#   include <alloca.h>
+#  else
+#   ifdef _AIX
+ #pragma alloca
+#   else
+#    ifndef alloca /* predefined by HP cc +Olibcalls */
+char *alloca ();
+#    endif
+#   endif
+#  endif
+# endif
+#endif
+
+int main() {
+char *p = (char *) alloca(1);
+; return 0; }
+EOF
+if { (eval echo configure:2354: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+  rm -rf conftest*
+  ac_cv_func_alloca_works=yes
+else
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -rf conftest*
+  ac_cv_func_alloca_works=no
+fi
+rm -f conftest*
+fi
+
+echo "$ac_t""$ac_cv_func_alloca_works" 1>&6
+if test $ac_cv_func_alloca_works = yes; then
+  cat >> confdefs.h <<\EOF
+#define HAVE_ALLOCA 1
+EOF
+
+fi
+
+if test $ac_cv_func_alloca_works = no; then
+  # The SVR3 libPW and SVR4 libucb both contain incompatible functions
+  # that cause trouble.  Some versions do not even contain alloca or
+  # contain a buggy version.  If you still want to use their alloca,
+  # use ar to extract alloca.o from them instead of compiling alloca.c.
+  ALLOCA=alloca.${ac_objext}
+  cat >> confdefs.h <<\EOF
+#define C_ALLOCA 1
+EOF
+
+
+echo $ac_n "checking whether alloca needs Cray hooks""... $ac_c" 1>&6
+echo "configure:2386: checking whether alloca needs Cray hooks" >&5
+if eval "test \"`echo '$''{'ac_cv_os_cray'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  cat > conftest.$ac_ext <<EOF
+#line 2391 "configure"
+#include "confdefs.h"
+#if defined(CRAY) && ! defined(CRAY2)
+webecray
+#else
+wenotbecray
+#endif
+
+EOF
+if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
+  egrep "webecray" >/dev/null 2>&1; then
+  rm -rf conftest*
+  ac_cv_os_cray=yes
+else
+  rm -rf conftest*
+  ac_cv_os_cray=no
+fi
+rm -f conftest*
+
+fi
+
+echo "$ac_t""$ac_cv_os_cray" 1>&6
+if test $ac_cv_os_cray = yes; then
+for ac_func in _getb67 GETB67 getb67; do
+  echo $ac_n "checking for $ac_func""... $ac_c" 1>&6
+echo "configure:2416: checking for $ac_func" >&5
+if eval "test \"`echo '$''{'ac_cv_func_$ac_func'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  cat > conftest.$ac_ext <<EOF
+#line 2421 "configure"
+#include "confdefs.h"
+/* System header to define __stub macros and hopefully few prototypes,
+    which can conflict with char $ac_func(); below.  */
+#include <assert.h>
+/* Override any gcc2 internal prototype to avoid an error.  */
+/* We use char because int might match the return type of a gcc2
+    builtin and then its argument prototype would still apply.  */
+char $ac_func();
+
+int main() {
+
+/* The GNU C library defines this for functions which it implements
+    to always fail with ENOSYS.  Some functions are actually named
+    something starting with __ and the normal name is an alias.  */
+#if defined (__stub_$ac_func) || defined (__stub___$ac_func)
+choke me
+#else
+$ac_func();
+#endif
+
+; return 0; }
+EOF
+if { (eval echo configure:2444: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+  rm -rf conftest*
+  eval "ac_cv_func_$ac_func=yes"
+else
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -rf conftest*
+  eval "ac_cv_func_$ac_func=no"
+fi
+rm -f conftest*
+fi
+
+if eval "test \"`echo '$ac_cv_func_'$ac_func`\" = yes"; then
+  echo "$ac_t""yes" 1>&6
+  cat >> confdefs.h <<EOF
+#define CRAY_STACKSEG_END $ac_func
+EOF
+
+  break
+else
+  echo "$ac_t""no" 1>&6
+fi
+
+done
+fi
+
+echo $ac_n "checking stack direction for C alloca""... $ac_c" 1>&6
+echo "configure:2471: checking stack direction for C alloca" >&5
+if eval "test \"`echo '$''{'ac_cv_c_stack_direction'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  if test "$cross_compiling" = yes; then
+  ac_cv_c_stack_direction=0
+else
+  cat > conftest.$ac_ext <<EOF
+#line 2479 "configure"
+#include "confdefs.h"
+find_stack_direction ()
+{
+  static char *addr = 0;
+  auto char dummy;
+  if (addr == 0)
+    {
+      addr = &dummy;
+      return find_stack_direction ();
+    }
+  else
+    return (&dummy > addr) ? 1 : -1;
+}
+main ()
+{
+  exit (find_stack_direction() < 0);
+}
+EOF
+if { (eval echo configure:2498: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext} && (./conftest; exit) 2>/dev/null
+then
+  ac_cv_c_stack_direction=1
+else
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -fr conftest*
+  ac_cv_c_stack_direction=-1
+fi
+rm -fr conftest*
+fi
+
+fi
+
+echo "$ac_t""$ac_cv_c_stack_direction" 1>&6
+cat >> confdefs.h <<EOF
+#define STACK_DIRECTION $ac_cv_c_stack_direction
+EOF
+
+fi
+
+if test $ac_cv_prog_gcc = yes; then
+    echo $ac_n "checking whether ${CC-cc} needs -traditional""... $ac_c" 1>&6
+echo "configure:2521: checking whether ${CC-cc} needs -traditional" >&5
+if eval "test \"`echo '$''{'ac_cv_prog_gcc_traditional'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+    ac_pattern="Autoconf.*'x'"
+  cat > conftest.$ac_ext <<EOF
+#line 2527 "configure"
+#include "confdefs.h"
+#include <sgtty.h>
+Autoconf TIOCGETP
+EOF
+if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
+  egrep "$ac_pattern" >/dev/null 2>&1; then
+  rm -rf conftest*
+  ac_cv_prog_gcc_traditional=yes
+else
+  rm -rf conftest*
+  ac_cv_prog_gcc_traditional=no
+fi
+rm -f conftest*
+
+
+  if test $ac_cv_prog_gcc_traditional = no; then
+    cat > conftest.$ac_ext <<EOF
+#line 2545 "configure"
+#include "confdefs.h"
+#include <termio.h>
+Autoconf TCGETA
+EOF
+if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
+  egrep "$ac_pattern" >/dev/null 2>&1; then
+  rm -rf conftest*
+  ac_cv_prog_gcc_traditional=yes
+fi
+rm -f conftest*
+
+  fi
+fi
+
+echo "$ac_t""$ac_cv_prog_gcc_traditional" 1>&6
+  if test $ac_cv_prog_gcc_traditional = yes; then
+    CC="$CC -traditional"
+  fi
+fi
+
+echo $ac_n "checking return type of signal handlers""... $ac_c" 1>&6
+echo "configure:2567: checking return type of signal handlers" >&5
+if eval "test \"`echo '$''{'ac_cv_type_signal'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  cat > conftest.$ac_ext <<EOF
+#line 2572 "configure"
+#include "confdefs.h"
+#include <sys/types.h>
+#include <signal.h>
+#ifdef signal
+#undef signal
+#endif
+#ifdef __cplusplus
+extern "C" void (*signal (int, void (*)(int)))(int);
+#else
+void (*signal ()) ();
+#endif
+
+int main() {
+int i;
+; return 0; }
+EOF
+if { (eval echo configure:2589: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
+  rm -rf conftest*
+  ac_cv_type_signal=void
+else
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -rf conftest*
+  ac_cv_type_signal=int
+fi
+rm -f conftest*
+fi
+
+echo "$ac_t""$ac_cv_type_signal" 1>&6
+cat >> confdefs.h <<EOF
+#define RETSIGTYPE $ac_cv_type_signal
+EOF
+
+
+echo $ac_n "checking for vprintf""... $ac_c" 1>&6
+echo "configure:2608: checking for vprintf" >&5
+if eval "test \"`echo '$''{'ac_cv_func_vprintf'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  cat > conftest.$ac_ext <<EOF
+#line 2613 "configure"
+#include "confdefs.h"
+/* System header to define __stub macros and hopefully few prototypes,
+    which can conflict with char vprintf(); below.  */
+#include <assert.h>
+/* Override any gcc2 internal prototype to avoid an error.  */
+/* We use char because int might match the return type of a gcc2
+    builtin and then its argument prototype would still apply.  */
+char vprintf();
+
+int main() {
+
+/* The GNU C library defines this for functions which it implements
+    to always fail with ENOSYS.  Some functions are actually named
+    something starting with __ and the normal name is an alias.  */
+#if defined (__stub_vprintf) || defined (__stub___vprintf)
+choke me
+#else
+vprintf();
+#endif
+
+; return 0; }
+EOF
+if { (eval echo configure:2636: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+  rm -rf conftest*
+  eval "ac_cv_func_vprintf=yes"
+else
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -rf conftest*
+  eval "ac_cv_func_vprintf=no"
+fi
+rm -f conftest*
+fi
+
+if eval "test \"`echo '$ac_cv_func_'vprintf`\" = yes"; then
+  echo "$ac_t""yes" 1>&6
+  cat >> confdefs.h <<\EOF
+#define HAVE_VPRINTF 1
+EOF
+
+else
+  echo "$ac_t""no" 1>&6
+fi
+
+if test "$ac_cv_func_vprintf" != yes; then
+echo $ac_n "checking for _doprnt""... $ac_c" 1>&6
+echo "configure:2660: checking for _doprnt" >&5
+if eval "test \"`echo '$''{'ac_cv_func__doprnt'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  cat > conftest.$ac_ext <<EOF
+#line 2665 "configure"
+#include "confdefs.h"
+/* System header to define __stub macros and hopefully few prototypes,
+    which can conflict with char _doprnt(); below.  */
+#include <assert.h>
+/* Override any gcc2 internal prototype to avoid an error.  */
+/* We use char because int might match the return type of a gcc2
+    builtin and then its argument prototype would still apply.  */
+char _doprnt();
+
+int main() {
+
+/* The GNU C library defines this for functions which it implements
+    to always fail with ENOSYS.  Some functions are actually named
+    something starting with __ and the normal name is an alias.  */
+#if defined (__stub__doprnt) || defined (__stub____doprnt)
+choke me
+#else
+_doprnt();
+#endif
+
+; return 0; }
+EOF
+if { (eval echo configure:2688: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+  rm -rf conftest*
+  eval "ac_cv_func__doprnt=yes"
+else
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -rf conftest*
+  eval "ac_cv_func__doprnt=no"
+fi
+rm -f conftest*
+fi
+
+if eval "test \"`echo '$ac_cv_func_'_doprnt`\" = yes"; then
+  echo "$ac_t""yes" 1>&6
+  cat >> confdefs.h <<\EOF
+#define HAVE_DOPRNT 1
+EOF
+
+else
+  echo "$ac_t""no" 1>&6
+fi
+
+fi
+
+for ac_func in ftime select strftime strtol getrusage times mallinfo setbuffer getpagesize strerror
+do
+echo $ac_n "checking for $ac_func""... $ac_c" 1>&6
+echo "configure:2715: checking for $ac_func" >&5
+if eval "test \"`echo '$''{'ac_cv_func_$ac_func'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  cat > conftest.$ac_ext <<EOF
+#line 2720 "configure"
+#include "confdefs.h"
+/* System header to define __stub macros and hopefully few prototypes,
+    which can conflict with char $ac_func(); below.  */
+#include <assert.h>
+/* Override any gcc2 internal prototype to avoid an error.  */
+/* We use char because int might match the return type of a gcc2
+    builtin and then its argument prototype would still apply.  */
+char $ac_func();
+
+int main() {
+
+/* The GNU C library defines this for functions which it implements
+    to always fail with ENOSYS.  Some functions are actually named
+    something starting with __ and the normal name is an alias.  */
+#if defined (__stub_$ac_func) || defined (__stub___$ac_func)
+choke me
+#else
+$ac_func();
+#endif
+
+; return 0; }
+EOF
+if { (eval echo configure:2743: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+  rm -rf conftest*
+  eval "ac_cv_func_$ac_func=yes"
+else
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -rf conftest*
+  eval "ac_cv_func_$ac_func=no"
+fi
+rm -f conftest*
+fi
+
+if eval "test \"`echo '$ac_cv_func_'$ac_func`\" = yes"; then
+  echo "$ac_t""yes" 1>&6
+    ac_tr_func=HAVE_`echo $ac_func | tr 'abcdefghijklmnopqrstuvwxyz' 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'`
+  cat >> confdefs.h <<EOF
+#define $ac_tr_func 1
+EOF
+ 
+else
+  echo "$ac_t""no" 1>&6
+fi
+done
+
+for ac_func in ftruncate strstr strcasecmp
+do
+echo $ac_n "checking for $ac_func""... $ac_c" 1>&6
+echo "configure:2770: checking for $ac_func" >&5
+if eval "test \"`echo '$''{'ac_cv_func_$ac_func'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  cat > conftest.$ac_ext <<EOF
+#line 2775 "configure"
+#include "confdefs.h"
+/* System header to define __stub macros and hopefully few prototypes,
+    which can conflict with char $ac_func(); below.  */
+#include <assert.h>
+/* Override any gcc2 internal prototype to avoid an error.  */
+/* We use char because int might match the return type of a gcc2
+    builtin and then its argument prototype would still apply.  */
+char $ac_func();
+
+int main() {
+
+/* The GNU C library defines this for functions which it implements
+    to always fail with ENOSYS.  Some functions are actually named
+    something starting with __ and the normal name is an alias.  */
+#if defined (__stub_$ac_func) || defined (__stub___$ac_func)
+choke me
+#else
+$ac_func();
+#endif
+
+; return 0; }
+EOF
+if { (eval echo configure:2798: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+  rm -rf conftest*
+  eval "ac_cv_func_$ac_func=yes"
+else
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -rf conftest*
+  eval "ac_cv_func_$ac_func=no"
+fi
+rm -f conftest*
+fi
+
+if eval "test \"`echo '$ac_cv_func_'$ac_func`\" = yes"; then
+  echo "$ac_t""yes" 1>&6
+    ac_tr_func=HAVE_`echo $ac_func | tr 'abcdefghijklmnopqrstuvwxyz' 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'`
+  cat >> confdefs.h <<EOF
+#define $ac_tr_func 1
+EOF
+ 
+else
+  echo "$ac_t""no" 1>&6
+LIBOBJS="$LIBOBJS ${ac_func}.${ac_objext}"
+fi
+done
+
+
+
+
+# *** Custom checking (based on GNU tar configure.in) ***
+# ---------------------------------------------------------------------------
+echo $ac_n "checking for HP-UX needing gmalloc""... $ac_c" 1>&6
+echo "configure:2829: checking for HP-UX needing gmalloc" >&5
+if test "`(uname -s) 2> /dev/null`" = 'HP-UX'; then
+  echo "$ac_t""yes" 1>&6
+  LIBOBJS="$LIBOBJS gmalloc.o"
+  cat >> confdefs.h <<\EOF
+#define HAVE_VALLOC 1
+EOF
+
+else
+  echo "$ac_t""no" 1>&6
+  for ac_func in valloc
+do
+echo $ac_n "checking for $ac_func""... $ac_c" 1>&6
+echo "configure:2842: checking for $ac_func" >&5
+if eval "test \"`echo '$''{'ac_cv_func_$ac_func'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  cat > conftest.$ac_ext <<EOF
+#line 2847 "configure"
+#include "confdefs.h"
+/* System header to define __stub macros and hopefully few prototypes,
+    which can conflict with char $ac_func(); below.  */
+#include <assert.h>
+/* Override any gcc2 internal prototype to avoid an error.  */
+/* We use char because int might match the return type of a gcc2
+    builtin and then its argument prototype would still apply.  */
+char $ac_func();
+
+int main() {
+
+/* The GNU C library defines this for functions which it implements
+    to always fail with ENOSYS.  Some functions are actually named
+    something starting with __ and the normal name is an alias.  */
+#if defined (__stub_$ac_func) || defined (__stub___$ac_func)
+choke me
+#else
+$ac_func();
+#endif
+
+; return 0; }
+EOF
+if { (eval echo configure:2870: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+  rm -rf conftest*
+  eval "ac_cv_func_$ac_func=yes"
+else
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -rf conftest*
+  eval "ac_cv_func_$ac_func=no"
+fi
+rm -f conftest*
+fi
+
+if eval "test \"`echo '$ac_cv_func_'$ac_func`\" = yes"; then
+  echo "$ac_t""yes" 1>&6
+    ac_tr_func=HAVE_`echo $ac_func | tr 'abcdefghijklmnopqrstuvwxyz' 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'`
+  cat >> confdefs.h <<EOF
+#define $ac_tr_func 1
+EOF
+ 
+else
+  echo "$ac_t""no" 1>&6
+fi
+done
+
+fi
+
+echo $ac_n "checking if malloc debugging is wanted""... $ac_c" 1>&6
+echo "configure:2897: checking if malloc debugging is wanted" >&5
+# Check whether --with-dmalloc or --without-dmalloc was given.
+if test "${with_dmalloc+set}" = set; then
+  withval="$with_dmalloc"
+  if test "$withval" = yes; then
+  echo "$ac_t""yes" 1>&6
+  cat >> confdefs.h <<\EOF
+#define WITH_DMALLOC 1
+EOF
+
+  LIBS="$LIBS -ldmalloc"
+  LDFLAGS="$LDFLAGS -g"
+else
+  echo "$ac_t""no" 1>&6
+fi
+else
+  echo "$ac_t""no" 1>&6
+fi
+
+
+echo $ac_n "checking which of rx or regex is wanted""... $ac_c" 1>&6
+echo "configure:2918: checking which of rx or regex is wanted" >&5
+# Check whether --with-regex or --without-regex was given.
+if test "${with_regex+set}" = set; then
+  withval="$with_regex"
+  if test "$withval" = yes; then
+  ac_with_regex=1
+  echo "$ac_t""regex" 1>&6
+  cat >> confdefs.h <<\EOF
+#define WITH_REGEX 1
+EOF
+
+  LIBOBJS="$LIBOBJS regex.o"
+fi
+fi
+
+if test -z "$ac_with_regex"; then
+  echo "$ac_t""rx" 1>&6
+  echo $ac_n "checking for re_rx_search""... $ac_c" 1>&6
+echo "configure:2936: checking for re_rx_search" >&5
+if eval "test \"`echo '$''{'ac_cv_func_re_rx_search'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  cat > conftest.$ac_ext <<EOF
+#line 2941 "configure"
+#include "confdefs.h"
+/* System header to define __stub macros and hopefully few prototypes,
+    which can conflict with char re_rx_search(); below.  */
+#include <assert.h>
+/* Override any gcc2 internal prototype to avoid an error.  */
+/* We use char because int might match the return type of a gcc2
+    builtin and then its argument prototype would still apply.  */
+char re_rx_search();
+
+int main() {
+
+/* The GNU C library defines this for functions which it implements
+    to always fail with ENOSYS.  Some functions are actually named
+    something starting with __ and the normal name is an alias.  */
+#if defined (__stub_re_rx_search) || defined (__stub___re_rx_search)
+choke me
+#else
+re_rx_search();
+#endif
+
+; return 0; }
+EOF
+if { (eval echo configure:2964: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+  rm -rf conftest*
+  eval "ac_cv_func_re_rx_search=yes"
+else
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -rf conftest*
+  eval "ac_cv_func_re_rx_search=no"
+fi
+rm -f conftest*
+fi
+
+if eval "test \"`echo '$ac_cv_func_'re_rx_search`\" = yes"; then
+  echo "$ac_t""yes" 1>&6
+  :
+else
+  echo "$ac_t""no" 1>&6
+LIBOBJS="$LIBOBJS rx.o"
+fi
+
+fi
+
+
+# ---------------------------------------------------------------------------
+if test "$ac_cv_func_alloca" = 'no'; then
+  LIBOBJS="$LIBOBJS xmalloc.o error.o"
+fi
+
+
+# ---------------------------------------------------------------------------
+
+ac_ext=C
+# CXXFLAGS is not in ac_cpp because -g, -O, etc. are not valid cpp options.
+ac_cpp='$CXXCPP $CPPFLAGS'
+ac_compile='${CXX-g++} -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext 1>&5'
+ac_link='${CXX-g++} -o conftest${ac_exeext} $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS 1>&5'
+cross_compiling=$ac_cv_prog_cxx_cross
+
+
+echo $ac_n "checking "that the GDBM library is available"""... $ac_c" 1>&6
+echo "configure:3004: checking "that the GDBM library is available"" >&5
+cat > conftest.$ac_ext <<EOF
+#line 3006 "configure"
+#include "confdefs.h"
+#include <gdbm.h>
+
+int main() {
+
+; return 0; }
+EOF
+if { (eval echo configure:3014: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
+  rm -rf conftest*
+  success=yes
+else
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -rf conftest*
+  success=no
+
+fi
+rm -f conftest*
+echo "$ac_t""$success" 1>&6
+if test $success = "no"; then
+{ echo "configure: error: "GDBM Library not available - cannot install"" 1>&2; exit 1; }
+fi
+
+echo $ac_n "checking "that Perl 5 is available"""... $ac_c" 1>&6
+echo "configure:3031: checking "that Perl 5 is available"" >&5
+success="no"
+pl_path="$PATH"
+IFS="${IFS=   }"; pl_save_ifs="$IFS"; IFS=":"
+for pl_dir in $pl_path; do
+  test -z "$pl_dir" && pl_dir=.
+  if test -x $pl_dir/perl; then
+    success="yes"
+    break
+  fi
+done
+IFS="$pl_save_ifs"
+
+if test $success = "yes"; then
+try=`perl configtest.pl` || try="0"
+try=`expr $try \> 5.000`
+if test $try = "1"; then
+echo "$ac_t"""yes"" 1>&6
+else
+success="no"
+fi
+fi
+
+if test $success = "no"; then
+echo "$ac_t"""no"" 1>&6
+{ echo "configure: error: "Perl 5 not available - cannot install"" 1>&2; exit 1; }
+fi
+
+success=no
+echo $ac_n "checking "whether STL library has known faults"""... $ac_c" 1>&6
+echo "configure:3061: checking "whether STL library has known faults"" >&5
+
+cat > conftest.$ac_ext <<EOF
+#line 3064 "configure"
+#include "confdefs.h"
+#include <vector>
+
+int main() {
+
+; return 0; }
+EOF
+if { (eval echo configure:3072: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
+  rm -rf conftest*
+  success=yes
+else
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+fi
+rm -f conftest*
+
+if test $success = "no"; then
+cat > conftest.$ac_ext <<EOF
+#line 3083 "configure"
+#include "confdefs.h"
+#include <vector.h>
+
+int main() {
+
+; return 0; }
+EOF
+if { (eval echo configure:3091: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
+  rm -rf conftest*
+  success="yes"
+else
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+fi
+rm -f conftest*
+fi
+
+if test $success = "no"; then
+cat > conftest.$ac_ext <<EOF
+#line 3103 "configure"
+#include "confdefs.h"
+#include <ospace\\std\\vector>
+
+int main() {
+
+; return 0; }
+EOF
+if { (eval echo configure:3111: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
+  rm -rf conftest*
+  success="yes"
+else
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+fi
+rm -f conftest*
+fi
+
+if test $success = yes; then
+echo "$ac_t"""no"" 1>&6
+else
+echo "$ac_t"""yes"" 1>&6
+{ echo "configure: error: "STL Broken - Obtain newer version of GNU C Compiler"" 1>&2; exit 1; }
+fi
+
+gsdlos=`uname | tr A-Z a-z`
+
+
+echo $ac_n "checking for HP-UX needing gmalloc""... $ac_c" 1>&6
+echo "configure:3132: checking for HP-UX needing gmalloc" >&5
+if test "`(uname -s) 2> /dev/null`" = 'HP-UX'; then
+  echo "$ac_t""yes" 1>&6
+  LIBOBJS="$LIBOBJS gmalloc.o"
+  cat >> confdefs.h <<\EOF
+#define HAVE_VALLOC 1
+EOF
+
+else
+  echo "$ac_t""no" 1>&6
+  for ac_func in valloc
+do
+echo $ac_n "checking for $ac_func""... $ac_c" 1>&6
+echo "configure:3145: checking for $ac_func" >&5
+if eval "test \"`echo '$''{'ac_cv_func_$ac_func'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  cat > conftest.$ac_ext <<EOF
+#line 3150 "configure"
+#include "confdefs.h"
+/* System header to define __stub macros and hopefully few prototypes,
+    which can conflict with char $ac_func(); below.  */
+#include <assert.h>
+/* Override any gcc2 internal prototype to avoid an error.  */
+#ifdef __cplusplus
+extern "C"
+#endif
+/* We use char because int might match the return type of a gcc2
+    builtin and then its argument prototype would still apply.  */
+char $ac_func();
+
+int main() {
+
+/* The GNU C library defines this for functions which it implements
+    to always fail with ENOSYS.  Some functions are actually named
+    something starting with __ and the normal name is an alias.  */
+#if defined (__stub_$ac_func) || defined (__stub___$ac_func)
+choke me
+#else
+$ac_func();
+#endif
+
+; return 0; }
+EOF
+if { (eval echo configure:3176: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+  rm -rf conftest*
+  eval "ac_cv_func_$ac_func=yes"
+else
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -rf conftest*
+  eval "ac_cv_func_$ac_func=no"
+fi
+rm -f conftest*
+fi
+
+if eval "test \"`echo '$ac_cv_func_'$ac_func`\" = yes"; then
+  echo "$ac_t""yes" 1>&6
+    ac_tr_func=HAVE_`echo $ac_func | tr 'abcdefghijklmnopqrstuvwxyz' 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'`
+  cat >> confdefs.h <<EOF
+#define $ac_tr_func 1
+EOF
+ 
+else
+  echo "$ac_t""no" 1>&6
+fi
+done
+
+fi
+
+echo $ac_n "checking if malloc debugging is wanted""... $ac_c" 1>&6
+echo "configure:3203: checking if malloc debugging is wanted" >&5
+# Check whether --with-dmalloc or --without-dmalloc was given.
+if test "${with_dmalloc+set}" = set; then
+  withval="$with_dmalloc"
+  if test "$withval" = yes; then
+  echo "$ac_t""yes" 1>&6
+  cat >> confdefs.h <<\EOF
+#define WITH_DMALLOC 1
+EOF
+
+  LIBS="$LIBS -ldmalloc"
+  LDFLAGS="$LDFLAGS -g"
+else
+  echo "$ac_t""no" 1>&6
+fi
+else
+  echo "$ac_t""no" 1>&6
+fi
+
+
+echo $ac_n "checking which of rx or regex is wanted""... $ac_c" 1>&6
+echo "configure:3224: checking which of rx or regex is wanted" >&5
+# Check whether --with-regex or --without-regex was given.
+if test "${with_regex+set}" = set; then
+  withval="$with_regex"
+  if test "$withval" = yes; then
+  ac_with_regex=1
+  echo "$ac_t""regex" 1>&6
+  cat >> confdefs.h <<\EOF
+#define WITH_REGEX 1
+EOF
+
+  LIBOBJS="$LIBOBJS regex.o"
+fi
+fi
+
+if test -z "$ac_with_regex"; then
+  echo "$ac_t""rx" 1>&6
+  echo $ac_n "checking for re_rx_search""... $ac_c" 1>&6
+echo "configure:3242: checking for re_rx_search" >&5
+if eval "test \"`echo '$''{'ac_cv_func_re_rx_search'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  cat > conftest.$ac_ext <<EOF
+#line 3247 "configure"
+#include "confdefs.h"
+/* System header to define __stub macros and hopefully few prototypes,
+    which can conflict with char re_rx_search(); below.  */
+#include <assert.h>
+/* Override any gcc2 internal prototype to avoid an error.  */
+#ifdef __cplusplus
+extern "C"
+#endif
+/* We use char because int might match the return type of a gcc2
+    builtin and then its argument prototype would still apply.  */
+char re_rx_search();
+
+int main() {
+
+/* The GNU C library defines this for functions which it implements
+    to always fail with ENOSYS.  Some functions are actually named
+    something starting with __ and the normal name is an alias.  */
+#if defined (__stub_re_rx_search) || defined (__stub___re_rx_search)
+choke me
+#else
+re_rx_search();
+#endif
+
+; return 0; }
+EOF
+if { (eval echo configure:3273: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+  rm -rf conftest*
+  eval "ac_cv_func_re_rx_search=yes"
+else
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -rf conftest*
+  eval "ac_cv_func_re_rx_search=no"
+fi
+rm -f conftest*
+fi
+
+if eval "test \"`echo '$ac_cv_func_'re_rx_search`\" = yes"; then
+  echo "$ac_t""yes" 1>&6
+  :
+else
+  echo "$ac_t""no" 1>&6
+LIBOBJS="$LIBOBJS rx.o"
+fi
+
+fi
+
+
+# ---------------------------------------------------------------------------
+if test "$ac_cv_func_alloca" = 'no'; then
+  LIBOBJS="$LIBOBJS xmalloc.o error.o"
+fi
+
+
+# ---------------------------------------------------------------------------
+
+trap '' 1 2 15
+cat > confcache <<\EOF
+# This file is a shell script that caches the results of configure
+# tests run on this system so they can be shared between configure
+# scripts and configure runs.  It is not useful on other systems.
+# If it contains results you don't want to keep, you may remove or edit it.
+#
+# By default, configure uses ./config.cache as the cache file,
+# creating it if it does not exist already.  You can give configure
+# the --cache-file=FILE option to use a different cache file; that is
+# what configure does when it calls configure scripts in
+# subdirectories, so they share the cache.
+# Giving --cache-file=/dev/null disables caching, for debugging configure.
+# config.status only pays attention to the cache file if you give it the
+# --recheck option to rerun configure.
+#
+EOF
+# The following way of writing the cache mishandles newlines in values,
+# but we know of no workaround that is simple, portable, and efficient.
+# So, don't put newlines in cache variables' values.
+# Ultrix sh set writes to stderr and can't be redirected directly,
+# and sets the high bit in the cache file unless we assign to the vars.
+(set) 2>&1 |
+  case `(ac_space=' '; set | grep ac_space) 2>&1` in
+  *ac_space=\ *)
+    # `set' does not quote correctly, so add quotes (double-quote substitution
+    # turns \\\\ into \\, and sed turns \\ into \).
+    sed -n \
+      -e "s/'/'\\\\''/g" \
+      -e "s/^\\([a-zA-Z0-9_]*_cv_[a-zA-Z0-9_]*\\)=\\(.*\\)/\\1=\${\\1='\\2'}/p"
+    ;;
+  *)
+    # `set' quotes correctly as required by POSIX, so do not add quotes.
+    sed -n -e 's/^\([a-zA-Z0-9_]*_cv_[a-zA-Z0-9_]*\)=\(.*\)/\1=${\1=\2}/p'
+    ;;
+  esac >> confcache
+if cmp -s $cache_file confcache; then
+  :
+else
+  if test -w $cache_file; then
+    echo "updating cache $cache_file"
+    cat confcache > $cache_file
+  else
+    echo "not updating unwritable cache $cache_file"
+  fi
+fi
+rm -f confcache
+
+trap 'rm -fr conftest* confdefs* core core.* *.core $ac_clean_files; exit 1' 1 2 15
+
+test "x$prefix" = xNONE && prefix=$ac_default_prefix
+# Let make expand exec_prefix.
+test "x$exec_prefix" = xNONE && exec_prefix='${prefix}'
+
+# Any assignment to VPATH causes Sun make to only execute
+# the first set of double-colon rules, so remove it if not needed.
+# If there is a colon in the path, we need to keep it.
+if test "x$srcdir" = x.; then
+  ac_vpsub='/^[ 	]*VPATH[ 	]*=[^:]*$/d'
+fi
+
+trap 'rm -f $CONFIG_STATUS conftest*; exit 1' 1 2 15
+
+DEFS=-DHAVE_CONFIG_H
+
+# Without the "./", some shells look in PATH for config.status.
+: ${CONFIG_STATUS=./config.status}
+
+echo creating $CONFIG_STATUS
+rm -f $CONFIG_STATUS
+cat > $CONFIG_STATUS <<EOF
+#! /bin/sh
+# Generated automatically by configure.
+# Run this file to recreate the current configuration.
+# This directory was configured as follows,
+# on host `(hostname || uname -n) 2>/dev/null | sed 1q`:
+#
+# $0 $ac_configure_args
+#
+# Compiler output produced by configure, useful for debugging
+# configure, is in ./config.log if it exists.
+
+ac_cs_usage="Usage: $CONFIG_STATUS [--recheck] [--version] [--help]"
+for ac_option
+do
+  case "\$ac_option" in
+  -recheck | --recheck | --rechec | --reche | --rech | --rec | --re | --r)
+    echo "running \${CONFIG_SHELL-/bin/sh} $0 $ac_configure_args --no-create --no-recursion"
+    exec \${CONFIG_SHELL-/bin/sh} $0 $ac_configure_args --no-create --no-recursion ;;
+  -version | --version | --versio | --versi | --vers | --ver | --ve | --v)
+    echo "$CONFIG_STATUS generated by autoconf version 2.13"
+    exit 0 ;;
+  -help | --help | --hel | --he | --h)
+    echo "\$ac_cs_usage"; exit 0 ;;
+  *) echo "\$ac_cs_usage"; exit 1 ;;
+  esac
+done
+
+ac_given_srcdir=$srcdir
+ac_given_INSTALL="$INSTALL"
+
+trap 'rm -fr `echo "packages/mg/Makefile packages/mg/src/text/Makefile packages/mg/src/images/Makefile 
+          packages/mg/src/scripts/Makefile packages/mg/lib/Makefile src/mgpp/Makefile
+	  src/mgpp/text/Makefile src/mgpp/lib/Makefile
+          src/hashfile/Makefile src/colservr/Makefile src/recpt/Makefile src/txt2db/Makefile 
+          src/db2txt/Makefile lib/Makefile Makefile config.h" | sed "s/:[^ ]*//g"` conftest*; exit 1' 1 2 15
+EOF
+cat >> $CONFIG_STATUS <<EOF
+
+# Protect against being on the right side of a sed subst in config.status.
+sed 's/%@/@@/; s/@%/@@/; s/%g\$/@g/; /@g\$/s/[\\\\&%]/\\\\&/g;
+ s/@@/%@/; s/@@/@%/; s/@g\$/%g/' > conftest.subs <<\\CEOF
+$ac_vpsub
+$extrasub
+s%@SHELL@%$SHELL%g
+s%@CFLAGS@%$CFLAGS%g
+s%@CPPFLAGS@%$CPPFLAGS%g
+s%@CXXFLAGS@%$CXXFLAGS%g
+s%@FFLAGS@%$FFLAGS%g
+s%@DEFS@%$DEFS%g
+s%@LDFLAGS@%$LDFLAGS%g
+s%@LIBS@%$LIBS%g
+s%@exec_prefix@%$exec_prefix%g
+s%@prefix@%$prefix%g
+s%@program_transform_name@%$program_transform_name%g
+s%@bindir@%$bindir%g
+s%@sbindir@%$sbindir%g
+s%@libexecdir@%$libexecdir%g
+s%@datadir@%$datadir%g
+s%@sysconfdir@%$sysconfdir%g
+s%@sharedstatedir@%$sharedstatedir%g
+s%@localstatedir@%$localstatedir%g
+s%@libdir@%$libdir%g
+s%@includedir@%$includedir%g
+s%@oldincludedir@%$oldincludedir%g
+s%@infodir@%$infodir%g
+s%@mandir@%$mandir%g
+s%@PACKAGE@%$PACKAGE%g
+s%@VERSION@%$VERSION%g
+s%@USE_FASTCGI@%$USE_FASTCGI%g
+s%@CC@%$CC%g
+s%@CXX@%$CXX%g
+s%@AWK@%$AWK%g
+s%@YACC@%$YACC%g
+s%@INSTALL_PROGRAM@%$INSTALL_PROGRAM%g
+s%@INSTALL_SCRIPT@%$INSTALL_SCRIPT%g
+s%@INSTALL_DATA@%$INSTALL_DATA%g
+s%@LN_S@%$LN_S%g
+s%@SET_MAKE@%$SET_MAKE%g
+s%@RANLIB@%$RANLIB%g
+s%@CPP@%$CPP%g
+s%@U@%$U%g
+s%@ANSI2KNR@%$ANSI2KNR%g
+s%@ALLOCA@%$ALLOCA%g
+s%@LIBOBJS@%$LIBOBJS%g
+s%@gsdlos@%$gsdlos%g
+
+CEOF
+EOF
+
+cat >> $CONFIG_STATUS <<\EOF
+
+# Split the substitutions into bite-sized pieces for seds with
+# small command number limits, like on Digital OSF/1 and HP-UX.
+ac_max_sed_cmds=90 # Maximum number of lines to put in a sed script.
+ac_file=1 # Number of current file.
+ac_beg=1 # First line for current file.
+ac_end=$ac_max_sed_cmds # Line after last line for current file.
+ac_more_lines=:
+ac_sed_cmds=""
+while $ac_more_lines; do
+  if test $ac_beg -gt 1; then
+    sed "1,${ac_beg}d; ${ac_end}q" conftest.subs > conftest.s$ac_file
+  else
+    sed "${ac_end}q" conftest.subs > conftest.s$ac_file
+  fi
+  if test ! -s conftest.s$ac_file; then
+    ac_more_lines=false
+    rm -f conftest.s$ac_file
+  else
+    if test -z "$ac_sed_cmds"; then
+      ac_sed_cmds="sed -f conftest.s$ac_file"
+    else
+      ac_sed_cmds="$ac_sed_cmds | sed -f conftest.s$ac_file"
+    fi
+    ac_file=`expr $ac_file + 1`
+    ac_beg=$ac_end
+    ac_end=`expr $ac_end + $ac_max_sed_cmds`
+  fi
+done
+if test -z "$ac_sed_cmds"; then
+  ac_sed_cmds=cat
+fi
+EOF
+
+cat >> $CONFIG_STATUS <<EOF
+
+CONFIG_FILES=\${CONFIG_FILES-"packages/mg/Makefile packages/mg/src/text/Makefile packages/mg/src/images/Makefile 
+          packages/mg/src/scripts/Makefile packages/mg/lib/Makefile src/mgpp/Makefile
+	  src/mgpp/text/Makefile src/mgpp/lib/Makefile
+          src/hashfile/Makefile src/colservr/Makefile src/recpt/Makefile src/txt2db/Makefile 
+          src/db2txt/Makefile lib/Makefile Makefile"}
+EOF
+cat >> $CONFIG_STATUS <<\EOF
+for ac_file in .. $CONFIG_FILES; do if test "x$ac_file" != x..; then
+  # Support "outfile[:infile[:infile...]]", defaulting infile="outfile.in".
+  case "$ac_file" in
+  *:*) ac_file_in=`echo "$ac_file"|sed 's%[^:]*:%%'`
+       ac_file=`echo "$ac_file"|sed 's%:.*%%'` ;;
+  *) ac_file_in="${ac_file}.in" ;;
+  esac
+
+  # Adjust a relative srcdir, top_srcdir, and INSTALL for subdirectories.
+
+  # Remove last slash and all that follows it.  Not all systems have dirname.
+  ac_dir=`echo $ac_file|sed 's%/[^/][^/]*$%%'`
+  if test "$ac_dir" != "$ac_file" && test "$ac_dir" != .; then
+    # The file is in a subdirectory.
+    test ! -d "$ac_dir" && mkdir "$ac_dir"
+    ac_dir_suffix="/`echo $ac_dir|sed 's%^\./%%'`"
+    # A "../" for each directory in $ac_dir_suffix.
+    ac_dots=`echo $ac_dir_suffix|sed 's%/[^/]*%../%g'`
+  else
+    ac_dir_suffix= ac_dots=
+  fi
+
+  case "$ac_given_srcdir" in
+  .)  srcdir=.
+      if test -z "$ac_dots"; then top_srcdir=.
+      else top_srcdir=`echo $ac_dots|sed 's%/$%%'`; fi ;;
+  /*) srcdir="$ac_given_srcdir$ac_dir_suffix"; top_srcdir="$ac_given_srcdir" ;;
+  *) # Relative path.
+    srcdir="$ac_dots$ac_given_srcdir$ac_dir_suffix"
+    top_srcdir="$ac_dots$ac_given_srcdir" ;;
+  esac
+
+  case "$ac_given_INSTALL" in
+  [/$]*) INSTALL="$ac_given_INSTALL" ;;
+  *) INSTALL="$ac_dots$ac_given_INSTALL" ;;
+  esac
+
+  echo creating "$ac_file"
+  rm -f "$ac_file"
+  configure_input="Generated automatically from `echo $ac_file_in|sed 's%.*/%%'` by configure."
+  case "$ac_file" in
+  *Makefile*) ac_comsub="1i\\
+# $configure_input" ;;
+  *) ac_comsub= ;;
+  esac
+
+  ac_file_inputs=`echo $ac_file_in|sed -e "s%^%$ac_given_srcdir/%" -e "s%:% $ac_given_srcdir/%g"`
+  sed -e "$ac_comsub
+s%@configure_input@%$configure_input%g
+s%@srcdir@%$srcdir%g
+s%@top_srcdir@%$top_srcdir%g
+s%@INSTALL@%$INSTALL%g
+" $ac_file_inputs | (eval "$ac_sed_cmds") > $ac_file
+fi; done
+rm -f conftest.s*
+
+# These sed commands are passed to sed as "A NAME B NAME C VALUE D", where
+# NAME is the cpp macro being defined and VALUE is the value it is being given.
+#
+# ac_d sets the value in "#define NAME VALUE" lines.
+ac_dA='s%^\([ 	]*\)#\([ 	]*define[ 	][ 	]*\)'
+ac_dB='\([ 	][ 	]*\)[^ 	]*%\1#\2'
+ac_dC='\3'
+ac_dD='%g'
+# ac_u turns "#undef NAME" with trailing blanks into "#define NAME VALUE".
+ac_uA='s%^\([ 	]*\)#\([ 	]*\)undef\([ 	][ 	]*\)'
+ac_uB='\([ 	]\)%\1#\2define\3'
+ac_uC=' '
+ac_uD='\4%g'
+# ac_e turns "#undef NAME" without trailing blanks into "#define NAME VALUE".
+ac_eA='s%^\([ 	]*\)#\([ 	]*\)undef\([ 	][ 	]*\)'
+ac_eB='$%\1#\2define\3'
+ac_eC=' '
+ac_eD='%g'
+
+if test "${CONFIG_HEADERS+set}" != set; then
+EOF
+cat >> $CONFIG_STATUS <<EOF
+  CONFIG_HEADERS="config.h"
+EOF
+cat >> $CONFIG_STATUS <<\EOF
+fi
+for ac_file in .. $CONFIG_HEADERS; do if test "x$ac_file" != x..; then
+  # Support "outfile[:infile[:infile...]]", defaulting infile="outfile.in".
+  case "$ac_file" in
+  *:*) ac_file_in=`echo "$ac_file"|sed 's%[^:]*:%%'`
+       ac_file=`echo "$ac_file"|sed 's%:.*%%'` ;;
+  *) ac_file_in="${ac_file}.in" ;;
+  esac
+
+  echo creating $ac_file
+
+  rm -f conftest.frag conftest.in conftest.out
+  ac_file_inputs=`echo $ac_file_in|sed -e "s%^%$ac_given_srcdir/%" -e "s%:% $ac_given_srcdir/%g"`
+  cat $ac_file_inputs > conftest.in
+
+EOF
+
+# Transform confdefs.h into a sed script conftest.vals that substitutes
+# the proper values into config.h.in to produce config.h.  And first:
+# Protect against being on the right side of a sed subst in config.status.
+# Protect against being in an unquoted here document in config.status.
+rm -f conftest.vals
+cat > conftest.hdr <<\EOF
+s/[\\&%]/\\&/g
+s%[\\$`]%\\&%g
+s%#define \([A-Za-z_][A-Za-z0-9_]*\) *\(.*\)%${ac_dA}\1${ac_dB}\1${ac_dC}\2${ac_dD}%gp
+s%ac_d%ac_u%gp
+s%ac_u%ac_e%gp
+EOF
+sed -n -f conftest.hdr confdefs.h > conftest.vals
+rm -f conftest.hdr
+
+# This sed command replaces #undef with comments.  This is necessary, for
+# example, in the case of _POSIX_SOURCE, which is predefined and required
+# on some systems where configure will not decide to define it.
+cat >> conftest.vals <<\EOF
+s%^[ 	]*#[ 	]*undef[ 	][ 	]*[a-zA-Z_][a-zA-Z_0-9]*%/* & */%
+EOF
+
+# Break up conftest.vals because some shells have a limit on
+# the size of here documents, and old seds have small limits too.
+
+rm -f conftest.tail
+while :
+do
+  ac_lines=`grep -c . conftest.vals`
+  # grep -c gives empty output for an empty file on some AIX systems.
+  if test -z "$ac_lines" || test "$ac_lines" -eq 0; then break; fi
+  # Write a limited-size here document to conftest.frag.
+  echo '  cat > conftest.frag <<CEOF' >> $CONFIG_STATUS
+  sed ${ac_max_here_lines}q conftest.vals >> $CONFIG_STATUS
+  echo 'CEOF
+  sed -f conftest.frag conftest.in > conftest.out
+  rm -f conftest.in
+  mv conftest.out conftest.in
+' >> $CONFIG_STATUS
+  sed 1,${ac_max_here_lines}d conftest.vals > conftest.tail
+  rm -f conftest.vals
+  mv conftest.tail conftest.vals
+done
+rm -f conftest.vals
+
+cat >> $CONFIG_STATUS <<\EOF
+  rm -f conftest.frag conftest.h
+  echo "/* $ac_file.  Generated automatically by configure.  */" > conftest.h
+  cat conftest.in >> conftest.h
+  rm -f conftest.in
+  if cmp -s $ac_file conftest.h 2>/dev/null; then
+    echo "$ac_file is unchanged"
+    rm -f conftest.h
+  else
+    # Remove last slash and all that follows it.  Not all systems have dirname.
+      ac_dir=`echo $ac_file|sed 's%/[^/][^/]*$%%'`
+      if test "$ac_dir" != "$ac_file" && test "$ac_dir" != .; then
+      # The file is in a subdirectory.
+      test ! -d "$ac_dir" && mkdir "$ac_dir"
+    fi
+    rm -f $ac_file
+    mv conftest.h $ac_file
+  fi
+fi; done
+
+EOF
+cat >> $CONFIG_STATUS <<EOF
+
+EOF
+cat >> $CONFIG_STATUS <<\EOF
+
+exit 0
+EOF
+chmod +x $CONFIG_STATUS
+rm -fr confdefs* $ac_clean_files
+test "$no_create" = yes || ${CONFIG_SHELL-/bin/sh} $CONFIG_STATUS || exit 1
+
+
+
Index: /main/tags/2.25/gsdl/configure.in
===================================================================
--- /main/tags/2.25/gsdl/configure.in	(revision 21064)
+++ /main/tags/2.25/gsdl/configure.in	(revision 21064)
@@ -0,0 +1,250 @@
+dnl Process this file with autoconf to produce a configure script.
+AC_INIT(lib/text_t.h)
+AC_CONFIG_HEADER(config.h)
+AC_ARG_PROGRAM
+
+PACKAGE=gsdl
+VERSION=2.1
+AC_DEFINE_UNQUOTED(PACKAGE, "$PACKAGE")
+AC_DEFINE_UNQUOTED(VERSION, "$VERSION")
+AC_SUBST(PACKAGE)
+AC_SUBST(VERSION)
+
+USE_FASTCGI=0
+if test USE_FASTCGI = 1; then
+AC_DEFINE(USE_FASTCGI)
+AC_SUBST(USE_FASTCGI)
+fi
+
+dnl Checks for programs.
+LDFLAGS=
+CFLAGS=-O2
+AC_SUBST(CFLAGS)
+
+AC_PROG_CC
+AC_PROG_CXX
+AC_PROG_AWK
+AC_PROG_YACC
+AC_PROG_INSTALL
+AC_PROG_LN_S
+AC_PROG_MAKE_SET
+AC_PROG_RANLIB
+
+
+dnl Checks for typedefs, structures, and compiler characteristics.
+AC_AIX
+AC_ISC_POSIX
+AC_MINIX
+fp_C_PROTOTYPES
+AC_C_CONST
+AC_TYPE_OFF_T
+AC_TYPE_SIZE_T
+AC_HEADER_TIME
+AC_STRUCT_TM
+
+dnl --- This should be in the stdc checking -----------------
+if test "$ac_cv_prog_cc_stdc" = '-Xc'; then
+dnl The Pyramids running SMP_DC.OSx on MIPS r3000 chips with
+dnl /usr/opt/cc3.11/bin/cc treat -Xc as full ANSI mode - no POSIX or
+dnl XOPEN extensions (like popen).
+dnl Unfortunately -D_{XOPEN,POSIX}_SOURCE can't provide all that mg
+dnl needs. So drop back to -Xa
+AC_TRY_COMPILE(
+[#include <stdio.h>
+], [ FILE *rubbish = popen("yes", "r"); ],,
+[CC="`echo $CC | sed 's/-Xc/-Xa/'`"    ac_cv_prog_cc_stdc='-Xa'])
+fi
+dnl ----------------------
+
+
+dnl Checks for libraries.
+dnl Replace `main' with a function in -lg:
+AC_CHECK_LIB(g, main)
+dnl Replace `main' with a function in -lgdbm:
+AC_CHECK_LIB(gdbm, main)
+dnl Replace `main' with a function in -lm:
+AC_CHECK_LIB(m, main)
+dnl Replace `main' with a function in -lstdc++:
+AC_CHECK_LIB(stdc++, main)
+dnl Replace `main' with a function in -lcrypt:
+AC_CHECK_LIB(crypt, main)
+
+
+dnl Checks for header files.
+AC_HEADER_DIRENT
+AC_HEADER_STDC
+AC_CHECK_HEADERS(fcntl.h limits.h sys/time.h unistd.h crypt.h string.h memory.h sys/procfs.h)
+AC_EGREP_HEADER(fread, stdio.h, AC_DEFINE(HAVE_FREAD_DECL))
+AC_EGREP_HEADER(fgetc, stdio.h, AC_DEFINE(HAVE_FGETC_DECL))
+AC_EGREP_HEADER(pr_brksize, sys/procfs.h, AC_DEFINE(HAVE_PR_BRKSIZE))
+
+dnl Checks for library functions.
+AC_FUNC_ALLOCA
+AC_PROG_GCC_TRADITIONAL
+AC_TYPE_SIGNAL
+AC_FUNC_VPRINTF
+AC_CHECK_FUNCS(ftime select strftime strtol getrusage times mallinfo setbuffer getpagesize strerror)
+AC_REPLACE_FUNCS(ftruncate strstr strcasecmp)
+
+
+# *** Custom checking (based on GNU tar configure.in) ***
+# ---------------------------------------------------------------------------
+AC_MSG_CHECKING(for HP-UX needing gmalloc)
+if test "`(uname -s) 2> /dev/null`" = 'HP-UX'; then
+  AC_MSG_RESULT(yes)
+  LIBOBJS="$LIBOBJS gmalloc.o"
+  AC_DEFINE(HAVE_VALLOC)
+else
+  AC_MSG_RESULT(no)
+  AC_CHECK_FUNCS(valloc)
+fi
+
+fp_WITH_DMALLOC
+fp_WITH_REGEX
+
+# ---------------------------------------------------------------------------
+if test "$ac_cv_func_alloca" = 'no'; then
+dnl    support functions for alloca.c
+  LIBOBJS="$LIBOBJS xmalloc.o error.o"
+fi
+
+
+# ---------------------------------------------------------------------------
+
+dnl
+dnl Switch into C++
+dnl
+AC_LANG_CPLUSPLUS
+
+dnl
+dnl Check that the GDBM library is available
+dnl
+AC_MSG_CHECKING("that the GDBM library is available")
+AC_TRY_COMPILE(
+[#include <gdbm.h>
+],
+[],
+success=yes,
+success=no
+)
+AC_MSG_RESULT($success)
+if test $success = "no"; then
+AC_MSG_ERROR("GDBM Library not available - cannot install")
+fi
+
+dnl
+dnl Now check that Perl is actually around, and can be found
+dnl
+AC_MSG_CHECKING("that Perl 5 is available")
+success="no"
+pl_path="$PATH"
+IFS="${IFS=   }"; pl_save_ifs="$IFS"; IFS=":"
+for pl_dir in $pl_path; do
+  test -z "$pl_dir" && pl_dir=.
+  if test -x $pl_dir/perl; then
+    success="yes"
+    break
+  fi
+done
+IFS="$pl_save_ifs"
+
+dnl
+dnl Perl actually can be run; now we see if it is version 5 by
+dnl running a sample script (which returns a "clean" version number
+dnl and then tests the result using expr.  If perl errors in some
+dnl way (eg. broken Perl executable, missing script), we set a failure
+dnl value ("0") and then proceed as best we can
+dnl
+if test $success = "yes"; then
+try=`perl configtest.pl` || try="0"
+try=`expr $try \> 5.000`
+if test $try = "1"; then
+AC_MSG_RESULT("yes")
+else
+success="no"
+fi
+fi
+
+if test $success = "no"; then
+AC_MSG_RESULT("no")
+AC_MSG_ERROR("Perl 5 not available - cannot install")
+fi
+
+dnl
+dnl Check if the STL library has any known faults;
+dnl In GCC 2.7.2.x series, some STL library headers are missing
+dnl a file called "new" which is referred to by other headers
+dnl (eg. vector/vector.h); if this applies, then all use of the
+dnl STL will cause a compile fail, so we'd better let the user
+dnl know now, before things really go wrong!
+dnl
+success=no
+AC_MSG_CHECKING("whether STL library has known faults")
+
+dnl - first shot, try simple good old vector on its own
+AC_TRY_COMPILE(
+[#include <vector>
+], 
+[],
+success=yes,
+)
+
+dnl - try using the .h equivalent
+if test $success = "no"; then
+AC_TRY_COMPILE(
+[#include <vector.h>
+], 
+[],
+success="yes",
+)
+fi
+
+dnl - now try for the objectspace headers
+if test $success = "no"; then
+AC_TRY_COMPILE(
+[#include <ospace\\std\\vector>
+], 
+[],
+success="yes",
+)
+fi
+
+if test $success = yes; then
+AC_MSG_RESULT("no")
+else
+AC_MSG_RESULT("yes")
+AC_MSG_ERROR("STL Broken - Obtain newer version of GNU C Compiler")
+fi
+
+gsdlos=`uname | tr A-Z a-z`
+AC_SUBST(gsdlos)
+
+AC_MSG_CHECKING(for HP-UX needing gmalloc)
+if test "`(uname -s) 2> /dev/null`" = 'HP-UX'; then
+  AC_MSG_RESULT(yes)
+  LIBOBJS="$LIBOBJS gmalloc.o"
+  AC_DEFINE(HAVE_VALLOC)
+else
+  AC_MSG_RESULT(no)
+  AC_CHECK_FUNCS(valloc)
+fi
+
+fp_WITH_DMALLOC
+fp_WITH_REGEX
+
+# ---------------------------------------------------------------------------
+if test "$ac_cv_func_alloca" = 'no'; then
+dnl    support functions for alloca.c
+  LIBOBJS="$LIBOBJS xmalloc.o error.o"
+fi
+
+
+# ---------------------------------------------------------------------------
+
+AC_OUTPUT(packages/mg/Makefile packages/mg/src/text/Makefile packages/mg/src/images/Makefile 
+          packages/mg/src/scripts/Makefile packages/mg/lib/Makefile src/mgpp/Makefile 
+	  src/mgpp/lib/Makefile src/mgpp/text/Makefile
+          src/hashfile/Makefile src/colservr/Makefile src/recpt/Makefile src/txt2db/Makefile 
+          src/db2txt/Makefile lib/Makefile Makefile)
+
+
Index: /main/tags/2.25/gsdl/docs/TODO
===================================================================
--- /main/tags/2.25/gsdl/docs/TODO	(revision 21064)
+++ /main/tags/2.25/gsdl/docs/TODO	(revision 21064)
@@ -0,0 +1,154 @@
+
+configuration/installation:
+	
+unix:
+
+	- look into getting perl scripts to run correctly on any operating
+          system (i.e. the #! stuff) -- those in cgi-bin particularly need
+          to work on windows too (#!perl on windows, #!/use/bin/perl on
+          linux) -- perlrun manpage
+
+	- add fastcgi to distribution
+
+windows:
+
+	- use Installshield to create windows packages - wait for George to
+          decide what he's going to do about InstallShield
+
+	- call server version of cd-rom executable 'standard' and other
+          version 'backup' (or maybe 'gold' and 'silver'?)
+
+	- fix up Local Library - somehow need to have option of old server
+          and single-user (or Gold and Silver?) within same executable.
+
+
+tidy up text versions of macro files
+
+look further into creating images containing non-latin1 characters
+
+create default collection images at build time with gimp script
+
+fix query caching - do caching in receptionist, finish off cross collection
+searching, remove any remaining phrase-searching stuff in queryaction -
+maybe wait for mgpp before worrying about this
+
+create default images/macros for remaining Dublin core metadata elements -
+maybe have a separate macro file for all these things to make it easier to
+add to
+
+write a gzip/bzip/zip/tar plugin and take any remaining gzip stuff out of
+rest of plugins
+
+look at speeding up acronym extraction code, add more options 
+
+create a general classifier for doing stuff like NPepaList.pm does. should
+handle things like HDLs organization classification, HDLs magazines section
+etc.
+
+for gsdl-3.0
+
+  - extend configuration file syntax - tidy up all the format stuff -
+    replace DocumentImages, DocumentTitles and DocumentHeading with
+    DocumentColumn stuff (develop New_Config_Format-branch CVS branch)
+
+  - tidy up classifiers, make collection-specific ones more object oriented
+    (probably create classifier base class), add section and compact
+    options instead of using separate classifiers - get classifiers using
+    same option passing code as plugins now use
+
+  - sort out arrows/paging of browserclasses (for queryaction too!)
+    DocumentBottomArrows?? - want arrows at bottom as well as top of pages
+    for gberg type collections
+
+  - tidy up automatic help text - need to work out type of collection at
+    build time - get rid of the hacky HelpNoDocs, HelpBibDocs and
+    HelpBookDocs config file entries
+
+  - fix up collection specific metadata - content negotiation??
+    "chapters" = "Kapiteln"
+    "section titles" = "Sektionstiteln"
+    "entire books" = "ganzen B&uuml;chern"
+
+  - add ability to use a separate formatstring for each index when
+    displaying query results
+
+  - make interface languages and encodings easier to add. defining
+    languages and encodings should be done in main.cfg (or collect.cfg for
+    collection specific control). should also define:
+      - which encodings a given language may use -- i.e. the preferences page
+      shouldn't let you select an encoding that doesn't work with the
+      currently selected language
+      - which encoding is the default for a given language
+      - which language is the default.
+
+
+tidy things up so that get_collectinfo is only called once per collection
+(at init time for fastcgi) - it's currently being called all over the
+place. maybe load collection info into recpt.collectinfo structure. load in
+as required for each collection so structure would slowly fill up with all
+collections when using fastcgi
+
+add Language metadata to all documents by default??
+
+usage page - Matthias Dalmeier
+
+create a usage page from ftp logs (build on ftp_stats.pl script)
+
+tidy up ohist to remove need for public_html/ohist stuff
+
+WebPlug - optimize to run reasonably quickly? - Currently works (I think)
+but processes each frame within each combination of a frameset - this means
+some html documents are processed hundreds of times and it takes forever to
+build a small collection
+
+update collections - set up auto-updating where needed
+        - csbib
+	- tidbits
+	- tcc - mail updating
+	- niupepa
+	- gberg
+
+sort documents between importing and building
+
+get polling for new collections to work when using fastcgi
+
+ipc and unesco collections have no 'about' text (maybe others too).
+
+compiler warnings
+
+windows cd-rom version 
+
+	- message in browser selection box to say that IE isn't compatible
+	  with 'silver' version (instead of simply greying out selection of
+	  IE as currently happens).
+
+	- look into Belgium bug ("Netscape was unable to create a network
+          socket connection... " -- NT 4.0 -- no internet connection -- run
+          programs/accessories/communication/internet connection wizard,
+          answer LAN to all questions -- bug appears to be present if you
+          get above error message when attempting to access 127.0.0.1 --
+          look into testing for this problem from InstallShield, maybe try
+          reading from 127.0.0.1 and see if it times out?
+
+look into need for _LITTLE_ENDIAN flag in mg
+
+make all external nzdl.org pages plain html rather than macro pages. remove
+all related images from distribution
+
+ohists RealAudio server appears to be broken
+
+capability to view actual BibTeX entries of csbib (and maybe other?)
+collections
+
+scripts for installing w3mir - a .bat version of davids install.sh files
+
+implement proper unicode sorting within classifiers
+
+get file locking to work on non GSDL_USE_IOS_H compilers (VC++ 6.0)
+
+produce an error message when no "built" collections are available
+(currently only produce an error when no collections at all are available)
+
+have another go at getting gsdl_system() function to work properly on
+windows 95 (for end-user collection building)
+
Index: /main/tags/2.25/gsdl/docs/makecol.txt
===================================================================
--- /main/tags/2.25/gsdl/docs/makecol.txt	(revision 21064)
+++ /main/tags/2.25/gsdl/docs/makecol.txt	(revision 21064)
@@ -0,0 +1,158 @@
+How to Make a Collection - A Quick Introduction
+
+                                 Cristian Francu
+                              francu@cs.rutgers.edu
+                                  Jan 12, 2000
+
+First, go to the directory where you installed GSDL.  In order to make
+sure that you can run certain perl scripts you should run either
+setup.bash or setup.csh, depending on the shell you're using:
+
+source setup.bash               or
+
+source setup.csh
+
+This scripts set variables GSDLHOME, GSDLOS and PATH.  Of course you
+can include them in .cshrc or .profile in order to have them set
+automatically.
+
+Next, you should run mkcol.pl in order to create the collection. This
+perl script creates the necessary environment for the collection, like
+directories and the file collect.cfg. The script mkcol.pl is located
+in the directory
+
+bin/script
+
+This directory contains all the scripts that you'll need, so it's a
+good idea to peek at it.
+
+If you run mkcol.pl it will tell you how to use it:
+
+$ mkcol.pl
+
+  usage: mkcol.pl [options] collection-name
+
+  options:
+   -creator email      Your email address
+   -maintainer email   The current maintainer's email address
+   -public true|false  If this collection has anonymous access
+   -beta true|false    If this collection is still under development
+
+After running mkcol.pl the collection will reside in
+collect/<collection-name>. The next thing you should do is edit the
+file
+
+collect/<collection-name>/etc/collect.cfg
+
+You should do at least two things: one is to add a line like this:
+
+collectionmeta iconcollection    "http://sequence.rutgers.edu/~gsdl/collect/cstr/images/cstr.jpg"
+
+This line will set the icon of the collection (the image that users
+will click to access the collection once it's on-line). Make sure you
+type a proper URL of the image between quotes. You should do this at
+this moment, because if you want to change the icon you have to
+rebuild the collection, which is a time consuming operation. Hey,
+gurus, is there any simpler way to change the icon of the collection
+once the collection is already built?
+
+Now, the second thing you should do in the collect.cfg file is add the
+proper plugin on the lines:
+
+plugin        GMLPlug 
+plugin        TEXTPlug 
+plugin        ArcPlug 
+plugin        RecPlug
+
+The plugins you need depend on the format of your documents. If the
+documents are plain text, or GSDL's own format named GML you don't
+need to change anything.  If your documents are in other formats you
+should look for a proper plugin in the directory
+
+perllib/plugins
+
+A very useful plugin is HTMLPlug which can process files with .html and
+.htm file extensions. You would normally replace the TEXTPlug plugin with
+the one you want to use. Say your collection is in html format, than you
+would change the plugin lines to:
+
+plugin       GMLPlug 
+plugin       HTMLPlug
+plugin       ArcPlug 
+plugin       RecPlug
+
+You're finally done with collect.cfg. Suppose you are creating a
+collection named "tutorial". The next thing you should do is go to the
+directory collect/tutorial and create two directories, import and
+archives:
+
+cd collect/tutorial
+mkdir import
+mkdir archives
+
+The material to be indexed should reside in 'import' directory. You
+can either copy it there, or create links to its directory. The
+material to be indexed can contain directories and subdirectories. The
+building script will go recursively into them and search for files to
+be indexed.  This is what the plugin RecPlug does.
+
+So, the next thing to do is make sure you have the documents to be
+indexed in the import directory.  You are now ready to run the
+processing scripts. The fastest way to build a collection is in two
+steps:
+
+1. process the documents in 'import' directory and generate their
+equivalent in .gml format in 'archives' directory
+
+2. process the documents in 'archives' directory (now in .gml format)
+and create the necessary indexes in 'building' directory
+
+For the first step just run the script import.pl:
+
+import.pl tutorial
+
+Depending on the size of your documents this might take between
+minutes and hours. You might also want to redirect stdout and stderr
+to capture the possible errors to files. You can also change the
+verbosity of the script, just run it without arguments and you'll get
+a complete list of options.
+
+For the second step run the script buildcol.pl:
+
+buildcol.pl tutorial
+
+Again, depending on the size of your material to be processed this may
+take minutes to hours. Keep in mind that you must have enough space on
+your hard drive for both steps, as the .gml documents eat up about the
+same amount as the original documents.
+
+If everything went fine, you should now have a directory named
+'building' under collect/tutorial. That directory contains the results
+of the processing of your documents.  In order to use it you have to
+move the content of 'building' directory to a new directory named
+'index'. First create it:
+
+cd collect/tutorial
+mkdir index
+
+Then move the content:
+
+mv building/* index
+
+As long as your collect.cfg file contains the line
+
+public  true
+
+and the collection built successfully the gsdl software should
+automatically notice your new collection. The collection should now appear
+on the main page, which can be accessed at:
+
+http://hostname.domain.edu/cgi-bin/library?a=p&p=home
+
+(replace hostname.domain.edu with the name of your server.)
+
+Keep in mind these instructions are just a jump start
+to get you quickly on the run. There are more options
+you can use and you can explore more of GSDL by reading
+the documentation carefully. You can also email the
+creators for further details.
Index: /main/tags/2.25/gsdl/etc/BUILDVERSION
===================================================================
--- /main/tags/2.25/gsdl/etc/BUILDVERSION	(revision 21064)
+++ /main/tags/2.25/gsdl/etc/BUILDVERSION	(revision 21064)
@@ -0,0 +1,1 @@
+build version: 2.1
Index: /main/tags/2.25/gsdl/etc/VERSION
===================================================================
--- /main/tags/2.25/gsdl/etc/VERSION	(revision 21064)
+++ /main/tags/2.25/gsdl/etc/VERSION	(revision 21064)
@@ -0,0 +1,3 @@
+gsdl version: x.xx
+cvs tag: gsdl-x_xx-distribution
+build version: 2.1
Index: /main/tags/2.25/gsdl/etc/main.cfg
===================================================================
--- /main/tags/2.25/gsdl/etc/main.cfg	(revision 21064)
+++ /main/tags/2.25/gsdl/etc/main.cfg	(revision 21064)
@@ -0,0 +1,18 @@
+maintainer      greenstone@cs.waikato.ac.nz
+
+macrofiles      style.dm base.dm query.dm help.dm pref.dm \
+                about.dm document.dm status.dm authen.dm \
+                users.dm html.dm build.dm extlink.dm delhistory.dm \
+                gsdl.dm english.dm chinese.dm french.dm german.dm maori.dm \
+                english2.dm french2.dm arabic.dm spanish.dm \
+                home.dm
+
+status          enabled
+usecookies      true
+logcgiargs      true
+pageparam       v 0
+macroprecedence c,v,l
+cgiarg          shortname=v longname=version multiplechar=false argdefault=0 \
+                defaultstatus=weak savedarginfo=must
+
+cgiarg          shortname=a argdefault=p
Index: /main/tags/2.25/gsdl/etc/recpt/z3950.cfg
===================================================================
--- /main/tags/2.25/gsdl/etc/recpt/z3950.cfg	(revision 21064)
+++ /main/tags/2.25/gsdl/etc/recpt/z3950.cfg	(revision 21064)
@@ -0,0 +1,35 @@
+[GSDL2.1] # config file version
+#
+# This file specifies a list of z39.50 servers to use.
+# Each field is separated by white-space.
+# If you want a " character inside a string, escape it - ie \" or ""
+
+#<GSDL short name>				collectname
+#<Internet address (default port is 210)>	servername:port
+#<z39.50 server database name>			dbname
+#<Brief description>				"humanname"
+#<optional>					icon "url to icon"  
+#<optional>					smallicon "url to small icon"
+#<optional>					About "about text"
+
+
+#LOCtest
+#       ilssun2.loc.gov:7090
+#       Voyager
+#       "Library of Congress TEST z39.50 server"
+#       About "This database/server is provided by the US LoC for the testing
+#           of z39.50 clients. For server capabilities, look at
+#           <a href=\"http://lcweb.loc.gov/z3950/lcserver.html\">their web 
+#           pages</a>. Note that <b>no records will ever be returned</b> -
+#           this server is for testing the protocols only."
+
+
+LOC
+        z3950.loc.gov:7090
+        Voyager
+        "Library of Congress z39.50 server"
+        About  en  "This is the z39.50 interface to the US LoC catalogue
+           system. It contains approximately 12 million bibliographic records.
+           For server capabilities, look at
+           <a href=\"http://lcweb.loc.gov/z3950/lcserver.html\">their web 
+           pages</a>."
Index: /main/tags/2.25/gsdl/install-sh
===================================================================
--- /main/tags/2.25/gsdl/install-sh	(revision 21064)
+++ /main/tags/2.25/gsdl/install-sh	(revision 21064)
@@ -0,0 +1,238 @@
+#! /bin/sh
+#
+# install - install a program, script, or datafile
+# This comes from X11R5.
+#
+# Calling this script install-sh is preferred over install.sh, to prevent
+# `make' implicit rules from creating a file called install from it
+# when there is no Makefile.
+#
+# This script is compatible with the BSD install script, but was written
+# from scratch.
+#
+
+
+# set DOITPROG to echo to test this script
+
+# Don't use :- since 4.3BSD and earlier shells don't like it.
+doit="${DOITPROG-}"
+
+
+# put in absolute paths if you don't have them in your path; or use env. vars.
+
+mvprog="${MVPROG-mv}"
+cpprog="${CPPROG-cp}"
+chmodprog="${CHMODPROG-chmod}"
+chownprog="${CHOWNPROG-chown}"
+chgrpprog="${CHGRPPROG-chgrp}"
+stripprog="${STRIPPROG-strip}"
+rmprog="${RMPROG-rm}"
+mkdirprog="${MKDIRPROG-mkdir}"
+
+tranformbasename=""
+transform_arg=""
+instcmd="$mvprog"
+chmodcmd="$chmodprog 0755"
+chowncmd=""
+chgrpcmd=""
+stripcmd=""
+rmcmd="$rmprog -f"
+mvcmd="$mvprog"
+src=""
+dst=""
+dir_arg=""
+
+while [ x"$1" != x ]; do
+    case $1 in
+	-c) instcmd="$cpprog"
+	    shift
+	    continue;;
+
+	-d) dir_arg=true
+	    shift
+	    continue;;
+
+	-m) chmodcmd="$chmodprog $2"
+	    shift
+	    shift
+	    continue;;
+
+	-o) chowncmd="$chownprog $2"
+	    shift
+	    shift
+	    continue;;
+
+	-g) chgrpcmd="$chgrpprog $2"
+	    shift
+	    shift
+	    continue;;
+
+	-s) stripcmd="$stripprog"
+	    shift
+	    continue;;
+
+	-t=*) transformarg=`echo $1 | sed 's/-t=//'`
+	    shift
+	    continue;;
+
+	-b=*) transformbasename=`echo $1 | sed 's/-b=//'`
+	    shift
+	    continue;;
+
+	*)  if [ x"$src" = x ]
+	    then
+		src=$1
+	    else
+		# this colon is to work around a 386BSD /bin/sh bug
+		:
+		dst=$1
+	    fi
+	    shift
+	    continue;;
+    esac
+done
+
+if [ x"$src" = x ]
+then
+	echo "install:	no input file specified"
+	exit 1
+else
+	true
+fi
+
+if [ x"$dir_arg" != x ]; then
+	dst=$src
+	src=""
+	
+	if [ -d $dst ]; then
+		instcmd=:
+	else
+		instcmd=mkdir
+	fi
+else
+
+# Waiting for this to be detected by the "$instcmd $src $dsttmp" command
+# might cause directories to be created, which would be especially bad 
+# if $src (and thus $dsttmp) contains '*'.
+
+	if [ -f $src -o -d $src ]
+	then
+		true
+	else
+		echo "install:  $src does not exist"
+		exit 1
+	fi
+	
+	if [ x"$dst" = x ]
+	then
+		echo "install:	no destination specified"
+		exit 1
+	else
+		true
+	fi
+
+# If destination is a directory, append the input filename; if your system
+# does not like double slashes in filenames, you may need to add some logic
+
+	if [ -d $dst ]
+	then
+		dst="$dst"/`basename $src`
+	else
+		true
+	fi
+fi
+
+## this sed command emulates the dirname command
+dstdir=`echo $dst | sed -e 's,[^/]*$,,;s,/$,,;s,^$,.,'`
+
+# Make sure that the destination directory exists.
+#  this part is taken from Noah Friedman's mkinstalldirs script
+
+# Skip lots of stat calls in the usual case.
+if [ ! -d "$dstdir" ]; then
+defaultIFS='	
+'
+IFS="${IFS-${defaultIFS}}"
+
+oIFS="${IFS}"
+# Some sh's can't handle IFS=/ for some reason.
+IFS='%'
+set - `echo ${dstdir} | sed -e 's@/@%@g' -e 's@^%@/@'`
+IFS="${oIFS}"
+
+pathcomp=''
+
+while [ $# -ne 0 ] ; do
+	pathcomp="${pathcomp}${1}"
+	shift
+
+	if [ ! -d "${pathcomp}" ] ;
+        then
+		$mkdirprog "${pathcomp}"
+	else
+		true
+	fi
+
+	pathcomp="${pathcomp}/"
+done
+fi
+
+if [ x"$dir_arg" != x ]
+then
+	$doit $instcmd $dst &&
+
+	if [ x"$chowncmd" != x ]; then $doit $chowncmd $dst; else true ; fi &&
+	if [ x"$chgrpcmd" != x ]; then $doit $chgrpcmd $dst; else true ; fi &&
+	if [ x"$stripcmd" != x ]; then $doit $stripcmd $dst; else true ; fi &&
+	if [ x"$chmodcmd" != x ]; then $doit $chmodcmd $dst; else true ; fi
+else
+
+# If we're going to rename the final executable, determine the name now.
+
+	if [ x"$transformarg" = x ] 
+	then
+		dstfile=`basename $dst`
+	else
+		dstfile=`basename $dst $transformbasename | 
+			sed $transformarg`$transformbasename
+	fi
+
+# don't allow the sed command to completely eliminate the filename
+
+	if [ x"$dstfile" = x ] 
+	then
+		dstfile=`basename $dst`
+	else
+		true
+	fi
+
+# Make a temp file name in the proper directory.
+
+	dsttmp=$dstdir/#inst.$$#
+
+# Move or copy the file name to the temp name
+
+	$doit $instcmd $src $dsttmp &&
+
+	trap "rm -f ${dsttmp}" 0 &&
+
+# and set any options; do chmod last to preserve setuid bits
+
+# If any of these fail, we abort the whole thing.  If we want to
+# ignore errors from any of these, just make sure not to ignore
+# errors from the above "$doit $instcmd $src $dsttmp" command.
+
+	if [ x"$chowncmd" != x ]; then $doit $chowncmd $dsttmp; else true;fi &&
+	if [ x"$chgrpcmd" != x ]; then $doit $chgrpcmd $dsttmp; else true;fi &&
+	if [ x"$stripcmd" != x ]; then $doit $stripcmd $dsttmp; else true;fi &&
+	if [ x"$chmodcmd" != x ]; then $doit $chmodcmd $dsttmp; else true;fi &&
+
+# Now rename the file to the real destination.
+
+	$doit $rmcmd -f $dstdir/$dstfile &&
+	$doit $mvcmd $dsttmp $dstdir/$dstfile 
+
+fi &&
+
+
+exit 0
Index: /main/tags/2.25/gsdl/lib/Makefile.in
===================================================================
--- /main/tags/2.25/gsdl/lib/Makefile.in	(revision 21064)
+++ /main/tags/2.25/gsdl/lib/Makefile.in	(revision 21064)
@@ -0,0 +1,80 @@
+###########################################################################
+#
+# Makefile -- lib
+# A component of the Greenstone digital library software
+# from the New Zealand Digital Library Project at the
+# University of Waikato, New Zealand.
+#
+# Copyright (C) 1999  The 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.
+#
+###########################################################################
+
+
+AR = ar
+CC = @CC@
+#CCFLAGS = @CFLAGS@ -Wall -Wunused -pedantic -W -Woverloaded-virtual
+CCFLAGS = @CFLAGS@
+DEFS = @DEFS@
+INCLUDES = -I../packages/mg/lib
+RANLIB = @RANLIB@
+
+COMPILE = $(CC) -c $(CCFLAGS) $(DEFS) $(INCLUDES)
+
+.SUFFIXES:
+.SUFFIXES: .c .o
+.c.o:
+	$(COMPILE) $<
+
+.SUFFIXES: .cpp .o
+.cpp.o:
+	$(COMPILE) $< 
+
+
+HEADERS = \
+  cfgread.h      fileutil.h     gsdlunicode.h  text_t.h \
+  display.h      gsdlconf.h     gsdltimes.h    gsdltools.h
+
+SOURCES = \
+  cfgread.cpp      fileutil.cpp     text_t.cpp \
+  display.cpp      gsdlunicode.cpp  gsdltimes.cpp  gsdltools.cpp
+
+OBJECTS = \
+  cfgread.o        fileutil.o       text_t.o   \
+  display.o        gsdlunicode.o    gsdltimes.o  gsdltools.o
+
+
+all: gsdllib.a
+
+
+GSDLLIBOBJECTS = $(OBJECTS)
+
+gsdllib.a: $(GSDLLIBOBJECTS)
+	rm -f gsdllib.a
+	$(AR) cru gsdllib.a $(GSDLLIBOBJECTS)
+	$(RANLIB) gsdllib.a
+
+distclean:
+	rm -f $(OBJECTS) gsdllib.a Makefile
+
+clean:
+	rm -f $(OBJECTS) gsdllib.a
+
+install:
+
+depend:
+	makedepend -Y -- $(DEFS) $(INCLUDES) $(CCFLAGS) -- $(SOURCES)
Index: /main/tags/2.25/gsdl/lib/cfgread.cpp
===================================================================
--- /main/tags/2.25/gsdl/lib/cfgread.cpp	(revision 21064)
+++ /main/tags/2.25/gsdl/lib/cfgread.cpp	(revision 21064)
@@ -0,0 +1,123 @@
+/**********************************************************************
+ *
+ * cfgread.cpp -- 
+ * Copyright (C) 1999  The New Zealand Digital Library Project
+ *
+ * A component of the Greenstone digital library software
+ * from the New Zealand Digital Library Project at the
+ * University of Waikato, New Zealand.
+ *
+ * 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.
+ *
+ *********************************************************************/
+
+#include "cfgread.h"
+
+int write_ini_line (ofstream &fileout, const text_t &key, const text_t value) {
+  if (key.empty() || value.empty()) return -1;
+  outconvertclass text_t2ascii;
+  fileout << text_t2ascii << key << "=" << value << "\n";
+  return 0;
+}
+
+int read_ini_line (ifstream &filein, text_t &key, text_t &value) {
+  if (filein.eof()) return -1;
+
+  key.clear();
+  value.clear();
+  char c;
+  filein.get(c);
+
+  int foundeq = 0;
+  while (!filein.eof() && c != '\n') {
+    if (!foundeq && c == '=') {foundeq = 1; filein.get(c);}
+
+    if (foundeq) value.push_back(c);
+    else key.push_back(c);
+    filein.get(c);
+  }
+  if (key.empty()) return -1;
+  return 0;
+} 
+
+
+// returns 0 on success, -1 on failure
+int read_cfg_line (ifstream &filein, text_tarray &values) {
+  //  outconvertclass text_t2ascii;
+
+  values.erase(values.begin(), values.end());
+
+  if (!filein.good()) return -1;
+
+  text_t curvalue;
+  char c, quote;
+
+  bool linecontinues = true;
+  filein.get(c);
+  while (!filein.eof() && linecontinues) {
+    // eat up all return characters
+    while (!filein.eof() && (c=='\n' || c=='\r')) { filein.get(c); }
+
+    // ignore comments
+    if (c == '#') {
+      while (!filein.eof() && c!='\n' && c!='\r') { filein.get(c); }
+    }
+
+    // deal with all the records on this line
+    while (!filein.eof() && c!='\n' && c!='\r') {
+      // ignore white space
+      while (!filein.eof() && (c==' ' || c=='\t')) { filein.get(c); }
+
+      // get the next record
+      if (c!='\n' && c!='\r') {
+	curvalue.clear();
+	quote = 0;
+
+	// see if this is a quoted record
+	if (c=='\'' || c=='\"') {
+	  quote = c;
+	  filein.get(c);
+	}
+
+	// get the value
+	while (!filein.eof() && c!='\n' && c!='\r') {
+	  if (quote != 0 && c == quote) { // end of quote
+	    filein.get(c);
+	    break;
+	  } else if (quote == 0 && (c == ' ' || c == '\t')) {
+	    break; // space seperator
+	  }
+	  curvalue.push_back(c);
+	  filein.get(c);
+	}
+
+	// see if the record continues on the next line
+	if ((c=='\n' || c=='\r') && curvalue=="\\") {
+	  linecontinues = true;
+	} else {
+	  //	  cerr << text_t2ascii << "\"" << curvalue << "\" ";
+	  
+	  values.push_back(curvalue);
+	  curvalue.clear();
+	  linecontinues = false;
+	}
+      }
+    }
+  }
+
+  //  cerr << "\n";
+
+  return 0;
+}
Index: /main/tags/2.25/gsdl/lib/cfgread.h
===================================================================
--- /main/tags/2.25/gsdl/lib/cfgread.h	(revision 21064)
+++ /main/tags/2.25/gsdl/lib/cfgread.h	(revision 21064)
@@ -0,0 +1,46 @@
+/**********************************************************************
+ *
+ * cfgread.h -- reads in configuration files
+ * Copyright (C) 1999  The New Zealand Digital Library Project
+ *
+ * A component of the Greenstone digital library software
+ * from the New Zealand Digital Library Project at the
+ * University of Waikato, New Zealand.
+ *
+ * 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.
+ *
+ *********************************************************************/
+
+
+#ifndef CFGREAD_H
+#define CFGREAD_H
+
+#include "gsdlconf.h"
+#include "text_t.h"
+
+#if defined(GSDL_USE_OBJECTSPACE)
+#  include <ospace\std\fstream>
+#elif defined(GSDL_USE_IOS_H)
+#  include <fstream.h>
+#else
+#  include <fstream>
+#endif
+
+// return 0 on success, -1 on failure
+int write_ini_line (ofstream &fileout, const text_t &key, const text_t value);
+int read_ini_line (ifstream &filein, text_t &key, text_t &value);
+int read_cfg_line (ifstream &filein, text_tarray &values);
+
+#endif
Index: /main/tags/2.25/gsdl/lib/display.cpp
===================================================================
--- /main/tags/2.25/gsdl/lib/display.cpp	(revision 21064)
+++ /main/tags/2.25/gsdl/lib/display.cpp	(revision 21064)
@@ -0,0 +1,1650 @@
+/**********************************************************************
+ *
+ * display.cpp -- Context sensitive macro language
+ * Copyright (C) 1999  The New Zealand Digital Library Project
+ *
+ * A component of the Greenstone digital library software
+ * from the New Zealand Digital Library Project at the
+ * University of Waikato, New Zealand.
+ *
+ * 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.
+ *
+ *********************************************************************/
+
+#include "display.h"
+#include "gsdlunicode.h"
+#include "unitool.h"
+#include <assert.h>
+
+// include to get NULL
+#include <stdlib.h>
+
+
+
+/////////////////////////////////////
+// misc classes
+/////////////////////////////////////
+
+
+// precedencetype defines a 'precedence value' for each parameter
+typedef map<text_t, double, lttext_t> precedencetype;
+
+
+// macro value structure
+struct mvalue
+{
+  text_t filename;
+  text_t value;
+};
+
+inline bool operator==(const mvalue &x, const mvalue &y) {
+  return (x.filename==y.filename && x.value==y.value);
+}
+
+inline bool operator<(const mvalue &x, const mvalue &y) {
+  return (x.filename<y.filename ||
+	  (x.filename==y.filename && x.filename<y.filename));
+}
+
+
+
+/////////////////////////////////////
+// stuff for defaultmacros_t
+/////////////////////////////////////
+  
+typedef map<text_t, mvalue, lttext_t> defparammap;
+typedef map<text_t, defparammap, lttext_t> defmacromap;
+typedef map<text_t, defmacromap, lttext_t> defpackagemap;
+
+// all methods in defaultmacros_t assume the parameters
+// and packages in a standard form and not empty
+class defaultmacros_t
+{
+protected:
+  defpackagemap macros;
+
+public:
+  typedef defpackagemap::const_iterator const_package_iterator;
+  typedef defpackagemap::size_type package_size_type;
+
+  // setmacro returns 0 if there was no error,
+  //            -1 if it redefined a macro
+  //            -2 if it hid a Global macro
+  //            -3 if it redefined a macro and hid a Global macro
+  //            -4 if either a package, macroname, or params were not supplied
+  int setmacro(const text_t &package,
+	  const text_t &macroname, 
+	  const text_t &params, 
+	  const text_t &filename, 
+	  const text_t &macrovalue);
+
+  void delmacro(const text_t &package,
+	      const text_t &macroname, 
+	      const text_t &params);
+
+  void clear () {macros.erase(macros.begin(), macros.end());}
+
+  // top level stuff
+  const_package_iterator package_begin () const {return macros.begin();}
+  const_package_iterator package_end () const {return macros.end();}
+  bool package_empty () const {return macros.empty();}
+  package_size_type package_size() const {return macros.size();}
+
+  // methods to find things
+  defmacromap *package_find (const text_t &packagename);
+  defparammap *macro_find (const text_t &packagename, 
+			   const text_t &macroname);
+  mvalue *parameter_find (const text_t &packagename, 
+			  const text_t &macroname,
+			  const text_t &parametername);
+};
+
+
+// setmacro returns 0 if there was no error,
+//            -1 if it redefined a macro
+//            -2 if it hid a Global macro
+//            -3 if it redefined a macro and hid a Global macro
+//            -4 if either a package, macroname, or params were not supplied
+int defaultmacros_t::setmacro(const text_t &package,
+			 const text_t &macroname, 
+			 const text_t &params, 
+			 const text_t &filename, 
+			 const text_t &macrovalue)
+{
+  paramhashtype paramhash;
+
+  defmacromap *macromapptr;
+  defparammap *parammapptr;
+  mvalue *mvalueptr;
+
+  int warning = 0;
+
+  // check to see if we would be hiding a Global macro with the 
+  // same name. Note: it doesn't matter what parameters are used
+  // a Global macro will still be hid by a non-Global one with
+  // the same name.
+  if ((package != "Global") && 
+      (macro_find ("Global", macroname) != NULL))
+    {
+      warning -= 2; // found the macroname
+    }
+
+  // define this macro
+  macromapptr = &(macros[package]); // -- package
+  parammapptr = &((*macromapptr)[macroname]); // -- macro name
+  // -- parameters
+  if ((*parammapptr).find(params) != (*parammapptr).end()) {
+    warning -= 1; // found the parameters
+  }
+  mvalueptr = &((*parammapptr)[params]);
+
+  // -- value
+  (*mvalueptr).filename = filename;
+  (*mvalueptr).value = macrovalue;
+
+  return warning;
+}
+
+void defaultmacros_t::delmacro(const text_t &package,
+			     const text_t &macroname, 
+			     const text_t &params)
+{
+  // make sure everything was supplied
+  if (package.empty() || macroname.empty() || params.empty()) return;
+
+  // find the package and macroname
+  defparammap *parammapptr = macro_find(package, macroname);
+  if (parammapptr == NULL) return;
+
+  // find the parameters
+  defparammap::iterator parammapit = parammapptr->find(params);
+  if (parammapit == parammapptr->end()) return;
+
+  // finally delete this element
+  parammapptr->erase(parammapit);
+}
+
+defmacromap *defaultmacros_t::package_find (const text_t &packagename)
+{
+  if (packagename.empty()) return NULL;
+
+  defpackagemap::iterator it = macros.find(packagename);
+  if (it == macros.end()) return NULL;
+
+  return &((*it).second);
+}
+
+defparammap *defaultmacros_t::macro_find (const text_t &packagename, 
+					       const text_t &macroname)
+{
+  defmacromap *macromapptr = package_find(packagename);
+  if (macromapptr == NULL || macroname.empty()) return NULL;
+
+  defmacromap::iterator it = (*macromapptr).find(macroname);
+  if (it == (*macromapptr).end()) return NULL;
+
+  return &((*it).second);
+}
+
+mvalue *defaultmacros_t::parameter_find (const text_t &packagename, 
+					 const text_t &macroname,
+					 const text_t &parametername)
+{
+  defparammap *parammapptr = macro_find(packagename, macroname);
+  if (parammapptr == NULL || parametername.empty()) return NULL;
+
+  defparammap::iterator it = (*parammapptr).find(parametername);
+  if (it == (*parammapptr).end()) return NULL;
+
+  return &((*it).second);
+}
+
+
+
+/////////////////////////////////////
+// stuff for currentmacros_t
+/////////////////////////////////////
+
+typedef map<text_t, mvalue, lttext_t> curmacromap;
+typedef map<text_t, curmacromap, lttext_t> curpackagemap;
+
+// all methods in currentmacros_t assume the parameters
+// and packages in a standard form and not empty
+class currentmacros_t 
+{
+protected:
+  curpackagemap macros;
+
+public:
+  typedef curpackagemap::const_iterator const_package_iterator;
+  typedef curpackagemap::size_type package_size_type;
+
+  // setmacro returns 0 if there was no error,
+  //            -1 if it redefined a macro
+  //            -4 if either a package, or macroname were not supplied
+  int setmacro(const text_t &package,
+	  const text_t &macroname, 
+	  const text_t &filename, 
+	  const text_t &macrovalue);
+
+  void delmacro(const text_t &package,
+		const text_t &macroname);
+
+  void clear () {macros.erase(macros.begin(), macros.end());}
+
+  // top level stuff
+  const_package_iterator package_begin () const {return macros.begin();}
+  const_package_iterator package_end () const {return macros.end();}
+  bool package_empty () const {return macros.empty();}
+  package_size_type package_size() const {return macros.size();}
+
+  // methods to find things
+  curmacromap *package_find (const text_t &packagename);
+  mvalue *macro_find (const text_t &packagename, 
+		      const text_t &macroname);
+};
+
+
+// setmacro returns 0 if there was no error,
+//            -1 if it redefined a macro
+//            -4 if either a package, or macroname were not supplied
+int currentmacros_t::setmacro(const text_t &package,
+			 const text_t &macroname, 
+			 const text_t &filename, 
+			 const text_t &macrovalue)
+{
+  int warning = 0;
+
+  // make sure everything was supplied
+  if (package.empty() || macroname.empty()) return -4;
+
+  // define this macro
+  curmacromap *macromapptr = &(macros[package]);
+  if ((*macromapptr).find(macroname) != (*macromapptr).end()) 
+    {
+      warning -= 1; // found the macroname
+    }
+  mvalue *mvalueptr = &((*macromapptr)[macroname]);
+
+  // -- value
+  (*mvalueptr).filename = filename;
+  (*mvalueptr).value = macrovalue;
+
+  return warning;
+}
+
+void currentmacros_t::delmacro(const text_t &package,
+			     const text_t &macroname)
+{
+  // make sure everything was supplied
+  if (package.empty() || macroname.empty()) return;
+
+  // find the package
+  curmacromap *macromapptr = package_find(package);
+  if (macromapptr == NULL) return;
+
+  // find the macroname
+  curmacromap::iterator macromapit = macromapptr->find(macroname);
+  if (macromapit == macromapptr->end()) return;
+
+  // finally delete this element
+  macromapptr->erase(macromapit);
+}
+
+curmacromap *currentmacros_t::package_find (const text_t &packagename)
+{
+  if (packagename.empty()) return NULL;
+
+  curpackagemap::iterator it = macros.find(packagename);
+  if (it == macros.end()) return NULL;
+
+  return &((*it).second);
+}
+
+mvalue *currentmacros_t::macro_find (const text_t &packagename, 
+				     const text_t &macroname)
+{
+  curmacromap *macromapptr = package_find(packagename);
+  if (macromapptr == NULL || macroname.empty()) return NULL;
+
+  curmacromap::iterator it = (*macromapptr).find(macroname);
+  if (it == (*macromapptr).end()) return NULL;
+
+  return &((*it).second);
+}
+
+
+
+
+/////////////////////////////////////
+// support functions
+/////////////////////////////////////
+
+// this calculation of precedence will make one occurance of a high
+// precedence item override many occurances of lower precedence items
+void calcprecedence (const text_t &precedstr, precedencetype &precedhash) 
+{
+  text_t param;
+  double multiple = 5.0;
+  double nextprec = multiple;
+
+  text_t::const_iterator here, end;
+
+  // set precedhash to an empty hash
+  precedhash.erase(precedhash.begin(), precedhash.end());
+
+  // iterate through paramstring ignoring space and extracting
+  // out key value pairs.
+  here = precedstr.begin();
+  end = precedstr.end();
+  while (here != end) 
+    {
+      // get the next parameter
+      param.clear(); // set param to an empty string
+      
+      while (here != end) 
+	{
+	  if (*here == ',') 
+	    {
+	      // found the end of the parameter
+	      here++;
+	      break;
+	    } 
+	  else if (*here == ' ') 
+	    {
+	      // do nothing (ignore spaces)
+	    } 
+	  else 
+	    {
+	      // character in parameter
+	      param.push_back (*here); // copy this character
+	    }
+	  
+	  here++;
+	}
+
+      // if a parameter was found insert its value
+      if (!param.empty()) 
+	{
+	  precedhash[param] = nextprec;
+	  nextprec *= multiple;
+	}
+    }
+}
+
+
+// decides how specific any given parameter is to the page parameters. Returns 
+// negative if any options are different or else the sum of the precedence for
+// the options which match. 
+double getspecificness(const paramhashtype &pageparams, 
+		       const paramhashtype &theseparams, 
+		       const precedencetype &precedhash) 
+{
+  double specificness = 0.0;
+  paramhashtype::const_iterator here, pagevalueit;
+  precedencetype::const_iterator precedit;
+  text_t thesekey, thesevalue, constignore("ignore");
+  
+  here = theseparams.begin();
+  while (here != theseparams.end()) 
+    {
+      thesekey = (*here).first;
+      thesevalue = (*here).second;
+      
+      if (thesekey == constignore) 
+	{
+	  // do nothing, this is a placeholder
+	} 
+      else 
+	{
+	  pagevalueit = pageparams.find(thesekey);
+	  if ((pagevalueit != pageparams.end()) && 
+	      ((*pagevalueit).second == thesevalue)) 
+	    {
+	      // this parameter fits, add its precedence value
+	      precedit = precedhash.find(thesekey);
+	      if (precedit == precedhash.end()) 
+		specificness += 1.0; // no precedence defined
+	      else 
+		  specificness += (*precedit).second;
+	    }
+	  else 
+	    {
+	      return -1.0; // did not match
+	    }
+	}
+
+      here++;
+    }
+  
+  return specificness;
+}
+
+
+void splitparams (const text_t &paramstring, paramhashtype &paramhash)
+{
+  text_t key;
+  text_t value;
+
+  text_t::const_iterator here, end;
+
+  // set paramhash to an empty hash
+  paramhash.erase(paramhash.begin(), paramhash.end());
+
+  // iterate through paramstring ignoring space and extracting
+  // out key value pairs.
+  here = paramstring.begin();
+  end  = paramstring.end();
+  while (here != end) 
+    {
+      // reset key and value
+      key.clear();
+      value.clear();
+
+      // get key
+      while (here != end) 
+	{
+	  if (*here == ',') 
+	    {
+	      // have a key with no value
+	      break;
+	    } 
+	  else if (*here == '=') 
+	    {
+	      // found the end of the key
+	      here ++; 
+	      break;
+	    } 
+	  else if (*here == ' ') 
+	    {
+	      // do nothing (ignore spaces)
+	    } 
+	  else 
+	    {
+	      // character in key
+	      key.push_back (*here); // copy this character
+	    }
+	  here ++;
+	}
+
+      // get value
+      while (here != end) 
+	{
+	  if (*here == '=') 
+	    {
+	      // multiple values for one key, ignore previous
+	      // values
+	      value.clear();
+	    } 
+	  else if (*here == ',') 
+	    {
+	      // found the end of the value
+	      here ++;
+	      break;
+	    } 
+	  else if (*here == ' ') 
+	    {
+	      // do nothing (ignore spaces)
+	    } 
+	  else 
+	    {
+	      // character in value
+	      value.push_back (*here); // copy this character
+	    }
+	  here ++;
+	}
+    
+      // if a key was found insert the key/value pair in 
+      // the map 
+      if (!key.empty()) 
+	{
+	  paramhash[key] = value;
+	}
+    }
+}
+
+
+void joinparams (const paramhashtype &paramhash, text_t &paramstring)
+{
+  //set paramstring to an empty string
+  paramstring.clear();
+
+  //iterate through the paramhash
+  paramhashtype::const_iterator thepair;
+  int firstparam = 1;
+
+  for (thepair=paramhash.begin();thepair!=paramhash.end(); thepair++)
+    {
+      if (!firstparam) paramstring.push_back(',');
+      firstparam = 0;
+      
+      // insert pairs of "key=value"
+      text_t thevalue;
+      paramstring.append((*thepair).first);
+      paramstring.push_back('=');
+      paramstring.append((*thepair).second);
+    }
+}
+
+
+
+/////////////////////////////////////
+// parsing support functions
+/////////////////////////////////////
+
+inline int my_isalpha (unsigned short c) 
+{
+  return ((c >= 'A' && c <= 'Z') ||
+	  (c >= 'a' && c <= 'z'));
+} 
+
+
+
+inline unsigned short my_ttnextchar (text_t::const_iterator &here, 
+				     text_t::const_iterator &end) 
+{
+  if (here != end) 
+    {
+      here++;
+      if (here != end) return (*here);
+    }
+  return '\0';
+}
+
+
+
+/////////////////////////////////////
+// methods for display
+/////////////////////////////////////
+
+// public methods for display
+
+displayclass::displayclass ()
+{
+  defaultmacros = new defaultmacros_t;
+  defaultfiles = new fileinfomap;
+  
+  orderparamlist = new paramspeclist;
+  currentmacros = new currentmacros_t;
+
+  outc = NULL;
+
+  logout = &cerr;
+}
+
+
+displayclass::~displayclass ()
+{
+  delete defaultmacros;
+  delete defaultfiles;
+  
+  delete orderparamlist;
+  delete currentmacros;
+}
+  
+// setdefaultmacro adds an entry to the list of default macros 
+// returns 0 if there was no error,
+//        -1 if it redefined a macro
+//        -2 if it hid a Global macro
+//        -3 if it redefined a macro and hid a Global macro
+//        -4 if no macroname was supplied
+int displayclass::setdefaultmacro (text_t package, const text_t &macroname, 
+			      text_t params, const text_t &macrovalue) 
+{
+  return setdefaultmacro (macroname, package, params, macrovalue, "memory");
+}
+
+
+
+// as we are using one character lookahead the
+// value of line might be off by one.
+// the input file must be in the utf-8 or unicode format
+// initially for each file isunicode should be set to 0 and 
+// bigendian should be set to 1
+// 0 will be returned when the end of the file has been found
+unsigned short my_uni_get (unistream &fin, int &line, 
+			   int &isunicode, int &bigendian) {
+  unsigned short c = 0;
+  
+  if (isunicode) {
+    // unicode text
+    // get the next two characters
+    unsigned char c1 = 0, c2 = 0;
+    
+    if (!fin.eof()) fin.get(c1);
+    if (!fin.eof()) fin.get(c2);
+    else c1 = 0;
+
+    // if they indicate the order get the next character
+    // otherwise just get these characters
+    if (c1 == 0xff && c2 == 0xfe) {
+      bigendian = 0;
+      c = my_uni_get (fin, line, isunicode, bigendian);
+    } else if (c1 == 0xfe && c2 == 0xff) {
+      bigendian = 1;
+      c = my_uni_get (fin, line, isunicode, bigendian);
+    } else c = (bigendian) ? (c1*256+c2) : (c2*256+c1);
+    
+  } else {
+    // utf-8 text
+    // how many characters we get depends on what we find
+    unsigned char c1 = 0, c2 = 0, c3 = 0;
+    while (!fin.eof()) {
+      fin.get(c1);
+      if (c1 == 0xfe || c1 == 0xff) {
+	// switch to unicode
+	isunicode = 1;
+	if (!fin.eof()) fin.get(c2);
+
+	if (c1 == 0xff && c2 == 0xfe) bigendian = 0;
+	else bigendian = 1;
+
+	c = my_uni_get (fin, line, isunicode, bigendian);
+	break;
+
+      } else if (c1 <= 0x7f) {
+	// one byte character
+	c = c1;
+	break;
+
+      } else if (c1 >= 0xc0 && c1 <= 0xdf) {
+	// two byte character
+	if (!fin.eof()) fin.get(c2);
+	c = ((c1 & 0x1f) << 6) + (c2 & 0x3f);
+	break;
+
+      } else if (c1 >= 0xe0 && c1 <= 0xef) {
+	// three byte character
+	if (!fin.eof()) fin.get(c2);
+	if (!fin.eof()) fin.get(c3);
+	c = ((c1 & 0xf) << 12) + ((c2 & 0x3f) << 6) + (c3 & 0x3f);
+	break;
+      }
+
+      // if we get here there was an error in the file, we should
+      // be able to recover from it however, maybe the file is in
+      // another encoding
+    }
+  }
+
+  if (c == '\n') line++;
+  return c;
+}
+
+
+
+// loads a default macro file (if it isn't already loaded)
+// returns 0 if didn't need to load the file (it was already loaded)
+//         1 if was (re)loaded
+//        -1 an error occurred while trying to load the file
+int displayclass::loaddefaultmacros (text_t thisfilename) {
+  // convert the filename to a C string
+  char *filenamestr = thisfilename.getcstr();
+  outconvertclass text_t2ascii;
+
+  // see if we need to open this file -- this isn't implemented yet
+  
+  // open the file
+  unistream fin (filenamestr);
+
+  if (fin.fail()) return -1; // read failed
+
+  text_t package = "Global";
+  int line = 1;
+  int isunicode = 0, bigendian = 1;
+
+  // pre-fetch the next character
+  unsigned short c = my_uni_get(fin, line, isunicode, bigendian);
+
+  text_t macropackage, macroname, macroparameters, macrovalue;
+  int err; // for keeping track of whether an error occurred somewhere
+
+  while (!fin.eof()) {
+    // expect: white space, comment, "package", or macroname
+    if (is_unicode_space(c)) {
+      // found some white-space
+      c = my_uni_get(fin, line, isunicode, bigendian);
+
+    } else if (c == '#') {
+      // found the start of a comment
+      // skip all characters up to the end of the line
+      c = my_uni_get(fin, line, isunicode, bigendian); // skip the '#'
+      while (!fin.eof ()) {
+	if (c == '\n') break;
+	c = my_uni_get(fin, line, isunicode, bigendian);
+      }
+
+    } else if (c == 'p') {
+      // found the start of 'package' (hopefully)
+      // get everything up to the next space
+      text_t tmp;
+      while (!fin.eof() && my_isalpha(c)) {
+	tmp.push_back(c);
+	c = my_uni_get(fin, line, isunicode, bigendian);
+      }
+      // see if we have a package name
+      if (tmp == "package") {
+	// skip all white space
+	while (!fin.eof() && is_unicode_space(c)) 
+	  c = my_uni_get(fin, line, isunicode, bigendian);
+	
+	// get the package name
+	tmp.clear(); // init tmp
+	while (!fin.eof() && my_isalpha(c)) {
+	  tmp.push_back(c);
+	  c = my_uni_get(fin, line, isunicode, bigendian);
+	}
+	package = tmp;
+	if (package.empty()) package = "Global";
+
+      } else {
+	// error
+	if (logout != NULL) {
+	  (*logout) << text_t2ascii << "Expected 'package' on line " << line 
+		    << " of " << thisfilename << "\n";
+	}
+      }
+      
+    } else if (c == '_') {
+      // found the start of a macro (hopefully)
+      c = my_uni_get(fin, line, isunicode, bigendian); // skip the _
+
+      // init variables
+      err = 0;
+      macropackage = package;
+      macroname.clear(); // init macroname
+      macroparameters.clear(); // init macroname
+      macrovalue.clear(); // init macroname
+      
+      // get the macro name
+      while ((!fin.eof()) && (!is_unicode_space(c)) && 
+	     (c != '\\') && (c != '_') &&(c != ':') && 
+	     (macroname.size() < 80)) {
+	macroname.push_back(c);
+	c = my_uni_get(fin, line, isunicode, bigendian);
+      }
+	  
+      if (c == ':') {
+	// we actually had the macro package
+	c = my_uni_get(fin, line, isunicode, bigendian); // skip :
+	macropackage = macroname;
+	macroname.clear ();
+	
+	// get the macro name (honest!)
+	while ((!fin.eof()) && (!is_unicode_space(c)) && 
+	       (c != '\\') && (c != '_') &&(c != ':') && 
+	       (macroname.size() < 80)) {
+	  macroname.push_back(c);
+	  c = my_uni_get(fin, line, isunicode, bigendian);
+	}
+      }
+      
+      if (!err && c == '_') {
+	c = my_uni_get(fin, line, isunicode, bigendian); // skip the _
+	
+	// skip all white space
+	while (!fin.eof() && is_unicode_space(c)) c = my_uni_get(fin, line, isunicode, bigendian);
+      } else if (!err) err = 1;
+
+      // get the macro parameters (optional)
+      if (!err && c == '[') {
+	c = my_uni_get(fin, line, isunicode, bigendian); // skip the [
+	while ((!fin.eof()) && (c != '\n') && (c != '\\') && (c != ']')) {
+	  macroparameters.push_back(c);
+	  c = my_uni_get(fin, line, isunicode, bigendian);
+	}
+	
+	if (c == ']') {
+	  c = my_uni_get(fin, line, isunicode, bigendian); // skip the ]
+	  
+	  // skip all white space
+	  while (!fin.eof() && is_unicode_space(c)) c = my_uni_get(fin, line, isunicode, bigendian);
+	} 
+	else if (!err) err = 2;
+      }
+
+      // get the macro value
+      if (!err && c == '{') {
+	c = my_uni_get(fin, line, isunicode, bigendian); // skip the {
+	while ((!fin.eof()) && (c != '}')) {
+	  if (c == '\\') {
+	    macrovalue.push_back(c); // keep the '\'
+	    c = my_uni_get(fin, line, isunicode, bigendian); // store the *next* value regardless
+	    if (!fin.eof()) macrovalue.push_back(c);
+	    c = my_uni_get(fin, line, isunicode, bigendian);
+	  }
+	  macrovalue.push_back(c);
+	  c = my_uni_get(fin, line, isunicode, bigendian);
+	}
+	
+	if (c == '}') {
+	  c = my_uni_get(fin, line, isunicode, bigendian); // skip the }
+	  
+	  // define the macro
+	  err = setdefaultmacro (macropackage, macroname, macroparameters,
+				 thisfilename, macrovalue);
+	  if ((err == -1 || err == -3) && logout != NULL) {
+	    (*logout) << text_t2ascii << "Warning: redefinition of _" << 
+	      package << ":" << macroname << "_[" << macroparameters <<
+	      "] on line ";
+	    (*logout) << line;
+	    (*logout) << text_t2ascii << " of " << thisfilename << "\n";
+	    
+	  } else if (err == -2 && logout != NULL) {
+	    (*logout) << text_t2ascii << "Warning: _" << 
+	      package << ":" << macroname << "_[" << macroparameters <<
+	      "] on line ";
+	    (*logout) << line;
+	    (*logout) << text_t2ascii << " of " << 
+	      thisfilename << " hides a Global macro with the same name\n";
+
+	  } else if (err == -4 && logout != NULL) {
+	    (*logout) << text_t2ascii << "Error: macro name expected on line ";
+	    (*logout) << line ;
+	    (*logout) << text_t2ascii << " of " << thisfilename << "\n";
+	  }		  
+	  
+	  err = 0; // for the test below
+	}
+	else if (!err) err = 3;
+      }
+      else if (!err) err = 4;
+      
+      if (err) {
+	// found an error, skip to the end of the line
+	if (logout != NULL) {
+	  (*logout) << text_t2ascii << "Error: ";
+	  if (err == 1) (*logout) << text_t2ascii << "'_'";
+	  else if (err == 2) (*logout) << text_t2ascii << "']'";
+	  else if (err == 3) (*logout) << text_t2ascii << "'}'";
+	  else if (err == 4) (*logout) << text_t2ascii << "'{'";
+	  (*logout) << text_t2ascii << " expected on line ";
+	  (*logout) << line ;
+	  (*logout) << text_t2ascii << " of " << thisfilename << "\n";
+	}
+	while (!fin.eof ()) {
+	  if (c == '\n') break;
+	  c = my_uni_get(fin, line, isunicode, bigendian);
+	}
+      }
+      
+    } else {
+      // found an error, skip to the end of the line
+      if (logout != NULL) {
+	(*logout) << text_t2ascii << "Error: Unexpected input on line " << line 
+		  << " of " << thisfilename << "\n";
+      }
+      while (!fin.eof ()) {
+	if (c == '\n') break;
+	c = my_uni_get(fin, line, isunicode, bigendian);
+      }
+      
+    }
+  }
+  
+  fin.close ();
+  
+  // free up memory
+  delete filenamestr;
+  return 0;
+}
+
+
+// prepares to create a page.
+void displayclass::openpage (const text_t &thispageparams, 
+			const text_t &thisprecedence)
+{
+  // init variables
+  currentmacros->clear();
+
+  // reload any default macro files which have changed.
+  if (checkdefaultmacrofiles() < 0) 
+    {
+      // print error message
+    }
+
+  setpageparams (thispageparams, thisprecedence);
+}
+
+
+// changes the parameters for the current page.
+void displayclass::setpageparams (text_t thispageparams, 
+			     text_t thisprecedence)
+{
+  paramhashtype thissplitparams, splittheseparams;
+  precedencetype precedhash;
+  text_tset::iterator text_tsetit;
+  paramspec tmpps;
+
+  precedence = thisprecedence;
+  calcprecedence(thisprecedence, precedhash);
+
+  splitparams(thispageparams, thissplitparams);
+  joinparams(thissplitparams, thispageparams);
+  params = thispageparams;
+
+  // get a list of parameters with their specificness
+  orderparamlist->erase(orderparamlist->begin(), orderparamlist->end());
+  for (text_tsetit=allparams.begin();
+       text_tsetit!=allparams.end();
+       text_tsetit++) 
+    {
+      tmpps.param = (*text_tsetit);
+      splitparams(tmpps.param, splittheseparams);
+      tmpps.spec = getspecificness(thissplitparams, splittheseparams, precedhash);
+      if (tmpps.spec >= 0) 
+	{
+	  orderparamlist->push_back (tmpps);
+	}
+    }
+
+  // sort the list
+  sort(orderparamlist->begin(), orderparamlist->end());
+
+//   paramspeclist::iterator pshere = orderparamlist->begin();
+//   paramspeclist::iterator psend = orderparamlist->end();
+//   while (pshere != psend) 
+//     {
+//       cerr << text_t2ascii << "param=" << (*pshere).param;
+//       cerr << " spec=" << (int)((*pshere).spec) << "\n";
+//       pshere++;
+//     }
+}
+
+
+// overrides (or sets) a macro for the current page.
+// returns 0 if there was no error,
+//        -1 if it redefined a macro
+//        -4 if no macroname was supplied
+int displayclass::setmacro (const text_t &macroname, 
+		       text_t package, 
+		       const text_t &macrovalue)
+{
+  // make sure a macroname was supplied
+  if (macroname.empty()) return -4;
+
+  // make package "Global" if it doesn't point to anything yet
+  if (package.empty()) package = "Global";
+
+  // set the macro
+  return currentmacros->setmacro(package, macroname, "memory", macrovalue);
+}
+
+
+void displayclass::expandstring (const text_t &inputtext, text_t &outputtext)
+{
+  expandstring("", inputtext, outputtext);
+}
+
+
+void displayclass::expandstring (text_t package, const text_t &inputtext,
+				 text_t &outputtext, int recursiondepth)
+{
+  text_t macroname, macropackage, macroargs;
+  text_t::const_iterator tthere = inputtext.begin();
+  text_t::const_iterator ttend = inputtext.end();
+  unsigned short c = '\0';
+
+  if (package.empty()) package = "Global";
+
+  outputtext.clear();
+      
+  // use one-character lookahead
+  if (tthere != ttend) c = (*tthere);
+  while (tthere != ttend) 
+    {
+      if (c == '\\')
+	{
+	  // found an escape character
+	  c = my_ttnextchar (tthere, ttend); // skip the escape character
+	  if (tthere != ttend) 
+	    {
+	      if (c == 'n') outputtext.push_back('\n');
+	      else if (c == 't') outputtext.push_back('\t');
+	      else outputtext.push_back(c);
+	    }
+	  c = my_ttnextchar (tthere, ttend);
+	  
+	} 
+      else if (c == '_') 
+	{
+	  // might have found the start of a macro
+      
+	  // embedded macros (macros within the names
+	  // of other macros) are no longer supported -- Rodger.
+      
+	  // save the current state (in case we need to back out)
+	  text_t::const_iterator savedtthere = tthere;
+	  unsigned short savedc = c;
+	  
+	  macroname.clear();
+	  macropackage = package;
+	  macroargs.clear();
+      
+	  c = my_ttnextchar (tthere, ttend); // skip the '_'
+	  
+	  // get the macroname
+	  while (tthere != ttend && (!is_unicode_space(c)) && 
+		 (c != '\\') && (c != '_') &&(c != ':') && 
+		 (macroname.size() < 80)) 
+	    {
+	      macroname.push_back((unsigned char)c);
+	      c = my_ttnextchar (tthere, ttend);
+	    }
+      
+	  if (c == ':') 
+	    {
+	      // we actually had the macro package
+	      c = my_ttnextchar (tthere, ttend);
+	      macropackage = macroname;
+	      macroname.clear ();
+	
+	      // get the macro name (honest!)
+	      while ((tthere != ttend) && (!is_unicode_space(c)) && 
+		     (c != '\\') && (c != '_') &&(c != ':') && 
+		     (macroname.size() < 80)) 
+		{
+		  macroname.push_back((unsigned char)c);
+		  c = my_ttnextchar (tthere, ttend);
+		}
+	    }
+      
+	  if ((tthere != ttend) && (c == '_') &&
+	      (macroname.size() > 0)) 
+	    {
+	      // found a macro!!!! (maybe)
+	
+	      c = my_ttnextchar (tthere, ttend); // skip the '_'
+	
+	      // get the parameters (if there are any)
+	      if ((tthere != ttend) && (c == '(')) 
+		{
+		  c = my_ttnextchar (tthere, ttend); // skip '('
+	  
+		  // have to be careful of quotes
+		  unsigned short quote = '\0';
+		  while (tthere != ttend) 
+		    {
+		      if (c == '\\') 
+			{
+			  // have an escape character, save escape 
+			  // character and next character as well
+			  macroargs.push_back (c);
+			  c = my_ttnextchar (tthere, ttend); 
+	      
+			} 
+		      else if (quote == '\0') 
+			{
+			  // not in a quote at the moment
+			  if (c == ')') 
+			    {
+			      // found end of the arguments
+			      c = my_ttnextchar (tthere, ttend); // skip ')'
+			      break;
+		
+			    } 
+			  else if (c == '\'' || c == '\"') 
+			    {
+			      // found a quote
+			      quote = c;
+			    }
+	      
+			} 
+		      else 
+			{
+			  // we are in a quote
+			  if (c == quote) quote = '\0';
+			}
+	    
+		      // save this character
+		      if (tthere != ttend) macroargs.push_back (c);
+		      c = my_ttnextchar (tthere, ttend);
+		    }
+		}
+	
+	      //
+	      // we now have the macropackage, macroname, and macroargs
+	      //
+	
+	      // try to expand out this macro
+	      text_t expandedmacro;
+	      if (macro (macroname, macropackage, macroargs, expandedmacro, recursiondepth)) 
+		{
+		  // append the expanded macro
+		  outputtext += expandedmacro;
+		} 
+	      else
+		{
+		  // wasn't a macro
+		  tthere = savedtthere;
+		  c = savedc;
+		  outputtext.push_back(c); // the '_'
+		  c = my_ttnextchar (tthere, ttend);
+		}
+	
+
+	    }
+	  else
+	    {
+	      // wasn't a macro
+	      tthere = savedtthere;
+	      c = savedc;
+	      outputtext.push_back(c); // the '_'
+	      c = my_ttnextchar (tthere, ttend);
+	    }
+
+	}
+      else 
+	{
+	  // nothing of interest
+	  outputtext.push_back(c); // the '_'
+	  c = my_ttnextchar (tthere, ttend);
+	}
+    }
+}
+
+ostream *displayclass::setlogout (ostream *thelogout) {
+
+  ostream *oldlogout = logout;
+  logout = thelogout;
+  return oldlogout;
+}
+
+// protected methods for display
+
+// reloads any default macro files which have changed
+// returns 0 no errors occurred
+//        -1 an error occurred while trying to load one of the files
+int displayclass::checkdefaultmacrofiles ()
+{
+  // this isn't implemented yet
+  return 0;
+}
+
+// isdefaultmacro sees if there is an entry in the list of
+// default macros with the given package and macro name
+// returns 0 if no macros in the package or in the global package
+//           were found
+//         1 if no macros in the package were found but a macro
+//           in the global package was found
+//         2 if a macro in the given package was found
+int displayclass::isdefaultmacro (text_t package, const text_t &macroname) {
+  // make sure a macroname was supplied
+  if (macroname.empty()) return 0;
+
+  // make package "Global" if it doesn't point to anything yet
+  if (package.empty()) package = "Global";
+
+  // check the given package
+  if (defaultmacros->macro_find(package, macroname) != NULL) return 2;
+
+  // check the Global package
+  if (defaultmacros->macro_find("Global", macroname) != NULL) return 1;
+
+  return 0;
+}
+
+
+// setdefaultmacro adds an entry to the list of default macros 
+// returns 0 if there was no error,
+//        -1 if it redefined a macro
+//        -2 if it hid a Global macro
+//        -3 if it redefined a macro and hid a Global macro
+//        -4 if no macroname was supplied
+int displayclass::setdefaultmacro (text_t package, const text_t &macroname, 
+			      text_t params, const text_t &filename,
+			      const text_t &macrovalue) 
+{
+  // make sure a macroname was supplied
+  if (macroname.empty()) return -4;
+
+  // put the parameters in a standard form
+  paramhashtype paramhash;
+  if (params.empty()) params = "ignore=yes";
+  splitparams (params, paramhash);
+  joinparams (paramhash, params);
+
+  // make package "Global" if it doesn't point to anything yet
+  if (package.empty()) package = "Global";
+
+  // remember these parameters
+  allparams.insert (params);
+
+  // remember this filename (this part isn't finished yet -- Rodger).
+
+  // set the macro
+  return defaultmacros->setmacro(package, macroname, params, filename, macrovalue);
+}
+
+
+// evaluates a boolean expression
+// returns false if expr equals "" or "0". 
+// otherwise returns true *unless* expr is 
+// format "XXXX" eq/ne "dddd" in which case
+// the two quoted strings are compared
+bool displayclass::boolexpr (text_t package, const text_t &expr, int recursiondepth) {
+
+  if (expr.empty()) return false;
+
+  text_t expexpr;
+  if (package.empty()) package = "Global";  
+  expandstring (package, expr, expexpr, recursiondepth);
+
+  if (expexpr.empty() || expexpr == "0") return false;
+  if (expr[0] != '\"') return true;
+
+  // don't use expexpr while separating quoted parts of
+  // expression just in case expanded out macros contain
+  // quotes
+  text_t::const_iterator here = expr.begin();
+  text_t::const_iterator end = expr.end();
+
+  int quotecount = 0;
+  text_t string1, expstring1;
+  text_t string2, expstring2;
+  text_t op;
+  text_t combineop;
+  bool result = false; // an empty string is false
+  bool result2 = false;
+
+  while (here != end) {
+    // get a comparison
+    quotecount = 0;
+    string1.clear();
+    string2.clear();
+    op.clear();
+    while (here != end) {
+      if (*here == '"') quotecount++;
+      else if (quotecount == 1) string1.push_back(*here);
+      else if ((quotecount == 2) && !is_unicode_space (*here))
+	op.push_back(*here);
+      else if (quotecount == 3) string2.push_back(*here);
+      else if (quotecount >= 4) break;
+      here ++;
+    }
+    
+    expandstring (package, string1, expstring1, recursiondepth);
+    expandstring (package, string2, expstring2, recursiondepth);
+
+    // get next result
+    result2 = true; // any badly formatted string will return true
+    if (op == "eq") result2 = (expstring1 == expstring2);
+    else if (op == "ne") result2 = (expstring1 != expstring2);
+    else if (op == "gt") result2 = (expstring1 > expstring2);
+    else if (op == "ge") result2 = (expstring1 >= expstring2);
+    else if (op == "lt") result2 = (expstring1 < expstring2);
+    else if (op == "le") result2 = (expstring1 <= expstring2);
+    else if (op == "==") result2 = (expstring1.getint() == expstring2.getint());
+    else if (op == "!=") result2 = (expstring1.getint() != expstring2.getint());
+    else if (op == ">") result2 = (expstring1.getint() > expstring2.getint());
+    else if (op == ">=") result2 = (expstring1.getint() >= expstring2.getint());
+    else if (op == "<") result2 = (expstring1.getint() < expstring2.getint());
+    else if (op == "<=") result2 = (expstring1.getint() <= expstring2.getint());
+
+    // combine the results
+    if (combineop == "&&") result = (result && result2);
+    else if (combineop == "||") result = (result || result2);
+    else result = result2;
+
+    // get next combination operator
+    combineop.clear();
+    while (here != end && *here != '"') {
+      if (!is_unicode_space(*here)) combineop.push_back(*here);
+      here++;
+    }
+  }
+
+  return result;
+}
+
+
+// (recursively) expand out a macro
+// returns true  if the macro was found
+//         false if the macro was not found
+bool displayclass::macro (const text_t &macroname, text_t macropackage, 
+		     const text_t &macroparam, text_t &outputtext,
+		     int recursiondepth)
+{
+  outconvertclass text_t2ascii;
+  text_tlist splitmacroparam;
+  text_t::const_iterator hereit, endit;
+  text_t aparam;
+  unsigned short c = '\0', quote = '\0';
+
+  //  cerr << "r: " << recursiondepth << "\n";
+
+  // check for deep recursion
+  if (recursiondepth >= MAXRECURSIONDEPTH)
+    {
+      if (logout != NULL)
+	(*logout) << "Warning: deep recursion, limiting macro expansion\n";
+      return false;
+    }
+
+  // check the macropackage
+  if (macropackage.empty()) macropackage = "Global";
+
+  // get the parameters (but don't expand them)
+  if (macroparam.size() > 0) {
+    // set up for loop
+    hereit = macroparam.begin();
+    endit = macroparam.end();
+    if (hereit != endit) c = (*hereit);
+
+    while (hereit != endit) {
+      // get the next parameter
+      aparam.clear();
+      quote = '\0'; // not-quoted unless proven quoted
+      
+      // ignore initial whitespace
+      while ((hereit!=endit)&&is_unicode_space(c)) c=my_ttnextchar(hereit,endit);
+      
+      // look for the end of the parameter
+      while (hereit != endit) {
+	if (c == '\\') {
+	  // found escape character, also get next character
+	  aparam.push_back(c);
+	  c = my_ttnextchar (hereit, endit);
+	  if (hereit != endit) aparam.push_back(c);
+	  
+	} else if (quote=='\0' && (c=='\'' /*|| c=='"'*/)) {
+	  // found a quoted section
+	  quote = c;
+	  //	  aparam.push_back(c);
+
+	} else if (quote!='\0' && c==quote) {
+	  // found the end of a quote
+	  quote = '\0';
+	  //	  aparam.push_back(c);
+
+	} else if (quote=='\0' && c==',') {
+	  // found the end of a parameter
+	  c = my_ttnextchar (hereit, endit);
+	  break;
+
+	} else {
+	  // ordinary character
+	  aparam.push_back(c);
+	}
+
+	c = my_ttnextchar (hereit, endit);
+      }
+
+      // add this parameter to the list
+      splitmacroparam.push_back(aparam);
+    }
+  }
+
+  if (macroname == "If") {
+    // get the condition, then clause and else clause
+    text_tlist::iterator paramcond = splitmacroparam.begin();
+    text_tlist::iterator paramend = splitmacroparam.end();
+    text_tlist::iterator paramthen = paramend;
+    text_tlist::iterator paramelse = paramend;
+    
+    if (paramcond != paramend) {
+      paramthen = paramcond;
+      paramthen++;
+    }
+    if (paramthen != paramend) {
+      paramelse = paramthen;
+      paramelse++;
+    }
+    
+    // will always output something
+    outputtext.clear();
+    
+    // expand out the first parameter
+    if (paramcond != paramend) {
+      text_t tmpoutput;
+      expandstring (macropackage, *paramcond, tmpoutput, recursiondepth+1);
+      lc (tmpoutput);
+      
+      // test the expanded string
+      if (boolexpr (macropackage, *paramcond, recursiondepth+1)) {
+	//(tmpoutput.size()) && (tmpoutput != "false") && (tmpoutput != "0")) {
+	// true
+	if (paramthen != paramend)
+	  expandstring (macropackage, *paramthen, outputtext, recursiondepth+1);
+
+      } else {
+	// false
+	if (paramelse != paramend)
+	  expandstring (macropackage, *paramelse, outputtext, recursiondepth+1);
+      }
+    }
+    
+    return true;
+  }
+
+  // try and find this macro
+
+  // this list might be replaced by something a little more
+  // sophisticated in the future.
+  text_tlist packagelist;
+  packagelist.push_back (macropackage);
+  packagelist.push_back ("Global");
+
+  paramspeclist::iterator paramhere, paramend;
+  text_tlist::iterator packagehere = packagelist.begin();
+  text_tlist::iterator packageend = packagelist.end();
+  mvalue *macrovalue = NULL;
+  while ((macrovalue == NULL) && (packagehere != packageend)) 
+    {
+      // first look in the currentmacros
+      macrovalue = currentmacros->macro_find(*packagehere, macroname);
+      if (macrovalue == NULL)
+	macrovalue = currentmacros->macro_find("Style", macroname);
+
+      // look in the default macros
+      if (macrovalue == NULL) 
+	{
+	  // next look in the defaultmacros
+	  if (defaultmacros->macro_find (*packagehere, macroname) != NULL)
+	    {
+	      paramhere = orderparamlist->begin(); paramend = orderparamlist->end();
+	      while ((macrovalue == NULL) && (paramhere != paramend))
+		{
+// 		  cerr << text_t2ascii << "\npackage: " << *packagehere << "\n";
+// 		  cerr << text_t2ascii << "macroname: " << macroname << "\n";
+// 		  cerr << text_t2ascii << "param: " << (*paramhere).param << "\n";
+// 		  cerr << "spec: " << (int)((*paramhere).spec) << "\n";
+		  macrovalue = defaultmacros->parameter_find(*packagehere, macroname,
+							     (*paramhere).param);
+		  paramhere++;
+		}
+	    }
+	}
+
+      // and again in the package "Style"
+      if (macrovalue == NULL) 
+	{
+	  // next look in the defaultmacros
+	  if (defaultmacros->macro_find ("Style", macroname) != NULL)
+	    {
+	      paramhere = orderparamlist->begin(); paramend = orderparamlist->end();
+	      while ((macrovalue == NULL) && (paramhere != paramend))
+		{
+		  macrovalue = defaultmacros->parameter_find("Style", macroname,
+							     (*paramhere).param);
+		  paramhere++;
+		}
+	    }
+	}
+      if (macrovalue == NULL) packagehere++;
+    }
+
+  if (macrovalue != NULL)
+    {
+      // we found a macro
+
+      // replace all the option macros (_1_, _2_, ...) in the value of this macro
+      // and decide if we need to expand the value of this macro
+      bool needsexpansion = false;
+      text_t tempmacrovalue;
+      tempmacrovalue.clear();
+      hereit = macrovalue->value.begin();
+      endit = macrovalue->value.end();
+      if (hereit != endit) c = (*hereit);
+      while (hereit != endit)
+	{
+	  if (c == '\\')
+	    {
+	      // found an escape character
+	      needsexpansion = true;
+	      tempmacrovalue.push_back(c);
+	      c = my_ttnextchar (hereit, endit);
+	      if (hereit != endit) tempmacrovalue.push_back(c);
+	      c = my_ttnextchar (hereit, endit);
+	    }
+	  else if (c == '_')
+	    {
+	      text_t::const_iterator savedhereit = hereit;
+
+	      // attempt to get a number
+	      int argnum = 0;
+	      unsigned short digc = my_ttnextchar (hereit, endit);
+	      while (digc >= '0' && digc <= '9') {
+		argnum = argnum*10 + digc - '0';
+		digc = my_ttnextchar (hereit, endit);
+	      }
+	      if (digc == '_' && argnum > 0) {
+		// found an option macro, append the appropriate text
+		text_tlist::iterator ttlisthere = splitmacroparam.begin();
+		text_tlist::iterator ttlistend = splitmacroparam.end();
+		while ((argnum > 1) && (ttlisthere != ttlistend)) {
+		  argnum--;
+		  ttlisthere++;
+		}
+		if (ttlisthere != ttlistend) {
+		  tempmacrovalue.append(*ttlisthere);
+		  if (findchar((*ttlisthere).begin(), (*ttlisthere).end(), '_') != (*ttlisthere).end())
+		    needsexpansion = true;
+		}
+
+		c = my_ttnextchar (hereit, endit);
+
+	      } else {
+		// wasn't a option macro
+		needsexpansion = true;
+		tempmacrovalue.push_back(c);
+		hereit = savedhereit;
+		c = my_ttnextchar (hereit, endit);
+	      }
+	    }
+	  else
+	    {
+	      tempmacrovalue.push_back(c);
+	      c = my_ttnextchar (hereit, endit);
+	    }
+	}
+      
+      // recursively replace this macro (if we need to)
+      if (needsexpansion) {
+	expandstring (*packagehere, tempmacrovalue, outputtext, recursiondepth+1);
+      } else {
+	outputtext += tempmacrovalue;
+      }
+
+      return true;
+    }
+
+  if (logout != NULL) {
+    (*logout) << text_t2ascii << "Warning: _" << 
+      macropackage << ":" << macroname << "_ not found\n";
+  }
+  
+  return false; // didn't find the macro
+}
+
+
+void displayclass::printdefaultmacros ()
+{
+  defpackagemap::const_iterator packagemapit;
+  defmacromap::const_iterator macromapit;
+  defparammap::const_iterator parammapit;
+  const mvalue *mvalueptr;
+  outconvertclass text_t2ascii;
+
+  text_t packagename, macroname, macroparam;
+  
+  for (packagemapit = defaultmacros->package_begin();
+       packagemapit != defaultmacros->package_end();
+       packagemapit++) 
+    {
+      packagename = (*packagemapit).first;
+      //     cerr << "***package   : \"" << packagename << "\"\n";
+    
+      for (macromapit = (*packagemapit).second.begin();
+	   macromapit != (*packagemapit).second.end();
+	   macromapit++) 
+	{
+	  macroname = (*macromapit).first;
+	  //       cerr << "***macroname : \"" << macroname << "\"\n";
+
+	  for (parammapit = (*macromapit).second.begin();
+	       parammapit != (*macromapit).second.end();
+	       parammapit++) 
+	    {
+	      macroparam = (*parammapit).first;
+	      mvalueptr = &((*parammapit).second);
+	      cerr << text_t2ascii << "package   : \"" << packagename << "\"\n";
+	      cerr << text_t2ascii << "macroname : \"" << macroname << "\"\n";
+	      cerr << text_t2ascii << "parameters: [" << macroparam << "]\n";
+	      cerr << text_t2ascii << "filename  : \"" << mvalueptr->filename << "\"\n";
+	      cerr << text_t2ascii << "value     : {" << mvalueptr->value << "}\n\n";
+	    }
+	}
+    }
+}
+
+void displayclass::printallparams ()
+{
+  text_tset::iterator text_tsetit;
+  outconvertclass text_t2ascii;
+
+  cerr << text_t2ascii << "** allparams\n";
+  for (text_tsetit=allparams.begin();
+       text_tsetit!=allparams.end();
+       text_tsetit++) {
+    cerr << text_t2ascii << (*text_tsetit) << "\n";
+  }
+  cerr << text_t2ascii << "\n";
+}
+
+
+
+/////////////////////////////////////
+// stuff to do tricky output
+/////////////////////////////////////
+
+displayclass &operator<< (outconvertclass &theoutc, displayclass &display)
+{
+  display.setconvertclass (&theoutc);
+  return display;
+}
+
+displayclass &operator<< (displayclass &display, const text_t &t)
+{
+  outconvertclass *theoutc = display.getconvertclass();
+
+  if (theoutc == NULL) return display;
+  
+  text_t output;
+  display.expandstring (t, output);
+  (*theoutc) << output;
+
+  return display;
+}
Index: /main/tags/2.25/gsdl/lib/display.h
===================================================================
--- /main/tags/2.25/gsdl/lib/display.h	(revision 21064)
+++ /main/tags/2.25/gsdl/lib/display.h	(revision 21064)
@@ -0,0 +1,267 @@
+/**********************************************************************
+ *
+ * display.h -- Context sensitive macro language
+ * Copyright (C) 1999  The New Zealand Digital Library Project
+ *
+ * A component of the Greenstone digital library software
+ * from the New Zealand Digital Library Project at the
+ * University of Waikato, New Zealand.
+ *
+ * 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.
+ *
+ *********************************************************************/
+
+
+#ifndef DISPLAY_H
+#define DISPLAY_H
+
+#include "gsdlconf.h"
+#include "text_t.h"
+
+
+#if defined(GSDL_USE_OBJECTSPACE)
+#  include <ospace\std\vector>
+#  include <ospace\std\list>
+#  include <ospace\std\set>
+#  include <ospace\std\map>
+#  include <ospace\std\algorithm>
+#elif defined(GSDL_USE_STL_H)
+#  include <vector.h>
+#  include <list.h>
+#  include <set.h>
+#  include <map.h>
+#  if defined(GSDL_USE_ALGO_H)
+#    include <algo.h>
+#  else
+#    include <algorithm.h>
+#  endif
+#else
+#  include <vector>
+#  include <list>
+#  include <set>
+#  include <map>
+#  include <algorithm>
+#endif
+
+#if defined(GSDL_USE_OBJECTSPACE)
+#  include <ospace\std\iostream>
+#  include <ospace\std\fstream>
+#elif defined(GSDL_USE_IOS_H)
+#  include <iostream.h>
+#  include <fstream.h>
+
+#define unistream ifstream
+
+#else
+#  include <iostream>
+#  include <fstream>
+
+typedef std::basic_ifstream<unsigned char> unistream;
+
+#endif
+
+
+// use the standard namespace
+#if defined(GSDL_USE_OBJECTSPACE)
+using namespace ospace::std;
+#elif !defined(GSDL_NAMESPACE_BROKEN)
+using namespace std;
+#endif
+
+
+
+// MAXRECURSIONDEPTH is a cutoff to catch
+// cyclic macros (a includes b and b includes a)
+#define MAXRECURSIONDEPTH 30
+
+// class prototypes
+class defaultmacros_t;
+class currentmacros_t;
+
+// a few supporting types
+// fileelement isn't finished yet, I have to find out
+// more about getting information about files
+struct fileinfoelement 
+{
+  int otherinfo;
+};
+
+inline bool operator==(const fileinfoelement &x, const fileinfoelement &y) {
+  return (x.otherinfo==y.otherinfo);
+}
+
+inline bool operator<(const fileinfoelement &x, const fileinfoelement &y) {
+  return (x.otherinfo<y.otherinfo);
+}
+
+typedef map<text_t, fileinfoelement, lttext_t> fileinfomap;
+
+
+typedef map<text_t, text_t, lttext_t> paramhashtype;
+
+
+struct paramspec 
+{
+  double spec;
+  text_t param;
+};
+
+inline bool operator==(const paramspec& x, const paramspec& y) 
+{
+  return ((x.spec == y.spec) && (x.param == y.param));
+}
+
+inline bool operator!=(const paramspec& x, const paramspec& y) 
+{
+  return ((x.spec != y.spec) || (x.param != y.param));
+}
+
+// note: paramspec is sorted by reverse spec and then param
+
+inline bool operator<(const paramspec& x, const paramspec& y) 
+{
+  return ((x.spec > y.spec) ||
+	  ((x.spec == y.spec) && (x.param < y.param)));
+}
+
+inline bool operator>(const paramspec& x, const paramspec& y) 
+{
+  return ((x.spec < y.spec) ||
+	  ((x.spec == y.spec) && (x.param > y.param)));
+}
+
+typedef vector<paramspec> paramspeclist;
+
+
+// NOTE: when macros are used within text they should have
+// underscores '_' on both sides, however, in calls to
+// setdefaultmacro and setmacro they should not have the
+// underscores. So you might have
+//
+// setmacro ("aname", "query", " some text ");
+// expandstring ("_aname_", expandedtext);
+//
+// because the input to expandstring is a block of text, not
+// a macroname
+
+class displayclass 
+{
+public:
+  displayclass ();
+  ~displayclass ();
+  
+  // isdefaultmacro sees if there is an entry in the list of
+  // default macros with the given package and macro name
+  // returns 0 if no macros in the package or in the global package
+  //           were found
+  //         1 if no macros in the package were found but a macro
+  //           in the global package was found
+  //         2 if a macro in the given package was found
+  int isdefaultmacro (text_t package, const text_t &macroname);
+
+  // setdefaultmacro adds an entry to the list of default macros 
+  // returns 0 if there was no error,
+  //        -1 if it redefined a macro
+  //        -2 if it hid a Global macro
+  //        -3 if it redefined a macro and hid a Global macro
+  //        -4 if no macroname was supplied
+  int setdefaultmacro (text_t package, const text_t &macroname, 
+		       text_t params, const text_t &macrovalue);
+  
+  // loads a default macro file (if it isn't already loaded)
+  // returns 0 if didn't need to load the file (it was already loaded)
+  //         1 if was (re)loaded
+  //        -1 an error occurred while trying to load the file
+  int loaddefaultmacros (text_t thisfilename);
+  
+  // prepares to create a page: deletes all macros set with
+  // 'setmacro', checks all the default macro files to see
+  // if any need reloading, and sets the page parameters.
+  void openpage (const text_t &thispageparams, 
+		 const text_t &thisprecedence);
+  
+  // changes the parameters for the current page.
+  void setpageparams (text_t thispageparams, 
+		      text_t thisprecedence);
+  
+  // overrides (or sets) a macro for the current page.
+  // returns 0 if there was no error,
+  //        -1 if it redefined a macro
+  //        -4 if no macroname was supplied
+  int setmacro (const text_t &macroname, 
+		text_t package, 
+		const text_t &macrovalue);
+  
+  void expandstring (const text_t &inputtext, text_t &outputtext);
+  void expandstring (text_t package, const text_t &inputtext,
+		     text_t &outputtext, int recursiondepth = 0);
+
+  // these functions are not ment to be used directly, they are used to permit 
+  // concise stream output like:
+  // cout << text_t2ascii << display << "_amacro_" << "_anothermacro_";
+  void setconvertclass (outconvertclass *theoutc) {outc = theoutc;}
+  outconvertclass *getconvertclass () {return outc;}
+
+  // say where any error logging goes, this can be NULL
+  // if no error logging is desired - returns previous value
+  ostream *setlogout (ostream *thelogout);
+
+  // debug stuff
+  void printdefaultmacros ();
+  void printallparams ();
+
+protected:
+  // special variables to permit trickly output
+  outconvertclass *outc;
+
+  // general variables
+  text_tset allparams;  // possible parameter combinations
+  defaultmacros_t *defaultmacros;
+  fileinfomap *defaultfiles;
+  
+  // variables to do with a page expansion
+  text_t params;
+  text_t precedence;
+  paramspeclist *orderparamlist; // ordered by specificness
+  currentmacros_t *currentmacros; // only macros set by setmacro
+
+  // logging variable
+  ostream *logout;
+
+  // reloads any default macro files which have changed
+  // returns 0 no errors occurred
+  //        -1 an error occurred while trying to load one of the files
+  int checkdefaultmacrofiles ();
+
+  int setdefaultmacro (text_t package, const text_t &macroname, 
+		       text_t params, const text_t &filename,
+		       const text_t &macrovalue); 
+
+  // evaluates a boolean expression
+  bool boolexpr (text_t package, const text_t &expr, int recursiondepth);
+
+  // (recursively) expand out a macro
+  // returns true  if the macro was found
+  //         false if the macro was not found
+  bool macro (const text_t &macroname, text_t macropackage, 
+	      const text_t &macroparam, text_t &outputtext,
+	      int recursiondepth);
+};
+
+
+displayclass &operator<< (outconvertclass &theoutc, displayclass &display);
+displayclass &operator<< (displayclass &display, const text_t &t);
+
+#endif
Index: /main/tags/2.25/gsdl/lib/fileutil.cpp
===================================================================
--- /main/tags/2.25/gsdl/lib/fileutil.cpp	(revision 21064)
+++ /main/tags/2.25/gsdl/lib/fileutil.cpp	(revision 21064)
@@ -0,0 +1,202 @@
+/**********************************************************************
+ *
+ * fileutil.cpp -- 
+ * Copyright (C) 1999  The New Zealand Digital Library Project
+ *
+ * A component of the Greenstone digital library software
+ * from the New Zealand Digital Library Project at the
+ * University of Waikato, New Zealand.
+ *
+ * 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.
+ *
+ *********************************************************************/
+
+#include "fileutil.h"
+
+#if defined(GSDL_USE_OBJECTSPACE)
+#  include <ospace\std\iostream>
+#  include <ospace\std\fstream>
+#elif defined(GSDL_USE_IOS_H)
+#  include <iostream.h>
+#  include <fstream.h>
+#else
+#  include <iostream>
+#  include <fstream>
+#endif
+
+
+// returns the proper concatenation of the two paths
+text_t filename_cat (text_t path1, text_t path2) {
+  text_t::iterator here;
+  text_t::iterator begin;
+  text_t::iterator end;
+
+  // make sure there is just one slash, of the correct type,
+  // at the end of path1 (unless path1 is an empty string).
+  if (!path1.empty()) {
+    // remove all trailing slashes
+    here = path1.end();
+    here--;
+    begin = path1.begin();
+    while (here != begin && (*here == '/' || *here == '\\')) {
+      here--;
+    }
+    here++;
+    path1.erase(here,path1.end());
+
+    // add one final slash
+#ifdef __WIN32__
+    path1 += "\\";
+#else
+    path1 += "/";
+#endif 
+  }
+
+  // remove all slashes from the start of path2
+  here = path2.begin();
+  end = path2.end();
+  while (here != end && (*here == '/' || *here == '\\')) {
+    here++;
+  }
+  path2.erase (path2.begin(), here);
+  
+  text_t fullpath = path1 + path2;
+
+  // make sure all the right slashes are used
+  here = fullpath.begin();
+  end = fullpath.end();
+  while (here != end) {
+#ifdef __WIN32__
+    if (*here == '/') *here = '\\';
+#else
+    if (*here == '\\') *here = '/';
+#endif
+    here ++;
+  }
+  return fullpath;
+}
+
+text_t filename_cat (text_t path1, text_t path2, text_t path3) {
+  return filename_cat(filename_cat(path1,path2),path3);
+}
+
+text_t filename_cat (text_t path1, text_t path2, text_t path3, text_t path4) {
+  return filename_cat(filename_cat(filename_cat(path1,path2),path3),path4);
+}
+
+text_t filename_cat (text_t path1, text_t path2, text_t path3, text_t path4, 
+		     text_t path5) {
+  return filename_cat(filename_cat(filename_cat(filename_cat(path1,path2),path3),
+				   path4),path5);
+}
+
+// returns true if filename can be opened
+bool file_exists (const text_t &filename) {
+  char *cstr = filename.getcstr();
+#ifdef GSDL_USE_IOS_H
+  ifstream filestream (cstr, ios::in | ios::nocreate);
+#else
+  ifstream filestream (cstr, ios::in);
+#endif
+  delete cstr;
+
+  if (filestream) {
+    // file exists
+    filestream.close ();
+    return true;
+  }
+
+  // file does not exist
+  return false;
+}
+
+// returns true if filename can be opened
+bool file_writable (const text_t &filename) {
+  char *cstr = filename.getcstr();
+#ifdef GSDL_USE_IOS_H
+  ifstream filestream (cstr, ios::out | ios::nocreate);
+#else
+  ifstream filestream (cstr, ios::out);
+#endif
+  delete cstr;
+
+  if (filestream) {
+    // file exists
+    filestream.close ();
+    return true;
+  }
+
+  // file does not exist
+  return false;
+}
+
+#if defined(__WIN32__) && !defined(__GNUC__)
+
+#include <windows.h>
+
+bool read_dir (const text_t &dirname, text_tarray &filelist) {
+  
+  WIN32_FIND_DATA FileData;  
+  HANDLE hSearch; 
+  char *dirpath = dirname.getcstr();
+  strcat (dirpath, "\\*");
+  
+  hSearch = FindFirstFile(dirpath, &FileData); 
+  if (hSearch == INVALID_HANDLE_VALUE) return false;
+  
+  text_t filename = FileData.cFileName;
+  if (filename != "." && filename != ".." && filename != "CVS")
+    filelist.push_back (filename); 
+  
+  while (FindNextFile(hSearch, &FileData)) {
+    filename = FileData.cFileName;
+    if (filename == "." || filename == ".." || filename == "CVS")
+      continue;
+    filelist.push_back (filename); 
+  }
+  
+  FindClose(hSearch);
+  
+  return true;
+}
+
+#else
+
+#include <dirent.h>
+
+bool read_dir (const text_t &dirname, text_tarray &filelist) {
+
+  filelist.erase (filelist.begin(), filelist.end());
+  
+  char *tmp = dirname.getcstr();
+  DIR *dirin = opendir (tmp);
+  delete tmp;
+  
+  if (dirin == NULL) return false;
+  
+  dirent *dirp; 
+
+  text_t filename;
+  while ((dirp = readdir (dirin)) != NULL) {
+    filename = dirp->d_name;
+    if (filename == "." || filename == ".." || filename == "CVS")
+      continue;
+    filelist.push_back (filename);
+  }
+  closedir (dirin);
+  return true;
+}
+
+#endif
Index: /main/tags/2.25/gsdl/lib/fileutil.h
===================================================================
--- /main/tags/2.25/gsdl/lib/fileutil.h	(revision 21064)
+++ /main/tags/2.25/gsdl/lib/fileutil.h	(revision 21064)
@@ -0,0 +1,48 @@
+/**********************************************************************
+ *
+ * fileutil.h -- a few useful file utilities
+ * Copyright (C) 1999  The New Zealand Digital Library Project
+ *
+ * A component of the Greenstone digital library software
+ * from the New Zealand Digital Library Project at the
+ * University of Waikato, New Zealand.
+ *
+ * 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.
+ *
+ *********************************************************************/
+
+
+#ifndef FILEUTIL_H
+#define FILEUTIL_H
+
+#include "text_t.h"
+
+
+// returns the proper concatenation of the two paths
+text_t filename_cat (text_t path1, text_t path2);
+text_t filename_cat (text_t path1, text_t path2, text_t path3);
+text_t filename_cat (text_t path1, text_t path2, text_t path3, text_t path4);
+text_t filename_cat (text_t path1, text_t path2, text_t path3, text_t path4, 
+		     text_t path5);
+
+// returns true if filename can be opened
+bool file_exists (const text_t &filename);
+
+// returns true if filename can be written to
+bool file_writable (const text_t &filename);
+
+bool read_dir (const text_t &dirname, text_tarray &filelist);
+
+#endif
Index: /main/tags/2.25/gsdl/lib/gsdlconf.h
===================================================================
--- /main/tags/2.25/gsdl/lib/gsdlconf.h	(revision 21064)
+++ /main/tags/2.25/gsdl/lib/gsdlconf.h	(revision 21064)
@@ -0,0 +1,172 @@
+/**********************************************************************
+ *
+ * gsdlconf.h -- system specific includes
+ * Copyright (C) 1999  The New Zealand Digital Library Project
+ *
+ * A component of the Greenstone digital library software
+ * from the New Zealand Digital Library Project at the
+ * University of Waikato, New Zealand.
+ *
+ * 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.
+ *
+ *********************************************************************/
+
+
+#ifndef GSDLCONF_H
+#define GSDLCONF_H
+
+#if defined(__WIN32__)
+#include "../win32cfg.h"
+#else
+#include "../config.h"
+#endif
+
+// Note: all macros used in the gsdl software (except the _H macros) should
+// now start with GSDL_
+
+// GSDL_NEED_STRINGS_H should be defined if some string functions
+// needed (like strcasecmp) are in strings.h
+#if defined(__IBMCPP__)
+#  define GSDL_NEED_STRINGS_H
+#endif
+
+// GSDL_USE_IOS_H should be defined if the .h extension needs to
+// be used for the io stream headers
+#if defined(__GNUG__) || defined(__IBMCPP__)
+#  define GSDL_USE_IOS_H 1
+#endif
+
+// GSDL_USE_STL_H should be defined if the .h extension needs to
+// be used for the stl header files
+#if defined(__IBMCPP__)
+#  define GSDL_USE_STL_H 1
+#endif
+
+// GSDL_USE_ALGO_H should be defined if algo.h should be used 
+// instead of algorithm.h
+#if defined(__IBMCPP__)
+#  define GSDL_USE_ALGO_H 1
+#endif
+
+// GSDL_NAMESPACE_BROKEN should be defined if namespaces should
+// not be used
+#if defined(__GNUG__) || defined(__IBMCPP__)
+#  define GSDL_NAMESPACE_BROKEN 1
+#endif
+
+// GSDL_USE_OBJECTSPACE should now be used instead of USE_OBJECTSPACE
+#if defined(USE_OBJECTSPACE)
+#  define GSDL_USE_OBJECTSPACE
+#endif
+
+// GSDL_NEED_DESTROY_USHORT should be defined if the compiler needs
+// a definition for void destroy(short unsigned int *)
+#if defined(__IBMCPP__)
+# define GSDL_NEED_DESTROY_USHORT
+#endif
+
+// mktemp
+
+#if !defined(__WIN32__) || defined(__GNUC__)
+#include <unistd.h>
+#define GSDL_MKTEMP(str) mktemp(str)
+#else
+#include <io.h>
+#define GSDL_MKTEMP(str) _mktemp(str)
+#endif
+
+
+
+// file locking
+
+#if defined(__WIN32__)
+
+#if !defined(LK_UNLOCK) && defined(LK_UNLCK)
+#define LK_UNLOCK LK_UNLCK
+#endif
+
+#if defined (GSDL_USE_IOS_H)
+#include <io.h>
+#include <sys/locking.h>
+
+#if defined(__GNUC__)
+#define GSDL_GET_FILEDESC(str) str.filedesc()
+#else
+#define GSDL_GET_FILEDESC(str) str.fd()
+#endif
+
+#define GSDL_UNLOCK_FILE(fd) _locking(fd, LK_UNLCK, 200)
+#define GSDL_LOCK_FILE(fd) lock_val = _locking(fd, LK_NBLCK, 200)
+
+#else
+
+// when using <fstream> (i.e. VC++ 6.0) I can't work out how
+// to return a filedesc. File locking won't currently work
+// for those windows compilers requiring GSDL_USE_IOS_H to
+// not be set -- Stefan.
+#define GSDL_GET_FILEDESC(str) 1
+#define GSDL_LOCK_FILE(fd) lock_val = 0
+#define GSDL_UNLOCK_FILE(fd) 0
+#endif
+
+#else
+#define GSDL_GET_FILEDESC(str) str.filedesc()
+
+#if GSDL_USE_FLOCK
+#include <sys/lock.h>
+
+#ifndef LOCK_SH
+#define LOCK_SH	1
+#endif
+
+#ifndef LOCK_EX
+#define LOCK_EX	2
+#endif
+
+#ifndef LOCK_NB
+#define LOCK_NB 4
+#endif
+
+#ifndef LOCK_UN
+#define LOCK_UN 8
+#endif
+
+#define GSDL_UNLOCK_FILE(fd) flock (fd, LOCK_UN)
+#define GSDL_LOCK_FILE(fd) lock_val = flock (fd, LOCK_EX + LOCK_NB)
+
+#else
+// use fcntl
+#include <fcntl.h>
+#define GSDL_UNLOCK_FILE(fd) \
+	{					\
+	  struct flock flock;			\
+	  flock.l_type = F_UNLCK;		\
+	  flock.l_whence = SEEK_SET;		\
+	  flock.l_start = flock.l_len = 0L;	\
+	  fcntl (fd, F_SETLK, &flock);	\
+	}
+#define GSDL_LOCK_FILE(fd) \
+	{					\
+	  struct flock flock;			\
+	  flock.l_type = F_WRLCK;		\
+	  flock.l_whence = SEEK_SET;			\
+	  flock.l_start = flock.l_len = 0L;	\
+	  lock_val = fcntl (fd, F_SETLK, &flock);	\
+	}
+
+#endif
+#endif
+
+#endif
Index: /main/tags/2.25/gsdl/lib/gsdltimes.cpp
===================================================================
--- /main/tags/2.25/gsdl/lib/gsdltimes.cpp	(revision 21064)
+++ /main/tags/2.25/gsdl/lib/gsdltimes.cpp	(revision 21064)
@@ -0,0 +1,115 @@
+/**********************************************************************
+ *
+ * gsdltimes.cpp -- functions to deal with time
+ * Copyright (C) 1999  DigiLib Systems Limited, New Zealand
+ *
+ * A component of the Greenstone digital library software
+ * from the New Zealand Digital Library Project at the
+ * University of Waikato, New Zealand.
+ *
+ * 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.
+ *
+ *********************************************************************/
+
+#include "gsdltimes.h"
+
+
+// returns "" if an error occurs
+text_t time2text (time_t time) {
+  tm *tm_ptr = gmtime(&time);
+  if (tm_ptr == NULL) return "";
+
+  // year
+  text_t timestr(tm_ptr->tm_year+1900);
+  timestr.push_back('/');
+
+  // month (note the +1)
+  if ((tm_ptr->tm_mon+1) < 10) timestr.push_back('0');
+  timestr += (tm_ptr->tm_mon+1);
+  timestr.push_back('/');
+
+  // day
+  if (tm_ptr->tm_mday < 10) timestr.push_back('0');
+  timestr += tm_ptr->tm_mday;
+  timestr.push_back(' ');
+
+  // hour
+  if (tm_ptr->tm_hour < 10) timestr.push_back('0');
+  timestr += tm_ptr->tm_hour;
+  timestr.push_back(':');
+
+  // minutes
+  if (tm_ptr->tm_min < 10) timestr.push_back('0');
+  timestr += tm_ptr->tm_min;
+  timestr.push_back(':');
+
+  // seconds
+  if (tm_ptr->tm_sec < 10) timestr.push_back('0');
+  timestr += tm_ptr->tm_sec;
+
+  return timestr;
+}
+
+// returns -1 if an error occurs
+time_t text2time (const text_t &timestr) {
+  tm timetm;
+  text_t tempstr;
+  
+  text_t::const_iterator time_here = timestr.begin();
+  text_t::const_iterator time_end = timestr.end();
+
+  // year
+  if (time_here == time_end) return (time_t) -1;
+  time_here = getdelimitstr (time_here, time_end, '/', tempstr);
+  timetm.tm_year = tempstr.getint() - 1900;
+  if (timetm.tm_year < 0) return (time_t) -1;
+
+  // month (note the -1)
+  if (time_here == time_end) return (time_t) -1;
+  time_here = getdelimitstr (time_here, time_end, '/', tempstr);
+  timetm.tm_mon = tempstr.getint() - 1;
+  if (timetm.tm_mon < 0 || timetm.tm_mon > 11)
+    return (time_t) -1;
+  
+  // day
+  if (time_here == time_end) return (time_t) -1;
+  time_here = getdelimitstr (time_here, time_end, ' ', tempstr);
+  timetm.tm_mday = tempstr.getint();
+  if (timetm.tm_mday < 1 || timetm.tm_mday > 31)
+    return (time_t) -1;
+  
+  // hour
+  if (time_here == time_end) return (time_t) -1;
+  time_here = getdelimitstr (time_here, time_end, ':', tempstr);
+  timetm.tm_hour = tempstr.getint();
+  if (timetm.tm_hour < 0 || timetm.tm_hour > 23)
+    return (time_t) -1;
+  
+  // min
+  if (time_here == time_end) return (time_t) -1;
+  time_here = getdelimitstr (time_here, time_end, ':', tempstr);
+  timetm.tm_min = tempstr.getint();
+  if (timetm.tm_min < 0 || timetm.tm_min > 59)
+    return (time_t) -1;
+  
+  // sec
+  if (time_here == time_end) return (time_t) -1;
+  time_here = getdelimitstr (time_here, time_end, ':', tempstr);
+  timetm.tm_sec = tempstr.getint();
+  if (timetm.tm_sec < 0 || timetm.tm_sec > 59)
+    return (time_t) -1;
+  
+  return mktime (&timetm);
+}
Index: /main/tags/2.25/gsdl/lib/gsdltimes.h
===================================================================
--- /main/tags/2.25/gsdl/lib/gsdltimes.h	(revision 21064)
+++ /main/tags/2.25/gsdl/lib/gsdltimes.h	(revision 21064)
@@ -0,0 +1,41 @@
+/**********************************************************************
+ *
+ * gsdltimes.h -- functions to deal with time
+ * Copyright (C) 1999  DigiLib Systems Limited, New Zealand
+ *
+ * A component of the Greenstone digital library software
+ * from the New Zealand Digital Library Project at the
+ * University of Waikato, New Zealand.
+ *
+ * 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.
+ *
+ *********************************************************************/
+
+
+#ifndef GSDLTIMES_H
+#define GSDLTIMES_H
+
+#include <time.h>
+#include "text_t.h"
+
+// dates are stored in the format YYYY/MM/DD hh:mm:ss
+
+// returns "" if an error occurs
+text_t time2text (time_t time);
+
+// returns -1 if an error occurs
+time_t text2time (const text_t &timestr);
+
+#endif
Index: /main/tags/2.25/gsdl/lib/gsdltools.cpp
===================================================================
--- /main/tags/2.25/gsdl/lib/gsdltools.cpp	(revision 21064)
+++ /main/tags/2.25/gsdl/lib/gsdltools.cpp	(revision 21064)
@@ -0,0 +1,86 @@
+/**********************************************************************
+ *
+ * gsdltools.cpp -- 
+ * A component of the Greenstone digital library software
+ * from the New Zealand Digital Library Project at the
+ * University of Waikato, New Zealand.
+ *
+ * Copyright (C) 1999  The 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.
+ *
+ *********************************************************************/
+
+#include "gsdltools.h"
+
+bool littleEndian() {
+  char s[2] = {'\xFE', '\xEF'};
+
+  if (sizeof(unsigned short) == 2)
+    return *(unsigned short*)s == 0xEFFE;
+  else if (sizeof(unsigned int) == 2)
+    return *(unsigned int*)s == 0xEFFE;
+}
+
+text_t dm_safe (const text_t &instring) {
+
+  text_t outstring;
+  text_t::const_iterator here = instring.begin();
+  text_t::const_iterator end = instring.end();
+  while (here != end) {
+    if (*here == '_' || *here == '\\') outstring.push_back('\\');
+    outstring.push_back(*here);
+    here ++;
+  }
+  return outstring;
+}
+
+// gsdl_system spawns a completely separate program (i.e. the calling
+// program continues and terminates normally). Arguments containing special
+// characters (e.g. '&') should be quoted with ""
+
+// on unix systems youcan get the same effext as this function by doing a
+// system call and putting the spawned process in the background
+// (e.g. system (funcname options &);
+
+#if defined (__WIN32__)
+#include <windows.h>
+void gsdl_system (char *cmd, ostream &logout) {
+
+  STARTUPINFO ps = {sizeof(STARTUPINFO), NULL, NULL, NULL,
+                    0, 0, 0, 0, 0, 0,
+                    0, 0,
+                    0, 0, NULL,
+                    NULL, NULL, NULL};
+  PROCESS_INFORMATION pi;
+  BOOL res = CreateProcess(NULL,
+                           cmd,
+                           NULL,
+                           NULL,
+                           FALSE,
+                           DETACHED_PROCESS,
+                           NULL,
+                           NULL,
+                           &ps,
+                           &pi);
+  if (!res) {
+    logout << "Failed to start " << cmd << " process, error code " << GetLastError();
+  } 
+
+  CloseHandle(pi.hProcess);
+  CloseHandle(pi.hThread);
+}
+
+#endif
Index: /main/tags/2.25/gsdl/lib/gsdltools.h
===================================================================
--- /main/tags/2.25/gsdl/lib/gsdltools.h	(revision 21064)
+++ /main/tags/2.25/gsdl/lib/gsdltools.h	(revision 21064)
@@ -0,0 +1,56 @@
+/**********************************************************************
+ *
+ * gsdltools.h -- 
+ * A component of the Greenstone digital library software
+ * from the New Zealand Digital Library Project at the
+ * University of Waikato, New Zealand.
+ *
+ * Copyright (C) 1999  The 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.
+ *
+ *********************************************************************/
+
+
+#ifndef GSDLTOOLS_H
+#define GSDLTOOLS_H
+
+// don't actually use this but some windows
+// versions of STL complain about use of 
+// bool keyword without it
+#include "text_t.h"
+
+// returns true if machine is little endian
+bool littleEndian();
+
+// escapes '\' and '_' characters with '\'
+// note that single '\' characters occurring 
+// naturally within text (or filenames!!) will
+// be removed by the dm macro language
+text_t dm_safe (const text_t &instring);
+
+
+// gsdl_system spawns a completely separate program (i.e. the calling
+// program continues and terminates normally). Arguments containing special
+// characters (e.g. '&') should be quoted with ""
+
+// on unix systems youcan get the same effext as this function by doing a
+// system call and putting the spawned process in the background
+// (e.g. system (funcname options &);
+#if defined (__WIN32__)
+void gsdl_system (char *cmd, ostream &logout);
+#endif
+
+#endif
Index: /main/tags/2.25/gsdl/lib/gsdlunicode.cpp
===================================================================
--- /main/tags/2.25/gsdl/lib/gsdlunicode.cpp	(revision 21064)
+++ /main/tags/2.25/gsdl/lib/gsdlunicode.cpp	(revision 21064)
@@ -0,0 +1,643 @@
+/**********************************************************************
+ *
+ * gsdlunicode.cpp -- 
+ * Copyright (C) 1999  The New Zealand Digital Library Project
+ *
+ * A component of the Greenstone digital library software
+ * from the New Zealand Digital Library Project at the
+ * University of Waikato, New Zealand.
+ *
+ * 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.
+ *
+ *********************************************************************/
+
+#include "gsdlunicode.h"
+
+
+// unitool is currently in mg, if mg is not being used it should
+// be moved into GSDLHOME/lib 
+#include "unitool.h"
+
+#include "fileutil.h"
+
+#include <stdio.h>
+
+#if defined(GSDL_USE_OBJECTSPACE)
+#  include <ospace\std\iostream>
+#  include <ospace\std\fstream>
+#elif defined(GSDL_USE_IOS_H)
+#  include <iostream.h>
+#  include <fstream.h>
+#else
+#  include <iostream>
+#  include <fstream>
+#endif
+
+
+// converts a unicode encode text_t string to a utf-8
+// encoded text_t string
+text_t to_utf8 (text_t::const_iterator here, text_t::const_iterator end) {
+  text_t out;
+
+  unsigned char thischar[MAXUTF8CHARLEN];
+  int i, charlen;
+
+  while (here != end) {
+    charlen = output_utf8_char (*here, thischar, &thischar[MAXUTF8CHARLEN-1]);
+    for (i=0; i<charlen; i++) out.push_back(thischar[i]);
+    here++;
+  }
+
+  return out;
+}
+
+// converts a utf-8 encoded text_t string to a unicode
+// encoded text_t string
+text_t to_uni (const text_t &in) {
+  text_t out;
+  unsigned char *in_cstr = (unsigned char *)in.getcstr();
+  unsigned char *here = in_cstr;
+  unsigned char *end = in_cstr;
+
+  unsigned short unichar;
+  int charlen = 0;
+
+  // get the last valid character in the string
+  while (*end != '\0') end++;
+  end--;
+
+  while ((charlen = parse_utf8_char (here, end, &unichar)) > 0) {
+    out.push_back(unichar);
+    here += charlen;
+  }
+
+  delete in_cstr;
+
+  return out;
+}
+
+
+
+utf8inconvertclass::utf8inconvertclass () {
+  utf8buflen = 0;
+}
+
+void utf8inconvertclass::reset () {
+  start = NULL;
+  len = 0;
+  utf8buflen=0;
+}
+
+void utf8inconvertclass::convert (text_t &output, status_t &status) {
+  output.clear();
+  output.reserve (len/3);
+  
+  if (start == NULL || len == 0) {
+    if (utf8buflen == 0) status = finished;
+    else status = stopped;
+    return;
+  }
+
+  // don't want any funny sign conversions happening
+  unsigned char *here = (unsigned char *)start;
+  unsigned char *end = here+len-1;
+  unsigned short c;
+  size_t realcharlen;
+
+  size_t charlen = getutf8charlen ();
+  while (len > 0) {
+    if (charlen == 0) {
+      // start parsing a new character
+      utf8buflen = 0;
+
+      // fast common case
+      while (len > 3) {
+  	realcharlen = parse_utf8_char (here, end, &c);
+  	output.push_back (c);
+  	here += realcharlen;
+  	len -= realcharlen;
+      }
+
+      utf8buf[utf8buflen++] = *here;
+      ++here;
+      --len;
+      charlen = getutf8charlen ();
+
+    } else if (utf8buflen < charlen) {
+      // assumes charlen is always less than MAXUTF8CHARLEN
+      utf8buf[utf8buflen++] = *here;
+      ++here;
+      --len;
+    }
+
+    if (utf8buflen == charlen) {
+      // got a complete character
+      realcharlen = parse_utf8_char (utf8buf, &utf8buf[utf8buflen-1], &c);
+      output.push_back (c);
+      
+      // move any unparsed characters. If an error occurred some of
+      // the characters might be unused.
+      int i;
+      int diff = utf8buflen - realcharlen;
+      for (i=0; i < diff; i++) utf8buf[i] = utf8buf[i+diff];
+      utf8buflen = diff;
+      charlen = getutf8charlen ();
+    }
+  }
+
+  start = (char *)here; // save current position
+
+  if (utf8buflen == 0) status = finished;
+  else status = stopped;
+}
+
+
+// returns the length that the current contents of the 
+// utf8buf should be
+size_t utf8inconvertclass::getutf8charlen () {
+  if (utf8buflen == 0) return 0;
+
+  // one byte character
+  if (utf8buf[0] < 0x80) return 1;
+
+  // error, is not the start of a utf-8 character
+  if (utf8buf[0] < 0xc0) return 1;
+
+  // two bute character
+  if (utf8buf[0] < 0xe0) return 2;
+
+  // three byte character
+  if (utf8buf[0] < 0xf0) return 3;
+
+  // error, character too long for unicode
+  return 1;
+}
+
+
+void utf8outconvertclass::reset () {
+  input = NULL;
+  outs = NULL;
+  utf8buflen = 0;
+  utf8bufhere = 0;
+}
+
+// note that convert does not null-terminate the
+// output array of characters
+void utf8outconvertclass::convert (char *output, size_t maxlen, 
+				   size_t &len, status_t &status) {
+  if (input == NULL || output == NULL) {
+    if (utf8buflen == 0) status = finished;
+    else status = unfinished;
+    return;
+  }
+
+  // don't want any funny sign conversions happening
+  unsigned char *uoutput = (unsigned char *)output;
+  text_t::iterator textend = input->end();
+  len = 0;
+  while (len < maxlen) {
+    // empty the contents of the internal buffer
+    if (utf8buflen > 0) {
+      while (len < maxlen && utf8bufhere < utf8buflen) {
+	*uoutput = utf8buf[utf8bufhere];
+	uoutput++;
+	len++;
+	utf8bufhere++;
+      }
+
+      if (utf8bufhere == utf8buflen) {
+	utf8bufhere = 0;
+	utf8buflen = 0;
+      }
+    }
+
+    // fill up the buffer with the next character
+    if (utf8buflen == 0) {
+      if (texthere == textend) break; // finished!
+      if (!rzws || (*texthere != 0x200b))
+	utf8buflen = output_utf8_char (*texthere, utf8buf, 
+				       &utf8buf[MAXUTF8CHARLEN-1]);
+      texthere++;
+      utf8bufhere = 0;
+    }
+  }
+  
+  if (texthere == textend && utf8buflen == 0) status = finished;
+  else status = unfinished;
+}
+
+
+
+
+
+
+mapdata_t::mapdata_t () {
+  int i;
+
+  // reset all the map ptrs to be NULL
+  for (i=0; i<256; i++) {
+    ptrs[i] = (unsigned short *)NULL;
+  }
+
+  // say nothing has been loaded
+  loaded = false;
+}
+
+
+mapconvert::mapconvert () {
+  absentc = 0;
+}
+
+// setmapfile will cause loadmapfile to be called when conversion is
+// needed
+bool mapconvert::setmapfile (const text_t &thegsdlhome, const text_t &theencoding, 
+			     unsigned short theabsentc) {
+  // check to see if the mapfile has been already loaded
+  if (mapdata.loaded && gsdlhome == thegsdlhome &&
+      encoding == theencoding && absentc == theabsentc) 
+    return true;
+
+  unloadmapfile ();
+  gsdlhome = thegsdlhome;
+  encoding = theencoding;
+  absentc = theabsentc;
+  
+  return true;
+}
+
+
+
+// loadmapfile should be called before any conversion is done
+bool mapconvert::loadmapfile (const text_t &thegsdlhome, 
+			      const text_t &theencoding, 
+			      unsigned short theabsentc) {
+  FILE *mapfilein = (FILE *)NULL;
+
+  // check to see if the mapfile has been already loaded
+  if (mapdata.loaded && gsdlhome == thegsdlhome &&
+      encoding == theencoding && absentc == theabsentc) 
+    return true;
+
+  unloadmapfile ();
+  gsdlhome = thegsdlhome;
+  encoding = theencoding;
+  absentc = theabsentc;
+
+  // open the map file
+  text_t filename = filename_cat (gsdlhome, "unicode");
+  filename = filename_cat (filename, encoding);
+  filename += ".ump";
+  char *cfilename = filename.getcstr();
+  if (cfilename == (char *)NULL) return false;
+  mapfilein = fopen(cfilename, "rb");
+  delete cfilename;
+
+  if (mapfilein == (FILE *)NULL) return false;
+
+  unsigned char c, n1, n2;
+  unsigned short *arrptr;
+  int i;
+  c = fgetc (mapfilein);
+  while (!feof (mapfilein)) {
+    if (mapdata.ptrs[c] == (unsigned short *)NULL) {
+      // allocate a new array
+      arrptr = new unsigned short[256];
+      mapdata.ptrs[c] = arrptr;
+    } else arrptr = mapdata.ptrs[c];
+
+    // clear the array
+    for (i=0; i<256; i++) arrptr[i] = 0;
+    
+    // read in this block
+    n1 = fgetc (mapfilein);
+    n2 = fgetc (mapfilein);
+    i=0;
+    while (!feof (mapfilein)) {
+      arrptr[i] = ((unsigned short)n1 << 8) | (unsigned short)n2;
+
+      i++;
+      if (i >= 256) break;
+      n1 = fgetc (mapfilein);
+      n2 = fgetc (mapfilein);
+    }
+
+    c = fgetc (mapfilein);
+  }
+
+  mapdata.loaded = true;
+
+  return true;
+}
+
+void mapconvert::unloadmapfile () {
+  if (!mapdata.loaded) return;
+
+  int i;
+  for (i=0; i<256; i++) {
+    if (mapdata.ptrs[i] != (unsigned short *)NULL) {
+      delete [] mapdata.ptrs[i];
+      mapdata.ptrs[i] = (unsigned short *)NULL;
+    }
+  }
+
+  mapdata.loaded = false;
+}
+
+
+unsigned short mapconvert::convert (unsigned short c) {
+  if (!mapdata.loaded) {
+    if (!gsdlhome.empty() && !encoding.empty() &&
+	loadmapfile (gsdlhome, encoding, absentc)) {
+      // do nothing, successfully loaded database
+    } else return absentc;
+  }
+
+  if (c == 0) return 0; // 0 always maps to 0...
+
+  unsigned short n1 = c >> 8;
+  unsigned short n2 = c & 0xff;
+
+  unsigned short *arrptr = mapdata.ptrs[n1];
+  if (arrptr == (unsigned short *)NULL) return absentc;
+
+  if (arrptr[n2] == 0) return absentc;
+  return arrptr[n2];
+}
+
+text_t mapconvert::convert (const text_t &instr) {
+  if (!mapdata.loaded) return absentc;
+
+  text_t outstr;
+  text_t::const_iterator here = instr.begin();
+  text_t::const_iterator end = instr.end();
+
+  while (here != end) {
+    outstr.push_back(this->convert(*here));
+    here++;
+  }
+  
+  return outstr;
+}
+
+
+
+
+mapinconvertclass::mapinconvertclass () {
+  mapbuflen = 0;
+}
+
+void mapinconvertclass::reset () {
+  start = NULL;
+  len = 0;
+  mapbuflen=0;
+}
+
+void mapinconvertclass::convert (text_t &output, status_t &status) {
+  output.clear();
+
+  if (start == NULL || len == 0) {
+    if (mapbuflen == 0) status = finished;
+    else status = stopped;
+    return;
+  }
+
+  // don't want any funny sign conversions happening
+  unsigned char *here = (unsigned char *)start;
+
+  size_t charlen = getmapcharlen ();
+  while (len > 0) {
+    if (charlen == 0) {
+      // start parsing a new character
+      mapbuflen = 0;
+      mapbuf[mapbuflen++] = *here;
+      ++here;
+      --len;
+      charlen = getmapcharlen ();
+
+    } else if (mapbuflen < charlen) {
+      // assumes charlen is always less than MAXMAPCHARLEN
+      mapbuf[mapbuflen++] = *here;
+      ++here;
+      --len;
+    }
+
+    if (mapbuflen == charlen) {
+      // got a complete character
+      if (charlen == 1) {
+	// ascii character
+	output.push_back (mapbuf[0]);
+
+      } else {
+	// two byte character
+	output.push_back (converter.convert(((unsigned short)mapbuf[0] << 8) |
+					    (unsigned short)mapbuf[1]));
+      }
+
+      mapbuflen = 0;
+      charlen = 0;
+    }
+  }
+
+  start = (char *)here; // save current position
+
+  if (mapbuflen == 0) status = finished;
+  else status = stopped;
+}
+
+
+
+mapoutconvertclass::mapoutconvertclass () {
+  mapbuflen=0; 
+  mapbufhere=0;
+}
+
+void mapoutconvertclass::reset () {
+  input = NULL;
+  outs = NULL;
+  mapbuflen = 0;
+  mapbufhere = 0;
+}
+
+// note that convert does not null-terminate the
+// output array of characters
+void mapoutconvertclass::convert (char *output, size_t maxlen, 
+				 size_t &len, status_t &status) {
+  unsigned short outc;
+
+  if (input == NULL || output == NULL) {
+    if (mapbuflen == 0) status = finished;
+    else status = unfinished;
+    return;
+  }
+
+  // don't want any funny sign conversions happening
+  unsigned char *uoutput = (unsigned char *)output;
+  text_t::iterator textend = input->end();
+  len = 0;
+  while (len < maxlen) {
+    // empty the contents of the internal buffer
+    if (mapbuflen > 0) {
+      while (len < maxlen && mapbufhere < mapbuflen) {
+	*uoutput = mapbuf[mapbufhere];
+	uoutput++;
+	len++;
+	mapbufhere++;
+      }
+
+      if (mapbufhere == mapbuflen) {
+	mapbufhere = 0;
+	mapbuflen = 0;
+      }
+    }
+
+    // fill up the buffer with the next character
+    if (mapbuflen == 0) {
+      if (texthere == textend) break; // finished!
+      if (!rzws || (*texthere != 0x200b)) {
+	if (*texthere < 0x80) {
+	  mapbuf[0] = (unsigned char)*texthere;
+	  mapbuflen = 1;
+	} else {
+	  outc = converter.convert (*texthere);
+	  mapbuf[0] = (unsigned char)(outc >> 8);
+	  mapbuf[1] = (unsigned char)(outc & 0xff);
+	  mapbuflen = 2;
+	}
+      }
+
+      texthere++;
+      mapbufhere = 0;
+    }
+  }
+  
+  if (texthere == textend && mapbuflen == 0) status = finished;
+  else status = unfinished;
+}
+
+
+bool simplemapconvert::loadmapfile (bool in) {
+  if (loaded) return true;
+  if (mapfile.empty()) return false;
+
+  char *cfilename = mapfile.getcstr();
+#ifdef GSDL_USE_IOS_H
+  ifstream mapfilein (cfilename, ios::in | ios::nocreate);
+#else
+  ifstream mapfilein (cfilename, ios::in);
+#endif
+  delete cfilename;
+  if (!mapfilein) return false;
+
+  char cline[2048];
+  text_t line;
+
+  while (!mapfilein.eof()) {
+    mapfilein.getline (cline, 2048);
+    line.clear();
+    line.appendcstr (cline);
+    if (line.empty()) continue;
+    // remove comments
+    text_t::iterator end = line.end();
+    text_t::iterator here = findchar (line.begin(), end, '#');
+    if (here != end) {
+      line.erase (here, end);
+      if (line.empty()) continue;
+    }
+    
+    text_tarray parts;
+    splitchar (line.begin(), line.end(), '\t', parts);
+    
+    // do some simple sanity checks
+    if (parts.size() < 2) continue;
+    text_t::iterator begin1 = parts[0].begin();
+    text_t::iterator begin2 = parts[1].begin();
+    if (*begin1 != '0' || *(begin1+1) != 'x') continue;
+    if (*begin2 != '0' || *(begin2+1) != 'x') continue;
+    char *from = parts[0].getcstr();
+    char *to = parts[1].getcstr();
+    unsigned int f = 0, t = 0;
+    sscanf (from, "%i", &f);
+    sscanf (to, "%i", &t);
+    delete from;
+    delete to;
+    
+    if (in) mapping[(unsigned short)f] = (unsigned short)t;
+    else mapping[(unsigned short)t] = (unsigned short)f;
+  }
+
+  loaded = true;
+  return true;
+}
+
+unsigned short simplemapconvert::convert (unsigned short c, bool in) {
+
+  if (!loaded) 
+    if (!loadmapfile(in)) return absentc;
+  
+  return mapping[c];
+}
+
+
+void simplemapinconvertclass::convert (text_t &output, status_t &status) {
+  output.clear();
+  
+  if (start == NULL || len == 0) {
+    status = finished;
+    return;
+  }
+
+  // don't want any funny sign conversions happening
+  unsigned char *here = (unsigned char *)start;
+  while (len > 0) {
+
+    if (*here < 0x80)
+      output.push_back (*here); // append this character
+    else 
+      output.push_back (converter.convert(*here, true));
+
+    ++here;
+    --len;
+  }
+
+  start = (char *)here; // save current position
+  status = finished;
+}
+
+
+void simplemapoutconvertclass::convert (char *output, size_t maxlen, 
+					size_t &len, status_t &status) {
+
+  if (input == NULL || output == NULL) {
+    status = finished;
+    return;
+  }
+
+  // don't want any funny sign conversions happening
+  unsigned char *uoutput = (unsigned char *)output;
+  text_t::iterator textend = input->end();
+  len = 0;
+  while ((len < maxlen) && (texthere != textend)) {
+
+    if (*texthere < 0x80) *uoutput = (unsigned char)(*texthere);
+    else *uoutput = converter.convert (*texthere, false);
+
+    ++uoutput;
+    ++len;
+    ++texthere;
+  }
+  
+  if (texthere == textend) status = finished;
+  else status = unfinished;
+}
Index: /main/tags/2.25/gsdl/lib/gsdlunicode.h
===================================================================
--- /main/tags/2.25/gsdl/lib/gsdlunicode.h	(revision 21064)
+++ /main/tags/2.25/gsdl/lib/gsdlunicode.h	(revision 21064)
@@ -0,0 +1,272 @@
+/**********************************************************************
+ *
+ * gsdlunicode.h -- 
+ * Copyright (C) 1999  The New Zealand Digital Library Project
+ *
+ * A component of the Greenstone digital library software
+ * from the New Zealand Digital Library Project at the
+ * University of Waikato, New Zealand.
+ *
+ * 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.
+ *
+ *********************************************************************/
+
+
+#ifndef GSDLUNICODE_H
+#define GSDLUNICODE_H
+
+#include "text_t.h"
+
+
+// converts a unicode encode text_t string to a utf-8
+// encoded text_t string
+text_t to_utf8 (text_t::const_iterator here, text_t::const_iterator end);
+inline text_t to_utf8 (const text_t &in) {return to_utf8 (in.begin(), in.end());}
+
+// converts a utf-8 encoded text_t string to a unicode
+// encoded text_t string
+text_t to_uni (const text_t &in);
+
+
+
+#define MAXUTF8CHARLEN 3
+
+// convert from a utf-8 char stream to the text_t class
+class utf8inconvertclass : public inconvertclass {
+public:
+  utf8inconvertclass();
+  void reset ();
+  void convert (text_t &output, status_t &status);
+
+protected:
+  // buffer to hold unconverted characters in a stream
+  unsigned char utf8buf[MAXUTF8CHARLEN];
+  size_t utf8buflen;
+
+  // returns the length that the current contents of the 
+  // utf8buf should be
+  size_t getutf8charlen ();
+};
+
+
+// This class provides the option of removing zero width
+// spaces (U+200B) during the output. By default this
+// option is turned off. The functionality is actually
+// implemented by the sub-classes, this class just provides
+// the framework for these classes. 
+//
+// Note: by convention reset() should not reset the rzws flag.
+class rzwsoutconvertclass : public outconvertclass {
+public:
+  rzwsoutconvertclass () {rzws = 0;};
+  void set_rzws (int new_rzws) {rzws = new_rzws;};
+
+protected:
+  int rzws;
+};
+
+
+// Convert from a text_t class to a utf-8 char stream
+class utf8outconvertclass : public rzwsoutconvertclass {
+public:
+  utf8outconvertclass () {utf8buflen=0; utf8bufhere=0;};
+  void reset ();
+  // note that convert does not null-terminate the
+  // output array of characters
+  void convert (char *output, size_t maxlen, 
+		size_t &len, status_t &status);
+
+protected:
+  unsigned char utf8buf[MAXUTF8CHARLEN];
+  size_t utf8buflen;
+  size_t utf8bufhere;
+};
+
+
+// mapdata_t is used by mapconvert to hold the map file data
+class mapdata_t {
+public:
+  mapdata_t();
+  bool loaded;
+  unsigned short *ptrs[256];
+};
+
+// mapconvert is used in situations where conversion is best
+// done using a map file. The mapfile should reside in 
+// gsdlhome/unicode.
+class mapconvert {
+public:
+  mapconvert ();
+  ~mapconvert () {unloadmapfile();};
+
+  // setmapfile will cause loadmapfile to be called when conversion is
+  // needed
+  bool setmapfile (const text_t &thegsdlhome, const text_t &theencoding, 
+		   unsigned short theabsentc);
+
+  // loadmapfile should be called before any conversion is done
+  bool loadmapfile (const text_t &thegsdlhome, const text_t &theencoding, 
+		    unsigned short theabsentc);
+  void unloadmapfile ();
+
+  unsigned short convert (unsigned short c);
+
+  // note that this version of convert has different semantics to
+  // the convertclass version.
+  text_t convert (const text_t &instr);
+
+protected:
+  text_t gsdlhome;
+  text_t encoding;
+  unsigned short absentc;
+  mapdata_t mapdata;
+};
+
+
+
+#define MAXMAPCHARLEN 2
+
+// convert from a gb char stream to the unicode text_t class
+class mapinconvertclass : public inconvertclass {
+public:
+  mapinconvertclass();
+  virtual ~mapinconvertclass() {};
+
+  // setmapfile will cause loadmapfile to be called when conversion is needed
+  bool setmapfile (const text_t &thegsdlhome, const text_t &theencoding, 
+		    unsigned short theabsentc) {
+    return converter.setmapfile (thegsdlhome, theencoding, theabsentc);
+  };
+
+  // loadmapfile should be called before any conversion takes
+  // place
+  bool loadmapfile (const text_t &thegsdlhome, const text_t &theencoding, 
+		    unsigned short theabsentc) {
+    return converter.loadmapfile (thegsdlhome, theencoding, theabsentc);
+  };
+
+  void reset ();
+  void convert (text_t &output, status_t &status);
+
+protected:
+  // buffer to hold unconverted characters in a stream
+  unsigned char mapbuf[MAXMAPCHARLEN];
+  size_t mapbuflen;
+
+  // note: multiple instances of mapinconvert class are expensive
+  // as each will have its own copy of the map file data. This
+  // could be reduced by making map2unimap static, but then it
+  // wouldn't be thread safe.
+  mapconvert converter;
+
+  // returns the length that the current contents of the 
+  // mapbuf should be
+  inline size_t getmapcharlen () {
+    if (mapbuflen == 0) return 0;
+    if (mapbuf[0] < 0x80) return 1;
+    return 2;
+  }
+};
+
+
+// Convert from a text_t class to a map char stream
+class mapoutconvertclass : public rzwsoutconvertclass {
+public:
+  mapoutconvertclass ();
+  virtual ~mapoutconvertclass() {};
+
+  // setmapfile will cause loadmapfile to be called when conversion is needed
+  bool setmapfile (const text_t &thegsdlhome, const text_t &theencoding, 
+		    unsigned short theabsentc) {
+    return converter.setmapfile (thegsdlhome, theencoding, theabsentc);
+  };
+
+  // loadmapfile should be called before any conversion takes
+  // place
+  bool loadmapfile (const text_t &thegsdlhome, const text_t &theencoding, 
+		    unsigned short theabsentc) {
+    return converter.loadmapfile (thegsdlhome, theencoding, theabsentc);
+  };
+
+  void reset ();
+  void convert (char *output, size_t maxlen, 
+		size_t &len, status_t &status);
+
+protected:
+  unsigned char mapbuf[MAXMAPCHARLEN];
+  size_t mapbuflen;
+  size_t mapbufhere;
+
+  mapconvert converter;
+};
+
+
+// Simple input and output converter classes for use with 8 bit encodings
+// using simple textual map files. Map files should contain (at least) two
+// tab-separated fields. The first field is the mapped value and the second
+// field is the unicode value.
+
+struct ltus_t 
+{
+  bool operator()(const unsigned short &t1, const unsigned short &t2) const
+  { return t1 < t2; }
+};
+
+
+class simplemapconvert {
+public:
+  simplemapconvert () {absentc=0; loaded=false;}
+  unsigned short convert (unsigned short c, bool in);
+  void setmapfile (const text_t &themapfile) {mapfile = themapfile;}
+
+protected:
+  bool loadmapfile (bool in);
+
+  map <unsigned short, unsigned short, ltus_t> mapping;
+  bool loaded;
+  text_t mapfile;
+  unsigned short absentc;
+};
+
+
+class simplemapinconvertclass : public inconvertclass {
+public:
+  virtual ~simplemapinconvertclass () {}
+
+  void convert (text_t &output, status_t &status);
+
+  void setmapfile (const text_t &themapfile) {converter.setmapfile(themapfile);}
+  
+protected:
+  simplemapconvert converter;
+};
+
+class simplemapoutconvertclass : public rzwsoutconvertclass {
+public:
+  virtual ~simplemapoutconvertclass () {}
+
+  void convert (char *output, size_t maxlen, 
+		size_t &len, status_t &status);
+
+  void setmapfile (const text_t &themapfile) {converter.setmapfile(themapfile);}
+  
+protected:
+  simplemapconvert converter;
+};
+
+
+
+
+#endif
Index: /main/tags/2.25/gsdl/lib/text_t.cpp
===================================================================
--- /main/tags/2.25/gsdl/lib/text_t.cpp	(revision 21064)
+++ /main/tags/2.25/gsdl/lib/text_t.cpp	(revision 21064)
@@ -0,0 +1,749 @@
+/**********************************************************************
+ *
+ * text_t.cpp -- a simple 16-bit character string class
+ * Copyright (C) 1999  The New Zealand Digital Library Project
+ *
+ * A component of the Greenstone digital library software
+ * from the New Zealand Digital Library Project at the
+ * University of Waikato, New Zealand.
+ *
+ * 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.
+ *
+ *********************************************************************/
+
+#include "text_t.h"
+
+#if defined(GSDL_USE_OBJECTSPACE)
+#  include <ospace\std\algorithm>
+#elif defined(GSDL_USE_STL_H)
+#  if defined(GSDL_USE_ALGO_H)
+#    include <algo.h>
+#  else
+#    include <algorithm.h>
+#  endif
+#else
+#  include <algorithm>
+#endif
+
+
+#include "unitool.h"
+
+////////////////////////////////////
+// text_t methods
+////////////////////////////////////
+
+text_t::text_t () 
+{
+  setencoding(0);
+  clear ();
+}
+
+text_t::text_t (int i) 
+{
+  setencoding(0);
+  clear ();
+  appendint (i);
+}
+
+text_t::text_t (char *s) 
+{ 
+  setencoding(0);
+  clear ();
+  appendcstr (s);
+}
+
+void text_t::append (const text_t &t) 
+{
+  text.insert(text.end(), t.begin(), t.end());
+  //  const_iterator here, end=t.end();
+  //  for (here=t.begin(); here!=end;here++)
+  //    {
+  //      text.push_back(*here);
+  //    }
+}
+
+void text_t::appendrange (iterator first, iterator last) 
+{
+  text.insert(text.end(), first, last);
+  //  while (first != last) 
+  //  {
+  //    text.push_back (*first);
+  //    first++;
+  //  }
+}
+
+void text_t::appendrange (const_iterator first, const_iterator last) 
+{
+  text.insert(text.end(), first, last);
+  //  while (first != last) 
+  //  {
+  //    text.push_back (*first);
+  //    first++;
+  //  }
+}
+
+void text_t::appendint (int i)
+{
+  // deal with zeros and negatives
+  if (i == 0) 
+    {
+      text.push_back('0');
+      return;
+    }
+  else if (i < 0)
+    {
+      text.push_back('-');
+      i *= -1;
+    }
+
+  // get a buffer for the conversion
+  int maxbuflen = sizeof(int)*3;
+  char *buf = new char[maxbuflen];
+  int len = 0;
+  
+  // get the number in reverse
+  while (i > 0)
+    {
+      buf[len++] = '0'+ (i%10);
+      i = i/10;
+    }
+
+  // reverse the number
+  while (len > 0)
+    {
+      text.push_back(buf[--len]);
+    }
+
+  delete buf;
+}
+
+int text_t::getint () const
+{
+  int i = 0;
+  int mult = 1; // become -1 for negative numbers
+
+  const_iterator here = text.begin();
+  const_iterator end = text.end();
+  
+  // do plus and minus signs
+  if (here != end)
+    {
+      if (*here == '-')
+	{
+	  mult = -1;
+	  here++;
+	}
+      else if (*here == '+')
+	{
+	  mult = 1;
+	  here++;
+	}
+    }
+
+  // deal with the number
+  while ((here != end) && (*here >= '0') && (*here <= '9'))
+    {
+      i = 10*i + (*here - '0');
+      here++;
+    }
+
+  i *= mult;
+  return i;
+}
+
+
+
+void text_t::appendcarr (char *s, size_type len)
+{
+  unsigned char *us = (unsigned char *)s;
+  while (len > 0) 
+    {
+      text.push_back (*us); // append this character
+      us++;
+      len--;
+    }
+}
+
+void text_t::appendcstr (char *s) 
+{
+  unsigned char *us = (unsigned char *)s;
+  while (*us != '\0') 
+    {
+      text.push_back (*us); // append this character
+      us++;
+    }
+}
+
+
+// strings returned from getcarr and getcstr become the callers 
+// responsibility and should be deallocated with "delete"
+
+char *text_t::getcarr(size_type &len) const
+{
+  unsigned char *cstr = new unsigned char[size()];
+  len = 0;
+
+  const_iterator ithere = begin();
+  const_iterator itend = end();
+  while (ithere != itend)
+    {
+      if (*ithere < 256) cstr[len] = (unsigned char)(*ithere);
+      else {
+	// put a space or a question mark depending on what
+	// the character is. Question marks tell the user that
+	// they are missing some information.
+	if (is_unicode_space (*ithere)) cstr[len] = ' ';
+	else cstr[len] = '?';
+      }
+      len++;
+      ithere++;
+    }
+
+  return (char *)cstr;
+}
+
+char *text_t::getcstr() const
+{
+  unsigned char *cstr = new unsigned char[size() + 1];
+  const_iterator ithere = begin();
+  const_iterator itend = end();
+  int len = 0;
+
+  while (ithere != itend)
+    {
+      if (*ithere < 256) cstr[len] = (unsigned char)(*ithere);
+      else {
+	// put a space or a question mark depending on what
+	// the character is. Question marks tell the user that
+	// they are missing some information.
+	if (is_unicode_space (*ithere)) cstr[len] = ' ';
+	else cstr[len] = '?';
+      }
+      len++;
+      ithere++;
+    }
+
+  cstr[len] = '\0';
+
+  return (char *)cstr;
+}
+
+
+// general functions which work on text_ts
+
+// find a character within a range
+text_t::const_iterator findchar (text_t::const_iterator first, text_t::const_iterator last, 
+				 unsigned short c)
+{
+  while (first != last)
+    {
+      if (*first == c) break;
+      first++;
+    }
+  return first;
+}
+
+text_t::iterator findchar (text_t::iterator first, text_t::iterator last, 
+			   unsigned short c)
+{
+  while (first != last)
+    {
+      if (*first == c) break;
+      first++;
+    }
+  return first;
+}
+
+// get a string up to the next delimiter (which is skipped)
+text_t::const_iterator getdelimitstr (text_t::const_iterator first, 
+				      text_t::const_iterator last,
+				      unsigned short c, text_t &outstr)
+{
+  text_t::const_iterator here = first;
+  here = findchar (first, last, c);
+  outstr.clear();
+  outstr.appendrange (first, here);
+  if (here != last) here++; // skip c
+  return here;
+}
+
+text_t::iterator getdelimitstr (text_t::iterator first, text_t::iterator last,
+				unsigned short c, text_t &outstr)
+{
+  text_t::iterator here = first;
+  here = findchar (first, last, c);
+  outstr.clear();
+  outstr.appendrange (first, here);
+  if (here != last) here++; // skip c
+  return here;
+}
+
+// split a string with a character
+void splitchar (text_t::const_iterator first, text_t::const_iterator last,
+		unsigned short c, text_tset &outlist)
+{
+  outlist.erase(outlist.begin(), outlist.end());
+
+  text_t t;
+
+  while (first != last)
+    {
+      first = getdelimitstr (first, last, c, t);
+      outlist.insert (t);
+    }
+}
+
+void splitchar (text_t::const_iterator first, text_t::const_iterator last,
+		unsigned short c, text_tlist &outlist)
+{
+  outlist.erase(outlist.begin(), outlist.end());
+
+  text_t t;
+
+  while (first != last)
+    {
+      first = getdelimitstr (first, last, c, t);
+      outlist.push_back (t);
+    }
+}
+
+void splitchar (text_t::const_iterator first, text_t::const_iterator last,
+		unsigned short c, text_tarray &outlist)
+{
+  outlist.erase(outlist.begin(), outlist.end());
+
+  text_t t;
+
+  while (first != last)
+    {
+      first = getdelimitstr (first, last, c, t);
+      outlist.push_back (t);
+    }
+}
+
+// join a string using a character
+void joinchar (const text_tset &inlist, unsigned short c, text_t &outtext)
+{
+  outtext.clear ();
+
+  text_tset::const_iterator here = inlist.begin ();
+  text_tset::const_iterator end = inlist.end ();
+  bool first = true;
+  while (here != end)
+    {
+      if (!first) outtext.push_back (c);
+      first = false;
+      outtext += *here;
+      here++;
+    }
+}
+
+void joinchar (const text_tlist &inlist, unsigned short c, text_t &outtext)
+{
+  outtext.clear ();
+
+  text_tlist::const_iterator here = inlist.begin ();
+  text_tlist::const_iterator end = inlist.end ();
+  bool first = true;
+  while (here != end)
+    {
+      if (!first) outtext.push_back (c);
+      first = false;
+      outtext += *here;
+      here++;
+    }
+}
+
+void joinchar (const text_tarray &inlist, unsigned short c, text_t &outtext)
+{
+  outtext.clear ();
+
+  text_tarray::const_iterator here = inlist.begin ();
+  text_tarray::const_iterator end = inlist.end ();
+  bool first = true;
+  while (here != end)
+    {
+      if (!first) outtext.push_back (c);
+      first = false;
+      outtext += *here;
+      here++;
+    }
+}
+
+void joinchar (const text_tlist &inlist, text_t c, text_t &outtext)
+{
+  outtext.clear ();
+
+  text_tlist::const_iterator here = inlist.begin ();
+  text_tlist::const_iterator end = inlist.end ();
+  bool first = true;
+  while (here != end)
+    {
+      if (!first) outtext += c;
+      first = false;
+      outtext += *here;
+      here++;
+    }
+}
+
+void joinchar (const text_tset &inlist, text_t c, text_t &outtext)
+{
+  outtext.clear ();
+
+  text_tset::const_iterator here = inlist.begin ();
+  text_tset::const_iterator end = inlist.end ();
+  bool first = true;
+  while (here != end)
+    {
+      if (!first) outtext += c;
+      first = false;
+      outtext += *here;
+      here++;
+    }
+}
+
+void joinchar (const text_tarray &inlist, text_t c, text_t &outtext)
+{
+  outtext.clear ();
+
+  text_tarray::const_iterator here = inlist.begin ();
+  text_tarray::const_iterator end = inlist.end ();
+  bool first = true;
+  while (here != end)
+    {
+      if (!first) outtext += c;
+      first = false;
+      outtext += *here;
+      here++;
+    }
+}
+
+// count the occurances of a character within a range
+int countchar (text_t::const_iterator first, text_t::const_iterator last,
+	       unsigned short c)
+{
+  int count = 0;
+  while (first != last) {
+    if (*first == c) count ++;
+    first ++;
+  }
+  return count;
+}
+
+// return a substring of string from first up to but not including last
+text_t substr (text_t::const_iterator first, text_t::const_iterator last) {
+
+  text_t substr;
+  while (first != last) {
+    substr.push_back(*first);
+    first ++;
+  }
+  return substr;
+}
+
+
+// convert to lowercase
+void lc (text_t::iterator first, text_t::iterator last) {
+  while (first != last) {
+    *first = unicode_tolower(*first);
+    first++;
+  }
+}
+
+// convert to uppercase
+void uc (text_t::iterator first, text_t::iterator last) {
+  while (first != last) {
+    *first = unicode_toupper(*first);
+    first++;
+  }
+}
+
+
+// checks to see if it is a number (i.e. contains only 0-9)
+bool is_number (const text_t &text) {
+
+  text_t::const_iterator here = text.begin();
+  text_t::const_iterator end = text.end();
+
+  while (here != end) {
+    if ((*here!='0') && (*here!='1') && (*here!='2') &&
+	(*here!='3') && (*here!='4') && (*here!='5') &&
+	(*here!='6') && (*here!='7') && (*here!='8') &&
+	(*here!='9')) return false;
+    here ++;
+  }
+  return true;
+}
+
+
+// checks to see if the text has any letters or digits
+bool has_unicode_letdig (const text_t &text) {
+  if (text.empty()) return false;
+  
+  text_t::const_iterator here = text.begin();
+  text_t::const_iterator end = text.end();
+  while (here != end) {
+    if (is_unicode_letdig (*here)) return true;
+    here++;
+  }
+
+  return false;
+}
+
+
+
+////////////////////////////////////
+// convertclass methods
+////////////////////////////////////
+
+// conversion classes used for getting information in to and out of
+// the text_t class.
+
+convertclass::convertclass () 
+{
+  // nothing to do
+}
+
+void convertclass::reset ()
+{
+  // nothing to do
+}
+
+
+////////////////////////////////////
+// inconvertclass methods
+////////////////////////////////////
+
+// convert from a char stream to the text_t class
+// the default version assumes the input is a ascii
+// character array
+
+inconvertclass::inconvertclass () 
+{
+  start = NULL;
+  len = 0;
+}
+
+
+void inconvertclass::reset ()
+{
+  start = NULL;
+  len = 0;
+}
+
+void inconvertclass::setinput (char *thestart, size_t thelen)
+{
+  start = thestart;
+  len = thelen;
+}
+
+void inconvertclass::convert (text_t &output, status_t &status)
+{
+  output.clear();
+
+  if (start == NULL || len == 0)
+    {
+      status = finished;
+      return;
+    }
+
+  // don't want any funny sign conversions happening
+  unsigned char *here = (unsigned char *)start;
+  while (len > 0) 
+    {
+      output.push_back (*here); // append this character
+      ++here;
+      --len;
+    }
+
+  start = (char *)here; // save current position
+  status = finished;
+}
+
+// will treat the text_t as a 8-bit string and convert
+// it to a 16-bit string using the about convert method.
+text_t inconvertclass::convert (const text_t &t) {
+  text_t out;
+  text_t tmpout;
+  status_t status;
+  text_t::const_iterator here = t.begin();
+  text_t::const_iterator end = t.end();
+  unsigned char cbuf[256];
+  size_t cbuflen = 0;
+ 
+  while (here != end) {
+    while (here != end && cbuflen < 256) {
+      cbuf[cbuflen++] = (unsigned char)(*here & 0xff);
+      here++;
+    }
+
+    if (cbuflen > 0) {
+      setinput ((char *)cbuf, cbuflen);
+      status = unfinished;
+      while (status == unfinished) {
+	convert (tmpout, status);
+	out += tmpout;
+      }
+      cbuflen = 0;
+    }
+  }
+
+  out.setencoding (0); // unicode
+
+  return out;
+}
+
+// an instance of the default inconvertclass to do simple
+// conversions. Note that any functions that use this are
+// not reentrant. If a function needs to be reentrant it
+// should declare its own instance.
+inconvertclass ascii2text_t;
+
+
+////////////////////////////////////
+// outconvertclass methods
+////////////////////////////////////
+
+// Convert from a text_t class to a char stream
+// This default version assumes the output is a ascii
+// character array. If you set the output stream you
+// can use this class to output to a stream using the
+// << operator. The << operator can also be conveniently
+// used to set the output stream by doing something like
+//
+// cout << text_t2ascii << text_tstr << anothertext_tstr;
+//
+outconvertclass::outconvertclass ()
+{
+  input = NULL;
+  outs = NULL;
+}
+
+void outconvertclass::reset ()
+{
+  input = NULL;
+  outs = NULL;
+}
+
+void outconvertclass::setinput (text_t *theinput)
+{
+  input = theinput;
+  if (input != NULL) texthere = input->begin();
+}
+
+void outconvertclass::convert (char *output, size_t maxlen, 
+		      size_t &len, status_t &status)
+{
+  if (input == NULL || output == NULL)
+    {
+      status = finished;
+      return;
+    }
+
+  // don't want any funny sign conversions happening
+  unsigned char *uoutput = (unsigned char *)output;
+  text_t::iterator textend = input->end();
+  len = 0;
+  while ((len < maxlen) && (texthere != textend)) 
+    {
+      if (*texthere < 256) *uoutput = (unsigned char)(*texthere);
+      else {
+	// put a space or a question mark depending on what
+	// the character is. Question marks tell the user that
+	// they are missing some information.
+	if (is_unicode_space (*texthere)) *uoutput = ' ';
+	else *uoutput = '?';
+      }
+      ++uoutput;
+      ++len;
+      ++texthere;
+    }
+  
+  if (texthere == textend) status = finished;
+  else status = unfinished;
+}
+
+// will convert the 16-bit string to a 8-bit stream
+// and place the result in a text_t. This method uses
+// the above convert function.
+text_t outconvertclass::convert (const text_t &t) {
+  text_t out;
+  unsigned char cbuf[256];
+  size_t cbuflen = 0;
+  status_t status = unfinished;
+
+  setinput ((text_t *)&t); // discard constant
+  while (status == unfinished) {
+    convert ((char *)cbuf, 256, cbuflen, status);
+    out.appendcarr ((char *)cbuf, cbuflen);
+  }
+
+  out.setencoding (1); // other encoding
+  
+  return out;
+}
+
+
+void outconvertclass::setostream (ostream *theouts)
+{
+  outs = theouts;
+}
+
+ostream *outconvertclass::getostream ()
+{
+  return outs;
+}
+
+
+
+
+// an instance of the default outconvertclass to do simple
+// conversions
+outconvertclass text_t2ascii;
+
+
+
+// stream operators for the output class
+
+outconvertclass &operator<< (ostream &theouts, outconvertclass &outconverter)
+{
+  outconverter.setostream(&theouts);
+  return outconverter;
+}
+
+
+#define STREAMBUFSIZE 256
+outconvertclass &operator<< (outconvertclass &outconverter, const text_t &t)
+{
+  ostream *outstream = outconverter.getostream();
+
+  if (outstream == NULL) return outconverter;
+
+  char outbuf[STREAMBUFSIZE];
+  size_t len;
+  outconvertclass::status_t status = outconvertclass::unfinished;
+
+  // assume that there is no data needing converting
+  // left in the converter
+  outconverter.setinput ((text_t *)(&t)); // note the const -> nonconst conversion
+
+  while (status == outconvertclass::unfinished)
+    {
+      outconverter.convert (outbuf, STREAMBUFSIZE, len, status);
+      if (len > 0) outstream->write(outbuf, len);
+    }
+
+  return outconverter;
+}
Index: /main/tags/2.25/gsdl/lib/text_t.h
===================================================================
--- /main/tags/2.25/gsdl/lib/text_t.h	(revision 21064)
+++ /main/tags/2.25/gsdl/lib/text_t.h	(revision 21064)
@@ -0,0 +1,358 @@
+/**********************************************************************
+ *
+ * text_t.h -- a simple 16-bit character string class
+ * Copyright (C) 1999  The New Zealand Digital Library Project
+ *
+ * A component of the Greenstone digital library software
+ * from the New Zealand Digital Library Project at the
+ * University of Waikato, New Zealand.
+ *
+ * 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.
+ *
+ *********************************************************************/
+
+
+#ifndef TEXT_T_H
+#define TEXT_T_H
+
+#include "gsdlconf.h"
+
+#if defined(GSDL_USE_OBJECTSPACE)
+#  include <ospace\std\vector>
+#  include <ospace\std\list>
+#  include <ospace\std\set>
+#  include <ospace\std\map>
+#elif defined(GSDL_USE_STL_H)
+#  include <vector.h>
+#  include <list.h>
+#  include <set.h>
+#  include <map.h>
+#else
+#  include <vector>
+#  include <list>
+#  include <set>
+#  include <map>
+#endif
+
+// use the standard namespace
+#if !defined (GSDL_NAMESPACE_BROKEN)
+#if defined(GSDL_USE_OBJECTSPACE)
+using namespace ospace::std;
+#else
+using namespace std;
+#endif
+#endif
+
+// class prototypes
+class inconvertclass;
+class outconvertclass;
+
+
+// for those stupid compilers which need it
+#if defined(GSDL_NEED_DESTROY_USHORT)
+inline void destroy(unsigned short *) {};
+inline void destroy(int *) {};
+#endif
+
+typedef vector<unsigned short> usvector;
+
+// The class text_t can handle long strings which may contain
+// null characters. It uses unsigned shorts to represent up to
+// 64K character values.
+class text_t {
+  public:
+  //type support for ucvector
+  typedef usvector::iterator iterator;
+  typedef usvector::const_iterator const_iterator;
+  typedef usvector::reference reference;
+  typedef usvector::const_reference const_reference;
+  typedef usvector::size_type size_type;
+  typedef usvector::difference_type difference_type;
+  typedef usvector::const_reverse_iterator const_reverse_iterator;
+  typedef usvector::reverse_iterator reverse_iterator;
+  
+protected:
+  usvector text;
+  unsigned short encoding; // 0 = unicode, 1 = other
+  
+public:
+  // constructors
+  text_t ();
+  text_t (int i);
+  text_t (char *s); // assumed to be a normal c string
+
+  void setencoding (unsigned short theencoding) {encoding=theencoding;};
+  unsigned short getencoding () {return encoding;};
+
+  // basic container support
+  iterator begin () {return text.begin();}
+  const_iterator begin () const {return text.begin();}
+  iterator end () {return text.end();}
+  const_iterator end () const {return text.end();}
+
+  void erase(iterator pos) {text.erase(pos);}
+  void erase(iterator first, iterator last) {text.erase(first, last);}
+  void push_back(unsigned short c) {text.push_back(c);}
+  void pop_back() {text.pop_back();}
+  text_t &operator=(const text_t &x) {text=x.text; encoding=x.encoding; return *this;}
+  reference operator[](size_type n) {return text[n];};
+  const_reference operator[](size_type n) const {return text[n];};
+
+  void reserve (size_type n) {text.reserve(n);}
+  
+  bool empty () const {return text.empty();}
+  size_type size() const {return text.size();}
+  friend inline bool operator!=(const text_t& x, const text_t& y)
+	{return (x.text != y.text);}
+  friend inline bool operator==(const text_t& x, const text_t& y) 
+	{return (x.text == y.text);}
+  friend inline bool operator<(const text_t& x, const text_t& y) 
+	{return (x.text < y.text);}
+  friend inline bool operator>(const text_t& x, const text_t& y) 
+	{return (x.text > y.text);}
+  friend inline bool operator>=(const text_t& x, const text_t& y) 
+	{return (x.text >= y.text);}
+  friend inline bool operator<=(const text_t& x, const text_t& y) 
+	{return (x.text <= y.text);}
+  
+  // added functionality
+  void clear () {text.erase(text.begin(),text.end());}
+  void append (const text_t &t);
+  void appendrange (iterator first, iterator last);
+  void appendrange (const_iterator first, const_iterator last);
+  text_t &operator+= (const text_t &t) {append(t);return *this;}
+
+  // support for integers
+  void appendint (int i);
+  void setint (int i) {clear();appendint(i);}
+  text_t &operator=(int i) {setint (i);return *this;}
+  text_t &operator+= (int i) {appendint(i);return *this;}
+  int getint () const;
+
+  // support for arrays of chars
+  void appendcarr (char *s, size_type len);
+  void setcarr (char *s, size_type len) {clear();appendcarr(s,len);}
+
+  // support for null-terminated C strings
+  void appendcstr (char *s);
+  void setcstr (char *s) {clear();appendcstr(s);}
+  text_t &operator= (char *s) {setcstr(s);return *this;} // c string
+  text_t &operator+= (char *s) {appendcstr(s);return *this;} // c string
+
+  // support for const null-terminated C string
+  void appendcstr (const char *s);
+  void setcstr (const char *s) {clear();appendcstr((char *) s);}
+  text_t &operator= (const char *s) {setcstr((char *) s);return *this;} // c string
+  text_t &operator+= (const char *s) {appendcstr((char *) s);return *this;} // c string
+
+  // strings returned from getcarr and getcstr become the callers 
+  // responsibility and should be deallocated with "delete"
+  char *getcarr(size_type &len) const;
+  char *getcstr() const;
+};
+
+
+inline text_t operator+(const text_t &t1, const text_t &t2)
+{
+  text_t tnew = t1;
+  tnew.append(t2);
+  return tnew;
+}
+
+inline text_t operator+(const text_t &t1, int i1)
+{
+  text_t tnew = t1;
+  tnew.appendint(i1);
+  return tnew;
+}
+
+inline text_t operator+(const text_t &t1, char *s1)
+{
+  text_t tnew = t1;
+  tnew.appendcstr(s1);
+  return tnew;
+}
+
+
+
+
+struct eqtext_t 
+{
+  bool operator()(const text_t &t1, const text_t &t2) const
+  { return t1 == t2; }
+};
+
+struct lttext_t 
+{
+  bool operator()(const text_t &t1, const text_t &t2) const
+  { return t1 < t2; }
+};
+
+
+// frequently used derived types
+typedef set<text_t,lttext_t> text_tset;
+typedef list<text_t> text_tlist;  // more efficient for insertions/deletions
+typedef vector<text_t> text_tarray; // more space efficient than text_tlist
+typedef map<text_t, text_t, lttext_t> text_tmap;
+
+
+// general functions which work on text_ts
+
+// find a character within a range
+text_t::const_iterator findchar (text_t::const_iterator first, text_t::const_iterator last, 
+				 unsigned short c);
+text_t::iterator findchar (text_t::iterator first, text_t::iterator last, 
+			   unsigned short c);
+
+// get a string up to the next delimiter (which is skipped)
+text_t::const_iterator getdelimitstr (text_t::const_iterator first, 
+				      text_t::const_iterator last,
+				      unsigned short c, text_t &outstr);
+text_t::iterator getdelimitstr (text_t::iterator first, text_t::iterator last,
+				unsigned short c, text_t &outstr);
+
+// split a string with a character
+void splitchar (text_t::const_iterator first, text_t::const_iterator last,
+		unsigned short c, text_tset &outlist);
+void splitchar (text_t::const_iterator first, text_t::const_iterator last,
+		unsigned short c, text_tlist &outlist);
+void splitchar (text_t::const_iterator first, text_t::const_iterator last,
+		unsigned short c, text_tarray &outlist);
+
+// join a string using a character
+void joinchar (const text_tset &inlist, unsigned short c, text_t &outtext);
+void joinchar (const text_tlist &inlist, unsigned short c, text_t &outtext);
+void joinchar (const text_tarray &inlist, unsigned short c, text_t &outtext);
+void joinchar (const text_tset &inlist, text_t c, text_t &outtext);
+void joinchar (const text_tlist &inlist, text_t c, text_t &outtext);
+void joinchar (const text_tarray &inlist, text_t c, text_t &outtext);
+
+// count the occurances of a character within a range
+int countchar (text_t::const_iterator first, text_t::const_iterator last,
+	       unsigned short c);
+
+// return a substring of string from first up to but not including last
+text_t substr (text_t::const_iterator first, text_t::const_iterator last);
+
+// convert to lowercase
+void lc (text_t::iterator first, text_t::iterator last);
+inline void lc (text_t &t) {lc (t.begin(), t.end());}
+
+// convert to uppercase
+void uc (text_t::iterator first, text_t::iterator last);
+inline void uc (text_t &t) {uc (t.begin(), t.end());}
+
+// checks to see if it is a number (i.e. contains only 0-9)
+bool is_number (const text_t &text);
+
+// checks to see if the text has any letters or digits
+bool has_unicode_letdig (const text_t &text);
+
+
+// conversion classes used for getting information in to and out of
+// the text_t class.
+
+class convertclass 
+{
+public:
+  enum status_t {finished, stopped, unfinished};
+  
+  convertclass ();
+  virtual void reset ();
+};
+
+
+
+// convert from a char stream to the text_t class
+// the default version assumes the input is a ascii
+// character array
+class inconvertclass : public convertclass
+{
+public:
+  inconvertclass ();
+  void reset ();
+  void setinput (char *thestart, size_t thelen);
+
+  // output will be cleared before the conversion
+  virtual void convert (text_t &output, status_t &status);
+
+  // will treat the text_t as a 8-bit string and convert
+  // it to a 16-bit string using the about convert method.
+  text_t convert (const text_t &t);
+
+protected:
+  char *start;
+  size_t len;
+};
+
+// to get something which will do the conversion
+// to ascii declare a (non global!) instance like
+// this
+// inconvertclass ascii2text_t;
+
+#if defined(GSDL_USE_IOS_H)
+#include <ostream.h>
+#else
+#include <ostream>
+#endif
+
+// Convert from a text_t class to a char stream
+// This default version assumes the output is a ascii
+// character array. If you set the output stream you
+// can use this class to output to a stream using the
+// << operator. The << operator can also be conveniently
+// used to set the output stream by doing something like
+//
+// cout << text_t2ascii << textstr << anothertextstr;
+//
+// this class assumes that the input text doesn't change
+// while the conversion takes place
+class outconvertclass : public convertclass
+{
+public:
+  outconvertclass ();
+  void reset ();
+  void setinput (text_t *theinput);
+  // note that convert does not null-terminate the
+  // output array of characters
+  virtual void convert (char *output, size_t maxlen, 
+			size_t &len, status_t &status);
+
+  // will convert the 16-bit string to a 8-bit stream
+  // and place the result in a text_t. This method uses
+  // the above convert function.
+  text_t convert (const text_t &t);
+
+  void setostream (ostream *theouts);
+  ostream *getostream ();
+
+protected:
+  text_t *input;
+  text_t::iterator texthere; // only valid if input is valid
+
+  ostream *outs;
+};
+
+// to get something which will do the conversion
+// to text_t declare a (non global!) instance like
+// this
+// outconvertclass text_t2ascii;
+
+
+// stream operators for the output class
+outconvertclass &operator<< (ostream &theouts, outconvertclass &outconverter);
+outconvertclass &operator<< (outconvertclass &outconverter, const text_t &t);
+
+#endif
Index: /main/tags/2.25/gsdl/lib/win32.mak
===================================================================
--- /main/tags/2.25/gsdl/lib/win32.mak	(revision 21064)
+++ /main/tags/2.25/gsdl/lib/win32.mak	(revision 21064)
@@ -0,0 +1,70 @@
+###########################################################################
+#
+# win32 makefile -- lib
+# A component of the Greenstone digital library software
+# from the New Zealand Digital Library Project at the
+# University of Waikato, New Zealand.
+#
+# Copyright (C) 1999  The 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.
+#
+###########################################################################
+
+GSDLHOME = c:\gsdl
+STLPATH = c:\stlport
+
+AR = lib
+CC = cl
+CPPFLAGS =
+DEFS = -DQUIET -D__WIN32__ -DGSDL_NAMESPACE_BROKEN -DGSDL_USE_IOS_H \
+	-DSHORT_SUFFIX -DPARADOCNUM -DHAVE_CONFIG_H -D__STL_NO_NEW_IOSTREAMS
+INCLUDES = -I$(GSDLHOME)\packages\mg\lib -I$(STLPATH)
+
+COMPILE = $(CC) -c $(CPPFLAGS) $(DEFS) $(INCLUDES)
+
+.SUFFIXES:
+.SUFFIXES: .c .obj
+.c.obj:
+	$(COMPILE) $<
+
+.SUFFIXES: .cpp .obj
+.cpp.obj:
+	$(COMPILE) $< 
+
+HEADERS = \
+  cfgread.h      fileutil.h     gsdlunicode.h  text_t.h \
+  display.h      gsdlconf.h     gsdltimes.h    gsdltools.h
+
+SOURCES = \
+  cfgread.cpp      fileutil.cpp     text_t.cpp \
+  display.cpp      gsdlunicode.cpp  gsdltimes.cpp  gsdltools.cpp
+
+OBJECTS = \
+  cfgread.obj        fileutil.obj       text_t.obj   \
+  display.obj        gsdlunicode.obj    gsdltimes.obj  gsdltools.obj
+
+all: gsdllib.lib
+
+gsdllib.lib : $(OBJECTS)
+	del gsdllib.lib
+	$(AR) /out:gsdllib.lib $(OBJECTS)
+
+clean:
+	del *.obj 
+	del gsdllib.lib
+
+install:
Index: /main/tags/2.25/gsdl/macros/Chktrans.pl
===================================================================
--- /main/tags/2.25/gsdl/macros/Chktrans.pl	(revision 21064)
+++ /main/tags/2.25/gsdl/macros/Chktrans.pl	(revision 21064)
@@ -0,0 +1,145 @@
+#! /usr/bin/perl -w
+
+use strict;
+
+my @languages = ("chinese", "french", "german", "maori");
+
+print "
+Chktrans.pl
+
+This file checks english.dm and english2.dm against 
+translations made in other languages.  It outputs 
+ whether the translation exists in each language,
+ what macros override the English (default) macros
+ what macros have not been translated,
+ what additional macros exist.
+
+Current languages:
+";
+
+foreach my $l (@languages) {
+    print " $l\n";
+}
+
+print "\nReading english.dm\n";
+
+open(E, "<english.dm");
+
+my $line;
+my $count = 0;
+my %macro;
+
+while (<E>) {
+    chomp;
+    $line = $_;
+
+    next unless ($line =~ /^_\w+_ +\{/);
+    
+    $line =~ s/ +\{.*//;
+    $macro{$line} = 1;
+    $count++;
+}
+
+print "Read $count macros.\n\n";
+
+my $file;
+
+foreach my $l (@languages) {
+    $file = "$l.dm";
+
+    print "=============================================\nLanguage: $l\n";
+
+    # make sure thwere is a translation for the language
+    if (!-e "$file") {
+	print "$file doesn't exist\n\n";
+	next;
+    }
+    
+    # read the macros in this language
+    print "Reading $file\n";
+    open(L, "<$file");
+    my (%lm, %lmnew, %lr, %lrnew);
+    my $lc = 0;
+    while (<L>) {
+	chomp;
+	$line = $_;
+	
+	next unless ($line =~ /^_\w+_/);
+	next unless ($line =~ /\{/);
+	
+	$line =~ s/ +\{.*//;
+	# There are four types of macro, the combos of:
+	#  With or without macro country code
+	#  Present or not present in %macro
+	if ($line =~ /\[/) {
+	    $line =~ s/ .*//;
+	    if (defined($macro{$line})) {
+		$lm{$line} = $line;
+	    } else {
+		$lmnew{$line} = $line;
+	    }
+	} else {
+	    if (defined($macro{$line})) {
+		$lr{$line} = $line;
+	    } else {
+		$lrnew{$line} = $line;
+	    }
+	}
+	$lc++;
+    }
+    close L;
+    print "Read $lc macros.\n\n";
+
+    # How many macros operate correctly
+    print (scalar keys %lm);
+    print" macros are translated from english to $l\n\n";
+   
+    # What are the new macros?
+    if (scalar keys %lmnew) {
+	print (scalar keys %lmnew);
+	print" macros are new $l macros with no eqivalents in english.dm:\n";
+	foreach my $m (sort (keys (%lmnew))) {
+	    print "$m ";
+	}
+	print "\n\n";
+    }
+
+    # What are the new macros?
+    if (scalar keys %lrnew) {
+	print (scalar keys %lrnew);
+	print" macros are new macros in english that do not appear in english.dm:\n";
+	foreach my $m (sort (keys (%lrnew))) {
+	    print "$m ";
+	}
+	print "\n\n";
+    }
+
+    # Which languages override their english counterparts?
+    if (scalar keys %lr) {
+	print (scalar keys %lr);
+	print" macros override equivalents in english.dm ";
+	print"(It doesn't matter if you override macros like widths, heights, and URLs):\n";
+	foreach my $m (sort (keys (%lr))) {
+	    print "$m ";
+	}
+	print "\n\n";
+    }
+
+    # Which macros in english.dm do not appear in the newfile?
+    my @missing = ();
+    foreach my $m (sort (keys (%macro))) {
+	next if defined($lm{$m});
+	push @missing, $m;
+    }
+    if (scalar @missing) {
+	print (scalar @missing);
+	print " macros in english.dm have no entry in $l.dm:\n";
+	foreach my $m (sort @missing) {
+	    print "$m ";
+	}
+	print "\n\n";
+    }
+
+    print "\n";
+
+}
Index: /main/tags/2.25/gsdl/macros/about.dm
===================================================================
--- /main/tags/2.25/gsdl/macros/about.dm	(revision 21064)
+++ /main/tags/2.25/gsdl/macros/about.dm	(revision 21064)
@@ -0,0 +1,38 @@
+package about
+
+#######################################################################
+# Icons
+#######################################################################
+
+_imagethispage_ {<img src="_httpiconhabout_" width=_widthhabout_ height=_heighthabout_>}
+
+# don't want link to 'about' page
+_imagecollection_ {_If_("_iconcollection_" ne "",
+	<img src="_iconcollection_" border=0>,<br><br><h2>_collectionname_</h2>)}
+_imagecollection_ [v=1] {<br><br><h2>_collectionname_</h2>}
+
+#######################################################################
+# about page content 
+#######################################################################
+
+_pagetitle_ {_collectionname_}
+
+_content_ {
+<center>
+_navigationbar_
+</center>
+_query:queryform_
+<p>_iconblankbar_
+<p>_textabout_
+_textsubcollections_
+<h3>_help:textsimplehelpheading_</h3>
+_help:simplehelp_
+}
+
+_textabout_ {
+<h3>_textabcol_</h3>
+_Global:collectionextra_
+}
+
+# set from within server
+_textsubcollections_ {}
Index: /main/tags/2.25/gsdl/macros/authen.dm
===================================================================
--- /main/tags/2.25/gsdl/macros/authen.dm	(revision 21064)
+++ /main/tags/2.25/gsdl/macros/authen.dm	(revision 21064)
@@ -0,0 +1,64 @@
+package authen
+
+#######################################################################
+# page content                     
+#######################################################################
+
+_pagetitle_ {_textGSDLtitle_}
+_imagethispage_ {_imagegreenstone_}
+
+_content_ {
+<br><br><br><br>
+<form name="login" method="get" action="_gwcgi_">
+<input type=hidden name="e" value="_If_(_cgiarger_,_cgiarger_,_decodedcompressedoptions_)">
+_hiddenargs_
+<center><table width=_pagewidth_>
+<tr><td>
+_messagestatus_
+</td></tr>
+
+<tr><td>
+<table><tr><td>_textusername_</td>
+<td><input type="text" name="un" value="_cgiargun_" size=10></td>
+<td></td></tr>
+<tr><td>_textpassword_</td>
+<td><input type="password" name="pw" size=10></td>
+<td><input type="submit" value="sign in"></td>
+</tr>
+</table>
+</td></tr>
+</table>
+</form>
+}
+
+
+_messageinvalid_ {_textmessageinvalid_}
+
+_messagefailed_ {_textmessagefailed_}
+
+_messageenabled_ {}
+
+_messagedisabled_ {_textmessagedisabled_}
+
+_messagepermissiondenied_ {_textmessagepermissiondenied_}
+
+_messagestalekey_ {_textmessagestalekey_}
+
+
+#################################
+# when authentication is accepted
+#################################
+
+package authenok
+
+
+#######################################################################
+# page content                     
+#######################################################################
+
+_pagetitle_ {_authen:textGSDLtitle_}
+_imagethispage_ {_imagegreenstone_}
+
+_content_ {
+_authen:messagestatus_
+}
Index: /main/tags/2.25/gsdl/macros/base.dm
===================================================================
--- /main/tags/2.25/gsdl/macros/base.dm	(revision 21064)
+++ /main/tags/2.25/gsdl/macros/base.dm	(revision 21064)
@@ -0,0 +1,690 @@
+#######################################################################
+# GLOBAL MACROS 
+#######################################################################
+
+package Global
+
+##########
+
+_htmlextra_ {}
+
+_starthighlight_ {<b><u>}
+_endhighlight_ {</u></b>}
+
+#######################################################################
+# page content
+#
+# these should always be overridden for each page/collection 
+#######################################################################
+
+_content_ {<p><h2>oops</h2>
+_textdefaultcontent_}
+_pagetitle_ {_textdefaulttitle_}
+_imagethispage_ {}
+_iconcollection_ {}
+_collectionname_ {}
+
+_imagecollection_ {_If_("_iconcollection_" ne "",
+<a href="_httppageabout_"><img src="_iconcollection_" border=0></a>,
+_imagecollectionv_}
+_imagecollection_ [v=1] {_imagecollectionv_}
+_imagecollectionv_ {_If_(_collectionname_,<br><br><h2><a href="_httppageabout_">_collectionname_</a></h2>)}
+
+#######################################################################
+# these width macros are read in by the server when calculating 
+# width of navigation bar etc. There should be one for each 
+# classification that this receptionist supports, one for the 
+# search button, and the _pagewidth_ macro which is the total width
+# of the page
+#######################################################################
+
+# width of tabs when displaying tables of contents
+_tabwidth_ {25}
+
+_pagewidth_ {537}
+# defaultwidth is the width buttons default to if not included in this list
+_defaultwidth_ {87}
+_searchwidth_ {_widthtsrchx_}
+_Titlewidth_ {_widthttitlx_}
+_Listwidth_ {_widthtlistx_}
+_Creatorwidth_ {_widthtauthx_}
+_Serieswidth_ {_widthtserx_}
+_Datewidth_ {_widthtdatex_}
+_Subjectwidth_ {_widthtsubjx_}
+_Towidth_ {_widthttox_}
+_Fromwidth_ {_widthtfromx_}
+_Organizationwidth_ {_widthtorgx_}
+_Howtowidth_ {_widththowx_}
+_Topicwidth_ {_widthttopicx_}
+_Browsewidth_ {_widthtbrwsex_}
+_Peoplewidth_ {_widthtpeopx_}
+_Languagewidth_ {_widthtlangx_}
+_Acronymswidth_ {_widthtacrox_}
+
+#######################################################################
+# Macros whose values are set from within the server at runtime. These 
+# are here only for reference and to set default values if required.           
+#######################################################################
+
+# _win32_ will be set to 1 if we're on windows
+_win32_ {}
+
+_navigationbar_ {}
+_javaimagesnavbar_ {}
+_javaimagescontent_ {}
+_widthtspace_ {2}
+
+# all cgi args are set as _cgiargX_ macros - those I've put here 
+# are those that need to default to something
+_cgiargd_ {}
+_cgiargcl_ {}
+
+# set from within the query action
+_hselection_ {}
+_jselection_ {}
+_nselection_ {}
+#granularity selection for mgpp
+_gselection_ {}
+#######################################################################
+# navigation bar images
+#
+#######################################################################
+
+# the spacer image - the width of this is set from server
+_imagespacer_ {<img 
+src="_httpicontspace_" width="_widthtspace_" height="_heighttspace_">}
+_imagespacer_[v=1] {<br>
+}
+
+# image macros for all the classifications currently supported by
+# this receptionist.
+#
+# image macros for to and from added by gwp on 2000 june 13
+
+_imagesearch_ {<a href="_httpquery_" 
+    onMouseover = "img\_on('search')"
+    onMouseout = "img\_off('search')"><img name="search"
+        src="_httpicontsrchof_" width="_widthtsrchx_" height="_heighttsrchx_" 
+        border="0" alt="_textimagesearch_"></a>}
+_imagesearch_[v=1] {<a href="_httpquery_">_textimagesearch_</a><br>
+}
+
+_imageTitle_ {<a href="_httpbrowseTitle_"
+    onMouseover = "img\_on('titles')" 
+    onMouseout = "img\_off('titles')"><img name="titles" 
+        src="_httpiconttitlof_" width=_widthttitlx_ height=_heightttitlx_ 
+        border=0 alt="_textimageTitle_"></a>}
+_imageTitle_[v=1] {<a href="_httpbrowseTitle_">_textimageTitle_</a><br>
+}
+
+_imageCreator_ {<a href="_httpbrowseCreator_"
+    onMouseover = "img\_on('authors')" 
+    onMouseout = "img\_off('authors')"><img name="authors" 
+        src="_httpicontauthof_" width=_widthtauthx_ height=_heighttauthx_ 
+        border=0 alt="_textimageCreator_"></a>}
+_imageCreator_[v=1] {<a href="_httpbrowseCreator_">_textimageCreator_</a><br>
+}
+
+_imageSeries_ {<a href="_httpbrowseSeries_"
+    onMouseover = "img\_on('series')" 
+    onMouseout = "img\_off('series')"><img name="series" 
+        src="_httpicontserof_" width="_widthtserx_" height="_heighttserx_" 
+        border="0" alt="_textimageSeries_"></a>}
+_imageSeries_[v=1] {<a href="_httpbrowseSeries_">_textimageSeries_</a><br>
+}
+
+_imageDate_ {<a href="_httpbrowseDate_"
+    onMouseover = "img\_on('dates')" 
+    onMouseout = "img\_off('dates')"><img name="dates" 
+        src="_httpicontdateof_" width="_widthtdatex_" height="_heighttdatex_" 
+        border="0" alt="_textimageDate_"></a>}
+_imageDate_[v=1] {<a href="_httpbrowseDate_">_textimageDate_</a><br>
+}
+
+_imageSubject_ {<a href="_httpbrowseSubject_"
+    onMouseover = "img\_on('subjects')" 
+    onMouseout = "img\_off('subjects')"><img name="subjects" 
+        src="_httpicontsubjof_" width="_widthtsubjx_" height="_heighttsubjx_" 
+        border="0" alt="_textimageSubject_"></a>}
+_imageSubject_[v=1] {<a href="_httpbrowseSubject_">_textimageSubject_</a><br>
+}
+
+_imageTo_ {<a href="_httpbrowseTo_"
+    onMouseover = "img\_on('to')" 
+    onMouseout = "img\_off('to')"><img name="to" 
+        src="_httpiconttoof_" width="_widthttox_" height="_heightttox_" 
+        border="0" alt="_textimageTo_"></a>}
+_imageTo_[v=1] {<a href="_httpbrowseTo_">_textimageTo_</a><br>
+}
+
+_imageFrom_ {<a href="_httpbrowseFrom_"
+    onMouseover = "img\_on('from')" 
+    onMouseout = "img\_off('from')"><img name="from" 
+        src="_httpicontfromof_" width="_widthtfromx_" height="_heighttfromx_" 
+        border="0" alt="_textimageFrom_"></a>}
+_imageFrom_[v=1] {<a href="_httpbrowseFrom_">_textimageFrom_</a><br>
+}
+
+_imageOrganization_ {<a href="_httpbrowseOrganization_"
+    onMouseover = "img\_on('org')" 
+    onMouseout = "img\_off('org')"><img name="org" 
+        src="_httpicontorgof_" width="_widthtorgx_" height="_heighttorgx_" 
+        border="0" alt="_textimageOrganization_"></a>}
+_imageOrganization_[v=1] {<a href="_httpbrowseOrganization_">_textimageOrganization_</a><br>
+}
+
+_imageHowto_ {<a href="_httpbrowseHowto_"
+    onMouseover = "img\_on('how')" 
+    onMouseout = "img\_off('how')"><img name="how" 
+        src="_httpiconthowof_" width="_widththowx_" height="_heightthowx_" 
+        border="0" alt="_textimageHowto_"></a>}
+_imageHowto_[v=1] {<a href="_httpbrowseHowto_">_textimageHowto_</a><br>
+}
+
+_imageTopic_ {<a href="_httpbrowseTopic_"
+    onMouseover = "img\_on('topic')" 
+    onMouseout = "img\_off('topic')"><img name="topic" 
+        src="_httpiconttopicof_" width="_widthttopicx_" height="_heightttopicx_" 
+        border="0" alt="_textimageTopic_"></a>}
+_imageTopic_[v=1] {<a href="_httpbrowseTopic_">_textimageTopic_</a><br>
+}
+
+_imageBrowse_ {<a href="_httpbrowseBrowse_"
+    onMouseover = "img\_on('browse')" 
+    onMouseout = "img\_off('browse')"><img name="browse" 
+        src="_httpicontbrwseof_" width="_widthtbrwsex_" height="_heighttbrwsex_" 
+        border="0" alt="_textimageBrowse_"></a>}
+_imageBrowse_[v=1] {<a href="_httpbrowseBrowse_">_textimageBrowse_</a><br>
+}
+
+_imagePeople_ {<a href="_httpbrowsePeople_"
+    onMouseover = "img\_on('People')"
+    onMouseout = "img\_off('People')"><img name="People"
+        src="_httpicontpeopof_" width=_widthtpeopx_ height=_heighttpeopx_
+        border=0 alt="_textimagePeople_"></a>}
+_imagePeople_[v=1] {<a href="_httpbrowsePeople_">_textimagePeople_</a><br>
+}
+
+_imageLanguage_ {<a href="_httpbrowseLanguage_"
+    onMouseover = "img\_on('Language')"
+    onMouseout = "img\_off('Language')"><img name="Language"
+        src="_httpicontlangof_" width=_widthtlangx_ height=_heighttlangx_
+        border=0 alt="_textimageLanguage_"></a>}
+_imageLanguage_[v=1] {<a href="_httpbrowseLanguage_">_textimageLanguage_</a><br>
+}
+
+_imageAcronyms_ {<a href="_httpbrowseAcronyms_"
+    onMouseover = "img\_on('Acronyms')"
+    onMouseout = "img\_off('Acronyms')"><img name="Acronyms"
+        src="_httpicontacroof_" width=_widthtacrox_ height=_heighttacrox_
+        border=0 alt="_textimageAcronyms_"></a>}
+_imageAcronyms_[v=1] {<a href="_httpbrowseAcronyms_">_textimageAcronyms_</a><br>
+}
+
+
+#######################################################################
+# java images/scripts
+#######################################################################
+
+# the _javalinks_ macros are the flashy image links at the top right of
+# the page. 
+
+_javalinks_ {_imagehome__imagehelp__imagepref_}
+_javalinks_ [v=1] {
+_imagehome_<br>
+_imagehelp_<br>
+_imagepref_<br>
+}
+
+# the javaimages macros contain the javascript code required
+# by each flashy javascript image. _javaimagesheader_ contains those
+# images at the top right of the page, _javaimagesnavbar_ (set
+# from within the server) contains those images in the navigation bar,
+# and _javaimagescontent_ (also set in server) contains any other 
+# javascript images that occur in the page. 
+# the javaimages macros should contain _javaX_ macros for each javascript
+# image link within the page.
+
+_javaimagesheader_ {_javahome__javahelp__javapref_}
+_javaimagesheader_ [v=1] {}
+
+_javaabout_ {
+	about\_on = new Image(_widthcabtx_, _heightcabtx_);
+	about\_on.src = "_httpiconcabton_";
+	about\_off = new Image(_widthcabtx_, _heightcabtx_);
+	about\_off.src = "_httpiconcabtof_";
+}
+
+_javahome_ {
+	home\_on = new Image(_widthchomex_, _heightchomex_);          
+	home\_on.src = "_httpiconchomeon_";		        
+	home\_off = new Image(_widthchomex_, _heightchomex_);          
+	home\_off.src = "_httpiconchomeof_";             
+}
+
+_javahelp_ {
+	help\_on = new Image(_widthchelpx_, _heightchelpx_);
+	help\_on.src = "_httpiconchelpon_";
+	help\_off = new Image(_widthchelpx_, _heightchelpx_);
+	help\_off.src = "_httpiconchelpof_";
+}
+
+_javapref_ {
+	pref\_on = new Image(_widthcprefx_, _heightcprefx_);          
+	pref\_on.src = "_httpiconcprefon_";
+	pref\_off = new Image(_widthcprefx_, _heightcprefx_);
+	pref\_off.src = "_httpiconcprefof_"; 
+}
+
+_javasearch_ {
+	search\_on = new Image(_widthtsrchx_, _heighttsrchx_);          
+	search\_on.src = "_httpicontsrchon_";
+	search\_off = new Image(_widthtsrchx_, _heighttsrchx_);          
+	search\_off.src = "_httpicontsrchof_";
+}
+
+_javaTitle_ {
+	titles\_on = new Image(_widthttitlx_, _heightttitlx_);
+	titles\_on.src = "_httpiconttitlon_";
+	titles\_off = new Image(_widthttitlx_, _heightttitlx_);
+	titles\_off.src = "_httpiconttitlof_";
+}
+
+_javaList_ {
+	list\_on = new Image(_widthtlistx_, _heighttlistx_);
+	list\_on.src = "_httpicontliston_";
+	list\_off = new Image(_widthtlistx_, _heighttlistx_);
+	list\_off.src = "_httpicontlistof_";
+}
+
+_javaCreator_ {
+	authors\_on = new Image(_widthtauthx_, _heighttauthx_);
+	authors\_on.src = "_httpicontauthon_";
+	authors\_off = new Image(_widthtauthx_, _heighttauthx_);
+	authors\_off.src = "_httpicontauthof_";
+}
+
+_javaSeries_ {
+	series\_on = new Image(_widthtserx_, _heighttserx_);          
+	series\_on.src = "_httpicontseron_";
+	series\_off = new Image(_widthtserx_, _heighttserx_);          
+	series\_off.src = "_httpicontserof_";
+}
+
+_javaDate_ {
+	dates\_on = new Image(_widthtdatex_, _heighttdatex_);          
+	dates\_on.src = "_httpicontdateon_";
+	dates\_off = new Image(_widthtdatex_, _heighttdatex_);          
+	dates\_off.src = "_httpicontdateof_";	 		
+}
+
+_javaSubject_ {
+	subjects\_on = new Image(_widthtsubjx_, _heighttsubjx_);          
+	subjects\_on.src = "_httpicontsubjon_";
+	subjects\_off = new Image(_widthtsubjx_, _heighttsubjx_);          
+	subjects\_off.src = "_httpicontsubjof_";	 		
+}
+
+_javaTo_ {
+	to\_on = new Image(_widthttox_, _heightttox_);          
+	to\_on.src = "_httpiconttoon_";
+	to\_off = new Image(_widthttox_, _heightttox_);          
+	to\_off.src = "_httpiconttoof_";	 		
+}
+
+_javaFrom_ {
+	from\_on = new Image(_widthtfromx_, _heighttfromx_);          
+	from\_on.src = "_httpicontfromon_";
+	from\_off = new Image(_widthtfromx_, _heighttfromx_);          
+	from\_off.src = "_httpicontfromof_";	 		
+}
+
+_javaHowto_ {
+	how\_on = new Image(_widththowx_, _heightthowx_);          
+	how\_on.src = "_httpiconthowon_";
+	how\_off = new Image(_widththowx_, _heightthowx_);          
+	how\_off.src = "_httpiconthowof_";	 		
+}
+
+_javaOrganization_ {
+	org\_on = new Image(_widthtorgx_, _heighttorgx_);          
+	org\_on.src = "_httpicontorgon_";
+	org\_off = new Image(_widthtorgx_, _heighttorgx_);          
+	org\_off.src = "_httpicontorgof_";	 		
+}
+
+_javaTopic_ {
+	topic\_on = new Image(_widthttopicx_, _heightttopicx_);          
+	topic\_on.src = "_httpiconttopicon_";
+	topic\_off = new Image(_widthttopicx_, _heightttopicx_);          
+	topic\_off.src = "_httpiconttopicof_";	 		
+}
+
+_javaBrowse_ {
+	browse\_on = new Image(_widthtbrwsex_, _heighttbrwsex_);          
+	browse\_on.src = "_httpicontbrwseon_";
+	browse\_off = new Image(_widthtbrwsex_, _heighttbrwsex_);          
+	browse\_off.src = "_httpicontbrwseof_";	 		
+}
+
+_javaPeople_ {
+        People\_on = new Image(_widthtpeopx_, _heighttpeopx_);
+        People\_on.src = "_httpicontpeopon_";
+        People\_off = new Image(_widthtpeopx_, _heighttpeopx_);
+        People\_off.src = "_httpicontpeopof_";
+}
+
+_javaLanguage_ {
+        Language\_on = new Image(_widthtlangx_, _heighttlangx_);
+        Language\_on.src = "_httpicontlangon_";
+        Language\_off = new Image(_widthtlangx_, _heighttlangx_);
+        Language\_off.src = "_httpicontlangof_";
+}
+
+_javaAcronym_ {
+        Acronym\_on = new Image(_widthtacrox_, _heighttacrox_);
+        Acronym\_on.src = "_httpicontacroon_";
+        Acronym\_off = new Image(_widthtacrox_, _heighttacrox_);
+        Acronym\_off.src = "_httpicontacroof_";
+}
+
+
+#######################################################################
+# general web macros 
+#######################################################################
+
+_mailaddr_ {greenstone@cs.waikato.ac.nz}
+
+_gsdltop_ {_top}
+
+#######################################################################
+# http macros 
+#
+# These contain the url without any quotes
+#######################################################################
+
+_httpcollimg_ {_httpcollection_/index/assoc}
+_httpdocimg_ {_httpcollimg_/_thisOID_}
+
+_httpcollection_ {_httpprefix_/collect/_cgiargc_}
+
+_httppagex_ {_gwcgi_?e=_compressedoptions_&a=p&p=_1_}
+_httppagestatus_ {_gwcgi_?e=_compressedoptions_&a=status}
+_httppageabout_ {_httppagex_(about)}
+#_httppagehome_ {_httppagex_(home)}
+_httppagehome_ {_gwcgi_?a=p&p=home}
+_httppagehelp_ {_httppagex_(help)}
+_httppagepref_ {_httppagex_(preferences)}
+_httpclearhistory_ {_gwcgi_?e=_compressedoptions_&a=dh}
+
+_httpgreenstone_ {_httppagex_(gsdl)}
+_httpdownload_ {http://www.nzdl.org/download}
+_httppublications_ {_httpdownload_/greenstone/publications}
+
+_httpcurrentdocument_ {_gwcgi_?e=_compressedoptions_&cl=_cgiargcl_&d=_cgiargd_}
+_httpquery_ {_gwcgi_?e=_compressedoptions_&a=q}
+
+# _httpdoc_ is the same as _httpdocument_ - _httpdocument_
+# may occasionally be altered by the server however
+_httpdocument_ {_gwcgi_?e=_compressedoptions_&a=d}
+_httpdoc_  {_gwcgi_?e=_compressedoptions_&a=d}
+
+_httpextlink_ {_gwcgi_?e=_compressedoptions_&a=extlink}
+_httpbuild_ {_gwcgi_?e=_compressedoptions_&a=bc}
+
+_httpiconchalk_ {_httpimg_/chalk.gif}
+_widthchalk_ {2000}
+_heightchalk_ {10}
+
+_httpicondivb_ {_httpimg_/divb.gif}
+_widthdivb_ {_pagewidth_}
+_heightdivb_ {17}
+
+_httpicongsdl_ {_httpimg_/gsdl.gif}
+_widthgsdl_ {140}
+_heightgsdl_ {77}
+
+_httpiconitext_ {_httpimg_/itext.gif}
+_widthitext_ {16}
+_heightitext_ {21}
+
+_httpiconibtext_ {_httpimg_/ibtext.gif}
+_widthibtext_ {16}
+_heightibtext_ {21}
+
+_httpiconimpegvideo_ {_httpimg_/impegvideo.gif}
+_widthimpegvideo_ {29}
+_heightimpegvideo_ {32}
+
+_httpiconiqtvideo_ {_httpimg_/iqtvideo.gif}
+_widthiqtvideo_ {29}
+_heightiqtvideo_ {32}
+
+_httpiconirmvideo_ {_httpimg_/irmvideo.gif}
+_widthirmvideo_ {29}
+_heightirmvideo_ {32}
+
+_httpiconless_ {_httpimg_/less.gif}
+_widthless_ {30}
+_heightless_ {16}
+
+_httpiconmore_ {_httpimg_/more.gif}
+_widthmore_ {30}
+_heightmore_ {16}
+
+_httpiconspacer_ {_httpimg_/spacer.gif}
+_widthspacer_ {42}
+_heightspacer_ {4}
+
+_httpicontabspace_ {_httpimg_/tabspace.gif}
+_widthtabspace_ {23}
+_heighttabspace_ {1}
+
+_httpicontspace_ {_httpimg_/tspace.gif}
+_heighttspace_ {17}
+
+_httpiconwarning_ {_httpimg_/warning.gif}
+_widthwarning_ {30}
+_heightwarning_ {29}
+
+_httpiconhhome_ {_httpimg_/h\_home.gif}
+_widthhhome_ {200}
+_heighthhome_ {57}
+
+_httpiconarrrght_ {_httpimg_/arrrght.gif}
+_widtharrrght_ {23}
+_heightarrrght_ {15}
+
+_httpiconopenbook_ {_httpimg_/openbook.gif}
+_widthopenbook_ {28}
+_heightopenbook_ {23}
+
+_httpiconaopenbk_ {_httpimg_/aopenbk.gif}
+_widthaopenbk_ {28}
+_heightaopenbk_ {23}
+
+_httpiconopenfldr_ {_httpimg_/openfldr.gif}
+_widthopenfldr_ {23}
+_heightopenfldr_ {15}
+
+_httpiconaopenfdr_ {_httpimg_/aopenfdr.gif}
+_widthaopenfdr_ {23}
+_heightaopenfdr_ {15}
+
+_httpiconbook_ {_httpimg_/book.gif}
+_widthbook_ {18}
+_heightbook_ {11}
+
+_httpiconabook_ {_httpimg_/abook.gif}
+_widthabook_ {18}
+_heightabook_ {11}
+
+_httpiconbshelf_ {_httpimg_/bshelf.gif}
+_widthbshelf_ {20}
+_heightbshelf_ {16}
+
+_httpiconabshelf_ {_httpimg_/abshelf.gif}
+_widthabshelf_ {20}
+_heightabshelf_ {16}
+
+_httpiconsmtext_ {_httpimg_/smtext.gif}
+_widthsmtext_ {23}
+_heightsmtext_ {15}
+
+_httpiconasmtext_ {_httpimg_/asmtext.gif}
+_widthasmtext_ {23}
+_heightasmtext_ {15}
+
+_httpiconclsdfldr_ {_httpimg_/clsdfldr.gif}
+_widthclsdfldr_ {23}
+_heightclsdfldr_ {15}
+
+_httpiconaclsdfdr_ {_httpimg_/aclsdfdr.gif}
+_widthaclsdfdr_ {23}
+_heightaclsdfdr_ {15}
+
+
+#######################################################################
+# Icons 
+#
+# Must not include links (so they can be used as links). If you want to
+# include links use _image
+#######################################################################
+
+_iconnext_{<img src="_httpiconmore_" align=absbottom 
+width=_widthmore_ height=_heightmore_ border=0 alt="_texticonnext_">}
+_iconnext_[v=1] {_texticonnext_}
+
+_iconprev_{<img src="_httpiconless_" align=absbottom 
+width=_widthless_ height=_heightless_ border=0 alt="_texticonprev_">}
+_iconprev_[v=1] {_texticonprev_}
+
+_icontabsearchgreen_ {<img 
+src="_httpicontsrchgr_" height=_heighttsrchx_ width=_widthtsrchx_ border=0>}
+_icontabsearchgreen_[v=1] {_texticontabsearchgreen_}
+
+_icontabListgreen_ {<img
+src="_httpicontlistgr_" height=_heighttlistx_ width=_widthtlistx_ border=0>}
+_icontablistgreen_ [v=1] {_texticontablistgreen_}
+
+_icontabTitlegreen_ {<img 
+src="_httpiconttitlgr_" height=_heightttitlx_ width=_widthttitlx_ border=0>}
+_icontabTitlegreen_[v=1] {_texticontabtitlegreen_}
+
+_icontabCreatorgreen_ {<img 
+src="_httpicontauthgr_" height=_heighttauthx_ width=_widthtauthx_ border=0>}
+_icontabCreatorgreen_[v=1] {_texticontabauthorgreen_}
+
+_icontabSeriesgreen_ {<img 
+src="_httpicontsergr_" height=_heighttserx_ width=_widthtserx_ border=0>}
+_icontabSeriesgreen_[v=1] {_texticontabseriesgreen_}
+
+_icontabDategreen_ {<img 
+src="_httpicontdategr_" height=_heighttdatex_ width=_widthtdatex_ border=0>}
+_icontabDategreen_[v=1] {_texticontabdategreen_}
+
+_icontabSubjectgreen_ {<img 
+src="_httpicontsubjgr_" height=_heighttsubjx_ width=_widthtsubjx_ border=0>}
+_icontabSubjectgreen_[v=1] {_texticontabsubjectgreen_}
+
+_icontabTogreen_ {<img 
+src="_httpiconttogr_" height=_heightttox_ width=_widthttox_ border=0>}
+_icontabTogreen_[v=1] {_texticontabtogreen_}
+
+_icontabFromgreen_ {<img 
+src="_httpicontfromgr_" height=_heighttfromx_ width=_widthtfromx_ border=0>}
+_icontabFromgreen_[v=1] {_texticontabfromgreen_}
+
+_icontabHowtogreen_ {<img 
+src="_httpiconthowgr_" height=_heightthowx_ width=_widththowx_ border=0>}
+_icontabHowtogreen_[v=1] {_texticontabhowgreen_}
+
+_icontabTopicgreen_ {<img 
+src="_httpiconttopicgr_" height=_heightttopicx_ width=_widthttopicx_ border=0>}
+_icontabTopicgreen_[v=1] {_texticontabtopicgreen_}
+
+_icontabBrowsegreen_ {<img 
+src="_httpicontbrwsegr_" height=_heighttbrwsex_ width=_widthtbrwsex_ border=0>}
+_icontabBrowsegreen_[v=1] {_texticontabbrwsegreen_}
+
+_icontabOrganizationgreen_ {<img 
+src="_httpicontorggr_" height=_heighttorgx_ width=_widthtorgx_ border=0>}
+_icontabOrganizationgreen_[v=1] {_texticontaborggreen_}
+
+_icontabPeoplegreen_ {<img
+src="_httpicontpeopgr_" height=_heighttpeopx_ width=_widthtpeopx_ border=0>}
+_icontabPeoplegreen_[v=1] {_texticontabPeoplegreen_}
+
+_icontabLanguagegreen_ {<img
+src="_httpicontlanggr_" height=_heighttlangx_ width=_widthtlangx_ border=0>}
+_icontabLanguagegreen_[v=1] {_texticontabLanguagegreen_}
+
+_icontabAcronymgreen_ {<img
+src="_httpicontacrogr_" height=_heighttacrox_ width=_widthtacrox_ border=0>}
+_icontabAcronymgreen_[v=1] {_texticontabAcronymgreen_}
+
+_iconblankbar_ {<center><img src="_httpicondivb_" width=_widthdivb_ height=6></center>}
+_iconblankbar_[v=1] {<br><hr><br>}
+
+_icontext_ {<img border=0 align=absmiddle src="_httpiconitext_" width=_widthitext_ height=_heightitext_ alt="_texticontext_">}
+_icontext_[v=1] {_texticontext_}
+
+_iconblanktext_ {<img border=0 align=absmiddle src="_httpiconibtext_" width=_widthibtext_ height=_heightibtext_>}
+_iconblanktext_[v=1] {}
+
+_iconclosedbook_ {<img src="_httpiconbook_" width=_widthbook_ height=_heightbook_ border=0 alt="_texticonclosedbook_">}
+_iconclosedbook_ [v=1] {<small><b>_texticonclosedbook_: </b></small>}
+_iconclosedbook_ [v=1,l=zh]{<small><_font_><b>_texticonclosedbook_: </b></font></small>}
+
+
+#######################################################################
+# Image links 
+#
+# These might include a link (not like an _icon_
+#######################################################################
+
+
+_imageabout_ {<a href="_httppageabout_" 
+    onMouseover = "img\_on('about')" 
+    onMouseout = "img\_off('about')"><img name="about"
+        src="_httpiconcabtof_" width=_widthcabtx_ height=_heightcabtx_
+        border=0 alt="_textimageabout_"></a>}
+
+_imageabout_[v=1] {
+<a href="_httppageabout_">_textimageabout_</a>
+}
+
+_imagehome_ {<a href="_httppagehome_" 
+    onMouseover = "img\_on('home')" 
+    onMouseout = "img\_off('home')"><img name="home"
+        src="_httpiconchomeof_" width="_widthchomex_" height="_heightchomex_"
+        border="0" alt="_textimagehome_"></a>}
+
+_imagehome_[v=1] {
+<a href="_httppagehome_">_textimagehome_</a>
+}
+
+
+_imagehelp_ {<a href="_httppagehelp_"
+    onMouseover = "img\_on('help')" 
+    onMouseout = "img\_off('help')"><img name="help" 
+        src="_httpiconchelpof_" width="_widthchelpx_" height="_heightchelpx_" 
+        border="0" alt="_textimagehelp_"></a>}
+
+_imagehelp_[v=1] {
+<a href="_httppagehelp_">_textimagehelp_</a>
+}
+
+
+_imagepref_ {<a href="_httppagepref_"
+    onMouseover = "img\_on('pref')" 
+    onMouseout = "img\_off('pref')"><img name="pref" 
+        src="_httpiconcprefof_" width="_widthcprefx_" height="_heightcprefx_" border="0" alt="_textimagepref_"></a>}
+
+_imagepref_[v=1] {
+<a href="_httppagepref_">_textimagepref_</a>
+}
+
+_imagegreenstone_ {<img src="_httpicongsdl_" width="_widthgsdl_" height="_heightgsdl_" border="0" alt="_textimagegreenstone_" hspace=0>}
+
+_imagegreenstone_[v=1] {_textimagegreenstone_}
Index: /main/tags/2.25/gsdl/macros/build.dm
===================================================================
--- /main/tags/2.25/gsdl/macros/build.dm	(revision 21064)
+++ /main/tags/2.25/gsdl/macros/build.dm	(revision 21064)
@@ -0,0 +1,1364 @@
+package build
+
+_header_ {
+<html>
+<head>
+<title>_1_</title>
+</head>
+<body bgcolor="#ffffff" text="#000000" link="#006666"
+      alink="#cc9900" vlink="#666633">
+<table width=100%>
+  <tr>
+    <td><img src="_httpimg_/spacer.gif" width=2 height=77></td>
+    <td>_iconblankbar_
+        <center><h2>_1_</h2></center>
+        _iconblankbar_</td>
+  </tr>
+</table>
+}
+
+
+_footer_ {
+_iconblankbar_
+
+</body>
+</html>
+}
+
+
+_frameheader_ {
+<html>
+<head>
+<title>_1_</title>
+</head>
+}
+
+_framefooter_ {
+</html>
+}
+
+_wizardfooter_ {
+
+</body>
+</html>
+}
+
+_httpiconstop_ {_httpimg_/stop.gif}
+
+_iconwizardnext_{<img src="_httpiconmore_" align=absbottom 
+width=_widthmore_ height=_heightmore_ border=0 alt="_texticonwizardnext_">}
+_iconwizardnext_[v=1] {_texticonwizardnext_}
+
+_iconwizardcurr_{<img src="_httpiconmore_" align=absbottom 
+width=_widthmore_ height=_heightmore_ border=0 alt="_texticonwizardcurr_">}
+
+_iconwizardprev_{<img src="_httpiconless_" align=absbottom 
+width=_widthless_ height=_heightless_ border=0 alt="_texticonwizardprev_">}
+_iconwizardprev_[v=1] {_texticonwizardprev_}
+
+_iconwizardreset_{<img src="_httpiconstop_" align=absbottom 
+width=_widthstop_ height=_heightstop_ border=0 alt="_texticonwizardreset_">}
+_iconwizardreset_[v=1] {_texticonwizardreset_}
+
+_texticonwizardnext_ {to next page}
+_texticonwizardcurr_ {this page}
+_texticonwizardprev_ {to previous page}
+_texticonwizardreset_ {reset page}
+
+
+# new collection
+_bcargfullname_     {}
+_bcargcontactemail_ {}
+_bcargaboutdesc_    {}
+_bcargsrcformat_    {TEXT}
+_bcarginputdir_     {}
+_bcargcopydir_      {yes}
+_bcargingsdlarea_   {no}
+_bcargacronyms_     {off}
+_bcargrefine_       {}
+
+# delete collection
+_bcargfullnameindex_ {0}
+_bcargdeletearea_    {archives}
+_bcargdirname_       {}
+
+# build collection
+_bcargcopydata_      {false}
+_bcargdoimport_      {true}
+_bcargdobuild_       {true}
+
+
+_commonjavascript_ {
+   function simulate_get_action(args)
+     \{
+        var form = document.form;
+	args += "&bc1fullname=" + escape(form.bc1fullname.value);
+	args += "&bc1contactemail=" + escape(form.bc1contactemail.value);
+	args += "&bc1aboutdesc=" + escape(form.bc1aboutdesc.value);
+	args += "&bc1srcformat=" + escape(form.bc1srcformat.value);
+	args += "&bc1inputdir=" + escape(form.bc1inputdir.value);
+	args += "&bc1copydir=" + escape(form.bc1copydir.value);
+	args += "&bc1ingsdlarea=" + escape(form.bc1ingsdlarea.value);
+	args += "&bc1acronyms=" + escape(form.bc1acronyms.value);
+	args += "&bc1refine=" + escape(form.bc1refine.value);
+	args += "&wizard=" + escape(form.wizard.value);
+
+	document.location = args;
+     \}
+
+   function prev_page(new_wizard) \{
+        var form = document.form;
+        form.wizard.value = new_wizard;
+
+        simulate_get_action("_httpbuild_&bca=newcol");
+   \}
+}
+
+_wizardlink_ {
+<script language="javascript">
+   <!-- Hide code from non-js browsers
+    var bgcol = "";
+    var fgcol = "";
+    var text  = "";
+
+    var wizard = "_wizard_";
+    if (wizard.match(/_1_/)) \{
+
+       if (wizard.match(/_1_$/)) \{          
+           // change here to give current page different background
+	   //  to previous pages
+           bgcol = "bgcolor=\\"#cece00\\""; 
+           fgcol = "color=\\"#006666\\"";
+           text = "_2_";
+       \}
+       else \{
+           bgcol = "bgcolor=\\"#ce9c00\\"";
+           fgcol = "color=\\"#006666\\"";
+           var page   = "_1_";
+           var break_pt = wizard.indexOf(page) + page.length;
+	   var wizard_direct = wizard.substring(0,break_pt);
+           text = "<a href=javascript:prev_page(\\""+wizard_direct+"\\")>_2_</a>";
+       \}
+
+
+    \}
+    else \{
+       fgcol = "color=\\"#006666\\"";
+       text = "_2_";
+    \}
+
+
+    document.writeln("<td "+bgcol+">");
+    document.writeln("  <font "+fgcol+">");
+    document.writeln("     "+text);
+    document.writeln("  </font>");
+    document.writeln("</td>");
+
+   // end hiding -->
+</script>
+}
+
+_wizardbar_ {
+<center>
+<table border=0 cellspacing=1 cellpadding=3>
+<tr bgcolor="#90c098">
+  <td bgcolor="#ffffff">
+    <font color="#000000">
+	Wizard page:
+    </font>
+  </td>
+  <td bgcolor="#ce9c00">
+    <font color="#006666">
+        <a href="_httpbuild_&bca=newcol">Reset</a>
+    </font>
+  </td>
+  _wizardlink_(textinfo,Textual information)
+  _wizardlink_(:source,Source data)
+  _wizardlink_(:archiveopts,Archive options)
+  _wizardlink_(:definished,Save)
+</tr>
+</table>
+</font>
+</center>
+}
+
+#---------------------------------------------------------------------------#
+# Create a new collection
+#---------------------------------------------------------------------------#
+
+_headmesstextinfo_ { New collection wizard: textual information }
+
+
+_contenttextinfo_ {
+
+
+<script language="javascript">
+
+   <!-- Hide code from non-js browsers
+   _commonjavascript_
+
+   function next_page() \{
+        _fullnamelist_
+        var form = document.form;
+
+	// check args
+        if (form.bc1fullname.value.match(/^\\s*$/))
+          \{
+             alert("Collection name needs to be specified");
+             form.bc1fullname.focus();
+             return;
+          \}
+        else if (form.bc1contactemail.value.match(/^\\s*$/))
+          \{
+	     var mess = "Email address of the person responsible";
+	     mess += " for the collection needs";
+             alert(mess);
+             form.bc1contactemail.focus();
+             return;
+          \}
+        else if (!form.bc1contactemail.value.match(/^([^@]+)@(.+)$/))
+          \{
+             alert("Please specify email address in the form: usename@domain");
+             form.bc1contactemail.focus();
+             return;
+          \}
+        else if (form.bc1aboutdesc.value.match(/^\\s*$/))
+          \{
+             alert("Description for about this collection needs to be specified");
+             form.bc1aboutdesc.focus();
+             return;
+          \}
+	var i;
+	for (i=0; i<fullnamelist.length; i++)
+	  \{
+	     var j;
+	     for (j=0; j<fullnamelist[i].length; j++)
+	      \{
+		var fn_re = "/"+fullnamelist[i][j]+"/i";
+		if (form.bc1fullname.value == fullnamelist[i][j])
+		  \{
+		    alert("Collection title already exists");
+		    form.bc1fullname.focus();
+		    return;
+		  \}
+	      \}
+	  \}
+
+	// if control reached here then args check out
+	form.wizard.value += ":source";
+
+	simulate_get_action("_httpbuild_&bca=newcol");
+   \}
+   // end hiding -->
+
+
+</script>
+
+<center><table><tr><td>
+<form name="form" method="post" action="_gwcgi_" >
+<input type=hidden name="gsdlhome" value="_gsdlhome_">
+<input type=hidden name="a" value="bc">
+<input type=hidden name="bc" value="newcol">
+_hiddenargs_
+
+<input type=hidden name="bc1srcformat" value="_bcargsrcformat_">
+<input type=hidden name="bc1inputdir" value="_bcarginputdir_">
+<input type=hidden name="bc1copydir" value="_bcargcopydir_">
+<input type=hidden name="bc1ingsdlarea" value="_bcargingsdlarea_">
+<input type=hidden name="bc1acronyms" value="_bcargacronyms_">
+<input type=hidden name="bc1refine" value="_bcargrefine_">
+
+<center><table border=0 width=_pagewidth_><tr><td>
+
+<p>
+To create a new collection you are required to enter some preliminary
+information about the source data.  This process is structured as a series
+of Web pages, overseen by the new-collection &quot;wizard.&quot The wizard
+bar at the bottom of the page shows you the sequence of pages to be
+completed.  You can return to a previous page by clicking on the
+corresponding item in the wizard bar.
+
+<p>_iconblankbar_<br><br>
+<h4>Title for collection:</h4>
+<input type="text" name="bc1fullname" value="_bcargfullname_") size=72>
+<br>
+<font color="#909090">
+The collection title is a text phrase that encapsulates the content of the
+collection and is used throughout the digital library.  Example titles
+include &quot;Computer Science Technical Reports&quot; and &quot;Humanity
+Development Library.&quot;
+</font>
+
+<h4>Contact email address:</h4>
+<input type="text" name="bc1contactemail" value="_bcargcontactemail_" size=72>
+<br>
+<font color="#909090">
+This email address specifies the first point of contact for the collection.
+If the collection software detects a problem, then a diagnostic report is
+sent to this address.  Enter an email address in its full form:
+<tt>name@domain</tt>.
+</font>
+
+<h4>About this collection:</h4>
+<textarea name="bc1aboutdesc"  cols=72 rows=6 
+     wrap=physical>_bcargaboutdesc_</textarea>
+<br>
+<font color="#909090">
+A statement describing the principles governing what is included in the collection.
+</font>
+
+</td></tr>
+<tr><td align=right>
+<br><br><a href="javascript:next_page();">Next page_iconwizardnext_</a>
+</td></tr>
+</table></center>
+</form>
+</td></tr></table></center>
+
+_wizardbar_
+}
+
+
+#---------------------------------------------------------------------------#
+
+_headmesssource_ { New collection wizard: source data }
+
+_contentsource_ {
+
+
+<script language="javascript">
+
+   <!-- Hide code from non-js browsers
+   _commonjavascript_
+
+   function next_page() \{
+        _fullnamelist_
+        var form = document.form;
+        if (form.bc1inputdir.value.match(/^\\s*$/))
+          \{
+             alert("Directory for source files needs to be specified");
+             form.bc1inputdir.focus();
+             return;
+          \}
+
+  	// work out the next newcol "wizard" page
+        var prefix_re 
+	   = new RegExp(form.gsdlhome.value + "/collect/([^/]+)/(import|archive)");
+
+        if (form.bc1inputdir.value.match(prefix_re))
+ 	  \{
+	     form.bc1ingsdlarea.value = "yes";
+             if (form.bc1inputdir.value != "_bcarginputdir_")
+	       \{
+                  // input dir has been changed
+                  form.bc1copydir.value = "no";
+               \}
+          \}
+        else
+	  \{
+	     form.bc1ingsdlarea.value = "no";
+	  \}
+	form.wizard.value += ":archiveopts";
+
+        simulate_get_action("_httpbuild_&bca=newcol");
+   \}
+
+
+   function srcformat_changed() \{
+        var form = document.form;
+	var sf_index = form.bc1srcformatmenu.selectedIndex;
+	var sf_choice = form.bc1srcformatmenu.options[sf_index].value;
+	form.bc1srcformat.value = sf_choice;
+   \}
+
+   // end hiding -->
+
+</script>
+
+<center><table><tr><td>
+<form name="form" method="post" action="_gwcgi_">
+<input type=hidden name="gsdlhome" value="_gsdlhome_">
+<input type=hidden name="a" value="bc">
+<input type=hidden name="bc" value="newcol">
+_hiddenargs_
+
+<input type=hidden name="bc1fullname" value="_bcargfullname_")>
+<input type=hidden name="bc1contactemail" value="_bcargcontactemail_")>
+<input type=hidden name="bc1aboutdesc" value="_bcargaboutdesc_")>
+<input type=hidden name="bc1copydir" value="_bcargcopydir_">
+<input type=hidden name="bc1ingsdlarea" value="_bcargingsdlarea_">
+<input type=hidden name="bc1acronyms" value="_bcargacronyms_">
+<input type=hidden name="bc1refine" value="_bcargrefine_">
+
+<center><table border=0 width=_pagewidth_><tr><td>
+
+<h4>Type of data:</h4>
+<input type="hidden" name="bc1srcformat" value="_bcargsrcformat_">
+<select name="bc1srcformatmenu" onChange=srcformat_changed()>
+<option value="TEXT" _If_("_bcargsrcformat_" eq "TEXT",selected)>Plain TEXT&nbsp;&nbsp;(.txt)
+<option value="HTML" _If_("_bcargsrcformat_" eq "HTML",selected)>HTML&nbsp;&nbsp;(.htm, html)
+<option value="EMAIL" _If_("_bcargsrcformat_" eq "EMAIL",selected)>E-mail&nbsp;&nbsp;(.email)
+</select>
+<br>
+<font color="#909090">
+This pull-down menu specifies the type of file format the source data is
+in: TEXT for plain text documents, HTML for Web pages and so for.  Also
+listed in the pull-down menu are the permissible file names extensions (for
+instance <tt>.htm</tt> and <tt>.html</tt>) for the source files (Web pages
+in this case).
+</font>
+
+<h4>Input directory:</h4>
+<input type=text name="bc1inputdir" value="_bcarginputdir_" size=72>
+<br>
+<font color="#909090">
+The input directory specifies where on the local disk the source data is
+located.
+</font>
+
+</td></tr>
+<tr><td align=right><br><br>
+<a href="javascript:next_page();">Next page_iconwizardnext_</a>
+</td></tr></table></center>
+</form>
+</td></tr></table></center>
+
+_wizardbar_
+}
+
+
+
+#---------------------------------------------------------------------------#
+
+_headmessarchiveopts_ { New collection wizard: archive options }
+
+_contentarchiveopts_ {
+
+
+<script language="javascript">
+
+   <!-- Hide code from non-js browsers
+   _commonjavascript_
+
+   function next_page() \{
+        _fullnamelist_
+        var form = document.form;
+
+	form.wizard.value += ":definished";
+
+        simulate_get_action("_httpbuild_&bca=newcol");
+   \}
+
+
+   function copydir_changed() \{
+        var form = document.form;
+	var cd_index = form.bc1copydirmenu.selectedIndex;
+	var cd_choice = form.bc1copydirmenu.options[cd_index].value;
+	form.bc1copydir.value = cd_choice;
+   \}
+   // end hiding -->
+
+
+</script>
+
+<center><table><tr><td>
+<form name="form" method="post" action="_gwcgi_">
+<input type=hidden name="gsdlhome" value="_gsdlhome_">
+<input type=hidden name="a" value="bc">
+<input type=hidden name="bc" value="newcol">
+_hiddenargs_
+
+<input type=hidden name="bc1fullname" value="_bcargfullname_")>
+<input type=hidden name="bc1contactemail" value="_bcargcontactemail_")>
+<input type=hidden name="bc1aboutdesc" value="_bcargaboutdesc_")>
+<input type=hidden name="bc1srcformat" value="_bcargsrcformat_">
+<input type=hidden name="bc1inputdir" value="_bcarginputdir_">
+<input type=hidden name="bc1ingsdlarea" value="_bcargingsdlarea_">
+<input type=hidden name="bc1acronyms" value="_bcargacronyms_">
+<input type=hidden name="bc1refine" value="_bcargrefine_">
+
+<center><table border=0 width=_pagewidth_><tr><td>
+
+<h4>Copy data:</h4>
+<input type="hidden" name="bc1copydir" value="_bcargcopydir_">
+<select name="bc1copydirmenu" onChange=copydir_changed()>
+ <option value="yes" _If_("_bcargcopydir_" eq "yes",selected)>Yes, make a local copy for the digital library
+ <option value="no" _If_("_bcargcopydir_" eq "no",selected)>No, form a link in digital library to source data
+</select>
+<br>
+<font color="#909090">
+_If_("_bcargingsdlarea_" eq "yes",
+The input directory <tt>_bcarginputdir_</tt> is internal to the 
+Greenstone collection file area.  In this situation the default
+behaviour is to build the collection directly from this
+source data.  Use the pull-down menu to alter this behaviour.
+,
+The input directory <tt>_bcarginputdir_</tt> is external to the 
+Greenstone collection file area.  Use this pull-down menu to
+control whether or not a copy of the data is made for collection
+building purposes.
+)  
+Note, once a collection has been built it is not necessary for the source
+data to remain in the Greenstone collection area -- the collection can be
+safely accessed, browsed and searched without this.  If you wish, however,
+to make changes to the collection and then rebuild, the source data must
+still be available.
+</font>
+
+</td></tr>
+<tr><td align=right><br><br>
+<a href="javascript:next_page();">Next page_iconwizardnext_</a>
+</td></tr>
+</table></center>
+</form>
+</td></tr></table></center>
+
+_wizardbar_
+}
+
+#---------------------------------------------------------------------------#
+
+_headmessdefinished_ { New collection wizard: data entry finished }
+
+_contentdefinished_ {
+
+
+<script language="javascript">
+
+   <!-- Hide code from non-js browsers
+   _commonjavascript_
+
+   function save() \{
+        _fullnamelist_
+        var form = document.form;
+
+	var bc1refine = "";
+	if (form.bc1acronyms == "on") \{
+	    bc1refine += "AcronymPlug ";
+	\}
+
+	form.wizard.value += ":definished";
+
+	var cgi_prefix = "webpage_mkcol.pl";
+	cgi_prefix += "?httpbuild=" + escape("_httpbuild_");
+	cgi_prefix += "&bc1refine=" + escape(bc1refine);
+
+        simulate_get_action(cgi_prefix);
+   \}
+   // end hiding -->
+
+
+</script>
+
+<center><table><tr><td>
+<form name="form" method="post" action="_gwcgi_">
+<input type=hidden name="gsdlhome" value="_gsdlhome_">
+<input type=hidden name="a" value="bc">
+<input type=hidden name="bc" value="newcol">
+_hiddenargs_
+
+<input type=hidden name="bc1fullname" value="_bcargfullname_")>
+<input type=hidden name="bc1contactemail" value="_bcargcontactemail_")>
+<input type=hidden name="bc1aboutdesc" value="_bcargaboutdesc_")>
+<input type=hidden name="bc1srcformat" value="_bcargsrcformat_">
+<input type=hidden name="bc1inputdir" value="_bcarginputdir_">
+<input type=hidden name="bc1copydir" value="_bcargcopydir_">
+<input type=hidden name="bc1ingsdlarea" value="_bcargingsdlarea_">
+<input type=hidden name="bc1acronyms" value="_bcargacronyms_">
+<input type=hidden name="bc1refine" value="_bcargrefine_">
+
+<center><table border=0 width=_pagewidth_><tr><td>
+<p>
+This concludes the data entry required to create a new collection.
+<p>
+Select "finish" to save your collection info and create the collection or
+select from the wizard bar to go back and change any of your previous
+selections.
+</td></tr>
+
+<tr><td align=right><br><br>
+<a href="javascript:save();">finish_iconwizardnext_</a>
+</td></tr>
+</table></center>
+</form>
+</td></tr></table></center>
+
+_wizardbar_
+}
+
+#---------------------------------------------------------------------------#
+# Edit a collection
+#---------------------------------------------------------------------------#
+
+_headmesseditcol_ { Edit a collection }
+
+
+_contenteditcol_ {
+
+
+<script language="javascript">
+
+   <!-- Hide code from non-js browsers
+   function simulate_get_action(args)
+     \{
+        var form = document.form;
+
+//	args += "&bc1fullnameindex=" + escape(form.bc1fullnameindex.value);
+	args += "&bc1dirname=" + escape(form.bc1dirname.value);
+
+	document.location = args;
+     \}
+
+   function save() \{
+        _dirnamelist_
+        var form = document.form;
+
+	var fn_index = form.bc1fullnameindex.value;
+	var fullname = form.bc1fullnamemenu.options[fn_index].value;
+	form.bc1dirname.value = dirnamelist[fn_index];
+
+	var do_save = true;
+	if (form.bc1cfgfile.value.match(/^\\s*$/))
+	\{
+	    var confirm_mess = "Configuration data to \\"" + fullname + "\\"";
+	    confirm_mess += " is empty.  Are you sure you want to save?";
+
+	    do_save = confirm(confirm_mess);
+	\}
+	if (do_save)
+	\{
+//	    var cgi_prefix = "webpage_editcol.pl";
+//	    cgi_prefix += "?httpbuild=" + escape("_httpbuild_");
+//	    cgi_prefix += "&bc1cfgfile=" + escape(form.bc1cfgfile.value);
+
+//	    simulate_get_action(cgi_prefix);
+
+	    // need to do it this way so POST method is used (as IE can't
+	    // handle large config files sent in URL)
+	    form.action = "webpage_editcol.pl";
+	    form.submit();
+
+	\}
+   \}
+
+   function fullnameindex_changed() \{
+        _dirnamelist_
+        var form = document.form;
+
+	var fn_index = form.bc1fullnamemenu.selectedIndex;
+	form.bc1fullnameindex.value = form.bc1fullnamemenu.selectedIndex;
+	form.bc1dirname.value = dirnamelist[fn_index];
+
+	var cgi_prefix = "_httpbuild_&bca=editcol";
+        simulate_get_action(cgi_prefix);
+   \}
+
+   // end hiding -->
+
+</script>
+
+<form name="form" method="post" action="_gwcgi_" >
+<input type=hidden name="gsdlhome" value="_gsdlhome_">
+<input type=hidden name="a" value="bc">
+<input type=hidden name="bc" value="editcol">
+<input type=hidden name="httpbuild" value="_httpbuild_">
+_hiddenargs_
+
+      
+<p> To edit the configuration settings for collection, first choose the
+collection to edit through the pulldown menu, then edit the data that
+appears.  To commit your changes to disk, click on &quot;Save configuration
+data&quot;.
+
+<br><p>
+<font color="#909090">
+Use the pull-down menu below to specify the collection to edit.
+</font>
+<br>_fullnamemenu_
+<input type="hidden" name="bc1dirname" value="_bcargdirname_">
+
+<br><p>
+<font color="#909090">
+Alter the data below to change the configuration settings for the selected
+collection.  Click on &quot;Save configuration data&quot; to commit your
+changes to disk.
+</font>
+<br>
+<center>
+<textarea name="bc1cfgfile" cols=72 rows=18 wrap=off>_cfgfile_</textarea>
+</center>
+
+<br>
+<center>
+<table border=0>
+  <tr>
+    <td>
+        &nbsp;<a href="_httpbuild_&bca=editcol">_iconwizardreset_Reset page</a>
+    </td>
+    <td>&nbsp;&nbsp;&nbsp;&nbsp;</td>
+    <td>
+     <a href="javascript:save();">Save configuration data_iconwizardnext_</a>&nbsp;<br>
+     <a href="_httpbuild_&bca=mess&head=_headnosave_&mess=_messnosave_&bc1dirname=_bcargdirname_">Don't 
+	Save configuration data_iconwizardnext_</a>&nbsp;
+    </td>
+  </tr>
+</table>
+</form>
+</center>
+}
+
+
+#---------------------------------------------------------------------------#
+# Rebuild a collection
+#---------------------------------------------------------------------------#
+
+_headmessbuildcol_ { Rebuild a collection }
+
+
+_allowcopydatano_ {
+  <td>
+    <input type=radio name="bc1copydataradio" value=false
+	_If_("_bcargcopydata_" eq "false", checked)
+	onClick=document.form.bc1copydata.value=false>No
+  </td>
+}
+
+_copydatatext_ {
+<tr>
+  <td>Copy data:</td>
+  <td>
+    <input type=hidden name="bc1copydata" value="_bcargcopydata_">
+    <input type=radio name="bc1copydataradio" value=true
+	_If_("_bcargcopydata_" eq "true", checked)
+	onClick=document.form.bc1copydata.value=true>Yes
+  </td>
+  _If_("_bcargfirsttime_" eq "false",_allowcopydatano_)
+</tr>
+<tr>
+  <td></td>
+  <td colspan=3>
+    <font color="#909090">
+	<p> Copying the data is necessary the very first time the collection is
+	built.  Subsequent builds do not need this option selected, unless new
+	data has been added to the original data, in which case the data should
+	be recopied.
+     </font>
+  </td>
+</tr>
+}
+
+_contentbuildcol_ {
+
+
+<script language="javascript">
+
+   <!-- Hide code from non-js browsers
+   function simulate_get_action(args)
+     \{
+        var form = document.form;
+
+//	args += "&bc1fullnameindex=" + escape(form.bc1fullnameindex.value); //****
+	args += "&bc1dirname=" + escape(form.bc1dirname.value);
+	args += "&bc1copydata=" + escape(form.bc1copydata.value);
+	args += "&bc1doimport=" + escape(form.bc1doimport.value);
+	args += "&bc1dobuild=" + escape(form.bc1dobuild.value);
+
+	document.location = args;
+     \}
+
+   function build() \{
+        _dirnamelist_
+        var form = document.form;
+
+	var fn_index = form.bc1fullnameindex.value;
+	var fullname = form.bc1fullnamemenu.options[fn_index].value;
+
+	form.bc1dirname.value = dirnamelist[fn_index];
+
+	var cgi_prefix = "_httpbuild_&bca=buildcol";
+	cgi_prefix += "&httpbuild=" + escape("_httpbuild_");
+	cgi_prefix += "&wizard=buildframe";
+
+        simulate_get_action(cgi_prefix);
+   \}
+
+   function fullnameindex_changed() \{
+        _dirnamelist_
+
+        var form = document.form;
+	var fn_index = form.bc1fullnamemenu.selectedIndex;
+	form.bc1fullnameindex.value = form.bc1fullnamemenu.selectedIndex;
+	form.bc1dirname.value = dirnamelist[fn_index];
+
+	var cgi_prefix = "_httpbuild_&bca=buildcol";
+	cgi_prefix += "&httpbuild=" + escape("_httpbuild_");
+	cgi_prefix += "&wizard=buildcol";
+
+	simulate_get_action(cgi_prefix);
+   \}
+
+   // end hiding -->
+
+</script>
+
+<center><table><tr><td>
+<form name="form" method="post" action="_gwcgi_" >
+<input type=hidden name="gsdlhome" value="_gsdlhome_">
+<input type=hidden name="a" value="bc">
+<input type=hidden name="bc" value="buildcol">
+_hiddenargs_
+
+
+<table border=0>
+<tr>
+  <td colspan=4> 
+      Building a collection is a multi-staged process.  After selecting the
+      collection you wish to be built, you must specify which stages of
+      the building process you want executed.
+      _If_(_win32_,
+      <p><font color="#B00000">
+      <blockquote>It is recommended that you close all other windows and applications
+      while building a collection as they may interfere with the building
+      process.
+      </blockquote></font>)
+      <br>
+  </td>
+</tr>
+
+
+<tr>
+  <td>Collection to rebuild:</td>
+  <td colspan=3>
+     _fullnamemenu_
+    <input type="hidden" name="bc1dirname" value="_bcargdirname_">
+  </td>
+<tr>
+  <td></td>
+  <td colspan=3>
+    <font color="#909090">
+	Select from the pull-down menu the collection you wish to rebuild.
+    </font>
+  </td>
+</tr>
+
+
+_If_("_bcargcopydir_" eq "yes",
+  _copydatatext_
+  ,
+    <input type=hidden name="bc1copydata" value="false">
+)
+
+
+<tr>
+  <td>Cache intermediate data:</td>
+  <td>
+    <input type=hidden name="bc1doimport" value="_bcargdoimport_">
+    <input type=radio name="bc1doimportradio" value=true
+	_If_("_bcargdoimport_" eq "true", checked)
+	onClick=document.form.bc1doimport.value=true>Yes
+  </td>
+  <td>
+    <input type=radio name="bc1doimportradio" value=false
+	_If_("_bcargdoimport_" eq "false", checked)
+	onClick=document.form.bc1doimport.value=false>No
+  </td>
+</tr>
+<tr>
+  <td></td>
+  <td colspan=3>
+    <font color="#909090">
+	<p> To speed up the collection building process, intermediate data can be
+	cached to file.  Set this option to &quot;yes&quot; (the default) unless 
+	the collection is prohibitively large or the amount of available disk space
+	is small.
+     </font>
+  </td>
+</tr>
+
+<tr>
+  <td>Create indexes:</td>
+  <td>
+    <input type=hidden name="bc1dobuild" value="_bcargdobuild_">
+    <input type=radio name="bc1dobuildradio" value=true
+	_If_("_bcargdobuild_" eq "true", checked)
+	onClick=document.form.bc1dobuild.value=true>Yes
+  </td>
+  <td>
+    <input type=radio name="bc1dobuildradio" value=false
+	_If_("_bcargdobuild_" eq "false", checked)
+	onClick=document.form.bc1dobuild.value=false>No
+  </td>
+</tr>
+<tr>
+  <td></td>
+  <td colspan=3>
+    <font color="#909090">
+  	<p> The final stage of building a collection is the creation of the indexes.
+        Except in very unusual circumstances this option should be
+	set to &quot;yes&quot; (the default).
+     </font>
+  </td>
+</tr>
+
+
+
+<tr><td><p>&nbsp;</td></tr>
+<tr><td colspan=4 align=middle>
+  &nbsp;<a href="_httpbuild_&bca=buildcol">_iconwizardreset_Reset page</a>&nbsp;&nbsp;&nbsp;&nbsp;
+  <a href="javascript:build();">Rebuild collection_iconwizardnext_</a>&nbsp;
+</table>
+</form>
+</td></tr></table></center>
+
+}
+
+
+#---------------------------------------------------------------------------#
+
+_headmessbuildframe_ { Executing build commands }
+
+_contentbuildframe_ {
+
+<frameset rows="200,150,*" border=0>
+  <noframes><body bgcolor="#ffffff">
+  <p>You must have a frame enabled browser to view this.</p>
+  </body>
+  </noframes>
+  <frame src="_httpbuild_&bca=buildcol&wizard=buildexec&bc1dirname=_bcargdirname_&bc1tmpname=_bcargtmpname_" name=infoframe>
+  <frame src="_httpbuild_&bca=buildstatus&bc1tmpname=_bcargtmpname_" name=execframe>
+  <frame src="_httpbuild_&bca=blankpage" name=blankframe>
+</frameset>
+}
+
+#---------------------------------------------------------------------------#
+
+_headmessbuildexec_ { Executing build commands }
+
+
+_contentbuildexec_ {
+
+
+<script language="javascript">
+
+   <!-- Hide code from non-js browsers
+   var timer = 10;
+   function restart_count_down() \{
+	timer=10;
+	setTimeout("count_down()",1000);
+   \}
+
+   function count_down() \{
+	if (timer==0) 
+	\{
+	  update_status_page();
+	\}
+	else 
+	\{
+	  window.status = "Building status update in  "+timer+" seconds";
+	  timer--;
+	  setTimeout("count_down()",1000);
+	\}	
+   \}
+
+   function update_status_page() \{
+	var cgi_cmd = "webpage_buildstatus.pl";
+	cgi_cmd += "?httpbuild=" + escape("_httpbuild_");
+	cgi_cmd += "&bc1dirname=" + escape("_bcargdirname_");
+	cgi_cmd += "&bc1tmpname=" + escape("_bcargtmpname_");
+	parent.execframe.document.location = cgi_cmd;
+
+	var finished = document.form.bc1finished.value;
+	if (finished==0)
+	  \{	
+//   	     setTimeout("update_status_page()",5000);	   //****
+//   	     setTimeout("count_down()",1000);
+	     restart_count_down();
+	  \}
+	else
+	  \{
+	     var cgi_cmd = "_httpbuild_&bca=mess";
+	     if (finished>0)
+	       \{
+		  cgi_cmd += "&head=_headdone_&mess=_messdonebuildcol_";
+	       \}
+	     else
+	       \{
+		  cgi_cmd += "&head=_headerror_&mess=_messerrorbuildcol_";
+	       \}
+
+	     cgi_cmd += "&httpbuild=" + escape("_httpbuild_");
+	     cgi_cmd += "&bc1dirname=" + escape("_bcargdirname_");
+	     parent.document.location = cgi_cmd;	
+	  \}
+   \}
+
+   // end hiding -->
+
+</script>
+
+<center><table><tr><td>
+<form name="form" method="post" action="_gwcgi_" >
+<!-- <input type=hidden name="gsdlhome" value="_gsdlhome_">
+<input type=hidden name="httpbuild" value="_httpbuild_"> ********* and others !!! -->
+<input type=hidden name="a" value="bc">
+<input type=hidden name="bc" value="buildcol">
+_hiddenargs_
+
+<input type=hidden name="bc1finished" value=0>
+
+
+
+<table border=0>
+<tr>
+  <td colspan=4> 
+	The collection is now being built.  See the building status line
+        below for feedback on how the operation is progressing.
+  </td>
+</tr>
+
+</table>
+</form>
+</td></tr></table></center>
+
+<script language="javascript">
+   <!-- Hide code from non-js browsers
+   update_status_page();
+   // end hiding -->
+</script>
+
+}
+
+package buildstatus
+
+_header_ {
+<html>
+<head>
+<title>Building status</title>
+</head>
+<body bgcolor="#ffffff" text="#000000" link="#006666"
+      alink="#cc9900" vlink="#666633">
+<h3>Building status:</h3>
+}
+
+_footer_ {
+</body>
+</html>
+}
+
+_content_ {
+
+<script language="javascript">
+   <!-- Hide code from non-js browsers
+   if (parent.infoframe.document.form) // form loaded
+     \{
+         parent.infoframe.document.form.bc1finished.value = "_build:bcargfinished_";
+     \}
+   // end hiding -->
+</script>
+
+	_contentpara_
+}
+
+
+#---------------------------------------------------------------------------#
+# Delete a collection
+#---------------------------------------------------------------------------#
+
+package build
+
+_headmessdelcol_ { Delete a collection }
+
+
+_contentdelcol_ {
+
+
+<script language="javascript">
+
+   <!-- Hide code from non-js browsers
+   function simulate_get_action(args)
+     \{
+        var form = document.form;
+
+//	args += "&bc1fullnameindex=" + escape(form.bc1fullnameindex.value);
+	args += "&bc1dirname=" + escape(form.bc1dirname.value);
+	args += "&bc1deletearea=" + escape(form.bc1deletearea.value);
+
+	document.location = args;
+     \}
+
+   function delete_area() \{
+        _dirnamelist_
+        var form = document.form;
+
+	var fn_index = form.bc1fullnameindex.value;
+	var fullname = form.bc1fullnamemenu.options[fn_index].value;
+	var deletearea = form.bc1deletearea.value;
+
+	form.bc1dirname.value = dirnamelist[fn_index];
+
+	var da_mess = "";
+	if (deletearea == "archives") \{ da_mess = "cached building data"; \}
+	else if (deletearea == "import") \{ da_mess = "source data"; \}
+	else \{ da_mess = "all data"; \}
+
+	var confirm_mess = "Confirm deletion of \\"" + da_mess + "\\"";
+	confirm_mess += " from \\"the " + fullname + " collection\\"";
+
+	var do_delete = confirm(confirm_mess);
+	if (do_delete)
+	  \{
+	    var cgi_prefix = "webpage_delcol.pl";
+	    cgi_prefix += "?httpbuild=" + escape("_httpbuild_");
+
+            simulate_get_action(cgi_prefix);
+	  \}
+   \}
+
+   function fullnameindex_changed() \{
+        var form = document.form;
+	var fn_index = form.bc1fullnamemenu.selectedIndex;
+	form.bc1fullnameindex.value = form.bc1fullnamemenu.selectedIndex;
+   \}
+
+   // end hiding -->
+
+</script>
+
+<center><table><tr><td>
+<form name="form" method="post" action="_gwcgi_" >
+<input type=hidden name="gsdlhome" value="_gsdlhome_">
+<input type=hidden name="a" value="bc">
+<input type=hidden name="bc" value="delcol">
+_hiddenargs_
+
+
+<table border=0>
+<tr>
+  <td colspan=4>
+      Deletion of data from a collection can be selective or all
+      encompassing. Use the options below to specify the required
+      deletion operation.
+  </td>
+</tr>
+
+
+<tr>
+  <td>Collection to delete:</td>
+  <td colspan=3>
+     _fullnamemenu_
+    <input type="hidden" name="bc1dirname" value="_bcargdirname_">
+  </td>
+<tr>
+  <td></td>
+  <td colspan=3>
+    <font color="#909090">
+	Use this pull-down menu to target the collection that has files deleted.
+    </font>
+  </td>
+</tr>
+
+<tr>
+  <td>Type of data to delete:</td>
+  <td>
+    <input type=hidden name="bc1deletearea" value="_bcargdeletearea_">
+    <input type=radio name="bc1deletearearadio" value="archives" 
+	onClick=document.form.bc1deletearea.value="archives"
+	_If_("_bcargdeletearea_" eq "archives", checked)
+	_If_("_bcargdeletearea_" eq "", checked)> cached data
+  </td>
+  <td>
+    <input type=radio name="bc1deletearearadio" value="import"
+	onClick=document.form.bc1deletearea.value="import"
+	_If_('"_bcargdeletearea_" eq "import"', checked)> cached and source data
+  </td>
+  <td>
+    <input type=radio name="bc1deletearearadio" value="all"
+	onClick=document.form.bc1deletearea.value="all"
+	_If_('"_bcargdeletearea_" eq "all"', checked)> all data
+  </td>
+</tr>
+<tr>
+  <td></td>
+  <td colspan=3>
+    <font color="#909090">
+	There are three levels to deletion: cached data; cached and
+	source data; and all data.  
+
+	<p> Cached data is generated during
+	a building operation, and is superfluous to a collection that
+	is &quot;live&quot;.  Keeping this data, however, can save
+	time if the only required step in a rebuild is index creation.
+
+	<p> Source data, like cached data, is superflous to a collection
+	that is &quot;live&quot;.  However, you must keep this data if
+	you intend to rebuild the collection in the future.
+
+	<p> The final level to collection deletion is delete &quot;all data&quot;
+	Selecting this option removes all traces of the collection 
+	from the digital library.
+
+     </font>
+  </td>
+</tr>
+
+
+<tr><td><p>&nbsp;</td></tr>
+<tr><td colspan=4 align=middle>
+  &nbsp;<a href="_httpbuild_&bca=delcol">_iconwizardreset_Reset page</a>&nbsp;&nbsp;&nbsp;&nbsp;
+  <a href="javascript:delete_area();">Delete specified data_iconwizardnext_</a>&nbsp;
+</table>
+</form>
+</td></tr></table></center>
+
+}
+
+
+
+_headmesscollog_ { Collection Build Log }
+
+
+_contentcollog_ {
+<pre>
+_bldfile_
+</pre>
+}
+
+
+package buildmess
+
+_headmess_ {}
+_headdone_ {Successful Operation}
+_headnosave_ {Configuration Unchanged}
+_headerror_ {Error Encountered}
+
+_messdonenewcol_ {
+    <p> Configuration of the new collection was successfully saved.
+        Would you like to:
+    <ul>
+      <li><a href="_httpbuild_&bca=newcol">Create a new
+	collection_build:iconwizardnext_</a>
+      <li><a href="_httpbuild_&bca=editcol&bc1dirname=_build:bcargdirname_">Edit 
+	this collection's configuration file_build:iconwizardnext_</a>
+      <li><a href="_httpbuild_&bca=buildcol&bc1dirname=_build:bcargdirname_">Build
+	this collection_build:iconwizardnext_</a>
+      <li><a href="_httpbuild_&bca=delcol">Delete data from a
+	collection_build:iconwizardnext_</a>
+      <li><a href="_httppagehome_" target="_top">Return to the Greenstone home
+	page_build:iconwizardnext_</a>
+    </ul>
+}
+
+_messdoneeditcol_ {
+    <p> Configuration of collection successfully updated.
+        Would you like to:
+    <ul>
+      <li><a href="_httppageabout_&c=_build:bcargdirname_" target="_top">Access
+	this collection_build:iconwizardnext_</a>
+      <li><a href="_httpbuild_&bca=newcol">Create a new
+	collection_build:iconwizardnext_</a>
+      <li><a href="_httpbuild_&bca=editcol&bc1dirname=_build:bcargdirname_">Edit 
+	this collection's configuration file_build:iconwizardnext_</a>
+      <li><a href="_httpbuild_&bca=buildcol&bc1dirname=_build:bcargdirname_">Build
+	this collection_build:iconwizardnext_</a>
+      <li><a href="_httpbuild_&bca=delcol">Delete data from a
+	collection_build:iconwizardnext_</a>
+      <li><a href="_httppagehome_" target="_top">Return to the Greenstone home
+	page_build:iconwizardnext_</a>
+    </ul>
+}
+
+_messnosave_ {
+    <p> Configuration unchanged.
+        Would you like to:
+    <ul>
+      <li><a href="_httppageabout_&c=_build:bcargdirname_" target="_top">Access
+	this collection_build:iconwizardnext_</a>
+      <li><a href="_httpbuild_&bca=newcol">Create a new
+	collection_build:iconwizardnext_</a>
+      <li><a href="_httpbuild_&bca=editcol&bc1dirname=_build:bcargdirname_">Edit 
+	this collection's configuration file_build:iconwizardnext_</a>
+      <li><a href="_httpbuild_&bca=buildcol&bc1dirname=_build:bcargdirname_">Build
+	this collection_build:iconwizardnext_</a>
+      <li><a href="_httpbuild_&bca=delcol">Delete data from a
+	collection_build:iconwizardnext_</a>
+      <li><a href="_httppagehome_" target="_top">Return to the Greenstone home
+	page_build:iconwizardnext_</a>
+    </ul>
+}
+
+_messdonebuildcol_ {
+    <p> The collection has been successfully built.
+        Would you like to:
+    <ul>
+      <li><a href="_httppageabout_&c=_build:bcargdirname_" target="_top">Access
+	the newly built collection_build:iconwizardnext_</a>
+      <li><a href="_httpbuild_&bca=collog&bc1dirname=_build:bcargdirname_">View 
+        the build log for this collection_build:iconwizardnext_</a>
+      <li><a href="_httpbuild_&bca=newcol">Create a new
+	collection_build:iconwizardnext_</a>
+      <li><a href="_httpbuild_&bca=editcol&bc1dirname=_build:bcargdirname_">Edit
+	this collection's configuration file_build:iconwizardnext_</a>
+      <li><a href="_httpbuild_&bca=buildcol&bc1dirname=_build:bcargdirname_">Rebuild
+	this collection_build:iconwizardnext_</a>
+      <li><a href="_httpbuild_&bca=delcol">Delete data from a
+	collection_build:iconwizardnext_</a>
+      <li><a href="_httppagehome_" target="_top">Return to the Greenstone home
+	page_build:iconwizardnext_</a>
+    </ul>
+}
+
+_messdonedelcol_ {
+    <p> Files successfully deleted.  Would you like to:
+    <ul>
+      <li><a href="_httpbuild_&bca=newcol">Create a new
+	collection_build:iconwizardnext_</a>
+      <li><a href="_httpbuild_&bca=editcol">Edit 
+	a collection's configuration file_build:iconwizardnext_</a>
+      <li><a href="_httpbuild_&bca=buildcol">Build
+	a collection_build:iconwizardnext_</a>
+      <li><a href="_httpbuild_&bca=delcol">Delete data from another
+	collection_build:iconwizardnext_</a>
+      <li><a href="_httppagehome_" target="_top">Return to the Greenstone home
+	page_build:iconwizardnext_</a>
+    </ul>
+}
+
+_messnofn_ { 
+  <p> <center>Empty collection title</center> }
+
+_messconfigexists_ {
+  <p> <center>A configuration file already exists for this collection.</center> }
+
+_messerrorbuildcol_ {
+  <p> An error was encountered during the building operation, and
+      consequently the generated files have not been 
+      transfered to the &quot;live&quot; collection.  Would you like to:
+
+    <ul>
+      <li><a href="_httppageabout_&c=_build:bcargdirname_" target="_top">Access
+	the existing collection_build:iconwizardnext_</a>
+      <li><a href="_httpbuild_&bca=newcol">Create a new
+	collection_build:iconwizardnext_</a>
+      <li><a href="_httpbuild_&bca=editcol&bc1dirname=_build:bcargdirname_">Edit
+	this collection's configuration file_build:iconwizardnext_</a>
+      <li><a href="_httpbuild_&bca=buildcol&bc1dirname=_build:bcargdirname_">Rebuild
+	this collection_build:iconwizardnext_</a>
+      <li><a href="_httpbuild_&bca=delcol">Delete data from a
+	collection_build:iconwizardnext_</a>
+      <li><a href="_httppagehome_" target="_top">Return to the Greenstone home
+	page_build:iconwizardnext_</a>
+    </ul>
+
+}
+
+_messerror_ {<center>An error was encountered.</center> }
+
+
+_content_ {
+	_contentpara_
+}
+
+_colexists_ {
+  <p> The collection title you have specified already exists.  Please choose another.
+
+}
Index: /main/tags/2.25/gsdl/macros/delhistory.dm
===================================================================
--- /main/tags/2.25/gsdl/macros/delhistory.dm	(revision 21064)
+++ /main/tags/2.25/gsdl/macros/delhistory.dm	(revision 21064)
@@ -0,0 +1,35 @@
+package delhistory
+
+#######################################################################
+# page content
+#######################################################################
+
+_pagetitle_ {_textdsh_}
+
+_content_ {
+<center>
+_navigationbar_
+</center>
+<center>
+_deletehistoryform_
+</center>
+
+
+}
+
+_deletehistoryform_ {
+<form name=DelHistoryForm method=get action="_gwcgi_">
+<input type=hidden name=a value=dh>
+<input type=hidden name=e value=_decodedcompressedoptions_>
+<input type=hidden name=hdh value=0>
+_textselectdelete_
+<p>
+<table width=200 border=0>
+<tr><td><input type=text name=hsr size=20 width=150 maxlength=50></td>
+<td><input type=submit value="_textclearselected_"></td></tr>
+</table>
+<p>
+_searchhistorylist_
+</form>
+
+}
Index: /main/tags/2.25/gsdl/macros/document.dm
===================================================================
--- /main/tags/2.25/gsdl/macros/document.dm	(revision 21064)
+++ /main/tags/2.25/gsdl/macros/document.dm	(revision 21064)
@@ -0,0 +1,335 @@
+package document
+
+#######################################################################
+# macros set from within the server
+#######################################################################
+
+_classificationlinks_ {}
+_imagethispage_ {}
+_httpprevarrow_ {}
+_httpnextarrow_ {}
+_pagetitle_ {}
+
+#######################################################################
+# page content
+#######################################################################
+
+_content_ {
+<center>
+_navigationbar_
+<p>
+_classificationlinks_
+</center>
+}
+
+
+#######################################################################
+# javascript macros
+#
+# there should be one of these for each flashy javascript button
+# that may appear within a document page
+#######################################################################
+
+# javaextras allows specific collections to include extra java macros
+# without having to override their document action
+_javaextras_ {}
+
+_javadetach_ {
+	detach\_on = new Image(_widthedtchx_, _heightedtchx_); 
+	detach\_on.src = "_httpiconedtchon_";
+	detach\_off = new Image(_widthedtchx_, _heightedtchx_); 
+	detach\_off.src = "_httpiconedtchof_";
+}
+
+_javaexpandcontents_ {
+	expcon\_on = new Image(_widtheexpcx_, _heighteexpcx_);
+	expcon\_on.src = "_httpiconeexpcon_";
+	expcon\_off = new Image(_widtheexpcx_, _heighteexpcx_);
+	expcon\_off.src = "_httpiconeexpcof_";
+}
+
+_javacontractcontents_ {
+	concon\_on = new Image(_widtheconcx_, _heighteconcx_);
+	concon\_on.src = "_httpiconeconcon_";
+	concon\_off = new Image(_widtheconcx_, _heighteconcx_);
+	concon\_off.src = "_httpiconeconcof_";
+}
+
+_javaexpandtext_ {
+	alltext\_on = new Image(_widthealltx_, _heightealltx_);
+	alltext\_on.src = "_httpiconeallton_";
+	alltext\_off = new Image(_widthealltx_, _heightealltx_);
+	alltext\_off.src = "_httpiconealltof_";
+}
+
+_javacontracttext_ {
+	thissec\_on = new Image(_widthetsecx_, _heightetsecx_);
+	thissec\_on.src = "_httpiconetsecon_";
+	thissec\_off = new Image(_widthetsecx_, _heightetsecx_);
+	thissec\_off.src = "_httpiconetsecof_";
+}
+
+_javahighlighting_ {
+	hl\_on = new Image(_widthehlx_, _heightehlx_);
+	hl\_on.src = "_httpiconehlon_";
+	hl\_off = new Image(_widthehlx_, _heightehlx_);
+	hl\_off.src = "_httpiconehlof_";
+}
+
+_javanohighlighting_ {
+	nhl\_on = new Image(_widthenhlx_, _heightenhlx_);
+	nhl\_on.src = "_httpiconenhlon_";
+	nhl\_off = new Image(_widthenhlx_, _heightenhlx_);
+	nhl\_off.src = "_httpiconenhlof_";
+}
+
+_javacontinue_ {
+	cont\_on = new Image(_widthcontx_, _heightcontx_);
+	cont\_on.src = "_httpiconconton_";
+	cont\_off = new Image(_widthcontx_, _heightcontx_);
+	cont\_off.src = "_httpiconcontoff_";
+}
+
+#######################################################################
+# navigation arrows
+#
+#######################################################################
+
+_navarrows_ {<center>
+<table width=_pagewidth_ cellpadding=0 cellspacing=0 border=0>
+<tr><td align=left valign=top>
+_prevarrow_
+</td><td align=right valign=top>
+_nextarrow_
+</td></tr></table>
+</center>
+}
+
+_prevarrow_ {_If_(_httpprevarrow_,<a href="_httpprevarrow_">_iconprev_</a>)}
+_nextarrow_ {_If_(_httpnextarrow_,<a href="_httpnextarrow_">_iconnext_</a>)}
+
+_navarrows_ [v=1] {<p>
+_prevarrow_<br>
+_nextarrow_
+}
+
+#######################################################################
+# the goto form
+#######################################################################
+
+_gotoform_ {
+<form name="GotoForm" method="get" action="_gwcgi_">
+<input type=hidden name="e" value="_decodedcompressedoptions_">
+<input type=hidden name="d" value="_cgiargd_">
+<input type=hidden name="cl" value="_cgiargcl_">
+<input type="text" name="gp" size="3" maxlength="4">
+<input type="submit" value="_textgoto_">
+</form>
+}
+
+_textnumpages_ {&nbsp;<i>(_1_ _pages_)</i>}
+_parentarrow_ {}
+
+
+#######################################################################
+# icons
+#######################################################################
+
+# title images - there should be one of these for each classification
+# supported by this receptionist
+
+_iconTitlepage_ {<img src="_httpiconhtitle_" width=_widthhtitle_
+height=_heighthtitle_}
+_iconTitlepage_ [v=1] {<h2>_texticonhtitle_</h2>}
+
+_iconListpage_ {<img src="_httpiconhlist_" width=_widthhlist_
+height=_heighthlist_}
+_iconListpage_ [v=1] {<h2>_texticonhlist_</h2>}
+
+_iconCreatorpage_ {<img src="_httpiconhauth_" width=_widthhauth_
+height=_heighthauth_}
+_iconCreatorpage_ [v=1] {<h2>_texticonhauth_</h2>}
+
+_iconSubjectpage_ {<img src="_httpiconhsubj_" width=_widthhsubj_
+height=_heighthsubj_}
+_iconSubjectpage_ [v=1] {<h2>_texticonhsubj_</h2>}
+
+_iconTopage_ {<img src="_httpiconhto_" width=_widthhto_
+height=_heighthto_}
+_iconTopage_ [v=1] {<h2>_texticonhto_</h2>}
+
+_iconFrompage_ {<img src="_httpiconhfrom_" width=_widthhfrom_
+height=_heighthfrom_}
+_iconFrompage_ [v=1] {<h2>_texticonhfrom_</h2>}
+
+_iconSeriespage_ {<img src="_httpiconhser_" width=_widthhser_
+height=_heighthser_}
+_iconSeriespage_ [v=1] {<h2>_texticonhser_</h2>}
+
+_iconDatepage_ {<img src="_httpiconhdate_" width=_widthhdate_
+height=_heighthdate_}
+_iconDatepage_ [v=1] {<h2>_texticonhdate_</h2>}
+
+_iconHowtopage_ {<img src="_httpiconhhow_" width=_widthhhow_
+height=_heighthhow_}
+_iconHowtopage_ [v=1] {<h2>_texticonhhow_</h2>}
+
+_iconTopicpage_ {<img src="_httpiconhtopic_" width=_widthhtopic_
+height=_heighthtopic_}
+_iconTopicpage_ [v=1] {<h2>_texticonhtopic_</h2>}
+
+_iconOrganizationpage_ {<img src="_httpiconhorg_" width=_widthhorg_
+height=_heighthorg_}
+_iconOrganizationpage_ [v=1] {<h2>_texticonhorg_</h2>}
+
+_iconBrowsepage_ {<img src="_httpiconhbrwse_" width=_widthhbrwse_
+height=_heighthbrwse_}
+_iconBrowsepage_ [v=1] {<h2>_texticonhbrwse_</h2>}
+
+_iconPeoplepage_ {<img src="_httpiconhpeople_" width=_widthhpeople_
+height=_heighthpeople_}
+_iconPeoplepage_ [v=1] {<h2>_texticonhpeople_</h2>}
+
+_iconLanguagepage_ {<img src="_httpiconhlanguage_" width=_widthhlanguage_
+height=_heighthlanguage_}
+_iconLanguagepage_ [v=1] {<h2>_texticonhlanguage_</h2>}
+
+_iconAcronymspage_ {<img src="_httpiconhacronyms_" width=_widthhacronyms_
+height=_heighthacronyms_}
+_iconAcronymspage_ [v=1] {<h2>_texticonhacronyms_</h2>}
+
+
+_iconsmalltext_ {<img src="_httpiconsmtext_" border=0 width=_widthsmtext_ height=_heightsmtext_ alt="_texticonsmalltext_">}
+_iconsmalltext_ [v=1] {<small><b>_texticonsmalltext2_</b></small>}
+
+_iconarrowsmalltext_ {<img src="_httpiconasmtext_" border=0 width=_widthasmtext_ height=_heightasmtext_ alt="_texticonsmalltext_">}
+_iconarrowsmalltext_ [v=1] {<small><b>->_texticonsmalltext2_</b></small>}
+
+_iconclosedfolder_ {<img src="_httpiconclsdfldr_" border=0 width=_widthclsdfldr_ height=_heightclsdfldr_ alt="_texticonclosedfolder_">}
+_iconclosedfolder_ [v=1] {<small><b>_texticonclosedfolder2_</b></small>}
+
+_iconarrowclosedfolder_ {<img src=_httpiconaclsdfdr_" border=0 width=_widthaclsdfdr_ height=_heightaclsdfdr_ alt="_texticonclosedfolder_">}
+_iconarrowclosedfolder_ [v=1] {<small><b>->_texticonclosedfolder2_</b></small>}
+
+_iconopenfolder_ {<img src="_httpiconopenfldr_" border=0 width=_widthopenfldr_ height=_heightopenfldr_ alt="_texticonopenfolder_">}
+_iconopenfolder_ [v=1] {<small><b>_texticonopenfolder2_</b></small>}
+
+_iconarrowopenfolder_ {<img src="_httpiconaopenfdr_" border=0 width=_widthaopenfdr_ height=_heightaopenfdr_ alt="_texticonopenfolder_">}
+_iconarrowopenfolder_ [v=1] {<small><b>->_texticonopenfolder2_</b></small>}
+
+_iconarrowclosedbook_ {<img src="_httpiconabook_" width=_widthabook_ height=_heightabook_ border=0 alt="_texticonclosedbook_">}
+_iconarrowclosedbook_ [v=1] {<small><b>->_texticonclosedbook_: </b></small>}
+
+_iconopenbook_ {<img src="_httpiconopenbook_" width=_widthopenbook_ height=_heightopenbook_ border=0 alt="_texticonopenbook_">}
+_iconopenbook_ [v=1] {<small><b>_texticonopenbook_: </b></small>}
+
+_iconarrowopenbook_ {<img src="_httpiconaopenbk_" width=_widthaopenbk_ height=_heightaopenbk_ border=0 alt="_texticonopenbook_">}
+_iconarrowopenbook_ [v=1] {<small><b>->_texticonopenbook_: </b></small>}
+
+_iconopenbookshelf_ {<img src="_httpiconbshelf_" border=0 width=_widthbshelf_ height=_heightbshelf_ alt="_texticonopenbookshelf_">}
+_iconopenbookshelf_ [v=1] {<small><b>_texticonopenbookshelf_: </b></small>}
+
+_iconarrowopenbookshelf_ {<img src="_httpiconabshelf_" border=0 width=_widthabshelf_ height=_heightabshelf_ alt="_texticonopenbookshelf_">}
+_iconarrowopenbookshelf_ [v=1] {<small><b>->_texticonopenbookshelf_: </b></small>}
+
+_iconclosedbookshelf_ {<img src="_httpiconbshelf_" border=0 width=_widthbshelf_ height=_heightbshelf_ alt="_texticonclosedbookshelf_">}
+_iconclosedbookshelf_ [v=1] {<small><b>_texticonclosedbookshelf_: </b></small>}
+
+_iconarrowclosedbookshelf_ {<img src="_httpiconabshelf_" border=0 width=_widthabshelf_ height=_heightabshelf_ alt="_texticonclosedbookshelf_">}
+_iconarrowclosedbookshelf_ [v=1] {<small><b>->_texticonclosedbookshelf_: </b></small>}
+
+_iconpointer_ {<img src="_httpiconarrrght_" border=0 width=_widtharrrght_ height=_heightarrrght_>}
+_iconpointer_ [v=1] {<small><b>_texticonpointer_-> </b></small>}
+
+_icontab_ {<img src="_httpicontabspace_" width=_widthtabspace_ height=_heighttabspace_>}
+_tab_ {<td>_icontab_</td>}
+
+_iconcontracttoc_ {<img name="concon" src="_httpiconeconcof_" width=_widtheconcx_ height=_heighteconcx_ alt="_texticoncontracttoc_" border=0>}
+_iconcontracttoc_[v=1] {_texticoncontracttoc_}
+
+_iconexpandtoc_ {<img name="expcon" src="_httpiconeexpcof_" width=_widtheexpcx_ height=_heighteexpcx_ alt="_texticonexpandtoc_" border=0>}
+_iconexpandtoc_[v=1] {_texticonexpandtoc_}
+
+_iconcontracttext_ {<img name="thissec" src="_httpiconetsecof_" width=_widthetsecx_ height=_heightetsecx_ alt="_texticoncontracttext_" border=0>}
+_iconcontracttext_[v=1] {_texticoncontracttext_}
+
+_iconexpandtext_ {<img name="alltext" src="_httpiconealltof_" width=_widthealltx_ height=_heightealltx_ alt="_texticonexpandtext_" border=0>}
+_iconexpandtext_[v=1] {_texticonexpandtext_}
+
+_icondetach_ {<img name="detach" src="_httpiconedtchof_" width=_widthedtchx_ height=_heightedtchx_ alt="_texticondetach_" border=0>}
+_icondetach_[v=1] {_texticondetach_}
+
+_iconhighlight_ {<img name="hl" src="_httpiconehlof_" width=_widthehlx_ height=_heightehlx_ alt="_texticonhighlight_" border=0>}
+_iconhighlight_ [v=1] {_texticonhighlight_}
+
+_iconnohighlight_ {<img name="nhl" src="_httpiconenhlof_" width=_widthenhlx_ height=_heightenhlx_ alt="_texticonnohighlight_" border=0>}
+_iconnohighlight_ [v=1] {_texticonnohighlight_}
+
+_iconwarning_ {<img src="_httpiconwarning_" width=_widthwarning_ height=_heightwarning_ border=0 align=left>}
+_iconwarning_ [v=1] {_texticonwarning_}
+
+_iconcont_ {<img name="cont" src="_httpiconcontoff_" width=_widthcontx_ height=_heightcontx_ border=0>}
+_iconcont_ [v=1] {_texticoncont_}
+
+
+#######################################################################
+# images
+#######################################################################
+
+_imagedetach_ {<a href="_httpcurrentdocument_&x=1" target=\_blank onMouseover = "img\_on('detach')"
+onMouseout = "img\_off('detach')">_icondetach_</a>}
+_imagedetach_[v=1] {<a href="_httpcurrentdocument_&x=1" target=\_blank>_texticondetach_</a><br>}
+
+_imagehighlight_ {<a href="_httpcurrentdocument_&hl=1&gc=_cgiarggc_&amp;gt=_cgiarggt_" onMouseover = "img\_on('hl')"
+onMouseout = "img\_off('hl')">_iconhighlight_</a>}
+_imagehighlight_ [v=1] {<a href="_httpcurrentdocument_&hl=1&gc=_cgiarggc_&amp;gt=_cgiarggt_">_texticonhighlight_</a><br>}
+
+_imagenohighlight_ {<a href="_httpcurrentdocument_&hl=0&gc=_cgiarggc_&amp;gt=_cgiarggt_" onMouseover = "img\_on('nhl')"
+onMouseout = "img\_off('nhl')">_iconnohighlight_</a>}
+_imagenohighlight_ [v=1] {<a href="_httpcurrentdocument_&hl=0&gc=_cgiarggc_&amp;gt=_cgiarggt_">_texticonnohighlight_</a><br>}
+
+_imagecontracttoc_ {<a href="_httpcurrentdocument_&gc=0" onMouseover = "img\_on('concon')"
+onMouseout = "img\_off('concon')">_iconcontracttoc_</a>}
+_imagecontracttoc_[v=1] {"<a href="_httpcurrentdocument_&gc=0">_texticoncontracttoc_</a><br>}
+
+_imageexpandtoc_ {<a href="_httpcurrentdocument_&gc=1" onMouseover = "img\_on('expcon')"
+onMouseout = "img\_off('expcon')">_iconexpandtoc_</a>}
+_imageexpandtoc_ [v=1] {"<a href="_httpcurrentdocument_&gc=1">_texticonexpandtoc_</a><br>}
+
+_imagecontracttext_ {<a href="_httpcurrentdocument_&amp;gt=0" onMouseover = "img\_on('thissec')"
+onMouseout = "img\_off('thissec')">_iconcontracttext_</a>}
+_imagecontracttext_[v=1] {<a href="_httpcurrentdocument_&amp;gt=0">display only current section</a><br>}
+
+_imageexpandtext_ {<a href="_httpcurrentdocument_&amp;gt=1" onMouseover = "img\_on('alltext')"
+onMouseout = "img\_off('alltext')">_iconexpandtext_</a>}
+_imageexpandtext_[v=1] {<a href="_httpcurrentdocument_&amp;gt=1">display all text</a><br>}
+
+_imagecont_ {<a href="_httpcurrentdocument_&amp;gt=2" onMouseover = "img\_on('cont')"
+onMouseout = "img\_off('cont')">_iconcont_</a>}
+_imagecont_[v=1] {<a href="_httpcurrentdocument&amp;gt=2">_texticoncont_</a><br>}
+
+
+#######################################################################
+# headers/footers
+#######################################################################
+
+
+# header overridden for text pages
+_textheader_ {_cgihead_
+_htmlhead_
+<center>
+<table width=_pagewidth_><tr><td align=right>
+_javalinks_</td></tr></table>
+</center>
+}
+_textheader_ [v=1] {_cgihead_
+_htmlhead_
+_javalinks_
+}
+
+_footer_ {
+<p>
+_navarrows_
+</table>
+_endspacer__htmlfooter_
+}
Index: /main/tags/2.25/gsdl/macros/english.dm
===================================================================
--- /main/tags/2.25/gsdl/macros/english.dm	(revision 21064)
+++ /main/tags/2.25/gsdl/macros/english.dm	(revision 21064)
@@ -0,0 +1,1035 @@
+######################################################################
+#
+# English Language text and icon macros 
+#
+######################################################################
+#
+# This is the main macro file for translation when creating an 
+# interface in another language.
+#
+# Under the 'text macros' comments are text macros of the form:
+# _macroname_ {macro value}
+# Everything between the {} is the text to be translated. This text 
+# may itself contain macros (i.e. characters other than space between
+# underscore characters, e.g. _about:numdocs_ or _textpage_). These
+# macro names occurring within text shouldn't be translated but should
+# be left as they are. Underscores or curly brackets occurring 
+# naturally within the text should be escaped with a leading backslash
+# (i.e. '\_', '\{' or '\}).
+#
+# Under the 'icons' comments are macros concerned with displaying
+# icons which themselves contain text.
+# Above each macro (or group of macros) for an icon is a comment line
+# that looks something like '## "HOME" ## top_nav_button ## chome ##'.
+# The first field of the comment ("HOME" in this case) is the text
+# that appears in the english version of the icon. This is the text
+# that must be translated, nothing needs to be done to the macros 
+# themselves. The other two fields of the comments are used by 
+# automatic icon generating software which reads the newly translated
+# file and generates appropriate icons.
+#
+# Comment lines (other than those described above) need not be 
+# translated (i.e. any lines beginning with '#', like this line).
+#
+# The simplest way to translate this file is to save it as something
+# else (e.g. french.dm) and work through translating all the text
+# macro values and icon comments.
+#
+######################################################################
+
+
+######################################################################
+# Global (base) package
+package Global
+######################################################################
+
+
+#------------------------------------------------------------
+# text macros
+#------------------------------------------------------------
+
+_textdefaultcontent_ {The requested page could not be found. Please use
+your browsers 'back' button or the above home button to return to the
+Greenstone Digital Library.}
+
+_textdefaulttitle_ {GSDL Error}
+
+_collectionextra_ {This collection contains _about:numdocs_ documents. 
+It was last built _about:builddate_ days ago.}
+
+_textimagecollection_ {}
+_textimageabout_ {About page}
+_textimagehome_ {Home page}
+_textimagehelp_ {Help page}
+_textimagepref_ {Preferences page}
+_textimagegreenstone_ {Greenstone Digital Library Software}
+
+_textimagesearch_ {Search for specific terms}
+_textimageTitle_ {Browse alphabetical list of titles}
+_textimageList_ {Browse document listing}
+_textimageCreator_ {Browse alphabetical list of authors}
+_textimageSeries_ {Browse by issue}
+_textimageDate_ {Browse by date}
+_textimageSubject_ {Browse by subject category}
+_textimageTo_ {Browse by To field}
+_textimageFrom_ {Browse by From field}
+_textimageOrganization_ {Browse by organization}
+_textimageHowto_ {Browse how to categories}
+_textimageTopic_ {Browse special topic issues}
+_textimageBrowse_ {Browse}
+_textimagePeople_ {Browse alphabetical list of People}
+_textimageLanguage_ {Browse by language}
+_textimageAcronyms_ {Browse acronyms}
+
+_texticontabsearchgreen_{Search}
+_texticontabdategreen_{Dates}
+_texticontabseriesgreen_{Series}
+_texticontabauthorgreen_{Authors A-Z}
+_texticontabtitlegreen_{Titles A-Z}
+_texticontablistgreen_ {Listing}
+_texticontabsubjectgreen_{Subjects}
+_texticontabtogreen_{To}
+_texticontabfromgreen_{From}
+_texticontaborggreen_{Organization}
+_texticontabhowgreen_{How to}
+_texticontabtopicgreen_{Topics}
+_texticontabbrwsegreen_{Browse}
+_texticontabPeoplegreen_{People A-Z}
+_texticontabLanguagegreen_{Language}
+_texticontabAcronymsgreen_{Acronyms}
+
+_texticontext_ {View the document}
+_texticonclosedbook_ {open this document and view contents}
+_texticonnext_ {to next section}
+_texticonprev_ {to previous section}
+
+_page_ {page }
+_pages_ {pages}
+_of_ { of }
+_vol_ {Volume}
+_num_ {Number}
+
+_textmonth00_ {}
+_textmonth01_ {January}
+_textmonth02_ {February}
+_textmonth03_ {March}
+_textmonth04_ {April}
+_textmonth05_ {May}
+_textmonth06_ {June}
+_textmonth07_ {July}
+_textmonth08_ {August}
+_textmonth09_ {September}
+_textmonth10_ {October}
+_textmonth11_ {November}
+_textmonth12_ {December}
+
+_Document_ {Document}
+_Section_ {Section}
+_Paragraph_ {Paragraph}
+
+_magazines_ {Magazines}
+
+_nzdlpagefooter_ {<p>_iconblankbar_
+<p><a href="http://www.nzdl.org">New Zealand Digital Library Project</a>
+<br><a href="http://www.cs.waikato.ac.nz/cs">Department of Computer Science</a>, 
+<a href="http://www.waikato.ac.nz">University of Waikato</a>, 
+New Zealand}
+
+#------------------------------------------------------------
+# icons
+#------------------------------------------------------------
+
+## "HOME" ## top_nav_button ## chome ##
+_httpiconchomeof_ {_httpimg_/chomeof.gif}
+_httpiconchomeon_ {_httpimg_/chomeon.gif}
+_widthchomex_ {43}
+_heightchomex_ {20}
+
+## "HELP" ## top_nav_button ## chelp ##
+_httpiconchelpof_ {_httpimg_/chelpof.gif}
+_httpiconchelpon_ {_httpimg_/chelpon.gif}
+_widthchelpx_ {36}
+_heightchelpx_ {20}
+
+## "PREFERENCES" ## top_nav_button ## cpref ##
+_httpiconcprefof_ {_httpimg_/cprefof.gif}
+_httpiconcprefon_ {_httpimg_/cprefon.gif}
+_widthcprefx_ {87}
+_heightcprefx_ {20}
+
+## "help" ## green_title ## h_help ##
+_httpiconhhelp_ {_httpimg_/h\_help.gif}
+_widthhhelp_ {200}
+_heighthhelp_ {57}
+
+## "authors a-z" ## nav_bar_button ## tauth ##
+_httpicontauthgr_ {_httpimg_/tauthgr.gif}
+_httpicontauthof_ {_httpimg_/tauthof.gif}
+_httpicontauthon_ {_httpimg_/tauthon.gif}
+_widthtauthx_ {110}
+_heighttauthx_ {17}
+
+## "series" ## nav_bar_button ## tser ##
+_httpicontsergr_ {_httpimg_/tsergr.gif}
+_httpicontserof_ {_httpimg_/tserof.gif}
+_httpicontseron_ {_httpimg_/tseron.gif}
+_widthtserx_ {87}
+_heighttserx_ {17}
+
+## "dates" ## nav_bar_button ## tdate ##
+_httpicontdategr_ {_httpimg_/tdategr.gif}
+_httpicontdateof_ {_httpimg_/tdateof.gif}
+_httpicontdateon_ {_httpimg_/tdateon.gif}
+_widthtdatex_ {87}
+_heighttdatex_ {17}
+
+## "subjects" ## nav_bar_button ## tsubj ##
+_httpicontsubjgr_ {_httpimg_/tsubjgr.gif}
+_httpicontsubjon_ {_httpimg_/tsubjon.gif}
+_httpicontsubjof_ {_httpimg_/tsubjof.gif}
+_widthtsubjx_ {87}
+_heighttsubjx_ {17}
+
+## "to" ## nav_bar_button ## tto ##
+_httpiconttogr_ {_httpimg_/ttogr.gif}
+_httpiconttoon_ {_httpimg_/ttoon.gif}
+_httpiconttoof_ {_httpimg_/ttoof.gif}
+_widthttox_ {87}
+_heightttox_ {17}
+
+## "from" ## nav_bar_button ## tfrom ##
+_httpicontfromgr_ {_httpimg_/tfromgr.gif}
+_httpicontfromon_ {_httpimg_/tfromon.gif}
+_httpicontfromof_ {_httpimg_/tfromof.gif}
+_widthtfromx_ {87}
+_heighttfromx_ {17}
+
+## "organization" ## nav_bar_button ## torg ##
+_httpicontorggr_{_httpimg_/torggr.gif}
+_httpicontorgon_{_httpimg_/torgon.gif}
+_httpicontorgof_{_httpimg_/torgof.gif}
+_widthtorgx_ {109}
+_heighttorgx_ {17}
+
+## "how to" ## nav_bar_button ## thow ##
+_httpiconthowgr_{_httpimg_/thowgr.gif}
+_httpiconthowon_{_httpimg_/thowon.gif}
+_httpiconthowof_{_httpimg_/thowof.gif}
+_widththowx_ {87}
+_heightthowx_ {17}
+
+## "topic" ## nav_bar_button ## ttopic ##
+_httpiconttopicgr_{_httpimg_/ttopicgr.gif}
+_httpiconttopicon_{_httpimg_/ttopicon.gif}
+_httpiconttopicof_{_httpimg_/ttopicof.gif}
+_widthttopicx_ {87}
+_heightttopicx_ {17}
+
+## "browse" ## nav_bar_button ## tbrwse ##
+_httpicontbrwsegr_{_httpimg_/tbrwsegr.gif}
+_httpicontbrwseon_{_httpimg_/tbrwseon.gif}
+_httpicontbrwseof_{_httpimg_/tbrwseof.gif}
+_widthtbrwsex_ {87}
+_heighttbrwsex_ {17}
+
+## "search" ## nav_bar_button ## tsrch ##
+_httpicontsrchgr_ {_httpimg_/tsrchgr.gif}
+_httpicontsrchof_ {_httpimg_/tsrchof.gif}
+_httpicontsrchon_ {_httpimg_/tsrchon.gif}
+_widthtsrchx_ {87}
+_heighttsrchx_ {17}
+
+## "titles a-z" ## nav_bar_button ## ttitl ##
+_httpiconttitlgr_ {_httpimg_/ttitlgr.gif}
+_httpiconttitlof_ {_httpimg_/ttitlof.gif}
+_httpiconttitlon_ {_httpimg_/ttitlon.gif}
+_widthttitlx_ {87}
+_heightttitlx_ {17}
+
+## "people" ## nav_bar_button ## tpeop ##
+_httpicontpeopgr_ {_httpimg_/tpeopgr.gif}
+_httpicontpeopof_ {_httpimg_/tpeopof.gif}
+_httpicontpeopon_ {_httpimg_/tpeopon.gif}
+_widthtpeopx_ {97}
+_heighttpeopx_ {17}
+
+## "language" ## nav_bar_button ## tlang ##
+_httpicontlanggr_ {_httpimg_/tlanggr.gif}
+_httpicontlangon_ {_httpimg_/tlangon.gif}
+_httpicontlangof_ {_httpimg_/tlangof.gif}
+_widthtlangx_ {87}
+_heighttlangx_ {17}
+
+## "acronyms" ## nav_bar_button ## tacro ##
+_httpicontacrogr_ {_httpimg_/tacrogr.gif}
+_httpicontacroof_ {_httpimg_/tacroof.gif}
+_httpicontacroon_ {_httpimg_/tacroon.gif}
+_widthtacrox_ {97}
+_heighttacrox_ {17}
+
+
+
+
+
+######################################################################
+# 'about' page
+package about
+######################################################################
+
+
+#------------------------------------------------------------
+# text macros
+#------------------------------------------------------------
+
+_textabcol_ {About this collection}
+
+_textsubcols1_ {<p>The complete collection comprises _1_ subcollections:
+<blockquote>}
+
+_textsubcols2_ {</blockquote>
+You can check (and alter) which subcollections you are 
+currently using on the Preferences page.}
+
+
+#------------------------------------------------------------
+# icons
+#------------------------------------------------------------
+
+## "about" ## green_title ## h_about ##
+_httpiconhabout_ {_httpimg_/h\_about.gif}
+_widthhabout_ {200}
+_heighthabout_ {57}
+
+
+
+######################################################################
+# document package
+package document
+######################################################################
+
+
+#------------------------------------------------------------
+# text macros
+#------------------------------------------------------------
+
+_textTitlepage_ {_texticonhtitle_}
+_textCreatorpage_ {_texticonhauth_}
+_textSubjectpage_ {_texticonhsubj_}
+_textTopage_ {_texticonhto_}
+_textFrompage_ {_texticonhfrom_}
+_textSeriespage_ {_texticonhser_}
+_textDatepage_ {_texticonhdate_}
+_textHowtopage_ {_texticonhhow_}
+_textOrganizationpage_ {_texticonhorg_}
+_textBrowsepage_ {_texticonhbrwse_}
+_textPeoplepage_ {_texticonhpeople_}
+_textLanguagepage_ {_texticonhlanguage_}
+_textAcronymspage_ {_texticonhacronyms_}
+
+_texticonhtitle_ {Titles A-Z}
+_texticonhauth_ {Authors A-Z}
+_texticonhsubj_ {Subjects}
+_texticonhto_ {To}
+_texticonhfrom_ {From}
+_texticonhser_ {Series}
+_texticonhdate_ {Dates}
+_texticonhhow_ {How to}
+_texticonhorg_ {Organizations}
+_texticonhbrwse_ {Browse}
+_texticonhpeople_ {People A-Z}
+_texticonhlanguage_ {Languages}
+_texticonhacronyms_ {Acronyms}
+
+_texticonopenbookshelf_ {close this section of the library}
+_texticonclosedbookshelf_ {open this section of the library and view contents}
+_texticonopenbook_ {close this book}
+_texticonclosedfolder_ {Open this folder and view contents}
+_texticonclosedfolder2_ {open sub-section: }
+_texticonopenfolder_ {close this folder}
+_texticonopenfolder2_ {close sub-section: }
+_texticonsmalltext_ {View this section of the text}
+_texticonsmalltext2_ {view text: }
+_texticonpointer_ {current section}
+_texticondetach_ {Open this page in a new window}
+_texticonhighlight_ {Highlight search terms}
+_texticonnohighlight_ {Don't highlight search terms}
+_texticoncontracttoc_ {Collapse table of contents}
+_texticonexpandtoc_ {Expand table of contents}
+_texticonexpandtext_ {Display all text}
+_texticoncontracttext_ {Display text only for currently selected section}
+_texticonwarning_ {<b>Warning: </b>}
+_texticoncont_ {continue?}
+
+_textltwarning_ {
+<p><center>
+<table cellspacing=0 cellpadding=0 width=_pagewidth_>
+<tr valign=top><td>_iconwarning_Expanding the text here will generate a large 
+amount of data for your browser to display _imagecont_
+</td></tr></table></center>
+}
+
+_textgoto_ {go to page}
+_textintro_ { <i>(introductory text)</i>}
+
+
+#------------------------------------------------------------
+# icons
+#------------------------------------------------------------
+
+## "titles a-z" ## green_title ## h_title ##
+_httpiconhtitle_ {_httpimg_/h\_title.gif}
+_widthhtitle_ {200}
+_heighthtitle_ {57}
+
+## "authors a-z" ## green_title ## h_auth ##
+_httpiconhauth_ {_httpimg_/h\_auth.gif}
+_widthhauth_ {200}
+_heighthauth_ {57}
+
+## "subjects" ## green_title ## h_subj ##
+_httpiconhsubj_ {_httpimg_/h\_subj.gif}
+_widthhsubj_ {200}
+_heighthsubj_ {57}
+
+## "to" ## green_title ## h_to ##
+_httpiconhto_ {_httpimg_/h\_to.gif}
+_widthhto_ {200}
+_heighthto_ {57}
+
+## "from" ## green_title ## h_from ##
+_httpiconhfrom_ {_httpimg_/h\_from.gif}
+_widthhfrom_ {200}
+_heighthfrom_ {57}
+
+## "series" ## green_title ## h_ser ##
+_httpiconhser_ {_httpimg_/h\_ser.gif}
+_widthhser_ {200}
+_heighthser_ {57}
+
+## "dates" ## green_title ## h_date ##
+_httpiconhdate_ {_httpimg_/h\_date.gif}
+_widthhdate_ {200}
+_heighthdate_ {57}
+
+## "how to" ## green_title ## h_how ##
+_httpiconhhow_ {_httpimg_/h\_how.gif}
+_widthhhow_ {200}
+_heighthhow_ {57}
+
+## "topics" ## green_title ## h_topic ##
+_httpiconhtopic_ {_httpimg_/h\_topic.gif}
+_widthhtopic_ {200}
+_heighthtopic_ {57}
+
+## "organization" ## green_title ## h_org ##
+_httpiconhorg_ {_httpimg_/h\_org.gif}
+_widthhorg_ {250}
+_heighthorg_ {57}
+
+## "browse" ## green_title ## h_brwse ##
+_httpiconhbrwse_ {_httpimg_/h\_brwse.gif}
+_widthhbrwse_ {200}
+_heighthbrwse_ {57}
+
+## "people" ## green_title ## h_people ##
+_httpiconhpeople_ {_httpimg_/h\_people.gif}
+_widthhpeople_ {200}
+_heighthpeople_ {57}
+
+## "languages" ## green_title ## h_lang ##
+_httpiconhlanguage_ {_httpimg_/h\_lang.gif}
+_widthhlanguage_ {200}
+_heighthlanguage_ {57}
+
+## "acronyms" ## green_title ## h_acro ##
+_httpiconhacronyms_ {_httpimg_/h\_acro.gif}
+_widthhacronyms_ {200}
+_heighthacronyms_ {57}
+
+## "CONTINUE?" ## top_nav_button ## cont ##
+_httpiconcontoff_ {_httpimg_/contoff.gif}
+_httpiconconton_ {_httpimg_/conton.gif}
+_widthcontx_ {76}
+_heightcontx_ {17}
+
+## "EXPAND TEXT" ## document_button ## eallt ## 
+_httpiconealltof_ {_httpimg_/ealltof.gif}
+_httpiconeallton_ {_httpimg_/eallton.gif}
+_widthealltx_ {65}
+_heightealltx_ {30}
+
+## "CONTRACT CONTENTS" ## document_button ## econc ##
+_httpiconeconcof_ {_httpimg_/econcof.gif}
+_httpiconeconcon_ {_httpimg_/econcon.gif}
+_widtheconcx_ {65}
+_heighteconcx_ {30}
+
+## "DETACH" ## document_button ## edtch ##
+_httpiconedtchof_ {_httpimg_/edtchof.gif}
+_httpiconedtchon_ {_httpimg_/edtchon.gif}
+_widthedtchx_ {65}
+_heightedtchx_ {30}
+
+## "EXPAND CONTENTS" ## document_button ## eexpc ##
+_httpiconeexpcof_ {_httpimg_/eexpcof.gif}
+_httpiconeexpcon_ {_httpimg_/eexpcon.gif}
+_widtheexpcx_ {65}
+_heighteexpcx_ {30}
+
+## "CONTRACT TEXT" ## document_button ## etsec ##
+_httpiconetsecof_ {_httpimg_/etsecof.gif}
+_httpiconetsecon_ {_httpimg_/etsecon.gif}
+_widthetsecx_ {65}
+_heightetsecx_ {30}
+
+## "HIGHLIGHTING" ## document_button ## ehl ##
+_httpiconehlof_ {_httpimg_/ehlof.gif}
+_httpiconehlon_ {_httpimg_/ehlon.gif}
+_widthehlx_ {65}
+_heightehlx_ {30}
+
+## "NO HIGHLIGHTING" ## document_button ## enhl ##
+_httpiconenhlof_ {_httpimg_/enhlof.gif}
+_httpiconenhlon_ {_httpimg_/enhlon.gif}
+_widthenhlx_ {65}
+_heightenhlx_ {30}
+
+
+
+######################################################################
+# 'search' page
+package query
+######################################################################
+
+
+#------------------------------------------------------------
+# text macros
+#------------------------------------------------------------
+
+# this if statement produces the text 'results n1 - nn for query: querystring' or 
+# 'No matches for query: querystring', depending on whether or not there were
+# any matches
+_textquerytitle_ {_If_(_thislast_,results _thisfirst_ - _thislast_ for query: _cgiargq_,No matches for query: _cgiargq_)}
+_textnoquerytitle_ {Search page}
+
+_texticonthispage_ {search}
+_textsome_ {_If_(_cgiargb_,ranked,some)}
+_textall_ {_If_(_cgiargb_,boolean,all)}
+_texticonqueryresultsbar_ {}
+_textfreqmsg1_ {Word count: }
+_textpostprocess_ {_If_(_quotedquery_,<br><i>post-processed to find _quotedquery_</i>
+)}
+
+_textmorethan_ {More than }
+_textapprox_ {About }
+_textnodocs_ {No documents matched the query.}
+_text1doc_ {1 document matched the query.}
+_textlotsdocs_ {documents matched the query.}
+_textmatches_ {Matches }
+_textbeginsearch_ {Begin Search}
+
+# _hselection_, _jselection_ and _nselection_ are set from within the server
+# some or all of them may remain unset
+_textsimplesearch_ {Search for _If_(_hselection_, _hselection_)_If_(_jselection_,_textjselect_)_If_(_gselection_, at _gselection_ level)_If_(_nselection_, in _nselection_ language) 
+which contain _querytypeselection_ of the words}
+
+_textadvancedsearch_ {Search_If_(_hselection_, _hselection_, _defaultindextext_)_If_(_jselection_,_textjselect_)_If_(_gselection_, at _gselection_ level)_If_(_nselection_, in _nselection_ language) 
+using _querytypeselection_ query}
+
+_textjselect_ {_If_(_hselection_, of) _jselection_}
+
+_textstemon_ { (ignoring word endings)}
+_textclearhistory_ {Clear History}
+_textexpand_ {Expand}
+_textcontract_ {Contract}
+_textsearchhistory_ {Search History}
+_textquery_ {Query}
+_textresults_ {Results}
+_textview_ {View}
+_textnohistory_ {Search history not available}
+
+
+#------------------------------------------------------------
+# icons
+#------------------------------------------------------------
+
+## "search" ## green_title ## h_search ##
+_httpiconhsearch_ {_httpimg_/h\_search.gif}
+_widthhsearch_ {200}
+_heighthsearch_ {57}
+
+## "results" ## green_bar_left_aligned ## qryresb ##
+_httpiconqryresb_ {_httpimg_/qryresb.gif}
+_widthqryresb_ {_pagewidth_}
+_heightqryresb_ {17}
+
+## "display" ## hand_made ##
+_httpicondisplay_ {_httpimg_/display.gif}
+_widthdisplay_ {60}
+_heightdisplay_ {20}
+
+
+
+######################################################################
+# 'preferences' page
+package preferences
+######################################################################
+
+
+#------------------------------------------------------------
+# text macros
+#------------------------------------------------------------
+
+_textsearchprefs_ {Search preferences}
+_textcollectionprefs_ {Collection preferences}
+_textpresentationprefs_ {Presentation preferences}
+_textpreferences_ {Preferences}
+_textignorecase_ { ignore case differences}
+_textmatchcase_ { upper/lower case must match}
+_textstem_ { ignore word endings}
+_textnostem_ { whole word must match}
+_textprefop_ {Return up to _maxdocoption_ hits with _hitsperpageoption_ hits per page.}
+_textextlink_ {Access to external Web pages: }
+_textintlink_ {Source documents retrieved from:}
+_textlanguage_ {Interface language: }
+_textencoding_ {Encoding: }
+_textformat_ {Interface format: }
+_textall_ {all}
+_textsimplemode_ {simple query mode}
+_textadvancedmode_ {advanced query mode (allows boolean searching using !, &, |, and parentheses)}
+_textlinkinterm_ {through intermediate page}
+_textlinkdirect_ {go directly there}
+_textdigitlib_ {the digital library}
+_textweb_ {the web}
+_textlangeng_ {English}
+_textlanggerman_ {German}
+_textlangfrench_ {French}
+_textlangspanish_ {Spanish}
+_textlangmaori_ {M_amn_ori}
+_textlangchinese_ {Chinese}
+_textlangarabic_ {Arabic}
+_textgraphical_ {Graphical}
+_texttextual_ {Textual}
+_textcollectionoption_ {<p>
+Subcollections to include:
+<br>}
+_textfcoption_ {Include navigation bar at top of document pages}
+_texthloption_ {Highlight search terms within document text}
+_texthistorydisplay_ {display search history}
+
+
+#------------------------------------------------------------
+# icons
+#------------------------------------------------------------
+
+## "preferences" ## green_title ## h_pref ##
+_httpiconhpref_ {_httpimg_/h\_pref.gif}
+_widthhpref_ {200}
+_heighthpref_ {57}
+
+
+
+######################################################################
+# 'delete search history' page
+package delhistory
+######################################################################
+
+
+#------------------------------------------------------------
+# text macros
+#------------------------------------------------------------
+
+_textdsh_ {Delete Search History}
+
+_textselectdelete_ {<a href="_httpclearhistory_&hdh=1">Delete all
+records</a> or select records to <select name=hmode><option value=save>not
+delete<option value=delete selected>delete</select><br> Records can be
+selected by typing their numbers into the box,<br> or by clicking in the
+boxes in each record.<br> Acceptable values are 1,2,3-6,7- etc }
+
+_textclearselected_ {Clear selected}
+_textselect_ {select}
+
+
+#------------------------------------------------------------
+# icons
+#------------------------------------------------------------
+
+
+
+######################################################################
+# 'help' page -- this is lower priority for translating than the
+# rest of this file
+package help
+######################################################################
+
+
+#------------------------------------------------------------
+# text macros
+#------------------------------------------------------------
+
+_textHelp_ {Help}
+_textSearchshort_ {search for particular words}
+_textSeriesshort_ {access publications by series}
+_textDateshort_ {access publications by date}
+_textSubjectshort_ {access publications by subject}
+_textToshort_ {access publications by To field}
+_textFromshort_ {access publications by From field}
+_textTitleshort_ {access publications by title}
+_textBrowseshort_ {browse publications}
+_textCreatorshort_ {access publications by author}
+_textOrganizationshort_ {access publications by organization}
+_textHowtoshort_ {access publications by how to listing}
+_textTopicshort_ {access publications by topic}
+_textPeopleshort_ {access publications by people}
+_textLanguageshort_ {access publications by language}
+_textAcronymshort_ {access publications by acronym occurance}
+_textdefaultshorttext_ {undefined classification}
+
+_textSearchlong_ { <p>You can <i>search for particular words</i> that
+appear in the text from the "search" page. This is the first page that
+comes up when you begin, and can be reached from other pages by pressing
+the <i>search</i> button.  }
+
+_textTitlelong_ { <p>You can <i>access publications by title</i> by
+pressing the <i>titles a-z</i> button.  This brings up a list of books in
+alphabetic order.  }
+
+_textOrganizationlong_ { <p>You can <i>access publications by
+organization</i> by pressing the <i>organization</i> button.  This brings
+up a list of organizations.  }
+
+_textHowtolong_ { <p>You can <i>access publications by how to listing</i>
+by pressing the <i>how to</i> button.  This brings up a list of how to
+strings.  }
+
+_textCreatorlong_ { <p>You can <i>access publications by author</i> by
+pressing the <i>authors a-z</i> button.  This brings up a list of books,
+sorted by author name.  }
+
+_textTopiclong_ { <p>You can <i>access publications by topic</i> by
+pressing the <i>topic</i> button.  This brings up a list of topics to
+browse.  }
+
+_textSubjectlong_ { <p>You can <i>access publications by subject</i> by
+pressing the <i>subjects</i> button.  This brings up a list of subjects,
+represented by bookshelves.  }
+
+_textTolong_ { <p>You can <i>access publications by To field</i> by
+pressing the <i>to</i> button.  This brings up a list of addressees.  }
+
+_textFromlong_ { <p>You can <i>access publications by From field</i> by
+pressing the <i>from</i> button.  This brings up a list of senders.  }
+
+_textSerieslong_ { <p>You can <i>access publications by series</i> by
+pressing the <i>series</i> button.  This brings up a list of those series
+which are currently in the collection.  }
+
+_textDatelong_ { <p>You can <i>access publications by date</i> by pressing
+the <i>dates</i> button.  This brings up a list of all the issues, sorted
+chronologically.  }
+
+_textBrowselong_ { <p>You can <i>browse publications</i> by pressing the
+<i>browse</i> button.  }
+
+_textPeoplelong_ { <p>You can <i>access publications by people</i> by
+pressing the <i>people a-z</i> button.  This brings up a list of entries,
+sorted by surname.  }
+
+_textLanguagelong_ { <p>You can <i>access publications by language</i> by
+pressing the <i>languages</i> button.  This brings up a list of entries,
+sorted by language.  }
+
+_textAcronymslong_ { <p>You can <i>access publications by acronym occurance</i> by
+pressing the <i>acronyms</i> button.  This brings up a list of the acronyms,
+and the places that they occur.  }
+
+_textdefaultlongtext_ { <p>Click on the <i>unknown</i> button to browse
+publications (listing is sorted by an unknown field).  }
+
+_texthelptopics_ {
+<h2 align=left>Topics</h2>
+<ul>
+  <li><a href="\#finding-information">_textsimplehelpheading_</a>
+  _topicreadingdocs_
+  <li><a href="\#searching">How to search for particular words</a>
+<ul>
+  <li><a href="\#query-terms">Search terms</a>
+  <li><a href="\#query-type">Query type</a>
+  <li><a href="\#scope-of-queries">Scope of queries</a>
+</ul>
+  <li><a href="\#preferences">_textchangeprefs_</a>
+<ul>
+  <li><a href="\#col-prefs">Collection preferences</a>
+  <li><a href="\#pres-prefs">Presentation preferences</a>
+  <li><a href="\#search-prefs">Search preferences</a>
+</ul>
+</ul>
+}
+
+# there are 4 versions of this section of the help text.
+# which version is used is currently set within the server
+# (it should probably use the macro language e.g. [type=book])
+# 1 = html (like fao collections) -- section is empty
+# 2 = book (like hdl collection) -- macros beginning with book
+# 3 = bibliographic (like csbib) -- macros beginning with bib
+# 4 = standard (like gberg) -- the default
+
+_topicreadingdocs_ {<li><a href="\#reading-docs">_textreadingdocs_</a>}
+
+_textreadingdocs_ {How to read the documents}
+_booktextreadingdocs_ {How to read the books}
+_bibtextreadingdocs_ {Getting more information on a bibliography item}
+
+_texthelpreadingdocs_ {
+<p>_iconblankbar_
+<a name=reading-docs>
+<h2>_textreadingdocs_</h2>
+
+<p>You can tell when you have arrived at an individual document because its
+title and author appear at the top left of the page. Beside these is the
+number of the current page, a box that allows you to select a new page, and
+forward and backward arrows.
+
+<p>Underneath is the text of the current section. When you have read
+through it, there are arrows at the bottom to take you on to the next
+section or back to the previous one.
+
+<p>Below the title and author are three buttons. Click on <i>expand
+text</i> to expand out the whole text of the current document. If the
+document is large, this could take a long time and use a lot of memory!
+Click on <i>detach</i> to make a new browser window for this
+document. (This is useful if you want to compare documents, or read two at
+once.)  Finally, when you do a search the words you search for are
+highlighted.  Click on <i>no highlighting</i> to remove the highlighting.
+<p>
+<table cellspacing="0" cellpadding="2" border="0">
+<tr><td colspan=2><img src="_httpiconmore_" border="0"></td><td>Click on the arrow to go to the next section ...</td></tr>
+<tr><td colspan=2><img src="_httpiconless_" border="0"></td><td>... or back to the previous section</td></tr>
+<tr><td><img src="_document:httpiconealltof_" border="0"></td><td><img 
+src="_document:httpiconetsecof_" border="0"></td><td>Display all text, or not</td></tr>
+<tr><td colspan=2><img src="_document:httpiconedtchof_" border="0"></td><td>Open this page in a new window</td></tr>
+<tr><td><img src="_document:httpiconehlof_" border="0"></td><td><img
+src="_document:httpiconenhlof_" border="0"></td><td>Highlight search terms, or not</td></tr>
+</table>
+
+}
+
+_booktexthelpreadingdocs_ {
+<p>_iconblankbar_
+<a name=reading-docs>
+<h2>_textreadingdocs_</h2>
+
+<p>You can tell when you have arrived at an individual book because there
+is a photograph of its front cover at the top left of the page.  Beside the
+photograph is a table of contents with an arrow marking where you are.
+This table is expandable: click on the folders to open them or close them.
+Click on the open book at the top to close it.
+
+<p>Underneath is the text of the current section.  When you have read
+through it, there are arrows at the bottom to take you on to the next
+section or back to the previous one.
+
+<p>Below the photograph are four buttons. Click on <i>expand text</i> to
+expand out the whole text of the current section, or book.  If the book is
+large, this could take a long time and use a lot of memory! Click on
+<i>expand contents</i> to expand out the whole table of contents so that
+you can see the titles of all chapters and subsections. Click on
+<i>detach</i> to make a new browser window for this book.  (This is useful
+if you want to compare books, or read two at once.) Finally, when you do a
+search the words you search for are highlighted. Click on <i>no
+highlighting</i> to remove highlighting.
+
+<p>
+<table cellspacing="0" cellpadding="2" border="0">
+<tr><td colspan=2><img src="_httpiconbshelf_" border="0"></td><td>Open this bookshelf</td></tr>
+<tr><td><img src="_httpiconopenbook_" border="0"></td><td><img 
+src="_httpiconbook_" border="0"></td><td>Open/close this book</td></tr>
+<tr><td colspan=2><img src="_httpiconitext_" border="0"></td><td>View this section of the text</td></tr>
+<tr><td><img src="_document:httpiconealltof_" border="0"></td><td><img 
+src="_document:httpiconetsecof_" border="0"></td><td>Display all text, or not</td></tr>
+<tr><td><img src="_document:httpiconeexpcof_" border="0"></td><td><img
+src="_document:httpiconeconcof_" border="0"></td><td>Expand table of contents, or not</td></tr>
+<tr><td colspan=2><img src="_document:httpiconedtchof_" border="0"></td><td>Open this page in a new window</td></tr>
+<tr><td><img src="_document:httpiconehlof_" border="0"></td><td><img
+src="_document:httpiconenhlof_" border="0"></td><td>Highlight search terms, or not</td></tr>
+<tr><td colspan=2><img src="_httpiconmore_" border="0"></td><td>Click the arrow to go to the next section ...</td></tr>
+<tr><td colspan=2><img src="_httpiconless_" border="0"></td><td>... or back to the previous section</td></tr>
+</table>
+}
+
+_bibtexthelpreadingdocs_ {
+<p>_iconblankbar_
+<a name=reading-docs>
+<h2>_textreadingdocs_</h2>
+
+<p>Some bibliography items contain more information, such as an abstract.
+You can tell from the query response page if this is the case because they 
+are shown with the _icontext_ icon instead of the _iconblanktext_ icon.
+
+<p>Clicking on the _icontext_ icon will give you more information about the
+bibliography item.
+
+<p> Below the bibliography item are two buttons. Click on <i>detach</i> to 
+make a new browser window for this book. (This is useful if you want to compare
+bibliography items.) Finally, when you do a search the words you search for are 
+highlighted. Click on <i>no highlighting</i> to remove the highlighting.
+
+<p>
+<table cellspacing="0" cellpadding="2" border="0">
+<tr><td colspan=2><img src="_document:httpiconedtchof_" border="0"></td><td>Open this page in a new window</td></tr>
+<tr><td><img src="_document:httpiconehlof_" border="0"></td><td><img
+src="_document:httpiconenhlof_" border="0"></td><td>Highlight search terms, or not</td></tr>
+</table>
+}
+
+_texthelpsearching_ {
+<h2>How to search for particular words</h2>
+<p>
+  From the search page, you make a query in these simple steps:<p>
+  
+  <ol><li>Specify what documents you want to search
+      <li>Say whether you want to search for all or just some of the words
+      <li>Type in the words you want to search for
+      <li>Click the <i>Begin Search</i> button
+  </ol>
+
+<p>When you make a query, the titles of twenty matching documents will be shown.
+There is a button at the end to take you on to the next twenty documents.  From
+there you will find buttons to take you on to the third twenty or back to the
+first twenty, and so on.  Click the title of any document, or the little button
+beside it, to see it.
+
+<p>A maximum of 100 is imposed on the number of
+  documents returned.  You can change this number by clicking the
+  <i>preferences</i> button at the top of the page.<p>
+
+<p>_iconblankbar_
+<a name=query-terms>
+<h3>Search terms</h3>
+
+<p>Whatever you type into the query box is interpreted as a list of words
+called "search terms."  Each term contains nothing but alphabetic characters
+and digits.  Terms are separated by white space.  If any other characters such
+as punctuation appear, they serve to separate terms just as though they were
+spaces.  And then they are ignored.  You can't search for words that include
+punctuation.
+
+<p>For example, the query<p>
+    <ul><kbd>Agro-forestry in the Pacific Islands: Systems for Sustainability (1993)</kbd></ul>
+      <p>will be treated the same as<p>
+      <ul><kbd>Agro forestry in the Pacific Islands  Systems for Sustainability  1993 </kbd></ul><p>
+
+<p>_iconblankbar_
+<a name=query-type>
+<h3>Query type</h3>
+
+<p>There are two different kinds of query.
+
+<ul>
+  <li>Queries for <b>all</b> of the words.  These look for documents that 
+      contain all the words you have specified.  Documents that satisfy the
+      query are displayed, in alphabetical order.<p>
+
+  <li>Queries for <b>some</b> of the words.  Just list some terms that are
+      likely to appear in the documents you are looking for.  Documents are
+      displayed in order of how closely they match the query.  When determining
+
+      the degree of match,
+
+      <p><ul>
+        <li> the more search terms a document contains, the closer it matches;
+        <li> rare terms are more important than common ones;
+        <li> short documents match better than long ones.
+      </ul>
+</ul>
+
+<p>Use as many search terms as you like--a whole sentence, or even a
+whole paragraph.  If you specify only
+one term, documents will be ordered by its frequency of occurrence.<p>
+_texthelpscope_
+}
+
+_textchangeprefs_ {Changing your preferences}
+
+_texthelppreferences_ {<h2>_textchangeprefs_</h2>
+
+<p>When you click the <i>preferences</i> button at the top of the page you will
+be able to change some features of the interface to suit your own requirements.
+
+<p>_iconblankbar_
+<a name=col-prefs>
+<h3 align=left>Collection preferences</h3>
+
+Some collections comprise several subcollections, which can be searched
+independently or together, as one unit.  If so, you can select which
+subcollections to include in your searches on the Preferences page.
+
+<p>_iconblankbar_
+<a name=pres-prefs>
+<h3 align=left>Presentation preferences</h3>
+
+Depending on the particular collection, there may be several options you can
+set that control the presentation.
+
+Collections of Web pages allow you to suppress the Greenstone navigation bar at
+the top of each document page, so that once you have done a search you land at
+the exact Web page that matches without any Greenstone header.  To do another
+search you will have to use your browser's "back" button.  These collections
+also allow you to suppress Greenstone's warning message when you click a link
+that takes you out of the digital library collection and on to the Web itself.
+And in some Web collections you can control whether the links on the "Search
+Results" page take you straight to the actual URL in question, rather than to
+the digital library's copy of the page.
+
+Collections that are capable of being presented in different languages allow
+you to specify the interface language.  If the language is Chinese, you can
+also specify which of the standard Chinese encodings your browser uses.
+
+Finally, all collections allow you to switch to a textual interface format
+rather than the standard graphical one.  This is particularly useful for
+visually impaired users who use large screen fonts or speech synthesizers for
+output.
+
+<p>_iconblankbar_
+<a name=search-prefs>
+<h3 align=left>Search preferences</h3>
+Two pairs of buttons control the case sensitivity and stemming of the searches
+that you make. The first set of buttons controls whether upper and lower case
+must match (case sensitivity).  The second set controls whether to ignore word
+endings or not (stemming).
+
+<p>For example, if the buttons <i>ignore case differences</i> and
+<i>ignore word endings</i> are selected, the query<p>
+    <ul><kbd>African building</kbd></ul>
+      <p>will be treated the same as<p>
+      <ul><kbd>africa builds</kbd></ul><p>
+      because the uppercase letter in "African" will be transformed to
+      lowercase, and  the suffixes "n" and "ing" will be removed from
+      "African" and "building" respectively (also, "s" would be removed from
+      "builds").
+
+<p>You can also switch to an "advanced" query mode which allows you to
+combine terms using AND (&), OR (|), and NOT (!). This allows you to
+specify more precise queries.
+
+<p>Finally, you can control the number of hits returned, and the number
+presented on each screenful.
+
+}
+
+_texttanumbrowseoptions_ {There are _numbrowseoptions_ ways to find information in this collection:}
+
+_textsimplehelpheading_ {How to find information}
+
+_texthelpscope_ {
+<p>_iconblankbar_
+<a name=scope-of-queries>
+<h3 align=left>Scope of queries</h3>
+
+<p>
+In most collections you can choose different indexes to search. For example, there might
+be author or title indexes. Or there might be chapter or paragraph indexes. Generally,
+the full matching document is returned regardless of which index you search.
+<p>If documents are books, they will be opened at the appropriate place.
+}
Index: /main/tags/2.25/gsdl/macros/english2.dm
===================================================================
--- /main/tags/2.25/gsdl/macros/english2.dm	(revision 21064)
+++ /main/tags/2.25/gsdl/macros/english2.dm	(revision 21064)
@@ -0,0 +1,164 @@
+######################################################################
+#
+# English Language text and icon macros 
+# -- this file contains english text that is of less importance
+# -- to translate when creating a new interface language
+######################################################################
+
+
+
+######################################################################
+# 'home' page
+package home
+######################################################################
+
+
+#------------------------------------------------------------
+# text macros
+#------------------------------------------------------------
+
+_documents_ { documents. }
+_lastupdate_ {Last updated}
+_ago_ {days ago.}
+_colnotbuilt_ {Collection not built.}
+
+_textpagetitle_ {Greenstone Digital Library}
+_textfb_ {Feedback}
+_textinfosheet_ {Info Sheet}
+
+_textprojhead_ {The Greenstone software and <br>The New Zealand Digital Library Project}
+_textprojinfo_ {
+<p>
+The Greenstone Digital Library software provides a new way of
+organizing information and making it available over the Internet or on
+CD-ROM. It is open-source software, available under the terms of the
+GNU General Public License. 
+<p>
+A digital library is made up of a set of collections. Each collection of
+information comprises several (typically several thousand, or even
+several million) documents, which share a uniform searching and
+browsing interface. Collections can be organized in many different
+ways while retaining a strong family resemblance. 
+<p>
+The 
+<a href="http://www.nzdl.org">New Zealand Digital Library Project</a>
+is a research programme at The University of Waikato whose aim is to 
+develop the underlying technology for digital libraries and make it 
+available publicly so that others can use it to create their own 
+collections.
+Greenstone was created to further this objective.
+Further details are available from  
+<a href="http://www.nzdl.org">http://www.nzdl.org</a>
+}
+
+_textpoem_ {
+<br><h2>Kia papapounamu te moana</h2>
+
+<p>kia hora te marino,
+<br>kia tere te karohirohi,
+<br>kia papapounamu te moana
+
+<p>may peace and calmness surround you,
+<br>may you reside in the warmth of a summer's haze,
+<br>may the ocean of your travels be as smooth as the polished greenstone.
+}
+
+_textgreenstone_ { 
+<p>Greenstone is a semi-precious stone that (like this software) is sourced in New Zealand.  In traditional Maori society it was the most highly prized and sought after of all substances.  It can absorb and hold <i>wairua</i>, which is a spirit or life force, and is endowed with traditional virtues that make it an appropriate emblem for a
+public-domain digital library project.  Its lustre shows charity; its
+translucence, honesty; its toughness, courage; and the sharp edge it can
+take, justice.  The carved piece used in the Greenstone Digital Library
+Software logo is a <i>patu</i> or fighting club, and is a family heirloom
+of one of our project members.  In hand-to-hand combat its delivery is very
+quick, very accurate, and very complete.  We like to think these qualities
+also apply to our software, the razor sharp edge of the <i>patu</i>
+symbolizing the leading edge of technology.
+
+}
+
+
+#------------------------------------------------------------
+# icons
+#------------------------------------------------------------
+
+## "THE NEW ZEALAND DIGITAL LIBRARY" ## nzdl_heading ## nzdl2gr ##
+_httpiconnzdl_ {_httpimg_/nzdl2gr.gif}
+_widthnzdl_ {457}
+_heightnzdl_ {181}
+
+## "select a collection" ## green_bar_left_aligned ## selcolgr ##
+_httpiconselcolgr_ {_httpimg_/selcolgr.gif}
+_widthselcolgr_ {537}
+_heightselcolgr_ {17}
+_altselcolgr_ {"Select a collection"}
+
+
+
+######################################################################
+# external link package
+package extlink
+######################################################################
+
+
+#------------------------------------------------------------
+# text macros
+#------------------------------------------------------------
+
+_textextlink_ {External Link}
+_textlinknotfound_{Internal Link not Found}
+
+_textextlinkcontent_ {The link you have selected is external to any of your currently selected collections.
+    If you still wish to view this link and your browser has access to 
+    the Web, you can <a href="_nexturl_">go forward</a> to this page; otherwise 
+    use your browsers "back" button to return to the previous document.}
+
+_textlinknotfoundcontent_ {For reasons beyond our control, the internal link you have selected 
+    does not exist.  This is probably due to an error in the source collection.
+    Use your browsers "back" button to return to the previous document.}
+
+# should have arguments of collection, collectionname and link
+_foundintcontent_ {
+
+<h3>Link to "_2_" collection</h3>
+
+<p> The link you have selected is external to the "_collectionname_"
+    collection (it links to the "_2_" collection).
+    If you wish to view this link in the "_2_" collection you can 
+    <a href="_httpdoc_&c=_1_&cl=_cgiargcl_&d=_3_">go forward</a> to this page; 
+    otherwise use your browsers "back" button to return to the previous document.
+}
+
+
+#------------------------------------------------------------
+# icons
+#------------------------------------------------------------
+
+
+
+######################################################################
+# authentication page
+package authen
+######################################################################
+
+
+#------------------------------------------------------------
+# text macros
+#------------------------------------------------------------
+
+_textGSDLtitle_ {Greenstone Digital Library}
+
+_textusername_ {username}
+_textpassword_ {password}
+
+_textmessageinvalid_ {The page you have requested requires you to sign in.
+Please enter your username and password.}
+
+_textmessagefailed_ {Either your user name or password was incorrect.}
+
+_textmessagedisabled_ {Sorry, your account has been disabled. Please contact
+the webmaster for this site.}
+
+_textmessagepermissiondenied_ {Sorry, you do not have permission to access this page.}
+
+_textmessagestalekey_ {The link you have followed is now stale. 
+Please enter your password to access this page.}
Index: /main/tags/2.25/gsdl/macros/extlink.dm
===================================================================
--- /main/tags/2.25/gsdl/macros/extlink.dm	(revision 21064)
+++ /main/tags/2.25/gsdl/macros/extlink.dm	(revision 21064)
@@ -0,0 +1,17 @@
+package extlink
+
+_header_ {_htmlhead_}
+
+_foundcontent_ {
+
+<h3>_textextlink_</h3>
+
+<p> _textextlinkcontent_
+}
+
+_notfoundcontent_ {
+
+<h3>_textlinknotfound_</h3>
+
+<p> _textlinknotfoundcontent_
+}
Index: /main/tags/2.25/gsdl/macros/french.dm
===================================================================
--- /main/tags/2.25/gsdl/macros/french.dm	(revision 21064)
+++ /main/tags/2.25/gsdl/macros/french.dm	(revision 21064)
@@ -0,0 +1,904 @@
+######################################################################
+# Global (base) package
+package Global
+######################################################################
+
+
+#------------------------------------------------------------
+# text macros
+#------------------------------------------------------------
+
+_textdefaultcontent_ [l=fr] {La page demandee n'a pu etre trouvee. Utilisez s'il vous plait
+le bouton 'retour' de votre navigateur ou le bouton 'principale' pour retourner
+a la Bibliotheque Numerique Greenstone.}
+
+_textdefaulttitle_ [l=fr] {Erreur GSDL}
+
+_collectionextra_ [l=fr] {Cette collection contient _about:numdocs_ documents.
+Sa derniere mise a jour a etait faite il y a _about:builddate_ jours.}
+
+_textimagecollection_ [l=fr] {}
+_textimageabout_ [l=fr] {Page a propos}
+_textimagehome_ [l=fr] {Page principale}
+_textimagehelp_ [l=fr] {Page d'aide}
+_textimagepref_ [l=fr] {Page de preferences}
+_textimagegreenstone_ [l=fr] {Logiciel de la Bibliotheque Numerique Greenstone}
+
+_textimagesearch_ [l=fr] {Recherche de termes specifiques}
+_textimageTitle_ [l=fr] {Naviguer a travers la liste alphabetique des titres}
+_textimageList_ [l=fr] {Naviguer a travers la liste des documents}
+_textimageCreator_ [l=fr] {Naviguer a travers la liste alphabetique des auteurs}
+_textimageSeries_ [l=fr] {Naviguer utilisant les numero}
+_textimageDate_ [l=fr] {Naviguer utilisant les dates}
+_textimageSubject_ [l=fr] {Naviguer par categorie de sujet}
+_textimageOrganization_ [l=fr] {Naviguer par organisation}
+_textimageHowto_ [l=fr] {Naviguer utilisant les categories comment faire}
+_textimageTopic_ [l=fr] {Naviguer utilisant les editions speciales a theme}
+_textimageBrowse_ [l=fr] {Naviguer}
+_textimagePeople_ [l=fr] {Naviguer par liste alphabetique de personnes}
+
+_texticontabsearchgreen_ [l=fr] {Rechercher}
+_texticontabdategreen_ [l=fr] {Dates}
+_texticontabseriesgreen_ [l=fr] {Series}
+_texticontabauthorgreen_ [l=fr] {Auteurs A-Z}
+_texticontabtitlegreen_ [l=fr] {Titres A-Z}
+_texticontablistgreen_ [l=fr] {Listing}
+_texticontabsubjectgreen_ [l=fr] {Sujets}
+_texticontaborggreen_ [l=fr] {Organisation}
+_texticontabhowgreen_ [l=fr] {Comment faire}
+_texticontabtopicgreen_ [l=fr] {Themes}
+_texticontabbrwsegreen_ [l=fr] {Naviguer}
+_texticontabPeoplegreen_ [l=fr] {Personnes A-Z}
+
+_texticontext_ [l=fr] {Voir le document}
+_texticonclosedbook_ [l=fr] {ouvrir ce document et voir son contenu}
+_texticonnext_ [l=fr] {vers la section suivante}
+_texticonprev_ [l=fr] {vers la section precedente}
+
+_page_ [l=fr] {page }
+_pages_ [l=fr] {pages}
+_of_ [l=fr] { de }
+_vol_ [l=fr] {Volume}
+_num_ [l=fr] {Nombre}
+
+_textmonth00_ [l=fr] {}
+_textmonth01_ [l=fr] {Janvier}
+_textmonth02_ [l=fr] {Fevrier}
+_textmonth03_ [l=fr] {Mars}
+_textmonth04_ [l=fr] {Avril}
+_textmonth05_ [l=fr] {Mai}
+_textmonth06_ [l=fr] {Juin}
+_textmonth07_ [l=fr] {Juillet}
+_textmonth08_ [l=fr] {Aout}
+_textmonth09_ [l=fr] {Septembre}
+_textmonth10_ [l=fr] {Octobre}
+_textmonth11_ [l=fr] {Novembre}
+_textmonth12_ [l=fr] {Decembre}
+
+_magazines_ [l=fr] {Magazines}
+
+
+#------------------------------------------------------------
+# icons
+#------------------------------------------------------------
+
+## "PRINCIPALE" ## top_nav_button ## chome ##
+_httpiconchomeof_ [l=fr] {_httpimg_/fr/chomeof.gif}
+_httpiconchomeon_ [l=fr] {_httpimg_/fr/chomeon.gif}
+_widthchomex_ [l=fr] {72}
+_heightchomex_ [l=fr] {20}
+
+## "AIDE" ## top_nav_button ## chelp ##
+_httpiconchelpof_ [l=fr] {_httpimg_/fr/chelpof.gif}
+_httpiconchelpon_ [l=fr] {_httpimg_/fr/chelpon.gif}
+_widthchelpx_ [l=fr] {32}
+_heightchelpx_ [l=fr] {20}
+
+## "PREFERENCES" ## top_nav_button ## cpref ##
+_httpiconcprefof_ [l=fr] {_httpimg_/fr/cprefof.gif}
+_httpiconcprefon_ [l=fr] {_httpimg_/fr/cprefon.gif}
+_widthcprefx_ [l=fr] {83}
+_heightcprefx_ [l=fr] {20}
+
+## "aide" ## green_title ## h_help ##
+_httpiconhhelp_ [l=fr] {_httpimg_/fr/h\_help.gif}
+_widthhhelp_ [l=fr] {200}
+_heighthhelp_ [l=fr] {57}
+
+## "auteurs a-z" ## nav_bar_button ## tauth ##
+_httpicontauthgr_ [l=fr] {_httpimg_/fr/tauthgr.gif}
+_httpicontauthof_ [l=fr] {_httpimg_/fr/tauthof.gif}
+_httpicontauthon_ [l=fr] {_httpimg_/fr/tauthon.gif}
+_widthtauthx_ [l=fr] {100}
+_heighttauthx_ [l=fr] {17}
+
+## "series" ## nav_bar_button ## tser ##
+_httpicontsergr_ [l=fr] {_httpimg_/fr/tsergr.gif}
+_httpicontserof_ [l=fr] {_httpimg_/fr/tserof.gif}
+_httpicontseron_ [l=fr] {_httpimg_/fr/tseron.gif}
+_widthtserx_ [l=fr] {87}
+_heighttserx_ [l=fr] {17}
+
+## "dates" ## nav_bar_button ## tdate ##
+_httpicontdategr_ [l=fr] {_httpimg_/fr/tdategr.gif}
+_httpicontdateof_ [l=fr] {_httpimg_/fr/tdateof.gif}
+_httpicontdateon_ [l=fr] {_httpimg_/fr/tdateon.gif}
+_widthtdatex_ [l=fr] {87}
+_heighttdatex_ [l=fr] {17}
+
+## "sujets" ## nav_bar_button ## tsubj ##
+_httpicontsubjgr_ [l=fr] {_httpimg_/fr/tsubjgr.gif}
+_httpicontsubjon_ [l=fr] {_httpimg_/fr/tsubjon.gif}
+_httpicontsubjof_ [l=fr] {_httpimg_/fr/tsubjof.gif}
+_widthtsubjx_ [l=fr] {87}
+_heighttsubjx_ [l=fr] {17}
+
+## "organisation" ## nav_bar_button ## torg ##
+_httpicontorggr_ [l=fr] {_httpimg_/fr/torggr.gif}
+_httpicontorgon_ [l=fr] {_httpimg_/fr/torgon.gif}
+_httpicontorgof_ [l=fr] {_httpimg_/fr/torgof.gif}
+_widthtorgx_ [l=fr] {105}
+_heighttorgx_ [l=fr] {17}
+
+## "comment faire" ## nav_bar_button ## thow ##
+_httpiconthowgr_ [l=fr] {_httpimg_/fr/thowgr.gif}
+_httpiconthowon_ [l=fr] {_httpimg_/fr/thowon.gif}
+_httpiconthowof_ [l=fr] {_httpimg_/fr/thowof.gif}
+_widththowx_ [l=fr] {122}
+_heightthowx_ [l=fr] {17}
+
+## "theme" ## nav_bar_button ## ttopic ##
+_httpiconttopicgr_ [l=fr] {_httpimg_/fr/ttopicgr.gif}
+_httpiconttopicon_ [l=fr] {_httpimg_/fr/ttopicon.gif}
+_httpiconttopicof_ [l=fr] {_httpimg_/fr/ttopicof.gif}
+_widthttopicx_ [l=fr] {87}
+_heightttopicx_ [l=fr] {17}
+
+## "naviguer" ## nav_bar_button ## tbrwse ##
+_httpicontbrwsegr_ [l=fr] {_httpimg_/fr/tbrwsegr.gif}
+_httpicontbrwseon_ [l=fr] {_httpimg_/fr/tbrwseon.gif}
+_httpicontbrwseof_ [l=fr] {_httpimg_/fr/tbrwseof.gif}
+_widthtbrwsex_ [l=fr] {87}
+_heighttbrwsex_ [l=fr] {17}
+
+## "rechercher" ## nav_bar_button ## tsrch ##
+_httpicontsrchgr_ [l=fr] {_httpimg_/fr/tsrchgr.gif}
+_httpicontsrchof_ [l=fr] {_httpimg_/fr/tsrchof.gif}
+_httpicontsrchon_ [l=fr] {_httpimg_/fr/tsrchon.gif}
+_widthtsrchx_ [l=fr] {90}
+_heighttsrchx_ [l=fr] {17}
+
+## "titres a-z" ## nav_bar_button ## ttitl ##
+_httpiconttitlgr_ [l=fr] {_httpimg_/fr/ttitlgr.gif}
+_httpiconttitlof_ [l=fr] {_httpimg_/fr/ttitlof.gif}
+_httpiconttitlon_ [l=fr] {_httpimg_/fr/ttitlon.gif}
+_widthttitlx_ [l=fr] {87}
+_heightttitlx_ [l=fr] {17}
+
+## "personnes" ## nav_bar_button ## tpeop ##
+_httpicontpeopgr_ [l=fr] {_httpimg/tpeopgr.gif}
+_httpicontpeopof_ [l=fr] {_httpimg/tpeopof.gif}
+_httpicontpeopon_ [l=fr] {_httpimg/tpeopon.gif}
+_widthtpeopx_ [l=fr] {87}
+_heighttpeopx_ [l=fr] {17}
+
+
+
+######################################################################
+# 'about' page
+package about
+######################################################################
+
+
+#------------------------------------------------------------
+# text macros
+#------------------------------------------------------------
+
+_textabcol_ [l=fr] {A propos de cette collection}
+
+_textsubcols1_ [l=fr] {<p>La collection comprents _1_ sous-collections au total:
+<blockquote>}
+
+_textsubcols2_ [l=fr] {</blockquote>
+Vous pouvez verifier (et modifier) la collection que vous
+utilisez courament en utilisant la page des preferences.}
+
+
+#------------------------------------------------------------
+# icons
+#------------------------------------------------------------
+
+## "about" ## green_title ## h_about ##
+_httpiconhabout_ [l=fr] {_httpimg_/fr/h\_about.gif}
+_widthhabout_ [l=fr] {200}
+_heighthabout_ [l=fr] {57}
+
+
+
+######################################################################
+# document package
+package document
+######################################################################
+
+
+#------------------------------------------------------------
+# text macros
+#------------------------------------------------------------
+
+_textTitlepage_ [l=fr] {_texticonhtitle_}
+_textCreatorpage_ [l=fr] {_texticonhauth_}
+_textSubjectpage_ [l=fr] {_texticonhsubj_}
+_textSeriespage_ [l=fr] {_texticonhser_}
+_textDatepage_ [l=fr] {_texticonhdate_}
+_textHowtopage_ [l=fr] {_texticonhhow_}
+_textOrganizationpage_ [l=fr] {_texticonhorg_}
+_textBrowsepage_ [l=fr] {_texticonhbrwse_}
+_textPeoplepage_ [l=fr] {_texticonhpeople_}
+
+_texticonhtitle_ [l=fr] {Titres A-Z}
+_texticonhauth_ [l=fr] {Auteurs A-Z}
+_texticonhsubj_ [l=fr] {Sujets}
+_texticonhser_ [l=fr] {Series}
+_texticonhdate_ [l=fr] {Dates}
+_texticonhhow_ [l=fr] {Comment faire}
+_texticonhorg_ [l=fr] {Organisations}
+_texticonhbrwse_ [l=fr] {Naviguer}
+_texticonhpeople_ [l=fr] {Personnes A-Z}
+
+_texticonopenbookshelf_ [l=fr] {fermer cette section de la bibliotheque}
+_texticonclosedbookshelf_ [l=fr] {ouvrir cette section de la bibliotheque et voir son contenu}
+_texticonopenbook_ [l=fr] {fermer ce livre}
+_texticonclosedfolder_ [l=fr] {Ouvrir ce repertoire et voir son contenu}
+_texticonclosedfolder2_ [l=fr] {ouvrir sous-section: }
+_texticonopenfolder_ [l=fr] {fermer ce repertoitre}
+_texticonopenfolder2_ [l=fr] {fermer sous-section: }
+_texticonsmalltext_ [l=fr] {Voir cette portion de texte}
+_texticonsmalltext2_ [l=fr] {voir texte: }
+_texticonpointer_ [l=fr] {section courante}
+_texticondetach_ [l=fr] {Ouvrir cette page dans une nouvelle fenetre}
+_texticonhighlight_ [l=fr] {Mettre en evidence les termes de recherche}
+_texticonnohighlight_ [l=fr] {Ne pas mettre en evidence les termes de recherche}
+_texticoncontracttoc_ [l=fr] {Reduire la table des matieres}
+_texticonexpandtoc_ [l=fr] {Etendre la table des matieres}
+_texticonexpandtext_ [l=fr] {Display all text}
+_texticoncontracttext_ [l=fr] {Display text only for currently selected section}
+_texticonwarning_ [l=fr] {<b>Attention: </b>}
+_texticoncont_ [l=fr] {continue?}
+
+_textltwarning_ [l=fr] {
+<p><center>
+<table cellspacing=0 cellpadding=0 width=_pagewidth_>
+<tr valign=top><td>_iconwarning_Etendre le texte 
+a ce niveau generera une importante quantite d'informations 
+a traiter par votre navigateur _imagecont_
+</td></tr></table></center>
+}
+
+_textgoto_ [l=fr] {aller a la page}
+_textintro_ [l=fr] { <i>(texte d'introduction)</i>}
+
+
+#------------------------------------------------------------
+# icons
+#------------------------------------------------------------
+
+## "titres a-z" ## green_title ## h_title ##
+_httpiconhtitle_ [l=fr] {_httpimg_/fr/h\_title.gif}
+_widthhtitle_ [l=fr] {200}
+_heighthtitle_ [l=fr] {57}
+
+## "auteurs a-z" ## green_title ## h_auth ##
+_httpiconhauth_ [l=fr] {_httpimg_/fr/h\_auth.gif}
+_widthhauth_ [l=fr] {200}
+
+## "sujets" ## green_title ## h_subj ##
+_httpiconhsubj_ [l=fr] {_httpimg_/fr/h\_subj.gif}
+_widthhsubj_ [l=fr] {200}
+_heighthsubj_ [l=fr] {57}
+
+## "series" ## green_title ## h_ser ##
+_httpiconhser_ [l=fr] {_httpimg_/fr/h\_ser.gif}
+_widthhser_ [l=fr] {200}
+_heighthser_ [l=fr] {57}
+
+## "dates" ## green_title ## h_date ##
+_httpiconhdate_ [l=fr] {_httpimg_/fr/h\_date.gif}
+_widthhdate_ [l=fr] {200}
+_heighthdate_ [l=fr] {57}
+
+## "comment faire" ## green_title ## h_how ##
+_httpiconhhow_ [l=fr] {_httpimg_/fr/h\_how.gif}
+_widthhhow_ [l=fr] {200}
+_heighthhow_ [l=fr] {57}
+
+## "themes" ## green_title ## h_topic ##
+_httpiconhtopic_ [l=fr] {_httpimg_/fr/h\_topic.gif}
+_widthhtopic_ [l=fr] {200}
+_heighthtopic_ [l=fr] {57}
+
+## "organisation" ## green_title ## h_org ##
+_httpiconhorg_ [l=fr] {_httpimg_/fr/h\_org.gif}
+_widthhorg_ [l=fr] {250}
+_heighthorg_ [l=fr] {57}
+
+## "naviguer" ## green_title ## h_brwse ##
+_httpiconhbrwse_ [l=fr] {_httpimg_/fr/h\_brwse.gif}
+_widthhbrwse_ [l=fr] {200}
+_heighthbrwse_ [l=fr] {57}
+
+## "personnes" ## green_title ## h_people ##
+_httpiconhpeople_ [l=fr] {_httpimg_/fr/h\_people.gif}
+_widthhpeople_ [l=fr] {200}
+_heighthpeople_ [l=fr] {57}
+
+## "CONTINUE?" ## top_nav_button ## cont ##
+_httpiconcontoff_ [l=fr] {_httpimg_/fr/contoff.gif}
+_httpiconconton_ [l=fr] {_httpimg_/fr/conton.gif}
+_widthcontx_ [l=fr] {72}
+_heightcontx_ [l=fr] {17}
+
+## "ETENDRE LE TEXTE" ## document_button ## eallt ## 
+_httpiconealltof_ [l=fr] {_httpimg_/fr/ealltof.gif}
+_httpiconeallton_ [l=fr] {_httpimg_/fr/eallton.gif}
+_widthealltx_ [l=fr] {92}
+_heightealltx_ [l=fr] {30}
+
+## "CONTRACT CONTENTS" ## document_button ## econc ##
+_httpiconeconcof_ [l=fr] {_httpimg_/fr/econcof.gif}
+_httpiconeconcon_ [l=fr] {_httpimg_/fr/econcon.gif}
+_widtheconcx_ [l=fr] {113}
+_heighteconcx_ [l=fr] {30}
+
+## "DETACH" ## document_button ## edtch ##
+_httpiconedtchof_ [l=fr] {_httpimg_/fr/edtchof.gif}
+_httpiconedtchon_ [l=fr] {_httpimg_/fr/edtchon.gif}
+_widthedtchx_ [l=fr] {65}
+_heightedtchx_ [l=fr] {30}
+
+## "ETENDRE LE CONTENU" ## document_button ## eexpc ##
+_httpiconeexpcof_ [l=fr] {_httpimg_/fr/eexpcof.gif}
+_httpiconeexpcon_ [l=fr] {_httpimg_/fr/eexpcon.gif}
+_widtheexpcx_ [l=fr] {110}
+_heighteexpcx_ [l=fr] {30}
+
+## "CONTRACT TEXT" ## document_button ## etsec ##
+_httpiconetsecof_ [l=fr] {_httpimg_/fr/etsecof.gif}
+_httpiconetsecon_ [l=fr] {_httpimg_/fr/etsecon.gif}
+_widthetsecx_ [l=fr] {85}
+_heightetsecx_ [l=fr] {30}
+
+## "METTRE EN EVIDENCE" ## document_button ## ehl ##
+_httpiconehlof_ [l=fr] {_httpimg_/fr/ehlof.gif}
+_httpiconehlon_ [l=fr] {_httpimg_/fr/ehlon.gif}
+_widthehlx_ [l=fr] {106}
+_heightehlx_ [l=fr] {30}
+
+## "NE PAS METTRE EN EVIDENCE" ## document_button ## enhl ##
+_httpiconenhlof_ [l=fr] {_httpimg_/fr/enhlof.gif}
+_httpiconenhlon_ [l=fr] {_httpimg_/fr/enhlon.gif}
+_widthenhlx_ [l=fr] {142}
+_heightenhlx_ [l=fr] {30}
+
+
+
+######################################################################
+# 'search' page
+package query
+######################################################################
+
+
+#------------------------------------------------------------
+# text macros
+#------------------------------------------------------------
+
+# this if statement produces the text 'results n1 - nn for query: querystring' or 
+# 'No matches for query: querystring', depending on whether or not there were
+# any matches
+_textquerytitle_ [l=fr] {_If_(_thislast_,resultats _thisfirst_ - _thislast_ pour la requete: _cgiargq_,Pas de documents contenant: _cgiargq_)}
+_textnoquerytitle_ [l=fr] {Page de recherche}
+
+_texticonthispage_ [l=fr] {rechercher}
+_textsome_ [l=fr] {_If_(_cgiargb_,ranked,quelque uns des)}
+_textall_ [l=fr] {_If_(_cgiargb_,booleen,tous les)}
+_texticonqueryresultsbar_ [l=fr] {}
+_textfreqmsg1_ [l=fr] {Compte des mots: }
+_textpostprocess_ [l=fr] {_If_(_quotedquery_,<br><i>post-processed to find _quotedquery_</i>
+)}
+
+_textmorethan_ [l=fr] {Plus de }
+_textapprox_ [l=fr] {A propos }
+_textnodocs_ [l=fr] {Aucun document ne contient la requete.}
+_text1doc_ [l=fr] {1 document contient la requete.}
+_textlotsdocs_ [l=fr] {documents contiennent la requete.}
+_textmatches_ [l=fr] {Matches }
+_textbeginsearch_ [l=fr] {Demarrer la recherche}
+
+_textsimplesearch_ [l=fr] {Rechercher pour des _If_(_hselection_, _hselection_)_If_(_jselection_,_textjselect_)_If_(_nselection_, in _nselection_ language) 
+contenant _querytypeselection_ mots}
+
+_textadvancedsearch_ [l=fr] {Search_If_(_hselection_, _hselection_, _defaultindextext_)_If_(_jselection_,_textjselect_)_If_(_nselection_, in _nselection_ language) 
+using _querytypeselection_ query}
+
+_textjselect_ [l=fr] {_If_(_hselection_, of) _jselection_}
+
+_textstemon_ [l=fr] { (ignorer la fin des mots)}
+_textclearhistory_ [l=fr] {Clear History}
+_textexpand_ [l=fr] {Etendre}
+_textcontract_ [l=fr] {Reduire}
+_textsearchhistory_ [l=fr] {Search History}
+_textquery_ [l=fr] {Requete}
+_textresults_ [l=fr] {Resultats}
+_textview_ [l=fr] {Voir}
+_textnohistory_ [l=fr] {Search history not available}
+
+
+#------------------------------------------------------------
+# icons
+#------------------------------------------------------------
+
+## "search" ## green_title ## h_search ##
+_httpiconhsearch_ [l=fr] {_httpimg_/fr/h\_search.gif}
+_widthhsearch_ [l=fr] {200}
+_heighthsearch_ [l=fr] {57}
+
+## "results" ## green_bar_left_aligned ## qryresb ##
+_httpiconqryresb_ [l=fr] {_httpimg_/fr/qryresb.gif}
+_widthqryresb_ [l=fr] {_pagewidth_}
+_heightqryresb_ [l=fr] {17}
+
+## "display" ## hand_made ##
+_httpicondisplay_ [l=fr] {_httpimg_/display.gif}
+_widthdisplay_ [l=fr] {60}
+_heightdisplay_ [l=fr] {20}
+
+
+
+######################################################################
+# 'preferences' page
+package preferences
+######################################################################
+
+
+#------------------------------------------------------------
+# text macros
+#------------------------------------------------------------
+
+_textsearchprefs_ [l=fr] {Preferences de recherche}
+_textcollectionprefs_ [l=fr] {Preferences de collection}
+_textpresentationprefs_ [l=fr] {Preferences de presentation}
+_textpreferences_ [l=fr] {Preferences}
+_textignorecase_ [l=fr] { ignorer la difference de casse}
+_textmatchcase_ [l=fr] { haute/basse case doivent correspondres}
+_textstem_ [l=fr] { ignorer la fin des mots}
+_textnostem_ [l=fr] { le mot entier doit correspondre}
+_textprefop_ [l=fr] {Retourner jusqu'a _maxdocoption_ enregistrement avec _hitsperpageoption_ enregistrement par page.}
+_textextlink_ [l=fr] {Acces aux pages Web externes: }
+_textintlink_ [l=fr] {Source documents retrieved from:}
+_textlanguage_ [l=fr] {Language de l'interface: }
+_textencoding_ [l=fr] {Encodage: }
+_textformat_ [l=fr] {Format de l'interface: }
+_textall_ [l=fr] {tous}
+_textsimplemode_ [l=fr] {mode requete simple}
+_textadvancedmode_ [l=fr] {mode requete avancee (authorise recherche booleenne utilisant !, &, |, et parentheses)}
+_textlinkinterm_ [l=fr] {through intermediate page}
+_textlinkdirect_ [l=fr] {aller directement la-bas}
+_textdigitlib_ [l=fr] {la bibliotheque numerique}
+_textweb_ [l=fr] {l'internet}
+_textlangeng_ [l=fr] {Anglais}
+_textlangmaori_ [l=fr] {M_amn_ori}
+_textlangchinese_ [l=fr] {Chinois}
+_textgraphical_ [l=fr] {Graphique}
+_texttextual_ [l=fr] {Textuel}
+_textcollectionoption_ [l=fr] {<p>
+Subcollections to include:
+<br>}
+_textfcoption_ [l=fr] {Inclure la barre de naviguation en haut des pages de document}
+_texthloption_ [l=fr] {Mettre en evidence les termes de recherche au sein du document}
+_texthistorydisplay_ [l=fr] {afficher l'historique des recherches}
+
+
+#------------------------------------------------------------
+# icons
+#------------------------------------------------------------
+
+## "preferences" ## green_title ## h_pref ##
+_httpiconhpref_ [l=fr] {_httpimg_/fr/h\_pref.gif}
+_widthhpref_ [l=fr] {200}
+_heighthpref_ [l=fr] {57}
+
+
+
+######################################################################
+# 'delete search history' page
+package delhistory
+######################################################################
+
+
+#------------------------------------------------------------
+# text macros
+#------------------------------------------------------------
+
+_textdsh_ [l=fr] {Delete Search History}
+
+_textselectdelete_ [l=fr] {<a href="_httpclearhistory_&hdh=1">Effacer tout
+les enregistrements</a> ou choisir les documents a <select name=hmode><option value=save>ne
+pas effacer<option value=delete selected>effacer</select><br> Les enregistrements peuvent etre 
+selectionnes en tapant leur numero dans la boite,<br> ou en clickant dans la boite de chaque 
+enregistrement.<br> Les valeurs acceptees sont 1,2,3-6,7- etc }
+
+_textclearselected_ [l=fr] {Clear selectionne}
+_textselect_ [l=fr] {selectionner}
+
+
+#------------------------------------------------------------
+# icons
+#------------------------------------------------------------
+
+
+
+######################################################################
+# 'help' page -- this is lower priority for translating than the
+# rest of this file
+package help
+######################################################################
+
+
+#------------------------------------------------------------
+# text macros
+#------------------------------------------------------------
+
+_textHelp_ [l=fr] {Help}
+_textSearchshort_ [l=fr] {chercher pour des mots en particulier}
+_textSeriesshort_ [l=fr] {acceder aux publications par series}
+_textDateshort_ [l=fr] {acceder aux publications par date}
+_textSubjectshort_ [l=fr] {acceder aux publications par sujet}
+_textTitleshort_ [l=fr] {acceder aux publications par titres}
+_textBrowseshort_ [l=fr] {naviguer a travers les publications}
+_textCreatorshort_ [l=fr] {acceder aux publications par auteurs}
+_textOrganizationshort_ [l=fr] {acceder aux publications par organisation}
+_textHowtoshort_ [l=fr] {acceder aux publications par la liste des comment faire}
+_textTopicshort_ [l=fr] {acceder aux publications par themes}
+_textPeopleshort_ [l=fr] {acceder aux publications par personnes}
+_textdefaultshorttext_ [l=fr] {classification non-definie}
+
+_textSearchlong_ [l=fr] { <p>Vous pouvez <i>rechercher certain mots</i> presents
+dans le texte a partir de la page de recherche. C'est la premiere page a s'afficher
+lorsque vous debutez, et peut etre atteinte a partir des autres pages par le bouton
+<i>rechercher</i>. }
+
+_textTitlelong_ [l=fr] { <p>Vous pouvez <i>acceder aux publications par titre</i> en
+pressant le bouton <i>titres a-z</i>. Ceci afichera une liste alphabetique 
+de livres. }
+
+_textOrganizationlong_ [l=fr] { <p>Vous pouvez <i>acceder aux publications par 
+organisation</i> en pressant le bouton <i>organisation</i>. Ceci afichera 
+une liste alphabetique d'organisations.  }
+
+_textHowtolong_ [l=fr] { <p>Vous pouvez <i>acceder aux publications par la liste des comment faire</i>
+ en pressant le bouton <i>comment faire</i>. Ceci afichera une liste de comment faire strings.  }
+
+_textCreatorlong_ [l=fr] { <p>Vous pouvez <i>acceder aux publications par auteur</i> en pressant le bouton 
+<i>auteurs a-z</i>. Ceci afichera une liste livres, classee par leur nom d'auteur.  }
+
+_textTopiclong_ [l=fr] { <p>Vous pouvez <i>acceder aux publications par theme</i> en pressant le bouton 
+<i>theme</i>. Ceci afichera une liste theme a naviguer.  }
+
+_textSubjectlong_ [l=fr] { <p>Vous pouvez <i>acceder aux publications par sujet</i> en pressant le bouton 
+<i>sujets</i>. Ceci afichera une liste de sujets, representee par rayons de livres.  }
+
+_textSerieslong_ [l=fr] { <p>Vous pouvez <i>acceder aux publications par series</i> en pressant le bouton 
+<i>series</i>.  Ceci afichera la liste des series comprisent actuellement dans la collection.  }
+
+_textDatelong_ [l=fr] { <p>Vous pouvez <i>acceder aux publications par date</i> en pressant le bouton 
+<i>dates</i>. Ceci afichera la liste des editions, triee chronologiquement. }
+
+_textBrowselong_ [l=fr] { <p>Vous pouvez <i>browse publications</i> en pressant le bouton 
+<i>naviguer</i>.  }
+
+_textPeoplelong_ [l=fr] { <p>Vous pouvez <i>acceder aux publications par personne</i> en pressant le bouton 
+<i>personne a-z</i>. Ceci afichera une liste d'entrees, triee par nom de famille.  }
+
+_textdefaultlongtext_ [l=fr] { <p>Pressez le bouton <i>inconu</i> par naviguer
+a travers les publications (la liste est triee par un champ inconu).  }
+
+_texthelptopics_ [l=fr] {
+<h2 align=left>Themes</h2>
+<ul>
+  <li><a href="\#finding-information">_textsimplehelpheading_</a>
+  _topicreadingdocs_
+  <li><a href="\#searching">Comment rechercher pour des mots particuliers</a>
+<ul>
+  <li><a href="\#query-terms">Termes de recherche</a>
+  <li><a href="\#query-type">Type de requetes</a>
+  <li><a href="\#scope-of-queries">Etendue des requetes</a>
+</ul>
+  <li><a href="\#preferences">_textchangeprefs_</a>
+<ul>
+  <li><a href="\#col-prefs">Preferences de la collection</a>
+  <li><a href="\#pres-prefs">Preferences de la presentation</a>
+  <li><a href="\#search-prefs">Preferences de recherche</a>
+</ul>
+</ul>
+}
+
+# there are 4 versions of this section of the help text.
+# which version is used is currently set within the server
+# (it should probably use the macro language e.g. [type=book])
+# 1 = html (like fao collections) -- section is empty
+# 2 = book (like hdl collection) -- macros beginning with book
+# 3 = bibliographic (like csbib) -- macros beginning with bib
+# 4 = standard (like gberg) -- the default
+
+_topicreadingdocs_ [l=fr] {<li><a href="\#reading-docs">_textreadingdocs_</a>}
+
+_textreadingdocs_ [l=fr] {Comment lire les documents}
+_booktextreadingdocs_ [l=fr] {Comment lire les livres}
+_bibtextreadingdocs_ [l=fr] {Obtenir plus d'informations sur une bibliographie}
+
+_texthelpreadingdocs_ [l=fr] {
+<p>_iconblankbar_
+<a name=reading-docs>
+<h2>_textreadingdocs_</h2>
+
+<p>Vous pouvez voir quand vous atteignez un document individuel car ses
+titres et auteurs apparaissent en haut a gauche de la page. A cote de 
+ces derniers, se presente le numero de la page courante, une boite vous
+permettant de selectionner une nouvelle page et des fleches suivante et
+precedente.
+
+<p>En dessous se trouve le texte de la portion courante. Lorsque
+vous aurez termine votre lecture, vous aurez deux fleches a votre disposition
+ pour vous emmener a la portion suivante ou vous ramener a la precedente.
+
+<p>Sous le titre et l'auteur se trouvent trois boutons.
+
+
+Below the title and author are three buttons. Click on <i>expand
+text</i> to expand out the whole text of the current document. If the
+document is large, this could take a long time and use a lot of memory!
+Click on <i>detach</i> to make a new browser window for this
+document. (This is useful if you want to compare documents, or read two at
+once.)  Finally, when you do a search the words you search for are
+highlighted.  Click on <i>no highlighting</i> to remove the highlighting.
+<p>
+<table cellspacing="0" cellpadding="2" border="0">
+<tr><td colspan=2><img src="_httpiconmore_" border="0"></td><td>Click on the arrow to go to the next section ...</td></tr>
+<tr><td colspan=2><img src="_httpiconless_" border="0"></td><td>... or back to the previous section</td></tr>
+<tr><td><img src="_document:httpiconealltof_" border="0"></td><td><img 
+src="_document:httpiconetsecof_" border="0"></td><td>Display all text, or not</td></tr>
+<tr><td colspan=2><img src="_document:httpiconedtchof_" border="0"></td><td>Open this page in a new window</td></tr>
+<tr><td><img src="_document:httpiconehlof_" border="0"></td><td><img
+src="_document:httpiconenhlof_" border="0"></td><td>Highlight search terms, or not</td></tr>
+</table>
+
+}
+
+_booktexthelpreadingdocs_ [l=fr] {
+<p>_iconblankbar_
+<a name=reading-docs>
+<h2>_textreadingdocs_</h2>
+
+<p>You can tell when you have arrived at an individual book because there
+is a photograph of its front cover at the top left of the page.  Beside the
+photograph is a table of contents with an arrow marking where you are.
+This table is expandable: click on the folders to open them or close them.
+Click on the open book at the top to close it.
+
+<p>Underneath is the text of the current section.  When you have read
+through it, there are arrows at the bottom to take you on to the next
+section or back to the previous one.
+
+<p>Below the photograph are four buttons. Click on <i>expand text</i> to
+expand out the whole text of the current section, or book.  If the book is
+large, this could take a long time and use a lot of memory! Click on
+<i>expand contents</i> to expand out the whole table of contents so that
+you can see the titles of all chapters and subsections. Click on
+<i>detach</i> to make a new browser window for this book.  (This is useful
+if you want to compare books, or read two at once.) Finally, when you do a
+search the words you search for are highlighted. Click on <i>no
+highlighting</i> to remove highlighting.
+
+<p>
+<table cellspacing="0" cellpadding="2" border="0">
+<tr><td colspan=2><img src="_httpiconbshelf_" border="0"></td><td>Open this bookshelf</td></tr>
+<tr><td><img src="_httpiconopenbook_" border="0"></td><td><img 
+src="_httpiconbook_" border="0"></td><td>Open/close this book</td></tr>
+<tr><td colspan=2><img src="_httpiconitext_" border="0"></td><td>View this section of the text</td></tr>
+<tr><td><img src="_document:httpiconealltof_" border="0"></td><td><img 
+src="_document:httpiconetsecof_" border="0"></td><td>Display all text, or not</td></tr>
+<tr><td><img src="_document:httpiconeexpcof_" border="0"></td><td><img
+src="_document:httpiconeconcof_" border="0"></td><td>Expand table of contents, or not</td></tr>
+<tr><td colspan=2><img src="_document:httpiconedtchof_" border="0"></td><td>Open this page in a new window</td></tr>
+<tr><td><img src="_document:httpiconehlof_" border="0"></td><td><img
+src="_document:httpiconenhlof_" border="0"></td><td>Highlight search terms, or not</td></tr>
+<tr><td colspan=2><img src="_httpiconmore_" border="0"></td><td>Click the arrow to go to the next section ...</td></tr>
+<tr><td colspan=2><img src="_httpiconless_" border="0"></td><td>... or back to the previous section</td></tr>
+</table>
+}
+
+_bibtexthelpreadingdocs_ [l=fr] {
+<p>_iconblankbar_
+<a name=reading-docs>
+<h2>_textreadingdocs_</h2>
+
+<p>Some bibliography items contain more information, such as an abstract.
+You can tell from the query response page if this is the case because they 
+are shown with the _icontext_ icon instead of the _iconblanktext_ icon.
+
+<p>Clicking on the _icontext_ icon will give you more information about the
+bibliography item.
+
+<p> Below the bibliography item are two buttons. Click on <i>detach</i> to 
+make a new browser window for this book. (This is useful if you want to compare
+bibliography items.) Finally, when you do a search the words you search for are 
+highlighted. Click on <i>no highlighting</i> to remove the highlighting.
+
+<p>
+<table cellspacing="0" cellpadding="2" border="0">
+<tr><td colspan=2><img src="_document:httpiconedtchof_" border="0"></td><td>Open this page in a new window</td></tr>
+<tr><td><img src="_document:httpiconehlof_" border="0"></td><td><img
+src="_document:httpiconenhlof_" border="0"></td><td>Highlight search terms, or not</td></tr>
+</table>
+}
+
+_texthelpsearching_ [l=fr] {
+<h2>How to search for particular words</h2>
+<p>
+  From the search page, you make a query in these simple steps:<p>
+  
+  <ol><li>Specify what documents you want to search
+      <li>Say whether you want to search for all or just some of the words
+      <li>Type in the words you want to search for
+      <li>Click the <i>Begin Search</i> button
+  </ol>
+
+<p>When you make a query, the titles of twenty matching documents will be shown.
+There is a button at the end to take you on to the next twenty documents.  From
+there you will find buttons to take you on to the third twenty or back to the
+first twenty, and so on.  Click the title of any document, or the little button
+beside it, to see it.
+
+<p>A maximum of 100 is imposed on the number of
+  documents returned.  You can change this number by clicking the
+  <i>preferences</i> button at the top of the page.<p>
+
+<p>_iconblankbar_
+<a name=query-terms>
+<h3>Search terms</h3>
+
+<p>Whatever you type into the query box is interpreted as a list of words
+called "search terms."  Each term contains nothing but alphabetic characters
+and digits.  Terms are separated by white space.  If any other characters such
+as punctuation appear, they serve to separate terms just as though they were
+spaces.  And then they are ignored.  You can't search for words that include
+punctuation.
+
+<p>For example, the query<p>
+    <ul><kbd>Agro-forestry in the Pacific Islands: Systems for Sustainability (1993)</kbd></ul>
+      <p>will be treated the same as<p>
+      <ul><kbd>Agro forestry in the Pacific Islands  Systems for Sustainability  1993 </kbd></ul><p>
+
+<p>_iconblankbar_
+<a name=query-type>
+<h3>Query type</h3>
+
+<p>There are two different kinds of query.
+
+<ul>
+  <li>Queries for <b>all</b> of the words.  These look for documents that 
+      contain all the words you have specified.  Documents that satisfy the
+      query are displayed, in alphabetical order.<p>
+
+  <li>Queries for <b>some</b> of the words.  Just list some terms that are
+      likely to appear in the documents you are looking for.  Documents are
+      displayed in order of how closely they match the query.  When determining
+
+      the degree of match,
+
+      <p><ul>
+        <li> the more search terms a document contains, the closer it matches;
+        <li> rare terms are more important than common ones;
+        <li> short documents match better than long ones.
+      </ul>
+</ul>
+
+<p>Use as many search terms as you like--a whole sentence, or even a
+whole paragraph.  If you specify only
+one term, documents will be ordered by its frequency of occurrence.<p>
+_texthelpscope_
+}
+
+_textchangeprefs_ [l=fr] {Changing your preferences}
+
+_texthelppreferences_ [l=fr] {<h2>_textchangeprefs_</h2>
+
+<p>When you click the <i>preferences</i> button at the top of the page you will
+be able to change some features of the interface to suit your own requirements.
+
+<p>_iconblankbar_
+<a name=col-prefs>
+<h3 align=left>Collection preferences</h3>
+
+Some collections comprise several subcollections, which can be searched
+independently or together, as one unit.  If so, you can select which
+subcollections to include in your searches on the Preferences page.
+
+<p>_iconblankbar_
+<a name=pres-prefs>
+<h3 align=left>Presentation preferences</h3>
+
+Depending on the particular collection, there may be several options you can
+set that control the presentation.
+
+Collections of Web pages allow you to suppress the Greenstone navigation bar at
+the top of each document page, so that once you have done a search you land at
+the exact Web page that matches without any Greenstone header.  To do another
+search you will have to use your browser's "back" button.  These collections
+also allow you to suppress Greenstone's warning message when you click a link
+that takes you out of the digital library collection and on to the Web itself.
+And in some Web collections you can control whether the links on the "Search
+Results" page take you straight to the actual URL in question, rather than to
+the digital library's copy of the page.
+
+Collections that are capable of being presented in different languages allow
+you to specify the interface language.  If the language is Chinese, you can
+also specify which of the standard Chinese encodings your browser uses.
+
+Finally, all collections allow you to switch to a textual interface format
+rather than the standard graphical one.  This is particularly useful for
+visually impaired users who use large screen fonts or speech synthesizers for
+output.
+
+<p>_iconblankbar_
+<a name=search-prefs>
+<h3 align=left>Search preferences</h3>
+Two pairs of buttons control the case sensitivity and stemming of the searches
+that you make. The first set of buttons controls whether upper and lower case
+must match (case sensitivity).  The second set controls whether to ignore word
+endings or not (stemming).
+
+<p>For example, if the buttons <i>ignore case differences</i> and
+<i>ignore word endings</i> are selected, the query<p>
+    <ul><kbd>African building</kbd></ul>
+      <p>will be treated the same as<p>
+      <ul><kbd>africa builds</kbd></ul><p>
+      because the uppercase letter in "African" will be transformed to
+      lowercase, and  the suffixes "n" and "ing" will be removed from
+      "African" and "building" respectively (also, "s" would be removed from
+      "builds").
+
+<p>You can also switch to an "advanced" query mode which allows you to
+combine terms using AND (&), OR (|), and NOT (!). This allows you to
+specify more precise queries.
+
+<p>Finally, you can control the number of hits returned, and the number
+presented on each screenful.
+
+}
+
+_texttanumbrowseoptions_ [l=fr] {il y a _numbrowseoptions_ facons de trouver des informations dans cette collection:}
+
+_textsimplehelpheading_ [l=fr] {Comment trouver des informations}
+
+_texthelpscope_ [l=fr] {
+<p>_iconblankbar_
+<a name=scope-of-queries>
+<h3 align=left>Scope of queries</h3>
+
+<p>
+Dans la plupart des collection, vous pouvez choisir differents indexes pour la recherche.
+Par exemple, il y aura peut-etre un indexe pour les auteurs et un autre pour les titres.
+Ou bien meme un index pur les chapitres ou paragraphes. Generalement, le document entier est retourne
+quelque soit l'index utilise.
+<p>Si les documents sont des livres, ils seront ouverts a l'endroit approprie.
+}
+
+
+#------------------------------------------------------------
+# icons
+#------------------------------------------------------------
+
+## "aide" ## green_title ## h_help ##
+_httpiconhhelp_ [l=fr] {_httpimg_/fr/h\_help.gif}
+_widthhhelp_ [l=fr] {200}
+_heighthhelp_ [l=fr] {57}
Index: /main/tags/2.25/gsdl/macros/french2.dm
===================================================================
--- /main/tags/2.25/gsdl/macros/french2.dm	(revision 21064)
+++ /main/tags/2.25/gsdl/macros/french2.dm	(revision 21064)
@@ -0,0 +1,86 @@
+# partially completed French translation of english2.dm
+
+######################################################################
+# html 
+package html
+######################################################################
+
+#------------------------------------------------------------
+# text macros
+#------------------------------------------------------------
+
+_textframebrowser_ [l=fr] {Vous devez avoir un navigateur acceptant les 'frames' pour voir ca.}
+
+#------------------------------------------------------------
+# icons
+#------------------------------------------------------------
+
+
+######################################################################
+# external links
+package extlink
+######################################################################
+
+#------------------------------------------------------------
+# text macros
+#------------------------------------------------------------
+
+_textextlink_ [l=fr] {Lien Exterieur}
+_textlinknotfound_ [l=fr] {Lien Interieur introuvable}
+
+_textextlinkcontent_ [l=fr] {Le lien selectionne est exterieur a toutes vos collections selectionnee actuellement
+The link you have selected is external to any of your currently selected collections.
+
+    If you still wish to view this link and your browser has access to 
+    the Web, you can <a href="_nexturl_">go forward</a> to this page; otherwise 
+    use your browsers "back" button to return to the previous document.}
+
+_textlinknotfoundcontent_ [l=fr] {For reasons beyond our control, the internal link you have selected 
+    does not exist.  This is probably due to an error in the source collection.
+    Use your browsers "back" button to return to the previous document.}
+
+# should have arguments of collection, collectionname and link
+_foundintcontent_ [l=fr] {
+
+<h3>Link to "_2_" collection</h3>
+
+<p> The link you have selected is external to the "_collectionname_"
+    collection (it links to the "_2_" collection).
+    If you wish to view this link in the "_2_" collection you can 
+    <a href="_httpdoc_&c=_1_&cl=_cgiargcl_&d=_3_">go forward</a> to this page; 
+    otherwise use your browsers "back" button to return to the previous document.
+}
+
+
+#------------------------------------------------------------
+# icons
+#------------------------------------------------------------
+
+
+######################################################################
+# authentication page
+package authen
+######################################################################
+
+
+#------------------------------------------------------------
+# text macros
+#------------------------------------------------------------
+
+_textGSDLtitle_ [l=fr] {Bibliotheque Numerique Greenstone}
+
+_textusername_ [l=fr] {nom d'utilisateur}
+_textpassword_ [l=fr] {mot de passe}
+
+_textmessageinvalid_ [l=fr] {La page demandee necessite votre enregistrement.
+Veuillez entrez votre nom d'utilisateur et mopt de passe.}
+
+_textmessagefailed_ [l=fr] {Votre nom d'utilisateur ou votre mot de passe est incorrect.}
+
+_textmessagedisabled_ [l=fr] {Desole, votre compte a ete mis hors service. Veuillez contacter
+l'administrateur de ce site.}
+
+_textmessagepermissiondenied_ [l=fr] {Desole, vous n'avez pas la permission d'acceder a cette page.}
+
+_textmessagestalekey_ [l=fr] {Le lien que vous avez choisit est maintenant perime.
+Veuillez entrez votre mot de passe pour acceder a cette page.}
Index: /main/tags/2.25/gsdl/macros/german.dm
===================================================================
--- /main/tags/2.25/gsdl/macros/german.dm	(revision 21064)
+++ /main/tags/2.25/gsdl/macros/german.dm	(revision 21064)
@@ -0,0 +1,1013 @@
+######################################################################
+#
+# German Language text and icon macros (translated from english.dm
+# 9 March 2000)
+#
+######################################################################
+#
+# This is the main macro file for translation when creating an 
+# interface in another language.
+#
+# Under the 'text macros' comments are text macros of the form:
+# _macroname_ {macro value}
+# Everything between the {} is the text to be translated. This text 
+# may itself contain macros (i.e. characters other than space between
+# underscore characters, e.g. _about:numdocs_ or _textpage_). These
+# macro names occurring within text shouldn't be translated but should
+# be left as they are. Underscores or curly brackets occurring 
+# naturally within the text should be escaped with a leading backslash
+# (i.e. '\_', '\{' or '\}).
+#
+# Under the 'icons' comments are macros concerned with displaying
+# icons which themselves contain text.
+# Above each macro (or group of macros) for an icon is a comment line
+# that looks something like '## "HOME" ## top_nav_button ## chome ##'.
+# The first field of the comment ("HOME" in this case) is the text
+# that appears in the english version of the icon. This is the text
+# that must be translated, nothing needs to be done to the macros 
+# themselves. The other two fields of the comments are used by 
+# automatic icon generating software which reads the newly translated
+# file and generates appropriate icons.
+#
+# Comment lines (other than those described above) need not be 
+# translated (i.e. any lines beginning with '#', like this line).
+#
+# The simplest way to translate this file is to save it as something
+# else (e.g. french.dm) and work through translating all the text
+# macro values and icon comments.
+#
+######################################################################
+
+
+######################################################################
+# Global (base) package
+package Global
+######################################################################
+
+
+#------------------------------------------------------------
+# text macros
+#------------------------------------------------------------
+
+_textdefaultcontent_ [l=de] {Die angegebene Seite konnte nicht gefunden
+werden. Bitte benutzen sie den "Zur&uuml;ck" Knopf ihres Browsers oder
+den obigen "Home" Knopf um zur Hauptseite der elektronischen
+Bibliothek zur&uuml;ckzukehren.}
+
+_textdefaulttitle_ [l=de] {GSDL Fehler}
+
+_collectionextra_ [l=de] {Diese Sammlung enth&auml;lt _about:numdocs_
+Dokumente.  Sie wurde vor _about:builddate_ Tagen erstellt.}
+
+_textimagecollection_ [l=de] {}
+_textimageabout_ [l=de] {Info}
+_textimagehome_ [l=de] {Hauptseite}
+_textimagehelp_ [l=de] {Hilfe}
+_textimagepref_ [l=de] {Voreinstellungen}
+_textimagegreenstone_ [l=de] {Greenstone Digital Library Software}
+
+_textimagesearch_ [l=de] {Suche nach einem bestimmten Begriff}
+_textimageTitle_ [l=de] {Alphabetische Liste der Titel}
+_textimageList_ [l=de] {Liste der Dokumente}
+_textimageCreator_ [l=de] {Alphabetische Liste der Autoren}
+_textimageSeries_ [l=de] {Sortiert nach Ausgaben}
+_textimageDate_ [l=de] {Sortiert nach Datum}
+_textimageSubject_ [l=de] {Sortiert nach Sparte}
+_textimageOrganization_ [l=de] {Sortiert nach Organisation}
+_textimageHowto_ [l=de] {&quot;Wie geht das?&quot;-Kategorien}
+_textimageTopic_ [l=de] {St&ouml;bern in Ausgaben zu speziellen Themen}
+_textimageBrowse_ [l=de] {St&ouml;bern}
+_textimagePeople_ [l=de] {Alphabetische Liste der Personen}
+
+_texticontabsearchgreen_ [l=de] {Suche}
+_texticontabdategreen_ [l=de] {Daten}
+_texticontabseriesgreen_ [l=de] {Serien}
+_texticontabauthorgreen_ [l=de] {Autoren A-Z}
+_texticontabtitlegreen_ [l=de] {Titel A-Z}
+_texticontablistgreen_ [l=de] {Auflistung}
+_texticontabsubjectgreen_ [l=de] {Sparten}
+_texticontaborggreen_ [l=de] {Organisation}
+_texticontabhowgreen_ [l=de] {Wie geht das?}
+_texticontabtopicgreen_ [l=de] {Themen}
+_texticontabbrwsegreen_ [l=de] {St&ouml;bern}
+_texticontabPeoplegreen_ [l=de] {Personen A-Z}
+
+_texticontext_ [l=de] {Sichten des Dokuments}
+_texticonclosedbook_ [l=de] {&Ouml;ffnen dieses Dokuments und Sichten des Inhalts}
+_texticonnext_ [l=de] {zur n&auml;chsten Sektion}
+_texticonprev_ [l=de] {zur vorhergehenden Sektion}
+
+_page_ [l=de] {Seite }
+_pages_ [l=de] {Seiten}
+_of_ [l=de] { of }
+_vol_ [l=de] {Volume}
+_num_ [l=de] {Number}
+
+_textmonth00_ [l=de] {}
+_textmonth01_ [l=de] {Januar}
+_textmonth02_ [l=de] {Februar}
+_textmonth03_ [l=de] {M&auml;rz}
+_textmonth04_ [l=de] {April}
+_textmonth05_ [l=de] {Mai}
+_textmonth06_ [l=de] {Juni}
+_textmonth07_ [l=de] {Juli}
+_textmonth08_ [l=de] {August}
+_textmonth09_ [l=de] {September}
+_textmonth10_ [l=de] {Oktober}
+_textmonth11_ [l=de] {November}
+_textmonth12_ [l=de] {Dezember}
+
+_magazines_ [l=de] {Magazine}
+
+
+#------------------------------------------------------------
+# icons
+#------------------------------------------------------------
+
+## "HAUPTSEITE" ## top_nav_button ## chome ##
+_httpiconchomeof_ [l=de] {_httpimg_/de/chomeof.gif}
+_httpiconchomeon_ [l=de] {_httpimg_/de/chomeon.gif}
+_widthchomex_ [l=de] {75}
+_heightchomex_ [l=de] {20}
+
+## "HILFE" ## top_nav_button ## chelp ##
+_httpiconchelpof_ [l=de] {_httpimg_/de/chelpof.gif}
+_httpiconchelpon_ [l=de] {_httpimg_/de/chelpon.gif}
+_widthchelpx_ [l=de] {36}
+_heightchelpx_ [l=de] {20}
+
+## "VOREINSTELLUNGEN" ## top_nav_button ## cpref ##
+_httpiconcprefof_ [l=de] {_httpimg_/de/cprefof.gif}
+_httpiconcprefon_ [l=de] {_httpimg_/de/cprefon.gif}
+_widthcprefx_ [l=de] {124}
+_heightcprefx_ [l=de] {20}
+
+## "hilfe" ## green_title ## h_help ##
+_httpiconhhelp_ [l=de] {_httpimg_/de/h\_help.gif}
+_widthhhelp_ [l=de] {200}
+_heighthhelp_ [l=de] {57}
+
+## "autoren a-z" ## nav_bar_button ## tauth ##
+_httpicontauthgr_ [l=de] {_httpimg_/de/tauthgr.gif}
+_httpicontauthof_ [l=de] {_httpimg_/de/tauthof.gif}
+_httpicontauthon_ [l=de] {_httpimg_/de/tauthon.gif}
+_widthtauthx_ [l=de] {102}
+_heighttauthx_ [l=de] {17}
+
+## "serien" ## nav_bar_button ## tser ##
+_httpicontsergr_ [l=de] {_httpimg_/de/tsergr.gif}
+_httpicontserof_ [l=de] {_httpimg_/de/tserof.gif}
+_httpicontseron_ [l=de] {_httpimg_/de/tseron.gif}
+_widthtserx_ [l=de] {87}
+_heighttserx_ [l=de] {17}
+
+## "daten" ## nav_bar_button ## tdate ##
+_httpicontdategr_ [l=de] {_httpimg_/de/tdategr.gif}
+_httpicontdateof_ [l=de] {_httpimg_/de/tdateof.gif}
+_httpicontdateon_ [l=de] {_httpimg_/de/tdateon.gif}
+_widthtdatex_ [l=de] {87}
+_heighttdatex_ [l=de] {17}
+
+## "sparten" ## nav_bar_button ## tsubj ##
+_httpicontsubjgr_ [l=de] {_httpimg_/de/tsubjgr.gif}
+_httpicontsubjon_ [l=de] {_httpimg_/de/tsubjon.gif}
+_httpicontsubjof_ [l=de] {_httpimg_/de/tsubjof.gif}
+_widthtsubjx_ [l=de] {87}
+_heighttsubjx_ [l=de] {17}
+
+## "organisation" ## nav_bar_button ## torg ##
+_httpicontorggr_ [l=de] {_httpimg_/de/torggr.gif}
+_httpicontorgon_ [l=de] {_httpimg_/de/torgon.gif}
+_httpicontorgof_ [l=de] {_httpimg_/de/torgof.gif}
+_widthtorgx_ [l=de] {105}
+_heighttorgx_ [l=de] {17}
+
+## "wie geht das?" ## nav_bar_button ## thow ##
+_httpiconthowgr_ [l=de] {_httpimg_/de/thowgr.gif}
+_httpiconthowon_ [l=de] {_httpimg_/de/thowon.gif}
+_httpiconthowof_ [l=de] {_httpimg_/de/thowof.gif}
+_widththowx_ [l=de] {115}
+_heightthowx_ [l=de] {17}
+
+## "thema" ## nav_bar_button ## ttopic ##
+_httpiconttopicgr_ [l=de] {_httpimg_/de/ttopicgr.gif}
+_httpiconttopicon_ [l=de] {_httpimg_/de/ttopicon.gif}
+_httpiconttopicof_ [l=de] {_httpimg_/de/ttopicof.gif}
+_widthttopicx_ [l=de] {87}
+_heightttopicx_ [l=de] {17}
+
+## "st&ouml;bern" ## nav_bar_button ## tbrwse ##
+_httpicontbrwsegr_ [l=de] {_httpimg_/de/tbrwsegr.gif}
+_httpicontbrwseon_ [l=de] {_httpimg_/de/tbrwseon.gif}
+_httpicontbrwseof_ [l=de] {_httpimg_/de/tbrwseof.gif}
+_widthtbrwsex_ [l=de] {87}
+_heighttbrwsex_ [l=de] {17}
+
+## "suche" ## nav_bar_button ## tsrch ##
+_httpicontsrchgr_ [l=de] {_httpimg_/de/tsrchgr.gif}
+_httpicontsrchof_ [l=de] {_httpimg_/de/tsrchof.gif}
+_httpicontsrchon_ [l=de] {_httpimg_/de/tsrchon.gif}
+_widthtsrchx_ [l=de] {87}
+_heighttsrchx_ [l=de] {17}
+
+## "titel a-z" ## nav_bar_button ## ttitl ##
+_httpiconttitlgr_ [l=de] {_httpimg_/de/ttitlgr.gif}
+_httpiconttitlof_ [l=de] {_httpimg_/de/ttitlof.gif}
+_httpiconttitlon_ [l=de] {_httpimg_/de/ttitlon.gif}
+_widthttitlx_ [l=de] {87}
+_heightttitlx_ [l=de] {17}
+
+## "personen" ## nav_bar_button ## tpeop ##
+_httpicontpeopgr_ [l=de] {_httpimg_/de/tpeopgr.gif}
+_httpicontpeopof_ [l=de] {_httpimg_/de/tpeopof.gif}
+_httpicontpeopon_ [l=de] {_httpimg_/de/tpeopon.gif}
+_widthtpeopx_ [l=de] {87}
+_heighttpeopx_ [l=de] {17}
+
+
+
+######################################################################
+# 'about' page
+package about
+######################################################################
+
+
+#------------------------------------------------------------
+# text macros
+#------------------------------------------------------------
+
+_textabcol_ [l=de] {&Uuml;ber diese Sammlung}
+
+_textsubcols1_ [l=de] {<p>Die komplette Sammlung umfa&szlig;t _1_ individuelle
+Kollektionen:
+<blockquote>}
+
+_textsubcols2_ [l=de] {</blockquote>
+Auf der Seite mit den Einstellugen k&ouml;nnen sie pr&uuml;fen (und
+ &auml;Yndern) welche individuellen Kollektionen sie momentan benutzen.}
+
+
+#------------------------------------------------------------
+# icons
+#------------------------------------------------------------
+
+## "info" ## green_title ## h_about ##
+_httpiconhabout_ [l=de] {_httpimg_/de/h\_about.gif}
+_widthhabout_ [l=de] {200}
+_heighthabout_ [l=de] {57}
+
+
+
+######################################################################
+# document package
+package document
+######################################################################
+
+
+#------------------------------------------------------------
+# text macros
+#------------------------------------------------------------
+
+_textTitlepage_ [l=de] {_texticonhtitle_}
+_textCreatorpage_ [l=de] {_texticonhauth_}
+_textSubjectpage_ [l=de] {_texticonhsubj_}
+_textSeriespage_ [l=de] {_texticonhser_}
+_textDatepage_ [l=de] {_texticonhdate_}
+_textHowtopage_ [l=de] {_texticonhhow_}
+_textOrganizationpage_ [l=de] {_texticonhorg_}
+_textBrowsepage_ [l=de] {_texticonhbrwse_}
+_textPeoplepage_ [l=de] {_texticonhpeople_}
+
+_texticonhtitle_ [l=de] {Titel A-Z}
+_texticonhauth_ [l=de] {Autoren A-Z}
+_texticonhsubj_ [l=de] {Sparten}
+_texticonhser_ [l=de] {Serien}
+_texticonhdate_ [l=de] {Daten}
+_texticonhhow_ [l=de] {Wie geht das?}
+_texticonhorg_ [l=de] {Organisationen}
+_texticonhbrwse_ [l=de] {St&ouml;bern}
+_texticonhpeople_ [l=de] {Personen A-Z}
+
+_texticonopenbookshelf_ [l=de] {Schliessen dieser Sektion der Bibliothek}
+_texticonclosedbookshelf_ [l=de] {&Ouml;ffnen dieser Sektion der Bibliothek und Sichten des Inhalts}
+_texticonopenbook_ [l=de] {Schliessen dieses Buches}
+_texticonclosedfolder_ [l=de] {&Ouml;ffnen dieses Ordners und Sichten des Inhalts}
+_texticonclosedfolder2_ [l=de] {&Ouml;ffnen der individuellen Kollektion: }
+_texticonopenfolder_ [l=de] {Schliessen dieses Ordners}
+_texticonopenfolder2_ [l=de] {Schliessen der individuellen Kollektion: }
+_texticonsmalltext_ [l=de] {Sichten des Textabschnittes}
+_texticonsmalltext2_ [l=de] {Sichten des Texts: }
+_texticonpointer_ [l=de] {Augenblickliche Sektion}
+_texticondetach_ [l=de] {&Ouml;ffnen dieser Seite in einem neuen Fenster}
+_texticonhighlight_ [l=de] {Suchbegriffe werden hervorgehoben}
+_texticonnohighlight_ [l=de] {Suchbegriffe werden nicht hervorgehoben}
+_texticoncontracttoc_ [l=de] {Verkleinerte Version des Inhaltsverzeichnisses}
+_texticonexpandtoc_ [l=de] {Expandierte Version des Inhaltsverzeichnisses}
+_texticonexpandtext_ [l=de] {Anzeigen des gesamten Texts}
+_texticoncontracttext_ [l=de] {Anzeigen des Textes nur f&uuml;r die augenblicklich ausgew&auml;hlte Sektion}
+_texticonwarning_ [l=de] {<b>Warnung: </b>}
+_texticoncont_ [l=de] {Weitermachen?}
+
+_textltwarning_ [l=de] {
+<p><center>
+<table cellspacing=0 cellpadding=0 width=_pagewidth_>
+<tr valign=top><td>_iconwarning_Wenn der Text hier expandiert wird, wird eine sehr grosse Menge an Daten dargestellt werden m&uuml;ssen _imagecont_
+</td></tr></table></center>
+}
+
+_textgoto_ [l=de] {Gehe zur Seite}
+_textintro_ [l=de] { <i>(Einf&uuml;hrender Text)</i>}
+
+
+#------------------------------------------------------------
+# icons
+#------------------------------------------------------------
+
+## "titel a-z" ## green_title ## h_title ##
+_httpiconhtitle_ [l=de] {_httpimg_/de/h\_title.gif}
+_widthhtitle_ [l=de] {200}
+_heighthtitle_ [l=de] {57}
+
+## "autoren a-z" ## green_title ## h_auth ##
+_httpiconhauth_ [l=de] {_httpimg_/de/h\_auth.gif}
+_widthhauth_ [l=de] {200}
+
+## "sparten" ## green_title ## h_subj ##
+_httpiconhsubj_ [l=de] {_httpimg_/de/h\_subj.gif}
+_widthhsubj_ [l=de] {200}
+_heighthsubj_ [l=de] {57}
+
+## "serien" ## green_title ## h_ser ##
+_httpiconhser_ [l=de] {_httpimg_/de/h\_ser.gif}
+_widthhser_ [l=de] {200}
+_heighthser_ [l=de] {57}
+
+## "daten" ## green_title ## h_date ##
+_httpiconhdate_ [l=de] {_httpimg_/de/h\_date.gif}
+_widthhdate_ [l=de] {200}
+_heighthdate_ [l=de] {57}
+
+## "wie geht das?" ## green_title ## h_how ##
+_httpiconhhow_ [l=de] {_httpimg_/de/h\_how.gif}
+_widthhhow_ [l=de] {200}
+_heighthhow_ [l=de] {57}
+
+## "themen" ## green_title ## h_topic ##
+_httpiconhtopic_ [l=de] {_httpimg_/de/h\_topic.gif}
+_widthhtopic_ [l=de] {200}
+_heighthtopic_ [l=de] {57}
+
+## "organisation" ## green_title ## h_org ##
+_httpiconhorg_ [l=de] {_httpimg_/de/h\_org.gif}
+_widthhorg_ [l=de] {250}
+_heighthorg_ [l=de] {57}
+
+## "st&ouml;bern" ## green_title ## h_brwse ##
+_httpiconhbrwse_ [l=de] {_httpimg_/de/h\_brwse.gif}
+_widthhbrwse_ [l=de] {200}
+_heighthbrwse_ [l=de] {57}
+
+## "personen" ## green_title ## h_people ##
+_httpiconhpeople_ [l=de] {_httpimg_/de/h\_people.gif}
+_widthhpeople_ [l=de] {200}
+_heighthpeople_ [l=de] {57}
+
+## "WEITERMACHEN?" ## top_nav_button ## cont ##
+_httpiconcontoff_ [l=de] {_httpimg_/de/contoff.gif}
+_httpiconconton_ [l=de] {_httpimg_/de/conton.gif}
+_widthcontx_ [l=de] {104}
+_heightcontx_ [l=de] {17}
+
+## "EXPANDIEREN
+#  DES TEXTS" ## document_button ## eallt ## 
+_httpiconealltof_ [l=de] {_httpimg_/de/ealltof.gif}
+_httpiconeallton_ [l=de] {_httpimg_/de/eallton.gif}
+_widthealltx_ [l=de] {65}
+_heightealltx_ [l=de] {30}
+
+## "KONTRAKTIONDES
+#        INHALTS" ## document_button ## econc ##
+_httpiconeconcof_ [l=de] {_httpimg_/de/econcof.gif}
+_httpiconeconcon_ [l=de] {_httpimg_/de/econcon.gif}
+_widtheconcx_ [l=de] {92}
+_heighteconcx_ [l=de] {30}
+
+## "SEPARATES
+#  FENSTER" ## document_button ## edtch ##
+_httpiconedtchof_ [l=de] {_httpimg_/de/edtchof.gif}
+_httpiconedtchon_ [l=de] {_httpimg_/de/edtchon.gif}
+_widthedtchx_ [l=de] {65}
+_heightedtchx_ [l=de] {30}
+
+## "EXPANDIEREN
+#DES INHALTS" ## document_button ## eexpc ##
+_httpiconeexpcof_ [l=de] {_httpimg_/de/eexpcof.gif}
+_httpiconeexpcon_ [l=de] {_httpimg_/de/eexpcon.gif}
+_widtheexpcx_ [l=de] {65}
+_heighteexpcx_ [l=de] {30}
+
+## "KONTRAKTION
+#   DES TEXTS" ## document_button ## etsec ##
+_httpiconetsecof_ [l=de] {_httpimg_/de/etsecof.gif}
+_httpiconetsecon_ [l=de] {_httpimg_/de/etsecon.gif}
+_widthetsecx_ [l=de] {74}
+_heightetsecx_ [l=de] {30}
+
+## "HERVORHEBUNG" ## document_button ## ehl ##
+_httpiconehlof_ [l=de] {_httpimg_/de/ehlof.gif}
+_httpiconehlon_ [l=de] {_httpimg_/de/ehlon.gif}
+_widthehlx_ [l=de] {81}
+_heightehlx_ [l=de] {30}
+
+## "         KEINE
+#HERVORHEBUNG" ## document_button ## enhl ##
+_httpiconenhlof_ [l=de] {_httpimg_/de/enhlof.gif}
+_httpiconenhlon_ [l=de] {_httpimg_/de/enhlon.gif}
+_widthenhlx_ [l=de] {81}
+_heightenhlx_ [l=de] {30}
+
+
+
+######################################################################
+# 'search' page
+package query
+######################################################################
+
+
+#------------------------------------------------------------
+# text macros
+#------------------------------------------------------------
+
+# this if statement produces the text 'results n1 - nn for query: querystring' or 
+# 'No matches for query: querystring', depending on whether or not there were
+# any matches
+_textquerytitle_ [l=de] {_If_(_thislast_,Treffer _thisfirst_ - _thislast_ zur Anfrage: _cgiargq_,Keine Treffer f&uuml;r die Anfrage: _cgiargq_)}
+_textnoquerytitle_ [l=de] {Suchseite}
+
+_texticonthispage_ [l=de] {Suche}
+_textsome_ [l=de] {_If_(_cgiargb_,gestaffelt,einige)}
+_textall_ [l=de] {_If_(_cgiargb_,boolsch,alle)}
+_texticonqueryresultsbar_ [l=de] {}
+_textfreqmsg1_ [l=de] {Zahl der W&ouml;rter: }
+_textpostprocess_ [l=de] {_If_(_quotedquery_,<br><i>weiterverarbeitet um _quotedquery_ zu finden</i>
+)}
+
+_textmorethan_ [l=de] {Mehr als }
+_textapprox_ [l=de] {&Uuml;ber }
+_textnodocs_ [l=de] {Keine Dokumente zur Anfrage passenden Dokumente gefunden.}
+_text1doc_ [l=de] {Eins zur Anfrage passendes Dokument gefunden.}
+_textlotsdocs_ [l=de] {zur Anfrage passenden Dokumente gefunden.}
+_textmatches_ [l=de] {Passende Dokumente }
+_textbeginsearch_ [l=de] {Suche beginnen}
+
+_textsimplesearch_ [l=de] {Suche nach _If_(_hselection_, _hselection_)_If_(_jselection_,_textjselect_)_If_(_nselection_, in der _nselection_ Sprache) 
+die _querytypeselection_ der W&ouml;rter enthalten}
+
+_textadvancedsearch_ [l=de] {Suche nach _If_(_hselection_, _hselection_, _defaultindextext_)_If_(_jselection_,_textjselect_)_If_(_nselection_, in der _nselection_ Sprache) 
+mit einer _querytypeselection_ Anfrage}
+
+_textjselect_ [l=de] {_If_(_hselection_, aus) _jselection_}
+
+_textstemon_ [l=de] { (Wortendungen werden ignoriert)}
+_textclearhistory_ [l=de] {L&ouml;schen der alten Suchresultate}
+_textexpand_ [l=de] {Expandierung}
+_textcontract_ [l=de] {Kontraktion}
+_textsearchhistory_ [l=de] {Alte Suchresultate}
+_textquery_ [l=de] {Anfrage}
+_textresults_ [l=de] {Resultate}
+_textview_ [l=de] {Sichtung}
+_textnohistory_ [l=de] {Alte Suchresultate nicht verf&uuml;gbar}
+
+
+#------------------------------------------------------------
+# icons
+#------------------------------------------------------------
+
+## "suche" ## green_title ## h_search ##
+_httpiconhsearch_ [l=de] {_httpimg_/de/h\_search.gif}
+_widthhsearch_ [l=de] {200}
+_heighthsearch_ [l=de] {57}
+
+## "resultate" ## green_bar_left_aligned ## qryresb ##
+_httpiconqryresb_ [l=de] {_httpimg_/de/qryresb.gif}
+_widthqryresb_ [l=de] {_pagewidth_}
+_heightqryresb_ [l=de] {17}
+
+## "sichtung" ## hand_made ##
+_httpicondisplay_ [l=de] {_httpimg_/display.gif}
+_widthdisplay_ [l=de] {60}
+_heightdisplay_ [l=de] {20}
+
+
+
+######################################################################
+# 'preferences' page
+package preferences
+######################################################################
+
+
+#------------------------------------------------------------
+# text macros
+#------------------------------------------------------------
+
+_textsearchprefs_ [l=de] {Suchvoreinstellungen}
+_textcollectionprefs_ [l=de] {Voreinstellungen zu Kollektionen}
+_textpresentationprefs_ [l=de] {Voreinstellungen zur Pr&auml;sentation}
+_textpreferences_ [l=de] {Voreinstellungen}
+_textignorecase_ [l=de] { ignoriere Gro&szlig;-/Kleinschreibung}
+_textmatchcase_ [l=de] { Gro&szlig;-/Kleinschreibung mu&szlig; passen}
+_textstem_ [l=de] { ignoriere Wortendungen}
+_textnostem_ [l=de] { das vollst&auml;ndige Wort mu&szlig; passen}
+_textprefop_ [l=de] {Zeige maximal _maxdocoption_ hits Treffer an, mit _hitsperpageoption_ Treffern per Seite.}
+_textextlink_ [l=de] {Zugang zu externen Seiten: }
+_textintlink_ [l=de] {Quelldokumente aufgefunden in:}
+_textlanguage_ [l=de] {Schnittstellensprache: }
+_textencoding_ [l=de] {Kodierung: }
+_textformat_ [l=de] {Schnittstellenformat: }
+_textall_ [l=de] {alle}
+_textsimplemode_ [l=de] {einfache Anfragen}
+_textadvancedmode_ [l=de] {komplexe Anfragen (erm&ouml;glicht boolsche Suche mit !, &, |, und Klammern)}
+_textlinkinterm_ [l=de] {via einer dazwischenliegenden Seite}
+_textlinkdirect_ [l=de] {gehe direkt dorthin}
+_textdigitlib_ [l=de] {die elektronische Bibliothek}
+_textweb_ [l=de] {das Web}
+_textlangeng_ [l=de] {Englisch}
+_textlangmaori_ [l=de] {M_amn_ori}
+_textlangchinese_ [l=de] {Chinesisch}
+_textgraphical_ [l=de] {Graphisch}
+_texttextual_ [l=de] {Textuell}
+_textcollectionoption_ [l=de] {<p>
+Individuelle Sammlungen die eingebunden werden sollen:
+<br>}
+_textfcoption_ [l=de] {Produziere Navigationsleiste am Kopfende des Dokuments}
+_texthloption_ [l=de] {Hervorhebung von Suchbegriffen im Text des Dokuments}
+_texthistorydisplay_ [l=de] {Anzeige der alten Resultate}
+
+
+#------------------------------------------------------------
+# icons
+#------------------------------------------------------------
+
+## "voreinstellungen" ## green_title ## h_pref ##
+_httpiconhpref_ [l=de] {_httpimg_/de/h\_pref.gif}
+_widthhpref_ [l=de] {200}
+_heighthpref_ [l=de] {57}
+
+
+
+######################################################################
+# 'delete search history' page
+package delhistory
+######################################################################
+
+
+#------------------------------------------------------------
+# text macros
+#------------------------------------------------------------
+
+_textdsh_ [l=de] {L&ouml;sche alte Resultate}
+
+_textselectdelete_ [l=de] {<a href="_httpclearhistory_&hdh=1">L&ouml;schen
+aller Datens&auml;tze</a> oder Auswahl <select name=hmode><option
+value=save>von Datens&auml;tzen die nicht gel&ouml;scht werden
+sollen<option value=delete selected>delete</select><br>
+Datens&auml;tze k&ouml;nnen ausgew&auml;hlt werden, indem ihre Nummern in das bereitgestellte Feld eingetragen werden,<br> oder indem auf das Felder im Datensatz geklickt wird.<br> M&ouml;gliche Werte sind 1,2,3-6,7- etc }
+
+_textclearselected_ [l=de] {L&ouml;sche Selektionen}
+_textselect_ [l=de] {Selektiere}
+
+
+#------------------------------------------------------------
+# icons
+#------------------------------------------------------------
+
+
+
+######################################################################
+# 'help' page -- this is lower priority for translating than the
+# rest of this file
+package help
+######################################################################
+
+
+#------------------------------------------------------------
+# text macros
+#------------------------------------------------------------
+
+_textHelp_ [l=de] {Help}
+_textSearchshort_ [l=de] {Suche nach bestimmten W&ouml;rtern}
+_textSeriesshort_ [l=de] {Zugriff auf Publikationen nach Serien}
+_textDateshort_ [l=de] {Zugriff auf Publikationen nach Zeit}
+_textSubjectshort_ [l=de] {Zugriff auf Publikationen nach Sparten}
+_textTitleshort_ [l=de] {Zugriff auf Publikationen nach Titel}
+_textBrowseshort_ [l=de] {St&ouml;bern in Publikationen}
+_textCreatorshort_ [l=de] {Zugriff auf Publikationen nach Autor}
+_textOrganizationshort_ [l=de] {Zugriff auf Publikationen nach Organisation}
+_textHowtoshort_ [l=de] {Zugriff auf Publikationen nach "Wie geht das?" Kategorien}
+_textTopicshort_ [l=de] {Zugriff auf Publikationen nach Thema}
+_textPeopleshort_ [l=de] {Zugriff auf Publikationen nach Personen}
+_textdefaultshorttext_ [l=de] {Klassifikation is nicht definiert}
+
+_textSearchlong_ [l=de] { <p>Sie k&ouml;nnen <i>nach bestimmten Begriffen
+suchen</i>, die im Text der Suchseite erscheinen. Das ist die erste
+Seite, die angezeigt wird, wenn sie anfangen. Sie kann von allen
+anderen Seiten durch Anklicken des <i>Suche</i> Knopfes erreicht
+werden.  }
+
+_textTitlelong_ [l=de] { <p>Sie k&ouml;nnen auf <i> Publikationen geordnet
+nach Titel zugreifen</i> indem sie den <i>Titel A-Z</i> Knopf
+anklicken. Dann wird ihnen eine alphabetisch geordnete Liste der
+B&uuml;cher angezeigt.  }
+
+_textOrganizationlong_ [l=de] { <p>Sie k&ouml;nnen auf <i> Publikationen
+geordnet nach Organisation zugreifen</i> indem sie den
+<i>Organisationen</i> Knopf anklicken. Dann wird ihnen eine Liste der
+Organisationen angezeigt.  }
+
+_textHowtolong_ [l=de] { <p>Sie k&ouml;nnen auf <i> Publikationen
+geordnet nach "Wie geht das?" Kategorie zugreifen</i> indem sie den
+<i>Wie geht das?</i> Knopf anklicken. Dann wird ihnen eine Liste der
+"Wie geht das?" Kategorien angezeigt.  }
+
+_textCreatorlong_ [l=de] { <p>Sie k&ouml;nnen auf <i> Publikationen geordnet
+nach Autor zugreifen</i> indem sie den <i>Autor</i> Knopf
+anklicken. Dann wird ihnen eine nach Autor geordnete Liste der
+B&uuml;cher angezeigt.  }
+
+_textTopiclong_ [l=de] {  <p>Sie k&ouml;nnen auf <i> Publikationen geordnet
+nach Thema zugreifen</i> indem sie den <i>Thema</i> Knopf
+anklicken. Dann wird ihnen eine Liste der Themen angezeigt.  }
+
+_textSubjectlong_ [l=de] { <p>Sie k&ouml;nnen auf <i> Publikationen geordnet
+nach Sparte zugreifen</i> indem sie den <i>Sparte</i> Knopf
+anklicken. Dann wird ihnen eine Liste der Sparten angezeigt,
+dargestellt durch B&uuml;cherregale.  }
+
+_textSerieslong_ [l=de] { <p>Sie k&ouml;nnen auf <i> Publikationen geordnet
+nach Serie zugreifen</i> indem sie den <i>Serie</i> Knopf
+anklicken. Dann wird ihnen eine Liste der Serien angezeigt, die sich momentan in der Sammlung befinden.  }
+
+_textDatelong_ [l=de] { <p>Sie k&ouml;nnen auf <i> Publikationen geordnet
+nach Datum zugreifen</i> indem sie den <i>Datum</i> Knopf
+anklicken. Dann wird ihnen eine chronologisch geordnete Liste aller
+Ausgaben angezeigt.  }
+
+_textBrowselong_ [l=de] { <p>Sie k&ouml;nnen durch <i>Publikationen
+st&ouml;bern</i> indem sie den <i>St&ouml;bern</i> Knopf anklicken.  }
+
+_textPeoplelong_ [l=de] { <p>Sie k&ouml;nnen auf <i> Publikationen geordnet
+nach Personen zugreifen</i> indem sie den <i>Personen A-Z</i> Knopf
+anklicken. Dann wird ihnen eine Liste aller Eintr&auml;ge angezeigt,
+die nach Nachnamen geordnet ist.  }
+
+_textdefaultlongtext_ [l=de] { <p>Klicken sie auf den <i>Unbekannt</i> Knopf
+um durch die Publikationen zu st&ouml;bern. In diesem Fall wird die
+Liste nach einem unbekannten Feld sortiert.  }
+
+_texthelptopics_ [l=de] {
+<h2 align=left>Themen</h2>
+<ul>
+  <li><a href="\#finding-information">_textsimplehelpheading_</a>
+  _topicreadingdocs_
+  <li><a href="\#searching">Wie man nach bestimmten W&ouml;rtern suchen kann</a>
+<ul>
+  <li><a href="\#query-terms">Suchbegriffe</a>
+  <li><a href="\#query-type">Typ der Anfrage</a>
+  <li><a href="\#scope-of-queries">Reichweite der Anfragen</a>
+</ul>
+  <li><a href="\#preferences">_textchangeprefs_</a>
+<ul>
+  <li><a href="\#col-prefs">Voreinstellungen zu den Sammlungen</a>
+  <li><a href="\#pres-prefs">Voreinstellungen zur Pr&auml;sentation</a>
+  <li><a href="\#search-prefs">Suchvoreinstellungen</a>
+</ul>
+</ul>
+}
+
+# there are 4 versions of this section of the help text.
+# which version is used is currently set within the server
+# (it should probably use the macro language e.g. [type=book])
+# 1 = html (like fao collections) -- section is empty
+# 2 = book (like hdl collection) -- macros beginning with book
+# 3 = bibliographic (like csbib) -- macros beginning with bib
+# 4 = standard (like gberg) -- the default
+
+_topicreadingdocs_ [l=de] {<li><a href="\#reading-docs">_textreadingdocs_</a>}
+
+_textreadingdocs_ [l=de] {Wie Dokumente gelesen werden k&ouml;nnen}
+_booktextreadingdocs_ [l=de] {Wie B&uuml;cher gelesen werden k&ouml;nnen}
+_bibtextreadingdocs_ [l=de] {Wie man weitere Informationen zu einem
+bibliographischen Eintrag erhalten kann}
+
+_texthelpreadingdocs_ [l=de] {
+<p>_iconblankbar_
+<a name=reading-docs>
+<h2>_textreadingdocs_</h2>
+
+<p> Sie k&ouml;onnen feststellem, dass sie bei einem einzelnen
+Dokument angekommen sind, wenn dessen Titel und Autor links oben auf
+der Seite angezeigt werden. Daneben ist die aktuelle Seitennummer, ein
+K&auml;stchen welches ihnen die Auswahl einer neuen Seite erlaubt und
+vorw&auml;rts und r&uuml;ckw&auml;ts Pfeile.
+
+<p>Darunter ist der Text des aktuellen Abschnitts. Unten befinden befinden
+sich Pfeile, die sie zum n&auml;chsten Abschnitt oder zum vorherigen
+bringen nachdem sie den aktuellen Abschnitt gelesen haben.
+
+<p>Unter dem Titel und dem Namen des Autors befinden sich drei Kn&ouml;pfe.
+Dr&uuml;cken sie auf <i>ganzes Dokument</i>, um den gesamten Text des
+aktuellen Dokuments anzuzeigen. Ist 
+das Dokument umfangreich, so kann der Ladevorgang einige Zeit in
+Anspruch nehmen und es wird viel Arbeitsspeicher benn&ouml;tigt!
+Dr&uuml;cken sie auf <i>neues Fenster</i>, um das Dokument in einem neuen
+Browserfenster zu &ouml;ffnen. (Dies is sinnvoll, wenn sie Dokumente
+vergleichen oder zwei auf einmal lesen wollen.) Wenn sie das Dokument
+aufgrund einer Suche erhalten haben sind die Suchbegriffe
+hervorgehoben. Dr&uuml;cken sie auf <i>nicht hervorheben</i>, um die
+Suchbegriffe normal darzustellen.
+<p>
+<table cellspacing="0" cellpadding="2" border="0">
+<tr><td colspan=2><img src="_httpiconmore_"
+border="0"></td><td>Dr&uuml;cken sie auf den Pfeil, um zum n&auml;chsten
+Abschnitt zu gelangen ...</td></tr>
+<tr><td colspan=2><img src="_httpiconless_" border="0"></td><td>... oder
+zur&uuml;ck zum vorigen Abschnitt</td></tr>
+<tr><td><img src="_document:httpiconealltof_" border="0"></td><td><img 
+src="_document:httpiconetsecof_" border="0"></td><td>Gesamten Text
+darstellen, oder nicht</td></tr>
+<tr><td colspan=2><img src="_document:httpiconedtchof_"
+border="0"></td><td>Diese Seite in einem neuen Fenster &ouml;ffnen</td></tr>
+<tr><td><img src="_document:httpiconehlof_" border="0"></td><td><img
+src="_document:httpiconenhlof_" border="0"></td><td>Suchbegriffe
+hervorheben, oder nicht</td></tr>
+</table>
+
+}
+
+_booktexthelpreadingdocs_ [l=de] {
+<p>_iconblankbar_
+<a name=reading-docs>
+<h2>_textreadingdocs_</h2>
+
+<p>Sie k&ouml;nnen feststellem, dass sie bei einem einzelnen Buch angekommen
+sind, wenn eine Photographie seines Titelbildes links oben auf der Seite
+angezeigt wird. Daneben ist das Inhaltsverzeichnis angezeigt. Ein Pfeil
+markiert wo sie sich befinden. Das Inhaltsverzeichnis kann expandiert
+werden. Dr&uuml;cken sie auf die dargestellten Ordner, um sie zu
+&ouml;ffnen bzw. zu schliessen. Dr&uuml;cken sie auf das offene Buch, um es
+zu schliessen.
+
+<p>Darunter ist der Text des aktuellen Abschnitts. Unten befinden befinden
+sich Pfeile, die sie zum n&auml;chsten Abschnitt oder zum vorherigen
+bringen nachdem sie den aktuellen Abschnitt gelesen haben.
+
+<p>Unter dem Titel und dem Namen des Autors befinden sich vier Kn&ouml;pfe.
+Dr&uuml;cken sie auf <i>ganzes Dokument</i>, um den gesamten Text des
+aktuellen Dokuments oder Buches anzuzeigen. Ist 
+das Buch umfangreich, so kann der Ladevorgang einige Zeit in
+Anspruch nehmen und es wird viel Arbeitsspeicher benn&ouml;tigt!
+Dr&uuml;cken sie auf <i>Verzeichnis expandieren</i>, um das
+Inhaltsverzeichnis des aktuellen Buches vollst&auml;ndig zu
+expandieren. Die Titel aller Kapitel und Unterkapitel werden dann
+angezeigt.
+Dr&uuml;cken sie auf <i>neues Fenster</i>, um das Buch in einem neuen
+Browserfenster zu &ouml;ffnen. (Dies is sinnvoll, wenn sie B&uuml;cher
+vergleichen oder zwei auf einmal lesen wollen.) Wenn sie das Buch
+aufgrund einer Suche erhalten haben sind die Suchbegriffe
+hervorgehoben. Dr&uuml;cken sie auf <i>nicht hervorheben</i>, um die
+Suchbegriffe normal darzustellen.
+
+<p>
+<table cellspacing="0" cellpadding="2" border="0">
+<tr><td colspan=2><img src="_httpiconbshelf_"
+border="0"></td><td>Dieses B&uuml;cherregal &ouml;ffnen</td></tr>
+<tr><td><img src="_httpiconopenbook_" border="0"></td><td><img 
+src="_httpiconbook_" border="0"></td><td>Dieses Buch &ouml;ffnen/schliessen</td></tr>
+<tr><td colspan=2><img src="_httpiconitext_" border="0"></td><td>Diesen Abschnitt des Texts zeigen</td></tr>
+<tr><td><img src="_document:httpiconealltof_" border="0"></td><td><img 
+src="_document:httpiconetsecof_" border="0"></td><td>Gesamten Text
+darstellen, oder nicht</td></tr>
+<tr><td><img src="_document:httpiconeexpcof_" border="0"></td><td><img
+src="_document:httpiconeconcof_" border="0"></td><td>Inhaltsverzeichnis
+expandieren, oder nicht</td></tr>
+<tr><td colspan=2><img src="_document:httpiconedtchof_" border="0"></td><td>Diese Seite in einem neuen Fenster &ouml;ffnen</td></tr>
+<tr><td><img src="_document:httpiconehlof_" border="0"></td><td><img
+src="_document:httpiconenhlof_" border="0"></td><td>Suchbegriffe
+hervorheben, oder nicht</td></tr>
+<tr><td colspan=2><img src="_httpiconmore_" border="0"></td><td>Pfeil
+dr&uuml;cken, um zum n&auml;chsten Abschnitt zu gelangen ...</td></tr>
+<tr><td colspan=2><img src="_httpiconless_" border="0"></td><td>... oder
+zur&uuml;ck zum vorigen Abschnitt</td></tr>
+</table>
+}
+
+_bibtexthelpreadingdocs_ [l=de] {
+<p>_iconblankbar_
+<a name=reading-docs>
+<h2>_textreadingdocs_</h2>
+
+<p> Manche Literatur eintr&auml;e enthalten zus&auml;tzliche Informationen,
+wie z.B. eine Zusammenfassung. Sie k&ouml;nnen am Aussehen der
+Antwortseite, die sie aufgrund ihrer Anfrage erhalten, feststellen, ob
+zus&auml;tzliche Informationen vorliegen. In diesem Fall werden die
+Literatureintr&auml;ge mittels des _icontext_ Ikons anstatt des
+_iconblanktext_ Ikons dargestellt.
+
+<p>Wenn sie auf das _icontext_ Ikon dr&uuml;cken erhalten sie
+zus&auml;tzliche Informationen &uuml;ber den Literatureintrag.
+
+<p> Unter einem Literatureintrag befinden sich zwei
+Kn&oum;pfe. Dr&uuml;cken sie auf <i>neues Fenster</i>, um das Buch in einem
+neuen Browserfenster darzustellen. (Dies ist sinnvoll falls
+Literatureintr&auml;ge vergleichen wollen.)
+Wenn sie den Literatureintrag
+aufgrund einer Suche erhalten haben sind die Suchbegriffe
+hervorgehoben. Dr&uuml;cken sie auf <i>nicht hervorheben</i>, um die
+Suchbegriffe normal darzustellen.
+
+<p>
+<table cellspacing="0" cellpadding="2" border="0">
+<tr><td colspan=2><img src="_document:httpiconedtchof_" border="0"></td><td>Open this page in a new window</td></tr>
+<tr><td><img src="_document:httpiconehlof_" border="0"></td><td><img
+src="_document:httpiconenhlof_" border="0"></td><td>Suchbegriffe
+hervorheben, oder nicht</td></tr> 
+</table>
+}
+
+_texthelpsearching_ [l=de] {
+<h2>Wie sie nach bestimmten Worten suchen k&ouml;nnen</h2>
+<p>
+  Ausgehend von der Suchseite starten sie eine Suchanfrage in den folgenden
+  einfachen Schritten::<p>
+  
+  <ol><li>Spezifizieren sie welche Dokumente sie durchsuchen wollen
+      <li>Sagen sie, ob sie nach allen oder lediglich einigen der
+      Suchbegriffe suchen wollen
+      <li>Geben sie die Suchbegriffe ein
+      <li>Dr&uuml;cken sie den Knopf <i>Starte Anfrage</i>
+  </ol>
+
+<p> Wenn sie eine Anfrage durchf&uuml;hren werden die Titel von zwanzig
+dazu gefundenen Dokumenten angezeigt. Am Ende der Seite befindet sich ein
+Knopf mit dem sie die n&auml;chsten zwanzig Seiten dargestellt
+bekommen. Dort finden sie einen Knopf, der sie zu den n&auml;chsten Zwanzig
+und einen der sie zu den ersten zwanzig bringt, und so fort. Um ein
+beliebiges Dokument zu sehen dr&uuml;cken sie auf seinen Titel  oder den
+kleinen Knopf daneben. 
+
+<p> Gem&auml;ss der Voreinstellungen werden maximal bis zu 100 Dokumente zu
+einer Anfrage zur&uuml;ckgegeben. Sie k&ouml;nnen diese Anzahl &auml;ndern
+inden sie auf den Knopf <i>Voreinstellungen</i> am Kopf der Seite
+dr&uuml;cken.<p> 
+
+<p>_iconblankbar_
+<a name=query-terms>
+<h3>Suchbegriffe</h3>
+
+<p> Was immer sie in das Suchfeld eingeben wird als Liste von Worten
+interpretiert, die "Suchbegriffe" genannt werden. Jeder Begriff darf
+ausschliesslich alphabetische Zeichen und Zahlen enthalten. Begriffe werden
+durch Leerzeichen getrennt. Falls Interpunktionszeichen wie Punkte oder Kommata
+auftauchen, dienen diese dazu, genau wie Leerzeichen, Begriffe zu
+trennen. Im weiteren werden sie nicht weiter beachtet. Sie k&ouml;nnen
+nicht nach Worten suchen die Interpunktionszeichen enthalten!
+
+<p>Beispiel: die Anfrage<p>
+    <ul><kbd>Agro-forestry in the Pacific Islands: Systems for Sustainability (1993)</kbd></ul>
+      <p>wird genauso interpretiert wie<p>
+      <ul><kbd>Agro forestry in the Pacific Islands  Systems for Sustainability  1993 </kbd></ul><p>
+
+<p>_iconblankbar_
+<a name=query-type>
+<h3>Anfragearten</h3>
+
+<p>Es gibt zwei unterschiedliche Arten von Anfragen.
+
+<ul>
+  <li>Anfragen nach <b>allen</b> eingegebenen Suchbegriffen. Anfragen
+  dieser Art suchen nach Dokumenten, die alle eingegebenen Suchbegriffe
+  beinhalten. Dokumente, die der Anfrage gen&uuml;gen werden in
+  alphabetischer Reihenfolge dargestellt.<p>
+
+  <li>Anfragen nach <b>einigen</b> der eingegebenen Suchbegriffen. Geben
+      sie einfach einige der Begriffe an, die m&ouml;glicherweise in den
+      Dokumenten enthalten sind nach denen sie suchen. Die Dokumente werden
+      in der Reihenfolge dargestellt je nachdem wie stark sie die
+      Suchanfrage erf&uuml;llen. Der Grad des Erf&uuml;llens der
+      Suchanfrage wird folgendermassen bestimmt.
+      <p><ul>
+        <li> Je mehr Suchbegriffe ein Dokument enth&auml;lt desto besser
+      erf&uuml;llt es die Anfrage.
+        <li> Seltene Begriffe sind wichtiger als sehr oft vorkommende.
+        <li> Kurze Dokumente erf&uuml;llen Anfragen besser als lange.
+      </ul>
+</ul>
+
+<p> Benutzen sie so viele Suchbegriffe wie sie wollen -- einen ganzen Satz
+oder gar einen ganzen Absatz. Falls sie nur einen einzigen Suchbegriff
+angeben werden die Dokumente nach der H&auml;ufigkeit dessen Auftauchens
+sortiert.<p>
+_texthelpscope_
+}
+
+_textchangeprefs_ [l=de] {&Auml;ndern ihrer Voreinstellungen}
+
+_texthelppreferences_ [l=de] {<h2>_textchangeprefs_</h2>
+
+<p>Wenn sie den Knopf <i>Voreinstellungen</i> am Kopf der Seite
+dr&uuml;cken, k&ouml;nnen sie einige Eigenschaften der
+Benutzerschnittstelle so ver&auml;ndern, dass sie ihren Anforderungen
+entspricht. 
+
+<p>_iconblankbar_
+<a name=col-prefs>
+<h3 align=left>Kollektionsvoreinstellungen</h3>
+
+Einige Kollektionen enthalten mehrere Unterkollektionen welche entwerder
+unabh&auml;ngig oder gemeinsam als eine Einheit durchsucht werden
+k&ouml;nnen. Falls dem so ist, k&ouml;nnen sie auf der Voreinstellungsseite
+festlegen, welche der Unterkollektionen im Rahmen ihrer Anfragen
+ber&uuml;cksichtigt werden sollen.
+
+<p>_iconblankbar_
+<a name=pres-prefs>
+<h3 align=left>Darstellungsvoreinstellungen</h3>
+
+Je nach vorliegender Kollektion k&ouml;nnen verschiedene Optionen
+eingestellt werden, die die Art der Darstellung beeinflussen.
+
+Kollektionen von Webseiten gestatten es ihnen die Darstellung der 
+Greenstonenavigationsleiste, die sich am Kopf jeder Dokumentseite befindet
+zu unterdr&uuml;cken. Auf diese Weise endet ihre Anfrage direkt auf der
+Webseite, die ihre Anfrage erf&uuml;llt, ohne dass der Greenstoneseitenkopf
+dargestellt wird. Um in diesem Falle eine weitere Suche durchf&uuml;hren zu
+k&ouml;nnen m&uuml;ssen sie den "Zur&uuml;ck" Knopf ihres Browsers
+bet&auml;tigen. Diese Art der Kollektionen erlaubt es ihnen auch die
+Greenstonewarnmeldungen zu unterdr&uuml;cken, die gezeigt werden, wenn sie
+einen Link verfolgen, der aus der Greenstonekollektion in das World-Wide
+Web f&uuml;hrt. Weiterhin k&ouml;nnen sie in manchen Webkollektionen
+einstellen, ob sie die Links auf der Ergebnisseite anstatt zur lokal in
+der Kollektion gespeicherten Kopie direkt zur Originalwebseite f&uuml;hren
+sollen. 
+
+Kollektionen, die in verschiedenen Sprachen dargestellt werden k&ouml;nnen,
+erlauben ihnen die Wahl der in der Benutzerschnittstelle zu verwendenden
+Sprache. Ist die gew&auml;hlte Sprache Chinesisch, so k&ouml;nnen sie
+ausserdem feststellen, welche der Standardkodierungen f&uuml;r Chinesisch
+ihr Browser verwendet.
+
+Schliesslich erlauben ihnen alle Kollektionen anstatt der graphischen
+Standardschnittstelle eine textuelle Schnittstelle zu verwenden. Dies ist
+besonders f&uuml;r sehbehinderte Benutzer, die auf die Verwendung grosser
+Zeichens&auml;tze oder von Ger&auml;ten zur Sprachausgabe angewiesen sind,
+sinnvoll.
+
+<p>_iconblankbar_
+<a name=search-prefs>
+<h3 align=left>Suchvoreinstellungen</h3>
+Zwei Knopfpaare steuern, ob bei ihren Anfragen Gross- und Kleinschreibung
+beachtet wird, und ob Wortst&auml;mme Verwendung finden. Die ersten beiden
+Kn&ouml;pfe steuern, ob Gross- und Kleinbuchstanben zwischen ihrer Anfrage
+und den Dokumententextem &uuml;bereinstimmen m&uuml;ssen. Die zweiten
+beiden Kn&ouml;pfe bestimmen, ob Wortenden bei der Suche ignoriert werden
+oder nicht. 
+
+<p>Beispiel: wenn die Kn&ouml;pfe <i>ignoriere Gross-/Kleinschreibung</i> und
+<i>ignoriere Wortendungen</i> angew&aauml;hlt sind, wird die Anfrage<p>
+    <ul><kbd>African buildings</kbd></ul>
+      <p>genauso behandelt wie die Anfrage<p>
+      <ul><kbd>africa build</kbd>,</ul><p>
+      da der Grossbuchstabe in "African" zu einem Kleinbuchstaben
+      transformiert wird und die Endungen "n" and "ing" von
+      "African" und "building" entfernt werden (ausserdem wird "s" von
+      "builds" entfernt).
+
+<p>Sie k&ouml;nnen auch auf einen komplexeren Anfragemodus umschalten,
+welcher es ihnen gestattet Begriffe zu kombinieren indem sie sie mittels
+der Operatoren AND (&), OR (|), und NOT (!) verkn&uuml;pfen. Dies erlaubt
+es ihnen pr&auml;zisere Anfragen zu spezifizieren.
+
+<p>Schliesslich k&ouml;nnen sie die Anzahl der als Antwort
+zur&uuml;ckgegebenen passenden Dokumente und  der
+auf einer Seite dargestellten Dokumente einstellen.
+
+}
+
+_texttanumbrowseoptions_ [l=de] {Es gibt _numbrowseoptions_ Arten Informationen in
+dieser Kollektion zu finden:}
+
+_textsimplehelpheading_ [l=de] {Wie man Informationen findet}
+
+_texthelpscope_ [l=de] {
+<p>_iconblankbar_
+<a name=scope-of-queries>
+<h3 align=left>Reichweite der Anfragen</h3>
+
+<p> In den meisten Kollektionen k&ouml;nnen sie in verschiedenen Indexen
+suchen. Es kann zum Beispiel einen Autoren- und einen Titelindex
+geben. Oder es gibt einen Kapitel- und einen Paragraphenindex. In jedem
+Fall wird zu ihrer Anfrage passendes Dokument immer vollst&auml;ndig
+zur&uuml;ckgegeben egal welchen Index sie zur Suche verwendet haben.
+<p>Sollte es sich bei Dokumenten um B&uuml;cher handeln, so werden sie immer
+an der passenden Stelle (in der Kollektion) ge&ouml;ffnet.
+}
Index: /main/tags/2.25/gsdl/macros/gsdl.dm
===================================================================
--- /main/tags/2.25/gsdl/macros/gsdl.dm	(revision 21064)
+++ /main/tags/2.25/gsdl/macros/gsdl.dm	(revision 21064)
@@ -0,0 +1,125 @@
+package gsdl
+
+
+#######################################################################
+# java images/scripts
+#######################################################################
+
+# the _javalinks_ macros are the flashy image links at the top right of
+# the page. 
+
+_javalinks_ {_imagehome_}
+_javalinks_ [v=1] {
+_imagehome_<br>
+}
+
+#######################################################################
+# page content
+#######################################################################
+
+_httpgsdlmanual_ {_httppublications_/gsdl_manual.pdf}
+
+_pagetitle_ {Greenstone Digital Library Software}
+
+_imagethispage_ {_imagegreenstone_}
+
+_content_ {
+_iconblankbar_
+<h2>Greenstone Digital Library Software</h2>
+
+<p>
+The Greenstone Digital Library software provides a new way of
+organizing information and making it available over the Internet or on
+CD-ROM. 
+<p>
+A digital library is made up of a set of collections. 
+Each collection of information comprises several 
+(typically several thousand, or even several million) documents, 
+which share a uniform searching and browsing interface. 
+Collections can be organized in many different ways while 
+retaining a strong family resemblance. 
+Numerous examples are hosted at the New Zealand Digital Library Project
+web site (<a href="http://www.nzdl.org">http://www.nzdl.org</a>).
+<p>
+Although primarily designed for access over the Web, 
+Greenstone collections can be made available,
+in precisely the same form, on CD-ROM for standalone PCs.  
+Greenstone CDs work with any version of Microsoft Windows.
+<p>
+Greenstone is open-source software, 
+available under the terms of the GNU General Public License. 
+The latest version can always be
+<a href="http://www.nzdl.org/html/DOWNLOAD.html">downloaded</a>
+from
+<a href="ftp://nzdl.org/pub/gsdl/">ftp://nzdl.org/pub/gsdl/</a>.
+Documentation is available in the form of 
+the Greenstone Digital Library Software manual.
+<p>
+
+<center><table><tr align=center valign=center>
+<td>_home:iconpdf_</td>
+<td><a href=_httpgsdlmanual_>Manual</a></td>
+<td width=10>&nbsp;</td>
+<td>_home:iconpdf_</td>
+<td><a href="_httppublications_/NZDLtext.pdf">_home:textinfosheet_</a></td>
+<td width=10>&nbsp;</td>
+<td>_home:iconpdf_</td>
+<td><a href="_httppublications_/NZDLpictures.pdf">Screenshots</a></td>
+</tr></table></center>
+
+<p>
+_iconblankbar_
+<p>
+There is now a mailing list for Greenstone, intended primarily for
+discussions about the digital library software developed by the New Zealand
+Digital Library project.  If you are, or plan to be, an active user of
+Greenstone, you should consider joining the mailing list and contributing
+to the discussions.
+<p>
+This mailing list is hosted by the Pathfinder Library System in beautiful
+Grand Junction, Colorado (John Campbell, john@colosys.net).  To subscribe,
+send email to <a
+href="mailto:majordomo@colosys.net">majordomo@colosys.net</a> with the text
+<blockquote>
+subscribe greenstone
+</blockquote>
+(no subject, no name, nothing else).  To send a message to the list,
+address it to <a
+href="mailto:greenstone@colosys.net">greenstone@colosys.net</a>.
+
+<p>
+_iconblankbar_
+<p>
+<h2>Credits</h2>
+<p>
+Greenstone Digital Library Software is produced by the New Zealand Digital
+Library project.  The current software was designed and implemented by
+Rodger McNab, Stefan Boddie, Bill Rogers, Hong Chen and Stuart Inglis, and
+has benefited greatly from previous versions constructed by Craig
+Nevill-Manning and Todd Reed and previous interface designs by Che
+Tamahere.
+<p>
+The New Zealand Digital Library project is directed by Ian Witten and
+involves Mark Apperley, David Bainbridge, Sally Jo Cunningham, Steve Jones,
+Te Taka Keegan, Malika Mahoui and Lloyd Smith as principal investigators.
+Other researchers who have contributed to the project include Carl Gutwin,
+Rob Holte, Gordon Paynter and Bill Teahan.
+<p>
+Greenstone Digital Library Software uses the MG search engine produced
+principally by Alistair Moffat at the University of Melbourne and described
+in the book <i>Managing Gigabytes: Compressing and indexing documents and
+images</i> by Ian H. Witten, Alistair Moffat, and Tim C. Bell (Van Nostrand
+Reinhold, 1994).
+<p>
+_iconblankbar_
+<p>
+<table>
+<tr valign=top>
+<td>_home:textpoem_</td>
+<td>_imagegreenstone_</td>
+</tr></table>
+<p>_home:textgreenstone_
+
+_nzdlpagefooter_
+<br>April 2000
+}
Index: /main/tags/2.25/gsdl/macros/help.dm
===================================================================
--- /main/tags/2.25/gsdl/macros/help.dm	(revision 21064)
+++ /main/tags/2.25/gsdl/macros/help.dm	(revision 21064)
@@ -0,0 +1,28 @@
+package help
+
+_imagethispage_ {_iconthispage_}
+_iconthispage_ {<img src="_httpiconhhelp_" alt="_textHelp_" width=_widthhhelp_ height=_heighthhelp_>}
+
+_textnumbrowseoptions_ {_If_("_numbrowseoptions_" != "1",<p>_texttanumbrowseoptions_)}
+
+_simplehelp_ {
+_textnumbrowseoptions_
+_textbrowseoptions_
+}
+
+_content_ {
+<center>_navigationbar_</center>
+_texthelptopics_
+<p>_iconblankbar_
+<a name=finding-information>
+<h2>_textsimplehelpheading_</h2>
+_simplehelp_
+_texthelpreadingdocs_
+<p>_iconblankbar_
+<a name=searching>
+_texthelpsearching_
+<p>_iconblankbar_
+<a name=preferences>
+_texthelppreferences_
+<p>_iconblankbar_
+}
Index: /main/tags/2.25/gsdl/macros/home.dm
===================================================================
--- /main/tags/2.25/gsdl/macros/home.dm	(revision 21064)
+++ /main/tags/2.25/gsdl/macros/home.dm	(revision 21064)
@@ -0,0 +1,83 @@
+package home
+
+#######################################################################
+# java images/scripts
+#######################################################################
+
+# the _javalinks_ macros are the flashy image links at the top right of
+# the page. this is overridden here as we don't want 'home' 
+# links on this page
+
+_javalinks_ {}
+_javalinks_ [v=1] {}
+
+#######################################################################
+# icons
+#######################################################################
+
+_iconnzdl_ {<img src="_httpiconnzdl_" width=_widthnzdl_ height=_heightnzdl_ alt="The New Zealand Digital Library">}
+_icongbull_ {<img src="_httpicongbull_">}
+_iconpdf_ {<img src="_httpiconpdf_">}
+_iconselectcollection_ {<img src="_httpiconselcolgr_" width=_widthselcolgr_ height=_heightselcolgr_ alt=_altselcolgr_>}
+_iconmusiclibrary_ {<img src="_httpicontmusic_" border=1 alt="meldex music library">}
+
+#######################################################################
+# http macros 
+#
+# These contain the url without any quotes
+#######################################################################
+
+_httpicongbull_ {_httpimg_/gbull.gif}
+
+_httpiconpdf_ {_httpimg_/pdf.gif}
+
+_httpicontmusic_ {_httpimg_/meldexsm.gif}
+
+#######################################################################
+# page content                     
+#######################################################################
+
+_pagetitle_ {_textpagetitle_}
+_imagethispage_ {}
+_imagecollection_ { }
+
+_content_ {
+<center>
+<p>_iconselectcollection_
+</center>
+<p>_homeextra_
+
+<center>
+<p>_iconblankbar_
+</center>
+<p><center><h2>_textprojhead_</h2></center>
+
+<table border=0 cellpadding=5>
+
+<tr valign=top>
+<td>
+<table><tr valign=middle><td>_icongbull_</td><td><a href="mailto:_mailaddr_">_textfb_</a></td></tr></table>
+<table><tr valign=middle><td>_icongbull_</td><td><a href="http://www.nzdl.org">NZDL</a></td></tr></table>
+<table><tr valign=middle><td>_icongbull_</td><td><a href="_httppagex_(gsdl)">Greenstone</a></td></tr></table>
+<table><tr valign=middle><td>_iconpdf_</td><td><a href="_gsdl:httpgsdlmanual_">Manual</a></i></td></tr></table>
+<table><tr valign=middle><td>_iconpdf_</td><td><a href="_httppublications_/NZDLtext.pdf">_textinfosheet_</a></td></tr></table>
+<p><a href="_httppagestatus_"><img src="_httpimg_/tabspace.gif" width=60 height=20 border=0></a>
+</td>
+<td>_textprojinfo_</td>
+</tr></table>
+
+<p>_iconblankbar_
+<table>
+<tr valign=top>
+<td>_textpoem_</td>
+<td>_imagegreenstone_</td>
+</tr></table>
+<p>_textgreenstone_
+
+<p>
+<p>_iconblankbar_
+<p>Greenstone software by <a href="http://www.nzdl.org">The New Zealand Digital Library Project</a>,
+<br><a href="http://www.cs.waikato.ac.nz/cs">Department of Computer Science</a>, 
+<a href="http://www.waikato.ac.nz">University of Waikato</a>, 
+New Zealand
+}
Index: /main/tags/2.25/gsdl/macros/html.dm
===================================================================
--- /main/tags/2.25/gsdl/macros/html.dm	(revision 21064)
+++ /main/tags/2.25/gsdl/macros/html.dm	(revision 21064)
@@ -0,0 +1,57 @@
+package html
+
+_header_ {<html>
+<head></head>
+}
+
+_footer_ {</html>}
+
+_pagetitle_ {_collectionname_}
+
+_content_ {
+<frameset rows="68,*" noresize border=0>
+  <frame frameborder=0 src="_gwcgi_?e=_compressedoptions_&a=p&p=nav">
+  <frame frameborder=0 src="_cgiarghp_">
+  <noframes>
+  <p>_textframebrowser_</p>
+  </noframes>
+</frameset>
+}
+
+
+package nav
+
+_header_ {_cgihead_
+_htmlhead_
+<center>
+<table width=_pagewidth_><tr><td align=right>
+_javalinks_</td></tr></table>
+</center>
+}
+
+_faoheader_ [v=1] {_cgihead_
+_htmlhead_
+_javalinks_
+}
+
+_htmlhead_ {
+<html>
+<head>
+<title>_pagetitle_</title>
+<base target="_top">
+_globalscripts_
+</head>
+
+<body bgcolor="\#ffffff" text="\#000000" link="\#006666" 
+      alink="\#cc9900" vlink="\#666633">
+}
+
+_footer_ {</body>
+</html>
+}
+
+_content_ {
+<center>
+_navigationbar_
+</center>
+}
Index: /main/tags/2.25/gsdl/macros/maori.dm
===================================================================
--- /main/tags/2.25/gsdl/macros/maori.dm	(revision 21064)
+++ /main/tags/2.25/gsdl/macros/maori.dm	(revision 21064)
@@ -0,0 +1,405 @@
+######################################################################
+#
+# Maori Language text and icon macros 
+#
+######################################################################
+
+
+######################################################################
+# Global (base) package
+package Global
+######################################################################
+
+#------------------------------------------------------------
+# text macros
+#------------------------------------------------------------
+
+# macron macro defaults (currently default to umlauts)
+_Amn_ {&Auml;}
+_amn_ {&auml;}
+_Emn_ {&Euml;}
+_emn_ {&euml;}
+_Imn_ {&Iuml;}
+_imn_ {&iuml;}
+_Omn_ {&Ouml;}
+_omn_ {&ouml;}
+_Umn_ {&Uuml;}
+_umn_ {&uuml;}
+
+_textimagehelp_ [l=mi] {Te wh_amn_rangi whakam_amn_rama}
+_textimagepref_ [l=mi] {Te wh_amn_rangi o ng_amn_ whiriwhiringa}
+_textimagehome_ [l=mi] {Te wh_amn_rangi k_amn_inga}
+_textimagesearch_ [l=mi] {rapua he kupu}
+_textimagebrowseseries_ [l=mi] {Tirohia te whakar_amn_rangi o ng_amn_ niupepa}
+_textimagebrowsedates_ [l=mi] {Tirohia te w_amn_ i puta mai ai ng_amn_ niupepa}
+
+_page_ [l=mi] {wh_amn_rangi }
+_pages_ [l=mi] {wh_amn_rangi}
+_vol_ [l=mi] {Pukapuka}
+_num_ [l=mi] {Nama}
+_textmonth01_ [l=mi] {Hanuere}
+_textmonth02_ [l=mi] {Pepuere}
+_textmonth03_ [l=mi] {Maehe}
+_textmonth04_ [l=mi] {Aperira}
+_textmonth05_ [l=mi] {Mei}
+_textmonth06_ [l=mi] {Hune}
+_textmonth07_ [l=mi] {Hurae}
+_textmonth08_ [l=mi] {Akuhata}
+_textmonth09_ [l=mi] {Hepetema}
+_textmonth10_ [l=mi] {Oketopa}
+_textmonth11_ [l=mi] {Noema}
+_textmonth12_ [l=mi] {Tihema}
+_of_ [l=mi] { i te }
+
+
+_texticontabsearchgreen_ [l=mi] {rapu}
+_texticontabdatesgreen_ [l=mi] {w_amn_taka}
+_texticontabseriesgreen_ [l=mi] {whakar_amn_rangi niupepa}
+_texticonnext_ [l=mi] {titiro ki te wh_amn_rangi o muri}
+_texticonprev_ [l=mi] {titiro ki te wh_amn_rangi o mua}
+_texticontext_ [l=mi] {Tirohia te wh_amn_rangi}
+
+_textimageSeries_ [l=mi] {Tirohia te whakar_amn_rangi taitara}
+_textimageDate_ [l=mi] {Tirohia te whakar_amn_rangi w_amn_taka}
+
+
+#------------------------------------------------------------
+# icons
+#------------------------------------------------------------
+
+_httpiconchomeof_ [l=mi] {_httpimg_/mi/chomeof.gif}
+_httpiconchomeon_ [l=mi] {_httpimg_/mi/chomeon.gif}
+_widthchomex_ [l=mi] {54}
+
+_httpiconchelpof_ [l=mi] {_httpimg_/mi/chelpof.gif}
+_httpiconchelpon_ [l=mi] {_httpimg_/mi/chelpon.gif}
+_widthchelpx_ [l=mi] {57}
+
+_httpiconcprefof_ [l=mi] {_httpimg_/mi/cprefof.gif}
+_httpiconcprefon_ [l=mi] {_httpimg_/mi/cprefon.gif}
+_widthcprefx_ [l=mi] {103}
+
+_httpicontsergr_ [l=mi] {_httpimg_/mi/tsergr.gif}
+_httpicontserof_ [l=mi] {_httpimg_/mi/tserof.gif}
+_httpicontseron_ [l=mi] {_httpimg_/mi/tseron.gif}
+_widthtserx_ [l=mi] {192}
+
+_httpicontdategr_ [l=mi] {_httpimg_/mi/tdategr.gif}
+_httpicontdateof_ [l=mi] {_httpimg_/mi/tdateof.gif}
+_httpicontdateon_ [l=mi] {_httpimg_/mi/tdateon.gif}
+
+_httpicontsrchgr_ [l=mi] {_httpimg_/mi/tsrchgr.gif}
+_httpicontsrchof_ [l=mi] {_httpimg_/mi/tsrchof.gif}
+_httpicontsrchon_ [l=mi] {_httpimg_/mi/tsrchon.gif}
+
+
+######################################################################
+# 'about' page
+package about
+######################################################################
+
+#------------------------------------------------------------
+# text macros
+#------------------------------------------------------------
+
+_textabcol_ [l=mi] {He kupu whakam_amn_rama i te kohikohinga niupepa}
+
+
+#------------------------------------------------------------
+# icons
+#------------------------------------------------------------
+
+_httpiconhabout_ [l=mi] {_httpimg_/mi/h\_about.gif}
+_widthhabout_ [l=mi] {262}
+
+
+######################################################################
+# document package
+package document
+######################################################################
+
+#------------------------------------------------------------
+# text macros
+#------------------------------------------------------------
+
+_texticondetach_ [l=mi] {Huakina mai he matapihi hou m_omn_ t_emn_nei k_omn_rero}
+_texticonexpandtext_ [l=mi] {Titiro ki ng_amn_ kupu katoa o t_emn_nei niupepa}
+_texticoncontracttext_ [l=mi] {Titiro ki ng_amn_ kupu o t_emn_nei wh_amn_rangi anake}
+_texticonopenbookshelf_ [l=mi] {k_amn_tia}
+_texticonclosedbookshelf_ [l=mi] {whakat_umn_whera mai}
+_texticonclosedbook_ [l=mi] {whakat_umn_whera mai}
+_texticonopenbook_ [l=mi] {k_amn_tia}
+_texticonpointer_ [l=mi] {w_amn_hanga e tiro ana}
+_texticonhighlight_ [l=mi] {Kia p_umn_kaha ng_amn_ kupu rapu}
+_texticonnohighlight_ [l=mi] {Kia kore he p_umn_kaha}
+_texticonsmalltext_ [l=mi] {He wh_amn_rangi niupepa}
+_texticonclosedfolder_ [l=mi] {He k_omn_paki}
+
+_textgoto_ [l=mi] {poka noa ki}
+
+#------------------------------------------------------------
+# icons
+#------------------------------------------------------------
+
+_httpiconhser_ [l=mi] {_httpimg_/mi/h\_ser.gif}
+_widthhser_ [l=mi] {310}
+
+_httpiconhdate_ [l=mi] {_httpimg_/mi/h\_date.gif}
+
+_httpiconealltof_ [l=mi] {_httpimg_/mi/ealltof.gif}
+_httpiconeallton_ [l=mi] {_httpimg_/mi/eallton.gif}
+
+_httpiconedtchof_ [l=mi] {_httpimg_/mi/edtchof.gif}
+_httpiconedtchon_ [l=mi] {_httpimg_/mi/edtchon.gif}
+
+_httpiconetsecof_ [l=mi] {_httpimg_/mi/etsecof.gif}
+_httpiconetsecon_ [l=mi] {_httpimg_/mi/etsecon.gif}
+
+_httpiconehlof_ [l=mi] {_httpimg_/mi/ehlof.gif}
+_httpiconehlon_ [l=mi] {_httpimg_/mi/ehlon.gif}
+
+_httpiconenhlof_ [l=mi] {_httpimg_/mi/enhlof.gif}
+_httpiconenhlon_ [l=mi] {_httpimg_/mi/enhlon.gif}
+
+
+######################################################################
+# 'home' page
+package home
+######################################################################
+
+#------------------------------------------------------------
+# text macros
+#------------------------------------------------------------
+
+
+#------------------------------------------------------------
+# icons
+#------------------------------------------------------------
+
+
+######################################################################
+# 'help' page
+package help
+######################################################################
+
+#------------------------------------------------------------
+# text macros
+#------------------------------------------------------------
+
+_texttanumbrowseoptions_ [l=mi] {E _numbrowseoptions_ ng_amn_ huarahi hei rapu k_omn_rero i te kohikohinga niupepa}
+
+_textHelp_ [l=mi] {_Amn_whina}
+_textSearchshort_ [l=mi] {rapua he kupu}
+
+_textSeriesshort_ [l=mi] {tirohia te whakar_amn_rangi taitara}
+
+_textDateshort_ [l=mi] {tirohia te whakar_amn_rangi e p_amn_ ana ki te w_amn_}
+
+
+_textSearchlong_ [l=mi] {
+<p>Ko te wh_amn_rangi rapu te wh_amn_rangi <i>e rapu atu ai ng_amn_ kupu</i> i roto
+i ng_amn_ tuhinga. Kia puta mai ai t_emn_nei wh_amn_rangi, i a koe e titiro ana ki 
+te kohinga niupepa nei p_amn_whiritia te p_amn_tene <i>rapu</i>.
+}
+
+
+_textSerieslong_ [l=mi] {
+<p>Kia <i>tirohia te whakar_amn_rangi taitara</i> p_amn_whiritia te p_amn_tene 
+<i>whakar_amn_rangi taitara</i>. Ka puta mai te whakar_amn_rangi o ng_amn_
+niupepa e p_amn_ ana ki ng_amn_ taitara.
+}
+
+_textDatelong_ [l=mi] {<p>Kia <i>tirohia te whakar_amn_rangi e p_amn_ ana ki te w_amn_</i> p_amn_whiritia te
+p_amn_tene <i>w_amn_taka</i>. Ka puta mai te whakar_amn_rangi o ng_amn_ niupepa
+e p_amn_ ana ki te w_amn_ i puta mai ai aua niupepa.
+}
+
+_texthelptopics_ [l=mi] {
+<h2 align=left>Kaupapa</h2>
+<ul>
+  <li><a href="\#finding-information">Ng_amn_ huarahi hei rapu k_omn_rero</a>
+  <li><a href="\#reading-books">Te p_amn_nui niupepa/kupu whakataki</a>
+  <li><a href="\#searching">Te rapu kupu</a>
+<ul>
+  <li><a href="\#query-terms">Ng_amn_ kupu hei rapu</a>
+  <li><a href="\#query-type">Ng_amn_ t_umn_momo rapu</a>
+  <li><a href="\#scope-of-queries">Te wh_amn_nui o te rapu</a>
+  <li><a href="\#stemming">Ng_amn_ p_umn_ matua, p_umn_ iti me ng_amn_ k_umn_muri hoki</a>
+</ul>
+</ul>
+}
+
+_texthelpsearching_ [l=mi] {
+<h2>Te rapu kupu</h2>
+<p>
+  Ko te wh_amn_rangi rapu te wh_amn_rangi hei rapu kupu. Ka puta mai taua wh_amn_rangi ka
+  whai mai _emn_nei k_omn_kiri kia rapu ai i (t)_emn_tehi kupu:<p>	
+
+  <ol><li>K_omn_whiritia ko ng_amn_ niupepa, ko ng_amn_ kupu whakataki r_amn_nei, 
+	ko ng_amn_ r_amn_popoto reo P_amn_keh_amn_, ko aua mea e toru r_amn_nei
+      <li>K_omn_whiritia ko _emn_tehi o ng_amn_ kupu rapu, ko te katoa r_amn_nei o ng_amn_
+          kupu rapu
+      <li>Tuhia ng_amn_ kupu rapu
+      <li>Pat_omn_hia te p_amn_tene <i>Rapua</i>
+  </ol>
+<p>Ka tukua te rapu ka hoki mai ng_amn_ pukapuka rua tekau e p_amn_ ana ki _amn_u kupu rapu.
+He p_amn_tene kei raro r_amn_ o te wh_amn_rangi hei titiro ai ki ng_amn_ pukapuka 21 ki te
+40 e p_amn_ ana ki _amn_u kupu rapu. M_amn_ _emn_nei p_amn_tene kei raro r_amn_ ka taea
+te tirohia te katoa o ng_amn_ wh_amn_rangi e p_amn_ ana ki t_amn_u i rapu ai.
+
+<p>Ka kore e nuku atu i te 100 o ng_amn_ pukapuka ka kitea i t_emn_tehi rapunga. Heoi an_amn_
+ka taea te whakarerek_emn_ t_emn_nei nama i te wh_amn_rangi whiriwhiringa.
+
+<p>
+<a name=query-terms>
+_iconblankbar_<br>
+
+<h3>Ng_amn_ kupu hei rapu</h3>
+
+<p>Koia nei ng_amn_ kupu ka tuhia ki roto i te pouaka rapu. Me tuhi ko ng_amn_ reta me ng_amn_
+nama anak_emn_. Kaua e tuhia ng_amn_ tohu t_omn_, he uaua te kite i ng_amn_ tohu t_omn_ i roto 
+i ng_amn_ niupepa. Me noho te mokow_amn_ (w_amn_hi w_amn_tea) i waenganui i ng_amn_ kupu.
+Kaua e tuhi ng_amn_ tuhutuhi (p_emn_r_amn_ i te "?" me te "/"), ka tangohia aua tohu e te
+rorohiko nei, ka whakauru ko te mokow_amn_.
+
+<p>Hei tauira, ki te tuku atu i _emn_nei kupu rapu;
+    <ul><kbd>huihuinga-a-motu / Whanganui (1860-1885)</kbd></ul>
+       <p>ka rapua k_emn_tia e te rorohiko _emn_nei kupu;
+    <ul><kbd>huihuinga a motu Whanganui 1860 1885</kbd></ul><p>
+
+<p>
+<a name=query-type>
+_iconblankbar_<br>
+
+<h3>Ng_amn_ T_umn_momo Rapu</h3>
+
+<p><ul>E rua ng_amn_ t_umn_momo rapu<p>
+
+  <li>Ka rapua te <b>katoa</b> o _amn_u kupu rapu. Ka rapua ng_amn_ pukapuka e mau ana i te katoa
+      o ng_amn_ kupu rapu kua tuhia e koe. Ka whakaatu mai aua pukapuka e p_amn_ ana ki te 
+      whakar_amn_rangi-_amn_-p_umn_.
+
+  <li>Ka rapua <b>_emn_tehi</b> o _amn_u kupu rapu. N_omn_ reira, me tuhi noa he kupu e p_amn_
+      ana ki te kaupapa e hiahia ana koe. Ka whakar_amn_rangitia ng_amn_ pukapuka e p_amn_ ana
+      ki te ritenga ki _amn_u kupu rapu. Ar_amn_, ka puta tuatahitia mai ng_amn_ pukapuka;	 
+
+      <p><ul>
+        <li> e mau ana i te maha o _amn_u kupu rapu;
+        <li> e mau ana i ng_amn_ kupu uaua te kite o _amn_u kupu rapu;
+        <li> e iti ana, ka whai mai ko ng_amn_ pukapuka nui.
+      </ul>
+
+      <p>Me tuhi i te maha o ng_amn_ kupu rapu kia arahina te rapu ki t_omn_ ake hiahia.
+</ul>
+
+<p>
+<a name=other-options><a name=scope-of-queries>
+_iconblankbar_<br>
+
+_texthelpscope_
+
+<h3 align=left>Ng_amn_ p_umn_ matua, p_umn_ iti me ng_amn_ k_umn_muri hoki</h3>
+
+<p>Pat_omn_hia te p_amn_tene whiriwhiringa kia puta mai ai te wh_amn_rangi e p_amn_
+ana ki ng_amn_ p_umn_ matua, p_umn_ iti me ng_amn_ k_umn_muri hoki. Ka h_amn_ngai
+te whiriwhiringa tuatahi ki ng_amn_ p_umn_ matua me ng_amn_ p_umn_ iti. _Amn_e
+r_amn_nei, me tika te p_umn_ matua me te p_umn_ iti, k_amn_ore r_amn_nei, hei aha
+te _amn_ta titiro ki ng_amn_ p_umn_ matua me ng_amn_ p_umn_ iti. Ka h_amn_ngai te
+whiriwhiringa tuarua ki ng_amn_ k_umn_muri o te kupu. _Amn_e r_amn_nei, me tino
+_omn_rite te k_umn_muri, k_amn_ore r_amn_nei, hei aha te _amn_ta titiro ki ng_amn_ 
+k_umn_muri o ng_amn_ kupu. M_omn_ ng_amn_ kupu P_amn_keh_amn_ anak_emn_ te 
+whiriwhiringa k_umn_muri.
+
+<p>Hei tauira, mehemea ka k_omn_whiritia te <i>hei aha te p_umn_ matua me te p_umn_
+iti</i>, _amn_, ka k_omn_whiritia hoki te <i>hei aha te k_umn_muri o te kupu</i>
+k_amn_tahi ka tukua _emn_nei kupu hei rapu;
+<p>
+  <ul><kbd>Aotearoa building</kbd></ul>
+    <p>ka _omn_rite te whakahoki mai o ng_amn_ pukapuka ki _emn_nei kupu rapu
+  <ul><kbd>aotearoa builds</kbd></ul>
+<p>ka p_emn_nei i te mea, k_amn_ore te rapu i te _amn_ta titiro mehemea he p_umn_
+matua, he p_umn_ iti r_amn_nei, _amn_, ka tangohia ng_amn_ k_umn_muri (p_emn_r_amn_
+i te "ing", me te "s") i t_emn_nei whiriwhiringa.
+
+}
+
+_textsimplehelpheading_ [l=mi] {Ng_amn_ huarahi hei rapu k_omn_rero}
+
+_textnextbutton_ [l=mi] {Haere whakamua}
+_textprevbutton_ [l=mi] {Haere whakamuri}
+
+
+#------------------------------------------------------------
+# icons
+#------------------------------------------------------------
+
+_httpiconhhelp_ [l=mi] {_httpimg_/mi/h\_help.gif}
+
+
+######################################################################
+# 'search' page
+package query
+######################################################################
+
+#------------------------------------------------------------
+# text macros
+#------------------------------------------------------------
+
+_texticonthispage_ [l=mi] {rapu}
+_textsome_ [l=mi] {_emn_tehi}
+_textall_ [l=mi] {_If_(_cgiargb_,te boolean,katoa)}
+_textbeginsearch_ [l=mi] {Rapua}
+_textfreqmsg1_ [l=mi] {Kia hia ng_amn_ kupu: }
+_textmorethan_ [l=mi] {Neke atu i te }
+_textnodocs_ [l=mi] {k_amn_ore he pukapuka e p_amn_ ana ki _amn_u kupu rapu.}
+_text1doc_ [l=mi] {1 te pukapuka e p_amn_ ana ki _amn_u kupu rapu.}
+_textlotsdocs_ [l=mi] {ng_amn_ pukapuka e p_amn_ ana ki _amn_u kupu rapu.}
+_textmatches_ [l=mi] {Kitenga }
+_textstemon_ [l=mi] { (hei aha te k_umn_muri)}
+
+_textsimplesearch_ [l=mi] {Tirohia ki _If_(_hselection_, _hselection_)_If_(_jselection_,_textjselect_)_If_(_nselection_, in _nselection_ language) m_omn_ _querytypeselection_ o ng_amn_ kupu}
+
+_textadvancedsearch_ [l=mi] {Tirohia ki_If_(_hselection_, _hselection_)_If_(_jselection_,_textjselect_)_If_(_nselection_, in _nselection_ language) 
+m_omn_ _querytypeselection_ o ng_amn_ kupu}
+
+
+#------------------------------------------------------------
+# icons
+#------------------------------------------------------------
+
+_httpiconhsearch_ [l=mi] {_httpimg_/mi/h\_search.gif}
+
+_httpiconqryresb_ [l=mi] {_httpimg_/mi/qryresb.gif}
+
+
+######################################################################
+# 'preferences' page
+package preferences
+######################################################################
+
+#------------------------------------------------------------
+# text macros
+#------------------------------------------------------------
+
+_textpreferences_ [l=mi] {Whiriwhiringa}
+_textignorecase_ [l=mi] { hei aha te p_umn_ matua me te p_umn_ iti}
+_textmatchcase_ [l=mi] { me tika te p_umn_ matua me te p_umn_ iti}
+_textstem_ [l=mi] { hei aha te k_umn_muri}
+_textnostem_ [l=mi] { me tika te k_umn_muri}
+_textprefop_ [l=mi] {Whakahokia mai te _maxdocoption_ kupu, _amn_, kia _hitsperpageoption_ kupu ki ia wh_amn_rangi.}
+_textlanguage_ [l=mi] {Reo: }
+_textencoding_ [l=mi] {Whakatakotoranga p_umn_: }
+_textformat_ [l=mi] {Whakatakotoranga wh_amn_rangi: }
+_textsimplemode_ [l=mi] {te rapu wh_amn_iti}
+_textadvancedmode_ [l=mi] {te rapu wh_amn_nui (ka taea te whakamahia ng_amn_ p_umn_ boolean, 
+p_emn_r_amn_ i te !, &, |, me te "()" hoki)}
+_textgraphical_ [l=mi] {Whakaahua}
+_texttextual_ [l=mi] {K_amn_ore he whakaahua}
+
+
+#------------------------------------------------------------
+# icons
+#------------------------------------------------------------
+
+_httpiconhpref_ [l=mi] {_httpimg_/mi/h\_pref.gif}
+_widthhpref_ [l=mi] {220}
Index: /main/tags/2.25/gsdl/macros/nzdlhome.dm
===================================================================
--- /main/tags/2.25/gsdl/macros/nzdlhome.dm	(revision 21064)
+++ /main/tags/2.25/gsdl/macros/nzdlhome.dm	(revision 21064)
@@ -0,0 +1,360 @@
+# nzdlhome.dm
+#
+# This file defines the homepage of the New Zealand Digital Library Project
+# as it appears on Http://www.nzdl.org. It is designed to override the default
+# homepage (defined in home.dm), so it should appear last in the "macrofiles"
+# section of the main.cfg file.
+#
+
+package home
+
+#######################################################################
+# java images/scripts
+#######################################################################
+
+# the _javalinks_ macros are the flashy image links at the top right of
+# the page. this is overridden here as we don't want 'home' 
+# links on this page
+
+_javalinks_ {}
+_javalinks_ [v=1] {}
+
+
+
+#######################################################################
+# icons
+#######################################################################
+
+_iconnzdl_ {<img src="_httpiconnzdl_" width=_widthnzdl_ height=_heightnzdl_ alt="The New Zealand Digital Library">}
+_icongbull_ {<img src="_httpicongbull_">}
+_iconpdf_ {<img src="_httpiconpdf_">}
+
+_iconselectcollection_ {<img src="_httpiconselcolgr_" width=_widthselcolgr_ height=_heightselcolgr_ alt=_altselcolgr_>}
+
+## "reference collections" ## green_bar_left_aligned ## selcolrf ##
+_httpiconselcolrf_ {_httpimg_/selcolrf.gif}
+_widthselcolrf_ {537}
+_heightselcolrf_ {17}
+_altselcolrf_ {"Reference collections"}
+
+## "humanitarian and UN collections" ## green_bar_left_aligned ## selcolun ##
+_httpiconselcolun_ {_httpimg_/selcolun.gif}
+_widthselcolun_ {537}
+_heightselcolun_ {17}
+_altselcolun_ {"Humanitarian and UN collections"}
+
+## "demonstration collections" ## green_bar_left_aligned ## selcolde ##
+_httpiconselcolde_ {_httpimg_/selcolde.gif}
+_widthselcolde_ {537}
+_heightselcolde_ {17}
+_altselcolde_ {"Demonstration collections"}
+
+_iconselectrf_ {<img src="_httpiconselcolrf_" width=_widthselcolrf_ height=_heightselcolrf_ alt=_altselcolrf_>}
+_iconselectun_ {<img src="_httpiconselcolun_" width=_widthselcolun_ height=_heightselcolun_ alt=_altselcolun_>}
+_iconselectde_ {<img src="_httpiconselcolde_" width=_widthselcolde_ height=_heightselcolde_ alt=_altselcolde_>}
+
+_iconmusiclibrary_ {<img src="_httpicontmusic_" border=1 alt="meldex music library">}
+
+
+#######################################################################
+# http macros 
+#
+# These contain the url without any quotes
+#######################################################################
+
+_httpicongbull_ {_httpimg_/gbull.gif}
+
+_httpiconpdf_ {_httpimg_/pdf.gif}
+
+_httpicontmusic_ {_httpimg_/meldexsm.gif}
+
+
+#######################################################################
+# page content                     
+#######################################################################
+
+_pagetitle_ {_textpagetitle_}
+_imagethispage_ {}
+_imagecollection_ {<center>_iconnzdl_</center>}
+
+_content_ {
+_nzdlcollectionlist_
+<center>_iconblankbar_</center>
+
+<p><center><h2>_textprojhead_</h2></center>
+
+<table border=0 cellpadding=5>
+
+<tr valign=top>
+<td>
+<table><tr valign=middle><td>_icongbull_</td><td><a href="mailto:_mailaddr_">_textfb_</a></td></tr></table>
+<table><tr valign=middle><td>_icongbull_</td><td><a href="http://www.nzdl.org/html/people.html">People</a></td></tr></table>
+</td>
+<td>_textprojinfo_</td>
+</tr>
+
+<tr>
+<td></td>
+<th align=left>_titlesoftwareinfo_</th>
+</tr>
+<tr valign=top>
+<td>
+<table><tr valign=middle><td>_icongbull_</td><td><a href="_httppagex_(gsdl)">About<br>Greenstone</a></td></tr></table>
+<table><tr valign=middle><td>_icongbull_</td><td><a href="http://www.nzdl.org/html/DOWNLOAD.html">Download<br>Greenstone</a></td></tr></table>
+<table><tr valign=middle><td>_icongbull_</td><td><a href="http://www.nzdl.org/html/trouble.html">Installation<br>Guide</a></td><td><img src="http://www.nzdl.org/images/new2.gif"></td></tr></table>
+<table><tr valign=middle><td>_iconpdf_</td><td><a href="_gsdl:httpgsdlmanual_">Manual</a></td></tr></table>
+<table><tr valign=middle><td>_iconpdf_</td><td><a href="_httppublications_/NZDLtext.pdf">_textinfosheet_</a></td></tr></table>
+
+</td>
+<td>_textsoftwareinfo_</td>
+</tr>
+
+<tr>
+<td></td>
+<th align=left>_titleresearchinfo_</th>
+</tr>
+<tr valign=top>
+<td>
+<table><tr valign=middle><td>_icongbull_</td><td><a href="http://www.nzdl.org/html/research.html">Research</a></td></tr></table>
+<table><tr valign=middle><td>_icongbull_</td><td><a href="http://www.nzdl.org/html/projects.html">Projects</a></td></tr></table>
+<table><tr valign=middle><td>_icongbull_</td><td><a href="http://www.nzdl.org/html/software.html">Software<br>Downloads</a></td></tr></table>
+<table><tr valign=middle><td>_icongbull_</td><td><a href="http://www.cs.waikato.ac.nz/~nzdl/publications/">Publications</a></td></tr></table>
+</td>
+<td>_textresearchinfo_</td>
+</tr>
+
+<tr valign=top>
+<td>
+<table><tr valign=middle><td>_icongbull_</td><td><a href="http://nikau.cs.waikato.ac.nz/~johnmcp/gsdl/cgi-bin/library.cgi">Z39.50<br>demo</a></td><td><img src="http://www.nzdl.org/images/new2.gif"></td></tr></table>
+</td><td>
+We have an experimental facility for searching Z39.50 collections using
+Greenstone.  Ultimately we plan a full bibliographic search facility, with
+the ability to combine tests on different fields, and to be able to search
+multiple collections, including cross-searching Greenstone and Z39.50
+collections.
+</td>
+</tr>
+
+<tr>
+<td></td>
+<th align=left>_titleaffiliateinfo_</th>
+</tr>
+<tr valign=top>
+<td>
+<img src="_httpimg_/ghproj.jpg" alt="Global Help Projects" width=100 height=90>
+</td>
+<td>_textaffiliateinfo_</td>
+</tr></table></p>
+
+_iconblankbar_
+<table>
+<tr valign=top>
+<td>_textpoem_</td>
+<td>_imagegreenstone_</td>
+</tr></table>
+<p>_textgreenstone_
+
+<p>
+_nzdlpagefooter_ 
+<br>April 2000
+}
+
+
+
+#######################################################################
+# English language text macros
+#######################################################################
+_textpagetitle_ {New Zealand Digital Library}
+_textprojhead_ {The New Zealand Digital Library Project}
+
+_textprojinfo_ {
+<p>
+The New Zealand Digital Library project is a research programme at
+The University of Waikato whose aim is to develop the underlying
+technology for digital libraries and make it available publicly so that
+others can use it to create their own collections. 
+<p>
+Our web site provides several document collections, including historical
+documents, humanitarian and development information, computer
+science technical reports and bibliographies, literary works, and
+magazines. All are available over the Web, and can be accessed
+through searching and browsing interfacees provided by the
+Greenstone digital library software. Behind the query interface lies a
+huge collection providing gigabytes of information. We hope you find
+what you want, or at least something intriguing!
+}
+
+_titlesoftwareinfo_ {The Greenstone software}
+
+_textsoftwareinfo_ {
+<p>
+The Greenstone Digital Library software provides a new way of
+organizing information and making it available over the Internet or on
+CD-ROM. It is open-source software, available under the terms of the
+Gnu public license. 
+<p>
+A digital library is made up of a set of collections. Each collection of
+information comprises several (typically several thousand, or even
+several million) documents, which share a uniform searching and
+browsing interface. Collections can be organized in many different
+ways while retaining a strong family resemblance. 
+
+<p><a href="mailto:majordomo@colosys.net">Subscribe to the Greenstone
+mailing list</a> (type "subscribe greenstone" in the <u>body</u> of the email)
+
+<p align=right>
+<a href="_httppagex_(gsdl)">More...</a>
+}
+
+_titleresearchinfo_ {Our research}
+
+_textresearchinfo_ {
+<p>
+The goal of our research program is to explore the potential of
+internet-based digital libraries. Our vision is to develop systems that
+automatically impose structure on anarchic, uncatalogued, distributed
+repositories of information, thereby providing information consumers
+with effective tools to locate what they need and to peruse it
+conveniently and comfortably. 
+<p>
+Project members are actively working on techniques for creating,
+managing, and and mainatining collections; extracting metadata from
+legacy documents; analysing library usage and user needs; Maori,
+Arabic and Chinese language systems; internationalising the library
+interface; optical music recognition and musical collections; novel
+interfaces for formulating queries and visualising results; novel
+interfaces for browsing metadata; text mining for keyphrases,
+acronyms, and other metadata; keyphrase extraction and
+phrase-based browsing; and other research topics. 
+<p align=right>
+<a href="_httppagex_(research)">More...</a>
+}
+
+_titleaffiliateinfo_ {Our affiliates}
+
+_textaffiliateinfo_ {
+<p>
+<a href="http://www.globalprojects.org">Global Help Projects</a>
+is a registered charity responsible for the
+Humanity Libraries Project that provides universal low-cost
+information access through co-operation between UN Agencies,
+universities and NGOs. Global Help Projects collaborate extensively
+with the NZDL project, and use the Greenstone software. 
+<p>
+<a href="http://www.digilibs.com">DigiLib Systems Limited</a>
+is an innovative software company that
+creates international digital libraries. As a major contributor to the
+Greenstone Digital Library Software they are able to build, customize,
+and extend digital libraries to meet exacting needs. Please contact them
+for an obligation free quote. 
+<p>
+<a name="mirrors"></a>
+The following websites are among those currently using Greenstone,
+either to make their own collections available, 
+or to mirror New Zealand Digital Library content.
+Some are still under development.
+<ul>
+<li><a href="http://canada.nzdl.org/~nzdl/cgi-bin/library">Canadian Mirror (CISTI)</a>
+<li><a href="http://gene.rutgers.edu/cgi-bin/library">Rutgers University</a>
+<li><a href="http://csdl1.mdx.ac.uk/">Middlesex University</a>
+<li><a href="http://laraine.unidata.ucar.edu/projects/coohl/htdig/cgi-bin/library">Unidata</a>
+</ul> 
+}
+
+
+#######################################################################
+# The collection display
+# A hand-crafted alternative to the _homeextra_ macro
+#######################################################################
+
+_nzdlgwcgi_ {http://www.nzdl.org/fast-cgi-bin/library}
+#_nzdlgwcgi_ {http://www.nzdl.org/cgi-bin/library}
+_nzdlhttpprefix_ {http://www.nzdl.org/gsdl}
+
+_nzdlcollection_ {http://www.nzdl.org/fast-cgi-bin/library?a=p&p=about&c=_1_}
+#_nzdlcollection_ {http://www.nzdl.org/cgi-bin/library?a=p&p=about&c=_1_}
+_nzdlcollectionimage_ {<img width=150 border=1 src="_nzdlhttpprefix_/collect/_1_/images/_2_" alt=_3_>}
+
+_collectionlink_ {<a href="_nzdlcollection_(_4_)">_nzdlcollectionimage_(_1_,_2_,_3_)</a>}
+
+
+_nzdlcollectionlist_ {
+<center>
+<p>_iconselectrf_
+<p>_collectactive_
+<p>_iconselectun_
+<p>_collectfao_
+<p>_iconselectde_
+<p>_collectrest_
+</center>
+}
+
+_collectactive_ {
+<table width=537>
+<tr valign=top>
+<td align=center>
+<p>_collectionlink_(arabic,  arabic.gif,  "Arabic text collection", arabic&l=ar&nw=u)
+<p>_collectionlink_(chinese, chinsm.jpg,  "Chinese text collection", chinese&l=zh&nw=u)
+<p>_collectionlink_(gberg,   gbergsm.gif, "Project Gutenberg Collection", gberg)
+</td>
+
+
+<td align=center>
+<p><a href="http://www.nzdl.org/fast-cgi-bin/niupepalibrary?a=p&p=about&c=niupepa&l=mi"><img width=150 border=1 src="_nzdlhttpprefix_/collect/niupepa/images/niupepsm.gif" alt="Niupepa: M&auml;ori Newspapers"></a>
+<p><a href="http://nzdl2.cs.waikato.ac.nz/cgi-bin/gwmm?c=meldex&a=page&p=coltitle"><img src="_nzdlhttpprefix_/images/meldexsm.gif" border=1 alt="Meldex music library"></a>
+<p><a href="_nzdlgwcgi_?a=p&p=about&c=musvid"><img width=150 border=1 src="http://www.cosc.canterbury.ac.nz/~davidb/gsdl/collect/musvid/images/musvid_frontpage.gif" alt="Music Videos"></a>
+<p><a href="http://www.nzdl.org/fast-cgi-bin/cstrlibrary?a=p&p=about"><img width=150 border=1 src="_nzdlhttpprefix_/collect/cstr/images/cstrsm.gif" alt="Computer Science Technical Reports"></a>
+<p>_collectionlink_(csbib, csbibsm.gif, "Computer Science Bibliographies", csbib)
+</td>
+
+<td align=center>
+<p>_collectionlink_(whist, whist\_logo\_small.gif, "Women&#039;s History Primary Source Documents", whist)
+<p>_collectionlink_(ohist, ohist\_title\_small.gif, "Hamilton Public Library Youth Oral History Collection", ohist)
+<p>_collectionlink_(hcibib, hcibibsm.gif, "The HCI Bibliography", hcibib)
+</td>
+</tr></table>
+}
+
+
+_collectfao_ {
+<table width=537>
+<tr valign=top>
+<td align=center>
+<p>_collectionlink_(fao1, fao.gif,   "The FAO Web site", fao1)
+<p>_collectionlink_(hdl,  hdlsm.gif, "Humanity Development Library", hdl)
+<p>_collectionlink_(envl, welsm.gif, "World Environment Library", envl)
+</td>
+<td align=center>
+<p>_collectionlink_(mhl,  mhlsm.gif,   "Medical and Health Library", mhl)
+<p>_collectionlink_(fnl,  fnlsm.gif,   "Food and Nutrition Library", fnl)
+<p>_collectionlink_(paho, pahosml.gif, "Virtual Disaster Library", paho)
+</td>
+<td align=center>
+<p>_collectionlink_(ccgi,   ccgism.gif,   "Collection on Critical Global Issues", ccgi)
+<p>_collectionlink_(tulane, tulanesm.gif, "Biblioth&egrave;que pour le d&eacute;veloppement", tulane)
+<p>_collectionlink_(unesco, unescosm.gif, "Sahel point Doc", unesco)
+</td>
+</tr>
+</table>
+}
+
+
+_collectrest_ {
+<table width=537>
+<tr valign=top>
+<td align=center>
+<p>_collectionlink_(ipc, ipcsm.gif, "Indigenous Peoples", ipc)
+</td>
+<td align=center>
+<p>_collectionlink_(tcc, tccsm.gif, "The Computists&#039; Weekly", tcc)
+<p>_collectionlink_(tidbits, tidbitsm.gif, "TidBITS", tidbits)
+</td>
+<td align=center>
+<p>_collectionlink_(dlmail, dlmailsm.gif, "The NZDL Project mailing list", dlmail)
+</td>
+</tr>
+</table>
+}
+
+# bbc no longer public
+#<p>_collectionlink_(bbc1, bbc_home.gif, "BBC archives (1900-1985)", bbc1)
Index: /main/tags/2.25/gsdl/macros/pref.dm
===================================================================
--- /main/tags/2.25/gsdl/macros/pref.dm	(revision 21064)
+++ /main/tags/2.25/gsdl/macros/pref.dm	(revision 21064)
@@ -0,0 +1,417 @@
+package preferences
+
+# set within server
+
+# collectionoption is only set when cross-collection searching is turned on
+_collectionoption_ {}
+
+# this macro will be set to "1" when the "source docs retrived from dl/web
+# button is required - i.e. whenever PreferenceDocsFromWeb isn't set to false
+# in collect.cfg
+_PreferenceDocsFromWeb_ {}
+
+
+#######################################################################
+# java images/scripts
+#######################################################################
+
+# the _javalinks_ macros are the flashy image links at the top right of
+# the page. this is overridden here as we don't want a 'preferences' 
+# link on this page
+
+_javalinks_ {_imagehome__imagehelp_}
+_javalinks_ [v=1] {
+_imagehome_<br>
+_imagehelp_<br>
+}
+
+
+#######################################################################
+# scripts
+# note that changing either the "m" or the "o" argument
+# from the preferences page necessitates reseting the "r"
+# argument to 1
+#######################################################################
+
+_ccsfunctions_ {argcc = "";
+savedccs = new Object();
+
+function initialize () \{
+  for (i = 0; i < document.links.length; i++)
+    savedhrefs[i] = document.links[i].href;
+
+  s = "_cgiargcc_";
+  a = s.split (",");
+  for (i = 0; i < a.length ;i++) \{
+    for (j = 0; j < document.PrefForm.cc.length; j++) \{
+      if (a[i] == document.PrefForm.elements["cc"][j].value) \{
+        document.PrefForm.elements["cc"][j].checked = true;
+        savedccs[a[i]] = 1;
+        argcc = argcc + "&cc=" + a[i];
+        break;
+      \} else \{
+        savedccs[a[i]] = 0;
+      \}
+    \}
+  \}
+  updatehrefs();
+\}
+
+function updatecc (collection) \{
+  if (savedccs[collection] == 1) savedccs[collection] = 0;
+  else savedccs[collection] = 1;
+		
+  var i;
+  argcc = "";
+  for (i in savedccs)
+    if (savedccs[i] == 1) argcc += "&cc=" + i;
+  updatehrefs();
+\}
+}
+
+_standardfunctions_ {
+function initialize () \{
+  for (i = 0; i < document.links.length; i++)
+    savedhrefs[i] = document.links[i].href;
+\}
+}
+
+_getargsfunction_ {
+function getargs () \{
+  return argk + args + argm + argo + arghd + argb_If_(_collectionoption_,_ccsargs_)_If_(_htmloptions_,_htmlargs_);
+\}
+}
+
+_ccsargs_ {+ argcc}
+_htmlargs_ {+ argel + argil + argfc + arghl}
+
+_htmlfunctions_ {argel = "";
+argil = "";
+argfc = "";
+arghl = "";
+
+function updateel () \{
+  value = document.PrefForm.el.options[document.PrefForm.el.selectedIndex].value;
+  if (value != "_cgiargel_") argel = "&el=" + value;
+  else argel = "";
+  updatehrefs();
+\}
+
+function updateil () \{
+  value = document.PrefForm.il.options[document.PrefForm.il.selectedIndex].value;
+  if (value != "_cgiargil_") argil = "&il=" + value;
+  else argil = "";
+  updatehrefs();
+\}
+
+function updatefc () \{
+  if (document.PrefForm.fc.checked)
+    _If_("_cgiargfc_" eq "1",_argfcblank_,_argfcon_)
+  else 
+    _If_("_cgiargfc_" ne "1",_argfcblank_,_argfcoff_)
+  updatehrefs();
+\}
+
+function updatehl () \{
+  if (document.PrefForm.hl.checked)
+    _If_("_cgiarghl_" eq "1",_arghlblank_,_arghlon_)
+  else 
+    _If_("_cgiarghl_" ne "1",_arghlblank_,_arghloff_)
+  updatehrefs();
+\}
+}
+
+_argfcblank_ {argfc = "";}
+_argfcon_ {argfc = "&fc=1&f=1";}
+_argfcoff_ {argfc = "&fc=0&f=0";}
+
+_arghlblank_ {arghl = "";}
+_arghlon_ {arghl = "&hl=1";}
+_arghloff_ {arghl = "&hl=0";}
+
+_arghdblank_ {arghd = "";}
+_arghdon_ {arghd = "&hd=1";}
+_arghdoff_{arghd = "&hd=0";}
+
+_pagescriptextra_ {
+// preferences scripts generated from \_preferences:pagescriptextra\_
+
+savedhrefs = new Object();
+
+argk = "";
+args = "";		
+argm = "";
+argo = "";
+argb = "";
+arghd = "";
+_If_(_collectionoption_,_ccsfunctions_,_standardfunctions_)
+_If_(_htmloptions_,_htmlfunctions_)
+_getargsfunction_
+function updatehrefs () \{
+  for (i = 0; i < document.links.length; i++)
+    document.links[i].href = savedhrefs[i] + getargs();
+\}
+
+function updatek (value) \{
+  if (value != _cgiargk_) argk = "&k=" + value;
+  else argk = "";
+  updatehrefs();
+\}
+
+function updates (value) \{
+  if (value != _cgiargs_) args = "&s=" + value;
+  else args = "";
+  updatehrefs();
+\}
+
+function updatem () \{
+  value = document.PrefForm.m.options[document.PrefForm.m.selectedIndex].value;
+  if (value != _cgiargm_) argm = "&r=1&m=" + value;
+  else argm = "";
+  updatehrefs();
+\}
+
+function updateo () \{
+  value = document.PrefForm.o.options[document.PrefForm.o.selectedIndex].value;
+  if (value != _cgiargo_) argo = "&r=1&o=" + value;
+  else argo = "";
+  updatehrefs();
+\}
+
+function updateb (value) \{
+  if (value != _cgiargb_) argb = "&b=" + value;
+  else argb = "";
+  updatehrefs();
+\}
+
+function updatehd () \{
+  if (document.PrefForm.hd.checked)
+    _If_("_cgiarghd_" eq "1",_arghdblank_,_arghdon_)
+  else
+    _If_("_cgiarghd_" ne "1",_arghdblank_,_arghdoff_)
+  updatehrefs();
+\}
+
+function updatel () \{
+  value = document.PrefForm.l.options[document.PrefForm.l.selectedIndex].value;
+  location.href = location.href + "&l=" + value + getargs();
+\}
+
+function updatev () \{
+  value = document.PrefForm.v.options[document.PrefForm.v.selectedIndex].value;
+  location.href = location.href + "&v=" + value + getargs();
+\}
+
+function updatew () \{
+  value = document.PrefForm.w.options[document.PrefForm.w.selectedIndex].value;
+  location.href = location.href + "&nw=" + value + getargs();
+\}
+}
+
+#######################################################################
+# headers
+# these are overridden so we can put an onLoad event handler
+# in the <body> tag of this page
+#######################################################################
+
+
+_header_ {_cgihead_
+_htmlhead_(background="_httpiconchalk_" onLoad="initialize();")_startspacer__pagebanner_
+}
+
+# this declaration ends up being the same as style=restrict, never mind
+_header_[v=1] {_cgihead_
+_htmlhead_(onLoad="initialize();")_pagebanner_
+}
+
+
+#######################################################################
+# page content
+#######################################################################
+
+_pagetitle_ {_collectionname_: _textpreferences_}
+_imagethispage_ {_iconthispage_}
+
+_htmloptions_ {}
+
+_htmloptionson_ {
+<p>
+_fcoption_
+<p>
+_hloption_
+<p>
+_extlinkoption_
+_If_(_PreferenceDocsFromWeb_,<p>
+_intlinkoption_)
+}
+
+_caseoption_ {
+<input type=radio name=k value=1 onClick="updatek(1);"
+		_If_(_cgiargk_, checked)>_textignorecase_<br>
+<input type=radio name=k value=0 onClick="updatek(0);"
+		_If_(_cgiargk_,, checked)>_textmatchcase_
+}
+
+_caseoption_ [l=ar] {}
+
+_fcoption_ {
+<input type=checkbox name=fc onClick="updatefc();"_If_("_cgiargfc_" eq "1", checked)> 
+_textfcoption_
+}
+
+_hloption_ {
+<input type=checkbox name=hl onClick="updatehl();"_If_("_cgiarghl_" eq "1", checked)> 
+_texthloption_
+}
+
+_caseoption_ [l=zh] {}
+
+_stemoption_ {
+<input type=radio name=s value=1 onClick="updates(1);"
+  _If_(_cgiargs_, checked)>_textstem_<br>
+<input type=radio name=s value=0 onClick="updates(0);"
+  _If_(_cgiargs_,, checked)>_textnostem_
+}
+
+_stemoption_ [l=zh] {}
+
+_maxdocoption_ {
+<select name="m" onChange="updatem();">
+  <option value="50"_If_("_cgiargm_" eq "50", selected)>50
+  <option value="100"_If_("_cgiargm_" eq "100", selected)>100
+  <option value="200"_If_("_cgiargm_" eq "200", selected)>200
+</select>
+}
+
+_hitsperpageoption_ {
+<select name="o" onChange="updateo();">
+  <option value="10"_If_("_cgiargo_" eq "10", selected)>10  
+  <option value="20"_If_("_cgiargo_" eq "20", selected)>20
+  <option value="50"_If_("_cgiargo_" eq "50", selected)>50
+  <option value="100")_If_("_cgiargo_" eq "100", selected)>_textall_
+</select>
+}
+
+_modeoption_ {
+<input type=radio name=b value=0 onClick="updateb(0);"
+		_If_(_cgiargb_,, checked)>_textsimplemode_<br>
+<input type=radio name=b value=1 onClick="updateb(1);"
+		_If_(_cgiargb_, checked)>_textadvancedmode_
+}
+
+_searchhistoryop_ {
+<input type=checkbox name="hd" onClick="updatehd();"
+                _If_("_cgiarghd_" eq "1", checked)>_texthistorydisplay_
+}
+
+_extlinkoption_ {
+_textextlink_
+<select name="el" onChange="updateel();">
+  <option value="prompt"_If_("_cgiargel_" eq "prompt", selected)>
+     _textlinkinterm_
+  <option value="direct"_If_("_cgiargel_" eq "direct", selected)>
+     _textlinkdirect_
+</select>
+}
+
+_intlinkoption_ {
+_textintlink_
+<select name="il" onChange="updateil();">
+  <option value="l"_If_("_cgiargil_" eq "l", selected)>
+     _textdigitlib_
+  <option value="w"_If_("_cgiargil_" eq "w", selected)>
+     _textweb_
+</select>
+}
+
+_languageoption_ {}
+
+_enlanguageoption_ {<option value="en"_If_("_cgiargl_",, selected)_If_("_cgiargl_" eq "en", selected)>_textlangeng_}
+_delanguageoption_ {<option value="de"_If_("_cgiargl_" eq "de", selected)>_textlanggerman_}
+_frlanguageoption_ {<option value="fr"_If_("_cgiargl_" eq "fr", selected)>_textlangfrench_}
+_eslanguageoption_ {<option value="es"_If_("_cgiargl_" eq "es", selected)>_textlangspanish_}
+_milanguageoption_ {<option value="mi"_If_("_cgiargl_" eq "mi", selected)>_textlangmaori_}
+_zhlanguageoption_ {<option value="zh"_If_("_cgiargl_" eq "zh", selected)>_textlangchinese_}
+_arlanguageoption_ {<option value="ar"_If_("_cgiargl_" eq "ar", selected)>_textlangarabic_}
+
+_encodingoption_ {
+_textencoding_
+<select name="w" onChange="updatew();">
+  <option value="w" _If_("_cgiargw_" eq "w",selected)>Western (ISO-8859-1)
+  <option value="u" _If_("_cgiargw_" eq "u",selected)>UTF-8
+  <option value="g" _If_("_cgiargw_" eq "g",selected)>GBK
+  <option value="a" _If_("_cgiargw_" eq "a",selected)>Arabic (windows 1256)
+</select>
+}
+
+_formatoption_ {
+_textformat_
+<select name="v" onChange="updatev();">
+  <option value="0"_If_("_cgiargv_" eq "0", selected)>_textgraphical_
+  <option value="1"_If_("_cgiargv_" eq "1", selected)>_texttextual_
+</select>
+}
+
+_content_ {
+<center>
+_navigationbar_
+</center>
+<blockquote>
+
+<form name=PrefForm method=get action="_gwcgi_">
+
+<input type="hidden" name="e" value="_decodedcompressedoptions_">
+
+_If_(_collectionoption_,_collectionprefs_)
+_presentationprefs_
+_searchprefs_
+
+</blockquote>
+</form>
+}
+
+_searchprefs_ {
+<h3>_textsearchprefs_</h3>
+<p>
+_caseoption_
+
+<p>
+_stemoption_
+
+<p>
+_modeoption_
+
+<p>
+_searchhistoryop_
+
+<p>
+_textprefop_
+<br>_iconblankbar_
+}
+
+_collectionprefs_ {
+<h3>_textcollectionprefs_</h3>
+_collectionoption_
+<br>_iconblankbar_
+}
+
+_presentationprefs_ {
+<h3>_textpresentationprefs_</h3>
+_htmloptions_
+
+<p>
+_languageoption_
+
+<p>
+_encodingoption_
+
+<p>
+_formatoption_
+<br>_iconblankbar_
+}
+
+#######################################################################
+# icons
+#######################################################################
+
+_iconthispage_ {<img src="_httpiconhpref_" alt="_textpreferences_" width="_widthhpref_" height="_heighthpref_">}
Index: /main/tags/2.25/gsdl/macros/query.dm
===================================================================
--- /main/tags/2.25/gsdl/macros/query.dm	(revision 21064)
+++ /main/tags/2.25/gsdl/macros/query.dm	(revision 21064)
@@ -0,0 +1,110 @@
+package query
+
+
+#######################################################################
+# Macros whose values are set from within the server at runtime. These 
+# are here only for reference and to set default values if required.           
+#######################################################################
+
+_quotedquery_ {}
+_freqmsg_ {}
+_resultline_ {}
+_thisfirst_ {}
+_thislast_ {}
+_nextfirst_ {}
+_nextlast_ {}
+_prevfirst_ {}
+_prevlast_ {}
+_searchhistorylist_ {}
+
+#######################################################################
+# icons
+#######################################################################
+
+_iconthispage_ {<img src="_httpiconhsearch_" alt="_texticonthispage_" width="_widthhsearch_" height="_heighthsearch_">}
+_iconthispage_ [v=1] {<h2>_texticonthispage_</h2>}
+
+_iconqueryresultsbar_ {<img src="_httpiconqryresb_" width="_widthqryresb_" height="_heightqryresb_" alt="_texticonqueryresultsbar_">}
+_iconqueryresultsbar_[v=1] {_texticonqueryresultsbar_}
+
+# _iconnext_ and _iconprev_ are overridden in this package as we
+# don't want alt text here
+_iconnext_{<img src="_httpiconmore_" width=_widthmore_ height=_heightmore_ border=0 align=top>}
+_iconnext_ [v=1] {}
+_iconprev_{<img src="_httpiconless_" width=_widthless_ height=_heightless_ border=0 align=top>}
+_iconprev_ [v=1] {}
+
+#######################################################################
+# images
+#######################################################################
+
+_imagethispage_ {_iconthispage_}
+
+
+#######################################################################
+# page content
+#######################################################################
+
+_pagetitle_ {_If_(_cgiargq_,_textquerytitle_,_textnoquerytitle_)}
+
+_content_ {
+<center>
+_navigationbar_
+</center>
+_queryform_
+_If_(_searchhistorylist_,<center>
+_searchhistorylist_
+</center>)
+_If_(_cgiargq_,<center>_iconqueryresultsbar_</center><br>
+<small>
+_freqmsg_
+_textpostprocess_</small><br>
+_resultline_
+,<center>_iconblankbar_</center>)<br>
+}
+
+_queryform_ {
+<!-- query form -->
+<form name=QueryForm method=get action="_gwcgi_">
+
+<input type=hidden name="a" value="q">
+<input type=hidden name="e" value="_decodedcompressedoptions_">
+<input type=hidden name="r" value="1">
+<input type=hidden name="hs" value="1">
+
+<center>
+<table><tr><td>
+<nobr>
+_textselect_<br>
+</nobr>
+</td></tr><tr><td>
+<nobr>
+<input type="text" name="q" value="_cgiargq_" size="50">
+<input type="submit" value="_textbeginsearch_">
+</nobr>
+</td></tr></table>
+</center>
+</form>
+<!-- end of query form -->
+}
+
+_textselect_ {_If_(_cgiargb_,_textadvancedsearch_,_textsimplesearch_)}
+
+# we want to put the links to previous/next pages of results
+# in the footer
+_pagefooterextra_ {
+<center>
+<table cellspacing=0 cellpadding=0 width=_pagewidth_>
+<tr>
+<td align=left>_If_(_prevfirst_,<a href="_httpquery_&r=_prevfirst_">_iconprev__textmatches__prevfirst_ - _prevlast_</a>)</td>
+<td align=right>_If_(_nextfirst_,<a href="_httpquery_&r=_nextfirst_">_textmatches__nextfirst_ - _nextlast__iconnext_</a>)</td>
+</tr></table>
+</center>
+}
+
+_querytypeselection_ {
+<select name="t">
+<option value="1"_If_(_cgiargt_, selected)>_textsome_
+<option value="0"_If_(_cgiargt_,, selected)>_textall_
+</select>
+}
Index: /main/tags/2.25/gsdl/macros/spanish.dm
===================================================================
--- /main/tags/2.25/gsdl/macros/spanish.dm	(revision 21064)
+++ /main/tags/2.25/gsdl/macros/spanish.dm	(revision 21064)
@@ -0,0 +1,963 @@
+######################################################################
+#
+# Spanish Language text and icon macros 
+#
+######################################################################
+#
+# This is the main macro file for translation when creating an 
+# interface in another language.
+#
+# Under the 'text macros' comments are text macros of the form:
+# _macroname_ {macro value}
+# Everything between the {} is the text to be translated. This text 
+# may itself contain macros (i.e. characters other than space between
+# underscore characters, e.g. _about:numdocs_ or _textpage_). These
+# macro names occurring within text shouldn't be translated but should
+# be left as they are. Underscores or curly brackets occurring 
+# naturally within the text should be escaped with a leading backslash
+# (i.e. '\_', '\{' or '\}).
+#
+# Under the 'icons' comments are macros concerned with displaying
+# icons which themselves contain text.
+# Above each macro (or group of macros) for an icon is a comment line
+# that looks something like '## "HOME" ## top_nav_button ## chome ##'.
+# The first field of the comment ("HOME" in this case) is the text
+# that appears in the english version of the icon. This is the text
+# that must be translated, nothing needs to be done to the macros 
+# themselves. The other two fields of the comments are used by 
+# automatic icon generating software which reads the newly translated
+# file and generates appropriate icons.
+#
+# Comment lines (other than those described above) need not be 
+# translated (i.e. any lines beginning with '#', like this line).
+#
+# The simplest way to translate this file is to save it as something
+# else (e.g. french.dm) and work through translating all the text
+# macro values and icon comments.
+#
+######################################################################
+
+
+######################################################################
+# Global (base) package
+package Global
+######################################################################
+
+
+#------------------------------------------------------------
+# text macros
+#------------------------------------------------------------
+
+_textdefaultcontent_ [l=es] {La p&aacute;gina solicitada no fue encontrada. Por 
+favor utilice el bot&oacute;n 'regresar' de su navegador o el bot&oacute;n 
+de principal para regresara la Biblioteca Digital Greenstone.}
+
+_textdefaulttitle_ [l=es] {Error en GSDL}
+
+_collectionextra_ [l=es] {Esta colecci&oacute;n contiene _about:numdocs_ documentos. 
+La colecci&oacute;n fue construida hace _about:builddate_ d&iacute;as.}
+
+_textimagecollection_ [l=es] {}
+_textimageabout_ [l=es] {P&aacute;gina Acerca de}
+_textimagehome_ [l=es] {P&aacute;gina Principal}
+_textimagehelp_ [l=es] {P&aacute;gina de Ayuda}
+_textimagepref_ [l=es] {P&aacute;gina de Preferencias}
+_textimagegreenstone_ [l=es] {Software de la Biblioteca Digital Greenstone}
+_textimagesearch_ [l=es] {Buscar t&eacute;rminos espec&iacute;ficos}
+_textimageTitle_ [l=es] {Navegar en las listas de t&iacute;tulos en orden alfab&eacute;tico}
+_textimageList_ [l=es] {Navegar en la lista de documentos}
+_textimageCreator_ [l=es] {Navegar en las listas de autores en orden alfab&eacute;tico}
+_textimageSeries_ [l=es] {Navegar por ejemplar}
+_textimageDate_ [l=es] {Navegar por fecha}
+_textimageSubject_ [l=es] {Navegar por categor&iacute;as de temas}
+_textimageOrganization_ [l=es] {Navegar por organizaci&oacute;n}
+_textimageHowto_ [l=es] {Navegar por categor&iacute;as de c&oacute;mo}
+_textimageTopic_ [l=es] {Navegar por t&oacute;picos especiales}
+_textimageBrowse_ [l=es] {Navegar}
+_textimagePeople_ [l=es] {Navegar en listas de gente en orden alfab&eacute;tico}
+
+_texticontabsearchgreen_ [l=es] {Buscar}
+_texticontabdategreen_ [l=es] {Fechas}
+_texticontabseriesgreen_ [l=es] {Series}
+_texticontabauthorgreen_ [l=es] {Autores A-Z}
+_texticontabtitlegreen_ [l=es] {T&iacute;tulos A-Z}
+_texticontablistgreen_ [l=es] {Listados}
+_texticontabsubjectgreen_ [l=es] {Temas}
+_texticontaborggreen_ [l=es] {Organizaci&oacute;n}
+_texticontabhowgreen_ [l=es] {C&oacute;mo}
+_texticontabtopicgreen_ [l=es] {T&oacute;picos}
+_texticontabbrwsegreen_ [l=es] {Navegar}
+_texticontabPeoplegreen_ [l=es] {Gente A-Z}
+
+_texticontext_ [l=es] {Ver el documento}
+_texticonclosedbook_ [l=es] {abrir este documento y ver su &iacute;ndice de contenido}
+_texticonnext_ [l=es] {ir a la siguiente secci&oacute;n}
+_texticonprev_ [l=es] {ir a la secci&oacute;n anterior}
+
+_page_ [l=es] {p&aacute;gina }
+_pages_ [l=es] {p&aacute;ginas}
+_of_ [l=es] { de }
+_vol_ [l=es] {Volumen}
+_num_ [l=es] {N&uacute;mero}
+
+_textmonth00_ [l=es] {}
+_textmonth01_ [l=es] {Enero}
+_textmonth02_ [l=es] {Febrero}
+_textmonth03_ [l=es] {Marzo}
+_textmonth04_ [l=es] {Abril}
+_textmonth05_ [l=es] {Mayo}
+_textmonth06_ [l=es] {Junio}
+_textmonth07_ [l=es] {Julio}
+_textmonth08_ [l=es] {Agosto}
+_textmonth09_ [l=es] {Septiembre}
+_textmonth10_ [l=es] {Octubre}
+_textmonth11_ [l=es] {Noviembre}
+_textmonth12_ [l=es] {Diciembre}
+
+_magazines_ [l=es] {Revistas}
+
+
+#------------------------------------------------------------
+# icons
+#------------------------------------------------------------
+
+## "PRINCIPAL" ## top_nav_button ## chome ##
+_httpiconchomeof_ [l=es] {_httpimg_/es/chomeof.gif}
+_httpiconchomeon_ [l=es] {_httpimg_/es/chomeon.gif}
+_widthchomex_ [l=es] {65}
+_heightchomex_ [l=es] {20}
+
+## "AYUDA" ## top_nav_button ## chelp ##
+_httpiconchelpof_ [l=es] {_httpimg_/es/chelpof.gif}
+_httpiconchelpon_ [l=es] {_httpimg_/es/chelpon.gif}
+_widthchelpx_ [l=es] {46}
+_heightchelpx_ [l=es] {20}
+   
+## "PREFERENCIAS" ## top_nav_button ## cpref ##
+_httpiconcprefof_ [l=es] {_httpimg_/es/cprefof.gif}
+_httpiconcprefon_ [l=es] {_httpimg_/es/cprefon.gif}
+_widthcprefx_ [l=es] {88}
+_heightcprefx_ [l=es] {20}
+
+## "ayuda" ## green_title ## h_help ##
+_httpiconhhelp_ [l=es] {_httpimg_/es/h\_help.gif}
+_widthhhelp_ [l=es] {200}
+_heighthhelp_ [l=es] {57}
+
+## "autores a-z" ## nav_bar_button ## tauth ##
+_httpicontauthgr_ [l=es] {_httpimg_/es/tauthgr.gif}
+_httpicontauthof_ [l=es] {_httpimg_/es/tauthof.gif}
+_httpicontauthon_ [l=es] {_httpimg_/es/tauthon.gif}
+_widthtauthx_ [l=es] {100}
+_heighttauthx_ [l=es] {17}
+
+## "series" ## nav_bar_button ## tser ##
+_httpicontsergr_ [l=es] {_httpimg_/es/tsergr.gif}
+_httpicontserof_ [l=es] {_httpimg_/es/tserof.gif}
+_httpicontseron_ [l=es] {_httpimg_/es/tseron.gif}
+_widthtserx_ [l=es] {87}
+_heighttserx_ [l=es] {17}
+
+## "fechas" ## nav_bar_button ## tdate ##
+_httpicontdategr_ [l=es] {_httpimg_/es/tdategr.gif}
+_httpicontdateof_ [l=es] {_httpimg_/es/tdateof.gif}
+_httpicontdateon_ [l=es] {_httpimg_/es/tdateon.gif}
+_widthtdatex_ [l=es] {87}
+_heighttdatex_ [l=es] {17}
+
+## "temas" ## nav_bar_button ## tsubj ##
+_httpicontsubjgr_ [l=es] {_httpimg_/es/tsubjgr.gif}
+_httpicontsubjon_ [l=es] {_httpimg_/es/tsubjon.gif}
+_httpicontsubjof_ [l=es] {_httpimg_/es/tsubjof.gif}
+_widthtsubjx_ [l=es] {87}
+_heighttsubjx_ [l=es] {17}
+
+## "organización" ## nav_bar_button ## torg ##
+_httpicontorggr_ [l=es] {_httpimg_/es/torggr.gif}
+_httpicontorgon_ [l=es] {_httpimg_/es/torgon.gif}
+_httpicontorgof_ [l=es] {_httpimg_/es/torgof.gif}
+_widthtorgx_ [l=es] {108}
+_heighttorgx_ [l=es] {17}
+
+## "cómo" ## nav_bar_button ## thow ##
+_httpiconthowgr_ [l=es] {_httpimg_/es/thowgr.gif}
+_httpiconthowon_ [l=es] {_httpimg_/es/thowon.gif}
+_httpiconthowof_ [l=es] {_httpimg_/es/thowof.gif}
+_widththowx_ [l=es] {87}
+_heightthowx_ [l=es] {17}
+
+## "tópicos" ## nav_bar_button ## ttopic ##
+_httpiconttopicgr_ [l=es] {_httpimg_/es/ttopicgr.gif}
+_httpiconttopicon_ [l=es] {_httpimg_/es/ttopicon.gif}
+_httpiconttopicof_ [l=es] {_httpimg_/es/ttopicof.gif}
+_widthttopicx_ [l=es] {87}
+_heightttopicx_ [l=es] {17}
+
+## "navegar" ## nav_bar_button ## tbrwse ##
+_httpicontbrwsegr_ [l=es] {_httpimg_/es/tbrwsegr.gif}
+_httpicontbrwseon_ [l=es] {_httpimg_/es/tbrwseon.gif}
+_httpicontbrwseof_ [l=es] {_httpimg_/es/tbrwseof.gif}
+_widthtbrwsex_ [l=es] {87}
+_heighttbrwsex_ [l=es] {17}
+
+## "buscar" ## nav_bar_button ## tsrch ##
+_httpicontsrchgr_ [l=es] {_httpimg_/es/tsrchgr.gif}
+_httpicontsrchof_ [l=es] {_httpimg_/es/tsrchof.gif}
+_httpicontsrchon_ [l=es] {_httpimg_/es/tsrchon.gif}
+_widthtsrchx_ [l=es] {87}
+_heighttsrchx_ [l=es] {17}
+
+## "títulos a-z" ## nav_bar_button ## ttitl ##
+_httpiconttitlgr_ [l=es] {_httpimg_/es/ttitlgr.gif}
+_httpiconttitlof_ [l=es] {_httpimg_/es/ttitlof.gif}
+_httpiconttitlon_ [l=es] {_httpimg_/es/ttitlon.gif}
+_widthttitlx_ [l=es] {90}
+_heightttitlx_ [l=es] {17}
+
+## "gente" ## nav_bar_button ## tpeop ##
+_httpicontpeopgr_ [l=es] {_httpimg_/es/tpeopgr.gif}
+_httpicontpeopof_ [l=es] {_httpimg_/es/tpeopof.gif}
+_httpicontpeopon_ [l=es] {_httpimg_/es/tpeopon.gif}
+_widthtpeopx_ [l=es] {87}
+_heighttpeopx_ [l=es] {17}
+
+
+
+######################################################################
+# 'about' page
+package about
+######################################################################
+
+
+#------------------------------------------------------------
+# text macros
+#------------------------------------------------------------
+
+_textabcol_ [l=es] {Acerca de esta colecci&oacute;n}
+
+_textsubcols1_ [l=es] {<p>La colecci&oacute;n completa comprende _1_ subcolecciones: 
+<blockquote>} 
+
+_textsubcols2_ [l=es] {</blockquote>
+Puede seleccionar (y cambiar) las subcolecciones que est&aacute;
+utilizando actualmente en la p&aacute;gina de Preferencias.}
+
+#------------------------------------------------------------
+# icons
+#------------------------------------------------------------
+
+## "acerca de" ## green_title ## h_about ##
+_httpiconhabout_ [l=es] {_httpimg_/es/h\_about.gif}
+_widthhabout_ [l=es] {200}
+_heighthabout_ [l=es] {57}
+
+
+
+######################################################################
+# document package
+package document
+######################################################################
+
+
+#------------------------------------------------------------
+# text macros
+#------------------------------------------------------------
+
+_textTitlepage_ [l=es] {_texticonhtitle_}
+_textCreatorpage_ [l=es] {_texticonhauth_}
+_textSubjectpage_ [l=es] {_texticonhsubj_}
+_textSeriespage_ [l=es] {_texticonhser_}
+_textDatepage_ [l=es] {_texticonhdate_}
+_textHowtopage_ [l=es] {_texticonhhow_}
+_textOrganizationpage_ [l=es] {_texticonhorg_}
+_textBrowsepage_ [l=es] {_texticonhbrwse_}
+_textPeoplepage_ [l=es] {_texticonhpeople_}
+
+_texticonhtitle_ [l=es] {T&iacute;tulos A-Z}
+_texticonhauth_ [l=es] {Autores A-Z}
+_texticonhsubj_ [l=es] {Temas}
+_texticonhser_ [l=es] {Series}
+_texticonhdate_ [l=es] {Fechas}
+_texticonhhow_ [l=es] {C&oacute;mo}
+_texticonhorg_ [l=es] {Organizaciones}
+_texticonhbrwse_ [l=es] {Navegar}
+_texticonhpeople_ [l=es] {Gente A-Z}
+
+_texticonopenbookshelf_ [l=es] {cerrar esta secci&oacute;n de la biblioteca}
+_texticonclosedbookshelf_ [l=es] {abrir esta secci&oacute;n de la biblioteca y ver el &iacute;ndice de contenido}
+_texticonopenbook_ [l=es] {cerrar este libro}
+_texticonclosedfolder_ [l=es] {Abrir esta carpeta y ver su contenido}
+_texticonclosedfolder2_ [l=es] {abrir subsecci&oacute;n: }
+_texticonopenfolder_ [l=es] {cerrar esta carpeta}
+_texticonopenfolder2_ [l=es] {cerrar subsecci&oacute;n: }
+_texticonsmalltext_ [l=es] {Ver esta secci&oacute;n del texto}
+_texticonsmalltext2_ [l=es] {ver texto: }
+_texticonpointer_ [l=es] {secci&oacute;n actual}
+_texticondetach_ [l=es] {Abrir esta p&aacute;gina en una nueva ventana}
+_texticonhighlight_ [l=es] {Resaltar los t&eacute;rminos de la b&uacute;squeda}
+_texticonnohighlight_ [l=es] {No resaltar los t&eacute;rminos de la b&uacute;squeda}
+_texticoncontracttoc_ [l=es] {Contraer el &iacute;ndice de contenido}
+_texticonexpandtoc_ [l=es] {Expandir el &iacute;ndice de contenido}
+_texticonexpandtext_ [l=es] {Mostrar el texto completo}
+_texticoncontracttext_ [l=es] {Mostrar el texto s&oacute;lo de la secci&oacute;n seleccionada}
+_texticonwarning_ [l=es] {<b>Advertencia: </b>}
+_texticoncont_ [l=es] {&#191;desea continuar?}
+
+_textltwarning_ [l=es] {
+<p><center>
+<table cellspacing=0 cellpadding=0 width=_pagewidth_>
+<tr valign=top><td>_iconwarning_Expandir el texto generar&aacute; una gran cantidad 
+de datos a desplegar en su navegador _imagecont_
+</td></tr></table></center>
+}  
+
+_textgoto_ [l=es] {ir a la p&aacute;gina}
+_textintro_ [l=es] { <i>(texto inicial)</i>}
+
+
+#------------------------------------------------------------
+# icons
+#------------------------------------------------------------
+
+## "títulos a-z" ## green_title ## h_title ##
+_httpiconhtitle_ [l=es] {_httpimg_/es/h\_title.gif}
+_widthhtitle_ [l=es] {200}
+_heighthtitle_ [l=es] {57}
+
+## "autores a-z" ## green_title ## h_auth ##
+_httpiconhauth_ [l=es] {_httpimg_/es/h\_auth.gif}
+_widthhauth_ [l=es] {200}
+
+## "temas" ## green_title ## h_subj ##
+_httpiconhsubj_ [l=es] {_httpimg_/es/h\_subj.gif}
+_widthhsubj_ [l=es] {200}
+_heighthsubj_ [l=es] {57}
+
+## "series" ## green_title ## h_ser ##
+_httpiconhser_ [l=es] {_httpimg_/es/h\_ser.gif}
+_widthhser_ [l=es] {200}
+_heighthser_ [l=es] {57}
+
+## "fechas" ## green_title ## h_date ##
+_httpiconhdate_ [l=es] {_httpimg_/es/h\_date.gif}
+_widthhdate_ [l=es] {200}
+_heighthdate_ [l=es] {57}
+
+## "cómo" ## green_title ## h_how ##
+_httpiconhhow_ [l=es] {_httpimg_/es/h\_how.gif}
+_widthhhow_ [l=es] {200}
+_heighthhow_ [l=es] {57}
+
+## "tópicos" ## green_title ## h_topic ##
+_httpiconhtopic_ [l=es] {_httpimg_/es/h\_topic.gif}
+_widthhtopic_ [l=es] {200}
+_heighthtopic_ [l=es] {57}
+
+## "organización" ## green_title ## h_org ##
+_httpiconhorg_ [l=es] {_httpimg_/es/h\_org.gif}
+_widthhorg_ [l=es] {250}
+_heighthorg_ [l=es] {57}
+
+## "navegar" ## green_title ## h_brwse ##
+_httpiconhbrwse_ [l=es] {_httpimg_/es/h\_brwse.gif}
+_widthhbrwse_ [l=es] {200}
+_heighthbrwse_ [l=es] {57}
+
+## "gente" ## green_title ## h_people ##
+_httpiconhpeople_ [l=es] {_httpimg_/es/h\_people.gif}
+_widthhpeople_ [l=es] {200}
+_heighthpeople_ [l=es] {57}
+
+## "DESEA CONTINUAR?" ## top_nav_button ## cont ##
+_httpiconcontoff_ [l=es] {_httpimg_/es/contoff.gif}
+_httpiconconton_ [l=es] {_httpimg_/es/conton.gif}
+_widthcontx_ [l=es] {122}
+_heightcontx_ [l=es] {17}
+
+## "TEXTO COMPLETO" ## document_button ## eallt ## 
+_httpiconealltof_ [l=es] {_httpimg_/es/ealltof.gif}
+_httpiconeallton_ [l=es] {_httpimg_/es/eallton.gif}
+_widthealltx_ [l=es] {91}
+_heightealltx_ [l=es] {30}
+
+## "CONTRAER ÍNDICE" ## document_button ## econc ##
+_httpiconeconcof_ [l=es] {_httpimg_/es/econcof.gif}
+_httpiconeconcon_ [l=es] {_httpimg_/es/econcon.gif}
+_widtheconcx_ [l=es] {92}
+_heighteconcx_ [l=es] {30}
+
+## "SEPARAR" ## document_button ## edtch ##
+_httpiconedtchof_ [l=es] {_httpimg_/es/edtchof.gif}
+_httpiconedtchon_ [l=es] {_httpimg_/es/edtchon.gif}
+_widthedtchx_ [l=es] {65}
+_heightedtchx_ [l=es] {30}
+
+## "EXPANDIR ÍNDICE" ## document_button ## eexpc ##
+_httpiconeexpcof_ [l=es] {_httpimg_/es/eexpcof.gif}
+_httpiconeexpcon_ [l=es] {_httpimg_/es/eexpcon.gif}
+_widtheexpcx_ [l=es] {86}
+_heighteexpcx_ [l=es] {30}
+
+## "CONTRAER TEXTO" ## document_button ## etsec ##
+_httpiconetsecof_ [l=es] {_httpimg_/es/etsecof.gif}
+_httpiconetsecon_ [l=es] {_httpimg_/es/etsecon.gif}
+_widthetsecx_ [l=es] {90}
+_heightetsecx_ [l=es] {30}
+
+## "RESALTAR" ## document_button ## ehl ##
+_httpiconehlof_ [l=es] {_httpimg_/es/ehlof.gif}
+_httpiconehlon_ [l=es] {_httpimg_/es/ehlon.gif}
+_widthehlx_ [l=es] {65}
+_heightehlx_ [l=es] {30}
+
+## "NO RESALTAR" ## document_button ## enhl ##
+_httpiconenhlof_ [l=es] {_httpimg_/es/enhlof.gif}
+_httpiconenhlon_ [l=es] {_httpimg_/es/enhlon.gif}
+_widthenhlx_ [l=es] {65}
+_heightenhlx_ [l=es] {30}
+
+
+
+######################################################################
+# 'search' page
+package query
+######################################################################
+
+
+#------------------------------------------------------------
+# text macros
+#------------------------------------------------------------
+
+# this if statement produces the text 'results n1 - nn for query: querystring' or 
+# 'No matches for query: querystring', depending on whether or not there were
+# any matches
+_textquerytitle_ [l=es] {_If_(_thislast_,resultados _thisfirst_ - _thislast_ para la petici&oacute;n:_cgiargq_,No se encontraron resultados para la petici&oacute;n: _cgiargq_)}
+
+_textnoquerytitle_ [l=es] {P&aacute;gina de b&uacute;squeda}
+
+_texticonthispage_ [l=es] {buscar}
+_textsome_ [l=es] {_If_(_cgiargb_,clasificado,algunas de)}
+_textall_ [l=es] {_If_(_cgiargb_,boleano,todas)}
+_texticonqueryresultsbar_ [l=es] {}
+_textfreqmsg1_ [l=es] {Palabras contadas: }
+_textpostprocess_ [l=es] {_If_(_quotedquery_,<br><i>postprocesado para encontrar _quotedquery_</i>
+)}					     
+
+_textmorethan_ [l=es] {M&aacute;s de }
+_textapprox_ [l=es] {Acerca de }
+_textnodocs_ [l=es] {No hay documentos que correspondan a la petici&oacute;n.}
+_text1doc_ [l=es] {un documento corresponde a la petici&oacute;n.}
+_textlotsdocs_ [l=es] {documentos corresponden a la petici&oacute;n.}
+_textmatches_ [l=es] {Correspondencias }
+_textbeginsearch_ [l=es] {Iniciar la b&uacute;squeda}
+
+_textsimplesearch_ [l=es] {Buscar _If_(_hselection_, _hselection_)_If_(_jselection_,_textjselect_)_If_(_nselection_, en idioma _nselection_) 
+que contengan _querytypeselection_ las palabras}
+
+_textadvancedsearch_ [l=es] {Buscar _If_(_hselection_, _hselection_, _defaultindextext_)_If_(_jselection_,_textjselect_)_If_(_nselection_, en idioma _nselection_) 
+utilizando la petici&oacute;n _querytypeselection_}
+
+_textjselect_ [l=es] {_If_(_hselection_, de) _jselection_}
+
+_textstemon_ [l=es] { (ignorar las terminaciones de las palabras)}
+_textclearhistory_ [l=es] {Borrar Historia}
+_textexpand_ [l=es] {Expandir}
+_textcontract_ [l=es] {Contraer}
+_textsearchhistory_ [l=es] {Buscar en la Historia}
+_textquery_ [l=es] {Petici&oacute;n}
+_textresults_ [l=es] {Resultados}
+_textview_ [l=es] {Ver}
+_textnohistory_ [l=es] {La b&uacute;squeda en la historia no est&aacute; disponible}
+
+
+#------------------------------------------------------------
+# icons
+#------------------------------------------------------------
+
+## "buscar" ## green_title ## h_search ##
+_httpiconhsearch_ [l=es] {_httpimg_/es/h\_search.gif}
+_widthhsearch_ [l=es] {200}
+_heighthsearch_ [l=es] {57}
+
+## "resultados" ## green_bar_left_aligned ## qryresb ##
+_httpiconqryresb_ [l=es] {_httpimg_/es/qryresb.gif}
+_widthqryresb_ [l=es] {_pagewidth_}
+_heightqryresb_ [l=es] {17}
+
+## "mostrar" ## hand_made ##
+_httpicondisplay_ [l=es] {_httpimg_/display.gif}
+_widthdisplay_ [l=es] {60}
+_heightdisplay_ [l=es] {20}
+
+
+
+######################################################################
+# 'preferences' page
+package preferences
+######################################################################
+
+
+#------------------------------------------------------------
+# text macros
+#------------------------------------------------------------
+
+_textsearchprefs_ [l=es] {Preferencias de b&uacute;squeda}
+_textcollectionprefs_ [l=es] {Preferencias de colecciones}
+_textpresentationprefs_ [l=es] {Preferencias de presentaci&oacute;n}
+_textpreferences_ [l=es] {Preferencias}
+_textignorecase_ [l=es] { ignorar diferencias entre may&uacute;sculas y min&uacute;sculas}
+_textmatchcase_ [l=es] { deben corresponder may&uacute;sculas y min&uacute;sculas}
+_textstem_ [l=es] { ignorar las terminaciones de las palabras}
+_textnostem_ [l=es] { debe corresponder la palabra completa}
+_textprefop_ [l=es] {Regresa hasta _maxdocoption_ resultados con _hitsperpageoption_ aciertos por p&aacute;gina.}
+_textextlink_ [l=es] {Acceder a p&aacute;ginas de Web externas: }
+_textintlink_ [l=es] {Documentos fuente recuperados de:}
+_textlanguage_ [l=es] {Idioma de la interfaz: }
+_textencoding_ [l=es] {Codificaci&oacute;n: }
+_textformat_ [l=es] {Formato de la interfaz: }
+_textall_ [l=es] {todas}
+_textsimplemode_ [l=es] {b&uacute;squeda simple}
+_textadvancedmode_ [l=es] {b&uacute;squeda avanzada (permite b&uacute;squedas boleanas utilizando !, &, | y par&eacute;ntesis)}
+_textlinkinterm_ [l=es] {a trav&eacute;s de una p&aacute;gina intermedia}
+_textlinkdirect_ [l=es] {ir directamente ah&iacute;}
+_textdigitlib_ [l=es] {la biblioteca digital}
+_textweb_ [l=es] {el web}
+_textlangeng_ [l=es] {Ingl&eacute;s}
+_textlanggerman_ [l=es] {Alem&aacute;n}
+_textlangfrench_ [l=es] {Franc&eacute;s}
+_textlangspanish_ [l=es] {Espa&ntilde;ol}
+_textlangmaori_ [l=es] {M_amn_ori}
+_textlangchinese_ [l=es] {Chino}
+_textgraphical_ [l=es] {Gr&aacute;fica}
+_texttextual_ [l=es] {S&oacute;lo texto}
+_textcollectionoption_ [l=es] {<p>
+Subcolecciones a incluir:
+<br>}
+_textfcoption_ [l=es] {Incluir la barra de navegaci&oacute;n en la parte superior de las p&aacute;ginas del documento}
+_texthloption_ [l=es] {Resaltar los t&eacute;rminos de la b&uacute;squeda dentro del documento}
+_texthistorydisplay_ [l=es] {mostrar la historia de la b&uacute;squeda}
+
+
+#------------------------------------------------------------
+# icons
+#------------------------------------------------------------
+
+## "preferencias" ## green_title ## h_pref ##
+_httpiconhpref_ [l=es] {_httpimg_/es/h\_pref.gif}
+_widthhpref_ [l=es] {200}
+_heighthpref_ [l=es] {57}
+
+
+
+######################################################################
+# 'delete search history' page
+package delhistory
+######################################################################
+
+
+#------------------------------------------------------------
+# text macros
+#------------------------------------------------------------
+
+_textdsh_ [l=es] {Borrar la historia de la b&uacute;squeda}
+
+_textselectdelete_ [l=es] {<a href="_httpclearhistory_&hdh=1">Borre todos los 
+registros</a> o seleccione los registros a <select name=hmode>
+<option value=save>conservar<option value=delete selected>borrar</select><br>
+Los registros pueden ser seleccionados escribiendo sus n&uacute;meros en el 
+cuadro, <br> o presionando en los cuadros de cada registro.<br> Los valores 
+aceptados son 1,2,3-6,7- etc }
+
+_textclearselected_ [l=es] {Borrar seleccionados}
+_textselect_ [l=es] {seleccionar}
+
+
+#------------------------------------------------------------
+# icons
+#------------------------------------------------------------
+
+
+
+######################################################################
+# 'help' page -- this is lower priority for translating than the
+# rest of this file
+package help
+######################################################################
+
+
+#------------------------------------------------------------
+# text macros
+#------------------------------------------------------------
+
+_textHelp_ [l=es] {Ayuda}
+_textSearchshort_ [l=es] {buscar palabras clave}
+_textSeriesshort_ [l=es] {acceder a las publicaciones por series}
+_textDateshort_ [l=es] {acceder a las publicaciones por fecha}
+_textSubjectshort_ [l=es] {acceder a las publicaciones por tema}
+_textTitleshort_ [l=es] {acceder a las publicaciones por t&iacute;tulo}
+_textBrowseshort_ [l=es] {navegar en las publicaciones}
+_textCreatorshort_ [l=es] {acceder a las publicaciones por autor}
+_textOrganizationshort_ [l=es] {acceder a las publicaciones por organizaci&oacute;n}
+_textHowtoshort_ [l=es] {acceder a las publicaciones por lista de c&oacute;mo}
+_textTopicshort_ [l=es] {acceder a las publicaciones por t&oacute;pico}
+_textPeopleshort_ [l=es] {acceder a las publicaciones por gente}
+_textdefaultshorttext_ [l=es] {clasificaci&oacute;n no definida}
+
+_textSearchlong_ [l=es] { <p>Puede <i>buscar palabras clave</i> que aparecen en 
+el texto desde la p&aacute;gina de "b&uacute;squeda". &Eacute;sta es la primera p&aacute;gina que 
+aparece cuando usted inicia y puede ser accesada desde otras p&aacute;ginas al 
+presionar el bot&oacute;n de <i>buscar</i>.  }
+
+_textTitlelong_ [l=es] { <p>Puede <i>acceder a las publicaciones por t&iacute;tulo</i> 
+presionando el bot&oacute;n <i>titulos a-z</i>. El resultado ser&aacute; una 
+lista de libros en orden alfab&eacute;tico.  }
+
+_textOrganizationlong_ [l=es] { <p>Puede <i>acceder a las publicaciones por 
+organizaci&oacute;n</i> presionando el bot&oacute;n <i>organizaci&oacute;n</i>. El resultado 
+ser&aacute; una lista de organizaciones.  }
+
+_textHowtolong_ [l=es] { <p>Puede <i>acceder a las publicaciones por una lista 
+de c&oacute;mo</i> presionando el bot&oacute;n <i>c&oacute;mo</i>. El resultado 
+ser&aacute; una lista de c&oacute;mos.  }
+
+_textCreatorlong_ [l=es] { <p>Puede <i>acceder a publicaciones por autor</i> 
+presionando el bot&oacute;n <i>autores a-z</i>. El resultado ser&aacute; una 
+lista de libros ordenados por el apellido del autor.  }
+
+_textTopiclong_ [l=es] { <p>Puede <i>acceder a las publicaciones por t&oacute;pico</i> 
+presionando el bot&oacute;n de <i>t&oacute;pico</i>. El resultado ser&aacute; 
+una lista de t&oacute;picos para navegarlos.  }
+
+_textSubjectlong_ [l=es] { <p>Puede <i>acceder a las publicaciones por tema</i> 
+presionando el bot&oacute;n de <i>temas</i>. El resultado ser&aacute; una lista de temas, 
+representados por libreros.  }
+
+_textSerieslong_ [l=es] { <p>Puede <i>acceder a las publicaciones por series</i> 
+presionando el bot&oacute;n de <i>series</i>. El resultado ser&aacute; una lista 
+de las series que se encuentran en la colecci&oacute;n.  }
+
+_textDatelong_ [l=es] { <p>Puede <i>acceder a las publicaciones por fecha</i> 
+presionando el bot&oacute;n de <i>fechas</i>. El resultado ser&aacute; una lista
+de todas las publicaciones, ordenadas cronol&oacute;gicamente.  }
+
+_textBrowselong_ [l=es] { <p> Puede <i>navegar en las publicaciones</i> presionando 
+el bot&oacute;n de <i>navegar</i>.  }
+
+_textPeoplelong_ [l=es] { <p>Puede <i>acceder a las publicaciones por gente</i> 
+presionando el bot&oacute;n <i>gente a-z</i>. El resultado ser&aacute; una lista
+ordenada por apellido.  }
+
+_textdefaultlongtext_ [l=es] { <p>Pulse el bot&oacute;n <i>desconocido</i> para navegar 
+en las publicaciones (el listado ser&aacute; ordenado por un campo desconocido).  }
+
+_texthelptopics_ [l=es] {
+
+<h2 align=left>T&oacute;picos</h2>
+<ul>
+  <li><a href="\#finding-information">_textsimplehelpheading_</a>
+  _topicreadingdocs_
+  <li><a href="\#searching">&#191;C&oacute;mo buscar palabras clave?</a>
+<ul>
+  <li><a href="\#query-terms">T&eacute;rminos de la b&uacute;squeda</a>
+  <li><a href="\#query-type">Tipo de petici&oacute;n</a>
+  <li><a href="\#scope-of-queries">Rango de las b&uacute;squedas</a>
+</ul>
+  <li><a href="\#preferences">_textchangeprefs_</a>
+<ul>
+  <li><a href="\#col-prefs">Preferencias de colecci&oacute;n</a>
+  <li><a href="\#pres-prefs">Preferencias de presentaci&oacute;n</a>
+  <li><a href="\#search-prefs">Preferencias de b&uacute;squeda</a>
+</ul>
+</ul>
+}
+
+# there are 4 versions of this section of the help text.
+# which version is used is currently set within the server
+# (it should probably use the macro language e.g. [type=book])
+# 1 = html (like fao collections) -- section is empty
+# 2 = book (like hdl collection) -- macros beginning with book
+# 3 = bibliographic (like csbib) -- macros beginning with bib
+# 4 = standard (like gberg) -- the default
+
+_topicreadingdocs_ [l=es] {<li><a href="\#reading-docs">_textreadingdocs_</a>}
+
+_textreadingdocs_ [l=es] {&#191;C&oacute;mo leer los documentos?}
+_booktextreadingdocs_ [l=es] {&#191;C&oacute;mo leer los libros?}
+_bibtextreadingdocs_ [l=es] {Obtener m&aacute;s informaci&oacute;n sobre un elemento bibliogr&aacute;fico}
+
+_texthelpreadingdocs_ [l=es] {
+<p>_iconblankbar_
+<a name=reading-docs>
+<h2>_textreadingdocs_</h2>
+
+<p>Puede notar cuando ha llegado a un documento en particular porque su 
+t&iacute;tulo y autor aparecen en la parte superior izquierda de la 
+p&aacute;gina. Al lado de &eacute;stos est&aacute; el n&uacute;mero de la 
+p&aacute;gina actual, un cuadro que le permite seleccionar la nueva 
+p&aacute;gina y las flechas de adelante y atr&aacute;s.
+
+<p>Debajo est&aacute; el texto de la secci&oacute;n actual. Cuando lo haya 
+leido, las flechas que se encuentran en la parte inferior pueden llevarlo a la 
+secci&oacute;n siguiente o regresarlo a la secci&oacute;n anterior.
+
+<p>Abajo del t&iacute;tulo y autor se encuentran tres botones. Presione
+<i>texto completo</i> para desplegar el texto completo de documento actual. 
+Si el documento es extenso, este proceso tomar&aacute; alg&uacute;n tiempo y 
+utilizar&aacute; mucha memoria!. Presione <i>separar</i> para crear un nueva 
+ventana de su navegador para este documento (esto es &uacute;til si desea 
+comparar documentos o leer dos a la vez). Finalmente, cuando realiza una 
+b&uacute;squeda, las palabras a buscar aparecen resaltadas; presione <i>sin 
+resaltar</i> para eliminar esta apariencia.
+
+<p>
+<table cellspacing="0" cellpadding="2" border="0">
+<tr><td colspan=2><img src="_httpiconmore_" border="0"></td><td>Presione la flecha para ir a la secci&oacute;n siguiente ...</td></tr>
+<tr><td colspan=2><img src="_httpiconless_" border="0"></td><td>... o regresar a la secci&oacute;n anterior</td></tr>
+<tr><td><img src="_document:httpiconealltof_" border="0"></td><td><img 
+src="_document:httpiconetsecof_" border="0"></td><td>Desplegar el texto completo, o no</td></tr>
+<tr><td colspan=2><img src="_document:httpiconedtchof_" border="0"></td><td>Abrir esta p&aacute;gina en una nueva ventana</td></tr>
+<tr><td><img src="_document:httpiconehlof_" border="0"></td><td><img
+src="_document:httpiconenhlof_" border="0"></td><td>Resaltar o no los t&eacute;rminos buscados</td></tr>
+</table>
+}
+
+_booktexthelpreadingdocs_ [l=es] {
+<p>_iconblankbar_
+<a name=reading-docs>
+<h2>_textreadingdocs_</h2>
+
+<p>Puede notar cuando ha llegado a un libro en particular porque la 
+fotograf&iacute;a de su portada aparece en la parte izquierda de la 
+p&aacute;gina. Al lado de la fotograf&iacute;a est&aacute; el &iacute;ndice 
+de contenido con una flecha que le indica d&oacute;nde est&aacute; usted. 
+Este &iacute;ndice es expandible: presione las carpetas para abrirlas o 
+cerrarlas. Presione en el libro abrierto, que se encuentra en la parte 
+superior, para cerrarlo.
+
+<p>Debajo est&aacute; el texto de la secci&oacute;n actual. Cuando lo haya 
+leido, las flechas que se encuentran en la parte inferior pueden llevarlo a la
+secci&oacute;n siguiente o regresarlo a la secci&oacute;n anterior.
+
+<p>Abajo de la fotograf&iacute;a se encuentran cuatro botones. Presione sobre 
+<i>texto completo</i> para desplegar el texto completo de la secci&oacute;n 
+actual o del libro. Si el libro es extenso, este proceso tomar&aacute; 
+alg&uacute;n tiempo y utilizar&aacute; mucha memoria!. Presione <i>expandir 
+&iacute;ndice</i> para expandir el &iacute;ndice completo y as&iacute; pueda 
+ver todos los t&iacute;tulos de cap&iacute;tulos y subsecciones. Presione 
+<i>separar</i> para crear un nueva ventana de su navegador para este documento 
+(esto es &uacute;til si desea comparar libros o leer dos a la vez). Finalmente, 
+cuando realiza una b&uacute;squeda, las palabras a buscar aparecen resaltadas; 
+presione <i>sin resaltar</i> para eliminar esta apariencia.
+
+<p>
+<table cellspacing="0" cellpadding="2" border="0">
+<tr><td colspan=2><img src="_httpiconbshelf_" border="0"></td><td>Abrir este librero</td></tr>
+<tr><td><img src="_httpiconopenbook_" border="0"></td><td><img 
+src="_httpiconbook_" border="0"></td><td>Abrir/cerrar este libro</td></tr>
+<tr><td colspan=2><img src="_httpiconitext_" border="0"></td><td>Ver esta secci&oacute;n del texto</td></tr>
+<tr><td><img src="_document:httpiconealltof_" border="0"></td><td><img 
+src="_document:httpiconetsecof_" border="0"></td><td>Desplegar el texto completo, o no</td></tr>
+<tr><td><img src="_document:httpiconeexpcof_" border="0"></td><td><img
+src="_document:httpiconeconcof_" border="0"></td><td>Expandir o no el &iacute;ndice de contenido</td></tr>
+<tr><td colspan=2><img src="_document:httpiconedtchof_" border="0"></td><td>Abrir esta p&aacute;gina en una nueva ventana</td></tr>
+<tr><td><img src="_document:httpiconehlof_" border="0"></td><td><img
+src="_document:httpiconenhlof_" border="0"></td><td>Resaltar o no los t&eacute;rminos de la b&uacute;squeda</td></tr>
+<tr><td colspan=2><img src="_httpiconmore_" border="0"></td><td>Presionar la flecha para ir a la secci&oacute;n siguiente ...</td></tr>
+<tr><td colspan=2><img src="_httpiconless_" border="0"></td><td>... o regresar a la secci&oacute;n anterior</td></tr>
+</table>
+}
+
+_bibtexthelpreadingdocs_ [l=es] {
+<p>_iconblankbar_
+<a name=reading-docs>
+<h2>_textreadingdocs_</h2>
+
+<p>Algunos elementos bibliogr&aacute;ficos contienen m&aacute;s 
+informaci&oacute;n, por ejemplo un resumen. Puede notar desde la p&aacute;gina 
+de resultados si este es el caso porque que se muestran con el &iacute;cono
+ _icontext_ en lugar del &iacute;cono _iconblanktext_.
+
+<p>Presionar el &iacute;cono _icontext_ le dar&aacute; m&aacute;s 
+informaci&oacute;n acerca del elemento bibliogr&aacute;fico.
+
+<p> Abajo del elemento bibliogr&aacute;fico se encuentran dos botones. Presione
+<i>separar</i> para crear un nueva ventana de su navegador para este 
+libro (esto es &uacute;til si desea comparar elementos bibliogr&aacute;ficos). 
+Finalmente, cuando realiza una b&uacute;squeda, las palabras a buscar aparecen 
+resaltadas; presione <i>sin resaltar</i> para eliminar esta apariencia.
+
+<p>
+<table cellspacing="0" cellpadding="2" border="0">
+<tr><td colspan=2><img src="_document:httpiconedtchof_" border="0"></td><td>Abrir esta p&aacute;gina en una nueva ventana</td></tr>
+<tr><td><img src="_document:httpiconehlof_" border="0"></td><td><img
+src="_document:httpiconenhlof_" border="0"></td><td>Resaltar o no los t&eacute;rminos buscados</td></tr>
+</table>
+}
+
+_texthelpsearching_ [l=es] {
+<h2>&#191;C&oacute;mo buscar palabras clave?</h2>
+<p>
+  Desde la p&aacute;gina de b&uacute;squeda, hacer una petici&oacute;n siguiendo estos pasos:<p>
+  <ol><li>Especificar qu&eacute; documentos quiere buscar
+      <li>Decir si quiere buscar todas las palabras o s&oacute;lo algunas
+      <li>Escribir las palabras que quiere buscar
+      <li>Presionar el bot&oacute;n de <i>Iniciar la b&uacute;squeda</i>
+  </ol>
+  
+<p>Cuando hace una petici&oacute;n, se mostrar&aacute;n los t&iacute;tulos de 
+veinte documentos resultantes. Existe un bot&oacute;n al final que lo 
+llevar&aacute; a los siguientes veinte documentos. De ah&iacute; 
+encontrar&aacute; botones para llevarlo a los terceros veinte o regresar a los 
+primeros veinte, etc&eacute;tera. Presione el t&iacute;tulo de cualquier 
+documento o el peque&ntilde;o bot&oacute;n al lado de &eacute;l, para verlo. 
+
+<p>El n&uacute;mero m&aacute;ximo documentos resultantes es de 100. Puede 
+  cambiar este n&uacute;mero presionando el bot&oacute;n de <i>preferencias</i>
+  que se encuentra en la parte superior de la p&aacute;gina.<p>
+
+<p>_iconblankbar_
+<a name=query-terms>
+<h3>T&eacute;rminos de la b&uacute;squeda</h3>
+
+<p>Lo que escribe en el cuadro de petici&oacute;n es interpretado como una 
+lista de palabras llamadas "t&eacute;rminos de la b&uacute;squeda". Cada 
+t&eacute;rmino contiene letras y d&iacute;gitos. Los t&eacute;rminos se separan 
+por el espacio en blanco. Si aparecen otros caracteres, como los de 
+puntuaci&oacute;n, &eacute;stos sirven para separar los t&eacute;rminos 
+como si fueran espacios y son ignorados. No puede buscar palabras que incluyan 
+puntuaci&oacute;n.
+
+<p>Por ejemplo, la petici&oacute;n<p>
+    <ul><kbd>Agro-sivicultura en las Islas del Pac&iacute;fico: Sistemas de Sustento (1993)</kbd></ul>
+      <p>ser&aacute; tratado de igual manera que<p>
+      <ul><kbd>Agro sivicultura en las Islas del Pac&iacute;fico Sistemas de Sustento 1993 </kbd></ul><p>
+      
+<p>_iconblankbar_
+<a name=query-type>
+<h3>Tipo de petici&oacute;n</h3>
+
+<p>Existen dos tipos de petici&oacute;n.
+
+<ul>
+  <li>Peticiones de <b>todas</b> las palabras. &Eacute;sta busca documentos que 
+      contengan todas las palabras que especifique. Los documentos que 
+      satisfagan la petici&oacute;n ser&aacute;n desplegados en orden 
+      alfab&eacute;tico. <p>     
+      
+  <li>Peticiones de <b>alguna(s)</b> palabra(s).  Solamente liste los
+      t&eacute;rminos que probablemente aparecer&aacute;n en los documentos que 
+      est&eacute; buscando. Los documentos se ordenar&aacute;n de acuerdo a que 
+      tanto coincidieron con su petici&oacute;n. Cuando se determina el grado de
+      correspondencia, 
+
+      <p><ul>
+        <li> entre m&aacute;s t&eacute;rminos buscados contenga el documento, 
+             satisfacer&aacute; mejor su petici&oacute;n;
+        <li> los t&eacute;rminos no comunes son m&aacute;s importantes que los 
+             comunes;
+        <li> los documentos m&aacute;s peque&ntilde;os tienen m&aacute;s 
+             probabilidades que los grandes de corresponder a su solicitud.
+      </ul>      
+</ul>
+
+<p>Utilice tantos t&eacute;rminos de b&uacute;squeda como desee, una 
+oraci&oacute;n completa, o quizas todo un p&aacute;rrafo. Si especifica un 
+s&oacute;lo t&eacute;rmino, los documentos ser&aacute;n 
+ordenados por frecuencia de ocurrencia.<p>
+_texthelpscope_
+}
+
+_textchangeprefs_ [l=es] {Cambiando sus preferencias}
+
+_texthelppreferences_ [l=es] {<h2>_textchangeprefs_</h2>
+
+<p>Cuando presione el bot&oacute;n de <i>preferencias</i>, de la parte superior de la
+p&aacute;gina, ser&aacute; capaz de cambiar algunas caracter&iacute;sticas de la 
+interfaz para satisfacer sus propios requisitos.
+
+<p>_iconblankbar_
+<a name=col-prefs>
+<h3 align=left>Perefencias de colecci&oacute;n</h3>
+<p>
+Algunas colecciones se componen de varias subcolecciones, las cuales pueden
+buscarse de forma independiente o juntas, como una unidad. De esta 
+manera, puede seleccionar qu&eacute; subcolecciones desea incluir en sus 
+b&uacute;squedas en la p&aacute;gina de preferencias.
+
+<p>_iconblankbar_
+<a name=pres-prefs>
+<h3 align=left>Preferencias de presentaci&oacute;n</h3>
+<p>
+Dependiendo de la colecci&oacute;n, pueden existir muchas opciones para definir 
+la manera de la presentaci&oacute;n.
+<p>
+Las colecciones de p&aacute;ginas de Web le permiten eliminar la barra de 
+navegaci&oacute;n de Greenstone de la parte superior de cada p&aacute;gina, 
+de modo que una vez terminada la b&uacute;squeda se encontrar&aacute; en la 
+p&aacute;gina correspondiente sin los encabezados de Greenstone. Para realizar 
+otra b&uacute;squeda tendr&aacute; que utilizar el bot&oacute;n "regresar" de 
+su navegador. Estas colecciones tambi&eacute;n le permiten eliminar el mensaje 
+de alerta de Greenstone cuando seleccione una liga que lo lleve fuera de la 
+colecci&oacute;n de la biblioteca digital y de Web en si. Y en algunas 
+colecciones del Web puede controlar si las ligas de la p&aacute;gina de 
+"Resultados de la b&uacute;squeda" lo llevan directo al URL en cuesti&oacute;n 
+o m&aacute;s bien a la copia de la p&aacute;gina de la biblioteca digital.
+
+<p>
+Las colecciones que son capaces de ser representadas en diferentes idiomas 
+le permiten especificar el idioma de la interfaz. Si el idioma es Chino, 
+puede especificar tambi&eacute;n cu&aacute;les son los est&aacute;ndares 
+Chinos de codificaci&oacute;n que utiliza su navegador.
+
+<p>
+Finalmente, todas las colecciones le permiten cambiar a una interfaz de texto
+diferente de la gr&aacute;fica. Esto es muy &uacute;til para los usuarios con 
+problemas visuales que utilizan fuentes grandes o sintetizadores de voz como 
+salida.
+
+<p>_iconblankbar_
+<a name=search-prefs>
+<h3 align=left>Preferencias de b&uacute;squeda</h3>
+Dos pares de botones controlan la diferencia entre may&uacute;sculas y 
+min&uacute;sculas y las ra&iacute;ces de las b&uacute;squedas que hace. 
+El primer conjunto de botones controla si deben coincidir may&uacute;sculas 
+o min&uacute;sculas. El segundo conjunto controla si se ignoran las 
+terminaciones de las palabras o no (ra&iacute;ces).
+
+<p>Por ejemplo, si los botones de <i>ignorar diferencias entre may&uacute;sculas
+y min&uacute;sculas</i> y el de <i>ignorar terminaciones de palabras</i> 
+est&aacute;n seleccionados, la b&uacute;squeda<p>
+    <ul><kbd>Construcciones Africanas</kbd></ul>
+      <p>ser&aacute; considerada al igual que <p>
+      <ul><kbd>constructores africanos</kbd></ul><p>
+      porque la letra may&uacute;scula en "Africanas" sera transformada a 
+      min&uacute;scula, y los sufijos "ciones" y "nas" se eliminaran de 
+      "Construcciones" y "Africanas" respectivamente ( de la misma manera, 
+      "tores" y "nos" se eliminar&aacute;n de "constructores" y "africanos").
+
+<p>Tambi&eacute;n puede cambiar a un modo "avanzado" de consulta que le permite 
+combinar t&eacute;rminos utilizando Y (&), O (|), y NO (!). Esto le 
+permitir&aacute; especificar consultas m&aacute;s precisas.
+
+<p>Finalmente, puede controlar el n&uacute;mero de aciertos regresados, y el
+n&uacute;mero de estos presentado en cada pantalla completa.
+}
+
+_texttanumbrowseoptions_ [l=es] {Existen _numbrowseoptions_ manera(s) de encontrar informaci&oacute;n en esta colecci&oacute;n:}
+
+_textsimplehelpheading_ [l=es] {&#191;C&oacute;mo encontrar informaci&oacute;n?}
+
+_texthelpscope_ [l=es] {
+<p>_iconblankbar_
+<a name=scope-of-queries>
+<h3 align=left>Rango de las b&uacute;squedas</h3> 
+
+<p>
+En la mayor&iacute;a de las colecciones puede escoger diferentes &iacute;ndices 
+para buscar. Por ejemplo, puede haber &iacute;ndices por autor o t&iacute;tulo. 
+Tambi&eacute;n puede haber &iacute;ndices por cap&iacute;tulo o p&aacute;rrafo. 
+Generalmente, se recupera el documento correspondiente sin importar &eacute;l 
+&iacute;ndice por el cual se busca. 
+<p>Si los documentos son libros, estos aparecer&aacute;n en el lugar 
+predefinido.
+}
Index: /main/tags/2.25/gsdl/macros/status.dm
===================================================================
--- /main/tags/2.25/gsdl/macros/status.dm	(revision 21064)
+++ /main/tags/2.25/gsdl/macros/status.dm	(revision 21064)
@@ -0,0 +1,145 @@
+package status
+
+_header_ {<html>
+<head>
+<title>_1_</title>
+</head>
+<body bgcolor="\#90c098" text="\#000000" link="\#006666"
+      alink="\#cc9900" vlink="\#666633">
+}
+
+_footer_ {</body>
+</html>
+}
+
+_infoheader_ {<html>
+<head>
+<title>_1_</title>
+</head>
+<body bgcolor="\#ffffff" text="\#000000" link="\#006666"
+      alink="\#cc9900" vlink="\#666633">
+
+<table width=100%>
+  <tr>
+    <td><img src="_httpimg_/spacer.gif" width=2 height=77></td>
+    <td>_iconblankbar_
+        <center><h2>_1_</h2></center>
+        _iconblankbar_</td>
+  </tr>
+</table>
+}
+
+_infofooter_ {
+<p> _iconblankbar_
+</body>
+</html>
+}
+
+
+_frameset_ {
+<html>
+<head>
+<title>_titlewelcome_</title>
+</head>
+
+<frameset cols="180,*" border=0>
+  <noframes><body bgcolor="#ffffff">
+  <p>_textframebrowser_</p>
+  </body>
+  </noframes>
+  <frame src="_gwcgi_?e=_compressedoptions_&a=status&sp=select" name=navframe>
+  <frame src="_gwcgi_?e=_compressedoptions_&a=status&sp=welcome" name=infoframe>
+</frameset>
+
+</html>
+}
+
+_select_ {
+<a href="_httppagehome_" target=_top border=0><img src="_httpimg_/gsdl.gif"></a>
+<p>
+<a href="_gwcgi_?e=_compressedoptions_&a=status&sp=welcome" target=infoframe>_textadminhome_</a><br>
+<a href="_httppagehome_" target=\_top>_textreturnhome_</a>
+
+<p><b>_textcollections_</b><br>
+<a href="_gwcgi_?e=_compressedoptions_&a=bc&bca=newcol&wizard=textinfo" target=infoframe>_textnewcoll_</a><br>
+<a href="_gwcgi_?e=_compressedoptions_&a=bc&bca=editcol" target=infoframe>_texteditcoll_</a><br>
+<a href="_gwcgi_?e=_compressedoptions_&a=bc&bca=buildcol&wizard=buildcol" target=infoframe>_textbuildcoll_</a><br>
+<a href="_gwcgi_?e=_compressedoptions_&a=bc&bca=delcol" target=infoframe>_textdeletecoll_</a><br>
+
+_If_("_cgiarguma_" ne "\_cgiarguma\_", 
+<p><b>_textusermanage_</b><br>
+<a href="_gwcgi_?e=_compressedoptions_&a=um&uma=listusers" target=infoframe>_textlistusers_</a><br>
+<a href="_gwcgi_?e=_compressedoptions_&a=um&uma=adduser" target=infoframe>_textaddusers_</a><br>
+)
+
+<p><b>_textinfo_</b><br>
+<a href="_gwcgi_?e=_compressedoptions_&a=status&sp=generalinfo" target=infoframe>_textgeneral_</a><br>
+<a href="_gwcgi_?e=_compressedoptions_&a=status&sp=argumentinfo" target=infoframe>_textarguments_</a><br>
+<a href="_gwcgi_?e=_compressedoptions_&a=status&sp=actioninfo" target=infoframe>_textactions_</a><br>
+<a href="_gwcgi_?e=_compressedoptions_&a=status&sp=browserinfo" target=infoframe>_textbrowsers_</a><br>
+<a href="_gwcgi_?e=_compressedoptions_&a=status&sp=protocolinfo" target=infoframe>_textprotocols_</a>
+
+<p><b>_textlogs_</b><br>
+<a href="_gwcgi_?e=_compressedoptions_&a=status&sp=initlog" target=infoframe>_textinitlog_</a><br>
+<a href="_gwcgi_?e=_compressedoptions_&a=status&sp=errorlog" target=infoframe>_texterrorlog_</a>
+}
+
+
+_textframebrowser_ {You must have a frame enabled browser to view this.}
+_textusermanage_ {User management}
+_textlistusers_ {list users}
+_textaddusers_ {add a new user}
+
+_textinfo_ {Information}
+_textgeneral_ {general}
+_textarguments_ {arguments}
+_textactions_ {actions}
+_textbrowsers_ {browsers}
+_textprotocols_ {protocols}
+
+_textcollections_ {Collection management}
+_textnewcoll_ {create new collection}
+_texteditcoll_ {edit collection}
+_textbuildcoll_ {rebuild collection}
+_textdeletecoll_ {delete collection}
+
+_textlogs_ {Logs}
+_textinitlog_ {init log}
+_texterrorlog_ {error log}
+
+_textadminhome_ {admin home}
+_textreturnhome_ {Greenstone home}
+
+_titlewelcome_ { Maintenance and Administration }
+
+_welcome_ {
+
+<center>
+<table width=_pagewidth_><tr><td>
+Maintenance and administration services available include:
+<ul>
+<li>view on-line logs
+<li>create, maintain and update collections
+<li>access technical information such as CGI arguments
+</ul>
+These services are accessed using the side navigation bar on the
+lefthand side of the page.
+<p>
+_iconblankbar_
+</td></tr>
+<tr><th align=left><br>Collection Status</th></tr>
+<tr><td>
+<font color=gray>
+Collections will only appear as &quot;running&quot; if their build.cfg
+files exist, are readable, contain a valid builddate field (i.e. > 0),
+and are in the collection's index directory (i.e. NOT the building
+directory).
+<p>
+click <i>abbrev.</i> for information on a collection
+<br>
+click <i>collection</i> to view a collection
+</font>
+</td></tr>
+</table>
+</center>
+}
Index: /main/tags/2.25/gsdl/macros/style.dm
===================================================================
--- /main/tags/2.25/gsdl/macros/style.dm	(revision 21064)
+++ /main/tags/2.25/gsdl/macros/style.dm	(revision 21064)
@@ -0,0 +1,175 @@
+#######################################################################
+# PAGE STYLES 
+#######################################################################
+
+package Style
+
+# to use this style system output
+# _header_
+# all your page content, then
+# _footer_
+
+# use the page parameter 'style' to choose the appropriate style
+
+# the style system uses
+# _pagetitle_  - what gets displayed at the top of the browser window
+# _pagescriptextra_ - any extra javascript you want included in the header
+# _pagebannerextra_ - anything extra you want displayed in the page banner
+# _pagefooterextra_ - anything extra you want displayed in the footer
+
+# defaults for the above macros
+_pagetitle_ {_collectionname_}
+_pagescriptextra_ {}
+_pagebannerextra_ {}
+_pagefooterextra_ {}
+
+# it also relies on lots of Globals, the most important of these are:
+# _cookie_ - put in the cgi header
+# _globalscripts_ - javascript stuff
+# _httpiconchalk_ - the image down the left of the page
+# _imagecollection_
+# _imagehome_
+# _imagehelp_
+# _imagepref_
+# _imagethispage_
+# _linkotherversion_
+
+_header_ {_cgihead_
+_htmlhead_(background="_httpiconchalk_")_startspacer__pagebanner_
+}
+
+_header_[v=1] {_cgihead_
+_htmlhead__pagebanner_
+}
+
+# _cgihead_ {Content-type: text/html
+# _cookie_
+#
+# }	
+_cgihead_{}
+
+# htmlhead uses:
+# _1_ - extra parameters for the body tag
+# _pagetitle_
+# _globalscripts_
+_htmlhead_ {
+<html_htmlextra_>
+<head>
+<title>_pagetitle_</title>
+_globalscripts_
+</head>
+
+<body bgcolor="\#ffffff" text="\#000000" link="\#006666" 
+      alink="\#cc9900" vlink="\#666633"_1_>
+}
+
+
+# _startspacer_ is a spacer to get past the 10010 graphic. It contains an open
+# <table> tag which must eventually be closed by _endspacer_.
+_startspacer_ {
+<table border=0 cellspacing=0 cellpadding=0 width="100%">
+<tr><td valign=top width=65><img src="_httpimg_/spacer.gif" width="65" height="1" alt="" border="0"></td>
+<td><center><table width="80%"><tr><td>
+}
+
+
+# pagebanner uses :
+# _imagecollection_ 
+# _imagehome_
+# _imagehelp_
+# _imagepref_
+# _imagethispage_
+# _pagebannerextra_
+_pagebanner_ {
+<!-- page banner (\_style:pagebanner\_) -->
+<center>
+<table width=_pagewidth_ cellspacing=0 cellpadding=0>
+  <tr valign=top>
+    <td rowspan=2 align=left>_imagecollection_</td>
+    <td align=right>_javalinks_</td>
+  </tr>
+
+  <tr>
+    <td align=right>_imagethispage_</td>
+  </tr>
+
+  <tr>
+    <td colspan=2>_pagebannerextra_</td>
+  </tr>
+</table>
+</center>
+<!-- end of page banner -->
+}
+
+_pagebanner_[v=1] {
+<!-- page banner - text version [v=1] (\_style:pagebanner\_) -->
+<center><h2><b><u>_imagecollection_</u></b></h2></center><p>
+_javalinks_
+_pagebannerextra_
+<p>
+<!-- end of page banner -->
+}
+
+_footer_ {
+<!-- page footer (\_style:footer\_) -->
+_pagefooterextra_
+</table>
+_endspacer__htmlfooter_
+}
+
+_endspacer_ {</center>
+</td></tr></table>
+}
+
+_htmlfooter_ {
+</body>
+</html>
+}
+
+_globalscripts_{
+<script>
+<!--
+    function img\_on(imgName) \{
+        if (version == "n3") \{
+            imgOn = eval(imgName + "\_on.src");
+            document [imgName].src = imgOn;
+        \}
+    \}
+
+    function img\_off(imgName) \{
+        if (version == "n3") \{
+            imgOff = eval(imgName + "\_off.src");
+            document [imgName].src = imgOff;
+        \}
+    \}
+    _If_(_cgiargx_,_scriptdetach_)
+    browserName = navigator.appName;          
+    browserVer = parseInt(navigator.appVersion);
+    if ((browserName == "Netscape" || browserName == "Microsoft Internet Explorer")
+        && browserVer >= 3) version = "n3";
+    else version = "n2";
+              
+    if (version == "n3") \{
+	_javaimagesheader_
+	_javaimagesnavbar_
+	_javaimagescontent_
+    \}
+    _pagescriptextra_
+// -->
+</script>
+}
+
+_globalscripts_ [v=1] {
+<script>
+<!--
+_If_(_cgiargx_,_scriptdetach_)
+_pagescriptextra_
+// -->
+</script>
+}
+
+_scriptdetach_ {
+    function close\_detach() \{
+	close();
+    \}
+}
Index: /main/tags/2.25/gsdl/macros/users.dm
===================================================================
--- /main/tags/2.25/gsdl/macros/users.dm	(revision 21064)
+++ /main/tags/2.25/gsdl/macros/users.dm	(revision 21064)
@@ -0,0 +1,195 @@
+package userslistusers
+
+_header_ {
+<html>
+<head>
+<title>List of current users</title>
+</head>
+<body bgcolor="#ffffff" text="#000000" link="#006666"
+      alink="#cc9900" vlink="#666633">
+}
+
+_content_ {}
+
+_contentstart_ {
+<h2>List of current users</h2>
+
+
+<table border=0 cellspacing=1 cellpadding=3 width=100%>
+<tr>
+  <th bgcolor="\#d0d0d0">user</th>
+  <th bgcolor="\#d0d0d0">account status</th>
+  <th bgcolor="\#d0d0d0">groups</th>
+  <th bgcolor="\#d0d0d0">comment</th>
+  <th>&nbsp;</th>
+</tr>
+}
+
+_contentend_ {
+</table>
+}
+
+_textadduser_ {add a new user}
+_textedituser_ {edit}
+_textdeleteuser_ {delete}
+
+_footer_ {
+</body>
+</html>
+}
+
+
+
+package usersedituser
+
+_header_ {
+<html>
+<head>
+<title>_If_("_cgiarguma_" eq "edituser",Edit user information,Add a new user)</title>
+</head>
+<body bgcolor="#ffffff" text="#000000" link="#006666"
+      alink="#cc9900" vlink="#666633">
+}
+
+_content_ {
+<h2>_If_("_cgiarguma_" eq "edituser",Edit user information,Add a new user)</h2>
+
+
+_users:messagestatus_
+
+<form name="edituser" method="post" action="_gwcgi_">
+<input type=hidden name="e" value="_decodedcompressedoptions_">
+<input type=hidden name="a" value="um">
+<input type=hidden name="uma" value="_cgiarguma_">
+
+<table border=0>
+<tr><td>username</td><td><input type="text" name="umun" value="_users:usersargun_" size=15></td>
+<td><font color=gray>Usernames must be between
+2 and 30 characters long. They can
+contain alphanumeric characters, '.', and '_'.
+</font></td>
+</tr>
+<tr><td>password</td><td><input type="text" name="umpw" value="_users:usersargpw_" size=9></td>
+<td><font color=gray>
+Passwords must be between 3 and 8 characters long. They can contain 
+any normal printable ASCII characters. 
+_If_("_cgiarguma_" eq "edituser",If this field is blank the old password will be kept.)
+</font></td></tr>
+<tr><td>account status</td><td>
+<select name="umus">
+<option value="enabled">enabled
+<option value="disabled"_If_("_users:usersargus_" ne "enabled", selected)>disabled
+</select>
+</td></tr>
+<tr><td>groups</td><td><input type="text" name="umug" value="_users:usersargug_" size=15></td>
+<td><font color=gray>
+Groups is a comma separated list, do not put spaces after the commas.
+</font></td></tr>
+<tr><td>comment</td><td colspan=2><input type="text" name="umc" value="_users:usersargc_" size=50></td></tr>
+<tr><td></td><td colspan=2><input type="submit" name=beu value="submit">
+<input type="submit" name=uma value="cancel"></td></tr>
+</table>
+</form>
+}
+
+_footer_ {
+</body>
+</html>
+}
+
+
+
+
+package usersdeleteuser
+
+_header_ {
+<html>
+<head>
+<title>Delete a user</title>
+</head>
+<body bgcolor="#ffffff" text="#000000" link="#006666"
+      alink="#cc9900" vlink="#666633">
+}
+
+_content_ {
+
+<p>
+<table border=0>
+<tr><td>
+<form name="deleteuser" method="post" action="_gwcgi_">
+<input type=hidden name="e" value="_decodedcompressedoptions_">
+<input type=hidden name="a" value="um">
+<input type=hidden name="uma" value="_cgiarguma_">
+<input type=hidden name="umun" value="_cgiargumun_">
+<font color=red>Do you really want to permanently remove user <b>_cgiargumun_</b>?</font>
+<input type="submit" name=cm value="no">
+<input type="submit" name=cm value="yes">
+</form>
+</td></tr>
+</table>
+}
+
+_footer_ {
+</body>
+</html>
+}
+
+
+
+package userschangepasswd
+
+_pagetitle_ {Change password}
+_imagethispage_ {_imagegreenstone_}
+
+_content_ {
+<h2>Change password</h2>
+<p><font color=gray>Passwords must be between 3 and 8 characters long. 
+They can contain any normal printable ASCII characters.</font>
+
+<p>_users:messagestatus_
+
+<p>
+<form name="changepasswd" method="post" action="_gwcgi_">
+<input type=hidden name="e" value="_decodedcompressedoptions_">
+<input type=hidden name="a" value="um">
+<input type=hidden name="uma" value="_cgiarguma_">
+<table border=0>
+<tr><td align=right>old password</td><td><input type="text" name="umpw" size=9></td></tr>
+<tr><td align=right>new password</td><td><input type="password" name="umnpw1" size=9></td></tr>
+<tr><td align=right>retype new password</td><td><input type="password" name="umnpw2" size=9></td></tr>
+<tr><td></td><td><input type="submit" name=bcp value="submit"></td></tr>
+</table>
+</table>
+</form>
+
+}
+
+
+package userschangepasswdok
+
+_pagetitle_ {Change password}
+_imagethispage_ {_imagegreenstone_}
+
+_content_ {
+<h2>Change password</h2>
+
+<p>Your password was successfully changed.
+}
+
+
+
+package users
+
+_messageinvalidusername_ {<font color=red>The username is invalid.</font> }
+_messageinvalidpassword_ {<font color=red>The password is invalid.</font> }
+_messageemptypassword_ {<font color=red>Please enter an initial password for this user.</font> }
+_messageuserexists_ {<font color=red>This user already exists, 
+please enter in another username.</font> }
+
+_messageusernameempty_ {<font color=red>Please enter your username.</font> }
+_messagepasswordempty_ {<font color=red>You must enter your old password.</font> }
+_messagenewpass1empty_ {<font color=red>Enter your new password and then retype it.</font> }
+_messagenewpass2empty_ {_messagenewpass1empty_}
+_messagenewpassmismatch_ {<font color=red>The two versions of your new password did not match.</font> }
+_messagenewinvalidpassword_ {<font color=red>You entered an invalid password.</font> }
+_messagefailed_ {<font color=red>Either your username or password was incorrect.</font> }
Index: /main/tags/2.25/gsdl/packages/mg/COPYING
===================================================================
--- /main/tags/2.25/gsdl/packages/mg/COPYING	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/mg/COPYING	(revision 21064)
@@ -0,0 +1,344 @@
+		    GNU GENERAL PUBLIC LICENSE
+		       Version 2, June 1991
+
+ Copyright (C) 1989, 1991 Free Software Foundation, Inc.
+                          675 Mass Ave, Cambridge, MA 02139, USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+			    Preamble
+
+  The licenses for most software are designed to take away your
+freedom to share and change it.  By contrast, the GNU General Public
+License is intended to guarantee your freedom to share and change free
+software--to make sure the software is free for all its users.  This
+General Public License applies to most of the Free Software
+Foundation's software and to any other program whose authors commit to
+using it.  (Some other Free Software Foundation software is covered by
+the GNU Library General Public License instead.)  You can apply it to
+your programs, too.
+
+  When we speak of free software, we are referring to freedom, not
+price.  Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+this service if you wish), that you receive source code or can get it
+if you want it, that you can change the software or use pieces of it
+in new free programs; and that you know you can do these things.
+
+  To protect your rights, we need to make restrictions that forbid
+anyone to deny you these rights or to ask you to surrender the rights.
+These restrictions translate to certain responsibilities for you if you
+distribute copies of the software, or if you modify it.
+
+  For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must give the recipients all the rights that
+you have.  You must make sure that they, too, receive or can get the
+source code.  And you must show them these terms so they know their
+rights.
+
+  We protect your rights with two steps: (1) copyright the software, and
+(2) offer you this license which gives you legal permission to copy,
+distribute and/or modify the software.
+
+  Also, for each author's protection and ours, we want to make certain
+that everyone understands that there is no warranty for this free
+software.  If the software is modified by someone else and passed on, we
+want its recipients to know that what they have is not the original, so
+that any problems introduced by others will not reflect on the original
+authors' reputations.
+
+  Finally, any free program is threatened constantly by software
+patents.  We wish to avoid the danger that redistributors of a free
+program will individually obtain patent licenses, in effect making the
+program proprietary.  To prevent this, we have made it clear that any
+patent must be licensed for everyone's free use or not licensed at all.
+
+  The precise terms and conditions for copying, distribution and
+modification follow.
+
+
+		    GNU GENERAL PUBLIC LICENSE
+   TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+  0. This License applies to any program or other work which contains
+a notice placed by the copyright holder saying it may be distributed
+under the terms of this General Public License.  The "Program", below,
+refers to any such program or work, and a "work based on the Program"
+means either the Program or any derivative work under copyright law:
+that is to say, a work containing the Program or a portion of it,
+either verbatim or with modifications and/or translated into another
+language.  (Hereinafter, translation is included without limitation in
+the term "modification".)  Each licensee is addressed as "you".
+
+Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope.  The act of
+running the Program is not restricted, and the output from the Program
+is covered only if its contents constitute a work based on the
+Program (independent of having been made by running the Program).
+Whether that is true depends on what the Program does.
+
+  1. You may copy and distribute verbatim copies of the Program's
+source code as you receive it, in any medium, provided that you
+conspicuously and appropriately publish on each copy an appropriate
+copyright notice and disclaimer of warranty; keep intact all the
+notices that refer to this License and to the absence of any warranty;
+and give any other recipients of the Program a copy of this License
+along with the Program.
+
+You may charge a fee for the physical act of transferring a copy, and
+you may at your option offer warranty protection in exchange for a fee.
+
+  2. You may modify your copy or copies of the Program or any portion
+of it, thus forming a work based on the Program, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+    a) You must cause the modified files to carry prominent notices
+    stating that you changed the files and the date of any change.
+
+    b) You must cause any work that you distribute or publish, that in
+    whole or in part contains or is derived from the Program or any
+    part thereof, to be licensed as a whole at no charge to all third
+    parties under the terms of this License.
+
+    c) If the modified program normally reads commands interactively
+    when run, you must cause it, when started running for such
+    interactive use in the most ordinary way, to print or display an
+    announcement including an appropriate copyright notice and a
+    notice that there is no warranty (or else, saying that you provide
+    a warranty) and that users may redistribute the program under
+    these conditions, and telling the user how to view a copy of this
+    License.  (Exception: if the Program itself is interactive but
+    does not normally print such an announcement, your work based on
+    the Program is not required to print an announcement.)
+
+
+These requirements apply to the modified work as a whole.  If
+identifiable sections of that work are not derived from the Program,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works.  But when you
+distribute the same sections as part of a whole which is a work based
+on the Program, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Program.
+
+In addition, mere aggregation of another work not based on the Program
+with the Program (or with a work based on the Program) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+  3. You may copy and distribute the Program (or a work based on it,
+under Section 2) in object code or executable form under the terms of
+Sections 1 and 2 above provided that you also do one of the following:
+
+    a) Accompany it with the complete corresponding machine-readable
+    source code, which must be distributed under the terms of Sections
+    1 and 2 above on a medium customarily used for software interchange; or,
+
+    b) Accompany it with a written offer, valid for at least three
+    years, to give any third party, for a charge no more than your
+    cost of physically performing source distribution, a complete
+    machine-readable copy of the corresponding source code, to be
+    distributed under the terms of Sections 1 and 2 above on a medium
+    customarily used for software interchange; or,
+
+    c) Accompany it with the information you received as to the offer
+    to distribute corresponding source code.  (This alternative is
+    allowed only for noncommercial distribution and only if you
+    received the program in object code or executable form with such
+    an offer, in accord with Subsection b above.)
+
+The source code for a work means the preferred form of the work for
+making modifications to it.  For an executable work, complete source
+code means all the source code for all modules it contains, plus any
+associated interface definition files, plus the scripts used to
+control compilation and installation of the executable.  However, as a
+special exception, the source code distributed need not include
+anything that is normally distributed (in either source or binary
+form) with the major components (compiler, kernel, and so on) of the
+operating system on which the executable runs, unless that component
+itself accompanies the executable.
+
+If distribution of executable or object code is made by offering
+access to copy from a designated place, then offering equivalent
+access to copy the source code from the same place counts as
+distribution of the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+
+  4. You may not copy, modify, sublicense, or distribute the Program
+except as expressly provided under this License.  Any attempt
+otherwise to copy, modify, sublicense or distribute the Program is
+void, and will automatically terminate your rights under this License.
+However, parties who have received copies, or rights, from you under
+this License will not have their licenses terminated so long as such
+parties remain in full compliance.
+
+  5. You are not required to accept this License, since you have not
+signed it.  However, nothing else grants you permission to modify or
+distribute the Program or its derivative works.  These actions are
+prohibited by law if you do not accept this License.  Therefore, by
+modifying or distributing the Program (or any work based on the
+Program), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Program or works based on it.
+
+  6. Each time you redistribute the Program (or any work based on the
+Program), the recipient automatically receives a license from the
+original licensor to copy, distribute or modify the Program subject to
+these terms and conditions.  You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties to
+this License.
+
+  7. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License.  If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Program at all.  For example, if a patent
+license would not permit royalty-free redistribution of the Program by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Program.
+
+If any portion of this section is held invalid or unenforceable under
+any particular circumstance, the balance of the section is intended to
+apply and the section as a whole is intended to apply in other
+circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system, which is
+implemented by public license practices.  Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+
+  8. If the distribution and/or use of the Program is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Program under this License
+may add an explicit geographical distribution limitation excluding
+those countries, so that distribution is permitted only in or among
+countries not thus excluded.  In such case, this License incorporates
+the limitation as if written in the body of this License.
+
+  9. The Free Software Foundation may publish revised and/or new versions
+of the General Public License from time to time.  Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+Each version is given a distinguishing version number.  If the Program
+specifies a version number of this License which applies to it and "any
+later version", you have the option of following the terms and conditions
+either of that version or of any later version published by the Free
+Software Foundation.  If the Program does not specify a version number of
+this License, you may choose any version ever published by the Free Software
+Foundation.
+
+  10. If you wish to incorporate parts of the Program into other free
+programs whose distribution conditions are different, write to the author
+to ask for permission.  For software which is copyrighted by the Free
+Software Foundation, write to the Free Software Foundation; we sometimes
+make exceptions for this.  Our decision will be guided by the two goals
+of preserving the free status of all derivatives of our free software and
+of promoting the sharing and reuse of software generally.
+
+			    NO WARRANTY
+
+  11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
+FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW.  EXCEPT WHEN
+OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
+PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
+OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.  THE ENTIRE RISK AS
+TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU.  SHOULD THE
+PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
+REPAIR OR CORRECTION.
+
+  12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
+REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
+INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
+OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
+TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
+YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
+PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGES.
+
+		     END OF TERMS AND CONDITIONS
+
+
+	    How to Apply These Terms to Your New Programs
+
+  If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+  To do so, attach the following notices to the program.  It is safest
+to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least
+the "copyright" line and a pointer to where the full notice is found.
+
+    <one line to give the program's name and a brief idea of what it does.>
+    Copyright (C) 19yy  <name of author>
+
+    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.
+
+Also add information on how to contact you by electronic and paper mail.
+
+If the program is interactive, make it output a short notice like this
+when it starts in an interactive mode:
+
+    Gnomovision version 69, Copyright (C) 19yy name of author
+    Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
+    This is free software, and you are welcome to redistribute it
+    under certain conditions; type `show c' for details.
+
+The hypothetical commands `show w' and `show c' should show the appropriate
+parts of the General Public License.  Of course, the commands you use may
+be called something other than `show w' and `show c'; they could even be
+mouse-clicks or menu items--whatever suits your program.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the program, if
+necessary.  Here is a sample; alter the names:
+
+  Yoyodyne, Inc., hereby disclaims all copyright interest in the program
+  `Gnomovision' (which makes passes at compilers) written by James Hacker.
+
+  <signature of Ty Coon>, 1 April 1989
+  Ty Coon, President of Vice
+
+This General Public License does not permit incorporating your program into
+proprietary programs.  If your program is a subroutine library, you may
+consider it more useful to permit linking proprietary applications with the
+library.  If this is what you want to do, use the GNU Library General
+Public License instead of this License.
Index: /main/tags/2.25/gsdl/packages/mg/INSTALL
===================================================================
--- /main/tags/2.25/gsdl/packages/mg/INSTALL	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/mg/INSTALL	(revision 21064)
@@ -0,0 +1,176 @@
+Basic Installation
+==================
+
+   These are generic installation instructions.
+
+   The `configure' shell script attempts to guess correct values for
+various system-dependent variables used during compilation.  It uses
+those values to create a `Makefile' in each directory of the package.
+It may also create one or more `.h' files containing system-dependent
+definitions.  Finally, it creates a shell script `config.status' that
+you can run in the future to recreate the current configuration, a file
+`config.cache' that saves the results of its tests to speed up
+reconfiguring, and a file `config.log' containing compiler output
+(useful mainly for debugging `configure').
+
+   If you need to do unusual things to compile the package, please try
+to figure out how `configure' could check whether to do them, and mail
+diffs or instructions to the address given in the `README' so they can
+be considered for the next release.  If at some point `config.cache'
+contains results you don't want to keep, you may remove or edit it.
+
+   The file `configure.in' is used to create `configure' by a program
+called `autoconf'.  You only need `configure.in' if you want to change
+it or regenerate `configure' using a newer version of `autoconf'.
+
+The simplest way to compile this package is:
+
+  1. `cd' to the directory containing the package's source code and type
+     `./configure' to configure the package for your system.  If you're
+     using `csh' on an old version of System V, you might need to type
+     `sh ./configure' instead to prevent `csh' from trying to execute
+     `configure' itself.
+
+     Running `configure' takes awhile.  While running, it prints some
+     messages telling which features it is checking for.
+
+  2. Type `make' to compile the package.
+
+  3. Optionally, type `make check' to run any self-tests that come with
+     the package.
+
+  4. Type `make install' to install the programs and any data files and
+     documentation.
+
+  5. You can remove the program binaries and object files from the
+     source code directory by typing `make clean'.  To also remove the
+     files that `configure' created (so you can compile the package for
+     a different kind of computer), type `make distclean'.  There is
+     also a `make maintainer-clean' target, but that is intended mainly
+     for the package's developers.  If you use it, you may have to get
+     all sorts of other programs in order to regenerate files that came
+     with the distribution.
+
+Compilers and Options
+=====================
+
+   Some systems require unusual options for compilation or linking that
+the `configure' script does not know about.  You can give `configure'
+initial values for variables by setting them in the environment.  Using
+a Bourne-compatible shell, you can do that on the command line like
+this:
+     CC=c89 CFLAGS=-O2 LIBS=-lposix ./configure
+
+Or on systems that have the `env' program, you can do it like this:
+     env CPPFLAGS=-I/usr/local/include LDFLAGS=-s ./configure
+
+Compiling For Multiple Architectures
+====================================
+
+   You can compile the package for more than one kind of computer at the
+same time, by placing the object files for each architecture in their
+own directory.  To do this, you must use a version of `make' that
+supports the `VPATH' variable, such as GNU `make'.  `cd' to the
+directory where you want the object files and executables to go and run
+the `configure' script.  `configure' automatically checks for the
+source code in the directory that `configure' is in and in `..'.
+
+   If you have to use a `make' that does not supports the `VPATH'
+variable, you have to compile the package for one architecture at a time
+in the source code directory.  After you have installed the package for
+one architecture, use `make distclean' before reconfiguring for another
+architecture.
+
+Installation Names
+==================
+
+   By default, `make install' will install the package's files in
+`/usr/local/bin', `/usr/local/man', etc.  You can specify an
+installation prefix other than `/usr/local' by giving `configure' the
+option `--prefix=PATH'.
+
+   You can specify separate installation prefixes for
+architecture-specific files and architecture-independent files.  If you
+give `configure' the option `--exec-prefix=PATH', the package will use
+PATH as the prefix for installing programs and libraries.
+Documentation and other data files will still use the regular prefix.
+
+   If the package supports it, you can cause programs to be installed
+with an extra prefix or suffix on their names by giving `configure' the
+option `--program-prefix=PREFIX' or `--program-suffix=SUFFIX'.
+
+Optional Features
+=================
+
+   Some packages pay attention to `--enable-FEATURE' options to
+`configure', where FEATURE indicates an optional part of the package.
+They may also pay attention to `--with-PACKAGE' options, where PACKAGE
+is something like `gnu-as' or `x' (for the X Window System).  The
+`README' should mention any `--enable-' and `--with-' options that the
+package recognizes.
+
+   For packages that use the X Window System, `configure' can usually
+find the X include and library files automatically, but if it doesn't,
+you can use the `configure' options `--x-includes=DIR' and
+`--x-libraries=DIR' to specify their locations.
+
+Specifying the System Type
+==========================
+
+   There may be some features `configure' can not figure out
+automatically, but needs to determine by the type of host the package
+will run on.  Usually `configure' can figure that out, but if it prints
+a message saying it can not guess the host type, give it the
+`--host=TYPE' option.  TYPE can either be a short name for the system
+type, such as `sun4', or a canonical name with three fields:
+     CPU-COMPANY-SYSTEM
+
+See the file `config.sub' for the possible values of each field.  If
+`config.sub' isn't included in this package, then this package doesn't
+need to know the host type.
+
+   If you are building compiler tools for cross-compiling, you can also
+use the `--target=TYPE' option to select the type of system they will
+produce code for and the `--build=TYPE' option to select the type of
+system on which you are compiling the package.
+
+Sharing Defaults
+================
+
+   If you want to set default values for `configure' scripts to share,
+you can create a site shell script called `config.site' that gives
+default values for variables like `CC', `cache_file', and `prefix'.
+`configure' looks for `PREFIX/share/config.site' if it exists, then
+`PREFIX/etc/config.site' if it exists.  Or, you can set the
+`CONFIG_SITE' environment variable to the location of the site script.
+A warning: not all `configure' scripts look for a site script.
+
+Operation Controls
+==================
+
+   `configure' recognizes the following options to control how it
+operates.
+
+`--cache-file=FILE'
+     Use and save the results of the tests in FILE instead of
+     `./config.cache'.  Set FILE to `/dev/null' to disable caching, for
+     debugging `configure'.
+
+`--help'
+     Print a summary of the options to `configure', and exit.
+
+`--quiet'
+`--silent'
+`-q'
+     Do not print messages saying which checks are being made.
+
+`--srcdir=DIR'
+     Look for the package's source code in directory DIR.  Usually
+     `configure' can determine that directory automatically.
+
+`--version'
+     Print the version of Autoconf used to generate the `configure'
+     script, and exit.
+
+`configure' also accepts some other, not widely useful, options.
+
Index: /main/tags/2.25/gsdl/packages/mg/INSTALL.mg
===================================================================
--- /main/tags/2.25/gsdl/packages/mg/INSTALL.mg	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/mg/INSTALL.mg	(revision 21064)
@@ -0,0 +1,38 @@
+                     BUILDING AND INSTALLATION OF MG
+                     ===============================
+ 
+This file explains how to build the mg system.
+ 
+(1) Follow the general GNU install instructions in the INSTALL file.
+    NOTE: this procedure has changed from version mg-1.1 which did
+    not use a GNU configure script.
+    e.g.
+      cd ~/mg-1.2
+      ./configure --prefix=`pwd`
+      make
+      make check
+      make install
+    Report portability problems to tes@kbs.citri.edu.au .
+ 
+(2) You will need to set the environment variable MGDATA which 
+    indicates where the mg data files will be created. You will also
+    need to create the directory you specify.
+ 
+    e.g.
+        setenv MGDATA ~/mgdata
+	mkdir ~/mgdata
+
+(4) You may also need to set the environment variable MGSAMPLE which
+    is used by mg_get and indicates where the sample data included
+    with this package is located.
+    If this is not specified it defaults to ``./SampleData''
+
+(4) Included with mg is an X11 interface to mgquery called xmg. 
+    Xmg is a ``wish'' script which uses the Tcl/Tk packages available
+    by anonymous ftp from allspice.berkeley.edu [128.32.150.27].
+ 
+(5) Another environment variable that you may wish to set is
+    MGIMAGEVIEWER, this variable sets the image viewer to be used
+    to display images. The image viewer must take the image from stdin.
+    If this is not specified it defaults to ``xv -''.
+ 
Index: /main/tags/2.25/gsdl/packages/mg/MODIFICATIONS
===================================================================
--- /main/tags/2.25/gsdl/packages/mg/MODIFICATIONS	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/mg/MODIFICATIONS	(revision 21064)
@@ -0,0 +1,1023 @@
+TITLE
+  Parsing of Long Words
+APPLICATION
+ mg-1, mg-2
+TYPE
+  bug
+REPORT
+  tim@cosc.canterbury.ac.nz - May 11th 1994
+FIX
+  tes@kbs.citri.edu.au - August 9th 1994
+CLAIM
+  Mg didn't handle long words properly; it crashed.
+PROBLEM
+  Invf passes calls PARSE_LONG_WORD [words.h] which uses a limit of
+  MAXLONGWORD on iterating thru the string and storing into 
+  a word. MAXLONGWORD = 8192.
+  However, mg strings generally store the length in the first
+  byte limiting them to 255 characters. The word which was passed
+  to PARSE_LONG_WORD was an allocated string of MAXSTEMLEN = 255,
+  which is as large as we should get anyway. Thus when accessing
+  a larger word than 255 chars, PARSE_LONG_WORD would allow it
+  (less than 8192) and would try storing beyond the array limit.
+SOLUTION
+  The author can't remember why PARSE_LONG_WORD was used and what
+  the significance of MAXLONGWORD = 8192 is.
+  So PARSE_LONG_WORD has been changed to PARSE_STEM_WORD which
+  uses MAXSTEMLEN as its limit.
+FILES
+ *   words.h
+ *   invf.pass1.c
+ *   invf.pass2.c
+ *   ivf.pass1.c
+ *   ivf.pass2.c
+ *   query.ranked.c
+*************************************************************
+TITLE
+  Use of Lovins stemmer
+APPLICATION
+  mg-1
+TYPE
+  improve
+REPORT
+  local - 1994
+FIX
+  linh@kbs.citri.edu.au - 1994
+CLAIM
+  Stemming was done naively.
+PROBLEM
+  Only a few types of words and their endings
+  were considered.
+SOLUTION
+  Replacement with a more elaborate "known" stemmer by Lovins.
+  The algorithm is described in:
+    J.B. Lovins, "Development of a Stemming Algorithm",
+    Mechanical Translation and Computational Linguistics, Vol 11,1968.
+FILES
+ *   stem.c
+ *   stem.h
+*************************************************************
+TITLE
+  Different term parsing
+APPLICATION
+  mg-1
+TYPE
+  bug
+REPORT
+  tes@kbs.citri.edu.au - 23 Aug 1994
+FIX
+  tes@kbs.citri.edu.au - 23 Aug 1994
+CLAIM
+  Boolean queries did not extract words/terms using the
+  same method as is done at inverted-file creation and
+  as is used for rank query parsing.
+PROBLEM
+  The hand-written lex. analyser, query_lex, which is called by
+  the boolean query parser was not calling a common
+  word-extraction routine as used by the rest of mg. 
+  This would be ok if the code did the same things - but they didn't.
+  Query_lex, for instance, did NOT place any limit on the
+  number of digits in a term.
+  Of even more concern, it would allow arbitrary sized words
+  although it used Pascal style strings which store the length
+  in the first byte and can therefore only be 255 characters in length.
+SOLUTION
+  Query_lex in "query.bool.y", was modified to call the routine
+  PARSE_STEM_WORD which is also used by text-inversion routines and
+  ranking query routines.
+  Now all terms are extracted by the same routine.
+  To do this, the end of the line buffer had to be noted as
+  PARSE_STEM_WORD requires a pointer to the end - which is the
+  safe thing to do (don't want to run over the end).
+  This meant I had to find the length of the query line buffer.
+  This was allocated in the file "read_line.c" by the routine,
+  "readline". Its size was the literal number 1024. 
+  This was changed to a constant and placed in "read_line.h".
+  The definition for PARSE_STEM_WORD can be found in "words.h".
+FILES
+ *   query.bool.y
+ *   query.bool.c (by bison)
+ *   read_line.c
+ *   read_line.h
+*************************************************************
+TITLE
+  Highlighting of query terms
+APPLICATION
+  mg-1
+TYPE
+  extend
+REPORT
+  tes@kbs.citri.edu.au - Aug 94
+FIX
+  tes@kbs.citri.edu.au - Sep 94
+CLAIM
+  Difficult to feel happy that the query-result returned is
+  satisfying the query - need to look hard to find the queried words.
+  Need to show words in results using some highlighting method.
+PROBLEM
+  No highlighting of query terms in results.
+SOLUTION
+  Mgquery was previously outputting the decompressed text to a pager
+  such as "less(1)" or "more(1)".
+  (Except when redirected or piped elsewhere :)
+  So what was needed was some sort of highlight pager that instead of
+  displaying the text would also use some means for highlighting the
+  stemmed query words. 
+  Two common forms of highlighting were chosen: underline and bolding.
+  These are supported by "less(1)" and possibly by "more(1)" by
+  using the backspace character.
+  A highlight pager will also need to know which words need to be
+  highlighted. Therefore, the code was modified to build up a
+  string of the stemmed query words for passing to the highlight pager.
+  Design Options:
+  ---------------
+    * Could do text filtering in mgquery before passing out to pager.
+      Instead I pipe to a separate process, the "hilite_words" pager,
+      which filters and pipes into less/more.
+    * Could do different highlighting or a combination.
+    * Could use a different structure for storing the query words other
+      than the hash-table I used.
+FILES
+ *   Makefile - to include hilite_words target
+ *   mg_hilite_words.c
+ *   mgquery.c
+ *   mgquery.1
+ *   query.bool.y
+ *   query.ranked.c
+ *   environment.c
+ *   environment.h
+ *   backend.h
+*************************************************************
+TITLE
+  Mg_compression_dict did premature free
+APPLICATION
+  mg-1
+TYPE
+  bug 
+REPORT
+  R.Sosic@cit.gu.edu.au - 23 Sep 94
+FIX
+  R.Sosic@cit.gu.edu.au - 23 Sep 94
+CLAIM
+  mg_compression_dict dumped core in 
+	file: mg_compression_dict.c
+	function: Write_data
+	line: int codelen = hd->clens[i];
+PROBLEM
+  Huffman data, hd, was freed *before* it was accessed again. 
+SOLUTION
+  The freeing of hd has been moved to after all accesses
+  (just before returning).
+FILES
+ *   mg_compression_dict.c
+*************************************************************
+TITLE
+  Boolean tree optimising rewrite
+APPLICATION
+  mg-1
+TYPE
+  bug
+REPORT
+  sosic@kurango.cit.gu.edu.au - 23 Sep 94
+FIX
+  tes@kbs.citri.edu.au - Oct 94
+CLAIM
+  "I am still getting core dump in "and" queries in mgquery, 
+   where the first word does not exist, but the second one does."
+PROBLEM
+  Having freed a particular node, it tried to refree it and 
+  access one of its fields.
+
+  I.e. code-fragment...
+
+       FreeNode(curr); /* where curr = CHILD(base) for 1st term in list */
+       FreeNodes(next);
+       FreeNodes(CHILD(base)); 
+              /* but CHILD(base) has already been freed above */
+              /* if the node was the first one in the list */
+
+SOLUTION
+  A number of things in the code seemed a bit dubious to me.
+  So I have rewritten the boolean optimising stage and abstracted out
+  the various stages - each file starts with "bool".
+  Boolean query optimising seems to be a tricky problem. 
+  It is not clear that putting an expression into a certain form will
+  actually simplify it and whether simplification means faster querying.
+  I have converted a given boolean expression into DNF 
+  (Disjunctive Normal Form).  "And not" nodes, which are readily apparent 
+  in DNF, are converted to "diff" nodes.  I have only applied the idempotency 
+  laws involving TRUE and FALSE, and not the ones requiring matching of 
+  expressions - it is a potentially more complicated problem.
+  The optimiser has been tested by playing with "bool_tester", and if you are
+  having a crash or problem in a boolean query it would be worth testing the
+  query on the "bool_tester." The token "*" stands for TRUE (or all documents) 
+  and the token "_" stands for FALSE (or no documents). This should show the 
+  expression before and after optimisation in an ascii tree bracketting format.
+FILES
+ *   bool_tree.c
+ *   bool_parser.y
+ *   bool_optimiser.c
+ *   bool_query.c 
+ *   bool_tester.c
+ *   term_lists.c
+*************************************************************
+TITLE
+  Mgtic pixel placement
+APPLICATION
+  mg-1
+TYPE
+  bug
+REPORT
+  Bruce McKenzie - bruce@cosc.canterbury.ac.nz (21st Oct 1994)
+FIX
+  singlis@cs.waikato.ac.nz
+CLAIM
+  mgtic crashed on certain files.
+PROBLEM
+  Placing pixels outside of bitmap.
+SOLUTION
+  Changed the putpixel routine to truncate at borders of the image.
+FILES
+ *   mgtic.c
+*************************************************************
+TITLE
+  Improved boolean tree optimising
+APPLICATION
+  mg-1
+TYPE
+  improve
+REPORT
+  tes@kbs.citri.edu.au - 12/Dec/94
+FIX
+  tes@kbs.citri.edu.au - 21/Dec/94, 14/Mar/95
+CLAIM
+  Optimising by conversion to DNF is not necessarily such
+  a good idea - can actually slow things down.
+PROBLEM
+  The distributive law used in converting to DNF
+  duplicates expressions.
+SOLUTION
+  Introduce a query environment variable, optimise_type = 0 | 1 | 2.
+  Type 0 does nothing to the parse tree. 
+  Type 2 does the DNF conversion.
+  Type 1 is the new default and does the following...
+    Do simple tree rearrangement like flattening. 
+    Optimise for CNF queries.
+FILES
+ *   bool_query.c, .h
+ *   bool_optimiser.c
+ *   environment.c
+ *   invf_get.c
+ *   bool_tree.c, .h
+ *   bool_tester.c
+ *   lists.h
+*************************************************************
+TITLE
+  Similarity variants
+APPLICATION
+  mg-2
+TYPE
+  extend
+REPORT
+  jz@kbs.citri.edu.au/alistair - June 1994
+FIX
+  tes@kbs.citri.edu.au - July 1994 .. Feb 1995
+CLAIM
+  Can only use one type of similarity measure - the
+  standard cosine measure.
+PROBLEM
+  See CITRI/TR-95-3 for more details.
+  The standard measure can be broken up into 7 components.
+  The 7 components are  
+  Each one of these components has a number of alternatives.
+  The overall measure, S_qd, can also be altered.
+  Thus the particular similarity measure used can be specified
+  by an 8 dimensional vector.
+  What is desired is to be able to specify to mgquery an option
+  and a 8-digit string representing this vector (assuming that
+  any one alternative can have at most 9 (not using zero) variants).
+SOLUTION
+  The programs which had to be modified were:
+  (i) mgquery,
+  (ii) mg_weights_build.
+  The other mg programs in existence store the text, indexing info,
+  and the basic statistics such as N, n, ft, fdt.  
+  Other programs which had to be created were:
+  (i) mg_fmd_build,
+  (ii) mg_wt_build.
+  Mg_fmd_build will create the file to store the f_md statistic, 
+  where f_md is the largest (maximum) f_dt of any term in document, d.
+  Mg_wt_build will create the file to store the w_t primitive.
+  It only creates this for the w_t variants 6-9 which would require
+  extra passes of invf at query time if they were not stored here.
+  For details on similarity changes for mgquery and mg_weights_build,
+  please see the other modification entries.  
+FILES
+ *   mg_fmd_build.c
+ *   mg_wt_build.c
+ *   build_lib.c, build_lib.h
+*************************************************************
+TITLE
+  Similarity variants for mgquery
+APPLICATION
+  mg-2
+TYPE
+  extend
+REPORT
+  jz@kbs.citri.edu.au/alistair - June 1994
+FIX
+  tes@kbs.citri.edu.au - July 1994 .. Feb 1995
+CLAIM
+  "mgquery" needs to be altered to allow modification of
+  the similarity measure. 
+PROBLEM
+  See CITRI/TR-95-3 for more details.
+SOLUTION
+
+  Most of the similarity measures, Sqd, are of the 
+  form:   Aqd
+         -----
+          Bqd
+  where Bqd is an expression involving Wd and possibly Wq,
+  where Aqd is a sum over the common document/query terms
+  of w_qt and w_dt.
+  Building of Aqd
+  ===============
+  The calculation of Aqd is done in the file build_Aqd.c .
+  The functions for doing this used to be in the file invf_get.c .
+  Build_Aqd.c contains 4 different functions for building Aqd, each
+  of them building a different data structure:
+    (i) Array, (ii) Splay Tree, (iii) Hash Table, (iv) List Table.
+  Each of these routines seems to have been construction by modifications
+  to duplicated code. This is often the easiest way to construct variants
+  but is quite difficult to maintain consistency. 
+  As the aim of the exercise was to try out different sim. measures for
+  retrieval effectiveness, I only modified the code that constructed
+  an array. This routine was called "CosineDecode"; I changed it to
+  "build_Aqd_Array." This change reflects the fact that we are only 
+  calculating Aqd and this need not be used for the Cosine measure.
+  The other routines: "CosineDecodeSplay," "CosineDecodeHash," and
+  "CosineDecodeList" have been left unaltered - they need to be updated
+  in the future which would be best be done by abstracting out common code.
+  By the stage of building Aqd, the query terms have been looked up in
+  the inverted file dictionary and put into a list.
+  This list of common terms is traversed to lookup the corresponding
+  invf entries. Before the invf entry is processed, all query and term
+  relevant statistics and primitive quantities are calculated.
+  For example, fqt, ft, wt, rqt, wqt, Wq-partial-sum.
+  To save unnecessary calculations, there is a test for each value
+  to see whether it is needed e.g. "if (sim->variant_needs & NEEDS_wt) ... ".  
+  Aside: Variant Needs
+  --------------------
+  The idea behind the "variant_needs" field is to be able to have all
+  the code in the one place for each possible variant and this code would
+  get the information at the correct time/place only when it is needed.
+  The overhead is a "bit-and" and "test" for each component.
+  The important concern though, is that the "variant_needs" must be
+  accurate i.e. it should be carefully maintained.
+  Each possible need is stored as a bit position in a constant/macro
+  of the form "NEEDS_component" e.g. NEEDS_wt, NEEDS_nt 
+  More recently (Jan/95), I have found that the _need_ing of a component
+  may be relevant to a particular purpose, that is, it may be needed in
+  one situation and not another. This was the case for Wd. 
+  For rdt#6, Wd was needed, however, it might not be needed for Bqd, the
+  denominator of Sqd. So I changed from NEEDS_Wd to NEEDS_Wd_for_Sqd and
+  NEEDS_Wd_for_rdt. 
+  --------------------
+  To handle the different calculations of the variants, I wrote macros
+  based around a switch statement. All these macros are stored in the file
+  "similarity.h" . The point of doing this is to centralise most of the changes
+  and cut down on the number of files which have to be altered if a new
+  way of calculating a primitive is to be added.  
+  This is achieved by having a data record called, "Similarity_variant" whose
+  fields includes all the statistics and the similarity primitives.
+  So the standard procedure is to see if something is needed and if so, then
+  extract it from an mg file or calculate it using a macro - most of the
+  input and output to the macro is done via the "Similarity_variant" structure.
+  As well as calculating Aqd, it is also a convenient place to calculate Wq.
+  Previously, for Cosine measure, Wq was not needed because each Aqd was directly
+  divided by Wq and thus would not change the ordering. However, there are
+  some Sqd's which divide by a sum involving Wq and thus need Wq. 
+  Calculating Sqd and Ordering Documents
+  ====================================== 
+  The file query.ranked.c contains the code for calculating Sqd using the
+  approximate Wd in order to do the ranking of the documents.
+  The mg-1 file was cleaned up and modified slightly.
+  All the heap data structures and routines were taken out and placed in 
+  their own file, heap_weights.c/.h .
+  The major components/steps in the ranking process were abstracted into
+  macros and functions:
+    calc_MaxParas
+    insert_heap_entry
+    insert_greater_heap_entry
+    approx_guided_insert
+    fill_initial_heap
+    add_heap_remainders
+    change_heap_to_exact
+    add_remainder_exact_weights
+    Make_Exact_Root
+    build_doc_list
+  Aside: Zeroing of an Aqd Element
+  -------------------------
+  One interesting change concerned the use of zeroing out an Aqd element
+  so as to mark it as being used in the heap.
+  In the heap, the approx. Sqd is stored based on Aqd/Wd-approx.
+  Later when Aqd is required, it can be extracted from the approx. Sqd
+  by muliplication of Wd-approx i.e. Aqd = Sqd-approx * Wd-approx.
+  This, however, is not always possible for the various Sqd variants.
+  So, instead of zeroing out Aqd, I decided just to make it negative.
+  -------------------------
+  In some Sqd cases, Wd and Wd-approx. are not required. In which case,
+  step 3 which calls on "change_heap_to_exact", "Heap_Build" and
+  "add_remainder_exact_weights" is not required.
+ 
+FILES
+ *    build_Aqd.c
+ *    query.ranked.c
+ *    similarity.c/.h (in libmg)
+ *    heap_weights.c/.h
+ *    backend.c/.h
+*************************************************************
+TITLE
+  Similarity variants for mg_weights_build
+APPLICATION
+  mg-2
+TYPE
+  extend
+REPORT
+  jz@kbs.citri.edu.au/alistair - June 1994
+FIX
+  tes@kbs.citri.edu.au - July 1994 .. Feb 1995
+CLAIM
+  "mg_weights_build" needs to be altered to allow modification of
+  the similarity measure.
+PROBLEM
+  See CITRI/TR-95-3 for more details.
+SOLUTION
+  The weight files which are generated for a particular similarity
+  measure have their names extended by a suffix.
+  In the case of Wd#1 no weights are generated.
+  In the case of the standard cosine weights, Wd#2, a 3 letter suffix
+  is used to represent .
+  In the case of the other Wd variants, a one letter suffix is used
+  to represent which Wd variant it is.
+  In each case, the variant input (e.g. -q 22222222) should be the whole
+  similarity variant string and the relevant fields will be extracted out.
+  This is done for consistency in code and interface. 
+  The code is fairly similar to the original.
+  A dependency check has been added so that the dates of files and the
+  type of needed files is verified before building.
+  The dependencies include, invf dictionary, invf index, invf, fmd and wt files.
+  The major change here, is the possible use of fmd and/or wt files.
+  Later when I was having to write mg_fmd_build and mg_wt_build,
+  I decided to abstract out some macros, namely:
+    Get_ft, Get_ft_Ft, loop_invf_entry,
+  which were put into "build_lib.c" .
+  "loop_invf_entry" takes a function/macro name as a parameter and applies
+  it to the sim record (with field fdt set), current doc number and modifies
+  the return value. 
+FILES
+ *   mg_weights_build.c
+ *   build_lib.c
+*************************************************************
+TITLE
+  Mgstat with non-existent files
+APPLICATION
+  mg-1
+TYPE
+  bug
+REPORT
+  beebe@math.utah.edu - 16 May 1994
+FIX
+  tes@kbs.citri.edu.au - 10 Aug 1994
+CLAIM
+  NaNs and Infinites would be printed out by mgstat
+  if unable to open .text or .text.dict file.
+PROBLEM
+  The NaNs etc. were output in the column stating
+  the percentage size of the file compared with the
+  number of input bytes of the source text data.
+  If it couldn't read the .text file with its
+  header describing the number of source text bytes, then
+  in working out the percentage it would divide by zero.
+  Also due to some bad control flow, it wouldn't attempt to
+  open the .text file if it failed when opening 
+  the .text.dict file.
+SOLUTION
+  Only printout the percentage if we can read the header
+  from the .text file.
+  Read in text header irrespective of text dictionary file.
+FILES
+ *   mgstat.c
+*************************************************************
+TITLE
+  Boolean tree optimisations
+APPLICATION
+  mg-2
+TYPE
+  extend
+REPORT
+  (i) tes@kbs.citri.edu.au - 28/Sep/94
+  (ii) tes@kbs.citri.edu.au - 12/Dec/94
+FIX
+  (i) tes@kbs.citri.edu.au - 18/Oct/94
+  (ii) tes@kbs.citri.edu.au - 21/Dec/94
+CLAIM
+  The initial prompt for investigating the optimisation of
+  boolean queries is noted in the mg-1 mod14.txt. 
+  The code for optimising seemed to have a number of faults.
+PROBLEM
+  Boolean optimisation was unreliable.
+SOLUTION
+  Initially (in case (i) above, see mg-1/mod14.txt), I rewrote 
+  all the boolean tree and optimising code. I converted the boolean
+  expression into DNF. I did this after reading some notes about 
+  the steps involved in optimisation and they suggested standardising
+  in some normal form. I thought that DNF would be appropriate so that
+  all the terms are converted to be part of "and" expressions and be
+  evaluated quickly using skipping.
+  This, however, can suffer quite badly if the distributive law is
+  applied to often and the query expands in size. If there was
+  some sort of cacheing of invf entries, then it might not be so
+  bad otherwise there is quite an overhead on reading the same
+  invf entry more than once.
+
+  As it happens, CNF queries are reasonably common, where the user
+  queries with a conjunction of disjunctions of similes:
+    e.g. (car | automobile | vehicle) & (fast | quick | speedy)
+  This sort of CNF query expands a hell of a lot !
+  So after speaking with Justin who wanted to benchmark Atlas with Mg on
+  these sort of queries, I looked up the MG book for other ideas.
+
+  The method that I implemented was the following:
+
+  -----------------------------------------------------------------
+  Steps of tree modifications:
+    Gets literals by pushing the nots down, detecting T/F at leaves
+    and collapsing the tree by detecting  'and' of 'and's and 'or' of
+    'or's.
+    Next it looks at the or nodes and if all the children are terms
+    then it marks the or-node as such.
+    Finally, the or-term-nodes are sorted by using the sum of their
+    ft's for comparison.
+  Steps at query evaluation:
+    If it comes across an 'and' of 'or-terms' then the evaluation is
+    done noting the distributive law.
+    I.e. a & (b | c | d) = (a & b) | (a & c) | (a & d)
+    Assuming 'a' is the c-set of documents.
+    All of 'a' is tested against 'b' and matching ones are marked.
+    Next, all the unmarked members of 'a' are tested against 'c'.
+    Likewise for 'd'.
+    Now all the marked members of our c-set are kept.
+    When we do the testing, we can use the skipping in the invf entries.
+  -----------------------------------------------------------------
+
+
+  After doing this, I added the choice of which type of optimisation
+  the user wanted by adding query-environment-variable, "optimise_type".
+  Type 0 = no parse tree modification. 
+  Type 1 = Or-term recognition and CNF query evaluation optimisation. 
+  Type 2 = Put into DNF form. [generally not recommended]
+FILES
+ *   bool_tree.c
+ *   bool_parser.y
+ *   bool_optimiser.c
+ *   bool_query.c 
+ *   bool_tester.c
+ *   term_lists.c
+ *   query_env.c
+ *   invf_get.c [GetDocsOp]
+*************************************************************
+TITLE
+  nonexistent HOME bug  
+APPLICATION
+  mg-1, mg-2
+TYPE
+  bug 
+REPORT
+  cgn@totara.cs.waikato.ac.nz - 2/May/95
+FIX
+  tes@kbs.citri.edu.au - 2/May/95
+CLAIM
+"The big problem was that mgquery crashes when the HOME environment
+ variable is not set, which is the case when it is run by the www server."
+ [...] "I expect it happens when looking for $HOME/.mgrc."
+PROBLEM
+  The result of getenv("HOME")" was used directly in
+  a sprintf call. If the environment variable HOME
+  was not in existence then null would be used.
+  In some C libraries sprintf will convert the 0
+  string into the string "(null)" on others it will core dump.
+  (For example, Solaris seems to core dump, sunos 4 seems ok).
+SOLUTION
+  The result from getenv("HOME")" is tested before
+  being used.
+FILES
+ *   commands.c
+*************************************************************
+TITLE
+  mgquery collection name preference  
+APPLICATION
+  mg-1, mg-2
+TYPE
+  improve
+REPORT
+  cgn@totara.cs.waikato.ac.nz - 2/May/95
+FIX
+  tes@kbs.citri.edu.au - 4/May/95
+CLAIM
+ Surely something must override mquery's preference for ./bib. 
+ If MGDATA is set correctly, I think it should prefer that collection, 
+ and -d should definitely override it. 
+ I could always say -d . if I really wanted ./bib.
+PROBLEM
+Currently the priority is:
+1.  Check if ./name is a directory,
+     If so then use it as the collection directory.
+2.  Check if ./name.text is a file,
+     If so then use ./ as the collection directory.
+3.  Check if mgdir/name is a directory,
+     If so then use mgdir/name as the collection directory.
+4.  Otherwise,
+     Use mgdir/name as the database file prefix.
+     This would be the case if one used "-f alice/alice".
+     However, one would then not specify a final name argument
+     and we'd never get here. Go figure ???
+SOLUTION
+Moved step 3 to the top instead.
+FILES
+ *   mgquery.c [search_for_collection()]
+*************************************************************
+TITLE
+  Printout of query terms
+APPLICATION
+  mg-1, mg-2
+TYPE
+  extend
+REPORT
+  tes@kbs.citri.edu.au - April 95
+FIX
+  tes@kbs.citri.edu.au - April 95
+CLAIM
+  No easy way to find out the parsed and stemmed words
+  used in the query. Would like to know these words
+  so I can call a separate highlighting program to 
+  highlight these words.
+PROBLEM
+  No facility available.
+SOLUTION
+  A ".queryterms" mgquery command was added which lists
+  out the parsed/stemmed queryterms of the last query.
+FILES
+ *    commands.c (added CmdQueryTerms)
+*************************************************************
+TITLE
+  mg_getrc  
+APPLICATION
+  mg-1, mg-2
+TYPE
+  extend
+REPORT
+  bruce@cosc.canterbury.ac.nz - 2/May/95
+FIX
+   - 
+CLAIM
+  Repeated code had to be written for different named
+  gets but really the same type of parsing required.
+  E.g. one might want to use a standard method for inserting
+  ^Bs between paragraphs for different books. One doesn't
+  want to write duplicate code for each different named book,
+  rather note that each book should be filtered "book" style.
+PROBLEM
+  There was no way of abstracting out types of filters from
+  the name of an instance of a collection.
+SOLUTION
+  Allow information to be given with <name, type, files>.
+  This extra info can be provided in a mg_getrc file.
+  See man page for mg_get for details.
+FILES
+ *    mg_get.sh
+*************************************************************
+TITLE
+  TREC DocNo file   
+APPLICATION
+  mg-2
+TYPE
+  improve
+REPORT
+  tes@kbs.citri.edu.au - 26/May/95
+FIX
+  tes@kbs.citri.edu.au - 26/May/95
+CLAIM
+  MG has problems dealing with trec docnos for trec disk 3.
+PROBLEM
+  Trec DocNos file didn't have a wide enough field
+  to handle disk 3. 
+SOLUTION
+  Allow different width fields for file.
+  It is still fixed width but a number in the header
+  says how wide the field is.
+FILES
+ *   passes/mg.special.c
+ *   query/mgquery.c
+*************************************************************
+TITLE
+  Boolean optimiser #1 with `!'  
+APPLICATION
+  mg-1, mg-2
+TYPE
+  bug 
+REPORT
+  triffid@iconz.co.nz - 20/7/95
+FIX
+  tes@kbs.citri.edu.au - 27/7/95
+CLAIM
+  Complained about not-nodes. 
+  e.g. complained about "croquet & !hedgehog"
+PROBLEM
+  Boolean optimiser type#1 didn't convert
+  "and not"s into diff nodes.
+SOLUTION
+  Added code to convert '&!' to '-'.
+FILES
+ *   mg/bool_optimiser.c [mg-1]
+ *   query/bool_optimiser.c [mg-2]
+*************************************************************
+TITLE
+   Autoconfiguring mg-1  
+APPLICATION
+  mg-1
+TYPE
+  improve
+REPORT
+  many people - 94/95
+FIX
+  tes@kbs.citri.edu.au - Aug/95
+CLAIM
+  Portability is limited by setting up c-macros just for particular
+  machines and operating systems.
+  People had to make changes for HP, Next, Linux, Dec Alpha, ...
+PROBLEM
+  Porting was only targetting at the machines that the author had
+  access to.
+SOLUTION
+  Use GNU's autoconfigure program.
+  This allows checking of the systems features/characteristics.
+  It also allows some checking for specific machines/OS - although
+  I have not utilised this option.
+  I used GNU's tar-1.11.8 as an example to base my changes on.
+  I also used autoscan to generate the initial "configure.in".
+  The "Makefile.in"s were done very similarly to GNU tar's.
+  The "config.h" and "sysfuncs.h" files were scrapped and 
+  rewritten. The new "config.h" file is generated by the configure
+  script - it contains all the #define's for the system features.
+  The "sysfuncs.h" file wraps up a number of system headers. 
+  For example, some systems use , while some use ;
+  which one is included is decided in "sysfuncs.h".
+  I have also used GNU tar's use of ansi2knr in its Makefiles.
+  This should hopefully allow the package to work on a system with
+  only a K&R C compiler.
+  However, there are probably problems with what I have done.
+  I am concerned about <stdarg.h> for example.
+  I also noticed that "ansi2knr" require function definitions as
+  the GNU coding style recommends ie. with function name the first
+  string on the line. This prompted me to run all the package's code
+  thru GNU's indent.
+  Setting up the configure changes is difficult. It really seems
+  necessary to try the package out on many target machines so one
+  can know what is necessary.
+  A simple check target for the main Makefile has been written.
+  It is used to see if the installation is working - it does
+  not test much of the functionality of mg.
+  It does cmp's on data files and diff's on query/result files.
+FILES
+  Most of the files in the distribution.
+*************************************************************
+TITLE
+  Consistent use of stderr
+APPLICATION
+  mg-1
+TYPE
+  improve
+REPORT
+  beebe@math.utah.edu - 16 May 1994
+FIX
+  tes@kbs.citri.edu.au - 11 August 1994
+CLAIM
+  Inconsistent use of stdout/stderr in usage messages.
+PROBLEM
+  Sometimes used "printf" and sometimes used "fprintf(stderr"
+  in usage messages.
+SOLUTION
+  All should now use "fprintf(stderr" in usage messages.
+FILES
+ *   mg_compression_dict.c
+ *   mg_compression_dict.1
+ *   mg_fast_comp_dict.c
+ *   mg_fast_comp_dict.1
+ *   mg_invf_dict.c
+ *   mg_invf_dict.1
+ *   mg_invf_dump.c
+ *   mg_invf_dump.1
+ *   mg_invf_rebuild.c
+ *   mg_invf_rebuild.1
+ *   mg_perf_hash_build.c
+ *   mg_perf_hash_build.1
+ *   mg_text_estimate.c
+ *   mg_text_estimate.1
+ *   mg_weights_build.c
+ *   mg_weights_build.1
+*************************************************************
+TITLE
+  xmg bug
+APPLICATION
+  mg-1
+TYPE
+  bug
+REPORT
+  cgn@cpsc.ucalgary.ca - 22 April 1994
+FIX
+  cgn@cpsc.ucalgary.ca - 22 April 1994
+CLAIM
+  "Serious problem in xmg, which I fear occurs whenever a query
+   doesn't return anything."
+PROBLEM
+  ??
+SOLUTION
+  [xmg.sh 201] set rank 0
+FILES
+ *   xmg.sh
+*************************************************************
+TITLE
+  Unnecessary loading of text
+APPLICATION
+  mg-1
+TYPE
+  bug
+REPORT
+  tes@kbs.citri.edu.au - ?? August 1994
+FIX
+  tes@kbs.citri.edu.au - 12 August 1994
+CLAIM
+  Mg was loading and uncompressing text when the
+  query did not require the text.
+PROBLEM
+  There was no test for the query mode
+  before loading and uncompressing the text.
+SOLUTION
+  Only load/uncompress text if query mode
+  is for text, headers or silent(for timing).
+FILES
+ *   mgquery.c
+*************************************************************
+TITLE
+  Man page errors
+APPLICATION
+  mg-1
+TYPE
+  bug
+REPORT
+  beebe@math.utah.edu - 16 May 1994
+FIX
+  beebe@math.utah.edu - 16 May 1994
+CLAIM
+  Man page errors.
+PROBLEM
+  See below.
+SOLUTION
+ "The mg_make_fast_dict.1 file has been renamed mg_fast_comp_dict.1,
+  and all mg_make_fast_dict strings changed to mg_fast_comp_dict in all
+  man pages.
+  A large number of errors of spelling, typography, spacing, fonts,
+  grammar, omitted words, slang, punctuation, missing man page
+  cross-references, and man-page style have been corrected."
+FILES
+ *    mg_compression_dict.1
+ *    mg_fast_comp_dict.1
+ *    mg_get.1
+ *    mg_invf_dict.1
+ *    mg_invf_dump.1
+ *    mg_invf_rebuild.1
+ *    mg_passes.1
+ *    mg_perf_hash_build.1
+ *    mg_text_estimate.1
+ *    mg_weights_build.1
+ *    mgbilevel.1
+ *    mgbuild.1
+ *    mgdictlist.1
+ *    mgfelics.1
+ *    mgquery.1
+ *    mgstat.1
+ *    mgtic.1
+ *    mgticbuild.1
+ *    mgticdump.1
+ *    mgticprune.1
+ *    mgticstat.1
+ *    xmg.1
+*************************************************************
+TITLE
+  Man page overview
+APPLICATION
+  mg-1
+TYPE
+  extend
+REPORT
+  beebe@math.utah.edu - 
+FIX
+  tes@kbs.citri.edu.au - 17 August 1994
+CLAIM
+  "Write new mg.1 file to give a brief overview of mg, with samples
+   of how to use it.  Otherwise, users are likely to be completely
+   overwhelmed by the number of programs (about 20) which might need to
+   be used, when in reality, only 2 or 3 are likely to be run by end
+   users."
+SOLUTION
+  It was thought that mg.1, written by Nelson Beebe, was very useful
+  but a bit too comprehensive for an introduction.
+  Therefore, two man files, mgintro.1 and mgintro++.1 were written
+  with the basic stuff in mgintro.1 and slightly more advanced stuff
+  in mgintro++.1 . 
+FILES
+ *   mg.1
+ *   mgintro.1
+ *   mgintro++.1 
+*************************************************************
+TITLE
+  Parse errors not bus errors
+APPLICATION
+  mg-1
+TYPE
+  bug
+REPORT
+  tim@cosc.canterbury.ac.nz - 2 Jun 94
+FIX
+  tes@kbs.citri.edu.au - 19 Aug 94
+CLAIM
+  "These two queries 
+   (which I typed in before I knew what I was doing!!)
+      > The Queen of Hearts, she made some tarts
+      > "The Queen of Hearts" and "she made some tarts"
+      produced the following result:
+      mgquery : parse error
+      Bus error
+  "
+PROBLEM
+  What is expected to happen under boolean querying:
+    Query1:
+    > The Queen of Hearts, she made some tarts
+    will produce a parse error due to the comma which
+    is not a valid TERM.
+    Query2:
+    > "The Queen of Hearts" and "she made some tarts"
+    will store a post-processing string
+    of ''The Queen of Hearts" and "she made some tarts'' and
+    will have a main boolean query of the empty string.
+    This is because the postprocessing string takes in
+    everything between the first quote and the last one.
+    An empty string is illegal for the boolean grammar and
+    hence a parse error.
+  The problem stems from the fact that the processing of
+  the parse tree is carried out, even though we have a 
+  parse error. In the case of using an empty string to build
+  a parse tree, it is likely to leave the parse tree undefined.
+SOLUTION
+  As soon as we find out that there is a parse-error,
+  we abandon any processing of the parse tree.
+FILES
+ *   query.bool.y
+ *   query.bool.c (generated from query.bool.y)
+*************************************************************
+TITLE
+  Perfect hashing on small vocab
+APPLICATION
+  mg-1
+TYPE
+  bug
+REPORT
+  tes@kbs.citri.edu.au - July 1994
+FIX
+  alistair@cs.mu.oz.au - July 1994
+CLAIM
+  Mg could not handle small collections in the case
+  where there was only a small number of unique words.
+  The perfect hash function would report an error.
+PROBLEM
+  Rounding of the arithmetic during the calculation of the
+  parameters of the perfect hash function was resulting in a
+  combination of values such that the probability of a hash
+  function being found was very small. This led to the limit
+  on the generation loop being exceeded, and eventual
+  failure.
+SOLUTION
+  By using ceiling rather than floor when converting from a
+  floating point value to an integer parameter, the arithmetic
+  is now correct for all lexicon sizes, and the probability of
+  each iteration successfully generating a hash function is
+  sufficiently great that with _very_ high probability the
+  execution loop counter will not be exceeded unless there
+  genuinely is no hash function (for example, if the lexicon
+  contains two words the same there cannot be  a hash
+  function).
+FILES
+ *   perf_hash.c
+*************************************************************
Index: /main/tags/2.25/gsdl/packages/mg/Makefile.in
===================================================================
--- /main/tags/2.25/gsdl/packages/mg/Makefile.in	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/mg/Makefile.in	(revision 21064)
@@ -0,0 +1,160 @@
+# Main Makefile for GNU tar.
+# Copyright (C) 1994, 1995 Free Software Foundation, Inc.
+ 
+# 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, 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 = @PACKAGE@
+VERSION = @VERSION@
+ 
+@SET_MAKE@
+SHELL = /bin/sh
+VPATH = @srcdir@
+exec_prefix = @exec_prefix@
+prefix = @prefix@
+srcdir = @srcdir@
+ 
+
+CC = @CC@
+CFLAGS = @CFLAGS@ 
+INSTALL = @INSTALL@
+INSTALL_DATA = @INSTALL_DATA@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@
+LDFLAGS = @LDFLAGS@
+LIBS = @LIBS@  
+TOUCH = echo timestamp >
+ 
+bindir = $(exec_prefix)/bin
+infodir = $(prefix)/info
+libexecdir = $(exec_prefix)/libexec
+ 
+MDEFINES = 
+#CC='$(CC)' CFLAGS='$(CFLAGS)' LDFLAGS='$(LDFLAGS)' LIBS='$(LIBS)' \
+#prefix='$(prefix)' exec_prefix='$(exec_prefix)' \
+#bindir='$(bindir)' libexecdir='$(libexecdir)' \
+#infodir='$(infodir)' infodir='$(infodir)' libexecdir='$(libexecdir)'
+
+SUBDIRS = lib src/text src/images src/scripts
+
+
+.SUFFIXES:
+
+all install uninstall execinstall execuninstall maninstall manuninstall: ../../config.h
+	for subdir in $(SUBDIRS); do \
+	  echo making $@ in $$subdir; \
+	  (cd $$subdir && $(MAKE) $(MDEFINES) $@) || exit 1; \
+	done
+
+# Have not written any texinfo files for the documentation yet
+#info dvi:
+#	cd doc && $(MAKE) $@
+
+check: all
+	echo making $@ in ./test directory
+	(cd ./test && $(MAKE) all) || exit 1
+	./test/testmg `pwd`
+
+mostlyclean: mostlyclean-recursive mostlyclean-local
+
+clean: clean-recursive clean-local
+
+distclean: distclean-recursive distclean-local
+	rm -f config.status
+
+maintainer-clean: maintainer-clean-recursive maintainer-clean-local
+	rm -f config.status
+
+mostlyclean-recursive clean-recursive distclean-recursive \
+maintainer-clean-recursive:
+	for subdir in $(SUBDIRS); do \
+	  target=`echo $@ | sed 's/-recursive//'`; \
+	  echo making $$target in $$subdir; \
+	  (cd $$subdir && $(MAKE) $$target) || exit 1; \
+	done
+
+mostlyclean-local:
+
+clean-local: mostlyclean-local
+
+distclean-local: clean-local
+	rm -f Makefile stamp-h
+
+maintainer-clean-local: distclean-local
+	@echo "This command is intended only for maintainers to use;"
+	@echo "rebuilding the deleted files may require special tools."
+
+# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
+
+distdir = $(PACKAGE)-$(VERSION)
+
+distname = $(distdir)
+
+DISTFILES = \
+INSTALL.mg INSTALL README README.port COPYING MODIFICATIONS about_mg.html \
+Makefile.in acconfig.h aclocal.m4 configure.in install-sh mkinstalldirs \
+config.guess config.sub \
+config.h.in configure stamp-h.in sysfuncs.h
+
+dist: $(DISTFILES)
+#-----------------------------------------------------------------
+	#create distribution directory
+	-rm -rf $(distdir)
+	mkdir $(distdir)
+#
+	#link in local distribution files
+	ln $(DISTFILES) $(distdir)
+#
+	#link in SampleData
+	mkdir $(distdir)/SampleData
+	(cd SampleData; $(MAKE) "distdir=../$(distdir)/SampleData" dist)
+	# link in davinci stuff
+	mkdir $(distdir)/SampleData/davinci
+	(cd SampleData/davinci; \
+	$(MAKE) "distdir=../../$(distdir)/SampleData/davinci" dist)
+	# link in bible stuff
+	mkdir $(distdir)/SampleData/bible
+	(cd SampleData/bible; \
+	$(MAKE) "distdir=../../$(distdir)/SampleData/bible" dist)
+#
+	#link in tests
+	mkdir $(distdir)/test
+	(cd test; $(MAKE) "distdir=../$(distdir)/test" dist)
+#
+	#link in docs directory
+	mkdir $(distdir)/docs
+	(cd docs; $(MAKE) "distdir=../$(distdir)/docs" dist)
+#
+	#link in lib directory
+	mkdir $(distdir)/lib
+	(cd lib; $(MAKE) "distdir=../$(distdir)/lib" dist)
+#
+	#link in src distribution files
+	mkdir $(distdir)/src
+	for dir in src/text src/images src/scripts; do \
+	  echo makeing $@ in $$dir ; \
+	  mkdir $(distdir)/$$dir; \
+	  (cd $$dir; $(MAKE) "distdir=../../$(distdir)/$$dir" $@) ; \
+	done
+#
+	# archive and compress
+	tar -chf - $(distdir) | gzip -9 > $(distname).tar.gz
+	tar -chf - $(distdir) | compress > $(distname).tar.Z
+#
+	# cleanup
+	rm -rf $(distdir)
+#-----------------------------------------------------------------
+
+# Tell versions [3.59,3.63) of GNU make not to export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:
Index: /main/tags/2.25/gsdl/packages/mg/README
===================================================================
--- /main/tags/2.25/gsdl/packages/mg/README	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/mg/README	(revision 21064)
@@ -0,0 +1,156 @@
+                 MG INFORMATION RETRIEVAL SYSTEM
+                 ===============================
+
+The MG system is a suite of programs for compressing and indexing text
+and images. Most of the functionality implemented in the suite is as
+described in the book ``Managing Gigabytes:  Compressing and Indexing
+Documents and Images'', I.H. Witten, A.  Moffat, and T.C. Bell; Van
+Nostrand Reinhold, New York, 1994, ISBN 0-442-01863-0; US $54.95; call
+1 (800) 544-0550 to order.
+
+These features include:
+
+-- text compression using a Huffman-coded semi-static word-based scheme
+-- two-level context-based compression of bi-level images
+-- FELICS lossless compression of gray-scale images
+-- combined lossy/lossless compression for textual images
+-- indexing algorithms for large volumes of text in limited main memory
+-- index compression
+-- a retrieval system that processes Boolean and ranked queries
+-- an X windows interface to the retrieval system
+
+As one example, a collection of 2 Gb of text (1,700,000 documents) can
+be indexed (on a SPARC 10 Model 512) in about four hours and compressed
+in a further four hours to make a database that in total occupies less
+than 800 Mb, or 40% of the original size. This includes a full index to
+every word and number in the original text. Boolean queries such as
+``managing AND gigabytes'' run in a few seconds, and ranked queries of
+30--50 terms are evaluated in 10--30 seconds.
+
+Details of these methods and further performance results appear in the
+MG book.
+
+The MG system comes with ABSOLUTELY NO WARRANTY; for details see the
+file COPYING.
+
+Instructions on how to build and install mg are in the file INSTALL.
+
+
+** CHANGES FROM BOOK
+
+For copyright reasons the stemmer used in this distribution of MG is
+not the same as the one illustrated in Figure 3.8 on page 108 of the MG
+book.  This means that the numbers generated by the command ``mgstat
+alice'' will not match those numbers in Figure A.1 on page 394.
+Another stemmer was initially written as a simple stopgap for version
+1.0.  That stemmer has been replaced by a stemmer based on the Lovin's
+stemming algorithm for mg-1.1.
+
+The output format of ``mgstat'' has changed since Figure A.1 (page 394)
+was prepared. The same information is displayed but formatted
+differently.
+
+** MG VERSIONS
+
+The current version is mg-1.2, September 1995. The changes from earlier 
+versions are listed in the file MODIFICATIONS. This can be accessed
+with mg by building a database using ``mgbuild mods'' and can also be
+accessed from the mg web page (see below). 
+
+The mg-1.2 extensions include:
+
+-- Source modifications for use of GNU's autoconf.
+
+The mg-1.1 extensions include:
+
+-- A new highlighting mode.
+   The output mode ``hilite'' will highlight the query terms in the
+   retrieved text documents. The variable ``hilite_style'' can be set
+   to ``bold'' or ``underline''. It works best with the pager
+   ``less''.  A .mgrc to use would include:
+	.set pager less
+	.set mode hilite
+	.set hilite_style bold
+
+-- A web site containing manual pages, documentation, and a
+   mgquery demo page (utilising cgi scripts). 
+   See: http://www.kbs.citri.edu.au/mg
+   One of these pages ``about_mg.html'' is included in this
+   distribution.
+
+-- A revised mg_get script which uses a .mg_getrc file to map
+   specific collection names to filter types.  (Modifications by Bruce
+   McKenzie). See mg_get.1 for more details.
+
+-- Code to perform merging of existing databases. This code
+   was created by Shane Hudson and is documented in the mgmerge.README
+   file found in the docs subdirectory.  This code is maintained by
+   Shane Hudson (shane@cosc.canterbury.ac.nz).
+
+-- Revised man pages, including some new entries (thanks to Nelson
+   Beebe). See mg.1, mgintro.1, mgintro++.1.
+
+-- A real (rather than toy) stemmer.
+
+** PORTABILITY
+
+Please refer to "README.port".
+
+** CREDITS
+ 
+The MG development is largely the result of research collaboration
+between:
+
+        Tim C. Bell            <tim@cosc.canterbury.ac.nz>
+        Ian Witten             <ihw@cs.waikato.ac.nz>
+        Alistair Moffat        <alistair@cs.mu.oz.au>
+        Justin Zobel           <jz@cs.rmit.oz.au>
+
+The bulk of the programming work has been carried out by:
+
+        Stuart Inglis          <singlis@cs.waikato.ac.nz>
+        Craig Nevill-Manning   <cgn@cs.waikato.ac.nz>
+        Neil Sharman           <neil@kbs.citri.edu.au>
+        Tim Shimmin            <tes@kbs.citri.edu.au>
+
+In addition to these, the following people have contributed to the
+development of the MG software:
+
+        Lachlan Andrew         <lha@kbs.citri.edu.au>
+        Gary Eddy              <gary@cs.mu.oz.au>
+        Hugh Emberson          <hugh@cosc.canterbury.ac.nz>
+        Kerry Guise            <kerry@cs.waikato.ac.nz>
+	Shane Hudson           <shane@cosc.canterbury.ac.nz>
+        Linh Huynh             <linh@kbs.citri.edu.au>
+        Bohdan S. Majewski     <bohdan@cs.uq.oz.au>
+        Bruce McKenzie         <bruce@cosc.canterbury.ac.nz>
+
+In addition to these, the following people have submitted bug reports
+and suggestions/fixes:
+
+        Rex Barzee             <rex@python.cs.byu.edu>
+        Tim A.H. Bell          <bhat@cs.mu.oz.au>
+        Tim C. Bell            <tim@cosc.canterbury.ac.nz>
+        Nelson Beebe           <beebe@math.utah.edu>
+	Rodney Brown           <RBrown@cmutual.com.au>
+        Rok Sosic              <R.Sosic@cit.gu.edu.au>
+        Carl Staelin           <staelin@cello.hpl.hp.com>
+
+Development of the MG system was supported by the Australian Research
+Council; the Universities of Melbourne, Waikato, Canterbury, and
+Calgary; RMIT; and the Collaborative Information Technology Research
+Institute (Melbourne).
+
+** BUG REPORTS
+
+Send bug reports to <alistair@cs.mu.oz.au> and <tes@kbs.citri.edu.au>.
+Back-traces from gdb are always welcome but not mandatory :-)
+
+** FURTHER READING
+
+A bibliography of MG related research work appears in the files
+MG.Bibliography.ps and MG.Bibliography.bib on the ftp site and
+is accessible through the Web page.
+
+
+
Index: /main/tags/2.25/gsdl/packages/mg/README.port
===================================================================
--- /main/tags/2.25/gsdl/packages/mg/README.port	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/mg/README.port	(revision 21064)
@@ -0,0 +1,125 @@
+P O R T A B I L I T Y
+=====================
+
+The main development of MG is done under Solaris on a Sun sparc.
+However, we would also like MG to be reasonably portable.
+Therefore, MG-1.2 now uses a configure stript generated by GNU's autoconf.
+Below, is a list of the machines that the s/ware has been ported to. 
+Most only need the configure script and some require manual modifications 
+mentioned in the "Problems" field.
+
+------------------------------------------------------------------------- 
+** Systems which have successfully been built.
+
+Tester:		tes@kbs.citri.edu.au
+Date:
+Machine:	Sun
+System:		SunOS 4.1.2 8 sun4c
+Compiler:	gcc version 2.3.3
+Problems:	none
+
+Tester:		tes@kbs.citri.edu.au
+Date:
+Machine:	Sun
+System:		SunOS 4.1.2_DB 14 sun4c
+Compiler:	gcc version 2.3.3
+Problems:	none
+
+Tester:		tes@kbs.citri.edu.au
+Date:
+Machine:	Sun
+System:		SunOS 4.1.3_U1 1 sun4c
+Compiler:	gcc version 2.5.7
+Problems:	none
+
+Tester:		tes@kbs.citri.edu.au
+Date:
+Machine:	Sun
+System:		SunOS 5.3 Generic_Patch sun4m sparc
+Compiler:	gcc version 2.4.3
+Problems:	none
+
+Tester:		tes@kbs.citri.edu.au
+Date:
+Machine:	Silicon Graphics
+System:		IRIX 5.2 02282014 IP7
+Compiler:	gcc version 2.6.3
+Problems:	none
+
+Tester:		tes@kbs.citri.edu.au
+Date:
+Machine:	Sun
+System:		SunOS 5.4 Generic_101945-27 sun4c sparc
+Compiler:	cc: SC3.0.1 13 Jul 1994
+Problems:	none
+
+Tester:		RBrown@cmutual.com.au
+Date:
+Machine:
+System:		SCO 3.2v4.1
+Compiler:	gcc 2.6.1
+Problems:	requires RANLIB=true, use of tcsh
+
+Tester:		RBrown@cmutual.com.au
+Date:
+Machine:	HP
+System:		HP-UX A.09.04 D 9000/837 415303291 64-user license
+Compiler:	HP92453-01 A.09.73 HP C Compiler
+Problems:
+
+Tester:		RBrown@cmutual.com.au
+Date:
+Machine:	Data General
+System:		dgux 5.4R3.00 generic AViiON mc88110 
+Compiler:	gcc 2.4.5 (dg supplied)
+Problems:	none
+
+Tester:		RBrown@cmutual.com.au
+Date:
+Machine:	Pyramid MIPS R3000 box
+System:		
+Compiler:	cc (vendor supplied)
+Problems:	none
+
+Tester:		RBrown@cmutual.com.au
+Date:
+Machine:	IBM RS6000
+System:		AIX 3.2
+Compiler:	AIX XL C Compiler/6000
+Problems:	none
+
+Tester:		RBrown@cmutual.com.au
+Date:
+Machine:	Linux 1.2.9
+System:		
+Compiler:	gcc 2.6.3
+Problems:	none
+
+-----------------------------------------------------------------------
+** Systems which have NOT successfully been built.
+
+Tester:		RBrown@cmutual.com.au, 
+		Lloyd.Parkes@vuw.ac.nz
+Date:		Oct, Nov, 1995
+Machine:	Dec Alpha OSF/1
+System:
+Compiler:	cc
+Problems: 	Many - see below.
+
+* Problems with Dec Alpha
+  - 64 bit length longs as opposed to 32 bit longs.
+  - Lloyd.Parkes@vuw.ac.nz says that there is some bit encoding problems 
+    but the decoding seems to work.
+  - RBrown@cmutual.com.au says that it will compile but will core dump
+    when  building the test database.
+  - tes.kbs.citri.edu.au says that he needs to look into the repercussions
+    of 64 bit longs, however, he does not have access to such a machine.
+		
+-----------------------------------------------------------------------
+** Other systems. 
+
+Systems other than the above may have installation problems.
+If this is the case, please send me (tes@kbs.citri.edu.au) a log of the output
+and I will modify the configuration files in an effort to fix the problems.
+
+-----------------------------------------------------------------------
Index: /main/tags/2.25/gsdl/packages/mg/SampleData/MODIFICATIONS
===================================================================
--- /main/tags/2.25/gsdl/packages/mg/SampleData/MODIFICATIONS	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/mg/SampleData/MODIFICATIONS	(revision 21064)
@@ -0,0 +1,664 @@
+TITLE
+  Parsing of Long Words
+APPLICATION
+ mg-1, mg-2
+TYPE
+  bug
+REPORT
+  tim@cosc.canterbury.ac.nz - May 11th 1994
+FIX
+  tes@kbs.citri.edu.au - August 9th 1994
+CLAIM
+  Mg didn't handle long words properly; it crashed.
+PROBLEM
+  Invf passes calls PARSE_LONG_WORD [words.h] which uses a limit of
+  MAXLONGWORD on iterating thru the string and storing into 
+  a word. MAXLONGWORD = 8192.
+  However, mg strings generally store the length in the first
+  byte limiting them to 255 characters. The word which was passed
+  to PARSE_LONG_WORD was an allocated string of MAXSTEMLEN = 255,
+  which is as large as we should get anyway. Thus when accessing
+  a larger word than 255 chars, PARSE_LONG_WORD would allow it
+  (less than 8192) and would try storing beyond the array limit.
+SOLUTION
+  The author can't remember why PARSE_LONG_WORD was used and what
+  the significance of MAXLONGWORD = 8192 is.
+  So PARSE_LONG_WORD has been changed to PARSE_STEM_WORD which
+  uses MAXSTEMLEN as its limit.
+FILES
+ *   words.h
+ *   invf.pass1.c
+ *   invf.pass2.c
+ *   ivf.pass1.c
+ *   ivf.pass2.c
+ *   query.ranked.c
+*************************************************************
+TITLE
+  Use of Lovins stemmer
+APPLICATION
+  mg-1
+TYPE
+  improve
+REPORT
+  local - 1994
+FIX
+  linh@kbs.citri.edu.au - 1994
+CLAIM
+  Stemming was done naively.
+PROBLEM
+  Only a few types of words and their endings
+  were considered.
+SOLUTION
+  Replacement with a more elaborate "known" stemmer by Lovins.
+  The algorithm is described in:
+    J.B. Lovins, "Development of a Stemming Algorithm",
+    Mechanical Translation and Computational Linguistics, Vol 11,1968.
+FILES
+ *   stem.c
+ *   stem.h
+*************************************************************
+TITLE
+  Different term parsing
+APPLICATION
+  mg-1
+TYPE
+  bug
+REPORT
+  tes@kbs.citri.edu.au - 23 Aug 1994
+FIX
+  tes@kbs.citri.edu.au - 23 Aug 1994
+CLAIM
+  Boolean queries did not extract words/terms using the
+  same method as is done at inverted-file creation and
+  as is used for rank query parsing.
+PROBLEM
+  The hand-written lex. analyser, query_lex, which is called by
+  the boolean query parser was not calling a common
+  word-extraction routine as used by the rest of mg. 
+  This would be ok if the code did the same things - but they didn't.
+  Query_lex, for instance, did NOT place any limit on the
+  number of digits in a term.
+  Of even more concern, it would allow arbitrary sized words
+  although it used Pascal style strings which store the length
+  in the first byte and can therefore only be 255 characters in length.
+SOLUTION
+  Query_lex in "query.bool.y", was modified to call the routine
+  PARSE_STEM_WORD which is also used by text-inversion routines and
+  ranking query routines.
+  Now all terms are extracted by the same routine.
+  To do this, the end of the line buffer had to be noted as
+  PARSE_STEM_WORD requires a pointer to the end - which is the
+  safe thing to do (don't want to run over the end).
+  This meant I had to find the length of the query line buffer.
+  This was allocated in the file "read_line.c" by the routine,
+  "readline". Its size was the literal number 1024. 
+  This was changed to a constant and placed in "read_line.h".
+  The definition for PARSE_STEM_WORD can be found in "words.h".
+FILES
+ *   query.bool.y
+ *   query.bool.c (by bison)
+ *   read_line.c
+ *   read_line.h
+*************************************************************
+TITLE
+  Highlighting of query terms
+APPLICATION
+  mg-1
+TYPE
+  extend
+REPORT
+  tes@kbs.citri.edu.au - Aug 94
+FIX
+  tes@kbs.citri.edu.au - Sep 94
+CLAIM
+  Difficult to feel happy that the query-result returned is
+  satisfying the query - need to look hard to find the queried words.
+  Need to show words in results using some highlighting method.
+PROBLEM
+  No highlighting of query terms in results.
+SOLUTION
+  Mgquery was previously outputting the decompressed text to a pager
+  such as "less(1)" or "more(1)".
+  (Except when redirected or piped elsewhere :)
+  So what was needed was some sort of highlight pager that instead of
+  displaying the text would also use some means for highlighting the
+  stemmed query words. 
+  Two common forms of highlighting were chosen: underline and bolding.
+  These are supported by "less(1)" and possibly by "more(1)" by
+  using the backspace character.
+  A highlight pager will also need to know which words need to be
+  highlighted. Therefore, the code was modified to build up a
+  string of the stemmed query words for passing to the highlight pager.
+  Design Options:
+  ---------------
+    * Could do text filtering in mgquery before passing out to pager.
+      Instead I pipe to a separate process, the "hilite_words" pager,
+      which filters and pipes into less/more.
+    * Could do different highlighting or a combination.
+    * Could use a different structure for storing the query words other
+      than the hash-table I used.
+FILES
+ *   Makefile - to include hilite_words target
+ *   mg_hilite_words.c
+ *   mgquery.c
+ *   mgquery.1
+ *   query.bool.y
+ *   query.ranked.c
+ *   environment.c
+ *   environment.h
+ *   backend.h
+*************************************************************
+TITLE
+  Mg_compression_dict did premature free
+APPLICATION
+  mg-1
+TYPE
+  bug 
+REPORT
+  R.Sosic@cit.gu.edu.au - 23 Sep 94
+FIX
+  R.Sosic@cit.gu.edu.au - 23 Sep 94
+CLAIM
+  mg_compression_dict dumped core in 
+	file: mg_compression_dict.c
+	function: Write_data
+	line: int codelen = hd->clens[i];
+PROBLEM
+  Huffman data, hd, was freed *before* it was accessed again. 
+SOLUTION
+  The freeing of hd has been moved to after all accesses
+  (just before returning).
+FILES
+ *   mg_compression_dict.c
+*************************************************************
+TITLE
+  Boolean tree optimising rewrite
+APPLICATION
+  mg-1
+TYPE
+  bug
+REPORT
+  sosic@kurango.cit.gu.edu.au - 23 Sep 94
+FIX
+  tes@kbs.citri.edu.au - Oct 94
+CLAIM
+  "I am still getting core dump in "and" queries in mgquery, 
+   where the first word does not exist, but the second one does."
+PROBLEM
+  Having freed a particular node, it tried to refree it and 
+  access one of its fields.
+
+  I.e. code-fragment...
+
+       FreeNode(curr); /* where curr = CHILD(base) for 1st term in list */
+       FreeNodes(next);
+       FreeNodes(CHILD(base)); 
+              /* but CHILD(base) has already been freed above */
+              /* if the node was the first one in the list */
+
+SOLUTION
+  A number of things in the code seemed a bit dubious to me.
+  So I have rewritten the boolean optimising stage and abstracted out
+  the various stages - each file starts with "bool".
+  Boolean query optimising seems to be a tricky problem. 
+  It is not clear that putting an expression into a certain form will
+  actually simplify it and whether simplification means faster querying.
+  I have converted a given boolean expression into DNF 
+  (Disjunctive Normal Form).  "And not" nodes, which are readily apparent 
+  in DNF, are converted to "diff" nodes.  I have only applied the idempotency 
+  laws involving TRUE and FALSE, and not the ones requiring matching of 
+  expressions - it is a potentially more complicated problem.
+  The optimiser has been tested by playing with "bool_tester", and if you are
+  having a crash or problem in a boolean query it would be worth testing the
+  query on the "bool_tester." The token "*" stands for TRUE (or all documents) 
+  and the token "_" stands for FALSE (or no documents). This should show the 
+  expression before and after optimisation in an ascii tree bracketting format.
+FILES
+ *   bool_tree.c
+ *   bool_parser.y
+ *   bool_optimiser.c
+ *   bool_query.c 
+ *   bool_tester.c
+ *   term_lists.c
+*************************************************************
+TITLE
+  Mgtic pixel placement
+APPLICATION
+  mg-1
+TYPE
+  bug
+REPORT
+  Bruce McKenzie - bruce@cosc.canterbury.ac.nz (21st Oct 1994)
+FIX
+  singlis@cs.waikato.ac.nz
+CLAIM
+  mgtic crashed on certain files.
+PROBLEM
+  Placing pixels outside of bitmap.
+SOLUTION
+  Changed the putpixel routine to truncate at borders of the image.
+FILES
+ *   mgtic.c
+*************************************************************
+TITLE
+  Improved boolean tree optimising
+APPLICATION
+  mg-1
+TYPE
+  improve
+REPORT
+  tes@kbs.citri.edu.au - 12/Dec/94
+FIX
+  tes@kbs.citri.edu.au - 21/Dec/94, 14/Mar/95
+CLAIM
+  Optimising by conversion to DNF is not necessarily such
+  a good idea - can actually slow things down.
+PROBLEM
+  The distributive law used in converting to DNF
+  duplicates expressions.
+SOLUTION
+  Introduce a query environment variable, optimise_type = 0 | 1 | 2.
+  Type 0 does nothing to the parse tree. 
+  Type 2 does the DNF conversion.
+  Type 1 is the new default and does the following...
+    Do simple tree rearrangement like flattening. 
+    Optimise for CNF queries.
+FILES
+ *   bool_query.c, .h
+ *   bool_optimiser.c
+ *   environment.c
+ *   invf_get.c
+ *   bool_tree.c, .h
+ *   bool_tester.c
+ *   lists.h
+*************************************************************
+TITLE
+  Mgstat with non-existent files
+APPLICATION
+  mg-1
+TYPE
+  bug
+REPORT
+  beebe@math.utah.edu - 16 May 1994
+FIX
+  tes@kbs.citri.edu.au - 10 Aug 1994
+CLAIM
+  NaNs and Infinites would be printed out by mgstat
+  if unable to open .text or .text.dict file.
+PROBLEM
+  The NaNs etc. were output in the column stating
+  the percentage size of the file compared with the
+  number of input bytes of the source text data.
+  If it couldn't read the .text file with its
+  header describing the number of source text bytes, then
+  in working out the percentage it would divide by zero.
+  Also due to some bad control flow, it wouldn't attempt to
+  open the .text file if it failed when opening 
+  the .text.dict file.
+SOLUTION
+  Only printout the percentage if we can read the header
+  from the .text file.
+  Read in text header irrespective of text dictionary file.
+FILES
+ *   mgstat.c
+*************************************************************
+TITLE
+  nonexistent HOME bug  
+APPLICATION
+  mg-1, mg-2
+TYPE
+  bug 
+REPORT
+  cgn@totara.cs.waikato.ac.nz - 2/May/95
+FIX
+  tes@kbs.citri.edu.au - 2/May/95
+CLAIM
+"The big problem was that mgquery crashes when the HOME environment
+ variable is not set, which is the case when it is run by the www server."
+ [...] "I expect it happens when looking for $HOME/.mgrc."
+PROBLEM
+  The result of getenv("HOME")" was used directly in
+  a sprintf call. If the environment variable HOME
+  was not in existence then null would be used.
+  In some C libraries sprintf will convert the 0
+  string into the string "(null)" on others it will core dump.
+  (For example, Solaris seems to core dump, sunos 4 seems ok).
+SOLUTION
+  The result from getenv("HOME")" is tested before
+  being used.
+FILES
+ *   commands.c
+*************************************************************
+TITLE
+  mgquery collection name preference  
+APPLICATION
+  mg-1, mg-2
+TYPE
+  improve
+REPORT
+  cgn@totara.cs.waikato.ac.nz - 2/May/95
+FIX
+  tes@kbs.citri.edu.au - 4/May/95
+CLAIM
+ Surely something must override mquery's preference for ./bib. 
+ If MGDATA is set correctly, I think it should prefer that collection, 
+ and -d should definitely override it. 
+ I could always say -d . if I really wanted ./bib.
+PROBLEM
+Currently the priority is:
+1.  Check if ./name is a directory,
+     If so then use it as the collection directory.
+2.  Check if ./name.text is a file,
+     If so then use ./ as the collection directory.
+3.  Check if mgdir/name is a directory,
+     If so then use mgdir/name as the collection directory.
+4.  Otherwise,
+     Use mgdir/name as the database file prefix.
+     This would be the case if one used "-f alice/alice".
+     However, one would then not specify a final name argument
+     and we'd never get here. Go figure ???
+SOLUTION
+Moved step 3 to the top instead.
+FILES
+ *   mgquery.c [search_for_collection()]
+*************************************************************
+TITLE
+  Printout of query terms
+APPLICATION
+  mg-1, mg-2
+TYPE
+  extend
+REPORT
+  tes@kbs.citri.edu.au - April 95
+FIX
+  tes@kbs.citri.edu.au - April 95
+CLAIM
+  No easy way to find out the parsed and stemmed words
+  used in the query. Would like to know these words
+  so I can call a separate highlighting program to 
+  highlight these words.
+PROBLEM
+  No facility available.
+SOLUTION
+  A ".queryterms" mgquery command was added which lists
+  out the parsed/stemmed queryterms of the last query.
+FILES
+ *    commands.c (added CmdQueryTerms)
+*************************************************************
+TITLE
+  mg_getrc  
+APPLICATION
+  mg-1, mg-2
+TYPE
+  extend
+REPORT
+  bruce@cosc.canterbury.ac.nz - 2/May/95
+FIX
+   - 
+CLAIM
+  Repeated code had to be written for different named
+  gets but really the same type of parsing required.
+  E.g. one might want to use a standard method for inserting
+  ^Bs between paragraphs for different books. One doesn't
+  want to write duplicate code for each different named book,
+  rather note that each book should be filtered "book" style.
+PROBLEM
+  There was no way of abstracting out types of filters from
+  the name of an instance of a collection.
+SOLUTION
+  Allow information to be given with <name, type, files>.
+  This extra info can be provided in a mg_getrc file.
+  See man page for mg_get for details.
+FILES
+ *    mg_get.sh
+*************************************************************
+TITLE
+  Boolean optimiser #1 with `!'  
+APPLICATION
+  mg-1, mg-2
+TYPE
+  bug 
+REPORT
+  triffid@iconz.co.nz - 20/7/95
+FIX
+  tes@kbs.citri.edu.au - 27/7/95
+CLAIM
+  Complained about not-nodes. 
+  e.g. complained about "croquet & !hedgehog"
+PROBLEM
+  Boolean optimiser type#1 didn't convert
+  "and not"s into diff nodes.
+SOLUTION
+  Added code to convert '&!' to '-'.
+FILES
+ *   mg/bool_optimiser.c [mg-1]
+ *   query/bool_optimiser.c [mg-2]
+*************************************************************
+TITLE
+  Consistent use of stderr
+APPLICATION
+  mg-1
+TYPE
+  improve
+REPORT
+  beebe@math.utah.edu - 16 May 1994
+FIX
+  tes@kbs.citri.edu.au - 11 August 1994
+CLAIM
+  Inconsistent use of stdout/stderr in usage messages.
+PROBLEM
+  Sometimes used "printf" and sometimes used "fprintf(stderr"
+  in usage messages.
+SOLUTION
+  All should now use "fprintf(stderr" in usage messages.
+FILES
+ *   mg_compression_dict.c
+ *   mg_compression_dict.1
+ *   mg_fast_comp_dict.c
+ *   mg_fast_comp_dict.1
+ *   mg_invf_dict.c
+ *   mg_invf_dict.1
+ *   mg_invf_dump.c
+ *   mg_invf_dump.1
+ *   mg_invf_rebuild.c
+ *   mg_invf_rebuild.1
+ *   mg_perf_hash_build.c
+ *   mg_perf_hash_build.1
+ *   mg_text_estimate.c
+ *   mg_text_estimate.1
+ *   mg_weights_build.c
+ *   mg_weights_build.1
+*************************************************************
+TITLE
+  xmg bug
+APPLICATION
+  mg-1
+TYPE
+  bug
+REPORT
+  cgn@cpsc.ucalgary.ca - 22 April 1994
+FIX
+  cgn@cpsc.ucalgary.ca - 22 April 1994
+CLAIM
+  "Serious problem in xmg, which I fear occurs whenever a query
+   doesn't return anything."
+PROBLEM
+  ??
+SOLUTION
+  [xmg.sh 201] set rank 0
+FILES
+ *   xmg.sh
+*************************************************************
+TITLE
+  Unnecessary loading of text
+APPLICATION
+  mg-1
+TYPE
+  bug
+REPORT
+  tes@kbs.citri.edu.au - ?? August 1994
+FIX
+  tes@kbs.citri.edu.au - 12 August 1994
+CLAIM
+  Mg was loading and uncompressing text when the
+  query did not require the text.
+PROBLEM
+  There was no test for the query mode
+  before loading and uncompressing the text.
+SOLUTION
+  Only load/uncompress text if query mode
+  is for text, headers or silent(for timing).
+FILES
+ *   mgquery.c
+*************************************************************
+TITLE
+  Man page errors
+APPLICATION
+  mg-1
+TYPE
+  bug
+REPORT
+  beebe@math.utah.edu - 16 May 1994
+FIX
+  beebe@math.utah.edu - 16 May 1994
+CLAIM
+  Man page errors.
+PROBLEM
+  See below.
+SOLUTION
+ "The mg_make_fast_dict.1 file has been renamed mg_fast_comp_dict.1,
+  and all mg_make_fast_dict strings changed to mg_fast_comp_dict in all
+  man pages.
+  A large number of errors of spelling, typography, spacing, fonts,
+  grammar, omitted words, slang, punctuation, missing man page
+  cross-references, and man-page style have been corrected."
+FILES
+ *    mg_compression_dict.1
+ *    mg_fast_comp_dict.1
+ *    mg_get.1
+ *    mg_invf_dict.1
+ *    mg_invf_dump.1
+ *    mg_invf_rebuild.1
+ *    mg_passes.1
+ *    mg_perf_hash_build.1
+ *    mg_text_estimate.1
+ *    mg_weights_build.1
+ *    mgbilevel.1
+ *    mgbuild.1
+ *    mgdictlist.1
+ *    mgfelics.1
+ *    mgquery.1
+ *    mgstat.1
+ *    mgtic.1
+ *    mgticbuild.1
+ *    mgticdump.1
+ *    mgticprune.1
+ *    mgticstat.1
+ *    xmg.1
+*************************************************************
+TITLE
+  Man page overview
+APPLICATION
+  mg-1
+TYPE
+  extend
+REPORT
+  beebe@math.utah.edu - 
+FIX
+  tes@kbs.citri.edu.au - 17 August 1994
+CLAIM
+  "Write new mg.1 file to give a brief overview of mg, with samples
+   of how to use it.  Otherwise, users are likely to be completely
+   overwhelmed by the number of programs (about 20) which might need to
+   be used, when in reality, only 2 or 3 are likely to be run by end
+   users."
+SOLUTION
+  It was thought that mg.1, written by Nelson Beebe, was very useful
+  but a bit too comprehensive for an introduction.
+  Therefore, two man files, mgintro.1 and mgintro++.1 were written
+  with the basic stuff in mgintro.1 and slightly more advanced stuff
+  in mgintro++.1 . 
+FILES
+ *   mg.1
+ *   mgintro.1
+ *   mgintro++.1 
+*************************************************************
+TITLE
+  Parse errors not bus errors
+APPLICATION
+  mg-1
+TYPE
+  bug
+REPORT
+  tim@cosc.canterbury.ac.nz - 2 Jun 94
+FIX
+  tes@kbs.citri.edu.au - 19 Aug 94
+CLAIM
+  "These two queries 
+   (which I typed in before I knew what I was doing!!)
+      > The Queen of Hearts, she made some tarts
+      > "The Queen of Hearts" and "she made some tarts"
+      produced the following result:
+      mgquery : parse error
+      Bus error
+  "
+PROBLEM
+  What is expected to happen under boolean querying:
+    Query1:
+    > The Queen of Hearts, she made some tarts
+    will produce a parse error due to the comma which
+    is not a valid TERM.
+    Query2:
+    > "The Queen of Hearts" and "she made some tarts"
+    will store a post-processing string
+    of ''The Queen of Hearts" and "she made some tarts'' and
+    will have a main boolean query of the empty string.
+    This is because the postprocessing string takes in
+    everything between the first quote and the last one.
+    An empty string is illegal for the boolean grammar and
+    hence a parse error.
+  The problem stems from the fact that the processing of
+  the parse tree is carried out, even though we have a 
+  parse error. In the case of using an empty string to build
+  a parse tree, it is likely to leave the parse tree undefined.
+SOLUTION
+  As soon as we find out that there is a parse-error,
+  we abandon any processing of the parse tree.
+FILES
+ *   query.bool.y
+ *   query.bool.c (generated from query.bool.y)
+*************************************************************
+TITLE
+  Perfect hashing on small vocab
+APPLICATION
+  mg-1
+TYPE
+  bug
+REPORT
+  tes@kbs.citri.edu.au - July 1994
+FIX
+  alistair@cs.mu.oz.au - July 1994
+CLAIM
+  Mg could not handle small collections in the case
+  where there was only a small number of unique words.
+  The perfect hash function would report an error.
+PROBLEM
+  Rounding of the arithmetic during the calculation of the
+  parameters of the perfect hash function was resulting in a
+  combination of values such that the probability of a hash
+  function being found was very small. This led to the limit
+  on the generation loop being exceeded, and eventual
+  failure.
+SOLUTION
+  By using ceiling rather than floor when converting from a
+  floating point value to an integer parameter, the arithmetic
+  is now correct for all lexicon sizes, and the probability of
+  each iteration successfully generating a hash function is
+  sufficiently great that with _very_ high probability the
+  execution loop counter will not be exceeded unless there
+  genuinely is no hash function (for example, if the lexicon
+  contains two words the same there cannot be  a hash
+  function).
+FILES
+ *   perf_hash.c
+*************************************************************
Index: /main/tags/2.25/gsdl/packages/mg/SampleData/Makefile
===================================================================
--- /main/tags/2.25/gsdl/packages/mg/SampleData/Makefile	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/mg/SampleData/Makefile	(revision 21064)
@@ -0,0 +1,4 @@
+DISTFILES = Makefile alice13a.txt.Z MODIFICATIONS 
+
+dist:
+	ln $(DISTFILES) $(distdir)
Index: /main/tags/2.25/gsdl/packages/mg/about_mg.html
===================================================================
--- /main/tags/2.25/gsdl/packages/mg/about_mg.html	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/mg/about_mg.html	(revision 21064)
@@ -0,0 +1,75 @@
+<HTML>
+<HEAD>
+<TITLE>About MG</TITLE>
+</HEAD>
+<BODY>
+<H1>About MG</H1>
+ 
+<HR SIZE=4>
+
+MG is a public domain
+indexing and retrieval system for text, images, and textual images.
+MG is covered by a 
+<a href="http://deimos.kbs.citri.edu.au/mg/intro/copying.html">GNU 
+public licence</a>.
+<P>
+MG is available for ftp <a href="ftp://munnari.oz.au/pub/mg">here</a>
+
+<H2>Developers</H2>
+
+The MG system is an embodiment of ideas developed primarily by:
+<ul>
+<li> <a href="http://www.cosc.canterbury.ac.nz/~tim">Tim C. Bell</a>,
+	University of Canterbury;
+<li> <a href="http://www.cs.mu.oz.au/~alistair">Alistair Moffat</a>,
+	University of Melbourne;
+<li> <a href="http://www.cs.waikato.ac.nz/~ihw">Ian Witten</a>,
+	University of Waikato; and
+<li> <a href="http://www.cs.rmit.edu.au/~jz">Justin Zobel</a>,
+	RMIT.
+</ul>
+
+<H2>Programmers</H2>
+
+The bulk of the programming work has been undertaken by:
+<ul>
+<li><A HREF="http://www.cs.waikato.ac.nz/~singlis/">Stuart Inglis</A>,
+       University of Waikato;
+<li><A HREF="http://www.cs.waikato.ac.nz/~cgn/">Craig Nevill-Manning</A>,
+       University of Waikato;
+<li> Neil Sharman, University of Melbourne; and
+<li> Tim Shimmin, Collaborative Information Technology Research Institute (CITRI).
+</ul>
+A full list of contributors appears
+<A HREF="http://deimos.kbs.citri.edu.au/mg/intro/mgintro.html#xtocid2063010">
+here</a>.
+
+<H2>Institutional Support</H2>
+
+The MG project has been supported by the following organisations:
+<ul>
+<li>	The Australian Research Council;
+<li>	<a HREF="http://www.citri.edu.au/">CITRI</a>, Melbourne;
+<li>	The <a HREF="http://www.cpsc.ucalgary.ca/">University
+		of Calgary</a>, Canada;
+<li>	The <a HREF="http://www.cosc.canterbury.ac.nz/">University
+		of Canterbury</a>, New Zealand;
+<li>	The <a HREF="http://www.cs.mu.oz.au/">University
+		of Melbourne</a>, Australia;
+<li>	<a HREF="http://www.cs.rmit.edu.au/">RMIT</a>, Australia; and
+<li>	The <a HREF="http://www.cs.waikato.ac.nz/">University
+		of Waikato</a>, New Zealand.
+</ul>
+
+<H2>Backpointer</H2>
+
+If you didn't just come from there, the MG home page is accessible
+<a href="http://www.kbs.citri.edu.au/mg/">here</a>.
+
+<HR SIZE=4>
+<ADDRESS>alistair@cs.mu.oz.au</ADDRESS><BR>
+ 
+</BODY>
+</HTML>
+
+
Index: /main/tags/2.25/gsdl/packages/mg/acconfig.h
===================================================================
--- /main/tags/2.25/gsdl/packages/mg/acconfig.h	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/mg/acconfig.h	(revision 21064)
@@ -0,0 +1,35 @@
+/* Special definitions for mg, processed by autoheader.
+   Created by [TS:Aug/95] 
+   by grepping for AC_DEFINE on configure.in and using the appropriate defs 
+   of acconfig.h used by GNU tar.
+*/
+
+/* Define to the name of the distribution.  */
+#undef PACKAGE
+
+/* Define to the version of the distribution.  */
+#undef VERSION
+
+/* Define if `union wait' is the type of the first arg to wait functions.  */
+#undef HAVE_UNION_WAIT
+
+/* Define to 1 if you have the valloc function.  */
+#undef HAVE_VALLOC
+
+/* Define to 1 if ANSI function prototypes are usable.  */
+#undef PROTOTYPES
+ 
+/* Define to 1 for better use of the debugging malloc library.  See
+   site ftp.antaire.com in antaire/src, file dmalloc/dmalloc.tar.gz.  */
+#undef WITH_DMALLOC
+ 
+/* Define to 1 if GNU regex should be used instead of GNU rx.  */
+#undef WITH_REGEX
+
+/* Some braindead header files do not have the requ'd function declarations */
+#undef HAVE_FGETC_DECL
+#undef HAVE_FREAD_DECL
+
+/* See if have this field in the prstatus_t structure */
+/* It stores the size of the process heap */
+#undef HAVE_PR_BRKSIZE
Index: /main/tags/2.25/gsdl/packages/mg/aclocal.m4
===================================================================
--- /main/tags/2.25/gsdl/packages/mg/aclocal.m4	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/mg/aclocal.m4	(revision 21064)
@@ -0,0 +1,141 @@
+# Local additions to Autoconf macros.
+# Copyright (C) 1992, 1994, 1995 Free Software Foundation, Inc.
+# François Pinard <pinard@iro.umontreal.ca>, 1992.
+
+# [TS:Aug/95] - chopped out the NLS stuff which I don't support
+
+## ------------------------------- ##
+## Check for function prototypes.  ##
+## ------------------------------- ##
+
+AC_DEFUN(fp_C_PROTOTYPES,
+[AC_REQUIRE([fp_PROG_CC_STDC])
+AC_MSG_CHECKING([for function prototypes])
+if test "$ac_cv_prog_cc_stdc" != no; then
+  AC_MSG_RESULT(yes)
+  AC_DEFINE(PROTOTYPES)
+  U= ANSI2KNR=
+else
+  AC_MSG_RESULT(no)
+  U=_ ANSI2KNR=ansi2knr
+fi
+AC_SUBST(U)dnl
+AC_SUBST(ANSI2KNR)dnl
+])
+
+## ----------------------------------------- ##
+## ANSIfy the C compiler whenever possible.  ##
+## ----------------------------------------- ##
+
+# @defmac AC_PROG_CC_STDC
+# @maindex PROG_CC_STDC
+# @ovindex CC
+# If the C compiler in not in ANSI C mode by default, try to add an option
+# to output variable @code{CC} to make it so.  This macro tries various
+# options that select ANSI C on some system or another.  It considers the
+# compiler to be in ANSI C mode if it defines @code{__STDC__} to 1 and
+# handles function prototypes correctly.
+#
+# If you use this macro, you should check after calling it whether the C
+# compiler has been set to accept ANSI C; if not, the shell variable
+# @code{ac_cv_prog_cc_stdc} is set to @samp{no}.  If you wrote your source
+# code in ANSI C, you can make an un-ANSIfied copy of it by using the
+# program @code{ansi2knr}, which comes with Ghostscript.
+# @end defmac
+
+AC_DEFUN(fp_PROG_CC_STDC,
+[AC_MSG_CHECKING(for ${CC-cc} option to accept ANSI C)
+AC_CACHE_VAL(ac_cv_prog_cc_stdc,
+[ac_cv_prog_cc_stdc=no
+ac_save_CFLAGS="$CFLAGS"
+# Don't try gcc -ansi; that turns off useful extensions and
+# breaks some systems' header files.
+# AIX			-qlanglvl=ansi
+# Ultrix and OSF/1	-std1
+# HP-UX			-Aa -D_HPUX_SOURCE
+# SVR4			-Xc
+for ac_arg in "" -qlanglvl=ansi -std1 "-Aa -D_HPUX_SOURCE" -Xc
+do
+  CFLAGS="$ac_save_CFLAGS $ac_arg"
+  AC_TRY_COMPILE(
+[#if !defined(__STDC__) || __STDC__ != 1
+choke me
+#endif	
+], [int test (int i, double x);
+struct s1 {int (*f) (int a);};
+struct s2 {int (*f) (double a);};],
+[ac_cv_prog_cc_stdc="$ac_arg"; break])
+done
+CFLAGS="$ac_save_CFLAGS"
+])
+AC_MSG_RESULT($ac_cv_prog_cc_stdc)
+case "x$ac_cv_prog_cc_stdc" in
+  x|xno) ;;
+  *) CC="$CC $ac_cv_prog_cc_stdc" ;;
+esac
+])
+
+## --------------------------------------------------------- ##
+## Use AC_PROG_INSTALL, supplementing it with INSTALL_SCRIPT ##
+## substitution.					     ##
+## --------------------------------------------------------- ##
+
+AC_DEFUN(fp_PROG_INSTALL,
+[AC_PROG_INSTALL
+test -z "$INSTALL_SCRIPT" && INSTALL_SCRIPT='${INSTALL} -m 755'
+AC_SUBST(INSTALL_SCRIPT)dnl
+])
+
+## ----------------------------------- ##
+## Check if --with-dmalloc was given.  ##
+## ----------------------------------- ##
+
+# I just checked, and GNU rx seems to work fine with a slightly
+# modified GNU m4.  So, I put out the test below in my aclocal.m4,
+# and will try to use it in my things.  The idea is to distribute
+# rx.[hc] and regex.[hc] together, for a while.  The WITH_REGEX symbol
+# (which should also be documented in acconfig.h) is used to decide
+# which of regex.h or rx.h should be included in the application.
+#
+# If `./configure --with-regex' is given, the package will use
+# the older regex.  Else, a check is made to see if rx is already
+# installed, as with newer Linux'es.  If not found, the package will
+# use the rx from the distribution.  If found, the package will use
+# the system's rx which, on Linux at least, will result in a smaller
+# executable file.
+
+AC_DEFUN(fp_WITH_DMALLOC,
+[AC_MSG_CHECKING(if malloc debugging is wanted)
+AC_ARG_WITH(dmalloc,
+[  --with-dmalloc          use dmalloc, as in
+                          ftp://ftp.letters.com/src/dmalloc/dmalloc.tar.gz],
+[if test "$withval" = yes; then
+  AC_MSG_RESULT(yes)
+  AC_DEFINE(WITH_DMALLOC)
+  LIBS="$LIBS -ldmalloc"
+  LDFLAGS="$LDFLAGS -g"
+else
+  AC_MSG_RESULT(no)
+fi], [AC_MSG_RESULT(no)])
+])
+
+## --------------------------------- ##
+## Check if --with-regex was given.  ##
+## --------------------------------- ##
+
+AC_DEFUN(fp_WITH_REGEX,
+[AC_MSG_CHECKING(which of rx or regex is wanted)
+AC_ARG_WITH(regex,
+[  --with-regex            use older regex in lieu of GNU rx for matching],
+[if test "$withval" = yes; then
+  ac_with_regex=1
+  AC_MSG_RESULT(regex)
+  AC_DEFINE(WITH_REGEX)
+  LIBOBJS="$LIBOBJS regex.o"
+fi])
+if test -z "$ac_with_regex"; then
+  AC_MSG_RESULT(rx)
+  AC_CHECK_FUNC(re_rx_search, , [LIBOBJS="$LIBOBJS rx.o"])
+fi
+AC_SUBST(LIBOBJS)dnl
+])
Index: /main/tags/2.25/gsdl/packages/mg/build_options.in
===================================================================
--- /main/tags/2.25/gsdl/packages/mg/build_options.in	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/mg/build_options.in	(revision 21064)
@@ -0,0 +1,2 @@
+set stem_method = 3
+set do_indexes = 1
Index: /main/tags/2.25/gsdl/packages/mg/config.guess
===================================================================
--- /main/tags/2.25/gsdl/packages/mg/config.guess	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/mg/config.guess	(revision 21064)
@@ -0,0 +1,470 @@
+#!/bin/sh
+# Attempt to guess a canonical system name.
+#   Copyright (C) 1992, 1993, 1994 Free Software Foundation, Inc.
+#
+# This file 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.
+#
+# As a special exception to the GNU General Public License, if you
+# distribute this file as part of a program that contains a
+# configuration script generated by Autoconf, you may include it under
+# the same distribution terms that you use for the rest of that program.
+
+# Written by Per Bothner <bothner@cygnus.com>.
+# The master version of this file is at the FSF in /home/gd/gnu/lib.
+#
+# This script attempts to guess a canonical system name similar to
+# config.sub.  If it succeeds, it prints the system name on stdout, and
+# exits with 0.  Otherwise, it exits with 1.
+#
+# The plan is that this can be called by configure scripts if you
+# don't specify an explicit system type (host/target name).
+#
+# Only a few systems have been added to this list; please add others
+# (but try to keep the structure clean).
+#
+
+# This is needed to find uname on a Pyramid OSx when run in the BSD universe.
+# (ghazi@noc.rutgers.edu 8/24/94.)
+if (test -f /.attbin/uname) >/dev/null 2>&1 ; then
+	PATH=$PATH:/.attbin ; export PATH
+fi
+
+UNAME_MACHINE=`(uname -m) 2>/dev/null` || UNAME_MACHINE=unknown
+UNAME_RELEASE=`(uname -r) 2>/dev/null` || UNAME_RELEASE=unknown
+UNAME_SYSTEM=`(uname -s) 2>/dev/null` || UNAME_SYSTEM=unknown
+UNAME_VERSION=`(uname -v) 2>/dev/null` || UNAME_VERSION=unknown
+
+trap 'rm -f dummy.c dummy.o dummy; exit 1' 1 2 15
+
+# Note: order is significant - the case branches are not exclusive.
+
+case "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" in
+    alpha:OSF1:V*:*)
+	# After 1.2, OSF1 uses "V1.3" for uname -r.
+	echo alpha-dec-osf`echo ${UNAME_RELEASE} | sed -e 's/^V//'`
+	exit 0 ;;
+    alpha:OSF1:*:*)
+	# 1.2 uses "1.2" for uname -r.
+	echo alpha-dec-osf${UNAME_RELEASE}
+        exit 0 ;;
+    arm:RISC*:1.[012]*:*|arm:riscix:1.[012]*:*)
+	echo arm-acorn-riscix${UNAME_RELEASE}
+	exit 0;;
+    Pyramid*:OSx*:*:*)
+	if test "`(/bin/universe) 2>/dev/null`" = att ; then
+		echo pyramid-pyramid-sysv3
+	else
+		echo pyramid-pyramid-bsd
+	fi
+	exit 0 ;;
+    sun4*:SunOS:5.*:*)
+	echo sparc-sun-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'`
+	exit 0 ;;
+    sun4*:SunOS:6*:*)
+	# According to config.sub, this is the proper way to canonicalize
+	# SunOS6.  Hard to guess exactly what SunOS6 will be like, but
+	# it's likely to be more like Solaris than SunOS4.
+	echo sparc-sun-solaris3`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'`
+	exit 0 ;;
+    sun4*:SunOS:*:*)
+	# Japanese Language versions have a version number like `4.1.3-JL'.
+	echo sparc-sun-sunos`echo ${UNAME_RELEASE}|sed -e 's/-/_/'`
+	exit 0 ;;
+    sun3*:SunOS:*:*)
+	echo m68k-sun-sunos${UNAME_RELEASE}
+	exit 0 ;;
+    RISC*:ULTRIX:*:*)
+	echo mips-dec-ultrix${UNAME_RELEASE}
+	exit 0 ;;
+    VAX*:ULTRIX*:*:*)
+	echo vax-dec-ultrix${UNAME_RELEASE}
+	exit 0 ;;
+    mips:*:5*:RISCos)
+	echo mips-mips-riscos${UNAME_RELEASE}
+	exit 0 ;;
+    m88k:CX/UX:7*:*)
+	echo m88k-harris-cxux7
+	exit 0 ;;
+    m88k:*:4*:R4*)
+	echo m88k-motorola-sysv4
+	exit 0 ;;
+    m88k:*:3*:R3*)
+	echo m88k-motorola-sysv3
+	exit 0 ;;
+    AViiON:dgux:*:*)
+	if [ ${TARGET_BINARY_INTERFACE}x = m88kdguxelfx \
+	     -o ${TARGET_BINARY_INTERFACE}x = x ] ; then
+		echo m88k-dg-dgux${UNAME_RELEASE}
+	else
+		echo m88k-dg-dguxbcs${UNAME_RELEASE}
+	fi
+ 	exit 0 ;;
+    M88*:DolphinOS:*:*)	# DolphinOS (SVR3)
+	echo m88k-dolphin-sysv3
+	exit 0 ;;
+    M88*:*:R3*:*)
+	# Delta 88k system running SVR3
+	echo m88k-motorola-sysv3
+	exit 0 ;;
+    XD88*:*:*:*) # Tektronix XD88 system running UTekV (SVR3)
+	echo m88k-tektronix-sysv3
+	exit 0 ;;
+    Tek43[0-9][0-9]:UTek:*:*) # Tektronix 4300 system running UTek (BSD)
+	echo m68k-tektronix-bsd
+	exit 0 ;;
+    *:IRIX:*:*)
+	echo mips-sgi-irix${UNAME_RELEASE}
+	exit 0 ;;
+    i[34]86:AIX:*:*)
+	echo i386-ibm-aix
+	exit 0 ;;
+    *:AIX:2:3)
+	if grep bos325 /usr/include/stdio.h >/dev/null 2>&1; then
+		sed 's/^		//' << EOF >dummy.c
+		#include <sys/systemcfg.h>
+
+		main()
+			{
+			if (!__power_pc())
+				exit(1);
+			puts("powerpc-ibm-aix3.2.5");
+			exit(0);
+			}
+EOF
+		${CC-cc} dummy.c -o dummy && ./dummy && rm dummy.c dummy && exit 0
+		rm -f dummy.c dummy
+		echo rs6000-ibm-aix3.2.5
+	elif grep bos324 /usr/include/stdio.h >/dev/null 2>&1; then
+		echo rs6000-ibm-aix3.2.4
+	else
+		echo rs6000-ibm-aix3.2
+	fi
+	exit 0 ;;
+    *:AIX:*:4)
+	if /usr/sbin/lsattr -EHl proc0 | grep POWER >/dev/null 2>&1; then
+		IBM_ARCH=rs6000
+	else
+		IBM_ARCH=powerpc
+	fi
+	if grep bos410 /usr/include/stdio.h >/dev/null 2>&1; then
+		IBM_REV=4.1
+	elif grep bos411 /usr/include/stdio.h >/dev/null 2>&1; then
+		IBM_REV=4.1.1
+	else
+		IBM_REV=4.${UNAME_RELEASE}
+	fi
+	echo ${IBM_ARCH}-ibm-aix${IBM_REV}
+	exit 0 ;;
+    *:AIX:*:*)
+	echo rs6000-ibm-aix
+	exit 0 ;;
+    *:BOSX:*:*)
+	echo rs6000-bull-bosx
+	exit 0 ;;
+    DPX/2?00:B.O.S.:*:*)
+	echo m68k-bull-sysv3
+	exit 0 ;;
+    9000/[34]??:4.3bsd:1.*:*)
+	echo m68k-hp-bsd
+	exit 0 ;;
+    hp300:4.4BSD:*:* | 9000/[34]??:4.3bsd:2.*:*)
+	echo m68k-hp-bsd4.4
+	exit 0 ;;
+    9000/[3478]??:HP-UX:*:*)
+	case "${UNAME_MACHINE}" in
+	    9000/31? )            HP_ARCH=m68000 ;;
+	    9000/[34]?? )         HP_ARCH=m68k ;;
+	    9000/7?? | 9000/8?7 ) HP_ARCH=hppa1.1 ;;
+	    9000/8?? )            HP_ARCH=hppa1.0 ;;
+	esac
+	HPUX_REV=`echo ${UNAME_RELEASE}|sed -e 's/[^.]*.[0B]*//'`
+	echo ${HP_ARCH}-hp-hpux${HPUX_REV}
+	exit 0 ;;
+    3050*:HI-UX:*:*)
+	sed 's/^	//' << EOF >dummy.c
+	#include <unistd.h>
+	int
+	main ()
+	{
+	  long cpu = sysconf (_SC_CPU_VERSION);
+	  /* The order matters, because CPU_IS_HP_MC68K erroneously returns
+	     true for CPU_PA_RISC1_0.  CPU_IS_PA_RISC returns correct
+	     results, however.  */
+	  if (CPU_IS_PA_RISC (cpu))
+	    {
+	      switch (cpu)
+		{
+		  case CPU_PA_RISC1_0: puts ("hppa1.0-hitachi-hiuxwe2"); break;
+		  case CPU_PA_RISC1_1: puts ("hppa1.1-hitachi-hiuxwe2"); break;
+		  case CPU_PA_RISC2_0: puts ("hppa2.0-hitachi-hiuxwe2"); break;
+		  default: puts ("hppa-hitachi-hiuxwe2"); break;
+		}
+	    }
+	  else if (CPU_IS_HP_MC68K (cpu))
+	    puts ("m68k-hitachi-hiuxwe2");
+	  else puts ("unknown-hitachi-hiuxwe2");
+	  exit (0);
+	}
+EOF
+	${CC-cc} dummy.c -o dummy && ./dummy && rm dummy.c dummy && exit 0
+	rm -f dummy.c dummy
+	echo unknown-hitachi-hiuxwe2
+	exit 0 ;;
+    9000/7??:4.3bsd:*:* | 9000/8?7:4.3bsd:*:* )
+	echo hppa1.1-hp-bsd
+	exit 0 ;;
+    9000/8??:4.3bsd:*:*)
+	echo hppa1.0-hp-bsd
+	exit 0 ;;
+    hp7??:OSF1:*:* | hp8?7:OSF1:*:* )
+	echo hppa1.1-hp-osf
+	exit 0 ;;
+    hp8??:OSF1:*:*)
+	echo hppa1.0-hp-osf
+	exit 0 ;;
+    C1*:ConvexOS:*:* | convex:ConvexOS:C1*:*)
+	echo c1-convex-bsd
+        exit 0 ;;
+    C2*:ConvexOS:*:* | convex:ConvexOS:C2*:*)
+	if getsysinfo -f scalar_acc
+	then echo c32-convex-bsd
+	else echo c2-convex-bsd
+	fi
+        exit 0 ;;
+    C34*:ConvexOS:*:* | convex:ConvexOS:C34*:*)
+	echo c34-convex-bsd
+        exit 0 ;;
+    C38*:ConvexOS:*:* | convex:ConvexOS:C38*:*)
+	echo c38-convex-bsd
+        exit 0 ;;
+    C4*:ConvexOS:*:* | convex:ConvexOS:C4*:*)
+	echo c4-convex-bsd
+        exit 0 ;;
+    CRAY*X-MP:UNICOS:*:*)
+	echo xmp-cray-unicos
+        exit 0 ;;
+    CRAY*Y-MP:UNICOS:*:*)
+	echo ymp-cray-unicos
+        exit 0 ;;
+    CRAY-2:UNICOS:*:*)
+	echo cray2-cray-unicos
+        exit 0 ;;
+    hp3[0-9][05]:NetBSD:*:*)
+	echo m68k-hp-netbsd${UNAME_RELEASE}
+	exit 0 ;;
+    i[34]86:BSD/386:*:*)
+	echo ${UNAME_MACHINE}-unknown-bsdi${UNAME_RELEASE}
+	exit 0 ;;
+    *:FreeBSD:*:*)
+	echo ${UNAME_MACHINE}-unknown-freebsd`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'`
+	exit 0 ;;
+    *:NetBSD:*:*)
+	echo ${UNAME_MACHINE}-unknown-netbsd`echo ${UNAME_RELEASE}|sed -e 's/[-_].*/\./'`
+	exit 0 ;;
+    *:GNU:*:*)
+	echo `echo ${UNAME_MACHINE}|sed -e 's,/.*$,,'`-unknown-gnu`echo ${UNAME_RELEASE}|sed -e 's,/.*$,,'`
+	exit 0 ;;
+    *:Linux:*:*)
+	echo ${UNAME_MACHINE}-unknown-linux
+	exit 0 ;;
+# ptx 4.0 does uname -s correctly, with DYNIX/ptx in there.  earlier versions
+# are messed up and put the nodename in both sysname and nodename.
+    i[34]86:DYNIX/ptx:4*:*)
+	echo i386-sequent-sysv4
+	exit 0 ;;
+    i[34]86:*:4.*:* | i[34]86:SYSTEM_V:4.*:*)
+	if grep Novell /usr/include/link.h >/dev/null 2>/dev/null; then
+		echo ${UNAME_MACHINE}-univel-sysv${UNAME_RELEASE}
+	else
+		echo ${UNAME_MACHINE}-unknown-sysv${UNAME_RELEASE}
+	fi
+	exit 0 ;;
+    i[34]86:*:3.2:*)
+	if /bin/uname -X 2>/dev/null >/dev/null ; then
+		UNAME_REL=`(/bin/uname -X|egrep Release|sed -e 's/.*= //')`
+		(/bin/uname -X|egrep i80486 >/dev/null) && UNAME_MACHINE=i486
+		echo ${UNAME_MACHINE}-unknown-sco$UNAME_REL
+	elif test -f /usr/options/cb.name; then
+		UNAME_REL=`sed -n 's/.*Version //p' </usr/options/cb.name`
+		echo ${UNAME_MACHINE}-unknown-isc$UNAME_REL
+	else
+		echo ${UNAME_MACHINE}-unknown-sysv32
+	fi
+	exit 0 ;;
+    Intel:Mach:3*:*)
+	echo i386-unknown-mach3
+	exit 0 ;;
+    i860:*:4.*:*) # i860-SVR4
+	if grep Stardent /usr/include/sys/uadmin.h >/dev/null 2>&1 ; then
+	  echo i860-stardent-sysv${UNAME_RELEASE} # Stardent Vistra i860-SVR4
+	else # Add other i860-SVR4 vendors below as they are discovered.
+	  echo i860-unknown-sysv${UNAME_RELEASE}  # Unknown i860-SVR4
+	fi
+	exit 0 ;;
+    mini*:CTIX:SYS*5:*)
+	# "miniframe"
+	echo m68010-convergent-sysv
+	exit 0 ;;
+    M680[234]0:*:R3V[567]*:*)
+	test -r /sysV68 && echo 'm68k-motorola-sysv' && exit 0 ;;
+    3[34]??:*:4.0:3.0 | 3[34]??,*:*:4.0:3.0)
+        uname -p 2>/dev/null | grep 86 >/dev/null \
+          && echo i486-ncr-sysv4.3 && exit 0 ;;
+    3[34]??:*:4.0:* | 3[34]??,*:*:4.0:*)
+        uname -p 2>/dev/null | grep 86 >/dev/null \
+          && echo i486-ncr-sysv4 && exit 0 ;;
+    m680[234]0:LynxOS:2.2*:*)
+	echo m68k-lynx-lynxos${UNAME_RELEASE}
+	exit 0 ;;
+    mc68030:UNIX_System_V:4.*:*)
+	echo m68k-atari-sysv4
+	exit 0 ;;
+    i[34]86:LynxOS:2.2*:*)
+	echo i386-lynx-lynxos${UNAME_RELEASE}
+	exit 0 ;;
+    TSUNAMI:LynxOS:2.2*:*)
+	echo sparc-lynx-lynxos${UNAME_RELEASE}
+	exit 0 ;;
+    rs6000:LynxOS:2.2*:*)
+	echo rs6000-lynx-lynxos${UNAME_RELEASE}
+	exit 0 ;;
+    RM*:SINIX-*:*:*)
+	echo mips-sni-sysv4
+	exit 0 ;;
+    *:SINIX-*:*:*)
+	if uname -p 2>/dev/null >/dev/null ; then
+		UNAME_MACHINE=`(uname -p) 2>/dev/null`
+		echo ${UNAME_MACHINE}-sni-sysv4
+	else
+		echo ns32k-sni-sysv
+	fi
+	exit 0 ;;
+esac
+
+#echo '(No uname command or uname output not recognized.)' 1>&2
+#echo "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" 1>&2
+
+cat >dummy.c <<EOF
+main ()
+{
+#if defined (sony)
+#if defined (MIPSEB)
+  /* BFD wants "bsd" instead of "newsos".  Perhaps BFD should be changed,
+     I don't know....  */
+  printf ("mips-sony-bsd\n"); exit (0);
+#else
+  printf ("m68k-sony-newsos\n"); exit (0);
+#endif
+#endif
+
+#if defined (__arm) && defined (__acorn) && defined (__unix)
+  printf ("arm-acorn-riscix"); exit (0);
+#endif
+
+#if defined (hp300) && !defined (hpux)
+  printf ("m68k-hp-bsd\n"); exit (0);
+#endif
+
+#if defined (NeXT)
+#if !defined (__ARCHITECTURE__)
+#define __ARCHITECTURE__ "m68k"
+#endif
+  int version;
+  version=`(hostinfo | sed -n 's/.*NeXT Mach \([0-9]*\).*/\1/p') 2>/dev/null`;
+  printf ("%s-next-nextstep%s\n", __ARCHITECTURE__,  version==2 ? "2" : "3");
+  exit (0);
+#endif
+
+#if defined (MULTIMAX) || defined (n16)
+#if defined (UMAXV)
+  printf ("ns32k-encore-sysv\n"); exit (0);
+#else
+#if defined (CMU)
+  printf ("ns32k-encore-mach\n"); exit (0);
+#else
+  printf ("ns32k-encore-bsd\n"); exit (0);
+#endif
+#endif
+#endif
+
+#if defined (__386BSD__)
+  printf ("i386-unknown-bsd\n"); exit (0);
+#endif
+
+#if defined (sequent)
+#if defined (i386)
+  printf ("i386-sequent-dynix\n"); exit (0);
+#endif
+#if defined (ns32000)
+  printf ("ns32k-sequent-dynix\n"); exit (0);
+#endif
+#endif
+
+#if defined (_SEQUENT_)
+  printf ("i386-sequent-ptx\n"); exit (0);
+#endif
+
+#if defined (vax)
+#if !defined (ultrix)
+  printf ("vax-dec-bsd\n"); exit (0);
+#else
+  printf ("vax-dec-ultrix\n"); exit (0);
+#endif
+#endif
+
+#if defined (alliant) && defined (i860)
+  printf ("i860-alliant-bsd\n"); exit (0);
+#endif
+
+  exit (1);
+}
+EOF
+
+${CC-cc} dummy.c -o dummy 2>/dev/null && ./dummy && rm dummy.c dummy && exit 0
+rm -f dummy.c dummy
+
+# Apollos put the system type in the environment.
+
+test -d /usr/apollo && { echo ${ISP}-apollo-${SYSTYPE}; exit 0; }
+
+# Convex versions that predate uname can use getsysinfo(1)
+
+if [ -x /usr/convex/getsysinfo ]
+then
+    case `getsysinfo -f cpu_type` in
+    c1*)
+	echo c1-convex-bsd
+	exit 0 ;;
+    c2*)
+	if getsysinfo -f scalar_acc
+	then echo c32-convex-bsd
+	else echo c2-convex-bsd
+	fi
+	exit 0 ;;
+    c34*)
+	echo c34-convex-bsd
+	exit 0 ;;
+    c38*)
+	echo c38-convex-bsd
+	exit 0 ;;
+    c4*)
+	echo c4-convex-bsd
+	exit 0 ;;
+    esac
+fi
+
+#echo '(Unable to guess system type)' 1>&2
+
+exit 1
Index: /main/tags/2.25/gsdl/packages/mg/config.h.in
===================================================================
--- /main/tags/2.25/gsdl/packages/mg/config.h.in	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/mg/config.h.in	(revision 21064)
@@ -0,0 +1,171 @@
+/* config.h.in.  Generated automatically from configure.in by autoheader.  */
+
+/* Define if on AIX 3.
+   System headers sometimes define this.
+   We just want to avoid a redefinition error message.  */
+#ifndef _ALL_SOURCE
+#undef _ALL_SOURCE
+#endif
+
+/* Define if using alloca.c.  */
+#undef C_ALLOCA
+
+/* Define to empty if the keyword does not work.  */
+#undef const
+
+/* Define to one of _getb67, GETB67, getb67 for Cray-2 and Cray-YMP systems.
+   This function is required for alloca.c support on those systems.  */
+#undef CRAY_STACKSEG_END
+
+/* Define if you have alloca, as a function or macro.  */
+#undef HAVE_ALLOCA
+
+/* Define if you have <alloca.h> and it should be used (not on Ultrix).  */
+#undef HAVE_ALLOCA_H
+
+/* Define if you don't have vprintf but do have _doprnt.  */
+#undef HAVE_DOPRNT
+
+/* Define if you have the vprintf function.  */
+#undef HAVE_VPRINTF
+
+/* Define if on MINIX.  */
+#undef _MINIX
+
+/* Define to `long' if <sys/types.h> doesn't define.  */
+#undef off_t
+
+/* Define if the system does not provide POSIX.1 features except
+   with this defined.  */
+#undef _POSIX_1_SOURCE
+
+/* Define if you need to in order for stat and other things to work.  */
+#undef _POSIX_SOURCE
+
+/* Define as the return type of signal handlers (int or void).  */
+#undef RETSIGTYPE
+
+/* Define to `unsigned' if <sys/types.h> doesn't define.  */
+#undef size_t
+
+/* If using the C implementation of alloca, define if you know the
+   direction of stack growth for your system; otherwise it will be
+   automatically deduced at run-time.
+ STACK_DIRECTION > 0 => grows toward higher addresses
+ STACK_DIRECTION < 0 => grows toward lower addresses
+ STACK_DIRECTION = 0 => direction of growth unknown
+ */
+#undef STACK_DIRECTION
+
+/* Define if you have the ANSI C header files.  */
+#undef STDC_HEADERS
+
+/* Define if you can safely include both <sys/time.h> and <time.h>.  */
+#undef TIME_WITH_SYS_TIME
+
+/* Define if your <sys/time.h> declares struct tm.  */
+#undef TM_IN_SYS_TIME
+
+/* Define to the name of the distribution.  */
+#undef PACKAGE
+
+/* Define to the version of the distribution.  */
+#undef VERSION
+
+/* Define to 1 if you have the valloc function.  */
+#undef HAVE_VALLOC
+
+/* Define to 1 if ANSI function prototypes are usable.  */
+#undef PROTOTYPES
+
+ 
+/* Define to 1 for better use of the debugging malloc library.  See
+   site ftp.antaire.com in antaire/src, file dmalloc/dmalloc.tar.gz.  */
+#undef WITH_DMALLOC
+
+ 
+/* Define to 1 if GNU regex should be used instead of GNU rx.  */
+#undef WITH_REGEX
+
+/* Some braindead header files do not have the requ'd function declarations */
+#undef HAVE_FGETC_DECL
+#undef HAVE_FREAD_DECL
+
+/* See if have this field in the prstatus_t structure */
+/* It stores the size of the process heap */
+#undef HAVE_PR_BRKSIZE
+
+/* Define if you have the ftime function.  */
+#undef HAVE_FTIME
+
+/* Define if you have the ftruncate function.  */
+#undef HAVE_FTRUNCATE
+
+/* Define if you have the getpagesize function.  */
+#undef HAVE_GETPAGESIZE
+
+/* Define if you have the getrusage function.  */
+#undef HAVE_GETRUSAGE
+
+/* Define if you have the mallinfo function.  */
+#undef HAVE_MALLINFO
+
+/* Define if you have the select function.  */
+#undef HAVE_SELECT
+
+/* Define if you have the setbuffer function.  */
+#undef HAVE_SETBUFFER
+
+/* Define if you have the strcasecmp function.  */
+#undef HAVE_STRCASECMP
+
+/* Define if you have the strftime function.  */
+#undef HAVE_STRFTIME
+
+/* Define if you have the strstr function.  */
+#undef HAVE_STRSTR
+
+/* Define if you have the strtol function.  */
+#undef HAVE_STRTOL
+
+/* Define if you have the times function.  */
+#undef HAVE_TIMES
+
+/* Define if you have the valloc function.  */
+#undef HAVE_VALLOC
+
+/* Define if you have the <dirent.h> header file.  */
+#undef HAVE_DIRENT_H
+
+/* Define if you have the <fcntl.h> header file.  */
+#undef HAVE_FCNTL_H
+
+/* Define if you have the <limits.h> header file.  */
+#undef HAVE_LIMITS_H
+
+/* Define if you have the <memory.h> header file.  */
+#undef HAVE_MEMORY_H
+
+/* Define if you have the <ndir.h> header file.  */
+#undef HAVE_NDIR_H
+
+/* Define if you have the <string.h> header file.  */
+#undef HAVE_STRING_H
+
+/* Define if you have the <sys/dir.h> header file.  */
+#undef HAVE_SYS_DIR_H
+
+/* Define if you have the <sys/ndir.h> header file.  */
+#undef HAVE_SYS_NDIR_H
+
+/* Define if you have the <sys/procfs.h> header file.  */
+#undef HAVE_SYS_PROCFS_H
+
+/* Define if you have the <sys/time.h> header file.  */
+#undef HAVE_SYS_TIME_H
+
+/* Define if you have the <unistd.h> header file.  */
+#undef HAVE_UNISTD_H
+
+/* Define if you have the m library (-lm).  */
+#undef HAVE_LIBM
Index: /main/tags/2.25/gsdl/packages/mg/config.sub
===================================================================
--- /main/tags/2.25/gsdl/packages/mg/config.sub	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/mg/config.sub	(revision 21064)
@@ -0,0 +1,793 @@
+#!/bin/sh
+# Configuration validation subroutine script, version 1.1.
+#   Copyright (C) 1991, 1992, 1993, 1994 Free Software Foundation, Inc.
+# This file is (in principle) common to ALL GNU software.
+# The presence of a machine in this file suggests that SOME GNU software
+# can handle that machine.  It does not imply ALL GNU software can. 
+#
+# This file 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.
+
+# As a special exception to the GNU General Public License, if you
+# distribute this file as part of a program that contains a
+# configuration script generated by Autoconf, you may include it under
+# the same distribution terms that you use for the rest of that program.
+
+# Configuration subroutine to validate and canonicalize a configuration type.
+# Supply the specified configuration type as an argument.
+# If it is invalid, we print an error message on stderr and exit with code 1.
+# Otherwise, we print the canonical config type on stdout and succeed.
+
+# This file is supposed to be the same for all GNU packages
+# and recognize all the CPU types, system types and aliases
+# that are meaningful with *any* GNU software.
+# Each package is responsible for reporting which valid configurations
+# it does not support.  The user should be able to distinguish
+# a failure to support a valid configuration from a meaningless
+# configuration.
+
+# The goal of this file is to map all the various variations of a given
+# machine specification into a single specification in the form:
+#	CPU_TYPE-MANUFACTURER-OPERATING_SYSTEM
+# It is wrong to echo any other type of specification.
+
+# First pass through any local machine types.
+case $1 in
+	*local*)
+		echo $1
+		exit 0
+		;;
+	*)
+	;;
+esac
+
+# Separate what the user gave into CPU-COMPANY and OS (if any).
+basic_machine=`echo $1 | sed 's/-[^-]*$//'`
+if [ $basic_machine != $1 ]
+then os=`echo $1 | sed 's/.*-/-/'`
+else os=; fi
+
+### Let's recognize common machines as not being operating systems so
+### that things like config.sub decstation-3100 work.  We also
+### recognize some manufacturers as not being operating systems, so we
+### can provide default operating systems below.
+case $os in
+	-sun*os*)
+		# Prevent following clause from handling this invalid input.
+		;;
+	-dec* | -mips* | -sequent* | -encore* | -pc532* | -sgi* | -sony* | \
+	-att* | -7300* | -3300* | -delta* | -motorola* | -sun[234]* | \
+	-unicom* | -ibm* | -next | -hp | -isi* | -apollo | -altos* | \
+	-convergent* | -ncr* | -news | -32* | -3600* | -3100* | -hitachi* |\
+	-c[123]* | -convex* | -sun | -crds | -omron* | -dg | -ultra | -tti* | \
+	-harris | -dolphin | -highlevel | -gould | -cbm | -ns | -masscomp )
+		os=
+		basic_machine=$1
+		;;
+	-hiux*)
+		os=-hiuxwe2
+		;;
+	-sco4)
+		os=-sco3.2v4
+		basic_machine=`echo $1 | sed -e 's/86-.*/86-unknown/'`
+		;;
+	-sco3.2.[4-9]*)
+		os=`echo $os | sed -e 's/sco3.2./sco3.2v/'`
+		basic_machine=`echo $1 | sed -e 's/86-.*/86-unknown/'`
+		;;
+	-sco3.2v[4-9]*)
+		# Don't forget version if it is 3.2v4 or newer.
+		basic_machine=`echo $1 | sed -e 's/86-.*/86-unknown/'`
+		;;
+	-sco*)
+		os=-sco3.2v2
+		basic_machine=`echo $1 | sed -e 's/86-.*/86-unknown/'`
+		;;
+	-isc)
+		os=-isc2.2
+		basic_machine=`echo $1 | sed -e 's/86-.*/86-unknown/'`
+		;;
+	-clix*)
+		basic_machine=clipper-intergraph
+		;;
+	-isc*)
+		basic_machine=`echo $1 | sed -e 's/86-.*/86-unknown/'`
+		;;
+	-lynx)
+		os=-lynxos
+		;;
+	-ptx*)
+		basic_machine=`echo $1 | sed -e 's/86-.*/86-sequent/'`
+		;;
+	-windowsnt*)
+		os=`echo $os | sed -e 's/windowsnt/winnt/'`
+		;;
+esac
+
+# Decode aliases for certain CPU-COMPANY combinations.
+case $basic_machine in
+	# Recognize the basic CPU types without company name.
+	# Some are omitted here because they have special meanings below.
+	tahoe | i[345]86 | i860 | m68k | m68000 | m88k | ns32k | arm | pyramid \
+		| tron | a29k | 580 | i960 | h8300 | hppa1.0 | hppa1.1 \
+		| alpha | we32k | ns16k | clipper | sparclite | i370 | sh \
+		| powerpc | sparc64 | 1750a | dsp16xx | mips64 | mipsel \
+		| pdp11 | mips64el | mips64orion | mips64orionel )
+		basic_machine=$basic_machine-unknown
+		;;
+	# Object if more than one company name word.
+	*-*-*)
+		echo Invalid configuration \`$1\': machine \`$basic_machine\' not recognized 1>&2
+		exit 1
+		;;
+	# Recognize the basic CPU types with company name.
+	vax-* | tahoe-* | i[345]86-* | i860-* | m68k-* | m68000-* | m88k-* \
+	      | sparc-* | ns32k-* | fx80-* | arm-* | c[123]* \
+	      | mips-* | pyramid-* | tron-* | a29k-* | romp-* | rs6000-* \
+	      | none-* | 580-* | cray2-* | h8300-* | i960-* | xmp-* | ymp-* \
+	      | hppa1.0-* | hppa1.1-* | alpha-* | we32k-* | cydra-* | ns16k-* \
+	      | pn-* | np1-* | xps100-* | clipper-* | orion-* | sparclite-* \
+	      | pdp11-* | sh-* | powerpc-* | sparc64-* | mips64-* | mipsel-* \
+	      | mips64el-* | mips64orion-* | mips64orionel-* )
+		;;
+	# Recognize the various machine names and aliases which stand
+	# for a CPU type and a company and sometimes even an OS.
+	3b1 | 7300 | 7300-att | att-7300 | pc7300 | safari | unixpc)
+		basic_machine=m68000-att
+		;;
+	3b*)
+		basic_machine=we32k-att
+		;;
+	alliant | fx80)
+		basic_machine=fx80-alliant
+		;;
+	altos | altos3068)
+		basic_machine=m68k-altos
+		;;
+	am29k)
+		basic_machine=a29k-none
+		os=-bsd
+		;;
+	amdahl)
+		basic_machine=580-amdahl
+		os=-sysv
+		;;
+	amiga | amiga-*)
+		basic_machine=m68k-cbm
+		;;
+	amigados)
+		basic_machine=m68k-cbm
+		os=-amigados
+		;;
+	amigaunix | amix)
+		basic_machine=m68k-cbm
+		os=-sysv4
+		;;
+	apollo68)
+		basic_machine=m68k-apollo
+		os=-sysv
+		;;
+	balance)
+		basic_machine=ns32k-sequent
+		os=-dynix
+		;;
+	convex-c1)
+		basic_machine=c1-convex
+		os=-bsd
+		;;
+	convex-c2)
+		basic_machine=c2-convex
+		os=-bsd
+		;;
+	convex-c32)
+		basic_machine=c32-convex
+		os=-bsd
+		;;
+	convex-c34)
+		basic_machine=c34-convex
+		os=-bsd
+		;;
+	convex-c38)
+		basic_machine=c38-convex
+		os=-bsd
+		;;
+	cray | ymp)
+		basic_machine=ymp-cray
+		os=-unicos
+		;;
+	cray2)
+		basic_machine=cray2-cray
+		os=-unicos
+		;;
+	crds | unos)
+		basic_machine=m68k-crds
+		;;
+	da30 | da30-*)
+		basic_machine=m68k-da30
+		;;
+	decstation | decstation-3100 | pmax | pmax-* | pmin | dec3100 | decstatn)
+		basic_machine=mips-dec
+		;;
+	delta | 3300 | motorola-3300 | motorola-delta \
+	      | 3300-motorola | delta-motorola)
+		basic_machine=m68k-motorola
+		;;
+	delta88)
+		basic_machine=m88k-motorola
+		os=-sysv3
+		;;
+	dpx20 | dpx20-*)
+		basic_machine=rs6000-bull
+		os=-bosx
+		;;
+	dpx2* | dpx2*-bull)
+		basic_machine=m68k-bull
+		os=-sysv3
+		;;
+	ebmon29k)
+		basic_machine=a29k-amd
+		os=-ebmon
+		;;
+	elxsi)
+		basic_machine=elxsi-elxsi
+		os=-bsd
+		;;
+	encore | umax | mmax)
+		basic_machine=ns32k-encore
+		;;
+	fx2800)
+		basic_machine=i860-alliant
+		;;
+	genix)
+		basic_machine=ns32k-ns
+		;;
+	gmicro)
+		basic_machine=tron-gmicro
+		os=-sysv
+		;;
+	h3050r* | hiux*)
+		basic_machine=hppa1.1-hitachi
+		os=-hiuxwe2
+		;;
+	h8300hms)
+		basic_machine=h8300-hitachi
+		os=-hms
+		;;
+	harris)
+		basic_machine=m88k-harris
+		os=-sysv3
+		;;
+	hp300-*)
+		basic_machine=m68k-hp
+		;;
+	hp300bsd)
+		basic_machine=m68k-hp
+		os=-bsd
+		;;
+	hp300hpux)
+		basic_machine=m68k-hp
+		os=-hpux
+		;;
+	hp9k2[0-9][0-9] | hp9k31[0-9])
+		basic_machine=m68000-hp
+		;;
+	hp9k3[2-9][0-9])
+		basic_machine=m68k-hp
+		;;
+	hp9k7[0-9][0-9] | hp7[0-9][0-9] | hp9k8[0-9]7 | hp8[0-9]7)
+		basic_machine=hppa1.1-hp
+		;;
+	hp9k8[0-9][0-9] | hp8[0-9][0-9])
+		basic_machine=hppa1.0-hp
+		;;
+	i370-ibm* | ibm*)
+		basic_machine=i370-ibm
+		os=-mvs
+		;;
+# I'm not sure what "Sysv32" means.  Should this be sysv3.2?
+	i[345]86v32)
+		basic_machine=`echo $1 | sed -e 's/86.*/86-unknown/'`
+		os=-sysv32
+		;;
+	i[345]86v4*)
+		basic_machine=`echo $1 | sed -e 's/86.*/86-unknown/'`
+		os=-sysv4
+		;;
+	i[345]86v)
+		basic_machine=`echo $1 | sed -e 's/86.*/86-unknown/'`
+		os=-sysv
+		;;
+	i[345]86sol2)
+		basic_machine=`echo $1 | sed -e 's/86.*/86-unknown/'`
+		os=-solaris2
+		;;
+	iris | iris4d)
+		basic_machine=mips-sgi
+		case $os in
+		    -irix*)
+			;;
+		    *)
+			os=-irix4
+			;;
+		esac
+		;;
+	isi68 | isi)
+		basic_machine=m68k-isi
+		os=-sysv
+		;;
+	m88k-omron*)
+		basic_machine=m88k-omron
+		;;
+	magnum | m3230)
+		basic_machine=mips-mips
+		os=-sysv
+		;;
+	merlin)
+		basic_machine=ns32k-utek
+		os=-sysv
+		;;
+	miniframe)
+		basic_machine=m68000-convergent
+		;;
+	mips3*-*)
+		basic_machine=`echo $basic_machine | sed -e 's/mips3/mips64/'`
+		;;
+	mips3*)
+		basic_machine=`echo $basic_machine | sed -e 's/mips3/mips64/'`-unknown
+		;;
+	ncr3000)
+		basic_machine=i486-ncr
+		os=-sysv4
+		;;
+	news | news700 | news800 | news900)
+		basic_machine=m68k-sony
+		os=-newsos
+		;;
+	news1000)
+		basic_machine=m68030-sony
+		os=-newsos
+		;;
+	news-3600 | risc-news)
+		basic_machine=mips-sony
+		os=-newsos
+		;;
+	next | m*-next )
+		basic_machine=m68k-next
+		case $os in
+		    -nextstep* )
+			;;
+		    -ns2*)
+		      os=-nextstep2
+			;;
+		    *)
+		      os=-nextstep3
+			;;
+		esac
+		;;
+	nh3000)
+		basic_machine=m68k-harris
+		os=-cxux
+		;;
+	nh[45]000)
+		basic_machine=m88k-harris
+		os=-cxux
+		;;
+	nindy960)
+		basic_machine=i960-intel
+		os=-nindy
+		;;
+	np1)
+		basic_machine=np1-gould
+		;;
+	pa-hitachi)
+		basic_machine=hppa1.1-hitachi
+		os=-hiuxwe2
+		;;
+	paragon)
+		basic_machine=i860-intel
+		os=-osf
+		;;
+	pbd)
+		basic_machine=sparc-tti
+		;;
+	pbb)
+		basic_machine=m68k-tti
+		;;
+        pc532 | pc532-*)
+		basic_machine=ns32k-pc532
+		;;
+	pentium-*)
+		# We will change tis to say i586 once there has been
+		# time for various packages to start to recognize that.
+		basic_machine=i486-`echo $basic_machine | sed 's/^[^-]*-//'`
+		;;
+	pn)
+		basic_machine=pn-gould
+		;;
+	ps2)
+		basic_machine=i386-ibm
+		;;
+	rtpc | rtpc-*)
+		basic_machine=romp-ibm
+		;;
+	sequent)
+		basic_machine=i386-sequent
+		;;
+	sh)
+		basic_machine=sh-hitachi
+		os=-hms
+		;;
+	sps7)
+		basic_machine=m68k-bull
+		os=-sysv2
+		;;
+	spur)
+		basic_machine=spur-unknown
+		;;
+	sun2)
+		basic_machine=m68000-sun
+		;;
+	sun2os3)
+		basic_machine=m68000-sun
+		os=-sunos3
+		;;
+	sun2os4)
+		basic_machine=m68000-sun
+		os=-sunos4
+		;;
+	sun3os3)
+		basic_machine=m68k-sun
+		os=-sunos3
+		;;
+	sun3os4)
+		basic_machine=m68k-sun
+		os=-sunos4
+		;;
+	sun4os3)
+		basic_machine=sparc-sun
+		os=-sunos3
+		;;
+	sun4os4)
+		basic_machine=sparc-sun
+		os=-sunos4
+		;;
+	sun3 | sun3-*)
+		basic_machine=m68k-sun
+		;;
+	sun4)
+		basic_machine=sparc-sun
+		;;
+	sun386 | sun386i | roadrunner)
+		basic_machine=i386-sun
+		;;
+	symmetry)
+		basic_machine=i386-sequent
+		os=-dynix
+		;;
+	tower | tower-32)
+		basic_machine=m68k-ncr
+		;;
+	ultra3)
+		basic_machine=a29k-nyu
+		os=-sym1
+		;;
+	vaxv)
+		basic_machine=vax-dec
+		os=-sysv
+		;;
+	vms)
+		basic_machine=vax-dec
+		os=-vms
+		;;
+	vxworks960)
+		basic_machine=i960-wrs
+		os=-vxworks
+		;;
+	vxworks68)
+		basic_machine=m68k-wrs
+		os=-vxworks
+		;;
+	xmp)
+		basic_machine=xmp-cray
+		os=-unicos
+		;;
+        xps | xps100)
+		basic_machine=xps100-honeywell
+		;;
+	none)
+		basic_machine=none-none
+		os=-none
+		;;
+
+# Here we handle the default manufacturer of certain CPU types.  It is in
+# some cases the only manufacturer, in others, it is the most popular.
+	mips)
+		basic_machine=mips-mips
+		;;
+	romp)
+		basic_machine=romp-ibm
+		;;
+	rs6000)
+		basic_machine=rs6000-ibm
+		;;
+	vax)
+		basic_machine=vax-dec
+		;;
+	pdp11)
+		basic_machine=pdp11-dec
+		;;
+	we32k)
+		basic_machine=we32k-att
+		;;
+	sparc)
+		basic_machine=sparc-sun
+		;;
+        cydra)
+		basic_machine=cydra-cydrome
+		;;
+	orion)
+		basic_machine=orion-highlevel
+		;;
+	orion105)
+		basic_machine=clipper-highlevel
+		;;
+	*)
+		echo Invalid configuration \`$1\': machine \`$basic_machine\' not recognized 1>&2
+		exit 1
+		;;
+esac
+
+# Here we canonicalize certain aliases for manufacturers.
+case $basic_machine in
+	*-digital*)
+		basic_machine=`echo $basic_machine | sed 's/digital.*/dec/'`
+		;;
+	*-commodore*)
+		basic_machine=`echo $basic_machine | sed 's/commodore.*/cbm/'`
+		;;
+	*)
+		;;
+esac
+
+# Decode manufacturer-specific aliases for certain operating systems.
+
+if [ x"$os" != x"" ]
+then
+case $os in
+	# -solaris* is a basic system type, with this one exception.
+	-solaris1 | -solaris1.*)
+		os=`echo $os | sed -e 's|solaris1|sunos4|'`
+		;;
+	-solaris)
+		os=-solaris2
+		;;
+	-gnu/linux*)
+		os=`echo $os | sed -e 's|gnu/linux|linux|'`
+		;;
+	# First accept the basic system types.
+	# The portable systems comes first.
+	# Each alternative must end in a *, to match a version number.
+	# -sysv* is not here because it comes later, after sysvr4.
+	-gnu* | -bsd* | -mach* | -minix* | -genix* | -ultrix* | -irix* \
+	      | -vms* | -sco* | -esix* | -isc* | -aix* | -sunos | -sunos[345]* \
+	      | -hpux* | -unos* | -osf* | -luna* | -dgux* | -solaris* | -sym* \
+	      | -amigados* | -msdos* | -newsos* | -unicos* | -aos* \
+	      | -nindy* | -vxworks* | -ebmon* | -hms* | -mvs* | -clix* \
+	      | -riscos* | -linux* | -uniplus* | -iris* | -rtu* | -xenix* \
+	      | -hiux* | -386bsd* | -netbsd* | -freebsd* | -riscix* \
+	      | -lynxos* | -bosx* | -nextstep* | -cxux* | -aout* | -elf* \
+	      | -ptx* | -coff* | -winnt*)
+		;;
+	-sunos5*)
+		os=`echo $os | sed -e 's|sunos5|solaris2|'`
+		;;
+	-sunos6*)
+		os=`echo $os | sed -e 's|sunos6|solaris3|'`
+		;;
+	-osfrose*)
+		os=-osfrose
+		;;
+	-osf*)
+		os=-osf
+		;;
+	-utek*)
+		os=-bsd
+		;;
+	-dynix*)
+		os=-bsd
+		;;
+	-acis*)
+		os=-aos
+		;;
+	-ctix* | -uts*)
+		os=-sysv
+		;;
+	-triton*)
+		os=-sysv3
+		;;
+	-oss*)
+		os=-sysv3
+		;;
+	-svr4)
+		os=-sysv4
+		;;
+	-svr3)
+		os=-sysv3
+		;;
+	-sysvr4)
+		os=-sysv4
+		;;
+	# This must come after -sysvr4.
+	-sysv*)
+		;;
+	-xenix)
+		os=-xenix
+		;;
+	-none)
+		;;
+	*)
+		# Get rid of the `-' at the beginning of $os.
+		os=`echo $os | sed 's/[^-]*-//'`
+		echo Invalid configuration \`$1\': system \`$os\' not recognized 1>&2
+		exit 1
+		;;
+esac
+else
+
+# Here we handle the default operating systems that come with various machines.
+# The value should be what the vendor currently ships out the door with their
+# machine or put another way, the most popular os provided with the machine.
+
+# Note that if you're going to try to match "-MANUFACTURER" here (say,
+# "-sun"), then you have to tell the case statement up towards the top
+# that MANUFACTURER isn't an operating system.  Otherwise, code above
+# will signal an error saying that MANUFACTURER isn't an operating
+# system, and we'll never get to this point.
+
+case $basic_machine in
+	*-acorn)
+		os=-riscix1.2
+		;;
+        pdp11-*)
+		os=-none
+		;;
+	*-dec | vax-*)
+		os=-ultrix4.2
+		;;
+	i386-sun)
+		os=-sunos4.0.2
+		;;
+	m68000-sun)
+		os=-sunos3
+		# This also exists in the configure program, but was not the
+		# default.
+		# os=-sunos4
+		;;
+	*-tti)	# must be before sparc entry or we get the wrong os.
+		os=-sysv3
+		;;
+	sparc-* | *-sun)
+		os=-sunos4.1.1
+		;;
+	*-ibm)
+		os=-aix
+		;;
+	*-hp)
+		os=-hpux
+		;;
+	*-hitachi)
+		os=-hiux
+		;;
+	i860-* | *-att | *-ncr | *-altos | *-motorola | *-convergent)
+		os=-sysv
+		;;
+	*-cbm)
+		os=-amigados
+		;;
+	*-dg)
+		os=-dgux
+		;;
+	*-dolphin)
+		os=-sysv3
+		;;
+	m68k-ccur)
+		os=-rtu
+		;;
+	m88k-omron*)
+		os=-luna
+		;;
+	*-sequent)
+		os=-ptx
+		;;
+	*-crds)
+		os=-unos
+		;;
+	*-ns)
+		os=-genix
+		;;
+	i370-*)
+		os=-mvs
+		;;
+	*-next)
+		os=-nextstep3
+		;;
+        *-gould)
+		os=-sysv
+		;;
+        *-highlevel)
+		os=-bsd
+		;;
+	*-encore)
+		os=-bsd
+		;;
+        *-sgi)
+		os=-irix
+		;;
+	*-masscomp)
+		os=-rtu
+		;;
+	*)
+		os=-none
+		;;
+esac
+fi
+
+# Here we handle the case where we know the os, and the CPU type, but not the
+# manufacturer.  We pick the logical manufacturer.
+vendor=unknown
+case $basic_machine in
+	*-unknown)
+		case $os in
+			-riscix*)
+				vendor=acorn
+				;;
+			-sunos*)
+				vendor=sun
+				;;
+			-lynxos*)
+				vendor=lynx
+				;;
+			-aix*)
+				vendor=ibm
+				;;
+			-hpux*)
+				vendor=hp
+				;;
+			-hiux*)
+				vendor=hitachi
+				;;
+			-unos*)
+				vendor=crds
+				;;
+			-dgux*)
+				vendor=dg
+				;;
+			-luna*)
+				vendor=omron
+				;;
+			-genix*)
+				vendor=ns
+				;;
+			-mvs*)
+				vendor=ibm
+				;;
+			-ptx*)
+				vendor=sequent
+				;;
+		esac
+		basic_machine=`echo $basic_machine | sed "s/unknown/$vendor/"`
+		;;
+esac
+
+echo $basic_machine$os
Index: /main/tags/2.25/gsdl/packages/mg/configure
===================================================================
--- /main/tags/2.25/gsdl/packages/mg/configure	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/mg/configure	(revision 21064)
@@ -0,0 +1,3073 @@
+#! /bin/sh
+
+# Guess values for system-dependent variables and create Makefiles.
+# Generated automatically using autoconf version 2.12 
+# Copyright (C) 1992, 93, 94, 95, 96 Free Software Foundation, Inc.
+#
+# This configure script is free software; the Free Software Foundation
+# gives unlimited permission to copy, distribute and modify it.
+
+# Defaults:
+ac_help=
+ac_default_prefix=/usr/local
+# Any additions from configure.in:
+ac_help="$ac_help
+  --with-dmalloc          use dmalloc, as in
+                          ftp://ftp.letters.com/src/dmalloc/dmalloc.tar.gz"
+ac_help="$ac_help
+  --with-regex            use older regex in lieu of GNU rx for matching"
+
+# Initialize some variables set by options.
+# The variables have the same names as the options, with
+# dashes changed to underlines.
+build=NONE
+cache_file=./config.cache
+exec_prefix=NONE
+host=NONE
+no_create=
+nonopt=NONE
+no_recursion=
+prefix=NONE
+program_prefix=NONE
+program_suffix=NONE
+program_transform_name=s,x,x,
+silent=
+site=
+srcdir=
+target=NONE
+verbose=
+x_includes=NONE
+x_libraries=NONE
+bindir='${exec_prefix}/bin'
+sbindir='${exec_prefix}/sbin'
+libexecdir='${exec_prefix}/libexec'
+datadir='${prefix}/share'
+sysconfdir='${prefix}/etc'
+sharedstatedir='${prefix}/com'
+localstatedir='${prefix}/var'
+libdir='${exec_prefix}/lib'
+includedir='${prefix}/include'
+oldincludedir='/usr/include'
+infodir='${prefix}/info'
+mandir='${prefix}/man'
+
+# Initialize some other variables.
+subdirs=
+MFLAGS= MAKEFLAGS=
+# Maximum number of lines to put in a shell here document.
+ac_max_here_lines=12
+
+ac_prev=
+for ac_option
+do
+
+  # If the previous option needs an argument, assign it.
+  if test -n "$ac_prev"; then
+    eval "$ac_prev=\$ac_option"
+    ac_prev=
+    continue
+  fi
+
+  case "$ac_option" in
+  -*=*) ac_optarg=`echo "$ac_option" | sed 's/[-_a-zA-Z0-9]*=//'` ;;
+  *) ac_optarg= ;;
+  esac
+
+  # Accept the important Cygnus configure options, so we can diagnose typos.
+
+  case "$ac_option" in
+
+  -bindir | --bindir | --bindi | --bind | --bin | --bi)
+    ac_prev=bindir ;;
+  -bindir=* | --bindir=* | --bindi=* | --bind=* | --bin=* | --bi=*)
+    bindir="$ac_optarg" ;;
+
+  -build | --build | --buil | --bui | --bu)
+    ac_prev=build ;;
+  -build=* | --build=* | --buil=* | --bui=* | --bu=*)
+    build="$ac_optarg" ;;
+
+  -cache-file | --cache-file | --cache-fil | --cache-fi \
+  | --cache-f | --cache- | --cache | --cach | --cac | --ca | --c)
+    ac_prev=cache_file ;;
+  -cache-file=* | --cache-file=* | --cache-fil=* | --cache-fi=* \
+  | --cache-f=* | --cache-=* | --cache=* | --cach=* | --cac=* | --ca=* | --c=*)
+    cache_file="$ac_optarg" ;;
+
+  -datadir | --datadir | --datadi | --datad | --data | --dat | --da)
+    ac_prev=datadir ;;
+  -datadir=* | --datadir=* | --datadi=* | --datad=* | --data=* | --dat=* \
+  | --da=*)
+    datadir="$ac_optarg" ;;
+
+  -disable-* | --disable-*)
+    ac_feature=`echo $ac_option|sed -e 's/-*disable-//'`
+    # Reject names that are not valid shell variable names.
+    if test -n "`echo $ac_feature| sed 's/[-a-zA-Z0-9_]//g'`"; then
+      { echo "configure: error: $ac_feature: invalid feature name" 1>&2; exit 1; }
+    fi
+    ac_feature=`echo $ac_feature| sed 's/-/_/g'`
+    eval "enable_${ac_feature}=no" ;;
+
+  -enable-* | --enable-*)
+    ac_feature=`echo $ac_option|sed -e 's/-*enable-//' -e 's/=.*//'`
+    # Reject names that are not valid shell variable names.
+    if test -n "`echo $ac_feature| sed 's/[-_a-zA-Z0-9]//g'`"; then
+      { echo "configure: error: $ac_feature: invalid feature name" 1>&2; exit 1; }
+    fi
+    ac_feature=`echo $ac_feature| sed 's/-/_/g'`
+    case "$ac_option" in
+      *=*) ;;
+      *) ac_optarg=yes ;;
+    esac
+    eval "enable_${ac_feature}='$ac_optarg'" ;;
+
+  -exec-prefix | --exec_prefix | --exec-prefix | --exec-prefi \
+  | --exec-pref | --exec-pre | --exec-pr | --exec-p | --exec- \
+  | --exec | --exe | --ex)
+    ac_prev=exec_prefix ;;
+  -exec-prefix=* | --exec_prefix=* | --exec-prefix=* | --exec-prefi=* \
+  | --exec-pref=* | --exec-pre=* | --exec-pr=* | --exec-p=* | --exec-=* \
+  | --exec=* | --exe=* | --ex=*)
+    exec_prefix="$ac_optarg" ;;
+
+  -gas | --gas | --ga | --g)
+    # Obsolete; use --with-gas.
+    with_gas=yes ;;
+
+  -help | --help | --hel | --he)
+    # Omit some internal or obsolete options to make the list less imposing.
+    # This message is too long to be a string in the A/UX 3.1 sh.
+    cat << EOF
+Usage: configure [options] [host]
+Options: [defaults in brackets after descriptions]
+Configuration:
+  --cache-file=FILE       cache test results in FILE
+  --help                  print this message
+  --no-create             do not create output files
+  --quiet, --silent       do not print \`checking...' messages
+  --version               print the version of autoconf that created configure
+Directory and file names:
+  --prefix=PREFIX         install architecture-independent files in PREFIX
+                          [$ac_default_prefix]
+  --exec-prefix=EPREFIX   install architecture-dependent files in EPREFIX
+                          [same as prefix]
+  --bindir=DIR            user executables in DIR [EPREFIX/bin]
+  --sbindir=DIR           system admin executables in DIR [EPREFIX/sbin]
+  --libexecdir=DIR        program executables in DIR [EPREFIX/libexec]
+  --datadir=DIR           read-only architecture-independent data in DIR
+                          [PREFIX/share]
+  --sysconfdir=DIR        read-only single-machine data in DIR [PREFIX/etc]
+  --sharedstatedir=DIR    modifiable architecture-independent data in DIR
+                          [PREFIX/com]
+  --localstatedir=DIR     modifiable single-machine data in DIR [PREFIX/var]
+  --libdir=DIR            object code libraries in DIR [EPREFIX/lib]
+  --includedir=DIR        C header files in DIR [PREFIX/include]
+  --oldincludedir=DIR     C header files for non-gcc in DIR [/usr/include]
+  --infodir=DIR           info documentation in DIR [PREFIX/info]
+  --mandir=DIR            man documentation in DIR [PREFIX/man]
+  --srcdir=DIR            find the sources in DIR [configure dir or ..]
+  --program-prefix=PREFIX prepend PREFIX to installed program names
+  --program-suffix=SUFFIX append SUFFIX to installed program names
+  --program-transform-name=PROGRAM
+                          run sed PROGRAM on installed program names
+EOF
+    cat << EOF
+Host type:
+  --build=BUILD           configure for building on BUILD [BUILD=HOST]
+  --host=HOST             configure for HOST [guessed]
+  --target=TARGET         configure for TARGET [TARGET=HOST]
+Features and packages:
+  --disable-FEATURE       do not include FEATURE (same as --enable-FEATURE=no)
+  --enable-FEATURE[=ARG]  include FEATURE [ARG=yes]
+  --with-PACKAGE[=ARG]    use PACKAGE [ARG=yes]
+  --without-PACKAGE       do not use PACKAGE (same as --with-PACKAGE=no)
+  --x-includes=DIR        X include files are in DIR
+  --x-libraries=DIR       X library files are in DIR
+EOF
+    if test -n "$ac_help"; then
+      echo "--enable and --with options recognized:$ac_help"
+    fi
+    exit 0 ;;
+
+  -host | --host | --hos | --ho)
+    ac_prev=host ;;
+  -host=* | --host=* | --hos=* | --ho=*)
+    host="$ac_optarg" ;;
+
+  -includedir | --includedir | --includedi | --included | --include \
+  | --includ | --inclu | --incl | --inc)
+    ac_prev=includedir ;;
+  -includedir=* | --includedir=* | --includedi=* | --included=* | --include=* \
+  | --includ=* | --inclu=* | --incl=* | --inc=*)
+    includedir="$ac_optarg" ;;
+
+  -infodir | --infodir | --infodi | --infod | --info | --inf)
+    ac_prev=infodir ;;
+  -infodir=* | --infodir=* | --infodi=* | --infod=* | --info=* | --inf=*)
+    infodir="$ac_optarg" ;;
+
+  -libdir | --libdir | --libdi | --libd)
+    ac_prev=libdir ;;
+  -libdir=* | --libdir=* | --libdi=* | --libd=*)
+    libdir="$ac_optarg" ;;
+
+  -libexecdir | --libexecdir | --libexecdi | --libexecd | --libexec \
+  | --libexe | --libex | --libe)
+    ac_prev=libexecdir ;;
+  -libexecdir=* | --libexecdir=* | --libexecdi=* | --libexecd=* | --libexec=* \
+  | --libexe=* | --libex=* | --libe=*)
+    libexecdir="$ac_optarg" ;;
+
+  -localstatedir | --localstatedir | --localstatedi | --localstated \
+  | --localstate | --localstat | --localsta | --localst \
+  | --locals | --local | --loca | --loc | --lo)
+    ac_prev=localstatedir ;;
+  -localstatedir=* | --localstatedir=* | --localstatedi=* | --localstated=* \
+  | --localstate=* | --localstat=* | --localsta=* | --localst=* \
+  | --locals=* | --local=* | --loca=* | --loc=* | --lo=*)
+    localstatedir="$ac_optarg" ;;
+
+  -mandir | --mandir | --mandi | --mand | --man | --ma | --m)
+    ac_prev=mandir ;;
+  -mandir=* | --mandir=* | --mandi=* | --mand=* | --man=* | --ma=* | --m=*)
+    mandir="$ac_optarg" ;;
+
+  -nfp | --nfp | --nf)
+    # Obsolete; use --without-fp.
+    with_fp=no ;;
+
+  -no-create | --no-create | --no-creat | --no-crea | --no-cre \
+  | --no-cr | --no-c)
+    no_create=yes ;;
+
+  -no-recursion | --no-recursion | --no-recursio | --no-recursi \
+  | --no-recurs | --no-recur | --no-recu | --no-rec | --no-re | --no-r)
+    no_recursion=yes ;;
+
+  -oldincludedir | --oldincludedir | --oldincludedi | --oldincluded \
+  | --oldinclude | --oldinclud | --oldinclu | --oldincl | --oldinc \
+  | --oldin | --oldi | --old | --ol | --o)
+    ac_prev=oldincludedir ;;
+  -oldincludedir=* | --oldincludedir=* | --oldincludedi=* | --oldincluded=* \
+  | --oldinclude=* | --oldinclud=* | --oldinclu=* | --oldincl=* | --oldinc=* \
+  | --oldin=* | --oldi=* | --old=* | --ol=* | --o=*)
+    oldincludedir="$ac_optarg" ;;
+
+  -prefix | --prefix | --prefi | --pref | --pre | --pr | --p)
+    ac_prev=prefix ;;
+  -prefix=* | --prefix=* | --prefi=* | --pref=* | --pre=* | --pr=* | --p=*)
+    prefix="$ac_optarg" ;;
+
+  -program-prefix | --program-prefix | --program-prefi | --program-pref \
+  | --program-pre | --program-pr | --program-p)
+    ac_prev=program_prefix ;;
+  -program-prefix=* | --program-prefix=* | --program-prefi=* \
+  | --program-pref=* | --program-pre=* | --program-pr=* | --program-p=*)
+    program_prefix="$ac_optarg" ;;
+
+  -program-suffix | --program-suffix | --program-suffi | --program-suff \
+  | --program-suf | --program-su | --program-s)
+    ac_prev=program_suffix ;;
+  -program-suffix=* | --program-suffix=* | --program-suffi=* \
+  | --program-suff=* | --program-suf=* | --program-su=* | --program-s=*)
+    program_suffix="$ac_optarg" ;;
+
+  -program-transform-name | --program-transform-name \
+  | --program-transform-nam | --program-transform-na \
+  | --program-transform-n | --program-transform- \
+  | --program-transform | --program-transfor \
+  | --program-transfo | --program-transf \
+  | --program-trans | --program-tran \
+  | --progr-tra | --program-tr | --program-t)
+    ac_prev=program_transform_name ;;
+  -program-transform-name=* | --program-transform-name=* \
+  | --program-transform-nam=* | --program-transform-na=* \
+  | --program-transform-n=* | --program-transform-=* \
+  | --program-transform=* | --program-transfor=* \
+  | --program-transfo=* | --program-transf=* \
+  | --program-trans=* | --program-tran=* \
+  | --progr-tra=* | --program-tr=* | --program-t=*)
+    program_transform_name="$ac_optarg" ;;
+
+  -q | -quiet | --quiet | --quie | --qui | --qu | --q \
+  | -silent | --silent | --silen | --sile | --sil)
+    silent=yes ;;
+
+  -sbindir | --sbindir | --sbindi | --sbind | --sbin | --sbi | --sb)
+    ac_prev=sbindir ;;
+  -sbindir=* | --sbindir=* | --sbindi=* | --sbind=* | --sbin=* \
+  | --sbi=* | --sb=*)
+    sbindir="$ac_optarg" ;;
+
+  -sharedstatedir | --sharedstatedir | --sharedstatedi \
+  | --sharedstated | --sharedstate | --sharedstat | --sharedsta \
+  | --sharedst | --shareds | --shared | --share | --shar \
+  | --sha | --sh)
+    ac_prev=sharedstatedir ;;
+  -sharedstatedir=* | --sharedstatedir=* | --sharedstatedi=* \
+  | --sharedstated=* | --sharedstate=* | --sharedstat=* | --sharedsta=* \
+  | --sharedst=* | --shareds=* | --shared=* | --share=* | --shar=* \
+  | --sha=* | --sh=*)
+    sharedstatedir="$ac_optarg" ;;
+
+  -site | --site | --sit)
+    ac_prev=site ;;
+  -site=* | --site=* | --sit=*)
+    site="$ac_optarg" ;;
+
+  -srcdir | --srcdir | --srcdi | --srcd | --src | --sr)
+    ac_prev=srcdir ;;
+  -srcdir=* | --srcdir=* | --srcdi=* | --srcd=* | --src=* | --sr=*)
+    srcdir="$ac_optarg" ;;
+
+  -sysconfdir | --sysconfdir | --sysconfdi | --sysconfd | --sysconf \
+  | --syscon | --sysco | --sysc | --sys | --sy)
+    ac_prev=sysconfdir ;;
+  -sysconfdir=* | --sysconfdir=* | --sysconfdi=* | --sysconfd=* | --sysconf=* \
+  | --syscon=* | --sysco=* | --sysc=* | --sys=* | --sy=*)
+    sysconfdir="$ac_optarg" ;;
+
+  -target | --target | --targe | --targ | --tar | --ta | --t)
+    ac_prev=target ;;
+  -target=* | --target=* | --targe=* | --targ=* | --tar=* | --ta=* | --t=*)
+    target="$ac_optarg" ;;
+
+  -v | -verbose | --verbose | --verbos | --verbo | --verb)
+    verbose=yes ;;
+
+  -version | --version | --versio | --versi | --vers)
+    echo "configure generated by autoconf version 2.12"
+    exit 0 ;;
+
+  -with-* | --with-*)
+    ac_package=`echo $ac_option|sed -e 's/-*with-//' -e 's/=.*//'`
+    # Reject names that are not valid shell variable names.
+    if test -n "`echo $ac_package| sed 's/[-_a-zA-Z0-9]//g'`"; then
+      { echo "configure: error: $ac_package: invalid package name" 1>&2; exit 1; }
+    fi
+    ac_package=`echo $ac_package| sed 's/-/_/g'`
+    case "$ac_option" in
+      *=*) ;;
+      *) ac_optarg=yes ;;
+    esac
+    eval "with_${ac_package}='$ac_optarg'" ;;
+
+  -without-* | --without-*)
+    ac_package=`echo $ac_option|sed -e 's/-*without-//'`
+    # Reject names that are not valid shell variable names.
+    if test -n "`echo $ac_package| sed 's/[-a-zA-Z0-9_]//g'`"; then
+      { echo "configure: error: $ac_package: invalid package name" 1>&2; exit 1; }
+    fi
+    ac_package=`echo $ac_package| sed 's/-/_/g'`
+    eval "with_${ac_package}=no" ;;
+
+  --x)
+    # Obsolete; use --with-x.
+    with_x=yes ;;
+
+  -x-includes | --x-includes | --x-include | --x-includ | --x-inclu \
+  | --x-incl | --x-inc | --x-in | --x-i)
+    ac_prev=x_includes ;;
+  -x-includes=* | --x-includes=* | --x-include=* | --x-includ=* | --x-inclu=* \
+  | --x-incl=* | --x-inc=* | --x-in=* | --x-i=*)
+    x_includes="$ac_optarg" ;;
+
+  -x-libraries | --x-libraries | --x-librarie | --x-librari \
+  | --x-librar | --x-libra | --x-libr | --x-lib | --x-li | --x-l)
+    ac_prev=x_libraries ;;
+  -x-libraries=* | --x-libraries=* | --x-librarie=* | --x-librari=* \
+  | --x-librar=* | --x-libra=* | --x-libr=* | --x-lib=* | --x-li=* | --x-l=*)
+    x_libraries="$ac_optarg" ;;
+
+  -*) { echo "configure: error: $ac_option: invalid option; use --help to show usage" 1>&2; exit 1; }
+    ;;
+
+  *)
+    if test -n "`echo $ac_option| sed 's/[-a-z0-9.]//g'`"; then
+      echo "configure: warning: $ac_option: invalid host type" 1>&2
+    fi
+    if test "x$nonopt" != xNONE; then
+      { echo "configure: error: can only configure for one host and one target at a time" 1>&2; exit 1; }
+    fi
+    nonopt="$ac_option"
+    ;;
+
+  esac
+done
+
+if test -n "$ac_prev"; then
+  { echo "configure: error: missing argument to --`echo $ac_prev | sed 's/_/-/g'`" 1>&2; exit 1; }
+fi
+
+trap 'rm -fr conftest* confdefs* core core.* *.core $ac_clean_files; exit 1' 1 2 15
+
+# File descriptor usage:
+# 0 standard input
+# 1 file creation
+# 2 errors and warnings
+# 3 some systems may open it to /dev/tty
+# 4 used on the Kubota Titan
+# 6 checking for... messages and results
+# 5 compiler messages saved in config.log
+if test "$silent" = yes; then
+  exec 6>/dev/null
+else
+  exec 6>&1
+fi
+exec 5>./config.log
+
+echo "\
+This file contains any messages produced by compilers while
+running configure, to aid debugging if configure makes a mistake.
+" 1>&5
+
+# Strip out --no-create and --no-recursion so they do not pile up.
+# Also quote any args containing shell metacharacters.
+ac_configure_args=
+for ac_arg
+do
+  case "$ac_arg" in
+  -no-create | --no-create | --no-creat | --no-crea | --no-cre \
+  | --no-cr | --no-c) ;;
+  -no-recursion | --no-recursion | --no-recursio | --no-recursi \
+  | --no-recurs | --no-recur | --no-recu | --no-rec | --no-re | --no-r) ;;
+  *" "*|*"	"*|*[\[\]\~\#\$\^\&\*\(\)\{\}\\\|\;\<\>\?]*)
+  ac_configure_args="$ac_configure_args '$ac_arg'" ;;
+  *) ac_configure_args="$ac_configure_args $ac_arg" ;;
+  esac
+done
+
+# NLS nuisances.
+# Only set these to C if already set.  These must not be set unconditionally
+# because not all systems understand e.g. LANG=C (notably SCO).
+# Fixing LC_MESSAGES prevents Solaris sh from translating var values in `set'!
+# Non-C LC_CTYPE values break the ctype check.
+if test "${LANG+set}"   = set; then LANG=C;   export LANG;   fi
+if test "${LC_ALL+set}" = set; then LC_ALL=C; export LC_ALL; fi
+if test "${LC_MESSAGES+set}" = set; then LC_MESSAGES=C; export LC_MESSAGES; fi
+if test "${LC_CTYPE+set}"    = set; then LC_CTYPE=C;    export LC_CTYPE;    fi
+
+# confdefs.h avoids OS command line length limits that DEFS can exceed.
+rm -rf conftest* confdefs.h
+# AIX cpp loses on an empty file, so make sure it contains at least a newline.
+echo > confdefs.h
+
+# A filename unique to this package, relative to the directory that
+# configure is in, which we can look for to find out if srcdir is correct.
+ac_unique_file=src/text/mgquery.c
+
+# Find the source files, if location was not specified.
+if test -z "$srcdir"; then
+  ac_srcdir_defaulted=yes
+  # Try the directory containing this script, then its parent.
+  ac_prog=$0
+  ac_confdir=`echo $ac_prog|sed 's%/[^/][^/]*$%%'`
+  test "x$ac_confdir" = "x$ac_prog" && ac_confdir=.
+  srcdir=$ac_confdir
+  if test ! -r $srcdir/$ac_unique_file; then
+    srcdir=..
+  fi
+else
+  ac_srcdir_defaulted=no
+fi
+if test ! -r $srcdir/$ac_unique_file; then
+  if test "$ac_srcdir_defaulted" = yes; then
+    { echo "configure: error: can not find sources in $ac_confdir or .." 1>&2; exit 1; }
+  else
+    { echo "configure: error: can not find sources in $srcdir" 1>&2; exit 1; }
+  fi
+fi
+srcdir=`echo "${srcdir}" | sed 's%\([^/]\)/*$%\1%'`
+
+# Prefer explicitly selected file to automatically selected ones.
+if test -z "$CONFIG_SITE"; then
+  if test "x$prefix" != xNONE; then
+    CONFIG_SITE="$prefix/share/config.site $prefix/etc/config.site"
+  else
+    CONFIG_SITE="$ac_default_prefix/share/config.site $ac_default_prefix/etc/config.site"
+  fi
+fi
+for ac_site_file in $CONFIG_SITE; do
+  if test -r "$ac_site_file"; then
+    echo "loading site script $ac_site_file"
+    . "$ac_site_file"
+  fi
+done
+
+if test -r "$cache_file"; then
+  echo "loading cache $cache_file"
+  . $cache_file
+else
+  echo "creating cache $cache_file"
+  > $cache_file
+fi
+
+ac_ext=c
+# CFLAGS is not in ac_cpp because -g, -O, etc. are not valid cpp options.
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='${CC-cc} -c $CFLAGS $CPPFLAGS conftest.$ac_ext 1>&5'
+ac_link='${CC-cc} -o conftest $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS 1>&5'
+cross_compiling=$ac_cv_prog_cc_cross
+
+if (echo "testing\c"; echo 1,2,3) | grep c >/dev/null; then
+  # Stardent Vistra SVR4 grep lacks -e, says ghazi@caip.rutgers.edu.
+  if (echo -n testing; echo 1,2,3) | sed s/-n/xn/ | grep xn >/dev/null; then
+    ac_n= ac_c='
+' ac_t='	'
+  else
+    ac_n=-n ac_c= ac_t=
+  fi
+else
+  ac_n= ac_c='\c' ac_t=
+fi
+
+
+
+if test "$program_transform_name" = s,x,x,; then
+  program_transform_name=
+else
+  # Double any \ or $.  echo might interpret backslashes.
+  cat <<\EOF_SED > conftestsed
+s,\\,\\\\,g; s,\$,$$,g
+EOF_SED
+  program_transform_name="`echo $program_transform_name|sed -f conftestsed`"
+  rm -f conftestsed
+fi
+test "$program_prefix" != NONE &&
+  program_transform_name="s,^,${program_prefix},; $program_transform_name"
+# Use a double $ so make ignores it.
+test "$program_suffix" != NONE &&
+  program_transform_name="s,\$\$,${program_suffix},; $program_transform_name"
+
+# sed with no file args requires a program.
+test "$program_transform_name" = "" && program_transform_name="s,x,x,"
+
+
+PACKAGE=mg
+VERSION=1.3e
+
+cat >> confdefs.h <<EOF
+#define PACKAGE "$PACKAGE"
+EOF
+
+cat >> confdefs.h <<EOF
+#define VERSION "$VERSION"
+EOF
+
+
+
+
+for ac_prog in $CCC c++ g++ gcc CC cxx cc++
+do
+# Extract the first word of "$ac_prog", so it can be a program name with args.
+set dummy $ac_prog; ac_word=$2
+echo $ac_n "checking for $ac_word""... $ac_c" 1>&6
+echo "configure:567: checking for $ac_word" >&5
+if eval "test \"`echo '$''{'ac_cv_prog_CXX'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  if test -n "$CXX"; then
+  ac_cv_prog_CXX="$CXX" # Let the user override the test.
+else
+  IFS="${IFS= 	}"; ac_save_ifs="$IFS"; IFS="${IFS}:"
+  for ac_dir in $PATH; do
+    test -z "$ac_dir" && ac_dir=.
+    if test -f $ac_dir/$ac_word; then
+      ac_cv_prog_CXX="$ac_prog"
+      break
+    fi
+  done
+  IFS="$ac_save_ifs"
+fi
+fi
+CXX="$ac_cv_prog_CXX"
+if test -n "$CXX"; then
+  echo "$ac_t""$CXX" 1>&6
+else
+  echo "$ac_t""no" 1>&6
+fi
+
+test -n "$CXX" && break
+done
+test -n "$CXX" || CXX="gcc"
+
+
+echo $ac_n "checking whether the C++ compiler ($CXX $CXXFLAGS $LDFLAGS) works""... $ac_c" 1>&6
+echo "configure:598: checking whether the C++ compiler ($CXX $CXXFLAGS $LDFLAGS) works" >&5
+
+ac_ext=C
+# CXXFLAGS is not in ac_cpp because -g, -O, etc. are not valid cpp options.
+ac_cpp='$CXXCPP $CPPFLAGS'
+ac_compile='${CXX-g++} -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext 1>&5'
+ac_link='${CXX-g++} -o conftest $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS 1>&5'
+cross_compiling=$ac_cv_prog_cxx_cross
+
+cat > conftest.$ac_ext <<EOF
+#line 608 "configure"
+#include "confdefs.h"
+main(){return(0);}
+EOF
+if { (eval echo configure:612: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest; then
+  ac_cv_prog_cxx_works=yes
+  # If we can't run a trivial program, we are probably using a cross compiler.
+  if (./conftest; exit) 2>/dev/null; then
+    ac_cv_prog_cxx_cross=no
+  else
+    ac_cv_prog_cxx_cross=yes
+  fi
+else
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  ac_cv_prog_cxx_works=no
+fi
+rm -fr conftest*
+ac_ext=c
+# CFLAGS is not in ac_cpp because -g, -O, etc. are not valid cpp options.
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='${CC-cc} -c $CFLAGS $CPPFLAGS conftest.$ac_ext 1>&5'
+ac_link='${CC-cc} -o conftest $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS 1>&5'
+cross_compiling=$ac_cv_prog_cc_cross
+
+echo "$ac_t""$ac_cv_prog_cxx_works" 1>&6
+if test $ac_cv_prog_cxx_works = no; then
+  { echo "configure: error: installation or configuration problem: C++ compiler cannot create executables." 1>&2; exit 1; }
+fi
+echo $ac_n "checking whether the C++ compiler ($CXX $CXXFLAGS $LDFLAGS) is a cross-compiler""... $ac_c" 1>&6
+echo "configure:638: checking whether the C++ compiler ($CXX $CXXFLAGS $LDFLAGS) is a cross-compiler" >&5
+echo "$ac_t""$ac_cv_prog_cxx_cross" 1>&6
+cross_compiling=$ac_cv_prog_cxx_cross
+
+echo $ac_n "checking whether we are using GNU C++""... $ac_c" 1>&6
+echo "configure:643: checking whether we are using GNU C++" >&5
+if eval "test \"`echo '$''{'ac_cv_prog_gxx'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  cat > conftest.C <<EOF
+#ifdef __GNUC__
+  yes;
+#endif
+EOF
+if { ac_try='${CXX-g++} -E conftest.C'; { (eval echo configure:652: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }; } | egrep yes >/dev/null 2>&1; then
+  ac_cv_prog_gxx=yes
+else
+  ac_cv_prog_gxx=no
+fi
+fi
+
+echo "$ac_t""$ac_cv_prog_gxx" 1>&6
+
+if test $ac_cv_prog_gxx = yes; then
+  GXX=yes
+  ac_test_CXXFLAGS="${CXXFLAGS+set}"
+  ac_save_CXXFLAGS="$CXXFLAGS"
+  CXXFLAGS=
+  echo $ac_n "checking whether ${CXX-g++} accepts -g""... $ac_c" 1>&6
+echo "configure:667: checking whether ${CXX-g++} accepts -g" >&5
+if eval "test \"`echo '$''{'ac_cv_prog_cxx_g'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  echo 'void f(){}' > conftest.cc
+if test -z "`${CXX-g++} -g -c conftest.cc 2>&1`"; then
+  ac_cv_prog_cxx_g=yes
+else
+  ac_cv_prog_cxx_g=no
+fi
+rm -f conftest*
+
+fi
+
+echo "$ac_t""$ac_cv_prog_cxx_g" 1>&6
+  if test "$ac_test_CXXFLAGS" = set; then
+    CXXFLAGS="$ac_save_CXXFLAGS"
+  elif test $ac_cv_prog_cxx_g = yes; then
+    CXXFLAGS="-g -O2"
+  else
+    CXXFLAGS="-O2"
+  fi
+else
+  GXX=
+  test "${CXXFLAGS+set}" = set || CXXFLAGS="-g"
+fi
+
+for ac_prog in mawk gawk nawk awk
+do
+# Extract the first word of "$ac_prog", so it can be a program name with args.
+set dummy $ac_prog; ac_word=$2
+echo $ac_n "checking for $ac_word""... $ac_c" 1>&6
+echo "configure:699: checking for $ac_word" >&5
+if eval "test \"`echo '$''{'ac_cv_prog_AWK'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  if test -n "$AWK"; then
+  ac_cv_prog_AWK="$AWK" # Let the user override the test.
+else
+  IFS="${IFS= 	}"; ac_save_ifs="$IFS"; IFS="${IFS}:"
+  for ac_dir in $PATH; do
+    test -z "$ac_dir" && ac_dir=.
+    if test -f $ac_dir/$ac_word; then
+      ac_cv_prog_AWK="$ac_prog"
+      break
+    fi
+  done
+  IFS="$ac_save_ifs"
+fi
+fi
+AWK="$ac_cv_prog_AWK"
+if test -n "$AWK"; then
+  echo "$ac_t""$AWK" 1>&6
+else
+  echo "$ac_t""no" 1>&6
+fi
+
+test -n "$AWK" && break
+done
+
+for ac_prog in 'bison -y' byacc
+do
+# Extract the first word of "$ac_prog", so it can be a program name with args.
+set dummy $ac_prog; ac_word=$2
+echo $ac_n "checking for $ac_word""... $ac_c" 1>&6
+echo "configure:732: checking for $ac_word" >&5
+if eval "test \"`echo '$''{'ac_cv_prog_YACC'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  if test -n "$YACC"; then
+  ac_cv_prog_YACC="$YACC" # Let the user override the test.
+else
+  IFS="${IFS= 	}"; ac_save_ifs="$IFS"; IFS="${IFS}:"
+  for ac_dir in $PATH; do
+    test -z "$ac_dir" && ac_dir=.
+    if test -f $ac_dir/$ac_word; then
+      ac_cv_prog_YACC="$ac_prog"
+      break
+    fi
+  done
+  IFS="$ac_save_ifs"
+fi
+fi
+YACC="$ac_cv_prog_YACC"
+if test -n "$YACC"; then
+  echo "$ac_t""$YACC" 1>&6
+else
+  echo "$ac_t""no" 1>&6
+fi
+
+test -n "$YACC" && break
+done
+test -n "$YACC" || YACC="yacc"
+
+# Extract the first word of "gcc", so it can be a program name with args.
+set dummy gcc; ac_word=$2
+echo $ac_n "checking for $ac_word""... $ac_c" 1>&6
+echo "configure:764: checking for $ac_word" >&5
+if eval "test \"`echo '$''{'ac_cv_prog_CC'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  if test -n "$CC"; then
+  ac_cv_prog_CC="$CC" # Let the user override the test.
+else
+  IFS="${IFS= 	}"; ac_save_ifs="$IFS"; IFS="${IFS}:"
+  for ac_dir in $PATH; do
+    test -z "$ac_dir" && ac_dir=.
+    if test -f $ac_dir/$ac_word; then
+      ac_cv_prog_CC="gcc"
+      break
+    fi
+  done
+  IFS="$ac_save_ifs"
+fi
+fi
+CC="$ac_cv_prog_CC"
+if test -n "$CC"; then
+  echo "$ac_t""$CC" 1>&6
+else
+  echo "$ac_t""no" 1>&6
+fi
+
+if test -z "$CC"; then
+  # Extract the first word of "cc", so it can be a program name with args.
+set dummy cc; ac_word=$2
+echo $ac_n "checking for $ac_word""... $ac_c" 1>&6
+echo "configure:793: checking for $ac_word" >&5
+if eval "test \"`echo '$''{'ac_cv_prog_CC'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  if test -n "$CC"; then
+  ac_cv_prog_CC="$CC" # Let the user override the test.
+else
+  IFS="${IFS= 	}"; ac_save_ifs="$IFS"; IFS="${IFS}:"
+  ac_prog_rejected=no
+  for ac_dir in $PATH; do
+    test -z "$ac_dir" && ac_dir=.
+    if test -f $ac_dir/$ac_word; then
+      if test "$ac_dir/$ac_word" = "/usr/ucb/cc"; then
+        ac_prog_rejected=yes
+	continue
+      fi
+      ac_cv_prog_CC="cc"
+      break
+    fi
+  done
+  IFS="$ac_save_ifs"
+if test $ac_prog_rejected = yes; then
+  # We found a bogon in the path, so make sure we never use it.
+  set dummy $ac_cv_prog_CC
+  shift
+  if test $# -gt 0; then
+    # We chose a different compiler from the bogus one.
+    # However, it has the same basename, so the bogon will be chosen
+    # first if we set CC to just the basename; use the full file name.
+    shift
+    set dummy "$ac_dir/$ac_word" "$@"
+    shift
+    ac_cv_prog_CC="$@"
+  fi
+fi
+fi
+fi
+CC="$ac_cv_prog_CC"
+if test -n "$CC"; then
+  echo "$ac_t""$CC" 1>&6
+else
+  echo "$ac_t""no" 1>&6
+fi
+
+  test -z "$CC" && { echo "configure: error: no acceptable cc found in \$PATH" 1>&2; exit 1; }
+fi
+
+echo $ac_n "checking whether the C compiler ($CC $CFLAGS $LDFLAGS) works""... $ac_c" 1>&6
+echo "configure:841: checking whether the C compiler ($CC $CFLAGS $LDFLAGS) works" >&5
+
+ac_ext=c
+# CFLAGS is not in ac_cpp because -g, -O, etc. are not valid cpp options.
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='${CC-cc} -c $CFLAGS $CPPFLAGS conftest.$ac_ext 1>&5'
+ac_link='${CC-cc} -o conftest $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS 1>&5'
+cross_compiling=$ac_cv_prog_cc_cross
+
+cat > conftest.$ac_ext <<EOF
+#line 851 "configure"
+#include "confdefs.h"
+main(){return(0);}
+EOF
+if { (eval echo configure:855: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest; then
+  ac_cv_prog_cc_works=yes
+  # If we can't run a trivial program, we are probably using a cross compiler.
+  if (./conftest; exit) 2>/dev/null; then
+    ac_cv_prog_cc_cross=no
+  else
+    ac_cv_prog_cc_cross=yes
+  fi
+else
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  ac_cv_prog_cc_works=no
+fi
+rm -fr conftest*
+
+echo "$ac_t""$ac_cv_prog_cc_works" 1>&6
+if test $ac_cv_prog_cc_works = no; then
+  { echo "configure: error: installation or configuration problem: C compiler cannot create executables." 1>&2; exit 1; }
+fi
+echo $ac_n "checking whether the C compiler ($CC $CFLAGS $LDFLAGS) is a cross-compiler""... $ac_c" 1>&6
+echo "configure:875: checking whether the C compiler ($CC $CFLAGS $LDFLAGS) is a cross-compiler" >&5
+echo "$ac_t""$ac_cv_prog_cc_cross" 1>&6
+cross_compiling=$ac_cv_prog_cc_cross
+
+echo $ac_n "checking whether we are using GNU C""... $ac_c" 1>&6
+echo "configure:880: checking whether we are using GNU C" >&5
+if eval "test \"`echo '$''{'ac_cv_prog_gcc'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  cat > conftest.c <<EOF
+#ifdef __GNUC__
+  yes;
+#endif
+EOF
+if { ac_try='${CC-cc} -E conftest.c'; { (eval echo configure:889: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }; } | egrep yes >/dev/null 2>&1; then
+  ac_cv_prog_gcc=yes
+else
+  ac_cv_prog_gcc=no
+fi
+fi
+
+echo "$ac_t""$ac_cv_prog_gcc" 1>&6
+
+if test $ac_cv_prog_gcc = yes; then
+  GCC=yes
+  ac_test_CFLAGS="${CFLAGS+set}"
+  ac_save_CFLAGS="$CFLAGS"
+  CFLAGS=
+  echo $ac_n "checking whether ${CC-cc} accepts -g""... $ac_c" 1>&6
+echo "configure:904: checking whether ${CC-cc} accepts -g" >&5
+if eval "test \"`echo '$''{'ac_cv_prog_cc_g'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  echo 'void f(){}' > conftest.c
+if test -z "`${CC-cc} -g -c conftest.c 2>&1`"; then
+  ac_cv_prog_cc_g=yes
+else
+  ac_cv_prog_cc_g=no
+fi
+rm -f conftest*
+
+fi
+
+echo "$ac_t""$ac_cv_prog_cc_g" 1>&6
+  if test "$ac_test_CFLAGS" = set; then
+    CFLAGS="$ac_save_CFLAGS"
+  elif test $ac_cv_prog_cc_g = yes; then
+    CFLAGS="-g -O2"
+  else
+    CFLAGS="-O2"
+  fi
+else
+  GCC=
+  test "${CFLAGS+set}" = set || CFLAGS="-g"
+fi
+
+ac_aux_dir=
+for ac_dir in $srcdir $srcdir/.. $srcdir/../..; do
+  if test -f $ac_dir/install-sh; then
+    ac_aux_dir=$ac_dir
+    ac_install_sh="$ac_aux_dir/install-sh -c"
+    break
+  elif test -f $ac_dir/install.sh; then
+    ac_aux_dir=$ac_dir
+    ac_install_sh="$ac_aux_dir/install.sh -c"
+    break
+  fi
+done
+if test -z "$ac_aux_dir"; then
+  { echo "configure: error: can not find install-sh or install.sh in $srcdir $srcdir/.. $srcdir/../.." 1>&2; exit 1; }
+fi
+ac_config_guess=$ac_aux_dir/config.guess
+ac_config_sub=$ac_aux_dir/config.sub
+ac_configure=$ac_aux_dir/configure # This should be Cygnus configure.
+
+# Find a good install program.  We prefer a C program (faster),
+# so one script is as good as another.  But avoid the broken or
+# incompatible versions:
+# SysV /etc/install, /usr/sbin/install
+# SunOS /usr/etc/install
+# IRIX /sbin/install
+# AIX /bin/install
+# AFS /usr/afsws/bin/install, which mishandles nonexistent args
+# SVR4 /usr/ucb/install, which tries to use the nonexistent group "staff"
+# ./install, which can be erroneously created by make from ./install.sh.
+echo $ac_n "checking for a BSD compatible install""... $ac_c" 1>&6
+echo "configure:961: checking for a BSD compatible install" >&5
+if test -z "$INSTALL"; then
+if eval "test \"`echo '$''{'ac_cv_path_install'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+    IFS="${IFS= 	}"; ac_save_IFS="$IFS"; IFS="${IFS}:"
+  for ac_dir in $PATH; do
+    # Account for people who put trailing slashes in PATH elements.
+    case "$ac_dir/" in
+    /|./|.//|/etc/*|/usr/sbin/*|/usr/etc/*|/sbin/*|/usr/afsws/bin/*|/usr/ucb/*) ;;
+    *)
+      # OSF1 and SCO ODT 3.0 have their own names for install.
+      for ac_prog in ginstall installbsd scoinst install; do
+        if test -f $ac_dir/$ac_prog; then
+	  if test $ac_prog = install &&
+            grep dspmsg $ac_dir/$ac_prog >/dev/null 2>&1; then
+	    # AIX install.  It has an incompatible calling convention.
+	    # OSF/1 installbsd also uses dspmsg, but is usable.
+	    :
+	  else
+	    ac_cv_path_install="$ac_dir/$ac_prog -c"
+	    break 2
+	  fi
+	fi
+      done
+      ;;
+    esac
+  done
+  IFS="$ac_save_IFS"
+
+fi
+  if test "${ac_cv_path_install+set}" = set; then
+    INSTALL="$ac_cv_path_install"
+  else
+    # As a last resort, use the slow shell script.  We don't cache a
+    # path for INSTALL within a source directory, because that will
+    # break other packages using the cache if that directory is
+    # removed, or if the path is relative.
+    INSTALL="$ac_install_sh"
+  fi
+fi
+echo "$ac_t""$INSTALL" 1>&6
+
+# Use test -z because SunOS4 sh mishandles braces in ${var-val}.
+# It thinks the first close brace ends the variable substitution.
+test -z "$INSTALL_PROGRAM" && INSTALL_PROGRAM='${INSTALL}'
+
+test -z "$INSTALL_DATA" && INSTALL_DATA='${INSTALL} -m 644'
+
+echo $ac_n "checking whether ln -s works""... $ac_c" 1>&6
+echo "configure:1011: checking whether ln -s works" >&5
+if eval "test \"`echo '$''{'ac_cv_prog_LN_S'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  rm -f conftestdata
+if ln -s X conftestdata 2>/dev/null
+then
+  rm -f conftestdata
+  ac_cv_prog_LN_S="ln -s"
+else
+  ac_cv_prog_LN_S=ln
+fi
+fi
+LN_S="$ac_cv_prog_LN_S"
+if test "$ac_cv_prog_LN_S" = "ln -s"; then
+  echo "$ac_t""yes" 1>&6
+else
+  echo "$ac_t""no" 1>&6
+fi
+
+echo $ac_n "checking whether ${MAKE-make} sets \${MAKE}""... $ac_c" 1>&6
+echo "configure:1032: checking whether ${MAKE-make} sets \${MAKE}" >&5
+set dummy ${MAKE-make}; ac_make=`echo "$2" | sed 'y%./+-%__p_%'`
+if eval "test \"`echo '$''{'ac_cv_prog_make_${ac_make}_set'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  cat > conftestmake <<\EOF
+all:
+	@echo 'ac_maketemp="${MAKE}"'
+EOF
+# GNU make sometimes prints "make[1]: Entering...", which would confuse us.
+eval `${MAKE-make} -f conftestmake 2>/dev/null | grep temp=`
+if test -n "$ac_maketemp"; then
+  eval ac_cv_prog_make_${ac_make}_set=yes
+else
+  eval ac_cv_prog_make_${ac_make}_set=no
+fi
+rm -f conftestmake
+fi
+if eval "test \"`echo '$ac_cv_prog_make_'${ac_make}_set`\" = yes"; then
+  echo "$ac_t""yes" 1>&6
+  SET_MAKE=
+else
+  echo "$ac_t""no" 1>&6
+  SET_MAKE="MAKE=${MAKE-make}"
+fi
+
+# Extract the first word of "ranlib", so it can be a program name with args.
+set dummy ranlib; ac_word=$2
+echo $ac_n "checking for $ac_word""... $ac_c" 1>&6
+echo "configure:1061: checking for $ac_word" >&5
+if eval "test \"`echo '$''{'ac_cv_prog_RANLIB'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  if test -n "$RANLIB"; then
+  ac_cv_prog_RANLIB="$RANLIB" # Let the user override the test.
+else
+  IFS="${IFS= 	}"; ac_save_ifs="$IFS"; IFS="${IFS}:"
+  for ac_dir in $PATH; do
+    test -z "$ac_dir" && ac_dir=.
+    if test -f $ac_dir/$ac_word; then
+      ac_cv_prog_RANLIB="ranlib"
+      break
+    fi
+  done
+  IFS="$ac_save_ifs"
+  test -z "$ac_cv_prog_RANLIB" && ac_cv_prog_RANLIB=":"
+fi
+fi
+RANLIB="$ac_cv_prog_RANLIB"
+if test -n "$RANLIB"; then
+  echo "$ac_t""$RANLIB" 1>&6
+else
+  echo "$ac_t""no" 1>&6
+fi
+
+
+echo $ac_n "checking how to run the C preprocessor""... $ac_c" 1>&6
+echo "configure:1089: checking how to run the C preprocessor" >&5
+# On Suns, sometimes $CPP names a directory.
+if test -n "$CPP" && test -d "$CPP"; then
+  CPP=
+fi
+if test -z "$CPP"; then
+if eval "test \"`echo '$''{'ac_cv_prog_CPP'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+    # This must be in double quotes, not single quotes, because CPP may get
+  # substituted into the Makefile and "${CC-cc}" will confuse make.
+  CPP="${CC-cc} -E"
+  # On the NeXT, cc -E runs the code through the compiler's parser,
+  # not just through cpp.
+  cat > conftest.$ac_ext <<EOF
+#line 1104 "configure"
+#include "confdefs.h"
+#include <assert.h>
+Syntax Error
+EOF
+ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out"
+{ (eval echo configure:1110: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }
+ac_err=`grep -v '^ *+' conftest.out`
+if test -z "$ac_err"; then
+  :
+else
+  echo "$ac_err" >&5
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -rf conftest*
+  CPP="${CC-cc} -E -traditional-cpp"
+  cat > conftest.$ac_ext <<EOF
+#line 1121 "configure"
+#include "confdefs.h"
+#include <assert.h>
+Syntax Error
+EOF
+ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out"
+{ (eval echo configure:1127: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }
+ac_err=`grep -v '^ *+' conftest.out`
+if test -z "$ac_err"; then
+  :
+else
+  echo "$ac_err" >&5
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -rf conftest*
+  CPP=/lib/cpp
+fi
+rm -f conftest*
+fi
+rm -f conftest*
+  ac_cv_prog_CPP="$CPP"
+fi
+  CPP="$ac_cv_prog_CPP"
+else
+  ac_cv_prog_CPP="$CPP"
+fi
+echo "$ac_t""$CPP" 1>&6
+
+echo $ac_n "checking for AIX""... $ac_c" 1>&6
+echo "configure:1150: checking for AIX" >&5
+cat > conftest.$ac_ext <<EOF
+#line 1152 "configure"
+#include "confdefs.h"
+#ifdef _AIX
+  yes
+#endif
+
+EOF
+if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
+  egrep "yes" >/dev/null 2>&1; then
+  rm -rf conftest*
+  echo "$ac_t""yes" 1>&6; cat >> confdefs.h <<\EOF
+#define _ALL_SOURCE 1
+EOF
+
+else
+  rm -rf conftest*
+  echo "$ac_t""no" 1>&6
+fi
+rm -f conftest*
+
+
+echo $ac_n "checking for POSIXized ISC""... $ac_c" 1>&6
+echo "configure:1174: checking for POSIXized ISC" >&5
+if test -d /etc/conf/kconfig.d &&
+  grep _POSIX_VERSION /usr/include/sys/unistd.h >/dev/null 2>&1
+then
+  echo "$ac_t""yes" 1>&6
+  ISC=yes # If later tests want to check for ISC.
+  cat >> confdefs.h <<\EOF
+#define _POSIX_SOURCE 1
+EOF
+
+  if test "$GCC" = yes; then
+    CC="$CC -posix"
+  else
+    CC="$CC -Xp"
+  fi
+else
+  echo "$ac_t""no" 1>&6
+  ISC=
+fi
+
+ac_safe=`echo "minix/config.h" | sed 'y%./+-%__p_%'`
+echo $ac_n "checking for minix/config.h""... $ac_c" 1>&6
+echo "configure:1196: checking for minix/config.h" >&5
+if eval "test \"`echo '$''{'ac_cv_header_$ac_safe'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  cat > conftest.$ac_ext <<EOF
+#line 1201 "configure"
+#include "confdefs.h"
+#include <minix/config.h>
+EOF
+ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out"
+{ (eval echo configure:1206: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }
+ac_err=`grep -v '^ *+' conftest.out`
+if test -z "$ac_err"; then
+  rm -rf conftest*
+  eval "ac_cv_header_$ac_safe=yes"
+else
+  echo "$ac_err" >&5
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -rf conftest*
+  eval "ac_cv_header_$ac_safe=no"
+fi
+rm -f conftest*
+fi
+if eval "test \"`echo '$ac_cv_header_'$ac_safe`\" = yes"; then
+  echo "$ac_t""yes" 1>&6
+  MINIX=yes
+else
+  echo "$ac_t""no" 1>&6
+MINIX=
+fi
+
+if test "$MINIX" = yes; then
+  cat >> confdefs.h <<\EOF
+#define _POSIX_SOURCE 1
+EOF
+
+  cat >> confdefs.h <<\EOF
+#define _POSIX_1_SOURCE 2
+EOF
+
+  cat >> confdefs.h <<\EOF
+#define _MINIX 1
+EOF
+
+fi
+
+echo $ac_n "checking for ${CC-cc} option to accept ANSI C""... $ac_c" 1>&6
+echo "configure:1244: checking for ${CC-cc} option to accept ANSI C" >&5
+if eval "test \"`echo '$''{'ac_cv_prog_cc_stdc'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  ac_cv_prog_cc_stdc=no
+ac_save_CFLAGS="$CFLAGS"
+# Don't try gcc -ansi; that turns off useful extensions and
+# breaks some systems' header files.
+# AIX			-qlanglvl=ansi
+# Ultrix and OSF/1	-std1
+# HP-UX			-Aa -D_HPUX_SOURCE
+# SVR4			-Xc
+for ac_arg in "" -qlanglvl=ansi -std1 "-Aa -D_HPUX_SOURCE" -Xc
+do
+  CFLAGS="$ac_save_CFLAGS $ac_arg"
+  cat > conftest.$ac_ext <<EOF
+#line 1260 "configure"
+#include "confdefs.h"
+#if !defined(__STDC__) || __STDC__ != 1
+choke me
+#endif	
+
+int main() {
+int test (int i, double x);
+struct s1 {int (*f) (int a);};
+struct s2 {int (*f) (double a);};
+; return 0; }
+EOF
+if { (eval echo configure:1272: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
+  rm -rf conftest*
+  ac_cv_prog_cc_stdc="$ac_arg"; break
+else
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+fi
+rm -f conftest*
+done
+CFLAGS="$ac_save_CFLAGS"
+
+fi
+
+echo "$ac_t""$ac_cv_prog_cc_stdc" 1>&6
+case "x$ac_cv_prog_cc_stdc" in
+  x|xno) ;;
+  *) CC="$CC $ac_cv_prog_cc_stdc" ;;
+esac
+
+
+echo $ac_n "checking for function prototypes""... $ac_c" 1>&6
+echo "configure:1293: checking for function prototypes" >&5
+if test "$ac_cv_prog_cc_stdc" != no; then
+  echo "$ac_t""yes" 1>&6
+  cat >> confdefs.h <<\EOF
+#define PROTOTYPES 1
+EOF
+
+  U= ANSI2KNR=
+else
+  echo "$ac_t""no" 1>&6
+  U=_ ANSI2KNR=ansi2knr
+fi
+
+echo $ac_n "checking for working const""... $ac_c" 1>&6
+echo "configure:1307: checking for working const" >&5
+if eval "test \"`echo '$''{'ac_cv_c_const'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  cat > conftest.$ac_ext <<EOF
+#line 1312 "configure"
+#include "confdefs.h"
+
+int main() {
+
+/* Ultrix mips cc rejects this.  */
+typedef int charset[2]; const charset x;
+/* SunOS 4.1.1 cc rejects this.  */
+char const *const *ccp;
+char **p;
+/* NEC SVR4.0.2 mips cc rejects this.  */
+struct point {int x, y;};
+static struct point const zero = {0,0};
+/* AIX XL C 1.02.0.0 rejects this.
+   It does not let you subtract one const X* pointer from another in an arm
+   of an if-expression whose if-part is not a constant expression */
+const char *g = "string";
+ccp = &g + (g ? g-g : 0);
+/* HPUX 7.0 cc rejects these. */
+++ccp;
+p = (char**) ccp;
+ccp = (char const *const *) p;
+{ /* SCO 3.2v4 cc rejects this.  */
+  char *t;
+  char const *s = 0 ? (char *) 0 : (char const *) 0;
+
+  *t++ = 0;
+}
+{ /* Someone thinks the Sun supposedly-ANSI compiler will reject this.  */
+  int x[] = {25, 17};
+  const int *foo = &x[0];
+  ++foo;
+}
+{ /* Sun SC1.0 ANSI compiler rejects this -- but not the above. */
+  typedef const int *iptr;
+  iptr p = 0;
+  ++p;
+}
+{ /* AIX XL C 1.02.0.0 rejects this saying
+     "k.c", line 2.27: 1506-025 (S) Operand must be a modifiable lvalue. */
+  struct s { int j; const int *ap[3]; };
+  struct s *b; b->j = 5;
+}
+{ /* ULTRIX-32 V3.1 (Rev 9) vcc rejects this */
+  const int foo = 10;
+}
+
+; return 0; }
+EOF
+if { (eval echo configure:1361: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
+  rm -rf conftest*
+  ac_cv_c_const=yes
+else
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -rf conftest*
+  ac_cv_c_const=no
+fi
+rm -f conftest*
+fi
+
+echo "$ac_t""$ac_cv_c_const" 1>&6
+if test $ac_cv_c_const = no; then
+  cat >> confdefs.h <<\EOF
+#define const 
+EOF
+
+fi
+
+echo $ac_n "checking for ANSI C header files""... $ac_c" 1>&6
+echo "configure:1382: checking for ANSI C header files" >&5
+if eval "test \"`echo '$''{'ac_cv_header_stdc'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  cat > conftest.$ac_ext <<EOF
+#line 1387 "configure"
+#include "confdefs.h"
+#include <stdlib.h>
+#include <stdarg.h>
+#include <string.h>
+#include <float.h>
+EOF
+ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out"
+{ (eval echo configure:1395: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }
+ac_err=`grep -v '^ *+' conftest.out`
+if test -z "$ac_err"; then
+  rm -rf conftest*
+  ac_cv_header_stdc=yes
+else
+  echo "$ac_err" >&5
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -rf conftest*
+  ac_cv_header_stdc=no
+fi
+rm -f conftest*
+
+if test $ac_cv_header_stdc = yes; then
+  # SunOS 4.x string.h does not declare mem*, contrary to ANSI.
+cat > conftest.$ac_ext <<EOF
+#line 1412 "configure"
+#include "confdefs.h"
+#include <string.h>
+EOF
+if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
+  egrep "memchr" >/dev/null 2>&1; then
+  :
+else
+  rm -rf conftest*
+  ac_cv_header_stdc=no
+fi
+rm -f conftest*
+
+fi
+
+if test $ac_cv_header_stdc = yes; then
+  # ISC 2.0.2 stdlib.h does not declare free, contrary to ANSI.
+cat > conftest.$ac_ext <<EOF
+#line 1430 "configure"
+#include "confdefs.h"
+#include <stdlib.h>
+EOF
+if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
+  egrep "free" >/dev/null 2>&1; then
+  :
+else
+  rm -rf conftest*
+  ac_cv_header_stdc=no
+fi
+rm -f conftest*
+
+fi
+
+if test $ac_cv_header_stdc = yes; then
+  # /bin/cc in Irix-4.0.5 gets non-ANSI ctype macros unless using -ansi.
+if test "$cross_compiling" = yes; then
+  :
+else
+  cat > conftest.$ac_ext <<EOF
+#line 1451 "configure"
+#include "confdefs.h"
+#include <ctype.h>
+#define ISLOWER(c) ('a' <= (c) && (c) <= 'z')
+#define TOUPPER(c) (ISLOWER(c) ? 'A' + ((c) - 'a') : (c))
+#define XOR(e, f) (((e) && !(f)) || (!(e) && (f)))
+int main () { int i; for (i = 0; i < 256; i++)
+if (XOR (islower (i), ISLOWER (i)) || toupper (i) != TOUPPER (i)) exit(2);
+exit (0); }
+
+EOF
+if { (eval echo configure:1462: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest && (./conftest; exit) 2>/dev/null
+then
+  :
+else
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -fr conftest*
+  ac_cv_header_stdc=no
+fi
+rm -fr conftest*
+fi
+
+fi
+fi
+
+echo "$ac_t""$ac_cv_header_stdc" 1>&6
+if test $ac_cv_header_stdc = yes; then
+  cat >> confdefs.h <<\EOF
+#define STDC_HEADERS 1
+EOF
+
+fi
+
+echo $ac_n "checking for off_t""... $ac_c" 1>&6
+echo "configure:1486: checking for off_t" >&5
+if eval "test \"`echo '$''{'ac_cv_type_off_t'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  cat > conftest.$ac_ext <<EOF
+#line 1491 "configure"
+#include "confdefs.h"
+#include <sys/types.h>
+#if STDC_HEADERS
+#include <stdlib.h>
+#include <stddef.h>
+#endif
+EOF
+if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
+  egrep "off_t[^a-zA-Z_0-9]" >/dev/null 2>&1; then
+  rm -rf conftest*
+  ac_cv_type_off_t=yes
+else
+  rm -rf conftest*
+  ac_cv_type_off_t=no
+fi
+rm -f conftest*
+
+fi
+echo "$ac_t""$ac_cv_type_off_t" 1>&6
+if test $ac_cv_type_off_t = no; then
+  cat >> confdefs.h <<\EOF
+#define off_t long
+EOF
+
+fi
+
+echo $ac_n "checking for size_t""... $ac_c" 1>&6
+echo "configure:1519: checking for size_t" >&5
+if eval "test \"`echo '$''{'ac_cv_type_size_t'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  cat > conftest.$ac_ext <<EOF
+#line 1524 "configure"
+#include "confdefs.h"
+#include <sys/types.h>
+#if STDC_HEADERS
+#include <stdlib.h>
+#include <stddef.h>
+#endif
+EOF
+if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
+  egrep "size_t[^a-zA-Z_0-9]" >/dev/null 2>&1; then
+  rm -rf conftest*
+  ac_cv_type_size_t=yes
+else
+  rm -rf conftest*
+  ac_cv_type_size_t=no
+fi
+rm -f conftest*
+
+fi
+echo "$ac_t""$ac_cv_type_size_t" 1>&6
+if test $ac_cv_type_size_t = no; then
+  cat >> confdefs.h <<\EOF
+#define size_t unsigned
+EOF
+
+fi
+
+echo $ac_n "checking whether time.h and sys/time.h may both be included""... $ac_c" 1>&6
+echo "configure:1552: checking whether time.h and sys/time.h may both be included" >&5
+if eval "test \"`echo '$''{'ac_cv_header_time'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  cat > conftest.$ac_ext <<EOF
+#line 1557 "configure"
+#include "confdefs.h"
+#include <sys/types.h>
+#include <sys/time.h>
+#include <time.h>
+int main() {
+struct tm *tp;
+; return 0; }
+EOF
+if { (eval echo configure:1566: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
+  rm -rf conftest*
+  ac_cv_header_time=yes
+else
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -rf conftest*
+  ac_cv_header_time=no
+fi
+rm -f conftest*
+fi
+
+echo "$ac_t""$ac_cv_header_time" 1>&6
+if test $ac_cv_header_time = yes; then
+  cat >> confdefs.h <<\EOF
+#define TIME_WITH_SYS_TIME 1
+EOF
+
+fi
+
+echo $ac_n "checking whether struct tm is in sys/time.h or time.h""... $ac_c" 1>&6
+echo "configure:1587: checking whether struct tm is in sys/time.h or time.h" >&5
+if eval "test \"`echo '$''{'ac_cv_struct_tm'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  cat > conftest.$ac_ext <<EOF
+#line 1592 "configure"
+#include "confdefs.h"
+#include <sys/types.h>
+#include <time.h>
+int main() {
+struct tm *tp; tp->tm_sec;
+; return 0; }
+EOF
+if { (eval echo configure:1600: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
+  rm -rf conftest*
+  ac_cv_struct_tm=time.h
+else
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -rf conftest*
+  ac_cv_struct_tm=sys/time.h
+fi
+rm -f conftest*
+fi
+
+echo "$ac_t""$ac_cv_struct_tm" 1>&6
+if test $ac_cv_struct_tm = sys/time.h; then
+  cat >> confdefs.h <<\EOF
+#define TM_IN_SYS_TIME 1
+EOF
+
+fi
+
+
+if test "$ac_cv_prog_cc_stdc" = '-Xc'; then
+cat > conftest.$ac_ext <<EOF
+#line 1623 "configure"
+#include "confdefs.h"
+#include <stdio.h>
+
+int main() {
+ FILE *rubbish = popen("yes", "r"); 
+; return 0; }
+EOF
+if { (eval echo configure:1631: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
+  :
+else
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -rf conftest*
+  CC="`echo $CC | sed 's/-Xc/-Xa/'`"    ac_cv_prog_cc_stdc='-Xa'
+fi
+rm -f conftest*
+fi
+
+
+echo $ac_n "checking for main in -lm""... $ac_c" 1>&6
+echo "configure:1644: checking for main in -lm" >&5
+ac_lib_var=`echo m'_'main | sed 'y%./+-%__p_%'`
+if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  ac_save_LIBS="$LIBS"
+LIBS="-lm  $LIBS"
+cat > conftest.$ac_ext <<EOF
+#line 1652 "configure"
+#include "confdefs.h"
+
+int main() {
+main()
+; return 0; }
+EOF
+if { (eval echo configure:1659: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest; then
+  rm -rf conftest*
+  eval "ac_cv_lib_$ac_lib_var=yes"
+else
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -rf conftest*
+  eval "ac_cv_lib_$ac_lib_var=no"
+fi
+rm -f conftest*
+LIBS="$ac_save_LIBS"
+
+fi
+if eval "test \"`echo '$ac_cv_lib_'$ac_lib_var`\" = yes"; then
+  echo "$ac_t""yes" 1>&6
+    ac_tr_lib=HAVE_LIB`echo m | sed -e 's/[^a-zA-Z0-9_]/_/g' \
+    -e 'y/abcdefghijklmnopqrstuvwxyz/ABCDEFGHIJKLMNOPQRSTUVWXYZ/'`
+  cat >> confdefs.h <<EOF
+#define $ac_tr_lib 1
+EOF
+
+  LIBS="-lm $LIBS"
+
+else
+  echo "$ac_t""no" 1>&6
+fi
+
+
+ac_header_dirent=no
+for ac_hdr in dirent.h sys/ndir.h sys/dir.h ndir.h
+do
+ac_safe=`echo "$ac_hdr" | sed 'y%./+-%__p_%'`
+echo $ac_n "checking for $ac_hdr that defines DIR""... $ac_c" 1>&6
+echo "configure:1692: checking for $ac_hdr that defines DIR" >&5
+if eval "test \"`echo '$''{'ac_cv_header_dirent_$ac_safe'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  cat > conftest.$ac_ext <<EOF
+#line 1697 "configure"
+#include "confdefs.h"
+#include <sys/types.h>
+#include <$ac_hdr>
+int main() {
+DIR *dirp = 0;
+; return 0; }
+EOF
+if { (eval echo configure:1705: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
+  rm -rf conftest*
+  eval "ac_cv_header_dirent_$ac_safe=yes"
+else
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -rf conftest*
+  eval "ac_cv_header_dirent_$ac_safe=no"
+fi
+rm -f conftest*
+fi
+if eval "test \"`echo '$ac_cv_header_dirent_'$ac_safe`\" = yes"; then
+  echo "$ac_t""yes" 1>&6
+    ac_tr_hdr=HAVE_`echo $ac_hdr | sed 'y%abcdefghijklmnopqrstuvwxyz./-%ABCDEFGHIJKLMNOPQRSTUVWXYZ___%'`
+  cat >> confdefs.h <<EOF
+#define $ac_tr_hdr 1
+EOF
+ ac_header_dirent=$ac_hdr; break
+else
+  echo "$ac_t""no" 1>&6
+fi
+done
+# Two versions of opendir et al. are in -ldir and -lx on SCO Xenix.
+if test $ac_header_dirent = dirent.h; then
+echo $ac_n "checking for opendir in -ldir""... $ac_c" 1>&6
+echo "configure:1730: checking for opendir in -ldir" >&5
+ac_lib_var=`echo dir'_'opendir | sed 'y%./+-%__p_%'`
+if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  ac_save_LIBS="$LIBS"
+LIBS="-ldir  $LIBS"
+cat > conftest.$ac_ext <<EOF
+#line 1738 "configure"
+#include "confdefs.h"
+/* Override any gcc2 internal prototype to avoid an error.  */
+/* We use char because int might match the return type of a gcc2
+    builtin and then its argument prototype would still apply.  */
+char opendir();
+
+int main() {
+opendir()
+; return 0; }
+EOF
+if { (eval echo configure:1749: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest; then
+  rm -rf conftest*
+  eval "ac_cv_lib_$ac_lib_var=yes"
+else
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -rf conftest*
+  eval "ac_cv_lib_$ac_lib_var=no"
+fi
+rm -f conftest*
+LIBS="$ac_save_LIBS"
+
+fi
+if eval "test \"`echo '$ac_cv_lib_'$ac_lib_var`\" = yes"; then
+  echo "$ac_t""yes" 1>&6
+  LIBS="$LIBS -ldir"
+else
+  echo "$ac_t""no" 1>&6
+fi
+
+else
+echo $ac_n "checking for opendir in -lx""... $ac_c" 1>&6
+echo "configure:1771: checking for opendir in -lx" >&5
+ac_lib_var=`echo x'_'opendir | sed 'y%./+-%__p_%'`
+if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  ac_save_LIBS="$LIBS"
+LIBS="-lx  $LIBS"
+cat > conftest.$ac_ext <<EOF
+#line 1779 "configure"
+#include "confdefs.h"
+/* Override any gcc2 internal prototype to avoid an error.  */
+/* We use char because int might match the return type of a gcc2
+    builtin and then its argument prototype would still apply.  */
+char opendir();
+
+int main() {
+opendir()
+; return 0; }
+EOF
+if { (eval echo configure:1790: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest; then
+  rm -rf conftest*
+  eval "ac_cv_lib_$ac_lib_var=yes"
+else
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -rf conftest*
+  eval "ac_cv_lib_$ac_lib_var=no"
+fi
+rm -f conftest*
+LIBS="$ac_save_LIBS"
+
+fi
+if eval "test \"`echo '$ac_cv_lib_'$ac_lib_var`\" = yes"; then
+  echo "$ac_t""yes" 1>&6
+  LIBS="$LIBS -lx"
+else
+  echo "$ac_t""no" 1>&6
+fi
+
+fi
+
+echo $ac_n "checking for ANSI C header files""... $ac_c" 1>&6
+echo "configure:1813: checking for ANSI C header files" >&5
+if eval "test \"`echo '$''{'ac_cv_header_stdc'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  cat > conftest.$ac_ext <<EOF
+#line 1818 "configure"
+#include "confdefs.h"
+#include <stdlib.h>
+#include <stdarg.h>
+#include <string.h>
+#include <float.h>
+EOF
+ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out"
+{ (eval echo configure:1826: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }
+ac_err=`grep -v '^ *+' conftest.out`
+if test -z "$ac_err"; then
+  rm -rf conftest*
+  ac_cv_header_stdc=yes
+else
+  echo "$ac_err" >&5
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -rf conftest*
+  ac_cv_header_stdc=no
+fi
+rm -f conftest*
+
+if test $ac_cv_header_stdc = yes; then
+  # SunOS 4.x string.h does not declare mem*, contrary to ANSI.
+cat > conftest.$ac_ext <<EOF
+#line 1843 "configure"
+#include "confdefs.h"
+#include <string.h>
+EOF
+if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
+  egrep "memchr" >/dev/null 2>&1; then
+  :
+else
+  rm -rf conftest*
+  ac_cv_header_stdc=no
+fi
+rm -f conftest*
+
+fi
+
+if test $ac_cv_header_stdc = yes; then
+  # ISC 2.0.2 stdlib.h does not declare free, contrary to ANSI.
+cat > conftest.$ac_ext <<EOF
+#line 1861 "configure"
+#include "confdefs.h"
+#include <stdlib.h>
+EOF
+if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
+  egrep "free" >/dev/null 2>&1; then
+  :
+else
+  rm -rf conftest*
+  ac_cv_header_stdc=no
+fi
+rm -f conftest*
+
+fi
+
+if test $ac_cv_header_stdc = yes; then
+  # /bin/cc in Irix-4.0.5 gets non-ANSI ctype macros unless using -ansi.
+if test "$cross_compiling" = yes; then
+  :
+else
+  cat > conftest.$ac_ext <<EOF
+#line 1882 "configure"
+#include "confdefs.h"
+#include <ctype.h>
+#define ISLOWER(c) ('a' <= (c) && (c) <= 'z')
+#define TOUPPER(c) (ISLOWER(c) ? 'A' + ((c) - 'a') : (c))
+#define XOR(e, f) (((e) && !(f)) || (!(e) && (f)))
+int main () { int i; for (i = 0; i < 256; i++)
+if (XOR (islower (i), ISLOWER (i)) || toupper (i) != TOUPPER (i)) exit(2);
+exit (0); }
+
+EOF
+if { (eval echo configure:1893: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest && (./conftest; exit) 2>/dev/null
+then
+  :
+else
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -fr conftest*
+  ac_cv_header_stdc=no
+fi
+rm -fr conftest*
+fi
+
+fi
+fi
+
+echo "$ac_t""$ac_cv_header_stdc" 1>&6
+if test $ac_cv_header_stdc = yes; then
+  cat >> confdefs.h <<\EOF
+#define STDC_HEADERS 1
+EOF
+
+fi
+
+for ac_hdr in fcntl.h limits.h sys/time.h unistd.h string.h memory.h sys/procfs.h
+do
+ac_safe=`echo "$ac_hdr" | sed 'y%./+-%__p_%'`
+echo $ac_n "checking for $ac_hdr""... $ac_c" 1>&6
+echo "configure:1920: checking for $ac_hdr" >&5
+if eval "test \"`echo '$''{'ac_cv_header_$ac_safe'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  cat > conftest.$ac_ext <<EOF
+#line 1925 "configure"
+#include "confdefs.h"
+#include <$ac_hdr>
+EOF
+ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out"
+{ (eval echo configure:1930: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }
+ac_err=`grep -v '^ *+' conftest.out`
+if test -z "$ac_err"; then
+  rm -rf conftest*
+  eval "ac_cv_header_$ac_safe=yes"
+else
+  echo "$ac_err" >&5
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -rf conftest*
+  eval "ac_cv_header_$ac_safe=no"
+fi
+rm -f conftest*
+fi
+if eval "test \"`echo '$ac_cv_header_'$ac_safe`\" = yes"; then
+  echo "$ac_t""yes" 1>&6
+    ac_tr_hdr=HAVE_`echo $ac_hdr | sed 'y%abcdefghijklmnopqrstuvwxyz./-%ABCDEFGHIJKLMNOPQRSTUVWXYZ___%'`
+  cat >> confdefs.h <<EOF
+#define $ac_tr_hdr 1
+EOF
+ 
+else
+  echo "$ac_t""no" 1>&6
+fi
+done
+
+cat > conftest.$ac_ext <<EOF
+#line 1957 "configure"
+#include "confdefs.h"
+#include <stdio.h>
+EOF
+if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
+  egrep "fread" >/dev/null 2>&1; then
+  rm -rf conftest*
+  cat >> confdefs.h <<\EOF
+#define HAVE_FREAD_DECL 1
+EOF
+
+fi
+rm -f conftest*
+
+cat > conftest.$ac_ext <<EOF
+#line 1972 "configure"
+#include "confdefs.h"
+#include <stdio.h>
+EOF
+if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
+  egrep "fgetc" >/dev/null 2>&1; then
+  rm -rf conftest*
+  cat >> confdefs.h <<\EOF
+#define HAVE_FGETC_DECL 1
+EOF
+
+fi
+rm -f conftest*
+
+cat > conftest.$ac_ext <<EOF
+#line 1987 "configure"
+#include "confdefs.h"
+#include <sys/procfs.h>
+EOF
+if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
+  egrep "pr_brksize" >/dev/null 2>&1; then
+  rm -rf conftest*
+  cat >> confdefs.h <<\EOF
+#define HAVE_PR_BRKSIZE 1
+EOF
+
+fi
+rm -f conftest*
+
+
+# The Ultrix 4.2 mips builtin alloca declared by alloca.h only works
+# for constant arguments.  Useless!
+echo $ac_n "checking for working alloca.h""... $ac_c" 1>&6
+echo "configure:2005: checking for working alloca.h" >&5
+if eval "test \"`echo '$''{'ac_cv_header_alloca_h'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  cat > conftest.$ac_ext <<EOF
+#line 2010 "configure"
+#include "confdefs.h"
+#include <alloca.h>
+int main() {
+char *p = alloca(2 * sizeof(int));
+; return 0; }
+EOF
+if { (eval echo configure:2017: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest; then
+  rm -rf conftest*
+  ac_cv_header_alloca_h=yes
+else
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -rf conftest*
+  ac_cv_header_alloca_h=no
+fi
+rm -f conftest*
+fi
+
+echo "$ac_t""$ac_cv_header_alloca_h" 1>&6
+if test $ac_cv_header_alloca_h = yes; then
+  cat >> confdefs.h <<\EOF
+#define HAVE_ALLOCA_H 1
+EOF
+
+fi
+
+echo $ac_n "checking for alloca""... $ac_c" 1>&6
+echo "configure:2038: checking for alloca" >&5
+if eval "test \"`echo '$''{'ac_cv_func_alloca_works'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  cat > conftest.$ac_ext <<EOF
+#line 2043 "configure"
+#include "confdefs.h"
+
+#ifdef __GNUC__
+# define alloca __builtin_alloca
+#else
+# if HAVE_ALLOCA_H
+#  include <alloca.h>
+# else
+#  ifdef _AIX
+ #pragma alloca
+#  else
+#   ifndef alloca /* predefined by HP cc +Olibcalls */
+char *alloca ();
+#   endif
+#  endif
+# endif
+#endif
+
+int main() {
+char *p = (char *) alloca(1);
+; return 0; }
+EOF
+if { (eval echo configure:2066: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest; then
+  rm -rf conftest*
+  ac_cv_func_alloca_works=yes
+else
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -rf conftest*
+  ac_cv_func_alloca_works=no
+fi
+rm -f conftest*
+fi
+
+echo "$ac_t""$ac_cv_func_alloca_works" 1>&6
+if test $ac_cv_func_alloca_works = yes; then
+  cat >> confdefs.h <<\EOF
+#define HAVE_ALLOCA 1
+EOF
+
+fi
+
+if test $ac_cv_func_alloca_works = no; then
+  # The SVR3 libPW and SVR4 libucb both contain incompatible functions
+  # that cause trouble.  Some versions do not even contain alloca or
+  # contain a buggy version.  If you still want to use their alloca,
+  # use ar to extract alloca.o from them instead of compiling alloca.c.
+  ALLOCA=alloca.o
+  cat >> confdefs.h <<\EOF
+#define C_ALLOCA 1
+EOF
+
+
+echo $ac_n "checking whether alloca needs Cray hooks""... $ac_c" 1>&6
+echo "configure:2098: checking whether alloca needs Cray hooks" >&5
+if eval "test \"`echo '$''{'ac_cv_os_cray'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  cat > conftest.$ac_ext <<EOF
+#line 2103 "configure"
+#include "confdefs.h"
+#if defined(CRAY) && ! defined(CRAY2)
+webecray
+#else
+wenotbecray
+#endif
+
+EOF
+if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
+  egrep "webecray" >/dev/null 2>&1; then
+  rm -rf conftest*
+  ac_cv_os_cray=yes
+else
+  rm -rf conftest*
+  ac_cv_os_cray=no
+fi
+rm -f conftest*
+
+fi
+
+echo "$ac_t""$ac_cv_os_cray" 1>&6
+if test $ac_cv_os_cray = yes; then
+for ac_func in _getb67 GETB67 getb67; do
+  echo $ac_n "checking for $ac_func""... $ac_c" 1>&6
+echo "configure:2128: checking for $ac_func" >&5
+if eval "test \"`echo '$''{'ac_cv_func_$ac_func'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  cat > conftest.$ac_ext <<EOF
+#line 2133 "configure"
+#include "confdefs.h"
+/* System header to define __stub macros and hopefully few prototypes,
+    which can conflict with char $ac_func(); below.  */
+#include <assert.h>
+/* Override any gcc2 internal prototype to avoid an error.  */
+/* We use char because int might match the return type of a gcc2
+    builtin and then its argument prototype would still apply.  */
+char $ac_func();
+
+int main() {
+
+/* The GNU C library defines this for functions which it implements
+    to always fail with ENOSYS.  Some functions are actually named
+    something starting with __ and the normal name is an alias.  */
+#if defined (__stub_$ac_func) || defined (__stub___$ac_func)
+choke me
+#else
+$ac_func();
+#endif
+
+; return 0; }
+EOF
+if { (eval echo configure:2156: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest; then
+  rm -rf conftest*
+  eval "ac_cv_func_$ac_func=yes"
+else
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -rf conftest*
+  eval "ac_cv_func_$ac_func=no"
+fi
+rm -f conftest*
+fi
+
+if eval "test \"`echo '$ac_cv_func_'$ac_func`\" = yes"; then
+  echo "$ac_t""yes" 1>&6
+  cat >> confdefs.h <<EOF
+#define CRAY_STACKSEG_END $ac_func
+EOF
+
+  break
+else
+  echo "$ac_t""no" 1>&6
+fi
+
+done
+fi
+
+echo $ac_n "checking stack direction for C alloca""... $ac_c" 1>&6
+echo "configure:2183: checking stack direction for C alloca" >&5
+if eval "test \"`echo '$''{'ac_cv_c_stack_direction'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  if test "$cross_compiling" = yes; then
+  ac_cv_c_stack_direction=0
+else
+  cat > conftest.$ac_ext <<EOF
+#line 2191 "configure"
+#include "confdefs.h"
+find_stack_direction ()
+{
+  static char *addr = 0;
+  auto char dummy;
+  if (addr == 0)
+    {
+      addr = &dummy;
+      return find_stack_direction ();
+    }
+  else
+    return (&dummy > addr) ? 1 : -1;
+}
+main ()
+{
+  exit (find_stack_direction() < 0);
+}
+EOF
+if { (eval echo configure:2210: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest && (./conftest; exit) 2>/dev/null
+then
+  ac_cv_c_stack_direction=1
+else
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -fr conftest*
+  ac_cv_c_stack_direction=-1
+fi
+rm -fr conftest*
+fi
+
+fi
+
+echo "$ac_t""$ac_cv_c_stack_direction" 1>&6
+cat >> confdefs.h <<EOF
+#define STACK_DIRECTION $ac_cv_c_stack_direction
+EOF
+
+fi
+
+if test $ac_cv_prog_gcc = yes; then
+    echo $ac_n "checking whether ${CC-cc} needs -traditional""... $ac_c" 1>&6
+echo "configure:2233: checking whether ${CC-cc} needs -traditional" >&5
+if eval "test \"`echo '$''{'ac_cv_prog_gcc_traditional'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+    ac_pattern="Autoconf.*'x'"
+  cat > conftest.$ac_ext <<EOF
+#line 2239 "configure"
+#include "confdefs.h"
+#include <sgtty.h>
+Autoconf TIOCGETP
+EOF
+if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
+  egrep "$ac_pattern" >/dev/null 2>&1; then
+  rm -rf conftest*
+  ac_cv_prog_gcc_traditional=yes
+else
+  rm -rf conftest*
+  ac_cv_prog_gcc_traditional=no
+fi
+rm -f conftest*
+
+
+  if test $ac_cv_prog_gcc_traditional = no; then
+    cat > conftest.$ac_ext <<EOF
+#line 2257 "configure"
+#include "confdefs.h"
+#include <termio.h>
+Autoconf TCGETA
+EOF
+if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
+  egrep "$ac_pattern" >/dev/null 2>&1; then
+  rm -rf conftest*
+  ac_cv_prog_gcc_traditional=yes
+fi
+rm -f conftest*
+
+  fi
+fi
+
+echo "$ac_t""$ac_cv_prog_gcc_traditional" 1>&6
+  if test $ac_cv_prog_gcc_traditional = yes; then
+    CC="$CC -traditional"
+  fi
+fi
+
+echo $ac_n "checking return type of signal handlers""... $ac_c" 1>&6
+echo "configure:2279: checking return type of signal handlers" >&5
+if eval "test \"`echo '$''{'ac_cv_type_signal'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  cat > conftest.$ac_ext <<EOF
+#line 2284 "configure"
+#include "confdefs.h"
+#include <sys/types.h>
+#include <signal.h>
+#ifdef signal
+#undef signal
+#endif
+#ifdef __cplusplus
+extern "C" void (*signal (int, void (*)(int)))(int);
+#else
+void (*signal ()) ();
+#endif
+
+int main() {
+int i;
+; return 0; }
+EOF
+if { (eval echo configure:2301: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
+  rm -rf conftest*
+  ac_cv_type_signal=void
+else
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -rf conftest*
+  ac_cv_type_signal=int
+fi
+rm -f conftest*
+fi
+
+echo "$ac_t""$ac_cv_type_signal" 1>&6
+cat >> confdefs.h <<EOF
+#define RETSIGTYPE $ac_cv_type_signal
+EOF
+
+
+echo $ac_n "checking for vprintf""... $ac_c" 1>&6
+echo "configure:2320: checking for vprintf" >&5
+if eval "test \"`echo '$''{'ac_cv_func_vprintf'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  cat > conftest.$ac_ext <<EOF
+#line 2325 "configure"
+#include "confdefs.h"
+/* System header to define __stub macros and hopefully few prototypes,
+    which can conflict with char vprintf(); below.  */
+#include <assert.h>
+/* Override any gcc2 internal prototype to avoid an error.  */
+/* We use char because int might match the return type of a gcc2
+    builtin and then its argument prototype would still apply.  */
+char vprintf();
+
+int main() {
+
+/* The GNU C library defines this for functions which it implements
+    to always fail with ENOSYS.  Some functions are actually named
+    something starting with __ and the normal name is an alias.  */
+#if defined (__stub_vprintf) || defined (__stub___vprintf)
+choke me
+#else
+vprintf();
+#endif
+
+; return 0; }
+EOF
+if { (eval echo configure:2348: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest; then
+  rm -rf conftest*
+  eval "ac_cv_func_vprintf=yes"
+else
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -rf conftest*
+  eval "ac_cv_func_vprintf=no"
+fi
+rm -f conftest*
+fi
+
+if eval "test \"`echo '$ac_cv_func_'vprintf`\" = yes"; then
+  echo "$ac_t""yes" 1>&6
+  cat >> confdefs.h <<\EOF
+#define HAVE_VPRINTF 1
+EOF
+
+else
+  echo "$ac_t""no" 1>&6
+fi
+
+if test "$ac_cv_func_vprintf" != yes; then
+echo $ac_n "checking for _doprnt""... $ac_c" 1>&6
+echo "configure:2372: checking for _doprnt" >&5
+if eval "test \"`echo '$''{'ac_cv_func__doprnt'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  cat > conftest.$ac_ext <<EOF
+#line 2377 "configure"
+#include "confdefs.h"
+/* System header to define __stub macros and hopefully few prototypes,
+    which can conflict with char _doprnt(); below.  */
+#include <assert.h>
+/* Override any gcc2 internal prototype to avoid an error.  */
+/* We use char because int might match the return type of a gcc2
+    builtin and then its argument prototype would still apply.  */
+char _doprnt();
+
+int main() {
+
+/* The GNU C library defines this for functions which it implements
+    to always fail with ENOSYS.  Some functions are actually named
+    something starting with __ and the normal name is an alias.  */
+#if defined (__stub__doprnt) || defined (__stub____doprnt)
+choke me
+#else
+_doprnt();
+#endif
+
+; return 0; }
+EOF
+if { (eval echo configure:2400: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest; then
+  rm -rf conftest*
+  eval "ac_cv_func__doprnt=yes"
+else
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -rf conftest*
+  eval "ac_cv_func__doprnt=no"
+fi
+rm -f conftest*
+fi
+
+if eval "test \"`echo '$ac_cv_func_'_doprnt`\" = yes"; then
+  echo "$ac_t""yes" 1>&6
+  cat >> confdefs.h <<\EOF
+#define HAVE_DOPRNT 1
+EOF
+
+else
+  echo "$ac_t""no" 1>&6
+fi
+
+fi
+
+for ac_func in ftime select strftime strtol getrusage times mallinfo setbuffer getpagesize
+do
+echo $ac_n "checking for $ac_func""... $ac_c" 1>&6
+echo "configure:2427: checking for $ac_func" >&5
+if eval "test \"`echo '$''{'ac_cv_func_$ac_func'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  cat > conftest.$ac_ext <<EOF
+#line 2432 "configure"
+#include "confdefs.h"
+/* System header to define __stub macros and hopefully few prototypes,
+    which can conflict with char $ac_func(); below.  */
+#include <assert.h>
+/* Override any gcc2 internal prototype to avoid an error.  */
+/* We use char because int might match the return type of a gcc2
+    builtin and then its argument prototype would still apply.  */
+char $ac_func();
+
+int main() {
+
+/* The GNU C library defines this for functions which it implements
+    to always fail with ENOSYS.  Some functions are actually named
+    something starting with __ and the normal name is an alias.  */
+#if defined (__stub_$ac_func) || defined (__stub___$ac_func)
+choke me
+#else
+$ac_func();
+#endif
+
+; return 0; }
+EOF
+if { (eval echo configure:2455: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest; then
+  rm -rf conftest*
+  eval "ac_cv_func_$ac_func=yes"
+else
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -rf conftest*
+  eval "ac_cv_func_$ac_func=no"
+fi
+rm -f conftest*
+fi
+
+if eval "test \"`echo '$ac_cv_func_'$ac_func`\" = yes"; then
+  echo "$ac_t""yes" 1>&6
+    ac_tr_func=HAVE_`echo $ac_func | tr 'abcdefghijklmnopqrstuvwxyz' 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'`
+  cat >> confdefs.h <<EOF
+#define $ac_tr_func 1
+EOF
+ 
+else
+  echo "$ac_t""no" 1>&6
+fi
+done
+
+for ac_func in ftruncate strstr strcasecmp
+do
+echo $ac_n "checking for $ac_func""... $ac_c" 1>&6
+echo "configure:2482: checking for $ac_func" >&5
+if eval "test \"`echo '$''{'ac_cv_func_$ac_func'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  cat > conftest.$ac_ext <<EOF
+#line 2487 "configure"
+#include "confdefs.h"
+/* System header to define __stub macros and hopefully few prototypes,
+    which can conflict with char $ac_func(); below.  */
+#include <assert.h>
+/* Override any gcc2 internal prototype to avoid an error.  */
+/* We use char because int might match the return type of a gcc2
+    builtin and then its argument prototype would still apply.  */
+char $ac_func();
+
+int main() {
+
+/* The GNU C library defines this for functions which it implements
+    to always fail with ENOSYS.  Some functions are actually named
+    something starting with __ and the normal name is an alias.  */
+#if defined (__stub_$ac_func) || defined (__stub___$ac_func)
+choke me
+#else
+$ac_func();
+#endif
+
+; return 0; }
+EOF
+if { (eval echo configure:2510: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest; then
+  rm -rf conftest*
+  eval "ac_cv_func_$ac_func=yes"
+else
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -rf conftest*
+  eval "ac_cv_func_$ac_func=no"
+fi
+rm -f conftest*
+fi
+
+if eval "test \"`echo '$ac_cv_func_'$ac_func`\" = yes"; then
+  echo "$ac_t""yes" 1>&6
+    ac_tr_func=HAVE_`echo $ac_func | tr 'abcdefghijklmnopqrstuvwxyz' 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'`
+  cat >> confdefs.h <<EOF
+#define $ac_tr_func 1
+EOF
+ 
+else
+  echo "$ac_t""no" 1>&6
+LIBOBJS="$LIBOBJS ${ac_func}.o"
+fi
+done
+
+
+
+
+# *** Custom checking (based on GNU tar configure.in) ***
+# ---------------------------------------------------------------------------
+echo $ac_n "checking for HP-UX needing gmalloc""... $ac_c" 1>&6
+echo "configure:2541: checking for HP-UX needing gmalloc" >&5
+if test "`(uname -s) 2> /dev/null`" = 'HP-UX'; then
+  echo "$ac_t""yes" 1>&6
+  LIBOBJS="$LIBOBJS gmalloc.o"
+  cat >> confdefs.h <<\EOF
+#define HAVE_VALLOC 1
+EOF
+
+else
+  echo "$ac_t""no" 1>&6
+  for ac_func in valloc
+do
+echo $ac_n "checking for $ac_func""... $ac_c" 1>&6
+echo "configure:2554: checking for $ac_func" >&5
+if eval "test \"`echo '$''{'ac_cv_func_$ac_func'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  cat > conftest.$ac_ext <<EOF
+#line 2559 "configure"
+#include "confdefs.h"
+/* System header to define __stub macros and hopefully few prototypes,
+    which can conflict with char $ac_func(); below.  */
+#include <assert.h>
+/* Override any gcc2 internal prototype to avoid an error.  */
+/* We use char because int might match the return type of a gcc2
+    builtin and then its argument prototype would still apply.  */
+char $ac_func();
+
+int main() {
+
+/* The GNU C library defines this for functions which it implements
+    to always fail with ENOSYS.  Some functions are actually named
+    something starting with __ and the normal name is an alias.  */
+#if defined (__stub_$ac_func) || defined (__stub___$ac_func)
+choke me
+#else
+$ac_func();
+#endif
+
+; return 0; }
+EOF
+if { (eval echo configure:2582: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest; then
+  rm -rf conftest*
+  eval "ac_cv_func_$ac_func=yes"
+else
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -rf conftest*
+  eval "ac_cv_func_$ac_func=no"
+fi
+rm -f conftest*
+fi
+
+if eval "test \"`echo '$ac_cv_func_'$ac_func`\" = yes"; then
+  echo "$ac_t""yes" 1>&6
+    ac_tr_func=HAVE_`echo $ac_func | tr 'abcdefghijklmnopqrstuvwxyz' 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'`
+  cat >> confdefs.h <<EOF
+#define $ac_tr_func 1
+EOF
+ 
+else
+  echo "$ac_t""no" 1>&6
+fi
+done
+
+fi
+
+echo $ac_n "checking if malloc debugging is wanted""... $ac_c" 1>&6
+echo "configure:2609: checking if malloc debugging is wanted" >&5
+# Check whether --with-dmalloc or --without-dmalloc was given.
+if test "${with_dmalloc+set}" = set; then
+  withval="$with_dmalloc"
+  if test "$withval" = yes; then
+  echo "$ac_t""yes" 1>&6
+  cat >> confdefs.h <<\EOF
+#define WITH_DMALLOC 1
+EOF
+
+  LIBS="$LIBS -ldmalloc"
+  LDFLAGS="$LDFLAGS -g"
+else
+  echo "$ac_t""no" 1>&6
+fi
+else
+  echo "$ac_t""no" 1>&6
+fi
+
+
+echo $ac_n "checking which of rx or regex is wanted""... $ac_c" 1>&6
+echo "configure:2630: checking which of rx or regex is wanted" >&5
+# Check whether --with-regex or --without-regex was given.
+if test "${with_regex+set}" = set; then
+  withval="$with_regex"
+  if test "$withval" = yes; then
+  ac_with_regex=1
+  echo "$ac_t""regex" 1>&6
+  cat >> confdefs.h <<\EOF
+#define WITH_REGEX 1
+EOF
+
+  LIBOBJS="$LIBOBJS regex.o"
+fi
+fi
+
+if test -z "$ac_with_regex"; then
+  echo "$ac_t""rx" 1>&6
+  echo $ac_n "checking for re_rx_search""... $ac_c" 1>&6
+echo "configure:2648: checking for re_rx_search" >&5
+if eval "test \"`echo '$''{'ac_cv_func_re_rx_search'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  cat > conftest.$ac_ext <<EOF
+#line 2653 "configure"
+#include "confdefs.h"
+/* System header to define __stub macros and hopefully few prototypes,
+    which can conflict with char re_rx_search(); below.  */
+#include <assert.h>
+/* Override any gcc2 internal prototype to avoid an error.  */
+/* We use char because int might match the return type of a gcc2
+    builtin and then its argument prototype would still apply.  */
+char re_rx_search();
+
+int main() {
+
+/* The GNU C library defines this for functions which it implements
+    to always fail with ENOSYS.  Some functions are actually named
+    something starting with __ and the normal name is an alias.  */
+#if defined (__stub_re_rx_search) || defined (__stub___re_rx_search)
+choke me
+#else
+re_rx_search();
+#endif
+
+; return 0; }
+EOF
+if { (eval echo configure:2676: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest; then
+  rm -rf conftest*
+  eval "ac_cv_func_re_rx_search=yes"
+else
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -rf conftest*
+  eval "ac_cv_func_re_rx_search=no"
+fi
+rm -f conftest*
+fi
+
+if eval "test \"`echo '$ac_cv_func_'re_rx_search`\" = yes"; then
+  echo "$ac_t""yes" 1>&6
+  :
+else
+  echo "$ac_t""no" 1>&6
+LIBOBJS="$LIBOBJS rx.o"
+fi
+
+fi
+
+
+# ---------------------------------------------------------------------------
+if test "$ac_cv_func_alloca" = 'no'; then
+  LIBOBJS="$LIBOBJS xmalloc.o error.o"
+fi
+
+
+# ---------------------------------------------------------------------------
+
+trap '' 1 2 15
+cat > confcache <<\EOF
+# This file is a shell script that caches the results of configure
+# tests run on this system so they can be shared between configure
+# scripts and configure runs.  It is not useful on other systems.
+# If it contains results you don't want to keep, you may remove or edit it.
+#
+# By default, configure uses ./config.cache as the cache file,
+# creating it if it does not exist already.  You can give configure
+# the --cache-file=FILE option to use a different cache file; that is
+# what configure does when it calls configure scripts in
+# subdirectories, so they share the cache.
+# Giving --cache-file=/dev/null disables caching, for debugging configure.
+# config.status only pays attention to the cache file if you give it the
+# --recheck option to rerun configure.
+#
+EOF
+# The following way of writing the cache mishandles newlines in values,
+# but we know of no workaround that is simple, portable, and efficient.
+# So, don't put newlines in cache variables' values.
+# Ultrix sh set writes to stderr and can't be redirected directly,
+# and sets the high bit in the cache file unless we assign to the vars.
+(set) 2>&1 |
+  case `(ac_space=' '; set) 2>&1` in
+  *ac_space=\ *)
+    # `set' does not quote correctly, so add quotes (double-quote substitution
+    # turns \\\\ into \\, and sed turns \\ into \).
+    sed -n \
+      -e "s/'/'\\\\''/g" \
+      -e "s/^\\([a-zA-Z0-9_]*_cv_[a-zA-Z0-9_]*\\)=\\(.*\\)/\\1=\${\\1='\\2'}/p"
+    ;;
+  *)
+    # `set' quotes correctly as required by POSIX, so do not add quotes.
+    sed -n -e 's/^\([a-zA-Z0-9_]*_cv_[a-zA-Z0-9_]*\)=\(.*\)/\1=${\1=\2}/p'
+    ;;
+  esac >> confcache
+if cmp -s $cache_file confcache; then
+  :
+else
+  if test -w $cache_file; then
+    echo "updating cache $cache_file"
+    cat confcache > $cache_file
+  else
+    echo "not updating unwritable cache $cache_file"
+  fi
+fi
+rm -f confcache
+
+trap 'rm -fr conftest* confdefs* core core.* *.core $ac_clean_files; exit 1' 1 2 15
+
+test "x$prefix" = xNONE && prefix=$ac_default_prefix
+# Let make expand exec_prefix.
+test "x$exec_prefix" = xNONE && exec_prefix='${prefix}'
+
+# Any assignment to VPATH causes Sun make to only execute
+# the first set of double-colon rules, so remove it if not needed.
+# If there is a colon in the path, we need to keep it.
+if test "x$srcdir" = x.; then
+  ac_vpsub='/^[ 	]*VPATH[ 	]*=[^:]*$/d'
+fi
+
+trap 'rm -f $CONFIG_STATUS conftest*; exit 1' 1 2 15
+
+DEFS=-DHAVE_CONFIG_H
+
+# Without the "./", some shells look in PATH for config.status.
+: ${CONFIG_STATUS=./config.status}
+
+echo creating $CONFIG_STATUS
+rm -f $CONFIG_STATUS
+cat > $CONFIG_STATUS <<EOF
+#! /bin/sh
+# Generated automatically by configure.
+# Run this file to recreate the current configuration.
+# This directory was configured as follows,
+# on host `(hostname || uname -n) 2>/dev/null | sed 1q`:
+#
+# $0 $ac_configure_args
+#
+# Compiler output produced by configure, useful for debugging
+# configure, is in ./config.log if it exists.
+
+ac_cs_usage="Usage: $CONFIG_STATUS [--recheck] [--version] [--help]"
+for ac_option
+do
+  case "\$ac_option" in
+  -recheck | --recheck | --rechec | --reche | --rech | --rec | --re | --r)
+    echo "running \${CONFIG_SHELL-/bin/sh} $0 $ac_configure_args --no-create --no-recursion"
+    exec \${CONFIG_SHELL-/bin/sh} $0 $ac_configure_args --no-create --no-recursion ;;
+  -version | --version | --versio | --versi | --vers | --ver | --ve | --v)
+    echo "$CONFIG_STATUS generated by autoconf version 2.12"
+    exit 0 ;;
+  -help | --help | --hel | --he | --h)
+    echo "\$ac_cs_usage"; exit 0 ;;
+  *) echo "\$ac_cs_usage"; exit 1 ;;
+  esac
+done
+
+ac_given_srcdir=$srcdir
+ac_given_INSTALL="$INSTALL"
+
+trap 'rm -fr `echo "Makefile src/text/Makefile src/images/Makefile 
+          src/scripts/Makefile lib/Makefile  config.h" | sed "s/:[^ ]*//g"` conftest*; exit 1' 1 2 15
+EOF
+cat >> $CONFIG_STATUS <<EOF
+
+# Protect against being on the right side of a sed subst in config.status.
+sed 's/%@/@@/; s/@%/@@/; s/%g\$/@g/; /@g\$/s/[\\\\&%]/\\\\&/g;
+ s/@@/%@/; s/@@/@%/; s/@g\$/%g/' > conftest.subs <<\\CEOF
+$ac_vpsub
+$extrasub
+s%@CFLAGS@%$CFLAGS%g
+s%@CPPFLAGS@%$CPPFLAGS%g
+s%@CXXFLAGS@%$CXXFLAGS%g
+s%@DEFS@%$DEFS%g
+s%@LDFLAGS@%$LDFLAGS%g
+s%@LIBS@%$LIBS%g
+s%@exec_prefix@%$exec_prefix%g
+s%@prefix@%$prefix%g
+s%@program_transform_name@%$program_transform_name%g
+s%@bindir@%$bindir%g
+s%@sbindir@%$sbindir%g
+s%@libexecdir@%$libexecdir%g
+s%@datadir@%$datadir%g
+s%@sysconfdir@%$sysconfdir%g
+s%@sharedstatedir@%$sharedstatedir%g
+s%@localstatedir@%$localstatedir%g
+s%@libdir@%$libdir%g
+s%@includedir@%$includedir%g
+s%@oldincludedir@%$oldincludedir%g
+s%@infodir@%$infodir%g
+s%@mandir@%$mandir%g
+s%@PACKAGE@%$PACKAGE%g
+s%@VERSION@%$VERSION%g
+s%@CXX@%$CXX%g
+s%@AWK@%$AWK%g
+s%@YACC@%$YACC%g
+s%@CC@%$CC%g
+s%@INSTALL_PROGRAM@%$INSTALL_PROGRAM%g
+s%@INSTALL_DATA@%$INSTALL_DATA%g
+s%@LN_S@%$LN_S%g
+s%@SET_MAKE@%$SET_MAKE%g
+s%@RANLIB@%$RANLIB%g
+s%@CPP@%$CPP%g
+s%@U@%$U%g
+s%@ANSI2KNR@%$ANSI2KNR%g
+s%@ALLOCA@%$ALLOCA%g
+s%@LIBOBJS@%$LIBOBJS%g
+
+CEOF
+EOF
+
+cat >> $CONFIG_STATUS <<\EOF
+
+# Split the substitutions into bite-sized pieces for seds with
+# small command number limits, like on Digital OSF/1 and HP-UX.
+ac_max_sed_cmds=90 # Maximum number of lines to put in a sed script.
+ac_file=1 # Number of current file.
+ac_beg=1 # First line for current file.
+ac_end=$ac_max_sed_cmds # Line after last line for current file.
+ac_more_lines=:
+ac_sed_cmds=""
+while $ac_more_lines; do
+  if test $ac_beg -gt 1; then
+    sed "1,${ac_beg}d; ${ac_end}q" conftest.subs > conftest.s$ac_file
+  else
+    sed "${ac_end}q" conftest.subs > conftest.s$ac_file
+  fi
+  if test ! -s conftest.s$ac_file; then
+    ac_more_lines=false
+    rm -f conftest.s$ac_file
+  else
+    if test -z "$ac_sed_cmds"; then
+      ac_sed_cmds="sed -f conftest.s$ac_file"
+    else
+      ac_sed_cmds="$ac_sed_cmds | sed -f conftest.s$ac_file"
+    fi
+    ac_file=`expr $ac_file + 1`
+    ac_beg=$ac_end
+    ac_end=`expr $ac_end + $ac_max_sed_cmds`
+  fi
+done
+if test -z "$ac_sed_cmds"; then
+  ac_sed_cmds=cat
+fi
+EOF
+
+cat >> $CONFIG_STATUS <<EOF
+
+CONFIG_FILES=\${CONFIG_FILES-"Makefile src/text/Makefile src/images/Makefile 
+          src/scripts/Makefile lib/Makefile "}
+EOF
+cat >> $CONFIG_STATUS <<\EOF
+for ac_file in .. $CONFIG_FILES; do if test "x$ac_file" != x..; then
+  # Support "outfile[:infile[:infile...]]", defaulting infile="outfile.in".
+  case "$ac_file" in
+  *:*) ac_file_in=`echo "$ac_file"|sed 's%[^:]*:%%'`
+       ac_file=`echo "$ac_file"|sed 's%:.*%%'` ;;
+  *) ac_file_in="${ac_file}.in" ;;
+  esac
+
+  # Adjust a relative srcdir, top_srcdir, and INSTALL for subdirectories.
+
+  # Remove last slash and all that follows it.  Not all systems have dirname.
+  ac_dir=`echo $ac_file|sed 's%/[^/][^/]*$%%'`
+  if test "$ac_dir" != "$ac_file" && test "$ac_dir" != .; then
+    # The file is in a subdirectory.
+    test ! -d "$ac_dir" && mkdir "$ac_dir"
+    ac_dir_suffix="/`echo $ac_dir|sed 's%^\./%%'`"
+    # A "../" for each directory in $ac_dir_suffix.
+    ac_dots=`echo $ac_dir_suffix|sed 's%/[^/]*%../%g'`
+  else
+    ac_dir_suffix= ac_dots=
+  fi
+
+  case "$ac_given_srcdir" in
+  .)  srcdir=.
+      if test -z "$ac_dots"; then top_srcdir=.
+      else top_srcdir=`echo $ac_dots|sed 's%/$%%'`; fi ;;
+  /*) srcdir="$ac_given_srcdir$ac_dir_suffix"; top_srcdir="$ac_given_srcdir" ;;
+  *) # Relative path.
+    srcdir="$ac_dots$ac_given_srcdir$ac_dir_suffix"
+    top_srcdir="$ac_dots$ac_given_srcdir" ;;
+  esac
+
+  case "$ac_given_INSTALL" in
+  [/$]*) INSTALL="$ac_given_INSTALL" ;;
+  *) INSTALL="$ac_dots$ac_given_INSTALL" ;;
+  esac
+
+  echo creating "$ac_file"
+  rm -f "$ac_file"
+  configure_input="Generated automatically from `echo $ac_file_in|sed 's%.*/%%'` by configure."
+  case "$ac_file" in
+  *Makefile*) ac_comsub="1i\\
+# $configure_input" ;;
+  *) ac_comsub= ;;
+  esac
+
+  ac_file_inputs=`echo $ac_file_in|sed -e "s%^%$ac_given_srcdir/%" -e "s%:% $ac_given_srcdir/%g"`
+  sed -e "$ac_comsub
+s%@configure_input@%$configure_input%g
+s%@srcdir@%$srcdir%g
+s%@top_srcdir@%$top_srcdir%g
+s%@INSTALL@%$INSTALL%g
+" $ac_file_inputs | (eval "$ac_sed_cmds") > $ac_file
+fi; done
+rm -f conftest.s*
+
+# These sed commands are passed to sed as "A NAME B NAME C VALUE D", where
+# NAME is the cpp macro being defined and VALUE is the value it is being given.
+#
+# ac_d sets the value in "#define NAME VALUE" lines.
+ac_dA='s%^\([ 	]*\)#\([ 	]*define[ 	][ 	]*\)'
+ac_dB='\([ 	][ 	]*\)[^ 	]*%\1#\2'
+ac_dC='\3'
+ac_dD='%g'
+# ac_u turns "#undef NAME" with trailing blanks into "#define NAME VALUE".
+ac_uA='s%^\([ 	]*\)#\([ 	]*\)undef\([ 	][ 	]*\)'
+ac_uB='\([ 	]\)%\1#\2define\3'
+ac_uC=' '
+ac_uD='\4%g'
+# ac_e turns "#undef NAME" without trailing blanks into "#define NAME VALUE".
+ac_eA='s%^\([ 	]*\)#\([ 	]*\)undef\([ 	][ 	]*\)'
+ac_eB='$%\1#\2define\3'
+ac_eC=' '
+ac_eD='%g'
+
+if test "${CONFIG_HEADERS+set}" != set; then
+EOF
+cat >> $CONFIG_STATUS <<EOF
+  CONFIG_HEADERS="config.h"
+EOF
+cat >> $CONFIG_STATUS <<\EOF
+fi
+for ac_file in .. $CONFIG_HEADERS; do if test "x$ac_file" != x..; then
+  # Support "outfile[:infile[:infile...]]", defaulting infile="outfile.in".
+  case "$ac_file" in
+  *:*) ac_file_in=`echo "$ac_file"|sed 's%[^:]*:%%'`
+       ac_file=`echo "$ac_file"|sed 's%:.*%%'` ;;
+  *) ac_file_in="${ac_file}.in" ;;
+  esac
+
+  echo creating $ac_file
+
+  rm -f conftest.frag conftest.in conftest.out
+  ac_file_inputs=`echo $ac_file_in|sed -e "s%^%$ac_given_srcdir/%" -e "s%:% $ac_given_srcdir/%g"`
+  cat $ac_file_inputs > conftest.in
+
+EOF
+
+# Transform confdefs.h into a sed script conftest.vals that substitutes
+# the proper values into config.h.in to produce config.h.  And first:
+# Protect against being on the right side of a sed subst in config.status.
+# Protect against being in an unquoted here document in config.status.
+rm -f conftest.vals
+cat > conftest.hdr <<\EOF
+s/[\\&%]/\\&/g
+s%[\\$`]%\\&%g
+s%#define \([A-Za-z_][A-Za-z0-9_]*\) *\(.*\)%${ac_dA}\1${ac_dB}\1${ac_dC}\2${ac_dD}%gp
+s%ac_d%ac_u%gp
+s%ac_u%ac_e%gp
+EOF
+sed -n -f conftest.hdr confdefs.h > conftest.vals
+rm -f conftest.hdr
+
+# This sed command replaces #undef with comments.  This is necessary, for
+# example, in the case of _POSIX_SOURCE, which is predefined and required
+# on some systems where configure will not decide to define it.
+cat >> conftest.vals <<\EOF
+s%^[ 	]*#[ 	]*undef[ 	][ 	]*[a-zA-Z_][a-zA-Z_0-9]*%/* & */%
+EOF
+
+# Break up conftest.vals because some shells have a limit on
+# the size of here documents, and old seds have small limits too.
+
+rm -f conftest.tail
+while :
+do
+  ac_lines=`grep -c . conftest.vals`
+  # grep -c gives empty output for an empty file on some AIX systems.
+  if test -z "$ac_lines" || test "$ac_lines" -eq 0; then break; fi
+  # Write a limited-size here document to conftest.frag.
+  echo '  cat > conftest.frag <<CEOF' >> $CONFIG_STATUS
+  sed ${ac_max_here_lines}q conftest.vals >> $CONFIG_STATUS
+  echo 'CEOF
+  sed -f conftest.frag conftest.in > conftest.out
+  rm -f conftest.in
+  mv conftest.out conftest.in
+' >> $CONFIG_STATUS
+  sed 1,${ac_max_here_lines}d conftest.vals > conftest.tail
+  rm -f conftest.vals
+  mv conftest.tail conftest.vals
+done
+rm -f conftest.vals
+
+cat >> $CONFIG_STATUS <<\EOF
+  rm -f conftest.frag conftest.h
+  echo "/* $ac_file.  Generated automatically by configure.  */" > conftest.h
+  cat conftest.in >> conftest.h
+  rm -f conftest.in
+  if cmp -s $ac_file conftest.h 2>/dev/null; then
+    echo "$ac_file is unchanged"
+    rm -f conftest.h
+  else
+    # Remove last slash and all that follows it.  Not all systems have dirname.
+      ac_dir=`echo $ac_file|sed 's%/[^/][^/]*$%%'`
+      if test "$ac_dir" != "$ac_file" && test "$ac_dir" != .; then
+      # The file is in a subdirectory.
+      test ! -d "$ac_dir" && mkdir "$ac_dir"
+    fi
+    rm -f $ac_file
+    mv conftest.h $ac_file
+  fi
+fi; done
+
+EOF
+cat >> $CONFIG_STATUS <<EOF
+
+EOF
+cat >> $CONFIG_STATUS <<\EOF
+test -z "$CONFIG_HEADERS" || echo timestamp > stamp-h
+exit 0
+EOF
+chmod +x $CONFIG_STATUS
+rm -fr confdefs* $ac_clean_files
+test "$no_create" = yes || ${CONFIG_SHELL-/bin/sh} $CONFIG_STATUS || exit 1
+
Index: /main/tags/2.25/gsdl/packages/mg/configure.in
===================================================================
--- /main/tags/2.25/gsdl/packages/mg/configure.in	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/mg/configure.in	(revision 21064)
@@ -0,0 +1,98 @@
+dnl Process this file with autoconf to produce a configure script.
+AC_INIT(src/text/mgquery.c)
+AC_CONFIG_HEADER(config.h)
+AC_ARG_PROGRAM
+
+dnl
+PACKAGE=mg
+VERSION=1.2
+
+AC_DEFINE_UNQUOTED(PACKAGE, "$PACKAGE")
+AC_DEFINE_UNQUOTED(VERSION, "$VERSION")
+AC_SUBST(PACKAGE)
+AC_SUBST(VERSION)
+
+dnl Checks for programs.
+AC_PROG_CXX
+AC_PROG_AWK
+AC_PROG_YACC
+AC_PROG_CC
+AC_PROG_INSTALL
+AC_PROG_LN_S
+AC_PROG_MAKE_SET
+AC_PROG_RANLIB
+
+dnl Checks for typedefs, structures, and compiler characteristics.
+AC_AIX
+AC_ISC_POSIX
+AC_MINIX
+fp_C_PROTOTYPES
+AC_C_CONST
+AC_TYPE_OFF_T
+AC_TYPE_SIZE_T
+AC_HEADER_TIME
+AC_STRUCT_TM
+
+dnl --- This should be in the stdc checking -----------------
+if test "$ac_cv_prog_cc_stdc" = '-Xc'; then
+dnl The Pyramids running SMP_DC.OSx on MIPS r3000 chips with
+dnl /usr/opt/cc3.11/bin/cc treat -Xc as full ANSI mode - no POSIX or
+dnl XOPEN extensions (like popen).
+dnl Unfortunately -D_{XOPEN,POSIX}_SOURCE can't provide all that mg
+dnl needs. So drop back to -Xa
+AC_TRY_COMPILE(
+[#include <stdio.h>
+], [ FILE *rubbish = popen("yes", "r"); ],,
+[CC="`echo $CC | sed 's/-Xc/-Xa/'`"    ac_cv_prog_cc_stdc='-Xa'])
+fi
+dnl ----------------------
+
+
+dnl Checks for libraries.
+dnl Replace `main' with a function in -lm:
+AC_CHECK_LIB(m, main)
+
+dnl Checks for header files.
+AC_HEADER_DIRENT
+AC_HEADER_STDC
+AC_CHECK_HEADERS(fcntl.h limits.h sys/time.h unistd.h string.h memory.h sys/procfs.h)
+AC_EGREP_HEADER(fread, stdio.h, AC_DEFINE(HAVE_FREAD_DECL))
+AC_EGREP_HEADER(fgetc, stdio.h, AC_DEFINE(HAVE_FGETC_DECL))
+AC_EGREP_HEADER(pr_brksize, sys/procfs.h, AC_DEFINE(HAVE_PR_BRKSIZE))
+
+dnl Checks for library functions.
+AC_FUNC_ALLOCA
+AC_PROG_GCC_TRADITIONAL
+AC_TYPE_SIGNAL
+AC_FUNC_VPRINTF
+AC_CHECK_FUNCS(ftime select strftime strtol getrusage times mallinfo setbuffer getpagesize)
+AC_REPLACE_FUNCS(ftruncate strstr strcasecmp)
+
+
+# *** Custom checking (based on GNU tar configure.in) ***
+# ---------------------------------------------------------------------------
+AC_MSG_CHECKING(for HP-UX needing gmalloc)
+if test "`(uname -s) 2> /dev/null`" = 'HP-UX'; then
+  AC_MSG_RESULT(yes)
+  LIBOBJS="$LIBOBJS gmalloc.o"
+  AC_DEFINE(HAVE_VALLOC)
+else
+  AC_MSG_RESULT(no)
+  AC_CHECK_FUNCS(valloc)
+fi
+
+fp_WITH_DMALLOC
+fp_WITH_REGEX
+
+# ---------------------------------------------------------------------------
+if test "$ac_cv_func_alloca" = 'no'; then
+dnl    support functions for alloca.c
+  LIBOBJS="$LIBOBJS xmalloc.o error.o"
+fi
+
+
+# ---------------------------------------------------------------------------
+
+AC_OUTPUT([Makefile src/text/Makefile src/images/Makefile 
+          src/scripts/Makefile lib/Makefile ], 
+[test -z "$CONFIG_HEADERS" || echo timestamp > stamp-h])
Index: /main/tags/2.25/gsdl/packages/mg/docs/Makefile
===================================================================
--- /main/tags/2.25/gsdl/packages/mg/docs/Makefile	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/mg/docs/Makefile	(revision 21064)
@@ -0,0 +1,5 @@
+DISTFILES = Makefile mgmerge.README mg_invf_dump.changes \
+  README.man mg.1 mgintro.1 mgintro++.1
+
+dist:
+	ln $(DISTFILES) $(distdir)
Index: /main/tags/2.25/gsdl/packages/mg/docs/README.man
===================================================================
--- /main/tags/2.25/gsdl/packages/mg/docs/README.man	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/mg/docs/README.man	(revision 21064)
@@ -0,0 +1,1 @@
+The rest of the man files are in the respective src directories.
Index: /main/tags/2.25/gsdl/packages/mg/docs/mg.1
===================================================================
--- /main/tags/2.25/gsdl/packages/mg/docs/mg.1	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/mg/docs/mg.1	(revision 21064)
@@ -0,0 +1,462 @@
+.\"------------------------------------------------------------
+.\" Id - set Rv,revision, and Dt, Date using rcs-Id tag.
+.de Id
+.ds Rv \\$3
+.ds Dt \\$4
+..
+.Id $Id$
+.\"------------------------------------------------------------
+.TH mg 1 \*(Dt CITRI
+.\"=====================================================================
+.\" Author:
+.\"     Nelson H. F. Beebe
+.\"     Center for Scientific Computing
+.\"     Department of Mathematics
+.\"     University of Utah
+.\"     Salt Lake City, UT 84112
+.\"     USA
+.\"     Email: beebe@math.utah.edu (Internet)
+.\"=====================================================================
+.if t .ds Bi B\s-2IB\s+2T\\h'-0.1667m'\\v'0.20v'E\\v'-0.20v'\\h'-0.125m'X
+.if n .ds Bi BibTeX
+.if t .ds Te T\\h'-0.1667m'\\v'0.20v'E\\v'-0.20v'\\h'-0.125m'X
+.if n .ds Te TeX
+.\"=====================================================================
+.SH NAME
+mg \- full-text inverted index support
+.\"=====================================================================
+.SH DESCRIPTION
+.B mg
+is a suite of programs that can be used to create
+and query full-text inverted indexes for a
+collection of documents.
+.PP
+An inverted index is essentially a list of
+pointers to occurrences of every word in a
+collection of documents, so that, for example, in
+a collection of Shakespeare's works, one can pose
+questions like
+.I "How often is a fool mentioned in the plays?"
+and
+.I "Are Romeo and Juliet ever mentioned in the same sentence?"
+While search utilities like the UNIX
+.BR grep (1)
+family can be used for simple queries, they suffer
+from several limitations:
+.TP \w'\(bu'u+2n
+\(bu
+Each invocation requires a separate pass over the
+documents, which becomes impossibly slow if the
+document collection is very large.
+.TP
+\(bu
+It is difficult to compose Boolean queries like
+.IR "Caesar AND Brutus AND NOT Antony" .
+.TP
+\(bu
+They provide no mechanism for ranking matches
+according to importance, which is extremely
+important when queries are complex and numerous
+matches are found.
+.TP
+\(bu
+They provide no mechanism for displaying
+surrounding context (although the Free Software
+Foundation
+implementations for the GNU Project remedy this
+with their
+.BI \-A " num"
+(after)
+and
+.BI \-B " num"
+(before)
+switches).
+.TP
+\(bu
+They provide no mechanism for searching for
+occurrences in the same paragraph, unless
+preprocessing is done on the files to wrap
+paragraphs into long lines.  Even that will often
+fail, because input buffer sizes may be limited to
+a few hundred characters.
+.TP
+\(bu
+They provide no easy way to deal with grammatical
+word-ending variants, except by explicit
+enumeration, such as searching for
+.IR compress ,
+.IR compressed ,
+.IR compresses ,
+.IR compressing ,
+and
+.IR compression .
+.PP
+Most computer users have been faced with the
+problem of finding information from a large
+collection of files, such as electronic mail,
+on-line documentation, or source code.  Inverted
+indices provide a highly-effective solution to
+this problem.
+.PP
+The
+.B mg
+software is described in Appendix A of the book
+.RS
+.nf
+Ian H. Witten, Alistair Moffat, and Timothy C. Bell
+.I "Managing Gigabytes: Compressing and Indexing Documents and Images"
+Van Nostrand Reinhold
+1994
+xiv + 429 pages
+US$54.95
+ISBN 0-442-01863-0
+Library of Congress catalog number TA1637 .W58 1994
+.fi
+.RE
+.PP
+Many of the algorithms implemented in
+.B mg
+represent significant advances over previous work,
+both in speed, and in storage requirements.  On a
+fast workstation, in tens of minutes, or a few
+hours,
+.BR mgbuild (1)
+can create an index to
+.I all
+of the words in hundreds of thousands of documents
+occupying hundreds of megabytes, or even more than
+a gigabyte, of disk space.
+.BR mgquery (1)
+can then be used to answer complex queries, with
+responses often returned in a second or less.
+.B mg
+also contains algorithms to deal with images, so
+that with a small amount of descriptive text for
+each image, it is possible to do searches in
+collections of images, and to have retrievals
+display the images using a viewer like
+.BR xv (1).
+.PP
+.B mg
+can deal with compressed text and image files and
+surprisingly, it usually runs faster than it would
+if the files were not compressed!  Thus, the
+considerable disk space savings possible from
+file compression are not lost because of the need
+for fast document search and retrieval.
+.PP
+The Free Software Foundation GNU Project
+compression utilities
+.BR gzip (1)
+and
+.BR gunzip (1)
+are recommended for general use over older
+alternatives, like
+.BR compress (1),
+because of their speed and high compression
+ratios.
+.\"=====================================================================
+.SH AVAILABILITY
+The
+.B mg
+software can be obtained via anonymous ftp to the
+Australian archive host
+.I "munnari.oz.au [128.250.1.21]"
+from the directory
+.IR "/pub/mg" .
+.\"=====================================================================
+.SH "TYPICAL USE OF mg"
+Although
+.B mg
+consists of more than 20 separate programs, many
+of which have complicated command-line options,
+take heart: most users require only two or three
+of these programs, and nothing more than a
+document name on the command line.
+.PP
+A
+.I document
+for
+.B mg
+is a fragment of text suitable for retrieval as a
+unit when it is found to contain a requested word,
+or words.  In a collection of poetry, a document
+might be a stanza, while in a novel, it could be a
+paragraph.  In an index of first lines of poems, a
+document would likely be just a single line.
+.PP
+Just what constitutes a document is decided by a
+user-modifiable UNIX shell script,
+.BR mg_get (1).
+The default script provided with the
+.B mg
+source distribution knows about these named
+document collections:
+.TP \w'mailfiles'u+2n
+.I alice
+Lewis Carroll's
+.I "Alice in Wonderland"
+book.
+.TP
+.I allfiles
+all mail files in the directory tree
+.IR $HOME/Mail ,
+including all of its nested subdirectories.
+.TP
+.I mailfiles
+individual mail messages in
+.IR $HOME/mbox
+and
+.IR $HOME/.sentmail.
+.TP
+.I davinci
+A small collection of text and images from the
+work of Leonardo da Vinci.
+.PP
+A document collection name is used by
+.B mg
+as a
+.BR csh (1)
+.I case
+statement selector, and as a subdirectory name in the
+.B $MGDATA
+directory, or the current directory, if
+.B MGDATA
+is not defined.
+.\"=====================================================================
+.SH "EXTENDING mg_get"
+This section describes how to extend
+.BR mg_get (1)
+to handle a new document collection.
+.PP
+Let us take two examples: all \*(Bi
+.I .bib
+files, and all \*(Te files, contained in
+subdirectories under the login directory.
+.PP
+For \*(Bi, each bibliographic entry will be
+considered a separate document.  In order to
+facilitate easy identification of entries, we
+shall require them to begin at the start of a
+line; the
+.BR bibclean (1)
+utility can be used to standardize the format of
+.I .bib
+files, and to validate their string values, so
+that this requirement is met.
+.PP
+For \*(Te, each paragraph will be a separate
+document, and we assume that paragraphs are
+separated by blank lines.  We assume that files
+with extensions
+.IR .atx ,
+.IR .ltx ,
+.IR .stx ,
+and
+.I .tex
+contain input to common \*(Te macro package
+variants.
+.PP
+Make a personal copy of the
+.I mg_get
+script, using the one in the
+.B mg
+source distribution
+.RI ( mg-1.0/mg/mg_get.sh ),
+or the one in the local binary program directory,
+at many sites called
+.IR /usr/local/bin/mg_get .
+.PP
+Examination of the
+.I mg_get
+script shows that each document collection name is
+used in a
+.BR csh (1)
+.I case
+statement selector, and that most of work is done
+by very simple
+.BR awk (1)
+programs that extract documents from files.  In
+your private copy of the
+.I mg_get
+file, after the line
+.PP
+.nf
+  breaksw #davinci
+.fi
+.PP
+and before the line
+.PP
+.nf
+  default:
+.fi
+.PP
+insert this new code:
+.PP
+.nf
+  case bibfiles:
+# Takes a list of files that contain BibTeX entries, and splits them up
+#   by putting ^B after each entry. Assumes that each entry
+#   begins with a line '^@'.
+  switch ($flag)
+    case '-init':
+    breaksw
+
+    case '-text':
+      find $HOME -name '*.bib' -print | \e
+        sort | \e
+        xargs -l100 awk \e
+          '/^@/&&NR!=1{print "^B"} {print $0} END{print "^B"}'
+    breaksw #-text
+
+    case '-cleanup':
+    breaksw #-cleanup
+
+  endsw #flag
+  breaksw #bibfiles
+
+  case texfiles:
+# Takes a list of TeX files and split them up
+#   by putting ^B after each paragraph. Assumes that each entry
+#   begins with a line '^@'.
+  switch ($flag)
+    case '-init':
+    breaksw
+
+    case '-text':
+      find $HOME -name '*x' -print | \e
+        egrep '[.]tex$|[.]ltx$|[.]atx$|[.]stx$' | \e
+        sort | \e
+        xargs -l100 nawk '   /^ *$/ {if (b!=1) printf "^B";b=1} \e
+            \e!/^ *$/ {print;b=0} \e
+            END {printf "^B"}'
+    breaksw #-text
+
+    case '-cleanup':
+    breaksw #-cleanup
+
+  endsw #flag
+  breaksw #texfiles
+.fi
+.PP
+The ^B characters here are Control-B characters,
+.I not
+caret-B pairs.
+.PP
+If you have a large number of \*(Bi or \*(Te
+files, it is likely that a list of them would be
+too long for the UNIX shell to hold in a single
+variable, or on a single command line.  Thus,
+instead of storing the output of
+.BR find (1)
+in a variable, we proceed more cautiously, and
+employ it to produce a list of the required files,
+then pipe them to
+.BR xargs (1),
+which in turn passes up to 100 filenames at a time
+to
+.BR nawk (1)
+for document selection.
+.PP
+Install this modified
+.I mg_get
+script in your private directory for executable
+programs (e.g.
+.IR $HOME/bin ),
+create a directory
+.I $HOME/mgdata
+to hold the index, issue a
+.B rehash
+command if you are using
+.BR csh (1)
+or
+.BR tcsh (1),
+ensure that
+.I mg_get
+occurs in your search path
+.I before
+any system-wide one (the command
+.BI which " mg_get"
+will tell you which version will be selected),
+then create the inverted indexes by
+.BI mgbuild " bibfiles"
+and
+.B mgbuild
+.IR texfiles .
+These commands may take several minutes to run if
+you have a lot of \*(Bi or \*(Te files, or a large
+home directory tree.  Once they are complete, you
+can then query the index with the commands
+.BI mgquery " bibfiles"
+and
+.B mgquery
+.IR texfiles .
+These should respond very rapidly.
+.PP
+In order to keep your index up-to-date, you should
+arrange for it to be recreated automatically and
+regularly, probably every night.  You can do this
+with
+.BR cron (1).
+Use the command
+.B "crontab \-e"
+to edit your
+.I crontab
+file and add two lines like this:
+.PP
+.nf
+00 04 * * * mgbuild bibfiles >$HOME/mgdata/bibfiles.log 2>&1
+15 04 * * * mgbuild texfiles >$HOME/mgdata/texfiles.log 2>&1
+.fi
+.PP
+Save the file and exit the editor.  Now, every
+night at 4am and 4:15am,
+.BR mgbuild (1)
+will reconstruct your inverted indexes, and the
+results of the builds will be saved in log files
+in your
+.I $HOME/mgdata
+directory.
+.\"=====================================================================
+.SH "SEE ALSO"
+.na
+.BR awk (1),
+.BR bibclean (1),
+.BR bibtex (1),
+.BR compress (1),
+.BR csh (1),
+.BR grep (1),
+.BR gunzip (1),
+.BR gzip (1),
+.BR mg_compression_dict (1),
+.BR mg_fast_comp_dict (1),
+.BR mg_get (1),
+.BR mg_invf_dict (1),
+.BR mg_invf_dump (1),
+.BR mg_invf_rebuild (1),
+.BR mg_passes (1),
+.BR mg_perf_hash_build (1),
+.BR mg_text_estimate (1),
+.BR mg_weights_build (1),
+.BR mgbilevel (1),
+.BR mgbuild (1),
+.BR mgdictlist (1),
+.BR mgfelics (1),
+.BR mgquery (1),
+.BR mgstat (1),
+.BR mgtic (1),
+.BR mgticbuild (1),
+.BR mgticdump (1),
+.BR mgticprune (1),
+.BR mgticstat (1),
+.BR nawk (1),
+.BR tcsh (1),
+.BR tex (1),
+.BR xargs (1),
+.BR xmg (1),
+.BR xv (1).
+.\"=====================================================================
+.\" This is for GNU Emacs file-specific customization:
+.\" Local Variables:
+.\" fill-column: 50
+.\" End:
Index: /main/tags/2.25/gsdl/packages/mg/docs/mgintro++.1
===================================================================
--- /main/tags/2.25/gsdl/packages/mg/docs/mgintro++.1	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/mg/docs/mgintro++.1	(revision 21064)
@@ -0,0 +1,212 @@
+.\"------------------------------------------------------------  
+.\" Id - set Rv,revision, and Dt, Date using rcs-Id tag.
+.de Id
+.ds Rv \\$3
+.ds Dt \\$4 
+..
+.Id $Id$
+.\"------------------------------------------------------------
+.ds r \&\s-1MG\s0
+.if n .ds - \%--
+.if t .ds - \(em
+.\"------------------------------------------------------------  
+.am SS
+.LP
+..
+.\"------------------------------------------------------------
+.TH MGINTRO++ 1 \*(Dt CITRI
+.\"--------------------------------------------------------------
+.SH NAME
+mgintro++ \- extended introduction to the MG system
+.\"-------------------------------------------------------------
+.SH DESCRIPTION
+This manual assumes the reader has already read
+.BR mgintro (1).
+.\"-------------------------------------------------------------
+.SS Creating Different Databases
+If a user wants to build databases other than for some
+predefined ones, such as "alice", "davinci", "mailfiles", "allfiles",
+then the user has a couple of choices.
+Ultimately (s)he must produce a text file with control-Bs 
+terminating the documents. 
+To do this one can produce one or more such files, or write a
+"get" command (typically in the form of a script or c program).
+.\"-------------------------------------------------------------
+.SS Using Input Files for mgbuild
+If you don't want to write a "get" script and just want to use
+one or more text files as input, then you must first generate
+the file with control-Bs. For a simple example, you could take
+any text file(s) such as "test1.txt" and "test2.txt", and use 
+.BR vi (1)
+to insert control-Bs by typing "control-V b".
+Next you should create a file with "set" statements 
+in the following form:
+.PP
+.IP
+\fBset pipe = 0 # do not use pipe - use file instead 
+.br
+\fBset input_files = 'test1.txt test2.txt'
+.LP
+Let's call this file, "build_options".
+Now issue the command:
+.IP
+.B mgbuild -s build_options test
+.LP
+This should build a database called "test" in the $MGDATA directory,
+based on the source data of "test1.txt" and "test2.txt".
+The build_options file is simply sourced by 
+.BR mgbuild (1)
+after it has set up its variables. 
+Therefore, any settings one makes in the
+build_options file will override the standard settings.
+See 
+.BR mgbuild (1) 
+for more information.
+.\"-------------------------------------------------------------
+.SS Writing A Get Program
+Instead of using files as input, it is often more convenient to 
+write a "get" program. This program is called by 
+.BR mgbuild (1)
+to get the text data with control-Bs as document terminators.
+It should take three options:
+.br
+(i) -init; (ii) -text; (iii) -cleanup.
+.br
+Get will be called with "init" first and with "cleanup" at the end.
+It will call get with "text" when it wants the text and it should
+write the text to stdout.
+.br
+See 
+.BR mg_get (1)
+for an example.
+.\"-------------------------------------------------------------
+.SS Regular Builds
+The MG system provides a static database; 
+there are no update commands.
+So if one wants to keep one's database reasonably up-to-date
+then one can have this done automatically on a regular basis by 
+.BR cron (1).
+A crontab file can be created using:
+crontab -e
+A crontab file contains lines of the form:
+.nf
+.IP
+\fBminute hour day-of-month month day-of-week shell-command.
+.LP
+.fi
+See
+.BR crontab (1)
+for more information.
+.nf
+An example crontab entry is:
+.IP
+\fB15 02 * * * mgbuild allfiles >$MGDATA/allfiles/allfiles.log 2>&1
+.LP
+.fi
+This will build up the mg database for "allfiles", your mail in
+the folders, every morning at 2:15am. 
+.\"
+.\"-------------------------------------------------------------
+.SS Command Structure
+There are 22 commands that make up the mg system. However,
+a user may only need to be aware of a few: 
+.BR mgbuild (1),
+.BR mgquery (1), 
+and perhaps
+.BR mg_get (1). 
+Many of the commands are called by 
+.BR mgbuild(1).
+The commands can be broken up into a hierarchy.
+.PP
+--------------------------------------
+.br
+MG--+--image compression
+    |  |
+    |  +--mgbilevel
+    |  |
+    |  +--mgfelics
+    |  |
+    |  +--mgtic
+    |  |
+    |  +--mgticbuild
+    |  |
+    |  +--mgticdump
+    |  |
+    |  +--mgticprune
+    |  |
+    |  +--mgticstat
+    |
+    +--text 
+       |
+       +--compression
+       |  |
+       |  +--mg_passes -T1
+       |  |
+       |  +--mg_passes -T2
+       |  |
+       |  +--mg_compression_dict
+       |  |
+       |  +--mg_fast_comp_dict
+       |
+       +--indexing
+       |  |
+       |  +--mg_passes -N1
+       |  |
+       |  +--mg_passes -N2
+       |  |
+       |  +--mg_perf_hash_build
+       |  |
+       |  +--mg_invf_dict
+       |  |
+       |  +--mg_invf_rebuild
+       |  
+       +--weights
+       |  |
+       |  +--mg_weights_build
+       |
+       +--query
+       |  |
+       |  +--mgquery
+       |
+       +--tools
+          |
+          +--mg_invf_dump
+          |
+          +--mg_text_estimate
+          |
+          +--mgdictlist
+          |
+          +--mgstat
+.br
+--------------------------------------
+.PP
+.nf
+.BR mgbuild (1)
+calls the following commands:
+.RS
+.BR mg_passes (1), mg_compression_dict (1)
+.BR mg_perf_hash_build (1), mg_invf_dict (1), mg_invf_rebuild (1)
+.BR mg_weights_build (1)
+.RE
+.fi
+.\"--------------------------------------------
+.SH SEE ALSO
+.BR mgintro (1),
+.BR mgbuild (1),
+.BR mg_get (1)
+.br
+"Guide To The \*r System", in Appendix A of the book:
+.PP
+.RS
+.nf
+Ian H. Witten, Alistair Moffat, and Timothy C. Bell
+.I "Managing Gigabytes: Compressing and Indexing Documents and Images"
+Van Nostrand Reinhold
+1994
+xiv + 429 pages
+US$54.95 
+ISBN 0-442-01863-0
+Library of Congress catalog number TA1637 .W58 1994.
+.fi
+.RE
+
Index: /main/tags/2.25/gsdl/packages/mg/docs/mgintro.1
===================================================================
--- /main/tags/2.25/gsdl/packages/mg/docs/mgintro.1	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/mg/docs/mgintro.1	(revision 21064)
@@ -0,0 +1,155 @@
+.\"------------------------------------------------------------
+.\" Id - set Rv,revision, and Dt, Date using rcs-Id tag.
+.de Id
+.ds Rv \\$3
+.ds Dt \\$4
+..
+.Id $Id$
+.\"------------------------------------------------------------
+.ds r \&\s-1MG\s0
+.if n .ds - \%--
+.if t .ds - \(em
+.\"------------------------------------------------------------
+.am SS
+.LP
+..
+.\"------------------------------------------------------------
+.TH MGINTRO 1 \*(Dt CITRI
+.\"--------------------------------------------------------------
+.SH NAME
+mgintro \- introduction to the MG system
+.\"--------------------------------------------------------------
+.SH DESCRIPTION
+The MG (Managing Gigabytes) system is a collection of
+programs which comprise a full-text retrieval system.
+A full-text retrieval system allows one to create a
+database out of some given documents and then do queries
+upon it to retrieve any relevant documents.
+It is "full-text" in the sense that every word in the
+text is indexed and the query operates only on this index 
+to do the searching.
+.PP
+For example, one could have a database on the book,
+"Alice in Wonderland." A document could be represented by
+each paragraph in the book.
+Having built up the "Alice" database, one could do queries
+such as "cat alice grin" and retrieve any paragraphs which
+match the query. The matching could either be boolean, that
+is the retrieved paragraphs contain a boolean expression of
+the query terms e.g. "cat alice grin"; or the matching
+could be ranked i.e. the most relevant documents to the query
+in relevance order, using some standard heuristic measure.
+.\"--------------------------------------------------------------
+.SS Motivation
+If one wants to find some particular information which
+is stored in a computer text file then one has a few alternative
+courses of action. One can operate directly on the text files
+with utilities such as grep or can process the text files into
+some form of database. Grep is generally limited to identifying
+lines by matching on regular expressions. If the collection 
+of files which grep operates on becomes large, then continual
+passes over the entire text on each query becomes expensive.
+However, its usage is simple as no auxiliary files must be created.
+.PP
+A database consists of some data and indexes into that data. By having
+indexes one can query a large database quickly. Standard databases
+divide the data up into records of fields. This means that the granularity
+of search is a field. In a full-text system, such as \*r,
+there are no fields 
+(or there is an arbitrary sized list of word fields per document) 
+and instead every word is indexed. 
+Using this method, we can except free-form information and yet be fast on searches.
+The next question is what is the overhead of this database.
+In \*r most files which are produced are in a compressed form. The
+two notable compressed files being the given data and the index, called
+an "inverted file". By compressing the files it is possible to have the
+size of the database smaller than the size of the source data.
+.\"--------------------------------------------------------------
+.SS Typical Usage
+The most common use for \*r
+has been as a search database on unix mail files.
+However, any set of text data can be used, one just needs to determine
+what constitutes a document (see 
+.BR mgintro++ (1)
+).
+\*r has also been used on large collections such
+as Comact (Commonwealth Acts of Australia) which is around 132 megabytes 
+and also on sizes up to around 2 gigabytes for TREC 
+(a mixture of collections such as the Wall Street Journal 
+and Associated Press).
+.\"--------------------------------------------------------------
+.SS Getting Started with \*r
+The first thing to do is install the package; 
+please follow the INSTALL instructions.
+Having done this, it is necessary to set a couple of environment variables.
+MGDATA should be set to a directory which is to hold subdirectories for
+each database that you build. For example: 
+.IP
+.B mkdir ~/mgdata; setenv MGDATA ~/mgdata.
+.LP
+If you want to try out building some sample databases then there is
+some sample data such as the "Alice In Wonderland" book. To make sure
+this is accessible you should set the environment variable MGSAMPLE.
+For example: 
+.IP
+.B setenv MGSAMPLE ~/mg/SampleData
+.LP
+Here, "~/mg/SampleData" should contain alice.z .
+.PP
+To build the Alice database (to be contained in $MGDATA/alice subdirectory), 
+type the command 
+.IP
+.B mgbuild alice 
+.LP
+Assuming all went well and some status messages 
+were printed indicating the build was completed, then type 
+.IP
+.B mgquery alice 
+.LP
+to query the database. 
+You can type a few words at the prompt, hit return and
+some relevant documents, Alice paragraphs, should be retrieved.
+Type ".set query ranked" to do ranking queries. Please refer to the 
+.BR mgquery (1)
+man-page for more information on the commands and options of 
+.BR mgquery (1).
+.PP
+The next thing to do is to use \*r
+on a more personal database. If you have
+your mail stored in subdirectories of ~/Mail, such as is done if you use the
+typical set up of 
+.BR elm (1), 
+then type 
+.IP
+.B mgbuild allfiles 
+.LP
+If, however, you keep all your mail in ~/mbox or ~/sentmail, then type 
+.IP
+.B mgbuild mailfiles
+.LP
+.\"--------------------------------------------------------------
+.SH AVAILABILITY
+The \*r software for SunOS 4, Solaris, HPUX, and MIPS,
+can be ftped from: munnari.oz.au [128.250.1.21] in the directory
+/pub/mg. 
+.\"--------------------------------------------------------------
+.SH SEE ALSO
+.na
+.BR mgintro++ (1),
+.BR mgbuild (1),
+.BR mgquery (1)
+.br
+"Guide To The \*r System", in Appendix A of the book:
+.PP
+.RS
+.nf
+Ian H. Witten, Alistair Moffat, and Timothy C. Bell
+.I "Managing Gigabytes: Compressing and Indexing Documents and Images"
+Van Nostrand Reinhold
+1994
+xiv + 429 pages
+US$54.95
+ISBN 0-442-01863-0
+Library of Congress catalog number TA1637 .W58 1994.
+.fi
+.RE
Index: /main/tags/2.25/gsdl/packages/mg/docs/mgmerge.README
===================================================================
--- /main/tags/2.25/gsdl/packages/mg/docs/mgmerge.README	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/mg/docs/mgmerge.README	(revision 21064)
@@ -0,0 +1,230 @@
+A CRASH COURSE GUIDE TO MGMERGE
+===============================
+
+Shane Hudson
+15 November 1994
+
+
+This document is intended as a note to the maintainers of mgmerge
+outlining the mgmerge utility, the changes
+that had to be made to the existing mg code to make mgmerge
+work, and the new source code for mgmerge.
+
+
+****  NOTE:    ****
+All the NEW/CHANGED files are in the file "new_mg.tar" which
+you should have received with this; files that were
+not changed are NOT in the tar file  so it will have to be
+extracted "on top of" the existing code. You'll figure it out :)
+
+
+****  DESCRIPTION:   ****
+mgmerge adds documents to an existing mg database
+without the need to rebuild the database from scratch.
+It works by building a temporary new database from the
+new documents, then merging the "old" and "new" databases
+to give one merged database.
+
+
+The source consists of:
+    mgmerge.sh		The main script, a lot like mgbuild.sh
+    mg_get_merge.sh	Script to retrieve new documents, a lot like
+			mg_get.sh
+    mg_merge.h		header file used by mg_invf_merge.c
+			and mg_text_merge.c
+    mg_text_merge.c	Program to append one compressed text file
+			to another
+    mg_invf_merge.c	Program to merge two inverted files and
+			stemmed dictionaries
+
+See the man pages for mgmerge, mg_get_merge, mg_text_merge and
+mg_invf_merge for a brief overview.
+
+mg_get_merge.sh should really be put into mg_get.sh, with a "-merge"
+option if it is being called by the mgmerge utility, but I was
+too lazy to change it to that.
+
+
+The files updated by mgmerge are:
+
+*.text			with mg_text_merge
+*.text.idx		with mg_text_merge
+*.text.idx.wgt		with mg_weights_build (after merging)
+*.invf			with mg_invf_merge
+*.invf.idx		with      "
+*.invf.dict		with      "
+*.weight		with mg_invf_merge or mg_weights_build
+*.invf.dict.blocked	with mg_invf_dict (after merging)
+
+The *.text.stats file and *.text.dict file remain the same.
+Any other database files (ie, *.invf.dict.hash)
+will be out of date after a merge and will need to be recomputed.
+
+--------------------------------------------------------------------------
+
+MG_TEXT_MERGE
+=============
+
+The two "merging" utilities are mg_text_merge and mg_invf_merge
+
+mg_text_merge simply appends the compressed text for the new
+documents to the old compressed text file.
+For this to succeed, the two files should have been created
+with the same parameters to mg_passes and the same compression
+model must be used. So *.text.dict from the old (static) database
+is used as the model for compressing the new documents.
+The default "-C" option to mg_compression_dict in mgbuild was
+changed to "-S" so novel words in the new documents can be coded.
+The option must be the same in mgmerge -- it is "-S" there too.
+
+---------------
+
+EFFECT on FILE COMPRESSION PERFORMANCE
+
+Since the compression model is not being updated,compression
+performance for the text will slowly degrade. The only solution
+is a periodic rebuild from scratch.
+
+---------------------------------------------------------------------------
+
+MG_INVF_MERGE
+=============
+
+mg_invf_merge updates the stemmed dictionary and
+inverted file.
+For reasons of simplicity, the stemmed dictionaries merged
+are in the ".invf.dict" format, NOT the ".invf.dict.blocked"
+format. 
+So if a database is to be merged the .invf.dict file should
+not be deleted after the .invf.dict.blocked file used by mgquery
+has been created.
+Also for simplicity, level 3 inverted files are not supported, nor
+are skipped format files.
+
+
+
+Merging the inverted files requires every entry in each file
+to be decoded and merged if an entry for the same term appears
+in the other inverted file.
+This can be a slow process if the old inverted file is very large.
+Especially since each entry is decoded bit-by-bit with
+the bit-level I/O rouutines.
+As was noted on page 94 of the book "Managing Gigabytes" (hereafter 
+called "MG"), switching from bernoulli coding (called "Bblock" in
+the mg source code) to gamma or delta coding for the
+inter-document gaps would be an advantage since they require no
+parameters.
+With Bblock coding, N (the number of documents) is a parameter and
+as N changes whenever documents are added, every entry must
+be decoded and recoded.
+My approach was to keep Bblock coding, but keep the N parameter
+constant by recording the artificial N  used to code document
+gaps (called "Nstatic") as well as the real number of documents.
+
+Then, any entry in the old inverted file (called "IFold") that
+is not merged with an entry in the new inverted file (called "IFnew")
+can be copied directly to the merged inverted file (called "IFmerge").
+This can give a significant increase in speed, since usually the
+size of IFnew is very small if only a few documents are being added.
+
+To store Nstatic, a field "static_num_of_docs" was added to
+the invf_dict_header and stem_dict_header structs defined
+in invf.h
+Any program that decodes inverted file entries also had to be changed.
+(The existing mg source code that I changed has been returned with
+this document.)
+Most changes were simply altering a line that
+called BIO_Bblock_Init() so it used the static_num_of_docs
+value rather than num_of_docs.
+
+So since the file format has changed, any existing collection will
+have to be rebuilt first even using mgmerge with it is not
+intended.
+
+-------------
+
+EFFECT on INVERTED FILE COMPRESSION PERFORMANCE
+
+As more merges are accumulatively performed on a database, the
+compression performance will decline.
+The solution is an option in mg_invf_merge to do a "slow"
+merge where every inverted file entry is decoded and recoded using
+the real value of N.
+This is not a lot slower than a fast merge when compared to the
+cost of completely rebuilding the collection from scratch, and 
+the option can be used periodically (when, say, 40% of the
+inverted file has been added since the previous slow merge).
+
+-----------------
+
+THE EXACT WEIGHTS FILE
+
+Recomputing exact document weights requires a complete scan over the
+merged inverted file. This is a waste since the weights for old
+documents will (hopefully) not change much anyway, and the weights
+for new documents can be computed exactly when merging the inverted files,
+at no extra time cost.
+So mg_invf_merge computes the weights for new documents and
+updates the .weight file.
+The weights for old documents are left untouched.
+mgmerge has an option to recompute the weights file.
+This is not much more expensive in terms of time, and is only
+periodically needed.
+
+The effect of leaving the old weights unchanged is difficult to
+asess since the "correct" ranking of documents for a query is
+subjective.
+The frequency with which a rebuild of the weights file with the
+"-w" option should be done is hard to guess.
+But if most merges involves only a few documents, it makes sense
+to not bother recomputing it since the change in old weights values
+is very small and the weights only stray from their "true"
+values slowly over accumulated merging.
+
+-------------------------------------------------------------------------
+
+EXPERIMENTAL RESULTS
+====================
+
+With some small test collections (only a few Mb of text)
+and a slow merge, and a weights file rebuild,
+mgmerge typically took under 20% of the time to completely
+rebuild. Using the default options (fast merge, dont rebuild weights)
+took around 10% or more.
+For larger collections, the savings were greater, especially if the
+added text is very small.
+For example, when the last 6Kb of text of the GNUBib collection was
+added to the rest of it (14Mb) using mgmerge, the total mgmerge time
+was around 20 seconds whereas a complete mgbuild took 280 seconds.
+Only one larger collection was tested (resource contraints prevented
+testing on any really large collections): two short (one-line)
+documents were added to the Gutenberg collection, which comprised
+of nearly 74Mb of source text and had an inverted file size of 9Mb.
+mgmerge took 42 seconds (or 142 seconds with a slow merge and rebuilding the
+weights file), and I'd estimate that an mgbuild on the same machine would 
+have taken at least 20 minutes.
+
+To summarise, mgmerge is not as fast as some sophisticated method
+such as the fixed-length blocks described in section 5.7 of "MG",
+but its huge advantage is that it required almost no changes to
+the existing mg code and is still far better than using mgbuild
+every time a document needs to be added to a collection.
+
+----------------------------------------------------------------------------
+
+OTHER NOTES
+===========
+
+Since it works like mgbuild, mgmerge needs mg_get_merge
+to return the SAME text each time "mg_get_merge -text .." is called.
+
+----
+
+One other thing discovered (but not fixed) was a bug in "invf.pass2.c":
+It crashes on parsed words longer than 128 characters.
+So if any text with words >128 chars is piped to mg_passes,
+the "-N1" and "-N2" options (the memory-efficient inversion method)
+had better be used and not the "-I1"/"-I2" option (which would only
+work on small collections anyway, being the memory-inefficient
+method).
+
Index: /main/tags/2.25/gsdl/packages/mg/install-sh
===================================================================
--- /main/tags/2.25/gsdl/packages/mg/install-sh	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/mg/install-sh	(revision 21064)
@@ -0,0 +1,238 @@
+#! /bin/sh
+#
+# install - install a program, script, or datafile
+# This comes from X11R5.
+#
+# Calling this script install-sh is preferred over install.sh, to prevent
+# `make' implicit rules from creating a file called install from it
+# when there is no Makefile.
+#
+# This script is compatible with the BSD install script, but was written
+# from scratch.
+#
+
+
+# set DOITPROG to echo to test this script
+
+# Don't use :- since 4.3BSD and earlier shells don't like it.
+doit="${DOITPROG-}"
+
+
+# put in absolute paths if you don't have them in your path; or use env. vars.
+
+mvprog="${MVPROG-mv}"
+cpprog="${CPPROG-cp}"
+chmodprog="${CHMODPROG-chmod}"
+chownprog="${CHOWNPROG-chown}"
+chgrpprog="${CHGRPPROG-chgrp}"
+stripprog="${STRIPPROG-strip}"
+rmprog="${RMPROG-rm}"
+mkdirprog="${MKDIRPROG-mkdir}"
+
+tranformbasename=""
+transform_arg=""
+instcmd="$mvprog"
+chmodcmd="$chmodprog 0755"
+chowncmd=""
+chgrpcmd=""
+stripcmd=""
+rmcmd="$rmprog -f"
+mvcmd="$mvprog"
+src=""
+dst=""
+dir_arg=""
+
+while [ x"$1" != x ]; do
+    case $1 in
+	-c) instcmd="$cpprog"
+	    shift
+	    continue;;
+
+	-d) dir_arg=true
+	    shift
+	    continue;;
+
+	-m) chmodcmd="$chmodprog $2"
+	    shift
+	    shift
+	    continue;;
+
+	-o) chowncmd="$chownprog $2"
+	    shift
+	    shift
+	    continue;;
+
+	-g) chgrpcmd="$chgrpprog $2"
+	    shift
+	    shift
+	    continue;;
+
+	-s) stripcmd="$stripprog"
+	    shift
+	    continue;;
+
+	-t=*) transformarg=`echo $1 | sed 's/-t=//'`
+	    shift
+	    continue;;
+
+	-b=*) transformbasename=`echo $1 | sed 's/-b=//'`
+	    shift
+	    continue;;
+
+	*)  if [ x"$src" = x ]
+	    then
+		src=$1
+	    else
+		# this colon is to work around a 386BSD /bin/sh bug
+		:
+		dst=$1
+	    fi
+	    shift
+	    continue;;
+    esac
+done
+
+if [ x"$src" = x ]
+then
+	echo "install:	no input file specified"
+	exit 1
+else
+	true
+fi
+
+if [ x"$dir_arg" != x ]; then
+	dst=$src
+	src=""
+	
+	if [ -d $dst ]; then
+		instcmd=:
+	else
+		instcmd=mkdir
+	fi
+else
+
+# Waiting for this to be detected by the "$instcmd $src $dsttmp" command
+# might cause directories to be created, which would be especially bad 
+# if $src (and thus $dsttmp) contains '*'.
+
+	if [ -f $src -o -d $src ]
+	then
+		true
+	else
+		echo "install:  $src does not exist"
+		exit 1
+	fi
+	
+	if [ x"$dst" = x ]
+	then
+		echo "install:	no destination specified"
+		exit 1
+	else
+		true
+	fi
+
+# If destination is a directory, append the input filename; if your system
+# does not like double slashes in filenames, you may need to add some logic
+
+	if [ -d $dst ]
+	then
+		dst="$dst"/`basename $src`
+	else
+		true
+	fi
+fi
+
+## this sed command emulates the dirname command
+dstdir=`echo $dst | sed -e 's,[^/]*$,,;s,/$,,;s,^$,.,'`
+
+# Make sure that the destination directory exists.
+#  this part is taken from Noah Friedman's mkinstalldirs script
+
+# Skip lots of stat calls in the usual case.
+if [ ! -d "$dstdir" ]; then
+defaultIFS='	
+'
+IFS="${IFS-${defaultIFS}}"
+
+oIFS="${IFS}"
+# Some sh's can't handle IFS=/ for some reason.
+IFS='%'
+set - `echo ${dstdir} | sed -e 's@/@%@g' -e 's@^%@/@'`
+IFS="${oIFS}"
+
+pathcomp=''
+
+while [ $# -ne 0 ] ; do
+	pathcomp="${pathcomp}${1}"
+	shift
+
+	if [ ! -d "${pathcomp}" ] ;
+        then
+		$mkdirprog "${pathcomp}"
+	else
+		true
+	fi
+
+	pathcomp="${pathcomp}/"
+done
+fi
+
+if [ x"$dir_arg" != x ]
+then
+	$doit $instcmd $dst &&
+
+	if [ x"$chowncmd" != x ]; then $doit $chowncmd $dst; else true ; fi &&
+	if [ x"$chgrpcmd" != x ]; then $doit $chgrpcmd $dst; else true ; fi &&
+	if [ x"$stripcmd" != x ]; then $doit $stripcmd $dst; else true ; fi &&
+	if [ x"$chmodcmd" != x ]; then $doit $chmodcmd $dst; else true ; fi
+else
+
+# If we're going to rename the final executable, determine the name now.
+
+	if [ x"$transformarg" = x ] 
+	then
+		dstfile=`basename $dst`
+	else
+		dstfile=`basename $dst $transformbasename | 
+			sed $transformarg`$transformbasename
+	fi
+
+# don't allow the sed command to completely eliminate the filename
+
+	if [ x"$dstfile" = x ] 
+	then
+		dstfile=`basename $dst`
+	else
+		true
+	fi
+
+# Make a temp file name in the proper directory.
+
+	dsttmp=$dstdir/#inst.$$#
+
+# Move or copy the file name to the temp name
+
+	$doit $instcmd $src $dsttmp &&
+
+	trap "rm -f ${dsttmp}" 0 &&
+
+# and set any options; do chmod last to preserve setuid bits
+
+# If any of these fail, we abort the whole thing.  If we want to
+# ignore errors from any of these, just make sure not to ignore
+# errors from the above "$doit $instcmd $src $dsttmp" command.
+
+	if [ x"$chowncmd" != x ]; then $doit $chowncmd $dsttmp; else true;fi &&
+	if [ x"$chgrpcmd" != x ]; then $doit $chgrpcmd $dsttmp; else true;fi &&
+	if [ x"$stripcmd" != x ]; then $doit $stripcmd $dsttmp; else true;fi &&
+	if [ x"$chmodcmd" != x ]; then $doit $chmodcmd $dsttmp; else true;fi &&
+
+# Now rename the file to the real destination.
+
+	$doit $rmcmd -f $dstdir/$dstfile &&
+	$doit $mvcmd $dsttmp $dstdir/$dstfile 
+
+fi &&
+
+
+exit 0
Index: /main/tags/2.25/gsdl/packages/mg/lib/GCC.mak
===================================================================
--- /main/tags/2.25/gsdl/packages/mg/lib/GCC.mak	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/mg/lib/GCC.mak	(revision 21064)
@@ -0,0 +1,84 @@
+###########################################################################
+#
+# gcc win32 makefile -- mg\lib
+# A component of the Greenstone digital library software
+# from the New Zealand Digital Library Project at the
+# University of Waikato, New Zealand.
+#
+# Copyright (C) 2000  The 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.
+#
+###########################################################################
+
+
+AR = ar
+RANLIB = ranlib
+CC = gcc
+DELETE = del
+
+CPPFLAGS = -g
+DEFS = -DQUIET -DHAVE_CONFIG_H -D__WIN32__ -D_LITTLE_ENDIAN
+INCLUDES = -I".." -I"."
+
+o = .o
+ 
+COMPILE = $(CC) -c $(DEFS) $(INCLUDES) $(CPPFLAGS)
+ 
+.SUFFIXES:
+.SUFFIXES: .c $o
+.c$o:
+	$(COMPILE) $<
+
+
+HEADERS = \
+    bitio_m_random.h filestats.h local_strings.h lovinstem.h \
+    bitio_m_stdio.h getopt.h memlib.h bitio_gen.h bitio_mem.h \
+    mgheap.h messages.h bitio_m.h bitio_mems.h huffman.h \
+    timing.h bitio_m_mem.h bitio_random.h huffman_mem.h \
+    perf_hash.h bitio_m_mems.h bitio_stdio.h huffman_stdio.h \
+    sptree.h rx.h pathmax.h getpagesize.h random.h \
+    win32in.h simplefrenchstem.h unitool.h
+
+SOURCES = \
+    bitio_random.c mgheap.c memlib.c bitio_stdio.c huffman.c \
+    messages.c bitio_gen.c filestats.c huffman_mem.c \
+    perf_hash.c bitio_mem.c getopt.c huffman_stdio.c \
+    sptree.c bitio_mems.c getopt1.c local_strings.c \
+    lovinstem.c timing.c rx.c alloca.c error.c xmalloc.c \
+    strstr.c ftruncate.c strcasecmp.c random.c win32in.c \
+    simplefrenchstem.c unitool.h
+
+OBJECTS = \
+    rx$o bitio_random$o mgheap$o memlib$o bitio_stdio$o \
+    huffman$o messages$o bitio_gen$o filestats$o huffman_mem$o \
+    perf_hash$o bitio_mem$o getopt$o huffman_stdio$o sptree$o \
+    bitio_mems$o getopt1$o local_strings$o lovinstem$o \
+    timing$o error$o xmalloc$o random$o win32in$o \
+    simplefrenchstem$o unitool$o
+ 
+all : libmg.a
+
+libmg.a : $(OBJECTS)
+	$(DELETE) libmg.a
+	$(AR) cru libmg.a $(OBJECTS)
+	$(RANLIB) libmg.a
+
+install: 
+ 
+clean: 
+	$(DELETE) *$o
+	$(DELETE) libmg.a
Index: /main/tags/2.25/gsdl/packages/mg/lib/Makefile.in
===================================================================
--- /main/tags/2.25/gsdl/packages/mg/lib/Makefile.in	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/mg/lib/Makefile.in	(revision 21064)
@@ -0,0 +1,174 @@
+###########################################################################
+#
+# Makefile.in -- Makefile for the general purpose library
+# Copyright (C) 1994  Neil Sharman; (C) 1995 Tim Shimmin
+#
+# 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.
+#
+#       @(#)Makefile.in	1.3 16 Mar 1994
+#
+###########################################################################
+
+
+PACKAGE = @PACKAGE@
+VERSION = @VERSION@
+ 
+SHELL = /bin/sh
+srcdir = @srcdir@
+subdir = lib
+VPATH = @srcdir@
+ 
+AR = ar
+CC = @CC@
+CFLAGS = @CFLAGS@ 
+CPPFLAGS = @CPPFLAGS@
+DEFS = @DEFS@
+RANLIB = @RANLIB@
+
+##########################################
+# Uncomment for compiling for the nzdl project
+#
+CFLAGS = @CFLAGS@ -DQUIET
+##########################################
+
+ 
+prefix = @prefix@
+datadir = $(prefix)/share
+localedir = $(datadir)/locale
+ 
+COMPILE = $(CC) -c $(DEFS) $(INCLUDES) $(CPPFLAGS) $(CFLAGS)
+ 
+.SUFFIXES:
+.SUFFIXES: .c .o
+.c.o:
+	$(COMPILE) $<
+
+ANSI2KNR = @ANSI2KNR@
+o = .@U@o
+ 
+.SUFFIXES: ._c ._o
+.c._c:
+	./ansi2knr $< > $*.tmp && mv $*.tmp $@
+._c._o:
+	@echo $(COMPILE) $<
+	@rm -f _$*.c
+	@ln $< _$*.c && $(COMPILE) _$*.c && mv _$*.o $@ && rm _$*.c
+.c._o:
+	./ansi2knr $< > $*.tmp && mv $*.tmp $*._c
+	@echo $(COMPILE) $*._c
+	@rm -f _$*.c
+	@ln $*._c _$*.c && $(COMPILE) _$*.c && mv _$*.o $@ && rm _$*.c
+
+ 
+INCLUDES = -I../../.. -I.. -I$(srcdir)
+ 
+HEADERS = \
+    bitio_m_random.h   filestats.h        local_strings.h    lovinstem.h \
+    bitio_m_stdio.h    getopt.h           memlib.h \
+    bitio_gen.h        bitio_mem.h        mgheap.h             messages.h \
+    bitio_m.h          bitio_mems.h       huffman.h          timing.h \
+    bitio_m_mem.h      bitio_random.h     huffman_mem.h      perf_hash.h \
+    bitio_m_mems.h     bitio_stdio.h      huffman_stdio.h    sptree.h \
+    pathmax.h          getpagesize.h \
+    random.h           simplefrenchstem.h unitool.h
+# regex.h            rx.h               
+
+
+SOURCES = \
+    bitio_random.c    mgheap.c            memlib.c \
+    bitio_stdio.c     huffman.c         messages.c \
+    bitio_gen.c       filestats.c       huffman_mem.c     perf_hash.c \
+    bitio_mem.c       getopt.c          huffman_stdio.c   sptree.c \
+    bitio_mems.c      getopt1.c         local_strings.c   lovinstem.c \
+    timing.c  \
+    alloca.c          error.c           xmalloc.c         strstr.c \
+    gmalloc.c         ftruncate.c       strcasecmp.c      random.c \
+    simplefrenchstem.c                  unitool.c
+# regex.c           rx.c              
+
+OBJECTS = @ALLOCA@ @LIBOBJS@ \
+    bitio_random$o    mgheap$o            memlib$o \
+    bitio_stdio$o     huffman$o         messages$o \
+    bitio_gen$o       filestats$o       huffman_mem$o     perf_hash$o \
+    bitio_mem$o       getopt$o          huffman_stdio$o   sptree$o \
+    bitio_mems$o      getopt1$o         local_strings$o   lovinstem$o \
+    timing$o \
+    error$o           xmalloc$o \
+    random$o          simplefrenchstem$o \
+    unitool$o
+#   gmalloc$o regex$o		rx$o 
+
+LIB_OBJECTS =   \
+    bitio_random$o    mgheap$o            memlib$o \
+    bitio_stdio$o     huffman$o          \
+    bitio_gen$o       filestats$o       huffman_mem$o     perf_hash$o \
+    bitio_mem$o       getopt$o          huffman_stdio$o   sptree$o \
+    bitio_mems$o      getopt1$o         local_strings$o   lovinstem$o \
+    timing$o \
+    error$o           xmalloc$o \
+    random$o          simplefrenchstem$o \
+    unitool$o
+
+
+DISTFILES = Makefile.in $(HEADERS) $(SOURCES)
+ 
+all : libmg.a gsdllibmg.a
+
+libmg.a : $(OBJECTS)
+	rm -f libmg.a
+	$(AR) cru libmg.a $(OBJECTS)
+	$(RANLIB) libmg.a
+
+$(OBJECTS): ../../../config.h
+
+gsdllibmg.a: $(LIB_OBJECTS)
+	rm -f gsdllibmg.a
+	$(AR) cru gsdllibmg.a $(LIB_OBJECTS)
+	$(RANLIB) gsdllibmg.a
+ 
+
+install: 
+installdirs:
+uninstall:
+execinstall:
+execuninstall:
+maninstall:
+manuninstall:
+ 
+dist: $(DISTFILES)
+	for file in $(DISTFILES); do \
+	  ln $$file $(distdir) 2> /dev/null \
+	  || cp -p $$file $(distdir); \
+	done
+
+mostlyclean:
+	rm -f *.o *_.o
+ 
+clean: mostlyclean
+	rm -f libmg.a
+ 
+distclean: clean
+	rm -f Makefile
+ 
+maintainer-clean: distclean
+	@echo "This command is intended only for maintainers to use;"
+	@echo "rebuilding the deleted files may require special tools."
+
+Makefile: Makefile.in ../../../config.status
+	cd ../../.. && CONFIG_FILES=$(subdir)/$@ CONFIG_HEADERS= ./config.status
+ 
+# Tell versions [3.59,3.63) of GNU make not to export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:
Index: /main/tags/2.25/gsdl/packages/mg/lib/WIN32.MAK
===================================================================
--- /main/tags/2.25/gsdl/packages/mg/lib/WIN32.MAK	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/mg/lib/WIN32.MAK	(revision 21064)
@@ -0,0 +1,92 @@
+###########################################################################
+#
+# win32 makefile -- mg\lib
+# A component of the Greenstone digital library software
+# from the New Zealand Digital Library Project at the
+# University of Waikato, New Zealand.
+#
+# Copyright (C) 1999  The 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.
+#
+###########################################################################
+ 
+GSDLHOME = c:\gsdl
+
+AR = lib
+CC = cl
+CPPFLAGS = 
+
+DEFS = -DQUIET -DHAVE_CONFIG_H -D__WIN32__ -D_LITTLE_ENDIAN
+INCLUDES = -I$(GSDLHOME)\packages\mg\lib -I$(GSDLHOME)\packages\mg \
+           -I$(GSDLHOME)
+
+COMPILE = $(CC) -c $(DEFS) $(INCLUDES)
+ 
+.SUFFIXES:
+.SUFFIXES: .c .obj
+.c.obj:
+	$(COMPILE) $<
+
+ANSI2KNR = 
+o = .obj
+ 
+HEADERS = \
+    bitio_m_random.h   filestats.h        local_strings.h    lovinstem.h \
+    bitio_m_stdio.h    getopt.h           memlib.h \
+    bitio_gen.h        bitio_mem.h        mgheap.h             messages.h \
+    bitio_m.h          bitio_mems.h       huffman.h          timing.h \
+    bitio_m_mem.h      bitio_random.h     huffman_mem.h      perf_hash.h \
+    bitio_m_mems.h     bitio_stdio.h      huffman_stdio.h    sptree.h \
+                       rx.h               pathmax.h          getpagesize.h \
+    random.h           win32in.h          simplefrenchstem.h unitool.h
+
+SOURCES = \
+    bitio_random.c    mgheap.c          memlib.c \
+    bitio_stdio.c     huffman.c         messages.c \
+    bitio_gen.c       filestats.c       huffman_mem.c     perf_hash.c \
+    bitio_mem.c       getopt.c          huffman_stdio.c   sptree.c \
+    bitio_mems.c      getopt1.c         local_strings.c   lovinstem.c \
+    timing.c                            rx.c              \
+    alloca.c          error.c           xmalloc.c         strstr.c \
+    ftruncate.c       strcasecmp.c      random.c          win32in.c \
+    simplefrenchstem.c                  unitool.h
+
+OBJECTS =   rx$o \
+    bitio_random$o    mgheap$o            memlib$o \
+    bitio_stdio$o     huffman$o         messages$o \
+    bitio_gen$o       filestats$o       huffman_mem$o     perf_hash$o \
+    bitio_mem$o       getopt$o          huffman_stdio$o   sptree$o \
+    bitio_mems$o      getopt1$o         local_strings$o   lovinstem$o \
+    timing$o           \
+    error$o           xmalloc$o \
+    random$o          win32in$o         simplefrenchstem$o \
+    unitool$o
+ 
+DISTFILES = Makefile.in $(HEADERS) $(SOURCES)
+ 
+all : libmg.lib
+
+libmg.lib : $(OBJECTS)
+	del libmg.lib
+	$(AR) /out:libmg.lib $(OBJECTS)
+
+$(OBJECTS): $(GSDLHOME)\packages\mg\win32cfg.h
+
+install: 
+clean:
+	del *$o 
+	del libmg.lib
Index: /main/tags/2.25/gsdl/packages/mg/lib/alloca.c
===================================================================
--- /main/tags/2.25/gsdl/packages/mg/lib/alloca.c	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/mg/lib/alloca.c	(revision 21064)
@@ -0,0 +1,496 @@
+/* alloca.c -- allocate automatically reclaimed memory
+   (Mostly) portable public-domain implementation -- D A Gwyn
+
+   This implementation of the PWB library alloca function,
+   which is used to allocate space off the run-time stack so
+   that it is automatically reclaimed upon procedure exit,
+   was inspired by discussions with J. Q. Johnson of Cornell.
+   J.Otto Tennant <jot@cray.com> contributed the Cray support.
+
+   There are some preprocessor constants that can
+   be defined when compiling for your specific system, for
+   improved efficiency; however, the defaults should be okay.
+
+   The general concept of this implementation is to keep
+   track of all alloca-allocated blocks, and reclaim any
+   that are found to be deeper in the stack than the current
+   invocation.  This heuristic does not reclaim storage as
+   soon as it becomes invalid, but it will do so eventually.
+
+   As a special case, alloca(0) reclaims storage without
+   allocating any.  It is a good idea to use alloca(0) in
+   your main control loop, etc. to force garbage collection.  */
+
+#ifdef HAVE_CONFIG_H
+# ifdef __WIN32__  /* [RPAP - Feb 97: WIN32 Port] */
+#  include <win32cfg.h>
+# else
+#  include <sysfuncs.h>
+# endif
+#endif
+
+#ifdef emacs
+#include "blockinput.h"
+#endif
+
+/* If compiling with GCC 2, this file's not needed.  */
+#if !defined (__GNUC__) || __GNUC__ < 2
+
+/* If someone has defined alloca as a macro,
+   there must be some other way alloca is supposed to work.  */
+#ifndef alloca
+
+#ifdef emacs
+#ifdef static
+/* actually, only want this if static is defined as ""
+   -- this is for usg, in which emacs must undefine static
+   in order to make unexec workable
+   */
+#ifndef STACK_DIRECTION
+you
+lose
+-- must know STACK_DIRECTION at compile-time
+#endif /* STACK_DIRECTION undefined */
+#endif /* static */
+#endif /* emacs */
+
+/* If your stack is a linked list of frames, you have to
+   provide an "address metric" ADDRESS_FUNCTION macro.  */
+
+#if defined (CRAY) && defined (CRAY_STACKSEG_END)
+long i00afunc ();
+#define ADDRESS_FUNCTION(arg) (char *) i00afunc (&(arg))
+#else
+#define ADDRESS_FUNCTION(arg) &(arg)
+#endif
+
+#if __STDC__
+typedef void *pointer;
+#else
+typedef char *pointer;
+#endif
+
+#define	NULL	0
+
+/* Different portions of Emacs need to call different versions of
+   malloc.  The Emacs executable needs alloca to call xmalloc, because
+   ordinary malloc isn't protected from input signals.  On the other
+   hand, the utilities in lib-src need alloca to call malloc; some of
+   them are very simple, and don't have an xmalloc routine.
+
+   Non-Emacs programs expect this to call use xmalloc.
+
+   Callers below should use malloc.  */
+
+#ifndef emacs
+#define malloc xmalloc
+#endif
+extern pointer malloc ();
+
+/* Define STACK_DIRECTION if you know the direction of stack
+   growth for your system; otherwise it will be automatically
+   deduced at run-time.
+
+   STACK_DIRECTION > 0 => grows toward higher addresses
+   STACK_DIRECTION < 0 => grows toward lower addresses
+   STACK_DIRECTION = 0 => direction of growth unknown  */
+
+#ifndef STACK_DIRECTION
+#define	STACK_DIRECTION	0	/* Direction unknown.  */
+#endif
+
+#if STACK_DIRECTION != 0
+
+#define	STACK_DIR	STACK_DIRECTION	/* Known at compile-time.  */
+
+#else /* STACK_DIRECTION == 0; need run-time code.  */
+
+static int stack_dir;		/* 1 or -1 once known.  */
+#define	STACK_DIR	stack_dir
+
+static void
+find_stack_direction ()
+{
+  static char *addr = NULL;	/* Address of first `dummy', once known.  */
+  auto char dummy;		/* To get stack address.  */
+
+  if (addr == NULL)
+    {				/* Initial entry.  */
+      addr = ADDRESS_FUNCTION (dummy);
+
+      find_stack_direction ();	/* Recurse once.  */
+    }
+  else
+    {
+      /* Second entry.  */
+      if (ADDRESS_FUNCTION (dummy) > addr)
+	stack_dir = 1;		/* Stack grew upward.  */
+      else
+	stack_dir = -1;		/* Stack grew downward.  */
+    }
+}
+
+#endif /* STACK_DIRECTION == 0 */
+
+/* An "alloca header" is used to:
+   (a) chain together all alloca'ed blocks;
+   (b) keep track of stack depth.
+
+   It is very important that sizeof(header) agree with malloc
+   alignment chunk size.  The following default should work okay.  */
+
+#ifndef	ALIGN_SIZE
+#define	ALIGN_SIZE	sizeof(double)
+#endif
+
+typedef union hdr
+{
+  char align[ALIGN_SIZE];	/* To force sizeof(header).  */
+  struct
+    {
+      union hdr *next;		/* For chaining headers.  */
+      char *deep;		/* For stack depth measure.  */
+    } h;
+} header;
+
+static header *last_alloca_header = NULL;	/* -> last alloca header.  */
+
+/* Return a pointer to at least SIZE bytes of storage,
+   which will be automatically reclaimed upon exit from
+   the procedure that called alloca.  Originally, this space
+   was supposed to be taken from the current stack frame of the
+   caller, but that method cannot be made to work for some
+   implementations of C, for example under Gould's UTX/32.  */
+
+pointer
+alloca (size)
+     unsigned size;
+{
+  auto char probe;		/* Probes stack depth: */
+  register char *depth = ADDRESS_FUNCTION (probe);
+
+#if STACK_DIRECTION == 0
+  if (STACK_DIR == 0)		/* Unknown growth direction.  */
+    find_stack_direction ();
+#endif
+
+  /* Reclaim garbage, defined as all alloca'd storage that
+     was allocated from deeper in the stack than currently. */
+
+  {
+    register header *hp;	/* Traverses linked list.  */
+
+#ifdef emacs
+    BLOCK_INPUT;
+#endif
+
+    for (hp = last_alloca_header; hp != NULL;)
+      if ((STACK_DIR > 0 && hp->h.deep > depth)
+	  || (STACK_DIR < 0 && hp->h.deep < depth))
+	{
+	  register header *np = hp->h.next;
+
+	  free ((pointer) hp);	/* Collect garbage.  */
+
+	  hp = np;		/* -> next header.  */
+	}
+      else
+	break;			/* Rest are not deeper.  */
+
+    last_alloca_header = hp;	/* -> last valid storage.  */
+
+#ifdef emacs
+    UNBLOCK_INPUT;
+#endif
+  }
+
+  if (size == 0)
+    return NULL;		/* No allocation required.  */
+
+  /* Allocate combined header + user data storage.  */
+
+  {
+    register pointer new = malloc (sizeof (header) + size);
+    /* Address of header.  */
+
+    ((header *) new)->h.next = last_alloca_header;
+    ((header *) new)->h.deep = depth;
+
+    last_alloca_header = (header *) new;
+
+    /* User storage begins just after header.  */
+
+    return (pointer) ((char *) new + sizeof (header));
+  }
+}
+
+#if defined (CRAY) && defined (CRAY_STACKSEG_END)
+
+#ifdef DEBUG_I00AFUNC
+#include <stdio.h>
+#endif
+
+#ifndef CRAY_STACK
+#define CRAY_STACK
+#ifndef CRAY2
+/* Stack structures for CRAY-1, CRAY X-MP, and CRAY Y-MP */
+struct stack_control_header
+  {
+    long shgrow:32;		/* Number of times stack has grown.  */
+    long shaseg:32;		/* Size of increments to stack.  */
+    long shhwm:32;		/* High water mark of stack.  */
+    long shsize:32;		/* Current size of stack (all segments).  */
+  };
+
+/* The stack segment linkage control information occurs at
+   the high-address end of a stack segment.  (The stack
+   grows from low addresses to high addresses.)  The initial
+   part of the stack segment linkage control information is
+   0200 (octal) words.  This provides for register storage
+   for the routine which overflows the stack.  */
+
+struct stack_segment_linkage
+  {
+    long ss[0200];		/* 0200 overflow words.  */
+    long sssize:32;		/* Number of words in this segment.  */
+    long ssbase:32;		/* Offset to stack base.  */
+    long:32;
+    long sspseg:32;		/* Offset to linkage control of previous
+				   segment of stack.  */
+    long:32;
+    long sstcpt:32;		/* Pointer to task common address block.  */
+    long sscsnm;		/* Private control structure number for
+				   microtasking.  */
+    long ssusr1;		/* Reserved for user.  */
+    long ssusr2;		/* Reserved for user.  */
+    long sstpid;		/* Process ID for pid based multi-tasking.  */
+    long ssgvup;		/* Pointer to multitasking thread giveup.  */
+    long sscray[7];		/* Reserved for Cray Research.  */
+    long ssa0;
+    long ssa1;
+    long ssa2;
+    long ssa3;
+    long ssa4;
+    long ssa5;
+    long ssa6;
+    long ssa7;
+    long sss0;
+    long sss1;
+    long sss2;
+    long sss3;
+    long sss4;
+    long sss5;
+    long sss6;
+    long sss7;
+  };
+
+#else /* CRAY2 */
+/* The following structure defines the vector of words
+   returned by the STKSTAT library routine.  */
+struct stk_stat
+  {
+    long now;			/* Current total stack size.  */
+    long maxc;			/* Amount of contiguous space which would
+				   be required to satisfy the maximum
+				   stack demand to date.  */
+    long high_water;		/* Stack high-water mark.  */
+    long overflows;		/* Number of stack overflow ($STKOFEN) calls.  */
+    long hits;			/* Number of internal buffer hits.  */
+    long extends;		/* Number of block extensions.  */
+    long stko_mallocs;		/* Block allocations by $STKOFEN.  */
+    long underflows;		/* Number of stack underflow calls ($STKRETN).  */
+    long stko_free;		/* Number of deallocations by $STKRETN.  */
+    long stkm_free;		/* Number of deallocations by $STKMRET.  */
+    long segments;		/* Current number of stack segments.  */
+    long maxs;			/* Maximum number of stack segments so far.  */
+    long pad_size;		/* Stack pad size.  */
+    long current_address;	/* Current stack segment address.  */
+    long current_size;		/* Current stack segment size.  This
+				   number is actually corrupted by STKSTAT to
+				   include the fifteen word trailer area.  */
+    long initial_address;	/* Address of initial segment.  */
+    long initial_size;		/* Size of initial segment.  */
+  };
+
+/* The following structure describes the data structure which trails
+   any stack segment.  I think that the description in 'asdef' is
+   out of date.  I only describe the parts that I am sure about.  */
+
+struct stk_trailer
+  {
+    long this_address;		/* Address of this block.  */
+    long this_size;		/* Size of this block (does not include
+				   this trailer).  */
+    long unknown2;
+    long unknown3;
+    long link;			/* Address of trailer block of previous
+				   segment.  */
+    long unknown5;
+    long unknown6;
+    long unknown7;
+    long unknown8;
+    long unknown9;
+    long unknown10;
+    long unknown11;
+    long unknown12;
+    long unknown13;
+    long unknown14;
+  };
+
+#endif /* CRAY2 */
+#endif /* not CRAY_STACK */
+
+#ifdef CRAY2
+/* Determine a "stack measure" for an arbitrary ADDRESS.
+   I doubt that "lint" will like this much. */
+
+static long
+i00afunc (long *address)
+{
+  struct stk_stat status;
+  struct stk_trailer *trailer;
+  long *block, size;
+  long result = 0;
+
+  /* We want to iterate through all of the segments.  The first
+     step is to get the stack status structure.  We could do this
+     more quickly and more directly, perhaps, by referencing the
+     $LM00 common block, but I know that this works.  */
+
+  STKSTAT (&status);
+
+  /* Set up the iteration.  */
+
+  trailer = (struct stk_trailer *) (status.current_address
+				    + status.current_size
+				    - 15);
+
+  /* There must be at least one stack segment.  Therefore it is
+     a fatal error if "trailer" is null.  */
+
+  if (trailer == 0)
+    abort ();
+
+  /* Discard segments that do not contain our argument address.  */
+
+  while (trailer != 0)
+    {
+      block = (long *) trailer->this_address;
+      size = trailer->this_size;
+      if (block == 0 || size == 0)
+	abort ();
+      trailer = (struct stk_trailer *) trailer->link;
+      if ((block <= address) && (address < (block + size)))
+	break;
+    }
+
+  /* Set the result to the offset in this segment and add the sizes
+     of all predecessor segments.  */
+
+  result = address - block;
+
+  if (trailer == 0)
+    {
+      return result;
+    }
+
+  do
+    {
+      if (trailer->this_size <= 0)
+	abort ();
+      result += trailer->this_size;
+      trailer = (struct stk_trailer *) trailer->link;
+    }
+  while (trailer != 0);
+
+  /* We are done.  Note that if you present a bogus address (one
+     not in any segment), you will get a different number back, formed
+     from subtracting the address of the first block.  This is probably
+     not what you want.  */
+
+  return (result);
+}
+
+#else /* not CRAY2 */
+/* Stack address function for a CRAY-1, CRAY X-MP, or CRAY Y-MP.
+   Determine the number of the cell within the stack,
+   given the address of the cell.  The purpose of this
+   routine is to linearize, in some sense, stack addresses
+   for alloca.  */
+
+static long
+i00afunc (long address)
+{
+  long stkl = 0;
+
+  long size, pseg, this_segment, stack;
+  long result = 0;
+
+  struct stack_segment_linkage *ssptr;
+
+  /* Register B67 contains the address of the end of the
+     current stack segment.  If you (as a subprogram) store
+     your registers on the stack and find that you are past
+     the contents of B67, you have overflowed the segment.
+
+     B67 also points to the stack segment linkage control
+     area, which is what we are really interested in.  */
+
+  stkl = CRAY_STACKSEG_END ();
+  ssptr = (struct stack_segment_linkage *) stkl;
+
+  /* If one subtracts 'size' from the end of the segment,
+     one has the address of the first word of the segment.
+
+     If this is not the first segment, 'pseg' will be
+     nonzero.  */
+
+  pseg = ssptr->sspseg;
+  size = ssptr->sssize;
+
+  this_segment = stkl - size;
+
+  /* It is possible that calling this routine itself caused
+     a stack overflow.  Discard stack segments which do not
+     contain the target address.  */
+
+  while (!(this_segment <= address && address <= stkl))
+    {
+#ifdef DEBUG_I00AFUNC
+      fprintf (stderr, "%011o %011o %011o\n", this_segment, address, stkl);
+#endif
+      if (pseg == 0)
+	break;
+      stkl = stkl - pseg;
+      ssptr = (struct stack_segment_linkage *) stkl;
+      size = ssptr->sssize;
+      pseg = ssptr->sspseg;
+      this_segment = stkl - size;
+    }
+
+  result = address - this_segment;
+
+  /* If you subtract pseg from the current end of the stack,
+     you get the address of the previous stack segment's end.
+     This seems a little convoluted to me, but I'll bet you save
+     a cycle somewhere.  */
+
+  while (pseg != 0)
+    {
+#ifdef DEBUG_I00AFUNC
+      fprintf (stderr, "%011o %011o\n", pseg, size);
+#endif
+      stkl = stkl - pseg;
+      ssptr = (struct stack_segment_linkage *) stkl;
+      size = ssptr->sssize;
+      pseg = ssptr->sspseg;
+      result += size;
+    }
+  return (result);
+}
+
+#endif /* not CRAY2 */
+#endif /* CRAY */
+
+#endif /* no alloca */
+#endif /* not GCC version 2 */
Index: /main/tags/2.25/gsdl/packages/mg/lib/bitio_gen.c
===================================================================
--- /main/tags/2.25/gsdl/packages/mg/lib/bitio_gen.c	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/mg/lib/bitio_gen.c	(revision 21064)
@@ -0,0 +1,153 @@
+/**************************************************************************
+ *
+ * bitio_gen.c -- General supoport routines for bitio
+ * Copyright (C) 1994  Neil Sharman and Alistair Moffat
+ *
+ * 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.
+ *
+ * $Id$
+ *
+ **************************************************************************/
+
+/*
+   $Log$
+   Revision 1.1  1999/08/10 21:16:42  sjboddie
+   renamed mg-1.3d directory mg
+
+   Revision 1.1  1998/11/17 09:31:40  rjmcnab
+   *** empty log message ***
+
+   * Revision 1.1  1994/08/22  00:24:38  tes
+   * Initial placement under CVS.
+   *
+ */
+
+static char *RCSID = "$Id$";
+
+#include "sysfuncs.h"
+#include "bitio_m.h"
+
+
+
+
+int fprintf (FILE *, const char *,...);
+
+unsigned long 
+BIO_Unary_Length (unsigned long val)
+{
+  register unsigned long num;
+  UNARY_LENGTH (val, num);
+  return (num);
+}
+
+
+unsigned long 
+BIO_Binary_Length (unsigned long val, unsigned long b)
+{
+  register unsigned long num;
+  BINARY_LENGTH (val, b, num);
+  return (num);
+}
+
+
+unsigned long 
+BIO_Gamma_Length (unsigned long val)
+{
+  register unsigned long num;
+  GAMMA_LENGTH (val, num);
+  return (num);
+}
+
+
+unsigned long 
+BIO_Delta_Length (unsigned long val)
+{
+  register unsigned long num;
+  DELTA_LENGTH (val, num);
+  return (num);
+}
+
+
+unsigned long 
+BIO_Elias_Length (unsigned long val, unsigned long b, double s)
+{
+  register unsigned long num;
+  ELIAS_LENGTH (val, b, s, num);
+  return (num);
+}
+
+unsigned long 
+BIO_Bblock_Length (unsigned long val, unsigned long b)
+{
+  register unsigned long num;
+  BBLOCK_LENGTH (val, b, num);
+  return (num);
+}
+
+
+int 
+BIO_Bblock_Init (int N, int p)
+{
+  int b;
+  b = (int) (0.5 + 0.6931471 * N / p);
+  return (b ? b : 1);
+}
+
+
+int 
+BIO_Bblock_Init_W (int N, int p)
+{
+  int logb;
+  FLOORLOG_2 ((N - p) / p, logb);
+  return (logb < 0 ? 1 : (1 << logb));
+}
+
+int 
+BIO_Bblock_Bound_b (int N, int p, int b)
+{
+  int clogb;
+  CEILLOG_2 (b, clogb);
+  return (p * (1 + clogb) + (N - p * ((1 << clogb) - b + 1)) / b);
+}
+
+int 
+BIO_Bblock_Bound (int N, int p)
+{
+  int b;
+  b = BIO_Bblock_Init_W (N, p);
+  return (BIO_Bblock_Bound_b (N, p, b));
+}
+
+int 
+BIO_Gamma_Bound (int N, int p)
+{
+  return ((int) (p * (2 * log2 ((double) N / p) + 1)));
+}
+
+int 
+floorlog_2 (int b)
+{
+  int logb;
+  FLOORLOG_2 (b, logb);
+  return logb;
+}
+
+int 
+ceillog_2 (int b)
+{
+  int logb;
+  CEILLOG_2 (b, logb);
+  return logb;
+}
Index: /main/tags/2.25/gsdl/packages/mg/lib/bitio_gen.h
===================================================================
--- /main/tags/2.25/gsdl/packages/mg/lib/bitio_gen.h	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/mg/lib/bitio_gen.h	(revision 21064)
@@ -0,0 +1,63 @@
+/**************************************************************************
+ *
+ * bitio_gen.h -- General supoport routines for bitio
+ * Copyright (C) 1994  Neil Sharman and Alistair Moffat
+ *
+ * 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.
+ *
+ * $Id$
+ *
+ **************************************************************************
+ *
+ *  This file contains function definitions for doing general bitio operations.
+ *
+ *  This file defines functions for calculation the length in bits of a number
+ *  coded unary, binary, delta, gamma, elias, and  bblock coding. It defines 
+ *  routines for calculating the parameter and bounds for bblock coding. 
+ *  Routines for calculating ceil and floor lg are also defined.
+ *
+ *
+ **************************************************************************/
+
+#ifndef H_BITIO_GEN
+#define H_BITIO_GEN
+
+unsigned long BIO_Unary_Length (unsigned long val);
+
+unsigned long BIO_Binary_Length (unsigned long val, unsigned long b);
+
+unsigned long BIO_Gamma_Length (unsigned long val);
+
+unsigned long BIO_Delta_Length (unsigned long val);
+
+unsigned long BIO_Elias_Length (unsigned long val, unsigned long b, double s);
+
+unsigned long BIO_Bblock_Length (unsigned long val, unsigned long b);
+
+int BIO_Bblock_Init (int N, int p);
+
+int BIO_Bblock_Init_W (int N, int p);
+
+int BIO_Bblock_Bound_b (int N, int p, int b);
+
+int BIO_Bblock_Bound (int N, int p);
+
+int BIO_Gamma_Bound (int N, int p);
+
+int floorlog_2 (int b);
+
+int ceillog_2 (int b);
+
+#endif
Index: /main/tags/2.25/gsdl/packages/mg/lib/bitio_m.h
===================================================================
--- /main/tags/2.25/gsdl/packages/mg/lib/bitio_m.h	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/mg/lib/bitio_m.h	(revision 21064)
@@ -0,0 +1,543 @@
+/**************************************************************************
+ *
+ * bitio_m.h -- Macros for bitio
+ * Copyright (C) 1994  Neil Sharman and Alistair Moffat
+ *
+ * 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.
+ *
+ * $Id$
+ *
+ **************************************************************************/
+
+
+#ifndef H_BITIO_M
+#define H_BITIO_M
+
+/* -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- */
+
+#ifndef BIO_ENCODE_PROLOGUE
+#define BIO_ENCODE_PROLOGUE
+#endif
+
+#ifndef BIO_DECODE_PROLOGUE
+#define BIO_DECODE_PROLOGUE
+#endif
+
+#ifndef BIO_ENCODE_EPILOGUE
+#define BIO_ENCODE_EPILOGUE
+#endif
+
+#ifndef BIO_DECODE_EPILOGUE
+#define BIO_DECODE_EPILOGUE
+#endif
+
+#ifndef DECODE_ADD
+#define DECODE_ADD(b) (b) += (b) + DECODE_BIT
+#endif
+
+/* -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- */
+
+#define POSITIVE(f, x)							\
+  if ((x)<=0) 								\
+    fprintf(stderr,"Error: Cannot "#f" encode %lu\n",(unsigned long)x),exit(1);
+
+
+#define CEILLOG_2(x,v)							\
+do {									\
+  register int _B_x  = (x) - 1;						\
+  (v) = 0;								\
+  for (; _B_x ; _B_x>>=1, (v)++);					\
+} while(0)
+
+
+#define FLOORLOG_2(x,v)							\
+do {									\
+  register int _B_x  = (x);						\
+  (v) = -1;								\
+  for (; _B_x ; _B_x>>=1, (v)++);					\
+} while(0)
+
+
+/****************************************************************************/
+
+
+
+#define UNARY_ENCODE(x)							\
+do {									\
+  register unsigned long _B_x = (x);					\
+  BIO_ENCODE_PROLOGUE;							\
+  POSITIVE(unary, _B_x);						\
+  while(--_B_x) ENCODE_BIT(0);						\
+  ENCODE_BIT(1);							\
+  BIO_ENCODE_EPILOGUE;							\
+} while(0)
+
+#define UNARY_ENCODE_L(x, count)					\
+do {									\
+  register unsigned long _B_x = (x);					\
+  BIO_ENCODE_PROLOGUE;							\
+  POSITIVE(unary, _B_x);						\
+  (count) += _B_x;							\
+  while(--_B_x) ENCODE_BIT(0);						\
+  ENCODE_BIT(1);							\
+  BIO_ENCODE_EPILOGUE;							\
+} while(0)
+
+#define UNARY_DECODE(x)							\
+do {									\
+  BIO_DECODE_PROLOGUE;							\
+  (x) = 1;								\
+  while (!DECODE_BIT) (x)++;						\
+  BIO_DECODE_EPILOGUE;							\
+} while(0)
+
+#define UNARY_DECODE_L(x, count)					\
+do {									\
+  BIO_DECODE_PROLOGUE;							\
+  (x) = 1;								\
+  while (!DECODE_BIT) (x)++;						\
+  (count) += (x);							\
+  BIO_DECODE_EPILOGUE;							\
+} while(0)
+
+
+#define UNARY_LENGTH(x, count)						\
+do {									\
+  POSITIVE(unary, x);							\
+  (count) = (x);							\
+} while(0)
+
+
+/****************************************************************************/
+
+
+#define BINARY_ENCODE(x, b)						\
+do {									\
+  register unsigned long _B_x = (x);					\
+  register unsigned long _B_b = (b);					\
+  register int _B_nbits, _B_logofb, _B_thresh;				\
+  BIO_ENCODE_PROLOGUE;							\
+  POSITIVE(binary, _B_x);						\
+  CEILLOG_2(_B_b, _B_logofb);						\
+  _B_thresh = (1<<_B_logofb) - _B_b;					\
+  if (--_B_x < _B_thresh)						\
+    _B_nbits = _B_logofb-1;						\
+  else									\
+    {									\
+      _B_nbits = _B_logofb;						\
+      _B_x += _B_thresh;						\
+    }									\
+  while (--_B_nbits>=0)							\
+    ENCODE_BIT((_B_x>>_B_nbits) & 0x1);					\
+  BIO_ENCODE_EPILOGUE;							\
+} while(0)
+
+#define BINARY_ENCODE_L(x, b, count)					\
+do {									\
+  register unsigned long _B_x = (x);					\
+  register unsigned long _B_b = (b);					\
+  register int _B_nbits, _B_logofb, _B_thresh;				\
+  BIO_ENCODE_PROLOGUE;							\
+  POSITIVE(binary, _B_x);						\
+  CEILLOG_2(_B_b, _B_logofb);						\
+  _B_thresh = (1<<_B_logofb) - _B_b;					\
+  if (--_B_x < _B_thresh)						\
+    _B_nbits = _B_logofb-1;						\
+  else									\
+    {									\
+      _B_nbits = _B_logofb;						\
+      _B_x += _B_thresh;						\
+    }									\
+  (count) += _B_nbits;							\
+  while (--_B_nbits>=0)							\
+    ENCODE_BIT((_B_x>>_B_nbits) & 0x1);					\
+  BIO_ENCODE_EPILOGUE;							\
+} while(0)
+
+
+#define BINARY_DECODE(x, b)						\
+do {									\
+  register unsigned long _B_x = 0;					\
+  register unsigned long _B_b = (b);					\
+  register int _B_i, _B_logofb, _B_thresh;				\
+  BIO_DECODE_PROLOGUE;							\
+  if (_B_b != 1)							\
+    {									\
+      CEILLOG_2(_B_b, _B_logofb);					\
+      _B_thresh = (1<<_B_logofb) - _B_b;				\
+      _B_logofb--;							\
+      for (_B_i=0; _B_i < _B_logofb; _B_i++)			 	\
+        DECODE_ADD(_B_x);						\
+      if (_B_x >= _B_thresh)						\
+        {								\
+          DECODE_ADD(_B_x);						\
+          _B_x -= _B_thresh;						\
+	}								\
+      (x) = _B_x+1;							\
+    }									\
+  else									\
+    (x) = 1;								\
+  BIO_DECODE_EPILOGUE;							\
+} while(0)
+
+#define BINARY_DECODE_L(x, b, count)					\
+do {									\
+  register unsigned long _B_x = 0;					\
+  register unsigned long _B_b = (b);					\
+  register int _B_i, _B_logofb, _B_thresh;				\
+  BIO_DECODE_PROLOGUE;							\
+  if (_B_b != 1)							\
+    {									\
+      CEILLOG_2(_B_b, _B_logofb);					\
+      _B_thresh = (1<<_B_logofb) - _B_b;				\
+      _B_logofb--;							\
+      (count) += _B_logofb;					       	\
+      for (_B_i=0; _B_i < _B_logofb; _B_i++)			 	\
+        DECODE_ADD(_B_x);						\
+      if (_B_x >= _B_thresh)						\
+        {								\
+          DECODE_ADD(_B_x);						\
+          _B_x -= _B_thresh;						\
+          (count)++;							\
+	}								\
+      (x) = _B_x+1;							\
+    }									\
+  else									\
+    (x) = 1;								\
+  BIO_DECODE_EPILOGUE;							\
+} while(0)
+
+#define BINARY_LENGTH(x, b, count)					\
+do {									\
+  register unsigned long _B_x = (x);					\
+  register unsigned long _B_b = (b);					\
+  register int _B_nbits, _B_logofb, _B_thresh;				\
+  POSITIVE(binary, _B_x);						\
+  CEILLOG_2(_B_b, _B_logofb);						\
+  _B_thresh = (1<<_B_logofb) - _B_b;					\
+  if (--_B_x < _B_thresh)						\
+    _B_nbits = _B_logofb-1;						\
+  else									\
+    _B_nbits = _B_logofb;						\
+  (count) = _B_nbits;							\
+} while(0)
+
+/****************************************************************************/
+
+
+
+
+#define GAMMA_ENCODE(x)							\
+do {									\
+  register unsigned long _B_xx = (x);					\
+  register int _B_logofb;						\
+  register int _B_nbits;						\
+  BIO_ENCODE_PROLOGUE;							\
+  POSITIVE(gamma, _B_xx);						\
+  FLOORLOG_2(_B_xx, _B_logofb);						\
+  _B_nbits = _B_logofb+1;						\
+  while(_B_logofb--) ENCODE_BIT(0);					\
+  while (--_B_nbits>=0)							\
+    ENCODE_BIT((_B_xx>>_B_nbits) & 0x1);				\
+  BIO_ENCODE_EPILOGUE;							\
+} while (0)
+
+#define GAMMA_ENCODE_L(x, count)					\
+do {									\
+  register unsigned long _B_xx = (x);					\
+  register int _B_logofb;						\
+  register int _B_nbits;						\
+  BIO_ENCODE_PROLOGUE;							\
+  POSITIVE(gamma, _B_xx);						\
+  FLOORLOG_2(_B_xx, _B_logofb);						\
+  _B_nbits = _B_logofb+1;						\
+  (count) += _B_logofb*2+1;						\
+  while(_B_logofb--) ENCODE_BIT(0);					\
+  while (--_B_nbits>=0)							\
+    ENCODE_BIT((_B_xx>>_B_nbits) & 0x1);				\
+  BIO_ENCODE_EPILOGUE;							\
+} while (0)
+
+#define GAMMA_DECODE(x)							\
+do {									\
+  register unsigned long _B_xx = 1;					\
+  register int _B_nbits = 0;						\
+  BIO_DECODE_PROLOGUE;							\
+  while(!DECODE_BIT) _B_nbits++;					\
+  while (_B_nbits-- > 0)						\
+    DECODE_ADD(_B_xx);							\
+  (x) = _B_xx;								\
+  BIO_DECODE_EPILOGUE;							\
+} while (0)
+
+#define GAMMA_DECODE_L(x, count)					\
+do {									\
+  register unsigned long _B_xx = 1;					\
+  register int _B_nbits = 0;						\
+  BIO_DECODE_PROLOGUE;							\
+  while(!DECODE_BIT) _B_nbits++;					\
+  (count) += _B_nbits*2+1;						\
+  while (_B_nbits-- > 0)						\
+    DECODE_ADD(_B_xx);							\
+  (x) = _B_xx;								\
+  BIO_DECODE_EPILOGUE;							\
+} while (0)
+
+#define GAMMA_LENGTH(x, count)						\
+do {									\
+  register unsigned long _B_xx = (x);					\
+  register int _B_logofb;						\
+  POSITIVE(gamma, _B_xx);						\
+  FLOORLOG_2(_B_xx, _B_logofb);						\
+  (count) = _B_logofb*2+1;						\
+} while (0)
+
+
+
+/****************************************************************************/
+
+
+#define DELTA_ENCODE(x)							\
+do {									\
+  register unsigned long _B_xxx = (x);					\
+  register int _B_logx;							\
+  FLOORLOG_2(_B_xxx, _B_logx);						\
+  GAMMA_ENCODE(_B_logx+1);						\
+  BINARY_ENCODE(_B_xxx+1, 1<<_B_logx);					\
+} while (0)
+
+#define DELTA_ENCODE_L(x, count)					\
+do {									\
+  register unsigned long _B_xxx = (x);					\
+  register int _B_logx;							\
+  FLOORLOG_2(_B_xxx, _B_logx);						\
+  GAMMA_ENCODE_L(_B_logx+1, count);					\
+  BINARY_ENCODE_L(_B_xxx+1, 1<<_B_logx, count);				\
+} while (0)
+
+
+#define DELTA_DECODE(x)							\
+do {									\
+  register unsigned long _B_xxx;					\
+  register int _B_logx;							\
+  GAMMA_DECODE(_B_logx); _B_logx--;					\
+  BINARY_DECODE(_B_xxx, 1<<_B_logx); _B_xxx--;				\
+  (x) = _B_xxx + (1<<_B_logx);						\
+} while (0)
+
+#define DELTA_DECODE_L(x, count)					\
+do {									\
+  register unsigned long _B_xxx;					\
+  register int _B_logx;							\
+  GAMMA_DECODE_L(_B_logx, count); _B_logx--;				\
+  BINARY_DECODE_L(_B_xxx, 1<<_B_logx, count); _B_xxx--;			\
+  (x) = _B_xxx + (1<<_B_logx);						\
+} while (0)
+
+#define DELTA_LENGTH(x, count)						\
+do {									\
+  register unsigned long _B_xxx = (x);					\
+  register int _B_logx, _B_dcount;					\
+  FLOORLOG_2(_B_xxx, _B_logx);						\
+  GAMMA_LENGTH(_B_logx+1, count);					\
+  BINARY_LENGTH(_B_xxx+1, 1<<_B_logx, _B_dcount);			\
+  (count) += _B_dcount;							\
+} while (0)
+
+
+/****************************************************************************/
+
+
+
+
+#define ELIAS_ENCODE(x, b, s)						\
+do {									\
+  register unsigned long _B_xx = (x);					\
+  register unsigned long _B_b = (b);					\
+  register double _B_s = (s);						\
+  register int _B_lower=1, _B_upper=1;					\
+  register int _B_k=0;							\
+  register double _B_pow=1.0;						\
+  POSITIVE(elias, _B_xx);						\
+  while (_B_xx>_B_upper) 						\
+    {									\
+      _B_k++;								\
+      _B_lower = _B_upper+1;						\
+      _B_pow *= _B_s;							\
+      _B_upper += _B_b*_B_pow;						\
+    }									\
+  UNARY_ENCODE(_B_k+1);							\
+  BINARY_ENCODE(_B_xx-_B_lower+1, _B_upper-_B_lower+1);			\
+} while (0)
+
+#define ELIAS_ENCODE_L(x, b, s, count)					\
+do {									\
+  register unsigned long _B_xx = (x);					\
+  register unsigned long _B_b = (b);					\
+  register double _B_s = (s);						\
+  register int _B_lower=1, _B_upper=1;					\
+  register int _B_k=0;							\
+  register double _B_pow=1.0;						\
+  POSITIVE(elias, _B_xx);						\
+  while (_B_xx>_B_upper) 						\
+    {									\
+      _B_k++;								\
+      _B_lower = _B_upper+1;						\
+      _B_pow *= _B_s;							\
+      _B_upper += _B_b*_B_pow;						\
+    }									\
+  UNARY_ENCODE_L(_B_k+1, count);					\
+  BINARY_ENCODE_L(_B_xx-_B_lower+1, _B_upper-_B_lower+1, count);	\
+} while (0)
+
+#define ELIAS_DECODE(x, b, s)						\
+do {									\
+  register unsigned long _B_xx;						\
+  register unsigned long _B_b = (b);					\
+  register double _B_s = (s);						\
+  register int _B_lower=1, _B_upper=1;					\
+  register int _B_k;							\
+  register double _B_pow=1.0;						\
+  UNARY_DECODE(_B_k); _B_k--;						\
+  while (_B_k--)							\
+    {									\
+      _B_lower = _B_upper+1;						\
+      _B_pow *= _B_s;							\
+      _B_upper += _B_b*_B_pow;						\
+    }									\
+  BINARY_DECODE(_B_xx, _B_upper-_B_lower+1); _B_xx--;			\
+  POSITIVE(gamma, _B_xx+_B_lower);				  	\
+  (x) = _B_xx+_B_lower;							\
+} while (0)
+
+#define ELIAS_DECODE_L(x, b, s, count)					\
+do {									\
+  register unsigned long _B_xx;						\
+  register unsigned long _B_b = (b);					\
+  register double _B_s = (s);						\
+  register int _B_lower=1, _B_upper=1;					\
+  register int _B_k;							\
+  register double _B_pow=1.0;						\
+  UNARY_DECODE_L(_B_k, count); _B_k--;					\
+  while (_B_k--)							\
+    {									\
+      _B_lower = _B_upper+1;						\
+      _B_pow *= _B_s;							\
+      _B_upper += _B_b*_B_pow;						\
+    }									\
+  BINARY_DECODE_L(_B_xx, _B_upper-_B_lower+1, count); _B_xx--;		\
+  POSITIVE(gamma, _B_xx+_B_lower);				  	\
+  (x) = _B_xx+_B_lower;							\
+} while (0)
+
+#define ELIAS_LENGTH(x, b, s, count)					\
+do {									\
+  register unsigned long _B_xx = (x);					\
+  register unsigned long _B_b = (b);					\
+  register double _B_s = (s);						\
+  register int _B_lower=1, _B_upper=1;					\
+  register int _B_k=0, _B_ecount;					\
+  register double _B_pow=1.0;						\
+  POSITIVE(gamma, _B_xx);						\
+  while (_B_xx>_B_upper) 						\
+    {									\
+      _B_k++;								\
+      _B_lower = _B_upper+1;						\
+      _B_pow *= _B_s;							\
+      _B_upper += _B_b*_B_pow;						\
+    }									\
+  UNARY_LENGTH(_B_k+1, count);						\
+  BINARY_LENGTH(_B_xx-_B_lower+1, _B_upper-_B_lower+1, _B_ecount);	\
+  (count) += _B_ecount;							\
+} while (0)
+
+
+/****************************************************************************/
+
+
+#define BBLOCK_ENCODE(x, b)						\
+do {									\
+  register unsigned long _B_xx = (x);					\
+  register unsigned long _B_bb = (b);					\
+  register int _B_xdivb = 0;						\
+  POSITIVE(bblock, _B_xx);						\
+  _B_xx--;								\
+  while (_B_xx >= _B_bb) 						\
+    {									\
+      _B_xdivb++;							\
+      _B_xx -= _B_bb;							\
+    }									\
+  UNARY_ENCODE(_B_xdivb+1);						\
+  BINARY_ENCODE(_B_xx+1, _B_bb);					\
+} while (0)
+
+#define BBLOCK_ENCODE_L(x, b, count)					\
+do {									\
+  register unsigned long _B_xx = (x);					\
+  register unsigned long _B_bb = (b);					\
+  register int _B_xdivb = 0;						\
+  POSITIVE(bblock, _B_xx);						\
+  _B_xx--;								\
+  while (_B_xx >= _B_bb) 						\
+    {									\
+      _B_xdivb++;							\
+      _B_xx -= _B_bb;							\
+    }									\
+  UNARY_ENCODE_L(_B_xdivb+1, count);					\
+  BINARY_ENCODE_L(_B_xx+1, _B_bb, count);				\
+} while (0)
+
+#define BBLOCK_DECODE(x, b)						\
+do {									\
+  register unsigned long _B_x1, _B_xx = 0;				\
+  register unsigned long _B_bb = (b);					\
+  register int _B_xdivb;						\
+  UNARY_DECODE(_B_xdivb); _B_xdivb--;					\
+  while (_B_xdivb--)							\
+    _B_xx += _B_bb;							\
+  BINARY_DECODE(_B_x1, _B_bb);						\
+  (x) = _B_xx+_B_x1;							\
+} while (0)
+
+#define BBLOCK_DECODE_L(x, b, count)					\
+do {									\
+  register unsigned long _B_x1, _B_xx = 0;				\
+  register unsigned long _B_bb = (b);					\
+  register int _B_xdivb;						\
+  UNARY_DECODE_L(_B_xdivb, count); _B_xdivb--;				\
+  while (_B_xdivb--)							\
+    _B_xx += _B_bb;							\
+  BINARY_DECODE_L(_B_x1, _B_bb, count);					\
+  (x) = _B_xx+_B_x1;							\
+} while (0)
+
+#define BBLOCK_LENGTH(x, b, count)					\
+do {									\
+  register unsigned long _B_bcount, _B_xx = (x);			\
+  register unsigned long _B_bb = (b);					\
+  register int _B_xdivb = 0;						\
+  POSITIVE(bblock, _B_xx);						\
+  _B_xx--;								\
+  while (_B_xx >= _B_bb) 						\
+    {									\
+      _B_xdivb++;							\
+      _B_xx -= _B_bb;							\
+    }									\
+  UNARY_LENGTH(_B_xdivb+1, count);					\
+  BINARY_LENGTH(_B_xx+1, _B_bb, _B_bcount);				\
+  (count) += _B_bcount;  						\
+} while (0)
+
+#endif
Index: /main/tags/2.25/gsdl/packages/mg/lib/bitio_m_mem.h
===================================================================
--- /main/tags/2.25/gsdl/packages/mg/lib/bitio_m_mem.h	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/mg/lib/bitio_m_mem.h	(revision 21064)
@@ -0,0 +1,191 @@
+/**************************************************************************
+ *
+ * bitio_m_mem.h -- Macros for bitio to memory
+ * Copyright (C) 1994  Neil Sharman
+ *
+ * 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.
+ *
+ * $Id$
+ *
+ **************************************************************************
+ *
+ *  This file contains macros for doing bitwise input and output on an array 
+ *  of chars. These routines are faster than the ones in "mems" files. But 
+ *  with these routines you cannot mix reads and writes on the array of chars,
+ *  or multiple write, at the same time and guarantee them to work, also you 
+ *  cannot seek to a point and do a write. The decode routine can detect when
+ *  you run off the end of the array and will produce an approate error 
+ *  message, and the encode routine will stop when it gets to the end of the 
+ *  character array. 
+ *
+ **************************************************************************/
+
+#ifndef H_BITIO_M_MEM
+#define H_BITIO_M_MEM
+
+typedef struct mem_bitio_state
+  {
+    unsigned char *Base;
+    unsigned char *Pos;
+    int Remaining;
+    unsigned char Buff;
+    unsigned char Btg;
+  }
+mem_bitio_state;
+
+
+
+
+#ifndef DECODE_ERROR
+#define DECODE_ERROR (fprintf(stderr,"Unexpected EOF in \"%s\" on line %d\n",\
+				__FILE__, __LINE__), exit(1))
+#endif
+
+
+
+#define ENCODE_START(p,r)						\
+  {									\
+    register unsigned char *__pos = p;					\
+    register unsigned char *__base = p;					\
+    register int __remaining = r;					\
+    register unsigned char __buff = 0;					\
+    register unsigned char __btg = sizeof(__buff)*8;
+
+#define ENCODE_CONTINUE(b)						\
+  {									\
+    register unsigned char *__pos = (b).Pos;				\
+    register unsigned char *__base = (b).Base;				\
+    register int __remaining = (b).Remaining;				\
+    register unsigned char __buff = (b).Buff;				\
+    register unsigned char __btg = (b).Btg;
+
+#define ENCODE_BIT(b)							\
+  do {									\
+    __btg--;								\
+    if (b) __buff |= (1 << __btg);					\
+    if (!__btg)								\
+      {									\
+	if (__remaining)						\
+	  {								\
+	    *__pos++ = __buff;						\
+	    __remaining--;						\
+	  }  								\
+	__buff = 0;							\
+	__btg = sizeof(__buff)*8;					\
+      }									\
+  } while(0)
+
+#define ENCODE_PAUSE(b)							\
+    (b).Pos = __pos;							\
+    (b).Base = __base;							\
+    (b).Remaining = __remaining;					\
+    (b).Buff = __buff;							\
+    (b).Btg =  __btg;							\
+  }
+
+#define ENCODE_FLUSH							\
+  do {									\
+    if (__btg != sizeof(__buff)*8)					\
+      if (__remaining)							\
+	{								\
+          *__pos++ = __buff;						\
+          __remaining--;						\
+	}  								\
+    __btg = sizeof(__buff)*8;						\
+  } while (0)
+
+#define ENCODE_DONE							\
+    ENCODE_FLUSH;							\
+  }
+
+
+#define DECODE_START(p,r)						\
+  {									\
+    register unsigned char *__pos = p;					\
+    register unsigned char *__base = p;					\
+    register int __remaining = r;					\
+    register unsigned char __buff = 0;					\
+    register unsigned char __btg = 0;
+
+#define DECODE_CONTINUE(b)						\
+  {									\
+    register unsigned char *__pos = (b).Pos;				\
+    register unsigned char *__base = (b).Base;				\
+    register int __remaining = (b).Remaining;				\
+    register unsigned char __buff = (b).Buff;				\
+    register unsigned char __btg = (b).Btg;
+
+#define DECODE_ADD_FF(b)						\
+  do {									\
+    if (!__btg)								\
+      {									\
+	if (__remaining)						\
+	  {								\
+  	    __buff = *__pos++;						\
+	    __remaining--;						\
+	  }								\
+        else								\
+          __buff = 0xff;						\
+	__btg = sizeof(__buff)*8;					\
+      }									\
+    (b) += (b) + ((__buff >> --__btg) & 1);				\
+  } while(0)
+
+#define DECODE_ADD_00(b)						\
+  do {									\
+    if (!__btg)								\
+      {									\
+	if (__remaining)						\
+	  {								\
+  	    __buff = *__pos++;						\
+	    __remaining--;						\
+	  }								\
+        else								\
+          __buff = 0x00;						\
+	__btg = sizeof(__buff)*8;					\
+      }									\
+    (b) += (b) + ((__buff >> --__btg) & 1);				\
+  } while(0)
+
+#define DECODE_BIT (__btg ? (__buff >> --__btg) & 1 :			\
+   (!__remaining ? 							\
+    (DECODE_ERROR, 0) :							\
+    (__buff = *__pos++, __remaining--, __btg = sizeof(__buff)*8, 	\
+     (__buff >> --__btg) & 1)))
+
+#define DECODE_DONE	;						\
+  }
+
+#define DECODE_PAUSE(b)							\
+    (b).Pos = __pos;							\
+    (b).Base = __base;							\
+    (b).Remaining = __remaining;					\
+    (b).Buff = __buff;							\
+    (b).Btg =  __btg;							\
+  }
+
+#define DECODE_SEEK(pos)						\
+  do {									\
+    register long __new_pos = (pos);					\
+    __pos = __base + (__new_pos >> 3);					\
+    __buff = *__pos++;							\
+    __btg = 8 - (__new_pos&7);						\
+    }									\
+  while(0)
+
+
+
+
+#endif
Index: /main/tags/2.25/gsdl/packages/mg/lib/bitio_m_mems.h
===================================================================
--- /main/tags/2.25/gsdl/packages/mg/lib/bitio_m_mems.h	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/mg/lib/bitio_m_mems.h	(revision 21064)
@@ -0,0 +1,114 @@
+/**************************************************************************
+ *
+ * bitio_m_mems.h -- Macros for bitio to memory (random access)
+ * Copyright (C) 1994  Neil Sharman
+ *
+ * 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.
+ *
+ * $Id$
+ *
+ **************************************************************************
+ *
+ *  This file contains macros for doing bitwise input and output on an array 
+ *  of chars. These routines are slower than the ones in "mem" files. but 
+ *  with these routines you can mix reads and writes, or multiple writes,  on
+ *  the array of chars at the same time and guarantee them to work, also you 
+ *  can seek to a point and do a write. The decode and encode macros cannot 
+ *  detect when the end off the character is reached and just continue 
+ *  processing.
+ *
+ **************************************************************************/
+
+#ifndef H_BITIO_M_MEMS
+#define H_BITIO_M_MEMS
+
+typedef struct mems_bitio_state
+  {
+    unsigned char *Base;
+    unsigned long pos;
+  }
+mems_bitio_state;
+
+
+#define ENCODE_START(b,p)						\
+  {									\
+    register unsigned char *__base = b;					\
+    register unsigned long __pos = p;
+
+#define ENCODE_CONTINUE(b)						\
+  {									\
+    register unsigned char *__base = (b).Base;				\
+    register unsigned long __pos = (b).pos;
+
+#define ENCODE_BIT(b)							\
+  do {									\
+    if (b)								\
+      __base[__pos>>3] |= 0x80 >> (__pos&7);				\
+    else								\
+      __base[__pos>>3] &= 0xff7f >> (__pos&7);				\
+    __pos++;								\
+  } while(0)
+
+#define ENCODE_PAUSE(b)							\
+    (b).Base = __base;							\
+    (b).pos = __pos;							\
+  }
+
+#define ENCODE_FLUSH
+
+
+#define ENCODE_DONE							\
+    ENCODE_FLUSH;							\
+  }
+
+
+#define DECODE_START(b,p)						\
+  {									\
+    register unsigned char *__base = b;					\
+    register unsigned long __pos = p;
+
+#define DECODE_CONTINUE(b)						\
+  {									\
+    register unsigned char *__base = (b).Base;				\
+    register unsigned long __pos = (b).pos;
+
+#define DECODE_ADD_FF(b)						\
+  do {									\
+    (b) += (b) + (__base[__pos>>3] & (0x80 >> (__pos&7)) != 0);		\
+    __pos++;								\
+  } while(0)
+
+#define DECODE_ADD_00(b) DECODE_ADD_FF(b)
+
+#define DECODE_BIT 							\
+    (__pos++, ((__base[(__pos-1)>>3] & (0x80 >> ((__pos-1)&7))) != 0))
+
+#define DECODE_DONE	;						\
+  }
+
+#define DECODE_PAUSE(b)							\
+    (b).Base = __base;							\
+    (b).pos = __pos;							\
+  }
+
+#define DECODE_SEEK(pos) __pos = (pos)
+
+#define ENCODE_SEEK(pos) __pos = (pos)
+
+
+
+
+
+#endif
Index: /main/tags/2.25/gsdl/packages/mg/lib/bitio_m_random.h
===================================================================
--- /main/tags/2.25/gsdl/packages/mg/lib/bitio_m_random.h	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/mg/lib/bitio_m_random.h	(revision 21064)
@@ -0,0 +1,168 @@
+/**************************************************************************
+ *
+ * bitio_m_random.h -- Macros for bitio to a file (random access)
+ * Copyright (C) 1994  Neil Sharman
+ *
+ * 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.
+ *
+ * $Id$
+ *
+ **************************************************************************
+ *
+ *  This file contains macros for doing bitwise input and output on an array 
+ *  of chars. These routines are slower than the ones in "mem" files. but 
+ *  with these routines you can mix reads and writes, or multiple writes,  on
+ *  the array of chars at the same time and guarantee them to work, also you 
+ *  can seek to a point and do a write. The decode and encode macros cannot 
+ *  detect when the end off the character is reached and just continue 
+ *  processing.
+ *
+ *
+ **************************************************************************/
+
+#ifndef H_BITIO_M_RANDOM
+#define H_BITIO_M_RANDOM
+
+typedef struct random_bitio_state
+  {
+    FILE *File;
+    unsigned char *Buf;
+    unsigned long Base;
+    unsigned long Used;
+    unsigned long pos;
+    unsigned long len;
+    unsigned long sft;
+  }
+random_bitio_state;
+
+
+#define ENCODE_START(f,l)						\
+  {									\
+    register FILE *__file = f;						\
+    register unsigned char *__buf;					\
+    register unsigned long __pos = 0;					\
+    register unsigned long __base = 0;					\
+    register unsigned long __used = 0;					\
+    register unsigned long __len = (l)-1;				\
+    register unsigned long __sft = 0;					\
+    while (__len) { __sft++; __len >>=1; }				\
+    __len = 1<<__sft;							\
+    __buf = Xmalloc(__len);						\
+    fseek(__file, 0, 0);						\
+    fread(__buf, 1, __len, __file);
+
+#define ENCODE_CONTINUE(b)						\
+  {									\
+    register FILE *__file = (b).File;					\
+    register unsigned char *__buf = (b).Buf;				\
+    register unsigned long __pos = (b).pos;				\
+    register unsigned long __base = (b).Base;				\
+    register unsigned long __used = (b).Used;				\
+    register unsigned long __len = (b).len;				\
+    register unsigned long __sft = (b).sft;
+
+#define SEEK fprintf(stderr, "Seek to %d\n",__base)
+#define READ fprintf(stderr, "Read of %d\n",__len)
+#define WRITE fprintf(stderr, "Write of %d\n",__used)
+
+#define WRITE_READ 							\
+	(__used ? (fseek(__file, __base, 0),				\
+                   fwrite(__buf, 1, __len, __file)) : 0,		\
+        __base += __len,						\
+	fseek(__file, __base, 0),					\
+        fread(__buf, 1, __len, __file),					\
+	__pos = 0, __used = 0)
+
+#define ENCODE_BIT(b)							\
+  do {									\
+    if (b)								\
+      __buf[__pos>>3] |= 0x80 >> (__pos&7);				\
+    else								\
+      __buf[__pos>>3] &= 0xff7f >> (__pos&7);				\
+    __used = 1;								\
+    __pos++;								\
+    if ((__pos>>3) >= __len)						\
+      (void)WRITE_READ;							\
+  } while(0)
+
+#define ENCODE_PAUSE(b)							\
+    (b).File = __file;							\
+    (b).Buf = __buf;							\
+    (b).pos = __pos;							\
+    (b).Base = __base;							\
+    (b).Used = __used;							\
+    (b).len = __len;							\
+    (b).sft = __sft;							\
+  }
+
+#define ENCODE_FLUSH							\
+  if (__used)								\
+    {									\
+      fseek(__file, __base, 0);						\
+      fwrite(__buf, 1, __len, __file);					\
+      __used = 0;							\
+    }
+
+
+
+#define ENCODE_DONE							\
+    ENCODE_FLUSH;							\
+    free(__buf);							\
+  }
+
+
+#define DECODE_START(f,l) ENCODE_START(f,l)
+
+#define DECODE_CONTINUE(b) ENCODE_CONTINUE(b)
+
+#define DECODE_BIT 							\
+    (__pos++, (((__pos-1)>>3) >= __len ? WRITE_READ, __pos=1 : 0),	\
+     ((__buf[(__pos-1)>>3] & (0x80 >> ((__pos-1)&7))) != 0))
+
+#define DECODE_ADD_FF(b) ((b) += (b) + DECODE_BIT)
+
+#define DECODE_ADD_00(b) DECODE_ADD_FF(b)
+
+#define DECODE_DONE ENCODE_DONE
+
+#define DECODE_PAUSE(b)	ENCODE_PAUSE(b)
+
+#define ENCODE_SEEK(pos) 						\
+  do {									\
+    if ((((pos)>>3) >= __base) && ((((pos)+7)>>3) < (__base+__len)))   	\
+      __pos = (pos)-(__base << 3); 					\
+    else								\
+      {									\
+        ENCODE_FLUSH;							\
+        __base = (pos) >> 3;						\
+        __base = ((pos)  >> (__sft+3)) << __sft;			\
+        fseek(__file, __base, 0);					\
+        fread(__buf, 1, __len, __file);					\
+        __pos = (pos)&7; 						\
+        __pos = (pos)&((8 << __sft)-1);					\
+      }									\
+  } while(0)
+
+
+#define DECODE_SEEK(pos) ENCODE_SEEK(pos)
+
+#define ENCODE_TELL ((__base << 3) + __pos)
+
+#define DECODE_TELL ENCODE_TELL
+
+
+
+
+#endif
Index: /main/tags/2.25/gsdl/packages/mg/lib/bitio_m_stdio.h
===================================================================
--- /main/tags/2.25/gsdl/packages/mg/lib/bitio_m_stdio.h	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/mg/lib/bitio_m_stdio.h	(revision 21064)
@@ -0,0 +1,147 @@
+/**************************************************************************
+ *
+ * bitio_m_stdio.h -- Macros for bitio to a file
+ * Copyright (C) 1994  Neil Sharman
+ *
+ * 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.
+ *
+ * $Id$
+ *
+ **************************************************************************
+ *
+ *  This file contains macros for doing bitwise input and output on a FILE*.
+ *  With these routines you cannot mix reads and writes on the FILE,
+ *  or multiple writes, at the same time and guarantee them to work, also you 
+ *  cannot seek to a point and do a write. The decode routine can detect when
+ *  you run off the end of the file and will produce an approate error message.
+ *
+ *
+ **************************************************************************/
+
+#ifndef H_BITIO_M_STDIO
+#define H_BITIO_M_STDIO
+
+typedef struct stdio_bitio_state
+  {
+    FILE *File;
+    unsigned char Buff;
+    unsigned char Btg;
+  }
+stdio_bitio_state;
+
+
+
+#ifndef DECODE_ERROR
+#define DECODE_ERROR (fprintf(stderr,"Unexpected EOF in \"%s\" on line %d\n",\
+				__FILE__, __LINE__), exit(1))
+#endif
+
+
+
+#define ENCODE_START(f)							\
+  {									\
+    FILE *__outfile = f;						\
+    register unsigned char __buff = 0;					\
+    register unsigned char __btg = sizeof(__buff)*8;
+
+#define ENCODE_CONTINUE(b)						\
+  {									\
+    FILE *__outfile = (b).File;						\
+    register unsigned char __buff = (b).Buff;				\
+    register unsigned char __btg = (b).Btg;
+
+#define ENCODE_BIT(b)							\
+  do {									\
+    __btg--;								\
+    if (b) __buff |= (1 << __btg);					\
+    if (!__btg)								\
+      {									\
+	putc(__buff, __outfile);					\
+	__buff = 0;							\
+	__btg = sizeof(__buff)*8;					\
+      }									\
+  } while(0)
+
+#define ENCODE_PAUSE(b)							\
+    (b).File = __outfile;						\
+    (b).Buff = __buff;							\
+    (b).Btg =  __btg;							\
+  }
+
+#define ENCODE_DONE							\
+    if (__btg != sizeof(__buff)*8)					\
+      putc(__buff,__outfile);						\
+  }
+
+
+#define DECODE_START(f)							\
+  {									\
+    FILE *__infile = f;							\
+    register unsigned char __buff = 0;					\
+    register unsigned char __btg = 0;
+
+#define DECODE_CONTINUE(b)						\
+  {									\
+    FILE *__infile = (b).File;						\
+    register unsigned char __buff = (b).Buff;				\
+    register unsigned char __btg = (b).Btg;
+
+#define DECODE_ADD_FF(b)						\
+  do {									\
+    if (!__btg)								\
+      {									\
+	register int val = getc(__infile);				\
+	__buff = val == EOF ? 0xff : val;				\
+	__btg = sizeof(__buff)*8;					\
+      }									\
+    (b) += (b) + ((__buff >> --__btg) & 1);				\
+  } while(0)
+
+#define DECODE_ADD_00(b)						\
+  do {									\
+    if (!__btg)								\
+      {									\
+	register int val = getc(__infile);				\
+	__buff = val == EOF ? 0xff : val;				\
+	__btg = sizeof(__buff)*8;					\
+      }									\
+    (b) += (b) + ((__buff >> --__btg) & 1);				\
+  } while(0)
+
+#define DECODE_BIT (__btg ? (__buff >> --__btg) & 1 :			\
+   (__buff = getc(__infile), (feof(__infile) ?				\
+    (DECODE_ERROR, 0) :							\
+    (__btg = sizeof(__buff)*8, (__buff >> --__btg) & 1))))
+
+#define DECODE_DONE	;						\
+  }
+
+#define DECODE_PAUSE(b)							\
+    (b).File = __infile;						\
+    (b).Buff = __buff;							\
+    (b).Btg =  __btg;							\
+  }
+
+
+#define DECODE_SEEK(pos)						\
+  do {									\
+    register long __new_pos = (pos);					\
+    fseek(__infile, __new_pos >> 3, 0);					\
+    __buff = getc(__infile);						\
+    __btg = 8 - (__new_pos&7);						\
+    }									\
+  while(0)
+
+#endif
Index: /main/tags/2.25/gsdl/packages/mg/lib/bitio_mem.c
===================================================================
--- /main/tags/2.25/gsdl/packages/mg/lib/bitio_mem.c	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/mg/lib/bitio_mem.c	(revision 21064)
@@ -0,0 +1,256 @@
+/**************************************************************************
+ *
+ * bitio_mem.c -- Functions for bitio to memory
+ * Copyright (C) 1994  Neil Sharman
+ *
+ * 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.
+ *
+ * $Id$
+ *
+ **************************************************************************/
+
+/*
+   $Log$
+   Revision 1.1  1999/08/10 21:16:45  sjboddie
+   renamed mg-1.3d directory mg
+
+   Revision 1.1  1998/11/17 09:31:47  rjmcnab
+   *** empty log message ***
+
+   * Revision 1.1  1994/08/22  00:24:39  tes
+   * Initial placement under CVS.
+   *
+ */
+
+static char *RCSID = "$Id$";
+
+
+
+#include "sysfuncs.h"
+
+#include "bitio_m_mem.h"
+#include "bitio_m.h"
+
+int fprintf (FILE *, const char *,...);
+
+
+
+void 
+BIO_Mem_Encode_Start (void *buf, int rem, mem_bitio_state * bs)
+{
+  ENCODE_START (buf, rem)
+    ENCODE_PAUSE (*bs)
+}
+
+void 
+BIO_Mem_Encode_Done (mem_bitio_state * bs)
+{
+  ENCODE_CONTINUE (*bs)
+    ENCODE_DONE
+}
+
+
+void 
+BIO_Mem_Decode_Start (void *buf, int rem, mem_bitio_state * bs)
+{
+  DECODE_START (buf, rem)
+    DECODE_PAUSE (*bs)
+}
+
+
+
+
+void 
+BIO_Mem_Unary_Encode (unsigned long val, mem_bitio_state * bs,
+		      unsigned long *bits)
+{
+  ENCODE_CONTINUE (*bs)
+    if (bits)
+    UNARY_ENCODE_L (val, *bits);
+  else
+    UNARY_ENCODE (val);
+  ENCODE_PAUSE (*bs)
+}
+
+
+unsigned long 
+BIO_Mem_Unary_Decode (mem_bitio_state * bs,
+		      unsigned long *bits)
+{
+  register unsigned long val;
+  DECODE_CONTINUE (*bs)
+    if (bits)
+    UNARY_DECODE_L (val, *bits);
+  else
+    UNARY_DECODE (val);
+  DECODE_PAUSE (*bs)
+    return (val);
+}
+
+
+
+
+
+
+
+void 
+BIO_Mem_Binary_Encode (unsigned long val, unsigned long b,
+		       mem_bitio_state * bs, unsigned long *bits)
+{
+  ENCODE_CONTINUE (*bs)
+    if (bits)
+    BINARY_ENCODE_L (val, b, *bits);
+  else
+    BINARY_ENCODE (val, b);
+  ENCODE_PAUSE (*bs)
+}
+
+
+unsigned long 
+BIO_Mem_Binary_Decode (unsigned long b, mem_bitio_state * bs,
+		       unsigned long *bits)
+{
+  register unsigned long val;
+  DECODE_CONTINUE (*bs)
+    if (bits)
+    BINARY_DECODE_L (val, b, *bits);
+  else
+    BINARY_DECODE (val, b);
+  DECODE_PAUSE (*bs)
+    return (val);
+}
+
+
+
+
+
+
+
+void 
+BIO_Mem_Gamma_Encode (unsigned long val, mem_bitio_state * bs,
+		      unsigned long *bits)
+{
+  ENCODE_CONTINUE (*bs)
+    if (bits)
+    GAMMA_ENCODE_L (val, *bits);
+  else
+    GAMMA_ENCODE (val);
+  ENCODE_PAUSE (*bs)
+}
+
+
+unsigned long 
+BIO_Mem_Gamma_Decode (mem_bitio_state * bs, unsigned long *bits)
+{
+  register unsigned long val;
+  DECODE_CONTINUE (*bs)
+    if (bits)
+    GAMMA_DECODE_L (val, *bits);
+  else
+    GAMMA_DECODE (val);
+  DECODE_PAUSE (*bs)
+    return (val);
+}
+
+
+
+
+void 
+BIO_Mem_Delta_Encode (unsigned long val, mem_bitio_state * bs,
+		      unsigned long *bits)
+{
+  ENCODE_CONTINUE (*bs)
+    if (bits)
+    DELTA_ENCODE_L (val, *bits);
+  else
+    DELTA_ENCODE (val);
+  ENCODE_PAUSE (*bs)
+}
+
+
+unsigned long 
+BIO_Mem_Delta_Decode (mem_bitio_state * bs, unsigned long *bits)
+{
+  register unsigned long val;
+  DECODE_CONTINUE (*bs)
+    if (bits)
+    DELTA_DECODE_L (val, *bits);
+  else
+    DELTA_DECODE (val);
+  DECODE_PAUSE (*bs)
+    return (val);
+}
+
+void 
+BIO_Mem_Elias_Encode (unsigned long val, unsigned long b, double s,
+		      mem_bitio_state * bs, unsigned long *bits)
+{
+  ENCODE_CONTINUE (*bs)
+    if (bits)
+    ELIAS_ENCODE_L (val, b, s, *bits);
+  else
+    ELIAS_ENCODE (val, b, s);
+  ENCODE_PAUSE (*bs)
+}
+
+
+unsigned long 
+BIO_Mem_Elias_Decode (unsigned long b, double s,
+		      mem_bitio_state * bs, unsigned long *bits)
+{
+  register unsigned long val;
+  DECODE_CONTINUE (*bs)
+    if (bits)
+    ELIAS_DECODE_L (val, b, s, *bits);
+  else
+    ELIAS_DECODE (val, b, s);
+  DECODE_PAUSE (*bs)
+    return (val);
+}
+
+void 
+BIO_Mem_Bblock_Encode (unsigned long val, unsigned long b,
+		       mem_bitio_state * bs, unsigned long *bits)
+{
+  ENCODE_CONTINUE (*bs)
+    if (bits)
+    BBLOCK_ENCODE_L (val, b, *bits);
+  else
+    BBLOCK_ENCODE (val, b);
+  ENCODE_PAUSE (*bs)
+}
+
+
+unsigned long 
+BIO_Mem_Bblock_Decode (unsigned long b, mem_bitio_state * bs,
+		       unsigned long *bits)
+{
+  register unsigned long val;
+  DECODE_CONTINUE (*bs)
+    if (bits)
+    BBLOCK_DECODE_L (val, b, *bits);
+  else
+    BBLOCK_DECODE (val, b);
+  DECODE_PAUSE (*bs)
+    return (val);
+}
+
+void 
+BIO_Mem_Decode_Seek (unsigned long pos, mem_bitio_state * bs)
+{
+  DECODE_CONTINUE (*bs)
+    DECODE_SEEK (pos);
+  DECODE_PAUSE (*bs)
+}
Index: /main/tags/2.25/gsdl/packages/mg/lib/bitio_mem.h
===================================================================
--- /main/tags/2.25/gsdl/packages/mg/lib/bitio_mem.h	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/mg/lib/bitio_mem.h	(revision 21064)
@@ -0,0 +1,105 @@
+/**************************************************************************
+ *
+ * bitio_mem.h -- Functions for bitio to memory
+ * Copyright (C) 1994  Neil Sharman
+ *
+ * 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.
+ *
+ * $Id$
+ *
+ **************************************************************************
+ *
+ *  This file contains function definitions for doing bitwise input and output
+ *  of numbers on an array of chars. These routines are faster than the ones 
+ *  in "mems" files. But with these routines you cannot mix reads and writes 
+ *  on the array of chars, or multiple write, at the same time and guarantee
+ *  them to work, also you cannot seek to a point and do a write. The decode
+ *  routine can detect when you run off the end of the array and will produce
+ *  an approate error message, and the encode routine will stop when it gets
+ *  to the end of the character array. 
+ *
+ *
+ **************************************************************************/
+
+
+#ifndef H_BITIO_MEM
+#define H_BITIO_MEM
+
+
+
+typedef struct mem_bitio_state
+  {
+    unsigned char *Base;
+    unsigned char *Pos;
+    int Remaining;
+    unsigned char Buff;
+    unsigned char Btg;
+  }
+mem_bitio_state;
+
+
+/* NOTE : All bytes are filled high bit first */
+
+
+void BIO_Mem_Encode_Start (void *buf, int rem, mem_bitio_state * bs);
+void BIO_Mem_Encode_Done (mem_bitio_state * bs);
+
+
+
+void BIO_Mem_Decode_Start (void *buf, int rem, mem_bitio_state * bs);
+
+
+
+void BIO_Mem_Unary_Encode (unsigned long val, mem_bitio_state * bs,
+			   unsigned long *bits);
+unsigned long BIO_Mem_Unary_Decode (mem_bitio_state * bs,
+				    unsigned long *bits);
+
+
+
+void BIO_Mem_Binary_Encode (unsigned long val, unsigned long b,
+			    mem_bitio_state * bs, unsigned long *bits);
+unsigned long BIO_Mem_Binary_Decode (unsigned long b, mem_bitio_state * bs,
+				     unsigned long *bits);
+
+
+
+void BIO_Mem_Gamma_Encode (unsigned long val, mem_bitio_state * bs,
+			   unsigned long *bits);
+unsigned long BIO_Mem_Gamma_Decode (mem_bitio_state * bs, unsigned long *bits);
+
+
+
+void BIO_Mem_Delta_Encode (unsigned long val, mem_bitio_state * bs,
+			   unsigned long *bits);
+unsigned long BIO_Mem_Delta_Decode (mem_bitio_state * bs, unsigned long *bits);
+
+
+void BIO_Mem_Elias_Encode (unsigned long val, unsigned long b, double s,
+			   mem_bitio_state * bs, unsigned long *bits);
+unsigned long BIO_Mem_Elias_Decode (unsigned long b, double s,
+				 mem_bitio_state * bs, unsigned long *bits);
+
+
+void BIO_Mem_Bblock_Encode (unsigned long val, unsigned long b,
+			    mem_bitio_state * bs, unsigned long *bits);
+unsigned long BIO_Mem_Bblock_Decode (unsigned long b, mem_bitio_state * bs,
+				     unsigned long *bits);
+
+
+void BIO_Mem_Decode_Seek (unsigned long pos, mem_bitio_state * bs);
+
+
+#endif
Index: /main/tags/2.25/gsdl/packages/mg/lib/bitio_mems.c
===================================================================
--- /main/tags/2.25/gsdl/packages/mg/lib/bitio_mems.c	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/mg/lib/bitio_mems.c	(revision 21064)
@@ -0,0 +1,265 @@
+/**************************************************************************
+ *
+ * bitio_mems.c -- Functions for bitio to memory (random access)
+ * Copyright (C) 1994  Neil Sharman
+ *
+ * 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.
+ *
+ * $Id$
+ *
+ **************************************************************************/
+
+/*
+   $Log$
+   Revision 1.1  1999/08/10 21:16:45  sjboddie
+   renamed mg-1.3d directory mg
+
+   Revision 1.1  1998/11/17 09:31:48  rjmcnab
+   *** empty log message ***
+
+   * Revision 1.1  1994/08/22  00:24:39  tes
+   * Initial placement under CVS.
+   *
+ */
+
+static char *RCSID = "$Id$";
+
+
+#include "sysfuncs.h"
+
+#include "bitio_m_mems.h"
+#include "bitio_m.h"
+
+int fprintf (FILE *, const char *,...);
+
+
+
+void 
+BIO_Mems_Encode_Start (unsigned char *buf, unsigned long pos,
+		       mems_bitio_state * bs)
+{
+  ENCODE_START (buf, pos)
+    ENCODE_PAUSE (*bs)
+}
+
+void 
+BIO_Mems_Encode_Done (mems_bitio_state * bs)
+{
+  ENCODE_CONTINUE (*bs)
+    ENCODE_DONE
+}
+
+
+void 
+BIO_Mems_Decode_Start (unsigned char *buf, unsigned long pos,
+		       mems_bitio_state * bs)
+{
+  DECODE_START (buf, pos)
+    DECODE_PAUSE (*bs)
+}
+
+
+
+
+void 
+BIO_Mems_Unary_Encode (unsigned long val, mems_bitio_state * bs,
+		       unsigned long *bits)
+{
+  ENCODE_CONTINUE (*bs)
+    if (bits)
+    UNARY_ENCODE_L (val, *bits);
+  else
+    UNARY_ENCODE (val);
+  ENCODE_PAUSE (*bs)
+}
+
+
+unsigned long 
+BIO_Mems_Unary_Decode (mems_bitio_state * bs,
+		       unsigned long *bits)
+{
+  register unsigned long val;
+  DECODE_CONTINUE (*bs)
+    if (bits)
+    UNARY_DECODE_L (val, *bits);
+  else
+    UNARY_DECODE (val);
+  DECODE_PAUSE (*bs)
+    return (val);
+}
+
+
+
+
+
+
+
+void 
+BIO_Mems_Binary_Encode (unsigned long val, unsigned long b,
+			mems_bitio_state * bs, unsigned long *bits)
+{
+  ENCODE_CONTINUE (*bs)
+    if (bits)
+    BINARY_ENCODE_L (val, b, *bits);
+  else
+    BINARY_ENCODE (val, b);
+  ENCODE_PAUSE (*bs)
+}
+
+
+unsigned long 
+BIO_Mems_Binary_Decode (unsigned long b, mems_bitio_state * bs,
+			unsigned long *bits)
+{
+  register unsigned long val;
+  DECODE_CONTINUE (*bs)
+    if (bits)
+    BINARY_DECODE_L (val, b, *bits);
+  else
+    BINARY_DECODE (val, b);
+  DECODE_PAUSE (*bs)
+    return (val);
+}
+
+
+
+
+
+
+
+void 
+BIO_Mems_Gamma_Encode (unsigned long val, mems_bitio_state * bs,
+		       unsigned long *bits)
+{
+  ENCODE_CONTINUE (*bs)
+    if (bits)
+    GAMMA_ENCODE_L (val, *bits);
+  else
+    GAMMA_ENCODE (val);
+  ENCODE_PAUSE (*bs)
+}
+
+
+unsigned long 
+BIO_Mems_Gamma_Decode (mems_bitio_state * bs, unsigned long *bits)
+{
+  register unsigned long val;
+  DECODE_CONTINUE (*bs)
+    if (bits)
+    GAMMA_DECODE_L (val, *bits);
+  else
+    GAMMA_DECODE (val);
+  DECODE_PAUSE (*bs)
+    return (val);
+}
+
+
+
+
+void 
+BIO_Mems_Delta_Encode (unsigned long val, mems_bitio_state * bs,
+		       unsigned long *bits)
+{
+  ENCODE_CONTINUE (*bs)
+    if (bits)
+    DELTA_ENCODE_L (val, *bits);
+  else
+    DELTA_ENCODE (val);
+  ENCODE_PAUSE (*bs)
+}
+
+
+unsigned long 
+BIO_Mems_Delta_Decode (mems_bitio_state * bs, unsigned long *bits)
+{
+  register unsigned long val;
+  DECODE_CONTINUE (*bs)
+    if (bits)
+    DELTA_DECODE_L (val, *bits);
+  else
+    DELTA_DECODE (val);
+  DECODE_PAUSE (*bs)
+    return (val);
+}
+
+void 
+BIO_Mems_Elias_Encode (unsigned long val, unsigned long b, double s,
+		       mems_bitio_state * bs, unsigned long *bits)
+{
+  ENCODE_CONTINUE (*bs)
+    if (bits)
+    ELIAS_ENCODE_L (val, b, s, *bits);
+  else
+    ELIAS_ENCODE (val, b, s);
+  ENCODE_PAUSE (*bs)
+}
+
+
+unsigned long 
+BIO_Mems_Elias_Decode (unsigned long b, double s,
+		       mems_bitio_state * bs, unsigned long *bits)
+{
+  register unsigned long val;
+  DECODE_CONTINUE (*bs)
+    if (bits)
+    ELIAS_DECODE_L (val, b, s, *bits);
+  else
+    ELIAS_DECODE (val, b, s);
+  DECODE_PAUSE (*bs)
+    return (val);
+}
+
+void 
+BIO_Mems_Bblock_Encode (unsigned long val, unsigned long b,
+			mems_bitio_state * bs, unsigned long *bits)
+{
+  ENCODE_CONTINUE (*bs)
+    if (bits)
+    BBLOCK_ENCODE_L (val, b, *bits);
+  else
+    BBLOCK_ENCODE (val, b);
+  ENCODE_PAUSE (*bs)
+}
+
+
+unsigned long 
+BIO_Mems_Bblock_Decode (unsigned long b, mems_bitio_state * bs,
+			unsigned long *bits)
+{
+  register unsigned long val;
+  DECODE_CONTINUE (*bs)
+    if (bits)
+    BBLOCK_DECODE_L (val, b, *bits);
+  else
+    BBLOCK_DECODE (val, b);
+  DECODE_PAUSE (*bs)
+    return (val);
+}
+
+void 
+BIO_Mems_Decode_Seek (unsigned long pos, mems_bitio_state * bs)
+{
+  DECODE_CONTINUE (*bs)
+    DECODE_SEEK (pos);
+  DECODE_PAUSE (*bs)
+}
+
+void 
+BIO_Mems_Encode_Seek (unsigned long pos, mems_bitio_state * bs)
+{
+  ENCODE_CONTINUE (*bs)
+    ENCODE_SEEK (pos);
+  ENCODE_PAUSE (*bs)
+}
Index: /main/tags/2.25/gsdl/packages/mg/lib/bitio_mems.h
===================================================================
--- /main/tags/2.25/gsdl/packages/mg/lib/bitio_mems.h	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/mg/lib/bitio_mems.h	(revision 21064)
@@ -0,0 +1,99 @@
+/**************************************************************************
+ *
+ * bitio_mems.h -- Functions for bitio to memory (random access)
+ * Copyright (C) 1994  Neil Sharman
+ *
+ * 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.
+ *
+ * $Id$
+ *
+ **************************************************************************
+ *
+ *  This file contains function definitions for doing bitwise input and output
+ *  of numbers on an array of chars. These routines are slower than the ones 
+ *  in "mem" files. but with these routines you can mix reads and writes, or 
+ *  multiple writes,  on the array of chars at the same time and guarantee
+ *  them to work, also you can seek to a point and do a write. The decode and 
+ *  encode functions cannot detect when the end off the character is reached
+ *  and just continue processing.
+ *
+ **************************************************************************/
+
+#ifndef H_BITIO_MEMS
+#define H_BITIO_MEMS
+
+
+
+typedef struct mems_bitio_state
+  {
+    unsigned char *Base;
+    unsigned long pos;
+  }
+mems_bitio_state;
+
+
+/* NOTE : All bytes are filled high bit first */
+
+
+void BIO_Mems_Encode_Start (char *buf, unsigned long pos, mems_bitio_state * bs);
+void BIO_Mems_Encode_Done (mems_bitio_state * bs);
+
+
+
+void BIO_Mems_Decode_Start (void *buf, unsigned long pos, mems_bitio_state * bs);
+
+
+
+void BIO_Mems_Unary_Encode (unsigned long val, mems_bitio_state * bs,
+			    unsigned long *bits);
+unsigned long BIO_Mems_Unary_Decode (mems_bitio_state * bs,
+				     unsigned long *bits);
+
+
+
+void BIO_Mems_Binary_Encode (unsigned long val, unsigned long b,
+			     mems_bitio_state * bs, unsigned long *bits);
+unsigned long BIO_Mems_Binary_Decode (unsigned long b, mems_bitio_state * bs,
+				      unsigned long *bits);
+
+
+
+void BIO_Mems_Gamma_Encode (unsigned long val, mems_bitio_state * bs,
+			    unsigned long *bits);
+unsigned long BIO_Mems_Gamma_Decode (mems_bitio_state * bs, unsigned long *bits);
+
+
+
+void BIO_Mems_Delta_Encode (unsigned long val, mems_bitio_state * bs,
+			    unsigned long *bits);
+unsigned long BIO_Mems_Delta_Decode (mems_bitio_state * bs, unsigned long *bits);
+
+
+void BIO_Mems_Elias_Encode (unsigned long val, unsigned long b, double s,
+			    mems_bitio_state * bs, unsigned long *bits);
+unsigned long BIO_Mems_Elias_Decode (unsigned long b, double s,
+				mems_bitio_state * bs, unsigned long *bits);
+
+
+void BIO_Mems_Bblock_Encode (unsigned long val, unsigned long b,
+			     mems_bitio_state * bs, unsigned long *bits);
+unsigned long BIO_Mems_Bblock_Decode (unsigned long b, mems_bitio_state * bs,
+				      unsigned long *bits);
+
+
+void BIO_Mems_Decode_Seek (unsigned long pos, mems_bitio_state * bs);
+
+
+#endif
Index: /main/tags/2.25/gsdl/packages/mg/lib/bitio_random.c
===================================================================
--- /main/tags/2.25/gsdl/packages/mg/lib/bitio_random.c	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/mg/lib/bitio_random.c	(revision 21064)
@@ -0,0 +1,285 @@
+/**************************************************************************
+ *
+ * bitio_random.c -- Functions for bitio to a file (random access)
+ * Copyright (C) 1994  Neil Sharman
+ *
+ * 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.
+ *
+ * $Id$
+ *
+ **************************************************************************/
+
+/*
+   $Log$
+   Revision 1.1  1999/08/10 21:16:46  sjboddie
+   renamed mg-1.3d directory mg
+
+   Revision 1.1  1998/11/17 09:31:50  rjmcnab
+   *** empty log message ***
+
+   * Revision 1.1  1994/08/22  00:24:40  tes
+   * Initial placement under CVS.
+   *
+ */
+
+static char *RCSID = "$Id$";
+
+
+
+#include "sysfuncs.h"
+#include "memlib.h"
+
+#include "bitio_m_random.h"
+#include "bitio_m.h"
+
+
+void 
+BIO_Random_Start (FILE * f, unsigned long len,
+		  random_bitio_state * bs)
+{
+  ENCODE_START (f, len)
+    ENCODE_PAUSE (*bs)
+}
+
+void 
+BIO_Random_Done (random_bitio_state * bs)
+{
+  ENCODE_CONTINUE (*bs)
+    ENCODE_DONE
+}
+
+void 
+BIO_Random_Encode_Bit (int bit, random_bitio_state * bs)
+{
+  ENCODE_CONTINUE (*bs)
+    ENCODE_BIT (bit);
+  ENCODE_PAUSE (*bs)
+}
+
+int 
+BIO_Random_Decode_Bit (random_bitio_state * bs)
+{
+  register int val;
+  DECODE_CONTINUE (*bs)
+    val = DECODE_BIT;
+  DECODE_PAUSE (*bs)
+    return (val);
+}
+
+
+void 
+BIO_Random_Unary_Encode (unsigned long val, random_bitio_state * bs,
+			 unsigned long *bits)
+{
+  ENCODE_CONTINUE (*bs)
+    if (bits)
+    UNARY_ENCODE_L (val, *bits);
+  else
+    UNARY_ENCODE (val);
+  ENCODE_PAUSE (*bs)
+}
+
+
+unsigned long 
+BIO_Random_Unary_Decode (random_bitio_state * bs,
+			 unsigned long *bits)
+{
+  register unsigned long val;
+  DECODE_CONTINUE (*bs)
+    if (bits)
+    UNARY_DECODE_L (val, *bits);
+  else
+    UNARY_DECODE (val);
+  DECODE_PAUSE (*bs)
+    return (val);
+}
+
+
+
+
+
+
+
+void 
+BIO_Random_Binary_Encode (unsigned long val, unsigned long b,
+			  random_bitio_state * bs, unsigned long *bits)
+{
+  ENCODE_CONTINUE (*bs)
+    if (bits)
+    BINARY_ENCODE_L (val, b, *bits);
+  else
+    BINARY_ENCODE (val, b);
+  ENCODE_PAUSE (*bs)
+}
+
+
+unsigned long 
+BIO_Random_Binary_Decode (unsigned long b,
+			  random_bitio_state * bs,
+			  unsigned long *bits)
+{
+  register unsigned long val;
+  DECODE_CONTINUE (*bs)
+    if (bits)
+    BINARY_DECODE_L (val, b, *bits);
+  else
+    BINARY_DECODE (val, b);
+  DECODE_PAUSE (*bs)
+    return (val);
+}
+
+
+
+
+
+
+
+void 
+BIO_Random_Gamma_Encode (unsigned long val, random_bitio_state * bs,
+			 unsigned long *bits)
+{
+  ENCODE_CONTINUE (*bs)
+    if (bits)
+    GAMMA_ENCODE_L (val, *bits);
+  else
+    GAMMA_ENCODE (val);
+  ENCODE_PAUSE (*bs)
+}
+
+
+unsigned long 
+BIO_Random_Gamma_Decode (random_bitio_state * bs,
+			 unsigned long *bits)
+{
+  register unsigned long val;
+  DECODE_CONTINUE (*bs)
+    if (bits)
+    GAMMA_DECODE_L (val, *bits);
+  else
+    GAMMA_DECODE (val);
+  DECODE_PAUSE (*bs)
+    return (val);
+}
+
+
+
+
+void 
+BIO_Random_Delta_Encode (unsigned long val, random_bitio_state * bs,
+			 unsigned long *bits)
+{
+  ENCODE_CONTINUE (*bs)
+    if (bits)
+    DELTA_ENCODE_L (val, *bits);
+  else
+    DELTA_ENCODE (val);
+  ENCODE_PAUSE (*bs)
+}
+
+
+unsigned long 
+BIO_Random_Delta_Decode (random_bitio_state * bs,
+			 unsigned long *bits)
+{
+  register unsigned long val;
+  DECODE_CONTINUE (*bs)
+    if (bits)
+    DELTA_DECODE_L (val, *bits);
+  else
+    DELTA_DECODE (val);
+  DECODE_PAUSE (*bs)
+    return (val);
+}
+
+void 
+BIO_Random_Elias_Encode (unsigned long val, unsigned long b, double s,
+			 random_bitio_state * bs, unsigned long *bits)
+{
+  ENCODE_CONTINUE (*bs)
+    if (bits)
+    ELIAS_ENCODE_L (val, b, s, *bits);
+  else
+    ELIAS_ENCODE (val, b, s);
+  ENCODE_PAUSE (*bs)
+}
+
+
+unsigned long 
+BIO_Random_Elias_Decode (unsigned long b, double s,
+			 random_bitio_state * bs,
+			 unsigned long *bits)
+{
+  register unsigned long val;
+  DECODE_CONTINUE (*bs)
+    if (bits)
+    ELIAS_DECODE_L (val, b, s, *bits);
+  else
+    ELIAS_DECODE (val, b, s);
+  DECODE_PAUSE (*bs)
+    return (val);
+}
+
+void 
+BIO_Random_Bblock_Encode (unsigned long val, unsigned long b,
+			  random_bitio_state * bs, unsigned long *bits)
+{
+  ENCODE_CONTINUE (*bs)
+    if (bits)
+    BBLOCK_ENCODE_L (val, b, *bits);
+  else
+    BBLOCK_ENCODE (val, b);
+  ENCODE_PAUSE (*bs)
+}
+
+
+unsigned long 
+BIO_Random_Bblock_Decode (unsigned long b,
+			  random_bitio_state * bs,
+			  unsigned long *bits)
+{
+  register unsigned long val;
+  DECODE_CONTINUE (*bs)
+    if (bits)
+    BBLOCK_DECODE_L (val, b, *bits);
+  else
+    BBLOCK_DECODE (val, b);
+  DECODE_PAUSE (*bs)
+    return (val);
+}
+
+void 
+BIO_Random_Seek (unsigned long pos, random_bitio_state * bs)
+{
+  ENCODE_CONTINUE (*bs)
+    ENCODE_SEEK (pos);
+  ENCODE_PAUSE (*bs)
+}
+void 
+BIO_Random_Flush (random_bitio_state * bs)
+{
+  ENCODE_CONTINUE (*bs)
+    ENCODE_FLUSH;
+  ENCODE_PAUSE (*bs)
+}
+
+unsigned long 
+BIO_Random_Tell (random_bitio_state * bs)
+{
+  register unsigned long t;
+  ENCODE_CONTINUE (*bs)
+    t = ENCODE_TELL;
+  ENCODE_PAUSE (*bs)
+    return (t);
+}
Index: /main/tags/2.25/gsdl/packages/mg/lib/bitio_random.h
===================================================================
--- /main/tags/2.25/gsdl/packages/mg/lib/bitio_random.h	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/mg/lib/bitio_random.h	(revision 21064)
@@ -0,0 +1,117 @@
+/**************************************************************************
+ *
+ * bitio_random.h -- Functions for bitio to a file (random access)
+ * Copyright (C) 1994  Neil Sharman
+ *
+ * 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.
+ *
+ * $Id$
+ *
+ **************************************************************************
+ *
+ *  This file contains function definitions for doing bitwise input and output
+ *  of numbers on an array of chars. These routines are slower than the ones 
+ *  in "mem" files. but with these routines you can mix reads and writes, or 
+ *  multiple writes,  on the array of chars at the same time and guarantee
+ *  them to work, also you can seek to a point and do a write. The decode and 
+ *  encode functions cannot detect when the end off the character is reached
+ *  and just continue processing.
+ *
+ **************************************************************************/
+
+#ifndef H_BITIO_RANDOM
+#define H_BITIO_RANDOM
+
+
+
+typedef struct random_bitio_state
+  {
+    FILE *File;
+    unsigned char *Buf;
+    unsigned long Base;
+    unsigned long Used;
+    unsigned long pos;
+    unsigned long len;
+    unsigned long sft;
+  }
+random_bitio_state;
+
+
+/* NOTE : All bytes are filled high bit first */
+
+
+void BIO_Random_Start (FILE * f, unsigned long len,
+		       random_bitio_state * bs);
+void BIO_Random_Done (random_bitio_state * bs);
+
+
+
+void BIO_Random_Decode_Start (void *buf, unsigned long pos,
+			      random_bitio_state * bs);
+
+void BIO_Random_Encode_Bit (int bit, random_bitio_state * bs);
+
+int BIO_Random_Decode_Bit (random_bitio_state * bs);
+
+
+void BIO_Random_Unary_Encode (unsigned long val, random_bitio_state * bs,
+			      unsigned long *bits);
+unsigned long BIO_Random_Unary_Decode (random_bitio_state * bs,
+				       unsigned long *bits);
+
+
+
+void BIO_Random_Binary_Encode (unsigned long val, unsigned long b,
+			       random_bitio_state * bs, unsigned long *bits);
+unsigned long BIO_Random_Binary_Decode (unsigned long b, random_bitio_state * bs,
+					unsigned long *bits);
+
+
+
+void BIO_Random_Gamma_Encode (unsigned long val, random_bitio_state * bs,
+			      unsigned long *bits);
+unsigned long BIO_Random_Gamma_Decode (random_bitio_state * bs,
+				       unsigned long *bits);
+
+
+
+void BIO_Random_Delta_Encode (unsigned long val, random_bitio_state * bs,
+			      unsigned long *bits);
+unsigned long BIO_Random_Delta_Decode (random_bitio_state * bs,
+				       unsigned long *bits);
+
+
+void BIO_Random_Elias_Encode (unsigned long val, unsigned long b, double s,
+			      random_bitio_state * bs, unsigned long *bits);
+unsigned long BIO_Random_Elias_Decode (unsigned long b, double s,
+				       random_bitio_state * bs,
+				       unsigned long *bits);
+
+
+void BIO_Random_Bblock_Encode (unsigned long val, unsigned long b,
+			       random_bitio_state * bs, unsigned long *bits);
+unsigned long BIO_Random_Bblock_Decode (unsigned long b,
+					random_bitio_state * bs,
+					unsigned long *bits);
+
+
+void BIO_Random_Seek (unsigned long pos, random_bitio_state * bs);
+
+void BIO_Random_Flush (random_bitio_state * bs);
+
+unsigned long BIO_Random_Tell (random_bitio_state * bs);
+
+
+#endif
Index: /main/tags/2.25/gsdl/packages/mg/lib/bitio_stdio.c
===================================================================
--- /main/tags/2.25/gsdl/packages/mg/lib/bitio_stdio.c	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/mg/lib/bitio_stdio.c	(revision 21064)
@@ -0,0 +1,281 @@
+/**************************************************************************
+ *
+ * bitio_stdio.c -- Functions for bitio to a file
+ * Copyright (C) 1994  Neil Sharman
+ *
+ * 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.
+ *
+ * $Id$
+ *
+ **************************************************************************/
+
+/*
+   $Log$
+   Revision 1.1  1999/08/10 21:16:47  sjboddie
+   renamed mg-1.3d directory mg
+
+   Revision 1.1  1998/11/17 09:31:52  rjmcnab
+   *** empty log message ***
+
+   * Revision 1.1  1994/08/22  00:24:41  tes
+   * Initial placement under CVS.
+   *
+ */
+
+static char *RCSID = "$Id$";
+
+
+
+#include "sysfuncs.h"
+
+#include "bitio_m_stdio.h"
+#include "bitio_m.h"
+
+
+
+void 
+BIO_Stdio_Encode_Start (FILE * f, stdio_bitio_state * bs)
+{
+  ENCODE_START (f)
+    ENCODE_PAUSE (*bs)
+}
+
+void 
+BIO_Stdio_Encode_Done (stdio_bitio_state * bs)
+{
+  ENCODE_CONTINUE (*bs)
+    ENCODE_DONE
+}
+
+
+void 
+BIO_Stdio_Decode_Start (FILE * f, stdio_bitio_state * bs)
+{
+  DECODE_START (f)
+    DECODE_PAUSE (*bs)
+}
+
+void 
+BIO_Stdio_Encode_Bit (int bit, stdio_bitio_state * bs)
+{
+  ENCODE_CONTINUE (*bs)
+    ENCODE_BIT (bit);
+  ENCODE_PAUSE (*bs)
+}
+
+
+int 
+BIO_Stdio_Decode_Bit (stdio_bitio_state * bs)
+{
+  register int val;
+  DECODE_CONTINUE (*bs)
+    val = DECODE_BIT;
+  DECODE_PAUSE (*bs)
+    return (val);
+}
+
+
+
+
+void 
+BIO_Stdio_Unary_Encode (unsigned long val, stdio_bitio_state * bs,
+			unsigned long *bits)
+{
+  ENCODE_CONTINUE (*bs)
+    if (bits)
+    UNARY_ENCODE_L (val, *bits);
+  else
+    UNARY_ENCODE (val);
+  ENCODE_PAUSE (*bs)
+}
+
+
+unsigned long 
+BIO_Stdio_Unary_Decode (stdio_bitio_state * bs,
+			unsigned long *bits)
+{
+  register unsigned long val;
+  DECODE_CONTINUE (*bs)
+    if (bits)
+    UNARY_DECODE_L (val, *bits);
+  else
+    UNARY_DECODE (val);
+  DECODE_PAUSE (*bs)
+    return (val);
+}
+
+
+
+
+
+
+
+void 
+BIO_Stdio_Binary_Encode (unsigned long val, unsigned long b,
+			 stdio_bitio_state * bs, unsigned long *bits)
+{
+  ENCODE_CONTINUE (*bs)
+    if (bits)
+    BINARY_ENCODE_L (val, b, *bits);
+  else
+    BINARY_ENCODE (val, b);
+  ENCODE_PAUSE (*bs)
+}
+
+
+unsigned long 
+BIO_Stdio_Binary_Decode (unsigned long b, stdio_bitio_state * bs,
+			 unsigned long *bits)
+{
+  register unsigned long val;
+  DECODE_CONTINUE (*bs)
+    if (bits)
+    BINARY_DECODE_L (val, b, *bits);
+  else
+    BINARY_DECODE (val, b);
+  DECODE_PAUSE (*bs)
+    return (val);
+}
+
+
+
+
+
+
+
+void 
+BIO_Stdio_Gamma_Encode (unsigned long val, stdio_bitio_state * bs,
+			unsigned long *bits)
+{
+  ENCODE_CONTINUE (*bs)
+    if (bits)
+    GAMMA_ENCODE_L (val, *bits);
+  else
+    GAMMA_ENCODE (val);
+  ENCODE_PAUSE (*bs)
+}
+
+
+unsigned long 
+BIO_Stdio_Gamma_Decode (stdio_bitio_state * bs,
+			unsigned long *bits)
+{
+  register unsigned long val;
+  DECODE_CONTINUE (*bs)
+    if (bits)
+    GAMMA_DECODE_L (val, *bits);
+  else
+    GAMMA_DECODE (val);
+  DECODE_PAUSE (*bs)
+    return (val);
+}
+
+
+
+
+void 
+BIO_Stdio_Delta_Encode (unsigned long val, stdio_bitio_state * bs,
+			unsigned long *bits)
+{
+  ENCODE_CONTINUE (*bs)
+    if (bits)
+    DELTA_ENCODE_L (val, *bits);
+  else
+    DELTA_ENCODE (val);
+  ENCODE_PAUSE (*bs)
+}
+
+
+unsigned long 
+BIO_Stdio_Delta_Decode (stdio_bitio_state * bs,
+			unsigned long *bits)
+{
+  register unsigned long val;
+  DECODE_CONTINUE (*bs)
+    if (bits)
+    DELTA_DECODE_L (val, *bits);
+  else
+    DELTA_DECODE (val);
+  DECODE_PAUSE (*bs)
+    return (val);
+}
+
+
+
+
+void 
+BIO_Stdio_Elias_Encode (unsigned long val, unsigned long b, double s,
+			stdio_bitio_state * bs, unsigned long *bits)
+{
+  ENCODE_CONTINUE (*bs)
+    if (bits)
+    ELIAS_ENCODE_L (val, b, s, *bits);
+  else
+    ELIAS_ENCODE (val, b, s);
+  ENCODE_PAUSE (*bs)
+}
+
+
+unsigned long 
+BIO_Stdio_Elias_Decode (unsigned long b, double s,
+			stdio_bitio_state * bs,
+			unsigned long *bits)
+{
+  register unsigned long val;
+  DECODE_CONTINUE (*bs)
+    if (bits)
+    ELIAS_DECODE_L (val, b, s, *bits);
+  else
+    ELIAS_DECODE (val, b, s);
+  DECODE_PAUSE (*bs)
+    return (val);
+}
+
+
+
+void 
+BIO_Stdio_Bblock_Encode (unsigned long val, unsigned long b,
+			 stdio_bitio_state * bs, unsigned long *bits)
+{
+  ENCODE_CONTINUE (*bs)
+    if (bits)
+    BBLOCK_ENCODE_L (val, b, *bits);
+  else
+    BBLOCK_ENCODE (val, b);
+  ENCODE_PAUSE (*bs)
+}
+
+
+unsigned long 
+BIO_Stdio_Bblock_Decode (unsigned long b, stdio_bitio_state * bs,
+			 unsigned long *bits)
+{
+  register unsigned long val;
+  DECODE_CONTINUE (*bs)
+    if (bits)
+    BBLOCK_DECODE_L (val, b, *bits);
+  else
+    BBLOCK_DECODE (val, b);
+  DECODE_PAUSE (*bs)
+    return (val);
+}
+
+void 
+BIO_Stdio_Decode_Seek (unsigned long pos, stdio_bitio_state * bs)
+{
+  DECODE_CONTINUE (*bs)
+    DECODE_SEEK (pos);
+  DECODE_PAUSE (*bs)
+}
Index: /main/tags/2.25/gsdl/packages/mg/lib/bitio_stdio.h
===================================================================
--- /main/tags/2.25/gsdl/packages/mg/lib/bitio_stdio.h	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/mg/lib/bitio_stdio.h	(revision 21064)
@@ -0,0 +1,106 @@
+/**************************************************************************
+ *
+ * bitio_stdio.h -- Functions for bitio to a file
+ * Copyright (C) 1994  Neil Sharman
+ *
+ * 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.
+ *
+ * $Id$
+ *
+ **************************************************************************
+ *
+ *  This file contains function definitions for doing bitwise input and output
+ *  of number on a FILE*. With these function you cannot mix reads and writes
+ *  on the FILE, or multiple writes, at the same time and guarantee them to 
+ *  work, also you  cannot seek to a point and do a write. The decode function
+ *  can detect when you run off the end of the file and will produce an 
+ *  approate error message.
+ *
+ *
+ **************************************************************************/
+
+#ifndef H_BITIO_STDIO
+#define H_BITIO_STDIO
+
+
+typedef struct stdio_bitio_state
+  {
+    FILE *File;
+    unsigned char Buff;
+    unsigned char Btg;
+  }
+stdio_bitio_state;
+
+
+/* NOTE : All bytes are filled high bit first */
+
+
+void BIO_Stdio_Encode_Start (FILE * f, stdio_bitio_state * bs);
+void BIO_Stdio_Encode_Done (stdio_bitio_state * bs);
+
+
+
+void BIO_Stdio_Decode_Start (FILE * f, stdio_bitio_state * bs);
+
+
+
+void BIO_Stdio_Encode_Bit (int bit, stdio_bitio_state * bs);
+int BIO_Stdio_Decode_Bit (stdio_bitio_state * bs);
+
+
+void BIO_Stdio_Unary_Encode (unsigned long val, stdio_bitio_state * bs,
+			     unsigned long *bits);
+unsigned long BIO_Stdio_Unary_Decode (stdio_bitio_state * bs,
+				      unsigned long *bits);
+
+
+
+void BIO_Stdio_Binary_Encode (unsigned long val, unsigned long b,
+			      stdio_bitio_state * bs, unsigned long *bits);
+unsigned long BIO_Stdio_Binary_Decode (unsigned long b, stdio_bitio_state * bs,
+				       unsigned long *bits);
+
+
+
+void BIO_Stdio_Gamma_Encode (unsigned long val, stdio_bitio_state * bs,
+			     unsigned long *bits);
+unsigned long BIO_Stdio_Gamma_Decode (stdio_bitio_state * bs,
+				      unsigned long *bits);
+
+
+
+void BIO_Stdio_Delta_Encode (unsigned long val, stdio_bitio_state * bs,
+			     unsigned long *bits);
+unsigned long BIO_Stdio_Delta_Decode (stdio_bitio_state * bs,
+				      unsigned long *bits);
+
+
+
+void BIO_Stdio_Elias_Encode (unsigned long val, unsigned long b, double s,
+			     stdio_bitio_state * bs, unsigned long *bits);
+unsigned long BIO_Stdio_Elias_Decode (unsigned long b, double s,
+				      stdio_bitio_state * bs,
+				      unsigned long *bits);
+
+
+void BIO_Stdio_Bblock_Encode (unsigned long val, unsigned long b,
+			      stdio_bitio_state * bs, unsigned long *bits);
+unsigned long BIO_Stdio_Bblock_Decode (unsigned long b, stdio_bitio_state * bs,
+				       unsigned long *bits);
+
+
+void BIO_Stdio_Decode_Seek (unsigned long pos, stdio_bitio_state * bs);
+
+#endif
Index: /main/tags/2.25/gsdl/packages/mg/lib/error.c
===================================================================
--- /main/tags/2.25/gsdl/packages/mg/lib/error.c	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/mg/lib/error.c	(revision 21064)
@@ -0,0 +1,127 @@
+/* error.c -- error handler for noninteractive utilities
+   Copyright (C) 1990, 91, 92, 93, 94 Free Software Foundation, Inc.
+
+   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, 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.  */
+
+/* Written by David MacKenzie <djm@gnu.ai.mit.edu>.  */
+
+#ifdef HAVE_CONFIG_H
+# ifdef __WIN32__  /* [RPAP - Feb 97: WIN32 Port] */
+#  include <win32cfg.h>
+# else
+#  include <sysfuncs.h>
+# endif
+#endif
+
+#include <stdio.h>
+
+#if HAVE_VPRINTF || HAVE_DOPRNT
+# if __STDC__
+#  include <stdarg.h>
+#  define VA_START(args, lastarg) va_start(args, lastarg)
+# else
+#  include <varargs.h>
+#  define VA_START(args, lastarg) va_start(args)
+# endif
+#else
+# define va_alist a1, a2, a3, a4, a5, a6, a7, a8
+# define va_dcl char *a1, *a2, *a3, *a4, *a5, *a6, *a7, *a8;
+#endif
+
+#if STDC_HEADERS
+# include <stdlib.h>
+# include <string.h>
+#else
+void exit ();
+#endif
+
+/* If NULL, error will flush stdout, then print on stderr the program
+   name, a colon and a space.  Otherwise, error will call this
+   function without parameters instead.  */
+void (*error_print_progname) () = NULL;
+
+/* The calling program should define program_name and set it to the
+   name of the executing program.  */
+#if 0 /* [RB/TS:10/95] do not use program_name */
+extern char *program_name;
+#endif
+
+#if HAVE_STRERROR
+char *strerror (int errnum);
+#else
+static char *
+private_strerror (errnum)
+     int errnum;
+{
+  extern char *sys_errlist[];
+  extern int sys_nerr;
+
+  if (errnum > 0 && errnum <= sys_nerr)
+    return sys_errlist[errnum];
+  return "Unknown system error";
+}
+#define strerror private_strerror
+#endif
+
+/* Print the program name and error message MESSAGE, which is a printf-style
+   format string with optional args.
+   If ERRNUM is nonzero, print its corresponding system error message.
+   Exit with status STATUS if it is nonzero.  */
+/* VARARGS */
+
+void
+#if defined(VA_START) && __STDC__
+error (int status, int errnum, const char *message, ...)
+#else
+error (status, errnum, message, va_alist)
+     int status;
+     int errnum;
+     char *message;
+     va_dcl
+#endif
+{
+#ifdef VA_START
+  va_list args;
+#endif
+
+  if (error_print_progname)
+    (*error_print_progname) ();
+  else
+    {
+      fflush (stdout);
+#if 0 /* [RB/TS:10/95] do not use program_name */
+      fprintf (stderr, "%s: ", program_name);
+#endif
+    }
+
+#ifdef VA_START
+  VA_START (args, message);
+# if HAVE_VPRINTF
+  vfprintf (stderr, message, args);
+# else
+  _doprnt (message, args, stderr);
+# endif
+  va_end (args);
+#else
+  fprintf (stderr, message, a1, a2, a3, a4, a5, a6, a7, a8);
+#endif
+
+  if (errnum)
+    fprintf (stderr, ": %s", strerror (errnum));
+  putc ('\n', stderr);
+  fflush (stderr);
+  if (status)
+    exit (status);
+}
Index: /main/tags/2.25/gsdl/packages/mg/lib/filestats.c
===================================================================
--- /main/tags/2.25/gsdl/packages/mg/lib/filestats.c	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/mg/lib/filestats.c	(revision 21064)
@@ -0,0 +1,133 @@
+/**************************************************************************
+ *
+ * filestats.c -- Functions for keeping stats on file accesses
+ * Copyright (C) 1994  Neil Sharman
+ *
+ * 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.
+ *
+ * $Id$
+ *
+ **************************************************************************/
+
+
+/*
+   $Log$
+   Revision 1.1  1999/08/10 21:16:48  sjboddie
+   renamed mg-1.3d directory mg
+
+   Revision 1.1  1998/11/17 09:31:54  rjmcnab
+   *** empty log message ***
+
+   * Revision 1.1  1994/08/22  00:24:42  tes
+   * Initial placement under CVS.
+   *
+ */
+
+static char *RCSID = "$Id$";
+
+#include "sysfuncs.h"
+
+#include "memlib.h"
+#include "filestats.h"
+#include "netorder.h"  /* [RPAP - Jan 97: Endian Ordering] */
+
+
+File *
+Fopen (char *name, char *mode, unsigned long magic)
+{
+  FILE *f;
+  File *F;
+  unsigned long m;
+  if (!(f = fopen (name, mode)))
+    return (NULL);
+  if (magic)
+    switch (*mode)
+      {
+      case 'r':
+	fread ((char *) &m, sizeof (m), 1, f);
+	NTOHUL(m);  /* [RPAP - Jan 97: Endian Ordering] */
+	if (m != magic)
+	  {
+	    fclose (f);
+	    return (NULL);
+	  }
+	break;
+      case 'w':
+	HTONUL(magic);  /* [RPAP - Jan 97: Endian Ordering] */
+	fwrite ((char *) &magic, sizeof (magic), 1, f);
+      }
+  if (!(F = Xmalloc (sizeof (File))))
+    {
+      fclose (f);
+      return (NULL);
+    }
+  F->pathname = Xstrdup (name);
+  F->name = strrchr (F->pathname, '/');
+  F->name = F->name ? F->name + 1 : F->pathname;
+  F->f = f;
+  F->Current.NumSeeks = F->Current.NumReads = F->Current.NumBytes = 0;
+  F->Cumulative = F->Current;
+  return (F);
+}
+
+
+int 
+Fclose (File * F)
+{
+  int num;
+  if (!F)
+    return (0);
+  num = fclose (F->f);
+  if (F->pathname)
+    Xfree (F->pathname);
+  Xfree (F);
+  return (num);
+}
+
+size_t 
+Fread (void *ptr, size_t size, size_t nitems, File * F)
+{
+  int num;
+  num = fread ((char *) ptr, size, nitems, F->f);
+  F->Current.NumReads++;
+  F->Current.NumBytes += num * size;
+  return (num);
+}
+
+int 
+Fseek (File * F, long offset, int ptrname)
+{
+  int num;
+  num = fseek (F->f, offset, ptrname);
+  F->Current.NumSeeks++;
+  return (num);
+}
+
+void 
+Rewind (File * F)
+{
+  rewind (F->f);
+  F->Current.NumSeeks++;
+}
+
+
+void 
+ZeroFileStats (File * F)
+{
+  F->Cumulative.NumSeeks += F->Current.NumSeeks;
+  F->Cumulative.NumReads += F->Current.NumReads;
+  F->Cumulative.NumBytes += F->Current.NumBytes;
+  F->Current.NumSeeks = F->Current.NumReads = F->Current.NumBytes = 0;
+}
Index: /main/tags/2.25/gsdl/packages/mg/lib/filestats.h
===================================================================
--- /main/tags/2.25/gsdl/packages/mg/lib/filestats.h	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/mg/lib/filestats.h	(revision 21064)
@@ -0,0 +1,67 @@
+/**************************************************************************
+ *
+ * filestats.h -- Functions for keeping stats on file accesses
+ * Copyright (C) 1994  Neil Sharman
+ *
+ * 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.
+ *
+ * $Id$
+ *
+ **************************************************************************/
+
+#ifndef H_FILESTATS
+#define H_FILESTATS
+
+#include "sysfuncs.h"
+
+typedef struct FileStats
+  {
+    unsigned long NumSeeks;
+    unsigned long NumReads;
+    unsigned long NumBytes;
+  }
+FileStats;
+
+
+
+typedef struct
+  {
+    FILE *f;
+    char *pathname;
+    char *name;
+    FileStats Current;
+    FileStats Cumulative;
+  }
+File;
+
+/* if magic is 0 no magic number is read or written */
+File *Fopen (char *name, char *mode, unsigned long magic);
+
+size_t Fread (void *ptr, size_t size, size_t nitems, File * F);
+
+int Fseek (File * F, long offset, int ptrname);
+
+void Rewind (File * F);
+
+int Fclose (File * F);
+
+#define Getc(F) (F->Current.NumReads++, F->Current.NumBytes++, getc(F->f))
+
+/* This adds the Current file stats to the Cumulative stats and then zeros
+   the Current stats */
+void ZeroFileStats (File * F);
+
+
+#endif
Index: /main/tags/2.25/gsdl/packages/mg/lib/ftruncate.c
===================================================================
--- /main/tags/2.25/gsdl/packages/mg/lib/ftruncate.c	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/mg/lib/ftruncate.c	(revision 21064)
@@ -0,0 +1,107 @@
+/* ftruncate emulations that work on some System V's.
+   This file is in the public domain.  */
+
+#ifdef HAVE_CONFIG_H
+# ifdef __WIN32__  /* [RPAP - Feb 97: WIN32 Port] */
+#  include <win32cfg.h>
+# else
+#  include <sysfuncs.h>
+# endif
+#endif
+
+#include <sys/types.h>
+#include <fcntl.h>
+
+#ifdef F_CHSIZE
+
+int
+ftruncate (fd, length)
+     int fd;
+     off_t length;
+{
+  return fcntl (fd, F_CHSIZE, length);
+}
+
+#else /* not F_CHSIZE */
+#ifdef F_FREESP
+
+/* By William Kucharski <kucharsk@netcom.com>.  */
+
+#include <sys/stat.h>
+#include <errno.h>
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+
+int
+ftruncate (fd, length)
+     int fd;
+     off_t length;
+{
+  struct flock fl;
+  struct stat filebuf;
+
+  if (fstat (fd, &filebuf) < 0)
+    return -1;
+
+  if (filebuf.st_size < length)
+    {
+      /* Extend file length. */
+      if (lseek (fd, (length - 1), SEEK_SET) < 0)
+	return -1;
+
+      /* Write a "0" byte. */
+      if (write (fd, "", 1) != 1)
+	return -1;
+    }
+  else
+    {
+
+      /* Truncate length. */
+
+      fl.l_whence = 0;
+      fl.l_len = 0;
+      fl.l_start = length;
+      fl.l_type = F_WRLCK;	/* write lock on file space */
+
+      /* This relies on the *undocumented* F_FREESP argument to fcntl,
+	 which truncates the file so that it ends at the position
+	 indicated by fl.l_start.  Will minor miracles never cease?  */
+
+      if (fcntl (fd, F_FREESP, &fl) < 0)
+	return -1;
+    }
+
+  return 0;
+}
+
+#else /* not F_CHSIZE nor F_FREESP */
+#ifdef HAVE_CHSIZE
+
+int
+ftruncate (fd, length)
+     int fd;
+     off_t length;
+{
+  return chsize (fd, length);
+}
+
+#else /* not F_CHSIZE nor F_FREESP nor HAVE_CHSIZE */
+
+#include <errno.h>
+#ifndef errno
+extern int errno;
+#endif
+
+int
+ftruncate (fd, length)
+     int fd;
+     off_t length;
+{
+  errno = EIO;
+  return -1;
+}
+
+#endif /* not HAVE_CHSIZE */
+#endif /* not F_FREESP */
+#endif /* not F_CHSIZE */
Index: /main/tags/2.25/gsdl/packages/mg/lib/getopt.c
===================================================================
--- /main/tags/2.25/gsdl/packages/mg/lib/getopt.c	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/mg/lib/getopt.c	(revision 21064)
@@ -0,0 +1,750 @@
+/* Getopt for GNU.
+   NOTE: getopt is now part of the C library, so if you don't know what
+   "Keep this file name-space clean" means, talk to roland@gnu.ai.mit.edu
+   before changing it!
+
+   Copyright (C) 1987, 88, 89, 90, 91, 92, 1993
+   Free Software Foundation, Inc.
+
+   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, 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, 675 Mass Ave, Cambridge, MA 02139, USA.  */
+
+
+#ifdef HAVE_CONFIG_H
+#include "sysfuncs.h"
+#endif
+
+#if !__STDC__ && !defined(const) && IN_GCC
+#define const
+#endif
+
+/* This tells Alpha OSF/1 not to define a getopt prototype in <stdio.h>.  */
+#ifndef _NO_PROTO
+#define _NO_PROTO
+#endif
+
+#include <stdio.h>
+
+/* Comment out all this code if we are using the GNU C Library, and are not
+   actually compiling the library itself.  This code is part of the GNU C
+   Library, but also included in many other GNU distributions.  Compiling
+   and linking in this code is a waste when using the GNU C library
+   (especially if it is a shared library).  Rather than having every GNU
+   program understand `configure --with-gnu-libc' and omit the object files,
+   it is simpler to just do this in the source for each such file.  */
+
+#if defined (_LIBC) || !defined (__GNU_LIBRARY__)
+
+
+/* This needs to come after some library #include
+   to get __GNU_LIBRARY__ defined.  */
+#ifdef	__GNU_LIBRARY__
+/* Don't include stdlib.h for non-GNU C libraries because some of them
+   contain conflicting prototypes for getopt.  */
+#include <stdlib.h>
+#endif /* GNU C library.  */
+
+/* If GETOPT_COMPAT is defined, `+' as well as `--' can introduce a
+   long-named option.  Because this is not POSIX.2 compliant, it is
+   being phased out.  */
+/* #define GETOPT_COMPAT */
+
+/* This version of `getopt' appears to the caller like standard Unix `getopt'
+   but it behaves differently for the user, since it allows the user
+   to intersperse the options with the other arguments.
+
+   As `getopt' works, it permutes the elements of ARGV so that,
+   when it is done, all the options precede everything else.  Thus
+   all application programs are extended to handle flexible argument order.
+
+   Setting the environment variable POSIXLY_CORRECT disables permutation.
+   Then the behavior is completely standard.
+
+   GNU application programs can use a third alternative mode in which
+   they can distinguish the relative order of options and other arguments.  */
+
+#include "getopt.h"
+
+/* For communication from `getopt' to the caller.
+   When `getopt' finds an option that takes an argument,
+   the argument value is returned here.
+   Also, when `ordering' is RETURN_IN_ORDER,
+   each non-option ARGV-element is returned here.  */
+
+char *optarg = 0;
+
+/* Index in ARGV of the next element to be scanned.
+   This is used for communication to and from the caller
+   and for communication between successive calls to `getopt'.
+
+   On entry to `getopt', zero means this is the first call; initialize.
+
+   When `getopt' returns EOF, this is the index of the first of the
+   non-option elements that the caller should itself scan.
+
+   Otherwise, `optind' communicates from one call to the next
+   how much of ARGV has been scanned so far.  */
+
+/* XXX 1003.2 says this must be 1 before any call.  */
+int optind = 0;
+
+/* The next char to be scanned in the option-element
+   in which the last option character we returned was found.
+   This allows us to pick up the scan where we left off.
+
+   If this is zero, or a null string, it means resume the scan
+   by advancing to the next ARGV-element.  */
+
+static char *nextchar;
+
+/* Callers store zero here to inhibit the error message
+   for unrecognized options.  */
+
+int opterr = 1;
+
+/* Set to an option character which was unrecognized.
+   This must be initialized on some systems to avoid linking in the
+   system's own getopt implementation.  */
+
+int optopt = '?';
+
+/* Describe how to deal with options that follow non-option ARGV-elements.
+
+   If the caller did not specify anything,
+   the default is REQUIRE_ORDER if the environment variable
+   POSIXLY_CORRECT is defined, PERMUTE otherwise.
+
+   REQUIRE_ORDER means don't recognize them as options;
+   stop option processing when the first non-option is seen.
+   This is what Unix does.
+   This mode of operation is selected by either setting the environment
+   variable POSIXLY_CORRECT, or using `+' as the first character
+   of the list of option characters.
+
+   PERMUTE is the default.  We permute the contents of ARGV as we scan,
+   so that eventually all the non-options are at the end.  This allows options
+   to be given in any order, even with programs that were not written to
+   expect this.
+
+   RETURN_IN_ORDER is an option available to programs that were written
+   to expect options and other ARGV-elements in any order and that care about
+   the ordering of the two.  We describe each non-option ARGV-element
+   as if it were the argument of an option with character code 1.
+   Using `-' as the first character of the list of option characters
+   selects this mode of operation.
+
+   The special argument `--' forces an end of option-scanning regardless
+   of the value of `ordering'.  In the case of RETURN_IN_ORDER, only
+   `--' can cause `getopt' to return EOF with `optind' != ARGC.  */
+
+static enum
+  {
+    REQUIRE_ORDER, PERMUTE, RETURN_IN_ORDER
+  }
+ordering;
+
+
+#ifdef	__GNU_LIBRARY__
+/* We want to avoid inclusion of string.h with non-GNU libraries
+   because there are many ways it can cause trouble.
+   On some systems, it contains special magic macros that don't work
+   in GCC.  */
+#include <string.h>
+#define	my_index	strchr
+#else
+
+/* Avoid depending on library functions or files
+   whose names are inconsistent.  */
+
+char *getenv ();
+
+static char *
+my_index (str, chr)
+     const char *str;
+     int chr;
+{
+  while (*str)
+    {
+      if (*str == chr)
+	return (char *) str;
+      str++;
+    }
+  return 0;
+}
+
+/* If using GCC, we can safely declare strlen this way.
+   If not using GCC, it is ok not to declare it.  */
+#ifdef __GNUC__
+#ifdef IN_GCC
+#include "gstddef.h"
+#else
+#include <stddef.h>
+#endif
+extern size_t strlen (const char *);
+#endif
+
+#endif /* GNU C library.  */
+
+
+/* Handle permutation of arguments.  */
+
+/* Describe the part of ARGV that contains non-options that have
+   been skipped.  `first_nonopt' is the index in ARGV of the first of them;
+   `last_nonopt' is the index after the last of them.  */
+
+static int first_nonopt;
+static int last_nonopt;
+
+/* Exchange two adjacent subsequences of ARGV.
+   One subsequence is elements [first_nonopt,last_nonopt)
+   which contains all the non-options that have been skipped so far.
+   The other is elements [last_nonopt,optind), which contains all
+   the options processed since those non-options were skipped.
+
+   `first_nonopt' and `last_nonopt' are relocated so that they describe
+   the new indices of the non-options in ARGV after they are moved.  */
+
+static void
+exchange (argv)
+     char **argv;
+{
+  int bottom = first_nonopt;
+  int middle = last_nonopt;
+  int top = optind;
+  char *tem;
+
+  /* Exchange the shorter segment with the far end of the longer segment.
+     That puts the shorter segment into the right place.
+     It leaves the longer segment in the right place overall,
+     but it consists of two parts that need to be swapped next.  */
+
+  while (top > middle && middle > bottom)
+    {
+      if (top - middle > middle - bottom)
+	{
+	  /* Bottom segment is the short one.  */
+	  int len = middle - bottom;
+	  register int i;
+
+	  /* Swap it with the top part of the top segment.  */
+	  for (i = 0; i < len; i++)
+	    {
+	      tem = argv[bottom + i];
+	      argv[bottom + i] = argv[top - (middle - bottom) + i];
+	      argv[top - (middle - bottom) + i] = tem;
+	    }
+	  /* Exclude the moved bottom segment from further swapping.  */
+	  top -= len;
+	}
+      else
+	{
+	  /* Top segment is the short one.  */
+	  int len = top - middle;
+	  register int i;
+
+	  /* Swap it with the bottom part of the bottom segment.  */
+	  for (i = 0; i < len; i++)
+	    {
+	      tem = argv[bottom + i];
+	      argv[bottom + i] = argv[middle + i];
+	      argv[middle + i] = tem;
+	    }
+	  /* Exclude the moved top segment from further swapping.  */
+	  bottom += len;
+	}
+    }
+
+  /* Update records for the slots the non-options now occupy.  */
+
+  first_nonopt += (optind - last_nonopt);
+  last_nonopt = optind;
+}
+
+
+/* Scan elements of ARGV (whose length is ARGC) for option characters
+   given in OPTSTRING.
+
+   If an element of ARGV starts with '-', and is not exactly "-" or "--",
+   then it is an option element.  The characters of this element
+   (aside from the initial '-') are option characters.  If `getopt'
+   is called repeatedly, it returns successively each of the option characters
+   from each of the option elements.
+
+   If `getopt' finds another option character, it returns that character,
+   updating `optind' and `nextchar' so that the next call to `getopt' can
+   resume the scan with the following option character or ARGV-element.
+
+   If there are no more option characters, `getopt' returns `EOF'.
+   Then `optind' is the index in ARGV of the first ARGV-element
+   that is not an option.  (The ARGV-elements have been permuted
+   so that those that are not options now come last.)
+
+   OPTSTRING is a string containing the legitimate option characters.
+   If an option character is seen that is not listed in OPTSTRING,
+   return '?' after printing an error message.  If you set `opterr' to
+   zero, the error message is suppressed but we still return '?'.
+
+   If a char in OPTSTRING is followed by a colon, that means it wants an arg,
+   so the following text in the same ARGV-element, or the text of the following
+   ARGV-element, is returned in `optarg'.  Two colons mean an option that
+   wants an optional arg; if there is text in the current ARGV-element,
+   it is returned in `optarg', otherwise `optarg' is set to zero.
+
+   If OPTSTRING starts with `-' or `+', it requests different methods of
+   handling the non-option ARGV-elements.
+   See the comments about RETURN_IN_ORDER and REQUIRE_ORDER, above.
+
+   Long-named options begin with `--' instead of `-'.
+   Their names may be abbreviated as long as the abbreviation is unique
+   or is an exact match for some defined option.  If they have an
+   argument, it follows the option name in the same ARGV-element, separated
+   from the option name by a `=', or else the in next ARGV-element.
+   When `getopt' finds a long-named option, it returns 0 if that option's
+   `flag' field is nonzero, the value of the option's `val' field
+   if the `flag' field is zero.
+
+   The elements of ARGV aren't really const, because we permute them.
+   But we pretend they're const in the prototype to be compatible
+   with other systems.
+
+   LONGOPTS is a vector of `struct option' terminated by an
+   element containing a name which is zero.
+
+   LONGIND returns the index in LONGOPT of the long-named option found.
+   It is only valid when a long-named option has been found by the most
+   recent call.
+
+   If LONG_ONLY is nonzero, '-' as well as '--' can introduce
+   long-named options.  */
+
+int
+_getopt_internal (argc, argv, optstring, longopts, longind, long_only)
+     int argc;
+     char *const *argv;
+     const char *optstring;
+     const struct option *longopts;
+     int *longind;
+     int long_only;
+{
+  int option_index;
+
+  optarg = 0;
+
+  /* Initialize the internal data when the first call is made.
+     Start processing options with ARGV-element 1 (since ARGV-element 0
+     is the program name); the sequence of previously skipped
+     non-option ARGV-elements is empty.  */
+
+  if (optind == 0)
+    {
+      first_nonopt = last_nonopt = optind = 1;
+
+      nextchar = NULL;
+
+      /* Determine how to handle the ordering of options and nonoptions.  */
+
+      if (optstring[0] == '-')
+	{
+	  ordering = RETURN_IN_ORDER;
+	  ++optstring;
+	}
+      else if (optstring[0] == '+')
+	{
+	  ordering = REQUIRE_ORDER;
+	  ++optstring;
+	}
+      else if (getenv ("POSIXLY_CORRECT") != NULL)
+	ordering = REQUIRE_ORDER;
+      else
+	ordering = PERMUTE;
+    }
+
+  if (nextchar == NULL || *nextchar == '\0')
+    {
+      if (ordering == PERMUTE)
+	{
+	  /* If we have just processed some options following some non-options,
+	     exchange them so that the options come first.  */
+
+	  if (first_nonopt != last_nonopt && last_nonopt != optind)
+	    exchange ((char **) argv);
+	  else if (last_nonopt != optind)
+	    first_nonopt = optind;
+
+	  /* Now skip any additional non-options
+	     and extend the range of non-options previously skipped.  */
+
+	  while (optind < argc
+		 && (argv[optind][0] != '-' || argv[optind][1] == '\0')
+#ifdef GETOPT_COMPAT
+		 && (longopts == NULL
+		     || argv[optind][0] != '+' || argv[optind][1] == '\0')
+#endif /* GETOPT_COMPAT */
+	    )
+	    optind++;
+	  last_nonopt = optind;
+	}
+
+      /* Special ARGV-element `--' means premature end of options.
+         Skip it like a null option,
+         then exchange with previous non-options as if it were an option,
+         then skip everything else like a non-option.  */
+
+      if (optind != argc && !strcmp (argv[optind], "--"))
+	{
+	  optind++;
+
+	  if (first_nonopt != last_nonopt && last_nonopt != optind)
+	    exchange ((char **) argv);
+	  else if (first_nonopt == last_nonopt)
+	    first_nonopt = optind;
+	  last_nonopt = argc;
+
+	  optind = argc;
+	}
+
+      /* If we have done all the ARGV-elements, stop the scan
+         and back over any non-options that we skipped and permuted.  */
+
+      if (optind == argc)
+	{
+	  /* Set the next-arg-index to point at the non-options
+	     that we previously skipped, so the caller will digest them.  */
+	  if (first_nonopt != last_nonopt)
+	    optind = first_nonopt;
+	  return EOF;
+	}
+
+      /* If we have come to a non-option and did not permute it,
+         either stop the scan or describe it to the caller and pass it by.  */
+
+      if ((argv[optind][0] != '-' || argv[optind][1] == '\0')
+#ifdef GETOPT_COMPAT
+	  && (longopts == NULL
+	      || argv[optind][0] != '+' || argv[optind][1] == '\0')
+#endif /* GETOPT_COMPAT */
+	)
+	{
+	  if (ordering == REQUIRE_ORDER)
+	    return EOF;
+	  optarg = argv[optind++];
+	  return 1;
+	}
+
+      /* We have found another option-ARGV-element.
+         Start decoding its characters.  */
+
+      nextchar = (argv[optind] + 1
+		  + (longopts != NULL && argv[optind][1] == '-'));
+    }
+
+  if (longopts != NULL
+      && ((argv[optind][0] == '-'
+	   && (argv[optind][1] == '-' || long_only))
+#ifdef GETOPT_COMPAT
+	  || argv[optind][0] == '+'
+#endif /* GETOPT_COMPAT */
+      ))
+    {
+      const struct option *p;
+      char *s = nextchar;
+      int exact = 0;
+      int ambig = 0;
+      const struct option *pfound = NULL;
+      int indfound;
+
+      while (*s && *s != '=')
+	s++;
+
+      /* Test all options for either exact match or abbreviated matches.  */
+      for (p = longopts, option_index = 0; p->name;
+	   p++, option_index++)
+	if (!strncmp (p->name, nextchar, s - nextchar))
+	  {
+	    if (s - nextchar == strlen (p->name))
+	      {
+		/* Exact match found.  */
+		pfound = p;
+		indfound = option_index;
+		exact = 1;
+		break;
+	      }
+	    else if (pfound == NULL)
+	      {
+		/* First nonexact match found.  */
+		pfound = p;
+		indfound = option_index;
+	      }
+	    else
+	      /* Second nonexact match found.  */
+	      ambig = 1;
+	  }
+
+      if (ambig && !exact)
+	{
+	  if (opterr)
+	    fprintf (stderr, "%s: option `%s' is ambiguous\n",
+		     argv[0], argv[optind]);
+	  nextchar += strlen (nextchar);
+	  optind++;
+	  return '?';
+	}
+
+      if (pfound != NULL)
+	{
+	  option_index = indfound;
+	  optind++;
+	  if (*s)
+	    {
+	      /* Don't test has_arg with >, because some C compilers don't
+	         allow it to be used on enums.  */
+	      if (pfound->has_arg)
+		optarg = s + 1;
+	      else
+		{
+		  if (opterr)
+		    {
+		      if (argv[optind - 1][1] == '-')
+			/* --option */
+			fprintf (stderr,
+			    "%s: option `--%s' doesn't allow an argument\n",
+				 argv[0], pfound->name);
+		      else
+			/* +option or -option */
+			fprintf (stderr,
+			    "%s: option `%c%s' doesn't allow an argument\n",
+				 argv[0], argv[optind - 1][0], pfound->name);
+		    }
+		  nextchar += strlen (nextchar);
+		  return '?';
+		}
+	    }
+	  else if (pfound->has_arg == 1)
+	    {
+	      if (optind < argc)
+		optarg = argv[optind++];
+	      else
+		{
+		  if (opterr)
+		    fprintf (stderr, "%s: option `%s' requires an argument\n",
+			     argv[0], argv[optind - 1]);
+		  nextchar += strlen (nextchar);
+		  return optstring[0] == ':' ? ':' : '?';
+		}
+	    }
+	  nextchar += strlen (nextchar);
+	  if (longind != NULL)
+	    *longind = option_index;
+	  if (pfound->flag)
+	    {
+	      *(pfound->flag) = pfound->val;
+	      return 0;
+	    }
+	  return pfound->val;
+	}
+      /* Can't find it as a long option.  If this is not getopt_long_only,
+         or the option starts with '--' or is not a valid short
+         option, then it's an error.
+         Otherwise interpret it as a short option.  */
+      if (!long_only || argv[optind][1] == '-'
+#ifdef GETOPT_COMPAT
+	  || argv[optind][0] == '+'
+#endif /* GETOPT_COMPAT */
+	  || my_index (optstring, *nextchar) == NULL)
+	{
+	  if (opterr)
+	    {
+	      if (argv[optind][1] == '-')
+		/* --option */
+		fprintf (stderr, "%s: unrecognized option `--%s'\n",
+			 argv[0], nextchar);
+	      else
+		/* +option or -option */
+		fprintf (stderr, "%s: unrecognized option `%c%s'\n",
+			 argv[0], argv[optind][0], nextchar);
+	    }
+	  nextchar = (char *) "";
+	  optind++;
+	  return '?';
+	}
+    }
+
+  /* Look at and handle the next option-character.  */
+
+  {
+    char c = *nextchar++;
+    char *temp = my_index (optstring, c);
+
+    /* Increment `optind' when we start to process its last character.  */
+    if (*nextchar == '\0')
+      ++optind;
+
+    if (temp == NULL || c == ':')
+      {
+	if (opterr)
+	  {
+#if 0
+	    if (c < 040 || c >= 0177)
+	      fprintf (stderr, "%s: unrecognized option, character code 0%o\n",
+		       argv[0], c);
+	    else
+	      fprintf (stderr, "%s: unrecognized option `-%c'\n", argv[0], c);
+#else
+	    /* 1003.2 specifies the format of this message.  */
+	    fprintf (stderr, "%s: illegal option -- %c\n", argv[0], c);
+#endif
+	  }
+	optopt = c;
+	return '?';
+      }
+    if (temp[1] == ':')
+      {
+	if (temp[2] == ':')
+	  {
+	    /* This is an option that accepts an argument optionally.  */
+	    if (*nextchar != '\0')
+	      {
+		optarg = nextchar;
+		optind++;
+	      }
+	    else
+	      optarg = 0;
+	    nextchar = NULL;
+	  }
+	else
+	  {
+	    /* This is an option that requires an argument.  */
+	    if (*nextchar != '\0')
+	      {
+		optarg = nextchar;
+		/* If we end this ARGV-element by taking the rest as an arg,
+		   we must advance to the next element now.  */
+		optind++;
+	      }
+	    else if (optind == argc)
+	      {
+		if (opterr)
+		  {
+#if 0
+		    fprintf (stderr, "%s: option `-%c' requires an argument\n",
+			     argv[0], c);
+#else
+		    /* 1003.2 specifies the format of this message.  */
+		    fprintf (stderr, "%s: option requires an argument -- %c\n",
+			     argv[0], c);
+#endif
+		  }
+		optopt = c;
+		if (optstring[0] == ':')
+		  c = ':';
+		else
+		  c = '?';
+	      }
+	    else
+	      /* We already incremented `optind' once;
+	         increment it again when taking next ARGV-elt as argument.  */
+	      optarg = argv[optind++];
+	    nextchar = NULL;
+	  }
+      }
+    return c;
+  }
+}
+
+int
+getopt (argc, argv, optstring)
+     int argc;
+     char *const *argv;
+     const char *optstring;
+{
+  return _getopt_internal (argc, argv, optstring,
+			   (const struct option *) 0,
+			   (int *) 0,
+			   0);
+}
+
+#endif /* _LIBC or not __GNU_LIBRARY__.  */
+
+
+#ifdef TEST
+
+/* Compile with -DTEST to make an executable for use in testing
+   the above definition of `getopt'.  */
+
+int
+main (argc, argv)
+     int argc;
+     char **argv;
+{
+  int c;
+  int digit_optind = 0;
+
+  while (1)
+    {
+      int this_option_optind = optind ? optind : 1;
+
+      c = getopt (argc, argv, "abc:d:0123456789");
+      if (c == EOF)
+	break;
+
+      switch (c)
+	{
+	case '0':
+	case '1':
+	case '2':
+	case '3':
+	case '4':
+	case '5':
+	case '6':
+	case '7':
+	case '8':
+	case '9':
+	  if (digit_optind != 0 && digit_optind != this_option_optind)
+	    printf ("digits occur in two different argv-elements.\n");
+	  digit_optind = this_option_optind;
+	  printf ("option %c\n", c);
+	  break;
+
+	case 'a':
+	  printf ("option a\n");
+	  break;
+
+	case 'b':
+	  printf ("option b\n");
+	  break;
+
+	case 'c':
+	  printf ("option c with value `%s'\n", optarg);
+	  break;
+
+	case '?':
+	  break;
+
+	default:
+	  printf ("?? getopt returned character code 0%o ??\n", c);
+	}
+    }
+
+  if (optind < argc)
+    {
+      printf ("non-option ARGV-elements: ");
+      while (optind < argc)
+	printf ("%s ", argv[optind++]);
+      printf ("\n");
+    }
+
+  exit (0);
+}
+
+#endif /* TEST */
Index: /main/tags/2.25/gsdl/packages/mg/lib/getopt.h
===================================================================
--- /main/tags/2.25/gsdl/packages/mg/lib/getopt.h	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/mg/lib/getopt.h	(revision 21064)
@@ -0,0 +1,130 @@
+/* Declarations for getopt.
+   Copyright (C) 1989, 1990, 1991, 1992, 1993 Free Software Foundation, Inc.
+
+   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, 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, 675 Mass Ave, Cambridge, MA 02139, USA.  */
+
+#ifndef _GETOPT_H
+#define _GETOPT_H 1
+
+#ifdef	__cplusplus
+extern "C"
+{
+#endif
+
+/* For communication from `getopt' to the caller.
+   When `getopt' finds an option that takes an argument,
+   the argument value is returned here.
+   Also, when `ordering' is RETURN_IN_ORDER,
+   each non-option ARGV-element is returned here.  */
+
+  extern char *optarg;
+
+/* Index in ARGV of the next element to be scanned.
+   This is used for communication to and from the caller
+   and for communication between successive calls to `getopt'.
+
+   On entry to `getopt', zero means this is the first call; initialize.
+
+   When `getopt' returns EOF, this is the index of the first of the
+   non-option elements that the caller should itself scan.
+
+   Otherwise, `optind' communicates from one call to the next
+   how much of ARGV has been scanned so far.  */
+
+  extern int optind;
+
+/* Callers store zero here to inhibit the error message `getopt' prints
+   for unrecognized options.  */
+
+  extern int opterr;
+
+/* Set to an option character which was unrecognized.  */
+
+  extern int optopt;
+
+/* Describe the long-named options requested by the application.
+   The LONG_OPTIONS argument to getopt_long or getopt_long_only is a vector
+   of `struct option' terminated by an element containing a name which is
+   zero.
+
+   The field `has_arg' is:
+   no_argument          (or 0) if the option does not take an argument,
+   required_argument    (or 1) if the option requires an argument,
+   optional_argument    (or 2) if the option takes an optional argument.
+
+   If the field `flag' is not NULL, it points to a variable that is set
+   to the value given in the field `val' when the option is found, but
+   left unchanged if the option is not found.
+
+   To have a long-named option do something other than set an `int' to
+   a compiled-in constant, such as set a value from `optarg', set the
+   option's `flag' field to zero and its `val' field to a nonzero
+   value (the equivalent single-letter option character, if there is
+   one).  For long options that have a zero `flag' field, `getopt'
+   returns the contents of the `val' field.  */
+
+  struct option
+    {
+#if	__STDC__
+      const char *name;
+#else
+      char *name;
+#endif
+      /* has_arg can't be an enum because some compilers complain about
+         type mismatches in all the code that assumes it is an int.  */
+      int has_arg;
+      int *flag;
+      int val;
+    };
+
+/* Names for the values of the `has_arg' field of `struct option'.  */
+
+#define	no_argument		0
+#define required_argument	1
+#define optional_argument	2
+
+#if __STDC__
+#if defined(__GNU_LIBRARY__)
+/* Many other libraries have conflicting prototypes for getopt, with
+   differences in the consts, in stdlib.h.  To avoid compilation
+   errors, only prototype getopt for the GNU C library.  */
+  extern int getopt (int argc, char *const *argv, const char *shortopts);
+#else				/* not __GNU_LIBRARY__ */
+  extern int getopt ();
+#endif				/* not __GNU_LIBRARY__ */
+  extern int getopt_long (int argc, char *const *argv, const char *shortopts,
+			  const struct option *longopts, int *longind);
+  extern int getopt_long_only (int argc, char *const *argv,
+			       const char *shortopts,
+			       const struct option *longopts, int *longind);
+
+/* Internal only.  Users should not call this directly.  */
+  extern int _getopt_internal (int argc, char *const *argv,
+			       const char *shortopts,
+			       const struct option *longopts, int *longind,
+			       int long_only);
+#else				/* not __STDC__ */
+  extern int getopt ();
+  extern int getopt_long ();
+  extern int getopt_long_only ();
+
+  extern int _getopt_internal ();
+#endif				/* not __STDC__ */
+
+#ifdef	__cplusplus
+}
+#endif
+
+#endif				/* _GETOPT_H */
Index: /main/tags/2.25/gsdl/packages/mg/lib/getopt1.c
===================================================================
--- /main/tags/2.25/gsdl/packages/mg/lib/getopt1.c	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/mg/lib/getopt1.c	(revision 21064)
@@ -0,0 +1,178 @@
+/* getopt_long and getopt_long_only entry points for GNU getopt.
+   Copyright (C) 1987, 88, 89, 90, 91, 92, 1993
+   Free Software Foundation, Inc.
+
+   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, 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, 675 Mass Ave, Cambridge, MA 02139, USA.  */
+
+
+#ifdef HAVE_CONFIG_H
+#include "sysfuncs.h"
+#endif
+
+#include "getopt.h"
+
+#if !__STDC__ && !defined(const) && IN_GCC
+#define const
+#endif
+
+#include <stdio.h>
+
+/* Comment out all this code if we are using the GNU C Library, and are not
+   actually compiling the library itself.  This code is part of the GNU C
+   Library, but also included in many other GNU distributions.  Compiling
+   and linking in this code is a waste when using the GNU C library
+   (especially if it is a shared library).  Rather than having every GNU
+   program understand `configure --with-gnu-libc' and omit the object files,
+   it is simpler to just do this in the source for each such file.  */
+
+#if defined (_LIBC) || !defined (__GNU_LIBRARY__)
+
+
+/* This needs to come after some library #include
+   to get __GNU_LIBRARY__ defined.  */
+#ifdef __GNU_LIBRARY__
+#include <stdlib.h>
+#else
+char *getenv ();
+#endif
+
+#ifndef	NULL
+#define NULL 0
+#endif
+
+int
+getopt_long (argc, argv, options, long_options, opt_index)
+     int argc;
+     char *const *argv;
+     const char *options;
+     const struct option *long_options;
+     int *opt_index;
+{
+  return _getopt_internal (argc, argv, options, long_options, opt_index, 0);
+}
+
+/* Like getopt_long, but '-' as well as '--' can indicate a long option.
+   If an option that starts with '-' (not '--') doesn't match a long option,
+   but does match a short option, it is parsed as a short option
+   instead.  */
+
+int
+getopt_long_only (argc, argv, options, long_options, opt_index)
+     int argc;
+     char *const *argv;
+     const char *options;
+     const struct option *long_options;
+     int *opt_index;
+{
+  return _getopt_internal (argc, argv, options, long_options, opt_index, 1);
+}
+
+
+#endif /* _LIBC or not __GNU_LIBRARY__.  */
+
+
+#ifdef TEST
+
+#include <stdio.h>
+
+int
+main (argc, argv)
+     int argc;
+     char **argv;
+{
+  int c;
+  int digit_optind = 0;
+
+  while (1)
+    {
+      int this_option_optind = optind ? optind : 1;
+      int option_index = 0;
+      static struct option long_options[] =
+      {
+	{"add", 1, 0, 0},
+	{"append", 0, 0, 0},
+	{"delete", 1, 0, 0},
+	{"verbose", 0, 0, 0},
+	{"create", 0, 0, 0},
+	{"file", 1, 0, 0},
+	{0, 0, 0, 0}
+      };
+
+      c = getopt_long (argc, argv, "abc:d:0123456789",
+		       long_options, &option_index);
+      if (c == EOF)
+	break;
+
+      switch (c)
+	{
+	case 0:
+	  printf ("option %s", long_options[option_index].name);
+	  if (optarg)
+	    printf (" with arg %s", optarg);
+	  printf ("\n");
+	  break;
+
+	case '0':
+	case '1':
+	case '2':
+	case '3':
+	case '4':
+	case '5':
+	case '6':
+	case '7':
+	case '8':
+	case '9':
+	  if (digit_optind != 0 && digit_optind != this_option_optind)
+	    printf ("digits occur in two different argv-elements.\n");
+	  digit_optind = this_option_optind;
+	  printf ("option %c\n", c);
+	  break;
+
+	case 'a':
+	  printf ("option a\n");
+	  break;
+
+	case 'b':
+	  printf ("option b\n");
+	  break;
+
+	case 'c':
+	  printf ("option c with value `%s'\n", optarg);
+	  break;
+
+	case 'd':
+	  printf ("option d with value `%s'\n", optarg);
+	  break;
+
+	case '?':
+	  break;
+
+	default:
+	  printf ("?? getopt returned character code 0%o ??\n", c);
+	}
+    }
+
+  if (optind < argc)
+    {
+      printf ("non-option ARGV-elements: ");
+      while (optind < argc)
+	printf ("%s ", argv[optind++]);
+      printf ("\n");
+    }
+
+  exit (0);
+}
+
+#endif /* TEST */
Index: /main/tags/2.25/gsdl/packages/mg/lib/getpagesize.h
===================================================================
--- /main/tags/2.25/gsdl/packages/mg/lib/getpagesize.h	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/mg/lib/getpagesize.h	(revision 21064)
@@ -0,0 +1,38 @@
+/* Emulate getpagesize on systems that lack it.  */
+
+#ifndef HAVE_GETPAGESIZE
+
+#ifdef VMS
+#define getpagesize() 512
+#endif
+
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+
+#ifdef _SC_PAGESIZE
+#define getpagesize() sysconf(_SC_PAGESIZE)
+#else
+
+/* [RPAP - Feb 97: WIN32 Port] */
+#ifndef __WIN32__
+#include <sys/param.h>
+#endif
+
+#ifdef EXEC_PAGESIZE
+#define getpagesize() EXEC_PAGESIZE
+#else
+#ifdef NBPG
+#define getpagesize() NBPG * CLSIZE
+#ifndef CLSIZE
+#define CLSIZE 1
+#endif /* no CLSIZE */
+#else /* no NBPG */
+#ifdef NBPC
+#define getpagesize() NBPC
+#endif /* NBPC */
+#endif /* no NBPG */
+#endif /* no EXEC_PAGESIZE */
+#endif /* no _SC_PAGESIZE */
+
+#endif /* not HAVE_GETPAGESIZE */
Index: /main/tags/2.25/gsdl/packages/mg/lib/gmalloc.c
===================================================================
--- /main/tags/2.25/gsdl/packages/mg/lib/gmalloc.c	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/mg/lib/gmalloc.c	(revision 21064)
@@ -0,0 +1,1318 @@
+/* DO NOT EDIT THIS FILE -- it is automagically generated.  -*- C -*- */
+
+#define _MALLOC_INTERNAL
+
+/* The malloc headers and source files from the C library follow here.  */
+
+/* Declarations for `malloc' and friends.
+   Copyright 1990, 1991, 1992, 1993 Free Software Foundation, Inc.
+		  Written May 1989 by Mike Haertel.
+
+This library is free software; you can redistribute it and/or
+modify it under the terms of the GNU Library General Public License as
+published by the Free Software Foundation; either version 2 of the
+License, or (at your option) any later version.
+
+This library is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+Library General Public License for more details.
+
+You should have received a copy of the GNU Library General Public
+License along with this library; see the file COPYING.LIB.  If
+not, write to the Free Software Foundation, Inc., 675 Mass Ave,
+Cambridge, MA 02139, USA.
+
+   The author may be reached (Email) at the address mike@ai.mit.edu,
+   or (US mail) as Mike Haertel c/o Free Software Foundation.  */
+
+#ifndef _MALLOC_H
+
+#define _MALLOC_H	1
+
+#ifdef _MALLOC_INTERNAL
+
+#ifdef	HAVE_CONFIG_H
+#include <sysfuncs.h>
+#endif
+
+#if	defined(_LIBC) || defined(STDC_HEADERS) || defined(USG)
+#include <string.h>
+#else
+#ifndef memset
+#define	memset(s, zero, n)	bzero ((s), (n))
+#endif
+#ifndef memcpy
+#define	memcpy(d, s, n)		bcopy ((s), (d), (n))
+#endif
+#endif
+
+#if	defined(__GNU_LIBRARY__) || __STDC__
+#include <limits.h>
+#else
+#define	CHAR_BIT	8
+#endif
+
+#ifdef	HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+
+#endif	/* _MALLOC_INTERNAL.  */
+
+
+#ifdef	__cplusplus
+extern "C"
+{
+#endif
+
+#if defined (__cplusplus) || __STDC__
+#undef	__P
+#define	__P(args)	args
+#undef	__ptr_t
+#define	__ptr_t		void *
+#else /* Not C++ or ANSI C.  */
+#undef	__P
+#define	__P(args)	()
+#undef	const
+#define	const
+#undef	__ptr_t
+#define	__ptr_t		char *
+#endif /* C++ or ANSI C.  */
+
+#if	__STDC__
+#include <stddef.h>
+#else
+#undef	size_t
+#define	size_t		unsigned int
+#undef	ptrdiff_t
+#define	ptrdiff_t	int
+#endif
+
+#ifndef	NULL
+#define	NULL	0
+#endif
+
+
+/* Allocate SIZE bytes of memory.  */
+extern __ptr_t malloc __P ((size_t __size));
+/* Re-allocate the previously allocated block
+   in __ptr_t, making the new block SIZE bytes long.  */
+extern __ptr_t realloc __P ((__ptr_t __ptr, size_t __size));
+/* Allocate NMEMB elements of SIZE bytes each, all initialized to 0.  */
+extern __ptr_t calloc __P ((size_t __nmemb, size_t __size));
+/* Free a block allocated by `malloc', `realloc' or `calloc'.  */
+extern void free __P ((__ptr_t __ptr));
+
+/* Allocate SIZE bytes allocated to ALIGNMENT bytes.  */
+extern __ptr_t memalign __P ((size_t __alignment, size_t __size));
+
+/* Allocate SIZE bytes on a page boundary.  */
+extern __ptr_t valloc __P ((size_t __size));
+
+
+#ifdef _MALLOC_INTERNAL
+
+/* The allocator divides the heap into blocks of fixed size; large
+   requests receive one or more whole blocks, and small requests
+   receive a fragment of a block.  Fragment sizes are powers of two,
+   and all fragments of a block are the same size.  When all the
+   fragments in a block have been freed, the block itself is freed.  */
+#define INT_BIT		(CHAR_BIT * sizeof(int))
+#define BLOCKLOG	(INT_BIT > 16 ? 12 : 9)
+#define BLOCKSIZE	(1 << BLOCKLOG)
+#define BLOCKIFY(SIZE)	(((SIZE) + BLOCKSIZE - 1) / BLOCKSIZE)
+
+/* Determine the amount of memory spanned by the initial heap table
+   (not an absolute limit).  */
+#define HEAP		(INT_BIT > 16 ? 4194304 : 65536)
+
+/* Number of contiguous free blocks allowed to build up at the end of
+   memory before they will be returned to the system.  */
+#define FINAL_FREE_BLOCKS	8
+
+/* Data structure giving per-block information.  */
+typedef union
+  {
+    /* Heap information for a busy block.  */
+    struct
+      {
+	/* Zero for a large block, or positive giving the
+	   logarithm to the base two of the fragment size.  */
+	int type;
+	union
+	  {
+	    struct
+	      {
+		size_t nfree;	/* Free fragments in a fragmented block.  */
+		size_t first;	/* First free fragment of the block.  */
+	      } frag;
+	    /* Size (in blocks) of a large cluster.  */
+	    size_t size;
+	  } info;
+      } busy;
+    /* Heap information for a free block
+       (that may be the first of a free cluster).  */
+    struct
+      {
+	size_t size;		/* Size (in blocks) of a free cluster.  */
+	size_t next;		/* Index of next free cluster.  */
+	size_t prev;		/* Index of previous free cluster.  */
+      } free;
+  } malloc_info;
+
+/* Pointer to first block of the heap.  */
+extern char *_heapbase;
+
+/* Table indexed by block number giving per-block information.  */
+extern malloc_info *_heapinfo;
+
+/* Address to block number and vice versa.  */
+#define BLOCK(A)	(((char *) (A) - _heapbase) / BLOCKSIZE + 1)
+#define ADDRESS(B)	((__ptr_t) (((B) - 1) * BLOCKSIZE + _heapbase))
+
+/* Current search index for the heap table.  */
+extern size_t _heapindex;
+
+/* Limit of valid info table indices.  */
+extern size_t _heaplimit;
+
+/* Doubly linked lists of free fragments.  */
+struct list
+  {
+    struct list *next;
+    struct list *prev;
+  };
+
+/* Free list headers for each fragment size.  */
+extern struct list _fraghead[];
+
+/* List of blocks allocated with `memalign' (or `valloc').  */
+struct alignlist
+  {
+    struct alignlist *next;
+    __ptr_t aligned;		/* The address that memaligned returned.  */
+    __ptr_t exact;		/* The address that malloc returned.  */
+  };
+extern struct alignlist *_aligned_blocks;
+
+/* Instrumentation.  */
+extern size_t _chunks_used;
+extern size_t _bytes_used;
+extern size_t _chunks_free;
+extern size_t _bytes_free;
+
+/* Internal version of `free' used in `morecore' (malloc.c). */
+extern void _free_internal __P ((__ptr_t __ptr));
+
+#endif /* _MALLOC_INTERNAL.  */
+
+/* Underlying allocation function; successive calls should
+   return contiguous pieces of memory.  */
+extern __ptr_t (*__morecore) __P ((ptrdiff_t __size));
+
+/* Default value of `__morecore'.  */
+extern __ptr_t __default_morecore __P ((ptrdiff_t __size));
+
+/* If not NULL, this function is called after each time
+   `__morecore' is called to increase the data size.  */
+extern void (*__after_morecore_hook) __P ((void));
+
+/* Nonzero if `malloc' has been called and done its initialization.  */
+extern int __malloc_initialized;
+
+/* Hooks for debugging versions.  */
+extern void (*__free_hook) __P ((__ptr_t __ptr));
+extern __ptr_t (*__malloc_hook) __P ((size_t __size));
+extern __ptr_t (*__realloc_hook) __P ((__ptr_t __ptr, size_t __size));
+
+/* Return values for `mprobe': these are the kinds of inconsistencies that
+   `mcheck' enables detection of.  */
+enum mcheck_status
+  {
+    MCHECK_DISABLED = -1,	/* Consistency checking is not turned on.  */
+    MCHECK_OK,			/* Block is fine.  */
+    MCHECK_FREE,		/* Block freed twice.  */
+    MCHECK_HEAD,		/* Memory before the block was clobbered.  */
+    MCHECK_TAIL			/* Memory after the block was clobbered.  */
+  };
+
+/* Activate a standard collection of debugging hooks.  This must be called
+   before `malloc' is ever called.  ABORTFUNC is called with an error code
+   (see enum above) when an inconsistency is detected.  If ABORTFUNC is
+   null, the standard function prints on stderr and then calls `abort'.  */
+extern int mcheck __P ((void (*__abortfunc) __P ((enum mcheck_status))));
+
+/* Check for aberrations in a particular malloc'd block.  You must have
+   called `mcheck' already.  These are the same checks that `mcheck' does
+   when you free or reallocate a block.  */
+extern enum mcheck_status mprobe __P ((__ptr_t __ptr));
+
+/* Activate a standard collection of tracing hooks.  */
+extern void mtrace __P ((void));
+
+/* Statistics available to the user.  */
+struct mstats
+  {
+    size_t bytes_total;		/* Total size of the heap. */
+    size_t chunks_used;		/* Chunks allocated by the user. */
+    size_t bytes_used;		/* Byte total of user-allocated chunks. */
+    size_t chunks_free;		/* Chunks in the free list. */
+    size_t bytes_free;		/* Byte total of chunks in the free list. */
+  };
+
+/* Pick up the current statistics. */
+extern struct mstats mstats __P ((void));
+
+/* Call WARNFUN with a warning message when memory usage is high.  */
+extern void memory_warnings __P ((__ptr_t __start,
+				  void (*__warnfun) __P ((const char *))));
+
+
+/* Relocating allocator.  */
+
+/* Allocate SIZE bytes, and store the address in *HANDLEPTR.  */
+extern __ptr_t r_alloc __P ((__ptr_t *__handleptr, size_t __size));
+
+/* Free the storage allocated in HANDLEPTR.  */
+extern void r_alloc_free __P ((__ptr_t *__handleptr));
+
+/* Adjust the block at HANDLEPTR to be SIZE bytes long.  */
+extern __ptr_t r_re_alloc __P ((__ptr_t *__handleptr, size_t __size));
+
+
+#ifdef	__cplusplus
+}
+#endif
+
+#endif /* malloc.h  */
+/* Allocate memory on a page boundary.
+   Copyright (C) 1991, 1992, 1993 Free Software Foundation, Inc.
+
+This library is free software; you can redistribute it and/or
+modify it under the terms of the GNU Library General Public License as
+published by the Free Software Foundation; either version 2 of the
+License, or (at your option) any later version.
+
+This library is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+Library General Public License for more details.
+
+You should have received a copy of the GNU Library General Public
+License along with this library; see the file COPYING.LIB.  If
+not, write to the Free Software Foundation, Inc., 675 Mass Ave,
+Cambridge, MA 02139, USA.
+
+   The author may be reached (Email) at the address mike@ai.mit.edu,
+   or (US mail) as Mike Haertel c/o Free Software Foundation.  */
+
+#if defined (__GNU_LIBRARY__) || defined (_LIBC)
+#include <stddef.h>
+#include <sys/cdefs.h>
+extern size_t __getpagesize __P ((void));
+#else
+#include "getpagesize.h"
+#define	 __getpagesize()	getpagesize()
+#endif
+
+#ifndef	_MALLOC_INTERNAL
+#define	_MALLOC_INTERNAL
+#include <malloc.h>
+#endif
+
+static size_t pagesize;
+
+__ptr_t
+valloc (size)
+     size_t size;
+{
+  if (pagesize == 0)
+    pagesize = __getpagesize ();
+
+  return memalign (pagesize, size);
+}
+/* Memory allocator `malloc'.
+   Copyright 1990, 1991, 1992, 1993, 1994 Free Software Foundation
+		  Written May 1989 by Mike Haertel.
+
+This library is free software; you can redistribute it and/or
+modify it under the terms of the GNU Library General Public License as
+published by the Free Software Foundation; either version 2 of the
+License, or (at your option) any later version.
+
+This library is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+Library General Public License for more details.
+
+You should have received a copy of the GNU Library General Public
+License along with this library; see the file COPYING.LIB.  If
+not, write to the Free Software Foundation, Inc., 675 Mass Ave,
+Cambridge, MA 02139, USA.
+
+   The author may be reached (Email) at the address mike@ai.mit.edu,
+   or (US mail) as Mike Haertel c/o Free Software Foundation.  */
+
+#ifndef	_MALLOC_INTERNAL
+#define _MALLOC_INTERNAL
+#include <malloc.h>
+#endif
+
+/* How to really get more memory.  */
+__ptr_t (*__morecore) __P ((ptrdiff_t __size)) = __default_morecore;
+
+/* Debugging hook for `malloc'.  */
+__ptr_t (*__malloc_hook) __P ((size_t __size));
+
+/* Pointer to the base of the first block.  */
+char *_heapbase;
+
+/* Block information table.  Allocated with align/__free (not malloc/free).  */
+malloc_info *_heapinfo;
+
+/* Number of info entries.  */
+static size_t heapsize;
+
+/* Search index in the info table.  */
+size_t _heapindex;
+
+/* Limit of valid info table indices.  */
+size_t _heaplimit;
+
+/* Free lists for each fragment size.  */
+struct list _fraghead[BLOCKLOG];
+
+/* Instrumentation.  */
+size_t _chunks_used;
+size_t _bytes_used;
+size_t _chunks_free;
+size_t _bytes_free;
+
+/* Are you experienced?  */
+int __malloc_initialized;
+
+void (*__after_morecore_hook) __P ((void));
+
+/* Aligned allocation.  */
+static __ptr_t align __P ((size_t));
+static __ptr_t
+align (size)
+     size_t size;
+{
+  __ptr_t result;
+  unsigned long int adj;
+
+  result = (*__morecore) (size);
+  adj = (unsigned long int) ((unsigned long int) ((char *) result -
+						  (char *) NULL)) % BLOCKSIZE;
+  if (adj != 0)
+    {
+      adj = BLOCKSIZE - adj;
+      (void) (*__morecore) (adj);
+      result = (char *) result + adj;
+    }
+
+  if (__after_morecore_hook)
+    (*__after_morecore_hook) ();
+
+  return result;
+}
+
+/* Set everything up and remember that we have.  */
+static int initialize __P ((void));
+static int
+initialize ()
+{
+  heapsize = HEAP / BLOCKSIZE;
+  _heapinfo = (malloc_info *) align (heapsize * sizeof (malloc_info));
+  if (_heapinfo == NULL)
+    return 0;
+  memset (_heapinfo, 0, heapsize * sizeof (malloc_info));
+  _heapinfo[0].free.size = 0;
+  _heapinfo[0].free.next = _heapinfo[0].free.prev = 0;
+  _heapindex = 0;
+  _heapbase = (char *) _heapinfo;
+
+  /* Account for the _heapinfo block itself in the statistics.  */
+  _bytes_used = heapsize * sizeof (malloc_info);
+  _chunks_used = 1;
+
+  __malloc_initialized = 1;
+  return 1;
+}
+
+/* Get neatly aligned memory, initializing or
+   growing the heap info table as necessary. */
+static __ptr_t morecore __P ((size_t));
+static __ptr_t
+morecore (size)
+     size_t size;
+{
+  __ptr_t result;
+  malloc_info *newinfo, *oldinfo;
+  size_t newsize;
+
+  result = align (size);
+  if (result == NULL)
+    return NULL;
+
+  /* Check if we need to grow the info table.  */
+  if ((size_t) BLOCK ((char *) result + size) > heapsize)
+    {
+      newsize = heapsize;
+      while ((size_t) BLOCK ((char *) result + size) > newsize)
+	newsize *= 2;
+      newinfo = (malloc_info *) align (newsize * sizeof (malloc_info));
+      if (newinfo == NULL)
+	{
+	  (*__morecore) (-size);
+	  return NULL;
+	}
+      memcpy (newinfo, _heapinfo, heapsize * sizeof (malloc_info));
+      memset (&newinfo[heapsize], 0,
+	      (newsize - heapsize) * sizeof (malloc_info));
+      oldinfo = _heapinfo;
+      newinfo[BLOCK (oldinfo)].busy.type = 0;
+      newinfo[BLOCK (oldinfo)].busy.info.size
+	= BLOCKIFY (heapsize * sizeof (malloc_info));
+      _heapinfo = newinfo;
+      /* Account for the _heapinfo block itself in the statistics.  */
+      _bytes_used += newsize * sizeof (malloc_info);
+      ++_chunks_used;
+      _free_internal (oldinfo);
+      heapsize = newsize;
+    }
+
+  _heaplimit = BLOCK ((char *) result + size);
+  return result;
+}
+
+/* Allocate memory from the heap.  */
+__ptr_t
+malloc (size)
+     size_t size;
+{
+  __ptr_t result;
+  size_t block, blocks, lastblocks, start;
+  register size_t i;
+  struct list *next;
+
+  /* ANSI C allows `malloc (0)' to either return NULL, or to return a
+     valid address you can realloc and free (though not dereference).
+
+     It turns out that some extant code (sunrpc, at least Ultrix's version)
+     expects `malloc (0)' to return non-NULL and breaks otherwise.
+     Be compatible.  */
+
+#if	0
+  if (size == 0)
+    return NULL;
+#endif
+
+  if (__malloc_hook != NULL)
+    return (*__malloc_hook) (size);
+
+  if (!__malloc_initialized)
+    if (!initialize ())
+      return NULL;
+
+  if (size < sizeof (struct list))
+      size = sizeof (struct list);
+
+#ifdef SUNOS_LOCALTIME_BUG
+  if (size < 16)
+    size = 16;
+#endif
+
+  /* Determine the allocation policy based on the request size.  */
+  if (size <= BLOCKSIZE / 2)
+    {
+      /* Small allocation to receive a fragment of a block.
+	 Determine the logarithm to base two of the fragment size. */
+      register size_t log = 1;
+      --size;
+      while ((size /= 2) != 0)
+	++log;
+
+      /* Look in the fragment lists for a
+	 free fragment of the desired size. */
+      next = _fraghead[log].next;
+      if (next != NULL)
+	{
+	  /* There are free fragments of this size.
+	     Pop a fragment out of the fragment list and return it.
+	     Update the block's nfree and first counters. */
+	  result = (__ptr_t) next;
+	  next->prev->next = next->next;
+	  if (next->next != NULL)
+	    next->next->prev = next->prev;
+	  block = BLOCK (result);
+	  if (--_heapinfo[block].busy.info.frag.nfree != 0)
+	    _heapinfo[block].busy.info.frag.first = (unsigned long int)
+	      ((unsigned long int) ((char *) next->next - (char *) NULL)
+	       % BLOCKSIZE) >> log;
+
+	  /* Update the statistics.  */
+	  ++_chunks_used;
+	  _bytes_used += 1 << log;
+	  --_chunks_free;
+	  _bytes_free -= 1 << log;
+	}
+      else
+	{
+	  /* No free fragments of the desired size, so get a new block
+	     and break it into fragments, returning the first.  */
+	  result = malloc (BLOCKSIZE);
+	  if (result == NULL)
+	    return NULL;
+
+	  /* Link all fragments but the first into the free list.  */
+	  for (i = 1; i < (size_t) (BLOCKSIZE >> log); ++i)
+	    {
+	      next = (struct list *) ((char *) result + (i << log));
+	      next->next = _fraghead[log].next;
+	      next->prev = &_fraghead[log];
+	      next->prev->next = next;
+	      if (next->next != NULL)
+		next->next->prev = next;
+	    }
+
+	  /* Initialize the nfree and first counters for this block.  */
+	  block = BLOCK (result);
+	  _heapinfo[block].busy.type = log;
+	  _heapinfo[block].busy.info.frag.nfree = i - 1;
+	  _heapinfo[block].busy.info.frag.first = i - 1;
+
+	  _chunks_free += (BLOCKSIZE >> log) - 1;
+	  _bytes_free += BLOCKSIZE - (1 << log);
+	  _bytes_used -= BLOCKSIZE - (1 << log);
+	}
+    }
+  else
+    {
+      /* Large allocation to receive one or more blocks.
+	 Search the free list in a circle starting at the last place visited.
+	 If we loop completely around without finding a large enough
+	 space we will have to get more memory from the system.  */
+      blocks = BLOCKIFY (size);
+      start = block = _heapindex;
+      while (_heapinfo[block].free.size < blocks)
+	{
+	  block = _heapinfo[block].free.next;
+	  if (block == start)
+	    {
+	      /* Need to get more from the system.  Check to see if
+		 the new core will be contiguous with the final free
+		 block; if so we don't need to get as much.  */
+	      block = _heapinfo[0].free.prev;
+	      lastblocks = _heapinfo[block].free.size;
+	      if (_heaplimit != 0 && block + lastblocks == _heaplimit &&
+		  (*__morecore) (0) == ADDRESS (block + lastblocks) &&
+		  (morecore ((blocks - lastblocks) * BLOCKSIZE)) != NULL)
+		{
+ 		  /* Which block we are extending (the `final free
+ 		     block' referred to above) might have changed, if
+ 		     it got combined with a freed info table.  */
+ 		  block = _heapinfo[0].free.prev;
+  		  _heapinfo[block].free.size += (blocks - lastblocks);
+		  _bytes_free += (blocks - lastblocks) * BLOCKSIZE;
+		  continue;
+		}
+	      result = morecore (blocks * BLOCKSIZE);
+	      if (result == NULL)
+		return NULL;
+	      block = BLOCK (result);
+	      _heapinfo[block].busy.type = 0;
+	      _heapinfo[block].busy.info.size = blocks;
+	      ++_chunks_used;
+	      _bytes_used += blocks * BLOCKSIZE;
+	      return result;
+	    }
+	}
+
+      /* At this point we have found a suitable free list entry.
+	 Figure out how to remove what we need from the list. */
+      result = ADDRESS (block);
+      if (_heapinfo[block].free.size > blocks)
+	{
+	  /* The block we found has a bit left over,
+	     so relink the tail end back into the free list. */
+	  _heapinfo[block + blocks].free.size
+	    = _heapinfo[block].free.size - blocks;
+	  _heapinfo[block + blocks].free.next
+	    = _heapinfo[block].free.next;
+	  _heapinfo[block + blocks].free.prev
+	    = _heapinfo[block].free.prev;
+	  _heapinfo[_heapinfo[block].free.prev].free.next
+	    = _heapinfo[_heapinfo[block].free.next].free.prev
+	    = _heapindex = block + blocks;
+	}
+      else
+	{
+	  /* The block exactly matches our requirements,
+	     so just remove it from the list. */
+	  _heapinfo[_heapinfo[block].free.next].free.prev
+	    = _heapinfo[block].free.prev;
+	  _heapinfo[_heapinfo[block].free.prev].free.next
+	    = _heapindex = _heapinfo[block].free.next;
+	  --_chunks_free;
+	}
+
+      _heapinfo[block].busy.type = 0;
+      _heapinfo[block].busy.info.size = blocks;
+      ++_chunks_used;
+      _bytes_used += blocks * BLOCKSIZE;
+      _bytes_free -= blocks * BLOCKSIZE;
+    }
+
+  return result;
+}
+
+
+#ifndef _LIBC
+
+/* On some ANSI C systems, some libc functions call _malloc, _free
+   and _realloc.  Make them use the GNU functions.  */
+
+__ptr_t
+_malloc (size)
+     size_t size;
+{
+  return malloc (size);
+}
+
+void
+_free (ptr)
+     __ptr_t ptr;
+{
+  free (ptr);
+}
+
+__ptr_t
+_realloc (ptr, size)
+     __ptr_t ptr;
+     size_t size;
+{
+  return realloc (ptr, size);
+}
+
+#endif
+/* Free a block of memory allocated by `malloc'.
+   Copyright 1990, 1991, 1992 Free Software Foundation
+		  Written May 1989 by Mike Haertel.
+
+This library is free software; you can redistribute it and/or
+modify it under the terms of the GNU Library General Public License as
+published by the Free Software Foundation; either version 2 of the
+License, or (at your option) any later version.
+
+This library is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+Library General Public License for more details.
+
+You should have received a copy of the GNU Library General Public
+License along with this library; see the file COPYING.LIB.  If
+not, write to the Free Software Foundation, Inc., 675 Mass Ave,
+Cambridge, MA 02139, USA.
+
+   The author may be reached (Email) at the address mike@ai.mit.edu,
+   or (US mail) as Mike Haertel c/o Free Software Foundation.  */
+
+#ifndef	_MALLOC_INTERNAL
+#define _MALLOC_INTERNAL
+#include <malloc.h>
+#endif
+
+/* Debugging hook for free.  */
+void (*__free_hook) __P ((__ptr_t __ptr));
+
+/* List of blocks allocated by memalign.  */
+struct alignlist *_aligned_blocks = NULL;
+
+/* Return memory to the heap.
+   Like `free' but don't call a __free_hook if there is one.  */
+void
+_free_internal (ptr)
+     __ptr_t ptr;
+{
+  int type;
+  size_t block, blocks;
+  register size_t i;
+  struct list *prev, *next;
+
+  block = BLOCK (ptr);
+
+  type = _heapinfo[block].busy.type;
+  switch (type)
+    {
+    case 0:
+      /* Get as many statistics as early as we can.  */
+      --_chunks_used;
+      _bytes_used -= _heapinfo[block].busy.info.size * BLOCKSIZE;
+      _bytes_free += _heapinfo[block].busy.info.size * BLOCKSIZE;
+
+      /* Find the free cluster previous to this one in the free list.
+	 Start searching at the last block referenced; this may benefit
+	 programs with locality of allocation.  */
+      i = _heapindex;
+      if (i > block)
+	while (i > block)
+	  i = _heapinfo[i].free.prev;
+      else
+	{
+	  do
+	    i = _heapinfo[i].free.next;
+	  while (i > 0 && i < block);
+	  i = _heapinfo[i].free.prev;
+	}
+
+      /* Determine how to link this block into the free list.  */
+      if (block == i + _heapinfo[i].free.size)
+	{
+	  /* Coalesce this block with its predecessor.  */
+	  _heapinfo[i].free.size += _heapinfo[block].busy.info.size;
+	  block = i;
+	}
+      else
+	{
+	  /* Really link this block back into the free list.  */
+	  _heapinfo[block].free.size = _heapinfo[block].busy.info.size;
+	  _heapinfo[block].free.next = _heapinfo[i].free.next;
+	  _heapinfo[block].free.prev = i;
+	  _heapinfo[i].free.next = block;
+	  _heapinfo[_heapinfo[block].free.next].free.prev = block;
+	  ++_chunks_free;
+	}
+
+      /* Now that the block is linked in, see if we can coalesce it
+	 with its successor (by deleting its successor from the list
+	 and adding in its size).  */
+      if (block + _heapinfo[block].free.size == _heapinfo[block].free.next)
+	{
+	  _heapinfo[block].free.size
+	    += _heapinfo[_heapinfo[block].free.next].free.size;
+	  _heapinfo[block].free.next
+	    = _heapinfo[_heapinfo[block].free.next].free.next;
+	  _heapinfo[_heapinfo[block].free.next].free.prev = block;
+	  --_chunks_free;
+	}
+
+      /* Now see if we can return stuff to the system.  */
+      blocks = _heapinfo[block].free.size;
+      if (blocks >= FINAL_FREE_BLOCKS && block + blocks == _heaplimit
+	  && (*__morecore) (0) == ADDRESS (block + blocks))
+	{
+	  register size_t bytes = blocks * BLOCKSIZE;
+	  _heaplimit -= blocks;
+	  (*__morecore) (-bytes);
+	  _heapinfo[_heapinfo[block].free.prev].free.next
+	    = _heapinfo[block].free.next;
+	  _heapinfo[_heapinfo[block].free.next].free.prev
+	    = _heapinfo[block].free.prev;
+	  block = _heapinfo[block].free.prev;
+	  --_chunks_free;
+	  _bytes_free -= bytes;
+	}
+
+      /* Set the next search to begin at this block.  */
+      _heapindex = block;
+      break;
+
+    default:
+      /* Do some of the statistics.  */
+      --_chunks_used;
+      _bytes_used -= 1 << type;
+      ++_chunks_free;
+      _bytes_free += 1 << type;
+
+      /* Get the address of the first free fragment in this block.  */
+      prev = (struct list *) ((char *) ADDRESS (block) +
+			   (_heapinfo[block].busy.info.frag.first << type));
+
+      if (_heapinfo[block].busy.info.frag.nfree == (BLOCKSIZE >> type) - 1)
+	{
+	  /* If all fragments of this block are free, remove them
+	     from the fragment list and free the whole block.  */
+	  next = prev;
+	  for (i = 1; i < (size_t) (BLOCKSIZE >> type); ++i)
+	    next = next->next;
+	  prev->prev->next = next;
+	  if (next != NULL)
+	    next->prev = prev->prev;
+	  _heapinfo[block].busy.type = 0;
+	  _heapinfo[block].busy.info.size = 1;
+
+	  /* Keep the statistics accurate.  */
+	  ++_chunks_used;
+	  _bytes_used += BLOCKSIZE;
+	  _chunks_free -= BLOCKSIZE >> type;
+	  _bytes_free -= BLOCKSIZE;
+
+	  free (ADDRESS (block));
+	}
+      else if (_heapinfo[block].busy.info.frag.nfree != 0)
+	{
+	  /* If some fragments of this block are free, link this
+	     fragment into the fragment list after the first free
+	     fragment of this block. */
+	  next = (struct list *) ptr;
+	  next->next = prev->next;
+	  next->prev = prev;
+	  prev->next = next;
+	  if (next->next != NULL)
+	    next->next->prev = next;
+	  ++_heapinfo[block].busy.info.frag.nfree;
+	}
+      else
+	{
+	  /* No fragments of this block are free, so link this
+	     fragment into the fragment list and announce that
+	     it is the first free fragment of this block. */
+	  prev = (struct list *) ptr;
+	  _heapinfo[block].busy.info.frag.nfree = 1;
+	  _heapinfo[block].busy.info.frag.first = (unsigned long int)
+	    ((unsigned long int) ((char *) ptr - (char *) NULL)
+	     % BLOCKSIZE >> type);
+	  prev->next = _fraghead[type].next;
+	  prev->prev = &_fraghead[type];
+	  prev->prev->next = prev;
+	  if (prev->next != NULL)
+	    prev->next->prev = prev;
+	}
+      break;
+    }
+}
+
+/* Return memory to the heap.  */
+void
+free (ptr)
+     __ptr_t ptr;
+{
+  register struct alignlist *l;
+
+  if (ptr == NULL)
+    return;
+
+  for (l = _aligned_blocks; l != NULL; l = l->next)
+    if (l->aligned == ptr)
+      {
+	l->aligned = NULL;	/* Mark the slot in the list as free.  */
+	ptr = l->exact;
+	break;
+      }
+
+  if (__free_hook != NULL)
+    (*__free_hook) (ptr);
+  else
+    _free_internal (ptr);
+}
+/* Copyright (C) 1991, 1993, 1994 Free Software Foundation, Inc.
+This file is part of the GNU C Library.
+
+The GNU C Library is free software; you can redistribute it and/or
+modify it under the terms of the GNU Library General Public License as
+published by the Free Software Foundation; either version 2 of the
+License, or (at your option) any later version.
+
+The GNU C Library is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+Library General Public License for more details.
+
+You should have received a copy of the GNU Library General Public
+License along with the GNU C Library; see the file COPYING.LIB.  If
+not, write to the Free Software Foundation, Inc., 675 Mass Ave,
+Cambridge, MA 02139, USA.  */
+
+#ifndef	_MALLOC_INTERNAL
+#define _MALLOC_INTERNAL
+#include <malloc.h>
+#endif
+
+#ifdef _LIBC
+
+#include <ansidecl.h>
+#include <gnu-stabs.h>
+
+#undef	cfree
+
+function_alias(cfree, free, void, (ptr),
+	       DEFUN(cfree, (ptr), PTR ptr))
+
+#else
+
+void
+cfree (ptr)
+     __ptr_t ptr;
+{
+  free (ptr);
+}
+
+#endif
+/* Change the size of a block allocated by `malloc'.
+   Copyright 1990, 1991, 1992, 1993, 1994 Free Software Foundation, Inc.
+		     Written May 1989 by Mike Haertel.
+
+This library is free software; you can redistribute it and/or
+modify it under the terms of the GNU Library General Public License as
+published by the Free Software Foundation; either version 2 of the
+License, or (at your option) any later version.
+
+This library is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+Library General Public License for more details.
+
+You should have received a copy of the GNU Library General Public
+License along with this library; see the file COPYING.LIB.  If
+not, write to the Free Software Foundation, Inc., 675 Mass Ave,
+Cambridge, MA 02139, USA.
+
+   The author may be reached (Email) at the address mike@ai.mit.edu,
+   or (US mail) as Mike Haertel c/o Free Software Foundation.  */
+
+#ifndef	_MALLOC_INTERNAL
+#define _MALLOC_INTERNAL
+#include <malloc.h>
+#endif
+
+#if  (defined (MEMMOVE_MISSING) || \
+      !defined(_LIBC) && !defined(STDC_HEADERS) && !defined(USG))
+
+/* Snarfed directly from Emacs src/dispnew.c:
+   XXX Should use system bcopy if it handles overlap.  */
+#ifndef emacs
+
+/* Like bcopy except never gets confused by overlap.  */
+
+static void
+safe_bcopy (from, to, size)
+     char *from, *to;
+     int size;
+{
+  if (size <= 0 || from == to)
+    return;
+
+  /* If the source and destination don't overlap, then bcopy can
+     handle it.  If they do overlap, but the destination is lower in
+     memory than the source, we'll assume bcopy can handle that.  */
+  if (to < from || from + size <= to)
+    bcopy (from, to, size);
+
+  /* Otherwise, we'll copy from the end.  */
+  else
+    {
+      register char *endf = from + size;
+      register char *endt = to + size;
+
+      /* If TO - FROM is large, then we should break the copy into
+	 nonoverlapping chunks of TO - FROM bytes each.  However, if
+	 TO - FROM is small, then the bcopy function call overhead
+	 makes this not worth it.  The crossover point could be about
+	 anywhere.  Since I don't think the obvious copy loop is too
+	 bad, I'm trying to err in its favor.  */
+      if (to - from < 64)
+	{
+	  do
+	    *--endt = *--endf;
+	  while (endf != from);
+	}
+      else
+	{
+	  for (;;)
+	    {
+	      endt -= (to - from);
+	      endf -= (to - from);
+
+	      if (endt < to)
+		break;
+
+	      bcopy (endf, endt, to - from);
+	    }
+
+	  /* If SIZE wasn't a multiple of TO - FROM, there will be a
+	     little left over.  The amount left over is
+	     (endt + (to - from)) - to, which is endt - from.  */
+	  bcopy (from, to, endt - from);
+	}
+    }
+}     
+#endif	/* Not emacs.  */
+
+#define memmove(to, from, size) safe_bcopy ((from), (to), (size))
+
+#endif
+
+
+#define min(A, B) ((A) < (B) ? (A) : (B))
+
+/* Debugging hook for realloc.  */
+__ptr_t (*__realloc_hook) __P ((__ptr_t __ptr, size_t __size));
+
+/* Resize the given region to the new size, returning a pointer
+   to the (possibly moved) region.  This is optimized for speed;
+   some benchmarks seem to indicate that greater compactness is
+   achieved by unconditionally allocating and copying to a
+   new region.  This module has incestuous knowledge of the
+   internals of both free and malloc. */
+__ptr_t
+realloc (ptr, size)
+     __ptr_t ptr;
+     size_t size;
+{
+  __ptr_t result;
+  int type;
+  size_t block, blocks, oldlimit;
+
+  if (size == 0)
+    {
+      free (ptr);
+      return malloc (0);
+    }
+  else if (ptr == NULL)
+    return malloc (size);
+
+  if (__realloc_hook != NULL)
+    return (*__realloc_hook) (ptr, size);
+
+  block = BLOCK (ptr);
+
+  type = _heapinfo[block].busy.type;
+  switch (type)
+    {
+    case 0:
+      /* Maybe reallocate a large block to a small fragment.  */
+      if (size <= BLOCKSIZE / 2)
+	{
+	  result = malloc (size);
+	  if (result != NULL)
+	    {
+	      memcpy (result, ptr, size);
+	      _free_internal (ptr);
+	      return result;
+	    }
+	}
+
+      /* The new size is a large allocation as well;
+	 see if we can hold it in place. */
+      blocks = BLOCKIFY (size);
+      if (blocks < _heapinfo[block].busy.info.size)
+	{
+	  /* The new size is smaller; return
+	     excess memory to the free list. */
+	  _heapinfo[block + blocks].busy.type = 0;
+	  _heapinfo[block + blocks].busy.info.size
+	    = _heapinfo[block].busy.info.size - blocks;
+	  _heapinfo[block].busy.info.size = blocks;
+	  /* We have just created a new chunk by splitting a chunk in two.
+	     Now we will free this chunk; increment the statistics counter
+	     so it doesn't become wrong when _free_internal decrements it.  */
+	  ++_chunks_used;
+	  _free_internal (ADDRESS (block + blocks));
+	  result = ptr;
+	}
+      else if (blocks == _heapinfo[block].busy.info.size)
+	/* No size change necessary.  */
+	result = ptr;
+      else
+	{
+	  /* Won't fit, so allocate a new region that will.
+	     Free the old region first in case there is sufficient
+	     adjacent free space to grow without moving. */
+	  blocks = _heapinfo[block].busy.info.size;
+	  /* Prevent free from actually returning memory to the system.  */
+	  oldlimit = _heaplimit;
+	  _heaplimit = 0;
+	  _free_internal (ptr);
+	  _heaplimit = oldlimit;
+	  result = malloc (size);
+	  if (result == NULL)
+	    {
+	      /* Now we're really in trouble.  We have to unfree
+		 the thing we just freed.  Unfortunately it might
+		 have been coalesced with its neighbors.  */
+	      if (_heapindex == block)
+	        (void) malloc (blocks * BLOCKSIZE);
+	      else
+		{
+		  __ptr_t previous = malloc ((block - _heapindex) * BLOCKSIZE);
+		  (void) malloc (blocks * BLOCKSIZE);
+		  _free_internal (previous);
+		}
+	      return NULL;
+	    }
+	  if (ptr != result)
+	    memmove (result, ptr, blocks * BLOCKSIZE);
+	}
+      break;
+
+    default:
+      /* Old size is a fragment; type is logarithm
+	 to base two of the fragment size.  */
+      if (size > (size_t) (1 << (type - 1)) && size <= (size_t) (1 << type))
+	/* The new size is the same kind of fragment.  */
+	result = ptr;
+      else
+	{
+	  /* The new size is different; allocate a new space,
+	     and copy the lesser of the new size and the old. */
+	  result = malloc (size);
+	  if (result == NULL)
+	    return NULL;
+	  memcpy (result, ptr, min (size, (size_t) 1 << type));
+	  free (ptr);
+	}
+      break;
+    }
+
+  return result;
+}
+/* Copyright (C) 1991, 1992 Free Software Foundation, Inc.
+
+This library is free software; you can redistribute it and/or
+modify it under the terms of the GNU Library General Public License as
+published by the Free Software Foundation; either version 2 of the
+License, or (at your option) any later version.
+
+This library is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+Library General Public License for more details.
+
+You should have received a copy of the GNU Library General Public
+License along with this library; see the file COPYING.LIB.  If
+not, write to the Free Software Foundation, Inc., 675 Mass Ave,
+Cambridge, MA 02139, USA.
+
+   The author may be reached (Email) at the address mike@ai.mit.edu,
+   or (US mail) as Mike Haertel c/o Free Software Foundation.  */
+
+#ifndef	_MALLOC_INTERNAL
+#define	_MALLOC_INTERNAL
+#include <malloc.h>
+#endif
+
+/* Allocate an array of NMEMB elements each SIZE bytes long.
+   The entire array is initialized to zeros.  */
+__ptr_t
+calloc (nmemb, size)
+     register size_t nmemb;
+     register size_t size;
+{
+  register __ptr_t result = malloc (nmemb * size);
+
+  if (result != NULL)
+    (void) memset (result, 0, nmemb * size);
+
+  return result;
+}
+/* Copyright (C) 1991, 1992, 1993 Free Software Foundation, Inc.
+This file is part of the GNU C Library.
+
+The GNU C Library 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, or (at your option)
+any later version.
+
+The GNU C Library is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with the GNU C Library; see the file COPYING.  If not, write to
+the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.  */
+
+#ifndef	_MALLOC_INTERNAL
+#define	_MALLOC_INTERNAL
+#include <malloc.h>
+#endif
+
+#ifndef	__GNU_LIBRARY__
+#define	__sbrk	sbrk
+#endif
+
+#ifdef __GNU_LIBRARY__
+/* It is best not to declare this and cast its result on foreign operating
+   systems with potentially hostile include files.  */
+extern __ptr_t __sbrk __P ((int increment));
+#endif
+
+#ifndef NULL
+#define NULL 0
+#endif
+
+/* Allocate INCREMENT more bytes of data space,
+   and return the start of data space, or NULL on errors.
+   If INCREMENT is negative, shrink data space.  */
+__ptr_t
+__default_morecore (increment)
+     ptrdiff_t increment;
+{
+  __ptr_t result = (__ptr_t) __sbrk ((int) increment);
+  if (result == (__ptr_t) -1)
+    return NULL;
+  return result;
+}
+/* Copyright (C) 1991, 1992, 1993 Free Software Foundation, Inc.
+
+This library is free software; you can redistribute it and/or
+modify it under the terms of the GNU Library General Public License as
+published by the Free Software Foundation; either version 2 of the
+License, or (at your option) any later version.
+
+This library is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+Library General Public License for more details.
+
+You should have received a copy of the GNU Library General Public
+License along with this library; see the file COPYING.LIB.  If
+not, write to the Free Software Foundation, Inc., 675 Mass Ave,
+Cambridge, MA 02139, USA.  */
+
+#ifndef	_MALLOC_INTERNAL
+#define _MALLOC_INTERNAL
+#include <malloc.h>
+#endif
+
+__ptr_t
+memalign (alignment, size)
+     size_t alignment;
+     size_t size;
+{
+  __ptr_t result;
+  unsigned long int adj;
+
+  size = ((size + alignment - 1) / alignment) * alignment;
+
+  result = malloc (size);
+  if (result == NULL)
+    return NULL;
+  adj = (unsigned long int) ((unsigned long int) ((char *) result -
+						  (char *) NULL)) % alignment;
+  if (adj != 0)
+    {
+      struct alignlist *l;
+      for (l = _aligned_blocks; l != NULL; l = l->next)
+	if (l->aligned == NULL)
+	  /* This slot is free.  Use it.  */
+	  break;
+      if (l == NULL)
+	{
+	  l = (struct alignlist *) malloc (sizeof (struct alignlist));
+	  if (l == NULL)
+	    {
+	      free (result);
+	      return NULL;
+	    }
+	  l->next = _aligned_blocks;
+	  _aligned_blocks = l;
+	}
+      l->exact = result;
+      result = l->aligned = (char *) result + alignment - adj;
+    }
+
+  return result;
+}
Index: /main/tags/2.25/gsdl/packages/mg/lib/huffman.c
===================================================================
--- /main/tags/2.25/gsdl/packages/mg/lib/huffman.c	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/mg/lib/huffman.c	(revision 21064)
@@ -0,0 +1,423 @@
+/**************************************************************************
+ *
+ * huffman.c -- Huffman coding functions
+ * Copyright (C) 1994  Neil Sharman
+ *
+ * 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.
+ *
+ * $Id$
+ *
+ **************************************************************************/
+
+/*
+   $Log$
+   Revision 1.1  1999/08/10 21:16:51  sjboddie
+   renamed mg-1.3d directory mg
+
+   Revision 1.1  1998/11/17 09:32:03  rjmcnab
+   *** empty log message ***
+
+   * Revision 1.1  1994/08/22  00:24:44  tes
+   * Initial placement under CVS.
+   *
+ */
+
+static char *RCSID = "$Id$";
+
+#include "sysfuncs.h"
+#include "memlib.h"
+#include "huffman.h"
+#include "messages.h"
+#include "netorder.h"  /* [RPAP - Jan 97: Endian Ordering] */
+
+/* ->data on success,  
+   NULL on error 
+ */
+huff_data *
+Generate_Huffman_Data (int num, long *freqs, huff_data * data,
+		       u_long * mem)
+{
+  int HNum, i, count;
+  unsigned long *heap;
+  huff_data *hd = data;
+  if (!hd)
+    {
+      if (!(hd = Xmalloc (sizeof (huff_data))))
+	goto error0;
+    }
+  if (!(heap = Xmalloc (num * 2 * sizeof (*heap))))
+    goto error1;
+  if (!(hd->clens = Xmalloc (num * sizeof (char))))
+      goto error2;
+  hd->num_codes = num;
+  if (mem)
+    {
+      if (hd != data)
+	*mem += sizeof (huff_data);
+      *mem += num * sizeof (char);
+    }
+  bcopy ((char *) freqs, (char *) &heap[num], num * sizeof (*heap));
+  bzero ((char *) heap, num * sizeof (*heap));
+
+  /* Initialise the pointers to the leaves */
+  for (count = i = 0; i < num; i++)
+    if (heap[num + i])
+      heap[count++] = num + i;
+
+  /* Reorganise the pointers so that it is a heap */
+  HNum = count;
+  for (i = HNum / 2; i > 0; i--)
+    {
+      register int curr, child;
+      curr = i;
+      child = curr * 2;
+      while (child <= HNum)
+	{
+	  if (child < HNum && heap[heap[child]] < heap[heap[child - 1]])
+	    child++;
+	  if (heap[heap[curr - 1]] > heap[heap[child - 1]])
+	    {
+	      register u_long temp;
+	      temp = heap[child - 1];
+	      heap[child - 1] = heap[curr - 1];
+	      heap[curr - 1] = temp;
+	      curr = child;
+	      child = 2 * curr;
+	    }
+	  else
+	    break;
+	}
+    }
+
+
+  /* Form the huffman tree */
+  while (HNum > 1)
+    {
+      int pos[2];
+
+      for (i = 0; i < 2; i++)
+	{
+	  register int curr, child;
+	  pos[i] = heap[0];
+	  heap[0] = heap[--HNum];
+	  curr = 1;
+	  child = 2;
+	  while (child <= HNum)
+	    {
+	      if (child < HNum &&
+		  heap[heap[child]] < heap[heap[child - 1]])
+		child++;
+	      if (heap[heap[curr - 1]] > heap[heap[child - 1]])
+		{
+		  register int temp;
+		  temp = heap[child - 1];
+		  heap[child - 1] = heap[curr - 1];
+		  heap[curr - 1] = temp;
+		  curr = child;
+		  child = 2 * curr;
+		}
+	      else
+		break;
+	    }
+	}
+
+      heap[HNum + 1] = heap[pos[0]] + heap[pos[1]];
+      heap[pos[0]] = heap[pos[1]] = HNum + 1;
+
+      heap[HNum] = HNum + 1;
+
+      {
+	register int parent, curr;
+	HNum++;
+	curr = HNum;
+	parent = curr >> 1;
+	while (parent && heap[heap[parent - 1]] > heap[heap[curr - 1]])
+	  {
+	    register int temp;
+	    temp = heap[parent - 1];
+	    heap[parent - 1] = heap[curr - 1];
+	    heap[curr - 1] = temp;
+	    curr = parent;
+	    parent = curr >> 1;
+	  }
+      }
+    }
+
+
+  /* Calculate the code lens */
+  heap[0] = -1UL;
+  heap[1] = 0;
+  for (i = 2; i < num * 2; i++)
+    heap[i] = heap[heap[i]] + 1;
+
+  /* zero the lencount's array */
+  bzero ((char *) hd->lencount, sizeof (hd->lencount));
+  hd->maxcodelen = 0;
+  hd->mincodelen = 100;
+
+  /* Set the code length of each leaf in the huffman tree */
+  for (i = 0; i < num; i++)
+    {
+      register u_long codelen = heap[i + num];
+      hd->clens[i] = (char) codelen;
+      if (!codelen)
+	continue;
+      if (codelen > hd->maxcodelen)
+	hd->maxcodelen = codelen;
+      if (codelen < hd->mincodelen)
+	hd->mincodelen = codelen;
+      hd->lencount[codelen]++;
+    }
+
+
+  if (hd->maxcodelen == 0 && hd->mincodelen == 100)
+    {
+      hd->num_codes = 0;
+    }
+  else
+    {
+      /* Calculate the current codes for each different code length */
+      hd->min_code[hd->maxcodelen] = 0;
+      for (i = hd->maxcodelen - 1; i>=0; i--)
+	hd->min_code[i] = (hd->min_code[i + 1] + hd->lencount[i + 1]) >> 1;
+    }
+  free (heap);
+  return (hd);
+
+error2:
+  free (heap);
+error1:
+  if (!data)
+    free (hd);
+error0:
+  return (NULL);
+
+}
+
+unsigned long *
+Generate_Huffman_Codes (huff_data * data, u_long * mem)
+{
+  int i;
+  unsigned long *codes;
+  unsigned long mc[MAX_HUFFCODE_LEN + 1];
+
+  if (!data)
+    return (NULL);
+  if (!(codes = Xmalloc (data->num_codes * sizeof (*codes))))
+    return (NULL);
+  if (mem)
+    *mem += data->num_codes * sizeof (*codes);
+  bcopy ((char *) data->min_code, (char *) mc, sizeof (mc));
+  for (i = 0; i < data->num_codes; i++)
+    if (data->clens[i])
+      codes[i] = mc[(int) (data->clens[i])]++;
+
+  return (codes);
+}
+
+
+unsigned long **
+Generate_Huffman_Vals (huff_data * data, u_long * mem)
+{
+  int i;
+  unsigned long *fcode[MAX_HUFFCODE_LEN + 1];
+  unsigned long **values;
+  unsigned long *vals;
+
+  if (!data)
+    return (NULL);
+  if (!(vals = Xmalloc (data->num_codes * sizeof (*vals))))
+    return (NULL);
+  if (!(values = Xmalloc ((MAX_HUFFCODE_LEN + 1) * sizeof (unsigned long *))))
+    {
+      free (vals);
+      return (NULL);
+    }
+
+  bzero ((char *) values, (MAX_HUFFCODE_LEN + 1) * sizeof (unsigned long *));
+
+  if (mem)
+    *mem += data->num_codes * sizeof (*vals) +
+      (MAX_HUFFCODE_LEN + 1) * sizeof (unsigned long *);
+
+  fcode[0] = values[0] = &vals[0];
+  for (i = 1; i <= data->maxcodelen; i++)
+    fcode[i] = values[i] = &vals[(values[i - 1] - vals) + data->lencount[i - 1]];
+
+  for (i = 0; i < data->num_codes; i++)
+    if (data->clens[i])
+      *fcode[(int) (data->clens[i])]++ = i;
+  return (values);
+}
+
+
+
+double 
+Calculate_Huffman_Size (int num, long *freqs, long *counts)
+{
+  double size = 0;
+  huff_data hd;
+  int i;
+  if (!Generate_Huffman_Data (num, freqs, &hd, NULL))
+    return -1;
+  for (i = 0; i < num; i++)
+    size += counts[i] * hd.clens[i];
+  Xfree (hd.clens);
+  return size;
+}
+
+
+
+int 
+Write_Huffman_Data (FILE * f, huff_data * hd)
+{
+  /* [RPAP - Jan 97: Endian Ordering] */
+  HTONSI(hd->num_codes);
+  HTONSI(hd->mincodelen);
+  HTONSI(hd->maxcodelen);
+
+  if (fwrite (&hd->num_codes, sizeof (hd->num_codes), 1, f) != 1)
+    return -1;
+
+  if (fwrite (&hd->mincodelen, sizeof (hd->mincodelen), 1, f) != 1)
+    return -1;
+
+  if (fwrite (&hd->maxcodelen, sizeof (hd->maxcodelen), 1, f) != 1)
+    return -1;
+
+  /* [RPAP - Jan 97: Endian Ordering] */
+  NTOHSI(hd->num_codes);
+  NTOHSI(hd->mincodelen);
+  NTOHSI(hd->maxcodelen);
+
+  if (hd->num_codes)
+    {
+      /* [RPAP - Jan 97: Endian Ordering] */
+      int i;
+      for (i = hd->mincodelen; i < hd->maxcodelen + 1; i++)
+	HTONSI(hd->lencount[i]);
+      for (i = 0; i < hd->maxcodelen + 1; i++)
+	HTONUL(hd->min_code[i]);
+
+      if (fwrite (hd->lencount + hd->mincodelen, sizeof (*hd->lencount),
+		  hd->maxcodelen - hd->mincodelen + 1, f) !=
+	  hd->maxcodelen - hd->mincodelen + 1)
+	return -1;
+
+      if (fwrite (hd->min_code, sizeof (*hd->min_code), hd->maxcodelen + 1, f) !=
+	  hd->maxcodelen + 1)
+	return -1;
+
+      if (fwrite (hd->clens, sizeof (*hd->clens), hd->num_codes, f) != hd->num_codes)
+	return -1;
+
+      /* [RPAP - Jan 97: Endian Ordering] */
+      for (i = hd->mincodelen; i < hd->maxcodelen + 1; i++)
+	NTOHSI(hd->lencount[i]);
+      for (i = 0; i < hd->maxcodelen + 1; i++)
+	NTOHUL(hd->min_code[i]);
+    }
+  return 0;
+}
+
+
+
+
+static int 
+General_Read_Huffman_Data (size_t (*rd) (), void *f,
+			   huff_data * hd, u_long * mem, u_long * disk)
+{
+  if (rd (&hd->num_codes, sizeof (hd->num_codes), 1, f) != 1)
+    return -1;
+
+  if (rd (&hd->mincodelen, sizeof (hd->mincodelen), 1, f) != 1)
+    return -1;
+
+  if (rd (&hd->maxcodelen, sizeof (hd->maxcodelen), 1, f) != 1)
+    return -1;
+
+  /* [RPAP - Jan 97: Endian Ordering] */
+  NTOHSI(hd->num_codes);
+  NTOHSI(hd->mincodelen);
+  NTOHSI(hd->maxcodelen);
+
+  if (disk)
+    (*disk) += sizeof (hd->num_codes) + sizeof (hd->mincodelen) +
+      sizeof (hd->maxcodelen);
+
+  hd->clens = NULL;
+
+  if (hd->num_codes)
+    {
+      int i;  /* [RPAP - Jan 97: Endian Ordering] */
+
+      bzero ((char *) (hd->lencount), sizeof (hd->lencount));
+      if (rd (hd->lencount + hd->mincodelen, sizeof (*hd->lencount),
+	      hd->maxcodelen - hd->mincodelen + 1, f) !=
+	  hd->maxcodelen - hd->mincodelen + 1)
+	return -1;
+
+      /* [RPAP - Jan 97: Endian Ordering] */
+      for (i = hd->mincodelen; i < hd->maxcodelen + 1; i++)
+	NTOHSI(hd->lencount[i]);
+
+      if (disk)
+	(*disk) += sizeof (*hd->lencount) * (hd->maxcodelen - hd->mincodelen + 1);
+
+      bzero ((char *) (hd->min_code), sizeof (hd->min_code));
+
+      if (rd (hd->min_code, sizeof (*hd->min_code), hd->maxcodelen + 1, f) !=
+	  hd->maxcodelen + 1)
+	return -1;
+
+      /* [RPAP - Jan 97: Endian Ordering] */
+      for (i = 0; i < hd->maxcodelen + 1; i++)
+	NTOHUL(hd->min_code[i]);
+
+      if (disk)
+	(*disk) += sizeof (*hd->min_code) * (hd->maxcodelen + 1);
+
+      if (!(hd->clens = Xmalloc (sizeof (*hd->clens) * hd->num_codes)))
+	return -1;
+
+
+      if (rd (hd->clens, sizeof (*hd->clens), hd->num_codes, f) != hd->num_codes)
+	return -1;
+
+      if (disk)
+	(*disk) += sizeof (*hd->clens) * hd->num_codes;
+    }
+
+  if (mem)
+    *mem += sizeof (*hd->clens) * hd->num_codes;
+  return 0;
+}
+
+
+
+int 
+Read_Huffman_Data (FILE * f, huff_data * hd, u_long * mem, u_long * disk)
+{
+  return General_Read_Huffman_Data (fread, f, hd, mem, disk);
+}
+
+
+
+
+int 
+F_Read_Huffman_Data (File * f, huff_data * hd, u_long * mem, u_long * disk)
+{
+  return General_Read_Huffman_Data (Fread, f, hd, mem, disk);
+}
Index: /main/tags/2.25/gsdl/packages/mg/lib/huffman.h
===================================================================
--- /main/tags/2.25/gsdl/packages/mg/lib/huffman.h	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/mg/lib/huffman.h	(revision 21064)
@@ -0,0 +1,114 @@
+/**************************************************************************
+ *
+ * huffman.h -- Huffman coding functions
+ * Copyright (C) 1994  Neil Sharman
+ *
+ * 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.
+ *
+ * $Id$
+ *
+ **************************************************************************/
+
+#ifndef H_HUFFMAN
+#define H_HUFFMAN
+
+#include "sysfuncs.h"
+
+#include "filestats.h"
+
+
+#define MAX_HUFFCODE_LEN 31
+
+typedef struct huff_data
+  {
+    int num_codes;
+    int mincodelen;
+    int maxcodelen;
+    int lencount[MAX_HUFFCODE_LEN + 1];
+    unsigned long min_code[MAX_HUFFCODE_LEN + 1];
+    char *clens;
+  }
+huff_data;
+
+
+huff_data *Generate_Huffman_Data (int num, long *freqs, huff_data * data,
+				  u_long * mem);
+
+unsigned long *Generate_Huffman_Codes (huff_data * data, u_long * mem);
+
+unsigned long **Generate_Huffman_Vals (huff_data * data, u_long * mem);
+
+int Write_Huffman_Data (FILE * f, huff_data * hd);
+
+int Read_Huffman_Data (FILE * f, huff_data * hd, u_long * mem, u_long * disk);
+
+int F_Read_Huffman_Data (File * f, huff_data * hd, u_long * mem, u_long * disk);
+
+/* Calculate the number of bits required to code the data with the
+   specified frequencies. Normally freqs and counts should point to
+   the same array. */
+double Calculate_Huffman_Size (int num, long *freqs, long *counts);
+
+
+
+#define HUFF_ENCODE(x, codes, lens)					\
+  do {									\
+    register int __i;							\
+    register int __clen = (lens)[x];					\
+    register unsigned long __code = (codes)[x];				\
+    for (__i=__clen-1; __i>=0; __i--)					\
+      ENCODE_BIT((__code >> __i) & 1);					\
+  } while(0)
+
+#define HUFF_ENCODE_L(x, codes, lens, count)				\
+  do {									\
+    HUFF_ENCODE(x, codes, lens);		   			\
+    (count) += (lens)[x];						\
+  } while(0)
+
+
+#define HUFF_DECODE(x, mcodes, values)					\
+  do {									\
+    register unsigned long *__min_code = (mcodes);			\
+    register unsigned long *__mclen = __min_code;			\
+    register unsigned long **__values = (values);			\
+    register unsigned long __code = 0;					\
+    do									\
+      {									\
+        DECODE_ADD(__code);						\
+      }									\
+    while (__code < *++__mclen);					\
+    (x) = __values[__mclen - __min_code][__code - *__mclen];		\
+  } while(0);
+
+
+#define HUFF_DECODE_L(x, mcodes, values, count)				\
+  do {									\
+    register unsigned long *__min_code = (mcodes);			\
+    register unsigned long *__mclen = __min_code;			\
+    register unsigned long **__values = (values);			\
+    register unsigned long __code = 0;					\
+    do									\
+      {									\
+        DECODE_ADD(__code);						\
+	(count)++;							\
+      }									\
+    while (__code < *++__mclen);					\
+    (x) = __values[__mclen - __min_code][__code - *__mclen];		\
+  } while(0);
+
+
+
+#endif
Index: /main/tags/2.25/gsdl/packages/mg/lib/huffman_mem.c
===================================================================
--- /main/tags/2.25/gsdl/packages/mg/lib/huffman_mem.c	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/mg/lib/huffman_mem.c	(revision 21064)
@@ -0,0 +1,66 @@
+/**************************************************************************
+ *
+ * huffman_mem.c -- Huffman coding functions to memory
+ * Copyright (C) 1994  Neil Sharman
+ *
+ * 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.
+ *
+ * $Id$
+ *
+ **************************************************************************/
+
+/*
+   $Log$
+   Revision 1.1  1999/08/10 21:16:51  sjboddie
+   renamed mg-1.3d directory mg
+
+   Revision 1.1  1998/11/17 09:32:05  rjmcnab
+   *** empty log message ***
+
+   * Revision 1.1  1994/08/22  00:24:45  tes
+   * Initial placement under CVS.
+   *
+ */
+
+static char *RCSID = "$Id$";
+
+#include "sysfuncs.h"
+#include "bitio_m.h"
+#include "bitio_m_mem.h"
+#include "huffman.h"
+
+#if 0
+int fprintf (FILE *, const char *,...);
+#endif
+
+void 
+BIO_Mem_Huff_Encode (unsigned long val, unsigned long *codes,
+		     char *clens, mem_bitio_state * bs)
+{
+  ENCODE_CONTINUE (*bs)
+    HUFF_ENCODE (val, codes, clens);
+  ENCODE_PAUSE (*bs)
+}
+
+unsigned long 
+BIO_Mem_Huff_Decode (unsigned long *mincodes,
+		     unsigned long **values, mem_bitio_state * bs)
+{
+  unsigned long val;
+  DECODE_CONTINUE (*bs)
+    HUFF_DECODE (val, mincodes, values);
+  DECODE_PAUSE (*bs)
+    return (val);
+}
Index: /main/tags/2.25/gsdl/packages/mg/lib/huffman_mem.h
===================================================================
--- /main/tags/2.25/gsdl/packages/mg/lib/huffman_mem.h	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/mg/lib/huffman_mem.h	(revision 21064)
@@ -0,0 +1,36 @@
+/**************************************************************************
+ *
+ * huffman_mem.h -- Huffman coding functions to memory
+ * Copyright (C) 1994  Neil Sharman
+ *
+ * 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.
+ *
+ * $Id$
+ *
+ **************************************************************************/
+
+#ifndef H_HUFFMAN_MEM
+#define H_HUFFMAN_MEM
+
+
+
+void BIO_Mem_Huff_Encode (unsigned long val, unsigned long *codes,
+			  char *clens, mem_bitio_state * bs);
+
+unsigned long BIO_Mem_Huff_Decode (unsigned long *mincodes,
+			      unsigned long **values, mem_bitio_state * bs);
+
+
+#endif
Index: /main/tags/2.25/gsdl/packages/mg/lib/huffman_stdio.c
===================================================================
--- /main/tags/2.25/gsdl/packages/mg/lib/huffman_stdio.c	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/mg/lib/huffman_stdio.c	(revision 21064)
@@ -0,0 +1,70 @@
+/**************************************************************************
+ *
+ * huffman_stdio.c -- Huffman coding function to a file
+ * Copyright (C) 1994  Neil Sharman
+ *
+ * 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.
+ *
+ * $Id$
+ *
+ **************************************************************************/
+
+/*
+   $Log$
+   Revision 1.1  1999/08/10 21:16:52  sjboddie
+   renamed mg-1.3d directory mg
+
+   Revision 1.1  1998/11/17 09:32:07  rjmcnab
+   *** empty log message ***
+
+   * Revision 1.1  1994/08/22  00:24:46  tes
+   * Initial placement under CVS.
+   *
+ */
+
+static char *RCSID = "$Id$";
+
+#include "sysfuncs.h"
+
+#include "bitio_m.h"
+#include "bitio_m_stdio.h"
+#include "huffman.h"
+
+#if 0
+int fprintf (FILE *, const char *,...);
+int _filbuf (FILE *);
+int _flsbuf (unsigned, FILE *);
+#endif
+
+void 
+BIO_Stdio_Huff_Encode (unsigned long val, unsigned long *codes,
+		       char *clens, stdio_bitio_state * bs)
+{
+  ENCODE_CONTINUE (*bs)
+    HUFF_ENCODE (val, codes, clens);
+  ENCODE_PAUSE (*bs)
+}
+
+unsigned long 
+BIO_Stdio_Huff_Decode (unsigned long *mincodes,
+		       unsigned long **values,
+		       stdio_bitio_state * bs)
+{
+  unsigned long val;
+  DECODE_CONTINUE (*bs)
+    HUFF_DECODE (val, mincodes, values);
+  DECODE_PAUSE (*bs)
+    return (val);
+}
Index: /main/tags/2.25/gsdl/packages/mg/lib/huffman_stdio.h
===================================================================
--- /main/tags/2.25/gsdl/packages/mg/lib/huffman_stdio.h	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/mg/lib/huffman_stdio.h	(revision 21064)
@@ -0,0 +1,38 @@
+/**************************************************************************
+ *
+ * huffman_stdio.h -- Huffman coding function to a file
+ * Copyright (C) 1994  Neil Sharman
+ *
+ * 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.
+ *
+ * $Id$
+ *
+ **************************************************************************/
+
+#ifndef H_HUFFMAN_STDIO
+#define H_HUFFMAN_STDIO
+
+
+
+void BIO_Stdio_Huff_Encode (unsigned long val, unsigned long *codes,
+			    char *clens, stdio_bitio_state * bs);
+
+
+unsigned long BIO_Stdio_Huff_Decode (unsigned long *mincodes,
+				     unsigned long **values,
+				     stdio_bitio_state * bs);
+
+
+#endif
Index: /main/tags/2.25/gsdl/packages/mg/lib/local_strings.c
===================================================================
--- /main/tags/2.25/gsdl/packages/mg/lib/local_strings.c	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/mg/lib/local_strings.c	(revision 21064)
@@ -0,0 +1,415 @@
+/**************************************************************************
+ *
+ * local_strings -- provides some extra string routines
+ * Copyright (C) 1994  Authors
+ *
+ * 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.
+ *
+ * $Id$
+ *
+ **************************************************************************/
+
+static char *RCSID = "$Id$";
+
+#include "sysfuncs.h"
+
+#include "local_strings.h"
+#include "memlib.h"
+
+/* =========================================================================
+ * Function: arg_atoi
+ * Description: 
+ *      Converts an ascii string to an integer
+ *      but allows a scale string immediately following.
+ *      i.e. "10Mb" or "20Kb" or "40Megabytes"
+ *      There must be no gap between the last digit and the scale.
+ *      Only the fist letter is significant.
+ *      K = Kilo
+ *      M = Mega
+ *      G = Giga
+ * Input: 
+ *      string of form: xxxxxxK or xxxxxxxM or xxxxxxxG
+ *      where x is a digit
+ * Output: 
+ *      a scaled integer
+ * ========================================================================= */
+
+#define KILO 	1024
+#define MEGA	1024*1024
+#define GIGA	1024*1024*1024
+
+int 
+arg_atoi (char *str)
+{
+  char *str_ptr = str;
+  char ch = '\0';
+  long scale = 1;
+
+  /* find any scale letter immediately after digits */
+  ch = *str_ptr;
+  while (!isalpha (ch) && (ch != '\0'))
+    ch = *str_ptr++;
+
+  /* replace scale letter by end-of-string character */
+  *str_ptr = '\0';
+
+  /* set scale appropriately */
+  switch (ch)
+    {
+    case 'K':
+      scale = KILO;
+      break;
+    case 'M':
+      scale = MEGA;
+      break;
+    case 'G':
+      scale = GIGA;
+      break;
+    default:
+      scale = 1;
+      break;
+    }
+
+  return (atoi (str) * scale);
+
+}
+
+/* ===============================================================================
+ * Function: compare
+ * Description: Compare two strings. 
+ * Input: Two binary strings, first byte of string indicates length. 
+ * Output: Like standard strcmp.
+ *      = 0 if s1 = s2
+ *      < 0 if s1 < s2
+ *      > 0 if s1 > s2
+ * =============================================================================== */
+int 
+compare (u_char * s1, u_char * s2)
+{
+  int l1 = *s1, l2 = *s2;
+  int l = (l1 < l2) ? l1 : l2;
+
+  while (l--)
+    if (*++s1 != *++s2)
+      return (*s1 - *s2);
+  return (l1 - l2);
+
+}
+
+/*
+ * This array is designed for mapping upper and lower case letter
+ * together for a case independent comparison.  The mappings are
+ * based upon ascii character sequences.
+ */
+static unsigned char casecharmap[] = {
+	'\000', '\001', '\002', '\003', '\004', '\005', '\006', '\007',
+	'\010', '\011', '\012', '\013', '\014', '\015', '\016', '\017',
+	'\020', '\021', '\022', '\023', '\024', '\025', '\026', '\027',
+	'\030', '\031', '\032', '\033', '\034', '\035', '\036', '\037',
+	'\040', '\041', '\042', '\043', '\044', '\045', '\046', '\047',
+	'\050', '\051', '\052', '\053', '\054', '\055', '\056', '\057',
+	'\060', '\061', '\062', '\063', '\064', '\065', '\066', '\067',
+	'\070', '\071', '\072', '\073', '\074', '\075', '\076', '\077',
+	'\100', '\141', '\142', '\143', '\144', '\145', '\146', '\147',
+	'\150', '\151', '\152', '\153', '\154', '\155', '\156', '\157',
+	'\160', '\161', '\162', '\163', '\164', '\165', '\166', '\167',
+	'\170', '\171', '\172', '\133', '\134', '\135', '\136', '\137',
+	'\140', '\141', '\142', '\143', '\144', '\145', '\146', '\147',
+	'\150', '\151', '\152', '\153', '\154', '\155', '\156', '\157',
+	'\160', '\161', '\162', '\163', '\164', '\165', '\166', '\167',
+	'\170', '\171', '\172', '\173', '\174', '\175', '\176', '\177',
+	'\200', '\201', '\202', '\203', '\204', '\205', '\206', '\207',
+	'\210', '\211', '\212', '\213', '\214', '\215', '\216', '\217',
+	'\220', '\221', '\222', '\223', '\224', '\225', '\226', '\227',
+	'\230', '\231', '\232', '\233', '\234', '\235', '\236', '\237',
+	'\240', '\241', '\242', '\243', '\244', '\245', '\246', '\247',
+	'\250', '\251', '\252', '\253', '\254', '\255', '\256', '\257',
+	'\260', '\261', '\262', '\263', '\264', '\265', '\266', '\267',
+	'\270', '\271', '\272', '\273', '\274', '\275', '\276', '\277',
+	'\300', '\341', '\342', '\343', '\344', '\345', '\346', '\347',
+	'\350', '\351', '\352', '\353', '\354', '\355', '\356', '\357',
+	'\360', '\361', '\362', '\363', '\364', '\365', '\366', '\367',
+	'\370', '\371', '\372', '\333', '\334', '\335', '\336', '\337',
+	'\340', '\341', '\342', '\343', '\344', '\345', '\346', '\347',
+	'\350', '\351', '\352', '\353', '\354', '\355', '\356', '\357',
+	'\360', '\361', '\362', '\363', '\364', '\365', '\366', '\367',
+	'\370', '\371', '\372', '\373', '\374', '\375', '\376', '\377',
+};
+
+/* ===============================================================================
+ * Function: casecompare   [RPAP - Jan 97: Stem Index Change]
+ * Description: Compare two strings in dictionary order
+ * Input: Two binary strings, first byte of string indicates length. 
+ * Output:
+ *      = 0 if s1 = s2
+ *      < 0 if s1 < s2
+ *      > 0 if s1 > s2
+ * =============================================================================== */
+int 
+casecompare (u_char * s1, u_char * s2)
+{
+  int l1 = *s1, l2 = *s2;
+  int l = (l1 < l2) ? l1 : l2;
+  int pos = 0;
+  register int diff = 0;
+
+  while (l--)
+    if ((diff = casecharmap[*++s1] - casecharmap[*++s2]) != 0)
+      return (diff);
+    else if ((diff = *s1 - *s2) != 0)
+      if (!pos)
+	pos = diff;
+
+  return ((l1 - l2) ? (l1 - l2) : (pos));
+
+}
+
+/* =========================================================================
+ * Function: copy_string
+ * Description: 
+ *      Copies a string with the len in 1st byte
+ * Input: 
+ * Output: 
+ * ========================================================================= */
+
+u_char *
+copy_string (u_char * src_str)
+{
+  u_char *copy = Xmalloc (src_str[0] + 1);
+
+  if (!copy)
+    return NULL;
+
+  bcopy ((char *) src_str, (char *) (copy), src_str[0] + 1);
+  return copy;
+
+}
+
+
+/* ===============================================================================
+ * Function: prefixlen
+ * Description: Returns length of common prefix string between s1 and s2.
+ * Input: two binary strings
+ * Output: prefix length
+ * =============================================================================== */
+int 
+prefixlen (u_char * s1, u_char * s2)
+{
+  int l = (*s1 < *s2) ? *s1 : *s2;
+  int i = 0;
+
+  while (i < l && *++s1 == *++s2)
+    i++;
+  return (i);
+}
+
+
+/* ===============================================================================
+ * Function: char2str
+ * Description: 
+ *      Ensures that non-printable characters are converted to a string
+ *      which is printable i.e. it indentifies the character.
+ *      e.g. carriage-return = "\n".
+ * Input: character (may be non-printable)
+ * Output: pointer to static string
+ * =============================================================================== */
+
+char *
+char2str (u_char c)
+{
+  static char buf[10];
+  switch (c)
+    {
+    case '\n':
+      sprintf (buf, "\\n");
+      break;
+    case '\b':
+      sprintf (buf, "\\b");
+      break;
+    case '\f':
+      sprintf (buf, "\\f");
+      break;
+    case '\t':
+      sprintf (buf, "\\t");
+      break;
+    default:
+	if (c >= ' ' && c <= 126)
+	switch (c)
+	  {
+	  case '\\':
+	    sprintf (buf, "\\\\");
+	    break;
+	  case '\"':
+	    sprintf (buf, "\\\"");
+	    break;
+	  case '\'':
+	    sprintf (buf, "\\\'");
+	    break;
+	  default:
+	    buf[0] = c;
+	    buf[1] = '\0';
+	    break;
+	  }
+      else
+	sprintf (buf, "\\x%02x", c);
+      break;
+    }
+  return buf;
+}
+
+/* ===============================================================================
+ * Function: word2str
+ * Description: 
+ *      Converts a string with possible non-printable characters into a string
+ *      consisting entirely of printable characters.
+ * Input: string, length stored in first byte
+ * Output: pointer to static string
+ * =============================================================================== */
+
+char *
+word2str (u_char * s)
+{
+  static char buf[1024];
+  char *p = buf;
+  int i, len = (int) *s++;
+
+  bzero (buf, sizeof (buf));
+  for (i = 0; i < len; i++)
+    {
+      strcpy (p, char2str (s[i]));
+      p = strchr (p, '\0');
+    }
+  return buf;
+}
+
+
+/* =========================================================================
+ * Function: de_escape_string
+ * Description: 
+ *      Turn a string containing \ escapes into real characters
+ *      Note this destroys the string s in the process
+ * Input: string to de-escape 
+ * Output: the de-escaped string
+ * ========================================================================= */
+char *
+de_escape_string (char *s)
+{
+  char *org = s;
+  char *d = s;
+  while (*s)
+    {
+      if (*s == '\\')
+	{
+	  s++;
+	  switch (*s++)
+	    {
+	    case '\0':
+	      *d++ = '\\';
+	      s--;
+	      break;
+	    case '\\':
+	      *d++ = '\\';
+	      break;
+	    case 'b':
+	      *d++ = '\b';
+	      break;
+	    case 'f':
+	      *d++ = '\f';
+	      break;
+	    case 'n':
+	      *d++ = '\n';
+	      break;
+	    case 'r':
+	      *d++ = '\r';
+	      break;
+	    case 't':
+	      *d++ = '\r';
+	      break;
+	    case '\"':
+	      *d++ = '\"';
+	      break;
+	    case '\'':
+	      *d++ = '\'';
+	      break;
+	    case 'x':
+	      {
+		int num = 0;
+		if (isxdigit (*s))
+		  {
+		    char ch = toupper (*s++);
+		    num = ch <= '9' ? ch - '0' : ch - 'A' + 10;
+		  }
+		if (isxdigit (*s))
+		  {
+		    char ch = toupper (*s++);
+		    num = (num << 4) + (ch <= '9' ? ch - '0' : ch - 'A' + 10);
+		  }
+		*d++ = num;
+		break;
+	      }
+	    case '0':
+	    case '1':
+	    case '2':
+	    case '3':
+	    case '4':
+	    case '5':
+	    case '6':
+	    case '7':
+	      {
+		int num = *(s - 1) - '0';
+		if (*s >= '0' && *s <= '7')
+		  num = (num << 3) + *s++ - '0';
+		if (*s >= '0' && *s <= '7')
+		  num = (num << 3) + *s++ - '0';
+		*d++ = num;
+		break;
+	      }
+	    }
+	}
+      else
+	*d++ = *s++;
+    }
+  *d = '\0';
+  return (org);
+}
+
+/* =========================================================================
+ * Function: str255_to_string 
+ * Description: 
+ * Input: 
+ * Output: 
+ * ========================================================================= */
+
+char *
+str255_to_string (u_char * str255, char *str)
+{
+  static char buf[256];
+  char *str_base = NULL;
+  int len = *str255++;
+  int i = 0;
+
+  /* if haven't been given a str to write to then use local buffer */
+  if (!str)
+    str = &(buf[0]);
+
+  str_base = str;
+  for (i = 0; i < len; i++)
+    {
+      *str++ = *str255++;
+    }
+  *str = '\0';
+
+  return str_base;
+}
Index: /main/tags/2.25/gsdl/packages/mg/lib/local_strings.h
===================================================================
--- /main/tags/2.25/gsdl/packages/mg/lib/local_strings.h	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/mg/lib/local_strings.h	(revision 21064)
@@ -0,0 +1,39 @@
+/**************************************************************************
+ *
+ * local_strings.h -- string routines
+ * Copyright (C) 1994  Neil Sharman
+ *
+ * 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.
+ *
+ * $Id$
+ *
+ **************************************************************************/
+
+#ifndef LOCAL_STRINGS_H
+#define LOCAL_STRINGS_H
+
+#include "sysfuncs.h"
+
+int arg_atoi (char *str);
+int compare (u_char * s1, u_char * s2);
+int casecompare (u_char * s1, u_char * s2);   /* [RPAP - Jan 97: Stem Index Change] */
+u_char *copy_string (u_char * src_str);
+char *str255_to_string (u_char * str255, char *str);
+int prefixlen (u_char * s1, u_char * s2);
+char *char2str (u_char c);
+char *word2str (u_char * s);
+char *de_escape_string (char *s);
+
+#endif
Index: /main/tags/2.25/gsdl/packages/mg/lib/lovinstem.c
===================================================================
--- /main/tags/2.25/gsdl/packages/mg/lib/lovinstem.c	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/mg/lib/lovinstem.c	(revision 21064)
@@ -0,0 +1,1187 @@
+/**************************************************************************
+ *
+ * lovinstem.c -- Stemming code
+ * Copyright (C) 1994  Linh Huynh (linh@kbs.citri.edu.au)
+ *
+ * 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.
+ *
+ * $Id$
+ *
+ **************************************************************************/
+
+static char *RCSID = "$Id$";
+
+#include "sysfuncs.h"
+
+
+/*****************************************************************************
+ *
+ *   Transformational Rules used in Recoding Stem Terminations
+ *
+ *   Parameter in functions:
+ *       ch : the second last character of the old ending
+ *            (after removing one of double consonants) 
+ *
+ ****************************************************************************/
+
+
+/************ Conditional rules associated with transformations **************/
+
+static int aio ();
+static int s ();
+static int pt ();
+static int m ();
+static int n ();
+
+static int 
+aio (ch)			/* Rule number 9     */
+     char ch;
+{
+  return ((ch != 'a') && (ch != 'i') && (ch != 'o'));
+}
+
+static int 
+s (ch)				/* Rule Number 24    */
+     char ch;
+{
+  return (ch != 's');
+}
+
+static int 
+pt (ch)				/* Rule number 28    */
+     char ch;
+{
+  return ((ch != 'p') && (ch != 't'));
+}
+
+static int 
+m (ch)				/* Rule number 30    */
+     char ch;
+{
+  return (ch != 'm');
+}
+
+static int 
+n (ch)				/* Rule number 32    */
+     char ch;
+{
+  return (ch != 'n');
+}
+
+
+/**************************************************************************
+ *
+ *  Context-sensitive rules associated with certain endings.
+ *
+ *  The notations of the rules are the same as in Lovins' paper
+ *  except that rule A is replaced by a NULL in the data structure.
+ *
+ *  Function parameters:
+ *      - stem_length: possible stem length
+ *      - end        : pointer points to the end of the possible stem.
+ *
+ *************************************************************************/
+
+
+/********* Context-sensitive rule function declarations ******************/
+
+static int B ();
+static int C ();
+static int D ();
+static int E ();
+static int F ();
+static int G ();
+static int H ();
+static int I ();
+static int J ();
+static int K ();
+static int L ();
+static int M ();
+static int N ();
+static int O ();
+static int P ();
+static int Q ();
+static int R ();
+static int S ();
+static int T ();
+static int U ();
+static int V ();
+static int W ();
+static int X ();
+static int Y ();
+static int Z ();
+static int AA ();
+static int BB ();
+static int CC ();
+
+static int 
+B (stem_length, end)
+     int stem_length;
+     char *end;
+{
+  return (stem_length >= 3);
+}
+
+static int 
+C (stem_length, end)
+     int stem_length;
+     char *end;
+{
+  return (stem_length >= 4);
+}
+
+static int 
+D (stem_length, end)
+     int stem_length;
+     char *end;
+{
+  return (stem_length >= 5);
+}
+
+static int 
+E (stem_length, end)
+     int stem_length;
+     char *end;
+{
+  return (*end != 'e');
+}
+
+static int 
+F (stem_length, end)
+     int stem_length;
+     char *end;
+{
+  return ((stem_length >= 3) && (*end != 'e'));
+}
+
+static int 
+G (stem_length, end)
+     int stem_length;
+     char *end;
+{
+  return ((stem_length >= 3) && (*end == 'f'));
+}
+
+static int 
+H (stem_length, end)
+     int stem_length;
+     char *end;
+{
+  char p1, p2;
+  p1 = *end;
+  p2 = *(end - 1);
+  return ((p1 == 't') || ((p1 == 'l') && (p2 == 'l')));
+}
+
+static int 
+I (stem_length, end)
+     int stem_length;
+     char *end;
+{
+  char p1;
+  p1 = *end;
+  return ((p1 != 'o') && (p1 != 'e'));
+}
+
+static int 
+J (stem_length, end)
+     int stem_length;
+     char *end;
+{
+  char p1;
+  p1 = *end;
+  return ((p1 != 'a') && (p1 != 'e'));
+}
+
+static int 
+K (stem_length, end)
+     int stem_length;
+     char *end;
+{
+  char p1;
+  p1 = *end;
+  return ((stem_length >= 3) &&
+	  ((p1 == 'l') || (p1 == 'i') ||
+	   ((p1 == 'e') && (*(end - 2) == 'u'))));
+}
+
+static int 
+L (stem_length, end)
+     int stem_length;
+     char *end;
+{
+  char p1, p2;
+  p1 = *end;
+  p2 = *(end - 1);
+  if (p1 == 's')
+    return (p2 == 'o');
+  else
+    return ((p1 != 'u') && (p1 != 'x'));
+}
+
+static int 
+M (stem_length, end)
+     int stem_length;
+     char *end;
+{
+  char p1;
+  p1 = *end;
+  return ((p1 != 'a') && (p1 != 'c') &&
+	  (p1 != 'e') && (p1 != 'm'));
+}
+
+static int 
+N (stem_length, end)
+     int stem_length;
+     char *end;
+{
+  if (stem_length >= 3)
+    {
+      if (*(end - 2) == 's')
+	return (stem_length >= 4);
+      else
+	return 1;
+    }
+  else
+    return 0;
+}
+
+static int 
+O (stem_length, end)
+     int stem_length;
+     char *end;
+{
+  char p1;
+  p1 = *end;
+  return ((p1 == 'l') || (p1 == 'i'));
+}
+
+static int 
+P (stem_length, end)
+     int stem_length;
+     char *end;
+{
+  return (*end != 'c');
+}
+
+static int 
+Q (stem_length, end)
+     int stem_length;
+     char *end;
+{
+  char p1;
+  p1 = *end;
+
+  return ((stem_length >= 3) && (p1 != 'l') && (p1 != 'n'));
+}
+
+static int 
+R (stem_length, end)
+     int stem_length;
+     char *end;
+{
+  char p1;
+  p1 = *end;
+  return ((p1 == 'n') || (p1 == 'r'));
+}
+
+static int 
+S (stem_length, end)
+     int stem_length;
+     char *end;
+{
+  char p1, p2;
+  p1 = *end;
+  p2 = *(end - 1);
+
+  if (p1 == 't')
+    return (p2 != 't');
+  else
+    return ((p1 == 'r') && (p2 == 'd'));
+}
+
+static int 
+T (stem_length, end)
+     int stem_length;
+     char *end;
+{
+  char p1, p2;
+  p1 = *end;
+  p2 = *(end - 1);
+
+  if (p1 == 't')
+    return (p2 != 'o');
+  else
+    return (p1 == 's');
+}
+
+static int 
+U (stem_length, end)
+     int stem_length;
+     char *end;
+{
+  char p1;
+  p1 = *end;
+
+  return ((p1 == 'l') || (p1 == 'm') ||
+	  (p1 == 'n') || (p1 == 'r'));
+}
+
+static int 
+V (stem_length, end)
+     int stem_length;
+     char *end;
+{
+  return (*end == 'c');
+}
+
+static int 
+W (stem_length, end)
+     int stem_length;
+     char *end;
+{
+  char p1;
+  p1 = *end;
+
+  return ((p1 != 's') && (p1 != 'u'));
+}
+
+static int 
+X (stem_length, end)
+     int stem_length;
+     char *end;
+{
+  char p1;
+  p1 = *end;
+
+  if (p1 == 'e')
+    return ((stem_length >= 3) && (*(end - 2) == 'u'));
+  else
+    return ((p1 == 'l') || (p1 == 'i'));
+}
+
+static int 
+Y (stem_length, end)
+     int stem_length;
+     char *end;
+{
+  return ((*end == 'n') && (*(end - 1) == 'i'));
+}
+
+static int 
+Z (stem_length, end)
+     int stem_length;
+     char *end;
+{
+  return (*end != 'f');
+}
+
+static int 
+AA (stem_length, end)
+     int stem_length;
+     char *end;
+{
+  char p1, p2;
+  p1 = *end;
+  p2 = *(end - 1);
+
+  if (p1 == 'h')
+    return ((p2 == 'p') || (p2 == 't'));
+  else if (p1 == 'r')
+    return ((p2 == 'e') || (p2 == 'o'));
+  else if (p1 == 's')
+    return (p2 == 'e');
+  else
+    return ((p1 == 'd') || (p1 == 'f') ||
+	    (p1 == 'l') || (p1 == 't'));
+}
+
+static int 
+BB (stem_length, end)
+     int stem_length;
+     char *end;
+{
+  if (stem_length >= 3)
+    {
+      if (stem_length >= 4)
+	return (strncmp (end - 3, "ryst", 4) != 0);
+      else
+	return (strncmp (end - 2, "met", 3) != 0);
+    }
+  else
+    return 0;
+}
+
+static int 
+CC (stem_length, end)
+     int stem_length;
+     char *end;
+{
+  return (*end == 'l');
+}
+
+/**************************************************************************/
+
+#define MIN_STEM_LENGTH 2
+#define MAX_ENDING_SIZE 11
+#define PREDEFINED_SIZE (MAX_ENDING_SIZE + MIN_STEM_LENGTH)
+#define EOS     '\0'
+/* [RPAP - Jan 97: Stem Index Change] */
+#define MAX_STEM_LENGTH 255
+
+static char *remove_ending (char *word, int w_len);
+static void recode_stem (char *stem_end);
+
+/* =========================================================================
+ * Function: stem
+ * Description: 
+ *      Implemetation of the Lovins' stemming algorithm described in
+ *      J.B. Lovins, "Development of a Stemming Algorithm",
+ *      Mechanical Translation and Computational Linguistics, Vol 11,1968.
+ * Input: a word string with the length in the first byte
+ * Output: the stemmed word
+ * ========================================================================= */
+
+void
+lovinstem (u_char * word)
+{
+  char *word_start;		/* points to first letter of word */
+  char *stem_end;		/* points to last character of stem portion */
+  int old_length;		/* length of word */
+  int new_length;		/* length after stemming */
+
+  /* [RPAP - Jan 97: Stem Index Change] */
+  u_char copy[MAX_STEM_LENGTH + 2];
+  bcopy ((char *) word, (char *) copy, *word + 1);
+
+  old_length = *copy; /* [RPAP - Jan 97: Stem Index Change] */
+
+  /* The word must be at least MIN_STEM_LENGTH characters long. */
+  if (old_length <= MIN_STEM_LENGTH)
+    return;
+
+  word_start = (char *) copy + 1;	/* jump over length byte */ /* [RPAP - Jan 97: Stem Index Change] */
+  copy[old_length + 1] = '\0';	/* null terminate string */ /* [RPAP - Jan 97: Stem Index Change] */
+
+  stem_end = remove_ending (word_start, old_length);
+  recode_stem (stem_end);
+
+  /* fix up new length */
+  /* have to use strlen because have no other way of telling length */
+  new_length = strlen (word_start);
+  *copy = new_length;  /* [RPAP - Jan 97: Stem Index Change] */
+
+  /* [RPAP - Jan 97: Stem Index Change] */
+  bcopy ((char *) copy, (char *) word, *copy + 1);
+
+}				/*stem_complex */
+
+/* =========================================================================
+
+ *   Data structure for recoding and the method for recoding the stem. 
+ *
+ * ========================================================================= */
+
+typedef struct
+{
+  char *old_end;		/* old ending */
+  char *new_end;		/* new ending */
+  char old_offset;		/* length of the old ending - 1 */
+  int (*cond) ();		/* condition rule */
+  char end_group;		/* signal the end of the group */
+}
+Recode_Rules;
+
+/*  
+   Stem terminations are divided into groups having the same last
+   character
+ */
+
+static Recode_Rules Rules[] =
+{
+  "uad", "uas", 2, NULL, 0,
+  "vad", "vas", 2, NULL, 0,
+  "cid", "cis", 2, NULL, 0,
+  "lid", "lis", 2, NULL, 0,
+  "erid", "eris", 3, NULL, 0,
+  "pand", "pans", 3, NULL, 0,
+  "end", "ens", 2, s, 0,
+  "end", "ens", 2, m, 0,
+  "ond", "ons", 2, NULL, 0,
+  "lud", "lus", 2, NULL, 0,
+  "rud", "rus", 2, NULL, 1,
+
+  "ul", "l", 1, aio, 1,
+
+  "istr", "ister", 3, NULL, 0,
+  "metr", "meter", 3, NULL, 0,
+  "her", "hes", 2, pt, 1,
+
+  "urs", "ur", 2, NULL, 1,
+
+  "uct", "uc", 2, NULL, 0,
+  "umpt", "um", 3, NULL, 0,
+  "rpt", "rb", 2, NULL, 0,
+  "mit", "mis", 2, NULL, 0,
+  "ert", "ers", 2, NULL, 0,
+  "et", "es", 1, n, 0,
+  "yt", "ys", 1, NULL, 1,
+
+  "iev", "ief", 2, NULL, 0,
+  "olv", "olut", 2, NULL, 1,
+
+  "bex", "bic", 2, NULL, 0,
+  "dex", "dic", 2, NULL, 0,
+  "pex", "pic", 2, NULL, 0,
+  "tex", "tic", 2, NULL, 0,
+  "ax", "ac", 1, NULL, 0,
+  "ex", "ec", 1, NULL, 0,
+  "ix", "ic", 1, NULL, 0,
+  "lux", "luc", 2, NULL, 1,
+
+  "yz", "ys", 1, NULL, 1
+};
+
+typedef struct last
+  {
+    char c;			/* The last character */
+    struct last *left;		/* used in balanced   */
+    struct last *right;		/* binary tree        */
+    Recode_Rules *pt;		/* location of approriate group */
+  }
+Last_Char_Node;
+
+/*------------
+       s
+     /   \
+    l     x
+   / \   / \
+  d   r t   z
+         \
+          v
+---------------*/
+static Last_Char_Node pr[] =
+{
+  'd', NULL, NULL, Rules,
+  'l', pr, pr + 2, Rules + 11,
+  'r', NULL, NULL, Rules + 12,
+  's', pr + 1, pr + 6, Rules + 15,
+  't', NULL, pr + 5, Rules + 16,
+  'v', NULL, NULL, Rules + 23,
+  'x', pr + 4, pr + 7, Rules + 25,
+  'z', NULL, NULL, Rules + 33,
+};
+
+
+/*****************************************************************************
+ *
+ *  Recode the stem according to the transformation rules.
+ *
+ *****************************************************************************/
+
+static void
+recode_stem (char *stem_end)
+{
+  static Last_Char_Node *root = pr + 3;
+  Last_Char_Node *p_last = root;
+  Recode_Rules *rule;		/* points to the transformation list */
+  char *h,			/* points to start of possible ending */
+    ch,				/* last character of the old ending  */
+    ch2;
+
+  h = stem_end - 1;
+  ch = *stem_end;
+  if (*h == ch)			/* Check for double consonant        */
+    {
+      if (strchr ("bdglmnprst", ch) != NULL)
+	{
+	  *stem_end = EOS;
+	  stem_end = h;
+	}
+    }
+
+  do				/* Check for the last character       */
+    {
+      ch2 = p_last->c;
+      if (ch == ch2)
+	break;
+      else if (ch > ch2)
+	p_last = p_last->right;
+      else
+	p_last = p_last->left;
+    }
+  while (p_last != NULL);
+
+  if (p_last != NULL)		/* Check for the rest of suffix list */
+    {
+      rule = p_last->pt;
+      for (;;)
+	{
+	  h = stem_end - rule->old_offset;
+	  if (strcmp (h, rule->old_end) == 0)
+	    {
+	      if (!rule->cond || (*rule->cond) (*(h - 1)))
+		{
+		  (void) strcpy (h, rule->new_end);
+		  break;
+		}
+	    }
+	  if (rule->end_group)
+	    break;
+	  rule++;
+	}
+    }
+}
+
+/* ======================================================================
+
+ *    List of endings and the method to remove the ending 
+ *
+ * ======================================================================*/
+
+/************ Data structures for list of endings  ********************/
+
+typedef struct
+{
+  char *ending;			/* old ending                */
+  int (*cond) ();		/* conditional rule          */
+  signed char left_offset;	/* used to find the siblings */
+  signed char right_offset;	/* in balanced binary tree   */
+}
+Ending_List;
+
+/*
+   The original list of endings is re-organised into groups having
+   the same length and the same first character.
+ */
+
+static Ending_List List[] =
+{
+  "a", NULL, 0, 0,
+
+  "ae", NULL, 0, 0,
+  "al", BB, -1, 2,
+  "ar", X, 0, 0,
+  "as", B, -1, 0,
+
+  "acy", NULL, 0, 1,
+  "age", B, 0, 0,
+  "aic", NULL, -2, 1,
+  "als", BB, 0, 0,
+  "ant", B, -2, 2,
+  "ars", O, 0, 0,
+  "ary", F, -1, 2,
+  "ata", NULL, 0, 0,
+  "ate", NULL, -1, 0,
+
+  "able", NULL, 0, 1,
+  "ably", NULL, 0, 0,
+  "ages", B, -2, 2,
+  "ally", B, 0, 0,
+  "ance", B, -1, 1,
+  "ancy", B, 0, 0,
+  "ants", B, -4, 4,
+  "aric", NULL, 0, 0,
+  "arly", K, -1, 1,
+  "ated", I, 0, 0,
+  "ates", NULL, -2, 2,
+  "atic", B, 0, 0,
+  "ator", NULL, -1, 0,
+
+  "acies", NULL, 0, 0,
+  "acity", NULL, -1, 1,
+  "aging", B, 0, 0,
+  "aical", NULL, -2, 2,
+  "alist", NULL, 0, 0,
+  "alism", B, -1, 0,
+  "ality", NULL, -3, 3,
+  "alize", NULL, 0, 1,
+  "allic", BB, 0, 0,
+  "anced", B, -2, 2,
+  "ances", B, 0, 0,
+  "antic", C, -1, 0,
+  "arial", NULL, -6, 6,
+  "aries", NULL, 0, 1,
+  "arily", NULL, 0, 0,
+  "arity", B, -2, 2,
+  "arize", NULL, 0, 0,
+  "aroid", NULL, -1, 0,
+  "ately", NULL, -3, 3,
+  "ating", I, 0, 1,
+  "ation", B, 0, 0,
+  "ative", NULL, -2, 2,
+  "ators", NULL, 0, 0,
+  "atory", NULL, -1, 1,
+  "ature", E, 0, 0,
+
+  "aceous", NULL, 0, 1,
+  "acious", B, 0, 0,
+  "action", G, -2, 2,
+  "alness", NULL, 0, 0,
+  "ancial", NULL, -1, 1,
+  "ancies", NULL, 0, 0,
+  "ancing", B, -4, 4,
+  "ariser", NULL, 0, 0,
+  "arized", NULL, -1, 1,
+  "arizer", NULL, 0, 0,
+  "atable", NULL, -2, 2,
+  "ations", B, 0, 0,
+  "atives", NULL, -1, 0,
+
+  "ability", NULL, 0, 1,
+  "aically", NULL, 0, 0,
+  "alistic", B, -2, 2,
+  "alities", NULL, 0, 0,
+  "ariness", E, -1, 0,
+  "aristic", NULL, -3, 3,
+  "arizing", NULL, 0, 1,
+  "ateness", NULL, 0, 0,
+  "atingly", NULL, -2, 2,
+  "ational", B, 0, 0,
+  "atively", NULL, -1, 1,
+  "ativism", NULL, 0, 0,
+
+  "ableness", NULL, 0, 1,
+  "arizable", NULL, 0, 0,
+
+  "allically", C, 0, 0,
+  "antaneous", NULL, -1, 1,
+  "antiality", NULL, 0, 0,
+  "arisation", NULL, -2, 2,
+  "arization", NULL, 0, 0,
+  "ationally", B, -1, 1,
+  "ativeness", NULL, 0, 0,
+
+  "antialness", NULL, 0, 0,
+  "arisations", NULL, -1, 1,
+  "arizations", NULL, 0, 0,
+
+  "alistically", B, 0, 1,
+  "arizability", NULL, 0, 0,
+
+  "e", NULL, 0, 0,
+
+  "ed", E, 0, 0,
+  "en", F, -1, 1,
+  "es", E, 0, 0,
+
+  "eal", Y, 0, 0,
+  "ear", Y, -1, 1,
+  "ely", E, 0, 0,
+  "ene", E, -2, 2,
+  "ent", C, 0, 0,
+  "ery", E, -1, 1,
+  "ese", NULL, 0, 0,
+
+  "ealy", Y, 0, 1,
+  "edly", E, 0, 0,
+  "eful", NULL, -2, 1,
+  "eity", NULL, 0, 0,
+  "ence", NULL, -2, 2,
+  "ency", NULL, 0, 0,
+  "ened", E, -1, 2,
+  "enly", E, 0, 0,
+  "eous", NULL, -1, 0,
+
+  "early", Y, 0, 1,
+  "ehood", NULL, 0, 0,
+  "eless", NULL, -2, 2,
+  "elity", NULL, 0, 0,
+  "ement", NULL, -1, 0,
+  "enced", NULL, -3, 3,
+  "ences", NULL, 0, 1,
+  "eness", E, 0, 0,
+  "ening", E, -2, 2,
+  "ental", NULL, 0, 0,
+  "ented", C, -1, 1,
+  "ently", NULL, 0, 0,
+
+  "eature", Z, 0, 0,
+  "efully", NULL, -1, 1,
+  "encies", NULL, 0, 0,
+  "encing", NULL, -2, 2,
+  "ential", NULL, 0, 0,
+  "enting", C, -1, 1,
+  "entist", NULL, 0, 1,
+  "eously", NULL, 0, 0,
+
+  "elihood", E, 0, 1,
+  "encible", NULL, 0, 0,
+  "entally", NULL, -2, 2,
+  "entials", NULL, 0, 0,
+  "entiate", NULL, -1, 1,
+  "entness", NULL, 0, 0,
+
+  "entation", NULL, 0, 0,
+  "entially", NULL, -1, 1,
+  "eousness", NULL, 0, 0,
+
+  "eableness", E, 0, 1,
+  "entations", NULL, 0, 0,
+  "entiality", NULL, -2, 2,
+  "entialize", NULL, 0, 0,
+  "entiation", NULL, -1, 0,
+
+  "entialness", NULL, 0, 0,
+
+  "ful", NULL, 0, 0,
+
+  "fully", NULL, 0, 0,
+
+  "fulness", NULL, 0, 0,
+
+  "hood", NULL, 0, 0,
+
+  "i", NULL, 0, 0,
+
+  "ia", NULL, 0, 0,
+  "ic", NULL, -1, 1,
+  "is", NULL, 0, 0,
+
+  "ial", NULL, 0, 0,
+  "ian", NULL, -1, 1,
+  "ics", NULL, 0, 1,
+  "ide", L, 0, 0,
+  "ied", NULL, -3, 3,
+  "ier", NULL, 0, 0,
+  "ies", P, -1, 0,
+  "ily", NULL, -1, 1,
+  "ine", M, 0, 0,
+  "ing", N, -5, 5,
+  "ion", Q, 0, 0,
+  "ish", C, -1, 1,
+  "ism", B, 0, 1,
+  "ist", NULL, 0, 0,
+  "ite", AA, -3, 3,
+  "ity", NULL, 0, 0,
+  "ium", NULL, -1, 0,
+  "ive", NULL, -1, 1,
+  "ize", F, 0, 0,
+
+  "ials", NULL, 0, 0,
+  "ians", NULL, -1, 0,
+  "ible", NULL, -1, 1,
+  "ibly", NULL, 0, 0,
+  "ical", NULL, -2, 2,
+  "ides", L, 0, 0,
+  "iers", NULL, -1, 1,
+  "iful", NULL, 0, 0,
+  "ines", M, -4, 4,
+  "ings", N, 0, 0,
+  "ions", B, -1, 1,
+  "ious", NULL, 0, 0,
+  "isms", B, -2, 2,
+  "ists", NULL, 0, 0,
+  "itic", H, -1, 1,
+  "ized", F, 0, 1,
+  "izer", F, 0, 0,
+
+  "ially", NULL, 0, 0,
+  "icant", NULL, -1, 1,
+  "ician", NULL, 0, 0,
+  "icide", NULL, -2, 2,
+  "icism", NULL, 0, 0,
+  "icist", NULL, -1, 0,
+  "icity", NULL, -3, 3,
+  "idine", I, 0, 1,
+  "iedly", NULL, 0, 0,
+  "ihood", NULL, -2, 2,
+  "inate", NULL, 0, 0,
+  "iness", NULL, -1, 0,
+  "ingly", B, -6, 6,
+  "inism", J, 0, 1,
+  "inity", CC, 0, 0,
+  "ional", NULL, -2, 2,
+  "ioned", NULL, 0, 0,
+  "ished", NULL, -1, 0,
+  "istic", NULL, -3, 3,
+  "ities", NULL, 0, 1,
+  "itous", NULL, 0, 0,
+  "ively", NULL, -2, 2,
+  "ivity", NULL, 0, 0,
+  "izers", F, -1, 1,
+  "izing", F, 0, 0,
+
+  "ialist", NULL, 0, 0,
+  "iality", NULL, -1, 1,
+  "ialize", NULL, 0, 0,
+  "ically", NULL, -2, 2,
+  "icance", NULL, 0, 0,
+  "icians", NULL, -1, 1,
+  "icists", NULL, 0, 0,
+  "ifully", NULL, -4, 4,
+  "ionals", NULL, 0, 0,
+  "ionate", D, -1, 1,
+  "ioning", NULL, 0, 0,
+  "ionist", NULL, -2, 2,
+  "iously", NULL, 0, 0,
+  "istics", NULL, -1, 1,
+  "izable", E, 0, 0,
+
+  "ibility", NULL, 0, 0,
+  "icalism", NULL, -1, 1,
+  "icalist", NULL, 0, 1,
+  "icality", NULL, 0, 0,
+  "icalize", NULL, -3, 3,
+  "ication", G, 0, 0,
+  "icianry", NULL, -1, 0,
+  "ination", NULL, -1, 1,
+  "ingness", NULL, 0, 0,
+  "ionally", NULL, -5, 5,
+  "isation", NULL, 0, 0,
+  "ishness", NULL, -1, 1,
+  "istical", NULL, 0, 1,
+  "iteness", NULL, 0, 0,
+  "iveness", NULL, -3, 3,
+  "ivistic", NULL, 0, 0,
+  "ivities", NULL, -1, 0,
+  "ization", F, -1, 1,
+  "izement", NULL, 0, 0,
+
+  "ibleness", NULL, 0, 0,
+  "icalness", NULL, -1, 1,
+  "ionalism", NULL, 0, 0,
+  "ionality", NULL, -2, 2,
+  "ionalize", NULL, 0, 0,
+  "iousness", NULL, -1, 1,
+  "izations", NULL, 0, 0,
+
+  "ionalness", NULL, 0, 1,
+  "istically", NULL, 0, 0,
+  "itousness", NULL, -2, 2,
+  "izability", NULL, 0, 0,
+  "izational", NULL, -1, 0,
+
+  "izationally", B, 0, 0,
+
+  "ly", B, 0, 0,
+
+  "less", NULL, 0, 1,
+  "lily", NULL, 0, 0,
+
+  "lessly", NULL, 0, 0,
+
+  "lessness", NULL, 0, 0,
+
+  "ness", NULL, 0, 0,
+
+  "nesses", NULL, 0, 0,
+
+  "o", NULL, 0, 0,
+
+  "on", S, 0, 1,
+  "or", T, 0, 0,
+
+  "oid", NULL, 0, 0,
+  "one", R, -1, 1,
+  "ous", NULL, 0, 0,
+
+  "ogen", NULL, 0, 0,
+
+  "oidal", NULL, 0, 0,
+  "oides", NULL, -1, 2,
+  "otide", NULL, 0, 0,
+  "ously", NULL, -1, 0,
+
+  "oidism", NULL, 0, 0,
+
+  "oidally", NULL, 0, 1,
+  "ousness", NULL, 0, 0,
+
+  "s", W, 0, 0,
+
+  "s'", NULL, 0, 0,
+
+  "um", U, 0, 1,
+  "us", V, 0, 0,
+
+  "ward", NULL, 0, 1,
+  "wise", NULL, 0, 0,
+
+  "y", B, 0, 0,
+
+  "yl", R, 0, 0,
+
+  "ying", B, 0, 1,
+  "yish", NULL, 0, 0,
+
+  "'s", NULL, 0, 0,
+};
+
+typedef struct node
+  {
+    char c;			/* First character  */
+    struct node *left;		/* used in balanced */
+    struct node *right;		/* binary tree      */
+    Ending_List *ptr[11];	/* the approriate location */
+  }
+First_Char_Node;
+
+static First_Char_Node First[] =
+{
+  '\'', NULL, NULL,
+  {NULL,
+   List + 293, NULL, NULL, NULL, NULL,
+   NULL, NULL, NULL, NULL, NULL},
+
+  'a', First, NULL,
+  {List,
+   List + 2, List + 9, List + 20, List + 39, List + 58,
+   List + 70, List + 77, List + 82, List + 87, List + 89},
+
+  'e', First + 1, First + 4,
+  {List + 91,
+   List + 93, List + 98, List + 106, List + 116, List + 126,
+   List + 133, List + 138, List + 142, List + 145, NULL},
+
+  'f', NULL, NULL,
+  {NULL,
+   NULL, List + 146, NULL, List + 147, NULL,
+   List + 148, NULL, NULL, NULL, NULL},
+
+  'h', First + 3, First + 5,
+  {NULL,
+   NULL, NULL, List + 149, NULL, NULL,
+   NULL, NULL, NULL, NULL, NULL},
+
+  'i', NULL, NULL,
+  {List + 150,
+   List + 152, List + 163, List + 181, List + 202, List + 222,
+   List + 239, List + 252, List + 258, NULL, List + 261},
+
+  'l', First + 2, First + 10,
+  {NULL,
+   List + 262, NULL, List + 263, NULL, List + 265,
+   NULL, List + 266, NULL, NULL, NULL},
+
+  'n', NULL, NULL,
+  {NULL,
+   NULL, NULL, List + 267, NULL, List + 268,
+   NULL, NULL, NULL, NULL, NULL},
+
+  'o', First + 7, First + 9,
+  {List + 269,
+   List + 270, List + 273, List + 275, List + 277, List + 280,
+   List + 281, NULL, NULL, NULL, NULL},
+
+  's', NULL, NULL,
+  {List + 283,
+   List + 284, NULL, NULL, NULL, NULL,
+   NULL, NULL, NULL, NULL, NULL},
+
+  'u', First + 8, First + 12,
+  {NULL,
+   List + 285, NULL, NULL, NULL, NULL,
+   NULL, NULL, NULL, NULL, NULL},
+
+  'w', NULL, NULL,
+  {NULL,
+   NULL, NULL, List + 287, NULL, NULL,
+   NULL, NULL, NULL, NULL, NULL},
+
+  'y', First + 11, NULL,
+  {List + 289,
+   List + 290, NULL, List + 291, NULL, NULL,
+   NULL, NULL, NULL, NULL, NULL},
+};
+
+
+/******************************************************************************
+ *
+ *  Look for a match in the suffix list.
+ *  Return the pointer to the end of the new stem if there is a match.
+ *  Otherwise, return the pointer to the end of the original word.
+ *
+ *  Method:
+ *      * Search for the first character in the suffix list.
+ *      * If there is match, search for the rest of the suffix list.
+ *         
+ *****************************************************************************/
+
+static char *
+remove_ending (char *word, int w_len)
+{
+  static First_Char_Node *root = First + 6;	/* the root of binary tree is 'l' */
+  First_Char_Node *p_first;	/* Points to the first character      */
+  /* of the possible suffix             */
+  Ending_List *p_list;		/* Points to the List of Endings      */
+  char *suffix_start,		/* Points to start of possible suffix */
+   *stem_end,			/* Points to the end of possible stem */
+    ch1, ch2;
+  int s_len,			/* Possible stem length               */
+    e_offset,			/* Offset from the end to the start of */
+  /* possible suffix                    */
+    not_done = 1, cmp;
+
+  stem_end = word + w_len - 1;
+  if (w_len > PREDEFINED_SIZE)	/* find the start of suffix   */
+    suffix_start = word + w_len - MAX_ENDING_SIZE;
+  else
+    suffix_start = word + MIN_STEM_LENGTH;
+
+  ch1 = *suffix_start;
+  do				/* Search for the first character     */
+    {
+      p_first = root;
+      do
+	{
+	  ch2 = p_first->c;
+	  if (ch1 == ch2)
+	    break;
+	  else if (ch1 > ch2)
+	    p_first = p_first->right;
+	  else
+	    p_first = p_first->left;
+	}
+      while (p_first != NULL);
+
+      if (p_first != NULL)	/* Search for the rest */
+	{
+	  e_offset = stem_end - suffix_start;
+	  if ((p_list = p_first->ptr[e_offset]) != NULL)
+	    {
+	      for (;;)		/* no need to compare the first char  */
+		{
+		  cmp = strcmp (suffix_start + 1, p_list->ending + 1);
+		  if (cmp > 0)
+		    if (p_list->right_offset)
+		      p_list += p_list->right_offset;
+		    else
+		      break;
+		  else if (cmp < 0)
+		    if (p_list->left_offset)
+		      p_list += p_list->left_offset;
+		    else
+		      break;
+		  else
+		    {
+		      s_len = suffix_start - word;
+		      if (!p_list->cond ||
+			  (*p_list->cond) (s_len, suffix_start - 1))
+			{
+			  *suffix_start = EOS;
+			  stem_end = suffix_start - 1;
+			  not_done = 0;
+			}
+		      break;
+		    }
+		}
+	    }
+	}
+      suffix_start++;
+    }
+  while (not_done && ((ch1 = *suffix_start) != EOS));
+  return (stem_end);
+}
Index: /main/tags/2.25/gsdl/packages/mg/lib/lovinstem.h
===================================================================
--- /main/tags/2.25/gsdl/packages/mg/lib/lovinstem.h	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/mg/lib/lovinstem.h	(revision 21064)
@@ -0,0 +1,53 @@
+/**************************************************************************
+ *
+ * lovinstem.h -- Lovins' stemmer header
+ * Copyright (C) 1994  Linh Huynh, 
+ *                     (glued into library by tes@kbs.citri.edu.au)
+ *
+ * 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.
+ *
+ * $Id$
+ *
+ **************************************************************************/
+
+/*
+   $Log$
+   Revision 1.1  1999/08/10 21:16:54  sjboddie
+   renamed mg-1.3d directory mg
+
+   Revision 1.1  1998/11/25 07:55:36  rjmcnab
+
+   Modified mg to that you can specify the stemmer you want
+   to use via a command line option. You specify it to
+   mg_passes during the build process. The number of the
+   stemmer that you used is stored within the inverted
+   dictionary header and the stemmed dictionary header so
+   the correct stemmer is used in later stages of building
+   and querying.
+
+   Revision 1.1  1998/11/17 09:32:47  rjmcnab
+   *** empty log message ***
+
+   * Revision 1.2  1994/09/20  04:20:10  tes
+   * Changes made for 1.1
+   *
+   *
+ */
+#ifndef LOVINSTEM_H
+#define LOVINSTEM_H
+
+void lovinstem (unsigned char *word);
+
+#endif
Index: /main/tags/2.25/gsdl/packages/mg/lib/memlib.c
===================================================================
--- /main/tags/2.25/gsdl/packages/mg/lib/memlib.c	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/mg/lib/memlib.c	(revision 21064)
@@ -0,0 +1,59 @@
+/**************************************************************************
+ *
+ * memlib.c -- Malloc wrappers
+ * Copyright (C) 1994  Neil Sharman
+ *
+ * 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.
+ *
+ * $Id$
+ *
+ **************************************************************************/
+
+/*
+   $Log$
+   Revision 1.1  1999/08/10 21:16:54  sjboddie
+   renamed mg-1.3d directory mg
+
+   Revision 1.1  1998/11/17 09:32:10  rjmcnab
+   *** empty log message ***
+
+   * Revision 1.1  1994/08/22  00:24:47  tes
+   * Initial placement under CVS.
+   *
+ */
+
+static char *RCSID = "$Id$";
+
+
+#include "sysfuncs.h"
+#include "memlib.h"
+
+/* Defined as strdup is not an ANSI function */
+char *
+my_strdup(const char *str)
+{
+  char *ret_str = malloc(strlen(str)+1);
+  if (ret_str) return strcpy(ret_str, str);
+  else return (char*) 0;
+}
+
+
+Malloc_func Xmalloc = malloc;
+
+Realloc_func Xrealloc = realloc;
+
+Free_func Xfree = free;
+
+Strdup_func Xstrdup = my_strdup;
Index: /main/tags/2.25/gsdl/packages/mg/lib/memlib.h
===================================================================
--- /main/tags/2.25/gsdl/packages/mg/lib/memlib.h	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/mg/lib/memlib.h	(revision 21064)
@@ -0,0 +1,51 @@
+/**************************************************************************
+ *
+ * memlib.h -- Malloc wrappers
+ * Copyright (C) 1994  Neil Sharman
+ *
+ * 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.
+ *
+ * $Id$
+ *
+ **************************************************************************/
+
+
+#ifndef H_MEMLIB
+#define H_MEMLIB
+
+#ifdef STD_MEM
+
+#define Xmalloc malloc
+#define Xrealloc realloc
+#define Xfree free
+#define Xstrdup strdup
+
+#else
+
+
+#include "sysfuncs.h"
+
+typedef void *(*Malloc_func) (size_t);
+typedef void *(*Realloc_func) (void *, size_t);
+typedef void (*Free_func) (void *);
+typedef char *(*Strdup_func) (const char *);
+
+extern Malloc_func Xmalloc;
+extern Realloc_func Xrealloc;
+extern Free_func Xfree;
+extern Strdup_func Xstrdup;
+#endif
+
+#endif
Index: /main/tags/2.25/gsdl/packages/mg/lib/messages.c
===================================================================
--- /main/tags/2.25/gsdl/packages/mg/lib/messages.c	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/mg/lib/messages.c	(revision 21064)
@@ -0,0 +1,96 @@
+/**************************************************************************
+ *
+ * messages.c -- Message and error functions
+ * Copyright (C) 1994  Neil Sharman
+ *
+ * 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.
+ *
+ * $Id$
+ *
+ **************************************************************************/
+
+/*
+   $Log$
+   Revision 1.1  1999/08/10 21:16:55  sjboddie
+   renamed mg-1.3d directory mg
+
+   Revision 1.2  1998/11/23 03:38:06  rjmcnab
+
+   combined unix and windows versions of mg
+
+   Revision 1.1  1998/11/19 03:00:32  sjboddie
+   Added windows gdbm and mg versions
+
+   * Revision 1.1  1994/08/22  00:24:48  tes
+   * Initial placement under CVS.
+   *
+ */
+
+static char *RCSID = "$Id$";
+
+#include "sysfuncs.h"
+
+#include <stdarg.h>
+#include "messages.h"
+
+char *msg_prefix = "";
+
+
+void VOLATILE 
+FatalError (int ExitCode, const char *fmt,...)
+{
+  char buf[1024];
+  char *s, *pfx;
+  va_list args;
+  va_start (args, fmt);
+  vsprintf (buf, fmt, args);
+  s = strrchr (buf, '\n');
+  if (!s || *(s + 1) != '\0')
+    strcat (buf, "\n");
+  pfx = strrchr (msg_prefix, '/');
+  pfx = pfx ? pfx + 1 : msg_prefix;
+  fprintf (stderr, "%s%s%s", pfx, *pfx ? " : " : "", buf);
+  exit (ExitCode);
+}
+
+
+
+/*
+ * This function writes messages to stderr. Due to the fact that I can't 
+ * guarantee that the fprintf call is monatomic I have to implement a 
+ * semaphore system.
+ */
+void 
+Message (const char *fmt,...)
+{
+  char buf[1024];
+  char *s, *pfx;
+  va_list args;
+
+#ifdef QUIET
+  return; /* stop those messages!!!! */
+#endif  
+
+  va_start (args, fmt);
+  vsprintf (buf, fmt, args);
+  s = strrchr (buf, '\n');
+  if (!s || *(s + 1) != '\0')
+    strcat (buf, "\n");
+
+  pfx = strrchr (msg_prefix, '/');
+  pfx = pfx ? pfx + 1 : msg_prefix;
+  fprintf (stderr, "%s%s%s", pfx, *pfx ? " : " : "", buf);
+
+}
Index: /main/tags/2.25/gsdl/packages/mg/lib/messages.h
===================================================================
--- /main/tags/2.25/gsdl/packages/mg/lib/messages.h	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/mg/lib/messages.h	(revision 21064)
@@ -0,0 +1,39 @@
+/**************************************************************************
+ *
+ * messages.h -- Message and error functions
+ * Copyright (C) 1994  Neil Sharman
+ *
+ * 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.
+ *
+ * $Id$
+ *
+ **************************************************************************/
+
+#ifndef H_MESSAGES
+#define H_MESSAGES
+
+#ifdef __GNUC__
+#define VOLATILE volatile
+#else
+#define VOLATILE
+#endif
+
+extern char *msg_prefix;
+
+void VOLATILE FatalError (int ExitCode, const char *fmt,...);
+
+void Message (const char *fmt,...);
+
+#endif
Index: /main/tags/2.25/gsdl/packages/mg/lib/mgheap.c
===================================================================
--- /main/tags/2.25/gsdl/packages/mg/lib/mgheap.c	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/mg/lib/mgheap.c	(revision 21064)
@@ -0,0 +1,170 @@
+/**************************************************************************
+ *
+ * mgheap.c -- Heap routines
+ * Copyright (C) 1994  Neil Sharman
+ *
+ * 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.
+ *
+ * $Id$
+ *
+ **************************************************************************/
+
+/*
+   $Log$
+   Revision 1.1  1999/08/10 21:16:55  sjboddie
+   renamed mg-1.3d directory mg
+
+   Revision 1.1  1999/01/15 03:05:50  rjmcnab
+
+   Renamed lib/heap to be lib/mgheap (it was causing some problems with
+   some versions of the STL libraries which contained a heap.h)
+
+   Revision 1.1  1998/11/17 09:32:01  rjmcnab
+   *** empty log message ***
+
+   * Revision 1.1  1994/08/22  00:24:43  tes
+   * Initial placement under CVS.
+   *
+ */
+
+static char *RCSID = "$Id$";
+
+#include "mgheap.h"
+
+#define SWAP(s, a, b) 						\
+do {								\
+     register int __i;						\
+     register char *__a = (a), *__b = (b);			\
+     for (__i = (s); __i; __i--)				\
+       {							\
+         register char __t = *__a;				\
+	 *__a++ = *__b; *__b++ = __t;				\
+       }							\
+} while(0)
+
+
+
+#define COPY(s, dst, src) 					\
+do {								\
+     register int __i;						\
+     register char *__dst = (dst), *__src = (src);		\
+     for (__i = (s); __i; __i--)				\
+       *__dst++ = *__src++;					\
+} while(0)
+
+
+
+static void 
+heap_heapify (void *heap, int size, int num, int curr, heap_comp hc)
+{
+  register int child = curr * 2;
+  while (child <= num)
+    {
+      if (child < num && hc ((char *) heap + child * size,
+			     (char *) heap + child * size - size) < 0)
+	child++;
+      if (hc ((char *) heap + (curr - 1) * size, (char *) heap + (child - 1) * size) > 0)
+	{
+	  SWAP (size, (char *) heap + (curr - 1) * size,
+		(char *) heap + (child - 1) * size);
+	  curr = child;
+	  child = child * 2;
+	}
+      else
+	break;
+    }
+}
+
+static void 
+heap_pullup (void *heap, int size, int num, heap_comp hc)
+{
+  register int curr = num;
+  register int parent = curr >> 1;
+  while (parent &&
+	 hc ((char *) heap + (curr - 1) * size, (char *) heap + (parent - 1) * size) < 0)
+    {
+      SWAP (size, (char *) heap + (curr - 1) * size,
+	    (char *) heap + (parent - 1) * size);
+      curr = parent;
+      parent = curr >> 1;
+    }
+}
+
+/************************************************************************
+ *
+ * NOTE: If you choose to change the comparison function the first thing 
+ *       you do after changing the function is call heap_build.
+ *
+ */
+void 
+heap_build (void *heap, int size, int num, heap_comp hc)
+{
+  register int i;
+  for (i = num / 2; i > 0; i--)
+    heap_heapify (heap, size, num, i, hc);
+}
+
+
+
+/****************************************************
+ *
+ * NOTE : The heap must be built before heap_sort is called. 
+ *        This has the effect of reversing the order of the array.
+ *		e.g. if your comparison function is designed to pull the
+ *                   biggest thing off the heap first then the result of
+ *		     sorting with this function will be to put the bigest
+ *                   thing at the end of the array.
+ *
+ */
+void 
+heap_sort (void *heap, int size, int num, heap_comp hc)
+{
+  register int i;
+  for (i = num; i > 1; i--)
+    {
+      SWAP (size, heap, (char *) heap + (i - 1) * size);
+      heap_heapify (heap, size, i - 1, 1, hc);
+    }
+}
+
+
+void 
+heap_deletehead (void *heap, int size, int *num, heap_comp hc)
+{
+  (*num)--;
+  SWAP (size, heap, (char *) heap + *num * size);
+  heap_heapify (heap, size, *num, 1, hc);
+}
+
+
+void 
+heap_changedhead (void *heap, int size, int num, heap_comp hc)
+{
+  heap_heapify (heap, size, num, 1, hc);
+}
+
+
+/***********************************************************************
+ *
+ * This assumes that the item has been added to the end of the
+ * array that is the heap. But that num has not been changed. 
+ *
+ */
+void 
+heap_additem (void *heap, int size, int *num, heap_comp hc)
+{
+  (*num)++;
+  heap_pullup (heap, size, *num, hc);
+}
Index: /main/tags/2.25/gsdl/packages/mg/lib/mgheap.h
===================================================================
--- /main/tags/2.25/gsdl/packages/mg/lib/mgheap.h	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/mg/lib/mgheap.h	(revision 21064)
@@ -0,0 +1,84 @@
+/**************************************************************************
+ *
+ * mgheap.h -- Heap routines
+ * Copyright (C) 1994  Neil Sharman
+ *
+ * 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.
+ *
+ * $Id$
+ *
+ **************************************************************************/
+
+/* Care should be taken when using these routines as NO error checking is
+ * done.
+ */
+
+
+
+/* The heap comparison routine should return 
+ * <0 : If a should be before b
+ *  0 : If a and b are equal
+ * >0 : If a should be after b
+ */
+typedef int (*heap_comp) (void *a, void *b);
+
+
+/************************************************************************
+ *
+ * NOTE: If you choose to change the comparison function the first thing 
+ *       you do after changing the function is call heap_build.
+ *
+ */
+void heap_build (void *heap, int size, int num, heap_comp hc);
+
+
+
+/************************************************************************
+ *
+ * NOTE : The heap must be built before heap_sort is called.
+ *        This has the effect of reversing the order of the array.
+ *		e.g. if your comparison function is designed to pull the
+ *                   biggest thing off the heap first then the result of
+ *		     sorting with this function will be to put the bigest
+ *                   thing at the end of the array.
+ *
+ */
+void heap_sort (void *heap, int size, int num, heap_comp hc);
+
+/***********************************************************************
+ *
+ * NOTE: After deleting the head the heap will be one item shorter.
+ *       The deleted item will be placed at the end of the heap.
+ *
+ */
+void heap_deletehead (void *heap, int size, int *num, heap_comp hc);
+
+
+/***********************************************************************
+ *
+ * If you change the "value" of the root node of the heap then you
+ * should call this to re-pritorize the heap.
+ *
+ */
+void heap_changedhead (void *heap, int size, int num, heap_comp hc);
+
+
+/***********************************************************************
+ *
+ * This assumes that the item has been added to the end of the
+ * array that is the heap. But that num has not been changed. 
+ *
+ */
+void heap_additem (void *heap, int size, int *num, heap_comp hc);
Index: /main/tags/2.25/gsdl/packages/mg/lib/netorder.h
===================================================================
--- /main/tags/2.25/gsdl/packages/mg/lib/netorder.h	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/mg/lib/netorder.h	(revision 21064)
@@ -0,0 +1,189 @@
+#ifndef NETORDER_H
+#define NETORDER_H
+
+#include "sysfuncs.h"
+
+/* [RPAP - Feb 97: WIN32 Port] */
+#ifdef __WIN32__
+#include "win32in.h"
+#else
+# include <netinet/in.h>
+#endif
+
+#if defined (BIG_ENDIAN) || defined (_BIG_ENDIAN) || defined (__BIG_ENDIAN)
+# ifndef _BIG_ENDIAN
+#  define _BIG_ENDIAN
+# endif
+#endif
+
+#if defined (LITTLE_ENDIAN) || defined (_LITTLE_ENDIAN) || defined(__LITTLE_ENDIAN)
+# ifndef _LITTLE_ENDIAN
+#  define _LITTLE_ENDIAN
+# endif
+#endif
+
+#ifdef _LITTLE_ENDIAN
+
+/* double */
+#define HTOND(d)                                                                                  \
+        do {                                                                                      \
+             unsigned long tmph, tmpl;                                                            \
+	     bcopy ((char *) &d, (char *) &tmph, sizeof(double) >> 1);                            \
+	     bcopy ((char *) &d + (sizeof(double) >> 1), (char *) &tmpl, sizeof (double) >> 1);   \
+	     tmph = htonl (tmph);                                                                 \
+	     tmpl = htonl (tmpl);                                                                 \
+	     bcopy ((char *) &tmpl, (char *) &d, sizeof (double) >> 1);                           \
+	     bcopy ((char *) &tmph, (char *) &d + (sizeof(double) >> 1), sizeof (double) >> 1);   \
+	}while(0)
+#define NTOHD(d)                                                                                  \
+        do {                                                                                      \
+             unsigned long tmph, tmpl;                                                            \
+	     bcopy ((char *) &d, (char *) &tmph, sizeof(double) >> 1);                            \
+	     bcopy ((char *) &d + (sizeof(double) >> 1), (char *) &tmpl, sizeof (double) >> 1);   \
+	     tmph = ntohl (tmph);                                                                 \
+	     tmpl = ntohl (tmpl);                                                                 \
+	     bcopy ((char *) &tmpl, (char *) &d, sizeof (double) >> 1);                           \
+	     bcopy ((char *) &tmph, (char *) &d + (sizeof(double) >> 1), sizeof (double) >> 1);   \
+        }while(0)
+#define HTOND2(hd, nd)                                                                            \
+        do {                                                                                      \
+             unsigned long tmph, tmpl;                                                            \
+	     bcopy ((char *) &hd, (char *) &tmph, sizeof(double) >> 1);                           \
+	     bcopy ((char *) &hd + (sizeof(double) >> 1), (char *) &tmpl, sizeof (double) >> 1);  \
+	     tmph = htonl (tmph);                                                                 \
+	     tmpl = htonl (tmpl);                                                                 \
+	     bcopy ((char *) &tmpl, (char *) &nd, sizeof (double) >> 1);                          \
+	     bcopy ((char *) &tmph, (char *) &nd + (sizeof(double) >> 1), sizeof (double) >> 1);  \
+	}while(0)
+#define NTOHD2(nd, hd)                                                                            \
+        do {                                                                                      \
+             unsigned long tmph, tmpl;                                                            \
+	     bcopy ((char *) &nd, (char *) &tmph, sizeof(double) >> 1);                           \
+	     bcopy ((char *) &nd + (sizeof(double) >> 1), (char *) &tmpl, sizeof (double) >> 1);  \
+	     tmph = ntohl (tmph);                                                                 \
+	     tmpl = ntohl (tmpl);                                                                 \
+	     bcopy ((char *) &tmpl, (char *) &hd, sizeof (double) >> 1);                          \
+	     bcopy ((char *) &tmph, (char *) &hd + (sizeof(double) >> 1), sizeof (double) >> 1);  \
+        }while(0)
+
+/* float */
+#define HTONF(f)                                                                   \
+        do {                                                                       \
+             unsigned long tmp;                                                    \
+             bcopy ((char *) &(f), (char *) &tmp, sizeof (float));                 \
+             HTONUL (tmp);                                                         \
+	     bcopy ((char *) &tmp, (char *) &(f), sizeof (float));                 \
+	}while(0)
+#define NTOHF(f)                                                                   \
+        do {                                                                       \
+             unsigned long tmp;                                                    \
+             bcopy ((char *) &(f), (char *) &tmp, sizeof (float));                 \
+	     NTOHUL (tmp);                                                         \
+	     bcopy ((char *) &tmp, (char *) &(f), sizeof (float));                 \
+	}while(0)
+#define HTONF2(hf, nf)                                                             \
+        do {                                                                       \
+             unsigned long tmp;                                                    \
+             bcopy ((char *) &(hf), (char *) &tmp, sizeof (float));                \
+             HTONUL (tmp);                                                         \
+	     bcopy ((char *) &tmp, (char *) &(nf), sizeof (float));                \
+	}while(0)
+#define NTOHF2(nf, hf)                                                             \
+        do {                                                                       \
+             unsigned long tmp;                                                    \
+             bcopy ((char *) &(nf), (char *) &tmp, sizeof (float));                \
+	     NTOHUL (tmp);                                                         \
+	     bcopy ((char *) &tmp, (char *) &(hf), sizeof (float));                \
+	}while(0)
+
+/* pointers */
+#define HTONP(p)          ((p) = (void *) htonl ((unsigned long) p))
+#define NTOHP(p)          ((p) = (void *) ntohl ((unsigned long) p))
+#define HTONP2(hp, np)    ((np) = (void *) htonl ((unsigned long) hp))
+#define NTOHP2(np, hp)    ((hp) = (void *) ntohl ((unsigned long) np))
+
+/* unsigned long */
+#define HTONUL(l)         ((l) = htonl((l)))
+#define NTOHUL(l)         ((l) = ntohl((l)))
+#define HTONUL2(hl, nl)   ((nl) = htonl ((hl)))
+#define NTOHUL2(nl, hl)   ((hl) = ntohl ((nl)))
+
+/* signed long */
+#define HTONSL(l)         ((l) = (long) htonl ((unsigned long) (l)))
+#define NTOHSL(l)         ((l) = (long) ntohl ((unsigned long) (l)))
+#define HTONSL2(hl, nl)   ((nl) = (long) htonl ((unsigned long) (hl)))
+#define NTOHSL2(nl, hl)   ((hl) = (long) ntohl ((unsigned long) (nl)))
+
+/* unsigned int */
+#define HTONUI(i)         ((i) = (unsigned int) htonl ((unsigned long) (i)))
+#define NTOHUI(i)         ((i) = (unsigned int) ntohl ((unsigned long) (i)))
+#define HTONUI2(hi, ni)   ((ni) = (unsigned int) htonl ((unsigned long) (hi)))
+#define NTOHUI2(ni, hi)   ((hi) = (unsigned int) ntohl ((unsigned long) (ni)))
+
+/* signed int */
+#define HTONSI(i)         ((i) = (int) htonl ((unsigned long) (i)))
+#define NTOHSI(i)         ((i) = (int) ntohl ((unsigned long) (i)))
+#define HTONSI2(hi, ni)   ((ni) = (int) htonl ((unsigned long) (hi)))
+#define NTOHSI2(ni, hi)   ((hi) = (int) ntohl ((unsigned long) (ni)))
+
+/* unsigned short */
+#define HTONUS(s)         ((s) = htons((s)))
+#define NTOHUS(s)         ((s) = ntohs((s)))
+#define HTONUS2(hs, ns)   ((ns) = htons((hs)))
+#define NTOHUS2(ns, hs)   ((hs) = ntohs((ns)))
+
+#else   /* _BIG_ENDIAN */
+
+/* double */
+#define HTOND(d)          (d)
+#define NTOHD(d)          (d)
+#define HTOND2(hd, nd)    ((hd) = (nd))
+#define NTOHD2(nd, hd)    ((nd) = (hd))
+
+/* float */
+#define HTONF(f)          (f)
+#define NTOHF(f)          (f)
+#define HTONF2(hf, nf)    ((nf) = (hf))
+#define NTOHF2(nf, hf)    ((hf) = (nf))
+
+/* pointers */
+#define HTONP(p)          (p)
+#define NTOHP(p)          (p)
+#define HTONP2(hp, np)    ((np) = (hp))
+#define NTOHP2(np, hp)    ((hp) = (np))
+
+/* unsigned long */
+#define HTONUL(l)         (l)
+#define NTOHUL(l)         (l)
+#define HTONUL2(hl, nl)   ((nl) = (hl))
+#define NTOHUL2(nl, hl)   ((hl) = (nl))
+
+/* signed long */
+#define HTONSL(l)         (l)
+#define NTOHSL(l)         (l)
+#define HTONSL2(hl, nl)   ((nl) = (hl))
+#define NTOHSL2(nl, hl)   ((hl) = (nl))
+
+/* unsigned int */
+#define HTONUI(i)         (i)
+#define NTOHUI(i)         (i)
+#define HTONUI2(hi, ni)   ((ni) = (hi))
+#define NTOHUI2(ni, hi)   ((hi) = (ni))
+
+/* signed int */
+#define HTONSI(i)         (i)
+#define NTOHSI(i)         (i)
+#define HTONSI2(hi, ni)   ((ni) = (hi))
+#define NTOHSI2(ni, hi)   ((hi) = (ni))
+
+/* unsigned short */
+#define HTONUS(s)         (s)
+#define NTOHUS(s)         (s)
+#define HTONUS2(hs, ns)   ((ns) = (hs))
+#define NTOHUS2(ns, hs)   ((hs) = (ns))
+
+
+
+#endif
+
+#endif /* netorder.h */
Index: /main/tags/2.25/gsdl/packages/mg/lib/pathmax.h
===================================================================
--- /main/tags/2.25/gsdl/packages/mg/lib/pathmax.h	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/mg/lib/pathmax.h	(revision 21064)
@@ -0,0 +1,53 @@
+/* Define PATH_MAX somehow.  Requires sys/types.h.
+   Copyright (C) 1992 Free Software Foundation, Inc.
+
+   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, 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.  */
+
+#ifndef _PATHMAX_H
+#define _PATHMAX_H
+
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+
+/* Non-POSIX BSD systems might have gcc's limits.h, which doesn't define
+   PATH_MAX but might cause redefinition warnings when sys/param.h is
+   later included (as on MORE/BSD 4.3).  */
+#if defined(_POSIX_VERSION) || (defined(HAVE_LIMITS_H) && !defined(__GNUC__))
+#include <limits.h>
+#endif
+
+#ifndef _POSIX_PATH_MAX
+#define _POSIX_PATH_MAX 255
+#endif
+
+#if !defined(PATH_MAX) && defined(_PC_PATH_MAX)
+#define PATH_MAX (pathconf ("/", _PC_PATH_MAX) < 1 ? 1024 : pathconf ("/", _PC_PATH_MAX))
+#endif
+
+/* Don't include sys/param.h if it already has been.  */
+#if defined(HAVE_SYS_PARAM_H) && !defined(PATH_MAX) && !defined(MAXPATHLEN)
+#include <sys/param.h>
+#endif
+
+#if !defined(PATH_MAX) && defined(MAXPATHLEN)
+#define PATH_MAX MAXPATHLEN
+#endif
+
+#ifndef PATH_MAX
+#define PATH_MAX _POSIX_PATH_MAX
+#endif
+
+#endif /* _PATHMAX_H */
Index: /main/tags/2.25/gsdl/packages/mg/lib/perf_hash.c
===================================================================
--- /main/tags/2.25/gsdl/packages/mg/lib/perf_hash.c	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/mg/lib/perf_hash.c	(revision 21064)
@@ -0,0 +1,1094 @@
+/**************************************************************************
+ *
+ * perf_hash.c -- Perfect hashing functions
+ * Copyright (C) 1992  Bohdan S. Majewski
+ *
+ * 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.
+ *
+ * $Id$
+ *
+ **************************************************************************
+ *
+ * 1994 Neil Sharman
+ *      Small modifications were made to the interface so that it fitted in
+ *      with mg.
+ *
+ **************************************************************************/
+
+/*
+   $Log$
+   Revision 1.1  1999/08/10 21:16:57  sjboddie
+   renamed mg-1.3d directory mg
+
+   Revision 1.1  1998/11/17 09:32:17  rjmcnab
+   *** empty log message ***
+
+   * Revision 1.2  1994/08/22  00:26:30  tes
+   * Made perf_hash take the ceiling of 1.23 * num
+   * in lieu of the floor.
+   * This was done so that perf_hash works ok on
+   * a small number of keys.
+   *
+   * Revision 1.1  1994/08/22  00:24:49  tes
+   * Initial placement under CVS.
+   *
+ */
+
+static char *RCSID = "$Id$";
+
+
+#define STRUCT
+
+#include "sysfuncs.h"
+
+#include "local_strings.h"
+#include "memlib.h"
+#include "messages.h"
+#include "perf_hash.h"
+#include "netorder.h"  /* [RPAP - Jan 97: Endian Ordering] */
+
+#define FALSE 0
+#define TRUE  1
+
+#define STATIC 0
+
+/* Random Number stuff */
+static long seed[] = {0, 0};
+#define RANDOM() irandm(seed)
+#define SEED_RANDOM(the_seed) do{ seed[0] = the_seed; }while(0)
+
+/* Max number of keys - must be a power of 2 minus 1 */
+static int MAX_M;
+
+
+static int MAX_CH;
+
+
+/* the width of the mapping tables  */
+static int MAX_L;
+
+
+
+#define c     1.23
+static int MAX_N;
+
+
+
+
+static u_char *translate;
+
+#define MEMBER 0
+#define ERASED 1
+
+
+
+/* direction constants for the edge oriented 3-graph representation */
+#define A              0
+#define B        (MAX_M)
+#define C          (2*B)
+
+/* NODEa, NODEb, NODEc, FIRST and NEXT are used to represent a 3-graph */
+static int *NODEa, *NODEb, *NODEc;
+static int *FIRST;
+static int *NEXT;
+
+
+#define norm(e) ((e) % MAX_M)
+/* in general should be ((e) % MAX_M) but MAX_M = 2^k - 1 */
+
+
+static char *mk;		/* for marking edges/vertices as removed */
+static int *g;			/* array g defines a minimal perfect hash function */
+
+
+
+/* stack of edges, created during the independency */
+/* test, used in the assignment step               */
+static struct
+  {
+    int sp;
+    int *st;
+  }
+S;
+#define push(s, e) s.st[s.sp++] = (e)
+#define pop(s, e)  e = s.st[--s.sp]
+
+#ifndef STRUCT
+static long **tb0, **tb1, **tb2;
+#else
+struct tb_entry **tb;
+#endif
+
+
+static int 
+unique (int v)
+{				/* checks if vertex v belongs to only one edge */
+  return (FIRST[v] != 0 && NEXT[FIRST[v]] == 0) ? FIRST[v] : 0;
+}				/*unique */
+
+
+
+
+
+
+
+
+static void 
+delete (int v, int e)
+{				/* deletes edge e from list of v */
+
+  int b;
+
+  b = FIRST[v];
+  assert (norm (b) != 0);
+  if (norm (b) == e)
+    FIRST[v] = NEXT[FIRST[v]];
+  else
+    {
+      while (norm (NEXT[b]) != e)
+	{
+	  b = NEXT[b];
+	  assert (norm (b) != 0);
+	}
+      NEXT[b] = NEXT[NEXT[b]];
+    }
+}				/*delete */
+
+
+
+
+
+
+#if 0
+/* recursively removes the edges of a 3-graph which have at least */
+/* one unique vertex. The removed edges are placed on stack S     */
+static void 
+ph_remove (int e, int v)
+{
+  int b;
+  mk[e] = ERASED;
+  push (S, e);
+
+  if (NODEa[e] != v)
+    delete (NODEa[e], e);
+  if (NODEb[e] != v)
+    delete (NODEb[e], e);
+  if (NODEc[e] != v)
+    delete (NODEc[e], e);
+
+  if (NODEa[e] != v && mk[b = norm (unique (NODEa[e]))] == MEMBER)
+    ph_remove (b, NODEa[e]);
+  if (NODEb[e] != v && mk[b = norm (unique (NODEb[e]))] == MEMBER)
+    ph_remove (b, NODEb[e]);
+  if (NODEc[e] != v && mk[b = norm (unique (NODEc[e]))] == MEMBER)
+    ph_remove (b, NODEc[e]);
+}
+#else
+
+
+static int StackPos, StackMax;
+static struct Stack
+  {
+    int e, v, m;
+  }
+ *Stack = NULL;
+
+#define StackAdd(_e, _v, _m)						\
+  do {									\
+    if (StackPos == StackMax)						\
+      {									\
+        StackMax <<= 1;							\
+	if (!(Stack = Xrealloc(Stack, sizeof(*Stack) * StackMax)))	\
+	  return(-1);							\
+      }									\
+    Stack[StackPos].e = (_e);						\
+    Stack[StackPos].v = (_v);						\
+    Stack[StackPos++].m = (_m);						\
+  } while(0)
+
+
+static int 
+ph_remove (int e, int v)
+{
+  if (!Stack)
+    {
+      StackMax = 256;
+      if (!(Stack = Xmalloc (sizeof (*Stack) * StackMax)))
+	return (-1);
+      StackPos = 0;
+    }
+  Stack[StackPos].e = e;
+  Stack[StackPos].v = v;
+  Stack[StackPos].m = 0;
+  StackPos++;
+  while (StackPos)
+    {
+      int m, b;
+      StackPos--;
+      e = Stack[StackPos].e;
+      v = Stack[StackPos].v;
+      m = Stack[StackPos].m;
+
+
+      switch (m)
+	{
+	case 0:
+	  {
+	    mk[e] = ERASED;
+	    push (S, e);
+
+	    if (NODEa[e] != v)
+	      delete (NODEa[e], e);
+	    if (NODEb[e] != v)
+	      delete (NODEb[e], e);
+	    if (NODEc[e] != v)
+	      delete (NODEc[e], e);
+
+	    if (NODEa[e] != v && mk[b = norm (unique (NODEa[e]))] == MEMBER)
+	      {
+		Stack[StackPos++].m = 1;
+		StackAdd (b, NODEa[e], 0);
+		break;
+	      }
+	  }
+	case 1:
+	  {
+	    if (NODEb[e] != v && mk[b = norm (unique (NODEb[e]))] == MEMBER)
+	      {
+		Stack[StackPos++].m = 2;
+		StackAdd (b, NODEb[e], 0);
+		break;
+	      }
+	  }
+	case 2:
+	  if (NODEc[e] != v && mk[b = norm (unique (NODEc[e]))] == MEMBER)
+	    StackAdd (b, NODEc[e], 0);
+	}
+    }
+  return (0);
+}
+#endif
+
+
+
+
+
+/* returns TRUE if and only if set of edges created in the tree_builder */
+/* procedure form a 3-graph with independent edges. Edges of a 3-graph  */
+/* are independent iff repeated deletion of edges containing vertices   */
+/* of degree 1 results in a graph with no edges in it.                  */
+static int 
+acyclic (int m, int n)
+{
+
+  int v, e;
+  /* build list of edges for each node */
+  for (v = 1; v <= n; FIRST[v++] = 0);
+  for (e = 1; e <= m; e++)
+    {
+      NEXT[A + e] = FIRST[NODEa[e]];
+      FIRST[NODEa[e]] = A + e;
+      NEXT[B + e] = FIRST[NODEb[e]];
+      FIRST[NODEb[e]] = B + e;
+      NEXT[C + e] = FIRST[NODEc[e]];
+      FIRST[NODEc[e]] = C + e;
+
+      /* mark edge e as belonging to the hypergraph */
+      mk[e] = MEMBER;
+    }
+
+
+  S.sp = 0;			/* empty the stack */
+  mk[0] = ERASED;		/* a sentinel for the test below */
+  for (v = 1; v <= n; v++)
+    {
+      if (mk[e = norm (unique (v))] == MEMBER)
+	ph_remove (e, v);
+    }
+
+  /* check if any edges were left in the graph */
+  return S.sp == m;
+}				/*acyclic */
+
+
+
+
+
+
+
+
+/* repeatedly maps words into edges of a 3-graph until the edges */
+/* are independent.                                              */
+static int 
+tree_builder (int num, u_char ** keys, int *n)
+{
+
+  int e, k = 0;
+  int i, j;
+  u_char *w;
+
+  do
+    {
+      *n = (int) (num * c + 1);
+      /* initialize tables of random integers */
+      for (i = 0; i < MAX_CH; i++)
+	for (j = 0; j < MAX_L; j++)
+	  {
+#ifndef STRUCT
+	    tb0[i][j] = RANDOM () % *n;
+	    tb1[i][j] = RANDOM () % *n;
+	    tb2[i][j] = RANDOM () % *n;
+#else
+	    struct tb_entry *tbp = &tb[i][j];
+	    tbp->tb0 = RANDOM () % *n;
+	    tbp->tb1 = RANDOM () % *n;
+	    tbp->tb2 = RANDOM () % *n;
+#endif
+	  }
+
+      /* compute an edge (NODEa[e], NODEb[e], NODEc[e]) for each word */
+      for (e = 1; e <= num; e++)
+	{
+	  /*generate an edge corresponding to the ith word */
+	  int x = 0, y = 0, z = 0, l;
+	  w = keys[e - 1];
+
+	  l = *w++;
+	  j = (l - 1) % MAX_L;
+
+	  do
+	    {
+#ifndef STRUCT
+	      x += tb0[translate[*w]][j];
+	      y += tb1[translate[*w]][j];
+	      z += tb2[translate[*w]][j];
+#else
+	      struct tb_entry *tbp = &tb[translate[*w]][j];
+	      x += tbp->tb0;
+	      y += tbp->tb1;
+	      z += tbp->tb2;
+#endif
+	      if (++j >= MAX_L)
+		j = 0;
+	      w++;
+	    }
+	  while (--l);
+	  x = (x % *n) + 1;
+	  y = (y % *n) + 1;
+	  z = (z % *n) + 1;
+	  if (y == x && ++y > *n)
+	    y = 1;
+	  if (z == x && ++z > *n)
+	    z = 1;
+	  if (z == y)
+	    {
+	      if (++z > *n)
+		z = 1;
+	      if (z == x && ++z > *n)
+		z = 1;
+	    }
+
+	  NODEa[e] = x;
+	  NODEb[e] = y;
+	  NODEc[e] = z;
+	}
+      if (++k > 50)		/* make sure we will not wait for ever */
+	FatalError (1, "Unable to generate the perfect hash function. "
+		    "This is probably because there aren't enough words");
+    }
+  while (!acyclic (num, *n));
+  return k;
+}				/*tree_builder */
+
+
+
+
+
+
+
+
+
+/* calculates values of the g function/array so that i-th word is */
+/* placed at the (i-1)st position of a hash table.                */
+static void 
+assign (int n)
+{
+
+  int v, w = 0, e;
+
+  /* mark all the vertices of the 3-graph as unassigned */
+  for (v = 1; v <= n; mk[v++] = FALSE);
+
+  while (S.sp > 0)
+    {
+      int xor = 0;
+      pop (S, e);
+      v = NODEa[e];
+      if (mk[v])
+	xor ^= g[v];
+      else
+	{
+	  g[w = v] = 0;
+	  mk[v] = TRUE;
+	}
+      v = NODEb[e];
+      if (mk[v])
+	xor ^= g[v];
+      else
+	{
+	  g[w = v] = 0;
+	  mk[v] = TRUE;
+	}
+      v = NODEc[e];
+      if (mk[v])
+	xor ^= g[v];
+      else
+	{
+	  g[w = v] = 0;
+	  mk[v] = TRUE;
+	}
+      g[w] = (e - 1) ^ xor;
+    }
+}				/*assign */
+
+
+
+
+
+
+
+
+
+/*check returns 0 if no error in mphf is detected, else returns error code */
+static int 
+check (int m)
+{
+
+  int e, err_code = 0;
+
+  /*for each word compute its place in hash table and check if correct */
+  for (e = 1; e <= m; e++)
+    {
+      if ((e - 1) != (g[NODEa[e]] ^ g[NODEb[e]] ^ g[NODEc[e]]))
+	{
+	  (void) fprintf (stderr, "Error for %dth word detected.\n", e);
+	  err_code = e;
+	}
+    }
+  return err_code;
+}				/*check */
+
+
+
+
+
+
+
+#if 0
+void 
+outputh (int m, int n)
+{
+
+  int i, j, w = (int) ceil (log10 ((double) n + 1.0)) + 1;
+
+#if 0
+  char *PRG =
+  "int h(char *s)\n"
+  "{\n"
+  "  int u, v, w, i;\n"
+  "i = (strlen(s) - 1) % _HXL;\n"
+  "  u = v = w = 0;\n"
+  "  while(*s)\n"
+  "    {\n"
+  "      u += mt1[(*s) - _HFC][i];\n"
+  "      v += mt2[(*s) - _HFC][i];\n"
+  "      w += mt3[(*s++) - _HFC][i];\n"
+  "      if(++i >= _HXL) i = 0;\n"
+  "    }\n"
+  "  u %= _HFN; v %= _HFN; w %= _HFN;\n"
+  "  if(u == v && ++v >= _HFN) v = 0;\n"
+  "  if(w == u && ++w >= _HFN) w = 0;\n"
+  "  if(w == v && ++w >= _HFN) w = 0;\n"
+  "  if(w == u && ++w >= _HFN) w = 0;\n"
+  "  return (g[u] ^ g[v] ^ g[w]) % _HFM;\n"
+  "};\n\n";
+#endif
+
+  char *PRG =
+  "int h(char *s)\n"
+  "{\n"
+  "  int u, v, w, i;\n"
+  "  i = (strlen(s) - 1) % _HXL;\n"
+  "  u = v = w = 0;\n"
+  "  while(*s)\n"
+  "    {\n"
+  "      if((u += mt1[(*s) - _HFC][i]) >= _HFN) u -= _HFN;\n"
+  "      if((v += mt2[(*s) - _HFC][i]) >= _HFN) v -= _HFN;\n"
+  "      if((w += mt3[(*s++) - _HFC][i]) >= _HFN) w -= _HFN;\n"
+  "      if(++i >= _HXL) i = 0;\n"
+  "    }\n"
+  "  if(u == v && ++v >= _HFN) v = 0;\n"
+  "  if(w == v) \n"
+  "    {\n"
+  "      if(++w >= _HFN) w = 0;\n"
+  "      if(w == u && ++w >= _HFN) w = 0;\n"
+  "    }\n"
+  "  else\n"
+  "    if(w == u)\n"
+  "      {\n"
+  "	     if(++w >= _HFN) w = 0;\n"
+  "	     if(w == v && ++w >= _HFN) w = 0;\n"
+  "      }\n"
+  "  return ((g[u] ^ g[v] ^ g[w]) > _HFM)? 0 : (g[u] ^ g[v] ^ g[w]);\n"
+  "}\n\n";
+
+  printf ("#define _HFN %d\n#define _HFC %d\n", n, fc);
+  printf ("#define _HFM %d\n#define _HXL %d\n", m, MAX_L);
+  printf ("#define _HFA %d\n\nstatic int g[_HFN] = {\n", lc - fc + 1);
+  for (i = 1; i < n; i++)
+    {
+      if (i % 8 == 0)
+	putchar ('\n');
+      printf ("%5d, ", g[i]);
+    }
+  printf ("%5d};\n\n", g[n]);
+
+  printf ("static int mt1[_HFA][_HXL] = {\n");
+  for (j = fc; j < lc; j++)
+    {
+      printf ("{");
+      for (i = 0; i < MAX_L - 1; i++)
+	printf ("%*d,", w, tb0[j][i]);
+      printf ("%*d},\n", w, tb0[j][MAX_L - 1]);
+    }
+  printf ("{");
+  for (i = 0; i < MAX_L - 1; i++)
+    printf ("%*d,", w, tb0[lc][i]);
+  printf ("%*d}\n", w, tb0[lc][MAX_L - 1]);
+  printf ("};\n\n");
+
+  printf ("static int mt2[_HFA][_HXL] = {\n");
+  for (j = fc; j < lc; j++)
+    {
+      printf ("{");
+      for (i = 0; i < MAX_L - 1; i++)
+	printf ("%*d,", w, tb1[j][i]);
+      printf ("%*d},\n", w, tb1[j][MAX_L - 1]);
+    }
+  printf ("{");
+  for (i = 0; i < MAX_L - 1; i++)
+    printf ("%*d,", w, tb1[lc][i]);
+  printf ("%*d}\n", w, tb1[lc][MAX_L - 1]);
+  printf ("};\n\n");
+
+  printf ("static int mt3[_HFA][_HXL] = {\n");
+  for (j = fc; j < lc; j++)
+    {
+      printf ("{");
+      for (i = 0; i < MAX_L - 1; i++)
+	printf ("%*d,", w, tb2[j][i]);
+      printf ("%*d},\n", w, tb2[j][MAX_L - 1]);
+    }
+  printf ("{");
+  for (i = 0; i < MAX_L - 1; i++)
+    printf ("%*d,", w, tb2[lc][i]);
+  printf ("%*d}\n", w, tb2[lc][MAX_L - 1]);
+  printf ("};\n\n");
+
+  printf ("%s", PRG);
+}				/*outputh */
+#endif
+
+
+
+
+
+
+
+static void 
+make_trans_func (int num, u_char ** keys)
+{
+  int i, j;
+
+  bzero ((char *) translate, sizeof (translate));
+
+  MAX_L = 1;
+  for (i = 0; i < num; i++)
+    {
+      unsigned len = keys[i][0];
+      u_char *s = keys[i] + 1;
+      for (; len; len--, s++)
+	translate[*s] = 1;
+      if (i)
+	{
+	  int l;
+	  l = prefixlen (keys[i - 1], keys[i]);
+	  if (l + 1 > MAX_L)
+	    MAX_L = l + 1;
+	}
+    }
+  j = 0;
+  for (i = 0; i < 256; i++)
+    if (translate[i])
+      translate[i] = j++;
+  MAX_CH = j;
+}
+
+
+static void 
+temp_free (void)
+{
+  if (NODEa)
+    Xfree (NODEa);
+  if (NODEb)
+    Xfree (NODEb);
+  if (NODEc)
+    Xfree (NODEc);
+  if (FIRST)
+    Xfree (FIRST);
+  if (NEXT)
+    Xfree (NEXT);
+  if (S.st)
+    Xfree (S.st);
+  if (mk)
+    Xfree (mk);
+}
+
+static void 
+all_free (void)
+{
+  int i;
+  temp_free ();
+  if (translate)
+    Xfree (translate);
+  if (g)
+    Xfree (g);
+#ifndef STRUCT
+  for (i = 0; i < MAX_CH; i++)
+    {
+      if (tb0 && tb0[i])
+	Xfree (tb0[i]);
+      if (tb1 && tb1[i])
+	Xfree (tb1[i]);
+      if (tb2 && tb2[i])
+	Xfree (tb2[i]);
+    }
+  if (tb0)
+    Xfree (tb0);
+  if (tb1)
+    Xfree (tb1);
+  if (tb2)
+    Xfree (tb2);
+#else
+  for (i = 0; i < MAX_CH; i++)
+    if (tb && tb[i])
+      Xfree (tb[i]);
+  if (tb)
+    Xfree (tb);
+#endif
+}
+
+static int 
+allocate_memory (void)
+{
+  int i, ok = 1;
+  NODEa = Xmalloc (sizeof (int) * (MAX_M + 1));
+  NODEb = Xmalloc (sizeof (int) * (MAX_M + 1));
+  NODEc = Xmalloc (sizeof (int) * (MAX_M + 1));
+  FIRST = Xmalloc (sizeof (int) * (MAX_N + 1));
+  NEXT = Xmalloc (sizeof (int) * (MAX_M + 1) * 3);
+  S.st = Xmalloc (sizeof (int) * MAX_M);
+  mk = Xmalloc (sizeof (char) * (MAX_N + 1));
+  g = Xmalloc (sizeof (int) * (MAX_N + 1));
+#ifndef STRUCT
+  tb0 = Xmalloc (sizeof (int *) * MAX_CH);
+  tb1 = Xmalloc (sizeof (int *) * MAX_CH);
+  tb2 = Xmalloc (sizeof (int *) * MAX_CH);
+  for (i = 0; i < MAX_CH; i++)
+    {
+      if (tb0)
+	if (!(tb0[i] = Xmalloc (sizeof (long) * MAX_L)))
+	    ok = 0;
+      if (tb1)
+	if (!(tb1[i] = Xmalloc (sizeof (long) * MAX_L)))
+	    ok = 0;
+      if (tb2)
+	if (!(tb2[i] = Xmalloc (sizeof (long) * MAX_L)))
+	    ok = 0;
+    }
+
+  if (!(NODEa && NODEb && NODEc && FIRST && NEXT && S.st && mk && g &&
+	tb0 && tb1 && tb2 && ok))
+    {
+      all_free ();
+      return (-1);
+    }
+#else
+  tb = Xmalloc (sizeof (struct tb_entry *) * MAX_CH);
+  for (i = 0; i < MAX_CH; i++)
+    if (tb)
+      if (!(tb[i] = Xmalloc (sizeof (struct tb_entry) * MAX_L)))
+	  ok = 0;
+
+  if (!(NODEa && NODEb && NODEc && FIRST && NEXT && S.st && mk && g &&
+	tb && ok))
+    {
+      all_free ();
+      return (-1);
+    }
+#endif
+  return (0);
+}
+
+
+perf_hash_data *
+gen_hash_func (int num, u_char ** keys, int r)
+{
+  int n;
+  perf_hash_data *phd;
+  translate = Xmalloc (sizeof (u_char) * 256);
+  bzero ((char *) translate, sizeof (u_char) * 256);  /* [RPAP - Feb 97: WIN32 Port] */
+  make_trans_func (num, keys);
+
+  if (r <= 0)
+    SEED_RANDOM ((long) time ((time_t *) NULL));
+  else
+    SEED_RANDOM (r);
+
+  MAX_M = num + 1;
+
+  MAX_N = MAX_M + MAX_M / 4;
+
+  if (allocate_memory () == -1)
+    return (NULL);
+
+  /* construct an "acyclic" hypergraph */
+  tree_builder (num, keys, &n);
+  /* compute function g */
+  assign (n);
+
+  if (check (num) != 0)
+    FatalError (1, "An error has been detected in the mphf.");
+  temp_free ();
+
+  if (!(phd = Xmalloc (sizeof (perf_hash_data))))
+    return (NULL);
+
+  bcopy ((char *) &g[1], (char *) g, n * sizeof (int));
+
+  phd->MAX_L = MAX_L;
+  phd->MAX_N = n;
+  phd->MAX_M = num;
+  phd->MAX_CH = MAX_CH;
+  phd->translate = translate;
+  phd->g = g;
+#ifndef STRUCT
+  phd->tb0 = tb0;
+  phd->tb1 = tb1;
+  phd->tb2 = tb2;
+#else
+  phd->tb = tb;
+#endif
+  return (phd);
+}
+
+int 
+write_perf_hash_data (FILE * f, perf_hash_data * phd)
+{
+  int tot, i;
+  /* [RPAP - Jan 97: Endian Ordering] */
+  HTONSI(phd->MAX_L);
+  HTONSI(phd->MAX_N);
+  HTONSI(phd->MAX_M);
+  HTONSI(phd->MAX_CH);
+
+  tot = fwrite ((char *) &phd->MAX_L, sizeof (int), 1, f) * sizeof (int);
+  tot += fwrite ((char *) &phd->MAX_N, sizeof (int), 1, f) * sizeof (int);
+  tot += fwrite ((char *) &phd->MAX_M, sizeof (int), 1, f) * sizeof (int);
+  tot += fwrite ((char *) &phd->MAX_CH, sizeof (int), 1, f) * sizeof (int);
+
+  /* [RPAP - Jan 97: Endian Ordering] */
+  NTOHSI(phd->MAX_L);
+  NTOHSI(phd->MAX_N);
+  NTOHSI(phd->MAX_M);
+  NTOHSI(phd->MAX_CH);
+
+  tot += fwrite ((char *) phd->translate, sizeof (u_char), 256, f);
+
+  /* [RPAP - Jan 97: Endian Ordering] */
+  for (i = 0; i < phd->MAX_N + 1; i++)
+    HTONSI(phd->g[i]);
+
+  tot += fwrite ((char *) phd->g, sizeof (int), phd->MAX_N + 1, f) * sizeof (int);
+
+  /* [RPAP - Jan 97: Endian Ordering] */
+  for (i = 0; i < phd->MAX_N + 1; i++)
+    NTOHSI(phd->g[i]);
+
+#ifndef STRUCT
+  for (i = 0; i < phd->MAX_CH; i++)
+    {
+      /* [RPAP - Jan 97: Endian Ordering] */
+      int j;
+      for (j = 0; j < phd->MAX_L; j++)
+	{
+	  HTONSI(phd->tb0[i][j]);
+	  HTONSI(phd->tb1[i][j]);
+	  HTONSI(phd->tb2[i][j]);
+	}
+
+      tot += fwrite ((char *) phd->tb0[i], sizeof (int), phd->MAX_L, f) *
+        sizeof (int);
+      tot += fwrite ((char *) phd->tb1[i], sizeof (int), phd->MAX_L, f) *
+        sizeof (int);
+      tot += fwrite ((char *) phd->tb2[i], sizeof (int), phd->MAX_L, f) *
+        sizeof (int);
+
+      /* [RPAP - Jan 97: Endian Ordering] */
+      for (j = 0; j < phd->MAX_L; j++)
+	{
+	  NTOHSI(phd->tb0[i][j]);
+	  NTOHSI(phd->tb1[i][j]);
+	  NTOHSI(phd->tb2[i][j]);
+	}
+    }
+#else
+  for (i = 0; i < phd->MAX_CH; i++)
+    {
+      /* [RPAP - Jan 97: Endian Ordering] */
+      int j;
+      for (j = 0; j < phd->MAX_L; j++)
+	{
+	  HTONSL(phd->tb[i][j].tb0);
+	  HTONSL(phd->tb[i][j].tb1);
+	  HTONSL(phd->tb[i][j].tb2);
+	}
+
+      tot += fwrite ((char *) phd->tb[i], sizeof (struct tb_entry), phd->MAX_L, f) *
+	sizeof (struct tb_entry);
+
+      /* [RPAP - Jan 97: Endian Ordering] */
+      for (j = 0; j < phd->MAX_L; j++)
+	{
+	  NTOHSL(phd->tb[i][j].tb0);
+	  NTOHSL(phd->tb[i][j].tb1);
+	  NTOHSL(phd->tb[i][j].tb2);
+	}
+    }
+#endif
+  return (tot);
+}
+
+
+perf_hash_data *
+read_perf_hash_data (FILE * f)
+{
+  perf_hash_data *phd;
+  int i, tot, ok = 1;
+  if (!(phd = Xmalloc (sizeof (perf_hash_data))))
+    return (NULL);
+  tot = fread ((char *) &phd->MAX_L, sizeof (int), 1, f) * sizeof (int);
+  tot += fread ((char *) &phd->MAX_N, sizeof (int), 1, f) * sizeof (int);
+  tot += fread ((char *) &phd->MAX_M, sizeof (int), 1, f) * sizeof (int);
+  tot += fread ((char *) &phd->MAX_CH, sizeof (int), 1, f) * sizeof (int);
+
+  /* [RPAP - Jan 97: Endian Ordering] */
+  NTOHSI(phd->MAX_L);
+  NTOHSI(phd->MAX_N);
+  NTOHSI(phd->MAX_M);
+  NTOHSI(phd->MAX_CH);
+
+  if (tot != 4 * sizeof (int))
+      return (NULL);
+  phd->translate = Xmalloc (sizeof (u_char) * 256);
+  phd->g = Xmalloc (sizeof (int) * (phd->MAX_N + 1));
+#ifndef STRUCT
+  phd->tb0 = Xmalloc (sizeof (int *) * phd->MAX_CH);
+  phd->tb1 = Xmalloc (sizeof (int *) * phd->MAX_CH);
+  phd->tb2 = Xmalloc (sizeof (int *) * phd->MAX_CH);
+  for (i = 0; i < phd->MAX_CH; i++)
+    {
+      if (phd->tb0)
+	if (!(phd->tb0[i] = Xmalloc (sizeof (long) * phd->MAX_L)))
+	    ok = 0;
+      if (phd->tb1)
+	if (!(phd->tb1[i] = Xmalloc (sizeof (long) * phd->MAX_L)))
+	    ok = 0;
+      if (phd->tb2)
+	if (!(phd->tb2[i] = Xmalloc (sizeof (long) * phd->MAX_L)))
+	    ok = 0;
+    }
+  if (!(phd->translate && phd->g && phd->tb0 && phd->tb1 && phd->tb2 && ok))
+    {
+      if (phd->translate)
+	Xfree (phd->translate);
+      if (phd->g)
+	Xfree (phd->g);
+      for (i = 0; i < MAX_CH; i++)
+	{
+	  if (phd->tb0 && phd->tb0[i])
+	    Xfree (phd->tb0[i]);
+	  if (phd->tb1 && phd->tb1[i])
+	    Xfree (phd->tb1[i]);
+	  if (phd->tb2 && phd->tb2[i])
+	    Xfree (phd->tb2[i]);
+	}
+      if (phd->tb0)
+	Xfree (phd->tb0);
+      if (phd->tb1)
+	Xfree (phd->tb1);
+      if (phd->tb2)
+	Xfree (phd->tb2);
+      Xfree (phd);
+      return (NULL);
+    }
+  tot += fread ((char *) phd->translate, sizeof (u_char), 256, f);
+  tot += fread ((char *) phd->g, sizeof (int), phd->MAX_N + 1, f) * sizeof (int);
+
+  /* [RPAP - Jan 97: Endian Ordering] */
+  for (i = 0; i < phd->MAX_N + 1; i++)
+    NTOHSI(phd->g[i]);
+
+  for (i = 0; i < phd->MAX_CH; i++)
+    {
+      int j;
+
+      tot += fread ((char *) phd->tb0[i], sizeof (long), phd->MAX_L, f) *
+        sizeof (int);
+      tot += fread ((char *) phd->tb1[i], sizeof (long), phd->MAX_L, f) *
+        sizeof (int);
+      tot += fread ((char *) phd->tb2[i], sizeof (long), phd->MAX_L, f) *
+        sizeof (int);
+
+      /* [RPAP - Jan 97: Endian Ordering] */
+      for (j = 0; j < phd->MAX_L; j++)
+	{
+	  NTOHSI(phd->tb0[i][j]);
+	  NTOHSI(phd->tb1[i][j]);
+	  NTOHSI(phd->tb2[i][j]);
+	}
+    }
+#else
+  phd->tb = Xmalloc (sizeof (struct tb_entry *) * phd->MAX_CH);
+  for (i = 0; i < phd->MAX_CH; i++)
+    if (phd->tb)
+      if (!(phd->tb[i] = Xmalloc (sizeof (struct tb_entry) * phd->MAX_L)))
+	  ok = 0;
+  if (!(phd->translate && phd->g && phd->tb && ok))
+    {
+      if (phd->translate)
+	Xfree (phd->translate);
+      if (phd->g)
+	Xfree (phd->g);
+      for (i = 0; i < MAX_CH; i++)
+	if (phd->tb && phd->tb[i])
+	  Xfree (phd->tb[i]);
+      if (phd->tb)
+	Xfree (phd->tb);
+      Xfree (phd);
+      return (NULL);
+    }
+  tot += fread ((char *) phd->translate, sizeof (u_char), 256, f);
+  tot += fread ((char *) phd->g, sizeof (int), phd->MAX_N + 1, f) * sizeof (int);
+
+  /* [RPAP - Jan 97: Endian Ordering] */
+  for (i = 0; i < phd->MAX_N + 1; i++)
+    NTOHSI(phd->g[i]);
+
+  for (i = 0; i < phd->MAX_CH; i++)
+    {
+      int j;
+
+      tot += fread ((char *) phd->tb[i], sizeof (struct tb_entry), phd->MAX_L, f) *
+	sizeof (struct tb_entry);
+
+      /* [RPAP - Jan 97: Endian Ordering] */
+      for (j = 0; j < phd->MAX_L; j++)
+	{
+	  NTOHSL(phd->tb[i][j].tb0);
+	  NTOHSL(phd->tb[i][j].tb1);
+	  NTOHSL(phd->tb[i][j].tb2);
+	}
+    }
+#endif
+  return (phd);
+}
+
+void 
+free_perf_hash (perf_hash_data * phd)
+{
+  int i;
+  if (phd->translate)
+    Xfree (phd->translate);
+  if (phd->g)
+    Xfree (phd->g);
+  for (i = 0; i < phd->MAX_CH; i++)
+    if (phd->tb && phd->tb[i])
+      Xfree (phd->tb[i]);
+  if (phd->tb)
+    Xfree (phd->tb);
+  Xfree (phd);
+}
+
+
+int 
+perf_hash (perf_hash_data * phd, u_char * s)
+{
+  int u, v, w, i, l;
+  l = *s++;
+  i = (l - 1) % phd->MAX_L;
+  u = v = w = 0;
+  while (l)
+    {
+#ifndef STRUCT
+      if ((u += phd->tb0[phd->translate[*s]][i]) >= phd->MAX_N)
+	u -= phd->MAX_N;
+      if ((v += phd->tb1[phd->translate[*s]][i]) >= phd->MAX_N)
+	v -= phd->MAX_N;
+      if ((w += phd->tb2[phd->translate[*s]][i]) >= phd->MAX_N)
+	w -= phd->MAX_N;
+#else
+      struct tb_entry *tbp = &phd->tb[phd->translate[*s]][i];
+      if ((u += tbp->tb0) >= phd->MAX_N)
+	u -= phd->MAX_N;
+      if ((v += tbp->tb1) >= phd->MAX_N)
+	v -= phd->MAX_N;
+      if ((w += tbp->tb2) >= phd->MAX_N)
+	w -= phd->MAX_N;
+#endif
+      if (++i >= phd->MAX_L)
+	i = 0;
+      l--;
+      s++;
+    }
+  if (u == v && ++v >= phd->MAX_N)
+    v = 0;
+  if (w == v)
+    {
+      if (++w >= phd->MAX_N)
+	w = 0;
+      if (w == u && ++w >= phd->MAX_N)
+	w = 0;
+    }
+  else if (w == u)
+    {
+      if (++w >= phd->MAX_N)
+	w = 0;
+      if (w == v && ++w >= phd->MAX_N)
+	w = 0;
+    }
+  return ((phd->g[u] ^ phd->g[v] ^ phd->g[w]) > phd->MAX_M) ? 0 :
+    (phd->g[u] ^ phd->g[v] ^ phd->g[w]);
+}
Index: /main/tags/2.25/gsdl/packages/mg/lib/perf_hash.h
===================================================================
--- /main/tags/2.25/gsdl/packages/mg/lib/perf_hash.h	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/mg/lib/perf_hash.h	(revision 21064)
@@ -0,0 +1,57 @@
+/**************************************************************************
+ *
+ * perf_hash.h -- Perfect hashing functions
+ * Copyright (C) 1994  Bohdan S. Majewski and Neil Sharman
+ *
+ * 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.
+ *
+ * $Id$
+ *
+ **************************************************************************/
+
+#ifndef H_PERF_HASH
+#define H_PERF_HASH
+
+
+
+
+struct tb_entry
+  {
+    long tb0, tb1, tb2;
+  };
+
+typedef struct
+  {
+    int MAX_L;
+    int MAX_N;
+    int MAX_M;
+    int MAX_CH;
+    u_char *translate;
+    int *g;
+    struct tb_entry **tb;
+  }
+perf_hash_data;
+
+perf_hash_data *gen_hash_func (int num, u_char ** keys, int r);
+
+int perf_hash (perf_hash_data * phd, u_char * s);
+
+int write_perf_hash_data (FILE * f, perf_hash_data * phd);
+
+void free_perf_hash (perf_hash_data * phd);
+
+perf_hash_data *read_perf_hash_data (FILE * f);
+
+#endif
Index: /main/tags/2.25/gsdl/packages/mg/lib/random.c
===================================================================
--- /main/tags/2.25/gsdl/packages/mg/lib/random.c	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/mg/lib/random.c	(revision 21064)
@@ -0,0 +1,225 @@
+/**************************************************************************
+ *
+ * random.c -- pseudo random number generator
+ * Copyright (C) 1994  Chris Wallace (csw@bruce.cs.monash.edu.au)
+ *
+ * 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.
+ *
+ * $Id$
+ *
+ **************************************************************************/
+
+/*
+$Log$
+Revision 1.1  1999/08/10 21:16:57  sjboddie
+renamed mg-1.3d directory mg
+
+Revision 1.1  1998/11/17 09:32:20  rjmcnab
+*** empty log message ***
+
+*/
+
+static char *RCSID = "$Id$";
+
+/*
+ *	A random number generator called as a function by
+ *	random (iseed)	or	irandm (iseed)
+ *	The parameter should be a pointer to a 2-element long vector.
+ *	The first function returns a double uniform in 0 .. 1.
+ *	The second returns a long integer uniform in 0 .. 2**31-1
+ *	Both update iseed[] in exactly the same way.
+ *	iseed[] must be a 2-element integer vector.
+ *	The initial value of the second element may be anything.
+ *
+ *	The period of the random sequence is 2**32 * (2**32-1)
+ *	The table mt[0:127] is defined by mt[i] = 69069 ** (128-i)
+ */
+
+#define MASK ((long) 593970775)
+/*	or in hex, 23674657	*/
+
+#define SCALE ((double) 1.0 / (1024.0 * 1024.0 * 1024.0 * 2.0))
+/*	i.e. 2 to power -31	*/
+
+static long mt [128] =   {
+      902906369,
+     2030498053,
+     -473499623,
+     1640834941,
+      723406961,
+     1993558325,
+     -257162999,
+    -1627724755,
+      913952737,
+      278845029,
+     1327502073,
+    -1261253155,
+      981676113,
+    -1785280363,
+     1700077033,
+      366908557,
+    -1514479167,
+     -682799163,
+      141955545,
+     -830150595,
+      317871153,
+     1542036469,
+     -946413879,
+    -1950779155,
+      985397153,
+      626515237,
+      530871481,
+      783087261,
+    -1512358895,
+     1031357269,
+    -2007710807,
+    -1652747955,
+    -1867214463,
+      928251525,
+     1243003801,
+    -2132510467,
+     1874683889,
+     -717013323,
+      218254473,
+    -1628774995,
+    -2064896159,
+       69678053,
+      281568889,
+    -2104168611,
+     -165128239,
+     1536495125,
+      -39650967,
+      546594317,
+     -725987007,
+     1392966981,
+     1044706649,
+      687331773,
+    -2051306575,
+     1544302965,
+     -758494647,
+    -1243934099,
+      -75073759,
+      293132965,
+    -1935153095,
+      118929437,
+      807830417,
+    -1416222507,
+    -1550074071,
+      -84903219,
+     1355292929,
+     -380482555,
+    -1818444007,
+     -204797315,
+      170442609,
+    -1636797387,
+      868931593,
+     -623503571,
+     1711722209,
+      381210981,
+     -161547783,
+     -272740131,
+    -1450066095,
+     2116588437,
+     1100682473,
+      358442893,
+    -1529216831,
+     2116152005,
+     -776333095,
+     1265240893,
+     -482278607,
+     1067190005,
+      333444553,
+       86502381,
+      753481377,
+       39000101,
+     1779014585,
+      219658653,
+     -920253679,
+     2029538901,
+     1207761577,
+    -1515772851,
+     -236195711,
+      442620293,
+      423166617,
+    -1763648515,
+     -398436623,
+    -1749358155,
+     -538598519,
+     -652439379,
+      430550625,
+    -1481396507,
+     2093206905,
+    -1934691747,
+     -962631983,
+     1454463253,
+    -1877118871,
+     -291917555,
+    -1711673279,
+      201201733,
+     -474645415,
+      -96764739,
+    -1587365199,
+     1945705589,
+     1303896393,
+     1744831853,
+      381957665,
+     2135332261,
+      -55996615,
+    -1190135011,
+     1790562961,
+    -1493191723,
+      475559465,
+          69069
+		};
+
+double 
+random (long is [2])
+{
+	long it, leh, nit;
+
+	it = is [0];
+	leh = is [1];
+	if (it <= 0)	
+		it = (it + it) ^ MASK;
+	else
+		it = it + it;
+	nit = it - 1;
+/*	to ensure all-ones pattern omitted    */
+	leh = leh * mt[nit & 127] + nit;
+	is [0] = it;    is [1] = leh;
+	if (leh < 0) leh = ~leh;
+	return (SCALE * ((long) (leh | 1)));
+}
+
+
+
+long 
+irandm (long is [2])
+{
+	long it, leh, nit;
+
+	it = is [0];
+	leh = is [1];
+	if (it <= 0)	
+		it = (it + it) ^ MASK;
+	else
+		it = it + it;
+	nit = it - 1;
+/*	to ensure all-ones pattern omitted    */
+	leh = leh * mt[nit & 127] + nit;
+	is [0] = it;    is [1] = leh;
+	if (leh < 0) leh = ~leh;
+	return (leh);
+}
Index: /main/tags/2.25/gsdl/packages/mg/lib/random.h
===================================================================
--- /main/tags/2.25/gsdl/packages/mg/lib/random.h	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/mg/lib/random.h	(revision 21064)
@@ -0,0 +1,54 @@
+/**************************************************************************
+ *
+ * random.h -- pseudo random number generator
+ * Copyright (C) 1994  Chris Wallace (csw@bruce.cs.monash.edu.au)
+ *
+ * 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.
+ *
+ * $Id$
+ *
+ **************************************************************************/
+
+/*
+$Log$
+Revision 1.1  1999/08/10 21:16:58  sjboddie
+renamed mg-1.3d directory mg
+
+Revision 1.1  1998/11/17 09:32:21  rjmcnab
+*** empty log message ***
+
+*/
+
+#ifndef RANDOM_H
+#define RANDOM_H
+
+/*
+ *	A random number generator called as a function by
+ *	random (iseed)	or	irandm (iseed)
+ *	The parameter should be a pointer to a 2-element long vector.
+ *	The first function returns a double uniform in 0 .. 1.
+ *	The second returns a long integer uniform in 0 .. 2**31-1
+ *	Both update iseed[] in exactly the same way.
+ *	iseed[] must be a 2-element integer vector.
+ *	The initial value of the second element may be anything.
+ *
+ *	The period of the random sequence is 2**32 * (2**32-1)
+ *	The table mt[0:127] is defined by mt[i] = 69069 ** (128-i)
+ */
+
+double random (long is [2]);
+long irandm (long is [2]);
+
+#endif
Index: /main/tags/2.25/gsdl/packages/mg/lib/regex.c
===================================================================
--- /main/tags/2.25/gsdl/packages/mg/lib/regex.c	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/mg/lib/regex.c	(revision 21064)
@@ -0,0 +1,5426 @@
+/* Extended regular expression matching and search library,
+   version 0.12.
+   (Implements POSIX draft P10003.2/D11.2, except for
+   internationalization features.)
+
+   Copyright (C) 1993, 1994, 1995 Free Software Foundation, Inc.
+
+   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, 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.  */
+
+/* AIX requires this to be the first thing in the file. */
+#if defined (_AIX) && !defined (REGEX_MALLOC)
+  #pragma alloca
+#endif
+
+#define _GNU_SOURCE
+
+#ifdef HAVE_CONFIG_H
+# ifdef __WIN32__  /* [RPAP - Feb 97: WIN32 Port] */
+#  include <win32cfg.h>
+# else
+#  include <sysfuncs.h>
+# endif
+#endif
+
+/* We need this for `regex.h', and perhaps for the Emacs include files.  */
+#include <sys/types.h>
+
+/* This is for other GNU distributions with internationalized messages.  */
+#if HAVE_LIBINTL_H || defined (_LIBC)
+# include <libintl.h>
+#else
+# define gettext(msgid) (msgid)
+#endif
+
+/* The `emacs' switch turns on certain matching commands
+   that make sense only in Emacs. */
+#ifdef emacs
+
+#include "lisp.h"
+#include "buffer.h"
+#include "syntax.h"
+
+#else  /* not emacs */
+
+/* If we are not linking with Emacs proper,
+   we can't use the relocating allocator
+   even if sysfuncs.h says that we can.  */
+#undef REL_ALLOC
+
+#if defined (STDC_HEADERS) || defined (_LIBC)
+#include <stdlib.h>
+#else
+char *malloc ();
+char *realloc ();
+#endif
+
+/* We used to test for `BSTRING' here, but only GCC and Emacs define
+   `BSTRING', as far as I know, and neither of them use this code.  */
+#ifndef INHIBIT_STRING_HEADER
+#if HAVE_STRING_H || STDC_HEADERS || defined (_LIBC)
+#include <string.h>
+#ifndef bcmp
+#define bcmp(s1, s2, n)	memcmp ((s1), (s2), (n))
+#endif
+#ifndef bcopy
+#define bcopy(s, d, n)	memcpy ((d), (s), (n))
+#endif
+#ifndef bzero
+#define bzero(s, n)	memset ((s), 0, (n))
+#endif
+#else
+#include <strings.h>
+#endif
+#endif
+
+/* Define the syntax stuff for \<, \>, etc.  */
+
+/* This must be nonzero for the wordchar and notwordchar pattern
+   commands in re_match_2.  */
+#ifndef Sword 
+#define Sword 1
+#endif
+
+#ifdef SWITCH_ENUM_BUG
+#define SWITCH_ENUM_CAST(x) ((int)(x))
+#else
+#define SWITCH_ENUM_CAST(x) (x)
+#endif
+
+#ifdef SYNTAX_TABLE
+
+extern char *re_syntax_table;
+
+#else /* not SYNTAX_TABLE */
+
+/* How many characters in the character set.  */
+#define CHAR_SET_SIZE 256
+
+static char re_syntax_table[CHAR_SET_SIZE];
+
+static void
+init_syntax_once ()
+{
+   register int c;
+   static int done = 0;
+
+   if (done)
+     return;
+
+   bzero (re_syntax_table, sizeof re_syntax_table);
+
+   for (c = 'a'; c <= 'z'; c++)
+     re_syntax_table[c] = Sword;
+
+   for (c = 'A'; c <= 'Z'; c++)
+     re_syntax_table[c] = Sword;
+
+   for (c = '0'; c <= '9'; c++)
+     re_syntax_table[c] = Sword;
+
+   re_syntax_table['_'] = Sword;
+
+   done = 1;
+}
+
+#endif /* not SYNTAX_TABLE */
+
+#define SYNTAX(c) re_syntax_table[c]
+
+#endif /* not emacs */
+
+
+/* Get the interface, including the syntax bits.  */
+#include "regex.h"
+
+/* isalpha etc. are used for the character classes.  */
+#include <ctype.h>
+
+/* Jim Meyering writes:
+
+   "... Some ctype macros are valid only for character codes that
+   isascii says are ASCII (SGI's IRIX-4.0.5 is one such system --when
+   using /bin/cc or gcc but without giving an ansi option).  So, all
+   ctype uses should be through macros like ISPRINT...  If
+   STDC_HEADERS is defined, then autoconf has verified that the ctype
+   macros don't need to be guarded with references to isascii. ...
+   Defining isascii to 1 should let any compiler worth its salt
+   eliminate the && through constant folding."  */
+
+#ifndef ISASCII
+#  if defined (STDC_HEADERS) || (!defined (isascii) && !defined (HAVE_ISASCII))
+#    define ISASCII(c) 1
+#  else
+#    define ISASCII(c) isascii(c)
+#  endif
+#endif
+
+#ifdef isblank
+#define ISBLANK(c) (ISASCII (c) && isblank (c))
+#else
+#define ISBLANK(c) ((c) == ' ' || (c) == '\t')
+#endif
+#ifdef isgraph
+#define ISGRAPH(c) (ISASCII (c) && isgraph (c))
+#else
+#define ISGRAPH(c) (ISASCII (c) && isprint (c) && !isspace (c))
+#endif
+
+#define ISPRINT(c) (ISASCII (c) && isprint (c))
+#define ISDIGIT(c) (ISASCII (c) && isdigit (c))
+#define ISALNUM(c) (ISASCII (c) && isalnum (c))
+#define ISALPHA(c) (ISASCII (c) && isalpha (c))
+#define ISCNTRL(c) (ISASCII (c) && iscntrl (c))
+#define ISLOWER(c) (ISASCII (c) && islower (c))
+#define ISPUNCT(c) (ISASCII (c) && ispunct (c))
+#define ISSPACE(c) (ISASCII (c) && isspace (c))
+#define ISUPPER(c) (ISASCII (c) && isupper (c))
+#define ISXDIGIT(c) (ISASCII (c) && isxdigit (c))
+
+#ifndef NULL
+#define NULL 0
+#endif
+
+/* We remove any previous definition of `SIGN_EXTEND_CHAR',
+   since ours (we hope) works properly with all combinations of
+   machines, compilers, `char' and `unsigned char' argument types.
+   (Per Bothner suggested the basic approach.)  */
+#undef SIGN_EXTEND_CHAR
+#if __STDC__
+#define SIGN_EXTEND_CHAR(c) ((signed char) (c))
+#else  /* not __STDC__ */
+/* As in Harbison and Steele.  */
+#define SIGN_EXTEND_CHAR(c) ((((unsigned char) (c)) ^ 128) - 128)
+#endif
+
+
+/* Should we use malloc or alloca?  If REGEX_MALLOC is not defined, we
+   use `alloca' instead of `malloc'.  This is because using malloc in
+   re_search* or re_match* could cause memory leaks when C-g is used in
+   Emacs; also, malloc is slower and causes storage fragmentation.  On
+   the other hand, malloc is more portable, and easier to debug.  
+   
+   Because we sometimes use alloca, some routines have to be macros,
+   not functions -- `alloca'-allocated space disappears at the end of the
+   function it is called in.  */
+
+#ifdef REGEX_MALLOC
+
+#define REGEX_ALLOCATE malloc
+#define REGEX_REALLOCATE(source, osize, nsize) realloc (source, nsize)
+#define REGEX_FREE free
+
+#else /* not REGEX_MALLOC  */
+
+/* Emacs already defines alloca, sometimes.  */
+#ifndef alloca
+
+/* Make alloca work the best possible way.  */
+#ifdef __GNUC__
+#define alloca __builtin_alloca
+#else /* not __GNUC__ */
+#if HAVE_ALLOCA_H
+#include <alloca.h>
+#else /* not __GNUC__ or HAVE_ALLOCA_H */
+#ifndef _AIX /* Already did AIX, up at the top.  */
+char *alloca ();
+#endif /* not _AIX */
+#endif /* not HAVE_ALLOCA_H */ 
+#endif /* not __GNUC__ */
+
+#endif /* not alloca */
+
+#define REGEX_ALLOCATE alloca
+
+/* Assumes a `char *destination' variable.  */
+#define REGEX_REALLOCATE(source, osize, nsize)				\
+  (destination = (char *) alloca (nsize),				\
+   bcopy (source, destination, osize),					\
+   destination)
+
+/* No need to do anything to free, after alloca.  */
+#define REGEX_FREE(arg) ((void)0) /* Do nothing!  But inhibit gcc warning.  */
+
+#endif /* not REGEX_MALLOC */
+
+/* Define how to allocate the failure stack.  */
+
+#ifdef REL_ALLOC
+#define REGEX_ALLOCATE_STACK(size)				\
+  r_alloc (&failure_stack_ptr, (size))
+#define REGEX_REALLOCATE_STACK(source, osize, nsize)		\
+  r_re_alloc (&failure_stack_ptr, (nsize))
+#define REGEX_FREE_STACK(ptr)					\
+  r_alloc_free (&failure_stack_ptr)
+
+#else /* not REL_ALLOC */
+
+#ifdef REGEX_MALLOC
+
+#define REGEX_ALLOCATE_STACK malloc
+#define REGEX_REALLOCATE_STACK(source, osize, nsize) realloc (source, nsize)
+#define REGEX_FREE_STACK free
+
+#else /* not REGEX_MALLOC */
+
+#define REGEX_ALLOCATE_STACK alloca
+
+#define REGEX_REALLOCATE_STACK(source, osize, nsize)			\
+   REGEX_REALLOCATE (source, osize, nsize)
+/* No need to explicitly free anything.  */
+#define REGEX_FREE_STACK(arg)
+
+#endif /* not REGEX_MALLOC */
+#endif /* not REL_ALLOC */
+
+
+/* True if `size1' is non-NULL and PTR is pointing anywhere inside
+   `string1' or just past its end.  This works if PTR is NULL, which is
+   a good thing.  */
+#define FIRST_STRING_P(ptr) 					\
+  (size1 && string1 <= (ptr) && (ptr) <= string1 + size1)
+
+/* (Re)Allocate N items of type T using malloc, or fail.  */
+#define TALLOC(n, t) ((t *) malloc ((n) * sizeof (t)))
+#define RETALLOC(addr, n, t) ((addr) = (t *) realloc (addr, (n) * sizeof (t)))
+#define RETALLOC_IF(addr, n, t) \
+  if (addr) RETALLOC((addr), (n), t); else (addr) = TALLOC ((n), t)
+#define REGEX_TALLOC(n, t) ((t *) REGEX_ALLOCATE ((n) * sizeof (t)))
+
+#define BYTEWIDTH 8 /* In bits.  */
+
+#define STREQ(s1, s2) ((strcmp (s1, s2) == 0))
+
+#undef MAX
+#undef MIN
+#define MAX(a, b) ((a) > (b) ? (a) : (b))
+#define MIN(a, b) ((a) < (b) ? (a) : (b))
+
+typedef char boolean;
+#define false 0
+#define true 1
+
+static int re_match_2_internal ();
+
+
+/* These are the command codes that appear in compiled regular
+   expressions.  Some opcodes are followed by argument bytes.  A
+   command code can specify any interpretation whatsoever for its
+   arguments.  Zero bytes may appear in the compiled regular expression.  */
+
+typedef enum
+{
+  no_op = 0,
+
+  /* Succeed right away--no more backtracking.  */
+  succeed,
+
+        /* Followed by one byte giving n, then by n literal bytes.  */
+  exactn,
+
+        /* Matches any (more or less) character.  */
+  anychar,
+
+        /* Matches any one char belonging to specified set.  First
+           following byte is number of bitmap bytes.  Then come bytes
+           for a bitmap saying which chars are in.  Bits in each byte
+           are ordered low-bit-first.  A character is in the set if its
+           bit is 1.  A character too large to have a bit in the map is
+           automatically not in the set.  */
+  charset,
+
+        /* Same parameters as charset, but match any character that is
+           not one of those specified.  */
+  charset_not,
+
+        /* Start remembering the text that is matched, for storing in a
+           register.  Followed by one byte with the register number, in
+           the range 0 to one less than the pattern buffer's re_nsub
+           field.  Then followed by one byte with the number of groups
+           inner to this one.  (This last has to be part of the
+           start_memory only because we need it in the on_failure_jump
+           of re_match_2.)  */
+  start_memory,
+
+        /* Stop remembering the text that is matched and store it in a
+           memory register.  Followed by one byte with the register
+           number, in the range 0 to one less than `re_nsub' in the
+           pattern buffer, and one byte with the number of inner groups,
+           just like `start_memory'.  (We need the number of inner
+           groups here because we don't have any easy way of finding the
+           corresponding start_memory when we're at a stop_memory.)  */
+  stop_memory,
+
+        /* Match a duplicate of something remembered. Followed by one
+           byte containing the register number.  */
+  duplicate,
+
+        /* Fail unless at beginning of line.  */
+  begline,
+
+        /* Fail unless at end of line.  */
+  endline,
+
+        /* Succeeds if at beginning of buffer (if emacs) or at beginning
+           of string to be matched (if not).  */
+  begbuf,
+
+        /* Analogously, for end of buffer/string.  */
+  endbuf,
+ 
+        /* Followed by two byte relative address to which to jump.  */
+  jump, 
+
+	/* Same as jump, but marks the end of an alternative.  */
+  jump_past_alt,
+
+        /* Followed by two-byte relative address of place to resume at
+           in case of failure.  */
+  on_failure_jump,
+	
+        /* Like on_failure_jump, but pushes a placeholder instead of the
+           current string position when executed.  */
+  on_failure_keep_string_jump,
+  
+        /* Throw away latest failure point and then jump to following
+           two-byte relative address.  */
+  pop_failure_jump,
+
+        /* Change to pop_failure_jump if know won't have to backtrack to
+           match; otherwise change to jump.  This is used to jump
+           back to the beginning of a repeat.  If what follows this jump
+           clearly won't match what the repeat does, such that we can be
+           sure that there is no use backtracking out of repetitions
+           already matched, then we change it to a pop_failure_jump.
+           Followed by two-byte address.  */
+  maybe_pop_jump,
+
+        /* Jump to following two-byte address, and push a dummy failure
+           point. This failure point will be thrown away if an attempt
+           is made to use it for a failure.  A `+' construct makes this
+           before the first repeat.  Also used as an intermediary kind
+           of jump when compiling an alternative.  */
+  dummy_failure_jump,
+
+	/* Push a dummy failure point and continue.  Used at the end of
+	   alternatives.  */
+  push_dummy_failure,
+
+        /* Followed by two-byte relative address and two-byte number n.
+           After matching N times, jump to the address upon failure.  */
+  succeed_n,
+
+        /* Followed by two-byte relative address, and two-byte number n.
+           Jump to the address N times, then fail.  */
+  jump_n,
+
+        /* Set the following two-byte relative address to the
+           subsequent two-byte number.  The address *includes* the two
+           bytes of number.  */
+  set_number_at,
+
+  wordchar,	/* Matches any word-constituent character.  */
+  notwordchar,	/* Matches any char that is not a word-constituent.  */
+
+  wordbeg,	/* Succeeds if at word beginning.  */
+  wordend,	/* Succeeds if at word end.  */
+
+  wordbound,	/* Succeeds if at a word boundary.  */
+  notwordbound	/* Succeeds if not at a word boundary.  */
+
+#ifdef emacs
+  ,before_dot,	/* Succeeds if before point.  */
+  at_dot,	/* Succeeds if at point.  */
+  after_dot,	/* Succeeds if after point.  */
+
+	/* Matches any character whose syntax is specified.  Followed by
+           a byte which contains a syntax code, e.g., Sword.  */
+  syntaxspec,
+
+	/* Matches any character whose syntax is not that specified.  */
+  notsyntaxspec
+#endif /* emacs */
+} re_opcode_t;
+
+
+/* Common operations on the compiled pattern.  */
+
+/* Store NUMBER in two contiguous bytes starting at DESTINATION.  */
+
+#define STORE_NUMBER(destination, number)				\
+  do {									\
+    (destination)[0] = (number) & 0377;					\
+    (destination)[1] = (number) >> 8;					\
+  } while (0)
+
+/* Same as STORE_NUMBER, except increment DESTINATION to
+   the byte after where the number is stored.  Therefore, DESTINATION
+   must be an lvalue.  */
+
+#define STORE_NUMBER_AND_INCR(destination, number)			\
+  do {									\
+    STORE_NUMBER (destination, number);					\
+    (destination) += 2;							\
+  } while (0)
+
+/* Put into DESTINATION a number stored in two contiguous bytes starting
+   at SOURCE.  */
+
+#define EXTRACT_NUMBER(destination, source)				\
+  do {									\
+    (destination) = *(source) & 0377;					\
+    (destination) += SIGN_EXTEND_CHAR (*((source) + 1)) << 8;		\
+  } while (0)
+
+#ifdef DEBUG
+static void
+extract_number (dest, source)
+    int *dest;
+    unsigned char *source;
+{
+  int temp = SIGN_EXTEND_CHAR (*(source + 1)); 
+  *dest = *source & 0377;
+  *dest += temp << 8;
+}
+
+#ifndef EXTRACT_MACROS /* To debug the macros.  */
+#undef EXTRACT_NUMBER
+#define EXTRACT_NUMBER(dest, src) extract_number (&dest, src)
+#endif /* not EXTRACT_MACROS */
+
+#endif /* DEBUG */
+
+/* Same as EXTRACT_NUMBER, except increment SOURCE to after the number.
+   SOURCE must be an lvalue.  */
+
+#define EXTRACT_NUMBER_AND_INCR(destination, source)			\
+  do {									\
+    EXTRACT_NUMBER (destination, source);				\
+    (source) += 2; 							\
+  } while (0)
+
+#ifdef DEBUG
+static void
+extract_number_and_incr (destination, source)
+    int *destination;
+    unsigned char **source;
+{ 
+  extract_number (destination, *source);
+  *source += 2;
+}
+
+#ifndef EXTRACT_MACROS
+#undef EXTRACT_NUMBER_AND_INCR
+#define EXTRACT_NUMBER_AND_INCR(dest, src) \
+  extract_number_and_incr (&dest, &src)
+#endif /* not EXTRACT_MACROS */
+
+#endif /* DEBUG */
+
+
+/* If DEBUG is defined, Regex prints many voluminous messages about what
+   it is doing (if the variable `debug' is nonzero).  If linked with the
+   main program in `iregex.c', you can enter patterns and strings
+   interactively.  And if linked with the main program in `main.c' and
+   the other test files, you can run the already-written tests.  */
+
+#ifdef DEBUG
+
+/* We use standard I/O for debugging.  */
+#include <stdio.h>
+
+/* It is useful to test things that ``must'' be true when debugging.  */
+#include <assert.h>
+
+static int debug = 0;
+
+#define DEBUG_STATEMENT(e) e
+#define DEBUG_PRINT1(x) if (debug) printf (x)
+#define DEBUG_PRINT2(x1, x2) if (debug) printf (x1, x2)
+#define DEBUG_PRINT3(x1, x2, x3) if (debug) printf (x1, x2, x3)
+#define DEBUG_PRINT4(x1, x2, x3, x4) if (debug) printf (x1, x2, x3, x4)
+#define DEBUG_PRINT_COMPILED_PATTERN(p, s, e) 				\
+  if (debug) print_partial_compiled_pattern (s, e)
+#define DEBUG_PRINT_DOUBLE_STRING(w, s1, sz1, s2, sz2)			\
+  if (debug) print_double_string (w, s1, sz1, s2, sz2)
+
+
+/* Print the fastmap in human-readable form.  */
+
+void
+print_fastmap (fastmap)
+    char *fastmap;
+{
+  unsigned was_a_range = 0;
+  unsigned i = 0;  
+  
+  while (i < (1 << BYTEWIDTH))
+    {
+      if (fastmap[i++])
+	{
+	  was_a_range = 0;
+          putchar (i - 1);
+          while (i < (1 << BYTEWIDTH)  &&  fastmap[i])
+            {
+              was_a_range = 1;
+              i++;
+            }
+	  if (was_a_range)
+            {
+              printf ("-");
+              putchar (i - 1);
+            }
+        }
+    }
+  putchar ('\n'); 
+}
+
+
+/* Print a compiled pattern string in human-readable form, starting at
+   the START pointer into it and ending just before the pointer END.  */
+
+void
+print_partial_compiled_pattern (start, end)
+    unsigned char *start;
+    unsigned char *end;
+{
+  int mcnt, mcnt2;
+  unsigned char *p = start;
+  unsigned char *pend = end;
+
+  if (start == NULL)
+    {
+      printf ("(null)\n");
+      return;
+    }
+    
+  /* Loop over pattern commands.  */
+  while (p < pend)
+    {
+      printf ("%d:\t", p - start);
+
+      switch ((re_opcode_t) *p++)
+	{
+        case no_op:
+          printf ("/no_op");
+          break;
+
+	case exactn:
+	  mcnt = *p++;
+          printf ("/exactn/%d", mcnt);
+          do
+	    {
+              putchar ('/');
+	      putchar (*p++);
+            }
+          while (--mcnt);
+          break;
+
+	case start_memory:
+          mcnt = *p++;
+          printf ("/start_memory/%d/%d", mcnt, *p++);
+          break;
+
+	case stop_memory:
+          mcnt = *p++;
+	  printf ("/stop_memory/%d/%d", mcnt, *p++);
+          break;
+
+	case duplicate:
+	  printf ("/duplicate/%d", *p++);
+	  break;
+
+	case anychar:
+	  printf ("/anychar");
+	  break;
+
+	case charset:
+        case charset_not:
+          {
+            register int c, last = -100;
+	    register int in_range = 0;
+
+	    printf ("/charset [%s",
+	            (re_opcode_t) *(p - 1) == charset_not ? "^" : "");
+            
+            assert (p + *p < pend);
+
+            for (c = 0; c < 256; c++)
+	      if (c / 8 < *p
+		  && (p[1 + (c/8)] & (1 << (c % 8))))
+		{
+		  /* Are we starting a range?  */
+		  if (last + 1 == c && ! in_range)
+		    {
+		      putchar ('-');
+		      in_range = 1;
+		    }
+		  /* Have we broken a range?  */
+		  else if (last + 1 != c && in_range)
+              {
+		      putchar (last);
+		      in_range = 0;
+		    }
+                
+		  if (! in_range)
+		    putchar (c);
+
+		  last = c;
+              }
+
+	    if (in_range)
+	      putchar (last);
+
+	    putchar (']');
+
+	    p += 1 + *p;
+	  }
+	  break;
+
+	case begline:
+	  printf ("/begline");
+          break;
+
+	case endline:
+          printf ("/endline");
+          break;
+
+	case on_failure_jump:
+          extract_number_and_incr (&mcnt, &p);
+  	  printf ("/on_failure_jump to %d", p + mcnt - start);
+          break;
+
+	case on_failure_keep_string_jump:
+          extract_number_and_incr (&mcnt, &p);
+  	  printf ("/on_failure_keep_string_jump to %d", p + mcnt - start);
+          break;
+
+	case dummy_failure_jump:
+          extract_number_and_incr (&mcnt, &p);
+  	  printf ("/dummy_failure_jump to %d", p + mcnt - start);
+          break;
+
+	case push_dummy_failure:
+          printf ("/push_dummy_failure");
+          break;
+          
+        case maybe_pop_jump:
+          extract_number_and_incr (&mcnt, &p);
+  	  printf ("/maybe_pop_jump to %d", p + mcnt - start);
+	  break;
+
+        case pop_failure_jump:
+	  extract_number_and_incr (&mcnt, &p);
+  	  printf ("/pop_failure_jump to %d", p + mcnt - start);
+	  break;          
+          
+        case jump_past_alt:
+	  extract_number_and_incr (&mcnt, &p);
+  	  printf ("/jump_past_alt to %d", p + mcnt - start);
+	  break;          
+          
+        case jump:
+	  extract_number_and_incr (&mcnt, &p);
+  	  printf ("/jump to %d", p + mcnt - start);
+	  break;
+
+        case succeed_n: 
+          extract_number_and_incr (&mcnt, &p);
+          extract_number_and_incr (&mcnt2, &p);
+	  printf ("/succeed_n to %d, %d times", p + mcnt - start, mcnt2);
+          break;
+        
+        case jump_n: 
+          extract_number_and_incr (&mcnt, &p);
+          extract_number_and_incr (&mcnt2, &p);
+	  printf ("/jump_n to %d, %d times", p + mcnt - start, mcnt2);
+          break;
+        
+        case set_number_at: 
+          extract_number_and_incr (&mcnt, &p);
+          extract_number_and_incr (&mcnt2, &p);
+	  printf ("/set_number_at location %d to %d", p + mcnt - start, mcnt2);
+          break;
+        
+        case wordbound:
+	  printf ("/wordbound");
+	  break;
+
+	case notwordbound:
+	  printf ("/notwordbound");
+          break;
+
+	case wordbeg:
+	  printf ("/wordbeg");
+	  break;
+          
+	case wordend:
+	  printf ("/wordend");
+          
+#ifdef emacs
+	case before_dot:
+	  printf ("/before_dot");
+          break;
+
+	case at_dot:
+	  printf ("/at_dot");
+          break;
+
+	case after_dot:
+	  printf ("/after_dot");
+          break;
+
+	case syntaxspec:
+          printf ("/syntaxspec");
+	  mcnt = *p++;
+	  printf ("/%d", mcnt);
+          break;
+	  
+	case notsyntaxspec:
+          printf ("/notsyntaxspec");
+	  mcnt = *p++;
+	  printf ("/%d", mcnt);
+	  break;
+#endif /* emacs */
+
+	case wordchar:
+	  printf ("/wordchar");
+          break;
+	  
+	case notwordchar:
+	  printf ("/notwordchar");
+          break;
+
+	case begbuf:
+	  printf ("/begbuf");
+          break;
+
+	case endbuf:
+	  printf ("/endbuf");
+          break;
+
+        default:
+          printf ("?%d", *(p-1));
+	}
+
+      putchar ('\n');
+    }
+
+  printf ("%d:\tend of pattern.\n", p - start);
+}
+
+
+void
+print_compiled_pattern (bufp)
+    struct re_pattern_buffer *bufp;
+{
+  unsigned char *buffer = bufp->buffer;
+
+  print_partial_compiled_pattern (buffer, buffer + bufp->used);
+  printf ("%d bytes used/%d bytes allocated.\n", bufp->used, bufp->allocated);
+
+  if (bufp->fastmap_accurate && bufp->fastmap)
+    {
+      printf ("fastmap: ");
+      print_fastmap (bufp->fastmap);
+    }
+
+  printf ("re_nsub: %d\t", bufp->re_nsub);
+  printf ("regs_alloc: %d\t", bufp->regs_allocated);
+  printf ("can_be_null: %d\t", bufp->can_be_null);
+  printf ("newline_anchor: %d\n", bufp->newline_anchor);
+  printf ("no_sub: %d\t", bufp->no_sub);
+  printf ("not_bol: %d\t", bufp->not_bol);
+  printf ("not_eol: %d\t", bufp->not_eol);
+  printf ("syntax: %d\n", bufp->syntax);
+  /* Perhaps we should print the translate table?  */
+}
+
+
+void
+print_double_string (where, string1, size1, string2, size2)
+    const char *where;
+    const char *string1;
+    const char *string2;
+    int size1;
+    int size2;
+{
+  unsigned this_char;
+  
+  if (where == NULL)
+    printf ("(null)");
+  else
+    {
+      if (FIRST_STRING_P (where))
+        {
+          for (this_char = where - string1; this_char < size1; this_char++)
+            putchar (string1[this_char]);
+
+          where = string2;    
+        }
+
+      for (this_char = where - string2; this_char < size2; this_char++)
+        putchar (string2[this_char]);
+    }
+}
+
+#else /* not DEBUG */
+
+#undef assert
+#define assert(e)
+
+#define DEBUG_STATEMENT(e)
+#define DEBUG_PRINT1(x)
+#define DEBUG_PRINT2(x1, x2)
+#define DEBUG_PRINT3(x1, x2, x3)
+#define DEBUG_PRINT4(x1, x2, x3, x4)
+#define DEBUG_PRINT_COMPILED_PATTERN(p, s, e)
+#define DEBUG_PRINT_DOUBLE_STRING(w, s1, sz1, s2, sz2)
+
+#endif /* not DEBUG */
+
+
+/* Set by `re_set_syntax' to the current regexp syntax to recognize.  Can
+   also be assigned to arbitrarily: each pattern buffer stores its own
+   syntax, so it can be changed between regex compilations.  */
+/* This has no initializer because initialized variables in Emacs
+   become read-only after dumping.  */
+reg_syntax_t re_syntax_options;
+
+
+/* Specify the precise syntax of regexps for compilation.  This provides
+   for compatibility for various utilities which historically have
+   different, incompatible syntaxes.
+
+   The argument SYNTAX is a bit mask comprised of the various bits
+   defined in regex.h.  We return the old syntax.  */
+
+reg_syntax_t
+re_set_syntax (syntax)
+    reg_syntax_t syntax;
+{
+  reg_syntax_t ret = re_syntax_options;
+  
+  re_syntax_options = syntax;
+  return ret;
+}
+
+
+/* This table gives an error message for each of the error codes listed
+   in regex.h.  Obviously the order here has to be same as there.
+   POSIX doesn't require that we do anything for REG_NOERROR,
+   but why not be nice?  */
+
+static const char *re_error_msgid[] =
+  { "Success",					/* REG_NOERROR */
+    "No match",					/* REG_NOMATCH */
+    "Invalid regular expression",		/* REG_BADPAT */
+    "Invalid collation character",		/* REG_ECOLLATE */
+    "Invalid character class name",		/* REG_ECTYPE */
+    "Trailing backslash",			/* REG_EESCAPE */
+    "Invalid back reference",			/* REG_ESUBREG */
+    "Unmatched [ or [^",			/* REG_EBRACK */
+    "Unmatched ( or \\(",			/* REG_EPAREN */
+    "Unmatched \\{",				/* REG_EBRACE */
+    "Invalid content of \\{\\}",		/* REG_BADBR */
+    "Invalid range end",			/* REG_ERANGE */
+    "Memory exhausted",				/* REG_ESPACE */
+    "Invalid preceding regular expression",	/* REG_BADRPT */
+    "Premature end of regular expression",	/* REG_EEND */
+    "Regular expression too big",		/* REG_ESIZE */
+    "Unmatched ) or \\)",			/* REG_ERPAREN */
+  };
+
+
+/* Avoiding alloca during matching, to placate r_alloc.  */
+
+/* Define MATCH_MAY_ALLOCATE unless we need to make sure that the
+   searching and matching functions should not call alloca.  On some
+   systems, alloca is implemented in terms of malloc, and if we're
+   using the relocating allocator routines, then malloc could cause a
+   relocation, which might (if the strings being searched are in the
+   ralloc heap) shift the data out from underneath the regexp
+   routines.
+
+   Here's another reason to avoid allocation: Emacs 
+   processes input from X in a signal handler; processing X input may
+   call malloc; if input arrives while a matching routine is calling
+   malloc, then we're scrod.  But Emacs can't just block input while
+   calling matching routines; then we don't notice interrupts when
+   they come in.  So, Emacs blocks input around all regexp calls
+   except the matching calls, which it leaves unprotected, in the
+   faith that they will not malloc.  */
+
+/* Normally, this is fine.  */
+#define MATCH_MAY_ALLOCATE
+
+/* When using GNU C, we are not REALLY using the C alloca, no matter
+   what sysfuncs.h may say.  So don't take precautions for it.  */
+#ifdef __GNUC__
+#undef C_ALLOCA
+#endif
+
+/* The match routines may not allocate if (1) they would do it with malloc
+   and (2) it's not safe for them to use malloc.
+   Note that if REL_ALLOC is defined, matching would not use malloc for the
+   failure stack, but we would still use it for the register vectors;
+   so REL_ALLOC should not affect this.  */
+#if (defined (C_ALLOCA) || defined (REGEX_MALLOC)) && defined (emacs)
+#undef MATCH_MAY_ALLOCATE
+#endif
+
+
+
+/* Failure stack declarations and macros; both re_compile_fastmap and
+   re_match_2 use a failure stack.  These have to be macros because of
+   REGEX_ALLOCATE_STACK.  */
+   
+
+/* Number of failure points for which to initially allocate space
+   when matching.  If this number is exceeded, we allocate more
+   space, so it is not a hard limit.  */
+#ifndef INIT_FAILURE_ALLOC
+#define INIT_FAILURE_ALLOC 5
+#endif
+
+/* Roughly the maximum number of failure points on the stack.  Would be
+   exactly that if always used MAX_FAILURE_SPACE each time we failed.
+   This is a variable only so users of regex can assign to it; we never
+   change it ourselves.  */
+#if defined (MATCH_MAY_ALLOCATE)
+int re_max_failures = 200000;
+#else
+int re_max_failures = 2000;
+#endif
+
+union fail_stack_elt
+{
+  unsigned char *pointer;
+  int integer;
+};
+
+typedef union fail_stack_elt fail_stack_elt_t;
+
+typedef struct
+{
+  fail_stack_elt_t *stack;
+  unsigned size;
+  unsigned avail;			/* Offset of next open position.  */
+} fail_stack_type;
+
+#define FAIL_STACK_EMPTY()     (fail_stack.avail == 0)
+#define FAIL_STACK_PTR_EMPTY() (fail_stack_ptr->avail == 0)
+#define FAIL_STACK_FULL()      (fail_stack.avail == fail_stack.size)
+
+
+/* Define macros to initialize and free the failure stack.
+   Do `return -2' if the alloc fails.  */
+
+#ifdef MATCH_MAY_ALLOCATE
+#define INIT_FAIL_STACK()						\
+  do {									\
+    fail_stack.stack = (fail_stack_elt_t *)				\
+      REGEX_ALLOCATE_STACK (INIT_FAILURE_ALLOC * sizeof (fail_stack_elt_t));	\
+									\
+    if (fail_stack.stack == NULL)					\
+      return -2;							\
+									\
+    fail_stack.size = INIT_FAILURE_ALLOC;				\
+    fail_stack.avail = 0;						\
+  } while (0)
+
+#define RESET_FAIL_STACK()  REGEX_FREE_STACK (fail_stack.stack)
+#else
+#define INIT_FAIL_STACK()						\
+  do {									\
+    fail_stack.avail = 0;						\
+  } while (0)
+
+#define RESET_FAIL_STACK()
+#endif
+
+
+/* Double the size of FAIL_STACK, up to approximately `re_max_failures' items.
+
+   Return 1 if succeeds, and 0 if either ran out of memory
+   allocating space for it or it was already too large.  
+   
+   REGEX_REALLOCATE_STACK requires `destination' be declared.   */
+
+#define DOUBLE_FAIL_STACK(fail_stack)					\
+  ((fail_stack).size > re_max_failures * MAX_FAILURE_ITEMS		\
+   ? 0									\
+   : ((fail_stack).stack = (fail_stack_elt_t *)				\
+        REGEX_REALLOCATE_STACK ((fail_stack).stack, 			\
+          (fail_stack).size * sizeof (fail_stack_elt_t),		\
+          ((fail_stack).size << 1) * sizeof (fail_stack_elt_t)),	\
+									\
+      (fail_stack).stack == NULL					\
+      ? 0								\
+      : ((fail_stack).size <<= 1, 					\
+         1)))
+
+
+/* Push pointer POINTER on FAIL_STACK. 
+   Return 1 if was able to do so and 0 if ran out of memory allocating
+   space to do so.  */
+#define PUSH_PATTERN_OP(POINTER, FAIL_STACK)				\
+  ((FAIL_STACK_FULL ()							\
+    && !DOUBLE_FAIL_STACK (FAIL_STACK))					\
+   ? 0									\
+   : ((FAIL_STACK).stack[(FAIL_STACK).avail++].pointer = POINTER,	\
+      1))
+
+/* Push a pointer value onto the failure stack.
+   Assumes the variable `fail_stack'.  Probably should only
+   be called from within `PUSH_FAILURE_POINT'.  */
+#define PUSH_FAILURE_POINTER(item)					\
+  fail_stack.stack[fail_stack.avail++].pointer = (unsigned char *) (item)
+
+/* This pushes an integer-valued item onto the failure stack.
+   Assumes the variable `fail_stack'.  Probably should only
+   be called from within `PUSH_FAILURE_POINT'.  */
+#define PUSH_FAILURE_INT(item)					\
+  fail_stack.stack[fail_stack.avail++].integer = (item)
+
+/* Push a fail_stack_elt_t value onto the failure stack.
+   Assumes the variable `fail_stack'.  Probably should only
+   be called from within `PUSH_FAILURE_POINT'.  */
+#define PUSH_FAILURE_ELT(item)					\
+  fail_stack.stack[fail_stack.avail++] =  (item)
+
+/* These three POP... operations complement the three PUSH... operations.
+   All assume that `fail_stack' is nonempty.  */
+#define POP_FAILURE_POINTER() fail_stack.stack[--fail_stack.avail].pointer
+#define POP_FAILURE_INT() fail_stack.stack[--fail_stack.avail].integer
+#define POP_FAILURE_ELT() fail_stack.stack[--fail_stack.avail]
+
+/* Used to omit pushing failure point id's when we're not debugging.  */
+#ifdef DEBUG
+#define DEBUG_PUSH PUSH_FAILURE_INT
+#define DEBUG_POP(item_addr) *(item_addr) = POP_FAILURE_INT ()
+#else
+#define DEBUG_PUSH(item)
+#define DEBUG_POP(item_addr)
+#endif
+
+
+/* Push the information about the state we will need
+   if we ever fail back to it.  
+   
+   Requires variables fail_stack, regstart, regend, reg_info, and
+   num_regs be declared.  DOUBLE_FAIL_STACK requires `destination' be
+   declared.
+   
+   Does `return FAILURE_CODE' if runs out of memory.  */
+
+#define PUSH_FAILURE_POINT(pattern_place, string_place, failure_code)	\
+  do {									\
+    char *destination;							\
+    /* Must be int, so when we don't save any registers, the arithmetic	\
+       of 0 + -1 isn't done as unsigned.  */				\
+    int this_reg;							\
+    									\
+    DEBUG_STATEMENT (failure_id++);					\
+    DEBUG_STATEMENT (nfailure_points_pushed++);				\
+    DEBUG_PRINT2 ("\nPUSH_FAILURE_POINT #%u:\n", failure_id);		\
+    DEBUG_PRINT2 ("  Before push, next avail: %d\n", (fail_stack).avail);\
+    DEBUG_PRINT2 ("                     size: %d\n", (fail_stack).size);\
+									\
+    DEBUG_PRINT2 ("  slots needed: %d\n", NUM_FAILURE_ITEMS);		\
+    DEBUG_PRINT2 ("     available: %d\n", REMAINING_AVAIL_SLOTS);	\
+									\
+    /* Ensure we have enough space allocated for what we will push.  */	\
+    while (REMAINING_AVAIL_SLOTS < NUM_FAILURE_ITEMS)			\
+      {									\
+        if (!DOUBLE_FAIL_STACK (fail_stack))				\
+          return failure_code;						\
+									\
+        DEBUG_PRINT2 ("\n  Doubled stack; size now: %d\n",		\
+		       (fail_stack).size);				\
+        DEBUG_PRINT2 ("  slots available: %d\n", REMAINING_AVAIL_SLOTS);\
+      }									\
+									\
+    /* Push the info, starting with the registers.  */			\
+    DEBUG_PRINT1 ("\n");						\
+									\
+    for (this_reg = lowest_active_reg; this_reg <= highest_active_reg;	\
+         this_reg++)							\
+      {									\
+	DEBUG_PRINT2 ("  Pushing reg: %d\n", this_reg);			\
+        DEBUG_STATEMENT (num_regs_pushed++);				\
+									\
+	DEBUG_PRINT2 ("    start: 0x%x\n", regstart[this_reg]);		\
+        PUSH_FAILURE_POINTER (regstart[this_reg]);			\
+                                                                        \
+	DEBUG_PRINT2 ("    end: 0x%x\n", regend[this_reg]);		\
+        PUSH_FAILURE_POINTER (regend[this_reg]);			\
+									\
+	DEBUG_PRINT2 ("    info: 0x%x\n      ", reg_info[this_reg]);	\
+        DEBUG_PRINT2 (" match_null=%d",					\
+                      REG_MATCH_NULL_STRING_P (reg_info[this_reg]));	\
+        DEBUG_PRINT2 (" active=%d", IS_ACTIVE (reg_info[this_reg]));	\
+        DEBUG_PRINT2 (" matched_something=%d",				\
+                      MATCHED_SOMETHING (reg_info[this_reg]));		\
+        DEBUG_PRINT2 (" ever_matched=%d",				\
+                      EVER_MATCHED_SOMETHING (reg_info[this_reg]));	\
+	DEBUG_PRINT1 ("\n");						\
+        PUSH_FAILURE_ELT (reg_info[this_reg].word);			\
+      }									\
+									\
+    DEBUG_PRINT2 ("  Pushing  low active reg: %d\n", lowest_active_reg);\
+    PUSH_FAILURE_INT (lowest_active_reg);				\
+									\
+    DEBUG_PRINT2 ("  Pushing high active reg: %d\n", highest_active_reg);\
+    PUSH_FAILURE_INT (highest_active_reg);				\
+									\
+    DEBUG_PRINT2 ("  Pushing pattern 0x%x: ", pattern_place);		\
+    DEBUG_PRINT_COMPILED_PATTERN (bufp, pattern_place, pend);		\
+    PUSH_FAILURE_POINTER (pattern_place);				\
+									\
+    DEBUG_PRINT2 ("  Pushing string 0x%x: `", string_place);		\
+    DEBUG_PRINT_DOUBLE_STRING (string_place, string1, size1, string2,   \
+				 size2);				\
+    DEBUG_PRINT1 ("'\n");						\
+    PUSH_FAILURE_POINTER (string_place);				\
+									\
+    DEBUG_PRINT2 ("  Pushing failure id: %u\n", failure_id);		\
+    DEBUG_PUSH (failure_id);						\
+  } while (0)
+
+/* This is the number of items that are pushed and popped on the stack
+   for each register.  */
+#define NUM_REG_ITEMS  3
+
+/* Individual items aside from the registers.  */
+#ifdef DEBUG
+#define NUM_NONREG_ITEMS 5 /* Includes failure point id.  */
+#else
+#define NUM_NONREG_ITEMS 4
+#endif
+
+/* We push at most this many items on the stack.  */
+#define MAX_FAILURE_ITEMS ((num_regs - 1) * NUM_REG_ITEMS + NUM_NONREG_ITEMS)
+
+/* We actually push this many items.  */
+#define NUM_FAILURE_ITEMS						\
+  ((highest_active_reg - lowest_active_reg + 1) * NUM_REG_ITEMS 	\
+    + NUM_NONREG_ITEMS)
+
+/* How many items can still be added to the stack without overflowing it.  */
+#define REMAINING_AVAIL_SLOTS ((fail_stack).size - (fail_stack).avail)
+
+
+/* Pops what PUSH_FAIL_STACK pushes.
+
+   We restore into the parameters, all of which should be lvalues:
+     STR -- the saved data position.
+     PAT -- the saved pattern position.
+     LOW_REG, HIGH_REG -- the highest and lowest active registers.
+     REGSTART, REGEND -- arrays of string positions.
+     REG_INFO -- array of information about each subexpression.
+   
+   Also assumes the variables `fail_stack' and (if debugging), `bufp',
+   `pend', `string1', `size1', `string2', and `size2'.  */
+
+#define POP_FAILURE_POINT(str, pat, low_reg, high_reg, regstart, regend, reg_info)\
+{									\
+  DEBUG_STATEMENT (fail_stack_elt_t failure_id;)			\
+  int this_reg;								\
+  const unsigned char *string_temp;					\
+									\
+  assert (!FAIL_STACK_EMPTY ());					\
+									\
+  /* Remove failure points and point to how many regs pushed.  */	\
+  DEBUG_PRINT1 ("POP_FAILURE_POINT:\n");				\
+  DEBUG_PRINT2 ("  Before pop, next avail: %d\n", fail_stack.avail);	\
+  DEBUG_PRINT2 ("                    size: %d\n", fail_stack.size);	\
+									\
+  assert (fail_stack.avail >= NUM_NONREG_ITEMS);			\
+									\
+  DEBUG_POP (&failure_id);						\
+  DEBUG_PRINT2 ("  Popping failure id: %u\n", failure_id);		\
+									\
+  /* If the saved string location is NULL, it came from an		\
+     on_failure_keep_string_jump opcode, and we want to throw away the	\
+     saved NULL, thus retaining our current position in the string.  */	\
+  string_temp = POP_FAILURE_POINTER ();					\
+  if (string_temp != NULL)						\
+    str = (const char *) string_temp;					\
+									\
+  DEBUG_PRINT2 ("  Popping string 0x%x: `", str);			\
+  DEBUG_PRINT_DOUBLE_STRING (str, string1, size1, string2, size2);	\
+  DEBUG_PRINT1 ("'\n");							\
+									\
+  pat = (unsigned char *) POP_FAILURE_POINTER ();			\
+  DEBUG_PRINT2 ("  Popping pattern 0x%x: ", pat);			\
+  DEBUG_PRINT_COMPILED_PATTERN (bufp, pat, pend);			\
+									\
+  /* Restore register info.  */						\
+  high_reg = (unsigned) POP_FAILURE_INT ();				\
+  DEBUG_PRINT2 ("  Popping high active reg: %d\n", high_reg);		\
+									\
+  low_reg = (unsigned) POP_FAILURE_INT ();				\
+  DEBUG_PRINT2 ("  Popping  low active reg: %d\n", low_reg);		\
+									\
+  for (this_reg = high_reg; this_reg >= low_reg; this_reg--)		\
+    {									\
+      DEBUG_PRINT2 ("    Popping reg: %d\n", this_reg);			\
+									\
+      reg_info[this_reg].word = POP_FAILURE_ELT ();			\
+      DEBUG_PRINT2 ("      info: 0x%x\n", reg_info[this_reg]);		\
+									\
+      regend[this_reg] = (const char *) POP_FAILURE_POINTER ();		\
+      DEBUG_PRINT2 ("      end: 0x%x\n", regend[this_reg]);		\
+									\
+      regstart[this_reg] = (const char *) POP_FAILURE_POINTER ();	\
+      DEBUG_PRINT2 ("      start: 0x%x\n", regstart[this_reg]);		\
+    }									\
+									\
+  set_regs_matched_done = 0;						\
+  DEBUG_STATEMENT (nfailure_points_popped++);				\
+} /* POP_FAILURE_POINT */
+
+
+
+
+/* Structure for per-register (a.k.a. per-group) information.
+   Other register information, such as the
+   starting and ending positions (which are addresses), and the list of
+   inner groups (which is a bits list) are maintained in separate
+   variables.  
+   
+   We are making a (strictly speaking) nonportable assumption here: that
+   the compiler will pack our bit fields into something that fits into
+   the type of `word', i.e., is something that fits into one item on the
+   failure stack.  */
+
+typedef union
+{
+  fail_stack_elt_t word;
+  struct
+  {
+      /* This field is one if this group can match the empty string,
+         zero if not.  If not yet determined,  `MATCH_NULL_UNSET_VALUE'.  */
+#define MATCH_NULL_UNSET_VALUE 3
+    unsigned match_null_string_p : 2;
+    unsigned is_active : 1;
+    unsigned matched_something : 1;
+    unsigned ever_matched_something : 1;
+  } bits;
+} register_info_type;
+
+#define REG_MATCH_NULL_STRING_P(R)  ((R).bits.match_null_string_p)
+#define IS_ACTIVE(R)  ((R).bits.is_active)
+#define MATCHED_SOMETHING(R)  ((R).bits.matched_something)
+#define EVER_MATCHED_SOMETHING(R)  ((R).bits.ever_matched_something)
+
+
+/* Call this when have matched a real character; it sets `matched' flags
+   for the subexpressions which we are currently inside.  Also records
+   that those subexprs have matched.  */
+#define SET_REGS_MATCHED()						\
+  do									\
+    {									\
+      if (!set_regs_matched_done)					\
+	{								\
+	  unsigned r;							\
+	  set_regs_matched_done = 1;					\
+	  for (r = lowest_active_reg; r <= highest_active_reg; r++)	\
+	    {								\
+	      MATCHED_SOMETHING (reg_info[r])				\
+		= EVER_MATCHED_SOMETHING (reg_info[r])			\
+		= 1;							\
+	    }								\
+	}								\
+    }									\
+  while (0)
+
+/* Registers are set to a sentinel when they haven't yet matched.  */
+static char reg_unset_dummy;
+#define REG_UNSET_VALUE (&reg_unset_dummy)
+#define REG_UNSET(e) ((e) == REG_UNSET_VALUE)
+
+
+/* Subroutine declarations and macros for regex_compile.  */
+
+static void store_op1 (), store_op2 ();
+static void insert_op1 (), insert_op2 ();
+static boolean at_begline_loc_p (), at_endline_loc_p ();
+static boolean group_in_compile_stack ();
+static reg_errcode_t compile_range ();
+
+/* Fetch the next character in the uncompiled pattern---translating it 
+   if necessary.  Also cast from a signed character in the constant
+   string passed to us by the user to an unsigned char that we can use
+   as an array index (in, e.g., `translate').  */
+#define PATFETCH(c)							\
+  do {if (p == pend) return REG_EEND;					\
+    c = (unsigned char) *p++;						\
+    if (translate) c = translate[c]; 					\
+  } while (0)
+
+/* Fetch the next character in the uncompiled pattern, with no
+   translation.  */
+#define PATFETCH_RAW(c)							\
+  do {if (p == pend) return REG_EEND;					\
+    c = (unsigned char) *p++; 						\
+  } while (0)
+
+/* Go backwards one character in the pattern.  */
+#define PATUNFETCH p--
+
+
+/* If `translate' is non-null, return translate[D], else just D.  We
+   cast the subscript to translate because some data is declared as
+   `char *', to avoid warnings when a string constant is passed.  But
+   when we use a character as a subscript we must make it unsigned.  */
+#define TRANSLATE(d) (translate ? translate[(unsigned char) (d)] : (d))
+
+
+/* Macros for outputting the compiled pattern into `buffer'.  */
+
+/* If the buffer isn't allocated when it comes in, use this.  */
+#define INIT_BUF_SIZE  32
+
+/* Make sure we have at least N more bytes of space in buffer.  */
+#define GET_BUFFER_SPACE(n)						\
+    while (b - bufp->buffer + (n) > bufp->allocated)			\
+      EXTEND_BUFFER ()
+
+/* Make sure we have one more byte of buffer space and then add C to it.  */
+#define BUF_PUSH(c)							\
+  do {									\
+    GET_BUFFER_SPACE (1);						\
+    *b++ = (unsigned char) (c);						\
+  } while (0)
+
+
+/* Ensure we have two more bytes of buffer space and then append C1 and C2.  */
+#define BUF_PUSH_2(c1, c2)						\
+  do {									\
+    GET_BUFFER_SPACE (2);						\
+    *b++ = (unsigned char) (c1);					\
+    *b++ = (unsigned char) (c2);					\
+  } while (0)
+
+
+/* As with BUF_PUSH_2, except for three bytes.  */
+#define BUF_PUSH_3(c1, c2, c3)						\
+  do {									\
+    GET_BUFFER_SPACE (3);						\
+    *b++ = (unsigned char) (c1);					\
+    *b++ = (unsigned char) (c2);					\
+    *b++ = (unsigned char) (c3);					\
+  } while (0)
+
+
+/* Store a jump with opcode OP at LOC to location TO.  We store a
+   relative address offset by the three bytes the jump itself occupies.  */
+#define STORE_JUMP(op, loc, to) \
+  store_op1 (op, loc, (to) - (loc) - 3)
+
+/* Likewise, for a two-argument jump.  */
+#define STORE_JUMP2(op, loc, to, arg) \
+  store_op2 (op, loc, (to) - (loc) - 3, arg)
+
+/* Like `STORE_JUMP', but for inserting.  Assume `b' is the buffer end.  */
+#define INSERT_JUMP(op, loc, to) \
+  insert_op1 (op, loc, (to) - (loc) - 3, b)
+
+/* Like `STORE_JUMP2', but for inserting.  Assume `b' is the buffer end.  */
+#define INSERT_JUMP2(op, loc, to, arg) \
+  insert_op2 (op, loc, (to) - (loc) - 3, arg, b)
+
+
+/* This is not an arbitrary limit: the arguments which represent offsets
+   into the pattern are two bytes long.  So if 2^16 bytes turns out to
+   be too small, many things would have to change.  */
+#define MAX_BUF_SIZE (1L << 16)
+
+
+/* Extend the buffer by twice its current size via realloc and
+   reset the pointers that pointed into the old block to point to the
+   correct places in the new one.  If extending the buffer results in it
+   being larger than MAX_BUF_SIZE, then flag memory exhausted.  */
+#define EXTEND_BUFFER()							\
+  do { 									\
+    unsigned char *old_buffer = bufp->buffer;				\
+    if (bufp->allocated == MAX_BUF_SIZE) 				\
+      return REG_ESIZE;							\
+    bufp->allocated <<= 1;						\
+    if (bufp->allocated > MAX_BUF_SIZE)					\
+      bufp->allocated = MAX_BUF_SIZE; 					\
+    bufp->buffer = (unsigned char *) realloc (bufp->buffer, bufp->allocated);\
+    if (bufp->buffer == NULL)						\
+      return REG_ESPACE;						\
+    /* If the buffer moved, move all the pointers into it.  */		\
+    if (old_buffer != bufp->buffer)					\
+      {									\
+        b = (b - old_buffer) + bufp->buffer;				\
+        begalt = (begalt - old_buffer) + bufp->buffer;			\
+        if (fixup_alt_jump)						\
+          fixup_alt_jump = (fixup_alt_jump - old_buffer) + bufp->buffer;\
+        if (laststart)							\
+          laststart = (laststart - old_buffer) + bufp->buffer;		\
+        if (pending_exact)						\
+          pending_exact = (pending_exact - old_buffer) + bufp->buffer;	\
+      }									\
+  } while (0)
+
+
+/* Since we have one byte reserved for the register number argument to
+   {start,stop}_memory, the maximum number of groups we can report
+   things about is what fits in that byte.  */
+#define MAX_REGNUM 255
+
+/* But patterns can have more than `MAX_REGNUM' registers.  We just
+   ignore the excess.  */
+typedef unsigned regnum_t;
+
+
+/* Macros for the compile stack.  */
+
+/* Since offsets can go either forwards or backwards, this type needs to
+   be able to hold values from -(MAX_BUF_SIZE - 1) to MAX_BUF_SIZE - 1.  */
+typedef int pattern_offset_t;
+
+typedef struct
+{
+  pattern_offset_t begalt_offset;
+  pattern_offset_t fixup_alt_jump;
+  pattern_offset_t inner_group_offset;
+  pattern_offset_t laststart_offset;  
+  regnum_t regnum;
+} compile_stack_elt_t;
+
+
+typedef struct
+{
+  compile_stack_elt_t *stack;
+  unsigned size;
+  unsigned avail;			/* Offset of next open position.  */
+} compile_stack_type;
+
+
+#define INIT_COMPILE_STACK_SIZE 32
+
+#define COMPILE_STACK_EMPTY  (compile_stack.avail == 0)
+#define COMPILE_STACK_FULL  (compile_stack.avail == compile_stack.size)
+
+/* The next available element.  */
+#define COMPILE_STACK_TOP (compile_stack.stack[compile_stack.avail])
+
+
+/* Set the bit for character C in a list.  */
+#define SET_LIST_BIT(c)                               \
+  (b[((unsigned char) (c)) / BYTEWIDTH]               \
+   |= 1 << (((unsigned char) c) % BYTEWIDTH))
+
+
+/* Get the next unsigned number in the uncompiled pattern.  */
+#define GET_UNSIGNED_NUMBER(num) 					\
+  { if (p != pend)							\
+     {									\
+       PATFETCH (c); 							\
+       while (ISDIGIT (c)) 						\
+         { 								\
+           if (num < 0)							\
+              num = 0;							\
+           num = num * 10 + c - '0'; 					\
+           if (p == pend) 						\
+              break; 							\
+           PATFETCH (c);						\
+         } 								\
+       } 								\
+    }		
+
+#define CHAR_CLASS_MAX_LENGTH  6 /* Namely, `xdigit'.  */
+
+#define IS_CHAR_CLASS(string)						\
+   (STREQ (string, "alpha") || STREQ (string, "upper")			\
+    || STREQ (string, "lower") || STREQ (string, "digit")		\
+    || STREQ (string, "alnum") || STREQ (string, "xdigit")		\
+    || STREQ (string, "space") || STREQ (string, "print")		\
+    || STREQ (string, "punct") || STREQ (string, "graph")		\
+    || STREQ (string, "cntrl") || STREQ (string, "blank"))
+
+
+#ifndef MATCH_MAY_ALLOCATE
+
+/* If we cannot allocate large objects within re_match_2_internal,
+   we make the fail stack and register vectors global.
+   The fail stack, we grow to the maximum size when a regexp
+   is compiled.
+   The register vectors, we adjust in size each time we
+   compile a regexp, according to the number of registers it needs.  */
+
+static fail_stack_type fail_stack;
+
+/* Size with which the following vectors are currently allocated.
+   That is so we can make them bigger as needed,
+   but never make them smaller.  */
+static int regs_allocated_size;
+
+static const char **     regstart, **     regend;
+static const char ** old_regstart, ** old_regend;
+static const char **best_regstart, **best_regend;
+static register_info_type *reg_info; 
+static const char **reg_dummy;
+static register_info_type *reg_info_dummy;
+
+/* Make the register vectors big enough for NUM_REGS registers,
+   but don't make them smaller.  */
+
+static
+regex_grow_registers (num_regs)
+     int num_regs;
+{
+  if (num_regs > regs_allocated_size)
+    {
+      RETALLOC_IF (regstart,	 num_regs, const char *);
+      RETALLOC_IF (regend,	 num_regs, const char *);
+      RETALLOC_IF (old_regstart, num_regs, const char *);
+      RETALLOC_IF (old_regend,	 num_regs, const char *);
+      RETALLOC_IF (best_regstart, num_regs, const char *);
+      RETALLOC_IF (best_regend,	 num_regs, const char *);
+      RETALLOC_IF (reg_info,	 num_regs, register_info_type);
+      RETALLOC_IF (reg_dummy,	 num_regs, const char *);
+      RETALLOC_IF (reg_info_dummy, num_regs, register_info_type);
+
+      regs_allocated_size = num_regs;
+    }
+}
+
+#endif /* not MATCH_MAY_ALLOCATE */
+
+
+/* `regex_compile' compiles PATTERN (of length SIZE) according to SYNTAX.
+   Returns one of error codes defined in `regex.h', or zero for success.
+
+   Assumes the `allocated' (and perhaps `buffer') and `translate'
+   fields are set in BUFP on entry.
+
+   If it succeeds, results are put in BUFP (if it returns an error, the
+   contents of BUFP are undefined):
+     `buffer' is the compiled pattern;
+     `syntax' is set to SYNTAX;
+     `used' is set to the length of the compiled pattern;
+     `fastmap_accurate' is zero;
+     `re_nsub' is the number of subexpressions in PATTERN;
+     `not_bol' and `not_eol' are zero;
+   
+   The `fastmap' and `newline_anchor' fields are neither
+   examined nor set.  */
+
+/* Return, freeing storage we allocated.  */
+#define FREE_STACK_RETURN(value)		\
+  return (free (compile_stack.stack), value)
+
+static reg_errcode_t
+regex_compile (pattern, size, syntax, bufp)
+     const char *pattern;
+     int size;
+     reg_syntax_t syntax;
+     struct re_pattern_buffer *bufp;
+{
+  /* We fetch characters from PATTERN here.  Even though PATTERN is
+     `char *' (i.e., signed), we declare these variables as unsigned, so
+     they can be reliably used as array indices.  */
+  register unsigned char c, c1;
+  
+  /* A random temporary spot in PATTERN.  */
+  const char *p1;
+
+  /* Points to the end of the buffer, where we should append.  */
+  register unsigned char *b;
+  
+  /* Keeps track of unclosed groups.  */
+  compile_stack_type compile_stack;
+
+  /* Points to the current (ending) position in the pattern.  */
+  const char *p = pattern;
+  const char *pend = pattern + size;
+  
+  /* How to translate the characters in the pattern.  */
+  char *translate = bufp->translate;
+
+  /* Address of the count-byte of the most recently inserted `exactn'
+     command.  This makes it possible to tell if a new exact-match
+     character can be added to that command or if the character requires
+     a new `exactn' command.  */
+  unsigned char *pending_exact = 0;
+
+  /* Address of start of the most recently finished expression.
+     This tells, e.g., postfix * where to find the start of its
+     operand.  Reset at the beginning of groups and alternatives.  */
+  unsigned char *laststart = 0;
+
+  /* Address of beginning of regexp, or inside of last group.  */
+  unsigned char *begalt;
+
+  /* Place in the uncompiled pattern (i.e., the {) to
+     which to go back if the interval is invalid.  */
+  const char *beg_interval;
+                
+  /* Address of the place where a forward jump should go to the end of
+     the containing expression.  Each alternative of an `or' -- except the
+     last -- ends with a forward jump of this sort.  */
+  unsigned char *fixup_alt_jump = 0;
+
+  /* Counts open-groups as they are encountered.  Remembered for the
+     matching close-group on the compile stack, so the same register
+     number is put in the stop_memory as the start_memory.  */
+  regnum_t regnum = 0;
+
+#ifdef DEBUG
+  DEBUG_PRINT1 ("\nCompiling pattern: ");
+  if (debug)
+    {
+      unsigned debug_count;
+      
+      for (debug_count = 0; debug_count < size; debug_count++)
+        putchar (pattern[debug_count]);
+      putchar ('\n');
+    }
+#endif /* DEBUG */
+
+  /* Initialize the compile stack.  */
+  compile_stack.stack = TALLOC (INIT_COMPILE_STACK_SIZE, compile_stack_elt_t);
+  if (compile_stack.stack == NULL)
+    return REG_ESPACE;
+
+  compile_stack.size = INIT_COMPILE_STACK_SIZE;
+  compile_stack.avail = 0;
+
+  /* Initialize the pattern buffer.  */
+  bufp->syntax = syntax;
+  bufp->fastmap_accurate = 0;
+  bufp->not_bol = bufp->not_eol = 0;
+
+  /* Set `used' to zero, so that if we return an error, the pattern
+     printer (for debugging) will think there's no pattern.  We reset it
+     at the end.  */
+  bufp->used = 0;
+  
+  /* Always count groups, whether or not bufp->no_sub is set.  */
+  bufp->re_nsub = 0;				
+
+#if !defined (emacs) && !defined (SYNTAX_TABLE)
+  /* Initialize the syntax table.  */
+   init_syntax_once ();
+#endif
+
+  if (bufp->allocated == 0)
+    {
+      if (bufp->buffer)
+	{ /* If zero allocated, but buffer is non-null, try to realloc
+             enough space.  This loses if buffer's address is bogus, but
+             that is the user's responsibility.  */
+          RETALLOC (bufp->buffer, INIT_BUF_SIZE, unsigned char);
+        }
+      else
+        { /* Caller did not allocate a buffer.  Do it for them.  */
+          bufp->buffer = TALLOC (INIT_BUF_SIZE, unsigned char);
+        }
+      if (!bufp->buffer) FREE_STACK_RETURN (REG_ESPACE);
+
+      bufp->allocated = INIT_BUF_SIZE;
+    }
+
+  begalt = b = bufp->buffer;
+
+  /* Loop through the uncompiled pattern until we're at the end.  */
+  while (p != pend)
+    {
+      PATFETCH (c);
+
+      switch (c)
+        {
+        case '^':
+          {
+            if (   /* If at start of pattern, it's an operator.  */
+                   p == pattern + 1
+                   /* If context independent, it's an operator.  */
+                || syntax & RE_CONTEXT_INDEP_ANCHORS
+                   /* Otherwise, depends on what's come before.  */
+                || at_begline_loc_p (pattern, p, syntax))
+              BUF_PUSH (begline);
+            else
+              goto normal_char;
+          }
+          break;
+
+
+        case '$':
+          {
+            if (   /* If at end of pattern, it's an operator.  */
+                   p == pend 
+                   /* If context independent, it's an operator.  */
+                || syntax & RE_CONTEXT_INDEP_ANCHORS
+                   /* Otherwise, depends on what's next.  */
+                || at_endline_loc_p (p, pend, syntax))
+               BUF_PUSH (endline);
+             else
+               goto normal_char;
+           }
+           break;
+
+
+	case '+':
+        case '?':
+          if ((syntax & RE_BK_PLUS_QM)
+              || (syntax & RE_LIMITED_OPS))
+            goto normal_char;
+        handle_plus:
+        case '*':
+          /* If there is no previous pattern... */
+          if (!laststart)
+            {
+              if (syntax & RE_CONTEXT_INVALID_OPS)
+                FREE_STACK_RETURN (REG_BADRPT);
+              else if (!(syntax & RE_CONTEXT_INDEP_OPS))
+                goto normal_char;
+            }
+
+          {
+            /* Are we optimizing this jump?  */
+            boolean keep_string_p = false;
+            
+            /* 1 means zero (many) matches is allowed.  */
+            char zero_times_ok = 0, many_times_ok = 0;
+
+            /* If there is a sequence of repetition chars, collapse it
+               down to just one (the right one).  We can't combine
+               interval operators with these because of, e.g., `a{2}*',
+               which should only match an even number of `a's.  */
+
+            for (;;)
+              {
+                zero_times_ok |= c != '+';
+                many_times_ok |= c != '?';
+
+                if (p == pend)
+                  break;
+
+                PATFETCH (c);
+
+                if (c == '*'
+                    || (!(syntax & RE_BK_PLUS_QM) && (c == '+' || c == '?')))
+                  ;
+
+                else if (syntax & RE_BK_PLUS_QM  &&  c == '\\')
+                  {
+                    if (p == pend) FREE_STACK_RETURN (REG_EESCAPE);
+
+                    PATFETCH (c1);
+                    if (!(c1 == '+' || c1 == '?'))
+                      {
+                        PATUNFETCH;
+                        PATUNFETCH;
+                        break;
+                      }
+
+                    c = c1;
+                  }
+                else
+                  {
+                    PATUNFETCH;
+                    break;
+                  }
+
+                /* If we get here, we found another repeat character.  */
+               }
+
+            /* Star, etc. applied to an empty pattern is equivalent
+               to an empty pattern.  */
+            if (!laststart)  
+              break;
+
+            /* Now we know whether or not zero matches is allowed
+               and also whether or not two or more matches is allowed.  */
+            if (many_times_ok)
+              { /* More than one repetition is allowed, so put in at the
+                   end a backward relative jump from `b' to before the next
+                   jump we're going to put in below (which jumps from
+                   laststart to after this jump).  
+
+                   But if we are at the `*' in the exact sequence `.*\n',
+                   insert an unconditional jump backwards to the .,
+                   instead of the beginning of the loop.  This way we only
+                   push a failure point once, instead of every time
+                   through the loop.  */
+                assert (p - 1 > pattern);
+
+                /* Allocate the space for the jump.  */
+                GET_BUFFER_SPACE (3);
+
+                /* We know we are not at the first character of the pattern,
+                   because laststart was nonzero.  And we've already
+                   incremented `p', by the way, to be the character after
+                   the `*'.  Do we have to do something analogous here
+                   for null bytes, because of RE_DOT_NOT_NULL?  */
+                if (TRANSLATE (*(p - 2)) == TRANSLATE ('.')
+		    && zero_times_ok
+                    && p < pend && TRANSLATE (*p) == TRANSLATE ('\n')
+                    && !(syntax & RE_DOT_NEWLINE))
+                  { /* We have .*\n.  */
+                    STORE_JUMP (jump, b, laststart);
+                    keep_string_p = true;
+                  }
+                else
+                  /* Anything else.  */
+                  STORE_JUMP (maybe_pop_jump, b, laststart - 3);
+
+                /* We've added more stuff to the buffer.  */
+                b += 3;
+              }
+
+            /* On failure, jump from laststart to b + 3, which will be the
+               end of the buffer after this jump is inserted.  */
+            GET_BUFFER_SPACE (3);
+            INSERT_JUMP (keep_string_p ? on_failure_keep_string_jump
+                                       : on_failure_jump,
+                         laststart, b + 3);
+            pending_exact = 0;
+            b += 3;
+
+            if (!zero_times_ok)
+              {
+                /* At least one repetition is required, so insert a
+                   `dummy_failure_jump' before the initial
+                   `on_failure_jump' instruction of the loop. This
+                   effects a skip over that instruction the first time
+                   we hit that loop.  */
+                GET_BUFFER_SPACE (3);
+                INSERT_JUMP (dummy_failure_jump, laststart, laststart + 6);
+                b += 3;
+              }
+            }
+	  break;
+
+
+	case '.':
+          laststart = b;
+          BUF_PUSH (anychar);
+          break;
+
+
+        case '[':
+          {
+            boolean had_char_class = false;
+
+            if (p == pend) FREE_STACK_RETURN (REG_EBRACK);
+
+            /* Ensure that we have enough space to push a charset: the
+               opcode, the length count, and the bitset; 34 bytes in all.  */
+	    GET_BUFFER_SPACE (34);
+
+            laststart = b;
+
+            /* We test `*p == '^' twice, instead of using an if
+               statement, so we only need one BUF_PUSH.  */
+            BUF_PUSH (*p == '^' ? charset_not : charset); 
+            if (*p == '^')
+              p++;
+
+            /* Remember the first position in the bracket expression.  */
+            p1 = p;
+
+            /* Push the number of bytes in the bitmap.  */
+            BUF_PUSH ((1 << BYTEWIDTH) / BYTEWIDTH);
+
+            /* Clear the whole map.  */
+            bzero (b, (1 << BYTEWIDTH) / BYTEWIDTH);
+
+            /* charset_not matches newline according to a syntax bit.  */
+            if ((re_opcode_t) b[-2] == charset_not
+                && (syntax & RE_HAT_LISTS_NOT_NEWLINE))
+              SET_LIST_BIT ('\n');
+
+            /* Read in characters and ranges, setting map bits.  */
+            for (;;)
+              {
+                if (p == pend) FREE_STACK_RETURN (REG_EBRACK);
+
+                PATFETCH (c);
+
+                /* \ might escape characters inside [...] and [^...].  */
+                if ((syntax & RE_BACKSLASH_ESCAPE_IN_LISTS) && c == '\\')
+                  {
+                    if (p == pend) FREE_STACK_RETURN (REG_EESCAPE);
+
+                    PATFETCH (c1);
+                    SET_LIST_BIT (c1);
+                    continue;
+                  }
+
+                /* Could be the end of the bracket expression.  If it's
+                   not (i.e., when the bracket expression is `[]' so
+                   far), the ']' character bit gets set way below.  */
+                if (c == ']' && p != p1 + 1)
+                  break;
+
+                /* Look ahead to see if it's a range when the last thing
+                   was a character class.  */
+                if (had_char_class && c == '-' && *p != ']')
+                  FREE_STACK_RETURN (REG_ERANGE);
+
+                /* Look ahead to see if it's a range when the last thing
+                   was a character: if this is a hyphen not at the
+                   beginning or the end of a list, then it's the range
+                   operator.  */
+                if (c == '-' 
+                    && !(p - 2 >= pattern && p[-2] == '[') 
+                    && !(p - 3 >= pattern && p[-3] == '[' && p[-2] == '^')
+                    && *p != ']')
+                  {
+                    reg_errcode_t ret
+                      = compile_range (&p, pend, translate, syntax, b);
+                    if (ret != REG_NOERROR) FREE_STACK_RETURN (ret);
+                  }
+
+                else if (p[0] == '-' && p[1] != ']')
+                  { /* This handles ranges made up of characters only.  */
+                    reg_errcode_t ret;
+
+		    /* Move past the `-'.  */
+                    PATFETCH (c1);
+                    
+                    ret = compile_range (&p, pend, translate, syntax, b);
+                    if (ret != REG_NOERROR) FREE_STACK_RETURN (ret);
+                  }
+
+                /* See if we're at the beginning of a possible character
+                   class.  */
+
+                else if (syntax & RE_CHAR_CLASSES && c == '[' && *p == ':')
+                  { /* Leave room for the null.  */
+                    char str[CHAR_CLASS_MAX_LENGTH + 1];
+
+                    PATFETCH (c);
+                    c1 = 0;
+
+                    /* If pattern is `[[:'.  */
+                    if (p == pend) FREE_STACK_RETURN (REG_EBRACK);
+
+                    for (;;)
+                      {
+                        PATFETCH (c);
+                        if (c == ':' || c == ']' || p == pend
+                            || c1 == CHAR_CLASS_MAX_LENGTH)
+                          break;
+                        str[c1++] = c;
+                      }
+                    str[c1] = '\0';
+
+                    /* If isn't a word bracketed by `[:' and:`]':
+                       undo the ending character, the letters, and leave 
+                       the leading `:' and `[' (but set bits for them).  */
+                    if (c == ':' && *p == ']')
+                      {
+                        int ch;
+                        boolean is_alnum = STREQ (str, "alnum");
+                        boolean is_alpha = STREQ (str, "alpha");
+                        boolean is_blank = STREQ (str, "blank");
+                        boolean is_cntrl = STREQ (str, "cntrl");
+                        boolean is_digit = STREQ (str, "digit");
+                        boolean is_graph = STREQ (str, "graph");
+                        boolean is_lower = STREQ (str, "lower");
+                        boolean is_print = STREQ (str, "print");
+                        boolean is_punct = STREQ (str, "punct");
+                        boolean is_space = STREQ (str, "space");
+                        boolean is_upper = STREQ (str, "upper");
+                        boolean is_xdigit = STREQ (str, "xdigit");
+                        
+                        if (!IS_CHAR_CLASS (str))
+			  FREE_STACK_RETURN (REG_ECTYPE);
+
+                        /* Throw away the ] at the end of the character
+                           class.  */
+                        PATFETCH (c);					
+
+                        if (p == pend) FREE_STACK_RETURN (REG_EBRACK);
+
+                        for (ch = 0; ch < 1 << BYTEWIDTH; ch++)
+                          {
+			    /* This was split into 3 if's to
+			       avoid an arbitrary limit in some compiler.  */
+                            if (   (is_alnum  && ISALNUM (ch))
+                                || (is_alpha  && ISALPHA (ch))
+                                || (is_blank  && ISBLANK (ch))
+                                || (is_cntrl  && ISCNTRL (ch)))
+			      SET_LIST_BIT (ch);
+			    if (   (is_digit  && ISDIGIT (ch))
+                                || (is_graph  && ISGRAPH (ch))
+                                || (is_lower  && ISLOWER (ch))
+                                || (is_print  && ISPRINT (ch)))
+			      SET_LIST_BIT (ch);
+			    if (   (is_punct  && ISPUNCT (ch))
+                                || (is_space  && ISSPACE (ch))
+                                || (is_upper  && ISUPPER (ch))
+                                || (is_xdigit && ISXDIGIT (ch)))
+			      SET_LIST_BIT (ch);
+                          }
+                        had_char_class = true;
+                      }
+                    else
+                      {
+                        c1++;
+                        while (c1--)    
+                          PATUNFETCH;
+                        SET_LIST_BIT ('[');
+                        SET_LIST_BIT (':');
+                        had_char_class = false;
+                      }
+                  }
+                else
+                  {
+                    had_char_class = false;
+                    SET_LIST_BIT (c);
+                  }
+              }
+
+            /* Discard any (non)matching list bytes that are all 0 at the
+               end of the map.  Decrease the map-length byte too.  */
+            while ((int) b[-1] > 0 && b[b[-1] - 1] == 0) 
+              b[-1]--; 
+            b += b[-1];
+          }
+          break;
+
+
+	case '(':
+          if (syntax & RE_NO_BK_PARENS)
+            goto handle_open;
+          else
+            goto normal_char;
+
+
+        case ')':
+          if (syntax & RE_NO_BK_PARENS)
+            goto handle_close;
+          else
+            goto normal_char;
+
+
+        case '\n':
+          if (syntax & RE_NEWLINE_ALT)
+            goto handle_alt;
+          else
+            goto normal_char;
+
+
+	case '|':
+          if (syntax & RE_NO_BK_VBAR)
+            goto handle_alt;
+          else
+            goto normal_char;
+
+
+        case '{':
+           if (syntax & RE_INTERVALS && syntax & RE_NO_BK_BRACES)
+             goto handle_interval;
+           else
+             goto normal_char;
+
+
+        case '\\':
+          if (p == pend) FREE_STACK_RETURN (REG_EESCAPE);
+
+          /* Do not translate the character after the \, so that we can
+             distinguish, e.g., \B from \b, even if we normally would
+             translate, e.g., B to b.  */
+          PATFETCH_RAW (c);
+
+          switch (c)
+            {
+            case '(':
+              if (syntax & RE_NO_BK_PARENS)
+                goto normal_backslash;
+
+            handle_open:
+              bufp->re_nsub++;
+              regnum++;
+
+              if (COMPILE_STACK_FULL)
+                { 
+                  RETALLOC (compile_stack.stack, compile_stack.size << 1,
+                            compile_stack_elt_t);
+                  if (compile_stack.stack == NULL) return REG_ESPACE;
+
+                  compile_stack.size <<= 1;
+                }
+
+              /* These are the values to restore when we hit end of this
+                 group.  They are all relative offsets, so that if the
+                 whole pattern moves because of realloc, they will still
+                 be valid.  */
+              COMPILE_STACK_TOP.begalt_offset = begalt - bufp->buffer;
+              COMPILE_STACK_TOP.fixup_alt_jump 
+                = fixup_alt_jump ? fixup_alt_jump - bufp->buffer + 1 : 0;
+              COMPILE_STACK_TOP.laststart_offset = b - bufp->buffer;
+              COMPILE_STACK_TOP.regnum = regnum;
+
+              /* We will eventually replace the 0 with the number of
+                 groups inner to this one.  But do not push a
+                 start_memory for groups beyond the last one we can
+                 represent in the compiled pattern.  */
+              if (regnum <= MAX_REGNUM)
+                {
+                  COMPILE_STACK_TOP.inner_group_offset = b - bufp->buffer + 2;
+                  BUF_PUSH_3 (start_memory, regnum, 0);
+                }
+                
+              compile_stack.avail++;
+
+              fixup_alt_jump = 0;
+              laststart = 0;
+              begalt = b;
+	      /* If we've reached MAX_REGNUM groups, then this open
+		 won't actually generate any code, so we'll have to
+		 clear pending_exact explicitly.  */
+	      pending_exact = 0;
+              break;
+
+
+            case ')':
+              if (syntax & RE_NO_BK_PARENS) goto normal_backslash;
+
+              if (COMPILE_STACK_EMPTY)
+                if (syntax & RE_UNMATCHED_RIGHT_PAREN_ORD)
+                  goto normal_backslash;
+                else
+                  FREE_STACK_RETURN (REG_ERPAREN);
+
+            handle_close:
+              if (fixup_alt_jump)
+                { /* Push a dummy failure point at the end of the
+                     alternative for a possible future
+                     `pop_failure_jump' to pop.  See comments at
+                     `push_dummy_failure' in `re_match_2'.  */
+                  BUF_PUSH (push_dummy_failure);
+                  
+                  /* We allocated space for this jump when we assigned
+                     to `fixup_alt_jump', in the `handle_alt' case below.  */
+                  STORE_JUMP (jump_past_alt, fixup_alt_jump, b - 1);
+                }
+
+              /* See similar code for backslashed left paren above.  */
+              if (COMPILE_STACK_EMPTY)
+                if (syntax & RE_UNMATCHED_RIGHT_PAREN_ORD)
+                  goto normal_char;
+                else
+                  FREE_STACK_RETURN (REG_ERPAREN);
+
+              /* Since we just checked for an empty stack above, this
+                 ``can't happen''.  */
+              assert (compile_stack.avail != 0);
+              {
+                /* We don't just want to restore into `regnum', because
+                   later groups should continue to be numbered higher,
+                   as in `(ab)c(de)' -- the second group is #2.  */
+                regnum_t this_group_regnum;
+
+                compile_stack.avail--;		
+                begalt = bufp->buffer + COMPILE_STACK_TOP.begalt_offset;
+                fixup_alt_jump
+                  = COMPILE_STACK_TOP.fixup_alt_jump
+                    ? bufp->buffer + COMPILE_STACK_TOP.fixup_alt_jump - 1 
+                    : 0;
+                laststart = bufp->buffer + COMPILE_STACK_TOP.laststart_offset;
+                this_group_regnum = COMPILE_STACK_TOP.regnum;
+		/* If we've reached MAX_REGNUM groups, then this open
+		   won't actually generate any code, so we'll have to
+		   clear pending_exact explicitly.  */
+		pending_exact = 0;
+
+                /* We're at the end of the group, so now we know how many
+                   groups were inside this one.  */
+                if (this_group_regnum <= MAX_REGNUM)
+                  {
+                    unsigned char *inner_group_loc
+                      = bufp->buffer + COMPILE_STACK_TOP.inner_group_offset;
+                    
+                    *inner_group_loc = regnum - this_group_regnum;
+                    BUF_PUSH_3 (stop_memory, this_group_regnum,
+                                regnum - this_group_regnum);
+                  }
+              }
+              break;
+
+
+            case '|':					/* `\|'.  */
+              if (syntax & RE_LIMITED_OPS || syntax & RE_NO_BK_VBAR)
+                goto normal_backslash;
+            handle_alt:
+              if (syntax & RE_LIMITED_OPS)
+                goto normal_char;
+
+              /* Insert before the previous alternative a jump which
+                 jumps to this alternative if the former fails.  */
+              GET_BUFFER_SPACE (3);
+              INSERT_JUMP (on_failure_jump, begalt, b + 6);
+              pending_exact = 0;
+              b += 3;
+
+              /* The alternative before this one has a jump after it
+                 which gets executed if it gets matched.  Adjust that
+                 jump so it will jump to this alternative's analogous
+                 jump (put in below, which in turn will jump to the next
+                 (if any) alternative's such jump, etc.).  The last such
+                 jump jumps to the correct final destination.  A picture:
+                          _____ _____ 
+                          |   | |   |   
+                          |   v |   v 
+                         a | b   | c   
+
+                 If we are at `b', then fixup_alt_jump right now points to a
+                 three-byte space after `a'.  We'll put in the jump, set
+                 fixup_alt_jump to right after `b', and leave behind three
+                 bytes which we'll fill in when we get to after `c'.  */
+
+              if (fixup_alt_jump)
+                STORE_JUMP (jump_past_alt, fixup_alt_jump, b);
+
+              /* Mark and leave space for a jump after this alternative,
+                 to be filled in later either by next alternative or
+                 when know we're at the end of a series of alternatives.  */
+              fixup_alt_jump = b;
+              GET_BUFFER_SPACE (3);
+              b += 3;
+
+              laststart = 0;
+              begalt = b;
+              break;
+
+
+            case '{': 
+              /* If \{ is a literal.  */
+              if (!(syntax & RE_INTERVALS)
+                     /* If we're at `\{' and it's not the open-interval 
+                        operator.  */
+                  || ((syntax & RE_INTERVALS) && (syntax & RE_NO_BK_BRACES))
+                  || (p - 2 == pattern  &&  p == pend))
+                goto normal_backslash;
+
+            handle_interval:
+              {
+                /* If got here, then the syntax allows intervals.  */
+
+                /* At least (most) this many matches must be made.  */
+                int lower_bound = -1, upper_bound = -1;
+
+                beg_interval = p - 1;
+
+                if (p == pend)
+                  {
+                    if (syntax & RE_NO_BK_BRACES)
+                      goto unfetch_interval;
+                    else
+                      FREE_STACK_RETURN (REG_EBRACE);
+                  }
+
+                GET_UNSIGNED_NUMBER (lower_bound);
+
+                if (c == ',')
+                  {
+                    GET_UNSIGNED_NUMBER (upper_bound);
+                    if (upper_bound < 0) upper_bound = RE_DUP_MAX;
+                  }
+                else
+                  /* Interval such as `{1}' => match exactly once. */
+                  upper_bound = lower_bound;
+
+                if (lower_bound < 0 || upper_bound > RE_DUP_MAX
+                    || lower_bound > upper_bound)
+                  {
+                    if (syntax & RE_NO_BK_BRACES)
+                      goto unfetch_interval;
+                    else 
+                      FREE_STACK_RETURN (REG_BADBR);
+                  }
+
+                if (!(syntax & RE_NO_BK_BRACES)) 
+                  {
+                    if (c != '\\') FREE_STACK_RETURN (REG_EBRACE);
+
+                    PATFETCH (c);
+                  }
+
+                if (c != '}')
+                  {
+                    if (syntax & RE_NO_BK_BRACES)
+                      goto unfetch_interval;
+                    else 
+                      FREE_STACK_RETURN (REG_BADBR);
+                  }
+
+                /* We just parsed a valid interval.  */
+
+                /* If it's invalid to have no preceding re.  */
+                if (!laststart)
+                  {
+                    if (syntax & RE_CONTEXT_INVALID_OPS)
+                      FREE_STACK_RETURN (REG_BADRPT);
+                    else if (syntax & RE_CONTEXT_INDEP_OPS)
+                      laststart = b;
+                    else
+                      goto unfetch_interval;
+                  }
+
+                /* If the upper bound is zero, don't want to succeed at
+                   all; jump from `laststart' to `b + 3', which will be
+                   the end of the buffer after we insert the jump.  */
+                 if (upper_bound == 0)
+                   {
+                     GET_BUFFER_SPACE (3);
+                     INSERT_JUMP (jump, laststart, b + 3);
+                     b += 3;
+                   }
+
+                 /* Otherwise, we have a nontrivial interval.  When
+                    we're all done, the pattern will look like:
+                      set_number_at <jump count> <upper bound>
+                      set_number_at <succeed_n count> <lower bound>
+                      succeed_n <after jump addr> <succeed_n count>
+                      <body of loop>
+                      jump_n <succeed_n addr> <jump count>
+                    (The upper bound and `jump_n' are omitted if
+                    `upper_bound' is 1, though.)  */
+                 else 
+                   { /* If the upper bound is > 1, we need to insert
+                        more at the end of the loop.  */
+                     unsigned nbytes = 10 + (upper_bound > 1) * 10;
+
+                     GET_BUFFER_SPACE (nbytes);
+
+                     /* Initialize lower bound of the `succeed_n', even
+                        though it will be set during matching by its
+                        attendant `set_number_at' (inserted next),
+                        because `re_compile_fastmap' needs to know.
+                        Jump to the `jump_n' we might insert below.  */
+                     INSERT_JUMP2 (succeed_n, laststart,
+                                   b + 5 + (upper_bound > 1) * 5,
+                                   lower_bound);
+                     b += 5;
+
+                     /* Code to initialize the lower bound.  Insert 
+                        before the `succeed_n'.  The `5' is the last two
+                        bytes of this `set_number_at', plus 3 bytes of
+                        the following `succeed_n'.  */
+                     insert_op2 (set_number_at, laststart, 5, lower_bound, b);
+                     b += 5;
+
+                     if (upper_bound > 1)
+                       { /* More than one repetition is allowed, so
+                            append a backward jump to the `succeed_n'
+                            that starts this interval.
+                            
+                            When we've reached this during matching,
+                            we'll have matched the interval once, so
+                            jump back only `upper_bound - 1' times.  */
+                         STORE_JUMP2 (jump_n, b, laststart + 5,
+                                      upper_bound - 1);
+                         b += 5;
+
+                         /* The location we want to set is the second
+                            parameter of the `jump_n'; that is `b-2' as
+                            an absolute address.  `laststart' will be
+                            the `set_number_at' we're about to insert;
+                            `laststart+3' the number to set, the source
+                            for the relative address.  But we are
+                            inserting into the middle of the pattern --
+                            so everything is getting moved up by 5.
+                            Conclusion: (b - 2) - (laststart + 3) + 5,
+                            i.e., b - laststart.
+                            
+                            We insert this at the beginning of the loop
+                            so that if we fail during matching, we'll
+                            reinitialize the bounds.  */
+                         insert_op2 (set_number_at, laststart, b - laststart,
+                                     upper_bound - 1, b);
+                         b += 5;
+                       }
+                   }
+                pending_exact = 0;
+                beg_interval = NULL;
+              }
+              break;
+
+            unfetch_interval:
+              /* If an invalid interval, match the characters as literals.  */
+               assert (beg_interval);
+               p = beg_interval;
+               beg_interval = NULL;
+
+               /* normal_char and normal_backslash need `c'.  */
+               PATFETCH (c);	
+
+               if (!(syntax & RE_NO_BK_BRACES))
+                 {
+                   if (p > pattern  &&  p[-1] == '\\')
+                     goto normal_backslash;
+                 }
+               goto normal_char;
+
+#ifdef emacs
+            /* There is no way to specify the before_dot and after_dot
+               operators.  rms says this is ok.  --karl  */
+            case '=':
+              BUF_PUSH (at_dot);
+              break;
+
+            case 's':	
+              laststart = b;
+              PATFETCH (c);
+              BUF_PUSH_2 (syntaxspec, syntax_spec_code[c]);
+              break;
+
+            case 'S':
+              laststart = b;
+              PATFETCH (c);
+              BUF_PUSH_2 (notsyntaxspec, syntax_spec_code[c]);
+              break;
+#endif /* emacs */
+
+
+            case 'w':
+              laststart = b;
+              BUF_PUSH (wordchar);
+              break;
+
+
+            case 'W':
+              laststart = b;
+              BUF_PUSH (notwordchar);
+              break;
+
+
+            case '<':
+              BUF_PUSH (wordbeg);
+              break;
+
+            case '>':
+              BUF_PUSH (wordend);
+              break;
+
+            case 'b':
+              BUF_PUSH (wordbound);
+              break;
+
+            case 'B':
+              BUF_PUSH (notwordbound);
+              break;
+
+            case '`':
+              BUF_PUSH (begbuf);
+              break;
+
+            case '\'':
+              BUF_PUSH (endbuf);
+              break;
+
+            case '1': case '2': case '3': case '4': case '5':
+            case '6': case '7': case '8': case '9':
+              if (syntax & RE_NO_BK_REFS)
+                goto normal_char;
+
+              c1 = c - '0';
+
+              if (c1 > regnum)
+                FREE_STACK_RETURN (REG_ESUBREG);
+
+              /* Can't back reference to a subexpression if inside of it.  */
+              if (group_in_compile_stack (compile_stack, c1))
+                goto normal_char;
+
+              laststart = b;
+              BUF_PUSH_2 (duplicate, c1);
+              break;
+
+
+            case '+':
+            case '?':
+              if (syntax & RE_BK_PLUS_QM)
+                goto handle_plus;
+              else
+                goto normal_backslash;
+
+            default:
+            normal_backslash:
+              /* You might think it would be useful for \ to mean
+                 not to translate; but if we don't translate it
+                 it will never match anything.  */
+              c = TRANSLATE (c);
+              goto normal_char;
+            }
+          break;
+
+
+	default:
+        /* Expects the character in `c'.  */
+	normal_char:
+	      /* If no exactn currently being built.  */
+          if (!pending_exact 
+
+              /* If last exactn not at current position.  */
+              || pending_exact + *pending_exact + 1 != b
+              
+              /* We have only one byte following the exactn for the count.  */
+	      || *pending_exact == (1 << BYTEWIDTH) - 1
+
+              /* If followed by a repetition operator.  */
+              || *p == '*' || *p == '^'
+	      || ((syntax & RE_BK_PLUS_QM)
+		  ? *p == '\\' && (p[1] == '+' || p[1] == '?')
+		  : (*p == '+' || *p == '?'))
+	      || ((syntax & RE_INTERVALS)
+                  && ((syntax & RE_NO_BK_BRACES)
+		      ? *p == '{'
+                      : (p[0] == '\\' && p[1] == '{'))))
+	    {
+	      /* Start building a new exactn.  */
+              
+              laststart = b;
+
+	      BUF_PUSH_2 (exactn, 0);
+	      pending_exact = b - 1;
+            }
+            
+	  BUF_PUSH (c);
+          (*pending_exact)++;
+	  break;
+        } /* switch (c) */
+    } /* while p != pend */
+
+  
+  /* Through the pattern now.  */
+  
+  if (fixup_alt_jump)
+    STORE_JUMP (jump_past_alt, fixup_alt_jump, b);
+
+  if (!COMPILE_STACK_EMPTY) 
+    FREE_STACK_RETURN (REG_EPAREN);
+
+  /* If we don't want backtracking, force success
+     the first time we reach the end of the compiled pattern.  */
+  if (syntax & RE_NO_POSIX_BACKTRACKING)
+    BUF_PUSH (succeed);
+
+  free (compile_stack.stack);
+
+  /* We have succeeded; set the length of the buffer.  */
+  bufp->used = b - bufp->buffer;
+
+#ifdef DEBUG
+  if (debug)
+    {
+      DEBUG_PRINT1 ("\nCompiled pattern: \n");
+      print_compiled_pattern (bufp);
+    }
+#endif /* DEBUG */
+
+#ifndef MATCH_MAY_ALLOCATE
+  /* Initialize the failure stack to the largest possible stack.  This
+     isn't necessary unless we're trying to avoid calling alloca in
+     the search and match routines.  */
+  {
+    int num_regs = bufp->re_nsub + 1;
+
+    /* Since DOUBLE_FAIL_STACK refuses to double only if the current size
+       is strictly greater than re_max_failures, the largest possible stack
+       is 2 * re_max_failures failure points.  */
+    if (fail_stack.size < (2 * re_max_failures * MAX_FAILURE_ITEMS))
+      {
+	fail_stack.size = (2 * re_max_failures * MAX_FAILURE_ITEMS);
+
+#ifdef emacs
+	if (! fail_stack.stack)
+	  fail_stack.stack
+	    = (fail_stack_elt_t *) xmalloc (fail_stack.size 
+					    * sizeof (fail_stack_elt_t));
+	else
+	  fail_stack.stack
+	    = (fail_stack_elt_t *) xrealloc (fail_stack.stack,
+					     (fail_stack.size
+					      * sizeof (fail_stack_elt_t)));
+#else /* not emacs */
+	if (! fail_stack.stack)
+	  fail_stack.stack
+	    = (fail_stack_elt_t *) malloc (fail_stack.size 
+					   * sizeof (fail_stack_elt_t));
+	else
+	  fail_stack.stack
+	    = (fail_stack_elt_t *) realloc (fail_stack.stack,
+					    (fail_stack.size
+					     * sizeof (fail_stack_elt_t)));
+#endif /* not emacs */
+      }
+
+    regex_grow_registers (num_regs);
+  }
+#endif /* not MATCH_MAY_ALLOCATE */
+
+  return REG_NOERROR;
+} /* regex_compile */
+
+
+/* Subroutines for `regex_compile'.  */
+
+/* Store OP at LOC followed by two-byte integer parameter ARG.  */
+
+static void
+store_op1 (op, loc, arg)
+    re_opcode_t op;
+    unsigned char *loc;
+    int arg;
+{
+  *loc = (unsigned char) op;
+  STORE_NUMBER (loc + 1, arg);
+}
+
+
+/* Like `store_op1', but for two two-byte parameters ARG1 and ARG2.  */
+
+static void
+store_op2 (op, loc, arg1, arg2)
+    re_opcode_t op;
+    unsigned char *loc;
+    int arg1, arg2;
+{
+  *loc = (unsigned char) op;
+  STORE_NUMBER (loc + 1, arg1);
+  STORE_NUMBER (loc + 3, arg2);
+}
+
+
+/* Copy the bytes from LOC to END to open up three bytes of space at LOC
+   for OP followed by two-byte integer parameter ARG.  */
+
+static void
+insert_op1 (op, loc, arg, end)
+    re_opcode_t op;
+    unsigned char *loc;
+    int arg;
+    unsigned char *end;    
+{
+  register unsigned char *pfrom = end;
+  register unsigned char *pto = end + 3;
+
+  while (pfrom != loc)
+    *--pto = *--pfrom;
+    
+  store_op1 (op, loc, arg);
+}
+
+
+/* Like `insert_op1', but for two two-byte parameters ARG1 and ARG2.  */
+
+static void
+insert_op2 (op, loc, arg1, arg2, end)
+    re_opcode_t op;
+    unsigned char *loc;
+    int arg1, arg2;
+    unsigned char *end;    
+{
+  register unsigned char *pfrom = end;
+  register unsigned char *pto = end + 5;
+
+  while (pfrom != loc)
+    *--pto = *--pfrom;
+    
+  store_op2 (op, loc, arg1, arg2);
+}
+
+
+/* P points to just after a ^ in PATTERN.  Return true if that ^ comes
+   after an alternative or a begin-subexpression.  We assume there is at
+   least one character before the ^.  */
+
+static boolean
+at_begline_loc_p (pattern, p, syntax)
+    const char *pattern, *p;
+    reg_syntax_t syntax;
+{
+  const char *prev = p - 2;
+  boolean prev_prev_backslash = prev > pattern && prev[-1] == '\\';
+  
+  return
+       /* After a subexpression?  */
+       (*prev == '(' && (syntax & RE_NO_BK_PARENS || prev_prev_backslash))
+       /* After an alternative?  */
+    || (*prev == '|' && (syntax & RE_NO_BK_VBAR || prev_prev_backslash));
+}
+
+
+/* The dual of at_begline_loc_p.  This one is for $.  We assume there is
+   at least one character after the $, i.e., `P < PEND'.  */
+
+static boolean
+at_endline_loc_p (p, pend, syntax)
+    const char *p, *pend;
+    int syntax;
+{
+  const char *next = p;
+  boolean next_backslash = *next == '\\';
+  const char *next_next = p + 1 < pend ? p + 1 : NULL;
+  
+  return
+       /* Before a subexpression?  */
+       (syntax & RE_NO_BK_PARENS ? *next == ')'
+        : next_backslash && next_next && *next_next == ')')
+       /* Before an alternative?  */
+    || (syntax & RE_NO_BK_VBAR ? *next == '|'
+        : next_backslash && next_next && *next_next == '|');
+}
+
+
+/* Returns true if REGNUM is in one of COMPILE_STACK's elements and 
+   false if it's not.  */
+
+static boolean
+group_in_compile_stack (compile_stack, regnum)
+    compile_stack_type compile_stack;
+    regnum_t regnum;
+{
+  int this_element;
+
+  for (this_element = compile_stack.avail - 1;  
+       this_element >= 0; 
+       this_element--)
+    if (compile_stack.stack[this_element].regnum == regnum)
+      return true;
+
+  return false;
+}
+
+
+/* Read the ending character of a range (in a bracket expression) from the
+   uncompiled pattern *P_PTR (which ends at PEND).  We assume the
+   starting character is in `P[-2]'.  (`P[-1]' is the character `-'.)
+   Then we set the translation of all bits between the starting and
+   ending characters (inclusive) in the compiled pattern B.
+   
+   Return an error code.
+   
+   We use these short variable names so we can use the same macros as
+   `regex_compile' itself.  */
+
+static reg_errcode_t
+compile_range (p_ptr, pend, translate, syntax, b)
+    const char **p_ptr, *pend;
+    char *translate;
+    reg_syntax_t syntax;
+    unsigned char *b;
+{
+  unsigned this_char;
+
+  const char *p = *p_ptr;
+  int range_start, range_end;
+  
+  if (p == pend)
+    return REG_ERANGE;
+
+  /* Even though the pattern is a signed `char *', we need to fetch
+     with unsigned char *'s; if the high bit of the pattern character
+     is set, the range endpoints will be negative if we fetch using a
+     signed char *.
+
+     We also want to fetch the endpoints without translating them; the 
+     appropriate translation is done in the bit-setting loop below.  */
+  /* The SVR4 compiler on the 3B2 had trouble with unsigned const char *.  */
+  range_start = ((const unsigned char *) p)[-2];
+  range_end   = ((const unsigned char *) p)[0];
+
+  /* Have to increment the pointer into the pattern string, so the
+     caller isn't still at the ending character.  */
+  (*p_ptr)++;
+
+  /* If the start is after the end, the range is empty.  */
+  if (range_start > range_end)
+    return syntax & RE_NO_EMPTY_RANGES ? REG_ERANGE : REG_NOERROR;
+
+  /* Here we see why `this_char' has to be larger than an `unsigned
+     char' -- the range is inclusive, so if `range_end' == 0xff
+     (assuming 8-bit characters), we would otherwise go into an infinite
+     loop, since all characters <= 0xff.  */
+  for (this_char = range_start; this_char <= range_end; this_char++)
+    {
+      SET_LIST_BIT (TRANSLATE (this_char));
+    }
+  
+  return REG_NOERROR;
+}
+
+
+/* re_compile_fastmap computes a ``fastmap'' for the compiled pattern in
+   BUFP.  A fastmap records which of the (1 << BYTEWIDTH) possible
+   characters can start a string that matches the pattern.  This fastmap
+   is used by re_search to skip quickly over impossible starting points.
+
+   The caller must supply the address of a (1 << BYTEWIDTH)-byte data
+   area as BUFP->fastmap.
+   
+   We set the `fastmap', `fastmap_accurate', and `can_be_null' fields in
+   the pattern buffer.
+
+   Returns 0 if we succeed, -2 if an internal error.   */
+
+int
+re_compile_fastmap (bufp)
+     struct re_pattern_buffer *bufp;
+{
+  int j, k;
+#ifdef MATCH_MAY_ALLOCATE
+  fail_stack_type fail_stack;
+#endif
+#ifndef REGEX_MALLOC
+  char *destination;
+#endif
+  /* We don't push any register information onto the failure stack.  */
+  unsigned num_regs = 0;
+  
+  register char *fastmap = bufp->fastmap;
+  unsigned char *pattern = bufp->buffer;
+  unsigned long size = bufp->used;
+  unsigned char *p = pattern;
+  register unsigned char *pend = pattern + size;
+
+  /* This holds the pointer to the failure stack, when
+     it is allocated relocatably.  */
+  fail_stack_elt_t *failure_stack_ptr;
+
+  /* Assume that each path through the pattern can be null until
+     proven otherwise.  We set this false at the bottom of switch
+     statement, to which we get only if a particular path doesn't
+     match the empty string.  */
+  boolean path_can_be_null = true;
+
+  /* We aren't doing a `succeed_n' to begin with.  */
+  boolean succeed_n_p = false;
+
+  assert (fastmap != NULL && p != NULL);
+  
+  INIT_FAIL_STACK ();
+  bzero (fastmap, 1 << BYTEWIDTH);  /* Assume nothing's valid.  */
+  bufp->fastmap_accurate = 1;	    /* It will be when we're done.  */
+  bufp->can_be_null = 0;
+      
+  while (1)
+    {
+      if (p == pend || *p == succeed)
+	{
+	  /* We have reached the (effective) end of pattern.  */
+	  if (!FAIL_STACK_EMPTY ())
+	    {
+	      bufp->can_be_null |= path_can_be_null;
+
+	      /* Reset for next path.  */
+	      path_can_be_null = true;
+
+	      p = fail_stack.stack[--fail_stack.avail].pointer;
+
+	      continue;
+	    }
+	  else
+	    break;
+	}
+
+      /* We should never be about to go beyond the end of the pattern.  */
+      assert (p < pend);
+      
+      switch (SWITCH_ENUM_CAST ((re_opcode_t) *p++))
+	{
+
+        /* I guess the idea here is to simply not bother with a fastmap
+           if a backreference is used, since it's too hard to figure out
+           the fastmap for the corresponding group.  Setting
+           `can_be_null' stops `re_search_2' from using the fastmap, so
+           that is all we do.  */
+	case duplicate:
+	  bufp->can_be_null = 1;
+          goto done;
+
+
+      /* Following are the cases which match a character.  These end
+         with `break'.  */
+
+	case exactn:
+          fastmap[p[1]] = 1;
+	  break;
+
+
+        case charset:
+          for (j = *p++ * BYTEWIDTH - 1; j >= 0; j--)
+	    if (p[j / BYTEWIDTH] & (1 << (j % BYTEWIDTH)))
+              fastmap[j] = 1;
+	  break;
+
+
+	case charset_not:
+	  /* Chars beyond end of map must be allowed.  */
+	  for (j = *p * BYTEWIDTH; j < (1 << BYTEWIDTH); j++)
+            fastmap[j] = 1;
+
+	  for (j = *p++ * BYTEWIDTH - 1; j >= 0; j--)
+	    if (!(p[j / BYTEWIDTH] & (1 << (j % BYTEWIDTH))))
+              fastmap[j] = 1;
+          break;
+
+
+	case wordchar:
+	  for (j = 0; j < (1 << BYTEWIDTH); j++)
+	    if (SYNTAX (j) == Sword)
+	      fastmap[j] = 1;
+	  break;
+
+
+	case notwordchar:
+	  for (j = 0; j < (1 << BYTEWIDTH); j++)
+	    if (SYNTAX (j) != Sword)
+	      fastmap[j] = 1;
+	  break;
+
+
+        case anychar:
+	  {
+	    int fastmap_newline = fastmap['\n'];
+
+	    /* `.' matches anything ...  */
+	    for (j = 0; j < (1 << BYTEWIDTH); j++)
+	      fastmap[j] = 1;
+
+	    /* ... except perhaps newline.  */
+	    if (!(bufp->syntax & RE_DOT_NEWLINE))
+	      fastmap['\n'] = fastmap_newline;
+
+	    /* Return if we have already set `can_be_null'; if we have,
+	       then the fastmap is irrelevant.  Something's wrong here.  */
+	    else if (bufp->can_be_null)
+	      goto done;
+
+	    /* Otherwise, have to check alternative paths.  */
+	    break;
+	  }
+
+#ifdef emacs
+        case syntaxspec:
+	  k = *p++;
+	  for (j = 0; j < (1 << BYTEWIDTH); j++)
+	    if (SYNTAX (j) == (enum syntaxcode) k)
+	      fastmap[j] = 1;
+	  break;
+
+
+	case notsyntaxspec:
+	  k = *p++;
+	  for (j = 0; j < (1 << BYTEWIDTH); j++)
+	    if (SYNTAX (j) != (enum syntaxcode) k)
+	      fastmap[j] = 1;
+	  break;
+
+
+      /* All cases after this match the empty string.  These end with
+         `continue'.  */
+
+
+	case before_dot:
+	case at_dot:
+	case after_dot:
+          continue;
+#endif /* not emacs */
+
+
+        case no_op:
+        case begline:
+        case endline:
+	case begbuf:
+	case endbuf:
+	case wordbound:
+	case notwordbound:
+	case wordbeg:
+	case wordend:
+        case push_dummy_failure:
+          continue;
+
+
+	case jump_n:
+        case pop_failure_jump:
+	case maybe_pop_jump:
+	case jump:
+        case jump_past_alt:
+	case dummy_failure_jump:
+          EXTRACT_NUMBER_AND_INCR (j, p);
+	  p += j;	
+	  if (j > 0)
+	    continue;
+            
+          /* Jump backward implies we just went through the body of a
+             loop and matched nothing.  Opcode jumped to should be
+             `on_failure_jump' or `succeed_n'.  Just treat it like an
+             ordinary jump.  For a * loop, it has pushed its failure
+             point already; if so, discard that as redundant.  */
+          if ((re_opcode_t) *p != on_failure_jump
+	      && (re_opcode_t) *p != succeed_n)
+	    continue;
+
+          p++;
+          EXTRACT_NUMBER_AND_INCR (j, p);
+          p += j;		
+	  
+          /* If what's on the stack is where we are now, pop it.  */
+          if (!FAIL_STACK_EMPTY () 
+	      && fail_stack.stack[fail_stack.avail - 1].pointer == p)
+            fail_stack.avail--;
+
+          continue;
+
+
+        case on_failure_jump:
+        case on_failure_keep_string_jump:
+	handle_on_failure_jump:
+          EXTRACT_NUMBER_AND_INCR (j, p);
+
+          /* For some patterns, e.g., `(a?)?', `p+j' here points to the
+             end of the pattern.  We don't want to push such a point,
+             since when we restore it above, entering the switch will
+             increment `p' past the end of the pattern.  We don't need
+             to push such a point since we obviously won't find any more
+             fastmap entries beyond `pend'.  Such a pattern can match
+             the null string, though.  */
+          if (p + j < pend)
+            {
+              if (!PUSH_PATTERN_OP (p + j, fail_stack))
+		{
+		  RESET_FAIL_STACK ();
+		  return -2;
+		}
+            }
+          else
+            bufp->can_be_null = 1;
+
+          if (succeed_n_p)
+            {
+              EXTRACT_NUMBER_AND_INCR (k, p);	/* Skip the n.  */
+              succeed_n_p = false;
+	    }
+
+          continue;
+
+
+	case succeed_n:
+          /* Get to the number of times to succeed.  */
+          p += 2;		
+
+          /* Increment p past the n for when k != 0.  */
+          EXTRACT_NUMBER_AND_INCR (k, p);
+          if (k == 0)
+	    {
+              p -= 4;
+  	      succeed_n_p = true;  /* Spaghetti code alert.  */
+              goto handle_on_failure_jump;
+            }
+          continue;
+
+
+	case set_number_at:
+          p += 4;
+          continue;
+
+
+	case start_memory:
+        case stop_memory:
+	  p += 2;
+	  continue;
+
+
+	default:
+          abort (); /* We have listed all the cases.  */
+        } /* switch *p++ */
+
+      /* Getting here means we have found the possible starting
+         characters for one path of the pattern -- and that the empty
+         string does not match.  We need not follow this path further.
+         Instead, look at the next alternative (remembered on the
+         stack), or quit if no more.  The test at the top of the loop
+         does these things.  */
+      path_can_be_null = false;
+      p = pend;
+    } /* while p */
+
+  /* Set `can_be_null' for the last path (also the first path, if the
+     pattern is empty).  */
+  bufp->can_be_null |= path_can_be_null;
+
+ done:
+  RESET_FAIL_STACK ();
+  return 0;
+} /* re_compile_fastmap */
+
+
+/* Set REGS to hold NUM_REGS registers, storing them in STARTS and
+   ENDS.  Subsequent matches using PATTERN_BUFFER and REGS will use
+   this memory for recording register information.  STARTS and ENDS
+   must be allocated using the malloc library routine, and must each
+   be at least NUM_REGS * sizeof (regoff_t) bytes long.
+
+   If NUM_REGS == 0, then subsequent matches should allocate their own
+   register data.
+
+   Unless this function is called, the first search or match using
+   PATTERN_BUFFER will allocate its own register data, without
+   freeing the old data.  */
+
+void
+re_set_registers (bufp, regs, num_regs, starts, ends)
+    struct re_pattern_buffer *bufp;
+    struct re_registers *regs;
+    unsigned num_regs;
+    regoff_t *starts, *ends;
+{
+  if (num_regs)
+    {
+      bufp->regs_allocated = REGS_REALLOCATE;
+      regs->num_regs = num_regs;
+      regs->start = starts;
+      regs->end = ends;
+    }
+  else
+    {
+      bufp->regs_allocated = REGS_UNALLOCATED;
+      regs->num_regs = 0;
+      regs->start = regs->end = (regoff_t *) 0;
+    }
+}
+
+
+/* Searching routines.  */
+
+/* Like re_search_2, below, but only one string is specified, and
+   doesn't let you say where to stop matching. */
+
+int
+re_search (bufp, string, size, startpos, range, regs)
+     struct re_pattern_buffer *bufp;
+     const char *string;
+     int size, startpos, range;
+     struct re_registers *regs;
+{
+  return re_search_2 (bufp, NULL, 0, string, size, startpos, range, 
+		      regs, size);
+}
+
+
+/* Using the compiled pattern in BUFP->buffer, first tries to match the
+   virtual concatenation of STRING1 and STRING2, starting first at index
+   STARTPOS, then at STARTPOS + 1, and so on.
+   
+   STRING1 and STRING2 have length SIZE1 and SIZE2, respectively.
+   
+   RANGE is how far to scan while trying to match.  RANGE = 0 means try
+   only at STARTPOS; in general, the last start tried is STARTPOS +
+   RANGE.
+   
+   In REGS, return the indices of the virtual concatenation of STRING1
+   and STRING2 that matched the entire BUFP->buffer and its contained
+   subexpressions.
+   
+   Do not consider matching one past the index STOP in the virtual
+   concatenation of STRING1 and STRING2.
+
+   We return either the position in the strings at which the match was
+   found, -1 if no match, or -2 if error (such as failure
+   stack overflow).  */
+
+int
+re_search_2 (bufp, string1, size1, string2, size2, startpos, range, regs, stop)
+     struct re_pattern_buffer *bufp;
+     const char *string1, *string2;
+     int size1, size2;
+     int startpos;
+     int range;
+     struct re_registers *regs;
+     int stop;
+{
+  int val;
+  register char *fastmap = bufp->fastmap;
+  register char *translate = bufp->translate;
+  int total_size = size1 + size2;
+  int endpos = startpos + range;
+
+  /* Check for out-of-range STARTPOS.  */
+  if (startpos < 0 || startpos > total_size)
+    return -1;
+    
+  /* Fix up RANGE if it might eventually take us outside
+     the virtual concatenation of STRING1 and STRING2.  */
+  if (endpos < -1)
+    range = -1 - startpos;
+  else if (endpos > total_size)
+    range = total_size - startpos;
+
+  /* If the search isn't to be a backwards one, don't waste time in a
+     search for a pattern that must be anchored.  */
+  if (bufp->used > 0 && (re_opcode_t) bufp->buffer[0] == begbuf && range > 0)
+    {
+      if (startpos > 0)
+	return -1;
+      else
+	range = 1;
+    }
+
+  /* Update the fastmap now if not correct already.  */
+  if (fastmap && !bufp->fastmap_accurate)
+    if (re_compile_fastmap (bufp) == -2)
+      return -2;
+  
+  /* Loop through the string, looking for a place to start matching.  */
+  for (;;)
+    { 
+      /* If a fastmap is supplied, skip quickly over characters that
+         cannot be the start of a match.  If the pattern can match the
+         null string, however, we don't need to skip characters; we want
+         the first null string.  */
+      if (fastmap && startpos < total_size && !bufp->can_be_null)
+	{
+	  if (range > 0)	/* Searching forwards.  */
+	    {
+	      register const char *d;
+	      register int lim = 0;
+	      int irange = range;
+
+              if (startpos < size1 && startpos + range >= size1)
+                lim = range - (size1 - startpos);
+
+	      d = (startpos >= size1 ? string2 - size1 : string1) + startpos;
+   
+              /* Written out as an if-else to avoid testing `translate'
+                 inside the loop.  */
+	      if (translate)
+                while (range > lim
+                       && !fastmap[(unsigned char)
+				   translate[(unsigned char) *d++]])
+                  range--;
+	      else
+                while (range > lim && !fastmap[(unsigned char) *d++])
+                  range--;
+
+	      startpos += irange - range;
+	    }
+	  else				/* Searching backwards.  */
+	    {
+	      register char c = (size1 == 0 || startpos >= size1
+                                 ? string2[startpos - size1] 
+                                 : string1[startpos]);
+
+	      if (!fastmap[(unsigned char) TRANSLATE (c)])
+		goto advance;
+	    }
+	}
+
+      /* If can't match the null string, and that's all we have left, fail.  */
+      if (range >= 0 && startpos == total_size && fastmap
+          && !bufp->can_be_null)
+	return -1;
+
+      val = re_match_2_internal (bufp, string1, size1, string2, size2,
+				 startpos, regs, stop);
+#ifndef REGEX_MALLOC
+#ifdef C_ALLOCA
+      alloca (0);
+#endif
+#endif
+
+      if (val >= 0)
+	return startpos;
+        
+      if (val == -2)
+	return -2;
+
+    advance:
+      if (!range) 
+        break;
+      else if (range > 0) 
+        {
+          range--; 
+          startpos++;
+        }
+      else
+        {
+          range++; 
+          startpos--;
+        }
+    }
+  return -1;
+} /* re_search_2 */
+
+
+/* Declarations and macros for re_match_2.  */
+
+static int bcmp_translate ();
+static boolean alt_match_null_string_p (),
+               common_op_match_null_string_p (),
+               group_match_null_string_p ();
+
+/* This converts PTR, a pointer into one of the search strings `string1'
+   and `string2' into an offset from the beginning of that string.  */
+#define POINTER_TO_OFFSET(ptr)			\
+  (FIRST_STRING_P (ptr)				\
+   ? ((regoff_t) ((ptr) - string1))		\
+   : ((regoff_t) ((ptr) - string2 + size1)))
+
+/* Macros for dealing with the split strings in re_match_2.  */
+
+#define MATCHING_IN_FIRST_STRING  (dend == end_match_1)
+
+/* Call before fetching a character with *d.  This switches over to
+   string2 if necessary.  */
+#define PREFETCH()							\
+  while (d == dend)						    	\
+    {									\
+      /* End of string2 => fail.  */					\
+      if (dend == end_match_2) 						\
+        goto fail;							\
+      /* End of string1 => advance to string2.  */ 			\
+      d = string2;						        \
+      dend = end_match_2;						\
+    }
+
+
+/* Test if at very beginning or at very end of the virtual concatenation
+   of `string1' and `string2'.  If only one string, it's `string2'.  */
+#define AT_STRINGS_BEG(d) ((d) == (size1 ? string1 : string2) || !size2)
+#define AT_STRINGS_END(d) ((d) == end2)	
+
+
+/* Test if D points to a character which is word-constituent.  We have
+   two special cases to check for: if past the end of string1, look at
+   the first character in string2; and if before the beginning of
+   string2, look at the last character in string1.  */
+#define WORDCHAR_P(d)							\
+  (SYNTAX ((d) == end1 ? *string2					\
+           : (d) == string2 - 1 ? *(end1 - 1) : *(d))			\
+   == Sword)
+
+/* Test if the character before D and the one at D differ with respect
+   to being word-constituent.  */
+#define AT_WORD_BOUNDARY(d)						\
+  (AT_STRINGS_BEG (d) || AT_STRINGS_END (d)				\
+   || WORDCHAR_P (d - 1) != WORDCHAR_P (d))
+
+
+/* Free everything we malloc.  */
+#ifdef MATCH_MAY_ALLOCATE
+#define FREE_VAR(var) if (var) REGEX_FREE (var); var = NULL
+#define FREE_VARIABLES()						\
+  do {									\
+    REGEX_FREE_STACK (fail_stack.stack);				\
+    FREE_VAR (regstart);						\
+    FREE_VAR (regend);							\
+    FREE_VAR (old_regstart);						\
+    FREE_VAR (old_regend);						\
+    FREE_VAR (best_regstart);						\
+    FREE_VAR (best_regend);						\
+    FREE_VAR (reg_info);						\
+    FREE_VAR (reg_dummy);						\
+    FREE_VAR (reg_info_dummy);						\
+  } while (0)
+#else
+#define FREE_VARIABLES() ((void)0) /* Do nothing!  But inhibit gcc warning.  */
+#endif /* not MATCH_MAY_ALLOCATE */
+
+/* These values must meet several constraints.  They must not be valid
+   register values; since we have a limit of 255 registers (because
+   we use only one byte in the pattern for the register number), we can
+   use numbers larger than 255.  They must differ by 1, because of
+   NUM_FAILURE_ITEMS above.  And the value for the lowest register must
+   be larger than the value for the highest register, so we do not try
+   to actually save any registers when none are active.  */
+#define NO_HIGHEST_ACTIVE_REG (1 << BYTEWIDTH)
+#define NO_LOWEST_ACTIVE_REG (NO_HIGHEST_ACTIVE_REG + 1)
+
+
+/* Matching routines.  */
+
+#ifndef emacs   /* Emacs never uses this.  */
+/* re_match is like re_match_2 except it takes only a single string.  */
+
+int
+re_match (bufp, string, size, pos, regs)
+     struct re_pattern_buffer *bufp;
+     const char *string;
+     int size, pos;
+     struct re_registers *regs;
+{
+  int result = re_match_2_internal (bufp, NULL, 0, string, size,
+				    pos, regs, size);
+  alloca (0);
+  return result;
+}
+#endif /* not emacs */
+
+
+/* re_match_2 matches the compiled pattern in BUFP against the
+   the (virtual) concatenation of STRING1 and STRING2 (of length SIZE1
+   and SIZE2, respectively).  We start matching at POS, and stop
+   matching at STOP.
+   
+   If REGS is non-null and the `no_sub' field of BUFP is nonzero, we
+   store offsets for the substring each group matched in REGS.  See the
+   documentation for exactly how many groups we fill.
+
+   We return -1 if no match, -2 if an internal error (such as the
+   failure stack overflowing).  Otherwise, we return the length of the
+   matched substring.  */
+
+int
+re_match_2 (bufp, string1, size1, string2, size2, pos, regs, stop)
+     struct re_pattern_buffer *bufp;
+     const char *string1, *string2;
+     int size1, size2;
+     int pos;
+     struct re_registers *regs;
+     int stop;
+{
+  int result = re_match_2_internal (bufp, string1, size1, string2, size2,
+				    pos, regs, stop);
+  alloca (0);
+  return result;
+}
+
+/* This is a separate function so that we can force an alloca cleanup
+   afterwards.  */
+static int
+re_match_2_internal (bufp, string1, size1, string2, size2, pos, regs, stop)
+     struct re_pattern_buffer *bufp;
+     const char *string1, *string2;
+     int size1, size2;
+     int pos;
+     struct re_registers *regs;
+     int stop;
+{
+  /* General temporaries.  */
+  int mcnt;
+  unsigned char *p1;
+
+  /* Just past the end of the corresponding string.  */
+  const char *end1, *end2;
+
+  /* Pointers into string1 and string2, just past the last characters in
+     each to consider matching.  */
+  const char *end_match_1, *end_match_2;
+
+  /* Where we are in the data, and the end of the current string.  */
+  const char *d, *dend;
+  
+  /* Where we are in the pattern, and the end of the pattern.  */
+  unsigned char *p = bufp->buffer;
+  register unsigned char *pend = p + bufp->used;
+
+  /* Mark the opcode just after a start_memory, so we can test for an
+     empty subpattern when we get to the stop_memory.  */
+  unsigned char *just_past_start_mem = 0;
+
+  /* We use this to map every character in the string.  */
+  char *translate = bufp->translate;
+
+  /* Failure point stack.  Each place that can handle a failure further
+     down the line pushes a failure point on this stack.  It consists of
+     restart, regend, and reg_info for all registers corresponding to
+     the subexpressions we're currently inside, plus the number of such
+     registers, and, finally, two char *'s.  The first char * is where
+     to resume scanning the pattern; the second one is where to resume
+     scanning the strings.  If the latter is zero, the failure point is
+     a ``dummy''; if a failure happens and the failure point is a dummy,
+     it gets discarded and the next next one is tried.  */
+#ifdef MATCH_MAY_ALLOCATE /* otherwise, this is global.  */
+  fail_stack_type fail_stack;
+#endif
+#ifdef DEBUG
+  static unsigned failure_id = 0;
+  unsigned nfailure_points_pushed = 0, nfailure_points_popped = 0;
+#endif
+
+  /* This holds the pointer to the failure stack, when
+     it is allocated relocatably.  */
+  fail_stack_elt_t *failure_stack_ptr;
+
+  /* We fill all the registers internally, independent of what we
+     return, for use in backreferences.  The number here includes
+     an element for register zero.  */
+  unsigned num_regs = bufp->re_nsub + 1;
+  
+  /* The currently active registers.  */
+  unsigned lowest_active_reg = NO_LOWEST_ACTIVE_REG;
+  unsigned highest_active_reg = NO_HIGHEST_ACTIVE_REG;
+
+  /* Information on the contents of registers. These are pointers into
+     the input strings; they record just what was matched (on this
+     attempt) by a subexpression part of the pattern, that is, the
+     regnum-th regstart pointer points to where in the pattern we began
+     matching and the regnum-th regend points to right after where we
+     stopped matching the regnum-th subexpression.  (The zeroth register
+     keeps track of what the whole pattern matches.)  */
+#ifdef MATCH_MAY_ALLOCATE /* otherwise, these are global.  */
+  const char **regstart, **regend;
+#endif
+
+  /* If a group that's operated upon by a repetition operator fails to
+     match anything, then the register for its start will need to be
+     restored because it will have been set to wherever in the string we
+     are when we last see its open-group operator.  Similarly for a
+     register's end.  */
+#ifdef MATCH_MAY_ALLOCATE /* otherwise, these are global.  */
+  const char **old_regstart, **old_regend;
+#endif
+
+  /* The is_active field of reg_info helps us keep track of which (possibly
+     nested) subexpressions we are currently in. The matched_something
+     field of reg_info[reg_num] helps us tell whether or not we have
+     matched any of the pattern so far this time through the reg_num-th
+     subexpression.  These two fields get reset each time through any
+     loop their register is in.  */
+#ifdef MATCH_MAY_ALLOCATE /* otherwise, this is global.  */
+  register_info_type *reg_info; 
+#endif
+
+  /* The following record the register info as found in the above
+     variables when we find a match better than any we've seen before. 
+     This happens as we backtrack through the failure points, which in
+     turn happens only if we have not yet matched the entire string. */
+  unsigned best_regs_set = false;
+#ifdef MATCH_MAY_ALLOCATE /* otherwise, these are global.  */
+  const char **best_regstart, **best_regend;
+#endif
+  
+  /* Logically, this is `best_regend[0]'.  But we don't want to have to
+     allocate space for that if we're not allocating space for anything
+     else (see below).  Also, we never need info about register 0 for
+     any of the other register vectors, and it seems rather a kludge to
+     treat `best_regend' differently than the rest.  So we keep track of
+     the end of the best match so far in a separate variable.  We
+     initialize this to NULL so that when we backtrack the first time
+     and need to test it, it's not garbage.  */
+  const char *match_end = NULL;
+
+  /* This helps SET_REGS_MATCHED avoid doing redundant work.  */
+  int set_regs_matched_done = 0;
+
+  /* Used when we pop values we don't care about.  */
+#ifdef MATCH_MAY_ALLOCATE /* otherwise, these are global.  */
+  const char **reg_dummy;
+  register_info_type *reg_info_dummy;
+#endif
+
+#ifdef DEBUG
+  /* Counts the total number of registers pushed.  */
+  unsigned num_regs_pushed = 0; 	
+#endif
+
+  DEBUG_PRINT1 ("\n\nEntering re_match_2.\n");
+  
+  INIT_FAIL_STACK ();
+  
+#ifdef MATCH_MAY_ALLOCATE
+  /* Do not bother to initialize all the register variables if there are
+     no groups in the pattern, as it takes a fair amount of time.  If
+     there are groups, we include space for register 0 (the whole
+     pattern), even though we never use it, since it simplifies the
+     array indexing.  We should fix this.  */
+  if (bufp->re_nsub)
+    {
+      regstart = REGEX_TALLOC (num_regs, const char *);
+      regend = REGEX_TALLOC (num_regs, const char *);
+      old_regstart = REGEX_TALLOC (num_regs, const char *);
+      old_regend = REGEX_TALLOC (num_regs, const char *);
+      best_regstart = REGEX_TALLOC (num_regs, const char *);
+      best_regend = REGEX_TALLOC (num_regs, const char *);
+      reg_info = REGEX_TALLOC (num_regs, register_info_type);
+      reg_dummy = REGEX_TALLOC (num_regs, const char *);
+      reg_info_dummy = REGEX_TALLOC (num_regs, register_info_type);
+
+      if (!(regstart && regend && old_regstart && old_regend && reg_info 
+            && best_regstart && best_regend && reg_dummy && reg_info_dummy)) 
+        {
+          FREE_VARIABLES ();
+          return -2;
+        }
+    }
+  else
+    {
+      /* We must initialize all our variables to NULL, so that
+         `FREE_VARIABLES' doesn't try to free them.  */
+      regstart = regend = old_regstart = old_regend = best_regstart
+        = best_regend = reg_dummy = NULL;
+      reg_info = reg_info_dummy = (register_info_type *) NULL;
+    }
+#endif /* MATCH_MAY_ALLOCATE */
+
+  /* The starting position is bogus.  */
+  if (pos < 0 || pos > size1 + size2)
+    {
+      FREE_VARIABLES ();
+      return -1;
+    }
+    
+  /* Initialize subexpression text positions to -1 to mark ones that no
+     start_memory/stop_memory has been seen for. Also initialize the
+     register information struct.  */
+  for (mcnt = 1; mcnt < num_regs; mcnt++)
+    {
+      regstart[mcnt] = regend[mcnt] 
+        = old_regstart[mcnt] = old_regend[mcnt] = REG_UNSET_VALUE;
+        
+      REG_MATCH_NULL_STRING_P (reg_info[mcnt]) = MATCH_NULL_UNSET_VALUE;
+      IS_ACTIVE (reg_info[mcnt]) = 0;
+      MATCHED_SOMETHING (reg_info[mcnt]) = 0;
+      EVER_MATCHED_SOMETHING (reg_info[mcnt]) = 0;
+    }
+  
+  /* We move `string1' into `string2' if the latter's empty -- but not if
+     `string1' is null.  */
+  if (size2 == 0 && string1 != NULL)
+    {
+      string2 = string1;
+      size2 = size1;
+      string1 = 0;
+      size1 = 0;
+    }
+  end1 = string1 + size1;
+  end2 = string2 + size2;
+
+  /* Compute where to stop matching, within the two strings.  */
+  if (stop <= size1)
+    {
+      end_match_1 = string1 + stop;
+      end_match_2 = string2;
+    }
+  else
+    {
+      end_match_1 = end1;
+      end_match_2 = string2 + stop - size1;
+    }
+
+  /* `p' scans through the pattern as `d' scans through the data. 
+     `dend' is the end of the input string that `d' points within.  `d'
+     is advanced into the following input string whenever necessary, but
+     this happens before fetching; therefore, at the beginning of the
+     loop, `d' can be pointing at the end of a string, but it cannot
+     equal `string2'.  */
+  if (size1 > 0 && pos <= size1)
+    {
+      d = string1 + pos;
+      dend = end_match_1;
+    }
+  else
+    {
+      d = string2 + pos - size1;
+      dend = end_match_2;
+    }
+
+  DEBUG_PRINT1 ("The compiled pattern is: ");
+  DEBUG_PRINT_COMPILED_PATTERN (bufp, p, pend);
+  DEBUG_PRINT1 ("The string to match is: `");
+  DEBUG_PRINT_DOUBLE_STRING (d, string1, size1, string2, size2);
+  DEBUG_PRINT1 ("'\n");
+  
+  /* This loops over pattern commands.  It exits by returning from the
+     function if the match is complete, or it drops through if the match
+     fails at this starting point in the input data.  */
+  for (;;)
+    {
+      DEBUG_PRINT2 ("\n0x%x: ", p);
+
+      if (p == pend)
+	{ /* End of pattern means we might have succeeded.  */
+          DEBUG_PRINT1 ("end of pattern ... ");
+          
+	  /* If we haven't matched the entire string, and we want the
+             longest match, try backtracking.  */
+          if (d != end_match_2)
+	    {
+	      /* 1 if this match ends in the same string (string1 or string2)
+		 as the best previous match.  */
+	      boolean same_str_p = (FIRST_STRING_P (match_end) 
+				    == MATCHING_IN_FIRST_STRING);
+	      /* 1 if this match is the best seen so far.  */
+	      boolean best_match_p;
+
+	      /* AIX compiler got confused when this was combined
+		 with the previous declaration.  */
+	      if (same_str_p)
+		best_match_p = d > match_end;
+	      else
+		best_match_p = !MATCHING_IN_FIRST_STRING;
+
+              DEBUG_PRINT1 ("backtracking.\n");
+              
+              if (!FAIL_STACK_EMPTY ())
+                { /* More failure points to try.  */
+
+                  /* If exceeds best match so far, save it.  */
+                  if (!best_regs_set || best_match_p)
+                    {
+                      best_regs_set = true;
+                      match_end = d;
+                      
+                      DEBUG_PRINT1 ("\nSAVING match as best so far.\n");
+                      
+                      for (mcnt = 1; mcnt < num_regs; mcnt++)
+                        {
+                          best_regstart[mcnt] = regstart[mcnt];
+                          best_regend[mcnt] = regend[mcnt];
+                        }
+                    }
+                  goto fail;	       
+                }
+
+              /* If no failure points, don't restore garbage.  And if
+                 last match is real best match, don't restore second
+                 best one. */
+              else if (best_regs_set && !best_match_p)
+                {
+  	        restore_best_regs:
+                  /* Restore best match.  It may happen that `dend ==
+                     end_match_1' while the restored d is in string2.
+                     For example, the pattern `x.*y.*z' against the
+                     strings `x-' and `y-z-', if the two strings are
+                     not consecutive in memory.  */
+                  DEBUG_PRINT1 ("Restoring best registers.\n");
+                  
+                  d = match_end;
+                  dend = ((d >= string1 && d <= end1)
+		           ? end_match_1 : end_match_2);
+
+		  for (mcnt = 1; mcnt < num_regs; mcnt++)
+		    {
+		      regstart[mcnt] = best_regstart[mcnt];
+		      regend[mcnt] = best_regend[mcnt];
+		    }
+                }
+            } /* d != end_match_2 */
+
+	succeed_label:
+          DEBUG_PRINT1 ("Accepting match.\n");
+
+          /* If caller wants register contents data back, do it.  */
+          if (regs && !bufp->no_sub)
+	    {
+              /* Have the register data arrays been allocated?  */
+              if (bufp->regs_allocated == REGS_UNALLOCATED)
+                { /* No.  So allocate them with malloc.  We need one
+                     extra element beyond `num_regs' for the `-1' marker
+                     GNU code uses.  */
+                  regs->num_regs = MAX (RE_NREGS, num_regs + 1);
+                  regs->start = TALLOC (regs->num_regs, regoff_t);
+                  regs->end = TALLOC (regs->num_regs, regoff_t);
+                  if (regs->start == NULL || regs->end == NULL)
+		    {
+		      FREE_VARIABLES ();
+		      return -2;
+		    }
+                  bufp->regs_allocated = REGS_REALLOCATE;
+                }
+              else if (bufp->regs_allocated == REGS_REALLOCATE)
+                { /* Yes.  If we need more elements than were already
+                     allocated, reallocate them.  If we need fewer, just
+                     leave it alone.  */
+                  if (regs->num_regs < num_regs + 1)
+                    {
+                      regs->num_regs = num_regs + 1;
+                      RETALLOC (regs->start, regs->num_regs, regoff_t);
+                      RETALLOC (regs->end, regs->num_regs, regoff_t);
+                      if (regs->start == NULL || regs->end == NULL)
+			{
+			  FREE_VARIABLES ();
+			  return -2;
+			}
+                    }
+                }
+              else
+		{
+		  /* These braces fend off a "empty body in an else-statement"
+		     warning under GCC when assert expands to nothing.  */
+		  assert (bufp->regs_allocated == REGS_FIXED);
+		}
+
+              /* Convert the pointer data in `regstart' and `regend' to
+                 indices.  Register zero has to be set differently,
+                 since we haven't kept track of any info for it.  */
+              if (regs->num_regs > 0)
+                {
+                  regs->start[0] = pos;
+                  regs->end[0] = (MATCHING_IN_FIRST_STRING
+				  ? ((regoff_t) (d - string1))
+			          : ((regoff_t) (d - string2 + size1)));
+                }
+              
+              /* Go through the first `min (num_regs, regs->num_regs)'
+                 registers, since that is all we initialized.  */
+	      for (mcnt = 1; mcnt < MIN (num_regs, regs->num_regs); mcnt++)
+		{
+                  if (REG_UNSET (regstart[mcnt]) || REG_UNSET (regend[mcnt]))
+                    regs->start[mcnt] = regs->end[mcnt] = -1;
+                  else
+                    {
+		      regs->start[mcnt]
+			= (regoff_t) POINTER_TO_OFFSET (regstart[mcnt]);
+                      regs->end[mcnt]
+			= (regoff_t) POINTER_TO_OFFSET (regend[mcnt]);
+                    }
+		}
+              
+              /* If the regs structure we return has more elements than
+                 were in the pattern, set the extra elements to -1.  If
+                 we (re)allocated the registers, this is the case,
+                 because we always allocate enough to have at least one
+                 -1 at the end.  */
+              for (mcnt = num_regs; mcnt < regs->num_regs; mcnt++)
+                regs->start[mcnt] = regs->end[mcnt] = -1;
+	    } /* regs && !bufp->no_sub */
+
+          DEBUG_PRINT4 ("%u failure points pushed, %u popped (%u remain).\n",
+                        nfailure_points_pushed, nfailure_points_popped,
+                        nfailure_points_pushed - nfailure_points_popped);
+          DEBUG_PRINT2 ("%u registers pushed.\n", num_regs_pushed);
+
+          mcnt = d - pos - (MATCHING_IN_FIRST_STRING 
+			    ? string1 
+			    : string2 - size1);
+
+          DEBUG_PRINT2 ("Returning %d from re_match_2.\n", mcnt);
+
+          FREE_VARIABLES ();
+          return mcnt;
+        }
+
+      /* Otherwise match next pattern command.  */
+      switch (SWITCH_ENUM_CAST ((re_opcode_t) *p++))
+	{
+        /* Ignore these.  Used to ignore the n of succeed_n's which
+           currently have n == 0.  */
+        case no_op:
+          DEBUG_PRINT1 ("EXECUTING no_op.\n");
+          break;
+
+	case succeed:
+          DEBUG_PRINT1 ("EXECUTING succeed.\n");
+	  goto succeed_label;
+
+        /* Match the next n pattern characters exactly.  The following
+           byte in the pattern defines n, and the n bytes after that
+           are the characters to match.  */
+	case exactn:
+	  mcnt = *p++;
+          DEBUG_PRINT2 ("EXECUTING exactn %d.\n", mcnt);
+
+          /* This is written out as an if-else so we don't waste time
+             testing `translate' inside the loop.  */
+          if (translate)
+	    {
+	      do
+		{
+		  PREFETCH ();
+		  if (translate[(unsigned char) *d++] != (char) *p++)
+                    goto fail;
+		}
+	      while (--mcnt);
+	    }
+	  else
+	    {
+	      do
+		{
+		  PREFETCH ();
+		  if (*d++ != (char) *p++) goto fail;
+		}
+	      while (--mcnt);
+	    }
+	  SET_REGS_MATCHED ();
+          break;
+
+
+        /* Match any character except possibly a newline or a null.  */
+	case anychar:
+          DEBUG_PRINT1 ("EXECUTING anychar.\n");
+
+          PREFETCH ();
+
+          if ((!(bufp->syntax & RE_DOT_NEWLINE) && TRANSLATE (*d) == '\n')
+              || (bufp->syntax & RE_DOT_NOT_NULL && TRANSLATE (*d) == '\000'))
+	    goto fail;
+
+          SET_REGS_MATCHED ();
+          DEBUG_PRINT2 ("  Matched `%d'.\n", *d);
+          d++;
+	  break;
+
+
+	case charset:
+	case charset_not:
+	  {
+	    register unsigned char c;
+	    boolean not = (re_opcode_t) *(p - 1) == charset_not;
+
+            DEBUG_PRINT2 ("EXECUTING charset%s.\n", not ? "_not" : "");
+
+	    PREFETCH ();
+	    c = TRANSLATE (*d); /* The character to match.  */
+
+            /* Cast to `unsigned' instead of `unsigned char' in case the
+               bit list is a full 32 bytes long.  */
+	    if (c < (unsigned) (*p * BYTEWIDTH)
+		&& p[1 + c / BYTEWIDTH] & (1 << (c % BYTEWIDTH)))
+	      not = !not;
+
+	    p += 1 + *p;
+
+	    if (!not) goto fail;
+            
+	    SET_REGS_MATCHED ();
+            d++;
+	    break;
+	  }
+
+
+        /* The beginning of a group is represented by start_memory.
+           The arguments are the register number in the next byte, and the
+           number of groups inner to this one in the next.  The text
+           matched within the group is recorded (in the internal
+           registers data structure) under the register number.  */
+        case start_memory:
+	  DEBUG_PRINT3 ("EXECUTING start_memory %d (%d):\n", *p, p[1]);
+
+          /* Find out if this group can match the empty string.  */
+	  p1 = p;		/* To send to group_match_null_string_p.  */
+          
+          if (REG_MATCH_NULL_STRING_P (reg_info[*p]) == MATCH_NULL_UNSET_VALUE)
+            REG_MATCH_NULL_STRING_P (reg_info[*p]) 
+              = group_match_null_string_p (&p1, pend, reg_info);
+
+          /* Save the position in the string where we were the last time
+             we were at this open-group operator in case the group is
+             operated upon by a repetition operator, e.g., with `(a*)*b'
+             against `ab'; then we want to ignore where we are now in
+             the string in case this attempt to match fails.  */
+          old_regstart[*p] = REG_MATCH_NULL_STRING_P (reg_info[*p])
+                             ? REG_UNSET (regstart[*p]) ? d : regstart[*p]
+                             : regstart[*p];
+	  DEBUG_PRINT2 ("  old_regstart: %d\n", 
+			 POINTER_TO_OFFSET (old_regstart[*p]));
+
+          regstart[*p] = d;
+	  DEBUG_PRINT2 ("  regstart: %d\n", POINTER_TO_OFFSET (regstart[*p]));
+
+          IS_ACTIVE (reg_info[*p]) = 1;
+          MATCHED_SOMETHING (reg_info[*p]) = 0;
+
+	  /* Clear this whenever we change the register activity status.  */
+	  set_regs_matched_done = 0;
+          
+          /* This is the new highest active register.  */
+          highest_active_reg = *p;
+          
+          /* If nothing was active before, this is the new lowest active
+             register.  */
+          if (lowest_active_reg == NO_LOWEST_ACTIVE_REG)
+            lowest_active_reg = *p;
+
+          /* Move past the register number and inner group count.  */
+          p += 2;
+	  just_past_start_mem = p;
+
+          break;
+
+
+        /* The stop_memory opcode represents the end of a group.  Its
+           arguments are the same as start_memory's: the register
+           number, and the number of inner groups.  */
+	case stop_memory:
+	  DEBUG_PRINT3 ("EXECUTING stop_memory %d (%d):\n", *p, p[1]);
+             
+          /* We need to save the string position the last time we were at
+             this close-group operator in case the group is operated
+             upon by a repetition operator, e.g., with `((a*)*(b*)*)*'
+             against `aba'; then we want to ignore where we are now in
+             the string in case this attempt to match fails.  */
+          old_regend[*p] = REG_MATCH_NULL_STRING_P (reg_info[*p])
+                           ? REG_UNSET (regend[*p]) ? d : regend[*p]
+			   : regend[*p];
+	  DEBUG_PRINT2 ("      old_regend: %d\n", 
+			 POINTER_TO_OFFSET (old_regend[*p]));
+
+          regend[*p] = d;
+	  DEBUG_PRINT2 ("      regend: %d\n", POINTER_TO_OFFSET (regend[*p]));
+
+          /* This register isn't active anymore.  */
+          IS_ACTIVE (reg_info[*p]) = 0;
+
+	  /* Clear this whenever we change the register activity status.  */
+	  set_regs_matched_done = 0;
+
+          /* If this was the only register active, nothing is active
+             anymore.  */
+          if (lowest_active_reg == highest_active_reg)
+            {
+              lowest_active_reg = NO_LOWEST_ACTIVE_REG;
+              highest_active_reg = NO_HIGHEST_ACTIVE_REG;
+            }
+          else
+            { /* We must scan for the new highest active register, since
+                 it isn't necessarily one less than now: consider
+                 (a(b)c(d(e)f)g).  When group 3 ends, after the f), the
+                 new highest active register is 1.  */
+              unsigned char r = *p - 1;
+              while (r > 0 && !IS_ACTIVE (reg_info[r]))
+                r--;
+              
+              /* If we end up at register zero, that means that we saved
+                 the registers as the result of an `on_failure_jump', not
+                 a `start_memory', and we jumped to past the innermost
+                 `stop_memory'.  For example, in ((.)*) we save
+                 registers 1 and 2 as a result of the *, but when we pop
+                 back to the second ), we are at the stop_memory 1.
+                 Thus, nothing is active.  */
+	      if (r == 0)
+                {
+                  lowest_active_reg = NO_LOWEST_ACTIVE_REG;
+                  highest_active_reg = NO_HIGHEST_ACTIVE_REG;
+                }
+              else
+                highest_active_reg = r;
+            }
+          
+          /* If just failed to match something this time around with a
+             group that's operated on by a repetition operator, try to
+             force exit from the ``loop'', and restore the register
+             information for this group that we had before trying this
+             last match.  */
+          if ((!MATCHED_SOMETHING (reg_info[*p])
+               || just_past_start_mem == p - 1)
+	      && (p + 2) < pend)              
+            {
+              boolean is_a_jump_n = false;
+              
+              p1 = p + 2;
+              mcnt = 0;
+              switch ((re_opcode_t) *p1++)
+                {
+                  case jump_n:
+		    is_a_jump_n = true;
+                  case pop_failure_jump:
+		  case maybe_pop_jump:
+		  case jump:
+		  case dummy_failure_jump:
+                    EXTRACT_NUMBER_AND_INCR (mcnt, p1);
+		    if (is_a_jump_n)
+		      p1 += 2;
+                    break;
+                  
+                  default:
+                    /* do nothing */ ;
+                }
+	      p1 += mcnt;
+        
+              /* If the next operation is a jump backwards in the pattern
+	         to an on_failure_jump right before the start_memory
+                 corresponding to this stop_memory, exit from the loop
+                 by forcing a failure after pushing on the stack the
+                 on_failure_jump's jump in the pattern, and d.  */
+              if (mcnt < 0 && (re_opcode_t) *p1 == on_failure_jump
+                  && (re_opcode_t) p1[3] == start_memory && p1[4] == *p)
+		{
+                  /* If this group ever matched anything, then restore
+                     what its registers were before trying this last
+                     failed match, e.g., with `(a*)*b' against `ab' for
+                     regstart[1], and, e.g., with `((a*)*(b*)*)*'
+                     against `aba' for regend[3].
+                     
+                     Also restore the registers for inner groups for,
+                     e.g., `((a*)(b*))*' against `aba' (register 3 would
+                     otherwise get trashed).  */
+                     
+                  if (EVER_MATCHED_SOMETHING (reg_info[*p]))
+		    {
+		      unsigned r; 
+        
+                      EVER_MATCHED_SOMETHING (reg_info[*p]) = 0;
+                      
+		      /* Restore this and inner groups' (if any) registers.  */
+                      for (r = *p; r < *p + *(p + 1); r++)
+                        {
+                          regstart[r] = old_regstart[r];
+
+                          /* xx why this test?  */
+                          if (old_regend[r] >= regstart[r])
+                            regend[r] = old_regend[r];
+                        }     
+                    }
+		  p1++;
+                  EXTRACT_NUMBER_AND_INCR (mcnt, p1);
+                  PUSH_FAILURE_POINT (p1 + mcnt, d, -2);
+
+                  goto fail;
+                }
+            }
+          
+          /* Move past the register number and the inner group count.  */
+          p += 2;
+          break;
+
+
+	/* \<digit> has been turned into a `duplicate' command which is
+           followed by the numeric value of <digit> as the register number.  */
+        case duplicate:
+	  {
+	    register const char *d2, *dend2;
+	    int regno = *p++;   /* Get which register to match against.  */
+	    DEBUG_PRINT2 ("EXECUTING duplicate %d.\n", regno);
+
+	    /* Can't back reference a group which we've never matched.  */
+            if (REG_UNSET (regstart[regno]) || REG_UNSET (regend[regno]))
+              goto fail;
+              
+            /* Where in input to try to start matching.  */
+            d2 = regstart[regno];
+            
+            /* Where to stop matching; if both the place to start and
+               the place to stop matching are in the same string, then
+               set to the place to stop, otherwise, for now have to use
+               the end of the first string.  */
+
+            dend2 = ((FIRST_STRING_P (regstart[regno]) 
+		      == FIRST_STRING_P (regend[regno]))
+		     ? regend[regno] : end_match_1);
+	    for (;;)
+	      {
+		/* If necessary, advance to next segment in register
+                   contents.  */
+		while (d2 == dend2)
+		  {
+		    if (dend2 == end_match_2) break;
+		    if (dend2 == regend[regno]) break;
+
+                    /* End of string1 => advance to string2. */
+                    d2 = string2;
+                    dend2 = regend[regno];
+		  }
+		/* At end of register contents => success */
+		if (d2 == dend2) break;
+
+		/* If necessary, advance to next segment in data.  */
+		PREFETCH ();
+
+		/* How many characters left in this segment to match.  */
+		mcnt = dend - d;
+                
+		/* Want how many consecutive characters we can match in
+                   one shot, so, if necessary, adjust the count.  */
+                if (mcnt > dend2 - d2)
+		  mcnt = dend2 - d2;
+                  
+		/* Compare that many; failure if mismatch, else move
+                   past them.  */
+		if (translate 
+                    ? bcmp_translate (d, d2, mcnt, translate) 
+                    : bcmp (d, d2, mcnt))
+		  goto fail;
+		d += mcnt, d2 += mcnt;
+
+		/* Do this because we've match some characters.  */
+		SET_REGS_MATCHED ();
+	      }
+	  }
+	  break;
+
+
+        /* begline matches the empty string at the beginning of the string
+           (unless `not_bol' is set in `bufp'), and, if
+           `newline_anchor' is set, after newlines.  */
+	case begline:
+          DEBUG_PRINT1 ("EXECUTING begline.\n");
+          
+          if (AT_STRINGS_BEG (d))
+            {
+              if (!bufp->not_bol) break;
+            }
+          else if (d[-1] == '\n' && bufp->newline_anchor)
+            {
+              break;
+            }
+          /* In all other cases, we fail.  */
+          goto fail;
+
+
+        /* endline is the dual of begline.  */
+	case endline:
+          DEBUG_PRINT1 ("EXECUTING endline.\n");
+
+          if (AT_STRINGS_END (d))
+            {
+              if (!bufp->not_eol) break;
+            }
+          
+          /* We have to ``prefetch'' the next character.  */
+          else if ((d == end1 ? *string2 : *d) == '\n'
+                   && bufp->newline_anchor)
+            {
+              break;
+            }
+          goto fail;
+
+
+	/* Match at the very beginning of the data.  */
+        case begbuf:
+          DEBUG_PRINT1 ("EXECUTING begbuf.\n");
+          if (AT_STRINGS_BEG (d))
+            break;
+          goto fail;
+
+
+	/* Match at the very end of the data.  */
+        case endbuf:
+          DEBUG_PRINT1 ("EXECUTING endbuf.\n");
+	  if (AT_STRINGS_END (d))
+	    break;
+          goto fail;
+
+
+        /* on_failure_keep_string_jump is used to optimize `.*\n'.  It
+           pushes NULL as the value for the string on the stack.  Then
+           `pop_failure_point' will keep the current value for the
+           string, instead of restoring it.  To see why, consider
+           matching `foo\nbar' against `.*\n'.  The .* matches the foo;
+           then the . fails against the \n.  But the next thing we want
+           to do is match the \n against the \n; if we restored the
+           string value, we would be back at the foo.
+           
+           Because this is used only in specific cases, we don't need to
+           check all the things that `on_failure_jump' does, to make
+           sure the right things get saved on the stack.  Hence we don't
+           share its code.  The only reason to push anything on the
+           stack at all is that otherwise we would have to change
+           `anychar's code to do something besides goto fail in this
+           case; that seems worse than this.  */
+        case on_failure_keep_string_jump:
+          DEBUG_PRINT1 ("EXECUTING on_failure_keep_string_jump");
+          
+          EXTRACT_NUMBER_AND_INCR (mcnt, p);
+          DEBUG_PRINT3 (" %d (to 0x%x):\n", mcnt, p + mcnt);
+
+          PUSH_FAILURE_POINT (p + mcnt, NULL, -2);
+          break;
+
+
+	/* Uses of on_failure_jump:
+        
+           Each alternative starts with an on_failure_jump that points
+           to the beginning of the next alternative.  Each alternative
+           except the last ends with a jump that in effect jumps past
+           the rest of the alternatives.  (They really jump to the
+           ending jump of the following alternative, because tensioning
+           these jumps is a hassle.)
+
+           Repeats start with an on_failure_jump that points past both
+           the repetition text and either the following jump or
+           pop_failure_jump back to this on_failure_jump.  */
+	case on_failure_jump:
+        on_failure:
+          DEBUG_PRINT1 ("EXECUTING on_failure_jump");
+
+          EXTRACT_NUMBER_AND_INCR (mcnt, p);
+          DEBUG_PRINT3 (" %d (to 0x%x)", mcnt, p + mcnt);
+
+          /* If this on_failure_jump comes right before a group (i.e.,
+             the original * applied to a group), save the information
+             for that group and all inner ones, so that if we fail back
+             to this point, the group's information will be correct.
+             For example, in \(a*\)*\1, we need the preceding group,
+             and in \(\(a*\)b*\)\2, we need the inner group.  */
+
+          /* We can't use `p' to check ahead because we push
+             a failure point to `p + mcnt' after we do this.  */
+          p1 = p;
+
+          /* We need to skip no_op's before we look for the
+             start_memory in case this on_failure_jump is happening as
+             the result of a completed succeed_n, as in \(a\)\{1,3\}b\1
+             against aba.  */
+          while (p1 < pend && (re_opcode_t) *p1 == no_op)
+            p1++;
+
+          if (p1 < pend && (re_opcode_t) *p1 == start_memory)
+            {
+              /* We have a new highest active register now.  This will
+                 get reset at the start_memory we are about to get to,
+                 but we will have saved all the registers relevant to
+                 this repetition op, as described above.  */
+              highest_active_reg = *(p1 + 1) + *(p1 + 2);
+              if (lowest_active_reg == NO_LOWEST_ACTIVE_REG)
+                lowest_active_reg = *(p1 + 1);
+            }
+
+          DEBUG_PRINT1 (":\n");
+          PUSH_FAILURE_POINT (p + mcnt, d, -2);
+          break;
+
+
+        /* A smart repeat ends with `maybe_pop_jump'.
+	   We change it to either `pop_failure_jump' or `jump'.  */
+        case maybe_pop_jump:
+          EXTRACT_NUMBER_AND_INCR (mcnt, p);
+          DEBUG_PRINT2 ("EXECUTING maybe_pop_jump %d.\n", mcnt);
+          {
+	    register unsigned char *p2 = p;
+
+            /* Compare the beginning of the repeat with what in the
+               pattern follows its end. If we can establish that there
+               is nothing that they would both match, i.e., that we
+               would have to backtrack because of (as in, e.g., `a*a')
+               then we can change to pop_failure_jump, because we'll
+               never have to backtrack.
+               
+               This is not true in the case of alternatives: in
+               `(a|ab)*' we do need to backtrack to the `ab' alternative
+               (e.g., if the string was `ab').  But instead of trying to
+               detect that here, the alternative has put on a dummy
+               failure point which is what we will end up popping.  */
+
+	    /* Skip over open/close-group commands.
+	       If what follows this loop is a ...+ construct,
+	       look at what begins its body, since we will have to
+	       match at least one of that.  */
+	    while (1)
+	      {
+		if (p2 + 2 < pend
+		    && ((re_opcode_t) *p2 == stop_memory
+			|| (re_opcode_t) *p2 == start_memory))
+		  p2 += 3;
+		else if (p2 + 6 < pend
+			 && (re_opcode_t) *p2 == dummy_failure_jump)
+		  p2 += 6;
+		else
+		  break;
+	      }
+
+	    p1 = p + mcnt;
+	    /* p1[0] ... p1[2] are the `on_failure_jump' corresponding
+	       to the `maybe_finalize_jump' of this case.  Examine what 
+	       follows.  */
+
+            /* If we're at the end of the pattern, we can change.  */
+            if (p2 == pend)
+	      {
+		/* Consider what happens when matching ":\(.*\)"
+		   against ":/".  I don't really understand this code
+		   yet.  */
+  	        p[-3] = (unsigned char) pop_failure_jump;
+                DEBUG_PRINT1
+                  ("  End of pattern: change to `pop_failure_jump'.\n");
+              }
+
+            else if ((re_opcode_t) *p2 == exactn
+		     || (bufp->newline_anchor && (re_opcode_t) *p2 == endline))
+	      {
+		register unsigned char c
+                  = *p2 == (unsigned char) endline ? '\n' : p2[2];
+
+                if ((re_opcode_t) p1[3] == exactn && p1[5] != c)
+                  {
+  		    p[-3] = (unsigned char) pop_failure_jump;
+                    DEBUG_PRINT3 ("  %c != %c => pop_failure_jump.\n",
+                                  c, p1[5]);
+                  }
+                  
+		else if ((re_opcode_t) p1[3] == charset
+			 || (re_opcode_t) p1[3] == charset_not)
+		  {
+		    int not = (re_opcode_t) p1[3] == charset_not;
+                    
+		    if (c < (unsigned char) (p1[4] * BYTEWIDTH)
+			&& p1[5 + c / BYTEWIDTH] & (1 << (c % BYTEWIDTH)))
+		      not = !not;
+
+                    /* `not' is equal to 1 if c would match, which means
+                        that we can't change to pop_failure_jump.  */
+		    if (!not)
+                      {
+  		        p[-3] = (unsigned char) pop_failure_jump;
+                        DEBUG_PRINT1 ("  No match => pop_failure_jump.\n");
+                      }
+		  }
+	      }
+            else if ((re_opcode_t) *p2 == charset)
+	      {
+#ifdef DEBUG
+		register unsigned char c
+                  = *p2 == (unsigned char) endline ? '\n' : p2[2];
+#endif
+
+                if ((re_opcode_t) p1[3] == exactn
+		    && ! ((int) p2[1] * BYTEWIDTH > (int) p1[4]
+			  && (p2[1 + p1[4] / BYTEWIDTH]
+			      & (1 << (p1[4] % BYTEWIDTH)))))
+                  {
+  		    p[-3] = (unsigned char) pop_failure_jump;
+                    DEBUG_PRINT3 ("  %c != %c => pop_failure_jump.\n",
+                                  c, p1[5]);
+                  }
+                  
+		else if ((re_opcode_t) p1[3] == charset_not)
+		  {
+		    int idx;
+		    /* We win if the charset_not inside the loop
+		       lists every character listed in the charset after.  */
+		    for (idx = 0; idx < (int) p2[1]; idx++)
+		      if (! (p2[2 + idx] == 0
+			     || (idx < (int) p1[4]
+				 && ((p2[2 + idx] & ~ p1[5 + idx]) == 0))))
+			break;
+
+		    if (idx == p2[1])
+                      {
+  		        p[-3] = (unsigned char) pop_failure_jump;
+                        DEBUG_PRINT1 ("  No match => pop_failure_jump.\n");
+                      }
+		  }
+		else if ((re_opcode_t) p1[3] == charset)
+		  {
+		    int idx;
+		    /* We win if the charset inside the loop
+		       has no overlap with the one after the loop.  */
+		    for (idx = 0;
+			 idx < (int) p2[1] && idx < (int) p1[4];
+			 idx++)
+		      if ((p2[2 + idx] & p1[5 + idx]) != 0)
+			break;
+
+		    if (idx == p2[1] || idx == p1[4])
+                      {
+  		        p[-3] = (unsigned char) pop_failure_jump;
+                        DEBUG_PRINT1 ("  No match => pop_failure_jump.\n");
+                      }
+		  }
+	      }
+	  }
+	  p -= 2;		/* Point at relative address again.  */
+	  if ((re_opcode_t) p[-1] != pop_failure_jump)
+	    {
+	      p[-1] = (unsigned char) jump;
+              DEBUG_PRINT1 ("  Match => jump.\n");
+	      goto unconditional_jump;
+	    }
+        /* Note fall through.  */
+
+
+	/* The end of a simple repeat has a pop_failure_jump back to
+           its matching on_failure_jump, where the latter will push a
+           failure point.  The pop_failure_jump takes off failure
+           points put on by this pop_failure_jump's matching
+           on_failure_jump; we got through the pattern to here from the
+           matching on_failure_jump, so didn't fail.  */
+        case pop_failure_jump:
+          {
+            /* We need to pass separate storage for the lowest and
+               highest registers, even though we don't care about the
+               actual values.  Otherwise, we will restore only one
+               register from the stack, since lowest will == highest in
+               `pop_failure_point'.  */
+            unsigned dummy_low_reg, dummy_high_reg;
+            unsigned char *pdummy;
+            const char *sdummy;
+
+            DEBUG_PRINT1 ("EXECUTING pop_failure_jump.\n");
+            POP_FAILURE_POINT (sdummy, pdummy,
+                               dummy_low_reg, dummy_high_reg,
+                               reg_dummy, reg_dummy, reg_info_dummy);
+          }
+          /* Note fall through.  */
+
+          
+        /* Unconditionally jump (without popping any failure points).  */
+        case jump:
+	unconditional_jump:
+	  EXTRACT_NUMBER_AND_INCR (mcnt, p);	/* Get the amount to jump.  */
+          DEBUG_PRINT2 ("EXECUTING jump %d ", mcnt);
+	  p += mcnt;				/* Do the jump.  */
+          DEBUG_PRINT2 ("(to 0x%x).\n", p);
+	  break;
+
+	
+        /* We need this opcode so we can detect where alternatives end
+           in `group_match_null_string_p' et al.  */
+        case jump_past_alt:
+          DEBUG_PRINT1 ("EXECUTING jump_past_alt.\n");
+          goto unconditional_jump;
+
+
+        /* Normally, the on_failure_jump pushes a failure point, which
+           then gets popped at pop_failure_jump.  We will end up at
+           pop_failure_jump, also, and with a pattern of, say, `a+', we
+           are skipping over the on_failure_jump, so we have to push
+           something meaningless for pop_failure_jump to pop.  */
+        case dummy_failure_jump:
+          DEBUG_PRINT1 ("EXECUTING dummy_failure_jump.\n");
+          /* It doesn't matter what we push for the string here.  What
+             the code at `fail' tests is the value for the pattern.  */
+          PUSH_FAILURE_POINT (0, 0, -2);
+          goto unconditional_jump;
+
+
+        /* At the end of an alternative, we need to push a dummy failure
+           point in case we are followed by a `pop_failure_jump', because
+           we don't want the failure point for the alternative to be
+           popped.  For example, matching `(a|ab)*' against `aab'
+           requires that we match the `ab' alternative.  */
+        case push_dummy_failure:
+          DEBUG_PRINT1 ("EXECUTING push_dummy_failure.\n");
+          /* See comments just above at `dummy_failure_jump' about the
+             two zeroes.  */
+          PUSH_FAILURE_POINT (0, 0, -2);
+          break;
+
+        /* Have to succeed matching what follows at least n times.
+           After that, handle like `on_failure_jump'.  */
+        case succeed_n: 
+          EXTRACT_NUMBER (mcnt, p + 2);
+          DEBUG_PRINT2 ("EXECUTING succeed_n %d.\n", mcnt);
+
+          assert (mcnt >= 0);
+          /* Originally, this is how many times we HAVE to succeed.  */
+          if (mcnt > 0)
+            {
+               mcnt--;
+	       p += 2;
+               STORE_NUMBER_AND_INCR (p, mcnt);
+               DEBUG_PRINT3 ("  Setting 0x%x to %d.\n", p, mcnt);
+            }
+	  else if (mcnt == 0)
+            {
+              DEBUG_PRINT2 ("  Setting two bytes from 0x%x to no_op.\n", p+2);
+	      p[2] = (unsigned char) no_op;
+              p[3] = (unsigned char) no_op;
+              goto on_failure;
+            }
+          break;
+        
+        case jump_n: 
+          EXTRACT_NUMBER (mcnt, p + 2);
+          DEBUG_PRINT2 ("EXECUTING jump_n %d.\n", mcnt);
+
+          /* Originally, this is how many times we CAN jump.  */
+          if (mcnt)
+            {
+               mcnt--;
+               STORE_NUMBER (p + 2, mcnt);
+	       goto unconditional_jump;	     
+            }
+          /* If don't have to jump any more, skip over the rest of command.  */
+	  else      
+	    p += 4;		     
+          break;
+        
+	case set_number_at:
+	  {
+            DEBUG_PRINT1 ("EXECUTING set_number_at.\n");
+
+            EXTRACT_NUMBER_AND_INCR (mcnt, p);
+            p1 = p + mcnt;
+            EXTRACT_NUMBER_AND_INCR (mcnt, p);
+            DEBUG_PRINT3 ("  Setting 0x%x to %d.\n", p1, mcnt);
+	    STORE_NUMBER (p1, mcnt);
+            break;
+          }
+
+        case wordbound:
+          DEBUG_PRINT1 ("EXECUTING wordbound.\n");
+          if (AT_WORD_BOUNDARY (d))
+	    break;
+          goto fail;
+
+	case notwordbound:
+          DEBUG_PRINT1 ("EXECUTING notwordbound.\n");
+	  if (AT_WORD_BOUNDARY (d))
+	    goto fail;
+          break;
+
+	case wordbeg:
+          DEBUG_PRINT1 ("EXECUTING wordbeg.\n");
+	  if (WORDCHAR_P (d) && (AT_STRINGS_BEG (d) || !WORDCHAR_P (d - 1)))
+	    break;
+          goto fail;
+
+	case wordend:
+          DEBUG_PRINT1 ("EXECUTING wordend.\n");
+	  if (!AT_STRINGS_BEG (d) && WORDCHAR_P (d - 1)
+              && (!WORDCHAR_P (d) || AT_STRINGS_END (d)))
+	    break;
+          goto fail;
+
+#ifdef emacs
+  	case before_dot:
+          DEBUG_PRINT1 ("EXECUTING before_dot.\n");
+ 	  if (PTR_CHAR_POS ((unsigned char *) d) >= point)
+  	    goto fail;
+  	  break;
+  
+  	case at_dot:
+          DEBUG_PRINT1 ("EXECUTING at_dot.\n");
+ 	  if (PTR_CHAR_POS ((unsigned char *) d) != point)
+  	    goto fail;
+  	  break;
+  
+  	case after_dot:
+          DEBUG_PRINT1 ("EXECUTING after_dot.\n");
+          if (PTR_CHAR_POS ((unsigned char *) d) <= point)
+  	    goto fail;
+  	  break;
+#if 0 /* not emacs19 */
+	case at_dot:
+          DEBUG_PRINT1 ("EXECUTING at_dot.\n");
+	  if (PTR_CHAR_POS ((unsigned char *) d) + 1 != point)
+	    goto fail;
+	  break;
+#endif /* not emacs19 */
+
+	case syntaxspec:
+          DEBUG_PRINT2 ("EXECUTING syntaxspec %d.\n", mcnt);
+	  mcnt = *p++;
+	  goto matchsyntax;
+
+        case wordchar:
+          DEBUG_PRINT1 ("EXECUTING Emacs wordchar.\n");
+	  mcnt = (int) Sword;
+        matchsyntax:
+	  PREFETCH ();
+	  /* Can't use *d++ here; SYNTAX may be an unsafe macro.  */
+	  d++;
+	  if (SYNTAX (d[-1]) != (enum syntaxcode) mcnt)
+	    goto fail;
+          SET_REGS_MATCHED ();
+	  break;
+
+	case notsyntaxspec:
+          DEBUG_PRINT2 ("EXECUTING notsyntaxspec %d.\n", mcnt);
+	  mcnt = *p++;
+	  goto matchnotsyntax;
+
+        case notwordchar:
+          DEBUG_PRINT1 ("EXECUTING Emacs notwordchar.\n");
+	  mcnt = (int) Sword;
+        matchnotsyntax:
+	  PREFETCH ();
+	  /* Can't use *d++ here; SYNTAX may be an unsafe macro.  */
+	  d++;
+	  if (SYNTAX (d[-1]) == (enum syntaxcode) mcnt)
+	    goto fail;
+	  SET_REGS_MATCHED ();
+          break;
+
+#else /* not emacs */
+	case wordchar:
+          DEBUG_PRINT1 ("EXECUTING non-Emacs wordchar.\n");
+	  PREFETCH ();
+          if (!WORDCHAR_P (d))
+            goto fail;
+	  SET_REGS_MATCHED ();
+          d++;
+	  break;
+	  
+	case notwordchar:
+          DEBUG_PRINT1 ("EXECUTING non-Emacs notwordchar.\n");
+	  PREFETCH ();
+	  if (WORDCHAR_P (d))
+            goto fail;
+          SET_REGS_MATCHED ();
+          d++;
+	  break;
+#endif /* not emacs */
+          
+        default:
+          abort ();
+	}
+      continue;  /* Successfully executed one pattern command; keep going.  */
+
+
+    /* We goto here if a matching operation fails. */
+    fail:
+      if (!FAIL_STACK_EMPTY ())
+	{ /* A restart point is known.  Restore to that state.  */
+          DEBUG_PRINT1 ("\nFAIL:\n");
+          POP_FAILURE_POINT (d, p,
+                             lowest_active_reg, highest_active_reg,
+                             regstart, regend, reg_info);
+
+          /* If this failure point is a dummy, try the next one.  */
+          if (!p)
+	    goto fail;
+
+          /* If we failed to the end of the pattern, don't examine *p.  */
+	  assert (p <= pend);
+          if (p < pend)
+            {
+              boolean is_a_jump_n = false;
+              
+              /* If failed to a backwards jump that's part of a repetition
+                 loop, need to pop this failure point and use the next one.  */
+              switch ((re_opcode_t) *p)
+                {
+                case jump_n:
+                  is_a_jump_n = true;
+                case maybe_pop_jump:
+                case pop_failure_jump:
+                case jump:
+                  p1 = p + 1;
+                  EXTRACT_NUMBER_AND_INCR (mcnt, p1);
+                  p1 += mcnt;	
+
+                  if ((is_a_jump_n && (re_opcode_t) *p1 == succeed_n)
+                      || (!is_a_jump_n
+                          && (re_opcode_t) *p1 == on_failure_jump))
+                    goto fail;
+                  break;
+                default:
+                  /* do nothing */ ;
+                }
+            }
+
+          if (d >= string1 && d <= end1)
+	    dend = end_match_1;
+        }
+      else
+        break;   /* Matching at this starting point really fails.  */
+    } /* for (;;) */
+
+  if (best_regs_set)
+    goto restore_best_regs;
+
+  FREE_VARIABLES ();
+
+  return -1;         			/* Failure to match.  */
+} /* re_match_2 */
+
+
+/* Subroutine definitions for re_match_2.  */
+
+
+/* We are passed P pointing to a register number after a start_memory.
+   
+   Return true if the pattern up to the corresponding stop_memory can
+   match the empty string, and false otherwise.
+   
+   If we find the matching stop_memory, sets P to point to one past its number.
+   Otherwise, sets P to an undefined byte less than or equal to END.
+
+   We don't handle duplicates properly (yet).  */
+
+static boolean
+group_match_null_string_p (p, end, reg_info)
+    unsigned char **p, *end;
+    register_info_type *reg_info;
+{
+  int mcnt;
+  /* Point to after the args to the start_memory.  */
+  unsigned char *p1 = *p + 2;
+  
+  while (p1 < end)
+    {
+      /* Skip over opcodes that can match nothing, and return true or
+	 false, as appropriate, when we get to one that can't, or to the
+         matching stop_memory.  */
+      
+      switch ((re_opcode_t) *p1)
+        {
+        /* Could be either a loop or a series of alternatives.  */
+        case on_failure_jump:
+          p1++;
+          EXTRACT_NUMBER_AND_INCR (mcnt, p1);
+          
+          /* If the next operation is not a jump backwards in the
+	     pattern.  */
+
+	  if (mcnt >= 0)
+	    {
+              /* Go through the on_failure_jumps of the alternatives,
+                 seeing if any of the alternatives cannot match nothing.
+                 The last alternative starts with only a jump,
+                 whereas the rest start with on_failure_jump and end
+                 with a jump, e.g., here is the pattern for `a|b|c':
+
+                 /on_failure_jump/0/6/exactn/1/a/jump_past_alt/0/6
+                 /on_failure_jump/0/6/exactn/1/b/jump_past_alt/0/3
+                 /exactn/1/c						
+
+                 So, we have to first go through the first (n-1)
+                 alternatives and then deal with the last one separately.  */
+
+
+              /* Deal with the first (n-1) alternatives, which start
+                 with an on_failure_jump (see above) that jumps to right
+                 past a jump_past_alt.  */
+
+              while ((re_opcode_t) p1[mcnt-3] == jump_past_alt)
+                {
+                  /* `mcnt' holds how many bytes long the alternative
+                     is, including the ending `jump_past_alt' and
+                     its number.  */
+
+                  if (!alt_match_null_string_p (p1, p1 + mcnt - 3, 
+				                      reg_info))
+                    return false;
+
+                  /* Move to right after this alternative, including the
+		     jump_past_alt.  */
+                  p1 += mcnt;	
+
+                  /* Break if it's the beginning of an n-th alternative
+                     that doesn't begin with an on_failure_jump.  */
+                  if ((re_opcode_t) *p1 != on_failure_jump)
+                    break;
+		
+		  /* Still have to check that it's not an n-th
+		     alternative that starts with an on_failure_jump.  */
+		  p1++;
+                  EXTRACT_NUMBER_AND_INCR (mcnt, p1);
+                  if ((re_opcode_t) p1[mcnt-3] != jump_past_alt)
+                    {
+		      /* Get to the beginning of the n-th alternative.  */
+                      p1 -= 3;
+                      break;
+                    }
+                }
+
+              /* Deal with the last alternative: go back and get number
+                 of the `jump_past_alt' just before it.  `mcnt' contains
+                 the length of the alternative.  */
+              EXTRACT_NUMBER (mcnt, p1 - 2);
+
+              if (!alt_match_null_string_p (p1, p1 + mcnt, reg_info))
+                return false;
+
+              p1 += mcnt;	/* Get past the n-th alternative.  */
+            } /* if mcnt > 0 */
+          break;
+
+          
+        case stop_memory:
+	  assert (p1[1] == **p);
+          *p = p1 + 2;
+          return true;
+
+        
+        default: 
+          if (!common_op_match_null_string_p (&p1, end, reg_info))
+            return false;
+        }
+    } /* while p1 < end */
+
+  return false;
+} /* group_match_null_string_p */
+
+
+/* Similar to group_match_null_string_p, but doesn't deal with alternatives:
+   It expects P to be the first byte of a single alternative and END one
+   byte past the last. The alternative can contain groups.  */
+   
+static boolean
+alt_match_null_string_p (p, end, reg_info)
+    unsigned char *p, *end;
+    register_info_type *reg_info;
+{
+  int mcnt;
+  unsigned char *p1 = p;
+  
+  while (p1 < end)
+    {
+      /* Skip over opcodes that can match nothing, and break when we get 
+         to one that can't.  */
+      
+      switch ((re_opcode_t) *p1)
+        {
+	/* It's a loop.  */
+        case on_failure_jump:
+          p1++;
+          EXTRACT_NUMBER_AND_INCR (mcnt, p1);
+          p1 += mcnt;
+          break;
+          
+	default: 
+          if (!common_op_match_null_string_p (&p1, end, reg_info))
+            return false;
+        }
+    }  /* while p1 < end */
+
+  return true;
+} /* alt_match_null_string_p */
+
+
+/* Deals with the ops common to group_match_null_string_p and
+   alt_match_null_string_p.  
+   
+   Sets P to one after the op and its arguments, if any.  */
+
+static boolean
+common_op_match_null_string_p (p, end, reg_info)
+    unsigned char **p, *end;
+    register_info_type *reg_info;
+{
+  int mcnt;
+  boolean ret;
+  int reg_no;
+  unsigned char *p1 = *p;
+
+  switch ((re_opcode_t) *p1++)
+    {
+    case no_op:
+    case begline:
+    case endline:
+    case begbuf:
+    case endbuf:
+    case wordbeg:
+    case wordend:
+    case wordbound:
+    case notwordbound:
+#ifdef emacs
+    case before_dot:
+    case at_dot:
+    case after_dot:
+#endif
+      break;
+
+    case start_memory:
+      reg_no = *p1;
+      assert (reg_no > 0 && reg_no <= MAX_REGNUM);
+      ret = group_match_null_string_p (&p1, end, reg_info);
+      
+      /* Have to set this here in case we're checking a group which
+         contains a group and a back reference to it.  */
+
+      if (REG_MATCH_NULL_STRING_P (reg_info[reg_no]) == MATCH_NULL_UNSET_VALUE)
+        REG_MATCH_NULL_STRING_P (reg_info[reg_no]) = ret;
+
+      if (!ret)
+        return false;
+      break;
+          
+    /* If this is an optimized succeed_n for zero times, make the jump.  */
+    case jump:
+      EXTRACT_NUMBER_AND_INCR (mcnt, p1);
+      if (mcnt >= 0)
+        p1 += mcnt;
+      else
+        return false;
+      break;
+
+    case succeed_n:
+      /* Get to the number of times to succeed.  */
+      p1 += 2;		
+      EXTRACT_NUMBER_AND_INCR (mcnt, p1);
+
+      if (mcnt == 0)
+        {
+          p1 -= 4;
+          EXTRACT_NUMBER_AND_INCR (mcnt, p1);
+          p1 += mcnt;
+        }
+      else
+        return false;
+      break;
+
+    case duplicate: 
+      if (!REG_MATCH_NULL_STRING_P (reg_info[*p1]))
+        return false;
+      break;
+
+    case set_number_at:
+      p1 += 4;
+
+    default:
+      /* All other opcodes mean we cannot match the empty string.  */
+      return false;
+  }
+
+  *p = p1;
+  return true;
+} /* common_op_match_null_string_p */
+
+
+/* Return zero if TRANSLATE[S1] and TRANSLATE[S2] are identical for LEN
+   bytes; nonzero otherwise.  */
+   
+static int
+bcmp_translate (s1, s2, len, translate)
+     unsigned char *s1, *s2;
+     register int len;
+     char *translate;
+{
+  register unsigned char *p1 = s1, *p2 = s2;
+  while (len)
+    {
+      if (translate[*p1++] != translate[*p2++]) return 1;
+      len--;
+    }
+  return 0;
+}
+
+
+/* Entry points for GNU code.  */
+
+/* re_compile_pattern is the GNU regular expression compiler: it
+   compiles PATTERN (of length SIZE) and puts the result in BUFP.
+   Returns 0 if the pattern was valid, otherwise an error string.
+   
+   Assumes the `allocated' (and perhaps `buffer') and `translate' fields
+   are set in BUFP on entry.
+   
+   We call regex_compile to do the actual compilation.  */
+
+const char *
+re_compile_pattern (pattern, length, bufp)
+     const char *pattern;
+     int length;
+     struct re_pattern_buffer *bufp;
+{
+  reg_errcode_t ret;
+  
+  /* GNU code is written to assume at least RE_NREGS registers will be set
+     (and at least one extra will be -1).  */
+  bufp->regs_allocated = REGS_UNALLOCATED;
+  
+  /* And GNU code determines whether or not to get register information
+     by passing null for the REGS argument to re_match, etc., not by
+     setting no_sub.  */
+  bufp->no_sub = 0;
+  
+  /* Match anchors at newline.  */
+  bufp->newline_anchor = 1;
+  
+  ret = regex_compile (pattern, length, re_syntax_options, bufp);
+
+  if (!ret)
+    return NULL;
+  return gettext (re_error_msgid[(int) ret]);
+}     
+
+
+/* Entry points compatible with 4.2 BSD regex library.  We don't define
+   them unless specifically requested.  */
+
+#ifdef _REGEX_RE_COMP
+
+/* BSD has one and only one pattern buffer.  */
+static struct re_pattern_buffer re_comp_buf;
+
+char *
+re_comp (s)
+    const char *s;
+{
+  reg_errcode_t ret;
+  
+  if (!s)
+    {
+      if (!re_comp_buf.buffer)
+	return gettext ("No previous regular expression");
+      return 0;
+    }
+
+  if (!re_comp_buf.buffer)
+    {
+      re_comp_buf.buffer = (unsigned char *) malloc (200);
+      if (re_comp_buf.buffer == NULL)
+        return gettext (re_error_msgid[(int) REG_ESPACE]);
+      re_comp_buf.allocated = 200;
+
+      re_comp_buf.fastmap = (char *) malloc (1 << BYTEWIDTH);
+      if (re_comp_buf.fastmap == NULL)
+	return gettext (re_error_msgid[(int) REG_ESPACE]);
+    }
+
+  /* Since `re_exec' always passes NULL for the `regs' argument, we
+     don't need to initialize the pattern buffer fields which affect it.  */
+
+  /* Match anchors at newlines.  */
+  re_comp_buf.newline_anchor = 1;
+
+  ret = regex_compile (s, strlen (s), re_syntax_options, &re_comp_buf);
+  
+  if (!ret)
+    return NULL;
+
+  /* Yes, we're discarding `const' here if !HAVE_LIBINTL.  */
+  return (char *) gettext (re_error_msgid[(int) ret]);
+}
+
+
+int
+re_exec (s)
+    const char *s;
+{
+  const int len = strlen (s);
+  return
+    0 <= re_search (&re_comp_buf, s, len, 0, len, (struct re_registers *) 0);
+}
+#endif /* _REGEX_RE_COMP */
+
+
+/* POSIX.2 functions.  Don't define these for Emacs.  */
+
+#ifndef emacs
+
+/* regcomp takes a regular expression as a string and compiles it.
+
+   PREG is a regex_t *.  We do not expect any fields to be initialized,
+   since POSIX says we shouldn't.  Thus, we set
+
+     `buffer' to the compiled pattern;
+     `used' to the length of the compiled pattern;
+     `syntax' to RE_SYNTAX_POSIX_EXTENDED if the
+       REG_EXTENDED bit in CFLAGS is set; otherwise, to
+       RE_SYNTAX_POSIX_BASIC;
+     `newline_anchor' to REG_NEWLINE being set in CFLAGS;
+     `fastmap' and `fastmap_accurate' to zero;
+     `re_nsub' to the number of subexpressions in PATTERN.
+
+   PATTERN is the address of the pattern string.
+
+   CFLAGS is a series of bits which affect compilation.
+
+     If REG_EXTENDED is set, we use POSIX extended syntax; otherwise, we
+     use POSIX basic syntax.
+
+     If REG_NEWLINE is set, then . and [^...] don't match newline.
+     Also, regexec will try a match beginning after every newline.
+
+     If REG_ICASE is set, then we considers upper- and lowercase
+     versions of letters to be equivalent when matching.
+
+     If REG_NOSUB is set, then when PREG is passed to regexec, that
+     routine will report only success or failure, and nothing about the
+     registers.
+
+   It returns 0 if it succeeds, nonzero if it doesn't.  (See regex.h for
+   the return codes and their meanings.)  */
+
+int
+regcomp (preg, pattern, cflags)
+    regex_t *preg;
+    const char *pattern; 
+    int cflags;
+{
+  reg_errcode_t ret;
+  unsigned syntax
+    = (cflags & REG_EXTENDED) ?
+      RE_SYNTAX_POSIX_EXTENDED : RE_SYNTAX_POSIX_BASIC;
+
+  /* regex_compile will allocate the space for the compiled pattern.  */
+  preg->buffer = 0;
+  preg->allocated = 0;
+  preg->used = 0;
+  
+  /* Don't bother to use a fastmap when searching.  This simplifies the
+     REG_NEWLINE case: if we used a fastmap, we'd have to put all the
+     characters after newlines into the fastmap.  This way, we just try
+     every character.  */
+  preg->fastmap = 0;
+  
+  if (cflags & REG_ICASE)
+    {
+      unsigned i;
+      
+      preg->translate = (char *) malloc (CHAR_SET_SIZE);
+      if (preg->translate == NULL)
+        return (int) REG_ESPACE;
+
+      /* Map uppercase characters to corresponding lowercase ones.  */
+      for (i = 0; i < CHAR_SET_SIZE; i++)
+        preg->translate[i] = ISUPPER (i) ? tolower (i) : i;
+    }
+  else
+    preg->translate = NULL;
+
+  /* If REG_NEWLINE is set, newlines are treated differently.  */
+  if (cflags & REG_NEWLINE)
+    { /* REG_NEWLINE implies neither . nor [^...] match newline.  */
+      syntax &= ~RE_DOT_NEWLINE;
+      syntax |= RE_HAT_LISTS_NOT_NEWLINE;
+      /* It also changes the matching behavior.  */
+      preg->newline_anchor = 1;
+    }
+  else
+    preg->newline_anchor = 0;
+
+  preg->no_sub = !!(cflags & REG_NOSUB);
+
+  /* POSIX says a null character in the pattern terminates it, so we 
+     can use strlen here in compiling the pattern.  */
+  ret = regex_compile (pattern, strlen (pattern), syntax, preg);
+  
+  /* POSIX doesn't distinguish between an unmatched open-group and an
+     unmatched close-group: both are REG_EPAREN.  */
+  if (ret == REG_ERPAREN) ret = REG_EPAREN;
+  
+  return (int) ret;
+}
+
+
+/* regexec searches for a given pattern, specified by PREG, in the
+   string STRING.
+   
+   If NMATCH is zero or REG_NOSUB was set in the cflags argument to
+   `regcomp', we ignore PMATCH.  Otherwise, we assume PMATCH has at
+   least NMATCH elements, and we set them to the offsets of the
+   corresponding matched substrings.
+   
+   EFLAGS specifies `execution flags' which affect matching: if
+   REG_NOTBOL is set, then ^ does not match at the beginning of the
+   string; if REG_NOTEOL is set, then $ does not match at the end.
+   
+   We return 0 if we find a match and REG_NOMATCH if not.  */
+
+int
+regexec (preg, string, nmatch, pmatch, eflags)
+    const regex_t *preg;
+    const char *string; 
+    size_t nmatch; 
+    regmatch_t pmatch[]; 
+    int eflags;
+{
+  int ret;
+  struct re_registers regs;
+  regex_t private_preg;
+  int len = strlen (string);
+  boolean want_reg_info = !preg->no_sub && nmatch > 0;
+
+  private_preg = *preg;
+  
+  private_preg.not_bol = !!(eflags & REG_NOTBOL);
+  private_preg.not_eol = !!(eflags & REG_NOTEOL);
+  
+  /* The user has told us exactly how many registers to return
+     information about, via `nmatch'.  We have to pass that on to the
+     matching routines.  */
+  private_preg.regs_allocated = REGS_FIXED;
+  
+  if (want_reg_info)
+    {
+      regs.num_regs = nmatch;
+      regs.start = TALLOC (nmatch, regoff_t);
+      regs.end = TALLOC (nmatch, regoff_t);
+      if (regs.start == NULL || regs.end == NULL)
+        return (int) REG_NOMATCH;
+    }
+
+  /* Perform the searching operation.  */
+  ret = re_search (&private_preg, string, len,
+                   /* start: */ 0, /* range: */ len,
+                   want_reg_info ? &regs : (struct re_registers *) 0);
+  
+  /* Copy the register information to the POSIX structure.  */
+  if (want_reg_info)
+    {
+      if (ret >= 0)
+        {
+          unsigned r;
+
+          for (r = 0; r < nmatch; r++)
+            {
+              pmatch[r].rm_so = regs.start[r];
+              pmatch[r].rm_eo = regs.end[r];
+            }
+        }
+
+      /* If we needed the temporary register info, free the space now.  */
+      free (regs.start);
+      free (regs.end);
+    }
+
+  /* We want zero return to mean success, unlike `re_search'.  */
+  return ret >= 0 ? (int) REG_NOERROR : (int) REG_NOMATCH;
+}
+
+
+/* Returns a message corresponding to an error code, ERRCODE, returned
+   from either regcomp or regexec.   We don't use PREG here.  */
+
+size_t
+regerror (errcode, preg, errbuf, errbuf_size)
+    int errcode;
+    const regex_t *preg;
+    char *errbuf;
+    size_t errbuf_size;
+{
+  const char *msg;
+  size_t msg_size;
+
+  if (errcode < 0
+      || errcode >= (sizeof (re_error_msgid) / sizeof (re_error_msgid[0])))
+    /* Only error codes returned by the rest of the code should be passed 
+       to this routine.  If we are given anything else, or if other regex
+       code generates an invalid error code, then the program has a bug.
+       Dump core so we can fix it.  */
+    abort ();
+
+  msg = gettext (re_error_msgid[errcode]);
+
+  msg_size = strlen (msg) + 1; /* Includes the null.  */
+  
+  if (errbuf_size != 0)
+    {
+      if (msg_size > errbuf_size)
+        {
+          strncpy (errbuf, msg, errbuf_size - 1);
+          errbuf[errbuf_size - 1] = 0;
+        }
+      else
+        strcpy (errbuf, msg);
+    }
+
+  return msg_size;
+}
+
+
+/* Free dynamically allocated space used by PREG.  */
+
+void
+regfree (preg)
+    regex_t *preg;
+{
+  if (preg->buffer != NULL)
+    free (preg->buffer);
+  preg->buffer = NULL;
+  
+  preg->allocated = 0;
+  preg->used = 0;
+
+  if (preg->fastmap != NULL)
+    free (preg->fastmap);
+  preg->fastmap = NULL;
+  preg->fastmap_accurate = 0;
+
+  if (preg->translate != NULL)
+    free (preg->translate);
+  preg->translate = NULL;
+}
+
+#endif /* not emacs  */
+
+
+/*
+Local variables:
+make-backup-files: t
+version-control: t
+trim-versions-without-asking: nil
+End:
+*/
Index: /main/tags/2.25/gsdl/packages/mg/lib/regex.h
===================================================================
--- /main/tags/2.25/gsdl/packages/mg/lib/regex.h	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/mg/lib/regex.h	(revision 21064)
@@ -0,0 +1,497 @@
+/* Definitions for data structures and routines for the regular
+   expression library, version 0.12.
+
+   Copyright (C) 1985, 89, 90, 91, 92, 93, 95 Free Software Foundation, Inc.
+
+   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, 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.  */
+
+#ifndef __REGEXP_LIBRARY_H__
+#define __REGEXP_LIBRARY_H__
+
+/* POSIX says that <sys/types.h> must be included (by the caller) before
+   <regex.h>.  */
+
+#if !defined (_POSIX_C_SOURCE) && !defined (_POSIX_SOURCE) && defined (VMS)
+/* VMS doesn't have `size_t' in <sys/types.h>, even though POSIX says it
+   should be there.  */
+#include <stddef.h>
+#endif
+
+
+/* The following bits are used to determine the regexp syntax we
+   recognize.  The set/not-set meanings are chosen so that Emacs syntax
+   remains the value 0.  The bits are given in alphabetical order, and
+   the definitions shifted by one from the previous bit; thus, when we
+   add or remove a bit, only one other definition need change.  */
+typedef unsigned reg_syntax_t;
+
+/* If this bit is not set, then \ inside a bracket expression is literal.
+   If set, then such a \ quotes the following character.  */
+#define RE_BACKSLASH_ESCAPE_IN_LISTS (1)
+
+/* If this bit is not set, then + and ? are operators, and \+ and \? are
+     literals. 
+   If set, then \+ and \? are operators and + and ? are literals.  */
+#define RE_BK_PLUS_QM (RE_BACKSLASH_ESCAPE_IN_LISTS << 1)
+
+/* If this bit is set, then character classes are supported.  They are:
+     [:alpha:], [:upper:], [:lower:],  [:digit:], [:alnum:], [:xdigit:],
+     [:space:], [:print:], [:punct:], [:graph:], and [:cntrl:].
+   If not set, then character classes are not supported.  */
+#define RE_CHAR_CLASSES (RE_BK_PLUS_QM << 1)
+
+/* If this bit is set, then ^ and $ are always anchors (outside bracket
+     expressions, of course).
+   If this bit is not set, then it depends:
+        ^  is an anchor if it is at the beginning of a regular
+           expression or after an open-group or an alternation operator;
+        $  is an anchor if it is at the end of a regular expression, or
+           before a close-group or an alternation operator.  
+
+   This bit could be (re)combined with RE_CONTEXT_INDEP_OPS, because
+   POSIX draft 11.2 says that * etc. in leading positions is undefined.
+   We already implemented a previous draft which made those constructs
+   invalid, though, so we haven't changed the code back.  */
+#define RE_CONTEXT_INDEP_ANCHORS (RE_CHAR_CLASSES << 1)
+
+/* If this bit is set, then special characters are always special
+     regardless of where they are in the pattern.
+   If this bit is not set, then special characters are special only in
+     some contexts; otherwise they are ordinary.  Specifically, 
+     * + ? and intervals are only special when not after the beginning,
+     open-group, or alternation operator.  */
+#define RE_CONTEXT_INDEP_OPS (RE_CONTEXT_INDEP_ANCHORS << 1)
+
+/* If this bit is set, then *, +, ?, and { cannot be first in an re or
+     immediately after an alternation or begin-group operator.  */
+#define RE_CONTEXT_INVALID_OPS (RE_CONTEXT_INDEP_OPS << 1)
+
+/* If this bit is set, then . matches newline.
+   If not set, then it doesn't.  */
+#define RE_DOT_NEWLINE (RE_CONTEXT_INVALID_OPS << 1)
+
+/* If this bit is set, then . doesn't match NUL.
+   If not set, then it does.  */
+#define RE_DOT_NOT_NULL (RE_DOT_NEWLINE << 1)
+
+/* If this bit is set, nonmatching lists [^...] do not match newline.
+   If not set, they do.  */
+#define RE_HAT_LISTS_NOT_NEWLINE (RE_DOT_NOT_NULL << 1)
+
+/* If this bit is set, either \{...\} or {...} defines an
+     interval, depending on RE_NO_BK_BRACES. 
+   If not set, \{, \}, {, and } are literals.  */
+#define RE_INTERVALS (RE_HAT_LISTS_NOT_NEWLINE << 1)
+
+/* If this bit is set, +, ? and | aren't recognized as operators.
+   If not set, they are.  */
+#define RE_LIMITED_OPS (RE_INTERVALS << 1)
+
+/* If this bit is set, newline is an alternation operator.
+   If not set, newline is literal.  */
+#define RE_NEWLINE_ALT (RE_LIMITED_OPS << 1)
+
+/* If this bit is set, then `{...}' defines an interval, and \{ and \}
+     are literals.
+  If not set, then `\{...\}' defines an interval.  */
+#define RE_NO_BK_BRACES (RE_NEWLINE_ALT << 1)
+
+/* If this bit is set, (...) defines a group, and \( and \) are literals.
+   If not set, \(...\) defines a group, and ( and ) are literals.  */
+#define RE_NO_BK_PARENS (RE_NO_BK_BRACES << 1)
+
+/* If this bit is set, then \<digit> matches <digit>.
+   If not set, then \<digit> is a back-reference.  */
+#define RE_NO_BK_REFS (RE_NO_BK_PARENS << 1)
+
+/* If this bit is set, then | is an alternation operator, and \| is literal. 
+   If not set, then \| is an alternation operator, and | is literal.  */
+#define RE_NO_BK_VBAR (RE_NO_BK_REFS << 1)
+
+/* If this bit is set, then an ending range point collating higher
+     than the starting range point, as in [z-a], is invalid.
+   If not set, then when ending range point collates higher than the
+     starting range point, the range is ignored.  */
+#define RE_NO_EMPTY_RANGES (RE_NO_BK_VBAR << 1)
+
+/* If this bit is set, then an unmatched ) is ordinary.
+   If not set, then an unmatched ) is invalid.  */
+#define RE_UNMATCHED_RIGHT_PAREN_ORD (RE_NO_EMPTY_RANGES << 1)
+
+/* If this bit is set, succeed as soon as we match the whole pattern,
+   without further backtracking.  */
+#define RE_NO_POSIX_BACKTRACKING (RE_UNMATCHED_RIGHT_PAREN_ORD << 1)
+
+/* This global variable defines the particular regexp syntax to use (for
+   some interfaces).  When a regexp is compiled, the syntax used is
+   stored in the pattern buffer, so changing this does not affect
+   already-compiled regexps.  */
+extern reg_syntax_t re_syntax_options;
+
+
+/* Define combinations of the above bits for the standard possibilities.
+   (The [[[ comments delimit what gets put into the Texinfo file, so
+   don't delete them!)  */ 
+/* [[[begin syntaxes]]] */
+#define RE_SYNTAX_EMACS 0
+
+#define RE_SYNTAX_AWK							\
+  (RE_BACKSLASH_ESCAPE_IN_LISTS | RE_DOT_NOT_NULL			\
+   | RE_NO_BK_PARENS            | RE_NO_BK_REFS				\
+   | RE_NO_BK_VBAR               | RE_NO_EMPTY_RANGES			\
+   | RE_UNMATCHED_RIGHT_PAREN_ORD)
+
+#define RE_SYNTAX_POSIX_AWK 						\
+  (RE_SYNTAX_POSIX_EXTENDED | RE_BACKSLASH_ESCAPE_IN_LISTS)
+
+#define RE_SYNTAX_GREP							\
+  (RE_BK_PLUS_QM              | RE_CHAR_CLASSES				\
+   | RE_HAT_LISTS_NOT_NEWLINE | RE_INTERVALS				\
+   | RE_NEWLINE_ALT)
+
+#define RE_SYNTAX_EGREP							\
+  (RE_CHAR_CLASSES        | RE_CONTEXT_INDEP_ANCHORS			\
+   | RE_CONTEXT_INDEP_OPS | RE_HAT_LISTS_NOT_NEWLINE			\
+   | RE_NEWLINE_ALT       | RE_NO_BK_PARENS				\
+   | RE_NO_BK_VBAR)
+
+#define RE_SYNTAX_POSIX_EGREP						\
+  (RE_SYNTAX_EGREP | RE_INTERVALS | RE_NO_BK_BRACES)
+
+/* P1003.2/D11.2, section 4.20.7.1, lines 5078ff.  */
+#define RE_SYNTAX_ED RE_SYNTAX_POSIX_BASIC
+
+#define RE_SYNTAX_SED RE_SYNTAX_POSIX_BASIC
+
+/* Syntax bits common to both basic and extended POSIX regex syntax.  */
+#define _RE_SYNTAX_POSIX_COMMON						\
+  (RE_CHAR_CLASSES | RE_DOT_NEWLINE      | RE_DOT_NOT_NULL		\
+   | RE_INTERVALS  | RE_NO_EMPTY_RANGES)
+
+#define RE_SYNTAX_POSIX_BASIC						\
+  (_RE_SYNTAX_POSIX_COMMON | RE_BK_PLUS_QM)
+
+/* Differs from ..._POSIX_BASIC only in that RE_BK_PLUS_QM becomes
+   RE_LIMITED_OPS, i.e., \? \+ \| are not recognized.  Actually, this
+   isn't minimal, since other operators, such as \`, aren't disabled.  */
+#define RE_SYNTAX_POSIX_MINIMAL_BASIC					\
+  (_RE_SYNTAX_POSIX_COMMON | RE_LIMITED_OPS)
+
+#define RE_SYNTAX_POSIX_EXTENDED					\
+  (_RE_SYNTAX_POSIX_COMMON | RE_CONTEXT_INDEP_ANCHORS			\
+   | RE_CONTEXT_INDEP_OPS  | RE_NO_BK_BRACES				\
+   | RE_NO_BK_PARENS       | RE_NO_BK_VBAR				\
+   | RE_UNMATCHED_RIGHT_PAREN_ORD)
+
+/* Differs from ..._POSIX_EXTENDED in that RE_CONTEXT_INVALID_OPS
+   replaces RE_CONTEXT_INDEP_OPS and RE_NO_BK_REFS is added.  */
+#define RE_SYNTAX_POSIX_MINIMAL_EXTENDED				\
+  (_RE_SYNTAX_POSIX_COMMON  | RE_CONTEXT_INDEP_ANCHORS			\
+   | RE_CONTEXT_INVALID_OPS | RE_NO_BK_BRACES				\
+   | RE_NO_BK_PARENS        | RE_NO_BK_REFS				\
+   | RE_NO_BK_VBAR	    | RE_UNMATCHED_RIGHT_PAREN_ORD)
+/* [[[end syntaxes]]] */
+
+
+/* Maximum number of duplicates an interval can allow.  Some systems
+   (erroneously) define this in other header files, but we want our
+   value, so remove any previous define.  */
+#ifdef RE_DUP_MAX
+#undef RE_DUP_MAX
+#endif
+#define RE_DUP_MAX ((1 << 15) - 1) 
+
+
+/* POSIX `cflags' bits (i.e., information for `regcomp').  */
+
+/* If this bit is set, then use extended regular expression syntax.
+   If not set, then use basic regular expression syntax.  */
+#define REG_EXTENDED 1
+
+/* If this bit is set, then ignore case when matching.
+   If not set, then case is significant.  */
+#define REG_ICASE (REG_EXTENDED << 1)
+ 
+/* If this bit is set, then anchors do not match at newline
+     characters in the string.
+   If not set, then anchors do match at newlines.  */
+#define REG_NEWLINE (REG_ICASE << 1)
+
+/* If this bit is set, then report only success or fail in regexec.
+   If not set, then returns differ between not matching and errors.  */
+#define REG_NOSUB (REG_NEWLINE << 1)
+
+
+/* POSIX `eflags' bits (i.e., information for regexec).  */
+
+/* If this bit is set, then the beginning-of-line operator doesn't match
+     the beginning of the string (presumably because it's not the
+     beginning of a line).
+   If not set, then the beginning-of-line operator does match the
+     beginning of the string.  */
+#define REG_NOTBOL 1
+
+/* Like REG_NOTBOL, except for the end-of-line.  */
+#define REG_NOTEOL (1 << 1)
+
+
+/* If any error codes are removed, changed, or added, update the
+   `re_error_msg' table in regex.c.  */
+typedef enum
+{
+  REG_NOERROR = 0,	/* Success.  */
+  REG_NOMATCH,		/* Didn't find a match (for regexec).  */
+
+  /* POSIX regcomp return error codes.  (In the order listed in the
+     standard.)  */
+  REG_BADPAT,		/* Invalid pattern.  */
+  REG_ECOLLATE,		/* Not implemented.  */
+  REG_ECTYPE,		/* Invalid character class name.  */
+  REG_EESCAPE,		/* Trailing backslash.  */
+  REG_ESUBREG,		/* Invalid back reference.  */
+  REG_EBRACK,		/* Unmatched left bracket.  */
+  REG_EPAREN,		/* Parenthesis imbalance.  */ 
+  REG_EBRACE,		/* Unmatched \{.  */
+  REG_BADBR,		/* Invalid contents of \{\}.  */
+  REG_ERANGE,		/* Invalid range end.  */
+  REG_ESPACE,		/* Ran out of memory.  */
+  REG_BADRPT,		/* No preceding re for repetition op.  */
+
+  /* Error codes we've added.  */
+  REG_EEND,		/* Premature end.  */
+  REG_ESIZE,		/* Compiled pattern bigger than 2^16 bytes.  */
+  REG_ERPAREN		/* Unmatched ) or \); not returned from regcomp.  */
+} reg_errcode_t;
+
+
+/* This data structure represents a compiled pattern.  Before calling
+   the pattern compiler, the fields `buffer', `allocated', `fastmap',
+   `translate', and `no_sub' can be set.  After the pattern has been
+   compiled, the `re_nsub' field is available.  All other fields are
+   private to the regex routines.  */
+
+struct re_pattern_buffer
+{
+/* [[[begin pattern_buffer]]] */
+	/* Space that holds the compiled pattern.  It is declared as
+          `unsigned char *' because its elements are
+           sometimes used as array indexes.  */
+  unsigned char *buffer;
+
+	/* Number of bytes to which `buffer' points.  */
+  unsigned long allocated;
+
+	/* Number of bytes actually used in `buffer'.  */
+  unsigned long used;	
+
+        /* Syntax setting with which the pattern was compiled.  */
+  reg_syntax_t syntax;
+
+        /* Pointer to a fastmap, if any, otherwise zero.  re_search uses
+           the fastmap, if there is one, to skip over impossible
+           starting points for matches.  */
+  char *fastmap;
+
+        /* Either a translate table to apply to all characters before
+           comparing them, or zero for no translation.  The translation
+           is applied to a pattern when it is compiled and to a string
+           when it is matched.  */
+  char *translate;
+
+	/* Number of subexpressions found by the compiler.  */
+  size_t re_nsub;
+
+        /* Zero if this pattern cannot match the empty string, one else.
+           Well, in truth it's used only in `re_search_2', to see
+           whether or not we should use the fastmap, so we don't set
+           this absolutely perfectly; see `re_compile_fastmap' (the
+           `duplicate' case).  */
+  unsigned can_be_null : 1;
+
+        /* If REGS_UNALLOCATED, allocate space in the `regs' structure
+             for `max (RE_NREGS, re_nsub + 1)' groups.
+           If REGS_REALLOCATE, reallocate space if necessary.
+           If REGS_FIXED, use what's there.  */
+#define REGS_UNALLOCATED 0
+#define REGS_REALLOCATE 1
+#define REGS_FIXED 2
+  unsigned regs_allocated : 2;
+
+        /* Set to zero when `regex_compile' compiles a pattern; set to one
+           by `re_compile_fastmap' if it updates the fastmap.  */
+  unsigned fastmap_accurate : 1;
+
+        /* If set, `re_match_2' does not return information about
+           subexpressions.  */
+  unsigned no_sub : 1;
+
+        /* If set, a beginning-of-line anchor doesn't match at the
+           beginning of the string.  */ 
+  unsigned not_bol : 1;
+
+        /* Similarly for an end-of-line anchor.  */
+  unsigned not_eol : 1;
+
+        /* If true, an anchor at a newline matches.  */
+  unsigned newline_anchor : 1;
+
+/* [[[end pattern_buffer]]] */
+};
+
+typedef struct re_pattern_buffer regex_t;
+
+
+/* Type for byte offsets within the string.  POSIX mandates this.  */
+typedef int regoff_t;
+
+
+/* This is the structure we store register match data in.  See
+   regex.texinfo for a full description of what registers match.  */
+struct re_registers
+{
+  unsigned num_regs;
+  regoff_t *start;
+  regoff_t *end;
+};
+
+
+/* If `regs_allocated' is REGS_UNALLOCATED in the pattern buffer,
+   `re_match_2' returns information about at least this many registers
+   the first time a `regs' structure is passed.  */
+#ifndef RE_NREGS
+#define RE_NREGS 30
+#endif
+
+
+/* POSIX specification for registers.  Aside from the different names than
+   `re_registers', POSIX uses an array of structures, instead of a
+   structure of arrays.  */
+typedef struct
+{
+  regoff_t rm_so;  /* Byte offset from string's start to substring's start.  */
+  regoff_t rm_eo;  /* Byte offset from string's start to substring's end.  */
+} regmatch_t;
+
+
+/* Declarations for routines.  */
+
+/* To avoid duplicating every routine declaration -- once with a
+   prototype (if we are ANSI), and once without (if we aren't) -- we
+   use the following macro to declare argument types.  This
+   unfortunately clutters up the declarations a bit, but I think it's
+   worth it.  */
+
+#if __STDC__
+
+#define _RE_ARGS(args) args
+
+#else /* not __STDC__ */
+
+#define _RE_ARGS(args) ()
+
+#endif /* not __STDC__ */
+
+/* Sets the current default syntax to SYNTAX, and return the old syntax.
+   You can also simply assign to the `re_syntax_options' variable.  */
+extern reg_syntax_t re_set_syntax _RE_ARGS ((reg_syntax_t syntax));
+
+/* Compile the regular expression PATTERN, with length LENGTH
+   and syntax given by the global `re_syntax_options', into the buffer
+   BUFFER.  Return NULL if successful, and an error string if not.  */
+extern const char *re_compile_pattern
+  _RE_ARGS ((const char *pattern, int length,
+             struct re_pattern_buffer *buffer));
+
+
+/* Compile a fastmap for the compiled pattern in BUFFER; used to
+   accelerate searches.  Return 0 if successful and -2 if was an
+   internal error.  */
+extern int re_compile_fastmap _RE_ARGS ((struct re_pattern_buffer *buffer));
+
+
+/* Search in the string STRING (with length LENGTH) for the pattern
+   compiled into BUFFER.  Start searching at position START, for RANGE
+   characters.  Return the starting position of the match, -1 for no
+   match, or -2 for an internal error.  Also return register
+   information in REGS (if REGS and BUFFER->no_sub are nonzero).  */
+extern int re_search
+  _RE_ARGS ((struct re_pattern_buffer *buffer, const char *string,
+            int length, int start, int range, struct re_registers *regs));
+
+
+/* Like `re_search', but search in the concatenation of STRING1 and
+   STRING2.  Also, stop searching at index START + STOP.  */
+extern int re_search_2
+  _RE_ARGS ((struct re_pattern_buffer *buffer, const char *string1,
+             int length1, const char *string2, int length2,
+             int start, int range, struct re_registers *regs, int stop));
+
+
+/* Like `re_search', but return how many characters in STRING the regexp
+   in BUFFER matched, starting at position START.  */
+extern int re_match
+  _RE_ARGS ((struct re_pattern_buffer *buffer, const char *string,
+             int length, int start, struct re_registers *regs));
+
+
+/* Relates to `re_match' as `re_search_2' relates to `re_search'.  */
+extern int re_match_2 
+  _RE_ARGS ((struct re_pattern_buffer *buffer, const char *string1,
+             int length1, const char *string2, int length2,
+             int start, struct re_registers *regs, int stop));
+
+
+/* Set REGS to hold NUM_REGS registers, storing them in STARTS and
+   ENDS.  Subsequent matches using BUFFER and REGS will use this memory
+   for recording register information.  STARTS and ENDS must be
+   allocated with malloc, and must each be at least `NUM_REGS * sizeof
+   (regoff_t)' bytes long.
+
+   If NUM_REGS == 0, then subsequent matches should allocate their own
+   register data.
+
+   Unless this function is called, the first search or match using
+   PATTERN_BUFFER will allocate its own register data, without
+   freeing the old data.  */
+extern void re_set_registers
+  _RE_ARGS ((struct re_pattern_buffer *buffer, struct re_registers *regs,
+             unsigned num_regs, regoff_t *starts, regoff_t *ends));
+
+#ifdef _REGEX_RE_COMP
+/* 4.2 bsd compatibility.  */
+extern char *re_comp _RE_ARGS ((const char *));
+extern int re_exec _RE_ARGS ((const char *));
+#endif
+
+/* POSIX compatibility.  */
+extern int regcomp _RE_ARGS ((regex_t *preg, const char *pattern, int cflags));
+extern int regexec
+  _RE_ARGS ((const regex_t *preg, const char *string, size_t nmatch,
+             regmatch_t pmatch[], int eflags));
+extern size_t regerror
+  _RE_ARGS ((int errcode, const regex_t *preg, char *errbuf,
+             size_t errbuf_size));
+extern void regfree _RE_ARGS ((regex_t *preg));
+
+#endif /* not __REGEXP_LIBRARY_H__ */
+
+
+/*
+Local variables:
+make-backup-files: t
+version-control: t
+trim-versions-without-asking: nil
+End:
+*/
Index: /main/tags/2.25/gsdl/packages/mg/lib/rx.c
===================================================================
--- /main/tags/2.25/gsdl/packages/mg/lib/rx.c	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/mg/lib/rx.c	(revision 21064)
@@ -0,0 +1,7271 @@
+/*	Copyright (C) 1992, 1993, 1994, 1995 Free Software Foundation, Inc.
+
+This file is part of the librx library.
+
+Librx is free software; you can redistribute it and/or modify it under
+the terms of the GNU Library General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+Librx 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 Library General Public
+License along with this software; see the file COPYING.LIB.  If not,
+write to the Free Software Foundation, 675 Mass Ave, Cambridge, MA
+02139, USA.  */
+
+/* NOTE!!!  AIX is so losing it requires this to be the first thing in the 
+ * file. 
+ * Do not put ANYTHING before it!  
+ */
+#if !defined (__GNUC__) && defined (_AIX)
+ #pragma alloca
+#endif
+
+/* To make linux happy? */
+#ifndef	_GNU_SOURCE
+#define	_GNU_SOURCE
+#endif
+
+#if HAVE_CONFIG_H
+# ifdef __WIN32__  /* [RPAP - Feb 97: WIN32 Port] */
+#  include <win32cfg.h>
+#  include <malloc.h>
+# else
+#  include <sysfuncs.h>
+# endif
+#endif
+
+
+
+char rx_version_string[] = "GNU Rx version 0.07.1";
+
+			/* ``Too hard!''
+			 *	    -- anon.
+			 */
+
+
+
+#include <stdio.h>
+#include <ctype.h>
+#ifndef isgraph
+#define isgraph(c) (isprint (c) && !isspace (c))
+#endif
+#ifndef isblank
+#define isblank(c) ((c) == ' ' || (c) == '\t')
+#endif
+
+#include <sys/types.h>
+
+#undef MAX
+#undef MIN
+#define MAX(a, b) ((a) > (b) ? (a) : (b))
+#define MIN(a, b) ((a) < (b) ? (a) : (b))
+
+typedef char boolean;
+#define false 0
+#define true 1
+
+#ifndef __GCC__
+#undef __inline__
+#define __inline__
+#endif
+
+/* Emacs already defines alloca, sometimes.  */
+#ifndef alloca
+
+/* Make alloca work the best possible way.  */
+#ifdef __GNUC__
+#define alloca __builtin_alloca
+#else /* not __GNUC__ */
+#if HAVE_ALLOCA_H
+#include <alloca.h>
+#else /* not __GNUC__ or HAVE_ALLOCA_H */
+#ifndef _AIX /* Already did AIX, up at the top.  */
+char *alloca ();
+#endif /* not _AIX */
+#endif /* not HAVE_ALLOCA_H */ 
+#endif /* not __GNUC__ */
+
+#endif /* not alloca */
+
+/* Memory management and stuff for emacs. */
+
+#define CHARBITS 8
+#define remalloc(M, S) (M ? realloc (M, S) : malloc (S))
+
+
+/* Should we use malloc or alloca?  If REGEX_MALLOC is not defined, we
+ * use `alloca' instead of `malloc' for the backtracking stack.
+ *
+ * Emacs will die miserably if we don't do this.
+ */
+
+#ifdef REGEX_MALLOC
+#define REGEX_ALLOCATE malloc
+#else /* not REGEX_MALLOC  */
+#ifdef __WIN32__  /* [RPAP - Feb 97: WIN32 Port] */
+#define REGEX_ALLOCATE _alloca
+#else
+#define REGEX_ALLOCATE alloca
+#endif /* __WIN32__ */
+#endif /* not REGEX_MALLOC */
+
+
+#ifdef RX_WANT_RX_DEFS
+#define RX_DECL extern
+#define RX_DEF_QUAL 
+#else
+#define RX_WANT_RX_DEFS
+#define RX_DECL static
+#define RX_DEF_QUAL static
+#endif
+#include "rx.h"
+#undef RX_DECL
+#define RX_DECL RX_DEF_QUAL
+
+
+#ifndef emacs
+
+#ifdef SYNTAX_TABLE
+extern char *re_syntax_table;
+#else /* not SYNTAX_TABLE */
+
+#ifdef __STDC__
+static void
+init_syntax_once (void)
+#else
+static void
+init_syntax_once ()
+#endif
+{
+   register int c;
+   static int done = 0;
+
+   if (done)
+     return;
+
+   bzero (re_syntax_table, sizeof re_syntax_table);
+
+   for (c = 'a'; c <= 'z'; c++)
+     re_syntax_table[c] = Sword;
+
+   for (c = 'A'; c <= 'Z'; c++)
+     re_syntax_table[c] = Sword;
+
+   for (c = '0'; c <= '9'; c++)
+     re_syntax_table[c] = Sword;
+
+   re_syntax_table['_'] = Sword;
+
+   done = 1;
+}
+#endif /* not SYNTAX_TABLE */
+#endif /* not emacs */
+
+
+/* Compile with `-DRX_DEBUG' and use the following flags.
+ *
+ * Debugging flags:
+ *   	rx_debug - print information as a regexp is compiled
+ * 	rx_debug_trace - print information as a regexp is executed
+ */
+
+#ifdef RX_DEBUG
+
+int rx_debug_compile = 0;
+int rx_debug_trace = 0;
+static struct re_pattern_buffer * dbug_rxb = 0;
+
+#ifdef __STDC__
+typedef void (*side_effect_printer) (struct rx *, void *, FILE *);
+#else
+typedef void (*side_effect_printer) ();
+#endif
+
+#ifdef __STDC__
+static void print_cset (struct rx *rx, rx_Bitset cset, FILE * fp);
+#else
+static void print_cset ();
+#endif
+
+#ifdef __STDC__
+static void
+print_rexp (struct rx *rx,
+	    struct rexp_node *node, int depth,
+	    side_effect_printer seprint, FILE * fp)
+#else
+static void
+print_rexp (rx, node, depth, seprint, fp)
+     struct rx *rx;
+     struct rexp_node *node;
+     int depth;
+     side_effect_printer seprint;
+     FILE * fp;
+#endif
+{
+  if (!node)
+    return;
+  else
+    {
+      switch (node->type)
+	{
+	case r_cset:
+	  {
+	    fprintf (fp, "%*s", depth, "");
+	    print_cset (rx, node->params.cset, fp);
+	    fputc ('\n', fp);
+	    break;
+	  }
+
+ 	case r_opt:
+	case r_star:
+	  fprintf (fp, "%*s%s\n", depth, "",
+		   node->type == r_opt ? "opt" : "star");
+	  print_rexp (rx, node->params.pair.left, depth + 3, seprint, fp);
+	  break;
+
+	case r_2phase_star:
+	  fprintf (fp, "%*s2phase star\n", depth, "");
+	  print_rexp (rx, node->params.pair.right, depth + 3, seprint, fp);
+	  print_rexp (rx, node->params.pair.left, depth + 3, seprint, fp);
+	  break;
+
+
+	case r_alternate:
+	case r_concat:
+	  fprintf (fp, "%*s%s\n", depth, "",
+		   node->type == r_alternate ? "alt" : "concat");
+	  print_rexp (rx, node->params.pair.left, depth + 3, seprint, fp);
+	  print_rexp (rx, node->params.pair.right, depth + 3, seprint, fp);
+	  break;
+	case r_side_effect:
+	  fprintf (fp, "%*sSide effect: ", depth, "");
+	  seprint (rx, node->params.side_effect, fp);
+	  fputc ('\n', fp);
+	}
+    }
+}
+
+#ifdef __STDC__
+static void
+print_nfa (struct rx * rx,
+	   struct rx_nfa_state * n,
+	   side_effect_printer seprint, FILE * fp)
+#else
+static void
+print_nfa (rx, n, seprint, fp)
+     struct rx * rx;
+     struct rx_nfa_state * n;
+     side_effect_printer seprint;
+     FILE * fp;
+#endif
+{
+  while (n)
+    {
+      struct rx_nfa_edge *e = n->edges;
+      struct rx_possible_future *ec = n->futures;
+      fprintf (fp, "node %d %s\n", n->id,
+	       n->is_final ? "final" : (n->is_start ? "start" : ""));
+      while (e)
+	{
+	  fprintf (fp, "   edge to %d, ", e->dest->id);
+	  switch (e->type)
+	    {
+	    case ne_epsilon:
+	      fprintf (fp, "epsilon\n");
+	      break;
+	    case ne_side_effect:
+	      fprintf (fp, "side effect ");
+	      seprint (rx, e->params.side_effect, fp);
+	      fputc ('\n', fp);
+	      break;
+	    case ne_cset:
+	      fprintf (fp, "cset ");
+	      print_cset (rx, e->params.cset, fp);
+	      fputc ('\n', fp);
+	      break;
+	    }
+	  e = e->next;
+	}
+
+      while (ec)
+	{
+	  int x;
+	  struct rx_nfa_state_set * s;
+	  struct rx_se_list * l;
+	  fprintf (fp, "   eclosure to {");
+	  for (s = ec->destset; s; s = s->cdr)
+	    fprintf (fp, "%d ", s->car->id);
+	  fprintf (fp, "} (");
+	  for (l = ec->effects; l; l = l->cdr)
+	    {
+	      seprint (rx, l->car, fp);
+	      fputc (' ', fp);
+	    }
+	  fprintf (fp, ")\n");
+	  ec = ec->next;
+	}
+      n = n->next;
+    }
+}
+
+static char * efnames [] =
+{
+  "bogon",
+  "re_se_try",
+  "re_se_pushback",
+  "re_se_push0",
+  "re_se_pushpos",
+  "re_se_chkpos",
+  "re_se_poppos",
+  "re_se_at_dot",
+  "re_se_syntax",
+  "re_se_not_syntax",
+  "re_se_begbuf",
+  "re_se_hat",
+  "re_se_wordbeg",
+  "re_se_wordbound",
+  "re_se_notwordbound",
+  "re_se_wordend",
+  "re_se_endbuf",
+  "re_se_dollar",
+  "re_se_fail",
+};
+
+static char * efnames2[] =
+{
+  "re_se_win",
+  "re_se_lparen",
+  "re_se_rparen",
+  "re_se_backref",
+  "re_se_iter",
+  "re_se_end_iter",
+  "re_se_tv"
+};
+
+static char * inx_names[] = 
+{
+  "rx_backtrack_point",
+  "rx_do_side_effects",
+  "rx_cache_miss",
+  "rx_next_char",
+  "rx_backtrack",
+  "rx_error_inx",
+  "rx_num_instructions"
+};
+
+
+#ifdef __STDC__
+static void
+re_seprint (struct rx * rx, void * effect, FILE * fp)
+#else
+static void
+re_seprint (rx, effect, fp)
+     struct rx * rx;
+     void * effect;
+     FILE * fp;
+#endif
+{
+  if ((int)effect < 0)
+    fputs (efnames[-(int)effect], fp);
+  else if (dbug_rxb)
+    {
+      struct re_se_params * p = &dbug_rxb->se_params[(int)effect];
+      fprintf (fp, "%s(%d,%d)", efnames2[p->se], p->op1, p->op2);
+    }
+  else
+    fprintf (fp, "[complex op # %d]", (int)effect);
+}
+
+
+/* These are so the regex.c regression tests will compile. */
+void
+print_compiled_pattern (rxb)
+     struct re_pattern_buffer * rxb;
+{
+}
+
+void
+print_fastmap (fm)
+     char * fm;
+{
+}
+
+#endif /* RX_DEBUG */
+
+
+
+
+/* This page: Bitsets.  Completely unintersting. */
+
+#ifdef __STDC__
+RX_DECL int
+rx_bitset_is_equal (int size, rx_Bitset a, rx_Bitset b)
+#else
+RX_DECL int
+rx_bitset_is_equal (size, a, b)
+     int size;
+     rx_Bitset a;
+     rx_Bitset b;
+#endif
+{
+  int x;
+  RX_subset s = b[0];
+  b[0] = ~a[0];
+
+  for (x = rx_bitset_numb_subsets(size) - 1; a[x] == b[x]; --x)
+    ;
+
+  b[0] = s;
+  return !x && s == a[0];
+}
+
+#ifdef __STDC__
+RX_DECL int
+rx_bitset_is_subset (int size, rx_Bitset a, rx_Bitset b)
+#else
+RX_DECL int
+rx_bitset_is_subset (size, a, b)
+     int size;
+     rx_Bitset a;
+     rx_Bitset b;
+#endif
+{
+  int x = rx_bitset_numb_subsets(size) - 1;
+  while (x-- && (a[x] & b[x]) == a[x]);
+  return x == -1;
+}
+
+
+#ifdef __STDC__
+RX_DECL int
+rx_bitset_empty (int size, rx_Bitset set)
+#else
+RX_DECL int
+rx_bitset_empty (size, set)
+     int size;
+     rx_Bitset set;
+#endif
+{
+  int x;
+  RX_subset s = set[0];
+  set[0] = 1;
+  for (x = rx_bitset_numb_subsets(size) - 1; !set[x]; --x)
+    ;
+  set[0] = s;
+  return !s;
+}
+
+#ifdef __STDC__
+RX_DECL void
+rx_bitset_null (int size, rx_Bitset b)
+#else
+RX_DECL void
+rx_bitset_null (size, b)
+     int size;
+     rx_Bitset b;
+#endif
+{
+  bzero (b, rx_sizeof_bitset(size));
+}
+
+
+#ifdef __STDC__
+RX_DECL void
+rx_bitset_universe (int size, rx_Bitset b)
+#else
+RX_DECL void
+rx_bitset_universe (size, b)
+     int size;
+     rx_Bitset b;
+#endif
+{
+  int x = rx_bitset_numb_subsets (size);
+  while (x--)
+    *b++ = ~(RX_subset)0;
+}
+
+
+#ifdef __STDC__
+RX_DECL void
+rx_bitset_complement (int size, rx_Bitset b)
+#else
+RX_DECL void
+rx_bitset_complement (size, b)
+     int size;
+     rx_Bitset b;
+#endif
+{
+  int x = rx_bitset_numb_subsets (size);
+  while (x--)
+    {
+      *b = ~*b;
+      ++b;
+    }
+}
+
+
+#ifdef __STDC__
+RX_DECL void
+rx_bitset_assign (int size, rx_Bitset a, rx_Bitset b)
+#else
+RX_DECL void
+rx_bitset_assign (size, a, b)
+     int size;
+     rx_Bitset a;
+     rx_Bitset b;
+#endif
+{
+  int x;
+  for (x = rx_bitset_numb_subsets(size) - 1; x >=0; --x)
+    a[x] = b[x];
+}
+
+
+#ifdef __STDC__
+RX_DECL void
+rx_bitset_union (int size, rx_Bitset a, rx_Bitset b)
+#else
+RX_DECL void
+rx_bitset_union (size, a, b)
+     int size;
+     rx_Bitset a;
+     rx_Bitset b;
+#endif
+{
+  int x;
+  for (x = rx_bitset_numb_subsets(size) - 1; x >=0; --x)
+    a[x] |= b[x];
+}
+
+
+#ifdef __STDC__
+RX_DECL void
+rx_bitset_intersection (int size,
+			rx_Bitset a, rx_Bitset b)
+#else
+RX_DECL void
+rx_bitset_intersection (size, a, b)
+     int size;
+     rx_Bitset a;
+     rx_Bitset b;
+#endif
+{
+  int x;
+  for (x = rx_bitset_numb_subsets(size) - 1; x >=0; --x)
+    a[x] &= b[x];
+}
+
+
+#ifdef __STDC__
+RX_DECL void
+rx_bitset_difference (int size, rx_Bitset a, rx_Bitset b)
+#else
+RX_DECL void
+rx_bitset_difference (size, a, b)
+     int size;
+     rx_Bitset a;
+     rx_Bitset b;
+#endif
+{
+  int x;
+  for (x = rx_bitset_numb_subsets(size) - 1; x >=0; --x)
+    a[x] &=  ~ b[x];
+}
+
+
+#ifdef __STDC__
+RX_DECL void
+rx_bitset_revdifference (int size,
+			 rx_Bitset a, rx_Bitset b)
+#else
+RX_DECL void
+rx_bitset_revdifference (size, a, b)
+     int size;
+     rx_Bitset a;
+     rx_Bitset b;
+#endif
+{
+  int x;
+  for (x = rx_bitset_numb_subsets(size) - 1; x >=0; --x)
+    a[x] = ~a[x] & b[x];
+}
+
+#ifdef __STDC__
+RX_DECL void
+rx_bitset_xor (int size, rx_Bitset a, rx_Bitset b)
+#else
+RX_DECL void
+rx_bitset_xor (size, a, b)
+     int size;
+     rx_Bitset a;
+     rx_Bitset b;
+#endif
+{
+  int x;
+  for (x = rx_bitset_numb_subsets(size) - 1; x >=0; --x)
+    a[x] ^= b[x];
+}
+
+
+#ifdef __STDC__
+RX_DECL unsigned long
+rx_bitset_hash (int size, rx_Bitset b)
+#else
+RX_DECL unsigned long
+rx_bitset_hash (size, b)
+     int size;
+     rx_Bitset b;
+#endif
+{
+  int x;
+  unsigned long hash = (unsigned long)rx_bitset_hash;
+
+  for (x = rx_bitset_numb_subsets(size) - 1; x >= 0; --x)
+    hash ^= rx_bitset_subset_val(b, x);
+
+  return hash;
+}
+
+
+RX_DECL RX_subset rx_subset_singletons [RX_subset_bits] = 
+{
+  0x1,
+  0x2,
+  0x4,
+  0x8,
+  0x10,
+  0x20,
+  0x40,
+  0x80,
+  0x100,
+  0x200,
+  0x400,
+  0x800,
+  0x1000,
+  0x2000,
+  0x4000,
+  0x8000,
+  0x10000,
+  0x20000,
+  0x40000,
+  0x80000,
+  0x100000,
+  0x200000,
+  0x400000,
+  0x800000,
+  0x1000000,
+  0x2000000,
+  0x4000000,
+  0x8000000,
+  0x10000000,
+  0x20000000,
+  0x40000000,
+  0x80000000
+};
+
+#ifdef RX_DEBUG
+
+#ifdef __STDC__
+static void
+print_cset (struct rx *rx, rx_Bitset cset, FILE * fp)
+#else
+static void
+print_cset (rx, cset, fp)
+     struct rx *rx;
+     rx_Bitset cset;
+     FILE * fp;
+#endif
+{
+  int x;
+  fputc ('[', fp);
+  for (x = 0; x < rx->local_cset_size; ++x)
+    if (RX_bitset_member (cset, x))
+      {
+	if (isprint(x))
+	  fputc (x, fp);
+	else
+	  fprintf (fp, "\\0%o ", x);
+      }
+  fputc (']', fp);
+}
+
+#endif /*  RX_DEBUG */
+
+
+
+
+static unsigned long rx_hash_masks[4] =
+{
+  0x12488421,
+  0x96699669,
+  0xbe7dd7eb,
+  0xffffffff
+};
+
+
+/* Hash tables */
+#ifdef __STDC__
+RX_DECL struct rx_hash_item * 
+rx_hash_find (struct rx_hash * table,
+	      unsigned long hash,
+	      void * value,
+	      struct rx_hash_rules * rules)
+#else
+RX_DECL struct rx_hash_item * 
+rx_hash_find (table, hash, value, rules)
+     struct rx_hash * table;
+     unsigned long hash;
+     void * value;
+     struct rx_hash_rules * rules;
+#endif
+{
+  rx_hash_eq eq = rules->eq;
+  int maskc = 0;
+  long mask = rx_hash_masks [0];
+  int bucket = (hash & mask) % 13;
+
+  while (table->children [bucket])
+    {
+      table = table->children [bucket];
+      ++maskc;
+      mask = rx_hash_masks[maskc];
+      bucket = (hash & mask) % 13;
+    }
+
+  {
+    struct rx_hash_item * it = table->buckets[bucket];
+    while (it)
+      if (eq (it->data, value))
+	return it;
+      else
+	it = it->next_same_hash;
+  }
+
+  return 0;
+}
+
+
+#ifdef __STDC__
+RX_DECL struct rx_hash_item *
+rx_hash_store (struct rx_hash * table,
+	       unsigned long hash,
+	       void * value,
+	       struct rx_hash_rules * rules)
+#else
+RX_DECL struct rx_hash_item *
+rx_hash_store (table, hash, value, rules)
+     struct rx_hash * table;
+     unsigned long hash;
+     void * value;
+     struct rx_hash_rules * rules;
+#endif
+{
+  rx_hash_eq eq = rules->eq;
+  int maskc = 0;
+  long mask = rx_hash_masks[0];
+  int bucket = (hash & mask) % 13;
+  int depth = 0;
+  
+  while (table->children [bucket])
+    {
+      table = table->children [bucket];
+      ++maskc;
+      mask = rx_hash_masks[maskc];
+      bucket = (hash & mask) % 13;
+      ++depth;
+    }
+  
+  {
+    struct rx_hash_item * it = table->buckets[bucket];
+    while (it)
+      if (eq (it->data, value))
+	return it;
+      else
+	it = it->next_same_hash;
+  }
+  
+  {
+    if (   (depth < 3)
+	&& (table->bucket_size [bucket] >= 4))
+      {
+	struct rx_hash * newtab = ((struct rx_hash *)
+				   rules->hash_alloc (rules));
+	if (!newtab)
+	  goto add_to_bucket;
+	bzero (newtab, sizeof (*newtab));
+	newtab->parent = table;
+	{
+	  struct rx_hash_item * them = table->buckets[bucket];
+	  unsigned long newmask = rx_hash_masks[maskc + 1];
+	  while (them)
+	    {
+	      struct rx_hash_item * save = them->next_same_hash;
+	      int new_buck = (them->hash & newmask) % 13;
+	      them->next_same_hash = newtab->buckets[new_buck];
+	      newtab->buckets[new_buck] = them;
+	      them->table = newtab;
+	      them = save;
+	      ++newtab->bucket_size[new_buck];
+	      ++newtab->refs;
+	    }
+	  table->refs = (table->refs - table->bucket_size[bucket] + 1);
+	  table->bucket_size[bucket] = 0;
+	  table->buckets[bucket] = 0;
+	  table->children[bucket] = newtab;
+	  table = newtab;
+	  bucket = (hash & newmask) % 13;
+	}
+      }
+  }
+ add_to_bucket:
+  {
+    struct rx_hash_item  * it = ((struct rx_hash_item *)
+				 rules->hash_item_alloc (rules, value));
+    if (!it)
+      return 0;
+    it->hash = hash;
+    it->table = table;
+    /* DATA and BINDING are to be set in hash_item_alloc */
+    it->next_same_hash = table->buckets [bucket];
+    table->buckets[bucket] = it;
+    ++table->bucket_size [bucket];
+    ++table->refs;
+    return it;
+  }
+}
+
+
+#ifdef __STDC__
+RX_DECL void
+rx_hash_free (struct rx_hash_item * it, struct rx_hash_rules * rules)
+#else
+RX_DECL void
+rx_hash_free (it, rules)
+     struct rx_hash_item * it;
+     struct rx_hash_rules * rules;
+#endif
+{
+  if (it)
+    {
+      struct rx_hash * table = it->table;
+      unsigned long hash = it->hash;
+      int depth = (table->parent
+		   ? (table->parent->parent
+		      ? (table->parent->parent->parent
+			 ? 3
+			 : 2)
+		      : 1)
+		   : 0);
+      int bucket = (hash & rx_hash_masks [depth]) % 13;
+      struct rx_hash_item ** pos = &table->buckets [bucket];
+      
+      while (*pos != it)
+	pos = &(*pos)->next_same_hash;
+      *pos = it->next_same_hash;
+      rules->free_hash_item (it, rules);
+      --table->bucket_size[bucket];
+      --table->refs;
+      while (!table->refs && depth)
+	{
+	  struct rx_hash * save = table;
+	  table = table->parent;
+	  --depth;
+	  bucket = (hash & rx_hash_masks [depth]) % 13;
+	  --table->refs;
+	  table->children[bucket] = 0;
+	  rules->free_hash (save, rules);
+	}
+    }
+}
+
+#ifdef __STDC__
+RX_DECL void
+rx_free_hash_table (struct rx_hash * tab, rx_hash_freefn freefn,
+		    struct rx_hash_rules * rules)
+#else
+RX_DECL void
+rx_free_hash_table (tab, freefn, rules)
+     struct rx_hash * tab;
+     rx_hash_freefn freefn;
+     struct rx_hash_rules * rules;
+#endif
+{
+  int x;
+
+  for (x = 0; x < 13; ++x)
+    if (tab->children[x])
+      {
+	rx_free_hash_table (tab->children[x], freefn, rules);
+	rules->free_hash (tab->children[x], rules);
+      }
+    else
+      {
+	struct rx_hash_item * them = tab->buckets[x];
+	while (them)
+	  {
+	    struct rx_hash_item * that = them;
+	    them = that->next_same_hash;
+	    freefn (that);
+	    rules->free_hash_item (that, rules);
+	  }
+      }
+}
+
+
+
+
+/* Utilities for manipulating bitset represntations of characters sets. */
+
+#ifdef __STDC__
+RX_DECL rx_Bitset
+rx_cset (struct rx *rx)
+#else
+RX_DECL rx_Bitset
+rx_cset (rx)
+     struct rx *rx;
+#endif
+{
+  rx_Bitset b = (rx_Bitset) malloc (rx_sizeof_bitset (rx->local_cset_size));
+  if (b)
+    rx_bitset_null (rx->local_cset_size, b);
+  return b;
+}
+
+
+#ifdef __STDC__
+RX_DECL rx_Bitset
+rx_copy_cset (struct rx *rx, rx_Bitset a)
+#else
+RX_DECL rx_Bitset
+rx_copy_cset (rx, a)
+     struct rx *rx;
+     rx_Bitset a;
+#endif
+{
+  rx_Bitset cs = rx_cset (rx);
+
+  if (cs)
+    rx_bitset_union (rx->local_cset_size, cs, a);
+
+  return cs;
+}
+
+
+#ifdef __STDC__
+RX_DECL void
+rx_free_cset (struct rx * rx, rx_Bitset c)
+#else
+RX_DECL void
+rx_free_cset (rx, c)
+     struct rx * rx;
+     rx_Bitset c;
+#endif
+{
+  if (c)
+    free ((char *)c);
+}
+
+
+
+/* Hash table memory allocation policy for the regexp compiler */
+
+#ifdef __STDC__
+static struct rx_hash *
+compiler_hash_alloc (struct rx_hash_rules * rules)
+#else
+static struct rx_hash *
+compiler_hash_alloc (rules)
+     struct rx_hash_rules * rules;
+#endif
+{
+  return (struct rx_hash *)malloc (sizeof (struct rx_hash));
+}
+
+
+#ifdef __STDC__
+static struct rx_hash_item *
+compiler_hash_item_alloc (struct rx_hash_rules * rules, void * value)
+#else
+static struct rx_hash_item *
+compiler_hash_item_alloc (rules, value)
+     struct rx_hash_rules * rules;
+     void * value;
+#endif
+{
+  struct rx_hash_item * it;
+  it = (struct rx_hash_item *)malloc (sizeof (*it));
+  if (it)
+    {
+      it->data = value;
+      it->binding = 0;
+    }
+  return it;
+}
+
+
+#ifdef __STDC__
+static void
+compiler_free_hash (struct rx_hash * tab,
+		    struct rx_hash_rules * rules)
+#else
+static void
+compiler_free_hash (tab, rules)
+     struct rx_hash * tab;
+     struct rx_hash_rules * rules;
+#endif
+{
+  free ((char *)tab);
+}
+
+
+#ifdef __STDC__
+static void
+compiler_free_hash_item (struct rx_hash_item * item,
+			 struct rx_hash_rules * rules)
+#else
+static void
+compiler_free_hash_item (item, rules)
+     struct rx_hash_item * item;
+     struct rx_hash_rules * rules;
+#endif
+{
+  free ((char *)item);
+}
+
+
+
+/* This page: REXP_NODE (expression tree) structures. */
+
+#ifdef __STDC__
+RX_DECL struct rexp_node *
+rexp_node (struct rx *rx,
+	   enum rexp_node_type type)
+#else
+RX_DECL struct rexp_node *
+rexp_node (rx, type)
+     struct rx *rx;
+     enum rexp_node_type type;
+#endif
+{
+  struct rexp_node *n;
+
+  n = (struct rexp_node *)malloc (sizeof (*n));
+  bzero (n, sizeof (*n));
+  if (n)
+    n->type = type;
+  return n;
+}
+
+
+/* free_rexp_node assumes that the bitset passed to rx_mk_r_cset
+ * can be freed using rx_free_cset.
+ */
+#ifdef __STDC__
+RX_DECL struct rexp_node *
+rx_mk_r_cset (struct rx * rx,
+	      rx_Bitset b)
+#else
+RX_DECL struct rexp_node *
+rx_mk_r_cset (rx, b)
+     struct rx * rx;
+     rx_Bitset b;
+#endif
+{
+  struct rexp_node * n = rexp_node (rx, r_cset);
+  if (n)
+    n->params.cset = b;
+  return n;
+}
+
+
+#ifdef __STDC__
+RX_DECL struct rexp_node *
+rx_mk_r_concat (struct rx * rx,
+		struct rexp_node * a,
+		struct rexp_node * b)
+#else
+RX_DECL struct rexp_node *
+rx_mk_r_concat (rx, a, b)
+     struct rx * rx;
+     struct rexp_node * a;
+     struct rexp_node * b;
+#endif
+{
+  struct rexp_node * n = rexp_node (rx, r_concat);
+  if (n)
+    {
+      n->params.pair.left = a;
+      n->params.pair.right = b;
+    }
+  return n;
+}
+
+
+#ifdef __STDC__
+RX_DECL struct rexp_node *
+rx_mk_r_alternate (struct rx * rx,
+		   struct rexp_node * a,
+		   struct rexp_node * b)
+#else
+RX_DECL struct rexp_node *
+rx_mk_r_alternate (rx, a, b)
+     struct rx * rx;
+     struct rexp_node * a;
+     struct rexp_node * b;
+#endif
+{
+  struct rexp_node * n = rexp_node (rx, r_alternate);
+  if (n)
+    {
+      n->params.pair.left = a;
+      n->params.pair.right = b;
+    }
+  return n;
+}
+
+
+#ifdef __STDC__
+RX_DECL struct rexp_node *
+rx_mk_r_opt (struct rx * rx,
+	     struct rexp_node * a)
+#else
+RX_DECL struct rexp_node *
+rx_mk_r_opt (rx, a)
+     struct rx * rx;
+     struct rexp_node * a;
+#endif
+{
+  struct rexp_node * n = rexp_node (rx, r_opt);
+  if (n)
+    {
+      n->params.pair.left = a;
+      n->params.pair.right = 0;
+    }
+  return n;
+}
+
+
+#ifdef __STDC__
+RX_DECL struct rexp_node *
+rx_mk_r_star (struct rx * rx,
+	      struct rexp_node * a)
+#else
+RX_DECL struct rexp_node *
+rx_mk_r_star (rx, a)
+     struct rx * rx;
+     struct rexp_node * a;
+#endif
+{
+  struct rexp_node * n = rexp_node (rx, r_star);
+  if (n)
+    {
+      n->params.pair.left = a;
+      n->params.pair.right = 0;
+    }
+  return n;
+}
+
+
+#ifdef __STDC__
+RX_DECL struct rexp_node *
+rx_mk_r_2phase_star (struct rx * rx,
+		     struct rexp_node * a,
+		     struct rexp_node * b)
+#else
+RX_DECL struct rexp_node *
+rx_mk_r_2phase_star (rx, a, b)
+     struct rx * rx;
+     struct rexp_node * a;
+     struct rexp_node * b;
+#endif
+{
+  struct rexp_node * n = rexp_node (rx, r_2phase_star);
+  if (n)
+    {
+      n->params.pair.left = a;
+      n->params.pair.right = b;
+    }
+  return n;
+}
+
+
+#ifdef __STDC__
+RX_DECL struct rexp_node *
+rx_mk_r_side_effect (struct rx * rx,
+		     rx_side_effect a)
+#else
+RX_DECL struct rexp_node *
+rx_mk_r_side_effect (rx, a)
+     struct rx * rx;
+     rx_side_effect a;
+#endif
+{
+  struct rexp_node * n = rexp_node (rx, r_side_effect);
+  if (n)
+    {
+      n->params.side_effect = a;
+      n->params.pair.right = 0;
+    }
+  return n;
+}
+
+
+#ifdef __STDC__
+RX_DECL struct rexp_node *
+rx_mk_r_data  (struct rx * rx,
+	       void * a)
+#else
+RX_DECL struct rexp_node *
+rx_mk_r_data  (rx, a)
+     struct rx * rx;
+     void * a;
+#endif
+{
+  struct rexp_node * n = rexp_node (rx, r_data);
+  if (n)
+    {
+      n->params.pair.left = a;
+      n->params.pair.right = 0;
+    }
+  return n;
+}
+
+
+#ifdef __STDC__
+RX_DECL void
+rx_free_rexp (struct rx * rx, struct rexp_node * node)
+#else
+RX_DECL void
+rx_free_rexp (rx, node)
+     struct rx * rx;
+     struct rexp_node * node;
+#endif
+{
+  if (node)
+    {
+      switch (node->type)
+	{
+	case r_cset:
+	  if (node->params.cset)
+	    rx_free_cset (rx, node->params.cset);
+
+	case r_side_effect:
+	  break;
+	  
+	case r_concat:
+	case r_alternate:
+	case r_2phase_star:
+	case r_opt:
+	case r_star:
+	  rx_free_rexp (rx, node->params.pair.left);
+	  rx_free_rexp (rx, node->params.pair.right);
+	  break;
+
+	case r_data:
+	  /* This shouldn't occur. */
+	  break;
+	}
+      free ((char *)node);
+    }
+}
+
+
+#ifdef __STDC__
+RX_DECL struct rexp_node * 
+rx_copy_rexp (struct rx *rx,
+	   struct rexp_node *node)
+#else
+RX_DECL struct rexp_node * 
+rx_copy_rexp (rx, node)
+     struct rx *rx;
+     struct rexp_node *node;
+#endif
+{
+  if (!node)
+    return 0;
+  else
+    {
+      struct rexp_node *n = rexp_node (rx, node->type);
+      if (!n)
+	return 0;
+      switch (node->type)
+	{
+	case r_cset:
+	  n->params.cset = rx_copy_cset (rx, node->params.cset);
+	  if (!n->params.cset)
+	    {
+	      rx_free_rexp (rx, n);
+	      return 0;
+	    }
+	  break;
+
+	case r_side_effect:
+	  n->params.side_effect = node->params.side_effect;
+	  break;
+
+	case r_concat:
+	case r_alternate:
+	case r_opt:
+	case r_2phase_star:
+	case r_star:
+	  n->params.pair.left =
+	    rx_copy_rexp (rx, node->params.pair.left);
+	  n->params.pair.right =
+	    rx_copy_rexp (rx, node->params.pair.right);
+	  if (   (node->params.pair.left && !n->params.pair.left)
+	      || (node->params.pair.right && !n->params.pair.right))
+	    {
+	      rx_free_rexp  (rx, n);
+	      return 0;
+	    }
+	  break;
+	case r_data:
+	  /* shouldn't happen */
+	  break;
+	}
+      return n;
+    }
+}
+
+
+
+
+/* This page: functions to build and destroy graphs that describe nfa's */
+
+/* Constructs a new nfa node. */
+#ifdef __STDC__
+RX_DECL struct rx_nfa_state *
+rx_nfa_state (struct rx *rx)
+#else
+RX_DECL struct rx_nfa_state *
+rx_nfa_state (rx)
+     struct rx *rx;
+#endif
+{
+  struct rx_nfa_state * n = (struct rx_nfa_state *)malloc (sizeof (*n));
+  if (!n)
+    return 0;
+  bzero (n, sizeof (*n));
+  n->next = rx->nfa_states;
+  rx->nfa_states = n;
+  return n;
+}
+
+
+#ifdef __STDC__
+RX_DECL void
+rx_free_nfa_state (struct rx_nfa_state * n)
+#else
+RX_DECL void
+rx_free_nfa_state (n)
+  struct rx_nfa_state * n;
+#endif
+{
+  free ((char *)n);
+}
+
+
+/* This looks up an nfa node, given a numeric id.  Numeric id's are
+ * assigned after the nfa has been built.
+ */
+#ifdef __STDC__
+RX_DECL struct rx_nfa_state * 
+rx_id_to_nfa_state (struct rx * rx,
+		    int id)
+#else
+RX_DECL struct rx_nfa_state * 
+rx_id_to_nfa_state (rx, id)
+     struct rx * rx;
+     int id;
+#endif
+{
+  struct rx_nfa_state * n;
+  for (n = rx->nfa_states; n; n = n->next)
+    if (n->id == id)
+      return n;
+  return 0;
+}
+
+
+/* This adds an edge between two nodes, but doesn't initialize the 
+ * edge label.
+ */
+
+#ifdef __STDC__
+RX_DECL struct rx_nfa_edge * 
+rx_nfa_edge (struct rx *rx,
+	     enum rx_nfa_etype type,
+	     struct rx_nfa_state *start,
+	     struct rx_nfa_state *dest)
+#else
+RX_DECL struct rx_nfa_edge * 
+rx_nfa_edge (rx, type, start, dest)
+     struct rx *rx;
+     enum rx_nfa_etype type;
+     struct rx_nfa_state *start;
+     struct rx_nfa_state *dest;
+#endif
+{
+  struct rx_nfa_edge *e;
+  e = (struct rx_nfa_edge *)malloc (sizeof (*e));
+  if (!e)
+    return 0;
+  e->next = start->edges;
+  start->edges = e;
+  e->type = type;
+  e->dest = dest;
+  return e;
+}
+
+
+#ifdef __STDC__
+RX_DECL void
+rx_free_nfa_edge (struct rx_nfa_edge * e)
+#else
+RX_DECL void
+rx_free_nfa_edge (e)
+     struct rx_nfa_edge * e;
+#endif
+{
+  free ((char *)e);
+}
+
+
+/* This constructs a POSSIBLE_FUTURE, which is a kind epsilon-closure
+ * of an NFA.  These are added to an nfa automaticly by eclose_nfa.
+ */  
+
+#ifdef __STDC__
+static struct rx_possible_future * 
+rx_possible_future (struct rx * rx,
+		 struct rx_se_list * effects)
+#else
+static struct rx_possible_future * 
+rx_possible_future (rx, effects)
+     struct rx * rx;
+     struct rx_se_list * effects;
+#endif
+{
+  struct rx_possible_future *ec;
+  ec = (struct rx_possible_future *) malloc (sizeof (*ec));
+  if (!ec)
+    return 0;
+  ec->destset = 0;
+  ec->next = 0;
+  ec->effects = effects;
+  return ec;
+}
+
+
+#ifdef __STDC__
+static void
+rx_free_possible_future (struct rx_possible_future * pf)
+#else
+static void
+rx_free_possible_future (pf)
+     struct rx_possible_future * pf;
+#endif
+{
+  free ((char *)pf);
+}
+
+
+#ifdef __STDC__
+RX_DECL void
+rx_free_nfa (struct rx *rx)
+#else
+RX_DECL void
+rx_free_nfa (rx)
+     struct rx *rx;
+#endif
+{
+  while (rx->nfa_states)
+    {
+      while (rx->nfa_states->edges)
+	{
+	  switch (rx->nfa_states->edges->type)
+	    {
+	    case ne_cset:
+	      rx_free_cset (rx, rx->nfa_states->edges->params.cset);
+	      break;
+	    default:
+	      break;
+	    }
+	  {
+	    struct rx_nfa_edge * e;
+	    e = rx->nfa_states->edges;
+	    rx->nfa_states->edges = rx->nfa_states->edges->next;
+	    rx_free_nfa_edge (e);
+	  }
+	} /* while (rx->nfa_states->edges) */
+      {
+	/* Iterate over the partial epsilon closures of rx->nfa_states */
+	struct rx_possible_future * pf = rx->nfa_states->futures;
+	while (pf)
+	  {
+	    struct rx_possible_future * pft = pf;
+	    pf = pf->next;
+	    rx_free_possible_future (pft);
+	  }
+      }
+      {
+	struct rx_nfa_state *n;
+	n = rx->nfa_states;
+	rx->nfa_states = rx->nfa_states->next;
+	rx_free_nfa_state (n);
+      }
+    }
+}
+
+
+
+
+/* This page: translating a pattern expression into an nfa and doing the 
+ * static part of the nfa->super-nfa translation.
+ */
+
+/* This is the thompson regexp->nfa algorithm. 
+ * It is modified to allow for `side-effect epsilons.'  Those are
+ * edges that are taken whenever a similar epsilon edge would be,
+ * but which imply that some side effect occurs when the edge 
+ * is taken.
+ *
+ * Side effects are used to model parts of the pattern langauge 
+ * that are not regular (in the formal sense).
+ */
+
+#ifdef __STDC__
+RX_DECL int
+rx_build_nfa (struct rx *rx,
+	      struct rexp_node *rexp,
+	      struct rx_nfa_state **start,
+	      struct rx_nfa_state **end)
+#else
+RX_DECL int
+rx_build_nfa (rx, rexp, start, end)
+     struct rx *rx;
+     struct rexp_node *rexp;
+     struct rx_nfa_state **start;
+     struct rx_nfa_state **end;
+#endif
+{
+  struct rx_nfa_edge *edge;
+
+  /* Start & end nodes may have been allocated by the caller. */
+  *start = *start ? *start : rx_nfa_state (rx);
+
+  if (!*start)
+    return 0;
+
+  if (!rexp)
+    {
+      *end = *start;
+      return 1;
+    }
+
+  *end = *end ? *end : rx_nfa_state (rx);
+
+  if (!*end)
+    {
+      rx_free_nfa_state (*start);
+      return 0;
+    }
+
+  switch (rexp->type)
+    {
+    case r_data:
+      return 0;
+
+    case r_cset:
+      edge = rx_nfa_edge (rx, ne_cset, *start, *end);
+      if (!edge)
+	return 0;
+      edge->params.cset = rx_copy_cset (rx, rexp->params.cset);
+      if (!edge->params.cset)
+	{
+	  rx_free_nfa_edge (edge);
+	  return 0;
+	}
+      return 1;
+ 
+    case r_opt:
+      return (rx_build_nfa (rx, rexp->params.pair.left, start, end)
+	      && rx_nfa_edge (rx, ne_epsilon, *start, *end));
+
+    case r_star:
+      {
+	struct rx_nfa_state * star_start = 0;
+	struct rx_nfa_state * star_end = 0;
+	return (rx_build_nfa (rx, rexp->params.pair.left,
+			      &star_start, &star_end)
+		&& star_start
+		&& star_end
+		&& rx_nfa_edge (rx, ne_epsilon, star_start, star_end)
+		&& rx_nfa_edge (rx, ne_epsilon, *start, star_start)
+		&& rx_nfa_edge (rx, ne_epsilon, star_end, *end)
+
+		&& rx_nfa_edge (rx, ne_epsilon, star_end, star_start));
+      }
+
+    case r_2phase_star:
+      {
+	struct rx_nfa_state * star_start = 0;
+	struct rx_nfa_state * star_end = 0;
+	struct rx_nfa_state * loop_exp_start = 0;
+	struct rx_nfa_state * loop_exp_end = 0;
+
+	return (rx_build_nfa (rx, rexp->params.pair.left,
+			      &star_start, &star_end)
+		&& rx_build_nfa (rx, rexp->params.pair.right,
+				 &loop_exp_start, &loop_exp_end)
+		&& star_start
+		&& star_end
+		&& loop_exp_end
+		&& loop_exp_start
+		&& rx_nfa_edge (rx, ne_epsilon, star_start, *end)
+		&& rx_nfa_edge (rx, ne_epsilon, *start, star_start)
+		&& rx_nfa_edge (rx, ne_epsilon, star_end, *end)
+
+		&& rx_nfa_edge (rx, ne_epsilon, star_end, loop_exp_start)
+		&& rx_nfa_edge (rx, ne_epsilon, loop_exp_end, star_start));
+      }
+
+
+    case r_concat:
+      {
+	struct rx_nfa_state *shared = 0;
+	return
+	  (rx_build_nfa (rx, rexp->params.pair.left, start, &shared)
+	   && rx_build_nfa (rx, rexp->params.pair.right, &shared, end));
+      }
+
+    case r_alternate:
+      {
+	struct rx_nfa_state *ls = 0;
+	struct rx_nfa_state *le = 0;
+	struct rx_nfa_state *rs = 0;
+	struct rx_nfa_state *re = 0;
+	return (rx_build_nfa (rx, rexp->params.pair.left, &ls, &le)
+		&& rx_build_nfa (rx, rexp->params.pair.right, &rs, &re)
+		&& rx_nfa_edge (rx, ne_epsilon, *start, ls)
+		&& rx_nfa_edge (rx, ne_epsilon, *start, rs)
+		&& rx_nfa_edge (rx, ne_epsilon, le, *end)
+		&& rx_nfa_edge (rx, ne_epsilon, re, *end));
+      }
+
+    case r_side_effect:
+      edge = rx_nfa_edge (rx, ne_side_effect, *start, *end);
+      if (!edge)
+	return 0;
+      edge->params.side_effect = rexp->params.side_effect;
+      return 1;
+    }
+
+  /* this should never happen */
+  return 0;
+}
+
+
+/* RX_NAME_NFA_STATES identifies all nodes with outgoing non-epsilon
+ * transitions.  Only these nodes can occur in super-states.  
+ * All nodes are given an integer id. 
+ * The id is non-negative if the node has non-epsilon out-transitions, negative
+ * otherwise (this is because we want the non-negative ids to be used as 
+ * array indexes in a few places).
+ */
+
+#ifdef __STDC__
+RX_DECL void
+rx_name_nfa_states (struct rx *rx)
+#else
+RX_DECL void
+rx_name_nfa_states (rx)
+     struct rx *rx;
+#endif
+{
+  struct rx_nfa_state *n = rx->nfa_states;
+
+  rx->nodec = 0;
+  rx->epsnodec = -1;
+
+  while (n)
+    {
+      struct rx_nfa_edge *e = n->edges;
+
+      if (n->is_start)
+	n->eclosure_needed = 1;
+
+      while (e)
+	{
+	  switch (e->type)
+	    {
+	    case ne_epsilon:
+	    case ne_side_effect:
+	      break;
+
+	    case ne_cset:
+	      n->id = rx->nodec++;
+	      {
+		struct rx_nfa_edge *from_n = n->edges;
+		while (from_n)
+		  {
+		    from_n->dest->eclosure_needed = 1;
+		    from_n = from_n->next;
+		  }
+	      }
+	      goto cont;
+	    }
+	  e = e->next;
+	}
+      n->id = rx->epsnodec--;
+    cont:
+      n = n->next;
+    }
+  rx->epsnodec = -rx->epsnodec;
+}
+
+
+
+/* This page: data structures for the static part of the nfa->supernfa
+ * translation.
+ *
+ * There are side effect lists -- lists of side effects occuring
+ * along an uninterrupted, acyclic path of side-effect epsilon edges.
+ * Such paths are collapsed to single edges in the course of computing
+ * epsilon closures.  Such single edges are labled with a list of all
+ * the side effects entailed in crossing them.  Like lists of side
+ * effects are made == by the constructors below.
+ *
+ * There are also nfa state sets.  These are used to hold a list of all
+ * states reachable from a starting state for a given type of transition
+ * and side effect list.   These are also hash-consed.
+ */
+
+/* The next several functions compare, construct, etc. lists of side
+ * effects.  See ECLOSE_NFA (below) for details.
+ */
+
+/* Ordering of rx_se_list
+ * (-1, 0, 1 return value convention).
+ */
+
+#ifdef __STDC__
+static int 
+se_list_cmp (void * va, void * vb)
+#else
+static int 
+se_list_cmp (va, vb)
+     void * va;
+     void * vb;
+#endif
+{
+  struct rx_se_list * a = (struct rx_se_list *)va;
+  struct rx_se_list * b = (struct rx_se_list *)vb;
+
+  return ((va == vb)
+	  ? 0
+	  : (!va
+	     ? -1
+	     : (!vb
+		? 1
+		: ((long)a->car < (long)b->car
+		   ? 1
+		   : ((long)a->car > (long)b->car
+		      ? -1
+		      : se_list_cmp ((void *)a->cdr, (void *)b->cdr))))));
+}
+
+
+#ifdef __STDC__
+static int 
+se_list_equal (void * va, void * vb)
+#else
+static int 
+se_list_equal (va, vb)
+     void * va;
+     void * vb;
+#endif
+{
+  return !(se_list_cmp (va, vb));
+}
+
+static struct rx_hash_rules se_list_hash_rules =
+{
+  se_list_equal,
+  compiler_hash_alloc,
+  compiler_free_hash,
+  compiler_hash_item_alloc,
+  compiler_free_hash_item
+};
+
+
+#ifdef __STDC__
+static struct rx_se_list * 
+side_effect_cons (struct rx * rx,
+		  void * se, struct rx_se_list * list)
+#else
+static struct rx_se_list * 
+side_effect_cons (rx, se, list)
+     struct rx * rx;
+     void * se;
+     struct rx_se_list * list;
+#endif
+{
+  struct rx_se_list * l;
+  l = ((struct rx_se_list *) malloc (sizeof (*l)));
+  if (!l)
+    return 0;
+  l->car = se;
+  l->cdr = list;
+  return l;
+}
+
+
+#ifdef __STDC__
+static struct rx_se_list *
+hash_cons_se_prog (struct rx * rx,
+		   struct rx_hash * memo,
+		   void * car, struct rx_se_list * cdr)
+#else
+static struct rx_se_list *
+hash_cons_se_prog (rx, memo, car, cdr)
+     struct rx * rx;
+     struct rx_hash * memo;
+     void * car;
+     struct rx_se_list * cdr;
+#endif
+{
+  long hash = (long)car ^ (long)cdr;
+  struct rx_se_list template;
+
+  template.car = car;
+  template.cdr = cdr;
+  {
+    struct rx_hash_item * it = rx_hash_store (memo, hash,
+					      (void *)&template,
+					      &se_list_hash_rules);
+    if (!it)
+      return 0;
+    if (it->data == (void *)&template)
+      {
+	struct rx_se_list * consed;
+	consed = (struct rx_se_list *) malloc (sizeof (*consed));
+	*consed = template;
+	it->data = (void *)consed;
+      }
+    return (struct rx_se_list *)it->data;
+  }
+}
+     
+
+#ifdef __STDC__
+static struct rx_se_list *
+hash_se_prog (struct rx * rx, struct rx_hash * memo, struct rx_se_list * prog)
+#else
+static struct rx_se_list *
+hash_se_prog (rx, memo, prog)
+     struct rx * rx;
+     struct rx_hash * memo;
+     struct rx_se_list * prog;
+#endif
+{
+  struct rx_se_list * answer = 0;
+  while (prog)
+    {
+      answer = hash_cons_se_prog (rx, memo, prog->car, answer);
+      if (!answer)
+	return 0;
+      prog = prog->cdr;
+    }
+  return answer;
+}
+
+#ifdef __STDC__
+static int 
+nfa_set_cmp (void * va, void * vb)
+#else
+static int 
+nfa_set_cmp (va, vb)
+     void * va;
+     void * vb;
+#endif
+{
+  struct rx_nfa_state_set * a = (struct rx_nfa_state_set *)va;
+  struct rx_nfa_state_set * b = (struct rx_nfa_state_set *)vb;
+
+  return ((va == vb)
+	  ? 0
+	  : (!va
+	     ? -1
+	     : (!vb
+		? 1
+		: (a->car->id < b->car->id
+		   ? 1
+		   : (a->car->id > b->car->id
+		      ? -1
+		      : nfa_set_cmp ((void *)a->cdr, (void *)b->cdr))))));
+}
+
+#ifdef __STDC__
+static int 
+nfa_set_equal (void * va, void * vb)
+#else
+static int 
+nfa_set_equal (va, vb)
+     void * va;
+     void * vb;
+#endif
+{
+  return !nfa_set_cmp (va, vb);
+}
+
+static struct rx_hash_rules nfa_set_hash_rules =
+{
+  nfa_set_equal,
+  compiler_hash_alloc,
+  compiler_free_hash,
+  compiler_hash_item_alloc,
+  compiler_free_hash_item
+};
+
+
+#ifdef __STDC__
+static struct rx_nfa_state_set * 
+nfa_set_cons (struct rx * rx,
+	      struct rx_hash * memo, struct rx_nfa_state * state,
+	      struct rx_nfa_state_set * set)
+#else
+static struct rx_nfa_state_set * 
+nfa_set_cons (rx, memo, state, set)
+     struct rx * rx;
+     struct rx_hash * memo;
+     struct rx_nfa_state * state;
+     struct rx_nfa_state_set * set;
+#endif
+{
+  struct rx_nfa_state_set template;
+  struct rx_hash_item * node;
+  template.car = state;
+  template.cdr = set;
+  node = rx_hash_store (memo,
+			(((long)state) >> 8) ^ (long)set,
+			&template, &nfa_set_hash_rules);
+  if (!node)
+    return 0;
+  if (node->data == &template)
+    {
+      struct rx_nfa_state_set * l;
+      l = (struct rx_nfa_state_set *) malloc (sizeof (*l));
+      node->data = (void *) l;
+      if (!l)
+	return 0;
+      *l = template;
+    }
+  return (struct rx_nfa_state_set *)node->data;
+}
+
+
+#ifdef __STDC__
+static struct rx_nfa_state_set * 
+nfa_set_enjoin (struct rx * rx,
+		struct rx_hash * memo, struct rx_nfa_state * state,
+		struct rx_nfa_state_set * set)
+#else
+static struct rx_nfa_state_set * 
+nfa_set_enjoin (rx, memo, state, set)
+     struct rx * rx;
+     struct rx_hash * memo;
+     struct rx_nfa_state * state;
+     struct rx_nfa_state_set * set;
+#endif
+{
+  if (!set || state->id < set->car->id)
+    return nfa_set_cons (rx, memo, state, set);
+  if (state->id == set->car->id)
+    return set;
+  else
+    {
+      struct rx_nfa_state_set * newcdr
+	= nfa_set_enjoin (rx, memo, state, set->cdr);
+      if (newcdr != set->cdr)
+	set = nfa_set_cons (rx, memo, set->car, newcdr);
+      return set;
+    }
+}
+
+
+
+
+/* This page: computing epsilon closures.  The closures aren't total.
+ * Each node's closures are partitioned according to the side effects entailed
+ * along the epsilon edges.  Return true on success.
+ */ 
+
+struct eclose_frame
+{
+  struct rx_se_list *prog_backwards;
+};
+
+
+#ifdef __STDC__
+static int 
+eclose_node (struct rx *rx, struct rx_nfa_state *outnode,
+	     struct rx_nfa_state *node, struct eclose_frame *frame)
+#else
+static int 
+eclose_node (rx, outnode, node, frame)
+     struct rx *rx;
+     struct rx_nfa_state *outnode;
+     struct rx_nfa_state *node;
+     struct eclose_frame *frame;
+#endif
+{
+  struct rx_nfa_edge *e = node->edges;
+
+  /* For each node, we follow all epsilon paths to build the closure.
+   * The closure omits nodes that have only epsilon edges.
+   * The closure is split into partial closures -- all the states in
+   * a partial closure are reached by crossing the same list of
+   * of side effects (though not necessarily the same path).
+   */
+  if (node->mark)
+    return 1;
+  node->mark = 1;
+
+  if (node->id >= 0 || node->is_final)
+    {
+      struct rx_possible_future **ec;
+      struct rx_se_list * prog_in_order
+	= ((struct rx_se_list *)hash_se_prog (rx,
+					      &rx->se_list_memo,
+					      frame->prog_backwards));
+      int cmp;
+
+      ec = &outnode->futures;
+
+      while (*ec)
+	{
+	  cmp = se_list_cmp ((void *)(*ec)->effects, (void *)prog_in_order);
+	  if (cmp <= 0)
+	    break;
+	  ec = &(*ec)->next;
+	}
+      if (!*ec || (cmp < 0))
+	{
+	  struct rx_possible_future * saved = *ec;
+	  *ec = rx_possible_future (rx, prog_in_order);
+	  (*ec)->next = saved;
+	  if (!*ec)
+	    return 0;
+	}
+      if (node->id >= 0)
+	{
+	  (*ec)->destset = nfa_set_enjoin (rx, &rx->set_list_memo,
+					   node, (*ec)->destset);
+	  if (!(*ec)->destset)
+	    return 0;
+	}
+    }
+
+  while (e)
+    {
+      switch (e->type)
+	{
+	case ne_epsilon:
+	  if (!eclose_node (rx, outnode, e->dest, frame))
+	    return 0;
+	  break;
+	case ne_side_effect:
+	  {
+	    frame->prog_backwards = side_effect_cons (rx, 
+						      e->params.side_effect,
+						      frame->prog_backwards);
+	    if (!frame->prog_backwards)
+	      return 0;
+	    if (!eclose_node (rx, outnode, e->dest, frame))
+	      return 0;
+	    {
+	      struct rx_se_list * dying = frame->prog_backwards;
+	      frame->prog_backwards = frame->prog_backwards->cdr;
+	      free ((char *)dying);
+	    }
+	    break;
+	  }
+	default:
+	  break;
+	}
+      e = e->next;
+    }
+  node->mark = 0;
+  return 1;
+}
+
+
+#ifdef __STDC__
+RX_DECL int 
+rx_eclose_nfa (struct rx *rx)
+#else
+RX_DECL int 
+rx_eclose_nfa (rx)
+     struct rx *rx;
+#endif
+{
+  struct rx_nfa_state *n = rx->nfa_states;
+  struct eclose_frame frame;
+  static int rx_id = 0;
+  
+  frame.prog_backwards = 0;
+  rx->rx_id = rx_id++;
+  bzero (&rx->se_list_memo, sizeof (rx->se_list_memo));
+  bzero (&rx->set_list_memo, sizeof (rx->set_list_memo));
+  while (n)
+    {
+      n->futures = 0;
+      if (n->eclosure_needed && !eclose_node (rx, n, n, &frame))
+	return 0;
+      /* clear_marks (rx); */
+      n = n->next;
+    }
+  return 1;
+}
+
+
+/* This deletes epsilon edges from an NFA.  After running eclose_node,
+ * we have no more need for these edges.  They are removed to simplify
+ * further operations on the NFA.
+ */
+
+#ifdef __STDC__
+RX_DECL void 
+rx_delete_epsilon_transitions (struct rx *rx)
+#else
+RX_DECL void 
+rx_delete_epsilon_transitions (rx)
+     struct rx *rx;
+#endif
+{
+  struct rx_nfa_state *n = rx->nfa_states;
+  struct rx_nfa_edge **e;
+
+  while (n)
+    {
+      e = &n->edges;
+      while (*e)
+	{
+	  struct rx_nfa_edge *t;
+	  switch ((*e)->type)
+	    {
+	    case ne_epsilon:
+	    case ne_side_effect:
+	      t = *e;
+	      *e = t->next;
+	      rx_free_nfa_edge (t);
+	      break;
+
+	    default:
+	      e = &(*e)->next;
+	      break;
+	    }
+	}
+      n = n->next;
+    }
+}
+
+
+
+/* This page: storing the nfa in a contiguous region of memory for
+ * subsequent conversion to a super-nfa.
+ */
+
+/* This is for qsort on an array of nfa_states. The order
+ * is based on state ids and goes 
+ *		[0...MAX][MIN..-1] where (MAX>=0) and (MIN<0)
+ * This way, positive ids double as array indices.
+ */
+
+#ifdef __STDC__
+static int 
+nfacmp (void * va, void * vb)
+#else
+static int 
+nfacmp (va, vb)
+     void * va;
+     void * vb;
+#endif
+{
+  struct rx_nfa_state **a = (struct rx_nfa_state **)va;
+  struct rx_nfa_state **b = (struct rx_nfa_state **)vb;
+  return (*a == *b		/* &&&& 3.18 */
+	  ? 0
+	  : (((*a)->id < 0) == ((*b)->id < 0)
+	     ? (((*a)->id  < (*b)->id) ? -1 : 1)
+	     : (((*a)->id < 0)
+		? 1 : -1)));
+}
+
+#ifdef __STDC__
+static int 
+count_hash_nodes (struct rx_hash * st)
+#else
+static int 
+count_hash_nodes (st)
+     struct rx_hash * st;
+#endif
+{
+  int x;
+  int count = 0;
+  for (x = 0; x < 13; ++x)
+    count += ((st->children[x])
+	      ? count_hash_nodes (st->children[x])
+	      : st->bucket_size[x]);
+  
+  return count;
+}
+
+
+#ifdef __STDC__
+static void 
+se_memo_freer (struct rx_hash_item * node)
+#else
+static void 
+se_memo_freer (node)
+     struct rx_hash_item * node;
+#endif
+{
+  free ((char *)node->data);
+}
+
+
+#ifdef __STDC__
+static void 
+nfa_set_freer (struct rx_hash_item * node)
+#else
+static void 
+nfa_set_freer (node)
+     struct rx_hash_item * node;
+#endif
+{
+  free ((char *)node->data);
+}
+
+
+/* This copies an entire NFA into a single malloced block of memory.
+ * Mostly this is for compatability with regex.c, though it is convenient
+ * to have the nfa nodes in an array.
+ */
+
+#ifdef __STDC__
+RX_DECL int 
+rx_compactify_nfa (struct rx *rx,
+		   void **mem, unsigned long *size)
+#else
+RX_DECL int 
+rx_compactify_nfa (rx, mem, size)
+     struct rx *rx;
+     void **mem;
+     unsigned long *size;
+#endif
+{
+  int total_nodec;
+  struct rx_nfa_state *n;
+  int edgec = 0;
+  int eclosec = 0;
+  int se_list_consc = count_hash_nodes (&rx->se_list_memo);
+  int nfa_setc = count_hash_nodes (&rx->set_list_memo);
+  unsigned long total_size;
+
+  /* This takes place in two stages.   First, the total size of the
+   * nfa is computed, then structures are copied.  
+   */   
+  n = rx->nfa_states;
+  total_nodec = 0;
+  while (n)
+    {
+      struct rx_nfa_edge *e = n->edges;
+      struct rx_possible_future *ec = n->futures;
+      ++total_nodec;
+      while (e)
+	{
+	  ++edgec;
+	  e = e->next;
+	}
+      while (ec)
+	{
+	  ++eclosec;
+	  ec = ec->next;
+	}
+      n = n->next;
+    }
+
+  total_size = (total_nodec * sizeof (struct rx_nfa_state)
+		+ edgec * rx_sizeof_bitset (rx->local_cset_size)
+		+ edgec * sizeof (struct rx_nfa_edge)
+		+ nfa_setc * sizeof (struct rx_nfa_state_set)
+		+ eclosec * sizeof (struct rx_possible_future)
+		+ se_list_consc * sizeof (struct rx_se_list)
+		+ rx->reserved);
+
+  if (total_size > *size)
+    {
+      *mem = remalloc (*mem, total_size);
+      if (*mem)
+	*size = total_size;
+      else
+	return 0;
+    }
+  /* Now we've allocated the memory; this copies the NFA. */
+  {
+    static struct rx_nfa_state **scratch = 0;
+    static int scratch_alloc = 0;
+    struct rx_nfa_state *state_base = (struct rx_nfa_state *) * mem;
+    struct rx_nfa_state *new_state = state_base;
+    struct rx_nfa_edge *new_edge =
+      (struct rx_nfa_edge *)
+	((char *) state_base + total_nodec * sizeof (struct rx_nfa_state));
+    struct rx_se_list * new_se_list =
+      (struct rx_se_list *)
+	((char *)new_edge + edgec * sizeof (struct rx_nfa_edge));
+    struct rx_possible_future *new_close =
+      ((struct rx_possible_future *)
+       ((char *) new_se_list
+	+ se_list_consc * sizeof (struct rx_se_list)));
+    struct rx_nfa_state_set * new_nfa_set =
+      ((struct rx_nfa_state_set *)
+       ((char *)new_close + eclosec * sizeof (struct rx_possible_future)));
+    char *new_bitset =
+      ((char *) new_nfa_set + nfa_setc * sizeof (struct rx_nfa_state_set));
+    int x;
+    struct rx_nfa_state *n;
+
+    if (scratch_alloc < total_nodec)
+      {
+	scratch = ((struct rx_nfa_state **)
+		   remalloc (scratch, total_nodec * sizeof (*scratch)));
+	if (scratch)
+	  scratch_alloc = total_nodec;
+	else
+	  {
+	    scratch_alloc = 0;
+	    return 0;
+	  }
+      }
+
+    for (x = 0, n = rx->nfa_states; n; n = n->next)
+      scratch[x++] = n;
+
+    qsort (scratch, total_nodec,
+	   sizeof (struct rx_nfa_state *), (int (*)())nfacmp);
+
+    for (x = 0; x < total_nodec; ++x)
+      {
+	struct rx_possible_future *eclose = scratch[x]->futures;
+	struct rx_nfa_edge *edge = scratch[x]->edges;
+	struct rx_nfa_state *cn = new_state++;
+	cn->futures = 0;
+	cn->edges = 0;
+	cn->next = (x == total_nodec - 1) ? 0 : (cn + 1);
+	cn->id = scratch[x]->id;
+	cn->is_final = scratch[x]->is_final;
+	cn->is_start = scratch[x]->is_start;
+	cn->mark = 0;
+	while (edge)
+	  {
+	    int indx = (edge->dest->id < 0
+			 ? (total_nodec + edge->dest->id)
+			 : edge->dest->id);
+	    struct rx_nfa_edge *e = new_edge++;
+	    rx_Bitset cset = (rx_Bitset) new_bitset;
+	    new_bitset += rx_sizeof_bitset (rx->local_cset_size);
+	    rx_bitset_null (rx->local_cset_size, cset);
+	    rx_bitset_union (rx->local_cset_size, cset, edge->params.cset);
+	    e->next = cn->edges;
+	    cn->edges = e;
+	    e->type = edge->type;
+	    e->dest = state_base + indx;
+	    e->params.cset = cset;
+	    edge = edge->next;
+	  }
+	while (eclose)
+	  {
+	    struct rx_possible_future *ec = new_close++;
+	    struct rx_hash_item * sp;
+	    struct rx_se_list ** sepos;
+	    struct rx_se_list * sesrc;
+	    struct rx_nfa_state_set * destlst;
+	    struct rx_nfa_state_set ** destpos;
+	    ec->next = cn->futures;
+	    cn->futures = ec;
+	    for (sepos = &ec->effects, sesrc = eclose->effects;
+		 sesrc;
+		 sesrc = sesrc->cdr, sepos = &(*sepos)->cdr)
+	      {
+		sp = rx_hash_find (&rx->se_list_memo,
+				   (long)sesrc->car ^ (long)sesrc->cdr,
+				   sesrc, &se_list_hash_rules);
+		if (sp->binding)
+		  {
+		    sesrc = (struct rx_se_list *)sp->binding;
+		    break;
+		  }
+		*new_se_list = *sesrc;
+		sp->binding = (void *)new_se_list;
+		*sepos = new_se_list;
+		++new_se_list;
+	      }
+	    *sepos = sesrc;
+	    for (destpos = &ec->destset, destlst = eclose->destset;
+		 destlst;
+		 destpos = &(*destpos)->cdr, destlst = destlst->cdr)
+	      {
+		sp = rx_hash_find (&rx->set_list_memo,
+				   ((((long)destlst->car) >> 8)
+				    ^ (long)destlst->cdr),
+				   destlst, &nfa_set_hash_rules);
+		if (sp->binding)
+		  {
+		    destlst = (struct rx_nfa_state_set *)sp->binding;
+		    break;
+		  }
+		*new_nfa_set = *destlst;
+		new_nfa_set->car = state_base + destlst->car->id;
+		sp->binding = (void *)new_nfa_set;
+		*destpos = new_nfa_set;
+		++new_nfa_set;
+	      }
+	    *destpos = destlst;
+	    eclose = eclose->next;
+	  }
+      }
+  }
+  rx_free_hash_table (&rx->se_list_memo, se_memo_freer, &se_list_hash_rules);
+  bzero (&rx->se_list_memo, sizeof (rx->se_list_memo));
+  rx_free_hash_table (&rx->set_list_memo, nfa_set_freer, &nfa_set_hash_rules);
+  bzero (&rx->set_list_memo, sizeof (rx->set_list_memo));
+
+  rx_free_nfa (rx);
+  rx->nfa_states = (struct rx_nfa_state *)*mem;
+  return 1;
+}
+
+
+
+/* The functions in the next several pages define the lazy-NFA-conversion used
+ * by matchers.  The input to this construction is an NFA such as 
+ * is built by compactify_nfa (rx.c).  The output is the superNFA.
+ */
+
+/* Match engines can use arbitrary values for opcodes.  So, the parse tree 
+ * is built using instructions names (enum rx_opcode), but the superstate
+ * nfa is populated with mystery opcodes (void *).
+ *
+ * For convenience, here is an id table.  The opcodes are == to their inxs
+ *
+ * The lables in re_search_2 would make good values for instructions.
+ */
+
+void * rx_id_instruction_table[rx_num_instructions] =
+{
+  (void *) rx_backtrack_point,
+  (void *) rx_do_side_effects,
+  (void *) rx_cache_miss,
+  (void *) rx_next_char,
+  (void *) rx_backtrack,
+  (void *) rx_error_inx
+};
+
+
+
+
+/* Memory mgt. for superstate graphs. */
+
+#ifdef __STDC__
+static char *
+rx_cache_malloc (struct rx_cache * cache, int bytes)
+#else
+static char *
+rx_cache_malloc (cache, bytes)
+     struct rx_cache * cache;
+     int bytes;
+#endif
+{
+  while (cache->bytes_left < bytes)
+    {
+      if (cache->memory_pos)
+	cache->memory_pos = cache->memory_pos->next;
+      if (!cache->memory_pos)
+	{
+	  cache->morecore (cache);
+	  if (!cache->memory_pos)
+	    return 0;
+	}
+      cache->bytes_left = cache->memory_pos->bytes;
+      cache->memory_addr = ((char *)cache->memory_pos
+			    + sizeof (struct rx_blocklist));
+    }
+  cache->bytes_left -= bytes;
+  {
+    char * addr = cache->memory_addr;
+    cache->memory_addr += bytes;
+    return addr;
+  }
+}
+
+#ifdef __STDC__
+static void
+rx_cache_free (struct rx_cache * cache,
+	       struct rx_freelist ** freelist, char * mem)
+#else
+static void
+rx_cache_free (cache, freelist, mem)
+     struct rx_cache * cache;
+     struct rx_freelist ** freelist;
+     char * mem;
+#endif
+{
+  struct rx_freelist * it = (struct rx_freelist *)mem;
+  it->next = *freelist;
+  *freelist = it;
+}
+
+
+/* The partially instantiated superstate graph has a transition 
+ * table at every node.  There is one entry for every character.
+ * This fills in the transition for a set.
+ */
+#ifdef __STDC__
+static void 
+install_transition (struct rx_superstate *super,
+		    struct rx_inx *answer, rx_Bitset trcset) 
+#else
+static void 
+install_transition (super, answer, trcset)
+     struct rx_superstate *super;
+     struct rx_inx *answer;
+     rx_Bitset trcset;
+#endif
+{
+  struct rx_inx * transitions = super->transitions;
+  int chr;
+  for (chr = 0; chr < 256; )
+    if (!*trcset)
+      {
+	++trcset;
+	chr += 32;
+      }
+    else
+      {
+	RX_subset sub = *trcset;
+	RX_subset mask = 1;
+	int bound = chr + 32;
+	while (chr < bound)
+	  {
+	    if (sub & mask)
+	      transitions [chr] = *answer;
+	    ++chr;
+	    mask <<= 1;
+	  }
+	++trcset;
+      }
+}
+
+
+#ifdef __STDC__
+static int
+qlen (struct rx_superstate * q)
+#else
+static int
+qlen (q)
+     struct rx_superstate * q;
+#endif
+{
+  int count = 1;
+  struct rx_superstate * it;
+  if (!q)
+    return 0;
+  for (it = q->next_recyclable; it != q; it = it->next_recyclable)
+    ++count;
+  return count;
+}
+
+#ifdef __STDC__
+static void
+check_cache (struct rx_cache * cache)
+#else
+static void
+check_cache (cache)
+     struct rx_cache * cache;
+#endif
+{
+  struct rx_cache * you_fucked_up = 0;
+  int total = cache->superstates;
+  int semi = cache->semifree_superstates;
+  if (semi != qlen (cache->semifree_superstate))
+    check_cache (you_fucked_up);
+  if ((total - semi) != qlen (cache->lru_superstate))
+    check_cache (you_fucked_up);
+}
+
+/* When a superstate is old and neglected, it can enter a 
+ * semi-free state.  A semi-free state is slated to die.
+ * Incoming transitions to a semi-free state are re-written
+ * to cause an (interpreted) fault when they are taken.
+ * The fault handler revives the semi-free state, patches
+ * incoming transitions back to normal, and continues.
+ *
+ * The idea is basicly to free in two stages, aborting 
+ * between the two if the state turns out to be useful again.
+ * When a free is aborted, the rescued superstate is placed
+ * in the most-favored slot to maximize the time until it
+ * is next semi-freed.
+ */
+
+#ifdef __STDC__
+static void
+semifree_superstate (struct rx_cache * cache)
+#else
+static void
+semifree_superstate (cache)
+     struct rx_cache * cache;
+#endif
+{
+  int disqualified = cache->semifree_superstates;
+  if (disqualified == cache->superstates)
+    return;
+  while (cache->lru_superstate->locks)
+    {
+      cache->lru_superstate = cache->lru_superstate->next_recyclable;
+      ++disqualified;
+      if (disqualified == cache->superstates)
+	return;
+    }
+  {
+    struct rx_superstate * it = cache->lru_superstate;
+    it->next_recyclable->prev_recyclable = it->prev_recyclable;
+    it->prev_recyclable->next_recyclable = it->next_recyclable;
+    cache->lru_superstate = (it == it->next_recyclable
+			     ? 0
+			     : it->next_recyclable);
+    if (!cache->semifree_superstate)
+      {
+	cache->semifree_superstate = it;
+	it->next_recyclable = it;
+	it->prev_recyclable = it;
+      }
+    else
+      {
+	it->prev_recyclable = cache->semifree_superstate->prev_recyclable;
+	it->next_recyclable = cache->semifree_superstate;
+	it->prev_recyclable->next_recyclable = it;
+	it->next_recyclable->prev_recyclable = it;
+      }
+    {
+      struct rx_distinct_future *df;
+      it->is_semifree = 1;
+      ++cache->semifree_superstates;
+      df = it->transition_refs;
+      if (df)
+	{
+	  df->prev_same_dest->next_same_dest = 0;
+	  for (df = it->transition_refs; df; df = df->next_same_dest)
+	    {
+	      df->future_frame.inx = cache->instruction_table[rx_cache_miss];
+	      df->future_frame.data = 0;
+	      df->future_frame.data_2 = (void *) df;
+	      /* If there are any NEXT-CHAR instruction frames that
+	       * refer to this state, we convert them to CACHE-MISS frames.
+	       */
+	      if (!df->effects
+		  && (df->edge->options->next_same_super_edge[0]
+		      == df->edge->options))
+		install_transition (df->present, &df->future_frame,
+				    df->edge->cset);
+	    }
+	  df = it->transition_refs;
+	  df->prev_same_dest->next_same_dest = df;
+	}
+    }
+  }
+}
+
+
+#ifdef __STDC__
+static void 
+refresh_semifree_superstate (struct rx_cache * cache,
+			     struct rx_superstate * super)
+#else
+static void 
+refresh_semifree_superstate (cache, super)
+     struct rx_cache * cache;
+     struct rx_superstate * super;
+#endif
+{
+  struct rx_distinct_future *df;
+
+  if (super->transition_refs)
+    {
+      super->transition_refs->prev_same_dest->next_same_dest = 0; 
+      for (df = super->transition_refs; df; df = df->next_same_dest)
+	{
+	  df->future_frame.inx = cache->instruction_table[rx_next_char];
+	  df->future_frame.data = (void *) super->transitions;
+	  /* CACHE-MISS instruction frames that refer to this state,
+	   * must be converted to NEXT-CHAR frames.
+	   */
+	  if (!df->effects
+	      && (df->edge->options->next_same_super_edge[0]
+		  == df->edge->options))
+	    install_transition (df->present, &df->future_frame,
+				df->edge->cset);
+	}
+      super->transition_refs->prev_same_dest->next_same_dest
+	= super->transition_refs;
+    }
+  if (cache->semifree_superstate == super)
+    cache->semifree_superstate = (super->prev_recyclable == super
+				  ? 0
+				  : super->prev_recyclable);
+  super->next_recyclable->prev_recyclable = super->prev_recyclable;
+  super->prev_recyclable->next_recyclable = super->next_recyclable;
+
+  if (!cache->lru_superstate)
+    (cache->lru_superstate
+     = super->next_recyclable
+     = super->prev_recyclable
+     = super);
+  else
+    {
+      super->next_recyclable = cache->lru_superstate;
+      super->prev_recyclable = cache->lru_superstate->prev_recyclable;
+      super->next_recyclable->prev_recyclable = super;
+      super->prev_recyclable->next_recyclable = super;
+    }
+  super->is_semifree = 0;
+  --cache->semifree_superstates;
+}
+
+#ifdef __STDC__
+static void
+rx_refresh_this_superstate (struct rx_cache * cache, struct rx_superstate * superstate)
+#else
+static void
+rx_refresh_this_superstate (cache, superstate)
+     struct rx_cache * cache;
+     struct rx_superstate * superstate;
+#endif
+{
+  if (superstate->is_semifree)
+    refresh_semifree_superstate (cache, superstate);
+  else if (cache->lru_superstate == superstate)
+    cache->lru_superstate = superstate->next_recyclable;
+  else if (superstate != cache->lru_superstate->prev_recyclable)
+    {
+      superstate->next_recyclable->prev_recyclable
+	= superstate->prev_recyclable;
+      superstate->prev_recyclable->next_recyclable
+	= superstate->next_recyclable;
+      superstate->next_recyclable = cache->lru_superstate;
+      superstate->prev_recyclable = cache->lru_superstate->prev_recyclable;
+      superstate->next_recyclable->prev_recyclable = superstate;
+      superstate->prev_recyclable->next_recyclable = superstate;
+    }
+}
+
+#ifdef __STDC__
+static void 
+release_superset_low (struct rx_cache * cache,
+		     struct rx_superset *set)
+#else
+static void 
+release_superset_low (cache, set)
+     struct rx_cache * cache;
+     struct rx_superset *set;
+#endif
+{
+  if (!--set->refs)
+    {
+      if (set->cdr)
+	release_superset_low (cache, set->cdr);
+
+      set->starts_for = 0;
+
+      rx_hash_free
+	(rx_hash_find
+	 (&cache->superset_table,
+	  (unsigned long)set->car ^ set->id ^ (unsigned long)set->cdr,
+	  (void *)set,
+	  &cache->superset_hash_rules),
+	 &cache->superset_hash_rules);
+      rx_cache_free (cache, &cache->free_supersets, (char *)set);
+    }
+}
+
+#ifdef __STDC__
+RX_DECL void 
+rx_release_superset (struct rx *rx,
+		     struct rx_superset *set)
+#else
+RX_DECL void 
+rx_release_superset (rx, set)
+     struct rx *rx;
+     struct rx_superset *set;
+#endif
+{
+  release_superset_low (rx->cache, set);
+}
+
+/* This tries to add a new superstate to the superstate freelist.
+ * It might, as a result, free some edge pieces or hash tables.
+ * If nothing can be freed because too many locks are being held, fail.
+ */
+
+#ifdef __STDC__
+static int
+rx_really_free_superstate (struct rx_cache * cache)
+#else
+static int
+rx_really_free_superstate (cache)
+     struct rx_cache * cache;
+#endif
+{
+  int locked_superstates = 0;
+  struct rx_superstate * it;
+
+  if (!cache->superstates)
+    return 0;
+
+  {
+    /* This is a total guess.  The idea is that we should expect as
+     * many misses as we've recently experienced.  I.e., cache->misses
+     * should be the same as cache->semifree_superstates.
+     */
+    while ((cache->hits + cache->misses) > cache->superstates_allowed)
+      {
+	cache->hits >>= 1;
+	cache->misses >>= 1;
+      }
+    if (  ((cache->hits + cache->misses) * cache->semifree_superstates)
+	< (cache->superstates		 * cache->misses))
+      {
+	semifree_superstate (cache);
+	semifree_superstate (cache);
+      }
+  }
+
+  while (cache->semifree_superstate && cache->semifree_superstate->locks)
+    {
+      refresh_semifree_superstate (cache, cache->semifree_superstate);
+      ++locked_superstates;
+      if (locked_superstates == cache->superstates)
+	return 0;
+    }
+
+  if (cache->semifree_superstate)
+    {
+      it = cache->semifree_superstate;
+      it->next_recyclable->prev_recyclable = it->prev_recyclable;
+      it->prev_recyclable->next_recyclable = it->next_recyclable;
+      cache->semifree_superstate = ((it == it->next_recyclable)
+				    ? 0
+				    : it->next_recyclable);
+      --cache->semifree_superstates;
+    }
+  else
+    {
+      while (cache->lru_superstate->locks)
+	{
+	  cache->lru_superstate = cache->lru_superstate->next_recyclable;
+	  ++locked_superstates;
+	  if (locked_superstates == cache->superstates)
+	    return 0;
+	}
+      it = cache->lru_superstate;
+      it->next_recyclable->prev_recyclable = it->prev_recyclable;
+      it->prev_recyclable->next_recyclable = it->next_recyclable;
+      cache->lru_superstate = ((it == it->next_recyclable)
+				    ? 0
+				    : it->next_recyclable);
+    }
+
+  if (it->transition_refs)
+    {
+      struct rx_distinct_future *df;
+      for (df = it->transition_refs,
+	   df->prev_same_dest->next_same_dest = 0;
+	   df;
+	   df = df->next_same_dest)
+	{
+	  df->future_frame.inx = cache->instruction_table[rx_cache_miss];
+	  df->future_frame.data = 0;
+	  df->future_frame.data_2 = (void *) df;
+	  df->future = 0;
+	}
+      it->transition_refs->prev_same_dest->next_same_dest =
+	it->transition_refs;
+    }
+  {
+    struct rx_super_edge *tc = it->edges;
+    while (tc)
+      {
+	struct rx_distinct_future * df;
+	struct rx_super_edge *tct = tc->next;
+	df = tc->options;
+	df->next_same_super_edge[1]->next_same_super_edge[0] = 0;
+	while (df)
+	  {
+	    struct rx_distinct_future *dft = df;
+	    df = df->next_same_super_edge[0];
+	    
+	    
+	    if (dft->future && dft->future->transition_refs == dft)
+	      {
+		dft->future->transition_refs = dft->next_same_dest;
+		if (dft->future->transition_refs == dft)
+		  dft->future->transition_refs = 0;
+	      }
+	    dft->next_same_dest->prev_same_dest = dft->prev_same_dest;
+	    dft->prev_same_dest->next_same_dest = dft->next_same_dest;
+	    rx_cache_free (cache, &cache->free_discernable_futures,
+			   (char *)dft);
+	  }
+	rx_cache_free (cache, &cache->free_transition_classes, (char *)tc);
+	tc = tct;
+      }
+  }
+  
+  if (it->contents->superstate == it)
+    it->contents->superstate = 0;
+  release_superset_low (cache, it->contents);
+  rx_cache_free (cache, &cache->free_superstates, (char *)it);
+  --cache->superstates;
+  return 1;
+}
+
+#ifdef __STDC__
+static char *
+rx_cache_get (struct rx_cache * cache,
+	      struct rx_freelist ** freelist)
+#else
+static char *
+rx_cache_get (cache, freelist)
+     struct rx_cache * cache;
+     struct rx_freelist ** freelist;
+#endif
+{
+  while (!*freelist && rx_really_free_superstate (cache))
+    ;
+  if (!*freelist)
+    return 0;
+  {
+    struct rx_freelist * it = *freelist;
+    *freelist = it->next;
+    return (char *)it;
+  }
+}
+
+#ifdef __STDC__
+static char *
+rx_cache_malloc_or_get (struct rx_cache * cache,
+			struct rx_freelist ** freelist, int bytes)
+#else
+static char *
+rx_cache_malloc_or_get (cache, freelist, bytes)
+     struct rx_cache * cache;
+     struct rx_freelist ** freelist;
+     int bytes;
+#endif
+{
+  if (!*freelist)
+    {
+      char * answer = rx_cache_malloc (cache, bytes);
+      if (answer)
+	return answer;
+    }
+
+  return rx_cache_get (cache, freelist);
+}
+
+#ifdef __STDC__
+static char *
+rx_cache_get_superstate (struct rx_cache * cache)
+#else
+static char *
+rx_cache_get_superstate (cache)
+	  struct rx_cache * cache;
+#endif
+{
+  char * answer;
+  int bytes = (   sizeof (struct rx_superstate)
+	       +  cache->local_cset_size * sizeof (struct rx_inx));
+  if (!cache->free_superstates
+      && (cache->superstates < cache->superstates_allowed))
+    {
+      answer = rx_cache_malloc (cache, bytes);
+      if (answer)
+	{
+	  ++cache->superstates;
+	  return answer;
+	}
+    }
+  answer = rx_cache_get (cache, &cache->free_superstates);
+  if (!answer)
+    {
+      answer = rx_cache_malloc (cache, bytes);
+      if (answer)
+	++cache->superstates_allowed;
+    }
+  ++cache->superstates;
+  return answer;
+}
+
+
+
+
+#ifdef __STDC__
+static int
+supersetcmp (void * va, void * vb)
+#else
+static int
+supersetcmp (va, vb)
+     void * va;
+     void * vb;
+#endif
+{
+  struct rx_superset * a = (struct rx_superset *)va;
+  struct rx_superset * b = (struct rx_superset *)vb;
+  return (   (a == b)
+	  || (a && b && (a->car == b->car) && (a->cdr == b->cdr)));
+}
+
+#ifdef __STDC__
+static struct rx_hash_item *
+superset_allocator (struct rx_hash_rules * rules, void * val)
+#else
+static struct rx_hash_item *
+superset_allocator (rules, val)
+     struct rx_hash_rules * rules;
+     void * val;
+#endif
+{
+  struct rx_cache * cache
+    = ((struct rx_cache *)
+       ((char *)rules
+	- (unsigned long)(&((struct rx_cache *)0)->superset_hash_rules)));
+  struct rx_superset * template = (struct rx_superset *)val;
+  struct rx_superset * newset
+    = ((struct rx_superset *)
+       rx_cache_malloc_or_get (cache,
+			       &cache->free_supersets,
+			       sizeof (*template)));
+  if (!newset)
+    return 0;
+  newset->refs = 0;
+  newset->car = template->car;
+  newset->id = template->car->id;
+  newset->cdr = template->cdr;
+  newset->superstate = 0;
+  rx_protect_superset (rx, template->cdr);
+  newset->hash_item.data = (void *)newset;
+  newset->hash_item.binding = 0;
+  return &newset->hash_item;
+}
+
+#ifdef __STDC__
+static struct rx_hash * 
+super_hash_allocator (struct rx_hash_rules * rules)
+#else
+static struct rx_hash * 
+super_hash_allocator (rules)
+     struct rx_hash_rules * rules;
+#endif
+{
+  struct rx_cache * cache
+    = ((struct rx_cache *)
+       ((char *)rules
+	- (unsigned long)(&((struct rx_cache *)0)->superset_hash_rules)));
+  return ((struct rx_hash *)
+	  rx_cache_malloc_or_get (cache,
+				  &cache->free_hash, sizeof (struct rx_hash)));
+}
+
+
+#ifdef __STDC__
+static void
+super_hash_liberator (struct rx_hash * hash, struct rx_hash_rules * rules)
+#else
+static void
+super_hash_liberator (hash, rules)
+     struct rx_hash * hash;
+     struct rx_hash_rules * rules;
+#endif
+{
+  struct rx_cache * cache
+    = ((struct rx_cache *)
+       (char *)rules - (long)(&((struct rx_cache *)0)->superset_hash_rules));
+  rx_cache_free (cache, &cache->free_hash, (char *)hash);
+}
+
+#ifdef __STDC__
+static void
+superset_hash_item_liberator (struct rx_hash_item * it,
+			      struct rx_hash_rules * rules)
+#else
+static void
+superset_hash_item_liberator (it, rules) /* Well, it does ya know. */
+     struct rx_hash_item * it;
+     struct rx_hash_rules * rules;
+#endif
+{
+}
+
+int rx_cache_bound = 128;
+static int rx_default_cache_got = 0;
+
+#ifdef __STDC__
+static int
+bytes_for_cache_size (int supers, int cset_size)
+#else
+static int
+bytes_for_cache_size (supers, cset_size)
+     int supers;
+     int cset_size;
+#endif
+{
+  /* What the hell is this? !!!*/
+  return (int)
+    ((float)supers *
+     (  (1.03 * (float) (  rx_sizeof_bitset (cset_size)
+			 + sizeof (struct rx_super_edge)))
+      + (1.80 * (float) sizeof (struct rx_possible_future))
+      + (float) (  sizeof (struct rx_superstate)
+		 + cset_size * sizeof (struct rx_inx))));
+}
+
+#ifdef __STDC__
+static void
+rx_morecore (struct rx_cache * cache)
+#else
+static void
+rx_morecore (cache)
+     struct rx_cache * cache;
+#endif
+{
+  if (rx_default_cache_got >= rx_cache_bound)
+    return;
+
+  rx_default_cache_got += 16;
+  cache->superstates_allowed = rx_cache_bound;
+  {
+    struct rx_blocklist ** pos = &cache->memory;
+    int size = bytes_for_cache_size (16, cache->local_cset_size);
+    while (*pos)
+      pos = &(*pos)->next;
+    *pos = ((struct rx_blocklist *)
+	    malloc (size + sizeof (struct rx_blocklist))); 
+    if (!*pos)
+      return;
+
+    (*pos)->next = 0;
+    (*pos)->bytes = size;
+    cache->memory_pos = *pos;
+    cache->memory_addr = (char *)*pos + sizeof (**pos);
+    cache->bytes_left = size;
+  }
+}
+
+static struct rx_cache default_cache = 
+{
+  {
+    supersetcmp,
+    super_hash_allocator,
+    super_hash_liberator,
+    superset_allocator,
+    superset_hash_item_liberator,
+  },
+  0,
+  0,
+  0,
+  0,
+  rx_morecore,
+
+  0,
+  0,
+  0,
+  0,
+  0,
+
+  0,
+  0,
+
+  0,
+
+  0,
+  0,
+  0,
+  0,
+  128,
+
+  256,
+  rx_id_instruction_table,
+
+  {
+    0,
+    0,
+    {0},
+    {0},
+    {0}
+  }
+};
+
+/* This adds an element to a superstate set.  These sets are lists, such
+ * that lists with == elements are ==.  The empty set is returned by
+ * superset_cons (rx, 0, 0) and is NOT equivelent to 
+ * (struct rx_superset)0.
+ */
+
+#ifdef __STDC__
+RX_DECL struct rx_superset *
+rx_superset_cons (struct rx * rx,
+		  struct rx_nfa_state *car, struct rx_superset *cdr)
+#else
+RX_DECL struct rx_superset *
+rx_superset_cons (rx, car, cdr)
+     struct rx * rx;
+     struct rx_nfa_state *car;
+     struct rx_superset *cdr;
+#endif
+{
+  struct rx_cache * cache = rx->cache;
+  if (!car && !cdr)
+    {
+      if (!cache->empty_superset)
+	{
+	  cache->empty_superset
+	    = ((struct rx_superset *)
+	       rx_cache_malloc_or_get (cache, &cache->free_supersets,
+				       sizeof (struct rx_superset)));
+	  if (!cache->empty_superset)
+	    return 0;
+	  bzero (cache->empty_superset, sizeof (struct rx_superset));
+	  cache->empty_superset->refs = 1000;
+	}
+      return cache->empty_superset;
+    }
+  {
+    struct rx_superset template;
+    struct rx_hash_item * hit;
+    template.car = car;
+    template.cdr = cdr;
+    template.id = car->id;
+    hit = rx_hash_store (&cache->superset_table,
+			 (unsigned long)car ^ car->id ^ (unsigned long)cdr,
+			 (void *)&template,
+			 &cache->superset_hash_rules);
+    return (hit
+	    ?  (struct rx_superset *)hit->data
+	    : 0);
+  }
+}
+
+/* This computes a union of two NFA state sets.  The sets do not have the
+ * same representation though.  One is a RX_SUPERSET structure (part
+ * of the superstate NFA) and the other is an NFA_STATE_SET (part of the NFA).
+ */
+
+#ifdef __STDC__
+RX_DECL struct rx_superset *
+rx_superstate_eclosure_union
+  (struct rx * rx, struct rx_superset *set, struct rx_nfa_state_set *ecl) 
+#else
+RX_DECL struct rx_superset *
+rx_superstate_eclosure_union (rx, set, ecl)
+     struct rx * rx;
+     struct rx_superset *set;
+     struct rx_nfa_state_set *ecl;
+#endif
+{
+  if (!ecl)
+    return set;
+
+  if (!set->car)
+    return rx_superset_cons (rx, ecl->car,
+			     rx_superstate_eclosure_union (rx, set, ecl->cdr));
+  if (set->car == ecl->car)
+    return rx_superstate_eclosure_union (rx, set, ecl->cdr);
+
+  {
+    struct rx_superset * tail;
+    struct rx_nfa_state * first;
+
+    if (set->car > ecl->car)
+      {
+	tail = rx_superstate_eclosure_union (rx, set->cdr, ecl);
+	first = set->car;
+      }
+    else
+      {
+	tail = rx_superstate_eclosure_union (rx, set, ecl->cdr);
+	first = ecl->car;
+      }
+    if (!tail)
+      return 0;
+    else
+      {
+	struct rx_superset * answer;
+	answer = rx_superset_cons (rx, first, tail);
+	if (!answer)
+	  {
+	    rx_protect_superset (rx, tail);
+	    rx_release_superset (rx, tail);
+	    return 0;
+	  }
+	else
+	  return answer;
+      }
+  }
+}
+
+
+
+
+
+/*
+ * This makes sure that a list of rx_distinct_futures contains
+ * a future for each possible set of side effects in the eclosure
+ * of a given state.  This is some of the work of filling in a
+ * superstate transition. 
+ */
+
+#ifdef __STDC__
+static struct rx_distinct_future *
+include_futures (struct rx *rx,
+		 struct rx_distinct_future *df, struct rx_nfa_state
+		 *state, struct rx_superstate *superstate) 
+#else
+static struct rx_distinct_future *
+include_futures (rx, df, state, superstate)
+     struct rx *rx;
+     struct rx_distinct_future *df;
+     struct rx_nfa_state *state;
+     struct rx_superstate *superstate;
+#endif
+{
+  struct rx_possible_future *future;
+  struct rx_cache * cache = rx->cache;
+  for (future = state->futures; future; future = future->next)
+    {
+      struct rx_distinct_future *dfp;
+      struct rx_distinct_future *insert_before = 0;
+      if (df)
+	df->next_same_super_edge[1]->next_same_super_edge[0] = 0;
+      for (dfp = df; dfp; dfp = dfp->next_same_super_edge[0])
+	if (dfp->effects == future->effects)
+	  break;
+	else
+	  {
+	    int order = rx->se_list_cmp (rx, dfp->effects, future->effects);
+	    if (order > 0)
+	      {
+		insert_before = dfp;
+		dfp = 0;
+		break;
+	      }
+	  }
+      if (df)
+	df->next_same_super_edge[1]->next_same_super_edge[0] = df;
+      if (!dfp)
+	{
+	  dfp
+	    = ((struct rx_distinct_future *)
+	       rx_cache_malloc_or_get (cache, &cache->free_discernable_futures,
+				       sizeof (struct rx_distinct_future)));
+	  if (!dfp)
+	    return 0;
+	  if (!df)
+	    {
+	      df = insert_before = dfp;
+	      df->next_same_super_edge[0] = df->next_same_super_edge[1] = df;
+	    }
+	  else if (!insert_before)
+	    insert_before = df;
+	  else if (insert_before == df)
+	    df = dfp;
+
+	  dfp->next_same_super_edge[0] = insert_before;
+	  dfp->next_same_super_edge[1]
+	    = insert_before->next_same_super_edge[1];
+	  dfp->next_same_super_edge[1]->next_same_super_edge[0] = dfp;
+	  dfp->next_same_super_edge[0]->next_same_super_edge[1] = dfp;
+	  dfp->next_same_dest = dfp->prev_same_dest = dfp;
+	  dfp->future = 0;
+	  dfp->present = superstate;
+	  dfp->future_frame.inx = rx->instruction_table[rx_cache_miss];
+	  dfp->future_frame.data = 0;
+	  dfp->future_frame.data_2 = (void *) dfp;
+	  dfp->side_effects_frame.inx
+	    = rx->instruction_table[rx_do_side_effects];
+	  dfp->side_effects_frame.data = 0;
+	  dfp->side_effects_frame.data_2 = (void *) dfp;
+	  dfp->effects = future->effects;
+	}
+    }
+  return df;
+}
+
+
+
+
+/* This constructs a new superstate from its state set.  The only 
+ * complexity here is memory management.
+ */
+#ifdef __STDC__
+RX_DECL struct rx_superstate *
+rx_superstate (struct rx *rx,
+	       struct rx_superset *set)
+#else
+RX_DECL struct rx_superstate *
+rx_superstate (rx, set)
+     struct rx *rx;
+     struct rx_superset *set;
+#endif
+{
+  struct rx_cache * cache = rx->cache;
+  struct rx_superstate * superstate = 0;
+
+  /* Does the superstate already exist in the cache? */
+  if (set->superstate)
+    {
+      if (set->superstate->rx_id != rx->rx_id)
+	{
+	  /* Aha.  It is in the cache, but belongs to a superstate
+	   * that refers to an NFA that no longer exists.
+	   * (We know it no longer exists because it was evidently
+	   *  stored in the same region of memory as the current nfa
+	   *  yet it has a different id.)
+	   */
+	  superstate = set->superstate;
+	  if (!superstate->is_semifree)
+	    {
+	      if (cache->lru_superstate == superstate)
+		{
+		  cache->lru_superstate = superstate->next_recyclable;
+		  if (cache->lru_superstate == superstate)
+		    cache->lru_superstate = 0;
+		}
+	      {
+		superstate->next_recyclable->prev_recyclable
+		  = superstate->prev_recyclable;
+		superstate->prev_recyclable->next_recyclable
+		  = superstate->next_recyclable;
+		if (!cache->semifree_superstate)
+		  {
+		    (cache->semifree_superstate
+		     = superstate->next_recyclable
+		     = superstate->prev_recyclable
+		     = superstate);
+		  }
+		else
+		  {
+		    superstate->next_recyclable = cache->semifree_superstate;
+		    superstate->prev_recyclable
+		      = cache->semifree_superstate->prev_recyclable;
+		    superstate->next_recyclable->prev_recyclable
+		      = superstate;
+		    superstate->prev_recyclable->next_recyclable
+		      = superstate;
+		    cache->semifree_superstate = superstate;
+		  }
+		++cache->semifree_superstates;
+	      }
+	    }
+	  set->superstate = 0;
+	  goto handle_cache_miss;
+	}
+      ++cache->hits;
+      superstate = set->superstate;
+
+      rx_refresh_this_superstate (cache, superstate);
+      return superstate;
+    }
+
+ handle_cache_miss:
+
+  /* This point reached only for cache misses. */
+  ++cache->misses;
+#if RX_DEBUG
+  if (rx_debug_trace > 1)
+    {
+      struct rx_superset * setp = set;
+      fprintf (stderr, "Building a superstet %d(%d): ", rx->rx_id, set);
+      while (setp)
+	{
+	  fprintf (stderr, "%d ", setp->id);
+	  setp = setp->cdr;
+	}
+      fprintf (stderr, "(%d)\n", set);
+    }
+#endif
+  superstate = (struct rx_superstate *)rx_cache_get_superstate (cache);
+  if (!superstate)
+    return 0;
+
+  if (!cache->lru_superstate)
+    (cache->lru_superstate
+     = superstate->next_recyclable
+     = superstate->prev_recyclable
+     = superstate);
+  else
+    {
+      superstate->next_recyclable = cache->lru_superstate;
+      superstate->prev_recyclable = cache->lru_superstate->prev_recyclable;
+      (  superstate->prev_recyclable->next_recyclable
+       = superstate->next_recyclable->prev_recyclable
+       = superstate);
+    }
+  superstate->rx_id = rx->rx_id;
+  superstate->transition_refs = 0;
+  superstate->locks = 0;
+  superstate->is_semifree = 0;
+  set->superstate = superstate;
+  superstate->contents = set;
+  rx_protect_superset (rx, set);
+  superstate->edges = 0;
+  {
+    int x;
+    /* None of the transitions from this superstate are known yet. */
+    for (x = 0; x < rx->local_cset_size; ++x) /* &&&&& 3.8 % */
+      {
+	struct rx_inx * ifr = &superstate->transitions[x];
+	ifr->inx = rx->instruction_table [rx_cache_miss];
+	ifr->data = ifr->data_2 = 0;
+      }
+  }
+  return superstate;
+}
+
+
+
+/* This computes the destination set of one edge of the superstate NFA.
+ * Note that a RX_DISTINCT_FUTURE is a superstate edge.
+ * Returns 0 on an allocation failure.
+ */
+
+#ifdef __STDC__
+static int 
+solve_destination (struct rx *rx, struct rx_distinct_future *df)
+#else
+static int 
+solve_destination (rx, df)
+     struct rx *rx;
+     struct rx_distinct_future *df;
+#endif
+{
+  struct rx_super_edge *tc = df->edge;
+  struct rx_superset *nfa_state;
+  struct rx_superset *nil_set = rx_superset_cons (rx, 0, 0);
+  struct rx_superset *solution = nil_set;
+  struct rx_superstate *dest;
+
+  rx_protect_superset (rx, solution);
+  /* Iterate over all NFA states in the state set of this superstate. */
+  for (nfa_state = df->present->contents;
+       nfa_state->car;
+       nfa_state = nfa_state->cdr)
+    {
+      struct rx_nfa_edge *e;
+      /* Iterate over all edges of each NFA state. */
+      for (e = nfa_state->car->edges; e; e = e->next)
+        /* If we find an edge that is labeled with 
+	 * the characters we are solving for.....
+	 */
+	if (rx_bitset_is_subset (rx->local_cset_size,
+				 tc->cset, e->params.cset))
+	  {
+	    struct rx_nfa_state *n = e->dest;
+	    struct rx_possible_future *pf;
+	    /* ....search the partial epsilon closures of the destination
+	     * of that edge for a path that involves the same set of
+	     * side effects we are solving for.
+	     * If we find such a RX_POSSIBLE_FUTURE, we add members to the
+	     * stateset we are computing.
+	     */
+	    for (pf = n->futures; pf; pf = pf->next)
+	      if (pf->effects == df->effects)
+		{
+		  struct rx_superset * old_sol;
+		  old_sol = solution;
+		  solution = rx_superstate_eclosure_union (rx, solution,
+							   pf->destset);
+		  if (!solution)
+		    return 0;
+		  rx_protect_superset (rx, solution);
+		  rx_release_superset (rx, old_sol);
+		}
+	  }
+    }
+  /* It is possible that the RX_DISTINCT_FUTURE we are working on has 
+   * the empty set of NFA states as its definition.  In that case, this
+   * is a failure point.
+   */
+  if (solution == nil_set)
+    {
+      df->future_frame.inx = (void *) rx_backtrack;
+      df->future_frame.data = 0;
+      df->future_frame.data_2 = 0;
+      return 1;
+    }
+  dest = rx_superstate (rx, solution);
+  rx_release_superset (rx, solution);
+  if (!dest)
+    return 0;
+
+  {
+    struct rx_distinct_future *dft;
+    dft = df;
+    df->prev_same_dest->next_same_dest = 0;
+    while (dft)
+      {
+	dft->future = dest;
+	dft->future_frame.inx = rx->instruction_table[rx_next_char];
+	dft->future_frame.data = (void *) dest->transitions;
+	dft = dft->next_same_dest;
+      }
+    df->prev_same_dest->next_same_dest = df;
+  }
+  if (!dest->transition_refs)
+    dest->transition_refs = df;
+  else
+    {
+      struct rx_distinct_future *dft = dest->transition_refs->next_same_dest;
+      dest->transition_refs->next_same_dest = df->next_same_dest;
+      df->next_same_dest->prev_same_dest = dest->transition_refs;
+      df->next_same_dest = dft;
+      dft->prev_same_dest = df;
+    }
+  return 1;
+}
+
+
+/* This takes a superstate and a character, and computes some edges
+ * from the superstate NFA.  In particular, this computes all edges
+ * that lead from SUPERSTATE given CHR.   This function also 
+ * computes the set of characters that share this edge set.
+ * This returns 0 on allocation error.
+ * The character set and list of edges are returned through 
+ * the paramters CSETOUT and DFOUT.
+} */
+
+#ifdef __STDC__
+static int 
+compute_super_edge (struct rx *rx, struct rx_distinct_future **dfout,
+			  rx_Bitset csetout, struct rx_superstate *superstate,
+			  unsigned char chr)  
+#else
+static int 
+compute_super_edge (rx, dfout, csetout, superstate, chr)
+     struct rx *rx;
+     struct rx_distinct_future **dfout;
+     rx_Bitset csetout;
+     struct rx_superstate *superstate;
+     unsigned char chr;
+#endif
+{
+  struct rx_superset *stateset = superstate->contents;
+
+  /* To compute the set of characters that share edges with CHR, 
+   * we start with the full character set, and subtract.
+   */
+  rx_bitset_universe (rx->local_cset_size, csetout);
+  *dfout = 0;
+
+  /* Iterate over the NFA states in the superstate state-set. */
+  while (stateset->car)
+    {
+      struct rx_nfa_edge *e;
+      for (e = stateset->car->edges; e; e = e->next)
+	if (RX_bitset_member (e->params.cset, chr))
+	  {
+	    /* If we find an NFA edge that applies, we make sure there
+	     * are corresponding edges in the superstate NFA.
+	     */
+	    {
+	      struct rx_distinct_future * saved;
+	      saved = *dfout;
+	      *dfout = include_futures (rx, *dfout, e->dest, superstate);
+	      if (!*dfout)
+		{
+		  struct rx_distinct_future * df;
+		  df = saved;
+		  df->next_same_super_edge[1]->next_same_super_edge[0] = 0;
+		  while (df)
+		    {
+		      struct rx_distinct_future *dft;
+		      dft = df;
+		      df = df->next_same_super_edge[0];
+
+		      if (dft->future && dft->future->transition_refs == dft)
+			{
+			  dft->future->transition_refs = dft->next_same_dest;
+			  if (dft->future->transition_refs == dft)
+			    dft->future->transition_refs = 0;
+			}
+		      dft->next_same_dest->prev_same_dest = dft->prev_same_dest;
+		      dft->prev_same_dest->next_same_dest = dft->next_same_dest;
+		      rx_cache_free (rx->cache,
+				     &rx->cache->free_discernable_futures,
+				     (char *)dft);
+		    }
+		  return 0;
+		}
+	    }
+	    /* We also trim the character set a bit. */
+	    rx_bitset_intersection (rx->local_cset_size,
+				    csetout, e->params.cset);
+	  }
+	else
+	  /* An edge that doesn't apply at least tells us some characters
+	   * that don't share the same edge set as CHR.
+	   */
+	  rx_bitset_difference (rx->local_cset_size, csetout, e->params.cset);
+      stateset = stateset->cdr;
+    }
+  return 1;
+}
+
+
+
+/* This is a constructor for RX_SUPER_EDGE structures.  These are
+ * wrappers for lists of superstate NFA edges that share character sets labels.
+ * If a transition class contains more than one rx_distinct_future (superstate
+ * edge), then it represents a non-determinism in the superstate NFA.
+ */
+
+#ifdef __STDC__
+static struct rx_super_edge *
+rx_super_edge (struct rx *rx,
+	       struct rx_superstate *super, rx_Bitset cset,
+	       struct rx_distinct_future *df) 
+#else
+static struct rx_super_edge *
+rx_super_edge (rx, super, cset, df)
+     struct rx *rx;
+     struct rx_superstate *super;
+     rx_Bitset cset;
+     struct rx_distinct_future *df;
+#endif
+{
+  struct rx_super_edge *tc =
+    (struct rx_super_edge *)rx_cache_malloc_or_get
+      (rx->cache, &rx->cache->free_transition_classes,
+       sizeof (struct rx_super_edge) + rx_sizeof_bitset (rx->local_cset_size));
+
+  if (!tc)
+    return 0;
+  tc->next = super->edges;
+  super->edges = tc;
+  tc->rx_backtrack_frame.inx = rx->instruction_table[rx_backtrack_point];
+  tc->rx_backtrack_frame.data = 0;
+  tc->rx_backtrack_frame.data_2 = (void *) tc;
+  tc->options = df;
+  tc->cset = (rx_Bitset) ((char *) tc + sizeof (*tc));
+  rx_bitset_assign (rx->local_cset_size, tc->cset, cset);
+  if (df)
+    {
+      struct rx_distinct_future * dfp = df;
+      df->next_same_super_edge[1]->next_same_super_edge[0] = 0;
+      while (dfp)
+	{
+	  dfp->edge = tc;
+	  dfp = dfp->next_same_super_edge[0];
+	}
+      df->next_same_super_edge[1]->next_same_super_edge[0] = df;
+    }
+  return tc;
+}
+
+
+/* There are three kinds of cache miss.  The first occurs when a
+ * transition is taken that has never been computed during the
+ * lifetime of the source superstate.  That cache miss is handled by
+ * calling COMPUTE_SUPER_EDGE.  The second kind of cache miss
+ * occurs when the destination superstate of a transition doesn't
+ * exist.  SOLVE_DESTINATION is used to construct the destination superstate.
+ * Finally, the third kind of cache miss occurs when the destination
+ * superstate of a transition is in a `semi-free state'.  That case is
+ * handled by UNFREE_SUPERSTATE.
+ *
+ * The function of HANDLE_CACHE_MISS is to figure out which of these
+ * cases applies.
+ */
+
+#ifdef __STDC__
+static void
+install_partial_transition  (struct rx_superstate *super,
+			     struct rx_inx *answer,
+			     RX_subset set, int offset)
+#else
+static void
+install_partial_transition  (super, answer, set, offset)
+     struct rx_superstate *super;
+     struct rx_inx *answer;
+     RX_subset set;
+     int offset;
+#endif
+{
+  int start = offset;
+  int end = start + 32;
+  RX_subset pos = 1;
+  struct rx_inx * transitions = super->transitions;
+  
+  while (start < end)
+    {
+      if (set & pos)
+	transitions[start] = *answer;
+      pos <<= 1;
+      ++start;
+    }
+}
+
+
+#ifdef __STDC__
+RX_DECL struct rx_inx *
+rx_handle_cache_miss
+  (struct rx *rx, struct rx_superstate *super, unsigned char chr, void *data) 
+#else
+RX_DECL struct rx_inx *
+rx_handle_cache_miss (rx, super, chr, data)
+     struct rx *rx;
+     struct rx_superstate *super;
+     unsigned char chr;
+     void *data;
+#endif
+{
+  int offset = chr / RX_subset_bits;
+  struct rx_distinct_future *df = data;
+
+  if (!df)			/* must be the shared_cache_miss_frame */
+    {
+      /* Perhaps this is just a transition waiting to be filled. */
+      struct rx_super_edge *tc;
+      RX_subset mask = rx_subset_singletons [chr % RX_subset_bits];
+
+      for (tc = super->edges; tc; tc = tc->next)
+	if (tc->cset[offset] & mask)
+	  {
+	    struct rx_inx * answer;
+	    df = tc->options;
+	    answer = ((tc->options->next_same_super_edge[0] != tc->options)
+		      ? &tc->rx_backtrack_frame
+		      : (df->effects
+			 ? &df->side_effects_frame
+			 : &df->future_frame));
+	    install_partial_transition (super, answer,
+					tc->cset [offset], offset * 32);
+	    return answer;
+	  }
+      /* Otherwise, it's a flushed or  newly encountered edge. */
+      {
+	char cset_space[1024];	/* this limit is far from unreasonable */
+	rx_Bitset trcset;
+	struct rx_inx *answer;
+
+	if (rx_sizeof_bitset (rx->local_cset_size) > sizeof (cset_space))
+	  return 0;		/* If the arbitrary limit is hit, always fail */
+				/* cleanly. */
+	trcset = (rx_Bitset)cset_space;
+	rx_lock_superstate (rx, super);
+	if (!compute_super_edge (rx, &df, trcset, super, chr))
+	  {
+	    rx_unlock_superstate (rx, super);
+	    return 0;
+	  }
+	if (!df)		/* We just computed the fail transition. */
+	  {
+	    static struct rx_inx
+	      shared_fail_frame = { 0, 0, (void *)rx_backtrack, 0 };
+	    answer = &shared_fail_frame;
+	  }
+	else
+	  {
+	    tc = rx_super_edge (rx, super, trcset, df);
+	    if (!tc)
+	      {
+		rx_unlock_superstate (rx, super);
+		return 0;
+	      }
+	    answer = ((tc->options->next_same_super_edge[0] != tc->options)
+		      ? &tc->rx_backtrack_frame
+		      : (df->effects
+			 ? &df->side_effects_frame
+			 : &df->future_frame));
+	  }
+	install_partial_transition (super, answer,
+				    trcset[offset], offset * 32);
+	rx_unlock_superstate (rx, super);
+	return answer;
+      }
+    }
+  else if (df->future) /* A cache miss on an edge with a future? Must be
+			* a semi-free destination. */
+    {				
+      if (df->future->is_semifree)
+	refresh_semifree_superstate (rx->cache, df->future);
+      return &df->future_frame;
+    }
+  else
+    /* no future superstate on an existing edge */
+    {
+      rx_lock_superstate (rx, super);
+      if (!solve_destination (rx, df))
+	{
+	  rx_unlock_superstate (rx, super);
+	  return 0;
+	}
+      if (!df->effects
+	  && (df->edge->options->next_same_super_edge[0] == df->edge->options))
+	install_partial_transition (super, &df->future_frame,
+				    df->edge->cset[offset], offset * 32);
+      rx_unlock_superstate (rx, super);
+      return &df->future_frame;
+    }
+}
+
+
+
+
+
+/* The rest of the code provides a regex.c compatable interface. */
+
+
+__const__ char *re_error_msg[] =
+{
+  0,						/* REG_NOUT */
+  "No match",					/* REG_NOMATCH */
+  "Invalid regular expression",			/* REG_BADPAT */
+  "Invalid collation character",		/* REG_ECOLLATE */
+  "Invalid character class name",		/* REG_ECTYPE */
+  "Trailing backslash",				/* REG_EESCAPE */
+  "Invalid back reference",			/* REG_ESUBREG */
+  "Unmatched [ or [^",				/* REG_EBRACK */
+  "Unmatched ( or \\(",				/* REG_EPAREN */
+  "Unmatched \\{",				/* REG_EBRACE */
+  "Invalid content of \\{\\}",			/* REG_BADBR */
+  "Invalid range end",				/* REG_ERANGE */
+  "Memory exhausted",				/* REG_ESPACE */
+  "Invalid preceding regular expression",	/* REG_BADRPT */
+  "Premature end of regular expression",	/* REG_EEND */
+  "Regular expression too big",			/* REG_ESIZE */
+  "Unmatched ) or \\)",				/* REG_ERPAREN */
+};
+
+
+
+
+/* 
+ * Macros used while compiling patterns.
+ *
+ * By convention, PEND points just past the end of the uncompiled pattern,
+ * P points to the read position in the pattern.  `translate' is the name
+ * of the translation table (`TRANSLATE' is the name of a macro that looks
+ * things up in `translate').
+ */
+
+
+/*
+ * Fetch the next character in the uncompiled pattern---translating it 
+ * if necessary. *Also cast from a signed character in the constant
+ * string passed to us by the user to an unsigned char that we can use
+ * as an array index (in, e.g., `translate').
+ */
+#define PATFETCH(c)							\
+ do {if (p == pend) return REG_EEND;					\
+    c = (unsigned char) *p++;						\
+    c = translate[c];		 					\
+ } while (0)
+
+/* 
+ * Fetch the next character in the uncompiled pattern, with no
+ * translation.
+ */
+#define PATFETCH_RAW(c)							\
+  do {if (p == pend) return REG_EEND;					\
+    c = (unsigned char) *p++; 						\
+  } while (0)
+
+/* Go backwards one character in the pattern.  */
+#define PATUNFETCH p--
+
+
+#define TRANSLATE(d) translate[(unsigned char) (d)]
+
+typedef unsigned regnum_t;
+
+/* Since offsets can go either forwards or backwards, this type needs to
+ * be able to hold values from -(MAX_BUF_SIZE - 1) to MAX_BUF_SIZE - 1.
+ */
+typedef int pattern_offset_t;
+
+typedef struct
+{
+  struct rexp_node ** top_expression; /* was begalt */
+  struct rexp_node ** last_expression; /* was laststart */
+  pattern_offset_t inner_group_offset;
+  regnum_t regnum;
+} compile_stack_elt_t;
+
+typedef struct
+{
+  compile_stack_elt_t *stack;
+  unsigned size;
+  unsigned avail;			/* Offset of next open position.  */
+} compile_stack_type;
+
+
+#define INIT_COMPILE_STACK_SIZE 32
+
+#define COMPILE_STACK_EMPTY  (compile_stack.avail == 0)
+#define COMPILE_STACK_FULL  (compile_stack.avail == compile_stack.size)
+
+/* The next available element.  */
+#define COMPILE_STACK_TOP (compile_stack.stack[compile_stack.avail])
+
+
+/* Set the bit for character C in a list.  */
+#define SET_LIST_BIT(c)                               \
+  (b[((unsigned char) (c)) / CHARBITS]               \
+   |= 1 << (((unsigned char) c) % CHARBITS))
+
+/* Get the next unsigned number in the uncompiled pattern.  */
+#define GET_UNSIGNED_NUMBER(num) 					\
+  { if (p != pend)							\
+     {									\
+       PATFETCH (c); 							\
+       while (isdigit (c)) 						\
+         { 								\
+           if (num < 0)							\
+              num = 0;							\
+           num = num * 10 + c - '0'; 					\
+           if (p == pend) 						\
+              break; 							\
+           PATFETCH (c);						\
+         } 								\
+       } 								\
+    }		
+
+#define CHAR_CLASS_MAX_LENGTH  6 /* Namely, `xdigit'.  */
+
+#define IS_CHAR_CLASS(string)						\
+   (!strcmp (string, "alpha") || !strcmp (string, "upper")		\
+    || !strcmp (string, "lower") || !strcmp (string, "digit")		\
+    || !strcmp (string, "alnum") || !strcmp (string, "xdigit")		\
+    || !strcmp (string, "space") || !strcmp (string, "print")		\
+    || !strcmp (string, "punct") || !strcmp (string, "graph")		\
+    || !strcmp (string, "cntrl") || !strcmp (string, "blank"))
+
+
+
+/* These predicates are used in regex_compile. */
+
+/* P points to just after a ^ in PATTERN.  Return true if that ^ comes
+ * after an alternative or a begin-subexpression.  We assume there is at
+ * least one character before the ^.  
+ */
+
+#ifdef __STDC__
+static boolean
+at_begline_loc_p (__const__ char *pattern, __const__ char * p, reg_syntax_t syntax)
+#else
+static boolean
+at_begline_loc_p (pattern, p, syntax)
+     __const__ char *pattern;
+     __const__ char * p;
+     reg_syntax_t syntax;
+#endif
+{
+  __const__ char *prev = p - 2;
+  boolean prev_prev_backslash = ((prev > pattern) && (prev[-1] == '\\'));
+  
+    return
+      
+      (/* After a subexpression?  */
+       ((*prev == '(') && ((syntax & RE_NO_BK_PARENS) || prev_prev_backslash))
+       ||
+       /* After an alternative?  */
+       ((*prev == '|') && ((syntax & RE_NO_BK_VBAR) || prev_prev_backslash))
+       );
+}
+
+/* The dual of at_begline_loc_p.  This one is for $.  We assume there is
+ * at least one character after the $, i.e., `P < PEND'.
+ */
+
+#ifdef __STDC__
+static boolean
+at_endline_loc_p (__const__ char *p, __const__ char *pend, int syntax)
+#else
+static boolean
+at_endline_loc_p (p, pend, syntax)
+     __const__ char *p;
+     __const__ char *pend;
+     int syntax;
+#endif
+{
+  __const__ char *next = p;
+  boolean next_backslash = (*next == '\\');
+  __const__ char *next_next = (p + 1 < pend) ? (p + 1) : 0;
+  
+  return
+    (
+     /* Before a subexpression?  */
+     ((syntax & RE_NO_BK_PARENS)
+      ? (*next == ')')
+      : (next_backslash && next_next && (*next_next == ')')))
+    ||
+     /* Before an alternative?  */
+     ((syntax & RE_NO_BK_VBAR)
+      ? (*next == '|')
+      : (next_backslash && next_next && (*next_next == '|')))
+     );
+}
+
+
+
+unsigned char rx_id_translation[256] =
+{
+  0,  1,  2,  3,  4,  5,  6,  7,  8,  9,
+ 10, 11, 12, 13, 14, 15, 16, 17, 18, 19,
+ 20, 21, 22, 23, 24, 25, 26, 27, 28, 29,
+ 30, 31, 32, 33, 34, 35, 36, 37, 38, 39,
+ 40, 41, 42, 43, 44, 45, 46, 47, 48, 49,
+ 50, 51, 52, 53, 54, 55, 56, 57, 58, 59,
+ 60, 61, 62, 63, 64, 65, 66, 67, 68, 69,
+ 70, 71, 72, 73, 74, 75, 76, 77, 78, 79,
+ 80, 81, 82, 83, 84, 85, 86, 87, 88, 89,
+ 90, 91, 92, 93, 94, 95, 96, 97, 98, 99,
+
+ 100, 101, 102, 103, 104, 105, 106, 107, 108, 109,
+ 110, 111, 112, 113, 114, 115, 116, 117, 118, 119,
+ 120, 121, 122, 123, 124, 125, 126, 127, 128, 129,
+ 130, 131, 132, 133, 134, 135, 136, 137, 138, 139,
+ 140, 141, 142, 143, 144, 145, 146, 147, 148, 149,
+ 150, 151, 152, 153, 154, 155, 156, 157, 158, 159,
+ 160, 161, 162, 163, 164, 165, 166, 167, 168, 169,
+ 170, 171, 172, 173, 174, 175, 176, 177, 178, 179,
+ 180, 181, 182, 183, 184, 185, 186, 187, 188, 189,
+ 190, 191, 192, 193, 194, 195, 196, 197, 198, 199,
+
+ 200, 201, 202, 203, 204, 205, 206, 207, 208, 209,
+ 210, 211, 212, 213, 214, 215, 216, 217, 218, 219,
+ 220, 221, 222, 223, 224, 225, 226, 227, 228, 229,
+ 230, 231, 232, 233, 234, 235, 236, 237, 238, 239,
+ 240, 241, 242, 243, 244, 245, 246, 247, 248, 249,
+ 250, 251, 252, 253, 254, 255
+};
+
+/* The compiler keeps an inverted translation table.
+ * This looks up/inititalize elements.
+ * VALID is an array of booleans that validate CACHE.
+ */
+
+#ifdef __STDC__
+static rx_Bitset
+inverse_translation (struct re_pattern_buffer * rxb,
+		     char * valid, rx_Bitset cache,
+		     unsigned char * translate, int c)
+#else
+static rx_Bitset
+inverse_translation (rxb, valid, cache, translate, c)
+     struct re_pattern_buffer * rxb;
+     char * valid;
+     rx_Bitset cache;
+     unsigned char * translate;
+     int c;
+#endif
+{
+  rx_Bitset cs
+    = cache + c * rx_bitset_numb_subsets (rxb->rx.local_cset_size); 
+
+  if (!valid[c])
+    {
+      int x;
+      int c_tr = TRANSLATE(c);
+      rx_bitset_null (rxb->rx.local_cset_size, cs);
+      for (x = 0; x < 256; ++x)	/* &&&& 13.37 */
+	if (TRANSLATE(x) == c_tr)
+	  RX_bitset_enjoin (cs, x);
+      valid[c] = 1;
+    }
+  return cs;
+}
+
+
+
+
+
+/* More subroutine declarations and macros for regex_compile.  */
+
+/* Returns true if REGNUM is in one of COMPILE_STACK's elements and 
+   false if it's not.  */
+
+#ifdef __STDC__
+static boolean
+group_in_compile_stack (compile_stack_type compile_stack, regnum_t regnum)
+#else
+static boolean
+group_in_compile_stack (compile_stack, regnum)
+    compile_stack_type compile_stack;
+    regnum_t regnum;
+#endif
+{
+  int this_element;
+
+  for (this_element = compile_stack.avail - 1;  
+       this_element >= 0; 
+       this_element--)
+    if (compile_stack.stack[this_element].regnum == regnum)
+      return true;
+
+  return false;
+}
+
+
+/*
+ * Read the ending character of a range (in a bracket expression) from the
+ * uncompiled pattern *P_PTR (which ends at PEND).  We assume the
+ * starting character is in `P[-2]'.  (`P[-1]' is the character `-'.)
+ * Then we set the translation of all bits between the starting and
+ * ending characters (inclusive) in the compiled pattern B.
+ * 
+ * Return an error code.
+ * 
+ * We use these short variable names so we can use the same macros as
+ * `regex_compile' itself.  
+ */
+
+#ifdef __STDC__
+static reg_errcode_t
+compile_range (struct re_pattern_buffer * rxb, rx_Bitset cs,
+	       __const__ char ** p_ptr, __const__ char * pend,
+	       unsigned char * translate, reg_syntax_t syntax,
+	       rx_Bitset inv_tr,  char * valid_inv_tr)
+#else
+static reg_errcode_t
+compile_range (rxb, cs, p_ptr, pend, translate, syntax, inv_tr, valid_inv_tr)
+     struct re_pattern_buffer * rxb;
+     rx_Bitset cs;
+     __const__ char ** p_ptr;
+     __const__ char * pend;
+     unsigned char * translate;
+     reg_syntax_t syntax;
+     rx_Bitset inv_tr;
+     char * valid_inv_tr;
+#endif
+{
+  unsigned this_char;
+
+  __const__ char *p = *p_ptr;
+
+  unsigned char range_end;
+  unsigned char range_start = TRANSLATE(p[-2]);
+
+  if (p == pend)
+    return REG_ERANGE;
+
+  PATFETCH (range_end);
+
+  (*p_ptr)++;
+
+  if (range_start > range_end)
+    return syntax & RE_NO_EMPTY_RANGES ? REG_ERANGE : REG_NOERROR;
+
+  for (this_char = range_start; this_char <= range_end; this_char++)
+    {
+      rx_Bitset it =
+	inverse_translation (rxb, valid_inv_tr, inv_tr, translate, this_char);
+      rx_bitset_union (rxb->rx.local_cset_size, cs, it);
+    }
+  
+  return REG_NOERROR;
+}
+
+
+
+/* This searches a regexp for backreference side effects.
+ * It fills in the array OUT with 1 at the index of every register pair
+ * referenced by a backreference.
+ *
+ * This is used to help optimize patterns for searching.  The information is
+ * useful because, if the caller doesn't want register values, backreferenced
+ * registers are the only registers for which we need rx_backtrack.
+ */
+
+#ifdef __STDC__
+static void
+find_backrefs (char * out, struct rexp_node * rexp,
+	       struct re_se_params * params)
+#else
+static void
+find_backrefs (out, rexp, params)
+     char * out;
+     struct rexp_node * rexp;
+     struct re_se_params * params;
+#endif
+{
+  if (rexp)
+    switch (rexp->type)
+      {
+      case r_cset:
+      case r_data:
+	return;
+      case r_alternate:
+      case r_concat:
+      case r_opt:
+      case r_star:
+      case r_2phase_star:
+	find_backrefs (out, rexp->params.pair.left, params);
+	find_backrefs (out, rexp->params.pair.right, params);
+	return;
+      case r_side_effect:
+	if (   ((long)rexp->params.side_effect >= 0)
+	    && (params [(long)rexp->params.side_effect].se == re_se_backref))
+	  out[ params [(long)rexp->params.side_effect].op1] = 1;
+	return;
+      }
+}
+
+
+
+
+/* Returns 0 unless the pattern can match the empty string. */
+
+#ifdef __STDC__
+static int
+compute_fastset (struct re_pattern_buffer * rxb, struct rexp_node * rexp)
+#else
+static int
+compute_fastset (rxb, rexp)
+     struct re_pattern_buffer * rxb;
+     struct rexp_node * rexp;
+#endif
+{
+  if (!rexp)
+    return 1;
+  switch (rexp->type)
+    {
+    case r_data:
+      return 1;
+    case r_cset:
+      {
+	rx_bitset_union (rxb->rx.local_cset_size,
+			 rxb->fastset, rexp->params.cset);
+      }
+      return 0;
+    case r_concat:
+      return (compute_fastset (rxb, rexp->params.pair.left)
+	      && compute_fastset (rxb, rexp->params.pair.right));
+    case r_2phase_star:
+      compute_fastset (rxb, rexp->params.pair.left);
+      /* compute_fastset (rxb, rexp->params.pair.right);  nope... */
+      return 1;
+    case r_alternate:
+      return !!(compute_fastset (rxb, rexp->params.pair.left)
+		+ compute_fastset (rxb, rexp->params.pair.right));
+    case r_opt:
+    case r_star:
+      compute_fastset (rxb, rexp->params.pair.left);
+      return 1;
+    case r_side_effect:
+      return 1;
+    }
+
+  /* this should never happen */
+  return 0;
+}
+
+
+
+/* returns
+ *  1 -- yes, definately anchored by the given side effect.
+ *  2 -- maybe anchored, maybe the empty string.
+ *  0 -- definately not anchored
+ *  There is simply no other possibility.
+ */
+
+#ifdef __STDC__
+static int
+is_anchored (struct rexp_node * rexp, rx_side_effect se)
+#else
+static int
+is_anchored (rexp, se)
+     struct rexp_node * rexp;
+     rx_side_effect se;
+#endif
+{
+  if (!rexp)
+    return 2;
+  switch (rexp->type)
+    {
+    case r_cset:
+    case r_data:
+      return 0;
+    case r_concat:
+    case r_2phase_star:
+      {
+	int l = is_anchored (rexp->params.pair.left, se);
+	return (l == 2 ? is_anchored (rexp->params.pair.right, se) : l);
+      }
+    case r_alternate:
+      {
+	int l = is_anchored (rexp->params.pair.left, se);
+	int r = l ? is_anchored (rexp->params.pair.right, se) : 0;
+
+	if (l == r)
+	  return l;
+	else if ((l == 0) || (r == 0))
+	  return 0;
+	else
+	  return 2;
+      }
+    case r_opt:
+    case r_star:
+      return is_anchored (rexp->params.pair.left, se) ? 2 : 0;
+      
+    case r_side_effect:
+      return ((rexp->params.side_effect == se)
+	      ? 1 : 2);
+    }
+
+  /* this should never happen */
+  return 0;
+}
+
+
+
+/* This removes register assignments that aren't required by backreferencing.
+ * This can speed up explore_future, especially if it eliminates
+ * non-determinism in the superstate NFA.
+ * 
+ * NEEDED is an array of characters, presumably filled in by FIND_BACKREFS.
+ * The non-zero elements of the array indicate which register assignments
+ * can NOT be removed from the expression.
+ */
+
+#ifdef __STDC__
+static struct rexp_node *
+remove_unecessary_side_effects (struct rx * rx, char * needed,
+				struct rexp_node * rexp,
+				struct re_se_params * params)
+#else
+static struct rexp_node *
+remove_unecessary_side_effects (rx, needed, rexp, params)
+     struct rx * rx;
+     char * needed;
+     struct rexp_node * rexp;
+     struct re_se_params * params;
+#endif
+{
+  struct rexp_node * l;
+  struct rexp_node * r;
+  if (!rexp)
+    return 0;
+  else
+    switch (rexp->type)
+      {
+      case r_cset:
+      case r_data:
+	return rexp;
+      case r_alternate:
+      case r_concat:
+      case r_2phase_star:
+	l = remove_unecessary_side_effects (rx, needed,
+					    rexp->params.pair.left, params);
+	r = remove_unecessary_side_effects (rx, needed,
+					    rexp->params.pair.right, params);
+	if ((l && r) || (rexp->type != r_concat))
+	  {
+	    rexp->params.pair.left = l;
+	    rexp->params.pair.right = r;
+	    return rexp;
+	  }
+	else
+	  {
+	    rexp->params.pair.left = rexp->params.pair.right = 0;
+	    rx_free_rexp (rx, rexp);
+	    return l ? l : r;
+	  }
+      case r_opt:
+      case r_star:
+	l = remove_unecessary_side_effects (rx, needed,
+					    rexp->params.pair.left, params);
+	if (l)
+	  {
+	    rexp->params.pair.left = l;
+	    return rexp;
+	  }
+	else
+	  {
+	    rexp->params.pair.left = 0;
+	    rx_free_rexp (rx, rexp);
+	    return 0;
+	  }
+      case r_side_effect:
+	{
+	  int se = (long)rexp->params.side_effect;
+	  if (   (se >= 0)
+	      && (   ((enum re_side_effects)params[se].se == re_se_lparen)
+		  || ((enum re_side_effects)params[se].se == re_se_rparen))
+	      && (params [se].op1 > 0)
+	      && (!needed [params [se].op1]))
+	    {
+	      rx_free_rexp (rx, rexp);
+	      return 0;
+	    }
+	  else
+	    return rexp;
+	}
+      }
+
+  /* this should never happen */
+  return 0;
+}
+
+
+
+
+#ifdef __STDC__
+static int
+pointless_if_repeated (struct rexp_node * node, struct re_se_params * params)
+#else
+static int
+pointless_if_repeated (node, params)
+     struct rexp_node * node;
+     struct re_se_params * params;
+#endif
+{
+  if (!node)
+    return 1;
+  switch (node->type)
+    {
+    case r_cset:
+      return 0;
+    case r_alternate:
+    case r_concat:
+    case r_2phase_star:
+      return (pointless_if_repeated (node->params.pair.left, params)
+	      && pointless_if_repeated (node->params.pair.right, params));
+    case r_opt:
+    case r_star:
+      return pointless_if_repeated (node->params.pair.left, params);
+    case r_side_effect:
+      switch ((enum re_side_effects) (((long)node->params.side_effect < 0)
+	      ? (enum re_side_effects) (long) node->params.side_effect
+	      : (enum re_side_effects)params[(long)node->params.side_effect].se))
+	{
+	case re_se_try:
+	case re_se_at_dot:
+	case re_se_begbuf:
+	case re_se_hat:
+	case re_se_wordbeg:
+	case re_se_wordbound:
+	case re_se_notwordbound:
+	case re_se_wordend:
+	case re_se_endbuf:
+	case re_se_dollar:
+	case re_se_fail:
+	case re_se_win:
+	  return 1;
+	case re_se_lparen:
+	case re_se_rparen:
+	case re_se_iter:
+	case re_se_end_iter:
+	case re_se_syntax:
+	case re_se_not_syntax:
+	case re_se_backref:
+	  return 0;
+	}
+    case r_data:
+    default:
+      return 0;
+    }
+}
+
+
+
+
+#ifdef __STDC__
+static int
+registers_on_stack (struct re_pattern_buffer * rxb,
+		    struct rexp_node * rexp, int in_danger,
+		    struct re_se_params * params)
+#else
+static int
+registers_on_stack (rxb, rexp, in_danger, params)
+     struct re_pattern_buffer * rxb;
+     struct rexp_node * rexp;
+     int in_danger;
+     struct re_se_params * params;
+#endif
+{
+  if (!rexp)
+    return 0;
+  else
+    switch (rexp->type)
+      {
+      case r_cset:
+      case r_data:
+	return 0;
+      case r_alternate:
+      case r_concat:
+	return (   registers_on_stack (rxb, rexp->params.pair.left,
+				       in_danger, params)
+		|| (registers_on_stack
+		    (rxb, rexp->params.pair.right,
+		     in_danger, params)));
+      case r_opt:
+	return registers_on_stack (rxb, rexp->params.pair.left, 0, params);
+      case r_star:
+	return registers_on_stack (rxb, rexp->params.pair.left, 1, params);
+      case r_2phase_star:
+	return
+	  (   registers_on_stack (rxb, rexp->params.pair.left, 1, params)
+	   || registers_on_stack (rxb, rexp->params.pair.right, 1, params));
+      case r_side_effect:
+	{
+	  int se = (long)rexp->params.side_effect;
+	  if (   in_danger
+	      && (se >= 0)
+	      && (params [se].op1 > 0)
+	      && (   ((enum re_side_effects)params[se].se == re_se_lparen)
+		  || ((enum re_side_effects)params[se].se == re_se_rparen)))
+	    return 1;
+	  else
+	    return 0;
+	}
+      }
+
+  /* this should never happen */
+  return 0;
+}
+
+
+
+
+static char idempotent_complex_se[] =
+{
+#define RX_WANT_SE_DEFS 1
+#undef RX_DEF_SE
+#undef RX_DEF_CPLX_SE
+#define RX_DEF_SE(IDEM, NAME, VALUE)	      
+#define RX_DEF_CPLX_SE(IDEM, NAME, VALUE)     IDEM,
+#include "rx.h"
+#undef RX_DEF_SE
+#undef RX_DEF_CPLX_SE
+#undef RX_WANT_SE_DEFS
+  23
+};
+
+static char idempotent_se[] =
+{
+  13,
+#define RX_WANT_SE_DEFS 1
+#undef RX_DEF_SE
+#undef RX_DEF_CPLX_SE
+#define RX_DEF_SE(IDEM, NAME, VALUE)	      IDEM,
+#define RX_DEF_CPLX_SE(IDEM, NAME, VALUE)     
+#include "rx.h"
+#undef RX_DEF_SE
+#undef RX_DEF_CPLX_SE
+#undef RX_WANT_SE_DEFS
+  42
+};
+
+
+
+
+
+#ifdef __STDC__
+static int
+has_any_se (struct rx * rx,
+	    struct rexp_node * rexp)
+#else
+static int
+has_any_se (rx, rexp)
+     struct rx * rx;
+     struct rexp_node * rexp;
+#endif
+{
+  if (!rexp)
+    return 0;
+
+  switch (rexp->type)
+    {
+    case r_cset:
+    case r_data:
+      return 0;
+
+    case r_side_effect:
+      return 1;
+      
+    case r_2phase_star:
+    case r_concat:
+    case r_alternate:
+      return
+	(   has_any_se (rx, rexp->params.pair.left)
+	 || has_any_se (rx, rexp->params.pair.right));
+
+    case r_opt:
+    case r_star:
+      return has_any_se (rx, rexp->params.pair.left);
+    }
+
+  /* this should never happen */
+  return 0;
+}
+
+
+
+
+/* This must be called AFTER `convert_hard_loops' for a given REXP. */
+#ifdef __STDC__
+static int
+has_non_idempotent_epsilon_path (struct rx * rx,
+				 struct rexp_node * rexp,
+				 struct re_se_params * params)
+#else
+static int
+has_non_idempotent_epsilon_path (rx, rexp, params)
+     struct rx * rx;
+     struct rexp_node * rexp;
+     struct re_se_params * params;
+#endif
+{
+  if (!rexp)
+    return 0;
+
+  switch (rexp->type)
+    {
+    case r_cset:
+    case r_data:
+    case r_star:
+      return 0;
+
+    case r_side_effect:
+      return
+	!((long)rexp->params.side_effect > 0
+	  ? idempotent_complex_se [ params [(long)rexp->params.side_effect].se ]
+	  : idempotent_se [-(long)rexp->params.side_effect]);
+      
+    case r_alternate:
+      return
+	(   has_non_idempotent_epsilon_path (rx,
+					     rexp->params.pair.left, params)
+	 || has_non_idempotent_epsilon_path (rx,
+					     rexp->params.pair.right, params));
+
+    case r_2phase_star:
+    case r_concat:
+      return
+	(   has_non_idempotent_epsilon_path (rx,
+					     rexp->params.pair.left, params)
+	 && has_non_idempotent_epsilon_path (rx,
+					     rexp->params.pair.right, params));
+
+    case r_opt:
+      return has_non_idempotent_epsilon_path (rx,
+					      rexp->params.pair.left, params);
+    }
+
+  /* this should never happen */
+  return 0;
+}
+
+
+
+
+/* This computes rougly what it's name suggests.   It can (and does) go wrong 
+ * in the direction of returning spurious 0 without causing disasters.
+ */
+#ifdef __STDC__
+static int
+begins_with_complex_se (struct rx * rx, struct rexp_node * rexp)
+#else
+static int
+begins_with_complex_se (rx, rexp)
+     struct rx * rx;
+     struct rexp_node * rexp;
+#endif
+{
+  if (!rexp)
+    return 0;
+
+  switch (rexp->type)
+    {
+    case r_cset:
+    case r_data:
+      return 0;
+
+    case r_side_effect:
+      return ((long)rexp->params.side_effect >= 0);
+      
+    case r_alternate:
+      return
+	(   begins_with_complex_se (rx, rexp->params.pair.left)
+	 && begins_with_complex_se (rx, rexp->params.pair.right));
+
+
+    case r_concat:
+      return has_any_se (rx, rexp->params.pair.left);
+    case r_opt:
+    case r_star:
+    case r_2phase_star:
+      return 0;
+    }
+
+  /* this should never happen */
+  return 0;
+}
+
+
+
+/* This destructively removes some of the re_se_tv side effects from 
+ * a rexp tree.  In particular, during parsing re_se_tv was inserted on the
+ * right half of every | to guarantee that posix path preference could be 
+ * honored.  This function removes some which it can be determined aren't 
+ * needed.  
+ */
+
+#ifdef __STDC__
+static void
+speed_up_alt (struct rx * rx,
+	      struct rexp_node * rexp,
+	      int unposix)
+#else
+static void
+speed_up_alt (rx, rexp, unposix)
+     struct rx * rx;
+     struct rexp_node * rexp;
+     int unposix;
+#endif
+{
+  if (!rexp)
+    return;
+
+  switch (rexp->type)
+    {
+    case r_cset:
+    case r_data:
+    case r_side_effect:
+      return;
+
+    case r_opt:
+    case r_star:
+      speed_up_alt (rx, rexp->params.pair.left, unposix);
+      return;
+
+    case r_2phase_star:
+    case r_concat:
+      speed_up_alt (rx, rexp->params.pair.left, unposix);
+      speed_up_alt (rx, rexp->params.pair.right, unposix);
+      return;
+
+    case r_alternate:
+      /* the right child is guaranteed to be (concat re_se_tv <subexp>) */
+
+      speed_up_alt (rx, rexp->params.pair.left, unposix);
+      speed_up_alt (rx, rexp->params.pair.right->params.pair.right, unposix);
+      
+      if (   unposix
+	  || (begins_with_complex_se
+	      (rx, rexp->params.pair.right->params.pair.right))
+	  || !(   has_any_se (rx, rexp->params.pair.right->params.pair.right)
+	       || has_any_se (rx, rexp->params.pair.left)))
+	{
+	  struct rexp_node * conc = rexp->params.pair.right;
+	  rexp->params.pair.right = conc->params.pair.right;
+	  conc->params.pair.right = 0;
+	  rx_free_rexp (rx, conc);
+	}
+    }
+}
+
+
+
+
+
+
+/* `regex_compile' compiles PATTERN (of length SIZE) according to SYNTAX.
+   Returns one of error codes defined in `regex.h', or zero for success.
+
+   Assumes the `allocated' (and perhaps `buffer') and `translate'
+   fields are set in BUFP on entry.
+
+   If it succeeds, results are put in BUFP (if it returns an error, the
+   contents of BUFP are undefined):
+     `buffer' is the compiled pattern;
+     `syntax' is set to SYNTAX;
+     `used' is set to the length of the compiled pattern;
+     `fastmap_accurate' is set to zero;
+     `re_nsub' is set to the number of groups in PATTERN;
+     `not_bol' and `not_eol' are set to zero.
+   
+   The `fastmap' and `newline_anchor' fields are neither
+   examined nor set.  */
+
+
+
+#ifdef __STDC__
+RX_DECL reg_errcode_t
+rx_compile (__const__ char *pattern, int size,
+	    reg_syntax_t syntax,
+	    struct re_pattern_buffer * rxb) 
+#else
+RX_DECL reg_errcode_t
+rx_compile (pattern, size, syntax, rxb)
+     __const__ char *pattern;
+     int size;
+     reg_syntax_t syntax;
+     struct re_pattern_buffer * rxb;
+#endif
+{
+  RX_subset
+    inverse_translate [CHAR_SET_SIZE * rx_bitset_numb_subsets(CHAR_SET_SIZE)];
+  char
+    validate_inv_tr [CHAR_SET_SIZE * rx_bitset_numb_subsets(CHAR_SET_SIZE)];
+
+  /* We fetch characters from PATTERN here.  Even though PATTERN is
+     `char *' (i.e., signed), we declare these variables as unsigned, so
+     they can be reliably used as array indices.  */
+  register unsigned char c, c1;
+  
+  /* A random tempory spot in PATTERN.  */
+  __const__ char *p1;
+  
+  /* Keeps track of unclosed groups.  */
+  compile_stack_type compile_stack;
+
+  /* Points to the current (ending) position in the pattern.  */
+  __const__ char *p = pattern;
+  __const__ char *pend = pattern + size;
+  
+  /* How to translate the characters in the pattern.  */
+  unsigned char *translate = (rxb->translate
+			      ? rxb->translate
+			      : rx_id_translation);
+
+  /* When parsing is done, this will hold the expression tree. */
+  struct rexp_node * rexp = 0;
+
+  /* In the midst of compilation, this holds onto the regexp 
+   * first parst while rexp goes on to aquire additional constructs.
+   */
+  struct rexp_node * orig_rexp = 0;
+  struct rexp_node * fewer_side_effects = 0;
+
+  /* This and top_expression are saved on the compile stack. */
+  struct rexp_node ** top_expression = &rexp;
+  struct rexp_node ** last_expression = top_expression;
+  
+  /* Parameter to `goto append_node' */
+  struct rexp_node * append;
+
+  /* Counts open-groups as they are encountered.  This is the index of the
+   * innermost group being compiled.
+   */
+  regnum_t regnum = 0;
+
+  /* Place in the uncompiled pattern (i.e., the {) to
+   * which to go back if the interval is invalid.  
+   */
+  __const__ char *beg_interval;
+
+  struct re_se_params * params = 0;
+  int paramc = 0;		/* How many complex side effects so far? */
+
+  rx_side_effect side;		/* param to `goto add_side_effect' */
+
+  bzero (validate_inv_tr, sizeof (validate_inv_tr));
+
+  rxb->rx.instruction_table = rx_id_instruction_table;
+
+
+  /* Initialize the compile stack.  */
+  compile_stack.stack =  (( compile_stack_elt_t *) malloc ((INIT_COMPILE_STACK_SIZE) * sizeof ( compile_stack_elt_t)));
+  if (compile_stack.stack == 0)
+    return REG_ESPACE;
+
+  compile_stack.size = INIT_COMPILE_STACK_SIZE;
+  compile_stack.avail = 0;
+
+  /* Initialize the pattern buffer.  */
+  rxb->rx.cache = &default_cache;
+  rxb->syntax = syntax;
+  rxb->fastmap_accurate = 0;
+  rxb->not_bol = rxb->not_eol = 0;
+  rxb->least_subs = 0;
+  
+  /* Always count groups, whether or not rxb->no_sub is set.  
+   * The whole pattern is implicitly group 0, so counting begins
+   * with 1.
+   */
+  rxb->re_nsub = 0;
+
+#if !defined (emacs) && !defined (SYNTAX_TABLE)
+  /* Initialize the syntax table.  */
+   init_syntax_once ();
+#endif
+
+  /* Loop through the uncompiled pattern until we're at the end.  */
+  while (p != pend)
+    {
+      PATFETCH (c);
+
+      switch (c)
+        {
+        case '^':
+          {
+            if (   /* If at start of pattern, it's an operator.  */
+                   p == pattern + 1
+                   /* If context independent, it's an operator.  */
+                || syntax & RE_CONTEXT_INDEP_ANCHORS
+                   /* Otherwise, depends on what's come before.  */
+                || at_begline_loc_p (pattern, p, syntax))
+	      {
+		struct rexp_node * n
+		  = rx_mk_r_side_effect (&rxb->rx, (rx_side_effect)re_se_hat);
+		if (!n)
+		  return REG_ESPACE;
+		append = n;
+		goto append_node;
+	      }
+            else
+              goto normal_char;
+          }
+          break;
+
+
+        case '$':
+          {
+            if (   /* If at end of pattern, it's an operator.  */
+                   p == pend 
+                   /* If context independent, it's an operator.  */
+                || syntax & RE_CONTEXT_INDEP_ANCHORS
+                   /* Otherwise, depends on what's next.  */
+                || at_endline_loc_p (p, pend, syntax))
+	      {
+		struct rexp_node * n
+		  = rx_mk_r_side_effect (&rxb->rx, (rx_side_effect)re_se_dollar);
+		if (!n)
+		  return REG_ESPACE;
+		append = n;
+		goto append_node;
+	      }
+             else
+               goto normal_char;
+           }
+           break;
+
+
+	case '+':
+        case '?':
+          if ((syntax & RE_BK_PLUS_QM)
+              || (syntax & RE_LIMITED_OPS))
+            goto normal_char;
+
+        handle_plus:
+        case '*':
+          /* If there is no previous pattern... */
+          if (pointless_if_repeated (*last_expression, params))
+            {
+              if (syntax & RE_CONTEXT_INVALID_OPS)
+                return REG_BADRPT;
+              else if (!(syntax & RE_CONTEXT_INDEP_OPS))
+                goto normal_char;
+            }
+
+          {
+            /* 1 means zero (many) matches is allowed.  */
+            char zero_times_ok = 0, many_times_ok = 0;
+
+            /* If there is a sequence of repetition chars, collapse it
+               down to just one (the right one).  We can't combine
+               interval operators with these because of, e.g., `a{2}*',
+               which should only match an even number of `a's.  */
+
+            for (;;)
+              {
+                zero_times_ok |= c != '+';
+                many_times_ok |= c != '?';
+
+                if (p == pend)
+                  break;
+
+                PATFETCH (c);
+
+                if (c == '*'
+                    || (!(syntax & RE_BK_PLUS_QM) && (c == '+' || c == '?')))
+                  ;
+
+                else if (syntax & RE_BK_PLUS_QM  &&  c == '\\')
+                  {
+                    if (p == pend) return REG_EESCAPE;
+
+                    PATFETCH (c1);
+                    if (!(c1 == '+' || c1 == '?'))
+                      {
+                        PATUNFETCH;
+                        PATUNFETCH;
+                        break;
+                      }
+
+                    c = c1;
+                  }
+                else
+                  {
+                    PATUNFETCH;
+                    break;
+                  }
+
+                /* If we get here, we found another repeat character.  */
+               }
+
+            /* Star, etc. applied to an empty pattern is equivalent
+               to an empty pattern.  */
+            if (!last_expression)
+              break;
+
+	    /* Now we know whether or not zero matches is allowed
+	     * and also whether or not two or more matches is allowed.
+	     */
+
+	    {
+	      struct rexp_node * inner_exp = *last_expression;
+	      int need_sync = 0;
+
+	      if (many_times_ok
+		  && has_non_idempotent_epsilon_path (&rxb->rx,
+						      inner_exp, params))
+		{
+		  struct rexp_node * pusher
+		    = rx_mk_r_side_effect (&rxb->rx,
+					   (rx_side_effect)re_se_pushpos);
+		  struct rexp_node * checker
+		    = rx_mk_r_side_effect (&rxb->rx,
+					   (rx_side_effect)re_se_chkpos);
+		  struct rexp_node * pushback
+		    = rx_mk_r_side_effect (&rxb->rx,
+					   (rx_side_effect)re_se_pushback);
+		  rx_Bitset cs = rx_cset (&rxb->rx);
+		  struct rexp_node * lit_t = rx_mk_r_cset (&rxb->rx, cs);
+		  struct rexp_node * fake_state
+		    = rx_mk_r_concat (&rxb->rx, pushback, lit_t);
+		  struct rexp_node * phase2
+		    = rx_mk_r_concat (&rxb->rx, checker, fake_state);
+		  struct rexp_node * popper
+		    = rx_mk_r_side_effect (&rxb->rx,
+					   (rx_side_effect)re_se_poppos);
+		  struct rexp_node * star
+		    = rx_mk_r_2phase_star (&rxb->rx, inner_exp, phase2);
+		  struct rexp_node * a
+		    = rx_mk_r_concat (&rxb->rx, pusher, star);
+		  struct rexp_node * whole_thing
+		    = rx_mk_r_concat (&rxb->rx, a, popper);
+		  if (!(pusher && star && pushback && lit_t && fake_state
+			&& lit_t && phase2 && checker && popper
+			&& a && whole_thing))
+		    return REG_ESPACE;
+		  RX_bitset_enjoin (cs, 't');
+		  *last_expression = whole_thing;
+		}
+	      else
+		{
+		  struct rexp_node * star =
+		    (many_times_ok ? rx_mk_r_star : rx_mk_r_opt)
+		      (&rxb->rx, *last_expression);
+		  if (!star)
+		    return REG_ESPACE;
+		  *last_expression = star;
+		  need_sync = has_any_se (&rxb->rx, *last_expression);
+		}
+	      if (!zero_times_ok)
+		{
+		  struct rexp_node * concat
+		    = rx_mk_r_concat (&rxb->rx, inner_exp,
+				      rx_copy_rexp (&rxb->rx,
+						    *last_expression));
+		  if (!concat)
+		    return REG_ESPACE;
+		  *last_expression = concat;
+		}
+	      if (need_sync)
+		{
+		  int sync_se = paramc;
+		  params = (params
+			    ? ((struct re_se_params *)
+			       realloc (params,
+					sizeof (*params) * (1 + paramc)))
+			    : ((struct re_se_params *)
+			       malloc (sizeof (*params))));
+		  if (!params)
+		    return REG_ESPACE;
+		  ++paramc;
+		  params [sync_se].se = re_se_tv;
+		  side = (rx_side_effect)sync_se;
+		  goto add_side_effect;
+		}
+	    }
+	    /* The old regex.c used to optimize `.*\n'.  
+	     * Maybe rx should too?
+	     */
+	  }
+	  break;
+
+
+	case '.':
+	  {
+	    rx_Bitset cs = rx_cset (&rxb->rx);
+	    struct rexp_node * n = rx_mk_r_cset (&rxb->rx, cs);
+	    if (!(cs && n))
+	      return REG_ESPACE;
+
+	    rx_bitset_universe (rxb->rx.local_cset_size, cs);
+	    if (!(rxb->syntax & RE_DOT_NEWLINE))
+	      RX_bitset_remove (cs, '\n');
+	    if (!(rxb->syntax & RE_DOT_NOT_NULL))
+	      RX_bitset_remove (cs, 0);
+
+	    append = n;
+	    goto append_node;
+	    break;
+	  }
+
+
+        case '[':
+	  if (p == pend) return REG_EBRACK;
+          {
+            boolean had_char_class = false;
+	    rx_Bitset cs = rx_cset (&rxb->rx);
+	    struct rexp_node * node = rx_mk_r_cset (&rxb->rx, cs);
+	    int is_inverted = *p == '^';
+	    
+	    if (!(node && cs))
+	      return REG_ESPACE;
+	    
+	    /* This branch of the switch is normally exited with
+	     *`goto append_node'
+	     */
+	    append = node;
+	    
+            if (is_inverted)
+	      p++;
+	    
+            /* Remember the first position in the bracket expression.  */
+            p1 = p;
+	    
+            /* Read in characters and ranges, setting map bits.  */
+            for (;;)
+              {
+                if (p == pend) return REG_EBRACK;
+		
+                PATFETCH (c);
+		
+                /* \ might escape characters inside [...] and [^...].  */
+                if ((syntax & RE_BACKSLASH_ESCAPE_IN_LISTS) && c == '\\')
+                  {
+                    if (p == pend) return REG_EESCAPE;
+		    
+                    PATFETCH (c1);
+		    {
+		      rx_Bitset it = inverse_translation (rxb, 
+							  validate_inv_tr,
+							  inverse_translate,
+							  translate,
+							  c1);
+		      rx_bitset_union (rxb->rx.local_cset_size, cs, it);
+		    }
+                    continue;
+                  }
+		
+                /* Could be the end of the bracket expression.  If it's
+                   not (i.e., when the bracket expression is `[]' so
+                   far), the ']' character bit gets set way below.  */
+                if (c == ']' && p != p1 + 1)
+                  goto finalize_class_and_append;
+		
+                /* Look ahead to see if it's a range when the last thing
+                   was a character class.  */
+                if (had_char_class && c == '-' && *p != ']')
+                  return REG_ERANGE;
+		
+                /* Look ahead to see if it's a range when the last thing
+                   was a character: if this is a hyphen not at the
+                   beginning or the end of a list, then it's the range
+                   operator.  */
+                if (c == '-' 
+                    && !(p - 2 >= pattern && p[-2] == '[') 
+                    && !(p - 3 >= pattern && p[-3] == '[' && p[-2] == '^')
+                    && *p != ']')
+                  {
+                    reg_errcode_t ret
+                      = compile_range (rxb, cs, &p, pend, translate, syntax,
+				       inverse_translate, validate_inv_tr);
+                    if (ret != REG_NOERROR) return ret;
+                  }
+		
+                else if (p[0] == '-' && p[1] != ']')
+                  { /* This handles ranges made up of characters only.  */
+                    reg_errcode_t ret;
+		    
+		    /* Move past the `-'.  */
+                    PATFETCH (c1);
+                    
+                    ret = compile_range (rxb, cs, &p, pend, translate, syntax,
+					 inverse_translate, validate_inv_tr);
+                    if (ret != REG_NOERROR) return ret;
+                  }
+		
+                /* See if we're at the beginning of a possible character
+                   class.  */
+		
+		else if ((syntax & RE_CHAR_CLASSES)
+			 && (c == '[') && (*p == ':'))
+                  {
+                    char str[CHAR_CLASS_MAX_LENGTH + 1];
+		    
+                    PATFETCH (c);
+                    c1 = 0;
+		    
+                    /* If pattern is `[[:'.  */
+                    if (p == pend) return REG_EBRACK;
+		    
+                    for (;;)
+                      {
+                        PATFETCH (c);
+                        if (c == ':' || c == ']' || p == pend
+                            || c1 == CHAR_CLASS_MAX_LENGTH)
+			  break;
+                        str[c1++] = c;
+                      }
+                    str[c1] = '\0';
+		    
+                    /* If isn't a word bracketed by `[:' and:`]':
+                       undo the ending character, the letters, and leave 
+                       the leading `:' and `[' (but set bits for them).  */
+                    if (c == ':' && *p == ']')
+                      {
+                        int ch;
+                        boolean is_alnum = !strcmp (str, "alnum");
+                        boolean is_alpha = !strcmp (str, "alpha");
+                        boolean is_blank = !strcmp (str, "blank");
+                        boolean is_cntrl = !strcmp (str, "cntrl");
+                        boolean is_digit = !strcmp (str, "digit");
+                        boolean is_graph = !strcmp (str, "graph");
+                        boolean is_lower = !strcmp (str, "lower");
+                        boolean is_print = !strcmp (str, "print");
+                        boolean is_punct = !strcmp (str, "punct");
+                        boolean is_space = !strcmp (str, "space");
+                        boolean is_upper = !strcmp (str, "upper");
+                        boolean is_xdigit = !strcmp (str, "xdigit");
+                        
+                        if (!IS_CHAR_CLASS (str)) return REG_ECTYPE;
+			
+                        /* Throw away the ] at the end of the character
+                           class.  */
+                        PATFETCH (c);					
+			
+                        if (p == pend) return REG_EBRACK;
+			
+                        for (ch = 0; ch < 1 << CHARBITS; ch++)
+                          {
+                            if (   (is_alnum  && isalnum (ch))
+                                || (is_alpha  && isalpha (ch))
+                                || (is_blank  && isblank (ch))
+                                || (is_cntrl  && iscntrl (ch))
+                                || (is_digit  && isdigit (ch))
+                                || (is_graph  && isgraph (ch))
+                                || (is_lower  && islower (ch))
+                                || (is_print  && isprint (ch))
+                                || (is_punct  && ispunct (ch))
+                                || (is_space  && isspace (ch))
+                                || (is_upper  && isupper (ch))
+                                || (is_xdigit && isxdigit (ch)))
+			      {
+				rx_Bitset it =
+				  inverse_translation (rxb, 
+						       validate_inv_tr,
+						       inverse_translate,
+						       translate,
+						       ch);
+				rx_bitset_union (rxb->rx.local_cset_size,
+						 cs, it);
+			      }
+                          }
+                        had_char_class = true;
+                      }
+                    else
+                      {
+                        c1++;
+                        while (c1--)    
+                          PATUNFETCH;
+			{
+			  rx_Bitset it =
+			    inverse_translation (rxb, 
+						 validate_inv_tr,
+						 inverse_translate,
+						 translate,
+						 '[');
+			  rx_bitset_union (rxb->rx.local_cset_size,
+					   cs, it);
+			}
+			{
+			  rx_Bitset it =
+			    inverse_translation (rxb, 
+						 validate_inv_tr,
+						 inverse_translate,
+						 translate,
+						 ':');
+			  rx_bitset_union (rxb->rx.local_cset_size,
+					   cs, it);
+			}
+                        had_char_class = false;
+                      }
+                  }
+                else
+                  {
+                    had_char_class = false;
+		    {
+		      rx_Bitset it = inverse_translation (rxb, 
+							  validate_inv_tr,
+							  inverse_translate,
+							  translate,
+							  c);
+		      rx_bitset_union (rxb->rx.local_cset_size, cs, it);
+		    }
+                  }
+              }
+
+	  finalize_class_and_append:
+	    if (is_inverted)
+	      {
+		rx_bitset_complement (rxb->rx.local_cset_size, cs);
+		if (syntax & RE_HAT_LISTS_NOT_NEWLINE)
+		  RX_bitset_remove (cs, '\n');
+	      }
+	    goto append_node;
+          }
+          break;
+
+
+	case '(':
+          if (syntax & RE_NO_BK_PARENS)
+            goto handle_open;
+          else
+            goto normal_char;
+
+
+        case ')':
+          if (syntax & RE_NO_BK_PARENS)
+            goto handle_close;
+          else
+            goto normal_char;
+
+
+        case '\n':
+          if (syntax & RE_NEWLINE_ALT)
+            goto handle_alt;
+          else
+            goto normal_char;
+
+
+	case '|':
+          if (syntax & RE_NO_BK_VBAR)
+            goto handle_alt;
+          else
+            goto normal_char;
+
+
+        case '{':
+	  if ((syntax & RE_INTERVALS) && (syntax & RE_NO_BK_BRACES))
+	    goto handle_interval;
+	  else
+	    goto normal_char;
+
+
+        case '\\':
+          if (p == pend) return REG_EESCAPE;
+
+          /* Do not translate the character after the \, so that we can
+             distinguish, e.g., \B from \b, even if we normally would
+             translate, e.g., B to b.  */
+          PATFETCH_RAW (c);
+
+          switch (c)
+            {
+            case '(':
+              if (syntax & RE_NO_BK_PARENS)
+                goto normal_backslash;
+
+            handle_open:
+              rxb->re_nsub++;
+              regnum++;
+              if (COMPILE_STACK_FULL)
+                { 
+                  ((compile_stack.stack) =
+		   (compile_stack_elt_t *) realloc (compile_stack.stack, ( compile_stack.size << 1) * sizeof (
+													      compile_stack_elt_t)));
+                  if (compile_stack.stack == 0) return REG_ESPACE;
+
+                  compile_stack.size <<= 1;
+                }
+
+	      if (*last_expression)
+		{
+		  struct rexp_node * concat
+		    = rx_mk_r_concat (&rxb->rx, *last_expression, 0);
+		  if (!concat)
+		    return REG_ESPACE;
+		  *last_expression = concat;
+		  last_expression = &concat->params.pair.right;
+		}
+
+              /*
+	       * These are the values to restore when we hit end of this
+               * group.  
+	       */
+	      COMPILE_STACK_TOP.top_expression = top_expression;
+	      COMPILE_STACK_TOP.last_expression = last_expression;
+              COMPILE_STACK_TOP.regnum = regnum;
+	      
+              compile_stack.avail++;
+	      
+	      top_expression = last_expression;
+	      break;
+
+
+            case ')':
+              if (syntax & RE_NO_BK_PARENS) goto normal_backslash;
+
+            handle_close:
+              /* See similar code for backslashed left paren above.  */
+              if (COMPILE_STACK_EMPTY)
+                if (syntax & RE_UNMATCHED_RIGHT_PAREN_ORD)
+                  goto normal_char;
+                else
+                  return REG_ERPAREN;
+
+              /* Since we just checked for an empty stack above, this
+                 ``can't happen''.  */
+
+              {
+                /* We don't just want to restore into `regnum', because
+                   later groups should continue to be numbered higher,
+                   as in `(ab)c(de)' -- the second group is #2.  */
+                regnum_t this_group_regnum;
+		struct rexp_node ** inner = top_expression;
+
+                compile_stack.avail--;
+		top_expression = COMPILE_STACK_TOP.top_expression;
+		last_expression = COMPILE_STACK_TOP.last_expression;
+                this_group_regnum = COMPILE_STACK_TOP.regnum;
+		{
+		  int left_se = paramc;
+		  int right_se = paramc + 1;
+
+		  params = (params
+			    ? ((struct re_se_params *)
+			       realloc (params,
+					(paramc + 2) * sizeof (params[0])))
+			    : ((struct re_se_params *)
+			       malloc (2 * sizeof (params[0]))));
+		  if (!params)
+		    return REG_ESPACE;
+		  paramc += 2;
+
+		  params[left_se].se = re_se_lparen;
+		  params[left_se].op1 = this_group_regnum;
+		  params[right_se].se = re_se_rparen;
+		  params[right_se].op1 = this_group_regnum;
+		  {
+		    struct rexp_node * left
+		      = rx_mk_r_side_effect (&rxb->rx,
+					     (rx_side_effect)left_se);
+		    struct rexp_node * right
+		      = rx_mk_r_side_effect (&rxb->rx,
+					     (rx_side_effect)right_se);
+		    struct rexp_node * c1
+		      = (*inner
+			 ? rx_mk_r_concat (&rxb->rx, left, *inner) : left);
+		    struct rexp_node * c2
+		      = rx_mk_r_concat (&rxb->rx, c1, right);
+		    if (!(left && right && c1 && c2))
+		      return REG_ESPACE;
+		    *inner = c2;
+		  }
+		}
+		break;
+	      }
+
+            case '|':					/* `\|'.  */
+              if ((syntax & RE_LIMITED_OPS) || (syntax & RE_NO_BK_VBAR))
+                goto normal_backslash;
+            handle_alt:
+              if (syntax & RE_LIMITED_OPS)
+                goto normal_char;
+
+	      {
+		struct rexp_node * alt
+		  = rx_mk_r_alternate (&rxb->rx, *top_expression, 0);
+		if (!alt)
+		  return REG_ESPACE;
+		*top_expression = alt;
+		last_expression = &alt->params.pair.right;
+		{
+		  int sync_se = paramc;
+
+		  params = (params
+			    ? ((struct re_se_params *)
+			       realloc (params,
+					(paramc + 1) * sizeof (params[0])))
+			    : ((struct re_se_params *)
+			       malloc (sizeof (params[0]))));
+		  if (!params)
+		    return REG_ESPACE;
+		  ++paramc;
+
+		  params[sync_se].se = re_se_tv;
+		  {
+		    struct rexp_node * sync
+		      = rx_mk_r_side_effect (&rxb->rx,
+					     (rx_side_effect)sync_se);
+		    struct rexp_node * conc
+		      = rx_mk_r_concat (&rxb->rx, sync, 0);
+
+		    if (!sync || !conc)
+		      return REG_ESPACE;
+
+		    *last_expression = conc;
+		    last_expression = &conc->params.pair.right;
+		  }
+		}
+	      }
+              break;
+
+
+            case '{': 
+              /* If \{ is a literal.  */
+              if (!(syntax & RE_INTERVALS)
+                     /* If we're at `\{' and it's not the open-interval 
+                        operator.  */
+                  || ((syntax & RE_INTERVALS) && (syntax & RE_NO_BK_BRACES))
+                  || (p - 2 == pattern  &&  p == pend))
+                goto normal_backslash;
+
+            handle_interval:
+              {
+                /* If got here, then the syntax allows intervals.  */
+
+                /* At least (most) this many matches must be made.  */
+                int lower_bound = -1, upper_bound = -1;
+
+                beg_interval = p - 1;
+
+                if (p == pend)
+                  {
+                    if (syntax & RE_NO_BK_BRACES)
+                      goto unfetch_interval;
+                    else
+                      return REG_EBRACE;
+                  }
+
+                GET_UNSIGNED_NUMBER (lower_bound);
+
+                if (c == ',')
+                  {
+                    GET_UNSIGNED_NUMBER (upper_bound);
+                    if (upper_bound < 0) upper_bound = RE_DUP_MAX;
+                  }
+                else
+                  /* Interval such as `{1}' => match exactly once. */
+                  upper_bound = lower_bound;
+
+                if (lower_bound < 0 || upper_bound > RE_DUP_MAX
+                    || lower_bound > upper_bound)
+                  {
+                    if (syntax & RE_NO_BK_BRACES)
+                      goto unfetch_interval;
+                    else 
+                      return REG_BADBR;
+                  }
+
+                if (!(syntax & RE_NO_BK_BRACES)) 
+                  {
+                    if (c != '\\') return REG_EBRACE;
+                    PATFETCH (c);
+                  }
+
+                if (c != '}')
+                  {
+                    if (syntax & RE_NO_BK_BRACES)
+                      goto unfetch_interval;
+                    else 
+                      return REG_BADBR;
+                  }
+
+                /* We just parsed a valid interval.  */
+
+                /* If it's invalid to have no preceding re.  */
+                if (pointless_if_repeated (*last_expression, params))
+                  {
+                    if (syntax & RE_CONTEXT_INVALID_OPS)
+                      return REG_BADRPT;
+                    else if (!(syntax & RE_CONTEXT_INDEP_OPS))
+                      goto unfetch_interval;
+		    /* was: else laststart = b; */
+                  }
+
+                /* If the upper bound is zero, don't want to iterate
+                 * at all.
+		 */
+                 if (upper_bound == 0)
+		   {
+		     if (*last_expression)
+		       {
+			 rx_free_rexp (&rxb->rx, *last_expression);
+			 *last_expression = 0;
+		       }
+		   }
+		else
+		  /* Otherwise, we have a nontrivial interval. */
+		  {
+		    int iter_se = paramc;
+		    int end_se = paramc + 1;
+		    params = (params
+			      ? ((struct re_se_params *)
+				 realloc (params,
+					  sizeof (*params) * (2 + paramc)))
+			      : ((struct re_se_params *)
+				 malloc (2 * sizeof (*params))));
+		    if (!params)
+		      return REG_ESPACE;
+		    paramc += 2;
+		    params [iter_se].se = re_se_iter;
+		    params [iter_se].op1 = lower_bound;
+		    params[iter_se].op2 = upper_bound;
+
+		    params[end_se].se = re_se_end_iter;
+		    params[end_se].op1 = lower_bound;
+		    params[end_se].op2 = upper_bound;
+		    {
+		      struct rexp_node * push0
+			= rx_mk_r_side_effect (&rxb->rx,
+					       (rx_side_effect)re_se_push0);
+		      struct rexp_node * start_one_iter
+			= rx_mk_r_side_effect (&rxb->rx,
+					       (rx_side_effect)iter_se);
+		      struct rexp_node * phase1
+			= rx_mk_r_concat (&rxb->rx, start_one_iter,
+					  *last_expression);
+		      struct rexp_node * pushback
+			= rx_mk_r_side_effect (&rxb->rx,
+					       (rx_side_effect)re_se_pushback);
+		      rx_Bitset cs = rx_cset (&rxb->rx);
+		      struct rexp_node * lit_t
+			= rx_mk_r_cset (&rxb->rx, cs);
+		      struct rexp_node * phase2
+			= rx_mk_r_concat (&rxb->rx, pushback, lit_t);
+		      struct rexp_node * loop
+			= rx_mk_r_2phase_star (&rxb->rx, phase1, phase2);
+		      struct rexp_node * push_n_loop
+			= rx_mk_r_concat (&rxb->rx, push0, loop);
+		      struct rexp_node * final_test
+			= rx_mk_r_side_effect (&rxb->rx,
+					       (rx_side_effect)end_se);
+		      struct rexp_node * full_exp
+			= rx_mk_r_concat (&rxb->rx, push_n_loop, final_test);
+
+		      if (!(push0 && start_one_iter && phase1
+			    && pushback && lit_t && phase2
+			    && loop && push_n_loop && final_test && full_exp))
+			return REG_ESPACE;
+
+		      RX_bitset_enjoin(cs, 't');
+
+		      *last_expression = full_exp;
+		    }
+		  }
+                beg_interval = 0;
+              }
+              break;
+
+            unfetch_interval:
+              /* If an invalid interval, match the characters as literals.  */
+               p = beg_interval;
+               beg_interval = 0;
+
+               /* normal_char and normal_backslash need `c'.  */
+               PATFETCH (c);	
+
+               if (!(syntax & RE_NO_BK_BRACES))
+                 {
+                   if (p > pattern  &&  p[-1] == '\\')
+                     goto normal_backslash;
+                 }
+               goto normal_char;
+
+#ifdef emacs
+            /* There is no way to specify the before_dot and after_dot
+               operators.  rms says this is ok.  --karl  */
+            case '=':
+	      side = (rx_side_effect)rx_se_at_dot;
+	      goto add_side_effect;
+              break;
+
+            case 's':
+	    case 'S':
+	      {
+		rx_Bitset cs = rx_cset (&rxb->rx);
+		struct rexp_node * set = rx_mk_r_cset (&rxb->rx, cs);
+		if (!(cs && set))
+		  return REG_ESPACE;
+		if (c == 'S')
+		  rx_bitset_universe (rxb->rx.local_cset_size, cs);
+
+		PATFETCH (c);
+		{
+		  int x;
+		  enum syntaxcode code = syntax_spec_code [c];
+		  for (x = 0; x < 256; ++x)
+		    {
+		      
+		      if (SYNTAX (x) == code)
+			{
+			  rx_Bitset it =
+			    inverse_translation (rxb, validate_inv_tr,
+						 inverse_translate,
+						 translate, x);
+			  rx_bitset_xor (rxb->rx.local_cset_size, cs, it);
+			}
+		    }
+		}
+		append = set;
+		goto append_node;
+	      }
+              break;
+#endif /* emacs */
+
+
+            case 'w':
+            case 'W':
+	      {
+		rx_Bitset cs = rx_cset (&rxb->rx);
+		struct rexp_node * n = (cs ? rx_mk_r_cset (&rxb->rx, cs) : 0);
+		if (!(cs && n))
+		  return REG_ESPACE;
+		if (c == 'W')
+		  rx_bitset_universe (rxb->rx.local_cset_size ,cs);
+		{
+		  int x;
+		  for (x = rxb->rx.local_cset_size - 1; x > 0; --x)
+		    if (SYNTAX(x) & Sword)
+		      RX_bitset_toggle (cs, x);
+		}
+		append = n;
+		goto append_node;
+	      }
+              break;
+
+/* With a little extra work, some of these side effects could be optimized
+ * away (basicly by looking at what we already know about the surrounding
+ * chars).  
+ */
+            case '<':
+	      side = (rx_side_effect)re_se_wordbeg;
+	      goto add_side_effect;
+              break;
+
+            case '>':
+              side = (rx_side_effect)re_se_wordend;
+	      goto add_side_effect;
+              break;
+
+            case 'b':
+              side = (rx_side_effect)re_se_wordbound;
+	      goto add_side_effect;
+              break;
+
+            case 'B':
+              side = (rx_side_effect)re_se_notwordbound;
+	      goto add_side_effect;
+              break;
+
+            case '`':
+	      side = (rx_side_effect)re_se_begbuf;
+	      goto add_side_effect;
+	      break;
+	      
+            case '\'':
+	      side = (rx_side_effect)re_se_endbuf;
+	      goto add_side_effect;
+              break;
+
+	    add_side_effect:
+	      {
+		struct rexp_node * se
+		  = rx_mk_r_side_effect (&rxb->rx, side);
+		if (!se)
+		  return REG_ESPACE;
+		append = se;
+		goto append_node;
+	      }
+	      break;
+
+            case '1': case '2': case '3': case '4': case '5':
+            case '6': case '7': case '8': case '9':
+              if (syntax & RE_NO_BK_REFS)
+                goto normal_char;
+
+              c1 = c - '0';
+
+              if (c1 > regnum)
+                return REG_ESUBREG;
+
+              /* Can't back reference to a subexpression if inside of it.  */
+              if (group_in_compile_stack (compile_stack, c1))
+		return REG_ESUBREG;
+
+	      {
+		int backref_se = paramc;
+		params = (params
+			  ? ((struct re_se_params *)
+			     realloc (params,
+				      sizeof (*params) * (1 + paramc)))
+			  : ((struct re_se_params *)
+			     malloc (sizeof (*params))));
+		if (!params)
+		  return REG_ESPACE;
+		++paramc;
+		params[backref_se].se = re_se_backref;
+		params[backref_se].op1 = c1;
+		side = (rx_side_effect)backref_se;
+		goto add_side_effect;
+	      }
+              break;
+
+            case '+':
+            case '?':
+              if (syntax & RE_BK_PLUS_QM)
+                goto handle_plus;
+              else
+                goto normal_backslash;
+
+            default:
+            normal_backslash:
+              /* You might think it would be useful for \ to mean
+                 not to translate; but if we don't translate it
+                 it will never match anything.  */
+              c = TRANSLATE (c);
+              goto normal_char;
+            }
+          break;
+
+
+	default:
+        /* Expects the character in `c'.  */
+	normal_char:
+	    {
+	      rx_Bitset cs = rx_cset(&rxb->rx);
+	      struct rexp_node * match = rx_mk_r_cset (&rxb->rx, cs);
+	      rx_Bitset it;
+	      if (!(cs && match))
+		return REG_ESPACE;
+	      it = inverse_translation (rxb, validate_inv_tr,
+					inverse_translate, translate, c);
+	      rx_bitset_union (CHAR_SET_SIZE, cs, it);
+	      append = match;
+
+	    append_node:
+	      /* This genericly appends the rexp APPEND to *LAST_EXPRESSION
+	       * and then parses the next character normally.
+	       */
+	      if (*last_expression)
+		{
+		  struct rexp_node * concat
+		    = rx_mk_r_concat (&rxb->rx, *last_expression, append);
+		  if (!concat)
+		    return REG_ESPACE;
+		  *last_expression = concat;
+		  last_expression = &concat->params.pair.right;
+		}
+	      else
+		*last_expression = append;
+	    }
+	} /* switch (c) */
+    } /* while p != pend */
+
+  
+  {
+    int win_se = paramc;
+    params = (params
+	      ? ((struct re_se_params *)
+		 realloc (params,
+			  sizeof (*params) * (1 + paramc)))
+	      : ((struct re_se_params *)
+		 malloc (sizeof (*params))));
+    if (!params)
+      return REG_ESPACE;
+    ++paramc;
+    params[win_se].se = re_se_win;
+    {
+      struct rexp_node * se
+	= rx_mk_r_side_effect (&rxb->rx, (rx_side_effect)win_se);
+      struct rexp_node * concat
+	= rx_mk_r_concat (&rxb->rx, rexp, se);
+      if (!(se && concat))
+	return REG_ESPACE;
+      rexp = concat;
+    }
+  }
+
+
+  /* Through the pattern now.  */
+
+  if (!COMPILE_STACK_EMPTY) 
+    return REG_EPAREN;
+
+      free (compile_stack.stack);
+
+  orig_rexp = rexp;
+#ifdef RX_DEBUG
+  if (rx_debug_compile)
+    {
+      dbug_rxb = rxb;
+      fputs ("\n\nCompiling ", stdout);
+      fwrite (pattern, 1, size, stdout);
+      fputs (":\n", stdout);
+      rxb->se_params = params;
+      print_rexp (&rxb->rx, orig_rexp, 2, re_seprint, stdout);
+    }
+#endif
+  {
+    rx_Bitset cs = rx_cset(&rxb->rx);
+    rx_Bitset cs2 = rx_cset(&rxb->rx);
+#ifdef __WIN32__  /* [RPAP - Feb 97: WIN32 Port] */
+    char * se_map = (char *) _alloca (paramc);
+#else
+    char * se_map = (char *) alloca (paramc);
+#endif
+    struct rexp_node * new_rexp = 0;
+
+
+    bzero (se_map, paramc);
+    find_backrefs (se_map, rexp, params);
+    fewer_side_effects =
+      remove_unecessary_side_effects (&rxb->rx, se_map,
+				      rx_copy_rexp (&rxb->rx, rexp), params);
+
+    speed_up_alt (&rxb->rx, rexp, 0);
+    speed_up_alt (&rxb->rx, fewer_side_effects, 1);
+
+    {
+      char * syntax_parens = rxb->syntax_parens;
+      if (syntax_parens == (char *)0x1)
+	rexp = remove_unecessary_side_effects
+	  (&rxb->rx, se_map, rexp, params);
+      else if (syntax_parens)
+	{
+	  int x;
+	  for (x = 0; x < paramc; ++x)
+	    if ((   (params[x].se == re_se_lparen)
+		 || (params[x].se == re_se_rparen))
+		&& (!syntax_parens [params[x].op1]))
+	      se_map [x] = 1;
+	  rexp = remove_unecessary_side_effects
+	    (&rxb->rx, se_map, rexp, params);
+	}
+    }
+
+    /* At least one more optimization would be nice to have here but i ran out 
+     * of time.  The idea would be to delay side effects.  
+     * For examle, `(abc)' is the same thing as `abc()' except that the
+     * left paren is offset by 3 (which we know at compile time).
+     * (In this comment, write that second pattern `abc(:3:)' 
+     * where `(:3:' is a syntactic unit.)
+     *
+     * Trickier:  `(abc|defg)'  is the same as `(abc(:3:|defg(:4:))'
+     * (The paren nesting may be hard to follow -- that's an alternation
+     *	of `abc(:3:' and `defg(:4:' inside (purely syntactic) parens
+     *  followed by the closing paren from the original expression.)
+     *
+     * Neither the expression tree representation nor the the nfa make
+     * this very easy to write. :(
+     */
+
+  /* What we compile is different than what the parser returns.
+   * Suppose the parser returns expression R.
+   * Let R' be R with unnecessary register assignments removed 
+   * (see REMOVE_UNECESSARY_SIDE_EFFECTS, above).
+   *
+   * What we will compile is the expression:
+   *
+   *    m{try}R{win}\|s{try}R'{win}
+   *
+   * {try} and {win} denote side effect epsilons (see EXPLORE_FUTURE).
+   * 
+   * When trying a match, we insert an `m' at the beginning of the 
+   * string if the user wants registers to be filled, `s' if not.
+   */
+    new_rexp =
+      rx_mk_r_alternate
+	(&rxb->rx,
+	 rx_mk_r_concat (&rxb->rx, rx_mk_r_cset (&rxb->rx, cs2), rexp),
+	 rx_mk_r_concat (&rxb->rx,
+			 rx_mk_r_cset (&rxb->rx, cs), fewer_side_effects));
+
+    if (!(new_rexp && cs && cs2))
+      return REG_ESPACE;
+    RX_bitset_enjoin (cs2, '\0'); /* prefixed to the rexp used for matching. */
+    RX_bitset_enjoin (cs, '\1'); /* prefixed to the rexp used for searching. */
+    rexp = new_rexp;
+  }
+
+#ifdef RX_DEBUG
+  if (rx_debug_compile)
+    {
+      fputs ("\n...which is compiled as:\n", stdout);
+      print_rexp (&rxb->rx, rexp, 2, re_seprint, stdout);
+    }
+#endif
+  {
+    struct rx_nfa_state *start = 0;
+    struct rx_nfa_state *end = 0;
+
+    if (!rx_build_nfa (&rxb->rx, rexp, &start, &end))
+      return REG_ESPACE;	/*  */
+    else
+      {
+	void * mem = (void *)rxb->buffer;
+	unsigned long size = rxb->allocated;
+	int start_id;
+	char * perm_mem;
+	int iterator_size = paramc * sizeof (params[0]);
+
+	end->is_final = 1;
+	start->is_start = 1;
+	rx_name_nfa_states (&rxb->rx);
+	start_id = start->id;
+#ifdef RX_DEBUG
+	if (rx_debug_compile)
+	  {
+	    fputs ("...giving the NFA: \n", stdout);
+	    dbug_rxb = rxb;
+	    print_nfa (&rxb->rx, rxb->rx.nfa_states, re_seprint, stdout);
+	  }
+#endif
+	if (!rx_eclose_nfa (&rxb->rx))
+	  return REG_ESPACE;
+	else
+	  {
+	    rx_delete_epsilon_transitions (&rxb->rx);
+	    
+	    /* For compatability reasons, we need to shove the
+	     * compiled nfa into one chunk of malloced memory.
+	     */
+	    rxb->rx.reserved = (   sizeof (params[0]) * paramc
+				+  rx_sizeof_bitset (rxb->rx.local_cset_size));
+#ifdef RX_DEBUG
+	    if (rx_debug_compile)
+	      {
+		dbug_rxb = rxb;
+		fputs ("...which cooks down (uncompactified) to: \n", stdout);
+		print_nfa (&rxb->rx, rxb->rx.nfa_states, re_seprint, stdout);
+	      }
+#endif
+	    if (!rx_compactify_nfa (&rxb->rx, &mem, &size))
+	      return REG_ESPACE;
+	    rxb->buffer = mem;
+	    rxb->allocated = size;
+	    rxb->rx.buffer = mem;
+	    rxb->rx.allocated = size;
+	    perm_mem = ((char *)rxb->rx.buffer
+			+ rxb->rx.allocated - rxb->rx.reserved);
+	    rxb->se_params = ((struct re_se_params *)perm_mem);
+	    bcopy (params, rxb->se_params, iterator_size);
+	    perm_mem += iterator_size;
+	    rxb->fastset = (rx_Bitset) perm_mem;
+	    rxb->start = rx_id_to_nfa_state (&rxb->rx, start_id);
+	  }
+	rx_bitset_null (rxb->rx.local_cset_size, rxb->fastset);
+	rxb->can_match_empty = compute_fastset (rxb, orig_rexp);
+	rxb->match_regs_on_stack =
+	  registers_on_stack (rxb, orig_rexp, 0, params); 
+	rxb->search_regs_on_stack =
+	  registers_on_stack (rxb, fewer_side_effects, 0, params);
+	if (rxb->can_match_empty)
+	  rx_bitset_universe (rxb->rx.local_cset_size, rxb->fastset);
+	rxb->is_anchored = is_anchored (orig_rexp, (rx_side_effect) re_se_hat);
+	rxb->begbuf_only = is_anchored (orig_rexp,
+					(rx_side_effect) re_se_begbuf);
+      }
+    rx_free_rexp (&rxb->rx, rexp);
+    if (params)
+      free (params);
+#ifdef RX_DEBUG
+    if (rx_debug_compile)
+      {
+	dbug_rxb = rxb;
+	fputs ("...which cooks down to: \n", stdout);
+	print_nfa (&rxb->rx, rxb->rx.nfa_states, re_seprint, stdout);
+      }
+#endif
+  }
+  return REG_NOERROR;
+}
+
+
+
+
+/* This table gives an error message for each of the error codes listed
+   in regex.h.  Obviously the order here has to be same as there.  */
+
+__const__ char * rx_error_msg[] =
+{ 0,						/* REG_NOERROR */
+    "No match",					/* REG_NOMATCH */
+    "Invalid regular expression",		/* REG_BADPAT */
+    "Invalid collation character",		/* REG_ECOLLATE */
+    "Invalid character class name",		/* REG_ECTYPE */
+    "Trailing backslash",			/* REG_EESCAPE */
+    "Invalid back reference",			/* REG_ESUBREG */
+    "Unmatched [ or [^",			/* REG_EBRACK */
+    "Unmatched ( or \\(",			/* REG_EPAREN */
+    "Unmatched \\{",				/* REG_EBRACE */
+    "Invalid content of \\{\\}",		/* REG_BADBR */
+    "Invalid range end",			/* REG_ERANGE */
+    "Memory exhausted",				/* REG_ESPACE */
+    "Invalid preceding regular expression",	/* REG_BADRPT */
+    "Premature end of regular expression",	/* REG_EEND */
+    "Regular expression too big",		/* REG_ESIZE */
+    "Unmatched ) or \\)",			/* REG_ERPAREN */
+};
+
+
+
+
+
+char rx_slowmap [256] =
+{
+  1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+  1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+  1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+  1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+  1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+  1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+  1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+  1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+  1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+  1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+  1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+  1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+  1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+  1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+  1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+  1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+};
+
+#ifdef __STDC__
+RX_DECL void
+rx_blow_up_fastmap (struct re_pattern_buffer * rxb)
+#else
+RX_DECL void
+rx_blow_up_fastmap (rxb)
+     struct re_pattern_buffer * rxb;
+#endif
+{
+  int x;
+  for (x = 0; x < 256; ++x)	/* &&&& 3.6 % */
+    rxb->fastmap [x] = !!RX_bitset_member (rxb->fastset, x);
+  rxb->fastmap_accurate = 1;
+}
+
+
+
+
+
+#if !defined(REGEX_MALLOC) && !defined(__GNUC__)
+#define RE_SEARCH_2_FN	inner_re_search_2
+#define RE_S2_QUAL static
+#else
+#define RE_SEARCH_2_FN	re_search_2
+#define RE_S2_QUAL 
+#endif
+
+struct re_search_2_closure
+{
+  __const__ char * string1;
+  int size1;
+  __const__ char * string2;
+  int size2;
+};
+
+
+static __inline__ enum rx_get_burst_return
+re_search_2_get_burst (pos, vclosure, stop)
+     struct rx_string_position * pos;
+     void * vclosure;
+     int stop;
+{
+  struct re_search_2_closure * closure;
+  closure = (struct re_search_2_closure *)vclosure;
+  if (!closure->string2)
+    {
+      int inset;
+
+      inset = pos->pos - pos->string;
+      if ((inset < -1) || (inset > closure->size1))
+	return rx_get_burst_no_more;
+      else
+	{
+	  pos->pos = (__const__ unsigned char *) closure->string1 + inset;
+	  pos->string = (__const__ unsigned char *) closure->string1;
+	  pos->size = closure->size1;
+	  pos->end = ((__const__ unsigned char *)
+		      MIN(closure->string1 + closure->size1,
+			  closure->string1 + stop));
+	  pos->offset = 0;
+	  return ((pos->pos < pos->end)
+		  ? rx_get_burst_ok
+		  :  rx_get_burst_no_more);
+	}
+    }
+  else if (!closure->string1)
+    {
+      int inset;
+
+      inset = pos->pos - pos->string;
+      pos->pos = (__const__ unsigned char *) closure->string2 + inset;
+      pos->string = (__const__ unsigned char *) closure->string2;
+      pos->size = closure->size2;
+      pos->end = ((__const__ unsigned char *)
+		  MIN(closure->string2 + closure->size2,
+		      closure->string2 + stop));
+      pos->offset = 0;
+      return ((pos->pos < pos->end)
+	      ? rx_get_burst_ok
+	      :  rx_get_burst_no_more);
+    }
+  else
+    {
+      int inset;
+
+      inset = pos->pos - pos->string + pos->offset;
+      if (inset < closure->size1)
+	{
+	  pos->pos = (__const__ unsigned char *) closure->string1 + inset;
+	  pos->string = (__const__ unsigned char *) closure->string1;
+	  pos->size = closure->size1;
+	  pos->end = ((__const__ unsigned char *)
+		      MIN(closure->string1 + closure->size1,
+			  closure->string1 + stop));
+	  pos->offset = 0;
+	  return rx_get_burst_ok;
+	}
+      else
+	{
+	  pos->pos = ((__const__ unsigned char *)
+		      closure->string2 + inset - closure->size1);
+	  pos->string = (__const__ unsigned char *) closure->string2;
+	  pos->size = closure->size2;
+	  pos->end = ((__const__ unsigned char *)
+		      MIN(closure->string2 + closure->size2,
+			  closure->string2 + stop - closure->size1));
+	  pos->offset = closure->size1;
+	  return ((pos->pos < pos->end)
+		  ? rx_get_burst_ok
+		  :  rx_get_burst_no_more);
+	}
+    }
+}
+
+
+static __inline__ enum rx_back_check_return
+re_search_2_back_check (pos, lparen, rparen, translate, vclosure, stop)
+     struct rx_string_position * pos;
+     int lparen;
+     int rparen;
+     unsigned char * translate;
+     void * vclosure;
+     int stop;
+{
+  struct rx_string_position there;
+  struct rx_string_position past;
+
+  there = *pos;
+  there.pos = there.string + lparen - there.offset;
+  re_search_2_get_burst (&there, vclosure, stop);
+
+  past = *pos;
+  past.pos = past.string + rparen - there.offset;
+  re_search_2_get_burst (&past, vclosure, stop);
+
+  ++pos->pos;
+  re_search_2_get_burst (pos, vclosure, stop);
+
+  while (   (there.pos != past.pos)
+	 && (pos->pos != pos->end))
+    if (TRANSLATE(*there.pos) != TRANSLATE(*pos->pos))
+      return rx_back_check_fail;
+    else
+      {
+	++there.pos;
+	++pos->pos;
+	if (there.pos == there.end)
+	  re_search_2_get_burst (&there, vclosure, stop);
+	if (pos->pos == pos->end)
+	  re_search_2_get_burst (pos, vclosure, stop);
+      }
+
+  if (there.pos != past.pos)
+    return rx_back_check_fail;
+  --pos->pos;
+  re_search_2_get_burst (pos, vclosure, stop);
+  return rx_back_check_pass;
+}
+
+static __inline__ int
+re_search_2_fetch_char (pos, offset, app_closure, stop)
+     struct rx_string_position * pos;
+     int offset;
+     void * app_closure;
+     int stop;
+{
+  struct re_search_2_closure * closure;
+  closure = (struct re_search_2_closure *)app_closure;
+  if (offset == 0)
+    {
+      if (pos->pos >= pos->string)
+	return *pos->pos;
+      else
+	{
+	  if (   (pos->string == (__const__ unsigned char *) closure->string2)
+	      && (closure->string1)
+	      && (closure->size1))
+	    return closure->string1[closure->size1 - 1];
+	  else
+	    return 0;		/* sure, why not. */
+	}
+    }
+  if (pos->pos == pos->end)
+    return *closure->string2;
+  else
+    return pos->pos[1];
+}
+     
+
+#ifdef __STDC__
+RE_S2_QUAL int
+RE_SEARCH_2_FN (struct re_pattern_buffer *rxb,
+		__const__ char * string1, int size1,
+		__const__ char * string2, int size2,
+		int startpos, int range,
+		struct re_registers *regs,
+		int stop)
+#else
+RE_S2_QUAL int
+RE_SEARCH_2_FN (rxb,
+		string1, size1, string2, size2, startpos, range, regs, stop)
+     struct re_pattern_buffer *rxb;
+     __const__ char * string1;
+     int size1;
+     __const__ char * string2;
+     int size2;
+     int startpos;
+     int range;
+     struct re_registers *regs;
+     int stop;
+#endif
+{
+  int answer;
+  struct re_search_2_closure closure;
+  closure.string1 = string1;
+  closure.size1 = size1;
+  closure.string2 = string2;
+  closure.size2 = size2;
+  answer = rx_search (rxb, startpos, range, stop, size1 + size2,
+		      re_search_2_get_burst,
+		      re_search_2_back_check,
+		      re_search_2_fetch_char,
+		      (void *)&closure,
+		      regs,
+		      0,
+		      0);
+  switch (answer)
+    {
+    case rx_search_continuation:
+      abort ();
+    case rx_search_error:
+      return -2;
+    case rx_search_soft_fail:
+    case rx_search_fail:
+      return -1;
+    default:
+      return answer;
+    }
+}
+
+/* Export rx_search to callers outside this file.  */
+
+int
+re_rx_search (rxb, startpos, range, stop, total_size,
+	      get_burst, back_check, fetch_char,
+	      app_closure, regs, resume_state, save_state)
+     struct re_pattern_buffer * rxb;
+     int startpos;
+     int range;
+     int stop;
+     int total_size;
+     rx_get_burst_fn get_burst;
+     rx_back_check_fn back_check;
+     rx_fetch_char_fn fetch_char;
+     void * app_closure;
+     struct re_registers * regs;
+     struct rx_search_state * resume_state;
+     struct rx_search_state * save_state;
+{
+  return rx_search (rxb, startpos, range, stop, total_size,
+		    get_burst, back_check, fetch_char, app_closure,
+		    regs, resume_state, save_state);
+}
+
+#if !defined(REGEX_MALLOC) && !defined(__GNUC__)
+#ifdef __STDC__
+int
+re_search_2 (struct re_pattern_buffer *rxb,
+	     __const__ char * string1, int size1,
+	     __const__ char * string2, int size2,
+	     int startpos, int range,
+	     struct re_registers *regs,
+	     int stop)
+#else
+int
+re_search_2 (rxb, string1, size1, string2, size2, startpos, range, regs, stop)
+     struct re_pattern_buffer *rxb;
+     __const__ char * string1;
+     int size1;
+     __const__ char * string2;
+     int size2;
+     int startpos;
+     int range;
+     struct re_registers *regs;
+     int stop;
+#endif
+{
+  int ret;
+  ret = inner_re_search_2 (rxb, string1, size1, string2, size2, startpos,
+			   range, regs, stop);
+#ifdef __WIN32__  /* [RPAP - Feb 97: WIN32 Port] */
+  _alloca (0);
+#else
+  alloca (0);
+#endif
+  return ret;
+}
+#endif
+
+
+/* Like re_search_2, above, but only one string is specified, and
+ * doesn't let you say where to stop matching.
+ */
+
+#ifdef __STDC__
+int
+re_search (struct re_pattern_buffer * rxb, __const__ char *string,
+	   int size, int startpos, int range,
+	   struct re_registers *regs)
+#else
+int
+re_search (rxb, string, size, startpos, range, regs)
+     struct re_pattern_buffer * rxb;
+     __const__ char * string;
+     int size;
+     int startpos;
+     int range;
+     struct re_registers *regs;
+#endif
+{
+  return re_search_2 (rxb, 0, 0, string, size, startpos, range, regs, size);
+}
+
+#ifdef __STDC__
+int
+re_match_2 (struct re_pattern_buffer * rxb,
+	    __const__ char * string1, int size1,
+	    __const__ char * string2, int size2,
+	    int pos, struct re_registers *regs, int stop)
+#else
+int
+re_match_2 (rxb, string1, size1, string2, size2, pos, regs, stop)
+     struct re_pattern_buffer * rxb;
+     __const__ char * string1;
+     int size1;
+     __const__ char * string2;
+     int size2;
+     int pos;
+     struct re_registers *regs;
+     int stop;
+#endif
+{
+  struct re_registers some_regs;
+  regoff_t start;
+  regoff_t end;
+  int srch;
+  int save = rxb->regs_allocated;
+  struct re_registers * regs_to_pass = regs;
+
+  if (!regs)
+    {
+      some_regs.start = &start;
+      some_regs.end = &end;
+      some_regs.num_regs = 1;
+      regs_to_pass = &some_regs;
+      rxb->regs_allocated = REGS_FIXED;
+    }
+
+  srch = re_search_2 (rxb, string1, size1, string2, size2,
+		      pos, 1, regs_to_pass, stop);
+  if (regs_to_pass != regs)
+    rxb->regs_allocated = save;
+  if (srch < 0)
+    return srch;
+  return regs_to_pass->end[0] - regs_to_pass->start[0];
+}
+
+/* re_match is like re_match_2 except it takes only a single string.  */
+
+#ifdef __STDC__
+int
+re_match (struct re_pattern_buffer * rxb,
+	  __const__ char * string,
+	  int size, int pos,
+	  struct re_registers *regs)
+#else
+int
+re_match (rxb, string, size, pos, regs)
+     struct re_pattern_buffer * rxb;
+     __const__ char *string;
+     int size;
+     int pos;
+     struct re_registers *regs;
+#endif
+{
+  return re_match_2 (rxb, string, size, 0, 0, pos, regs, size);
+}
+
+
+
+
+/* Set by `re_set_syntax' to the current regexp syntax to recognize.  Can
+   also be assigned to arbitrarily: each pattern buffer stores its own
+   syntax, so it can be changed between regex compilations.  */
+reg_syntax_t re_syntax_options = RE_SYNTAX_EMACS;
+
+
+/* Specify the precise syntax of regexps for compilation.  This provides
+   for compatibility for various utilities which historically have
+   different, incompatible syntaxes.
+
+   The argument SYNTAX is a bit mask comprised of the various bits
+   defined in regex.h.  We return the old syntax.  */
+
+#ifdef __STDC__
+reg_syntax_t
+re_set_syntax (reg_syntax_t syntax)
+#else
+reg_syntax_t
+re_set_syntax (syntax)
+    reg_syntax_t syntax;
+#endif
+{
+  reg_syntax_t ret = re_syntax_options;
+
+  re_syntax_options = syntax;
+  return ret;
+}
+
+
+
+/* Set REGS to hold NUM_REGS registers, storing them in STARTS and
+   ENDS.  Subsequent matches using PATTERN_BUFFER and REGS will use
+   this memory for recording register information.  STARTS and ENDS
+   must be allocated using the malloc library routine, and must each
+   be at least NUM_REGS * sizeof (regoff_t) bytes long.
+
+   If NUM_REGS == 0, then subsequent matches should allocate their own
+   register data.
+
+   Unless this function is called, the first search or match using
+   PATTERN_BUFFER will allocate its own register data, without
+   freeing the old data.  */
+
+#ifdef __STDC__
+void
+re_set_registers (struct re_pattern_buffer *bufp,
+		  struct re_registers *regs,
+		  unsigned num_regs,
+		  regoff_t * starts, regoff_t * ends)
+#else
+void
+re_set_registers (bufp, regs, num_regs, starts, ends)
+     struct re_pattern_buffer *bufp;
+     struct re_registers *regs;
+     unsigned num_regs;
+     regoff_t * starts;
+     regoff_t * ends;
+#endif
+{
+  if (num_regs)
+    {
+      bufp->regs_allocated = REGS_REALLOCATE;
+      regs->num_regs = num_regs;
+      regs->start = starts;
+      regs->end = ends;
+    }
+  else
+    {
+      bufp->regs_allocated = REGS_UNALLOCATED;
+      regs->num_regs = 0;
+      regs->start = regs->end = (regoff_t) 0;
+    }
+}
+
+
+
+
+
+#ifdef __STDC__
+static int 
+cplx_se_sublist_len (struct rx_se_list * list)
+#else
+static int 
+cplx_se_sublist_len (list)
+     struct rx_se_list * list;
+#endif
+{
+  int x = 0;
+  while (list)
+    {
+      if ((long)list->car >= 0)
+	++x;
+      list = list->cdr;
+    }
+  return x;
+}
+
+
+/* For rx->se_list_cmp */
+
+#ifdef __STDC__
+static int 
+posix_se_list_order (struct rx * rx,
+		     struct rx_se_list * a, struct rx_se_list * b)
+#else
+static int 
+posix_se_list_order (rx, a, b)
+     struct rx * rx;
+     struct rx_se_list * a;
+     struct rx_se_list * b;
+#endif
+{
+  int al = cplx_se_sublist_len (a);
+  int bl = cplx_se_sublist_len (b);
+
+  if (!al && !bl)
+    return ((a == b)
+	    ? 0
+	    : ((a < b) ? -1 : 1));
+  
+  else if (!al)
+    return -1;
+
+  else if (!bl)
+    return 1;
+
+  else
+    {
+#ifdef __WIN32__  /* [RPAP - Feb 97: WIN32 Port] */
+      rx_side_effect * av = ((rx_side_effect *)
+			     _alloca (sizeof (rx_side_effect) * (al + 1)));
+      rx_side_effect * bv = ((rx_side_effect *)
+			     _alloca (sizeof (rx_side_effect) * (bl + 1)));
+#else
+      rx_side_effect * av = ((rx_side_effect *)
+			     alloca (sizeof (rx_side_effect) * (al + 1)));
+      rx_side_effect * bv = ((rx_side_effect *)
+			     alloca (sizeof (rx_side_effect) * (bl + 1)));
+#endif
+      struct rx_se_list * ap = a;
+      struct rx_se_list * bp = b;
+      int ai, bi;
+      
+      for (ai = al - 1; ai >= 0; --ai)
+	{
+	  while ((long)ap->car < 0)
+	    ap = ap->cdr;
+	  av[ai] = ap->car;
+	  ap = ap->cdr;
+	}
+      av[al] = (rx_side_effect)-2;
+      for (bi = bl - 1; bi >= 0; --bi)
+	{
+	  while ((long)bp->car < 0)
+	    bp = bp->cdr;
+	  bv[bi] = bp->car;
+	  bp = bp->cdr;
+	}
+      bv[bl] = (rx_side_effect)-1;
+
+      {
+	int ret;
+	int x = 0;
+	while (av[x] == bv[x])
+	  ++x;
+ 	ret = (((unsigned *)(av[x]) < (unsigned *)(bv[x])) ? -1 : 1);
+	return ret;
+      }
+    }
+}
+
+
+
+
+
+/* re_compile_pattern is the GNU regular expression compiler: it
+   compiles PATTERN (of length SIZE) and puts the result in RXB.
+   Returns 0 if the pattern was valid, otherwise an error string.
+
+   Assumes the `allocated' (and perhaps `buffer') and `translate' fields
+   are set in RXB on entry.
+
+   We call rx_compile to do the actual compilation.  */
+
+#ifdef __STDC__
+__const__ char *
+re_compile_pattern (__const__ char *pattern,
+		    int length,
+		    struct re_pattern_buffer * rxb)
+#else
+__const__ char *
+re_compile_pattern (pattern, length, rxb)
+     __const__ char *pattern;
+     int length;
+     struct re_pattern_buffer * rxb;
+#endif
+{
+  reg_errcode_t ret;
+
+  /* GNU code is written to assume at least RE_NREGS registers will be set
+     (and at least one extra will be -1).  */
+  rxb->regs_allocated = REGS_UNALLOCATED;
+
+  /* And GNU code determines whether or not to get register information
+     by passing null for the REGS argument to re_match, etc., not by
+     setting no_sub.  */
+  rxb->no_sub = 0;
+
+  rxb->rx.local_cset_size = 256;
+
+  /* Match anchors at newline.  */
+  rxb->newline_anchor = 1;
+ 
+  rxb->re_nsub = 0;
+  rxb->start = 0;
+  rxb->se_params = 0;
+  rxb->rx.nodec = 0;
+  rxb->rx.epsnodec = 0;
+  rxb->rx.instruction_table = 0;
+  rxb->rx.nfa_states = 0;
+  rxb->rx.se_list_cmp = posix_se_list_order;
+  rxb->rx.start_set = 0;
+
+  ret = rx_compile (pattern, length, re_syntax_options, rxb);
+#ifdef __WIN32__  /* [RPAP - Feb 97: WIN32 Port] */
+  _alloca (0);
+#else
+  alloca (0);
+#endif
+  return rx_error_msg[(int) ret];
+}
+
+
+
+#ifdef __STDC__
+int
+re_compile_fastmap (struct re_pattern_buffer * rxb)
+#else
+int
+re_compile_fastmap (rxb)
+     struct re_pattern_buffer * rxb;
+#endif
+{
+  rx_blow_up_fastmap (rxb);
+  return 0;
+}
+
+
+
+
+
+/* Entry points compatible with 4.2 BSD regex library.  We don't define
+   them if this is an Emacs or POSIX compilation.  */
+
+#if (!defined (emacs) && !defined (_POSIX_SOURCE)) || defined(USE_BSD_REGEX)
+
+/* BSD has one and only one pattern buffer.  */
+static struct re_pattern_buffer rx_comp_buf;
+
+#ifdef __STDC__
+char *
+re_comp (__const__ char *s)
+#else
+char *
+re_comp (s)
+    __const__ char *s;
+#endif
+{
+  reg_errcode_t ret;
+
+  if (!s || (*s == '\0'))
+    {
+      if (!rx_comp_buf.buffer)
+	return "No previous regular expression";
+      return 0;
+    }
+
+  if (!rx_comp_buf.fastmap)
+    {
+      rx_comp_buf.fastmap = (char *) malloc (1 << CHARBITS);
+      if (!rx_comp_buf.fastmap)
+	return "Memory exhausted";
+    }
+
+  /* Since `rx_exec' always passes NULL for the `regs' argument, we
+     don't need to initialize the pattern buffer fields which affect it.  */
+
+  /* Match anchors at newlines.  */
+  rx_comp_buf.newline_anchor = 1;
+
+  rx_comp_buf.re_nsub = 0;
+  rx_comp_buf.start = 0;
+  rx_comp_buf.se_params = 0;
+  rx_comp_buf.rx.nodec = 0;
+  rx_comp_buf.rx.epsnodec = 0;
+  rx_comp_buf.rx.instruction_table = 0;
+  rx_comp_buf.rx.nfa_states = 0;
+  rx_comp_buf.rx.start = 0;
+  rx_comp_buf.rx.se_list_cmp = posix_se_list_order;
+  rx_comp_buf.rx.local_cset_size = 256;
+
+  ret = rx_compile (s, strlen (s), re_syntax_options, &rx_comp_buf);
+#ifdef __WIN32__  /* [RPAP - Feb 97: WIN32 Port] */
+  _alloca (0);
+#else
+  alloca (0);
+#endif
+
+  /* Yes, we're discarding `__const__' here.  */
+  return (char *) rx_error_msg[(int) ret];
+}
+
+
+#ifdef __STDC__
+int
+re_exec (__const__ char *s)
+#else
+int
+re_exec (s)
+    __const__ char *s;
+#endif
+{
+  __const__ int len = strlen (s);
+  return
+    0 <= re_search (&rx_comp_buf, s, len, 0, len, (struct re_registers *) 0);
+}
+#endif /* not emacs and not _POSIX_SOURCE */
+
+
+
+
+/* POSIX.2 functions.  Don't define these for Emacs.  */
+
+#if !defined(emacs)
+
+/* regcomp takes a regular expression as a string and compiles it.
+
+   PREG is a regex_t *.  We do not expect any fields to be initialized,
+   since POSIX says we shouldn't.  Thus, we set
+
+     `buffer' to the compiled pattern;
+     `used' to the length of the compiled pattern;
+     `syntax' to RE_SYNTAX_POSIX_EXTENDED if the
+       REG_EXTENDED bit in CFLAGS is set; otherwise, to
+       RE_SYNTAX_POSIX_BASIC;
+     `newline_anchor' to REG_NEWLINE being set in CFLAGS;
+     `fastmap' and `fastmap_accurate' to zero;
+     `re_nsub' to the number of subexpressions in PATTERN.
+
+   PATTERN is the address of the pattern string.
+
+   CFLAGS is a series of bits which affect compilation.
+
+     If REG_EXTENDED is set, we use POSIX extended syntax; otherwise, we
+     use POSIX basic syntax.
+
+     If REG_NEWLINE is set, then . and [^...] don't match newline.
+     Also, regexec will try a match beginning after every newline.
+
+     If REG_ICASE is set, then we considers upper- and lowercase
+     versions of letters to be equivalent when matching.
+
+     If REG_NOSUB is set, then when PREG is passed to regexec, that
+     routine will report only success or failure, and nothing about the
+     registers.
+
+   It returns 0 if it succeeds, nonzero if it doesn't.  (See regex.h for
+   the return codes and their meanings.)  */
+
+
+#ifdef __STDC__
+int
+regcomp (regex_t * preg, __const__ char * pattern, int cflags)
+#else
+int
+regcomp (preg, pattern, cflags)
+    regex_t * preg;
+    __const__ char * pattern;
+    int cflags;
+#endif
+{
+  reg_errcode_t ret;
+  unsigned syntax
+    = cflags & REG_EXTENDED ? RE_SYNTAX_POSIX_EXTENDED : RE_SYNTAX_POSIX_BASIC;
+
+  /* regex_compile will allocate the space for the compiled pattern.  */
+  preg->buffer = 0;
+  preg->allocated = 0;
+  preg->fastmap = malloc (256);
+  if (!preg->fastmap)
+    return REG_ESPACE;
+  preg->fastmap_accurate = 0;
+
+  if (cflags & REG_ICASE)
+    {
+      unsigned i;
+
+      preg->translate = (unsigned char *) malloc (256);
+      if (!preg->translate)
+        return (int) REG_ESPACE;
+
+      /* Map uppercase characters to corresponding lowercase ones.  */
+      for (i = 0; i < CHAR_SET_SIZE; i++)
+        preg->translate[i] = isupper (i) ? tolower (i) : i;
+    }
+  else
+    preg->translate = 0;
+
+  /* If REG_NEWLINE is set, newlines are treated differently.  */
+  if (cflags & REG_NEWLINE)
+    { /* REG_NEWLINE implies neither . nor [^...] match newline.  */
+      syntax &= ~RE_DOT_NEWLINE;
+      syntax |= RE_HAT_LISTS_NOT_NEWLINE;
+      /* It also changes the matching behavior.  */
+      preg->newline_anchor = 1;
+    }
+  else
+    preg->newline_anchor = 0;
+
+  preg->no_sub = !!(cflags & REG_NOSUB);
+
+  /* POSIX says a null character in the pattern terminates it, so we
+     can use strlen here in compiling the pattern.  */
+  preg->re_nsub = 0;
+  preg->start = 0;
+  preg->se_params = 0;
+  preg->syntax_parens = 0;
+  preg->rx.nodec = 0;
+  preg->rx.epsnodec = 0;
+  preg->rx.instruction_table = 0;
+  preg->rx.nfa_states = 0;
+  preg->rx.local_cset_size = 256;
+  preg->rx.start = 0;
+  preg->rx.se_list_cmp = posix_se_list_order;
+  preg->rx.start_set = 0;
+  ret = rx_compile (pattern, strlen (pattern), syntax, preg);
+
+#ifdef __WIN32__  /* [RPAP - Feb 97: WIN32 Port] */
+  _alloca (0);
+#else
+  alloca (0);
+#endif
+
+  /* POSIX doesn't distinguish between an unmatched open-group and an
+     unmatched close-group: both are REG_EPAREN.  */
+  if (ret == REG_ERPAREN) ret = REG_EPAREN;
+
+  return (int) ret;
+}
+
+
+/* regexec searches for a given pattern, specified by PREG, in the
+   string STRING.
+
+   If NMATCH is zero or REG_NOSUB was set in the cflags argument to
+   `regcomp', we ignore PMATCH.  Otherwise, we assume PMATCH has at
+   least NMATCH elements, and we set them to the offsets of the
+   corresponding matched substrings.
+
+   EFLAGS specifies `execution flags' which affect matching: if
+   REG_NOTBOL is set, then ^ does not match at the beginning of the
+   string; if REG_NOTEOL is set, then $ does not match at the end.
+
+   We return 0 if we find a match and REG_NOMATCH if not.  */
+
+#ifdef __STDC__
+int
+regexec (__const__ regex_t *preg, __const__ char *string,
+	 size_t nmatch, regmatch_t pmatch[],
+	 int eflags)
+#else
+int
+regexec (preg, string, nmatch, pmatch, eflags)
+    __const__ regex_t *preg;
+    __const__ char *string;
+    size_t nmatch;
+    regmatch_t pmatch[];
+    int eflags;
+#endif
+{
+  int ret;
+  struct re_registers regs;
+  regex_t private_preg;
+  int len = strlen (string);
+  boolean want_reg_info = !preg->no_sub && nmatch > 0;
+
+  private_preg = *preg;
+
+  private_preg.not_bol = !!(eflags & REG_NOTBOL);
+  private_preg.not_eol = !!(eflags & REG_NOTEOL);
+
+  /* The user has told us exactly how many registers to return
+   * information about, via `nmatch'.  We have to pass that on to the
+   * matching routines.
+   */
+  private_preg.regs_allocated = REGS_FIXED;
+
+  if (want_reg_info)
+    {
+      regs.num_regs = nmatch;
+      regs.start =  (( regoff_t *) malloc ((nmatch) * sizeof ( regoff_t)));
+      regs.end =  (( regoff_t *) malloc ((nmatch) * sizeof ( regoff_t)));
+      if (regs.start == 0 || regs.end == 0)
+        return (int) REG_NOMATCH;
+    }
+
+  /* Perform the searching operation.  */
+  ret = re_search (&private_preg,
+		   string, len,
+                   /* start: */ 0,
+		   /* range: */ len,
+                   want_reg_info ? &regs : (struct re_registers *) 0);
+
+  /* Copy the register information to the POSIX structure.  */
+  if (want_reg_info)
+    {
+      if (ret >= 0)
+        {
+          unsigned r;
+
+          for (r = 0; r < nmatch; r++)
+            {
+              pmatch[r].rm_so = regs.start[r];
+              pmatch[r].rm_eo = regs.end[r];
+            }
+        }
+
+      /* If we needed the temporary register info, free the space now.  */
+      free (regs.start);
+      free (regs.end);
+    }
+
+  /* We want zero return to mean success, unlike `re_search'.  */
+  return ret >= 0 ? (int) REG_NOERROR : (int) REG_NOMATCH;
+}
+
+
+/* Returns a message corresponding to an error code, ERRCODE, returned
+   from either regcomp or regexec.   */
+
+#ifdef __STDC__
+size_t
+regerror (int errcode, __const__ regex_t *preg,
+	  char *errbuf, size_t errbuf_size)
+#else
+size_t
+regerror (errcode, preg, errbuf, errbuf_size)
+    int errcode;
+    __const__ regex_t *preg;
+    char *errbuf;
+    size_t errbuf_size;
+#endif
+{
+  __const__ char *msg
+    = rx_error_msg[errcode] == 0 ? "Success" : rx_error_msg[errcode];
+  size_t msg_size = strlen (msg) + 1; /* Includes the 0.  */
+
+  if (errbuf_size != 0)
+    {
+      if (msg_size > errbuf_size)
+        {
+          strncpy (errbuf, msg, errbuf_size - 1);
+          errbuf[errbuf_size - 1] = 0;
+        }
+      else
+        strcpy (errbuf, msg);
+    }
+
+  return msg_size;
+}
+
+
+/* Free dynamically allocated space used by PREG.  */
+
+#ifdef __STDC__
+void
+regfree (regex_t *preg)
+#else
+void
+regfree (preg)
+    regex_t *preg;
+#endif
+{
+  if (preg->buffer != 0)
+    free (preg->buffer);
+  preg->buffer = 0;
+  preg->allocated = 0;
+
+  if (preg->fastmap != 0)
+    free (preg->fastmap);
+  preg->fastmap = 0;
+  preg->fastmap_accurate = 0;
+
+  if (preg->translate != 0)
+    free (preg->translate);
+  preg->translate = 0;
+}
+
+#endif /* not emacs  */
+
+
+
+
+
Index: /main/tags/2.25/gsdl/packages/mg/lib/rx.h
===================================================================
--- /main/tags/2.25/gsdl/packages/mg/lib/rx.h	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/mg/lib/rx.h	(revision 21064)
@@ -0,0 +1,3755 @@
+#if !defined(RXH) || defined(RX_WANT_SE_DEFS)
+#define RXH
+
+/*	Copyright (C) 1992, 1993 Free Software Foundation, Inc.
+
+This file is part of the librx library.
+
+Librx is free software; you can redistribute it and/or modify it under
+the terms of the GNU Library General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+Librx 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 Library General Public
+License along with this software; see the file COPYING.LIB.  If not,
+write to the Free Software Foundation, 675 Mass Ave, Cambridge, MA
+02139, USA.  */
+/*  t. lord	Wed Sep 23 18:20:57 1992	*/
+
+
+
+
+
+
+
+
+
+#ifndef RX_WANT_SE_DEFS
+
+/* This page: Bitsets */
+
+#ifndef RX_subset
+typedef unsigned int RX_subset;
+#define RX_subset_bits	(32)
+#define RX_subset_mask	(RX_subset_bits - 1)
+#endif
+
+typedef RX_subset * rx_Bitset;
+
+#ifdef __STDC__
+typedef void (*rx_bitset_iterator) (void *, int member_index);
+#else
+typedef void (*rx_bitset_iterator) ();
+#endif
+
+#define rx_bitset_subset(N)  ((N) / RX_subset_bits)
+#define rx_bitset_subset_val(B,N)  ((B)[rx_bitset_subset(N)])
+#define RX_bitset_access(B,N,OP) \
+  ((B)[rx_bitset_subset(N)] OP rx_subset_singletons[(N) & RX_subset_mask])
+#define RX_bitset_member(B,N)   RX_bitset_access(B, N, &)
+#define RX_bitset_enjoin(B,N)   RX_bitset_access(B, N, |=)
+#define RX_bitset_remove(B,N)   RX_bitset_access(B, N, &= ~)
+#define RX_bitset_toggle(B,N)   RX_bitset_access(B, N, ^= )
+#define rx_bitset_numb_subsets(N) (((N) + RX_subset_bits - 1) / RX_subset_bits)
+#define rx_sizeof_bitset(N)	(rx_bitset_numb_subsets(N) * sizeof(RX_subset))
+
+
+
+
+/* This page: Splay trees. */
+
+#ifdef __STDC__
+typedef int (*rx_sp_comparer) (void * a, void * b);
+#else
+typedef int (*rx_sp_comparer) ();
+#endif
+
+struct rx_sp_node 
+{
+  void * key;
+  void * data;
+  struct rx_sp_node * kids[2];
+};
+
+#ifdef __STDC__
+typedef void (*rx_sp_key_data_freer) (struct rx_sp_node *);
+#else
+typedef void (*rx_sp_key_data_freer) ();
+#endif
+
+
+
+/* giant inflatable hash trees */
+
+struct rx_hash_item
+{
+  struct rx_hash_item * next_same_hash;
+  struct rx_hash * table;
+  unsigned long hash;
+  void * data;
+  void * binding;
+};
+
+struct rx_hash
+{
+  struct rx_hash * parent;
+  int refs;
+  struct rx_hash * children[13];
+  struct rx_hash_item * buckets [13];
+  int bucket_size [13];
+};
+
+struct rx_hash_rules;
+
+#ifdef __STDC__
+/* should return like == */
+typedef int (*rx_hash_eq)(void *, void *);
+typedef struct rx_hash * (*rx_alloc_hash)(struct rx_hash_rules *);
+typedef void (*rx_free_hash)(struct rx_hash *,
+			    struct rx_hash_rules *);
+typedef struct rx_hash_item * (*rx_alloc_hash_item)(struct rx_hash_rules *,
+						    void *);
+typedef void (*rx_free_hash_item)(struct rx_hash_item *,
+				 struct rx_hash_rules *);
+#else
+typedef int (*rx_hash_eq)();
+typedef struct rx_hash * (*rx_alloc_hash)();
+typedef void (*rx_free_hash)();
+typedef struct rx_hash_item * (*rx_alloc_hash_item)();
+typedef void (*rx_free_hash_item)();
+#endif
+
+struct rx_hash_rules
+{
+  rx_hash_eq eq;
+  rx_alloc_hash hash_alloc;
+  rx_free_hash free_hash;
+  rx_alloc_hash_item hash_item_alloc;
+  rx_free_hash_item free_hash_item;
+};
+
+
+
+/* Forward declarations */
+
+struct rx_cache;
+struct rx_superset;
+struct rx;
+struct rx_se_list;
+
+
+
+
+/* 
+ * GLOSSARY
+ *
+ * regexp
+ * regular expression
+ * expression
+ * pattern - a `regular' expression.  The expression
+ *       need not be formally regular -- it can contain
+ *       constructs that don't correspond to purely regular
+ *       expressions.
+ *
+ * buffer
+ * string - the string (or strings) being searched or matched.
+ *
+ * pattern buffer - a structure of type `struct re_pattern_buffer'
+ *       This in turn contains a `struct rx', which holds the
+ *       NFA compiled from a pattern, as well as some of the state
+ *       of a matcher using the pattern.
+ *
+ * NFA - nondeterministic finite automata.  Some people
+ *       use this term to a member of the class of 
+ *       regular automata (those corresponding to a regular
+ *       language).  However, in this code, the meaning is
+ *       more general.  The automata used by Rx are comperable
+ *       in power to what are usually called `push down automata'.
+ *
+ *       Two NFA are built by rx for every pattern.  One is built
+ *       by the compiler.  The other is built from the first, on
+ *       the fly, by the matcher.  The latter is called the `superstate
+ *       NFA' because its states correspond to sets of states from
+ *       the first NFA.  (Joe Keane gets credit for the name
+ *       `superstate NFA').
+ *
+ * NFA edges
+ * epsilon edges
+ * side-effect edges - The NFA compiled from a pattern can have three
+ *       kinds of edges.  Epsilon edges can be taken freely anytime
+ *       their source state is reached.  Character set edges can be
+ *       taken when their source state is reached and when the next 
+ *       character in the buffer is a member of the set.  Side effect
+ *       edges imply a transition that can only be taken after the
+ *       indicated side effect has been successfully accomplished.
+ *       Some examples of side effects are:
+ *
+ *		Storing the current match position to record the
+ *              location of a parentesized subexpression.
+ *
+ *              Advancing the matcher over N characters if they
+ *              match the N characters previously matched by a 
+ *              parentesized subexpression.
+ *
+ *       Both of those kinds of edges occur in the NFA generated
+ *       by the pattern:  \(.\)\1
+ *
+ *       Epsilon and side effect edges are similar.  Unfortunately,
+ *       some of the code uses the name `epsilon edge' to mean
+ *       both epsilon and side effect edges.  For example,  the
+ *       function has_non_idempotent_epsilon_path computes the existance
+ *       of a non-trivial path containing only a mix of epsilon and
+ *       side effect edges.  In that case `nonidempotent epsilon' is being
+ *       used to mean `side effect'.
+ */
+
+
+
+
+
+
+/* LOW LEVEL PATTERN BUFFERS */
+
+/* Suppose that from some NFA state, more than one path through
+ * side-effect edges is possible.  In what order should the paths
+ * be tried?  A function of type rx_se_list_order answers that
+ * question.  It compares two lists of side effects, and says
+ * which list comes first.
+ */
+ 
+#ifdef __STDC__
+typedef int (*rx_se_list_order) (struct rx *,
+				 struct rx_se_list *, 
+				 struct rx_se_list *);
+#else
+typedef int (*rx_se_list_order) ();
+#endif
+
+
+
+/* Struct RX holds a compiled regular expression - that is, an nfa
+ * ready to be converted on demand to a more efficient superstate nfa.
+ * This is for the low level interface.  The high-level interfaces enclose
+ * this in a `struct re_pattern_buffer'.  
+ */
+struct rx
+{
+  /* The compiler assigns a unique id to every pattern.
+   * Like sequence numbers in X, there is a subtle bug here
+   * if you use Rx in a system that runs for a long time.
+   * But, because of the way the caches work out, it is almost
+   * impossible to trigger the Rx version of this bug.
+   *
+   * The id is used to validate superstates found in a cache
+   * of superstates.  It isn't sufficient to let a superstate
+   * point back to the rx for which it was compiled -- the caller
+   * may be re-using a `struct rx' in which case the superstate
+   * is not really valid.  So instead, superstates are validated
+   * by checking the sequence number of the pattern for which
+   * they were built.
+   */
+  int rx_id;
+
+  /* This is memory mgt. state for superstates.  This may be 
+   * shared by more than one struct rx.
+   */
+  struct rx_cache * cache;
+
+  /* Every regex defines the size of its own character set. 
+   * A superstate has an array of this size, with each element
+   * a `struct rx_inx'.  So, don't make this number too large.
+   * In particular, don't make it 2^16.
+   */
+  int local_cset_size;
+
+  /* After the NFA is built, it is copied into a contiguous region
+   * of memory (mostly for compatability with GNU regex).
+   * Here is that region, and it's size:
+   */
+  void * buffer;
+  unsigned long allocated;
+
+  /* Clients of RX can ask for some extra storage in the space pointed
+   * to by BUFFER.  The field RESERVED is an input parameter to the
+   * compiler.  After compilation, this much space will be available 
+   * at (buffer + allocated - reserved)
+   */
+  unsigned long reserved;
+
+  /* --------- The remaining fields are for internal use only. --------- */
+  /* --------- But! they must be initialized to 0.	       --------- */
+
+  /* NODEC is the number of nodes in the NFA with non-epsilon
+   * transitions. 
+   */
+  int nodec;
+
+  /* EPSNODEC is the number of nodes with only epsilon transitions. */
+  int epsnodec;
+
+  /* The sum (NODEC + EPSNODEC) is the total number of states in the
+   * compiled NFA.
+   */
+
+  /* Lists of side effects as stored in the NFA are `hash consed'..meaning
+   * that lists with the same elements are ==.  During compilation, 
+   * this table facilitates hash-consing.
+   */
+  struct rx_hash se_list_memo;
+
+  /* Lists of NFA states are also hashed. 
+   */
+  struct rx_hash set_list_memo;
+
+
+
+
+  /* The compiler and matcher must build a number of instruction frames.
+   * The format of these frames is fixed (c.f. struct rx_inx).  The values
+   * of the instructions is not fixed.
+   *
+   * An enumerated type (enum rx_opcode) defines the set of instructions
+   * that the compiler or matcher might generate.  When filling an instruction
+   * frame, the INX field is found by indexing this instruction table
+   * with an opcode:
+   */
+  void ** instruction_table;
+
+  /* The list of all states in an NFA.
+   * During compilation, the NEXT field of NFA states links this list.
+   * After compilation, all the states are compacted into an array,
+   * ordered by state id numbers.  At that time, this points to the base 
+   * of that array.
+   */
+  struct rx_nfa_state *nfa_states;
+
+  /* Every nfa begins with one distinguished starting state:
+   */
+  struct rx_nfa_state *start;
+
+  /* This orders the search through super-nfa paths.
+   * See the comment near the typedef of rx_se_list_order.
+   */
+  rx_se_list_order se_list_cmp;
+
+  struct rx_superset * start_set;
+};
+
+
+
+
+
+/* SYNTAX TREES */
+
+/* Compilation is in stages.  
+ *
+ * In the first stage, a pattern specified by a string is 
+ * translated into a syntax tree.  Later stages will convert
+ * the syntax tree into an NFA optimized for conversion to a
+ * superstate-NFA.
+ *
+ * This page is about syntax trees.
+ */
+
+enum rexp_node_type
+{
+  r_cset,			/* Match from a character set. `a' or `[a-z]'*/
+  r_concat,			/* Concat two subexpressions.   `ab' */
+  r_alternate,			/* Choose one of two subexpressions. `a\|b' */
+  r_opt,			/* Optional subexpression. `a?' */
+  r_star,			/* Repeated subexpression. `a*' */
+
+
+  /* A 2phase-star is a variation on a repeated subexpression.
+   * In this case, there are two subexpressions.  The first, if matched,
+   * begins a repitition (otherwise, the whole expression is matches the
+   * empth string).  
+   * 
+   * After matching the first subexpression, a 2phase star either finishes,
+   * or matches the second subexpression.  If the second subexpression is
+   * matched, then the whole construct repeats.
+   *
+   * 2phase stars are used in two circumstances.  First, they
+   * are used as part of the implementation of POSIX intervals (counted
+   * repititions).  Second, they are used to implement proper star
+   * semantics when the repeated subexpression contains paths of
+   * only side effects.  See rx_compile for more information.
+   */
+  r_2phase_star,
+
+
+  /* c.f. "typedef void * rx_side_effect" */
+  r_side_effect,
+
+  /* This is an extension type:  It is for transient use in source->source
+   * transformations (implemented over syntax trees).
+   */
+  r_data
+};
+
+/* A side effect is a matcher-specific action associated with
+ * transitions in the NFA.  The details of side effects are up
+ * to the matcher.  To the compiler and superstate constructors
+ * side effects are opaque:
+ */
+
+typedef void * rx_side_effect;
+
+/* Nodes in a syntax tree are of this type:
+ */
+struct rexp_node
+{
+  enum rexp_node_type type;
+  union
+  {
+    rx_Bitset cset;
+    rx_side_effect side_effect;
+    struct
+      {
+	struct rexp_node *left;
+	struct rexp_node *right;
+      } pair;
+    void * data;
+  } params;
+};
+
+
+
+
+/* NFA
+ *
+ * A syntax tree is compiled into an NFA.  This page defines the structure
+ * of that NFA.
+ */
+
+struct rx_nfa_state
+{
+  /* These are kept in a list as the NFA is being built. */
+  struct rx_nfa_state *next;
+
+  /* After the NFA is built, states are given integer id's.
+   * States whose outgoing transitions are all either epsilon or 
+   * side effect edges are given ids less than 0.  Other states
+   * are given successive non-negative ids starting from 0.
+   */
+  int id;
+
+  /* The list of NFA edges that go from this state to some other. */
+  struct rx_nfa_edge *edges;
+
+  /* If you land in this state, then you implicitly land
+   * in all other states reachable by only epsilon translations.
+   * Call the set of maximal paths to such states the epsilon closure
+   * of this state.
+   *
+   * There may be other states that are reachable by a mixture of
+   * epsilon and side effect edges.  Consider the set of maximal paths
+   * of that sort from this state.  Call it the epsilon-side-effect
+   * closure of the state.
+   * 
+   * The epsilon closure of the state is a subset of the epsilon-side-
+   * effect closure.  It consists of all the paths that contain 
+   * no side effects -- only epsilon edges.
+   * 
+   * The paths in the epsilon-side-effect closure  can be partitioned
+   * into equivalance sets. Two paths are equivalant if they have the
+   * same set of side effects, in the same order.  The epsilon-closure
+   * is one of these equivalance sets.  Let's call these equivalance
+   * sets: observably equivalant path sets.  That name is chosen
+   * because equivalance of two paths means they cause the same side
+   * effects -- so they lead to the same subsequent observations other
+   * than that they may wind up in different target states.
+   *
+   * The superstate nfa, which is derived from this nfa, is based on
+   * the observation that all of the paths in an observably equivalant
+   * path set can be explored at the same time, provided that the
+   * matcher keeps track not of a single nfa state, but of a set of
+   * states.   In particular, after following all the paths in an
+   * observably equivalant set, you wind up at a set of target states.
+   * That set of target states corresponds to one state in the
+   * superstate NFA.
+   *
+   * Staticly, before matching begins, it is convenient to analyze the
+   * nfa.  Each state is labeled with a list of the observably
+   * equivalant path sets who's union covers all the
+   * epsilon-side-effect paths beginning in this state.  This list is
+   * called the possible futures of the state.
+   *
+   * A trivial example is this NFA:
+   *             s1
+   *         A  --->  B
+   *
+   *             s2  
+   *            --->  C
+   *
+   *             epsilon           s1
+   *            --------->  D   ------> E
+   * 
+   * 
+   * In this example, A has two possible futures.
+   * One invokes the side effect `s1' and contains two paths,
+   * one ending in state B, the other in state E.
+   * The other invokes the side effect `s2' and contains only
+   * one path, landing in state C.
+   */
+  struct rx_possible_future *futures;
+
+
+  /* There are exactly two distinguished states in every NFA: */
+  unsigned int is_final:1;
+  unsigned int is_start:1;
+
+  /* These are used during NFA construction... */
+  unsigned int eclosure_needed:1;
+  unsigned int mark:1;
+};
+
+
+/* An edge in an NFA is typed: */
+enum rx_nfa_etype
+{
+  /* A cset edge is labled with a set of characters one of which
+   * must be matched for the edge to be taken.
+   */
+  ne_cset,
+
+  /* An epsilon edge is taken whenever its starting state is
+   * reached. 
+   */
+  ne_epsilon,
+
+  /* A side effect edge is taken whenever its starting state is
+   * reached.  Side effects may cause the match to fail or the
+   * position of the matcher to advance.
+   */
+  ne_side_effect		/* A special kind of epsilon. */
+};
+
+struct rx_nfa_edge
+{
+  struct rx_nfa_edge *next;
+  enum rx_nfa_etype type;
+  struct rx_nfa_state *dest;
+  union
+  {
+    rx_Bitset cset;
+    rx_side_effect side_effect;
+  } params;
+};
+
+
+
+/* A possible future consists of a list of side effects
+ * and a set of destination states.  Below are their
+ * representations.  These structures are hash-consed which
+ * means that lists with the same elements share a representation
+ * (their addresses are ==).
+ */
+
+struct rx_nfa_state_set
+{
+  struct rx_nfa_state * car;
+  struct rx_nfa_state_set * cdr;
+};
+
+struct rx_se_list
+{
+  rx_side_effect car;
+  struct rx_se_list * cdr;
+};
+
+struct rx_possible_future
+{
+  struct rx_possible_future *next;
+  struct rx_se_list * effects;
+  struct rx_nfa_state_set * destset;
+};
+
+
+
+
+/* This begins the description of the superstate NFA.
+ *
+ * The superstate NFA corresponds to the NFA in these ways:
+ *
+ * Every superstate NFA states SUPER correspond to sets of NFA states,
+ * nfa_states(SUPER).
+ *
+ * Superstate edges correspond to NFA paths.
+ *
+ * The superstate has no epsilon transitions;
+ * every edge has a character label, and a (possibly empty) side
+ * effect label.   The side effect label corresponds to a list of
+ * side effects that occur in the NFA.  These parts are referred
+ * to as:   superedge_character(EDGE) and superedge_sides(EDGE).
+ *
+ * For a superstate edge EDGE starting in some superstate SUPER,
+ * the following is true (in pseudo-notation :-):
+ *
+ *       exists DEST in nfa_states s.t. 
+ *         exists nfaEDGE in nfa_edges s.t.
+ *                 origin (nfaEDGE) == DEST
+ *              && origin (nfaEDGE) is a member of nfa_states(SUPER)
+ *              && exists PF in possible_futures(dest(nfaEDGE)) s.t.
+ * 	                sides_of_possible_future (PF) == superedge_sides (EDGE)
+ *
+ * also:
+ *
+ *      let SUPER2 := superedge_destination(EDGE)
+ *          nfa_states(SUPER2)
+ *           == union of all nfa state sets S s.t.
+ *                          exists PF in possible_futures(dest(nfaEDGE)) s.t.
+ * 	                       sides_of_possible_future (PF) == superedge_sides (EDGE)
+ *                          && S == dests_of_possible_future (PF) }
+ *
+ * Or in english, every superstate is a set of nfa states.  A given
+ * character and a superstate implies many transitions in the NFA --
+ * those that begin with an edge labeled with that character from a
+ * state in the set corresponding to the superstate.
+ * 
+ * The destinations of those transitions each have a set of possible
+ * futures.  A possible future is a list of side effects and a set of
+ * destination NFA states.  Two sets of possible futures can be
+ * `merged' by combining all pairs of possible futures that have the
+ * same side effects.  A pair is combined by creating a new future
+ * with the same side effect but the union of the two destination sets.
+ * In this way, all the possible futures suggested by a superstate
+ * and a character can be merged into a set of possible futures where
+ * no two elements of the set have the same set of side effects.
+ *
+ * The destination of a possible future, being a set of NFA states, 
+ * corresponds to a supernfa state.  So, the merged set of possible
+ * futures we just created can serve as a set of edges in the
+ * supernfa.
+ *
+ * The representation of the superstate nfa and the nfa is critical.
+ * The nfa has to be compact, but has to facilitate the rapid
+ * computation of missing superstates.  The superstate nfa has to 
+ * be fast to interpret, lazilly constructed, and bounded in space.
+ *
+ * To facilitate interpretation, the superstate data structures are 
+ * peppered with `instruction frames'.  There is an instruction set
+ * defined below which matchers using the supernfa must be able to
+ * interpret.
+ *
+ * We'd like to make it possible but not mandatory to use code
+ * addresses to represent instructions (c.f. gcc's computed goto).
+ * Therefore, we define an enumerated type of opcodes, and when
+ * writing one of these instructions into a data structure, use
+ * the opcode as an index into a table of instruction values.
+ * 
+ * Here are the opcodes that occur in the superstate nfa:
+ */
+ 
+
+/* Every superstate contains a table of instruction frames indexed 
+ * by characters.  A normal `move' in a matcher is to fetch the next
+ * character and use it as an index into a superstates transition
+ * table.
+ *
+ * In the fasted case, only one edge follows from that character.
+ * In other cases there is more work to do.
+ * 
+ * The descriptions of the opcodes refer to data structures that are
+ * described further below. 
+ */
+
+enum rx_opcode
+{
+  /* 
+   * BACKTRACK_POINT is invoked when a character transition in 
+   * a superstate leads to more than one edge.  In that case,
+   * the edges have to be explored independently using a backtracking
+   * strategy.
+   *
+   * A BACKTRACK_POINT instruction is stored in a superstate's 
+   * transition table for some character when it is known that that
+   * character crosses more than one edge.  On encountering this
+   * instruction, the matcher saves enough state to backtrack to this
+   * point in the match later.
+   */
+  rx_backtrack_point = 0,	/* data is (struct transition_class *) */
+
+  /* 
+   * RX_DO_SIDE_EFFECTS evaluates the side effects of an epsilon path.
+   * There is one occurence of this instruction per rx_distinct_future.
+   * This instruction is skipped if a rx_distinct_future has no side effects.
+   */
+  rx_do_side_effects = rx_backtrack_point + 1,
+
+  /* data is (struct rx_distinct_future *) */
+
+  /* 
+   * RX_CACHE_MISS instructions are stored in rx_distinct_futures whose
+   * destination superstate has been reclaimed (or was never built).
+   * It recomputes the destination superstate.
+   * RX_CACHE_MISS is also stored in a superstate transition table before
+   * any of its edges have been built.
+   */
+  rx_cache_miss = rx_do_side_effects + 1,
+  /* data is (struct rx_distinct_future *) */
+
+  /* 
+   * RX_NEXT_CHAR is called to consume the next character and take the
+   * corresponding transition.  This is the only instruction that uses 
+   * the DATA field of the instruction frame instead of DATA_2.
+   * (see EXPLORE_FUTURE in regex.c).
+   */
+  rx_next_char = rx_cache_miss + 1, /* data is (struct superstate *) */
+
+  /* RX_BACKTRACK indicates that a transition fails.
+   */
+  rx_backtrack = rx_next_char + 1, /* no data */
+
+  /* 
+   * RX_ERROR_INX is stored only in places that should never be executed.
+   */
+  rx_error_inx = rx_backtrack + 1, /* Not supposed to occur. */
+
+  rx_num_instructions = rx_error_inx + 1
+};
+
+/* An id_instruction_table holds the values stored in instruction
+ * frames.  The table is indexed by the enums declared above.
+ */
+extern void * rx_id_instruction_table[rx_num_instructions];
+
+/* The heart of the matcher is a `word-code-interpreter' 
+ * (like a byte-code interpreter, except that instructions
+ * are a full word wide).
+ *
+ * Instructions are not stored in a vector of code, instead,
+ * they are scattered throughout the data structures built
+ * by the regexp compiler and the matcher.  One word-code instruction,
+ * together with the arguments to that instruction, constitute
+ * an instruction frame (struct rx_inx).
+ *
+ * This structure type is padded by hand to a power of 2 because
+ * in one of the dominant cases, we dispatch by indexing a table
+ * of instruction frames.  If that indexing can be accomplished
+ * by just a shift of the index, we're happy.
+ *
+ * Instructions take at most one argument, but there are two
+ * slots in an instruction frame that might hold that argument.
+ * These are called data and data_2.  The data slot is only
+ * used for one instruction (RX_NEXT_CHAR).  For all other 
+ * instructions, data should be set to 0.
+ *
+ * RX_NEXT_CHAR is the most important instruction by far.
+ * By reserving the data field for its exclusive use, 
+ * instruction dispatch is sped up in that case.  There is
+ * no need to fetch both the instruction and the data,
+ * only the data is needed.  In other words, a `cycle' begins
+ * by fetching the field data.  If that is non-0, then it must
+ * be the destination state of a next_char transition, so
+ * make that value the current state, advance the match position
+ * by one character, and start a new cycle.  On the other hand,
+ * if data is 0, fetch the instruction and do a more complicated
+ * dispatch on that.
+ */
+
+struct rx_inx 
+{
+  void * data;
+  void * data_2;
+  void * inx;
+  void * fnord;
+};
+
+#ifndef RX_TAIL_ARRAY
+#define RX_TAIL_ARRAY  1
+#endif
+
+/* A superstate corresponds to a set of nfa states.  Those sets are
+ * represented by STRUCT RX_SUPERSET.  The constructors
+ * guarantee that only one (shared) structure is created for a given set.
+ */
+struct rx_superset
+{
+  int refs;			/* This is a reference counted structure. */
+
+  /* We keep these sets in a cache because (in an unpredictable way),
+   * the same set is often created again and again.  But that is also
+   * problematic -- compatibility with POSIX and GNU regex requires
+   * that we not be able to tell when a program discards a particular
+   * NFA (thus invalidating the supersets created from it).
+   *
+   * But when a cache hit appears to occur, we will have in hand the
+   * nfa for which it may have happened.  That is why every nfa is given
+   * its own sequence number.  On a cache hit, the cache is validated
+   * by comparing the nfa sequence number to this field:
+   */
+  int id;
+
+  struct rx_nfa_state * car;	/* May or may not be a valid addr. */
+  struct rx_superset * cdr;
+
+  /* If the corresponding superstate exists: */
+  struct rx_superstate * superstate;
+
+
+  /* There is another bookkeeping problem.  It is expensive to 
+   * compute the starting nfa state set for an nfa.  So, once computed,
+   * it is cached in the `struct rx'.
+   *
+   * But, the state set can be flushed from the superstate cache.
+   * When that happens, we can't know if the corresponding `struct rx'
+   * is still alive or if it has been freed or re-used by the program.
+   * So, the cached pointer to this set in a struct rx might be invalid
+   * and we need a way to validate it.
+   *
+   * Fortunately, even if this set is flushed from the cache, it is
+   * not freed.  It just goes on the free-list of supersets.
+   * So we can still examine it.  
+   *
+   * So to validate a starting set memo, check to see if the
+   * starts_for field still points back to the struct rx in question,
+   * and if the ID matches the rx sequence number.
+   */
+  struct rx * starts_for;
+
+  /* This is used to link into a hash bucket so these objects can
+   * be `hash-consed'.
+   */
+  struct rx_hash_item hash_item;
+};
+
+#define rx_protect_superset(RX,CON) (++(CON)->refs)
+
+/* The terminology may be confusing (rename this structure?).
+ * Every character occurs in at most one rx_super_edge per super-state.
+ * But, that structure might have more than one option, indicating a point
+ * of non-determinism. 
+ *
+ * In other words, this structure holds a list of superstate edges
+ * sharing a common starting state and character label.  The edges
+ * are in the field OPTIONS.  All superstate edges sharing the same
+ * starting state and character are in this list.
+ */
+struct rx_super_edge
+{
+  struct rx_super_edge *next;
+  struct rx_inx rx_backtrack_frame;
+  int cset_size;
+  rx_Bitset cset;
+  struct rx_distinct_future *options;
+};
+
+/* A superstate is a set of nfa states (RX_SUPERSET) along
+ * with a transition table.  Superstates are built on demand and reclaimed
+ * without warning.  To protect a superstate from this ghastly fate,
+ * use LOCK_SUPERSTATE. 
+ */
+struct rx_superstate
+{
+  int rx_id;			/* c.f. the id field of rx_superset */
+  int locks;			/* protection from reclamation */
+
+  /* Within a superstate cache, all the superstates are kept in a big
+   * queue.  The tail of the queue is the state most likely to be
+   * reclaimed.  The *recyclable fields hold the queue position of 
+   * this state.
+   */
+  struct rx_superstate * next_recyclable;
+  struct rx_superstate * prev_recyclable;
+
+  /* The supernfa edges that exist in the cache and that have
+   * this state as their destination are kept in this list:
+   */
+  struct rx_distinct_future * transition_refs;
+
+  /* The list of nfa states corresponding to this superstate: */
+  struct rx_superset * contents;
+
+  /* The list of edges in the cache beginning from this state. */
+  struct rx_super_edge * edges;
+
+  /* A tail of the recyclable queue is marked as semifree.  A semifree
+   * state has no incoming next_char transitions -- any transition
+   * into a semifree state causes a complex dispatch with the side
+   * effect of rescuing the state from its semifree state.
+   *
+   * An alternative to this might be to make next_char more expensive,
+   * and to move a state to the head of the recyclable queue whenever
+   * it is entered.  That way, popular states would never be recycled.
+   *
+   * But unilaterally making next_char more expensive actually loses.
+   * So, incoming transitions are only made expensive for states near
+   * the tail of the recyclable queue.  The more cache contention
+   * there is, the more frequently a state will have to prove itself
+   * and be moved back to the front of the queue.  If there is less 
+   * contention, then popular states just aggregate in the front of 
+   * the queue and stay there.
+   */
+  int is_semifree;
+
+
+  /* This keeps track of the size of the transition table for this
+   * state.  There is a half-hearted attempt to support variable sized
+   * superstates.
+   */
+  int trans_size;
+
+  /* Indexed by characters... */
+  struct rx_inx transitions[RX_TAIL_ARRAY];
+};
+
+
+/* A list of distinct futures define the edges that leave from a 
+ * given superstate on a given character.  c.f. rx_super_edge.
+ */
+
+struct rx_distinct_future
+{
+  struct rx_distinct_future * next_same_super_edge[2];
+  struct rx_distinct_future * next_same_dest;
+  struct rx_distinct_future * prev_same_dest;
+  struct rx_superstate * present;	/* source state */
+  struct rx_superstate * future;	/* destination state */
+  struct rx_super_edge * edge;
+
+
+  /* The future_frame holds the instruction that should be executed
+   * after all the side effects are done, when it is time to complete
+   * the transition to the next state.
+   *
+   * Normally this is a next_char instruction, but it may be a
+   * cache_miss instruction as well, depending on whether or not
+   * the superstate is in the cache and semifree.
+   * 
+   * If this is the only future for a given superstate/char, and
+   * if there are no side effects to be performed, this frame is
+   * not used (directly) at all.  Instead, its contents are copied
+   * into the transition table of the starting state of this dist. future.
+   */
+  struct rx_inx future_frame;
+
+  struct rx_inx side_effects_frame;
+  struct rx_se_list * effects;
+};
+
+#define rx_lock_superstate(R,S)  ((S)->locks++)
+#define rx_unlock_superstate(R,S) (--(S)->locks)
+
+
+
+/* This page destined for rx.h */
+
+struct rx_blocklist
+{
+  struct rx_blocklist * next;
+  int bytes;
+};
+
+struct rx_freelist
+{
+  struct rx_freelist * next;
+};
+
+struct rx_cache;
+
+#ifdef __STDC__
+typedef void (*rx_morecore_fn)(struct rx_cache *);
+#else
+typedef void (*rx_morecore_fn)();
+#endif
+
+/* You use this to control the allocation of superstate data 
+ * during matching.  Most of it should be initialized to 0.
+ *
+ * A MORECORE function is necessary.  It should allocate
+ * a new block of memory or return 0.
+ * A default that uses malloc is called `rx_morecore'.
+ *
+ * The number of SUPERSTATES_ALLOWED indirectly limits how much memory
+ * the system will try to allocate.  The default is 128.  Batch style
+ * applications that are very regexp intensive should use as high a number
+ * as possible without thrashing.
+ * 
+ * The LOCAL_CSET_SIZE is the number of characters in a character set.
+ * It is therefore the number of entries in a superstate transition table.
+ * Generally, it should be 256.  If your character set has 16 bits, 
+ * it is better to translate your regexps into equivalent 8 bit patterns.
+ */
+
+struct rx_cache
+{
+  struct rx_hash_rules superset_hash_rules;
+
+  /* Objects are allocated by incrementing a pointer that 
+   * scans across rx_blocklists.
+   */
+  struct rx_blocklist * memory;
+  struct rx_blocklist * memory_pos;
+  int bytes_left;
+  char * memory_addr;
+  rx_morecore_fn morecore;
+
+  /* Freelists. */
+  struct rx_freelist * free_superstates;
+  struct rx_freelist * free_transition_classes;
+  struct rx_freelist * free_discernable_futures;
+  struct rx_freelist * free_supersets;
+  struct rx_freelist * free_hash;
+
+  /* Two sets of superstates -- those that are semifreed, and those
+   * that are being used.
+   */
+  struct rx_superstate * lru_superstate;
+  struct rx_superstate * semifree_superstate;
+
+  struct rx_superset * empty_superset;
+
+  int superstates;
+  int semifree_superstates;
+  int hits;
+  int misses;
+  int superstates_allowed;
+
+  int local_cset_size;
+  void ** instruction_table;
+
+  struct rx_hash superset_table;
+};
+
+
+
+
+/* The lowest-level search function supports arbitrarily fragmented
+ * strings and (optionally) suspendable/resumable searches.
+ *
+ * Callers have to provide a few hooks.
+ */
+
+#ifndef __GNUC__
+#ifdef __STDC__
+#define __const__ const
+#else
+#define __const__
+#endif
+#endif
+
+/* This holds a matcher position */
+struct rx_string_position
+{
+  __const__ unsigned char * pos;	/* The current pos. */
+  __const__ unsigned char * string; /* The current string burst. */
+  __const__ unsigned char * end;	/* First invalid position >= POS. */
+  int offset;			/* Integer address of the current burst. */
+  int size;			/* Current string's size. */
+  int search_direction;		/* 1 or -1 */
+  int search_end;		/* First position to not try. */
+};
+
+
+enum rx_get_burst_return
+{
+  rx_get_burst_continuation,
+  rx_get_burst_error,
+  rx_get_burst_ok,
+  rx_get_burst_no_more
+};
+
+
+/* A call to get burst should make POS valid.  It might be invalid
+ * if the STRING field doesn't point to a burst that actually
+ * contains POS.
+ *
+ * GET_BURST should take a clue from SEARCH_DIRECTION (1 or -1) as to
+ * whether or not to pad to the left.  Padding to the right is always
+ * appropriate, but need not go past the point indicated by STOP.
+ *
+ * If a continuation is returned, then the reentering call to
+ * a search function will retry the get_burst.
+ */
+
+#ifdef __STDC__
+typedef enum rx_get_burst_return
+  (*rx_get_burst_fn) (struct rx_string_position * pos,
+		      void * app_closure,
+		      int stop);
+					       
+#else
+typedef enum rx_get_burst_return (*rx_get_burst_fn) ();
+#endif
+
+
+enum rx_back_check_return
+{
+  rx_back_check_continuation,
+  rx_back_check_error,
+  rx_back_check_pass,
+  rx_back_check_fail
+};
+
+/* Back_check should advance the position it is passed 
+ * over rparen - lparen characters and return pass iff
+ * the characters starting at POS match those indexed
+ * by [LPAREN..RPAREN].
+ *
+ * If a continuation is returned, then the reentering call to
+ * a search function will retry the back_check.
+ */
+
+#ifdef __STDC__
+typedef enum rx_back_check_return
+  (*rx_back_check_fn) (struct rx_string_position * pos,
+		       int lparen,
+		       int rparen,
+		       unsigned char * translate,
+		       void * app_closure,
+		       int stop);
+					       
+#else
+typedef enum rx_back_check_return (*rx_back_check_fn) ();
+#endif
+
+
+
+
+/* A call to fetch_char should return the character at POS or POS + 1.
+ * Returning continuations here isn't supported.  OFFSET is either 0 or 1
+ * and indicates which characters is desired.
+ */
+
+#ifdef __STDC__
+typedef int (*rx_fetch_char_fn) (struct rx_string_position * pos,
+				 int offset,
+				 void * app_closure,
+				 int stop);
+#else
+typedef int (*rx_fetch_char_fn) ();
+#endif
+
+
+enum rx_search_return
+{
+  rx_search_continuation = -4,
+  rx_search_error = -3,
+  rx_search_soft_fail = -2,	/* failed by running out of string */
+  rx_search_fail = -1		/* failed only by reaching failure states */
+  /* return values >= 0 indicate the position of a successful match */
+};
+
+
+
+
+
+
+
+/* regex.h
+ * 
+ * The remaining declarations replace regex.h.
+ */
+
+/* This is an array of error messages corresponding to the error codes.
+ */
+extern __const__ char *re_error_msg[];
+
+/* If any error codes are removed, changed, or added, update the
+   `re_error_msg' table in regex.c.  */
+typedef enum
+{
+  REG_NOERROR = 0,	/* Success.  */
+  REG_NOMATCH,		/* Didn't find a match (for regexec).  */
+
+  /* POSIX regcomp return error codes.  (In the order listed in the
+     standard.)  */
+  REG_BADPAT,		/* Invalid pattern.  */
+  REG_ECOLLATE,		/* Not implemented.  */
+  REG_ECTYPE,		/* Invalid character class name.  */
+  REG_EESCAPE,		/* Trailing backslash.  */
+  REG_ESUBREG,		/* Invalid back reference.  */
+  REG_EBRACK,		/* Unmatched left bracket.  */
+  REG_EPAREN,		/* Parenthesis imbalance.  */ 
+  REG_EBRACE,		/* Unmatched \{.  */
+  REG_BADBR,		/* Invalid contents of \{\}.  */
+  REG_ERANGE,		/* Invalid range end.  */
+  REG_ESPACE,		/* Ran out of memory.  */
+  REG_BADRPT,		/* No preceding re for repetition op.  */
+
+  /* Error codes we've added.  */
+  REG_EEND,		/* Premature end.  */
+  REG_ESIZE,		/* Compiled pattern bigger than 2^16 bytes.  */
+  REG_ERPAREN		/* Unmatched ) or \); not returned from regcomp.  */
+} reg_errcode_t;
+
+/* The regex.c support, as a client of rx, defines a set of possible
+ * side effects that can be added to the edge lables of nfa edges.
+ * Here is the list of sidef effects in use.
+ */
+
+enum re_side_effects
+{
+#define RX_WANT_SE_DEFS 1
+#undef RX_DEF_SE
+#undef RX_DEF_CPLX_SE
+#define RX_DEF_SE(IDEM, NAME, VALUE)	      NAME VALUE,
+#define RX_DEF_CPLX_SE(IDEM, NAME, VALUE)     NAME VALUE,
+#include "rx.h"
+#undef RX_DEF_SE
+#undef RX_DEF_CPLX_SE
+#undef RX_WANT_SE_DEFS
+   re_floogle_flap = 65533
+};
+
+/* These hold paramaters for the kinds of side effects that are possible
+ * in the supported pattern languages.  These include things like the 
+ * numeric bounds of {} operators and the index of paren registers for 
+ * subexpression measurement or backreferencing.
+ */
+struct re_se_params
+{
+  enum re_side_effects se;
+  int op1;
+  int op2;
+};
+
+typedef unsigned reg_syntax_t;
+
+struct re_pattern_buffer
+{
+  struct rx rx;
+  reg_syntax_t syntax;		/* See below for syntax bit definitions. */
+
+  unsigned int no_sub:1;	/* If set, don't  return register offsets. */
+  unsigned int not_bol:1;	/* If set, the anchors ('^' and '$') don't */
+  unsigned int not_eol:1;	/*     match at the ends of the string.  */  
+  unsigned int newline_anchor:1;/* If true, an anchor at a newline matches.*/
+  unsigned int least_subs:1;	/* If set, and returning registers, return
+				 * as few values as possible.  Only 
+				 * backreferenced groups and group 0 (the whole
+				 * match) will be returned.
+				 */
+
+  /* If true, this says that the matcher should keep registers on its
+   * backtracking stack.  For many patterns, we can easily determine that
+   * this isn't necessary.
+   */
+  unsigned int match_regs_on_stack:1;
+  unsigned int search_regs_on_stack:1;
+
+  /* is_anchored and begbuf_only are filled in by rx_compile. */
+  unsigned int is_anchored:1;	/* Anchorded by ^? */
+  unsigned int begbuf_only:1;	/* Anchored to char position 0? */
+
+  
+  /* If REGS_UNALLOCATED, allocate space in the `regs' structure
+   * for `max (RE_NREGS, re_nsub + 1)' groups.
+   * If REGS_REALLOCATE, reallocate space if necessary.
+   * If REGS_FIXED, use what's there.  
+   */
+#define REGS_UNALLOCATED 0
+#define REGS_REALLOCATE 1
+#define REGS_FIXED 2
+  unsigned int regs_allocated:2;
+
+  
+  /* Either a translate table to apply to all characters before
+   * comparing them, or zero for no translation.  The translation
+   * is applied to a pattern when it is compiled and to a string
+   * when it is matched.
+   */
+  unsigned char * translate;
+
+  /* If this is a valid pointer, it tells rx not to store the extents of 
+   * certain subexpressions (those corresponding to non-zero entries).
+   * Passing 0x1 is the same as passing an array of all ones.  Passing 0x0
+   * is the same as passing an array of all zeros.
+   * The array should contain as many entries as their are subexps in the 
+   * regexp.
+   *
+   * For POSIX compatability, when using regcomp and regexec this field
+   * is zeroed and ignored.
+   */
+  char * syntax_parens;
+
+	/* Number of subexpressions found by the compiler.  */
+  size_t re_nsub;
+
+  void * buffer;		/* Malloced memory for the nfa. */
+  unsigned long allocated;	/* Size of that memory. */
+
+  /* Pointer to a fastmap, if any, otherwise zero.  re_search uses
+   * the fastmap, if there is one, to skip over impossible
+   * starting points for matches.  */
+  char *fastmap;
+
+  unsigned int fastmap_accurate:1; /* These three are internal. */
+  unsigned int can_match_empty:1;  
+  struct rx_nfa_state * start;	/* The nfa starting state. */
+
+  /* This is the list of iterator bounds for {lo,hi} constructs.
+   * The memory pointed to is part of the rx->buffer.
+   */
+  struct re_se_params *se_params;
+
+  /* This is a bitset representation of the fastmap.
+   * This is a true fastmap that already takes the translate
+   * table into account.
+   */
+  rx_Bitset fastset;
+};
+
+/* Type for byte offsets within the string.  POSIX mandates this.  */
+typedef int regoff_t;
+
+/* This is the structure we store register match data in.  See
+   regex.texinfo for a full description of what registers match.  */
+struct re_registers
+{
+  unsigned num_regs;
+  regoff_t *start;
+  regoff_t *end;
+};
+
+typedef struct re_pattern_buffer regex_t;
+
+/* POSIX specification for registers.  Aside from the different names than
+   `re_registers', POSIX uses an array of structures, instead of a
+   structure of arrays.  */
+typedef struct
+{
+  regoff_t rm_so;  /* Byte offset from string's start to substring's start.  */
+  regoff_t rm_eo;  /* Byte offset from string's start to substring's end.  */
+} regmatch_t;
+
+
+
+/* The following bits are used to determine the regexp syntax we
+   recognize.  The set/not-set meanings are chosen so that Emacs syntax
+   remains the value 0.  The bits are given in alphabetical order, and
+   the definitions shifted by one from the previous bit; thus, when we
+   add or remove a bit, only one other definition need change.  */
+
+/* If this bit is not set, then \ inside a bracket expression is literal.
+   If set, then such a \ quotes the following character.  */
+#define RE_BACKSLASH_ESCAPE_IN_LISTS (1)
+
+/* If this bit is not set, then + and ? are operators, and \+ and \? are
+     literals. 
+   If set, then \+ and \? are operators and + and ? are literals.  */
+#define RE_BK_PLUS_QM (RE_BACKSLASH_ESCAPE_IN_LISTS << 1)
+
+/* If this bit is set, then character classes are supported.  They are:
+     [:alpha:], [:upper:], [:lower:],  [:digit:], [:alnum:], [:xdigit:],
+     [:space:], [:print:], [:punct:], [:graph:], and [:cntrl:].
+   If not set, then character classes are not supported.  */
+#define RE_CHAR_CLASSES (RE_BK_PLUS_QM << 1)
+
+/* If this bit is set, then ^ and $ are always anchors (outside bracket
+     expressions, of course).
+   If this bit is not set, then it depends:
+        ^  is an anchor if it is at the beginning of a regular
+           expression or after an open-group or an alternation operator;
+        $  is an anchor if it is at the end of a regular expression, or
+           before a close-group or an alternation operator.  
+
+   This bit could be (re)combined with RE_CONTEXT_INDEP_OPS, because
+   POSIX draft 11.2 says that * etc. in leading positions is undefined.
+   We already implemented a previous draft which made those constructs
+   invalid, though, so we haven't changed the code back.  */
+#define RE_CONTEXT_INDEP_ANCHORS (RE_CHAR_CLASSES << 1)
+
+/* If this bit is set, then special characters are always special
+     regardless of where they are in the pattern.
+   If this bit is not set, then special characters are special only in
+     some contexts; otherwise they are ordinary.  Specifically, 
+     * + ? and intervals are only special when not after the beginning,
+     open-group, or alternation operator.  */
+#define RE_CONTEXT_INDEP_OPS (RE_CONTEXT_INDEP_ANCHORS << 1)
+
+/* If this bit is set, then *, +, ?, and { cannot be first in an re or
+     immediately after an alternation or begin-group operator.  */
+#define RE_CONTEXT_INVALID_OPS (RE_CONTEXT_INDEP_OPS << 1)
+
+/* If this bit is set, then . matches newline.
+   If not set, then it doesn't.  */
+#define RE_DOT_NEWLINE (RE_CONTEXT_INVALID_OPS << 1)
+
+/* If this bit is set, then . doesn't match NUL.
+   If not set, then it does.  */
+#define RE_DOT_NOT_NULL (RE_DOT_NEWLINE << 1)
+
+/* If this bit is set, nonmatching lists [^...] do not match newline.
+   If not set, they do.  */
+#define RE_HAT_LISTS_NOT_NEWLINE (RE_DOT_NOT_NULL << 1)
+
+/* If this bit is set, either \{...\} or {...} defines an
+     interval, depending on RE_NO_BK_BRACES. 
+   If not set, \{, \}, {, and } are literals.  */
+#define RE_INTERVALS (RE_HAT_LISTS_NOT_NEWLINE << 1)
+
+/* If this bit is set, +, ? and | aren't recognized as operators.
+   If not set, they are.  */
+#define RE_LIMITED_OPS (RE_INTERVALS << 1)
+
+/* If this bit is set, newline is an alternation operator.
+   If not set, newline is literal.  */
+#define RE_NEWLINE_ALT (RE_LIMITED_OPS << 1)
+
+/* If this bit is set, then `{...}' defines an interval, and \{ and \}
+     are literals.
+  If not set, then `\{...\}' defines an interval.  */
+#define RE_NO_BK_BRACES (RE_NEWLINE_ALT << 1)
+
+/* If this bit is set, (...) defines a group, and \( and \) are literals.
+   If not set, \(...\) defines a group, and ( and ) are literals.  */
+#define RE_NO_BK_PARENS (RE_NO_BK_BRACES << 1)
+
+/* If this bit is set, then \<digit> matches <digit>.
+   If not set, then \<digit> is a back-reference.  */
+#define RE_NO_BK_REFS (RE_NO_BK_PARENS << 1)
+
+/* If this bit is set, then | is an alternation operator, and \| is literal. 
+   If not set, then \| is an alternation operator, and | is literal.  */
+#define RE_NO_BK_VBAR (RE_NO_BK_REFS << 1)
+
+/* If this bit is set, then an ending range point collating higher
+     than the starting range point, as in [z-a], is invalid.
+   If not set, then when ending range point collates higher than the
+     starting range point, the range is ignored.  */
+#define RE_NO_EMPTY_RANGES (RE_NO_BK_VBAR << 1)
+
+/* If this bit is set, then an unmatched ) is ordinary.
+   If not set, then an unmatched ) is invalid.  */
+#define RE_UNMATCHED_RIGHT_PAREN_ORD (RE_NO_EMPTY_RANGES << 1)
+
+/* This global variable defines the particular regexp syntax to use (for
+   some interfaces).  When a regexp is compiled, the syntax used is
+   stored in the pattern buffer, so changing this does not affect
+   already-compiled regexps.  */
+extern reg_syntax_t re_syntax_options;
+
+
+/* Define combinations of the above bits for the standard possibilities.
+   (The [[[ comments delimit what gets put into the Texinfo file, so
+   don't delete them!)  */ 
+/* [[[begin syntaxes]]] */
+#define RE_SYNTAX_EMACS 0
+
+#define RE_SYNTAX_AWK							\
+  (RE_BACKSLASH_ESCAPE_IN_LISTS | RE_DOT_NOT_NULL			\
+   | RE_NO_BK_PARENS            | RE_NO_BK_REFS				\
+   | RE_NO_BK_VAR               | RE_NO_EMPTY_RANGES			\
+   | RE_UNMATCHED_RIGHT_PAREN_ORD)
+
+#define RE_SYNTAX_POSIX_AWK 						\
+  (RE_SYNTAX_POSIX_EXTENDED | RE_BACKSLASH_ESCAPE_IN_LISTS)
+
+#define RE_SYNTAX_GREP							\
+  (RE_BK_PLUS_QM              | RE_CHAR_CLASSES				\
+   | RE_HAT_LISTS_NOT_NEWLINE | RE_INTERVALS				\
+   | RE_NEWLINE_ALT)
+
+#define RE_SYNTAX_EGREP							\
+  (RE_CHAR_CLASSES        | RE_CONTEXT_INDEP_ANCHORS			\
+   | RE_CONTEXT_INDEP_OPS | RE_HAT_LISTS_NOT_NEWLINE			\
+   | RE_NEWLINE_ALT       | RE_NO_BK_PARENS				\
+   | RE_NO_BK_VBAR)
+
+#define RE_SYNTAX_POSIX_EGREP						\
+  (RE_SYNTAX_EGREP | RE_INTERVALS | RE_NO_BK_BRACES)
+
+#define RE_SYNTAX_SED RE_SYNTAX_POSIX_BASIC
+
+/* Syntax bits common to both basic and extended POSIX regex syntax.  */
+#define _RE_SYNTAX_POSIX_COMMON						\
+  (RE_CHAR_CLASSES | RE_DOT_NEWLINE      | RE_DOT_NOT_NULL		\
+   | RE_INTERVALS  | RE_NO_EMPTY_RANGES)
+
+#define RE_SYNTAX_POSIX_BASIC						\
+  (_RE_SYNTAX_POSIX_COMMON | RE_BK_PLUS_QM)
+
+/* Differs from ..._POSIX_BASIC only in that RE_BK_PLUS_QM becomes
+   RE_LIMITED_OPS, i.e., \? \+ \| are not recognized.  Actually, this
+   isn't minimal, since other operators, such as \`, aren't disabled.  */
+#define RE_SYNTAX_POSIX_MINIMAL_BASIC					\
+  (_RE_SYNTAX_POSIX_COMMON | RE_LIMITED_OPS)
+
+#define RE_SYNTAX_POSIX_EXTENDED					\
+  (_RE_SYNTAX_POSIX_COMMON | RE_CONTEXT_INDEP_ANCHORS			\
+   | RE_CONTEXT_INDEP_OPS  | RE_NO_BK_BRACES				\
+   | RE_NO_BK_PARENS       | RE_NO_BK_VBAR				\
+   | RE_UNMATCHED_RIGHT_PAREN_ORD)
+
+/* Differs from ..._POSIX_EXTENDED in that RE_CONTEXT_INVALID_OPS
+   replaces RE_CONTEXT_INDEP_OPS and RE_NO_BK_REFS is added.  */
+#define RE_SYNTAX_POSIX_MINIMAL_EXTENDED				\
+  (_RE_SYNTAX_POSIX_COMMON  | RE_CONTEXT_INDEP_ANCHORS			\
+   | RE_CONTEXT_INVALID_OPS | RE_NO_BK_BRACES				\
+   | RE_NO_BK_PARENS        | RE_NO_BK_REFS				\
+   | RE_NO_BK_VBAR	    | RE_UNMATCHED_RIGHT_PAREN_ORD)
+/* [[[end syntaxes]]] */
+
+/* Maximum number of duplicates an interval can allow.  Some systems
+   (erroneously) define this in other header files, but we want our
+   value, so remove any previous define.  */
+#ifdef RE_DUP_MAX
+#undef RE_DUP_MAX
+#endif
+#define RE_DUP_MAX ((1 << 15) - 1) 
+
+
+
+/* POSIX `cflags' bits (i.e., information for `regcomp').  */
+
+/* If this bit is set, then use extended regular expression syntax.
+   If not set, then use basic regular expression syntax.  */
+#define REG_EXTENDED 1
+
+/* If this bit is set, then ignore case when matching.
+   If not set, then case is significant.  */
+#define REG_ICASE (REG_EXTENDED << 1)
+ 
+/* If this bit is set, then anchors do not match at newline
+     characters in the string.
+   If not set, then anchors do match at newlines.  */
+#define REG_NEWLINE (REG_ICASE << 1)
+
+/* If this bit is set, then report only success or fail in regexec.
+   If not set, then returns differ between not matching and errors.  */
+#define REG_NOSUB (REG_NEWLINE << 1)
+
+
+/* POSIX `eflags' bits (i.e., information for regexec).  */
+
+/* If this bit is set, then the beginning-of-line operator doesn't match
+     the beginning of the string (presumably because it's not the
+     beginning of a line).
+   If not set, then the beginning-of-line operator does match the
+     beginning of the string.  */
+#define REG_NOTBOL 1
+
+/* Like REG_NOTBOL, except for the end-of-line.  */
+#define REG_NOTEOL (1 << 1)
+
+/* If `regs_allocated' is REGS_UNALLOCATED in the pattern buffer,
+ * `re_match_2' returns information about at least this many registers
+ * the first time a `regs' structure is passed. 
+ *
+ * Also, this is the greatest number of backreferenced subexpressions
+ * allowed in a pattern being matched without caller-supplied registers.
+ */
+#ifndef RE_NREGS
+#define RE_NREGS 30
+#endif
+
+extern int rx_cache_bound;
+extern char rx_version_string[];
+
+
+
+
+#ifdef RX_WANT_RX_DEFS
+
+/* This is decls to the interesting subsystems and lower layers
+ * of rx.  Everything which doesn't have a public counterpart in 
+ * regex.c is declared here.
+ */
+
+
+#ifdef __STDC__
+typedef void (*rx_hash_freefn) (struct rx_hash_item * it);
+#else /* ndef __STDC__ */
+typedef void (*rx_hash_freefn) ();
+#endif /* ndef __STDC__ */
+
+
+
+
+
+#ifdef __STDC__
+RX_DECL int rx_bitset_is_equal (int size, rx_Bitset a, rx_Bitset b);
+RX_DECL int rx_bitset_is_subset (int size, rx_Bitset a, rx_Bitset b);
+RX_DECL int rx_bitset_empty (int size, rx_Bitset set);
+RX_DECL void rx_bitset_null (int size, rx_Bitset b);
+RX_DECL void rx_bitset_universe (int size, rx_Bitset b);
+RX_DECL void rx_bitset_complement (int size, rx_Bitset b);
+RX_DECL void rx_bitset_assign (int size, rx_Bitset a, rx_Bitset b);
+RX_DECL void rx_bitset_union (int size, rx_Bitset a, rx_Bitset b);
+RX_DECL void rx_bitset_intersection (int size,
+				     rx_Bitset a, rx_Bitset b);
+RX_DECL void rx_bitset_difference (int size, rx_Bitset a, rx_Bitset b);
+RX_DECL void rx_bitset_revdifference (int size,
+				      rx_Bitset a, rx_Bitset b);
+RX_DECL void rx_bitset_xor (int size, rx_Bitset a, rx_Bitset b);
+RX_DECL unsigned long rx_bitset_hash (int size, rx_Bitset b);
+RX_DECL struct rx_hash_item * rx_hash_find (struct rx_hash * table,
+					    unsigned long hash,
+					    void * value,
+					    struct rx_hash_rules * rules);
+RX_DECL struct rx_hash_item * rx_hash_store (struct rx_hash * table,
+					     unsigned long hash,
+					     void * value,
+					     struct rx_hash_rules * rules);
+RX_DECL void rx_hash_free (struct rx_hash_item * it, struct rx_hash_rules * rules);
+RX_DECL void rx_free_hash_table (struct rx_hash * tab, rx_hash_freefn freefn,
+				 struct rx_hash_rules * rules);
+RX_DECL rx_Bitset rx_cset (struct rx *rx);
+RX_DECL rx_Bitset rx_copy_cset (struct rx *rx, rx_Bitset a);
+RX_DECL void rx_free_cset (struct rx * rx, rx_Bitset c);
+RX_DECL struct rexp_node * rexp_node (struct rx *rx,
+				      enum rexp_node_type type);
+RX_DECL struct rexp_node * rx_mk_r_cset (struct rx * rx,
+					 rx_Bitset b);
+RX_DECL struct rexp_node * rx_mk_r_concat (struct rx * rx,
+					   struct rexp_node * a,
+					   struct rexp_node * b);
+RX_DECL struct rexp_node * rx_mk_r_alternate (struct rx * rx,
+					      struct rexp_node * a,
+					      struct rexp_node * b);
+RX_DECL struct rexp_node * rx_mk_r_opt (struct rx * rx,
+					struct rexp_node * a);
+RX_DECL struct rexp_node * rx_mk_r_star (struct rx * rx,
+					 struct rexp_node * a);
+RX_DECL struct rexp_node * rx_mk_r_2phase_star (struct rx * rx,
+						struct rexp_node * a,
+						struct rexp_node * b);
+RX_DECL struct rexp_node * rx_mk_r_side_effect (struct rx * rx,
+						rx_side_effect a);
+RX_DECL struct rexp_node * rx_mk_r_data  (struct rx * rx,
+					  void * a);
+RX_DECL void rx_free_rexp (struct rx * rx, struct rexp_node * node);
+RX_DECL struct rexp_node * rx_copy_rexp (struct rx *rx,
+					 struct rexp_node *node);
+RX_DECL struct rx_nfa_state * rx_nfa_state (struct rx *rx);
+RX_DECL void rx_free_nfa_state (struct rx_nfa_state * n);
+RX_DECL struct rx_nfa_state * rx_id_to_nfa_state (struct rx * rx,
+						  int id);
+RX_DECL struct rx_nfa_edge * rx_nfa_edge (struct rx *rx,
+					  enum rx_nfa_etype type,
+					  struct rx_nfa_state *start,
+					  struct rx_nfa_state *dest);
+RX_DECL void rx_free_nfa_edge (struct rx_nfa_edge * e);
+RX_DECL void rx_free_nfa (struct rx *rx);
+RX_DECL int rx_build_nfa (struct rx *rx,
+			  struct rexp_node *rexp,
+			  struct rx_nfa_state **start,
+			  struct rx_nfa_state **end);
+RX_DECL void rx_name_nfa_states (struct rx *rx);
+RX_DECL int rx_eclose_nfa (struct rx *rx);
+RX_DECL void rx_delete_epsilon_transitions (struct rx *rx);
+RX_DECL int rx_compactify_nfa (struct rx *rx,
+			       void **mem, unsigned long *size);
+RX_DECL void rx_release_superset (struct rx *rx,
+				  struct rx_superset *set);
+RX_DECL struct rx_superset * rx_superset_cons (struct rx * rx,
+					       struct rx_nfa_state *car, struct rx_superset *cdr);
+RX_DECL struct rx_superset * rx_superstate_eclosure_union
+  (struct rx * rx, struct rx_superset *set, struct rx_nfa_state_set *ecl);
+RX_DECL struct rx_superstate * rx_superstate (struct rx *rx,
+					      struct rx_superset *set);
+RX_DECL struct rx_inx * rx_handle_cache_miss
+  (struct rx *rx, struct rx_superstate *super, unsigned char chr, void *data);
+RX_DECL reg_errcode_t rx_compile (__const__ char *pattern, int size,
+				  reg_syntax_t syntax,
+				  struct re_pattern_buffer * rxb);
+RX_DECL void rx_blow_up_fastmap (struct re_pattern_buffer * rxb);
+#else /* STDC */
+RX_DECL int rx_bitset_is_equal ();
+RX_DECL int rx_bitset_is_subset ();
+RX_DECL int rx_bitset_empty ();
+RX_DECL void rx_bitset_null ();
+RX_DECL void rx_bitset_universe ();
+RX_DECL void rx_bitset_complement ();
+RX_DECL void rx_bitset_assign ();
+RX_DECL void rx_bitset_union ();
+RX_DECL void rx_bitset_intersection ();
+RX_DECL void rx_bitset_difference ();
+RX_DECL void rx_bitset_revdifference ();
+RX_DECL void rx_bitset_xor ();
+RX_DECL unsigned long rx_bitset_hash ();
+RX_DECL struct rx_hash_item * rx_hash_find ();
+RX_DECL struct rx_hash_item * rx_hash_store ();
+RX_DECL void rx_hash_free ();
+RX_DECL void rx_free_hash_table ();
+RX_DECL rx_Bitset rx_cset ();
+RX_DECL rx_Bitset rx_copy_cset ();
+RX_DECL void rx_free_cset ();
+RX_DECL struct rexp_node * rexp_node ();
+RX_DECL struct rexp_node * rx_mk_r_cset ();
+RX_DECL struct rexp_node * rx_mk_r_concat ();
+RX_DECL struct rexp_node * rx_mk_r_alternate ();
+RX_DECL struct rexp_node * rx_mk_r_opt ();
+RX_DECL struct rexp_node * rx_mk_r_star ();
+RX_DECL struct rexp_node * rx_mk_r_2phase_star ();
+RX_DECL struct rexp_node * rx_mk_r_side_effect ();
+RX_DECL struct rexp_node * rx_mk_r_data  ();
+RX_DECL void rx_free_rexp ();
+RX_DECL struct rexp_node * rx_copy_rexp ();
+RX_DECL struct rx_nfa_state * rx_nfa_state ();
+RX_DECL void rx_free_nfa_state ();
+RX_DECL struct rx_nfa_state * rx_id_to_nfa_state ();
+RX_DECL struct rx_nfa_edge * rx_nfa_edge ();
+RX_DECL void rx_free_nfa_edge ();
+RX_DECL void rx_free_nfa ();
+RX_DECL int rx_build_nfa ();
+RX_DECL void rx_name_nfa_states ();
+RX_DECL int rx_eclose_nfa ();
+RX_DECL void rx_delete_epsilon_transitions ();
+RX_DECL int rx_compactify_nfa ();
+RX_DECL void rx_release_superset ();
+RX_DECL struct rx_superset * rx_superset_cons ();
+RX_DECL struct rx_superset * rx_superstate_eclosure_union ();
+RX_DECL struct rx_superstate * rx_superstate ();
+RX_DECL struct rx_inx * rx_handle_cache_miss ();
+RX_DECL reg_errcode_t rx_compile ();
+RX_DECL void rx_blow_up_fastmap ();
+#endif /* STDC */
+
+
+#endif /* RX_WANT_RX_DEFS */
+
+
+
+
+#ifdef __STDC__
+extern int re_search_2 (struct re_pattern_buffer *rxb,
+			__const__ char * string1, int size1,
+			__const__ char * string2, int size2,
+			int startpos, int range,
+			struct re_registers *regs,
+			int stop);
+extern int re_search (struct re_pattern_buffer * rxb, __const__ char *string,
+		      int size, int startpos, int range,
+		      struct re_registers *regs);
+extern int re_match_2 (struct re_pattern_buffer * rxb,
+		       __const__ char * string1, int size1,
+		       __const__ char * string2, int size2,
+		       int pos, struct re_registers *regs, int stop);
+extern int re_match (struct re_pattern_buffer * rxb,
+		     __const__ char * string,
+		     int size, int pos,
+		     struct re_registers *regs);
+extern reg_syntax_t re_set_syntax (reg_syntax_t syntax);
+extern void re_set_registers (struct re_pattern_buffer *bufp,
+			      struct re_registers *regs,
+			      unsigned num_regs,
+			      regoff_t * starts, regoff_t * ends);
+extern __const__ char * re_compile_pattern (__const__ char *pattern,
+					int length,
+					struct re_pattern_buffer * rxb);
+extern int re_compile_fastmap (struct re_pattern_buffer * rxb);
+extern char * re_comp (__const__ char *s);
+extern int re_exec (__const__ char *s);
+extern int regcomp (regex_t * preg, __const__ char * pattern, int cflags);
+extern int regexec (__const__ regex_t *preg, __const__ char *string,
+		    size_t nmatch, regmatch_t pmatch[],
+		    int eflags);
+extern size_t regerror (int errcode, __const__ regex_t *preg,
+			char *errbuf, size_t errbuf_size);
+extern void regfree (regex_t *preg);
+
+#else /* STDC */
+extern int re_search_2 ();
+extern int re_search ();
+extern int re_match_2 ();
+extern int re_match ();
+extern reg_syntax_t re_set_syntax ();
+extern void re_set_registers ();
+extern __const__ char * re_compile_pattern ();
+extern int re_compile_fastmap ();
+extern char * re_comp ();
+extern int re_exec ();
+extern int regcomp ();
+extern int regexec ();
+extern size_t regerror ();
+extern void regfree ();
+
+#endif /* STDC */
+
+
+
+
+#ifdef RX_WANT_RX_DEFS
+
+struct rx_counter_frame
+{
+  int tag;
+  int val;
+  struct rx_counter_frame * inherited_from; /* If this is a copy. */
+  struct rx_counter_frame * cdr;
+};
+
+struct rx_backtrack_frame
+{
+  char * counter_stack_sp;
+
+  /* A frame is used to save the matchers state when it crosses a 
+   * backtracking point.  The `stk_' fields correspond to variables
+   * in re_search_2 (just strip off thes `stk_').  They are documented
+   * tere.
+   */
+  struct rx_superstate * stk_super;
+  unsigned int stk_c;
+  struct rx_string_position stk_test_pos;
+  int stk_last_l;
+  int stk_last_r;
+  int stk_test_ret;
+
+  /* This is the list of options left to explore at the backtrack
+   * point for which this frame was created. 
+   */
+  struct rx_distinct_future * df;
+  struct rx_distinct_future * first_df;
+
+#ifdef RX_DEBUG
+   int stk_line_no;
+#endif
+};
+
+struct rx_stack_chunk
+{
+  struct rx_stack_chunk * next_chunk;
+  int bytes_left;
+  char * sp;
+};
+
+enum rx_outer_entry
+{
+  rx_outer_start,
+  rx_outer_fastmap,
+  rx_outer_test,
+  rx_outer_restore_pos
+};
+
+enum rx_fastmap_return
+{
+  rx_fastmap_continuation,
+  rx_fastmap_error,
+  rx_fastmap_ok,
+  rx_fastmap_fail
+};
+
+enum rx_fastmap_entry
+{
+  rx_fastmap_start,
+  rx_fastmap_string_break
+};
+
+enum rx_test_return
+{
+  rx_test_continuation,
+  rx_test_error,
+  rx_test_fail,
+  rx_test_ok
+};
+
+enum rx_test_internal_return
+{
+  rx_test_internal_error,
+  rx_test_found_first,
+  rx_test_line_finished
+};
+
+enum rx_test_match_entry
+{
+  rx_test_start,
+  rx_test_cache_hit_loop,
+  rx_test_backreference_check,
+  rx_test_backtrack_return
+};
+
+struct rx_search_state
+{
+  /* Two groups of registers are kept.  The group with the register state
+   * of the current test match, and the group that holds the state at the end
+   * of the best known match, if any.
+   *
+   * For some patterns, there may also be registers saved on the stack.
+   */
+  unsigned num_regs;		/* Includes an element for register zero. */
+  regoff_t * lparen;		/* scratch space for register returns */
+  regoff_t * rparen;
+  regoff_t * best_lpspace;	/* in case the user doesn't want these */
+  regoff_t * best_rpspace;	/* values, we still need space to store
+				 * them.  Normally, this memoryis unused
+				 * and the space pointed to by REGS is 
+				 * used instead.
+				 */
+  
+  int last_l;			/* Highest index of a valid lparen. */
+  int last_r;			/* It's dual. */
+  
+  int * best_lparen;		/* This contains the best known register */
+  int * best_rparen;		/* assignments. 
+				 * This may point to the same mem as
+				 * best_lpspace, or it might point to memory
+				 * passed by the caller.
+				 */
+  int best_last_l;		/* best_last_l:best_lparen::last_l:lparen */
+  int best_last_r;
+
+
+  unsigned char * translate;  
+
+  struct rx_string_position outer_pos;
+
+  struct rx_superstate * start_super;
+  int nfa_choice;
+  int first_found;		/* If true, return after finding any match. */
+  int ret_val;
+
+  /* For continuations... */
+  enum rx_outer_entry outer_search_resume_pt;
+  struct re_pattern_buffer * saved_rxb;
+  int saved_startpos;
+  int saved_range;
+  int saved_stop;
+  int saved_total_size;
+  rx_get_burst_fn saved_get_burst;
+  rx_back_check_fn saved_back_check;
+  struct re_registers * saved_regs;
+  
+  /**
+   ** state for fastmap
+   **/
+  char * fastmap;
+  int fastmap_chr;
+  int fastmap_val;
+
+  /* for continuations in the fastmap procedure: */
+  enum rx_fastmap_entry fastmap_resume_pt;
+
+  /**
+   ** state for test_match 
+   **/
+
+  /* The current superNFA position of the matcher. */
+  struct rx_superstate * super;
+  
+  /* The matcher interprets a series of instruction frames.
+   * This is the `instruction counter' for the interpretation.
+   */
+  struct rx_inx * ifr;
+  
+  /* We insert a ghost character in the string to prime
+   * the nfa.  test_pos.pos, test_pos.str_half, and test_pos.end_half
+   * keep track of the test-match position and string-half.
+   */
+  unsigned char c;
+  
+  /* Position within the string. */
+  struct rx_string_position test_pos;
+
+  struct rx_stack_chunk * counter_stack;
+  struct rx_stack_chunk * backtrack_stack;
+  int backtrack_frame_bytes;
+  int chunk_bytes;
+  struct rx_stack_chunk * free_chunks;
+
+  /* To return from this function, set test_ret and 
+   * `goto test_do_return'.
+   *
+   * Possible return values are:
+   *     1   --- end of string while the superNFA is still going
+   *     0   --- internal error (out of memory)
+   *	-1   --- search completed by reaching the superNFA fail state
+   *    -2   --- a match was found, maybe not the longest.
+   *
+   * When the search is complete (-1), best_last_r indicates whether
+   * a match was found.
+   *
+   * -2 is return only if search_state.first_found is non-zero.
+   *
+   * if search_state.first_found is non-zero, a return of -1 indicates no match,
+   * otherwise, best_last_r has to be checked.
+   */
+  int test_ret;
+
+  int could_have_continued;
+  
+#ifdef RX_DEBUG
+  int backtrack_depth;
+  /* There is a search tree with every node as set of deterministic
+   * transitions in the super nfa.  For every branch of a 
+   * backtrack point is an edge in the tree.
+   * This counts up a pre-order of nodes in that tree.
+   * It's saved on the search stack and printed when debugging. 
+   */
+  int line_no;
+  int lines_found;
+#endif
+
+
+  /* For continuations within the match tester */
+  enum rx_test_match_entry test_match_resume_pt;
+  struct rx_inx * saved_next_tr_table;
+  struct rx_inx * saved_this_tr_table;
+  int saved_reg;
+  struct rx_backtrack_frame * saved_bf;
+  
+};
+
+
+
+extern char rx_slowmap[];
+extern unsigned char rx_id_translation[];
+
+static __inline__ void
+init_fastmap (rxb, search_state)
+     struct re_pattern_buffer * rxb;
+     struct rx_search_state * search_state;
+{
+  search_state->fastmap = (rxb->fastmap
+			   ? (char *)rxb->fastmap
+			   : (char *)rx_slowmap);
+  /* Update the fastmap now if not correct already. 
+   * When the regexp was compiled, the fastmap was computed
+   * and stored in a bitset.  This expands the bitset into a
+   * character array containing 1s and 0s.
+   */
+  if ((search_state->fastmap == rxb->fastmap) && !rxb->fastmap_accurate)
+    rx_blow_up_fastmap (rxb);
+  search_state->fastmap_chr = -1;
+  search_state->fastmap_val = 0;
+  search_state->fastmap_resume_pt = rx_fastmap_start;
+}
+
+static __inline__ void
+uninit_fastmap (rxb, search_state)
+     struct re_pattern_buffer * rxb;
+     struct rx_search_state * search_state;
+{
+  /* Unset the fastmap sentinel */
+  if (search_state->fastmap_chr >= 0)
+    search_state->fastmap[search_state->fastmap_chr]
+      = search_state->fastmap_val;
+}
+
+static __inline__ int
+fastmap_search (rxb, stop, get_burst, app_closure, search_state)
+     struct re_pattern_buffer * rxb;
+     int stop;
+     rx_get_burst_fn get_burst;
+     void * app_closure;
+     struct rx_search_state * search_state;
+{
+  enum rx_fastmap_entry pc;
+
+  if (0)
+    {
+    return_continuation:
+      search_state->fastmap_resume_pt = pc;
+      return rx_fastmap_continuation;
+    }
+
+  pc = search_state->fastmap_resume_pt;
+
+  switch (pc)
+    {
+    default:
+      return rx_fastmap_error;
+    case rx_fastmap_start:
+    init_fastmap_sentinal:
+      /* For the sake of fast fastmapping, set a sentinal in the fastmap.
+       * This sentinal will trap the fastmap loop when it reaches the last
+       * valid character in a string half.
+       *
+       * This must be reset when the fastmap/search loop crosses a string 
+       * boundry, and before returning to the caller.  So sometimes,
+       * the fastmap loop is restarted with `continue', othertimes by
+       * `goto init_fastmap_sentinal'.
+       */
+      if (search_state->outer_pos.size)
+	{
+	  search_state->fastmap_chr = ((search_state->outer_pos.search_direction == 1)
+				       ? *(search_state->outer_pos.end - 1)
+				       : *search_state->outer_pos.string);
+	  search_state->fastmap_val
+	    = search_state->fastmap[search_state->fastmap_chr];
+	  search_state->fastmap[search_state->fastmap_chr] = 1;
+	}
+      else
+	{
+	  search_state->fastmap_chr = -1;
+	  search_state->fastmap_val = 0;
+	}
+      
+      if (search_state->outer_pos.pos >= search_state->outer_pos.end)
+	goto fastmap_hit_bound;
+      else
+	{
+	  if (search_state->outer_pos.search_direction == 1)
+	    {
+	      if (search_state->fastmap_val)
+		{
+		  for (;;)
+		    {
+		      while (!search_state->fastmap[*search_state->outer_pos.pos])
+			++search_state->outer_pos.pos;
+		      return rx_fastmap_ok;
+		    }
+		}
+	      else
+		{
+		  for (;;)
+		    {
+		      while (!search_state->fastmap[*search_state->outer_pos.pos])
+			++search_state->outer_pos.pos;
+		      if (*search_state->outer_pos.pos != search_state->fastmap_chr)
+			return rx_fastmap_ok;
+		      else 
+			{
+			  ++search_state->outer_pos.pos;
+			  if (search_state->outer_pos.pos == search_state->outer_pos.end)
+			    goto fastmap_hit_bound;
+			}
+		    }
+		}
+	    }
+	  else
+	    {
+	      __const__ unsigned char * bound;
+	      bound = search_state->outer_pos.string - 1;
+	      if (search_state->fastmap_val)
+		{
+		  for (;;)
+		    {
+		      while (!search_state->fastmap[*search_state->outer_pos.pos])
+			--search_state->outer_pos.pos;
+		      return rx_fastmap_ok;
+		    }
+		}
+	      else
+		{
+		  for (;;)
+		    {
+		      while (!search_state->fastmap[*search_state->outer_pos.pos])
+			--search_state->outer_pos.pos;
+		      if ((*search_state->outer_pos.pos != search_state->fastmap_chr) || search_state->fastmap_val)
+			return rx_fastmap_ok;
+		      else 
+			{
+			  --search_state->outer_pos.pos;
+			  if (search_state->outer_pos.pos == bound)
+			    goto fastmap_hit_bound;
+			}
+		    }
+		}
+	    }
+	}
+      
+    case rx_fastmap_string_break:
+    fastmap_hit_bound:
+      {
+	/* If we hit a bound, it may be time to fetch another burst
+	 * of string, or it may be time to return a continuation to 
+ 	 * the caller, or it might be time to fail.
+	 */
+
+	int burst_state;
+	burst_state = get_burst (&search_state->outer_pos, app_closure, stop);
+	switch (burst_state)
+	  {
+	  default:
+	  case rx_get_burst_error:
+	    return rx_fastmap_error;
+	  case rx_get_burst_continuation:
+	    {
+	      pc = rx_fastmap_string_break;
+	      goto return_continuation;
+	    }
+	  case rx_get_burst_ok:
+	    goto init_fastmap_sentinal;
+	  case rx_get_burst_no_more:
+	    /* ...not a string split, simply no more string. 
+	     *
+	     * When searching backward, running out of string
+	     * is reason to quit.
+	     *
+	     * When searching forward, we allow the possibility
+	     * of an (empty) match after the last character in the
+	     * virtual string.  So, fall through to the matcher
+	     */
+	    return (  (search_state->outer_pos.search_direction == 1)
+		    ? rx_fastmap_ok
+		    : rx_fastmap_fail);
+	  }
+      }
+    }
+
+}
+
+
+
+
+#ifdef emacs
+/* The `emacs' switch turns on certain matching commands
+ * that make sense only in Emacs. 
+ */
+#include "sysfuncs.h"
+#include "lisp.h"
+#include "buffer.h"
+#include "syntax.h"
+#endif /* emacs */
+
+/* Setting RX_MEMDBUG is useful if you have dbmalloc.  Maybe with similar
+ * packages too.
+ */
+#ifdef RX_MEMDBUG
+#include <malloc.h>
+#endif /* RX_RX_MEMDBUG */
+
+/* We used to test for `BSTRING' here, but only GCC and Emacs define
+ * `BSTRING', as far as I know, and neither of them use this code.  
+ */
+#if HAVE_STRING_H || STDC_HEADERS
+#include <string.h>
+
+#ifndef bcmp
+#define bcmp(s1, s2, n)	memcmp ((s1), (s2), (n))
+#endif
+
+#ifndef bcopy
+#define bcopy(s, d, n)	memcpy ((d), (s), (n))
+#endif
+
+#ifndef bzero
+#define bzero(s, n)	memset ((s), 0, (n))
+#endif
+
+#else /*  HAVE_STRING_H || STDC_HEADERS */
+#include <strings.h>
+#endif   /* not (HAVE_STRING_H || STDC_HEADERS) */
+
+#ifdef STDC_HEADERS
+#include <stdlib.h>
+#else /* not STDC_HEADERS */
+char *malloc ();
+char *realloc ();
+#endif /* not STDC_HEADERS */
+
+
+
+
+
+/* How many characters in the character set.  */
+#define CHAR_SET_SIZE (1 << CHARBITS)
+
+#ifndef emacs
+/* Define the syntax basics for \<, \>, etc.
+ * This must be nonzero for the wordchar and notwordchar pattern
+ * commands in re_match_2.
+ */
+#ifndef Sword 
+#define Sword 1
+#endif
+#define SYNTAX(c) re_syntax_table[c]
+#ifdef SYNTAX_TABLE
+extern char *re_syntax_table;
+#else
+RX_DECL char re_syntax_table[CHAR_SET_SIZE];
+#endif
+#endif /* not emacs */
+
+
+/* Test if at very beginning or at very end of the virtual concatenation
+ *  of `string1' and `string2'.  If only one string, it's `string2'.  
+ */
+
+#define AT_STRINGS_BEG() \
+  (   -1		 \
+   == ((search_state.test_pos.pos - search_state.test_pos.string) \
+       + search_state.test_pos.offset))
+
+#define AT_STRINGS_END() \
+  (   (total_size - 1)	 \
+   == ((search_state.test_pos.pos - search_state.test_pos.string) \
+       + search_state.test_pos.offset))
+
+
+/* Test if POS + 1 points to a character which is word-constituent.  We have
+ * two special cases to check for: if past the end of string1, look at
+ * the first character in string2; and if before the beginning of
+ * string2, look at the last character in string1.
+ *
+ * Assumes `string1' exists, so use in conjunction with AT_STRINGS_BEG ().  
+ */
+#define LETTER_P(POS,OFF)						\
+  (   SYNTAX (fetch_char(POS, OFF, app_closure, stop))			\
+   == Sword)
+
+/* Test if the character at D and the one after D differ with respect
+ * to being word-constituent.  
+ */
+#define AT_WORD_BOUNDARY(d)						\
+  (AT_STRINGS_BEG () || AT_STRINGS_END () || LETTER_P (d,0) != LETTER_P (d, 1))
+
+
+#ifdef RX_SUPPORT_CONTINUATIONS
+#define RX_STACK_ALLOC(BYTES) malloc(BYTES)
+#define RX_STACK_FREE(MEM) free(MEM)
+#else
+#define RX_STACK_ALLOC(BYTES) alloca(BYTES)
+#define RX_STACK_FREE(MEM) \
+      ((struct rx_stack_chunk *)MEM)->next_chunk = search_state.free_chunks; \
+      search_state.free_chunks = ((struct rx_stack_chunk *)MEM);
+
+#endif
+
+#define PUSH(CHUNK_VAR,BYTES)   \
+  if (!CHUNK_VAR || (CHUNK_VAR->bytes_left < (BYTES)))  \
+    {					\
+      struct rx_stack_chunk * new_chunk;	\
+      if (search_state.free_chunks)			\
+	{				\
+	  new_chunk = search_state.free_chunks;	\
+	  search_state.free_chunks = search_state.free_chunks->next_chunk; \
+	}				\
+      else				\
+	{				\
+	  new_chunk = (struct rx_stack_chunk *)RX_STACK_ALLOC(search_state.chunk_bytes); \
+	  if (!new_chunk)		\
+	    {				\
+	      search_state.ret_val = 0;		\
+	      goto test_do_return;	\
+	    }				\
+	}				\
+      new_chunk->sp = (char *)new_chunk + sizeof (struct rx_stack_chunk); \
+      new_chunk->bytes_left = (search_state.chunk_bytes \
+			       - (BYTES) \
+			       - sizeof (struct rx_stack_chunk)); \
+      new_chunk->next_chunk = CHUNK_VAR; \
+      CHUNK_VAR = new_chunk;		\
+    } \
+  else \
+    (CHUNK_VAR->sp += (BYTES)), (CHUNK_VAR->bytes_left -= (BYTES))
+
+#define POP(CHUNK_VAR,BYTES) \
+  if (CHUNK_VAR->sp == ((char *)CHUNK_VAR + sizeof(*CHUNK_VAR))) \
+    { \
+      struct rx_stack_chunk * new_chunk = CHUNK_VAR->next_chunk; \
+      RX_STACK_FREE(CHUNK_VAR); \
+      CHUNK_VAR = new_chunk; \
+    } \
+  else \
+    (CHUNK_VAR->sp -= BYTES), (CHUNK_VAR->bytes_left += BYTES)
+
+
+
+#define SRCH_TRANSLATE(C)  search_state.translate[(unsigned char) (C)]
+
+
+
+
+
+#ifdef __STDC__
+RX_DECL __inline__ int
+rx_search  (struct re_pattern_buffer * rxb,
+	    int startpos,
+	    int range,
+	    int stop,
+	    int total_size,
+	    rx_get_burst_fn get_burst,
+	    rx_back_check_fn back_check,
+	    rx_fetch_char_fn fetch_char,
+	    void * app_closure,
+	    struct re_registers * regs,
+	    struct rx_search_state * resume_state,
+	    struct rx_search_state * save_state)
+#else
+RX_DECL __inline__ int
+rx_search  (rxb, startpos, range, stop, total_size,
+	    get_burst, back_check, fetch_char,
+	    app_closure, regs, resume_state, save_state)
+     struct re_pattern_buffer * rxb;
+     int startpos;
+     int range;
+     int stop;
+     int total_size;
+     rx_get_burst_fn get_burst;
+     rx_back_check_fn back_check;
+     rx_fetch_char_fn fetch_char;
+     void * app_closure;
+     struct re_registers * regs;
+     struct rx_search_state * resume_state;
+     struct rx_search_state * save_state;
+#endif
+{
+  int pc;
+  int test_state;
+  struct rx_search_state search_state;
+
+  search_state.free_chunks = 0;
+  if (!resume_state)
+    pc = rx_outer_start;
+  else
+    {
+      search_state = *resume_state;
+      regs = search_state.saved_regs;
+      rxb = search_state.saved_rxb;
+      startpos = search_state.saved_startpos;
+      range = search_state.saved_range;
+      stop = search_state.saved_stop;
+      total_size = search_state.saved_total_size;
+      get_burst = search_state.saved_get_burst;
+      back_check = search_state.saved_back_check;
+      pc = search_state.outer_search_resume_pt;
+      if (0)
+	{
+	return_continuation:
+	  if (save_state)
+	    {
+	      *save_state = search_state;
+	      save_state->saved_regs = regs;
+	      save_state->saved_rxb = rxb;
+	      save_state->saved_startpos = startpos;
+	      save_state->saved_range = range;
+	      save_state->saved_stop = stop;
+	      save_state->saved_total_size = total_size;
+	      save_state->saved_get_burst = get_burst;
+	      save_state->saved_back_check = back_check;
+	      save_state->outer_search_resume_pt = pc;
+	    }
+	  return rx_search_continuation;
+	}
+    }
+
+  switch (pc)
+    {
+    case rx_outer_start:
+      search_state.ret_val = rx_search_fail;
+      (  search_state.lparen
+       = search_state.rparen
+       = search_state.best_lpspace
+       = search_state.best_rpspace
+       = 0);
+      
+      /* figure the number of registers we may need for use in backreferences.
+       * the number here includes an element for register zero.  
+       */
+      search_state.num_regs = rxb->re_nsub + 1;
+      
+      
+      /* check for out-of-range startpos.  */
+      if ((startpos < 0) || (startpos > total_size))
+	return rx_search_fail;
+      
+      /* fix up range if it might eventually take us outside the string. */
+      {
+	int endpos;
+	endpos = startpos + range;
+	if (endpos < -1)
+	  range = (-1 - startpos);
+	else if (endpos > (total_size + 1))
+	  range = total_size - startpos;
+      }
+      
+      /* if the search isn't to be a backwards one, don't waste time in a
+       * long search for a pattern that says it is anchored.
+       */
+      if (rxb->begbuf_only && (range > 0))
+	{
+	  if (startpos > 0)
+	    return rx_search_fail;
+	  else
+	    range = 1;
+	}
+      
+      /* decide whether to use internal or user-provided reg buffers. */
+      if (!regs || rxb->no_sub)
+	{
+	  search_state.best_lpspace =
+	    (regoff_t *)REGEX_ALLOCATE (search_state.num_regs * sizeof(regoff_t));
+	  search_state.best_rpspace =
+	    (regoff_t *)REGEX_ALLOCATE (search_state.num_regs * sizeof(regoff_t));
+	  search_state.best_lparen = search_state.best_lpspace;
+	  search_state.best_rparen = search_state.best_rpspace;
+	}
+      else
+	{	
+	  /* have the register data arrays been allocated?  */
+	  if (rxb->regs_allocated == REGS_UNALLOCATED)
+	    { /* no.  so allocate them with malloc.  we need one
+		 extra element beyond `search_state.num_regs' for the `-1' marker
+		 gnu code uses.  */
+	      regs->num_regs = MAX (RE_NREGS, rxb->re_nsub + 1);
+	      regs->start = ((regoff_t *)
+			     malloc (regs->num_regs * sizeof ( regoff_t)));
+	      regs->end = ((regoff_t *)
+			   malloc (regs->num_regs * sizeof ( regoff_t)));
+	      if (regs->start == 0 || regs->end == 0)
+		return rx_search_error;
+	      rxb->regs_allocated = REGS_REALLOCATE;
+	    }
+	  else if (rxb->regs_allocated == REGS_REALLOCATE)
+	    { /* yes.  if we need more elements than were already
+		 allocated, reallocate them.  if we need fewer, just
+		 leave it alone.  */
+	      if (regs->num_regs < search_state.num_regs + 1)
+		{
+		  regs->num_regs = search_state.num_regs + 1;
+		  regs->start = ((regoff_t *)
+				 realloc (regs->start,
+					  regs->num_regs * sizeof (regoff_t)));
+		  regs->end = ((regoff_t *)
+			       realloc (regs->end,
+					regs->num_regs * sizeof ( regoff_t)));
+		  if (regs->start == 0 || regs->end == 0)
+		    return rx_search_error;
+		}
+	    }
+	  else if (rxb->regs_allocated != REGS_FIXED)
+	    return rx_search_error;
+	  
+	  if (regs->num_regs < search_state.num_regs + 1)
+	    {
+	      search_state.best_lpspace =
+		((regoff_t *)
+		 REGEX_ALLOCATE (search_state.num_regs * sizeof(regoff_t)));
+	      search_state.best_rpspace =
+		((regoff_t *)
+		 REGEX_ALLOCATE (search_state.num_regs * sizeof(regoff_t)));
+	      search_state.best_lparen = search_state.best_lpspace;
+	      search_state.best_rparen = search_state.best_rpspace;
+	    }
+	  else
+	    {
+	      search_state.best_lparen = regs->start;
+	      search_state.best_rparen = regs->end;
+	    }
+	}
+      
+      search_state.lparen =
+	(regoff_t *) REGEX_ALLOCATE (search_state.num_regs * sizeof(regoff_t));
+      search_state.rparen =
+	(regoff_t *) REGEX_ALLOCATE (search_state.num_regs * sizeof(regoff_t)); 
+      
+      if (! (   search_state.best_rparen
+	     && search_state.best_lparen
+	     && search_state.lparen && search_state.rparen))
+	return rx_search_error;
+      
+      search_state.best_last_l = search_state.best_last_r = -1;
+      
+      search_state.translate = (rxb->translate
+				? rxb->translate
+				: rx_id_translation);
+      
+      
+      
+      /*
+       * two nfa's were compiled.  
+       * `0' is complete.
+       * `1' faster but gets registers wrong and ends too soon.
+       */
+      search_state.nfa_choice = (regs && !rxb->least_subs) ? '\0' : '\1';
+      
+      /* we have the option to look for the best match or the first
+       * one we can find.  if the user isn't asking for register information,
+       * we don't need to find the best match.
+       */
+      search_state.first_found = !regs;
+      
+      if (range >= 0)
+	{
+	  search_state.outer_pos.search_end = startpos + range;
+	  search_state.outer_pos.search_direction = 1;
+	}
+      else
+	{
+	  search_state.outer_pos.search_end = startpos + range;
+	  search_state.outer_pos.search_direction = -1;
+	}
+      
+      /* the vacuous search always turns up nothing. */
+      if ((search_state.outer_pos.search_direction == 1)
+	  ? (startpos > search_state.outer_pos.search_end)
+	  : (startpos < search_state.outer_pos.search_end))
+	return rx_search_fail;
+      
+      /* now we build the starting state of the supernfa. */
+      {
+	struct rx_superset * start_contents;
+	struct rx_nfa_state_set * start_nfa_set;
+	
+	/* we presume here that the nfa start state has only one
+	 * possible future with no side effects.  
+	 */
+	start_nfa_set = rxb->start->futures->destset;
+	if (   rxb->rx.start_set
+	    && (rxb->rx.start_set->starts_for == &rxb->rx))
+	  start_contents = rxb->rx.start_set;
+	else
+	  {
+	    start_contents =
+	      rx_superstate_eclosure_union (&rxb->rx,
+					    rx_superset_cons (&rxb->rx, 0, 0),
+					    start_nfa_set);
+	    
+	    if (!start_contents)
+	      return rx_search_fail;
+	    
+	    start_contents->starts_for = &rxb->rx;
+	    rxb->rx.start_set = start_contents;
+	  }
+	if (   start_contents->superstate
+	    && (start_contents->superstate->rx_id == rxb->rx.rx_id))
+	  {
+	    search_state.start_super = start_contents->superstate;
+	    rx_lock_superstate (&rxb->rx, search_state.start_super);
+	  }
+	else
+	  {
+	    rx_protect_superset (&rxb->rx, start_contents);
+	    
+	    search_state.start_super = rx_superstate (&rxb->rx, start_contents);
+	    if (!search_state.start_super)
+	      return rx_search_fail;
+	    rx_lock_superstate (&rxb->rx, search_state.start_super);
+	    rx_release_superset (&rxb->rx, start_contents);
+	  }
+      }
+      
+      
+      /* The outer_pos tracks the position within the strings
+       * as seen by loop that calls fastmap_search.
+       *
+       * The caller supplied get_burst function actually 
+       * gives us pointers to chars.
+       * 
+       * Communication with the get_burst function is through an
+       * rx_string_position structure.  Here, the structure for
+       * outer_pos is initialized.   It is set to point to the
+       * NULL string, at an offset of STARTPOS.  STARTPOS is out
+       * of range of the NULL string, so the first call to 
+       * getburst will patch up the rx_string_position to point
+       * to valid characters.
+       */
+
+      (  search_state.outer_pos.string
+       = search_state.outer_pos.end
+       = 0);
+
+      search_state.outer_pos.offset = 0;
+      search_state.outer_pos.size = 0;
+      search_state.outer_pos.pos = (unsigned char *)startpos;
+      init_fastmap (rxb, &search_state);
+
+      search_state.fastmap_resume_pt = rx_fastmap_start;
+    case rx_outer_fastmap:
+      /* do { */
+    pseudo_do:
+      {
+	{
+	  int fastmap_state;
+	  fastmap_state = fastmap_search (rxb, stop, get_burst, app_closure,
+					  &search_state);
+	  switch (fastmap_state)
+	    {
+	    case rx_fastmap_continuation:
+	      pc = rx_outer_fastmap;
+	      goto return_continuation;
+	    case rx_fastmap_fail:
+	      goto finish;
+	    case rx_fastmap_ok:
+	      break;
+	    }
+	}
+	
+	/* now the fastmap loop has brought us to a plausible 
+	 * starting point for a match.  so, it's time to run the
+	 * nfa and see if a match occured.
+	 */
+	startpos = (  search_state.outer_pos.pos
+		    - search_state.outer_pos.string
+		    + search_state.outer_pos.offset);
+/*|*/	if ((range > 0) && (startpos == search_state.outer_pos.search_end))
+/*|*/	  goto finish;
+      }
+
+      search_state.test_match_resume_pt = rx_test_start;
+      /* do interrupted for entry point... */
+    case rx_outer_test:
+      /* ...do continued */
+      {
+	goto test_match;
+      test_returns_to_search:
+	switch (test_state)
+	  {
+	  case rx_test_continuation:
+	    pc = rx_outer_test;
+	    goto return_continuation;
+	  case rx_test_error:
+	    search_state.ret_val = rx_search_error;
+	    goto finish;
+	  case rx_test_fail:
+	    break;
+	  case rx_test_ok:
+	    goto finish;
+	  }
+	search_state.outer_pos.pos += search_state.outer_pos.search_direction;
+	startpos += search_state.outer_pos.search_direction;
+#if 0
+/*|*/	if (search_state.test_pos.pos < search_state.test_pos.end)
+/*|*/	  break;
+#endif
+      }
+      /* do interrupted for entry point... */
+    case rx_outer_restore_pos:
+      {
+	int x;
+	x = get_burst (&search_state.outer_pos, app_closure, stop);
+	switch (x)
+	  {
+	  case rx_get_burst_continuation:
+	    pc = rx_outer_restore_pos;
+	    goto return_continuation;
+	  case rx_get_burst_error:
+	    search_state.ret_val = rx_search_error;
+	    goto finish;
+	  case rx_get_burst_no_more:
+	    if (rxb->can_match_empty)
+	      break;
+	    goto finish;
+	  case rx_get_burst_ok:
+	    break;
+	  }
+      } /* } while (...see below...) */
+
+      if ((search_state.outer_pos.search_direction == 1)
+	  ? (startpos < search_state.outer_pos.search_end)
+	  : (startpos > search_state.outer_pos.search_end))
+	goto pseudo_do;
+
+	
+    finish:
+      uninit_fastmap (rxb, &search_state);
+      if (search_state.start_super)
+	rx_unlock_superstate (&rxb->rx, search_state.start_super);
+      
+#ifdef regex_malloc
+      if (search_state.lparen) free (search_state.lparen);
+      if (search_state.rparen) free (search_state.rparen);
+      if (search_state.best_lpspace) free (search_state.best_lpspace);
+      if (search_state.best_rpspace) free (search_state.best_rpspace);
+#endif
+      return search_state.ret_val;
+    }
+
+
+ test_match:
+  {
+    enum rx_test_match_entry test_pc;
+    int inx;
+    test_pc = search_state.test_match_resume_pt;
+    if (test_pc == rx_test_start)
+      {
+#ifdef RX_DEBUG
+	search_state.backtrack_depth = 0;
+#endif
+	search_state.last_l = search_state.last_r = 0;
+	search_state.lparen[0] = startpos;
+	search_state.super = search_state.start_super;
+	search_state.c = search_state.nfa_choice;
+	search_state.test_pos.pos = search_state.outer_pos.pos - 1;    
+	search_state.test_pos.string = search_state.outer_pos.string;
+	search_state.test_pos.end = search_state.outer_pos.end;
+	search_state.test_pos.offset = search_state.outer_pos.offset;
+	search_state.test_pos.size = search_state.outer_pos.size;
+	search_state.test_pos.search_direction = 1;
+	search_state.counter_stack = 0;
+	search_state.backtrack_stack = 0;
+	search_state.backtrack_frame_bytes =
+	  (sizeof (struct rx_backtrack_frame)
+	   + (rxb->match_regs_on_stack
+	      ? sizeof (regoff_t) * (search_state.num_regs + 1) * 2
+	      : 0));
+	search_state.chunk_bytes = search_state.backtrack_frame_bytes * 64;
+	search_state.test_ret = rx_test_line_finished;
+	search_state.could_have_continued = 0;
+      }  
+    /* This is while (1)...except that the body of the loop is interrupted 
+     * by some alternative entry points.
+     */
+  pseudo_while_1:
+    switch (test_pc)
+      {
+      case rx_test_cache_hit_loop:
+	goto resume_continuation_1;
+      case rx_test_backreference_check:
+	goto resume_continuation_2;
+      case rx_test_backtrack_return:
+	goto resume_continuation_3;
+      case rx_test_start:
+#ifdef RX_DEBUG
+	/* There is a search tree with every node as set of deterministic
+	 * transitions in the super nfa.  For every branch of a 
+	 * backtrack point is an edge in the tree.
+	 * This counts up a pre-order of nodes in that tree.
+	 * It's saved on the search stack and printed when debugging. 
+	 */
+	search_state.line_no = 0;
+	search_state.lines_found = 0;
+#endif
+	
+      top_of_cycle:
+	/* A superstate is basicly a transition table, indexed by 
+	 * characters from the string being tested, and containing 
+	 * RX_INX (`instruction frame') structures.
+	 */
+	search_state.ifr = &search_state.super->transitions [search_state.c];
+	
+      recurse_test_match:
+	/* This is the point to which control is sent when the
+	 * test matcher `recurses'.  Before jumping here, some variables
+	 * need to be saved on the stack and the next instruction frame
+	 * has to be computed.
+	 */
+	
+      restart:
+	/* Some instructions don't advance the matcher, but just
+	 * carry out some side effects and fetch a new instruction.
+	 * To dispatch that new instruction, `goto restart'.
+	 */
+	
+	{
+	  struct rx_inx * next_tr_table;
+	  struct rx_inx * this_tr_table;
+	  /* The fastest route through the loop is when the instruction 
+	   * is RX_NEXT_CHAR.  This case is detected when SEARCH_STATE.IFR->DATA
+	   * is non-zero.  In that case, it points to the next
+	   * superstate. 
+	   *
+	   * This allows us to not bother fetching the bytecode.
+	   */
+	  next_tr_table = (struct rx_inx *)search_state.ifr->data;
+	  this_tr_table = search_state.super->transitions;
+	  while (next_tr_table)
+	    {
+#ifdef RX_DEBUG_0
+	      if (rx_debug_trace)
+		{
+		  struct rx_superset * setp;
+		  
+		  fprintf (stderr, "%d %d>> re_next_char @ %d (%d)",
+			   search_state.line_no,
+			   search_state.backtrack_depth,
+			   (search_state.test_pos.pos - search_state.test_pos.string
+			    + search_state.test_pos.offset), search_state.c);
+		  
+		  search_state.super =
+		    ((struct rx_superstate *)
+		     ((char *)this_tr_table
+		      - ((unsigned long)
+			 ((struct rx_superstate *)0)->transitions)));
+		  
+		  setp = search_state.super->contents;
+		  fprintf (stderr, "   superstet (rx=%d, &=%x: ",
+			   rxb->rx.rx_id, setp);
+		  while (setp)
+		    {
+		      fprintf (stderr, "%d ", setp->id);
+		      setp = setp->cdr;
+		    }
+		  fprintf (stderr, "\n");
+		}
+#endif
+	      this_tr_table = next_tr_table;
+	      ++search_state.test_pos.pos;
+	      if (search_state.test_pos.pos == search_state.test_pos.end)
+		{
+		  int burst_state;
+		try_burst_1:
+		  burst_state = get_burst (&search_state.test_pos,
+					   app_closure, stop);
+		  switch (burst_state)
+		    {
+		    case rx_get_burst_continuation:
+		      search_state.saved_this_tr_table = this_tr_table;
+		      search_state.saved_next_tr_table = next_tr_table;
+		      test_pc = rx_test_cache_hit_loop;
+		      goto test_return_continuation;
+		      
+		    resume_continuation_1:
+		      /* Continuation one jumps here to do its work: */
+		      search_state.saved_this_tr_table = this_tr_table;
+		      search_state.saved_next_tr_table = next_tr_table;
+		      goto try_burst_1;
+		      
+		    case rx_get_burst_ok:
+		      /* get_burst succeeded...keep going */
+		      break;
+		      
+		    case rx_get_burst_no_more:
+		      search_state.test_ret = rx_test_line_finished;
+		      search_state.could_have_continued = 1;
+		      goto test_do_return;
+		      
+		    case rx_get_burst_error:
+		      /* An error... */
+		      search_state.test_ret = rx_test_internal_error;
+		      goto test_do_return;
+		    }
+		}
+	      search_state.c = *search_state.test_pos.pos;
+	      search_state.ifr = this_tr_table + search_state.c;
+	      next_tr_table = (struct rx_inx *)search_state.ifr->data;
+	    } /* Fast loop through cached transition tables */
+	  
+	  /* Here when we ran out of cached next-char transitions. 
+	   * So, it will be necessary to do a more expensive
+	   * dispatch on the current instruction.  The superstate
+	   * pointer is allowed to become invalid during next-char
+	   * transitions -- now we must bring it up to date.
+	   */
+	  search_state.super =
+	    ((struct rx_superstate *)
+	     ((char *)this_tr_table
+	      - ((unsigned long)
+		 ((struct rx_superstate *)0)->transitions)));
+	}
+	
+	/* We've encountered an instruction other than next-char.
+	 * Dispatch that instruction:
+	 */
+	inx = (int)search_state.ifr->inx;
+#ifdef RX_DEBUG_0
+	if (rx_debug_trace)
+	  {
+	    struct rx_superset * setp = search_state.super->contents;
+	    
+	    fprintf (stderr, "%d %d>> %s @ %d (%d)", search_state.line_no,
+		     search_state.backtrack_depth,
+		     inx_names[inx],
+		     (search_state.test_pos.pos - search_state.test_pos.string
+		      + (test_pos.half == 0 ? 0 : size1)), search_state.c);
+	    
+	    fprintf (stderr, "   superstet (rx=%d, &=%x: ",
+		     rxb->rx.rx_id, setp);
+	    while (setp)
+	      {
+		fprintf (stderr, "%d ", setp->id);
+		setp = setp->cdr;
+	      }
+	    fprintf (stderr, "\n");
+	  }
+#endif
+	switch ((enum rx_opcode)inx)
+	  {
+	  case rx_do_side_effects:
+	    
+	    /*  RX_DO_SIDE_EFFECTS occurs when we cross epsilon 
+	     *  edges associated with parentheses, backreferencing, etc.
+	     */
+	    {
+	      struct rx_distinct_future * df =
+		(struct rx_distinct_future *)search_state.ifr->data_2;
+	      struct rx_se_list * el = df->effects;
+	      /* Side effects come in lists.  This walks down
+	       * a list, dispatching.
+	       */
+	      while (el)
+		{
+		  long effect;
+		  effect = (long)el->car;
+		  if (effect < 0)
+		    {
+#ifdef RX_DEBUG_0
+		      if (rx_debug_trace)
+			{
+			  struct rx_superset * setp = search_state.super->contents;
+			  
+			  fprintf (stderr, "....%d %d>> %s\n", search_state.line_no,
+				   search_state.backtrack_depth,
+				   efnames[-effect]);
+			}
+#endif
+		      switch ((enum re_side_effects) effect)
+
+			{
+			case re_se_pushback:
+			  search_state.ifr = &df->future_frame;
+			  if (!search_state.ifr->data)
+			    {
+			      struct rx_superstate * sup;
+			      sup = search_state.super;
+			      rx_lock_superstate (rx, sup);
+			      if (!rx_handle_cache_miss (&rxb->rx,
+							 search_state.super,
+							 search_state.c,
+							 (search_state.ifr
+							  ->data_2)))
+				{
+				  rx_unlock_superstate (rx, sup);
+				  search_state.test_ret = rx_test_internal_error;
+				  goto test_do_return;
+				}
+			      rx_unlock_superstate (rx, sup);
+			    }
+			  /* --search_state.test_pos.pos; */
+			  search_state.c = 't';
+			  search_state.super
+			    = ((struct rx_superstate *)
+			       ((char *)search_state.ifr->data
+				- (long)(((struct rx_superstate *)0)
+					 ->transitions)));
+			  goto top_of_cycle;
+			  break;
+			case re_se_push0:
+			  {
+			    struct rx_counter_frame * old_cf
+			      = (search_state.counter_stack
+				 ? ((struct rx_counter_frame *)
+				    search_state.counter_stack->sp)
+				 : 0);
+			    struct rx_counter_frame * cf;
+			    PUSH (search_state.counter_stack,
+				  sizeof (struct rx_counter_frame));
+			    cf = ((struct rx_counter_frame *)
+				  search_state.counter_stack->sp);
+			    cf->tag = re_se_iter;
+			    cf->val = 0;
+			    cf->inherited_from = 0;
+			    cf->cdr = old_cf;
+			    break;
+			  }
+			case re_se_fail:
+			  goto test_do_return;
+			case re_se_begbuf:
+			  if (!AT_STRINGS_BEG ())
+			    goto test_do_return;
+			  break;
+			case re_se_endbuf:
+			  if (!AT_STRINGS_END ())
+			    goto test_do_return;
+			  break;
+			case re_se_wordbeg:
+			  if (   LETTER_P (&search_state.test_pos, 1)
+			      && (   AT_STRINGS_BEG()
+				  || !LETTER_P (&search_state.test_pos, 0)))
+			    break;
+			  else
+			    goto test_do_return;
+			case re_se_wordend:
+			  if (   !AT_STRINGS_BEG ()
+			      && LETTER_P (&search_state.test_pos, 0)
+			      && (AT_STRINGS_END ()
+				  || !LETTER_P (&search_state.test_pos, 1)))
+			    break;
+			  else
+			    goto test_do_return;
+			case re_se_wordbound:
+			  if (AT_WORD_BOUNDARY (&search_state.test_pos))
+			    break;
+			  else
+			    goto test_do_return;
+			case re_se_notwordbound:
+			  if (!AT_WORD_BOUNDARY (&search_state.test_pos))
+			    break;
+			  else
+			    goto test_do_return;
+			case re_se_hat:
+			  if (AT_STRINGS_BEG ())
+			    {
+			      if (rxb->not_bol)
+				goto test_do_return;
+			      else
+				break;
+			    }
+			  else
+			    {
+			      char pos_c = *search_state.test_pos.pos;
+			      if (   (SRCH_TRANSLATE (pos_c)
+				      == SRCH_TRANSLATE('\n'))
+				  && rxb->newline_anchor)
+				break;
+			      else
+				goto test_do_return;
+			    }
+			case re_se_dollar:
+			  if (AT_STRINGS_END ())
+			    {
+			      if (rxb->not_eol)
+				goto test_do_return;
+			      else
+				break;
+			    }
+			  else
+			    {
+			      if (   (   SRCH_TRANSLATE (fetch_char
+						    (&search_state.test_pos, 1,
+						     app_closure, stop))
+				      == SRCH_TRANSLATE ('\n'))
+				  && rxb->newline_anchor)
+				break;
+			      else
+				goto test_do_return;
+			    }
+			  
+			case re_se_try:
+			  /* This is the first side effect in every
+			   * expression.
+			   *
+			   *  FOR NO GOOD REASON...get rid of it...
+			   */
+			  break;
+			  
+			case re_se_pushpos:
+			  {
+			    int urhere =
+			      ((int)(search_state.test_pos.pos
+				     - search_state.test_pos.string)
+			       + search_state.test_pos.offset);
+			    struct rx_counter_frame * old_cf
+			      = (search_state.counter_stack
+				 ? ((struct rx_counter_frame *)
+				    search_state.counter_stack->sp)
+				 : 0);
+			    struct rx_counter_frame * cf;
+			    PUSH(search_state.counter_stack,
+				 sizeof (struct rx_counter_frame));
+			    cf = ((struct rx_counter_frame *)
+				  search_state.counter_stack->sp);
+			    cf->tag = re_se_pushpos;
+			    cf->val = urhere;
+			    cf->inherited_from = 0;
+			    cf->cdr = old_cf;
+			    break;
+			  }
+			  
+			case re_se_chkpos:
+			  {
+			    int urhere =
+			      ((int)(search_state.test_pos.pos
+				     - search_state.test_pos.string)
+			       + search_state.test_pos.offset);
+			    struct rx_counter_frame * cf
+			      = ((struct rx_counter_frame *)
+				 search_state.counter_stack->sp);
+			    if (cf->val == urhere)
+			      goto test_do_return;
+			    cf->val = urhere;
+			    break;
+			  }
+			  break;
+			  
+			case re_se_poppos:
+			  POP(search_state.counter_stack,
+			      sizeof (struct rx_counter_frame));
+			  break;
+			  
+			  
+			case re_se_at_dot:
+			case re_se_syntax:
+			case re_se_not_syntax:
+#ifdef emacs
+			  /* 
+			   * this release lacks emacs support
+			   */
+#endif
+			  break;
+			case re_se_win:
+			case re_se_lparen:
+			case re_se_rparen:
+			case re_se_backref:
+			case re_se_iter:
+			case re_se_end_iter:
+			case re_se_tv:
+			case re_floogle_flap:
+			  search_state.ret_val = 0;
+			  goto test_do_return;
+			}
+		    }
+		  else
+		    {
+#ifdef RX_DEBUG_0
+		      if (rx_debug_trace)
+			fprintf (stderr, "....%d %d>> %s %d %d\n", search_state.line_no,
+				 search_state.backtrack_depth,
+				 efnames2[rxb->se_params [effect].se],
+				 rxb->se_params [effect].op1,
+				 rxb->se_params [effect].op2);
+#endif
+		      switch (rxb->se_params [effect].se)
+			{
+			case re_se_win:
+			  /* This side effect indicates that we've 
+			   * found a match, though not necessarily the 
+			   * best match.  This is a fancy assignment to 
+			   * register 0 unless the caller didn't 
+			   * care about registers.  In which case,
+			   * this stops the match.
+			   */
+			  {
+			    int urhere =
+			      ((int)(search_state.test_pos.pos
+				     - search_state.test_pos.string)
+			       + search_state.test_pos.offset);
+			    
+			    if (   (search_state.best_last_r < 0)
+				|| (urhere + 1 > search_state.best_rparen[0]))
+			      {
+				/* Record the best known and keep
+				 * looking.
+				 */
+				int x;
+				for (x = 0; x <= search_state.last_l; ++x)
+				  search_state.best_lparen[x] = search_state.lparen[x];
+				search_state.best_last_l = search_state.last_l;
+				for (x = 0; x <= search_state.last_r; ++x)
+				  search_state.best_rparen[x] = search_state.rparen[x];
+				search_state.best_rparen[0] = urhere + 1;
+				search_state.best_last_r = search_state.last_r;
+			      }
+			    /* If we're not reporting the match-length 
+			     * or other register info, we need look no
+			     * further.
+			     */
+			    if (search_state.first_found)
+			      {
+				search_state.test_ret = rx_test_found_first;
+				goto test_do_return;
+			      }
+			  }
+			  break;
+			case re_se_lparen:
+			  {
+			    int urhere =
+			      ((int)(search_state.test_pos.pos
+				     - search_state.test_pos.string)
+			       + search_state.test_pos.offset);
+			    
+			    int reg = rxb->se_params [effect].op1;
+#if 0
+			    if (reg > search_state.last_l)
+#endif
+			      {
+				search_state.lparen[reg] = urhere + 1;
+				/* In addition to making this assignment,
+				 * we now know that lower numbered regs
+				 * that haven't already been assigned,
+				 * won't be.  We make sure they're
+				 * filled with -1, so they can be
+				 * recognized as unassigned.
+				 */
+				if (search_state.last_l < reg)
+				  while (++search_state.last_l < reg)
+				    search_state.lparen[search_state.last_l] = -1;
+			      }
+			    break;
+			  }
+			  
+			case re_se_rparen:
+			  {
+			    int urhere =
+			      ((int)(search_state.test_pos.pos
+				     - search_state.test_pos.string)
+			       + search_state.test_pos.offset);
+			    int reg = rxb->se_params [effect].op1;
+			    search_state.rparen[reg] = urhere + 1;
+			    if (search_state.last_r < reg)
+			      {
+				while (++search_state.last_r < reg)
+				  search_state.rparen[search_state.last_r]
+				    = -1;
+			      }
+			    break;
+			  }
+			  
+			case re_se_backref:
+			  {
+			    int reg = rxb->se_params [effect].op1;
+			    if (   reg > search_state.last_r
+				|| search_state.rparen[reg] < 0)
+			      goto test_do_return;
+			    
+			    {
+			      int backref_status;
+			    check_backreference:
+			      backref_status
+				= back_check (&search_state.test_pos,
+					      search_state.lparen[reg],
+					      search_state.rparen[reg],
+					      search_state.translate,
+					      app_closure,
+					      stop);
+			      switch (backref_status)
+				{
+				case rx_back_check_continuation:
+				  search_state.saved_reg = reg;
+				  test_pc = rx_test_backreference_check;
+				  goto test_return_continuation;
+				resume_continuation_2:
+				  reg = search_state.saved_reg;
+				  goto check_backreference;
+				case rx_back_check_fail:
+				  /* Fail */
+				  goto test_do_return;
+				case rx_back_check_pass:
+				  /* pass --
+				   * test_pos now advanced to last
+				   * char matched by backref
+				   */
+				  break;
+				}
+			    }
+			    break;
+			  }
+			case re_se_iter:
+			  {
+			    struct rx_counter_frame * csp
+			      = ((struct rx_counter_frame *)
+				 search_state.counter_stack->sp);
+			    if (csp->val == rxb->se_params[effect].op2)
+			      goto test_do_return;
+			    else
+			      ++csp->val;
+			    break;
+			  }
+			case re_se_end_iter:
+			  {
+			    struct rx_counter_frame * csp
+			      = ((struct rx_counter_frame *)
+				 search_state.counter_stack->sp);
+			    if (csp->val < rxb->se_params[effect].op1)
+			      goto test_do_return;
+			    else
+			      {
+				struct rx_counter_frame * source = csp;
+				while (source->inherited_from)
+				  source = source->inherited_from;
+				if (!source || !source->cdr)
+				  {
+				    POP(search_state.counter_stack,
+					sizeof(struct rx_counter_frame));
+				  }
+				else
+				  {
+				    source = source->cdr;
+				    csp->val = source->val;
+				    csp->tag = source->tag;
+				    csp->cdr = 0;
+				    csp->inherited_from = source;
+				  }
+			      }
+			    break;
+			  }
+			case re_se_tv:
+			  /* is a noop */
+			  break;
+			case re_se_try:
+			case re_se_pushback:
+			case re_se_push0:
+			case re_se_pushpos:
+			case re_se_chkpos:
+			case re_se_poppos:
+			case re_se_at_dot:
+			case re_se_syntax:
+			case re_se_not_syntax:
+			case re_se_begbuf:
+			case re_se_hat:
+			case re_se_wordbeg:
+			case re_se_wordbound:
+			case re_se_notwordbound:
+			case re_se_wordend:
+			case re_se_endbuf:
+			case re_se_dollar:
+			case re_se_fail:
+			case re_floogle_flap:
+			  search_state.ret_val = 0;
+			  goto test_do_return;
+			}
+		    }
+		  el = el->cdr;
+		}
+	      /* Now the side effects are done,
+	       * so get the next instruction.
+	       * and move on.
+	       */
+	      search_state.ifr = &df->future_frame;
+	      goto restart;
+	    }
+	    
+	  case rx_backtrack_point:
+	    {
+	      /* A backtrack point indicates that we've reached a
+	       * non-determinism in the superstate NFA.  This is a
+	       * loop that exhaustively searches the possibilities.
+	       *
+	       * A backtracking strategy is used.  We keep track of what
+	       * registers are valid so we can erase side effects.
+	       *
+	       * First, make sure there is some stack space to hold 
+	       * our state.
+	       */
+	      
+	      struct rx_backtrack_frame * bf;
+	      
+	      PUSH(search_state.backtrack_stack,
+		   search_state.backtrack_frame_bytes);
+#ifdef RX_DEBUG_0
+	      ++search_state.backtrack_depth;
+#endif
+	      
+	      bf = ((struct rx_backtrack_frame *)
+		    search_state.backtrack_stack->sp);
+	      {
+		bf->stk_super = search_state.super;
+		/* We prevent the current superstate from being
+		 * deleted from the superstate cache.
+		 */
+		rx_lock_superstate (&rxb->rx, search_state.super);
+#ifdef RX_DEBUG_0
+		bf->stk_search_state.line_no = search_state.line_no;
+#endif
+		bf->stk_c = search_state.c;
+		bf->stk_test_pos = search_state.test_pos;
+		bf->stk_last_l = search_state.last_l;
+		bf->stk_last_r = search_state.last_r;
+		bf->df = ((struct rx_super_edge *)
+			  search_state.ifr->data_2)->options;
+		bf->first_df = bf->df;
+		bf->counter_stack_sp = (search_state.counter_stack
+					? search_state.counter_stack->sp
+					: 0);
+		bf->stk_test_ret = search_state.test_ret;
+		if (rxb->match_regs_on_stack)
+		  {
+		    int x;
+		    regoff_t * stk =
+		      (regoff_t *)((char *)bf + sizeof (*bf));
+		    for (x = 0; x <= search_state.last_l; ++x)
+		      stk[x] = search_state.lparen[x];
+		    stk += x;
+		    for (x = 0; x <= search_state.last_r; ++x)
+		      stk[x] = search_state.rparen[x];
+		  }
+	      }
+	      
+	      /* Here is a while loop whose body is mainly a function
+	       * call and some code to handle a return from that
+	       * function.
+	       *
+	       * From here on for the rest of `case backtrack_point' it
+	       * is unsafe to assume that the search_state copies of 
+	       * variables saved on the backtracking stack are valid
+	       * -- so read their values from the backtracking stack.
+	       *
+	       * This lets us use one generation fewer stack saves in
+	       * the call-graph of a search.
+	       */
+	      
+	    while_non_det_options:
+#ifdef RX_DEBUG_0
+	      ++search_state.lines_found;
+	      if (rx_debug_trace)
+		fprintf (stderr, "@@@ %d calls %d @@@\n",
+			 search_state.line_no, search_state.lines_found);
+	      
+	      search_state.line_no = search_state.lines_found;
+#endif
+	      
+	      if (bf->df->next_same_super_edge[0] == bf->first_df)
+		{
+		  /* This is a tail-call optimization -- we don't recurse
+		   * for the last of the possible futures.
+		   */
+		  search_state.ifr = (bf->df->effects
+				      ? &bf->df->side_effects_frame
+				      : &bf->df->future_frame);
+		  
+		  rx_unlock_superstate (&rxb->rx, search_state.super);
+		  POP(search_state.backtrack_stack,
+		      search_state.backtrack_frame_bytes);
+#ifdef RX_DEBUG
+		  --search_state.backtrack_depth;
+#endif
+		  goto restart;
+		}
+	      else
+		{
+		  if (search_state.counter_stack)
+		    {
+		      struct rx_counter_frame * old_cf
+			= ((struct rx_counter_frame *)search_state.counter_stack->sp);
+		      struct rx_counter_frame * cf;
+		      PUSH(search_state.counter_stack, sizeof (struct rx_counter_frame));
+		      cf = ((struct rx_counter_frame *)search_state.counter_stack->sp);
+		      cf->tag = old_cf->tag;
+		      cf->val = old_cf->val;
+		      cf->inherited_from = old_cf;
+		      cf->cdr = 0;
+		    }			
+		  /* `Call' this test-match block */
+		  search_state.ifr = (bf->df->effects
+				      ? &bf->df->side_effects_frame
+				      : &bf->df->future_frame);
+		  goto recurse_test_match;
+		}
+	      
+	      /* Returns in this block are accomplished by
+	       * goto test_do_return.  There are two cases.
+	       * If there is some search-stack left,
+	       * then it is a return from a `recursive' call.
+	       * If there is no search-stack left, then
+	       * we should return to the fastmap/search loop.
+	       */
+	      
+	    test_do_return:
+	      
+	      if (!search_state.backtrack_stack)
+		{
+#ifdef RX_DEBUG_0
+		  if (rx_debug_trace)
+		    fprintf (stderr, "!!! %d bails returning %d !!!\n",
+			     search_state.line_no, search_state.test_ret);
+#endif
+		  
+		  /* No more search-stack -- this test is done. */
+		  if (search_state.test_ret)
+		    goto return_from_test_match;
+		  else
+		    goto error_in_testing_match;
+		}
+	      
+	      /* Returning from a recursive call to 
+	       * the test match block:
+	       */
+	      
+	      bf = ((struct rx_backtrack_frame *)
+		    search_state.backtrack_stack->sp);
+#ifdef RX_DEBUG_0
+	      if (rx_debug_trace)
+		fprintf (stderr, "+++ %d returns %d (to %d)+++\n",
+			 search_state.line_no,
+			 search_state.test_ret,
+			 bf->stk_search_state.line_no);
+#endif
+	      
+	      while (search_state.counter_stack
+		     && (!bf->counter_stack_sp
+			 || (bf->counter_stack_sp
+			     != search_state.counter_stack->sp)))
+		{
+		  POP(search_state.counter_stack,
+		      sizeof (struct rx_counter_frame));
+		}
+	      
+	      if (search_state.test_ret == rx_test_error)
+		{
+		  POP (search_state.backtrack_stack,
+		       search_state.backtrack_frame_bytes);
+		  goto test_do_return;
+		}
+	      
+	      /* If a non-longest match was found and that is good 
+	       * enough, return immediately.
+	       */
+	      if (   (search_state.test_ret == rx_test_found_first)
+		  && search_state.first_found)
+		{
+		  rx_unlock_superstate (&rxb->rx, bf->stk_super);
+		  POP (search_state.backtrack_stack,
+		       search_state.backtrack_frame_bytes);
+		  goto test_do_return;
+		}
+	      
+	      search_state.test_ret = bf->stk_test_ret;
+	      search_state.last_l = bf->stk_last_l;
+	      search_state.last_r = bf->stk_last_r;
+	      bf->df = bf->df->next_same_super_edge[0];
+	      search_state.super = bf->stk_super;
+	      search_state.c = bf->stk_c;
+#ifdef RX_DEBUG_0
+	      search_state.line_no = bf->stk_search_state.line_no;
+#endif
+	      
+	      if (rxb->match_regs_on_stack)
+		{
+		  int x;
+		  regoff_t * stk =
+		    (regoff_t *)((char *)bf + sizeof (*bf));
+		  for (x = 0; x <= search_state.last_l; ++x)
+		    search_state.lparen[x] = stk[x];
+		  stk += x;
+		  for (x = 0; x <= search_state.last_r; ++x)
+		    search_state.rparen[x] = stk[x];
+		}
+	      
+	      {
+		int x;
+	      try_burst_2:
+		x = get_burst (&bf->stk_test_pos, app_closure, stop);
+		switch (x)
+		  {
+		  case rx_get_burst_continuation:
+		    search_state.saved_bf = bf;
+		    test_pc = rx_test_backtrack_return;
+		    goto test_return_continuation;
+		  resume_continuation_3:
+		    bf = search_state.saved_bf;
+		    goto try_burst_2;
+		  case rx_get_burst_no_more:
+		    /* Since we've been here before, it is some kind of
+		     * error that we can't return.
+		     */
+		  case rx_get_burst_error:
+		    search_state.test_ret = rx_test_internal_error;
+		    goto test_do_return;
+		  case rx_get_burst_ok:
+		    break;
+		  }
+	      }
+	      search_state.test_pos = bf->stk_test_pos;
+	      goto while_non_det_options;
+	    }
+	    
+	    
+	  case rx_cache_miss:
+	    /* Because the superstate NFA is lazily constructed,
+	     * and in fact may erode from underneath us, we sometimes
+	     * have to construct the next instruction from the hard way.
+	     * This invokes one step in the lazy-conversion.
+	     */
+	    search_state.ifr = rx_handle_cache_miss (&rxb->rx,
+						     search_state.super,
+						     search_state.c,
+						     search_state.ifr->data_2);
+	    if (!search_state.ifr)
+	      {
+		search_state.test_ret = rx_test_internal_error;
+		goto test_do_return;
+	      }
+	    goto restart;
+	    
+	  case rx_backtrack:
+	    /* RX_BACKTRACK means that we've reached the empty
+	     * superstate, indicating that match can't succeed
+	     * from this point.
+	     */
+	    goto test_do_return;
+	    
+	  case rx_next_char:
+	  case rx_error_inx:
+	  case rx_num_instructions:
+	    search_state.ret_val = 0;
+	    goto test_do_return;
+	  }
+	goto pseudo_while_1;
+      }
+    
+    /* Healthy exits from the test-match loop do a 
+     * `goto return_from_test_match'   On the other hand, 
+     * we might end up here.
+     */
+  error_in_testing_match:
+    test_state = rx_test_error;
+    goto test_returns_to_search;
+    
+    /***** fastmap/search loop body
+     *	      considering the results testing for a match
+     */
+    
+  return_from_test_match:
+    
+    if (search_state.best_last_l >= 0)
+      {
+	if (regs && (regs->start != search_state.best_lparen))
+	  {
+	    bcopy (search_state.best_lparen, regs->start,
+		   regs->num_regs * sizeof (int));
+	    bcopy (search_state.best_rparen, regs->end,
+		   regs->num_regs * sizeof (int));
+	  }
+	if (regs && !rxb->no_sub)
+	  {
+	    int q;
+	    int bound = (regs->num_regs > search_state.num_regs
+			 ? regs->num_regs
+			 : search_state.num_regs);
+	    regoff_t * s = regs->start;
+	    regoff_t * e = regs->end;
+	    for (q = search_state.best_last_l + 1;  q < bound; ++q)
+	      s[q] = e[q] = -1;
+	  }
+	search_state.ret_val = search_state.best_lparen[0];
+	test_state = rx_test_ok;
+	goto test_returns_to_search;
+      }
+    else
+      {
+	test_state = rx_test_fail;
+	goto test_returns_to_search;
+      }
+    
+  test_return_continuation:
+    search_state.test_match_resume_pt = test_pc;
+    test_state = rx_test_continuation;
+    goto test_returns_to_search;
+  }
+}
+
+
+
+#endif /* RX_WANT_RX_DEFS */
+
+
+
+#else /* RX_WANT_SE_DEFS */
+  /* Integers are used to represent side effects.
+   *
+   * Simple side effects are given negative integer names by these enums.
+   * 
+   * Non-negative names are reserved for complex effects.
+   *
+   * Complex effects are those that take arguments.  For example, 
+   * a register assignment associated with a group is complex because
+   * it requires an argument to tell which group is being matched.
+   * 
+   * The integer name of a complex effect is an index into rxb->se_params.
+   */
+ 
+  RX_DEF_SE(1, re_se_try, = -1)		/* Epsilon from start state */
+
+  RX_DEF_SE(0, re_se_pushback, = re_se_try - 1)
+  RX_DEF_SE(0, re_se_push0, = re_se_pushback -1)
+  RX_DEF_SE(0, re_se_pushpos, = re_se_push0 - 1)
+  RX_DEF_SE(0, re_se_chkpos, = re_se_pushpos -1)
+  RX_DEF_SE(0, re_se_poppos, = re_se_chkpos - 1)
+
+  RX_DEF_SE(1, re_se_at_dot, = re_se_poppos - 1)	/* Emacs only */
+  RX_DEF_SE(0, re_se_syntax, = re_se_at_dot - 1) /* Emacs only */
+  RX_DEF_SE(0, re_se_not_syntax, = re_se_syntax - 1) /* Emacs only */
+
+  RX_DEF_SE(1, re_se_begbuf, = re_se_not_syntax - 1) /* match beginning of buffer */
+  RX_DEF_SE(1, re_se_hat, = re_se_begbuf - 1) /* match beginning of line */
+
+  RX_DEF_SE(1, re_se_wordbeg, = re_se_hat - 1) 
+  RX_DEF_SE(1, re_se_wordbound, = re_se_wordbeg - 1)
+  RX_DEF_SE(1, re_se_notwordbound, = re_se_wordbound - 1)
+
+  RX_DEF_SE(1, re_se_wordend, = re_se_notwordbound - 1)
+  RX_DEF_SE(1, re_se_endbuf, = re_se_wordend - 1)
+
+  /* This fails except at the end of a line. 
+   * It deserves to go here since it is typicly one of the last steps 
+   * in a match.
+   */
+  RX_DEF_SE(1, re_se_dollar, = re_se_endbuf - 1)
+
+  /* Simple effects: */
+  RX_DEF_SE(1, re_se_fail, = re_se_dollar - 1)
+
+  /* Complex effects.  These are used in the 'se' field of 
+   * a struct re_se_params.  Indexes into the se array
+   * are stored as instructions on nfa edges.
+   */
+  RX_DEF_CPLX_SE(1, re_se_win, = 0)
+  RX_DEF_CPLX_SE(1, re_se_lparen, = re_se_win + 1)
+  RX_DEF_CPLX_SE(1, re_se_rparen, = re_se_lparen + 1)
+  RX_DEF_CPLX_SE(0, re_se_backref, = re_se_rparen + 1)
+  RX_DEF_CPLX_SE(0, re_se_iter, = re_se_backref + 1) 
+  RX_DEF_CPLX_SE(0, re_se_end_iter, = re_se_iter + 1)
+  RX_DEF_CPLX_SE(0, re_se_tv, = re_se_end_iter + 1)
+
+#endif
+
+#endif
Index: /main/tags/2.25/gsdl/packages/mg/lib/simplefrenchstem.c
===================================================================
--- /main/tags/2.25/gsdl/packages/mg/lib/simplefrenchstem.c	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/mg/lib/simplefrenchstem.c	(revision 21064)
@@ -0,0 +1,72 @@
+/**************************************************************************
+ *
+ * simplefrenchstem.c -- a simple french stemmer
+ *
+ * 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.
+ *
+ * $Id$
+ *
+ **************************************************************************/
+
+#include "simplefrenchstem.h"
+
+
+
+/* =========================================================================
+ * Function: simplefrenchstem
+ * Description: a simple french stemmer
+ * Input: a word string with the length in the first byte
+ * Output: the stemmed word
+ * ========================================================================= */
+
+void simplefrenchstem (unsigned char *word) {      
+  unsigned short out[256]; /* temp space */
+  unsigned short *wordstart; /* points to first letter of word */
+  int last;                  /* last points to the last character */
+
+  /* decode */
+  utf8_word_to_unicode (word, out, 255);
+  wordstart = out + 1;
+  last = out[0]-1;
+  
+
+  if (last > 4) {
+    if (wordstart[last]=='x') {
+      if (wordstart[last-1]=='u' && wordstart[last-2]=='a') {
+	wordstart[last-1]='l';
+      }
+      last--;
+
+    } else {
+      if (last>=0 && wordstart[last]=='s') last--;
+      if (last>=0 && wordstart[last]=='r') last--;
+      if (last>=0 && wordstart[last]=='e') last--;
+
+      /* letter with accent e + ' -- there are two possible encodings  */
+      if (last>=0 && wordstart[last]==0xe9) { 
+	last--;
+      } else if (last>=1 && wordstart[last-1]=='e' && wordstart[last]==0x301) {
+	last -= 2; 
+      }
+
+      if (last >= 1 && wordstart[last]==wordstart[last-1]) last--;
+    }  /* end else */
+
+    out[0] = (unsigned char)(last+1);
+  } /* end if (len > 4) */
+
+  /* re-code, make sure the result is not longer than the input */
+  unicode_to_utf8_word (out, word, word[0]+1);
+}
Index: /main/tags/2.25/gsdl/packages/mg/lib/simplefrenchstem.h
===================================================================
--- /main/tags/2.25/gsdl/packages/mg/lib/simplefrenchstem.h	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/mg/lib/simplefrenchstem.h	(revision 21064)
@@ -0,0 +1,50 @@
+/**************************************************************************
+ *
+ * simplefrenchstem.h -- a simple french stemmer
+ *
+ * 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.
+ *
+ * $Id$
+ *
+ **************************************************************************/
+
+/*
+   $Log$
+   Revision 1.1  1999/08/10 21:17:04  sjboddie
+   renamed mg-1.3d directory mg
+
+   Revision 1.1  1998/11/25 07:55:37  rjmcnab
+
+   Modified mg to that you can specify the stemmer you want
+   to use via a command line option. You specify it to
+   mg_passes during the build process. The number of the
+   stemmer that you used is stored within the inverted
+   dictionary header and the stemmed dictionary header so
+   the correct stemmer is used in later stages of building
+   and querying.
+
+   Revision 1.1  1998/11/24 06:37:53  rjmcnab
+
+   Incorporated the french stemmer better.
+
+
+ */
+
+#ifndef SIMPLEFRENCHSTEM_H
+#define SIMPLEFRENCHSTEM_H
+
+void simplefrenchstem (unsigned char *word);
+
+#endif
Index: /main/tags/2.25/gsdl/packages/mg/lib/sptree.c
===================================================================
--- /main/tags/2.25/gsdl/packages/mg/lib/sptree.c	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/mg/lib/sptree.c	(revision 21064)
@@ -0,0 +1,391 @@
+/**************************************************************************
+ *
+ * sptree.c -- Splay tree code
+ * Copyright (C) 1994  Gary Eddy, Alistair Moffat and Neil Sharman
+ *
+ * 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.
+ *
+ * $Id$
+ *
+ **************************************************************************/
+
+
+#include	"sysfuncs.h"
+#include	"sptree.h"
+
+/*
+   $Log$
+   Revision 1.1  1999/08/10 21:17:04  sjboddie
+   renamed mg-1.3d directory mg
+
+   Revision 1.1  1998/11/17 09:32:45  rjmcnab
+   *** empty log message ***
+
+   * Revision 1.1  1994/08/22  00:24:50  tes
+   * Initial placement under CVS.
+   *
+ */
+
+static char *RCSID = "$Id$";
+
+#define TRACE(w)
+
+#define POOL_SIZE 1024
+
+
+typedef struct node_rec node;
+
+struct node_rec
+  {
+    node *left, *rght;
+    node *par;
+    char *datsun;
+  };
+
+struct pool
+  {
+    int length, pos;
+    struct pool *next;
+    node nodes[POOL_SIZE];
+  };
+
+static node *SP_splay ();
+
+#define	CNULL	((char *) NULL)
+#define	NNULL	((node *) NULL)
+#define	SNULL	((Splay_Tree *) NULL)
+
+
+/*
+ *    createset():
+ *              allocates memory for and initialises a set.
+ *
+ *      Accesses outside variables:     none
+ *
+ *      Return value...:                none
+ */
+
+Splay_Tree *
+SP_createset (int (*cmp) (void *, void *))
+{
+  Splay_Tree *S;
+
+  if (!(S = (Splay_Tree *) malloc (sizeof (Splay_Tree))))
+    return (SNULL);
+  S->cmp = cmp;
+  S->root = CNULL;
+  S->no_of_items = 0;
+  S->mem_in_use = sizeof (Splay_Tree);
+  S->pool = NULL;
+  S->pool_chunks = 1024;
+  return S;
+}				/* createset() */
+
+
+
+static node *
+SP_get_node (Splay_Tree * S)
+{
+  struct pool *p = S->pool;
+  if (!p || p->pos == p->length)
+    {
+      p = malloc (sizeof (struct pool));
+      if (!p)
+	return NULL;
+      S->mem_in_use += sizeof (struct pool);
+      p->length = POOL_SIZE;
+      p->pos = 0;
+      p->next = S->pool;
+      S->pool = p;
+    }
+  return &(p->nodes[p->pos++]);
+}
+
+
+
+/*
+ *    SP_freeset():
+ *              free the memory allocated to a splay tree. Note this Does not
+ *              free the data in the tree you must do this yourself.
+ *
+ *      Accesses outside variables:     none
+ *
+ *      Return value...:                none
+ */
+
+void 
+SP_freeset (Splay_Tree * S)
+{
+  while (S->pool)
+    {
+      struct pool *p = S->pool;
+      S->pool = p->next;
+      free (p);
+    }
+  free (S);
+}
+
+
+/*
+ *    insert():
+ *              inserts the item given into the set given in the order
+ *              specified by the comparison function in the set 
+ *              definition.
+ *
+ *      Accesses outside variables:     none
+ *
+ *      Return value...:                none
+ */
+
+
+void *
+SP_insert (void *item, Splay_Tree * S)
+{
+  int dir = 0;
+  register node *curr, *prev;
+  node *tmp;
+
+  prev = NNULL;
+  curr = (node *) S->root;
+  for (; curr;)
+    {
+      prev = curr;
+      dir = S->cmp (item, curr->datsun);
+      if (dir < 0)
+	curr = curr->left;
+      else
+	curr = curr->rght;
+    }
+  if (!(tmp = SP_get_node (S)))
+    return NULL;
+  tmp->datsun = item;
+
+  if (prev == NNULL)
+    S->root = (char *) tmp;
+  else if (dir < 0)
+    prev->left = tmp;
+  else
+    prev->rght = tmp;
+
+  tmp->par = prev;
+  tmp->left = NNULL;
+  tmp->rght = NNULL;
+  S->no_of_items++;
+  S->root = (char *) SP_splay (tmp);
+  return (tmp->datsun);
+}				/* insert() */
+
+/*
+ *    get_first():
+ *              returns a pointer to the first item in the set. If the set 
+ *              is empty a NULL pointer is returned.
+ *
+ *      Accesses outside variables:     none
+ */
+
+void *
+SP_get_first (Splay_Tree * S)
+{
+  node *curr, *prev;
+
+  for (curr = (node *) S->root, prev = NNULL; curr;
+       prev = curr, curr = curr->left)
+    ;				/* NULLBODY */
+
+  if (prev)
+    S->root = (char *) SP_splay (prev);
+  return (prev ? prev->datsun : CNULL);
+}				/* get_first() */
+
+/*
+ *    get_next():
+ *              returns the in-order successor of the currently fingered
+ *              item of the set. If no item is fingered or if there is 
+ *              no in-order successor a NULL pointer is returned.
+ *
+ *      Accesses outside variables:     none
+ */
+
+void *
+SP_get_next (Splay_Tree * S)
+{
+  node *curr, *prev;
+
+  curr = (node *) S->root;
+  if (!curr || !curr->rght)
+    return (CNULL);
+
+  for (prev = curr, curr = curr->rght; curr;
+       prev = curr, curr = curr->left)
+    ;				/* NULLBODY */
+
+  if (prev)
+    S->root = (char *) SP_splay (prev);
+  return (prev ? prev->datsun : CNULL);
+}				/* get_next() */
+
+/*
+ *    deletemin():
+ *              removes the first element in the set and returns a
+ *              pointer to it. If the set is empty a NULL pointer 
+ *              is returned.
+ *
+ *      Accesses outside variables:     none
+ */
+
+void *
+SP_deletemin (Splay_Tree * S)
+{
+  node *tmp;
+  char *dat;
+
+  dat = SP_get_first (S);
+  if (dat)
+    {
+      tmp = (node *) S->root;
+      S->root = (char *) tmp->rght;
+      if (S->root)
+	((node *) S->root)->par = NULL;
+    }
+  S->no_of_items--;
+  return dat;
+}				/* deletemin() */
+
+
+/*
+ *    member():
+ *              searches the given set for an item which matches (has
+ *              the same key) and returns a pointer to a copy of that item.
+ *              If no matching item is found a NULL pointer is 
+ *              returned.
+ *
+ *      Accesses outside variables:     none
+ */
+
+void *
+SP_member (void *dat, Splay_Tree * S)
+{
+  register node *curr;
+  register int dir;
+  static int calls = 0;
+
+  TRACE ("in member");
+  for (curr = (node *) S->root; curr;)
+    {
+      TRACE ("call to cmp");
+      dir = S->cmp (dat, curr->datsun);
+      TRACE ("out of cmp");
+      if (dir < 0)
+	curr = curr->left;
+      else if (dir > 0)
+	curr = curr->rght;
+      else
+	{
+	  /* splay occasionaly to speed up execution */
+	  if ((calls++ % 4) == 0 && curr)
+	    S->root = (char *) SP_splay (curr);
+	  TRACE ("out of member");
+	  return (curr->datsun);
+	}
+    }
+  TRACE ("out of member");
+  return (CNULL);
+}				/* member() */
+
+#define	ROTATEL(p,q) 					\
+	do{						\
+		p->par = q->par;			\
+		q->par = p;				\
+		q->rght = p->left;			\
+		if(q->rght)				\
+			q->rght->par = q;		\
+		p->left = q;				\
+		if(p->par)				\
+			if(q == p->par->left)		\
+				p->par->left = p;	\
+			else				\
+				p->par->rght = p;	\
+	}while(0)
+
+#define	ROTATER(p,q) 					\
+	do{						\
+		p->par = q->par;			\
+		q->par = p;				\
+		q->left = p->rght;			\
+		if(q->left)				\
+			q->left->par = q;		\
+		p->rght = q;				\
+		if(p->par)				\
+			if(q == p->par->left)		\
+				p->par->left = p;	\
+			else				\
+				p->par->rght = p;	\
+	}while(0)
+
+
+/*
+ *    splay():
+ *              i
+ *
+ *      Accesses outside variables:     i
+ *
+ *      Return value...:                i
+ */
+
+static node *
+SP_splay (p)
+     register node *p;
+{
+  register node *q, *g;
+
+  q = p->par;
+  /* splay the tree about p */
+  while (q != NNULL)
+    {
+      g = q->par;
+      if (p == q->left)
+	{
+	  if (g == NNULL)
+	    ROTATER (p, q);
+	  else if (q == g->left)
+	    {
+	      ROTATER (q, g);
+	      ROTATER (p, q);
+	    }
+	  else
+	    {
+	      ROTATER (p, q);
+	      ROTATEL (p, g);
+	    }
+	}
+      else
+	{
+	  if (g == NNULL)
+	    ROTATEL (p, q);
+	  else if (q == g->rght)
+	    {
+	      ROTATEL (q, g);
+	      ROTATEL (p, q);
+	    }
+	  else
+	    {
+	      ROTATEL (p, q);
+	      ROTATER (p, g);
+	    }
+	}
+      q = p->par;
+    }
+  return (p);
+}
Index: /main/tags/2.25/gsdl/packages/mg/lib/sptree.h
===================================================================
--- /main/tags/2.25/gsdl/packages/mg/lib/sptree.h	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/mg/lib/sptree.h	(revision 21064)
@@ -0,0 +1,47 @@
+/**************************************************************************
+ *
+ * sptree.h -- Splay tree code
+ * Copyright (C) 1994  Gary Eddy and Neil Sharman
+ *
+ * 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.
+ *
+ * $Id$
+ *
+ **************************************************************************/
+
+
+#ifndef SPTREE_H
+#define SPTREE_H
+
+typedef struct set_rec Splay_Tree;
+
+struct set_rec
+  {
+    int no_of_items;
+    unsigned long mem_in_use;
+    int (*cmp) (void *, void *);
+    void *root;
+    void *pool;
+    int pool_chunks;
+  };
+
+Splay_Tree *SP_createset (int (*cmp) (void *, void *));
+void *SP_insert (void *item, Splay_Tree * S);
+void *SP_get_first (Splay_Tree * S);
+void *SP_get_next (Splay_Tree * S);
+void *SP_deletemin (Splay_Tree * S);
+void *SP_member (void *dat, Splay_Tree * S);
+void SP_freeset (Splay_Tree * S);
+#endif
Index: /main/tags/2.25/gsdl/packages/mg/lib/strcasecmp.c
===================================================================
--- /main/tags/2.25/gsdl/packages/mg/lib/strcasecmp.c	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/mg/lib/strcasecmp.c	(revision 21064)
@@ -0,0 +1,74 @@
+/*
+ * Copyright (c) 1987 Regents of the University of California.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms are permitted
+ * provided that this notice is preserved and that due credit is given
+ * to the University of California at Berkeley. The name of the University
+ * may not be used to endorse or promote products derived from this
+ * software without specific written prior permission. This software
+ * is provided ``as is'' without express or implied warranty.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static char sccsid[] = "@(#)strcasecmp.c	5.5 (Berkeley) 11/24/87";
+#endif /* LIBC_SCCS and not lint */
+
+/*
+ * This array is designed for mapping upper and lower case letter
+ * together for a case independent comparison.  The mappings are
+ * based upon ascii character sequences.
+ */
+static unsigned char charmap[] = {
+	'\000', '\001', '\002', '\003', '\004', '\005', '\006', '\007',
+	'\010', '\011', '\012', '\013', '\014', '\015', '\016', '\017',
+	'\020', '\021', '\022', '\023', '\024', '\025', '\026', '\027',
+	'\030', '\031', '\032', '\033', '\034', '\035', '\036', '\037',
+	'\040', '\041', '\042', '\043', '\044', '\045', '\046', '\047',
+	'\050', '\051', '\052', '\053', '\054', '\055', '\056', '\057',
+	'\060', '\061', '\062', '\063', '\064', '\065', '\066', '\067',
+	'\070', '\071', '\072', '\073', '\074', '\075', '\076', '\077',
+	'\100', '\141', '\142', '\143', '\144', '\145', '\146', '\147',
+	'\150', '\151', '\152', '\153', '\154', '\155', '\156', '\157',
+	'\160', '\161', '\162', '\163', '\164', '\165', '\166', '\167',
+	'\170', '\171', '\172', '\133', '\134', '\135', '\136', '\137',
+	'\140', '\141', '\142', '\143', '\144', '\145', '\146', '\147',
+	'\150', '\151', '\152', '\153', '\154', '\155', '\156', '\157',
+	'\160', '\161', '\162', '\163', '\164', '\165', '\166', '\167',
+	'\170', '\171', '\172', '\173', '\174', '\175', '\176', '\177',
+	'\200', '\201', '\202', '\203', '\204', '\205', '\206', '\207',
+	'\210', '\211', '\212', '\213', '\214', '\215', '\216', '\217',
+	'\220', '\221', '\222', '\223', '\224', '\225', '\226', '\227',
+	'\230', '\231', '\232', '\233', '\234', '\235', '\236', '\237',
+	'\240', '\241', '\242', '\243', '\244', '\245', '\246', '\247',
+	'\250', '\251', '\252', '\253', '\254', '\255', '\256', '\257',
+	'\260', '\261', '\262', '\263', '\264', '\265', '\266', '\267',
+	'\270', '\271', '\272', '\273', '\274', '\275', '\276', '\277',
+	'\300', '\341', '\342', '\343', '\344', '\345', '\346', '\347',
+	'\350', '\351', '\352', '\353', '\354', '\355', '\356', '\357',
+	'\360', '\361', '\362', '\363', '\364', '\365', '\366', '\367',
+	'\370', '\371', '\372', '\333', '\334', '\335', '\336', '\337',
+	'\340', '\341', '\342', '\343', '\344', '\345', '\346', '\347',
+	'\350', '\351', '\352', '\353', '\354', '\355', '\356', '\357',
+	'\360', '\361', '\362', '\363', '\364', '\365', '\366', '\367',
+	'\370', '\371', '\372', '\373', '\374', '\375', '\376', '\377',
+};
+
+int
+strcasecmp(s1, s2)
+    char *s1, *s2;
+{
+    register unsigned char u1, u2;
+
+    for (;;) {
+	u1 = (unsigned char) *s1++;
+	u2 = (unsigned char) *s2++;
+	if (charmap[u1] != charmap[u2]) {
+	    return charmap[u1] - charmap[u2];
+	}
+	if (u1 == '\0') {
+	    return 0;
+	}
+    }
+}
+
Index: /main/tags/2.25/gsdl/packages/mg/lib/strstr.c
===================================================================
--- /main/tags/2.25/gsdl/packages/mg/lib/strstr.c	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/mg/lib/strstr.c	(revision 21064)
@@ -0,0 +1,44 @@
+/* strstr.c -- return the offset of one string within another
+   Copyright (C) 1989, 1990 Free Software Foundation, Inc.
+
+   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, 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.  */
+
+/* Written by Mike Rendell <michael@cs.mun.ca>.  */
+
+/* Return the starting address of string S2 in S1;
+   return 0 if it is not found. */
+
+char *
+strstr (s1, s2)
+     char *s1;
+     char *s2;
+{
+  int i;
+  char *p1;
+  char *p2;
+  char *s = s1;
+
+  for (p2 = s2, i = 0; *s; p2 = s2, i++, s++)
+    {
+      for (p1 = s; *p1 && *p2 && *p1 == *p2; p1++, p2++)
+	;
+      if (!*p2)
+	break;
+    }
+  if (!*p2)
+    return s1 + i;
+
+  return 0;
+}
Index: /main/tags/2.25/gsdl/packages/mg/lib/timing.c
===================================================================
--- /main/tags/2.25/gsdl/packages/mg/lib/timing.c	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/mg/lib/timing.c	(revision 21064)
@@ -0,0 +1,234 @@
+/**************************************************************************
+ *
+ * timing.c -- Program timing routines
+ * Copyright (C) 1994  Neil Sharman
+ *
+ * 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.
+ *
+ * $Id$
+ *
+ **************************************************************************/
+
+/*
+   $Log$
+   Revision 1.1  1999/08/10 21:17:05  sjboddie
+   renamed mg-1.3d directory mg
+
+   Revision 1.1  1998/11/17 09:32:49  rjmcnab
+   *** empty log message ***
+
+   * Revision 1.1  1994/08/22  00:24:53  tes
+   * Initial placement under CVS.
+   *
+ */
+
+static char *RCSID = "$Id$";
+
+#include "sysfuncs.h"
+#include "timing.h"
+
+
+/*
+ * Return the time in seconds since 00:00:00 GMT, Jan. 1, 1970 to the
+ * best precision possible
+ *
+ */
+double 
+RealTime (void)
+{
+  return ((double) time (NULL));
+}
+
+
+
+/*
+ * Return the amount of system and user CPU used by the process to date to 
+ * the best precision possible. If user is non-null then it is initialised to 
+ * the user time. If sys is non-null then it is initialised to the system time.
+ *
+ */
+double 
+CPUTime (double *user, double *sys)
+{
+
+#if defined(HAVE_TIMES)
+
+  struct tms buffer;
+  static double clk_tck = 0;
+  double u, s;
+
+  times (&buffer);
+
+  if (clk_tck == 0)
+    clk_tck = CLK_TCK;
+
+  u = (double) buffer.tms_utime / clk_tck;
+  s = (double) buffer.tms_stime / clk_tck;
+  if (user)
+    *user = u;
+  if (sys)
+    *sys = s;
+  return u + s;
+
+#elif defined(HAVE_GETRUSAGE)
+
+  struct rusage ruse;
+  getrusage (RUSAGE_SELF, &ruse);
+  if (user)
+    *user = (double) ruse.ru_utime.tv_sec +
+      (double) ruse.ru_utime.tv_usec / 1000000;
+  if (sys)
+    *sys = (double) ruse.ru_stime.tv_sec +
+      (double) ruse.ru_stime.tv_usec / 1000000;
+  return ((double) ruse.ru_utime.tv_sec + ruse.ru_stime.tv_sec +
+	((double) ruse.ru_utime.tv_usec + ruse.ru_stime.tv_usec) / 1000000);
+
+#else
+
+  /* [RPAP - Feb 97: WIN32 Port] */
+#ifdef __WIN32__
+  if (user) *user = 0.0;
+  if (sys) *sys = 0.0;
+  return 0.0;
+#else
+  -->Can NOT find a system time routine to use ! !!
+#endif  /* __WIN32__ */
+
+#endif
+
+}
+
+
+
+
+/*
+ * Get the Real and CPU time and store them in a ProgTime structure
+ */
+void 
+GetTime (ProgTime * StartTime)
+{
+  StartTime->RealTime = RealTime ();
+  StartTime->CPUTime = CPUTime (NULL, NULL);
+}
+
+
+
+
+/*
+ * Display the Real and CPU time elapsed since the StartTime anf FinishTime 
+ * structures were initialised. If FinishTime is NULL then FinishTime is
+ * Now.
+ */
+char *
+ElapsedTime (ProgTime * StartTime,
+	     ProgTime * FinishTime)
+{
+  static char buf[50];
+  double Real, CPU, hour, min, sec;
+  if (!FinishTime)
+    {
+      Real = RealTime () - StartTime->RealTime;
+      CPU = CPUTime (NULL, NULL) - StartTime->CPUTime;
+    }
+  else
+    {
+      Real = FinishTime->RealTime - StartTime->RealTime;
+      CPU = FinishTime->CPUTime - StartTime->CPUTime;
+    }
+  hour = floor (CPU / 3600);
+  min = floor ((CPU - hour * 3600) / 60);
+  sec = CPU - hour * 3600 - min * 60;
+  sprintf (buf, "%02.0f:%02.0f:%05.2f cpu, %02d:%02d:%02d elapsed.",
+	   hour, min, sec,
+	   ((int) ceil (Real)) / 3600,
+	   (((int) ceil (Real)) % 3600) / 60, ((int) ceil (Real)) % 60);
+  return (buf);
+}
+
+
+#define MILLION 1000000
+
+/* ===============================================================================
+ * Function: cputime_string
+ * Description:
+ *      Prints out given cpu time into a string buffer.
+ * Input: cpu-time in clock_t or timeval format
+ * Output: pointer to internal buffer 
+ * =============================================================================== */
+
+#ifdef HAVE_TIMES
+char *
+cputime_string (clock_t clk)
+{
+  static char buf[15];
+  double CPU, hour, min, sec;
+
+  CPU = (double) clk / (double) CLK_TCK;
+  hour = floor (CPU / 3600);
+  min = floor ((CPU - hour * 3600) / 60);
+  sec = CPU - hour * 3600 - min * 60;
+  sprintf (buf, "%02.0f:%02.0f:%05.2f", hour, min, sec);
+  return (buf);
+}
+#else
+char *
+cputime_string (struct timeval *t)
+{
+  static char buf[15];
+  double CPU, hour, min, sec;
+
+  CPU = (double) t->tv_sec + (double) t->tv_usec / MILLION;
+  hour = floor (CPU / 3600);
+  min = floor ((CPU - hour * 3600) / 60);
+  sec = CPU - hour * 3600 - min * 60;
+  sprintf (buf, "%02.0f:%02.0f:%05.2f", hour, min, sec);
+  return (buf);
+}
+#endif
+
+
+
+/* ===============================================================================
+ * Function: time_normalise
+ * Description:
+ *      If the micro-second component is negative or over a million,
+ *      then must take the over/under flow and add it to the second component.
+ * Usage:
+ *      Use this routine when you have just been doing straight addition and
+ *      subtraction on the micro-second component. For this could lead to a
+ *      negative number or over a million.
+ *
+ * =============================================================================== */
+
+#ifndef HAVE_TIMES
+
+#ifndef __WIN32__  /* [RPAP - Feb 97: WIN32 Port] */
+static 
+#endif
+void
+time_normalise (struct timeval *t)
+{
+  while (t->tv_usec < 0)
+    {
+      t->tv_usec += MILLION;
+      t->tv_sec--;
+    }
+  while (t->tv_usec > MILLION)
+    {
+      t->tv_usec -= MILLION;
+      t->tv_sec++;
+    }
+}
+#endif
Index: /main/tags/2.25/gsdl/packages/mg/lib/timing.h
===================================================================
--- /main/tags/2.25/gsdl/packages/mg/lib/timing.h	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/mg/lib/timing.h	(revision 21064)
@@ -0,0 +1,75 @@
+/**************************************************************************
+ *
+ * timing.h -- Program timing routines
+ * Copyright (C) 1994  Neil Sharman
+ *
+ * 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.
+ *
+ * $Id$
+ *
+ **************************************************************************/
+
+#ifndef H_TIMING
+#define H_TIMING
+
+
+#ifdef HAVE_TIMES
+# if TIME_WITH_SYS_TIME
+#  include <sys/times.h>
+#  include <time.h>
+#  ifndef CLK_TCK
+#   define CLK_TCK sysconf(_SC_CLK_TCK)
+#  endif
+# else
+#  if HAVE_SYS_TIME_H
+#   include <sys/time.h>
+#  else
+#   include <time.h>
+#  endif
+# endif
+#else
+/* [RPAP - Feb 97: WIN32 Port] */
+# ifdef __WIN32__
+   struct timeval { long tv_sec, tv_usec; };
+# else
+#  include <sys/time.h>
+#  include <sys/resource.h>
+# endif
+#endif
+
+
+typedef struct
+  {
+    double RealTime, CPUTime;
+  }
+ProgTime;
+
+double RealTime (void);
+
+double CPUTime (double *user, double *sys);
+
+void GetTime (ProgTime * StartTime);
+
+/* FinishTime may be NULL */
+char *ElapsedTime (ProgTime * StartTime, ProgTime * FinishTime);
+
+#ifdef HAVE_TIMES
+char *cputime_string (clock_t clk);
+#else
+void time_normalise (struct timeval *t);
+char *cputime_string (struct timeval *t);
+#endif
+
+#endif
Index: /main/tags/2.25/gsdl/packages/mg/lib/unitool.c
===================================================================
--- /main/tags/2.25/gsdl/packages/mg/lib/unitool.c	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/mg/lib/unitool.c	(revision 21064)
@@ -0,0 +1,1756 @@
+#include "unitool.h"
+#include "sysfuncs.h"
+
+
+/* unicode_cat_data is a combination of the letter, digit, and
+ * space information in a form that is quick to look up.
+ * The information about each byte is stored in two bits
+ *
+ * 00 - neither letter, digit or space
+ * 01 - letter
+ * 10 - space
+ * 11 - digit
+ *
+ * You can test for letter | space by looking at the right
+ * column
+ */
+unsigned long *unicode_cat_data=NULL;
+
+
+typedef struct unidecompose {
+  unsigned short ch;
+  unsigned short str[3];
+} unidecompose;
+
+typedef struct unirelate {
+  unsigned short ch1;
+  unsigned short ch2;
+} unirelate;
+
+typedef struct unirange {
+  unsigned short first;
+  unsigned short last;
+} unirange;
+
+
+
+/* This decomposition data only includes canonical decompositional
+ * characters.  Any unused bytes are set to 0x0. */
+
+#define NUM_DECOMPOSE_INFO 1269
+static const unidecompose decompose_info[NUM_DECOMPOSE_INFO] = {
+  {0xC0,0x41,0x300,0x0}, {0xC1,0x41,0x301,0x0}, {0xC2,0x41,0x302,0x0}, 
+  {0xC3,0x41,0x303,0x0}, {0xC4,0x41,0x308,0x0}, {0xC5,0x41,0x30A,0x0}, 
+  {0xC7,0x43,0x327,0x0}, {0xC8,0x45,0x300,0x0}, {0xC9,0x45,0x301,0x0}, 
+  {0xCA,0x45,0x302,0x0}, {0xCB,0x45,0x308,0x0}, {0xCC,0x49,0x300,0x0}, 
+  {0xCD,0x49,0x301,0x0}, {0xCE,0x49,0x302,0x0}, {0xCF,0x49,0x308,0x0}, 
+  {0xD1,0x4E,0x303,0x0}, {0xD2,0x4F,0x300,0x0}, {0xD3,0x4F,0x301,0x0}, 
+  {0xD4,0x4F,0x302,0x0}, {0xD5,0x4F,0x303,0x0}, {0xD6,0x4F,0x308,0x0}, 
+  {0xD9,0x55,0x300,0x0}, {0xDA,0x55,0x301,0x0}, {0xDB,0x55,0x302,0x0}, 
+  {0xDC,0x55,0x308,0x0}, {0xDD,0x59,0x301,0x0}, {0xE0,0x61,0x300,0x0}, 
+  {0xE1,0x61,0x301,0x0}, {0xE2,0x61,0x302,0x0}, {0xE3,0x61,0x303,0x0}, 
+  {0xE4,0x61,0x308,0x0}, {0xE5,0x61,0x30A,0x0}, {0xE7,0x63,0x327,0x0}, 
+  {0xE8,0x65,0x300,0x0}, {0xE9,0x65,0x301,0x0}, {0xEA,0x65,0x302,0x0}, 
+  {0xEB,0x65,0x308,0x0}, {0xEC,0x69,0x300,0x0}, {0xED,0x69,0x301,0x0}, 
+  {0xEE,0x69,0x302,0x0}, {0xEF,0x69,0x308,0x0}, {0xF1,0x6E,0x303,0x0}, 
+  {0xF2,0x6F,0x300,0x0}, {0xF3,0x6F,0x301,0x0}, {0xF4,0x6F,0x302,0x0}, 
+  {0xF5,0x6F,0x303,0x0}, {0xF6,0x6F,0x308,0x0}, {0xF9,0x75,0x300,0x0}, 
+  {0xFA,0x75,0x301,0x0}, {0xFB,0x75,0x302,0x0}, {0xFC,0x75,0x308,0x0}, 
+  {0xFD,0x79,0x301,0x0}, {0xFF,0x79,0x308,0x0}, {0x100,0x41,0x304,0x0}, 
+  {0x101,0x61,0x304,0x0}, {0x102,0x41,0x306,0x0}, {0x103,0x61,0x306,0x0}, 
+  {0x104,0x41,0x328,0x0}, {0x105,0x61,0x328,0x0}, {0x106,0x43,0x301,0x0}, 
+  {0x107,0x63,0x301,0x0}, {0x108,0x43,0x302,0x0}, {0x109,0x63,0x302,0x0}, 
+  {0x10A,0x43,0x307,0x0}, {0x10B,0x63,0x307,0x0}, {0x10C,0x43,0x30C,0x0}, 
+  {0x10D,0x63,0x30C,0x0}, {0x10E,0x44,0x30C,0x0}, {0x10F,0x64,0x30C,0x0}, 
+  {0x112,0x45,0x304,0x0}, {0x113,0x65,0x304,0x0}, {0x114,0x45,0x306,0x0}, 
+  {0x115,0x65,0x306,0x0}, {0x116,0x45,0x307,0x0}, {0x117,0x65,0x307,0x0}, 
+  {0x118,0x45,0x328,0x0}, {0x119,0x65,0x328,0x0}, {0x11A,0x45,0x30C,0x0}, 
+  {0x11B,0x65,0x30C,0x0}, {0x11C,0x47,0x302,0x0}, {0x11D,0x67,0x302,0x0}, 
+  {0x11E,0x47,0x306,0x0}, {0x11F,0x67,0x306,0x0}, {0x120,0x47,0x307,0x0}, 
+  {0x121,0x67,0x307,0x0}, {0x122,0x47,0x327,0x0}, {0x123,0x67,0x327,0x0}, 
+  {0x124,0x48,0x302,0x0}, {0x125,0x68,0x302,0x0}, {0x128,0x49,0x303,0x0}, 
+  {0x129,0x69,0x303,0x0}, {0x12A,0x49,0x304,0x0}, {0x12B,0x69,0x304,0x0}, 
+  {0x12C,0x49,0x306,0x0}, {0x12D,0x69,0x306,0x0}, {0x12E,0x49,0x328,0x0}, 
+  {0x12F,0x69,0x328,0x0}, {0x130,0x49,0x307,0x0}, {0x134,0x4A,0x302,0x0}, 
+  {0x135,0x6A,0x302,0x0}, {0x136,0x4B,0x327,0x0}, {0x137,0x6B,0x327,0x0}, 
+  {0x139,0x4C,0x301,0x0}, {0x13A,0x6C,0x301,0x0}, {0x13B,0x4C,0x327,0x0}, 
+  {0x13C,0x6C,0x327,0x0}, {0x13D,0x4C,0x30C,0x0}, {0x13E,0x6C,0x30C,0x0}, 
+  {0x143,0x4E,0x301,0x0}, {0x144,0x6E,0x301,0x0}, {0x145,0x4E,0x327,0x0}, 
+  {0x146,0x6E,0x327,0x0}, {0x147,0x4E,0x30C,0x0}, {0x148,0x6E,0x30C,0x0}, 
+  {0x14C,0x4F,0x304,0x0}, {0x14D,0x6F,0x304,0x0}, {0x14E,0x4F,0x306,0x0}, 
+  {0x14F,0x6F,0x306,0x0}, {0x150,0x4F,0x30B,0x0}, {0x151,0x6F,0x30B,0x0}, 
+  {0x154,0x52,0x301,0x0}, {0x155,0x72,0x301,0x0}, {0x156,0x52,0x327,0x0}, 
+  {0x157,0x72,0x327,0x0}, {0x158,0x52,0x30C,0x0}, {0x159,0x72,0x30C,0x0}, 
+  {0x15A,0x53,0x301,0x0}, {0x15B,0x73,0x301,0x0}, {0x15C,0x53,0x302,0x0}, 
+  {0x15D,0x73,0x302,0x0}, {0x15E,0x53,0x327,0x0}, {0x15F,0x73,0x327,0x0}, 
+  {0x160,0x53,0x30C,0x0}, {0x161,0x73,0x30C,0x0}, {0x162,0x54,0x327,0x0}, 
+  {0x163,0x74,0x327,0x0}, {0x164,0x54,0x30C,0x0}, {0x165,0x74,0x30C,0x0}, 
+  {0x168,0x55,0x303,0x0}, {0x169,0x75,0x303,0x0}, {0x16A,0x55,0x304,0x0}, 
+  {0x16B,0x75,0x304,0x0}, {0x16C,0x55,0x306,0x0}, {0x16D,0x75,0x306,0x0}, 
+  {0x16E,0x55,0x30A,0x0}, {0x16F,0x75,0x30A,0x0}, {0x170,0x55,0x30B,0x0}, 
+  {0x171,0x75,0x30B,0x0}, {0x172,0x55,0x328,0x0}, {0x173,0x75,0x328,0x0}, 
+  {0x174,0x57,0x302,0x0}, {0x175,0x77,0x302,0x0}, {0x176,0x59,0x302,0x0}, 
+  {0x177,0x79,0x302,0x0}, {0x178,0x59,0x308,0x0}, {0x179,0x5A,0x301,0x0}, 
+  {0x17A,0x7A,0x301,0x0}, {0x17B,0x5A,0x307,0x0}, {0x17C,0x7A,0x307,0x0}, 
+  {0x17D,0x5A,0x30C,0x0}, {0x17E,0x7A,0x30C,0x0}, {0x1A0,0x4F,0x31B,0x0}, 
+  {0x1A1,0x6F,0x31B,0x0}, {0x1AF,0x55,0x31B,0x0}, {0x1B0,0x75,0x31B,0x0}, 
+  {0x1CD,0x41,0x30C,0x0}, {0x1CE,0x61,0x30C,0x0}, {0x1CF,0x49,0x30C,0x0}, 
+  {0x1D0,0x69,0x30C,0x0}, {0x1D1,0x4F,0x30C,0x0}, {0x1D2,0x6F,0x30C,0x0}, 
+  {0x1D3,0x55,0x30C,0x0}, {0x1D4,0x75,0x30C,0x0}, {0x1D5,0xDC,0x304,0x0}, 
+  {0x1D6,0xFC,0x304,0x0}, {0x1D7,0xDC,0x301,0x0}, {0x1D8,0xFC,0x301,0x0}, 
+  {0x1D9,0xDC,0x30C,0x0}, {0x1DA,0xFC,0x30C,0x0}, {0x1DB,0xDC,0x300,0x0}, 
+  {0x1DC,0xFC,0x300,0x0}, {0x1DE,0xC4,0x304,0x0}, {0x1DF,0xE4,0x304,0x0}, 
+  {0x1E0,0x41,0x307,0x304}, {0x1E1,0x61,0x307,0x304}, {0x1E2,0xC6,0x304,0x0}, 
+  {0x1E3,0xE6,0x304,0x0}, {0x1E6,0x47,0x30C,0x0}, {0x1E7,0x67,0x30C,0x0}, 
+  {0x1E8,0x4B,0x30C,0x0}, {0x1E9,0x6B,0x30C,0x0}, {0x1EA,0x4F,0x328,0x0}, 
+  {0x1EB,0x6F,0x328,0x0}, {0x1EC,0x1EA,0x304,0x0}, {0x1ED,0x1EB,0x304,0x0}, 
+  {0x1EE,0x1B7,0x30C,0x0}, {0x1EF,0x292,0x30C,0x0}, {0x1F0,0x6A,0x30C,0x0}, 
+  {0x1F4,0x47,0x301,0x0}, {0x1F5,0x67,0x301,0x0}, {0x1FA,0xC5,0x301,0x0}, 
+  {0x1FB,0xE5,0x301,0x0}, {0x1FC,0xC6,0x301,0x0}, {0x1FD,0xE6,0x301,0x0}, 
+  {0x1FE,0xD8,0x301,0x0}, {0x1FF,0xF8,0x301,0x0}, {0x200,0x41,0x30F,0x0}, 
+  {0x201,0x61,0x30F,0x0}, {0x202,0x41,0x311,0x0}, {0x203,0x61,0x311,0x0}, 
+  {0x204,0x45,0x30F,0x0}, {0x205,0x65,0x30F,0x0}, {0x206,0x45,0x311,0x0}, 
+  {0x207,0x65,0x311,0x0}, {0x208,0x49,0x30F,0x0}, {0x209,0x69,0x30F,0x0}, 
+  {0x20A,0x49,0x311,0x0}, {0x20B,0x69,0x311,0x0}, {0x20C,0x4F,0x30F,0x0}, 
+  {0x20D,0x6F,0x30F,0x0}, {0x20E,0x4F,0x311,0x0}, {0x20F,0x6F,0x311,0x0}, 
+  {0x210,0x52,0x30F,0x0}, {0x211,0x72,0x30F,0x0}, {0x212,0x52,0x311,0x0}, 
+  {0x213,0x72,0x311,0x0}, {0x214,0x55,0x30F,0x0}, {0x215,0x75,0x30F,0x0}, 
+  {0x216,0x55,0x311,0x0}, {0x217,0x75,0x311,0x0}, {0x310,0x306,0x307,0x0}, 
+  {0x340,0x300,0x0,0x0}, {0x341,0x301,0x0,0x0}, {0x343,0x313,0x0,0x0}, 
+  {0x344,0x308,0x30D,0x0}, {0x374,0x2B9,0x0,0x0}, {0x37E,0x3B,0x0,0x0}, 
+  {0x385,0xA8,0x30D,0x0}, {0x386,0x391,0x30D,0x0}, {0x387,0xB7,0x0,0x0}, 
+  {0x388,0x395,0x30D,0x0}, {0x389,0x397,0x30D,0x0}, {0x38A,0x399,0x30D,0x0}, 
+  {0x38C,0x39F,0x30D,0x0}, {0x38E,0x3A5,0x30D,0x0}, {0x38F,0x3A9,0x30D,0x0}, 
+  {0x390,0x3B9,0x344,0x0}, {0x3AA,0x399,0x308,0x0}, {0x3AB,0x3A5,0x308,0x0}, 
+  {0x3AC,0x3B1,0x30D,0x0}, {0x3AD,0x3B5,0x30D,0x0}, {0x3AE,0x3B7,0x30D,0x0}, 
+  {0x3AF,0x3B9,0x30D,0x0}, {0x3B0,0x3C5,0x344,0x0}, {0x3CA,0x3B9,0x308,0x0}, 
+  {0x3CB,0x3C5,0x308,0x0}, {0x3CC,0x3BF,0x30D,0x0}, {0x3CD,0x3C5,0x30D,0x0}, 
+  {0x3CE,0x3C9,0x30D,0x0}, {0x3D3,0x3D2,0x30D,0x0}, {0x3D4,0x3D2,0x308,0x0}, 
+  {0x401,0x415,0x308,0x0}, {0x403,0x413,0x301,0x0}, {0x407,0x406,0x308,0x0}, 
+  {0x40C,0x41A,0x301,0x0}, {0x40E,0x423,0x306,0x0}, {0x419,0x418,0x306,0x0}, 
+  {0x439,0x438,0x306,0x0}, {0x451,0x435,0x308,0x0}, {0x453,0x433,0x301,0x0}, 
+  {0x457,0x456,0x308,0x0}, {0x45C,0x43A,0x301,0x0}, {0x45E,0x443,0x306,0x0}, 
+  {0x476,0x474,0x30F,0x0}, {0x477,0x475,0x30F,0x0}, {0x4C1,0x416,0x306,0x0}, 
+  {0x4C2,0x436,0x306,0x0}, {0x4D0,0x410,0x306,0x0}, {0x4D1,0x430,0x306,0x0}, 
+  {0x4D2,0x410,0x308,0x0}, {0x4D3,0x430,0x308,0x0}, {0x4D6,0x415,0x306,0x0}, 
+  {0x4D7,0x435,0x306,0x0}, {0x4DA,0x4D8,0x308,0x0}, {0x4DB,0x4D9,0x308,0x0}, 
+  {0x4DC,0x416,0x308,0x0}, {0x4DD,0x436,0x308,0x0}, {0x4DE,0x417,0x308,0x0}, 
+  {0x4DF,0x437,0x308,0x0}, {0x4E2,0x418,0x304,0x0}, {0x4E3,0x438,0x304,0x0}, 
+  {0x4E4,0x418,0x308,0x0}, {0x4E5,0x438,0x308,0x0}, {0x4E6,0x41E,0x308,0x0}, 
+  {0x4E7,0x43E,0x308,0x0}, {0x4EA,0x4E8,0x308,0x0}, {0x4EB,0x4E9,0x308,0x0}, 
+  {0x4EE,0x423,0x304,0x0}, {0x4EF,0x443,0x304,0x0}, {0x4F0,0x423,0x308,0x0}, 
+  {0x4F1,0x443,0x308,0x0}, {0x4F2,0x423,0x30B,0x0}, {0x4F3,0x443,0x30B,0x0}, 
+  {0x4F4,0x427,0x308,0x0}, {0x4F5,0x447,0x308,0x0}, {0x4F8,0x42B,0x308,0x0}, 
+  {0x4F9,0x44B,0x308,0x0}, {0x929,0x928,0x93C,0x0}, {0x931,0x930,0x93C,0x0}, 
+  {0x934,0x933,0x93C,0x0}, {0x958,0x915,0x93C,0x0}, {0x959,0x916,0x93C,0x0}, 
+  {0x95A,0x917,0x93C,0x0}, {0x95B,0x91C,0x93C,0x0}, {0x95C,0x921,0x93C,0x0}, 
+  {0x95D,0x922,0x93C,0x0}, {0x95E,0x92B,0x93C,0x0}, {0x95F,0x92F,0x93C,0x0}, 
+  {0x9B0,0x9AC,0x9BC,0x0}, {0x9CB,0x9C7,0x9BE,0x0}, {0x9CC,0x9C7,0x9D7,0x0}, 
+  {0x9DC,0x9A1,0x9BC,0x0}, {0x9DD,0x9A2,0x9BC,0x0}, {0x9DF,0x9AF,0x9BC,0x0}, 
+  {0xA59,0xA16,0xA3C,0x0}, {0xA5A,0xA17,0xA3C,0x0}, {0xA5B,0xA1C,0xA3C,0x0}, 
+  {0xA5C,0xA21,0xA3C,0x0}, {0xA5E,0xA2B,0xA3C,0x0}, {0xB48,0xB47,0xB56,0x0}, 
+  {0xB4B,0xB47,0xB3E,0x0}, {0xB4C,0xB47,0xB57,0x0}, {0xB5C,0xB21,0xB3C,0x0}, 
+  {0xB5D,0xB22,0xB3C,0x0}, {0xB5F,0xB2F,0xB3C,0x0}, {0xB94,0xB92,0xBD7,0x0}, 
+  {0xBCA,0xBC6,0xBBE,0x0}, {0xBCB,0xBC7,0xBBE,0x0}, {0xBCC,0xBC6,0xBD7,0x0}, 
+  {0xC48,0xC46,0xC56,0x0}, {0xCC0,0xCBF,0xCD5,0x0}, {0xCC7,0xCC6,0xCD5,0x0}, 
+  {0xCC8,0xCC6,0xCD6,0x0}, {0xCCA,0xCC6,0xCC2,0x0}, {0xCCB,0xCC6,0xCC2,0xCD5}, 
+  {0xD4A,0xD46,0xD3E,0x0}, {0xD4B,0xD47,0xD3E,0x0}, {0xD4C,0xD46,0xD57,0x0}, 
+  {0xE33,0xE4D,0xE32,0x0}, {0xEB3,0xECD,0xEB2,0x0}, {0xF43,0xF42,0xFB7,0x0}, 
+  {0xF4D,0xF4C,0xFB7,0x0}, {0xF52,0xF51,0xFB7,0x0}, {0xF57,0xF56,0xFB7,0x0}, 
+  {0xF5C,0xF5B,0xFB7,0x0}, {0xF69,0xF40,0xFB5,0x0}, {0xF73,0xF72,0xF71,0x0}, 
+  {0xF75,0xF71,0xF74,0x0}, {0xF76,0xFB2,0xF80,0x0}, {0xF77,0xF76,0xF71,0x0}, 
+  {0xF78,0xFB3,0xF80,0x0}, {0xF79,0xF78,0xF71,0x0}, {0xF81,0xF80,0xF71,0x0}, 
+  {0xF93,0xF92,0xFB7,0x0}, {0xF9D,0xF9C,0xFB7,0x0}, {0xFA2,0xFA1,0xFB7,0x0}, 
+  {0xFA7,0xFA6,0xFB7,0x0}, {0xFAC,0xFAB,0xFB7,0x0}, {0xFB9,0xF90,0xFB5,0x0}, 
+  {0x1E00,0x41,0x325,0x0}, {0x1E01,0x61,0x325,0x0}, {0x1E02,0x42,0x307,0x0}, 
+  {0x1E03,0x62,0x307,0x0}, {0x1E04,0x42,0x323,0x0}, {0x1E05,0x62,0x323,0x0}, 
+  {0x1E06,0x42,0x331,0x0}, {0x1E07,0x62,0x331,0x0}, {0x1E08,0xC7,0x301,0x0}, 
+  {0x1E09,0xE7,0x301,0x0}, {0x1E0A,0x44,0x307,0x0}, {0x1E0B,0x64,0x307,0x0}, 
+  {0x1E0C,0x44,0x323,0x0}, {0x1E0D,0x64,0x323,0x0}, {0x1E0E,0x44,0x331,0x0}, 
+  {0x1E0F,0x64,0x331,0x0}, {0x1E10,0x44,0x327,0x0}, {0x1E11,0x64,0x327,0x0}, 
+  {0x1E12,0x44,0x32D,0x0}, {0x1E13,0x64,0x32D,0x0}, {0x1E14,0x112,0x300,0x0}, 
+  {0x1E15,0x113,0x300,0x0}, {0x1E16,0x112,0x301,0x0}, {0x1E17,0x113,0x301,0x0}, 
+  {0x1E18,0x45,0x32D,0x0}, {0x1E19,0x65,0x32D,0x0}, {0x1E1A,0x45,0x330,0x0}, 
+  {0x1E1B,0x65,0x330,0x0}, {0x1E1C,0x114,0x327,0x0}, {0x1E1D,0x115,0x327,0x0}, 
+  {0x1E1E,0x46,0x307,0x0}, {0x1E1F,0x66,0x307,0x0}, {0x1E20,0x47,0x304,0x0}, 
+  {0x1E21,0x67,0x304,0x0}, {0x1E22,0x48,0x307,0x0}, {0x1E23,0x68,0x307,0x0}, 
+  {0x1E24,0x48,0x323,0x0}, {0x1E25,0x68,0x323,0x0}, {0x1E26,0x48,0x308,0x0}, 
+  {0x1E27,0x68,0x308,0x0}, {0x1E28,0x48,0x327,0x0}, {0x1E29,0x68,0x327,0x0}, 
+  {0x1E2A,0x48,0x32E,0x0}, {0x1E2B,0x68,0x32E,0x0}, {0x1E2C,0x49,0x330,0x0}, 
+  {0x1E2D,0x69,0x330,0x0}, {0x1E2E,0xCF,0x301,0x0}, {0x1E2F,0xEF,0x301,0x0}, 
+  {0x1E30,0x4B,0x301,0x0}, {0x1E31,0x6B,0x301,0x0}, {0x1E32,0x4B,0x323,0x0}, 
+  {0x1E33,0x6B,0x323,0x0}, {0x1E34,0x4B,0x331,0x0}, {0x1E35,0x6B,0x331,0x0}, 
+  {0x1E36,0x4C,0x323,0x0}, {0x1E37,0x6C,0x323,0x0}, {0x1E38,0x1E36,0x304,0x0}, 
+  {0x1E39,0x1E37,0x304,0x0}, {0x1E3A,0x4C,0x331,0x0}, {0x1E3B,0x6C,0x331,0x0}, 
+  {0x1E3C,0x4C,0x32D,0x0}, {0x1E3D,0x6C,0x32D,0x0}, {0x1E3E,0x4D,0x301,0x0}, 
+  {0x1E3F,0x6D,0x301,0x0}, {0x1E40,0x4D,0x307,0x0}, {0x1E41,0x6D,0x307,0x0}, 
+  {0x1E42,0x4D,0x323,0x0}, {0x1E43,0x6D,0x323,0x0}, {0x1E44,0x4E,0x307,0x0}, 
+  {0x1E45,0x6E,0x307,0x0}, {0x1E46,0x4E,0x323,0x0}, {0x1E47,0x6E,0x323,0x0}, 
+  {0x1E48,0x4E,0x331,0x0}, {0x1E49,0x6E,0x331,0x0}, {0x1E4A,0x4E,0x32D,0x0}, 
+  {0x1E4B,0x6E,0x32D,0x0}, {0x1E4C,0xD5,0x301,0x0}, {0x1E4D,0xF5,0x301,0x0}, 
+  {0x1E4E,0xD5,0x308,0x0}, {0x1E4F,0xF5,0x308,0x0}, {0x1E50,0x14C,0x300,0x0}, 
+  {0x1E51,0x14D,0x300,0x0}, {0x1E52,0x14C,0x301,0x0}, {0x1E53,0x14D,0x301,0x0}, 
+  {0x1E54,0x50,0x301,0x0}, {0x1E55,0x70,0x301,0x0}, {0x1E56,0x50,0x307,0x0}, 
+  {0x1E57,0x70,0x307,0x0}, {0x1E58,0x52,0x307,0x0}, {0x1E59,0x72,0x307,0x0}, 
+  {0x1E5A,0x52,0x323,0x0}, {0x1E5B,0x72,0x323,0x0}, {0x1E5C,0x1E5A,0x304,0x0}, 
+  {0x1E5D,0x1E5B,0x304,0x0}, {0x1E5E,0x52,0x331,0x0}, {0x1E5F,0x72,0x331,0x0}, 
+  {0x1E60,0x53,0x307,0x0}, {0x1E61,0x73,0x307,0x0}, {0x1E62,0x53,0x323,0x0}, 
+  {0x1E63,0x73,0x323,0x0}, {0x1E64,0x15A,0x307,0x0}, {0x1E65,0x15B,0x307,0x0}, 
+  {0x1E66,0x160,0x307,0x0}, {0x1E67,0x161,0x307,0x0}, {0x1E68,0x1E62,0x307,0x0}, 
+  {0x1E69,0x1E63,0x307,0x0}, {0x1E6A,0x54,0x307,0x0}, {0x1E6B,0x74,0x307,0x0}, 
+  {0x1E6C,0x54,0x323,0x0}, {0x1E6D,0x74,0x323,0x0}, {0x1E6E,0x54,0x331,0x0}, 
+  {0x1E6F,0x74,0x331,0x0}, {0x1E70,0x54,0x32D,0x0}, {0x1E71,0x74,0x32D,0x0}, 
+  {0x1E72,0x55,0x324,0x0}, {0x1E73,0x75,0x324,0x0}, {0x1E74,0x55,0x330,0x0}, 
+  {0x1E75,0x75,0x330,0x0}, {0x1E76,0x55,0x32D,0x0}, {0x1E77,0x75,0x32D,0x0}, 
+  {0x1E78,0x168,0x301,0x0}, {0x1E79,0x169,0x301,0x0}, {0x1E7A,0x16A,0x308,0x0}, 
+  {0x1E7B,0x16B,0x308,0x0}, {0x1E7C,0x56,0x303,0x0}, {0x1E7D,0x76,0x303,0x0}, 
+  {0x1E7E,0x56,0x323,0x0}, {0x1E7F,0x76,0x323,0x0}, {0x1E80,0x57,0x300,0x0}, 
+  {0x1E81,0x77,0x300,0x0}, {0x1E82,0x57,0x301,0x0}, {0x1E83,0x77,0x301,0x0}, 
+  {0x1E84,0x57,0x308,0x0}, {0x1E85,0x77,0x308,0x0}, {0x1E86,0x57,0x307,0x0}, 
+  {0x1E87,0x77,0x307,0x0}, {0x1E88,0x57,0x323,0x0}, {0x1E89,0x77,0x323,0x0}, 
+  {0x1E8A,0x58,0x307,0x0}, {0x1E8B,0x78,0x307,0x0}, {0x1E8C,0x58,0x308,0x0}, 
+  {0x1E8D,0x78,0x308,0x0}, {0x1E8E,0x59,0x307,0x0}, {0x1E8F,0x79,0x307,0x0}, 
+  {0x1E90,0x5A,0x302,0x0}, {0x1E91,0x7A,0x302,0x0}, {0x1E92,0x5A,0x323,0x0}, 
+  {0x1E93,0x7A,0x323,0x0}, {0x1E94,0x5A,0x331,0x0}, {0x1E95,0x7A,0x331,0x0}, 
+  {0x1E96,0x68,0x331,0x0}, {0x1E97,0x74,0x308,0x0}, {0x1E98,0x77,0x30A,0x0}, 
+  {0x1E99,0x79,0x30A,0x0}, {0x1E9B,0x17F,0x307,0x0}, {0x1EA0,0x41,0x323,0x0}, 
+  {0x1EA1,0x61,0x323,0x0}, {0x1EA2,0x41,0x309,0x0}, {0x1EA3,0x61,0x309,0x0}, 
+  {0x1EA4,0xC2,0x301,0x0}, {0x1EA5,0xE2,0x301,0x0}, {0x1EA6,0xC2,0x300,0x0}, 
+  {0x1EA7,0xE2,0x300,0x0}, {0x1EA8,0xC2,0x309,0x0}, {0x1EA9,0xE2,0x309,0x0}, 
+  {0x1EAA,0xC2,0x303,0x0}, {0x1EAB,0xE2,0x303,0x0}, {0x1EAC,0xC2,0x323,0x0}, 
+  {0x1EAD,0xE2,0x323,0x0}, {0x1EAE,0x102,0x301,0x0}, {0x1EAF,0x103,0x301,0x0}, 
+  {0x1EB0,0x102,0x300,0x0}, {0x1EB1,0x103,0x300,0x0}, {0x1EB2,0x102,0x309,0x0}, 
+  {0x1EB3,0x103,0x309,0x0}, {0x1EB4,0x102,0x303,0x0}, {0x1EB5,0x103,0x303,0x0}, 
+  {0x1EB6,0x102,0x323,0x0}, {0x1EB7,0x103,0x323,0x0}, {0x1EB8,0x45,0x323,0x0}, 
+  {0x1EB9,0x65,0x323,0x0}, {0x1EBA,0x45,0x309,0x0}, {0x1EBB,0x65,0x309,0x0}, 
+  {0x1EBC,0x45,0x303,0x0}, {0x1EBD,0x65,0x303,0x0}, {0x1EBE,0xCA,0x301,0x0}, 
+  {0x1EBF,0xEA,0x301,0x0}, {0x1EC0,0xCA,0x300,0x0}, {0x1EC1,0xEA,0x300,0x0}, 
+  {0x1EC2,0xCA,0x309,0x0}, {0x1EC3,0xEA,0x309,0x0}, {0x1EC4,0xCA,0x303,0x0}, 
+  {0x1EC5,0xEA,0x303,0x0}, {0x1EC6,0xCA,0x323,0x0}, {0x1EC7,0xEA,0x323,0x0}, 
+  {0x1EC8,0x49,0x309,0x0}, {0x1EC9,0x69,0x309,0x0}, {0x1ECA,0x49,0x323,0x0}, 
+  {0x1ECB,0x69,0x323,0x0}, {0x1ECC,0x4F,0x323,0x0}, {0x1ECD,0x6F,0x323,0x0}, 
+  {0x1ECE,0x4F,0x309,0x0}, {0x1ECF,0x6F,0x309,0x0}, {0x1ED0,0xD4,0x301,0x0}, 
+  {0x1ED1,0xF4,0x301,0x0}, {0x1ED2,0xD4,0x300,0x0}, {0x1ED3,0xF4,0x300,0x0}, 
+  {0x1ED4,0xD4,0x309,0x0}, {0x1ED5,0xF4,0x309,0x0}, {0x1ED6,0xD4,0x303,0x0}, 
+  {0x1ED7,0xF4,0x303,0x0}, {0x1ED8,0xD4,0x323,0x0}, {0x1ED9,0xF4,0x323,0x0}, 
+  {0x1EDA,0x1A0,0x301,0x0}, {0x1EDB,0x1A1,0x301,0x0}, {0x1EDC,0x1A0,0x300,0x0}, 
+  {0x1EDD,0x1A1,0x300,0x0}, {0x1EDE,0x1A0,0x309,0x0}, {0x1EDF,0x1A1,0x309,0x0}, 
+  {0x1EE0,0x1A0,0x303,0x0}, {0x1EE1,0x1A1,0x303,0x0}, {0x1EE2,0x1A0,0x323,0x0}, 
+  {0x1EE3,0x1A1,0x323,0x0}, {0x1EE4,0x55,0x323,0x0}, {0x1EE5,0x75,0x323,0x0}, 
+  {0x1EE6,0x55,0x309,0x0}, {0x1EE7,0x75,0x309,0x0}, {0x1EE8,0x1AF,0x301,0x0}, 
+  {0x1EE9,0x1B0,0x301,0x0}, {0x1EEA,0x1AF,0x300,0x0}, {0x1EEB,0x1B0,0x300,0x0}, 
+  {0x1EEC,0x1AF,0x309,0x0}, {0x1EED,0x1B0,0x309,0x0}, {0x1EEE,0x1AF,0x303,0x0}, 
+  {0x1EEF,0x1B0,0x303,0x0}, {0x1EF0,0x1AF,0x323,0x0}, {0x1EF1,0x1B0,0x323,0x0}, 
+  {0x1EF2,0x59,0x300,0x0}, {0x1EF3,0x79,0x300,0x0}, {0x1EF4,0x59,0x323,0x0}, 
+  {0x1EF5,0x79,0x323,0x0}, {0x1EF6,0x59,0x309,0x0}, {0x1EF7,0x79,0x309,0x0}, 
+  {0x1EF8,0x59,0x303,0x0}, {0x1EF9,0x79,0x303,0x0}, {0x1F00,0x3B1,0x313,0x0}, 
+  {0x1F01,0x3B1,0x314,0x0}, {0x1F02,0x1F00,0x300,0x0}, {0x1F03,0x1F01,0x300,0x0}, 
+  {0x1F04,0x1F00,0x301,0x0}, {0x1F05,0x1F01,0x301,0x0}, {0x1F06,0x1F00,0x342,0x0}, 
+  {0x1F07,0x1F01,0x342,0x0}, {0x1F08,0x391,0x313,0x0}, {0x1F09,0x391,0x314,0x0}, 
+  {0x1F0A,0x1F08,0x300,0x0}, {0x1F0B,0x1F09,0x300,0x0}, {0x1F0C,0x1F08,0x301,0x0}, 
+  {0x1F0D,0x1F09,0x301,0x0}, {0x1F0E,0x1F08,0x342,0x0}, {0x1F0F,0x1F09,0x342,0x0}, 
+  {0x1F10,0x3B5,0x313,0x0}, {0x1F11,0x3B5,0x314,0x0}, {0x1F12,0x1F10,0x300,0x0}, 
+  {0x1F13,0x1F11,0x300,0x0}, {0x1F14,0x1F10,0x301,0x0}, {0x1F15,0x1F11,0x301,0x0}, 
+  {0x1F18,0x395,0x313,0x0}, {0x1F19,0x395,0x314,0x0}, {0x1F1A,0x1F18,0x300,0x0}, 
+  {0x1F1B,0x1F19,0x300,0x0}, {0x1F1C,0x1F18,0x301,0x0}, {0x1F1D,0x1F19,0x301,0x0}, 
+  {0x1F20,0x3B7,0x313,0x0}, {0x1F21,0x3B7,0x314,0x0}, {0x1F22,0x1F20,0x300,0x0}, 
+  {0x1F23,0x1F21,0x300,0x0}, {0x1F24,0x1F20,0x301,0x0}, {0x1F25,0x1F21,0x301,0x0}, 
+  {0x1F26,0x1F20,0x342,0x0}, {0x1F27,0x1F21,0x342,0x0}, {0x1F28,0x397,0x313,0x0}, 
+  {0x1F29,0x397,0x314,0x0}, {0x1F2A,0x1F28,0x300,0x0}, {0x1F2B,0x1F29,0x300,0x0}, 
+  {0x1F2C,0x1F28,0x301,0x0}, {0x1F2D,0x1F29,0x301,0x0}, {0x1F2E,0x1F28,0x342,0x0}, 
+  {0x1F2F,0x1F29,0x342,0x0}, {0x1F30,0x3B9,0x313,0x0}, {0x1F31,0x3B9,0x314,0x0}, 
+  {0x1F32,0x1F30,0x300,0x0}, {0x1F33,0x1F31,0x300,0x0}, {0x1F34,0x1F30,0x301,0x0}, 
+  {0x1F35,0x1F31,0x301,0x0}, {0x1F36,0x1F30,0x342,0x0}, {0x1F37,0x1F31,0x342,0x0}, 
+  {0x1F38,0x399,0x313,0x0}, {0x1F39,0x399,0x314,0x0}, {0x1F3A,0x1F38,0x300,0x0}, 
+  {0x1F3B,0x1F39,0x300,0x0}, {0x1F3C,0x1F38,0x301,0x0}, {0x1F3D,0x1F39,0x301,0x0}, 
+  {0x1F3E,0x1F38,0x342,0x0}, {0x1F3F,0x1F39,0x342,0x0}, {0x1F40,0x3BF,0x313,0x0}, 
+  {0x1F41,0x3BF,0x314,0x0}, {0x1F42,0x1F40,0x300,0x0}, {0x1F43,0x1F41,0x300,0x0}, 
+  {0x1F44,0x1F40,0x301,0x0}, {0x1F45,0x1F41,0x301,0x0}, {0x1F48,0x39F,0x313,0x0}, 
+  {0x1F49,0x39F,0x314,0x0}, {0x1F4A,0x1F48,0x300,0x0}, {0x1F4B,0x1F49,0x300,0x0}, 
+  {0x1F4C,0x1F48,0x301,0x0}, {0x1F4D,0x1F49,0x301,0x0}, {0x1F50,0x3C5,0x313,0x0}, 
+  {0x1F51,0x3C5,0x314,0x0}, {0x1F52,0x1F50,0x300,0x0}, {0x1F53,0x1F51,0x300,0x0}, 
+  {0x1F54,0x1F50,0x301,0x0}, {0x1F55,0x1F51,0x301,0x0}, {0x1F56,0x1F50,0x342,0x0}, 
+  {0x1F57,0x1F51,0x342,0x0}, {0x1F59,0x3A5,0x314,0x0}, {0x1F5B,0x1F59,0x300,0x0}, 
+  {0x1F5D,0x1F59,0x301,0x0}, {0x1F5F,0x1F59,0x342,0x0}, {0x1F60,0x3C9,0x313,0x0}, 
+  {0x1F61,0x3C9,0x314,0x0}, {0x1F62,0x1F60,0x300,0x0}, {0x1F63,0x1F61,0x300,0x0}, 
+  {0x1F64,0x1F60,0x301,0x0}, {0x1F65,0x1F61,0x301,0x0}, {0x1F66,0x1F60,0x342,0x0}, 
+  {0x1F67,0x1F61,0x342,0x0}, {0x1F68,0x3A9,0x313,0x0}, {0x1F69,0x3A9,0x314,0x0}, 
+  {0x1F6A,0x1F68,0x300,0x0}, {0x1F6B,0x1F69,0x300,0x0}, {0x1F6C,0x1F68,0x301,0x0}, 
+  {0x1F6D,0x1F69,0x301,0x0}, {0x1F6E,0x1F68,0x342,0x0}, {0x1F6F,0x1F69,0x342,0x0}, 
+  {0x1F70,0x3B1,0x300,0x0}, {0x1F71,0x3B1,0x301,0x0}, {0x1F72,0x3B5,0x300,0x0}, 
+  {0x1F73,0x3B5,0x301,0x0}, {0x1F74,0x3B7,0x300,0x0}, {0x1F75,0x3B7,0x301,0x0}, 
+  {0x1F76,0x3B9,0x300,0x0}, {0x1F77,0x3B9,0x301,0x0}, {0x1F78,0x3BF,0x300,0x0}, 
+  {0x1F79,0x3BF,0x301,0x0}, {0x1F7A,0x3C5,0x300,0x0}, {0x1F7B,0x3C5,0x301,0x0}, 
+  {0x1F7C,0x3C9,0x300,0x0}, {0x1F7D,0x3C9,0x301,0x0}, {0x1F80,0x1F00,0x345,0x0}, 
+  {0x1F81,0x1F01,0x345,0x0}, {0x1F82,0x1F02,0x345,0x0}, {0x1F83,0x1F03,0x345,0x0}, 
+  {0x1F84,0x1F04,0x345,0x0}, {0x1F85,0x1F05,0x345,0x0}, {0x1F86,0x1F06,0x345,0x0}, 
+  {0x1F87,0x1F07,0x345,0x0}, {0x1F88,0x1F08,0x345,0x0}, {0x1F89,0x1F09,0x345,0x0}, 
+  {0x1F8A,0x1F0A,0x345,0x0}, {0x1F8B,0x1F0B,0x345,0x0}, {0x1F8C,0x1F0C,0x345,0x0}, 
+  {0x1F8D,0x1F0D,0x345,0x0}, {0x1F8E,0x1F0E,0x345,0x0}, {0x1F8F,0x1F0F,0x345,0x0}, 
+  {0x1F90,0x1F20,0x345,0x0}, {0x1F91,0x1F21,0x345,0x0}, {0x1F92,0x1F22,0x345,0x0}, 
+  {0x1F93,0x1F23,0x345,0x0}, {0x1F94,0x1F24,0x345,0x0}, {0x1F95,0x1F25,0x345,0x0}, 
+  {0x1F96,0x1F26,0x345,0x0}, {0x1F97,0x1F27,0x345,0x0}, {0x1F98,0x1F28,0x345,0x0}, 
+  {0x1F99,0x1F29,0x345,0x0}, {0x1F9A,0x1F2A,0x345,0x0}, {0x1F9B,0x1F2B,0x345,0x0}, 
+  {0x1F9C,0x1F2C,0x345,0x0}, {0x1F9D,0x1F2D,0x345,0x0}, {0x1F9E,0x1F2E,0x345,0x0}, 
+  {0x1F9F,0x1F2F,0x345,0x0}, {0x1FA0,0x1F60,0x345,0x0}, {0x1FA1,0x1F61,0x345,0x0}, 
+  {0x1FA2,0x1F62,0x345,0x0}, {0x1FA3,0x1F63,0x345,0x0}, {0x1FA4,0x1F64,0x345,0x0}, 
+  {0x1FA5,0x1F65,0x345,0x0}, {0x1FA6,0x1F66,0x345,0x0}, {0x1FA7,0x1F67,0x345,0x0}, 
+  {0x1FA8,0x1F68,0x345,0x0}, {0x1FA9,0x1F69,0x345,0x0}, {0x1FAA,0x1F6A,0x345,0x0}, 
+  {0x1FAB,0x1F6B,0x345,0x0}, {0x1FAC,0x1F6C,0x345,0x0}, {0x1FAD,0x1F6D,0x345,0x0}, 
+  {0x1FAE,0x1F6E,0x345,0x0}, {0x1FAF,0x1F6F,0x345,0x0}, {0x1FB0,0x3B1,0x306,0x0}, 
+  {0x1FB1,0x3B1,0x304,0x0}, {0x1FB2,0x1F70,0x345,0x0}, {0x1FB3,0x3B1,0x345,0x0}, 
+  {0x1FB4,0x1F71,0x345,0x0}, {0x1FB6,0x3B1,0x342,0x0}, {0x1FB7,0x1FB6,0x345,0x0}, 
+  {0x1FB8,0x391,0x306,0x0}, {0x1FB9,0x391,0x304,0x0}, {0x1FBA,0x391,0x300,0x0}, 
+  {0x1FBB,0x391,0x301,0x0}, {0x1FBC,0x391,0x345,0x0}, {0x1FBE,0x3B9,0x0,0x0}, 
+  {0x1FC1,0xA8,0x342,0x0}, {0x1FC2,0x1F74,0x345,0x0}, {0x1FC3,0x3B7,0x345,0x0}, 
+  {0x1FC4,0x1F75,0x345,0x0}, {0x1FC6,0x3B7,0x342,0x0}, {0x1FC7,0x1FC6,0x345,0x0}, 
+  {0x1FC8,0x395,0x300,0x0}, {0x1FC9,0x395,0x301,0x0}, {0x1FCA,0x397,0x300,0x0}, 
+  {0x1FCB,0x397,0x301,0x0}, {0x1FCC,0x397,0x345,0x0}, {0x1FCD,0x1FBF,0x300,0x0}, 
+  {0x1FCE,0x1FBF,0x301,0x0}, {0x1FCF,0x1FBF,0x342,0x0}, {0x1FD0,0x3B9,0x306,0x0}, 
+  {0x1FD1,0x3B9,0x304,0x0}, {0x1FD2,0x3CA,0x300,0x0}, {0x1FD3,0x3CA,0x301,0x0}, 
+  {0x1FD6,0x3B9,0x342,0x0}, {0x1FD7,0x3CA,0x342,0x0}, {0x1FD8,0x399,0x306,0x0}, 
+  {0x1FD9,0x399,0x304,0x0}, {0x1FDA,0x399,0x300,0x0}, {0x1FDB,0x399,0x301,0x0}, 
+  {0x1FDD,0x1FFE,0x300,0x0}, {0x1FDE,0x1FFE,0x301,0x0}, {0x1FDF,0x1FFE,0x342,0x0}, 
+  {0x1FE0,0x3C5,0x306,0x0}, {0x1FE1,0x3C5,0x304,0x0}, {0x1FE2,0x3CB,0x300,0x0}, 
+  {0x1FE3,0x3CB,0x301,0x0}, {0x1FE4,0x3C1,0x313,0x0}, {0x1FE5,0x3C1,0x314,0x0}, 
+  {0x1FE6,0x3C5,0x342,0x0}, {0x1FE7,0x3CB,0x342,0x0}, {0x1FE8,0x3A5,0x306,0x0}, 
+  {0x1FE9,0x3A5,0x304,0x0}, {0x1FEA,0x3A5,0x300,0x0}, {0x1FEB,0x3A5,0x301,0x0}, 
+  {0x1FEC,0x3A1,0x314,0x0}, {0x1FED,0xA8,0x300,0x0}, {0x1FEE,0xA8,0x301,0x0}, 
+  {0x1FEF,0x60,0x0,0x0}, {0x1FF2,0x1F7C,0x345,0x0}, {0x1FF3,0x3C9,0x345,0x0}, 
+  {0x1FF4,0x1F79,0x345,0x0}, {0x1FF6,0x3C9,0x342,0x0}, {0x1FF7,0x1FF6,0x345,0x0}, 
+  {0x1FF8,0x39F,0x300,0x0}, {0x1FF9,0x39F,0x301,0x0}, {0x1FFA,0x3A9,0x300,0x0}, 
+  {0x1FFB,0x3A9,0x301,0x0}, {0x1FFC,0x3A9,0x345,0x0}, {0x1FFD,0xB4,0x0,0x0}, 
+  {0x2000,0x2002,0x0,0x0}, {0x2001,0x2003,0x0,0x0}, {0x2126,0x3A9,0x0,0x0}, 
+  {0x212A,0x4B,0x0,0x0}, {0x212B,0xC5,0x0,0x0}, {0x2204,0x2203,0x338,0x0}, 
+  {0x2209,0x2208,0x338,0x0}, {0x220C,0x220B,0x338,0x0}, {0x2224,0x2223,0x338,0x0}, 
+  {0x2226,0x2225,0x338,0x0}, {0x2241,0x7E,0x338,0x0}, {0x2244,0x2243,0x338,0x0}, 
+  {0x2247,0x2245,0x338,0x0}, {0x2249,0x2248,0x338,0x0}, {0x2260,0x3D,0x338,0x0}, 
+  {0x2262,0x2261,0x338,0x0}, {0x226D,0x224D,0x338,0x0}, {0x226E,0x3C,0x338,0x0}, 
+  {0x226F,0x3E,0x338,0x0}, {0x2270,0x2264,0x338,0x0}, {0x2271,0x2265,0x338,0x0}, 
+  {0x2274,0x2272,0x338,0x0}, {0x2275,0x2273,0x338,0x0}, {0x2278,0x2276,0x338,0x0}, 
+  {0x2279,0x2277,0x338,0x0}, {0x2280,0x227A,0x338,0x0}, {0x2281,0x227B,0x338,0x0}, 
+  {0x2284,0x2282,0x338,0x0}, {0x2285,0x2283,0x338,0x0}, {0x2288,0x2286,0x338,0x0}, 
+  {0x2289,0x2287,0x338,0x0}, {0x22AC,0x22A2,0x338,0x0}, {0x22AD,0x22A8,0x338,0x0}, 
+  {0x22AE,0x22A9,0x338,0x0}, {0x22AF,0x22AB,0x338,0x0}, {0x22E0,0x227C,0x338,0x0}, 
+  {0x22E1,0x227D,0x338,0x0}, {0x22E2,0x2291,0x338,0x0}, {0x22E3,0x2292,0x338,0x0}, 
+  {0x22EA,0x22B2,0x338,0x0}, {0x22EB,0x22B3,0x338,0x0}, {0x22EC,0x22B4,0x338,0x0}, 
+  {0x22ED,0x22B5,0x338,0x0}, {0x2329,0x3008,0x0,0x0}, {0x232A,0x3009,0x0,0x0}, 
+  {0x304C,0x304B,0x3099,0x0}, {0x304E,0x304D,0x3099,0x0}, {0x3050,0x304F,0x3099,0x0}, 
+  {0x3052,0x3051,0x3099,0x0}, {0x3054,0x3053,0x3099,0x0}, {0x3056,0x3055,0x3099,0x0}, 
+  {0x3058,0x3057,0x3099,0x0}, {0x305A,0x3059,0x3099,0x0}, {0x305C,0x305B,0x3099,0x0}, 
+  {0x305E,0x305D,0x3099,0x0}, {0x3060,0x305F,0x3099,0x0}, {0x3062,0x3061,0x3099,0x0}, 
+  {0x3065,0x3064,0x3099,0x0}, {0x3067,0x3066,0x3099,0x0}, {0x3069,0x3068,0x3099,0x0}, 
+  {0x3070,0x306F,0x3099,0x0}, {0x3071,0x306F,0x309A,0x0}, {0x3073,0x3072,0x3099,0x0}, 
+  {0x3074,0x3072,0x309A,0x0}, {0x3076,0x3075,0x3099,0x0}, {0x3077,0x3075,0x309A,0x0}, 
+  {0x3079,0x3078,0x3099,0x0}, {0x307A,0x3078,0x309A,0x0}, {0x307C,0x307B,0x3099,0x0}, 
+  {0x307D,0x307B,0x309A,0x0}, {0x3094,0x3046,0x3099,0x0}, {0x309E,0x309D,0x3099,0x0}, 
+  {0x30AC,0x30AB,0x3099,0x0}, {0x30AE,0x30AD,0x3099,0x0}, {0x30B0,0x30AF,0x3099,0x0}, 
+  {0x30B2,0x30B1,0x3099,0x0}, {0x30B4,0x30B3,0x3099,0x0}, {0x30B6,0x30B5,0x3099,0x0}, 
+  {0x30B8,0x30B7,0x3099,0x0}, {0x30BA,0x30B9,0x3099,0x0}, {0x30BC,0x30BB,0x3099,0x0}, 
+  {0x30BE,0x30BD,0x3099,0x0}, {0x30C0,0x30BF,0x3099,0x0}, {0x30C2,0x30C1,0x3099,0x0}, 
+  {0x30C5,0x30C4,0x3099,0x0}, {0x30C7,0x30C6,0x3099,0x0}, {0x30C9,0x30C8,0x3099,0x0}, 
+  {0x30D0,0x30CF,0x3099,0x0}, {0x30D1,0x30CF,0x309A,0x0}, {0x30D3,0x30D2,0x3099,0x0}, 
+  {0x30D4,0x30D2,0x309A,0x0}, {0x30D6,0x30D5,0x3099,0x0}, {0x30D7,0x30D5,0x309A,0x0}, 
+  {0x30D9,0x30D8,0x3099,0x0}, {0x30DA,0x30D8,0x309A,0x0}, {0x30DC,0x30DB,0x3099,0x0}, 
+  {0x30DD,0x30DB,0x309A,0x0}, {0x30F4,0x30A6,0x3099,0x0}, {0x30F7,0x30EF,0x3099,0x0}, 
+  {0x30F8,0x30F0,0x3099,0x0}, {0x30F9,0x30F1,0x3099,0x0}, {0x30FA,0x30F2,0x3099,0x0}, 
+  {0x30FE,0x30FD,0x3099,0x0}, {0xF900,0x8C48,0x0,0x0}, {0xF901,0x66F4,0x0,0x0}, 
+  {0xF902,0x8ECA,0x0,0x0}, {0xF903,0x8CC8,0x0,0x0}, {0xF904,0x6ED1,0x0,0x0}, 
+  {0xF905,0x4E32,0x0,0x0}, {0xF906,0x53E5,0x0,0x0}, {0xF907,0x9F9C,0x0,0x0}, 
+  {0xF908,0x9F9C,0x0,0x0}, {0xF909,0x5951,0x0,0x0}, {0xF90A,0x91D1,0x0,0x0}, 
+  {0xF90B,0x5587,0x0,0x0}, {0xF90C,0x5948,0x0,0x0}, {0xF90D,0x61F6,0x0,0x0}, 
+  {0xF90E,0x7669,0x0,0x0}, {0xF90F,0x7F85,0x0,0x0}, {0xF910,0x863F,0x0,0x0}, 
+  {0xF911,0x87BA,0x0,0x0}, {0xF912,0x88F8,0x0,0x0}, {0xF913,0x908F,0x0,0x0}, 
+  {0xF914,0x6A02,0x0,0x0}, {0xF915,0x6D1B,0x0,0x0}, {0xF916,0x70D9,0x0,0x0}, 
+  {0xF917,0x73DE,0x0,0x0}, {0xF918,0x843D,0x0,0x0}, {0xF919,0x916A,0x0,0x0}, 
+  {0xF91A,0x99F1,0x0,0x0}, {0xF91B,0x4E82,0x0,0x0}, {0xF91C,0x5375,0x0,0x0}, 
+  {0xF91D,0x6B04,0x0,0x0}, {0xF91E,0x721B,0x0,0x0}, {0xF91F,0x862D,0x0,0x0}, 
+  {0xF920,0x9E1E,0x0,0x0}, {0xF921,0x5D50,0x0,0x0}, {0xF922,0x6FEB,0x0,0x0}, 
+  {0xF923,0x85CD,0x0,0x0}, {0xF924,0x8964,0x0,0x0}, {0xF925,0x62C9,0x0,0x0}, 
+  {0xF926,0x81D8,0x0,0x0}, {0xF927,0x881F,0x0,0x0}, {0xF928,0x5ECA,0x0,0x0}, 
+  {0xF929,0x6717,0x0,0x0}, {0xF92A,0x6D6A,0x0,0x0}, {0xF92B,0x72FC,0x0,0x0}, 
+  {0xF92C,0x90CE,0x0,0x0}, {0xF92D,0x4F86,0x0,0x0}, {0xF92E,0x51B7,0x0,0x0}, 
+  {0xF92F,0x52DE,0x0,0x0}, {0xF930,0x64C4,0x0,0x0}, {0xF931,0x6AD3,0x0,0x0}, 
+  {0xF932,0x7210,0x0,0x0}, {0xF933,0x76E7,0x0,0x0}, {0xF934,0x8001,0x0,0x0}, 
+  {0xF935,0x8606,0x0,0x0}, {0xF936,0x865C,0x0,0x0}, {0xF937,0x8DEF,0x0,0x0}, 
+  {0xF938,0x9732,0x0,0x0}, {0xF939,0x9B6F,0x0,0x0}, {0xF93A,0x9DFA,0x0,0x0}, 
+  {0xF93B,0x788C,0x0,0x0}, {0xF93C,0x797F,0x0,0x0}, {0xF93D,0x7DA0,0x0,0x0}, 
+  {0xF93E,0x83C9,0x0,0x0}, {0xF93F,0x9304,0x0,0x0}, {0xF940,0x9E7F,0x0,0x0}, 
+  {0xF941,0x8AD6,0x0,0x0}, {0xF942,0x58DF,0x0,0x0}, {0xF943,0x5F04,0x0,0x0}, 
+  {0xF944,0x7C60,0x0,0x0}, {0xF945,0x807E,0x0,0x0}, {0xF946,0x7262,0x0,0x0}, 
+  {0xF947,0x78CA,0x0,0x0}, {0xF948,0x8CC2,0x0,0x0}, {0xF949,0x96F7,0x0,0x0}, 
+  {0xF94A,0x58D8,0x0,0x0}, {0xF94B,0x5C62,0x0,0x0}, {0xF94C,0x6A13,0x0,0x0}, 
+  {0xF94D,0x6DDA,0x0,0x0}, {0xF94E,0x6F0F,0x0,0x0}, {0xF94F,0x7D2F,0x0,0x0}, 
+  {0xF950,0x7E37,0x0,0x0}, {0xF951,0x96FB,0x0,0x0}, {0xF952,0x52D2,0x0,0x0}, 
+  {0xF953,0x808B,0x0,0x0}, {0xF954,0x51DC,0x0,0x0}, {0xF955,0x51CC,0x0,0x0}, 
+  {0xF956,0x7A1C,0x0,0x0}, {0xF957,0x7DBE,0x0,0x0}, {0xF958,0x83F1,0x0,0x0}, 
+  {0xF959,0x9675,0x0,0x0}, {0xF95A,0x8B80,0x0,0x0}, {0xF95B,0x62CF,0x0,0x0}, 
+  {0xF95C,0x6A02,0x0,0x0}, {0xF95D,0x8AFE,0x0,0x0}, {0xF95E,0x4E39,0x0,0x0}, 
+  {0xF95F,0x5BE7,0x0,0x0}, {0xF960,0x6012,0x0,0x0}, {0xF961,0x7387,0x0,0x0}, 
+  {0xF962,0x7570,0x0,0x0}, {0xF963,0x5317,0x0,0x0}, {0xF964,0x78FB,0x0,0x0}, 
+  {0xF965,0x4FBF,0x0,0x0}, {0xF966,0x5FA9,0x0,0x0}, {0xF967,0x4E0D,0x0,0x0}, 
+  {0xF968,0x6CCC,0x0,0x0}, {0xF969,0x6578,0x0,0x0}, {0xF96A,0x7D22,0x0,0x0}, 
+  {0xF96B,0x53C3,0x0,0x0}, {0xF96C,0x585E,0x0,0x0}, {0xF96D,0x7701,0x0,0x0}, 
+  {0xF96E,0x8449,0x0,0x0}, {0xF96F,0x8AAA,0x0,0x0}, {0xF970,0x6BBA,0x0,0x0}, 
+  {0xF971,0x8FB0,0x0,0x0}, {0xF972,0x6C88,0x0,0x0}, {0xF973,0x62FE,0x0,0x0}, 
+  {0xF974,0x82E5,0x0,0x0}, {0xF975,0x63A0,0x0,0x0}, {0xF976,0x7565,0x0,0x0}, 
+  {0xF977,0x4EAE,0x0,0x0}, {0xF978,0x5169,0x0,0x0}, {0xF979,0x51C9,0x0,0x0}, 
+  {0xF97A,0x6881,0x0,0x0}, {0xF97B,0x7CE7,0x0,0x0}, {0xF97C,0x826F,0x0,0x0}, 
+  {0xF97D,0x8AD2,0x0,0x0}, {0xF97E,0x91CF,0x0,0x0}, {0xF97F,0x52F5,0x0,0x0}, 
+  {0xF980,0x5442,0x0,0x0}, {0xF981,0x5973,0x0,0x0}, {0xF982,0x5EEC,0x0,0x0}, 
+  {0xF983,0x65C5,0x0,0x0}, {0xF984,0x6FFE,0x0,0x0}, {0xF985,0x792A,0x0,0x0}, 
+  {0xF986,0x95AD,0x0,0x0}, {0xF987,0x9A6A,0x0,0x0}, {0xF988,0x9E97,0x0,0x0}, 
+  {0xF989,0x9ECE,0x0,0x0}, {0xF98A,0x529B,0x0,0x0}, {0xF98B,0x66C6,0x0,0x0}, 
+  {0xF98C,0x6B77,0x0,0x0}, {0xF98D,0x8F62,0x0,0x0}, {0xF98E,0x5E74,0x0,0x0}, 
+  {0xF98F,0x6190,0x0,0x0}, {0xF990,0x6200,0x0,0x0}, {0xF991,0x649A,0x0,0x0}, 
+  {0xF992,0x6F23,0x0,0x0}, {0xF993,0x7149,0x0,0x0}, {0xF994,0x7489,0x0,0x0}, 
+  {0xF995,0x79CA,0x0,0x0}, {0xF996,0x7DF4,0x0,0x0}, {0xF997,0x806F,0x0,0x0}, 
+  {0xF998,0x8F26,0x0,0x0}, {0xF999,0x84EE,0x0,0x0}, {0xF99A,0x9023,0x0,0x0}, 
+  {0xF99B,0x934A,0x0,0x0}, {0xF99C,0x5217,0x0,0x0}, {0xF99D,0x52A3,0x0,0x0}, 
+  {0xF99E,0x54BD,0x0,0x0}, {0xF99F,0x70C8,0x0,0x0}, {0xF9A0,0x88C2,0x0,0x0}, 
+  {0xF9A1,0x8AAA,0x0,0x0}, {0xF9A2,0x5EC9,0x0,0x0}, {0xF9A3,0x5FF5,0x0,0x0}, 
+  {0xF9A4,0x637B,0x0,0x0}, {0xF9A5,0x6BAE,0x0,0x0}, {0xF9A6,0x7C3E,0x0,0x0}, 
+  {0xF9A7,0x7375,0x0,0x0}, {0xF9A8,0x4EE4,0x0,0x0}, {0xF9A9,0x56F9,0x0,0x0}, 
+  {0xF9AA,0x5BE7,0x0,0x0}, {0xF9AB,0x5DBA,0x0,0x0}, {0xF9AC,0x601C,0x0,0x0}, 
+  {0xF9AD,0x73B2,0x0,0x0}, {0xF9AE,0x7469,0x0,0x0}, {0xF9AF,0x7F9A,0x0,0x0}, 
+  {0xF9B0,0x8046,0x0,0x0}, {0xF9B1,0x9234,0x0,0x0}, {0xF9B2,0x96F6,0x0,0x0}, 
+  {0xF9B3,0x9748,0x0,0x0}, {0xF9B4,0x9818,0x0,0x0}, {0xF9B5,0x4F8B,0x0,0x0}, 
+  {0xF9B6,0x79AE,0x0,0x0}, {0xF9B7,0x91B4,0x0,0x0}, {0xF9B8,0x96B8,0x0,0x0}, 
+  {0xF9B9,0x60E1,0x0,0x0}, {0xF9BA,0x4E86,0x0,0x0}, {0xF9BB,0x50DA,0x0,0x0}, 
+  {0xF9BC,0x5BEE,0x0,0x0}, {0xF9BD,0x5C3F,0x0,0x0}, {0xF9BE,0x6599,0x0,0x0}, 
+  {0xF9BF,0x6A02,0x0,0x0}, {0xF9C0,0x71CE,0x0,0x0}, {0xF9C1,0x7642,0x0,0x0}, 
+  {0xF9C2,0x84FC,0x0,0x0}, {0xF9C3,0x907C,0x0,0x0}, {0xF9C4,0x9F8D,0x0,0x0}, 
+  {0xF9C5,0x6688,0x0,0x0}, {0xF9C6,0x962E,0x0,0x0}, {0xF9C7,0x5289,0x0,0x0}, 
+  {0xF9C8,0x677B,0x0,0x0}, {0xF9C9,0x67F3,0x0,0x0}, {0xF9CA,0x6D41,0x0,0x0}, 
+  {0xF9CB,0x6E9C,0x0,0x0}, {0xF9CC,0x7409,0x0,0x0}, {0xF9CD,0x7559,0x0,0x0}, 
+  {0xF9CE,0x786B,0x0,0x0}, {0xF9CF,0x7D10,0x0,0x0}, {0xF9D0,0x985E,0x0,0x0}, 
+  {0xF9D1,0x516D,0x0,0x0}, {0xF9D2,0x622E,0x0,0x0}, {0xF9D3,0x9678,0x0,0x0}, 
+  {0xF9D4,0x502B,0x0,0x0}, {0xF9D5,0x5D19,0x0,0x0}, {0xF9D6,0x6DEA,0x0,0x0}, 
+  {0xF9D7,0x8F2A,0x0,0x0}, {0xF9D8,0x5F8B,0x0,0x0}, {0xF9D9,0x6144,0x0,0x0}, 
+  {0xF9DA,0x6817,0x0,0x0}, {0xF9DB,0x7387,0x0,0x0}, {0xF9DC,0x9686,0x0,0x0}, 
+  {0xF9DD,0x5229,0x0,0x0}, {0xF9DE,0x540F,0x0,0x0}, {0xF9DF,0x5C65,0x0,0x0}, 
+  {0xF9E0,0x6613,0x0,0x0}, {0xF9E1,0x674E,0x0,0x0}, {0xF9E2,0x68A8,0x0,0x0}, 
+  {0xF9E3,0x6CE5,0x0,0x0}, {0xF9E4,0x7406,0x0,0x0}, {0xF9E5,0x75E2,0x0,0x0}, 
+  {0xF9E6,0x7F79,0x0,0x0}, {0xF9E7,0x88CF,0x0,0x0}, {0xF9E8,0x88E1,0x0,0x0}, 
+  {0xF9E9,0x91CC,0x0,0x0}, {0xF9EA,0x96E2,0x0,0x0}, {0xF9EB,0x533F,0x0,0x0}, 
+  {0xF9EC,0x6EBA,0x0,0x0}, {0xF9ED,0x541D,0x0,0x0}, {0xF9EE,0x71D0,0x0,0x0}, 
+  {0xF9EF,0x7498,0x0,0x0}, {0xF9F0,0x85FA,0x0,0x0}, {0xF9F1,0x96A3,0x0,0x0}, 
+  {0xF9F2,0x9C57,0x0,0x0}, {0xF9F3,0x9E9F,0x0,0x0}, {0xF9F4,0x6797,0x0,0x0}, 
+  {0xF9F5,0x6DCB,0x0,0x0}, {0xF9F6,0x81E8,0x0,0x0}, {0xF9F7,0x7ACB,0x0,0x0}, 
+  {0xF9F8,0x7B20,0x0,0x0}, {0xF9F9,0x7C92,0x0,0x0}, {0xF9FA,0x72C0,0x0,0x0}, 
+  {0xF9FB,0x7099,0x0,0x0}, {0xF9FC,0x8B58,0x0,0x0}, {0xF9FD,0x4EC0,0x0,0x0}, 
+  {0xF9FE,0x8336,0x0,0x0}, {0xF9FF,0x523A,0x0,0x0}, {0xFA00,0x5207,0x0,0x0}, 
+  {0xFA01,0x5EA6,0x0,0x0}, {0xFA02,0x62D3,0x0,0x0}, {0xFA03,0x7CD6,0x0,0x0}, 
+  {0xFA04,0x5B85,0x0,0x0}, {0xFA05,0x6D1E,0x0,0x0}, {0xFA06,0x66B4,0x0,0x0}, 
+  {0xFA07,0x8F3B,0x0,0x0}, {0xFA08,0x884C,0x0,0x0}, {0xFA09,0x964D,0x0,0x0}, 
+  {0xFA0A,0x898B,0x0,0x0}, {0xFA0B,0x5ED3,0x0,0x0}, {0xFA0C,0x5140,0x0,0x0}, 
+  {0xFA0D,0x55C0,0x0,0x0}, {0xFA10,0x585A,0x0,0x0}, {0xFA12,0x6674,0x0,0x0}, 
+  {0xFA15,0x51DE,0x0,0x0}, {0xFA16,0x732A,0x0,0x0}, {0xFA17,0x76CA,0x0,0x0}, 
+  {0xFA18,0x793C,0x0,0x0}, {0xFA19,0x795E,0x0,0x0}, {0xFA1A,0x7965,0x0,0x0}, 
+  {0xFA1B,0x798F,0x0,0x0}, {0xFA1C,0x9756,0x0,0x0}, {0xFA1D,0x7CBE,0x0,0x0}, 
+  {0xFA1E,0x7FBD,0x0,0x0}, {0xFA20,0x8612,0x0,0x0}, {0xFA22,0x8AF8,0x0,0x0}, 
+  {0xFA25,0x9038,0x0,0x0}, {0xFA26,0x90FD,0x0,0x0}, {0xFA2A,0x98EF,0x0,0x0}, 
+  {0xFA2B,0x98FC,0x0,0x0}, {0xFA2C,0x9928,0x0,0x0}, {0xFA2D,0x9DB4,0x0,0x0}, 
+  {0xFB1F,0x5F2,0x5B7,0x0}, {0xFB2A,0x5E9,0x5C1,0x0}, {0xFB2B,0x5E9,0x5C2,0x0}, 
+  {0xFB2C,0x5E9,0x5BC,0x5C1}, {0xFB2D,0x5E9,0x5BC,0x5C2}, {0xFB2E,0x5D0,0x5B7,0x0}, 
+  {0xFB2F,0x5D0,0x5B8,0x0}, {0xFB30,0x5D0,0x5BC,0x0}, {0xFB31,0x5D1,0x5BC,0x0}, 
+  {0xFB32,0x5D2,0x5BC,0x0}, {0xFB33,0x5D3,0x5BC,0x0}, {0xFB34,0x5D4,0x5BC,0x0}, 
+  {0xFB35,0x5D5,0x5BC,0x0}, {0xFB36,0x5D6,0x5BC,0x0}, {0xFB38,0x5D8,0x5BC,0x0}, 
+  {0xFB39,0x5D9,0x5BC,0x0}, {0xFB3A,0x5DA,0x5BC,0x0}, {0xFB3B,0x5DB,0x5BC,0x0}, 
+  {0xFB3C,0x5DC,0x5BC,0x0}, {0xFB3E,0x5DE,0x5BC,0x0}, {0xFB40,0x5E0,0x5BC,0x0}, 
+  {0xFB41,0x5E1,0x5BC,0x0}, {0xFB43,0x5E3,0x5BC,0x0}, {0xFB44,0x5E4,0x5BC,0x0}, 
+  {0xFB46,0x5E6,0x5BC,0x0}, {0xFB47,0x5E7,0x5BC,0x0}, {0xFB48,0x5E8,0x5BC,0x0}, 
+  {0xFB49,0x5E9,0x5BC,0x0}, {0xFB4A,0x5EA,0x5BC,0x0}, {0xFB4B,0x5D5,0x5B9,0x0}, 
+  {0xFB4C,0x5D1,0x5BF,0x0}, {0xFB4D,0x5DB,0x5BF,0x0}, {0xFB4E,0x5E4,0x5BF,0x0} 
+};
+
+
+/* All upper-case translations are included here */
+
+#define NUM_TOUPPER_INFO 677
+static const unirelate toupper_info[NUM_TOUPPER_INFO] = {
+  {0x61,0x41}, {0x62,0x42}, {0x63,0x43}, {0x64,0x44}, {0x65,0x45}, 
+  {0x66,0x46}, {0x67,0x47}, {0x68,0x48}, {0x69,0x49}, {0x6A,0x4A}, 
+  {0x6B,0x4B}, {0x6C,0x4C}, {0x6D,0x4D}, {0x6E,0x4E}, {0x6F,0x4F}, 
+  {0x70,0x50}, {0x71,0x51}, {0x72,0x52}, {0x73,0x53}, {0x74,0x54}, 
+  {0x75,0x55}, {0x76,0x56}, {0x77,0x57}, {0x78,0x58}, {0x79,0x59}, 
+  {0x7A,0x5A}, {0xE0,0xC0}, {0xE1,0xC1}, {0xE2,0xC2}, {0xE3,0xC3}, 
+  {0xE4,0xC4}, {0xE5,0xC5}, {0xE6,0xC6}, {0xE7,0xC7}, {0xE8,0xC8}, 
+  {0xE9,0xC9}, {0xEA,0xCA}, {0xEB,0xCB}, {0xEC,0xCC}, {0xED,0xCD}, 
+  {0xEE,0xCE}, {0xEF,0xCF}, {0xF0,0xD0}, {0xF1,0xD1}, {0xF2,0xD2}, 
+  {0xF3,0xD3}, {0xF4,0xD4}, {0xF5,0xD5}, {0xF6,0xD6}, {0xF8,0xD8}, 
+  {0xF9,0xD9}, {0xFA,0xDA}, {0xFB,0xDB}, {0xFC,0xDC}, {0xFD,0xDD}, 
+  {0xFE,0xDE}, {0xFF,0x178}, {0x101,0x100}, {0x103,0x102}, {0x105,0x104}, 
+  {0x107,0x106}, {0x109,0x108}, {0x10B,0x10A}, {0x10D,0x10C}, {0x10F,0x10E}, 
+  {0x111,0x110}, {0x113,0x112}, {0x115,0x114}, {0x117,0x116}, {0x119,0x118}, 
+  {0x11B,0x11A}, {0x11D,0x11C}, {0x11F,0x11E}, {0x121,0x120}, {0x123,0x122}, 
+  {0x125,0x124}, {0x127,0x126}, {0x129,0x128}, {0x12B,0x12A}, {0x12D,0x12C}, 
+  {0x12F,0x12E}, {0x131,0x49}, {0x133,0x132}, {0x135,0x134}, {0x137,0x136}, 
+  {0x13A,0x139}, {0x13C,0x13B}, {0x13E,0x13D}, {0x140,0x13F}, {0x142,0x141}, 
+  {0x144,0x143}, {0x146,0x145}, {0x148,0x147}, {0x14B,0x14A}, {0x14D,0x14C}, 
+  {0x14F,0x14E}, {0x151,0x150}, {0x153,0x152}, {0x155,0x154}, {0x157,0x156}, 
+  {0x159,0x158}, {0x15B,0x15A}, {0x15D,0x15C}, {0x15F,0x15E}, {0x161,0x160}, 
+  {0x163,0x162}, {0x165,0x164}, {0x167,0x166}, {0x169,0x168}, {0x16B,0x16A}, 
+  {0x16D,0x16C}, {0x16F,0x16E}, {0x171,0x170}, {0x173,0x172}, {0x175,0x174}, 
+  {0x177,0x176}, {0x17A,0x179}, {0x17C,0x17B}, {0x17E,0x17D}, {0x17F,0x53}, 
+  {0x183,0x182}, {0x185,0x184}, {0x188,0x187}, {0x18C,0x18B}, {0x192,0x191}, 
+  {0x199,0x198}, {0x1A1,0x1A0}, {0x1A3,0x1A2}, {0x1A5,0x1A4}, {0x1A8,0x1A7}, 
+  {0x1AD,0x1AC}, {0x1B0,0x1AF}, {0x1B4,0x1B3}, {0x1B6,0x1B5}, {0x1B9,0x1B8}, 
+  {0x1BD,0x1BC}, {0x1C5,0x1C4}, {0x1C6,0x1C4}, {0x1C8,0x1C7}, {0x1C9,0x1C7}, 
+  {0x1CB,0x1CA}, {0x1CC,0x1CA}, {0x1CE,0x1CD}, {0x1D0,0x1CF}, {0x1D2,0x1D1}, 
+  {0x1D4,0x1D3}, {0x1D6,0x1D5}, {0x1D8,0x1D7}, {0x1DA,0x1D9}, {0x1DC,0x1DB}, 
+  {0x1DD,0x18E}, {0x1DF,0x1DE}, {0x1E1,0x1E0}, {0x1E3,0x1E2}, {0x1E5,0x1E4}, 
+  {0x1E7,0x1E6}, {0x1E9,0x1E8}, {0x1EB,0x1EA}, {0x1ED,0x1EC}, {0x1EF,0x1EE}, 
+  {0x1F2,0x1F1}, {0x1F3,0x1F1}, {0x1F5,0x1F4}, {0x1FB,0x1FA}, {0x1FD,0x1FC}, 
+  {0x1FF,0x1FE}, {0x201,0x200}, {0x203,0x202}, {0x205,0x204}, {0x207,0x206}, 
+  {0x209,0x208}, {0x20B,0x20A}, {0x20D,0x20C}, {0x20F,0x20E}, {0x211,0x210}, 
+  {0x213,0x212}, {0x215,0x214}, {0x217,0x216}, {0x253,0x181}, {0x254,0x186}, 
+  {0x256,0x189}, {0x257,0x18A}, {0x259,0x18F}, {0x25B,0x190}, {0x260,0x193}, 
+  {0x263,0x194}, {0x268,0x197}, {0x269,0x196}, {0x26F,0x19C}, {0x272,0x19D}, 
+  {0x275,0x19F}, {0x283,0x1A9}, {0x288,0x1AE}, {0x28A,0x1B1}, {0x28B,0x1B2}, 
+  {0x292,0x1B7}, {0x3AC,0x386}, {0x3AD,0x388}, {0x3AE,0x389}, {0x3AF,0x38A}, 
+  {0x3B1,0x391}, {0x3B2,0x392}, {0x3B3,0x393}, {0x3B4,0x394}, {0x3B5,0x395}, 
+  {0x3B6,0x396}, {0x3B7,0x397}, {0x3B8,0x398}, {0x3B9,0x399}, {0x3BA,0x39A}, 
+  {0x3BB,0x39B}, {0x3BC,0x39C}, {0x3BD,0x39D}, {0x3BE,0x39E}, {0x3BF,0x39F}, 
+  {0x3C0,0x3A0}, {0x3C1,0x3A1}, {0x3C2,0x3A3}, {0x3C3,0x3A3}, {0x3C4,0x3A4}, 
+  {0x3C5,0x3A5}, {0x3C6,0x3A6}, {0x3C7,0x3A7}, {0x3C8,0x3A8}, {0x3C9,0x3A9}, 
+  {0x3CA,0x3AA}, {0x3CB,0x3AB}, {0x3CC,0x38C}, {0x3CD,0x38E}, {0x3CE,0x38F}, 
+  {0x3D0,0x392}, {0x3D1,0x398}, {0x3D5,0x3A6}, {0x3D6,0x3A0}, {0x3E3,0x3E2}, 
+  {0x3E5,0x3E4}, {0x3E7,0x3E6}, {0x3E9,0x3E8}, {0x3EB,0x3EA}, {0x3ED,0x3EC}, 
+  {0x3EF,0x3EE}, {0x3F0,0x39A}, {0x3F1,0x3A1}, {0x3F2,0x3A3}, {0x430,0x410}, 
+  {0x431,0x411}, {0x432,0x412}, {0x433,0x413}, {0x434,0x414}, {0x435,0x415}, 
+  {0x436,0x416}, {0x437,0x417}, {0x438,0x418}, {0x439,0x419}, {0x43A,0x41A}, 
+  {0x43B,0x41B}, {0x43C,0x41C}, {0x43D,0x41D}, {0x43E,0x41E}, {0x43F,0x41F}, 
+  {0x440,0x420}, {0x441,0x421}, {0x442,0x422}, {0x443,0x423}, {0x444,0x424}, 
+  {0x445,0x425}, {0x446,0x426}, {0x447,0x427}, {0x448,0x428}, {0x449,0x429}, 
+  {0x44A,0x42A}, {0x44B,0x42B}, {0x44C,0x42C}, {0x44D,0x42D}, {0x44E,0x42E}, 
+  {0x44F,0x42F}, {0x451,0x401}, {0x452,0x402}, {0x453,0x403}, {0x454,0x404}, 
+  {0x455,0x405}, {0x456,0x406}, {0x457,0x407}, {0x458,0x408}, {0x459,0x409}, 
+  {0x45A,0x40A}, {0x45B,0x40B}, {0x45C,0x40C}, {0x45E,0x40E}, {0x45F,0x40F}, 
+  {0x461,0x460}, {0x463,0x462}, {0x465,0x464}, {0x467,0x466}, {0x469,0x468}, 
+  {0x46B,0x46A}, {0x46D,0x46C}, {0x46F,0x46E}, {0x471,0x470}, {0x473,0x472}, 
+  {0x475,0x474}, {0x477,0x476}, {0x479,0x478}, {0x47B,0x47A}, {0x47D,0x47C}, 
+  {0x47F,0x47E}, {0x481,0x480}, {0x491,0x490}, {0x493,0x492}, {0x495,0x494}, 
+  {0x497,0x496}, {0x499,0x498}, {0x49B,0x49A}, {0x49D,0x49C}, {0x49F,0x49E}, 
+  {0x4A1,0x4A0}, {0x4A3,0x4A2}, {0x4A5,0x4A4}, {0x4A7,0x4A6}, {0x4A9,0x4A8}, 
+  {0x4AB,0x4AA}, {0x4AD,0x4AC}, {0x4AF,0x4AE}, {0x4B1,0x4B0}, {0x4B3,0x4B2}, 
+  {0x4B5,0x4B4}, {0x4B7,0x4B6}, {0x4B9,0x4B8}, {0x4BB,0x4BA}, {0x4BD,0x4BC}, 
+  {0x4BF,0x4BE}, {0x4C2,0x4C1}, {0x4C4,0x4C3}, {0x4C8,0x4C7}, {0x4CC,0x4CB}, 
+  {0x4D1,0x4D0}, {0x4D3,0x4D2}, {0x4D5,0x4D4}, {0x4D7,0x4D6}, {0x4D9,0x4D8}, 
+  {0x4DB,0x4DA}, {0x4DD,0x4DC}, {0x4DF,0x4DE}, {0x4E1,0x4E0}, {0x4E3,0x4E2}, 
+  {0x4E5,0x4E4}, {0x4E7,0x4E6}, {0x4E9,0x4E8}, {0x4EB,0x4EA}, {0x4EF,0x4EE}, 
+  {0x4F1,0x4F0}, {0x4F3,0x4F2}, {0x4F5,0x4F4}, {0x4F9,0x4F8}, {0x561,0x531}, 
+  {0x562,0x532}, {0x563,0x533}, {0x564,0x534}, {0x565,0x535}, {0x566,0x536}, 
+  {0x567,0x537}, {0x568,0x538}, {0x569,0x539}, {0x56A,0x53A}, {0x56B,0x53B}, 
+  {0x56C,0x53C}, {0x56D,0x53D}, {0x56E,0x53E}, {0x56F,0x53F}, {0x570,0x540}, 
+  {0x571,0x541}, {0x572,0x542}, {0x573,0x543}, {0x574,0x544}, {0x575,0x545}, 
+  {0x576,0x546}, {0x577,0x547}, {0x578,0x548}, {0x579,0x549}, {0x57A,0x54A}, 
+  {0x57B,0x54B}, {0x57C,0x54C}, {0x57D,0x54D}, {0x57E,0x54E}, {0x57F,0x54F}, 
+  {0x580,0x550}, {0x581,0x551}, {0x582,0x552}, {0x583,0x553}, {0x584,0x554}, 
+  {0x585,0x555}, {0x586,0x556}, {0x1E01,0x1E00}, {0x1E03,0x1E02}, {0x1E05,0x1E04}, 
+  {0x1E07,0x1E06}, {0x1E09,0x1E08}, {0x1E0B,0x1E0A}, {0x1E0D,0x1E0C}, {0x1E0F,0x1E0E}, 
+  {0x1E11,0x1E10}, {0x1E13,0x1E12}, {0x1E15,0x1E14}, {0x1E17,0x1E16}, {0x1E19,0x1E18}, 
+  {0x1E1B,0x1E1A}, {0x1E1D,0x1E1C}, {0x1E1F,0x1E1E}, {0x1E21,0x1E20}, {0x1E23,0x1E22}, 
+  {0x1E25,0x1E24}, {0x1E27,0x1E26}, {0x1E29,0x1E28}, {0x1E2B,0x1E2A}, {0x1E2D,0x1E2C}, 
+  {0x1E2F,0x1E2E}, {0x1E31,0x1E30}, {0x1E33,0x1E32}, {0x1E35,0x1E34}, {0x1E37,0x1E36}, 
+  {0x1E39,0x1E38}, {0x1E3B,0x1E3A}, {0x1E3D,0x1E3C}, {0x1E3F,0x1E3E}, {0x1E41,0x1E40}, 
+  {0x1E43,0x1E42}, {0x1E45,0x1E44}, {0x1E47,0x1E46}, {0x1E49,0x1E48}, {0x1E4B,0x1E4A}, 
+  {0x1E4D,0x1E4C}, {0x1E4F,0x1E4E}, {0x1E51,0x1E50}, {0x1E53,0x1E52}, {0x1E55,0x1E54}, 
+  {0x1E57,0x1E56}, {0x1E59,0x1E58}, {0x1E5B,0x1E5A}, {0x1E5D,0x1E5C}, {0x1E5F,0x1E5E}, 
+  {0x1E61,0x1E60}, {0x1E63,0x1E62}, {0x1E65,0x1E64}, {0x1E67,0x1E66}, {0x1E69,0x1E68}, 
+  {0x1E6B,0x1E6A}, {0x1E6D,0x1E6C}, {0x1E6F,0x1E6E}, {0x1E71,0x1E70}, {0x1E73,0x1E72}, 
+  {0x1E75,0x1E74}, {0x1E77,0x1E76}, {0x1E79,0x1E78}, {0x1E7B,0x1E7A}, {0x1E7D,0x1E7C}, 
+  {0x1E7F,0x1E7E}, {0x1E81,0x1E80}, {0x1E83,0x1E82}, {0x1E85,0x1E84}, {0x1E87,0x1E86}, 
+  {0x1E89,0x1E88}, {0x1E8B,0x1E8A}, {0x1E8D,0x1E8C}, {0x1E8F,0x1E8E}, {0x1E91,0x1E90}, 
+  {0x1E93,0x1E92}, {0x1E95,0x1E94}, {0x1E9B,0x1E60}, {0x1EA1,0x1EA0}, {0x1EA3,0x1EA2}, 
+  {0x1EA5,0x1EA4}, {0x1EA7,0x1EA6}, {0x1EA9,0x1EA8}, {0x1EAB,0x1EAA}, {0x1EAD,0x1EAC}, 
+  {0x1EAF,0x1EAE}, {0x1EB1,0x1EB0}, {0x1EB3,0x1EB2}, {0x1EB5,0x1EB4}, {0x1EB7,0x1EB6}, 
+  {0x1EB9,0x1EB8}, {0x1EBB,0x1EBA}, {0x1EBD,0x1EBC}, {0x1EBF,0x1EBE}, {0x1EC1,0x1EC0}, 
+  {0x1EC3,0x1EC2}, {0x1EC5,0x1EC4}, {0x1EC7,0x1EC6}, {0x1EC9,0x1EC8}, {0x1ECB,0x1ECA}, 
+  {0x1ECD,0x1ECC}, {0x1ECF,0x1ECE}, {0x1ED1,0x1ED0}, {0x1ED3,0x1ED2}, {0x1ED5,0x1ED4}, 
+  {0x1ED7,0x1ED6}, {0x1ED9,0x1ED8}, {0x1EDB,0x1EDA}, {0x1EDD,0x1EDC}, {0x1EDF,0x1EDE}, 
+  {0x1EE1,0x1EE0}, {0x1EE3,0x1EE2}, {0x1EE5,0x1EE4}, {0x1EE7,0x1EE6}, {0x1EE9,0x1EE8}, 
+  {0x1EEB,0x1EEA}, {0x1EED,0x1EEC}, {0x1EEF,0x1EEE}, {0x1EF1,0x1EF0}, {0x1EF3,0x1EF2}, 
+  {0x1EF5,0x1EF4}, {0x1EF7,0x1EF6}, {0x1EF9,0x1EF8}, {0x1F00,0x1F08}, {0x1F01,0x1F09}, 
+  {0x1F02,0x1F0A}, {0x1F03,0x1F0B}, {0x1F04,0x1F0C}, {0x1F05,0x1F0D}, {0x1F06,0x1F0E}, 
+  {0x1F07,0x1F0F}, {0x1F10,0x1F18}, {0x1F11,0x1F19}, {0x1F12,0x1F1A}, {0x1F13,0x1F1B}, 
+  {0x1F14,0x1F1C}, {0x1F15,0x1F1D}, {0x1F20,0x1F28}, {0x1F21,0x1F29}, {0x1F22,0x1F2A}, 
+  {0x1F23,0x1F2B}, {0x1F24,0x1F2C}, {0x1F25,0x1F2D}, {0x1F26,0x1F2E}, {0x1F27,0x1F2F}, 
+  {0x1F30,0x1F38}, {0x1F31,0x1F39}, {0x1F32,0x1F3A}, {0x1F33,0x1F3B}, {0x1F34,0x1F3C}, 
+  {0x1F35,0x1F3D}, {0x1F36,0x1F3E}, {0x1F37,0x1F3F}, {0x1F40,0x1F48}, {0x1F41,0x1F49}, 
+  {0x1F42,0x1F4A}, {0x1F43,0x1F4B}, {0x1F44,0x1F4C}, {0x1F45,0x1F4D}, {0x1F51,0x1F59}, 
+  {0x1F53,0x1F5B}, {0x1F55,0x1F5D}, {0x1F57,0x1F5F}, {0x1F60,0x1F68}, {0x1F61,0x1F69}, 
+  {0x1F62,0x1F6A}, {0x1F63,0x1F6B}, {0x1F64,0x1F6C}, {0x1F65,0x1F6D}, {0x1F66,0x1F6E}, 
+  {0x1F67,0x1F6F}, {0x1F70,0x1FBA}, {0x1F71,0x1FBB}, {0x1F72,0x1FC8}, {0x1F73,0x1FC9}, 
+  {0x1F74,0x1FCA}, {0x1F75,0x1FCB}, {0x1F76,0x1FDA}, {0x1F77,0x1FDB}, {0x1F78,0x1FF8}, 
+  {0x1F79,0x1FF9}, {0x1F7A,0x1FEA}, {0x1F7B,0x1FEB}, {0x1F7C,0x1FFA}, {0x1F7D,0x1FFB}, 
+  {0x1F80,0x1F88}, {0x1F81,0x1F89}, {0x1F82,0x1F8A}, {0x1F83,0x1F8B}, {0x1F84,0x1F8C}, 
+  {0x1F85,0x1F8D}, {0x1F86,0x1F8E}, {0x1F87,0x1F8F}, {0x1F90,0x1F98}, {0x1F91,0x1F99}, 
+  {0x1F92,0x1F9A}, {0x1F93,0x1F9B}, {0x1F94,0x1F9C}, {0x1F95,0x1F9D}, {0x1F96,0x1F9E}, 
+  {0x1F97,0x1F9F}, {0x1FA0,0x1FA8}, {0x1FA1,0x1FA9}, {0x1FA2,0x1FAA}, {0x1FA3,0x1FAB}, 
+  {0x1FA4,0x1FAC}, {0x1FA5,0x1FAD}, {0x1FA6,0x1FAE}, {0x1FA7,0x1FAF}, {0x1FB0,0x1FB8}, 
+  {0x1FB1,0x1FB9}, {0x1FB3,0x1FBC}, {0x1FC3,0x1FCC}, {0x1FD0,0x1FD8}, {0x1FD1,0x1FD9}, 
+  {0x1FE0,0x1FE8}, {0x1FE1,0x1FE9}, {0x1FE5,0x1FEC}, {0x1FF3,0x1FFC}, {0x2170,0x2160}, 
+  {0x2171,0x2161}, {0x2172,0x2162}, {0x2173,0x2163}, {0x2174,0x2164}, {0x2175,0x2165}, 
+  {0x2176,0x2166}, {0x2177,0x2167}, {0x2178,0x2168}, {0x2179,0x2169}, {0x217A,0x216A}, 
+  {0x217B,0x216B}, {0x217C,0x216C}, {0x217D,0x216D}, {0x217E,0x216E}, {0x217F,0x216F}, 
+  {0x24D0,0x24B6}, {0x24D1,0x24B7}, {0x24D2,0x24B8}, {0x24D3,0x24B9}, {0x24D4,0x24BA}, 
+  {0x24D5,0x24BB}, {0x24D6,0x24BC}, {0x24D7,0x24BD}, {0x24D8,0x24BE}, {0x24D9,0x24BF}, 
+  {0x24DA,0x24C0}, {0x24DB,0x24C1}, {0x24DC,0x24C2}, {0x24DD,0x24C3}, {0x24DE,0x24C4}, 
+  {0x24DF,0x24C5}, {0x24E0,0x24C6}, {0x24E1,0x24C7}, {0x24E2,0x24C8}, {0x24E3,0x24C9}, 
+  {0x24E4,0x24CA}, {0x24E5,0x24CB}, {0x24E6,0x24CC}, {0x24E7,0x24CD}, {0x24E8,0x24CE}, 
+  {0x24E9,0x24CF}, {0xFF41,0xFF21}, {0xFF42,0xFF22}, {0xFF43,0xFF23}, {0xFF44,0xFF24}, 
+  {0xFF45,0xFF25}, {0xFF46,0xFF26}, {0xFF47,0xFF27}, {0xFF48,0xFF28}, {0xFF49,0xFF29}, 
+  {0xFF4A,0xFF2A}, {0xFF4B,0xFF2B}, {0xFF4C,0xFF2C}, {0xFF4D,0xFF2D}, {0xFF4E,0xFF2E}, 
+  {0xFF4F,0xFF2F}, {0xFF50,0xFF30}, {0xFF51,0xFF31}, {0xFF52,0xFF32}, {0xFF53,0xFF33}, 
+  {0xFF54,0xFF34}, {0xFF55,0xFF35}, {0xFF56,0xFF36}, {0xFF57,0xFF37}, {0xFF58,0xFF38}, 
+  {0xFF59,0xFF39}, {0xFF5A,0xFF3A} 
+};
+
+
+
+/* All lower-case translations are included here */
+
+#define NUM_TOLOWER_INFO 705
+static const unirelate tolower_info[NUM_TOLOWER_INFO] = {
+  {0x41,0x61}, {0x42,0x62}, {0x43,0x63}, {0x44,0x64}, {0x45,0x65}, 
+  {0x46,0x66}, {0x47,0x67}, {0x48,0x68}, {0x49,0x69}, {0x4A,0x6A}, 
+  {0x4B,0x6B}, {0x4C,0x6C}, {0x4D,0x6D}, {0x4E,0x6E}, {0x4F,0x6F}, 
+  {0x50,0x70}, {0x51,0x71}, {0x52,0x72}, {0x53,0x73}, {0x54,0x74}, 
+  {0x55,0x75}, {0x56,0x76}, {0x57,0x77}, {0x58,0x78}, {0x59,0x79}, 
+  {0x5A,0x7A}, {0xC0,0xE0}, {0xC1,0xE1}, {0xC2,0xE2}, {0xC3,0xE3}, 
+  {0xC4,0xE4}, {0xC5,0xE5}, {0xC6,0xE6}, {0xC7,0xE7}, {0xC8,0xE8}, 
+  {0xC9,0xE9}, {0xCA,0xEA}, {0xCB,0xEB}, {0xCC,0xEC}, {0xCD,0xED}, 
+  {0xCE,0xEE}, {0xCF,0xEF}, {0xD0,0xF0}, {0xD1,0xF1}, {0xD2,0xF2}, 
+  {0xD3,0xF3}, {0xD4,0xF4}, {0xD5,0xF5}, {0xD6,0xF6}, {0xD8,0xF8}, 
+  {0xD9,0xF9}, {0xDA,0xFA}, {0xDB,0xFB}, {0xDC,0xFC}, {0xDD,0xFD}, 
+  {0xDE,0xFE}, {0x100,0x101}, {0x102,0x103}, {0x104,0x105}, {0x106,0x107}, 
+  {0x108,0x109}, {0x10A,0x10B}, {0x10C,0x10D}, {0x10E,0x10F}, {0x110,0x111}, 
+  {0x112,0x113}, {0x114,0x115}, {0x116,0x117}, {0x118,0x119}, {0x11A,0x11B}, 
+  {0x11C,0x11D}, {0x11E,0x11F}, {0x120,0x121}, {0x122,0x123}, {0x124,0x125}, 
+  {0x126,0x127}, {0x128,0x129}, {0x12A,0x12B}, {0x12C,0x12D}, {0x12E,0x12F}, 
+  {0x130,0x69}, {0x132,0x133}, {0x134,0x135}, {0x136,0x137}, {0x139,0x13A}, 
+  {0x13B,0x13C}, {0x13D,0x13E}, {0x13F,0x140}, {0x141,0x142}, {0x143,0x144}, 
+  {0x145,0x146}, {0x147,0x148}, {0x14A,0x14B}, {0x14C,0x14D}, {0x14E,0x14F}, 
+  {0x150,0x151}, {0x152,0x153}, {0x154,0x155}, {0x156,0x157}, {0x158,0x159}, 
+  {0x15A,0x15B}, {0x15C,0x15D}, {0x15E,0x15F}, {0x160,0x161}, {0x162,0x163}, 
+  {0x164,0x165}, {0x166,0x167}, {0x168,0x169}, {0x16A,0x16B}, {0x16C,0x16D}, 
+  {0x16E,0x16F}, {0x170,0x171}, {0x172,0x173}, {0x174,0x175}, {0x176,0x177}, 
+  {0x178,0xFF}, {0x179,0x17A}, {0x17B,0x17C}, {0x17D,0x17E}, {0x181,0x253}, 
+  {0x182,0x183}, {0x184,0x185}, {0x186,0x254}, {0x187,0x188}, {0x189,0x256}, 
+  {0x18A,0x257}, {0x18B,0x18C}, {0x18E,0x1DD}, {0x18F,0x259}, {0x190,0x25B}, 
+  {0x191,0x192}, {0x193,0x260}, {0x194,0x263}, {0x196,0x269}, {0x197,0x268}, 
+  {0x198,0x199}, {0x19C,0x26F}, {0x19D,0x272}, {0x19F,0x275}, {0x1A0,0x1A1}, 
+  {0x1A2,0x1A3}, {0x1A4,0x1A5}, {0x1A7,0x1A8}, {0x1A9,0x283}, {0x1AC,0x1AD}, 
+  {0x1AE,0x288}, {0x1AF,0x1B0}, {0x1B1,0x28A}, {0x1B2,0x28B}, {0x1B3,0x1B4}, 
+  {0x1B5,0x1B6}, {0x1B7,0x292}, {0x1B8,0x1B9}, {0x1BC,0x1BD}, {0x1C4,0x1C6}, 
+  {0x1C5,0x1C6}, {0x1C7,0x1C9}, {0x1C8,0x1C9}, {0x1CA,0x1CC}, {0x1CB,0x1CC}, 
+  {0x1CD,0x1CE}, {0x1CF,0x1D0}, {0x1D1,0x1D2}, {0x1D3,0x1D4}, {0x1D5,0x1D6}, 
+  {0x1D7,0x1D8}, {0x1D9,0x1DA}, {0x1DB,0x1DC}, {0x1DE,0x1DF}, {0x1E0,0x1E1}, 
+  {0x1E2,0x1E3}, {0x1E4,0x1E5}, {0x1E6,0x1E7}, {0x1E8,0x1E9}, {0x1EA,0x1EB}, 
+  {0x1EC,0x1ED}, {0x1EE,0x1EF}, {0x1F1,0x1F3}, {0x1F2,0x1F3}, {0x1F4,0x1F5}, 
+  {0x1FA,0x1FB}, {0x1FC,0x1FD}, {0x1FE,0x1FF}, {0x200,0x201}, {0x202,0x203}, 
+  {0x204,0x205}, {0x206,0x207}, {0x208,0x209}, {0x20A,0x20B}, {0x20C,0x20D}, 
+  {0x20E,0x20F}, {0x210,0x211}, {0x212,0x213}, {0x214,0x215}, {0x216,0x217}, 
+  {0x386,0x3AC}, {0x388,0x3AD}, {0x389,0x3AE}, {0x38A,0x3AF}, {0x38C,0x3CC}, 
+  {0x38E,0x3CD}, {0x38F,0x3CE}, {0x391,0x3B1}, {0x392,0x3B2}, {0x393,0x3B3}, 
+  {0x394,0x3B4}, {0x395,0x3B5}, {0x396,0x3B6}, {0x397,0x3B7}, {0x398,0x3B8}, 
+  {0x399,0x3B9}, {0x39A,0x3BA}, {0x39B,0x3BB}, {0x39C,0x3BC}, {0x39D,0x3BD}, 
+  {0x39E,0x3BE}, {0x39F,0x3BF}, {0x3A0,0x3C0}, {0x3A1,0x3C1}, {0x3A3,0x3C3}, 
+  {0x3A4,0x3C4}, {0x3A5,0x3C5}, {0x3A6,0x3C6}, {0x3A7,0x3C7}, {0x3A8,0x3C8}, 
+  {0x3A9,0x3C9}, {0x3AA,0x3CA}, {0x3AB,0x3CB}, {0x3E2,0x3E3}, {0x3E4,0x3E5}, 
+  {0x3E6,0x3E7}, {0x3E8,0x3E9}, {0x3EA,0x3EB}, {0x3EC,0x3ED}, {0x3EE,0x3EF}, 
+  {0x401,0x451}, {0x402,0x452}, {0x403,0x453}, {0x404,0x454}, {0x405,0x455}, 
+  {0x406,0x456}, {0x407,0x457}, {0x408,0x458}, {0x409,0x459}, {0x40A,0x45A}, 
+  {0x40B,0x45B}, {0x40C,0x45C}, {0x40E,0x45E}, {0x40F,0x45F}, {0x410,0x430}, 
+  {0x411,0x431}, {0x412,0x432}, {0x413,0x433}, {0x414,0x434}, {0x415,0x435}, 
+  {0x416,0x436}, {0x417,0x437}, {0x418,0x438}, {0x419,0x439}, {0x41A,0x43A}, 
+  {0x41B,0x43B}, {0x41C,0x43C}, {0x41D,0x43D}, {0x41E,0x43E}, {0x41F,0x43F}, 
+  {0x420,0x440}, {0x421,0x441}, {0x422,0x442}, {0x423,0x443}, {0x424,0x444}, 
+  {0x425,0x445}, {0x426,0x446}, {0x427,0x447}, {0x428,0x448}, {0x429,0x449}, 
+  {0x42A,0x44A}, {0x42B,0x44B}, {0x42C,0x44C}, {0x42D,0x44D}, {0x42E,0x44E}, 
+  {0x42F,0x44F}, {0x460,0x461}, {0x462,0x463}, {0x464,0x465}, {0x466,0x467}, 
+  {0x468,0x469}, {0x46A,0x46B}, {0x46C,0x46D}, {0x46E,0x46F}, {0x470,0x471}, 
+  {0x472,0x473}, {0x474,0x475}, {0x476,0x477}, {0x478,0x479}, {0x47A,0x47B}, 
+  {0x47C,0x47D}, {0x47E,0x47F}, {0x480,0x481}, {0x490,0x491}, {0x492,0x493}, 
+  {0x494,0x495}, {0x496,0x497}, {0x498,0x499}, {0x49A,0x49B}, {0x49C,0x49D}, 
+  {0x49E,0x49F}, {0x4A0,0x4A1}, {0x4A2,0x4A3}, {0x4A4,0x4A5}, {0x4A6,0x4A7}, 
+  {0x4A8,0x4A9}, {0x4AA,0x4AB}, {0x4AC,0x4AD}, {0x4AE,0x4AF}, {0x4B0,0x4B1}, 
+  {0x4B2,0x4B3}, {0x4B4,0x4B5}, {0x4B6,0x4B7}, {0x4B8,0x4B9}, {0x4BA,0x4BB}, 
+  {0x4BC,0x4BD}, {0x4BE,0x4BF}, {0x4C1,0x4C2}, {0x4C3,0x4C4}, {0x4C7,0x4C8}, 
+  {0x4CB,0x4CC}, {0x4D0,0x4D1}, {0x4D2,0x4D3}, {0x4D4,0x4D5}, {0x4D6,0x4D7}, 
+  {0x4D8,0x4D9}, {0x4DA,0x4DB}, {0x4DC,0x4DD}, {0x4DE,0x4DF}, {0x4E0,0x4E1}, 
+  {0x4E2,0x4E3}, {0x4E4,0x4E5}, {0x4E6,0x4E7}, {0x4E8,0x4E9}, {0x4EA,0x4EB}, 
+  {0x4EE,0x4EF}, {0x4F0,0x4F1}, {0x4F2,0x4F3}, {0x4F4,0x4F5}, {0x4F8,0x4F9}, 
+  {0x531,0x561}, {0x532,0x562}, {0x533,0x563}, {0x534,0x564}, {0x535,0x565}, 
+  {0x536,0x566}, {0x537,0x567}, {0x538,0x568}, {0x539,0x569}, {0x53A,0x56A}, 
+  {0x53B,0x56B}, {0x53C,0x56C}, {0x53D,0x56D}, {0x53E,0x56E}, {0x53F,0x56F}, 
+  {0x540,0x570}, {0x541,0x571}, {0x542,0x572}, {0x543,0x573}, {0x544,0x574}, 
+  {0x545,0x575}, {0x546,0x576}, {0x547,0x577}, {0x548,0x578}, {0x549,0x579}, 
+  {0x54A,0x57A}, {0x54B,0x57B}, {0x54C,0x57C}, {0x54D,0x57D}, {0x54E,0x57E}, 
+  {0x54F,0x57F}, {0x550,0x580}, {0x551,0x581}, {0x552,0x582}, {0x553,0x583}, 
+  {0x554,0x584}, {0x555,0x585}, {0x556,0x586}, {0x10A0,0x10D0}, {0x10A1,0x10D1}, 
+  {0x10A2,0x10D2}, {0x10A3,0x10D3}, {0x10A4,0x10D4}, {0x10A5,0x10D5}, {0x10A6,0x10D6}, 
+  {0x10A7,0x10D7}, {0x10A8,0x10D8}, {0x10A9,0x10D9}, {0x10AA,0x10DA}, {0x10AB,0x10DB}, 
+  {0x10AC,0x10DC}, {0x10AD,0x10DD}, {0x10AE,0x10DE}, {0x10AF,0x10DF}, {0x10B0,0x10E0}, 
+  {0x10B1,0x10E1}, {0x10B2,0x10E2}, {0x10B3,0x10E3}, {0x10B4,0x10E4}, {0x10B5,0x10E5}, 
+  {0x10B6,0x10E6}, {0x10B7,0x10E7}, {0x10B8,0x10E8}, {0x10B9,0x10E9}, {0x10BA,0x10EA}, 
+  {0x10BB,0x10EB}, {0x10BC,0x10EC}, {0x10BD,0x10ED}, {0x10BE,0x10EE}, {0x10BF,0x10EF}, 
+  {0x10C0,0x10F0}, {0x10C1,0x10F1}, {0x10C2,0x10F2}, {0x10C3,0x10F3}, {0x10C4,0x10F4}, 
+  {0x10C5,0x10F5}, {0x1E00,0x1E01}, {0x1E02,0x1E03}, {0x1E04,0x1E05}, {0x1E06,0x1E07}, 
+  {0x1E08,0x1E09}, {0x1E0A,0x1E0B}, {0x1E0C,0x1E0D}, {0x1E0E,0x1E0F}, {0x1E10,0x1E11}, 
+  {0x1E12,0x1E13}, {0x1E14,0x1E15}, {0x1E16,0x1E17}, {0x1E18,0x1E19}, {0x1E1A,0x1E1B}, 
+  {0x1E1C,0x1E1D}, {0x1E1E,0x1E1F}, {0x1E20,0x1E21}, {0x1E22,0x1E23}, {0x1E24,0x1E25}, 
+  {0x1E26,0x1E27}, {0x1E28,0x1E29}, {0x1E2A,0x1E2B}, {0x1E2C,0x1E2D}, {0x1E2E,0x1E2F}, 
+  {0x1E30,0x1E31}, {0x1E32,0x1E33}, {0x1E34,0x1E35}, {0x1E36,0x1E37}, {0x1E38,0x1E39}, 
+  {0x1E3A,0x1E3B}, {0x1E3C,0x1E3D}, {0x1E3E,0x1E3F}, {0x1E40,0x1E41}, {0x1E42,0x1E43}, 
+  {0x1E44,0x1E45}, {0x1E46,0x1E47}, {0x1E48,0x1E49}, {0x1E4A,0x1E4B}, {0x1E4C,0x1E4D}, 
+  {0x1E4E,0x1E4F}, {0x1E50,0x1E51}, {0x1E52,0x1E53}, {0x1E54,0x1E55}, {0x1E56,0x1E57}, 
+  {0x1E58,0x1E59}, {0x1E5A,0x1E5B}, {0x1E5C,0x1E5D}, {0x1E5E,0x1E5F}, {0x1E60,0x1E61}, 
+  {0x1E62,0x1E63}, {0x1E64,0x1E65}, {0x1E66,0x1E67}, {0x1E68,0x1E69}, {0x1E6A,0x1E6B}, 
+  {0x1E6C,0x1E6D}, {0x1E6E,0x1E6F}, {0x1E70,0x1E71}, {0x1E72,0x1E73}, {0x1E74,0x1E75}, 
+  {0x1E76,0x1E77}, {0x1E78,0x1E79}, {0x1E7A,0x1E7B}, {0x1E7C,0x1E7D}, {0x1E7E,0x1E7F}, 
+  {0x1E80,0x1E81}, {0x1E82,0x1E83}, {0x1E84,0x1E85}, {0x1E86,0x1E87}, {0x1E88,0x1E89}, 
+  {0x1E8A,0x1E8B}, {0x1E8C,0x1E8D}, {0x1E8E,0x1E8F}, {0x1E90,0x1E91}, {0x1E92,0x1E93}, 
+  {0x1E94,0x1E95}, {0x1EA0,0x1EA1}, {0x1EA2,0x1EA3}, {0x1EA4,0x1EA5}, {0x1EA6,0x1EA7}, 
+  {0x1EA8,0x1EA9}, {0x1EAA,0x1EAB}, {0x1EAC,0x1EAD}, {0x1EAE,0x1EAF}, {0x1EB0,0x1EB1}, 
+  {0x1EB2,0x1EB3}, {0x1EB4,0x1EB5}, {0x1EB6,0x1EB7}, {0x1EB8,0x1EB9}, {0x1EBA,0x1EBB}, 
+  {0x1EBC,0x1EBD}, {0x1EBE,0x1EBF}, {0x1EC0,0x1EC1}, {0x1EC2,0x1EC3}, {0x1EC4,0x1EC5}, 
+  {0x1EC6,0x1EC7}, {0x1EC8,0x1EC9}, {0x1ECA,0x1ECB}, {0x1ECC,0x1ECD}, {0x1ECE,0x1ECF}, 
+  {0x1ED0,0x1ED1}, {0x1ED2,0x1ED3}, {0x1ED4,0x1ED5}, {0x1ED6,0x1ED7}, {0x1ED8,0x1ED9}, 
+  {0x1EDA,0x1EDB}, {0x1EDC,0x1EDD}, {0x1EDE,0x1EDF}, {0x1EE0,0x1EE1}, {0x1EE2,0x1EE3}, 
+  {0x1EE4,0x1EE5}, {0x1EE6,0x1EE7}, {0x1EE8,0x1EE9}, {0x1EEA,0x1EEB}, {0x1EEC,0x1EED}, 
+  {0x1EEE,0x1EEF}, {0x1EF0,0x1EF1}, {0x1EF2,0x1EF3}, {0x1EF4,0x1EF5}, {0x1EF6,0x1EF7}, 
+  {0x1EF8,0x1EF9}, {0x1F08,0x1F00}, {0x1F09,0x1F01}, {0x1F0A,0x1F02}, {0x1F0B,0x1F03}, 
+  {0x1F0C,0x1F04}, {0x1F0D,0x1F05}, {0x1F0E,0x1F06}, {0x1F0F,0x1F07}, {0x1F18,0x1F10}, 
+  {0x1F19,0x1F11}, {0x1F1A,0x1F12}, {0x1F1B,0x1F13}, {0x1F1C,0x1F14}, {0x1F1D,0x1F15}, 
+  {0x1F28,0x1F20}, {0x1F29,0x1F21}, {0x1F2A,0x1F22}, {0x1F2B,0x1F23}, {0x1F2C,0x1F24}, 
+  {0x1F2D,0x1F25}, {0x1F2E,0x1F26}, {0x1F2F,0x1F27}, {0x1F38,0x1F30}, {0x1F39,0x1F31}, 
+  {0x1F3A,0x1F32}, {0x1F3B,0x1F33}, {0x1F3C,0x1F34}, {0x1F3D,0x1F35}, {0x1F3E,0x1F36}, 
+  {0x1F3F,0x1F37}, {0x1F48,0x1F40}, {0x1F49,0x1F41}, {0x1F4A,0x1F42}, {0x1F4B,0x1F43}, 
+  {0x1F4C,0x1F44}, {0x1F4D,0x1F45}, {0x1F59,0x1F51}, {0x1F5B,0x1F53}, {0x1F5D,0x1F55}, 
+  {0x1F5F,0x1F57}, {0x1F68,0x1F60}, {0x1F69,0x1F61}, {0x1F6A,0x1F62}, {0x1F6B,0x1F63}, 
+  {0x1F6C,0x1F64}, {0x1F6D,0x1F65}, {0x1F6E,0x1F66}, {0x1F6F,0x1F67}, {0x1F88,0x1F80}, 
+  {0x1F89,0x1F81}, {0x1F8A,0x1F82}, {0x1F8B,0x1F83}, {0x1F8C,0x1F84}, {0x1F8D,0x1F85}, 
+  {0x1F8E,0x1F86}, {0x1F8F,0x1F87}, {0x1F98,0x1F90}, {0x1F99,0x1F91}, {0x1F9A,0x1F92}, 
+  {0x1F9B,0x1F93}, {0x1F9C,0x1F94}, {0x1F9D,0x1F95}, {0x1F9E,0x1F96}, {0x1F9F,0x1F97}, 
+  {0x1FA8,0x1FA0}, {0x1FA9,0x1FA1}, {0x1FAA,0x1FA2}, {0x1FAB,0x1FA3}, {0x1FAC,0x1FA4}, 
+  {0x1FAD,0x1FA5}, {0x1FAE,0x1FA6}, {0x1FAF,0x1FA7}, {0x1FB8,0x1FB0}, {0x1FB9,0x1FB1}, 
+  {0x1FBA,0x1F70}, {0x1FBB,0x1F71}, {0x1FBC,0x1FB3}, {0x1FC8,0x1F72}, {0x1FC9,0x1F73}, 
+  {0x1FCA,0x1F74}, {0x1FCB,0x1F75}, {0x1FCC,0x1FC3}, {0x1FD8,0x1FD0}, {0x1FD9,0x1FD1}, 
+  {0x1FDA,0x1F76}, {0x1FDB,0x1F77}, {0x1FE8,0x1FE0}, {0x1FE9,0x1FE1}, {0x1FEA,0x1F7A}, 
+  {0x1FEB,0x1F7B}, {0x1FEC,0x1FE5}, {0x1FF8,0x1F78}, {0x1FF9,0x1F79}, {0x1FFA,0x1F7C}, 
+  {0x1FFB,0x1F7D}, {0x1FFC,0x1FF3}, {0x2160,0x2170}, {0x2161,0x2171}, {0x2162,0x2172}, 
+  {0x2163,0x2173}, {0x2164,0x2174}, {0x2165,0x2175}, {0x2166,0x2176}, {0x2167,0x2177}, 
+  {0x2168,0x2178}, {0x2169,0x2179}, {0x216A,0x217A}, {0x216B,0x217B}, {0x216C,0x217C}, 
+  {0x216D,0x217D}, {0x216E,0x217E}, {0x216F,0x217F}, {0x24B6,0x24D0}, {0x24B7,0x24D1}, 
+  {0x24B8,0x24D2}, {0x24B9,0x24D3}, {0x24BA,0x24D4}, {0x24BB,0x24D5}, {0x24BC,0x24D6}, 
+  {0x24BD,0x24D7}, {0x24BE,0x24D8}, {0x24BF,0x24D9}, {0x24C0,0x24DA}, {0x24C1,0x24DB}, 
+  {0x24C2,0x24DC}, {0x24C3,0x24DD}, {0x24C4,0x24DE}, {0x24C5,0x24DF}, {0x24C6,0x24E0}, 
+  {0x24C7,0x24E1}, {0x24C8,0x24E2}, {0x24C9,0x24E3}, {0x24CA,0x24E4}, {0x24CB,0x24E5}, 
+  {0x24CC,0x24E6}, {0x24CD,0x24E7}, {0x24CE,0x24E8}, {0x24CF,0x24E9}, {0xFF21,0xFF41}, 
+  {0xFF22,0xFF42}, {0xFF23,0xFF43}, {0xFF24,0xFF44}, {0xFF25,0xFF45}, {0xFF26,0xFF46}, 
+  {0xFF27,0xFF47}, {0xFF28,0xFF48}, {0xFF29,0xFF49}, {0xFF2A,0xFF4A}, {0xFF2B,0xFF4B}, 
+  {0xFF2C,0xFF4C}, {0xFF2D,0xFF4D}, {0xFF2E,0xFF4E}, {0xFF2F,0xFF4F}, {0xFF30,0xFF50}, 
+  {0xFF31,0xFF51}, {0xFF32,0xFF52}, {0xFF33,0xFF53}, {0xFF34,0xFF54}, {0xFF35,0xFF55}, 
+  {0xFF36,0xFF56}, {0xFF37,0xFF57}, {0xFF38,0xFF58}, {0xFF39,0xFF59}, {0xFF3A,0xFF5A}
+};
+
+
+
+#define NUM_TOSIMPLIFIED_INFO 2145
+static const unirelate tosimplified_info[NUM_TOSIMPLIFIED_INFO] = {
+  {0x4E48,0x9EBD}, {0x4E82,0x4E71}, {0x4E9E,0x4E9A}, {0x4F47,0x4F2B}, {0x4F59,0x9980}, 
+  {0x4F86,0x6765}, {0x4F96,0x4ED1}, {0x4FE0,0x4FA0}, {0x5000,0x4F25}, {0x5006,0x4FE9}, 
+  {0x5009,0x4ED3}, {0x500B,0x4E2A}, {0x5011,0x4EEC}, {0x502B,0x4F26}, {0x5049,0x4F1F}, 
+  {0x5074,0x4FA7}, {0x5075,0x4FA6}, {0x5096,0x4F27}, {0x5098,0x4F1E}, {0x5099,0x5907}, 
+  {0x50AD,0x4F63}, {0x50B3,0x4F20}, {0x50B4,0x4F1B}, {0x50B5,0x503A}, {0x50B7,0x4F24}, 
+  {0x50BE,0x503E}, {0x50C2,0x507B}, {0x50C5,0x4EC5}, {0x50C9,0x4F65}, {0x50D1,0x4FA8}, 
+  {0x50D5,0x4EC6}, {0x50DE,0x4F2A}, {0x50E5,0x4FA5}, {0x50E8,0x507E}, {0x50F9,0x4EF7}, 
+  {0x5100,0x4EEA}, {0x5102,0x4FAC}, {0x5104,0x4EBF}, {0x5108,0x4FA9}, {0x5109,0x4FED}, 
+  {0x5110,0x50A7}, {0x5114,0x4FE6}, {0x5115,0x4FAA}, {0x511F,0x507F}, {0x512A,0x4F18}, 
+  {0x5132,0x50A8}, {0x5137,0x4FEA}, {0x513A,0x50A9}, {0x513B,0x50A5}, {0x513C,0x4FE8}, 
+  {0x5152,0x513F}, {0x5169,0x4E24}, {0x51C8,0x51C0}, {0x51CD,0x51BB}, {0x51F1,0x51EF}, 
+  {0x5244,0x522D}, {0x5247,0x5219}, {0x525B,0x521A}, {0x526E,0x5250}, {0x5274,0x5240}, 
+  {0x5275,0x521B}, {0x5283,0x5212}, {0x5287,0x5267}, {0x5289,0x5218}, {0x528A,0x523D}, 
+  {0x528C,0x523F}, {0x528D,0x5251}, {0x5291,0x5242}, {0x52C1,0x52B2}, {0x52D5,0x52A8}, 
+  {0x52D9,0x52A1}, {0x52DB,0x52CB}, {0x52DD,0x80DC}, {0x52DE,0x52B3}, {0x52E2,0x52BF}, 
+  {0x52F1,0x52A2}, {0x52F5,0x52B1}, {0x52F8,0x529D}, {0x532D,0x5326}, {0x532F,0x6C47}, 
+  {0x5331,0x532E}, {0x5340,0x533A}, {0x5354,0x534F}, {0x5399,0x538D}, {0x53A0,0x5395}, 
+  {0x53AD,0x538C}, {0x53B2,0x5389}, {0x53B4,0x53A3}, {0x53C3,0x53C2}, {0x53E2,0x4E1B}, 
+  {0x540E,0x5F8C}, {0x54BC,0x5459}, {0x54E1,0x5458}, {0x5504,0x5457}, {0x554F,0x95EE}, 
+  {0x5553,0x542F}, {0x555E,0x54D1}, {0x559A,0x5524}, {0x55AA,0x4E27}, {0x55AC,0x4E54}, 
+  {0x55AE,0x5355}, {0x55B2,0x54DF}, {0x55C6,0x545B}, {0x55C7,0x556C}, {0x55CE,0x5417}, 
+  {0x55DA,0x545C}, {0x55E9,0x5522}, {0x55F6,0x54D4}, {0x5606,0x53F9}, {0x560D,0x55BD}, 
+  {0x5614,0x5455}, {0x5616,0x5567}, {0x5617,0x5C1D}, {0x561C,0x551B}, {0x5629,0x54D7}, 
+  {0x562E,0x5520}, {0x562F,0x5578}, {0x5630,0x53FD}, {0x5635,0x54D3}, {0x5638,0x5452}, 
+  {0x565D,0x549D}, {0x5660,0x54D2}, {0x5665,0x54DD}, {0x5666,0x54D5}, {0x566F,0x55F3}, 
+  {0x5672,0x54D9}, {0x5674,0x55B7}, {0x5678,0x5428}, {0x5680,0x549B}, {0x5687,0x5413}, 
+  {0x568C,0x54DC}, {0x5695,0x565C}, {0x5699,0x556E}, {0x56A6,0x5456}, {0x56A8,0x5499}, 
+  {0x56B3,0x55BE}, {0x56B4,0x4E25}, {0x56B6,0x5624}, {0x56C0,0x556D}, {0x56C1,0x55EB}, 
+  {0x56C2,0x56A3}, {0x56C5,0x5181}, {0x56C8,0x5453}, {0x56D1,0x5631}, {0x5707,0x56F5}, 
+  {0x570B,0x56FD}, {0x570D,0x56F4}, {0x5712,0x56ED}, {0x5713,0x5706}, {0x5716,0x56FE}, 
+  {0x5718,0x56E2}, {0x57E1,0x57AD}, {0x57F7,0x6267}, {0x5805,0x575A}, {0x580A,0x57A9}, 
+  {0x5816,0x57B4}, {0x581D,0x57DA}, {0x582F,0x5C27}, {0x5831,0x62A5}, {0x5834,0x573A}, 
+  {0x584A,0x5757}, {0x584B,0x8314}, {0x584F,0x57B2}, {0x5852,0x57D8}, {0x5857,0x6D82}, 
+  {0x5862,0x575E}, {0x5864,0x57D9}, {0x5875,0x5C18}, {0x5879,0x5811}, {0x588A,0x57AB}, 
+  {0x589C,0x5760}, {0x58AE,0x5815}, {0x58B3,0x575F}, {0x58BB,0x5899}, {0x58BE,0x57A6}, 
+  {0x58C7,0x575B}, {0x58D3,0x538B}, {0x58D8,0x5792}, {0x58D9,0x5739}, {0x58DA,0x5786}, 
+  {0x58DE,0x574F}, {0x58DF,0x5784}, {0x58E0,0x5785}, {0x58E2,0x575C}, {0x58E9,0x575D}, 
+  {0x58EF,0x58EE}, {0x58FA,0x58F6}, {0x58FD,0x5BFF}, {0x5922,0x68A6}, {0x593E,0x5939}, 
+  {0x5950,0x5942}, {0x5969,0x5941}, {0x596A,0x593A}, {0x596C,0x5956}, {0x596E,0x594B}, 
+  {0x599D,0x5986}, {0x5A41,0x5A04}, {0x5A66,0x5987}, {0x5A6D,0x5A05}, {0x5AA7,0x5A32}, 
+  {0x5ABD,0x5988}, {0x5AD7,0x59AA}, {0x5AF5,0x59A9}, {0x5AFB,0x5A34}, {0x5B00,0x59AB}, 
+  {0x5B08,0x5A06}, {0x5B0B,0x5A75}, {0x5B0C,0x5A07}, {0x5B19,0x5AF1}, {0x5B21,0x5AD2}, 
+  {0x5B2A,0x5AD4}, {0x5B30,0x5A74}, {0x5B38,0x5A76}, {0x5B4C,0x5A08}, {0x5B6B,0x5B59}, 
+  {0x5B78,0x5B66}, {0x5B7F,0x5B6A}, {0x5BE2,0x5BDD}, {0x5BE6,0x5B9E}, {0x5BE7,0x5B81}, 
+  {0x5BE9,0x5BA1}, {0x5BEB,0x5199}, {0x5BEC,0x5BBD}, {0x5BF5,0x5BA0}, {0x5BF6,0x5B9D}, 
+  {0x5C07,0x5C06}, {0x5C08,0x4E13}, {0x5C0B,0x5BFB}, {0x5C0D,0x5BF9}, {0x5C0E,0x5BFC}, 
+  {0x5C37,0x5C34}, {0x5C62,0x5C61}, {0x5C64,0x5C42}, {0x5C68,0x5C66}, {0x5C6C,0x5C5E}, 
+  {0x5CA1,0x5188}, {0x5CF4,0x5C98}, {0x5CF6,0x5C9B}, {0x5CFD,0x5CE1}, {0x5D0D,0x5D03}, 
+  {0x5D17,0x5C97}, {0x5D22,0x5CE5}, {0x5D2C,0x5CBD}, {0x5D50,0x5C9A}, {0x5D81,0x5D5D}, 
+  {0x5D84,0x5D2D}, {0x5D87,0x5C96}, {0x5D97,0x5D02}, {0x5DA0,0x5CE4}, {0x5DA7,0x5CC4}, 
+  {0x5DB8,0x5D58}, {0x5DBA,0x5CAD}, {0x5DBC,0x5C7F}, {0x5DCB,0x5CBF}, {0x5DD2,0x5CE6}, 
+  {0x5DD4,0x5DC5}, {0x5DF0,0x5DEF}, {0x5E25,0x5E05}, {0x5E2B,0x5E08}, {0x5E33,0x5E10}, 
+  {0x5E36,0x5E26}, {0x5E40,0x5E27}, {0x5E43,0x5E0F}, {0x5E57,0x5E3C}, {0x5E58,0x5E3B}, 
+  {0x5E5F,0x5E1C}, {0x5E63,0x5E01}, {0x5E6B,0x5E2E}, {0x5E6C,0x5E31}, {0x5E79,0x5E72}, 
+  {0x5E7E,0x51E0}, {0x5EAB,0x5E93}, {0x5EDF,0x5E99}, {0x5EE0,0x5382}, {0x5EE1,0x5E91}, 
+  {0x5EE2,0x5E9F}, {0x5EE3,0x5E7F}, {0x5EEC,0x5E90}, {0x5EF3,0x5385}, {0x5F33,0x5F2A}, 
+  {0x5F35,0x5F20}, {0x5F48,0x5F39}, {0x5F4C,0x5F25}, {0x5F4E,0x5F2F}, {0x5F8C,0x540E}, 
+  {0x5F91,0x5F84}, {0x5F9E,0x4ECE}, {0x5FA0,0x5F95}, {0x5FA9,0x590D}, {0x5FB9,0x5F7B}, 
+  {0x60B5,0x6005}, {0x60B6,0x95F7}, {0x60E1,0x6076}, {0x60F1,0x607C}, {0x60F2,0x607D}, 
+  {0x60FB,0x607B}, {0x611B,0x7231}, {0x611C,0x60EC}, {0x6134,0x6006}, {0x6137,0x607A}, 
+  {0x613E,0x5FFE}, {0x614B,0x6001}, {0x6158,0x60E8}, {0x615A,0x60ED}, {0x615F,0x6078}, 
+  {0x6163,0x60EF}, {0x6164,0x60AB}, {0x616A,0x6004}, {0x616B,0x6002}, {0x616E,0x8651}, 
+  {0x6173,0x60AD}, {0x6176,0x5E86}, {0x6182,0x5FE7}, {0x618A,0x60EB}, {0x6190,0x601C}, 
+  {0x6191,0x51ED}, {0x6192,0x6126}, {0x619A,0x60EE}, {0x61A4,0x6124}, {0x61AB,0x60AF}, 
+  {0x61AE,0x6003}, {0x61B2,0x5BAA}, {0x61B6,0x5FC6}, {0x61C7,0x6073}, {0x61C9,0x5E94}, 
+  {0x61CC,0x603F}, {0x61DF,0x603C}, {0x61E3,0x61D1}, {0x61E8,0x6079}, {0x61F2,0x60E9}, 
+  {0x61F6,0x61D2}, {0x61F7,0x6000}, {0x61F8,0x60AC}, {0x61FA,0x5FCF}, {0x61FC,0x60E7}, 
+  {0x61FE,0x6151}, {0x6200,0x604B}, {0x6207,0x6206}, {0x6214,0x620B}, {0x6227,0x6217}, 
+  {0x6229,0x622C}, {0x6230,0x6218}, {0x6232,0x620F}, {0x633E,0x631F}, {0x6368,0x820D}, 
+  {0x636B,0x626A}, {0x6383,0x626B}, {0x6384,0x62A1}, {0x6399,0x6323}, {0x63C0,0x62E3}, 
+  {0x63DA,0x626C}, {0x63DB,0x6362}, {0x63EE,0x6325}, {0x640D,0x635F}, {0x6417,0x6363}, 
+  {0x6436,0x62A2}, {0x6451,0x63B4}, {0x645C,0x63BC}, {0x645F,0x6402}, {0x646F,0x631A}, 
+  {0x6473,0x62A0}, {0x6476,0x629F}, {0x647B,0x63BA}, {0x6488,0x635E}, {0x6493,0x6320}, 
+  {0x649F,0x6322}, {0x64A3,0x63B8}, {0x64A5,0x62E8}, {0x64AB,0x629A}, {0x64B2,0x6251}, 
+  {0x64B3,0x63FF}, {0x64BB,0x631E}, {0x64BE,0x631D}, {0x64BF,0x6361}, {0x64C1,0x62E5}, 
+  {0x64C4,0x63B3}, {0x64C7,0x62E9}, {0x64CA,0x51FB}, {0x64CB,0x6321}, {0x64D4,0x62C5}, 
+  {0x64DA,0x636E}, {0x64E0,0x6324}, {0x64EC,0x62DF}, {0x64EF,0x6448}, {0x64F0,0x62E7}, 
+  {0x64F1,0x6401}, {0x64F2,0x63B7}, {0x64F4,0x6269}, {0x64F7,0x64B7}, {0x64FA,0x6446}, 
+  {0x64FB,0x64DE}, {0x64FC,0x64B8}, {0x64FE,0x6270}, {0x6504,0x6445}, {0x6506,0x64B5}, 
+  {0x650F,0x62E2}, {0x6514,0x62E6}, {0x6516,0x6484}, {0x6519,0x6400}, {0x651B,0x64BA}, 
+  {0x651D,0x6444}, {0x6522,0x6512}, {0x6523,0x631B}, {0x6524,0x644A}, {0x652A,0x6405}, 
+  {0x652C,0x63FD}, {0x6557,0x8D25}, {0x6575,0x654C}, {0x6578,0x6570}, {0x6582,0x655B}, 
+  {0x6583,0x6BD9}, {0x6595,0x6593}, {0x65AC,0x65A9}, {0x65B7,0x65AD}, {0x6642,0x65F6}, 
+  {0x6649,0x664B}, {0x665D,0x663C}, {0x6688,0x6655}, {0x6689,0x6656}, {0x66A2,0x7545}, 
+  {0x66AB,0x6682}, {0x66C4,0x6654}, {0x66C7,0x6619}, {0x66C9,0x6653}, {0x66D6,0x66A7}, 
+  {0x66E0,0x65F7}, {0x66EC,0x6652}, {0x66F8,0x4E66}, {0x6703,0x4F1A}, {0x6727,0x80E7}, 
+  {0x6771,0x4E1C}, {0x6898,0x67A7}, {0x689D,0x6761}, {0x689F,0x67AD}, {0x68C4,0x5F03}, 
+  {0x68D6,0x67A8}, {0x68D7,0x67A3}, {0x68DF,0x680B}, {0x68E7,0x6808}, {0x68F2,0x6816}, 
+  {0x690F,0x6860}, {0x694A,0x6768}, {0x6953,0x67AB}, {0x6968,0x6862}, {0x696D,0x4E1A}, 
+  {0x6975,0x6781}, {0x69AA,0x6769}, {0x69AE,0x8363}, {0x69BF,0x6864}, {0x69CB,0x6784}, 
+  {0x69CD,0x67AA}, {0x69E7,0x6920}, {0x69F3,0x6868}, {0x6A01,0x6869}, {0x6A02,0x4E50}, 
+  {0x6A05,0x679E}, {0x6A13,0x697C}, {0x6A19,0x6807}, {0x6A1E,0x67A2}, {0x6A23,0x6837}, 
+  {0x6A38,0x6734}, {0x6A39,0x6811}, {0x6A3A,0x6866}, {0x6A48,0x6861}, {0x6A4B,0x6865}, 
+  {0x6A5F,0x673A}, {0x6A62,0x692D}, {0x6A89,0x67FD}, {0x6A94,0x6863}, {0x6A9C,0x6867}, 
+  {0x6AA2,0x68C0}, {0x6AA3,0x6A2F}, {0x6AB3,0x69DF}, {0x6AB8,0x67E0}, {0x6ABB,0x69DB}, 
+  {0x6AC3,0x67DC}, {0x6AD3,0x6A79}, {0x6ADA,0x6988}, {0x6ADB,0x6809}, {0x6ADD,0x691F}, 
+  {0x6ADE,0x6A7C}, {0x6ADF,0x680E}, {0x6AE7,0x69E0}, {0x6AE8,0x680C}, {0x6AEA,0x67A5}, 
+  {0x6AEC,0x6987}, {0x6AF3,0x680A}, {0x6AF8,0x6989}, {0x6AFB,0x6A31}, {0x6B04,0x680F}, 
+  {0x6B0A,0x6743}, {0x6B0F,0x6924}, {0x6B12,0x683E}, {0x6B16,0x6984}, {0x6B1E,0x68C2}, 
+  {0x6B3D,0x94A6}, {0x6B50,0x6B27}, {0x6B5F,0x6B24}, {0x6B61,0x6B22}, {0x6B72,0x5C81}, 
+  {0x6B77,0x5386}, {0x6B78,0x5F52}, {0x6B98,0x6B8B}, {0x6B9E,0x6B92}, {0x6BA4,0x6B87}, 
+  {0x6BAB,0x6B9A}, {0x6BAE,0x6B93}, {0x6BAF,0x6BA1}, {0x6BB2,0x6B7C}, {0x6BBA,0x6740}, 
+  {0x6BBB,0x58F3}, {0x6BC6,0x6BB4}, {0x6BFF,0x6BF5}, {0x6C08,0x6BE1}, {0x6C0C,0x6C07}, 
+  {0x6C23,0x6C14}, {0x6C2B,0x6C22}, {0x6C2C,0x6C29}, {0x6D79,0x6D43}, {0x6D87,0x6CFE}, 
+  {0x6DEA,0x6CA6}, {0x6DF5,0x6E0A}, {0x6DF6,0x6D9E}, {0x6DFA,0x6D45}, {0x6E19,0x6DA3}, 
+  {0x6E26,0x6DA1}, {0x6E2C,0x6D4B}, {0x6E3E,0x6D51}, {0x6E5E,0x6D48}, {0x6E6F,0x6C64}, 
+  {0x6E96,0x51C6}, {0x6E9D,0x6C9F}, {0x6EC4,0x6CA7}, {0x6EC5,0x706D}, {0x6ECC,0x6DA4}, 
+  {0x6ECE,0x8365}, {0x6EEC,0x6CAA}, {0x6EEF,0x6EDE}, {0x6EF2,0x6E17}, {0x6EF7,0x5364}, 
+  {0x6EF8,0x6D52}, {0x6EFF,0x6EE1}, {0x6F01,0x6E14}, {0x6F1A,0x6CA4}, {0x6F22,0x6C49}, 
+  {0x6F23,0x6D9F}, {0x6F2C,0x6E0D}, {0x6F32,0x6DA8}, {0x6F38,0x6E10}, {0x6F3F,0x6D46}, 
+  {0x6F41,0x988D}, {0x6F51,0x6CFC}, {0x6F54,0x6D01}, {0x6F59,0x6CA9}, {0x6F5B,0x6F5C}, 
+  {0x6F64,0x6DA6}, {0x6F6F,0x6D54}, {0x6F70,0x6E83}, {0x6F77,0x6ED7}, {0x6F7F,0x6DA0}, 
+  {0x6F80,0x6DA9}, {0x6F86,0x6D47}, {0x6F87,0x6D9D}, {0x6F97,0x6DA7}, {0x6FA0,0x6E11}, 
+  {0x6FA4,0x6CFD}, {0x6FA9,0x6CF6}, {0x6FAE,0x6D4D}, {0x6FB1,0x6DC0}, {0x6FC1,0x6D4A}, 
+  {0x6FC3,0x6D53}, {0x6FD5,0x6E7F}, {0x6FD8,0x6CDE}, {0x6FDF,0x6D4E}, {0x6FE4,0x6D9B}, 
+  {0x6FEB,0x6EE5}, {0x6FF0,0x6F4D}, {0x6FF1,0x6EE8}, {0x6FFA,0x6E85}, {0x6FFC,0x6CFA}, 
+  {0x6FFE,0x6EE4}, {0x7005,0x6EE2}, {0x7006,0x6E0E}, {0x7009,0x6CFB}, {0x700B,0x6E16}, 
+  {0x700F,0x6D4F}, {0x7015,0x6FD2}, {0x7018,0x6CF8}, {0x701D,0x6CA5}, {0x701F,0x6F47}, 
+  {0x7020,0x6F46}, {0x7027,0x6CF7}, {0x7028,0x6FD1}, {0x7032,0x6F4B}, {0x703E,0x6F9C}, 
+  {0x7043,0x6CA3}, {0x7044,0x6EE0}, {0x7051,0x6D12}, {0x7055,0x6F13}, {0x7058,0x6EE9}, 
+  {0x705D,0x704F}, {0x7063,0x6E7E}, {0x7064,0x6EE6}, {0x7067,0x6EDF}, {0x70CF,0x4E4C}, 
+  {0x70F4,0x70C3}, {0x7121,0x65E0}, {0x7149,0x70BC}, {0x7152,0x709C}, {0x7162,0x8315}, 
+  {0x7165,0x7115}, {0x7169,0x70E6}, {0x716C,0x7080}, {0x7192,0x8367}, {0x7197,0x709D}, 
+  {0x71B1,0x70ED}, {0x71BE,0x70BD}, {0x71C1,0x70E8}, {0x71C8,0x706F}, {0x71D2,0x70E7}, 
+  {0x71D9,0x70EB}, {0x71DC,0x7116}, {0x71DF,0x8425}, {0x71E6,0x707F}, {0x71ED,0x70DB}, 
+  {0x71F4,0x70E9}, {0x71FC,0x70EC}, {0x71FE,0x7118}, {0x720D,0x70C1}, {0x7210,0x7089}, 
+  {0x721B,0x70C2}, {0x722D,0x4E89}, {0x7232,0x4E3A}, {0x723A,0x7237}, {0x723E,0x5C14}, 
+  {0x7258,0x724D}, {0x727D,0x7275}, {0x7296,0x8366}, {0x72A2,0x728A}, {0x72A7,0x727A}, 
+  {0x72C0,0x72B6}, {0x72F9,0x72ED}, {0x72FD,0x72C8}, {0x7319,0x72F0}, {0x7336,0x72B9}, 
+  {0x733B,0x72F2}, {0x7341,0x72B8}, {0x7344,0x72F1}, {0x7345,0x72EE}, {0x7368,0x72EC}, 
+  {0x736A,0x72EF}, {0x736B,0x7303}, {0x7370,0x72DE}, {0x7372,0x83B7}, {0x7375,0x730E}, 
+  {0x7377,0x72B7}, {0x7378,0x517D}, {0x737A,0x736D}, {0x737B,0x732E}, {0x737C,0x7315}, 
+  {0x7380,0x7321}, {0x73FE,0x73B0}, {0x743F,0x73F2}, {0x744B,0x73AE}, {0x7463,0x7410}, 
+  {0x7469,0x83B9}, {0x746A,0x739B}, {0x7489,0x740F}, {0x74A3,0x7391}, {0x74A6,0x7477}, 
+  {0x74B0,0x73AF}, {0x74BD,0x73BA}, {0x74CA,0x743C}, {0x74CF,0x73D1}, {0x74D4,0x748E}, 
+  {0x74DA,0x74D2}, {0x750C,0x74EF}, {0x7523,0x4EA7}, {0x755D,0x4EA9}, {0x7562,0x6BD5}, 
+  {0x756B,0x753B}, {0x7576,0x5F53}, {0x7587,0x7574}, {0x758A,0x53E0}, {0x75D9,0x75C9}, 
+  {0x7602,0x75D6}, {0x760B,0x75AF}, {0x760D,0x75A1}, {0x7613,0x75EA}, {0x761E,0x7617}, 
+  {0x7621,0x75AE}, {0x7627,0x759F}, {0x763B,0x7618}, {0x7642,0x7597}, {0x7646,0x75E8}, 
+  {0x7647,0x75EB}, {0x7649,0x7605}, {0x7658,0x75A0}, {0x765F,0x762A}, {0x7662,0x75D2}, 
+  {0x7664,0x7596}, {0x7665,0x75C7}, {0x7667,0x75AC}, {0x7669,0x765E}, {0x766C,0x7663}, 
+  {0x766D,0x763F}, {0x766E,0x763E}, {0x7670,0x75C8}, {0x7671,0x762B}, {0x7672,0x766B}, 
+  {0x767C,0x53D1}, {0x769A,0x7691}, {0x76B8,0x76B2}, {0x76BA,0x76B1}, {0x76DE,0x76CF}, 
+  {0x76E1,0x5C3D}, {0x76E3,0x76D1}, {0x76E4,0x76D8}, {0x76E7,0x5362}, {0x775C,0x7741}, 
+  {0x775E,0x7750}, {0x7798,0x770D}, {0x779E,0x7792}, {0x77BC,0x7751}, {0x77DA,0x77A9}, 
+  {0x77EF,0x77EB}, {0x7864,0x7856}, {0x7868,0x7817}, {0x786F,0x781A}, {0x78A9,0x7855}, 
+  {0x78AD,0x7800}, {0x78B8,0x781C}, {0x78BA,0x786E}, {0x78BC,0x7801}, {0x78DA,0x7816}, 
+  {0x78E3,0x789C}, {0x78E7,0x789B}, {0x78EF,0x77F6}, {0x78FD,0x7857}, {0x790E,0x7840}, 
+  {0x7919,0x788D}, {0x7926,0x77FF}, {0x792A,0x783A}, {0x792B,0x783E}, {0x792C,0x77FE}, 
+  {0x7931,0x783B}, {0x798D,0x7978}, {0x798E,0x796F}, {0x79AA,0x7985}, {0x79AE,0x793C}, 
+  {0x79B0,0x7962}, {0x79B1,0x7977}, {0x7A2E,0x79CD}, {0x7A31,0x79F0}, {0x7A4C,0x7A23}, 
+  {0x7A4D,0x79EF}, {0x7A4E,0x9896}, {0x7A61,0x7A51}, {0x7A62,0x79FD}, {0x7A69,0x7A33}, 
+  {0x7AA9,0x7A9D}, {0x7AAA,0x6D3C}, {0x7AAE,0x7A77}, {0x7AB6,0x7AAD}, {0x7ABA,0x7AA5}, 
+  {0x7AC4,0x7A9C}, {0x7AC5,0x7A8D}, {0x7AC7,0x7AA6}, {0x7AC8,0x7076}, {0x7ACA,0x7A83}, 
+  {0x7AEA,0x7AD6}, {0x7AF6,0x7ADE}, {0x7B46,0x7B14}, {0x7B67,0x7B15}, {0x7B8B,0x7B3A}, 
+  {0x7B8F,0x7B5D}, {0x7BC0,0x8282}, {0x7BC4,0x8303}, {0x7BC9,0x7B51}, {0x7BCB,0x7BA7}, 
+  {0x7BE4,0x7B03}, {0x7BE9,0x7B5B}, {0x7BF3,0x7B5A}, {0x7C00,0x7BA6}, {0x7C0D,0x7BD3}, 
+  {0x7C1E,0x7BAA}, {0x7C21,0x7B80}, {0x7C23,0x7BD1}, {0x7C2B,0x7BAB}, {0x7C3D,0x7B7E}, 
+  {0x7C3E,0x5E18}, {0x7C43,0x7BEE}, {0x7C4C,0x7B79}, {0x7C5C,0x7BA8}, {0x7C5F,0x7C41}, 
+  {0x7C60,0x7B3C}, {0x7C69,0x7B3E}, {0x7C6A,0x7C16}, {0x7C6C,0x7BF1}, {0x7C6E,0x7BA9}, 
+  {0x7CDD,0x7CC1}, {0x7CDE,0x7CAA}, {0x7CE7,0x7CAE}, {0x7CF2,0x7C9D}, {0x7CF4,0x7C74}, 
+  {0x7CF6,0x7C9C}, {0x7CF9,0x7E9F}, {0x7CFE,0x7EA0}, {0x7D00,0x7EAA}, {0x7D02,0x7EA3}, 
+  {0x7D04,0x7EA6}, {0x7D05,0x7EA2}, {0x7D06,0x7EA1}, {0x7D07,0x7EA5}, {0x7D08,0x7EA8}, 
+  {0x7D09,0x7EAB}, {0x7D0B,0x7EB9}, {0x7D0D,0x7EB3}, {0x7D10,0x7EBD}, {0x7D13,0x7EBE}, 
+  {0x7D14,0x7EAF}, {0x7D15,0x7EB0}, {0x7D17,0x7EB1}, {0x7D19,0x7EB8}, {0x7D1A,0x7EA7}, 
+  {0x7D1B,0x7EB7}, {0x7D1C,0x7EAD}, {0x7D21,0x7EBA}, {0x7D30,0x7EC6}, {0x7D31,0x7EC2}, 
+  {0x7D32,0x7EC1}, {0x7D33,0x7EC5}, {0x7D39,0x7ECD}, {0x7D3A,0x7EC0}, {0x7D3C,0x7ECB}, 
+  {0x7D3F,0x7ED0}, {0x7D40,0x7ECC}, {0x7D42,0x7EC8}, {0x7D44,0x7EC4}, {0x7D46,0x7ECA}, 
+  {0x7D4E,0x7ED7}, {0x7D50,0x7ED3}, {0x7D5D,0x7ED4}, {0x7D5E,0x7EDE}, {0x7D61,0x7EDC}, 
+  {0x7D62,0x7EDA}, {0x7D66,0x7ED9}, {0x7D68,0x7ED2}, {0x7D71,0x7EDF}, {0x7D72,0x4E1D}, 
+  {0x7D73,0x7EDB}, {0x7D76,0x7EDD}, {0x7D79,0x7EE2}, {0x7D81,0x7ED1}, {0x7D83,0x7EE1}, 
+  {0x7D86,0x7EE0}, {0x7D88,0x7EE8}, {0x7D89,0x7EE3}, {0x7D8F,0x7EE5}, {0x7D93,0x7ECF}, 
+  {0x7D9C,0x7EFC}, {0x7D9E,0x7F0D}, {0x7DA2,0x7EF8}, {0x7DA3,0x7EFB}, {0x7DAB,0x7EBF}, 
+  {0x7DAC,0x7EF6}, {0x7DAD,0x7EF4}, {0x7DB0,0x7EFE}, {0x7DB1,0x7EB2}, {0x7DB2,0x7F51}, 
+  {0x7DB3,0x7EF7}, {0x7DB4,0x7F00}, {0x7DB8,0x7EB6}, {0x7DB9,0x7EFA}, {0x7DBA,0x7EEE}, 
+  {0x7DBB,0x7EFD}, {0x7DBD,0x7EF0}, {0x7DBE,0x7EEB}, {0x7DBF,0x7EF5}, {0x7DC4,0x7EF2}, 
+  {0x7DC7,0x7F01}, {0x7DCA,0x7D27}, {0x7DCB,0x7EEF}, {0x7DD1,0x7EFF}, {0x7DD2,0x7EEA}, 
+  {0x7DD4,0x7EF1}, {0x7DD7,0x7F03}, {0x7DD8,0x7F04}, {0x7DD9,0x7F02}, {0x7DDD,0x7F09}, 
+  {0x7DDE,0x7F0E}, {0x7DE0,0x7F14}, {0x7DE1,0x7F17}, {0x7DE3,0x7F18}, {0x7DE6,0x7F0C}, 
+  {0x7DE8,0x7F16}, {0x7DE9,0x7F13}, {0x7DEC,0x7F05}, {0x7DEF,0x7EAC}, {0x7DF1,0x7F11}, 
+  {0x7DF2,0x7F08}, {0x7DF4,0x7EC3}, {0x7DF6,0x7F0F}, {0x7DF9,0x7F07}, {0x7E08,0x8426}, 
+  {0x7E09,0x7F19}, {0x7E0A,0x7F22}, {0x7E0B,0x7F12}, {0x7E10,0x7EC9}, {0x7E11,0x7F23}, 
+  {0x7E1B,0x7F1A}, {0x7E1D,0x7F1C}, {0x7E1E,0x7F1F}, {0x7E1F,0x7F1B}, {0x7E23,0x53BF}, 
+  {0x7E27,0x7EE6}, {0x7E2B,0x7F1D}, {0x7E2D,0x7F21}, {0x7E2E,0x7F29}, {0x7E31,0x7EB5}, 
+  {0x7E32,0x7F27}, {0x7E35,0x7F26}, {0x7E36,0x7D77}, {0x7E37,0x7F15}, {0x7E39,0x7F25}, 
+  {0x7E3D,0x603B}, {0x7E3E,0x7EE9}, {0x7E45,0x7F2B}, {0x7E46,0x7F2A}, {0x7E52,0x7F2F}, 
+  {0x7E54,0x7EC7}, {0x7E55,0x7F2E}, {0x7E5A,0x7F2D}, {0x7E5E,0x7ED5}, {0x7E62,0x7F0B}, 
+  {0x7E69,0x7EF3}, {0x7E6A,0x7ED8}, {0x7E6D,0x8327}, {0x7E6E,0x7F30}, {0x7E6F,0x7F33}, 
+  {0x7E70,0x7F32}, {0x7E73,0x7F34}, {0x7E79,0x7ECE}, {0x7E7C,0x7EE7}, {0x7E7D,0x7F24}, 
+  {0x7E7E,0x7F31}, {0x7E88,0x7F2C}, {0x7E8A,0x7EA9}, {0x7E8C,0x7EED}, {0x7E8F,0x7F20}, 
+  {0x7E93,0x7F28}, {0x7E96,0x7EA4}, {0x7E98,0x7F35}, {0x7E9C,0x7F06}, {0x7F4C,0x7F42}, 
+  {0x7F70,0x7F5A}, {0x7F77,0x7F62}, {0x7F85,0x7F57}, {0x7F86,0x7F74}, {0x7F88,0x7F81}, 
+  {0x7FA5,0x7F9F}, {0x7FA9,0x4E49}, {0x7FD2,0x4E60}, {0x7FF9,0x7FD8}, {0x802C,0x8027}, 
+  {0x802E,0x8022}, {0x8056,0x5723}, {0x805E,0x95FB}, {0x806F,0x8054}, {0x8070,0x806A}, 
+  {0x8072,0x58F0}, {0x8073,0x8038}, {0x8075,0x8069}, {0x8076,0x8042}, {0x8077,0x804C}, 
+  {0x8079,0x804D}, {0x807D,0x542C}, {0x807E,0x804B}, {0x8085,0x8083}, {0x8105,0x80C1}, 
+  {0x811B,0x80EB}, {0x8139,0x80C0}, {0x814E,0x80BE}, {0x8156,0x80E8}, {0x8161,0x8136}, 
+  {0x8166,0x8111}, {0x816B,0x80BF}, {0x8178,0x80A0}, {0x819A,0x80A4}, {0x81A0,0x80F6}, 
+  {0x81A9,0x817B}, {0x81BD,0x80C6}, {0x81BE,0x810D}, {0x81BF,0x8113}, {0x81C9,0x8138}, 
+  {0x81CD,0x8110}, {0x81CF,0x8191}, {0x81D8,0x814A}, {0x81DA,0x80EA}, {0x81DF,0x810F}, 
+  {0x81E0,0x8114}, {0x81E8,0x4E34}, {0x81FA,0x53F0}, {0x8207,0x4E0E}, {0x8208,0x5174}, 
+  {0x8209,0x4E3E}, {0x820A,0x65E7}, {0x8259,0x8231}, {0x8264,0x8223}, {0x8266,0x8230}, 
+  {0x826B,0x823B}, {0x8271,0x8270}, {0x8277,0x8273}, {0x82BB,0x520D}, {0x82E7,0x82CE}, 
+  {0x838A,0x5E84}, {0x8396,0x830E}, {0x83A2,0x835A}, {0x83A7,0x82CB}, {0x83EF,0x534E}, 
+  {0x8407,0x82CC}, {0x840A,0x83B1}, {0x842C,0x4E07}, {0x8435,0x83B4}, {0x8449,0x53F6}, 
+  {0x8452,0x836D}, {0x8464,0x836E}, {0x8466,0x82C7}, {0x8477,0x8364}, {0x8493,0x83BC}, 
+  {0x8494,0x83B3}, {0x84BC,0x82CD}, {0x84C0,0x836A}, {0x84CB,0x76D6}, {0x84EE,0x83B2}, 
+  {0x84EF,0x82C1}, {0x84FD,0x835C}, {0x851E,0x848C}, {0x8523,0x848B}, {0x8526,0x8311}, 
+  {0x852D,0x836B}, {0x8541,0x8368}, {0x8546,0x8487}, {0x854E,0x835E}, {0x8552,0x836C}, 
+  {0x8553,0x82B8}, {0x8555,0x83B8}, {0x8558,0x835B}, {0x8562,0x8489}, {0x8569,0x8361}, 
+  {0x856A,0x829C}, {0x856D,0x8427}, {0x8577,0x84E3}, {0x8588,0x835F}, {0x858A,0x84DF}, 
+  {0x858C,0x8297}, {0x8594,0x8537}, {0x859F,0x83B6}, {0x85A6,0x8350}, {0x85A9,0x8428}, 
+  {0x85BA,0x8360}, {0x85CD,0x84DD}, {0x85CE,0x8369}, {0x85DD,0x827A}, {0x85E5,0x836F}, 
+  {0x85EA,0x85AE}, {0x85F4,0x8574}, {0x85F6,0x82C8}, {0x85F9,0x853C}, {0x85FA,0x853A}, 
+  {0x8604,0x8572}, {0x8606,0x82A6}, {0x8607,0x82CF}, {0x860B,0x82F9}, {0x861A,0x85D3}, 
+  {0x861E,0x8539}, {0x8622,0x830F}, {0x862D,0x5170}, {0x863A,0x84E0}, {0x863F,0x841D}, 
+  {0x8655,0x5904}, {0x865C,0x864F}, {0x865F,0x53F7}, {0x8667,0x4E8F}, {0x86FA,0x86F1}, 
+  {0x8706,0x86AC}, {0x8755,0x8680}, {0x8766,0x867E}, {0x8778,0x8717}, {0x8784,0x86F3}, 
+  {0x879E,0x8682}, {0x87A2,0x8424}, {0x87BB,0x877C}, {0x87C4,0x86F0}, {0x87C8,0x8748}, 
+  {0x87CE,0x87A8}, {0x87E3,0x866E}, {0x87EC,0x8749}, {0x87EF,0x86F2}, {0x87F2,0x866B}, 
+  {0x87F6,0x86CF}, {0x87FB,0x8681}, {0x8805,0x8747}, {0x8806,0x867F}, {0x8810,0x86F4}, 
+  {0x8811,0x877E}, {0x881F,0x8721}, {0x8823,0x86CE}, {0x8831,0x86CA}, {0x8836,0x8695}, 
+  {0x883B,0x86EE}, {0x8846,0x4F17}, {0x8853,0x672F}, {0x885B,0x536B}, {0x885D,0x51B2}, 
+  {0x8879,0x53EA}, {0x88CA,0x8885}, {0x88CF,0x91CC}, {0x88DC,0x8865}, {0x88DD,0x88C5}, 
+  {0x8932,0x88E4}, {0x8933,0x88E2}, {0x8938,0x891B}, {0x893B,0x4EB5}, {0x8947,0x88E5}, 
+  {0x8956,0x8884}, {0x895D,0x88E3}, {0x8960,0x88C6}, {0x8964,0x8934}, {0x896A,0x889C}, 
+  {0x896F,0x886C}, {0x8972,0x88AD}, {0x898B,0x89C1}, {0x898F,0x89C4}, {0x8993,0x89C5}, 
+  {0x8996,0x89C6}, {0x8998,0x89C7}, {0x89A1,0x89CB}, {0x89A6,0x89CE}, {0x89AA,0x4EB2}, 
+  {0x89AC,0x89CA}, {0x89AF,0x89CF}, {0x89B2,0x89D0}, {0x89B7,0x89D1}, {0x89BA,0x89C9}, 
+  {0x89BD,0x89C8}, {0x89BF,0x89CC}, {0x89C0,0x89C2}, {0x89F4,0x89DE}, {0x89F6,0x89EF}, 
+  {0x89F8,0x89E6}, {0x8A01,0x8BA0}, {0x8A02,0x8BA2}, {0x8A03,0x8BA3}, {0x8A08,0x8BA1}, 
+  {0x8A0A,0x8BAF}, {0x8A0C,0x8BA7}, {0x8A0E,0x8BA8}, {0x8A10,0x8BA6}, {0x8A13,0x8BAD}, 
+  {0x8A15,0x8BAA}, {0x8A16,0x8BAB}, {0x8A18,0x8BB0}, {0x8A1B,0x8BB9}, {0x8A1D,0x8BB6}, 
+  {0x8A1F,0x8BBC}, {0x8A23,0x8BC0}, {0x8A25,0x8BB7}, {0x8A2A,0x8BBF}, {0x8A2D,0x8BBE}, 
+  {0x8A31,0x8BB8}, {0x8A34,0x8BC9}, {0x8A36,0x8BC3}, {0x8A3A,0x8BCA}, {0x8A41,0x8BC2}, 
+  {0x8A46,0x8BCB}, {0x8A4E,0x8BB5}, {0x8A50,0x8BC8}, {0x8A52,0x8BD2}, {0x8A54,0x8BCF}, 
+  {0x8A55,0x8BC4}, {0x8A58,0x8BCE}, {0x8A5B,0x8BC5}, {0x8A5E,0x8BCD}, {0x8A61,0x8BE9}, 
+  {0x8A62,0x8BE2}, {0x8A63,0x8BE3}, {0x8A66,0x8BD5}, {0x8A69,0x8BD7}, {0x8A6B,0x8BE7}, 
+  {0x8A6C,0x8BDF}, {0x8A6D,0x8BE1}, {0x8A6E,0x8BE0}, {0x8A70,0x8BD8}, {0x8A71,0x8BDD}, 
+  {0x8A72,0x8BE5}, {0x8A73,0x8BE6}, {0x8A75,0x8BDC}, {0x8A7C,0x8BD9}, {0x8A7F,0x8BD6}, 
+  {0x8A84,0x8BD4}, {0x8A85,0x8BDB}, {0x8A86,0x8BD3}, {0x8A87,0x5938}, {0x8A8D,0x8BA4}, 
+  {0x8A91,0x8BF3}, {0x8A92,0x8BF6}, {0x8A95,0x8BDE}, {0x8A98,0x8BF1}, {0x8A9A,0x8BEE}, 
+  {0x8A9E,0x8BED}, {0x8AA0,0x8BDA}, {0x8AA1,0x8BEB}, {0x8AA3,0x8BEC}, {0x8AA4,0x8BEF}, 
+  {0x8AA5,0x8BF0}, {0x8AA6,0x8BF5}, {0x8AA8,0x8BF2}, {0x8AAC,0x8BF4}, {0x8AB0,0x8C01}, 
+  {0x8AB2,0x8BFE}, {0x8AB6,0x8C07}, {0x8AB9,0x8BFD}, {0x8ABC,0x8C0A}, {0x8ABF,0x8C03}, 
+  {0x8AC2,0x8C04}, {0x8AC4,0x8C06}, {0x8AC7,0x8C08}, {0x8AC9,0x8BFF}, {0x8ACB,0x8BF7}, 
+  {0x8ACD,0x8BE4}, {0x8ACF,0x8BF9}, {0x8AD1,0x8BFC}, {0x8AD2,0x8C05}, {0x8AD6,0x8BBA}, 
+  {0x8AD7,0x8C02}, {0x8ADB,0x8C00}, {0x8ADC,0x8C0D}, {0x8ADE,0x8C1D}, {0x8AE2,0x8BE8}, 
+  {0x8AE4,0x8C14}, {0x8AE6,0x8C1B}, {0x8AE7,0x8C10}, {0x8AEB,0x8C0F}, {0x8AED,0x8C15}, 
+  {0x8AEE,0x8C18}, {0x8AF1,0x8BB3}, {0x8AF3,0x8C19}, {0x8AF6,0x8C0C}, {0x8AF7,0x8BBD}, 
+  {0x8AF8,0x8BF8}, {0x8AFA,0x8C1A}, {0x8AFC,0x8C16}, {0x8AFE,0x8BFA}, {0x8B00,0x8C0B}, 
+  {0x8B01,0x8C12}, {0x8B02,0x8C13}, {0x8B04,0x8A8A}, {0x8B05,0x8BCC}, {0x8B0A,0x8C0E}, 
+  {0x8B0E,0x8C1C}, {0x8B10,0x8C27}, {0x8B14,0x8C11}, {0x8B16,0x8C21}, {0x8B17,0x8C24}, 
+  {0x8B19,0x8C26}, {0x8B1A,0x8C25}, {0x8B1B,0x8BB2}, {0x8B1D,0x8C22}, {0x8B21,0x8C23}, 
+  {0x8B28,0x8C1F}, {0x8B2B,0x8C2A}, {0x8B2C,0x8C2C}, {0x8B2D,0x8C2B}, {0x8B33,0x8BB4}, 
+  {0x8B39,0x8C28}, {0x8B3E,0x8C29}, {0x8B49,0x8BC1}, {0x8B4E,0x8C32}, {0x8B4F,0x8BA5}, 
+  {0x8B56,0x8C2E}, {0x8B58,0x8BC6}, {0x8B59,0x8C2F}, {0x8B5A,0x8C2D}, {0x8B5C,0x8C31}, 
+  {0x8B6B,0x8C35}, {0x8B6F,0x8BD1}, {0x8B70,0x8BAE}, {0x8B74,0x8C34}, {0x8B77,0x62A4}, 
+  {0x8B7D,0x8A89}, {0x8B80,0x8BFB}, {0x8B8A,0x53D8}, {0x8B8E,0x96E0}, {0x8B92,0x8C17}, 
+  {0x8B93,0x8BA9}, {0x8B95,0x8C30}, {0x8B96,0x8C36}, {0x8B9C,0x8C20}, {0x8B9E,0x8C33}, 
+  {0x8C48,0x5C82}, {0x8C50,0x4E30}, {0x8C9D,0x8D1D}, {0x8C9E,0x8D1E}, {0x8CA0,0x8D1F}, 
+  {0x8CA1,0x8D22}, {0x8CA2,0x8D21}, {0x8CA7,0x8D2B}, {0x8CA8,0x8D27}, {0x8CA9,0x8D29}, 
+  {0x8CAA,0x8D2A}, {0x8CAB,0x8D2F}, {0x8CAC,0x8D23}, {0x8CAF,0x8D2E}, {0x8CB0,0x8D33}, 
+  {0x8CB2,0x8D40}, {0x8CB3,0x8D30}, {0x8CB4,0x8D35}, {0x8CB6,0x8D2C}, {0x8CB7,0x4E70}, 
+  {0x8CB8,0x8D37}, {0x8CBA,0x8D36}, {0x8CBB,0x8D39}, {0x8CBC,0x8D34}, {0x8CBD,0x8D3B}, 
+  {0x8CBF,0x8D38}, {0x8CC0,0x8D3A}, {0x8CC1,0x8D32}, {0x8CC2,0x8D42}, {0x8CC3,0x8D41}, 
+  {0x8CC4,0x8D3F}, {0x8CC5,0x8D45}, {0x8CC7,0x8D44}, {0x8CC8,0x8D3E}, {0x8CCA,0x8D3C}, 
+  {0x8CD1,0x8D48}, {0x8CD2,0x8D4A}, {0x8CD3,0x5BBE}, {0x8CD5,0x8D47}, {0x8CDA,0x8D49}, 
+  {0x8CDC,0x8D50}, {0x8CDE,0x8D4F}, {0x8CE0,0x8D54}, {0x8CE1,0x8D53}, {0x8CE2,0x8D24}, 
+  {0x8CE3,0x5356}, {0x8CE4,0x8D31}, {0x8CE6,0x8D4B}, {0x8CE7,0x8D55}, {0x8CEA,0x8D28}, 
+  {0x8CEB,0x8D4D}, {0x8CEC,0x8D26}, {0x8CED,0x8D4C}, {0x8CF4,0x8D56}, {0x8CFA,0x8D5A}, 
+  {0x8CFB,0x8D59}, {0x8CFC,0x8D2D}, {0x8CFD,0x8D5B}, {0x8CFE,0x8D5C}, {0x8D04,0x8D3D}, 
+  {0x8D05,0x8D58}, {0x8D08,0x8D60}, {0x8D0A,0x8D5E}, {0x8D0B,0x8D5D}, {0x8D0D,0x8D61}, 
+  {0x8D0F,0x8D62}, {0x8D10,0x8D46}, {0x8D16,0x8D4E}, {0x8D1B,0x8D63}, {0x8D1C,0x8D43}, 
+  {0x8D95,0x8D76}, {0x8D99,0x8D75}, {0x8DA8,0x8D8B}, {0x8DB2,0x8DB1}, {0x8E10,0x8DF5}, 
+  {0x8E34,0x8E0A}, {0x8E4C,0x8DC4}, {0x8E55,0x8DF8}, {0x8E63,0x8E52}, {0x8E7A,0x8DF7}, 
+  {0x8E89,0x8DB8}, {0x8E8A,0x8E0C}, {0x8E8B,0x8DFB}, {0x8E8D,0x8DC3}, {0x8E91,0x8E2F}, 
+  {0x8E92,0x8DDE}, {0x8E93,0x8E2C}, {0x8E9A,0x8DF9}, {0x8EA1,0x8E51}, {0x8EA5,0x8E7F}, 
+  {0x8EA6,0x8E9C}, {0x8EAA,0x8E8F}, {0x8EC0,0x8EAF}, {0x8ECA,0x8F66}, {0x8ECB,0x8F67}, 
+  {0x8ECC,0x8F68}, {0x8ECD,0x519B}, {0x8ED2,0x8F69}, {0x8ED4,0x8F6B}, {0x8EDB,0x8F6D}, 
+  {0x8EDF,0x8F6F}, {0x8EE4,0x8F77}, {0x8EEB,0x8F78}, {0x8EF2,0x8F71}, {0x8EF8,0x8F74}, 
+  {0x8EF9,0x8F75}, {0x8EFA,0x8F7A}, {0x8EFB,0x8F72}, {0x8EFC,0x8F76}, {0x8EFE,0x8F7C}, 
+  {0x8F03,0x8F83}, {0x8F05,0x8F82}, {0x8F07,0x8F81}, {0x8F09,0x8F7D}, {0x8F0A,0x8F7E}, 
+  {0x8F12,0x8F84}, {0x8F14,0x8F85}, {0x8F15,0x8F7B}, {0x8F1B,0x8F86}, {0x8F1C,0x8F8E}, 
+  {0x8F1D,0x8F89}, {0x8F1E,0x8F8B}, {0x8F1F,0x8F8D}, {0x8F25,0x8F8A}, {0x8F26,0x8F87}, 
+  {0x8F29,0x8F88}, {0x8F2A,0x8F6E}, {0x8F2F,0x8F91}, {0x8F33,0x8F8F}, {0x8F38,0x8F93}, 
+  {0x8F3B,0x8F90}, {0x8F3E,0x8F97}, {0x8F3F,0x8206}, {0x8F42,0x6BC2}, {0x8F44,0x8F96}, 
+  {0x8F45,0x8F95}, {0x8F46,0x8F98}, {0x8F49,0x8F6C}, {0x8F4D,0x8F99}, {0x8F4E,0x8F7F}, 
+  {0x8F54,0x8F9A}, {0x8F5F,0x8F70}, {0x8F61,0x8F94}, {0x8F62,0x8F79}, {0x8F64,0x8F73}, 
+  {0x8FA6,0x529E}, {0x8FAD,0x8F9E}, {0x8FAE,0x8FAB}, {0x8FAF,0x8FA9}, {0x8FB2,0x519C}, 
+  {0x9015,0x8FF3}, {0x9019,0x8FD9}, {0x9023,0x8FDE}, {0x9032,0x8FDB}, {0x904B,0x8FD0}, 
+  {0x904E,0x8FC7}, {0x9054,0x8FBE}, {0x9055,0x8FDD}, {0x905C,0x900A}, {0x905E,0x9012}, 
+  {0x9060,0x8FDC}, {0x9069,0x9002}, {0x9072,0x8FDF}, {0x9077,0x8FC1}, {0x9078,0x9009}, 
+  {0x907A,0x9057}, {0x907C,0x8FBD}, {0x9081,0x8FC8}, {0x9084,0x8FD8}, {0x9087,0x8FE9}, 
+  {0x908A,0x8FB9}, {0x908F,0x903B}, {0x9090,0x9026}, {0x90DF,0x90CF}, {0x90F5,0x90AE}, 
+  {0x9106,0x90D3}, {0x9109,0x4E61}, {0x9112,0x90B9}, {0x9114,0x90AC}, {0x9116,0x90E7}, 
+  {0x9127,0x9093}, {0x912D,0x90D1}, {0x9130,0x90BB}, {0x9132,0x90F8}, {0x9134,0x90BA}, 
+  {0x9136,0x90D0}, {0x913A,0x909D}, {0x9148,0x90E6}, {0x9196,0x915D}, {0x919C,0x4E11}, 
+  {0x91AB,0x533B}, {0x91AC,0x9171}, {0x91C0,0x917F}, {0x91C1,0x8845}, {0x91C3,0x917E}, 
+  {0x91C5,0x917D}, {0x91CB,0x91CA}, {0x91D2,0x9485}, {0x91D3,0x9486}, {0x91D4,0x9487}, 
+  {0x91D5,0x948C}, {0x91D7,0x948A}, {0x91D8,0x9489}, {0x91D9,0x948B}, {0x91DD,0x9488}, 
+  {0x91E3,0x9493}, {0x91E4,0x9490}, {0x91E7,0x948F}, {0x91E9,0x9492}, {0x91F5,0x9497}, 
+  {0x91F7,0x948D}, {0x91F9,0x9495}, {0x91FA,0x948E}, {0x9200,0x94AF}, {0x9201,0x94AB}, 
+  {0x9204,0x94AD}, {0x9208,0x949A}, {0x9209,0x94A0}, {0x920D,0x949D}, {0x920E,0x94A9}, 
+  {0x9210,0x94A4}, {0x9211,0x94A3}, {0x9214,0x949E}, {0x9215,0x94AE}, {0x921E,0x94A7}, 
+  {0x9223,0x9499}, {0x9225,0x94AC}, {0x9226,0x949B}, {0x9227,0x94AA}, {0x922E,0x94CC}, 
+  {0x9230,0x94C8}, {0x9233,0x94B6}, {0x9234,0x94C3}, {0x9237,0x94B4}, {0x9238,0x94B9}, 
+  {0x9239,0x94CD}, {0x923A,0x94B0}, {0x923D,0x94B8}, {0x923E,0x94C0}, {0x923F,0x94BF}, 
+  {0x9240,0x94BE}, {0x9245,0x949C}, {0x9248,0x94CA}, {0x9249,0x94C9}, {0x924D,0x94CB}, 
+  {0x9251,0x94C2}, {0x9255,0x94B7}, {0x9257,0x94B3}, {0x925A,0x94C6}, {0x925B,0x94C5}, 
+  {0x925E,0x94BA}, {0x9262,0x94B5}, {0x9266,0x94B2}, {0x926C,0x94BC}, {0x926D,0x94BD}, 
+  {0x9278,0x94F0}, {0x927A,0x94D2}, {0x927B,0x94EC}, {0x927F,0x94EA}, {0x9280,0x94F6}, 
+  {0x9283,0x94F3}, {0x9285,0x94DC}, {0x9291,0x94E3}, {0x9293,0x94E8}, {0x9296,0x94E2}, 
+  {0x9298,0x94ED}, {0x929A,0x94EB}, {0x929C,0x8854}, {0x92A0,0x94D1}, {0x92A3,0x94F7}, 
+  {0x92A5,0x94F1}, {0x92A6,0x94DF}, {0x92A8,0x94F5}, {0x92A9,0x94E5}, {0x92AA,0x94D5}, 
+  {0x92AB,0x94EF}, {0x92AC,0x94D0}, {0x92B1,0x94DE}, {0x92B7,0x9500}, {0x92B9,0x9508}, 
+  {0x92BB,0x9511}, {0x92BC,0x9509}, {0x92C1,0x94DD}, {0x92C3,0x9512}, {0x92C5,0x950C}, 
+  {0x92C7,0x94A1}, {0x92CC,0x94E4}, {0x92CF,0x94D7}, {0x92D2,0x950B}, {0x92DD,0x950A}, 
+  {0x92DF,0x9513}, {0x92E3,0x94D8}, {0x92E4,0x9504}, {0x92E5,0x9503}, {0x92E6,0x9514}, 
+  {0x92E8,0x9507}, {0x92EA,0x94FA}, {0x92ED,0x9510}, {0x92EE,0x94D6}, {0x92EF,0x9506}, 
+  {0x92F0,0x9502}, {0x92F1,0x94FD}, {0x92F6,0x950D}, {0x92F8,0x952F}, {0x92FC,0x94A2}, 
+  {0x9301,0x951E}, {0x9306,0x9516}, {0x9307,0x952B}, {0x9308,0x9529}, {0x9310,0x9525}, 
+  {0x9312,0x9515}, {0x9315,0x951F}, {0x9318,0x9524}, {0x9319,0x9531}, {0x931A,0x94EE}, 
+  {0x931B,0x951B}, {0x931F,0x952C}, {0x9320,0x952D}, {0x9322,0x94B1}, {0x9326,0x9526}, 
+  {0x9328,0x951A}, {0x932B,0x9521}, {0x932E,0x9522}, {0x932F,0x9519}, {0x9332,0x5F55}, 
+  {0x9333,0x9530}, {0x9338,0x94FC}, {0x9340,0x951D}, {0x9341,0x9528}, {0x9343,0x952A}, 
+  {0x9346,0x9494}, {0x9347,0x9534}, {0x934B,0x9505}, {0x934D,0x9540}, {0x9354,0x9537}, 
+  {0x9358,0x94E1}, {0x935B,0x953B}, {0x9364,0x9538}, {0x9365,0x9532}, {0x9369,0x9518}, 
+  {0x936C,0x9539}, {0x9370,0x953E}, {0x9375,0x952E}, {0x9376,0x9536}, {0x937A,0x9517}, 
+  {0x937E,0x953A}, {0x9382,0x9541}, {0x9384,0x953F}, {0x9387,0x9545}, {0x938A,0x9551}, 
+  {0x9396,0x9501}, {0x9398,0x9549}, {0x93A2,0x94A8}, {0x93A3,0x84E5}, {0x93A6,0x954F}, 
+  {0x93A7,0x94E0}, {0x93A9,0x94E9}, {0x93AA,0x953C}, {0x93AC,0x9550}, {0x93AE,0x9547}, 
+  {0x93B0,0x9552}, {0x93B3,0x954D}, {0x93B5,0x9553}, {0x93B8,0x954C}, {0x93BF,0x954E}, 
+  {0x93C3,0x955E}, {0x93C7,0x955F}, {0x93C8,0x94FE}, {0x93CC,0x9546}, {0x93CD,0x9559}, 
+  {0x93D1,0x955D}, {0x93D7,0x94FF}, {0x93D8,0x9535}, {0x93DC,0x9557}, {0x93DD,0x9558}, 
+  {0x93DE,0x955B}, {0x93DF,0x94F2}, {0x93E1,0x955C}, {0x93E2,0x9556}, {0x93E4,0x9542}, 
+  {0x93E8,0x933E}, {0x93F5,0x94E7}, {0x93F7,0x9564}, {0x93F9,0x956A}, {0x9403,0x94D9}, 
+  {0x940B,0x94F4}, {0x9410,0x9563}, {0x9412,0x94F9}, {0x9413,0x9566}, {0x9414,0x9561}, 
+  {0x9418,0x949F}, {0x9419,0x956B}, {0x941D,0x9562}, {0x9420,0x9568}, {0x9426,0x950E}, 
+  {0x9427,0x950F}, {0x9428,0x9544}, {0x942E,0x9570}, {0x9432,0x956F}, {0x9433,0x956D}, 
+  {0x9435,0x94C1}, {0x9438,0x94CE}, {0x943A,0x94DB}, {0x943F,0x9571}, {0x9444,0x94F8}, 
+  {0x944A,0x956C}, {0x944C,0x9554}, {0x9452,0x9274}, {0x9454,0x9572}, {0x9460,0x94C4}, 
+  {0x9463,0x9573}, {0x9465,0x9565}, {0x946D,0x9567}, {0x9470,0x94A5}, {0x9472,0x9576}, 
+  {0x9477,0x954A}, {0x9479,0x9569}, {0x947C,0x9523}, {0x947D,0x94BB}, {0x947E,0x92AE}, 
+  {0x947F,0x51FF}, {0x9577,0x957F}, {0x9580,0x95E8}, {0x9582,0x95E9}, {0x9583,0x95EA}, 
+  {0x9586,0x95EB}, {0x9589,0x95ED}, {0x958B,0x5F00}, {0x958C,0x95F6}, {0x958E,0x95F3}, 
+  {0x958F,0x95F0}, {0x9591,0x95F2}, {0x9593,0x95F4}, {0x9594,0x95F5}, {0x9598,0x95F8}, 
+  {0x95A1,0x9602}, {0x95A3,0x9601}, {0x95A5,0x9600}, {0x95A8,0x95FA}, {0x95A9,0x95FD}, 
+  {0x95AB,0x9603}, {0x95AC,0x9606}, {0x95AD,0x95FE}, {0x95B2,0x9605}, {0x95B6,0x960A}, 
+  {0x95B9,0x9609}, {0x95BB,0x960E}, {0x95BC,0x960F}, {0x95BD,0x960D}, {0x95BE,0x9608}, 
+  {0x95BF,0x960C}, {0x95C3,0x9612}, {0x95C8,0x95F1}, {0x95CA,0x9614}, {0x95CB,0x9615}, 
+  {0x95CC,0x9611}, {0x95D0,0x9617}, {0x95D4,0x9616}, {0x95D5,0x9619}, {0x95D6,0x95EF}, 
+  {0x95DC,0x5173}, {0x95DE,0x961A}, {0x95E1,0x9610}, {0x95E5,0x95FC}, {0x9658,0x9649}, 
+  {0x965D,0x9655}, {0x9663,0x9635}, {0x9670,0x9634}, {0x9673,0x9648}, {0x9678,0x9646}, 
+  {0x967D,0x9633}, {0x9689,0x9667}, {0x968A,0x961F}, {0x968E,0x9636}, {0x9695,0x9668}, 
+  {0x969B,0x9645}, {0x96A8,0x968F}, {0x96AA,0x9669}, {0x96B1,0x9690}, {0x96B4,0x9647}, 
+  {0x96B8,0x96B6}, {0x96D6,0x867D}, {0x96D9,0x53CC}, {0x96DB,0x96CF}, {0x96DC,0x6742}, 
+  {0x96E2,0x79BB}, {0x96E3,0x96BE}, {0x96F2,0x4E91}, {0x96FB,0x7535}, {0x9727,0x96FE}, 
+  {0x973D,0x9701}, {0x9742,0x96F3}, {0x9744,0x972D}, {0x9748,0x7075}, {0x975A,0x9753}, 
+  {0x975C,0x9759}, {0x9768,0x9765}, {0x978F,0x5DE9}, {0x97BD,0x9792}, {0x97C3,0x9791}, 
+  {0x97C9,0x97AF}, {0x97CB,0x97E6}, {0x97CC,0x97E7}, {0x97D3,0x97E9}, {0x97D9,0x97EA}, 
+  {0x97DC,0x97EC}, {0x97DE,0x97EB}, {0x97FF,0x54CD}, {0x9801,0x9875}, {0x9802,0x9876}, 
+  {0x9803,0x9877}, {0x9805,0x9879}, {0x9806,0x987A}, {0x9807,0x9878}, {0x9808,0x987B}, 
+  {0x980A,0x987C}, {0x980C,0x9882}, {0x980E,0x9880}, {0x980F,0x9883}, {0x9810,0x9884}, 
+  {0x9811,0x987D}, {0x9812,0x9881}, {0x9813,0x987F}, {0x9817,0x9887}, {0x9818,0x9886}, 
+  {0x981C,0x988C}, {0x9821,0x9889}, {0x9824,0x9890}, {0x9826,0x988F}, {0x982D,0x5934}, 
+  {0x9830,0x988A}, {0x9837,0x9894}, {0x9838,0x9888}, {0x983B,0x9891}, {0x983D,0x9893}, 
+  {0x9846,0x9897}, {0x984C,0x9898}, {0x984D,0x989D}, {0x984E,0x989A}, {0x9853,0x989B}, 
+  {0x9854,0x989C}, {0x9858,0x613F}, {0x9859,0x98A1}, {0x985B,0x98A0}, {0x985E,0x7C7B}, 
+  {0x9862,0x989F}, {0x9865,0x98A2}, {0x9867,0x987E}, {0x986B,0x98A4}, {0x986C,0x98A5}, 
+  {0x986F,0x663E}, {0x9870,0x98A6}, {0x9871,0x9885}, {0x9873,0x989E}, {0x9874,0x98A7}, 
+  {0x98A8,0x98CE}, {0x98AE,0x98D1}, {0x98AF,0x98D2}, {0x98B6,0x98D3}, {0x98BC,0x98D5}, 
+  {0x98C4,0x98D8}, {0x98C6,0x98D9}, {0x98C8,0x98DA}, {0x98DB,0x98DE}, {0x98E0,0x9963}, 
+  {0x98E9,0x9968}, {0x98EA,0x996A}, {0x98EB,0x996B}, {0x98ED,0x996C}, {0x98EF,0x996D}, 
+  {0x98F2,0x996E}, {0x98F4,0x9974}, {0x98FC,0x9972}, {0x98FD,0x9971}, {0x98FE,0x9970}, 
+  {0x9903,0x997A}, {0x9905,0x997C}, {0x9909,0x9977}, {0x990A,0x517B}, {0x990C,0x9975}, 
+  {0x9911,0x997D}, {0x9912,0x9981}, {0x9913,0x997F}, {0x9918,0x4F59}, {0x991B,0x9984}, 
+  {0x991E,0x996F}, {0x9921,0x9985}, {0x9928,0x9986}, {0x9933,0x9967}, {0x9937,0x9987}, 
+  {0x993C,0x9969}, {0x993E,0x998F}, {0x993F,0x998A}, {0x9943,0x998D}, {0x9945,0x9992}, 
+  {0x9948,0x9990}, {0x9949,0x9991}, {0x994A,0x9993}, {0x994B,0x9988}, {0x994C,0x9994}, 
+  {0x9951,0x9965}, {0x9952,0x9976}, {0x9957,0x98E8}, {0x995C,0x990D}, {0x995E,0x998B}, 
+  {0x9962,0x9995}, {0x99AC,0x9A6C}, {0x99AD,0x9A6D}, {0x99AE,0x51AF}, {0x99B1,0x9A6E}, 
+  {0x99B3,0x9A70}, {0x99B4,0x9A6F}, {0x99C1,0x9A73}, {0x99D0,0x9A7B}, {0x99D1,0x9A7D}, 
+  {0x99D2,0x9A79}, {0x99D4,0x9A75}, {0x99D5,0x9A7E}, {0x99D8,0x9A80}, {0x99D9,0x9A78}, 
+  {0x99DB,0x9A76}, {0x99DD,0x9A7C}, {0x99DF,0x9A77}, {0x99E1,0x9A82}, {0x99E2,0x9A88}, 
+  {0x99ED,0x9A87}, {0x99F1,0x9A86}, {0x99FF,0x9A8F}, {0x9A01,0x9A8B}, {0x9A05,0x9A93}, 
+  {0x9A0D,0x9A92}, {0x9A0E,0x9A91}, {0x9A0F,0x9A90}, {0x9A16,0x9A9B}, {0x9A19,0x9A97}, 
+  {0x9A2B,0x9A9E}, {0x9A2D,0x9A98}, {0x9A2E,0x9A9D}, {0x9A30,0x817E}, {0x9A36,0x9A7A}, 
+  {0x9A37,0x9A9A}, {0x9A38,0x9A9F}, {0x9A3E,0x9AA1}, {0x9A40,0x84E6}, {0x9A41,0x9A9C}, 
+  {0x9A42,0x9A96}, {0x9A43,0x9AA0}, {0x9A44,0x9AA2}, {0x9A45,0x9A71}, {0x9A4A,0x9A85}, 
+  {0x9A4D,0x9A81}, {0x9A4F,0x9AA3}, {0x9A55,0x9A84}, {0x9A57,0x9A8C}, {0x9A5A,0x60CA}, 
+  {0x9A5B,0x9A7F}, {0x9A5F,0x9AA4}, {0x9A62,0x9A74}, {0x9A64,0x9AA7}, {0x9A65,0x9AA5}, 
+  {0x9A6A,0x9A8A}, {0x9AAF,0x80AE}, {0x9ACF,0x9AC5}, {0x9AD4,0x4F53}, {0x9AD5,0x9ACC}, 
+  {0x9AD6,0x9ACB}, {0x9B06,0x677E}, {0x9B22,0x9B13}, {0x9B25,0x6597}, {0x9B27,0x95F9}, 
+  {0x9B29,0x960B}, {0x9B2E,0x9604}, {0x9B31,0x90C1}, {0x9B4E,0x9B49}, {0x9B58,0x9B47}, 
+  {0x9B5A,0x9C7C}, {0x9B6F,0x9C81}, {0x9B74,0x9C82}, {0x9B77,0x9C7F}, {0x9B81,0x9C85}, 
+  {0x9B83,0x9C86}, {0x9B8E,0x9C87}, {0x9B90,0x9C90}, {0x9B91,0x9C8D}, {0x9B92,0x9C8B}, 
+  {0x9B9A,0x9C92}, {0x9B9D,0x9C9E}, {0x9B9E,0x9C95}, {0x9BAA,0x9C94}, {0x9BAB,0x9C9B}, 
+  {0x9BAD,0x9C91}, {0x9BAE,0x9C9C}, {0x9BC0,0x9CA7}, {0x9BC1,0x9CA0}, {0x9BC7,0x9CA9}, 
+  {0x9BC9,0x9CA4}, {0x9BCA,0x9CA8}, {0x9BD4,0x9CBB}, {0x9BD6,0x9CAD}, {0x9BDB,0x9CB7}, 
+  {0x9BDD,0x9CB4}, {0x9BE1,0x9CB1}, {0x9BE2,0x9CB5}, {0x9BE4,0x9CB2}, {0x9BE7,0x9CB3}, 
+  {0x9BE8,0x9CB8}, {0x9BEA,0x9CAE}, {0x9BEB,0x9CB0}, {0x9BF0,0x9CB6}, {0x9BF4,0x9CBA}, 
+  {0x9BFD,0x9CAB}, {0x9BFF,0x9CCA}, {0x9C08,0x9CBD}, {0x9C09,0x9CC7}, {0x9C0D,0x9CC5}, 
+  {0x9C10,0x9CC4}, {0x9C12,0x9CC6}, {0x9C13,0x9CC3}, {0x9C20,0x9CCB}, {0x9C23,0x9CA5}, 
+  {0x9C25,0x9CCF}, {0x9C28,0x9CCE}, {0x9C29,0x9CD0}, {0x9C2D,0x9CCD}, {0x9C31,0x9CA2}, 
+  {0x9C32,0x9CCC}, {0x9C33,0x9CD3}, {0x9C35,0x9CD8}, {0x9C37,0x9CA6}, {0x9C39,0x9CA3}, 
+  {0x9C3B,0x9CD7}, {0x9C3E,0x9CD4}, {0x9C45,0x9CD9}, {0x9C48,0x9CD5}, {0x9C49,0x9CD6}, 
+  {0x9C52,0x9CDF}, {0x9C54,0x9CDD}, {0x9C56,0x9CDC}, {0x9C57,0x9CDE}, {0x9C58,0x9C9F}, 
+  {0x9C5D,0x9CBC}, {0x9C5F,0x9C8E}, {0x9C67,0x9CE2}, {0x9C6D,0x9C9A}, {0x9C78,0x9C88}, 
+  {0x9C7A,0x9CA1}, {0x9CE5,0x9E1F}, {0x9CE9,0x9E20}, {0x9CEC,0x51EB}, {0x9CF3,0x51E4}, 
+  {0x9CF4,0x9E23}, {0x9CF6,0x9E22}, {0x9D06,0x9E29}, {0x9D07,0x9E28}, {0x9D09,0x9E26}, 
+  {0x9D15,0x9E35}, {0x9D1B,0x9E33}, {0x9D1D,0x9E32}, {0x9D1F,0x9E31}, {0x9D23,0x9E2A}, 
+  {0x9D26,0x9E2F}, {0x9D28,0x9E2D}, {0x9D2F,0x9E38}, {0x9D30,0x9E39}, {0x9D3B,0x9E3F}, 
+  {0x9D3F,0x9E3D}, {0x9D42,0x9E3A}, {0x9D51,0x9E43}, {0x9D52,0x9E46}, {0x9D53,0x9E41}, 
+  {0x9D5C,0x9E48}, {0x9D5D,0x9E45}, {0x9D60,0x9E44}, {0x9D61,0x9E49}, {0x9D6A,0x9E4C}, 
+  {0x9D6C,0x9E4F}, {0x9D6F,0x9E4E}, {0x9D72,0x9E4A}, {0x9D87,0x9E2B}, {0x9D89,0x9E51}, 
+  {0x9D93,0x9E4B}, {0x9D98,0x9E55}, {0x9D9A,0x9E57}, {0x9DA5,0x9E5B}, {0x9DA9,0x9E5C}, 
+  {0x9DAF,0x83BA}, {0x9DB4,0x9E64}, {0x9DBB,0x9E58}, {0x9DBC,0x9E63}, {0x9DC0,0x9E5A}, 
+  {0x9DC2,0x9E5E}, {0x9DC4,0x9E21}, {0x9DD3,0x9E67}, {0x9DD7,0x9E25}, {0x9DD9,0x9E37}, 
+  {0x9DDA,0x9E68}, {0x9DE5,0x9E36}, {0x9DE6,0x9E6A}, {0x9DEF,0x9E69}, {0x9DF2,0x9E6B}, 
+  {0x9DF3,0x9E47}, {0x9DF8,0x9E6C}, {0x9DF9,0x9E70}, {0x9DFA,0x9E6D}, {0x9E0C,0x9E71}, 
+  {0x9E15,0x9E2C}, {0x9E1A,0x9E66}, {0x9E1B,0x9E73}, {0x9E1D,0x9E42}, {0x9E1E,0x9E3E}, 
+  {0x9E7A,0x9E7E}, {0x9E7C,0x7877}, {0x9E7D,0x76D0}, {0x9E97,0x4E3D}, {0x9EA5,0x9EA6}, 
+  {0x9EA9,0x9EB8}, {0x9EBD,0x4E48}, {0x9ECC,0x9EC9}, {0x9EDE,0x70B9}, {0x9EE8,0x515A}, 
+  {0x9EF2,0x9EEA}, {0x9EF7,0x9EE9}, {0x9EFD,0x9EFE}, {0x9EFF,0x9F0B}, {0x9F09,0x9F0D}, 
+  {0x9F4A,0x9F50}, {0x9F4B,0x658B}, {0x9F4F,0x9F51}, {0x9F52,0x9F7F}, {0x9F54,0x9F80}, 
+  {0x9F59,0x9F85}, {0x9F5C,0x9F87}, {0x9F5F,0x9F83}, {0x9F60,0x9F86}, {0x9F61,0x9F84}, 
+  {0x9F66,0x9F88}, {0x9F6A,0x9F8A}, {0x9F6C,0x9F89}, {0x9F72,0x9F8B}, {0x9F77,0x9F8C}, 
+  {0x9F8D,0x9F99}, {0x9F90,0x5E9E}, {0x9F94,0x9F9A}, {0x9F95,0x9F9B}, {0x9F9C,0x9F9F}
+};
+
+
+
+/* the letters correspond to unicode characters which
+ * have Lu, Ll, Lt, Lm, Lo, Mn, Mc, or Me in their
+ * GENERAL CATEGORY */
+
+#define NUM_LETTER_INFO 274
+static const unirange letter_info[NUM_LETTER_INFO] = {
+  {0x41,0x5a}, {0x61,0x7a}, {0xaa,0xaa}, {0xb5,0xb5}, 
+  {0xba,0xba}, {0xc0,0xd6}, {0xd8,0xf6}, {0xf8,0x1f5}, 
+  {0x1fa,0x217}, {0x250,0x2a8}, {0x2b0,0x2b8}, {0x2bb,0x2c1}, 
+  {0x2d0,0x2d1}, {0x2e0,0x2e4}, {0x300,0x345}, {0x360,0x361}, 
+  {0x37a,0x37a}, {0x386,0x386}, {0x388,0x38a}, {0x38c,0x38c}, 
+  {0x38e,0x3a1}, {0x3a3,0x3ce}, {0x3d0,0x3d6}, {0x3da,0x3da}, 
+  {0x3dc,0x3dc}, {0x3de,0x3de}, {0x3e0,0x3e0}, {0x3e2,0x3f3}, 
+  {0x401,0x40c}, {0x40e,0x44f}, {0x451,0x45c}, {0x45e,0x481}, 
+  {0x483,0x486}, {0x490,0x4c4}, {0x4c7,0x4c8}, {0x4cb,0x4cc}, 
+  {0x4d0,0x4eb}, {0x4ee,0x4f5}, {0x4f8,0x4f9}, {0x531,0x556}, 
+  {0x559,0x559}, {0x561,0x587}, {0x591,0x5a1}, {0x5a3,0x5b9}, 
+  {0x5bb,0x5bd}, {0x5bf,0x5bf}, {0x5c1,0x5c2}, {0x5c4,0x5c4}, 
+  {0x5d0,0x5ea}, {0x5f0,0x5f2}, {0x621,0x63a}, {0x640,0x652}, 
+  {0x670,0x6b7}, {0x6ba,0x6be}, {0x6c0,0x6ce}, {0x6d0,0x6d3}, 
+  {0x6d5,0x6e8}, {0x6ea,0x6ed}, {0x901,0x903}, {0x905,0x939}, 
+  {0x93c,0x94d}, {0x951,0x954}, {0x958,0x963}, {0x981,0x983}, 
+  {0x985,0x98c}, {0x98f,0x990}, {0x993,0x9a8}, {0x9aa,0x9b0}, 
+  {0x9b2,0x9b2}, {0x9b6,0x9b9}, {0x9bc,0x9bc}, {0x9be,0x9c4}, 
+  {0x9c7,0x9c8}, {0x9cb,0x9cd}, {0x9d7,0x9d7}, {0x9dc,0x9dd}, 
+  {0x9df,0x9e3}, {0x9f0,0x9f1}, {0xa02,0xa02}, {0xa05,0xa0a}, 
+  {0xa0f,0xa10}, {0xa13,0xa28}, {0xa2a,0xa30}, {0xa32,0xa33}, 
+  {0xa35,0xa36}, {0xa38,0xa39}, {0xa3c,0xa3c}, {0xa3e,0xa42}, 
+  {0xa47,0xa48}, {0xa4b,0xa4d}, {0xa59,0xa5c}, {0xa5e,0xa5e}, 
+  {0xa70,0xa74}, {0xa81,0xa83}, {0xa85,0xa8b}, {0xa8d,0xa8d}, 
+  {0xa8f,0xa91}, {0xa93,0xaa8}, {0xaaa,0xab0}, {0xab2,0xab3}, 
+  {0xab5,0xab9}, {0xabc,0xac5}, {0xac7,0xac9}, {0xacb,0xacd}, 
+  {0xae0,0xae0}, {0xb01,0xb03}, {0xb05,0xb0c}, {0xb0f,0xb10}, 
+  {0xb13,0xb28}, {0xb2a,0xb30}, {0xb32,0xb33}, {0xb36,0xb39}, 
+  {0xb3c,0xb43}, {0xb47,0xb48}, {0xb4b,0xb4d}, {0xb56,0xb57}, 
+  {0xb5c,0xb5d}, {0xb5f,0xb61}, {0xb82,0xb83}, {0xb85,0xb8a}, 
+  {0xb8e,0xb90}, {0xb92,0xb95}, {0xb99,0xb9a}, {0xb9c,0xb9c}, 
+  {0xb9e,0xb9f}, {0xba3,0xba4}, {0xba8,0xbaa}, {0xbae,0xbb5}, 
+  {0xbb7,0xbb9}, {0xbbe,0xbc2}, {0xbc6,0xbc8}, {0xbca,0xbcd}, 
+  {0xbd7,0xbd7}, {0xc01,0xc03}, {0xc05,0xc0c}, {0xc0e,0xc10}, 
+  {0xc12,0xc28}, {0xc2a,0xc33}, {0xc35,0xc39}, {0xc3e,0xc44}, 
+  {0xc46,0xc48}, {0xc4a,0xc4d}, {0xc55,0xc56}, {0xc60,0xc61}, 
+  {0xc82,0xc83}, {0xc85,0xc8c}, {0xc8e,0xc90}, {0xc92,0xca8}, 
+  {0xcaa,0xcb3}, {0xcb5,0xcb9}, {0xcbe,0xcc4}, {0xcc6,0xcc8}, 
+  {0xcca,0xccd}, {0xcd5,0xcd6}, {0xcde,0xcde}, {0xce0,0xce1}, 
+  {0xd02,0xd03}, {0xd05,0xd0c}, {0xd0e,0xd10}, {0xd12,0xd28}, 
+  {0xd2a,0xd39}, {0xd3e,0xd43}, {0xd46,0xd48}, {0xd4a,0xd4d}, 
+  {0xd57,0xd57}, {0xd60,0xd61}, {0xe01,0xe2e}, {0xe30,0xe3a}, 
+  {0xe40,0xe4e}, {0xe81,0xe82}, {0xe84,0xe84}, {0xe87,0xe88}, 
+  {0xe8a,0xe8a}, {0xe8d,0xe8d}, {0xe94,0xe97}, {0xe99,0xe9f}, 
+  {0xea1,0xea3}, {0xea5,0xea5}, {0xea7,0xea7}, {0xeaa,0xeab}, 
+  {0xead,0xeae}, {0xeb0,0xeb9}, {0xebb,0xebd}, {0xec0,0xec4}, 
+  {0xec6,0xec6}, {0xec8,0xecd}, {0xedc,0xedd}, {0xf18,0xf19}, 
+  {0xf35,0xf35}, {0xf37,0xf37}, {0xf39,0xf39}, {0xf40,0xf47}, 
+  {0xf49,0xf69}, {0xf71,0xf84}, {0xf86,0xf87}, {0xf90,0xf95}, 
+  {0xf97,0xf97}, {0xf99,0xfad}, {0xfb1,0xfb7}, {0xfb9,0xfb9}, 
+  {0x10a0,0x10c5}, {0x10d0,0x10f6}, {0x1100,0x1159}, {0x115f,0x11a2}, 
+  {0x11a8,0x11f9}, {0x1e00,0x1e9b}, {0x1ea0,0x1ef9}, {0x1f00,0x1f15}, 
+  {0x1f18,0x1f1d}, {0x1f20,0x1f45}, {0x1f48,0x1f4d}, {0x1f50,0x1f57}, 
+  {0x1f59,0x1f59}, {0x1f5b,0x1f5b}, {0x1f5d,0x1f5d}, {0x1f5f,0x1f7d}, 
+  {0x1f80,0x1fb4}, {0x1fb6,0x1fbc}, {0x1fbe,0x1fbe}, {0x1fc2,0x1fc4}, 
+  {0x1fc6,0x1fcc}, {0x1fd0,0x1fd3}, {0x1fd6,0x1fdb}, {0x1fe0,0x1fec}, 
+  {0x1ff2,0x1ff4}, {0x1ff6,0x1ffc}, {0x207f,0x207f}, {0x20d0,0x20e1}, 
+  {0x2102,0x2102}, {0x2107,0x2107}, {0x210a,0x2113}, {0x2115,0x2115}, 
+  {0x2118,0x211d}, {0x2124,0x2124}, {0x2126,0x2126}, {0x2128,0x2128}, 
+  {0x212a,0x2131}, {0x2133,0x2138}, {0x3005,0x3005}, {0x302a,0x302f}, 
+  {0x3031,0x3035}, {0x3041,0x3094}, {0x3099,0x309e}, {0x30a1,0x30fa}, 
+  {0x30fc,0x30fe}, {0x3105,0x312c}, {0x3131,0x318e}, {0x4e00,0x9fa5}, 
+  {0xac00,0xd7a3}, {0xf900,0xfa2d}, {0xfb00,0xfb06}, {0xfb13,0xfb17}, 
+  {0xfb1e,0xfb28}, {0xfb2a,0xfb36}, {0xfb38,0xfb3c}, {0xfb3e,0xfb3e}, 
+  {0xfb40,0xfb41}, {0xfb43,0xfb44}, {0xfb46,0xfbb1}, {0xfbd3,0xfd3d}, 
+  {0xfd50,0xfd8f}, {0xfd92,0xfdc7}, {0xfdf0,0xfdfb}, {0xfe20,0xfe23}, 
+  {0xfe70,0xfe72}, {0xfe74,0xfe74}, {0xfe76,0xfefc}, {0xff21,0xff3a}, 
+  {0xff41,0xff5a}, {0xff66,0xffbe}, {0xffc2,0xffc7}, {0xffca,0xffcf}, 
+  {0xffd2,0xffd7}, {0xffda,0xffdc}
+};
+
+
+/* the digits correspond to unicode characters which
+ * have Nd in their GENERAL CATEGORY */
+
+#define NUM_DIGIT_INFO 16
+static const unirange digit_info[NUM_DIGIT_INFO] = {
+  {0x30,0x39}, {0x660,0x669}, {0x6f0,0x6f9}, {0x966,0x96f}, 
+  {0x9e6,0x9ef}, {0xa66,0xa6f}, {0xae6,0xaef}, {0xb66,0xb6f}, 
+  {0xbe7,0xbef}, {0xc66,0xc6f}, {0xce6,0xcef}, {0xd66,0xd6f}, 
+  {0xe50,0xe59}, {0xed0,0xed9}, {0xf20,0xf29}, {0xff10,0xff19}
+};
+
+
+/* the spaces correspond to unicode characters which
+ * have Zs, Zl, or Zp in their GENERAL CATEGORY */
+
+#define NUM_SPACE_INFO 5
+static const unirange space_info[NUM_SPACE_INFO] = {
+  {0x20,0x20}, {0xa0,0xa0}, {0x2000,0x200b}, {0x2028,0x2029}, 
+  {0x3000,0x3000}
+};
+
+
+
+/* parse_utf8_char parses the next utf-8 character, placing its
+ * unicode equivalent in *value. The length of the utf-8 character
+ * is returned */
+int parse_utf8_char(const unsigned char *here,
+		    const unsigned char *end,
+		    unsigned short *value) {
+  unsigned short c1;
+  unsigned short c2;
+  unsigned short c3;
+  
+  *value = 0; /* will be the value for illegal characters */
+  
+  if (here <= end) {
+    c1 = (unsigned short)(*here);
+    
+    if (c1 <= 0x7f) {
+      /* found a one-byte character */
+      *value = c1;
+      return 1;
+      
+    } else if (c1 >= 0xc0 && c1 <= 0xdf && here+1 <= end &&
+	       (c2=(unsigned short)(*(here+1))) >= 0x80) {
+      /* found a two-byte character */
+      *value = ((c1 & 0x1f) << 6) + (c2 & 0x3f);
+      return 2;
+      
+    } else if (c1 >= 0xe0 && c1 <= 0xef && here+2 <= end &&
+	       (c2=(unsigned int)(*(here+1))) >= 0x80 &&
+	       (c3=(unsigned int)(*(here+2))) >= 0x80) {
+      /* found a three-byte character */
+      *value = ((c1 & 0xf) << 12) + ((c2 & 0x3f) << 6) +
+	(c3 & 0x3f);
+      return 3;
+      
+    } else {
+      /* error in encoding, return the length as 1 */
+      return 1;
+    }
+  }
+
+  /* end of string */
+  return 0;
+}
+
+
+/* output_utf8_char encodes a unicode character as a UTF-8 character.
+ * The length of the encoding is returned. If the string was not
+ * long enough to encode the character 0 is returned. */
+int output_utf8_char (unsigned short value,
+		      unsigned char *here,
+		      unsigned char *end) {
+  int len = (int)(end - here + 1); /* end is the last character */
+  if (value < 0x80) {
+    /* will be encoded in one byte */
+    if (len >= 1) {
+      *here = (unsigned char)value;
+      return 1;
+    }
+
+  } else if (value < 0x800) {
+    /* will be encoded in two bytes */
+    if (len >= 2) {
+      *here++ = 0xc0 | (unsigned char)((value >> 6) & 0x1f);
+      *here = 0x80 | (unsigned char)(value & 0x3f);
+
+      return 2;
+    }
+
+  } else {
+    /* will be encoded in three bytes */
+    if (len >= 3) {
+      *here++ = 0xe0 | (unsigned char)((value >> 12) & 0xf);
+      *here++ = 0x80 | (unsigned char)((value >> 6) & 0x3f);
+      *here = 0x80 | (unsigned char)(value & 0x3f);
+      return 3;
+    }
+  }
+
+  return 0;
+}
+
+
+static int lookup_decompose_table (unsigned short value) {
+  int first = 0;
+  int last = NUM_DECOMPOSE_INFO;
+  int here;
+
+  while (first < last) {
+    here = (last-first)/2 + first;
+    if (value < decompose_info[here].ch) {
+      last = here;
+    } else if (value > decompose_info[here].ch) {
+      first = here+1;
+    } else {
+      return here;
+    }
+  }
+
+  return -1;
+}
+
+/* decompose_str will decompose a unicode string into its canonical
+ * equivalents. NULL is returned if the input array was not 
+ * large enough to contain the fully decomposed string (the array
+ * will be in a correct, but partially decomposed state). The input 
+ * must be null-terminated. */
+unsigned short *decompose_str (unsigned short *input,
+			       int max_output_len) {
+  int curpos = 0;
+  int curlen = unicode_strlen (input);
+  int tablepos = 0;
+  int leninc;
+  int i;
+
+  while (input[curpos] != 0) {
+    tablepos = lookup_decompose_table (input[curpos]);
+    if (tablepos >= 0) {
+      /* found a decomposition */
+      leninc = unicode_strnlen (decompose_info[tablepos].str, 3)-1;
+      if (curlen+leninc < max_output_len) {
+	/* enough space for this decomposition */
+
+	if (leninc > 1) {
+	  /* we have to shift the array along */
+	  for (i=curlen-1; i>=curpos; i--) {
+	    input[i+leninc] = input[i];
+	  }
+	  input[curlen+leninc] = 0;
+	  curlen += leninc;
+	}
+
+	/* decompose the character */
+	for (i=0; i<=leninc; i++) {
+	  input[curpos+i] = decompose_info[tablepos].str[i];
+	}
+
+	/* note: curpos is not incremented because the decomposed */
+	/*       characters might need decomposing */
+
+      } else {
+	/* no space left in string */
+	return NULL;
+      }
+
+    } else {
+      /* the character cannot be decomposed */
+      curpos++;
+    }
+  }
+
+  return input;
+}
+
+
+
+/* unicode_cat_data is a combination of the letter, digit, and
+ * space information in a form that is quick to look up.
+ * The information about each byte is stored in two bits
+ *
+ * 00 - neither letter, digit or space
+ * 01 - letter
+ * 10 - space
+ * 11 - digit
+ *
+ * You can test for letter | space by looking at the right
+ * column
+ */
+unsigned long *unicode_cat_data;
+
+void create_unicat_data () {
+  int i=0;
+  int min_start=0;
+  int min_end=0;
+  register unsigned long min_value=0; /* filling the whole byte */
+  
+  const unirange *letter_here = letter_info;
+  const unirange *letter_end = letter_info+NUM_LETTER_INFO;
+  const unirange *digit_here = digit_info;
+  const unirange *digit_end = digit_info+NUM_DIGIT_INFO;
+  const unirange *space_here = space_info;
+  const unirange *space_end = space_info+NUM_SPACE_INFO;
+
+  if (unicode_cat_data != NULL) return;
+  unicode_cat_data = malloc (0x10000/4);
+  if (unicode_cat_data == NULL) return;
+  
+  while (i <= 0xffff) {
+    /* decide what to fill with next */
+    min_start = i;
+    min_end = 0xffff;
+    min_value = 0; /* 00 */
+    
+    while (letter_here < letter_end && letter_here->last < i) letter_here++;
+    if (letter_here < letter_end && letter_here->last <= min_end) {
+      min_start = letter_here->first;
+      min_end = letter_here->last;
+      min_value = 0x55555555; /* 01 */
+    }
+    
+    while (digit_here < digit_end && digit_here->last < i) digit_here++;
+    if (digit_here < digit_end && digit_here->last <= min_end) {
+      min_start = digit_here->first;
+      min_end = digit_here->last;
+      min_value = 0xffffffff; /* 11 */
+    }
+    
+    while (space_here < space_end && space_here->last < i) space_here++;
+    if (space_here < space_end && space_here->last <= min_end) {
+      min_start = space_here->first;
+      min_end = space_here->last;
+      min_value = 0xaaaaaaaa; /* 10 */
+    }
+
+    if (min_start < i) min_start = i;
+    else if (min_start > i) {
+      min_end = min_start-1;
+      min_start = i;
+      min_value = 0; /* 00 */
+    }
+
+    /* fill the entries from min_start to min_end with min_value */
+    while (i <= min_end) {
+      /* special version for common case */
+      if (i % 16 == 0) {
+	unicode_cat_data[i/16] = min_value; /* doesn't matter if too long */
+	i += 16;
+	if (i > min_end) {
+	  i = min_end+1;
+	  break;
+	}
+	
+      } else {
+	register unsigned long mask = 3 << ((i % 16) * 2);
+	unicode_cat_data[i/16] = (unicode_cat_data[i/16] & (~mask)) |
+				  (min_value & mask);
+	i++;
+      }
+    }
+  }
+}
+
+/* does a binary search on a range table */
+static int in_unirange (const unirange *info, int num_info,
+			unsigned short value) {
+  int first = 0;
+  int last = num_info;
+  int here;
+
+  while (first < last) {
+    here = (last-first)/2 + first;
+    if (value < info[here].first) {
+      last = here;
+    } else if (value > info[here].last) {
+      first = here+1;
+    } else {
+      return 1;
+    }
+  }
+
+  return 0;
+}
+
+
+
+/* tests to see whether 'value' is a valid Unicode letter */
+int is_unicode_letter (unsigned short value) {
+  if (unicode_cat_data == NULL) create_unicat_data ();
+  if (unicode_cat_data == NULL) {
+    /* use old method */
+    return in_unirange(letter_info, NUM_LETTER_INFO, value);
+  }
+
+  return (((unicode_cat_data[value/16] >> ((value%16)*2)) & 0x3) == 0x1);
+}
+
+/* tests to see whether 'value' is a valid Unicode digit */
+int is_unicode_digit (unsigned short value) {
+  if (unicode_cat_data == NULL) create_unicat_data ();
+  if (unicode_cat_data == NULL) {
+    /* use old method */
+    return in_unirange(digit_info, NUM_DIGIT_INFO, value);
+  }
+
+  return (((unicode_cat_data[value/16] >> ((value%16)*2)) & 0x3) == 0x3);
+}
+
+/* tests to see whether 'value' is a valid Unicode letter or 
+ * digit */
+int is_unicode_letdig (unsigned short value) {
+  if (unicode_cat_data == NULL) create_unicat_data ();
+  if (unicode_cat_data == NULL) {
+    /* use old method */
+    return (in_unirange(letter_info, NUM_LETTER_INFO, value) ||
+	    in_unirange(digit_info, NUM_DIGIT_INFO, value));
+    
+  }
+
+  return ((unicode_cat_data[value/16] >> ((value%16)*2)) & 0x1);
+}
+
+/* tests to see whether 'value' is a valid space
+ * The test includes both "C" spaces and "Unicode" spaces, i.e. 
+ * form-feed, newline, carriage return, horizontal tab,
+ * vertical tab, and the Zs, Zl, and Zp Unicode categorizations */
+int is_unicode_space (unsigned short value) {
+  if (value < 0x80) return isspace (value);
+  if (unicode_cat_data == NULL) create_unicat_data ();
+  if (unicode_cat_data == NULL) {
+    /* use old method */
+    return in_unirange(space_info, NUM_SPACE_INFO, value);
+  }
+
+  return (((unicode_cat_data[value/16] >> ((value%16)*2)) & 0x3) == 0x2);
+}
+
+/* returns the length of the unicode string */
+int unicode_strlen (const unsigned short *str) {
+  int len = 0;
+
+  /* keep going till you find the null-terminator */
+  while (*str != 0) {
+    len++;
+    str++;
+  }
+
+  return len;
+}
+
+/* returns the length of the unicode string, up to a maximum */
+int unicode_strnlen (const unsigned short *str, int max_length) {
+  int len = 0;
+
+  /* keep going till you find the null-terminator */
+  while (*str != 0 && len < max_length ) {
+    len++;
+    str++;
+  }
+
+  return len;
+}
+
+
+/* Does a binary search on a relate table, returns -1 if it is not
+ * found. */
+static int search_unirelate (const unirelate *info, int num_info,
+			     unsigned short value) {
+  int first = 0;
+  int last = num_info;
+  int here;
+
+  while (first < last) {
+    here = (last-first)/2 + first;
+    if (value < info[here].ch1) {
+      last = here;
+    } else if (value > info[here].ch1) {
+      first = here+1;
+    } else {
+      return here;
+    }
+  }
+
+  return -1;
+}
+
+
+/* returns the upper-case equivalent of value */
+unsigned short unicode_toupper (unsigned short value) {
+  int related = search_unirelate (toupper_info, NUM_TOUPPER_INFO, value);
+  if (related >= 0) {
+    value = toupper_info[related].ch2;
+  }
+  return value;
+}
+
+/* returns the lower-case equivalent of value */
+unsigned short unicode_tolower (unsigned short value) {
+  int related = search_unirelate (tolower_info, NUM_TOLOWER_INFO, value);
+  if (related >= 0) {
+    value = tolower_info[related].ch2;
+  }
+  return value;
+}
+
+/* returns the simplified Chinese character equivalent of 
+ * another Chinese character */
+unsigned short unicode_tosimplified (unsigned short value) {
+  int related = search_unirelate (tosimplified_info, NUM_TOSIMPLIFIED_INFO, value);
+  if (related >= 0) {
+    value = tosimplified_info[related].ch2;
+  }
+  return value;
+}
+
+
+/* converts a utf-8 word (string with length stored in the first byte
+ * to a Unicode array. To handle all situations the output buffer should
+ * be 256 unsigned shorts long. The output will also have the length as
+ * the first entry. */
+unsigned short *utf8_word_to_unicode (const unsigned char *input,
+				      unsigned short *output,
+				      int max_output_length) {
+  int inlen = *input;
+  const unsigned char *inhere = input+1;
+  const unsigned char *inend = &inhere[inlen-1];
+  unsigned short c;
+  int clen;
+  
+  int outlen = 0;
+  unsigned short *outhere = output+1;
+  
+  while (inhere <= inend && inlen < max_output_length-1) {
+    /* decode the character */
+    clen = parse_utf8_char (inhere, inend, &c);
+    inhere += clen;
+
+    if (clen > 0) {
+      /* store the character */
+      *outhere = c;
+      outhere++;
+      outlen++;
+    }
+  }
+
+  output[0] = outlen;
+  return output;
+}
+
+
+/* converts a unicode word buffer (with the length stored in the
+ * entry) to a utf8 encoded word output (with the length stored in
+ * the first byte. Only 255 bytes (not characters) can be stored 
+ * in the output. */
+unsigned char *unicode_to_utf8_word (const unsigned short *input,
+				     unsigned char *output,
+				     int max_output_length) {
+  int inlen = *input;
+  const unsigned short *word = input + 1;
+  int in_i = 0;
+  int clen;
+
+  int outlen = 0;
+  unsigned char *outhere = output+1;
+  unsigned char *outend = output+max_output_length;
+
+  while (in_i < inlen) {
+    if ((clen=output_utf8_char(word[in_i], outhere, outend)) == 0) {
+      /* ran out of space to encode the character */
+      break;
+    }
+
+    outhere += clen;
+    outlen += clen;
+    in_i++;
+  }
+
+  output[0] = outlen;
+
+  return output;
+}
+
Index: /main/tags/2.25/gsdl/packages/mg/lib/unitool.h
===================================================================
--- /main/tags/2.25/gsdl/packages/mg/lib/unitool.h	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/mg/lib/unitool.h	(revision 21064)
@@ -0,0 +1,88 @@
+#ifndef UNITOOL_H
+#define UNITOOL_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+
+/* This module is based on Unicode 2.1 */
+
+
+/* parse_utf8_char parses the next utf-8 character, placing its
+ * unicode equivalent in *value. The length of the utf-8 character
+ * is returned. end is the address of the last character. */
+int parse_utf8_char (const unsigned char *here,
+		     const unsigned char *end,
+		     unsigned short *value);
+
+/* output_utf8_char encodes a unicode character as a UTF-8 character.
+ * The length of the encoding is returned. If the string was not
+ * long enough to encode the character 0 is returned. end is the
+ * address of the last character */
+int output_utf8_char (unsigned short value,
+		      unsigned char *here,
+		      unsigned char *end);
+
+/* decompose_str will decompose a unicode string into its canonical
+ * equivalents. NULL is returned if the input array was not 
+ * large enough to contain the fully decomposed string (the array
+ * will be in a correct, but partially decomposed state). The input 
+ * must be null-terminated. */
+unsigned short *decompose_str (unsigned short *input,
+			       int max_output_len);
+
+/* tests to see whether 'value' is a valid Unicode letter */
+int is_unicode_letter (unsigned short value);
+
+/* tests to see whether 'value' is a valid Unicode digit */
+int is_unicode_digit (unsigned short value);
+
+/* tests to see whether 'value' is a valid Unicode letter or 
+ * digit */
+int is_unicode_letdig (unsigned short value);
+
+/* tests to see whether 'value' is a valid space
+ * The test includes both "C" spaces and "Unicode" spaces, i.e. 
+ * form-feed, newline, carriage return, horizontal tab,
+ * vertical tab, and the Zs, Zl, and Zp Unicode categorizations */
+int is_unicode_space (unsigned short value);
+
+/* returns the length of the unicode string */
+int unicode_strlen (const unsigned short *str);
+
+/* returns the length of the unicode string, up to a maximum */
+int unicode_strnlen (const unsigned short *str, int max_length);
+
+/* returns the upper-case equivalent of value */
+unsigned short unicode_toupper (unsigned short value);
+
+/* returns the lower-case equivalent of value */
+unsigned short unicode_tolower (unsigned short value);
+
+/* returns the simplified Chinese character equivalent of 
+ * another Chinese character */
+unsigned short unicode_tosimplified (unsigned short value);
+
+
+/* converts a utf-8 word (string with length stored in the first byte
+ * to a Unicode array. To handle all situations the output buffer should
+ * be 256 unsigned shorts long. The output will also have the length as
+ * the first entry. */
+unsigned short *utf8_word_to_unicode (const unsigned char *input,
+				      unsigned short *output,
+				      int max_output_length);
+
+/* converts a unicode word buffer (with the length stored in the
+ * entry) to a utf8 encoded word output (with the length stored in
+ * the first byte. Only 255 bytes (not characters) can be stored 
+ * in the output. */
+unsigned char *unicode_to_utf8_word (const unsigned short *input,
+				     unsigned char *output,
+				     int max_output_length);
+
+#ifdef __cplusplus
+	   }
+#endif
+
+#endif
Index: /main/tags/2.25/gsdl/packages/mg/lib/win32in.c
===================================================================
--- /main/tags/2.25/gsdl/packages/mg/lib/win32in.c	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/mg/lib/win32in.c	(revision 21064)
@@ -0,0 +1,72 @@
+/* This module provides an equivalent of <netinet/in.h> on  */
+/* unix systems. */
+
+unsigned long htonl(unsigned long x) {
+#if defined (LITTLE_ENDIAN) || defined (_LITTLE_ENDIAN) || defined(__LITTLE_ENDIAN)
+	x = ((x >> 24) & 0x000000FF) | ((x >> 8) & 0x0000FF00) |
+		((x << 8) & 0x00FF0000) | ((x << 24) & 0xFF000000);
+#endif
+
+	return x;
+}
+
+unsigned long ntohl(unsigned long x) {
+#if defined (LITTLE_ENDIAN) || defined (_LITTLE_ENDIAN) || defined(__LITTLE_ENDIAN)
+	x = ((x >> 24) & 0x000000FF) | ((x >> 8) & 0x0000FF00) |
+		((x << 8) & 0x00FF0000) | ((x << 24) & 0xFF000000);
+#endif
+	return x;
+}
+
+unsigned short htons(unsigned short x) {
+#if defined (LITTLE_ENDIAN) || defined (_LITTLE_ENDIAN) || defined(__LITTLE_ENDIAN)
+	x = ((x >> 8) & 0x00FF) | ((x << 8) & 0xFF00);
+#endif
+	return x;
+}
+
+unsigned short ntohs(unsigned short x) {
+#if defined (LITTLE_ENDIAN) || defined (_LITTLE_ENDIAN) || defined(__LITTLE_ENDIAN)
+	x = ((x >> 8) & 0x00FF) | ((x << 8) & 0xFF00);
+#endif
+	return x;
+}
+
+/* just to test stuff
+#include <stdio.h>
+
+main () {
+	long x;
+	short sx;
+
+	x = 0x000000FF;
+	printf ("before %i, ",(int)x);
+	x = htonl (x);
+	printf ("after %i\n",(int)x);
+
+	x = 0x0000FF00;
+	printf ("before %i, ",(int)x);
+	x = htonl (x);
+	printf ("after %i\n",(int)x);
+
+	x = 0x00FF0000;
+	printf ("before %i, ",(int)x);
+	x = htonl (x);
+	printf ("after %i\n",(int)x);
+
+	x = 0xFF000000;
+	printf ("before %i, ",(int)x);
+	x = htonl (x);
+	printf ("after %i\n\n",(int)x);
+
+	sx = 0x00FF;
+	printf ("before %i, ",(int)sx);
+	sx = htons (sx);
+	printf ("after %i\n",(int)sx);
+
+	sx = 0xFF00;
+	printf ("before %i, ",(int)sx);
+	sx = htons (sx);
+	printf ("after %i\n",(int)sx);
+}
+*/
Index: /main/tags/2.25/gsdl/packages/mg/lib/win32in.h
===================================================================
--- /main/tags/2.25/gsdl/packages/mg/lib/win32in.h	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/mg/lib/win32in.h	(revision 21064)
@@ -0,0 +1,7 @@
+/* This module provides an equivalent of <netinet/in.h> on  */
+/* unix systems. */
+
+unsigned long htonl(unsigned long x);
+unsigned long ntohl(unsigned long x);
+unsigned short htons(unsigned short x);
+unsigned short ntohs(unsigned short x);
Index: /main/tags/2.25/gsdl/packages/mg/lib/xmalloc.c
===================================================================
--- /main/tags/2.25/gsdl/packages/mg/lib/xmalloc.c	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/mg/lib/xmalloc.c	(revision 21064)
@@ -0,0 +1,111 @@
+/* xmalloc.c -- malloc with out of memory checking
+   Copyright (C) 1990, 91, 92, 93, 94 Free Software Foundation, Inc.
+
+   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, 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.  */
+
+#ifdef HAVE_CONFIG_H
+# ifdef __WIN32__  /* [RPAP - Feb 97: WIN32 Port] */
+#  include <win32cfg.h>
+# else
+#  include <sysfuncs.h>
+# endif
+#endif
+
+#if __STDC__
+#define VOID void
+#else
+#define VOID char
+#endif
+
+#include <sys/types.h>
+
+#if STDC_HEADERS
+#include <stdlib.h>
+#else
+VOID *malloc ();
+VOID *realloc ();
+void free ();
+#endif
+
+/* This is for other GNU distributions with internationalized messages.
+   The GNU C Library itself does not yet support such messages.  */
+#if HAVE_LIBINTL_H
+# include <libintl.h>
+#else
+# define gettext(msgid) (msgid)
+#endif
+
+#ifndef EXIT_FAILURE
+#define EXIT_FAILURE 1
+#endif
+
+/* Exit value when the requested amount of memory is not available.
+   The caller may set it to some other value.  */
+int xmalloc_exit_failure = EXIT_FAILURE;
+
+#if defined(__WIN32__)
+void error (int, int, const char *, ...);
+#else
+#if __STDC__ && (HAVE_VPRINTF || HAVE_DOPRNT)
+void error (int, int, const char *, ...);
+#else
+void error (int, int, char *, char *, char *, char *, char *, char *, char *, char *, char *);
+#endif
+#endif;
+
+static VOID *
+fixup_null_alloc (n)
+     size_t n;
+{
+  VOID *p;
+
+  p = 0;
+  if (n == 0)
+    p = malloc ((size_t) 1);
+  if (p == 0)
+    error (xmalloc_exit_failure, 0, gettext ("Memory exhausted"));
+  return p;
+}
+
+/* Allocate N bytes of memory dynamically, with error checking.  */
+
+VOID *
+xmalloc (n)
+     size_t n;
+{
+  VOID *p;
+
+  p = malloc (n);
+  if (p == 0)
+    p = fixup_null_alloc (n);
+  return p;
+}
+
+/* Change the size of an allocated block of memory P to N bytes,
+   with error checking.
+   If P is NULL, run xmalloc.  */
+
+VOID *
+xrealloc (p, n)
+     VOID *p;
+     size_t n;
+{
+  if (p == 0)
+    return xmalloc (n);
+  p = realloc (p, n);
+  if (p == 0)
+    p = fixup_null_alloc (n);
+  return p;
+}
Index: /main/tags/2.25/gsdl/packages/mg/man/man1/mg_compression_dict.1
===================================================================
--- /main/tags/2.25/gsdl/packages/mg/man/man1/mg_compression_dict.1	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/mg/man/man1/mg_compression_dict.1	(revision 21064)
@@ -0,0 +1,219 @@
+.\"------------------------------------------------------------
+.\" Id - set Rv,revision, and Dt, Date using rcs-Id tag.
+.de Id
+.ds Rv \\$3
+.ds Dt \\$4
+..
+.Id $Id$
+.\"------------------------------------------------------------
+.TH mg_compression_dict 1 \*(Dt CITRI
+.SH NAME
+mg_compression_dict \- build a compression dictionary.
+.SH SYNOPSIS
+.B mg_compression_dict
+[
+.B \-h
+]
+[
+.BR \-C " |"
+.BR \-P " |"
+.B  \-S
+]
+.if n .ti +9n
+[
+.BR \-0 " |"
+.BR \-1 " |"
+.BR \-2 " |"
+.B  \-3
+]
+[
+.BR \-H " |"
+.BR \-B " |"
+.BR \-D " |"
+.BR \-Y " |"
+.B  \-M
+]
+.if n .ti +9n
+.if t .ti +.5i
+[
+.BI \-l " lookback"
+]
+[
+.BI \-k " mem"
+]
+[
+.BI \-d " directory"
+]
+.BI \-f " name"
+.SH DESCRIPTION
+.B mg_compression_dict
+builds a compression dictionary based on the statistics gathered
+during the first pass over the text.  The options to the program are
+mainly concerned with limiting the amount of memory the dictionary
+will use and with how the text compressor will cope with any novel
+words found during the compression phase.
+.SH OPTIONS
+Options may appear in any order.
+.TP "\w'\fB\-d\fP \fIdirectory\fP'u+2n"
+.B \-h
+This displays a usage line on
+.IR stderr .
+.TP
+.B \-C
+Build a complete dictionary from the statistics file.  If during the
+text compression phase a novel word is found, then the compressor will
+produce an error message and stop.
+.TP
+.B \-P
+Build a partial dictionary from the statistics file.  This dictionary
+assumes that the statistics file are based on the entire text.  The
+statistics of words not includes in the dictionary are used to
+calculate the escape probability.  If novel words are being coded
+character by character, then there may not be a Huffman code for every
+possible character.  This means that the compressor may fail if a novel
+word contains a novel character.
+.TP
+.B \-S
+Build a seed dictionary from the statistics file.  This dictionary
+assumes that the statistics file is based on only a portion of the
+text to be compressed.  The probability of a novel word is based on the
+number of words that have only occurred once.  If novel words are being
+coded character by character, then the Huffman codes for characters are
+based on the frequency of characters in the dictionary.
+.TP
+.B \-0
+All words from the statistics file are included in the built
+dictionary.
+.TP
+.B \-1
+Words are included in the dictionary until the dictionary reaches the
+desired size.  Words are selected for the dictionary based on the order
+they occurred in the source text.
+.TP
+.B \-2
+Words are included in the dictionary until the dictionary reaches the
+desired size.  The most frequent words are included in the dictionary
+first; where there is a tie for frequency, the shortest word is
+included first.
+.TP
+.B \-3
+Words are included in the dictionary until the dictionary reaches the
+desired size.  The most frequent words are included in the dictionary
+first; where there is a tie for frequency, the shortest word is
+included first.  Words are the shuffled back and forth between the
+`keep' and `discard' lists to find the `optimal' set of words that
+should be in the dictionary.
+.TP
+.B \-H
+This specifies that novel words will be coded character by character
+using Huffman codes.
+.TP
+.B \-B
+This specifies that an auxiliary dictionary will be built by the
+compressor.  Each novel word found will be placed at the end of the
+auxiliary dictionary.  Novel words will be coded in the compressed text
+using binary codes.  The binary code represents their occurrence
+position in the auxiliary dictionary.
+.TP
+.B \-D
+This specifies that an auxiliary dictionary will be built by the
+compressor.  Each novel word found will be placed at the end of the
+auxiliary dictionary.  Novel words will be coded in the compressed text
+using delta codes.  The delta code represents their occurrence position
+in the auxiliary dictionary.
+.TP
+.B \-Y
+This specifies that an auxiliary dictionary will be built by the
+compressor.  Each novel word found will be placed at the end of the
+auxiliary dictionary.  Novel words will be coded in the compressed text
+using a combination of gamma and binary codes.  The code represents
+their occurrence position in the auxiliary dictionary.  This generally
+produces better compression than
+.B \-B
+or
+.BR \-D .
+.TP
+.B \-M
+This specifies that an auxiliary dictionary will be built by the
+compressor.  Each novel word found will be placed at the end of the
+auxiliary dictionary.  Novel words will be coded in the compressed text
+using a combination of gamma and binary codes.  The code represents
+their occurrence position in the auxiliary dictionary.  This method is
+adaptive within documents, and generally produces better compression
+than
+.BR \-B ,
+.B \-D
+or
+.BR \-Y .
+.TP
+.BI \-l " lookback"
+The generated dictionary is designed to be front coded when it is
+loaded into memory.  Under normal circumstances, a front-coded
+dictionary would require scanning from the beginning in order to find
+any particular word.  However, every
+.I lookback
+words in the dictionary, the whole word is stored and a pointer to that
+word maintained.  E.g., if
+.I lookback
+is 4, then every fourth word is stored in its entirety.
+.TP
+.BI \-k " mem"
+This limits the amount of memory to use for the generated
+dictionary.  Words are selected for the dictionary based of the text
+statistics, and whether
+.BR \-0 , " \-1" , " \-2"
+or
+.B \-3
+is specified.  The memory is calculated assuming a lookback of 0,
+irrespective of what actual lookback is specified.  This means that if
+a non-zero lookback is given, the dictionary will actually occupy
+less space than specified by
+.BR \-k .
+.TP
+.BI \-d " directory"
+This specifies the directory where the document collection can be found.
+.TP
+.BI \-f " name"
+This specifies the base name of the document collection.
+.SH ENVIRONMENT
+.TP "\w'\fBMGDATA\fP'u+2n"
+.SB MGDATA
+If this environment variable exists, then its value is used as the
+default directory where the
+.BR mg (1)
+collection files are.  If this variable does not exist, then the
+directory \*(lq\fB.\fP\*(rq is used by default.  The command line
+option
+.BI \-d " directory"
+overrides the directory in
+.BR MGDATA .
+.SH FILES
+.TP 20
+.B *.text.stats
+Statistics about the source text.
+.TP
+.B *.text.dict
+Compression dictionary for the source text.
+.SH "SEE ALSO"
+.na
+.BR mg (1),
+.BR mg_fast_comp_dict (1),
+.BR mg_get (1),
+.BR mg_invf_dict (1),
+.BR mg_invf_dump (1),
+.BR mg_invf_rebuild (1),
+.BR mg_passes (1),
+.BR mg_perf_hash_build (1),
+.BR mg_text_estimate (1),
+.BR mg_weights_build (1),
+.BR mgbilevel (1),
+.BR mgbuild (1),
+.BR mgdictlist (1),
+.BR mgfelics (1),
+.BR mgquery (1),
+.BR mgstat (1),
+.BR mgtic (1),
+.BR mgticbuild (1),
+.BR mgticdump (1),
+.BR mgticprune (1),
+.BR mgticstat (1).
Index: /main/tags/2.25/gsdl/packages/mg/man/man1/mg_decompress_text.1
===================================================================
--- /main/tags/2.25/gsdl/packages/mg/man/man1/mg_decompress_text.1	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/mg/man/man1/mg_decompress_text.1	(revision 21064)
@@ -0,0 +1,78 @@
+.\"------------------------------------------------------------
+.\" Id - set Rv,revision, and Dt, Date using rcs-Id tag.
+.de Id
+.ds Rv \\$3
+.ds Dt \\$4
+..
+.Id $Id$
+.\"------------------------------------------------------------
+.TH mg_decompress_text 1 \*(Dt CITRI
+.SH NAME
+mg_decompress_text \- decompresses the compressed text of a collection
+.SH SYNOPSIS
+.B mg_decompress_text
+[
+.B \-h
+]
+[
+.BI \-d " directory"
+]
+.BI \-f " name"
+.SH DESCRIPTION
+.B mg_decompress_text
+decompresses the compressed text of a collection, inserts paragraph and
+document markers, writing the output to
+.IR stdout ".  "
+This program was created
+to be used as a type of
+.BR mg_get (1).
+.SH OPTIONS
+Options may appear in any order.
+.TP "\w'\fB\-d\fP \fIdirectory\fP'u+2n"
+.B \-h
+This displays a usage line on
+.IR stderr .
+.TP
+.BI \-d " directory"
+This specifies the directory where the document collection can be found.
+.TP
+.BI \-f " name"
+This specifies the base name of the document collection.
+.SH ENVIRONMENT
+.TP "\w'\fBMGDATA\fP'u+2n"
+.SB MGDATA
+If this environment variable exists, then its value is used as the
+default directory where the
+.BR mg (1)
+collection files are.  If this variable does not exist, then the
+directory \*(lq\fB.\fP\*(rq is used by default.  The command line
+option
+.BI \-d " directory"
+overrides the directory in
+.BR MGDATA .
+.SH FILES
+.TP 25
+.B *.text
+Compressed documents.
+.TP
+.B *.text.idx
+Index into the compressed documents.
+.TP
+.B *.text.dict
+Compressed compression dictionary.
+.TP
+.B *.text.dict.aux
+Auxiliary compression dictionary.
+.TP
+.B *.text.dict.fast
+Fast loading compression dictionary.
+.TP
+.B *.invf.paragraph
+Paragraph counts for documents.
+.SH "SEE ALSO"
+.na
+.BR mg (1),
+.BR mg_compression_dict (1),
+.BR mg_fast_comp_dict (1),
+.BR mg_get (1),
+.BR mg_passes (1).
Index: /main/tags/2.25/gsdl/packages/mg/man/man1/mg_fast_comp_dict.1
===================================================================
--- /main/tags/2.25/gsdl/packages/mg/man/man1/mg_fast_comp_dict.1	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/mg/man/man1/mg_fast_comp_dict.1	(revision 21064)
@@ -0,0 +1,86 @@
+.\"------------------------------------------------------------
+.\" Id - set Rv,revision, and Dt, Date using rcs-Id tag.
+.de Id
+.ds Rv \\$3
+.ds Dt \\$4
+..
+.Id $Id$
+.\"------------------------------------------------------------
+.TH mg_fast_comp_dict 1 \*(Dt CITRI
+.SH NAME
+mg_fast_comp_dict \- build a fast loading compression dictionary
+.SH SYNOPSIS
+.B mg_fast_comp_dict
+[
+.B \-h
+]
+[
+.BI \-d " directory"
+]
+.BI \-f " name"
+.SH DESCRIPTION
+.B mg_fast_comp_dict
+builds a fast-loading compression dictionary from the standard
+compression dictionary.  The new dictionary has the property that
+.BR mgquery (1)
+can load it in very quickly, making the startup time for
+.BR mgquery (1)
+much shorter.  The new dictionary is larger on disk than the original,
+but they are no different when it comes to memory usage.
+.SH OPTIONS
+Options may appear in any order.
+.TP "\w'\fB\-d\fP \fIdirectory\fP'u+2n"
+.B \-h
+This displays a usage line on
+.IR stderr .
+.TP
+.BI \-d " directory"
+This specifies the directory where the document collection can be found.
+.TP
+.BI \-f " name"
+This specifies the base name of the document collection.
+.SH ENVIRONMENT
+.TP "\w'\fBMGDATA\fP'u+2n"
+.SB MGDATA
+If this environment variable exists, then its value is used as the
+default directory where the
+.BR mg (1)
+collection files are.  If this variable does not exist, then the
+directory \*(lq\fB.\fP\*(rq is used by default.  The command line
+option
+.BI \-d " directory"
+overrides the directory in
+.BR MGDATA .
+.SH FILES
+.TP 20
+.B *.text.dict
+Compression dictionary.
+.TP
+.B *.text.dict.fast
+Fast loading compression dictionary.
+.TP
+.B *.text.dict.aux
+Auxiliary compression dictionary.
+.SH "SEE ALSO"
+.na
+.BR mg (1),
+.BR mg_compression_dict (1),
+.BR mg_get (1),
+.BR mg_invf_dict (1),
+.BR mg_invf_dump (1),
+.BR mg_invf_rebuild (1),
+.BR mg_passes (1),
+.BR mg_perf_hash_build (1),
+.BR mg_text_estimate (1),
+.BR mg_weights_build (1),
+.BR mgbilevel (1),
+.BR mgbuild (1),
+.BR mgdictlist (1),
+.BR mgfelics (1),
+.BR mgquery (1),
+.BR mgstat (1),
+.BR mgtic (1),
+.BR mgticbuild (1),
+.BR mgticdump (1),
+.BR mgticprune (1),
+.BR mgticstat (1).
Index: /main/tags/2.25/gsdl/packages/mg/man/man1/mg_get.1
===================================================================
--- /main/tags/2.25/gsdl/packages/mg/man/man1/mg_get.1	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/mg/man/man1/mg_get.1	(revision 21064)
@@ -0,0 +1,154 @@
+.TH mg_get 1 "31 January 1994"
+.SH NAME
+mg_get \- output source texts for processing
+.SH SYNOPSIS
+ 
+.B mg_get
+.I collection-name
+.RB [ \-init | \-i | \-text\fP|\fB\-t\fP|\fB\-cleanup\fP|\fB\-c\fP]
+.SH DESCRIPTION
+.LP
+This program is the default one used by mgbuild to generate the source text for the MG system. Any program may be used to generate the source text for mgbuild as long as it confirms to the interface specified here. 
+.SH OPTIONS
+.LP
+The
+.I collection\-name
+must appear before any other option. Only the first option has any significance. If no option is specified
+.B \-text
+is assumed.
+.RS
+.TP
+.BR \-init " and " \-i
+The program is called once with this flag at the start of building a collection.
+.TP
+.BR \-text " and " \-t
+The program is called with this flag multiple times during the building of a collection. The program outputs (on stdout) the text of the collection. \*(lq\fBDocuments\fP\*(rq within the collection are separated with by ctrl-B's (ASCII code 2). \*(lq\fBParagraphs\fP\*(rq within the collection are separated with ctrl-C's (ASCII code 3). A collection need not contain paragraphs unless a level 3 inverted file is being generated (see 
+.B mgbuild 
+and 
+.BR mg_passes ). 
+.TP
+.BR \-cleanup " and " \-c
+The program is called once with this flag at the completion of building a collection.
+.SH ENVIRONMENT
+.TP
+.SB MGDATA
+If this environment variable exists then its value is used a the default 
+directory where the mg collection files are. If this variable does not exist
+then the directory \*(lq\fB.\fP\*(rq is used by default. The command line 
+option 
+.BI \-d " directory"
+overrides the directory in 
+.BR MGDATA .
+.TP
+.SB MG_GETRC
+This environment variable specifies where the file containing the users 
+mg source configurations is. If not set, mg_get uses a default of 
+.B \*\~/.mg_getrc.
+
+This file contains TAB delimited lines of the form
+.RS 
+.RS 
+.I CollectionName
+.I CollectionType
+.I files or directory
+.RE
+
+.I CollectionName
+is the name of the collection supplied to mg_get.
+
+.I CollectionType
+specifies how mg_get should process the
+named files and directories and are descibed below.
+
+.I files or directory
+is either a list of files separted by blanks or a single directory.
+Some of the
+.I CollectionTypes
+deal with files and others with just a single directory.
+Any files used ending with .gz or .Z are decompressed with gzip before
+processing. References to '~' expands to the users HOME directory.
+
+.I CollectionType
+is one of
+.RS
+.TP
+.BR PARA
+For text based documents. The list of files specified are treated as
+a series of paragraphs separated by blank lines. Each paragraph becomes
+a seperate document on the indexed collection.
+.TP
+.BR MAIL
+for mail files. The list of files specified are treated as UNIX mail
+files separated by lines starting with 'From'. Each mail message becomes
+a seperate document on the indexed collection. As a extra feature any
+embedded tarmail encoded contents (enclosed by a 'xbtoa Begin' and 'xbtoa End'
+pair are removed.
+.TP
+.BR DIR
+(and DIR2)
+For a single directory of files. Each file in the directory (and in any of
+it's subdirectories) are treated as a single document. With
+.I DIR
+the pathname of the file is prefixed to the contents of each file as an
+extra line while this is not done for
+.I DIR2
+collections.
+.TP
+.BR BIB
+for biblography files. The list of files specified are treated as
+a series of biblography files (eg BIBTEX or TROFF) separated by lines
+starting with '@'. Each reference  becomes a seperate document on the indexed
+collection.
+.TP
+.BR TXTIMG
+for integrated collections of text and images. The single directory should
+contain files that have the same prefix if they are related. For example,
+monaLisa.pgm might be a gray-level image, and monaLisa.txt would be a textual
+file describing the image. The suffixes recognised are:
+.BR   .txt
+for  ascii text
+.BR  .ptm
+for  scanned text stored as a bilevel image
+.BR  .pbm
+for a black and white image (typically a line drawing)
+.BR  .pgm
+for a gray-scale image
+.BR In addition, if no corresponding ascii text file is found for
+a .pbm or .pgm file, then one is created with suffix .tmp.txt,
+and it stores the name of the image file (in principle it could
+store the OCR of a .txt.pbm file). At present the .tmp.txt files
+are deleted by the '-cleanup' option.
+
+.SH "EXAMPLE"
+
+An example ~/.mg_getrc file might look like:
+   alice   PARA    /users/alice13a.txt.Z
+   mail95  MAIL    ~/MAIL/1995/*
+   doc     DIR     ~/documents
+   bibs    BIB     ~/etc/REFS/*.bib ~/etc/REFS/CC/*.bib
+   letters DIR     ~/LETTERS
+   davinci TXTIMG  ~/images/davinci
+
+.SH "SEE ALSO"
+.LP
+.BR mg_compression_dict (1),
+.BR mg_invf_dict (1),
+.BR mg_invf_dump (1),
+.BR mg_invf_rebuild (1),
+.BR mg_make_fast_dict (1),
+.BR mg_passes (1),
+.BR mg_perf_hash_build (1),
+.BR mg_text_estimate (1),
+.BR mg_weights_build (1),
+.BR mgbilevel (1),
+.BR mgbuild (1),
+.BR mgdictlist (1),
+.BR mgfelics (1),
+.BR mgquery (1),
+.BR mgstat (1),
+.BR mgtic (1),
+.BR mgticbuild (1),
+.BR mgticdump (1),
+.BR mgticprune (1),
+.BR mgticstat (1)
+
Index: /main/tags/2.25/gsdl/packages/mg/man/man1/mg_get_merge.1
===================================================================
--- /main/tags/2.25/gsdl/packages/mg/man/man1/mg_get_merge.1	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/mg/man/man1/mg_get_merge.1	(revision 21064)
@@ -0,0 +1,86 @@
+.\"------------------------------------------------------------
+.\" Id - set Rv,revision, and Dt, Date using rcs-Id tag.
+.de Id
+.ds Rv \\$3
+.ds Dt \\$4
+..
+.Id $Id$
+.\"------------------------------------------------------------
+.TH mg_get_merge 1 \*(Dt CITRI
+.SH NAME
+mg_get_merge \- output source texts for processing
+.SH SYNOPSIS
+.B mg_get_merge
+.I collection-name
+.if n .ti +9n
+[
+.BR \-init " |"
+.BR \-i " |"
+.BR \-text " |"
+.BR \-t " |"
+.BR \-cleanup " |"
+.B  \-c
+]
+.SH DESCRIPTION
+This program is the default one used by
+.BR mgmerge (1)
+to generate the source text for new documents to appended to
+an
+.BR mg (1)
+system database.
+Its function is exactly the same as
+.BR mg_get (1)
+except that it generates the 
+.I new 
+documents to be added to an
+.BR mg (1)
+system database that has already been built using
+.BR mgbuild(1).
+Any program may be used to generate the source
+text for
+.BR mgmerge (1),
+as long as it confirms to the interface specified
+here.
+.SH OPTIONS
+The
+.I collection-name
+must appear before any other option.  Only the first option has any
+significance.  If no option is specified,
+.B \-text
+is assumed.
+.TP "\w'\fB\-cleanup\fP and \fB\-c\fP'u+2n"
+.BR \-init " and " \-i
+The program is called once with this flag at the start of merging a
+collection.
+.TP
+.BR \-text " and " \-t
+The program is called with this flag multiple times during the
+merging of a collection.  The program outputs (on
+.IR stdout )
+the text of the collection.
+.I Documents
+within the collection are separated by ctrl-B's (ASCII code 2).
+.TP
+.BR \-cleanup " and " \-c
+The program is called once with this flag at the completion of
+merging a collection.
+.SH ENVIRONMENT
+.TP "\w'\fBMGDATA\fP'u+2n"
+.SB MGDATA
+If this environment variable exists, then its value is used as the
+default directory where the
+.BR mg (1)
+collection files are.  If this variable does not exist, then the
+directory \*(lq\fB.\fP\*(rq is used by default.  The command line
+option
+.BI \-d " directory"
+overrides the directory in
+.BR MGDATA .
+.SH "SEE ALSO"
+.na
+.BR mg (1),
+.BR mg_get (1),
+.BR mgbuild (1),
+.BR mgmerge (1),
+.BR mg_text_merge (1),
+.BR mg_invf_merge (1).
Index: /main/tags/2.25/gsdl/packages/mg/man/man1/mg_hilite_words.1
===================================================================
--- /main/tags/2.25/gsdl/packages/mg/man/man1/mg_hilite_words.1	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/mg/man/man1/mg_hilite_words.1	(revision 21064)
@@ -0,0 +1,95 @@
+.\"------------------------------------------------------------
+.\" Id - set Rv,revision, and Dt, Date using rcs-Id tag.
+.de Id
+.ds Rv \\$3
+.ds Dt \\$4
+..
+.Id $Id$
+.\"------------------------------------------------------------
+.TH mg_hilite_words 1 \*(Dt CITRI
+.SH NAME
+mg_hilite_words \- display text and highlight particular words which it contains
+.SH SYNOPSIS
+.B mg_hilite_words
+.if n .ti +9n
+[
+.B --stem_method [0-3]
+]
+.if n .ti +9n
+[
+.B --stemmer [english|lovin|french|simplefrench]
+]
+.if n .ti +9n
+[
+.B --style [bold|underline|italic|emphasis|strong]
+]
+.if n .ti +9n
+[
+.B --pager [less|more|html|???]
+]
+.if n .ti +9n
+.I list-of-words-to-highlight
+
+.SH DESCRIPTION
+.B mg_hilite_words
+reads text from stdin and outputs it into a pager such as
+less. It's command arguments include a list of stemmed words
+which if extracted from the text will be highlighted on the output
+using a highlighting style.
+
+It has been extended to output the highlighted text using html
+straight to stdout.
+
+.SH OPTIONS
+Options may appear in any order, but the
+.IR list-of-words-to-highlight ,
+must be last.
+.TP
+.B --stem_method [0-3]
+This option allows one to set the stemming method for the extraction of
+the words from the incoming text.
+This should match the way the inverted file index was created.
+The default is 3, which is fold and stem.
+.TP
+.B --stemmer [english|lovin|french|simplefrench]
+This option allows you to select the stemmer to use.  The
+default is the English stemmer.
+.TP
+.B --style [bold|underline|italic|emphasis|strong]
+This option sets the highlighting style.
+.IR Bold 
+and 
+.IR underline
+are utilised by the pager or for html output.
+.IR Italic,
+.IR emphasis,
+and
+.IR strong
+can only be used for html output.
+.TP
+.B --pager [less|more|html|???]
+One can use the standard 
+.IR less
+or
+.IR more
+pages for displaying the highlighted text.
+Or one can generate highlighted html using the paging setting of
+.IR html.
+One can also specify a custom pager of their own choosing (i.e. ???).
+.TP
+.B list-of-words-to-highlight
+Each word is taken as a command line argument.
+Each word should already be stemmed and folded according to
+the stem option.
+.SH USAGE
+This program was written primarily to be called by 
+.IR mgquery(1)
+.
+When the user selects the mode of "hilite" then this program
+is called for displaying the query-result documents instead of
+just the pager.
+.SH "SEE ALSO"
+.na
+.BR mgquery (1).
+
+
Index: /main/tags/2.25/gsdl/packages/mg/man/man1/mg_invf_dict.1
===================================================================
--- /main/tags/2.25/gsdl/packages/mg/man/man1/mg_invf_dict.1	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/mg/man/man1/mg_invf_dict.1	(revision 21064)
@@ -0,0 +1,104 @@
+.\"------------------------------------------------------------
+.\" Id - set Rv,revision, and Dt, Date using rcs-Id tag.
+.de Id
+.ds Rv \\$3
+.ds Dt \\$4
+..
+.Id $Id$
+.\"------------------------------------------------------------
+.TH mg_invf_dict 1 \*(Dt CITRI
+.SH NAME
+mg_invf_dict \- build an `on-disk' stemmed dictionary
+.SH SYNOPSIS
+.B mg_invf_dict
+[
+.B \-h
+]
+[
+.B \-F
+]
+[
+.BI \-b " num"
+]
+[
+.BI \-d " directory"
+]
+.if n .ti +9n
+.BI \-f " name"
+.SH DESCRIPTION
+.B mg_invf_dict
+builds an `on-disk' stemmed dictionary from the
+compressed stemmed dictionary that the
+.BR mgquery (1)
+program can access.  Each entry in the dictionary contains the disk
+pointer to the associated inverted file entry, and various other pieces
+of information about the stemmed word.
+.SH OPTIONS
+Options may appear in any order.
+.TP "\w'\fB\-d\fP \fIdirectory\fP'u+2n"
+.B \-h
+This displays a usage line on
+.IR stderr .
+.TP
+.BI \-b " num"
+The dictionary is stored in blocks on disk; this option is used to set
+the block size.  The default is 4-KB blocks.
+.TP
+.B \-F
+This option causes the disk blocks to be aligned on the appropriate
+boundaries.  For example, if 4-KB blocks are used, they will be aligned
+in the file on 4-KB boundaries.
+.TP
+.BI \-d " directory"
+This specifies the directory where the document collection can be found.
+.TP
+.BI \-f " name"
+This specifies the base name of the document collection.
+.SH ENVIRONMENT
+.TP "\w'\fBMGDATA\fP'u+2n"
+.SB MGDATA
+If this environment variable exists, then its value is used as the
+default directory where the
+.BR mg (1)
+collection files are.  If this variable does not exist, then the
+directory \*(lq\fB.\fP\*(rq is used by default.  The command line
+option
+.BI \-d " directory"
+overrides the directory in
+.BR MGDATA .
+.SH FILES
+.TP 20
+.B *.invf
+Inverted file.
+.TP
+.B *.invf.dict.build
+Compressed stemmed dictionary.
+.TP
+.B *.invf.dict
+The `on-disk' stemmed dictionary.
+.TP
+.B *.invf.idx
+The index into the inverted file.
+.SH "SEE ALSO"
+.na
+.BR mg (1),
+.BR mg_compression_dict (1),
+.BR mg_fast_comp_dict (1),
+.BR mg_get (1),
+.BR mg_invf_dump (1),
+.BR mg_invf_rebuild (1),
+.BR mg_passes (1),
+.BR mg_perf_hash_build (1),
+.BR mg_text_estimate (1),
+.BR mg_weights_build (1),
+.BR mgbilevel (1),
+.BR mgbuild (1),
+.BR mgdictlist (1),
+.BR mgfelics (1),
+.BR mgquery (1),
+.BR mgstat (1),
+.BR mgtic (1),
+.BR mgticbuild (1),
+.BR mgticdump (1),
+.BR mgticprune (1),
+.BR mgticstat (1).
Index: /main/tags/2.25/gsdl/packages/mg/man/man1/mg_invf_dump.1
===================================================================
--- /main/tags/2.25/gsdl/packages/mg/man/man1/mg_invf_dump.1	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/mg/man/man1/mg_invf_dump.1	(revision 21064)
@@ -0,0 +1,142 @@
+.\"------------------------------------------------------------
+.\" Id - set Rv,revision, and Dt, Date using rcs-Id tag.
+.de Id
+.ds Rv \\$3
+.ds Dt \\$4
+..
+.Id $Id$
+.\"------------------------------------------------------------
+.TH mg_invf_dump 1 \*(Dt CITRI
+.SH NAME
+mg_invf_dump \- Dump out an inverted file in ASCII
+.SH SYNOPSIS
+.B mg_invf_dump
+[
+.B \-h
+]
+[
+.B \-b
+]
+[
+.B \-w
+]
+[
+.B \-t
+]
+[
+.BI \-d " directory"
+]
+.BI \-f " name"
+.SH DESCRIPTION
+This program dumps out an inverted file produced by the
+.BR mg (1)
+system as ASCII numbers.  This program could be used in conjunction
+with
+.BR mgdictlist (1)
+to write simple shell programs that work with the inverted files.  The
+output from the program looks something like this:
+.LP
+.RS
+.ft 3
+.nf
+6 337
+1
+ 1 1
+1
+ 5 1
+1
+ 2 1
+1
+ 1 1
+4
+ 1 3
+ 2 7
+ 3 2
+ 5 2
+1
+ 1 1
+ . . .
+.fi
+.ft
+.RE
+The first number (6) is the number of documents in the collection.  It
+is followed by the number of different terms in the collection.  For
+each term, the number of different documents it occurs in follows. The
+document numbers that the term occurs in are listed next.  If
+.B \-w
+is specified, then the number of times the term occurred in the
+document is printed alongside the document number.
+If
+.B \-t
+is specified, the term itself is also displayed in quotes.
+.SH OPTIONS
+Options may appear in any order.
+.TP "\w'\fB\-d\fP \fIdirectory\fP'u+2n"
+.B \-h
+This displays a usage line on
+.IR stderr .
+.TP
+.B \-b
+This option will cause the output from the program to be in fixed-size
+binary numbers, rather than in ASCII.
+.TP
+.B \-w
+If the inverted file is a level-2 or level-3 inverted file, this causes
+the word counts per document to be output.
+.TP
+.B \-t
+This option causes each term to be displayed along with the number of
+documents it appears in. The term is printed in quotes,
+as in "the".
+.TP
+.BI \-d " directory"
+This specifies the directory where the document collection can be found.
+.TP
+.BI \-f " name"
+This specifies the base name of the document collection.
+.SH ENVIRONMENT
+.TP "\w'\fBMGDATA\fP'u+2n"
+.SB MGDATA
+If this environment variable exists, then its value is used as the
+default directory where the
+.BR mg (1)
+collection files are.  If this variable does not exist, then the
+directory \*(lq\fB.\fP\*(rq is used by default.  The command line
+option
+.BI \-d " directory"
+overrides the directory in
+.BR MGDATA .
+.SH FILES
+.TP 20
+.B *.invf.dict
+The compressed stemmed dictionary.
+.TP
+.B *.invf.ORG
+The original inverted file saved by
+.BR mg_invf_rebuild .
+.TP
+.B *.invf
+The inverted file.
+.SH "SEE ALSO"
+.na
+.BR mg (1),
+.BR mg_compression_dict (1),
+.BR mg_fast_comp_dict (1),
+.BR mg_get (1),
+.BR mg_invf_dict (1),
+.BR mg_invf_rebuild (1),
+.BR mg_passes (1),
+.BR mg_perf_hash_build (1),
+.BR mg_text_estimate (1),
+.BR mg_weights_build (1),
+.BR mgbilevel (1),
+.BR mgbuild (1),
+.BR mgdictlist (1),
+.BR mgfelics (1),
+.BR mgquery (1),
+.BR mgstat (1),
+.BR mgtic (1),
+.BR mgticbuild (1),
+.BR mgticdump (1),
+.BR mgticprune (1),
+.BR mgticstat (1).
Index: /main/tags/2.25/gsdl/packages/mg/man/man1/mg_invf_merge.1
===================================================================
--- /main/tags/2.25/gsdl/packages/mg/man/man1/mg_invf_merge.1	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/mg/man/man1/mg_invf_merge.1	(revision 21064)
@@ -0,0 +1,112 @@
+.\"------------------------------------------------------------
+.\" Id - set Rv,revision, and Dt, Date using rcs-Id tag.
+.de Id
+.ds Rv \\$3
+.ds Dt \\$4
+..
+.Id $Id$
+.\"------------------------------------------------------------
+.TH mg_invf_merge 1 \*(Dt CITRI
+.SH NAME
+mg_invf_merge \- Merge two inverted files and stemmed dictionaries
+.SH SYNOPSIS
+.B mg_invf_merge
+[
+.B \-h
+]
+[
+.B \-s
+]
+[
+.B \-w
+]
+[
+.BI \-d " directory"
+]
+.BI \-f " name"
+.SH DESCRIPTION
+This program takes two
+.BR mg (1)
+database compressed text files and appends the second to
+the first.
+It is part of the
+.BR mgmerge (1)
+addition to the
+.BR mg (1)
+package.
+.SH OPTIONS
+Options may appear in any order.
+.TP "\w'\fB\-d\fP \fIdirectory\fP'u+2n"
+.B \-h
+This displays a usage line on
+.IR stderr .
+.TP
+.B \-s
+This option will cause a slow merge to be performed on the inverted files,
+where each inverted file entry is decoded and recoded.
+The default is a fast merge. Accumulated fast merges slowly degrade
+compression performance on the resulting inverted file so
+a periodic slow merge is recommended.
+.TP
+.B \-w
+By default the database .weights file is updated with
+new weights for the new documents in
+.B mg_text_merge.
+The
+.B -w
+option turns this step off.
+.TP
+.BI \-d " directory"
+This specifies the directory where the document collection can be found.
+.TP
+.BI \-f " name"
+This specifies the base name of the document collection.
+.SH ENVIRONMENT
+.TP "\w'\fBMGDATA\fP'u+2n"
+.SB MGDATA
+If this environment variable exists, then its value is used as the
+default directory where the
+.BR mg (1)
+collection files are.  If this variable does not exist, then the
+directory \*(lq\fB.\fP\*(rq is used by default.  The command line
+option
+.BI \-d " directory"
+overrides the directory in
+.BR MGDATA .
+.SH FILES
+.TP 20
+.B *.old.invf.dict
+The old compressed stemmed dictionary.
+.TP
+.B *.new.invf.dict
+The new compressed stemmed dictionary.
+.TP
+.B *.invf.dict
+The resulting merged compressed stemmed dictionary.
+.TP
+.B *.old.invf.ORG
+The original inverted file saved by
+.BR mg_invf_rebuild .
+.TP
+.B *.old.invf
+The old inverted file.
+.TP
+.B *.new.invf
+The new inverted file.
+.TP
+.B *.invf
+The resulting merged inverted file.
+.TP
+.B *.weight
+The exact weights file.
+.TP
+.SH "SEE ALSO"
+.na
+.BR mg (1),
+.BR mgmerge (1),
+.BR mg_get_merge (1),
+.BR mg_text_merge (1),
+.BR mg_invf_rebuild (1),
+.BR mg_invf_dict (1),
+.BR mg_weights_build (1),
+.BR mgquery (1).
Index: /main/tags/2.25/gsdl/packages/mg/man/man1/mg_invf_rebuild.1
===================================================================
--- /main/tags/2.25/gsdl/packages/mg/man/man1/mg_invf_rebuild.1	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/mg/man/man1/mg_invf_rebuild.1	(revision 21064)
@@ -0,0 +1,156 @@
+.\"------------------------------------------------------------
+.\" Id - set Rv,revision, and Dt, Date using rcs-Id tag.
+.de Id
+.ds Rv \\$3
+.ds Dt \\$4
+..
+.Id $Id$
+.\"------------------------------------------------------------
+.TH mg_invf_rebuild 1 \*(Dt CITRI
+.SH NAME
+mg_invf_rebuild \- Rebuild an mg inverted file with or without skips.
+.SH SYNOPSIS
+.B mg_invf_rebuild
+.RB [ \-h ]
+.if n .ti +9n
+[
+.BR \-0 " |"
+.B \-1
+[
+.BI \-k " num"
+] |
+.B \-2
+[
+.BI \-s " num"
+]
+[
+.BI \-m " num"
+]
+]
+.if n .ti +9n
+[
+.BI \-d " directory"
+]
+.BI \-f " name"
+.SH DESCRIPTION
+.B mg_invf_rebuild
+builds a new inverted file, with or without skipping, from an old
+inverted file.  This file uses
+.I *.invf.ORG
+and
+.I *.invf.idx.ORG
+as the
+source from which it builds
+.I *.invf
+and
+.IR *.invf.idx .
+If
+.I *.invf.ORG
+or
+.I *.invf.idx.ORG
+do not exist, the program renames
+.I *.invf
+or
+.I *.invf.idx
+to
+.I *.invf.ORG
+or
+.I *.invf.idx.ORG
+as appropriate.  The old inverted file may contain skipping.  This
+means that it is possible to delete the
+.I *.ORG
+files
+after the new inverted file is built.
+.SH OPTIONS
+Options may appear in any order.
+.TP "\w'\fB\-m\fP \fInum\fP'u+2n"
+.B \-h
+This displays a usage line on
+.IR stderr .
+.TP
+.B \-0
+This generates a non-skipped inverted file.  This option is normally
+only needed if the
+.I *.ORG
+files have been deleted.
+.TP
+.B \-1
+This generates a skipped inverted file.  The
+.BI \-k " num"
+argument specifies the number of pointers hopped over with each skip.
+.TP
+.B \-2
+This option generates a skipped inverted file.  The skipped inverted
+file is built so that it is `optimal' for ranking using a specific
+number of accumulators.  Each term in the inverted file has a
+different skip length.  The arguments
+.BR \-s " and " \-m
+control the sizes of the skips.
+.TP
+.BI \-k " num"
+This specifies the number of pointers that should be hopped over with
+each skip.  This option is only valid if
+.B \-1
+is specified.
+.TP
+.BI \-m " num"
+This specifies the intended number of accumulators that will be used
+when ranking queries are done on the collection.
+.TP
+.BI \-s " num"
+This specifies the minimum size for skips.  If the calculation of the
+optimal skip size results in a number smaller than
+.IR num ,
+the skip size is set to
+.IR num .
+.SH ENVIRONMENT
+.TP "\w'\fBMGDATA\fP'u+2n"
+.SB MGDATA
+If this environment variable exists, then its value is used as the
+default directory where the
+.BR mg (1)
+collection files are.  If this variable does not exist, then the
+directory \*(lq\fB.\fP\*(rq is used by default.  The command line
+option
+.BI \-d " directory"
+overrides the directory in
+.BR MGDATA .
+.SH FILES
+.TP 20
+.B *.invf
+Inverted file.
+.TP
+.B *.invf.ORG
+Original inverted file.
+.TP
+.B *.invf.idx
+The index into the inverted file.
+.TP
+.B *.invf.idx.ORG
+The original index into the inverted file.
+.TP
+.B *.invf.dict.build
+Compressed stemmed dictionary.
+.SH "SEE ALSO"
+.na
+.BR mg (1),
+.BR mg_compression_dict (1),
+.BR mg_fast_comp_dict (1),
+.BR mg_get (1),
+.BR mg_invf_dict (1),
+.BR mg_invf_dump (1),
+.BR mg_passes (1),
+.BR mg_perf_hash_build (1),
+.BR mg_text_estimate (1),
+.BR mg_weights_build (1),
+.BR mgbilevel (1),
+.BR mgbuild (1),
+.BR mgdictlist (1),
+.BR mgfelics (1),
+.BR mgquery (1),
+.BR mgstat (1),
+.BR mgtic (1),
+.BR mgticbuild (1),
+.BR mgticdump (1),
+.BR mgticprune (1),
+.BR mgticstat (1).
Index: /main/tags/2.25/gsdl/packages/mg/man/man1/mg_passes.1
===================================================================
--- /main/tags/2.25/gsdl/packages/mg/man/man1/mg_passes.1	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/mg/man/man1/mg_passes.1	(revision 21064)
@@ -0,0 +1,441 @@
+.\"------------------------------------------------------------
+.\" Id - set Rv,revision, and Dt, Date using rcs-Id tag.
+.de Id
+.ds Rv \\$3
+.ds Dt \\$4
+..
+.Id $Id$
+.\"------------------------------------------------------------
+.TH mg_passes 1 \*(Dt CITRI
+.SH NAME
+mg_passes \- builds mg databases
+.SH SYNOPSIS
+.B mg_passes
+[
+.B \-h
+]
+[
+.B \-G
+]
+[
+.B \-S
+]
+[
+.B \-D
+]
+[
+.B \-W
+]
+.if n .ti +9n
+[
+.BR \-1 " |"
+.BR \-2 " |"
+.B  \-3
+]
+[
+.BI \-C " compstatpoint"
+]
+.if n .ti +9n
+[
+.BI \-n " tracename"
+]
+.if t .ti +.5i
+[
+.BI \-b " bufsize"
+]
+[
+.BI \-m " memlimit"
+]
+.if n .ti +9n
+[
+.BI \-c " numchunks"
+]
+[
+.BI \-a " stemmer"
+]
+[
+.BI \-s " stemmethod"
+]
+[
+.BI \-t " tracepos"
+]
+.if n .ti +9n
+[
+.B \-T1
+]
+[
+.B \-T2
+]
+.if t .ti +.5i
+[
+.B \-I1
+]
+[
+.B \-I2
+]
+.if n .ti +9n
+[
+.BI \-d " directory"
+]
+.BI \-f " name"
+[
+.I filename(s)
+]
+.SH DESCRIPTION
+.B mg_passes
+is the program that does most of the work when building
+.BR mg (1)
+database systems.  The input documents can come from either
+.I stdin
+or from a list of files on the command line.  Individual documents
+must be separated with control-B characters.  In general,
+.B mg_passes
+must be run twice to build a database, first with the
+.B \-T1
+and
+.B \-I1
+options, and second with the
+.B \-T2
+and
+.B \-I2
+options.  Several other programs must be run in order to get an
+.BR mg (1)
+database that is ready for the
+.BR mgquery (1)
+program.  The
+.SB EXAMPLE
+section below gives an example of how to build a complete
+.BR mg (1)
+database.
+.SH OPTIONS
+Options may appear in any order, but the
+.IR filename(s) ,
+if specified, must be last.
+.TP "\w'\fB\-C\fP \fIcompstatpoint\fP'u+2n"
+.B \-h
+This displays a usage line on
+.IR stderr .
+.TP
+.B \-G
+Treat SGML tags as non-words when building the inverted file.  An SGML
+tag is anything between angle brackets, i.e., `<' and `>'.
+.TP
+.B \-S
+This option causes a special pass to be executed.  It is up to a user
+to modify
+.I mg.special.c
+in the source code to do something with the documents it is given.
+.TP
+.B \-D
+If
+.B mg_passes
+fails, then print the document that caused the failure to the trace
+file if tracing is active, or to
+.I stderr
+if it is not.
+.TP
+.B \-W
+This option enables the generation of the weights file when
+.B \-I2
+is specified.  It causes
+.B \-I2
+to use a little more memory and CPU.
+.TP
+.B \-1
+Produce a level-1 inverted file.  This option is only useful when
+specified with
+.BR "\-I1 ".
+A level-1 inverted file makes it possible for
+.BR mgquery (1)
+to do Boolean queries.  Ranked queries can still be done,
+although the quality of the ranking is abysmal.
+.TP
+.B \-2
+Produce a level-2 inverted file.  This option is only useful when
+specified with
+.BR "\-I1 ".
+This is the default when neither
+.BR \-1 ", " "\-2 " "or " \-3
+is specified.
+A level-2 inverted file makes it possible for
+.BR mgquery (1)
+to do Boolean queries and cosine-ranked queries.
+.TP
+.B \-3
+Produce a level-3 inverted file.  This option is only useful when
+specified with
+.BR "\-I1 ".
+This has been implemented to enable paragraph-level inversion.
+Paragraphs are delimited by control-C characters in the source text.
+.TP
+.BI \-C " compstatpoint"
+This option causes statistics on the compression performance to be
+output to a file called
+.IR *.compression.stats .
+.I compstatpoint
+specifies the interval between outputting each line of statistics.  The
+units of
+.I compstatpoint
+are kilobytes of source text.  E.g., if
+.I compstatpoint
+is 10, then a line is output to the file every 10 KB of input
+source.  Each line of the file consists of 4 numbers The first number
+is the amount of input text, in bytes, processed so far.  The second
+number is the amount of input text, in bytes, processed since the
+last line was output to the file.  The third number is the number of
+output bytes generated since the last line was output to the file, and
+the fourth number is the compression achieved since the last line was
+output, i.e., the third number divided by the second number.
+.TP
+.BI \-n " tracename"
+This specifies the filename to use for the trace log, if tracing is
+enabled using the
+.B \-t
+option.  If
+.BI \-n " tracename"
+is not given and tracing is enabled, a default trace filename will be
+used.
+.TP
+.BI \-s " stemmethod"
+This specifies the method to use to \*(lqstem\*(rq the words in the
+inverted file dictionary.  This is a bit mask specifying the
+operations to do on words as they are parsed out of the text, where
+bit number 0 is the low-order (rightmost) bit.  Bit 0 does case
+folding, and bit 1 does simple stemming, so the value 3 for
+.I stemmethod
+does both case folding and stemming.
+.TP
+.BI \-a " stemmer"
+This specifies the stemmer to use when stemming words.  This
+is a description of the language the stemmer is intended for
+or a description of the stemmer.  Valid options include:
+english, lovin, french, and simplefrench.
+.TP
+.BI \-b " bufsize"
+Specify the size of the document buffer in kilobytes.  If any document
+is larger than
+.IR bufsize ,
+the program will abort with an error message.  This should probably be
+replaced with some system which automatically increases the buffer
+size as required.  The default size is 3072 KB (3 MB).
+.TP
+.BI \-m " memlimit"
+Maximum amount of memory to use for the pass-2 file inversion in
+megabytes.  This option is only useful when used in conjunction with
+the option
+.BR \-I1 .
+The larger this value, the faster the pass-2 inversion will proceed.
+The default value is 5 MB.
+.TP
+.BI \-c " numchunks"
+The maximum number of inversion chunks to write to disk.  Each chunk
+will be approximately as large as
+.IR memlimit .
+This option is only useful when used in conjunction with the option
+.BR \-I2 .
+The larger this value, the faster the pass-2 inversion will proceed.
+The default value is 5 MB.
+.TP
+.BI \-t " tracepos"
+This option activates tracing.  A line will be generated in the
+trace file for every
+.I tracepos
+input bytes processed.  The default name for the trace file can be
+overridden using the
+.BI \-n " tracename"
+option.
+.TP
+.B \-T1
+Generate the
+.I *.text.stats
+file.
+.TP
+.B \-T2
+Generate the
+.IR *.text ,
+.IR *.text.idx ,
+and possibly the
+.I *.text.dict.aux
+files.  Using this option requires that the
+.I *.text.dict
+file be present.
+.TP
+.B \-I1
+Generate the
+.IR *.invf.dict ,
+.IR *.invf.chunk ,
+and
+.I *.invf.chunk.trans
+files.
+.TP
+.B \-I2
+Generate the
+.I *.invf
+and
+.I *.invf.idx
+files.  Using this option requires
+that the
+.IR *.invf.dict.hash ,
+.IR *.invf.chunk ,
+and
+.I *.invf.chunk.trans
+files
+be present.  The
+.I *.invf.dict.hash
+file is generated by
+.BR mg_perf_hash_build (1)
+from the
+.I *.invf.dict.build
+file.  If the
+.B \-W
+option is specified, the
+.I *.weight
+file will also be generated.
+.TP
+.BI \-d " directory"
+This specifies the directory where the document collection is to be
+written.
+.TP
+.BI \-f " name"
+This specifies the base name of the document collection that will be
+created.
+.TP
+.I filename(s)
+This specifies the source text. If this is not specified, then the
+program expects the source text from
+.IR stdin .
+.SH EXAMPLE
+What follows is a UNIX
+.BR csh (1)
+script as an example of how to build an
+.BR mg (1)
+document collection.
+.LP
+.nf
+.DT
+.ft B
+.I #! /bin/csh
+.I
+# The first argument on the command line specifies the
+.I
+#   source of the text
+set source = ($1)
+.PP
+.I
+# The second argument is the name of the collection
+set text = ($2)
+.PP
+.I
+# Create *.text.stats,  *.invf.dict.build,
+.I
+#   *.invf.chunk and *.invf.chunks.trans
+${source} | mg_passes -T1 -I1 -m 1 -t 1 -f ${text}
+.PP
+.I
+# Create *.text.dict
+mg_compression_dict -f ${text}
+.PP
+.I
+# Create *.invf.dict.hash
+mg_perf_hash_build -f ${text}
+.PP
+.I
+# Create *.text,  *.text.idx,
+.I
+#   *.invf and *.invf.idx
+${source} | mg_passes -T2 -I2 -c 2 -t 1 -f ${text}
+.PP
+.I
+# Create *.text.idx.wgt and *.weight.approx
+mg_weights_build -f ${text} -b 8
+.PP
+.I
+# Create *.invf.dict
+mg_invf_dict -f ${text} -b 4096
+.PP
+.I
+# Create *.text.dict
+mg_fast_comp_dict -f ${text}
+.ft R
+.fi
+.SH ENVIRONMENT
+.TP "\w'\fBMGDATA\fP'u+2n"
+.SB MGDATA
+If this environment variable exists, then its value is used as the
+default directory where the
+.BR mg (1)
+collection files are.  If this variable does not exist, then the
+directory \*(lq\fB.\fP\*(rq is used by default.  The command line
+option
+.BI \-d " directory"
+overrides the directory in
+.BR MGDATA .
+.SH FILES
+.TP 20
+.B *.invf
+Inverted file.
+.TP
+.B *.invf.chunk
+Inverted file chunk descriptor file.  When the inverted file is
+created it is created in chunks that use no more than a set amount of
+memory.  This file describes those chunks.
+.TP
+.B *.invf.chunk.trans
+Word-occurrence-order to lexical-order translation file.  The
+.B *.invf.chunk
+file is written in word-occurrence order but is required by
+.B \-I2
+to be in lexical order.
+.TP
+.B *.invf.dict.build
+Compressed stemmed dictionary.
+.TP
+.B *.invf.dict.hash
+Data for an order-preserving perfect hash function.
+.TP
+.B *.invf.idx
+The index into the inverted file.
+.TP
+.B *.weight
+The exact weights file.
+.TP
+.B *.text
+Compressed documents.
+.TP
+.B *.text.stats
+Statistics about the text.
+.TP
+.B *.text.dict
+Compressed compression dictionary.
+.TP
+.B *.text.idx
+Index into the compressed documents.
+.TP
+.B *.trace
+The default trace file.
+.TP
+.B *.compression.stats
+Statistics about the compression of the text.
+.SH "SEE ALSO"
+.na
+.BR mg (1),
+.BR mg_compression_dict (1),
+.BR mg_fast_comp_dict (1),
+.BR mg_get (1),
+.BR mg_invf_dict (1),
+.BR mg_invf_dump (1),
+.BR mg_invf_rebuild (1),
+.BR mg_perf_hash_build (1),
+.BR mg_text_estimate (1),
+.BR mg_weights_build (1),
+.BR mgbilevel (1),
+.BR mgbuild (1),
+.BR mgdictlist (1),
+.BR mgfelics (1),
+.BR mgquery (1),
+.BR mgstat (1),
+.BR mgtic (1),
+.BR mgticbuild (1),
+.BR mgticdump (1),
+.BR mgticprune (1),
+.BR mgticstat (1).
Index: /main/tags/2.25/gsdl/packages/mg/man/man1/mg_perf_hash_build.1
===================================================================
--- /main/tags/2.25/gsdl/packages/mg/man/man1/mg_perf_hash_build.1	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/mg/man/man1/mg_perf_hash_build.1	(revision 21064)
@@ -0,0 +1,89 @@
+.\"------------------------------------------------------------
+.\" Id - set Rv,revision, and Dt, Date using rcs-Id tag.
+.de Id
+.ds Rv \\$3
+.ds Dt \\$4
+..
+.Id $Id$
+.\"------------------------------------------------------------
+.TH mg_perf_hash_build 1 \*(Dt CITRI
+.SH NAME
+mg_perf_hash_build \- generate an order-preserving hash function for the stemmed dictionary
+.SH SYNOPSIS
+.B mg_perf_hash_build
+[
+.B \-h
+]
+[
+.BI \-r " rndseed"
+]
+[
+.BI \-d  " directory"
+]
+.if n .ti +9n
+.BI \-f " name"
+.SH DESCRIPTION
+.B mg_perf_hash_build
+generates an order-preserving hashing function from the compressed
+stemmed dictionary and writes it out to disk.
+.BR mg_passes (1)
+will make use of the hash function when it builds the inverted file.
+.SH OPTIONS
+Options may appear in any order.
+.TP "\w'\fB\-d\fP \fIdirectory\fP'u+2n"
+.B \-h
+This displays a usage line on
+.IR stderr .
+.TP
+.BI \-r " rndseed"
+This specifies the random seed to be used in the generation of the
+hash function; it must be an integer.  If this is not specified, the
+current time will be used as the random seed.
+.TP
+.BI \-d " directory"
+This specifies the directory where the document collection can be found.
+.TP
+.BI \-f " name"
+This specifies the base name of the document collection.
+.SH ENVIRONMENT
+.TP "\w'\fBMGDATA\fP'u+2n"
+.SB MGDATA
+If this environment variable exists, then its value is used as the
+default directory where the
+.BR mg (1)
+collection files are.  If this variable does not exist, then the
+directory \*(lq\fB.\fP\*(rq is used by default.  The command line
+option
+.BI \-d " directory"
+overrides the directory in
+.BR MGDATA .
+.SH FILES
+.TP 20
+.B *.invf.dict
+Stemmed dictionary.
+.TP
+.B *.invf.dict.hash
+Data for a order-preserving perfect hash function.
+.SH "SEE ALSO"
+.na
+.BR mg (1),
+.BR mg_compression_dict (1),
+.BR mg_fast_comp_dict (1),
+.BR mg_get (1),
+.BR mg_invf_dict (1),
+.BR mg_invf_dump (1),
+.BR mg_invf_rebuild (1),
+.BR mg_passes (1),
+.BR mg_text_estimate (1),
+.BR mg_weights_build (1),
+.BR mgbilevel (1),
+.BR mgbuild (1),
+.BR mgdictlist (1),
+.BR mgfelics (1),
+.BR mgquery (1),
+.BR mgstat (1),
+.BR mgtic (1),
+.BR mgticbuild (1),
+.BR mgticdump (1),
+.BR mgticprune (1),
+.BR mgticstat (1).
Index: /main/tags/2.25/gsdl/packages/mg/man/man1/mg_stem_idx.1
===================================================================
--- /main/tags/2.25/gsdl/packages/mg/man/man1/mg_stem_idx.1	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/mg/man/man1/mg_stem_idx.1	(revision 21064)
@@ -0,0 +1,95 @@
+.\"------------------------------------------------------------
+.\" Id - set Rv,revision, and Dt, Date using rcs-Id tag.
+.de Id
+.ds Rv \\$3
+.ds Dt \\$4
+..
+.Id $Id$
+.\"------------------------------------------------------------
+.TH mg_stem_idx 1 \*(Dt CITRI
+.SH NAME
+mg_stem_idx \- builds a stem index file
+.SH SYNOPSIS
+.B mg_stem_idx
+[
+.B \-h
+]
+[
+.B \-F
+]
+[
+.BI \-b " num"
+]
+[
+.BI \-d " directory"
+]
+.if n .ti +9n
+.B \-s 1|2|3
+.BI \-f " name"
+.SH DESCRIPTION
+.B mg_stem_idx
+generates a stem index file for a collection that is to be built with
+stem indexes.  This program should be called three times: once for each
+.B -s
+parameter.  It uses the stemmed dictionary to create the stem index which
+contains pointers into the stemmed dictionary.
+.SH OPTIONS
+Options may appear in any order.
+.TP "\w'\fB\-d\fP \fIdirectory\fP'u+2n"
+.B \-h
+This displays a usage line on
+.IR stderr .
+.TP
+.BI \-b " num"
+The dictionary is stored in blocks on disk; this option is used to set
+the block size.  The default is 4-KB blocks.
+.TP
+.B \-F
+This option causes the disk blocks to be aligned on the appropriate
+boundaries.  For example, if 4-KB blocks are used, they will be aligned
+in the file on 4-KB boundaries.
+.TP
+.B -s 1|2|3
+The stem method to apply for the stem index.
+.br
+1 = casefolded and non-stemmed
+.br
+2 = non-casefolded and stemmed
+.br
+3 = casefolded and stemmed
+.TP
+.BI \-d " directory"
+This specifies the directory where the document collection can be found.
+.TP
+.BI \-f " name"
+This specifies the base name of the document collection.
+.SH ENVIRONMENT
+.TP "\w'\fBMGDATA\fP'u+2n"
+.SB MGDATA
+If this environment variable exists, then its value is used as the
+default directory where the
+.BR mg (1)
+collection files are.  If this variable does not exist, then the
+directory \*(lq\fB.\fP\*(rq is used by default.  The command line
+option
+.BI \-d " directory"
+overrides the directory in
+.BR MGDATA .
+.SH FILES
+.TP 25
+.B *.invf.dict.blocked
+Compressed stemmed dictionary.
+.TP
+.B *.invf.dict.blocked.1
+Stem index with stem index method 1.
+.TP
+.B *.invf.dict.blocked.2
+Stem index with stem index method 2.
+.TP
+.B *.invf.dict.blocked.3
+Stem index with stem index method 3.
+.SH "SEE ALSO"
+.na
+.BR mg (1),
+.BR mg_invf_dict (1),
+.BR mgstemidxlist (1).
Index: /main/tags/2.25/gsdl/packages/mg/man/man1/mg_text_estimate.1
===================================================================
--- /main/tags/2.25/gsdl/packages/mg/man/man1/mg_text_estimate.1	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/mg/man/man1/mg_text_estimate.1	(revision 21064)
@@ -0,0 +1,112 @@
+.\"------------------------------------------------------------
+.\" Id - set Rv,revision, and Dt, Date using rcs-Id tag.
+.de Id
+.ds Rv \\$3
+.ds Dt \\$4
+..
+.Id $Id$
+.\"------------------------------------------------------------
+.TH mg_text_estimate 1 \*(Dt CITRI
+.SH NAME
+mg_text_estimate \- Estimate the size of the compressed text based on the text statistics and a compression dictionary.
+.SH SYNOPSIS
+.B mg_text_estimate
+[
+.B \-h
+]
+[
+.BR \-H " |"
+.BR \-B " |"
+.BR \-D " |"
+.BR \-Y " |"
+.B \-M
+]
+.if n .ti +9n
+.I stats-dict
+.I compression-dict
+.SH DESCRIPTION
+This program estimates the size of the compressed text that would be
+generated if text with certain statistics were compressed with a
+particular dictionary.  This program has no real use in the
+.BR mg (1)
+system, except for experimenting with the
+.BR mg_compression_dict (1)
+program.
+.SH OPTIONS
+Options may appear in any order.
+.TP "\w'\fB\-m\fP'u+2n"
+.B \-h
+This displays a usage line on
+.IR stderr .
+.TP
+.B \-H
+This specifies that novel words will be coded character by character
+using Huffman codes.
+.TP
+.B \-B
+This specifies that the size of an auxiliary dictionary will be
+estimated.  Each novel word found will be placed at the end of the
+auxiliary dictionary.  Novel words will be coded in the compressed text
+using binary codes.  The binary code represents their occurrence
+position in the auxiliary dictionary.
+.TP
+.B \-D
+This specifies that the size of an auxiliary dictionary will be
+estimated.  Each novel word found will be placed at the end of the
+auxiliary dictionary.  Novel words will be coded in the compressed text
+using delta codes.  The delta code represents their occurrence position
+in the auxiliary dictionary.
+.TP
+.B \-Y
+This specifies that the size of an auxiliary dictionary will be
+estimated.  Each novel word found will be placed at the end of the
+auxiliary dictionary.  Novel words will be coded in the compressed text
+using a combination of gamma and binary codes.  The code represents
+their occurrence position in the auxiliary dictionary.  This generally
+produces better compression than
+.B \-B
+or
+.BR \-D .
+.TP
+.B \-M
+This specifies that the size of an auxiliary dictionary will be
+estimated.  Each novel word found will be placed at the end of the
+auxiliary dictionary.  Novel words will be coded in the compressed text
+using a combination of gamma and binary codes.  The code represents
+their occurrence position in the auxiliary dictionary.  This method is
+adaptive within documents, and generally produces better compression
+than
+.BR \-B ,
+.B \-D
+or
+.BR \-Y .
+.SH FILES
+.TP 20
+.B *.text.stats
+Statistics about the text.
+.TP
+.B *.text.dict
+Compressed compression dictionary.
+.SH "SEE ALSO"
+.na
+.BR mg (1),
+.BR mg_compression_dict (1),
+.BR mg_fast_comp_dict (1),
+.BR mg_get (1),
+.BR mg_invf_dict (1),
+.BR mg_invf_dump (1),
+.BR mg_invf_rebuild (1),
+.BR mg_passes (1),
+.BR mg_perf_hash_build (1),
+.BR mg_weights_build (1),
+.BR mgbilevel (1),
+.BR mgbuild (1),
+.BR mgdictlist (1),
+.BR mgfelics (1),
+.BR mgquery (1),
+.BR mgstat (1),
+.BR mgtic (1),
+.BR mgticbuild (1),
+.BR mgticdump (1),
+.BR mgticprune (1),
+.BR mgticstat (1).
Index: /main/tags/2.25/gsdl/packages/mg/man/man1/mg_text_merge.1
===================================================================
--- /main/tags/2.25/gsdl/packages/mg/man/man1/mg_text_merge.1	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/mg/man/man1/mg_text_merge.1	(revision 21064)
@@ -0,0 +1,76 @@
+.\"------------------------------------------------------------
+.\" Id - set Rv,revision, and Dt, Date using rcs-Id tag.
+.de Id
+.ds Rv \\$3
+.ds Dt \\$4
+..
+.Id $Id$
+.\"------------------------------------------------------------
+.TH mg_text_merge 1 \*(Dt CITRI
+.SH NAME
+mg_text_merge \- Append one compressed text file to another
+.SH SYNOPSIS
+.B mg_text_merge
+[
+.B \-h
+]
+[
+.BI \-d " directory"
+]
+.BI \-f " name"
+.SH DESCRIPTION
+This program takes two
+.BR mg (1)
+database inverted files and stemmed
+dictionaries, named "old" and "new" respectively, and creates
+a merged stemmed dictionary and inverted file.
+It is part of the
+.BR mgmerge (1)
+addition to the
+.BR mg (1)
+package.
+The two compressed text files are
+.IR "name" .old.text
+and
+.IR "name" .new.text.
+.SH OPTIONS
+Options may appear in any order.
+.TP "\w'\fB\-d\fP \fIdirectory\fP'u+2n"
+.B \-h
+This displays a usage line on
+.IR stderr .
+.TP
+.BI \-d " directory"
+This specifies the directory where the document collection can be found.
+.TP
+.BI \-f " name"
+This specifies the base name of the document collection.
+.SH ENVIRONMENT
+.TP "\w'\fBMGDATA\fP'u+2n"
+.SB MGDATA
+If this environment variable exists, then its value is used as the
+default directory where the
+.BR mg (1)
+collection files are.  If this variable does not exist, then the
+directory \*(lq\fB.\fP\*(rq is used by default.  The command line
+option
+.BI \-d " directory"
+overrides the directory in
+.BR MGDATA .
+.SH FILES
+.TP 20
+.B *.old.text
+The old compressed text.
+.TP
+.B *.new.text
+The new compressed text that will be appended
+.TP
+.SH "SEE ALSO"
+.na
+.BR mg (1),
+.BR mgmerge (1),
+.BR mg_get_merge (1),
+.BR mg_invf_merge (1),
+.BR mg_compression_dict (1),
+.BR mg_fast_comp_dict (1),
+.BR mgquery (1).
Index: /main/tags/2.25/gsdl/packages/mg/man/man1/mg_weights_build.1
===================================================================
--- /main/tags/2.25/gsdl/packages/mg/man/man1/mg_weights_build.1	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/mg/man/man1/mg_weights_build.1	(revision 21064)
@@ -0,0 +1,112 @@
+.\"------------------------------------------------------------
+.\" Id - set Rv,revision, and Dt, Date using rcs-Id tag.
+.de Id
+.ds Rv \\$3
+.ds Dt \\$4
+..
+.Id $Id$
+.\"------------------------------------------------------------
+.TH mg_weights_build 1 \*(Dt CITRI
+.SH NAME
+mg_weights_build \- builds the approximate weights file
+.SH SYNOPSIS
+.B mg_weights_build
+[
+.B \-h
+]
+[
+.B \-s
+]
+[
+.BI \-b " num"
+]
+[
+.BI \-d " directory"
+]
+.if n .ti +9n
+.BI \-f " name"
+.SH DESCRIPTION
+.B mg_weights_build
+is the program that generates the approximate weights file and the
+interleaved text index and exact weights file.  To do this, it uses
+the text index and either the exact weights file, or the inverted file
+and stemmed dictionary.
+.SH OPTIONS
+Options may appear in any order.
+.TP "\w'\fB\-d\fP \fIdirectory\fP'u+2n"
+.B \-h
+This displays a usage line on
+.IR stderr .
+.TP
+.B \-s
+Save the weights generated from the
+.I *.invf
+and
+.I *.invf.dict
+file in a
+.I *.weight
+file.
+.TP
+.BI \-b " num"
+This specifies the number of bits of precision that should be used for
+the approximate weights.  If not specified, it defaults to 8.
+.TP
+.BI \-d " directory"
+This specifies the directory where the document collection is.
+.TP
+.BI \-f " name"
+This specifies the base name of the document collection.
+.SH ENVIRONMENT
+.TP "\w'\fBMGDATA\fP'u+2n"
+.SB MGDATA
+If this environment variable exists, then its value is used as the
+default directory where the
+.BR mg (1)
+collection files are.  If this variable does not exist, then the
+directory \*(lq\fB.\fP\*(rq is used by default.  The command line
+option
+.BI \-d " directory"
+overrides the directory in
+.BR MGDATA .
+.SH FILES
+.TP 20
+.B *.invf
+Inverted file.
+.TP
+.B *.invf.dict
+Compressed stemmed dictionary.
+.TP
+.B *.weight
+The exact weights file.
+.TP
+.B *.text.idx
+Index into the compressed documents.
+.TP
+.B *.text.idx.wgt
+Interleaved index into the compressed documents and document weights.
+.TP
+.B *.weight.approx
+Approximate document weights.
+.SH "SEE ALSO"
+.na
+.BR mg (1),
+.BR mg_compression_dict (1),
+.BR mg_fast_comp_dict (1),
+.BR mg_get (1),
+.BR mg_invf_dict (1),
+.BR mg_invf_dump (1),
+.BR mg_invf_rebuild (1),
+.BR mg_passes (1),
+.BR mg_perf_hash_build (1),
+.BR mg_text_estimate (1),
+.BR mgbilevel (1),
+.BR mgbuild (1),
+.BR mgdictlist (1),
+.BR mgfelics (1),
+.BR mgquery (1),
+.BR mgstat (1),
+.BR mgtic (1),
+.BR mgticbuild (1),
+.BR mgticdump (1),
+.BR mgticprune (1),
+.BR mgticstat (1).
Index: /main/tags/2.25/gsdl/packages/mg/man/man1/mgbilevel.1
===================================================================
--- /main/tags/2.25/gsdl/packages/mg/man/man1/mgbilevel.1	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/mg/man/man1/mgbilevel.1	(revision 21064)
@@ -0,0 +1,116 @@
+.\"------------------------------------------------------------
+.\" Id - set Rv,revision, and Dt, Date using rcs-Id tag.
+.de Id
+.ds Rv \\$3
+.ds Dt \\$4
+..
+.Id $Id$
+.\"------------------------------------------------------------
+.TH mgbilevel 1 \*(Dt CITRI
+.SH NAME
+mgbilevel \- compresses a bilevel image using a specified template
+.SH SYNOPSIS
+.B mgbilevel
+.B \-e
+[
+.B \-t
+.I \*(lqstring\*(rq
+]
+.I infile
+[
+.I \>compressed-outfile
+]
+.nf
+or
+.fi
+.B mgbilevel
+.B \-d
+.I compressed-infile
+[
+.I \>outfile
+]
+.SH DESCRIPTION
+.B mgbilevel
+performs (up to) a two-stage template-based compression.  The
+user can specify the template to be used in the compression process.  The
+default template size is a two-stage template 22/10.  The compressed file
+contains the template type in the stream.  The output files are written
+to
+.IR stdout .
+.SH OPTIONS
+Options may appear in any order.
+.TP "\w'\fB\-t\fP \fI\*(lqstring\*(rq\fP'u+2n"
+.B \-h
+This displays a usage line on
+.IR stderr .
+.TP
+.B \-e
+Compresses
+.I infile
+using a template specified, and writes to
+.IR compressed-outfile .
+.TP
+.B \-d
+Decompresses
+.I compressed-infile
+using the template contained in the compressed file.  Writes to
+.IR outfile .
+.TP
+\fB\-t \fP\fI\*(lqstring\*(rq\fP
+This option specifies which template combination is to
+be used in the compression.  Five different characters
+can occur in the string: `.' for a pixel not
+included in the template, `p' for a pixel included in the 1st
+level template, `2' for a pixel included in the 2nd level
+template (a subset of the 1st level), `*' denoting the position
+of the
+.I current
+pixel, and a `;' denoting the end of each template line.
+The default template is a two-level 22/10 template:
+.IP
+.RS
+.nf
+\&.ppppp.;
+pp222pp;
+p22222p;
+p22*.\|.\|.;
+.fi
+.RE
+.IP
+This would be specified on the command line as:
+.nf
+\&\fB\-T\fP ".ppppp.;pp222pp;p22222p;p22*.\|.\|.;"
+.fi
+.TP
+.I infile
+This is the input
+.I .pbm
+file to be compressed.
+.TP
+.I outfile
+This is the decompressed
+.I .pbm
+file.
+.SH "SEE ALSO"
+.na
+.BR mg (1),
+.BR mg_compression_dict (1),
+.BR mg_fast_comp_dict (1),
+.BR mg_get (1),
+.BR mg_invf_dict (1),
+.BR mg_invf_dump (1),
+.BR mg_invf_rebuild (1),
+.BR mg_passes (1),
+.BR mg_perf_hash_build (1),
+.BR mg_text_estimate (1),
+.BR mg_weights_build (1),
+.BR mgbuild (1),
+.BR mgdictlist (1),
+.BR mgfelics (1),
+.BR mgquery (1),
+.BR mgstat (1),
+.BR mgtic (1),
+.BR mgticbuild (1),
+.BR mgticdump (1),
+.BR mgticprune (1),
+.BR mgticstat (1).
Index: /main/tags/2.25/gsdl/packages/mg/man/man1/mgbuild.1
===================================================================
--- /main/tags/2.25/gsdl/packages/mg/man/man1/mgbuild.1	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/mg/man/man1/mgbuild.1	(revision 21064)
@@ -0,0 +1,169 @@
+.\"------------------------------------------------------------
+.\" Id - set Rv,revision, and Dt, Date using rcs-Id tag.
+.de Id
+.ds Rv \\$3
+.ds Dt \\$4
+..
+.Id $Id$
+.\"------------------------------------------------------------
+.TH mgbuild 1 \*(Dt CITRI
+.SH NAME
+mgbuild \- build an mg system database
+.SH SYNOPSIS
+.B mgbuild
+[
+.B \-c
+]
+[
+.BI \-g " get"
+]
+[
+.BI \-s " source"
+]
+[
+.BI \-d " mgdata dir"
+]
+.I collection-name
+.SH DESCRIPTION
+.B mgbuild
+is a
+.B csh
+script that executes all the appropriate programs in the correct order
+to completely build an
+.BR mg (1)
+system database ready for queries to be made
+by
+.BR mgquery.
+This program makes use of the
+.BR mg_get (1)
+script to obtain the text of the collection.
+.SH OPTIONS
+Options can occur in any order, but the collection name must be last.
+.TP "\w'\fIcollection-name\fP'u+2n"
+.BI \-c
+This specifies whether the
+.I get
+program is \*(lqcomplex\*(rq.  If a
+.I get
+program is \*(lqcomplex\*(rq, then it requires initialisation and
+cleanup with the
+.B \-i
+and
+.B \-c
+options.
+.TP
+.BI \-g " get"
+This specifies the program to use for getting the source text for the
+build.  If no
+.B \-g
+option is given, the default program
+.BR mg_get (1)
+is used.
+.TP
+.BI \-s " source"
+The
+.B mgbuild
+program consists of two parts.  The first part initializes variables
+to default values.  The second part uses these variables to control
+how the
+.BR mg (1)
+database is built.  This option specifies a program to execute between
+the first and second parts.  The details of what the variables are, and
+how they may be changed, are in comments in the
+.B mgbuild
+program.
+.TP
+.BI \-d " mgdata dir"
+Setting this option allows one to override the MGDATA environment variable.
+.TP
+.I collection-name
+This is the collection name, as required by the
+.BR mg_get (1)
+program.  It serves both as a
+.I case
+statement selector, and as the name of a subdirectory that holds the
+indexing files.
+.SH ENVIRONMENT
+.TP "\w'\fBMGDATA\fP'u+2n"
+.SB MGDATA
+If this environment variable exists, then its value is used as the
+default directory where the
+.BR mg (1)
+collection files are.  If this variable does not exist, then the
+directory \*(lq\fB.\fP\*(rq is used by default.  The command line
+option
+.BI \-d " directory"
+overrides the directory in
+.BR MGDATA .
+.SH FILES
+.TP 20
+.B *.invf
+Inverted file.
+.TP
+.B *.invf.chunk
+Inverted file chunk descriptor file.  When the inverted file is
+created, it is written in chunks that use no more than a set amount of
+memory.  This file describes those chunks.
+.TP
+.B *.invf.chunk.trans
+Word-occurrence-order to lexical-order translation file.  The
+.B *.invf.chunk
+file is written in word-occurrence order but is required by
+.B \-N2
+to be in lexical order.
+.TP
+.B *.invf.dict
+Compressed stemmed dictionary.
+.TP
+.B *.invf.dict.blocked
+The `on-disk' stemmed dictionary.
+.TP
+.B *.invf.dict.hash
+Data for an order-preserving perfect hash function.
+.TP
+.B *.invf.idx
+The index into the inverted file.
+.TP
+.B *.weight
+The exact weights file.
+.TP
+.B *.text
+Compressed documents.
+.TP
+.B *.text.stats
+Text statistics.
+.TP
+.B *.text.dict
+Compressed compression dictionary.
+.TP
+.B *.text.idx
+Index into the compressed documents.
+.TP
+.B *.text.idx.wgt
+Interleaved index into the compressed documents and document weights.
+.TP
+.B *.weight.approx
+Approximate document weights.
+.SH "SEE ALSO"
+.na
+.BR mg (1),
+.BR mg_compression_dict (1),
+.BR mg_fast_comp_dict (1),
+.BR mg_get (1),
+.BR mg_invf_dict (1),
+.BR mg_invf_dump (1),
+.BR mg_invf_rebuild (1),
+.BR mg_passes (1),
+.BR mg_perf_hash_build (1),
+.BR mg_text_estimate (1),
+.BR mg_weights_build (1),
+.BR mgbilevel (1),
+.BR mgdictlist (1),
+.BR mgfelics (1),
+.BR mgquery (1),
+.BR mgstat (1),
+.BR mgtic (1),
+.BR mgticbuild (1),
+.BR mgticdump (1),
+.BR mgticprune (1),
+.BR mgticstat (1).
Index: /main/tags/2.25/gsdl/packages/mg/man/man1/mgbuild_4.1
===================================================================
--- /main/tags/2.25/gsdl/packages/mg/man/man1/mgbuild_4.1	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/mg/man/man1/mgbuild_4.1	(revision 21064)
@@ -0,0 +1,53 @@
+.\"------------------------------------------------------------
+.\" Id - set Rv,revision, and Dt, Date using rcs-Id tag.
+.de Id
+.ds Rv \\$3
+.ds Dt \\$4
+..
+.Id $Id$
+.\"------------------------------------------------------------
+.TH mgbuild_4 1 \*(Dt CITRI
+.SH NAME
+mgbuild_4 \- build an mg system database using 4 passes instead of 2
+.SH SYNOPSIS
+.B mgbuild_4
+[
+.B \-c
+]
+[
+.BI \-g " get"
+]
+[
+.BI \-s " source"
+]
+[
+.BI \-d " mgdata dir"
+]
+.I collection-name
+.SH DESCRIPTION
+.B mgbuild_4
+is a
+.B csh
+script that executes all the appropriate programs in the correct order
+to completely build an
+.BR mg (1)
+system database ready for queries to be made
+by
+.BR mgquery.
+This program makes use of the
+.BR mg_get (1)
+script to obtain the text of the collection.
+In 
+.BR mgbuild (1)
+the build is done by two passes over the input text. The first
+pass creates the compressed text dictionary and inverted file dictionary,
+the second pass creates the compressed text and inverted file. What 
+.BR mgbuild_4
+does is use a separate pass for each function. This will be slower but will
+not require as much RAM at one time. Therefore, if your build is failing
+due to running short of memory, then 
+.BR mgbuild_4
+is worth a try.
+.SH "SEE ALSO"
+.na
+.BR mgbuild (1)
Index: /main/tags/2.25/gsdl/packages/mg/man/man1/mgdictlist.1
===================================================================
--- /main/tags/2.25/gsdl/packages/mg/man/man1/mgdictlist.1	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/mg/man/man1/mgdictlist.1	(revision 21064)
@@ -0,0 +1,72 @@
+.\"------------------------------------------------------------
+.\" Id - set Rv,revision, and Dt, Date using rcs-Id tag.
+.de Id
+.ds Rv \\$3
+.ds Dt \\$4
+..
+.Id $Id$
+.\"------------------------------------------------------------
+.TH mgdictlist 1 \*(Dt CITRI
+.SH NAME
+mgdictlist \- list the contents of a dictionary
+.SH SYNOPSIS
+.B mgdictlist
+[
+.B \-q
+]
+.I filename
+.SH DESCRIPTION
+.B mgdictlist
+lists the contents of either a compressed compression dictionary, a
+text statistics file, or a compressed stemmed dictionary.  Unlike all
+the other programs in the
+.BR mg (1)
+suite, it is necessary to specify the complete pathname of the
+dictionary to list.
+.SH OPTIONS
+The
+.I filename
+must be last.
+.TP "\w'\fIfilename\fP'u+2n"
+.B \-q
+Generate an abbreviated output (machine-readable rather than
+human-readable).
+.TP
+.I filename
+This is the name of the dictionary to list.
+.B mgdictlist
+automatically detects whether the file is a compressed compression
+dictionary, text statistics file, or a compressed stemmed dictionary.
+.SH FILES
+.TP 20
+.B *.text.dict
+Text statistics file.
+.TP
+.B *.text.dict
+Compressed compression dictionary.
+.TP
+.B *.invf.build
+Compressed stemmed dictionary.
+.SH "SEE ALSO"
+.na
+.BR mg (1),
+.BR mg_compression_dict (1),
+.BR mg_fast_comp_dict (1),
+.BR mg_get (1),
+.BR mg_invf_dict (1),
+.BR mg_invf_dump (1),
+.BR mg_invf_rebuild (1),
+.BR mg_passes (1),
+.BR mg_perf_hash_build (1),
+.BR mg_text_estimate (1),
+.BR mg_weights_build (1),
+.BR mgbilevel (1),
+.BR mgbuild (1),
+.BR mgfelics (1),
+.BR mgquery (1),
+.BR mgstat (1),
+.BR mgtic (1),
+.BR mgticbuild (1),
+.BR mgticdump (1),
+.BR mgticprune (1),
+.BR mgticstat (1).
Index: /main/tags/2.25/gsdl/packages/mg/man/man1/mgfelics.1
===================================================================
--- /main/tags/2.25/gsdl/packages/mg/man/man1/mgfelics.1	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/mg/man/man1/mgfelics.1	(revision 21064)
@@ -0,0 +1,103 @@
+.\"------------------------------------------------------------
+.\" Id - set Rv,revision, and Dt, Date using rcs-Id tag.
+.de Id
+.ds Rv \\$3
+.ds Dt \\$4
+..
+.Id $Id$
+.\"------------------------------------------------------------
+.TH mgfelics 1 \*(Dt CITRI
+.SH NAME
+mgfelics \- fast and efficient lossless image (de)compression
+.SH SYNOPSIS
+.B mgfelics
+.B \-e
+[
+.BI \-k " n"
+]
+.I infile
+[
+.I \>compressed-outfile
+]
+.br
+or
+.br
+.B mgfelics
+.B \-d
+.I compressed-infile
+[
+.I \>outfile
+]
+.SH DESCRIPTION
+.B mgfelics
+is a lossless compression process which can (de)compress portable
+bitmap files in
+.I pgm
+format.
+.B mgfelics
+writes to
+.IR stdout .
+.SH OPTIONS
+.TP "\w'\fB\-k\fP \fIn\fP'u+2n"
+.BI \-k " n"
+An integer parameter (< 32) which controls the compression speed and
+ratio.  The value of
+.I n
+is included in the output stream, and therefore is not needed in the
+decompression stage.  The default value of
+.I n
+is equal to the number of bits required to represent each grey level.
+.TP
+.B \-e
+Encodes the file
+.IR infile ,
+sending the output to
+.IR stdout .
+.TP
+.B \-d
+Decodes the file from
+.IR compressed-infile ,
+sending the output to
+.IR stdout .
+.SH NOTE
+.B mgfelics
+uses a combination of adjusted binary and Rice codes, the choice of
+which for any given pixel depends on the environment as determined by
+the intensity values of neighbouring pixels.  The result is a very
+fast and lossless algorithm for compressing grayscale images.  The
+optional parameter
+.BI \-k " n"
+corresponds to the maximum exponent of the same name in Rice encoding.
+Smaller values of
+.BI \-k " n"
+can result in significant improvement in compression times with a
+corresponding loss in compression ratio.  However the reduction in
+compression ratio with a small
+.BI \-k " n"
+parameter may be insignificant for many images.
+.SH REFERENCES
+Algorithm by Paul G. Howard and Jeffrey Scott Vitter
+of Brown University, RI, and Duke University, NC, respectively.
+.SH "SEE ALSO"
+.na
+.BR mg (1),
+.BR mg_compression_dict (1),
+.BR mg_fast_comp_dict (1),
+.BR mg_get (1),
+.BR mg_invf_dict (1),
+.BR mg_invf_dump (1),
+.BR mg_invf_rebuild (1),
+.BR mg_passes (1),
+.BR mg_perf_hash_build (1),
+.BR mg_text_estimate (1),
+.BR mg_weights_build (1),
+.BR mgbilevel (1),
+.BR mgbuild (1),
+.BR mgdictlist (1),
+.BR mgquery (1),
+.BR mgstat (1),
+.BR mgtic (1),
+.BR mgticbuild (1),
+.BR mgticdump (1),
+.BR mgticprune (1),
+.BR mgticstat (1).
Index: /main/tags/2.25/gsdl/packages/mg/man/man1/mgmerge.1
===================================================================
--- /main/tags/2.25/gsdl/packages/mg/man/man1/mgmerge.1	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/mg/man/man1/mgmerge.1	(revision 21064)
@@ -0,0 +1,175 @@
+`.\"------------------------------------------------------------
+.\" Id - set Rv,revision, and Dt, Date using rcs-Id tag.
+.de Id
+.ds Rv \\$3
+.ds Dt \\$4
+..
+.Id $Id$
+.\"------------------------------------------------------------
+.TH mgmerge 1 \*(Dt CITRI
+.SH NAME
+mgmerge \- update an mg system database with new documents
+.SH SYNOPSIS
+.B mgmerge
+[
+.B \-c
+]
+[
+.BI \-g " get"
+]
+[
+.BI \-s " source"
+]
+[
+.B \-S
+]
+[
+.B \-w
+]
+.I collection-name
+.SH DESCRIPTION
+.B mgmerge
+is a
+.B csh
+script that executes all the appropriate programs in the correct order
+to completely merge a current
+.BR mg (1)
+system database ready with some new documents, saving the need for a complete
+database rebuild with
+.B mgbuild.
+It does this by building a second
+.BR mg (1)
+system database from the new documents and then merging this database
+with the old one.
+This program makes use of the
+.BR mg_get_merge (1)
+script to obtain the text of the collection.
+.B mgmerge
+cannot edit or delete documents already in a database; only new documents
+can be added.
+.SH OPTIONS
+Options can occur in any order, but the collection name must be last.
+.TP "\w'\fIcollection-name\fP'u+2n"
+.BI \-c
+This specifies whether the
+.I get
+program is \*(lqcomplex\*(rq.  If a
+.I get
+program is \*(lqcomplex\*(rq, then it requires initialisation and
+cleanup with the
+.B \-i
+and
+.B \-c
+options.
+.TP
+.BI \-g " get"
+This specifies the program to use for getting the source text for the
+build.  If no
+.B \-g
+option is given, the default program
+.BR mg_get_merge (1)
+is used.
+.TP
+.BI \-s " source"
+The
+.B mgmerge
+program consists of two parts.  The first part initializes variables
+to default values.  The second part uses these variables to control
+how the
+.BR mg (1)
+database is built.  This option specifies a program to execute between
+the first and second parts.  The details of what the variables are, and
+how they may be changed, are in comments in the
+.B mgmerge
+program.
+If this option is used, the program should ideally be the same one that
+was called by
+.BR mgbuild (1)
+to build the database since some parameters need to be consistent between
+.B mgbuild
+and
+.B mgmerge.
+.TP
+.B \-S
+This option will cause a slow merge to be performed on the inverted files,
+where each inverted file entry is decoded and recoded.
+The default is a fast merge. Accumulated fast merges slowly degrade
+compression performance on the resulting inverted file so
+a periodic slow merge is recommended.
+.TP
+.B \-w
+Adding new documents can have an effect on the weight of the previous ones.
+By default the weights for documents already in the collection are not 
+recomputed since the change in their values is usually small.
+This option forces new weights to be recomputed.
+Periodic use of this option, as for the "-S" option, is recomended,
+otherwise query rankings may become inaccurate.
+.TP
+.I collection-name
+This is the collection name, as required by the
+.BR mg_get_merge (1)
+program.  It serves both as a
+.I case
+statement selector, and as the name of a subdirectory that holds the
+indexing files.
+.SH ENVIRONMENT
+.TP "\w'\fBMGDATA\fP'u+2n"
+.SB MGDATA
+If this environment variable exists, then its value is used as the
+default directory where the
+.BR mg (1)
+collection files are.  If this variable does not exist, then the
+directory \*(lq\fB.\fP\*(rq is used by default.  The command line
+option
+.BI \-d " directory"
+overrides the directory in
+.BR MGDATA .
+Note that a temporary directory under the
+.B MGDATA
+directory is used to perform the merge.
+The default name for this directory is
+.BR MERGE .
+.SH FILES
+.TP 20
+.B *.invf
+Inverted file.
+.TP
+.B *.invf.dict
+Compressed stemmed dictionary.
+.TP
+.B *.invf.dict.blocked
+The `on-disk' stemmed dictionary.
+.TP
+.B *.invf.idx
+The index into the inverted file.
+.TP
+.B *.weight
+The exact weights file.
+.TP
+.B *.text
+Compressed documents.
+.TP
+.B *.text.stats
+Text statistics.
+.TP
+.B *.text.dict
+Compressed compression dictionary.
+.TP
+.B *.text.idx
+Index into the compressed documents.
+.TP
+.B *.text.idx.wgt
+Interleaved index into the compressed documents and document weights.
+.TP
+.B *.weight.approx
+Approximate document weights.
+.SH "SEE ALSO"
+.na
+.BR mg (1),
+.BR mgbuild (1),
+.BR mg_get_merge (1),
+.BR mg_get (1),
+.BR mg_invf_merge (1),
+.BR mg_text_merge (1),
+.BR mg_query (1),
+.BR mg_weights_build (1).
Index: /main/tags/2.25/gsdl/packages/mg/man/man1/mgquery.1
===================================================================
--- /main/tags/2.25/gsdl/packages/mg/man/man1/mgquery.1	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/mg/man/man1/mgquery.1	(revision 21064)
@@ -0,0 +1,693 @@
+.\"------------------------------------------------------------
+.\" Id - set Rv,revision, and Dt, Date using rcs-Id tag.
+.de Id
+.ds Rv \\$3
+.ds Dt \\$4
+..
+.Id $Id$
+.\"------------------------------------------------------------
+.TH mgquery 1 \*(Dt CITRI
+.SH NAME
+mgquery \- query program for the mg system
+.SH SYNOPSIS
+.B mgquery
+[
+.B \-h
+]
+[
+.B \-D
+]
+[
+.BI \-f " name"
+]
+[
+.BI \-d " directory"
+]
+.if n .ti +9n
+[
+.I collection-name
+]
+.SH DESCRIPTION
+.B mgquery
+enables users to make Boolean or ranked queries from a data base
+generated by the
+.BR mg (1)
+system.  It accepts queries from
+.I stdin
+and sends the retrieved documents to
+.IR stdout .
+Information on the resource usage of
+.B mgquery
+as it processes queries can be obtained interactively.
+.SH OPTIONS
+Options may appear in any order, but the
+.IR collection-name ,
+if specified, must be last.
+.TP "\w'\fB\-d\fP \fIdirectory\fP'u+2n"
+.B \-h
+This displays a usage line on
+.IR stderr .
+.TP
+.B \-D
+This option causes the entire text to be decompressed and sent to
+.IR stdout .
+.TP
+.BI \-f " name"
+This specifies the base name of the document collection that will be
+used.  If a collection with the specified base
+.I name
+does not exist, an error message will be displayed and
+.B mgquery
+will exit.
+.TP
+.BI \-d " directory"
+This specifies the directory where the document collection can be found.
+.SH USAGE
+Prior to processing the command line arguments, the
+.B mgquery
+program attempts to read in a startup script called
+.IR ./.mgrc .
+If that fails, it attempts to read in the file
+.IR $HOME/.mgrc .
+The startup file can only contain commands\(emno queries are
+permitted in the
+.I .mgrc
+file.  Lines starting with \*(lq\fB#\fP\*(rq in the file are comments.
+The most common use for the
+.I .mgrc
+file is to personalise the initial values of the predefined parameters
+with
+.B .set
+commands.
+.LP
+The input to
+.B mgquery
+consists of a series of input lines.  The backslash
+character
+.RB (\*(lq \e \*(rq)
+is used at the end of lines to indicate
+that input continues on the next line.
+.LP
+Input lines on which the first character is a dot
+.RB (\*(lq . \*(rq)
+are commands to the
+.B mgquery
+program.  Input lines that do not start with a dot are queries.
+.LP
+A query consists of two parts.  One part is a Boolean or ranked query
+that identifies documents.  The second part is a post-processing
+pattern matching operation.  Any text between the first speech mark
+(\*(lq) and the last speech mark (\*(rq) is considered to be a
+post-processing pattern.
+.SH COMMANDS
+The
+.B mgquery
+program can accept the following commands.
+.TP 17
+.B .help
+Display several pages of help text.
+.TP
+.B .quit
+Quit the program.
+.TP
+.B .warranty
+Display the
+.BR mg (1)
+warranty.
+.TP
+.B .conditions
+Display the conditions of use and distribution of
+.BR mg (1).
+.TP
+.BI ".set " "name value"
+Set the parameter
+.I name
+to the specified
+.IR value .
+If the parameter is a Boolean
+.I value
+and the
+.I value
+is omitted, the parameter will be inverted (i.e., if it was
+.IR true ,
+then it will change to
+.IR false ;
+if it was
+.IR false ,
+then it will change to
+.IR true ).
+.TP
+.BI ".unset " name
+Delete the parameter
+.I name
+from the currently-defined parameters.
+.TP
+.B .reset
+Reset the parameters to the state that they had after the processing
+of the
+.B mgquery
+command line.
+.TP
+.B .display
+Display the values of all the currently-defined parameters.
+.TP
+.B .push
+Push the currently-defined parameters onto a stack.
+.TP
+.B .pop
+Pops a set of parameters off the stack, replacing the currently-defined
+ones.
+.TP
+.BI ".output " arg
+This is used to specify where to send the text of the documents.  Once
+the
+.B .output
+command is specified, all subsequent output will be sent to the place
+specified by
+.IR arg .
+If
+.I arg
+is not specified subsequent output will be directed to
+.IR stdout .
+.I Arg
+may be any of the following.
+.RS
+.TP 13
+.BI "> " filename
+Send output to the specified file.
+.TP
+.BI ">> " filename
+Append output to the specified file.
+.TP
+.BI "| " command
+Pipe the output to
+.IR command ,
+which is executed by
+.IR sh .
+.RE
+.TP
+.BI ".input " arg
+This is used to specify where input (queries and commands) comes
+from.  Once the
+.B .input
+command is specified all subsequent input will be come from the place
+specified by
+.IR arg .
+If
+.I arg
+is not specified subsequent input will come from
+.IR stdin .
+.RS
+.TP 13
+.BI "< " filename
+Get input from the specified file.
+.TP
+.BI "| " command
+The input comes from the standard output of
+.IR command ,
+which is executed by
+.IR sh .
+.RE
+.SH PARAMETERS
+The following parameters are predefined and have special
+significance.  Each parameter will be followed by its default
+value.  Parameters are initialised before the
+.I .mgrc
+file is read or the command line arguments are processed.
+.TP 17
+.BI accumulator_method " `array'"
+This parameter is used during ranking, and specifies how the
+weight for each document should be accumulated.  The following
+methods are available:
+.IR array ,
+.IR splay_tree ,
+.IR hash_table ,
+and
+.IR list .
+.TP
+.BI briefstats " `off'"
+This is a Boolean parameter that determines whether the
+totals for disk, memory and time usage statistics will be
+displayed at the end of each query.
+.IR Note :
+this takes precedence over the parameters
+.BR diskstats ,
+.BR memstats " and " timestats .
+This parameter may take the values
+.IR yes ", " no ", "
+.IR true ", " false ", "
+.IR on " or " off .
+.TP
+.BI buffer " `1048576'"
+When the documents are being read in, they are read into a
+buffer of this size and then displayed from this buffer.  If
+the documents are larger than this buffer, the buffer is
+expanded automatically.  Having a large buffer gives a very
+slight performance improvement, because it allows the order of
+disk operations to be optimised.  The buffer size is measured
+in bytes.
+.TP
+.BI diskstats " `off'"
+This is a Boolean parameter that determines whether the disk
+usage statistics for the preceding query will be displayed
+after each query.  This parameter may take the values
+.IR yes ", " no ", "
+.IR true ", " false ", "
+.IR on " or " off .
+.TP
+.BI doc_sepstr " `---------------------------------- %n\en\'"
+This specifies the string that will be used to separate
+documents when they are displayed for `Boolean' or `docnums'
+queries.  The standard C escape character sequences
+may be used to place special characters in the
+string.  For example, a newline would be `\en'.  To include a `%',
+use the sequence `%%'.  To include the
+.BR mg (1)
+document number, use the sequence `%n'.  The following escape character
+sequences are available
+.nf
+.ta 1.7iL
+.B Sequence	Meaning
+`\e\e'	backslash
+`\eb'	backspace
+`\ef'	formfeed
+`\en'	newline
+`\er'	carriage return
+`\et'	tab
+`\e"'	speech marks
+`\e''	quote mark
+`\ex\fIhh\fP'	ASCII code in hexadecimal
+`\ennn'	ASCII code in octal
+.fi
+.TP
+.BI expert " `false'"
+If this is
+.IR true ,
+then much of the dialogue output is suppressed.  This parameter may
+take the values
+.IR yes ", " no ", "
+.IR true ", " false ", "
+.IR on " or " off .
+.TP
+.BI hash_tbl_size " `1000'"
+One of the options during ranking queries is to use a hash
+table to accumulate the weights for each document.  The hash
+table is a simple chained type.  This parameter specifies the
+size of the hash table and may take any value between 8 and
+268435456 (2^28).
+.TP
+.BI heads_length " `50'"
+When the mode is
+.BR heads ,
+this specifies the number of characters that will be output for each
+document.
+.TP
+.BI maxdocs " `all'"
+The maximum number of documents to display in response to a
+query.  This parameter may take on a numeric value between 1
+and 429467295 (2^32 - 1) or the word
+.IR all .
+.TP
+.BI maxparas " `1000'"
+The maximum number of paragraphs to identify during a ranked
+query with paragraph indexing.  After the paragraphs have been
+identified, the paragraphs are converted into documents, and
+because some of the paragraphs may refer to the same documents
+the final number of answers may be less than
+.BR maxparas .
+The
+.B maxdocs
+parameter will then be applied.  This parameter may take on a numeric
+value between 1 and 429467295 (2^32 - 1).
+.TP
+.BI max_accumulators " `50000'"
+This parameter limits the number of different paragraph and
+document numbers to be accumulated during ranked queries when
+the parameter
+.B accumulator_method
+is set to
+.IR splay_tree ,
+.IR hash_table ,
+or
+.IR list .
+This parameter may take any value between 8 and 268435456 (2^28).
+.TP
+.BI max_terms " `all'"
+This parameter limits the number of terms that will actually
+be used during a ranked query.  If more terms than the number
+specified by
+.B max_terms
+are entered, then the extra terms will be discarded.  If
+.B sorted_terms
+is on, then the limiting will be done after the terms have been
+sorted.  This parameter may take any value between 1 and 429467295
+(2^32 - 1), or the word
+.IR all.
+.TP
+.BI memstats " `off'"
+This is a Boolean parameter that determines whether the memory
+usage statistics for the preceding query will be displayed
+after each query.  This parameter may take the values
+.IR yes ", " no ", "
+.IR true ", " false ", "
+.IR on " or " off .
+.TP
+.BI mgdir " `.'"
+This is set to the directory where the
+.BR mg (1)
+data files may be found.  If
+the environment variable
+.B MGDATA
+exists, then this is instead initialised to the value of
+.BR MGDATA .
+The value of this parameter may be changed, either in the
+.I .mgrc
+file with a
+.BI ".set mgdir "directory
+command, or from the command line using the
+.BI \-d " directory"
+option.  Once the \*(lq\fB>\fP\*(rq prompt appears, changing this
+parameter will have no effect.
+.TP
+.BI mgname " `bible'"
+This is set to the name of the
+.BR mg (1)
+collection that is to be used for the session.  The value of this
+parameter may be changed, either in the
+.I .mgrc
+file with a
+.BI ".set mgname "name
+command, or from the command line using the
+.BI \-f " name"
+option.  Once the \*(lq\fB>\fP\*(rq prompt appears, changing this
+parameter will have no effect.
+.TP
+.BI mode " `text'"
+This specifies how documents should be displayed when they
+are retrieved.  It may take six different values:
+.IR text ,
+.IR hilite ,
+.IR docnums ,
+.IR heads ,
+.IR silent ,
+or
+.IR count .
+.I text
+displays the contents of the document.
+.I hilite
+displays the contents of the document and highlights any of the 
+stemmed query terms.
+.I docnums
+displays only the document numbers.
+.I heads
+is used to print out the head of each document.
+.I silent
+retrieves all the documents but displays nothing except how many
+documents were retrieved.  This mode is intended to be used in timing
+experiments.
+.I count
+does the minimum
+amount of work required to determine how many documents would
+be retrieved, but does not retrieve them.
+.TP
+.BI optimise_type " `1'"
+There are three types of boolean query optimisation (parse tree
+rearrangement). Type 0 leaves parse tree unaltered. Type 1 optimises
+for AND of terms and AND of OR of terms. Type 2 converts the tree
+into DNF (an experiment :-).
+.TP
+.BI pager " `more'"
+This is the name of the program that will be used to display
+the help and the retrieved documents.  If the environment
+variable
+.B PAGER
+is defined, then
+.B pager
+takes on that value.
+.TP
+.BI hilite_style " `bold'"
+This specifies the type of highlighting method.
+It may take one of two different values:
+.IR bold,
+or
+.IR underline.
+.TP
+.BI para_sepstr " `\en######## PARAGRAPH %n ########\en'"
+This specifies the string that will be used to separate paragraphs.
+The standard C escape character sequences may be used to place special
+characters in the string.  For example, a newline would be written
+as `\en'.  To include a `%', use the sequence `%%'.  To include the
+paragraph number within the document, use the sequence `%n'.
+.TP
+.BI para_start " `***** Weight = %w *****\en'"
+This specifies the string that will be used at the head of paragraphs
+for a paragraph-level index following a ranked query.  The standard
+C-language escape character sequences may be used to place special
+characters in the string.  For example, a newline would be written as
+`\en'.  To include a `%', use the sequence `%%'.  To include the
+paragraph weight, use the sequence `%w'.
+.TP
+.BI qfreq " `true'"
+This determine whether the ranked queries will take into account the
+number of times each query term is specified.  When this is
+.IR true ,
+the number of times a term appears in the query is used in the
+ranking.  When this is
+.IR false ,
+all query terms are assumed to occur only once.  This parameter may
+take the values
+.IR yes ", " no ", "
+.IR true ", " false ", "
+.IR on " or " off .
+.TP
+.BI query  " `Boolean'"
+This specifies the type of queries that are to be specified.
+It can take four different values:
+.IR Boolean ,
+.IR ranked ,
+.IR docnums " or " approx-ranked.
+.I Boolean
+is for Boolean queries.
+The
+.BR yacc (1)
+grammar for Boolean queries is as follows.
+.IP
+.nf
+        query   : or;
+.IP
+        or      : or '|' and
+                | and ;
+.IP
+        and     : and '&' not
+                | and not
+                | not ;
+.IP
+        not     : term
+                | '!' not ;
+.IP
+        term    : TERM
+                | '(' or ')' ;
+.fi
+.IP
+.IR ranked " and " approx-ranked
+are for queries ranked by the cosine measure.
+.I approx-ranked
+uses only the low-precision document lengths, and therefore only
+produces an approximation to full cosine ranking.
+.IP
+.nf
+        query   : TERM
+                | query TERM ;
+.fi
+.IP
+.I docnums
+allows the entry of document numbers.  Multiple numbers separated by
+spaces may be specified, or ranges separated by hyphens.
+.IP
+.nf
+        query   : range
+                | query range ;
+.IP
+        range   : num
+                | num '-' num ;
+.fi
+.TP
+.BI ranked_doc_sepstr " `-------------------------------- %n %w\en'"
+This specifies the string that will be used to separate documents when
+they are displayed for `ranked' or `approx-ranked' queries.  The
+standard C escape character sequences may be used to place special
+characters in the string.  For example, a newline would be written as
+`\en'.  To include a `%', use the sequence `%%'.  To include the
+.BR mg (1)
+document number, use the sequence `%n'.  To include the document
+weight, use the sequence `%w'.
+.TP
+.BI sizestats " `false'"
+If this is
+.IR true ,
+then various numbers are output at the end of each query indicating
+what went on during the query.  This parameter may take the values
+.IR yes ", " no ", "
+.IR true ", " false ", "
+.IR on " or " off .
+.TP
+.BI skip_dump " `skips.%d'"
+If this parameter is set, then a file will be produced in the current
+directory during ranked queries on skipped inverted files when
+.B accumulator_method
+is set to
+.IR splay_tree ,
+.IR hash_table ,
+or
+.IR list .
+The name of the file is the value of this parameter.  A `%d' in the
+file name will be replaced with the process id of
+.BR mgquery .
+This file will contain information about the usage of skips during the
+query processing.  This option is expensive; use
+.B .unset skip_dump
+to obtain optimal performance.
+.TP
+.BI sorted_terms " `on'"
+This specifies whether or not the terms should be sorted into
+decreasing occurrence in documents so that the least-often occurring
+terms are processed first when ranked queries are being done.  When
+this is
+.IR true ,
+the terms are sorted.  When this is
+.IR false ,
+the terms are not sorted, and are instead processed in order of
+occurrence.  This parameter may take the values
+.IR yes ", " no ", "
+.IR true ", " false ", "
+.IR on " or " off .
+.TP
+.BI stop_at_max_accum " `on'"
+This specifies what should happen when the maximum number of
+accumulators set by
+.B max_accumulators
+is reached.  When this is
+.IR true ,
+the processing of terms is stopped at the completion of the current
+term.  When this is
+.IR false ,
+processing continues but no new accumulators are created.  This
+parameter may take the values
+.IR yes ", " no ", "
+.IR true ", " false ", "
+.IR on " or " off .
+.TP
+.BI terminator " `'"
+This specifies the string that will be output after the last document
+from the previous query has been output.  The standard C escape
+character sequences may be used to place special characters in the
+string.  For example, a newline would be written as `\en'.  To include
+a `%', use the sequence `%%'.
+.TP
+.BI timestats " `false'"
+If this is
+.IR true ,
+then the time to process a query is displayed in both real time and
+CPU time.  This parameter may take the values
+.IR yes ", " no ", "
+.IR true ", " false ", "
+.IR on " or " off .
+.TP
+.BI verbatim " `off'"
+This is a Boolean parameter that determines whether the program
+should attempt to do a regular-expression match on the retrieved
+text.  If verbatim is
+.I on
+and a post-processing string is specified with the query, then the
+post-processing string will be searched for in the documents just
+before they are displayed.  If the string is found, the document will
+be displayed; if not, the document will not be displayed.  If verbatim
+is
+.IR off ,
+the post-processing string will be considered a regular expression
+as in
+.BR egrep (1)
+or
+.BR vi (1).
+E.g., if verbatim is
+.I on,
+\*(lq\fBand.*the\fP\*(rq will look for the 8-character sequence
+\*(lq\fBand.*the\fP\*(rq.  If verbatim is
+.IR off ,
+\*(lq\fBand.*the\fP\*(rq will look for the sequence
+\*(lq\fBand\fP\*(rq followed somewhere later in the document by the
+sequence \*(lq\fBthe\fP\*(rq.  This parameter may take the values
+.IR yes ", " no ", "
+.IR true ", " false ", "
+.IR on " or " off .
+.SH ENVIRONMENT
+.TP "\w'\fBMGDATA\fP'u+2n"
+.SB MGDATA
+If this environment variable exists, then its value is used as the
+default directory where the
+.BR mg (1)
+collection files are.  If this variable does not exist, then the
+directory \*(lq\fB.\fP\*(rq is used by default.  The command line
+option
+.BI \-d " directory"
+overrides the directory in
+.BR MGDATA .
+.SH FILES
+.TP 20
+.I .mgrc
+.B mgquery
+startup file
+.TP
+.B help.mg
+Help file for
+.BR mgquery .
+The contents of this file is displayed with the
+.B .help
+command.
+.TP
+.B *.invf
+Inverted file.
+.TP
+.B *.invf.dict
+The `on-disk' stemmed dictionary.
+.TP
+.B *.text
+Compressed documents.
+.TP
+.B *.text.dict
+Compression dictionary.
+.TP
+.B *.text.idx
+Index into the compressed documents.
+.TP
+.B *.text.idx.wgt
+Interleaved index into the compressed documents and document weights.
+.TP
+.B *.weight.approx
+Approximate document weights.
+.SH "SEE ALSO"
+.na
+.BR egrep (1),
+.BR mg (1),
+.BR mg_compression_dict (1),
+.BR mg_fast_comp_dict (1),
+.BR mg_get (1),
+.BR mg_invf_dict (1),
+.BR mg_invf_dump (1),
+.BR mg_invf_rebuild (1),
+.BR mg_passes (1),
+.BR mg_perf_hash_build (1),
+.BR mg_text_estimate (1),
+.BR mg_weights_build (1),
+.BR mgbilevel (1),
+.BR mgbuild (1),
+.BR mgdictlist (1),
+.BR mgfelics (1),
+.BR mgstat (1),
+.BR mgtic (1),
+.BR mgticbuild (1),
+.BR mgticdump (1),
+.BR mgticprune (1),
+.BR mgticstat (1),
+.BR vi (1),
+.BR yacc (1).
Index: /main/tags/2.25/gsdl/packages/mg/man/man1/mgstat.1
===================================================================
--- /main/tags/2.25/gsdl/packages/mg/man/man1/mgstat.1	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/mg/man/man1/mgstat.1	(revision 21064)
@@ -0,0 +1,131 @@
+.\"------------------------------------------------------------
+.\" Id - set Rv,revision, and Dt, Date using rcs-Id tag.
+.de Id
+.ds Rv \\$3
+.ds Dt \\$4
+..
+.Id $Id$
+.\"------------------------------------------------------------
+.TH mgstat 1 \*(Dt CITRI
+.SH NAME
+mgstat \- print out statistics about a document collection
+.SH SYNOPSIS
+.B mgstat
+[
+.B \-h
+]
+[
+.B \-E
+]
+[
+.BI \-d " directory"
+]
+.BI \-f " name"
+.SH DESCRIPTION
+.B mgstat
+prints out various statistics about an existing
+.BR mg (1)
+document collection.  Depending on the size of the collection, sizes
+will be printed in either kilobytes or megabytes.
+.SH OPTIONS
+Options may appear in any order.
+.TP "\w'\fB\-d\fP \fIdirectory\fP'u+2n"
+.B \-h
+This displays a usage line on
+.IR stdout .
+.TP
+.B \-E
+This option forces sizes to be printed in bytes rather than kilobytes
+or megabytes.
+.TP
+.BI \-d " directory"
+This specifies the directory where the document collection can be found.
+.TP
+.BI \-f " name"
+This specifies the base name of the document collection.
+.SH ENVIRONMENT
+.TP "\w'\fBMGDATA\fP'u+2n"
+.SB MGDATA
+If this environment variable exists, then its value is used as the
+default directory where the
+.BR mg (1)
+collection files are.  If this variable does not exist, then the
+directory \*(lq\fB.\fP\*(rq is used by default.  The command line
+option
+.BI \-d " directory"
+overrides the directory in
+.BR MGDATA .
+.SH FILES
+.TP 20
+.B *.text
+Compressed documents.
+.TP
+.B *.invf
+Inverted file.
+.TP
+.B *.text.idx.wgt
+Interleaved index into the compressed documents and document weights.
+.TP
+.B *.weight.approx
+Approximate document weights.
+.TP
+.B *.invf.dict.blocked
+Compressed stemmed dictionary and index into the inverted file merged
+into an inverted file.
+.TP
+.B *.text.dict.fast
+Fast loading compression dictionary.
+.TP
+.B *.text.dict
+Compressed compression dictionary.
+.TP
+.B *.invf.dict
+Compressed stemmed dictionary.
+.TP
+.B *.invf.idx
+The index into the inverted file.
+.TP
+.B *.text.stats
+Statistics about the text.
+.TP
+.B *.text.dict.aux
+Auxiliary compression dictionary.
+.TP
+.B *.text.idx
+Index into the compressed documents.
+.TP
+.B *.weight
+The exact weights file.
+.TP
+.B *.invf.chunk
+Maps stemmed terms from occurrence order to lexical order.
+.TP
+.B *.invf.chunk.trans
+Describes where the source text is broken up into chunks for the
+inversion pass.
+.TP
+.B *.invf.dict.hash
+A perfect hash function for the terms in the stemmed dictionary.
+.SH "SEE ALSO"
+.na
+.BR mg (1),
+.BR mg_compression_dict (1),
+.BR mg_fast_comp_dict (1),
+.BR mg_get (1),
+.BR mg_invf_dict (1),
+.BR mg_invf_dump (1),
+.BR mg_invf_rebuild (1),
+.BR mg_passes (1),
+.BR mg_perf_hash_build (1),
+.BR mg_text_estimate (1),
+.BR mg_weights_build (1),
+.BR mgbilevel (1),
+.BR mgbuild (1),
+.BR mgdictlist (1),
+.BR mgfelics (1),
+.BR mgquery (1),
+.BR mgtic (1),
+.BR mgticbuild (1),
+.BR mgticdump (1),
+.BR mgticprune (1),
+.BR mgticstat (1).
Index: /main/tags/2.25/gsdl/packages/mg/man/man1/mgstemidxlist.1
===================================================================
--- /main/tags/2.25/gsdl/packages/mg/man/man1/mgstemidxlist.1	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/mg/man/man1/mgstemidxlist.1	(revision 21064)
@@ -0,0 +1,86 @@
+.\"------------------------------------------------------------
+.\" Id - set Rv,revision, and Dt, Date using rcs-Id tag.
+.de Id
+.ds Rv \\$3
+.ds Dt \\$4
+..
+.Id $Id$
+.\"------------------------------------------------------------
+.TH mgstemidxlist 1 \*(Dt CITRI
+.SH NAME
+mgstemidxlist \- dumps the stem index file to STDOUT in ASCII format
+.SH SYNOPSIS
+.B mgstemidxlist
+[
+.B \-h
+]
+[
+.BI \-d " directory"
+]
+.B \-s 1|2|3
+.BI \-f " name"
+.SH DESCRIPTION
+.B mgstemidxlist
+is a utility program which passes through the stem index and displays
+the information.  (This program was used for debugging but is included
+for completeness!)  The header information is printed out, then for each
+block in the file the block header is displayed.  For each word in the
+stem index, the output is formatted as:
+
+.RS
+.I number_of_references \*(lqword\*(rq
+.br
+.RS
+.I "->  number_of_cases block 3-in-4_block offset"
+.br
+.I "->  ..."
+.RE
+.RE
+.SH OPTIONS
+Options may appear in any order.
+.TP "\w'\fB\-d\fP \fIdirectory\fP'u+2n"
+.B \-h
+This displays a usage line on
+.IR stderr .
+.TP
+.B -s 1|2|3
+The stem index file with the associated stem method.
+.br
+1 = casefolded and non-stemmed
+.br
+2 = non-casefolded and stemmed
+.br
+3 = casefolded and stemmed
+.TP
+.BI \-d " directory"
+This specifies the directory where the document collection can be found.
+.TP
+.BI \-f " name"
+This specifies the base name of the document collection.
+.SH ENVIRONMENT
+.TP "\w'\fBMGDATA\fP'u+2n"
+.SB MGDATA
+If this environment variable exists, then its value is used as the
+default directory where the
+.BR mg (1)
+collection files are.  If this variable does not exist, then the
+directory \*(lq\fB.\fP\*(rq is used by default.  The command line
+option
+.BI \-d " directory"
+overrides the directory in
+.BR MGDATA .
+.SH FILES
+.TP 25
+.B *.invf.dict.blocked.1
+Stem index with stem index method 1.
+.TP
+.B *.invf.dict.blocked.2
+Stem index with stem index method 2.
+.TP
+.B *.invf.dict.blocked.3
+Stem index with stem index method 3.
+.SH "SEE ALSO"
+.na
+.BR mg (1),
+.BR mg_invf_dict (1),
+.BR mg_stem_idx (1).
Index: /main/tags/2.25/gsdl/packages/mg/man/man1/mgtic.1
===================================================================
--- /main/tags/2.25/gsdl/packages/mg/man/man1/mgtic.1	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/mg/man/man1/mgtic.1	(revision 21064)
@@ -0,0 +1,137 @@
+.\"------------------------------------------------------------
+.\" Id - set Rv,revision, and Dt, Date using rcs-Id tag.
+.de Id
+.ds Rv \\$3
+.ds Dt \\$4
+..
+.Id $Id$
+.\"------------------------------------------------------------
+.TH mgtic 1 \*(Dt CITRI
+.SH NAME
+mgtic \- textual image compression.
+.SH SYNOPSIS
+.B mgtic
+.B \-e
+[
+.B \-L
+]
+[
+.B \-Q
+]
+[
+.B \-X
+]
+.I libraryfile
+.I infile
+.if n .ti +9n
+[
+.I \>compressed\-outfile
+]
+.nf
+or
+.fi
+.B mgtic
+.B \-d
+[
+.B \-L
+]
+[
+.BI \-X " libraryfile"
+]
+.I compressed-infile
+.if n .ti +9n
+[
+.I \>outfile
+]
+.SH DESCRIPTION
+This is the main routine in the
+.B mgtic
+system.
+.B mgtic
+is used to
+processes a series of files, and by using the
+.I libraryfile
+produced by
+.BR mgticbuild (1),
+compresses input files with respect to the marks contained in the
+library.  On the CCITT test faxes, lossless mode achieved around 20:1
+compression, and lossy, around 40:1 compression.  On more textual
+images, the amount of compression is determined by the resolution of
+the original file, and the amount of noise in the image.  By default,
+.B mgtic
+will reconstruct a lossy version of the image.  This
+can be changed to lossless by using the
+.B \-L
+option.
+.SH OPTIONS
+Options may appear in any order, but must come before the input
+filenames.
+.TP "\w'\fB\-X\fP \fI[libraryfile]\fP'u+2n"
+.B \-h
+This displays a usage line on
+.IR stderr .
+.TP
+.B \-e
+Encode
+.I infile
+with respect to the library.
+.TP
+.B \-d
+Decodes
+.IR compressed-infile
+with respect to the library.
+.TP
+.B \-l
+This specifies lossy mode, and is the default mode for (de)compression.
+Do not generate the residue.  If used in encoding mode, does not store
+the residue in the output.  If used in decoding mode, the residue (if
+it exists) is ignored.
+.TP
+.B \-L
+Use lossless mode for (de)compression, which generates the residue.
+If used in encoding mode, this stores the residue in the compressed
+output.  If used in decoding mode (assuming the residue is present),
+this allows the original file to be recovered exactly.
+.TP
+.BI \-R\  filename
+Stores the residue as an external file
+.I filename
+which could possibly be stored on another medium.  During
+decompression, if the residue file specified does not relate to the
+compressed file, the resulting decompressed image will be a mess.
+Note that only the width and height of the residue image is checked.
+.TP
+.BI \-Q
+Uses a quicker form of compression.  This option decreases the time
+spent looking for a good match during encoding.  On average this
+option decreases compression ratios, but increases compression speed.
+.TP
+.BI \-X " [libraryfile]"
+Use an external library file, instead of (de)compressing the library
+within the normal stream.  When decoding, the
+.B \-X
+option must be followed by the
+.IR libraryfile .
+.SH "SEE ALSO"
+.na
+.BR mg (1),
+.BR mg_compression_dict (1),
+.BR mg_fast_comp_dict (1),
+.BR mg_get (1),
+.BR mg_invf_dict (1),
+.BR mg_invf_dump (1),
+.BR mg_invf_rebuild (1),
+.BR mg_passes (1),
+.BR mg_perf_hash_build (1),
+.BR mg_text_estimate (1),
+.BR mg_weights_build (1),
+.BR mgbilevel (1),
+.BR mgbuild (1),
+.BR mgdictlist (1),
+.BR mgfelics (1),
+.BR mgquery (1),
+.BR mgstat (1),
+.BR mgticbuild (1),
+.BR mgticdump (1),
+.BR mgticprune (1),
+.BR mgticstat (1).
Index: /main/tags/2.25/gsdl/packages/mg/man/man1/mgticbuild.1
===================================================================
--- /main/tags/2.25/gsdl/packages/mg/man/man1/mgticbuild.1	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/mg/man/man1/mgticbuild.1	(revision 21064)
@@ -0,0 +1,61 @@
+.\"------------------------------------------------------------
+.\" Id - set Rv,revision, and Dt, Date using rcs-Id tag.
+.de Id
+.ds Rv \\$3
+.ds Dt \\$4
+..
+.Id $Id$
+.\"------------------------------------------------------------
+.TH mgticbuild 1 \*(Dt CITRI
+.SH NAME
+mgticbuild \- build a library of marks from training documents
+.SH SYNOPSIS
+.B mgticbuild
+[
+.B \-h
+]
+.I "libraryfile infile1 infile2 .\|.\|."
+.SH DESCRIPTION
+.B mgticbuild
+builds an uncompressed library of marks that have been
+extracted from a series of input files.  If the
+.I libraryfile
+does
+not exist, it is created, otherwise new marks are appended to the
+file.
+.SH OPTIONS
+Options may appear in any order.
+.TP "\w'\fIlibraryfile\fP'u+2n"
+.B \-h
+This displays a usage line on
+.IR stderr .
+.TP
+.I libraryfile
+This specifies the name of the library file.
+.TP
+.I infile(s)
+The training files; the only currently-supported format is
+.IR pbm .
+.SH "SEE ALSO"
+.na
+.BR mg (1),
+.BR mg_compression_dict (1),
+.BR mg_fast_comp_dict (1),
+.BR mg_get (1),
+.BR mg_invf_dict (1),
+.BR mg_invf_dump (1),
+.BR mg_invf_rebuild (1),
+.BR mg_passes (1),
+.BR mg_perf_hash_build (1),
+.BR mg_text_estimate (1),
+.BR mg_weights_build (1),
+.BR mgbilevel (1),
+.BR mgbuild (1),
+.BR mgdictlist (1),
+.BR mgfelics (1),
+.BR mgquery (1),
+.BR mgstat (1),
+.BR mgtic (1),
+.BR mgticdump (1),
+.BR mgticprune (1),
+.BR mgticstat (1).
Index: /main/tags/2.25/gsdl/packages/mg/man/man1/mgticdump.1
===================================================================
--- /main/tags/2.25/gsdl/packages/mg/man/man1/mgticdump.1	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/mg/man/man1/mgticdump.1	(revision 21064)
@@ -0,0 +1,55 @@
+.\"------------------------------------------------------------
+.\" Id - set Rv,revision, and Dt, Date using rcs-Id tag.
+.de Id
+.ds Rv \\$3
+.ds Dt \\$4
+..
+.Id $Id$
+.\"------------------------------------------------------------
+.TH mgticdump 1 \*(Dt CITRI
+.SH NAME
+mgticdump \- displays the library in a user-friendly manner
+.SH SYNOPSIS
+.B mgticdump
+[
+.B \-h
+]
+.I libraryfile
+.SH DESCRIPTION
+.B mgticdump
+displays the marks in a library in a user-viewable form.  The output
+is to
+.I stdout
+and is in a plain ASCII form.
+.SH OPTIONS
+Options may appear in any order.
+.TP "\w'\fIlibraryfile\fP'u+2n"
+.B \-h
+This displays a usage line on
+.IR stderr .
+.TP
+.I libraryfile
+This specifies the name of the library file.
+.SH "SEE ALSO"
+.na
+.BR mg (1),
+.BR mg_compression_dict (1),
+.BR mg_fast_comp_dict (1),
+.BR mg_get (1),
+.BR mg_invf_dict (1),
+.BR mg_invf_dump (1),
+.BR mg_invf_rebuild (1),
+.BR mg_passes (1),
+.BR mg_perf_hash_build (1),
+.BR mg_text_estimate (1),
+.BR mg_weights_build (1),
+.BR mgbilevel (1),
+.BR mgbuild (1),
+.BR mgdictlist (1),
+.BR mgfelics (1),
+.BR mgquery (1),
+.BR mgstat (1),
+.BR mgtic (1),
+.BR mgticbuild (1),
+.BR mgticprune (1),
+.BR mgticstat (1).
Index: /main/tags/2.25/gsdl/packages/mg/man/man1/mgticprune.1
===================================================================
--- /main/tags/2.25/gsdl/packages/mg/man/man1/mgticprune.1	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/mg/man/man1/mgticprune.1	(revision 21064)
@@ -0,0 +1,91 @@
+.\"------------------------------------------------------------
+.\" Id - set Rv,revision, and Dt, Date using rcs-Id tag.
+.de Id
+.ds Rv \\$3
+.ds Dt \\$4
+..
+.Id $Id$
+.\"------------------------------------------------------------
+.TH mgticprune 1 \*(Dt CITRI
+.SH NAME
+mgticprune \- prunes the library to remove duplicates
+.SH SYNOPSIS
+.B mgticprune
+[
+.BI \-a " n"
+]
+[
+.BI \-s " n"
+]
+[
+.B \-Q
+]
+.I libraryfile
+.if n .ti +9n
+[
+.I pruned-libraryfile
+]
+.SH DESCRIPTION
+.B mgticprune
+examines
+.I libraryfile
+and removes duplicate marks.  If
+.I pruned-libraryfile
+is not specified,
+.I libraryfile
+is overwritten with the marks in the pruned library.  The Combined
+Symbol Independent Strategy (CSIS) method is used to match marks.
+.SH OPTIONS
+Options may appear in any order.
+.TP "\w'\fIpruned-libraryfile\fP'u+2n"
+.B \-h
+This displays a usage line on
+.IR stderr .
+.TP
+.BI \-a " n"
+Prune marks when their area is under or equal to the threshold,
+.IR n .
+The default value is\ 3.
+.TP
+.BI \-s " n"
+Prune marks when their width and height is under or equal to
+the threshold,
+.IR n .
+The default value is\ 0.
+.TP
+.BI \-Q
+Use a quicker method of pruning.  The number of iterations through the
+averaging and pruning processes is decreased.  This usually reduces
+time by a half, but compression ratios decrease.
+.TP
+.I libraryfile
+This specifies the name of the library file
+.TP
+.I pruned-libraryfile
+This specifies the name of the prune library, after duplicates and
+matches have been removed.  If this file is not specified, then
+.I libraryfile
+will be overwritten.
+.SH "SEE ALSO"
+.na
+.BR mg (1),
+.BR mg_compression_dict (1),
+.BR mg_fast_comp_dict (1),
+.BR mg_get (1),
+.BR mg_invf_dict (1),
+.BR mg_invf_dump (1),
+.BR mg_invf_rebuild (1),
+.BR mg_passes (1),
+.BR mg_perf_hash_build (1),
+.BR mg_text_estimate (1),
+.BR mg_weights_build (1),
+.BR mgbilevel (1),
+.BR mgbuild (1),
+.BR mgdictlist (1),
+.BR mgfelics (1),
+.BR mgquery (1),
+.BR mgstat (1),
+.BR mgtic (1),
+.BR mgticbuild (1),
+.BR mgticdump (1),
+.BR mgticstat (1).
Index: /main/tags/2.25/gsdl/packages/mg/man/man1/mgticstat.1
===================================================================
--- /main/tags/2.25/gsdl/packages/mg/man/man1/mgticstat.1	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/mg/man/man1/mgticstat.1	(revision 21064)
@@ -0,0 +1,57 @@
+.\"------------------------------------------------------------
+.\" Id - set Rv,revision, and Dt, Date using rcs-Id tag.
+.de Id
+.ds Rv \\$3
+.ds Dt \\$4
+..
+.Id $Id$
+.\"------------------------------------------------------------
+.TH mgticstat 1 \*(Dt CITRI
+.SH NAME
+mgticstat \- displays the statistics for the library
+.SH SYNOPSIS
+.B mgticstat
+[
+.B \-h
+]
+.I libraryfile
+.SH DESCRIPTION
+.B mgticstat
+displays statistics about the
+.I libraryfile
+file.
+The output of this program contains the average mark size, average
+centroid position, and the number of marks with an area less than or
+equal to a few powers of\ 2.
+.SH OPTIONS
+Options may appear in any order.
+.TP "\w'\fIlibraryfile\fP'u+2n"
+.B \-h
+This displays a usage line on
+.IR stderr .
+.TP
+.I libraryfile
+This specifies the name of the library file.
+.SH "SEE ALSO"
+.na
+.BR mg (1),
+.BR mg_compression_dict (1),
+.BR mg_fast_comp_dict (1),
+.BR mg_get (1),
+.BR mg_invf_dict (1),
+.BR mg_invf_dump (1),
+.BR mg_invf_rebuild (1),
+.BR mg_passes (1),
+.BR mg_perf_hash_build (1),
+.BR mg_text_estimate (1),
+.BR mg_weights_build (1),
+.BR mgbilevel (1),
+.BR mgbuild (1),
+.BR mgdictlist (1),
+.BR mgfelics (1),
+.BR mgquery (1),
+.BR mgstat (1),
+.BR mgtic (1),
+.BR mgticbuild (1),
+.BR mgticdump (1),
+.BR mgticprune (1).
Index: /main/tags/2.25/gsdl/packages/mg/man/man1/xmg.1
===================================================================
--- /main/tags/2.25/gsdl/packages/mg/man/man1/xmg.1	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/mg/man/man1/xmg.1	(revision 21064)
@@ -0,0 +1,130 @@
+.\"------------------------------------------------------------
+.\" Id - set Rv,revision, and Dt, Date using rcs-Id tag.
+.de Id
+.ds Rv \\$3
+.ds Dt \\$4
+..
+.Id $Id$
+.\"------------------------------------------------------------
+.TH xmg 1 \*(Dt CITRI
+.SH NAME
+xmg \- An X interface to mgquery
+.SH SYNOPSIS
+.B xmg
+[
+.I collection-name
+]
+.SH DESCRIPTION
+.B xmg
+is an X interface to the
+.BR mg (1)
+information retrieval system.
+.PP
+Type a query in the ``Query'' box.  The escape key clears the query text.
+.PP
+The first line or so of each matching document is listed.
+.PP
+Click on any line to show the complete document.
+.PP
+Shift-click to show the document in a new window.
+.PP
+Press
+.I Next
+and
+.I Previous
+to cycle through the list of documents (shift works here too).
+.PP
+If you change the query, existing windows continue to refer to the
+original query.
+.PP
+You can select either Boolean or ranked queries:
+.RS
+.TP "\w'\fIBoolean queries:\fP'u+2n"
+.I "Boolean queries:"
+use ``&'' for AND, ``|'' for OR, ``!'' for NOT, and parentheses for
+grouping.
+.TP
+.I "Ranked queries:"
+Documents are listed in order of relevance.  A weight is shown
+alongside each.  Weights are normalized to 100 for the most relevant
+document.  Choose
+.I "Approximate Ranking"
+for greater retrieval speed.
+.RE
+.PP
+In document windows (other than the main window):
+.RS
+.br
+Typing `n' = next document;
+.br
+Typing `N' = next document in new window;
+.br
+Typing `p' = previous document;
+.br
+Typing `P' = previous document in new window;
+.br
+Typing `q' = close window.
+.RE
+.SH ENVIRONMENT
+.TP "\w'\fBMGDATA\fP'u+2n"
+.SB MGDATA
+If this environment variable exists, then its value is used as the
+default directory where the
+.BR mg (1)
+collection files are.  If this variable does not exist, then the
+directory \*(lq\fB.\fP\*(rq is used by default.  The command line
+option
+.BI \-d " directory"
+overrides the directory in
+.BR MGDATA .
+.TP
+.SB Xdefaults
+To override the default font options, use RESOURCE_MANAGER properties
+like the following in your
+.I .Xdefaults
+file:
+.IP
+.RS
+.nf
+.I "xmg.textfont: fixed"
+.I "xmg.buttonfont: fixed"
+.fi
+.RE
+.IP
+To override the default query type of ranked, use
+.IP
+.RS
+.I "xmg.querytype: boolean"
+.RE
+.IP
+To override the default collection name (the first one listed by
+.BR ls (1)
+from your MGDATA environment variable), use
+.IP
+.RS
+.I "xmg.collection: mail93"
+.RE
+.SH "SEE ALSO"
+.na
+.BR ls (1),
+.BR mg (1),
+.BR mg_compression_dict (1),
+.BR mg_fast_comp_dict (1),
+.BR mg_get (1),
+.BR mg_invf_dict (1),
+.BR mg_invf_dump (1),
+.BR mg_invf_rebuild (1),
+.BR mg_passes (1),
+.BR mg_perf_hash_build (1),
+.BR mg_text_estimate (1),
+.BR mg_weights_build (1),
+.BR mgbilevel (1),
+.BR mgbuild (1),
+.BR mgdictlist (1),
+.BR mgfelics (1),
+.BR mgquery (1),
+.BR mgtic (1),
+.BR mgticbuild (1),
+.BR mgticdump (1),
+.BR mgticprune (1),
+.BR mgticstat (1).
Index: /main/tags/2.25/gsdl/packages/mg/mkinstalldirs
===================================================================
--- /main/tags/2.25/gsdl/packages/mg/mkinstalldirs	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/mg/mkinstalldirs	(revision 21064)
@@ -0,0 +1,32 @@
+#! /bin/sh
+# mkinstalldirs --- make directory hierarchy
+# Author: Noah Friedman <friedman@prep.ai.mit.edu>
+# Created: 1993-05-16
+# Last modified: 1994-03-25
+# Public domain
+
+errstatus=0
+
+for file in ${1+"$@"} ; do 
+   set fnord `echo ":$file" | sed -ne 's/^:\//#/;s/^://;s/\// /g;s/^#/\//;p'`
+   shift
+
+   pathcomp=
+   for d in ${1+"$@"} ; do
+     pathcomp="$pathcomp$d"
+     case "$pathcomp" in
+       -* ) pathcomp=./$pathcomp ;;
+     esac
+
+     if test ! -d "$pathcomp"; then
+        echo "mkdir $pathcomp" 1>&2
+        mkdir "$pathcomp" || errstatus=$?
+     fi
+
+     pathcomp="$pathcomp/"
+   done
+done
+
+exit $errstatus
+
+# mkinstalldirs ends here
Index: /main/tags/2.25/gsdl/packages/mg/src/images/Makefile.in
===================================================================
--- /main/tags/2.25/gsdl/packages/mg/src/images/Makefile.in	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/mg/src/images/Makefile.in	(revision 21064)
@@ -0,0 +1,216 @@
+###########################################################################
+#
+# Makefile.in -- Makefile for the MG system
+# Copyright (C) 1994  Neil Sharman
+#
+# 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.
+#
+#       @(#)Makefile.in	1.10 22 Mar 1994
+#
+###########################################################################
+
+PACKAGE = @PACKAGE@
+VERSION = @VERSION@
+ 
+SHELL = /bin/sh
+VPATH = @srcdir@
+exec_prefix = @exec_prefix@
+prefix = @prefix@
+srcdir = @srcdir@
+subdir = src/images
+top_srcdir = @top_srcdir@
+transform = @program_transform_name@
+ 
+CC = @CC@
+CFLAGS = @CFLAGS@ 
+CPPFLAGS = @CPPFLAGS@
+DEFS = @DEFS@
+INSTALL = @INSTALL@
+INSTALL_DATA = @INSTALL_DATA@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@
+LDFLAGS = @LDFLAGS@
+LIBS = ../../lib/libmg.a @LIBS@
+GSDLOS = @gsdlos@
+TOUCH = echo timestamp >
+ 
+bindir = ../../../../bin/$(GSDLOS)
+datadir = $(prefix)/share
+libexecdir = $(exec_prefix)/libexec
+localedir = $(datadir)/locale
+mandir = $(prefix)/man/man1
+ 
+COMPILE = $(CC) -c $(DEFS) $(INCLUDES) $(CPPFLAGS) $(CFLAGS)
+LINK = $(CC) $(LDFLAGS) -o $@
+
+.SUFFIXES:
+.SUFFIXES: .c .o
+.c.o:
+	$(COMPILE) $<
+ 
+
+ANSI2KNR = @ANSI2KNR@
+o = .@U@o
+ 
+.SUFFIXES: ._c ._o
+.c._c:
+	./ansi2knr $< > $*.tmp && mv $*.tmp $@
+._c._o:
+	@echo $(COMPILE) $<
+	@rm -f _$*.c
+	@ln $< _$*.c && $(COMPILE) _$*.c && mv _$*.o $@ && rm _$*.c
+.c._o:
+	./ansi2knr $< > $*.tmp && mv $*.tmp $*._c
+	@echo $(COMPILE) $*._c
+	@rm -f _$*.c
+	@ln $*._c _$*.c && $(COMPILE) _$*.c && mv _$*.o $@ && rm _$*.c
+ 
+INCLUDES = -I../../../.. -I../.. -I../../lib -I.
+
+
+SOURCES = \
+  arithcode.c     extractor.c     mgbilevel.c     mgticdump.c     utils.c \
+  bilevel.c       felics.c        mgfelics.c      mgticprune.c    mgticstat.c\
+  codeoffsets.c   marklist.c      mgtic.c         pbmtools.c      lstevent.c \
+  codesyms.c      match.c         mgticbuild.c    sortmarks.c     ppm.c  
+
+
+ 
+HEADERS = \
+  arithcode.h     codeoffsets.h   marklist.h      sortmarks.h \
+  basictypes.h    codesyms.h      match.h         utils.h     \
+  bilevel.h       extractor.h     pbmtools.h      model.h
+
+MISC          = Makefile.in 
+
+ALLFILES      =	$(SOURCES) $(HEADERS) $(MISC) $(MAN)
+
+DISTFILES     = $(ALLFILES) 
+
+EXEC          = mgfelics mgbilevel mgtic mgticbuild mgticprune mgticstat \
+                mgticdump
+
+MAN           = mgfelics.1 mgbilevel.1 mgtic.1 mgticbuild.1  mgticprune.1 \
+                mgticstat.1 mgticdump.1
+
+# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
+
+
+all: $(EXEC)
+
+
+# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
+
+FELICS_OBJS = felics$o mgfelics$o utils$o
+
+mgfelics: $(FELICS_OBJS)
+	$(LINK) $(FELICS_OBJS) $(LIBS)
+
+# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
+
+BILEVEL_OBJS = \
+	arithcode$o bilevel$o extractor$o marklist$o mgbilevel$o \
+	pbmtools$o utils$o
+            
+mgbilevel: $(BILEVEL_OBJS)
+	$(LINK) $(BILEVEL_OBJS) $(LIBS)
+
+# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
+
+TIC_OBJS = \
+	mgtic$o extractor$o marklist$o pbmtools$o utils$o match$o \
+	sortmarks$o codesyms$o ppm$o lstevent$o arithcode$o codeoffsets$o bilevel$o
+
+mgtic: $(TIC_OBJS) 
+	$(LINK) $(TIC_OBJS) $(LIBS) 
+
+TICBUILD_OBJS = mgticbuild$o extractor$o marklist$o pbmtools$o utils$o
+
+mgticbuild: $(TICBUILD_OBJS)
+	$(LINK) $(TICBUILD_OBJS) $(LIBS)
+ 
+TICPRUNE_OBJS = \
+	mgticprune$o extractor$o marklist$o pbmtools$o \
+	utils$o match$o
+
+mgticprune: $(TICPRUNE_OBJS)
+	$(LINK) $(TICPRUNE_OBJS) $(LIBS)
+ 
+TICSTAT_OBJS = mgticstat$o extractor$o marklist$o pbmtools$o utils$o
+
+mgticstat: $(TICSTAT_OBJS)
+	$(LINK) $(TICSTAT_OBJS) $(LIBS) 
+ 
+TICDUMP = mgticdump$o extractor$o marklist$o pbmtools$o utils$o
+
+mgticdump: $(TICDUMP)
+	$(LINK) $(TICDUMP) $(LIBS) 
+ 
+# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
+
+ansi2knr: ansi2knr.o
+	$(LINK) ansi2knr.o $(LIBS)
+
+install: execinstall #maninstall
+uninstall: execuninstall manuninstall
+
+execinstall: $(EXEC)
+	for name in $(EXEC); do \
+	  $(INSTALL_PROGRAM) $$name \
+	  $(bindir)/`echo $$name | sed '$(transform)'`; \
+	done
+
+execuninstall:
+	for name in $(EXEC); do \
+	 rm -f $(bindir)/`echo $$name | sed '$(transform)'`; \
+	done
+
+maninstall: $(MAN)
+	$(top_srcdir)/mkinstalldirs $(mandir); \
+	for f in $(MAN); do \
+	  $(INSTALL_DATA) $$f $(mandir)/$$f ;\
+	done
+
+manuninstall: $(MAN)
+	for f in $(MAN); do \
+	  rm -f $(mandir)/$$f ;\
+	done
+
+
+mostlyclean:
+	rm -f *$o _*.c _*.o *._c *._o core core.*
+ 
+clean: mostlyclean
+	rm -f $(EXEC)
+ 
+distclean: clean
+	rm -f ansi2knr
+	rm -f Makefile
+ 
+maintainer-clean: distclean
+	@echo "This command is intended only for maintainers to use;"
+	@echo "rebuilding the deleted files may require special tools."
+ 
+dist: $(DISTFILES)
+	for file in $(DISTFILES); do \
+	  ln $(srcdir)/$$file $(distdir) 2> /dev/null \
+	  || cp -p $(srcdir)/$$file $(distdir); \
+	done
+ 
+Makefile: Makefile.in ../../../../config.status
+	cd ../../../.. && CONFIG_FILES=$(subdir)/$@ CONFIG_HEADERS= ./config.status
+ 
+# Tell versions [3.59,3.63) of GNU make not to export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:
Index: /main/tags/2.25/gsdl/packages/mg/src/images/WIN32.MAK
===================================================================
--- /main/tags/2.25/gsdl/packages/mg/src/images/WIN32.MAK	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/mg/src/images/WIN32.MAK	(revision 21064)
@@ -0,0 +1,201 @@
+# Generated automatically from Makefile.in by configure.
+###########################################################################
+#
+# Makefile.in -- Makefile for the MG system
+# Copyright (C) 1994  Neil Sharman
+#
+# 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.
+#
+#       @(#)Makefile.in	1.10 22 Mar 1994
+#
+###########################################################################
+
+#PACKAGE = mg
+#VERSION = 1.2
+ 
+#SHELL = /bin/sh
+#exec_prefix = ${prefix}
+#prefix = /home/rpeeters/mg/mg-1.3.2
+#srcdir = .
+#subdir = src/images
+#top_srcdir = ../..
+#transform = s,x,x,
+ 
+CC = cl
+#CFLAGS = -g -O -Wall 
+CPPFLAGS = 
+DEFS = -DHAVE_CONFIG_H -D__WIN32__ -D_LITTLE_ENDIAN
+#INSTALL = /usr/local/gnu/bin/install -c
+#INSTALL_DATA = ${INSTALL} -m 644
+#INSTALL_PROGRAM = ${INSTALL}
+LDFLAGS = 
+LIBS = ..\..\lib\libmg.lib 
+#TOUCH = echo timestamp >
+ 
+#bindir = $(exec_prefix)/bin
+#datadir = $(prefix)/share
+#libexecdir = $(exec_prefix)/libexec
+#localedir = $(datadir)/locale
+#mandir = $(prefix)/man/man1
+ 
+COMPILE = $(CC) -c $(DEFS) -I. -I..\.. -I..\..\lib
+LINK = $(CC) $(LDFLAGS)
+
+.SUFFIXES:
+.SUFFIXES: .c .obj
+.c.obj:
+	$(COMPILE) $<
+ 
+
+o = .obj
+e = .exe
+ 
+
+SOURCES = \
+  arithcode.c     extractor.c     mgbilevel.c     mgticdump.c     utils.c \
+  bilevel.c       felics.c        mgfelics.c      mgticprune.c    mgticstat.c\
+  codeoffsets.c   marklist.c      mgtic.c         pbmtools.c      lstevent.c \
+  codesyms.c      match.c         mgticbuild.c    sortmarks.c     ppm.c  
+
+
+ 
+HEADERS = \
+  arithcode.h     codeoffsets.h   marklist.h      sortmarks.h \
+  basictypes.h    codesyms.h      match.h         utils.h     \
+  bilevel.h       extractor.h     pbmtools.h      model.h
+
+MISC          = Makefile.in 
+
+ALLFILES      =	$(SOURCES) $(HEADERS) $(MISC) $(MAN)
+
+DISTFILES     = $(ALLFILES) 
+
+EXEC          = mgfelics$e mgbilevel$e mgtic$e mgticbuild$e mgticprune$e mgticstat$e \
+                mgticdump$e
+
+MAN           = mgfelics.1 mgbilevel.1 mgtic.1 mgticbuild.1  mgticprune.1 \
+                mgticstat.1 mgticdump.1
+
+# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
+
+
+all: $(EXEC)
+
+
+# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
+
+FELICS_OBJS = felics$o mgfelics$o utils$o
+
+mgfelics$e: $(FELICS_OBJS)
+	$(LINK) $(FELICS_OBJS) $(LIBS)
+
+# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
+
+BILEVEL_OBJS = \
+	arithcode$o bilevel$o extractor$o marklist$o mgbilevel$o \
+	pbmtools$o utils$o
+            
+mgbilevel$e: $(BILEVEL_OBJS)
+	$(LINK) $(BILEVEL_OBJS) $(LIBS)
+
+# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
+
+TIC_OBJS = \
+	mgtic$o extractor$o marklist$o pbmtools$o utils$o match$o \
+	sortmarks$o codesyms$o ppm$o lstevent$o arithcode$o codeoffsets$o bilevel$o
+
+mgtic$e: $(TIC_OBJS) 
+	$(LINK) $(TIC_OBJS) $(LIBS) 
+
+TICBUILD_OBJS = mgticbuild$o extractor$o marklist$o pbmtools$o utils$o
+
+mgticbuild$e: $(TICBUILD_OBJS)
+	$(LINK) $(TICBUILD_OBJS) $(LIBS)
+ 
+TICPRUNE_OBJS = \
+	mgticprune$o extractor$o marklist$o pbmtools$o \
+	utils$o match$o
+
+mgticprune$e: $(TICPRUNE_OBJS)
+	$(LINK) $(TICPRUNE_OBJS) $(LIBS)
+ 
+TICSTAT_OBJS = mgticstat$o extractor$o marklist$o pbmtools$o utils$o
+
+mgticstat$e: $(TICSTAT_OBJS)
+	$(LINK) $(TICSTAT_OBJS) $(LIBS) 
+ 
+TICDUMP = mgticdump$o extractor$o marklist$o pbmtools$o utils$o
+
+mgticdump$e: $(TICDUMP)
+	$(LINK) $(TICDUMP) $(LIBS) 
+ 
+# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
+
+#ansi2knr: ansi2knr.o
+#	$(LINK) ansi2knr.o $(LIBS)
+#
+install: execinstall maninstall
+uninstall: execuninstall manuninstall
+
+#execinstall: $(EXEC)
+#	$(top_srcdir)/mkinstalldirs $(bindir); \
+#	for name in $(EXEC); do \
+#	  $(INSTALL_PROGRAM) $$name \
+#	  $(bindir)/`echo $$name | sed '$(transform)'`; \
+#	done
+
+#execuninstall:
+#	for name in $(EXEC); do \
+#	 rm -f $(bindir)/`echo $$name | sed '$(transform)'`; \
+#	done
+
+maninstall: $(MAN)
+	$(top_srcdir)/mkinstalldirs $(mandir); \
+	for f in $(MAN); do \
+	  $(INSTALL_DATA) $$f $(mandir)/$$f ;\
+	done
+
+manuninstall: $(MAN)
+	for f in $(MAN); do \
+	  rm -f $(mandir)/$$f ;\
+	done
+
+
+mostlyclean:
+	rm -f *$o _*.c _*.o *._c *._o core core.*
+ 
+clean: mostlyclean
+	rm -f $(EXEC)
+ 
+distclean: clean
+	rm -f ansi2knr
+	rm -f Makefile
+ 
+maintainer-clean: distclean
+	@echo "This command is intended only for maintainers to use;"
+	@echo "rebuilding the deleted files may require special tools."
+ 
+#dist: $(DISTFILES)
+#	for file in $(DISTFILES); do \
+#	  ln $(srcdir)/$$file $(distdir) 2> /dev/null \
+#	  || cp -p $(srcdir)/$$file $(distdir); \
+#	done
+ 
+#Makefile: Makefile.in ../../config.status
+#	cd ../.. && CONFIG_FILES=$(subdir)/$@ CONFIG_HEADERS= ./config.status
+ 
+# Tell versions [3.59,3.63) of GNU make not to export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+#.NOEXPORT:
Index: /main/tags/2.25/gsdl/packages/mg/src/images/arithcode.c
===================================================================
--- /main/tags/2.25/gsdl/packages/mg/src/images/arithcode.c	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/mg/src/images/arithcode.c	(revision 21064)
@@ -0,0 +1,471 @@
+/**************************************************************************
+ *
+ * arithcode.c -- Arithmetic coding
+ * Copyright (C) 1994  Alistair Moffat
+ *
+ * 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.
+ *
+ *
+ * $Id$
+ *
+ **************************************************************************
+ *
+ *	Arithmetic encoding. Taken largely from Witten, Neal, Cleary,
+ *		CACM, 1987, p520.
+ *	Includes bitfiddling routines.
+ *
+ **************************************************************************/
+
+#include "sysfuncs.h"
+#include "arithcode.h"
+
+
+FILE *arith_in, *arith_out;
+
+/*
+   $log$
+ */
+
+static char *RCSID = "$Id$";
+
+#undef BECAREFUL
+#define INTEGRATED
+
+
+codevalue S_low = 0, S_high = 0, S_value = 0;
+long S_bitstofollow = 0;
+int S_buffer = 0, S_bitstogo = 0;
+
+long cmpbytes = 0, rawbytes = 0;
+
+#ifdef INTEGRATED
+long CountOfBitsOut;
+#endif
+
+
+/*==================================*/
+
+#define BITPLUSFOLLOW(b)		\
+{	OUTPUTBIT((b));			\
+	while (bitstofollow)		\
+	{	OUTPUTBIT(!(b));	\
+		bitstofollow -= 1;	\
+	}				\
+}
+
+#ifdef INTEGRATED
+#define OUTPUTBIT(b)			\
+{	buffer >>= 1;			\
+	if (b) buffer |= 0x80;	 	\
+	bitstogo -= 1;			\
+	if (bitstogo==0)		\
+	{	putc(buffer, arith_out);	\
+		bitstogo = 8;		\
+		cmpbytes += 1;		\
+	}				\
+	CountOfBitsOut++;		\
+}
+#else
+#define OUTPUTBIT(b)			\
+{	buffer >>= 1;			\
+	if (b) buffer |= 0x80;	 	\
+	bitstogo -= 1;			\
+	if (bitstogo==0)		\
+	{	putc(buffer, arith_out);	\
+		bitstogo = 8;		\
+		cmpbytes += 1;		\
+	}				\
+}
+#endif
+
+#define ADDNEXTINPUTBIT(v)		\
+{	if (bitstogo==0)		\
+	{	buffer = getc(arith_in);	\
+		bitstogo = 8;		\
+	}				\
+	v = (v<<1)+(buffer&1);		\
+	buffer >>= 1;			\
+	bitstogo -=1;			\
+}
+
+/*==================================*/
+
+void
+arithmetic_encode (lbnd, hbnd, totl)
+     int lbnd, hbnd, totl;
+{
+  register codevalue low, high;
+
+#ifdef BECAREFUL
+  if (!(0 <= lbnd && lbnd < hbnd && hbnd <= totl && totl < maxfrequency))
+    {
+      fprintf (stderr, "(corrupt file) coding error: %d %d %d\n", lbnd, hbnd, totl);
+      abort ();
+    }
+#endif
+
+  {
+    register codevalue range;
+    range = S_high - S_low + 1;
+    high = S_low + range * hbnd / totl - 1;
+    low = S_low + range * lbnd / totl;
+  }
+
+  {
+    register codevalue H;
+    register long bitstofollow;
+    register int buffer, bitstogo;
+
+    bitstofollow = S_bitstofollow;
+    buffer = S_buffer;
+    bitstogo = S_bitstogo;
+    H = half;
+
+    for (;;)
+      {
+	if (high < H)
+	  {
+	    BITPLUSFOLLOW (0);
+	  }
+	else if (low >= H)
+	  {
+	    BITPLUSFOLLOW (1);
+	    low -= H;
+	    high -= H;
+	  }
+	else if (low >= firstqtr && high < thirdqtr)
+	  {
+	    bitstofollow++;
+	    low -= firstqtr;
+	    high -= firstqtr;
+	  }
+	else
+	  break;
+	low += low;
+	high += high;
+	high++;
+      }
+    S_bitstofollow = bitstofollow;
+    S_buffer = buffer;
+    S_bitstogo = bitstogo;
+    S_low = low;
+    S_high = high;
+  }
+}
+
+/*==================================*/
+
+/* Made into a macro 
+
+   codevalue
+   arithmetic_decode_target(totl)
+   register int totl;
+   {    return (((S_value-S_low+1)*totl-1) / (S_high -S_low+1));
+   } 
+ */
+
+/*==================================*/
+
+void
+arithmetic_decode (lbnd, hbnd, totl)
+     int lbnd, hbnd, totl;
+{
+  register codevalue low, high;
+
+#ifdef BECAREFUL
+  if (!(0 <= lbnd && lbnd < hbnd && hbnd <= totl && totl < maxfrequency))
+    {
+      fprintf (stderr, "(corrupt file) coding error: %d %d %d\n", lbnd, hbnd, totl);
+      abort ();
+    }
+#endif
+
+  {
+    register codevalue range;
+    range = S_high - S_low + 1;
+    high = S_low + range * hbnd / totl - 1;
+    low = S_low + range * lbnd / totl;
+  }
+
+  {
+    register codevalue value, H;
+    register int buffer, bitstogo;
+
+    buffer = S_buffer;
+    bitstogo = S_bitstogo;
+    H = half;
+    value = S_value;
+
+    for (;;)
+      {
+	if (high < H)
+	  {			/* nothing */
+	  }
+	else if (low >= H)
+	  {
+	    value -= H;
+	    low -= H;
+	    high -= H;
+	  }
+	else if (low >= firstqtr && high < thirdqtr)
+	  {
+	    value -= firstqtr;
+	    low -= firstqtr;
+	    high -= firstqtr;
+	  }
+	else
+	  break;
+	low += low;
+	high += high;
+	high += 1;
+	ADDNEXTINPUTBIT (value);
+      }
+    S_buffer = buffer;
+    S_bitstogo = bitstogo;
+    S_low = low;
+    S_high = high;
+    S_value = value;
+  }
+}
+
+/*==================================*/
+
+
+static void
+startoutputingbits ()
+{
+  S_buffer = 0;
+  S_bitstogo = 8;
+}
+
+static void
+startinputingbits ()
+{
+  S_buffer = 0;
+  S_bitstogo = 0;
+}
+
+static void
+doneoutputingbits ()
+{				/* write another byte if necessary */
+  if (S_bitstogo < 8)
+    {
+      putc (S_buffer >> S_bitstogo, arith_out);
+      cmpbytes += 1;
+    }
+}
+
+/*==================================*/
+
+static void
+startencoding ()
+{
+  S_low = 0;
+  S_high = topvalue;
+  S_bitstofollow = 0;
+}
+
+static void
+startdecoding ()
+{
+  register int i;
+  register int buffer, bitstogo;
+  S_low = 0;
+  S_high = topvalue;
+  S_value = 0;
+  bitstogo = S_bitstogo;
+  buffer = S_buffer;
+  for (i = 0; i < codevaluebits; i++)
+    ADDNEXTINPUTBIT (S_value);
+  S_bitstogo = bitstogo;
+  S_buffer = buffer;
+}
+
+static void
+doneencoding ()
+{
+  register long bitstofollow;
+  register int buffer, bitstogo;
+  bitstofollow = S_bitstofollow;
+  buffer = S_buffer;
+  bitstogo = S_bitstogo;
+  bitstofollow += 1;
+  if (S_low < firstqtr)
+    {
+      BITPLUSFOLLOW (0);
+    }
+  else
+    {
+      BITPLUSFOLLOW (1);
+    }
+  S_bitstofollow = bitstofollow;
+  S_buffer = buffer;
+  S_bitstogo = bitstogo;
+}
+
+
+
+void 
+EncodeGammaDist (int Off)
+/* Encode Off with probability distribution derived from the Elias gamma distribution. */
+{
+  int Len, i;
+
+  Off++;
+  for (Len = 31; Len >= 0 && !(Off & (1 << Len)); Len--);
+
+  for (i = Len; i >= 0; i--)
+    arithmetic_encode (0, 1, 2);
+  arithmetic_encode (1, 2, 2);
+
+  for (i = Len - 1; i >= 0; i--)
+    if (Off & (1 << i))
+      arithmetic_encode (1, 2, 2);
+    else
+      arithmetic_encode (0, 1, 2);
+}
+
+
+
+int 
+DecodeGammaDist ()
+/* Decode next Off using probability distribution derived from the Elias gamma distribution. Inverse of EncodeGammaDist. */
+{
+  int i = 1, Len = 0, bit;
+
+  do
+    {
+      bit = arithmetic_decode_target (2) < 1 ? 0 : 1;
+      if (bit)
+	arithmetic_decode (1, 2, 2);
+      else
+	{
+	  arithmetic_decode (0, 1, 2);
+	  Len++;
+	}
+    }
+  while (!bit);
+
+  Len--;
+  while (Len-- > 0)
+    {
+      bit = arithmetic_decode_target (2) < 1 ? 0 : 1;
+      if (bit)
+	arithmetic_decode (1, 2, 2);
+      else
+	arithmetic_decode (0, 1, 2);
+      i = (i << 1) | bit;
+    }
+  return (i - 1);
+}
+
+
+
+
+
+void 
+EncodeGammaSigned (int snum, int *pos, int *neg)
+{
+  if (snum >= 0)
+    arithmetic_encode (0, *pos, *pos + (*neg)), (*pos)++;
+  else
+    arithmetic_encode (*pos, *pos + (*neg), *pos + (*neg)), (*neg)++;
+  if (*pos + (*neg) >= maxfrequency)
+    {
+      *pos = (*pos + 1) / 2;
+      *neg = (*neg + 1) / 2;
+    }
+  EncodeGammaDist (abs (snum));
+}
+
+
+int 
+DecodeGammaSigned (int *pos, int *neg)
+{
+  int signedpos = 1;
+  if (arithmetic_decode_target (*pos + (*neg)) < *pos)
+    arithmetic_decode (0, *pos, *pos + (*neg)), (*pos)++;
+  else
+    arithmetic_decode (*pos, *pos + (*neg), *pos + (*neg)), (*neg)++, signedpos = 0;
+
+  if (*pos + (*neg) >= maxfrequency)
+    {
+      *pos = (*pos + 1) / 2;
+      *neg = (*neg + 1) / 2;
+    }
+
+  if (signedpos)
+    return DecodeGammaDist ();
+  else
+    return (-DecodeGammaDist ());
+}
+
+
+void 
+InitArithEncoding (void)
+{
+  S_low = 0, S_high = 0, S_value = 0;
+  S_bitstofollow = 0;
+  S_buffer = 0, S_bitstogo = 0;
+  cmpbytes = 0, rawbytes = 0;
+
+  startoutputingbits ();
+  startencoding ();
+}
+
+void 
+InitArithDecoding (void)
+{
+  S_low = 0, S_high = 0, S_value = 0;
+  S_bitstofollow = 0;
+  S_buffer = 0, S_bitstogo = 0;
+  cmpbytes = 0, rawbytes = 0;
+
+  startinputingbits ();
+  startdecoding ();
+}
+
+void 
+CloseDownArithEncoding (void)
+{
+  doneencoding ();
+  doneoutputingbits ();
+}
+
+void 
+CloseDownArithDecoding (void)
+{
+}
+
+
+
+
+
+/* encode that famous number, 42 uses 12 bits */
+void 
+EncodeChecksum ()
+{
+  EncodeGammaDist (42);
+}
+
+void 
+DecodeChecksum (char str[])
+{
+  if (DecodeGammaDist () != 42)
+    {
+      fprintf (stderr, "%s: checksum error, file corrupt.\n", str);
+      exit (1);
+    }
+}
Index: /main/tags/2.25/gsdl/packages/mg/src/images/arithcode.h
===================================================================
--- /main/tags/2.25/gsdl/packages/mg/src/images/arithcode.h	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/mg/src/images/arithcode.h	(revision 21064)
@@ -0,0 +1,78 @@
+/**************************************************************************
+ *
+ * arithcode.h -- Arithmetic coding
+ * Copyright (C) 1994  Alistair Moffat
+ *
+ * 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.
+ *
+ * $Id$
+ *
+ **************************************************************************/
+
+#ifndef _arithcode_h
+#define _arithcode_h
+
+extern FILE *arith_in, *arith_out;
+
+#define codevaluebits 16
+#if (codevaluebits<16)
+typedef unsigned short codevalue;
+#else
+typedef unsigned long codevalue;
+#endif
+
+#define topvalue ((codevalue)((1<<codevaluebits)-1))
+#define maxfrequency ((topvalue+1)/4 + 1)
+
+#define firstqtr (topvalue/4+1)
+#define half     (2*firstqtr)
+#define thirdqtr (3*firstqtr)
+
+#define	escape_event	U->totalcnt-U->notfound, U->totalcnt, U->totalcnt
+
+void arithmetic_encode ();
+codevalue arithmetic_decode_target ();
+
+#define	arithmetic_decode_target(totl)	\
+	(  ((S_value-S_low+1)*(totl)-1) / (S_high-S_low+1)  )
+
+void arithmetic_decode ();
+
+
+extern codevalue S_low, S_high, S_value;
+extern long S_bitstofollow;
+extern int S_buffer, S_bitstogo;
+
+extern long cmpbytes, rawbytes;
+
+extern long CountOfBitsOut;
+
+void EncodeGammaDist (int Off);
+int DecodeGammaDist ();
+
+void EncodeGammaSigned (int snum, int *pos, int *neg);
+int DecodeGammaSigned (int *pos, int *neg);
+
+
+void InitArithEncoding (void);
+void InitArithDecoding (void);
+
+void CloseDownArithEncoding (void);
+void CloseDownArithDecoding (void);
+
+void EncodeChecksum ();
+void DecodeChecksum (char str[]);
+
+#endif
Index: /main/tags/2.25/gsdl/packages/mg/src/images/basictypes.h
===================================================================
--- /main/tags/2.25/gsdl/packages/mg/src/images/basictypes.h	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/mg/src/images/basictypes.h	(revision 21064)
@@ -0,0 +1,34 @@
+/**************************************************************************
+ *
+ * basictypes.h -- base data types
+ * Copyright (C) 1994  Stuart Inglis
+ *
+ * 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.
+ *
+ * $Id$
+ *
+ **************************************************************************
+ *
+ * This file contains information relating to the base data types
+ *
+ **************************************************************************/
+
+#ifndef __basictypes_h
+#define __basictypes_h
+
+typedef unsigned long Pixel;
+
+
+#endif
Index: /main/tags/2.25/gsdl/packages/mg/src/images/bilevel.c
===================================================================
--- /main/tags/2.25/gsdl/packages/mg/src/images/bilevel.c	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/mg/src/images/bilevel.c	(revision 21064)
@@ -0,0 +1,747 @@
+/**************************************************************************
+ *
+ * bilevel.c -- Compress a bilevel bitmap
+ * Copyright (C) 1994  Stuart Inglis
+ *
+ * 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.
+ *
+ * $Id$
+ *
+ **************************************************************************
+ *
+ *  
+ *  
+ *  This is the code used to compress a bitmap.  The template is given in
+ *  the following format. 
+ *   '.'  = pixel not used
+ *   'p'  = pixel used in 1st order context (the superset)
+ *   '2'  = pixel used in 2nd order context (the subset)
+ *   ';'  = marker used to denote the end of a row in the template
+ *   '*'  = the current context pixel.
+ *  for instance, the common 22/10 template would be shown as:
+ *     ".ppppp.;"
+ *     "pp222pp;"
+ *     "p22222p;"
+ *     "p22*...;"
+ * 
+ **************************************************************************/
+
+
+#include "sysfuncs.h"
+
+#include "bilevel.h"
+#include "extractor.h"
+#include "pbmtools.h"
+#include "marklist.h"
+#include "arithcode.h"
+#include "utils.h"
+
+
+
+#define INITVALUE 2
+#define INCREMENT 4
+
+#define MAX_T_W 32
+
+/* note memory usage is 2*TEMPLATESIZE*sizeof(prob), which is currently 4.9 Mb */
+#define TEMPLATESIZE 612317
+
+
+#define HASH(x) ((x)%TEMPLATESIZE)
+
+
+typedef struct
+  {
+    unsigned short s, n;
+  }
+prob;				/* set and notset */
+typedef struct
+  {
+    short int x, y;
+  }
+coordinate;
+
+coordinate MM[MAX_T_W][MAX_T_W];	/* the actual (x,y) positions */
+unsigned int MMcount[MAX_T_W];	/* number of bits in this row of the template */
+unsigned int MMmask[MAX_T_W];	/* the "current" mask value */
+unsigned int MMbits[MAX_T_W];	/* the bitmask to mask out higher bits */
+unsigned int MMrows;		/* total number of rows */
+unsigned int MM2level[MAX_T_W];	/* bitmask to calculate the 2nd level mask */
+int twolevel, curr_row, surr;
+
+prob *P = NULL;			/* probability array, up to N bits */
+prob *P2 = NULL;
+
+void 
+bl_clearmodel ()
+{
+  int i;
+
+  P = (prob *) malloc (TEMPLATESIZE * sizeof (prob));
+  if (!P)
+    error_msg ("bl_clearmodel()", "not enough memory.", "");
+
+  P2 = (prob *) malloc (TEMPLATESIZE * sizeof (prob));
+  if (!P2)
+    error_msg ("bl_clearmodel()", "not enough memory.", "");
+
+  for (i = 0; i < TEMPLATESIZE; i++)
+    {
+      P[i].s = P[i].n = INITVALUE;
+      P2[i].s = P2[i].n = INITVALUE;
+    }
+}
+
+
+void 
+bl_freemodel ()
+{
+  free (P);
+  free (P2);
+}
+
+
+
+
+#define update_counts(p, pixel)                        \
+    pixel ? (p->s+=INCREMENT) : (p->n+=INCREMENT);     \
+                                                       \
+    if(p->s+p->n >= (unsigned)(maxfrequency)) {        \
+       p->s=(p->s+1)/(unsigned)2;                      \
+       p->n=(p->n+1)/(unsigned)2;                      \
+    }
+
+
+
+
+/* mask is the bigger one, mask2l is smaller one */
+static void 
+bl_encode_in_context (unsigned long mask, unsigned long mask2l, unsigned long pixel)
+{
+  register int twol, t;
+  prob *p = &P[mask];
+  prob *p2 = &P2[mask2l];
+
+  twol = twolevel && (p->s + p->n < (unsigned) (2 * INITVALUE + 5 * INCREMENT));
+
+  t = twol ? (p2->s + p2->n) : (p->s + p->n);
+
+  if (twol == 0)
+    {
+      if (pixel)
+	arithmetic_encode (0, p->s, t);
+      else
+	arithmetic_encode (p->s, t, t);
+      update_counts (p, pixel);
+    }
+  else
+    {
+      if (pixel)
+	arithmetic_encode (0, p2->s, t);
+      else
+	arithmetic_encode (p2->s, t, t);
+      update_counts (p2, pixel);
+      update_counts (p, pixel);
+    }
+}
+
+
+static void 
+bl_decode_in_context (unsigned long mask, unsigned long mask2l, unsigned long *val)
+{
+  register int twol, pixel, t;
+  prob *p = &P[mask];
+  prob *p2 = &P2[mask2l];
+
+
+  if (twolevel && (p->s + p->n < (unsigned) (2 * INITVALUE + 5 * INCREMENT)))
+    {
+      pixel = arithmetic_decode_target (p2->s + p2->n) < p2->s, twol = 1;
+    }
+  else
+    {
+      pixel = arithmetic_decode_target (p->s + p->n) < p->s, twol = 0;
+    }
+
+  t = twol ? (p2->s + p2->n) : (p->s + p->n);
+
+  if (twol == 0)
+    {
+      if (pixel)
+	arithmetic_decode (0, p->s, t);
+      else
+	arithmetic_decode (p->s, t, t);
+      update_counts (p, pixel);
+    }
+  else
+    {
+      if (pixel)
+	arithmetic_decode (0, p2->s, t);
+      else
+	arithmetic_decode (p2->s, t, t);
+      update_counts (p2, pixel);
+      update_counts (p, pixel);
+    }
+
+  *val = pixel;
+}
+
+static void 
+bl_string_to_array (char inputstr[], char parsestr[], int *w, int *h)
+{
+  int r, c;
+  int i, j, lastc, p, l;
+  int xc, yc;
+  int foundstatus;
+
+  surr = twolevel = 0;
+  for (i = 0; i < MAX_T_W; i++)
+    MMcount[i] = MM2level[i] = 0;
+  MMrows = 0;
+
+  for (i = 0; i < (int) strlen (inputstr); i++)
+    {
+      p = inputstr[i];
+      if ((p != '.') && (p != '2') && (p != '*') && (p != 'p') && (p != ';'))
+	{
+	  fprintf (stderr, "Template string can only contain [.p2*;], not \"%c\".\n", inputstr[i]);
+	  exit (1);
+	}
+    }
+
+  /* get the width and height, test rectangularity... */
+  parsestr[l = 0] = 0;
+  for (c = 0, r = 0, lastc = -1, p = 0; p < (int) strlen (inputstr); p++)
+    {
+      if ((inputstr[p] == ';'))
+	{
+	  r++;
+	  if (lastc != -1)
+	    {			/* this is the 2nd row at least */
+	      if (lastc != c)
+		{
+		  fprintf (stderr, "The rows have to be the same width. "
+			   "Row %d has width %d (previous row has width %d)\n", r, c, lastc);
+		  exit (1);
+		}
+	    }
+	  lastc = c;
+	  c = 0;
+	}
+      else
+	{
+	  c++;
+	  parsestr[l] = inputstr[p];
+	  parsestr[++l] = 0;
+	}
+    }
+
+  if (c != 0)
+    lastc = c;
+  *w = lastc;
+  *h = r;
+  if ((*w) <= 0)
+    {
+      fprintf (stderr, "Must have at least one column!\n");
+      exit (1);
+    }
+  if ((*h) <= 0)
+    {
+      fprintf (stderr, "Must have at least one row! Terminate each row with a ';'\n");
+      exit (1);
+    }
+  if ((*w > MAX_T_W) || (*h > MAX_T_W))
+    {
+      fprintf (stderr, "template size bigger than internal threshold of %d\n", MAX_T_W);
+      exit (1);
+    }
+
+  /* get the (x,y) position of the current (*) pixel */
+  for (xc = -1, yc = 0, i = 0; i < *w; i++)
+    for (j = 0; j < *h; j++)
+      if (parsestr[j * (*w) + i] == '*')
+	{
+	  if (xc >= 0)
+	    {
+	      fprintf (stderr, "There can only be ONE current ('*') pixel.\n");
+	      exit (1);
+	    }
+	  xc = i;
+	  yc = j;
+	  curr_row = j + 1;
+	}
+  if (xc < 0)
+    error_msg ("bl_string_to_array", "Error in mask, no current ('*') pixel.", "");
+  /* found the position (xc,yc) */
+
+
+  /* convert parsestr[] into a MM[][] structure */
+  for (j = 0; j < *h; j++)
+    {
+      foundstatus = 0;
+      for (i = 0; i < *w; i++)
+	{
+	  p = j * (*w) + i;
+	  if ((parsestr[p] == 'p') || (parsestr[p] == '2'))
+	    {
+	      if (!foundstatus)
+		foundstatus = 1;
+	      MM2level[j] = MM2level[j] * 2 | (parsestr[p] == '2');
+	      if (parsestr[p] == '2')
+		twolevel = 1;
+
+	      MM[j][MMcount[j]].x = i - xc;
+	      MM[j][MMcount[j]++].y = j - yc;
+	      if (((i - xc) >= 0) && ((j - yc) >= 0))
+		surr = 1;
+	    }
+	  else
+	    {
+	      if (foundstatus == 1)
+		foundstatus = 2;
+	    }
+
+	}
+      if (foundstatus)
+	MMrows++;
+      MMbits[j] = (1 << MMcount[j]) - 1;
+    }
+
+  /* reverse matrix, so [][0] is the closest to the right */
+  {
+    coordinate temp;
+    for (i = 0; i < MMrows; i++)
+      for (j = 0; j < MMcount[i] / (unsigned) 2; j++)
+	{
+	  temp = MM[i][MMcount[i] - 1 - j];
+	  MM[i][MMcount[i] - 1 - j] = MM[i][j];
+	  MM[i][j] = temp;
+	}
+  }
+}
+
+
+
+
+
+
+
+
+void 
+bl_writetemplate (char inputstr[])
+{
+  register int i, j;
+  int w, h;
+  char ind[255];
+  char *str;
+
+  str = (char *) malloc (strlen (inputstr) * sizeof (char) + 2);
+
+  bl_string_to_array (inputstr, str, &w, &h);
+
+  EncodeGammaDist (surr);
+  EncodeGammaDist (w);
+  EncodeGammaDist (h);
+  ind['.'] = 0;
+  ind['p'] = 1;
+  ind['2'] = 2;
+  ind['*'] = 3;
+  for (j = 0; j < h; j++)
+    for (i = 0; i < w; i++)
+      EncodeGammaDist (ind[(int) str[j * w + i]]);
+
+  free (str);
+}
+
+
+void 
+bl_readtemplate ()
+{
+  register int i, j;
+  int w, h, p;
+  char ind[4];
+  char *inputstr, *str;
+
+  surr = DecodeGammaDist (surr);
+  if (surr)
+    {
+      fprintf (stderr, "It's fine compressing an image using a 'surrounding' template, but I can't "
+	       "decompress it!\n");
+      exit (1);
+    }
+  w = DecodeGammaDist ();
+  h = DecodeGammaDist ();
+
+  inputstr = (char *) malloc ((w + 2) * h * sizeof (char) + 2);
+  ind[0] = '.';
+  ind[1] = 'p';
+  ind[2] = '2';
+  ind[3] = '*';
+  for (p = 0, j = 0; j < h; j++)
+    {
+      for (i = 0; i < w; i++)
+	{
+	  inputstr[p++] = ind[DecodeGammaDist ()];
+	}
+      inputstr[p++] = ';';
+      inputstr[p] = 0;
+    }
+
+  str = (char *) malloc (strlen (inputstr) * sizeof (char) + 2);
+  bl_string_to_array (inputstr, str, &w, &h);
+}
+
+
+
+
+
+/* Currently if there are more than 32 bits, the topmost 32 will be discarded, if the 
+   topbits are to be used in compression, define _MORETHAN32 */
+#undef _MORETHAN32
+
+void 
+bl_compress_mark (marktype d)
+{
+  register int r, c;
+  register int i, j;
+  register unsigned long mask, mask2level;
+  char *array[MAX_T_W];
+
+
+  for (i = 0; i < MAX_T_W; i++)
+    {
+      array[i] = (char *) calloc ((size_t) d.w + 2 * MAX_T_W + 1, (size_t) sizeof (char));
+      array[i] = array[i] + MAX_T_W;
+    }
+
+  EncodeGammaDist (d.w);
+  EncodeGammaDist (d.h);
+
+  for (r = 0; r < min (curr_row, d.h); r++)
+    for (c = 0; c < d.w; c++)
+      array[r % MAX_T_W][c] = pbm_getpixel (d.bitmap, c, r);
+
+  for (r = 0; r < d.h; r++)
+    {
+      if (V)
+	if (r && (r % 200 == 0))
+	  fprintf (stderr, ".");
+
+      if (r + curr_row < d.h)
+	for (c = 0; c < d.w; c++)
+	  array[(r + curr_row) % MAX_T_W][c] = pbm_getpixel (d.bitmap, c, r + curr_row);
+      else
+	for (c = 0; c < d.w; c++)
+	  array[(r + curr_row) % MAX_T_W][c] = 0;
+
+      for (c = 0; c < d.w; c++)
+	{
+	  for (mask = 0, mask2level = 0, i = 0; i < MMrows; i++)
+	    {
+	      if (c != 0)
+		{
+		  MMmask[i] = (MMmask[i] * 2);
+		  MMmask[i] |= array[(r + MM[i][0].y + MAX_T_W) % MAX_T_W][c + MM[i][0].x];
+		}
+	      else
+		{
+		  for (MMmask[i] = 0, j = MMcount[i] - 1; j >= 0; j--)
+		    MMmask[i] = 2 * MMmask[i] | array[(r + MM[i][j].y + MAX_T_W) % MAX_T_W][c + MM[i][j].x];
+		}
+	      MMmask[i] &= MMbits[i];
+#ifdef _MORETHAN32
+	      mask = ((mask * 8191) << MMcount[i]) | MMmask[i];
+	      mask2level = ((mask2level * 499) << MMcount[i]) | (MMmask[i] & MM2level[i]);
+#else
+	      mask = (mask << MMcount[i]) | MMmask[i];
+	      mask2level = (mask2level << MMcount[i]) | (MMmask[i] & MM2level[i]);
+#endif
+	    }
+
+	  mask = HASH (mask);
+	  mask2level = HASH (mask2level);
+
+	  bl_encode_in_context (mask, mask2level, pbm_getpixel (d.bitmap, c, r));
+	}
+    }
+  for (i = 0; i < MAX_T_W; i++)
+    free (array[i] - MAX_T_W);
+}
+
+
+
+void 
+bl_decompress_mark (marktype * d)
+{
+  register int r, c;
+  register int i, j;
+  unsigned long pix;
+  register unsigned long mask, mask2level;
+  char *array[MAX_T_W];
+
+
+  d->w = DecodeGammaDist ();
+  d->h = DecodeGammaDist ();
+
+  d->bitmap = pbm_allocarray (d->w, d->h);
+  for (i = 0; i < MAX_T_W; i++)
+    {
+      array[i] = (char *) calloc ((size_t) d->w + 2 * MAX_T_W + 1, (size_t) sizeof (char));
+      array[i] = array[i] + MAX_T_W;
+    }
+
+  for (r = 0; r < d->h; r++)
+    {
+      if (V)
+	if (r && (r % 200 == 0))
+	  fprintf (stderr, ".");
+      for (c = 0; c < d->w; c++)
+	array[r % MAX_T_W][c] = pbm_getpixel (d->bitmap, c, r);
+      for (c = 0; c < d->w; c++)
+	{
+	  for (mask = 0, mask2level = 0, i = 0; i < MMrows; i++)
+	    {
+	      if (c != 0)
+		{
+		  MMmask[i] = (MMmask[i] * 2);
+		  MMmask[i] |= array[(r + MM[i][0].y + MAX_T_W) % MAX_T_W][c + MM[i][0].x];
+		}
+	      else
+		{
+		  for (MMmask[i] = 0, j = MMcount[i] - 1; j >= 0; j--)	/* get all pixels */
+		    MMmask[i] = 2 * MMmask[i] | array[(r + MM[i][j].y + MAX_T_W) % MAX_T_W][c + MM[i][j].x];
+		}
+	      MMmask[i] &= MMbits[i];
+
+#ifdef _MORETHAN32
+	      mask = ((mask * 8191) << MMcount[i]) | MMmask[i];
+	      mask2level = ((mask2level * 499) << MMcount[i]) | (MMmask[i] & MM2level[i]);
+#else
+	      mask = (mask << MMcount[i]) | MMmask[i];
+	      mask2level = (mask2level << MMcount[i]) | (MMmask[i] & MM2level[i]);
+#endif
+	    }
+
+	  mask = HASH (mask);
+	  mask2level = HASH (mask2level);
+
+	  bl_decode_in_context (mask, mask2level, &pix);
+	  if (pix)
+	    {
+	      pbm_putpixel (d->bitmap, c, r, pix);
+	      array[r % MAX_T_W][c] = pix;
+	    }
+	}
+    }
+  for (i = 0; i < MAX_T_W; i++)
+    free (array[i] - MAX_T_W);
+}
+
+
+
+void 
+bl_compress (marktype d, char inputstr[])
+{
+  bl_clearmodel ();
+  bl_writetemplate (inputstr);
+  bl_compress_mark (d);
+  bl_freemodel ();
+}
+
+
+void 
+bl_decompress (marktype * d)
+{
+  bl_clearmodel ();
+  bl_readtemplate ();
+  bl_decompress_mark (d);
+  bl_freemodel ();
+}
+
+
+
+
+
+
+/* 
+   The bitmap in d2, can be examined clairvoyantly.  The ordering of the
+   params is therefore non-clairvoyant, and clairvoyant in that order.
+
+ */
+/*
+   coordinate M1[6]={        { 0,-2},
+   {-1,-1},{ 0,-1}, {1,-1},
+   {-2,0},  {-1, 0}};
+   };
+   coordinate M2[13]={       { 0,-2},
+   {-1,-1}, { 0,-1},   {1, -1},
+   {-2,0}, {-1, 0}, { 0, 0},   { 1, 0},  {2,0},
+   {-1, 1}, { 0, 1},   { 1, 1},
+   { 0, 2}
+ */
+
+coordinate M1[6] =
+{
+  {0, -2},
+  {-2, 0},
+  {1, -1},
+  {-1, -1},
+  {0, -1},
+  {-1, 0}};
+coordinate M2[13] =
+{
+  {0, -2},
+  {1, -1},
+  {-2, 0},
+  {2, 0},
+  {-1, 1},
+  {1, 1},
+  {0, 2},
+  {-1, -1},
+  {0, -1},
+  {1, 0},
+  {-1, 0},
+  {0, 1},
+  {0, 0}
+};
+#define M1S 6
+#define M1S_2level 3
+#define M2S 13
+#define M2S_2level 6
+
+
+void 
+bl_clair_compress (marktype d1, marktype d2)
+{
+  register int r, c;
+  register int i, j, n;
+  register unsigned long mask, mask2level = 0;
+  int cols, rows;
+  int gap;
+  Pixel **b1, **b2;
+
+
+  bl_clearmodel ();
+  twolevel = 1;
+
+  b1 = d1.bitmap;
+  b2 = d2.bitmap;
+  cols = d1.w;
+  rows = d1.h;
+
+  gap = max (50, rows / 10);
+
+  EncodeGammaDist (cols);
+  EncodeGammaDist (rows);
+
+  for (r = 0; r < rows; r++)
+    {
+      if (V)
+	if (!(r % gap))
+	  fprintf (stderr, ".");
+      for (c = 0; c < cols; c++)
+	{
+
+	  mask = 0;
+	  for (n = 0; n < M1S; n++)
+	    {
+	      i = c + M1[n].x;
+	      j = r + M1[n].y;
+	      mask = (2 * mask) | pbm_getpixel_trunc (b1, i, j, cols, rows);
+	    }
+
+	  mask2level = mask & ((1 << M1S_2level) - 1);
+
+	  for (n = 0; n < M2S; n++)
+	    {
+	      i = c + M2[n].x;
+	      j = r + M2[n].y;
+	      mask = (2 * mask) | pbm_getpixel_trunc (b2, i, j, cols, rows);
+	    }
+
+	  mask2level = (mask2level << M2S_2level) | (mask & ((1 << M2S_2level) - 1));
+
+	  bl_encode_in_context (mask, mask2level, pbm_getpixel (b1, c, r));
+
+	}
+    }
+  if (V)
+    fprintf (stderr, "\n");
+  bl_freemodel ();
+}
+
+
+void 
+bl_clair_decompress (marktype d1, marktype d2)
+{
+  register int r, c;
+  register int i, j, n;
+  register unsigned long mask, mask2level = 0;
+  unsigned long p;
+  int cols, rows;
+  int gap;
+  Pixel **b1, **b2;
+
+  bl_clearmodel ();
+  twolevel = 1;
+
+  b1 = d1.bitmap;
+  b2 = d2.bitmap;
+  cols = d1.w;
+  rows = d1.h;
+
+  gap = max (50, rows / 10);
+
+  i = DecodeGammaDist ();
+  j = DecodeGammaDist ();
+  if ((i != cols) || (j != rows))
+    error_msg ("bl_clair_decompress", "incorrect size of residue image", "");
+
+  if (V)
+    fprintf (stderr, "cols=%d rows=%d\n", cols, rows);
+
+  for (r = 0; r < rows; r++)
+    {
+      if (V)
+	if (!(r % gap))
+	  fprintf (stderr, ".");
+      for (c = 0; c < cols; c++)
+	{
+	  mask = 0;
+	  for (n = 0; n < M1S; n++)
+	    {
+	      i = c + M1[n].x;
+	      j = r + M1[n].y;
+	      mask = (2 * mask) | pbm_getpixel_trunc (b1, i, j, cols, rows);
+	    }
+	  mask2level = mask & ((1 << M1S_2level) - 1);
+	  for (n = 0; n < M2S; n++)
+	    {
+	      i = c + M2[n].x;
+	      j = r + M2[n].y;
+	      mask = (2 * mask) | pbm_getpixel_trunc (b2, i, j, cols, rows);
+	    }
+	  mask2level = (mask2level << M2S_2level) | (mask & ((1 << M2S_2level) - 1));
+
+
+	  bl_decode_in_context (mask, mask2level, &p);
+	  if (p)
+	    pbm_putpixel (b1, c, r, 1);
+	}
+    }
+  if (V)
+    fprintf (stderr, "\n");
+  bl_freemodel ();
+}
Index: /main/tags/2.25/gsdl/packages/mg/src/images/bilevel.h
===================================================================
--- /main/tags/2.25/gsdl/packages/mg/src/images/bilevel.h	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/mg/src/images/bilevel.h	(revision 21064)
@@ -0,0 +1,47 @@
+/**************************************************************************
+ *
+ * bilevel.h -- Compress a bilevel bitmap
+ * Copyright (C) 1994  Stuart Inglis
+ *
+ * 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.
+ *
+ * $Id$
+ *
+ **************************************************************************/
+
+#ifndef __BILEVEL_H
+#define __BILEVEL_H
+
+#include "marklist.h"
+
+/* must be called before the start of de/compression */
+void bl_clearmodel ();
+void bl_freemodel ();
+
+/* writes the template to the stream, and sets up the de/compression params */
+void bl_writetemplate (char inputstr[]);
+void bl_readtemplate ();
+
+/* actually performs the de/compression */
+void bl_compress (marktype d, char str[]);
+void bl_compress_mark (marktype d);
+void bl_decompress (marktype * d);
+void bl_decompress_mark (marktype * d);
+
+/* clairvoyantly de/compress d1 with respect to clairvoyantly viewable d2 */
+void bl_clair_compress (marktype d1, marktype d2);
+void bl_clair_decompress (marktype d1, marktype d2);
+
+#endif
Index: /main/tags/2.25/gsdl/packages/mg/src/images/codeoffsets.c
===================================================================
--- /main/tags/2.25/gsdl/packages/mg/src/images/codeoffsets.c	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/mg/src/images/codeoffsets.c	(revision 21064)
@@ -0,0 +1,257 @@
+/**************************************************************************
+ *
+ * codeoffsets.c -- Functions which code the mark offsets
+ * Copyright (C) 1994  Stuart Inglis
+ *
+ * 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.
+ *
+ * $Id$
+ *
+ **************************************************************************/
+
+#include "sysfuncs.h"
+
+#include "marklist.h"
+#include "arithcode.h"
+#include "utils.h"
+
+#define TOP_INC 2
+#define MID_INC 1
+#define BOT_INC 1
+
+
+void 
+EncodeOffsets (marklistptr symbol_list, int nsyms)
+{
+  int xpos = 1, xneg = 1, ypos = 1, yneg = 1;
+  marklistptr step;
+  int found;
+  int dox = 0, leveltop = 1, levelmid = 1, levelbot = 1;
+  elemlist xlist, ylist;	/* all previous offsets */
+  int p, f, t, xoff, yoff, symnum, count;
+  elemlist *xcond, *ycond;	/* previous offsets conditioned on symbol num */
+
+  xcond = (elemlist *) malloc (nsyms * sizeof (elemlist));
+  if (!xcond)
+    error_msg ("EncodeOffsets", "Out of memory...", "");
+  ycond = (elemlist *) malloc (nsyms * sizeof (elemlist));
+  if (!ycond)
+    error_msg ("EncodeOffsets", "Out of memory...", "");
+
+  for (t = 0; t < nsyms; t++)
+    {
+      xcond[t].head = ycond[t].head = NULL;
+      xcond[t].tot = ycond[t].tot = 0;
+    }
+  xlist.head = NULL;
+  xlist.tot = 0;
+  ylist.head = NULL;
+  ylist.tot = 0;
+  for (step = symbol_list, count = 0; step; step = step->next, count++)
+    {
+      xoff = step->data.xoffset;
+      yoff = step->data.yoffset;
+      symnum = step->data.symnum;
+      for (dox = 1; dox >= 0; dox--)
+	{
+	  /* encode the offsets, x first then y */
+
+	  if (dox)
+	    found = elem_find (&xcond[symnum], xoff, &p, &f, &t);
+	  else
+	    found = elem_find (&ycond[symnum], yoff, &p, &f, &t);
+
+	  if (found)
+	    {
+	      arithmetic_encode (0, leveltop, leveltop + levelmid + levelbot);
+	      leveltop += TOP_INC;
+	      arithmetic_encode (p, f, t);
+	    }
+	  else
+	    {
+	      if (dox)
+		found = elem_find (&xlist, xoff, &p, &f, &t);
+	      else
+		found = elem_find (&ylist, yoff, &p, &f, &t);
+
+	      if (found)
+		{
+		  arithmetic_encode (leveltop, leveltop + levelmid, leveltop + levelmid + levelbot);
+		  levelmid += MID_INC;
+		  arithmetic_encode (p, f, t);
+		}
+	      else
+		{
+		  arithmetic_encode (leveltop + levelmid, leveltop + levelmid + levelbot, leveltop + levelmid + levelbot);
+		  levelbot += BOT_INC;
+		  if (dox)
+		    EncodeGammaSigned (xoff, &xpos, &xneg);
+		  else
+		    EncodeGammaSigned (yoff, &ypos, &yneg);
+		}
+	    }
+	  if (dox)
+	    {
+	      elem_add (&xlist, xoff);
+	      elem_add (&xcond[symnum], xoff);
+	    }
+	  else
+	    {
+	      elem_add (&ylist, yoff);
+	      elem_add (&ycond[symnum], yoff);
+	    }
+
+	  if (leveltop + levelmid >= maxfrequency)
+	    {
+	      leveltop = (leveltop + 1) / 2;
+	      levelmid = (levelmid + 1) / 2;
+	      levelbot = (levelbot + 1) / 2;
+	    }
+	}
+    }
+  for (t = 0; t < nsyms; t++)
+    {
+      elem_free (&xcond[t]);
+      elem_free (&ycond[t]);
+    }
+  elem_free (&xlist);
+  elem_free (&ylist);
+  if (V)
+    fprintf (stderr, "offset models: top %d, mid %d, bot %d\n", (leveltop - 1) / TOP_INC, (levelmid - 1) / MID_INC, (levelbot - 1) / BOT_INC);
+}
+
+
+
+
+
+void 
+DecodeOffsets (marklistptr symbol_list, int nsyms)
+{
+  int xpos = 1, xneg = 1, ypos = 1, yneg = 1;
+  marklistptr step;
+  int i, target, dox;
+  int leveltop = 1, levelmid = 1, levelbot = 1;
+  elemlist xlist, ylist;
+  int p, f, t, xoff = 0, yoff = 0, symnum, count = 0;
+  elemlist *xcond, *ycond;
+
+  xcond = (elemlist *) malloc (nsyms * sizeof (elemlist));
+  if (!xcond)
+    error_msg ("EncodeOffsets", "Out of memory...", "");
+  ycond = (elemlist *) malloc (nsyms * sizeof (elemlist));
+  if (!ycond)
+    error_msg ("EncodeOffsets", "Out of memory...", "");
+
+  for (i = 0; i < nsyms; i++)
+    {
+      xcond[i].head = ycond[i].head = NULL;
+      xcond[i].tot = ycond[i].tot = 0;
+    }
+
+  xlist.head = NULL;
+  xlist.tot = 0;
+  ylist.head = NULL;
+  ylist.tot = 0;
+
+  for (step = symbol_list, count = 0; step; step = step->next, count++)
+    {
+      symnum = step->data.symnum;
+      for (dox = 1; dox >= 0; dox--)
+	{
+	  /* decode x offset first, then y */
+	  target = arithmetic_decode_target (leveltop + levelmid + levelbot);
+	  if (target < leveltop)
+	    {
+	      arithmetic_decode (0, leveltop, leveltop + levelmid + levelbot);
+	      leveltop += TOP_INC;
+
+	      if (dox)
+		i = arithmetic_decode_target (xcond[symnum].tot);
+	      else
+		i = arithmetic_decode_target (ycond[symnum].tot);
+
+	      if (dox)
+		{
+		  elem_getrange (&xcond[symnum], i, &xoff);
+		  elem_find (&xcond[symnum], xoff, &p, &f, &t);
+		}
+	      else
+		{
+		  elem_getrange (&ycond[symnum], i, &yoff);
+		  elem_find (&ycond[symnum], yoff, &p, &f, &t);
+		}
+	      arithmetic_decode (p, f, t);
+	    }
+	  else if (target < leveltop + levelmid)
+	    {
+	      arithmetic_decode (leveltop, leveltop + levelmid, leveltop + levelmid + levelbot);
+	      levelmid += MID_INC;
+
+	      if (dox)
+		i = arithmetic_decode_target (xlist.tot);
+	      else
+		i = arithmetic_decode_target (ylist.tot);
+
+	      if (dox)
+		{
+		  elem_getrange (&xlist, i, &xoff);
+		  elem_find (&xlist, xoff, &p, &f, &t);
+		}
+	      else
+		{
+		  elem_getrange (&ylist, i, &yoff);
+		  elem_find (&ylist, yoff, &p, &f, &t);
+		}
+	      arithmetic_decode (p, f, t);
+	    }
+	  else
+	    {
+	      arithmetic_decode (leveltop + levelmid, leveltop + levelmid + levelbot, leveltop + levelmid + levelbot);
+	      levelbot += BOT_INC;
+	      if (dox)
+		xoff = DecodeGammaSigned (&xpos, &xneg);
+	      else
+		yoff = DecodeGammaSigned (&ypos, &yneg);
+	    }
+
+	  if (dox)
+	    {
+	      step->data.xoffset = xoff;
+	      elem_add (&xlist, xoff);
+	      elem_add (&xcond[symnum], xoff);
+	    }
+	  else
+	    {
+	      step->data.yoffset = yoff;
+	      elem_add (&ylist, yoff);
+	      elem_add (&ycond[symnum], yoff);
+	    }
+
+	  if (leveltop + levelmid >= maxfrequency)
+	    {
+	      leveltop = (leveltop + 1) / 2;
+	      levelmid = (levelmid + 1) / 2;
+	      levelbot = (levelbot + 1) / 2;
+	    }
+	}
+    }
+  for (t = 0; t < nsyms; t++)
+    {
+      elem_free (&xcond[t]);
+      elem_free (&ycond[t]);
+    }
+  elem_free (&xlist);
+  elem_free (&ylist);
+}
Index: /main/tags/2.25/gsdl/packages/mg/src/images/codeoffsets.h
===================================================================
--- /main/tags/2.25/gsdl/packages/mg/src/images/codeoffsets.h	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/mg/src/images/codeoffsets.h	(revision 21064)
@@ -0,0 +1,32 @@
+/**************************************************************************
+ *
+ * codeoffsets.h -- Functions which code the mark offsets
+ * Copyright (C) 1994  Stuart Inglis
+ *
+ * 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.
+ *
+ * $Id$
+ *
+ **************************************************************************/
+
+#ifndef __CODEOFFSETS_H
+#define __CODEOFFSETS_H
+
+#include "marklist.h"
+
+void EncodeOffsets (marklistptr MarkList, int num_symbols);
+void DecodeOffsets (marklistptr MarkList, int num_symbols);
+
+#endif
Index: /main/tags/2.25/gsdl/packages/mg/src/images/codesyms.c
===================================================================
--- /main/tags/2.25/gsdl/packages/mg/src/images/codesyms.c	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/mg/src/images/codesyms.c	(revision 21064)
@@ -0,0 +1,96 @@
+/**************************************************************************
+ *
+ * codesyms.c -- Functions which code the symbol sequence
+ * Copyright (C) 1994  Hugh Emberson
+ *
+ * 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.
+ *
+ * $Id$
+ *
+ **************************************************************************/
+
+#include "sysfuncs.h"
+
+#include "arithcode.h"
+#include "marklist.h"
+#include "pbmtools.h"
+#include "utils.h"
+#include "codesyms.h"
+
+int charsetsize = 256;
+
+void 
+EncodeSymbols (marklistptr MarkList, int NSyms)
+{
+  marklistptr step;
+  unsigned short Events[PPM_CHUNK];
+  int j = 0;
+
+  charsetsize = max (NSyms, 256);
+
+  step = MarkList;
+  while (step)
+    {
+      Events[j] = step->data.symnum;
+
+      assert (Events[j] > 0 || Events[j] < (unsigned) NSyms);
+
+      j++;
+
+      if (j == PPM_CHUNK)
+	{
+	  encodestring (Events, PPM_CHUNK);
+	  j = 0;
+	}
+      step = step->next;
+    };
+
+  if (j != 0)
+    encodestring (Events, j);
+
+  encodestring (Events, 0);
+}
+
+
+marklistptr 
+DecodeSymbols (int NSyms)
+{
+  marklistptr MarkList = NULL;
+  unsigned short Events[PPM_CHUNK];
+  int j, n;
+  marktype d;
+
+  charsetsize = max (NSyms, 256);
+
+  do
+    {
+      decodestring (Events, &n);
+
+      for (j = 0; j < n; j++)
+	{
+	  d.symnum = Events[j];
+	  marklist_add (&MarkList, d);
+	}
+    }
+  while (n != 0);
+
+  return MarkList;
+}
+
+void 
+InitPPM (void)
+{
+  kbytes = 896;
+}
Index: /main/tags/2.25/gsdl/packages/mg/src/images/codesyms.h
===================================================================
--- /main/tags/2.25/gsdl/packages/mg/src/images/codesyms.h	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/mg/src/images/codesyms.h	(revision 21064)
@@ -0,0 +1,44 @@
+/**************************************************************************
+ *
+ * codesyms.h -- Functions which code the symbol sequence
+ * Copyright (C) 1994  Stuart Inglis
+ *
+ * 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.
+ *
+ * $Id$
+ *
+ **************************************************************************/
+#ifndef _CodeSymbols_h_
+#define _CodeSymbols_h_
+
+#include "marklist.h"
+#include "arithcode.h"
+
+#ifndef FIXEDORDER
+#define FIXEDORDER	3
+#endif
+
+#define PPM_CHUNK	1024
+
+extern int kbytes;
+extern void decodestring ();
+extern void encodestring ();
+
+void EncodeSymbols (marklistptr MarkList, int NSyms);
+marklistptr DecodeSymbols (int NSyms);
+
+void InitPPM (void);
+
+#endif
Index: /main/tags/2.25/gsdl/packages/mg/src/images/extractor.c
===================================================================
--- /main/tags/2.25/gsdl/packages/mg/src/images/extractor.c	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/mg/src/images/extractor.c	(revision 21064)
@@ -0,0 +1,423 @@
+/**************************************************************************
+ *
+ * extractor.c -- Functions related to extracting marks
+ * Copyright (C) 1994  Stuart Inglis
+ *
+ * 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.
+ *
+ * $Id$
+ *
+ **************************************************************************/
+
+#include "sysfuncs.h"
+
+#include "extractor.h"
+#include "pbmtools.h"
+#include "marklist.h"
+#include "utils.h"
+
+
+/* 
+   'splitjoined' defines whether the extractor modules tries to break
+   "seemingly" merged/joined marks.
+ */
+int splitjoined = 1;
+
+#define MAX_FILL_STACK_SIZE 10000
+
+/* RunRegionFill uses line conherence to implement a better fill
+   routine.  The stack has currently got 10000 elements, although the
+   biggest I have encountered used a maximum stack size of 1294.  usage:
+   RunRegionFill(bitmap,mark,i,j,xpos,ypos); xpos and ypos are the top
+   left corners of the mark.  */
+
+int maxst = 0, st = 0;
+struct
+  {
+    int x, y;
+  }
+a[MAX_FILL_STACK_SIZE];
+
+#define push(i,j) a[st].x=i;a[st].y=j;st++;if(st>MAX_FILL_STACK_SIZE){error_msg ("extractor/flood_fill","woooo! Fill stack overflow!","");}
+#define pop(i,j) st--;i=a[st].x;j=a[st].y
+
+void 
+RunRegionFill (Pixel ** bitmap, marktype * mark, int i, int j, int xl, int yt, int cols, int rows)
+{
+  int l, r, t, start_up, start_down;
+
+  push (i, j);
+  while (st > 0)
+    {
+      if (st > maxst)
+	maxst = st;
+
+      pop (l, j);
+      r = l;
+
+      while (pbm_getpixel (bitmap, l - 1, j))
+	l--;
+      while (pbm_getpixel (bitmap, r + 1, j))
+	r++;
+      start_up = start_down = 1;
+      for (t = min (r + 1, cols - 1); t >= max (l - 1, 0); t--)
+	{
+	  if ((t >= l) && (t <= r))
+	    {
+	      pbm_putpixel (bitmap, t, j, 0);
+
+	      if (mark)
+		pbm_putpixel (mark->bitmap, t - xl, j - yt, 1);
+	    }
+
+	  if ((j - 1 >= 0) && (pbm_getpixel (bitmap, t, j - 1)))
+	    {
+	      if (start_up)
+		{
+		  push (t, j - 1);
+		  start_up = 0;
+		}
+	    }
+	  else
+	    start_up = 1;
+	  if ((j + 1 < rows) && (pbm_getpixel (bitmap, t, j + 1)))
+	    {
+	      if (start_down)
+		{
+		  push (t, j + 1);
+		  start_down = 0;
+		}
+	    }
+	  else
+	    start_down = 1;
+	}
+    }
+}
+
+
+
+
+/*
+
+   ExtractNextMark starts at (tx,ty) and looks for a set (==1) pixel.
+   The mark is then boundary traced to give an outline {The process is a
+   4-pixel exterior check -- giving 8 way connectivity}, and then
+   RunRegionFill is used to remove the mark and set the pixels in the
+   mark.
+
+   usage: ExtractNextMark(bitmap,&marklist,&startx,&starty,int cols,int rows);
+   Defines:
+   gp - gets a pixel, but returns 0 for outside regions.
+   boundary_{x,y}comp - returns the {x,y} component of the direction.
+   dir 0=right, 1=down, 2=left, 3=up.
+ */
+
+#define gp(i,j) ( (((i)<0)||((j)<0)||((i)>=cols)||((j)>=rows))? 0 : pbm_getpixel(bitmap,(i),(j)))
+
+#define boundary_xcomp(x) (x==0?1:(x==2?-1 : 0))
+#define boundary_ycomp(x) (x==1?1:(x==3?-1 : 0))
+
+int 
+ExtractNextMark (Pixel ** bitmap, marklistptr * marklist, int *tx, int *ty, int cols, int rows)
+{
+  int i, j, xl, xr, yt, yb;
+  register int dir, tempdir;
+  marktype d;
+
+  xl = INT_MAX;
+  xr = (-1);
+  yt = INT_MAX;
+  yb = (-1);
+
+  i = *tx;
+  j = *ty;
+  if ((i < 0) || (j < 0))
+    error_msg ("ExtractNextMark()", "Stupid values for x,y in findnextmark()", "");
+  while (!pbm_getpixel (bitmap, i, j))
+    {
+      i++;
+      if (i >= cols)
+	{
+	  i = 0;
+	  j++;
+	  if (j >= rows)
+	    return 0;
+	}
+    }
+
+  *tx = i;
+  *ty = j;
+  dir = 0;
+  j = j - 1;			/* start above */
+  do
+    {
+      if (i > xr)
+	xr = i - 1;
+      if (i < xl)
+	xl = i + 1;
+      if (j < yt)
+	yt = j + 1;
+      if (j > yb)
+	yb = j - 1;
+      tempdir = (dir + 1) % 4;
+      if (gp (i + boundary_xcomp (tempdir), j + boundary_ycomp (tempdir)) == 0)
+	dir = tempdir;
+      else
+	{
+	  tempdir = dir;
+	  if (gp (i + boundary_xcomp (tempdir), j + boundary_ycomp (tempdir)) == 0)
+	    dir = tempdir;
+	  else
+	    {
+	      tempdir = (dir + 3) % 4;
+	      if (gp (i + boundary_xcomp (tempdir), j + boundary_ycomp (tempdir)) == 0)
+		dir = tempdir;
+	      else
+		dir = (dir + 2) % 4;
+	    }
+	}
+      i += boundary_xcomp (dir);
+      j += boundary_ycomp (dir);
+    }
+  while ((i != (*tx)) || (j != (*ty - 1)));
+
+  d.w = (xr - xl + 1);
+  d.h = (yb - yt + 1);
+  d.xpos = xl;
+  d.ypos = yt;
+  d.bitmap = pbm_allocarray (d.w, d.h);
+
+  RunRegionFill (bitmap, &d, *tx, *ty, xl, yt, cols, rows);
+
+  marktype_calc_features (&d, "?");
+  marklist_add (marklist, d);
+
+  *tx = *tx + 1;
+  return 1;
+}
+
+
+
+
+static void 
+normalise (float *p, int w)
+{
+  int x;
+  float mx;
+
+  mx = p[0];
+  for (x = 0; x < w; x++)
+    if (p[x] > mx)
+      mx = p[x];
+  if (mx != 0)
+    {
+      for (x = 0; x < w; x++)
+	p[x] = p[x] / mx;
+    }
+}
+
+
+
+#define MAXPROFILE 1000
+float profile[MAXPROFILE], p2[MAXPROFILE];
+
+
+static int 
+possibly_joined (marktype * d)
+{
+  float aspect;
+  int i, n, x, y;
+  int leftable, l2;
+
+
+  aspect = d->w / (float) d->h;
+
+  if ((aspect >= 1.1) || (d->w < MAXPROFILE))
+    {
+      /* examine it more closely */
+
+
+      /* set up profile[] with a vertical profile */
+      for (x = 0; x < d->w; x++)
+	{
+	  profile[x] = 0;
+	  for (y = 0; y < d->h; y++)
+	    if (pbm_getpixel (d->bitmap, x, y))
+	      profile[x]++;
+	}
+
+      /* average the profile from (up to) 3 either way */
+      for (x = 0; x < d->w; x++)
+	{
+	  n = 0;
+	  p2[x] = 0;
+	  for (i = x - 3; i <= x + 3; i++)
+	    if ((i >= 0) && (i < d->w))
+	      {
+		n++;
+		p2[x] += profile[x];
+	      }
+	  p2[x] = p2[x] / (float) n;
+	}
+      for (x = 0; x < d->w; x++)
+	profile[x] = p2[x];
+
+      /* normalise profile[] */
+      normalise (profile, d->w);
+
+      /* find a little local minimum, with profile <0.25, make p2[] either 0 or 1 */
+      for (x = 0; x < d->w; x++)
+	p2[x] = 0;
+      for (x = 3; x < d->w - 3; x++)
+	{
+	  if (((profile[x - 2] - profile[x]) > 0.00) &&
+	      ((profile[x + 2] - profile[x]) > 0.00) &&
+	      (profile[x] < .25))
+	    p2[x] = 1;
+	}
+
+      /* travel rightwards, checking aspect ratio, looking at p2 now */
+      leftable = l2 = 0;
+      for (x = 0; x < d->w; x++)
+	if (p2[x] == 1)
+	  {
+	    if ((fabs ((abs (x - leftable) / (float) d->h) - 0.7) > 0.3) &&
+		(fabs ((abs (x - l2) / (float) d->h) - 0.7) > 0.3))
+	      p2[x] = 0;
+	    if (p2[x] == 1)
+	      {
+		leftable = l2;
+		l2 = x;
+	      }
+	  }
+
+      /* travel inwards, checking widths of chars, looking at p2 */
+      /* if a char has an aspect ratio of <= ? kill it */
+      l2 = 0;
+      leftable = d->w - 1;
+      x = 0;
+      y = d->w - 1;
+      while (x <= y)
+	{
+	  if (p2[x])
+	    {
+	      if (abs (x - l2) < max (d->h * 0.6, 5))
+		p2[x] = 0;
+	      if (p2[x])
+		l2 = x;
+	    }
+	  if (p2[y])
+	    {
+	      if (abs (y - leftable) < max (d->h * 0.6, 5))
+		p2[y] = 0;
+	      if (p2[y])
+		leftable = y;
+	    }
+	  x++;
+	  y--;
+	}
+
+
+      for (x = 0; x < d->w; x++)
+	if (p2[x])
+	  return 1;
+    }
+  return 0;
+}
+
+
+static void 
+split_mark (marklistptr * list, marktype * joinedmark)
+{
+  marktype new, old;
+  int x, found = 0, left = 0;
+  int i, j;
+  int oldw, oldh;
+  int overwrite = 1;
+
+  old = marktype_copy (*joinedmark);
+  oldw = joinedmark->w;
+  oldh = joinedmark->h;
+  for (x = 0; x < old.w; x++)
+    if (p2[x])
+      {
+	found = x;
+	break;
+      }
+  do
+    {
+      /* split at (found) position */
+      new.w = found + 1 - left;
+      new.h = old.h;
+      new.xpos = old.xpos + left;
+      new.ypos = old.ypos;
+      new.bitmap = pbm_allocarray (new.w, new.h);
+
+      for (i = 0; i < new.w; i++)
+	for (j = 0; j < new.h; j++)
+	  pbm_putpixel (new.bitmap, i, j, pbm_getpixel (old.bitmap, left + i, j));
+
+      marktype_adj_bound (&new);
+
+      if (overwrite)
+	{
+	  overwrite = 0;
+	  pbm_freearray (&(joinedmark->bitmap), oldh);
+	  *joinedmark = new;
+	}
+      else
+	marklist_add (list, new);
+
+
+      p2[found] = 0;
+      left = found;
+      found = 0;
+      for (x = left; x < old.w; x++)
+	if (p2[x])
+	  {
+	    found = x;
+	    break;
+	  }
+      if (left == old.w - 1)
+	break;			/* if we've got to the right */
+      if (found == 0)
+	found = old.w - 1;
+    }
+  while (found);
+  pbm_freearray (&(old.bitmap), oldh);
+}
+
+
+
+
+
+void 
+ExtractAllMarks (Pixel ** bitmap, marklistptr * list, int cols, int rows)
+{
+  int startx, starty, count;
+  marklistptr step;
+
+  startx = starty = 0;
+  while (ExtractNextMark (bitmap, list, &startx, &starty, cols, rows))
+    ;
+
+  if (splitjoined)
+    for (step = (*list), count = 0; step; step = step->next, count++)
+      if (possibly_joined (&(step->data)))
+	split_mark (list, &(step->data));
+
+  for (step = (*list), count = 0; step; step = step->next, count++)
+    step->data.symnum = count;
+}
Index: /main/tags/2.25/gsdl/packages/mg/src/images/extractor.h
===================================================================
--- /main/tags/2.25/gsdl/packages/mg/src/images/extractor.h	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/mg/src/images/extractor.h	(revision 21064)
@@ -0,0 +1,38 @@
+/**************************************************************************
+ *
+ * extractor.h -- Functions related to extracting marks
+ * Copyright (C) 1994  Stuart Inglis
+ *
+ * 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.
+ *
+ * $Id$
+ *
+ **************************************************************************/
+
+
+#ifndef _EXTRACTOR_H_
+#define _EXTRACTOR_H_
+
+#include "marklist.h"
+#include "pbmtools.h"
+
+extern int splitjoined;
+
+void RunRegionFill (Pixel ** bitmap, marktype * mark, int i, int j, int xl, int yt, int cols, int rows);
+
+int ExtractNextMark (Pixel ** bitmap, marklistptr * marklist, int *tx, int *ty, int cols, int rows);
+void ExtractAllMarks (Pixel ** bitmap, marklistptr * marklist, int cols, int rows);
+
+#endif
Index: /main/tags/2.25/gsdl/packages/mg/src/images/felics.c
===================================================================
--- /main/tags/2.25/gsdl/packages/mg/src/images/felics.c	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/mg/src/images/felics.c	(revision 21064)
@@ -0,0 +1,340 @@
+/**************************************************************************
+ *
+ * felics.c -- The main guts of the felics algorithm
+ * Copyright (C) 1994  Neil Sharman and Kerry Guise
+ *
+ * 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.
+ *
+ * $Id$
+ *
+ **************************************************************************/
+
+#include "sysfuncs.h"
+
+#include "bitio_m.h"
+#include "bitio_m_stdio.h"
+
+
+#undef putw
+#define putw(x)	{					\
+	short z;					\
+	byteptr = (unsigned char *)(x);			\
+	for (z = 0; z < sizeof(int); z++)		\
+		(void) putc((int) byteptr[z], fp_out);	\
+}
+#define INTSIZE sizeof(int) * 8
+#define BOOLEAN short
+#define TRUE 1
+#define FALSE 0
+
+#define IN_RANGE 0
+#define OUT_OF_RANGE 1
+#define BELOW_RANGE 0
+#define ABOVE_RANGE 1
+
+
+void 
+encode (unsigned int *line, int width, int height, int maxval, int maxk,
+	FILE * fp_in, FILE * fp_out, int (*get) (FILE *))
+{
+  int x, y;
+  unsigned long P, L, H, N1, N2, delta;
+  unsigned long cumul_param[256][INTSIZE];
+  unsigned max_cumul;
+
+  memset (cumul_param, '0', sizeof (cumul_param));
+
+  if (maxk)
+    max_cumul = maxk;
+  else
+    CEILLOG_2 (maxval, max_cumul);
+
+  ENCODE_START (fp_out)
+
+    for (y = 0; y < height; y++)
+    for (x = 0; x < width; x++)
+      {
+	if (y > 0)
+	  {
+	    if (x > 0)
+	      {			/* ******** */
+		N1 = line[x];	/* ****1*** */
+		N2 = line[x - 1];	/* ***2P*** */
+	      }			/* ******** */
+	    else
+	      {			/* |******* */
+		N1 = line[x];	/* |12***** */
+		N2 = line[x + 1];	/* |P***** */
+	      }			/* |******* */
+	  }
+	else
+	  {
+	    if (x > 1)
+	      {
+		N1 = line[x - 1];	/* -------- */
+		N2 = line[x - 2];	/* **12P*** */
+	      }			/* ******** */
+	    else if (x > 0)
+	      {
+		N1 = line[x - 1];	/* +------- */
+		N2 = N1;	/* |3P***** */
+	      }			/* |******* */
+	    else
+	      {
+		line[x] = get (fp_in);	/* +------- */
+		BINARY_ENCODE (line[x] + 1, maxval + 1);	/* |P****** */
+		continue;	/* |******* */
+	      }
+	  }
+
+
+	H = N1 > N2 ? N1 : N2;
+	L = N1 < N2 ? N1 : N2;
+	delta = H - L;
+
+	line[x] = P = get (fp_in);
+
+	if ((L <= P) && (P <= H))
+	  {
+	    /* IN-RANGE */
+	    unsigned long range, logofrange, thresh, numlong;
+	    int nbits;
+
+	    ENCODE_BIT (IN_RANGE);
+
+	    P -= L;
+
+	    range = delta + 1;
+
+	    if (range > 1)
+	      {
+		/* 2**i <= delta + 1 < 2**(i+1) ; find i ... */
+		CEILLOG_2 (range, logofrange);
+
+		/* number of n-bit values in the range */
+		thresh = (1 << logofrange) - range;
+
+		/* number of n+1-bit values in the range */
+		numlong = range - thresh;
+
+		/* rotate the n-bit codes into the centre */
+		P -= (numlong >> 1);
+		if ((long) P < 0)
+		  P += range;
+
+		if (P < thresh)
+		  nbits = logofrange - 1;
+		else
+		  {
+		    nbits = logofrange;
+		    P += thresh;
+		  }
+		while (--nbits >= 0)
+		  ENCODE_BIT ((P >> nbits) & 1);
+	      }
+	  }
+	else
+	  {
+	    /* OUT_OF_RANGE */
+	    unsigned long diff, parm, i, min;
+
+	    ENCODE_BIT (OUT_OF_RANGE);
+
+	    if (P < L)
+	      {
+		ENCODE_BIT (BELOW_RANGE);
+		diff = L - P - 1;
+	      }
+	    else
+	      {
+		ENCODE_BIT (ABOVE_RANGE);
+		diff = P - H - 1;
+	      }
+
+	    /* Now code 'diff' as a Golomb-Rice code */
+
+	    parm = 0;
+	    min = cumul_param[delta][0];
+	    for (i = 1; i < max_cumul; i++)
+	      if (cumul_param[delta][i] < min)
+		{
+		  min = cumul_param[delta][i];
+		  parm = i;
+		}
+
+	    UNARY_ENCODE ((diff >> parm) + 1);
+	    BINARY_ENCODE ((diff & ((1 << parm) - 1)) + 1, 1 << parm);
+
+	    for (i = 0; i < max_cumul; i++)
+	      cumul_param[delta][i] += (diff >> i) + 1 + i;
+	  }
+
+      }
+
+  ENCODE_DONE
+
+}
+
+
+
+
+
+
+void 
+decode (unsigned int *line, int width, int height, int maxval, int maxk,
+	FILE * fp_in, FILE * fp_out)
+{
+  int x, y;
+  unsigned int P, L, H, N1, N2, delta;
+  unsigned long cumul_param[256][INTSIZE];
+  unsigned max_cumul;
+
+  memset (cumul_param, '0', sizeof (cumul_param));
+
+  if (maxk)
+    max_cumul = maxk;
+  else
+    CEILLOG_2 (maxval, max_cumul);
+
+  DECODE_START (fp_in);
+
+  for (y = 0; y < height; y++)
+    for (x = 0; x < width; x++)
+      {
+	if (y > 0)
+	  {
+	    if (x > 0)
+	      {			/* ******** */
+		N1 = line[x];	/* ****1*** */
+		N2 = line[x - 1];	/* ***2P*** */
+	      }			/* ******** */
+	    else
+	      {			/* |******* */
+		N1 = line[x];	/* |12***** */
+		N2 = line[x + 1];	/* |P***** */
+	      }			/* |******* */
+	  }
+	else
+	  {
+	    if (x > 1)
+	      {
+		N1 = line[x - 1];	/* -------- */
+		N2 = line[x - 2];	/* **12P*** */
+	      }			/* ******** */
+	    else if (x > 0)
+	      {
+		N1 = line[x - 1];	/* +------- */
+		N2 = N1;	/* |3P***** */
+	      }			/* |******* */
+	    else
+	      {
+		BINARY_DECODE (line[x], maxval + 1);
+		line[x]--;
+		if (maxval < 256)
+		  putc (line[x], fp_out);	/* +------- */
+		else		/* |P****** */
+		  fprintf (fp_out, "%u ", line[x]);	/* |******* */
+		continue;
+	      }
+	  }
+
+
+	H = N1 > N2 ? N1 : N2;
+	L = N1 < N2 ? N1 : N2;
+	delta = H - L;
+
+	if (DECODE_BIT == IN_RANGE)
+	  {
+	    unsigned long i, range, logofrange, thresh, numlong;
+	    unsigned xx, l;
+
+	    range = delta + 1;
+
+	    if (range > 1)
+	      {
+		/* 2**i <= delta + 1 < 2**(i+1) ; find i ... */
+		CEILLOG_2 (range, logofrange);
+
+		/* number of n-bit values in the range */
+		thresh = (1 << logofrange) - range;
+		for (P = i = 0; i < logofrange - 1; i++)
+		  DECODE_ADD (P);
+		xx = P;
+		l = logofrange - 1;
+		if (P >= thresh)
+		  {
+		    DECODE_ADD (P);
+		    xx = P;
+		    l++;
+		    P -= thresh;
+		  }
+
+		/* number of n+1-bit values in the range */
+		numlong = range - thresh;
+
+		/* rotate the n-bit codes into the centre */
+		P += (numlong >> 1);
+		if ((long) P >= range)
+		  P -= range;
+
+		P += L;
+	      }
+	    else
+	      P = L;
+	  }
+	else
+	  {
+	    int out_of_range = DECODE_BIT;
+	    unsigned long diff, unary, binary, i, min, parm;
+
+	    /* Now code 'diff' as a Golomb-Rice code */
+
+	    parm = 0;
+	    min = cumul_param[delta][0];
+	    for (i = 1; i < max_cumul; i++)
+	      if (cumul_param[delta][i] < min)
+		{
+		  min = cumul_param[delta][i];
+		  parm = i;
+		}
+
+	    UNARY_DECODE (unary);
+	    diff = (unary - 1) << parm;
+	    BINARY_DECODE (binary, 1 << parm);
+	    diff |= binary - 1;
+
+	    for (i = 0; i < max_cumul; i++)
+	      cumul_param[delta][i] += (diff >> i) + 1 + i;
+
+	    if (out_of_range == BELOW_RANGE)
+	      {
+		P = L - diff - 1;
+	      }
+	    else
+	      {
+		P = diff + H + 1;
+	      }
+	  }
+
+	line[x] = P;
+
+	if (maxval < 256)
+	  (void) putc (P, fp_out);
+	else
+	  fprintf (fp_out, "%u ", P);
+      }
+
+  DECODE_DONE
+}
Index: /main/tags/2.25/gsdl/packages/mg/src/images/lstevent.c
===================================================================
--- /main/tags/2.25/gsdl/packages/mg/src/images/lstevent.c	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/mg/src/images/lstevent.c	(revision 21064)
@@ -0,0 +1,421 @@
+/**************************************************************************
+ *
+ * lstevent.c -- Routines to implement "events" using MTF lists.
+ * Copyright (C) 1987  Alistair Moffat
+ *
+ * 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.
+ *
+ * $Id$
+ *
+ **************************************************************************/
+
+#include "sysfuncs.h"
+
+#include "arithcode.h"
+#include "model.h"
+
+/*
+   $Log$
+   Revision 1.1  1999/08/10 21:17:26  sjboddie
+   renamed mg-1.3d directory mg
+
+   Revision 1.1  1998/11/17 09:33:37  rjmcnab
+   *** empty log message ***
+
+   * Revision 1.2  1994/09/20  04:41:40  tes
+   * For version 1.1
+   *
+ */
+
+static char *RCSID = "$Id$";
+
+void
+write_method ()
+{
+  fprintf (stderr, "C");
+}
+
+
+/*===========================================*/
+
+/*
+ * [Rodney Brown - Sep/95]
+ * On IBM RS/6000 AIX version 3.2 the compiler defines NULL as (void *)0
+ * when in ANSI mode. Hence the (event) and (point) casts
+ */
+
+
+#define GETNEWNODE(e,node)		\
+do 					\
+{	node = p32(numnodes) ;		\
+	node->eventnum = (event)e ;	\
+	node->count = increment ;	\
+	node->foll.totalcnt = 0 ;	\
+	node->foll.notfound = 0 ;	\
+	node->foll.list = (point)NULL ;	\
+	numnodes += 1 ;			\
+	nfreenodes -= 1 ;		\
+}					\
+while (false)
+
+/*===========================================*/
+
+#define INSERTNODE(U,node)		\
+do					\
+{	node->next = U->list ;		\
+	U->list = p16(node) ;		\
+	U->totalcnt += increment;	\
+}					\
+while (false)
+
+/*===========================================*/
+
+int
+halvelist (p)
+     register eventnode *p;
+{
+  register int sum = 0;
+  while (p != ENULL)
+    {
+      sum += p->count = (p->count + 1) / 2;
+      p = p32 (p->next);
+    }
+  return (sum);
+}
+
+/*===========================================*/
+
+void
+halveallcounts (U)
+     register eventset *U;
+{
+  U->notfound = (U->notfound + 1) / 2;
+  U->totalcnt = U->notfound;
+  U->totalcnt += halvelist (p32 (U->list));
+}
+
+/*===========================================*/
+
+eventnode *
+encode_event_noex (U, e, success)
+     register eventset *U;
+     event e;
+     boolean *success;
+{
+  register eventnode *pnode, *node;
+  register int lbnd, totl;
+
+  if (U->list == (point)NULL)
+    {
+      *success = false;
+      U->notfound += increment;
+      U->totalcnt += increment;
+      GETNEWNODE (e, node);
+      INSERTNODE (U, node);
+      return (node);
+    }
+
+  lbnd = 0;
+  pnode = ENULL;
+  node = p32 (U->list);
+  while (node != ENULL)
+    {
+      if (e == node->eventnum)
+	break;
+      lbnd += node->count;
+      pnode = node;
+      node = p32 (node->next);
+    }
+
+  totl = U->totalcnt;
+
+  if (node == ENULL)
+    {				/* event not found in list */
+      if ((totl > U->notfound))
+	arithmetic_encode (totl - U->notfound, totl, totl);
+      U->notfound += increment;
+      U->totalcnt += increment;
+      *success = false;
+      GETNEWNODE (e, node);
+      INSERTNODE (U, node);
+    }
+  else
+    {				/* found in the list, so go ahead and code */
+      arithmetic_encode (lbnd, lbnd + node->count, totl);
+      node->count += increment;
+      U->totalcnt += increment;
+      *success = true;
+      /* and move to front */
+      if (pnode != ENULL)
+	{
+	  pnode->next = node->next;
+	  node->next = U->list;
+	  U->list = p16 (node);
+	}
+    }
+  if (U->totalcnt > maxtotalcnt)
+    halveallcounts (U);
+  return (node);
+}
+
+/*===========================================*/
+
+eventnode *
+decode_event_noex (U, success, e)
+     register eventset *U;
+     boolean *success;
+     event *e;
+{
+  register eventnode *node, *pnode;
+  register int tget, lbnd, totl;
+
+  if (U->list == (point)NULL)
+    {
+      *success = false;
+      U->totalcnt += increment;
+      U->notfound += increment;
+      GETNEWNODE (NULL, node);
+      INSERTNODE (U, node);
+      return (node);
+    }
+  totl = U->totalcnt;
+  tget = arithmetic_decode_target (totl);
+
+  if (tget >= totl - U->notfound)
+    {
+      if (totl > U->notfound)
+	arithmetic_decode (totl - U->notfound, totl, totl);
+      U->totalcnt += increment;
+      U->notfound += increment;
+      *success = false;
+      GETNEWNODE (NULL, node);
+      INSERTNODE (U, node);
+    }
+  else
+    {
+      pnode = ENULL;
+      node = p32 (U->list);
+      lbnd = 0;
+      for (;;)
+	{
+	  if (tget < (lbnd += node->count))
+	    break;
+	  pnode = node;
+	  node = p32 (node->next);
+	}
+
+      arithmetic_decode (lbnd - node->count, lbnd, totl);
+      node->count += increment;
+      U->totalcnt += increment;
+      *e = node->eventnum;
+      *success = true;
+      /* and move to front */
+      if (pnode != ENULL)
+	{
+	  pnode->next = node->next;
+	  node->next = U->list;
+	  U->list = p16 (node);
+	}
+    }
+  if (U->totalcnt > maxtotalcnt)
+    halveallcounts (U);
+  return (node);
+}
+
+/*===========================================*/
+
+eventnode *
+encode_event (U, e, success)
+     register eventset *U;
+     event e;
+     boolean *success;
+{
+  register eventnode *pnode, *node, *p;
+  register int lbnd, totl;
+
+  if (U->list == (point)NULL)
+    {
+      *success = false;
+      U->notfound += increment;
+      U->totalcnt += increment;
+      GETNEWNODE (e, node);
+      INSERTNODE (U, node);
+      return (node);
+    }
+
+  lbnd = 0;
+  pnode = ENULL;
+  node = p32 (U->list);
+  while (node != ENULL)
+    {
+      if (!excluded[node->eventnum])
+	{
+	  if (e == node->eventnum)
+	    break;
+	  lbnd += node->count;
+	}
+      pnode = node;
+      node = p32 (node->next);
+    }
+
+  if (node == ENULL)
+    {				/* event not found in list, and whole list has been scanned */
+      totl = lbnd + U->notfound;
+      if ((totl > U->notfound))
+	arithmetic_encode (totl - U->notfound, totl, totl);
+      U->notfound += increment;
+      U->totalcnt += increment;
+      *success = false;
+      GETNEWNODE (e, node);
+      INSERTNODE (U, node);
+    }
+  else
+    {				/* found in the list, so go ahead and code */
+      /* first, total up rest of list */
+      totl = lbnd + node->count;
+      p = p32 (node->next);
+      while (p != ENULL)
+	{
+	  if (!excluded[p->eventnum])
+	    totl += p->count;
+	  p = p32 (p->next);
+	}
+      totl += U->notfound;
+
+      arithmetic_encode (lbnd, lbnd + node->count, totl);
+      node->count += increment;
+      U->totalcnt += increment;
+      *success = true;
+      /* and move to front */
+      if (pnode != ENULL)
+	{
+	  pnode->next = node->next;
+	  node->next = U->list;
+	  U->list = p16 (node);
+	}
+    }
+  if (U->totalcnt > maxtotalcnt)
+    halveallcounts (U);
+  return (node);
+}
+
+/*===========================================*/
+
+eventnode *
+decode_event (U, success, e)
+     register eventset *U;
+     boolean *success;
+     event *e;
+{
+  register eventnode *node, *pnode;
+  register int tget, lbnd, totl;
+
+  if (U->list == (point)NULL)
+    {
+      *success = false;
+      U->totalcnt += increment;
+      U->notfound += increment;
+      GETNEWNODE (NULL, node);
+      INSERTNODE (U, node);
+      return (node);
+    }
+  totl = 0;
+  node = p32 (U->list);
+  while (node != ENULL)
+    {
+      if (!excluded[node->eventnum])
+	totl += node->count;
+      node = p32 (node->next);
+    }
+  totl += U->notfound;
+  tget = arithmetic_decode_target (totl);
+
+  if (tget >= totl - U->notfound)
+    {
+      if (totl > U->notfound)
+	arithmetic_decode (totl - U->notfound, totl, totl);
+      U->totalcnt += increment;
+      U->notfound += increment;
+      *success = false;
+      GETNEWNODE (NULL, node);
+      INSERTNODE (U, node);
+    }
+  else
+    {
+      pnode = ENULL;
+      node = p32 (U->list);
+      lbnd = 0;
+      for (;;)
+	{
+	  if (!excluded[node->eventnum])
+	    {
+	      lbnd += node->count;
+	      if (tget < lbnd)
+		break;
+	    }
+	  pnode = node;
+	  node = p32 (node->next);
+	}
+
+      arithmetic_decode (lbnd - node->count, lbnd, totl);
+      node->count += increment;
+      U->totalcnt += increment;
+      *e = node->eventnum;
+      *success = true;
+      /* and move to front */
+      if (pnode != ENULL)
+	{
+	  pnode->next = node->next;
+	  node->next = U->list;
+	  U->list = p16 (node);
+	}
+    }
+  if (U->totalcnt > maxtotalcnt)
+    halveallcounts (U);
+  return (node);
+}
+
+/*===========================================*/
+
+eventnode *
+newnode (e)
+     event e;
+{
+  register eventnode *node;
+  GETNEWNODE (e, node);
+  node->next = (point)NULL;
+  node->prev = (point)NULL;
+  return (node);
+}
+
+/*===========================================*/
+
+/* not required in this version */
+
+#if 0
+eventnode *
+addevent (U, e)
+     register eventset *U;
+     event e;
+{
+  register eventnode *node;
+  /* get an event node */
+  GETNEWNODE (e, node);
+  INSERTNODE (U, node);
+  if (U->totalcnt > maxtotalcnt)
+    halveallcounts (U);
+  return (node);
+}
+#endif
Index: /main/tags/2.25/gsdl/packages/mg/src/images/marklist.c
===================================================================
--- /main/tags/2.25/gsdl/packages/mg/src/images/marklist.c	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/mg/src/images/marklist.c	(revision 21064)
@@ -0,0 +1,827 @@
+/**************************************************************************
+ *
+ * marklist.c -- Functions managing the list of marks
+ * Copyright (C) 1994  Stuart Inglis
+ *
+ * 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.
+ *
+ * $Id$
+ *
+ **************************************************************************/
+
+#include "sysfuncs.h"
+
+#include "marklist.h"
+#include "pbmtools.h"
+#include "utils.h"
+
+void 
+marktype_dump (marktype d)
+{
+  fprintf (stderr, "symnum: %d\n", d.symnum);
+  fprintf (stderr, "xpos: %d, ypos: %d\n", d.xpos, d.ypos);
+  fprintf (stderr, "w: %d, h: %d\n", d.w, d.h);
+  fprintf (stderr, "xcen: %d, ycen: %d\n", d.xcen, d.ycen);
+  write_library_mark (stderr, d);
+}
+
+
+/* copy, including make a copy of the bitmap */
+marktype 
+marktype_copy (marktype d)
+{
+  marktype d2;
+  int i, j;
+
+  d2 = d;
+  d2.bitmap = pbm_allocarray (d2.w, d2.h);
+  for (i = 0; i < d2.w; i++)
+    for (j = 0; j < d2.h; j++)
+      pbm_putpixel (d2.bitmap, i, j, pbm_getpixel (d.bitmap, i, j));
+  return d2;
+}
+
+
+float 
+marktype_density (marktype d)
+{
+  return d.set / (float) (d.w * d.h);
+}
+
+
+
+void 
+marktype_calc_centroid (marktype * b)
+{
+  int r, c;
+  int count = 0;
+  int xtot = 0, ytot = 0;
+
+  for (r = 0; r < b->h; r++)
+    for (c = 0; c < b->w; c++)
+      if (pbm_getpixel (b->bitmap, c, r))
+	{
+	  count++;
+	  xtot += c;
+	  ytot += r;
+	}
+  if (count)
+    {
+      xtot /= count;
+      ytot /= count;
+    }
+  b->xcen = xtot;
+  b->ycen = ytot;
+}
+
+
+
+static void 
+marktype_area (marktype * d)
+{
+  int x, y;
+  int set = 0;
+
+  for (y = 0; y < d->h; y++)
+    for (x = 0; x < d->w; x++)
+      if (pbm_getpixel (d->bitmap, x, y))
+	set++;
+  d->set = set;
+}
+
+
+static void 
+marktype_h_runs (marktype * d)
+{
+  int x, y;
+  int inrun = 0, num = 0;
+  int foundblack = 0;
+
+  for (y = 0; y < d->h; y++)
+    {
+      inrun = 0;
+      foundblack = 0;
+      for (x = 0; x < d->w; x++)
+	{
+	  if ((!foundblack) && (pbm_getpixel (d->bitmap, x, y)))
+	    foundblack = 1;
+	  if ((foundblack) && (pbm_getpixel (d->bitmap, x, y) == 0))
+	    inrun = 1;
+	  if ((inrun) && (pbm_getpixel (d->bitmap, x, y)))
+	    {
+	      num++;
+	      inrun = 0;
+	      foundblack = 0;
+	    }
+	}
+    }
+  d->h_runs = num;
+}
+
+static void 
+marktype_v_runs (marktype * d)
+{
+  int x, y;
+  int inrun = 0, num = 0;
+  int foundblack = 0;
+
+
+  for (x = 0; x < d->w; x++)
+    {
+      inrun = 0;
+      foundblack = 0;
+      for (y = 0; y < d->h; y++)
+	{
+	  if ((!foundblack) && (pbm_getpixel (d->bitmap, x, y)))
+	    foundblack = 1;
+	  if ((foundblack) && (pbm_getpixel (d->bitmap, x, y) == 0))
+	    inrun = 1;
+	  if ((inrun) && (pbm_getpixel (d->bitmap, x, y)))
+	    {
+	      num++;
+	      inrun = 0;
+	      foundblack = 0;
+	    }
+	}
+    }
+  d->v_runs = num;
+}
+
+
+/* assume we already have the centroid! */
+static void 
+marktype_prog_cent (marktype * d)
+{
+  int x, y;
+  int xtot = 0, ytot = 0;
+  int num = 0;
+
+  xtot = ytot = num = 0;
+  for (x = 0; x < d->xcen; x++)
+    for (y = 0; y < d->ycen; y++)
+      if (pbm_getpixel (d->bitmap, x, y))
+	{
+	  xtot += x;
+	  ytot += y;
+	  num++;
+	}
+  if (num == 0)
+    {
+      d->xcen1 = -1;
+      d->ycen1 = -1;
+    }
+  else
+    {
+      d->xcen1 = xtot / num;
+      d->ycen1 = ytot / num;
+    }
+
+
+  xtot = ytot = num = 0;
+  for (x = d->xcen; x < d->w; x++)
+    for (y = 0; y < d->ycen; y++)
+      if (pbm_getpixel (d->bitmap, x, y))
+	{
+	  xtot += x;
+	  ytot += y;
+	  num++;
+	}
+  if (num == 0)
+    {
+      d->xcen2 = -1;
+      d->ycen2 = -1;
+    }
+  else
+    {
+      d->xcen2 = xtot / num;
+      d->ycen2 = ytot / num;
+    }
+
+
+
+  xtot = ytot = num = 0;
+  for (x = 0; x < d->xcen; x++)
+    for (y = d->ycen; y < d->h; y++)
+      if (pbm_getpixel (d->bitmap, x, y))
+	{
+	  xtot += x;
+	  ytot += y;
+	  num++;
+	}
+
+
+  if (num == 0)
+    {
+      d->xcen3 = -1;
+      d->ycen3 = -1;
+    }
+  else
+    {
+      d->xcen3 = xtot / num;
+      d->ycen3 = ytot / num;
+    }
+
+  xtot = ytot = num = 0;
+  for (x = d->xcen; x < d->w; x++)
+    for (y = d->ycen; y < d->h; y++)
+      if (pbm_getpixel (d->bitmap, x, y))
+	{
+	  xtot += x;
+	  ytot += y;
+	  num++;
+	}
+  if (num == 0)
+    {
+      d->xcen4 = -1;
+      d->ycen4 = -1;
+    }
+  else
+    {
+      d->xcen4 = xtot / num;
+      d->ycen4 = ytot / num;
+    }
+}
+
+
+
+/* call this to get all features */
+void 
+marktype_calc_features (marktype * d, char str[])
+{
+  if (strlen (str))
+    strcpy (d->name, str);
+  marktype_calc_centroid (d);
+  marktype_area (d);
+  marktype_prog_cent (d);
+  marktype_h_runs (d);
+  marktype_v_runs (d);
+}
+
+
+
+
+
+void 
+marktype_adj_bound (marktype * m)
+{
+  int x, y, w, h;
+  int xpos, ypos;
+  int top = 0, left = 0, right = 0, bot = 0;
+  marktype temp;
+
+  w = m->w;
+  h = m->h;
+  xpos = m->xpos;
+  ypos = m->ypos;
+
+  for (y = 0; y < h; y++)
+    for (x = 0; x < w; x++)
+      if (pbm_getpixel (m->bitmap, x, y))
+	{
+	  top = y;
+	  x = w;
+	  y = h;
+	}
+
+  for (y = h - 1; y >= 0; y--)
+    for (x = 0; x < w; x++)
+      if (pbm_getpixel (m->bitmap, x, y))
+	{
+	  bot = y;
+	  x = w;
+	  y = -1;
+	}
+
+  for (x = 0; x < w; x++)
+    for (y = 0; y < h; y++)
+      if (pbm_getpixel (m->bitmap, x, y))
+	{
+	  left = x;
+	  x = w;
+	  y = h;
+	}
+
+  for (x = w - 1; x >= 0; x--)
+    for (y = 0; y < h; y++)
+      if (pbm_getpixel (m->bitmap, x, y))
+	{
+	  right = x;
+	  x = -1;
+	  y = h;
+	}
+
+  temp.w = right - left + 1;
+  temp.h = bot - top + 1;
+  temp.xpos = xpos + left;
+  temp.ypos = ypos + top;
+  temp.bitmap = pbm_allocarray (temp.w, temp.h);
+
+  for (x = 0; x < temp.w; x++)
+    for (y = 0; y < temp.h; y++)
+      pbm_putpixel (temp.bitmap, x, y, pbm_getpixel (m->bitmap, x + left, y + top));
+
+  pbm_freearray (&(m->bitmap), h);
+
+  marktype_calc_features (&temp, "?");
+  *m = temp;
+}
+
+
+
+
+
+
+/* returns a newly created mark reprenting the average of the marklist */
+void 
+marklist_average (marklistptr list, marktype * avgmark)
+{
+  int w = 0, h = 0;
+  int t = INT_MAX, b = 0, l = INT_MAX, r = 0, matched = 0;
+  marktype d, temp;
+  marklistptr step;
+  static int a[100][100];
+  int x, y;
+
+  if (list == NULL)
+    error_msg ("marklist_average", "Can't average 'nothing'!", "");
+
+  for (step = list; step; step = step->next)
+    {
+      matched++;
+      temp = step->data;
+      w = max (w, temp.w);
+      h = max (h, temp.h);
+      r = max (r, temp.xcen);
+      l = min (l, temp.xcen);
+      b = max (b, temp.ycen);
+      t = min (t, temp.ycen);
+    }
+  w = w + (r - l);
+  h = h + (b - t);
+  if ((w >= 100) || (h >= 100))
+    matched = 0;
+
+  if (matched > 1)
+    {
+      int x_off, y_off;
+      for (x = 0; x < w; x++)
+	for (y = 0; y < h; y++)
+	  a[x][y] = 0;
+
+      for (step = list; step; step = step->next)
+	{
+	  x_off = r - step->data.xcen;
+	  y_off = b - step->data.ycen;
+	  for (x = 0; x < step->data.w; x++)
+	    for (y = 0; y < step->data.h; y++)
+	      if (pbm_getpixel (step->data.bitmap, x, y))
+		a[x + x_off][y + y_off]++;
+	}
+
+      d.w = w;
+      d.h = h;
+      d.bitmap = pbm_allocarray (w, h);
+      for (x = 0; x < w; x++)
+	for (y = 0; y < h; y++)
+	  if (a[x][y] > max (1, (matched / 2)))		/* > gives better CR than >= */
+	    pbm_putpixel (d.bitmap, x, y, 1);
+      marktype_adj_bound (&d);
+      strcpy (d.name, "?");
+      marktype_calc_centroid (&d);
+    }
+  else
+    d = marktype_copy (list->data);
+
+  *avgmark = d;
+}
+
+
+
+
+
+
+void 
+marklist_setnull (marklistptr * list)
+{
+  *list = NULL;
+}
+
+
+marklistptr 
+marklist_add (marklistptr * list, marktype m)
+{
+  marklistptr p;
+
+  if (*list == NULL)
+    {
+      *list = (marklistptr) malloc (sizeof (marklisttype));
+      if ((*list) == NULL)
+	error_msg ("marklist_add", "OUT of Memory in marklist_add", "");
+      p = *list;
+    }
+  else
+    {
+      p = *list;
+      while (p->next != NULL)
+	p = p->next;
+      p->next = (marklistptr) malloc (sizeof (marklisttype));
+      if (p->next == NULL)
+	error_msg ("marklist_add", "OUT of Memory in marklist_add", "");
+      p = p->next;
+    }
+  p->data = m;
+  p->next = NULL;
+  return p;
+
+}
+
+
+
+marklistptr 
+marklist_addcopy (marklistptr * list, marktype m)
+{
+  marktype d;
+
+  d = marktype_copy (m);
+  return marklist_add (list, d);
+}
+
+
+
+int 
+marklist_length (marklistptr list)
+{
+  int count = 0;
+
+  while (list)
+    {
+      count++;
+      list = list->next;
+    }
+  return count;
+}
+
+
+
+
+
+void 
+marklist_dump (marklistptr list)
+{
+  int count = 0;
+  marktype d;
+
+  while (list)
+    {
+      d = list->data;
+      marktype_dump (d);
+
+      count++;
+      list = list->next;
+    }
+}
+
+
+
+
+/* pos starts from 0, to up marklist_length-1 */
+marklistptr 
+marklist_getat (marklistptr list, int pos, marktype * d)
+{
+  int count = 0;
+
+  while (list)
+    {
+      if (count == pos)
+	{
+	  *d = list->data;
+	  return list;
+	}
+      count++;
+      list = list->next;
+    }
+  fprintf (stderr, "marklist_getat(): access off ends of list: pos %d\n", pos);
+  return NULL;
+}
+
+
+
+void 
+marklist_free (marklistptr * list)
+{
+  marklistptr n;
+
+  while ((*list) != NULL)
+    {
+      n = (*list)->next;
+      pbm_freearray (&((*list)->data.bitmap), (*list)->data.h);
+      free ((*list));
+      (*list) = n;
+    }
+}
+
+
+
+int 
+marklist_removeat (marklistptr * list, int pos)
+{
+  marklistptr c, n, p = NULL;
+  int count = 0;
+
+  if ((pos == 0) && (*list))
+    {				/* if removing the 1st element */
+      *list = (*list)->next;
+      return 1;
+    }
+  else
+    {
+      c = *list;
+      while (c)
+	{
+	  if (count == pos)
+	    {			/* two cases, no previous, >=1 previous */
+	      if (p == NULL)	/* no previous */
+		{
+		  n = c->next;
+		  pbm_freearray (&c->data.bitmap, c->data.h);
+		  free (c);
+		  c = n;
+		  return 1;
+		}
+	      else
+		/* >=1 previous */
+		{
+		  n = c->next;
+		  pbm_freearray (&c->data.bitmap, c->data.h);
+		  free (c);
+		  p->next = n;
+		  return 1;
+		}
+	    }
+	  count++;
+	  p = c;
+	  c = c->next;
+	}
+    }
+  fprintf (stderr, "marklist_removeat(): access off ends of list: pos %d\n", pos);
+  return 0;			/* nothing was removed */
+}
+
+
+
+marklistptr 
+marklist_next (marklistptr list)
+{
+  return list->next;
+}
+
+
+/* only writes out ascii form */
+void 
+write_library_mark (FILE * fp, marktype d)
+{
+  int r, c, rows, cols;
+  int xtot = d.xcen, ytot = d.ycen;
+
+  rows = d.h;
+  cols = d.w;
+
+  fprintf (fp, "Mark: %d\n", d.symnum);
+  fprintf (fp, "Char: %s\n", d.name);
+  fprintf (fp, "Cols: %d Rows: %d\n", d.w, d.h);
+  for (r = 0; r < d.h; r++)
+    {
+      for (c = 0; c < d.w; c++)
+	if ((r == ytot) && (c == xtot))
+	  putc (pbm_getpixel (d.bitmap, c, r) ? 'C' : '!', fp);
+	else
+	  putc (pbm_getpixel (d.bitmap, c, r) ? 'X' : '.', fp);
+      putc ('\n', fp);
+    }
+}
+
+
+
+/* only reads in ascii library */
+int 
+read_library_mark (FILE * fp, marktype * d)
+{
+  int r, c, rows, cols, numread, ch1 = 'C';
+  char str1[100], str2[100];
+
+  numread = fscanf (fp, "%s %d\n", str1, &(d->symnum));
+  if ((numread != 2) || (strcmp (str1, "Mark:") != 0))
+    return 0;
+  fscanf (fp, "%s %s\n", str1, (d->name));
+  fscanf (fp, "%s %d %s %d\n", str1, &(d->w), str2, &(d->h));
+  cols = d->w;
+  rows = d->h;
+  d->bitmap = pbm_allocarray (cols, rows);
+  for (r = 0; r < rows; r++)
+    {
+      for (c = 0; c < cols; c++)
+	{
+	  ch1 = getc (fp);
+	  if ((ch1 == 'X') || (ch1 == 'C'))
+	    pbm_putpixel (d->bitmap, c, r, 1);
+	  else
+	    pbm_putpixel (d->bitmap, c, r, 0);
+	}
+      ch1 = getc (fp);
+    }
+  marktype_calc_features (d, "?");
+
+  return 1;
+}
+
+
+
+
+
+
+
+int 
+read_library (char libraryname[], marklistptr * library)
+{
+  int err, count;
+  FILE *lib;
+  marktype d;
+  marklistptr step;
+
+  lib = fopen (libraryname, "rb");
+  if (lib == NULL)
+    error_msg ("read_library()", "Trouble opening library file", "");
+  *library = NULL;
+  count = 0;
+  while (!isEOF (lib))
+    {
+      err = read_library_mark (lib, &d);
+      if (!err)
+	error_msg ("read_library()", "unknown format of the library file.", "");
+      d.symnum = count;
+      count++;
+      if ((*library) == NULL)
+	step = marklist_add (library, d);
+      else
+	step = marklist_add (&step, d);
+    }
+  count = marklist_length (*library);
+  fclose (lib);
+
+  return count;
+}
+
+
+
+
+
+
+/**********************************************************************
+
+'elem' routines for coding offsets
+
+the elem datatype contains the 3 params for arithmetic coding,
+stored as a no-duplicates order linked list.
+
+************************************************************************/
+
+
+
+
+void 
+elem_add (elemlist * list, int num)
+{
+  elemptr temp, nn;
+  int p, f;
+
+  list->tot++;
+  if (list->head == NULL)
+    {
+      list->head = (elemptr) malloc (sizeof (elem));
+      if ((list->head) == NULL)
+	error_msg ("", "ekk", "");
+      temp = list->head;
+      temp->next = NULL;
+      temp->num = num;
+      temp->pos = 0;
+      temp->freq = 1;
+    }
+  else
+    {				/* add to list */
+      temp = list->head;
+      p = 0;
+      f = 0;
+      while ((num > temp->num) && (temp->next != NULL))
+	{
+	  p = temp->pos;
+	  f = temp->freq;
+	  temp = temp->next;
+	}
+
+      if (temp->num == num)
+	temp->freq++;
+      else
+	{			/* insert it */
+	  nn = (elemptr) malloc (sizeof (elem));
+	  if (nn == NULL)
+	    error_msg ("", "ekk", "");
+
+	  if (num < temp->num)
+	    {
+	      nn->num = temp->num;
+	      nn->pos = temp->pos;
+	      nn->freq = temp->freq;
+	      nn->next = temp->next;
+	      temp->num = num;
+	      temp->pos = p + f;
+	      temp->freq = 1;
+	      temp->next = nn;
+	    }
+	  else
+	    {
+	      nn->next = temp->next;
+	      temp->next = nn;
+	      nn->pos = temp->pos + temp->freq;
+	      nn->num = num;
+	      nn->freq = 1;
+	      temp = nn;
+	    }
+	}
+    }
+  /* update frequencies */
+  temp = temp->next;
+  if (temp)
+    do
+      {
+	temp->pos++;
+	temp = temp->next;
+      }
+    while (temp);
+}
+
+
+void 
+elem_free (elemlist * list)
+{
+  elemptr n, p;
+
+  p = list->head;
+  while (p != NULL)
+    {
+      n = p->next;
+      free (p);
+      p = n;
+    }
+  list->head = NULL;
+}
+
+int 
+elem_find (elemlist * list, int n, int *p, int *f, int *t)
+{
+  elemptr temp;
+
+  temp = list->head;
+  while (temp)
+    {
+      if (temp->num == n)
+	{
+	  *p = temp->pos;
+	  *f = temp->freq + temp->pos;
+	  *t = list->tot;
+	  return 1;
+	}
+      temp = temp->next;
+    }
+  return 0;
+}
+
+
+int 
+elem_getrange (elemlist * list, int range, int *num)
+{
+  elemptr temp;
+
+  temp = list->head;
+  while (temp)
+    {
+      if ((range >= temp->pos) && (range < (temp->pos + temp->freq)))
+	{
+	  *num = temp->num;
+	  return 1;
+	}
+      temp = temp->next;
+    }
+  return 0;
+}
Index: /main/tags/2.25/gsdl/packages/mg/src/images/marklist.h
===================================================================
--- /main/tags/2.25/gsdl/packages/mg/src/images/marklist.h	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/mg/src/images/marklist.h	(revision 21064)
@@ -0,0 +1,114 @@
+/**************************************************************************
+ *
+ * marklist.h -- Functions managing the list of marks
+ * Copyright (C) 1994  Stuart Inglis
+ *
+ * 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.
+ *
+ * $Id$
+ *
+ **************************************************************************/
+
+#ifndef __MARKLIST_H
+#define __MARKLIST_H
+
+#include "sysfuncs.h"
+#include "basictypes.h"
+
+typedef struct
+  {
+    int symnum;
+    int xpos, ypos;
+    int w, h;
+    int xcen, ycen;
+    int xoffset, yoffset;
+    char name[10];
+    Pixel **bitmap;
+
+    int xcen1, ycen1;
+    int xcen2, ycen2;
+    int xcen3, ycen3;
+    int xcen4, ycen4;
+    int set;
+    int h_runs;
+    int v_runs;
+  }
+marktype;
+
+
+typedef struct marklisttype *marklistptr;
+typedef struct marklisttype
+  {
+    marktype data;
+    marklistptr next;
+  }
+marklisttype;
+
+
+void marktype_dump (marktype d);
+marktype marktype_copy (marktype d);
+
+float marktype_density (marktype d);
+void marktype_calc_centroid (marktype * b);
+void marktype_calc_features (marktype * d, char str[]);
+void marktype_adj_bound (marktype * m);
+
+void marklist_average (marklistptr list, marktype * avgmark);
+void marklist_setnull (marklistptr * list);
+marklistptr marklist_add (marklistptr * list, marktype m);
+marklistptr marklist_addcopy (marklistptr * list, marktype m);
+int marklist_length (marklistptr list);
+void marklist_dump (marklistptr list);
+marklistptr marklist_getat (marklistptr list, int pos, marktype * d);
+void marklist_free (marklistptr * list);
+int marklist_removeat (marklistptr * list, int pos);
+marklistptr marklist_next (marklistptr list);
+
+void write_library_mark (FILE * fp, marktype d);
+int read_library_mark (FILE * fp, marktype * d);
+int read_library (char libraryname[], marklistptr * library);
+
+
+
+
+
+
+/* 
+   The 'elem' structure is an ordered linked list, with fields corresponding
+   directly to the arithmetic coding routines.  
+ */
+typedef struct elem *elemptr;
+typedef struct elem
+  {
+    int num;
+    int pos;
+    int freq;
+    elemptr next;
+  }
+elem;
+
+typedef struct elemlist
+  {
+    elemptr head;
+    int tot;
+  }
+elemlist;
+
+void elem_add (elemlist * list, int num);
+void elem_free (elemlist * list);
+int elem_find (elemlist * list, int n, int *p, int *f, int *t);
+int elem_getrange (elemlist * list, int range, int *num);
+
+#endif
Index: /main/tags/2.25/gsdl/packages/mg/src/images/match.c
===================================================================
--- /main/tags/2.25/gsdl/packages/mg/src/images/match.c	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/mg/src/images/match.c	(revision 21064)
@@ -0,0 +1,417 @@
+/**************************************************************************
+ *
+ * match.c -- Functions related to matching marks
+ * Copyright (C) 1994  Stuart Inglis
+ *
+ * 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.
+ *
+ * $Id$
+ *
+ **************************************************************************/
+
+#include "sysfuncs.h"
+
+#include "marklist.h"
+#include "pbmtools.h"
+#include "utils.h"
+
+
+/* error mask goes from 0..8, single pixel errors are worth nothing */
+int 
+WXOR_match (marktype b1, marktype b2)
+{
+  int r, c, i, j;
+  int minr, minc;
+  int maxr, maxc;
+  int offx, offy;
+  int p1, p2;
+  int count = 0;
+  marktype d;
+
+  offx = b1.xcen - b2.xcen;
+  offy = b1.ycen - b2.ycen;
+
+  minc = min (0, offx);
+  minr = min (0, offy);
+
+  maxc = max (b1.w, b2.w + offx);
+  maxr = max (b1.h, b2.h + offy);
+
+  d.w = maxc - minc + 1;
+  d.h = maxr - minr + 1;
+  d.bitmap = pbm_allocarray (d.w, d.h);
+
+
+  for (r = minr; r < maxr; r++)
+    for (c = minc; c < maxc; c++)
+      {
+	if ((r >= 0) && (c >= 0) && (r < b1.h) && (c < b1.w))
+	  p1 = pbm_getpixel (b1.bitmap, c, r);
+	else
+	  p1 = 0;		/* 0 = back ground colour */
+	if ((r - offy >= 0) && (c - offx >= 0) && (r - offy < b2.h) && (c - offx < b2.w))
+	  p2 = pbm_getpixel (b2.bitmap, c - offx, r - offy);
+	else
+	  p2 = 0;		/* background colour */
+	pbm_putpixel (d.bitmap, c - minc, r - minr, p1 != p2);
+      }
+  for (r = minr; r < maxr; r++)
+    for (c = minc; c < maxc; c++)
+      if (pbm_getpixel (d.bitmap, c - minc, r - minr))
+	for (i = -1; i <= 1; i++)
+	  for (j = -1; j <= 1; j++)
+	    if ((r + j >= 0) && (c + i >= 0) && (r + j < d.h) && (c + i < d.w) && ((i != 0) || (j != 0)) && (pbm_getpixel (d.bitmap, c + i - minc, r + j - minr)))
+	      count++;
+  pbm_freearray (&d.bitmap, d.h);
+  return count;
+}
+
+
+
+/* define an array for most matches, if it is a massive mark, then WXOR is called */
+#define S_SIZE 500
+
+static unsigned char scratch[S_SIZE][S_SIZE], sc2[S_SIZE][S_SIZE];
+
+
+
+
+/* Weighted AND-NOT */
+
+int 
+WAN_match (marktype b1, marktype b2)
+{
+  int r, c, i, j;
+  int minr, minc;
+  int maxr, maxc;
+  int offx, offy;
+  int p1, p2;
+  int count = 0;
+
+  offx = b1.xcen - b2.xcen;
+  offy = b1.ycen - b2.ycen;
+
+  minc = min (0, offx);
+  minr = min (0, offy);
+
+  maxc = max (b1.w, b2.w + offx);
+  maxr = max (b1.h, b2.h + offy);
+
+  if (((maxc - minc) >= S_SIZE) || ((maxr - minr) >= S_SIZE))
+    return WXOR_match (b1, b2);
+
+  for (r = minr; r < maxr; r++)
+    for (c = minc; c < maxc; c++)
+      {
+	scratch[r - minr][c - minc] = sc2[r - minr][c - minc] = 0;
+	if ((r >= 0) && (c >= 0) && (r < b1.h) && (c < b1.w))
+	  p1 = pbm_getpixel (b1.bitmap, c, r);
+	else
+	  p1 = 0;		/* 0 == background colour */
+	if ((r - offy >= 0) && (c - offx >= 0) && (r - offy < b2.h) && (c - offx < b2.w))
+	  p2 = pbm_getpixel (b2.bitmap, c - offx, r - offy);
+	else
+	  p2 = 0;
+
+	if ((p1 == 0) && (p2 == 1))	/* p1 not set, p2 = set */
+	  scratch[r - minr][c - minc] = 1;
+	if ((p1 == 1) && (p2 == 0))	/* p1 set, p2 not set */
+	  sc2[r - minr][c - minc] = 1;
+      }
+
+  count = 0;
+  for (r = minr; r < maxr; r++)
+    for (c = minc; c < maxc; c++)
+      if (scratch[r - minr][c - minc])
+	for (i = -1; i <= 1; i++)
+	  for (j = -1; j <= 1; j++)
+	    if ((r + j >= minr) && (c + i >= minc) && (r + j < maxr) && (c + i < maxc) && ((i != 0) || (j != 0)) && scratch[r - minr + j][c - minc + i])
+	      count++;
+
+  for (r = minr; r < maxr; r++)
+    for (c = minc; c < maxc; c++)
+      if (sc2[r - minr][c - minc])
+	for (i = -1; i <= 1; i++)
+	  for (j = -1; j <= 1; j++)
+	    if ((r + j >= minr) && (c + i >= minc) && (r + j < maxr) && (c + i < maxc) && ((i != 0) || (j != 0)) && sc2[r - minr + j][c - minc + i])
+	      count++;
+
+  return count;
+}
+
+/* oc 8 must be in a clock wise order, with oc[0] a corner */
+struct
+{
+  int x, y;
+}
+oc[8] =
+{
+  {
+    -1, -1
+  }
+  ,
+  {
+    0, -1
+  }
+  ,
+  {
+    1, -1
+  }
+  ,
+  {
+    1, 0
+  }
+  ,
+  {
+    1, 1
+  }
+  ,
+  {
+    0, 1
+  }
+  ,
+  {
+    -1, 1
+  }
+  ,
+  {
+    -1, 0
+  }
+};
+
+
+
+static void 
+xormatchscratch (marktype * b1, marktype * b2, int minr, int maxr, int minc, int maxc, int offx, int offy)
+{
+  int r, c, rmm, roo, coo;
+  int p1, p2;
+  Pixel **bm1 = b1->bitmap, **bm2 = b2->bitmap;
+  int w1 = b1->w, h1 = b1->h, w2 = b2->w, h2 = b2->h;
+
+  for (r = minr; r < maxr; r++)
+    {
+      rmm = r - minr;
+      roo = r - offy;
+      p1 = 0;
+      for (c = minc; c < 0; c++)
+	{
+	  coo = c - offx;
+	  scratch[rmm][c - minc] = sc2[rmm][c - minc] = 0;
+	  if ((coo >= 0) && (roo >= 0) && (coo < w2) && (roo < h2))
+	    p2 = pbm_getpixel (bm2, coo, roo);
+	  else
+	    p2 = 0;		/* background */
+	  scratch[rmm][c - minc] = p1 != p2;
+	}
+      for (c = 0; c < maxc; c++)
+	{
+	  coo = c - offx;
+	  scratch[rmm][c - minc] = sc2[rmm][c - minc] = 0;
+	  if ((r >= 0) && (c < w1) && (r < h1))
+	    p1 = pbm_getpixel (bm1, c, r);
+	  else
+	    p1 = 0;		/* background */
+	  if ((coo >= 0) && (roo >= 0) && (coo < w2) && (roo < h2))
+	    p2 = pbm_getpixel (bm2, coo, roo);
+	  else
+	    p2 = 0;		/* background */
+	  scratch[rmm][c - minc] = p1 != p2;
+	}
+    }
+}
+
+
+
+int 
+CSIS_match (marktype * b1, marktype * b2)
+{
+  int r, c, i;
+  int minr, minc;
+  int maxr, maxc;
+  int offx, offy, fepcount;
+  int totscratch = 0;
+
+
+  offx = b1->xcen - b2->xcen;
+  offy = b1->ycen - b2->ycen;
+
+  minc = min (0, offx);
+  minr = min (0, offy);
+
+  maxc = max (b1->w, b2->w + offx);
+  maxr = max (b1->h, b2->h + offy);
+
+  if (((maxc - minc) >= S_SIZE) || ((maxr - minr) >= S_SIZE))
+    return WXOR_match (*b1, *b2);
+
+  /* set the scratch array to 1 if there is an XOR match */
+
+  xormatchscratch (b1, b2, minr, maxr, minc, maxc, offx, offy);
+  /* We how have the XOR map. Scratch contains the number of neighbours, 1=1 neighbour set...etc */
+
+  /* CSIS rule 1, if FEP (four error pels) then exit */
+  fepcount = 0;
+  for (r = minr; r < maxr - 1; r++)
+    for (c = minc; c < maxc - 1; c++)
+      if ((scratch[r - minr][c - minc]) && (scratch[r - minr + 1][c - minc]) &&
+	  (scratch[r - minr][c - minc + 1]) && (scratch[r - minr + 1][c - minc + 1]))
+	{
+	  fepcount++;
+	  if (fepcount == 1)
+	    return 10001;
+	}
+
+  /* foreach set pixel, update scratch with the number of pels around in five dir's. 
+     FPN (five-pel neighbour hood) */
+  for (r = minr; r < maxr; r++)
+    for (c = minc; c < maxc; c++)
+      if (scratch[r - minr][c - minc])
+	{
+	  sc2[r - minr][c - minc] = 1;	/* itself */
+	  for (i = 1; i < 8; i += 3)
+	    if (((r + oc[i].y) >= minr) && ((c + oc[i].x) >= minc) && ((r + oc[i].y) < maxr) && ((c + oc[i].x) < maxc))
+	      if (scratch[r + oc[i].y - minr][c + oc[i].x - minc])
+		sc2[r - minr][c - minc]++;
+	}
+  /* now scratch has the value of the FPN - 1=single error, 5=4 neighbouring errors etc... */
+
+  /* set scratch and sc2 to be the same */
+  for (r = minr; r < maxr; r++)
+    for (c = minc; c < maxc; c++)
+      totscratch += scratch[r - minr][c - minc] = sc2[r - minr][c - minc];
+
+  for (r = minr; r < maxr; r++)
+    for (c = minc; c < maxc; c++)
+      {
+	/* CSIS rule 2i: an error pel has 2 or more neighbours---this num is the same as PMS */
+	if (scratch[r - minr][c - minc] >= 3)
+	  if ((r - minr >= 1) && (c - minc >= 1) && (r - minr < (maxr - 1)) && (c - minc < (maxc - 1)))
+	    {
+	      int i, numsep = 0;
+	      /* find how many neighbours a set pixel has, only check the 4 edges-FPN */
+	      for (i = 1; i < 8; i += 2)
+		if (scratch[r + oc[i].y - minr][c + oc[i].x - minc])	/* if a scratch pixel is set */
+		  {
+		    if ((scratch[r + oc[(i + 2) % 8].y - minr][c + oc[(i + 2) % 8].x - minc] == 0) &&
+			(scratch[r + oc[(i + 6) % 8].y - minr][c + oc[(i + 6) % 8].x - minc] == 0)
+		      )
+		      numsep++;
+		  }
+
+	      if ((b1->w >= 12) || (b2->w >= 12) || (b1->h >= 12) || (b2->h >= 12))
+		{
+
+		  /* PMS rule 2ii: at least two of its neigh. error p's aren't connected */
+		  if (numsep >= 2)
+		    {
+		      int i, j, p, p2, same;
+
+		      /* PMS rule 2(iii), look for regions in the original images of 3x3 the same */
+		      if ((c >= 0) && (r >= 0) && (c < b1->w) && (r < b1->h))
+			{
+			  p = pbm_getpixel (b1->bitmap, c, r);
+			  same = 0;
+			  for (i = -1; i <= 1; i++)
+			    for (j = -1; j <= 1; j++)
+			      {
+				if ((c + i >= 0) && (r + j >= 0) && (c + i < b1->w) && (r + j < b1->h))
+				  p2 = pbm_getpixel (b1->bitmap, c + i, r + j);
+				else
+				  p2 = 0;
+				if (p2 == p)
+				  same++;
+			      }	/* i,j loop */
+			  /* PMS rule 2(iii) */
+			  if (same == 9)
+			    {
+			      return 10002;
+			    }
+			}	/* (*b1) in range */
+
+		      if ((c - offx >= 0) && (r - offy >= 0) && (c - offx < b2->w) && (r - offy < b2->h))
+			{
+			  p = pbm_getpixel (b2->bitmap, c - offx, r - offy);
+			  same = 0;
+			  for (i = -1; i <= 1; i++)
+			    for (j = -1; j <= 1; j++)
+			      {
+				if ((c + i - offx >= 0) && (r + j - offy >= 0) && (c + i - offx < b2->w) && (r + j - offy < b2->h))
+				  p2 = pbm_getpixel (b2->bitmap, c + i - offx, r + j - offy);
+				else
+				  p2 = 0;
+				if (p2 == p)
+				  same++;
+			      }	/* i,j loop */
+			  /* PMS rule 2(iii) */
+			  if (same == 9)
+			    {
+			      return 10003;
+			    }
+			}
+		    }
+		}
+	      else
+		{		/* do the CSIS rule */
+		  /* CSIS rule 2ii: at least two of its neigh. error p's aren't connected */
+		  if (numsep >= 2)
+		    {
+		      int i, p, p2, same;
+
+		      /* PMS rule 2(iii), look for regions in the original images of 3x3 the same */
+		      if ((c >= 0) && (r >= 0) && (c < b1->w) && (r < b1->h))
+			{
+			  p = pbm_getpixel (b1->bitmap, c, r);
+			  same = 1;
+			  for (i = 1; i < 8; i += 2)
+			    if ((c + oc[i].x >= 0) && (r + oc[i].y >= 0) && (c + oc[i].x < b1->w) && (r + oc[i].y < b1->h))
+			      p2 = pbm_getpixel (b1->bitmap, c + oc[i].x, r + oc[i].y);
+			    else
+			      p2 = 0;
+			  if (p2 == p)
+			    same++;
+
+			  /* CSIS rule 2(iii) */
+			  if (same == 5)
+			    {
+			      return 10002;
+			    }
+			}
+
+		      if ((c - offx >= 0) && (r - offy >= 0) && (c - offx < b2->w) && (r - offy < b2->h))
+			{
+			  p = pbm_getpixel (b2->bitmap, c - offx, r - offy);
+			  same = 1;
+			  for (i = 1; i < 8; i += 2)
+			    if ((c + oc[i].x - offx >= 0) && (r + oc[i].y - offy >= 0) && (c + oc[i].x - offx < b2->w) && (r + oc[i].y - offy < b2->h))
+			      p2 = pbm_getpixel (b2->bitmap, c + oc[i].x - offx, r + oc[i].y - offy);
+			    else
+			      p2 = 0;
+			  if (p2 == p)
+			    same++;
+
+			  /* CSIS rule 2(iii) */
+			  if (same == 5)
+			    {
+			      return 10003;
+			    }
+			}
+		    }
+		}
+	    }
+      }
+
+  return totscratch;
+}
Index: /main/tags/2.25/gsdl/packages/mg/src/images/match.h
===================================================================
--- /main/tags/2.25/gsdl/packages/mg/src/images/match.h	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/mg/src/images/match.h	(revision 21064)
@@ -0,0 +1,47 @@
+/**************************************************************************
+ *
+ * match.h -- Functions related to matching marks
+ * Copyright (C) 1994  Stuart Inglis
+ *
+ * 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.
+ *
+ * $Id$
+ *
+ **************************************************************************/
+
+#ifndef __MATCH_H
+#define __MATCH_H
+
+#include "marklist.h"
+#include "pbmtools.h"
+#include "utils.h"
+
+
+/*
+   #define NOT_SCREENED(b1,b2) ((abs(b1.w-b2.w)<=4) && (abs(b1.h-b2.h)<=4))
+ */
+
+#define NOT_SCREENED(b1,b2) ((abs(b1.xcen-b2.xcen)+abs(b1.ycen-b2.ycen))<=3)
+
+#define MATCH_VAL 1000
+#define MATCH(b1,b2) (CSIS_match(b1,b2))
+
+int XOR_match (marktype b1, marktype b2);
+int WXOR_match (marktype b1, marktype b2);
+int WAN_match (marktype b1, marktype b2);
+int PMS_match (marktype b1, marktype b2);
+int CSIS_match (marktype * b1, marktype * b2);
+
+#endif
Index: /main/tags/2.25/gsdl/packages/mg/src/images/mgbilevel.1
===================================================================
--- /main/tags/2.25/gsdl/packages/mg/src/images/mgbilevel.1	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/mg/src/images/mgbilevel.1	(revision 21064)
@@ -0,0 +1,116 @@
+.\"------------------------------------------------------------
+.\" Id - set Rv,revision, and Dt, Date using rcs-Id tag.
+.de Id
+.ds Rv \\$3
+.ds Dt \\$4
+..
+.Id $Id$
+.\"------------------------------------------------------------
+.TH mgbilevel 1 \*(Dt CITRI
+.SH NAME
+mgbilevel \- compresses a bilevel image using a specified template
+.SH SYNOPSIS
+.B mgbilevel
+.B \-e
+[
+.B \-t
+.I \*(lqstring\*(rq
+]
+.I infile
+[
+.I \>compressed-outfile
+]
+.nf
+or
+.fi
+.B mgbilevel
+.B \-d
+.I compressed-infile
+[
+.I \>outfile
+]
+.SH DESCRIPTION
+.B mgbilevel
+performs (up to) a two-stage template-based compression.  The
+user can specify the template to be used in the compression process.  The
+default template size is a two-stage template 22/10.  The compressed file
+contains the template type in the stream.  The output files are written
+to
+.IR stdout .
+.SH OPTIONS
+Options may appear in any order.
+.TP "\w'\fB\-t\fP \fI\*(lqstring\*(rq\fP'u+2n"
+.B \-h
+This displays a usage line on
+.IR stderr .
+.TP
+.B \-e
+Compresses
+.I infile
+using a template specified, and writes to
+.IR compressed-outfile .
+.TP
+.B \-d
+Decompresses
+.I compressed-infile
+using the template contained in the compressed file.  Writes to
+.IR outfile .
+.TP
+\fB\-t \fP\fI\*(lqstring\*(rq\fP
+This option specifies which template combination is to
+be used in the compression.  Five different characters
+can occur in the string: `.' for a pixel not
+included in the template, `p' for a pixel included in the 1st
+level template, `2' for a pixel included in the 2nd level
+template (a subset of the 1st level), `*' denoting the position
+of the
+.I current
+pixel, and a `;' denoting the end of each template line.
+The default template is a two-level 22/10 template:
+.IP
+.RS
+.nf
+\&.ppppp.;
+pp222pp;
+p22222p;
+p22*.\|.\|.;
+.fi
+.RE
+.IP
+This would be specified on the command line as:
+.nf
+\&\fB\-T\fP ".ppppp.;pp222pp;p22222p;p22*.\|.\|.;"
+.fi
+.TP
+.I infile
+This is the input
+.I .pbm
+file to be compressed.
+.TP
+.I outfile
+This is the decompressed
+.I .pbm
+file.
+.SH "SEE ALSO"
+.na
+.BR mg (1),
+.BR mg_compression_dict (1),
+.BR mg_fast_comp_dict (1),
+.BR mg_get (1),
+.BR mg_invf_dict (1),
+.BR mg_invf_dump (1),
+.BR mg_invf_rebuild (1),
+.BR mg_passes (1),
+.BR mg_perf_hash_build (1),
+.BR mg_text_estimate (1),
+.BR mg_weights_build (1),
+.BR mgbuild (1),
+.BR mgdictlist (1),
+.BR mgfelics (1),
+.BR mgquery (1),
+.BR mgstat (1),
+.BR mgtic (1),
+.BR mgticbuild (1),
+.BR mgticdump (1),
+.BR mgticprune (1),
+.BR mgticstat (1).
Index: /main/tags/2.25/gsdl/packages/mg/src/images/mgbilevel.c
===================================================================
--- /main/tags/2.25/gsdl/packages/mg/src/images/mgbilevel.c	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/mg/src/images/mgbilevel.c	(revision 21064)
@@ -0,0 +1,149 @@
+/**************************************************************************
+ *
+ * mgbilevel.c -- Program to compress/decompress bilevel images
+ * Copyright (C) 1994  Stuart Inglis
+ *
+ * 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.
+ *
+ * $Id$
+ *
+ **************************************************************************/
+
+#include "sysfuncs.h"
+
+#include "utils.h"
+#include "pbmtools.h"
+#include "arithcode.h"
+#include "bilevel.h"
+
+
+
+static char default_template[] =
+{
+  ".ppppp.;"
+  "pp222pp;"
+  "p22222p;"
+  "p22*...;"
+};
+
+void 
+Encode_bitmap (marktype b, char template[])
+{
+  InitArithEncoding ();
+
+  bl_compress (b, template);
+
+  CloseDownArithEncoding ();
+}
+
+void 
+Decode_bitmap (marktype * b)
+{
+  InitArithDecoding ();
+
+  bl_decompress (b);
+
+  CloseDownArithDecoding ();
+}
+
+
+void 
+usage ()
+{
+  fprintf (stderr,
+	   "usage:\n"
+	   "       mgbilevel -e  [-t \"string\"]  infile      >compressed\n"
+	   "or\n"
+	   "       mgbilevel -d                 compressed  >outfile\n");
+  exit (1);
+}
+
+#define BUF_SIZE 65536
+
+void 
+main (int argc, char *args[])
+{
+  marktype d;
+  char *filename = NULL, *template = NULL;
+  Pixel **bitmap;
+  int encode = 0, decode = 0, i;
+  char buffer[BUF_SIZE];
+
+  if (argc < 2)
+    usage ();
+  template = default_template;
+  for (i = 1; i < argc; i++)
+    {
+      if (strcmp (args[i], "-e") == 0)
+	encode = 1;
+      else if (strcmp (args[i], "-d") == 0)
+	decode = 1;
+      else if (strcmp (args[i], "-h") == 0)
+	usage ();
+      else if (strcmp (args[i], "-t") == 0)
+	{
+	  template = args[i + 1];
+	  i++;
+	}
+      else if (args[i][0] == '-')
+	error_msg (args[0], "unknown switch:", args[i]);
+      else if (!filename)
+	filename = args[i];
+      else
+	error_msg (args[0], "only specify 1 filename", "");
+    }
+  if (encode == decode)
+    {
+      fprintf (stderr, "You must specify either encode XOR decode.\n");
+      exit (1);
+    }
+
+  if (!filename)
+    {
+      fprintf (stderr, "You must specify a filename.\n");
+      exit (1);
+    }
+
+  if (encode)
+    {
+      bitmap = pbm_readnamedfile (filename, &d.w, &d.h);
+      if (bitmap == NULL)
+	error_msg (args[0], "problem reading bitmap", "");
+
+      arith_out = stdout;
+      setbuffer (stdout, buffer, BUF_SIZE);
+      magic_write (stdout, MAGIC_BILEVEL);
+      if (bitmap)
+	{
+	  d.bitmap = bitmap;
+	  Encode_bitmap (d, template);
+	}
+    }
+  else if (decode)
+    {
+      FILE *tpin;
+      tpin = fopen (filename, "rb");
+      if (!tpin)
+	error_msg ("mgbilevel", "Can't open file:", filename);
+      arith_in = tpin;
+      setbuffer (tpin, buffer, BUF_SIZE);
+      magic_check (tpin, MAGIC_BILEVEL);
+      Decode_bitmap (&d);
+      fclose (tpin);
+
+      setbuffer (stdout, buffer, BUF_SIZE);
+      pbm_writefile (stdout, d.bitmap, d.w, d.h);
+    }
+}
Index: /main/tags/2.25/gsdl/packages/mg/src/images/mgfelics.1
===================================================================
--- /main/tags/2.25/gsdl/packages/mg/src/images/mgfelics.1	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/mg/src/images/mgfelics.1	(revision 21064)
@@ -0,0 +1,103 @@
+.\"------------------------------------------------------------
+.\" Id - set Rv,revision, and Dt, Date using rcs-Id tag.
+.de Id
+.ds Rv \\$3
+.ds Dt \\$4
+..
+.Id $Id$
+.\"------------------------------------------------------------
+.TH mgfelics 1 \*(Dt CITRI
+.SH NAME
+mgfelics \- fast and efficient lossless image (de)compression
+.SH SYNOPSIS
+.B mgfelics
+.B \-e
+[
+.BI \-k " n"
+]
+.I infile
+[
+.I \>compressed-outfile
+]
+.br
+or
+.br
+.B mgfelics
+.B \-d
+.I compressed-infile
+[
+.I \>outfile
+]
+.SH DESCRIPTION
+.B mgfelics
+is a lossless compression process which can (de)compress portable
+bitmap files in
+.I pgm
+format.
+.B mgfelics
+writes to
+.IR stdout .
+.SH OPTIONS
+.TP "\w'\fB\-k\fP \fIn\fP'u+2n"
+.BI \-k " n"
+An integer parameter (< 32) which controls the compression speed and
+ratio.  The value of
+.I n
+is included in the output stream, and therefore is not needed in the
+decompression stage.  The default value of
+.I n
+is equal to the number of bits required to represent each grey level.
+.TP
+.B \-e
+Encodes the file
+.IR infile ,
+sending the output to
+.IR stdout .
+.TP
+.B \-d
+Decodes the file from
+.IR compressed-infile ,
+sending the output to
+.IR stdout .
+.SH NOTE
+.B mgfelics
+uses a combination of adjusted binary and Rice codes, the choice of
+which for any given pixel depends on the environment as determined by
+the intensity values of neighbouring pixels.  The result is a very
+fast and lossless algorithm for compressing grayscale images.  The
+optional parameter
+.BI \-k " n"
+corresponds to the maximum exponent of the same name in Rice encoding.
+Smaller values of
+.BI \-k " n"
+can result in significant improvement in compression times with a
+corresponding loss in compression ratio.  However the reduction in
+compression ratio with a small
+.BI \-k " n"
+parameter may be insignificant for many images.
+.SH REFERENCES
+Algorithm by Paul G. Howard and Jeffrey Scott Vitter
+of Brown University, RI, and Duke University, NC, respectively.
+.SH "SEE ALSO"
+.na
+.BR mg (1),
+.BR mg_compression_dict (1),
+.BR mg_fast_comp_dict (1),
+.BR mg_get (1),
+.BR mg_invf_dict (1),
+.BR mg_invf_dump (1),
+.BR mg_invf_rebuild (1),
+.BR mg_passes (1),
+.BR mg_perf_hash_build (1),
+.BR mg_text_estimate (1),
+.BR mg_weights_build (1),
+.BR mgbilevel (1),
+.BR mgbuild (1),
+.BR mgdictlist (1),
+.BR mgquery (1),
+.BR mgstat (1),
+.BR mgtic (1),
+.BR mgticbuild (1),
+.BR mgticdump (1),
+.BR mgticprune (1),
+.BR mgticstat (1).
Index: /main/tags/2.25/gsdl/packages/mg/src/images/mgfelics.c
===================================================================
--- /main/tags/2.25/gsdl/packages/mg/src/images/mgfelics.c	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/mg/src/images/mgfelics.c	(revision 21064)
@@ -0,0 +1,155 @@
+/**************************************************************************
+ *
+ * mgfelics.c -- Program to compress/decompress grey scale images
+ * Copyright (C) 1994  Stuart Inglis
+ *
+ * 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.
+ *
+ * $Id$
+ *
+ **************************************************************************/
+
+#include "sysfuncs.h"
+#include "utils.h"
+
+
+#define MAXKVALUE 32
+
+
+
+void encode (unsigned int *line, int width, int height, int maxval, int maxk,
+	     FILE * fp_in, FILE * fp_out, int (*get) (FILE *));
+
+void decode (unsigned int *line, int width, int height, int maxval, int maxk,
+	     FILE * fp_in, FILE * fp_out);
+
+
+void 
+usage (char *prog)
+{
+  fprintf (stderr, "usage:\n");
+  fprintf (stderr, "\t%s -e [-k n]   infile    [>compressed]\n"
+	   "or\n"
+	   "\t%s -d  compressed-infile   [>outfile]\n", prog, prog);
+  exit (1);
+}
+
+
+
+
+int 
+main (int argc, char **argv)
+{
+  FILE *fp_in = (stdin), *fp_out = (stdout);
+  int width, height, maxval;
+  u_long magic;
+  char *filename = NULL;
+  unsigned int *line;
+  int maxk = 0;
+  int i;
+  int encode_flag = 0, decode_flag = 0;
+
+  if (argc < 2)
+    usage (argv[0]);
+
+  for (i = 1; i < argc; i++)
+    {
+      if (!strcmp (argv[i], "-h"))
+	usage (argv[0]);
+      else if (!strcmp (argv[i], "-e"))
+	encode_flag = 1;
+      else if (!strcmp (argv[i], "-d"))
+	decode_flag = 1;
+      else if (!strcmp (argv[i], "-k"))
+	{
+	  maxk = atoi (argv[++i]);
+	}
+      else if (argv[i][0] == '-')
+	error_msg (argv[0], "unknown switch:", argv[i]);
+      else if (!filename)
+	filename = argv[i];
+      else
+	error_msg (argv[0], "too many filenames specified.", "");
+    }
+
+  if (encode_flag == decode_flag)
+    error_msg (argv[0], "please specify either encode XOR decode.", "");
+
+  if (!filename)
+    error_msg (argv[0], "please specify a filename.", "");
+
+  if ((encode_flag) && (maxk >= MAXKVALUE))
+    {				/* to fit into 32 bit integers */
+      fprintf (stderr, "%s: k value of %d is too large; it must be less than %d\n",
+	       argv[0], maxk, MAXKVALUE);
+      exit (1);
+    }
+
+
+  if ((fp_in = fopen (filename, "rb")) == NULL)
+    error_msg (argv[0], "unable to open file:", filename);
+
+  /* read file header to determine the type and dimensions */
+
+
+  magic = magic_read (fp_in);
+  if (magic != MAGIC_FELICS)
+    {
+      rewind (fp_in);
+      magic = getmagicno_short_pop (fp_in);
+    }
+
+  if ((decode_flag && (magic != MAGIC_FELICS)) ||
+      (encode_flag && ((magic != MAGIC_P2) && (magic != MAGIC_P5))))
+    {
+      fclose (fp_in);
+      error_msg (argv[0], encode_flag ? "only PGM files can be used." : "only felics compressed files can be used.", "");
+    }
+
+  width = gethint (fp_in);
+  height = gethint (fp_in);
+  maxval = gethint (fp_in);
+
+  if ((line = (unsigned int *) malloc (width * sizeof (int *))) == NULL)
+    {
+      fclose (fp_in);
+      error_msg (argv[0], "unable to allocate memory,", "");
+    }
+
+
+  if (encode_flag)
+    {
+      magic_write (fp_out, MAGIC_FELICS);
+      fprintf (fp_out, "%d\n%d\n%d\n%d\n", width, height, maxval, maxk);
+      encode (line, width, height, maxval, maxk, fp_in, fp_out,
+	      magic == MAGIC_P2 ? getint : fgetc);
+    }
+  else if (decode_flag)
+    {
+      if (maxk)
+	warn (argv[0], "k value not required for decompression, ignored.", "");
+
+      maxk = gethint (fp_in);
+      fprintf (fp_out, "P%d\n%d %d\n%d\n", maxval < 256 ? 5 : 2,
+	       width, height, maxval);
+      decode (line, width, height, maxval, maxk, fp_in, fp_out);
+    }
+
+
+  fclose (fp_in);
+  fclose (fp_out);
+
+  return 0;
+}
Index: /main/tags/2.25/gsdl/packages/mg/src/images/mgtic.1
===================================================================
--- /main/tags/2.25/gsdl/packages/mg/src/images/mgtic.1	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/mg/src/images/mgtic.1	(revision 21064)
@@ -0,0 +1,137 @@
+.\"------------------------------------------------------------
+.\" Id - set Rv,revision, and Dt, Date using rcs-Id tag.
+.de Id
+.ds Rv \\$3
+.ds Dt \\$4
+..
+.Id $Id$
+.\"------------------------------------------------------------
+.TH mgtic 1 \*(Dt CITRI
+.SH NAME
+mgtic \- textual image compression.
+.SH SYNOPSIS
+.B mgtic
+.B \-e
+[
+.B \-L
+]
+[
+.B \-Q
+]
+[
+.B \-X
+]
+.I libraryfile
+.I infile
+.if n .ti +9n
+[
+.I \>compressed\-outfile
+]
+.nf
+or
+.fi
+.B mgtic
+.B \-d
+[
+.B \-L
+]
+[
+.BI \-X " libraryfile"
+]
+.I compressed-infile
+.if n .ti +9n
+[
+.I \>outfile
+]
+.SH DESCRIPTION
+This is the main routine in the
+.B mgtic
+system.
+.B mgtic
+is used to
+processes a series of files, and by using the
+.I libraryfile
+produced by
+.BR mgticbuild (1),
+compresses input files with respect to the marks contained in the
+library.  On the CCITT test faxes, lossless mode achieved around 20:1
+compression, and lossy, around 40:1 compression.  On more textual
+images, the amount of compression is determined by the resolution of
+the original file, and the amount of noise in the image.  By default,
+.B mgtic
+will reconstruct a lossy version of the image.  This
+can be changed to lossless by using the
+.B \-L
+option.
+.SH OPTIONS
+Options may appear in any order, but must come before the input
+filenames.
+.TP "\w'\fB\-X\fP \fI[libraryfile]\fP'u+2n"
+.B \-h
+This displays a usage line on
+.IR stderr .
+.TP
+.B \-e
+Encode
+.I infile
+with respect to the library.
+.TP
+.B \-d
+Decodes
+.IR compressed-infile
+with respect to the library.
+.TP
+.B \-l
+This specifies lossy mode, and is the default mode for (de)compression.
+Do not generate the residue.  If used in encoding mode, does not store
+the residue in the output.  If used in decoding mode, the residue (if
+it exists) is ignored.
+.TP
+.B \-L
+Use lossless mode for (de)compression, which generates the residue.
+If used in encoding mode, this stores the residue in the compressed
+output.  If used in decoding mode (assuming the residue is present),
+this allows the original file to be recovered exactly.
+.TP
+.BI \-R\  filename
+Stores the residue as an external file
+.I filename
+which could possibly be stored on another medium.  During
+decompression, if the residue file specified does not relate to the
+compressed file, the resulting decompressed image will be a mess.
+Note that only the width and height of the residue image is checked.
+.TP
+.BI \-Q
+Uses a quicker form of compression.  This option decreases the time
+spent looking for a good match during encoding.  On average this
+option decreases compression ratios, but increases compression speed.
+.TP
+.BI \-X " [libraryfile]"
+Use an external library file, instead of (de)compressing the library
+within the normal stream.  When decoding, the
+.B \-X
+option must be followed by the
+.IR libraryfile .
+.SH "SEE ALSO"
+.na
+.BR mg (1),
+.BR mg_compression_dict (1),
+.BR mg_fast_comp_dict (1),
+.BR mg_get (1),
+.BR mg_invf_dict (1),
+.BR mg_invf_dump (1),
+.BR mg_invf_rebuild (1),
+.BR mg_passes (1),
+.BR mg_perf_hash_build (1),
+.BR mg_text_estimate (1),
+.BR mg_weights_build (1),
+.BR mgbilevel (1),
+.BR mgbuild (1),
+.BR mgdictlist (1),
+.BR mgfelics (1),
+.BR mgquery (1),
+.BR mgstat (1),
+.BR mgticbuild (1),
+.BR mgticdump (1),
+.BR mgticprune (1),
+.BR mgticstat (1).
Index: /main/tags/2.25/gsdl/packages/mg/src/images/mgtic.c
===================================================================
--- /main/tags/2.25/gsdl/packages/mg/src/images/mgtic.c	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/mg/src/images/mgtic.c	(revision 21064)
@@ -0,0 +1,596 @@
+/**************************************************************************
+ *
+ * mgtic.c -- Program to compress/decompress textual images
+ * Copyright (C) 1994  Stuart Inglis
+ *
+ * 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.
+ *
+ * $Id$
+ *
+ **************************************************************************
+ *
+ * This file is the basis of mgtic, which compresses the components of an
+ * image. 
+ * The compressed file contains the following sections:
+ *         mgtic magic_no
+ *         mgtic version
+ *         lossy/lossless flag 
+ *         internal/external library flag 
+ *         cols, rows, number of marks, library size
+ *         [library sequence]
+ *         symbol sequence
+ *         offset sequence
+ *         [residue bitmap]
+ *
+ **************************************************************************/
+
+#include "sysfuncs.h"
+
+#include "marklist.h"
+#include "pbmtools.h"
+#include "extractor.h"
+#include "utils.h"
+#include "match.h"
+#include "sortmarks.h"
+#include "codesyms.h"
+#include "arithcode.h"
+#include "codeoffsets.h"
+#include "bilevel.h"
+
+static char library_template[] =
+{
+  ".ppppp.;"
+  "pp222pp;"
+  "p22222p;"
+  "p22*...;"
+};
+
+void 
+usage ()
+{
+  fprintf (stderr, "usage: \n"
+	"\tmgtic -e [-L] [-Q] [-X]  libraryfile   infile    [>compressed]\n"
+	   "or\n"
+	   "\tmgtic -d [-L] [-X libraryfile]  compressed  [>outfile]\n");
+  exit (1);
+}
+
+
+/* encode the list of marks 'list', w.r.t. the library 'library' */
+void 
+match_sequence (marklistptr list, marklistptr library, marklistptr * symbol_list, Pixel ** recon, int quick)
+{
+  int carryx, carryy, gap;
+  int lastx = 0, lasty = 0;
+  int i, j;
+  marktype d, d2;
+  marklistptr liststep, librarystep;
+  int score, found;
+  int r, c;
+  int p;
+
+  carryx = carryy = 0;
+  gap = max (1, marklist_length (list) / 10);
+
+  for (liststep = list, i = 0; liststep; liststep = liststep->next, i++)
+    {
+      if (V)
+	if (!(i % gap))
+	  fprintf (stderr, ".");
+      d = liststep->data;
+
+      found = -1;
+      score = INT_MAX;
+      for (librarystep = library, j = 0; librarystep; librarystep = librarystep->next, j++)
+	{
+	  d2 = librarystep->data;
+
+	  if (NOT_SCREENED (d2, d))
+	    if ((p = MATCH (&d, &d2)) < MATCH_VAL)
+	      {
+		if (p < score)
+		  {
+		    score = p;
+		    found = j;
+		    if (quick)
+		      break;
+		  }
+	      }
+	}
+      /*
+         if(found<0){
+         for(librarystep=library,j=0; librarystep; librarystep=librarystep->next,j++){
+         d2=librarystep->data;
+
+         if((p=MATCH(&d,&d2))<MATCH_VAL){
+         if(p<score){
+         score=p;found=j; if(quick) break;
+         }
+         }
+         }
+         }
+       */
+      if (found >= 0)
+	{
+	  liststep->data.symnum = found;
+	  marklist_getat (library, found, &d2);
+	  d2.symnum = found;
+
+	  d2.xoffset = d.xpos - lastx + carryx;		/* propagate changes to next mark */
+	  d2.yoffset = d.ypos - lasty + carryy;
+	  carryx = (d2.xcen - d.xcen);	/* offet centroids because thats where we match them! */
+	  carryy = (d2.ycen - d.ycen);
+	  d2.xoffset -= carryx;	/* make the changes to this mark */
+	  d2.yoffset -= carryy;
+	  lastx = d.xpos + d2.w;
+	  lasty = d.ypos;
+
+	  marklist_add (symbol_list, d2);
+
+	  /* add to the reconstructed image--this is the lossy version */
+	  for (r = 0; r < d2.h; r++)
+	    for (c = 0; c < d2.w; c++)
+	      if (pbm_getpixel (d2.bitmap, c, r))
+		pbm_putpixel_trunc (recon, d.xpos + c - carryx, d.ypos + r - carryy, 1, d2.w, d2.h);
+	}
+      else
+	{
+	  /* didn't match at all..hopefully noise */
+	  if ((liststep->data.w >= 10) || (liststep->data.w >= 10))
+	    {
+	      fprintf (stderr, "mgtic: warning, unable to match a char.\n");
+	      write_library_mark (stderr, liststep->data);
+	    }
+	  if (V)
+	    fprintf (stderr, "x");
+	  liststep->data.symnum = -1;
+	}
+    }
+  if (V)
+    fprintf (stderr, "\n");
+}
+
+
+
+
+void 
+main (int argc, char *args[])
+{
+  int i, n, r, c, ch;
+  FILE *inf;
+  marklistptr library = NULL, list = NULL, step = NULL;
+  marklistptr symbol_list = NULL;
+  marktype d, d2;
+  Pixel **bitmap, **recon, **bitmapcopy;
+  char *splitfilename = NULL;
+  int cols, rows, count, librarysize, lossy = 1;
+  int quick = 0;
+  int ticencode = 0, ticdecode = 0, external = 0;
+  char *libraryname = NULL, *infile = NULL;
+  char *s1 = NULL, *s2 = NULL;
+  char bufferin[BUFSIZ], bufferout[BUFSIZ];
+
+  if (argc < 2)
+    usage ();
+
+  while ((ch = getopt (argc, args, "edlLQhvXR:")) != -1)
+    switch (ch)
+      {
+      case 'e':
+	ticencode = 1;
+	break;
+      case 'd':
+	ticdecode = 1;
+	break;
+      case 'l':
+	lossy = 1;
+	break;
+      case 'L':
+	lossy = 0;
+	break;
+      case 'Q':
+	quick = 1;
+	break;
+      case 'v':
+	V = 1;
+	break;
+      case 'X':
+	external = 1;
+	break;
+      case 'R':
+	splitfilename = optarg;
+	break;
+      case 'h':
+      case '?':
+	usage ();
+      }
+
+  for (i = 1; i < argc; i++)
+    if (args[i][0] != '-')
+      if (strcmp (args[i - 1], "-R"))
+	{			/* ignore arg following -R, ie. -R <filename> */
+	  if (!s1)
+	    s1 = args[i];
+	  else if (!s2)
+	    s2 = args[i];
+	  else
+	    error_msg (args[0], "too many filenames", "");
+	}
+
+  if (ticencode == ticdecode)
+    error_msg (args[0], "please specify either encode XOR decode", "");
+
+  if (ticencode)
+    {
+	  /*****************
+	    ENCODING STAGE
+	  *****************/
+      long PrevBits = 0;
+      long BITS_header = 0, BITS_symbols = 0, BITS_offsets = 0, BITS_residue = 0,
+        BITS_footer = 0, BITS_library = 0;
+
+      libraryname = s1;
+      if (!libraryname)
+	error_msg (args[0], "please specify a library file", "");
+      infile = s2;
+      if (!infile)
+	error_msg (args[0], "please specify a file name", "");
+
+      inf = fopen (infile, "rb");
+      if (inf == NULL)
+	error_msg (args[0], "Trouble opening file:", infile);
+      setbuf (inf, bufferin);
+
+      count = librarysize = read_library (libraryname, &library);
+
+      if (V)
+	fprintf (stderr, "%s: processing...\n", args[0]);
+
+      if (pbm_isapbmfile (inf))
+	{
+	  if (V)
+	    fprintf (stderr, "reading file %s...\n", infile);
+	  bitmap = pbm_readfile (inf, &cols, &rows);
+	  fclose (inf);
+
+	  bitmapcopy = pbm_copy (bitmap, cols, rows);
+
+	  if (V)
+	    fprintf (stderr, "extracting...");
+	  ExtractAllMarks (bitmap, &list, cols, rows);
+	  if (V)
+	    fprintf (stderr, "(%d marks)\n", marklist_length (list));
+
+	  /* sort into reading order */
+	  if (V)
+	    fprintf (stderr, "sorting...\n");
+	  list = sortmarks (list);
+
+	  pbm_freearray (&bitmap, rows);	/* clear old version */
+	  bitmap = bitmapcopy;	/* point to the copy */
+	  recon = pbm_allocarray (cols, rows);
+
+	  if (V)
+	    fprintf (stderr, "matching...");
+
+	  match_sequence (list, library, &symbol_list, recon, quick);
+
+
+	  PrevBits = 0;
+	  setbuf (stdout, bufferout);
+	  /* start output */
+	  magic_write (stdout, MAGIC_TIC);
+	  InitArithEncoding ();
+
+	  EncodeGammaDist (1);	/* version 1 of the program */
+	  EncodeGammaDist (lossy);	/* lossy=1 = no residue */
+	  EncodeGammaDist (external);	/* 1== external file */
+
+	  count = marklist_length (symbol_list);
+	  if (V)
+	    fprintf (stderr, "encoding cols, rows, and number of symbols=%d\n", count);
+
+	  EncodeGammaDist (cols);
+	  EncodeGammaDist (rows);
+	  EncodeGammaDist (count);
+	  EncodeGammaDist (librarysize);
+
+	  BITS_header = CountOfBitsOut - PrevBits;
+	  PrevBits = CountOfBitsOut;
+
+
+	  /* output the library sequence */
+	  if (external == 0)
+	    {
+	      if (V)
+		fprintf (stderr, "encoding library\n");
+
+	      bl_clearmodel ();
+	      bl_writetemplate (library_template);
+	      for (step = library; step; step = step->next)
+		bl_compress_mark (step->data);
+	      bl_freemodel ();
+	      BITS_library = CountOfBitsOut - PrevBits;
+	      PrevBits = CountOfBitsOut;
+	    }
+
+	  /* output the symbol sequence */
+	  if (V)
+	    fprintf (stderr, "encoding symbol sequence\n");
+	  InitPPM ();
+	  EncodeSymbols (symbol_list, count);
+	  BITS_symbols = CountOfBitsOut - PrevBits;
+	  PrevBits = CountOfBitsOut;
+
+
+	  /* output the offset sequence */
+	  if (V)
+	    fprintf (stderr, "encoding offset sequence\n");
+	  EncodeOffsets (symbol_list, count);
+	  BITS_offsets = CountOfBitsOut - PrevBits;
+	  PrevBits = CountOfBitsOut;
+
+	  EncodeChecksum ();	/* code lossy checksum */
+
+	  /* calculate the residue...and compress it---if need be! */
+	  if (!lossy)
+	    {
+	      if (V)
+		fprintf (stderr, "encoding residue...\n");
+
+	      d.bitmap = bitmap;
+	      d.h = rows;
+	      d.w = cols;
+	      d2.bitmap = recon;
+	      d2.h = rows;
+	      d2.w = cols;
+
+	      if (splitfilename)
+		{
+		  FILE *temp;
+
+		  CloseDownArithEncoding ();
+		  fclose (stdout);
+		  /* no residue result */
+		  BITS_footer = CountOfBitsOut - PrevBits;
+
+		  temp = fopen (splitfilename, "wb");
+		  if (temp == NULL)
+		    error_msg (args[0], "Trouble creating file:", splitfilename);
+
+		  arith_out = temp;
+		  InitArithEncoding ();
+		  bl_clair_compress (d, d2);
+		  CloseDownArithEncoding ();
+		  BITS_residue = CountOfBitsOut;
+		  fclose (temp);
+		}
+	      else
+		{
+		  bl_clair_compress (d, d2);
+		  BITS_residue = CountOfBitsOut - PrevBits;
+		  PrevBits = CountOfBitsOut;
+		  EncodeChecksum ();	/* code lossless checksum */
+		  CloseDownArithEncoding ();
+		  BITS_footer = CountOfBitsOut - PrevBits;
+		}
+	    }
+	  else
+	    {
+	      if (V)
+		fprintf (stderr, "not encoding residue..lossy mode\n");
+	      CloseDownArithEncoding ();
+	      BITS_footer = CountOfBitsOut - PrevBits;
+	    }
+
+	  /* because we edit the values above */
+	  CountOfBitsOut = BITS_header + BITS_library + BITS_symbols + BITS_offsets + BITS_residue + BITS_footer;
+
+	  fprintf (stderr, "bits: header=%ld, library=%ld, "
+		   "symbols=%ld, offsets=%ld, residue=%ld, footer=%ld\n",
+		   BITS_header, BITS_library, BITS_symbols,
+		   BITS_offsets, BITS_residue, BITS_footer);
+	  fprintf (stderr, "total bits: %ld, ", CountOfBitsOut);
+	  fprintf (stderr, "Lossy CR: %4.2f", (cols * rows) / (float) (CountOfBitsOut - BITS_residue));
+	  if (external)
+	    fprintf (stderr, " (excluding external lib)");
+	  fprintf (stderr, ", Lossless CR: %4.2f\n", (!lossy) * (cols * rows) / (float) (CountOfBitsOut));
+	}
+      else
+	error_msg (args[0], "unknown format of bitmap--expecting PBM.", "");
+    }
+  else
+    {
+	  /*****************
+	    DECODING STAGE
+	  *****************/
+      int lastx, lasty;
+      librarysize = 0;
+
+      if (external)
+	{
+	  libraryname = s1;
+	  infile = s2;
+	  count = librarysize = read_library (libraryname, &library);
+	}
+      else
+	{
+	  infile = s1;
+	  if (infile && s2)
+	    error_msg (args[0], "too many filenames", "");
+	}
+
+      if (!freopen (infile, "rb", stdin))
+	error_msg (args[0], "Trouble opening file:", infile);
+
+
+      if (V)
+	fprintf (stderr, "decompressing...\n");
+
+      setbuf (stdin, bufferin);
+      magic_check (stdin, MAGIC_TIC);
+
+      InitArithDecoding ();
+
+      {
+	int version = DecodeGammaDist ();
+	if (version != 1)
+	  error_msg (args[0], "Need later version of decompressor.", "");
+      }
+
+      {
+	int templossy = DecodeGammaDist ();
+	if (!lossy)
+	  lossy = templossy;	/* can only choose if encoded file is lossless */
+	if (V)
+	  {
+	    if (lossy)
+	      fprintf (stderr, "lossy mode\n");
+	    else
+	      fprintf (stderr, "lossless mode\n");
+	  }
+      }
+
+      if (DecodeGammaDist ())
+	{			/* if compressed file doesn't contain library */
+	  if (!external)
+	    error_msg (args[0], "compressed file doesn't contain library, specify externally", "");
+	  external = 1;
+	}
+      else
+	{			/* if compressed file contains library */
+	  if (external)
+	    fprintf (stderr, "ignoring external library file\n");
+	  external = 0;
+	}
+
+      cols = DecodeGammaDist ();
+      rows = DecodeGammaDist ();
+      count = DecodeGammaDist ();
+
+      i = DecodeGammaDist ();	/* librarysize */
+      if (external)
+	{
+	  if (i > librarysize)
+	    error_msg (args[0], "external library file is too small!", "");
+	  else if (i < librarysize)
+	    fprintf (stderr, "%s: warning, expecting a different (smaller) library.\n", args[0]);
+	}
+      librarysize = i;
+
+      if (V)
+	fprintf (stderr, "cols %d, rows %d, num syms %d, library size %d\n", cols, rows, count, librarysize);
+
+      /* decode library */
+      if (external == 0)
+	{
+	  if (V)
+	    fprintf (stderr, "reading library\n");
+	  bl_clearmodel ();
+	  bl_readtemplate ();
+	  for (n = 0; n < librarysize; n++)
+	    {
+	      bl_decompress_mark (&d);
+	      d.symnum = n;
+	      if (library == NULL)
+		step = marklist_add (&library, d);
+	      else
+		step = marklist_add (&step, d);
+	    }
+	  bl_freemodel ();
+	  if (V)
+	    fprintf (stderr, "read %d marks from library\n", marklist_length (library));
+	}
+
+      recon = pbm_allocarray (cols, rows);
+
+      /* decode symbols */
+      InitPPM ();
+      if (V)
+	fprintf (stderr, "decompressing %d symbols\n", count);
+      symbol_list = DecodeSymbols (count);
+
+      /* decode offsets */
+      if (V)
+	fprintf (stderr, "reading offsets...\n");
+      DecodeOffsets (symbol_list, count);
+      lastx = lasty = 0;
+      for (step = symbol_list; step; step = step->next)
+	{
+	  lastx = lastx + step->data.xoffset;
+	  lasty = lasty + step->data.yoffset;
+
+	  marklist_getat (library, step->data.symnum, &d2);
+	  for (r = 0; r < d2.h; r++)
+	    for (c = 0; c < d2.w; c++)
+	      if (pbm_getpixel (d2.bitmap, c, r))
+		pbm_putpixel_trunc (recon, lastx + c, lasty + r, 1, cols, rows);	/* we don't care, already warned them! */
+	  lastx += d2.w;
+	}
+
+      DecodeChecksum (args[0]);
+
+      /* decode the residue */
+      if (!lossy)
+	{
+	  if (V)
+	    fprintf (stderr, "decoding residue...\n");
+
+	  bitmap = pbm_allocarray (cols, rows);
+	  d.bitmap = bitmap;
+	  d.w = d2.w = cols;
+	  d.h = d2.h = rows;
+
+	  d2.bitmap = recon;
+
+	  /* NOTE: the 2nd argument is clairvoyantly compressed */
+	  if (splitfilename)
+	    {
+	      FILE *temp;
+
+	      CloseDownArithDecoding ();
+	      fclose (stdin);
+
+	      temp = fopen (splitfilename, "rb");
+	      if (temp == NULL)
+		error_msg (args[0], "Trouble opening file:", splitfilename);
+
+	      arith_in = temp;
+	      InitArithDecoding ();
+	      bl_clair_decompress (d, d2);
+	      CloseDownArithDecoding ();
+	      fclose (temp);
+	    }
+	  else
+	    {
+	      bl_clair_decompress (d, d2);
+	      DecodeChecksum (args[0]);
+	      CloseDownArithDecoding ();
+	    }
+	  pbm_freearray (&recon, rows);
+	  recon = bitmap;	/* point to the bitmap */
+	}
+      else
+	{
+	  CloseDownArithDecoding ();
+	}
+
+      if (V)
+	fprintf (stderr, "writing pbm file...\n");
+      setbuf (stdout, bufferout);
+      pbm_writefile (stdout, recon, cols, rows);
+      pbm_freearray (&recon, rows);
+    }				/* end decoding */
+}
Index: /main/tags/2.25/gsdl/packages/mg/src/images/mgticbuild.1
===================================================================
--- /main/tags/2.25/gsdl/packages/mg/src/images/mgticbuild.1	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/mg/src/images/mgticbuild.1	(revision 21064)
@@ -0,0 +1,61 @@
+.\"------------------------------------------------------------
+.\" Id - set Rv,revision, and Dt, Date using rcs-Id tag.
+.de Id
+.ds Rv \\$3
+.ds Dt \\$4
+..
+.Id $Id$
+.\"------------------------------------------------------------
+.TH mgticbuild 1 \*(Dt CITRI
+.SH NAME
+mgticbuild \- build a library of marks from training documents
+.SH SYNOPSIS
+.B mgticbuild
+[
+.B \-h
+]
+.I "libraryfile infile1 infile2 .\|.\|."
+.SH DESCRIPTION
+.B mgticbuild
+builds an uncompressed library of marks that have been
+extracted from a series of input files.  If the
+.I libraryfile
+does
+not exist, it is created, otherwise new marks are appended to the
+file.
+.SH OPTIONS
+Options may appear in any order.
+.TP "\w'\fIlibraryfile\fP'u+2n"
+.B \-h
+This displays a usage line on
+.IR stderr .
+.TP
+.I libraryfile
+This specifies the name of the library file.
+.TP
+.I infile(s)
+The training files; the only currently-supported format is
+.IR pbm .
+.SH "SEE ALSO"
+.na
+.BR mg (1),
+.BR mg_compression_dict (1),
+.BR mg_fast_comp_dict (1),
+.BR mg_get (1),
+.BR mg_invf_dict (1),
+.BR mg_invf_dump (1),
+.BR mg_invf_rebuild (1),
+.BR mg_passes (1),
+.BR mg_perf_hash_build (1),
+.BR mg_text_estimate (1),
+.BR mg_weights_build (1),
+.BR mgbilevel (1),
+.BR mgbuild (1),
+.BR mgdictlist (1),
+.BR mgfelics (1),
+.BR mgquery (1),
+.BR mgstat (1),
+.BR mgtic (1),
+.BR mgticdump (1),
+.BR mgticprune (1),
+.BR mgticstat (1).
Index: /main/tags/2.25/gsdl/packages/mg/src/images/mgticbuild.c
===================================================================
--- /main/tags/2.25/gsdl/packages/mg/src/images/mgticbuild.c	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/mg/src/images/mgticbuild.c	(revision 21064)
@@ -0,0 +1,145 @@
+/**************************************************************************
+ *
+ * mgticbuild.c -- Program to build the textual image library
+ * Copyright (C) 1994  Stuart Inglis
+ *
+ * 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.
+ *
+ * $Id$
+ *
+ **************************************************************************/
+
+#include "sysfuncs.h"
+
+#include "marklist.h"
+#include "pbmtools.h"
+#include "extractor.h"
+#include "utils.h"
+
+
+void 
+usage ()
+{
+  fprintf (stderr, "usage: \n"
+	"\tmgticbuild   libraryfile   infile.pbm  [infile2 infile3 ...]\n");
+  exit (1);
+}
+
+void 
+main (int argc, char *args[])
+{
+  int i;
+  FILE *lib = NULL, *inf = NULL;
+  marklistptr list = NULL, step;
+  Pixel **bitmap;
+  int cols, rows;
+  int count, pos = 0;
+  char *libraryname = NULL;
+
+  if (argc < 2)
+    usage ();
+
+  for (i = 1; i < argc; i++)
+    {
+      if (!strcmp (args[i], "-v"))
+	V = 1;
+      else if (!strcmp (args[i], "-h"))
+	usage ();
+      else if (args[i][0] == '-')
+	error_msg (args[0], "unknown switch:", args[i]);
+      else if (!libraryname)
+	libraryname = args[i];
+      else
+	pos = i;
+    }
+
+  if (!libraryname)
+    error_msg (args[0], "please specify a library file", "");
+  if (pos < 2)
+    usage ();
+
+  count = 0;
+  for (i = pos; i < argc; i++)
+    if (args[i][0] != '-')
+      {
+	inf = fopen (args[i], "rb");
+	count = 0;
+	if (inf == NULL)
+	  fprintf (stderr, "Trouble opening file: %s\n", args[i]);
+	else
+	  {
+	    if (pbm_isapbmfile (inf))
+	      {
+		if (V)
+		  fprintf (stderr, "%s: processing...\n", args[0]);
+		if (V)
+		  fprintf (stderr, "reading file %s...", args[i]);
+		bitmap = pbm_readfile (inf, &cols, &rows);
+		if (V && (count == 0))
+		  fprintf (stderr, "building...");
+
+		list = NULL;
+
+		ExtractAllMarks (bitmap, &list, cols, rows);
+
+		if (V)
+		  fprintf (stderr, "writing...");
+
+		if ((!lib) && (marklist_length (list)))
+		  {
+		    lib = fopen (libraryname, "r");
+		    if (lib)
+		      {
+			fclose (lib);
+			lib = fopen (libraryname, "ab");
+			if (lib == NULL)
+			  error_msg (args[0], "trouble appending library file", "");
+			fprintf (stderr, "\nwarning: appending library file: %s\n", libraryname);
+		      }
+		    else
+		      {
+			lib = fopen (libraryname, "wb");
+			if (lib == NULL)
+			  error_msg (args[0], "trouble creating library file", "");
+		      }
+		  }		/* if !lib */
+
+		step = list;
+		while (step)
+		  {
+		    step->data.symnum = count;
+		    write_library_mark (lib, step->data);
+		    count++;
+		    step = step->next;
+		  }
+		pbm_freearray (&bitmap, rows);
+	      }
+	    else
+	      fprintf (stderr, "warning: %s is not a PBM file.\n", args[i]);
+	    fclose (inf);
+	  }
+	if (count)
+	  {
+	    if (V)
+	      fprintf (stderr, "%d marks written.\n", count);
+	  }
+	else
+	  fprintf (stderr, "No marks written!\n");
+      }
+
+  if (lib)
+    fclose (lib);
+  marklist_free (&list);
+}
Index: /main/tags/2.25/gsdl/packages/mg/src/images/mgticdump.1
===================================================================
--- /main/tags/2.25/gsdl/packages/mg/src/images/mgticdump.1	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/mg/src/images/mgticdump.1	(revision 21064)
@@ -0,0 +1,55 @@
+.\"------------------------------------------------------------
+.\" Id - set Rv,revision, and Dt, Date using rcs-Id tag.
+.de Id
+.ds Rv \\$3
+.ds Dt \\$4
+..
+.Id $Id$
+.\"------------------------------------------------------------
+.TH mgticdump 1 \*(Dt CITRI
+.SH NAME
+mgticdump \- displays the library in a user-friendly manner
+.SH SYNOPSIS
+.B mgticdump
+[
+.B \-h
+]
+.I libraryfile
+.SH DESCRIPTION
+.B mgticdump
+displays the marks in a library in a user-viewable form.  The output
+is to
+.I stdout
+and is in a plain ASCII form.
+.SH OPTIONS
+Options may appear in any order.
+.TP "\w'\fIlibraryfile\fP'u+2n"
+.B \-h
+This displays a usage line on
+.IR stderr .
+.TP
+.I libraryfile
+This specifies the name of the library file.
+.SH "SEE ALSO"
+.na
+.BR mg (1),
+.BR mg_compression_dict (1),
+.BR mg_fast_comp_dict (1),
+.BR mg_get (1),
+.BR mg_invf_dict (1),
+.BR mg_invf_dump (1),
+.BR mg_invf_rebuild (1),
+.BR mg_passes (1),
+.BR mg_perf_hash_build (1),
+.BR mg_text_estimate (1),
+.BR mg_weights_build (1),
+.BR mgbilevel (1),
+.BR mgbuild (1),
+.BR mgdictlist (1),
+.BR mgfelics (1),
+.BR mgquery (1),
+.BR mgstat (1),
+.BR mgtic (1),
+.BR mgticbuild (1),
+.BR mgticprune (1),
+.BR mgticstat (1).
Index: /main/tags/2.25/gsdl/packages/mg/src/images/mgticdump.c
===================================================================
--- /main/tags/2.25/gsdl/packages/mg/src/images/mgticdump.c	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/mg/src/images/mgticdump.c	(revision 21064)
@@ -0,0 +1,86 @@
+/**************************************************************************
+ *
+ * mgticdump.c -- Program to dump out a library in a human readable form
+ * Copyright (C) 1994  Stuart Inglis
+ *
+ * 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.
+ *
+ * $Id$
+ *
+ **************************************************************************/
+
+#include "sysfuncs.h"
+
+#include "marklist.h"
+#include "pbmtools.h"
+#include "extractor.h"
+#include "utils.h"
+
+
+void 
+usage ()
+{
+  fprintf (stderr, "usage:\n"
+	   "\tmgticdump   libraryfile\n");
+  exit (1);
+}
+
+
+
+void 
+main (int argc, char *args[])
+{
+  FILE *lib;
+  int count, i;
+  marktype d;
+  char *libraryname = NULL;
+  FILE *outf = (stdout);
+
+  if (argc < 2)
+    usage ();
+
+  for (i = 1; i < argc; i++)
+    {
+      if (!strcmp (args[i], "-h"))
+	usage ();
+      else if (args[i][0] == '-')
+	error_msg (args[0], "unknown switch:", args[i]);
+      else if (!libraryname)
+	libraryname = args[i];
+      else
+	error_msg (args[0], "too many filenames", "");
+    }
+
+  if (!libraryname)
+    error_msg (args[0], "please specify a library file", "");
+
+
+  lib = fopen (libraryname, "rb");
+  if (lib == NULL)
+    error_msg (args[0], "trouble opening library file:", libraryname);
+
+  count = 0;
+  while (!isEOF (lib))
+    {
+      read_library_mark (lib, &d);
+
+      write_library_mark (outf, d);
+      count++;
+
+      pbm_freearray (&d.bitmap, d.h);
+    }
+  fprintf (stderr, "count=%d", count);
+  fclose (lib);
+}
Index: /main/tags/2.25/gsdl/packages/mg/src/images/mgticprune.1
===================================================================
--- /main/tags/2.25/gsdl/packages/mg/src/images/mgticprune.1	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/mg/src/images/mgticprune.1	(revision 21064)
@@ -0,0 +1,91 @@
+.\"------------------------------------------------------------
+.\" Id - set Rv,revision, and Dt, Date using rcs-Id tag.
+.de Id
+.ds Rv \\$3
+.ds Dt \\$4
+..
+.Id $Id$
+.\"------------------------------------------------------------
+.TH mgticprune 1 \*(Dt CITRI
+.SH NAME
+mgticprune \- prunes the library to remove duplicates
+.SH SYNOPSIS
+.B mgticprune
+[
+.BI \-a " n"
+]
+[
+.BI \-s " n"
+]
+[
+.B \-Q
+]
+.I libraryfile
+.if n .ti +9n
+[
+.I pruned-libraryfile
+]
+.SH DESCRIPTION
+.B mgticprune
+examines
+.I libraryfile
+and removes duplicate marks.  If
+.I pruned-libraryfile
+is not specified,
+.I libraryfile
+is overwritten with the marks in the pruned library.  The Combined
+Symbol Independent Strategy (CSIS) method is used to match marks.
+.SH OPTIONS
+Options may appear in any order.
+.TP "\w'\fIpruned-libraryfile\fP'u+2n"
+.B \-h
+This displays a usage line on
+.IR stderr .
+.TP
+.BI \-a " n"
+Prune marks when their area is under or equal to the threshold,
+.IR n .
+The default value is\ 3.
+.TP
+.BI \-s " n"
+Prune marks when their width and height is under or equal to
+the threshold,
+.IR n .
+The default value is\ 0.
+.TP
+.BI \-Q
+Use a quicker method of pruning.  The number of iterations through the
+averaging and pruning processes is decreased.  This usually reduces
+time by a half, but compression ratios decrease.
+.TP
+.I libraryfile
+This specifies the name of the library file
+.TP
+.I pruned-libraryfile
+This specifies the name of the prune library, after duplicates and
+matches have been removed.  If this file is not specified, then
+.I libraryfile
+will be overwritten.
+.SH "SEE ALSO"
+.na
+.BR mg (1),
+.BR mg_compression_dict (1),
+.BR mg_fast_comp_dict (1),
+.BR mg_get (1),
+.BR mg_invf_dict (1),
+.BR mg_invf_dump (1),
+.BR mg_invf_rebuild (1),
+.BR mg_passes (1),
+.BR mg_perf_hash_build (1),
+.BR mg_text_estimate (1),
+.BR mg_weights_build (1),
+.BR mgbilevel (1),
+.BR mgbuild (1),
+.BR mgdictlist (1),
+.BR mgfelics (1),
+.BR mgquery (1),
+.BR mgstat (1),
+.BR mgtic (1),
+.BR mgticbuild (1),
+.BR mgticdump (1),
+.BR mgticstat (1).
Index: /main/tags/2.25/gsdl/packages/mg/src/images/mgticprune.c
===================================================================
--- /main/tags/2.25/gsdl/packages/mg/src/images/mgticprune.c	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/mg/src/images/mgticprune.c	(revision 21064)
@@ -0,0 +1,393 @@
+/**************************************************************************
+ *
+ * mgticprune.c -- Program to prune a textual image library
+ * Copyright (C) 1994  Stuart Inglis
+ *
+ * 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.
+ *
+ * $Id$
+ *
+ **************************************************************************/
+
+#include "sysfuncs.h"
+
+#include "marklist.h"
+#include "pbmtools.h"
+#include "extractor.h"
+#include "utils.h"
+#include "match.h"
+
+marklistptr *avglib = NULL;
+int avglibsize;
+int libsize = 0;
+
+
+void 
+usage ()
+{
+  fprintf (stderr, "usage:\n"
+    "\tmgticbuild [-a n]  [-s n]  [-Q]   libraryfile   [pruned-library]\n");
+  exit (1);
+}
+
+
+
+
+/* foreach list in the avglib[] array, an average mark is returned */
+marklistptr 
+average_library ()
+{
+  marklistptr librarylist;
+  int i;
+  marktype avgmark;
+
+  librarylist = NULL;
+  for (i = 0; i < libsize; i++)
+    {
+      if (avglib[i])
+	{
+	  marklist_average (avglib[i], &avgmark);
+	  avgmark.symnum = i;
+	  marklist_addcopy (&librarylist, avgmark);
+	}
+    }
+  return librarylist;
+}
+
+
+void 
+average_space_enlarge ()
+{
+  int j;
+
+  if (libsize >= avglibsize)
+    {
+      avglib = (marklistptr *) realloc (avglib, (avglibsize + 100) * sizeof (marklistptr));
+      if (!avglib)
+	error_msg ("mgticprune", "out of memory in reallocating..", "");
+      for (j = avglibsize; j < avglibsize + 100; j++)
+	avglib[j] = NULL;
+      avglibsize += 100;
+    }
+}
+
+
+/* for each mark in 'origlist', if it can't be matched with one in 
+   'librarylist', then add to the librarylist, and update the relevant
+   avglib[] position */
+void 
+greedy_add (marklistptr origlist, marklistptr * librarylist)
+{
+  marklistptr step, step_i;
+  int i, j, notfound;
+  marktype d_i;
+
+  for (i = 0, step_i = origlist; step_i; i++, step_i = step_i->next)
+    {
+      d_i = step_i->data;
+
+      notfound = 1;
+      for (j = 0, step = *librarylist; step; j++, step = step->next)
+	{
+	  if (NOT_SCREENED (d_i, step->data))
+	    if (MATCH (&d_i, &step->data) < MATCH_VAL)
+	      {
+		d_i.symnum = j;
+		marklist_addcopy (&avglib[j], d_i);
+		notfound = 0;
+		break;
+	      }
+	}
+
+      if (notfound)
+	{
+	  d_i.symnum = libsize;
+	  marklist_addcopy (librarylist, d_i);
+	  marklist_addcopy (&avglib[libsize], d_i);
+	  libsize++;
+	  if (libsize >= avglibsize)
+	    average_space_enlarge ();
+	}
+    }
+}
+
+
+
+/* for each mark in 'library', if another matches with it, remove
+   one copy from the library, and erase the relevant avglib[] */
+void 
+greedy_prune (marklistptr * library)
+{
+  int count;
+  int i, j;
+  marklistptr step;
+  marktype d;
+
+  count = marklist_length (*library);
+  /* an invariant, all marks <i have been kept in the pruned library */
+  for (i = 0; i < count; i++)
+    {
+      marklist_getat (*library, i, &d);
+
+      for (j = 0, step = *library; j < i; j++, step = step->next)
+	{
+	  if (NOT_SCREENED (d, step->data))
+	    if (MATCH (&d, &step->data) < MATCH_VAL)
+	      {
+		/* [i,d] has matched with library element [j,d2]. */
+		marklist_removeat (library, i);		/* because we kill it here */
+		marklist_free (&avglib[d.symnum]);
+		avglib[d.symnum] = NULL;
+		i--, count--;
+		break;
+	      }
+	}
+    }
+}
+
+
+void 
+prune_on_size (marklistptr * list, int sizethres)
+{
+  int count, i;
+  marktype d;
+
+  if (sizethres)
+    {
+      count = marklist_length (*list);
+      i = 0;
+      do
+	{
+	  marklist_getat (*list, i, &d);
+	  if ((d.w <= sizethres) && (d.h <= sizethres))
+	    {
+	      marklist_removeat (list, i);
+	      i--;
+	      count--;
+	    }
+	  i++;
+	}
+      while (i < count);
+    }
+}
+
+
+
+void 
+prune_on_area (marklistptr * list, int areathres)
+{
+  int count, i;
+  marktype d;
+
+  if (areathres)
+    {
+      count = marklist_length (*list);
+      i = 0;
+      do
+	{
+	  marklist_getat (*list, i, &d);
+	  if (d.set <= areathres)
+	    {
+	      marklist_removeat (list, i);
+	      i--;
+	      count--;
+	    }
+	  i++;
+	}
+      while (i < count);
+    }
+}
+
+
+void 
+averagedout_addagain (marklistptr origlist, marklistptr * librarylist)
+{
+  marklistptr step, stepi;
+  int notfound;
+  int i, j;
+
+  for (i = 0, step = origlist; step; i++, step = step->next)
+    {
+      notfound = 1;
+
+      for (j = 0, stepi = *librarylist; stepi; j++, stepi = stepi->next)
+	if (NOT_SCREENED (step->data, stepi->data))
+	  if (MATCH (&step->data, &stepi->data) < MATCH_VAL)
+	    {
+	      notfound = 0;
+	      break;
+	    }
+
+      if (notfound)
+	{
+	  marklist_addcopy (librarylist, step->data);
+	  marklist_addcopy (&avglib[libsize], step->data);
+	  libsize++;
+	  if (libsize >= avglibsize)
+	    average_space_enlarge ();
+	}
+    }
+}
+
+
+
+
+
+void 
+main (int argc, char *args[])
+{
+  int i;
+  FILE *lib;
+
+  marklistptr origlist = NULL, librarylist = NULL;
+  marklistptr step;
+  char tempn[1000], sysstr[1000];
+  int count;
+  char *libraryname = NULL, *prunename = NULL;
+  int sizethres = 3, areathres = 0;
+  int pass;
+  int num_passes = 3;
+  int overwrite = 0;
+
+  V = 0;
+
+  if (argc < 2)
+    usage ();
+
+  for (i = 1; i < argc; i++)
+    {
+      if (!strcmp (args[i], "-v"))
+	V = 1;
+      else if (!strcmp (args[i], "-h"))
+	usage ();
+      else if (!strcmp (args[i], "-Q"))
+	{
+	  num_passes = 0;
+	}
+      else if (!strcmp (args[i], "-s"))
+	{
+	  i++;
+	  if ((i < argc) && (isinteger (args[i])))
+	    sizethres = atoi (args[i]);
+	  else
+	    error_msg (args[0], "follow the -s option with a numeric arg >=0", "");
+	}
+      else if (!strcmp (args[i], "-a"))
+	{
+	  i++;
+	  if ((i < argc) && (isinteger (args[i])))
+	    areathres = atoi (args[i]);
+	  else
+	    error_msg (args[0], "follow the -a option with a numeric arg >=0", "");
+	}
+      else if (args[i][0] == '-')
+	error_msg (args[0], "unknown switch:", args[i]);
+      else if (!libraryname)
+	libraryname = args[i];
+      else if (!prunename)
+	prunename = args[i];
+      else
+	error_msg (args[0], "too many filenames", "");
+    }
+
+  if (!libraryname)
+    error_msg (args[0], "please specify a library file", "");
+
+  if (V)
+    fprintf (stderr, "%s: processing...\n", args[0]);
+
+  overwrite = 0;
+  if (!prunename)
+    {
+      prunename = libraryname;
+      if (V)
+	fprintf (stderr, "overwriting previous library file.\n");
+      overwrite = 1;
+    }
+
+  if (overwrite)
+    {
+      tmpnam (tempn);
+    }
+  else
+    strcpy (tempn, prunename);
+
+
+  avglibsize = count = read_library (libraryname, &origlist);
+  if (V)
+    fprintf (stderr, "%d marks...", count);
+
+  avglib = (marklistptr *) malloc (count * sizeof (marklistptr));
+  if (!avglib)
+    error_msg (args[0], "out of memory", "");
+  for (i = 0; i < avglibsize; i++)
+    avglib[i] = NULL;
+
+
+  prune_on_size (&origlist, sizethres);
+
+  prune_on_area (&origlist, areathres);
+  if (V)
+    fprintf (stderr, "after threshold pruning, %d marks\n", count = marklist_length (origlist));
+
+
+  if (V)
+    fprintf (stderr, "starting greedy library creation...\n");
+
+  greedy_add (origlist, &librarylist);
+
+
+  for (pass = 0; pass < num_passes; pass++)
+    {
+      marklist_free (&librarylist);
+      if (V)
+	fprintf (stderr, "averaging...\n");
+      librarylist = average_library ();
+      averagedout_addagain (origlist, &librarylist);
+      greedy_prune (&librarylist);
+      if (V)
+	fprintf (stderr, "after pass %d greedy prune %d marks\n", 1 + pass, marklist_length (librarylist));
+    }
+
+
+  lib = fopen (tempn, "wb");
+  if (lib == NULL)
+    error_msg (args[0], "trouble creating prune-library file.", "");
+
+
+  if (V)
+    fprintf (stderr, "writing to file: %s...", prunename);
+  for (step = librarylist, count = 0; step; step = step->next, count++)
+    {
+      step->data.symnum = count;
+      write_library_mark (lib, step->data);
+    }
+
+  if (V)
+    fprintf (stderr, "%d marks.\n", count);
+  fclose (lib);
+
+  if (overwrite)
+    {
+      sprintf (sysstr, "mv %s %s", tempn, prunename);
+      system (sysstr);		/* move temp to proper name */
+    }
+
+  for (i = 0; i < avglibsize; i++)
+    {
+      marklist_free (&avglib[i]);
+      free (avglib[i]);
+    }
+}
Index: /main/tags/2.25/gsdl/packages/mg/src/images/mgticstat.1
===================================================================
--- /main/tags/2.25/gsdl/packages/mg/src/images/mgticstat.1	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/mg/src/images/mgticstat.1	(revision 21064)
@@ -0,0 +1,57 @@
+.\"------------------------------------------------------------
+.\" Id - set Rv,revision, and Dt, Date using rcs-Id tag.
+.de Id
+.ds Rv \\$3
+.ds Dt \\$4
+..
+.Id $Id$
+.\"------------------------------------------------------------
+.TH mgticstat 1 \*(Dt CITRI
+.SH NAME
+mgticstat \- displays the statistics for the library
+.SH SYNOPSIS
+.B mgticstat
+[
+.B \-h
+]
+.I libraryfile
+.SH DESCRIPTION
+.B mgticstat
+displays statistics about the
+.I libraryfile
+file.
+The output of this program contains the average mark size, average
+centroid position, and the number of marks with an area less than or
+equal to a few powers of\ 2.
+.SH OPTIONS
+Options may appear in any order.
+.TP "\w'\fIlibraryfile\fP'u+2n"
+.B \-h
+This displays a usage line on
+.IR stderr .
+.TP
+.I libraryfile
+This specifies the name of the library file.
+.SH "SEE ALSO"
+.na
+.BR mg (1),
+.BR mg_compression_dict (1),
+.BR mg_fast_comp_dict (1),
+.BR mg_get (1),
+.BR mg_invf_dict (1),
+.BR mg_invf_dump (1),
+.BR mg_invf_rebuild (1),
+.BR mg_passes (1),
+.BR mg_perf_hash_build (1),
+.BR mg_text_estimate (1),
+.BR mg_weights_build (1),
+.BR mgbilevel (1),
+.BR mgbuild (1),
+.BR mgdictlist (1),
+.BR mgfelics (1),
+.BR mgquery (1),
+.BR mgstat (1),
+.BR mgtic (1),
+.BR mgticbuild (1),
+.BR mgticdump (1),
+.BR mgticprune (1).
Index: /main/tags/2.25/gsdl/packages/mg/src/images/mgticstat.c
===================================================================
--- /main/tags/2.25/gsdl/packages/mg/src/images/mgticstat.c	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/mg/src/images/mgticstat.c	(revision 21064)
@@ -0,0 +1,130 @@
+/**************************************************************************
+ *
+ * mgticstat.c -- Program to print out stats about a textual image library
+ * Copyright (C) 1994  Stuart Inglis
+ *
+ * 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.
+ *
+ * $Id$
+ *
+ **************************************************************************/
+
+#include "sysfuncs.h"
+
+#include "marklist.h"
+#include "pbmtools.h"
+#include "extractor.h"
+#include "utils.h"
+
+void 
+usage ()
+{
+  fprintf (stderr, "usage:\n"
+	   "\tmgticstat   libraryfile\n");
+  exit (1);
+}
+
+void 
+main (int argc, char *args[])
+{
+  FILE *lib, *outf = (stdout);
+  int count;
+  int small1, small2, small4, small9, small16, small25, small36, small49,
+    small64, small81, small100;
+  marktype d;
+  int avx, avy;
+  int hhh, www, i;
+  int avruns_h = 0, avruns_v = 0;
+  int av_area = 0;
+  char *libraryname = NULL;
+
+
+  if (argc < 2)
+    usage ();
+
+  for (i = 1; i < argc; i++)
+    {
+      if (!strcmp (args[i], "-v"))
+	V = 1;
+      else if (!strcmp (args[i], "-h"))
+	usage ();
+      else if (args[i][0] == '-')
+	error_msg (args[0], "unknown switch:", args[i]);
+      else if (!libraryname)
+	libraryname = args[i];
+      else
+	error_msg (args[0], "too many filenames", "");
+    }
+
+  if (!libraryname)
+    error_msg (args[0], "please specify a library file", "");
+
+
+  lib = fopen (libraryname, "r");
+  if (lib == NULL)
+    error_msg (args[0], "Trouble opening library file", "");
+
+  count = 0;
+  small1 = small2 = small4 = small9 = small16 = small25 = small36 = small49 = small64 = small81 = small100 = 0;
+  avx = avy = 0;
+  www = hhh = 0;
+  while (!isEOF (lib))
+    {
+      if (!read_library_mark (lib, &d))
+	error_msg (args[0], "error in library file", "");
+
+      av_area += d.set;
+      if (d.set <= 1)
+	small1++;
+      if (d.set <= 2)
+	small2++;
+      if (d.set <= 4)
+	small4++;
+      if (d.set <= 9)
+	small9++;
+      if (d.set <= 16)
+	small16++;
+      if (d.set <= 25)
+	small25++;
+      if (d.set <= 36)
+	small36++;
+      if (d.set <= 49)
+	small49++;
+      if (d.set <= 64)
+	small64++;
+      if (d.set <= 81)
+	small81++;
+      if (d.set <= 100)
+	small100++;
+      avx += d.xcen;
+      avy += d.ycen;
+      www += d.w;
+      hhh += d.h;
+      avruns_h += d.h_runs;
+      avruns_v += d.v_runs;
+      pbm_freearray (&d.bitmap, d.h);
+      count++;
+      if (count % 5000 == 0)
+	fprintf (outf, "%dk ", count / 1000);
+    }
+  fprintf (outf, "number of marks=%d\n", count);
+  fprintf (outf, "average area=%d\n", av_area / count);
+  fprintf (outf, "area <=1:%d, <=2:%d, <=4:%d, <=9:%d, <=16:%d, <=25:%d, <=36:%d, <=49:%d, <=64:%d, <=81:%d, <=100:%d\n", small1, small2, small4, small9, small16, small25, small36, small49, small64, small81, small100);
+
+  fprintf (outf, "average num runs, horizontal=%d, vertical=%d\n", avruns_h / count, avruns_v / count);
+  fprintf (outf, "average centroid position=(%d,%d)\n", avx / count, avy / count);
+  fprintf (outf, "average width=%d, average height=%d\n", www / count, hhh / count);
+  fclose (lib);
+}
Index: /main/tags/2.25/gsdl/packages/mg/src/images/model.h
===================================================================
--- /main/tags/2.25/gsdl/packages/mg/src/images/model.h	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/mg/src/images/model.h	(revision 21064)
@@ -0,0 +1,92 @@
+/**************************************************************************
+ *
+ * model.h -- Part pf PPM data compression
+ * Copyright (C) 1987  Alistair Moffat
+ *
+ * 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.
+ *
+ * $Id$
+ *
+ **************************************************************************/
+
+#define defaultkbytes	896
+#define minkbytes	56
+#define maxkbytes	((65536/1024)*sizeof(eventnode))
+
+#ifndef increment
+#define	increment	8
+#endif
+#ifndef halveat
+#define halveat		64
+#endif
+#define maxtotalcnt 	(increment*halveat)
+
+typedef int boolean;
+#define false           0
+#define true            1
+
+typedef short event;
+typedef unsigned short point;
+
+typedef struct
+  {
+    short totalcnt;
+    short notfound;
+    point list;			/* list storing the event records */
+  }
+eventset;
+
+typedef struct
+  {
+    event eventnum;
+    short count;
+    point next, prev;
+    eventset foll;
+  }
+eventnode, *eventptr;
+
+#define memsize		(kbytes*1024)
+#define maxnodes	(memsize/sizeof(eventnode))
+/* #define charsetsize     256 -- MAHE */
+#define nchars          (charsetsize+1)
+
+extern int charsetsize;		/* -- MAHE */
+
+extern eventptr E;
+extern long kbytes;
+extern point numnodes, nfreenodes;
+extern boolean excluded[];	/* -- MAHE */
+
+#define ENULL		(E)
+
+typedef unsigned u;
+#define p32(p)	(E+p)
+#define p16(p)	(p-E)
+
+/* in ppm.c */
+void write_model ();
+void encodestring ();
+void decodestring ();
+void encodefile ();
+void decodefile ();
+
+/* in lstevent.c */
+void write_method ();
+eventnode *encode_event_noex ();
+eventnode *decode_event_noex ();
+eventnode *encode_event ();
+eventnode *decode_event ();
+/* eventnode *addevent(); */
+eventnode *newnode ();
Index: /main/tags/2.25/gsdl/packages/mg/src/images/pbmtools.c
===================================================================
--- /main/tags/2.25/gsdl/packages/mg/src/images/pbmtools.c	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/mg/src/images/pbmtools.c	(revision 21064)
@@ -0,0 +1,288 @@
+/**************************************************************************
+ *
+ * pbmtools.c -- Routines for dealing with portable bitmap files (PBM)
+ * Copyright (C) 1994  Stuart Inglis
+ *
+ * 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.
+ *
+ * $Id$
+ *
+ **************************************************************************/
+
+#include "sysfuncs.h"
+
+#include "marklist.h"
+#include "pbmtools.h"
+#include "extractor.h"
+#include "utils.h"
+
+
+
+void 
+pbm_putpixel_range (Pixel ** bitmap, int c, int r, int val, int cols, int rows)
+{
+  if (((c) >= 0) && ((c) < cols) && ((r) >= 0) && ((r) < rows))
+    pbm_putpixel (bitmap, c, r, val);
+  else
+    fprintf (stderr, "putpitxel (%d %d) outside (%d %d)\n", c, r, cols, rows);
+}
+
+int 
+pbm_getpixel_range (Pixel ** bitmap, int c, int r, int cols, int rows)
+{
+  if (((c) >= 0) && ((c) < cols) && ((r) >= 0) && ((r) < rows))
+    return pbm_getpixel (bitmap, c, r);
+  else
+    {
+      fprintf (stderr, "getpixel (%d %d) outside (%d %d)\n", c, r, cols, rows);
+      return 0;
+    }
+}
+
+
+
+
+
+/*
+   Returns 1 if *fp points to a PBM (magic is P1 or P4) file.
+   leaves the fp in it's original position.
+   usage: if(pbm_isapbmfile(fp)) process(fp);
+ */
+int 
+pbm_isapbmfile (FILE * fp)
+{
+  u_long magic;
+
+  magic = getmagicno_short (fp);
+  if ((magic == MAGIC_P4) || (magic == MAGIC_P1))
+    return 1;
+  else
+    return 0;
+}
+
+
+/*
+   Frees the memory used in the bitmap structure.
+   usage: pbm_freearray(&bitmap);
+   Sets bitmap to be NULL on return.
+ */
+void 
+pbm_freearray (Pixel *** bitmap, int rows)
+{
+  int r;
+  if (rows == 0)
+    rows++;
+  for (r = 0; r < rows; r++)
+    free ((*bitmap)[r]);
+  free (*bitmap);
+  (*bitmap) = NULL;
+}
+
+
+/*
+   This function allocates the bitmap.
+   usage: bitmap=pbm_allocarray(cols,rows);
+ */
+Pixel **
+pbm_allocarray (int cols, int rows)
+{
+  Pixel **p;
+  int i, newc = (cols + PBITS) / PBITS;
+
+  if (cols == 0)
+    cols++;
+  if (rows == 0)
+    rows++;
+  p = (Pixel **) malloc (rows * sizeof (Pixel *));
+  if (p == NULL)
+    error_msg ("pbm_allocarray", "out of memory", "");
+  for (i = 0; i < rows; i++)
+    {
+      p[i] = (Pixel *) calloc (newc, sizeof (Pixel));
+      if (p[i] == NULL)
+	error_msg ("pbm_allocarray", "out of memory", "");
+    }
+  return p;
+}
+
+
+
+Pixel **
+pbm_copy (Pixel ** bitmap, int cols, int rows)
+{
+  Pixel **p;
+  int newc = (cols + PBITS) / PBITS;
+  int x, y;
+
+  p = pbm_allocarray (cols, rows);
+  for (x = 0; x < newc; x++)
+    for (y = 0; y < rows; y++)
+      p[y][x] = bitmap[y][x];
+  return p;
+}
+
+
+
+
+/*
+   Reads in a pbm file and returns a pointer to the allocated bitmap, 
+   in the P4 format.
+   Assumes fp was opened and keeps it that way.
+   usage: bitmap=pbm_readfile(fp,&cols,&rows);
+ */
+Pixel **
+pbm_readfile (FILE * fp, int *cols, int *rows)
+{
+  Pixel **p = NULL;
+  char s[100];
+  unsigned char *buf;
+  int r, c, ii = 0;
+  int p1 = 0;
+  int arg;
+
+
+  do
+    {
+      readline (s, fp);
+    }
+  while (s[0] == '#');
+
+  if (strcmp (s, "P1") == 0)
+    p1 = 1;
+  else if (strcmp (s, "P4") == 0)
+    p1 = 0;
+  else
+    error_msg ("pbm_readfile", "only pbm files are supported", "");
+
+  do
+    {
+      readline (s, fp);
+    }
+  while (s[0] == '#');
+
+  arg = sscanf (s, "%d %d", cols, rows);
+  if (arg == 1)
+    {
+      readline (s, fp);
+      arg = sscanf (s, "%d", rows);
+      if (arg != 1)
+	error_msg ("pbm_readfile", "bizzare pbm format", "");
+    }
+  p = pbm_allocarray (*cols, *rows);
+  buf = (unsigned char *) malloc ((*cols + 2) * sizeof (unsigned char));
+  if (!buf)
+    error_msg ("pbm_readfile", "out of memory", "");
+
+  if (p1)
+    {
+      for (r = 0; r < *rows; r++)
+	for (c = 0; c < *cols; c++)
+	  {
+	    fscanf (fp, "%d", &ii);
+	    pbm_putpixel (p, c, r, ii);
+	  }
+    }
+  else
+    {
+      for (r = 0; r < *rows; r++)
+	{
+	  c = 0;
+	  fread (buf, 1, (*cols + 7) / 8, fp);
+	  for (c = 0; c < *cols; c++)
+	    {
+	      if (!(c % 8))
+		ii = buf[c / 8];
+	      if (ii < 0)
+		error_msg ("pbm_readfile", "file reading error", "");
+	      pbm_putpixel (p, c, r, (ii & 128) ? 1 : 0);
+	      ii <<= 1;
+	    }
+	}
+    }				/* p4 type */
+  free (buf);
+  return p;
+}
+
+
+/*
+   Writes a pbm file given a file pointer and bitmap. Assumes that
+   fp is already open, and keeps in that way.
+   usage: pbm_writefile(fp,bitmap,cols,rows);
+ */
+void 
+pbm_writefile (FILE * fp, Pixel ** bitmap, int cols, int rows)
+{
+  int r, c, ii = 0, j;
+  unsigned char *buf;
+
+  buf = (unsigned char *) malloc (((cols + 14) / 8) * sizeof (unsigned char));
+
+  fprintf (fp, "%s\n", "P4");
+  fprintf (fp, "%d %d\n", cols, rows);
+
+  for (r = 0; r < rows; r++)
+    {
+      for (c = 0; c < cols; c += 8)
+	{
+	  ii = 0;
+	  for (j = 0; j < 8; j++)
+	    if (c + j < cols)
+	      {
+		if (pbm_getpixel (bitmap, c + j, r))
+		  ii |= (128 >> j);
+	      }
+	  buf[c / 8] = ii;
+	}
+      fwrite (buf, 1, (cols + 7) / 8, fp);
+    }
+  free (buf);
+/*      putc('\n',fp);   if this line is included programs don't say things like 'short image' &c, but then again,
+   in most cases a 'cmp' between the original will fail because of the last byte...sigh, "standards". */
+}
+
+#define BUF_SIZE 131072
+char buffer[BUF_SIZE];
+
+void 
+pbm_writenamedfile (char fn[], Pixel ** bitmap, int cols, int rows)
+{
+  FILE *tempfp;
+
+  tempfp = fopen (fn, "wb");
+  if (tempfp == NULL)
+    error_msg ("pbm_writenamedfile", "can't open file:", fn);
+  setbuffer (tempfp, buffer, BUF_SIZE);
+  pbm_writefile (tempfp, bitmap, cols, rows);
+  fclose (tempfp);
+}
+
+
+
+Pixel **
+pbm_readnamedfile (char fn[], int *cols, int *rows)
+{
+  FILE *tempfp;
+  Pixel **temp;
+
+  tempfp = fopen (fn, "rb");
+  if (tempfp == NULL)
+    return NULL;
+  setbuffer (tempfp, buffer, BUF_SIZE);
+
+  temp = pbm_readfile (tempfp, cols, rows);
+
+  fclose (tempfp);
+  return temp;
+}
Index: /main/tags/2.25/gsdl/packages/mg/src/images/pbmtools.h
===================================================================
--- /main/tags/2.25/gsdl/packages/mg/src/images/pbmtools.h	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/mg/src/images/pbmtools.h	(revision 21064)
@@ -0,0 +1,86 @@
+/**************************************************************************
+ *
+ * pbmtools.h -- Routines for dealing with portable bitmap files (PBM)
+ * Copyright (C) 1994  Stuart Inglis
+ *
+ * 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.
+ *
+ * $Id$
+ *
+ **************************************************************************/
+
+#ifndef __PBMTOOLS_H
+#define __PBMTOOLS_H
+
+#include "sysfuncs.h"
+#include "basictypes.h"
+
+#include "utils.h"
+#include "marklist.h"
+
+#define PBITS 32
+#define PSH 5
+
+
+/* The next two are ordered pixels col0=left, cols31=right */
+
+/*
+   #define pbm_getpixel(bitmap,c,r)  \
+   ((bitmap[r][(c)>>PSH] >> ((PBITS-1)-((c)&(PBITS-1))))&1)
+   #define pbm_putpixel(bitmap,c,r,val) \
+   if((val))  \
+   bitmap[r][(c)>>PSH] |=  (((unsigned)1<<(PBITS-1)) >> ((c)&(PBITS-1))); \
+   else \
+   bitmap[r][(c)>>PSH] &= ~(((unsigned)1<<(PBITS-1)) >> ((c)&(PBITS-1))) 
+ */
+
+
+
+
+/* The next two defines are ordered pixel cols0=right, cols31=left */
+
+#define pbm_getpixel(bitmap,c,r)                            \
+         ((bitmap[r][(c)>>PSH] >> ((c)&(PBITS-1)))&1)
+#define pbm_putpixel(bitmap,c,r,val)                        \
+         if((val))                                          \
+              bitmap[r][(c)>>PSH] |= (1<<((c)&(PBITS-1)));  \
+         else                                               \
+              bitmap[r][(c)>>PSH] &= ~(1<<((c)&(PBITS-1)))
+
+
+#define pbm_putpixel_trunc(bitmap,c,r,val,cols,rows) \
+       if(((c)>=0)&&((c)<cols)&&((r)>=0)&&((r)<rows)) \
+             pbm_putpixel(bitmap,c,r,val)
+
+#define pbm_getpixel_trunc(bitmap,c,r,cols,rows)       \
+       ((((c)>=0)&&((c)<cols)&&((r)>=0)&&((r)<rows)) ?  \
+             pbm_getpixel(bitmap,c,r) : 0)
+
+
+
+
+int pbm_isapbmfile (FILE * fp);
+void pbm_freearray (Pixel *** bitmap, int rows);
+Pixel **pbm_copy (Pixel ** bitmap, int cols, int rows);
+Pixel **pbm_allocarray (int cols, int rows);
+Pixel **pbm_readfile (FILE * fp, int *cols, int *rows);
+Pixel **pbm_readnamedfile (char fn[], int *cols, int *rows);
+void pbm_writefile (FILE * fp, Pixel ** bitmap, int cols, int rows);
+void pbm_writenamedfile (char fn[], Pixel ** bitmap, int cols, int rows);
+
+void pbm_putpixel_range (Pixel ** bitmap, int c, int r, int val, int cols, int rows);
+int pbm_getpixel_range (Pixel ** bitmap, int c, int r, int cols, int rows);
+
+#endif
Index: /main/tags/2.25/gsdl/packages/mg/src/images/ppm.c
===================================================================
--- /main/tags/2.25/gsdl/packages/mg/src/images/ppm.c	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/mg/src/images/ppm.c	(revision 21064)
@@ -0,0 +1,585 @@
+/**************************************************************************
+ *
+ * ppm.c -- PPM data compression
+ * Copyright (C) 1987  Alistair Moffat
+ *
+ * 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.
+ *
+ * $Id$
+ *
+ **************************************************************************/
+
+#include "sysfuncs.h"
+
+#include "arithcode.h"
+#include "model.h"
+
+
+
+/*
+   $Log$
+   Revision 1.1  1999/08/10 21:17:33  sjboddie
+   renamed mg-1.3d directory mg
+
+   Revision 1.1  1998/11/17 09:33:55  rjmcnab
+   *** empty log message ***
+
+   * Revision 1.2  1994/09/20  04:42:02  tes
+   * For version 1.1
+   *
+ */
+
+static char *RCSID = "$Id$";
+
+/* FIXEDORDER sets the maximum context length that will be used.
+   Making FIXEDORDER large increases the compression if there is enough
+   space to store the model, but when space limit is reached increasing
+   FIXEDORDER will decrease compression because of model thrashing.
+   Third order (FIXEDORDER=3) is suitable for a few hundred Kb of model
+   space, FIXEDORDER=1 is suitable for a few tens of kB.
+   This version requires that FIXEDORDER be a preprocessor rather
+   than runtime variable to allow loops to be unrolled and make for faster
+   execution. Maximum in this implementation is 3 */
+
+#ifndef FIXEDORDER
+#define FIXEDORDER	3
+#endif
+
+/* global variables */
+eventptr E = NULL;		/* array of eventnodes */
+point numnodes = 0, nfreenodes = 0;
+long kbytes = defaultkbytes;
+/*boolean               excluded[nchars]={false};  - MAHE */
+boolean excluded[16384] =
+{false};			/* excluded characters */
+
+/* local variables */
+#define defaultchunksize        4096	/* compression chunks */
+
+#define EOSchar         (charsetsize)
+
+unsigned chunksize = defaultchunksize;
+eventptr s[FIXEDORDER + 1] =
+{NULL},				/* current contexts */
+  t[FIXEDORDER + 1] =
+{NULL};				/* new contexts */
+
+#if (FIXEDORDER==3)
+#define SHIFT_ST	s[1] = t[0]; s[2] = t[1] ; s[3] = t[2]
+#else
+#if (FIXEDORDER==2)
+#define SHIFT_ST	s[1] = t[0]; s[2] = t[1]
+#else
+#if (FIXEDORDER==1)
+#define SHIFT_ST	s[1] = t[0]
+#else
+#define SHIFT_ST
+#endif
+#endif
+#endif
+
+/* follow a character list and set the exclusions */
+#define SET_EX(p)				\
+do						\
+{	register eventptr q;			\
+	q = p32((p32(p))->next);		\
+	for (; q!=ENULL; q=p32(q->next))	\
+		excluded[q->eventnum] = true;	\
+}						\
+while (false)
+
+/* clear the exclusions */
+#define CLEAR_EX(p)				\
+do						\
+{	register eventptr q;			\
+	q = p32((p32(p))->next);		\
+	for (; q!=ENULL; q=p32(q->next))	\
+		excluded[q->eventnum] = false;	\
+}						\
+while (false)
+
+/*==================================*/
+
+void
+write_model ()
+{
+  fprintf (stderr, "ppm");
+  write_method ();
+#ifdef NOEXCLUSIONS
+  fprintf (stderr, "nx");
+#endif
+  fprintf (stderr, "-o%1d", FIXEDORDER);
+  fprintf (stderr, "-k%ld", kbytes);
+}
+
+/*==================================*/
+
+void
+encode_in_order (n, e)
+     int n;
+     event e;
+/* encode character e in order n */
+{
+  boolean encoded;
+  int i, c;
+  t[n] = encode_event_noex (&s[n]->foll, e, &encoded);
+  if (encoded)
+    c = n;
+  else
+    for (c = n - 1; c >= 0; c--)
+      {
+#ifdef NOEXCLUSIONS
+	t[c] = encode_event_noex (&s[c]->foll, e, &encoded);
+#else
+	SET_EX (s[c + 1]->foll.list);
+	t[c] = encode_event (&s[c]->foll, e, &encoded);
+#endif
+	if (encoded)
+	  break;
+      }
+  if (!encoded)
+    arithmetic_encode (e, e + 1, nchars);
+  for (i = c + 1; i <= n; i++)
+    if (i > 0)
+      t[i]->prev = p16 (t[i - 1]);
+    else
+      t[0]->prev = p16 (s[0]);
+  for (i = c - 1; i >= 0; i--)
+    t[i] = p32 (t[i + 1]->prev);
+#ifndef NOEXCLUSIONS
+  if (c != n)
+    CLEAR_EX (s[c + 1]->foll.list);
+#endif
+  SHIFT_ST;
+}
+
+/*==================================*/
+
+/* not required in this version */
+
+#if 0
+
+void
+decode_in_order (n, e)
+     int n;
+     event *e;
+{
+  boolean decoded;
+  int i, c;
+  t[n] = decode_event_noex (&s[n]->foll, &decoded, e);
+  if (decoded)
+    c = n;
+  else
+    for (c = n - 1; c >= 0; c--)
+      {
+#ifdef NOEXCLUSIONS
+	t[c] = decode_event_noex (&s[c]->foll, &decoded, e);
+#else
+	SET_EX (s[c + 1]->foll.list);
+	t[c] = decode_event (&s[c]->foll, &decoded, e);
+#endif
+	if (decoded)
+	  break;
+      }
+  if (!decoded)
+    {
+      *e = arithmetic_decode_target (nchars);
+      arithmetic_decode (*e, *e + 1, nchars);
+    }
+  for (i = c + 1; i <= n; i++)
+    {
+      t[i]->eventnum = *e;
+      if (i > 0)
+	t[i]->prev = p16 (t[i - 1]);
+      else
+	t[0]->prev = p16 (s[0]);
+    }
+  {
+    register int i;
+    for (i = c - 1; i >= 0; i--)
+      t[i] = p32 (t[i + 1]->prev);
+  }
+#ifndef NOEXCLUSIONS
+  if (c != n)
+    CLEAR_EX (s[c + 1]->foll.list);
+#endif
+  SHIFT_ST;
+}
+
+#endif
+
+/*==================================*/
+
+void
+start_model ()
+{
+  int i;
+  /* is this the first call? */
+  if (E == NULL)
+    E = (eventptr) malloc ((unsigned) kbytes * 1024);
+  /* start off with no information */
+  numnodes = 0;
+  nfreenodes = maxnodes;
+  for (i = 0; i <= FIXEDORDER; i++)
+    {
+      s[i] = newnode (NULL);
+      if (i > 0)
+	s[i]->prev = p16 (s[i - 1]);
+    }
+}
+
+/*==================================*/
+
+void
+encodestring (str, n)
+     unsigned short *str;
+     int n;
+/* encode all n characters of the supplied string str */
+{
+  event e;
+  boolean encoded;
+  register eventptr S, T;
+  int i;
+#ifndef NOEXCLUSIONS
+  register eventptr Sex;
+#endif
+
+  if (E == NULL)
+    start_model ();
+  /* set the initial context node */
+  S = s[FIXEDORDER];
+
+  for (i = 0; i < n; i++)
+    {
+      /* encode one character */
+      e = *str++;
+      /* this next monstrosity is logically equivalent to 
+         encode_in_order(FIXEDORDER,e)
+         the loop has been unrolled to make it all go faster */
+      for (;;)
+	{
+	  T = encode_event_noex (&S->foll, e, &encoded);
+	  if (encoded)
+	    break;
+	  t[FIXEDORDER] = T;
+
+#ifdef NOEXCLUSIONS
+#if (FIXEDORDER>2)
+	  S = p32 (S->prev);
+	  t[2] = encode_event_noex (&S->foll, e, &encoded);
+	  t[3]->prev = p16 (t[2]);
+	  if (encoded)
+	    break;
+#endif
+
+#if (FIXEDORDER>1)
+	  S = p32 (S->prev);
+	  t[1] = encode_event_noex (&S->foll, e, &encoded);
+	  t[2]->prev = p16 (t[1]);
+	  if (encoded)
+	    break;
+#endif
+
+#if (FIXEDORDER>0)
+	  S = p32 (S->prev);
+	  t[0] = encode_event_noex (&S->foll, e, &encoded);
+	  t[1]->prev = p16 (t[0]);
+	  if (encoded)
+	    break;
+#endif
+#else
+#if (FIXEDORDER>2)
+	  Sex = S;
+	  SET_EX (Sex->foll.list);
+	  S = p32 (S->prev);
+	  t[2] = encode_event (&S->foll, e, &encoded);
+	  t[3]->prev = p16 (t[2]);
+	  if (encoded)
+	    {
+	      CLEAR_EX (Sex->foll.list);
+	      break;
+	    }
+#endif
+
+#if (FIXEDORDER>1)
+	  Sex = S;
+	  SET_EX (Sex->foll.list);
+	  S = p32 (S->prev);
+	  t[1] = encode_event (&S->foll, e, &encoded);
+	  t[2]->prev = p16 (t[1]);
+	  if (encoded)
+	    {
+	      CLEAR_EX (Sex->foll.list);
+	      break;
+	    }
+#endif
+
+#if (FIXEDORDER>0)
+	  Sex = S;
+	  SET_EX (Sex->foll.list);
+	  S = p32 (S->prev);
+	  t[0] = encode_event (&S->foll, e, &encoded);
+	  t[1]->prev = p16 (t[0]);
+	  if (encoded)
+	    {
+	      CLEAR_EX (Sex->foll.list);
+	      break;
+	    }
+	  CLEAR_EX (Sex->foll.list);
+#endif
+#endif
+
+	  arithmetic_encode (e, e + 1, nchars);
+	  t[0]->prev = p16 (s[0]);
+	  break;
+	}
+      /* phew! Update the current context to the latest node */
+      S = p32 (T->prev);
+
+      /* is there a danger of running out of space? */
+      if (nfreenodes <= FIXEDORDER)
+	{
+	  start_model ();
+	  S = s[FIXEDORDER];
+	}
+    }
+
+  /* save the current contexts for the various order submodels */
+  s[FIXEDORDER] = S;
+  for (i = FIXEDORDER; i > 0; i--)
+    s[i - 1] = p32 (s[i]->prev);
+  /* and send the terminator character */
+  encode_in_order (FIXEDORDER, EOSchar);
+  /* and check the space again */
+  if (nfreenodes <= FIXEDORDER)
+    start_model ();
+}
+
+/*==================================*/
+
+void
+decodestring (str, n)
+     unsigned short *str;
+     int *n;
+{
+  event e;
+  boolean decoded;
+  register eventptr S, T;
+#ifndef NOEXCLUSIONS
+  register eventptr Sex;
+#endif
+
+  /* just mimic the corresponding encoding actions */
+  if (E == NULL)
+    start_model ();
+  S = s[FIXEDORDER];
+
+  *n = 0;
+  for (;;)
+    {				/* logically equivalent to "decode_in_order(FIXEDORDER,&e)" */
+
+      for (;;)
+	{
+	  T = decode_event_noex (&S->foll, &decoded, &e);
+	  if (decoded)
+	    break;
+	  t[FIXEDORDER] = T;
+
+#ifdef NOEXCLUSIONS
+#if (FIXEDORDER>2)
+	  S = p32 (S->prev);
+	  t[2] = decode_event_noex (&S->foll, &decoded, &e);
+	  t[3]->prev = p16 (t[2]);
+	  if (decoded)
+	    {
+	      t[3]->eventnum = e;
+	      break;
+	    }
+#endif
+
+#if (FIXEDORDER>1)
+	  S = p32 (S->prev);
+	  t[1] = decode_event_noex (&S->foll, &decoded, &e);
+	  t[2]->prev = p16 (t[1]);
+	  if (decoded)
+	    {
+#if (FIXEDORDER>2)
+	      t[3]->eventnum =
+#endif
+		t[2]->eventnum = e;
+	      break;
+	    }
+#endif
+
+#if (FIXEDORDER>0)
+	  S = p32 (S->prev);
+	  t[0] = decode_event_noex (&S->foll, &decoded, &e);
+	  t[1]->prev = p16 (t[0]);
+	  if (decoded)
+	    {
+#if (FIXEDORDER>2)
+	      t[3]->eventnum =
+#endif
+#if (FIXEDORDER>1)
+		t[2]->eventnum =
+#endif
+		t[1]->eventnum = e;
+	      break;
+	    }
+#endif
+#else
+#if (FIXEDORDER>2)
+	  Sex = S;
+	  SET_EX (Sex->foll.list);
+	  S = p32 (S->prev);
+	  t[2] = decode_event (&S->foll, &decoded, &e);
+	  t[3]->prev = p16 (t[2]);
+	  if (decoded)
+	    {
+	      t[3]->eventnum = e;
+	      CLEAR_EX (Sex->foll.list);
+	      break;
+	    }
+#endif
+
+#if (FIXEDORDER>1)
+	  Sex = S;
+	  SET_EX (Sex->foll.list);
+	  S = p32 (S->prev);
+	  t[1] = decode_event (&S->foll, &decoded, &e);
+	  t[2]->prev = p16 (t[1]);
+	  if (decoded)
+	    {
+#if (FIXEDORDER>2)
+	      t[3]->eventnum =
+#endif
+		t[2]->eventnum = e;
+	      CLEAR_EX (Sex->foll.list);
+	      break;
+	    }
+#endif
+
+#if (FIXEDORDER>0)
+	  Sex = S;
+	  SET_EX (Sex->foll.list);
+	  S = p32 (S->prev);
+	  t[0] = decode_event (&S->foll, &decoded, &e);
+	  t[1]->prev = p16 (t[0]);
+	  if (decoded)
+	    {
+#if (FIXEDORDER>2)
+	      t[3]->eventnum =
+#endif
+#if (FIXEDORDER>1)
+		t[2]->eventnum =
+#endif
+		t[1]->eventnum = e;
+	      CLEAR_EX (Sex->foll.list);
+	      break;
+	    }
+	  CLEAR_EX (Sex->foll.list);
+#endif
+#endif
+
+	  e = arithmetic_decode_target (nchars);
+	  arithmetic_decode (e, e + 1, nchars);
+#if (FIXEDORDER>2)
+	  t[3]->eventnum =
+#endif
+#if (FIXEDORDER>1)
+	    t[2]->eventnum =
+#endif
+#if (FIXEDORDER>0)
+	    t[1]->eventnum =
+#endif
+	    t[0]->eventnum = e;
+	  t[0]->prev = p16 (s[0]);
+	  break;
+	}
+      S = p32 (T->prev);
+
+      /* check the space requirements */
+      if (nfreenodes <= FIXEDORDER)
+	{
+	  start_model ();
+	  S = s[FIXEDORDER];
+	}
+      /* are we done?  or do we save the char */
+      if (e == EOSchar)
+	break;
+      *str++ = e;
+      (*n)++;
+    }
+  s[FIXEDORDER] = S;
+}
+
+
+#if 0				/* Writing my own version of this - MAHE */
+void
+encodefile ()
+/* encodes a file by breaking into a sequence of fixed length chunks */
+{
+  unsigned char *str;
+  int c, n = 0;
+
+  str = (unsigned char *) malloc ((unsigned) chunksize);
+  startoutputingbits ();
+  startencoding ();
+
+  /* to encode the file, break it into chunks and encode the
+     chunks one by one */
+  while ((c = getchar ()) != EOF)
+    {
+      str[n++] = c;
+      if (n == chunksize)
+	{
+	  encodestring (str, n);
+	  rawbytes += n;
+	  n = 0;
+	}
+    }
+  /* send final partial chunk */
+  if (n > 0)
+    {
+      encodestring (str, n);
+      rawbytes += n;
+    }
+  /* send EOF as an empty string */
+  encodestring (str, 0);
+  doneencoding ();
+  doneoutputingbits ();
+}
+
+void
+decodefile ()
+{
+  unsigned char *str;
+  int n, i;
+
+  str = (unsigned char *) malloc ((unsigned) chunksize);
+  startinputingbits ();
+  startdecoding ();
+  for (;;)
+    {
+      decodestring (str, &n);
+      if (n == 0)
+	break;
+      for (i = 0; i < n; i++)
+	putchar ((int) str[i]);
+      rawbytes += n;
+    }
+}
+
+#endif /* #if 0 */
Index: /main/tags/2.25/gsdl/packages/mg/src/images/sortmarks.c
===================================================================
--- /main/tags/2.25/gsdl/packages/mg/src/images/sortmarks.c	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/mg/src/images/sortmarks.c	(revision 21064)
@@ -0,0 +1,93 @@
+/**************************************************************************
+ *
+ * sortmarks.c -- Functions which sort the marks into a "readable sequence"
+ * Copyright (C) 1994  Stuart Inglis
+ *
+ * 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.
+ *
+ * $Id$
+ *
+ **************************************************************************/
+
+#include "sysfuncs.h"
+
+#include "marklist.h"
+#include "sortmarks.h"
+
+#define GAP 4
+
+
+
+static int 
+CmpOnY (const void *e1, const void *e2)
+{
+  return (((marktype *) e1)->ycen * 0 + ((marktype *) e1)->ypos) -
+    (((marktype *) e2)->ycen * 0 + ((marktype *) e2)->ypos);
+}
+
+static int 
+CmpOnX (const void *e1, const void *e2)
+{
+  return (((marktype *) e1)->xcen * 0 + ((marktype *) e1)->xpos) -
+    (((marktype *) e2)->xcen * 0 + ((marktype *) e2)->xpos);
+}
+
+
+
+
+
+
+
+
+marklistptr 
+sortmarks (marklistptr listofmarks)
+{
+  marktype *table;
+  int count = 0;
+  int i, s, e;
+
+
+  table = calloc ((unsigned int) marklist_length (listofmarks), sizeof (marklisttype));
+
+  while (listofmarks)
+    {
+      table[count] = listofmarks->data;
+      marklist_removeat (&listofmarks, 0);
+      count++;
+    }
+
+  /* sort first on the y position of their centroids */
+  qsort ((void *) table, (unsigned int) (count), sizeof (*table), CmpOnY);
+
+  for (s = 0; s < count;)
+    {
+      int c;
+
+      for (e = s + 1, c = 0; (e < count) &&
+	   ((table[e].ypos + table[e].ycen * 0) - (table[e - 1].ypos + table[e - 1].ycen * 0) <= GAP); c++, e++);
+
+      if (e < count && c >= 1)
+	qsort (&table[s], (unsigned int) (e - s), sizeof (*table), CmpOnX);
+      s = e;
+    }
+
+  for (i = 0; i < count; i++)
+    {
+      table[i].symnum = i;
+      marklist_add (&listofmarks, table[i]);
+    }
+
+  return listofmarks;
+}
Index: /main/tags/2.25/gsdl/packages/mg/src/images/sortmarks.h
===================================================================
--- /main/tags/2.25/gsdl/packages/mg/src/images/sortmarks.h	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/mg/src/images/sortmarks.h	(revision 21064)
@@ -0,0 +1,30 @@
+/**************************************************************************
+ *
+ * sortmarks.h -- Functions which sort the marks into a "readable sequence"
+ * Copyright (C) 1994  Stuart Inglis
+ *
+ * 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.
+ *
+ * $Id$
+ *
+ **************************************************************************/
+
+
+#ifndef _SortMarks_h_
+#define _SortMarks_h_
+
+marklistptr sortmarks (marklistptr listofmarks);
+
+#endif
Index: /main/tags/2.25/gsdl/packages/mg/src/images/utils.c
===================================================================
--- /main/tags/2.25/gsdl/packages/mg/src/images/utils.c	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/mg/src/images/utils.c	(revision 21064)
@@ -0,0 +1,270 @@
+/**************************************************************************
+ *
+ * utils.c -- Functions which are common utilities for the image programs
+ * Copyright (C) 1994  Stuart Inglis
+ *
+ * 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.
+ *
+ * $Id$
+ *
+ **************************************************************************/
+
+#include "sysfuncs.h"
+
+#include "netorder.h"  /* [RPAP - Jan 97: Endian Ordering] */
+
+#include "utils.h"
+
+
+int V = 0;
+
+
+int 
+isEOF (FILE * fp)
+{
+  int ch;
+
+  ch = getc (fp);
+  ungetc (ch, fp);
+  if (ch == EOF)
+    return 1;
+  return 0;
+}
+
+
+int 
+getmagicno_short (FILE * fp)
+{
+  int ch1, ch2;
+  ch1 = getc (fp);
+  if (ch1 == EOF)
+    {
+      ungetc (ch1, fp);
+      return 0;
+    }
+  ch2 = getc (fp);
+  if (ch2 == EOF)
+    {
+      ungetc (ch2, fp);
+      return 0;
+    }
+  ungetc (ch2, fp);
+  ungetc (ch1, fp);
+
+  return ((ch1 << 8) | ch2);
+}
+
+int 
+getmagicno_short_pop (FILE * fp)
+{
+  int ch1, ch2;
+  ch1 = getc (fp);
+  if (ch1 == EOF)
+    return 0;
+  ch2 = getc (fp);
+  if (ch2 == EOF)
+    return 0;
+
+  return ((ch1 << 8) | ch2);  
+}
+
+int 
+getmagicno_byte (FILE * fp)
+{
+  int ch1;
+  ch1 = getc (fp);
+  if (ch1 == EOF)
+    {
+      ungetc (ch1, fp);
+      return 0;
+    }
+  ungetc (ch1, fp);
+  return (ch1);
+}
+
+
+int 
+getmagicno_long (FILE * fp)
+{
+  int ch1, ch2, ch3, ch4;
+  ch1 = getc (fp);
+  if (ch1 == EOF)
+    {
+      ungetc (ch1, fp);
+      return 0;
+    }
+  ch2 = getc (fp);
+  if (ch2 == EOF)
+    {
+      ungetc (ch2, fp);
+      return 0;
+    }
+  ch3 = getc (fp);
+  if (ch3 == EOF)
+    {
+      ungetc (ch3, fp);
+      return 0;
+    }
+  ch4 = getc (fp);
+  if (ch4 == EOF)
+    {
+      ungetc (ch4, fp);
+      return 0;
+    }
+  ungetc (ch4, fp);
+  ungetc (ch3, fp);
+  ungetc (ch2, fp);
+  ungetc (ch1, fp);
+
+  return ((ch1 << 24) | (ch2 << 16) | (ch3 << 8) | (ch4));
+}
+
+
+
+
+void 
+error_msg (char *prog, char *message, char *extra)
+{
+  fprintf (stderr, "%s: %s %s\n", prog, message, extra);
+  exit (1);
+}
+
+void 
+warn (char *prog, char *message, char *extra)
+{
+  fprintf (stderr, "%s: %s %s\n", prog, message, extra);
+}
+
+
+
+void 
+readline (char str[], FILE * fp)
+{
+  int i = 0, ch;
+
+  while (((ch = fgetc (fp)) != '\n') && (!feof (fp)))
+    str[i++] = ch;
+  str[i] = '\0';
+}
+
+
+
+
+
+
+
+int 
+getint (FILE * fp)
+{
+  register char ch;
+  register unsigned int i = 0;
+
+  do
+    {
+      ch = getc (fp);
+      if (feof (fp))
+	return EOF;
+    }
+  while (ch < '0' || ch > '9');
+
+  do
+    {
+      i = i * 10 + ch - '0';
+      ch = getc (fp);
+      if (feof (fp))
+	return EOF;
+    }
+  while (ch >= '0' && ch <= '9');
+
+  return i;
+}
+
+/* get_header_int i.e. get an integer from a PNM header ; basically  
+   the same as
+   above except for comment checking ; above kept because of lower  
+   overhead */
+
+unsigned int 
+gethint (FILE * fp)
+{
+  register char ch, prev = '\0';
+  register unsigned int i = 0;
+
+  do
+    {
+      ch = getc (fp);
+      if ((ch == '#') && (prev == '\n'))
+	while (((ch = getc (fp)) != '\n') && !(feof (fp)));
+      prev = ch;
+      if (feof (fp))
+	return EOF;
+    }
+  while (ch < '0' || ch > '9');
+
+  do
+    {
+      i = i * 10 + ch - '0';
+      ch = getc (fp);
+      if (feof (fp))
+	return EOF;
+    }
+  while (ch >= '0' && ch <= '9');
+
+  return i;
+}
+
+
+
+
+void 
+magic_write (FILE * fp, u_long magic_num)
+{
+  HTONUL(magic_num);  /* [RPAP - Jan 97: Endian Ordering] */
+  if (fwrite (&magic_num, sizeof (magic_num), 1, fp) != 1)
+    error_msg ("magic num", "Couldn't write magic number.", "");
+}
+
+
+void 
+magic_check (FILE * fp, u_long magic_num)
+{
+  u_long magic;
+  if (fread (&magic, sizeof (magic), 1, fp) != 1 || NTOHUL(magic) != magic_num)  /* [RPAP - Jan 97: Endian Ordering] */
+    error_msg ("magic num", "Incorrect magic number.", "");
+}
+
+
+u_long 
+magic_read (FILE * fp)
+{
+  u_long magic;
+  if (fread (&magic, sizeof (magic), 1, fp) != 1)
+    error_msg ("magic num", "Couldn't read magic number.", "");
+  return NTOHUL(magic);  /* [RPAP - Jan 97: Endian Ordering] */
+}
+
+
+
+
+int 
+isinteger (char s[])
+{
+  int i = 0;
+
+  for (i = 0; s[i] != '\0'; i++)
+    if (!isdigit (s[i]))
+      return 0;
+  return 1;
+}
Index: /main/tags/2.25/gsdl/packages/mg/src/images/utils.h
===================================================================
--- /main/tags/2.25/gsdl/packages/mg/src/images/utils.h	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/mg/src/images/utils.h	(revision 21064)
@@ -0,0 +1,75 @@
+/**************************************************************************
+ *
+ * utils.h -- Functions which are common utilities for the image programs
+ * Copyright (C) 1994  Stuart Inglis
+ *
+ * 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.
+ *
+ * $Id$
+ *
+ **************************************************************************/
+
+#ifndef __UTILS_H
+#define __UTILS_H
+
+#include "sysfuncs.h"
+
+extern int V;
+
+#define DEBUG
+
+#define min(a,b) ((a)<(b) ? (a) : (b))
+#define max(a,b) ((a)>(b) ? (a) : (b))
+
+#define GEN_MAGIC(a,b,c,d) ((unsigned long)(((a)<<24) + ((b)<<16) + \
+                                            ((c)<<8) + (d)))
+ 
+/* --- MG magic file codes [TS:Aug/95] --- */
+#define MAGIC_FELICS            GEN_MAGIC('M','G','F','X')
+#define MAGIC_BILEVEL           GEN_MAGIC('M','G','B','I')
+#define MAGIC_TIC               GEN_MAGIC('M','G','T','C')
+#define IS_MAGIC(a) ((((u_long)(a)) & 0xffff0000) == MAGIC_XXXX)
+/* --------------------------------------- */
+
+#define MAGIC_P1      0x5031	/* P1   - pbm */
+#define MAGIC_P2      0x5032	/* P2   - pgm */
+#define MAGIC_P3      0x5033	/* P3   - ppm */
+#define MAGIC_P4      0x5034	/* P4   - rawbits pbm */
+#define MAGIC_P5      0x5035	/* P5   - rawbits pgm */
+#define MAGIC_P6      0x5036	/* P6   - rawbits ppm */
+
+int isEOF (FILE * fp);
+int getmagicno_byte (FILE * fp);
+int getmagicno_short (FILE * fp);
+int getmagicno_short_pop (FILE * fp);
+int getmagicno_long (FILE * fp);
+
+
+
+void error_msg (char *prog, char *message, char *extra);
+void warn (char *prog, char *message, char *extra);
+
+void readline (char str[], FILE * fp);
+
+void magic_write (FILE * fp, u_long magic_num);
+void magic_check (FILE * fp, u_long magic_num);
+u_long magic_read (FILE * fp);
+/* kerry's code */
+
+int getint (FILE * fp);
+unsigned int gethint (FILE * fp);
+int isinteger (char s[]);
+
+#endif
Index: /main/tags/2.25/gsdl/packages/mg/src/scripts/Makefile.in
===================================================================
--- /main/tags/2.25/gsdl/packages/mg/src/scripts/Makefile.in	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/mg/src/scripts/Makefile.in	(revision 21064)
@@ -0,0 +1,151 @@
+###########################################################################
+#
+# Makefile.in -- Makefile for the MG system
+# Copyright (C) 1994  Neil Sharman
+#
+# 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.
+#
+#       @(#)Makefile.in	1.10 22 Mar 1994
+#
+###########################################################################
+
+PACKAGE = @PACKAGE@
+VERSION = @VERSION@
+ 
+SHELL = /bin/sh
+VPATH = @srcdir@
+exec_prefix = @exec_prefix@
+prefix = @prefix@
+srcdir = @srcdir@
+subdir = src/scripts
+top_srcdir = @top_srcdir@
+transform = @program_transform_name@
+GSDLOS = @gsdlos@
+ 
+DEFS = @DEFS@
+INSTALL = @INSTALL@
+INSTALL_DATA = @INSTALL_DATA@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@
+TOUCH = echo timestamp >
+ 
+bindir = ../../../../bin/$(GSDLOS)
+datadir = $(prefix)/share
+libexecdir = $(exec_prefix)/libexec
+localedir = $(datadir)/locale
+mandir = $(prefix)/man/man1
+ 
+SHFILES       =	mgbuild.sh mgbuild_4.sh mg_get.sh xmg.sh  mg_get_merge.sh mgmerge.sh
+
+MISC          = Makefile.in 
+
+ALLFILES      =	$(SHFILES) $(MISC) $(MAN)
+
+DISTFILES     = $(ALLFILES) 
+
+EXEC          = mgbuild mg_get xmg mg_get_merge mgmerge mgbuild_4
+
+MAN           = mgbuild.1 mgbuild_4.1 mg_get.1 xmg.1 mg_get_merge.1 mgmerge.1
+
+# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
+
+
+all:	$(EXEC)
+
+
+# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
+
+mgbuild : mgbuild.sh
+	@rm -f $@
+	cat mgbuild.sh >$@
+	chmod +x $@
+
+mgbuild_4 : mgbuild_4.sh
+	@rm -f $@
+	cat mgbuild_4.sh >$@
+	chmod +x $@
+
+mg_get : mg_get.sh
+	@rm -f $@
+	cat mg_get.sh >$@
+	chmod +x $@
+
+mgmerge : mgmerge.sh
+	@rm -f $@
+	cat mgmerge.sh >$@
+	chmod +x $@
+
+mg_get_merge : mg_get_merge.sh
+	@rm -f $@
+	cat mg_get_merge.sh >$@
+	chmod +x $@
+
+xmg : xmg.sh
+	@rm -f $@
+	cat xmg.sh >$@
+	chmod +x $@
+
+# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
+
+
+install: execinstall #maninstall
+uninstall: execuninstall manuninstall
+
+execinstall: $(EXEC)
+	for name in $(EXEC); do \
+	  $(INSTALL_PROGRAM) $$name \
+	  $(bindir)/`echo $$name | sed '$(transform)'`; \
+	done
+
+execuninstall:
+	for name in $(EXEC); do \
+	 rm -f $(bindir)/`echo $$name | sed '$(transform)'`; \
+	done
+
+maninstall: $(MAN)
+	$(top_srcdir)/mkinstalldirs $(mandir); \
+	for f in $(MAN); do \
+	  $(INSTALL_DATA) $$f $(mandir)/$$f ;\
+	done
+
+manuninstall: $(MAN)
+	for f in $(MAN); do \
+	  rm -f $(mandir)/$$f ;\
+	done
+
+mostlyclean:
+ 
+clean: mostlyclean
+	rm -f $(EXEC)
+ 
+distclean: clean
+	rm -f ansi2knr
+	rm -f Makefile
+ 
+maintainer-clean: distclean
+	@echo "This command is intended only for maintainers to use;"
+	@echo "rebuilding the deleted files may require special tools."
+ 
+dist: $(DISTFILES)
+	for file in $(DISTFILES); do \
+	  ln $(srcdir)/$$file $(distdir) 2> /dev/null \
+	  || cp -p $(srcdir)/$$file $(distdir); \
+	done
+ 
+Makefile: Makefile.in ../../../../config.status
+	cd ../../../.. && CONFIG_FILES=$(subdir)/$@ CONFIG_HEADERS= ./config.status
+ 
+# Tell versions [3.59,3.63) of GNU make not to export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:
Index: /main/tags/2.25/gsdl/packages/mg/src/scripts/mg_get.1
===================================================================
--- /main/tags/2.25/gsdl/packages/mg/src/scripts/mg_get.1	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/mg/src/scripts/mg_get.1	(revision 21064)
@@ -0,0 +1,154 @@
+.TH mg_get 1 "31 January 1994"
+.SH NAME
+mg_get \- output source texts for processing
+.SH SYNOPSIS
+ 
+.B mg_get
+.I collection-name
+.RB [ \-init | \-i | \-text\fP|\fB\-t\fP|\fB\-cleanup\fP|\fB\-c\fP]
+.SH DESCRIPTION
+.LP
+This program is the default one used by mgbuild to generate the source text for the MG system. Any program may be used to generate the source text for mgbuild as long as it confirms to the interface specified here. 
+.SH OPTIONS
+.LP
+The
+.I collection\-name
+must appear before any other option. Only the first option has any significance. If no option is specified
+.B \-text
+is assumed.
+.RS
+.TP
+.BR \-init " and " \-i
+The program is called once with this flag at the start of building a collection.
+.TP
+.BR \-text " and " \-t
+The program is called with this flag multiple times during the building of a collection. The program outputs (on stdout) the text of the collection. \*(lq\fBDocuments\fP\*(rq within the collection are separated with by ctrl-B's (ASCII code 2). \*(lq\fBParagraphs\fP\*(rq within the collection are separated with ctrl-C's (ASCII code 3). A collection need not contain paragraphs unless a level 3 inverted file is being generated (see 
+.B mgbuild 
+and 
+.BR mg_passes ). 
+.TP
+.BR \-cleanup " and " \-c
+The program is called once with this flag at the completion of building a collection.
+.SH ENVIRONMENT
+.TP
+.SB MGDATA
+If this environment variable exists then its value is used a the default 
+directory where the mg collection files are. If this variable does not exist
+then the directory \*(lq\fB.\fP\*(rq is used by default. The command line 
+option 
+.BI \-d " directory"
+overrides the directory in 
+.BR MGDATA .
+.TP
+.SB MG_GETRC
+This environment variable specifies where the file containing the users 
+mg source configurations is. If not set, mg_get uses a default of 
+.B \*\~/.mg_getrc.
+
+This file contains TAB delimited lines of the form
+.RS 
+.RS 
+.I CollectionName
+.I CollectionType
+.I files or directory
+.RE
+
+.I CollectionName
+is the name of the collection supplied to mg_get.
+
+.I CollectionType
+specifies how mg_get should process the
+named files and directories and are descibed below.
+
+.I files or directory
+is either a list of files separted by blanks or a single directory.
+Some of the
+.I CollectionTypes
+deal with files and others with just a single directory.
+Any files used ending with .gz or .Z are decompressed with gzip before
+processing. References to '~' expands to the users HOME directory.
+
+.I CollectionType
+is one of
+.RS
+.TP
+.BR PARA
+For text based documents. The list of files specified are treated as
+a series of paragraphs separated by blank lines. Each paragraph becomes
+a seperate document on the indexed collection.
+.TP
+.BR MAIL
+for mail files. The list of files specified are treated as UNIX mail
+files separated by lines starting with 'From'. Each mail message becomes
+a seperate document on the indexed collection. As a extra feature any
+embedded tarmail encoded contents (enclosed by a 'xbtoa Begin' and 'xbtoa End'
+pair are removed.
+.TP
+.BR DIR
+(and DIR2)
+For a single directory of files. Each file in the directory (and in any of
+it's subdirectories) are treated as a single document. With
+.I DIR
+the pathname of the file is prefixed to the contents of each file as an
+extra line while this is not done for
+.I DIR2
+collections.
+.TP
+.BR BIB
+for biblography files. The list of files specified are treated as
+a series of biblography files (eg BIBTEX or TROFF) separated by lines
+starting with '@'. Each reference  becomes a seperate document on the indexed
+collection.
+.TP
+.BR TXTIMG
+for integrated collections of text and images. The single directory should
+contain files that have the same prefix if they are related. For example,
+monaLisa.pgm might be a gray-level image, and monaLisa.txt would be a textual
+file describing the image. The suffixes recognised are:
+.BR   .txt
+for  ascii text
+.BR  .ptm
+for  scanned text stored as a bilevel image
+.BR  .pbm
+for a black and white image (typically a line drawing)
+.BR  .pgm
+for a gray-scale image
+.BR In addition, if no corresponding ascii text file is found for
+a .pbm or .pgm file, then one is created with suffix .tmp.txt,
+and it stores the name of the image file (in principle it could
+store the OCR of a .txt.pbm file). At present the .tmp.txt files
+are deleted by the '-cleanup' option.
+
+.SH "EXAMPLE"
+
+An example ~/.mg_getrc file might look like:
+   alice   PARA    /users/alice13a.txt.Z
+   mail95  MAIL    ~/MAIL/1995/*
+   doc     DIR     ~/documents
+   bibs    BIB     ~/etc/REFS/*.bib ~/etc/REFS/CC/*.bib
+   letters DIR     ~/LETTERS
+   davinci TXTIMG  ~/images/davinci
+
+.SH "SEE ALSO"
+.LP
+.BR mg_compression_dict (1),
+.BR mg_invf_dict (1),
+.BR mg_invf_dump (1),
+.BR mg_invf_rebuild (1),
+.BR mg_make_fast_dict (1),
+.BR mg_passes (1),
+.BR mg_perf_hash_build (1),
+.BR mg_text_estimate (1),
+.BR mg_weights_build (1),
+.BR mgbilevel (1),
+.BR mgbuild (1),
+.BR mgdictlist (1),
+.BR mgfelics (1),
+.BR mgquery (1),
+.BR mgstat (1),
+.BR mgtic (1),
+.BR mgticbuild (1),
+.BR mgticdump (1),
+.BR mgticprune (1),
+.BR mgticstat (1)
+
Index: /main/tags/2.25/gsdl/packages/mg/src/scripts/mg_get.sh
===================================================================
--- /main/tags/2.25/gsdl/packages/mg/src/scripts/mg_get.sh	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/mg/src/scripts/mg_get.sh	(revision 21064)
@@ -0,0 +1,447 @@
+#! /bin/csh -f
+###########################################################################
+#
+# mg_get.sh -- script to get text for mgbuild
+# Copyright (C) 1994  Tim Bell
+# Changed to allow it to be driven from a file ~/.mg_getrc
+# by Bruce McKenzie, Oct 1994
+#
+# 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.
+#
+#       @(#)mg_get.sh	1.11 25 Mar 1994
+#
+###########################################################################
+#
+# "mg_get" formats the text for mgbuild by collecting the appropriate
+#   documents, and outputing them with control-B after each document.
+#   The name of the text must be supplied as an argument.
+#   mg_get is called with -i (init) first, then with -t (text) each time the 
+#   text is needed, then with -c (cleanup).
+#   e.g. mg_get alice -t
+#
+# The file ~/.mg_get contains lines of the form:
+#     name	TYPE	files and directories
+# where name is the name supplied to mg_get, TYPE is one of
+# PARA, MAIL, DIR, DIR2, BIB or TXTIMG and says how mg_get should process the
+# named files and directories
+#
+###########################################################################
+
+if ($?MG_GETRC) then
+  set mg_getrc = $MG_GETRC
+else
+  set mg_getrc = ~/.mg_getrc
+endif
+
+# Added by [TS:May/95]
+# if we don't have an mg_getrc file in existence then create a default one
+if !(-e $mg_getrc) then 
+  echo "Can not find a .mg_getrc, so creating a default one: $mg_getrc"
+
+  if ($?MGSAMPLE) then
+    set SampleData = $MGSAMPLE
+  else
+    set SampleData = ./SampleData
+  endif
+
+  cat > $mg_getrc << END
+alice	PARA	$SampleData/alice13a.txt.Z
+davinci	TXTIMG	$SampleData/davinci
+mailfiles	MAIL	~/mbox ~/.sentmail
+allfiles	DIR	~/Mail
+mods	LINESEP	$SampleData/MODIFICATIONS
+bible	PLAIN	$SampleData/bible/genesis.txt.Z $SampleData/bible/revelation.txt.Z
+END
+endif
+
+if (! $?MGIMAGEVIEWER) then
+  setenv MGIMAGEVIEWER "xv -"
+endif
+
+set rm = /bin/rm
+
+switch ($#argv)
+  case 1:
+  set flag = '-text'
+  breaksw
+
+  case 2:
+  set flag = $2
+  switch ($flag)
+     case '-i':
+	set flag = '-init'
+	breaksw
+     case '-t':
+	set flag = '-text'
+	breaksw
+     case '-c':
+	set flag = '-cleanup'
+	breaksw
+     case '-init':
+     case '-text':
+     case '-cleanup':
+     breaksw
+     default:
+     echo 'Usage: mg_get <document> [-i | -t | -c]'
+     exit(1)
+     endsw
+  breaksw
+
+  default:
+  echo 'Usage: get <document> [-i | -t | -c]'
+  exit(1)
+  endsw
+
+set COLLECTION = $1
+set TYPE  = `grep \^$1 $mg_getrc | cut -f2`
+set FILES = `grep \^$1 $mg_getrc | cut -f3`
+
+set bindir = $0
+set bindir = $bindir:h
+
+switch ($TYPE)
+  case PLAIN:
+# Just outputs the given text, assumes ^Bs already inserted 
+  switch ($flag)
+     case '-init':
+     breaksw
+
+     case '-text':
+      foreach f ($FILES)
+	if ($f:e == 'Z') then
+	  set decoder=zcat
+	else if ($f:e == 'gz') then
+	  set decoder=gunzip
+	else
+	  set decoder=cat
+	endif
+        $decoder < $f
+      end
+     breaksw #-text
+
+     case '-cleanup':
+     breaksw
+  endsw #flag
+  breaksw
+
+  case LINESEP:
+# Assumes that the documents are separated by a line of =====
+  switch ($flag)
+     case '-init':
+     breaksw
+
+     case '-text':
+      foreach f ($FILES)
+	if ($f:e == 'Z') then
+	  set decoder=zcat
+	else if ($f:e == 'gz') then
+	  set decoder=gunzip
+	else
+	  set decoder=cat
+	endif
+        $decoder < $f |  sed -e '/\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*/s/.*//' < $f
+      end
+     breaksw #-text
+
+     case '-cleanup':
+     breaksw
+  endsw #flag
+  breaksw
+
+  case PARA:
+# Splits the file at blank lines, which corresponds to paragraphs.
+  switch ($flag)
+     case '-init':
+     breaksw
+
+     case '-text':
+      foreach f ($FILES)
+	if ($f:e == 'Z') then
+	  set decoder=zcat
+	else if ($f:e == 'gz') then
+	  set decoder=gunzip
+	else
+	  set decoder=cat
+	endif
+      $decoder <$f |awk '   /^ *$/ {if (b!=1) printf "";b=1} \
+		\!/^ *$/ {print;b=0} \
+		 END {printf ""}'
+       end #foreach
+     breaksw #-text
+
+     case '-cleanup':
+     breaksw
+  endsw #flag
+  breaksw
+
+  case BIB:
+# Takes a list of files that contain bibliographies, and splits them up 
+#   by putting ^B after each reference. Assumes that each reference
+#   begins with a line '^@'.
+
+  switch ($flag)
+    case '-init':
+    breaksw
+ 
+    case '-text':
+      foreach f ($FILES)
+	if ($f:e == 'Z') then
+	  set decoder=zcat
+	else if ($f:e == 'gz') then
+	  set decoder=gunzip
+	else
+	  set decoder=cat
+	endif
+      $decoder <$f |awk '/^@/&&NR!=1{printf ""} {print $0} END{print ""}'
+      end # foreach
+    breaksw #-text
+ 
+    case '-cleanup':
+    breaksw #-cleanup
+  endsw #flag
+  breaksw #BIB
+
+  case MAIL:
+# Takes a list of files that contain mail, and splits them up 
+#   by putting ^B after each message. Assumes that each message
+#   begins with a line '^From '.
+
+  switch ($flag)
+    case '-init':
+    breaksw
+ 
+    case '-text':
+      foreach f ($FILES)
+	if ($f:e == 'Z') then
+	  set decoder=zcat
+	else if ($f:e == 'gz') then
+	  set decoder=gunzip
+	else
+	  set decoder=cat
+	endif
+      $decoder <$f| awk '/xbtoa Begin/,/xbtoa End/ {next} /^From /&&NR!=1{printf ""} {print $0} END{print ""}'
+      end # foreach
+    breaksw #-text
+ 
+    case '-cleanup':
+    breaksw #-cleanup
+  endsw #flag
+  breaksw #MAIL
+
+  case DIR:
+# Recursively concatenates every file in every subdirectory of the given
+#   directory.
+
+  switch ($flag)
+    case '-init':
+    breaksw
+
+    case '-text'
+      find $FILES -type f -name '*.gz' -exec echo '<' {} '>' \;		\
+			 -exec gzcat {} \; -exec echo -n '' \;
+      find $FILES -type f -name '*.Z' -exec echo '<' {} '>' \;		\
+			 -exec zcat {} \; -exec echo -n '' \;
+#     find $FILES -type f -not -regex '.*\.\(gz\|Z\)' -exec echo '<' {} \
+#			'>' \; -exec cat {} \; -exec echo -n '' \;
+      find $FILES -type f \! \( -name '*.gz' -o -name '*.Z' \) \
+			-exec echo '<' {} '>' \; \
+			-exec cat {} \; -exec echo -n '' \;
+
+    breaksw
+
+    case '-cleanup':
+    breaksw #-cleanup
+  endsw #flag
+  breaksw #DIR
+
+
+
+  case DIR2:
+# Recursively concatenates every file in every subdirectory of the given
+#   directory. Does not include filename
+
+  switch ($flag)
+    case '-init':
+    breaksw
+
+    case '-text'
+      find $FILES -type f -name '*.gz'  		\
+			 -exec gzcat {} \; -exec echo -n '' \;
+      find $FILES -type f -name '*.Z' 	 		\
+			 -exec zcat {} \; -exec echo -n '' \;
+#     find $FILES -type f -not -regex '.*\.\(gz\|Z\)'	\
+#			-exec cat {} \; -exec echo -n '' \;
+      find $FILES -type f \! \( -name '*.gz' -o -name '*.Z' \) \
+			-exec cat {} \; -exec echo -n '' \;
+    breaksw
+
+    case '-cleanup':
+    breaksw #-cleanup
+  endsw #flag
+  breaksw #DIR2
+
+
+
+
+  case TXTIMG:
+# compress and index the collection of text and images
+# (this code is suitable for all sorts of integrated collections
+#  of text and images)
+# Files that are related have the same prefix. For example,
+#  monaLisa.pgm might be a gray-level image, and
+#  monaLisa.txt would be a textual file describing the image.
+# The suffixes recognised are:
+#    .txt	ascii text
+#    .ptm	scanned text stored as a bilevel image
+#    .pbm	a black and white image (typically a line drawing)
+#    .pgm	a gray-scale image
+# In addition, if no corresponding ascii text file is found for
+#  a .pbm or .pgm file, then one is created with suffix .tmp.txt,
+#  and it stores the name of the image file (in principle it could
+#  store the OCR of a .txt.pbm file). At present the .tmp.txt files
+#  are deleted by the '-cleanup' option.
+  
+#### the next two 'set' statements define which directory the files
+#    come from, and where they will be stored. This is the only
+#    part of this code that is specific to the 'davinci' collection
+  set sourceDir = $FILES
+  set targetDir = $MGDATA/$COLLECTION
+
+  switch ($flag)
+    case '-init':
+      mkdir $targetDir >&/dev/null	   # create the directory to store
+					   # compressed images in
+      $rm -rf $targetDir/* >&/dev/null     # in case it already existed
+    
+      # take care if no match to foreach statements
+      set nonomatch
+
+      # process all pbm (black and white) images of text
+      foreach f ($sourceDir/*.ptm)
+        if ($f == "$sourceDir/*.ptm") then
+                break
+        endif
+	set base = $f:t
+	
+        $bindir/mgticbuild $targetDir/$base:r.ticlib.$$ $f
+        $bindir/mgticprune $targetDir/$base:r.ticlib.$$
+
+	$bindir/mgtic -L -e $targetDir/$base:r.ticlib.$$ $f >$targetDir/$base:r.tic
+	$rm $targetDir/$base:r.ticlib.$$
+	set r = $f:r	#root name of file
+	if (! (-e $r.txt || -e $r.tmp)) then
+	# creates a file; could do OCR here to get its contents
+	    echo "No corresponding txt file for" $f "- creating" $r.tmp
+	    echo '#######' $f > $r.tmp
+	endif
+      end
+      # process all pgm (gray scale) images
+      foreach f ($sourceDir/*.pgm)
+        if ($f == "$sourceDir/*.pgm") then
+                break
+        endif
+	set base = $f:t
+	$bindir/mgfelics -e $f >$targetDir/$base:r.flx
+	set r = $f:r	#root name of file
+	if (! (-e $r.txt || -e $r.tmp)) then
+	# creates a file; could do image recognition here to create one(!)
+	    echo "No corresponding txt file for" $f "- creating" $r.tmp
+	    echo '#######' $f > $r.tmp
+	endif
+      end
+      # process all pbm (black and white) images
+      foreach f ($sourceDir/*.pbm)
+        if ($f == "$sourceDir/*.pbm") then
+                break
+        endif
+	set base = $f:t
+	$bindir/mgbilevel -e $f >$targetDir/$base:r.blv
+	set r = $f:r	#root name of file
+	if (! (-e $r.txt || -e $r.tmp)) then
+	# creates a file; could do drawing recognition here to create one(!)
+	    echo "No corresponding txt file for" $f "- creating" $r.tmp
+	    echo '####### No corresponding text file available for this image' >$r.tmp
+	    echo 'Original image file name was' $f >> $r.tmp
+	endif
+      end
+      unset nonomatch
+    breaksw #-init
+
+    case '-text'
+      # take care if no match to foreach statements
+      set nonomatch
+
+      #output each text file and tmp.txt, with names of other associated files
+
+      foreach f ($sourceDir/*.txt $sourceDir/*.tmp)
+        if ($f == "$sourceDir/*.txt") then
+           continue
+        endif
+        if ($f == "$sourceDir/*.tmp") then
+           continue
+        endif
+	set r = $f:r	#root name of file
+	set base = $r:t
+        set first_image = 1 # set so that I print out image header once
+                            # also signifies if header printed out at all
+
+	foreach d ($targetDir/$base.*)
+          if ($d == "$targetDir/$base.*") then
+                break
+          endif
+
+          if ($first_image) then
+            set first_image = 0
+            echo '::::::::::'  #separate the image information from the text
+            echo 'Image(s) available:'
+          endif
+
+	  switch ($d:e)	# work out decoding method from suffix
+            case 'tic':
+              echo 'MGDATA (mgtic -d ' $d '  | '$MGIMAGEVIEWER') '
+            breaksw
+            case 'flx':
+              echo 'MGDATA (mgfelics -d ' $d '  | '$MGIMAGEVIEWER')'
+            breaksw
+            case 'blv':
+              echo 'MGDATA (mgbilevel -d ' $d '  | '$MGIMAGEVIEWER')'
+	    breaksw
+	  endsw # $d:e (suffix)
+
+	end #foreach d (associated file)
+
+        if (! $first_image) then
+	  echo '::::::::::'  #separate the image information from the text
+        endif
+
+	cat $f  # output the text associated with the images
+	echo -n ''
+      end #foreach f (text file)
+      unset nonomatch
+    breaksw #-text
+
+    case '-cleanup':
+      #remove temporary text files
+      $rm $sourceDir/*.tmp
+    breaksw #-cleanup
+  endsw #flag
+  breaksw #IMGTXT
+
+
+  default:
+    echo 'Sorry, I do not know how to get' $1
+    exit 1	
+endsw
+exit 0
Index: /main/tags/2.25/gsdl/packages/mg/src/scripts/mg_get_merge.1
===================================================================
--- /main/tags/2.25/gsdl/packages/mg/src/scripts/mg_get_merge.1	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/mg/src/scripts/mg_get_merge.1	(revision 21064)
@@ -0,0 +1,86 @@
+.\"------------------------------------------------------------
+.\" Id - set Rv,revision, and Dt, Date using rcs-Id tag.
+.de Id
+.ds Rv \\$3
+.ds Dt \\$4
+..
+.Id $Id$
+.\"------------------------------------------------------------
+.TH mg_get_merge 1 \*(Dt CITRI
+.SH NAME
+mg_get_merge \- output source texts for processing
+.SH SYNOPSIS
+.B mg_get_merge
+.I collection-name
+.if n .ti +9n
+[
+.BR \-init " |"
+.BR \-i " |"
+.BR \-text " |"
+.BR \-t " |"
+.BR \-cleanup " |"
+.B  \-c
+]
+.SH DESCRIPTION
+This program is the default one used by
+.BR mgmerge (1)
+to generate the source text for new documents to appended to
+an
+.BR mg (1)
+system database.
+Its function is exactly the same as
+.BR mg_get (1)
+except that it generates the 
+.I new 
+documents to be added to an
+.BR mg (1)
+system database that has already been built using
+.BR mgbuild(1).
+Any program may be used to generate the source
+text for
+.BR mgmerge (1),
+as long as it confirms to the interface specified
+here.
+.SH OPTIONS
+The
+.I collection-name
+must appear before any other option.  Only the first option has any
+significance.  If no option is specified,
+.B \-text
+is assumed.
+.TP "\w'\fB\-cleanup\fP and \fB\-c\fP'u+2n"
+.BR \-init " and " \-i
+The program is called once with this flag at the start of merging a
+collection.
+.TP
+.BR \-text " and " \-t
+The program is called with this flag multiple times during the
+merging of a collection.  The program outputs (on
+.IR stdout )
+the text of the collection.
+.I Documents
+within the collection are separated by ctrl-B's (ASCII code 2).
+.TP
+.BR \-cleanup " and " \-c
+The program is called once with this flag at the completion of
+merging a collection.
+.SH ENVIRONMENT
+.TP "\w'\fBMGDATA\fP'u+2n"
+.SB MGDATA
+If this environment variable exists, then its value is used as the
+default directory where the
+.BR mg (1)
+collection files are.  If this variable does not exist, then the
+directory \*(lq\fB.\fP\*(rq is used by default.  The command line
+option
+.BI \-d " directory"
+overrides the directory in
+.BR MGDATA .
+.SH "SEE ALSO"
+.na
+.BR mg (1),
+.BR mg_get (1),
+.BR mgbuild (1),
+.BR mgmerge (1),
+.BR mg_text_merge (1),
+.BR mg_invf_merge (1).
Index: /main/tags/2.25/gsdl/packages/mg/src/scripts/mg_get_merge.sh
===================================================================
--- /main/tags/2.25/gsdl/packages/mg/src/scripts/mg_get_merge.sh	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/mg/src/scripts/mg_get_merge.sh	(revision 21064)
@@ -0,0 +1,313 @@
+#! /bin/csh -f
+###########################################################################
+#
+# mg_get_merge.sh -- script to get text for mgbuild
+# Copyright (C) 1994  Tim Bell, Shane Hudson (mods. for merging)
+#
+# 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.
+#
+#
+###########################################################################
+#
+# "mg_get_merge" formats the text for mgbuild by collecting the appropriate
+#   documents, and outputing them with control-B after each document.
+#   The name of the text must be supplied as an argument.
+#   mg_get is called with -i (init) first, then with -t (text) each time the 
+#   text is needed, then with -c (cleanup).
+#   e.g. mg_get alice -t
+#
+###########################################################################
+
+
+
+# The directory containing the data files is stored in the environment
+#   variable MGSAMPLE
+
+if ($?MGSAMPLE) then
+  set SampleData = $MGSAMPLE
+else
+  set SampleData = ./SampleData
+endif
+
+if (! $?MGIMAGEVIEWER) then
+  setenv MGIMAGEVIEWER "xv -"
+endif
+
+set rm = /bin/rm
+
+switch ($#argv)
+  case 1:
+  set flag = '-text'
+  breaksw
+
+  case 2:
+  set flag = $2
+  switch ($flag)
+     case '-i':
+	set flag = '-init'
+	breaksw
+     case '-t':
+	set flag = '-text'
+	breaksw
+     case '-c':
+	set flag = '-cleanup'
+	breaksw
+     case '-init':
+     case '-text':
+     case '-cleanup':
+     breaksw
+     default:
+     echo 'Usage: get <document> [-i | -t | -c]'
+     exit(1)
+     endsw
+  breaksw
+
+  default:
+  echo 'Usage: get <document> [-i | -t | -c]'
+  exit(1)
+  endsw
+
+set bindir = $0
+set bindir = $bindir:h
+
+switch ($1)
+  case alice:
+  switch ($flag)
+     case '-init':
+     breaksw
+
+     case '-text':
+	echo "This is a test document 1 2 3 4 5 6 7 8 9 "
+	echo ""
+	echo "A B C"
+     breaksw
+
+     case '-cleanup':
+     breaksw
+  endsw #flag
+  breaksw
+
+  case bible:
+  switch ($flag)
+    case '-init':
+    breaksw
+
+    case '-text':
+       # use uncompressed file if it exists
+       # revelation.txt already contains '^B' characters between verses
+       if (-e $SampleData/bible/revelation.txt) then
+          cat $SampleData/bible/revelation.txt
+       else
+          uncompress <$SampleData/bible/revelation.txt.Z
+    breaksw #-text
+
+    case '-cleanup':
+    breaksw #-cleanup
+
+  endsw #flag
+  breaksw #bible
+
+
+
+  case mailfiles:
+# Takes a list of files that contain mail, and splits them up 
+#   by putting ^B after each message. Assumes that each message
+#   begins with a line '^From '.
+# If messages are already in individual files, use "get allfiles"
+#   rather than this one.
+# The EXTRA documents added are in files in the directory mailextra
+#### The variable 'mailfiles' contains a list of files to be split up
+  set mailfiles = '~/mbox ~/.sentmail'
+  set mailextra = '~/extra/*'
+
+  switch ($flag)
+    case '-init':
+    breaksw
+
+    case '-text':
+      foreach f ($mailextra)
+	awk '/^From /&&NR!=1{print ""} {print $0} END{print ""}' $f
+      end # foreach
+    breaksw #-text
+
+    case '-cleanup':
+    breaksw #-cleanup
+
+  endsw #flag
+  breaksw #mailfiles
+
+
+
+  case allfiles:
+# Recursively concatenates every file in every subdirectory of the given
+#   directory.
+
+# The variable 'directory' on the next line contains the directory to be used
+  set directory = ~/Mail
+
+# The date of the file ".mgbuildtime" in 'directory' is the last
+# build or merge. At the start of the merge ("-init" argument) the
+# file ".mgmergetime" is touched. Only files newer than ".mgbuildtime"
+# but older than ".mgmergetime" are output by mg_get_merge
+
+  switch ($flag)
+    case '-init':
+        touch $directory/.mgmergetime
+    breaksw
+
+    case '-text'
+      find $directory -type f -newer $directory/.mgbuildtime \! -newer $directory/.mgmergetime \! -name '.*' -exec echo '<' {} '>' \; -exec cat {} \; -exec echo -n '' \;
+    breaksw
+
+    case '-cleanup':
+        touch $directory/.mgmergetime
+        touch $directory/.mgbuildtime
+    breaksw #-cleanup
+  endsw #flag
+  breaksw #allfiles
+
+
+
+
+  case davinci:
+# compress and index the DaVinci collection of text and images
+# (this code is suitable for all sorts of integrated collections
+#  of text and images)
+# It assumes that all files are in one directory ($sourceDir).
+# Files that are related have the same prefix. For example,
+#  monaLisa.img.pgm might be a gray-level image, and
+#  monaLisa.txt.txt would be a textual file describing the image.
+# The suffixes recognised are:
+#    .txt.txt	ascii text
+#    .txt.pbm	scanned text stored as a bilevel image
+#    .img.pbm	a black and white image (typically a line drawing)
+#    .img.pgm	a gray-scale image
+# In addition, if no corresponding ascii text file is found for
+#  a .pbm or .pgm file, then one is created with suffix .tmp.txt,
+#  and it stores the name of the image file (in principle it could
+#  store the OCR of a .txt.pbm file). At present the .tmp.txt files
+#  are deleted by the '-cleanup' option.
+  
+#### the next two 'set' statements define which directory the files
+#    come from, and where they will be stored. This is the only
+#    part of this code that is specific to the 'davinci' collection
+  set sourceDir = $SampleData/davinci
+  set targetDir = $MGDATA/davinci
+
+  switch ($flag)
+    case '-init':
+      mkdir $targetDir >&/dev/null	   #create the directory to store
+					   # compressed images in
+      $rm -rf $targetDir/* >&/dev/null #in case it already existed
+    
+      # process all pbm (black and white) images of text
+      foreach f ($sourceDir/*.ptm)
+	set base = $f:t
+	
+        $bindir/mgticbuild $targetDir/$base:r.ticlib.$$ $f
+        $bindir/mgticprune $targetDir/$base:r.ticlib.$$
+
+	$bindir/mgtic -L -e $targetDir/$base:r.ticlib.$$ $f >$targetDir/$base:r.tic
+	$rm $targetDir/$base:r.ticlib.$$
+	set r = $f:r	#root name of file
+	if (! (-e $r.txt || -e $r.tmp)) then
+	# creates a file; could do OCR here to get its contents
+	    echo "No corresponding txt file for" $f "- creating" $r.tmp
+	    echo '#######' $f > $r.tmp
+	endif
+      end
+      # process all pgm (gray scale) images
+      foreach f ($sourceDir/*.pgm)
+	set base = $f:t
+	$bindir/mgfelics -e $f >$targetDir/$base:r.flx
+	set r = $f:r	#root name of file
+	if (! (-e $r.txt || -e $r.tmp)) then
+	# creates a file; could do image recognition here to create one(!)
+	    echo "No corresponding txt file for" $f "- creating" $r.tmp
+	    echo '#######' $f > $r.tmp
+	endif
+      end
+      # process all pbm (black and white) images
+      foreach f ($sourceDir/*.pbm)
+	set base = $f:t
+	$bindir/mgbilevel -e $f >$targetDir/$base:r.blv
+	set r = $f:r	#root name of file
+	if (! (-e $r.txt || -e $r.tmp)) then
+	# creates a file; could do drawing recognition here to create one(!)
+	    echo "No corresponding txt file for" $f "- creating" $r.tmp
+	    echo '####### No corresponding text file available for this image' >$r.tmp
+	    echo 'Original image file name was' $f >> $r.tmp
+	endif
+      end
+    breaksw #-init
+
+    case '-text'
+      #output each text file and tmp.txt, with names of other associated files
+      foreach f ($sourceDir/*.txt $sourceDir/*.tmp)
+	set r = $f:r	#root name of file
+	set base = $r:t
+	set n = `/bin/ls $sourceDir/$base.* | wc -l`
+	if ($n != 1) then # more files than just the text one
+	 echo '::::::::::'  #separate the image information from the text
+	 echo 'Image(s) available:'
+	 foreach d ($targetDir/$base.*)
+	  switch ($d:e)	# work out decoding method from suffix
+            case 'tic':
+              echo 'MGDATA (mgtic -d ' $d '  | '$MGIMAGEVIEWER') '
+            breaksw
+            case 'flx':
+              echo 'MGDATA (mgfelics -d ' $d '  | '$MGIMAGEVIEWER')'
+            breaksw
+            case 'blv':
+              echo 'MGDATA (mgbilevel -d ' $d '  | '$MGIMAGEVIEWER')'
+	    breaksw
+	  endsw # $d:e (suffix)
+	 end #foreach d (associated file)
+	echo '::::::::::'  #separate the image information from the text
+	endif # if more than one file
+	cat $f  # output the text associated with the images
+	echo -n ''
+      end #foreach f (text file)
+    breaksw #-text
+
+    case '-cleanup':
+      #remove temporary text files
+      $rm $sourceDir/*.tmp
+    breaksw #-cleanup
+  endsw #flag
+  breaksw #davinci
+
+
+#---------------------------
+  case mods:
+# Splits the modifications file at the mod separator "--------"
+  switch ($flag)
+     case '-init':
+     breaksw
+ 
+     case '-text':
+       sed -e 's/^---.*//g' < ${SampleData}/MODIFICATIONS
+     breaksw
+ 
+     case '-cleanup':
+     breaksw
+  endsw #flag
+  breaksw #mods
+
+  default:
+    echo 'Sorry, I do not know how to get' $1
+    exit 1	
+endsw
+exit 0
Index: /main/tags/2.25/gsdl/packages/mg/src/scripts/mgbuild.1
===================================================================
--- /main/tags/2.25/gsdl/packages/mg/src/scripts/mgbuild.1	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/mg/src/scripts/mgbuild.1	(revision 21064)
@@ -0,0 +1,169 @@
+.\"------------------------------------------------------------
+.\" Id - set Rv,revision, and Dt, Date using rcs-Id tag.
+.de Id
+.ds Rv \\$3
+.ds Dt \\$4
+..
+.Id $Id$
+.\"------------------------------------------------------------
+.TH mgbuild 1 \*(Dt CITRI
+.SH NAME
+mgbuild \- build an mg system database
+.SH SYNOPSIS
+.B mgbuild
+[
+.B \-c
+]
+[
+.BI \-g " get"
+]
+[
+.BI \-s " source"
+]
+[
+.BI \-d " mgdata dir"
+]
+.I collection-name
+.SH DESCRIPTION
+.B mgbuild
+is a
+.B csh
+script that executes all the appropriate programs in the correct order
+to completely build an
+.BR mg (1)
+system database ready for queries to be made
+by
+.BR mgquery.
+This program makes use of the
+.BR mg_get (1)
+script to obtain the text of the collection.
+.SH OPTIONS
+Options can occur in any order, but the collection name must be last.
+.TP "\w'\fIcollection-name\fP'u+2n"
+.BI \-c
+This specifies whether the
+.I get
+program is \*(lqcomplex\*(rq.  If a
+.I get
+program is \*(lqcomplex\*(rq, then it requires initialisation and
+cleanup with the
+.B \-i
+and
+.B \-c
+options.
+.TP
+.BI \-g " get"
+This specifies the program to use for getting the source text for the
+build.  If no
+.B \-g
+option is given, the default program
+.BR mg_get (1)
+is used.
+.TP
+.BI \-s " source"
+The
+.B mgbuild
+program consists of two parts.  The first part initializes variables
+to default values.  The second part uses these variables to control
+how the
+.BR mg (1)
+database is built.  This option specifies a program to execute between
+the first and second parts.  The details of what the variables are, and
+how they may be changed, are in comments in the
+.B mgbuild
+program.
+.TP
+.BI \-d " mgdata dir"
+Setting this option allows one to override the MGDATA environment variable.
+.TP
+.I collection-name
+This is the collection name, as required by the
+.BR mg_get (1)
+program.  It serves both as a
+.I case
+statement selector, and as the name of a subdirectory that holds the
+indexing files.
+.SH ENVIRONMENT
+.TP "\w'\fBMGDATA\fP'u+2n"
+.SB MGDATA
+If this environment variable exists, then its value is used as the
+default directory where the
+.BR mg (1)
+collection files are.  If this variable does not exist, then the
+directory \*(lq\fB.\fP\*(rq is used by default.  The command line
+option
+.BI \-d " directory"
+overrides the directory in
+.BR MGDATA .
+.SH FILES
+.TP 20
+.B *.invf
+Inverted file.
+.TP
+.B *.invf.chunk
+Inverted file chunk descriptor file.  When the inverted file is
+created, it is written in chunks that use no more than a set amount of
+memory.  This file describes those chunks.
+.TP
+.B *.invf.chunk.trans
+Word-occurrence-order to lexical-order translation file.  The
+.B *.invf.chunk
+file is written in word-occurrence order but is required by
+.B \-N2
+to be in lexical order.
+.TP
+.B *.invf.dict
+Compressed stemmed dictionary.
+.TP
+.B *.invf.dict.blocked
+The `on-disk' stemmed dictionary.
+.TP
+.B *.invf.dict.hash
+Data for an order-preserving perfect hash function.
+.TP
+.B *.invf.idx
+The index into the inverted file.
+.TP
+.B *.weight
+The exact weights file.
+.TP
+.B *.text
+Compressed documents.
+.TP
+.B *.text.stats
+Text statistics.
+.TP
+.B *.text.dict
+Compressed compression dictionary.
+.TP
+.B *.text.idx
+Index into the compressed documents.
+.TP
+.B *.text.idx.wgt
+Interleaved index into the compressed documents and document weights.
+.TP
+.B *.weight.approx
+Approximate document weights.
+.SH "SEE ALSO"
+.na
+.BR mg (1),
+.BR mg_compression_dict (1),
+.BR mg_fast_comp_dict (1),
+.BR mg_get (1),
+.BR mg_invf_dict (1),
+.BR mg_invf_dump (1),
+.BR mg_invf_rebuild (1),
+.BR mg_passes (1),
+.BR mg_perf_hash_build (1),
+.BR mg_text_estimate (1),
+.BR mg_weights_build (1),
+.BR mgbilevel (1),
+.BR mgdictlist (1),
+.BR mgfelics (1),
+.BR mgquery (1),
+.BR mgstat (1),
+.BR mgtic (1),
+.BR mgticbuild (1),
+.BR mgticdump (1),
+.BR mgticprune (1),
+.BR mgticstat (1).
Index: /main/tags/2.25/gsdl/packages/mg/src/scripts/mgbuild.sh
===================================================================
--- /main/tags/2.25/gsdl/packages/mg/src/scripts/mgbuild.sh	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/mg/src/scripts/mgbuild.sh	(revision 21064)
@@ -0,0 +1,339 @@
+#!/bin/csh -f
+###########################################################################
+#
+# mgbuild.sh -- Script used to build mg text collection.
+# Copyright (C) 1994  Neil Sharman
+#
+# 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.
+#
+#       @(#)mgbuild.sh	1.9 16 Mar 1994
+#
+###########################################################################
+#  mg.build
+# Creates a Full Text Retrieval database
+#
+#  @(#)mgbuild.sh	1.9 16 Mar 1994
+#
+
+set complex = ""
+
+# Parse the command line arguments
+while ($#argv >= 1)
+  if ("$1" == "-s") then
+    shift
+    if ($#argv >= 1) then
+      set source = $1
+      shift
+    endif
+  else if ("$1" == "-d") then
+    shift
+    if ($#argv >= 1) then
+      set mgdata = $1
+      shift
+    endif
+  else if ("$1" == "-g") then
+    shift
+    if ($#argv >= 1) then
+      set get = $1
+      shift
+    endif
+  else if ("$1" == "-c") then
+    set complex = "-text"
+    shift
+  else
+    if ($?text == "0") then
+      set text = $1
+    endif
+    shift
+  endif
+    
+end
+
+if ($?text == "0") then
+  set prog = $0
+  echo "USAGE:"
+  echo "     "$prog:t" [-s config-script] [-g get-program] [-d mgdata dir] [-c] source"
+  echo ""
+  echo " The config-script is only needed if a non-standard build is required."
+  echo " The get-program defaults to mg_get if not specified."
+  exit 1	
+endif
+
+set bindir = $0
+set bindir = $bindir:h
+
+# if $pipe == 1 then pipe in the source text using $get and $text otherwise
+# read the source text directly from the file names specified in $input_files
+set pipe = 1
+
+if ($?get == "0") then
+  set complex = "-text"
+  set get = $bindir/mg_get
+endif
+
+if ($?mgdata) then
+  setenv MGDATA $mgdata
+endif
+
+if (-e $MGDATA/${text}.chunks) then
+  set input_files = `cat $MGDATA/${text}.chunks`
+endif
+
+# Set the stemming method
+#   Bit 0 = case folding
+#   Bit 1 = S stemmer
+set stem_method = 3
+
+
+# [RPAP - Jan 97: Stem Index Change]
+# If do_indexes == 1 then build collection with full indexes to blocked file
+# overriding stem_method (stem_method will be set to 0)
+# Otherwise don't build with indexes
+set do_indexes = 0
+
+
+# If do_text == 1 then do the text component of building a mg database. 
+# Otherwise don't do the text component.
+set do_text = 1
+
+
+# If do_invf == 1 then do the inversion component of building a mg database. 
+# Otherwise don't do the inversion component.
+set do_invf = 1
+
+
+# If do_pass1 == 1 then do pass1 of building a mg database. 
+# Otherwise don't do pass1.
+set do_pass1 = 1
+
+# If do_pass2 == 1 then do pass2 of building a mg database. 
+# Otherwise don't do pass2.
+set do_pass2 = 1
+
+
+# $invf_mem specifies the amount of memory to use for the pass2 inversion
+set invf_mem = 32
+
+
+# $num_chunks specifies the number of interium chunks of inverted file that
+# may be written to disc before a merge into the invf file is done
+set num_chunks = 3
+
+# $invf_level specifies the level of the inverted file that will be generated.
+set invf_level = 2
+
+
+# If $strip_sgml == 1 then sgml tags are stripped from the inversion phase.
+# Otherwise sgml tags are kepted.
+set strip_sgml = 1
+
+
+# $trace specifies the interval between trace entries in Mb.
+# If this is not set no trace entries will be generated.
+set trace = 10
+
+
+# $weight_bits specifies the number of bits of precision bo be given to the 
+# approximate weights.
+set weight_bits = 6
+
+
+# $mcd specifies the commandline arguments for the mg_compression_dict program
+#### Note: Set -S so novel words can be encoded, as this will happen if
+#### mgmerge is used.
+set mcd = -S
+
+
+# Source the parameter file to modify parameters of the build.
+if ($?source) then
+  source ${source}
+endif
+
+
+# [RPAP - Jan 97: Stem Index Change]
+# If do_indexes == 1 then set stem_method = 0
+if ("$do_indexes" == "1") then
+  set stem_method = 0
+endif
+
+
+# Generate the collection name.
+set coll_name = ${text}
+if ("$invf_level" == "3") then
+  set coll_name = ${text}-p
+endif
+
+# Generate the directory for the collection.
+if (-e $MGDATA/${coll_name}) then
+else
+  mkdir $MGDATA/${coll_name}
+endif
+
+# Generate the base name for the collection.
+set bname = ${coll_name}/${coll_name}
+
+
+#build up the command lines for pass 1 and 2
+set pass1 = (-f ${bname} -${invf_level} -m ${invf_mem} -s ${stem_method})
+set pass2 = (-f ${bname} -${invf_level} -c ${num_chunks})
+
+if ($strip_sgml) then
+  set pass1 = (${pass1} -G)
+  set pass2 = (${pass2} -G)
+endif
+
+if ($?trace) then
+  set pass1 = (${pass1} -t ${trace})
+  set pass2 = (${pass2} -t ${trace})
+endif
+
+if ($do_text) then
+  set pass1 = (${pass1} -T1)
+  set pass2 = (${pass2} -T2)
+endif
+
+if ($do_invf) then
+  set pass1 = (${pass1} -I1)
+  set pass2 = (${pass2} -I2)
+endif
+  
+if ($?trace_name) then
+  set pass1 = (${pass1} -n ${trace_name})
+  set pass2 = (${pass2} -n ${trace_name})
+endif
+  
+if ($?comp_stats) then
+  set pass2 = (${pass2} -C ${comp_stats})
+endif
+
+echo "-----------------------------------"
+echo "`uname -n`, `date`"
+echo "${text} --> ${bname}"
+echo "-----------------------------------"
+if ($pipe) then
+  if ("$complex" != "") then
+    echo "$get $text -init"
+    $get $text -init
+    if ("$status" != "0") exit 1 
+    echo "-----------------------------------"
+  endif  
+endif
+
+if (${do_pass1}) then
+  if ($pipe) then
+    if ($?pass1filter) then
+      echo "$get $text $complex | $pass1filter | mg_passes ${pass1}"
+      $get $text $complex| $pass1filter | $bindir/mg_passes ${pass1}
+      if ("$status" != "0") exit 1 
+    else
+      echo "$get $text $complex | mg_passes ${pass1}"
+      $get $text $complex| $bindir/mg_passes ${pass1}
+      if ("$status" != "0") exit 1 
+    endif
+  else
+    echo mg_passes ${pass1} ${input_files}
+    $bindir/mg_passes ${pass1} ${input_files}
+    if ("$status" != "0") exit 1 
+  endif
+  echo "-----------------------------------"
+
+  echo "mg_perf_hash_build -f ${bname}"
+  $bindir/mg_perf_hash_build -f ${bname}
+  if ("$status" != "0") exit 1 
+
+  echo "-----------------------------------"
+  echo "mg_compression_dict -f ${bname} ${mcd}"
+  $bindir/mg_compression_dict -f ${bname} ${mcd}
+  if ("$status" != "0") exit 1 
+  echo "-----------------------------------"
+endif
+
+if (${do_pass2}) then
+  if ($pipe) then
+    if ($?pass2filter) then
+      echo "$get $text $complex | $pass2filter | mg_passes ${pass2}"
+      $get $text $complex | $pass2filter | $bindir/mg_passes ${pass2}
+      if ("$status" != "0") exit 1 
+    else
+      echo "$get $text $complex | mg_passes ${pass2}"
+      $get $text $complex | $bindir/mg_passes ${pass2}
+      if ("$status" != "0") exit 1 
+    endif
+  else
+    echo mg_passes ${pass2} ${input_files}
+    $bindir/mg_passes ${pass2} ${input_files}
+    if ("$status" != "0") exit 1 
+  endif
+  echo "-----------------------------------"
+endif
+
+echo "mg_weights_build -f ${bname} -b ${weight_bits}"
+$bindir/mg_weights_build -f ${bname} -b ${weight_bits}
+if ("$status" != "0") exit 1 
+
+echo "-----------------------------------"
+
+echo "mg_invf_dict -f ${bname} -b 4096"
+$bindir/mg_invf_dict -f ${bname} -b 4096
+if ("$status" != "0") exit 1 
+
+echo "-----------------------------------"
+
+# [RPAP - Jan 97: Stem Index Change]
+if ("$do_indexes" == "1") then
+  echo "mg_stem_idx -f ${bname} -b 4096 -s1"
+  $bindir/mg_stem_idx -f ${bname} -b 4096 -s1
+  if ("$status" != "0") exit 1 
+
+  echo ""
+
+  echo "mg_stem_idx -f ${bname} -b 4096 -s2"
+  $bindir/mg_stem_idx -f ${bname} -b 4096 -s2
+  if ("$status" != "0") exit 1 
+
+  echo ""
+
+  echo "mg_stem_idx -f ${bname} -b 4096 -s3"
+  $bindir/mg_stem_idx -f ${bname} -b 4096 -s3
+  if ("$status" != "0") exit 1 
+
+  echo "-----------------------------------"
+endif
+
+echo "mgstat -f ${bname} -E"
+$bindir/mgstat -f ${bname} -E
+if ("$status" != "0") exit 1 
+
+if ($pipe) then
+  if ("$complex" != "") then
+    echo "-----------------------------------"
+    echo "$get $text -cleanup"
+    $get $text -cleanup
+    if ("$status" != "0") exit 1 
+  endif
+endif
+
+echo "-----------------------------------"
+echo "`uname -n`, `date`"
+echo "-----------------------------------"
+
+echo "-- The fast-loading compression dictionary has not been built."
+echo "-- If you wish to build it, execute the following command:"
+echo "-- "$bindir/mg_fast_comp_dict -f ${bname}
+
+echo "-----------------------------------"
+
+echo ""
+
Index: /main/tags/2.25/gsdl/packages/mg/src/scripts/mgbuild_4.1
===================================================================
--- /main/tags/2.25/gsdl/packages/mg/src/scripts/mgbuild_4.1	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/mg/src/scripts/mgbuild_4.1	(revision 21064)
@@ -0,0 +1,53 @@
+.\"------------------------------------------------------------
+.\" Id - set Rv,revision, and Dt, Date using rcs-Id tag.
+.de Id
+.ds Rv \\$3
+.ds Dt \\$4
+..
+.Id $Id$
+.\"------------------------------------------------------------
+.TH mgbuild_4 1 \*(Dt CITRI
+.SH NAME
+mgbuild_4 \- build an mg system database using 4 passes instead of 2
+.SH SYNOPSIS
+.B mgbuild_4
+[
+.B \-c
+]
+[
+.BI \-g " get"
+]
+[
+.BI \-s " source"
+]
+[
+.BI \-d " mgdata dir"
+]
+.I collection-name
+.SH DESCRIPTION
+.B mgbuild_4
+is a
+.B csh
+script that executes all the appropriate programs in the correct order
+to completely build an
+.BR mg (1)
+system database ready for queries to be made
+by
+.BR mgquery.
+This program makes use of the
+.BR mg_get (1)
+script to obtain the text of the collection.
+In 
+.BR mgbuild (1)
+the build is done by two passes over the input text. The first
+pass creates the compressed text dictionary and inverted file dictionary,
+the second pass creates the compressed text and inverted file. What 
+.BR mgbuild_4
+does is use a separate pass for each function. This will be slower but will
+not require as much RAM at one time. Therefore, if your build is failing
+due to running short of memory, then 
+.BR mgbuild_4
+is worth a try.
+.SH "SEE ALSO"
+.na
+.BR mgbuild (1)
Index: /main/tags/2.25/gsdl/packages/mg/src/scripts/mgbuild_4.sh
===================================================================
--- /main/tags/2.25/gsdl/packages/mg/src/scripts/mgbuild_4.sh	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/mg/src/scripts/mgbuild_4.sh	(revision 21064)
@@ -0,0 +1,435 @@
+#!/bin/csh -f
+###########################################################################
+#
+# mgbuild_4.sh -- Script used to build mg text collection in 4 passes.
+# Copyright (C) 1994  Neil Sharman; Modified by tes@kbs 1995
+#
+# 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.
+#
+#
+###########################################################################
+#
+# Does an mgbuild in 4 passes instead of 2 passes.
+# This is useful if one does not have as much RAM and a large collection.
+#
+
+set complex = ""
+
+# ************ parse the command line arguments ************
+
+while ($#argv >= 1)
+  if ("$1" == "-s" || "$1" == "--source") then
+    shift
+    if ($#argv >= 1) then
+      set source = $1
+      shift
+    endif
+  else if ("$1" == "-g" || "$1" == "--get") then
+    shift
+    if ($#argv >= 1) then
+      set get = $1
+      shift
+    endif
+  else if ("$1" == "-c" || "$1" == "--complex") then
+    set complex = "-text"
+    shift
+  else
+    if (! $?text ) then
+      set text = $1
+    endif
+    shift
+  endif
+    
+end
+
+if (! $?text ) then
+  set prog = $0
+  echo "USAGE:"
+  echo "     "$prog:t" [-s config-script] [-g get-program] [-c] source"
+  echo ""
+  echo " The config-script is only needed if a non-standard build is required."
+  echo " The get-program defaults to mg_get if not specified."
+  exit 1	
+endif
+
+set bindir = `which $0` # find which one we are executing
+set bindir = $bindir:h # use it as the bindir path
+
+# ************ set up shell variables ************
+# Override these by providing a script to source using the -s option
+
+# if $pipe == 1 then pipe in the source text using $get and $text otherwise
+# read the source text directly from the file names specified in $input_files
+set pipe = 1
+
+set get_options = ""
+
+
+if (! $?get ) then
+  set complex = "-text"
+  set get = $bindir/mg_get $get_options
+endif
+
+
+if (-e $MGDATA/${text}.chunks) then
+  set input_files = `cat $MGDATA/${text}.chunks`
+endif
+
+# Set the stemming method
+#   Bit 0 = case folding
+#   Bit 1 = S stemmer
+set stem_method = 3
+
+
+# [RPAP - Jan 97: Stem Index Change]
+# If do_indexes == 1 then build collection with full indexes to blocked file
+# overriding stem_method (stem_method will be set to 0)
+# Otherwise don't build with indexes
+set do_indexes = 0
+
+
+# whether to build weights or not
+set do_weights = 1
+
+# If do_pass1 == 1 then do pass1 of building a mg database. 
+# Otherwise don't do pass1.
+# Text 1st pass
+set do_pass1 = 1
+
+# If do_pass2 == 1 then do pass2 of building a mg database. 
+# Otherwise don't do pass2.
+# Text 2nd pass
+set do_pass2 = 1
+
+# If do_pass3 == 1 then do pass3 of building a mg database. 
+# Otherwise don't do pass3.
+# Invf 1st pass
+set do_pass3 = 1
+
+# If do_pass4 == 1 then do pass4 of building a mg database. 
+# Otherwise don't do pass4.
+# Invf 2nd pass
+set do_pass4 = 1
+
+# Buffer size used by mg_passes
+# Should be big enough to hold largest document
+# In Kilobytes
+set buf_size = 3072
+
+# $invf_mem specifies the amount of memory to use for the pass2 inversion
+set invf_mem = 5
+
+# $num_chunks specifies the number of interium chunks of inverted file that
+# may be written to disc before a merge into the invf file is done
+set num_chunks = 3
+
+# $invf_level specifies the level of the inverted file that will be generated.
+set invf_level = 2
+
+
+# If $strip_sgml == 1 then sgml tags are stripped from the inversion phase.
+# Otherwise sgml tags are kepted.
+set strip_sgml = 1
+
+
+# $trace specifies the interval between trace entries in Mb.
+# If this is not set no trace entries will be generated.
+set trace = 10
+
+
+# $weight_bits specifies the number of bits of precision bo be given to the 
+# approximate weights.
+set weight_bits = 6
+
+
+# $mcd specifies the commandline arguments for the mg_compression_dict program
+set mcd = -C
+
+
+# Source the parameter file to modify parameters of the build.
+if ($?source) then
+  source ${source}
+endif
+
+
+# [RPAP - Jan 97: Stem Index Change]
+# If do_indexes == 1 then set stem_method = 0
+if ("$do_indexes" == "1") then
+  set stem_method = 0
+endif
+
+
+# Generate the collection name.
+set coll_name = ${text}
+if ("$invf_level" == "3") then
+  set coll_name = ${text}-p
+endif
+
+# Generate the directory for the collection.
+if (-e $MGDATA/${coll_name}) then
+else
+  mkdir $MGDATA/${coll_name}
+endif
+
+# Generate the base name for the collection.
+set bname = ${coll_name}/${coll_name}
+
+# ************ set up pass parameters ************
+
+if ($do_pass1) then
+  set pass1_text = (-f ${bname} -T1)
+endif
+
+if ($do_pass2) then
+  set pass2_text = (-f ${bname} -T2)
+endif
+
+if ($do_pass3) then
+  set pass3_invf = (-f ${bname} -${invf_level} -m ${invf_mem} -s ${stem_method})
+  set pass3_invf = (${pass3_invf} -N1)
+endif
+
+if ($do_pass4) then
+  set pass4_invf = (-f ${bname} -${invf_level} -N2)
+endif
+
+if ($strip_sgml) then
+  set pass1_text = (${pass1_text} -G)
+  set pass2_text = (${pass2_text} -G)
+  set pass3_invf = (${pass3_invf} -G)
+  set pass4_invf = (${pass4_invf} -G)
+endif
+
+if ($?trace) then
+  set pass1_text = (${pass1_text} -t ${trace})
+  set pass2_text = (${pass2_text} -t ${trace})
+  set pass3_invf = (${pass3_invf} -t ${trace})
+  set pass4_invf = (${pass4_invf} -t ${trace})
+endif
+
+if ($?trace_name) then
+  set pass1_text = (${pass1_text} -n ${trace_name})
+  set pass2_text = (${pass2_text} -n ${trace_name})
+  set pass3_invf = (${pass3_invf} -n ${trace_name})
+  set pass4_invf = (${pass4_invf} -n ${trace_name})
+endif
+
+if ($buf_size) then
+  set pass1_text = (${pass1_text} -b ${buf_size})
+  set pass2_text = (${pass2_text} -b ${buf_size})
+  set pass3_invf = (${pass3_invf} -b ${buf_size})
+  set pass4_invf = (${pass4_invf} -b ${buf_size})
+endif
+  
+if ($?comp_stats) then
+  set pass2_text = (${pass2_text} -C ${comp_stats})
+endif
+
+echo "-----------------------------------"
+echo "`uname -n`, `date`"
+echo "${text} --> ${bname}"
+echo "-----------------------------------"
+
+# ************ init get ************
+
+if ($pipe) then
+  if ("$complex" != "") then
+    echo "$get $text -init"
+    $get $text -init
+    if ("$status" != "0") exit 1 
+    echo "-----------------------------------"
+  endif  
+endif
+
+# ************************************* T E X T **********************************
+
+# ************ pass 1_text ************
+
+if (${do_pass1}) then
+  if ($pipe) then
+    if ($?pass1filter) then
+      echo "$get $text $complex | $pass1filter | mg_passes ${pass1_text}"
+      $get $text $complex| $pass1filter | $bindir/mg_passes ${pass1_text}
+      if ("$status" != "0") exit 1 
+    else
+      echo "$get $text $complex | mg_passes ${pass1_text}"
+      $get $text $complex| $bindir/mg_passes ${pass1_text}
+      if ("$status" != "0") exit 1 
+    endif
+  else
+    echo mg_passes ${pass1_text} ${input_files}
+    $bindir/mg_passes ${pass1_text} ${input_files}
+    if ("$status" != "0") exit 1 
+  endif
+  echo "-----------------------------------"
+endif
+
+# ************ compression dict  ************
+if ($do_pass2) then 
+  echo "mg_compression_dict -f ${bname} ${mcd}"
+  $bindir/mg_compression_dict -f ${bname} ${mcd}
+  if ("$status" != "0") exit 1 
+  echo "-----------------------------------"
+endif
+
+# ************ pass 2_text ************
+if (${do_pass2}) then
+  if ($pipe) then
+    if ($?pass2filter) then
+      echo "$get $text $complex | $pass2filter | mg_passes ${pass2_text}"
+      $get $text $complex| $pass2filter | $bindir/mg_passes ${pass2_text}
+      if ("$status" != "0") exit 1 
+    else
+      echo "$get $text $complex | mg_passes ${pass2_text}"
+      $get $text $complex| $bindir/mg_passes ${pass2_text}
+      if ("$status" != "0") exit 1 
+    endif
+  else
+    echo mg_passes ${pass2_text} ${input_files}
+    $bindir/mg_passes ${pass2_text} ${input_files}
+    if ("$status" != "0") exit 1 
+  endif
+  echo "-----------------------------------"
+endif
+
+# ************************************* I N V F **********************************
+
+# ************ pass 3_invf ************
+if (${do_pass3}) then
+  if ($pipe) then
+    if ($?pass3filter) then
+      echo "$get $text $complex | $pass3filter | mg_passes ${pass3_invf}"
+      $get $text $complex| $pass3filter | $bindir/mg_passes ${pass3_invf}
+      if ("$status" != "0") exit 1 
+    else
+      echo "$get $text $complex | mg_passes ${pass3_invf}"
+      $get $text $complex| $bindir/mg_passes ${pass3_invf}
+      if ("$status" != "0") exit 1 
+    endif
+  else
+    echo mg_passes ${pass3_invf} ${input_files}
+    $bindir/mg_passes ${pass3_invf} ${input_files}
+    if ("$status" != "0") exit 1 
+  endif
+  echo "-----------------------------------"
+endif
+
+# ************ perfect hash  ************
+if ($do_pass4) then
+  echo "mg_perf_hash_build -f ${bname}"
+  $bindir/mg_perf_hash_build -f ${bname}
+  if ("$status" != "0") exit 1 
+
+  echo "-----------------------------------"
+endif
+
+# ************ pass 4_invf ************
+if (${do_pass4}) then
+  if ($pipe) then
+    if ($?pass4filter) then
+      echo "$get $text $complex | $pass4filter | mg_passes ${pass4_invf}"
+      $get $text $complex| $pass4filter | $bindir/mg_passes ${pass4_invf}
+      if ("$status" != "0") exit 1 
+    else
+      echo "$get $text $complex | mg_passes ${pass4_invf}"
+      $get $text $complex| $bindir/mg_passes ${pass4_invf}
+      if ("$status" != "0") exit 1 
+    endif
+  else
+    echo mg_passes ${pass4_invf} ${input_files}
+    $bindir/mg_passes ${pass4_invf} ${input_files}
+    if ("$status" != "0") exit 1 
+  endif
+  echo "-----------------------------------"
+endif
+
+
+# ************ build invf dictionary ************
+
+if ($do_pass4) then
+  echo "mg_invf_dict -f ${bname} -b 4096"
+  $bindir/mg_invf_dict -f ${bname} -b 4096
+  if ("$status" != "0") exit 1 
+  echo "-----------------------------------"
+endif
+
+# ******** build indexes to stem dict *********
+
+# [RPAP - Jan 97: Stem Index Change]
+if ($do_pass4 && "$do_indexes" == "1") then
+  echo "mg_stem_idx -f ${bname} -b 4096 -s1"
+  $bindir/mg_stem_idx -f ${bname} -b 4096 -s1
+  if ("$status" != "0") exit 1 
+
+  echo ""
+
+  echo "mg_stem_idx -f ${bname} -b 4096 -s2"
+  $bindir/mg_stem_idx -f ${bname} -b 4096 -s2
+  if ("$status" != "0") exit 1 
+
+  echo ""
+
+  echo "mg_stem_idx -f ${bname} -b 4096 -s3"
+  $bindir/mg_stem_idx -f ${bname} -b 4096 -s3
+  if ("$status" != "0") exit 1 
+
+  echo "-----------------------------------"
+endif
+
+# ************ build weights ************
+
+if ($do_pass4 && $do_weights) then
+  echo "mg_weights_build -f ${bname} -b ${weight_bits} "
+  $bindir/mg_weights_build -f ${bname} -b ${weight_bits}
+  if ("$status" != "0") exit 1 
+  echo "-----------------------------------"
+endif
+
+# *******************************************************************************
+
+
+# ************ print out statistics ************
+if ($do_pass1 && $do_pass2 && $do_pass3 && $do_pass4) then
+  echo "mgstat -f ${bname} -E"
+  $bindir/mgstat -f ${bname} -E
+  if ("$status" != "0") exit 1 
+endif
+
+
+# ************ cleanup get ************
+
+if ($pipe) then
+  if ("$complex" != "") then
+    echo "-----------------------------------"
+    echo "$get $text -cleanup"
+    $get $text -cleanup
+    if ("$status" != "0") exit 1 
+  endif
+endif
+
+echo "-----------------------------------"
+echo "`uname -n`, `date`"
+echo "-----------------------------------"
+
+if ($do_pass2) then
+  echo "-- The fast-loading compression dictionary has not been built."
+  echo "-- If you wish to build it, execute the following command:"
+  echo "-- "$bindir/mg_fast_comp_dict -f ${bname}
+
+  echo "-----------------------------------"
+endif
+
+echo ""
+
Index: /main/tags/2.25/gsdl/packages/mg/src/scripts/mgmerge.1
===================================================================
--- /main/tags/2.25/gsdl/packages/mg/src/scripts/mgmerge.1	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/mg/src/scripts/mgmerge.1	(revision 21064)
@@ -0,0 +1,175 @@
+`.\"------------------------------------------------------------
+.\" Id - set Rv,revision, and Dt, Date using rcs-Id tag.
+.de Id
+.ds Rv \\$3
+.ds Dt \\$4
+..
+.Id $Id$
+.\"------------------------------------------------------------
+.TH mgmerge 1 \*(Dt CITRI
+.SH NAME
+mgmerge \- update an mg system database with new documents
+.SH SYNOPSIS
+.B mgmerge
+[
+.B \-c
+]
+[
+.BI \-g " get"
+]
+[
+.BI \-s " source"
+]
+[
+.B \-S
+]
+[
+.B \-w
+]
+.I collection-name
+.SH DESCRIPTION
+.B mgmerge
+is a
+.B csh
+script that executes all the appropriate programs in the correct order
+to completely merge a current
+.BR mg (1)
+system database ready with some new documents, saving the need for a complete
+database rebuild with
+.B mgbuild.
+It does this by building a second
+.BR mg (1)
+system database from the new documents and then merging this database
+with the old one.
+This program makes use of the
+.BR mg_get_merge (1)
+script to obtain the text of the collection.
+.B mgmerge
+cannot edit or delete documents already in a database; only new documents
+can be added.
+.SH OPTIONS
+Options can occur in any order, but the collection name must be last.
+.TP "\w'\fIcollection-name\fP'u+2n"
+.BI \-c
+This specifies whether the
+.I get
+program is \*(lqcomplex\*(rq.  If a
+.I get
+program is \*(lqcomplex\*(rq, then it requires initialisation and
+cleanup with the
+.B \-i
+and
+.B \-c
+options.
+.TP
+.BI \-g " get"
+This specifies the program to use for getting the source text for the
+build.  If no
+.B \-g
+option is given, the default program
+.BR mg_get_merge (1)
+is used.
+.TP
+.BI \-s " source"
+The
+.B mgmerge
+program consists of two parts.  The first part initializes variables
+to default values.  The second part uses these variables to control
+how the
+.BR mg (1)
+database is built.  This option specifies a program to execute between
+the first and second parts.  The details of what the variables are, and
+how they may be changed, are in comments in the
+.B mgmerge
+program.
+If this option is used, the program should ideally be the same one that
+was called by
+.BR mgbuild (1)
+to build the database since some parameters need to be consistent between
+.B mgbuild
+and
+.B mgmerge.
+.TP
+.B \-S
+This option will cause a slow merge to be performed on the inverted files,
+where each inverted file entry is decoded and recoded.
+The default is a fast merge. Accumulated fast merges slowly degrade
+compression performance on the resulting inverted file so
+a periodic slow merge is recommended.
+.TP
+.B \-w
+Adding new documents can have an effect on the weight of the previous ones.
+By default the weights for documents already in the collection are not 
+recomputed since the change in their values is usually small.
+This option forces new weights to be recomputed.
+Periodic use of this option, as for the "-S" option, is recomended,
+otherwise query rankings may become inaccurate.
+.TP
+.I collection-name
+This is the collection name, as required by the
+.BR mg_get_merge (1)
+program.  It serves both as a
+.I case
+statement selector, and as the name of a subdirectory that holds the
+indexing files.
+.SH ENVIRONMENT
+.TP "\w'\fBMGDATA\fP'u+2n"
+.SB MGDATA
+If this environment variable exists, then its value is used as the
+default directory where the
+.BR mg (1)
+collection files are.  If this variable does not exist, then the
+directory \*(lq\fB.\fP\*(rq is used by default.  The command line
+option
+.BI \-d " directory"
+overrides the directory in
+.BR MGDATA .
+Note that a temporary directory under the
+.B MGDATA
+directory is used to perform the merge.
+The default name for this directory is
+.BR MERGE .
+.SH FILES
+.TP 20
+.B *.invf
+Inverted file.
+.TP
+.B *.invf.dict
+Compressed stemmed dictionary.
+.TP
+.B *.invf.dict.blocked
+The `on-disk' stemmed dictionary.
+.TP
+.B *.invf.idx
+The index into the inverted file.
+.TP
+.B *.weight
+The exact weights file.
+.TP
+.B *.text
+Compressed documents.
+.TP
+.B *.text.stats
+Text statistics.
+.TP
+.B *.text.dict
+Compressed compression dictionary.
+.TP
+.B *.text.idx
+Index into the compressed documents.
+.TP
+.B *.text.idx.wgt
+Interleaved index into the compressed documents and document weights.
+.TP
+.B *.weight.approx
+Approximate document weights.
+.SH "SEE ALSO"
+.na
+.BR mg (1),
+.BR mgbuild (1),
+.BR mg_get_merge (1),
+.BR mg_get (1),
+.BR mg_invf_merge (1),
+.BR mg_text_merge (1),
+.BR mg_query (1),
+.BR mg_weights_build (1).
Index: /main/tags/2.25/gsdl/packages/mg/src/scripts/mgmerge.sh
===================================================================
--- /main/tags/2.25/gsdl/packages/mg/src/scripts/mgmerge.sh	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/mg/src/scripts/mgmerge.sh	(revision 21064)
@@ -0,0 +1,417 @@
+#!/bin/csh -f
+###########################################################################
+#
+# mgmerge.sh -- Script used to build mg text collection.
+# Copyright (C) 1994  Neil Sharman, Shane Hudson (mods. for merging)
+#
+# 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.
+#
+#
+###########################################################################
+
+set complex = ""
+set slow_merge = ""
+set guess_weights = "-w "
+# [RPAP - Feb 97: Level 3 Merge]
+set text_pass = 1
+
+# Parse the command line arguments
+while ($#argv >= 1)
+  if ("$1" == "-s") then
+    shift
+    if ($#argv >= 1) then
+      set source = $1
+      shift
+    endif
+  else if ("$1" == "-g") then
+    shift
+    if ($#argv >= 1) then
+      set get = $1
+      shift
+    endif
+  else if ("$1" == "-c") then
+    set complex = "-text"
+    shift
+  else if ("$1" == "-S") then
+# set slow merge option in mg_invf_merge
+    set slow_merge = "-s "
+    shift
+  else if ("$1" == "-w") then
+# turn weights guessing off (rebuild weights file from scratch)
+    set guess_weights = ""
+    shift
+
+# [RPAP - Feb 97: Level 3 Merge]
+  else if ("$1" == "-T") then
+# turn text pass off
+    set text_pass = 0
+    shift
+
+  else
+    if ($?text == "0") then
+      set text = $1
+    endif
+    shift
+  endif
+    
+end
+
+if ($?text == "0") then
+  set prog = $0
+  echo "USAGE:"
+  echo "     "$prog:t" [-s config-script] [-g get-program] [-c] source"
+  echo ""
+  echo " The config-script is only needed if a non-standard build is required."
+  echo " The get-program defaults to mg_get if not specified."
+  exit 1	
+endif
+
+set bindir = $0
+set bindir = $bindir:h
+
+# if $pipe == 1 then pipe in the source text using $get and $text otherwise
+# read the source text directly from the file names specified in $input_files
+set pipe = 1
+
+if ($?get == "0") then
+  set complex = "-text"
+  set get = $bindir/mg_get_merge
+endif
+
+if (-e $MGDATA/${text}.chunks) then
+  set input_files = `cat $MGDATA/${text}.chunks`
+endif
+
+# Set the inversion method this may be either "I" or "N"
+# N is memory-efficient, I is faster for small collections
+set invf_method = N
+
+
+# Set the stemming method
+#   Bit 0 = case folding
+#   Bit 1 = S stemmer
+set stem_method = 3
+
+
+# [RPAP - Jan 97: Stem Index Change]
+# If do_indexes == 1 then build collection with full indexes to blocked file
+# overriding stem_method (stem_method will be set to 0)
+# Otherwise don't build with indexes
+set do_indexes = 0
+
+
+# $invf_mem specifies the amount of memory to use for the pass2 inversion
+# This only has an effect if $invf_method is "N".
+set invf_mem = 32
+
+
+# $num_chunks specifies the number of interium chunks of inverted file that
+# may be written to disc before a merge into the invf file is done
+# This only has an effect if $invf_method is "N".
+set num_chunks = 3
+
+# $invf_level specifies the level of the inverted file that will be generated.
+# Note: The value *MUST* be the same as was used to build the collection
+# that is being merged.
+# In the current mg_invf_merge implementation the maximum level is 2. 
+# Paragraph-level inversion (invf_level = 3) is NOT supported.
+set invf_level = 2
+
+
+# If $strip_sgml == 1 then sgml tags are stripped from the inversion phase.
+# Otherwise sgml tags are kepted.
+set strip_sgml = 1
+
+
+# $trace specifies the interval between trace entries in Mb.
+# If this is not set no trace entries will be generated.
+set trace = 10
+
+
+# $weight_bits specifies the number of bits of precision bo be given to the 
+# approximate weights.
+set weight_bits = 6
+
+
+# $mcd specifies the commandline arguments for the mg_compression_dict program
+set mcd = -S
+
+# $merge_name is the name of the subdirectory under ${MGDATA} where
+# the mergeing steps will be performed. There should NOT be an mg
+# collection with this name! The default is "MERGE"
+set merge = "MERGE"
+
+# Source the parameter file to modify parameters of the build.
+if ($?source) then
+  source ${source}
+endif
+
+
+# [RPAP - Jan 97: Stem Index Change]
+# If do_indexes == 1 then set stem_method = 0
+if ($do_indexes) then
+  set stem_method = 0
+endif
+
+
+# Generate the collection name.
+set coll_name = ${text}
+
+# Generate the directory where merging will take place
+if (-e $MGDATA/${merge}) then
+else
+  mkdir $MGDATA/${merge}
+endif
+
+# Generate the base name for the collection.
+# [RPAP - Feb 97: Level 3 Merge]
+set bname = ${coll_name}
+
+# generate the old, new and merge names in the $merge directory
+set oldname = ${merge}/${coll_name}.old
+set newname = ${merge}/${coll_name}.new
+set mergename = ${merge}/${coll_name}
+
+# build up the command lines for pass 1 and 2 to build a
+# dummy collection for the new documents
+set pass1 = (-f ${newname} -${invf_level} -m ${invf_mem} -s ${stem_method})
+set pass2 = (-f ${newname} -${invf_level} -c ${num_chunks})
+
+if ($strip_sgml) then
+  set pass1 = (${pass1} -G)
+  set pass2 = (${pass2} -G)
+endif
+
+if ($?trace) then
+  set pass1 = (${pass1} -t ${trace})
+  set pass2 = (${pass2} -t ${trace})
+endif
+
+# Note that a -T1 pass isnt done since the old .text.stats file is used
+# as the compression model for compressing the new documents.
+
+# [RPAP - Feb 97: Level 3 Merge]
+# Do not perform -T2 pass if text_pass == 0
+if ($text_pass) then
+  set pass2 = (${pass2} -T2)
+endif
+
+set pass1 = (${pass1} -${invf_method}1)
+set pass2 = (${pass2} -${invf_method}2)
+
+
+if ($?trace_name) then
+  set pass1 = (${pass1} -n ${trace_name})
+  set pass2 = (${pass2} -n ${trace_name})
+endif
+  
+if ($?comp_stats) then
+  set pass2 = (${pass2} -C ${comp_stats})
+endif
+
+########################################################################
+# Here is where mgmerge goes to work.
+
+echo "--------------------------------------------------------------"
+echo "`uname -n`, `date`"
+echo "MGMERGE collection: ${bname}"
+echo "--------------------------------------------------------------"
+echo "FIRST PHASE: build new collection from new documents"
+echo "--------------------------------------------------------------"
+
+# move and rename the text dictionary file
+# [RPAP - Feb 97: Level 3 Merge] - only if performing text pass
+if ($text_pass) then
+  mv $MGDATA/${bname}.text.dict $MGDATA/${newname}.text.dict
+endif
+
+if ($pipe) then
+  if ("$complex" != "") then
+    echo ">> $get $text -init"
+    $get $text -init
+    if ("$status" != "0") exit 1 
+    echo "-----------------------------------"
+  endif  
+endif
+
+if ($pipe) then
+  if ($?pass1filter) then
+    echo ">> $get $text $complex | $pass1filter | mg_passes ${pass1}"
+    $get $text $complex| $pass1filter | $bindir/mg_passes ${pass1}
+    if ("$status" != "0") exit 1 
+  else
+    echo ">> $get $text $complex | mg_passes ${pass1}"
+    $get $text $complex| $bindir/mg_passes ${pass1}
+    if ("$status" != "0") exit 1 
+  endif
+else
+  echo ">> mg_passes ${pass1} ${input_files}"
+  $bindir/mg_passes ${pass1} ${input_files}
+  if ("$status" != "0") exit 1 
+endif
+echo "-----------------------------------"
+
+echo "mg_perf_hash_build -f ${newname}"
+$bindir/mg_perf_hash_build -f ${newname}
+if ("$status" != "0") exit 1 
+echo "-----------------------------------"
+
+if ($pipe) then
+  if ($?pass2filter) then
+    echo ">> $get $text $complex | $pass2filter | mg_passes ${pass2}"
+    $get $text $complex | $pass2filter | $bindir/mg_passes ${pass2}
+    if ("$status" != "0") exit 1 
+  else
+    echo ">> $get $text $complex | mg_passes ${pass2}"
+    $get $text $complex | $bindir/mg_passes ${pass2}
+    if ("$status" != "0") exit 1 
+  endif
+else
+  echo ">> mg_passes ${pass2} ${input_files}"
+  $bindir/mg_passes ${pass2} ${input_files}
+  if ("$status" != "0") exit 1 
+endif
+echo "-----------------------------------"
+
+if ($pipe) then
+  if ("$complex" != "") then
+    echo "-----------------------------------"
+    echo ">> $get $text -cleanup"
+    $get $text -cleanup
+    if ("$status" != "0") exit 1 
+  endif
+endif
+
+echo "---------------------------------------"
+date
+echo "--------------------------------------------------------------"
+echo "SECOND PHASE: merge the two collections"
+echo "--------------------------------------------------------------"
+
+# move the appropriate files from the base directory to the merge dir
+echo "(moving files....)"
+# [RPAP - Feb 97: Level 3 Merge]
+# Move files if doing text pass
+if ($text_pass) then
+  mv $MGDATA/${bname}.text       $MGDATA/${oldname}.text
+  mv $MGDATA/${bname}.text.idx   $MGDATA/${oldname}.text.idx
+else
+# Need this file if building weights
+  cp -d $MGDATA/${bname}.text.idx   $MGDATA/${mergename}.text.idx
+endif
+mv $MGDATA/${bname}.invf       $MGDATA/${oldname}.invf
+mv $MGDATA/${bname}.invf.idx   $MGDATA/${oldname}.invf.idx
+mv $MGDATA/${bname}.invf.dict  $MGDATA/${oldname}.invf.dict
+# the old weight file may be used for the new file
+mv $MGDATA/${bname}.weight     $MGDATA/${mergename}.weight
+# EOC: the old invf.paragraph file may be used for the new file for Level 3 Invf
+if (-e $MGDATA/${bname}.invf.paragraph) then
+  mv $MGDATA/${bname}.invf.paragraph  $MGDATA/${mergename}.invf.paragraph
+endif
+echo "---------------------------------------"
+
+# [RPAP - Feb 97: Level 3 Merge]
+# Only merge text if doing text pass
+if ($text_pass) then
+  echo ">> mg_text_merge -f ${mergename}"
+  $bindir/mg_text_merge -f $mergename
+  echo "---------------------------------------"
+endif
+
+echo ">> mg_invf_merge ${slow_merge}${guess_weights} -f ${mergename}"
+$bindir/mg_invf_merge ${slow_merge}${guess_weights} -f ${mergename}
+echo "---------------------------------------"
+
+#remove .weight file, so a new one will be created by mg_weights_build
+if ("$guess_weights" == "") then
+  echo "rm ${mergename}.weight"
+  rm $MGDATA/${mergename}.weight
+endif
+
+# mv $MGDATA/${mergename}.weight $MGDATA/${mergename}.w2
+
+echo ">> mg_weights_build -f ${mergename} -b ${weight_bits}"
+$bindir/mg_weights_build -f ${mergename} -b ${weight_bits}
+if ("$status" != "0") exit 1 
+
+echo "---------------------------------------"
+
+echo ">> mg_invf_dict -f ${mergename} -b 4096"
+$bindir/mg_invf_dict -f ${mergename} -b 4096
+
+# [RPAP - Jan 97: Stem Index Change]
+if ($do_indexes) then
+  echo "-----------------------------------"
+
+  echo "mg_stem_idx -f ${mergename} -b 4096 -s1"
+  $bindir/mg_stem_idx -f ${mergename} -b 4096 -s1
+  if ("$status" != "0") exit 1 
+
+  echo ""
+
+  echo "mg_stem_idx -f ${mergename} -b 4096 -s2"
+  $bindir/mg_stem_idx -f ${mergename} -b 4096 -s2
+  if ("$status" != "0") exit 1 
+
+  echo ""
+
+  echo "mg_stem_idx -f ${mergename} -b 4096 -s3"
+  $bindir/mg_stem_idx -f ${mergename} -b 4096 -s3
+  if ("$status" != "0") exit 1 
+endif
+
+echo "--------------------------------------------------------------"
+
+# move files back to base dir
+# [RPAP - Feb 97: Level 3 Merge]
+# mv the text files if doing text pass
+if ($text_pass) then
+  mv $MGDATA/${oldname}.text         $MGDATA/${bname}.text
+  mv $MGDATA/${mergename}.text.idx   $MGDATA/${bname}.text.idx
+  mv $MGDATA/${newname}.text.dict    $MGDATA/${bname}.text.dict
+endif
+mv $MGDATA/${mergename}.invf       $MGDATA/${bname}.invf
+mv $MGDATA/${mergename}.invf.idx   $MGDATA/${bname}.invf.idx
+mv $MGDATA/${mergename}.invf.dict  $MGDATA/${bname}.invf.dict
+mv $MGDATA/${mergename}.invf.dict.blocked  $MGDATA/${bname}.invf.dict.blocked
+
+# [RPAP - Jan 97: Stem Index Change]
+if ($do_indexes) then
+  mv $MGDATA/${mergename}.invf.dict.blocked.1 $MGDATA/${bname}.invf.dict.blocked.1
+  mv $MGDATA/${mergename}.invf.dict.blocked.2 $MGDATA/${bname}.invf.dict.blocked.2
+  mv $MGDATA/${mergename}.invf.dict.blocked.3 $MGDATA/${bname}.invf.dict.blocked.3
+endif
+
+mv $MGDATA/${mergename}.weight     $MGDATA/${bname}.weight
+mv $MGDATA/${mergename}.weight.approx $MGDATA/${bname}.weight.approx
+mv $MGDATA/${mergename}.text.idx.wgt $MGDATA/${bname}.text.idx.wgt
+
+# EOC: mv .invf.paragraph file if exists
+if (-e $MGDATA/${mergename}.invf.paragraph) then
+  mv $MGDATA/${mergename}.invf.paragraph   $MGDATA/${bname}.invf.paragraph
+endif
+
+# remove old files in the MERGE directory
+rm -f $MGDATA/${merge}/*
+
+echo "mgstat -f ${bname} -E"
+$bindir/mgstat -f ${bname} -E
+if ("$status" != "0") exit 1 
+
+echo "--------------------------------------------------------------"
+echo "`uname -n`, `date`"
+echo "--------------------------------------------------------------"
+
+echo ""
Index: /main/tags/2.25/gsdl/packages/mg/src/scripts/xmg.1
===================================================================
--- /main/tags/2.25/gsdl/packages/mg/src/scripts/xmg.1	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/mg/src/scripts/xmg.1	(revision 21064)
@@ -0,0 +1,130 @@
+.\"------------------------------------------------------------
+.\" Id - set Rv,revision, and Dt, Date using rcs-Id tag.
+.de Id
+.ds Rv \\$3
+.ds Dt \\$4
+..
+.Id $Id$
+.\"------------------------------------------------------------
+.TH xmg 1 \*(Dt CITRI
+.SH NAME
+xmg \- An X interface to mgquery
+.SH SYNOPSIS
+.B xmg
+[
+.I collection-name
+]
+.SH DESCRIPTION
+.B xmg
+is an X interface to the
+.BR mg (1)
+information retrieval system.
+.PP
+Type a query in the ``Query'' box.  The escape key clears the query text.
+.PP
+The first line or so of each matching document is listed.
+.PP
+Click on any line to show the complete document.
+.PP
+Shift-click to show the document in a new window.
+.PP
+Press
+.I Next
+and
+.I Previous
+to cycle through the list of documents (shift works here too).
+.PP
+If you change the query, existing windows continue to refer to the
+original query.
+.PP
+You can select either Boolean or ranked queries:
+.RS
+.TP "\w'\fIBoolean queries:\fP'u+2n"
+.I "Boolean queries:"
+use ``&'' for AND, ``|'' for OR, ``!'' for NOT, and parentheses for
+grouping.
+.TP
+.I "Ranked queries:"
+Documents are listed in order of relevance.  A weight is shown
+alongside each.  Weights are normalized to 100 for the most relevant
+document.  Choose
+.I "Approximate Ranking"
+for greater retrieval speed.
+.RE
+.PP
+In document windows (other than the main window):
+.RS
+.br
+Typing `n' = next document;
+.br
+Typing `N' = next document in new window;
+.br
+Typing `p' = previous document;
+.br
+Typing `P' = previous document in new window;
+.br
+Typing `q' = close window.
+.RE
+.SH ENVIRONMENT
+.TP "\w'\fBMGDATA\fP'u+2n"
+.SB MGDATA
+If this environment variable exists, then its value is used as the
+default directory where the
+.BR mg (1)
+collection files are.  If this variable does not exist, then the
+directory \*(lq\fB.\fP\*(rq is used by default.  The command line
+option
+.BI \-d " directory"
+overrides the directory in
+.BR MGDATA .
+.TP
+.SB Xdefaults
+To override the default font options, use RESOURCE_MANAGER properties
+like the following in your
+.I .Xdefaults
+file:
+.IP
+.RS
+.nf
+.I "xmg.textfont: fixed"
+.I "xmg.buttonfont: fixed"
+.fi
+.RE
+.IP
+To override the default query type of ranked, use
+.IP
+.RS
+.I "xmg.querytype: boolean"
+.RE
+.IP
+To override the default collection name (the first one listed by
+.BR ls (1)
+from your MGDATA environment variable), use
+.IP
+.RS
+.I "xmg.collection: mail93"
+.RE
+.SH "SEE ALSO"
+.na
+.BR ls (1),
+.BR mg (1),
+.BR mg_compression_dict (1),
+.BR mg_fast_comp_dict (1),
+.BR mg_get (1),
+.BR mg_invf_dict (1),
+.BR mg_invf_dump (1),
+.BR mg_invf_rebuild (1),
+.BR mg_passes (1),
+.BR mg_perf_hash_build (1),
+.BR mg_text_estimate (1),
+.BR mg_weights_build (1),
+.BR mgbilevel (1),
+.BR mgbuild (1),
+.BR mgdictlist (1),
+.BR mgfelics (1),
+.BR mgquery (1),
+.BR mgtic (1),
+.BR mgticbuild (1),
+.BR mgticdump (1),
+.BR mgticprune (1),
+.BR mgticstat (1).
Index: /main/tags/2.25/gsdl/packages/mg/src/scripts/xmg.sh
===================================================================
--- /main/tags/2.25/gsdl/packages/mg/src/scripts/xmg.sh	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/mg/src/scripts/xmg.sh	(revision 21064)
@@ -0,0 +1,1376 @@
+#!/usr/local/bin/wish -f
+# Edit the line above to point to your version of wish
+#
+###############################################################################
+#
+# xmg -- X interface to the mg information retrieval system
+# Copyright (C) 1994  Bruce McKenzie, Ian Witten and Craig Nevill-Manning
+#
+# 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.
+#
+#       @(#)xmg.sh	1.4 25 Mar 1994
+#
+###############################################################################
+#
+# "xmg" is an X interface to the mg information retrieval system.
+#
+# Type a query in the "Query" box.
+# The first line or so of each matching document is listed.
+# Click on any line to show the complete document.
+# Shift-click to show the document in a new window.
+# Press Next and Previous to cycle through the list of documents (Shift works
+#   here too). 
+# If you change the query, existing windows continue to refer to the original
+#   query. 
+# 
+# You can select either Boolean or Ranked queries.
+# Boolean queries: use "&" for AND, "|" for OR, "!" for NOT, and parentheses
+# for grouping 
+# Ranked queries:  - documents are listed in order of relevance; a weight is
+# 		     shown alongside each 
+#                  - weights are normalized to 100 for the most relevant
+#		     document 
+#                  - choose Approximate Ranking for greater retrieval speed. 
+# 
+# In document windows (other than the main window): 
+#		Typing 'n' = next document
+#		Typing 'N' = next document in new window
+#		Typing 'p' = previous document
+#		Typing 'P' = previous document in new window
+#		Typing 'q' = close window
+#
+###############################################################################
+
+# Date: 13 March 1994
+# Authors: Bruce McKenzie, Ian Witten and Craig Nevill-Manning
+
+###############################################################################
+# Customizing xmg
+###############################################################################
+
+# To override the default font options, use RESOURCE_MANAGER properties like
+# the following in your .Xdefaults file
+#
+#	xmg.textfont: fixed
+#	xmg.buttonfont: fixed
+#
+# To override the default query type of ranked, use
+#
+#	xmg.querytype: boolean
+#
+# To override the default collection name (the first one listed by /bin/ls from
+# your MGDATA environment variable), use
+#
+#	xmg.collection: mail93
+
+###############################################################################
+# Global variables
+###############################################################################
+
+#   genuine constants:
+#
+#	env		the environment variables
+#	Terminator	terminator for mgquery
+#	MaxWindowHeight	the maximum height permitted for a document window
+#	ListBoxLength	the number of items in the document list
+#	HeadLength	the length document head displayed in the list box
+#	ImageString	the string at the start of a document associated
+#			with an image
+#
+#   things that rarely get changed:
+#
+#	querytype	the current query type (boolean, ranked, approx-ranked)
+#	booleanquery	says whether the query is boolean or ranked
+#	approxquery	says whether ranking is to be approximate or not
+#	collection	the name of the document collection being used
+#	fileId		file identifer for a pipe to the mgquery process
+#       errorOccurred	flag to say that there has been an I/O error on the
+#			current collection
+#
+#   things that reflect items in the main panel
+#
+#	query		the current query
+#	hits		number of hits for the current query
+#	display		shell command to display the image associated with
+#			the last document retrieved
+#	scrolledto	document prefixes have been obtained for all documents
+#			up to this position in the document list
+#
+#   static variable needed in just one procedure
+#
+#	top_rank	weight associated with the first document retrieved
+#	windowname	unique id for each document window
+
+###############################################################################
+# High-level procedures
+###############################################################################
+
+proc SaveDocument {w} {
+  set file [FSBox "Save document to file:"]
+
+  if {$file != ""} {
+    if [file exists $file] {
+      toplevel .r
+      wm title .r "\n"
+      .r configure -borderwidth 2 -relief raised 
+      focus .r
+      label .r.message -text "The file already exists"
+      button .r.replace -text "Replace" -width 10 -height 2 \
+          -command "destroy .r; WriteDocument $file \"w\" $w" 
+      button .r.append -text "Append" -width 10 -height 2 \
+          -command "destroy .r; WriteDocument $file \"a\" $w"
+      button .r.cancel -text "Cancel" -command {destroy .r} -width 10 -height 2
+      pack .r.message -side top -pady 10 -padx 20
+      pack .r.replace .r.append .r.cancel -side left -pady 10 -padx 20
+
+    } else {
+       WriteDocument $file "w" $w
+    }
+  }
+}
+
+proc Dialog {text command} {
+      if {![winfo exists .r] } { toplevel .r }
+      wm title .r "\n"
+      .r configure -borderwidth 2 -relief raised 
+      focus .r
+      label .r.message -text $text
+      button .r.ok -text "OK" -width 10 -height 2 \
+          -command "destroy .r $command"
+      pack .r.message -side top -pady 10 -padx 20
+      pack .r.ok -side bottom -pady 10 -padx 20
+}
+
+proc WriteDocument {file mode w} {
+    if {[catch {set f [open $file $mode]}] == 0} {
+        if [winfo exists $w] {
+            puts $f [$w get 0.0 end]
+        } else {
+            Dialog "Unable to save text" ""
+        }
+        flush $f
+        close $f
+    } else {
+        Dialog "Unable to open file for writing" "; SaveDocument $w"
+    }
+}
+
+# Send a query to mg and enter the response in the document list
+#
+proc sendQuery {window} {
+    global query hits querytype errorOccurred scrolledto
+
+    .m.t.q.retrieved.label configure -foreground Gray
+    .m.t.q.retrieved.hits configure -foreground Gray
+
+    sendto ".set query \"$querytype\""
+    sendto ".set mode \"docnums\""
+    foreach f "sdocnums sdocs srank" { $window.$f delete 0 end }
+    disableButton .m.d.buttons.previous
+    disableButton .m.d.buttons.next
+    if {[string index $query 0] == "." || [string length $query] > 255} {
+        set doclist ""
+    } else { set doclist [sendandget $query] }
+
+    if {$errorOccurred} {
+        enterText .m.d.text [mgqueryFailure]
+        .m.t.q.retrieved.label configure -foreground Black
+        .m.t.q.retrieved.hits configure -foreground Black 
+        update
+        return
+    }
+    sendto ".set query \"DocNums\""
+    sendto ".set mode  \"text\""
+    .m.t.q.retrieved.label configure -foreground Black
+    .m.t.q.retrieved.hits configure -foreground Black 
+    set hits [llength $doclist]
+    set i 0
+    global top_rank
+
+    scan [lindex $doclist 0] "%d %f %d" d rank size
+    set top_rank $rank
+    if {$top_rank == 0} {set top_rank 1}
+
+    while {$i < $hits} {
+	scan [lindex $doclist $i] "%d %f %d" d rank size
+        if {$rank == "Inf"} {set rank 1}
+	if {$querytype == "boolean"} {
+	    $window.srank insert end ""
+	} else {
+	    $window.srank insert end \
+		[format "%3.0f" [expr $rank / $top_rank * 99 + 1]]
+	}
+	$window.sdocnums insert end [format " %d" $d]
+	incr i
+    }
+
+    set scrolledto 0
+    scroll $window 0
+    bind $window.sdocs <ButtonRelease-1> \
+	"showDocument $window.sdocs %y .m.d \"$doclist\" \"$query\""
+    bind $window.sdocs <Shift-ButtonRelease-1> \
+	"showDocument $window.sdocs %y New \"$doclist\" \"$query\""
+    enterText .m.d.text ""
+}
+
+# Scrolling routine for the document list
+#
+proc scroll {window n} {
+    global hits scrolledto ListBoxLength Terminator fileId ImageString
+
+    $window.sdocnums yview $n
+    $window.sdocs yview $n
+    $window.srank yview $n
+    set last $n
+    if {$last <= 0} {set last 0}
+    incr last $ListBoxLength
+    if {$last > $hits} {set last $hits}
+
+#    .m config -cursor {watch}
+#    update
+    sendto ".set mode \"heads\""
+    sendto ".set terminator \"\""
+    while {$scrolledto < $last} {
+	if {[scan [$window.sdocnums get $scrolledto] "%d" d] == 1} {
+            sendto $d
+            gets $fileId line
+            set i [string first " " $line]
+            if {$i != -1} {set line [string range $line [expr $i + 1] end]}
+            if {[string compare $ImageString [string range $line 0 9]] == 0} {
+                set line [getImageDocumentHead $d]
+            }
+	    $window.sdocs insert $scrolledto $line
+	}
+	incr scrolledto
+    }
+    sendto ".set terminator \"$Terminator\\n\""
+    sendto ".set mode text"
+#   .m config -cursor {}
+}
+
+proc getImageDocumentHead {d} {
+    global HeadLength ImageString fileId
+
+    sendto ".set heads_length 1000"
+    sendto $d
+    gets $fileId line
+
+    set line [string range $line 11 end]
+
+    set s [string first $ImageString $line]
+    if {$s != -1} {
+        incr s 11
+        set line [string range $line $s [expr $s + $HeadLength]]
+    }
+  
+    sendto ".set heads_length $HeadLength"
+
+    return "* $line"
+}
+
+# Show document from the document list
+#
+proc showDocument {window y newWindow doclist query} {
+    showThisDocument [$window nearest $y] $doclist $newWindow $query
+}
+
+proc adjacentDocument {index doclist window q button} {
+    global ListBoxLength
+
+    showThisDocument $index $doclist $window $q
+
+    if {$window == ".m.d"} {
+      set first [.m.t.q.r.sdocs nearest 0]
+      if {$index < $first || $index >= $first + $ListBoxLength} {
+          scroll .m.t.q.r [expr $index - $ListBoxLength / 2]
+      }
+      .m.t.q.r.sdocs select from $index
+    } 
+}
+
+
+# Show document with this index in the document list
+#
+proc showThisDocument {index doclist window q} {
+    global collection MaxWindowHeight display windowname
+
+    set document ""
+    scan [lindex $doclist $index] "%d %f" document rank
+    if {$document == ""} { return }
+    set textlist [sendandget $document]
+	
+    if {[string length $display] != 0} { exec csh -c $display >& /dev/null & }
+	
+# throw away the first line
+    set text [join [lrange $textlist 1 end] "\n"]
+
+# if necessary, create a new window for this document
+    if {$window == "New"} {
+        .m.t.q.r.sdocs select clear
+	set window .m.document$windowname
+        incr windowname
+        set existing ""
+        set raised 0
+        foreach w [lrange [winfo children .m] 2 end] {
+           if {[lindex [$w.docnum configure -text] 4] == $index && \
+               [lindex [$w.query configure -text] 4] == $q} {
+              if {$raised} {
+                 closeDocumentWindow $w
+              } else {
+                  raise $w
+		  getFocus $w
+                  set window $w
+                  set raised 1
+              }
+           }
+        }
+  
+        if {!$raised} {
+   	    toplevel $window
+            $window configure -borderwidth 2 -relief raised
+            wm protocol $window WM_TAKE_FOCUS "getFocus $window"
+	    getFocus $window
+	    makeDocumentPanel $window
+            bind $window q "$window.buttons.close invoke"
+            label $window.docnum -text $index
+            label $window.query -text $q
+       }
+    }
+
+# configure the window for this document
+    set rows [expr [llength $textlist] - 1]
+    if {$window != ".m.d"} {
+	wm title $window "$collection \"$q\""
+	wm iconname $window "$document"
+	$window.text configure -height $rows
+	if {$rows > $MaxWindowHeight} {
+	    $window.text configure -height $MaxWindowHeight
+	}
+    }
+
+# show the document text in the window
+    enterText $window.text $text
+
+# configure the window's Previous and Next buttons
+    if {$index == 0} {
+        disableButton $window.buttons.previous
+    } else {
+	set newindex [expr $index-1]
+	bindBoth $window previous $newindex $doclist $q
+        bind $window p [bind $window.buttons.previous <1>]
+        bind $window P [bind $window.buttons.previous <Shift-1>]
+    }
+    if {$index == [expr [llength $doclist]-1]} {
+	disableButton $window.buttons.next 
+    } else {
+	set newindex [expr $index+1]
+	bindBoth $window next $newindex $doclist $q
+        bind $window n [bind $window.buttons.next <1>]
+        bind $window N [bind $window.buttons.next <Shift-1>]
+    }
+
+    if {$window != ".m.d"} { $window.docnum configure -text $index }
+
+    if {[string length $display] != 0} { 
+        set on "{
+            if \[winfo exists $window\] \{
+                 $window.buttons.image configure \
+                   -foreground Black
+                 update\}
+        }"
+        set off "{
+            if \[winfo exists $window\] \{
+                 $window.buttons.image configure \
+                   -foreground [lindex [.m.d configure -background] 4]
+                 update\}
+        }"
+        set t 0
+        while {$t < 5} {
+            after [expr $t * 1000] eval $on
+            after [expr $t * 1000 + 500] eval $off
+            incr t
+        }   
+    }
+}
+
+# Bind both Button-1 and Shift-Button-1 commands
+#
+proc bindBoth {window button index doclist query} {
+    $window.buttons.$button configure -state normal
+    bind $window.buttons.$button <Button-1> \
+	"adjacentDocument $index \"$doclist\" $window \"$query\" $button"
+    bind $window.buttons.$button <Shift-Button-1> \
+	"adjacentDocument $index \"$doclist\" New \"$query\" $button"
+}
+
+# Change the type of query
+#
+proc changeQuerytype {name element op} {
+    global querytype booleanquery approxquery
+
+    if {$booleanquery} {
+	.m.t.b.type.approx configure -state disabled
+	.m.t.q.retrieved.weight configure \
+             -foreground [lindex [.m configure -background] 4]
+	set querytype boolean
+    } else {
+	.m.t.b.type.approx configure -state normal
+	.m.t.q.retrieved.weight configure -foreground Black
+	if {$approxquery} {
+	    set querytype "approx-ranked"
+	} else {
+	    set querytype "ranked"
+	}
+    }
+}
+
+proc enterText {window text} {
+    $window configure -state normal
+    $window delete 0.0 end
+    $window insert 0.0 $text
+    $window configure -state disabled
+}
+
+###############################################################################
+# IO and initialization
+###############################################################################
+
+# Send a message to mg and return the reply
+#
+proc sendandget {message} {
+    global fileId Terminator display errorOccurred ImageString
+    set display ""
+
+    .m config -cursor {watch}
+    update idletasks
+    set reply ""
+    sendto "$message\n"
+    if {$message != "" && !$errorOccurred} {
+        gets $fileId line
+    	while {[string compare $Terminator $line] != 0} {
+            lappend reply $line;
+            gets $fileId line
+        }
+
+        if {[string compare $ImageString [lindex $reply 1]] == 0 } {
+          if {[string compare "MGDATA" [string range [lindex $reply 3] 0 5]] == 0} {
+             set display [string range [lindex $reply 3] 7 end];
+          }
+          set reply [lrange $reply 4 end]
+        }
+    }
+
+    .m config -cursor {}
+    return $reply
+}
+    
+# Send a message to mg
+#
+proc sendto {message} {
+    global fileId errorOccurred
+
+    puts $fileId $message
+    set errorOccurred [catch {flush $fileId}]
+}
+
+# Reinitialise mgquery to work with a new document collection
+#
+proc reInitMG {c} {
+    global fileId
+    catch {close $fileId}
+    initMG $c
+}
+
+# Initialize mgquery to work with a specified text collection
+#
+proc initMG {c} {
+    global query hits fileId collection Terminator env errorOccurred
+    global HeadLength
+
+    set collection $c
+    set query ""
+    set hits 0
+    set errorOccurred 0
+
+    foreach f "sdocs srank" { .m.t.q.r.$f delete 0 end }
+    enterText .m.d.text ""
+    .m.t.b.collect.m configure -text $collection
+    foreach w [winfo children .m] {
+	if {[string first ".m.document" $w] == 0} { closeDocumentWindow $w }
+    }
+
+    disableButton .m.d.buttons.previous 
+    disableButton .m.d.buttons.next
+
+    if {$c != ""} {
+        set f $env(MGDATA)/$c
+
+        if {[file exists $f] && [file readable $f]} {
+    	    set fileId [open "| mgquery $collection" RDWR]
+	    sendto ".set expert \"true\""
+	    sendto ".set terminator \"$Terminator\\n\""
+	    sendto ".set pager \"cat\""
+            sendto ".set heads_length $HeadLength"
+	    return
+        }
+    }
+    bind .m.t.q.e.entry <Return> {null}
+    enterText .m.d.text [initializationFailure]
+    update
+}
+
+# Routine to obtain values from RESOURCE_MANAGER
+#
+proc query_resource {option class default} {
+	set val [option get . $option $class]
+	if {[string length $val] == 0} { return $default }
+	return $val
+}
+
+
+proc disableButton {b} {
+    bind $b <Button-1> {null}
+    bind $b <Shift-Button-1> {null}
+    $b configure -state disabled
+}
+
+proc null {} {}
+
+###############################################################################
+# Setting up windows
+###############################################################################
+
+proc removeFromWindowList {window} {
+    global stacking
+
+    set i 0
+    while {$i < [llength $stacking]} {
+      if {$window == [lindex $stacking $i]} {
+         set stacking [lreplace $stacking $i $i]
+      }
+      incr i
+    }
+}
+
+proc getFocus {window} {
+    global stacking
+
+    focus $window
+    removeFromWindowList $window
+    set stacking [linsert $stacking 0 $window]
+}
+
+proc closeDocumentWindow {w} {
+   global stacking
+   removeFromWindowList $w
+   set t [lindex $stacking 0]
+
+   if {$t != ""} {
+     focus $t
+     raise $t
+  }
+  destroy $w
+}
+
+# Make a "document" panel, including Previous, Next, and Close buttons
+#
+proc makeDocumentPanel {window} {
+    frame $window.buttons
+    button $window.buttons.previous -text "Previous" -width 10 -state disabled
+    button $window.buttons.next -text "Next" -width 10 -state disabled
+    button $window.buttons.close -text "Close" -width 10 \
+	-command "closeDocumentWindow $window"
+    button $window.buttons.save -text "Save" -width 10 \
+        -command "SaveDocument $window.text"
+
+    label $window.buttons.image -text "Fetching image..." \
+            -foreground [lindex [$window configure -background] 4]
+    pack $window.buttons.previous $window.buttons.next -side left
+    pack $window.buttons.image -side left -padx 10
+    pack $window.buttons.close $window.buttons.save -side right 
+    pack $window.buttons -side top -fill x 
+
+    text $window.text -borderwidth 2 -relief raised \
+             -setgrid true -width 80 -state disabled
+
+    $window.text configure -yscrollcommand "$window.sy set" 
+    scrollbar $window.sy -relief flat -command "$window.text yview"
+    pack $window.sy -side right -fill y 
+    pack $window.text -side top -expand yes -fill both
+}
+
+# Make the "buttons" panel, with the query type and collection name
+#
+proc mkButtons {window} {
+    global collection booleanquery approxquery env
+    frame $window.type
+    label $window.type.label -text "Query type"
+
+    radiobutton $window.type.boolean -text "Boolean" -variable booleanquery \
+	  -value 1 -relief flat
+
+    radiobutton $window.type.ranked -text "Ranked" -variable booleanquery \
+	  -value 0 -relief flat
+
+    checkbutton $window.type.approx -text "Approximate" -variable approxquery \
+	  -relief flat
+
+    trace variable booleanquery w changeQuerytype
+    trace variable approxquery w changeQuerytype
+
+    pack $window.type.label   -side top -anchor w
+    pack $window.type.boolean -side top -anchor w -padx 12
+    pack $window.type.ranked  -side top -anchor w -padx 12
+    pack $window.type.approx  -side top -anchor w -padx 36
+
+    pack $window.type -side top -anchor w -pady 12
+
+    frame $window.collect
+    label $window.collect.label -text "Collection: "
+    pack $window.collect.label -side left -anchor w
+
+    getViewer
+
+    set dirs [getMGDATA]
+    set collection ""
+    if {$dirs != ""} { set collection [lindex $dirs 0] }
+   
+    menubutton $window.collect.m -menu $window.collect.m.menu \
+	-relief sunken
+    menu $window.collect.m.menu
+    foreach c $dirs {
+        if {[file readable $env(MGDATA)/$c] && 
+            [file isdirectory $env(MGDATA)/$c]} {
+    	    $window.collect.m.menu add command -label $c \
+	        -command "reInitMG $c"
+        }
+    }
+    pack $window.collect.m -side left
+    pack $window.collect -side bottom -anchor w
+
+
+}
+
+# Check that the MGDATA environment variable is set, and is non-null
+#
+proc getMGDATA {} {
+    global env
+
+    set MGDATA 0
+    foreach i [array names env] {
+	if {$i == "MGDATA"} {
+	    set dirs [exec /bin/ls $env(MGDATA)]
+	    if {[info exists dirs]} { return $dirs }
+	}
+    }
+
+    return ""
+}
+
+proc getViewer {} {
+    global env
+
+    set viewer 0
+    foreach i [array names env] {
+	if {$i == "MGIMAGEVIEWER"} {set viewer $env(MGIMAGEVIEWER)}
+    }
+
+    if {$viewer == 0} {set env(MGIMAGEVIEWER) "xloadimage -quiet -fit stdin"}
+}
+
+# Make the "query" panel, with the query and list of retrieved documents
+#
+proc mkQuery {window} {
+    global hits ListBoxLength
+
+# at the top of the "query" panel is the "entry" frame
+    frame $window.e
+    label $window.e.label -text "Query"
+    entry $window.e.entry -relief sunk -width 47 -textvariable query
+    pack $window.e.label -side left
+    pack $window.e.entry -side right -expand yes -fill x
+    focus default $window.e.entry
+    focus $window.e.entry
+
+    bind $window.e.entry <Control-Key> {null}
+    bind $window.e.entry <Return> "sendQuery $window.r"
+    bind $window.e.entry <Escape> { set query "" }
+    bind $window.e.entry <2> {
+	%W insert insert [selection get STRING]
+	tk_entrySeeCaret %W
+    }
+
+# next is the "retrieved" frame
+    frame $window.retrieved
+    label $window.retrieved.weight -text "Weight"
+    label $window.retrieved.label -text "   Documents retrieved: "
+    label $window.retrieved.hits -width 4 -relief sunk -textvariable hits
+    set documentsRetrieved 0
+    pack $window.retrieved.weight $window.retrieved.label \
+        $window.retrieved.hits -side left
+
+# next is the "results" frame (note that the docnums listbox doesn't appear on
+# the screen)
+    frame $window.r
+    scrollbar $window.r.sscroll -relief sunken -command "scroll $window.r"
+#    bind $window.r.sscroll <ButtonRelease-1> "updateSdocs $window.r.sdocs $window.r.sdocnums"
+    listbox $window.r.sdocnums
+    listbox $window.r.sdocs -relief sunken \
+            -setgrid 1 -geometry 50x$ListBoxLength
+    listbox $window.r.srank -yscroll "$window.r.sscroll set" \
+            -setgrid 1 -geometry 4x$ListBoxLength
+  
+    bind $window.r.srank <Any-1> {null}
+    bind $window.r.srank <Any-2> {null}
+    bind $window.r.srank <Any-3> {null}
+
+    bind $window.r.srank <Any-B1-Motion> {null}
+    bind $window.r.srank <Any-B2-Motion> {null}
+    bind $window.r.srank <Any-B3-Motion> {null}
+
+    bind $window.r.sdocs <Any-2> {null}
+    bind $window.r.sdocs <Any-B2-Motion> {null}
+
+    pack $window.r.sscroll -side right -fill y
+    pack $window.r.srank -side left 
+    pack $window.r.sdocs -side left -fill x -expand yes
+
+# pack them up
+    pack $window.e -side top -anchor e -pady 10 -fill x -expand yes
+    pack $window.retrieved -anchor w
+    pack $window.r -side bottom -anchor e -pady 10 -fill x -expand yes
+}
+
+# Make a "help" window
+#
+proc mkHelp {} {
+    if [winfo exists .help] { destroy .help }
+    toplevel .help
+    wm title .help "X interface to the mg information retrieval system"
+    wm iconname .help "About xmg"
+    frame .help.buttons
+    button .help.buttons.close -text Close -command "destroy .help" -width 10
+    button .help.buttons.help -text Help -width 10
+    button .help.buttons.conditions -text Conditions -width 10
+    button .help.buttons.warranty -text Warranty -width 10
+    button .help.buttons.bugs -text Bugs -width 10
+
+    frame .help.t
+    text .help.t.text -relief raised -bd 2 -setgrid true -height 24 -width 95
+    .help.t.text configure -yscrollcommand ".help.t.sy set" 
+    scrollbar .help.t.sy -relief flat -command ".help.t.text yview"
+    
+    pack .help.buttons.close .help.buttons.help -side right -fill x
+    pack .help.buttons.conditions .help.buttons.warranty \
+         .help.buttons.bugs -side left
+    pack .help.buttons -side bottom -fill x
+
+    pack .help.t.text -side left -expand yes -fill both
+    pack .help.t.sy -side right -fill y 
+    pack .help.t -side top -fill both -expand yes
+    enterText .help.t.text [HelpText]
+    grayButton help
+}
+
+proc grayButton {button} {
+    bind .help.buttons.help <1> "enterText .help.t.text \[HelpText\]
+         grayButton help" 
+    .help.buttons.help configure -state normal
+
+    bind .help.buttons.bugs <1> "enterText .help.t.text \[Bugs\]
+         grayButton bugs" 
+    .help.buttons.bugs configure -state normal
+
+    bind .help.buttons.warranty <1> "enterText .help.t.text \[Warranty\]
+         grayButton warranty"
+    .help.buttons.warranty configure -state normal
+
+    bind .help.buttons.conditions <1> "enterText .help.t.text \[Conditions\]
+         grayButton conditions" 
+    .help.buttons.conditions configure -state normal
+    disableButton .help.buttons.$button
+}
+
+# The text for errors in the MG environment variable
+#
+
+
+proc bookDetails {} {
+  return { \
+
+ This X interface was written by Bruce McKenzie, Ian Witten and Craig Nevill-Manning.  
+ For information on mg, see
+             Witten, I.H.,  Moffat, A. and Bell, T.C. (1994) "Managing gigabytes: compressing
+             and indexing documents and images." Van Nostrand Reinhold, New York.
+             ISBN 0-442-01863-0, US $54.95; call 1 (800) 544-0550 to order.
+}
+}
+
+proc initializationFailure {} {
+    return [format "%s\n%s" {\
+In order to run XMG you need to have already created and indexed some document collections,
+ and placed them in a directory whose name is given by the environment variable MGDATA.
+ Your MGDATA variable is unset or does not specify a directory with files in; therefore XMG
+ cannot proceed.
+} [bookDetails]]
+}
+
+proc mgqueryFailure {} {
+    return [format "%s\n%s" {\
+In order to run XMG you need to have already created and indexed some document collections,
+ and placed them in a directory whose name is given by the environment variable MGDATA.
+ There is a problem with the collection that you have chosen. Please re-index the collection before
+ you use it again.
+} [bookDetails]]
+
+}
+
+# The text for the help message
+#
+proc HelpText {} {
+    return [format "%s\n%s" {\
+This is an X interface to the mg information retrieval system.
+
+ Type a query in the "Query" box.
+ The first line or so of each matching document is listed. 
+ Click on any line to show the complete document.
+ Shift-click to show the document in its own window
+ Press Next and Previous to cycle through the list of documents (Shift works here too).
+ In document windows (other than the main window), typing n or p shows the next and previous 
+ documents; N or P creates a new window for them. q closes the most recently created window.
+ If you change the query, existing windows continue to refer to the original query.
+ 
+ You can select either Boolean or Ranked queries.
+ Boolean queries: use & for AND, | for OR, ! for NOT, and parentheses for grouping
+ Ranked queries:  documents are listed in order of relevance; a weight is shown alongside each
+                                  weights are normalized to 100 for the most relevant document
+                                  choose Approximate Ranking for greater retrieval speed. 
+ } [bookDetails]]
+}
+
+proc reformat {text} {
+    regsub -all "\n *\n *" $text "BLEQUEWFI" text
+    regsub -all "\[ \t\n\r\]+" $text " " text
+    regsub -all "BLEQUEWFI" $text "\n\n" text
+    return $text
+}
+
+proc Conditions {} {
+    return [reformat [join [sendandget ".conditions\nTHISWILLNEVERMATCHANYTHING\n"] "\n"]]
+}
+
+proc Warranty {} {
+    return [reformat [join [sendandget ".warranty\nTHISWILLNEVERMATCHANYTHING\n"] "\n"]]
+}
+
+proc Bugs {} {
+    return [reformat {
+Known shortcomings of xmg include:
+
+    Slow picture viewing.  Pictures are decompressed in their entirety before a window is created 
+        for the picture.  This often results in a long delay with no feedback. Moreover, when 
+        an image's document is displayed repeatedly, multiple identical images are shown.
+
+    Sequential viewing.  There is no way of going to the next document in the collection to see the
+        context of documents that have been retrieved.  This would be trivial to implement but
+        conflicts with the interpretation of the "previous" and "next" buttons.
+    }]
+}
+
+###############################################################################
+# The main program
+###############################################################################
+
+scan [info tclversion] "%d.%d" major minor
+
+if {$major < 7} {
+    puts "xmg requires version 7.0 of the tcl interpreter. You are using version $major.$minor"
+    exit
+}
+
+# Default font settings
+set defaulttextfont   -adobe-times-medium-r-normal--14-140-75-75-p-74-iso8859-1
+set defaultbuttonfont -adobe-times-bold-r-normal--14-140-75-75-p-77-iso8859-1
+set textfont   [query_resource textfont Textfont $defaulttextfont]
+set buttonfont [query_resource buttonfont Buttonfont $defaultbuttonfont]
+
+set MaxWindowHeight 10
+set HeadLength 100
+set scrolledto 0
+set ListBoxLength 12
+set windowname 0
+set Terminator "RECORD_END"
+set fileId ""
+set query ""
+set ImageString "::::::::::"
+set stacking ".m.t"
+
+tk_listboxSingleSelect Listbox
+option add *Text.wrap word
+
+option add *Text.font $textfont
+option add *Listbox.font $textfont
+option add *Entry.font $textfont
+
+option add *Button.font $buttonfont
+option add *Menubutton.font $buttonfont
+option add *Radiobutton.font $buttonfont
+option add *Checkbutton.font $buttonfont
+option add *Label.font $buttonfont
+option add *Menu.font $buttonfont
+
+wm title . "Managing Gigabytes"
+wm iconname . "xmg"
+frame .m -borderwidth 5 -relief raised
+
+# top part of frame
+frame .m.t
+
+# on the left side of the top part is the "buttons" panel
+frame .m.t.b
+mkButtons .m.t.b
+
+# on the right side is the "query" panel
+frame .m.t.q
+mkQuery .m.t.q
+
+set q [query_resource querytype Querytype approx-ranked]
+set booleanquery [expr \"$q\" == \"boolean\"]
+set approxquery [expr \"$q\" == \"approx-ranked\"]
+# the above lines will trigger changeQuerytype
+
+pack .m.t.b -side left -anchor nw
+pack .m.t.q -side right -anchor ne -fill both -expand yes
+
+# at the bottom is the "document" panel
+frame .m.d
+makeDocumentPanel .m.d
+
+.m.d.buttons.close configure -text "Exit" \
+    -command "destroy ."
+button .m.d.buttons.help -text "Help" -width 10 \
+	-command "mkHelp"
+
+pack .m.d.buttons.help -side right
+pack .m.t -side top -fill x -expand yes
+pack .m.d -side bottom -fill both -expand yes
+
+pack .m -fill both -expand yes
+wm geometry . +300+85
+
+set collection [query_resource collection Collection $collection]
+if {$argc>0} { set collection $argv }
+
+enterText .m.d.text [HelpText]
+
+initMG $collection
+
+###############################################################################
+###############################################################################
+# The following file selection box procedure was written by Andrew Donkin
+# of the University of Waikato. 
+###############################################################################
+
+proc FSBox { {fsBoxMessage "Select file:"}} {
+# xf ignore me 5
+  global fsBox
+
+  set fsBox(name) ""
+  set fsBox(internalPath) [pwd]
+  set fsBox(pattern) "*"
+  set fsBox(all) 0
+
+  # build widget structure
+
+  # start build of toplevel
+  if {"[info commands XFDestroy]" != ""} {
+    catch {XFDestroy .fsBox}
+  } {
+    catch {destroy .fsBox}
+  }
+  toplevel .fsBox -borderwidth 0
+  wm geometry .fsBox 350x300 
+  wm title .fsBox {File select box}
+  wm maxsize .fsBox 1000 1000
+  wm minsize .fsBox 100 100
+  # end build of toplevel
+
+  label .fsBox.message1 -anchor c -text "$fsBoxMessage"
+  frame .fsBox.frame1  -borderwidth 0  -relief raised
+
+  button .fsBox.frame1.ok  -text "OK"  -command "
+      global fsBox
+      set fsBox(name) \[.fsBox.file.file get\]
+      set fsBox(path) \[.fsBox.path.path get\]
+
+      set fsBox(internalPath) \[.fsBox.path.path get\]
+
+      if {\"\[info commands XFDestroy\]\" != \"\"} {
+        catch {XFDestroy .fsBox}
+      } {
+        catch {destroy .fsBox}
+      }"
+
+  button .fsBox.frame1.rescan -text "Rescan" -command {
+      global fsBox
+      FSBoxFSShow [.fsBox.path.path get] [.fsBox.pattern.pattern get] $fsBox(all)
+  }
+
+  button .fsBox.frame1.cancel -text "Cancel" -command "
+      global fsBox
+      set fsBox(name) {}
+      set fsBox(path) {}
+
+      if {\"\[info commands XFDestroy\]\" != \"\"} {
+        catch {XFDestroy .fsBox}
+      } {
+        catch {destroy .fsBox}
+      }"
+
+  frame .fsBox.path -borderwidth 0 -relief raised
+  frame .fsBox.path.paths 
+  label .fsBox.path.paths.paths -borderwidth 0 -text "Pathname:"
+
+  entry .fsBox.path.path -relief sunken
+  .fsBox.path.path insert 0 $fsBox(internalPath)
+  frame .fsBox.pattern -borderwidth 0 -relief raised
+  frame .fsBox.pattern.patterns 
+
+  label .fsBox.pattern.patterns.patterns -borderwidth 0 -text "Selection pattern:"
+  entry .fsBox.pattern.pattern -relief sunken
+  .fsBox.pattern.pattern insert 0 $fsBox(pattern)
+  
+  frame .fsBox.files -borderwidth 0 -relief raised
+  scrollbar .fsBox.files.vscroll -relief raised -command ".fsBox.files.files yview"
+  scrollbar .fsBox.files.hscroll -orient horiz -relief raised -command ".fsBox.files.files xview" 
+  listbox .fsBox.files.files -exportselection false -relief raised -xscrollcommand \
+        ".fsBox.files.hscroll set" -yscrollcommand ".fsBox.files.vscroll set"
+  frame .fsBox.file -borderwidth 0 -relief raised
+  label .fsBox.file.labelfile -text "Filename:"
+  entry .fsBox.file.file -relief sunken
+  focus .fsBox.file.file
+
+  .fsBox.file.file delete 0 end
+  .fsBox.file.file insert 0 $fsBox(name)
+  
+  checkbutton .fsBox.pattern.all -offvalue 0 -onvalue 1 -text "Show all files" -variable fsBox(all) -command {
+      global fsBox
+      FSBoxFSShow [.fsBox.path.path get] [.fsBox.pattern.pattern get] $fsBox(all)
+    }
+
+  FSBoxFSShow $fsBox(internalPath) $fsBox(pattern) $fsBox(all)
+
+  # bindings
+  bind .fsBox.files.files <Double-Button-1> "FSBoxFSFileSelectDouble %W %y"
+  bind .fsBox.files.files <ButtonPress-1> "FSBoxFSFileSelect %W %y"
+  bind .fsBox.files.files <Button1-Motion> "FSBoxFSFileSelect %W %y"
+  bind .fsBox.files.files <Shift-Button1-Motion> "FSBoxFSFileSelect %W %y"
+  bind .fsBox.files.files <Shift-ButtonPress-1> "FSBoxFSFileSelect %W %y"
+
+  bind .fsBox.path.path <Return> {
+    global fsBox
+    FSBoxFSShow [.fsBox.path.path get] [.fsBox.pattern.pattern get] $fsBox(all)
+    .fsBox.file.file icursor end
+    focus .fsBox.file.file}
+  catch "bind .fsBox.path.path <Up> {}"
+  bind .fsBox.path.path <Down> {
+    .fsBox.file.file icursor end
+    focus .fsBox.file.file}
+
+  bind .fsBox.file.file <Return> "
+    global fsBox
+    set fsBox(name) \[.fsBox.file.file get\]
+    set fsBox(path) \[.fsBox.path.path get\]
+    set fsBox(internalPath) \[.fsBox.path.path get\]
+
+    if {\"\[info commands XFDestroy\]\" != \"\"} {
+      catch {XFDestroy .fsBox}
+    } {
+      catch {destroy .fsBox}
+    }"
+  bind .fsBox.file.file <Up> {.fsBox.path.path icursor end
+    focus .fsBox.path.path}
+  bind .fsBox.file.file <Down> {.fsBox.pattern.pattern icursor end
+    focus .fsBox.pattern.pattern}
+
+  bind .fsBox.pattern.pattern <Return> {
+    global fsBox
+    FSBoxFSShow [.fsBox.path.path get] [.fsBox.pattern.pattern get] $fsBox(all)}
+  bind .fsBox.pattern.pattern <Up> {
+    .fsBox.file.file icursor end
+    focus .fsBox.file.file}
+  catch "bind .fsBox.pattern.pattern <Down> {}"
+
+  # packing
+  pack .fsBox.files.vscroll -side left -fill y 
+  pack .fsBox.files.hscroll -side bottom -fill x
+  pack .fsBox.files.files -side left -fill both -expand yes
+
+  pack .fsBox.file.labelfile -side left
+  pack .fsBox.file.file -side left -fill  both -expand yes
+
+  pack .fsBox.frame1.ok -side left -fill both -expand yes
+  pack .fsBox.frame1.rescan -side left -fill both -expand yes
+  pack .fsBox.frame1.cancel -side left -fill both -expand yes
+
+  pack .fsBox.path.paths.paths -side left
+
+  pack .fsBox.pattern.patterns.patterns -side left
+
+  pack .fsBox.path.paths -side left
+  pack .fsBox.path.path -side left -fill both -expand yes
+
+  pack .fsBox.pattern.patterns -side left
+  pack .fsBox.pattern.all -side right -fill both
+  pack .fsBox.pattern.pattern -side left -fill both -expand yes
+
+  pack .fsBox.message1 -side top -fill both
+  pack .fsBox.frame1 -side bottom -fill both
+  pack .fsBox.pattern -side bottom -fill both
+  pack .fsBox.file -side bottom -fill both
+  pack .fsBox.path -side bottom -fill both
+  pack .fsBox.files -side left -fill both -expand yes
+
+  update idletask
+  grab .fsBox
+  tkwait window .fsBox
+
+  if {"[string trim $fsBox(path)]" != "" ||
+      "[string trim $fsBox(name)]" != ""} {
+    if {"[string trimleft [string trim $fsBox(name)] /]" == ""} {
+      return [string trimright [string trim $fsBox(path)] /]
+    } {
+      return [string trimright [string trim $fsBox(path)] /]/[string trimleft [string trim $fsBox(name)] /]
+    }
+  }
+}
+
+proc FSBoxBindSelectOne { fsBoxW fsBoxY} {
+# xf ignore me 6
+
+  set fsBoxNearest [$fsBoxW nearest $fsBoxY]
+  if {$fsBoxNearest >= 0} {
+    $fsBoxW select from $fsBoxNearest
+    $fsBoxW select to $fsBoxNearest
+  }
+}
+
+proc FSBoxFSFileSelect { fsBoxW fsBoxY} {
+# xf ignore me 6
+  global fsBox
+
+  FSBoxBindSelectOne $fsBoxW $fsBoxY
+  set fsBoxNearest [$fsBoxW nearest $fsBoxY]
+  if {$fsBoxNearest >= 0} {
+    set fsBoxTmpEntry [$fsBoxW get $fsBoxNearest]
+    if {"[string index $fsBoxTmpEntry           [expr [string length $fsBoxTmpEntry]-1]]" == "/" ||
+        "[string index $fsBoxTmpEntry           [expr [string length $fsBoxTmpEntry]-1]]" == "@"} {
+      set fsBoxFileName [string range $fsBoxTmpEntry 0             [expr [string length $fsBoxTmpEntry]-2]]
+      if {![IsADir [string trimright $fsBox(internalPath)/$fsBoxFileName @]] &&
+          ![IsASymlink [string trimright $fsBox(internalPath)/$fsBoxFileName @]]} {
+        set fsBoxFileName $fsBoxTmpEntry
+      }
+    } {
+      if {"[string index $fsBoxTmpEntry             [expr [string length $fsBoxTmpEntry]-1]]" == "*"} {
+        set fsBoxFileName [string range $fsBoxTmpEntry 0           [expr [string length $fsBoxTmpEntry]-2]]
+        if {![file executable $fsBox(internalPath)/$fsBoxFileName]} {
+          set fsBoxFileName $fsBoxTmpEntry
+        }
+      } {
+        set fsBoxFileName $fsBoxTmpEntry
+      }
+    }
+    if {![IsADir [string trimright $fsBox(internalPath)/$fsBoxFileName @]]} {
+      set fsBox(name) $fsBoxFileName
+      .fsBox.file.file delete 0 end
+      .fsBox.file.file insert 0 $fsBox(name)
+    }
+  }
+}
+
+proc FSBoxFSFileSelectDouble { fsBoxW fsBoxY} {
+# xf ignore me 6
+  global fsBox
+
+  FSBoxBindSelectOne $fsBoxW $fsBoxY
+  set fsBoxNearest [$fsBoxW nearest $fsBoxY]
+  if {$fsBoxNearest >= 0} {
+    set fsBoxTmpEntry [$fsBoxW get $fsBoxNearest]
+    if {"$fsBoxTmpEntry" == "../"} {
+      set fsBoxTmpEntry [string trimright [string trim $fsBox(internalPath)] "@/"]
+      if {"$fsBoxTmpEntry" == ""} {
+        return
+      }
+      FSBoxFSShow [file dirname $fsBoxTmpEntry]         [.fsBox.pattern.pattern get] $fsBox(all)
+      .fsBox.path.path delete 0 end
+      .fsBox.path.path insert 0 $fsBox(internalPath)
+    } {
+      if {"[string index $fsBoxTmpEntry [expr [string length $fsBoxTmpEntry]-1]]" == "/" ||
+          "[string index $fsBoxTmpEntry [expr [string length $fsBoxTmpEntry]-1]]" == "@"} {
+        set fsBoxFileName [string range $fsBoxTmpEntry 0               [expr [string length $fsBoxTmpEntry]-2]]
+        if {![IsADir [string trimright $fsBox(internalPath)/$fsBoxFileName @]] &&
+            ![IsASymlink [string trimright $fsBox(internalPath)/$fsBoxFileName @]]} {
+          set fsBoxFileName $fsBoxTmpEntry
+        }
+      } {
+        if {"[string index $fsBoxTmpEntry [expr [string length $fsBoxTmpEntry]-1]]" == "*"} {
+          set fsBoxFileName [string range $fsBoxTmpEntry 0                 [expr [string length $fsBoxTmpEntry]-2]]
+          if {![file executable $fsBox(internalPath)/$fsBoxFileName]} {
+            set fsBoxFileName $fsBoxTmpEntry
+          }
+        } {
+          set fsBoxFileName $fsBoxTmpEntry
+        }
+      }
+      if {[IsADir [string trimright $fsBox(internalPath)/$fsBoxFileName @]]} {
+        set fsBox(internalPath) "[string trimright $fsBox(internalPath) {/@}]/$fsBoxFileName"
+        FSBoxFSShow $fsBox(internalPath) [.fsBox.pattern.pattern get] $fsBox(all)
+        .fsBox.path.path delete 0 end
+        .fsBox.path.path insert 0 $fsBox(internalPath)
+      } {
+        set fsBox(name) $fsBoxFileName
+        set fsBox(path) $fsBox(internalPath)
+        if {"[info commands XFDestroy]" != ""} {
+          catch {XFDestroy .fsBox}
+        } {
+          catch {destroy .fsBox}
+        }
+      }
+    }
+  }
+}
+
+proc FSBoxFSShow { fsBoxPath fsBoxPattern fsBoxAll} {
+# xf ignore me 6
+  global fsBox
+
+  set fsBox(pattern) $fsBoxPattern
+
+  if {[file exists $fsBoxPath] && [file readable $fsBoxPath] &&
+      [IsADir $fsBoxPath]} {
+    set fsBox(internalPath) $fsBoxPath
+  } {
+    if {[file exists $fsBoxPath] && [file readable $fsBoxPath] &&
+        [IsAFile $fsBoxPath]} {
+      set fsBox(internalPath) [file dirname $fsBoxPath]
+      .fsBox.file.file delete 0 end
+      .fsBox.file.file insert 0 [file tail $fsBoxPath]
+      set fsBoxPath $fsBox(internalPath)
+    } {
+      while {"$fsBoxPath" != "" && "$fsBoxPath" != "/" &&
+             ![file isdirectory $fsBoxPath]} {
+        set fsBox(internalPath) [file dirname $fsBoxPath]
+         set fsBoxPath $fsBox(internalPath)
+      }
+    }
+  }
+  if {"$fsBoxPath" == ""} {
+    set fsBoxPath "/"
+    set fsBox(internalPath) "/"
+  }
+  .fsBox.path.path delete 0 end
+  .fsBox.path.path insert 0 $fsBox(internalPath)
+
+  if {[.fsBox.files.files size] > 0} {
+    .fsBox.files.files delete 0 end
+  }
+  if {$fsBoxAll} {
+    if {[catch "exec ls -F -a $fsBoxPath" fsBoxResult]} {
+      puts stderr "$fsBoxResult"
+    }
+  } {
+    if {[catch "exec ls -F $fsBoxPath" fsBoxResult]} {
+      puts stderr "$fsBoxResult"
+    }
+  }
+  set fsBoxElementList [lsort $fsBoxResult]
+
+  foreach fsBoxCounter [winfo children .fsBox.pattern.patterns.patterns] {
+    if {[string length [info commands XFDestroy]] > 0} {
+      catch {XFDestroy $fsBoxCounter}
+    } {
+      catch {destroy $fsBoxCounter}
+    }
+  }
+  menu .fsBox.pattern.patterns.patterns.menu
+
+  if {"$fsBoxPath" != "/"} {
+    .fsBox.files.files insert end "../"
+  }
+  foreach fsBoxCounter $fsBoxElementList {
+    if {[string match $fsBoxPattern $fsBoxCounter] ||
+        [IsADir [string trimright $fsBoxPath/$fsBoxCounter "/@"]]} {
+      if {"$fsBoxCounter" != "../" &&
+          "$fsBoxCounter" != "./"} {
+        .fsBox.files.files insert end $fsBoxCounter
+      }
+    }
+  }
+}
+
+proc IsADir { pathName} {
+# xf ignore me 5
+  if {[file isdirectory $pathName]} {
+    return 1
+  } {
+    catch "file type $pathName" fileType
+    if {"$fileType" == "link"} {
+      if {[catch "file readlink $pathName" linkName]} {
+        return 0
+      }
+      catch "file type $linkName" fileType
+      while {"$fileType" == "link"} {
+        if {[catch "file readlink $linkName" linkName]} {
+          return 0
+        }
+        catch "file type $linkName" fileType
+      }
+      return [file isdirectory $linkName]
+    }
+  }
+  return 0
+}
+
+proc IsAFile { fileName} {
+# xf ignore me 5
+  if {[file isfile $fileName]} {
+    return 1
+  } {
+    catch "file type $fileName" fileType
+    if {"$fileType" == "link"} {
+      if {[catch "file readlink $fileName" linkName]} {
+        return 0
+      }
+      catch "file type $linkName" fileType
+      while {"$fileType" == "link"} {
+        if {[catch "file readlink $linkName" linkName]} {
+          return 0
+        }
+        catch "file type $linkName" fileType
+      }
+      return [file isfile $linkName]
+    }
+  }
+  return 0
+}
+
+proc IsASymlink { fileName} {
+# xf ignore me 5
+  catch "file type $fileName" fileType
+  if {"$fileType" == "link"} {
+    return 1
+  }
+  return 0
+}
Index: /main/tags/2.25/gsdl/packages/mg/src/text/GCC.mak
===================================================================
--- /main/tags/2.25/gsdl/packages/mg/src/text/GCC.mak	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/mg/src/text/GCC.mak	(revision 21064)
@@ -0,0 +1,205 @@
+###########################################################################
+#
+# gcc win32 makefile -- mg\src\text
+# A component of the Greenstone digital library software
+# from the New Zealand Digital Library Project at the
+# University of Waikato, New Zealand.
+#
+# Copyright (C) 2000  The 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.
+#
+###########################################################################
+
+
+AR = ar
+RANLIB = ranlib
+CC = gcc
+DELETE = del
+INSTALL = copy
+
+o = .o
+e = .exe
+/ = \\
+
+CPPFLAGS = -g
+DEFS = -DNZDL -DQUIET -DSHORT_SUFFIX -DPARADOCNUM -DHAVE_CONFIG_H \
+       -D_LITTLE_ENDIAN
+LIBS = ..$/..$/lib$/libmg.a
+ 
+COMPILE = $(CC) -c $(DEFS) $(INCLUDES) $(CPPFLAGS) $(CFLAGS)
+LINK = $(CC) $(LDFLAGS) -o $@
+ 
+.SUFFIXES:
+.SUFFIXES: .c $o
+.c$o:
+	$(COMPILE) $<
+ 
+INCLUDES = -I"..$/.." -I"..$/..$/lib"
+
+
+SOURCES = \
+  backend.c               locallib.c              mg_weights_build.c   \
+  bool_optimiser.c        mg.special.c            mgdictlist.c         \
+  bool_parser.c           mg_compression_dict.c   mgquery.c            \
+  bool_query.c            mg_errors.c             mgstat.c             \
+  bool_tester.c           mg_fast_comp_dict.c     mg_decompress_text.c \
+  bool_tree.c             mg_files.c              query.docnums.c      \
+  commands.c              mg_hilite_words.c       query.ranked.c       \
+  comp_dict.c             mg_invf_dict.c          read_line.c          \
+  environment.c           mg_invf_dump.c          stem_search.c        \
+  mg_invf_merge.c         stemmer.c               mg_stem_idx.c        \
+  mg_invf_rebuild.c       term_lists.c            mgstemidxlist.c      \
+  invf_get.c              mg_passes.c             text.pass1.c         \
+  ivf.pass1.c             mg_perf_hash_build.c    text.pass2.c         \
+  ivf.pass2.c             mg_text_estimate.c      text_get.c           \
+  lists.c                 mg_text_merge.c         weights.c            \
+  query_term_list.c       words.c
+
+HEADERS = \
+  backend.h          conditions.h       locallib.h         term_lists.h \
+  bool_optimiser.h   environment.h      mg.h               text.h       \
+  bool_parser.h      globals.h          mg_errors.h        text_get.h   \
+  bool_query.h       hash.h             mg_files.h         warranty.h   \
+  bool_tree.h        help.mg.h          mg_merge.h         weights.h    \
+  build.h            invf.h             read_line.h        words.h      \
+  commands.h         invf_get.h         stem_search.h                   \
+  comp_dict.h        lists.h            stemmer.h                       \
+  query_term_list.h
+
+EXEC = \
+  mgquery$e mg_weights_build$e mgstat$e mg_invf_dump$e \
+  mg_invf_dict$e mg_invf_rebuild$e mgdictlist$e \
+  mg_passes$e mg_perf_hash_build$e mg_compression_dict$e \
+  mg_text_estimate$e mg_fast_comp_dict$e mg_hilite_words$e \
+  mg_invf_merge$e mg_text_merge$e bool_tester$e \
+  mg_stem_idx$e  mgstemidxlist$e mg_decompress_text$e
+
+all:    $(EXEC) libtextin.a
+
+HILITE_OBJS = mg_hilite_words$o stemmer$o locallib$o words$o
+mg_hilite_words$e: $(HILITE_OBJS)
+	$(LINK) $(HILITE_OBJS) $(LIBS)
+
+BOOL_OBJS = bool_tree$o bool_parser$o bool_optimiser$o bool_tester$o \
+	    term_lists$o stemmer$o stem_search$o mg_errors$o query_term_list$o \
+	    words$o
+bool_tester$e: $(BOOL_OBJS)
+	$(LINK) $(BOOL_OBJS) $(LIBS)
+
+QUERY_OBJS = \
+	mgquery$o locallib$o lists$o \
+	query.ranked$o query.docnums$o stem_search$o \
+	environment$o commands$o weights$o text_get$o stemmer$o \
+	read_line$o mg_errors$o backend$o invf_get$o \
+	term_lists$o bool_tree$o bool_parser$o bool_optimiser$o bool_query$o \
+	query_term_list$o words$o
+mgquery$e: $(QUERY_OBJS)
+	$(LINK) $(QUERY_OBJS) $(LIBS)
+
+commands$o : help.mg.h warranty.h conditions.h
+
+PASSES_OBJS = \
+	mg_passes$o text.pass1$o comp_dict$o stemmer$o \
+	text.pass2$o locallib$o \
+	ivf.pass1$o ivf.pass2$o mg.special$o mg_files$o \
+	words$o
+mg_passes$e: $(PASSES_OBJS)
+	$(LINK) $(PASSES_OBJS) $(LIBS)
+
+WEIGHTS_BUILD_OBJS = mg_weights_build$o mg_files$o
+mg_weights_build$e: $(WEIGHTS_BUILD_OBJS)
+	$(LINK) $(WEIGHTS_BUILD_OBJS) $(LIBS)
+
+COMP_DICT_OBJS = mg_compression_dict$o mg_files$o locallib$o
+mg_compression_dict$e: $(COMP_DICT_OBJS)
+	$(LINK) $(COMP_DICT_OBJS) $(LIBS)
+
+FAST_COMP_OBJS = mg_fast_comp_dict$o mg_files$o locallib$o
+mg_fast_comp_dict$e: $(FAST_COMP_OBJS)
+	$(LINK) $(FAST_COMP_OBJS) $(LIBS)
+
+TEXT_EST_OBJS = mg_text_estimate$o locallib$o comp_dict$o mg_files$o
+mg_text_estimate$e: $(TEXT_EST_OBJS)
+	$(LINK) $(TEXT_EST_OBJS) $(LIBS)
+
+STAT_OBJS = mgstat$o mg_files$o locallib$o
+mgstat$e: $(STAT_OBJS)
+	$(LINK) $(STAT_OBJS) $(LIBS)
+
+INVF_DUMP_OBJS = mg_invf_dump$o locallib$o mg_files$o
+mg_invf_dump$e: $(INVF_DUMP_OBJS)
+	$(LINK) $(INVF_DUMP_OBJS) $(LIBS)
+
+INVF_DICT_OBJS = mg_invf_dict$o mg_files$o locallib$o
+mg_invf_dict$e: $(INVF_DICT_OBJS)
+	$(LINK) $(INVF_DICT_OBJS) $(LIBS)
+
+INVF_REB_OBJS = mg_invf_rebuild$o locallib$o
+mg_invf_rebuild$e: $(INVF_REB_OBJS)
+	$(LINK) $(INVF_REB_OBJS) $(LIBS)
+
+DICTLIST_OBJS = mgdictlist$o locallib$o
+mgdictlist$e: $(DICTLIST_OBJS)
+	$(LINK) $(DICTLIST_OBJS) $(LIBS)
+
+PERF_HASH_OBJS = mg_perf_hash_build$o mg_files$o
+mg_perf_hash_build$e: $(PERF_HASH_OBJS)
+	$(LINK) $(PERF_HASH_OBJS) $(LIBS)
+
+STEM_IDX_OBJS = mg_stem_idx$o mg_files$o stemmer$o locallib$o \
+                mg_errors$o term_lists$o
+mg_stem_idx$e: $(STEM_IDX_OBJS)
+	$(LINK) $(STEM_IDX_OBJS) $(LIBS)
+
+STEM_IDX_LIST_OBJS = mgstemidxlist$o mg_files$o
+mgstemidxlist$e: $(STEM_IDX_LIST_OBJS)
+	$(LINK) $(STEM_IDX_LIST_OBJS) $(LIBS)
+
+DECOMPRESS_TEXT_OBJS = mg_decompress_text$o query_term_list$o mg_files$o mg_errors$o \
+                       text_get$o locallib$o backend$o stem_search$o \
+                       term_lists$o stemmer$o weights$o invf_get$o lists$o
+mg_decompress_text$e: $(DECOMPRESS_TEXT_OBJS)
+	$(LINK) $(DECOMPRESS_TEXT_OBJS) $(LIBS)
+
+TEXT_MERGE_OBJS = mg_text_merge$o mg_files$o locallib$o
+mg_text_merge$e: $(TEXT_MERGE_OBJS)
+	$(LINK) $(TEXT_MERGE_OBJS) $(LIBS)
+
+INVF_MERGE_OBJS = mg_invf_merge$o mg_files$o locallib$o
+mg_invf_merge$e: $(INVF_MERGE_OBJS)
+	$(LINK) $(INVF_MERGE_OBJS) $(LIBS)
+
+install: 
+	$(INSTALL) *$e ..$/..$/..$/..$/bin$/windows
+
+LIB_OBJS = \
+	query_term_list$o \
+	locallib$o lists$o \
+	query.ranked$o query.docnums$o stem_search$o \
+	environment$o commands$o weights$o text_get$o stemmer$o \
+	read_line$o mg_errors$o backend$o invf_get$o \
+	term_lists$o bool_tree$o bool_parser$o bool_optimiser$o \
+	bool_query$o words$o
+
+libtextin.a: $(LIB_OBJS)
+	$(DELETE) libtextin.a
+	$(AR) cru libtextin.a $(LIB_OBJS)
+	$(RANLIB) libtextin.a
+
+clean:
+	$(DELETE) *$o 
+	$(DELETE) *$e
Index: /main/tags/2.25/gsdl/packages/mg/src/text/MGPASS.C
===================================================================
--- /main/tags/2.25/gsdl/packages/mg/src/text/MGPASS.C	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/mg/src/text/MGPASS.C	(revision 21064)
@@ -0,0 +1,502 @@
+/**************************************************************************
+ *
+ * mgpass.cpp -- Driver for the various passes -
+
+	V1 -  removed all the pipe processing and replaced with
+	      code to directly explore a directory of files.
+	V2 -  rebuilt to extract non text files from web browser
+	      'catch' file.  Also to display progress count
+			   GH/WJR
+
+ * Copyright (C) 1994  Neil Sharman, ..
+ *
+ * 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.
+ *
+ * $Id$
+ *
+ **************************************************************************/
+
+#include "sysfuncs.h"
+
+#include <malloc.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <io.h>
+#include <fcntl.h>
+#include <string.h>
+
+#include "memlib.h"
+#include "messages.h"
+
+#include "mg_files.h"
+#include "mg.h"
+#include "build.h"
+#include "text.h"
+#include "stemmer.h"
+
+/*
+   $Log$
+   Revision 1.1  1999/08/10 21:17:39  sjboddie
+   renamed mg-1.3d directory mg
+
+   Revision 1.5  1998/12/02 01:32:40  sjboddie
+   fixed 1 missing semi-colon..
+
+   Revision 1.4  1998/12/02 00:57:10  rjmcnab
+
+   Fixed to compile with the changes to the stemming.
+
+   Revision 1.3  1998/11/24 03:39:23  rjmcnab
+
+   Fixed a small error in the windows compilation
+
+   Revision 1.2  1998/11/24 01:29:39  rjmcnab
+
+   Fixed a few problems with the windows build
+
+   Revision 1.1  1998/11/17 09:34:12  rjmcnab
+   *** empty log message ***
+
+   * Revision 1.3  1994/10/20  03:56:57  tes
+   * I have rewritten the boolean query optimiser and abstracted out the
+   * components of the boolean query.
+   *
+   * Revision 1.2  1994/09/20  04:41:52  tes
+   * For version 1.1
+   *
+ */
+
+static char *RCSID = "$Id$";
+
+#define MAX_PASSES 5
+
+#define SPECIAL 1
+#define TEXT_PASS_1 2
+#define TEXT_PASS_2 4
+#define IVF_PASS_1 8
+#define IVF_PASS_2 16
+
+#define MIN_BUF 8192
+#define path_length 256
+
+unsigned long buf_size = 3 * 1024 * 1024;       /* 3Mb */
+unsigned long invf_buffer_size = 5 * 1024 * 1024;       /* 5Mb */
+unsigned long ChunkLimit = 0;
+char InvfLevel = 2;
+char SkipSGML = 0;
+char MakeWeights = 0;
+FILE *Comp_Stats = NULL;
+int comp_stat_point = 0;
+double bytes_processed = 0;
+int num_docs = 0;
+double bytes_received = 0;
+int stem_method = 0;
+int stemmer_num = 0; /* default to the Lovin stemmer */
+
+static char Passes = 0;
+static unsigned long trace = 0;
+static int Dump = 0;
+static char **files = NULL;
+static int num_files = 0;
+static char *trace_name = NULL;
+
+static char dirname[path_length], wildname[path_length];
+static int by_para = 0, recurse = 0, html_catch = 0;
+static char *buffer;
+char *line_start, *data_end, *base, *scan;
+
+typedef struct pass_data
+  {
+    char *name;
+    int (*init) (char *);
+    int (*process) (u_char *, int);
+    int (*done) (char *);
+  }
+pass_data;
+
+static pass_data PassData[MAX_PASSES] =
+{
+  {"special", init_special, process_special, done_special},
+  {"text.pass1", init_text_1, process_text_1, done_text_1},
+  {"text.pass2", init_text_2, process_text_2, done_text_2},
+  {"ivf.pass1", init_ivf_1, process_ivf_1, done_ivf_1},
+  {"ivf.pass2", init_ivf_2, process_ivf_2, done_ivf_2},
+};
+
+static char *usage_str = "\nUSAGE:\n"
+"  %s [-h] [-G] [-D] [-1|-2|-3] [-T1] [-T2] [-I1] [-I2] [-N1]\n"
+"  %*s [-N2] [-W] [-S] [-b buffer-size] [-d dictionary-directory]\n"
+"  %*s [-t trace-point Mb] [-m invf-memory] [-c chunk-limit]\n"
+"  %*s [-n trace-name] [-C comp-stat-size] [-s stem_method] -f doc-collection-name\n"
+"  %*s [source directory\\] [source file]\n";
+
+static void usage (char *err)
+{
+  if (err) Message (err);
+  fprintf (stderr, usage_str, msg_prefix, strlen (msg_prefix), "",
+    strlen (msg_prefix), "", strlen (msg_prefix), "");
+  exit (1);
+}
+
+void do_process(char *buffer, int num)
+{
+  int pass;
+  if (num == 0) Message ("Warning : Processing zero length document");
+  num_docs++;
+  bytes_processed += num;
+  for (pass = 0; pass < MAX_PASSES; pass++)
+    if (Passes & (1 << pass))
+	if (PassData[pass].process((u_char *)buffer, num) == COMPERROR)
+	   FatalError(1, "Error during file processing");
+}
+
+int refill(int in_fd)
+{
+  int num, bitleft;
+  bitleft = data_end - base;
+  memmove(buffer, base, bitleft);
+  if (buf_size - bitleft < MIN_BUF)
+    FatalError(1, "Paragraph too big for buffer");
+  num = read(in_fd, &buffer[bitleft], buf_size - bitleft);
+  line_start -= (base - buffer);
+  scan -= (base - buffer);
+  base = buffer;
+  data_end = buffer + bitleft + num;
+  if (num > 0) return 1; else return 0;
+}
+
+char *scanpara(int in_fd)
+{
+  int num, blank, in_blank, at_end;
+  num = read(in_fd,buffer,buf_size);
+  in_blank = 1;  base = buffer;  line_start = buffer;  scan = buffer;
+  data_end = buffer + num;  at_end = 0;
+  for (;;) {
+    blank = 1;  line_start = scan;                   // Get a line
+    while (scan < data_end  &&  *scan != '\n')
+      if (*scan++ > ' ') blank = 0;
+    if (scan >= data_end) {
+      if (refill(in_fd)) {
+	while (scan < data_end  &&  *scan != '\n')
+	  if (*scan++ > ' ') blank = 0;
+	if (scan < data_end) scan++;
+	}
+      else at_end = 1;
+      }
+    else scan++;
+    if (line_start < scan) {                         // If we have a line
+      if (in_blank) {
+	if (!blank) { in_blank = 0; base = line_start; }
+	}
+      else {
+	if (blank) {
+	  do_process(base, line_start - base);
+	  in_blank = 1;  base = line_start;
+	  }
+	}
+      }
+    if (at_end) break;
+    }
+  if (in_blank) base = scan;
+  if (scan + 2 <= buffer + buf_size) {
+    *scan++ = 26;  *scan++ = 10;
+    }
+  if (base < scan) do_process(base, scan - base);
+  return NULL;
+}
+
+char *scanfile(int in_fd)
+{
+  int num = read(in_fd,buffer,buf_size);  /*expect to read the whole file*/
+  if (num < 0) return "file locked";
+  if (num >= buf_size-1) return "file too long";
+  do_process(buffer, num);
+  return NULL;
+}
+
+void search(char *dname, char *fname)
+{
+  long dirtag;  struct _finddata_t dirinfo;  int in_fd;  char *res;
+  char search_name[path_length], found_name[path_length];
+
+  sprintf(search_name, "%s%s", dname, fname);    /*Scan files*/
+  dirtag = _findfirst(search_name, &dirinfo);
+  if (dirtag >= 0) {
+    do {
+      if ((dirinfo.attrib & (_A_SUBDIR | _A_HIDDEN | _A_SYSTEM)) == 0) {
+	sprintf(found_name,"%s%s",dname,dirinfo.name);
+	in_fd = open(found_name,O_RDONLY|O_BINARY);
+	if (in_fd >= 0) {
+	  if (by_para)
+	    res = scanpara(in_fd);
+	  else
+	    res = scanfile(in_fd);
+	  if (res != NULL) {
+	    Message("Error %s in processing file %s\n", res, found_name);
+	    exit(1);
+	    }
+	  close(in_fd);
+	  }
+	}
+      } while (_findnext(dirtag, &dirinfo) == 0);
+    _findclose(dirtag);
+    }
+
+  if (recurse == 0) return;
+
+  sprintf(search_name, "%s*.*", dname);          /*Look for subdirs*/
+  dirtag = _findfirst(search_name, &dirinfo);
+  if (dirtag < 0) return;
+  do {
+    if ( ((dirinfo.attrib & (_A_HIDDEN | _A_SYSTEM)) == 0)  &&
+	 ((dirinfo.attrib & _A_SUBDIR) != 0)  &&
+	 strcmp(dirinfo.name,".") != 0 &&
+	 strcmp(dirinfo.name,"..") != 0) {
+      sprintf(found_name,"%s%s",dname,dirinfo.name);
+      strcat(found_name,"\\");
+      search(found_name,fname);
+      }
+    } while (_findnext(dirtag, &dirinfo) == 0);
+  _findclose(dirtag);
+}
+
+static int toobig(int n)
+{
+  if (n > path_length) {
+    printf("Cannot handle urls > %d characters in length\n", path_length);
+    exit(1);
+    }
+  return 0;
+}
+
+void scan_catch(char *dname, char *fname)
+{
+  int in_fd, urllen, conlen, filesize;  char catch_name[path_length];
+  int filecount = 0;
+  enum { filekind_redirected, filekind_text, filekind_other } filekind;
+  sprintf(catch_name, "%s%s", dname, fname);
+  in_fd = open(catch_name,O_RDONLY|O_BINARY);
+  if (in_fd < 0)
+    FatalError(1, "Couldn't open catch file \"%s\"", catch_name);
+  for (;;) {
+    filecount++;  if (filecount%100 == 0) { printf("%d\r", filecount);  fflush(stdout); }
+    if (read(in_fd, &urllen, sizeof(int)) != sizeof(int) || toobig(urllen) ||
+	read(in_fd, catch_name, urllen) != urllen ||
+	read(in_fd, &conlen, sizeof(int)) != sizeof(int) || toobig(conlen) ||
+	read(in_fd, catch_name, conlen) != conlen) break;
+    if (conlen >= 1 && *catch_name == '@')
+      filekind = filekind_redirected;
+    else {
+      if (conlen >= 4 && strncmp(catch_name, "text", 4) == 0)
+	filekind = filekind_text;
+      else
+	filekind = filekind_other;
+      if (read(in_fd, &filesize, sizeof(int)) != sizeof(int))
+	FatalError(1, "File read failed for size field");
+      if (filesize > buf_size)
+	FatalError(1, "File too large (%d > %d)", filesize, buf_size);
+      if (read(in_fd, buffer, filesize) != filesize)
+	FatalError(1, "Failed to read file data");
+      }
+    if (filekind == filekind_text) do_process(buffer, filesize);
+    }
+  close(in_fd);
+}
+
+static void driver (FILE * Trace, char *file_name)
+{
+  int pass;
+
+  buffer = (char *)Xmalloc (buf_size);
+
+  for (pass = 0; pass < MAX_PASSES; pass++)
+    if (Passes & (1 << pass))
+      {
+	if (PassData[pass].init (file_name) == COMPERROR)
+	  FatalError (1, "Error during init of \"%s\"",PassData[pass].name);
+      }
+
+  if (html_catch == 0) search(dirname, wildname);
+		  else scan_catch(dirname, wildname);
+
+  for (pass = 0; pass < MAX_PASSES; pass++)
+    if (Passes & (1 << pass))
+      {
+	if (PassData[pass].done (file_name) == COMPERROR)
+	  FatalError (1, "Error during done of \"%s\"", PassData[pass].name);
+      }
+
+
+  free (buffer);
+}
+
+void main (int argc, char **argv)
+{
+  int ch;
+  char *filename = NULL;
+  FILE *Trace = NULL;
+
+  msg_prefix = argv[0];
+
+  opterr = 0;
+  while ((ch = getopt (argc, argv, "hC:WHGpSD123f:d:b:T:I:t:m:N:c:n:s:")) != -1)
+    {
+      switch (ch)
+	{
+	case 'H':
+	  html_catch = 1;
+	  break;
+	case 'G':
+	  SkipSGML = 1;
+	  break;
+	case 'p':
+	  by_para = 1;
+	  break;
+	case 'S':
+	  Passes |= SPECIAL;
+	  break;
+	case '1':
+	  InvfLevel = 1;
+	  break;
+	case '2':
+	  InvfLevel = 2;
+	  break;
+	case '3':
+	  InvfLevel = 3;
+	  break;
+	case 'f':
+	  filename = optarg;
+	  break;
+	case 'n':
+	  trace_name = optarg;
+	  break;
+	case 'D':
+	  Dump = 1;
+	  break;
+	case 'W':
+	  MakeWeights = 1;
+	  break;
+	case 'd':
+	  set_basepath (optarg);
+	  break;
+	case 's':
+	  stem_method = atoi (optarg) & STEMMER_MASK;
+	  break;
+	case 'b':
+	  buf_size = atoi (optarg) * 1024;
+	  break;
+	case 'C':
+	  comp_stat_point = atoi (optarg) * 1024;
+	  break;
+	case 'c':
+	  ChunkLimit = atoi (optarg);
+	  break;
+	case 'm':
+	  invf_buffer_size = (int) (atof (optarg) * 1024 * 1024);
+	  break;
+	case 'I':
+	case 'N': /* N kept for compatability */
+	  if (*optarg == '1')
+	    Passes |= IVF_PASS_1;
+	  else if (*optarg == '2')
+	    Passes |= IVF_PASS_2;
+	  else
+	    usage ("Invalid pass number");
+	  break;
+	case 'T':
+	  if (*optarg == '1')
+	    Passes |= TEXT_PASS_1;
+	  else if (*optarg == '2')
+	    Passes |= TEXT_PASS_2;
+	  else
+	    usage ("Invalid pass number");
+	  break;
+	case 't':
+	  trace = (unsigned long) (atof (optarg) * 1024 * 1024);
+	  break;
+	case 'h':
+	case '?':
+	  usage (NULL);
+	}
+    }
+
+  if (!filename || *filename == '\0')
+    FatalError (1, "A document collection name must be specified.");
+
+  if (buf_size < MIN_BUF)
+    FatalError (1, "The buffer size must exceed 1024 bytes.");
+
+  if ((Passes & (IVF_PASS_1 | IVF_PASS_2)) == (IVF_PASS_1 | IVF_PASS_2))
+    FatalError (1, "I1 and I2 cannot be done simultaneously.");
+
+  if ((Passes & (TEXT_PASS_1 | TEXT_PASS_2)) == (TEXT_PASS_1 | TEXT_PASS_2))
+    FatalError (1, "T1 and T2 cannot be done simultaneously.");
+
+  if (!Passes)
+    FatalError (1, "S, T1, T2, I1 or I2 must be specified.");
+
+  if (argc - optind == 1) {
+    strcpy(dirname,"");
+    strcpy(wildname,argv[optind]);
+    }
+  else if (argc - optind == 2) {
+    strcpy(dirname,argv[optind]);
+    strcpy(wildname,argv[optind+1]);
+    }
+  else FatalError(1, "Finder code requires directory and filespec.");
+
+  if (strrchr(wildname,'*') != NULL  ||  strrchr(wildname,'?') != NULL)
+    recurse = 1;
+
+  if (trace)
+    {
+      if (!trace_name)
+	trace_name = make_name (filename, TRACE_SUFFIX, NULL);
+      if (!(Trace = fopen (trace_name, "a")))
+	Message ("Unable to open \"%s\". No tracing will be done.", trace_name);
+      else
+	setbuf (Trace, NULL);
+    }
+  else
+    Trace = NULL;
+
+  if (comp_stat_point)
+    {
+      char *name = make_name (filename, COMPRESSION_STATS_SUFFIX, NULL);
+      if (!(Comp_Stats = fopen (name, "wb")))
+	Message ("Unable to open \"%s\". No comp. stats. will be generated.",
+		 name);
+    }
+
+
+  if (Trace)
+    {
+      int i;
+      fprintf (Trace, "\n\n\t\t-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-\n\n");
+      for (i = 0; i < argc; i++)
+	fprintf (Trace, "%s ", argv[i]);
+      fprintf (Trace, "\n\n");
+    }
+
+  driver (Trace, filename);
+
+  if (Trace)
+    fclose (Trace);
+
+  if (Comp_Stats)
+    fclose (Comp_Stats);
+
+  exit (0);
+}
Index: /main/tags/2.25/gsdl/packages/mg/src/text/Makefile.in
===================================================================
--- /main/tags/2.25/gsdl/packages/mg/src/text/Makefile.in	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/mg/src/text/Makefile.in	(revision 21064)
@@ -0,0 +1,384 @@
+###########################################################################
+#
+# Makefile.in -- Makefile for the MG system
+# Copyright (C) 1994  Neil Sharman;  1995 Tim Shimmin
+#
+# 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.
+#
+#       @(#)Makefile.in	1.10 22 Mar 1994
+#
+###########################################################################
+
+PACKAGE = @PACKAGE@
+VERSION = @VERSION@
+ 
+SHELL = /bin/sh
+VPATH = @srcdir@
+exec_prefix = @exec_prefix@
+prefix = @prefix@
+srcdir = @srcdir@
+subdir = src/text
+top_srcdir = @top_srcdir@
+transform = @program_transform_name@
+ 
+AR = ar
+CC = @CC@
+CFLAGS = @CFLAGS@
+CPPFLAGS = @CPPFLAGS@
+DEFS = @DEFS@
+RANLIB = @RANLIB@
+INSTALL = @INSTALL@
+INSTALL_DATA = @INSTALL_DATA@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@
+LDFLAGS = @LDFLAGS@
+#LIBS = ../../lib/libmg.a -lm
+LIBS = ../../lib/libmg.a @LIBS@
+TOUCH = echo timestamp >
+AWK = @AWK@
+YACC = @YACC@
+GSDLOS = @gsdlos@
+
+##########################################
+# Uncomment for compiling for the nzdl project
+#
+CFLAGS = @CFLAGS@ -DNZDL -DQUIET -DSHORT_SUFFIX -DPARADOCNUM
+##########################################
+
+ 
+bindir = ../../../../bin/$(GSDLOS)
+datadir = $(prefix)/share
+libexecdir = $(exec_prefix)/libexec
+localedir = $(datadir)/locale
+mandir = $(prefix)/man/man1
+ 
+COMPILE = $(CC) -c $(DEFS) $(TREC_MODE) $(READLINE) $(INCLUDES) $(CPPFLAGS) $(CFLAGS)
+LINK = $(CC) $(LDFLAGS) -o $@
+
+.SUFFIXES:
+.SUFFIXES: .c .o
+.c.o:
+	$(COMPILE) $<
+ 
+
+ANSI2KNR = @ANSI2KNR@
+o = .@U@o
+ 
+.SUFFIXES: ._c ._o
+.c._c:
+	./ansi2knr $< > $*.tmp && mv $*.tmp $@
+._c._o:
+	@echo $(COMPILE) $<
+	@rm -f _$*.c
+	@ln $< _$*.c && $(COMPILE) _$*.c && mv _$*.o $@ && rm _$*.c
+.c._o:
+	./ansi2knr $< > $*.tmp && mv $*.tmp $*._c
+	@echo $(COMPILE) $*._c
+	@rm -f _$*.c
+	@ln $*._c _$*.c && $(COMPILE) _$*.c && mv _$*.o $@ && rm _$*.c
+ 
+INCLUDES = -I../../../.. -I../.. -I../../lib -I.
+
+#############################################################################
+#
+# Uncomment (and possibly edit) the following lines if you wish
+# to use the GNU readline library for the input in mgquery
+# 
+#READLINE = -DGNU_READLINE -I/opt/gnu/include/readline -L/opt/gnu/lib
+#READLINE_LIBS = -lreadline -ltermcap
+#
+#
+#############################################################################
+
+#############################################################################
+#
+# When working with the trec collection this should be uncommented.
+#
+# TREC_MODE = -DTREC_MODE
+#
+#
+#############################################################################
+
+SOURCES = \
+  backend.c               locallib.c              mg_weights_build.c   \
+  bool_optimiser.c        mg.special.c            mgdictlist.c         \
+  bool_parser.c           mg_compression_dict.c   mgquery.c            \
+  bool_query.c            mg_errors.c             mgstat.c             \
+  bool_tester.c           mg_fast_comp_dict.c     mg_decompress_text.c \
+  bool_tree.c             mg_files.c              query.docnums.c      \
+  commands.c              mg_hilite_words.c       query.ranked.c       \
+  comp_dict.c             mg_invf_dict.c          read_line.c          \
+  environment.c           mg_invf_dump.c          stem_search.c        \
+  mg_invf_merge.c         stemmer.c               mg_stem_idx.c        \
+  mg_invf_rebuild.c       term_lists.c            mgstemidxlist.c      \
+  invf_get.c              mg_passes.c             text.pass1.c         \
+  ivf.pass1.c             mg_perf_hash_build.c    text.pass2.c         \
+  ivf.pass2.c             mg_text_estimate.c      text_get.c           \
+  lists.c                 mg_text_merge.c         weights.c            \
+  query_term_list.c       words.c
+
+HEADERS = \
+  backend.h          conditions.h       locallib.h         term_lists.h \
+  bool_optimiser.h   environment.h      mg.h               text.h       \
+  bool_parser.h      globals.h          mg_errors.h        text_get.h   \
+  bool_query.h       hash.h             mg_files.h         warranty.h   \
+  bool_tree.h        help.mg.h          mg_merge.h         weights.h    \
+  build.h            invf.h             read_line.h        words.h      \
+  commands.h         invf_get.h         stem_search.h                   \
+  comp_dict.h        lists.h            stemmer.h                       \
+  query_term_list.h
+
+
+MISC          = Makefile.in help.mg.src bool_parser.y warranty.src conditions.src
+
+ALLFILES      =	$(SOURCES) $(HEADERS) $(MISC) $(MAN)
+
+DISTFILES     = $(ALLFILES) 
+
+EXEC          = mgquery mg_weights_build mgstat mg_invf_dump mg_invf_dict \
+                mg_invf_rebuild mgdictlist mg_passes mg_perf_hash_build \
+                mg_compression_dict mg_text_estimate mg_fast_comp_dict \
+                mg_hilite_words mg_invf_merge mg_text_merge bool_tester \
+                mg_stem_idx mgstemidxlist mg_decompress_text
+
+MAN           = mgquery.1 mg_weights_build.1 mgstat.1 mg_invf_dump.1 mg_invf_dict.1 \
+                mg_invf_rebuild.1 mgdictlist.1 mg_passes.1 mg_perf_hash_build.1 \
+                mg_compression_dict.1 mg_text_estimate.1 mg_fast_comp_dict.1 \
+                mg_hilite_words.1 mg_invf_merge.1 mg_text_merge.1 \
+                mg_stem_idx.1 mgstemidxlist.1 mg_decompress_text.1 
+
+# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
+
+
+all:	$(EXEC) libtextin.a 
+
+
+# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
+
+help.mg.h : help.mg.src
+	sed -e 's/\\/\\\\/g' -e 's/\"/\\\"/g' help.mg.src | $(AWK) '/^#/ { next; };{ if (x == 0) printf("static char *help_str[] = {\n\"%s\\n\"", $$0); else printf(",\n\"%s\\n\"", $$0); x = 1; }; END { printf("};\n"); }' - >help.mg.h
+
+warranty.h : warranty.src
+	sed  -e 's/\\/\\\\/g' -e 's/\"/\\\"/g' warranty.src | $(AWK) '/^#/ { next; };{ if (x == 0) printf("static char *warranty_str[] = {\n\"%s\\n\"", $$0); else printf(",\n\"%s\\n\"", $$0); x = 1; }; END { printf("};\n"); }' - >warranty.h
+
+conditions.h : conditions.src
+	sed -e 's/\\/\\\\/g' -e 's/\"/\\\"/g' conditions.src | $(AWK) '/^#/ { next; };{ if (x == 0) printf("static char *cond_str[] = {\n\"%s\\n\"", $$0); else printf(",\n\"%s\\n\"", $$0); x = 1; }; END { printf("};\n"); }' - >conditions.h
+
+
+# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
+
+HILITE_OBJS = mg_hilite_words$o stemmer$o locallib$o words$o
+
+mg_hilite_words: $(HILITE_OBJS)
+	$(LINK) $(HILITE_OBJS) $(LIBS)
+
+# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
+
+bool_parser.c: bool_parser.y
+	$(YACC) $?
+	mv y.tab.c $@
+
+BOOL_OBJS = bool_tree$o bool_parser$o bool_optimiser$o bool_tester$o \
+            term_lists$o stemmer$o stem_search$o mg_errors$o query_term_list$o \
+	    words$o
+
+bool_tester: $(BOOL_OBJS)
+	$(LINK) $(BOOL_OBJS) $(LIBS)
+
+# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
+
+QUERY_OBJS = \
+	mgquery$o locallib$o lists$o \
+	query.ranked$o query.docnums$o stem_search$o \
+	environment$o commands$o weights$o text_get$o stemmer$o \
+	read_line$o mg_errors$o backend$o invf_get$o \
+	term_lists$o bool_tree$o bool_parser$o bool_optimiser$o bool_query$o \
+	query_term_list$o words$o
+
+mgquery: $(QUERY_OBJS)	
+	$(LINK) $(READLINE) $(QUERY_OBJS) $(READLINE_LIBS) $(LIBS)
+
+commands$o : help.mg.h warranty.h conditions.h
+
+# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
+
+PASSES_OBJS = \
+	mg_passes$o text.pass1$o comp_dict$o stemmer$o \
+	text.pass2$o locallib$o \
+	ivf.pass1$o ivf.pass2$o mg.special$o mg_files$o \
+	words$o
+
+mg_passes: $(PASSES_OBJS)
+	$(LINK) $(PASSES_OBJS) $(LIBS) 
+
+# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
+
+WEIGHTS_BUILD_OBJS = mg_weights_build$o mg_files$o
+
+mg_weights_build: $(WEIGHTS_BUILD_OBJS)
+	$(LINK) $(WEIGHTS_BUILD_OBJS) $(LIBS)
+
+COMP_DICT_OBJS = mg_compression_dict$o mg_files$o locallib$o
+
+mg_compression_dict: $(COMP_DICT_OBJS)
+	$(LINK) $(COMP_DICT_OBJS) $(LIBS)
+
+FAST_COMP_OBJS = mg_fast_comp_dict$o mg_files$o locallib$o
+
+mg_fast_comp_dict: $(FAST_COMP_OBJS)
+	$(LINK) $(FAST_COMP_OBJS) $(LIBS)
+
+TEXT_EST_OBJS = mg_text_estimate$o locallib$o comp_dict$o mg_files$o
+
+mg_text_estimate: $(TEXT_EST_OBJS)
+	$(LINK) $(TEXT_EST_OBJS) $(LIBS)
+
+STAT_OBJS = mgstat$o mg_files$o locallib$o
+
+mgstat:	$(STAT_OBJS)
+	$(LINK) $(STAT_OBJS) $(LIBS)
+
+INVF_DUMP_OBJS = mg_invf_dump$o locallib$o mg_files$o
+
+mg_invf_dump: $(INVF_DUMP_OBJS)
+	$(LINK) $(INVF_DUMP_OBJS) $(LIBS)
+
+INVF_DICT_OBJS = mg_invf_dict$o mg_files$o locallib$o
+
+mg_invf_dict: $(INVF_DICT_OBJS)
+	$(LINK) $(INVF_DICT_OBJS) $(LIBS)
+
+INVF_REB_OBJS = mg_invf_rebuild$o locallib$o
+
+mg_invf_rebuild: $(INVF_REB_OBJS)
+	$(LINK) $(INVF_REB_OBJS) $(LIBS)
+
+DICTLIST_OBJS = mgdictlist$o locallib$o
+
+mgdictlist: $(DICTLIST_OBJS)
+	$(LINK) $(DICTLIST_OBJS) $(LIBS)
+
+PERF_HASH_OBJS = mg_perf_hash_build$o mg_files$o
+
+mg_perf_hash_build: $(PERF_HASH_OBJS)
+	$(LINK) $(PERF_HASH_OBJS) $(LIBS)
+
+STEM_IDX_OBJS = \
+                mg_stem_idx$o mg_files$o stemmer$o locallib$o \
+                mg_errors$o term_lists$o
+
+mg_stem_idx: $(STEM_IDX_OBJS)
+	$(LINK) $(STEM_IDX_OBJS) $(LIBS)
+
+STEM_IDX_LIST_OBJS = mgstemidxlist$o mg_files$o
+
+mgstemidxlist: $(STEM_IDX_LIST_OBJS)
+	$(LINK) $(STEM_IDX_LIST_OBJS) $(LIBS)
+
+DECOMPRESS_TEXT_OBJS = \
+                mg_decompress_text.o query_term_list.o mg_files.o mg_errors.o \
+                text_get.o locallib.o backend.o stem_search.o \
+                term_lists.o stemmer.o weights.o invf_get.o lists.o
+
+mg_decompress_text: $(DECOMPRESS_TEXT_OBJS)
+	$(LINK) $(DECOMPRESS_TEXT_OBJS) $(LIBS)
+
+# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
+
+TEXT_MERGE_OBJS = mg_text_merge$o mg_files$o locallib$o
+
+mg_text_merge: $(TEXT_MERGE_OBJS)
+	$(LINK) $(TEXT_MERGE_OBJS) $(LIBS)
+
+INVF_MERGE_OBJS = mg_invf_merge$o mg_files$o locallib$o
+
+mg_invf_merge: $(INVF_MERGE_OBJS)
+	$(LINK) $(INVF_MERGE_OBJS) $(LIBS)
+
+# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
+
+ansi2knr: ansi2knr.o
+	$(LINK) ansi2knr.o $(LIBS)
+
+install: execinstall #maninstall
+uninstall: execuninstall manuninstall
+
+execinstall: $(EXEC)
+	for name in $(EXEC); do \
+	  $(INSTALL_PROGRAM) $$name \
+	  $(bindir)/`echo $$name | sed '$(transform)'`; \
+	done
+
+execuninstall:
+	for name in $(EXEC); do \
+	 rm -f $(bindir)/`echo $$name | sed '$(transform)'`; \
+	done
+
+maninstall: $(MAN)
+	$(top_srcdir)/mkinstalldirs $(mandir); \
+	for f in $(MAN); do \
+	  $(INSTALL_DATA) $$f $(mandir)/$$f ;\
+	done
+
+manuninstall: $(MAN)
+	for f in $(MAN); do \
+	  rm -f $(mandir)/$$f ;\
+	done
+
+# words$o,  removed to avoid conflict with mgpp libtextin.a
+LIB_OBJS = \
+	query_term_list$o \
+	locallib$o lists$o \
+	query.ranked$o query.docnums$o stem_search$o \
+	environment$o commands$o weights$o text_get$o stemmer$o \
+	read_line$o mg_errors$o backend$o invf_get$o \
+	term_lists$o bool_tree$o bool_parser$o bool_optimiser$o \
+	bool_query$o 
+
+libtextin.a: $(LIB_OBJS)
+	rm -f libtextin.a
+	$(AR) cru libtextin.a $(LIB_OBJS)
+	$(RANLIB) libtextin.a
+
+mostlyclean:
+	rm -f *$o _*.c _*.o *._c *._o core core.*
+ 
+clean: mostlyclean
+	rm -f $(EXEC)
+ 
+distclean: clean
+	rm -f ansi2knr
+	rm -f Makefile
+ 
+maintainer-clean: distclean
+	@echo "This command is intended only for maintainers to use;"
+	@echo "rebuilding the deleted files may require special tools."
+ 
+dist: $(DISTFILES)
+	for file in $(DISTFILES); do \
+	  ln $(srcdir)/$$file $(distdir) 2> /dev/null \
+	  || cp -p $(srcdir)/$$file $(distdir); \
+	done
+ 
+Makefile: Makefile.in ../../../../config.status
+	cd ../../../.. && CONFIG_FILES=$(subdir)/$@ CONFIG_HEADERS= ./config.status
+ 
+# Tell versions [3.59,3.63) of GNU make not to export all variables.
+# Otherwise a system limit (for SysV at least) may be exc
+
+
+
+
+
+
Index: /main/tags/2.25/gsdl/packages/mg/src/text/WIN32.MAK
===================================================================
--- /main/tags/2.25/gsdl/packages/mg/src/text/WIN32.MAK	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/mg/src/text/WIN32.MAK	(revision 21064)
@@ -0,0 +1,222 @@
+###########################################################################
+#
+# win32 makefile -- mg\src\text
+# A component of the Greenstone digital library software
+# from the New Zealand Digital Library Project at the
+# University of Waikato, New Zealand.
+#
+# Copyright (C) 1999  The 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.
+#
+###########################################################################
+
+GSDLHOME = c:\gsdl
+
+CC = cl
+CPPFLAGS =
+DEFS = -DNZDL -DQUIET -DSHORT_SUFFIX -DPARADOCNUM -DHAVE_CONFIG_H \
+       -D__WIN32__ -D_LITTLE_ENDIAN
+INCLUDES = -I$(GSDLHOME)\packages\mg\src\text -I$(GSDLHOME)\packages\mg \
+	   -I$(GSDLHOME)\packages\mg\lib -I$(GSDLHOME)
+LDFLAGS =
+
+LIBS = $(GSDLHOME)\packages\mg\lib\libmg.lib
+
+COMPILE = $(CC) -c $(DEFS) $(INCLUDES)
+LINK = $(CC) $(LDFLAGS)
+
+.SUFFIXES:
+.SUFFIXES: .c .obj .cpp
+.c.obj:
+	$(COMPILE) $<
+.cpp.obj:
+	$(COMPILE) $<
+
+o = .obj
+e = .exe
+
+SOURCES = \
+  backend.c               locallib.c              mg_weights_build.c   \
+  bool_optimiser.c        mg.special.c            mgdictlist.c         \
+  bool_parser.c           mg_compression_dict.c   mgquery.c            \
+  bool_query.c            mg_errors.c             mgstat.c             \
+  bool_tester.c           mg_fast_comp_dict.c     mg_decompress_text.c \
+  bool_tree.c             mg_files.c              query.docnums.c      \
+  commands.c              mg_hilite_words.c       query.ranked.c       \
+  comp_dict.c             mg_invf_dict.c          read_line.c          \
+  environment.c           mg_invf_dump.c          stem_search.c        \
+  mg_invf_merge.c         stemmer.c               mg_stem_idx.c        \
+  mg_invf_rebuild.c       term_lists.c            mgstemidxlist.c      \
+  invf_get.c              mg_passes.c             text.pass1.c         \
+  ivf.pass1.c             mg_perf_hash_build.c    text.pass2.c         \
+  ivf.pass2.c             mg_text_estimate.c      text_get.c           \
+  lists.c                 mg_text_merge.c         weights.c            \
+  mgpass.c                query_term_list.c       words.c
+
+HEADERS = \
+  backend.h          conditions.h       locallib.h         term_lists.h \
+  bool_optimiser.h   environment.h      mg.h               text.h       \
+  bool_parser.h      globals.h          mg_errors.h        text_get.h   \
+  bool_query.h       hash.h             mg_files.h         warranty.h   \
+  bool_tree.h        help.mg.h          mg_merge.h         weights.h    \
+  build.h            invf.h             read_line.h        words.h      \
+  commands.h         invf_get.h         stem_search.h                   \
+  comp_dict.h        lists.h            stemmer.h          query_term_list.h
+
+EXEC          = mgquery$e mg_weights_build$e mgstat$e \
+		mg_invf_dump$e     mg_invf_dict$e \
+		mg_invf_rebuild$e     mgdictlist$e \
+		mg_passes$e     mg_perf_hash_build$e \
+		mg_compression_dict$e     mg_text_estimate$e \
+		mg_fast_comp_dict$e \
+		mg_hilite_words$e     mg_invf_merge$e \
+		mg_text_merge$e     bool_tester$e  mgpass$e \
+		mg_stem_idx$e  mgstemidxlist$e \
+                mg_decompress_text$e
+
+all:    $(EXEC) libtextin.lib
+
+HILITE_OBJS = mg_hilite_words$o stemmer$o locallib$o words$o
+mg_hilite_words$e: $(HILITE_OBJS)
+	$(LINK) $(HILITE_OBJS) $(LIBS)
+
+BOOL_OBJS = bool_tree$o bool_parser$o bool_optimiser$o bool_tester$o \
+	    term_lists$o stemmer$o stem_search$o mg_errors$o query_term_list$o \
+	    words$o
+bool_tester$e: $(BOOL_OBJS)
+	$(LINK) $(BOOL_OBJS) $(LIBS)
+
+QUERY_OBJS = \
+	mgquery$o locallib$o lists$o \
+	query.ranked$o query.docnums$o stem_search$o \
+	environment$o commands$o weights$o text_get$o stemmer$o \
+	read_line$o mg_errors$o backend$o invf_get$o \
+	term_lists$o bool_tree$o bool_parser$o bool_optimiser$o bool_query$o \
+	query_term_list$o words$o
+mgquery$e: $(QUERY_OBJS)
+	$(LINK) $(READLINE) $(QUERY_OBJS) $(READLINE_LIBS) $(LIBS)
+
+commands$o : help.mg.h warranty.h conditions.h
+
+PASSES_OBJS = \
+	mg_passes$o text.pass1$o comp_dict$o stemmer$o \
+	text.pass2$o locallib$o \
+	ivf.pass1$o ivf.pass2$o mg.special$o mg_files$o \
+	words$o
+mg_passes$e: $(PASSES_OBJS)
+	$(LINK) $(PASSES_OBJS) $(LIBS)
+
+PASS_OBJS = \
+	words$o mgpass$o text.pass1$o comp_dict$o stemmer$o \
+	text.pass2$o locallib$o \
+	ivf.pass1$o ivf.pass2$o mg.special$o mg_files$o
+mgpass$e: $(PASS_OBJS)
+	$(LINK) $(PASS_OBJS) $(LIBS)
+
+LINK32_FLAGS=kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib\
+ advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib\
+ odbccp32.lib
+
+BUILDER_OBJS = \
+	builder$o
+builder$e: $(BUILDER_OBJS)
+	$(LINK) $(BUILDER_OBJS) $(LIBS) $(LINK32_FLAGS)
+
+WEIGHTS_BUILD_OBJS = mg_weights_build$o mg_files$o
+mg_weights_build$e: $(WEIGHTS_BUILD_OBJS)
+	$(LINK) $(WEIGHTS_BUILD_OBJS) $(LIBS)
+
+COMP_DICT_OBJS = mg_compression_dict$o mg_files$o locallib$o
+mg_compression_dict$e: $(COMP_DICT_OBJS)
+	$(LINK) $(COMP_DICT_OBJS) $(LIBS)
+
+FAST_COMP_OBJS = mg_fast_comp_dict$o mg_files$o locallib$o
+mg_fast_comp_dict$e: $(FAST_COMP_OBJS)
+	$(LINK) $(FAST_COMP_OBJS) $(LIBS)
+
+TEXT_EST_OBJS = mg_text_estimate$o locallib$o comp_dict$o mg_files$o
+mg_text_estimate$e: $(TEXT_EST_OBJS)
+	$(LINK) $(TEXT_EST_OBJS) $(LIBS)
+
+STAT_OBJS = mgstat$o mg_files$o locallib$o
+mgstat$e: $(STAT_OBJS)
+	$(LINK) $(STAT_OBJS) $(LIBS)
+
+INVF_DUMP_OBJS = mg_invf_dump$o locallib$o mg_files$o
+mg_invf_dump$e: $(INVF_DUMP_OBJS)
+	$(LINK) $(INVF_DUMP_OBJS) $(LIBS)
+
+INVF_DICT_OBJS = mg_invf_dict$o mg_files$o locallib$o
+mg_invf_dict$e: $(INVF_DICT_OBJS)
+	$(LINK) $(INVF_DICT_OBJS) $(LIBS)
+
+INVF_REB_OBJS = mg_invf_rebuild$o locallib$o
+mg_invf_rebuild$e: $(INVF_REB_OBJS)
+	$(LINK) $(INVF_REB_OBJS) $(LIBS)
+
+DICTLIST_OBJS = mgdictlist$o locallib$o
+mgdictlist$e: $(DICTLIST_OBJS)
+	$(LINK) $(DICTLIST_OBJS) $(LIBS)
+
+PERF_HASH_OBJS = mg_perf_hash_build$o mg_files$o
+mg_perf_hash_build$e: $(PERF_HASH_OBJS)
+	$(LINK) $(PERF_HASH_OBJS) $(LIBS)
+
+STEM_IDX_OBJS = mg_stem_idx$o mg_files$o stemmer$o locallib$o \
+                mg_errors$o term_lists$o
+mg_stem_idx$e: $(STEM_IDX_OBJS)
+	$(LINK) $(STEM_IDX_OBJS) $(LIBS)
+
+STEM_IDX_LIST_OBJS = mgstemidxlist$o mg_files$o
+mgstemidxlist$e: $(STEM_IDX_LIST_OBJS)
+	$(LINK) $(STEM_IDX_LIST_OBJS) $(LIBS)
+
+DECOMPRESS_TEXT_OBJS = mg_decompress_text$o query_term_list$o mg_files$o mg_errors$o \
+                       text_get$o locallib$o backend$o stem_search$o \
+                       term_lists$o stemmer$o weights$o invf_get$o lists$o
+mg_decompress_text$e: $(DECOMPRESS_TEXT_OBJS)
+	$(LINK) $(DECOMPRESS_TEXT_OBJS) $(LIBS)
+
+TEXT_MERGE_OBJS = mg_text_merge$o mg_files$o locallib$o
+mg_text_merge$e: $(TEXT_MERGE_OBJS)
+	$(LINK) $(TEXT_MERGE_OBJS) $(LIBS)
+
+INVF_MERGE_OBJS = mg_invf_merge$o mg_files$o locallib$o
+mg_invf_merge$e: $(INVF_MERGE_OBJS)
+	$(LINK) $(INVF_MERGE_OBJS) $(LIBS)
+
+install: 
+	if NOT EXIST $(GSDLHOME)\bin\windows mkdir $(GSDLHOME)\bin\windows
+	for %%i in ($(EXEC)) do \
+	  copy %%i $(GSDLHOME)\bin\windows
+
+LIB_OBJS = \
+	query_term_list$o \
+	locallib$o lists$o \
+	query.ranked$o query.docnums$o stem_search$o \
+	environment$o commands$o weights$o text_get$o stemmer$o \
+	read_line$o mg_errors$o backend$o invf_get$o \
+	term_lists$o bool_tree$o bool_parser$o bool_optimiser$o \
+	bool_query$o words$o
+
+libtextin.lib: $(LIB_OBJS)
+	del libtextin.lib
+	lib /out:libtextin.lib $(LIB_OBJS)
+
+clean:
+	del *$o 
+	del $(EXEC)
Index: /main/tags/2.25/gsdl/packages/mg/src/text/backend.c
===================================================================
--- /main/tags/2.25/gsdl/packages/mg/src/text/backend.c	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/mg/src/text/backend.c	(revision 21064)
@@ -0,0 +1,838 @@
+/**************************************************************************
+ *
+ * backend.c -- Underlying routines for mgquery
+ * Copyright (C) 1994  Neil Sharman
+ *
+ * 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.
+ *
+ * $Id$
+ *
+ **************************************************************************/
+
+#include "sysfuncs.h"
+
+#include "memlib.h"
+#include "messages.h"
+#include "timing.h"
+#include "filestats.h"
+#include "sptree.h"
+#include "netorder.h"  /* [RPAP - Jan 97: Endian Ordering] */
+
+
+#include "mg_files.h"
+#include "mg.h"
+#include "invf.h"
+#include "text.h"
+#include "lists.h"
+#include "backend.h"
+#include "stem_search.h"
+#include "invf_get.h"
+#include "text_get.h"
+#include "weights.h"
+#include "locallib.h"
+#include "mg_errors.h"
+
+
+static File *
+OpenFile (char *base, char *suffix, unsigned long magic, int *ok)
+{
+  char FileName[512];
+  File *F;
+  sprintf (FileName, "%s%s", base, suffix);
+  if (!(F = Fopen (FileName, "rb", 0)))  /* [RPAP - Feb 97: WIN32 Port] */
+    {
+      mg_errno = MG_NOFILE;
+      MgErrorData (FileName);
+      if (ok)
+	*ok = 0;
+      return (NULL);
+    }
+  if (magic)
+    {
+      unsigned long m;
+      if (fread ((char *) &m, sizeof (m), 1, F->f) == 0)
+	{
+	  mg_errno = MG_READERR;
+	  MgErrorData (FileName);
+	  if (ok)
+	    *ok = 0;
+	  Fclose (F);
+	  return (NULL);
+	}
+      NTOHUL(m);  /* [RPAP - Jan 97: Endian Ordering] */
+      if (m != magic)
+	{
+	  mg_errno = MG_BADMAGIC;
+	  MgErrorData (FileName);
+	  if (ok)
+	    *ok = 0;
+	  Fclose (F);
+	  return (NULL);
+	}
+    }
+  return (F);
+}
+
+
+static int 
+open_all_files (query_data * qd)
+{
+  int ok = 1;
+
+  qd->File_text = OpenFile (qd->textpathname, TEXT_SUFFIX, /* [RJM 06/97: text filename] */
+			    MAGIC_TEXT, &ok);
+  qd->File_fast_comp_dict = OpenFile (qd->textpathname, /* [RJM 06/97: text filename] */
+				      TEXT_DICT_FAST_SUFFIX, MAGIC_FAST_DICT, NULL);
+  if (!qd->File_fast_comp_dict)
+    {
+      qd->File_comp_dict = OpenFile (qd->textpathname, /* [RJM 06/97: text filename] */
+				     TEXT_DICT_SUFFIX, MAGIC_DICT, &ok);
+      qd->File_aux_dict = OpenFile (qd->textpathname, /* [RJM 06/97: text filename] */
+				    TEXT_DICT_AUX_SUFFIX, MAGIC_AUX_DICT, NULL);
+    }
+  else
+    qd->File_comp_dict = qd->File_aux_dict = NULL;
+
+  qd->File_stem = OpenFile (qd->pathname, INVF_DICT_BLOCKED_SUFFIX,
+			    MAGIC_STEM, &ok);
+
+  /* [RPAP - Jan 97: Stem Index Change]
+     These will fail if collection not built with stem indexes */
+  qd->File_stem1 = OpenFile (qd->pathname, INVF_DICT_BLOCKED_1_SUFFIX,
+			     MAGIC_STEM_1, NULL);
+  qd->File_stem2 = OpenFile (qd->pathname, INVF_DICT_BLOCKED_2_SUFFIX,
+			     MAGIC_STEM_2, NULL);
+  qd->File_stem3 = OpenFile (qd->pathname, INVF_DICT_BLOCKED_3_SUFFIX,
+			     MAGIC_STEM_3, NULL);
+
+  qd->File_invf = OpenFile (qd->pathname, INVF_SUFFIX,
+			    MAGIC_INVF, &ok);
+
+  /* These will fail if a level 1 inverted file was created because there 
+     will be no document weights */
+  qd->File_text_idx_wgt = OpenFile (qd->pathname, TEXT_IDX_WGT_SUFFIX,
+				    MAGIC_TEXI_WGT, NULL);
+  qd->File_weight_approx = OpenFile (qd->pathname, APPROX_WEIGHTS_SUFFIX,
+				     MAGIC_WGHT_APPROX, NULL);
+  if (qd->File_text_idx_wgt == NULL && qd->File_weight_approx == NULL)
+    qd->File_text_idx = OpenFile (qd->textpathname, /* [RJM 06/97: text filename] */
+				  TEXT_IDX_SUFFIX, MAGIC_TEXI, NULL);
+  else
+    qd->File_text_idx = NULL;
+
+
+  if (!ok)
+    {
+      Fclose (qd->File_text);
+      if (qd->File_fast_comp_dict)
+	Fclose (qd->File_fast_comp_dict);
+      if (qd->File_comp_dict)
+	Fclose (qd->File_comp_dict);
+      Fclose (qd->File_stem);
+
+      /* [RPAP - Jan 97: Stem Index Change] */
+      if (qd->File_stem1)
+	Fclose (qd->File_stem1);
+      if (qd->File_stem2)
+	Fclose (qd->File_stem2);
+      if (qd->File_stem3)
+	Fclose (qd->File_stem3);
+
+      Fclose (qd->File_invf);
+      if (qd->File_text_idx_wgt)
+	Fclose (qd->File_text_idx_wgt);
+      if (qd->File_weight_approx)
+	Fclose (qd->File_weight_approx);
+      if (qd->File_text_idx)
+	Fclose (qd->File_text_idx);
+      return (-1);
+    }
+  return (0);
+
+}
+
+static void 
+close_all_files (query_data * qd)
+{
+  Fclose (qd->File_text);
+  if (qd->File_fast_comp_dict)
+    Fclose (qd->File_fast_comp_dict);
+  if (qd->File_aux_dict)
+    Fclose (qd->File_aux_dict);
+  if (qd->File_comp_dict)
+    Fclose (qd->File_comp_dict);
+  Fclose (qd->File_stem);
+
+  /* [RPAP - Jan 97: Stem Index Change] */
+  if (qd->File_stem1)
+    Fclose (qd->File_stem1);
+  if (qd->File_stem2)
+    Fclose (qd->File_stem2);
+  if (qd->File_stem3)
+    Fclose (qd->File_stem3);
+
+  Fclose (qd->File_invf);
+  if (qd->File_text_idx_wgt)
+    Fclose (qd->File_text_idx_wgt);
+  if (qd->File_weight_approx)
+    Fclose (qd->File_weight_approx);
+  if (qd->File_text_idx)
+    Fclose (qd->File_text_idx);
+}
+
+/* If textname is equal to null then name will be used instead */
+/* [RJM 06/97: text filename] */
+query_data *
+InitQuerySystem (char *dir, char *name, char *textname, InitQueryTimes * iqt)
+{
+  query_data *qd;
+  char *s;
+
+  if (textname == NULL) textname = name; /* [RJM 06/97: text filename] */
+
+  if (!(qd = Xmalloc (sizeof (query_data))))
+    {
+      mg_errno = MG_NOMEM;
+      return (NULL);
+    }
+
+  bzero ((char *) qd, sizeof (*qd));
+
+  qd->mem_in_use = qd->max_mem_in_use = 0;
+
+  qd->doc_pos = qd->buf_in_use = 0;
+  qd->TextBufferLen = 0;
+  qd->DL = NULL;
+
+  /* [RPAP - Feb 97: Term Frequency] */
+  qd->TL = NULL;
+  qd->QTL = NULL;
+
+  qd->TextBuffer = NULL;
+
+  qd->tot_hops_taken = 0;
+  qd->tot_num_of_ptrs = 0;
+  qd->tot_num_of_accum = 0;
+  qd->tot_num_of_terms = 0;
+  qd->tot_num_of_ans = 0;
+  qd->tot_text_idx_lookups = 0;
+
+  qd->hops_taken = 0;
+  qd->num_of_ptrs = 0;
+  qd->num_of_accum = 0;
+  qd->num_of_terms = 0;
+  qd->num_of_ans = 0;
+  qd->text_idx_lookups = 0;
+
+  qd->pathname = NULL; /* RJM 06/97: text filename] */
+  qd->textpathname = NULL; /* RJM 06/97: text filename] */
+
+  s = strrchr (dir, '/');
+  if (s && *(s + 1) == '\0')
+    {
+      /* [RJM 06/97: text filename] */
+      if (!(qd->pathname = Xmalloc (strlen (dir) + strlen (name) + 1)) ||
+	  !(qd->textpathname = Xmalloc (strlen (dir) + strlen (textname) + 1)))
+	{
+	  mg_errno = MG_NOMEM;
+	  if (qd->pathname) Xfree (qd->pathname); /* [RJM 06/97: text filename] */
+	  Xfree (qd);
+	  return (NULL);
+	}
+      sprintf (qd->pathname, "%s%s", dir, name);
+      sprintf (qd->textpathname, "%s%s", dir, textname); /* [RJM 06/97: text filename] */
+    }
+
+  else
+    {
+      /* [RJM 06/97: text filename] */
+      if (!(qd->pathname = Xmalloc (strlen (dir) + strlen (name) + 2)) ||
+	  !(qd->textpathname = Xmalloc (strlen (dir) + strlen (textname) + 2)))
+	{
+	  mg_errno = MG_NOMEM;
+	  if (qd->pathname) Xfree (qd->pathname); /* [RJM 06/97: text filename] */
+	  Xfree (qd);
+	  return (NULL);
+	}
+/* [RPAP - Feb 97: WIN32 Port] */
+#ifdef __WIN32__
+      if (dir == NULL || dir[0] == '\0') {
+	sprintf (qd->pathname, "%s", name);
+	sprintf (qd->textpathname, "%s", textname); /* [RJM 06/97: text filename] */
+      } else {
+	sprintf (qd->pathname, "%s%s", dir, name);
+	sprintf (qd->textpathname, "%s%s", dir, textname); /* [RJM 06/97: text filename] */
+      }
+#else
+      sprintf (qd->pathname, "%s/%s", dir, name);
+      sprintf (qd->textpathname, "%s/%s", dir, textname); /* [RJM 06/97: text filename] */
+#endif
+    }
+
+  if (open_all_files (qd) == -1)
+    {
+      Xfree (qd->pathname);
+      Xfree (qd->textpathname); /* [RJM 06/97: text filename] */
+      Xfree (qd);
+      return (NULL);
+    }
+
+  if (iqt)
+    GetTime (&iqt->Start);
+
+  /* Initialise the stemmed dictionary system */
+  if (!(qd->sd = ReadStemDictBlk (qd->File_stem)))
+    {
+      close_all_files (qd);
+      Xfree (qd->pathname);
+      Xfree (qd->textpathname); /* [RJM 06/97: text filename] */
+      Xfree (qd);
+      return (NULL);
+    }
+
+  /* [RPAP - Jan 97: Stem Index Change] */
+  if ((qd->sd->sdh.indexed & 7) && qd->File_stem1 && qd->File_stem2 && qd->File_stem3)
+    {
+      if (!(qd->sd->stem1 = ReadStemIdxBlk (qd->File_stem1)))
+	{
+	  FreeStemDict (qd->sd);
+	  close_all_files (qd);
+	  Xfree (qd->pathname);
+	  Xfree (qd->textpathname); /* [RJM 06/97: text filename] */
+	  Xfree (qd);
+	  return (NULL);
+	}
+      if (!(qd->sd->stem2 = ReadStemIdxBlk (qd->File_stem2)))
+	{
+	  FreeStemDict (qd->sd);
+	  close_all_files (qd);
+	  Xfree (qd->pathname);
+	  Xfree (qd->textpathname); /* [RJM 06/97: text filename] */
+	  Xfree (qd);
+	  return (NULL);
+	}
+      if (!(qd->sd->stem3 = ReadStemIdxBlk (qd->File_stem3)))
+	{
+	  FreeStemDict (qd->sd);
+	  close_all_files (qd);
+	  Xfree (qd->pathname);
+	  Xfree (qd->textpathname); /* [RJM 06/97: text filename] */
+	  Xfree (qd);
+	  return (NULL);
+	}
+      }
+  else if (qd->sd->sdh.indexed != 0)
+    {
+      FreeStemDict (qd->sd);
+      close_all_files (qd);
+      Xfree (qd->pathname);
+      Xfree (qd->textpathname); /* [RJM 06/97: text filename] */
+      Xfree (qd);
+      return (NULL);
+    }
+  else
+    {
+      if (qd->File_stem1)
+	Fclose (qd->File_stem1);
+      if (qd->File_stem2)
+	Fclose (qd->File_stem2);
+      if (qd->File_stem3)
+	Fclose (qd->File_stem3);
+      qd->File_stem1 = NULL;
+      qd->File_stem2 = NULL;
+      qd->File_stem3 = NULL;
+      qd->sd->stem1 = NULL;
+      qd->sd->stem2 = NULL;
+      qd->sd->stem3 = NULL;
+    }
+
+  if (iqt)
+    GetTime (&iqt->StemDict);
+  if (qd->File_weight_approx)
+    {
+      if (!(qd->awd = LoadDocWeights (qd->File_weight_approx,
+				      qd->sd->sdh.num_of_docs)))
+	{
+	  FreeStemDict (qd->sd);
+	  close_all_files (qd);
+	  Xfree (qd->pathname);
+	  Xfree (qd->textpathname); /* [RJM 06/97: text filename] */
+	  Xfree (qd);
+	  return (NULL);
+	}
+    }
+  else
+    qd->awd = NULL;
+
+
+  if (iqt)
+    GetTime (&iqt->ApproxWeights);
+
+  if (!(qd->cd = LoadCompDict (qd->File_comp_dict, qd->File_aux_dict,
+			       qd->File_fast_comp_dict)))
+    {
+      if (qd->awd)
+	FreeWeights (qd->awd);
+      FreeStemDict (qd->sd);
+      close_all_files (qd);
+      Xfree (qd->pathname);
+      Xfree (qd->textpathname); /* [RJM 06/97: text filename] */
+      Xfree (qd);
+      return (NULL);
+    }
+
+  if (iqt)
+    GetTime (&iqt->CompDict);
+
+  if (!(qd->id = InitInvfFile (qd->File_invf, qd->sd)))
+    {
+      FreeCompDict (qd->cd);
+      if (qd->awd)
+	FreeWeights (qd->awd);
+      FreeStemDict (qd->sd);
+      close_all_files (qd);
+      Xfree (qd->pathname);
+      Xfree (qd->textpathname); /* [RJM 06/97: text filename] */
+      Xfree (qd);
+      return (NULL);
+    }
+  if ((qd->File_text_idx_wgt == NULL || qd->File_weight_approx == NULL) &&
+      qd->id->ifh.InvfLevel >= 2)
+    {
+      FreeInvfData (qd->id);
+      FreeCompDict (qd->cd);
+      if (qd->awd)
+	FreeWeights (qd->awd);
+      FreeStemDict (qd->sd);
+      close_all_files (qd);
+      Xfree (qd->pathname);
+      Xfree (qd->textpathname); /* [RJM 06/97: text filename] */
+      Xfree (qd);
+      mg_errno = MG_INVERSION;
+      return (NULL);
+    }
+  if (iqt)
+    GetTime (&iqt->Invf);
+
+  if (!(qd->td = LoadTextData (qd->File_text, qd->File_text_idx_wgt,
+			       qd->File_text_idx)))
+    {
+      FreeInvfData (qd->id);
+      FreeCompDict (qd->cd);
+      if (qd->awd)
+	FreeWeights (qd->awd);
+      FreeStemDict (qd->sd);
+      close_all_files (qd);
+      Xfree (qd->pathname);
+      Xfree (qd->textpathname); /* [RJM 06/97: text filename] */
+      Xfree (qd);
+      return (NULL);
+    }
+
+/* [RPAP - Feb 97: NZDL Additions] */
+#if defined(PARADOCNUM) || defined(NZDL)
+
+/*
+
+This code is based on the TREC_MODE code below to read the .paragraph
+file to determine what document numbers correspond to what paragraphs.
+This code is more space efficient, reading in the .paragraph file
+into memory as an accumulate docnum array.  Eg.  the .paragraph may contain
+
+	[5 3 6 4 7 9 4]
+
+indicating the first document has 5 paragraphs, the next 3, etc.
+This will be stored in memory as
+
+	[0 5 8 14 18 25 34 38]
+
+so a binary search can be performed.  The first 0 is for convenience;
+it prevents testing boundary conditions.
+
+
+The TREC_MODE code does this differently; it stores the array
+
+	[1 1 1 1 1 2 2 2 3 3 3 3 3 3 ....]
+
+allowing directy paragraph to docnum conversion, at the expense
+of memory.
+
+*/ 
+  qd->paragraph = NULL;
+
+  if (qd->id->ifh.InvfLevel == 3)
+    {
+      unsigned long magic;
+      FILE *paragraph;
+      int i;
+      char paraFile[512];
+
+      sprintf(paraFile, "%s%s", qd->pathname, INVF_PARAGRAPH_SUFFIX);
+      paragraph = fopen(paraFile, "rb");
+      if (!paragraph)
+	FatalError(1, "Unable to open 'paraFile'.", paraFile);
+
+      fread((void *)&magic, sizeof(magic), 1, paragraph);
+      qd->paragraph = Xmalloc((qd->td->cth.num_of_docs+1)*sizeof(int));
+      qd->paragraph[0] = 0;
+      for (i = 1; i <= qd->td->cth.num_of_docs; i++)
+	{
+	  int count;
+
+	  if (fread((void *)&count, sizeof(count), 1, paragraph) != 1)
+	    FatalError(1, "Unexpected EOF while reading '%s'.", paraFile);
+	  NTOHSI(count);  /* [RPAP - Jan 97: Endian Ordering] */
+	  qd->paragraph[i] = qd->paragraph[i-1]+count;
+	}
+
+      fclose (paragraph); /* [RJM 07/98: Memory Leak] */
+    }
+  
+  
+#endif
+
+#ifdef TREC_MODE
+  {
+    extern char *trec_ids;
+    extern long *trec_paras;
+    int size;
+    char FileName[512];
+    FILE *f;
+    if (!strstr (qd->pathname, "trec"))
+      goto error;
+    sprintf (FileName, "%s%s", qd->pathname, ".DOCIDS");
+    if (!(f = fopen (FileName, "rb")))  /* [RPAP - Feb 97: WIN32 Port] */
+      {
+	Message ("Unable to open \"%s\"", FileName);
+	goto error;
+      }
+    fseek (f, 0, 2);
+    size = ftell (f);
+    fseek (f, 0, 0);
+    trec_ids = Xmalloc (size);
+    if (!trec_ids)
+      {
+	fclose (f);
+	goto error;
+      }
+    fread (trec_ids, 1, size, f);
+    fclose (f);
+    if (qd->id->ifh.InvfLevel == 3)
+      {
+	int i, d;
+	unsigned long magic;
+	trec_paras = Xmalloc (qd->sd->sdh.num_of_docs * sizeof (long));
+	if (!trec_paras)
+	  {
+	    Xfree (trec_ids);
+	    trec_ids = NULL;
+	    goto error;
+	  }
+	sprintf (FileName, "%s%s", qd->pathname, INVF_PARAGRAPH_SUFFIX);
+	if (!(f = fopen (FileName, "rb")))  /* [RPAP - Feb 97: WIN32 Port] */
+	  {
+	    Message ("Unable to open \"%s\"", FileName);
+	    goto error;
+	  }
+	if (fread ((char *) &magic, sizeof (magic), 1, f) != 1 ||
+	    NTOHUL(magic) != MAGIC_PARAGRAPH)  /* [RPAP - Jan 97: Endian Ordering] */
+	  {
+	    fclose (f);
+	    Message ("Bad magic number in \"%s\"", FileName);
+	    goto error;
+	  }
+
+	for (d = i = 0; i < qd->td->cth.num_of_docs; i++)
+	  {
+	    int count;
+	    if (fread ((char *) &count, sizeof (count), 1, f) != 1)
+	      {
+		fclose (f);
+		goto error;
+	      }
+	    NTOHSI(count);  /* [RPAP - Jan 97: Endian Ordering] */
+	    while (count--)
+	      trec_paras[d++] = i;
+	  }
+	fclose (f);
+      }
+    goto ok;
+  error:
+    if (trec_ids)
+      Xfree (trec_ids);
+    if (trec_paras)
+      Xfree (trec_paras);
+    trec_ids = NULL;
+    trec_paras = NULL;
+  ok:
+    ;
+  }
+#endif
+
+  if (iqt)
+    GetTime (&iqt->Text);
+
+  return (qd);
+}
+
+
+
+
+
+
+/*
+ * Change the amount of memory currently in use
+ *
+ */
+void 
+ChangeMemInUse (query_data * qd, long delta)
+{
+  qd->mem_in_use += delta;
+  if (qd->mem_in_use > qd->max_mem_in_use)
+    qd->max_mem_in_use = qd->mem_in_use;
+}
+
+
+void 
+FinishQuerySystem (query_data * qd)
+{
+/* [RJM 07/98: Memory Leak] */
+#if defined(PARADOCNUM) || defined(NZDL)
+  if (qd->paragraph != NULL) {
+    Xfree (qd->paragraph);
+    qd->paragraph = NULL;
+  }
+#endif
+
+  FreeTextData (qd->td);
+  FreeInvfData (qd->id);
+  FreeCompDict (qd->cd);
+  if (qd->awd)
+    FreeWeights (qd->awd);
+  FreeStemDict (qd->sd);
+  close_all_files (qd);
+  Xfree (qd->textpathname); /* [RJM 06/97: text filename] */
+  Xfree (qd->pathname);
+  FreeQueryDocs (qd);
+  if (qd->TL != NULL) FreeTermList(&qd->TL);         /* [RJM 07/98: Memory Leak] */
+  if (qd->QTL != NULL) FreeQueryTermList(&qd->QTL);  /* [RJM 07/98: Memory Leak] */
+  Xfree (qd);
+
+  /* other global stuff hanging around */
+  MgErrorDeinit ();
+}
+
+
+void 
+ResetFileStats (query_data * qd)
+{
+  ZeroFileStats (qd->File_text);
+  if (qd->File_comp_dict)
+    ZeroFileStats (qd->File_comp_dict);
+  if (qd->File_fast_comp_dict)
+    ZeroFileStats (qd->File_fast_comp_dict);
+  ZeroFileStats (qd->File_stem);
+
+  /* [RPAP - Jan 97: Stem Index Change] */
+  if (qd->File_stem1)
+    ZeroFileStats (qd->File_stem1);
+  if (qd->File_stem2)
+    ZeroFileStats (qd->File_stem2);
+  if (qd->File_stem3)
+    ZeroFileStats (qd->File_stem3);
+
+  ZeroFileStats (qd->File_invf);
+  if (qd->File_text_idx_wgt)
+    ZeroFileStats (qd->File_text_idx_wgt);
+  if (qd->File_weight_approx)
+    ZeroFileStats (qd->File_weight_approx);
+  if (qd->File_text_idx)
+    ZeroFileStats (qd->File_text_idx);
+}
+
+
+void 
+TransFileStats (query_data * qd)
+{
+  qd->File_text->Current = qd->File_text->Cumulative;
+  if (qd->File_comp_dict)
+    qd->File_comp_dict->Current = qd->File_comp_dict->Cumulative;
+  if (qd->File_fast_comp_dict)
+    qd->File_fast_comp_dict->Current = qd->File_fast_comp_dict->Cumulative;
+  qd->File_stem->Current = qd->File_stem->Cumulative;
+
+  /* [RPAP - Jan 97: Stem Index Change] */
+  if (qd->File_stem1)
+    qd->File_stem1->Current = qd->File_stem1->Cumulative;
+  if (qd->File_stem2)
+    qd->File_stem2->Current = qd->File_stem2->Cumulative;
+  if (qd->File_stem3)
+    qd->File_stem3->Current = qd->File_stem3->Cumulative;
+
+  qd->File_invf->Current = qd->File_invf->Cumulative;
+  if (qd->File_text_idx_wgt)
+    qd->File_text_idx_wgt->Current = qd->File_text_idx_wgt->Cumulative;
+  if (qd->File_weight_approx)
+    qd->File_weight_approx->Current = qd->File_weight_approx->Cumulative;
+  if (qd->File_text_idx)
+    qd->File_text_idx->Current = qd->File_text_idx->Cumulative;
+}
+
+
+void 
+FreeTextBuffer (query_data * qd)
+{
+  if (qd->TextBuffer)
+    {
+      Xfree (qd->TextBuffer);
+      ChangeMemInUse (qd, -qd->TextBufferLen);
+    }
+  qd->TextBuffer = NULL;
+  qd->TextBufferLen = 0;
+}
+
+void 
+FreeQueryDocs (query_data * qd)
+{
+  qd->doc_pos = 0;
+  qd->buf_in_use = 0;
+  if (qd->DL)
+    {
+      int i;
+      for (i = 0; i < qd->DL->num; i++)
+	if (qd->DL->DE[i].CompTextBuffer)
+	  {
+	    Xfree (qd->DL->DE[i].CompTextBuffer);
+	    qd->DL->DE[i].CompTextBuffer = NULL;
+	    ChangeMemInUse (qd, -qd->DL->DE[i].Len);
+	  }
+      Xfree (qd->DL);
+    }
+  qd->DL = NULL;
+  FreeTextBuffer (qd);
+}
+
+int 
+LoadCompressedText (query_data * qd, int max_mem)
+{
+  DocEntry *DE;
+  if (qd->DL == NULL || qd->doc_pos >= qd->DL->num)
+    return -1;
+
+  DE = &qd->DL->DE[qd->doc_pos];
+  if (!DE->CompTextBuffer)
+    {
+      int i;
+      DocEntry *de;
+      for (i = 0, de = qd->DL->DE; i < qd->DL->num; i++, de++)
+	if (de->CompTextBuffer)
+	  {
+	    Xfree (de->CompTextBuffer);
+	    de->CompTextBuffer = NULL;
+	    ChangeMemInUse (qd, -de->Len);
+	  }
+      if (LoadBuffers (qd, &qd->DL->DE[qd->doc_pos], max_mem,
+		       qd->DL->num - qd->doc_pos) == -1)
+	return -1;
+    }
+  return 0;
+}
+
+int 
+GetDocNum (query_data * qd)
+{
+  if (qd->DL == NULL || qd->doc_pos >= qd->DL->num)
+    return -1;
+  return qd->DL->DE[qd->doc_pos].DocNum;
+}
+
+DocEntry *
+GetDocChain (query_data * qd)
+{
+  if (qd->DL == NULL || qd->doc_pos >= qd->DL->num)
+    return NULL;
+  return &(qd->DL->DE[qd->doc_pos]);
+}
+
+float 
+GetDocWeight (query_data * qd)
+{
+  if (qd->DL == NULL || qd->doc_pos >= qd->DL->num)
+    return -1;
+  return qd->DL->DE[qd->doc_pos].Weight;
+}
+
+long 
+GetDocCompLength (query_data * qd)
+{
+  if (qd->DL == NULL || qd->doc_pos >= qd->DL->num)
+    return -1;
+  return qd->DL->DE[qd->doc_pos].Len;
+}
+
+
+u_char *
+GetDocText (query_data * qd, unsigned long *len)
+{
+  DocEntry *DE;
+  int ULen;
+  if (qd->DL == NULL || qd->doc_pos >= qd->DL->num)
+    return NULL;
+
+  DE = &qd->DL->DE[qd->doc_pos];
+
+  if (!DE->CompTextBuffer)
+    {
+      fprintf (stderr, "The compressed text buffer is NULL\n");
+      mg_errno = MG_NOMEM;
+      return (NULL);
+    }
+
+  FreeTextBuffer (qd);
+
+  qd->TextBufferLen = (int) (qd->td->cth.ratio * 1.01 *
+			     DE->Len) + 100;
+  if (!(qd->TextBuffer = Xmalloc (qd->TextBufferLen)))
+    {
+      fprintf (stderr, "No memory for TextBuffer\n");
+      mg_errno = MG_NOMEM;
+      return (NULL);
+    }
+
+  DecodeText (qd->cd, (u_char *) (DE->CompTextBuffer), DE->Len,
+	      (u_char *) (qd->TextBuffer), &ULen);
+  qd->TextBuffer[ULen] = '\0';
+
+  if (ULen >= qd->TextBufferLen)
+    {
+      fprintf (stderr, "%d >= %d\n", ULen, qd->TextBufferLen);
+      mg_errno = MG_BUFTOOSMALL;
+      return (NULL);
+    }
+
+  if (len)
+    *len = ULen;
+
+  return qd->TextBuffer;
+}
+
+int 
+NextDoc (query_data * qd)
+{
+  if (qd->DL == NULL || qd->doc_pos >= qd->DL->num)
+    return 0;
+  qd->doc_pos++;
+  return qd->doc_pos < qd->DL->num;
+}
Index: /main/tags/2.25/gsdl/packages/mg/src/text/backend.h
===================================================================
--- /main/tags/2.25/gsdl/packages/mg/src/text/backend.h	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/mg/src/text/backend.h	(revision 21064)
@@ -0,0 +1,263 @@
+/**************************************************************************
+ *
+ * backend.h -- Underlying routines and datastructures for mgquery
+ * Copyright (C) 1994  Neil Sharman
+ *
+ * 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.
+ *
+ * $Id$
+ *
+ **************************************************************************/
+
+
+#ifndef BACKEND_H
+#define BACKEND_H
+
+#include "sysfuncs.h"
+
+#include "timing.h"
+#include "lists.h"
+#include "term_lists.h"
+#include "query_term_list.h"  /* [RPAP - Feb 97: Term Frequency] */
+#include "mg.h"
+#include "invf.h"
+#include "text.h"
+
+
+typedef struct invf_data
+  {
+    File *InvfFile;
+    unsigned long N;
+    unsigned long Nstatic;	/* N parameter for decoding inverted file entries */
+    struct invf_file_header ifh;
+  }
+invf_data;
+
+typedef struct text_data
+  {
+    File *TextFile;
+    File *TextIdxFile;
+    File *TextIdxWgtFile;
+    long current_pos;
+    struct
+      {
+	unsigned long Start;
+	float Weight;
+      }
+     *idx_data;
+    compressed_text_header cth;
+  }
+text_data;
+
+
+typedef struct auxiliary_dict
+  {
+    aux_frags_header afh[2];
+    u_char *word_data[2];
+    u_char **words[2];
+    int blk_start[2][33], blk_end[2][33];	/* blk_start and blk_end are required
+						   for the hybrid methods */
+  }
+auxiliary_dict;
+
+
+typedef struct compression_dict
+  {
+    compression_dict_header cdh;
+    comp_frags_header *cfh[2];
+    unsigned long MemForCompDict;
+    u_char ***values[2];
+    u_char *escape[2];
+    huff_data *chars_huff[2];
+    u_long **chars_vals[2];
+    huff_data *lens_huff[2];
+    u_long **lens_vals[2];
+    auxiliary_dict *ad;
+    int fast_loaded;
+  }
+compression_dict;
+
+
+typedef struct stemmed_idx   /* [RPAP - Jan 97: Stem Index Change] */
+  {
+    File *stem_idx_file;
+    struct stem_idx_header sih;
+    u_char **index;
+    unsigned long *pos;
+    int active;
+    u_char *buffer;
+    unsigned long MemForStemIdx;
+  }
+stemmed_idx;
+
+
+typedef struct stemmed_dict
+  {
+    File *stem_file;
+    struct stem_dict_header sdh;
+    u_char **index;
+    unsigned long *pos;
+    int active;
+    u_char *buffer;
+    unsigned long MemForStemDict;
+
+    /* [RPAP - Jan 97: Stem Index Change] */
+    stemmed_idx *stem1;
+    stemmed_idx *stem2;
+    stemmed_idx *stem3;
+  }
+stemmed_dict;
+
+
+typedef struct approx_weights_data
+  {
+    double L;
+    double B;
+    unsigned long *DocWeights;
+    char bits;
+    float *table;
+    unsigned long mask;
+    unsigned long MemForWeights;
+    unsigned long num_of_docs;
+  }
+approx_weights_data;
+
+
+typedef struct RankedQueryInfo
+  {
+    int QueryFreqs;
+    int Exact;           /* use exact weights for ranking or not */
+    long MaxDocsToRetrieve;	/* may be -1 for all */
+    long MaxParasToRetrieve;
+    int Sort;        
+    char AccumMethod;		/* 'A' = array,  'S' = splay tree,  'H' = hash_table */
+    long MaxAccums;		/* may be -1 for all */
+    long MaxTerms;		/* may be -1 for all */
+    int StopAtMaxAccum; /* Stop at maximum accumulator or not */
+    long HashTblSize;
+    char *skip_dump;
+  }
+RankedQueryInfo;
+
+
+
+typedef struct BooleanQueryInfo
+  {
+    long MaxDocsToRetrieve;
+  }
+BooleanQueryInfo;
+
+
+/* [TS:24/Aug/94] - maximum number of characters in term string */
+#define MAXTERMSTRLEN 1023
+
+typedef struct query_data
+  {
+    stemmed_dict *sd;
+    compression_dict *cd;
+    approx_weights_data *awd;
+    invf_data *id;
+    text_data *td;
+#if defined(PARADOCNUM) || defined(NZDL)
+    int *paragraph;
+#endif
+    char *pathname;
+    char *textpathname; /* [RJM 06/97: text filename] */
+    File *File_text;
+    File *File_comp_dict;
+    File *File_aux_dict;
+    File *File_fast_comp_dict;
+    File *File_text_idx_wgt;
+    File *File_text_idx;
+    File *File_stem;
+
+    /* [RPAP - Jan 97: Stem Index Change] */
+    File *File_stem1;
+    File *File_stem2;
+    File *File_stem3;
+
+    File *File_invf;
+    File *File_weight_approx;
+    unsigned long mem_in_use, max_mem_in_use;
+    unsigned long num_of_ptrs, tot_num_of_ptrs;
+    unsigned long num_of_terms, tot_num_of_terms;
+    unsigned long num_of_accum, tot_num_of_accum;
+    unsigned long num_of_ans, tot_num_of_ans;
+    unsigned long hops_taken, tot_hops_taken;
+    unsigned long text_idx_lookups, tot_text_idx_lookups;
+    unsigned long max_buffers;
+    unsigned doc_pos;
+    unsigned buf_in_use;
+    DocList *DL;
+    TermList *TL;		/* [TS:Oct/94] - so term list for query can easily be accessed */
+    u_char *TextBuffer;
+    int TextBufferLen;
+    QueryTermList *QTL;    /* [RPAP - Feb 97: Term Frequency] */
+  }
+query_data;
+
+
+
+typedef struct InitQueryTimes
+  {
+    ProgTime Start;
+    ProgTime StemDict;
+    ProgTime ApproxWeights;
+    ProgTime CompDict;
+    ProgTime Invf;
+    ProgTime Text;
+  }
+InitQueryTimes;
+
+
+/* [RJM 06/97: text filename] */
+query_data *InitQuerySystem (char *dir, char *name, char *textname, InitQueryTimes * iqt);
+
+void ChangeMemInUse (query_data * qd, long delta);
+
+void FinishQuerySystem (query_data * qd);
+
+void ResetFileStats (query_data * qd);
+
+void TransFileStats (query_data * qd);
+
+void ChangeMemInUse (query_data * qd, long delta);
+
+void RankedQuery (query_data * qd, char *Query, RankedQueryInfo * rqi);
+
+void BooleanQuery (query_data * qd, char *Query, BooleanQueryInfo * bqi,
+		   int stem_method);
+
+void DocnumsQuery (query_data * qd, char *QueryLine);
+
+void FreeTextBuffer (query_data * qd);
+
+void FreeQueryDocs (query_data * qd);
+
+int LoadCompressedText (query_data * qd, int max_mem);
+
+int GetDocNum (query_data * qd);
+
+float GetDocWeight (query_data * qd);
+
+long GetDocCompLength (query_data * qd);
+
+u_char *GetDocText (query_data * qd, unsigned long *len);
+
+DocEntry *GetDocChain (query_data * qd);
+
+int NextDoc (query_data * qd);
+
+#endif
Index: /main/tags/2.25/gsdl/packages/mg/src/text/bool_optimiser.c
===================================================================
--- /main/tags/2.25/gsdl/packages/mg/src/text/bool_optimiser.c	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/mg/src/text/bool_optimiser.c	(revision 21064)
@@ -0,0 +1,1108 @@
+/**************************************************************************
+ *
+ * bool_optimiser -- optimise boolean parse tree
+ * Copyright (C) 1994,95  Tim Shimmin
+ *
+ * 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.
+ *
+ * $Id$
+ *
+ **************************************************************************/
+
+/*
+   $Log$
+   Revision 1.1  1999/08/10 21:17:42  sjboddie
+   renamed mg-1.3d directory mg
+
+   Revision 1.1  1998/11/17 09:34:20  rjmcnab
+   *** empty log message ***
+
+   * Revision 1.4  1995/07/27  04:54:55  tes
+   * Committing optimiser before I add the code
+   * to find diff-nodes in any kind of tree.
+   *
+   * Revision 1.3  1994/10/20  00:02:55  tes
+   * Fixed bug with bool_optimiser:
+   *   - it couldn't handle "false | false"
+   *   - it couldn't handle "true & true"
+   * These would collapse into an empty list and cause an error.
+   *
+   * Revision 1.2  1994/10/18  06:11:02  tes
+   * The boolean optimiser seems to be modifying the parse tree
+   * like it is supposed to.
+   * Paragraph ranking now works without any text files if required to.
+   *
+   * Revision 1.1  1994/10/12  01:15:28  tes
+   * Found bugs in the existing boolean query optimiser.
+   * So decided to rewrite it.
+   * I accidentally deleted query.bool.y, but I have replaced it
+   * with bool_parser.y (which I have forgotten to add here ! ;-(
+   *
+ */
+
+static char *RCSID = "$Id$";
+
+#include "sysfuncs.h"
+
+#include "memlib.h"
+#include "bool_tree.h"
+#include "term_lists.h"
+#include "messages.h"
+
+typedef int (*CompFunc) (const void *, const void *);
+typedef void (*TreeFunc) (bool_tree_node *);
+
+/* --- routines --- */
+static void PermeateNots (bool_tree_node * tree);
+static void DoubleNeg (bool_tree_node * not_tree);
+static void AndDeMorgan (bool_tree_node * not_tree);
+static void OrDeMorgan (bool_tree_node * not_tree);
+static int AndDistribute (bool_tree_node * tree);
+static void DNF_Distribute (bool_tree_node * tree);
+static void ReplaceWithChildren (bool_tree_node * tree);
+static void CollapseTree (bool_tree_node * tree);
+static void AndTrueFalse (bool_tree_node * and_tree);
+static void OrTrueFalse (bool_tree_node * or_tree);
+static void TF_Idempotent (bool_tree_node * tree);
+static void AndNotToDiff (bool_tree_node * and_tree, TreeFunc recurs_func);
+static void DiffDNF (bool_tree_node * or_node);
+static void DiffTree (bool_tree_node * tree);
+static void AndSort (bool_tree_node * and_tree, TermList * tl, CompFunc comp);
+static void AndOrSort (bool_tree_node * tree, TermList * tl);
+static void AndSortDNF (bool_tree_node * or_node, TermList * tl);
+static void MarkOrTerms (bool_tree_node * tree, TermList * tl);
+static int calc_sum_ft (bool_tree_node * term_tree, TermList * tl);
+static int AndOrSort_comp (const void *A, const void *B);
+static int AndSort_comp (const void *A, const void *B);
+
+/* =========================================================================
+ * Function: OptimiseBoolTree
+ * Description: 
+ *      For case 2:
+ *        Do three major steps:
+ *        (i) put into standard form
+ *            -> put into DNF (disjunctive normal form - or of ands)
+ *            Use DeMorgan's, Double-negative, Distributive rules
+ *        (ii) simplify
+ *             apply idempotency rules
+ *        (iii) ameliorate
+ *              convert &! to diff nodes, order terms by frequency,...
+ *     Could also do the matching idempotency laws i.e. ...
+ *     (A | A), (A | !A), (A & !A), (A & A), (A & (A | B)), (A | (A & B)) 
+ *     Job for future.... ;-) 
+ * Input: 
+ * Output: 
+ * ========================================================================= */
+
+void
+OptimiseBoolTree (bool_tree_node * parse_tree, TermList * tl, int type)
+{
+  switch (type)
+    {
+    case 1:
+      /* --- sorts for and of or-terms --- */
+      PermeateNots (parse_tree);
+      TF_Idempotent (parse_tree);
+      CollapseTree (parse_tree);
+      DiffTree (parse_tree);
+      MarkOrTerms (parse_tree, tl);
+      AndOrSort (parse_tree, tl);
+      break;
+    case 2:
+      /* --- put into DNF --- */
+      PermeateNots (parse_tree);
+      TF_Idempotent (parse_tree);
+      DNF_Distribute (parse_tree);
+      CollapseTree (parse_tree);
+      AndSortDNF (parse_tree, tl);
+      DiffDNF (parse_tree);
+      break;
+    default:
+      /* --- do nothing --- */
+      break;
+    }				/*switch */
+}				/*OptimiseBoolTree */
+
+/* =========================================================================
+ * Function: DoubleNeg
+ * Description: 
+ *      !(!(a) = a
+ *      Assumes binary tree.
+ * Input: 
+ * Output: 
+ * ========================================================================= */
+static void
+DoubleNeg (bool_tree_node * not_tree)
+{
+  bool_tree_node *child = BOOL_CHILD (not_tree);
+  bool_tree_node *a = BOOL_CHILD (child);
+  bool_tree_node *sibling = BOOL_SIBLING (not_tree);
+
+  /* copy a into not tree */
+  bcopy (a, not_tree, sizeof (bool_tree_node));
+
+  BOOL_SIBLING (not_tree) = sibling;
+
+  Xfree (child);
+  Xfree (a);
+
+}
+
+/* =========================================================================
+ * Function: AndDeMorgan
+ * Description: 
+ *      DeMorgan's rule for 'not' of an 'and'  i.e. !(a & b) <=> (!a) | (!b)
+ *      Assumes Binary Tree
+ * Input: 
+ *      not of and tree
+ * Output: 
+ *      or of not trees
+ * ========================================================================= */
+
+static void
+AndDeMorgan (bool_tree_node * not_tree)
+{
+  bool_tree_node *child = BOOL_CHILD (not_tree);
+  bool_tree_node *a = BOOL_CHILD (child);
+  bool_tree_node *b = BOOL_SIBLING (a);
+  bool_tree_node *new_not = NULL;
+
+  /* change 'not' to 'or' */
+  BOOL_TAG (not_tree) = N_or;
+
+  /* change 'and' to 'not' */
+  BOOL_TAG (child) = N_not;
+
+  /* 'a' no longer has a sibling */
+  BOOL_SIBLING (a) = NULL;
+
+  /* 'a's old sibling is now a child of a new not */
+  new_not = CreateBoolTreeNode (N_not, b, NULL);
+  BOOL_SIBLING (child) = new_not;
+}
+
+/* =========================================================================
+ * Function: OrDeMorgan
+ * Description: 
+ *      DeMorgan's rule for 'not' of an 'or' i.e. !(a | b) <=> (!a) & (!b)
+ *      Assumes Binary Tree
+ * Input: 
+ *      not of and tree
+ * Output: 
+ *      or of not trees
+ * ========================================================================= */
+
+static void
+OrDeMorgan (bool_tree_node * not_tree)
+{
+  bool_tree_node *child = BOOL_CHILD (not_tree);
+  bool_tree_node *a = BOOL_CHILD (child);
+  bool_tree_node *b = BOOL_SIBLING (a);
+  bool_tree_node *new_not = NULL;
+
+  /* change 'not' to 'and' */
+  BOOL_TAG (not_tree) = N_and;
+
+  /* change 'or' to 'not' */
+  BOOL_TAG (child) = N_not;
+
+  /* 'a' no longer has a sibling */
+  BOOL_SIBLING (a) = NULL;
+
+  /* 'a's old sibling is now a child of a new not */
+  new_not = CreateBoolTreeNode (N_not, b, NULL);
+  BOOL_SIBLING (child) = new_not;
+}
+
+/* =========================================================================
+ * Function: PermeateNots
+ * Description: 
+ *      Use DeMorgan's and Double-negative
+ *      Assumes tree in binary form (i.e. No ands/ors collapsed)
+ * Input: 
+ * Output: 
+ * ========================================================================= */
+
+static void
+PermeateNots (bool_tree_node * tree)
+{
+  if (!tree)
+    return;
+
+  if (BOOL_TAG (tree) == N_not)
+    {
+      switch (BOOL_TAG (BOOL_CHILD (tree)))
+	{
+	case N_not:
+	  DoubleNeg (tree);
+/** NOTE: I do not go on to do the children **/
+	  /* I permeate the nots on the tree here & leave it at that */
+	  /* In this case I do not know what type 'tree' will end up */
+	  PermeateNots (tree);
+	  return;
+	case N_and:
+	  AndDeMorgan (tree);
+	  break;
+	case N_or:
+	  OrDeMorgan (tree);
+	  break;
+	default:
+	  /* leave alone */
+	  break;
+	}
+    }
+
+  /* Permeate Nots for children */
+  if (BOOL_HAS_CHILD (tree))
+    {
+      PermeateNots (BOOL_CHILD (tree));
+      PermeateNots (BOOL_SIBLING (BOOL_CHILD (tree)));
+    }
+
+}
+
+/* =========================================================================
+ * Function: DNF_Distribute
+ * Description: 
+ * Input: 
+ * Output: 
+ * ========================================================================= */
+
+
+#define ITER_LIMIT 500		/* if reach limit then probably in trouble */
+
+static void
+DNF_Distribute (bool_tree_node * tree)
+{
+  int i = 0;
+
+  /* multiple passes until no change */
+  /* not very smart :-( */
+  while (1)
+    {
+      if (AndDistribute (tree) == 0)
+	return;
+      if (i == ITER_LIMIT)
+	FatalError (1, "DNF infinite loop");
+      i++;
+    }				/*while */
+
+}
+
+/* =========================================================================
+ * Function: AndDistribute
+ * Description: 
+ *      (a | b) & A <=> (a & A) | (b & A)
+ * Input: 
+ *      binary tree of "AND" , "OR"s.
+ * Output: 
+ *      return 1 if changed the tree
+ *      return 0 if there was NO change (no distributive rule to apply)
+ * ========================================================================= */
+
+static int
+AndDistribute (bool_tree_node * tree)
+{
+  if (!tree)
+    return 0;
+
+  if (BOOL_TAG (tree) != N_and)
+    {
+      /* try the children if got some */
+      if (BOOL_TAG (tree) == N_or)
+	{
+	  bool_tree_node *left_child = BOOL_CHILD (tree);
+	  int left = AndDistribute (left_child);
+	  int right = AndDistribute (BOOL_SIBLING (left_child));
+	  return (left || right);
+	}
+
+      /* no children, then no change */
+      return 0;
+    }
+
+  /* AND case */
+  {
+    /* we have to check the children to see if can distribute */
+    bool_tree_node *left_child = BOOL_CHILD (tree);
+    bool_tree_node *right_child = BOOL_SIBLING (left_child);
+    int swap = 0;
+
+    /* If "or" on the right side then do a swap */
+    /* This is done for code simplicity */
+    if (BOOL_TAG (right_child) == N_or)
+      {
+	/* do a swap */
+	bool_tree_node *temp;
+	temp = right_child;
+	right_child = left_child;
+	left_child = temp;
+
+	BOOL_SIBLING (left_child) = right_child;
+	BOOL_SIBLING (right_child) = NULL;
+	BOOL_CHILD (tree) = left_child;
+
+	swap = 1;
+      }
+
+    /* do the actual distribution */
+    if (swap || BOOL_TAG (left_child) == N_or)
+      {
+	bool_tree_node *A = right_child;
+	bool_tree_node *A_copy = CopyBoolTree (A);
+	bool_tree_node *a = BOOL_CHILD (left_child);
+	bool_tree_node *b = BOOL_SIBLING (a);
+
+	/* then can distribute away ... */
+	BOOL_TAG (tree) = N_or;
+	BOOL_TAG (left_child) = N_and;
+	BOOL_SIBLING (left_child) = CreateBoolTreeNode (N_and, b, A);
+	BOOL_SIBLING (a) = A_copy;
+
+	AndDistribute (tree);
+	return 1;
+      }
+
+    /* if "and" of something other than "or" s then try the children */
+    {
+      int left = AndDistribute (left_child);
+      int right = AndDistribute (right_child);
+      return (left || right);
+    }
+  }				/* AND case */
+
+}				/*AndDistribute */
+
+/* =========================================================================
+ * Function: CollapseTree
+ * Description: 
+ *      Collapse "and" and "or"s.
+ * Input: 
+ * Output: 
+ * ========================================================================= */
+
+static void
+CollapseTree (bool_tree_node * tree)
+{
+  if (!tree)
+    return;
+
+  if ((BOOL_TAG (tree) == N_and) || (BOOL_TAG (tree) == N_or))
+    {
+      bool_tree_node *child = BOOL_CHILD (tree);
+      while (child)
+	{
+	  while (BOOL_TAG (child) == BOOL_TAG (tree))
+	    {
+	      ReplaceWithChildren (child);
+	    }
+	  CollapseTree (child);
+	  child = BOOL_SIBLING (child);
+	}
+    }
+
+  /* assume "not"s permeated */
+  return;
+}
+
+/* =========================================================================
+ * Function: ReplaceWithChildren
+ * Description: 
+ * Input: 
+ * Output: 
+ * ========================================================================= */
+
+static void
+ReplaceWithChildren (bool_tree_node * tree)
+{
+  bool_tree_node *next = BOOL_SIBLING (tree);
+  bool_tree_node *child = BOOL_CHILD (tree);
+  bool_tree_node *last = LastBoolSibling (child);
+
+  bcopy ((char *) child, (char *) tree, sizeof (bool_tree_node));
+  Xfree (child);
+  BOOL_SIBLING (last) = next;
+
+}
+
+/* =========================================================================
+ * Function: TF_Idempotent
+ * Description: 
+ *      Applies Idempotency laws which refer to True or False (hence "TF")
+ *      uses the true or false idempotent rules
+ * Input: 
+ *      operates on n-ary trees (not restricted to binary)
+ * Output: 
+ * ========================================================================= */
+
+static void
+TF_Idempotent (bool_tree_node * tree)
+{
+  bool_tree_node *child = NULL;
+
+  while (tree)
+    {
+      if (BOOL_HAS_CHILD (tree))
+	{
+	  child = BOOL_CHILD (tree);
+	  TF_Idempotent (child);
+	}
+
+      /* --- process node --- */
+      switch (BOOL_TAG (tree))
+	{
+	case N_not:
+	  child = BOOL_CHILD (tree);
+
+	  /* if true then falsify */
+	  if (BOOL_TAG (child) == N_all)
+	    {
+	      BOOL_TAG (tree) = N_none;
+	      BOOL_CHILD (tree) = NULL;
+	      Xfree (child);
+	      break;
+	    }
+
+	  /* if false then trueify */
+	  if (BOOL_TAG (child) == N_none)
+	    {
+	      BOOL_TAG (tree) = N_all;
+	      BOOL_CHILD (tree) = NULL;
+	      Xfree (child);
+	      break;
+	    }
+
+	  break;
+	case N_and:
+	  AndTrueFalse (tree);
+	  break;
+	case N_or:
+	  OrTrueFalse (tree);
+	  break;
+
+	default:
+	  /* do nothing */
+	  break;
+	}			/*switch */
+
+      tree = BOOL_SIBLING (tree);
+    }				/*while */
+}				/*TF_Idempotent */
+
+/* =========================================================================
+ * Function: AndTrueFalse
+ * Description: 
+ *      If any "false" then falsify whole tree 
+ *      If any "true" then delete them
+ * Input: 
+ * Output: 
+ * ========================================================================= */
+
+static void
+AndTrueFalse (bool_tree_node * and_tree)
+{
+  bool_tree_node *child = BOOL_CHILD (and_tree);
+
+  bool_tree_node *prev = NULL;
+
+  while (child)
+    {
+      if (BOOL_TAG (child) == N_none)
+	{
+	  FreeBoolTree (&(BOOL_CHILD (and_tree)));
+	  BOOL_TAG (and_tree) = N_none;
+	  return;
+	}
+
+      if (BOOL_TAG (child) == N_all)
+	{
+	  bool_tree_node *sibling = BOOL_SIBLING (child);
+
+	  /* --- link over child --- */
+	  if (!prev)
+	    {
+	      BOOL_CHILD (and_tree) = sibling;
+	    }
+	  else
+	    {
+	      BOOL_SIBLING (prev) = sibling;
+	    }
+
+	  Xfree (child);
+	  child = sibling;
+	}
+      else
+	{
+	  prev = child;
+	  child = BOOL_SIBLING (child);
+	}
+    }				/*while */
+
+  child = BOOL_CHILD (and_tree);
+
+  /* if no children ... */
+  /* => all have been true */
+  if (!child)
+    {
+      BOOL_TAG (and_tree) = N_all;
+      return;
+    }
+
+  /* If only one child ... */
+  if (!BOOL_SIBLING (child))
+    {
+      /* replace the parent with child - move it up */
+      bool_tree_node *save_sibling = BOOL_SIBLING (and_tree);
+      bcopy ((char *) child, (char *) and_tree, sizeof (bool_tree_node));
+      BOOL_SIBLING (and_tree) = save_sibling;
+      Xfree (child);
+    }
+
+}				/*AndTrueFalse */
+
+/* =========================================================================
+ * Function: OrTrueFalse
+ * Description: 
+ *      If any "true" then trueify whole tree 
+ *      If any "false" then delete them 
+ *      ***** NOTE: This is a reflection of AndTrueFalse *****
+ * Input: 
+ * Output: 
+ * ========================================================================= */
+
+static void
+OrTrueFalse (bool_tree_node * or_tree)
+{
+  bool_tree_node *child = BOOL_CHILD (or_tree);
+
+  bool_tree_node *prev = NULL;
+
+  while (child)
+    {
+      if (BOOL_TAG (child) == N_all)
+	{
+	  FreeBoolTree (&(BOOL_CHILD (or_tree)));
+	  BOOL_TAG (or_tree) = N_all;
+	  return;
+	}
+
+      if (BOOL_TAG (child) == N_none)
+	{
+	  bool_tree_node *sibling = BOOL_SIBLING (child);
+	  if (!prev)
+	    {
+	      BOOL_CHILD (or_tree) = sibling;
+	    }
+	  else
+	    {
+	      BOOL_SIBLING (prev) = sibling;
+	    }
+	  Xfree (child);
+	  child = sibling;
+
+	}
+      else
+	{
+	  prev = child;
+	  child = BOOL_SIBLING (child);
+	}
+    }				/*while */
+
+  child = BOOL_CHILD (or_tree);
+
+  /* if no children ... */
+  /* => all have been false */
+  if (!child)
+    {
+      BOOL_TAG (or_tree) = N_none;
+      return;
+    }
+
+  /* If only one child ... */
+  if (!BOOL_SIBLING (child))
+    {
+      /* replace the parent with child - move it up */
+      bool_tree_node *save_sibling = BOOL_SIBLING (or_tree);
+      bcopy ((char *) child, (char *) or_tree, sizeof (bool_tree_node));
+      BOOL_SIBLING (or_tree) = save_sibling;
+      Xfree (child);
+    }
+
+}				/*AndTrueFalse */
+
+/* =========================================================================
+ * Function: AndNotToDiff
+ * Description: 
+ *      Convert an "And" tree with possibly some negated terms into
+ *      a "And - neg-terms". 
+ * Input: 
+ *      Expects "And" of only literals - as tree should be in DNF form.
+ *      This means that no recursion is necessary.
+ * Output: 
+ * ========================================================================= */
+
+static void
+AndNotToDiff (bool_tree_node * and_tree, TreeFunc recurs_func)
+{
+
+  /* -------------------------------------------------- */
+  /* --- Divide the children up into positive and negative literals --- */
+  /* Preserves ordering of children */
+  bool_tree_node *pos = NULL;
+  bool_tree_node *neg = NULL;
+  bool_tree_node *last_pos = NULL;
+  bool_tree_node *last_neg = NULL;
+
+  bool_tree_node *child = BOOL_CHILD (and_tree);
+  while (child)
+    {
+      bool_tree_node *next = BOOL_SIBLING (child);
+      if (BOOL_TAG (child) == N_not)
+	{
+	  /* add to end of neg list */
+	  if (!neg)
+	    neg = child;
+	  else
+	    BOOL_SIBLING (last_neg) = child;
+	  last_neg = child;
+	}
+      else
+	{
+	  /* add to end of pos list */
+	  if (!pos)
+	    pos = child;
+	  else
+	    BOOL_SIBLING (last_pos) = child;
+	  last_pos = child;
+	}
+      child = next;
+    }				/*while */
+  if (last_pos)
+    BOOL_SIBLING (last_pos) = NULL;
+  if (last_neg)
+    BOOL_SIBLING (last_neg) = NULL;
+  /* -------------------------------------------------- */
+
+  if (!neg)			/* no negtives => no subtraction */
+    {
+      /* fix up parent's child link */
+      BOOL_CHILD (and_tree) = pos;
+      return;
+    }
+
+  if (!pos)			/* no positives = all negatives */
+    {
+      /* Choose one of the negs for the left-hand-side of the subtraction */
+      /* In particular, choose the first */
+      pos = neg;
+      neg = BOOL_SIBLING (neg);
+      BOOL_SIBLING (pos) = NULL;
+    }
+
+  /* Get rid of all '!' from not nodes */
+  /* Make a list out of the children */
+  {
+    bool_tree_node *n = neg;
+    bool_tree_node *next = NULL;
+
+    neg = BOOL_CHILD (neg);
+    while (n)
+      {
+	bool_tree_node *c = BOOL_CHILD (n);
+	next = BOOL_SIBLING (n);
+	Xfree (n);
+	if (next)
+	  BOOL_SIBLING (c) = BOOL_CHILD (next);
+	n = next;
+      }
+  }
+
+  /* --- restructure the tree with "and" and "diff" --- */
+  BOOL_TAG (and_tree) = N_diff;
+  if (!BOOL_SIBLING (pos))	/* i.e. only one pos */
+    {
+      /* (A & !B & !C & !D & ...) ==> A - (B,C,D,...) */
+
+      BOOL_CHILD (and_tree) = pos;
+      BOOL_SIBLING (pos) = neg;
+    }
+  else
+    {
+      /* (A & !C & B & !D & ...) ==> (A & B & ....) - (C, D, ...) */
+
+      bool_tree_node *n = CreateBoolNode (N_and);
+      BOOL_CHILD (and_tree) = n;
+      BOOL_CHILD (n) = pos;
+      BOOL_SIBLING (n) = neg;
+    }				/*if */
+
+  if (recurs_func)
+    {
+      recurs_func (BOOL_CHILD (and_tree));
+    }
+
+}				/*AndNotToDiff */
+
+/* =========================================================================
+ * Function: DiffTree
+ * Description: 
+ *      Applies "AndNotToNeg" to each conjunct.
+ *      Unlike DiffDNF, this routine will search throughout the tree for
+ *      "and"-nodes. It will call AndNotToNeg with this as its recursive 
+ *      routine.
+ * Date: 27/July/95
+ * Input: 
+ * Output: 
+ * ========================================================================= */
+
+static void
+DiffTree (bool_tree_node * tree)
+{
+  bool_tree_node *t = tree;
+
+  while (t)
+    {
+      if (BOOL_TAG (t) == N_and)
+	{
+	  AndNotToDiff (t, DiffTree);
+	}
+      t = BOOL_SIBLING (t);
+    }				/*while */
+
+}				/*DiffTree */
+
+/* =========================================================================
+ * Function: DiffDNF
+ * Description: 
+ *      Applies "AndNotToNeg" to each conjunct.
+ * Input: 
+ *      A DNF tree
+ * Output: 
+ *      A tree possibly with some diffs in it.
+ * ========================================================================= */
+
+static void
+DiffDNF (bool_tree_node * DNF_tree)
+{
+
+  if (BOOL_TAG (DNF_tree) == N_or)
+    {
+      bool_tree_node *child = BOOL_CHILD (DNF_tree);
+
+      while (child)
+	{
+	  if (BOOL_TAG (child) == N_and)
+	    {
+	      AndNotToDiff (child, NULL);
+	    }
+	  child = BOOL_SIBLING (child);
+	}
+    }
+  else if (BOOL_TAG (DNF_tree) == N_and)
+    {
+      AndNotToDiff (DNF_tree, NULL);
+    }
+}
+
+/* =========================================================================
+ * Function: AndSort_comp 
+ * Description: 
+ * Input: 
+ * Output: 
+ * ========================================================================= */
+
+/* Module variable, "term_list",  used as parameter for comparison function */
+/* The comparison function only allows certain fixed parameters */
+static TermList *term_list;
+
+static int
+AndSort_comp (const void *A, const void *B)
+{
+  const bool_tree_node *const *a = A;
+  const bool_tree_node *const *b = B;
+
+  if (BOOL_TAG (*a) == N_term && BOOL_TAG (*b) == N_term)
+    {
+      /* look up in term list */
+      int a_doc_count = GetNthWE (term_list, BOOL_TERM (*a))->doc_count;
+      int b_doc_count = GetNthWE (term_list, BOOL_TERM (*b))->doc_count;
+
+      return a_doc_count - b_doc_count;
+    }
+
+  if (BOOL_TAG (*a) == N_term && BOOL_TAG (*b) != N_term)
+    return -1;
+
+  if (BOOL_TAG (*a) != N_term && BOOL_TAG (*b) == N_term)
+    return 1;
+
+  return 0;
+}				/*AndSort_comp */
+
+/* =========================================================================
+ * Function: AndSort
+ * Description: 
+ *      Sort the list of nodes by increasing doc_count 
+ *      Using some Neil Sharman code - pretty straight forward.
+ *      Note: not-terms are sent to the end of the list
+ * Input: 
+ * Output: 
+ * ========================================================================= */
+
+static void
+AndSort (bool_tree_node * and_tree, TermList * tl, CompFunc comp)
+{
+  bool_tree_node **list = NULL;
+  bool_tree_node *child = NULL;
+  int count = 0;
+  int i = 0;
+
+  if (BOOL_TAG (and_tree) != N_and)
+    return;
+
+  /* --- Convert linked list into an array for sorting --- */
+  child = BOOL_CHILD (and_tree);
+  count = 0;
+  while (child)
+    {
+      count++;
+      child = BOOL_SIBLING (child);
+    }
+
+  if (!(list = Xmalloc (sizeof (bool_tree_node *) * count)))
+    return;
+
+  child = BOOL_CHILD (and_tree);
+  for (i = 0; i < count; i++)
+    {
+      list[i] = child;
+      child = BOOL_SIBLING (child);
+    }
+  /* ----------------------------------------------------- */
+
+  term_list = tl;
+  qsort (list, count, sizeof (bool_tree_node *), comp);
+
+  /* --- Convert array back into linked list --- */
+  for (i = 0; i < count - 1; i++)
+    BOOL_SIBLING (list[i]) = list[i + 1];
+  BOOL_SIBLING (list[count - 1]) = NULL;
+  BOOL_CHILD (and_tree) = list[0];
+  Xfree (list);
+  /* ----------------------------------------------------- */
+
+}				/*AndSort */
+
+/* =========================================================================
+ * Function: AndSortDNF
+ * Description: 
+ * Input: 
+ * Output: 
+ * ========================================================================= */
+
+
+static void
+AndSortDNF (bool_tree_node * DNF_tree, TermList * tl)
+{
+
+  if (BOOL_TAG (DNF_tree) == N_or)
+    {
+      bool_tree_node *child = BOOL_CHILD (DNF_tree);
+
+      while (child)
+	{
+	  if (BOOL_TAG (child) == N_and)
+	    {
+	      AndSort (child, tl, AndSort_comp);
+	    }
+	  child = BOOL_SIBLING (child);
+	}
+    }
+  else if (BOOL_TAG (DNF_tree) == N_and)
+    {
+      AndSort (DNF_tree, tl, AndSort_comp);
+    }
+}
+
+/* =========================================================================
+ * Function: MarkOrTerms
+ * Description: 
+ *      Mark or-nodes whose children are all terms.
+ *      Also store the sum of the ft's of these nodes.
+ * Input: 
+ * Output: 
+ * ========================================================================= */
+
+static void
+MarkOrTerms (bool_tree_node * tree, TermList * tl)
+{
+  if (BOOL_TAG (tree) == N_or)
+    {
+      int found_non_term = 0;
+      bool_tree_node *child = BOOL_CHILD (tree);
+
+      /* --- check to see if got all terms --- */
+      while (child)
+	{
+	  if (BOOL_TAG (child) != N_term)
+	    {
+	      found_non_term = 1;
+	    }
+	  if (BOOL_HAS_CHILD (tree))
+	    {
+	      MarkOrTerms (child, tl);
+	    }
+	  child = BOOL_SIBLING (child);
+	}			/*while */
+
+      if (!found_non_term)
+	{
+	  /* Must have all terms for the OR node */
+	  /* So change its tag and calculate its sum */
+	  BOOL_TAG (tree) = N_or_terms;
+	  BOOL_SUM_FT (tree) = calc_sum_ft (tree, tl);
+	}			/*if */
+      /* ------------------------------------- */
+
+    }				/*if OR node */
+
+  else if (BOOL_HAS_CHILD (tree))
+    {
+      bool_tree_node *child = BOOL_CHILD (tree);
+      while (child)
+	{
+	  MarkOrTerms (child, tl);
+	  child = BOOL_SIBLING (child);
+	}
+    }
+
+}				/*MarkOrTerms */
+
+/* =========================================================================
+ * Function: calc_sum_ft
+ * Description: 
+ *      Sums up the ft's of all the terms 
+ * Input: 
+ *      Assumes that the tree only contains terms in it 
+ * Output: 
+ *      the ft sum
+ * ========================================================================= */
+static int
+calc_sum_ft (bool_tree_node * term_tree, TermList * tl)
+{
+  int sum_ft = 0;
+  bool_tree_node *child = BOOL_CHILD (term_tree);
+  while (child)
+    {
+      sum_ft += GetNthWE (tl, BOOL_TERM (child))->doc_count;
+      child = BOOL_SIBLING (child);
+    }
+  return sum_ft;
+}
+
+/* =========================================================================
+ * Function: AndOrSort
+ * Description: 
+ *      This is like an AndSort of just terms. 
+ *      The difference is that we are now also 
+ *      considering sorting with <or of terms> by using the sum of f_t's.
+ * Input: 
+ * Output: 
+ * ========================================================================= */
+static void
+AndOrSort (bool_tree_node * tree, TermList * tl)
+{
+  if (BOOL_HAS_CHILD (tree))
+    {
+
+      if (BOOL_TAG (tree) == N_and)
+	{
+	  AndSort (tree, tl, AndOrSort_comp);
+	}
+
+      /* Check out any children down the tree */
+      /* Probably a waste of time */
+      {
+	bool_tree_node *child = BOOL_CHILD (tree);
+	while (child)
+	  {
+	    AndOrSort (child, tl);
+	    child = BOOL_SIBLING (child);
+	  }
+      }				/*do the tree */
+
+    }				/*if has children */
+}				/*AndOrSort */
+
+/* =========================================================================
+ * Function: AndOrSort_comp
+ * Description: 
+ *      Comparison function used to order "term"s and "or_terms"s.
+ *      It's purpose is to be used by a sort routine.
+ * Input: 
+ * Output: 
+ * ========================================================================= */
+static int
+AndOrSort_comp (const void *A, const void *B)
+{
+  const bool_tree_node *const *a = A;
+  const bool_tree_node *const *b = B;
+
+  if (BOOL_TAG (*a) == N_term && BOOL_TAG (*b) == N_term)
+    {
+      /* look up in term list */
+      int a_doc_count = GetNthWE (term_list, BOOL_TERM (*a))->doc_count;
+      int b_doc_count = GetNthWE (term_list, BOOL_TERM (*b))->doc_count;
+
+      return a_doc_count - b_doc_count;
+    }
+
+  if (BOOL_TAG (*a) == N_term && BOOL_TAG (*b) == N_or_terms)
+    {
+      /* look up in term list */
+      int a_doc_count = GetNthWE (term_list, BOOL_TERM (*a))->doc_count;
+      int b_doc_count = BOOL_SUM_FT (*b);
+
+      return a_doc_count - b_doc_count;
+    }
+
+  if (BOOL_TAG (*a) == N_or_terms && BOOL_TAG (*b) == N_term)
+    {
+      /* look up in term list */
+      int a_doc_count = BOOL_SUM_FT (*a);
+      int b_doc_count = GetNthWE (term_list, BOOL_TERM (*b))->doc_count;
+
+      return a_doc_count - b_doc_count;
+    }
+
+  if (BOOL_TAG (*a) == N_or_terms && BOOL_TAG (*b) == N_or_terms)
+    {
+      /* look up in term list */
+      int a_doc_count = BOOL_SUM_FT (*a);
+      int b_doc_count = BOOL_SUM_FT (*b);
+
+      return a_doc_count - b_doc_count;
+    }
+
+  if ((BOOL_TAG (*a) == N_term || BOOL_TAG (*a) == N_or_terms) &&
+      (BOOL_TAG (*b) != N_term && BOOL_TAG (*b) != N_or_terms))
+    return -1;
+
+  if ((BOOL_TAG (*a) != N_term && BOOL_TAG (*a) != N_or_terms) &&
+      (BOOL_TAG (*b) == N_term || BOOL_TAG (*b) == N_or_terms))
+    return 1;
+
+  return 0;
+}				/*AndOrSort_comp */
Index: /main/tags/2.25/gsdl/packages/mg/src/text/bool_optimiser.h
===================================================================
--- /main/tags/2.25/gsdl/packages/mg/src/text/bool_optimiser.h	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/mg/src/text/bool_optimiser.h	(revision 21064)
@@ -0,0 +1,62 @@
+/**************************************************************************
+ *
+ * bool_optimiser -- optimise boolean parse tree
+ * Copyright (C) 1994  Tim Shimmin
+ *
+ * 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.
+ *
+ * $Id$
+ *
+ **************************************************************************/
+
+/*
+   $Log$
+   Revision 1.1  1999/08/10 21:17:42  sjboddie
+   renamed mg-1.3d directory mg
+
+   Revision 1.1  1998/11/17 09:34:23  rjmcnab
+   *** empty log message ***
+
+   * Revision 1.2  1995/03/14  05:15:21  tes
+   * Updated the boolean query optimiser to do different types of optimisation.
+   * A query environment variable "optimise_type" specifies which one is to be
+   * used. Type 1 is the new one which is faster than 2.
+   *
+   * Revision 1.1  1994/10/20  03:56:32  tes
+   * I have rewritten the boolean query optimiser and abstracted out the
+   * components of the boolean query.
+   *
+   * Revision 1.2  1994/10/18  06:11:03  tes
+   * The boolean optimiser seems to be modifying the parse tree
+   * like it is supposed to.
+   * Paragraph ranking now works without any text files if required to.
+   *
+   * Revision 1.1  1994/10/12  01:15:29  tes
+   * Found bugs in the existing boolean query optimiser.
+   * So decided to rewrite it.
+   * I accidentally deleted query.bool.y, but I have replaced it
+   * with bool_parser.y (which I have forgotten to add here ! ;-(
+   *
+ */
+
+#ifndef BOOL_OPTIMISER_H
+#define BOOL_OPTIMISER_H
+
+#include "bool_tree.h"
+#include "term_lists.h"
+
+void OptimiseBoolTree (bool_tree_node * parse_tree, TermList * term_list, int type);
+
+#endif
Index: /main/tags/2.25/gsdl/packages/mg/src/text/bool_parser.c
===================================================================
--- /main/tags/2.25/gsdl/packages/mg/src/text/bool_parser.c	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/mg/src/text/bool_parser.c	(revision 21064)
@@ -0,0 +1,643 @@
+#ifndef lint
+static char yysccsid[] = "@(#)yaccpar	1.9 (Berkeley) 02/21/93";
+#endif
+#define YYBYACC 1
+#define YYMAJOR 1
+#define YYMINOR 9
+#define yyclearin (yychar=(-1))
+#define yyerrok (yyerrflag=0)
+#define YYRECOVERING (yyerrflag!=0)
+#define YYPREFIX "yy"
+#line 25 "bool_parser.y"
+ 
+#include "sysfuncs.h"
+
+#include "messages.h"
+ 
+#include "memlib.h"
+#include "words.h"
+#include "stemmer.h"
+#include "term_lists.h"
+#include "bool_tree.h"
+/* [RPAP - Jan 97: Stem Index Change] */
+#include "backend.h"     /* for stemmed_dict def */
+#include "stem_search.h"
+
+#include "query_term_list.h"  /* [RPAP - Feb 97: Term Frequency] */
+
+/* --- routines --- */
+static int query_lex();
+static int yyerror(char *);
+#define yylex() query_lex(&ch_buf, end_buf)
+ 
+/* --- module variables --- */
+static char *ch_buf; /* ptr to the character query line buffer */
+static char *end_buf; /* ptr to the last character of the line buffer */
+static bool_tree_node *tree_base = NULL;
+static TermList **term_list;
+static int stemmer_num;
+static int stem_method;
+/* [RPAP - Jan 97: Stem Index Change] */
+stemmed_dict *p__sd;
+static int indexed;
+/* [RPAP - Feb 97: Term Frequency] */
+static QueryTermList **query_term_list;
+static int word_num;
+static u_long count;
+static u_long doc_count;
+static u_long invf_ptr;
+static u_long invf_len;
+#line 65 "bool_parser.y"
+typedef union {
+  char *text;
+  bool_tree_node *node;
+} YYSTYPE;
+#line 55 "y.tab.c"
+#define TERM 257
+#define YYERRCODE 256
+short yylhs[] = {                                        -1,
+    0,    1,    1,    1,    1,    2,    2,    3,    3,    3,
+    4,    4,
+};
+short yylen[] = {                                         2,
+    1,    1,    3,    1,    1,    1,    2,    3,    2,    1,
+    3,    1,
+};
+short yydefred[] = {                                      0,
+    2,    0,    4,    5,    0,    0,    6,   10,    0,    0,
+    0,    7,    0,    9,    0,    3,    8,    0,
+};
+short yydgoto[] = {                                       6,
+    7,    8,    9,   10,
+};
+short yysindex[] = {                                    -32,
+    0,  -32,    0,    0,  -32,    0,    0,    0,  -33, -118,
+  -37,    0,  -32,    0,  -32,    0,    0,  -33,
+};
+short yyrindex[] = {                                      0,
+    0,    0,    0,    0,    0,    0,    0,    0,    2,   12,
+    0,    0,    0,    0,    0,    0,    0,    3,
+};
+short yygindex[] = {                                      0,
+    0,    6,   -2,   14,
+};
+#define YYTABLESIZE 225
+short yytable[] = {                                       5,
+    5,   12,   11,   16,   13,   15,    2,    2,    3,    3,
+   12,    1,   18,    0,   14,   11,    0,    0,   17,    0,
+    0,    0,    0,   14,    0,    0,    0,    0,    0,    0,
+    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,
+    0,    0,   12,   11,    0,    0,    0,    0,    0,    0,
+    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,
+    0,    4,    4,    0,    0,    0,    0,    0,    0,    0,
+    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,
+    0,    0,    0,    0,    0,    0,   15,    0,    0,    0,
+    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,
+    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,
+    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,
+    0,    0,    0,    0,    0,   12,   11,    0,    0,    0,
+    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,
+    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,
+    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,
+    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,
+    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,
+    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,
+    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,
+    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,
+    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,
+    0,    0,    0,    1,    1,
+};
+short yycheck[] = {                                      33,
+   33,    0,    0,   41,   38,  124,   40,   40,   42,   42,
+    5,    0,   15,   -1,    9,    2,   -1,   -1,   13,   -1,
+   -1,   -1,   -1,   18,   -1,   -1,   -1,   -1,   -1,   -1,
+   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,
+   -1,   -1,   41,   41,   -1,   -1,   -1,   -1,   -1,   -1,
+   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,
+   -1,   95,   95,   -1,   -1,   -1,   -1,   -1,   -1,   -1,
+   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,
+   -1,   -1,   -1,   -1,   -1,   -1,  124,   -1,   -1,   -1,
+   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,
+   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,
+   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,
+   -1,   -1,   -1,   -1,   -1,  124,  124,   -1,   -1,   -1,
+   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,
+   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,
+   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,
+   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,
+   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,
+   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,
+   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,
+   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,
+   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,
+   -1,   -1,   -1,  257,  257,
+};
+#define YYFINAL 6
+#ifndef YYDEBUG
+#define YYDEBUG 0
+#endif
+#define YYMAXTOKEN 257
+#if YYDEBUG
+char *yyname[] = {
+"end-of-file",0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+"'!'",0,0,0,0,"'&'",0,"'('","')'","'*'",0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,"'_'",0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,"'|'",0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+"TERM",
+};
+char *yyrule[] = {
+"$accept : query",
+"query : or",
+"term : TERM",
+"term : '(' or ')'",
+"term : '*'",
+"term : '_'",
+"not : term",
+"not : '!' not",
+"and : and '&' not",
+"and : and not",
+"and : not",
+"or : or '|' and",
+"or : and",
+};
+#endif
+#ifdef YYSTACKSIZE
+#undef YYMAXDEPTH
+#define YYMAXDEPTH YYSTACKSIZE
+#else
+#ifdef YYMAXDEPTH
+#define YYSTACKSIZE YYMAXDEPTH
+#else
+#define YYSTACKSIZE 500
+#define YYMAXDEPTH 500
+#endif
+#endif
+int yydebug;
+int yynerrs;
+int yyerrflag;
+int yychar;
+short *yyssp;
+YYSTYPE *yyvsp;
+YYSTYPE yyval;
+YYSTYPE yylval;
+short yyss[YYSTACKSIZE];
+YYSTYPE yyvs[YYSTACKSIZE];
+#define yystacksize YYSTACKSIZE
+#line 99 "bool_parser.y"
+ 
+/* Bison on one mips machine defined "const" to be nothing but
+   then did not undef it */
+#ifdef const
+#undef const
+#endif
+
+/**************************************************************************/ 
+
+
+/* =========================================================================
+ * Function: query_lex
+ * Description:
+ *      Hand written lexical analyser for the parser.
+ * Input:
+ *      ptr = ptr to a ptr into character query-line buffer
+ *      end = ptr to last char in buffer
+ * Output:
+ *      yylval.text = the token's text
+ * Notes:
+ *      does NOT produce WILD tokens at the moment
+ * ========================================================================= */
+ 
+/* [RPAP - Jan 97: Stem Index Change]
+   state mode:
+      0 = Read next token
+      1 = Output word
+      2 = Output '|' or ')'
+ */
+static int query_lex(char **ptr, const char *end)
+{
+  char *buf_ptr = *ptr;
+  static int mode = 0;
+  static int termnum = 0;
+  static TermList *Terms = NULL;
+
+  if (mode == 0)
+    {
+      /* jump over whitespace */
+      while (isspace(*buf_ptr))
+	buf_ptr++;
+ 
+      if (inaword(buf_ptr, end))
+	{
+	  static char word[MAXSTEMLEN + 1]; /* [RJM 07/98: Memory Leak] */
+	  char *sWord = Xmalloc(MAXSTEMLEN + 1);
+	  int stem_to_apply, method_using = -1;
+
+	  PARSE_STEM_WORD(word, buf_ptr, end);
+
+	  /* Extract any parameters */
+	  stem_to_apply = stem_method;
+	  while (buf_ptr <= end)
+	    {
+	      int stem_param, param_type;
+	      char param[MAXPARAMLEN + 1];
+
+	      param_type = 0;
+	      PARSE_OPT_TERM_PARAM (param, param_type, buf_ptr, end);
+	      if (!param_type)
+		break;
+
+	      if (param_type == STEMPARAM)
+		{
+		  stem_param = atoi (param);
+		  if (errno != ERANGE && indexed && stem_param >= 0 && stem_param <= 3)
+		    method_using = stem_to_apply = stem_param;
+		}
+	    }
+
+	  bcopy ((char *) word, (char *) sWord, *word + 1);
+	  stemmer (stem_to_apply, stemmer_num, sWord);
+
+	  if (stem_to_apply == 0 || !indexed || p__sd == NULL)
+	    {
+	      /* [RPAP - Feb 97: Term Frequency] */
+	      word_num = FindWord (p__sd, sWord, &count, &doc_count, &invf_ptr, &invf_len);
+	      if (word_num == -1)
+		count = doc_count = invf_ptr = invf_len = 0;
+	      AddQueryTerm (query_term_list, (u_char *) word, count, method_using);
+
+	      yylval.text = word;
+	      *ptr = buf_ptr; /* fix up ptr */
+	      Xfree (sWord);
+	      return TERM;
+	    }
+	  else
+	    {
+	      *ptr = buf_ptr; /* fix up ptr */
+	      termnum = 0;
+	      ResetTermList (&Terms);
+	      if (FindWords (p__sd, (u_char *) sWord, stem_to_apply, &Terms) > 0)
+		{
+		  /* [RPAP - Feb 97: Term Frequency] */ 
+		  int i, freq = 0;
+		  for (i = 0; i < Terms->num; i++)
+		    freq += Terms->TE[i].WE.count;
+		  AddQueryTerm (query_term_list, word, freq, method_using);
+
+		  Xfree (sWord);
+		  mode = 1;
+		  return '(';
+		}
+	      else
+		{
+		  /* Word does not exists - include in tree anyway */
+		  Xfree (sWord);
+
+		  /* [RPAP - Feb 97: Term Frequency] */
+		  word_num = -1;
+		  count = doc_count = invf_ptr = invf_len = 0;
+		  AddQueryTerm (query_term_list, (u_char *) word, count, method_using);
+
+		  yylval.text = word;
+		  return TERM;
+		}
+	    }
+	}
+      else /* NON-WORD */
+	{
+	  if (*buf_ptr == '\0')
+	    {
+	      /* return null-char if it is one */
+	      *ptr = buf_ptr; /* fix up ptr */
+	      return 0;
+	    }
+	  else
+	    {
+	      /* return 1st char, and delete from buffer */
+	      char c = *buf_ptr++;
+	      *ptr = buf_ptr; /* fix up ptr */
+	      return c;
+	    }
+	}
+    }
+  else if (mode == 1)
+    {
+      yylval.text = Terms->TE[termnum].Word;
+      
+      /* [RPAP - Feb 97: Term Frequency] */
+      word_num = Terms->TE[termnum].WE.word_num;
+      count = Terms->TE[termnum].WE.count;
+      doc_count = Terms->TE[termnum].WE.doc_count;
+      invf_ptr = Terms->TE[termnum].WE.invf_ptr;
+      invf_len = Terms->TE[termnum].WE.invf_len;
+
+      termnum++;
+      mode = 2;
+      return TERM;
+    }
+  else  /* mode == 2 */
+    {
+      if (termnum >= Terms->num)
+	{
+	  mode = 0;
+	  return ')';
+	}
+      else
+	{
+	  mode = 1;
+	  return '|';
+	}
+    }
+}/*query_lex*/
+
+/* =========================================================================
+ * Function: yyerror
+ * Description: 
+ * Input: 
+ * Output: 
+ * ========================================================================= */ 
+static int yyerror(char *s)
+{
+  Message("%s", s);
+  return(1);
+}
+
+ 
+/* =========================================================================
+ * Function: ParseBool
+ * Description:
+ *      Parse a boolean query string into a term-list and a boolean parse tree
+ * Input:
+ *      query_line = query line string
+ *      query_len = query line length
+ *      the_stem_method = stem method id used for stemming
+ * Output:
+ *      the_term_list = the list of terms
+ *      res = parser result code
+ * ========================================================================= */
+ 
+bool_tree_node *
+ParseBool(char *query_line, int query_len,
+          TermList **the_term_list, int the_stemmer_num, int the_stem_method, 
+	  int *res,
+	  stemmed_dict * the_sd, int is_indexed,   /* [RPAP - Jan 97: Stem Index Change] */
+	  QueryTermList **the_query_term_list)  /* [RPAP - Feb 97: Term Frequency] */
+{
+  /* global variables to be accessed by bison/yacc created parser */
+  term_list = the_term_list;
+  stemmer_num = the_stemmer_num;
+  stem_method = the_stem_method;
+  ch_buf = query_line;
+  end_buf = query_line + query_len;
+  p__sd = the_sd;   /* [RPAP - Jan 97: Stem Index Change] */
+  indexed = is_indexed;  /* [RPAP - Jan 97: Stem Index Change] */
+  query_term_list = the_query_term_list; /* [RPAP - Feb 97: Term Frequency] */
+
+  FreeBoolTree(&(tree_base));
+ 
+  ResetTermList(term_list);
+  ResetQueryTermList(query_term_list);  /* [RPAP - Feb 97: Term Frequency] */
+
+  *res = yyparse();
+ 
+  return tree_base;
+}
+ 
+
+#line 407 "y.tab.c"
+#define YYABORT goto yyabort
+#define YYREJECT goto yyabort
+#define YYACCEPT goto yyaccept
+#define YYERROR goto yyerrlab
+int
+yyparse()
+{
+    register int yym, yyn, yystate;
+#if YYDEBUG
+    register char *yys;
+    extern char *getenv();
+
+    if (yys = getenv("YYDEBUG"))
+    {
+        yyn = *yys;
+        if (yyn >= '0' && yyn <= '9')
+            yydebug = yyn - '0';
+    }
+#endif
+
+    yynerrs = 0;
+    yyerrflag = 0;
+    yychar = (-1);
+
+    yyssp = yyss;
+    yyvsp = yyvs;
+    *yyssp = yystate = 0;
+
+yyloop:
+    if (yyn = yydefred[yystate]) goto yyreduce;
+    if (yychar < 0)
+    {
+        if ((yychar = yylex()) < 0) yychar = 0;
+#if YYDEBUG
+        if (yydebug)
+        {
+            yys = 0;
+            if (yychar <= YYMAXTOKEN) yys = yyname[yychar];
+            if (!yys) yys = "illegal-symbol";
+            printf("%sdebug: state %d, reading %d (%s)\n",
+                    YYPREFIX, yystate, yychar, yys);
+        }
+#endif
+    }
+    if ((yyn = yysindex[yystate]) && (yyn += yychar) >= 0 &&
+            yyn <= YYTABLESIZE && yycheck[yyn] == yychar)
+    {
+#if YYDEBUG
+        if (yydebug)
+            printf("%sdebug: state %d, shifting to state %d\n",
+                    YYPREFIX, yystate, yytable[yyn]);
+#endif
+        if (yyssp >= yyss + yystacksize - 1)
+        {
+            goto yyoverflow;
+        }
+        *++yyssp = yystate = yytable[yyn];
+        *++yyvsp = yylval;
+        yychar = (-1);
+        if (yyerrflag > 0)  --yyerrflag;
+        goto yyloop;
+    }
+    if ((yyn = yyrindex[yystate]) && (yyn += yychar) >= 0 &&
+            yyn <= YYTABLESIZE && yycheck[yyn] == yychar)
+    {
+        yyn = yytable[yyn];
+        goto yyreduce;
+    }
+    if (yyerrflag) goto yyinrecovery;
+#ifdef lint
+    goto yynewerror;
+#endif
+yynewerror:
+    yyerror("syntax error");
+#ifdef lint
+    goto yyerrlab;
+#endif
+yyerrlab:
+    ++yynerrs;
+yyinrecovery:
+    if (yyerrflag < 3)
+    {
+        yyerrflag = 3;
+        for (;;)
+        {
+            if ((yyn = yysindex[*yyssp]) && (yyn += YYERRCODE) >= 0 &&
+                    yyn <= YYTABLESIZE && yycheck[yyn] == YYERRCODE)
+            {
+#if YYDEBUG
+                if (yydebug)
+                    printf("%sdebug: state %d, error recovery shifting\
+ to state %d\n", YYPREFIX, *yyssp, yytable[yyn]);
+#endif
+                if (yyssp >= yyss + yystacksize - 1)
+                {
+                    goto yyoverflow;
+                }
+                *++yyssp = yystate = yytable[yyn];
+                *++yyvsp = yylval;
+                goto yyloop;
+            }
+            else
+            {
+#if YYDEBUG
+                if (yydebug)
+                    printf("%sdebug: error recovery discarding state %d\n",
+                            YYPREFIX, *yyssp);
+#endif
+                if (yyssp <= yyss) goto yyabort;
+                --yyssp;
+                --yyvsp;
+            }
+        }
+    }
+    else
+    {
+        if (yychar == 0) goto yyabort;
+#if YYDEBUG
+        if (yydebug)
+        {
+            yys = 0;
+            if (yychar <= YYMAXTOKEN) yys = yyname[yychar];
+            if (!yys) yys = "illegal-symbol";
+            printf("%sdebug: state %d, error recovery discards token %d (%s)\n",
+                    YYPREFIX, yystate, yychar, yys);
+        }
+#endif
+        yychar = (-1);
+        goto yyloop;
+    }
+yyreduce:
+#if YYDEBUG
+    if (yydebug)
+        printf("%sdebug: state %d, reducing by rule %d (%s)\n",
+                YYPREFIX, yystate, yyn, yyrule[yyn]);
+#endif
+    yym = yylen[yyn];
+    yyval = yyvsp[1-yym];
+    switch (yyn)
+    {
+case 1:
+#line 75 "bool_parser.y"
+{ tree_base = yyvsp[0].node;}
+break;
+case 2:
+#line 79 "bool_parser.y"
+{ yyval.node = CreateBoolTermNode(term_list, yyvsp[0].text, 1, word_num, count, doc_count, invf_ptr, invf_len, stemmer_num); }
+break;
+case 3:
+#line 80 "bool_parser.y"
+{ yyval.node = yyvsp[-1].node; }
+break;
+case 4:
+#line 81 "bool_parser.y"
+{ yyval.node = CreateBoolTreeNode(N_all, NULL, NULL); }
+break;
+case 5:
+#line 82 "bool_parser.y"
+{ yyval.node = CreateBoolTreeNode(N_none, NULL, NULL); }
+break;
+case 7:
+#line 86 "bool_parser.y"
+{ yyval.node = CreateBoolTreeNode(N_not, yyvsp[0].node, NULL); }
+break;
+case 8:
+#line 89 "bool_parser.y"
+{ yyval.node = CreateBoolTreeNode(N_and, yyvsp[-2].node, yyvsp[0].node); }
+break;
+case 9:
+#line 90 "bool_parser.y"
+{ yyval.node = CreateBoolTreeNode(N_and, yyvsp[-1].node, yyvsp[0].node); }
+break;
+case 11:
+#line 94 "bool_parser.y"
+{ yyval.node = CreateBoolTreeNode(N_or, yyvsp[-2].node, yyvsp[0].node); }
+break;
+#line 584 "y.tab.c"
+    }
+    yyssp -= yym;
+    yystate = *yyssp;
+    yyvsp -= yym;
+    yym = yylhs[yyn];
+    if (yystate == 0 && yym == 0)
+    {
+#if YYDEBUG
+        if (yydebug)
+            printf("%sdebug: after reduction, shifting from state 0 to\
+ state %d\n", YYPREFIX, YYFINAL);
+#endif
+        yystate = YYFINAL;
+        *++yyssp = YYFINAL;
+        *++yyvsp = yyval;
+        if (yychar < 0)
+        {
+            if ((yychar = yylex()) < 0) yychar = 0;
+#if YYDEBUG
+            if (yydebug)
+            {
+                yys = 0;
+                if (yychar <= YYMAXTOKEN) yys = yyname[yychar];
+                if (!yys) yys = "illegal-symbol";
+                printf("%sdebug: state %d, reading %d (%s)\n",
+                        YYPREFIX, YYFINAL, yychar, yys);
+            }
+#endif
+        }
+        if (yychar == 0) goto yyaccept;
+        goto yyloop;
+    }
+    if ((yyn = yygindex[yym]) && (yyn += yystate) >= 0 &&
+            yyn <= YYTABLESIZE && yycheck[yyn] == yystate)
+        yystate = yytable[yyn];
+    else
+        yystate = yydgoto[yym];
+#if YYDEBUG
+    if (yydebug)
+        printf("%sdebug: after reduction, shifting from state %d \
+to state %d\n", YYPREFIX, *yyssp, yystate);
+#endif
+    if (yyssp >= yyss + yystacksize - 1)
+    {
+        goto yyoverflow;
+    }
+    *++yyssp = yystate;
+    *++yyvsp = yyval;
+    goto yyloop;
+yyoverflow:
+    yyerror("yacc stack overflow");
+yyabort:
+    return (1);
+yyaccept:
+    return (0);
+}
+
Index: /main/tags/2.25/gsdl/packages/mg/src/text/bool_parser.h
===================================================================
--- /main/tags/2.25/gsdl/packages/mg/src/text/bool_parser.h	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/mg/src/text/bool_parser.h	(revision 21064)
@@ -0,0 +1,67 @@
+/**************************************************************************
+ *
+ * filename -- description
+ * Copyright (C) 1994  Authors
+ *
+ * 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.
+ *
+ * $Id$
+ *
+ **************************************************************************/
+
+/*
+   $Log$
+   Revision 1.1  1999/08/10 21:17:43  sjboddie
+   renamed mg-1.3d directory mg
+
+   Revision 1.2  1998/11/25 07:55:40  rjmcnab
+
+   Modified mg to that you can specify the stemmer you want
+   to use via a command line option. You specify it to
+   mg_passes during the build process. The number of the
+   stemmer that you used is stored within the inverted
+   dictionary header and the stemmed dictionary header so
+   the correct stemmer is used in later stages of building
+   and querying.
+
+   Revision 1.1  1998/11/17 09:34:26  rjmcnab
+   *** empty log message ***
+
+   * Revision 1.1  1994/10/20  03:56:33  tes
+   * I have rewritten the boolean query optimiser and abstracted out the
+   * components of the boolean query.
+   *
+   * Revision 1.1  1994/10/12  01:15:31  tes
+   * Found bugs in the existing boolean query optimiser.
+   * So decided to rewrite it.
+   * I accidentally deleted query.bool.y, but I have replaced it
+   * with bool_parser.y (which I have forgotten to add here ! ;-(
+   *
+ */
+
+#ifndef BOOL_PARSER_H
+#define BOOL_PARSER_H
+
+#include "backend.h"
+#include "term_lists.h"
+#include "invf.h"
+
+bool_tree_node *ParseBool (char *query_line, int query_len,
+			   TermList ** the_term_list, int the_stemmer_num, 
+			   int the_stem_method, int *res,
+			   stemmed_dict * the_sd, int is_indexed,  /* [RPAP - Jan 97: Stem Index Change] */
+			   QueryTermList ** the_query_term_list);  /* [RPAP - Feb 97: Term Frequency] */
+
+#endif
Index: /main/tags/2.25/gsdl/packages/mg/src/text/bool_parser.y
===================================================================
--- /main/tags/2.25/gsdl/packages/mg/src/text/bool_parser.y	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/mg/src/text/bool_parser.y	(revision 21064)
@@ -0,0 +1,317 @@
+/**************************************************************************
+ *
+ * bool_parser - boolean query parser
+ * Copyright (C) 1994  Neil Sharman & Tim Shimmin
+ *
+ * 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.
+ *
+ *
+ **************************************************************************/
+ 
+/**************************************************************************/
+%{
+ 
+#include "sysfuncs.h"
+
+#include "messages.h"
+ 
+#include "memlib.h"
+#include "words.h"
+#include "stemmer.h"
+#include "term_lists.h"
+#include "bool_tree.h"
+/* [RPAP - Jan 97: Stem Index Change] */
+#include "backend.h"     /* for stemmed_dict def */
+#include "stem_search.h"
+
+#include "query_term_list.h"  /* [RPAP - Feb 97: Term Frequency] */
+
+/* --- routines --- */
+static int query_lex();
+static int yyerror(char *);
+#define yylex() query_lex(&ch_buf, end_buf)
+ 
+/* --- module variables --- */
+static char *ch_buf; /* ptr to the character query line buffer */
+static char *end_buf; /* ptr to the last character of the line buffer */
+static bool_tree_node *tree_base = NULL;
+static TermList **term_list;
+static int stemmer_num;
+static int stem_method;
+/* [RPAP - Jan 97: Stem Index Change] */
+stemmed_dict *p__sd;
+static int indexed;
+/* [RPAP - Feb 97: Term Frequency] */
+static QueryTermList **query_term_list;
+static int word_num;
+static u_long count;
+static u_long doc_count;
+static u_long invf_ptr;
+static u_long invf_len;
+%}
+ 
+ 
+%union {
+  char *text;
+  bool_tree_node *node;
+}
+ 
+%token <text> TERM
+%type <node> query term not and or
+ 
+%%
+ 
+query: or  { tree_base = $1;}
+;
+ 
+ 
+term:     TERM  { $$ = CreateBoolTermNode(term_list, $1, 1, word_num, count, doc_count, invf_ptr, invf_len, stemmer_num); }
+        | '(' or ')' { $$ = $2; }
+        | '*' { $$ = CreateBoolTreeNode(N_all, NULL, NULL); }
+        | '_' { $$ = CreateBoolTreeNode(N_none, NULL, NULL); }
+;
+ 
+not:      term
+        | '!' not { $$ = CreateBoolTreeNode(N_not, $2, NULL); }
+;
+ 
+and:      and '&' not { $$ = CreateBoolTreeNode(N_and, $1, $3); }
+        | and not { $$ = CreateBoolTreeNode(N_and, $1, $2); }
+        | not
+;
+ 
+or:       or '|' and { $$ = CreateBoolTreeNode(N_or, $1, $3); }
+        | and
+;
+ 
+%%
+ 
+/* Bison on one mips machine defined "const" to be nothing but
+   then did not undef it */
+#ifdef const
+#undef const
+#endif
+
+/**************************************************************************/ 
+
+
+/* =========================================================================
+ * Function: query_lex
+ * Description:
+ *      Hand written lexical analyser for the parser.
+ * Input:
+ *      ptr = ptr to a ptr into character query-line buffer
+ *      end = ptr to last char in buffer
+ * Output:
+ *      yylval.text = the token's text
+ * Notes:
+ *      does NOT produce WILD tokens at the moment
+ * ========================================================================= */
+ 
+/* [RPAP - Jan 97: Stem Index Change]
+   state mode:
+      0 = Read next token
+      1 = Output word
+      2 = Output '|' or ')'
+ */
+static int query_lex(char **ptr, const char *end)
+{
+  char *buf_ptr = *ptr;
+  static int mode = 0;
+  static int termnum = 0;
+  static TermList *Terms = NULL;
+
+  if (mode == 0)
+    {
+      /* jump over whitespace */
+      while (isspace(*buf_ptr))
+	buf_ptr++;
+ 
+      if (inaword(buf_ptr, end))
+	{
+	  static char word[MAXSTEMLEN + 1]; /* [RJM 07/98: Memory Leak] */
+	  char *sWord = Xmalloc(MAXSTEMLEN + 1);
+	  int stem_to_apply, method_using = -1;
+
+	  PARSE_STEM_WORD(word, buf_ptr, end);
+
+	  /* Extract any parameters */
+	  stem_to_apply = stem_method;
+	  while (buf_ptr <= end)
+	    {
+	      int stem_param, param_type;
+	      char param[MAXPARAMLEN + 1];
+
+	      param_type = 0;
+	      PARSE_OPT_TERM_PARAM (param, param_type, buf_ptr, end);
+	      if (!param_type)
+		break;
+
+	      if (param_type == STEMPARAM)
+		{
+		  stem_param = atoi (param);
+		  if (errno != ERANGE && indexed && stem_param >= 0 && stem_param <= 3)
+		    method_using = stem_to_apply = stem_param;
+		}
+	    }
+
+	  bcopy ((char *) word, (char *) sWord, *word + 1);
+	  stemmer (stem_to_apply, stemmer_num, sWord);
+
+	  if (stem_to_apply == 0 || !indexed || p__sd == NULL)
+	    {
+	      /* [RPAP - Feb 97: Term Frequency] */
+	      word_num = FindWord (p__sd, sWord, &count, &doc_count, &invf_ptr, &invf_len);
+	      if (word_num == -1)
+		count = doc_count = invf_ptr = invf_len = 0;
+	      AddQueryTerm (query_term_list, (u_char *) word, count, method_using);
+
+	      yylval.text = word;
+	      *ptr = buf_ptr; /* fix up ptr */
+	      Xfree (sWord);
+	      return TERM;
+	    }
+	  else
+	    {
+	      *ptr = buf_ptr; /* fix up ptr */
+	      termnum = 0;
+	      ResetTermList (&Terms);
+	      if (FindWords (p__sd, (u_char *) sWord, stem_to_apply, &Terms) > 0)
+		{
+		  /* [RPAP - Feb 97: Term Frequency] */ 
+		  int i, freq = 0;
+		  for (i = 0; i < Terms->num; i++)
+		    freq += Terms->TE[i].WE.count;
+		  AddQueryTerm (query_term_list, word, freq, method_using);
+
+		  Xfree (sWord);
+		  mode = 1;
+		  return '(';
+		}
+	      else
+		{
+		  /* Word does not exists - include in tree anyway */
+		  Xfree (sWord);
+
+		  /* [RPAP - Feb 97: Term Frequency] */
+		  word_num = -1;
+		  count = doc_count = invf_ptr = invf_len = 0;
+		  AddQueryTerm (query_term_list, (u_char *) word, count, method_using);
+
+		  yylval.text = word;
+		  return TERM;
+		}
+	    }
+	}
+      else /* NON-WORD */
+	{
+	  if (*buf_ptr == '\0')
+	    {
+	      /* return null-char if it is one */
+	      *ptr = buf_ptr; /* fix up ptr */
+	      return 0;
+	    }
+	  else
+	    {
+	      /* return 1st char, and delete from buffer */
+	      char c = *buf_ptr++;
+	      *ptr = buf_ptr; /* fix up ptr */
+	      return c;
+	    }
+	}
+    }
+  else if (mode == 1)
+    {
+      yylval.text = Terms->TE[termnum].Word;
+      
+      /* [RPAP - Feb 97: Term Frequency] */
+      word_num = Terms->TE[termnum].WE.word_num;
+      count = Terms->TE[termnum].WE.count;
+      doc_count = Terms->TE[termnum].WE.doc_count;
+      invf_ptr = Terms->TE[termnum].WE.invf_ptr;
+      invf_len = Terms->TE[termnum].WE.invf_len;
+
+      termnum++;
+      mode = 2;
+      return TERM;
+    }
+  else  /* mode == 2 */
+    {
+      if (termnum >= Terms->num)
+	{
+	  mode = 0;
+	  return ')';
+	}
+      else
+	{
+	  mode = 1;
+	  return '|';
+	}
+    }
+}/*query_lex*/
+
+/* =========================================================================
+ * Function: yyerror
+ * Description: 
+ * Input: 
+ * Output: 
+ * ========================================================================= */ 
+static int yyerror(char *s)
+{
+  Message("%s", s);
+  return(1);
+}
+
+ 
+/* =========================================================================
+ * Function: ParseBool
+ * Description:
+ *      Parse a boolean query string into a term-list and a boolean parse tree
+ * Input:
+ *      query_line = query line string
+ *      query_len = query line length
+ *      the_stem_method = stem method id used for stemming
+ * Output:
+ *      the_term_list = the list of terms
+ *      res = parser result code
+ * ========================================================================= */
+ 
+bool_tree_node *
+ParseBool(char *query_line, int query_len,
+          TermList **the_term_list, int the_stemmer_num, int the_stem_method, int *res,
+	  stemmed_dict * the_sd, int is_indexed,   /* [RPAP - Jan 97: Stem Index Change] */
+	  QueryTermList **the_query_term_list)  /* [RPAP - Feb 97: Term Frequency] */
+{
+  /* global variables to be accessed by bison/yacc created parser */
+  term_list = the_term_list;
+  stemmer_num = the_stemmer_num;
+  stem_method = the_stem_method;
+  ch_buf = query_line;
+  end_buf = query_line + query_len;
+  p__sd = the_sd;   /* [RPAP - Jan 97: Stem Index Change] */
+  indexed = is_indexed;  /* [RPAP - Jan 97: Stem Index Change] */
+  query_term_list = the_query_term_list; /* [RPAP - Feb 97: Term Frequency] */
+
+  FreeBoolTree(&(tree_base));
+ 
+  ResetTermList(term_list);
+  ResetQueryTermList(query_term_list);  /* [RPAP - Feb 97: Term Frequency] */
+
+  *res = yyparse();
+ 
+  return tree_base;
+}
+ 
+
Index: /main/tags/2.25/gsdl/packages/mg/src/text/bool_query.c
===================================================================
--- /main/tags/2.25/gsdl/packages/mg/src/text/bool_query.c	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/mg/src/text/bool_query.c	(revision 21064)
@@ -0,0 +1,353 @@
+/**************************************************************************
+ *
+ * bool_query.c -- Boolean query evaluation
+ * Copyright (C) 1994  Neil Sharman & Tim Shimmin
+ *
+ * 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.
+ *
+ *
+ **************************************************************************/
+
+#include "sysfuncs.h"
+
+#include "memlib.h"
+#include "messages.h"
+#include "filestats.h"
+#include "timing.h"
+#include "sptree.h"
+
+
+#include "mg.h"
+#include "text.h"
+#include "invf.h"
+#include "lists.h"
+#include "term_lists.h"
+#include "backend.h"
+#include "words.h"
+#include "stemmer.h"
+#include "stem_search.h"
+#include "invf_get.h"
+#include "text_get.h"
+#include "read_line.h"
+#include "bool_tree.h"
+#include "bool_parser.h"
+#include "bool_optimiser.h"
+#include "environment.h"
+
+
+/**********************
+  [RPAP - Feb 97: Term Frequency]
+
+  Shifted to bool_parser.y
+
+  *********************/
+
+/* =========================================================================
+ * Function: ReadInTermInfo
+ * Description: 
+ * Input: 
+ * Output: 
+ * ========================================================================= */
+/**************************
+static void 
+ReadInTermInfo (query_data * qd)
+{
+  int i;
+  TermList *tl = qd->TL;
+
+  for (i = 0; i < tl->num; i++)
+    {
+      TermEntry *te = &(tl->TE[i]);
+      WordEntry *we = &(te->WE);
+
+       we->word_num = FindWord (qd->sd, te->Word,
+			       &we->count, &we->doc_count,
+			       &we->invf_ptr, &we->invf_len);
+      if (we->word_num == -1)
+	we->count = we->doc_count = 0;
+    }
+}
+
+***********************/
+
+
+
+/* =========================================================================
+ * Function: FindNoneTerms 
+ * Description: 
+ *      Set any terms which are not in dictionary to N_none (i.e. false)
+ *      Assumes a prior call to ReadInTermInfo
+ * Input: 
+ * Output: 
+ * ========================================================================= */
+
+static void 
+FindNoneTerms (query_data * qd, bool_tree_node * tree)
+{
+  if (BOOL_HAS_CHILD (tree))
+    {
+      bool_tree_node *child = BOOL_CHILD (tree);
+      while (child)
+	{
+	  FindNoneTerms (qd, child);
+	  child = BOOL_SIBLING (child);
+	}
+    }
+  else if (BOOL_TAG (tree) == N_term)
+    {
+      int doc_count = qd->TL->TE[BOOL_TERM (tree)].WE.doc_count;
+      if (!doc_count)
+	BOOL_TAG (tree) = N_none;
+    }
+
+}				/*FindNoneTerms */
+
+/* =========================================================================
+ * Function: ReduceList
+ * Description: 
+ *      Go thru doc-set and get rid of all docs which are unmarked
+ *      The motivation for this routine is in the case of CNF queries.
+ * Input: 
+ * Output: 
+ * ========================================================================= */
+
+void
+ReduceList (DocList * cset)
+{
+  DocEntry *src;
+  DocEntry *dest;
+
+  src = dest = cset->DE;
+  for (src = dest = cset->DE; src < cset->DE + cset->num; src++)
+    {
+      if (src->or_included)
+	{
+	  src->or_included = 0;
+	  *dest++ = *src;
+	}
+    }
+  cset->num = dest - cset->DE;
+
+}				/*ReduceList */
+
+/* =========================================================================
+ * Function: BooleanGet
+ * Description: 
+ * Input: 
+ * Output: 
+ * ========================================================================= */
+static DocList *
+BooleanGet (query_data * qd, bool_tree_node * n,
+	    BooleanQueryInfo * bqi)
+{
+  if (n)
+    {
+      DocList *res = NULL;
+      switch (BOOL_TAG (n))
+	{
+	case N_all:
+	  Message ("Unexpected \"all\" node in the parse tree.");
+	  res = MakeDocList (0);
+	  break;
+	case N_not:
+	  Message ("Unexpected \"not\" node in the parse tree.");
+	  res = MakeDocList (0);
+	  break;
+	case N_none:
+	  {
+	    res = MakeDocList (0);
+	    break;
+	  }
+	case N_diff:
+	  {
+	    res = BooleanGet (qd, BOOL_CHILD (n), bqi);
+	    n = BOOL_SIBLING (BOOL_CHILD (n));
+	    while (n)
+	      {
+		bool_tree_node *next = BOOL_SIBLING (n);
+		if (BOOL_TAG (n) == N_term)
+		  {
+		    WordEntry *we = GetNthWE (qd->TL, BOOL_TERM (n));
+		    res = GetDocsOp (qd, we, op_diff_terms, res);
+		  }
+		else
+		  res = DiffLists (res, BooleanGet (qd, n, bqi));
+		n = next;
+	      }
+	    break;
+	  }
+	case N_and:
+	  {
+	    res = BooleanGet (qd, BOOL_CHILD (n), bqi);		/* initial fill of c-set */
+	    n = BOOL_SIBLING (BOOL_CHILD (n));
+	    while (n)
+	      {
+		bool_tree_node *next = BOOL_SIBLING (n);
+		switch (BOOL_TAG (n))
+		  {
+		  case N_term:
+		    {
+		      WordEntry *we = GetNthWE (qd->TL, BOOL_TERM (n));
+		      res = GetDocsOp (qd, we, op_and_terms, res);
+		    }
+		    break;
+		  case N_or_terms:
+		    {
+		      bool_tree_node *child = BOOL_CHILD (n);
+		      /* note: all children are terms - predetermined */
+		      while (child)
+			{
+			  WordEntry *we = GetNthWE (qd->TL, BOOL_TERM (child));
+			  res = GetDocsOp (qd, we, op_and_or_terms, res);
+			  child = BOOL_SIBLING (child);
+			}
+		      ReduceList (res);
+		    }
+		    break;
+		  default:
+		    res = IntersectLists (res, BooleanGet (qd, n, bqi));
+		  }		/*switch */
+		n = next;
+	      }
+	    break;
+	  }
+	case N_or:
+	case N_or_terms:
+	  {
+	    res = BooleanGet (qd, BOOL_CHILD (n), bqi);
+	    n = BOOL_SIBLING (BOOL_CHILD (n));
+	    while (n)
+	      {
+		bool_tree_node *next = BOOL_SIBLING (n);
+		res = MergeLists (res, BooleanGet (qd, n, bqi));
+		n = next;
+	      }
+	    break;
+	  }
+	case N_term:
+	  {
+	    res = GetDocsOp (qd, GetNthWE (qd->TL, BOOL_TERM (n)), op_term, NULL);
+	    break;
+	  }
+	}
+      return (res ? res : MakeDocList (0));
+    }
+  else
+    return MakeDocList (0);
+}
+
+/* =========================================================================
+ * Function: AdjustParaDocs
+ * Description: 
+ * Input: 
+ * Output: 
+ * ========================================================================= */
+static int 
+DE_comp (void *a, void *b)
+{
+  return ((DocEntry *) a)->SeekPos - ((DocEntry *) b)->SeekPos;
+}
+
+static void
+AdjustParaDocs (query_data * qd, DocList * Docs)
+{
+  DocEntry *DE = Docs->DE;
+  int s, d;
+  Splay_Tree *SP;
+
+
+  /* Make the doc-list contain only references to unique
+   * real documents. So can get rid of cases where there
+   * are multiple paragraphs for a real document.
+   */
+
+  /* Note: [TS: 29/Sep/94] */
+  /* reads in seek-pos for docnums so can compare docs */
+  /* seek-pos used as real doc identifier */
+  /* whereas doc-num entries refer to paragraphs -- I think */
+  for (s = 0; s < Docs->num; s++)
+    FetchDocStart (qd, DE[s].DocNum, &DE[s].SeekPos, &DE[s].Len);
+
+  Message ("Original Number = %d\n", Docs->num);
+  SP = SP_createset (DE_comp);
+  d = 0;
+  for (s = 0; s < Docs->num; s++)
+    if (!SP_member (&DE[s], SP))
+      {
+	DE[d] = DE[s];
+	SP_insert (&DE[d], SP);
+	d++;
+      }
+  SP_freeset (SP);
+  Docs->num = d;
+  Message ("Final Number = %d\n", Docs->num);
+}
+
+/* =========================================================================
+ * Function: BooleanQuery 
+ * Description: 
+ *      The main control function for the boolean query.
+ * Input: 
+ * Output: 
+ *      qd->DL
+ * ========================================================================= */
+
+void 
+BooleanQuery (query_data * qd, char *Query, BooleanQueryInfo * bqi,
+	      int stem_method)
+{
+  bool_tree_node *tree;
+  DocList *Docs;
+  int res = 0;
+
+  tree = ParseBool (Query, MAXLINEBUFFERLEN, &(qd->TL), 
+		    qd->sd->sdh.stemmer_num, stem_method, &res,
+		    qd->sd, qd->sd->sdh.indexed,         /* [RPAP - Jan 97: Stem Index Change] */
+		    &(qd->QTL));                         /* [RPAP - Feb 97: Term Frequency] */
+
+  /* [TS:Aug/94] no longer tries to continue after parse failure */
+  if (res != 0)			/* failed the parse */
+    {
+      qd->DL = NULL;		/* have empty doc-list */
+      return;
+    }
+
+  /* [RPAP - Feb 97: Term Frequency] */
+  /*  ReadInTermInfo (qd); */
+
+  FindNoneTerms (qd, tree);
+
+  OptimiseBoolTree (tree, qd->TL, atoi (GetEnv ("optimise_type")));
+
+  qd->hops_taken = qd->num_of_ptrs = 0;
+  qd->num_of_terms = 0;
+
+  Docs = BooleanGet (qd, tree, bqi);
+
+/* [RPAP - Feb 97: NZDL Specifics] */
+#if !defined(PARABOOLEANMATCHES) && !defined(NZDL)
+  if (qd->id->ifh.InvfLevel == 3)
+    {
+      AdjustParaDocs (qd, Docs);
+    }
+#endif
+
+  if (bqi->MaxDocsToRetrieve != -1 && Docs->num > bqi->MaxDocsToRetrieve)
+    Docs->num = bqi->MaxDocsToRetrieve;
+
+  FreeQueryDocs (qd);
+
+  qd->DL = Docs;
+}
Index: /main/tags/2.25/gsdl/packages/mg/src/text/bool_query.h
===================================================================
--- /main/tags/2.25/gsdl/packages/mg/src/text/bool_query.h	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/mg/src/text/bool_query.h	(revision 21064)
@@ -0,0 +1,52 @@
+/**************************************************************************
+ *
+ * bool_query.h -- boolean query processing
+ * Copyright (C) 1994  Authors
+ *
+ * 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.
+ *
+ * $Id$
+ *
+ **************************************************************************/
+
+/*
+   $Log$
+   Revision 1.1  1999/08/10 21:17:45  sjboddie
+   renamed mg-1.3d directory mg
+
+   Revision 1.1  1998/11/17 09:34:28  rjmcnab
+   *** empty log message ***
+
+   * Revision 1.1  1994/10/20  03:56:36  tes
+   * I have rewritten the boolean query optimiser and abstracted out the
+   * components of the boolean query.
+   *
+   * Revision 1.1  1994/10/12  01:15:33  tes
+   * Found bugs in the existing boolean query optimiser.
+   * So decided to rewrite it.
+   * I accidentally deleted query.bool.y, but I have replaced it
+   * with bool_parser.y (which I have forgotten to add here ! ;-(
+   *
+ */
+
+#ifndef BOOL_QUERY_H
+#define BOOL_QUERY_H
+
+#include "backend.h"
+
+void BooleanQuery (query_data * qd, char *Query, BooleanQueryInfo * bqi,
+		   int stem_method);
+
+#endif
Index: /main/tags/2.25/gsdl/packages/mg/src/text/bool_tester.c
===================================================================
--- /main/tags/2.25/gsdl/packages/mg/src/text/bool_tester.c	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/mg/src/text/bool_tester.c	(revision 21064)
@@ -0,0 +1,182 @@
+/**************************************************************************
+ *
+ * bool_tester -- used to test bool_tree, bool_parser, bool_optimiser
+ * Copyright (C) 1994  Authors
+ *
+ * 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.
+ *
+ * $Id$
+ *
+ **************************************************************************/
+
+/*
+   $Log$
+   Revision 1.2  2000/03/05 22:58:24  sjboddie
+   compiler complained about using stdin and stdout to do global
+   initialization - variables were never changed so they were
+   replaced with #defines
+
+   Revision 1.1  1999/08/10 21:17:45  sjboddie
+   renamed mg-1.3d directory mg
+
+   Revision 1.2  1998/11/25 07:55:41  rjmcnab
+
+   Modified mg to that you can specify the stemmer you want
+   to use via a command line option. You specify it to
+   mg_passes during the build process. The number of the
+   stemmer that you used is stored within the inverted
+   dictionary header and the stemmed dictionary header so
+   the correct stemmer is used in later stages of building
+   and querying.
+
+   Revision 1.1  1998/11/17 09:34:29  rjmcnab
+   *** empty log message ***
+
+   * Revision 1.2  1995/03/14  05:15:23  tes
+   * Updated the boolean query optimiser to do different types of optimisation.
+   * A query environment variable "optimise_type" specifies which one is to be
+   * used. Type 1 is the new one which is faster than 2.
+   *
+   * Revision 1.2  1994/10/18  06:11:05  tes
+   * The boolean optimiser seems to be modifying the parse tree
+   * like it is supposed to.
+   * Paragraph ranking now works without any text files if required to.
+   *
+   * Revision 1.1  1994/10/12  01:15:33  tes
+   * Found bugs in the existing boolean query optimiser.
+   * So decided to rewrite it.
+   * I accidentally deleted query.bool.y, but I have replaced it
+   * with bool_parser.y (which I have forgotten to add here ! ;-(
+   *
+ */
+
+static char *RCSID = "$Id$";
+
+#include "sysfuncs.h"
+
+#include "local_strings.h"
+#include "term_lists.h"
+#include "bool_tree.h"
+#include "bool_parser.h"
+#include "bool_optimiser.h"
+#include "query_term_list.h"  /* [RPAP - Feb 97: Term Frequency] */
+
+#define MAX_LINE_LEN  255
+#define STEMMER_NUM 0 /* Lovin's stemmer */
+#define STEM_METHOD 3
+
+/* Newer compilers complain when you use stdin and stdout to do global 
+initialization. Since they're static we'll just use #defines instead
+static FILE *file_in = stdin;
+static FILE *file_out = stdout;
+*/
+#define FILE_IN stdin
+#define FILE_OUT stdout
+
+static char line[MAX_LINE_LEN + 1];
+
+/* --- prototypes --- */
+static char *prompt (char *str);
+
+
+/* =========================================================================
+ * Function: main
+ * Description: 
+ * Input: 
+ * Output: 
+ * ========================================================================= */
+
+int main (int argc, char *argv[])
+{
+  bool_tree_node *tree = NULL;
+  TermList *term_list = NULL;
+  QueryTermList *query_term_list = NULL;  /* [RPAP - Feb 97: Term Frequency] */
+  int opt_type = 0;
+
+  while (1)
+    {
+      int res = 0;
+      int len = 0;
+
+      /* get a line */
+      if (!prompt ("Please enter boolean expression..."))
+	break;
+
+      len = strlen (line) - 1;	/* -1 => ignore the \n */
+
+      tree = ParseBool (line, len, &term_list, STEMMER_NUM, STEM_METHOD, &res,
+			NULL, 0,             /* [RPAP - Jan 97: Stem Index Change] */
+			&query_term_list);   /* [RPAP - Feb 97: Term Frequency] */
+
+      {
+	int done = 0;
+	while (!done)
+	  {
+	    if (!prompt ("Which type of optimisation 1 or 2 ?"))
+	      break;
+	    opt_type = atoi (line);
+	    done = (opt_type == 1 || opt_type == 2);
+	  }
+      }
+
+      if (!prompt ("Do you want to assign doc_counts to terms ?"))
+	break;
+
+      if (toupper (line[0]) == 'Y')
+	{
+	  /* cycle thru terms asking for doc_counts */
+	  int i;
+	  for (i = 0; i < term_list->num; i++)
+	    {
+	      char str[80];
+	      TermEntry *te = &(term_list->TE[i]);
+
+	      sprintf (str, "Please enter doc count for term '%s'",
+		       str255_to_string (te->Word, NULL));
+	      prompt (str);
+	      te->WE.doc_count = atoi (line);
+	      printf ("doc_count = %ld\n", te->WE.doc_count);
+	    }			/*for */
+	}			/*if */
+
+
+      if (res == 0)
+	{
+	  fprintf (FILE_OUT, "\n***Parsed Expression***\n");
+	  PrintBoolTree (tree, FILE_OUT);
+	  fputc ('\n', FILE_OUT);
+	  OptimiseBoolTree (tree, term_list, opt_type);
+	  fprintf (FILE_OUT, "\n***Optimised Expression ***\n");
+	  PrintBoolTree (tree, FILE_OUT);
+	  fputc ('\n', FILE_OUT);
+	}
+
+    }
+  return 0;
+}
+
+/* =========================================================================
+ * Function: 
+ * Description: 
+ * Input: 
+ * Output: 
+ * ========================================================================= */
+
+static char *
+prompt (char *str)
+{
+  fprintf (FILE_OUT, "\n%s\n", str);
+  return fgets (line, MAX_LINE_LEN, FILE_IN);
+}
Index: /main/tags/2.25/gsdl/packages/mg/src/text/bool_tree.c
===================================================================
--- /main/tags/2.25/gsdl/packages/mg/src/text/bool_tree.c	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/mg/src/text/bool_tree.c	(revision 21064)
@@ -0,0 +1,292 @@
+/**************************************************************************
+ *
+ * bool_tree.c -- Boolean parse tree ADT
+ * Copyright (C) 1994  Tim Shimmin
+ *
+ * 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.
+ *
+ *       @(#)query.bool.y	1.9 16 Mar 1994
+ *
+ **************************************************************************/
+
+#include "sysfuncs.h"
+
+#include "memlib.h"
+#include "messages.h"
+#include "bool_tree.h"
+
+static char *RCSID = "$Id$";
+
+
+/* =========================================================================
+ * Function: CreateBoolNode
+ * Description: 
+ * Input: 
+ * Output: 
+ * ========================================================================= */
+bool_tree_node *
+CreateBoolNode (N_Tag tag)
+{
+  bool_tree_node *n;
+  if (!(n = Xmalloc (sizeof (bool_tree_node))))
+    FatalError (1, "Can not create bool_tree_node for boolean query");
+  n->tag = tag;
+  BOOL_SIBLING (n) = NULL;
+  return n;
+}
+
+/* =========================================================================
+ * Function: 
+ * Description: 
+ * Input: 
+ * Output: 
+ * ========================================================================= */
+bool_tree_node *
+CreateBoolTermNode (TermList ** tl, char *text, int Count, int word_num,
+		    u_long count, u_long doc_count, u_long invf_ptr, u_long invf_len,  /* [RPAP - Feb 97: Term Frequency] */
+		    int stemmer_num) 
+{
+  bool_tree_node *n = NULL;
+
+  /* allocate bool_tree_node */
+  n = CreateBoolNode (N_term);
+
+  BOOL_TERM (n) = AddTerm (tl, (u_char *) text, Count, word_num, count, doc_count, 
+			   invf_ptr, invf_len, stemmer_num);  /* [RPAP - Feb 97: Term Frequency] */
+
+  return n;
+}
+
+
+/* =========================================================================
+ * Function: CreateTreeNode
+ * Description: 
+ * Input: 
+ * Output: 
+ * ========================================================================= */
+
+bool_tree_node *
+CreateBoolTreeNode (N_Tag tag, bool_tree_node * left, bool_tree_node * right)
+{
+  bool_tree_node *n = CreateBoolNode (tag);
+
+  BOOL_CHILD (n) = left;
+  if (left)
+    BOOL_SIBLING (left) = right;
+  if (right)
+    BOOL_SIBLING (right) = NULL;
+
+  return (n);
+}
+
+/* =========================================================================
+ * Function: 
+ * Description: 
+ * Input: 
+ * Output: 
+ * ========================================================================= */
+
+int
+EqualBoolNodes (bool_tree_node * a, bool_tree_node * b)
+{
+  if (BOOL_TAG (a) == N_term && BOOL_TAG (a) == N_term)
+    return BOOL_TERM (a) == BOOL_TERM (b);
+  return 0;
+}
+
+/* =========================================================================
+ * Function: FreeBoolTree
+ * Description: 
+ *      Notes: does not fix up any parent or sibling links around given tree
+ * Input: 
+ * Output: 
+ * ========================================================================= */
+
+static void 
+FreeTree (bool_tree_node * tree)
+{
+  bool_tree_node *sibling;
+
+  while (tree)
+    {
+      if (BOOL_HAS_CHILD (tree))
+	FreeTree (BOOL_CHILD (tree));
+      sibling = BOOL_SIBLING (tree);
+      Xfree (tree);
+      tree = sibling;
+    }
+}
+
+void 
+FreeBoolTree (bool_tree_node ** the_tree)
+{
+  bool_tree_node *tree = *the_tree;
+
+  if (!tree)
+    return;
+
+  FreeTree (tree);
+  *the_tree = NULL;
+/*********************************/
+  /* THIS IS POTENTIALLY DANGEROUS */
+  /* FIX UP LATER */
+  /* Need to correct the links for parent/siblings */
+/*********************************/
+
+}
+
+/* =========================================================================
+ * Function: PrintBoolTree
+ * Description: 
+ *      Print out a text version of the tree to the file
+ * Input: 
+ * Output: 
+ * ========================================================================= */
+
+static void
+PrintBinaryOp (bool_tree_node * tree, FILE * file, char op)
+{
+  bool_tree_node *child = NULL;
+  assert (BOOL_HAS_CHILD (tree));
+
+  child = BOOL_CHILD (tree);
+  while (child)
+    {
+      PrintBoolTree (child, file);
+      child = BOOL_SIBLING (child);
+      if (child)
+	fprintf (file, " %c ", op);
+    }
+}
+
+static void
+PrintUnaryOp (bool_tree_node * tree, FILE * file, char op)
+{
+  bool_tree_node *child = NULL;
+
+  fprintf (file, " %c ", op);
+  assert (BOOL_HAS_CHILD (tree));
+  child = BOOL_CHILD (tree);
+  PrintBoolTree (child, file);
+}
+
+void
+PrintBoolTree (bool_tree_node * tree, FILE * file)
+{
+  if (!tree)
+    return;
+
+  fprintf (file, "(");
+  switch (BOOL_TAG (tree))
+    {
+    case N_term:
+      fprintf (file, "term %d", BOOL_TERM (tree));
+      break;
+    case N_and:
+      PrintBinaryOp (tree, file, '&');
+      break;
+    case N_or:
+      PrintBinaryOp (tree, file, '|');
+      break;
+    case N_or_terms:
+      PrintBinaryOp (tree, file, '+');
+      break;
+    case N_diff:
+      PrintBinaryOp (tree, file, '-');
+      break;
+    case N_not:
+      PrintUnaryOp (tree, file, '!');
+      break;
+    case N_all:
+      fprintf (file, " TRUE ");
+      break;
+    case N_none:
+      fprintf (file, " FALSE ");
+      break;
+    default:
+      break;
+    }
+
+  fprintf (file, ")");
+}
+
+
+/* =========================================================================
+ * Function: CopyBoolTree
+ * Description: 
+ * Input: 
+ * Output: 
+ * ========================================================================= */
+
+bool_tree_node *
+CopyBoolTree (bool_tree_node * tree)
+{
+  bool_tree_node *sibling = NULL;
+  bool_tree_node *tree_copy = NULL;
+  bool_tree_node *prev = NULL;
+
+  if (!tree)
+    return NULL;
+
+  sibling = tree;
+  prev = NULL;
+  while (sibling)
+    {
+      /* copy sibling */
+      bool_tree_node *sibling_copy = (bool_tree_node *) malloc (sizeof (bool_tree_node));
+      if (!sibling_copy)
+	FatalError (1, "No memory for bool tree copy");
+      bcopy ((char *) sibling, (char *) sibling_copy, sizeof (bool_tree_node));
+
+      if (BOOL_HAS_CHILD (sibling))
+	{
+	  BOOL_CHILD (sibling_copy) = CopyBoolTree (BOOL_CHILD (sibling));
+	}
+
+      /* do the link up of copies */
+      if (prev)
+	BOOL_SIBLING (prev) = sibling_copy;
+      else
+	tree_copy = sibling_copy;
+      prev = sibling_copy;
+
+      sibling = BOOL_SIBLING (sibling);
+    }
+  return tree_copy;
+}
+
+
+/* =========================================================================
+ * Function: LastBoolSibling
+ * Description: 
+ * Input: 
+ * Output: 
+ * ========================================================================= */
+
+bool_tree_node *
+LastBoolSibling (bool_tree_node * tree)
+{
+
+  if (!tree)
+    return NULL;
+
+  do
+    {
+      tree = BOOL_SIBLING (tree);
+    }
+  while (BOOL_SIBLING (tree));
+
+  return tree;
+}
Index: /main/tags/2.25/gsdl/packages/mg/src/text/bool_tree.h
===================================================================
--- /main/tags/2.25/gsdl/packages/mg/src/text/bool_tree.h	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/mg/src/text/bool_tree.h	(revision 21064)
@@ -0,0 +1,110 @@
+/**************************************************************************
+ *
+ * bool_tree.h -- description
+ * Copyright (C) 1994  Authors
+ *
+ * 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.
+ *
+ * $Id$
+ *
+ **************************************************************************/
+
+/*
+   $Log$
+   Revision 1.1  1999/08/10 21:17:46  sjboddie
+   renamed mg-1.3d directory mg
+
+   Revision 1.2  1998/11/25 07:55:42  rjmcnab
+
+   Modified mg to that you can specify the stemmer you want
+   to use via a command line option. You specify it to
+   mg_passes during the build process. The number of the
+   stemmer that you used is stored within the inverted
+   dictionary header and the stemmed dictionary header so
+   the correct stemmer is used in later stages of building
+   and querying.
+
+   Revision 1.1  1998/11/17 09:34:31  rjmcnab
+   *** empty log message ***
+
+   * Revision 1.2  1995/03/14  05:15:25  tes
+   * Updated the boolean query optimiser to do different types of optimisation.
+   * A query environment variable "optimise_type" specifies which one is to be
+   * used. Type 1 is the new one which is faster than 2.
+   *
+   * Revision 1.2  1994/10/18  06:11:07  tes
+   * The boolean optimiser seems to be modifying the parse tree
+   * like it is supposed to.
+   * Paragraph ranking now works without any text files if required to.
+   *
+   * Revision 1.1  1994/10/12  01:15:35  tes
+   * Found bugs in the existing boolean query optimiser.
+   * So decided to rewrite it.
+   * I accidentally deleted query.bool.y, but I have replaced it
+   * with bool_parser.y (which I have forgotten to add here ! ;-(
+   *
+ */
+
+#ifndef BOOL_TREE_H
+#define BOOL_TREE_H
+
+#include "sysfuncs.h"
+#include "term_lists.h"
+
+typedef enum
+  {
+    N_term, N_and, N_or, N_diff, N_none, N_all,
+    N_not, N_or_terms
+  }
+N_Tag;
+
+typedef struct bool_tree_node
+  {
+    N_Tag tag;
+    struct bool_tree_node *sibling;
+    union
+      {
+	struct bool_tree_node *child;
+	int term_id;
+      }
+    fields;
+    int sum_ft;			/* for or_terms nodes */
+  }
+bool_tree_node;
+
+
+#define BOOL_HAS_CHILD(n) (\
+			(n)->tag==N_and || \
+			(n)->tag==N_or || (n)->tag==N_or_terms || \
+			(n)->tag==N_not || (n)->tag==N_diff)
+#define BOOL_TAG(n) ((n)->tag)
+#define BOOL_SIBLING(n) ((n)->sibling)
+#define BOOL_TERM(n) ((n)->fields.term_id)
+#define BOOL_CHILD(n) ((n)->fields.child)
+#define BOOL_SUM_FT(n) ((n)->sum_ft)
+
+bool_tree_node *CreateBoolNode (N_Tag tag);
+bool_tree_node *CopyBoolTree (bool_tree_node * tree);
+bool_tree_node *CreateBoolTermNode (TermList ** tl, char *text, int Count, int word_num,
+				    u_long count, u_long doc_count, u_long invf_ptr, 
+				    u_long invf_len, int stemmer_num);
+bool_tree_node *CreateBoolTreeNode (N_Tag tag,
+			     bool_tree_node * left, bool_tree_node * right);
+void FreeBoolTree (bool_tree_node ** tree);
+void PrintBoolTree (bool_tree_node * tree, FILE * file);
+bool_tree_node *LastBoolSibling (bool_tree_node * tree);
+
+
+#endif
Index: /main/tags/2.25/gsdl/packages/mg/src/text/build.h
===================================================================
--- /main/tags/2.25/gsdl/packages/mg/src/text/build.h	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/mg/src/text/build.h	(revision 21064)
@@ -0,0 +1,170 @@
+/**************************************************************************
+ *
+ * build.h -- Global information for the passes of mg_passes
+ * Copyright (C) 1994  Neil Sharman, Alistair Moffat and Lachlan Andrew
+ *
+ * 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.
+ *
+ * $Id$
+ *
+ **************************************************************************/
+
+
+#ifndef H_BUILD
+#define H_BUILD
+
+
+#define	TERMPARAGRAPH	'\003'
+
+
+int init_special (char *file_name);
+int init_text_1 (char *file_name);
+int init_text_2 (char *file_name);
+int init_invf_1 (char *file_name);
+int init_invf_2 (char *file_name);
+int init_ivf_1 (char *file_name);
+int init_ivf_2 (char *file_name);
+/*
+ * file_name  IN      The name of the dictionary file
+ * 
+ * returns      COMPALLOK for all ok,
+ *              COMPERROR for any error.  e.g. cannot read file
+ */
+
+
+
+
+
+int process_special (u_char * s_in, int l_in);
+int process_text_1 (u_char * s_in, int l_in);
+int process_text_2 (u_char * s_in, int l_in);
+int process_invf_1 (u_char * s_in, int l_in);
+int process_invf_2 (u_char * s_in, int l_in);
+int process_ivf_1 (u_char * s_in, int l_in);
+int process_ivf_2 (u_char * s_in, int l_in);
+/*
+ * s_in               IN      The binary string to be compressed
+ * l_in         IN      The number of characters in s_in
+ *
+ * returns      COMPALLOK for all ok,
+ *              COMPERROR for any error.  e.g. cannot read file
+ *
+ * The calling routine is responsible for ensuring that s_out is long 
+ * enough.
+ */
+
+
+
+
+
+int done_special (char *filename);
+int done_text_1 (char *filename);
+int done_text_2 (char *filename);
+int done_invf_1 (char *filename);
+int done_invf_2 (char *filename);
+int done_ivf_1 (char *filename);
+int done_ivf_2 (char *filename);
+/*
+ * returns    COMPALLOK for all ok,
+ *              COMPERROR for any error.  e.g. cannot write file
+ */
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+extern char InvfLevel;
+/*
+ * This will determine the level of the inverted file it can take on the
+ * values 1, 2, or 3.
+ *
+ * Level 1: The inverted file contains only document numbers making it possible
+ *          to do only boolean queries.
+ * 
+ * Level 2: The inverted file also contains word counts per document making it
+ *          possible to do cosine ranked queries.
+ *
+ * Level 3: The inverted file contains word positions.
+ */
+
+
+extern unsigned long buf_size;
+/*
+ * The size of the document input buffer.
+ */
+
+extern unsigned long ChunkLimit;
+/*
+ * The maximum number of chunks that can be written to disk.
+ */
+
+extern unsigned long invf_buffer_size;
+/*
+ * The amount of memory to allocate to the invertion buffer.
+ */
+
+extern char SkipSGML;
+/*
+ * 1 if SGML tags are to be considered non-words when building the 
+ * inverted file.
+ */
+
+extern char MakeWeights;
+/*
+ * 1 if the weights file should be generated.
+ */
+
+extern FILE *Comp_Stats;
+/*
+ * Contains a file pointer to the file where compression stats should be sent
+ */
+
+extern int comp_stat_point;
+/*
+ * Generate a compression stat entry every comp_stat_point bytes 
+ */
+
+extern double bytes_processed; /* [RJM 07/97: 4G limit] */
+/*
+ * The number of bytes processed. NOTE: This excludes document separators.
+ */
+
+extern double bytes_received; /* [RJM 07/97: 4G limit] */
+/*
+ * The number of bytes processed. NOTE: This includes document separators.
+ */
+
+
+extern int stemmer_num;
+/*
+ * The stemmer to use for stemming words for the inverted file.
+ * see stemmer.h
+ */
+
+extern int stem_method;
+/*
+ * The method to use for stemming words for the inverted file.
+ * see stemmer.h
+ */
+#endif
Index: /main/tags/2.25/gsdl/packages/mg/src/text/commands.c
===================================================================
--- /main/tags/2.25/gsdl/packages/mg/src/text/commands.c	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/mg/src/text/commands.c	(revision 21064)
@@ -0,0 +1,582 @@
+/**************************************************************************
+ *
+ * commands.c -- mgquery command processing functions
+ * Copyright (C) 1994  Neil Sharman
+ *
+ * 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.
+ *
+ * $Id$
+ *
+ **************************************************************************/
+
+/*
+   $Log$
+   Revision 1.1  1999/08/10 21:17:47  sjboddie
+   renamed mg-1.3d directory mg
+
+   Revision 1.1  1998/11/17 09:34:32  rjmcnab
+   *** empty log message ***
+
+   * Revision 1.2  1994/09/20  04:41:22  tes
+   * For version 1.1
+   *
+ */
+
+static char *RCSID = "$Id$";
+
+#include "sysfuncs.h"
+#include "memlib.h"
+#include "messages.h"
+
+#include "environment.h"
+#include "mg.h"
+#include "locallib.h"
+#include "backend.h"		/* for qd */
+#include "term_lists.h"		/* for MAXTERMSTRLEN */
+
+/* [RPAP - Feb 97: WIN32 Port] */
+#ifdef __WIN32__
+# define OPENPIPE        _popen
+# define CLOSEPIPE       _pclose
+#else
+# define OPENPIPE        popen
+# define CLOSEPIPE       pclose
+#endif
+
+extern char *PathName;
+extern FILE *OutFile, *InFile;
+extern int OutPipe, InPipe;
+extern int Quitting;
+
+char *CommandsErrorStr = NULL;
+
+/* [TS: June/95] */
+/* current qd for use by any commands */
+static query_data *the_qd = NULL;
+
+
+#include "help.mg.h"
+#include "warranty.h"
+#include "conditions.h"
+
+static void 
+CmdQuit (void)
+{
+  Quitting = 1;
+}
+
+static void 
+CmdPush (void)
+{
+  PushEnv ();
+}
+
+
+static void 
+CmdPop (void)
+{
+  PopEnv ();
+  if (EnvStackHeight () == 1)
+    PushEnv ();
+}
+
+static void 
+CmdHelp (void)
+{
+  FILE *more;
+  int i;
+
+  if (!(more = OPENPIPE (GetDefEnv ("pager", "more"), "w")))  /* [RPAP - Feb 97: WIN32 Port] */
+    {
+      fprintf (stderr, "ERROR : Unable to run more\n");
+      return;
+    }
+  for (i = 0; i < sizeof (help_str) / sizeof (help_str[0]); i++)
+    fputs (help_str[i], more);
+
+  CLOSEPIPE (more);  /* [RPAP - Feb 97: WIN32 Port] */
+}
+
+
+static void 
+CmdWarranty (void)
+{
+  FILE *more;
+  int i;
+
+  if (!(more = OPENPIPE (GetDefEnv ("pager", "more"), "w")))  /* [RPAP - Feb 97: WIN32 Port] */
+    {
+      fprintf (stderr, "ERROR : Unable to run more\n");
+      return;
+    }
+  for (i = 0; i < sizeof (warranty_str) / sizeof (warranty_str[0]); i++)
+    fputs (warranty_str[i], more);
+
+  CLOSEPIPE (more);  /* [RPAP - Feb 97: WIN32 Port] */
+}
+
+
+static void 
+CmdConditions (void)
+{
+  FILE *more;
+  int i;
+
+  if (!(more = OPENPIPE (GetDefEnv ("pager", "more"), "w")))  /* [RPAP - Feb 97: WIN32 Port] */
+    {
+      fprintf (stderr, "ERROR : Unable to run more\n");
+      return;
+    }
+  for (i = 0; i < sizeof (cond_str) / sizeof (cond_str[0]); i++)
+    fputs (cond_str[i], more);
+
+  CLOSEPIPE (more);
+}
+
+static void 
+CmdReset (void)
+{
+  while (EnvStackHeight () > 1)
+    PopEnv ();
+  PushEnv ();
+}
+
+static void 
+CmdDisplay (void)
+{
+  int i;
+  size_t l = 0;
+  char *name;
+  for (i = 0; (name = GetEnvName (i)) != NULL; i++)
+    if (strlen (name) > l)
+      l = strlen (name);
+
+  for (i = 0; (name = GetEnvName (i)) != NULL; i++)
+    printf ("%-*s = \"%s\"\n", (int) l, name, GetEnv (name));
+}
+
+static void 
+CmdQueryTerms (void)
+{
+  static char terms_str[MAXTERMSTRLEN + 1];
+
+  if (the_qd && the_qd->TL)
+    {
+      ConvertTermsToString (the_qd->TL, terms_str);
+      printf ("%s\n", terms_str);
+      fflush (stdout);
+    }
+
+}
+
+
+static void 
+CmdSet (char *name, char *value)
+{
+  if (!*name)
+    {
+      CommandsErrorStr = "Blank names are not permitted";
+      return;
+    }
+  switch (SetEnv (name, value, NULL))
+    {
+    case -1:
+      CommandsErrorStr = "Out of memory\n";
+      break;
+    case -2:
+      CommandsErrorStr = ConstraintErrorStr;
+      break;
+    }
+}
+
+static void 
+CmdUnset (char *name)
+{
+  if (!*name)
+    {
+      CommandsErrorStr = "Blank names are not permitted";
+      return;
+    }
+  if (UnsetEnv (name, 0) == -1)
+    CommandsErrorStr = "Specified name does not exist";
+}
+
+
+
+
+
+
+/*
+ * Do the .input command 
+ */
+static void 
+CmdInput (char *param1, char *param2)
+{
+  enum
+  {
+    READ, APPEND, PIPEFROM
+  }
+  mode;
+  FILE *NewInput;
+  char *buf, *s;
+
+  /* join the two parameters together */
+  buf = Xmalloc (strlen (param1) + strlen (param2) + 1);
+  strcpy (buf, param1);
+  strcat (buf, param2);
+  s = buf;
+
+
+  while (*s == ' ' || *s == '\t')
+    s++;
+
+  if (*s == '<')
+    {
+      s++;
+      mode = READ;
+    }
+  else if (*s == '|')
+    {
+      mode = PIPEFROM;
+      s++;
+    }
+  else
+    {
+      if (InPipe)
+	CLOSEPIPE (InFile);  /* [RPAP - Feb 97: WIN32 Port] */
+      else if (InFile != stdin)
+	fclose (InFile);
+      InPipe = 0;
+      InFile = stdin;
+      Xfree (buf);
+      return;
+    }
+
+  while (*s == ' ' || *s == '\t')
+    s++;
+
+  if (*s)
+    {
+      if (mode == READ)
+	NewInput = fopen (s, "r");
+      else
+	NewInput = OPENPIPE (s, "r");  /* [RPAP - Feb 97: WIN32 Port] */
+
+      if (NewInput)
+	{
+	  if (InPipe)
+	    CLOSEPIPE (InFile);  /* [RPAP - Feb 97: WIN32 Port] */
+	  else if (InFile != stdin)
+	    fclose (InFile);
+	  InPipe = (mode == PIPEFROM);
+	  InFile = NewInput;
+	}
+      else
+	CommandsErrorStr = "Bad input file/pipe";
+    }
+  else
+    {
+      if (InPipe)
+	CLOSEPIPE (InFile);  /* [RPAP - Feb 97: WIN32 Port] */
+      else if (InFile != stdin)
+	fclose (InFile);
+      InPipe = 0;
+      InFile = stdin;
+    }
+  Xfree (buf);
+}
+
+
+
+static void 
+CmdOutput (char *param1, char *param2)
+{
+  enum
+  {
+    WRITE, APPEND, PIPETO
+  }
+  mode;
+  char *buf, *s;
+  FILE *NewOutput;
+
+  /* join the two parameters together */
+  buf = Xmalloc (strlen (param1) + strlen (param2) + 1);
+  strcpy (buf, param1);
+  strcat (buf, param2);
+  s = buf;
+
+  while (*s == ' ' || *s == '\t')
+    s++;
+
+  if (*s == '>')
+    {
+      s++;
+      mode = APPEND;
+      if (*s == '>')
+	s++;
+      else
+	mode = WRITE;
+    }
+  else if (*s == '|')
+    {
+      mode = PIPETO;
+      s++;
+    }
+  else
+    {
+      if (OutPipe)
+	CLOSEPIPE (OutFile);  /* [RPAP - Feb 97: WIN32 Port] */
+      else if (OutFile != stdout)
+	fclose (OutFile);
+      OutPipe = 0;
+      OutFile = stdout;
+      Xfree (buf);
+      return;
+    }
+
+  while (*s == ' ' || *s == '\t')
+    s++;
+
+  if (*s)
+    {
+      if (mode == PIPETO)
+	NewOutput = OPENPIPE (s, "w");  /* [RPAP - Feb 97: WIN32 Port] */
+      else
+	NewOutput = fopen (s, mode == WRITE ? "w" : "a");
+      if (NewOutput)
+	{
+	  if (OutPipe)
+	    CLOSEPIPE (OutFile);  /* [RPAP - Feb 97: WIN32 Port] */
+	  else if (OutFile != stdout)
+	    fclose (OutFile);
+	  OutPipe = (mode == PIPETO);
+	  OutFile = NewOutput;
+	}
+      else
+	CommandsErrorStr = "Bad output file/pipe";
+    }
+  else
+    {
+      if (OutPipe)
+	CLOSEPIPE (OutFile);  /* [RPAP - Feb 97: WIN32 Port] */
+      else if (OutFile != stdout)
+	fclose (OutFile);
+      OutPipe = 0;
+      OutFile = stdout;
+    }
+  Xfree (buf);
+}
+
+
+
+static char *
+ParseArg (char *line, char *buffer)
+{
+  if (*line == '\"')
+    {
+      line++;
+      while (*line != '\"' && *line != '\0')
+	{
+	  if (*line == '\\')
+	    *buffer++ = *line++;
+	  if (*line != '\0')
+	    *buffer++ = *line++;
+	}
+      if (*line == '\"')
+	line++;
+    }
+  else
+    while (*line != ' ' && *line != '\t' && *line != '\0')
+      {
+	if (*line == '\\')
+	  line++;
+	if (*line != '\0')
+	  *buffer++ = *line++;
+      }
+  *buffer = '\0';
+  while (*line == ' ' || *line == '\t')
+    line++;
+  return (line);
+}
+
+
+
+char *
+ProcessCommands (char *line, query_data * qd)
+{
+  struct
+  {
+    char *Command;
+    void (*action) (void);
+    void (*action1) (char *);
+    void (*action2) (char *, char *);
+  }
+   *dc, dot_command[] =
+  {
+    {
+      "set", NULL, NULL, CmdSet
+    }
+    ,
+    {
+      "input", NULL, NULL, CmdInput
+    }
+    ,
+    {
+      "output", NULL, NULL, CmdOutput
+    }
+    ,
+    {
+      "unset", NULL, CmdUnset, NULL
+    }
+    ,
+    {
+      "help", CmdHelp, NULL, NULL
+    }
+    ,
+    {
+      "reset", CmdReset, NULL, NULL
+    }
+    ,
+    {
+      "display", CmdDisplay, NULL, NULL
+    }
+    ,
+    {
+      "push", CmdPush, NULL, NULL
+    }
+    ,
+    {
+      "quit", CmdQuit, NULL, NULL
+    }
+    ,
+    {
+      "pop", CmdPop, NULL, NULL
+    }
+    ,
+    {
+      "warranty", CmdWarranty, NULL, NULL
+    }
+    ,
+    {
+      "conditions", CmdConditions, NULL, NULL
+    }
+    ,
+    {
+      "queryterms", CmdQueryTerms, NULL, NULL
+    }
+  };
+
+
+  char command[512];
+  char param1[512], param2[512];
+  CommandsErrorStr = NULL;
+  the_qd = qd;			/* set globally to be accessed by command functions if needed */
+  while (*line == ' ' || *line == '\t')
+    line++;
+  while (*line == '.')
+    {
+      int i;
+      line++;
+      for (i = 0; isalpha (*line) && i < 512; i++, line++)
+	command[i] = tolower (*line);
+      while (*line == ' ' || *line == '\t')
+	line++;
+      if (i != 512)
+	{
+	  command[i] = '\0';
+	  for (i = 0, dc = dot_command; i < NUMOF (dot_command); i++, dc++)
+	    if (!strcmp (dc->Command, command))
+	      {
+		if (dc->action)
+		  dc->action ();
+		else if (dc->action1)
+		  {
+		    line = ParseArg (line, param1);
+		    dc->action1 (param1);
+		    break;
+		  }
+		else if (dc->action2)
+		  {
+		    line = ParseArg (line, param1);
+		    line = ParseArg (line, param2);
+		    dc->action2 (param1, param2);
+		    break;
+		  }
+		if (CommandsErrorStr)
+		  *line = '\0';
+		break;
+	      }
+	  if (i == NUMOF (dot_command))
+	    i = 100;
+	}
+      if (i == 100)
+	{
+	  CommandsErrorStr = "Illegal command";
+	  *line = '\0';
+	}
+      while (*line == ' ' || *line == '\t')
+	line++;
+    }
+  return (line);
+}
+
+
+
+
+
+void 
+read_mgrc_file (void)
+{
+  char line[1000];
+  char FileName[256];
+  int LineNum = 0;
+  FILE *mgrc;
+
+  strcpy (FileName, ".mgrc");
+  mgrc = fopen (FileName, "r");
+
+  if (!mgrc)
+    {
+      char *home_path = getenv ("HOME");
+      if (home_path)
+	{
+	  sprintf (FileName, "%s/.mgrc", home_path);
+	  mgrc = fopen (FileName, "r");
+	}
+    }
+
+  if (!mgrc)
+    return;
+
+  while (fgets (line, sizeof (line), mgrc))
+    {
+      char *s, linebuf[1000];
+      LineNum++;
+      if ((s = strchr (line, '\n')) != NULL)
+	*s = '\0';
+      strcpy (linebuf, line);
+      if ((s = strchr (line, '#')) != NULL)
+	*s = '\0';
+      if (!*line)
+	continue;
+      ProcessCommands (line, NULL);
+      if (CommandsErrorStr)
+	Message ("%s\n%s : ERROR in line %d of %s\n%s : %s\n",
+		 linebuf,
+		 msg_prefix, LineNum, FileName,
+		 msg_prefix, CommandsErrorStr);
+    }
+  fclose (mgrc);
+}
Index: /main/tags/2.25/gsdl/packages/mg/src/text/commands.h
===================================================================
--- /main/tags/2.25/gsdl/packages/mg/src/text/commands.h	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/mg/src/text/commands.h	(revision 21064)
@@ -0,0 +1,33 @@
+/**************************************************************************
+ *
+ * commands.h -- mgquery command processing functions
+ * Copyright (C) 1994  Neil Sharman
+ *
+ * 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.
+ *
+ * $Id$
+ *
+ **************************************************************************/
+
+#ifndef COMMANDS_H
+#define COMMANDS_H
+
+#include "backend.h"
+
+extern char *CommandsErrorStr;
+char *ProcessCommands (char *line, query_data * qd);
+void read_mgrc_file (void);
+
+#endif
Index: /main/tags/2.25/gsdl/packages/mg/src/text/comp_dict.c
===================================================================
--- /main/tags/2.25/gsdl/packages/mg/src/text/comp_dict.c	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/mg/src/text/comp_dict.c	(revision 21064)
@@ -0,0 +1,255 @@
+/**************************************************************************
+ *
+ * comp_dict.c -- Functions for loading the compression dictionary
+ * Copyright (C) 1994  Neil Sharman
+ *
+ * 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.
+ *
+ * $Id$
+ *
+ **************************************************************************/
+
+#include "sysfuncs.h"
+
+#include "huffman.h"
+#include "local_strings.h"
+#include "memlib.h"
+#include "messages.h"
+
+#include "mg.h"
+#include "hash.h"
+#include "text.h"
+#include "comp_dict.h"
+#include "locallib.h"
+#include "mg_files.h"
+
+/*
+   $Log$
+   Revision 1.1  1999/08/10 21:17:48  sjboddie
+   renamed mg-1.3d directory mg
+
+   Revision 1.1  1998/11/17 09:34:34  rjmcnab
+   *** empty log message ***
+
+   * Revision 1.3  1994/10/20  03:56:41  tes
+   * I have rewritten the boolean query optimiser and abstracted out the
+   * components of the boolean query.
+   *
+   * Revision 1.2  1994/09/20  04:41:24  tes
+   * For version 1.1
+   *
+ */
+
+static char *RCSID = "$Id$";
+
+compression_dict_header cdh;
+compressed_text_header cth;
+comp_frags_header cfh[2];
+
+dict_hash_table *ht[2];
+
+huff_data char_huff[2];
+huff_data lens_huff[2];
+u_long *char_codes[2], *lens_codes[2];
+u_long Words_disk = 0;
+u_long Chars_disk = 0;
+
+
+static dict_hash_table *
+ReadInWords (FILE * dict, comp_frags_header * cfh,
+	     int esc)
+{
+  int i;
+  u_char *allwords, *prev = NULL;
+  dict_hash_table *ht;
+  u_char **words;
+  u_long ht_size;
+
+  ht_size = prime (cfh->hd.num_codes * HASH_RATIO);
+  if (!(ht = Xmalloc (sizeof (dict_hash_table) +
+		      (ht_size - 1) * sizeof (ht->table[0]))))
+    {
+      Message ("no memory for hash_table\n");
+      return NULL;
+    }
+
+  ht->size = ht_size;
+  ht->hd = &cfh->hd;
+
+  if (!(ht->codes = Generate_Huffman_Codes (&cfh->hd, NULL)))
+    {
+      Message ("no memory for huffman codes\n");
+      return NULL;
+    }
+
+  if (!(ht->words = Xmalloc (sizeof (u_char *) * cfh->hd.num_codes)))
+    {
+      Message ("no memory for word pointers\n");
+      return NULL;
+    }
+  words = ht->words;
+
+  bzero ((char *) ht->table, ht_size * sizeof (ht->table[0]));
+
+  if (!(allwords = Xmalloc (sizeof (u_char) * cfh->uncompressed_size)))
+    {
+      Message ("no memory for words\n");
+      return NULL;
+    }
+
+  for (i = 0; i < cfh->hd.num_codes; i++, words++)
+    {
+      register int val, copy;
+      val = fgetc (dict);
+      copy = (val >> 4) & 0xf;
+      val &= 0xf;
+
+      *words = allwords;
+
+      memcpy (allwords + 1, prev + 1, copy);
+      fread (allwords + copy + 1, sizeof (u_char), val, dict);
+      *allwords = val + copy;
+
+      Words_disk += val + 1;
+
+      /* insert into the hash table */
+      if (i < cfh->hd.num_codes - esc)
+	{
+	  register u_char **wptr;
+	  register int tsize = ht->size;
+	  register unsigned long hashval, step;
+
+	  HASH (hashval, step, allwords, tsize);
+
+	  wptr = ht->table[hashval];
+	  for (; wptr;)
+	    {
+	      hashval += step;
+	      if (hashval >= tsize)
+		hashval -= tsize;
+	      wptr = ht->table[hashval];
+	    }
+	  ht->table[hashval] = words;
+	}
+      prev = allwords;
+      allwords += *allwords + 1;
+    }
+  return ht;
+}
+
+
+
+int 
+LoadCompressionDictionary (char *dict_file_name)
+{
+  FILE *dict;
+  int which;
+  if (!(dict = open_named_file (dict_file_name, "rb", MAGIC_DICT, MG_MESSAGE)))  /* [RPAP - Feb 97: WIN32 Port] */
+    return COMPERROR;
+
+  Words_disk = sizeof (u_long);
+
+  if (Read_cdh (dict, &cdh, NULL, &Words_disk) == -1)
+    goto error;
+
+  for (which = 0; which < 2; which++)
+    switch (cdh.dict_type)
+      {
+      case MG_COMPLETE_DICTIONARY:
+	{
+	  if (Read_cfh (dict, &cfh[which], NULL, &Words_disk) == -1)
+	    goto error;
+
+	  if (!(ht[which] = ReadInWords (dict, &cfh[which], 0)))
+	    goto error;
+
+	}
+	break;
+      case MG_PARTIAL_DICTIONARY:
+	{
+	  if (cdh.num_words[which])
+	    {
+	      if (Read_cfh (dict, &cfh[which], NULL, &Words_disk) == -1)
+		goto error;
+	      if (!(ht[which] = ReadInWords (dict, &cfh[which], 1)))
+		goto error;
+	    }
+	  else
+	    ht[which] = NULL;
+	  if (Read_Huffman_Data (dict, &char_huff[which], NULL,
+				 &Chars_disk) == -1)
+	    goto error;
+	  if (!(char_codes[which] =
+		Generate_Huffman_Codes (&char_huff[which], NULL)))
+	    goto error;
+	  if (Read_Huffman_Data (dict, &lens_huff[which], NULL,
+				 &Chars_disk) == -1)
+	    goto error;
+	  if (!(lens_codes[which] =
+		Generate_Huffman_Codes (&lens_huff[which], NULL)))
+	    goto error;
+	}
+	break;
+      case MG_SEED_DICTIONARY:
+	{
+	  if (cdh.num_words[which])
+	    {
+	      if (Read_cfh (dict, &cfh[which], NULL, &Words_disk) == -1)
+		goto error;
+	      if (!(ht[which] = ReadInWords (dict, &cfh[which], 1)))
+		goto error;
+	    }
+	  else
+	    ht[which] = NULL;
+	  switch (cdh.novel_method)
+	    {
+	    case MG_NOVEL_HUFFMAN_CHARS:
+	      if (Read_Huffman_Data (dict, &char_huff[which], NULL,
+				     &Chars_disk) == -1)
+		goto error;
+	      if (!(char_codes[which] =
+		    Generate_Huffman_Codes (&char_huff[which], NULL)))
+		goto error;
+	      if (Read_Huffman_Data (dict, &lens_huff[which], NULL,
+				     &Chars_disk) == -1)
+		goto error;
+	      if (!(lens_codes[which] =
+		    Generate_Huffman_Codes (&lens_huff[which], NULL)))
+		goto error;
+	      break;
+	    case MG_NOVEL_BINARY:
+	      break;
+	    case MG_NOVEL_DELTA:
+	      break;
+	    case MG_NOVEL_HYBRID:
+	      break;
+	    case MG_NOVEL_HYBRID_MTF:
+	      break;
+	    default:
+	      FatalError (1, "Bad novel method");
+	    }
+	}
+	break;
+      default:
+	FatalError (1, "Bad dictionary kind\n");
+      }
+
+  return (COMPALLOK);
+
+
+error:
+  fclose (dict);
+  return (COMPERROR);
+}
Index: /main/tags/2.25/gsdl/packages/mg/src/text/comp_dict.h
===================================================================
--- /main/tags/2.25/gsdl/packages/mg/src/text/comp_dict.h	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/mg/src/text/comp_dict.h	(revision 21064)
@@ -0,0 +1,59 @@
+/**************************************************************************
+ *
+ * comp_dict.h -- Functions for loading the compression dictionary
+ * Copyright (C) 1994  Neil Sharman
+ *
+ * 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.
+ *
+ * $Id$
+ *
+ **************************************************************************/
+
+
+
+
+#define HASH_RATIO 2
+
+
+
+
+typedef struct dict_hash_table
+  {
+    u_long size;
+    huff_data *hd;
+    u_long *codes;
+    u_char **words;
+    u_char **table[1];
+  }
+dict_hash_table;
+
+
+
+
+extern compression_dict_header cdh;
+extern compressed_text_header cth;
+extern comp_frags_header cfh[2];
+
+extern dict_hash_table *ht[2];
+
+extern huff_data char_huff[2];
+extern huff_data lens_huff[2];
+extern u_long *char_codes[2], *lens_codes[2];
+extern u_long Words_disk;
+extern u_long Chars_disk;
+
+
+
+int LoadCompressionDictionary (char *dict_file_name);
Index: /main/tags/2.25/gsdl/packages/mg/src/text/conditions.h
===================================================================
--- /main/tags/2.25/gsdl/packages/mg/src/text/conditions.h	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/mg/src/text/conditions.h	(revision 21064)
@@ -0,0 +1,226 @@
+static char *cond_str[] = {
+"		    GNU GENERAL PUBLIC LICENSE\n",
+"   TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION\n",
+"\n",
+"  0. This License applies to any program or other work which contains\n",
+"a notice placed by the copyright holder saying it may be distributed\n",
+"under the terms of this General Public License.  The \"Program\", below,\n",
+"refers to any such program or work, and a \"work based on the Program\"\n",
+"means either the Program or any derivative work under copyright law:\n",
+"that is to say, a work containing the Program or a portion of it,\n",
+"either verbatim or with modifications and/or translated into another\n",
+"language.  (Hereinafter, translation is included without limitation in\n",
+"the term \"modification\".)  Each licensee is addressed as \"you\".\n",
+"\n",
+"Activities other than copying, distribution and modification are not\n",
+"covered by this License; they are outside its scope.  The act of\n",
+"running the Program is not restricted, and the output from the Program\n",
+"is covered only if its contents constitute a work based on the\n",
+"Program (independent of having been made by running the Program).\n",
+"Whether that is true depends on what the Program does.\n",
+"\n",
+"  1. You may copy and distribute verbatim copies of the Program's\n",
+"source code as you receive it, in any medium, provided that you\n",
+"conspicuously and appropriately publish on each copy an appropriate\n",
+"copyright notice and disclaimer of warranty; keep intact all the\n",
+"notices that refer to this License and to the absence of any warranty;\n",
+"and give any other recipients of the Program a copy of this License\n",
+"along with the Program.\n",
+"\n",
+"You may charge a fee for the physical act of transferring a copy, and\n",
+"you may at your option offer warranty protection in exchange for a fee.\n",
+"\n",
+"  2. You may modify your copy or copies of the Program or any portion\n",
+"of it, thus forming a work based on the Program, and copy and\n",
+"distribute such modifications or work under the terms of Section 1\n",
+"above, provided that you also meet all of these conditions:\n",
+"\n",
+"    a) You must cause the modified files to carry prominent notices\n",
+"    stating that you changed the files and the date of any change.\n",
+"\n",
+"    b) You must cause any work that you distribute or publish, that in\n",
+"    whole or in part contains or is derived from the Program or any\n",
+"    part thereof, to be licensed as a whole at no charge to all third\n",
+"    parties under the terms of this License.\n",
+"\n",
+"    c) If the modified program normally reads commands interactively\n",
+"    when run, you must cause it, when started running for such\n",
+"    interactive use in the most ordinary way, to print or display an\n",
+"    announcement including an appropriate copyright notice and a\n",
+"    notice that there is no warranty (or else, saying that you provide\n",
+"    a warranty) and that users may redistribute the program under\n",
+"    these conditions, and telling the user how to view a copy of this\n",
+"    License.  (Exception: if the Program itself is interactive but\n",
+"    does not normally print such an announcement, your work based on\n",
+"    the Program is not required to print an announcement.)\n",
+"
+\n",
+"These requirements apply to the modified work as a whole.  If\n",
+"identifiable sections of that work are not derived from the Program,\n",
+"and can be reasonably considered independent and separate works in\n",
+"themselves, then this License, and its terms, do not apply to those\n",
+"sections when you distribute them as separate works.  But when you\n",
+"distribute the same sections as part of a whole which is a work based\n",
+"on the Program, the distribution of the whole must be on the terms of\n",
+"this License, whose permissions for other licensees extend to the\n",
+"entire whole, and thus to each and every part regardless of who wrote it.\n",
+"\n",
+"Thus, it is not the intent of this section to claim rights or contest\n",
+"your rights to work written entirely by you; rather, the intent is to\n",
+"exercise the right to control the distribution of derivative or\n",
+"collective works based on the Program.\n",
+"\n",
+"In addition, mere aggregation of another work not based on the Program\n",
+"with the Program (or with a work based on the Program) on a volume of\n",
+"a storage or distribution medium does not bring the other work under\n",
+"the scope of this License.\n",
+"\n",
+"  3. You may copy and distribute the Program (or a work based on it,\n",
+"under Section 2) in object code or executable form under the terms of\n",
+"Sections 1 and 2 above provided that you also do one of the following:\n",
+"\n",
+"    a) Accompany it with the complete corresponding machine-readable\n",
+"    source code, which must be distributed under the terms of Sections\n",
+"    1 and 2 above on a medium customarily used for software interchange; or,\n",
+"\n",
+"    b) Accompany it with a written offer, valid for at least three\n",
+"    years, to give any third party, for a charge no more than your\n",
+"    cost of physically performing source distribution, a complete\n",
+"    machine-readable copy of the corresponding source code, to be\n",
+"    distributed under the terms of Sections 1 and 2 above on a medium\n",
+"    customarily used for software interchange; or,\n",
+"\n",
+"    c) Accompany it with the information you received as to the offer\n",
+"    to distribute corresponding source code.  (This alternative is\n",
+"    allowed only for noncommercial distribution and only if you\n",
+"    received the program in object code or executable form with such\n",
+"    an offer, in accord with Subsection b above.)\n",
+"\n",
+"The source code for a work means the preferred form of the work for\n",
+"making modifications to it.  For an executable work, complete source\n",
+"code means all the source code for all modules it contains, plus any\n",
+"associated interface definition files, plus the scripts used to\n",
+"control compilation and installation of the executable.  However, as a\n",
+"special exception, the source code distributed need not include\n",
+"anything that is normally distributed (in either source or binary\n",
+"form) with the major components (compiler, kernel, and so on) of the\n",
+"operating system on which the executable runs, unless that component\n",
+"itself accompanies the executable.\n",
+"\n",
+"If distribution of executable or object code is made by offering\n",
+"access to copy from a designated place, then offering equivalent\n",
+"access to copy the source code from the same place counts as\n",
+"distribution of the source code, even though third parties are not\n",
+"compelled to copy the source along with the object code.\n",
+"
+\n",
+"  4. You may not copy, modify, sublicense, or distribute the Program\n",
+"except as expressly provided under this License.  Any attempt\n",
+"otherwise to copy, modify, sublicense or distribute the Program is\n",
+"void, and will automatically terminate your rights under this License.\n",
+"However, parties who have received copies, or rights, from you under\n",
+"this License will not have their licenses terminated so long as such\n",
+"parties remain in full compliance.\n",
+"\n",
+"  5. You are not required to accept this License, since you have not\n",
+"signed it.  However, nothing else grants you permission to modify or\n",
+"distribute the Program or its derivative works.  These actions are\n",
+"prohibited by law if you do not accept this License.  Therefore, by\n",
+"modifying or distributing the Program (or any work based on the\n",
+"Program), you indicate your acceptance of this License to do so, and\n",
+"all its terms and conditions for copying, distributing or modifying\n",
+"the Program or works based on it.\n",
+"\n",
+"  6. Each time you redistribute the Program (or any work based on the\n",
+"Program), the recipient automatically receives a license from the\n",
+"original licensor to copy, distribute or modify the Program subject to\n",
+"these terms and conditions.  You may not impose any further\n",
+"restrictions on the recipients' exercise of the rights granted herein.\n",
+"You are not responsible for enforcing compliance by third parties to\n",
+"this License.\n",
+"\n",
+"  7. If, as a consequence of a court judgment or allegation of patent\n",
+"infringement or for any other reason (not limited to patent issues),\n",
+"conditions are imposed on you (whether by court order, agreement or\n",
+"otherwise) that contradict the conditions of this License, they do not\n",
+"excuse you from the conditions of this License.  If you cannot\n",
+"distribute so as to satisfy simultaneously your obligations under this\n",
+"License and any other pertinent obligations, then as a consequence you\n",
+"may not distribute the Program at all.  For example, if a patent\n",
+"license would not permit royalty-free redistribution of the Program by\n",
+"all those who receive copies directly or indirectly through you, then\n",
+"the only way you could satisfy both it and this License would be to\n",
+"refrain entirely from distribution of the Program.\n",
+"\n",
+"If any portion of this section is held invalid or unenforceable under\n",
+"any particular circumstance, the balance of the section is intended to\n",
+"apply and the section as a whole is intended to apply in other\n",
+"circumstances.\n",
+"\n",
+"It is not the purpose of this section to induce you to infringe any\n",
+"patents or other property right claims or to contest validity of any\n",
+"such claims; this section has the sole purpose of protecting the\n",
+"integrity of the free software distribution system, which is\n",
+"implemented by public license practices.  Many people have made\n",
+"generous contributions to the wide range of software distributed\n",
+"through that system in reliance on consistent application of that\n",
+"system; it is up to the author/donor to decide if he or she is willing\n",
+"to distribute software through any other system and a licensee cannot\n",
+"impose that choice.\n",
+"\n",
+"This section is intended to make thoroughly clear what is believed to\n",
+"be a consequence of the rest of this License.\n",
+"
+\n",
+"  8. If the distribution and/or use of the Program is restricted in\n",
+"certain countries either by patents or by copyrighted interfaces, the\n",
+"original copyright holder who places the Program under this License\n",
+"may add an explicit geographical distribution limitation excluding\n",
+"those countries, so that distribution is permitted only in or among\n",
+"countries not thus excluded.  In such case, this License incorporates\n",
+"the limitation as if written in the body of this License.\n",
+"\n",
+"  9. The Free Software Foundation may publish revised and/or new versions\n",
+"of the General Public License from time to time.  Such new versions will\n",
+"be similar in spirit to the present version, but may differ in detail to\n",
+"address new problems or concerns.\n",
+"\n",
+"Each version is given a distinguishing version number.  If the Program\n",
+"specifies a version number of this License which applies to it and \"any\n",
+"later version\", you have the option of following the terms and conditions\n",
+"either of that version or of any later version published by the Free\n",
+"Software Foundation.  If the Program does not specify a version number of\n",
+"this License, you may choose any version ever published by the Free Software\n",
+"Foundation.\n",
+"\n",
+"  10. If you wish to incorporate parts of the Program into other free\n",
+"programs whose distribution conditions are different, write to the author\n",
+"to ask for permission.  For software which is copyrighted by the Free\n",
+"Software Foundation, write to the Free Software Foundation; we sometimes\n",
+"make exceptions for this.  Our decision will be guided by the two goals\n",
+"of preserving the free status of all derivatives of our free software and\n",
+"of promoting the sharing and reuse of software generally.\n",
+"\n",
+"			    NO WARRANTY\n",
+"\n",
+"  11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY\n",
+"FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW.  EXCEPT WHEN\n",
+"OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES\n",
+"PROVIDE THE PROGRAM \"AS IS\" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED\n",
+"OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF\n",
+"MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.  THE ENTIRE RISK AS\n",
+"TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU.  SHOULD THE\n",
+"PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,\n",
+"REPAIR OR CORRECTION.\n",
+"\n",
+"  12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING\n",
+"WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR\n",
+"REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,\n",
+"INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING\n",
+"OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED\n",
+"TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY\n",
+"YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER\n",
+"PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE\n",
+"POSSIBILITY OF SUCH DAMAGES.\n",
+"\n",
+"		     END OF TERMS AND CONDITIONS\n"};
Index: /main/tags/2.25/gsdl/packages/mg/src/text/conditions.src
===================================================================
--- /main/tags/2.25/gsdl/packages/mg/src/text/conditions.src	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/mg/src/text/conditions.src	(revision 21064)
@@ -0,0 +1,225 @@
+		    GNU GENERAL PUBLIC LICENSE
+   TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+  0. This License applies to any program or other work which contains
+a notice placed by the copyright holder saying it may be distributed
+under the terms of this General Public License.  The "Program", below,
+refers to any such program or work, and a "work based on the Program"
+means either the Program or any derivative work under copyright law:
+that is to say, a work containing the Program or a portion of it,
+either verbatim or with modifications and/or translated into another
+language.  (Hereinafter, translation is included without limitation in
+the term "modification".)  Each licensee is addressed as "you".
+
+Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope.  The act of
+running the Program is not restricted, and the output from the Program
+is covered only if its contents constitute a work based on the
+Program (independent of having been made by running the Program).
+Whether that is true depends on what the Program does.
+
+  1. You may copy and distribute verbatim copies of the Program's
+source code as you receive it, in any medium, provided that you
+conspicuously and appropriately publish on each copy an appropriate
+copyright notice and disclaimer of warranty; keep intact all the
+notices that refer to this License and to the absence of any warranty;
+and give any other recipients of the Program a copy of this License
+along with the Program.
+
+You may charge a fee for the physical act of transferring a copy, and
+you may at your option offer warranty protection in exchange for a fee.
+
+  2. You may modify your copy or copies of the Program or any portion
+of it, thus forming a work based on the Program, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+    a) You must cause the modified files to carry prominent notices
+    stating that you changed the files and the date of any change.
+
+    b) You must cause any work that you distribute or publish, that in
+    whole or in part contains or is derived from the Program or any
+    part thereof, to be licensed as a whole at no charge to all third
+    parties under the terms of this License.
+
+    c) If the modified program normally reads commands interactively
+    when run, you must cause it, when started running for such
+    interactive use in the most ordinary way, to print or display an
+    announcement including an appropriate copyright notice and a
+    notice that there is no warranty (or else, saying that you provide
+    a warranty) and that users may redistribute the program under
+    these conditions, and telling the user how to view a copy of this
+    License.  (Exception: if the Program itself is interactive but
+    does not normally print such an announcement, your work based on
+    the Program is not required to print an announcement.)
+
+
+These requirements apply to the modified work as a whole.  If
+identifiable sections of that work are not derived from the Program,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works.  But when you
+distribute the same sections as part of a whole which is a work based
+on the Program, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Program.
+
+In addition, mere aggregation of another work not based on the Program
+with the Program (or with a work based on the Program) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+  3. You may copy and distribute the Program (or a work based on it,
+under Section 2) in object code or executable form under the terms of
+Sections 1 and 2 above provided that you also do one of the following:
+
+    a) Accompany it with the complete corresponding machine-readable
+    source code, which must be distributed under the terms of Sections
+    1 and 2 above on a medium customarily used for software interchange; or,
+
+    b) Accompany it with a written offer, valid for at least three
+    years, to give any third party, for a charge no more than your
+    cost of physically performing source distribution, a complete
+    machine-readable copy of the corresponding source code, to be
+    distributed under the terms of Sections 1 and 2 above on a medium
+    customarily used for software interchange; or,
+
+    c) Accompany it with the information you received as to the offer
+    to distribute corresponding source code.  (This alternative is
+    allowed only for noncommercial distribution and only if you
+    received the program in object code or executable form with such
+    an offer, in accord with Subsection b above.)
+
+The source code for a work means the preferred form of the work for
+making modifications to it.  For an executable work, complete source
+code means all the source code for all modules it contains, plus any
+associated interface definition files, plus the scripts used to
+control compilation and installation of the executable.  However, as a
+special exception, the source code distributed need not include
+anything that is normally distributed (in either source or binary
+form) with the major components (compiler, kernel, and so on) of the
+operating system on which the executable runs, unless that component
+itself accompanies the executable.
+
+If distribution of executable or object code is made by offering
+access to copy from a designated place, then offering equivalent
+access to copy the source code from the same place counts as
+distribution of the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+
+  4. You may not copy, modify, sublicense, or distribute the Program
+except as expressly provided under this License.  Any attempt
+otherwise to copy, modify, sublicense or distribute the Program is
+void, and will automatically terminate your rights under this License.
+However, parties who have received copies, or rights, from you under
+this License will not have their licenses terminated so long as such
+parties remain in full compliance.
+
+  5. You are not required to accept this License, since you have not
+signed it.  However, nothing else grants you permission to modify or
+distribute the Program or its derivative works.  These actions are
+prohibited by law if you do not accept this License.  Therefore, by
+modifying or distributing the Program (or any work based on the
+Program), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Program or works based on it.
+
+  6. Each time you redistribute the Program (or any work based on the
+Program), the recipient automatically receives a license from the
+original licensor to copy, distribute or modify the Program subject to
+these terms and conditions.  You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties to
+this License.
+
+  7. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License.  If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Program at all.  For example, if a patent
+license would not permit royalty-free redistribution of the Program by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Program.
+
+If any portion of this section is held invalid or unenforceable under
+any particular circumstance, the balance of the section is intended to
+apply and the section as a whole is intended to apply in other
+circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system, which is
+implemented by public license practices.  Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+
+  8. If the distribution and/or use of the Program is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Program under this License
+may add an explicit geographical distribution limitation excluding
+those countries, so that distribution is permitted only in or among
+countries not thus excluded.  In such case, this License incorporates
+the limitation as if written in the body of this License.
+
+  9. The Free Software Foundation may publish revised and/or new versions
+of the General Public License from time to time.  Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+Each version is given a distinguishing version number.  If the Program
+specifies a version number of this License which applies to it and "any
+later version", you have the option of following the terms and conditions
+either of that version or of any later version published by the Free
+Software Foundation.  If the Program does not specify a version number of
+this License, you may choose any version ever published by the Free Software
+Foundation.
+
+  10. If you wish to incorporate parts of the Program into other free
+programs whose distribution conditions are different, write to the author
+to ask for permission.  For software which is copyrighted by the Free
+Software Foundation, write to the Free Software Foundation; we sometimes
+make exceptions for this.  Our decision will be guided by the two goals
+of preserving the free status of all derivatives of our free software and
+of promoting the sharing and reuse of software generally.
+
+			    NO WARRANTY
+
+  11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
+FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW.  EXCEPT WHEN
+OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
+PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
+OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.  THE ENTIRE RISK AS
+TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU.  SHOULD THE
+PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
+REPAIR OR CORRECTION.
+
+  12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
+REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
+INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
+OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
+TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
+YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
+PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGES.
+
+		     END OF TERMS AND CONDITIONS
Index: /main/tags/2.25/gsdl/packages/mg/src/text/environment.c
===================================================================
--- /main/tags/2.25/gsdl/packages/mg/src/text/environment.c	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/mg/src/text/environment.c	(revision 21064)
@@ -0,0 +1,678 @@
+/**************************************************************************
+ *
+ * environment.c -- mgquery environment functions
+ * Copyright (C) 1994  Neil Sharman
+ *
+ * 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.
+ *
+ * $Id$
+ *
+ **************************************************************************/
+
+/*
+   $Log$
+   Revision 1.1  1999/08/10 21:17:50  sjboddie
+   renamed mg-1.3d directory mg
+
+   Revision 1.1  1998/11/17 09:34:37  rjmcnab
+   *** empty log message ***
+
+   * Revision 1.5  1995/03/14  05:15:26  tes
+   * Updated the boolean query optimiser to do different types of optimisation.
+   * A query environment variable "optimise_type" specifies which one is to be
+   * used. Type 1 is the new one which is faster than 2.
+   *
+   * Revision 1.4  1994/11/25  03:47:43  tes
+   * Committing files before adding the merge stuff.
+   *
+   * Revision 1.3  1994/10/20  03:56:43  tes
+   * I have rewritten the boolean query optimiser and abstracted out the
+   * components of the boolean query.
+   *
+   * Revision 1.2  1994/09/20  04:41:25  tes
+   * For version 1.1
+   *
+ */
+
+static char *RCSID = "$Id$";
+
+#include "sysfuncs.h"
+
+#include "memlib.h"
+#include "locallib.h"
+#include "local_strings.h"
+#include "messages.h"
+
+#include "environment.h"
+
+/* [RPAP - Feb 97: WIN32 Port] */
+#ifdef __WIN32__
+# define STRCASECMP      stricmp
+#else
+# define STRCASECMP      strcasecmp
+#endif
+
+typedef struct
+  {
+    char *Name, *Data;
+    char *(*Constraint) (char *Old, char *New);
+  }
+EEntry;
+
+typedef struct Env
+  {
+    EEntry *Environment;
+    int NumEnv;
+    struct Env *Next;
+  }
+Env;
+
+
+char *ConstraintErrorStr;
+
+static Env Base =
+{NULL, 0, NULL};
+
+
+/*
+ * Add name and data to the environment (data may be NULL)
+ * All names are converted to lower case
+ * returns 0 on success, -1 on memory failure or -2 on constraint failure
+ */
+int 
+SetEnv (char *name, char *data, char *(*Constraint) (char *, char *))
+{
+  int i;
+  EEntry *newenv, *env = Base.Environment;
+
+  if (data && *data == '\0')
+    data = NULL;
+
+  /* search for name in the environment */
+  for (i = 0; i < Base.NumEnv && STRCASECMP (name, env->Name); i++, env++);  /* [RPAP - Feb 97: WIN32 Port] */
+
+  /* if not found the increase the environment size */
+  if (i >= Base.NumEnv)
+    {
+      if (Constraint)
+	{
+	  data = Constraint (NULL, data);
+	  if (!data)
+	    return (-2);
+	}
+      /* allocate memory for the new environment */
+      newenv = Base.Environment ?
+	Xrealloc (Base.Environment, sizeof (EEntry) * (Base.NumEnv + 1)) :
+	Xmalloc (sizeof (EEntry) * (Base.NumEnv + 1));
+      if (!newenv)
+	return (-1);
+      Base.Environment = newenv;
+      env = &newenv[Base.NumEnv];
+      env->Data = NULL;
+      env->Name = NULL;
+      env->Constraint = Constraint;
+      env->Name = Xstrdup (name);
+      if (!env->Name)
+	return (-1);
+      Base.NumEnv++;
+      for (i = 0; env->Name[i]; i++)
+	env->Name[i] = tolower (env->Name[i]);
+    }
+  if (env->Constraint)
+    {
+      data = env->Constraint (env->Data, data);
+      if (!data)
+	return (-2);
+    }
+  if (env->Data)
+    Xfree (env->Data);
+  env->Data = NULL;
+  if (data && *data != '\0')
+    {
+      env->Data = Xstrdup (data);
+      if (!env->Data)
+	return (-1);
+    }
+  return (0);
+}
+
+
+
+/*
+ * Returns the data associated with name. If Data = NULL then this routine
+ * returns a pointer to "". If the specified name does not exist then this 
+ * routine returns NULL.
+ */
+char *
+GetEnv (char *name)
+{
+  int i;
+  EEntry *env = Base.Environment;
+  /* search for name in the environment */
+  for (i = 0; i < Base.NumEnv && STRCASECMP (name, env->Name); i++, env++);  /* [RPAP - Feb 97: WIN32 Port] */
+
+  if (i >= Base.NumEnv)
+    return (NULL);
+
+  return (env->Data ? env->Data : "");
+}
+
+/*
+ * Returns the data associated with name. If Data = NULL then this routine
+ * returns a pointer to "". If the specified name does not exist then this 
+ * routine returns default.
+ */
+char *
+GetDefEnv (char *name, char *def)
+{
+  char *data = GetEnv (name);
+  return (data ? data : def);
+}
+
+
+
+/*
+ * This function pushes the environment on to a stack and duplicated it in 
+ * the current stack.
+ *
+ */
+int 
+PushEnv (void)
+{
+  Env *env = Xmalloc (sizeof (Env));
+  int i;
+  *env = Base;
+  Base.Next = env;
+  Base.Environment = NULL;
+  Base.NumEnv = 0;
+  for (i = 0; i < env->NumEnv; i++)
+    if (SetEnv (env->Environment[i].Name, env->Environment[i].Data,
+		env->Environment[i].Constraint))
+      return (-1);
+  return (0);
+}
+
+int 
+PopEnv (void)
+{
+  Env *env;
+  int i;
+  if (!Base.Next)
+    return (-1);
+  for (i = 0; i < Base.NumEnv; i++)
+    {
+      Xfree (Base.Environment[i].Name);
+      if (Base.Environment[i].Data)
+	Xfree (Base.Environment[i].Data);
+    }
+  if (Base.Environment)
+    Xfree (Base.Environment);
+  env = Base.Next;
+  Base = *env;
+  Xfree (env);
+  return (0);
+}
+
+
+/*
+ * Count the number of environments on the stack, including the current one.
+ *
+ */
+int 
+EnvStackHeight (void)
+{
+  int i = 1;
+  Env *env = &Base;
+  while (env->Next)
+    {
+      i++;
+      env = env->Next;
+    }
+  return (i);
+}
+
+/*
+ * Delete environment variable name. If name does not exist it returns -1
+ * otherwise it returns 0
+ */
+int 
+UnsetEnv (char *name, int Force)
+{
+  int i;
+  EEntry *env = Base.Environment;
+  /* search for name in the environment */
+  for (i = 0; i < Base.NumEnv && STRCASECMP (name, env->Name); i++, env++);  /* [RPAP - Feb 97: WIN32 Port] */
+
+  if (i >= Base.NumEnv ||
+      (Base.Environment[i].Constraint && !Force))
+    return (-1);
+  Xfree (Base.Environment[i].Name);
+  if (Base.Environment[i].Data)
+    Xfree (Base.Environment[i].Data);
+  for (i++; i < Base.NumEnv; i++)
+    Base.Environment[i - 1] = Base.Environment[i];
+  Base.NumEnv--;
+  if (Base.NumEnv == 0)
+    {
+      Xfree (Base.Environment);
+      Base.Environment = NULL;
+    }
+  return (0);
+}
+
+
+
+
+
+
+
+
+/*
+ * Returns the name of environment variable number i or NULL if i is greater 
+ * than or equal to the number of environment variables. Names start from
+ * zero. 
+ */
+char *
+GetEnvName (int i)
+{
+  return (i < Base.NumEnv ? Base.Environment[i].Name : NULL);
+}
+
+static char *BooleanStrs[] =
+{"false", "true", "no", "yes", "off", "on"};
+
+static char *
+BooleanCons (char *Old, char *New)
+{
+  int i;
+  int old = -1, new = -1;
+  if (Old)
+    for (i = 0; i < sizeof (BooleanStrs) / sizeof (char *); i++)
+      if (!STRCASECMP (Old, BooleanStrs[i]))  /* [RPAP - Feb 97: WIN32 Port] */
+	{
+	  old = i;
+	  break;
+	}
+  if (New)
+    for (i = 0; i < sizeof (BooleanStrs) / sizeof (char *); i++)
+      if (!STRCASECMP (New, BooleanStrs[i]))  /* [RPAP - Feb 97: WIN32 Port] */
+	{
+	  new = i;
+	  break;
+	}
+  if (new >= 0)
+    return (New);
+  if (!New)
+    return (BooleanStrs[Old ? old ^ 1 : 0]);
+  ConstraintErrorStr = "Invalid argument [true|false|yes|no|on|off] required";
+  return (NULL);
+}
+
+/*
+ * returns 0 or 1  for a boolean string
+ * or default on a error
+ */
+int 
+BooleanEnv (char *data, int def)
+{
+  int i;
+  if (!data)
+    return (def);
+  for (i = 0; i < sizeof (BooleanStrs) / sizeof (char *); i++)
+    if (!STRCASECMP (data, BooleanStrs[i]))  /* [RPAP - Feb 97: WIN32 Port] */
+      return (i & 1);
+  return (def);
+}
+
+/*
+ * returns the value for a integer string
+ * or default on a error
+ */
+long 
+IntEnv (char *data, long def)
+{
+  long val;
+  char *ptr;
+  if (!data)
+    return (def);
+  val = strtol (data, &ptr, 10);
+  return *ptr ? def : val;
+}
+
+static char *
+NumberCmp (char *num, int min, int max)
+{
+  char *err;
+  int val;
+  static char Err[100];
+  ConstraintErrorStr = "Not a valid number";
+  if (!num)
+    return (NULL);
+  val = strtol (num, &err, 10);
+  if (*err)
+    return (NULL);
+  sprintf (Err, "Not in legal range [%d <= num <= %d]", min, max);
+  ConstraintErrorStr = Err;
+  if (val < min || val > max)
+    return (NULL);
+  return (num);
+}
+
+/*ARGSUSED */
+static char *
+MaxDocsCons (char *Old, char *New)
+{
+  if (!STRCASECMP (New, "all"))  /* [RPAP - Feb 97: WIN32 Port] */
+    return (New);
+  return (NumberCmp (New, 1, ((unsigned) (~0)) >> 1));
+}
+
+/*ARGSUSED */
+static char *
+MaxTermsCons (char *Old, char *New)
+{
+  if (!STRCASECMP (New, "all"))  /* [RPAP - Feb 97: WIN32 Port] */
+    return (New);
+  return (NumberCmp (New, 1, ((unsigned) (~0)) >> 1));
+}
+
+/* ARGSUSED */
+static char *
+BufferCons (char *Old, char *New)
+{
+  return (NumberCmp (New, 0, 16 * 1024 * 1024));
+}
+
+/* ARGSUSED */
+static char *
+MaxNodesCons (char *Old, char *New)
+{
+  if (!STRCASECMP (New, "all"))  /* [RPAP - Feb 97: WIN32 Port] */
+    return (New);
+  return (NumberCmp (New, 8, 256 * 1024 * 1024));
+}
+
+/* ARGSUSED */
+static char *
+MaxHashCons (char *Old, char *New)
+{
+  return (NumberCmp (New, 8, 256 * 1024 * 1024));
+}
+
+/* ARGSUSED */
+static char *
+MaxParasCons (char *Old, char *New)
+{
+  return (NumberCmp (New, 1, 256 * 1024 * 1024));
+}
+
+/* ARGSUSED */
+static char *
+MaxHeadsCons (char *Old, char *New)
+{
+  return (NumberCmp (New, 1, 1000));
+}
+
+/* ARGSUSED */
+char *
+OptimiseCons (char *Old, char *New)
+{
+  return (NumberCmp (New, 0, 2));
+}
+
+
+
+/*
+ * Makes sure that New is a valid query type
+ *
+ */
+/* ARGSUSED */
+static char *
+QueryCons (char *Old, char *New)
+{
+  static char *QueryStrs[] =
+  {
+    "boolean", "ranked",
+    "docnums", "approx-ranked"};
+  int i;
+  int new = -1;
+  if (New)
+    for (i = 0; i < sizeof (QueryStrs) / sizeof (char *); i++)
+      if (!STRCASECMP (New, QueryStrs[i]))  /* [RPAP - Feb 97: WIN32 Port] */
+	{
+	  new = i;
+	  break;
+	}
+  if (new >= 0)
+    return (New);
+  ConstraintErrorStr = "Invalid argument [boolean|ranked|docnums|approx-ranked] required";
+  return (NULL);
+}
+
+/*
+ * Makes sure that New is a valid accum type
+ *
+ */
+/* ARGSUSED */
+static char *
+AccumCons (char *Old, char *New)
+{
+  static char *AccumStrs[] =
+  {
+    "array", "splay_tree", "hash_table", "list"};
+  int i;
+  int new = -1;
+  if (New)
+    for (i = 0; i < sizeof (AccumStrs) / sizeof (char *); i++)
+      if (!STRCASECMP (New, AccumStrs[i]))  /* [RPAP - Feb 97: WIN32 Port] */
+	{
+	  new = i;
+	  break;
+	}
+  if (new >= 0)
+    return (New);
+  ConstraintErrorStr = "Invalid argument "
+    "[array|splay_tree|hash_table|list] required";
+  return (NULL);
+}
+
+
+
+/*
+ * Makes sure that New is a valid output type type
+ *
+ */
+/* ARGSUSED */
+static char *
+OutputTypeCons (char *Old, char *New)
+{
+  static char *OutputTypeStrs[] =
+  {"text", "silent", "docnums",
+   "count", "heads", "hilite"
+#ifdef TREC_MODE
+   ,"extras_for_trec"
+#endif
+  };
+
+  int i;
+  int new = -1;
+  if (New)
+    for (i = 0; i < sizeof (OutputTypeStrs) / sizeof (char *); i++)
+      if (!STRCASECMP (New, OutputTypeStrs[i]))  /* [RPAP - Feb 97: WIN32 Port] */
+	{
+	  new = i;
+	  break;
+	}
+  if (new >= 0)
+    return (New);
+  ConstraintErrorStr = "Invalid argument [text|silent|docnums|heads|count|hilite"
+#ifdef TREC_MODE
+    "|extras_for_trec"
+#endif
+    "] required";
+  return (NULL);
+}
+
+/*
+ * Makes sure that New is a valid query type
+ *
+ */
+/* ARGSUSED */
+char *
+HiliteStyleCons (char *Old, char *New)
+{
+  static char *StyleStrs[] =
+  {"bold", "underline"};
+  int i;
+  int new = -1;
+  if (New)
+    for (i = 0; i < sizeof (StyleStrs) / sizeof (char *); i++)
+      if (!STRCASECMP (New, StyleStrs[i]))  /* [RPAP - Feb 97: WIN32 Port] */
+	{
+	  new = i;
+	  break;
+	}
+  if (new >= 0)
+    return (New);
+  ConstraintErrorStr = "Invalid argument [bold|underline] required";
+  return (NULL);
+}
+
+/* =========================================================================
+ * Function: get_output_type
+ * Description:
+ *      Map a mode string onto a mode char e.g. OUTPUT_????
+ * Input:
+ * Output:
+ *      The mode char which is a subrange value.
+ * ========================================================================= */
+
+char
+get_output_type (void)
+{
+  char *env_str = GetDefEnv ("mode", "text");
+  char ch1 = toupper (env_str[0]);
+  char ch2 = toupper (env_str[1]);
+
+  switch (ch1)
+    {
+    case 'T':
+      return OUTPUT_TEXT;
+    case 'S':
+      return OUTPUT_SILENT;
+    case 'E':
+      return OUTPUT_EXTRAS;
+    case 'C':
+      return OUTPUT_COUNT;
+    case 'D':
+      return OUTPUT_DOCNUMS;
+    case 'H':
+      if (ch2 == 'E')
+	return OUTPUT_HEADERS;
+      else
+	return OUTPUT_HILITE;
+    default:
+      FatalError (1, "Problem in output type switch");
+    }
+
+  return '\0';			/*shouldn't reach here -- keep compiler happy */
+}
+
+/* =========================================================================
+ * Function: get_query_type
+ * Description:
+ *      Map a query type string onto a char.
+ * Input:
+ * Output:
+ *      Query type char.
+ * ========================================================================= */
+
+char
+get_query_type (void)
+{
+  char *env_str = GetDefEnv ("query", "boolean");
+  char ch1 = toupper (env_str[0]);
+
+  switch (ch1)
+    {
+    case 'R':
+      return QUERY_RANKED;
+    case 'A':
+      return QUERY_APPROX;
+    case 'B':
+      return QUERY_BOOLEAN;
+    case 'D':
+      return QUERY_DOCNUMS;
+    default:
+      FatalError (1, "Problem in query type switch");
+    }
+
+  return '\0';			/*shouldn't reach here */
+}
+
+
+
+/*
+ * This initialises certain environment variables
+ *
+ */
+void 
+InitEnv (void)
+{
+  SetEnv ("hilite_style", "underline", HiliteStyleCons);	/*[TS:Sep/94] */
+  SetEnv ("briefstats", "off", BooleanCons);
+  SetEnv ("diskstats", "off", BooleanCons);
+  SetEnv ("expert", "false", BooleanCons);
+  SetEnv ("mgdir", getenv ("MGDATA") ? getenv ("MGDATA") : ".", NULL);
+  SetEnv ("mgname", "", NULL);
+  SetEnv ("maxdocs", "all", MaxDocsCons);
+  SetEnv ("memstats", "off", BooleanCons);
+  SetEnv ("mode", "text", OutputTypeCons);
+  SetEnv ("pager", getenv ("PAGER") ? getenv ("PAGER") : "more", NULL);
+  SetEnv ("qfreq", "true", BooleanCons);
+  SetEnv ("query", "boolean", QueryCons);
+  SetEnv ("sizestats", "off", BooleanCons);
+  SetEnv ("timestats", "off", BooleanCons);
+  SetEnv ("verbatim", "off", BooleanCons);
+  SetEnv ("sorted_terms", "on", BooleanCons);
+  SetEnv ("accumulator_method", "array", AccumCons);
+  SetEnv ("stop_at_max_accum", "off", BooleanCons);
+  SetEnv ("buffer", "1048576", BufferCons);
+  SetEnv ("max_accumulators", "50000", MaxNodesCons);
+  SetEnv ("max_terms", "all", MaxTermsCons);
+  SetEnv ("maxparas", "1000", MaxParasCons);
+  SetEnv ("hash_tbl_size", "1000", MaxHashCons);
+  SetEnv ("skip_dump", "skips.%d", NULL);
+  SetEnv ("ranked_doc_sepstr", "---------------------------------- %n %w\\n", NULL);
+  SetEnv ("doc_sepstr", "---------------------------------- %n\\n", NULL);
+  SetEnv ("para_sepstr", "\\n######## PARAGRAPH %n ########\\n", NULL);
+  SetEnv ("para_start", "***** Weight = %w *****\\n", NULL);
+  SetEnv ("terminator", "", NULL);
+  SetEnv ("heads_length", "50", MaxHeadsCons);
+  SetEnv ("optimise_type", "1", OptimiseCons);	/*[TS:Mar/95] */
+  SetEnv ("casefold", "on", BooleanCons);  /* [RPAP - Jan 97: Stem Index Change] */
+  SetEnv ("stem", "on", BooleanCons);  /* [RPAP - Jan 97: Stem Index Change] */
+  SetEnv ("term_freq", "off", BooleanCons);  /* [RPAP - Feb 97: Term Frequency] */
+}
+
+
+void 
+UninitEnv (void)
+{
+  char *name;
+  while (PopEnv () == 0);
+  while ((name = GetEnvName (0)) != 0)
+    UnsetEnv (name, 1);
+}
Index: /main/tags/2.25/gsdl/packages/mg/src/text/environment.h
===================================================================
--- /main/tags/2.25/gsdl/packages/mg/src/text/environment.h	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/mg/src/text/environment.h	(revision 21064)
@@ -0,0 +1,61 @@
+/**************************************************************************
+ *
+ * environment.h -- mgquery environment functions
+ * Copyright (C) 1994  Neil Sharman
+ *
+ * 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.
+ *
+ * $Id$
+ *
+ **************************************************************************/
+
+
+#ifndef ENVIRONMENT_H
+#define ENVIRONMENT_H
+
+#define OUTPUT_TEXT     'T'
+#define OUTPUT_HEADERS  'H'
+#define OUTPUT_SILENT   'S'
+#define OUTPUT_EXTRAS   'E'
+#define OUTPUT_HILITE   'I'
+#define OUTPUT_COUNT    'C'
+#define OUTPUT_DOCNUMS  'D'
+
+#define QUERY_RANKED    'R'
+#define QUERY_APPROX    'A'
+#define QUERY_BOOLEAN   'B'
+#define QUERY_DOCNUMS   'D'
+
+
+char get_output_type (void);
+char get_query_type (void);
+
+extern char *ConstraintErrorStr;
+int SetEnv (char *name, char *data, char *(*Constraint) (char *, char *));
+char *GetEnv (char *name);
+char *GetDefEnv (char *name, char *def);
+int UnsetEnv (char *name, int Force);
+char *de_escape_string (char *s);
+int PushEnv (void);
+int PopEnv (void);
+int EnvStackHeight (void);
+char *GetEnvName (int i);
+int BooleanEnv (char *data, int def);
+long IntEnv (char *data, long def);
+
+void InitEnv (void);
+void UninitEnv (void);
+
+#endif
Index: /main/tags/2.25/gsdl/packages/mg/src/text/globals.h
===================================================================
--- /main/tags/2.25/gsdl/packages/mg/src/text/globals.h	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/mg/src/text/globals.h	(revision 21064)
@@ -0,0 +1,32 @@
+/**************************************************************************
+ *
+ * globals.h -- Some global stuff for mgquery
+ * Copyright (C) 1994  Neil Sharman
+ *
+ * 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.
+ *
+ * $Id$
+ *
+ **************************************************************************/
+
+
+#ifndef H_GLOBALS
+#define H_GLOBALS
+
+
+extern FILE *OutFile;
+extern FILE *InFile;
+
+#endif
Index: /main/tags/2.25/gsdl/packages/mg/src/text/hash.h
===================================================================
--- /main/tags/2.25/gsdl/packages/mg/src/text/hash.h	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/mg/src/text/hash.h	(revision 21064)
@@ -0,0 +1,44 @@
+/**************************************************************************
+ *
+ * hash.h -- Hash function
+ * Copyright (C) 1994  Neil Sharman
+ *
+ * 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.
+ *
+ * $Id$
+ *
+ **************************************************************************/
+
+
+#ifndef H_HASH
+#define H_HASH
+
+
+
+#define HASH(h, step, wd, tablesize)			\
+	do {						\
+		register u_char *p=wd;			\
+		register long len = *p++;		\
+		register unsigned long hval;		\
+		if (len>25) len = 25;			\
+		for (hval=0; len; len--)		\
+		  hval = (hval << 5) - hval + *p++;	\
+		step = hval % (tablesize - 2) + 1;	\
+		h = hval % tablesize;			\
+	} while (0)
+
+
+
+#endif
Index: /main/tags/2.25/gsdl/packages/mg/src/text/help.mg.h
===================================================================
--- /main/tags/2.25/gsdl/packages/mg/src/text/help.mg.h	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/mg/src/text/help.mg.h	(revision 21064)
@@ -0,0 +1,320 @@
+static char *help_str[] = {
+"\n",
+"			  HELP for mgquery\n",
+"		   ================================\n",
+"\n",
+"The text is a summary of the information in the \"mgquery\" manual pages.\n",
+"\n",
+"The input to 'mgquery' consists of a series of input lines. The backslash\n",
+"character (\"\\\") is used at the end of lines to indicate that input \n",
+"continues on the next line.\n",
+"\n",
+"Input lines on which the first character is a dot (\".\") are commands to\n",
+"the mgquery program. Input lines that do not start with a dot are queries.\n",
+"\n",
+"A query consists of two parts. One part is a boolean or ranked query that\n",
+"identifies documents. The second part is a post-processing pattern matching\n",
+"operation. Any text between the first speech mark (\") and the last speech\n",
+"mark is considered to the a post-processing pattern. \n",
+"\n",
+"\n",
+"The following command are available :-\n",
+"\n",
+"    .help	     - displays this text.\n",
+"    .quit            - quits the program.\n",
+"    .set name value  - sets parameter \"name\" to \"value\" . If the parameter\n",
+"                       is a boolean parameter and value is omitted the\n",
+"	    	       parameter will be inverted (i.e. if it is true it\n",
+"		       will change to false, if it is false it will change\n",
+"		       to true).\n",
+"    .unset name      - deletes parameter \"name\"\n",
+"    .reset           - sets all the parameters to their initial state.\n",
+"    .display         - displays the values of all the current parameters.\n",
+"    .push            - pushes the current parameters on to a stack.\n",
+"    .pop             - destroys the current parameters and pops a new set\n",
+"                       of parameters off the stack.\n",
+"    .output arg      - This is used to specify where to send the documents.\n",
+"                       Arg may one be of the following:\n",
+"		       > filename  : Send output to the specified file.\n",
+"		       >> filename : Append output to the specified file.\n",
+"                       | command   : The output is piped into command, \n",
+"                                     which is executed by sh.\n",
+"    .input arg       - This is used to specify where input comes from.\n",
+"                       Arg may one be of the following:\n",
+"		       < filename  : Get the input from the specified\n",
+"                                     file.\n",
+"                       | command   : The input comes from the standard\n",
+"                                     output of command, which is executed\n",
+"                                     by sh.\n",
+"\n",
+"On startup the mgquery program reads from the file .mgrc a sequence \n",
+"of commands (NOTE: The .mgrc file may not contain any queries). mgquery \n",
+"first looks for .mgrc in the current directory and then in the users home \n",
+"directory. Lines starting with a '#' in the .mgrc file are considered to\n",
+"be comments and are ignored.\n",
+"\n",
+"The following parameters (used in the .set and .unset commands) are \n",
+"predefined and have special significance :-\n",
+"\n",
+"accumulator_method = `array'\n",
+"	This parameter is used during ranking, and specifies how the\n",
+"	weight for each document should be accumulated. The following\n",
+"	methods are available `array', `splay_tree', `hash_table', and\n",
+"	`list'.\n",
+"\n",
+"briefstats = `off'\n",
+"	This is a boolean parameter that determines whether the the\n",
+"	totals for disk, memory and time usage statistics will be \n",
+"	displayed. at the end of each query. \n",
+"	NOTE: this takes precedence over the parameters \"diskstats\",\n",
+"	\"memstats\" and \"timestats\". This parameter may take the values \n",
+"	`yes', `no', `true', `false', `on' or `off'.\n",
+"\n",
+"buffer = `1048576'\n",
+"	When the documents are being read in they are read into a \n",
+"	buffer of this size and then displayed from this buffer. If \n",
+"        the documents are larger than this buffer the buffer is\n",
+"	expanded automatically. Having a large buffer gives a very\n",
+"	slight performance improvement because it allows the order of \n",
+"	disk operations to be optimised. The buffer size is measured\n",
+"	in bytes.\n",
+"\n",
+"diskstats = `off'\n",
+"	This is a boolean parameter that determines whether the disk\n",
+"	usage statistics for the preceding query will be displayed\n",
+"	after each query. This parameter may take the values `yes',\n",
+"	`no', `true', `false', `on' or `off'.\n",
+"\n",
+"doc_sepstr = `---------------------------------- %n\\n'\n",
+"	This specifies the string that will be used to separate \n",
+"	documents when they are displayed for `boolean' or `docnums'\n",
+"	queries. The standard C escape character sequences (see the \n",
+"	man page) may be used to place special characters in the \n",
+"	string. For example, a newline would the `\\n'. To include a `%'\n",
+"	use the sequence `%%'. To include the MG document number use\n",
+"	the sequence `%n'.\n",
+"\n",
+"expert = `false'\n",
+"	If this is true then a lot of the waffle that the program \n",
+"	spits out is suppressed. This parameter may take the values\n",
+"	`yes', `no', `true', `false', `on' or `off'.\n",
+"\n",
+"hash_tbl_size = `1000'\n",
+"	One of the options during ranking queries is to use a hash \n",
+"	table to accumulate the weights for each document. The hash \n",
+"	table is a simple chained type. This parameter specifies the \n",
+"	size of the hash table and may take any value between 8 and\n",
+"	268435456. \n",
+"\n",
+"heads_length = `50'\n",
+"	When the mode is `heads' this specifies the number of \n",
+"	characters that	will be output for each document.\n",
+"\n",
+"maxdocs = `all'\n",
+"	The maximum number of documents to display in response to a\n",
+"	query. This parameter may take on a numeric value between 1 \n",
+"	and 429467295 or the word `all'.\n",
+"\n",
+"maxparas = `1000'\n",
+"	The maximum number of paragraphs to identify during a ranked\n",
+"	query with paragraph indexing. After the paragraphs have been\n",
+"	identified the paragraphs are converted into documents, and \n",
+"	because some of the paragraphs may refer to the same documents \n",
+"	the final number of answers may be less that maxparas. The \n",
+"	maxdocs parameter will then be applied. This parameter may \n",
+"	take on a numeric value between 1 and 429467295.\n",
+"\n",
+"max_accumulators = `50000'\n",
+"	This parameter limits the number of different paragraph/\n",
+"	document numbers to be accumulated during ranked queries when \n",
+"	the parameter `accumulator_method` is set to `splay_tree',\n",
+"	`hash_table', or `list'.  This parameter may take any value \n",
+"	between 8 and 268435456.\n",
+"\n",
+"max_terms = `all'\n",
+"	This parameter limits the number of terms that will actually\n",
+"	be used during a ranked query. If more terms than the number\n",
+"	specified by max_terms are entered, then the extra terms will\n",
+"	be discarded. If `sorted_terms' is on then the limiting will \n",
+"	be done after the terms have been sorted. This parameter may\n",
+"	take any value between 1 and 429467295 or the word `all'.\n",
+"\n",
+"memstats = `off'\n",
+"	This is a boolean parameter that determines whether the memory \n",
+"	usage statistics for the preceding query will be displayed\n",
+"	after each query. This parameter may take the values `yes', \n",
+"	`no', `true', `false', `on' or `off'.\n",
+"\n",
+"mgdir = `.'\n",
+"	This specifies the directory where the MG files may be found.\n",
+"	If the environment variable `MGDATA' is set then `mgdir' is\n",
+"	initialised to the value in `MGDATA'.\n",
+"\n",
+"mgname = `'\n",
+"	This specifies the name of the MG database to process.\n",
+"\n",
+"mode = `text'\n",
+"	This specifies how documents should be displayed when they\n",
+"	are retrieved it may take four different values `text', \n",
+"	`docnums', `silent', `heads' or `count'. `text' displays \n",
+"	the contents of the document. `docnums' displays only the\n",
+"	document numbers. `Silent' retrieves all the documents but\n",
+"	displays nothing except how many documents were retrieved.\n",
+"	This mode is intended to be used in timing experiments. \n",
+"	`Heads` is used to print out the head of each document.\n",
+"	`Count' does the minimum amount of work required to determine\n",
+"	how many documents would be retrieved, but does not retrieve\n",
+"	them.\n",
+"\n",
+"pager = `more'\n",
+"	This is the name of the program that will be used to display\n",
+"	the help and the retrieved documents. If the environment \n",
+"	variable \"PAGER\" is defined then `pager' takes on that value.\n",
+"\n",
+"para_sepstr = `\\n######## PARAGRAPH %n ########\\n'\n",
+"	This specifies the string that will be used to separate \n",
+"	paragraphs. The standard C escape character sequences (see the \n",
+"	man page) may be used to place special characters in the \n",
+"	string. For example, a newline would the `\\n'. To include a `%'\n",
+"	use the sequence `%%'. To include the paragraph number within\n",
+"	the document use the sequence `%n'.\n",
+"\n",
+"para_start = `***** Weight = %w *****\\n'\n",
+"	This specifies the string that will be used at the head of \n",
+"	paragraphs for a paraghaph level index following a ranked query.\n",
+"	The standard C escape character sequences (see the man page)\n",
+"	may be used to place special characters in the string. For \n",
+"	example, a newline would the `\\n'. To include a `%' use the\n",
+"	sequence `%%'. To include the paragraph weight use the \n",
+"	sequence `%w'.\n",
+"\n",
+"qfreq = `true'\n",
+"	This determine whether the ranked queries will take into \n",
+"	account the number of times each query term is specified.\n",
+"	When this is `true' the number of times a term appears in\n",
+"	the query is used in the ranking. When this is `false' all \n",
+"	query term are assumed to occur only once. This parameter\n",
+"	may take the values `yes', `no', `true', `false', `on' or\n",
+"	`off'.\n",
+"\n",
+"query = `boolean'\n",
+"	This specifies the type of queries that are to be specified.\n",
+"	It can take four different values `boolean', `ranked', \n",
+"	`docnums' or `approx-ranked'. \n",
+"\n",
+"	`boolean' is for boolean queries. \n",
+"		The yacc grammar for boolean queries is as follows :-\n",
+"\n",
+"		query   : or;\n",
+" \n",
+"		or      : or '|' and\n",
+"		        | and ;	\n",
+" \n",
+"		and     : and '&' not\n",
+"        		| and not\n",
+"        		| not ;\n",
+"\n",
+"		not     : term\n",
+"		        | '!' not ;\n",
+" \n",
+"		term    : TERM\n",
+"		        | '(' or ')' ;\n",
+" \n",
+"\n",
+"\n",
+"\n",
+"	`ranked' and `approx-ranked' are for queries ranked by the\n",
+"		cosine measure. `approx-ranked' uses only the low\n",
+"		precision document lengths, and therefore only\n",
+"		produces an approximation to full cosine ranking.\n",
+"\n",
+"		query   : TERM\n",
+"      			| query TERM ;\n",
+"	\n",
+"	`docnums' allows the entry of document numbers. Multiple \n",
+"		numbers separated by spaces may be specified\n",
+"		or ranges separated by hyphens.\n",
+"\n",
+"\n",
+"		query   : range\n",
+"			| query range ;\n",
+"\n",
+"\n",
+"		range   : num\n",
+"			| num '-' num ;\n",
+"\n",
+"\n",
+"ranked_doc_sepstr = `---------------------------------- %n %w\\n'\n",
+"	This specifies the string that will be used to separate \n",
+"	documents when they are displayed for `ranked' or \n",
+"	`approx-ranked'	queries. The standard C escape character \n",
+"	sequences (see the man page) may be used to place special\n",
+"	characters in the string. For example, a newline would the\n",
+"	`\\n'. To include a `%' use the sequence `%%'. To include the\n",
+"	MG document number use the sequence `%n'. To include the\n",
+"	document weight use the sequence `%w'.\n",
+"\n",
+"sizestats = `false'\n",
+"	If this is true then various numbers are output at the end\n",
+"	of each query indicating what went on during the query. \n",
+"	This parameter may take the values `yes', `no', `true', \n",
+"	`false', `on' or `off'.\n",
+"\n",
+"skip_dump = `skips.%d'\n",
+"	If this parameter is set then during ranked queries on skipped\n",
+"	inverted files when `accumulator_method' is set to `splay_tree',\n",
+"	`hash_table', or `list` a file will be produced in the current\n",
+"	directory. The name of the file is the value of this parameter,\n",
+"	a `%d' in the file name will be replaced with the process id of\n",
+"	mgquery. This file will contain information about the usage of\n",
+"	skips during the query processing. This option is expensive; \n",
+"	use `.unset skip_dump' to obtain optimal performance.\n",
+"\n",
+"sorted_terms = `on'\n",
+"	This specifies whether of not the terms should be sorted into\n",
+"	decreasing occurrence in documents so that the least often\n",
+"	occurring terms are processed first when ranked queries are\n",
+"	being done. When this is true the terms are sorted. When this\n",
+"	is false the terms are not sorted and are instead processed in\n",
+"	order of occurrence. This parameter may take the values `yes',\n",
+"	`no', `true', `false', `on' or `off'.\n",
+"\n",
+"\n",
+"stop_at_max_accum = `on'\n",
+"	This specifies what should happen when the maximum number of\n",
+"	accumulators set by `max_accumulators' is reached. When this\n",
+"	is true the the processing of terms is stopped at the completion\n",
+"	of the current term. When this is false processing continues but\n",
+"	no new accumulators are created. This parameter may take the \n",
+"	values `yes', `no', `true', `false', `on' or `off'.\n",
+"\n",
+"terminator = `'\n",
+"	This specifies the string that will be output after the	last\n",
+"	document from the previous query has been output. The standard\n",
+"	C escape character sequences (see the man page) may be used to\n",
+"	place special characters in the string. For example, a newline\n",
+"	would the `\\n'. To include a `%' use the sequence `%%'.\n",
+"	\n",
+"\n",
+"timestats = `false'\n",
+"	If this is true then the time to process a query is displayed\n",
+"	in both real time and CPU time. This parameter may take the\n",
+"	values `yes', `no', `true', `false', `on' or `off'.\n",
+"\n",
+"verbatim = `off'\n",
+"	This is a boolean parameter that determines whether the program\n",
+"	should attempt to do a regular expression match on the retrieved\n",
+"	text. If verbatim is `on' and a post-processing strng is specified\n",
+"	with the query then the post-processing string will be searched for\n",
+"	in the documents just before they are displayed. If the string is\n",
+"	found the document will be displayed, if not the document will not\n",
+"	be displayed. If verbatim is `off' the post-processing string will\n",
+"	be considered a regular expression like in `vi' or `egrep'.\n",
+"	E.G. If verbatim is `on', \"and.*the\" will look for the 8 character\n",
+"	     sequence \"and.*the\". If verbatim is `off', \"and.*the\" will\n",
+"	     look for the sequence \"and\" followed somewhere later in the\n",
+"	     document by the sequence \"the\".\n",
+"	This parameter may take the values `yes', `no', `true', `false',\n",
+"	`on' or `off'.\n",
+"\n",
+"\n"};
Index: /main/tags/2.25/gsdl/packages/mg/src/text/help.mg.src
===================================================================
--- /main/tags/2.25/gsdl/packages/mg/src/text/help.mg.src	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/mg/src/text/help.mg.src	(revision 21064)
@@ -0,0 +1,347 @@
+###########################################################################
+#
+# help.mg.src -- Source for the help command
+# Copyright (C) 1994  Neil Sharman
+#
+# 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.
+#
+#       @(#)help.mg.src	1.8 21 Mar 1994
+#
+###########################################################################
+#
+# The help file for mgquery.  
+# Lines starting with '#' are treated as comments and are discarded when
+# the 'help.mg.h' file is produced
+#
+###########################################################################
+
+			  HELP for mgquery
+		   ================================
+
+The text is a summary of the information in the "mgquery" manual pages.
+
+The input to 'mgquery' consists of a series of input lines. The backslash
+character ("\") is used at the end of lines to indicate that input 
+continues on the next line.
+
+Input lines on which the first character is a dot (".") are commands to
+the mgquery program. Input lines that do not start with a dot are queries.
+
+A query consists of two parts. One part is a boolean or ranked query that
+identifies documents. The second part is a post-processing pattern matching
+operation. Any text between the first speech mark (") and the last speech
+mark is considered to the a post-processing pattern. 
+
+
+The following command are available :-
+
+    .help	     - displays this text.
+    .quit            - quits the program.
+    .set name value  - sets parameter "name" to "value" . If the parameter
+                       is a boolean parameter and value is omitted the
+	    	       parameter will be inverted (i.e. if it is true it
+		       will change to false, if it is false it will change
+		       to true).
+    .unset name      - deletes parameter "name"
+    .reset           - sets all the parameters to their initial state.
+    .display         - displays the values of all the current parameters.
+    .push            - pushes the current parameters on to a stack.
+    .pop             - destroys the current parameters and pops a new set
+                       of parameters off the stack.
+    .output arg      - This is used to specify where to send the documents.
+                       Arg may one be of the following:
+		       > filename  : Send output to the specified file.
+		       >> filename : Append output to the specified file.
+                       | command   : The output is piped into command, 
+                                     which is executed by sh.
+    .input arg       - This is used to specify where input comes from.
+                       Arg may one be of the following:
+		       < filename  : Get the input from the specified
+                                     file.
+                       | command   : The input comes from the standard
+                                     output of command, which is executed
+                                     by sh.
+
+On startup the mgquery program reads from the file .mgrc a sequence 
+of commands (NOTE: The .mgrc file may not contain any queries). mgquery 
+first looks for .mgrc in the current directory and then in the users home 
+directory. Lines starting with a '#' in the .mgrc file are considered to
+be comments and are ignored.
+
+The following parameters (used in the .set and .unset commands) are 
+predefined and have special significance :-
+
+accumulator_method = `array'
+	This parameter is used during ranking, and specifies how the
+	weight for each document should be accumulated. The following
+	methods are available `array', `splay_tree', `hash_table', and
+	`list'.
+
+briefstats = `off'
+	This is a boolean parameter that determines whether the the
+	totals for disk, memory and time usage statistics will be 
+	displayed. at the end of each query. 
+	NOTE: this takes precedence over the parameters "diskstats",
+	"memstats" and "timestats". This parameter may take the values 
+	`yes', `no', `true', `false', `on' or `off'.
+
+buffer = `1048576'
+	When the documents are being read in they are read into a 
+	buffer of this size and then displayed from this buffer. If 
+        the documents are larger than this buffer the buffer is
+	expanded automatically. Having a large buffer gives a very
+	slight performance improvement because it allows the order of 
+	disk operations to be optimised. The buffer size is measured
+	in bytes.
+
+diskstats = `off'
+	This is a boolean parameter that determines whether the disk
+	usage statistics for the preceding query will be displayed
+	after each query. This parameter may take the values `yes',
+	`no', `true', `false', `on' or `off'.
+
+doc_sepstr = `---------------------------------- %n\n'
+	This specifies the string that will be used to separate 
+	documents when they are displayed for `boolean' or `docnums'
+	queries. The standard C escape character sequences (see the 
+	man page) may be used to place special characters in the 
+	string. For example, a newline would the `\n'. To include a `%'
+	use the sequence `%%'. To include the MG document number use
+	the sequence `%n'.
+
+expert = `false'
+	If this is true then a lot of the waffle that the program 
+	spits out is suppressed. This parameter may take the values
+	`yes', `no', `true', `false', `on' or `off'.
+
+hash_tbl_size = `1000'
+	One of the options during ranking queries is to use a hash 
+	table to accumulate the weights for each document. The hash 
+	table is a simple chained type. This parameter specifies the 
+	size of the hash table and may take any value between 8 and
+	268435456. 
+
+heads_length = `50'
+	When the mode is `heads' this specifies the number of 
+	characters that	will be output for each document.
+
+maxdocs = `all'
+	The maximum number of documents to display in response to a
+	query. This parameter may take on a numeric value between 1 
+	and 429467295 or the word `all'.
+
+maxparas = `1000'
+	The maximum number of paragraphs to identify during a ranked
+	query with paragraph indexing. After the paragraphs have been
+	identified the paragraphs are converted into documents, and 
+	because some of the paragraphs may refer to the same documents 
+	the final number of answers may be less that maxparas. The 
+	maxdocs parameter will then be applied. This parameter may 
+	take on a numeric value between 1 and 429467295.
+
+max_accumulators = `50000'
+	This parameter limits the number of different paragraph/
+	document numbers to be accumulated during ranked queries when 
+	the parameter `accumulator_method` is set to `splay_tree',
+	`hash_table', or `list'.  This parameter may take any value 
+	between 8 and 268435456.
+
+max_terms = `all'
+	This parameter limits the number of terms that will actually
+	be used during a ranked query. If more terms than the number
+	specified by max_terms are entered, then the extra terms will
+	be discarded. If `sorted_terms' is on then the limiting will 
+	be done after the terms have been sorted. This parameter may
+	take any value between 1 and 429467295 or the word `all'.
+
+memstats = `off'
+	This is a boolean parameter that determines whether the memory 
+	usage statistics for the preceding query will be displayed
+	after each query. This parameter may take the values `yes', 
+	`no', `true', `false', `on' or `off'.
+
+mgdir = `.'
+	This specifies the directory where the MG files may be found.
+	If the environment variable `MGDATA' is set then `mgdir' is
+	initialised to the value in `MGDATA'.
+
+mgname = `'
+	This specifies the name of the MG database to process.
+
+mode = `text'
+	This specifies how documents should be displayed when they
+	are retrieved it may take four different values `text', 
+	`docnums', `silent', `heads' or `count'. `text' displays 
+	the contents of the document. `docnums' displays only the
+	document numbers. `Silent' retrieves all the documents but
+	displays nothing except how many documents were retrieved.
+	This mode is intended to be used in timing experiments. 
+	`Heads` is used to print out the head of each document.
+	`Count' does the minimum amount of work required to determine
+	how many documents would be retrieved, but does not retrieve
+	them.
+
+pager = `more'
+	This is the name of the program that will be used to display
+	the help and the retrieved documents. If the environment 
+	variable "PAGER" is defined then `pager' takes on that value.
+
+para_sepstr = `\n######## PARAGRAPH %n ########\n'
+	This specifies the string that will be used to separate 
+	paragraphs. The standard C escape character sequences (see the 
+	man page) may be used to place special characters in the 
+	string. For example, a newline would the `\n'. To include a `%'
+	use the sequence `%%'. To include the paragraph number within
+	the document use the sequence `%n'.
+
+para_start = `***** Weight = %w *****\n'
+	This specifies the string that will be used at the head of 
+	paragraphs for a paraghaph level index following a ranked query.
+	The standard C escape character sequences (see the man page)
+	may be used to place special characters in the string. For 
+	example, a newline would the `\n'. To include a `%' use the
+	sequence `%%'. To include the paragraph weight use the 
+	sequence `%w'.
+
+qfreq = `true'
+	This determine whether the ranked queries will take into 
+	account the number of times each query term is specified.
+	When this is `true' the number of times a term appears in
+	the query is used in the ranking. When this is `false' all 
+	query term are assumed to occur only once. This parameter
+	may take the values `yes', `no', `true', `false', `on' or
+	`off'.
+
+query = `boolean'
+	This specifies the type of queries that are to be specified.
+	It can take four different values `boolean', `ranked', 
+	`docnums' or `approx-ranked'. 
+
+	`boolean' is for boolean queries. 
+		The yacc grammar for boolean queries is as follows :-
+
+		query   : or;
+ 
+		or      : or '|' and
+		        | and ;	
+ 
+		and     : and '&' not
+        		| and not
+        		| not ;
+
+		not     : term
+		        | '!' not ;
+ 
+		term    : TERM
+		        | '(' or ')' ;
+ 
+
+
+
+	`ranked' and `approx-ranked' are for queries ranked by the
+		cosine measure. `approx-ranked' uses only the low
+		precision document lengths, and therefore only
+		produces an approximation to full cosine ranking.
+
+		query   : TERM
+      			| query TERM ;
+	
+	`docnums' allows the entry of document numbers. Multiple 
+		numbers separated by spaces may be specified
+		or ranges separated by hyphens.
+
+
+		query   : range
+			| query range ;
+
+
+		range   : num
+			| num '-' num ;
+
+
+ranked_doc_sepstr = `---------------------------------- %n %w\n'
+	This specifies the string that will be used to separate 
+	documents when they are displayed for `ranked' or 
+	`approx-ranked'	queries. The standard C escape character 
+	sequences (see the man page) may be used to place special
+	characters in the string. For example, a newline would the
+	`\n'. To include a `%' use the sequence `%%'. To include the
+	MG document number use the sequence `%n'. To include the
+	document weight use the sequence `%w'.
+
+sizestats = `false'
+	If this is true then various numbers are output at the end
+	of each query indicating what went on during the query. 
+	This parameter may take the values `yes', `no', `true', 
+	`false', `on' or `off'.
+
+skip_dump = `skips.%d'
+	If this parameter is set then during ranked queries on skipped
+	inverted files when `accumulator_method' is set to `splay_tree',
+	`hash_table', or `list` a file will be produced in the current
+	directory. The name of the file is the value of this parameter,
+	a `%d' in the file name will be replaced with the process id of
+	mgquery. This file will contain information about the usage of
+	skips during the query processing. This option is expensive; 
+	use `.unset skip_dump' to obtain optimal performance.
+
+sorted_terms = `on'
+	This specifies whether of not the terms should be sorted into
+	decreasing occurrence in documents so that the least often
+	occurring terms are processed first when ranked queries are
+	being done. When this is true the terms are sorted. When this
+	is false the terms are not sorted and are instead processed in
+	order of occurrence. This parameter may take the values `yes',
+	`no', `true', `false', `on' or `off'.
+
+
+stop_at_max_accum = `on'
+	This specifies what should happen when the maximum number of
+	accumulators set by `max_accumulators' is reached. When this
+	is true the the processing of terms is stopped at the completion
+	of the current term. When this is false processing continues but
+	no new accumulators are created. This parameter may take the 
+	values `yes', `no', `true', `false', `on' or `off'.
+
+terminator = `'
+	This specifies the string that will be output after the	last
+	document from the previous query has been output. The standard
+	C escape character sequences (see the man page) may be used to
+	place special characters in the string. For example, a newline
+	would the `\n'. To include a `%' use the sequence `%%'.
+	
+
+timestats = `false'
+	If this is true then the time to process a query is displayed
+	in both real time and CPU time. This parameter may take the
+	values `yes', `no', `true', `false', `on' or `off'.
+
+verbatim = `off'
+	This is a boolean parameter that determines whether the program
+	should attempt to do a regular expression match on the retrieved
+	text. If verbatim is `on' and a post-processing strng is specified
+	with the query then the post-processing string will be searched for
+	in the documents just before they are displayed. If the string is
+	found the document will be displayed, if not the document will not
+	be displayed. If verbatim is `off' the post-processing string will
+	be considered a regular expression like in `vi' or `egrep'.
+	E.G. If verbatim is `on', "and.*the" will look for the 8 character
+	     sequence "and.*the". If verbatim is `off', "and.*the" will
+	     look for the sequence "and" followed somewhere later in the
+	     document by the sequence "the".
+	This parameter may take the values `yes', `no', `true', `false',
+	`on' or `off'.
+
+
Index: /main/tags/2.25/gsdl/packages/mg/src/text/invf.h
===================================================================
--- /main/tags/2.25/gsdl/packages/mg/src/text/invf.h	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/mg/src/text/invf.h	(revision 21064)
@@ -0,0 +1,79 @@
+/**************************************************************************
+ *
+ * invf.h -- Data structures for inverted files
+ * Copyright (C) 1994  Neil Sharman
+ *
+ * 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.
+ *
+ * $Id$
+ *
+ **************************************************************************/
+
+
+
+#ifndef H_INVF
+#define H_INVF
+
+/* NOTE: This does not include the magic number */
+struct invf_dict_header
+  {
+    unsigned long lookback;
+    unsigned long dict_size;
+    unsigned long total_bytes;
+    unsigned long index_string_bytes;
+    double input_bytes; /* [RJM 07/97: 4G limit] */
+    unsigned long num_of_docs;
+    unsigned long static_num_of_docs;
+    unsigned long num_of_words;
+    unsigned long stemmer_num;
+    unsigned long stem_method;
+  };
+
+struct stem_dict_header
+  {
+    unsigned long lookback;
+    unsigned long block_size;
+    unsigned long num_blocks;
+    unsigned long blocks_start;
+    unsigned long index_chars;
+    unsigned long num_of_docs;
+    unsigned long static_num_of_docs;
+    unsigned long num_of_words;
+    unsigned long stemmer_num;
+    unsigned long stem_method;
+    unsigned long indexed;       /* [RPAP - Jan 97: Stem Index Change] */
+  };
+
+struct invf_file_header
+  {
+    unsigned long no_of_words;
+    unsigned long no_of_ptrs;
+    unsigned long skip_mode;
+    unsigned long params[16];
+    unsigned long InvfLevel;
+  };
+
+/* [RPAP - Jan 97: Stem Index Change] */
+struct stem_idx_header
+  {
+    unsigned long lookback;
+    unsigned long block_size;
+    unsigned long num_blocks;
+    unsigned long blocks_start;
+    unsigned long index_chars;
+    unsigned long num_of_words;
+  };
+
+#endif
Index: /main/tags/2.25/gsdl/packages/mg/src/text/invf_get.c
===================================================================
--- /main/tags/2.25/gsdl/packages/mg/src/text/invf_get.c	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/mg/src/text/invf_get.c	(revision 21064)
@@ -0,0 +1,1666 @@
+/**************************************************************************
+ *
+ * invf_get.c -- Inverted file reading routines
+ * Copyright (C) 1994  Neil Sharman
+ *
+ * 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.
+ *
+ * $Id$
+ *
+ **************************************************************************/
+
+#include "sysfuncs.h"
+
+#include "memlib.h"
+#include "filestats.h"
+#include "timing.h"
+#include "bitio_gen.h"
+#include "bitio_m_mem.h"
+#include "bitio_m.h"
+#include "sptree.h"
+#include "messages.h"
+#include "netorder.h"  /* [RPAP - Jan 97: Endian Ordering] */
+
+#include "mg.h"
+#include "invf.h"
+#include "text.h"
+#include "lists.h"
+#include "backend.h"
+#include "invf_get.h"
+#include "mg_errors.h"
+
+#define SKIPPING
+#define SHORT_CUT
+
+struct pool
+  {
+    int length, pos;
+    struct pool *next;
+    Invf_Doc_Entry ide[1];
+  };
+
+static int skip_header = 0;
+
+static char skip_header_text0[] =
+"#######################################################################\n"
+"#\n"
+"# 1\tWord number.\n"
+"# 2\tNumber of time the word occurs in the collection.\n"
+"# 3\tNumber of documents the word occurs in.\n"
+"# 4\tThe word.\n"
+"# 5\tNumber of docnum/word_count entries decoded.\n"
+"# 6\tNumber of hits.\n"
+"# 7\tNumber of entries in the splay tree or hash table.\n"
+"# 8\tAmount added to the accumulators while while processing this word.\n"
+"#\n"
+"#######################################################################\n";
+
+static char skip_header_text1[] =
+"#######################################################################\n"
+"#\n"
+"# 1\tWord number.\n"
+"# 2\tNumber of time the word occurs in the collection.\n"
+"# 3\tNumber of documents the word occurs in.\n"
+"# 4\tThe word.\n"
+"# 5\tNumber of skips taken in evaluating the inverted file entry.\n"
+"# 6\tNumber of docnum/word_count entries decoded.\n"
+"# 7\tNumber of hits.\n"
+"# 8\tNumber of entries in the splay tree or hash table.\n"
+"# 9\tAmount added to the accumulators while while processing this word.\n"
+"#\n"
+"#######################################################################\n";
+
+
+static char skip_header_text2[] =
+"#######################################################################\n"
+"#\n"
+"#  1\tWord number.\n"
+"#  2\tNumber of time the word occurs in the collection.\n"
+"#  3\tNumber of documents the word occurs in.\n"
+"#  4\tThe word.\n"
+"#  5\tSkip size.\n"
+"#  6\tNumber of skips taken in evaluating the inverted file entry.\n"
+"#  7\tNumber of docnum/word_count entries decoded.\n"
+"#  8\tNumber of hits.\n"
+"#  9\tNumber of entries in the splay tree or hash table.\n"
+"# 10\tAmount added to the accumulators while while processing this word.\n"
+"#\n"
+"#######################################################################\n";
+
+static char *skip_header_text[] =
+{skip_header_text0,
+ skip_header_text1,
+ skip_header_text2};
+
+
+
+
+
+
+
+
+/**************************************************************************
+ *
+ * Code for the hash table.
+ *
+ */
+
+static Hash_Table *
+HT_create (query_data * qd, unsigned max_entries,
+	   unsigned max_size)
+{
+  unsigned es, hts;
+  Hash_Table *HT;
+  if (max_entries == 0)
+    max_entries = 8192;
+  es = sizeof (Hash_Table) + sizeof (Invf_Doc_EntryH) * (max_entries - 1);
+  hts = sizeof (Invf_Doc_EntryH *) * max_size;
+
+  HT = Xmalloc (es);
+  if (!HT)
+    return NULL;
+
+  HT->HashTable = Xmalloc (hts);
+  if (!(HT->HashTable))
+    {
+      Xfree (HT);
+      return NULL;
+    }
+
+  ChangeMemInUse (qd, es + hts);
+  bzero ((char *) (HT->HashTable), hts);
+  HT->max = max_entries;
+  HT->num = 0;
+  HT->Suplimentary_Entries = NULL;
+  HT->Suplimentary_Size = 0;
+  HT->Suplimentary_Num = 0;
+  HT->Head = NULL;
+  HT->size = max_size;
+  return HT;
+}
+
+
+static void 
+HT_Sup_create (query_data * qd, Hash_Table * HT, unsigned max_size)
+{
+  int es = sizeof (Invf_Doc_EntryH) * max_size;
+  HT->Suplimentary_Entries = Xmalloc (es);
+  if (!HT->Suplimentary_Entries)
+    return;
+  HT->Suplimentary_Size = max_size;
+  HT->Suplimentary_Num = 0;
+  ChangeMemInUse (qd, es);
+}
+
+static void 
+HT_Sup_Add (Hash_Table * HT, unsigned long DN, float Sum)
+{
+  Invf_Doc_EntryH *IDEH;
+  IDEH = &HT->Suplimentary_Entries[HT->Suplimentary_Num++];
+  IDEH->next = NULL;
+  IDEH->IDE.DocNum = DN;
+  IDEH->IDE.Sum = Sum;
+}
+
+Invf_Doc_Entry *
+HT_find (Hash_Table * HT, unsigned long DN)
+{
+  Invf_Doc_EntryH *IDEH;
+  if (!HT->HashTable)
+    FatalError (1, "Accessing the hash_table through HT_find after HT_sort");
+  IDEH = HT->HashTable[DN % HT->size];
+  while (IDEH)
+    {
+      if (IDEH->IDE.DocNum == DN)
+	return &(IDEH->IDE);
+      IDEH = IDEH->next;
+    }
+  return NULL;
+}
+
+
+static int 
+HT_insert (Hash_Table * HT,
+	   unsigned long DN, float Sum)
+{
+  Invf_Doc_EntryH **IDEH;
+  if (HT->num == HT->max)
+    return 0;
+  IDEH = &(HT->HashTable[DN % HT->size]);
+  while (*IDEH)
+    IDEH = &((*IDEH)->next);
+  *IDEH = &(HT->IDEH[HT->num++]);
+  (*IDEH)->next = NULL;
+  (*IDEH)->IDE.DocNum = DN;
+  (*IDEH)->IDE.Sum = Sum;
+  return 1;
+}
+
+
+void 
+HT_free (query_data * qd, Hash_Table * HT)
+{
+  unsigned es;
+  es = sizeof (Hash_Table) + sizeof (Invf_Doc_EntryH) * HT->max +
+    sizeof (Invf_Doc_EntryH *) * HT->size;
+  if (HT->HashTable)
+    Xfree (HT->HashTable);
+  if (HT->Suplimentary_Entries)
+    {
+      Xfree (HT->Suplimentary_Entries);
+      es += sizeof (Invf_Doc_EntryH) * HT->Suplimentary_Size;
+    }
+  Xfree (HT);
+  ChangeMemInUse (qd, -es);
+}
+
+
+static int 
+IDEH_comp (const void *a, const void *b)
+{
+  const Invf_Doc_EntryH *A = a;
+  const Invf_Doc_EntryH *B = b;
+  return A->IDE.DocNum - B->IDE.DocNum;
+}
+
+static void 
+HT_sort (query_data * qd, Hash_Table * HT)
+{
+  int i;
+  Invf_Doc_EntryH *l, *r, **b;
+  unsigned es = sizeof (Invf_Doc_EntryH *) * HT->size;
+  if (HT->HashTable)
+    Xfree (HT->HashTable);
+  HT->size = 0;
+  HT->HashTable = NULL;
+  ChangeMemInUse (qd, -es);
+
+  qsort (HT->IDEH, HT->num, sizeof (Invf_Doc_EntryH), IDEH_comp);
+
+  for (i = 0; i < HT->num - 1; i++)
+    HT->IDEH[i].next = &HT->IDEH[i + 1];
+  HT->IDEH[i].next = NULL;
+  l = HT->IDEH;
+
+  if (HT->Suplimentary_Entries)
+    {
+      for (i = 0; i < HT->Suplimentary_Num - 1; i++)
+	HT->Suplimentary_Entries[i].next = &HT->Suplimentary_Entries[i + 1];
+      HT->Suplimentary_Entries[i].next = NULL;
+    }
+  r = HT->Suplimentary_Entries;
+
+  b = &HT->Head;
+
+  while (l || r)
+    {
+      if (r && (!l || (l->IDE.DocNum > r->IDE.DocNum)))
+	{
+	  *b = r;
+	  b = &r->next;
+	  r = *b;
+	}
+      else
+	{
+	  *b = l;
+	  b = &l->next;
+	  l = *b;
+	}
+    }
+  *b = NULL;
+}
+
+
+
+
+
+
+/**************************************************************************
+ *
+ * Code for the hash table.
+ *
+ */
+
+static List_Table *
+LT_create (query_data * qd, unsigned max_entries)
+{
+  unsigned es;
+  List_Table *LT;
+  if (max_entries == 0)
+    max_entries = 8192;
+  es = sizeof (List_Table) + sizeof (Invf_Doc_Entry) * (max_entries - 1);
+
+  LT = Xmalloc (es);
+  if (!LT)
+    return NULL;
+
+  ChangeMemInUse (qd, es);
+  LT->max = max_entries;
+  LT->num = 0;
+  return LT;
+}
+
+
+
+Invf_Doc_Entry *
+LT_find (List_Table * LT, unsigned long DN)
+{
+  int l = 0;
+  int r = LT->num - 1;
+  int m, c;
+  while (l <= r)
+    {
+      m = (l + r) / 2;
+      c = DN - LT->IDE[m].DocNum;
+      if (c < 0)
+	r = m - 1;
+      else if (c > 0)
+	l = m + 1;
+      else
+	return &LT->IDE[m];
+    }
+  return NULL;
+}
+
+static List_Table *
+LT_add (query_data * qd, List_Table * LT,
+	unsigned long DN, float Sum)
+{
+  Invf_Doc_Entry *ide;
+
+  /* increase the size of the list if there is not enough */
+  /* room for this entry */
+  if (LT->num == LT->max)
+    {
+      int old, new, max_entries;
+      old = sizeof (List_Table) + sizeof (Invf_Doc_Entry) * LT->max;
+      max_entries = LT->max + (LT->max >> 1);
+      new = sizeof (List_Table) + sizeof (Invf_Doc_Entry) * max_entries;
+
+      LT = Xrealloc (LT, new);
+      if (!LT)
+	return NULL;
+
+      ChangeMemInUse (qd, new - old);
+      LT->max = max_entries;
+    }
+
+  /* add the entry to the end of the list */
+  ide = &LT->IDE[LT->num];
+  ide->DocNum = DN;
+  ide->Sum = Sum;
+  LT->num++;
+
+  return LT;
+}
+
+
+void 
+LT_free (query_data * qd, List_Table * LT)
+{
+  unsigned es;
+  es = sizeof (List_Table) + sizeof (Invf_Doc_Entry) * LT->max;
+  Xfree (LT);
+  ChangeMemInUse (qd, -es);
+}
+
+
+static int 
+IDE_comp (const void *a, const void *b)
+{
+  const Invf_Doc_Entry *A = a;
+  const Invf_Doc_Entry *B = b;
+  return A->DocNum - B->DocNum;
+}
+
+static void 
+LT_sort (List_Table * LT)
+{
+  qsort (LT->IDE, LT->num, sizeof (Invf_Doc_Entry), IDE_comp);
+}
+
+
+/* [RJM 07/97: Ranked Required Terms] */
+/* accumulators with a sum less than or equal to 0.0 are to be deleted */
+static void 
+LT_pack (List_Table * LT)
+{
+  int s, d = 0;
+  for (s = 0; s < LT->num; s++) {
+      if (LT->IDE[s].Sum <= 0.0) {
+	/* ignore this accumulator */
+
+      } else if (d > 0 && LT->IDE[s].DocNum == LT->IDE[d-1].DocNum) {
+	LT->IDE[d-1].Sum += LT->IDE[s].Sum;
+
+      } else {
+	if (d != s) LT->IDE[d] = LT->IDE[s];
+	d++;
+      }
+  }
+
+  if (LT->num) LT->num = d;
+}
+
+
+/**************************************************************************/
+
+
+
+invf_data *
+InitInvfFile (File * InvfFile, stemmed_dict * sd)
+{
+  invf_data *id;
+  if (!(id = Xmalloc (sizeof (invf_data))))
+    {
+      mg_errno = MG_NOMEM;
+      return NULL;
+    }
+
+  id->InvfFile = InvfFile;
+
+  Fread (&id->ifh, sizeof (id->ifh), 1, InvfFile);
+  /* [RPAP - Jan 97: Endian Ordering] */
+  {
+    int i;
+    
+    NTOHUL(id->ifh.no_of_words);
+    NTOHUL(id->ifh.no_of_ptrs);
+    NTOHUL(id->ifh.skip_mode);
+    for (i = 0; i < 16; i++)
+      NTOHUL(id->ifh.params[i]);
+    NTOHUL(id->ifh.InvfLevel);
+  }
+
+  id->N = sd->sdh.num_of_docs;
+  id->Nstatic = sd->sdh.static_num_of_docs;
+
+  return (id);
+}
+
+
+void 
+FreeInvfData (invf_data * id)
+{
+  Xfree (id);
+}
+
+/****************************************************************************/
+
+
+static void 
+CalcBlks (query_data * qd, WordEntry * we, int *blk,
+	  int *dn_blk, int *len_blk, int *k, int *p)
+{
+  *p = we->doc_count;
+
+  *blk = BIO_Bblock_Init (qd->id->Nstatic, *p);
+  switch (qd->id->ifh.skip_mode)
+    {
+    case 1:
+      {
+	unsigned long len;
+	if (*p <= qd->id->ifh.params[0])
+	  *k = 0;
+	else
+	  {
+	    *k = qd->id->ifh.params[0];
+	    len = BIO_Bblock_Bound (qd->id->N, *p);
+	    if (qd->id->ifh.InvfLevel >= 2)
+	      len += we->count;
+	    *dn_blk = BIO_Bblock_Init (qd->sd->sdh.num_of_docs, (*p + *k - 1) / *k);
+	    *len_blk = BIO_Bblock_Init (len, (*p + *k - 1) / *k);
+	  }
+	break;
+      }
+    case 2:
+      {
+	unsigned long len;
+	if (*p <= qd->id->ifh.params[1])
+	  *k = 0;
+	else
+	  {
+	    *k = (int) (2 * sqrt (((double) (*p)) / qd->id->ifh.params[0]));
+	    if (*k <= qd->id->ifh.params[1])
+	      *k = qd->id->ifh.params[1];
+	    len = BIO_Bblock_Bound (qd->id->N, *p);
+	    if (qd->id->ifh.InvfLevel >= 2)
+	      len += we->count;
+	    *dn_blk = BIO_Bblock_Init (qd->sd->sdh.num_of_docs,
+				       (*p + *k - 1) / *k);
+	    *len_blk = BIO_Bblock_Init (len, (*p + *k - 1) / *k);
+	  }
+	break;
+      }
+    default:
+      *k = 0;
+    }
+}
+
+
+/* =========================================================================
+ * Function: GetDocsOp
+ * Description: 
+ *      if op == op_term then 
+ *        look up term in invf and decode all its entries/documents
+ *      if op == op_and_terms then 
+ *        go thru L, testing if it exists in invf using skips  
+ *        if it does exist then overwrite the entry nearer the start of the list
+ *      if op == op_and_or_terms then
+ *        go thru L, testing if it exists in invf using skips  
+ *        BUT only mark ones which are found - keep list intact
+ *      if op == op_diff_terms then     >>>> NOT tested <<<<
+ * Input: 
+ * Output: 
+ * ========================================================================= */
+
+DocList *
+GetDocsOp (query_data * qd, WordEntry * we, Op_types op, DocList * L)
+{
+  u_char *buffer;
+  DocEntry *src = NULL, *dest = NULL;
+  int i;			/* index counter into inverted list */
+  unsigned long pos;
+  int next_start, next_doc_num, next_i;
+  int block_counter;		/* within counter in block */
+  int dn_blk = 0, len_blk = 0;
+  int skip_size, have_skipping;
+  int blk;			/* bblock control parameter */
+  int ft;			/* The number of documents the word occurs in */
+  unsigned long CurrDoc = 0;	/* NOTE: Document numbers start at 1 */
+  float Weight;
+
+  /* ... AND empty */
+  if (op == op_and_terms && (!L || !L->num))
+    {
+      if (L)
+	Xfree (L);
+      return MakeDocList (0);
+    }
+
+  if (op == op_term)
+    L = MakeDocList (we->doc_count);
+
+  CalcBlks (qd, we, &blk, &dn_blk, &len_blk, &skip_size, &ft);
+  have_skipping = (skip_size != 0);
+  if (!(buffer = Xmalloc (we->invf_len)))
+    return MakeDocList (0);
+
+  ChangeMemInUse (qd, we->invf_len);
+
+  qd->num_of_terms++;
+
+  /* --- Read an inverted file entry for the given word --- */
+  Fseek (qd->File_invf, we->invf_ptr, 0);
+  Fread (buffer, sizeof (char), we->invf_len, qd->File_invf);
+
+  /* Read from the buffer */
+  DECODE_START (buffer, we->invf_len);
+
+  Weight = qd->sd->sdh.num_of_words / (100 * log2 ((float) we->count + 1));
+
+  if (op != op_term)
+    dest = src = L->DE;
+  i = pos = 0;
+  next_i = next_start = next_doc_num = 0;
+  block_counter = skip_size - 1;
+
+  /* Go thru the elements of an inverted list for a term */
+  /* May not go sequentially if skipping is done */
+  while (i < ft && ((op == op_term) || src - L->DE < L->num))
+    {
+      unsigned long diff, Temp;
+
+      if (have_skipping)
+	{
+
+	  /* --- Skip to next block --- */
+	  if (op != op_term && i + skip_size < ft &&
+	      src->DocNum > next_doc_num && next_doc_num >= 0)
+	    {
+	    ShortCut:
+	      i = next_i;
+	      DECODE_SEEK (next_start);
+	      pos = next_start;
+	      CurrDoc = next_doc_num;
+	      qd->hops_taken++;
+	      block_counter = skip_size - 1;
+	    }
+
+	  /* --- Decode the skip block header --- */
+	  if (block_counter == skip_size - 1)
+	    {
+	      if (i + skip_size < ft)
+		{
+		  /* --- Decode the skip block header --- */
+		  int doc_diff, pos_diff;
+		  BBLOCK_DECODE_L (doc_diff, dn_blk, pos);
+		  next_doc_num += doc_diff;
+		  next_i += skip_size;
+		  BBLOCK_DECODE_L (pos_diff, len_blk, pos);
+		  next_start = pos + pos_diff;
+		}
+	      else
+		next_doc_num = -1;
+	    }
+
+	  /* --- Do a skip if c-set doc is higher than block header doc --- */
+	  if (op != op_term && i + skip_size < ft &&
+	      src->DocNum > next_doc_num && next_doc_num >= 0)
+	    goto ShortCut;
+
+
+	}			/*if skipping */
+
+      /* --- increment CurrDoc --- */
+      if (have_skipping && block_counter == 0 && i != ft - 1)
+	CurrDoc = next_doc_num;
+      else
+	{
+	  BBLOCK_DECODE_L (diff, blk, pos);
+	  CurrDoc += diff;
+	}
+
+      /* --- If have f_dt's then eat them up --- */
+      if (qd->id->ifh.InvfLevel >= 2)
+	GAMMA_DECODE_L (Temp, pos);	/* discard word count */
+
+      /* --- Increment counters --- */
+      qd->num_of_ptrs++;
+      i++;
+      block_counter--;
+      if (block_counter < 0)	/* ??? Why would this happen ? */
+	block_counter = skip_size - 1;
+
+      switch (op)
+	{
+	case op_term:
+	  /* --- Add the doc from invf onto the c-set list --- */
+	  L->DE[L->num].DocNum = CurrDoc;
+	  L->DE[L->num].Weight = Weight;
+	  L->DE[L->num].SeekPos = 0;
+	  L->DE[L->num].Len = 0;
+	  L->DE[L->num].CompTextBuffer = NULL;
+	  L->DE[L->num].Next = NULL;
+	  L->DE[L->num].or_included = 0;
+	  L->num++;
+	  break;
+
+	case op_and_terms:
+	case op_and_or_terms:
+	  /* --- see if have a match and save it --- */
+
+	  while (src < (L->DE + L->num) && CurrDoc > src->DocNum)
+	    {
+	      src++;
+	    }
+	  /* Unless at end of list, assert(CurrDoc <= src->DocNum) */
+
+	  /* --- Accept the doc as a candidate --- */
+	  if (src < (L->DE + L->num) && CurrDoc == src->DocNum)
+	    {
+	      if (op == op_and_terms)
+		{
+		  *dest++ = *src;
+		}
+	      else
+		{
+		  src->or_included = 1;
+		}
+	      src++;		/* Move onto next one */
+	    }
+
+	  /* If the next one to try has already been tried then move on again */
+	  if (op == op_and_or_terms)
+	    {
+	      while (src < (L->DE + L->num) && src->or_included)
+		src++;
+	    }
+
+	  break;
+
+	case op_diff_terms:
+	  while (src < (L->DE + L->num) && src->DocNum < CurrDoc)
+	    *dest++ = *src++;
+	  if (src < (L->DE + L->num) && src->DocNum == CurrDoc)
+	    src++;
+	  break;
+
+	default:
+	  break;
+	}			/*switch */
+
+    }				/*while traversing invf */
+
+  if (op == op_and_terms || op == op_diff_terms)
+    {
+      if (op == op_diff_terms)
+	while (src - L->DE < L->num)
+	  *dest++ = *src++;
+
+      /* update size of c-set */
+      L->num = dest - L->DE;
+    }
+  DECODE_DONE
+
+    Xfree (buffer);
+  ChangeMemInUse (qd, -we->invf_len);
+
+  return (L);
+}
+
+
+
+
+
+
+
+float *
+CosineDecode (query_data * qd, TermList * Terms, RankedQueryInfo * rqi)
+{
+  float *AccumulatedWeights;
+  int j, num_docs, num_terms;
+  int seen_must_match = 0; /* [RJM 07/97: Ranked Required Terms] says whether to 'and' queries or not */
+
+  num_docs = qd->sd->sdh.num_of_docs;
+  /* Create the array for the documents */
+  if (!(AccumulatedWeights = Xmalloc (num_docs * sizeof (float))))
+      return (NULL);
+
+  bzero ((char *) AccumulatedWeights, sizeof (float) * num_docs);
+  ChangeMemInUse (qd, sizeof (float) * num_docs);
+
+  if (rqi->MaxTerms == -1)
+    num_terms = Terms->num;
+  else
+    num_terms = rqi->MaxTerms < Terms->num ? rqi->MaxTerms : Terms->num;
+
+
+  /* For each word in the list . . . */
+  for (j = 0; j < num_terms; j++)
+    {
+      u_char *buffer;
+      int i, kd;
+      unsigned long next_mjr_dn = 0;
+      unsigned long CurrDocNum = 0;	/* NOTE: Document numbers start at 1 */
+      unsigned long LastDocNum = 0; /* [RJM 07/97: Ranked Required Terms] */
+      unsigned long TempDocNum = 0; /* [RJM 07/97: Ranked Required Terms] */
+      double Wqt, WordLog;
+      int dn_blk = 0, len_blk = 0, k;
+      int blk;			/* bblock control parameter */
+      int p;			/* The number of documents the word occurs in */
+      int require_match = Terms->TE[j].require_match; /* [RJM 07/97: Ranked Required Terms] */
+      WordEntry *we = &Terms->TE[j].WE;
+      CalcBlks (qd, we, &blk, &dn_blk, &len_blk, &k, &p);
+      if (!(buffer = Xmalloc (we->invf_len)))
+	break;
+
+      ChangeMemInUse (qd, we->invf_len);
+
+      Fseek (qd->File_invf, we->invf_ptr, 0);
+      Fread (buffer, sizeof (char), we->invf_len, qd->File_invf);
+
+      /* Read from the buffer */
+      DECODE_START (buffer, we->invf_len);
+
+      WordLog = log ((double) num_docs / (double) we->max_doc_count);  /* [RPAP - Jan 97: Stem Index Change] */
+
+      Wqt = (rqi->QueryFreqs ? Terms->TE[j].Count : 1) * WordLog;
+
+      qd->num_of_terms++;
+
+      kd = 0;
+      for (i = 0; i < p; i++, kd++)
+	{
+	  int Count;		/* The number of times the word occurs in a document */
+	  double Wdt;
+	  unsigned long diff;
+	  if (kd == k)
+	    {
+	      kd = 0;
+	    }
+	  if (k && kd == 0)
+	    if (i + k < p)
+	      {
+		int temp;
+		BBLOCK_DECODE (next_mjr_dn, dn_blk);
+		next_mjr_dn += CurrDocNum;
+		BBLOCK_DECODE (temp, len_blk);
+	      }
+	  if (k && kd == k - 1 && i != p - 1)
+	    CurrDocNum = next_mjr_dn;
+	  else
+	    {
+	      BBLOCK_DECODE (diff, blk);
+	      CurrDocNum += diff;
+	    }
+	  if (qd->id->ifh.InvfLevel >= 2)
+	    GAMMA_DECODE (Count);
+	  else
+	    Count = (double) we->count / p;
+	  Wdt = Count * WordLog;
+
+	  /* [RJM 07/97: Ranked Required Terms] */
+	  /* zero the weights of intermediate documents if this term is required to match */
+	  if (require_match == 1) {
+	    for (TempDocNum = LastDocNum+1; TempDocNum < CurrDocNum; TempDocNum++)
+	      AccumulatedWeights[TempDocNum - 1] = 0.0;
+	  }
+
+	  /* [RJM 07/97: Ranked Required Terms] */
+	  /* if a term has been required to match before, the weight we are */
+	  /* adding to must be non-zero */
+	  if (!seen_must_match || (AccumulatedWeights[CurrDocNum - 1] > 0.0)) {
+	      AccumulatedWeights[CurrDocNum - 1] += Wqt * Wdt;
+	  }
+
+	  qd->num_of_ptrs++;
+	  LastDocNum = CurrDocNum; /* [RJM 07/97: Ranked Required Terms] */
+	}
+
+      DECODE_DONE
+
+	Xfree (buffer);
+      ChangeMemInUse (qd, -we->invf_len);
+
+      /* [RJM 07/97: Ranked Required Terms] */
+      /* zero the remaining weights if this term is required to match */
+      if (require_match == 1) {
+	for (TempDocNum = LastDocNum+1; TempDocNum <= num_docs; TempDocNum++)
+	  AccumulatedWeights[TempDocNum - 1] = 0.0;
+	seen_must_match = 1;
+      }
+    }
+  return AccumulatedWeights;
+}
+
+
+
+static int 
+doc_comp (void *a, void *b)
+{
+  return ((Invf_Doc_Entry *) a)->DocNum - ((Invf_Doc_Entry *) b)->DocNum;
+}
+
+
+static Invf_Doc_Entry *
+get_ide (query_data * qd, Invf_Doc_Entry_Pool * pool)
+{
+  struct pool *p = pool->pool;
+  if (!p || p->pos == p->length)
+    {
+      register unsigned size = sizeof (struct pool) +
+      (pool->pool_chunks - 1) * sizeof (Invf_Doc_Entry);
+      p = malloc (size);
+      if (!p)
+	return NULL;
+      ChangeMemInUse (qd, size);
+      p->length = pool->pool_chunks;
+      p->pos = 0;
+      p->next = pool->pool;
+      pool->pool = p;
+    }
+  return &(p->ide[p->pos++]);
+}
+
+
+void 
+free_ide_pool (query_data * qd, Invf_Doc_Entry_Pool * pool)
+{
+  while (pool->pool)
+    {
+      struct pool *p = pool->pool;
+      pool->pool = p->next;
+      ChangeMemInUse (qd, -(sizeof (struct pool) + (p->length - 1) *
+			    sizeof (Invf_Doc_Entry)));
+      free (p);
+    }
+  pool->pool = NULL;
+}
+
+
+FILE *
+open_skip (char *sd)
+{
+  char buf[256];
+  if (sd == NULL || *sd == '\0')
+    return NULL;
+  sprintf (buf, sd, getpid ());
+  return fopen (buf, "a");
+}
+
+
+
+Splay_Tree *
+CosineDecodeSplay (query_data * qd, TermList * Terms,
+		   RankedQueryInfo * rqi, Invf_Doc_Entry_Pool * pool)
+{
+  Splay_Tree *Doc_Set;
+  int j, num_docs, num_terms, MoreAccum;
+  int Anding = 0;
+  FILE *sk = open_skip (rqi->skip_dump);
+  u_char indent = 0;
+  if (sk)
+    {
+      if (!skip_header)
+	{
+	  skip_header = 1;
+	  fprintf (sk, "%s", skip_header_text[qd->id->ifh.skip_mode]);
+	  fprintf (sk, "\nSkipping method %ld\n", qd->id->ifh.skip_mode);
+	  switch (qd->id->ifh.skip_mode)
+	    {
+	    case 1:
+	      fprintf (sk, "Skipping is every %ld docnums\n",
+		       qd->id->ifh.params[0]);
+	      break;
+	    case 2:
+	      fprintf (sk, "Max nodes = %ld\nNo skips smaller or equal to %ld\n",
+		       qd->id->ifh.params[0], qd->id->ifh.params[1]);
+	      break;
+	    }
+	}
+      fprintf (sk, "\n\t\t\t-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-\n\n");
+      for (j = 0; j < Terms->num; j++)
+	if (Terms->TE[j].Word[0] > indent)
+	  indent = Terms->TE[j].Word[0];
+    }
+
+  num_docs = qd->sd->sdh.num_of_docs;
+  /* Create the array for the documents */
+  Doc_Set = SP_createset (doc_comp);
+
+  pool->pool = NULL;
+  pool->pool_chunks = 1024;
+
+  if (rqi->MaxTerms == -1)
+    num_terms = Terms->num;
+  else
+    num_terms = rqi->MaxTerms < Terms->num ? rqi->MaxTerms : Terms->num;
+
+  MoreAccum = 1;
+
+  /* For each word in the list . . . */
+  for (j = 0; j < num_terms; j++)
+    {
+      int Abort = 0;
+      u_char *buffer;
+      int pos, i;
+      unsigned long CurrDocNum = 0;	/* NOTE: Document numbers start at 1 */
+      double Wqt, WordLog;
+      int dn_blk = 0, len_blk = 0, k, kd;
+      int blk;			/* bblock control parameter */
+      int p;			/* The number of documents the word occurs in */
+      WordEntry *we = &Terms->TE[j].WE;
+      Invf_Doc_Entry *next = NULL;
+      int next_i, next_doc_num, next_start;
+      int skips_taken = 0, ptrs_dec = 0;
+      double total_added = 0.0;
+      int hits = 0;
+      if (sk)
+	{
+	  fprintf (sk, "%3d : %8ld %6ld \"%.*s\"%*s", j, we->count,
+		 we->doc_count, Terms->TE[j].Word[0], Terms->TE[j].Word + 1,
+		   indent - Terms->TE[j].Word[0], "");
+	}
+
+      CalcBlks (qd, we, &blk, &dn_blk, &len_blk, &k, &p);
+      if (!(buffer = Xmalloc (we->invf_len)))
+	break;
+
+      ChangeMemInUse (qd, we->invf_len);
+
+      if (sk && qd->id->ifh.skip_mode == 2)
+	fprintf (sk, "%4d", k);
+
+      Fseek (qd->File_invf, we->invf_ptr, 0);
+      Fread (buffer, sizeof (char), we->invf_len, qd->File_invf);
+
+      /* Read from the buffer */
+      DECODE_START (buffer, we->invf_len);
+
+      WordLog = log ((double) num_docs / (double) we->max_doc_count);  /* [RPAP - Jan 97: Stem Index Change] */
+
+      Wqt = (rqi->QueryFreqs ? Terms->TE[j].Count : 1) * WordLog;
+
+      qd->num_of_terms++;
+
+      if (rqi->MaxAccums != -1 && Doc_Set->no_of_items >= rqi->MaxAccums)
+	{
+	  MoreAccum = 0;
+	  Anding = 1;
+	  next = SP_get_first (Doc_Set);
+	}
+      i = pos = 0;
+      next_i = next_start = next_doc_num = 0;
+      kd = k - 1;
+      while (i < p && (!Anding || next))
+	{
+	  int Count;		/* The number of times the occurs in a document */
+	  double Wdt;
+	  unsigned long diff;
+	  Invf_Doc_Entry ent, *mem;
+	  if (k)
+	    {
+	      if (Anding && i + k < p && next->DocNum > next_doc_num &&
+		  next_doc_num >= 0)
+		{
+		  i = next_i;
+		  DECODE_SEEK (next_start);
+		  pos = next_start;
+		  CurrDocNum = next_doc_num;
+		  qd->hops_taken++;
+		  skips_taken++;
+		  kd = k - 1;
+		}
+	      if (kd == k - 1)
+		if (i + k < p)
+		  {
+		    int doc_diff, pos_diff;
+		    BBLOCK_DECODE_L (doc_diff, dn_blk, pos);
+		    next_doc_num += doc_diff;
+		    next_i += k;
+		    BBLOCK_DECODE_L (pos_diff, len_blk, pos);
+		    next_start = pos + pos_diff;
+		  }
+		else
+		  next_doc_num = -1;
+	      if (Anding && i + k < p && next->DocNum > next_doc_num &&
+		  next_doc_num >= 0)
+		continue;
+	    }
+	  if (k && kd == 0 && i != p - 1)
+	    CurrDocNum = next_doc_num;
+	  else
+	    {
+	      BBLOCK_DECODE_L (diff, blk, pos);
+	      CurrDocNum += diff;
+	    }
+	  qd->num_of_ptrs++;
+	  ptrs_dec++;
+	  if (qd->id->ifh.InvfLevel >= 2)
+	    GAMMA_DECODE_L (Count, pos);
+	  else
+	    Count = (double) we->count / p;
+	  i++;
+	  kd--;
+	  if (kd < 0)
+	    kd = k - 1;
+	  Wdt = Count * WordLog;
+
+
+	  if (Anding)
+	    {
+	      while (next && next->DocNum < CurrDocNum - 1)
+		next = SP_get_next (Doc_Set);
+	      if (next && next->DocNum == CurrDocNum - 1)
+		{
+		  next->Sum += Wqt * Wdt;
+		  total_added += Wqt * Wdt;
+		  hits++;
+		}
+	      if (next && next->DocNum <= CurrDocNum - 1)
+		next = SP_get_next (Doc_Set);
+	      goto NextDocNum;
+	    }
+	  ent.DocNum = CurrDocNum - 1;
+	  if ((mem = SP_member (&ent, Doc_Set)) == NULL)
+	    {
+	      hits++;
+	      if (rqi->MaxAccums != -1 &&
+		  Doc_Set->no_of_items >= rqi->MaxAccums &&
+		  !MoreAccum)
+		goto NextDocNum;
+	      if ((mem = get_ide (qd, pool)) == NULL)
+		return NULL;
+	      ChangeMemInUse (qd, sizeof (*mem));
+	      mem->DocNum = CurrDocNum - 1;
+	      mem->Sum = 0;
+	      ChangeMemInUse (qd, -Doc_Set->mem_in_use);
+	      if (SP_insert (mem, Doc_Set) == NULL)
+		{
+		  Message ("Unable to allocate memory for a splay node");
+		  Abort = 1;
+		  goto FastAbort;
+		}
+	      ChangeMemInUse (qd, Doc_Set->mem_in_use);
+	      if (rqi->MaxAccums != -1 &&
+		  Doc_Set->no_of_items >= rqi->MaxAccums &&
+		  rqi->StopAtMaxAccum)
+		Abort = 1;
+	    }
+
+	  mem->Sum += Wqt * Wdt;
+	  total_added += Wqt * Wdt;
+
+	NextDocNum:
+	  ;
+	}
+
+    FastAbort:
+
+      DECODE_DONE
+
+	Xfree (buffer);
+      ChangeMemInUse (qd, -we->invf_len);
+      if (sk)
+	{
+	  if (qd->id->ifh.skip_mode != 0)
+	    fprintf (sk, " %6d", skips_taken);
+	  fprintf (sk, " %6d %6d %6d%12.2f\n",
+		   ptrs_dec, hits, Doc_Set->no_of_items, total_added);
+	}
+      if (Abort)
+	break;
+    }
+  if (sk)
+    fclose (sk);
+  return Doc_Set;
+}
+
+
+
+
+Hash_Table *
+CosineDecodeHash (query_data * qd, TermList * Terms,
+		  RankedQueryInfo * rqi)
+{
+  int j, num_docs, num_terms, MoreAccum;
+  Hash_Table *HT;
+  int Anding = 0;
+  int Sorted = 0;
+  FILE *sk = open_skip (rqi->skip_dump);
+  u_char indent = 0;
+  if (sk)
+    {
+      if (!skip_header)
+	{
+	  skip_header = 1;
+	  fprintf (sk, "%s", skip_header_text[qd->id->ifh.skip_mode]);
+	  fprintf (sk, "\nSkipping method %ld\n", qd->id->ifh.skip_mode);
+	  switch (qd->id->ifh.skip_mode)
+	    {
+	    case 1:
+	      fprintf (sk, "Skipping is every %ld docnums\n",
+		       qd->id->ifh.params[0]);
+	      break;
+	    case 2:
+	      fprintf (sk, "Max nodes = %ld\nNo skips smaller or equal to %ld\n",
+		       qd->id->ifh.params[0], qd->id->ifh.params[1]);
+	      break;
+	    }
+	}
+      fprintf (sk, "\n\t\t\t-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-\n\n");
+      for (j = 0; j < Terms->num; j++)
+	if (Terms->TE[j].Word[0] > indent)
+	  indent = Terms->TE[j].Word[0];
+    }
+
+  num_docs = qd->sd->sdh.num_of_docs;
+  /* Create the array for the documents */
+  HT = HT_create (qd, rqi->MaxAccums, rqi->HashTblSize);
+  if (!HT)
+    return NULL;
+
+  if (rqi->MaxTerms == -1)
+    num_terms = Terms->num;
+  else
+    num_terms = rqi->MaxTerms < Terms->num ? rqi->MaxTerms : Terms->num;
+
+  MoreAccum = 1;
+
+  /* For each word in the list . . . */
+  for (j = 0; j < num_terms; j++)
+    {
+      int Abort = 0;
+      u_char *buffer;
+      int pos;
+      int i;
+      unsigned long CurrDocNum = 0;	/* NOTE: Document numbers start at 1 */
+      double Wqt, WordLog;
+      int dn_blk = 0, len_blk = 0, k, kd;
+      int blk;			/* bblock control parameter */
+      int p;			/* The number of documents the word occurs in */
+      WordEntry *we = &Terms->TE[j].WE;
+      Invf_Doc_EntryH *next = NULL;
+      int next_i, next_doc_num, next_start;
+      int skips_taken = 0, ptrs_dec = 0;
+      double total_added = 0.0;
+      int hits = 0;
+      if (sk)
+	{
+	  fprintf (sk, "%3d : %8ld %6ld \"%.*s\"%*s", j, we->count,
+		 we->doc_count, Terms->TE[j].Word[0], Terms->TE[j].Word + 1,
+		   indent - Terms->TE[j].Word[0], "");
+	}
+
+      CalcBlks (qd, we, &blk, &dn_blk, &len_blk, &k, &p);
+      if (!(buffer = Xmalloc (we->invf_len)))
+	break;
+
+      ChangeMemInUse (qd, we->invf_len);
+
+      if (sk && qd->id->ifh.skip_mode == 2)
+	fprintf (sk, "%4d", k);
+
+      Fseek (qd->File_invf, we->invf_ptr, 0);
+      Fread (buffer, sizeof (char), we->invf_len, qd->File_invf);
+
+      /* Read from the buffer */
+      DECODE_START (buffer, we->invf_len);
+
+      WordLog = log ((double) num_docs / (double) we->max_doc_count);  /* [RPAP - Jan 97: Stem Index Change] */
+
+      Wqt = (rqi->QueryFreqs ? Terms->TE[j].Count : 1) * WordLog;
+
+      qd->num_of_terms++;
+
+      if (rqi->MaxAccums != -1 && HT->num >= rqi->MaxAccums)
+	{
+	  MoreAccum = 0;
+	  Anding = 1;
+	  if (!Sorted)
+	    {
+	      HT_sort (qd, HT);
+	      Sorted = 1;
+	    }
+	  next = HT->Head;
+	}
+      i = pos = 0;
+      next_i = next_start = next_doc_num = 0;
+      kd = k - 1;
+      while (i < p && (!Anding || next))
+	{
+	  int Count;		/* The number of times the occurs in a document */
+	  double Wdt;
+	  unsigned long diff;
+	  Invf_Doc_Entry *mem;
+	  if (k)
+	    {
+	      if (Anding && i + k < p && next->IDE.DocNum > next_doc_num &&
+		  next_doc_num >= 0)
+		{
+#ifdef SHORT_CUT
+		ShortCut:
+#endif
+		  i = next_i;
+		  DECODE_SEEK (next_start);
+		  pos = next_start;
+		  CurrDocNum = next_doc_num;
+		  qd->hops_taken++;
+		  skips_taken++;
+		  kd = k - 1;
+		}
+	      if (kd == k - 1)
+		{
+		  if (i + k < p)
+		    {
+		      int doc_diff, pos_diff;
+		      BBLOCK_DECODE_L (doc_diff, dn_blk, pos);
+		      next_doc_num += doc_diff;
+		      next_i += k;
+		      BBLOCK_DECODE_L (pos_diff, len_blk, pos);
+		      next_start = pos + pos_diff;
+		    }
+		  else
+		    next_doc_num = -1;
+		}
+#ifdef SHORT_CUT
+	      if (Anding && i + k < p && next->IDE.DocNum > next_doc_num &&
+		  next_doc_num >= 0)
+		goto ShortCut;
+#else
+	      if (Anding && i + k < p && next->IDE.DocNum > next_doc_num &&
+		  next_doc_num >= 0)
+		continue;
+#endif
+	    }
+	  if (k && kd == 0 && i != p - 1)
+	    {
+	      CurrDocNum = next_doc_num;
+	    }
+	  else
+	    {
+	      BBLOCK_DECODE_L (diff, blk, pos);
+	      CurrDocNum += diff;
+	    }
+	  qd->num_of_ptrs++;
+	  ptrs_dec++;
+	  if (qd->id->ifh.InvfLevel >= 2)
+	    GAMMA_DECODE_L (Count, pos);
+	  else
+	    Count = (double) we->count / p;
+	  i++;
+	  kd--;
+	  if (kd < 0)
+	    kd = k - 1;
+
+
+	  if (Anding)
+	    {
+	      while (next && next->IDE.DocNum < CurrDocNum - 1)
+		next = next->next;
+	      if (next && next->IDE.DocNum == CurrDocNum - 1)
+		{
+		  Wdt = Count * WordLog;
+		  next->IDE.Sum += Wqt * Wdt;
+		  total_added += Wqt * Wdt;
+		  hits++;
+		}
+	      if (next && next->IDE.DocNum <= CurrDocNum - 1)
+		next = next->next;
+	      goto NextDocNum;
+	    }
+	  if ((mem = HT_find (HT, CurrDocNum - 1)) == NULL)
+	    {
+	      if (rqi->MaxAccums != -1 && HT->num >= rqi->MaxAccums &&
+		  !MoreAccum)
+		goto NextDocNum;
+	      Wdt = Count * WordLog;
+	      if (!HT_insert (HT, CurrDocNum - 1, Wqt * Wdt))
+		{
+		  if (!HT->Suplimentary_Entries)
+		    HT_Sup_create (qd, HT, we->doc_count - i + 1);
+		  HT_Sup_Add (HT, CurrDocNum - 1, Wqt * Wdt);
+		}
+	      if (rqi->MaxAccums != -1 && HT->num >= rqi->MaxAccums &&
+		  rqi->StopAtMaxAccum)
+		Abort = 1;
+	    }
+	  else
+	    {
+	      Wdt = Count * WordLog;
+	      mem->Sum += Wqt * Wdt;
+	      total_added += Wqt * Wdt;
+	      hits++;
+	    }
+
+	NextDocNum:
+	  ;
+	}
+
+      DECODE_DONE
+
+	Xfree (buffer);
+      ChangeMemInUse (qd, -we->invf_len);
+      if (sk)
+	{
+	  if (qd->id->ifh.skip_mode != 0)
+	    fprintf (sk, " %6d", skips_taken);
+	  fprintf (sk, " %6d %6d %6d%12.2f\n",
+	       ptrs_dec, hits, HT->num + HT->Suplimentary_Num, total_added);
+	}
+      if (Abort)
+	break;
+    }
+  if (sk)
+    fclose (sk);
+  if (!HT->Head)
+    HT_sort (qd, HT);
+  return HT;
+}
+
+
+
+List_Table *
+CosineDecodeList (query_data * qd, TermList * Terms,
+		  RankedQueryInfo * rqi)
+{
+  int j, num_docs, num_terms, MoreAccum;
+  List_Table *LT;
+  int Anding = 0;
+  int Sorted = 0;
+  int has_grown = 0; /* [RJM 07/97: Ranked Required Match] whether elements have been added lately */
+  FILE *sk = open_skip (rqi->skip_dump);
+  u_char indent = 0;
+  if (sk)
+    {
+      if (!skip_header)
+	{
+	  skip_header = 1;
+	  fprintf (sk, "%s", skip_header_text[qd->id->ifh.skip_mode]);
+	  fprintf (sk, "\nSkipping method %ld\n", qd->id->ifh.skip_mode);
+	  switch (qd->id->ifh.skip_mode)
+	    {
+	    case 1:
+	      fprintf (sk, "Skipping is every %ld docnums\n",
+		       qd->id->ifh.params[0]);
+	      break;
+	    case 2:
+	      fprintf (sk, "Max nodes = %ld\nNo skips smaller or equal to %ld\n",
+		       qd->id->ifh.params[0], qd->id->ifh.params[1]);
+	      break;
+	    }
+	}
+      fprintf (sk, "\n\t\t\t-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-\n\n");
+      for (j = 0; j < Terms->num; j++)
+	if (Terms->TE[j].Word[0] > indent)
+	  indent = Terms->TE[j].Word[0];
+    }
+
+  num_docs = qd->sd->sdh.num_of_docs;
+
+  /* Create the list for the documents */
+  LT = LT_create (qd, rqi->MaxAccums);
+  if (!LT)
+    return NULL;
+
+  if (rqi->MaxTerms == -1)
+    num_terms = Terms->num;
+  else
+    num_terms = rqi->MaxTerms < Terms->num ? rqi->MaxTerms : Terms->num;
+
+  MoreAccum = 1;
+
+  /* For each word in the list . . . */
+  for (j = 0; j < num_terms; j++)
+    {
+      int Abort = 0;
+      u_char *buffer;
+      int pos;
+      int i, n = 0;
+      unsigned long CurrDocNum = 0;	/* NOTE: Document numbers start at 1 */
+      unsigned long LastDocNum = 0;	/* [RJM 07/97: Ranked Required Match] */
+      int this_item = 0; /* [RJM 07/97: Ranked Required Match] points to the next possible LT to delete */
+      double Wqt, WordLog;
+      int dn_blk = 0, len_blk = 0, k, kd;
+      int blk;			/* bblock control parameter */
+      int p;			/* The number of documents the word occurs in */
+      int require_match = Terms->TE[j].require_match; /* [RJM 07/97: Ranked Required Match] */
+      WordEntry *we = &Terms->TE[j].WE;
+      Invf_Doc_Entry *next = NULL;
+      int next_i, next_doc_num, next_start;
+      int skips_taken = 0, ptrs_dec = 0;
+      double total_added = 0.0;
+      int hits = 0;
+
+      if (sk)
+	{
+	  fprintf (sk, "%3d : %8ld %6ld \"%.*s\"%*s", j, we->count,
+		 we->doc_count, Terms->TE[j].Word[0], Terms->TE[j].Word + 1,
+		   indent - Terms->TE[j].Word[0], "");
+	}
+
+      CalcBlks (qd, we, &blk, &dn_blk, &len_blk, &k, &p);
+      if (!(buffer = Xmalloc (we->invf_len)))
+	break;
+
+      ChangeMemInUse (qd, we->invf_len);
+
+      if (sk && qd->id->ifh.skip_mode == 2)
+	fprintf (sk, "%4d", k);
+
+      Fseek (qd->File_invf, we->invf_ptr, 0);
+      Fread (buffer, sizeof (char), we->invf_len, qd->File_invf);
+
+      /* Read from the buffer */
+      DECODE_START (buffer, we->invf_len);
+
+      WordLog = log ((double) num_docs / (double) we->max_doc_count);  /* [RPAP - Jan 97: Stem Index Change] */
+
+      Wqt = (rqi->QueryFreqs ? Terms->TE[j].Count : 1) * WordLog;
+
+      qd->num_of_terms++;
+
+      if (rqi->MaxAccums != -1 && LT->num >= rqi->MaxAccums)
+	MoreAccum = 0;
+
+      if ((rqi->MaxAccums != -1 && LT->num >= rqi->MaxAccums) || Anding)
+	{
+	  Anding = 1;
+	  if (!Sorted || has_grown)
+	    {
+	      LT_sort (LT);
+	      LT_pack (LT);
+	      Sorted = 1;
+	      has_grown = 0;
+	    }
+	  next = LT->IDE;
+	  n = 0;
+	}
+
+      /* [RJM 07/97: Ranked Required Terms] */
+      /* make sure that the document list is set up correctly for */
+      /* requiring a term to match */
+      if (require_match == 1) {
+	if (!Sorted || has_grown) {
+	  LT_sort (LT);
+	  LT_pack (LT);
+	  Sorted = 1;
+	  has_grown = 0;
+	}
+	/* this_item is already set to zero */
+      }
+
+      i = pos = 0;
+      next_i = next_start = next_doc_num = 0;
+      kd = k - 1;
+      while (i < p && (!Anding || n < LT->num))
+	{
+	  int Count;		/* The number of times the occurs in a document */
+	  double Wdt;
+	  unsigned long diff;
+	  Invf_Doc_Entry *mem;
+
+	  /* deal with skipping */
+	  if (k)
+	    {
+	      /* see if we should take a skip */
+	      if (Anding && i + k < p && next->DocNum > next_doc_num &&
+		  next_doc_num >= 0)
+		{
+		  i = next_i;
+		  DECODE_SEEK (next_start);
+		  pos = next_start;
+		  CurrDocNum = next_doc_num;
+		  qd->hops_taken++;
+		  skips_taken++;
+		  kd = k - 1;
+		}
+	      if (kd == k - 1)
+		if (i + k < p)
+		  {
+		    int doc_diff, pos_diff;
+		    BBLOCK_DECODE_L (doc_diff, dn_blk, pos);
+		    next_doc_num += doc_diff;
+		    next_i += k;
+		    BBLOCK_DECODE_L (pos_diff, len_blk, pos);
+		    next_start = pos + pos_diff;
+		  }
+		else
+		  next_doc_num = -1;
+
+	      /* should we take another skip? */
+	      if (Anding && i + k < p && next->DocNum > next_doc_num &&
+		  next_doc_num >= 0)
+		continue;
+	    }
+	  if (k && kd == 0 && i != p - 1)
+	    CurrDocNum = next_doc_num;
+	  else
+	    {
+	      BBLOCK_DECODE_L (diff, blk, pos);
+	      CurrDocNum += diff;
+	    }
+	  qd->num_of_ptrs++;
+	  ptrs_dec++;
+	  if (qd->id->ifh.InvfLevel >= 2)
+	    GAMMA_DECODE_L (Count, pos);
+	  else
+	    Count = (double) we->count / p;
+	  i++;
+	  kd--;
+	  if (kd < 0)
+	    kd = k - 1;
+	  Wdt = Count * WordLog;
+
+	  /* [RJM 07/97: Ranked Required Terms] */
+	  /* if this is a required match we must remove all accumulators */
+	  /* of intermediate documents */
+	  if (require_match == 1) {
+	    while (this_item < LT->num && LT->IDE[this_item].DocNum < CurrDocNum - 1) {
+	      if (LT->IDE[this_item].DocNum > LastDocNum - 1)
+		LT->IDE[this_item].Sum = -1000.0; /* mark for deletion */
+	      this_item++;
+	    }
+	  }
+
+	  if (Anding)
+	    {
+	      while (n < LT->num && next->DocNum < CurrDocNum - 1)
+		{
+		  next++;
+		  n++;
+		}
+	      if (n < LT->num && next->DocNum == CurrDocNum - 1)
+		{
+		  next->Sum += Wqt * Wdt;
+		  total_added += Wqt * Wdt;
+		  hits++;
+		}
+	      if (n < LT->num && next->DocNum <= CurrDocNum - 1)
+		{
+		  next++;
+		  n++;
+		}
+	      goto NextDocNum;
+	    }
+	  if (!Anding)
+	    {
+	      if (rqi->MaxAccums != -1 && LT->num >= rqi->MaxAccums &&
+		  !MoreAccum)
+		goto NextDocNum;
+	      LT = LT_add (qd, LT, CurrDocNum - 1, Wqt * Wdt);
+	      if (!LT)
+		{
+		  Abort = 1;
+		  goto FastAbort;
+		}
+
+	      /* the list of accumulators just got bigger */
+	      has_grown = 1;
+
+	      if (rqi->MaxAccums != -1 && LT->num >= rqi->MaxAccums &&
+		  rqi->StopAtMaxAccum)
+		Abort = 1;
+
+
+	    }
+	  else if ((mem = LT_find (LT, CurrDocNum - 1)))
+	    {
+	      mem->Sum += Wqt * Wdt;
+	      total_added += Wqt * Wdt;
+	      hits++;
+	    }
+
+	NextDocNum:
+
+	  LastDocNum = CurrDocNum;
+	}
+
+    FastAbort:
+
+      DECODE_DONE
+
+	Xfree (buffer);
+      ChangeMemInUse (qd, -we->invf_len);
+      if (sk)
+	{
+	  if (qd->id->ifh.skip_mode != 0)
+	    fprintf (sk, " %6d", skips_taken);
+	  fprintf (sk, " %6d %6d %6d%12.2f\n",
+		   ptrs_dec, hits, LT->num, total_added);
+	}
+      if (Abort)
+	break;
+
+      /* [RJM 07/97: Ranked Required Terms] */
+      /* remove the remaining accumulators if this term is required to match */
+      if (require_match == 1) {
+	while (this_item < LT->num) {
+	  if (LT->IDE[this_item].DocNum > LastDocNum - 1)
+	    LT->IDE[this_item].Sum = -1000.0; /* mark for deletion */
+	  this_item++;
+	}
+	Anding = 1; /* no more documents should be added */
+
+	/* Get rid of any documents which have been deleted */
+	LT_pack (LT);
+      }
+    }
+
+  if (sk)
+    fclose (sk);
+  return LT;
+}
Index: /main/tags/2.25/gsdl/packages/mg/src/text/invf_get.h
===================================================================
--- /main/tags/2.25/gsdl/packages/mg/src/text/invf_get.h	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/mg/src/text/invf_get.h	(revision 21064)
@@ -0,0 +1,103 @@
+/**************************************************************************
+ *
+ * invf_get.h -- Inverted file reading routines
+ * Copyright (C) 1994  Neil Sharman
+ *
+ * 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.
+ *
+ * $Id$
+ *
+ **************************************************************************/
+
+
+#ifndef H_INVF_GET
+#define H_INVF_GET
+
+typedef struct Invf_Doc_Entry
+  {
+    int DocNum;
+    float Sum;
+  }
+Invf_Doc_Entry;
+
+typedef struct Invf_Doc_Entry_Pool
+  {
+    void *pool;
+    unsigned pool_chunks;
+  }
+Invf_Doc_Entry_Pool;
+
+typedef struct Invf_Doc_EntryH
+  {
+    Invf_Doc_Entry IDE;
+    struct Invf_Doc_EntryH *next;
+  }
+Invf_Doc_EntryH;
+
+typedef struct Hash_Table
+  {
+    Invf_Doc_EntryH *Suplimentary_Entries;
+    int Suplimentary_Size;
+    int Suplimentary_Num;
+    unsigned max;
+    unsigned num;
+    unsigned size;
+    Invf_Doc_EntryH **HashTable;
+    Invf_Doc_EntryH *Head;
+    Invf_Doc_EntryH IDEH[1];
+  }
+Hash_Table;
+
+typedef struct List_Table
+  {
+    unsigned max;
+    unsigned num;
+    Invf_Doc_Entry IDE[1];
+  }
+List_Table;
+
+typedef enum
+  {
+    op_term, op_and_terms, op_and_or_terms, op_diff_terms
+  }
+Op_types;
+
+/*Invf_Doc_Entry *HT_find(Hash_Table *HT, unsigned long DN); */
+void HT_free (query_data * qd, Hash_Table * HT);
+void LT_free (query_data * qd, List_Table * LT);
+
+invf_data *InitInvfFile (File * InvfFile, stemmed_dict * sd);
+void FreeInvfData (invf_data * id);
+
+DocList *GetDocs (query_data * qd, WordEntry * we, BooleanQueryInfo * bqi);
+
+float *CosineDecode (query_data * qd, TermList * Terms, RankedQueryInfo * rqi);
+
+void free_ide_pool (query_data * qd, Invf_Doc_Entry_Pool * pool);
+
+Splay_Tree *CosineDecodeSplay (query_data * qd, TermList * Terms,
+			 RankedQueryInfo * rqi, Invf_Doc_Entry_Pool * pool);
+
+Hash_Table *CosineDecodeHash (query_data * qd, TermList * Terms,
+			      RankedQueryInfo * rqi);
+List_Table *CosineDecodeList (query_data * qd, TermList * Terms,
+			      RankedQueryInfo * rqi);
+
+
+DocList *GetDocsOp (query_data * qd, WordEntry * we, Op_types op, DocList * L);
+
+
+
+#endif
Index: /main/tags/2.25/gsdl/packages/mg/src/text/ivf.pass1.c
===================================================================
--- /main/tags/2.25/gsdl/packages/mg/src/text/ivf.pass1.c	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/mg/src/text/ivf.pass1.c	(revision 21064)
@@ -0,0 +1,796 @@
+/**************************************************************************
+ *
+ * ivf.pass1.c -- Memory efficient pass 1 inversion
+ * Copyright (C) 1994  Neil Sharman
+ *
+ * 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.
+ *
+ * $Id$
+ *
+ **************************************************************************/
+
+#include "sysfuncs.h"
+
+#include "memlib.h"
+#include "messages.h"
+#include "bitio_m.h"
+#include "bitio_m_stdio.h"
+#include "bitio_gen.h"
+#include "local_strings.h"
+#include "netorder.h"  /* [RPAP - Jan 97: Endian Ordering] */
+
+#include "mg_files.h"
+#include "invf.h"
+#include "mg.h"
+#include "build.h"
+#include "locallib.h"
+#include "words.h"
+#include "stemmer.h"
+#include "hash.h"
+
+
+/*
+   $Log$
+   Revision 1.1  1999/08/10 21:17:54  sjboddie
+   renamed mg-1.3d directory mg
+
+   Revision 1.3  1998/12/17 09:12:50  rjmcnab
+
+   Altered mg to process utf-8 encoded Unicode. The main changes
+   are in the parsing of the input, the casefolding, and the stemming.
+
+   Revision 1.2  1998/11/25 07:55:43  rjmcnab
+
+   Modified mg to that you can specify the stemmer you want
+   to use via a command line option. You specify it to
+   mg_passes during the build process. The number of the
+   stemmer that you used is stored within the inverted
+   dictionary header and the stemmed dictionary header so
+   the correct stemmer is used in later stages of building
+   and querying.
+
+   Revision 1.1  1998/11/17 09:34:44  rjmcnab
+   *** empty log message ***
+
+   * Revision 1.6  1995/01/16  03:57:05  tes
+   * Fixed bug for index_string_bytes which was calculated
+   * by adding the suffix lengths except for every lookback (block)
+   * number of words. This was incorrect as invf.dict is fully
+   * front coded - perhaps it was partially coded in the past.
+   * This would only affect a statistic - hence the reason why the
+   * bug could exist ;-)
+   *
+   * Revision 1.5  1994/11/29  00:31:59  tes
+   * Committing the new merged files and changes.
+   *
+   * Revision 1.3  1994/10/20  03:56:48  tes
+   * I have rewritten the boolean query optimiser and abstracted out the
+   * components of the boolean query.
+   *
+   * Revision 1.2  1994/09/20  04:41:34  tes
+   * For version 1.1
+   *
+ */
+
+static char *RCSID = "$Id$";
+
+#define LOGLOOKBACK	2
+#define POOL_SIZE 1024*1024
+#define HASH_POOL_SIZE 8192
+#define INITIAL_HASH_SIZE 7927
+
+#define INIT_CHECK_FRAC 0.10
+#define CHECK_FRAC 0.75
+#define CHECK_CLOSE 0.999
+#define PARA_DIV 1.5
+#define NORM_DIV 1.0
+
+
+typedef struct hash_rec
+  {
+    unsigned long fcnt;		/* fragment frequency */
+    unsigned long lfcnt;	/* local fragment frequency */
+    unsigned long fnum;		/* last fragment to use stem */
+    unsigned long wcnt;		/* stem frequency */
+    unsigned long lwcnt;	/* local stem frequency */
+    u_char *word;
+  }
+hash_rec;
+
+
+
+
+
+
+
+
+static unsigned long words_read = 0, words_diff = 0, bytes_diff = 0;
+static unsigned long outputbytes = 0;
+static double inputbytes = 0; /* [RJM 07/97: 4G limit] */
+static unsigned long MaxMemInUse = 0;
+static unsigned long MemInUse = 0;
+static unsigned long ChunksWritten = 0;
+
+
+static FILE *ic;		/* The invf block file */
+static stdio_bitio_state sbs;
+
+static hash_rec **HashTable;
+static unsigned long HashSize;
+static unsigned long HashUsed;
+static u_char *Pool;
+static int PoolLeft;
+
+static hash_rec *hr_pool;
+static int hr_PoolLeft;
+
+static hash_rec **first_occr;
+static int max_first_occr;
+
+static unsigned long L1_bits = 0, L1_ohead = 0;
+static unsigned long L2_bits = 0, L2_ohead = 0;
+static unsigned long L3_bits = 0, L3_ohead = 0;
+static unsigned long callnum = 0, lcallnum = 0, wordnum = 0, lwordnum = 0;
+static unsigned long ptrcnt = 0;
+static unsigned long checknum;
+static long max_mem = 0;
+
+
+static void 
+ChangeMem (int Change)
+{
+  MemInUse += Change;
+  if (MemInUse > MaxMemInUse)
+    MaxMemInUse = MemInUse;
+}
+
+
+
+int 
+init_ivf_1 (char *file_name)
+{
+  if (!(ic = create_file (file_name, INVF_CHUNK_SUFFIX, "wb", MAGIC_CHUNK,
+			  MG_MESSAGE)))  /* [RPAP - Feb 97: WIN32 Port] */
+    return (COMPERROR);
+  fwrite ("    ", sizeof (u_long), 1, ic);	/* Space for the maxmem */
+  ENCODE_START (ic)
+    ENCODE_PAUSE (sbs)
+
+    if (!(Pool = Xmalloc (POOL_SIZE)))
+    {
+      Message ("Unable to allocate memory for pool");
+      return (COMPERROR);
+    }
+  PoolLeft = POOL_SIZE;
+  ChangeMem (POOL_SIZE);
+
+  if (!(hr_pool = Xmalloc (HASH_POOL_SIZE * sizeof (hash_rec))))
+    {
+      Message ("Unable to allocate memory for pool");
+      return (COMPERROR);
+    }
+  hr_PoolLeft = HASH_POOL_SIZE;
+  ChangeMem (HASH_POOL_SIZE * sizeof (hash_rec));
+
+  HashSize = INITIAL_HASH_SIZE;
+  HashUsed = 0;
+  if (!(HashTable = Xmalloc (sizeof (hash_rec *) * HashSize)))
+    {
+      Message ("Unable to allocate memory for table");
+      return (COMPERROR);
+    }
+  ChangeMem (sizeof (hash_rec *) * HashSize);
+  bzero ((char *) HashTable, sizeof (hash_rec *) * HashSize);
+  max_first_occr = 8192;
+  if (!(first_occr = Xmalloc (sizeof (hash_rec *) * max_first_occr)))
+    {
+      Message ("Unable to allocate memory for first_occur");
+      return (COMPERROR);
+    }
+  ChangeMem (sizeof (hash_rec *) * max_first_occr);
+
+  checknum = (invf_buffer_size * INIT_CHECK_FRAC) /
+    (InvfLevel == 3 ? PARA_DIV : NORM_DIV);
+
+  return (COMPALLOK);
+}
+
+
+
+static unsigned long 
+mem_reqd (void)
+{
+  register int i;
+  register unsigned long total = 0;
+/*  register unsigned long N = InvfLevel == 3 ? lwordnum : lcallnum; */
+  register unsigned long N = lcallnum;
+  for (i = 0; i < HashUsed; i++)
+    {
+      register hash_rec *ent = first_occr[i];
+/*      register unsigned long p = InvfLevel == 3 ? ent->lwcnt : ent->lfcnt; */
+      register unsigned long p = ent->lfcnt;
+      if (p)
+	total += BIO_Bblock_Bound (N, p);
+      if (InvfLevel >= 2)
+	total += ent->lwcnt;
+    }
+
+  total = (total + 7) >> 3;
+  return total;
+}
+
+static unsigned long 
+max_mem_reqd (void)
+{
+  register int i;
+  register unsigned long total = 0;
+/*  register unsigned long N = InvfLevel == 3 ? wordnum : callnum; */
+  register unsigned long N = callnum;
+  for (i = 0; i < HashUsed; i++)
+    {
+      register hash_rec *ent = first_occr[i];
+/*      register unsigned long p = InvfLevel == 3 ? ent->wcnt : ent->fcnt; */
+      register unsigned long p = ent->fcnt;
+      if (p)
+	total += BIO_Bblock_Bound (N, p);
+      if (InvfLevel >= 2)
+	total += ent->wcnt;
+    }
+
+  total = (total + 7) >> 3;
+  return total;
+}
+
+
+static void 
+dump_dict (unsigned long mem)
+{
+  int i;
+
+  ChunksWritten++;
+
+  ENCODE_CONTINUE (sbs)
+
+    GAMMA_ENCODE (lcallnum + 1);
+  if (mem > max_mem)
+    max_mem = mem;
+  GAMMA_ENCODE (mem + 1);
+  lwordnum = lcallnum = 0;
+  GAMMA_ENCODE (HashUsed + 1);
+  for (i = 0; i < HashUsed; i++)
+    {
+      hash_rec *ent = first_occr[i];
+      GAMMA_ENCODE (ent->lwcnt + 1);
+      if (ent->lwcnt >= 2)
+	GAMMA_ENCODE (ent->lfcnt);
+      ent->lwcnt = ent->lfcnt = 0;
+    }
+  ptrcnt = 0;
+  ENCODE_PAUSE (sbs)
+}
+
+
+
+static int 
+process_doc (u_char * s_in, int l_in)
+{
+  u_char *end = s_in + l_in - 1;
+
+  callnum++;
+  lcallnum++;
+  inputbytes += l_in;
+
+  if (!inaword (s_in, end))
+    if (SkipSGML)
+      PARSE_NON_STEM_WORD_OR_SGML_TAG (s_in, end);
+    else
+      PARSE_NON_STEM_WORD (s_in, end);
+  /*
+   ** Alternately parse off words and non-words from the input
+   ** stream beginning with a non-word. Each token is then
+   ** inserted into the set if it does not exist or has it's
+   ** frequency count incremented if it does.
+   */
+  while (s_in <= end)
+    {
+      u_char Word[MAXSTEMLEN + 1];
+
+      PARSE_STEM_WORD (Word, s_in, end);
+      
+      stemmer (stem_method, stemmer_num, Word);
+      if (SkipSGML)
+	PARSE_NON_STEM_WORD_OR_SGML_TAG (s_in, end);
+      else
+	PARSE_NON_STEM_WORD (s_in, end);
+
+      words_read++;
+      wordnum++;
+      lwordnum++;
+      /* Search the hash table for Word */
+      {
+	register unsigned long hashval, step;
+	register int hsize = HashSize;
+	HASH (hashval, step, Word, hsize);
+	for (;;)
+	  {
+	    register u_char *s1;
+	    register u_char *s2;
+	    register int len;
+	    register hash_rec *ent;
+	    ent = HashTable[hashval];
+	    if (!ent)
+	      {
+		int len = *Word + 1;
+		if (!hr_PoolLeft)
+		  {
+		    if (!(hr_pool = Xmalloc (HASH_POOL_SIZE *
+					     sizeof (hash_rec))))
+		      {
+			Message ("Unable to allocate memory for pool");
+			return (COMPERROR);
+		      }
+		    hr_PoolLeft = HASH_POOL_SIZE;
+		    ChangeMem (HASH_POOL_SIZE * sizeof (hash_rec));
+		  }
+		ent = hr_pool++;
+		hr_PoolLeft--;
+		if (len > PoolLeft)
+		  {
+		    if (!(Pool = Xmalloc (POOL_SIZE)))
+		      {
+			Message ("Unable to allocate memory for pool");
+			return (COMPERROR);
+		      }
+		    PoolLeft = POOL_SIZE;
+		    ChangeMem (POOL_SIZE);
+		  }
+		ent->wcnt = 1;
+		ent->fcnt = 1;
+		ent->lwcnt = 1;
+		ent->lfcnt = 1;
+		ent->fnum = callnum;
+		ent->word = Pool;
+		memcpy (Pool, Word, len);
+		Pool += len;
+		PoolLeft -= len;
+		if (HashUsed == max_first_occr - 1)
+		  {
+		    ChangeMem (-sizeof (hash_rec *) * max_first_occr);
+		    max_first_occr *= 2;
+		    if (!(first_occr = Xrealloc (first_occr, sizeof (hash_rec *) *
+						 max_first_occr)))
+		      {
+			Message ("Unable to allocate memory for first_occr");
+			return (COMPERROR);
+		      }
+		    ChangeMem (sizeof (hash_rec *) * max_first_occr);
+		  }
+		first_occr[HashUsed] = ent;
+		HashUsed++;
+		HashTable[hashval] = ent;
+		bytes_diff += Word[0];
+		break;
+	      }
+
+	    /* Compare the words */
+	    s1 = Word;
+	    s2 = ent->word;
+	    len = *s1 + 1;
+	    for (; len; len--)
+	      if (*s1++ != *s2++)
+		break;
+
+	    if (len)
+	      {
+		hashval = (hashval + step);
+		if (hashval >= hsize)
+		  hashval -= hsize;
+	      }
+	    else
+	      {
+		ent->wcnt++;
+		ent->lwcnt++;
+		if (callnum > ent->fnum)
+		  {
+		    ptrcnt++;
+		    ent->fcnt++;
+		    ent->lfcnt++;
+		    ent->fnum = callnum;
+		  }
+		break;
+	      }
+	  }
+      }
+
+      if (HashUsed >= HashSize >> 1)
+	{
+	  hash_rec **ht;
+	  unsigned long size;
+	  unsigned long i;
+	  size = prime (HashSize * 2);
+	  if (!(ht = Xmalloc (sizeof (hash_rec *) * size)))
+	    {
+	      Message ("Unable to allocate memory for table");
+	      return (COMPERROR);
+	    }
+	  bzero ((char *) ht, sizeof (hash_rec *) * size);
+	  ChangeMem (sizeof (hash_rec *) * size);
+
+	  for (i = 0; i < HashSize; i++)
+	    if (HashTable[i])
+	      {
+		register u_char *wptr;
+		hash_rec *ent;
+		register unsigned long hashval, step;
+
+		wptr = HashTable[i]->word;
+		HASH (hashval, step, wptr, size);
+		ent = ht[hashval];
+		while (ent)
+		  {
+		    hashval += step;
+		    if (hashval >= size)
+		      hashval -= size;
+		    ent = ht[hashval];
+		  }
+		ht[hashval] = HashTable[i];
+	      }
+	  Xfree (HashTable);
+	  ChangeMem (-sizeof (hash_rec *) * HashSize);
+	  HashTable = ht;
+	  HashSize = size;
+	}
+
+    }
+
+  if (ptrcnt >= checknum)
+    {
+      unsigned long mem;
+      /*fprintf(stderr, "Checking at %u . . . ", ptrcnt); */
+      mem = mem_reqd ();
+      if (mem >= invf_buffer_size * CHECK_CLOSE)
+	{
+	  /*fprintf(stderr, "Got a match\n"); */
+	  dump_dict (mem);
+	  checknum = (invf_buffer_size * INIT_CHECK_FRAC) /
+	    (InvfLevel == 3 ? PARA_DIV : NORM_DIV);
+	}
+      else
+	{
+	  checknum = checknum * ((CHECK_FRAC * (invf_buffer_size - mem)) / mem) +
+	    checknum;
+	  if (checknum <= ptrcnt)
+	    checknum = ptrcnt + 1;
+	  /*fprintf(stderr, "Next check at %u\n", checknum); */
+	}
+    }
+  return (COMPALLOK);
+
+}				/* encode */
+
+
+int 
+process_ivf_1 (u_char * s_in, int l_in)
+{
+  if (InvfLevel <= 2)
+    return process_doc (s_in, l_in);
+  else
+    {
+      int pos = 0;
+      u_char *start = s_in;
+      while (pos < l_in)
+	{
+	  if (s_in[pos] == TERMPARAGRAPH)
+	    {
+	      int len = pos + s_in + 1 - start;
+	      if (process_doc (start, len) != COMPALLOK)
+		return (COMPERROR);
+	      start = s_in + pos + 1;
+	    }
+	  pos++;
+	}
+      if (start < s_in + pos)
+	return process_doc (start, pos + s_in - start);
+    }
+  return COMPALLOK;
+}
+
+static int 
+PackHashTable (void)
+{
+  int s, d;
+  for (s = d = 0; s < HashSize; s++)
+    if (HashTable[s])
+      HashTable[d++] = HashTable[s];
+  ChangeMem (-sizeof (hash_rec *) * HashSize);
+  ChangeMem (sizeof (hash_rec *) * HashUsed);
+  if (!(HashTable = Xrealloc (HashTable, sizeof (hash_rec *) * HashUsed)))
+    {
+      Message ("Out of memory");
+      return COMPERROR;
+    }
+  HashSize = HashUsed;
+  return COMPALLOK;
+}
+
+
+
+
+
+static int 
+ent_comp (const void *A, const void *B)
+{
+  u_char *s1 = (*((hash_rec **) A))->word;
+  u_char *s2 = (*((hash_rec **) B))->word;
+
+  return (casecompare (s1, s2)); /* [RPAP - Jan 97: Stem Index Change] */
+}				/* stem_comp */
+
+
+
+
+
+/*
+ * void count_text()
+ *
+ * The maths used in this function is described in the paper "Coding for 
+ * Compression in Full-Text Retrieval Systems"
+ *
+ */
+static void 
+count_text ()
+{
+  int i;
+  for (i = 0; i < HashUsed; i++)
+    {
+      hash_rec *wrd = HashTable[i];
+      /* estimate size of a level 1 inverted file */
+      L1_bits += (int) (0.99 + wrd->fcnt * (1.6 + log2 (1.0 * callnum / wrd->fcnt)));
+      L1_ohead += BIO_Gamma_Length (wrd->fcnt);
+
+      L2_bits += BIO_Unary_Length (wrd->wcnt);
+      L2_ohead += BIO_Gamma_Length (wrd->wcnt - wrd->fcnt + 1);
+
+      L3_bits += (int) (0.99 + wrd->wcnt *
+		  (1.6 + log2 (1.0 * words_read / (wrd->wcnt + callnum))));
+      L3_ohead += 0;
+    }
+  L3_bits = (L3_bits + L2_bits + L1_bits + 7) / 8;
+  L3_ohead = (L3_ohead + L2_ohead + L1_ohead + 7) / 8;
+  L2_bits = (L2_bits + L1_bits + 7) / 8;
+  L2_ohead = (L2_ohead + L1_ohead + 7) / 8;
+  L1_bits = (L1_bits + 7) / 8;
+  L1_ohead = (L1_ohead + 7) / 8;
+}				/* count_text */
+
+
+
+/*
+ *    write_stem_file():
+ *              writes out the stemmed dictionary file
+ *              in the following format 
+ *                      lookback value (int)
+ *                      totalbytes value (int)
+ *                      indexstringbytes (int)
+ *                      for each word 
+ *                        wordlen (4 bits)
+ *                        prefix match (4 bits)
+ *                        word (wordlen bytes)
+ *                        word frequency (int)
+ *                        word count (int)
+ *
+ *      Accesses outside variables:     
+ *
+ *      Return value...:                
+ */
+
+static void 
+write_stem_file (char *file_name)
+{
+  long j;
+  struct invf_dict_header idh;
+  long lookback = (1 << LOGLOOKBACK);	/* ???? */
+  long totalbytes = 0;		/* The sum of the length of all words, including 
+				   the length byte */
+  long indexstringbytes = 0;	/* The amount of space required to store the 
+				   words in the diction, this takes into account 
+				   the prefixes */
+  u_char *lastword = NULL;	/* A pointer to the last word processed */
+  FILE *sp;
+
+
+  /* Calculate the size of certain things */
+  for (j = 0; j < HashSize; j++)
+    {
+      u_char *word = HashTable[j]->word;
+      indexstringbytes += word[0] + 2;
+      totalbytes += word[0] + 1;
+      if (lastword)
+	indexstringbytes -= prefixlen (lastword, word);
+      lastword = word;
+    }
+
+  lastword = NULL;
+
+  if (!(sp = create_file (file_name, INVF_DICT_SUFFIX, "wb", MAGIC_STEM_BUILD,
+			  MG_MESSAGE)))  /* [RPAP - Feb 97: WIN32 Port] */
+    return;
+
+  /* [RPAP - Jan 97: Endian Ordering] */
+  HTONUL2(lookback, idh.lookback);
+  HTONUL2(HashSize, idh.dict_size);
+  HTONUL2(totalbytes, idh.total_bytes);
+  HTONUL2(indexstringbytes, idh.index_string_bytes);
+  HTOND2(inputbytes, idh.input_bytes); /* [RJM 07/97: 4G limit] */
+  HTONUL2(callnum, idh.num_of_docs);
+  HTONUL2(callnum, idh.static_num_of_docs);
+  HTONUL2(words_read, idh.num_of_words);
+  HTONUL2(stemmer_num, idh.stemmer_num);
+  HTONUL2(stem_method, idh.stem_method);
+
+  fwrite ((char *) &idh, sizeof (idh), 1, sp);
+  outputbytes += sizeof (idh);
+
+  for (j = 0; j < HashSize; j++)
+    {
+      int i;
+      unsigned long wcnt, fcnt;  /* [RPAP - Jan 97: Endian Ordering] */
+      hash_rec *ent = HashTable[j];
+      if (lastword != NULL)
+	/* look for prefix match with prev string */
+	i = prefixlen (lastword, ent->word);
+      else
+	i = 0;
+      fputc (i, sp);
+      fputc (ent->word[0] - i, sp);
+      fwrite ((char *) ent->word + i + 1, sizeof (u_char), ent->word[0] - i, sp);
+      outputbytes += ent->word[0] - i + 1;
+
+      /* [RPAP - Jan 97: Endian Ordering] */
+      HTONUL2(ent->fcnt, fcnt);
+      fwrite ((char *) &(fcnt), sizeof (fcnt), 1, sp);
+
+      outputbytes += sizeof (ent->fcnt);
+
+      /* [RPAP - Jan 97: Endian Ordering] */
+      HTONUL2(ent->wcnt, wcnt);
+      fwrite ((char *) &(wcnt), sizeof (wcnt), 1, sp);
+
+      outputbytes += sizeof (ent->wcnt);
+      lastword = ent->word;
+    }
+
+  fclose (sp);
+}				/* write_stem_file() */
+
+
+
+/*
+ *    write_codes():
+ *              calls functions to assign and write out codes and
+ *              then prints out stats about execution results.
+ *
+ *      Accesses outside variables:     z
+ *
+ *      Return value...:                z
+ */
+
+static void 
+write_codes (char *file_name)
+{
+  unsigned long dicts = 0;
+  outputbytes = 0;
+  write_stem_file (file_name);
+  dicts = outputbytes;
+
+#ifndef SILENT
+  Message ("Chunks written      : %d\n",
+	   ChunksWritten);
+  if (InvfLevel == 3)
+    Message ("Paragraphs          : %8d\n", callnum);
+  Message ("Peak memory usage   : %10.1f Mb\n",
+	   (double) MaxMemInUse / 1024.0 / 1024.0);
+  Message ("Stems size          : %10.1f kB  %5.2f%%\n",
+	   (double) dicts / 1024, (double) 100 * dicts / inputbytes);
+  Message ("Lev 1 inverted file : %10.1f kB  %5.2f%%\n",
+	   (double) (L1_bits + L1_ohead) / 1024,
+	   (double) 100 * (L1_bits + L1_ohead) / inputbytes);
+  Message ("Lev 2 inverted file : %10.1f kB  %5.2f%%\n",
+	   (double) (L2_bits + L2_ohead) / 1024,
+	   (double) 100 * (L2_bits + L2_ohead) / inputbytes);
+  Message ("Lev 3 inverted file : %10.1f kB  %5.2f%%\n",
+	   (double) (L3_bits + L3_ohead) / 1024,
+	   (double) 100 * (L3_bits + L3_ohead) / inputbytes);
+  Message ("Record addresses    : %10.1f kB  %5.2f%%\n",
+	   (double) words_diff * 4 / 1024, (double) 100 * words_diff * 4 / inputbytes);
+#endif
+}				/* write_codes() */
+
+
+
+void 
+write_num_file (char *file_name)
+{
+
+  int i;
+  FILE *f;
+
+  for (i = 0; i < HashSize; i++)
+    HashTable[i]->fnum = i;
+
+  if (!(f = create_file (file_name, INVF_CHUNK_TRANS_SUFFIX, "wb",
+			 MAGIC_CHUNK_TRANS, MG_MESSAGE)))  /* [RPAP - Feb 97: WIN32 Port] */
+    return;
+
+#if 1
+  ENCODE_START (f)
+
+    for (i = 0; i < HashSize; i++)
+    BINARY_ENCODE (first_occr[i]->fnum + 1, HashSize + 1);
+
+  ENCODE_DONE;
+#else
+  for (i = 0; i < HashSize; i++)
+    {
+      /* [RPAP - Jan 97: Endian Ordering] */
+      unsigned long fnum;
+      HTONUL2(first_occur[i]->fnum, fnum);
+      fwrite ((char *) &fnum, sizeof (unsigned long), 1, f);
+    }
+#endif
+
+  fclose (f);
+}
+
+
+
+
+int 
+done_ivf_1 (char *FileName)
+{
+  char *temp_str = msg_prefix;
+  msg_prefix = "ivf.pass1";
+#ifndef SILENT
+  Message ("Mem reqd for 1 chunk: %8u bytes\n",
+	   max_mem_reqd ());
+#endif
+  if (lcallnum)
+    dump_dict (mem_reqd ());
+
+  if (PackHashTable () == COMPERROR)
+    return COMPERROR;
+
+  qsort (HashTable, HashUsed, sizeof (hash_rec *), ent_comp);
+
+  count_text ();
+  write_codes (FileName);
+
+  ENCODE_CONTINUE (sbs)
+    GAMMA_ENCODE (1);
+  ENCODE_DONE
+    fseek (ic, sizeof (long), 0);
+  
+  HTONSL(max_mem);  /* [RPAP - Jan 97: Endian Ordering] */
+  fwrite (&max_mem, sizeof (max_mem), 1, ic);
+  NTOHSL(max_mem);  /* [RPAP - Jan 97: Endian Ordering] */
+
+  fclose (ic);
+
+  write_num_file (FileName);
+
+  msg_prefix = temp_str;
+
+  return (COMPALLOK);
+}				/* done_encode */
Index: /main/tags/2.25/gsdl/packages/mg/src/text/ivf.pass2.c
===================================================================
--- /main/tags/2.25/gsdl/packages/mg/src/text/ivf.pass2.c	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/mg/src/text/ivf.pass2.c	(revision 21064)
@@ -0,0 +1,1096 @@
+/**************************************************************************
+ *
+ * ivf.pass2.c -- Memory efficient pass 2 inversion
+ * Copyright (C) 1994  Neil Sharman
+ *
+ * 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.
+ *
+ * $Id$
+ *
+ **************************************************************************/
+
+/*
+   $Log$
+   Revision 1.1  1999/08/10 21:17:54  sjboddie
+   renamed mg-1.3d directory mg
+
+   Revision 1.3  1998/12/17 09:12:51  rjmcnab
+
+   Altered mg to process utf-8 encoded Unicode. The main changes
+   are in the parsing of the input, the casefolding, and the stemming.
+
+   Revision 1.2  1998/11/25 07:55:43  rjmcnab
+
+   Modified mg to that you can specify the stemmer you want
+   to use via a command line option. You specify it to
+   mg_passes during the build process. The number of the
+   stemmer that you used is stored within the inverted
+   dictionary header and the stemmed dictionary header so
+   the correct stemmer is used in later stages of building
+   and querying.
+
+   Revision 1.1  1998/11/17 09:34:45  rjmcnab
+   *** empty log message ***
+
+   * Revision 1.3  1994/10/20  03:56:49  tes
+   * I have rewritten the boolean query optimiser and abstracted out the
+   * components of the boolean query.
+   *
+   * Revision 1.2  1994/09/20  04:41:35  tes
+   * For version 1.1
+   *
+ */
+
+static char *RCSID = "$Id$";
+
+#include "local_strings.h"
+#include "sysfuncs.h"
+#include "memlib.h"
+#include "messages.h"
+#include "stemmer.h"
+#include "perf_hash.h"
+#include "bitio_m.h"
+#include "bitio_m_mems.h"
+#include "bitio_gen.h"
+#include "bitio_random.h"
+#include "bitio_stdio.h"
+#include "netorder.h"  /* [RPAP - Jan 97: Endian Ordering] */
+
+#include "mg_files.h"
+#include "invf.h"
+#include "locallib.h"
+#include "mg.h"
+#include "build.h"
+#include "words.h"
+#include "hash.h"
+
+/* [RPAP - Feb 97: WIN32 Port] */
+#ifdef __WIN32__
+#include <io.h>
+#endif
+
+#ifndef RND_BUF_SIZE
+#define RND_BUF_SIZE 8*1024
+/*#define RND_BUF_SIZE 128 */
+#endif
+
+#define print_fsize(file)\
+do\
+  {\
+    struct stat file_state;\
+    fstat(fileno(invf_out), &file_state);\
+    Message("len(invf) = %ld", file_state.st_size);\
+  }while(0)
+
+typedef struct word_rec
+  {
+    unsigned long ptr;
+    unsigned long last;
+  }
+word_rec;
+
+typedef struct invf_state_rec
+  {
+    unsigned long Disk_Ptr;
+    unsigned long Disk_Last;
+    unsigned long Disk_B;
+  }
+invf_state_rec;
+
+typedef struct chunk
+  {
+    unsigned long start_doc;
+    unsigned long params_pos;
+    unsigned long disk_pos;
+    unsigned long N;
+  }
+chunk;
+
+
+static FILE *dict;		/* Stemmed dictionary file */
+static FILE *hash;		/* Stemmed dictionary hash file */
+static FILE *invf;		/* Inverted file */
+static FILE *invf_in;		/* Inverted file */
+static FILE *invf_out;		/* Inverted file */
+static FILE *invf_idx;		/* Inverted index file */
+static FILE *count;		/* Count file */
+static FILE *count_trans;	/* Count translation file */
+static FILE *invf_state;	/* Inverted file State */
+static FILE *chunk_state;	/* Chunk state */
+static FILE *chunks;		/* Chunk state */
+static FILE *invf_para = NULL;	/* Paragraph counts file */
+static FILE *weights = NULL;	/* Weights file */
+
+static stdio_bitio_state sbs;
+static random_bitio_state crbs;
+static chunk *chunk_data = NULL;
+static random_bitio_state rbs, rbsp;
+
+static int docs_left = 0, next_docs_left = 0;
+static unsigned long N;
+
+static word_rec *WordRecs;
+static u_char *lg_bs;
+static float *idf = NULL;
+
+static char *MemoryBuffer = NULL;
+static unsigned long MemBufSize;
+static unsigned long BufToUse;
+static struct invf_dict_header idh;
+
+static perf_hash_data *phd;
+
+static unsigned long *word_list = NULL;
+static unsigned long wl_size = 0;
+
+static unsigned long dict_size;
+static unsigned long no_of_ptrs = 0;
+static unsigned long chunks_read = 0;
+static unsigned long Disk_pos = 0;
+static unsigned long callnum = 0;
+static unsigned long wordnum = 0;
+
+static unsigned long totalIbytes = 0;
+static unsigned long totalDbytes = 0;
+static unsigned long totalHbytes = 0;
+
+static unsigned long MemInUse = 0;
+static unsigned long MaxMemInUse = 0;
+static unsigned long max_buffer_len;
+
+void 
+ChangeMemInUse (int mem)
+{
+  MemInUse += mem;
+  if (MemInUse > MaxMemInUse)
+    MaxMemInUse = MemInUse;
+}
+
+
+
+
+static int 
+open_files (char *file_name)
+{
+  char FName[200];
+
+  if (!(dict = open_file (file_name, INVF_DICT_SUFFIX, "rb",
+			  MAGIC_STEM_BUILD, MG_CONTINUE)))  /* [RPAP - Feb 97: WIN32 Port] */
+    return (COMPERROR);
+
+  if (!(hash = open_file (file_name, INVF_DICT_HASH_SUFFIX, "rb",
+			  MAGIC_HASH, MG_CONTINUE)))  /* [RPAP - Feb 97: WIN32 Port] */
+    return (COMPERROR);
+
+  if (!(count = open_file (file_name, INVF_CHUNK_SUFFIX, "rb",
+			   MAGIC_CHUNK, MG_CONTINUE)))  /* [RPAP - Feb 97: WIN32 Port] */
+    return (COMPERROR);
+  fread (&max_buffer_len, sizeof (max_buffer_len), 1, count);
+  NTOHUL(max_buffer_len);  /* [RPAP - Jan 97: Endian Ordering] */
+
+  BIO_Stdio_Decode_Start (count, &sbs);
+  next_docs_left = BIO_Stdio_Gamma_Decode (&sbs, NULL) - 1;
+
+  if (!(count_trans = open_file (file_name, INVF_CHUNK_TRANS_SUFFIX, "rb",
+				 MAGIC_CHUNK_TRANS, MG_CONTINUE)))  /* [RPAP - Feb 97: WIN32 Port] */
+    return (COMPERROR);
+
+  if (!(invf = create_file (file_name, INVF_SUFFIX, "w+b",
+			    MAGIC_INVF, MG_CONTINUE)))  /* [RPAP - Feb 97: WIN32 Port] */
+    return (COMPERROR);
+  fflush (invf);
+  if (!(invf_in = open_file (file_name, INVF_SUFFIX, "rb",
+			     MAGIC_INVF, MG_CONTINUE)))  /* [RPAP - Feb 97: WIN32 Port] */
+    return (COMPERROR);
+  if (!(invf_out = create_file (file_name, INVF_SUFFIX, "wb",
+				MAGIC_INVF, MG_CONTINUE)))  /* [RPAP - Feb 97: WIN32 Port] */
+    return (COMPERROR);
+  BIO_Random_Start (invf, RND_BUF_SIZE, &rbs);
+  BIO_Random_Start (invf, RND_BUF_SIZE, &rbsp);
+  ChangeMemInUse (RND_BUF_SIZE * 2);
+
+  if (!(invf_idx = create_file (file_name, INVF_IDX_SUFFIX, "wb",
+				MAGIC_INVI, MG_CONTINUE)))  /* [RPAP - Feb 97: WIN32 Port] */
+    return (COMPERROR);
+
+  if (InvfLevel == 3)
+    if (!(invf_para = create_file (file_name, INVF_PARAGRAPH_SUFFIX, "wb",
+				   MAGIC_PARAGRAPH, MG_CONTINUE)))  /* [RPAP - Feb 97: WIN32 Port] */
+      return (COMPERROR);
+
+  sprintf (FName, FILE_NAME_FORMAT ".%ld", get_basepath (), file_name,
+	   ".invf.state", (long) getpid ());  /* [RPAP - Feb 97: WIN32 Port] */
+  if (!(invf_state = fopen (FName, "w+b")))  /* [RPAP - Feb 97: WIN32 Port] */
+    {
+      Message ("Unable to create \"%s\"", FName);
+      return (COMPERROR);
+    }
+  unlink (FName);
+
+  sprintf (FName, FILE_NAME_FORMAT ".%ld", get_basepath (), file_name,
+	   ".chunk.state", (long) getpid ());  /* [RPAP - Feb 97: WIN32 Port] */
+  if (!(chunk_state = fopen (FName, "w+b")))  /* [RPAP - Feb 97: WIN32 Port] */
+    {
+      Message ("Unable to create \"%s\"", FName);
+      return (COMPERROR);
+    }
+  unlink (FName);
+  BIO_Random_Start (chunk_state, RND_BUF_SIZE, &crbs);
+  ChangeMemInUse (RND_BUF_SIZE);
+
+  sprintf (FName, FILE_NAME_FORMAT ".%ld", get_basepath (), file_name,
+	   ".chunks", (long) getpid ());  /* [RPAP - Feb 97: WIN32 Port] */
+  if (!(chunks = fopen (FName, "w+b")))  /* [RPAP - Feb 97: WIN32 Port] */
+    {
+      Message ("Unable to create \"%s\"", FName);
+      return (COMPERROR);
+    }
+  unlink (FName);
+
+  return (COMPALLOK);
+}
+
+
+
+
+
+#define ISR_CACHE 1024
+#define ISR_ENTRY_SIZE (sizeof(unsigned long)*2 + sizeof(unsigned long))
+
+invf_state_rec *
+in_cache (int pos)
+{
+  static char isr_data[ISR_CACHE * ISR_ENTRY_SIZE];
+  static invf_state_rec isr;
+  static int isr_base = 0, isr_num = -1, isr_pos = -1;
+  if (isr_pos >= 0)
+    bcopy ((char *) &isr, &isr_data[isr_pos * ISR_ENTRY_SIZE], ISR_ENTRY_SIZE);
+  if (pos < isr_base || pos >= isr_base + isr_num)
+    {
+      if (isr_num >= 0)
+	{
+	  fseek (invf_state, isr_base * ISR_ENTRY_SIZE, 0);
+	  fwrite (isr_data, 1, ISR_ENTRY_SIZE * isr_num, invf_state);
+	}
+      isr_base = pos;
+      fseek (invf_state, isr_base * ISR_ENTRY_SIZE, 0);
+      fread (isr_data, 1, ISR_ENTRY_SIZE * ISR_CACHE, invf_state);
+      isr_num = ISR_CACHE;
+    }
+  isr_pos = pos - isr_base;
+  bcopy (&isr_data[isr_pos * ISR_ENTRY_SIZE], (char *) &isr, ISR_ENTRY_SIZE);
+  return &isr;
+}
+
+
+
+
+
+unsigned long 
+occur_to_lexical (long occ)
+{
+  static long pos = -1;
+  static random_bitio_state rbs;
+  static int val = 0;
+  if (pos == -1)
+    {
+      BIO_Random_Start (count_trans, RND_BUF_SIZE, &rbs);
+      pos = 0x7fffffff;
+    }
+  if (occ < pos)
+    {
+      if (occ == -1)
+	{
+	  BIO_Random_Done (&rbs);
+	  return 0;
+	}
+      BIO_Random_Seek (32, &rbs);
+      pos = 0;
+    }
+  while (pos <= occ)
+    {
+      val = BIO_Random_Binary_Decode (dict_size + 1, &rbs, NULL) - 1;
+      pos++;
+    }
+  return (val);
+}
+
+
+void 
+add_chunk_state (unsigned long pos, unsigned long start_doc,
+		 unsigned long N)
+{
+  chunk_data[chunks_read].params_pos = pos;
+  chunk_data[chunks_read].start_doc = start_doc;
+  chunk_data[chunks_read].N = N;
+  chunks_read++;
+}
+
+
+int 
+init_ivf_2 (char *file_name)
+{
+  u_char prev[MAXSTEMLEN + 1];
+  int i;
+  unsigned long totalIbits;
+  double logN = 0.0;
+
+  if (open_files (file_name) == COMPERROR)
+    return COMPERROR;
+
+
+  /* Read in the stemmed dictionary file header */
+  fread ((char *) &idh, sizeof (idh), 1, dict);
+
+  /* [RPAP - Jan 97: Endian Ordering] */
+  NTOHUL(idh.lookback);
+  NTOHUL(idh.dict_size);
+  NTOHUL(idh.total_bytes);
+  NTOHUL(idh.index_string_bytes);
+  NTOHD(idh.input_bytes); /* [RJM 07/97: 4G limit] */
+  NTOHUL(idh.num_of_docs);
+  NTOHUL(idh.static_num_of_docs);
+  NTOHUL(idh.num_of_words);
+  NTOHUL(idh.stemmer_num);
+  NTOHUL(idh.stem_method);
+
+  dict_size = idh.dict_size;
+
+  N = idh.num_of_docs;
+
+  if (!(phd = read_perf_hash_data (hash)))
+    {
+      Message ("Unable to read in hash data");
+      return COMPERROR;
+    }
+  totalHbytes = sizeof (perf_hash_data) + sizeof (u_char) * 256 +
+    sizeof (int) * (phd->MAX_N + 1) + sizeof (int *) * 3 * phd->MAX_CH +
+    sizeof (long) * phd->MAX_CH * phd->MAX_L;
+
+  if (!(WordRecs = Xmalloc (sizeof (word_rec) * idh.dict_size)))
+    {
+      Message ("No memory for word entries");
+      return COMPERROR;
+    }
+  totalDbytes += sizeof (word_rec) * idh.dict_size;
+
+  /* separate storage for the log(b) values, one byte each */
+  if (!(lg_bs = Xmalloc (sizeof (u_char) * idh.dict_size)))
+    {
+      Message ("No memory for lg b's");
+      return COMPERROR;
+    }
+  totalDbytes += sizeof (u_char) * idh.dict_size;
+
+  if (MakeWeights)
+    {
+      /* separate storage for the idf values, one single each */
+      if (!(idf = Xmalloc (sizeof (float) * idh.dict_size)))
+	{
+	  Message ("No memory for idf's");
+	  return COMPERROR;
+	}
+      totalDbytes += sizeof (float) * idh.dict_size;
+
+      if (!(weights = create_file (file_name, WEIGHTS_SUFFIX, "wb",
+				 MAGIC_WGHT, MG_CONTINUE))) { /* [RPAP - Feb 97: WIN32 Port] */
+	Message ("Couldn't open weights file for writing");
+	return (COMPERROR);
+      }
+    }
+  else
+    {
+      unlink (make_name (file_name, WEIGHTS_SUFFIX, NULL));
+    }
+
+  chunk_data = Xmalloc (sizeof (chunk) * (ChunkLimit + 2));
+  totalDbytes += sizeof (chunk) * (ChunkLimit + 2);
+
+  totalIbits = 32;		/* The magic number */
+  totalIbits += 8 * 100;	/* A 100 byte gap */
+
+  if (MakeWeights)
+    {
+      wl_size = 1024;
+      if (!(word_list = Xmalloc (sizeof (*word_list) * wl_size)))
+	{
+	  Message ("No memory for word_list");
+	  return COMPERROR;
+	}
+
+      logN = log ((double) N);
+    }
+
+  for (i = 0; i < idh.dict_size; i++)
+    {
+      invf_state_rec *isr;
+      register unsigned long copy, suff, p;
+      unsigned long fcnt, wcnt;
+
+      copy = fgetc (dict);
+      suff = fgetc (dict);
+      *prev = copy + suff;
+      fread (prev + copy + 1, sizeof (u_char), suff, dict);
+
+      fread ((char *) &fcnt, sizeof (fcnt), 1, dict);
+      fread ((char *) &wcnt, sizeof (wcnt), 1, dict);
+
+      /* [RPAP - Jan 97: Endian Ordering] */
+      NTOHUL(fcnt);
+      NTOHUL(wcnt);
+
+      WordRecs[i].last = 0;
+      WordRecs[i].ptr = 0;
+
+      p = fcnt;
+
+      if (MakeWeights)
+	idf[i] = logN - log ((double) fcnt);
+
+
+      isr = in_cache (i);
+
+      isr->Disk_Last = 0;
+      isr->Disk_Ptr = totalIbits;
+
+      isr->Disk_B = BIO_Bblock_Init (N, p);
+
+      totalIbits += BIO_Bblock_Bound_b (N, p, isr->Disk_B);
+
+      if (InvfLevel >= 2)
+	totalIbits += BIO_Gamma_Bound (wcnt, fcnt);
+
+      totalIbits = (totalIbits + 7ul) & 0xfffffff8ul;
+
+    }
+
+
+  /* now convert to bytes, and actually get the space */
+  totalIbytes = (totalIbits + 7ul) >> 3ul;
+
+
+  return (COMPALLOK);
+
+}
+
+
+
+
+
+static void 
+LoadCounts (void)
+{
+  unsigned long numwords, i, last_total;
+  static unsigned long local_N = 0;
+  unsigned long totalIbits, crbs_pos;
+  word_rec *wr;
+  unsigned long *counts;
+
+  if (MemoryBuffer == NULL)
+    {
+      MemBufSize = sizeof (unsigned long) * dict_size;
+      if (max_buffer_len > MemBufSize)
+	MemBufSize = max_buffer_len;
+      if (!(MemoryBuffer = Xmalloc (MemBufSize)))
+	FatalError (1, "Unable to allocate memory for buffer");
+      ChangeMemInUse (MemBufSize);
+    }
+
+  counts = (unsigned long *) MemoryBuffer;
+  bzero ((char *) counts, sizeof (unsigned long) * dict_size);
+
+  docs_left = next_docs_left;
+  if (!docs_left)
+    FatalError (1, "The number of docs in the current chunk is 0");
+
+  BufToUse = BIO_Stdio_Gamma_Decode (&sbs, NULL) - 1;
+
+  numwords = BIO_Stdio_Gamma_Decode (&sbs, NULL) - 1;
+
+  local_N = docs_left;
+
+
+
+  for (wr = WordRecs, i = 0; i < dict_size; i++, wr++)
+    wr->ptr = 0;
+
+  bzero ((char *) lg_bs, dict_size);
+
+  for (i = 0; i < numwords; i++)
+    {
+      unsigned long word_num, wcnt, fcnt, p;
+      word_num = occur_to_lexical (i);
+
+      wr = &WordRecs[word_num];
+
+      wcnt = BIO_Stdio_Gamma_Decode (&sbs, NULL) - 1;
+      if (wcnt >= 2)
+	fcnt = BIO_Stdio_Gamma_Decode (&sbs, NULL);
+      else
+	fcnt = wcnt;
+
+      p = fcnt;
+
+      if (wcnt)
+	{
+	  register unsigned long length;
+	  counts[word_num] = p;
+	  length = BIO_Bblock_Bound (local_N, p);
+	  if (InvfLevel >= 2)
+	    length += wcnt;
+	  wr->ptr = length;
+	  lg_bs[word_num] = floorlog_2 (BIO_Bblock_Init_W (local_N, p));
+	}
+
+    }
+
+  crbs_pos = BIO_Random_Tell (&crbs);
+
+  totalIbits = 0;
+  last_total = 0;
+  for (wr = WordRecs, i = 0; i < dict_size; i++, wr++)
+    {
+      register unsigned long length;
+      length = wr->ptr;
+      wr->last = callnum;
+      BIO_Random_Gamma_Encode (counts[i] + 1, &crbs, NULL);
+      if (counts[i])
+	{
+	  if (i)
+	    BIO_Random_Delta_Encode (totalIbits - last_total + 1, &crbs, NULL);
+	  else
+	    BIO_Random_Delta_Encode (1, &crbs, NULL);
+
+	  last_total = totalIbits;
+	}
+      wr->ptr = totalIbits;
+      totalIbits += length;
+    }
+  add_chunk_state (crbs_pos, callnum, local_N);
+
+  if ((totalIbits + 7ul) >> 3ul > BufToUse)
+    FatalError (1, "Pointers exceed buffer size");
+
+  next_docs_left = BIO_Stdio_Gamma_Decode (&sbs, NULL) - 1;
+}
+
+
+
+
+static void 
+DumpChunk (void)
+{
+  chunk_data[chunks_read - 1].disk_pos = Disk_pos << 3;
+  fseek (chunks, Disk_pos, 0);
+  fwrite (MemoryBuffer, sizeof (char), BufToUse, chunks);
+  Disk_pos += BufToUse;
+}
+
+
+
+
+static void 
+DiskMerge (void)
+{
+  random_bitio_state *rbsi;
+  random_bitio_state *chks = NULL;
+  unsigned long *chunk_ptrs;
+  int i;
+
+  BIO_Random_Flush (&crbs);
+
+  chunk_ptrs = Xmalloc (chunks_read * sizeof (unsigned long));
+  ChangeMemInUse (chunks_read * sizeof (unsigned long));
+  bzero ((char *) chunk_ptrs, chunks_read * sizeof (unsigned long));
+
+  rbsi = Xmalloc (chunks_read * sizeof (random_bitio_state));
+  ChangeMemInUse (chunks_read * sizeof (random_bitio_state));
+  for (i = 0; i < chunks_read; i++)
+    {
+      rbsi[i] = crbs;
+      rbsi[i].Buf = Xmalloc (rbsi[i].len);
+      ChangeMemInUse (rbsi[i].len);
+      bcopy ((char *) (crbs.Buf), (char *) (rbsi[i].Buf), rbsi[i].len);
+      BIO_Random_Seek (chunk_data[i].params_pos, &rbsi[i]);
+    }
+
+  if (chunks_read > 1)
+    {
+      int j;
+      chks = Xmalloc ((chunks_read - 1) * sizeof (random_bitio_state));
+      ChangeMemInUse ((chunks_read - 1) * sizeof (random_bitio_state));
+      BIO_Random_Start (chunks, RND_BUF_SIZE, &chks[0]);
+      ChangeMemInUse (RND_BUF_SIZE);
+      for (j = 1; j < chunks_read - 1; j++)
+	{
+	  chks[j] = chks[0];
+	  chks[j].Buf = Xmalloc (chks[0].len);
+	  ChangeMemInUse (chks[0].len);
+	  bcopy ((char *) (chks[0].Buf), (char *) (chks[j].Buf), chks[0].len);
+	}
+    }
+  for (i = 0; i < dict_size; i++)
+    {
+      int j;
+      invf_state_rec *isr = in_cache (i);
+      register int B;
+
+      BIO_Random_Seek (isr->Disk_Ptr, &rbs);	/* Position in invf file */
+
+      B = isr->Disk_B;
+
+      for (j = 0; j < chunks_read; j++)
+	{
+	  int p;
+	  p = BIO_Random_Gamma_Decode (&rbsi[j], NULL) - 1;
+
+	  if (p)
+	    {
+	      int ptr, b;
+	      chunk_ptrs[j] += BIO_Random_Delta_Decode (&rbsi[j], NULL) - 1;
+	      ptr = chunk_ptrs[j];
+	      b = 1 << floorlog_2 (BIO_Bblock_Init_W (chunk_data[j].N, p));
+
+	      if (j == chunks_read - 1)
+		{
+		  int k, CurrDoc;
+		  DECODE_START ((u_char *) MemoryBuffer, ptr)
+		    CurrDoc = isr->Disk_Last;
+		  for (k = 0; k < p; k++)
+		    {
+		      register unsigned long x, tf;
+		      BBLOCK_DECODE (x, b);
+		      if (k == 0)
+			x = x + chunk_data[j].start_doc - isr->Disk_Last;
+		      CurrDoc += x;
+		      BIO_Random_Bblock_Encode (x, B, &rbs, NULL);
+		      if (InvfLevel >= 2)
+			{
+			  UNARY_DECODE (tf);
+			  BIO_Random_Gamma_Encode (tf, &rbs, NULL);
+			}
+		    }
+		  DECODE_DONE
+		    isr->Disk_Last = CurrDoc;
+		}
+	      else
+		{
+		  int k, CurrDoc;
+		  random_bitio_state *Chks = chks + j;
+		  BIO_Random_Seek (chunk_data[j].disk_pos + ptr, Chks);
+		  CurrDoc = isr->Disk_Last;
+		  for (k = 0; k < p; k++)
+		    {
+		      register unsigned long x, tf;
+		      x = BIO_Random_Bblock_Decode (b, Chks, NULL);
+		      if (k == 0)
+			x = x + chunk_data[j].start_doc - isr->Disk_Last;
+		      CurrDoc += x;
+		      BIO_Random_Bblock_Encode (x, B, &rbs, NULL);
+		      if (InvfLevel >= 2)
+			{
+			  tf = BIO_Random_Unary_Decode (Chks, NULL);
+			  BIO_Random_Gamma_Encode (tf, &rbs, NULL);
+			}
+		    }
+		  isr->Disk_Last = CurrDoc;
+		}
+	    }
+	}
+
+      isr->Disk_Ptr = BIO_Random_Tell (&rbs);
+
+    }
+  if (chunks_read > 1)
+    {
+      int j;
+      for (j = 0; j < chunks_read - 1; j++)
+	{
+	  Xfree (chks[j].Buf);
+	  ChangeMemInUse (-chks[j].len);
+	}
+      Xfree (chks);
+      ChangeMemInUse (-(chunks_read - 1) * sizeof (random_bitio_state));
+    }
+
+  for (i = 0; i < chunks_read; i++)
+    {
+      Xfree (rbsi[i].Buf);
+      ChangeMemInUse (-rbsi[i].len);
+    }
+  Xfree (rbsi);
+  ChangeMemInUse (-chunks_read * sizeof (random_bitio_state));
+  chunks_read = 0;
+  Xfree (chunk_ptrs);
+  ChangeMemInUse (-chunks_read * sizeof (unsigned long));
+  Disk_pos = 0;
+  BIO_Random_Seek (0, &crbs);
+}
+
+static void 
+MergeIn (void)
+{
+  static int disk_chunks = 0;
+  static header = 0;
+  if (!header)
+    {
+      fprintf (stderr, "ivf.pass2 : ");
+      header = 1;
+    }
+  if (disk_chunks == ChunkLimit || next_docs_left == 0)
+    {
+      fprintf (stderr, "M");
+      DiskMerge ();
+      disk_chunks = 0;
+    }
+  else
+    {
+      fprintf (stderr, "-");
+      DumpChunk ();
+      disk_chunks++;
+    }
+  if (next_docs_left == 0)
+    fprintf (stderr, "\n");
+}
+
+
+static int 
+wl_comp (const void *a, const void *b)
+{
+  return *((int *) a) - *((int *) b);
+}
+
+static int 
+process_doc (u_char * s_in, int l_in)
+{
+  int res;
+  u_char *end = s_in + l_in - 1;
+  unsigned long tocode;
+  unsigned long wl_pos = 0;
+
+  if (!docs_left)
+    LoadCounts ();
+
+  callnum++;
+
+  if (!inaword (s_in, end))
+    if (SkipSGML)
+      PARSE_NON_STEM_WORD_OR_SGML_TAG (s_in, end);
+    else
+      PARSE_NON_STEM_WORD (s_in, end);
+
+  while (s_in <= end)
+    {
+      u_char Word[MAXSTEMLEN + 1];
+
+      PARSE_STEM_WORD (Word, s_in, end);
+      stemmer (idh.stem_method, idh.stemmer_num, Word);
+      if (SkipSGML)
+	PARSE_NON_STEM_WORD_OR_SGML_TAG (s_in, end);
+      else
+	PARSE_NON_STEM_WORD (s_in, end);
+
+      if (*Word == 0)
+	continue;
+
+      res = perf_hash (phd, Word);
+
+      {
+	word_rec *arr = &WordRecs[res];
+	int b = 1 << lg_bs[res];
+	wordnum++;
+
+	tocode = callnum;
+
+	ENCODE_START ((u_char *) MemoryBuffer, arr->ptr)
+
+	  if (tocode > arr->last)
+	  {
+	    register int x;
+	    x = tocode - arr->last - 1;
+	    BBLOCK_ENCODE (x + 1, b);
+	    if (InvfLevel >= 2)
+	      ENCODE_BIT (1);
+	    no_of_ptrs++;
+	    arr->last = tocode;
+	  }
+	else if (InvfLevel >= 2)
+	  {
+	    __pos--;
+	    ENCODE_BIT (0);
+	    ENCODE_BIT (1);
+	  }
+	arr->ptr = __pos;
+	ENCODE_DONE
+      }
+
+      if (MakeWeights)
+	{
+	  if (wl_pos >= wl_size)
+	    {
+	      wl_size += (wl_size >> 1);
+	      word_list = Xrealloc (word_list, sizeof (*word_list) * wl_size);
+	    }
+	  word_list[wl_pos++] = res;
+	}
+    }
+  if (MakeWeights)
+    {
+      float doc_weight = 0.0;
+      if (wl_pos)
+	{
+	  unsigned long *wl = word_list;
+	  unsigned long i, count, val;
+	  qsort (wl, wl_pos, sizeof (*wl), wl_comp);
+	  count = 1;
+	  val = *wl++;
+	  for (i = 1; i <= wl_pos; i++, wl++)
+	    if (i == wl_pos || val != *wl)
+	      {
+		double weight = count * idf[val];
+		doc_weight += weight * weight;
+		count = 1;
+		val = *wl;
+	      }
+	    else
+	      count++;
+	}
+      HTONF(doc_weight);  /* [RPAP - Jan 97: Endian Ordering] */
+      fwrite ((char *) &doc_weight, sizeof (doc_weight), 1, weights);
+    }
+  docs_left--;
+  if (!docs_left)
+    MergeIn ();
+
+  return COMPALLOK;
+}
+
+int 
+process_ivf_2 (u_char * s_in, int l_in)
+{
+  if (InvfLevel <= 2)
+    return process_doc (s_in, l_in);
+  else
+    {
+      int count = 0;
+      int pos = 0;
+      u_char *start = s_in;
+      while (pos < l_in)
+	{
+	  if (s_in[pos] == TERMPARAGRAPH)
+	    {
+	      int len = pos + s_in + 1 - start;
+	      if (process_doc (start, len) != COMPALLOK)
+		return (COMPERROR);
+	      start = s_in + pos + 1;
+	      count++;
+	    }
+	  pos++;
+	}
+      if (start < s_in + pos)
+	{
+	  if (process_doc (start, pos + s_in - start) != COMPALLOK)
+	    return (COMPERROR);
+	  count++;
+	}
+      HTONSI(count);  /* [RPAP - Jan 97: Endian Ordering] */
+      fwrite ((char *) &count, sizeof (count), 1, invf_para);
+    }
+  return COMPALLOK;
+}
+
+
+
+
+
+static void 
+stats (unsigned long len)
+{
+#ifndef SILENT
+  fseek (count, 0, 2);
+  fseek (count_trans, 0, 2);
+  fseek (invf_state, 0, 2);
+  fseek (invf, 0, 0);
+  fseek (invf, 0, 2);
+  fseek (chunks, 0, 2);
+  fseek (chunk_state, 0, 2);
+  Message ("File sizes\n");
+  Message ("  Chunk desc    : %10u bytes\n", ftell (count));
+  Message ("  Chunk trans   : %10u bytes\n", ftell (count_trans));
+  Message ("  Chunks        : %10u bytes\n", ftell (chunks));
+  Message ("  Chunk state   : %10u bytes\n", ftell (chunk_state));
+  Message ("  Invf state    : %10u bytes\n", ftell (invf_state));
+  Message ("  Peak invf     : %10u bytes\n", len);
+  Message ("  Final invf    : %10u bytes\n", ftell (invf));
+  Message ("Peak disk usage : %10.2f %%\n",
+	   (double) (ftell (count) + ftell (count_trans) +
+		     ftell (invf_state) + ftell (chunks) +
+		     ftell (chunk_state) + len) / ftell (invf) * 100.0);
+#endif
+}
+
+
+/* ARGSUSED */
+int 
+done_ivf_2 (char *FileName)
+{
+  long i;
+  unsigned long totalIbits;
+  unsigned long invf_len;
+  unsigned long bytes_output;
+  struct invf_file_header ifh;
+
+  if (weights)
+    fclose (weights);
+  if (invf_para)
+    fclose (invf_para);
+
+  free_perf_hash (phd);
+
+  free (MemoryBuffer);
+  ChangeMemInUse (-MemBufSize);
+
+  BIO_Random_Done (&rbs);
+  BIO_Random_Done (&rbsp);
+  fflush (invf);
+
+  fseek (invf, 0, 2);
+  invf_len = ftell (invf);
+
+  fseek (invf_out, sizeof (long), 0);
+  /* [RPAP - Jan 97: Endian Ordering] */
+  HTONUL2(dict_size, ifh.no_of_words);
+  HTONUL2(no_of_ptrs, ifh.no_of_ptrs);
+  ifh.skip_mode = 0;
+  bzero ((char *) ifh.params, sizeof (ifh.params));
+  HTONUL2(InvfLevel, ifh.InvfLevel);
+  fwrite ((char *) &ifh, sizeof (ifh), 1, invf_out);
+
+  bytes_output = ftell (invf_out);
+
+  totalIbits = 32;		/* The magic number */
+  totalIbits += 8 * 100;	/* A 100 byte gap */
+
+  /* find the right place in the file to start reading p values */
+  fseek (dict, sizeof (unsigned long) + sizeof (struct invf_dict_header), 0);
+  for (i = 0; i < dict_size; i++)
+    {
+      invf_state_rec *isr;
+      unsigned long fcnt, wcnt, s, e;
+      register unsigned long p;
+      u_char dummy1, dummy2[MAXSTEMLEN + 1];
+
+      /* output location to the invf_idx  */
+      HTONUL(bytes_output);  /* [RPAP - Jan 97: Endian Ordering] */
+      fwrite ((char *) &bytes_output, sizeof (bytes_output), 1, invf_idx);
+      NTOHUL(bytes_output);  /* [RPAP - Jan 97: Endian Ordering] */
+
+      /* read an entry for a word, just to get p value */
+      dummy1 = fgetc (dict);
+      dummy1 = fgetc (dict);
+      fread (dummy2, sizeof (u_char), dummy1, dict);
+      fread ((char *) &fcnt, sizeof (fcnt), 1, dict);
+      fread ((char *) &wcnt, sizeof (wcnt), 1, dict);
+
+      /* [RPAP - Jan 97: Endian Ordering] */
+      NTOHUL(fcnt);
+      NTOHUL(wcnt);
+
+      p = fcnt;
+
+      isr = in_cache (i);
+
+      e = (isr->Disk_Ptr + 7ul) >> 3ul;
+      s = totalIbits >> 3;
+
+      fseek (invf_in, s, 0);
+      while (s < e)
+	{
+	  u_char c = getc (invf_in);
+	  if (s == e - 1)
+	    {
+	      u_char ands[8] =
+	      {0xff, 0x80, 0xc0, 0xe0, 0xf0, 0xf8, 0xfc, 0xfe};
+	      c &= ands[isr->Disk_Ptr & 7ul];
+	    }
+	  putc (c, invf_out);
+	  bytes_output++;
+	  s++;
+	}
+
+      totalIbits += BIO_Bblock_Bound_b (N, p, isr->Disk_B);
+      if (InvfLevel >= 2)
+	totalIbits += BIO_Gamma_Bound (wcnt, fcnt);
+      totalIbits = (totalIbits + 7ul) & 0xfffffff8ul;
+
+    }
+
+  fclose (invf_in);
+
+  /* [RPAP - Feb 97: WIN32 Port] */
+#ifdef __WIN32__
+  if (!(_chsize (_fileno (invf_out), bytes_output)))
+    Message ("Could not truncate invf.");
+#else
+  ftruncate (fileno (invf_out), bytes_output);
+#endif
+
+  fclose (invf_out);
+
+  HTONUL(bytes_output);  /* [RPAP - Jan 97: Endian Ordering] */
+  fwrite ((char *) &bytes_output, sizeof (bytes_output), 1, invf_idx);
+  NTOHUL(bytes_output);  /* [RPAP - Jan 97: Endian Ordering] */
+
+  fclose (invf_idx);
+
+#ifndef SILENT
+  {
+    char *temp_str = msg_prefix;
+    unsigned long total;
+    msg_prefix = "ivf.pass2";
+    stats (invf_len);
+    Message ("Pass two data structures      : %6.3f Mbyte\n",
+	     (double) totalDbytes / 1024 / 1024);
+    total = totalDbytes;
+    Message ("Pass two hash structure(s)    : %6.3f Mbyte\n",
+	     (double) totalHbytes / 1024 / 1024);
+    total += totalHbytes;
+    Message ("Peak extra memory in use      : %6.3f Mbyte\n",
+	     (double) MaxMemInUse / 1024 / 1024);
+    total += MaxMemInUse;
+    Message ("Peak total memory in use      : %6.3f Mbyte\n",
+	     (double) total / 1024 / 1024);
+    msg_prefix = temp_str;
+  }
+#endif
+
+  Xfree (WordRecs);
+  Xfree (lg_bs);
+
+  /* Free the memory allocated for the BIO_Random */
+  occur_to_lexical (-1);
+
+  BIO_Random_Done (&crbs);
+
+  fclose (invf);
+  fclose (dict);
+  fclose (hash);
+  fclose (count);
+  fclose (count_trans);
+  fclose (chunk_state);
+  fclose (chunks);
+  fclose (invf_state);
+  return (COMPALLOK);
+}
Index: /main/tags/2.25/gsdl/packages/mg/src/text/lists.c
===================================================================
--- /main/tags/2.25/gsdl/packages/mg/src/text/lists.c	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/mg/src/text/lists.c	(revision 21064)
@@ -0,0 +1,214 @@
+/**************************************************************************
+ *
+ * lists.c -- List processing functions for boolean queries
+ * Copyright (C) 1994  Neil Sharman, Alistair Moffat and Lachlan Andrew
+ *
+ * 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.
+ *
+ * $Id$
+ *
+ **************************************************************************/
+
+#include "sysfuncs.h"
+
+#include "memlib.h"
+
+#include "lists.h"
+#include "local_strings.h"
+#include "locallib.h"
+
+/*
+   $Log$
+   Revision 1.1  1999/08/10 21:18:01  sjboddie
+   renamed mg-1.3d directory mg
+
+   Revision 1.2  1999/07/01 09:30:48  rjmcnab
+   Changes for better match reporting.
+
+   Revision 1.1  1998/11/17 09:34:47  rjmcnab
+   *** empty log message ***
+
+   * Revision 1.3  1994/10/20  03:56:50  tes
+   * I have rewritten the boolean query optimiser and abstracted out the
+   * components of the boolean query.
+   *
+   * Revision 1.2  1994/09/20  04:41:37  tes
+   * For version 1.1
+   *
+ */
+
+static char *RCSID = "$Id$";
+
+
+
+
+
+/*
+ * Make a DocList large enough to hold num entries 
+ */
+DocList *
+MakeDocList (int num)
+{
+  DocList *d;
+  if (!(d = Xmalloc (sizeof (DocList) + sizeof (DocEntry) * (num - 1))))
+    return (NULL);
+  d->num = 0;
+  d->total_retrieved = 0;
+  d->is_approx = 0;
+  return (d);
+}
+
+
+/*
+ * Change the size of a DocList so that it can hold num entries 
+ */
+DocList *
+ResizeDocList (DocList * d, int num)
+{
+  if (!(d = Xrealloc (d, sizeof (DocList) + sizeof (DocEntry) * (num - 1))))
+    return (NULL);
+  return (d);
+}
+
+
+/* IntersectLists () */
+/* Returns the intersection of List1 and List2 by deleting from List1 all */
+/* entries not in List2.  All of List2 is freed, and the nodes of List1 not */
+/* included in the resultant list are freed. */
+/* On exit the intersection of the lists is returned, or NULL on empty */
+/* intersection. */
+/* Assumes that both lists are ordered on increasing Value. */
+DocList *
+IntersectLists (DocList * List1, DocList * List2)
+{
+  DocEntry *s1, *d1, *s2;
+  if (!List2 || !List1)
+    {
+      if (List1)
+	Xfree (List1);
+      if (List2)
+	Xfree (List2);
+      return (MakeDocList (0));
+    }
+  d1 = s1 = List1->DE;
+  s2 = List2->DE;
+  while (s1 - List1->DE < List1->num && s2 - List2->DE < List2->num)
+    {
+      if (s1->DocNum == s2->DocNum)
+	*d1++ = *s1++;
+      if (s1 - List1->DE < List1->num)
+	while (s2 - List2->DE < List2->num && s2->DocNum < s1->DocNum)
+	  s2++;
+      if (s2 - List2->DE < List2->num)
+	while (s1 - List1->DE < List1->num && s1->DocNum < s2->DocNum)
+	  s1++;
+    }
+  List1->num = d1 - List1->DE;
+  Xfree (List2);
+  return (List1);
+}
+
+
+/* DiffLists () */
+/* Returns the difference of List1 and List2 by deleting from List1 all */
+/* entries in List2.  All of List2 is freed, and the nodes of List1 not */
+/* included in the resultant list are freed. */
+/* On exit the differrence of the lists is returned, or NULL on empty */
+/* intersection. */
+/* Assumes that both lists are ordered on increasing Value. */
+DocList *
+DiffLists (DocList * List1, DocList * List2)
+{
+  DocEntry *s1, *d1, *s2;
+  if (!List1)
+    {
+      if (List2)
+	Xfree (List2);
+      return (MakeDocList (0));
+    }
+  if (!List2)
+    return (List1);
+  d1 = s1 = List1->DE;
+  s2 = List2->DE;
+  while (s1 - List1->DE < List1->num)
+    {
+      if (s2 - List2->DE == List2->num)
+	*d1++ = *s1++;
+      else
+	{
+	  if (s1->DocNum == s2->DocNum)
+	    {
+	      s1++;
+	      s2++;
+	    }
+	  else if (s1->DocNum < s2->DocNum)
+	    *d1++ = *s1++;
+	  else
+	    s2++;
+	}
+    }
+  List1->num = d1 - List1->DE;
+  Xfree (List2);
+  return (List1);
+}
+
+/* MergeLists () */
+/* Finds the union of two lists and returns the head of the new list formed. */
+/* Assumes that both lists are ordered on increasing Value. */
+DocList *
+MergeLists (DocList * List1, DocList * List2)
+{
+  DocList *NewList;
+  DocEntry *d, *s1, *s2;
+  if (!List1)
+    {
+      if (List2)
+	return (List2);
+      else
+	return (MakeDocList (0));
+    }
+  if (!List2)
+    return (List1);
+  if (!(NewList = MakeDocList (List1->num + List2->num)))
+    {
+      Xfree (List1);
+      Xfree (List2);
+      return (NULL);
+    }
+
+  s1 = List1->DE;
+  s2 = List2->DE;
+  d = NewList->DE;
+  while (s1 - List1->DE < List1->num || s2 - List2->DE < List2->num)
+    {
+      if (s1 - List1->DE >= List1->num)
+	*d++ = *s2++;
+      else if (s2 - List2->DE >= List2->num)
+	*d++ = *s1++;
+      else if (s1->DocNum == s2->DocNum)
+	{
+	  *d = *s1++;
+	  (d++)->Weight += (s2++)->Weight;
+	}
+      else if (s1->DocNum < s2->DocNum)
+	*d++ = *s1++;
+      else
+	*d++ = *s2++;
+    }
+  NewList->num = d - NewList->DE;
+  Xfree (List1);
+  Xfree (List2);
+  return (NewList);
+}
Index: /main/tags/2.25/gsdl/packages/mg/src/text/lists.h
===================================================================
--- /main/tags/2.25/gsdl/packages/mg/src/text/lists.h	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/mg/src/text/lists.h	(revision 21064)
@@ -0,0 +1,59 @@
+/**************************************************************************
+ *
+ * lists.h -- List processing functions for boolean queries
+ * Copyright (C) 1994  Neil Sharman, Alistair Moffat and Lachlan Andrew
+ *
+ * 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.
+ *
+ * $Id$
+ *
+ **************************************************************************/
+
+
+#ifndef H_LISTS
+#define H_LISTS
+
+
+
+typedef struct DocEntry
+  {
+    float Weight;
+    int DocNum;
+    unsigned long SeekPos;	/* position in the text file in bytes */
+    unsigned long Len;		/* length of the document in bytes */
+    char *CompTextBuffer;
+    struct DocEntry *Next;
+    short or_included;		/*[TS:Mar/95] whether included in an AND of ORed-terms */
+  }
+DocEntry;
+
+typedef struct DocList
+  {
+    int num;
+    int total_retrieved; /* valid if > 0 */
+    int is_approx;       /* whether total_retrieved is approximate */
+    DocEntry DE[1];
+  }
+DocList;
+
+DocList *MakeDocList (int num);
+DocList *ResizeDocList (DocList * d, int num);
+DocList *IntersectLists (DocList * List1, DocList * List2);
+DocList *DiffLists (DocList * List1, DocList * List2);
+DocList *MergeLists (DocList * List1, DocList * List2);
+
+
+
+#endif
Index: /main/tags/2.25/gsdl/packages/mg/src/text/locallib.c
===================================================================
--- /main/tags/2.25/gsdl/packages/mg/src/text/locallib.c	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/mg/src/text/locallib.c	(revision 21064)
@@ -0,0 +1,304 @@
+/**************************************************************************
+ *
+ * locallib.c -- Misc functions
+ * Copyright (C) 1994  Gary Eddy, Alistair Moffat and Neil Sharman
+ *
+ * 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.
+ *
+ * $Id$
+ *
+ **************************************************************************/
+
+#include "sysfuncs.h"
+
+#include "memlib.h"
+#include "bitio_gen.h"
+#include "huffman.h"
+#include "netorder.h"  /* [RPAP - Jan 97: Endian Ordering] */
+
+#include "locallib.h"
+#include "text.h"
+
+/*
+   $Log$
+   Revision 1.1  1999/08/10 21:18:02  sjboddie
+   renamed mg-1.3d directory mg
+
+   Revision 1.1  1998/11/17 09:34:49  rjmcnab
+   *** empty log message ***
+
+   * Revision 1.3  1994/10/20  03:56:51  tes
+   * I have rewritten the boolean query optimiser and abstracted out the
+   * components of the boolean query.
+   *
+   * Revision 1.2  1994/09/20  04:41:38  tes
+   * For version 1.1
+   *
+ */
+
+static char *RCSID = "$Id$";
+
+
+int 
+vecentropy (int *A, int n)
+{
+  int total = 0, i;
+  double bits = 0.0;
+
+  for (i = 0; i < n; i++)
+    total += A[i];
+  for (i = 0; i < n; i++)
+    if (A[i])
+      bits += A[i] * log2 (1.0 * total / A[i]);
+  return ((int) (bits + 0.9999));
+
+}
+
+static void 
+siftdown (int *A, int i, int n)
+{
+  int ms, t;
+
+  while (2 * i + 1 <= n - 1)
+    {
+      if (2 * i + 1 == n - 1 || A[2 * i + 1] < A[2 * i + 2])
+	ms = 2 * i + 1;
+      else
+	ms = 2 * i + 2;
+      if (A[i] > A[ms])
+	{
+	  t = A[i];
+	  A[i] = A[ms];
+	  A[ms] = t;
+	}
+      i = ms;
+    }
+}
+
+static void 
+buildheap (int *A, int n)
+{
+  int i;
+  for (i = n / 2 - 1; i >= 0; i--)
+    siftdown (A, i, n);
+}
+
+int 
+huffcodebits (unsigned long *A, int n)
+{
+  int i, j, tot = 0, bits = 0, v1, v2, *B;
+
+  B = (int *) Xmalloc (n * sizeof (int));
+  j = 0;
+  for (i = 0; i < n; i++)
+    {
+      if (A[i])
+	{
+	  tot += (B[j++] = A[i]);
+	}
+    }
+  n = j;
+
+  if (n == 0 || tot == 0)
+    return (0);
+
+  buildheap (B, n);
+  while (n > 1)
+    {
+      v1 = B[0];
+      B[0] = B[n - 1];
+      n--;
+      siftdown (B, 0, n);
+      v2 = B[0];
+      B[0] = v1 + v2;
+      siftdown (B, 0, n);
+      bits += v1 + v2;
+    }
+  Xfree (B);
+  return (bits);
+}
+
+
+int 
+modelbits (unsigned long *A, int n)
+{
+  int i, bits = 0, last, N = 0;
+
+  last = -1;
+  for (i = 0; i < n; i++)
+    {
+      if (A[i])
+	{
+	  bits += BIO_Gamma_Length (i - last) + BIO_Gamma_Length (A[i]);
+	  last = i;
+	  N++;
+	}
+    }
+  if (N == 0)
+    return (0);
+  bits += BIO_Gamma_Length (N);
+  return (bits);
+}
+
+
+
+
+
+/* Find the next prime number larger than p */
+int 
+prime (int p)
+{
+  int limit;
+  p += (p & 1) + 1;
+  limit = (int) sqrt ((double) p) + 1;
+  do
+    {
+      int j;
+      while (limit * limit < p)
+	limit++;
+      for (j = 3; j <= limit && p % j; j += 2)
+	;			/* NULLBODY */
+      if (j > limit)
+	break;
+      p += 2;
+    }
+  while (1);
+  return (p);
+}
+
+
+
+int 
+Read_cdh (FILE * f, compression_dict_header * cdh, u_long * mem,
+	  u_long * disk)
+{
+  if (disk)
+    (*disk) += sizeof (*cdh);
+
+  /* [RPAP - Jan 97: Endian Ordering] */
+  if (fread (cdh, sizeof (*cdh), 1, f) == 1)
+    {
+      int i;
+      NTOHUL(cdh->dict_type);
+      NTOHUL(cdh->novel_method);
+      for (i = 0; i < TEXT_PARAMS; i++)
+	NTOHUL(cdh->params[i]);
+      NTOHUL(cdh->num_words[0]);
+      NTOHUL(cdh->num_words[1]);
+      NTOHUL(cdh->num_word_chars[0]);
+      NTOHUL(cdh->num_word_chars[1]);
+      NTOHUL(cdh->lookback);
+      return 0;
+    }
+  else
+    return -1;
+}
+
+
+int 
+F_Read_cdh (File * f, compression_dict_header * cdh, u_long * mem,
+	    u_long * disk)
+{
+  if (disk)
+    (*disk) += sizeof (*cdh);
+
+  /* [RPAP - Jan 97: Endian Ordering] */
+  if (Fread (cdh, sizeof (*cdh), 1, f) == 1)
+    {
+      int i;
+      NTOHUL(cdh->dict_type);
+      NTOHUL(cdh->novel_method);
+      for (i = 0; i < TEXT_PARAMS; i++)
+	NTOHUL(cdh->params[i]);
+      NTOHUL(cdh->num_words[0]);
+      NTOHUL(cdh->num_words[1]);
+      NTOHUL(cdh->num_word_chars[0]);
+      NTOHUL(cdh->num_word_chars[1]);
+      NTOHUL(cdh->lookback);
+      return 0;
+    }
+  else
+    return -1;
+}
+
+
+int 
+Read_cfh (FILE * f, comp_frags_header * cfh, u_long * mem, u_long * disk)
+{
+  int i;  /* [RPAP - Jan 97: Endian Ordering] */
+
+  if (Read_Huffman_Data (f, &cfh->hd, mem, disk) == -1)
+    return -1;
+  if (fread (&cfh->uncompressed_size,
+	     sizeof (cfh->uncompressed_size), 1, f) != 1)
+    return -1;
+  NTOHUL(cfh->uncompressed_size);  /* [RPAP - Jan 97: Endian Ordering] */
+
+  if (disk)
+    (*disk) += sizeof (cfh->uncompressed_size);
+
+  bzero ((char *) cfh->huff_words_size, sizeof (cfh->huff_words_size));
+
+  if (fread (cfh->huff_words_size + cfh->hd.mincodelen,
+	     sizeof (*cfh->huff_words_size),
+	     cfh->hd.maxcodelen - cfh->hd.mincodelen + 1, f) !=
+      cfh->hd.maxcodelen - cfh->hd.mincodelen + 1)
+    return -1;
+
+  /* [RPAP - Jan 97: Endian Ordering] */
+  for (i = cfh->hd.mincodelen; i < cfh->hd.maxcodelen + 1; i++)
+    NTOHUL(cfh->huff_words_size[i]);
+
+  if (disk)
+    (*disk) += sizeof (*cfh->huff_words_size) *
+      (cfh->hd.maxcodelen - cfh->hd.mincodelen + 1);
+  return 0;
+}
+
+
+
+int 
+F_Read_cfh (File * f, comp_frags_header * cfh, u_long * mem, u_long * disk)
+{
+  int i;  /* [RPAP - Jan 97: Endian Ordering] */
+
+  if (F_Read_Huffman_Data (f, &cfh->hd, mem, disk) == -1)
+    return -1;
+  if (Fread (&cfh->uncompressed_size,
+	     sizeof (cfh->uncompressed_size), 1, f) != 1)
+    return -1;
+  NTOHUL(cfh->uncompressed_size);  /* [RPAP - Jan 97: Endian Ordering] */
+
+  if (disk)
+    (*disk) += sizeof (cfh->uncompressed_size);
+
+  bzero ((char *) cfh->huff_words_size, sizeof (cfh->huff_words_size));
+
+  if (Fread (cfh->huff_words_size + cfh->hd.mincodelen,
+	     sizeof (*cfh->huff_words_size),
+	     cfh->hd.maxcodelen - cfh->hd.mincodelen + 1, f) !=
+      cfh->hd.maxcodelen - cfh->hd.mincodelen + 1)
+    return -1;
+
+  /* [RPAP - Jan 97: Endian Ordering] */
+  for (i = cfh->hd.mincodelen; i < cfh->hd.maxcodelen + 1; i++)
+    NTOHUL(cfh->huff_words_size[i]);
+
+  if (disk)
+    (*disk) += sizeof (*cfh->huff_words_size) *
+      (cfh->hd.maxcodelen - cfh->hd.mincodelen + 1);
+
+  return 0;
+}
Index: /main/tags/2.25/gsdl/packages/mg/src/text/locallib.h
===================================================================
--- /main/tags/2.25/gsdl/packages/mg/src/text/locallib.h	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/mg/src/text/locallib.h	(revision 21064)
@@ -0,0 +1,52 @@
+/**************************************************************************
+ *
+ * locallib.h -- Misc functions
+ * Copyright (C) 1994  Gary Eddy, Alistair Moffat and Neil Sharman
+ *
+ * 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.
+ *
+ * $Id$
+ *
+ **************************************************************************/
+
+#ifndef LOCALLIB_H
+#define LOCALLIB_H
+
+#include "sysfuncs.h"
+
+#include "text.h"
+
+#define NUMOF(a) (sizeof(a)/sizeof((a)[0]))
+
+int vecentropy (int *A, int n);
+
+int huffcodebits (unsigned long *A, int n);
+
+int modelbits (unsigned long *A, int n);
+
+int prime (int p);
+
+
+int Read_cdh (FILE * f, compression_dict_header * cdh, u_long * mem, u_long * disk);
+
+int Read_cfh (FILE * f, comp_frags_header * cfh, u_long * mem, u_long * disk);
+
+int F_Read_cdh (File * f, compression_dict_header * cdh, u_long * mem,
+		u_long * disk);
+
+int F_Read_cfh (File * f, comp_frags_header * cfh, u_long * mem, u_long * disk);
+
+
+#endif
Index: /main/tags/2.25/gsdl/packages/mg/src/text/mg.h
===================================================================
--- /main/tags/2.25/gsdl/packages/mg/src/text/mg.h	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/mg/src/text/mg.h	(revision 21064)
@@ -0,0 +1,42 @@
+/**************************************************************************
+ *
+ * mg.h -- General header file
+ * Copyright (C) 1994  Neil Sharman, Alistair Moffat and Lachlan Andrew
+ *
+ * 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.
+ *
+ * $Id$
+ *
+ **************************************************************************/
+
+
+#ifndef H_MG
+#define H_MG
+
+
+#define COMPALLOK	(0)
+#define COMPERROR	(-1)
+
+#define MAXSTRING       3000000
+#define BUFFERSIZE      (MAXSTRING+30000)
+
+
+
+
+#define	MAXLN	65536
+#define WORDS           1
+#define NONWORDS        0
+
+#endif
Index: /main/tags/2.25/gsdl/packages/mg/src/text/mg.special.c
===================================================================
--- /main/tags/2.25/gsdl/packages/mg/src/text/mg.special.c	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/mg/src/text/mg.special.c	(revision 21064)
@@ -0,0 +1,115 @@
+/**************************************************************************
+ *
+ * mg.special.c -- Special pass for mg_passes
+ * Copyright (C) 1994  Neil Sharman
+ *
+ * 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.
+ *
+ * $Id$
+ *
+ **************************************************************************/
+
+#include "sysfuncs.h"
+
+#include "mg.h"
+#include "build.h"
+
+
+/*
+   $Log$
+   Revision 1.1  1999/08/10 21:18:03  sjboddie
+   renamed mg-1.3d directory mg
+
+   Revision 1.1  1998/11/17 09:34:51  rjmcnab
+   *** empty log message ***
+
+   * Revision 1.3  1994/10/20  03:56:53  tes
+   * I have rewritten the boolean query optimiser and abstracted out the
+   * components of the boolean query.
+   *
+   * Revision 1.2  1994/09/20  04:41:44  tes
+   * For version 1.1
+   *
+ */
+
+static char *RCSID = "$Id$";
+
+
+FILE *fp;
+
+
+int 
+init_special (char *FileName)
+{
+  char FName[200];
+  sprintf (FName, "%s%s", FileName, ".docnums");
+  if (!(fp = fopen (FName, "w")))
+    return (COMPERROR);
+  return (COMPALLOK);
+}
+
+
+
+
+int 
+process_special (u_char * s_in, int l_in)
+{
+  static int un = 1;
+  char *s_done = (char *) (s_in + l_in);
+  for (; (char *) s_in != s_done; s_in++)
+    if (*s_in == '<')
+      {
+	if (strncmp ((char *) s_in, "<DOCNO>", 7) == 0)
+	  {
+	    char *s_end = (char *) (s_in + 1);
+	    for (; s_end != s_done; s_end++)
+	      if (*s_end == '<')
+		if (strncmp (s_end, "</DOCNO>", 8) == 0)
+		  break;
+	    if (s_end == s_done)
+	      {
+		fprintf (fp, "NO DOC ID %d\n", un++);
+		return COMPALLOK;
+	      }
+	    s_in += 7;
+	    while (s_end != (char *) s_in &&
+		   (*(s_end - 1) == ' ' || *(s_end - 1) == '\n'))
+	      s_end--;
+	    while ((char *) s_in != s_end &&
+		   (*s_in == ' ' || *s_in == '\n'))
+	      s_in++;
+	    for (; (char *) s_in != s_end; s_in++)
+	      putc (*s_in, fp);
+	    putc ('\n', fp);
+	    return (COMPALLOK);
+	  }
+      }
+  fprintf (fp, "NO DOC ID %d\n", un++);
+  return (COMPALLOK);
+}
+
+
+
+
+
+
+
+
+int 
+done_special (char *FileName)
+{
+  fclose (fp);
+  return COMPALLOK;
+}
Index: /main/tags/2.25/gsdl/packages/mg/src/text/mg_compression_dict.1
===================================================================
--- /main/tags/2.25/gsdl/packages/mg/src/text/mg_compression_dict.1	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/mg/src/text/mg_compression_dict.1	(revision 21064)
@@ -0,0 +1,219 @@
+.\"------------------------------------------------------------
+.\" Id - set Rv,revision, and Dt, Date using rcs-Id tag.
+.de Id
+.ds Rv \\$3
+.ds Dt \\$4
+..
+.Id $Id$
+.\"------------------------------------------------------------
+.TH mg_compression_dict 1 \*(Dt CITRI
+.SH NAME
+mg_compression_dict \- build a compression dictionary.
+.SH SYNOPSIS
+.B mg_compression_dict
+[
+.B \-h
+]
+[
+.BR \-C " |"
+.BR \-P " |"
+.B  \-S
+]
+.if n .ti +9n
+[
+.BR \-0 " |"
+.BR \-1 " |"
+.BR \-2 " |"
+.B  \-3
+]
+[
+.BR \-H " |"
+.BR \-B " |"
+.BR \-D " |"
+.BR \-Y " |"
+.B  \-M
+]
+.if n .ti +9n
+.if t .ti +.5i
+[
+.BI \-l " lookback"
+]
+[
+.BI \-k " mem"
+]
+[
+.BI \-d " directory"
+]
+.BI \-f " name"
+.SH DESCRIPTION
+.B mg_compression_dict
+builds a compression dictionary based on the statistics gathered
+during the first pass over the text.  The options to the program are
+mainly concerned with limiting the amount of memory the dictionary
+will use and with how the text compressor will cope with any novel
+words found during the compression phase.
+.SH OPTIONS
+Options may appear in any order.
+.TP "\w'\fB\-d\fP \fIdirectory\fP'u+2n"
+.B \-h
+This displays a usage line on
+.IR stderr .
+.TP
+.B \-C
+Build a complete dictionary from the statistics file.  If during the
+text compression phase a novel word is found, then the compressor will
+produce an error message and stop.
+.TP
+.B \-P
+Build a partial dictionary from the statistics file.  This dictionary
+assumes that the statistics file are based on the entire text.  The
+statistics of words not includes in the dictionary are used to
+calculate the escape probability.  If novel words are being coded
+character by character, then there may not be a Huffman code for every
+possible character.  This means that the compressor may fail if a novel
+word contains a novel character.
+.TP
+.B \-S
+Build a seed dictionary from the statistics file.  This dictionary
+assumes that the statistics file is based on only a portion of the
+text to be compressed.  The probability of a novel word is based on the
+number of words that have only occurred once.  If novel words are being
+coded character by character, then the Huffman codes for characters are
+based on the frequency of characters in the dictionary.
+.TP
+.B \-0
+All words from the statistics file are included in the built
+dictionary.
+.TP
+.B \-1
+Words are included in the dictionary until the dictionary reaches the
+desired size.  Words are selected for the dictionary based on the order
+they occurred in the source text.
+.TP
+.B \-2
+Words are included in the dictionary until the dictionary reaches the
+desired size.  The most frequent words are included in the dictionary
+first; where there is a tie for frequency, the shortest word is
+included first.
+.TP
+.B \-3
+Words are included in the dictionary until the dictionary reaches the
+desired size.  The most frequent words are included in the dictionary
+first; where there is a tie for frequency, the shortest word is
+included first.  Words are the shuffled back and forth between the
+`keep' and `discard' lists to find the `optimal' set of words that
+should be in the dictionary.
+.TP
+.B \-H
+This specifies that novel words will be coded character by character
+using Huffman codes.
+.TP
+.B \-B
+This specifies that an auxiliary dictionary will be built by the
+compressor.  Each novel word found will be placed at the end of the
+auxiliary dictionary.  Novel words will be coded in the compressed text
+using binary codes.  The binary code represents their occurrence
+position in the auxiliary dictionary.
+.TP
+.B \-D
+This specifies that an auxiliary dictionary will be built by the
+compressor.  Each novel word found will be placed at the end of the
+auxiliary dictionary.  Novel words will be coded in the compressed text
+using delta codes.  The delta code represents their occurrence position
+in the auxiliary dictionary.
+.TP
+.B \-Y
+This specifies that an auxiliary dictionary will be built by the
+compressor.  Each novel word found will be placed at the end of the
+auxiliary dictionary.  Novel words will be coded in the compressed text
+using a combination of gamma and binary codes.  The code represents
+their occurrence position in the auxiliary dictionary.  This generally
+produces better compression than
+.B \-B
+or
+.BR \-D .
+.TP
+.B \-M
+This specifies that an auxiliary dictionary will be built by the
+compressor.  Each novel word found will be placed at the end of the
+auxiliary dictionary.  Novel words will be coded in the compressed text
+using a combination of gamma and binary codes.  The code represents
+their occurrence position in the auxiliary dictionary.  This method is
+adaptive within documents, and generally produces better compression
+than
+.BR \-B ,
+.B \-D
+or
+.BR \-Y .
+.TP
+.BI \-l " lookback"
+The generated dictionary is designed to be front coded when it is
+loaded into memory.  Under normal circumstances, a front-coded
+dictionary would require scanning from the beginning in order to find
+any particular word.  However, every
+.I lookback
+words in the dictionary, the whole word is stored and a pointer to that
+word maintained.  E.g., if
+.I lookback
+is 4, then every fourth word is stored in its entirety.
+.TP
+.BI \-k " mem"
+This limits the amount of memory to use for the generated
+dictionary.  Words are selected for the dictionary based of the text
+statistics, and whether
+.BR \-0 , " \-1" , " \-2"
+or
+.B \-3
+is specified.  The memory is calculated assuming a lookback of 0,
+irrespective of what actual lookback is specified.  This means that if
+a non-zero lookback is given, the dictionary will actually occupy
+less space than specified by
+.BR \-k .
+.TP
+.BI \-d " directory"
+This specifies the directory where the document collection can be found.
+.TP
+.BI \-f " name"
+This specifies the base name of the document collection.
+.SH ENVIRONMENT
+.TP "\w'\fBMGDATA\fP'u+2n"
+.SB MGDATA
+If this environment variable exists, then its value is used as the
+default directory where the
+.BR mg (1)
+collection files are.  If this variable does not exist, then the
+directory \*(lq\fB.\fP\*(rq is used by default.  The command line
+option
+.BI \-d " directory"
+overrides the directory in
+.BR MGDATA .
+.SH FILES
+.TP 20
+.B *.text.stats
+Statistics about the source text.
+.TP
+.B *.text.dict
+Compression dictionary for the source text.
+.SH "SEE ALSO"
+.na
+.BR mg (1),
+.BR mg_fast_comp_dict (1),
+.BR mg_get (1),
+.BR mg_invf_dict (1),
+.BR mg_invf_dump (1),
+.BR mg_invf_rebuild (1),
+.BR mg_passes (1),
+.BR mg_perf_hash_build (1),
+.BR mg_text_estimate (1),
+.BR mg_weights_build (1),
+.BR mgbilevel (1),
+.BR mgbuild (1),
+.BR mgdictlist (1),
+.BR mgfelics (1),
+.BR mgquery (1),
+.BR mgstat (1),
+.BR mgtic (1),
+.BR mgticbuild (1),
+.BR mgticdump (1),
+.BR mgticprune (1),
+.BR mgticstat (1).
Index: /main/tags/2.25/gsdl/packages/mg/src/text/mg_compression_dict.c
===================================================================
--- /main/tags/2.25/gsdl/packages/mg/src/text/mg_compression_dict.c	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/mg/src/text/mg_compression_dict.c	(revision 21064)
@@ -0,0 +1,1084 @@
+/**************************************************************************
+ *
+ * mg_compression_dict.c -- Routines for reading the compression dictionary
+ * Copyright (C) 1994  Neil Sharman
+ *
+ * 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.
+ *
+ * $Id$
+ *
+ **************************************************************************/
+
+#include "sysfuncs.h"
+
+#include "memlib.h"
+#include "messages.h"
+#include "local_strings.h"
+#include "bitio_gen.h"
+#include "bitio_m.h"
+#include "bitio_m_stdio.h"
+#include "timing.h"
+#include "mgheap.h"
+#include "netorder.h"  /* [RPAP - Jan 97: Endian Ordering] */
+
+#include "mg_files.h"
+#include "locallib.h"
+#include "invf.h"
+#include "text.h"
+#include "words.h"
+#include "mg.h"
+
+#define MAXBITS (sizeof(unsigned long) * 8)
+
+/*
+   $Log$
+   Revision 1.2  1999/12/10 15:04:25  cs025
+   Incorrect use of NTOHUL on a double value (num_bytes).
+
+   Revision 1.1  1999/08/10 21:18:04  sjboddie
+   renamed mg-1.3d directory mg
+
+   Revision 1.4  1999/01/15 03:05:51  rjmcnab
+
+   Renamed lib/heap to be lib/mgheap (it was causing some problems with
+   some versions of the STL libraries which contained a heap.h)
+
+   Revision 1.3  1998/12/17 09:12:52  rjmcnab
+
+   Altered mg to process utf-8 encoded Unicode. The main changes
+   are in the parsing of the input, the casefolding, and the stemming.
+
+   Revision 1.2  1998/11/25 07:55:44  rjmcnab
+
+   Modified mg to that you can specify the stemmer you want
+   to use via a command line option. You specify it to
+   mg_passes during the build process. The number of the
+   stemmer that you used is stored within the inverted
+   dictionary header and the stemmed dictionary header so
+   the correct stemmer is used in later stages of building
+   and querying.
+
+   Revision 1.1  1998/11/17 09:34:52  rjmcnab
+   *** empty log message ***
+
+   * Revision 1.3  1994/10/20  03:56:54  tes
+   * I have rewritten the boolean query optimiser and abstracted out the
+   * components of the boolean query.
+   *
+   * Revision 1.2  1994/09/20  04:41:45  tes
+   * For version 1.1
+   *
+ */
+
+static char *RCSID = "$Id$";
+
+/* #define DEBUG1 */
+
+/* #define DEBUG */
+
+#define is_power_of_two(a) ((a) != 0 && (((a) & ((a)-1)) == 0))
+
+#define MAX_RECALCULATIONS 100
+
+typedef struct WordData
+  {
+    u_long freq, occur_num;
+    float saving;
+    float char_bit_cost;
+    u_long num_trans;
+    u_char *word;
+  }
+WordData;
+
+static WordData *Words[2];
+static u_long Num[2];
+static u_long chars[2];
+
+#define KIND(p) (((p) >= Words[0] && (p) < Words[0] + Num[0]) ? 0 : 1)
+#define IsWord(p) (((p) >= Words[1] && (p) < Words[1] + Num[1]) ? 1 : 0)
+#define IsNonWord(p) (((p) >= Words[0] && (p) < Words[0] + Num[0]) ? 1 : 0)
+
+
+typedef struct DictData
+  {
+    WordData **wd;
+    u_long num_wds;
+    u_long chars;
+  }
+DictData;
+
+typedef DictData DictInfo[2];
+
+static DictInfo keep, discard, all;
+static compression_stats_header csh;
+
+static char *file_name = "";
+static u_long novel_method = MG_NOVEL_HUFFMAN_CHARS;
+
+
+static void ReadInWords (char *);
+static void Select_on (int k, heap_comp hc);
+static void Method3 (int k);
+static void Select_all (void);
+static u_long WriteOutWords (char *, u_long, int);
+static int DecFreqIncWL (void *a, void *b);
+static int OccuranceOrder (void *a, void *b);
+
+
+
+int main (int argc, char **argv)
+{
+  ProgTime StartTime;
+  int ch;
+  char type = 'C';
+  char mode = '0';
+  int lookback = 2;
+  double k = 0;
+  u_long mem_reqd;
+  opterr = 0;
+  msg_prefix = argv[0];
+  while ((ch = getopt (argc, argv, "0123CPSf:d:l:hk:HBDYM")) != -1)
+    switch (ch)
+      {
+      case 'H':
+	novel_method = MG_NOVEL_HUFFMAN_CHARS;
+	break;
+      case 'B':
+	novel_method = MG_NOVEL_BINARY;
+	break;
+      case 'D':
+	novel_method = MG_NOVEL_DELTA;
+	break;
+      case 'Y':
+	novel_method = MG_NOVEL_HYBRID;
+	break;
+      case 'M':
+	novel_method = MG_NOVEL_HYBRID_MTF;
+	break;
+      case 'f':		/* input file */
+	file_name = optarg;
+	break;
+      case 'd':
+	set_basepath (optarg);
+	break;
+      case 'C':
+      case 'P':
+      case 'S':
+	type = ch;
+	break;
+      case '0':
+      case '1':
+      case '2':
+      case '3':
+	mode = ch;
+	break;
+      case 'l':
+	lookback = atoi (optarg);
+	if (!is_power_of_two (lookback))
+	  FatalError (1, "The lookback value must be a power of 2");
+	lookback = floorlog_2 (lookback);
+	break;
+      case 'k':
+	k = atof (optarg) * 1024;
+	break;
+      case 'h':
+      case '?':
+	fprintf (stderr, "usage: %s [-l lookback] [-f input_file]"
+	"[-d data directory] [-h] [-0|-1|-2|-3] [-C|-P|-S] [-k mem (Kb)]\n",
+		 argv[0]);
+	exit (1);
+      }
+  GetTime (&StartTime);
+
+  ReadInWords (file_name);
+
+  if (type == 'C')
+    {
+      Select_all ();
+      mem_reqd = WriteOutWords (file_name, MG_COMPLETE_DICTIONARY, lookback);
+    }
+  else
+    {
+      switch (mode)
+	{
+	case '0':
+	  Select_all ();
+	  break;
+	case '1':
+	  Message ("Dictionary limit of %.2f Kb", k / 1024);
+	  Select_on ((int) k, OccuranceOrder);
+	  break;
+	case '2':
+	  Message ("Dictionary limit of %.2f Kb", k / 1024);
+	  Select_on ((int) k, DecFreqIncWL);
+	  break;
+	case '3':
+	  Message ("Dictionary limit of %.2f Kb", k / 1024);
+	  Method3 ((int) k);
+	  break;
+	}
+      if (type == 'P')
+	{
+	  mem_reqd = WriteOutWords (file_name, MG_PARTIAL_DICTIONARY, lookback);
+	}
+      else
+	{
+	  mem_reqd = WriteOutWords (file_name, MG_SEED_DICTIONARY, lookback);
+	}
+    }
+
+  Message ("Num words           : %8u -> %8u\n", Num[1], keep[1].num_wds);
+  Message ("Num non-words       : %8u -> %8u\n", Num[0], keep[0].num_wds);
+  Message ("Chars of words      : %8u -> %8u\n", chars[1], keep[1].chars);
+  Message ("Chars of non-words  : %8u -> %8u\n", chars[0], keep[0].chars);
+  Message ("Mem usage           : %8u -> %8u\n",
+	   (Num[0] + Num[1]) * sizeof (char *) + chars[0] + chars[1],
+	     (keep[0].num_wds + keep[1].num_wds) * sizeof (char *) +
+	   keep[0].chars + keep[1].chars);
+  Message ("Actual mem required : %8u\n", mem_reqd);
+
+  Message ("%s", ElapsedTime (&StartTime, NULL));
+  return 0;
+}
+
+
+
+
+static void 
+ReadInWords (char *filename)
+{
+  FILE *f;
+  unsigned long i;
+  f = open_file (filename, TEXT_STATS_DICT_SUFFIX, "rb",
+		 MAGIC_STATS_DICT, MG_ABORT);  /* [RPAP - Feb 97: WIN32 Port] */
+
+  fread (&csh, sizeof (csh), 1, f);
+
+  /* [RPAP - Jan 97: Endian Ordering] */
+  NTOHUL(csh.num_docs);
+  NTOHD(csh.num_bytes);
+
+  for (i = 0; i < 2; i++)
+    {
+      frags_stats_header fsh;
+      char *buf;
+      WordData *wd;
+      int j;
+      chars[i] = 0;
+
+      fread (&fsh, sizeof (fsh), 1, f);
+      /* [RPAP - Jan 97: Endian Ordering] */
+      NTOHUL(fsh.num_frags);
+      NTOHUL(fsh.mem_for_frags);
+
+      Num[i] = all[i].num_wds = fsh.num_frags;
+
+      /* The +1 on the following line is to leave room for the esc code. */
+      all[i].wd = Xmalloc (sizeof (WordData *) * Num[i] + 1);
+
+      buf = Xmalloc (fsh.mem_for_frags);
+      wd = Words[i] = Xmalloc (sizeof (WordData) * Num[i]);
+      for (j = 0; j < Num[i]; j++, wd++)
+	{
+	  int len;
+	  fread (&wd->freq, sizeof (wd->freq), 1, f);
+	  NTOHUL(wd->freq);  /* [RPAP - Jan 97: Endian Ordering] */
+	  fread (&wd->occur_num, sizeof (wd->occur_num), 1, f);
+	  NTOHUL(wd->occur_num);  /* [RPAP - Jan 97: Endian Ordering] */
+	  len = fgetc (f);
+	  wd->word = (u_char *) buf;
+	  *buf++ = len;
+	  fread (buf, len, 1, f);
+	  buf += len;
+	  all[i].wd[j] = wd;
+	}
+      chars[i] = fsh.mem_for_frags - fsh.num_frags;
+    }
+  fclose (f);
+}
+
+
+static void 
+Alloc_keep_discard (void)
+{
+  keep[0].num_wds = 0;
+  keep[0].wd = Xmalloc ((Num[0] + 1) * sizeof (WordData *));
+  keep[1].num_wds = 0;
+  keep[1].wd = Xmalloc ((Num[1] + 1) * sizeof (WordData *));
+  discard[0].num_wds = 0;
+  discard[0].wd = Xmalloc ((Num[0] + 1) * sizeof (WordData *));
+  discard[1].num_wds = 0;
+  discard[1].wd = Xmalloc ((Num[1] + 1) * sizeof (WordData *));
+}
+
+
+static int 
+sort_comp (const void *a, const void *b)
+{
+  WordData *aa = *(WordData **) a;
+  WordData *bb = *(WordData **) b;
+  return casecompare (aa->word, bb->word);  /* [RPAP - Jan 97: Stem Index Change] */
+}
+
+
+
+static void 
+SortAndCount_DictData (DictData * dd)
+{
+  int i;
+  WordData **wd;
+  qsort (dd->wd, dd->num_wds, sizeof (WordData *), sort_comp);
+  dd->chars = 0;
+  wd = dd->wd;
+  for (i = 0; i < dd->num_wds; i++, wd++)
+    dd->chars += (*wd)->word[0];
+}
+
+
+static void 
+Select_all (void)
+{
+  int i;
+  Alloc_keep_discard ();
+  keep[0].num_wds = Num[0];
+  for (i = 0; i < Num[0]; i++)
+    keep[0].wd[i] = Words[0] + i;
+  keep[1].num_wds = Num[1];
+  for (i = 0; i < Num[1]; i++)
+    keep[1].wd[i] = Words[1] + i;
+  SortAndCount_DictData (&keep[0]);
+  SortAndCount_DictData (&keep[1]);
+}
+
+
+
+
+static int 
+DecFreqIncWL (void *a, void *b)
+{
+  WordData *aa = *(WordData **) a;
+  WordData *bb = *(WordData **) b;
+  if (aa->freq > bb->freq)
+    return -1;
+  else if (aa->freq < bb->freq)
+    return 1;
+  else
+    return bb->word[0] - aa->word[0];
+}
+
+
+static int 
+OccuranceOrder (void *a, void *b)
+{
+  WordData *aa = *(WordData **) a;
+  WordData *bb = *(WordData **) b;
+  if (aa->occur_num > bb->occur_num)
+    return 1;
+  else if (aa->occur_num < bb->occur_num)
+    return -1;
+  else
+    return 0;
+}
+
+
+static void 
+Select_on (int k, heap_comp hc)
+{
+  int i, num, mem;
+  WordData **wd;
+
+  Alloc_keep_discard ();
+
+  num = Num[0] + Num[1];
+  wd = Xmalloc (num * sizeof (WordData *));
+  for (i = 0; i < Num[0]; i++)
+    wd[i] = Words[0] + i;
+  for (i = 0; i < Num[1]; i++)
+    wd[i + Num[0]] = Words[1] + i;
+
+  heap_build (wd, sizeof (*wd), num, hc);
+
+  mem = 0;
+  while (k > mem && num)
+    {
+      int idx;
+      WordData *word = wd[0];
+#ifdef DEBUG
+      fprintf (stderr, "%4d:%4d:%8d :%8d :%8d : \"%s\"\n",
+	       keep[0].num_wds, keep[1].num_wds,
+	       mem, word->freq, word->occur_num, word2str (word->word));
+#endif
+      mem += sizeof (u_char *) + word->word[0];
+      heap_deletehead (wd, sizeof (*wd), &num, hc);
+      idx = KIND (word);
+      keep[idx].wd[keep[idx].num_wds++] = word;
+    }
+
+  for (i = 0; i < num; i++)
+    {
+      WordData *word = wd[i];
+      int idx = KIND (word);
+      discard[idx].wd[discard[idx].num_wds++] = word;
+    }
+  SortAndCount_DictData (&keep[0]);
+  SortAndCount_DictData (&keep[1]);
+  SortAndCount_DictData (&discard[0]);
+  SortAndCount_DictData (&discard[1]);
+
+  assert (keep[0].num_wds + discard[0].num_wds == Num[0]);
+  assert (keep[1].num_wds + discard[1].num_wds == Num[1]);
+
+}
+
+
+
+static int 
+BigSaving (void *a, void *b)
+{
+  WordData *aa = *(WordData **) a;
+  WordData *bb = *(WordData **) b;
+  return (aa->saving > bb->saving) ? -1 : (aa->saving < bb->saving);
+}
+
+static int 
+SmallSaving (void *a, void *b)
+{
+  WordData *aa = *(WordData **) a;
+  WordData *bb = *(WordData **) b;
+  return (aa->saving < bb->saving) ? -1 : (aa->saving > bb->saving);
+}
+
+
+static void 
+CalcCharCounts (WordData ** wd, int num,
+		char *char_lens[2], char *len_lens[2],
+		u_long escape[2])
+{
+  long char_freqs[2][256];
+  long len_freqs[2][16];
+  huff_data hd;
+  int i;
+  escape[0] = 0;
+  escape[1] = 0;
+  bzero ((char *) char_freqs, sizeof (char_freqs));
+  bzero ((char *) len_freqs, sizeof (len_freqs));
+  for (i = 0; i < num; i++, wd++)
+    {
+      u_long freq = (*wd)->freq;
+      u_char *buf = (*wd)->word;
+      int len = *buf++;
+      int idx = KIND (*wd);
+      len_freqs[idx][len] += freq;
+      escape[idx] += freq;
+      for (; len; len--, buf++)
+	char_freqs[idx][(u_long) (*buf)] += freq;
+    }
+  Generate_Huffman_Data (256, char_freqs[0], &hd, NULL);
+  char_lens[0] = hd.clens;
+  Generate_Huffman_Data (256, char_freqs[1], &hd, NULL);
+  char_lens[1] = hd.clens;
+
+  Generate_Huffman_Data (16, len_freqs[0], &hd, NULL);
+  len_lens[0] = hd.clens;
+  Generate_Huffman_Data (16, len_freqs[1], &hd, NULL);
+  len_lens[1] = hd.clens;
+}
+
+
+
+
+
+
+
+
+
+void 
+CalcBitCost (WordData ** discard_word, int discard_num,
+	     WordData ** keep_word, int keep_num, double freqs_trans[2],
+	     u_long escape[2], int num_trans)
+{
+  char *char_lens[2];
+  char *len_lens[2];
+  double esc[2];
+  int j;
+  CalcCharCounts (discard_word, discard_num, char_lens, len_lens, escape);
+  esc[0] = -log2 (escape[0] / (freqs_trans[0] + escape[0]));
+  esc[1] = -log2 (escape[1] / (freqs_trans[1] + escape[1]));
+  for (j = 0; j < discard_num; j++, discard_word++)
+    {
+      float cbc, wbc;
+      u_char *buf = (*discard_word)->word;
+      int len = *buf++;
+      u_long freq = (*discard_word)->freq;
+      int idx = KIND (*discard_word);
+
+      cbc = len_lens[idx][len];
+      for (; len; len--, buf++)
+	cbc += char_lens[idx][(u_long) (*buf)];
+
+      (*discard_word)->char_bit_cost = (cbc + esc[idx]) * freq;
+
+      wbc = -log2 (freq / (freqs_trans[idx] + escape[idx])) * freq;
+
+      (*discard_word)->saving = ((*discard_word)->char_bit_cost - wbc) /
+	(sizeof (char *) + (*discard_word)->word[0]);
+
+      (*discard_word)->num_trans = num_trans;
+    }
+  for (j = 0; j < keep_num; j++, keep_word++)
+    {
+      float cbc, wbc;
+      u_char *buf = (*keep_word)->word;
+      int len = *buf++;
+      u_long freq = (*keep_word)->freq;
+      int idx = KIND (*keep_word);
+
+      cbc = len_lens[idx][len];
+      for (; len; len--, buf++)
+	cbc += char_lens[idx][(u_long) (*buf)];
+
+      (*keep_word)->char_bit_cost = (cbc + esc[idx]) * freq;
+
+      wbc = -log2 (freq / (freqs_trans[idx] + escape[idx])) * freq;
+
+      (*keep_word)->saving = ((*keep_word)->char_bit_cost - wbc) /
+	(sizeof (char *) + (*keep_word)->word[0]);
+
+      (*keep_word)->num_trans = num_trans;
+    }
+  Xfree (char_lens[0]);
+  Xfree (char_lens[1]);
+  Xfree (len_lens[0]);
+  Xfree (len_lens[1]);
+}
+
+
+
+static void 
+Method3 (int k)
+{
+  int i, keep_num, discard_num, mem, num_trans, recalc_reqd;
+  int keep_to_discard = 0;
+  int discard_to_keep = 0;
+  int recalcs = 0;
+  double freqs_trans[2], total;
+  u_long escape[2];
+  WordData **keep_heap, **discard_heap;
+
+  freqs_trans[0] = freqs_trans[1] = 0;
+  num_trans = 0;
+
+  discard_num = Num[0] + Num[1];
+  discard_heap = Xmalloc (discard_num * sizeof (WordData *));
+
+  keep_num = 0;
+  keep_heap = Xmalloc (discard_num * sizeof (WordData *));
+
+
+  for (i = 0; i < Num[0]; i++)
+    discard_heap[i] = Words[0] + i;
+  for (i = 0; i < Num[1]; i++)
+    discard_heap[i + Num[0]] = Words[1] + i;
+
+  heap_build (discard_heap, sizeof (*discard_heap), discard_num, DecFreqIncWL);
+
+  mem = 0;
+  while (k > mem && discard_num)
+    {
+      WordData *word = discard_heap[0];
+      mem += sizeof (u_char *) + word->word[0];
+      heap_deletehead (discard_heap, sizeof (word), &discard_num, DecFreqIncWL);
+      keep_heap[keep_num++] = word;
+      freqs_trans[KIND (word)] += word->freq;
+      num_trans++;
+    }
+
+  CalcBitCost (discard_heap, discard_num, keep_heap, keep_num,
+	       freqs_trans, escape, num_trans);
+  heap_build (discard_heap, sizeof (*discard_heap), discard_num, BigSaving);
+  heap_build (keep_heap, sizeof (*keep_heap), keep_num, SmallSaving);
+
+  total = 0;
+  recalc_reqd = 0;
+  while (keep_num && discard_num)
+    {
+      if ((keep_num && keep_heap[0]->num_trans < num_trans) ||
+	  (discard_num && discard_heap[0]->num_trans < num_trans))
+	{
+	  if (keep_num && keep_heap[0]->num_trans < num_trans)
+	    {
+	      WordData *word = keep_heap[0];
+	      int idx = KIND (word);
+	      float wbc;
+#ifdef DEBUG1
+	      fprintf (stderr, "KEEP \"%s\" %.2f ->", word2str (word->word),
+		       word->saving);
+#endif
+	      wbc = -log2 (word->freq / (freqs_trans[idx] + escape[idx])) *
+		word->freq;
+	      word->saving = (word->char_bit_cost - wbc) /
+		(sizeof (char *) + word->word[0]);
+#ifdef DEBUG1
+	      fprintf (stderr, " %.2f\n", word->saving);
+#endif
+	      word->num_trans = num_trans;
+	      heap_changedhead (keep_heap, sizeof (word), keep_num, SmallSaving);
+	    }
+
+	  if (discard_num && discard_heap[0]->num_trans < num_trans)
+	    {
+	      WordData *word = discard_heap[0];
+	      int idx = KIND (word);
+	      float wbc;
+#ifdef DEBUG1
+	      fprintf (stderr, "DISCARD \"%s\" %.2f ->", word2str (word->word),
+		       word->saving);
+#endif
+	      wbc = -log2 (word->freq / (freqs_trans[idx] + escape[idx])) *
+		word->freq;
+	      word->saving = (word->char_bit_cost - wbc) /
+		(sizeof (char *) + word->word[0]);
+#ifdef DEBUG1
+	      fprintf (stderr, " %.2f\n", word->saving);
+#endif
+	      word->num_trans = num_trans;
+	      heap_changedhead (discard_heap, sizeof (word),
+				discard_num, BigSaving);
+	    }
+	}
+      else if (keep_heap[0]->saving < discard_heap[0]->saving)
+	{
+	  assert (keep_num && discard_num);
+	  if (keep_num && mem + sizeof (char *) + discard_heap[0]->word[0] > k)
+	    {
+	      /* Transfer the word at the top of the keep heap to the
+	         discard heap. */
+	      WordData *word = keep_heap[0];
+	      int idx = KIND (word);
+	      heap_deletehead (keep_heap, sizeof (word), &keep_num, SmallSaving);
+	      discard_heap[discard_num] = word;
+	      heap_additem (discard_heap, sizeof (word), &discard_num,
+			    BigSaving);
+	      freqs_trans[idx] -= word->freq;
+	      mem -= sizeof (u_char *) + word->word[0];
+	      num_trans++;
+	      total += word->saving;
+	      keep_to_discard++;
+#ifdef DEBUG
+	      fprintf (stderr,
+		       "KEEP -> DISCARD %8d :%8d :%8.0f :%8.0f : \"%s\"\n",
+		       mem, word->freq, word->char_bit_cost,
+		       word->saving, word2str (word->word));
+#endif
+	    }
+	  else
+	    {
+	      /* Transfer the word at the top of the discard heap to the
+	         keep heap. */
+	      WordData *word = discard_heap[0];
+	      int idx = KIND (word);
+	      heap_deletehead (discard_heap, sizeof (word),
+			       &discard_num, BigSaving);
+	      keep_heap[keep_num] = word;
+	      heap_additem (keep_heap, sizeof (word), &keep_num, SmallSaving);
+	      freqs_trans[idx] += word->freq;
+	      mem += sizeof (u_char *) + word->word[0];
+	      num_trans++;
+	      total += word->saving;
+	      discard_to_keep++;
+#ifdef DEBUG
+	      fprintf (stderr,
+		       "DISCARD -> KEEP %8d :%8d :%8.0f :%8.0f : \"%s\"\n",
+		       mem, word->freq, word->char_bit_cost,
+		       word->saving, word2str (word->word));
+#endif
+	    }
+
+	  recalc_reqd = 1;
+
+	}
+      else
+	{
+	  if (recalc_reqd == 0)
+	    break;
+#ifdef DEBUG1
+	  fprintf (stderr, "--------------\n");
+#endif
+	  if (recalcs == MAX_RECALCULATIONS)
+	    break;
+	  CalcBitCost (discard_heap, discard_num, keep_heap, keep_num,
+		       freqs_trans, escape, num_trans);
+	  heap_build (discard_heap, sizeof (*discard_heap),
+		      discard_num, BigSaving);
+	  heap_build (keep_heap, sizeof (keep_heap), keep_num, SmallSaving);
+	  recalc_reqd = 0;
+	  recalcs++;
+	}
+    }
+
+  Alloc_keep_discard ();
+
+  for (i = 0; i < discard_num; i++)
+    {
+      WordData *word = discard_heap[i];
+      int idx = KIND (word);
+      assert (IsWord (word) || IsNonWord (word));
+      discard[idx].wd[discard[idx].num_wds++] = word;
+    }
+  for (i = 0; i < keep_num; i++)
+    {
+      WordData *word = keep_heap[i];
+      int idx = KIND (word);
+      assert (IsWord (word) || IsNonWord (word));
+      keep[idx].wd[keep[idx].num_wds++] = word;
+    }
+  SortAndCount_DictData (&keep[0]);
+  SortAndCount_DictData (&keep[1]);
+  SortAndCount_DictData (&discard[0]);
+  SortAndCount_DictData (&discard[1]);
+
+  assert (keep[0].num_wds + discard[0].num_wds == Num[0]);
+  assert (keep[1].num_wds + discard[1].num_wds == Num[1]);
+  Message ("Keep -> Discard        : %8d", keep_to_discard);
+  Message ("Discard -> Keep        : %8d", discard_to_keep);
+  Message ("Huffman Recalculations : %8d", recalcs);
+  if (recalcs == MAX_RECALCULATIONS)
+    Message ("WARNING: The number of recalculations == %d", MAX_RECALCULATIONS);
+}
+
+
+
+
+
+
+
+
+
+
+/****************************************************************************
+ *****									*****
+ *****			Dictionary saving code				*****
+ *****									*****
+ ****************************************************************************/
+
+
+
+static void 
+Write_cdh (FILE * f, compression_dict_header * cdh)
+{
+  /* [RPAP - Jan 97: Endian Ordering] */
+  int i;
+  compression_dict_header tmp = *cdh;
+  HTONUL(tmp.dict_type);
+  HTONUL(tmp.novel_method);
+  for (i = 0; i < TEXT_PARAMS; i++)
+    HTONUL(tmp.params[i]);
+  HTONUL(tmp.num_words[0]);
+  HTONUL(tmp.num_words[1]);
+  HTONUL(tmp.num_word_chars[0]);
+  HTONUL(tmp.num_word_chars[1]);
+  HTONUL(tmp.lookback);
+
+  fwrite (&tmp, sizeof (tmp), 1, f);
+}
+
+
+static void 
+Write_words (FILE * f, DictData * dd)
+{
+  int i;
+  u_char *curr, *prev = NULL;
+  for (i = 0; i < dd->num_wds; i++)
+    {
+      int len;
+      curr = dd->wd[i]->word;
+      if (prev)
+	/* look for prefix match with prev string */
+	len = prefixlen (prev, curr);
+      else
+	len = 0;
+      fputc ((len << 4) + (curr[0] - len), f);
+      fwrite (curr + len + 1, sizeof (u_char), curr[0] - len, f);
+      prev = curr;
+    }
+
+}
+
+
+static int 
+Uncompressed_size (DictData * dd)
+{
+  int i, us;
+  for (us = i = 0; i < dd->num_wds; i++)
+    us += dd->wd[i]->word[0];
+  return us;
+}
+
+
+static u_long 
+Write_data (FILE * f, DictData * dd, int lookback)
+{
+  u_long mem_reqd;
+  huff_data *hd;
+  int i; 
+  u_long us = dd->num_wds;
+  long *freqs;
+  u_long huff_words_size[MAX_HUFFCODE_LEN + 1];
+  u_long lencounts[MAX_HUFFCODE_LEN + 1];
+  u_char *lastword[MAX_HUFFCODE_LEN + 1];
+
+  if (!(freqs = Xmalloc ((dd->num_wds) * sizeof (*freqs))))
+    FatalError (1, "Unable to allocate memory for freqs");
+
+  for (i = 0; i < dd->num_wds; i++)
+    {
+      freqs[i] = dd->wd[i]->freq;
+      us += dd->wd[i]->word[0];
+    }
+
+  if (!(hd = Generate_Huffman_Data (dd->num_wds, freqs, NULL, NULL)))
+    FatalError (1, "Unable to allocate memory for huffman data");
+
+  Xfree (freqs), freqs = NULL;
+
+  if (Write_Huffman_Data (f, hd) == -1)
+    FatalError (1, "Unable to write huffman data");
+
+  HTONUL(us);  /* [RPAP - Jan 97: Endian Ordering] */
+  fwrite (&us, sizeof (us), 1, f);
+  NTOHUL(us);  /* [RPAP - Jan 97: Endian Ordering] */
+
+
+/* Calculate the amount of memory that will be required to store the text for
+   each different huffman code len. Every 1<<lookback words for each different
+   codelen length will not be prefixed by previous strings. */
+
+
+  bzero ((char *) &huff_words_size, sizeof (huff_words_size));
+  bzero ((char *) &lencounts, sizeof (lencounts));
+
+  mem_reqd = 0;
+
+  for (i = 0; i < dd->num_wds; i++)
+    {
+      int codelen = hd->clens[i];
+      u_char *word = dd->wd[i]->word;
+
+      if (!codelen)
+	FatalError (1, "The length of a code for a word was zero");
+
+      huff_words_size[codelen] += word[0] + 1;
+      mem_reqd += word[0] + (lookback != 0);
+#if 0
+      if ((lencounts[codelen] & ((1 << lookback) - 1)) == 0)
+	lastword[codelen] = word;
+      else
+	huff_words_size[codelen] -= prefixlen (lastword[codelen], word);
+#else
+      if ((lencounts[codelen] & ((1 << lookback) - 1)) != 0)
+	{
+	  int save = prefixlen (lastword[codelen], word);
+	  mem_reqd -= save;
+	  huff_words_size[codelen] -= save;
+	}
+      else
+	{
+	  mem_reqd += sizeof (u_char *);
+	}
+      lastword[codelen] = word;
+#endif
+      lencounts[codelen]++;
+    }
+
+  /* [RPAP - Jan 97: Endian Ordering] */
+  for (i = hd->mincodelen; i < hd->maxcodelen + 1; i++)
+    HTONUL(huff_words_size[i]);
+
+  fwrite (huff_words_size + hd->mincodelen, sizeof (*huff_words_size),
+	  hd->maxcodelen - hd->mincodelen + 1, f);
+
+  /* [RPAP - Jan 97: Endian Ordering] */
+  for (i = hd->mincodelen; i < hd->maxcodelen + 1; i++)
+    NTOHUL(huff_words_size[i]);
+
+  Write_words (f, dd);
+
+  Xfree (hd->clens);
+  Xfree (hd);
+
+  return mem_reqd;
+}
+
+
+
+static void 
+Write_charfreqs (FILE * f, DictData * dd, int words,
+		 int zero_freq_permitted)
+{
+  int j;
+  long freqs[256];
+  WordData **wd = dd->wd;
+  huff_data *hd;
+
+  bzero ((char *) freqs, sizeof (freqs));
+
+  for (j = 0; j < dd->num_wds; j++, wd++)
+    {
+      u_char *buf = (*wd)->word;
+      int len = *buf++;
+      for (; len; len--, buf++)
+	freqs[(u_long) (*buf)] += (*wd)->freq;
+    }
+
+  if (!zero_freq_permitted)
+    for (j = 0; j < 256; j++)
+      if (!freqs[j] && PESINAWORD (j) == words)
+	freqs[j] = 1;
+
+  if (!(hd = Generate_Huffman_Data (256, freqs, NULL, NULL)))
+    FatalError (1, "Unable to allocate memory for huffman data");
+
+  if (Write_Huffman_Data (f, hd) == -1)
+    FatalError (1, "Unable to write huffman data");
+
+  Xfree (hd->clens);
+  Xfree (hd);
+}
+
+
+
+
+static void 
+Write_wordlens (FILE * f, DictData * dd, int zero_freq_permitted)
+{
+  int j;
+  long freqs[16];
+  WordData **wd = dd->wd;
+  huff_data *hd;
+
+  bzero ((char *) freqs, sizeof (freqs));
+
+  for (j = 0; j < dd->num_wds; j++, wd++)
+    freqs[(*wd)->word[0]] += (*wd)->freq;
+
+  if (!zero_freq_permitted)
+    for (j = 0; j < 16; j++)
+      if (!freqs[j])
+	freqs[j] = 1;
+
+  if (!(hd = Generate_Huffman_Data (16, freqs, NULL, NULL)))
+    FatalError (1, "Unable to allocate memory for huffman data");
+
+  if (Write_Huffman_Data (f, hd) == -1)
+    FatalError (1, "Unable to write huffman data");
+
+
+  Xfree (hd->clens);
+  Xfree (hd);
+}
+
+
+
+static u_long 
+WriteOutWords (char *file_name, u_long type, int lookback)
+{
+  FILE *f;
+  int i;
+  u_long mem_reqd = 0;
+
+  compression_dict_header cdh;
+  f = create_file (file_name, TEXT_DICT_SUFFIX, "w+b",
+		   MAGIC_DICT, MG_ABORT);  /* [RPAP - Feb 97: WIN32 Port] */
+
+  bzero((char *) &cdh, sizeof(cdh));
+
+  cdh.dict_type = type;
+  cdh.novel_method = (type == MG_SEED_DICTIONARY) ? novel_method :
+    MG_NOVEL_HUFFMAN_CHARS;
+
+  cdh.num_words[1] = keep[1].num_wds;
+  cdh.num_words[0] = keep[0].num_wds;
+  cdh.num_word_chars[1] = Uncompressed_size (&keep[1]);
+  cdh.num_word_chars[0] = Uncompressed_size (&keep[0]);
+  cdh.lookback = lookback;
+
+  Write_cdh (f, &cdh);
+
+  for (i = 0; i < 2; i++)
+    switch (type)
+      {
+      case MG_COMPLETE_DICTIONARY:
+	{
+	  mem_reqd += Write_data (f, &keep[i], lookback);
+	}
+	break;
+      case MG_PARTIAL_DICTIONARY:
+	{
+	  if (keep[i].num_wds)
+	    {
+	      int j;
+	      WordData esc;
+	      esc.freq = 0;
+	      esc.word = (u_char *) "";
+	      keep[i].wd[keep[i].num_wds++] = &esc;
+	      for (j = 0; j < discard[i].num_wds; j++)
+		esc.freq += discard[i].wd[j]->freq;
+	      if (!esc.freq)
+		esc.freq++;
+	      mem_reqd += Write_data (f, &keep[i], lookback);
+	    }
+	  Write_charfreqs (f, &discard[i], i, 1);
+	  Write_wordlens (f, &discard[i], 1);
+	}
+	break;
+      case MG_SEED_DICTIONARY:
+	{
+	  if (keep[i].num_wds)
+	    {
+	      int j;
+	      WordData esc;
+	      esc.freq = 0;
+	      esc.word = (u_char *) "";
+	      keep[i].wd[keep[i].num_wds++] = &esc;
+	      for (j = 0; j < all[i].num_wds; j++)
+		if (all[i].wd[j]->freq == 1)
+		  esc.freq++;
+	      if (!esc.freq)
+		esc.freq++;
+	      mem_reqd += Write_data (f, &keep[i], lookback);
+	    }
+	  switch (novel_method)
+	    {
+	    case MG_NOVEL_HUFFMAN_CHARS:
+	      Write_charfreqs (f, &all[i], i, 0);
+	      Write_wordlens (f, &all[i], 0);
+	      break;
+	    case MG_NOVEL_BINARY:
+	      break;
+	    case MG_NOVEL_DELTA:
+	      break;
+	    case MG_NOVEL_HYBRID:
+	      break;
+	    case MG_NOVEL_HYBRID_MTF:
+	      break;
+	    default:
+	      FatalError (1, "Bad novel method");
+	    }
+	}
+	break;
+      }
+  fclose (f);
+  return mem_reqd;
+}
Index: /main/tags/2.25/gsdl/packages/mg/src/text/mg_decompress_text.1
===================================================================
--- /main/tags/2.25/gsdl/packages/mg/src/text/mg_decompress_text.1	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/mg/src/text/mg_decompress_text.1	(revision 21064)
@@ -0,0 +1,78 @@
+.\"------------------------------------------------------------
+.\" Id - set Rv,revision, and Dt, Date using rcs-Id tag.
+.de Id
+.ds Rv \\$3
+.ds Dt \\$4
+..
+.Id $Id$
+.\"------------------------------------------------------------
+.TH mg_decompress_text 1 \*(Dt CITRI
+.SH NAME
+mg_decompress_text \- decompresses the compressed text of a collection
+.SH SYNOPSIS
+.B mg_decompress_text
+[
+.B \-h
+]
+[
+.BI \-d " directory"
+]
+.BI \-f " name"
+.SH DESCRIPTION
+.B mg_decompress_text
+decompresses the compressed text of a collection, inserts paragraph and
+document markers, writing the output to
+.IR stdout ".  "
+This program was created
+to be used as a type of
+.BR mg_get (1).
+.SH OPTIONS
+Options may appear in any order.
+.TP "\w'\fB\-d\fP \fIdirectory\fP'u+2n"
+.B \-h
+This displays a usage line on
+.IR stderr .
+.TP
+.BI \-d " directory"
+This specifies the directory where the document collection can be found.
+.TP
+.BI \-f " name"
+This specifies the base name of the document collection.
+.SH ENVIRONMENT
+.TP "\w'\fBMGDATA\fP'u+2n"
+.SB MGDATA
+If this environment variable exists, then its value is used as the
+default directory where the
+.BR mg (1)
+collection files are.  If this variable does not exist, then the
+directory \*(lq\fB.\fP\*(rq is used by default.  The command line
+option
+.BI \-d " directory"
+overrides the directory in
+.BR MGDATA .
+.SH FILES
+.TP 25
+.B *.text
+Compressed documents.
+.TP
+.B *.text.idx
+Index into the compressed documents.
+.TP
+.B *.text.dict
+Compressed compression dictionary.
+.TP
+.B *.text.dict.aux
+Auxiliary compression dictionary.
+.TP
+.B *.text.dict.fast
+Fast loading compression dictionary.
+.TP
+.B *.invf.paragraph
+Paragraph counts for documents.
+.SH "SEE ALSO"
+.na
+.BR mg (1),
+.BR mg_compression_dict (1),
+.BR mg_fast_comp_dict (1),
+.BR mg_get (1),
+.BR mg_passes (1).
Index: /main/tags/2.25/gsdl/packages/mg/src/text/mg_decompress_text.c
===================================================================
--- /main/tags/2.25/gsdl/packages/mg/src/text/mg_decompress_text.c	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/mg/src/text/mg_decompress_text.c	(revision 21064)
@@ -0,0 +1,167 @@
+#include "sysfuncs.h"
+
+#include "filestats.h"
+#include "netorder.h"
+#include "memlib.h"
+#include "messages.h"
+#include "huffman.h"
+#include "bitio_m_mem.h"
+#include "bitio_m.h"
+#include "bitio_stdio.h"
+#include "huffman_stdio.h"
+
+#include "mg_files.h"
+#include "mg.h"
+#include "backend.h"  /* compressed_dict struct */
+#include "text_get.h"
+#include "words.h"
+
+#define EOD         '\002'
+#define EOP         '\003'
+
+/* These are defined in mgquery, and they need to be here for backend.o */
+/* Messy I know but this was meant to be a quick hack :-) */
+#if defined(PARADOCNUM) || defined(NZDL)
+int *Paragraph = NULL;
+int Documents = 0;
+#endif
+
+int
+main (int argc, char **argv)
+{
+  FILE *text, *text_idx, *para;
+  File *text_comp_dict = NULL, *text_aux_dict = NULL, *text_fast_comp_dict = NULL;
+
+  int ch;
+  unsigned long start, finish, len;
+  u_long total_chars = 0;
+  u_char *c_buffer = 0;
+  int buf_len = -1;
+  u_char *uc_buffer = 0;
+  int ULen;
+  compression_dict *cd = NULL;
+  compressed_text_header cth;
+  u_long doc;
+  int count;
+  char *filename = "";
+  char path[512];
+  opterr = 0;
+  msg_prefix = argv[0];
+
+  while ((ch = getopt (argc, argv, "f:d:h")) != -1)
+    switch (ch)
+      {
+      case 'f':		/* input file */
+	filename = optarg;
+	break;
+      case 'd':
+	set_basepath (optarg);
+	break;
+      case 'h':
+      case '?':
+	fprintf (stderr, "usage: %s [-h] [-d directory] -f name\n",
+		 argv[0]);
+	exit (1);
+      }
+
+  /* Open files */
+  text = open_file (filename, TEXT_SUFFIX, "rb", MAGIC_TEXT, MG_ABORT);
+  fread ((char *)&cth, sizeof (cth), 1, text);
+
+  text_idx = open_file (filename, TEXT_IDX_SUFFIX, "rb", MAGIC_TEXI, MG_ABORT);
+  fread ((char *)&cth, sizeof (cth), 1, text_idx);
+
+  NTOHUL(cth.num_of_docs);
+  NTOHD(cth.num_of_bytes); /* [RJM 07/97: 4G limit] */
+  NTOHUL(cth.num_of_words);
+  NTOHUL(cth.length_of_longest_doc);
+  NTOHD(cth.ratio);
+
+  para = open_file (filename, INVF_PARAGRAPH_SUFFIX, "rb", MAGIC_PARAGRAPH, MG_CONTINUE);
+
+  sprintf (path, FILE_NAME_FORMAT, get_basepath(), filename, TEXT_DICT_FAST_SUFFIX);  /* [RPAP - Feb 97: WIN32 Port] */
+  if (!(text_fast_comp_dict = Fopen (path, "rb", MAGIC_FAST_DICT)))
+    {
+      sprintf (path, FILE_NAME_FORMAT, get_basepath(), filename, TEXT_DICT_SUFFIX);  /* [RPAP - Feb 97: WIN32 Port] */
+      text_comp_dict = Fopen (path, "rb", MAGIC_DICT);
+      if (!text_comp_dict)
+	FatalError (1, "Could not open compressed dictionary");
+      sprintf (path, FILE_NAME_FORMAT, get_basepath(), filename, TEXT_DICT_AUX_SUFFIX);  /* [RPAP - Feb 97: WIN32 Port] */
+      text_aux_dict = Fopen (path, "rb", MAGIC_AUX_DICT);
+    }
+
+  cd = LoadCompDict (text_comp_dict, text_aux_dict, text_fast_comp_dict);
+
+
+  /* Uncompress text */
+
+  doc = 1;
+  fread ((char *)&start, sizeof (start), 1, text_idx);
+  if (para)
+    fread ((char *)&count, sizeof (count), 1, para);
+  else
+    count = 1;
+
+  for (;;)
+    {
+      fread ((char *) &finish, sizeof (finish), 1, text_idx);
+      len = finish - start;
+      
+      if ((int) len > buf_len)
+	{
+	  if (c_buffer)
+	    {
+	      Xfree (c_buffer);
+	      Xfree (uc_buffer);
+	    }
+	  if (!(c_buffer = Xmalloc (len)))
+	    FatalError (1, "Cannot allocate memory for compressed buffer");
+	  if (!(uc_buffer = Xmalloc ((int) (cth.ratio * 1.01 * len) + 100)))
+	    FatalError (1, "Cannot allocate memory for uncompressed buffer");
+	  buf_len = len;
+	}
+
+      fread (c_buffer, 1, len, text);
+      DecodeText (cd, c_buffer, len, uc_buffer, &ULen);
+      fwrite (uc_buffer, ULen, sizeof (u_char), stdout);
+      fflush (stdout);
+
+      total_chars += ULen;
+
+      if (++doc > cth.num_of_docs)
+	{
+	  if (para)
+	    fputc (EOP, stdout);
+	  fputc (EOD, stdout);
+	  fflush (stdout);
+	  break;
+	}
+
+      if (!--count)
+	{
+	  /* End of document */
+	  fputc (EOD, stdout);
+	  if (para)
+	    fread ((char *)&count, sizeof (count), 1, para);
+	  else
+	    count = 1;
+	}
+      else
+	fputc (EOP, stdout);
+      fflush (stdout);
+      start = finish;
+    }
+
+  /* Close files */
+
+  fclose (text);
+  fclose (text_idx);
+  if (para)
+    fclose (para);
+
+#if 0
+  printf ("\n#Total chars output = %lu\n", total_chars);
+#endif
+
+  return 0;
+}
Index: /main/tags/2.25/gsdl/packages/mg/src/text/mg_errors.c
===================================================================
--- /main/tags/2.25/gsdl/packages/mg/src/text/mg_errors.c	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/mg/src/text/mg_errors.c	(revision 21064)
@@ -0,0 +1,73 @@
+/**************************************************************************
+ *
+ * mg_errors.c -- Error related stuff for mgquery
+ * Copyright (C) 1994  Neil Sharman
+ *
+ * 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.
+ *
+ * $Id$
+ *
+ **************************************************************************/
+
+#include "sysfuncs.h"
+#include "memlib.h"
+
+#include "mg_errors.h"
+
+
+
+int mg_errno = MG_NOERROR;
+
+char *mg_errorstrs[] =
+{
+  "No error",
+  "Out of memory",
+  "File \"%s\" not found",
+  "Bad magic number in \"%s\"",
+  "Error reading \"%s\"",
+  "MG_BUFTOOSMALL",
+  "Files required for level 2 and 3 inversion are missing"};
+
+
+/* [RJM 07/98: Memory Leak] -- rest of file */
+
+static char null_data[] = "";
+char *mg_error_data = null_data;
+
+
+void MgErrorData (char *s)
+{
+  /* free the current error string, unless it is the null string */
+  if ((mg_error_data != NULL) && (mg_error_data != null_data)) {
+    Xfree (mg_error_data);
+    mg_error_data = null_data;
+  }
+
+  /* make a copy of the string */
+  mg_error_data = Xstrdup (s);
+
+  /* if the alloc failed set the error to the null string */
+  if (!mg_error_data) mg_error_data = null_data;
+}
+
+
+void MgErrorDeinit (void)
+{
+  /* free the current error string, unless it is the null string */
+  if ((mg_error_data != NULL) && (mg_error_data != null_data)) {
+    Xfree (mg_error_data);
+    mg_error_data = null_data;
+  }
+}
Index: /main/tags/2.25/gsdl/packages/mg/src/text/mg_errors.h
===================================================================
--- /main/tags/2.25/gsdl/packages/mg/src/text/mg_errors.h	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/mg/src/text/mg_errors.h	(revision 21064)
@@ -0,0 +1,39 @@
+/**************************************************************************
+ *
+ * mg_errors.h -- Error related stuff for mgquery
+ * Copyright (C) 1994  Neil Sharman
+ *
+ * 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.
+ *
+ * $Id$
+ *
+ **************************************************************************/
+
+
+extern int mg_errno;
+extern char *mg_error_data;
+extern char *mg_errorstrs[];
+
+
+#define MG_NOERROR 0
+#define MG_NOMEM 1
+#define MG_NOFILE 2
+#define MG_BADMAGIC 3
+#define MG_READERR 4
+#define MG_BUFTOOSMALL 5
+#define MG_INVERSION 6
+
+void MgErrorData (char *s);
+void MgErrorDeinit (void);
Index: /main/tags/2.25/gsdl/packages/mg/src/text/mg_fast_comp_dict.1
===================================================================
--- /main/tags/2.25/gsdl/packages/mg/src/text/mg_fast_comp_dict.1	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/mg/src/text/mg_fast_comp_dict.1	(revision 21064)
@@ -0,0 +1,86 @@
+.\"------------------------------------------------------------
+.\" Id - set Rv,revision, and Dt, Date using rcs-Id tag.
+.de Id
+.ds Rv \\$3
+.ds Dt \\$4
+..
+.Id $Id$
+.\"------------------------------------------------------------
+.TH mg_fast_comp_dict 1 \*(Dt CITRI
+.SH NAME
+mg_fast_comp_dict \- build a fast loading compression dictionary
+.SH SYNOPSIS
+.B mg_fast_comp_dict
+[
+.B \-h
+]
+[
+.BI \-d " directory"
+]
+.BI \-f " name"
+.SH DESCRIPTION
+.B mg_fast_comp_dict
+builds a fast-loading compression dictionary from the standard
+compression dictionary.  The new dictionary has the property that
+.BR mgquery (1)
+can load it in very quickly, making the startup time for
+.BR mgquery (1)
+much shorter.  The new dictionary is larger on disk than the original,
+but they are no different when it comes to memory usage.
+.SH OPTIONS
+Options may appear in any order.
+.TP "\w'\fB\-d\fP \fIdirectory\fP'u+2n"
+.B \-h
+This displays a usage line on
+.IR stderr .
+.TP
+.BI \-d " directory"
+This specifies the directory where the document collection can be found.
+.TP
+.BI \-f " name"
+This specifies the base name of the document collection.
+.SH ENVIRONMENT
+.TP "\w'\fBMGDATA\fP'u+2n"
+.SB MGDATA
+If this environment variable exists, then its value is used as the
+default directory where the
+.BR mg (1)
+collection files are.  If this variable does not exist, then the
+directory \*(lq\fB.\fP\*(rq is used by default.  The command line
+option
+.BI \-d " directory"
+overrides the directory in
+.BR MGDATA .
+.SH FILES
+.TP 20
+.B *.text.dict
+Compression dictionary.
+.TP
+.B *.text.dict.fast
+Fast loading compression dictionary.
+.TP
+.B *.text.dict.aux
+Auxiliary compression dictionary.
+.SH "SEE ALSO"
+.na
+.BR mg (1),
+.BR mg_compression_dict (1),
+.BR mg_get (1),
+.BR mg_invf_dict (1),
+.BR mg_invf_dump (1),
+.BR mg_invf_rebuild (1),
+.BR mg_passes (1),
+.BR mg_perf_hash_build (1),
+.BR mg_text_estimate (1),
+.BR mg_weights_build (1),
+.BR mgbilevel (1),
+.BR mgbuild (1),
+.BR mgdictlist (1),
+.BR mgfelics (1),
+.BR mgquery (1),
+.BR mgstat (1),
+.BR mgtic (1),
+.BR mgticbuild (1),
+.BR mgticdump (1),
+.BR mgticprune (1),
+.BR mgticstat (1).
Index: /main/tags/2.25/gsdl/packages/mg/src/text/mg_fast_comp_dict.c
===================================================================
--- /main/tags/2.25/gsdl/packages/mg/src/text/mg_fast_comp_dict.c	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/mg/src/text/mg_fast_comp_dict.c	(revision 21064)
@@ -0,0 +1,798 @@
+/**************************************************************************
+ *
+ * mg_fast_comp_dict.c -- Program to generate a fast compression dictionary
+ * Copyright (C) 1994  Neil Sharman
+ *
+ * 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.
+ *
+ * $Id$
+ *
+ **************************************************************************/
+
+
+/*
+   $Log$
+   Revision 1.1  1999/08/10 21:18:06  sjboddie
+   renamed mg-1.3d directory mg
+
+   Revision 1.2  1998/11/25 07:55:44  rjmcnab
+
+   Modified mg to that you can specify the stemmer you want
+   to use via a command line option. You specify it to
+   mg_passes during the build process. The number of the
+   stemmer that you used is stored within the inverted
+   dictionary header and the stemmed dictionary header so
+   the correct stemmer is used in later stages of building
+   and querying.
+
+   Revision 1.1  1998/11/17 09:34:57  rjmcnab
+   *** empty log message ***
+
+   * Revision 1.3  1994/10/20  03:56:55  tes
+   * I have rewritten the boolean query optimiser and abstracted out the
+   * components of the boolean query.
+   *
+   * Revision 1.2  1994/09/20  04:41:47  tes
+   * For version 1.1
+   *
+ */
+
+static char *RCSID = "$Id$";
+
+#include "sysfuncs.h"
+
+#include "filestats.h"
+#include "huffman.h"
+#include "timing.h"
+#include "messages.h"
+#include "memlib.h"
+#include "netorder.h"  /* [RPAP - Jan 97: Endian Ordering] */
+
+#include "local_strings.h"
+#include "mg.h"
+#include "text.h"
+#include "invf.h"
+#include "lists.h"
+#include "backend.h"
+#include "mg_files.h"
+#include "locallib.h"
+#include "words.h"
+
+
+
+#define ALIGN_SIZE(p,t) (((p) + (sizeof(t)-1)) & (~(sizeof(t)-1)))
+
+#define WORDNO(p, base) ((((char*)(p))-((char*)(base)))/sizeof(u_char*))
+#define FIXUP(p) (fixup[WORDNO(p,buffer)/8] |= (1<<(WORDNO(p, buffer) & 7)))
+
+#define IS_FIXUP(p) ((fixup[WORDNO(p,buffer)/8] & (1<<(WORDNO(p, buffer) & 7))) != 0)
+
+#define FIXUP_VALS(vals) do {						\
+	int i;								\
+	for (i=0; i < MAX_HUFFCODE_LEN+1; i++)				\
+	  FIXUP(&vals[i]);						\
+      } while(0)
+
+
+
+static u_long mem_for_comp_dict (char *filename);
+static void load_comp_dict (char *filename);
+static void save_fast_dict (char *filename);
+static void unfixup_buffer (void);
+
+
+static void *buffer;
+static void *cur;
+static u_char *fixup;
+static u_long mem, fixup_mem;
+
+int main (int argc, char **argv)
+{
+  ProgTime StartTime;
+  int ch;
+  char *filename = "";
+  opterr = 0;
+  msg_prefix = argv[0];
+  while ((ch = getopt (argc, argv, "f:d:h")) != -1)
+    switch (ch)
+      {
+      case 'f':		/* input file */
+	filename = optarg;
+	break;
+      case 'd':
+	set_basepath (optarg);
+	break;
+      case 'h':
+      case '?':
+	fprintf (stderr, "usage: %s [-f input_file] [-d data directory] [-h]\n",
+		 argv[0]);
+	exit (1);
+      }
+  GetTime (&StartTime);
+
+  mem = mem_for_comp_dict (filename);
+
+  fixup_mem = (ALIGN_SIZE (mem, u_char *) / sizeof (u_char *) + 7) / 8;
+
+  cur = buffer = Xmalloc (mem);
+  bzero (buffer, mem);
+  fixup = Xmalloc (fixup_mem);
+  bzero (fixup, fixup_mem);
+
+  Message ("Estimated memory for fast_dict %u", mem);
+  Message ("Estimated memory for fixups %u", fixup_mem);
+
+  load_comp_dict (filename);
+
+  Message ("Actual memory for fast_dict %u", (char *) cur - (char *) buffer);
+
+  if ((u_long) cur > (u_long) buffer + mem)
+    FatalError (1, "The buffer was not big enough for the dictionary");
+
+  {
+    /* [RPAP - Jan 97: Endian Ordering] */
+    compression_dict *cd = (compression_dict *) buffer;
+    int i, which;
+
+    /* cfh */
+    for (which = 0; which <= 1; which++)
+      {
+	int j;
+	
+	HTONSI(cd->cfh[which]->hd.num_codes);
+	HTONSI(cd->cfh[which]->hd.mincodelen);
+	HTONSI(cd->cfh[which]->hd.maxcodelen);
+	for (j = 0; j < MAX_HUFFCODE_LEN + 1; j++)
+	  {
+	    HTONSI(cd->cfh[which]->hd.lencount[j]);
+	    HTONUL(cd->cfh[which]->hd.min_code[j]);
+	  }
+	HTONUL(cd->cfh[which]->uncompressed_size);
+	for (j = 0; j < MAX_HUFFCODE_LEN + 1; j++)
+	  HTONUL(cd->cfh[which]->huff_words_size[j]);
+      }
+    HTONUL(cd->MemForCompDict);
+    /* ad */
+    if (cd->cdh.novel_method == MG_NOVEL_BINARY ||
+	cd->cdh.novel_method == MG_NOVEL_DELTA ||
+	cd->cdh.novel_method == MG_NOVEL_HYBRID ||
+	cd->cdh.novel_method == MG_NOVEL_HYBRID_MTF)
+      for (which = 0; which <= 1; which++)
+	{
+	  int j;
+	  
+	  HTONUL(cd->ad->afh[which].num_frags);
+	  HTONUL(cd->ad->afh[which].mem_for_frags);
+	  for (j = 0; j < 33; j++)
+	    {
+	      HTONSI(cd->ad->blk_start[which][j]);
+	      HTONSI(cd->ad->blk_end[which][j]);
+	    }
+	}
+    /* cdh */
+    HTONUL(cd->cdh.dict_type);
+    HTONUL(cd->cdh.novel_method);
+    for (i = 0; i < TEXT_PARAMS; i++)
+      HTONUL(cd->cdh.params[which]);
+    HTONUL(cd->cdh.num_words[0]);
+    HTONUL(cd->cdh.num_words[1]);
+    HTONUL(cd->cdh.num_word_chars[0]);
+    HTONUL(cd->cdh.num_word_chars[1]);
+    HTONUL(cd->cdh.lookback);
+    HTONSI(cd->fast_loaded);
+  }
+
+  unfixup_buffer ();
+
+  save_fast_dict (filename);
+
+  Message ("%s", ElapsedTime (&StartTime, NULL));
+  return 0;
+}
+
+
+
+static void 
+unfixup_buffer ()
+{
+  u_long *p;
+  for (p = buffer; (u_long) p < (u_long) cur; p++)
+    {
+      if (IS_FIXUP (p))
+	*p = *p - (u_long) buffer;
+    }
+}
+
+
+
+
+static u_long 
+mem_for_aux_dict (compression_dict_header * cdh, char *filename)
+{
+  int i;
+  u_long mem = sizeof (auxiliary_dict);
+  FILE *aux;
+
+  aux = open_file (filename, TEXT_DICT_AUX_SUFFIX, "rb",
+		   MAGIC_AUX_DICT, MG_ABORT);  /* [RPAP - Feb 97: WIN32 Port] */
+
+  for (i = 0; i <= 1; i++)
+    {
+      aux_frags_header afh;
+      fread (&afh, sizeof (afh), 1, aux);
+      NTOHUL(afh.num_frags);  /* [RPAP - Jan 97: Endian Ordering] */
+      NTOHUL(afh.mem_for_frags);  /* [RPAP - Jan 97: Endian Ordering] */
+      mem += afh.num_frags * sizeof (u_char *);
+      mem = ALIGN_SIZE (mem + afh.mem_for_frags, u_char *);
+      fseek (aux, afh.mem_for_frags, SEEK_CUR);
+    }
+  fclose (aux);
+
+  return mem;
+}
+
+
+
+static u_long 
+mem_for_words (FILE * dict, compression_dict_header * cdh,
+	       comp_frags_header * cfh)
+{
+  u_long mem = 0;
+  u_long i, lookback;
+  int ptrs_reqd = 0;
+  int mem_reqd = 0;
+
+  lookback = cdh->lookback;
+
+  for (i = cfh->hd.mincodelen; i <= cfh->hd.maxcodelen; i++)
+    {
+      ptrs_reqd += (cfh->hd.lencount[i] + ((1 << lookback) - 1)) >> lookback;
+      mem_reqd += cfh->huff_words_size[i];
+    }
+
+  mem += ptrs_reqd * sizeof (u_char *);
+  mem += (MAX_HUFFCODE_LEN + 1) * sizeof (u_char **);
+  mem += mem_reqd;
+
+  for (i = 0; i < cfh->hd.num_codes; i++)
+    {
+      register int val;
+      for (val = getc (dict) & 0xf; val; val--)
+	getc (dict);
+    }
+  return ALIGN_SIZE (mem, u_char *);
+}
+
+
+
+
+static u_long 
+mem_for_comp_dict (char *filename)
+{
+  u_long mem = sizeof (compression_dict);
+  compression_dict_header cdh;
+  comp_frags_header cfh;
+  FILE *dict;
+  int which;
+  int i;  /* [RPAP - Jan 97: Endian Ordering] */
+
+  dict = open_file (filename, TEXT_DICT_SUFFIX, "rb",
+		    MAGIC_DICT, MG_ABORT);  /* [RPAP - Feb 97: WIN32 Port] */
+
+  fread (&cdh, sizeof (cdh), 1, dict);
+  /* [RPAP - Jan 97: Endian Ordering] */
+  NTOHUL(cdh.dict_type);
+  NTOHUL(cdh.novel_method);
+  for (i = 0; i < TEXT_PARAMS; i++)
+    NTOHUL(cdh.params[i]);
+  NTOHUL(cdh.num_words[0]);
+  NTOHUL(cdh.num_words[1]);
+  NTOHUL(cdh.num_word_chars[0]);
+  NTOHUL(cdh.num_word_chars[1]);
+  NTOHUL(cdh.lookback);
+
+  for (which = 0; which < 2; which++)
+    switch (cdh.dict_type)
+      {
+      case MG_COMPLETE_DICTIONARY:
+	{
+	  mem += sizeof (comp_frags_header);
+	  Read_cfh (dict, &cfh, NULL, NULL);
+
+	  /* Don't need to count the space for the clens of the huffman data */
+
+	  mem += mem_for_words (dict, &cdh, &cfh);
+	  if (cfh.hd.clens)
+	    Xfree (cfh.hd.clens);
+	}
+	break;
+      case MG_PARTIAL_DICTIONARY:
+	{
+	  huff_data hd;
+	  if (cdh.num_words[which])
+	    {
+	      mem += sizeof (comp_frags_header);
+	      Read_cfh (dict, &cfh, NULL, NULL);
+
+	      /* Don't need to count the space for the clens of the
+	         huffman data */
+
+	      mem += mem_for_words (dict, &cdh, &cfh);
+	      if (cfh.hd.clens)
+		Xfree (cfh.hd.clens);
+
+	    }
+
+	  mem += sizeof (hd);
+	  Read_Huffman_Data (dict, &hd, NULL, NULL);
+	  if (hd.clens)
+	    Xfree (hd.clens);
+	  mem += hd.num_codes * sizeof (unsigned long);
+	  mem += (MAX_HUFFCODE_LEN + 1) * sizeof (unsigned long *);
+
+	  mem += sizeof (hd);
+	  Read_Huffman_Data (dict, &hd, NULL, NULL);
+	  if (hd.clens)
+	    Xfree (hd.clens);
+	  mem += hd.num_codes * sizeof (unsigned long);
+	  mem += (MAX_HUFFCODE_LEN + 1) * sizeof (unsigned long *);
+	}
+	break;
+      case MG_SEED_DICTIONARY:
+	{
+	  huff_data hd;
+	  if (cdh.num_words[which])
+	    {
+	      mem += sizeof (comp_frags_header);
+	      Read_cfh (dict, &cfh, NULL, NULL);
+
+	      /* Don't need to count the space for the clens of the
+	         huffman data */
+
+	      mem += mem_for_words (dict, &cdh, &cfh);
+	      if (cfh.hd.clens)
+		Xfree (cfh.hd.clens);
+
+	    }
+	  switch (cdh.novel_method)
+	    {
+	    case MG_NOVEL_HUFFMAN_CHARS:
+	      mem += sizeof (hd);
+	      Read_Huffman_Data (dict, &hd, NULL, NULL);
+	      if (hd.clens)
+		Xfree (hd.clens);
+	      mem += hd.num_codes * sizeof (unsigned long);
+	      mem += (MAX_HUFFCODE_LEN + 1) * sizeof (unsigned long *);
+
+	      mem += sizeof (hd);
+	      Read_Huffman_Data (dict, &hd, NULL, NULL);
+	      if (hd.clens)
+		Xfree (hd.clens);
+	      mem += hd.num_codes * sizeof (unsigned long);
+	      mem += (MAX_HUFFCODE_LEN + 1) * sizeof (unsigned long *);
+	      break;
+	    case MG_NOVEL_BINARY:
+	      break;
+	    case MG_NOVEL_DELTA:
+	      break;
+	    case MG_NOVEL_HYBRID:
+	      break;
+	    case MG_NOVEL_HYBRID_MTF:
+	      break;
+	    }
+	  break;
+	}
+      }
+  fclose (dict);
+
+  if (cdh.novel_method == MG_NOVEL_BINARY ||
+      cdh.novel_method == MG_NOVEL_DELTA ||
+      cdh.novel_method == MG_NOVEL_HYBRID ||
+      cdh.novel_method == MG_NOVEL_HYBRID_MTF)
+    mem += mem_for_aux_dict (&cdh, filename);
+
+  return ALIGN_SIZE (mem, u_char *);
+}
+
+
+
+void *
+getmem (u_long size, int align)
+{
+  void *res;
+  cur = (void *) (((u_long) cur + (align - 1)) & (~(align - 1)));
+  res = cur;
+  cur = (char *) cur + size;
+  if ((long) cur > (long) buffer + mem)
+    FatalError (1, "The buffer was not big enough for the dictionary");
+  return res;
+}
+
+
+
+
+
+
+
+
+
+
+
+static auxiliary_dict *
+LoadAuxDict (compression_dict_header * cdh,
+	     char *filename)
+{
+  auxiliary_dict *ad;
+  int i;
+  FILE *aux;
+
+  aux = open_file (filename, TEXT_DICT_AUX_SUFFIX, "rb",
+		   MAGIC_AUX_DICT, MG_ABORT);  /* [RPAP - Feb 97: WIN32 Port] */
+
+  ad = getmem (sizeof (auxiliary_dict), sizeof (u_char *));
+
+  for (i = 0; i <= 1; i++)
+    {
+      int j;
+      u_char *pos;
+
+      fread (&ad->afh[i], sizeof (aux_frags_header), 1, aux);
+
+      /* [RPAP - Jan 97: Endian Ordering] */
+      NTOHUL(ad->afh[i].num_frags);
+      NTOHUL(ad->afh[i].mem_for_frags);
+
+      ad->word_data[i] = getmem (ad->afh[i].mem_for_frags, 1);
+      FIXUP (&ad->word_data[i]);
+
+      ad->words[i] = getmem (ad->afh[i].num_frags * sizeof (u_char *),
+			     sizeof (u_char *));
+      FIXUP (&ad->words[i]);
+
+      fread (ad->word_data[i], ad->afh[i].mem_for_frags, sizeof (u_char), aux);
+
+      pos = ad->word_data[i];
+      for (j = 0; j < ad->afh[i].num_frags; j++)
+	{
+	  ad->words[i][j] = pos;
+	  FIXUP (&ad->words[i][j]);
+	  pos += *pos + 1;
+	}
+      if (cdh->novel_method == MG_NOVEL_HYBRID ||
+	  cdh->novel_method == MG_NOVEL_HYBRID_MTF)
+	{
+	  int num;
+	  num = 1;
+	  ad->blk_start[i][0] = 0;
+	  ad->blk_end[i][0] = cdh->num_words[i] - 1;
+	  while (num < 33)
+	    {
+	      ad->blk_start[i][num] = ad->blk_end[i][num - 1] + 1;
+	      ad->blk_end[i][num] = ad->blk_start[i][num] +
+		(ad->blk_end[i][num - 1] - ad->blk_start[i][num - 1]) * 2;
+	      num++;
+	    }
+	}
+    }
+  fclose (aux);
+  return (ad);
+}
+
+
+
+
+
+static u_char ***
+ReadInWords (FILE * dict, compression_dict * cd,
+	     comp_frags_header * cfh, u_char ** escape)
+{
+  int i, lookback;
+  int ptrs_reqd = 0;
+  int mem_reqd = 0;
+  int num_set[MAX_HUFFCODE_LEN + 1];
+  u_char *next_word[MAX_HUFFCODE_LEN + 1];
+  u_char **vals;
+  u_char ***values;
+  u_char word[MAXWORDLEN + 1];
+  u_char last_word[MAX_HUFFCODE_LEN + 1][MAXWORDLEN + 1];
+
+  lookback = cd->cdh.lookback;
+
+  for (i = cfh->hd.mincodelen; i <= cfh->hd.maxcodelen; i++)
+    {
+      ptrs_reqd += (cfh->hd.lencount[i] + ((1 << lookback) - 1)) >> lookback;
+      mem_reqd += cfh->huff_words_size[i];
+    }
+
+  vals = getmem (ptrs_reqd * sizeof (*vals), sizeof (u_char *));
+
+  values = getmem ((MAX_HUFFCODE_LEN + 1) * sizeof (u_char **), sizeof (u_char **));
+
+  next_word[0] = getmem (mem_reqd, sizeof (char));
+
+  cd->MemForCompDict += ptrs_reqd * sizeof (*vals) +
+    (MAX_HUFFCODE_LEN + 1) * sizeof (u_char **) +
+    mem_reqd;
+
+  values[0] = vals;
+  FIXUP (&values[0]);
+  values[0][0] = next_word[0];
+  FIXUP (&values[0][0]);
+  for (i = 1; i <= cfh->hd.maxcodelen; i++)
+    {
+      int next_start = (values[i - 1] - vals) +
+      ((cfh->hd.lencount[i - 1] + ((1 << lookback) - 1)) >> lookback);
+      values[i] = &vals[next_start];
+      FIXUP (&values[i]);
+      next_word[i] = next_word[i - 1] + cfh->huff_words_size[i - 1];
+      values[i][0] = next_word[i];
+      FIXUP (&values[i][0]);
+    }
+
+  bzero ((char *) num_set, sizeof (num_set));
+
+  for (i = 0; i < cfh->hd.num_codes; i++)
+    {
+      register int val, copy;
+      register int len = cfh->hd.clens[i];
+      val = getc (dict);
+      copy = (val >> 4) & 0xf;
+      val &= 0xf;
+
+      fread (word + copy + 1, sizeof (u_char), val, dict);
+      *word = val + copy;
+
+      if ((num_set[len] & ((1 << lookback) - 1)) == 0)
+	{
+	  values[len][num_set[len] >> lookback] = next_word[len];
+	  FIXUP (&values[len][num_set[len] >> lookback]);
+	  memcpy (next_word[len], word, *word + 1);
+	  if (escape && i == cfh->hd.num_codes - 1)
+	    {
+	      *escape = next_word[len];
+	      FIXUP (escape);
+	    }
+	  next_word[len] += *word + 1;
+	}
+      else
+	{
+	  copy = prefixlen (last_word[len], word);
+	  memcpy (next_word[len] + 1, word + copy + 1, *word - copy);
+	  *next_word[len] = (copy << 4) + (*word - copy);
+	  if (escape && i == cfh->hd.num_codes - 1)
+	    {
+	      *escape = next_word[len];
+	      FIXUP (escape);
+	    }
+	  next_word[len] += (*word - copy) + 1;
+	}
+      memcpy (last_word[len], word, *word + 1);
+      num_set[len]++;
+    }
+  if (cfh->hd.clens)
+    Xfree (cfh->hd.clens);
+  cfh->hd.clens = NULL;
+  return values;
+}
+
+
+static unsigned long **
+Generate_Fast_Huffman_Vals (huff_data * data, u_long * mem)
+{
+  int i;
+  unsigned long *fcode[MAX_HUFFCODE_LEN + 1];
+  unsigned long **values;
+  unsigned long *vals;
+
+  if (!data)
+    return (NULL);
+  vals = getmem (data->num_codes * sizeof (*vals), sizeof (long *));
+  values = getmem ((MAX_HUFFCODE_LEN + 1) * sizeof (unsigned long *),
+		   sizeof (long *));
+
+  bzero ((char *) values, (MAX_HUFFCODE_LEN + 1) * sizeof (unsigned long *));
+
+  if (mem)
+    *mem += data->num_codes * sizeof (*vals) +
+      (MAX_HUFFCODE_LEN + 1) * sizeof (unsigned long *);
+
+  fcode[0] = values[0] = &vals[0];
+  FIXUP (&values[0]);
+  for (i = 1; i <= data->maxcodelen; i++)
+    {
+      fcode[i] = values[i] = &vals[(values[i - 1] - vals) + data->lencount[i - 1]];
+      FIXUP (&values[i]);
+    }
+
+  for (i = 0; i < data->num_codes; i++)
+    if (data->clens[i])
+      *fcode[(int) (data->clens[i])]++ = i;
+  return (values);
+}
+
+
+
+static void 
+load_comp_dict (char *filename)
+{
+  FILE *dict;
+  int which;
+  compression_dict *cd;
+
+  cd = getmem (sizeof (compression_dict), sizeof (u_char *));
+  cd->fast_loaded = 1;
+
+  dict = open_file (filename, TEXT_DICT_SUFFIX, "rb",
+		    MAGIC_DICT, MG_ABORT);  /* [RPAP - Feb 97: WIN32 Port] */
+
+  Read_cdh (dict, &cd->cdh, NULL, NULL);
+
+  for (which = 0; which < 2; which++)
+    switch (cd->cdh.dict_type)
+      {
+      case MG_COMPLETE_DICTIONARY:
+	{
+	  cd->cfh[which] = getmem (sizeof (*cd->cfh[which]), sizeof (u_char *));
+	  cd->MemForCompDict += sizeof (*cd->cfh[which]);
+	  Read_cfh (dict, cd->cfh[which], &cd->MemForCompDict, NULL);
+
+	  cd->values[which] = ReadInWords (dict, cd, cd->cfh[which], NULL);
+	  FIXUP (&cd->cfh[which]);
+	  FIXUP (&cd->values[which]);
+	  cd->escape[which] = NULL;
+	}
+	break;
+      case MG_PARTIAL_DICTIONARY:
+	{
+	  huff_data *hd;
+	  u_long **vals;
+	  if (cd->cdh.num_words[which])
+	    {
+	      cd->cfh[which] = getmem (sizeof (*cd->cfh[which]), sizeof (u_char *));
+	      cd->MemForCompDict += sizeof (*cd->cfh[which]);
+	      Read_cfh (dict, cd->cfh[which], &cd->MemForCompDict, NULL);
+	      cd->values[which] = ReadInWords (dict, cd, cd->cfh[which],
+					       &cd->escape[which]);
+	      FIXUP (&cd->cfh[which]);
+	      FIXUP (&cd->values[which]);
+	      FIXUP (&cd->escape[which]);
+	    }
+
+	  hd = getmem (sizeof (huff_data), sizeof (char *));
+	  cd->MemForCompDict += sizeof (huff_data);
+	  Read_Huffman_Data (dict, hd, &cd->MemForCompDict, NULL);
+	  vals = Generate_Fast_Huffman_Vals (hd, &cd->MemForCompDict);
+	  cd->chars_huff[which] = hd;
+	  FIXUP (&cd->chars_huff[which]);
+	  cd->chars_vals[which] = vals;
+	  FIXUP (&cd->chars_vals[which]);
+	  if (hd->clens)
+	    Xfree (hd->clens);
+	  hd->clens = NULL;
+
+	  hd = getmem (sizeof (huff_data), sizeof (char *));
+	  cd->MemForCompDict += sizeof (huff_data);
+	  Read_Huffman_Data (dict, hd, &cd->MemForCompDict, NULL);
+	  vals = Generate_Fast_Huffman_Vals (hd, &cd->MemForCompDict);
+	  cd->lens_huff[which] = hd;
+	  FIXUP (&cd->lens_huff[which]);
+	  cd->lens_vals[which] = vals;
+	  FIXUP (&cd->lens_vals[which]);
+	  if (hd->clens)
+	    Xfree (hd->clens);
+	  hd->clens = NULL;
+	}
+	break;
+      case MG_SEED_DICTIONARY:
+	{
+	  huff_data *hd;
+	  u_long **vals;
+	  if (cd->cdh.num_words[which])
+	    {
+	      cd->cfh[which] = getmem (sizeof (*cd->cfh[which]), sizeof (u_char *));
+	      cd->MemForCompDict += sizeof (*cd->cfh[which]);
+	      Read_cfh (dict, cd->cfh[which], &cd->MemForCompDict, NULL);
+	      cd->values[which] = ReadInWords (dict, cd, cd->cfh[which],
+					       &cd->escape[which]);
+	      FIXUP (&cd->cfh[which]);
+	      FIXUP (&cd->values[which]);
+	      FIXUP (&cd->escape[which]);
+	    }
+	  switch (cd->cdh.novel_method)
+	    {
+	    case MG_NOVEL_HUFFMAN_CHARS:
+	      hd = getmem (sizeof (huff_data), sizeof (char *));
+	      cd->MemForCompDict += sizeof (huff_data);
+	      Read_Huffman_Data (dict, hd, &cd->MemForCompDict, NULL);
+	      vals = Generate_Fast_Huffman_Vals (hd, &cd->MemForCompDict);
+	      cd->chars_huff[which] = hd;
+	      FIXUP (&cd->chars_huff[which]);
+	      cd->chars_vals[which] = vals;
+	      FIXUP (&cd->chars_vals[which]);
+	      if (hd->clens)
+		Xfree (hd->clens);
+	      hd->clens = NULL;
+
+	      hd = getmem (sizeof (huff_data), sizeof (char *));
+	      cd->MemForCompDict += sizeof (huff_data);
+	      Read_Huffman_Data (dict, hd, &cd->MemForCompDict, NULL);
+	      vals = Generate_Fast_Huffman_Vals (hd, &cd->MemForCompDict);
+	      cd->lens_huff[which] = hd;
+	      FIXUP (&cd->lens_huff[which]);
+	      cd->lens_vals[which] = vals;
+	      FIXUP (&cd->lens_vals[which]);
+	      if (hd->clens)
+		Xfree (hd->clens);
+	      hd->clens = NULL;
+	      break;
+	    case MG_NOVEL_BINARY:
+	      break;
+	    case MG_NOVEL_DELTA:
+	      break;
+	    case MG_NOVEL_HYBRID:
+	      break;
+	    case MG_NOVEL_HYBRID_MTF:
+	      break;
+	    }
+	  break;
+	}
+      }
+  fclose (dict);
+
+
+  if (cd->cdh.novel_method == MG_NOVEL_BINARY ||
+      cd->cdh.novel_method == MG_NOVEL_DELTA ||
+      cd->cdh.novel_method == MG_NOVEL_HYBRID ||
+      cd->cdh.novel_method == MG_NOVEL_HYBRID_MTF)
+    {
+      cd->ad = LoadAuxDict (&cd->cdh, filename);
+      FIXUP (&cd->ad);
+    }
+}
+
+
+static void 
+save_fast_dict (char *filename)
+{
+  FILE *fdict;
+
+  fdict = create_file (filename, TEXT_DICT_FAST_SUFFIX, "wb",
+		       MAGIC_FAST_DICT, MG_ABORT);  /* [RPAP - Feb 97: WIN32 Port] */
+
+  {
+    u_long *p;
+    for (p = buffer; (u_long) p < (u_long) cur; p++)
+      {
+	if (IS_FIXUP (p))
+	  HTONUL(*p);
+      }
+  }
+
+  /* [RPAP - Jan 97: Endian Ordering] */
+  HTONUL(mem);
+  HTONUL(fixup_mem);
+
+  fwrite (&mem, sizeof (mem), 1, fdict);
+  fwrite (&fixup_mem, sizeof (fixup_mem), 1, fdict);
+
+  /* [RPAP - Jan 97: Endian Ordering] */
+  NTOHUL(mem);
+  NTOHUL(fixup_mem);
+
+  fwrite (buffer, sizeof (u_char), mem, fdict);
+  fwrite (fixup, sizeof (u_char), fixup_mem, fdict);
+
+  fclose (fdict);
+}
Index: /main/tags/2.25/gsdl/packages/mg/src/text/mg_files.c
===================================================================
--- /main/tags/2.25/gsdl/packages/mg/src/text/mg_files.c	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/mg/src/text/mg_files.c	(revision 21064)
@@ -0,0 +1,261 @@
+/**************************************************************************
+ *
+ * mg_files.c -- Routines for handling files for the auxillary programs
+ * Copyright (C) 1994  Neil Sharman
+ *
+ * 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.
+ *
+ * $Id$
+ *
+ **************************************************************************/
+
+#include "sysfuncs.h"
+#include "memlib.h"
+#include "messages.h"
+#include "netorder.h"  /* [RPAP - Jan 97: Endian Ordering] */
+
+#include "mg_files.h"
+
+
+/* This must contain a valid path without a trailing slash */
+static char *basepath = NULL;
+
+
+
+/* This sets the base path for all file operations */
+void 
+set_basepath (const char *bp)
+{
+/* [RPAP - Feb 97: WIN32 Port] */
+#ifdef __WIN32__
+  basepath = "";
+#else
+  char *s;
+  /* Free the memory for the base path if it has already been allocated */
+  if (basepath)
+    {
+      Xfree (basepath);
+      basepath = NULL;
+    }
+
+  if (!bp || *bp == '\0')
+    bp = ".";
+
+  s = strrchr (bp, '/');
+  if (s && *(s + 1) == '\0')
+    {
+      basepath = Xmalloc (strlen (bp) + 2);
+      if (!basepath)
+	return;
+      strcpy (basepath, bp);
+      strcat (basepath, ".");
+    }
+  else
+    basepath = Xstrdup (bp);
+#endif
+}
+
+
+
+/* return the currently defined basepath */
+char *
+get_basepath (void)
+{
+  if (!basepath)
+    set_basepath (getenv ("MGDATA"));
+  return basepath;
+}
+
+
+
+/* This generates the name of a file. It places the name in the buffer
+   specified or if that is NULL it uses a static buffer. */
+char *
+make_name (const char *name, const char *suffix, char *buffer)
+{
+  static char path[512];
+  if (!buffer)
+    buffer = path;
+  if (!basepath)
+    set_basepath (getenv ("MGDATA"));
+  sprintf (buffer, FILE_NAME_FORMAT, basepath, name, suffix);  /* [RPAP - Feb 97: WIN32 Port] */
+  return buffer;
+}
+
+
+
+/* This will open the specified file and check its magic number.
+   Mode may take on the following values
+   MG_ABORT    : causes an error message to be generated and the
+   program aborted if there is an error.
+   MG_MESSAGE  : causes a message to be generated and a NULL value to
+   be returned if there is an error.
+   MG_CONTINUE : causes a NULL value to be returned if there is an error.
+
+   On success if returns the FILE *. On failure it will return a NULL value
+   and possibly generate an error message, or it will exit the program with
+   an error message.   */
+FILE *
+open_named_file (const char *name, const char *mode,
+		 u_long magic_num, int err_mode)
+{
+  unsigned long magic;
+  FILE *f = NULL;
+  char *err;
+  f = fopen (name, mode);
+
+  if (!f)
+    {
+      err = "Unable to open \"%s\"";
+      goto error;
+    }
+
+  if (magic_num)
+    {
+      if (fread (&magic, sizeof (magic), 1, f) != 1)
+	{
+	  err = "No magic number \"%s\"";
+	  goto error;
+	}
+
+      NTOHUL(magic);  /* [RPAP - Jan 97: Endian Ordering] */
+
+      if (!IS_MAGIC (magic))
+	{
+	  err = "No MG magic number \"%s\"";
+	  goto error;
+	}
+
+      if (magic != magic_num)
+	{
+	  err = "Wrong MG magic number \"%s\"";
+	  goto error;
+	}
+    }
+  return f;
+
+error:
+  if (f)
+    fclose (f);
+  if (err_mode == MG_ABORT)
+    FatalError (1, err, name);
+  if (err_mode == MG_MESSAGE)
+    Message (err, name);
+  return NULL;
+}
+
+
+
+/* This will open the specified file and check its magic number.
+   Mode may take on the following values
+   MG_ABORT    : causes an error message to be generated and the
+   program aborted if there is an error.
+   MG_MESSAGE  : causes a message to be generated and a NULL value to
+   be returned if there is an error.
+   MG_CONTINUE : causes a NULL value to be returned if there is an error.
+
+   On success if returns the FILE *. On failure it will return a NULL value
+   and possibly generate an error message, or it will exit the program with
+   an error message.   */
+FILE *
+open_file (const char *name, const char *suffix, const char *mode,
+	   u_long magic_num, int err_mode)
+{
+  char path[512];
+  if (!basepath)
+    set_basepath (getenv ("MGDATA"));
+  sprintf (path, FILE_NAME_FORMAT, basepath, name, suffix);  /* [RPAP - Feb 97: WIN32 Port] */
+  return open_named_file (path, mode, magic_num, err_mode);
+}
+
+
+
+
+
+
+/* This will create the specified file and set its magic number.
+
+   Mode may take on the following values
+   MG_ABORT    : causes an error message to be generated and the
+   program aborted if there is an error.
+   MG_MESSAGE  : causes a message to be generated and a NULL value to
+   be returned if there is an error.
+   MG_CONTINUE : causes a NULL value to be returned if there is an error.
+
+   On success if returns the FILE *. On failure it will return a NULL value
+   and possibly generate an error message, or it will exit the program with
+   an error message.   */
+FILE *
+create_named_file (const char *name, const char *mode,
+		   u_long magic_num, int err_mode)
+{
+  FILE *f = NULL;
+  char *err;
+  f = fopen (name, mode);
+
+  if (!f)
+    {
+      err = "Unable to open \"%s\"";
+      goto error;
+    }
+
+  if (magic_num)
+    HTONUL(magic_num);  /* [RPAP - Jan 97: Endian Ordering] */
+    if (fwrite (&magic_num, sizeof (magic_num), 1, f) != 1)
+      {
+	err = "Couldn't write magic number \"%s\"";
+	goto error;
+      }
+
+  return f;
+
+error:
+  if (f)
+    fclose (f);
+  if (err_mode == MG_ABORT)
+    FatalError (1, err, name);
+  if (err_mode == MG_MESSAGE)
+    Message (err, name);
+  return NULL;
+}
+
+
+
+
+
+
+
+/* This will create the specified file and set its magic number.
+
+   Mode may take on the following values
+   MG_ABORT    : causes an error message to be generated and the
+   program aborted if there is an error.
+   MG_MESSAGE  : causes a message to be generated and a NULL value to
+   be returned if there is an error.
+   MG_CONTINUE : causes a NULL value to be returned if there is an error.
+
+   On success if returns the FILE *. On failure it will return a NULL value
+   and possibly generate an error message, or it will exit the program with
+   an error message.   */
+FILE *
+create_file (const char *name, const char *suffix, const char *mode,
+	     u_long magic_num, int err_mode)
+{
+  char path[512];
+  if (!basepath)
+    set_basepath (getenv ("MGDATA"));
+  sprintf (path, FILE_NAME_FORMAT, basepath, name, suffix);  /* [RPAP - Feb 97: WIN32 Port] */
+  return create_named_file (path, mode, magic_num, err_mode);
+}
Index: /main/tags/2.25/gsdl/packages/mg/src/text/mg_files.h
===================================================================
--- /main/tags/2.25/gsdl/packages/mg/src/text/mg_files.h	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/mg/src/text/mg_files.h	(revision 21064)
@@ -0,0 +1,329 @@
+/**************************************************************************
+ *
+ * mg_files.h -- Routines for handling files for the auxillary programs
+ * Copyright (C) 1994  Neil Sharman
+ *
+ * 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.
+ *
+ * $Id$
+ *
+ **************************************************************************/
+
+#ifndef MG_FILES_H
+#define MG_FILES_H
+
+#include "sysfuncs.h"
+
+/* Magic numbers for the different types of files */
+
+#define GEN_MAGIC(a,b,c,d) ((unsigned long)(((a)<<24) + ((b)<<16) + \
+					    ((c)<<8) + (d)))
+
+#define MAGIC_XXXX		GEN_MAGIC('M','G', 0 , 0)
+#define MAGIC_STATS_DICT	GEN_MAGIC('M','G','S','D')
+#define MAGIC_AUX_DICT		GEN_MAGIC('M','G','A','D')
+#define MAGIC_FAST_DICT		GEN_MAGIC('M','G','F','D')
+#define MAGIC_DICT		GEN_MAGIC('M','G','D', 0 )
+#define MAGIC_STEM_BUILD	GEN_MAGIC('M','G','S', 0 )
+#define MAGIC_HASH		GEN_MAGIC('M','G','H', 0 )
+#define MAGIC_STEM		GEN_MAGIC('M','G','s', 0 )
+#define MAGIC_CHUNK		GEN_MAGIC('M','G','C', 0 )
+#define MAGIC_CHUNK_TRANS	GEN_MAGIC('M','G','c', 0 )
+#define MAGIC_TEXT		GEN_MAGIC('M','G','T', 0 )
+#define MAGIC_TEXI		GEN_MAGIC('M','G','t', 0 )
+#define MAGIC_TEXI_WGT		GEN_MAGIC('M','G','t','W')
+#define MAGIC_INVF		GEN_MAGIC('M','G','I', 0 )
+#define MAGIC_INVI		GEN_MAGIC('M','G','i', 0 )
+#define MAGIC_WGHT		GEN_MAGIC('M','G','W', 0 )
+#define MAGIC_WGHT_APPROX	GEN_MAGIC('M','G','w', 0 )
+#define MAGIC_PARAGRAPH		GEN_MAGIC('M','G','P', 0 )
+/* [RPAP - Jan 97: Stem Index Change] */
+#define MAGIC_STEM_1            GEN_MAGIC('M','G','s','1')
+#define MAGIC_STEM_2            GEN_MAGIC('M','G','s','2')
+#define MAGIC_STEM_3            GEN_MAGIC('M','G','s','3')
+
+#define IS_MAGIC(a) ((((u_long)(a)) & 0xffff0000) == MAGIC_XXXX)
+
+
+/* err_mode values for open_file and create_file */
+#define MG_ABORT 0
+#define MG_MESSAGE 1
+#define MG_CONTINUE 2
+
+
+
+
+
+/* File suffixes */
+
+
+/* The compression dictionary built by txt.pass1 */
+#ifdef SHORT_SUFFIX
+# define TEXT_STATS_DICT_SUFFIX	 ".tsd"
+#else
+# define TEXT_STATS_DICT_SUFFIX	 ".text.stats"
+#endif
+
+/* The compression dictionary built by text.pass1 and comp_dict.process */
+#ifdef SHORT_SUFFIX
+# define TEXT_DICT_SUFFIX	 ".td"
+#else
+# define TEXT_DICT_SUFFIX	 ".text.dict"
+#endif
+
+/* The compression dictionary built by mg_make_fast_dict */
+#ifdef SHORT_SUFFIX
+# define TEXT_DICT_FAST_SUFFIX	 ".tdf"
+#else
+# define TEXT_DICT_FAST_SUFFIX	 ".text.dict.fast"
+#endif
+
+/* The auxilary dictionary built by text.pass2 */
+#ifdef SHORT_SUFFIX
+# define TEXT_DICT_AUX_SUFFIX	 ".tda"
+#else
+# define TEXT_DICT_AUX_SUFFIX	 ".text.dict.aux"
+#endif
+
+/* The compressed text build by text.pass2 */
+#ifdef SHORT_SUFFIX
+# define TEXT_SUFFIX		 ".t"
+#else
+# define TEXT_SUFFIX		 ".text"
+#endif
+
+/* The combined compressed text index and document weight file */
+#ifdef SHORT_SUFFIX
+# define TEXT_IDX_WGT_SUFFIX	 ".tiw"
+#else
+# define TEXT_IDX_WGT_SUFFIX	 ".text.idx.wgt"
+#endif
+
+/* The compressed text index file */
+#ifdef SHORT_SUFFIX
+# define TEXT_IDX_SUFFIX	 	".ti"
+#else
+# define TEXT_IDX_SUFFIX	 	".text.idx"
+#endif
+
+/* The dictionary of stemmed words build by invf.pass1 and ivf.pass1 */
+#ifdef SHORT_SUFFIX
+# define INVF_DICT_SUFFIX         ".id"
+#else
+# define INVF_DICT_SUFFIX         ".invf.dict"
+#endif
+
+/* The dictionary of stemmed words build by stem.process */
+#ifdef SHORT_SUFFIX
+# define INVF_DICT_BLOCKED_SUFFIX ".idb"
+#else
+# define INVF_DICT_BLOCKED_SUFFIX ".invf.dict.blocked"
+#endif
+
+/* The exact document weights file build by make.weights, invf.pass2,
+   or ivf.pass2 */
+#ifdef SHORT_SUFFIX
+# define WEIGHTS_SUFFIX           ".w"
+#else
+# define WEIGHTS_SUFFIX           ".weight"
+#endif
+
+/* The approximate weights file built by make.weights */
+#ifdef SHORT_SUFFIX
+# define APPROX_WEIGHTS_SUFFIX    ".wa"
+#else
+# define APPROX_WEIGHTS_SUFFIX    ".weight.approx"
+#endif
+
+/* The inverted file build by invf.pass2 or ivf.pass2 */
+#ifdef SHORT_SUFFIX
+# define INVF_SUFFIX              ".i"
+#else
+# define INVF_SUFFIX              ".invf"
+#endif
+
+/* The inverted file index build by invf.pass2 or ivf.pass2 */
+#ifdef SHORT_SUFFIX
+# define INVF_IDX_SUFFIX          ".ii"
+#else
+# define INVF_IDX_SUFFIX          ".invf.idx"
+#endif
+
+/* The inverted file chunk descriptor built by ivf.pass1 */
+#ifdef SHORT_SUFFIX
+# define INVF_CHUNK_SUFFIX        ".ic"
+#else
+# define INVF_CHUNK_SUFFIX        ".invf.chunk"
+#endif
+
+/* The word index translation file built by ivf.pass1 */
+#ifdef SHORT_SUFFIX
+# define INVF_CHUNK_TRANS_SUFFIX  ".ict"
+#else
+# define INVF_CHUNK_TRANS_SUFFIX  ".invf.chunk.trans"
+#endif
+
+/* The hashed stemmed dictionary built by make.perf_hash */
+#ifdef SHORT_SUFFIX
+# define INVF_DICT_HASH_SUFFIX    ".idh"
+#else
+# define INVF_DICT_HASH_SUFFIX    ".invf.dict.hash"
+#endif
+
+/* The paragraph descriptior file built by invf.pass1 or ivf.pass1 */
+#ifdef SHORT_SUFFIX
+# define INVF_PARAGRAPH_SUFFIX    ".ip"
+#else
+# define INVF_PARAGRAPH_SUFFIX    ".invf.paragraph"
+#endif
+
+/* The trace file build by mg.builder. */
+#ifdef SHORT_SUFFIX
+# define TRACE_SUFFIX             ".trc"
+#else
+# define TRACE_SUFFIX             ".trace"
+#endif
+
+/* The compression stats file build by mg.builder. */
+#ifdef SHORT_SUFFIX
+# define COMPRESSION_STATS_SUFFIX ".cs"
+#else
+# define COMPRESSION_STATS_SUFFIX ".compression.stats"
+#endif
+
+/* [RPAP - Jan 97: Stem Index Change] */
+/* The casefolded index into the stemmed dictionary */
+#ifdef SHORT_SUFFIX
+# define INVF_DICT_BLOCKED_1_SUFFIX ".ib1"
+#else
+# define INVF_DICT_BLOCKED_1_SUFFIX ".invf.dict.blocked.1"
+#endif
+
+/* [RPAP - Jan 97: Stem Index Change] */
+/* The stemmed index into the stemmed dictionary */
+#ifdef SHORT_SUFFIX
+# define INVF_DICT_BLOCKED_2_SUFFIX ".ib2"
+#else
+# define INVF_DICT_BLOCKED_2_SUFFIX ".invf.dict.blocked.2"
+#endif
+
+/* [RPAP - Jan 97: Stem Index Change] */
+/* The casefolded and stemmed  index into the stemmed dictionary */
+#ifdef SHORT_SUFFIX
+# define INVF_DICT_BLOCKED_3_SUFFIX ".ib3"
+#else
+# define INVF_DICT_BLOCKED_3_SUFFIX ".invf.dict.blocked.3"
+#endif
+
+/* [RPAP - Feb 97: WIN32 Port] */
+#ifdef __WIN32__
+#define FILE_NAME_FORMAT "%s%s%s"
+#else
+#define FILE_NAME_FORMAT "%s/%s%s"
+#endif
+
+
+/* This sets the base path for all file operations */
+void set_basepath (const char *bp);
+
+
+/* return the currently defined basepath */
+char *get_basepath (void);
+
+
+
+
+/* This generates the name of a file. It places the name in the buffer
+   specified or if that is NULL it uses a static buffer. */
+char *make_name (const char *name, const char *suffix, char *buffer);
+
+
+
+
+
+
+
+/* This will open the specified file and check its magic number.
+   Mode may take on the following values
+   MG_ABORT    : causes an error message to be generated and the
+   program aborted if there is an error.
+   MG_MESSAGE  : causes a message to be generated and a NULL value to
+   be returned if there is an error.
+   MG_CONTINUE : causes a NULL value to be returned if there is an error.
+
+   On success if returns the FILE *. On failure it will return a NULL value
+   and possibly generate an error message, or it will exit the program with
+   an error message.   */
+FILE *open_named_file (const char *name, const char *mode,
+		       u_long magic_num, int err_mode);
+
+
+
+
+/* This will open the specified file and check its magic number.
+
+   err_mode may take on the following values
+   MG_ABORT    : causes an error message to be generated and the
+   program aborted if there is an error.
+   MG_MESSAGE  : causes a message to be generated and a NULL value to
+   be returned if there is an error.
+   MG_CONTINUE : causes a NULL value to be returned if there is an error.
+
+   On success if returns the FILE *. On failure it will return a NULL value
+   and possibly generate an error message, or it will exit the program with
+   an error message.   */
+FILE *open_file (const char *name, const char *suffix, const char *mode,
+		 u_long magic_num, int err_mode);
+
+
+
+
+
+/* This will create the specified file and set its magic number.
+
+   Mode may take on the following values
+   MG_ABORT    : causes an error message to be generated and the
+   program aborted if there is an error.
+   MG_MESSAGE  : causes a message to be generated and a NULL value to
+   be returned if there is an error.
+   MG_CONTINUE : causes a NULL value to be returned if there is an error.
+
+   On success if returns the FILE *. On failure it will return a NULL value
+   and possibly generate an error message, or it will exit the program with
+   an error message.   */
+FILE *create_named_file (const char *name, const char *mode,
+			 u_long magic_num, int err_mode);
+
+
+
+/* This will create the specified file and set its magic number.
+
+   err_mode may take on the following values
+   MG_ABORT    : causes an error message to be generated and the
+   program aborted if there is an error.
+   MG_MESSAGE  : causes a message to be generated and a NULL value to
+   be returned if there is an error.
+   MG_CONTINUE : causes a NULL value to be returned if there is an error.
+
+   On success if returns the FILE *. On failure it will return a NULL value
+   and possibly generate an error message, or it will exit the program with
+   an error message.   */
+FILE *create_file (const char *name, const char *suffix, const char *mode,
+		   u_long magic_num, int err_mode);
+
+
+
+
+#endif
Index: /main/tags/2.25/gsdl/packages/mg/src/text/mg_hilite_words.1
===================================================================
--- /main/tags/2.25/gsdl/packages/mg/src/text/mg_hilite_words.1	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/mg/src/text/mg_hilite_words.1	(revision 21064)
@@ -0,0 +1,95 @@
+.\"------------------------------------------------------------
+.\" Id - set Rv,revision, and Dt, Date using rcs-Id tag.
+.de Id
+.ds Rv \\$3
+.ds Dt \\$4
+..
+.Id $Id$
+.\"------------------------------------------------------------
+.TH mg_hilite_words 1 \*(Dt CITRI
+.SH NAME
+mg_hilite_words \- display text and highlight particular words which it contains
+.SH SYNOPSIS
+.B mg_hilite_words
+.if n .ti +9n
+[
+.B --stem_method [0-3]
+]
+.if n .ti +9n
+[
+.B --stemmer [english|lovin|french|simplefrench]
+]
+.if n .ti +9n
+[
+.B --style [bold|underline|italic|emphasis|strong]
+]
+.if n .ti +9n
+[
+.B --pager [less|more|html|???]
+]
+.if n .ti +9n
+.I list-of-words-to-highlight
+
+.SH DESCRIPTION
+.B mg_hilite_words
+reads text from stdin and outputs it into a pager such as
+less. It's command arguments include a list of stemmed words
+which if extracted from the text will be highlighted on the output
+using a highlighting style.
+
+It has been extended to output the highlighted text using html
+straight to stdout.
+
+.SH OPTIONS
+Options may appear in any order, but the
+.IR list-of-words-to-highlight ,
+must be last.
+.TP
+.B --stem_method [0-3]
+This option allows one to set the stemming method for the extraction of
+the words from the incoming text.
+This should match the way the inverted file index was created.
+The default is 3, which is fold and stem.
+.TP
+.B --stemmer [english|lovin|french|simplefrench]
+This option allows you to select the stemmer to use.  The
+default is the English stemmer.
+.TP
+.B --style [bold|underline|italic|emphasis|strong]
+This option sets the highlighting style.
+.IR Bold 
+and 
+.IR underline
+are utilised by the pager or for html output.
+.IR Italic,
+.IR emphasis,
+and
+.IR strong
+can only be used for html output.
+.TP
+.B --pager [less|more|html|???]
+One can use the standard 
+.IR less
+or
+.IR more
+pages for displaying the highlighted text.
+Or one can generate highlighted html using the paging setting of
+.IR html.
+One can also specify a custom pager of their own choosing (i.e. ???).
+.TP
+.B list-of-words-to-highlight
+Each word is taken as a command line argument.
+Each word should already be stemmed and folded according to
+the stem option.
+.SH USAGE
+This program was written primarily to be called by 
+.IR mgquery(1)
+.
+When the user selects the mode of "hilite" then this program
+is called for displaying the query-result documents instead of
+just the pager.
+.SH "SEE ALSO"
+.na
+.BR mgquery (1).
+
+
Index: /main/tags/2.25/gsdl/packages/mg/src/text/mg_hilite_words.c
===================================================================
--- /main/tags/2.25/gsdl/packages/mg/src/text/mg_hilite_words.c	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/mg/src/text/mg_hilite_words.c	(revision 21064)
@@ -0,0 +1,693 @@
+/**************************************************************************
+ *
+ * mg_hilite_words -- display text and highlight particular words which 
+ *                    it contains
+ * Copyright (C) 1994 Tim Shimmin
+ *
+ * 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.
+ *
+ * $Id$
+ *
+ **************************************************************************/
+
+static char *RCSID = "$Id$";
+
+#include "sysfuncs.h"
+
+#include "getopt.h"
+#include "messages.h"
+#include "local_strings.h"
+#include "stemmer.h"
+#include "words.h"
+
+
+/*
+ * Description
+ * -----------
+ *   Hilite_words reads text from stdin and outputs it into a pager such as
+ *   less. It's command arguments include a list of stemmed words 
+ *   which if extracted from the text will be highlighted on the output.
+ *
+ * Implementation
+ * --------------
+ *   Extracting of words - using PARSE_STEM_WORD & stemmer
+ *   
+ *   Highlighting of words - for standard pager:
+ *                             using back-space character code
+ *                             e.g. bolded a = "a\ba", underlined a = "_\ba"
+ *                         - for pager==html:
+ *                             use some of the standard html character 
+ *                             formatting tags
+ *
+ *   Storage of words - using hashtable (set) of size equalling a constant
+ *                      times the number of words
+ * 
+ * Usage
+ * -----
+ *   mg_hilite_words --stem_method [0-3] 
+ *                   --style [bold|underline|italic|emphasis|strong]
+ *                   --pager [less|more|html|???]
+ *                   --terminator [terminator-string]
+ *                   list-of-words-to-highlight
+ */
+
+/*
+ * Modifications:
+ *
+ * 21/Apr/95: To handle outputting html tags to stdout
+ *
+ */
+
+/* --- constants --- */
+
+/* highlighting styles */
+#define HILITE_MAX      5	/* the number of styles */
+#define BOLD 		0
+#define UNDERLINE	1
+#define ITALIC     	2
+#define EMPHASIS     	3
+#define STRONG     	4
+
+/* maximum length of line buffer */
+#define MAX_LINE_BUFFER 200
+
+/* set pager to this to get html hilited text to stdout */
+#define HTML_OUT "html"
+
+/* output types */
+#define PAGER 0
+#define HTML  1
+
+/* --- types --- */
+
+typedef u_char *Word;
+
+/* --- globals --- */
+
+/* keep in synch with constants */
+static char *hilite_names[] =
+{"bold", "underline", "italic", "emphasis", "strong"};
+static char *hilite_tags[] =
+{"B", "", "I", "EM", "STRONG"};
+static short hilite_style = BOLD;
+static char *pager = "less";
+static int stemmer_num = 0;	/* Lovin's stemmer */
+static int stem_method = 3;	/* fold & stem */
+static char **word_list;
+static int num_of_words = 0;
+static int output_type = PAGER;
+static char *terminator = NULL;
+
+/* --- prototypes --- */
+
+static Word copy_c_word (char *w);
+static void process_words (char **words, int num_of_words);
+static int get_line (u_char * line, int n, FILE * stream);
+static void process_text (FILE * input_file, FILE * output_file);
+static void copy_word (u_char * w1, u_char * w2);
+static void process_buffer (u_char * s_in, int len, FILE * output_file);
+static void output_word (u_char * s_start, u_char * s_finish, FILE * output_file);
+static void output_hilite_word (u_char * s_start, u_char * s_finish,
+				FILE * output_file);
+static void process_args (int argc, char *argv[]);
+static void print_line (u_char * line, int n, FILE * stream);
+
+
+/******************************** word set ************************************/
+
+#include "hash.h"
+#include "locallib.h"
+
+#define SIZE_FACTOR 2
+
+typedef Word *WordSet;
+static WordSet set_of_words = NULL;
+static int hash_size = 0;
+
+/* prototypes - set routines */
+static void set_create (int num_of_words);
+static void set_add (Word word);
+static int set_member (Word word);
+static void set_print (void);
+
+/* =========================================================================
+ * Function: set_print
+ * Description: 
+ * Input: 
+ * Output: 
+ * ========================================================================= */
+
+static void
+set_print (void)
+{
+  int i = 0;
+
+  for (i = 0; i < hash_size; i++)
+    {
+      Word word = set_of_words[i];
+
+      if (word)
+	{
+	  int len = *word++;
+
+	  fprintf (stderr, "[%d] = ", i);
+	  while (len--)
+	    fputc (*word++, stderr);
+	  fputc ('\n', stderr);
+	}
+    }
+
+}
+
+
+/* =========================================================================
+ * Function: set_create
+ * Description: 
+ *      Allocate memory for the set
+ * Input: 
+ * Output: 
+ * ========================================================================= */
+
+static void
+set_create (int num_of_words)
+{
+  WordSet set;
+
+  hash_size = prime (num_of_words * SIZE_FACTOR);
+  set = (WordSet) malloc (hash_size * sizeof (Word));
+  if (!set)
+    FatalError (1, "Runout of memory for word hashtable");
+  bzero ((char *) set, hash_size * sizeof (Word));  /* [RPAP - Feb 97: WIN32 Port] */
+
+  set_of_words = set;
+
+}
+
+/* =========================================================================
+ * Function: set_add
+ * Description: 
+ *      Add a string element to the set.
+ * Input: 
+ * Output: 
+ * ========================================================================= */
+
+static void
+set_add (Word word)
+{
+  int hash_val;
+  int hash_step;
+
+  HASH (hash_val, hash_step, word, hash_size);
+
+  /* loop around in case of collisions and need to step */
+  while (1)
+    {
+
+      Word entry = set_of_words[hash_val];
+
+      /* if doesn't exist then */
+      if (!entry)
+	{
+	  set_of_words[hash_val] = word;
+	  break;
+	}
+
+      /* if we have a matching word */
+      if (compare (entry, word) == 0)
+	break;
+
+      /* if collides with a different word */
+      hash_val = (hash_val + hash_step) % hash_size;
+
+    }
+}
+
+
+/* =========================================================================
+ * Function: set_member
+ * Description: 
+ *      Tests whether a string is a member of the set
+ * Input: 
+ * Output: 
+ * ========================================================================= */
+
+static int
+set_member (Word word)
+{
+  int hash_val;
+  int hash_step;
+
+  HASH (hash_val, hash_step, word, hash_size);
+
+  /* loop around in case of collisions and need to step */
+  while (1)
+    {
+
+      Word entry = set_of_words[hash_val];
+
+      /* if doesn't exist then */
+      if (!entry)
+	return 0;
+
+      /* if we have a matching word */
+      if (compare (entry, word) == 0)
+	return 1;
+
+      /* if collides with a different word */
+      hash_val = (hash_val + hash_step) % hash_size;
+
+    }
+}
+
+/******************************** end of word set ******************************/
+
+
+
+/* =========================================================================
+ * Function: copy_c_word
+ * Description: 
+ *      Allocate enough memory and copy word over
+ * Input: 
+ *      w = null terminated string (c_word)
+ * Output: 
+ *      word with length in 1st byte
+ * ========================================================================= */
+
+static Word
+copy_c_word (char *w)
+{
+  int len = strlen (w);
+  Word w_copy = (Word) malloc (len + 1);
+  Word w_ptr = NULL;
+  int j = 0;
+
+  if (!w_copy)
+    FatalError (1, "Not enough memory to copy a word");
+
+  w_copy[0] = len;
+  w_ptr = w_copy + 1;
+  for (j = 0; j < len; j++)
+    *w_ptr++ = *w++;
+
+  return w_copy;
+}
+
+/* =========================================================================
+ * Function: process_words
+ * Description: 
+ *      Go through the stemmed words and add to word set
+ * Input: 
+ * Output: 
+ * ========================================================================= */
+
+static void
+process_words (char **words, int num_of_words)
+{
+  int i = 0;
+
+  set_create (num_of_words);
+
+  for (i = 0; i < num_of_words; i++)
+    {
+      Word word = copy_c_word (words[i]);
+      set_add (word);
+    }
+
+}
+
+/* =========================================================================
+ * Function: get_line
+ * Description: 
+ *      Equivalent of fgets for u_char*.
+ *      But returns length of read-in line.
+ *      Expects to see a '\n' before an EOF
+ * Input: 
+ * Output: 
+ * ========================================================================= */
+
+static int
+get_line (u_char * line, int n, FILE * stream)
+{
+  int i = 0;
+  int ch = '\0';
+
+  while (1)
+    {
+      if (i == n)
+	return i;
+
+      ch = fgetc (stream);
+
+      if (ch == EOF)
+	{
+	  if (!feof (stream))
+	    FatalError (1, "Error on reading a line from stdin");
+	  return EOF;
+	}
+
+      if (ch == '\n')
+	return i;
+
+      *line++ = ch;
+      i++;
+    }
+
+}
+
+/* =========================================================================
+ * Function: print_line
+ * Description: 
+ * Input: 
+ * Output: 
+ * ========================================================================= */
+
+static void
+print_line (u_char * line, int n, FILE * stream)
+{
+
+  while (n--)
+    {
+      fputc (*line++, stream);
+    }
+  fputc ('\n', stream);
+
+}
+
+/* =========================================================================
+ * Function: process_text
+ * Description: 
+ *      Go through the text from input_file and highlight to output_file 
+ * Input: 
+ * Output: 
+ * ========================================================================= */
+
+static void
+process_text (FILE * input_file, FILE * output_file)
+{
+  static u_char line_buffer[MAX_LINE_BUFFER];
+
+
+  while (1)
+    {
+      int len = get_line (line_buffer, MAX_LINE_BUFFER, input_file);
+
+      if (len == EOF)
+	break;
+      process_buffer (line_buffer, len, output_file);
+
+    }
+}
+
+/* =========================================================================
+ * Function: copy_word
+ * Description: 
+ *      Copies w2 into w1. Assumes both have storage allocated.
+ * Input: 
+ * Output: 
+ * ========================================================================= */
+
+static void
+copy_word (u_char * w1, u_char * w2)
+{
+  int i;
+  int len = w2[0];
+
+  for (i = 0; i <= len; i++)
+    *w1++ = *w2++;
+
+}
+
+/* =========================================================================
+ * Function: process_buffer
+ * Description: 
+ *      Parse & stem words of line buffer
+ *      Based on the usage of PARSEing in other mg files.
+ * Input: 
+ * Output: 
+ * ========================================================================= */
+
+static void
+process_buffer (u_char * s_in, int len, FILE * output_file)
+{
+  u_char *end = s_in + len - 1;
+  u_char *s_start = NULL;
+
+  if (!inaword (s_in, end))
+    {
+      s_start = s_in;
+      PARSE_NON_STEM_WORD (s_in, end);
+      output_word (s_start, s_in - 1, output_file);
+    }
+
+  while (s_in <= end)
+    {
+      u_char word[MAXSTEMLEN + 1];
+
+      s_start = s_in;
+      PARSE_STEM_WORD (word, s_in, end);
+
+      stemmer (stem_method, stemmer_num, word);
+
+      if (set_member (word))	/* output with highlighting */
+	{
+	  output_hilite_word (s_start, s_start + word[0] - 1, output_file);
+	  s_start += word[0];	/* step over hilited output */
+	}
+      output_word (s_start, s_in - 1, output_file);
+
+      s_start = s_in;
+      PARSE_NON_STEM_WORD (s_in, end);
+      output_word (s_start, s_in - 1, output_file);
+
+    }				/*while */
+
+  fputc ('\n', output_file);
+  fflush (output_file);
+
+}				/*process_buffer */
+
+/* =========================================================================
+ * Function: output_word
+ * Description: 
+ *      Output a word which lies from s_start to s_finish in buffer
+ * Input: 
+ *      s_start = ptr to 1st char
+ *      s_finish = ptr to last char
+ * Output: 
+ * ========================================================================= */
+
+static void
+output_word (u_char * s_start, u_char * s_finish, FILE * output_file)
+{
+  while (s_start <= s_finish)
+    {
+      fputc (*s_start++, output_file);
+    }
+}
+
+
+/* =========================================================================
+ * Function: output_hilite_word
+ * Description: 
+ *      Highlight a word (with length in 1st byte)
+ *      Pager highlighting:
+ *        Highlighting is either by bolding or underlining using
+ *        the method used by UNIX utilities More(1) and Less(1)
+ *      HTML highlighting:
+ *        use the appropriate start and end tags around the word
+ * ========================================================================= */
+
+static void
+output_hilite_word (u_char * s_start, u_char * s_finish, FILE * output_file)
+{
+
+  if (output_type == HTML)
+    {
+      char *hilite_tag = hilite_tags[hilite_style];
+
+      /* print start tag */
+      fprintf (output_file, "<%s>", hilite_tag);
+
+      output_word (s_start, s_finish, output_file);
+
+      /* print end tag */
+      fprintf (output_file, "</%s>", hilite_tag);
+    }
+
+  else
+    /* PAGER */
+    {
+      /* use backspaces around each letter */
+      while (s_start <= s_finish)
+	{
+	  switch (hilite_style)
+	    {
+	    case BOLD:
+	      fputc (*s_start, output_file);
+	      fputc ('\b', output_file);
+	      fputc (*s_start, output_file);
+	      break;
+	    case UNDERLINE:
+	      fputc ('_', output_file);
+	      fputc ('\b', output_file);
+	      fputc (*s_start, output_file);
+	      break;
+	    default:
+	      fputc (*s_start, output_file);
+	    }
+	  s_start++;
+	}			/*while */
+    }
+}
+
+/* =========================================================================
+ * Function: process_args
+ * Description: 
+ *      sets the global variables:
+ *              hilite_style, pager, num_of_words, word_list
+ * Input: 
+ * Output: 
+ * ========================================================================= */
+
+struct option long_opts[] =
+{
+  {"style", required_argument, 0, 's'},
+  {"terminator", required_argument, 0, 't'},
+  {"pager", required_argument, 0, 'p'},
+  {"stem_method", required_argument, 0, 'm'},
+  {"stemmer", required_argument, 0, 'a'},
+  {0, 0, 0, 0}
+};
+
+static void
+process_args (int argc, char *argv[])
+{
+  int ch;
+
+
+  opterr = 0;
+  while ((ch = getopt_long (argc, argv, "s:p:t:m:a:", long_opts, (int *) 0)) != -1)
+    {
+      switch (ch)
+	{
+	case 's':
+	  {
+	    int i;
+	    for (i = 0; i < HILITE_MAX; i++)
+	      if (strcmp (optarg, hilite_names[i]) == 0)
+		break;
+
+	    if (i < HILITE_MAX)
+	      hilite_style = i;
+	  }
+	  break;
+	case 'a':
+	  stemmer_num = stemmernumber (optarg);
+	  break;
+	case 't':
+	  terminator = optarg;
+	  break;
+	case 'm':
+	  stem_method = atoi (optarg);
+	  break;
+	case 'p':
+	  pager = optarg;
+	  break;
+	default:
+	  FatalError (1, "Usage: \n"
+		      "mg_hilite_words --stem_method [0-3]\n"
+	  "                --stemmer [english|lovin|french|simplefrench]\n"
+	  "                --style [bold|underline|italic|emphasis|strong]\n"
+		      "                --pager [less|more|html|???]\n");
+	}
+    }
+
+  num_of_words = argc - optind;
+
+  word_list = &argv[optind];
+
+  /* fix up output type */
+  if (strcmp (pager, HTML_OUT) == 0)
+    output_type = HTML;
+  else
+    output_type = PAGER;
+
+}
+
+/* =========================================================================
+ * Function: main
+ * Description: 
+ * Input: 
+ * Output: 
+ * ========================================================================= */
+
+int
+main (int argc, char *argv[])
+{
+  FILE *output = NULL;
+
+  process_args (argc, argv);
+
+  /* set output file */
+  if (output_type == PAGER)
+/* [RPAP - Feb 97: WIN32 Port] */
+#ifdef __WIN32__
+    output = _popen (pager, "w");
+#else
+    output = popen (pager, "w");
+#endif
+  else
+    output = stdout;
+
+  if (!output)
+    FatalError (1, "Unable to run \"%s\"\n", pager);
+
+  if (num_of_words < 1)
+    {
+      int ch;
+
+      /* just echo the input */
+      /* better not to call this program at all ;-) */
+      while ((ch = fgetc (stdin)) != EOF)
+	{
+	  fputc (ch, output);
+	}
+    }
+  else
+    {
+      /* set up hash table for words */
+      process_words (word_list, num_of_words);
+
+
+      /* Go thru lines of text from stdin and 
+       * output words with hilite info if
+       * words parse into existence in the hash table 
+       */
+      process_text (stdin, output);
+    }
+
+  if (terminator)
+    fprintf (output, "%s\n", terminator);
+
+  if (output != stdout)
+/* [RPAP - Feb 97: WIN32 Port] */
+#ifdef __WIN32__
+    _pclose (output);
+#else
+    pclose (output);
+#endif
+
+  return 0;
+}
Index: /main/tags/2.25/gsdl/packages/mg/src/text/mg_invf_dict.1
===================================================================
--- /main/tags/2.25/gsdl/packages/mg/src/text/mg_invf_dict.1	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/mg/src/text/mg_invf_dict.1	(revision 21064)
@@ -0,0 +1,104 @@
+.\"------------------------------------------------------------
+.\" Id - set Rv,revision, and Dt, Date using rcs-Id tag.
+.de Id
+.ds Rv \\$3
+.ds Dt \\$4
+..
+.Id $Id$
+.\"------------------------------------------------------------
+.TH mg_invf_dict 1 \*(Dt CITRI
+.SH NAME
+mg_invf_dict \- build an `on-disk' stemmed dictionary
+.SH SYNOPSIS
+.B mg_invf_dict
+[
+.B \-h
+]
+[
+.B \-F
+]
+[
+.BI \-b " num"
+]
+[
+.BI \-d " directory"
+]
+.if n .ti +9n
+.BI \-f " name"
+.SH DESCRIPTION
+.B mg_invf_dict
+builds an `on-disk' stemmed dictionary from the
+compressed stemmed dictionary that the
+.BR mgquery (1)
+program can access.  Each entry in the dictionary contains the disk
+pointer to the associated inverted file entry, and various other pieces
+of information about the stemmed word.
+.SH OPTIONS
+Options may appear in any order.
+.TP "\w'\fB\-d\fP \fIdirectory\fP'u+2n"
+.B \-h
+This displays a usage line on
+.IR stderr .
+.TP
+.BI \-b " num"
+The dictionary is stored in blocks on disk; this option is used to set
+the block size.  The default is 4-KB blocks.
+.TP
+.B \-F
+This option causes the disk blocks to be aligned on the appropriate
+boundaries.  For example, if 4-KB blocks are used, they will be aligned
+in the file on 4-KB boundaries.
+.TP
+.BI \-d " directory"
+This specifies the directory where the document collection can be found.
+.TP
+.BI \-f " name"
+This specifies the base name of the document collection.
+.SH ENVIRONMENT
+.TP "\w'\fBMGDATA\fP'u+2n"
+.SB MGDATA
+If this environment variable exists, then its value is used as the
+default directory where the
+.BR mg (1)
+collection files are.  If this variable does not exist, then the
+directory \*(lq\fB.\fP\*(rq is used by default.  The command line
+option
+.BI \-d " directory"
+overrides the directory in
+.BR MGDATA .
+.SH FILES
+.TP 20
+.B *.invf
+Inverted file.
+.TP
+.B *.invf.dict.build
+Compressed stemmed dictionary.
+.TP
+.B *.invf.dict
+The `on-disk' stemmed dictionary.
+.TP
+.B *.invf.idx
+The index into the inverted file.
+.SH "SEE ALSO"
+.na
+.BR mg (1),
+.BR mg_compression_dict (1),
+.BR mg_fast_comp_dict (1),
+.BR mg_get (1),
+.BR mg_invf_dump (1),
+.BR mg_invf_rebuild (1),
+.BR mg_passes (1),
+.BR mg_perf_hash_build (1),
+.BR mg_text_estimate (1),
+.BR mg_weights_build (1),
+.BR mgbilevel (1),
+.BR mgbuild (1),
+.BR mgdictlist (1),
+.BR mgfelics (1),
+.BR mgquery (1),
+.BR mgstat (1),
+.BR mgtic (1),
+.BR mgticbuild (1),
+.BR mgticdump (1),
+.BR mgticprune (1),
+.BR mgticstat (1).
Index: /main/tags/2.25/gsdl/packages/mg/src/text/mg_invf_dict.c
===================================================================
--- /main/tags/2.25/gsdl/packages/mg/src/text/mg_invf_dict.c	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/mg/src/text/mg_invf_dict.c	(revision 21064)
@@ -0,0 +1,344 @@
+/**************************************************************************
+ *
+ * mg_invf_dict.c -- Program to build the blocked stemmed dictionary
+ * Copyright (C) 1994  Neil Sharman
+ *
+ * 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.
+ *
+ * $Id$
+ *
+ **************************************************************************/
+
+#include "sysfuncs.h"
+
+#include "memlib.h"
+#include "messages.h"
+#include "netorder.h"  /* [RPAP - Jan 97: Endian Ordering] */
+
+#include "mg_files.h"
+#include "invf.h"
+#include "locallib.h"
+#include "words.h"
+#include "mg.h"
+
+/*
+   $Log$
+   Revision 1.1  1999/08/10 21:18:08  sjboddie
+   renamed mg-1.3d directory mg
+
+   Revision 1.2  1998/11/25 07:55:45  rjmcnab
+
+   Modified mg to that you can specify the stemmer you want
+   to use via a command line option. You specify it to
+   mg_passes during the build process. The number of the
+   stemmer that you used is stored within the inverted
+   dictionary header and the stemmed dictionary header so
+   the correct stemmer is used in later stages of building
+   and querying.
+
+   Revision 1.1  1998/11/17 09:35:03  rjmcnab
+   *** empty log message ***
+
+   * Revision 1.4  1994/11/29  00:32:00  tes
+   * Committing the new merged files and changes.
+   *
+   * Revision 1.3  1994/10/20  03:56:56  tes
+   * I have rewritten the boolean query optimiser and abstracted out the
+   * components of the boolean query.
+   *
+   * Revision 1.2  1994/09/20  04:41:49  tes
+   * For version 1.1
+   *
+ */
+
+static char *RCSID = "$Id$";
+
+int block_size = 1024 * 4;
+
+int force = 0;
+
+static void process_files (char *filename);
+
+int main (int argc, char **argv)
+{
+  char *file_name = "";
+  int ch;
+  msg_prefix = argv[0];
+  opterr = 0;
+  msg_prefix = argv[0];
+  while ((ch = getopt (argc, argv, "f:d:b:Fh")) != -1)
+    switch (ch)
+      {
+      case 'f':		/* input file */
+	file_name = optarg;
+	break;
+      case 'd':
+	set_basepath (optarg);
+	break;
+      case 'b':
+	block_size = atoi (optarg);
+	break;
+      case 'F':
+	force = 1;
+	break;
+      case 'h':
+      case '?':
+	fprintf (stderr, "usage: %s [-f input_file]"
+		 "[-d data directory] [-b num] [-F] [-h]\n", argv[0]);
+	exit (1);
+      }
+
+  process_files (file_name);
+  return 0;
+}
+
+
+
+
+static void 
+process_files (char *filename)
+{
+  FILE *id, *idb, *tmp, *ii;
+  unsigned long i, pos, num, First_word, invf_ptr, invf_len;
+  unsigned long last_ptr = 0;
+  char *FName;
+  struct invf_dict_header idh;
+  struct stem_dict_header sdh;
+  u_char prev[MAXSTEMLEN + 1];
+  u_char *buffer;
+  unsigned short *pointers;
+  int buf_in_use;
+  unsigned short ptrs_in_use, word_num;
+
+  id = open_file (filename, INVF_DICT_SUFFIX, "rb", MAGIC_STEM_BUILD, MG_ABORT);  /* [RPAP - Feb 97: WIN32 Port] */
+
+  ii = open_file (filename, INVF_IDX_SUFFIX, "rb", MAGIC_INVI, MG_ABORT);  /* [RPAP - Feb 97: WIN32 Port] */
+
+  idb = create_file (filename, INVF_DICT_BLOCKED_SUFFIX, "w+b", MAGIC_STEM,
+		     MG_ABORT);  /* [RPAP - Feb 97: WIN32 Port] */
+
+  FName = make_name (filename, ".tmp", NULL);
+  if (!(tmp = fopen (FName, "w+b")))  /* [RPAP - Feb 97: WIN32 Port] */
+    FatalError (1, "Unable to open \"%s\".\n", FName);
+
+  /* Delete the file now */
+  unlink (FName);
+
+  fread (&idh, sizeof (idh), 1, id);
+  /* [RPAP - Jan 97: Endian Ordering] */
+  NTOHUL(idh.lookback);
+  NTOHUL(idh.dict_size);
+  NTOHUL(idh.total_bytes);
+  NTOHUL(idh.index_string_bytes);
+  NTOHD(idh.input_bytes); /* [RJM 07/97: 4G limit] */
+  NTOHUL(idh.num_of_docs);
+  NTOHUL(idh.static_num_of_docs);
+  NTOHUL(idh.num_of_words);
+  NTOHUL(idh.stemmer_num);
+  NTOHUL(idh.stem_method);
+
+  sdh.lookback = idh.lookback;
+  sdh.block_size = block_size;
+  sdh.num_blocks = 0;
+  sdh.index_chars = 0;
+  sdh.blocks_start = 0;
+  sdh.num_of_docs = idh.num_of_docs;
+  sdh.static_num_of_docs = idh.static_num_of_docs;
+  sdh.num_of_words = idh.num_of_words;
+  sdh.stemmer_num = idh.stemmer_num;
+  sdh.stem_method = idh.stem_method;
+  sdh.indexed = 0;  /* [RPAP - Jan 97: Stem Index Change] */
+
+  fwrite (&sdh, sizeof (sdh), 1, idb);
+
+  if (!(buffer = Xmalloc (block_size + 512)))
+    FatalError (1, "Unable to allocate memory for \"buffer\"\n");
+  if (!(pointers = Xmalloc (block_size + 512)))
+    FatalError (1, "Unable to allocate memory for \"buffer\"\n");
+
+  buf_in_use = 0;
+  pos = 0;
+  word_num = 0;
+  ptrs_in_use = 0;
+  First_word = 0;
+  for (i = 0; i < idh.dict_size; i++)
+    {
+      register unsigned long extra, copy, suff;
+      unsigned long wcnt, fcnt;
+
+      /* build a new word on top of prev */
+      copy = getc (id);
+      suff = getc (id);
+      *prev = copy + suff;
+      fread (prev + copy + 1, sizeof (u_char), suff, id);
+
+      /* read other data, but no need to store it */
+      fread (&fcnt, sizeof (fcnt), 1, id);
+      fread (&wcnt, sizeof (wcnt), 1, id);
+
+      /* [RPAP - Jan 97: Endian Ordering] */
+      NTOHUL(fcnt);
+      NTOHUL(wcnt);
+
+      /* read in the inverted file position */
+      fread (&invf_ptr, sizeof (invf_ptr), 1, ii);
+      NTOHUL(invf_ptr);  /* [RPAP - Jan 97: Endian Ordering] */
+      if (word_num % idh.lookback == 0)
+	extra = copy + sizeof (*pointers);
+      else
+	extra = 0;
+      if ((ptrs_in_use + 1) * sizeof (*pointers) + sizeof (ptrs_in_use) + extra +
+	  buf_in_use + suff + 1 + sizeof (fcnt) + sizeof (wcnt) +
+	  sizeof (First_word) + sizeof (invf_ptr) + sizeof (invf_len) > block_size)
+	{
+	  int chunk;
+	  invf_len = invf_ptr - last_ptr;
+
+	  /* [RPAP - Jan 97: Endian Ordering] */
+	  HTONUL(First_word);
+	  HTONUL(invf_len);
+	  HTONUS(word_num);
+
+	  fwrite (&First_word, sizeof (First_word), 1, tmp);
+	  fwrite (&invf_len, sizeof (invf_len), 1, tmp);
+	  fwrite (&word_num, sizeof (word_num), 1, tmp);
+	  fwrite (pointers, sizeof (*pointers), ptrs_in_use, tmp);
+	  fwrite (buffer, sizeof (u_char), buf_in_use, tmp);
+	  bzero ((char *) buffer, block_size);
+	  chunk = buf_in_use + ptrs_in_use * sizeof (*pointers) +
+	    sizeof (ptrs_in_use) + sizeof (First_word) + sizeof (invf_len);
+	  if (force && chunk < block_size)
+	    {
+	      fwrite (buffer, sizeof (u_char), block_size - chunk, tmp);
+	      chunk = block_size;
+	    }
+
+	  pos += chunk;
+
+	  buf_in_use = 0;
+	  word_num = 0;
+	  ptrs_in_use = 0;
+	  sdh.num_blocks++;
+	}
+
+      if (word_num % idh.lookback == 0)
+	{
+	  HTONUS2(buf_in_use, pointers[ptrs_in_use++]);  /* [RPAP - Jan 97: Endian Ordering] */
+	  suff += copy;
+	  copy = 0;
+	}
+      buffer[buf_in_use++] = copy;
+      buffer[buf_in_use++] = suff;
+      bcopy ((char *) (prev + copy + 1), (char *) (buffer + buf_in_use), suff);
+      buf_in_use += suff;
+      HTONUL(fcnt);  /* [RPAP - Jan 97: Endian Ordering] */
+      bcopy ((char *) &fcnt, (char *) (buffer + buf_in_use), sizeof (fcnt));
+      buf_in_use += sizeof (fcnt);
+      HTONUL(wcnt);  /* [RPAP - Jan 97: Endian Ordering] */
+      bcopy ((char *) &wcnt, (char *) (buffer + buf_in_use), sizeof (wcnt));
+      buf_in_use += sizeof (wcnt);
+      last_ptr = invf_ptr;
+      HTONUL(invf_ptr);  /* [RPAP - Jan 97: Endian Ordering] */
+      bcopy ((char *) &invf_ptr, (char *) (buffer + buf_in_use), sizeof (invf_ptr));
+      NTOHUL(invf_ptr);  /* [RPAP - Jan 97: Endian Ordering] */
+      buf_in_use += sizeof (invf_ptr);
+      if (buf_in_use + ptrs_in_use * sizeof (*pointers) +
+	  sizeof (ptrs_in_use) > block_size)
+	FatalError (1, "Fatal Internal Error # 34876234\n");
+      if (word_num == 0)
+	{
+	  fwrite (prev, sizeof (u_char), *prev + 1, idb);
+	  HTONUL(pos);  /* [RPAP - Jan 97: Endian Ordering] */
+	  fwrite (&pos, sizeof (pos), 1, idb);
+	  NTOHUL(pos);  /* [RPAP - Jan 97: Endian Ordering] */
+	  sdh.index_chars += *prev + 1;
+	  First_word = i;
+	}
+      word_num++;
+    }
+  if (buf_in_use)
+    {
+      int chunk;
+      fread (&invf_ptr, sizeof (invf_ptr), 1, ii);
+      NTOHUL(invf_ptr);  /* [RPAP - Jan 97: Endian Ordering] */
+      invf_len = invf_ptr - last_ptr;
+
+      /* [RPAP - Jan 97: Endian Ordering] */
+      HTONUL(First_word);
+      HTONUL(invf_len);
+      HTONUS(word_num);
+
+      fwrite (&First_word, sizeof (First_word), 1, tmp);
+      fwrite (&invf_len, sizeof (invf_len), 1, tmp);
+      fwrite (&word_num, sizeof (word_num), 1, tmp);
+      fwrite (pointers, sizeof (*pointers), ptrs_in_use, tmp);
+      fwrite (buffer, sizeof (u_char), buf_in_use, tmp);
+      bzero ((char *) buffer, block_size);
+      chunk = buf_in_use + ptrs_in_use * sizeof (*pointers) +
+	sizeof (ptrs_in_use) + sizeof (First_word) + sizeof (invf_len);
+      if (force && chunk < block_size)
+	{
+	  fwrite (buffer, sizeof (u_char), block_size - chunk, tmp);
+	  chunk = block_size;
+	}
+
+      sdh.num_blocks++;
+    }
+  fclose (id);
+  fclose (ii);
+
+  rewind (tmp);
+  sdh.blocks_start = sdh.index_chars + sizeof (u_long) + sizeof (sdh) +
+    sdh.num_blocks * sizeof (pos);
+  if (force)
+    {
+      int amount;
+      amount = sdh.blocks_start % block_size;
+      if (amount != 0)
+	{
+	  bzero ((char *) buffer, block_size);
+	  fwrite (buffer, sizeof (u_char), block_size - amount, idb);
+	  sdh.blocks_start += block_size - amount;
+	}
+    }
+
+  while ((num = fread (buffer, sizeof (u_char), block_size, tmp)) != 0)
+    fwrite (buffer, sizeof (u_char), num, idb);
+  fclose (tmp);
+
+  /* skip over the magic number */
+  fseek (idb, sizeof (u_long), 0);
+
+  /* [RPAP - Jan 97: Endian Ordering] */
+  HTONUL(sdh.lookback);
+  HTONUL(sdh.block_size);
+  HTONUL(sdh.num_blocks);
+  HTONUL(sdh.blocks_start);
+  HTONUL(sdh.index_chars);
+  HTONUL(sdh.num_of_docs);
+  HTONUL(sdh.static_num_of_docs);
+  HTONUL(sdh.num_of_words);
+  HTONUL(sdh.stemmer_num);
+  HTONUL(sdh.stem_method);
+  HTONUL(sdh.indexed);
+
+  fwrite (&sdh, sizeof (sdh), 1, idb);
+  fclose (idb);
+
+
+  Message ("Block size = %d\n", block_size);
+  Message ("Number of blocks written = %d\n", NTOHUL(sdh.num_blocks));
+
+}
Index: /main/tags/2.25/gsdl/packages/mg/src/text/mg_invf_dump.1
===================================================================
--- /main/tags/2.25/gsdl/packages/mg/src/text/mg_invf_dump.1	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/mg/src/text/mg_invf_dump.1	(revision 21064)
@@ -0,0 +1,142 @@
+.\"------------------------------------------------------------
+.\" Id - set Rv,revision, and Dt, Date using rcs-Id tag.
+.de Id
+.ds Rv \\$3
+.ds Dt \\$4
+..
+.Id $Id$
+.\"------------------------------------------------------------
+.TH mg_invf_dump 1 \*(Dt CITRI
+.SH NAME
+mg_invf_dump \- Dump out an inverted file in ASCII
+.SH SYNOPSIS
+.B mg_invf_dump
+[
+.B \-h
+]
+[
+.B \-b
+]
+[
+.B \-w
+]
+[
+.B \-t
+]
+[
+.BI \-d " directory"
+]
+.BI \-f " name"
+.SH DESCRIPTION
+This program dumps out an inverted file produced by the
+.BR mg (1)
+system as ASCII numbers.  This program could be used in conjunction
+with
+.BR mgdictlist (1)
+to write simple shell programs that work with the inverted files.  The
+output from the program looks something like this:
+.LP
+.RS
+.ft 3
+.nf
+6 337
+1
+ 1 1
+1
+ 5 1
+1
+ 2 1
+1
+ 1 1
+4
+ 1 3
+ 2 7
+ 3 2
+ 5 2
+1
+ 1 1
+ . . .
+.fi
+.ft
+.RE
+The first number (6) is the number of documents in the collection.  It
+is followed by the number of different terms in the collection.  For
+each term, the number of different documents it occurs in follows. The
+document numbers that the term occurs in are listed next.  If
+.B \-w
+is specified, then the number of times the term occurred in the
+document is printed alongside the document number.
+If
+.B \-t
+is specified, the term itself is also displayed in quotes.
+.SH OPTIONS
+Options may appear in any order.
+.TP "\w'\fB\-d\fP \fIdirectory\fP'u+2n"
+.B \-h
+This displays a usage line on
+.IR stderr .
+.TP
+.B \-b
+This option will cause the output from the program to be in fixed-size
+binary numbers, rather than in ASCII.
+.TP
+.B \-w
+If the inverted file is a level-2 or level-3 inverted file, this causes
+the word counts per document to be output.
+.TP
+.B \-t
+This option causes each term to be displayed along with the number of
+documents it appears in. The term is printed in quotes,
+as in "the".
+.TP
+.BI \-d " directory"
+This specifies the directory where the document collection can be found.
+.TP
+.BI \-f " name"
+This specifies the base name of the document collection.
+.SH ENVIRONMENT
+.TP "\w'\fBMGDATA\fP'u+2n"
+.SB MGDATA
+If this environment variable exists, then its value is used as the
+default directory where the
+.BR mg (1)
+collection files are.  If this variable does not exist, then the
+directory \*(lq\fB.\fP\*(rq is used by default.  The command line
+option
+.BI \-d " directory"
+overrides the directory in
+.BR MGDATA .
+.SH FILES
+.TP 20
+.B *.invf.dict
+The compressed stemmed dictionary.
+.TP
+.B *.invf.ORG
+The original inverted file saved by
+.BR mg_invf_rebuild .
+.TP
+.B *.invf
+The inverted file.
+.SH "SEE ALSO"
+.na
+.BR mg (1),
+.BR mg_compression_dict (1),
+.BR mg_fast_comp_dict (1),
+.BR mg_get (1),
+.BR mg_invf_dict (1),
+.BR mg_invf_rebuild (1),
+.BR mg_passes (1),
+.BR mg_perf_hash_build (1),
+.BR mg_text_estimate (1),
+.BR mg_weights_build (1),
+.BR mgbilevel (1),
+.BR mgbuild (1),
+.BR mgdictlist (1),
+.BR mgfelics (1),
+.BR mgquery (1),
+.BR mgstat (1),
+.BR mgtic (1),
+.BR mgticbuild (1),
+.BR mgticdump (1),
+.BR mgticprune (1),
+.BR mgticstat (1).
Index: /main/tags/2.25/gsdl/packages/mg/src/text/mg_invf_dump.c
===================================================================
--- /main/tags/2.25/gsdl/packages/mg/src/text/mg_invf_dump.c	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/mg/src/text/mg_invf_dump.c	(revision 21064)
@@ -0,0 +1,222 @@
+/**************************************************************************
+ *
+ * mg_invf_dump.c -- Program to dump uot an inverted fil
+ * Copyright (C) 1994  Neil Sharman
+ *
+ * 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.
+ *
+ * $Id$
+ *
+ **************************************************************************/
+
+#include "sysfuncs.h"
+
+#include "messages.h"
+#include "timing.h"
+#include "bitio_m.h"
+#include "bitio_m_stdio.h"
+#include "bitio_gen.h"
+#include "netorder.h"  /* [RPAP - Jan 97: Endian Ordering] */
+
+#include "mg_files.h"
+#include "locallib.h"
+#include "words.h"
+#include "invf.h"
+
+extern unsigned long S_btg;
+
+/*
+   $Log$
+   Revision 1.1  1999/08/10 21:18:09  sjboddie
+   renamed mg-1.3d directory mg
+
+   Revision 1.2  1998/11/25 07:55:46  rjmcnab
+
+   Modified mg to that you can specify the stemmer you want
+   to use via a command line option. You specify it to
+   mg_passes during the build process. The number of the
+   stemmer that you used is stored within the inverted
+   dictionary header and the stemmed dictionary header so
+   the correct stemmer is used in later stages of building
+   and querying.
+
+   Revision 1.1  1998/11/17 09:35:05  rjmcnab
+   *** empty log message ***
+
+   * Revision 1.3  1994/11/29  00:32:01  tes
+   * Committing the new merged files and changes.
+   *
+   * Revision 1.2  1994/09/20  04:41:50  tes
+   * For version 1.1
+   *
+ */
+
+static char *RCSID = "$Id$";
+
+
+
+static void process_files (char *filename);
+
+int binary = 0;
+int word_counts = 0;
+int term_dump = 0;
+
+
+int main (int argc, char **argv)
+{
+  ProgTime start;
+  char *dir_name, *file_name = "";
+  int ch;
+  msg_prefix = argv[0];
+  dir_name = getenv ("MGDATA");
+  opterr = 0;
+  msg_prefix = argv[0];
+  while ((ch = getopt (argc, argv, "hbwtf:d:")) != -1)
+    switch (ch)
+      {
+      case 'f':		/* input file */
+	file_name = optarg;
+	break;
+      case 'd':
+        set_basepath(optarg);
+	break;
+      case 'b':
+	binary = 1;
+	break;
+      case 'w':
+	word_counts = 1;
+	break;
+      case 't':
+	term_dump = 1;
+	break;
+      case 'h':
+      case '?':
+	fprintf (stderr, "usage: %s [-h] [-b] [-w] [-t] [-f input_file]"
+		 "[-d data directory]\n", argv[0]);
+	exit (1);
+      }
+  GetTime (&start);
+  process_files (file_name);
+  Message ("%s\n", ElapsedTime (&start, NULL));
+  return 0;
+}
+
+static void 
+process_files (char *name)
+{
+  unsigned long N, Nstatic, k;
+  FILE *dict;
+  FILE *invf;
+  struct invf_dict_header idh;
+  struct invf_file_header ifh;
+  int i;  /* [RPAP - Jan 97: Endian Ordering] */
+
+  dict = open_file (name, INVF_DICT_SUFFIX, "rb", MAGIC_STEM_BUILD, MG_ABORT);  /* [RPAP - Feb 97: WIN32 Port] */
+
+  fread ((char *) &idh, sizeof (idh), 1, dict);
+
+  /* [RPAP - Jan 97: Endian Ordering] */
+  NTOHUL(idh.lookback);
+  NTOHUL(idh.dict_size);
+  NTOHUL(idh.total_bytes);
+  NTOHUL(idh.index_string_bytes);
+  NTOHD(idh.input_bytes); /* [RJM 07/97: 4G limit] */
+  NTOHUL(idh.num_of_docs);
+  NTOHUL(idh.static_num_of_docs);
+  NTOHUL(idh.num_of_words);
+  NTOHUL(idh.stemmer_num);
+  NTOHUL(idh.stem_method);
+
+  if (!(invf = open_file (name, INVF_SUFFIX ".ORG", "rb", MAGIC_INVF, MG_CONTINUE)))  /* [RPAP - Feb 97: WIN32 Port] */
+    invf = open_file (name, INVF_SUFFIX, "rb", MAGIC_INVF, MG_ABORT);  /* [RPAP - Feb 97: WIN32 Port] */
+
+  fread ((char *) &ifh, sizeof (ifh), 1, invf);
+
+  /* [RPAP - Jan 97: Endian Ordering] */
+  NTOHUL(ifh.no_of_words);
+  NTOHUL(ifh.no_of_ptrs);
+  NTOHUL(ifh.skip_mode);
+  for (i = 0; i < 16; i++)
+    NTOHUL(ifh.params[i]);
+  NTOHUL(ifh.InvfLevel);
+
+  if (ifh.skip_mode != 0)
+    FatalError (1, "The invf file contains skips. Unable to dump.");
+
+  DECODE_START (invf)
+    N = idh.num_of_docs;
+  Nstatic = idh.static_num_of_docs;
+  if (binary)
+    {
+      fwrite ((char *) &N, sizeof (N), 1, stdout);
+      fwrite ((char *) &ifh.no_of_words, sizeof (ifh.no_of_words), 1, stdout);
+    }
+  else
+    printf ("%ld %ld\n", N, ifh.no_of_words);
+  for (k = 0; k < ifh.no_of_words; k++)
+    {
+      int i, blk, doc;
+      register unsigned long suff, prefix;
+      unsigned long fcnt, wcnt;
+      char term[MAXSTEMLEN + 1];
+
+      prefix = fgetc (dict);
+      suff = fgetc (dict);
+      fread (&term[prefix], sizeof (char), suff, dict);
+      fread ((char *) &fcnt, sizeof (fcnt), 1, dict);
+      fread ((char *) &wcnt, sizeof (wcnt), 1, dict);
+      term[prefix + suff] = '\0';
+
+      /* [RPAP - Jan 97: Endian Ordering] */
+      NTOHUL(fcnt);
+      NTOHUL(wcnt);
+
+      if (binary)
+	fwrite ((char *) &fcnt, sizeof (fcnt), 1, stdout);
+      else
+	{
+	  if (term_dump)
+	    printf ("%ld    \"%s\"\n", fcnt, term);
+	  else
+	    printf ("%ld\n", fcnt);
+	}
+      blk = BIO_Bblock_Init (Nstatic, fcnt);
+      for (doc = i = 0; i < fcnt; i++)
+	{
+	  int num;
+	  BBLOCK_DECODE (num, blk);
+	  doc += num;
+	  if (binary)
+	    fwrite ((char *) &doc, sizeof (doc), 1, stdout);
+	  else
+	    printf (" %d", doc);
+	  if (ifh.InvfLevel >= 2)
+	    {
+	      int count;
+	      GAMMA_DECODE (count);
+	      if (word_counts)
+		if (binary)
+		  fwrite ((char *) &count, sizeof (count), 1, stdout);
+		else
+		  printf (" %d", count);
+	    }
+	  if (!binary)
+	    putchar ('\n');
+	}
+      while (__btg)
+	DECODE_BIT;
+    }
+  DECODE_DONE
+}
Index: /main/tags/2.25/gsdl/packages/mg/src/text/mg_invf_merge.1
===================================================================
--- /main/tags/2.25/gsdl/packages/mg/src/text/mg_invf_merge.1	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/mg/src/text/mg_invf_merge.1	(revision 21064)
@@ -0,0 +1,112 @@
+.\"------------------------------------------------------------
+.\" Id - set Rv,revision, and Dt, Date using rcs-Id tag.
+.de Id
+.ds Rv \\$3
+.ds Dt \\$4
+..
+.Id $Id$
+.\"------------------------------------------------------------
+.TH mg_invf_merge 1 \*(Dt CITRI
+.SH NAME
+mg_invf_merge \- Merge two inverted files and stemmed dictionaries
+.SH SYNOPSIS
+.B mg_invf_merge
+[
+.B \-h
+]
+[
+.B \-s
+]
+[
+.B \-w
+]
+[
+.BI \-d " directory"
+]
+.BI \-f " name"
+.SH DESCRIPTION
+This program takes two
+.BR mg (1)
+database compressed text files and appends the second to
+the first.
+It is part of the
+.BR mgmerge (1)
+addition to the
+.BR mg (1)
+package.
+.SH OPTIONS
+Options may appear in any order.
+.TP "\w'\fB\-d\fP \fIdirectory\fP'u+2n"
+.B \-h
+This displays a usage line on
+.IR stderr .
+.TP
+.B \-s
+This option will cause a slow merge to be performed on the inverted files,
+where each inverted file entry is decoded and recoded.
+The default is a fast merge. Accumulated fast merges slowly degrade
+compression performance on the resulting inverted file so
+a periodic slow merge is recommended.
+.TP
+.B \-w
+By default the database .weights file is updated with
+new weights for the new documents in
+.B mg_text_merge.
+The
+.B -w
+option turns this step off.
+.TP
+.BI \-d " directory"
+This specifies the directory where the document collection can be found.
+.TP
+.BI \-f " name"
+This specifies the base name of the document collection.
+.SH ENVIRONMENT
+.TP "\w'\fBMGDATA\fP'u+2n"
+.SB MGDATA
+If this environment variable exists, then its value is used as the
+default directory where the
+.BR mg (1)
+collection files are.  If this variable does not exist, then the
+directory \*(lq\fB.\fP\*(rq is used by default.  The command line
+option
+.BI \-d " directory"
+overrides the directory in
+.BR MGDATA .
+.SH FILES
+.TP 20
+.B *.old.invf.dict
+The old compressed stemmed dictionary.
+.TP
+.B *.new.invf.dict
+The new compressed stemmed dictionary.
+.TP
+.B *.invf.dict
+The resulting merged compressed stemmed dictionary.
+.TP
+.B *.old.invf.ORG
+The original inverted file saved by
+.BR mg_invf_rebuild .
+.TP
+.B *.old.invf
+The old inverted file.
+.TP
+.B *.new.invf
+The new inverted file.
+.TP
+.B *.invf
+The resulting merged inverted file.
+.TP
+.B *.weight
+The exact weights file.
+.TP
+.SH "SEE ALSO"
+.na
+.BR mg (1),
+.BR mgmerge (1),
+.BR mg_get_merge (1),
+.BR mg_text_merge (1),
+.BR mg_invf_rebuild (1),
+.BR mg_invf_dict (1),
+.BR mg_weights_build (1),
+.BR mgquery (1).
Index: /main/tags/2.25/gsdl/packages/mg/src/text/mg_invf_merge.c
===================================================================
--- /main/tags/2.25/gsdl/packages/mg/src/text/mg_invf_merge.c	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/mg/src/text/mg_invf_merge.c	(revision 21064)
@@ -0,0 +1,852 @@
+/**************************************************************************
+ *
+ * mg_invf_merge.c -- description
+ * Copyright (C) 1995  Shane Hudson (shane@cosc.canterbury.ac.nz)
+ *
+ * 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.
+ *
+ * Last edited:  31 March, 1995 
+ * $Id$
+ *
+ **************************************************************************/
+
+#include "sysfuncs.h"
+
+#include "memlib.h"
+#include "locallib.h"
+#include "local_strings.h"
+#include "messages.h"
+#include "timing.h"
+#include "netorder.h"  /* [RPAP - Jan 97: Endian Ordering] */
+
+#include "bitio_m.h"
+#include "bitio_gen.h"
+#include "bitio_stdio.h"
+
+#include "mg.h"
+#include "mg_merge.h"
+#include "mg_files.h"
+#include "invf.h"
+#include "words.h"
+
+typedef char FileName[256];
+
+
+/*
+ *  The merge_info struct contains all the data for an inverted file and
+ *  lexicon. We declare 3 merge_info variables, m[OLD] m[NEW] and m[MERGE].
+ */
+typedef struct merge_info_type
+  {
+    FileName fname;
+    FILE *invf;
+    FILE *dict;
+    FILE *idx;
+    FILE *para;  /* [RPAP - Feb 97: Level 3 Merge] */
+    struct invf_dict_header idh;
+    struct invf_file_header ifh;
+    u_long nDocs;
+
+    /* Lexicon processing variables */
+    u_long fcnt, wcnt;
+    int suff, pref;
+    unsigned char term[MAXSTEMLEN + 1];
+    u_long term_count;
+    int done;
+
+    /* Variables used for merging */
+    struct stdio_bitio_state sbs;	/* for bit-based I/O on inverted files */
+    u_long nTerms;		/* = number of invf entries */
+    int *fcntlist;		/* store fcnt values read in from the lexicons */
+
+  }
+merge_info;
+
+
+/***************************************************
+ **** GLOBALS ****
+ ***************************************************/
+
+merge_info m[3];		/*  m[OLD], m[NEW] and m[MERGE] */
+u_long magicsize;		/* how big is magic number? currently always 4 */
+u_long Nstatic;			/* static # of documents in file */
+
+float *DocWeightBuffer;
+int weightOption = 0;		/* true if weights file is to be appended */
+
+/*** Globals for processing the lexicons -- see readTerm() and writeTerm() 
+ ***/
+ProgTime start;			/* for printing elapsed time */
+unsigned char prevTerm[MAXSTEMLEN + 1];
+
+/*** Globals for merging -- see processEntry() 
+ ***/
+char *mergedata;		/* stores value OLD/NEW/MERGE for each term */
+int fastMerge = 1;		/* True if fast merge selected. Default = true */
+
+u_long oldIdxValue;		/* stores last read value from m[OLD].idx
+				   Used to calculate entry lengths */
+u_long bytes_output;		/* for writing .invf.idx file */
+u_long oldOnlyBits = 0;		/* entries in old only */
+u_long oldMergeBits = 0;	/* entries in old that are merged with 
+				   a new entry */
+
+/**************************************************************************/
+
+
+/*=======================================================================
+ * init_merge_invf(): open files, initialise globals, etc
+ *=======================================================================*/
+int 
+init_merge_invf ()
+{
+  prevTerm[0] = prevTerm[1] = 0;
+
+    /***
+     *  open .dict files
+     ***/
+  m[OLD].dict = open_file (m[OLD].fname, INVF_DICT_SUFFIX, "rb",
+			   MAGIC_STEM_BUILD, MG_ABORT);  /* [RPAP - Feb 97: WIN32 Port] */
+  magicsize = ftell (m[OLD].dict);
+  fread (&(m[OLD].idh), sizeof (m[OLD].idh), 1, m[OLD].dict);
+
+  /* [RPAP - Jan 97: Endian Ordering] */
+  NTOHUL(m[OLD].idh.lookback);
+  NTOHUL(m[OLD].idh.dict_size);
+  NTOHUL(m[OLD].idh.total_bytes);
+  NTOHUL(m[OLD].idh.index_string_bytes);
+  NTOHD(m[OLD].idh.input_bytes); /* [RJM 07/97: 4G limit] */
+  NTOHUL(m[OLD].idh.num_of_docs);
+  NTOHUL(m[OLD].idh.static_num_of_docs);
+  NTOHUL(m[OLD].idh.num_of_words);
+  NTOHUL(m[OLD].idh.stemmer_num);
+  NTOHUL(m[OLD].idh.stem_method);
+
+  m[NEW].dict = open_file (m[NEW].fname, INVF_DICT_SUFFIX, "rb",
+			   MAGIC_STEM_BUILD, MG_ABORT);  /* [RPAP - Feb 97: WIN32 Port] */
+  fread (&(m[NEW].idh), sizeof (m[NEW].idh), 1, m[NEW].dict);
+
+  /* [RPAP - Jan 97: Endian Ordering] */
+  NTOHUL(m[NEW].idh.lookback);
+  NTOHUL(m[NEW].idh.dict_size);
+  NTOHUL(m[NEW].idh.total_bytes);
+  NTOHUL(m[NEW].idh.index_string_bytes);
+  NTOHD(m[NEW].idh.input_bytes); /* [RJM 07/97: 4G limit] */
+  NTOHUL(m[NEW].idh.num_of_docs);
+  NTOHUL(m[NEW].idh.static_num_of_docs);
+  NTOHUL(m[NEW].idh.num_of_words);
+  NTOHUL(m[NEW].idh.stemmer_num);
+  NTOHUL(m[NEW].idh.stem_method);
+
+  m[MERGE].dict = create_file (m[MERGE].fname, INVF_DICT_SUFFIX, "wb",
+			       MAGIC_STEM_BUILD, MG_ABORT);  /* [RPAP - Feb 97: WIN32 Port] */
+
+  /* write space for header */
+  fwrite ((char *) &(m[OLD].idh), sizeof (m[OLD].idh), 1, m[MERGE].dict);
+
+  m[OLD].nDocs = m[OLD].idh.num_of_docs;
+  m[NEW].nDocs = m[NEW].idh.num_of_docs;
+  Nstatic = m[OLD].idh.static_num_of_docs;
+  m[OLD].nTerms = m[OLD].idh.dict_size;
+  m[NEW].nTerms = m[NEW].idh.dict_size;
+  m[MERGE].nDocs = m[OLD].nDocs + m[NEW].nDocs;
+  m[MERGE].nTerms = 0;
+
+  /* Set up weight buffer for weights of new documents */
+  if (!(DocWeightBuffer = Xmalloc (m[NEW].nDocs * sizeof (*DocWeightBuffer))))
+    {
+      Message ("Insufficient memory\n");
+      return COMPERROR;
+    }
+  bzero ((char *) DocWeightBuffer, m[NEW].nDocs * sizeof (*DocWeightBuffer));
+
+    /***
+     *  open .invf files
+     *  Try ".ORG" extension first for m[OLD].invf since an inverted file
+     *  with skips may have been created.
+     ****/
+  if (!(m[OLD].invf = open_file (m[OLD].fname, INVF_SUFFIX ".ORG", "rb",
+				 MAGIC_INVF, MG_CONTINUE)))  /* [RPAP - Feb 97: WIN32 Port] */
+    m[OLD].invf = open_file (m[OLD].fname, INVF_SUFFIX, "rb",
+			     MAGIC_INVF, MG_ABORT);  /* [RPAP - Feb 97: WIN32 Port] */
+  fread (&(m[OLD].ifh), sizeof (m[OLD].ifh), 1, m[OLD].invf);
+
+  /* [RPAP - Jan 97: Endian Ordering] */
+  NTOHUL(m[OLD].ifh.no_of_words);
+  NTOHUL(m[OLD].ifh.no_of_ptrs);
+  NTOHUL(m[OLD].ifh.skip_mode);
+  {
+    int i;
+    for (i = 0; i < 16; i++)
+      NTOHUL(m[OLD].ifh.params[i]);
+  }
+  NTOHUL(m[OLD].ifh.InvfLevel);
+
+  m[NEW].invf = open_file (m[NEW].fname, INVF_SUFFIX, "rb",
+			   MAGIC_INVF, MG_ABORT);
+  fread (&(m[NEW].ifh), sizeof (m[NEW].ifh), 1, m[NEW].invf);
+
+  /* [RPAP - Jan 97: Endian Ordering] */
+  NTOHUL(m[NEW].ifh.no_of_words);
+  NTOHUL(m[NEW].ifh.no_of_ptrs);
+  NTOHUL(m[NEW].ifh.skip_mode);
+  {
+    int i;
+    for (i = 0; i < 16; i++)
+      NTOHUL(m[NEW].ifh.params[i]);
+  }
+  NTOHUL(m[NEW].ifh.InvfLevel);
+
+  if (m[OLD].ifh.skip_mode != 0)
+    FatalError (1, "The old invf file contains skips. Unable to merge.");
+
+  if (m[OLD].ifh.InvfLevel != m[NEW].ifh.InvfLevel)
+    FatalError (1, "The two invf files have different inversion levels!");
+
+  /********** [RPAP - Feb 97: Level 3 Merge]
+
+  if ((m[OLD].ifh.InvfLevel > 2) || (m[NEW].ifh.InvfLevel > 2))
+    FatalError (1, "mgmerge cannot handle level 3 inverted files!");
+
+    *************/
+
+  m[MERGE].invf = create_file (m[MERGE].fname, INVF_SUFFIX, "wb",
+			       MAGIC_INVF, MG_ABORT);  /* [RPAP - Feb 97: WIN32 Port] */
+
+  /* write space for header in inverted file */
+  m[MERGE].ifh.no_of_words = m[MERGE].ifh.no_of_ptrs = 0;
+  m[MERGE].ifh.skip_mode = 0;
+  m[MERGE].ifh.InvfLevel = 2;
+  {
+    int i;
+    for (i = 0; i < 16; i++)
+      m[MERGE].ifh.params[i] = 0;
+  }
+  fwrite ((char *) &(m[MERGE].ifh), sizeof (m[MERGE].ifh), 1, m[MERGE].invf);
+
+    /***
+     *  open .invf.idx files
+     ***/
+  m[OLD].idx = open_file (m[OLD].fname, INVF_IDX_SUFFIX, "rb",
+			  MAGIC_INVI, MG_ABORT);
+  fread (&oldIdxValue, sizeof (u_long), 1, m[OLD].idx);
+  NTOHUL(oldIdxValue);  /* [RPAP - Jan 97: Endian Ordering] */
+
+  m[NEW].idx = open_file (m[NEW].fname, INVF_IDX_SUFFIX, "rb",
+			  MAGIC_INVI, MG_ABORT);
+
+  m[MERGE].idx = create_file (m[MERGE].fname, INVF_IDX_SUFFIX, "wb",
+			      MAGIC_INVI, MG_ABORT);
+
+
+  /* [RPAP - Feb 97: Level 3 Merge] */
+
+    /***
+     *  open .invf.parargraph files
+     ***/
+  if (m[OLD].ifh.InvfLevel == 3)
+    {
+      m[OLD].para = NULL;
+      m[NEW].para = open_file (m[NEW].fname, INVF_PARAGRAPH_SUFFIX, "rb",
+			       MAGIC_PARAGRAPH, MG_ABORT);
+      m[MERGE].para = open_file (m[MERGE].fname, INVF_PARAGRAPH_SUFFIX, "rb+",
+				 MAGIC_PARAGRAPH, MG_ABORT);
+    }
+  else
+    {
+      m[OLD].para = NULL;
+      m[NEW].para = NULL;
+      m[MERGE].para = NULL;
+    }
+
+  return OK;
+}
+
+
+/*=======================================================================
+ * procEntry_slow(): merge an entry, slow method
+ *=======================================================================*/
+void 
+procEntry_slow (int tnum, int type, u_long oldN, u_long newN, u_long mergeN)
+/* 
+ *  Process an invf entry. 
+ *  Slow Merge. (Always decode/re-encode).
+ *
+ *  tnum is the entry number, type = OLD or NEW or MERGE.
+ *  oldN, newN and mergeN are the N parameters for Bblock coding.
+ *  They are passed so other procEntry_fast can call this one
+ *  when a decode/recode is needed to save repeating code.
+ */
+{
+  int doc = 0;
+  int fcntOLD = m[OLD].fcntlist[tnum];
+  int fcntNEW = m[NEW].fcntlist[tnum];
+  int inblk, outblk;
+  u_long inbits = 0, outbits = 0;
+
+  /* write .invf.idx pointer */
+  HTONUL(bytes_output);  /* [RPAP - Jan 97: Endian Ordering] */
+  fwrite (&bytes_output, sizeof (u_long), 1, m[MERGE].idx);
+  NTOHUL(bytes_output);  /* [RPAP - Jan 97: Endian Ordering] */
+
+  outblk = BIO_Bblock_Init (mergeN, (fcntOLD + fcntNEW));
+
+/*** OLD entry -> merge entry ***/
+  if (type != NEW)
+    {
+      int i;
+      inblk = BIO_Bblock_Init (oldN, fcntOLD);
+      for (i = 0; i < fcntOLD; i++)
+	{
+	  int num;
+	  num = BIO_Stdio_Bblock_Decode (inblk, &(m[OLD].sbs), &inbits);
+	  doc += num;
+	  BIO_Stdio_Bblock_Encode (num, outblk, &(m[MERGE].sbs), &outbits);
+	  if (m[OLD].ifh.InvfLevel >= 2)	/* frequencies */
+	    {
+	      num = BIO_Stdio_Gamma_Decode (&(m[OLD].sbs), &inbits);
+	      BIO_Stdio_Gamma_Encode (num, &(m[MERGE].sbs), &outbits);
+	    }
+	}
+      if (type == OLD)
+	oldOnlyBits += (inbits + m[OLD].sbs.Btg);
+      else
+	oldMergeBits += (inbits + m[OLD].sbs.Btg);
+    }
+
+/*** NEW entry -> merge entry ***/
+  if (type != OLD)
+    {
+      int i;
+      int offset;
+      double logN = log ((double) m[MERGE].nDocs);
+      double idf = logN - log ((double) (fcntOLD + fcntNEW));
+
+      inblk = BIO_Bblock_Init (newN, fcntNEW);
+      offset = (m[OLD].nDocs - doc);	/* amount to be added to 1ST pointer */
+      for (i = 0; i < fcntNEW; i++)
+	{
+	  register int num;
+	  register double weight;
+	  num = BIO_Stdio_Bblock_Decode (inblk, &(m[NEW].sbs), &inbits);
+	  if (i == 0)
+	    num += offset;
+	  doc += num;
+	  BIO_Stdio_Bblock_Encode (num, outblk, &(m[MERGE].sbs), &outbits);
+	  if (m[OLD].ifh.InvfLevel >= 2)	/* frequencies */
+	    {
+	      num = BIO_Stdio_Gamma_Decode (&(m[NEW].sbs), &inbits);
+	      BIO_Stdio_Gamma_Encode (num, &(m[MERGE].sbs), &outbits);
+	      weight = num * idf;
+	      DocWeightBuffer[doc - m[OLD].nDocs - 1] += weight * weight;
+	    }
+	}
+    }
+/*** Now the padding bits ***/
+  while (m[OLD].sbs.Btg)
+    BIO_Stdio_Decode_Bit (&(m[OLD].sbs));
+  while (m[NEW].sbs.Btg)
+    BIO_Stdio_Decode_Bit (&(m[NEW].sbs));
+  while (m[MERGE].sbs.Btg != 8)
+    {
+      BIO_Stdio_Encode_Bit (0, &(m[MERGE].sbs));
+      outbits++;
+    }
+  bytes_output += (outbits >> 3);
+  return;
+}
+
+
+/*=======================================================================
+ * procEntry_fast(): merge an entry, WITHOUT decoding if it's in the
+ *                   old inverted file only
+ *=======================================================================*/
+void 
+procEntry_fast (int tnum, int type)
+/*
+ *  Merge an invf entry. 
+ *  Faster Method : Copy (don't re-code) entries for terms only in IFold.
+ *  The N parameter is Nstatic, from m[OLD].idh.static_num_of_docs.
+ *  If entry type isnt OLD, just call procEntry_slow()
+ */
+{
+  u_long newIdxValue, len = 0;
+
+  /* Calculate IFold entry length in bytes if not NEW type */
+  if (type != NEW)		/* read in an index number from m[OLD].idx */
+    {
+      fread (&newIdxValue, sizeof (u_long), 1, m[OLD].idx);
+      NTOHUL(newIdxValue);  /* [RPAP - Jan 97: Endian Ordering] */
+      len = newIdxValue - oldIdxValue;
+      oldIdxValue = newIdxValue;
+    }
+
+  if (type != OLD)		/* must decode/recode */
+    procEntry_slow (tnum, type, Nstatic, m[NEW].nDocs, Nstatic);
+  else
+    {
+      /* write .invf.idx pointer */
+      HTONUL(bytes_output);  /* [RPAP - Jan 97: Endian Ordering] */
+      fwrite (&bytes_output, sizeof (u_long), 1, m[MERGE].idx);
+      NTOHUL(bytes_output);  /* [RPAP - Jan 97: Endian Ordering] */
+
+      /* copy entry */
+      {
+	int i;
+	char c;
+	for (i = 0; i < len; i++)
+	  {
+	    c = fgetc (m[OLD].invf);
+	    fputc (c, m[MERGE].invf);
+	  }
+      }
+      bytes_output += len;
+      oldOnlyBits += (len * 8);
+    }
+  return;
+}
+
+
+/*=======================================================================
+ * processEntry(): merge an entry. Call either procEntry_slow() or
+ *                 procEntry_fast.
+ *=======================================================================*/
+void 
+processEntry (int tnum, int type)
+/* 
+ *  Read an entry from IFold and/or IFnew, and write to IFmerge.
+ *  tnum is the term number, type is OLD or NEW or MERGE
+ */
+{
+  if (fastMerge)
+    procEntry_fast (tnum, type);
+  else
+    procEntry_slow (tnum, type, Nstatic, m[NEW].nDocs, m[MERGE].nDocs);
+  return;
+}
+
+
+/*=======================================================================
+ * readTerm()
+ *=======================================================================*/
+void 
+readTerm (int x)
+/*
+ *  Read the next term from the appropriate ".invf.dict" file.
+ *  x should be either OLD or NEW.
+ *  Sets m[x].done to true when that lexicon has been completely read.
+ */
+{
+  int i;
+
+  if (m[x].term_count >= m[x].nTerms)
+    {
+      m[x].term[0] = 0;
+      m[x].done = 1;
+      return;
+    }
+  m[x].pref = fgetc (m[x].dict);
+  m[x].suff = fgetc (m[x].dict);
+  m[x].term[0] = m[x].pref + m[x].suff;
+
+  for (i = 0; i < m[x].suff; i++)
+    {
+      m[x].term[m[x].pref + i + 1] = fgetc (m[x].dict);
+    }
+  m[x].term_count = m[x].term_count + 1;
+
+  fread ((char *) &(m[x].fcnt), sizeof (u_long), 1, m[x].dict);
+  fread ((char *) &(m[x].wcnt), sizeof (u_long), 1, m[x].dict);
+
+  /* [RPAP - Jan 97: Endian Ordering] */
+  NTOHUL(m[x].fcnt);
+  NTOHUL(m[x].wcnt);
+
+  return;
+}
+
+
+/*=======================================================================
+ * writeTerm()
+ *=======================================================================*/
+void 
+writeTerm (int x)
+/*
+ *  Write the current term to m[MERGE].dict file.
+ *  x is OLD, NEW or MERGE.
+ */
+{
+  unsigned char i, prefix, suffix;
+  if (x == MERGE)
+    {
+      m[MERGE].fcnt = m[OLD].fcnt + m[NEW].fcnt;
+      m[MERGE].wcnt = m[OLD].wcnt + m[NEW].wcnt;
+      m[MERGE].pref = m[OLD].pref;
+      m[MERGE].suff = m[OLD].suff;
+      memcpy (m[MERGE].term, m[OLD].term, m[OLD].term[0] + 1);
+    }
+  if (x == OLD)
+    {
+      m[MERGE].fcnt = m[OLD].fcnt;
+      m[MERGE].wcnt = m[OLD].wcnt;
+    }
+  if (x == NEW)
+    {
+      m[MERGE].fcnt = m[NEW].fcnt;
+      m[MERGE].wcnt = m[NEW].wcnt;
+    }
+  prefix = prefixlen (prevTerm, m[x].term);
+  suffix = m[x].term[0] - prefix;
+  fputc (prefix, m[MERGE].dict);	/* prefix length */
+  fputc (suffix, m[MERGE].dict);	/* suffix length */
+  for (i = 0; i < suffix; i++)
+    fputc (m[x].term[prefix + i + 1], m[MERGE].dict);
+
+  /* [RPAP - Jan 97: Endian Ordering] */
+  HTONUL(m[MERGE].fcnt);
+  HTONUL(m[MERGE].wcnt);
+
+  fwrite ((char *) &(m[MERGE].fcnt), sizeof (m[MERGE].fcnt), 1, m[MERGE].dict);
+  fwrite ((char *) &(m[MERGE].wcnt), sizeof (m[MERGE].wcnt), 1, m[MERGE].dict);
+
+  /* [RPAP - Jan 97: Endian Ordering] */
+  NTOHUL(m[MERGE].fcnt);
+  NTOHUL(m[MERGE].wcnt);
+
+  memcpy (prevTerm, m[x].term, prefix + suffix + 1);
+  m[MERGE].idh.total_bytes += m[x].term[0] + 1;
+  m[MERGE].idh.index_string_bytes += m[x].term[0] + 2 - prefix;
+  fflush (m[MERGE].dict);
+}
+
+
+/*=======================================================================
+ * process_merge_invf(): The main loop
+ *=======================================================================*/
+int 
+process_merge_invf (void)
+/*
+ *  The main function to merge the lexicons and inverted files.
+ */
+{
+/*** Some extra Initialisation stuff first ***/
+
+  m[OLD].term[0] = m[NEW].term[0] = '\0';
+  m[OLD].term_count = m[NEW].term_count = 0;
+  m[OLD].done = m[NEW].done = 0;
+  m[MERGE].idh.total_bytes = m[MERGE].idh.index_string_bytes = 0;
+
+/*** malloc arrays: mergedata, m[OLD].fcntlist, m[NEW].fcntlist ***/
+  mergedata = malloc ((m[OLD].nTerms + m[NEW].nTerms) * sizeof (char));
+  if (mergedata == 0)
+    {
+      fprintf (stderr, "MALLOC error!\n");
+      exit (1);
+    }
+  {
+    int i;
+    for (i = 0; i < 2; i++)
+      {
+	m[i].fcntlist = malloc ((m[OLD].nTerms + m[NEW].nTerms) * sizeof (int));
+	if (m[i].fcntlist == 0)
+	  {
+	    fprintf (stderr, "MALLOC error!\n");
+	    exit (1);
+	  }
+      }
+  }
+
+/*========================*/
+/***    LEXICON PASS    ***/
+/*========================*/
+
+/*** read first terms ***/
+  readTerm (OLD);
+  readTerm (NEW);
+
+  m[MERGE].nTerms = 0;
+  while (m[OLD].done == 0 || m[NEW].done == 0)
+    {
+      int i;
+      if (m[OLD].done)
+	i = 1; /* NEW will always be greater */
+      else if (m[NEW].done)
+	i = -1; /* OLD will always be greater */
+      else
+	i = casecompare (m[OLD].term, m[NEW].term);
+
+      if (i < 0)
+	{			/* term in OLD only */
+	  mergedata[m[MERGE].nTerms] = (char) OLD;
+	  m[OLD].fcntlist[m[MERGE].nTerms] = m[OLD].fcnt;
+	  m[NEW].fcntlist[m[MERGE].nTerms] = 0;
+	  m[MERGE].nTerms++;
+	  writeTerm (OLD);
+	  readTerm (OLD);
+	}
+      if (i == 0)
+	{			/* term in both lexions */
+	  mergedata[m[MERGE].nTerms] = (char) MERGE;
+	  m[OLD].fcntlist[m[MERGE].nTerms] = m[OLD].fcnt;
+	  m[NEW].fcntlist[m[MERGE].nTerms] = m[NEW].fcnt;
+	  m[MERGE].nTerms++;
+	  writeTerm (MERGE);
+	  readTerm (OLD);
+	  readTerm (NEW);
+	}
+      if (i > 0)
+	{			/* term in NEW only */
+	  mergedata[m[MERGE].nTerms] = (char) NEW;
+	  m[NEW].fcntlist[m[MERGE].nTerms] = m[NEW].fcnt;
+	  m[OLD].fcntlist[m[MERGE].nTerms] = 0;
+	  m[MERGE].nTerms++;
+	  writeTerm (NEW);
+	  readTerm (NEW);
+	}
+    }/*while*/
+  Message ("%s\n", ElapsedTime (&start, NULL));
+  /* print some results about terms */
+  {
+    fprintf (stderr, "   Terms: OLD = %ld,  NEW = %ld,  MERGE = %ld\n",
+	     m[OLD].nTerms, m[NEW].nTerms, m[MERGE].nTerms);
+    fprintf (stderr, "   In OLD only: %ld,  In NEW only: %ld,  BOTH: %ld\n",
+	     (m[MERGE].nTerms - m[NEW].nTerms),
+	     (m[MERGE].nTerms - m[OLD].nTerms),
+	     (m[OLD].nTerms + m[NEW].nTerms - m[MERGE].nTerms));
+  }
+
+
+/*========================*/
+/***      INVF PASS     ***/
+/*========================*/
+
+  bytes_output = ftell (m[MERGE].invf);
+  BIO_Stdio_Decode_Start (m[OLD].invf, &m[OLD].sbs);
+  BIO_Stdio_Decode_Start (m[NEW].invf, &m[NEW].sbs);
+  BIO_Stdio_Encode_Start (m[MERGE].invf, &m[MERGE].sbs);
+  {
+    int i;
+    for (i = 0; i < m[MERGE].nTerms; i++)
+      {
+	processEntry (i, mergedata[i]);
+      }
+    /* write final .invf.idx pointer */
+    HTONUL(bytes_output);  /* [RPAP - Jan 97: Endian Ordering] */
+    fwrite (&bytes_output, sizeof (u_long), 1, m[MERGE].idx);
+    NTOHUL(bytes_output);  /* [RPAP - Jan 97: Endian Ordering] */
+
+    fprintf (stderr, "Old invf: old only bits: %ld, merged bits: %ld\n",
+	     oldOnlyBits, oldMergeBits);
+  }
+
+  return OK;
+}
+
+
+/*=======================================================================
+ * done_merge_invf(): write headers, close files, append weights to
+ *                     weights file
+ *=======================================================================*/
+int 
+done_merge_invf (void)
+{
+/*** write new lexicon header ***/
+  m[MERGE].idh.dict_size = m[MERGE].nTerms;
+  m[MERGE].idh.lookback = m[OLD].idh.lookback;
+  m[MERGE].idh.input_bytes = m[OLD].idh.input_bytes + m[NEW].idh.input_bytes;
+  m[MERGE].idh.total_bytes = m[OLD].idh.total_bytes + m[NEW].idh.total_bytes;
+  m[MERGE].idh.num_of_docs = m[MERGE].nDocs;
+  m[MERGE].idh.num_of_words = m[OLD].idh.num_of_words + m[NEW].idh.num_of_words;
+  m[MERGE].idh.stemmer_num = m[OLD].idh.stemmer_num;
+  m[MERGE].idh.stem_method = m[OLD].idh.stem_method;
+
+  /* if fastMerge, static num of docs stays the same! */
+  if (fastMerge)
+    m[MERGE].idh.static_num_of_docs = m[OLD].idh.static_num_of_docs;
+  else
+    m[MERGE].idh.static_num_of_docs = m[MERGE].nDocs;
+
+  /* [RPAP - Jan 97: Endian Ordering] */
+  HTONUL(m[MERGE].idh.lookback);
+  HTONUL(m[MERGE].idh.dict_size);
+  HTONUL(m[MERGE].idh.total_bytes);
+  HTONUL(m[MERGE].idh.index_string_bytes);
+  HTOND(m[MERGE].idh.input_bytes); /* [RJM 07/97: 4G limit] */
+  HTONUL(m[MERGE].idh.num_of_docs);
+  HTONUL(m[MERGE].idh.static_num_of_docs);
+  HTONUL(m[MERGE].idh.num_of_words);
+  HTONUL(m[MERGE].idh.stemmer_num);
+  HTONUL(m[MERGE].idh.stem_method);
+
+  fseek (m[MERGE].dict, magicsize, 0);
+  fwrite (&(m[MERGE].idh), sizeof (struct invf_dict_header), 1, m[MERGE].dict);
+
+/*** write new inverted file header ***/
+  m[MERGE].ifh.no_of_words = m[MERGE].nTerms;
+  m[MERGE].ifh.no_of_ptrs = m[OLD].ifh.no_of_ptrs + m[NEW].ifh.no_of_ptrs;
+  m[MERGE].ifh.skip_mode = m[OLD].ifh.skip_mode;
+  m[MERGE].ifh.InvfLevel = m[OLD].ifh.InvfLevel;
+
+  /* ifh.params[16] -- I have NO IDEA what these do!!!!! */
+  /* only set if a inverted file is in skipped format, I think */
+  {
+    int i;
+    for (i = 0; i < 16; i++)
+      m[MERGE].ifh.params[i] = m[OLD].ifh.params[i];
+  }
+
+  /* [RPAP - Jan 97: Endian Ordering] */
+  HTONUL(m[MERGE].ifh.no_of_words);
+  HTONUL(m[MERGE].ifh.no_of_ptrs);
+  HTONUL(m[MERGE].ifh.skip_mode);
+  {
+    int i;
+    for (i = 0; i < 16; i++)
+      HTONUL(m[MERGE].ifh.params[i]);
+  }
+  HTONUL(m[MERGE].ifh.InvfLevel);
+
+  fseek (m[MERGE].invf, magicsize, 0);	/* go to start of header */
+  fwrite (&(m[MERGE].ifh), sizeof (struct invf_file_header), 1, m[MERGE].invf);
+
+/*** Write new document weights --- leave old weights alone ***/
+  if ((weightOption) && (m[OLD].ifh.InvfLevel >= 2))
+    {
+      FILE *weightfile = open_file (m[MERGE].fname, WEIGHTS_SUFFIX, "r+b",
+				    MAGIC_WGHT, MG_CONTINUE);  /* [RPAP - Feb 97: WIN32 Port] */
+      if (weightfile)
+	{
+	  u_long i;  /* [RPAP - Jan 97: Endian Ordering] */
+
+	  fprintf (stderr, "writing new weights: Nnew = %ld\n", m[NEW].nDocs);
+	  fseek (weightfile, 0, 2);	/* end of file */
+
+	  /* [RPAP - Jan 97: Endian Ordering] */
+	  for (i = 0; i < m[NEW].nDocs; i++)
+	    HTONF(DocWeightBuffer[i]);
+
+	  fwrite ((char *) DocWeightBuffer, sizeof (float), m[NEW].nDocs,
+		  weightfile);
+	}
+      fclose (weightfile);
+    }
+
+
+  /* [RPAP - Feb 97: Level 3 Merge] */
+  if (m[OLD].ifh.InvfLevel == 3)
+    {
+      /* Update paragraph file */
+      int buffer_size = 1000;
+      u_char *buffer;
+      int num;
+
+      if (!(buffer = (u_char *) Xmalloc (buffer_size)))
+	FatalError (1, "Could not allocate memory for paragraph buffer");
+
+      fseek (m[MERGE].para, 0, SEEK_END);
+      while ((num = fread ((char *) buffer, sizeof (*buffer), buffer_size, m[NEW].para)) != 0)
+	fwrite ((char *) buffer, sizeof (*buffer), num, m[MERGE].para);
+
+      Xfree (buffer);
+    }
+
+/*** close files ***/
+  fclose (m[MERGE].invf);
+  fclose (m[OLD].invf);
+  fclose (m[NEW].invf);
+  fclose (m[MERGE].dict);
+  fclose (m[OLD].dict);
+  fclose (m[NEW].dict);
+  fclose (m[MERGE].idx);
+  fclose (m[OLD].idx);
+  fclose (m[NEW].idx);
+
+  /* [RPAP - Feb 97: Level 3 Merge] */
+  if (m[OLD].ifh.InvfLevel == 3)
+    {
+      fclose (m[NEW].para);
+      fclose (m[MERGE].para);
+    }
+
+  return OK;
+}
+
+
+/*=======================================================================
+ * usage()
+ *=======================================================================*/
+void 
+usage (char *progname)
+{
+  fprintf (stderr, "usage:  %s [-s] [-w] [-d directory] -f mg_collection\n",
+	   progname);
+  fprintf (stderr, "  example: %s -s -w -f MERGE/mailfiles\n", progname);
+  exit (1);
+}
+
+
+/*=======================================================================
+ * main()
+ *=======================================================================*/
+int 
+main (int argc, char *argv[])
+{
+  int ch;
+  char *progname;
+  progname = argv[0];
+  m[MERGE].fname[0] = '\0';
+
+  /* message and timing information */
+  msg_prefix = argv[0];
+
+  while ((ch = getopt (argc, argv, "f:d:swh")) != -1)
+    switch (ch)
+      {
+      case 'f':
+	strcpy (m[MERGE].fname, optarg);
+	break;
+      case 'd':
+	set_basepath (optarg);
+	break;
+      case 's':
+	fastMerge = 0;
+	break;
+      case 'w':
+	weightOption = 1;
+	break;
+      case 'h':
+      case '?':
+      default:
+	usage (progname);
+      }
+
+  if (m[MERGE].fname[0] == '\0')
+    usage (progname);
+  strcpy (m[OLD].fname, m[MERGE].fname);
+  strcat (m[OLD].fname, ".old");
+  strcpy (m[NEW].fname, m[MERGE].fname);
+  strcat (m[NEW].fname, ".new");
+
+  GetTime (&start);
+  init_merge_invf ();
+  process_merge_invf ();
+  done_merge_invf ();
+  Message ("%s\n", ElapsedTime (&start, NULL));
+  exit (0);
+}
+
+/*************************************************************************/
+/*   EOF: mg_invf_merge_new.c                                            */
+/*************************************************************************/
Index: /main/tags/2.25/gsdl/packages/mg/src/text/mg_invf_rebuild.1
===================================================================
--- /main/tags/2.25/gsdl/packages/mg/src/text/mg_invf_rebuild.1	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/mg/src/text/mg_invf_rebuild.1	(revision 21064)
@@ -0,0 +1,156 @@
+.\"------------------------------------------------------------
+.\" Id - set Rv,revision, and Dt, Date using rcs-Id tag.
+.de Id
+.ds Rv \\$3
+.ds Dt \\$4
+..
+.Id $Id$
+.\"------------------------------------------------------------
+.TH mg_invf_rebuild 1 \*(Dt CITRI
+.SH NAME
+mg_invf_rebuild \- Rebuild an mg inverted file with or without skips.
+.SH SYNOPSIS
+.B mg_invf_rebuild
+.RB [ \-h ]
+.if n .ti +9n
+[
+.BR \-0 " |"
+.B \-1
+[
+.BI \-k " num"
+] |
+.B \-2
+[
+.BI \-s " num"
+]
+[
+.BI \-m " num"
+]
+]
+.if n .ti +9n
+[
+.BI \-d " directory"
+]
+.BI \-f " name"
+.SH DESCRIPTION
+.B mg_invf_rebuild
+builds a new inverted file, with or without skipping, from an old
+inverted file.  This file uses
+.I *.invf.ORG
+and
+.I *.invf.idx.ORG
+as the
+source from which it builds
+.I *.invf
+and
+.IR *.invf.idx .
+If
+.I *.invf.ORG
+or
+.I *.invf.idx.ORG
+do not exist, the program renames
+.I *.invf
+or
+.I *.invf.idx
+to
+.I *.invf.ORG
+or
+.I *.invf.idx.ORG
+as appropriate.  The old inverted file may contain skipping.  This
+means that it is possible to delete the
+.I *.ORG
+files
+after the new inverted file is built.
+.SH OPTIONS
+Options may appear in any order.
+.TP "\w'\fB\-m\fP \fInum\fP'u+2n"
+.B \-h
+This displays a usage line on
+.IR stderr .
+.TP
+.B \-0
+This generates a non-skipped inverted file.  This option is normally
+only needed if the
+.I *.ORG
+files have been deleted.
+.TP
+.B \-1
+This generates a skipped inverted file.  The
+.BI \-k " num"
+argument specifies the number of pointers hopped over with each skip.
+.TP
+.B \-2
+This option generates a skipped inverted file.  The skipped inverted
+file is built so that it is `optimal' for ranking using a specific
+number of accumulators.  Each term in the inverted file has a
+different skip length.  The arguments
+.BR \-s " and " \-m
+control the sizes of the skips.
+.TP
+.BI \-k " num"
+This specifies the number of pointers that should be hopped over with
+each skip.  This option is only valid if
+.B \-1
+is specified.
+.TP
+.BI \-m " num"
+This specifies the intended number of accumulators that will be used
+when ranking queries are done on the collection.
+.TP
+.BI \-s " num"
+This specifies the minimum size for skips.  If the calculation of the
+optimal skip size results in a number smaller than
+.IR num ,
+the skip size is set to
+.IR num .
+.SH ENVIRONMENT
+.TP "\w'\fBMGDATA\fP'u+2n"
+.SB MGDATA
+If this environment variable exists, then its value is used as the
+default directory where the
+.BR mg (1)
+collection files are.  If this variable does not exist, then the
+directory \*(lq\fB.\fP\*(rq is used by default.  The command line
+option
+.BI \-d " directory"
+overrides the directory in
+.BR MGDATA .
+.SH FILES
+.TP 20
+.B *.invf
+Inverted file.
+.TP
+.B *.invf.ORG
+Original inverted file.
+.TP
+.B *.invf.idx
+The index into the inverted file.
+.TP
+.B *.invf.idx.ORG
+The original index into the inverted file.
+.TP
+.B *.invf.dict.build
+Compressed stemmed dictionary.
+.SH "SEE ALSO"
+.na
+.BR mg (1),
+.BR mg_compression_dict (1),
+.BR mg_fast_comp_dict (1),
+.BR mg_get (1),
+.BR mg_invf_dict (1),
+.BR mg_invf_dump (1),
+.BR mg_passes (1),
+.BR mg_perf_hash_build (1),
+.BR mg_text_estimate (1),
+.BR mg_weights_build (1),
+.BR mgbilevel (1),
+.BR mgbuild (1),
+.BR mgdictlist (1),
+.BR mgfelics (1),
+.BR mgquery (1),
+.BR mgstat (1),
+.BR mgtic (1),
+.BR mgticbuild (1),
+.BR mgticdump (1),
+.BR mgticprune (1),
+.BR mgticstat (1).
Index: /main/tags/2.25/gsdl/packages/mg/src/text/mg_invf_rebuild.c
===================================================================
--- /main/tags/2.25/gsdl/packages/mg/src/text/mg_invf_rebuild.c	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/mg/src/text/mg_invf_rebuild.c	(revision 21064)
@@ -0,0 +1,564 @@
+/**************************************************************************
+ *
+ * mg_invf_rebuild.c -- Program to rebuild an inverted file with skipping
+ * Copyright (C) 1994  Neil Sharman
+ *
+ * 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.
+ *
+ * $Id$
+ *
+ **************************************************************************/
+
+#include "sysfuncs.h"
+
+#include "memlib.h"
+#include "messages.h"
+#include "timing.h"
+#include "bitio_m.h"
+#include "bitio_m_stdio.h"
+#include "bitio_gen.h"
+#include "netorder.h"  /* [RPAP - Jan 97: Endian Ordering] */
+
+#include "mg_files.h"
+#include "invf.h"
+#include "locallib.h"
+#include "words.h"
+#include "mg.h"
+
+#define LEN 40
+#define WRD 1
+
+typedef struct invf_info
+  {
+    unsigned long doc_num, count, bits_so_far, count_bits;
+  }
+invf_info;
+
+/*
+   $Log$
+   Revision 1.1  1999/08/10 21:18:11  sjboddie
+   renamed mg-1.3d directory mg
+
+   Revision 1.2  1998/11/25 07:55:46  rjmcnab
+
+   Modified mg to that you can specify the stemmer you want
+   to use via a command line option. You specify it to
+   mg_passes during the build process. The number of the
+   stemmer that you used is stored within the inverted
+   dictionary header and the stemmed dictionary header so
+   the correct stemmer is used in later stages of building
+   and querying.
+
+   Revision 1.1  1998/11/17 09:35:10  rjmcnab
+   *** empty log message ***
+
+   * Revision 1.4  1994/11/29  00:32:03  tes
+   * Committing the new merged files and changes.
+   *
+   * Revision 1.3  1994/10/20  03:56:56  tes
+   * I have rewritten the boolean query optimiser and abstracted out the
+   * components of the boolean query.
+   *
+   * Revision 1.2  1994/09/20  04:41:51  tes
+   * For version 1.1
+   *
+ */
+
+static char *RCSID = "$Id$";
+
+static char pathname[256];
+
+static void process_files (char *filename);
+
+static int k = -1;
+static int mode = 0;
+static int max_nodes = -1;
+static int mins = -1;
+
+void 
+usage (char *pgname)
+{
+  fprintf (stderr, "usage: %s [-f input_file]"
+       "[-d data directory] -0|-1|-2 [-k num] [-m num] [-s num]\n", pgname);
+  printf ("Mode 0: (the default)\n");
+  printf ("\tk, m, and s have no meaning and if specified produce an error\n");
+  printf ("Mode 1:\n");
+  printf ("\tm, and s have no meaning and if specified produce an error\n");
+  printf ("\tk The size of skips\n");
+  printf ("Mode 2:\n");
+  printf ("\tk has no meaning and if specified will produce an error\n");
+  printf ("\tm is the the number of accumulators that will be used for the\n");
+  printf ("\t  ranking. The program builds an inverted file that is \n");
+  printf ("\t  \"optimal\" for that number of accumulators.\n");
+  printf ("\ts is the minimum size for skips.\n");
+  exit (1);
+}
+
+
+
+int main (int argc, char **argv)
+{
+  ProgTime start;
+  char *dir_name, *file_name = "";
+  int ch;
+  msg_prefix = argv[0];
+  dir_name = getenv ("MGDATA");
+  strcpy (pathname, dir_name ? dir_name : ".");
+  opterr = 0;
+  msg_prefix = argv[0];
+  while ((ch = getopt (argc, argv, "012hf:d:k:b:s:m:")) != -1)
+    switch (ch)
+      {
+      case '0':
+	mode = 0;
+	break;
+      case '1':
+	mode = 1;
+	break;
+      case '2':
+	mode = 2;
+	break;
+      case 'f':		/* input file */
+	file_name = optarg;
+	break;
+      case 'd':
+	strcpy (pathname, optarg);
+	break;
+      case 'k':
+	k = atoi (optarg);
+	break;
+      case 'm':
+	max_nodes = atoi (optarg);
+	break;
+      case 's':
+	mins = atoi (optarg);
+	if (mins < 1)
+	  FatalError (1, "The number for the -m option must be greater"
+		      " than or equal to 1");
+	break;
+      case 'h':
+      case '?':
+	usage (argv[0]);
+      }
+
+  if ((mode == 0 && (k != -1 || max_nodes != -1 || mins != -1)) ||
+      (mode == 1 && (max_nodes != -1 || mins != -1)) ||
+      (mode == 2 && (k != -1)))
+    {
+      Message ("Illegal parameters for mode");
+      usage (argv[0]);
+    }
+
+  if (mode == 1 && k == -1)
+    {
+      k = 8;
+      Message ("k is required for mode 1: defaulting k to %d", k);
+    }
+  if (mode == 2 && max_nodes == -1)
+    {
+      max_nodes = 1024;
+      Message ("m is required for mode 2: defaulting m to %d", max_nodes);
+    }
+  if (mode == 2 && mins == -1)
+    {
+      mins = 1;
+      Message ("s is required for mode 2: defaulting s to %d", mins);
+    }
+
+
+  GetTime (&start);
+  process_files (file_name);
+  Message ("%s\n", ElapsedTime (&start, NULL));
+  Message ("**** Don\'t forget to rebuild the stemmed dictionary with mg_invf_dict. ****\n");
+  Message ("**** If the collection was built with stem indexes don\'t forget to     ****\n");
+  Message ("**** rebuild them with mg_stem_idx.                                     ****\n");
+
+  return 0;
+}
+
+
+
+
+
+static void 
+process_files (char *filename)
+{
+  FILE *in, *out, *idx, *odx, *dict;
+  unsigned long magic, outmode, N, in_k, out_k;
+  unsigned long bits_out, bytes_out, i, j;
+  stdio_bitio_state out_buf, in_buf;
+  struct invf_dict_header idh;
+  struct invf_file_header ifh_in, ifh_out;
+  char FName[256];
+
+  outmode = mode;
+
+  /* open .invf.ORG, rename .invf if have to */
+  sprintf (FName, FILE_NAME_FORMAT ".ORG", pathname, filename, INVF_SUFFIX);  /* [RPAP - Feb 97: WIN32 Port] */
+  if (!(in = fopen (FName, "rb")))  /* [RPAP - Feb 97: WIN32 Port] */
+    {
+      char fname[256];
+      sprintf (fname, FILE_NAME_FORMAT, pathname, filename, INVF_SUFFIX);  /* [RPAP - Feb 97: WIN32 Port] */
+      rename (fname, FName);
+      if (!(in = fopen (FName, "rb")))  /* [RPAP - Feb 97: WIN32 Port] */
+	FatalError (1, "Unable to open \"%s\".\n", FName);
+    }
+  else
+    {
+      char fname[256];
+      sprintf (fname, FILE_NAME_FORMAT, pathname, filename, INVF_SUFFIX);  /* [RPAP - Feb 97: WIN32 Port] */
+      unlink (fname);
+    }
+  Message ("Opening \"%s\"\n", FName);
+
+  /* check the magic number for .invf.ORG */
+  if (fread (&magic, sizeof (magic), 1, in) != 1 || NTOHUL(magic) != MAGIC_INVF)  /* [RPAP - Jan 97: Endian Ordering] */
+    FatalError (1, "Bad magic number in \"%s\".\n", FName);
+
+
+  /* open .invf.idx.ORG, rename .invf.idx if have to */
+  sprintf (FName, FILE_NAME_FORMAT ".ORG", pathname, filename, INVF_IDX_SUFFIX);  /* [RPAP - Feb 97: WIN32 Port] */
+  if (!(idx = fopen (FName, "rb")))  /* [RPAP - Feb 97: WIN32 Port] */
+    {
+      char fname[256];
+      sprintf (fname, FILE_NAME_FORMAT, pathname, filename, INVF_IDX_SUFFIX);
+      rename (fname, FName);
+      if (!(idx = fopen (FName, "rb")))  /* [RPAP - Feb 97: WIN32 Port] */
+	FatalError (1, "Unable to open \"%s\".\n", FName);
+    }
+  else
+    {
+      char fname[256];
+      sprintf (fname, FILE_NAME_FORMAT, pathname, filename, INVF_IDX_SUFFIX);
+      unlink (fname);
+    }
+  Message ("Opening \"%s\"\n", FName);
+
+  /* check the magic number for .invf.idx.ORG */
+  if (fread (&magic, sizeof (magic), 1, idx) != 1 || NTOHUL(magic) != MAGIC_INVI)  /* [RPAP - Jan 97: Endian Ordering] */
+    FatalError (1, "Bad magic number in \"%s\".\n", FName);
+
+  sprintf (FName, FILE_NAME_FORMAT, pathname, filename, INVF_SUFFIX);  /* [RPAP - Feb 97: WIN32 Port] */
+  Message ("Creating \"%s\"\n", FName);
+  if (!(out = fopen (FName, "wb")))  /* [RPAP - Feb 97: WIN32 Port] */
+    FatalError (1, "Unable to open \"%s\".\n", FName);
+
+  sprintf (FName, FILE_NAME_FORMAT, pathname, filename, INVF_IDX_SUFFIX);  /* [RPAP - Feb 97: WIN32 Port] */
+  Message ("Creating \"%s\"\n", FName);
+  if (!(odx = fopen (FName, "wb")))  /* [RPAP - Feb 97: WIN32 Port] */
+    FatalError (1, "Unable to open \"%s\".\n", FName);
+
+  sprintf (FName, FILE_NAME_FORMAT, pathname, filename, INVF_DICT_SUFFIX);  /* [RPAP - Feb 97: WIN32 Port] */
+  Message ("Opening \"%s\"\n", FName);
+  if (!(dict = fopen (FName, "rb")))  /* [RPAP - Feb 97: WIN32 Port] */
+    FatalError (1, "Unable to open \"%s\".\n", FName);
+
+  if (fread (&magic, sizeof (magic), 1, dict) != 1 || NTOHUL(magic) != MAGIC_STEM_BUILD)  /* [RPAP - Jan 97: Endian Ordering] */
+    FatalError (1, "Bad magic number in \"%s\".\n", FName);
+
+  fread ((char *) &idh, sizeof (idh), 1, dict);
+
+  /* [RPAP - Jan 97: Endian Ordering] */
+  NTOHUL(idh.lookback);
+  NTOHUL(idh.dict_size);
+  NTOHUL(idh.total_bytes);
+  NTOHUL(idh.index_string_bytes);
+  NTOHD(idh.input_bytes); /* [RJM 07/97: 4G limit] */
+  NTOHUL(idh.num_of_docs);
+  NTOHUL(idh.static_num_of_docs);
+  NTOHUL(idh.num_of_words);
+  NTOHUL(idh.stemmer_num);
+  NTOHUL(idh.stem_method);
+
+  HTONUL2(MAGIC_INVF, magic);  /* [RPAP - Jan 97: Endian Ordering] */
+  fwrite ((char *) &magic, sizeof (magic), 1, out);
+
+  fread ((char *) &ifh_in, sizeof (ifh_in), 1, in);
+
+  /* [RPAP - Jan 97: Endian Ordering] */
+  NTOHUL(ifh_in.no_of_words);
+  NTOHUL(ifh_in.no_of_ptrs);
+  NTOHUL(ifh_in.skip_mode);
+  for (i = 0; i < 16; i++)
+    NTOHUL(ifh_in.params[i]);
+  NTOHUL(ifh_in.InvfLevel);
+
+  ifh_out = ifh_in;
+  ifh_out.skip_mode = outmode;
+  bzero ((char *) ifh_out.params, sizeof (ifh_out.params));
+  switch (outmode)
+    {
+    case 0:
+      break;
+    case 1:
+      ifh_out.params[0] = k;
+      break;
+    case 2:
+      ifh_out.params[0] = max_nodes;
+      ifh_out.params[1] = mins;
+      break;
+    }
+
+  /* [RPAP - Jan 97: Endian Ordering] */
+  HTONUL(ifh_out.no_of_words);
+  HTONUL(ifh_out.no_of_ptrs);
+  HTONUL(ifh_out.skip_mode);
+  for (i = 0; i < 16; i++)
+    HTONUL(ifh_out.params[i]);
+  HTONUL(ifh_out.InvfLevel);
+
+  fwrite ((char *) &ifh_out, sizeof (ifh_out), 1, out);
+
+  /* [RPAP - Jan 97: Endian Ordering] */
+  NTOHUL(ifh_out.no_of_words);
+  NTOHUL(ifh_out.no_of_ptrs);
+  NTOHUL(ifh_out.skip_mode);
+  for (i = 0; i < 16; i++)
+    NTOHUL(ifh_out.params[i]);
+  NTOHUL(ifh_out.InvfLevel);
+
+  Message ("The file is a level %d inverted file.\n", ifh_in.InvfLevel);
+
+  bits_out = ftell (out) * 8;
+
+
+  HTONUL2(MAGIC_INVI, magic);  /* [RPAP - Jan 97: Endian Ordering] */
+  fwrite ((char *) &magic, sizeof (magic), 1, odx);
+
+  DECODE_START (in)
+    DECODE_PAUSE (in_buf)
+
+    ENCODE_START (out)
+    ENCODE_PAUSE (out_buf)
+
+    N = idh.num_of_docs;
+
+  for (i = 0; i < ifh_in.no_of_words; i++)
+    {
+      unsigned long blk, p;
+      unsigned long odn_blk = 0, olen_blk = 0;
+      unsigned long idn_blk = 0, ilen_blk = 0;
+      register unsigned long suff;
+      unsigned long fcnt, wcnt, doc_num, bits_so_far, last_major;
+      unsigned long next_mjr_dn, kd;
+      char dummy2[MAXSTEMLEN + 1];
+      invf_info *ii;
+
+      fgetc (dict);
+      suff = fgetc (dict);
+      fread (dummy2, sizeof (u_char), suff, dict);
+      fread ((char *) &fcnt, sizeof (fcnt), 1, dict);
+      fread ((char *) &wcnt, sizeof (wcnt), 1, dict);
+
+      /* [RPAP - Jan 97: Endian Ordering] */
+      NTOHUL(fcnt);
+      NTOHUL(wcnt);
+
+      HTONUL2(bits_out >> 3, bytes_out);  /* [RPAP - Jan 97: Endian Ordering] */
+      fwrite ((char *) &bytes_out, sizeof (bytes_out), 1, odx);
+      NTOHUL(bytes_out);  /* [RPAP - Jan 97: Endian Ordering] */
+
+      p = fcnt;
+      blk = BIO_Bblock_Init (idh.static_num_of_docs, p);
+      switch (outmode)
+	{
+	case 1:
+	  {
+	    unsigned long len;
+	    if (p <= ifh_out.params[0])
+	      out_k = 0;
+	    else
+	      {
+		out_k = ifh_out.params[0];
+		len = BIO_Bblock_Bound (N, p);
+		if (ifh_in.InvfLevel >= 2)
+		  len += wcnt;
+		odn_blk = BIO_Bblock_Init (idh.num_of_docs, (p + out_k - 1) / out_k);
+		olen_blk = BIO_Bblock_Init (len, (p + out_k - 1) / out_k);
+	      }
+	    break;
+	  }
+	case 2:
+	  {
+	    unsigned long len;
+	    if (p <= mins)
+	      out_k = 0;
+	    else
+	      {
+		out_k = (int) (2 * sqrt ((double) p / max_nodes));
+		if (out_k <= mins)
+		  out_k = mins;
+		len = BIO_Bblock_Bound (N, p);
+		if (ifh_in.InvfLevel >= 2)
+		  len += wcnt;
+		odn_blk = BIO_Bblock_Init (idh.num_of_docs,
+					   (p + out_k - 1) / out_k);
+		olen_blk = BIO_Bblock_Init (len, (p + out_k - 1) / out_k);
+	      }
+	    break;
+	  }
+	default:
+	  out_k = 0;
+	}
+
+      switch (ifh_in.skip_mode)
+	{
+	case 1:
+	  {
+	    unsigned long len;
+	    if (p <= ifh_in.params[0])
+	      in_k = 0;
+	    else
+	      {
+		in_k = ifh_in.params[0];
+		len = BIO_Bblock_Bound (N, p);
+		if (ifh_in.InvfLevel >= 2)
+		  len += wcnt;
+		idn_blk = BIO_Bblock_Init (idh.num_of_docs, (p + in_k - 1) / in_k);
+		ilen_blk = BIO_Bblock_Init (len, (p + in_k - 1) / in_k);
+	      }
+	    break;
+	  }
+	case 2:
+	  {
+	    unsigned long len;
+	    if (p <= ifh_in.params[1])
+	      {
+		in_k = 0;
+	      }
+	    else
+	      {
+		in_k = (int) (2 * sqrt ((double) p / ifh_in.params[0]));
+		if (in_k <= ifh_in.params[1])
+		  in_k = ifh_in.params[1];
+		len = BIO_Bblock_Bound (N, p);
+		if (ifh_in.InvfLevel >= 2)
+		  len += wcnt;
+		idn_blk = BIO_Bblock_Init (idh.num_of_docs,
+					   (p + in_k - 1) / in_k);
+		ilen_blk = BIO_Bblock_Init (len, (p + in_k - 1) / in_k);
+	      }
+	    break;
+	  }
+	default:
+	  in_k = 0;
+	}
+
+      if (!(ii = Xmalloc (sizeof (invf_info) * p)))
+	FatalError (1, "Unable to allocate memory for \"ii\"\n");
+
+      doc_num = bits_so_far = 0;
+      next_mjr_dn = 0;
+      kd = 0;
+      DECODE_CONTINUE (in_buf)
+	for (j = 0; j < p; j++, kd++)
+	{
+	  unsigned long doc_diff, count = 0;
+	  if (kd == in_k)
+	    kd = 0;
+	  if (in_k && kd == 0 && j + in_k < p)
+	    {
+	      int temp;
+	      BBLOCK_DECODE (next_mjr_dn, idn_blk);
+	      next_mjr_dn += doc_num;
+	      BBLOCK_DECODE (temp, ilen_blk);
+	    }
+	  ii[j].bits_so_far = bits_so_far;
+	  if (in_k && kd == in_k - 1 && j != p - 1)
+	    {
+	      int count;
+	      BBLOCK_LENGTH (next_mjr_dn - doc_num, blk, count);
+	      bits_so_far += count;
+	      doc_num = next_mjr_dn;
+	    }
+	  else
+	    {
+	      BBLOCK_DECODE_L (doc_diff, blk, bits_so_far);
+	      doc_num += doc_diff;
+	    }
+	  ii[j].doc_num = doc_num;
+	  if (ifh_in.InvfLevel >= 2)
+	    {
+	      int count_bits = 0;
+	      GAMMA_DECODE_L (count, count_bits);
+	      ii[j].count_bits = count_bits;
+	      bits_so_far += count_bits;
+	      ii[j].count = count;
+	    }
+	}
+
+      /* read till a byte boundary */
+      while (__btg)
+	{
+	  DECODE_BIT;
+	  bits_so_far++;
+	}
+
+      DECODE_PAUSE (in_buf)
+
+	doc_num = bits_so_far = 0;
+      last_major = 0;
+      kd = 0;
+      ENCODE_CONTINUE (out_buf)
+	for (j = 0; j < p; j++, kd++)
+	{
+	  if (kd == out_k)
+	    kd = 0;
+	  if (out_k && kd == 0)
+	    {
+	      if (j + out_k < p)
+		{
+		  int num = ii[j + out_k - 1].doc_num - last_major;
+		  BBLOCK_ENCODE_L (num, odn_blk, bits_out);
+		  last_major = ii[j + out_k - 1].doc_num;
+
+		  num = ii[j + out_k - 1].bits_so_far + ii[j + out_k - 1].count_bits -
+		    bits_so_far;
+		  BBLOCK_ENCODE_L (num, olen_blk, bits_out);
+		  bits_so_far = ii[j + out_k].bits_so_far;
+		}
+	    }
+	  if (!(out_k && kd == out_k - 1 && j != p - 1))
+	    BBLOCK_ENCODE_L (ii[j].doc_num - doc_num, blk, bits_out);
+	  doc_num = ii[j].doc_num;
+	  if (ifh_in.InvfLevel >= 2)
+	    GAMMA_ENCODE_L (ii[j].count, bits_out);
+	}
+
+      /* write till a byte boundary */
+      while (__btg != 8)
+	{
+	  ENCODE_BIT (0);
+	  bits_out++;
+	}
+      ENCODE_PAUSE (out_buf)
+
+	Xfree (ii);
+
+    }
+  ENCODE_CONTINUE (out_buf)
+    ENCODE_DONE
+
+    HTONUL2(bits_out >> 3, bytes_out);  /* [RPAP - Jan 97: Endian Ordering] */
+  fwrite ((char *) &bytes_out, sizeof (bytes_out), 1, odx);
+  NTOHUL(bytes_out);
+
+  fclose (idx);
+  fclose (odx);
+  fclose (in);
+  fclose (out);
+  fclose (dict);
+
+}
Index: /main/tags/2.25/gsdl/packages/mg/src/text/mg_merge.h
===================================================================
--- /main/tags/2.25/gsdl/packages/mg/src/text/mg_merge.h	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/mg/src/text/mg_merge.h	(revision 21064)
@@ -0,0 +1,37 @@
+/**************************************************************************
+ *
+ * mgmerge.h --- mgmerge #defines, etc
+ * Copyright (C) 1995  Shane Hudson (shane@cosc.canterbury.ac.nz)
+ *
+ * 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.
+ *
+ * $Id$
+ * Last edtited: November 12 1994
+ *
+ **************************************************************************/
+
+#ifndef MGMERGE_H
+#define MGMERGE_H
+
+typedef unsigned char byte;
+
+#define OLD 0
+#define NEW 1
+#define MERGE 2
+
+#define OK 0
+#define ERROR_MGMERGE 1
+
+#endif
Index: /main/tags/2.25/gsdl/packages/mg/src/text/mg_passes.1
===================================================================
--- /main/tags/2.25/gsdl/packages/mg/src/text/mg_passes.1	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/mg/src/text/mg_passes.1	(revision 21064)
@@ -0,0 +1,441 @@
+.\"------------------------------------------------------------
+.\" Id - set Rv,revision, and Dt, Date using rcs-Id tag.
+.de Id
+.ds Rv \\$3
+.ds Dt \\$4
+..
+.Id $Id$
+.\"------------------------------------------------------------
+.TH mg_passes 1 \*(Dt CITRI
+.SH NAME
+mg_passes \- builds mg databases
+.SH SYNOPSIS
+.B mg_passes
+[
+.B \-h
+]
+[
+.B \-G
+]
+[
+.B \-S
+]
+[
+.B \-D
+]
+[
+.B \-W
+]
+.if n .ti +9n
+[
+.BR \-1 " |"
+.BR \-2 " |"
+.B  \-3
+]
+[
+.BI \-C " compstatpoint"
+]
+.if n .ti +9n
+[
+.BI \-n " tracename"
+]
+.if t .ti +.5i
+[
+.BI \-b " bufsize"
+]
+[
+.BI \-m " memlimit"
+]
+.if n .ti +9n
+[
+.BI \-c " numchunks"
+]
+[
+.BI \-a " stemmer"
+]
+[
+.BI \-s " stemmethod"
+]
+[
+.BI \-t " tracepos"
+]
+.if n .ti +9n
+[
+.B \-T1
+]
+[
+.B \-T2
+]
+.if t .ti +.5i
+[
+.B \-I1
+]
+[
+.B \-I2
+]
+.if n .ti +9n
+[
+.BI \-d " directory"
+]
+.BI \-f " name"
+[
+.I filename(s)
+]
+.SH DESCRIPTION
+.B mg_passes
+is the program that does most of the work when building
+.BR mg (1)
+database systems.  The input documents can come from either
+.I stdin
+or from a list of files on the command line.  Individual documents
+must be separated with control-B characters.  In general,
+.B mg_passes
+must be run twice to build a database, first with the
+.B \-T1
+and
+.B \-I1
+options, and second with the
+.B \-T2
+and
+.B \-I2
+options.  Several other programs must be run in order to get an
+.BR mg (1)
+database that is ready for the
+.BR mgquery (1)
+program.  The
+.SB EXAMPLE
+section below gives an example of how to build a complete
+.BR mg (1)
+database.
+.SH OPTIONS
+Options may appear in any order, but the
+.IR filename(s) ,
+if specified, must be last.
+.TP "\w'\fB\-C\fP \fIcompstatpoint\fP'u+2n"
+.B \-h
+This displays a usage line on
+.IR stderr .
+.TP
+.B \-G
+Treat SGML tags as non-words when building the inverted file.  An SGML
+tag is anything between angle brackets, i.e., `<' and `>'.
+.TP
+.B \-S
+This option causes a special pass to be executed.  It is up to a user
+to modify
+.I mg.special.c
+in the source code to do something with the documents it is given.
+.TP
+.B \-D
+If
+.B mg_passes
+fails, then print the document that caused the failure to the trace
+file if tracing is active, or to
+.I stderr
+if it is not.
+.TP
+.B \-W
+This option enables the generation of the weights file when
+.B \-I2
+is specified.  It causes
+.B \-I2
+to use a little more memory and CPU.
+.TP
+.B \-1
+Produce a level-1 inverted file.  This option is only useful when
+specified with
+.BR "\-I1 ".
+A level-1 inverted file makes it possible for
+.BR mgquery (1)
+to do Boolean queries.  Ranked queries can still be done,
+although the quality of the ranking is abysmal.
+.TP
+.B \-2
+Produce a level-2 inverted file.  This option is only useful when
+specified with
+.BR "\-I1 ".
+This is the default when neither
+.BR \-1 ", " "\-2 " "or " \-3
+is specified.
+A level-2 inverted file makes it possible for
+.BR mgquery (1)
+to do Boolean queries and cosine-ranked queries.
+.TP
+.B \-3
+Produce a level-3 inverted file.  This option is only useful when
+specified with
+.BR "\-I1 ".
+This has been implemented to enable paragraph-level inversion.
+Paragraphs are delimited by control-C characters in the source text.
+.TP
+.BI \-C " compstatpoint"
+This option causes statistics on the compression performance to be
+output to a file called
+.IR *.compression.stats .
+.I compstatpoint
+specifies the interval between outputting each line of statistics.  The
+units of
+.I compstatpoint
+are kilobytes of source text.  E.g., if
+.I compstatpoint
+is 10, then a line is output to the file every 10 KB of input
+source.  Each line of the file consists of 4 numbers The first number
+is the amount of input text, in bytes, processed so far.  The second
+number is the amount of input text, in bytes, processed since the
+last line was output to the file.  The third number is the number of
+output bytes generated since the last line was output to the file, and
+the fourth number is the compression achieved since the last line was
+output, i.e., the third number divided by the second number.
+.TP
+.BI \-n " tracename"
+This specifies the filename to use for the trace log, if tracing is
+enabled using the
+.B \-t
+option.  If
+.BI \-n " tracename"
+is not given and tracing is enabled, a default trace filename will be
+used.
+.TP
+.BI \-s " stemmethod"
+This specifies the method to use to \*(lqstem\*(rq the words in the
+inverted file dictionary.  This is a bit mask specifying the
+operations to do on words as they are parsed out of the text, where
+bit number 0 is the low-order (rightmost) bit.  Bit 0 does case
+folding, and bit 1 does simple stemming, so the value 3 for
+.I stemmethod
+does both case folding and stemming.
+.TP
+.BI \-a " stemmer"
+This specifies the stemmer to use when stemming words.  This
+is a description of the language the stemmer is intended for
+or a description of the stemmer.  Valid options include:
+english, lovin, french, and simplefrench.
+.TP
+.BI \-b " bufsize"
+Specify the size of the document buffer in kilobytes.  If any document
+is larger than
+.IR bufsize ,
+the program will abort with an error message.  This should probably be
+replaced with some system which automatically increases the buffer
+size as required.  The default size is 3072 KB (3 MB).
+.TP
+.BI \-m " memlimit"
+Maximum amount of memory to use for the pass-2 file inversion in
+megabytes.  This option is only useful when used in conjunction with
+the option
+.BR \-I1 .
+The larger this value, the faster the pass-2 inversion will proceed.
+The default value is 5 MB.
+.TP
+.BI \-c " numchunks"
+The maximum number of inversion chunks to write to disk.  Each chunk
+will be approximately as large as
+.IR memlimit .
+This option is only useful when used in conjunction with the option
+.BR \-I2 .
+The larger this value, the faster the pass-2 inversion will proceed.
+The default value is 5 MB.
+.TP
+.BI \-t " tracepos"
+This option activates tracing.  A line will be generated in the
+trace file for every
+.I tracepos
+input bytes processed.  The default name for the trace file can be
+overridden using the
+.BI \-n " tracename"
+option.
+.TP
+.B \-T1
+Generate the
+.I *.text.stats
+file.
+.TP
+.B \-T2
+Generate the
+.IR *.text ,
+.IR *.text.idx ,
+and possibly the
+.I *.text.dict.aux
+files.  Using this option requires that the
+.I *.text.dict
+file be present.
+.TP
+.B \-I1
+Generate the
+.IR *.invf.dict ,
+.IR *.invf.chunk ,
+and
+.I *.invf.chunk.trans
+files.
+.TP
+.B \-I2
+Generate the
+.I *.invf
+and
+.I *.invf.idx
+files.  Using this option requires
+that the
+.IR *.invf.dict.hash ,
+.IR *.invf.chunk ,
+and
+.I *.invf.chunk.trans
+files
+be present.  The
+.I *.invf.dict.hash
+file is generated by
+.BR mg_perf_hash_build (1)
+from the
+.I *.invf.dict.build
+file.  If the
+.B \-W
+option is specified, the
+.I *.weight
+file will also be generated.
+.TP
+.BI \-d " directory"
+This specifies the directory where the document collection is to be
+written.
+.TP
+.BI \-f " name"
+This specifies the base name of the document collection that will be
+created.
+.TP
+.I filename(s)
+This specifies the source text. If this is not specified, then the
+program expects the source text from
+.IR stdin .
+.SH EXAMPLE
+What follows is a UNIX
+.BR csh (1)
+script as an example of how to build an
+.BR mg (1)
+document collection.
+.LP
+.nf
+.DT
+.ft B
+.I #! /bin/csh
+.I
+# The first argument on the command line specifies the
+.I
+#   source of the text
+set source = ($1)
+.PP
+.I
+# The second argument is the name of the collection
+set text = ($2)
+.PP
+.I
+# Create *.text.stats,  *.invf.dict.build,
+.I
+#   *.invf.chunk and *.invf.chunks.trans
+${source} | mg_passes -T1 -I1 -m 1 -t 1 -f ${text}
+.PP
+.I
+# Create *.text.dict
+mg_compression_dict -f ${text}
+.PP
+.I
+# Create *.invf.dict.hash
+mg_perf_hash_build -f ${text}
+.PP
+.I
+# Create *.text,  *.text.idx,
+.I
+#   *.invf and *.invf.idx
+${source} | mg_passes -T2 -I2 -c 2 -t 1 -f ${text}
+.PP
+.I
+# Create *.text.idx.wgt and *.weight.approx
+mg_weights_build -f ${text} -b 8
+.PP
+.I
+# Create *.invf.dict
+mg_invf_dict -f ${text} -b 4096
+.PP
+.I
+# Create *.text.dict
+mg_fast_comp_dict -f ${text}
+.ft R
+.fi
+.SH ENVIRONMENT
+.TP "\w'\fBMGDATA\fP'u+2n"
+.SB MGDATA
+If this environment variable exists, then its value is used as the
+default directory where the
+.BR mg (1)
+collection files are.  If this variable does not exist, then the
+directory \*(lq\fB.\fP\*(rq is used by default.  The command line
+option
+.BI \-d " directory"
+overrides the directory in
+.BR MGDATA .
+.SH FILES
+.TP 20
+.B *.invf
+Inverted file.
+.TP
+.B *.invf.chunk
+Inverted file chunk descriptor file.  When the inverted file is
+created it is created in chunks that use no more than a set amount of
+memory.  This file describes those chunks.
+.TP
+.B *.invf.chunk.trans
+Word-occurrence-order to lexical-order translation file.  The
+.B *.invf.chunk
+file is written in word-occurrence order but is required by
+.B \-I2
+to be in lexical order.
+.TP
+.B *.invf.dict.build
+Compressed stemmed dictionary.
+.TP
+.B *.invf.dict.hash
+Data for an order-preserving perfect hash function.
+.TP
+.B *.invf.idx
+The index into the inverted file.
+.TP
+.B *.weight
+The exact weights file.
+.TP
+.B *.text
+Compressed documents.
+.TP
+.B *.text.stats
+Statistics about the text.
+.TP
+.B *.text.dict
+Compressed compression dictionary.
+.TP
+.B *.text.idx
+Index into the compressed documents.
+.TP
+.B *.trace
+The default trace file.
+.TP
+.B *.compression.stats
+Statistics about the compression of the text.
+.SH "SEE ALSO"
+.na
+.BR mg (1),
+.BR mg_compression_dict (1),
+.BR mg_fast_comp_dict (1),
+.BR mg_get (1),
+.BR mg_invf_dict (1),
+.BR mg_invf_dump (1),
+.BR mg_invf_rebuild (1),
+.BR mg_perf_hash_build (1),
+.BR mg_text_estimate (1),
+.BR mg_weights_build (1),
+.BR mgbilevel (1),
+.BR mgbuild (1),
+.BR mgdictlist (1),
+.BR mgfelics (1),
+.BR mgquery (1),
+.BR mgstat (1),
+.BR mgtic (1),
+.BR mgticbuild (1),
+.BR mgticdump (1),
+.BR mgticprune (1),
+.BR mgticstat (1).
Index: /main/tags/2.25/gsdl/packages/mg/src/text/mg_passes.c
===================================================================
--- /main/tags/2.25/gsdl/packages/mg/src/text/mg_passes.c	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/mg/src/text/mg_passes.c	(revision 21064)
@@ -0,0 +1,625 @@
+/**************************************************************************
+ *
+ * mg_passes.c -- Driver for the various passes
+ * Copyright (C) 1994  Neil Sharman
+ *
+ * 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.
+ *
+ * $Id$
+ *
+ **************************************************************************/
+
+#include "sysfuncs.h"
+
+#ifdef HAVE_MALLINFO
+# include <malloc.h> 
+#endif
+
+#include "memlib.h"
+#include "messages.h"
+#include "timing.h"
+
+#include "mg_files.h"
+#include "mg.h"
+#include "build.h"
+#include "text.h"
+#include "stemmer.h"
+
+
+/*
+   $Log$
+   Revision 1.1  1999/08/10 21:18:12  sjboddie
+   renamed mg-1.3d directory mg
+
+   Revision 1.3  1998/12/17 09:12:53  rjmcnab
+
+   Altered mg to process utf-8 encoded Unicode. The main changes
+   are in the parsing of the input, the casefolding, and the stemming.
+
+   Revision 1.2  1998/11/25 07:55:47  rjmcnab
+
+   Modified mg to that you can specify the stemmer you want
+   to use via a command line option. You specify it to
+   mg_passes during the build process. The number of the
+   stemmer that you used is stored within the inverted
+   dictionary header and the stemmed dictionary header so
+   the correct stemmer is used in later stages of building
+   and querying.
+
+   Revision 1.1  1998/11/17 09:35:13  rjmcnab
+   *** empty log message ***
+
+   * Revision 1.3  1994/10/20  03:56:57  tes
+   * I have rewritten the boolean query optimiser and abstracted out the
+   * components of the boolean query.
+   *
+   * Revision 1.2  1994/09/20  04:41:52  tes
+   * For version 1.1
+   *
+ */
+
+static char *RCSID = "$Id$";
+
+#define MAX_PASSES 5
+
+#define SPECIAL 1
+#define TEXT_PASS_1 2
+#define TEXT_PASS_2 4
+#define IVF_PASS_1 8
+#define IVF_PASS_2 16
+
+#define MIN_BUF 8192
+#define	TERMRECORD	'\002'
+
+unsigned long buf_size = 3 * 1024 * 1024;	/* 3Mb */
+unsigned long invf_buffer_size = 5 * 1024 * 1024;	/* 5Mb */
+unsigned long ChunkLimit = 0;
+char InvfLevel = 2;
+char SkipSGML = 0;
+char MakeWeights = 0;
+FILE *Comp_Stats = NULL;
+int comp_stat_point = 0;
+double bytes_processed = 0; /* [RJM 07/97: 4G limit] */
+double bytes_received = 0; /* [RJM 07/97: 4G limit] */
+int stemmer_num = 0; /* default to the lovin stemmer */
+int stem_method = 0;
+
+static char Passes = 0;
+static unsigned long trace = 0;
+static int Dump = 0;
+static char **files = NULL;
+static int num_files = 0;
+static char *trace_name = NULL;
+
+
+typedef struct pass_data
+  {
+    char *name;
+    int (*init) (char *);
+    int (*process) (u_char *, int);
+    int (*done) (char *);
+#ifdef HAVE_TIMES
+    clock_t init_time;
+    clock_t process_time;
+    clock_t done_time;
+#else
+    struct timeval init_time;
+    struct timeval process_time;
+    struct timeval done_time;
+#endif
+  }
+pass_data;
+
+#ifdef HAVE_TIMES
+#define NULL_TIMES 0, 0, 0
+#else
+#define NULL_TIMES {0, 0}, {0, 0}, {0, 0}
+#endif
+
+static pass_data PassData[MAX_PASSES] =
+{
+  {"special", init_special, process_special, done_special, NULL_TIMES},
+  {"text.pass1", init_text_1, process_text_1, done_text_1, NULL_TIMES},
+  {"text.pass2", init_text_2, process_text_2, done_text_2, NULL_TIMES},
+  {"ivf.pass1", init_ivf_1, process_ivf_1, done_ivf_1, NULL_TIMES},
+  {"ivf.pass2", init_ivf_2, process_ivf_2, done_ivf_2, NULL_TIMES},
+};
+
+static char *usage_str = "\nUSAGE:\n"
+"  %s [-h] [-G] [-D] [-1|-2|-3] [-T1] [-T2] [-I1] [-I2] [-N1]\n"
+"  %*s [-N2] [-W] [-S] [-b buffer-size] [-d dictionary-directory]\n"
+"  %*s [-t trace-point Mb] [-m invf-memory] [-c chunk-limit]\n"
+"  %*s [-n trace-name] [-C comp-stat-size] [-s stem_method]\n"
+"  %*s [-a stemmer] -f doc-collection-name\n";
+
+
+
+
+
+
+
+
+
+static void 
+usage (char *err)
+{
+  if (err)
+    Message (err);
+  fprintf (stderr, usage_str, msg_prefix, strlen (msg_prefix), "",
+	   strlen (msg_prefix), "", strlen (msg_prefix), "");
+  exit (1);
+}
+
+
+
+
+#if 0
+static char *
+str_comma (unsigned long u)
+{
+  static char buf[20];
+  unsigned long a, b, c, d;
+  a = u / 1000000000;
+  u -= a * 1000000000;
+  b = u / 1000000;
+  u -= b * 1000000;
+  c = u / 1000;
+  u -= c * 1000;
+  d = u;
+
+  if (a)
+    sprintf (buf, "%u,%03u,%03u,%03u", a, b, c, d);
+  else if (b)
+    sprintf (buf, "%u,%03u,%03u", b, c, d);
+  else if (c)
+    sprintf (buf, "%u,%03u", c, d);
+  else
+    sprintf (buf, "%u", d);
+  return (buf);
+}
+#endif
+
+
+
+
+int 
+open_next_file (int in_fd)
+{
+  if (in_fd > 0)
+    close (in_fd);
+  if (num_files == 0)
+    return (-1);
+  if ((in_fd = open (files[0], O_RDONLY)) == -1)
+    FatalError (1, "Cannot open %s", files[0]);
+  files++;
+  num_files--;
+  return (in_fd);
+}
+
+
+static void 
+driver (int in_fd, FILE * Trace, char *file_name)
+{
+  int pass, num = 1;
+
+  char *buffer = Xmalloc (buf_size);
+  unsigned long num_docs = 0;
+  unsigned long block_bytes = 0;
+  register int buf_left = buf_size;
+  register char *look_pos = buffer;
+  register char *end_pos = buffer;
+
+  ProgTime StartTime, InitTime, ProcTime, DoneTime;
+
+  GetTime (&StartTime);
+
+  for (pass = 0; pass < MAX_PASSES; pass++)
+    if (Passes & (1 << pass))
+      {
+	pass_data *pd = &PassData[pass];
+#ifdef HAVE_TIMES
+	struct tms tims;
+	times (&tims);
+	pd->init_time -= tims.tms_utime + tims.tms_stime;
+#elif defined(HAVE_GETRUSAGE)  /* [RPAP - Feb 97: WIN32 Port] */
+	struct rusage ru;
+
+	getrusage (RUSAGE_SELF, &ru);
+	pd->init_time.tv_sec -= ru.ru_utime.tv_sec + ru.ru_stime.tv_sec;
+	pd->init_time.tv_usec -= ru.ru_utime.tv_usec + ru.ru_stime.tv_usec;
+#endif
+	if (pd->init (file_name) == COMPERROR)
+	  FatalError (1, "Error during init of \"%s\"", pd->name);
+
+#ifdef HAVE_TIMES
+	times (&tims);
+	pd->init_time += tims.tms_utime + tims.tms_stime;
+#elif defined(HAVE_GETRUSAGE)  /* [RPAP - Feb 97: WIN32 Port] */
+	getrusage (RUSAGE_SELF, &ru);
+	pd->init_time.tv_sec += ru.ru_utime.tv_sec + ru.ru_stime.tv_sec;
+	pd->init_time.tv_usec += ru.ru_utime.tv_usec + ru.ru_stime.tv_usec;
+	time_normalise (&pd->init_time);
+#endif
+      }
+
+  GetTime (&InitTime);
+  for (;;)
+    {
+      int len = 0;
+      char *base = look_pos;
+
+      while (look_pos != end_pos && *look_pos != TERMRECORD)
+	look_pos++;
+
+      while (look_pos == end_pos)
+	{
+	  if (buf_left < MIN_BUF)
+	    {
+	      bcopy (base, buffer, end_pos - base);
+	      look_pos = buffer + (end_pos - base);
+	      buf_left = buf_size - (end_pos - base);
+	      end_pos = look_pos;
+	      base = buffer;
+	    }
+	  if (buf_left)
+	    {
+    	      num = read (in_fd, end_pos, buf_left);
+	      if (num < 0) num = 0; /* RJM - quick hack :-) */
+	      if (num == 0)
+		if ((in_fd = open_next_file (in_fd)) != -1)
+		  num = read (in_fd, end_pos, buf_left);
+	      bytes_received += num;
+	      buf_left -= num;
+	      end_pos += num;
+	    }
+	  while (look_pos < end_pos && *look_pos != TERMRECORD)
+	    look_pos++;
+	  if (buf_left == 0 && base == buffer && look_pos == end_pos)
+	    {
+	      Message ("Unable to find document terminator (i.e ^B)"
+		       " in the document");
+	      FatalError (1, "The document is in excess of %d chars long",
+			  look_pos - base);
+	    }
+	  if (!num)
+	    break;
+	}
+      len = look_pos++ - base;
+
+      if (!num && base == end_pos)
+	break;
+
+      bytes_processed += len;
+
+#ifndef QUIET
+      if (!len)
+	Message ("Warning : Processing zero length document");
+#endif
+
+      for (pass = 0; pass < MAX_PASSES; pass++)
+	if (Passes & (1 << pass))
+	  {
+	    register pass_data *pd = &PassData[pass];
+
+#ifdef HAVE_TIMES
+	    struct tms tims;
+	    times (&tims);
+	    pd->process_time -= tims.tms_utime + tims.tms_stime;
+#elif defined(HAVE_GETRUSAGE)  /* [RPAP - Feb 97: WIN32 Port] */
+	    struct rusage ru;
+	    register struct timeval *tv = &pd->process_time;
+
+	    getrusage (RUSAGE_SELF, &ru);
+	    tv->tv_sec -= ru.ru_utime.tv_sec + ru.ru_stime.tv_sec;
+	    tv->tv_usec -= ru.ru_utime.tv_usec + ru.ru_stime.tv_usec;
+#endif
+
+	    if (pd->process ((u_char *) base, len) == COMPERROR)
+	      {
+		Message ("Error during processing of \"%s\"", pd->name);
+		if (Dump || Trace)
+		  {
+		    int i;
+		    FILE *f = Trace ? Trace : stderr;
+		    fprintf (f, "-=- * -=- * -=- * -=- * -=- * -=- * -=-\n");
+		    for (i = 0; i < len; i++)
+		      {
+			char ch = base[i];
+			if (ch == '\1' || ch == '\2')
+			  ch = '\n';
+			putc (ch, f);
+		      }
+		    fprintf (f, "-=- * -=- * -=- * -=- * -=- * -=- * -=-\n");
+		  }
+		if (Trace)
+		  fprintf (Trace, "%10.0f bytes |%7lu docs | %s\n",
+			   bytes_processed, num_docs,
+			   ElapsedTime (&StartTime, NULL));
+		exit (1);
+	      }
+
+#ifdef HAVE_TIMES
+	    times (&tims);
+	    pd->process_time += tims.tms_utime + tims.tms_stime;
+#elif defined(HAVE_GETRUSAGE)  /* [RPAP - Feb 97: WIN32 Port] */
+	    getrusage (RUSAGE_SELF, &ru);
+	    tv->tv_sec += ru.ru_utime.tv_sec + ru.ru_stime.tv_sec;
+	    tv->tv_usec += ru.ru_utime.tv_usec + ru.ru_stime.tv_usec;
+#endif
+	  }
+      num_docs++;
+      if (Trace)
+	{
+	  block_bytes += (look_pos - base);
+	  if (block_bytes >= trace)
+	    {
+#ifdef HAVE_MALLINFO
+	      struct mallinfo mi;
+	      mi = mallinfo ();
+	      block_bytes -= trace;
+	      fprintf (Trace, "%10.0f bytes |%7lu docs |%7.3f Mb | %s\n",
+		       bytes_processed, num_docs, mi.arena / 1024.0 / 1024.0,
+		       ElapsedTime (&StartTime, NULL));
+#else
+	      block_bytes -= trace;
+	      fprintf (Trace, "%10.0f bytes |%7lu docs | %s\n",
+		       bytes_processed, num_docs,
+		       ElapsedTime (&StartTime, NULL));
+#endif
+	    }
+	}
+      if (!num && look_pos - 1 == end_pos)
+	break;
+    }
+
+#ifndef HAVE_TIMES
+  for (pass = 0; pass < MAX_PASSES; pass++)
+    if (Passes & (1 << pass))
+      time_normalise (&PassData[pass].process_time);
+#endif
+
+  GetTime (&ProcTime);
+
+  for (pass = 0; pass < MAX_PASSES; pass++)
+    if (Passes & (1 << pass))
+      {
+	pass_data *pd = &PassData[pass];
+#ifdef HAVE_TIMES
+	struct tms tims;
+	times (&tims);
+	pd->done_time -= tims.tms_utime + tims.tms_stime;
+#elif defined(HAVE_GETRUSAGE)  /* [RPAP - Feb 97: WIN32 Port] */
+	struct rusage ru;
+
+	getrusage (RUSAGE_SELF, &ru);
+	pd->done_time.tv_sec -= ru.ru_utime.tv_sec + ru.ru_stime.tv_sec;
+	pd->done_time.tv_usec -= ru.ru_utime.tv_usec + ru.ru_stime.tv_usec;
+#endif
+	if (pd->done (file_name) == COMPERROR)
+	  FatalError (1, "Error during done of \"%s\"", pd->name);
+
+#ifdef HAVE_TIMES
+	times (&tims);
+	pd->done_time += tims.tms_utime + tims.tms_stime;
+#elif defined(HAVE_GETRUSAGE)  /* [RPAP - Feb 97: WIN32 Port] */
+	getrusage (RUSAGE_SELF, &ru);
+	pd->done_time.tv_sec += ru.ru_utime.tv_sec + ru.ru_stime.tv_sec;
+	pd->done_time.tv_usec += ru.ru_utime.tv_usec + ru.ru_stime.tv_usec;
+	time_normalise (&pd->done_time);
+#endif
+      }
+  if (Trace)
+    {
+#ifdef HAVE_MALLINFO
+      struct mallinfo mi;
+      mi = mallinfo ();
+      fprintf (Trace, "%10.0f bytes |%7lu docs |%7.3f Mb | %s\n",
+	       bytes_processed, num_docs, mi.arena / 1024.0 / 1024.0,
+	       ElapsedTime (&StartTime, NULL));
+#else
+      fprintf (Trace, "%10.0f bytes |%7lu docs | %s\n",
+	       bytes_processed, num_docs,
+	       ElapsedTime (&StartTime, NULL));
+#endif
+    }
+
+  GetTime (&DoneTime);
+
+  Message ("");
+  Message ("%10s      :    init         process        done", "");
+  for (pass = 0; pass < MAX_PASSES; pass++)
+    if (Passes & (1 << pass))
+      {
+	pass_data *pd = &PassData[pass];
+	char it[15], pt[15], dt[15];
+#ifdef HAVE_TIMES
+	strcpy (it, cputime_string (pd->init_time));
+	strcpy (pt, cputime_string (pd->process_time));
+	strcpy (dt, cputime_string (pd->done_time));
+#else
+	strcpy (it, cputime_string (&pd->init_time));
+	strcpy (pt, cputime_string (&pd->process_time));
+	strcpy (dt, cputime_string (&pd->done_time));
+#endif
+	Message ("%-10s      : %s   %s   %s", pd->name, it, pt, dt);
+      }
+  Message ("");
+  Message ("Init time       : %s", ElapsedTime (&StartTime, &InitTime));
+  Message ("Process time    : %s", ElapsedTime (&InitTime, &ProcTime));
+  Message ("Done time       : %s", ElapsedTime (&ProcTime, &DoneTime));
+  Message ("Total time      : %s", ElapsedTime (&StartTime, &DoneTime));
+  Message ("Documents       : %u", num_docs);
+  Message ("Bytes received  : %.0f", bytes_received);
+  Message ("Bytes processed : %.0f", bytes_processed);
+  Message ("Process Rate    : %.1f kB per cpu second",
+   (double) bytes_processed / (ProcTime.CPUTime - InitTime.CPUTime) / 1024);
+  free (buffer);
+}
+
+
+
+int main (int argc, char **argv)
+{
+  int ch, in_fd;
+  char *filename = NULL;
+  FILE *Trace = NULL;
+
+  msg_prefix = argv[0];
+
+  opterr = 0;
+  while ((ch = getopt (argc, argv, "hC:WGSD123f:d:b:T:I:t:m:N:c:n:s:a:")) != -1)
+    {
+      switch (ch)
+	{
+	case 'G':
+	  SkipSGML = 1;
+	  break;
+	case 'S':
+	  Passes |= SPECIAL;
+	  break;
+	case '1':
+	  InvfLevel = 1;
+	  break;
+	case '2':
+	  InvfLevel = 2;
+	  break;
+	case '3':
+	  InvfLevel = 3;
+	  break;
+	case 'f':
+	  filename = optarg;
+	  break;
+	case 'n':
+	  trace_name = optarg;
+	  break;
+	case 'D':
+	  Dump = 1;
+	  break;
+	case 'W':
+	  MakeWeights = 1;
+	  break;
+	case 'd':
+	  set_basepath (optarg);
+	  break;
+	case 'a':
+	  stemmer_num = stemmernumber (optarg);
+	  break;
+	case 's':
+	  stem_method = atoi (optarg) & STEMMER_MASK;
+	  break;
+	case 'b':
+	  buf_size = atoi (optarg) * 1024;
+	  break;
+	case 'C':
+	  comp_stat_point = atoi (optarg) * 1024;
+	  break;
+	case 'c':
+	  ChunkLimit = atoi (optarg);
+	  break;
+	case 'm':
+	  invf_buffer_size = (int) (atof (optarg) * 1024 * 1024);
+	  break;
+	case 'I':
+	case 'N': /* N kept for compatability */
+	  if (*optarg == '1')
+	    Passes |= IVF_PASS_1;
+	  else if (*optarg == '2')
+	    Passes |= IVF_PASS_2;
+	  else
+	    usage ("Invalid pass number");
+	  break;
+	case 'T':
+	  if (*optarg == '1')
+	    Passes |= TEXT_PASS_1;
+	  else if (*optarg == '2')
+	    Passes |= TEXT_PASS_2;
+	  else
+	    usage ("Invalid pass number");
+	  break;
+	case 't':
+	  trace = (unsigned long) (atof (optarg) * 1024 * 1024);
+	  break;
+	case 'h':
+	case '?':
+	  usage (NULL);
+	}
+    }
+
+  if (!filename || *filename == '\0')
+    FatalError (1, "A document collection name must be specified.");
+
+  if (buf_size < MIN_BUF)
+    FatalError (1, "The buffer size must exceed 1024 bytes.");
+
+  if ((Passes & (IVF_PASS_1 | IVF_PASS_2)) == (IVF_PASS_1 | IVF_PASS_2))
+    FatalError (1, "I1 and I2 cannot be done simultaneously.");
+
+  if ((Passes & (TEXT_PASS_1 | TEXT_PASS_2)) == (TEXT_PASS_1 | TEXT_PASS_2))
+    FatalError (1, "T1 and T2 cannot be done simultaneously.");
+
+  if (!Passes)
+    FatalError (1, "S, T1, T2, I1 or I2 must be specified.");
+
+  if (optind < argc)
+    {
+      if ((in_fd = open (argv[optind], O_RDONLY)) == -1)
+	FatalError (1, "Cannot open %s", argv[optind]);
+      files = &argv[optind + 1];
+      num_files = argc - (optind + 1);
+    }
+  else
+    in_fd = 0;			/* stdin */
+
+
+  if (trace)
+    {
+      if (!trace_name)
+	trace_name = make_name (filename, TRACE_SUFFIX, NULL);
+      if (!(Trace = fopen (trace_name, "a")))
+	Message ("Unable to open \"%s\". No tracing will be done.", trace_name);
+      else
+	setbuf (Trace, NULL);
+    }
+  else
+    Trace = NULL;
+
+  if (comp_stat_point)
+    {
+      char *name = make_name (filename, COMPRESSION_STATS_SUFFIX, NULL);
+      if (!(Comp_Stats = fopen (name, "wb")))  /* [RPAP - Feb 97: WIN32 Port] */
+	Message ("Unable to open \"%s\". No comp. stats. will be generated.",
+		 name);
+    }
+
+
+  if (Trace)
+    {
+      int i;
+      fprintf (Trace, "\n\n\t\t-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-\n\n");
+      for (i = 0; i < argc; i++)
+	fprintf (Trace, "%s ", argv[i]);
+      fprintf (Trace, "\n\n");
+    }
+
+  driver (in_fd, Trace, filename);
+
+  if (Trace)
+    fclose (Trace);
+
+  if (Comp_Stats)
+    fclose (Comp_Stats);
+
+  return 0;
+}
Index: /main/tags/2.25/gsdl/packages/mg/src/text/mg_perf_hash_build.1
===================================================================
--- /main/tags/2.25/gsdl/packages/mg/src/text/mg_perf_hash_build.1	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/mg/src/text/mg_perf_hash_build.1	(revision 21064)
@@ -0,0 +1,89 @@
+.\"------------------------------------------------------------
+.\" Id - set Rv,revision, and Dt, Date using rcs-Id tag.
+.de Id
+.ds Rv \\$3
+.ds Dt \\$4
+..
+.Id $Id$
+.\"------------------------------------------------------------
+.TH mg_perf_hash_build 1 \*(Dt CITRI
+.SH NAME
+mg_perf_hash_build \- generate an order-preserving hash function for the stemmed dictionary
+.SH SYNOPSIS
+.B mg_perf_hash_build
+[
+.B \-h
+]
+[
+.BI \-r " rndseed"
+]
+[
+.BI \-d  " directory"
+]
+.if n .ti +9n
+.BI \-f " name"
+.SH DESCRIPTION
+.B mg_perf_hash_build
+generates an order-preserving hashing function from the compressed
+stemmed dictionary and writes it out to disk.
+.BR mg_passes (1)
+will make use of the hash function when it builds the inverted file.
+.SH OPTIONS
+Options may appear in any order.
+.TP "\w'\fB\-d\fP \fIdirectory\fP'u+2n"
+.B \-h
+This displays a usage line on
+.IR stderr .
+.TP
+.BI \-r " rndseed"
+This specifies the random seed to be used in the generation of the
+hash function; it must be an integer.  If this is not specified, the
+current time will be used as the random seed.
+.TP
+.BI \-d " directory"
+This specifies the directory where the document collection can be found.
+.TP
+.BI \-f " name"
+This specifies the base name of the document collection.
+.SH ENVIRONMENT
+.TP "\w'\fBMGDATA\fP'u+2n"
+.SB MGDATA
+If this environment variable exists, then its value is used as the
+default directory where the
+.BR mg (1)
+collection files are.  If this variable does not exist, then the
+directory \*(lq\fB.\fP\*(rq is used by default.  The command line
+option
+.BI \-d " directory"
+overrides the directory in
+.BR MGDATA .
+.SH FILES
+.TP 20
+.B *.invf.dict
+Stemmed dictionary.
+.TP
+.B *.invf.dict.hash
+Data for a order-preserving perfect hash function.
+.SH "SEE ALSO"
+.na
+.BR mg (1),
+.BR mg_compression_dict (1),
+.BR mg_fast_comp_dict (1),
+.BR mg_get (1),
+.BR mg_invf_dict (1),
+.BR mg_invf_dump (1),
+.BR mg_invf_rebuild (1),
+.BR mg_passes (1),
+.BR mg_text_estimate (1),
+.BR mg_weights_build (1),
+.BR mgbilevel (1),
+.BR mgbuild (1),
+.BR mgdictlist (1),
+.BR mgfelics (1),
+.BR mgquery (1),
+.BR mgstat (1),
+.BR mgtic (1),
+.BR mgticbuild (1),
+.BR mgticdump (1),
+.BR mgticprune (1),
+.BR mgticstat (1).
Index: /main/tags/2.25/gsdl/packages/mg/src/text/mg_perf_hash_build.c
===================================================================
--- /main/tags/2.25/gsdl/packages/mg/src/text/mg_perf_hash_build.c	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/mg/src/text/mg_perf_hash_build.c	(revision 21064)
@@ -0,0 +1,183 @@
+/**************************************************************************
+ *
+ * mg_perf_hash_build.c -- Program to build a perfect hash function
+ * Copyright (C) 1994  Neil Sharman
+ *
+ * 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.
+ *
+ * $Id$
+ *
+ **************************************************************************/
+
+#include "sysfuncs.h"
+#include "memlib.h"
+#include "messages.h"
+#include "timing.h"
+#include "local_strings.h"
+#include "perf_hash.h"
+#include "netorder.h"  /* [RPAP - Jan 97: Endian Ordering] */
+
+#include "mg_files.h"
+#include "invf.h"
+#include "locallib.h"
+#include "words.h"
+#include "mg.h"
+
+/*
+   $Log$
+   Revision 1.1  1999/08/10 21:18:13  sjboddie
+   renamed mg-1.3d directory mg
+
+   Revision 1.2  1998/11/25 07:55:47  rjmcnab
+
+   Modified mg to that you can specify the stemmer you want
+   to use via a command line option. You specify it to
+   mg_passes during the build process. The number of the
+   stemmer that you used is stored within the inverted
+   dictionary header and the stemmed dictionary header so
+   the correct stemmer is used in later stages of building
+   and querying.
+
+   Revision 1.1  1998/11/17 09:35:15  rjmcnab
+   *** empty log message ***
+
+   * Revision 1.3  1994/10/20  03:56:58  tes
+   * I have rewritten the boolean query optimiser and abstracted out the
+   * components of the boolean query.
+   *
+   * Revision 1.2  1994/09/20  04:41:53  tes
+   * For version 1.1
+   *
+ */
+
+static char *RCSID = "$Id$";
+
+
+
+#define POOL_SIZE 1024*1024
+
+static void process_files (char *filename);
+
+int r = -1;
+
+int main (int argc, char **argv)
+{
+  ProgTime start;
+  char *file_name = "";
+  int ch;
+  msg_prefix = argv[0];
+  opterr = 0;
+  while ((ch = getopt (argc, argv, "f:d:r:h")) != -1)
+    switch (ch)
+      {
+      case 'f':		/* input file */
+	file_name = optarg;
+	break;
+      case 'd':
+	set_basepath (optarg);
+	break;
+      case 'r':
+	r = atoi (optarg);
+	break;
+      case 'h':
+      case '?':
+	fprintf (stderr, "usage: %s [-f input_file]"
+		 "[-d data directory] [-r random seed] [-h]\n", argv[0]);
+	exit (1);
+      }
+
+  GetTime (&start);
+  process_files (file_name);
+  Message ("%s\n", ElapsedTime (&start, NULL));
+  return 0;
+}
+
+
+
+
+
+static void 
+process_files (char *filename)
+{
+  FILE *dict, *hash;
+  unsigned long i;
+  u_char prev[MAXSTEMLEN + 1];
+  struct invf_dict_header idh;
+  perf_hash_data *phd;
+  u_char *pool;
+  int pool_left;
+  u_char **starts;
+
+
+  dict = open_file (filename, INVF_DICT_SUFFIX, "rb",
+		    MAGIC_STEM_BUILD, MG_ABORT);  /* [RPAP - Feb 97: WIN32 Port] */
+
+  fread ((char *) &idh, sizeof (idh), 1, dict);
+
+  /* [RPAP - Jan 97: Endian Ordering] */
+  NTOHUL(idh.lookback);
+  NTOHUL(idh.dict_size);
+  NTOHUL(idh.total_bytes);
+  NTOHUL(idh.index_string_bytes);
+  NTOHD(idh.input_bytes); /* [RJM 07/97: 4G limit] */
+  NTOHUL(idh.num_of_docs);
+  NTOHUL(idh.static_num_of_docs);
+  NTOHUL(idh.num_of_words);
+  NTOHUL(idh.stemmer_num);
+  NTOHUL(idh.stem_method);
+
+  hash = create_file (filename, INVF_DICT_HASH_SUFFIX, "wb",
+		      MAGIC_HASH, MG_ABORT);  /* [RPAP - Feb 97: WIN32 Port] */
+
+  if (!(pool = Xmalloc (POOL_SIZE)))
+    FatalError (1, "Out of memory");
+  pool_left = POOL_SIZE;
+
+  if (!(starts = Xmalloc (sizeof (u_char *) * idh.dict_size)))
+    FatalError (1, "Out of memory");
+
+  for (i = 0; i < idh.dict_size; i++)
+    {
+      register unsigned long copy, suff, l;
+      unsigned long wcnt, fcnt;
+
+      /* build a new word on top of prev */
+      copy = getc (dict);
+      suff = getc (dict);
+      *prev = copy + suff;
+      fread (prev + copy + 1, sizeof (u_char), suff, dict);
+
+      /* read other data, but no need to store it */
+      fread (&fcnt, sizeof (fcnt), 1, dict);
+      fread (&wcnt, sizeof (wcnt), 1, dict);
+
+      l = *prev + 1;
+      if (pool_left < l)
+	{
+	  pool = Xmalloc (POOL_SIZE);
+	  pool_left = POOL_SIZE;
+	}
+      starts[i] = pool;
+      bcopy ((char *) prev, (char *) pool, l);
+      pool += l;
+      pool_left -= l;
+    }
+  if (!(phd = gen_hash_func (idh.dict_size, starts, r)))
+    FatalError (1, "Unable to generate hash function");
+  if (write_perf_hash_data (hash, phd) == -1)
+    FatalError (1, "Unable to write hash function");
+  fclose (dict);
+  fclose (hash);
+}
Index: /main/tags/2.25/gsdl/packages/mg/src/text/mg_stem_idx.1
===================================================================
--- /main/tags/2.25/gsdl/packages/mg/src/text/mg_stem_idx.1	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/mg/src/text/mg_stem_idx.1	(revision 21064)
@@ -0,0 +1,95 @@
+.\"------------------------------------------------------------
+.\" Id - set Rv,revision, and Dt, Date using rcs-Id tag.
+.de Id
+.ds Rv \\$3
+.ds Dt \\$4
+..
+.Id $Id$
+.\"------------------------------------------------------------
+.TH mg_stem_idx 1 \*(Dt CITRI
+.SH NAME
+mg_stem_idx \- builds a stem index file
+.SH SYNOPSIS
+.B mg_stem_idx
+[
+.B \-h
+]
+[
+.B \-F
+]
+[
+.BI \-b " num"
+]
+[
+.BI \-d " directory"
+]
+.if n .ti +9n
+.B \-s 1|2|3
+.BI \-f " name"
+.SH DESCRIPTION
+.B mg_stem_idx
+generates a stem index file for a collection that is to be built with
+stem indexes.  This program should be called three times: once for each
+.B -s
+parameter.  It uses the stemmed dictionary to create the stem index which
+contains pointers into the stemmed dictionary.
+.SH OPTIONS
+Options may appear in any order.
+.TP "\w'\fB\-d\fP \fIdirectory\fP'u+2n"
+.B \-h
+This displays a usage line on
+.IR stderr .
+.TP
+.BI \-b " num"
+The dictionary is stored in blocks on disk; this option is used to set
+the block size.  The default is 4-KB blocks.
+.TP
+.B \-F
+This option causes the disk blocks to be aligned on the appropriate
+boundaries.  For example, if 4-KB blocks are used, they will be aligned
+in the file on 4-KB boundaries.
+.TP
+.B -s 1|2|3
+The stem method to apply for the stem index.
+.br
+1 = casefolded and non-stemmed
+.br
+2 = non-casefolded and stemmed
+.br
+3 = casefolded and stemmed
+.TP
+.BI \-d " directory"
+This specifies the directory where the document collection can be found.
+.TP
+.BI \-f " name"
+This specifies the base name of the document collection.
+.SH ENVIRONMENT
+.TP "\w'\fBMGDATA\fP'u+2n"
+.SB MGDATA
+If this environment variable exists, then its value is used as the
+default directory where the
+.BR mg (1)
+collection files are.  If this variable does not exist, then the
+directory \*(lq\fB.\fP\*(rq is used by default.  The command line
+option
+.BI \-d " directory"
+overrides the directory in
+.BR MGDATA .
+.SH FILES
+.TP 25
+.B *.invf.dict.blocked
+Compressed stemmed dictionary.
+.TP
+.B *.invf.dict.blocked.1
+Stem index with stem index method 1.
+.TP
+.B *.invf.dict.blocked.2
+Stem index with stem index method 2.
+.TP
+.B *.invf.dict.blocked.3
+Stem index with stem index method 3.
+.SH "SEE ALSO"
+.na
+.BR mg (1),
+.BR mg_invf_dict (1),
+.BR mgstemidxlist (1).
Index: /main/tags/2.25/gsdl/packages/mg/src/text/mg_stem_idx.c
===================================================================
--- /main/tags/2.25/gsdl/packages/mg/src/text/mg_stem_idx.c	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/mg/src/text/mg_stem_idx.c	(revision 21064)
@@ -0,0 +1,892 @@
+/**************************************************************************
+ *
+ * mg_stem_idx.c -- Memory efficient stem index builder
+ * Copyright (C) 1997  Ross Peeters
+ *
+ * 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.
+ *
+ **************************************************************************/
+
+#include "sysfuncs.h"
+
+#include "memlib.h"
+#include "messages.h"
+#include "filestats.h"
+#include "netorder.h"  /* [RPAP - Jan 97: Endian Ordering] */
+
+#include "mg_files.h"
+#include "invf.h"
+#include "mg.h"
+#include "locallib.h"
+#include "backend.h"     /* For struct stemmed_dict */
+#include "words.h"
+#include "stemmer.h"
+#include "hash.h"
+#include "local_strings.h"
+
+typedef struct PosEntry
+{
+  unsigned int num_cases;
+  unsigned int blk;
+  unsigned short blk_index;
+  unsigned short offset;
+}
+PosEntry;
+
+
+typedef struct PosList
+{
+  unsigned int list_size;
+  unsigned int num_entries;
+  PosEntry PE[1];
+}
+PosList;
+
+
+typedef struct idx_hash_rec
+{
+  u_char *word;
+  PosList *PL;
+}
+idx_hash_rec;
+
+
+#define POOL_SIZE 1024*1024
+#define HASH_POOL_SIZE 8192
+#define INITIAL_HASH_SIZE 7927
+
+
+static unsigned long MaxMemInUse = 0;
+static unsigned long MemInUse = 0;
+
+static idx_hash_rec **IdxHashTable;
+static unsigned long IdxHashSize;
+static unsigned long IdxHashUsed;
+static u_char *IdxPool;
+static int IdxPoolLeft;
+
+static idx_hash_rec *idx_hr_pool;
+static int idx_hr_PoolLeft;
+
+static idx_hash_rec **idx_first_occr;
+static int idx_max_first_occr;
+
+int block_size = 1024 * 4;
+
+int force = 0;
+
+static long lookback = 4;
+
+static void 
+ChangeMem (int Change)
+{
+  MemInUse += Change;
+  if (MemInUse > MaxMemInUse)
+    MaxMemInUse = MemInUse;
+}
+
+
+/* =========================================================================
+ * Function: MakePosList
+ * Description:
+ * Input:
+ * Output:
+ * ========================================================================= */
+PosList *
+MakePosList (int n)
+{
+  PosList *pl;
+  int list_size = (n == 0 ? 1 : n);	/* always allocate at least one node */
+
+  pl = Xmalloc (sizeof (PosList) + (list_size - 1) * sizeof (PosEntry));
+  if (!pl)
+    FatalError (1, "Unable to allocate term list");
+  ChangeMem (sizeof (PosList) + (list_size - 1) * sizeof (PosEntry));
+
+  pl->num_entries = n;
+  pl->list_size = list_size;
+
+  return pl;
+}
+
+/* =========================================================================
+ * Function: ResizePosList
+ * Description:
+ * Input:
+ * Output:
+ * ========================================================================= */
+
+#define GROWTH_FACTOR 2
+#define MIN_SIZE 2
+
+static void
+ResizePosList (PosList ** pos_list)
+{
+  PosList *pl = *pos_list;
+
+  ChangeMem (-(sizeof (PosList) + (pl->list_size - 1) * sizeof (PosEntry)));
+  if (pl->num_entries > pl->list_size)
+    {
+      if (pl->list_size)
+	pl->list_size *= GROWTH_FACTOR;
+      else
+	pl->list_size = MIN_SIZE;
+    }
+  pl = Xrealloc (pl, sizeof (PosList) + (pl->list_size - 1) * sizeof (PosEntry));
+
+  if (!pl)
+    FatalError (1, "Unable to resize pos list");
+  ChangeMem (sizeof (PosList) + (pl->list_size - 1) * sizeof (PosEntry));
+
+  *pos_list = pl;
+}
+
+
+/* =========================================================================
+ * Function: FreePosList
+ * Description:
+ * Input:
+ * Output:
+ * ========================================================================= */
+
+void
+FreePosList (PosList ** the_pl)
+{
+  PosList *pl = *the_pl;
+
+  ChangeMem (-(sizeof(PosList) + sizeof (PosEntry) * (pl->list_size - 1)));
+  Xfree (pl);
+
+  *the_pl = NULL;
+}
+
+
+/* =========================================================================
+ * Function: ResetPosList
+ * Description: 
+ * Input: 
+ * Output: 
+ * ========================================================================= */
+
+void
+ResetPosList (PosList ** pl)
+{
+  if (*pl)
+    FreePosList (pl);
+  *pl = MakePosList (0);
+}
+
+/* =========================================================================
+ * Function: AddPosEntry
+ * Description: 
+ * Input: 
+ * Output: 
+ * ========================================================================= */
+
+int
+AddPosEntry (PosList ** pos_list, PosEntry * pe)
+{
+  PosList *pl = *pos_list;
+
+  pl->num_entries++;
+  ResizePosList (pos_list);
+  pl = *pos_list;
+
+  /* copy the structure contents */
+  bcopy ((char *) pe, (char *) &(pl->PE[pl->num_entries - 1]), sizeof (PosEntry));
+
+  return pl->num_entries - 1;
+}
+
+
+/* Modified from stem_search.c */
+stemmed_dict *
+ReadStemDictBlk (File * stem_file)
+{
+  unsigned long i;
+  stemmed_dict *sd;
+  u_char *buffer;
+
+  if (!(sd = Xmalloc (sizeof (stemmed_dict))))
+    FatalError (1, "Could not allocate memory for stemmed dict");
+
+
+  sd->stem_file = stem_file;
+  sd->MemForStemDict = 0;
+
+  Fread (&sd->sdh, sizeof (sd->sdh), 1, stem_file);
+
+  /* [RPAP - Jan 97: Endian Ordering] */
+  NTOHUL(sd->sdh.lookback);
+  NTOHUL(sd->sdh.block_size);
+  NTOHUL(sd->sdh.num_blocks);
+  NTOHUL(sd->sdh.blocks_start);
+  NTOHUL(sd->sdh.index_chars);
+  NTOHUL(sd->sdh.num_of_docs);
+  NTOHUL(sd->sdh.static_num_of_docs);
+  NTOHUL(sd->sdh.num_of_words);
+  NTOHUL(sd->sdh.stemmer_num);
+  NTOHUL(sd->sdh.stem_method);
+  NTOHUL(sd->sdh.indexed);
+
+  if (!(buffer = Xmalloc (sd->sdh.index_chars)))
+    {
+      Xfree (sd);
+      FatalError (1, "Could not allocate memory for stemmed dict");
+      return (NULL);
+    };
+  sd->MemForStemDict += sd->sdh.index_chars;
+
+  if (!(sd->index = Xmalloc (sd->sdh.num_blocks * sizeof (*sd->index))))
+    {
+      Xfree (sd);
+      Xfree (buffer);
+      FatalError (1, "Could not allocate memory for stemmed dict");
+      return (NULL);
+    };
+  sd->MemForStemDict += sd->sdh.num_blocks * sizeof (*sd->index);
+
+  if (!(sd->pos = Xmalloc (sd->sdh.num_blocks * sizeof (*sd->pos))))
+    {
+      Xfree (sd);
+      Xfree (buffer);
+      Xfree (sd->index);
+      FatalError (1, "Could not allocate memory for stemmed dict");
+      return (NULL);
+    };
+  sd->MemForStemDict += sd->sdh.num_blocks * sizeof (*sd->pos);
+
+  if (!(sd->buffer = Xmalloc (sd->sdh.block_size * sizeof (*sd->buffer))))
+    {
+      Xfree (sd);
+      Xfree (buffer);
+      Xfree (sd->index);
+      Xfree (sd->buffer);
+      FatalError (1, "Could not allocate memory for stemmed dict");
+      return (NULL);
+    };
+  sd->MemForStemDict += sd->sdh.block_size * sizeof (*sd->buffer);
+
+  sd->active = -1;
+
+  for (i = 0; i < sd->sdh.num_blocks; i++)
+    {
+      register u_char len;
+      sd->index[i] = buffer;
+      len = Getc (stem_file);
+      *buffer++ = len;
+      Fread (buffer, sizeof (u_char), len, stem_file);
+      buffer += len;
+      Fread (&sd->pos[i], sizeof (*sd->pos), 1, stem_file);
+      NTOHUL(sd->pos[i]);  /* [RPAP - Jan 97: Endian Ordering] */
+    }
+
+  return sd;
+}
+
+
+void
+init_process ()
+{
+  /* Allocate memory for idx hash table */
+
+  if (!(IdxPool = Xmalloc (POOL_SIZE)))
+    FatalError (1, "Unable to allocate memory for idx pool");
+  IdxPoolLeft = POOL_SIZE;
+  ChangeMem (POOL_SIZE);
+
+  if (!(idx_hr_pool = Xmalloc (HASH_POOL_SIZE * sizeof (idx_hash_rec))))
+    FatalError (1, "Unable to allocate memory for idx pool");
+  idx_hr_PoolLeft = HASH_POOL_SIZE;
+  ChangeMem (HASH_POOL_SIZE * sizeof (idx_hash_rec));
+
+  IdxHashSize = INITIAL_HASH_SIZE;
+  IdxHashUsed = 0;
+  if (!(IdxHashTable = Xmalloc (sizeof (idx_hash_rec *) * IdxHashSize)))
+    FatalError (1, "Unable to allocate memory for idx table");
+  ChangeMem (sizeof (idx_hash_rec *) * IdxHashSize);
+  bzero ((char *) IdxHashTable, sizeof (idx_hash_rec *) * IdxHashSize);
+  idx_max_first_occr = 8192;
+  if (!(idx_first_occr = Xmalloc (sizeof (idx_hash_rec *) * idx_max_first_occr)))
+    FatalError (1, "Unable to allocate memory for idx_first_occur");
+  ChangeMem (sizeof (idx_hash_rec *) * idx_max_first_occr);
+}
+
+
+void
+PackIdxHashTable (void)
+{
+  int s, d;
+  for (s = d = 0; s < IdxHashSize; s++)
+    if (IdxHashTable[s])
+      IdxHashTable[d++] = IdxHashTable[s];
+  ChangeMem (-sizeof (idx_hash_rec *) * IdxHashSize);
+  ChangeMem (sizeof (idx_hash_rec *) * IdxHashUsed);
+  if (!(IdxHashTable = Xrealloc (IdxHashTable, sizeof (idx_hash_rec *) * IdxHashUsed)))
+    FatalError (1, "Out of memory");
+  IdxHashSize = IdxHashUsed;
+}
+
+
+void
+process_stem_dict (stemmed_dict * sd, int stem_method)
+{
+  int block;
+  short blk_index = -1;
+  int wordnum = -1;
+  PosEntry *prevPE = NULL;
+  idx_hash_rec *prevIdx = NULL;
+  u_char word[MAXSTEMLEN + 1];
+  u_char prev[MAXSTEMLEN + 1];
+
+  /* For each block in stem dict... */
+  for (block = 0; block < sd->sdh.num_blocks; block++)
+    {
+      register unsigned int res;
+      int num_indexes;
+      unsigned long *first_word, *last_invf_len;
+      unsigned short *num_words;
+      u_char *base;
+      unsigned short *index;
+
+      /* Read block into buffer */
+      Fseek (sd->stem_file, sd->pos[block] + sd->sdh.blocks_start, 0);
+      Fread (sd->buffer, sd->sdh.block_size, sizeof (u_char), sd->stem_file);
+      sd->active = sd->pos[block];
+
+      /* Move through block header */
+      first_word = (unsigned long *) (sd->buffer);
+      NTOHUL(*first_word);  /* [RPAP - Jan 97: Endian Ordering] */
+      last_invf_len = (unsigned long *) (first_word + 1);
+      NTOHUL(*last_invf_len);  /* [RPAP - Jan 97: Endian Ordering] */
+      num_words = (unsigned short *) (last_invf_len + 1);
+      NTOHUS(*num_words);  /* [RPAP - Jan 97: Endian Ordering] */
+      index = num_words + 1;
+      num_indexes = ((*num_words - 1) / sd->sdh.lookback) + 1;
+
+      {
+	/* [RPAP - Jan 97: Endian Ordering] */
+	int i;
+	for (i = 0; i < num_indexes; i++)
+	  NTOHUS(index[i]);
+      }
+
+      base = (u_char *) (index + num_indexes);
+      blk_index = -1;
+
+      /* For each word in block... */
+      for (res = 0; res < *num_words; res++)
+	{
+	  unsigned copy, suff;
+	  register idx_hash_rec *idx_ent = 0;
+
+	  /* Update blk_index */
+	  if (!(res % sd->sdh.lookback))
+	    blk_index++;
+
+	  copy = *base++;
+	  suff = *base++;
+	  bcopy ((char *) base, (char *) (prev + copy + 1), suff);
+	  base += suff;
+	  *prev = copy + suff;
+
+	  /* Skip irrelevant word info */
+	  base += sizeof (u_long);
+	  base += sizeof (u_long);
+	  base += sizeof (u_long);
+
+	  /* Stem word */
+	  bcopy ((char *) prev, (char *) word, *prev + 1);
+	  stemmer (stem_method, sd->sdh.stemmer_num, word);
+
+	  /* Check if word follows straight on from previous word */
+	  if (prevIdx && !compare (word, prevIdx->word))
+	    prevPE->num_cases++;
+
+	  else
+	    {
+	      /* Search the idx hash table for word */
+	      register unsigned long hashval, step;
+	      register int hsize = IdxHashSize;
+	      HASH (hashval, step, word, hsize);
+	      for (;;)
+		{
+		  register u_char *s1;
+		  register u_char *s2;
+		  register int len;
+		  idx_ent = IdxHashTable[hashval];
+		  if (!idx_ent)
+		    {
+		      /* Create a next entry in the hash table */
+		      int len = *word + 1;
+		      if (!idx_hr_PoolLeft)
+			{
+			  if (!(idx_hr_pool = Xmalloc (HASH_POOL_SIZE *
+						       sizeof (idx_hash_rec))))
+			    FatalError (1, "Unable to allocate memory for pool");
+			  idx_hr_PoolLeft = HASH_POOL_SIZE;
+			  ChangeMem (HASH_POOL_SIZE * sizeof (idx_hash_rec));
+			}
+		      idx_ent = idx_hr_pool++;
+		      idx_hr_PoolLeft--;
+		      if (len > IdxPoolLeft)
+			{
+			  if (!(IdxPool = Xmalloc (POOL_SIZE)))
+			    FatalError (1, "Unable to allocate memory for pool");
+			  IdxPoolLeft = POOL_SIZE;
+			  ChangeMem (POOL_SIZE);
+			}
+		      wordnum++;
+
+		      idx_ent->word = IdxPool;
+		      idx_ent->PL = MakePosList (0);
+		      {
+			PosEntry PE;
+			PE.num_cases = 1;
+			PE.blk = block;
+			PE.blk_index = (unsigned short) blk_index;
+			PE.offset = res % sd->sdh.lookback;
+			AddPosEntry (&(idx_ent->PL), &PE);
+		      }
+		      prevIdx = idx_ent;
+		      prevPE = &(idx_ent->PL->PE[idx_ent->PL->num_entries - 1]);
+
+		      bcopy ((char *) word, (char *) IdxPool, len);
+		      IdxPool += len;
+		      IdxPoolLeft -= len;
+		      if (IdxHashUsed == idx_max_first_occr - 1)
+			{
+			  ChangeMem (-sizeof (idx_hash_rec *) * idx_max_first_occr);
+			  idx_max_first_occr *= 2;
+			  if (!(idx_first_occr = Xrealloc (idx_first_occr, sizeof (idx_hash_rec *) *
+							   idx_max_first_occr)))
+			    FatalError (1, "Unable to allocate memory for idx_first_occr");
+			  ChangeMem (sizeof (idx_hash_rec *) * idx_max_first_occr);
+			}
+		      idx_first_occr[IdxHashUsed] = idx_ent;
+		      IdxHashUsed++;
+		      IdxHashTable[hashval] = idx_ent;
+		      break;
+		    }
+		  
+		  /* Compare the words */
+		  s1 = word;
+		  s2 = idx_ent->word;
+		  len = *s1 + 1;
+		  for (; len; len--)
+		    if (*s1++ != *s2++)
+		      break;
+		  
+		  if (len)
+		    {
+		      /* Entry is not the right one - move to next hash index */
+		      hashval = (hashval + step);
+		      if (hashval >= hsize)
+			hashval -= hsize;
+		    }
+		  else
+		    {
+		      /* Entry is correct - added PosEntry to word */
+		      PosEntry PE;
+		      PE.num_cases = 1;
+		      PE.blk = block;
+		      PE.blk_index = (unsigned short) blk_index;
+		      PE.offset = res % sd->sdh.lookback;
+		      AddPosEntry (&(idx_ent->PL), &PE);
+		      prevIdx = idx_ent;
+		      prevPE = &(idx_ent->PL->PE[idx_ent->PL->num_entries - 1]);
+		      break;
+		    }
+		}      
+	    }
+
+	  if (IdxHashUsed >= IdxHashSize >> 1)
+	    {
+	      idx_hash_rec **ht;
+	      unsigned long size;
+	      unsigned long i;
+	      size = prime (IdxHashSize * 2);
+	      if (!(ht = Xmalloc (sizeof (idx_hash_rec *) * size)))
+		FatalError (1, "Unable to allocate memory for idx table");
+	      bzero ((char *) ht, sizeof (idx_hash_rec *) * size);
+	      ChangeMem (sizeof (idx_hash_rec *) * size);
+
+	      for (i = 0; i < IdxHashSize; i++)
+		if (IdxHashTable[i])
+		  {
+		    register u_char *wptr;
+		    idx_hash_rec *ent;
+		    register unsigned long hashval, step;
+		    
+		    wptr = IdxHashTable[i]->word;
+		    HASH (hashval, step, wptr, size);
+		    ent = ht[hashval];
+		    while (ent)
+		      {
+			hashval += step;
+			if (hashval >= size)
+			  hashval -= size;
+			ent = ht[hashval];
+		      }
+		    ht[hashval] = IdxHashTable[i];
+		  }
+	      Xfree (IdxHashTable);
+	      ChangeMem (-sizeof (idx_hash_rec *) * IdxHashSize);
+	      IdxHashTable = ht;
+	      IdxHashSize = size;
+	    }
+	  
+	} /* end for each word */
+
+    } /* end for each block */
+
+}
+ 
+static int 
+idx_comp (const void *A, const void *B)
+{
+  u_char *s1 = (*((idx_hash_rec **) A))->word;
+  u_char *s2 = (*((idx_hash_rec **) B))->word;
+  return (casecompare (s1, s2));
+}
+
+
+void
+save_idx (char * filename, int stem_method)
+{
+  char *FName;
+  unsigned long i, j, pos, First_word, num;
+  struct stem_idx_header sih;
+  u_char *buffer, *last_word = NULL;
+  unsigned short *pointers;
+  int buf_in_use;
+  unsigned short ptrs_in_use, word_num;
+  FILE *idbi = NULL, *tmp = NULL;
+
+  FName = make_name (filename, ".tmp", NULL);
+  if (!(tmp = fopen (FName, "w+b")))
+    FatalError (1, "Unable to open \"%s\".\n", FName);
+
+  /* Delete the file now */
+  unlink (FName);
+
+  /* Create appropriate stem index file */
+  switch (stem_method)
+    {
+    case (1):
+      {
+	idbi = create_file (filename, INVF_DICT_BLOCKED_1_SUFFIX, "wb", MAGIC_STEM_1,
+			    MG_ABORT);
+	break;
+      }
+
+    case (2):
+      {
+	idbi = create_file (filename, INVF_DICT_BLOCKED_2_SUFFIX, "wb", MAGIC_STEM_2,
+			    MG_ABORT);
+	break;
+      }
+    case (3):
+      {
+	idbi = create_file (filename, INVF_DICT_BLOCKED_3_SUFFIX, "wb", MAGIC_STEM_3,
+			    MG_ABORT);
+	break;
+      }
+    }
+
+  if (!idbi)
+    FatalError (1, "Could NOT create .invf.blocked.%d file", stem_method);
+
+  PackIdxHashTable();
+  qsort (IdxHashTable, IdxHashUsed, sizeof (idx_hash_rec *), idx_comp);
+
+  sih.lookback = lookback;
+  sih.block_size = block_size;
+  sih.num_blocks = 0;
+  sih.blocks_start = 0;
+  sih.index_chars = 0;
+  sih.num_of_words = IdxHashUsed;
+
+  fwrite ((char *) &sih, sizeof (sih), 1, idbi);
+
+  if (!(buffer = Xmalloc (block_size + 512)))
+    FatalError (1, "Unable to allocate memory for \"buffer\"\n");
+  if (!(pointers = Xmalloc (block_size + 512)))
+    FatalError (1, "Unable to allocate memory for \"buffer\"\n");
+
+  buf_in_use = 0;
+  pos = 0;
+  word_num = 0;
+  ptrs_in_use = 0;
+  First_word = 0;
+
+  /* For each word in the hashtable... */
+  for (i = 0; i < IdxHashUsed; i++)
+    {
+      register unsigned long extra, copy, suff;
+      register struct idx_hash_rec *ent = IdxHashTable[i];
+
+      /* build a new word on top of prev */
+      if (last_word != NULL)
+	copy = prefixlen (last_word, ent->word);
+      else
+	copy = 0;
+      suff = *(ent->word) - copy;
+      last_word = ent->word;
+
+      if (word_num % sih.lookback == 0)
+	/* Will need copy chars to add + a pointer in index */
+	extra = copy + sizeof (*pointers);
+      else
+	extra = 0;
+      if ((ptrs_in_use + 1) * sizeof (*pointers) + sizeof (ptrs_in_use) + extra +
+	  buf_in_use + sizeof (First_word) + suff + 1 + sizeof (ent->PL->num_entries) + 
+	  ent->PL->num_entries * sizeof (PosEntry) > block_size)
+	{
+	  /* Dump buffer to tmp file */
+	  int chunk;
+	  HTONUL(First_word);  /* [RPAP - Jan 97: Endian Ordering] */
+	  HTONUS(word_num);  /* [RPAP - Jan 97: Endian Ordering] */
+	  fwrite (&First_word, sizeof (First_word), 1, tmp);
+	  fwrite (&word_num, sizeof (word_num), 1, tmp);
+	  fwrite (pointers, sizeof (*pointers), ptrs_in_use, tmp);
+	  fwrite (buffer, sizeof (u_char), buf_in_use, tmp);
+	  bzero ((char *) buffer, block_size);
+	  chunk = buf_in_use + ptrs_in_use * sizeof (*pointers) +
+	    sizeof (ptrs_in_use) + sizeof (First_word);
+	  if (force && chunk < block_size)
+	    {
+	      fwrite (buffer, sizeof (u_char), block_size - chunk, tmp);
+	      chunk = block_size;
+	    }
+
+	  pos += chunk;
+
+	  buf_in_use = 0;
+	  word_num = 0;
+	  ptrs_in_use = 0;
+	  sih.num_blocks++;
+
+	  /* Check that entry will fit into new block */
+	  if (sizeof (*pointers) + sizeof (ptrs_in_use) + extra + sizeof (First_word) +
+	      suff + 1 + sizeof (ent->PL->num_entries) + 
+	      ent->PL->num_entries * sizeof (PosEntry) > block_size)
+	    FatalError (1, "Block size to small");
+
+	}
+
+      if (word_num % sih.lookback == 0)
+	{
+	  HTONUS2(buf_in_use, pointers[ptrs_in_use++]);  /* [RPAP - Jan 97: Endian Ordering] */
+	  suff += copy;
+	  copy = 0;
+	}
+
+      /* Output Word information */
+      buffer[buf_in_use++] = copy;
+      buffer[buf_in_use++] = suff;
+      bcopy ((char *) (ent->word + copy + 1), (char *) (buffer + buf_in_use), suff);
+      buf_in_use += suff;
+      HTONUI(ent->PL->num_entries);  /* [RPAP - Jan 97: Endian Ordering] */
+      bcopy ((char *) &(ent->PL->num_entries), (char *) (buffer + buf_in_use), sizeof (ent->PL->num_entries));
+      NTOHUI(ent->PL->num_entries);  /* [RPAP - Jan 97: Endian Ordering] */
+      buf_in_use += sizeof (ent->PL->num_entries);
+
+      for (j = 0; j < ent->PL->num_entries; j++)
+	{
+	  register PosEntry *pe = &(ent->PL->PE[j]);
+	  HTONUI(pe->num_cases);  /* [RPAP - Jan 97: Endian Ordering] */
+	  bcopy ((char *) &(pe->num_cases), (char *) (buffer + buf_in_use), sizeof (pe->num_cases));
+	  buf_in_use += sizeof (pe->num_cases);
+	  HTONUI(pe->blk);  /* [RPAP - Jan 97: Endian Ordering] */
+	  bcopy ((char *) &(pe->blk), (char *) (buffer + buf_in_use), sizeof (pe->blk));
+	  buf_in_use += sizeof (pe->blk);
+	  HTONUS(pe->blk_index);  /* [RPAP - Jan 97: Endian Ordering] */
+	  bcopy ((char *) &(pe->blk_index), (char *) (buffer + buf_in_use), sizeof (pe->blk_index));
+	  buf_in_use += sizeof (pe->blk_index);
+	  HTONUS(pe->offset);  /* [RPAP - Jan 97: Endian Ordering] */
+	  bcopy ((char *) &(pe->offset), (char *) (buffer + buf_in_use), sizeof (pe->offset));
+	  buf_in_use += sizeof (pe->offset);
+	}
+
+      if (buf_in_use + ptrs_in_use * sizeof (*pointers) +
+	  sizeof (ptrs_in_use) > block_size)
+	FatalError (1, "Fatal Internal Error # 64209258\n");
+
+      if (word_num == 0)
+	{
+	  /* Write word to main index */
+	  fwrite (ent->word, sizeof (u_char), *(ent->word) + 1, idbi);
+	  HTONUL(pos);  /* [RPAP - Jan 97: Endian Ordering] */
+	  fwrite (&pos, sizeof (pos), 1, idbi);
+	  NTOHUL(pos);  /* [RPAP - Jan 97: Endian Ordering] */
+	  sih.index_chars += *(ent->word) + 1;
+	  First_word = i;
+	}
+      word_num++;
+    } /* end for each word */
+
+  if (buf_in_use)
+    {
+      /* Write last buffer to tmp file */
+      int chunk;
+
+      /* [RPAP - Jan 97: Endian Ordering] */
+      HTONUL(First_word);
+      HTONUS(word_num);
+
+      fwrite (&First_word, sizeof (First_word), 1, tmp);
+      fwrite (&word_num, sizeof (word_num), 1, tmp);
+      fwrite (pointers, sizeof (*pointers), ptrs_in_use, tmp);
+      fwrite (buffer, sizeof (u_char), buf_in_use, tmp);
+      bzero ((char *) buffer, block_size);
+      chunk = buf_in_use + ptrs_in_use * sizeof (*pointers) +
+	sizeof (ptrs_in_use) + sizeof (First_word);
+      if (force && chunk < block_size)
+	{
+	  fwrite (buffer, sizeof (u_char), block_size - chunk, tmp);
+	  chunk = block_size;
+	}
+
+      sih.num_blocks++;
+    }
+
+  rewind (tmp);
+  sih.blocks_start = sih.index_chars + sizeof (u_long) + sizeof (sih) +
+    sih.num_blocks * sizeof (pos);
+  if (force)
+    {
+      int amount;
+      amount = sih.blocks_start % block_size;
+      if (amount != 0)
+	{
+	  bzero ((char *) buffer, block_size);
+	  fwrite (buffer, sizeof (u_char), block_size - amount, idbi);
+	  sih.blocks_start += block_size - amount;
+	}
+    }
+
+  while ((num = fread (buffer, sizeof (u_char), block_size, tmp)) != 0)
+    fwrite (buffer, sizeof (u_char), num, idbi);
+  fclose (tmp);
+
+  /* skip over the magic number */
+  fseek (idbi, sizeof (u_long), 0);
+
+  /* [RPAP - Jan 97: Endian Ordering] */
+  HTONUL(sih.lookback);
+  HTONUL(sih.block_size);
+  HTONUL(sih.num_blocks);
+  HTONUL(sih.blocks_start);
+  HTONUL(sih.index_chars);
+  HTONUL(sih.num_of_words);
+
+  fwrite (&sih, sizeof (sih), 1, idbi);
+  fclose (idbi);
+
+#ifndef SILENT
+  Message ("Stem %d:\n", stem_method);
+  Message ("     Block size   : %10d\n", block_size);
+  Message ("     Num_blocks   : %10d\n", NTOHUL(sih.num_blocks));  /* [RPAP - Jan 97: Endian Ordering] */
+  Message ("     Max mem used : %10.1f Mb\n", (double) MaxMemInUse / 1024.0 / 1024.0);
+  Message ("     Num_of_words : %10d\n", NTOHUL(sih.num_of_words));  /* [RPAP - Jan 97: Endian Ordering] */
+#endif
+}
+
+
+void
+UpdateStemDict (char * filename, int stem_method)
+{
+  FILE *idb;
+  struct stem_dict_header sdh;
+
+  if (!(idb = open_file (filename, INVF_DICT_BLOCKED_SUFFIX, "r+b",
+			 MAGIC_STEM, MG_CONTINUE)))
+    FatalError (1, "Could not update stemmed dict");
+
+  fread ((char *) &sdh, sizeof (sdh), 1, idb);
+  NTOHUL(sdh.indexed);  /* [RPAP - Jan 97: Endian Ordering] */
+  sdh.indexed |= 1 << (stem_method - 1);
+  HTONUL(sdh.indexed);
+  fseek (idb, sizeof (u_long), 0);
+  fwrite ((char *) &sdh, sizeof (sdh), 1, idb);
+  fclose (idb);
+}
+
+
+
+/* Main */
+int main (int argc, char **argv)
+{
+  File *idb;    /* File to .invf.dict.blocked */
+  char *filename = "";
+  stemmed_dict *sd;   /* Stemmed dictionary */
+  int ch;
+  char path[512];
+  int stem_method = 0;
+
+  msg_prefix = argv[0];
+  opterr = 0;
+  while ((ch = getopt (argc, argv, "f:d:b:hFs:")) != -1)
+    switch (ch)
+      {
+      case 'f':		/* input file */
+	filename = optarg;
+	break;
+      case 'd':
+	set_basepath (optarg);
+	break;
+      case 'b':
+	block_size = atoi (optarg);
+	break;
+      case 'F':
+	force = 1;
+	break;
+      case 's':
+	stem_method = atoi (optarg);
+	break;
+      case 'h':
+      case '?':
+	fprintf (stderr, "usage: %s [-d directory] "
+		 "[-b num] [-F] [-h] -s 1|2|3 -f name\n", argv[0]);
+	exit (1);
+      }
+
+  if (stem_method < 1 || stem_method > 3)
+    FatalError (1, "Stem method must be 1, 2 or 3");
+
+  /* Open required stem dict file */
+  sprintf (path, FILE_NAME_FORMAT, get_basepath (), filename, INVF_DICT_BLOCKED_SUFFIX);
+  if (!(idb = Fopen (path, "rb", MAGIC_STEM)))
+    FatalError (1, "Unable to open \"%s\"", path);
+
+  /* Read in idb header and index to blocks */
+  if (!(sd = ReadStemDictBlk (idb)))
+    FatalError (1, "Could not read stemmed dictionary");
+
+  /* Process stemmed dictionary */
+  init_process ();
+  process_stem_dict (sd, stem_method);
+  save_idx (filename, stem_method);
+ 
+  /* Close stemmed dict */
+  Fclose (idb);
+
+  /* Update stemmed dict */
+  UpdateStemDict (filename, stem_method);
+
+  return 0;
+}
+
Index: /main/tags/2.25/gsdl/packages/mg/src/text/mg_text_estimate.1
===================================================================
--- /main/tags/2.25/gsdl/packages/mg/src/text/mg_text_estimate.1	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/mg/src/text/mg_text_estimate.1	(revision 21064)
@@ -0,0 +1,112 @@
+.\"------------------------------------------------------------
+.\" Id - set Rv,revision, and Dt, Date using rcs-Id tag.
+.de Id
+.ds Rv \\$3
+.ds Dt \\$4
+..
+.Id $Id$
+.\"------------------------------------------------------------
+.TH mg_text_estimate 1 \*(Dt CITRI
+.SH NAME
+mg_text_estimate \- Estimate the size of the compressed text based on the text statistics and a compression dictionary.
+.SH SYNOPSIS
+.B mg_text_estimate
+[
+.B \-h
+]
+[
+.BR \-H " |"
+.BR \-B " |"
+.BR \-D " |"
+.BR \-Y " |"
+.B \-M
+]
+.if n .ti +9n
+.I stats-dict
+.I compression-dict
+.SH DESCRIPTION
+This program estimates the size of the compressed text that would be
+generated if text with certain statistics were compressed with a
+particular dictionary.  This program has no real use in the
+.BR mg (1)
+system, except for experimenting with the
+.BR mg_compression_dict (1)
+program.
+.SH OPTIONS
+Options may appear in any order.
+.TP "\w'\fB\-m\fP'u+2n"
+.B \-h
+This displays a usage line on
+.IR stderr .
+.TP
+.B \-H
+This specifies that novel words will be coded character by character
+using Huffman codes.
+.TP
+.B \-B
+This specifies that the size of an auxiliary dictionary will be
+estimated.  Each novel word found will be placed at the end of the
+auxiliary dictionary.  Novel words will be coded in the compressed text
+using binary codes.  The binary code represents their occurrence
+position in the auxiliary dictionary.
+.TP
+.B \-D
+This specifies that the size of an auxiliary dictionary will be
+estimated.  Each novel word found will be placed at the end of the
+auxiliary dictionary.  Novel words will be coded in the compressed text
+using delta codes.  The delta code represents their occurrence position
+in the auxiliary dictionary.
+.TP
+.B \-Y
+This specifies that the size of an auxiliary dictionary will be
+estimated.  Each novel word found will be placed at the end of the
+auxiliary dictionary.  Novel words will be coded in the compressed text
+using a combination of gamma and binary codes.  The code represents
+their occurrence position in the auxiliary dictionary.  This generally
+produces better compression than
+.B \-B
+or
+.BR \-D .
+.TP
+.B \-M
+This specifies that the size of an auxiliary dictionary will be
+estimated.  Each novel word found will be placed at the end of the
+auxiliary dictionary.  Novel words will be coded in the compressed text
+using a combination of gamma and binary codes.  The code represents
+their occurrence position in the auxiliary dictionary.  This method is
+adaptive within documents, and generally produces better compression
+than
+.BR \-B ,
+.B \-D
+or
+.BR \-Y .
+.SH FILES
+.TP 20
+.B *.text.stats
+Statistics about the text.
+.TP
+.B *.text.dict
+Compressed compression dictionary.
+.SH "SEE ALSO"
+.na
+.BR mg (1),
+.BR mg_compression_dict (1),
+.BR mg_fast_comp_dict (1),
+.BR mg_get (1),
+.BR mg_invf_dict (1),
+.BR mg_invf_dump (1),
+.BR mg_invf_rebuild (1),
+.BR mg_passes (1),
+.BR mg_perf_hash_build (1),
+.BR mg_weights_build (1),
+.BR mgbilevel (1),
+.BR mgbuild (1),
+.BR mgdictlist (1),
+.BR mgfelics (1),
+.BR mgquery (1),
+.BR mgstat (1),
+.BR mgtic (1),
+.BR mgticbuild (1),
+.BR mgticdump (1),
+.BR mgticprune (1),
+.BR mgticstat (1).
Index: /main/tags/2.25/gsdl/packages/mg/src/text/mg_text_estimate.c
===================================================================
--- /main/tags/2.25/gsdl/packages/mg/src/text/mg_text_estimate.c	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/mg/src/text/mg_text_estimate.c	(revision 21064)
@@ -0,0 +1,581 @@
+/**************************************************************************
+ *
+ * mg_text_estimate.c -- Program to estimate the compressed text size
+ * Copyright (C) 1994  Neil Sharman
+ *
+ * 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.
+ *
+ * $Id$
+ *
+ **************************************************************************/
+
+#include "sysfuncs.h"
+
+#include "memlib.h"
+#include "messages.h"
+#include "local_strings.h"
+#include "bitio_gen.h"
+#include "bitio_m.h"
+#include "bitio_m_stdio.h"
+#include "timing.h"
+#include "mgheap.h"
+#include "netorder.h"  /* [RPAP - Jan 97: Endian Ordering] */
+
+#include "mg_files.h"
+#include "locallib.h"
+#include "invf.h"
+#include "text.h"
+#include "words.h"
+#include "mg.h"
+#include "comp_dict.h"
+#include "hash.h"
+
+
+
+
+
+/*
+   $Log$
+   Revision 1.1  1999/08/10 21:18:14  sjboddie
+   renamed mg-1.3d directory mg
+
+   Revision 1.4  1999/01/15 03:05:51  rjmcnab
+
+   Renamed lib/heap to be lib/mgheap (it was causing some problems with
+   some versions of the STL libraries which contained a heap.h)
+
+   Revision 1.3  1998/12/17 09:12:53  rjmcnab
+
+   Altered mg to process utf-8 encoded Unicode. The main changes
+   are in the parsing of the input, the casefolding, and the stemming.
+
+   Revision 1.2  1998/11/25 07:55:48  rjmcnab
+
+   Modified mg to that you can specify the stemmer you want
+   to use via a command line option. You specify it to
+   mg_passes during the build process. The number of the
+   stemmer that you used is stored within the inverted
+   dictionary header and the stemmed dictionary header so
+   the correct stemmer is used in later stages of building
+   and querying.
+
+   Revision 1.1  1998/11/17 09:35:19  rjmcnab
+   *** empty log message ***
+
+   * Revision 1.3  1994/10/20  03:56:59  tes
+   * I have rewritten the boolean query optimiser and abstracted out the
+   * components of the boolean query.
+   *
+   * Revision 1.2  1994/09/20  04:41:54  tes
+   * For version 1.1
+   *
+ */
+
+static char *RCSID = "$Id$";
+
+typedef struct stats_t
+  {
+    u_long freq, occur;
+    u_long len;
+  }
+stats_t;
+
+static u_long huff_count = 0;
+static u_long escape_count = 0;
+
+
+char mode = 'H';
+
+/* [RJM 07/97: 4G limit] */
+static double ReadInWordsStandard (char *name, double *num_bytes);
+static double ReadInWordsSpecial (char *name, double *num_bytes,
+				  double *num_extra_bytes,
+				  u_long *aux_compressed);
+
+
+
+
+int main (int argc, char **argv)
+{
+  char *stats_dict = NULL, *comp_dict = NULL;
+  ProgTime StartTime;
+  double num_bytes, num_extra_bytes = 0; /* [RJM 07/97: 4G limit] */
+  u_long aux_compressed;
+  int ch;
+  double bytes;
+  opterr = 0;
+  msg_prefix = argv[0];
+  while ((ch = getopt (argc, argv, "BMDYHh")) != -1)
+    switch (ch)
+      {
+      case 'B':
+	Message ("The compressed text size for this method cannot be\n"
+		 "estimated exactly, so an upper bound will be calculated.");
+	mode = ch;
+	break;
+      case 'M':
+	Message ("The compressed text size for this method cannot be\n"
+		 "estimated exactly, so an upper bound will be calculated.");
+	mode = 'Y';
+	break;
+      case 'D':
+      case 'Y':
+      case 'H':
+	mode = ch;
+	break;
+      case 'h':
+      case '?':
+	fprintf (stderr, "usage: %s [-h] [B|M|D|Y|H] stats_dict comp_dict\n",
+		 argv[0]);
+	exit (1);
+      }
+
+  if (optind < argc)
+    stats_dict = argv[optind++];
+  else
+    stats_dict = NULL;
+  if (optind < argc)
+    comp_dict = argv[optind++];
+  else
+    {
+      fprintf (stderr, "usage: %s [-h] [B|M|D|Y|H] stats_dict comp_dict\n",
+	       argv[0]);
+      exit (1);
+    }
+
+
+
+  GetTime (&StartTime);
+
+  if (LoadCompressionDictionary (comp_dict) == COMPERROR)
+    exit (1);
+
+  if (mode == 'H')
+    bytes = ReadInWordsStandard (stats_dict, &num_bytes);
+  else
+    bytes = ReadInWordsSpecial (stats_dict, &num_bytes, &num_extra_bytes,
+				&aux_compressed);
+
+
+  Message ("Compressed Text %.2f Mb ( %.0f bytes   %0.3f %%)",
+	   bytes / 1024.0 / 1024, bytes, bytes * 100 / num_bytes);
+  Message ("Words portion of the dictionary %.2f Mb ( %.0f bytes   %0.3f %%)",
+	   Words_disk / 1024.0 / 1024, Words_disk * 1.0,
+	   (Words_disk * 100.0) / num_bytes);
+  if (mode == 'H')
+    Message ("Huffman info for chars in dictionary %.2f Mb ( %.0f bytes   %0.3f %%)",
+	     Chars_disk / 1024.0 / 1024, Chars_disk * 1.0,
+	     (Chars_disk * 100.0) / num_bytes);
+  else
+    {
+      Message ("Aux dictionary (Uncompressed) %.2f Mb ( %.0f bytes   %0.3f %%)",
+	       num_extra_bytes / 1024.0 / 1024, num_extra_bytes * 1.0,
+	       (num_extra_bytes * 100.0) / num_bytes);
+      Message ("Aux dictionary (Compressed)   %.2f Mb ( %.0f bytes   %0.3f %%)",
+	       aux_compressed / 1024.0 / 1024, aux_compressed * 1.0,
+	       (aux_compressed * 100.0) / num_bytes);
+    }
+  Message ("Words and non-words in the text %u", huff_count + escape_count);
+  Message ("Words and non-words coded by escapes %u ( %0.3f %%)", escape_count,
+	   escape_count * 100.0 / huff_count);
+  Message ("%s", ElapsedTime (&StartTime, NULL));
+  return 0;
+}
+
+
+
+
+
+static double 
+ReadInWordsStandard (char *name, double *num_bytes)
+{
+  compression_stats_header csh;
+  FILE *f;
+  u_long which;
+  double bytes, bits = 0;
+
+  f = open_named_file (name, "rb", MAGIC_STATS_DICT, MG_ABORT);  /* [RPAP - Feb 97: WIN32 Port] */
+
+  fread (&csh, sizeof (csh), 1, f);
+
+  /* [RPAP - Jan 97: Endian Ordering] */
+  NTOHUL(csh.num_docs);
+  NTOHD(csh.num_bytes); /* [RJM 07/97: 4G limit] */
+
+  for (which = 0; which < 2; which++)
+    {
+      frags_stats_header fsh;
+      int j;
+      fread (&fsh, sizeof (fsh), 1, f);
+
+      /* [RPAP - Jan 97: Endian Ordering] */
+      NTOHUL(fsh.num_frags);
+      NTOHUL(fsh.mem_for_frags);
+
+      for (j = 0; j < fsh.num_frags; j++)
+	{
+	  int len, freq, res, occur_num;
+	  u_char Word[16];
+	  fread (&freq, sizeof (freq), 1, f);
+	  fread (&occur_num, sizeof (occur_num), 1, f);
+	  len = fgetc (f);
+
+	  /* [RPAP - Jan 97: Endian Ordering] */
+	  NTOHSI(freq);
+	  NTOHSI(occur_num);
+
+	  Word[0] = len;
+	  fread (Word + 1, len, 1, f);
+
+	  /* Search the hash table for Word */
+	  if (ht[which])
+	    {
+	      register unsigned long hashval, step;
+	      register int tsize = ht[which]->size;
+	      register u_char **wptr;
+	      HASH (hashval, step, Word, tsize);
+	      for (;;)
+		{
+		  register u_char *s1;
+		  register u_char *s2;
+		  register int len;
+		  wptr = ht[which]->table[hashval];
+		  if (wptr == NULL)
+		    {
+		      res = COMPERROR;
+		      break;
+		    }
+
+		  /* Compare the words */
+		  s1 = Word;
+		  s2 = *wptr;
+		  len = *s1 + 1;
+		  for (; len; len--)
+		    if (*s1++ != *s2++)
+		      break;
+
+		  if (len)
+		    {
+		      hashval += step;
+		      if (hashval >= tsize)
+			hashval -= tsize;
+		    }
+		  else
+		    {
+		      res = ht[which]->table[hashval] - ht[which]->words;
+		      break;
+		    }
+		}
+	    }
+	  else
+	    res = COMPERROR;
+
+	  /* Check that the word was found in the dictionary */
+	  if (res == COMPERROR)
+	    {
+	      escape_count += freq;
+	      if (cdh.dict_type == MG_COMPLETE_DICTIONARY)
+		Message ("Unknown word \"%.*s\"\n", *Word, Word + 1);
+	      if (cdh.dict_type == MG_PARTIAL_DICTIONARY)
+		{
+		  unsigned i;
+		  if (ht[which])
+		    {
+		      res = ht[which]->hd->num_codes - 1;
+		      bits += ht[which]->hd->clens[res] * freq;
+		    }
+		  bits += lens_huff[which].clens[Word[0]] * freq;
+		  for (i = 0; i < Word[0]; i++)
+		    bits += char_huff[which].clens[Word[i + 1]] * freq;
+		}
+	      if (cdh.dict_type == MG_SEED_DICTIONARY)
+		{
+		  unsigned i;
+		  if (ht[which])
+		    {
+		      res = ht[which]->hd->num_codes - 1;
+		      bits += ht[which]->hd->clens[res] * freq;
+		    }
+		  bits += lens_huff[which].clens[Word[0]] * freq;
+		  for (i = 0; i < Word[0]; i++)
+		    bits += char_huff[which].clens[Word[i + 1]] * freq;
+		}
+	    }
+	  else
+	    {
+	      bits += ht[which]->hd->clens[res] * freq;
+	      huff_count += freq;
+	    }
+	}
+    }
+  fclose (f);
+
+
+  /*
+   * The 5.5 bits added on per document consist of
+   *   1 bit for the word/non-word flag at the start of the document.
+   *   1 bit on average for document termination.
+   *   3.5 bits on average for padding to a byte boundary.
+   */
+  bits += 5.5 * csh.num_docs;
+
+  bytes = bits / 8 + sizeof (compressed_text_header) + sizeof (u_long);
+
+  *num_bytes = csh.num_bytes;
+
+  return bytes;
+}
+
+
+static int 
+stats_comp (const void *a, const void *b)
+{
+  return ((stats_t *) a)->occur - ((stats_t *) b)->occur;
+}
+
+
+
+
+
+static double 
+ReadInWordsSpecial (char *name, double *num_bytes,
+		    double *num_extra_bytes,
+		    u_long *aux_compressed)
+{
+  compression_stats_header csh;
+  FILE *f;
+  u_long magic, which;
+  double bytes, bits = 0;
+  double size[2];
+
+  if (!(f = fopen (name, "rb")))  /* [RPAP - Feb 97: WIN32 Port] */
+    FatalError (1, "Unable to open file \"%s\"\n", name);
+
+  if (fread (&magic, sizeof (magic), 1, f) != 1)
+    FatalError (1, "Unable to read magic number");
+
+  NTOHUL(magic);  /* [RPAP - Jan 97: Endian Ordering] */
+
+  if (magic != MAGIC_STATS_DICT)
+    FatalError (1, "Bad magic number");
+
+  fread (&csh, sizeof (csh), 1, f);
+
+  /* [RPAP - Jan 97: Endian Ordering] */
+  NTOHUL(csh.num_docs);
+  NTOHD(csh.num_bytes); /* [RJM 07/97: 4G limit] */
+
+  for (which = 0; which < 2; which++)
+    {
+      stats_t *stats;
+      frags_stats_header fsh;
+      int j, num = 0;
+      long lens[16], chars[256];
+
+      bzero ((char *) lens, sizeof (lens));
+      bzero ((char *) chars, sizeof (chars));
+
+      fread (&fsh, sizeof (fsh), 1, f);
+
+      /* [RPAP - Jan 97: Endian Ordering] */
+      NTOHUL(fsh.num_frags);
+      NTOHUL(fsh.mem_for_frags);
+
+      stats = Xmalloc (fsh.num_frags * sizeof (*stats));
+      if (!stats)
+	FatalError (1, "Unable to allocate memory for stats");
+      for (j = 0; j < fsh.num_frags; j++)
+	{
+	  int len, res;
+	  u_char Word[16];
+	  fread (&stats[num].freq, sizeof (stats[num].freq), 1, f);
+	  fread (&stats[num].occur, sizeof (stats[num].occur), 1, f);
+	  len = fgetc (f);
+
+	  /* [RPAP - Jan 97: Endian Ordering] */
+	  NTOHSI(stats[num].freq);
+	  NTOHSI(stats[num].occur);
+
+	  stats[num].len = len + 1;
+
+	  Word[0] = len;
+	  fread (Word + 1, len, 1, f);
+
+	  /* Search the hash table for Word */
+	  if (ht[which])
+	    {
+	      register unsigned long hashval, step;
+	      register int tsize = ht[which]->size;
+	      register u_char **wptr;
+	      HASH (hashval, step, Word, tsize);
+	      for (;;)
+		{
+		  register u_char *s1;
+		  register u_char *s2;
+		  register int len;
+		  wptr = ht[which]->table[hashval];
+		  if (wptr == NULL)
+		    {
+		      res = COMPERROR;
+		      break;
+		    }
+
+		  /* Compare the words */
+		  s1 = Word;
+		  s2 = *wptr;
+		  len = *s1 + 1;
+		  for (; len; len--)
+		    if (*s1++ != *s2++)
+		      break;
+
+		  if (len)
+		    {
+		      hashval += step;
+		      if (hashval >= tsize)
+			hashval -= tsize;
+		    }
+		  else
+		    {
+		      res = ht[which]->table[hashval] - ht[which]->words;
+		      break;
+		    }
+		}
+	    }
+	  else
+	    res = COMPERROR;
+
+	  assert (stats[num].freq > 0);
+
+	  /* Check that the word was found in the dictionary */
+	  if (res == COMPERROR)
+	    {
+	      if (cdh.dict_type == MG_COMPLETE_DICTIONARY)
+		Message ("Unknown word \"%.*s\"\n", *Word, Word + 1);
+	      if ((cdh.dict_type == MG_PARTIAL_DICTIONARY ||
+		   cdh.dict_type == MG_SEED_DICTIONARY) &&
+		  ht[which])
+		{
+		  int k;
+		  res = ht[which]->hd->num_codes - 1;
+		  bits += ht[which]->hd->clens[res] * stats[num].freq;
+		  lens[Word[0]]++;
+		  for (k = 0; k < (int) Word[0]; k++)
+		    chars[Word[k + 1]]++;
+		}
+	      num++;
+	    }
+	  else
+	    {
+	      bits += ht[which]->hd->clens[res] * stats[num].freq;
+	    }
+	}
+
+      {
+	int j, num_buckets = 0;
+	int start[10], end[10];
+	long flens[16], fchars[256];
+
+	for (j = 0; j < 256; j++)
+	  if (!chars[j] && PESINAWORD (j) == which)
+	    fchars[j] = 1;
+	  else
+	    fchars[j] = chars[j];
+	for (j = 0; j < 16; j++)
+	  if (!lens[j])
+	    flens[j] = 1;
+	  else
+	    flens[j] = lens[j];
+
+	size[which] = Calculate_Huffman_Size (16, flens, lens) +
+	  Calculate_Huffman_Size (256, fchars, chars);
+
+
+	qsort (stats, num, sizeof (*stats), stats_comp);
+
+
+	if (mode == 'Y')
+	  {
+	    int k;
+	    num_buckets = 1;
+	    start[0] = 0;
+	    end[0] = cdh.num_words[which] - 1;
+	    Message ("There are %d novel %swords", num, which ? "" : "non-");
+	    while (end[num_buckets - 1] < num)
+	      {
+		start[num_buckets] = end[num_buckets - 1] + 1;
+		end[num_buckets] = start[num_buckets] +
+		  (end[num_buckets - 1] - start[num_buckets - 1]) * 2;
+		num_buckets++;
+	      }
+	    for (k = 0; k < num_buckets; k++)
+	      Message ("Bucket %d   %d <= x <= %d\n", k + 1, start[k], end[k]);
+	  }
+
+	for (j = 0; j < num; j++)
+	  {
+	    (*num_extra_bytes) += stats[j].len;
+	    switch (mode)
+	      {
+	      case 'D':
+		bits += BIO_Delta_Length (j + 1) * stats[j].freq;
+		break;
+	      case 'B':
+		bits += BIO_Binary_Length (j + 1, num) * stats[j].freq;
+		break;
+	      case 'Y':
+		{
+		  int k = 0;
+		  while (j > end[k])
+		    k++;
+		  if (!(j - start[k] + 1 >= 1 &&
+			j - start[k] + 1 <= end[k] - start[k] + 1))
+		    {
+		      Message ("k = %d, j = %d", k, j);
+		      assert (j - start[k] + 1 >= 1 &&
+			      j - start[k] + 1 <= end[k] - start[k] + 1);
+		    }
+		  else
+		    {
+		      bits += (BIO_Gamma_Length (k + 1) +
+			       BIO_Binary_Length (j - start[k] + 1,
+						  end[k] - start[k] + 1)) *
+			stats[j].freq;
+		    }
+		}
+	      }
+	  }
+	if (mode == 'B' && num)
+	  bits += BIO_Delta_Length (num) * csh.num_docs;
+      }
+      Xfree (stats);
+    }
+  fclose (f);
+
+  *aux_compressed = (size[0] + size[1]) / 8;
+
+  /*
+   * The 5.5 bits added on per document consist of
+   *   1 bit for the word/non-word flag at the start of the document.
+   *   1 bit on average for document termination.
+   *   3.5 bits on average for padding to a byte boundary.
+   */
+  bits += 5.5 * csh.num_docs;
+
+  bytes = bits / 8 + sizeof (compressed_text_header) + sizeof (u_long);
+
+  *num_bytes = csh.num_bytes;
+
+  return bytes;
+}
Index: /main/tags/2.25/gsdl/packages/mg/src/text/mg_text_merge.1
===================================================================
--- /main/tags/2.25/gsdl/packages/mg/src/text/mg_text_merge.1	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/mg/src/text/mg_text_merge.1	(revision 21064)
@@ -0,0 +1,76 @@
+.\"------------------------------------------------------------
+.\" Id - set Rv,revision, and Dt, Date using rcs-Id tag.
+.de Id
+.ds Rv \\$3
+.ds Dt \\$4
+..
+.Id $Id$
+.\"------------------------------------------------------------
+.TH mg_text_merge 1 \*(Dt CITRI
+.SH NAME
+mg_text_merge \- Append one compressed text file to another
+.SH SYNOPSIS
+.B mg_text_merge
+[
+.B \-h
+]
+[
+.BI \-d " directory"
+]
+.BI \-f " name"
+.SH DESCRIPTION
+This program takes two
+.BR mg (1)
+database inverted files and stemmed
+dictionaries, named "old" and "new" respectively, and creates
+a merged stemmed dictionary and inverted file.
+It is part of the
+.BR mgmerge (1)
+addition to the
+.BR mg (1)
+package.
+The two compressed text files are
+.IR "name" .old.text
+and
+.IR "name" .new.text.
+.SH OPTIONS
+Options may appear in any order.
+.TP "\w'\fB\-d\fP \fIdirectory\fP'u+2n"
+.B \-h
+This displays a usage line on
+.IR stderr .
+.TP
+.BI \-d " directory"
+This specifies the directory where the document collection can be found.
+.TP
+.BI \-f " name"
+This specifies the base name of the document collection.
+.SH ENVIRONMENT
+.TP "\w'\fBMGDATA\fP'u+2n"
+.SB MGDATA
+If this environment variable exists, then its value is used as the
+default directory where the
+.BR mg (1)
+collection files are.  If this variable does not exist, then the
+directory \*(lq\fB.\fP\*(rq is used by default.  The command line
+option
+.BI \-d " directory"
+overrides the directory in
+.BR MGDATA .
+.SH FILES
+.TP 20
+.B *.old.text
+The old compressed text.
+.TP
+.B *.new.text
+The new compressed text that will be appended
+.TP
+.SH "SEE ALSO"
+.na
+.BR mg (1),
+.BR mgmerge (1),
+.BR mg_get_merge (1),
+.BR mg_invf_merge (1),
+.BR mg_compression_dict (1),
+.BR mg_fast_comp_dict (1),
+.BR mgquery (1).
Index: /main/tags/2.25/gsdl/packages/mg/src/text/mg_text_merge.c
===================================================================
--- /main/tags/2.25/gsdl/packages/mg/src/text/mg_text_merge.c	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/mg/src/text/mg_text_merge.c	(revision 21064)
@@ -0,0 +1,249 @@
+/**************************************************************************
+ *
+ * mg_text_merge.c --- merge  *.text, *.text.idx files
+ *                     part of the mgmerge utility
+ * Copyright (C) 1995 Shane Hudson (shane@cosc.canterbury.ac.nz)
+ *
+ * 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.
+ *
+ * $Id$
+ * Last edited:  November 11 1994
+ *
+ **************************************************************************/
+
+#include "sysfuncs.h"
+
+#include "messages.h"
+#include "timing.h"
+#include "netorder.h"  /* [RPAP - Jan 97: Endian Ordering] */
+
+#include "locallib.h"
+#include "mg.h"
+#include "mg_merge.h"
+#include "mg_files.h"
+#include "text.h"
+
+
+/**** GLOBALS ****/
+FILE *text[3], *idx[3];
+
+typedef char FileName[256];
+FileName old_name, new_name, merge_name;
+
+long magicsize;			/* == where the header in a file begins */
+
+compressed_text_header cth[3];
+
+/*=======================================================================
+ * init_merge_text(): open files, set up global variables, etc
+ *=======================================================================*/
+int 
+init_merge_text ()
+{
+
+  /* open .text files */
+  text[OLD] = open_file (old_name, TEXT_SUFFIX, "r+b",
+			 MAGIC_TEXT, MG_ABORT);  /* [RPAP - Feb 97: WIN32 Port] */
+  magicsize = ftell (text[OLD]);
+  fread (&cth[OLD], sizeof (cth[OLD]), 1, text[OLD]);
+
+  text[NEW] = open_file (new_name, TEXT_SUFFIX, "rb+",
+			 MAGIC_TEXT, MG_ABORT);
+  fread (&cth[NEW], sizeof (cth[NEW]), 1, text[NEW]);
+
+  /* open .text.idx files */
+  idx[OLD] = open_file (old_name, TEXT_IDX_SUFFIX, "rb+",
+			MAGIC_TEXI, MG_ABORT);
+  fread (&cth[OLD], sizeof (cth[OLD]), 1, idx[OLD]);
+
+  /* [RPAP - Jan 97: Endian Ordering] */
+  NTOHUL(cth[OLD].num_of_docs);
+  NTOHD(cth[OLD].num_of_bytes); /* [RJM 07/97: 4G limit] */
+  NTOHUL(cth[OLD].num_of_words);
+  NTOHUL(cth[OLD].length_of_longest_doc);
+  NTOHD(cth[OLD].ratio);
+
+  idx[NEW] = open_file (new_name, TEXT_IDX_SUFFIX, "rb+",
+			MAGIC_TEXI, MG_ABORT);
+  fread (&cth[NEW], sizeof (cth[NEW]), 1, idx[NEW]);
+
+  /* [RPAP - Jan 97: Endian Ordering] */
+  NTOHUL(cth[NEW].num_of_docs);
+  NTOHD(cth[NEW].num_of_bytes); /* [RJM 07/97: 4G limit] */
+  NTOHUL(cth[NEW].num_of_words);
+  NTOHUL(cth[NEW].length_of_longest_doc);
+  NTOHD(cth[NEW].ratio);
+
+  idx[MERGE] = create_file (merge_name, TEXT_IDX_SUFFIX, "wb",
+			    MAGIC_TEXI, MG_ABORT);
+  return OK;
+}
+
+
+/*=======================================================================
+ * process_merge_text(): merge the files
+ *=======================================================================*/
+int 
+process_merge_text (void)
+{
+  int i;
+  u_long data, offset;
+  byte c;
+
+  /* update and write merged header to .text and .text.idx files */
+  /* they have the exact same header */
+  cth[MERGE].num_of_docs = cth[OLD].num_of_docs
+    + cth[NEW].num_of_docs;
+  cth[MERGE].num_of_bytes = cth[OLD].num_of_bytes
+    + cth[NEW].num_of_bytes;
+  cth[MERGE].num_of_words = cth[OLD].num_of_words;
+  cth[MERGE].length_of_longest_doc =
+    (cth[OLD].length_of_longest_doc > cth[NEW].length_of_longest_doc
+     ? cth[OLD].length_of_longest_doc
+     : cth[NEW].length_of_longest_doc);
+  cth[MERGE].ratio = ((cth[OLD].num_of_bytes * cth[OLD].ratio) +
+		      (cth[NEW].num_of_bytes * cth[NEW].ratio))
+    / cth[MERGE].num_of_bytes;
+
+  /* [RPAP - Jan 97: Endian Ordering] */
+  HTONUL(cth[MERGE].num_of_docs);
+  HTOND(cth[MERGE].num_of_bytes); /* [RJM 07/97: 4G limit] */
+  HTONUL(cth[MERGE].num_of_words);
+  HTONUL(cth[MERGE].length_of_longest_doc);
+  HTOND(cth[MERGE].ratio);
+
+  fwrite (&cth[MERGE], sizeof (cth[MERGE]), 1, idx[MERGE]);
+  fseek (text[OLD], magicsize, 0);
+  fwrite (&cth[MERGE], sizeof (cth[MERGE]), 1, text[OLD]);
+
+  /*
+   *  Update *.text.idx:  need to know where each new doc starts
+   *  in the appended .text file
+   */
+  for (i = 0; i < cth[OLD].num_of_docs; i++)
+    {
+      fread (&data, sizeof (u_long), 1, idx[OLD]);
+      fwrite (&data, sizeof (u_long), 1, idx[MERGE]);
+    }
+
+  /* offset is the amount to add to each entry from idx[NEW] */
+  fread (&offset, sizeof (u_long), 1, idx[OLD]);
+  NTOHUL(offset);  /* [RPAP - Jan 97: Endian Ordering] */
+  offset -= (4 + sizeof (cth[OLD]));	/* 4 for the magic number */
+
+  for (i = 0; i < cth[NEW].num_of_docs; i++)
+    {
+      fread (&data, sizeof (u_long), 1, idx[NEW]);
+      NTOHUL(data);  /* [RPAP - Jan 97: Endian Ordering] */
+      data += offset;
+      HTONUL(data);  /* [RPAP - Jan 97: Endian Ordering] */
+      fwrite (&data, sizeof (u_long), 1, idx[MERGE]);
+    }
+  /* write last u_long in idx[MERGE] (= length of file) */
+  fread (&data, sizeof (u_long), 1, idx[NEW]);
+  NTOHUL(data);  /* [RPAP - Jan 97: Endian Ordering] */
+  data += offset;
+  HTONUL(data);  /* [RPAP - Jan 97: Endian Ordering] */
+  fwrite (&data, sizeof (u_long), 1, idx[MERGE]);
+
+/******* update .text *******/
+  /* simply cat's the files together, except for the headers 
+   * and magic numbers, of course
+   */
+  fseek (text[OLD], 0L, 2);
+  while (!feof (text[NEW]))
+    {
+      fread (&c, sizeof (c), 1, text[NEW]);
+      if (!feof (text[NEW]))
+	fwrite (&c, sizeof (c), 1, text[OLD]);
+    }
+
+  return OK;
+}
+
+
+
+/*=======================================================================
+ * done_merge_text(): close files.
+ *=======================================================================*/
+int 
+done_merge_text (void)
+{
+  fclose (idx[MERGE]);
+  fclose (text[OLD]);
+  fclose (idx[OLD]);
+  fclose (text[NEW]);
+  fclose (idx[NEW]);
+
+  fprintf (stderr, "mg_text_merge: %ld documents added to %s\n",
+	   cth[NEW].num_of_docs, merge_name);
+
+  return OK;
+}
+
+
+/*=======================================================================
+ * usage()
+ *=======================================================================*/
+void 
+usage (char *progname)
+{
+  fprintf (stderr, "usage:  %s -f collection_name\n", progname);
+  exit (1);
+}
+
+
+/*=======================================================================
+ * main()
+ *=======================================================================*/
+int main (int argc, char *argv[])
+{
+  char *progname;
+  ProgTime start;
+  int ch;			/* for command line processing */
+
+  progname = argv[0];
+  msg_prefix = argv[0];
+  merge_name[0] = '\0';
+
+  while ((ch = getopt (argc, argv, "f:d:h")) != -1)
+    switch (ch)
+      {
+      case 'f':
+	strcpy (merge_name, optarg);
+	break;
+      case 'd':
+	set_basepath (optarg);
+	break;
+      case 'h':
+      case '?':
+      default:
+	usage (progname);
+      }
+
+  if (merge_name[0] == '\0')
+    usage (progname);
+  strcpy (old_name, merge_name);
+  strcat (old_name, ".old");
+  strcpy (new_name, merge_name);
+  strcat (new_name, ".new");
+
+  GetTime (&start);
+  init_merge_text ();
+  process_merge_text ();
+  done_merge_text ();
+  Message ("%s\n", ElapsedTime (&start, NULL));
+  return 0;
+}
Index: /main/tags/2.25/gsdl/packages/mg/src/text/mg_weights_build.1
===================================================================
--- /main/tags/2.25/gsdl/packages/mg/src/text/mg_weights_build.1	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/mg/src/text/mg_weights_build.1	(revision 21064)
@@ -0,0 +1,112 @@
+.\"------------------------------------------------------------
+.\" Id - set Rv,revision, and Dt, Date using rcs-Id tag.
+.de Id
+.ds Rv \\$3
+.ds Dt \\$4
+..
+.Id $Id$
+.\"------------------------------------------------------------
+.TH mg_weights_build 1 \*(Dt CITRI
+.SH NAME
+mg_weights_build \- builds the approximate weights file
+.SH SYNOPSIS
+.B mg_weights_build
+[
+.B \-h
+]
+[
+.B \-s
+]
+[
+.BI \-b " num"
+]
+[
+.BI \-d " directory"
+]
+.if n .ti +9n
+.BI \-f " name"
+.SH DESCRIPTION
+.B mg_weights_build
+is the program that generates the approximate weights file and the
+interleaved text index and exact weights file.  To do this, it uses
+the text index and either the exact weights file, or the inverted file
+and stemmed dictionary.
+.SH OPTIONS
+Options may appear in any order.
+.TP "\w'\fB\-d\fP \fIdirectory\fP'u+2n"
+.B \-h
+This displays a usage line on
+.IR stderr .
+.TP
+.B \-s
+Save the weights generated from the
+.I *.invf
+and
+.I *.invf.dict
+file in a
+.I *.weight
+file.
+.TP
+.BI \-b " num"
+This specifies the number of bits of precision that should be used for
+the approximate weights.  If not specified, it defaults to 8.
+.TP
+.BI \-d " directory"
+This specifies the directory where the document collection is.
+.TP
+.BI \-f " name"
+This specifies the base name of the document collection.
+.SH ENVIRONMENT
+.TP "\w'\fBMGDATA\fP'u+2n"
+.SB MGDATA
+If this environment variable exists, then its value is used as the
+default directory where the
+.BR mg (1)
+collection files are.  If this variable does not exist, then the
+directory \*(lq\fB.\fP\*(rq is used by default.  The command line
+option
+.BI \-d " directory"
+overrides the directory in
+.BR MGDATA .
+.SH FILES
+.TP 20
+.B *.invf
+Inverted file.
+.TP
+.B *.invf.dict
+Compressed stemmed dictionary.
+.TP
+.B *.weight
+The exact weights file.
+.TP
+.B *.text.idx
+Index into the compressed documents.
+.TP
+.B *.text.idx.wgt
+Interleaved index into the compressed documents and document weights.
+.TP
+.B *.weight.approx
+Approximate document weights.
+.SH "SEE ALSO"
+.na
+.BR mg (1),
+.BR mg_compression_dict (1),
+.BR mg_fast_comp_dict (1),
+.BR mg_get (1),
+.BR mg_invf_dict (1),
+.BR mg_invf_dump (1),
+.BR mg_invf_rebuild (1),
+.BR mg_passes (1),
+.BR mg_perf_hash_build (1),
+.BR mg_text_estimate (1),
+.BR mgbilevel (1),
+.BR mgbuild (1),
+.BR mgdictlist (1),
+.BR mgfelics (1),
+.BR mgquery (1),
+.BR mgstat (1),
+.BR mgtic (1),
+.BR mgticbuild (1),
+.BR mgticdump (1),
+.BR mgticprune (1),
+.BR mgticstat (1).
Index: /main/tags/2.25/gsdl/packages/mg/src/text/mg_weights_build.c
===================================================================
--- /main/tags/2.25/gsdl/packages/mg/src/text/mg_weights_build.c	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/mg/src/text/mg_weights_build.c	(revision 21064)
@@ -0,0 +1,508 @@
+/**************************************************************************
+ *
+ * mg_weights_build.c -- Program to build the document weights file
+ * Copyright (C) 1994  Neil Sharman
+ *
+ * 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.
+ *
+ * $Id$
+ *
+ **************************************************************************/
+
+#include "sysfuncs.h"
+#include "memlib.h"
+#include "messages.h"
+#include "local_strings.h"
+#include "bitio_gen.h"
+#include "bitio_m.h"
+#include "bitio_m_stdio.h"
+#include "timing.h"
+#include "netorder.h"  /* [RPAP - Jan 97: Endian Ordering] */
+
+#include "mg_files.h"
+#include "locallib.h"
+#include "invf.h"
+#include "text.h"
+#include "words.h"
+
+#define MAXBITS (sizeof(unsigned long) * 8)
+
+/*
+   $Log$
+   Revision 1.1  1999/08/10 21:18:16  sjboddie
+   renamed mg-1.3d directory mg
+
+   Revision 1.2  1998/11/25 07:55:49  rjmcnab
+
+   Modified mg to that you can specify the stemmer you want
+   to use via a command line option. You specify it to
+   mg_passes during the build process. The number of the
+   stemmer that you used is stored within the inverted
+   dictionary header and the stemmed dictionary header so
+   the correct stemmer is used in later stages of building
+   and querying.
+
+   Revision 1.1  1998/11/17 09:35:22  rjmcnab
+   *** empty log message ***
+
+   * Revision 1.4  1994/11/29  00:32:05  tes
+   * Committing the new merged files and changes.
+   *
+   * Revision 1.3  1994/10/20  03:57:00  tes
+   * I have rewritten the boolean query optimiser and abstracted out the
+   * components of the boolean query.
+   *
+   * Revision 1.2  1994/09/20  04:41:55  tes
+   * For version 1.1
+   *
+ */
+
+static char *RCSID = "$Id$";
+
+unsigned char bits = 8;
+static char *file_name = "";
+static char *text_file_name = "";
+static unsigned long NumPara = 0;
+static unsigned long StaticNumOfDocs = 0;
+
+unsigned long get_NumPara (void);
+unsigned long get_StaticNumOfDocs (void);
+void GenerateWeights (void);
+void Make_weight_approx (void);
+void Make_text_idx_wgt (void);
+
+
+int main (int argc, char **argv)
+{
+  ProgTime StartTime;
+  int ch;
+  opterr = 0;
+  msg_prefix = argv[0];
+  while ((ch = getopt (argc, argv, "f:t:d:b:sh")) != -1) /* [RJM 10/98 - Text Filename] */
+    switch (ch)
+      {
+      case 'f':		/* input file */
+	file_name = optarg;
+	if (strlen(text_file_name) == 0) text_file_name = optarg;
+	break;
+      /* [RJM 10/98 - Text Filename] */
+      case 't':		/* text input file */
+	text_file_name = optarg;
+	break;
+      case 'd':
+	set_basepath (optarg);
+	break;
+      case 'b':
+	bits = atoi (optarg);
+	if (bits > 32)
+	  {
+	    fprintf (stderr, "b may only take values 0-32\n");
+	    exit (1);
+	  }
+	break;
+      case 'h':
+      case '?':
+	fprintf (stderr, "usage: %s [-f input_file]"
+		 "[-d data directory] [-b bits] [-s] [-h]\n", argv[0]);
+	exit (1);
+      }
+  GetTime (&StartTime);
+
+  GenerateWeights ();
+
+  Make_weight_approx ();
+
+  Make_text_idx_wgt ();
+
+  Message ("%s", ElapsedTime (&StartTime, NULL));
+
+  return 0;
+}
+
+
+
+
+unsigned long 
+get_NumPara (void)
+{
+  struct invf_dict_header idh;
+  FILE *invf_dict;
+  if (NumPara)
+    return (NumPara);
+  invf_dict = open_file (file_name, INVF_DICT_SUFFIX, "rb", MAGIC_STEM_BUILD,
+			 MG_ABORT);  /* [RPAP - Feb 97: WIN32 Port] */
+  fread ((char *) &idh, sizeof (idh), 1, invf_dict);
+  fclose (invf_dict);
+  NTOHUL2(idh.num_of_docs, NumPara);  /* [RPAP - Jan 97: Endian Ordering] */
+  return NumPara;
+}
+
+
+
+unsigned long 
+get_StaticNumOfDocs (void)
+/* the static number of documents is the N parameter used to
+ * decode document gaps in the inverted file encoded using
+ * the Bblock method.
+ */
+{
+  struct invf_dict_header idh;
+  FILE *invf_dict;
+  if (StaticNumOfDocs)
+    return (StaticNumOfDocs);
+  invf_dict = open_file (file_name, INVF_DICT_SUFFIX, "rb", MAGIC_STEM_BUILD,
+			 MG_ABORT);  /* [RPAP - Feb 97: WIN32 Port] */
+  fread ((char *) &idh, sizeof (idh), 1, invf_dict);
+  fclose (invf_dict);
+  NTOHUL2(idh.static_num_of_docs, StaticNumOfDocs);  /* [RPAP - Jan 97: Endian Ordering] */
+  return StaticNumOfDocs;
+}
+
+
+
+void GenerateWeights (void) {
+  FILE *dict, *invf, *f, *idx;
+  struct invf_dict_header idh;
+  struct invf_file_header ifh;
+  int i;
+  double logN;
+  float *DocWeights;
+
+  /* make sure the globals NumPara and StaticNumOfDocs are loaded */
+  get_NumPara ();
+  get_StaticNumOfDocs ();
+
+  /* check to see if the weights file has already been built */
+  if ((f = open_file (file_name, WEIGHTS_SUFFIX, "rb", MAGIC_WGHT,
+		      MG_CONTINUE)) != NULL) {
+      fclose (f);
+      return;
+  }
+  Message ("The file \"%s.weight\" does not exist.", file_name);
+  Message ("Building the weight data from the file \"%s.invf\".", file_name);
+
+  logN = log ((double) NumPara);
+
+  /* allocate memory for the weights */
+  if (!(DocWeights = Xmalloc (sizeof (float) * (NumPara + 1))))
+      FatalError (1, "No memory for doc weights");
+  bzero ((char *) DocWeights, sizeof (float) * (NumPara + 1));
+
+  /* open the .invf.dict file and read in its header */
+  dict = open_file (file_name, INVF_DICT_SUFFIX, "rb", MAGIC_STEM_BUILD,
+		    MG_ABORT);  /* [RPAP - Feb 97: WIN32 Port] */
+  fread ((char *) &idh, sizeof (idh), 1, dict);
+
+  /* [RPAP - Jan 97: Endian Ordering] */
+  NTOHUL(idh.lookback);
+  NTOHUL(idh.dict_size);
+  NTOHUL(idh.total_bytes);
+  NTOHUL(idh.index_string_bytes);
+  NTOHD(idh.input_bytes); /* [RJM 07/97: 4G limit] */
+  NTOHUL(idh.num_of_docs);
+  NTOHUL(idh.static_num_of_docs);
+  NTOHUL(idh.num_of_words);
+  NTOHUL(idh.stemmer_num);
+  NTOHUL(idh.stem_method);
+
+  /* open .invf.idx */
+  idx = open_file (file_name, INVF_IDX_SUFFIX, "rb", MAGIC_INVI,
+		   MG_ABORT);  /* [RPAP - Feb 97: WIN32 Port] */
+
+  /* open .invf and read in its header */
+  invf = open_file (file_name, INVF_SUFFIX, "rb", MAGIC_INVF,
+		    MG_ABORT);
+  fread ((char *) &ifh, sizeof (ifh), 1, invf);
+
+  /* [RPAP - Jan 97: Endian Ordering] */
+  NTOHUL(ifh.no_of_words);
+  NTOHUL(ifh.no_of_ptrs);
+  NTOHUL(ifh.skip_mode);
+  for (i = 0; i <= 15; i++)
+    NTOHUL(ifh.params[i]);
+  NTOHUL(ifh.InvfLevel);
+
+  /* make sure the inverted file does not contain skips and is not level 1 */
+  if (ifh.skip_mode != 0)
+    FatalError (0, "Can\'t make weights file from a skipped inverted file.");
+  if (ifh.InvfLevel == 1)
+    FatalError (0, "Can\'t make weights file from level 1 inverted file.");
+
+  DECODE_START (invf)
+
+    /* process each word adding its contributions to the document weights */
+    for (i = 0; i < ifh.no_of_words; i++)
+    {
+      u_char dummy1, dummy2[MAXSTEMLEN + 1];
+      unsigned long fcnt, wcnt, blk, CurrDoc, p, j;
+      float idf;
+
+      /* give a little feedback every 4096 words */
+      if ((i & 0xfff) == 0)
+	fprintf (stderr, ".");
+
+      /* read an entry for a word, just to get p value */
+      dummy1 = fgetc (dict);
+      dummy1 = fgetc (dict);
+      fread (dummy2, sizeof (u_char), dummy1, dict);
+      fread ((char *) &fcnt, sizeof (fcnt), 1, dict);
+      fread ((char *) &wcnt, sizeof (wcnt), 1, dict);
+
+      dummy2[dummy1] = '\0';
+
+      /* [RPAP - Jan 97: Endian Ordering] */
+      NTOHUL(fcnt);
+      NTOHUL(wcnt);
+
+      p = fcnt;
+
+      idf = logN - log ((double) fcnt);
+      blk = BIO_Bblock_Init (StaticNumOfDocs, p);
+      CurrDoc = 0;
+
+      /* check the inverted file index entry for this word */
+      {
+	unsigned long loc;
+	fread ((char *) &loc, sizeof (loc), 1, idx);
+	NTOHUL(loc);  /* [RPAP - Jan 97: Endian Ordering] */
+	if (ftell (invf) != loc)
+	  {
+	    FatalError (1, "Word %d  %d != %d", i, ftell (invf), loc);
+	  }
+      }
+
+      for (j = 0; j < p; j++)
+	{
+	  unsigned long x, tf;
+	  BBLOCK_DECODE (x, blk);
+	  CurrDoc += x;
+
+	  if (CurrDoc > idh.num_of_docs) {
+	    FatalError (1, "CurrDoc = %d, number of documents = %d", 
+			CurrDoc, idh.num_of_docs);
+	  }	  
+
+	  if (ifh.InvfLevel >= 2)
+	    {
+	      double weight;
+	      GAMMA_DECODE (tf);
+	      weight = tf * idf;
+	      DocWeights[CurrDoc - 1] += weight * weight;
+	    }
+	}
+      
+      while (__btg)
+	DECODE_BIT;
+    }
+
+  DECODE_DONE
+
+  fclose (dict);
+  fclose (invf);
+  fprintf (stderr, "\n");
+
+  /* [RPAP - Jan 97: Endian Ordering] */
+  for (i = 0; i < NumPara; i++)
+    HTONF(DocWeights[i]);
+
+  f = create_file (file_name, WEIGHTS_SUFFIX, "wb", MAGIC_WGHT,
+		   MG_ABORT);
+
+  fwrite ((char *) DocWeights, sizeof (float), NumPara, f);
+  fclose (f);
+  Xfree (DocWeights);
+}
+
+
+
+
+
+
+
+
+
+
+
+void 
+Make_weight_approx (void)
+{
+  int i, pos, max;
+  unsigned long buf;
+  double U, L, B;
+  FILE *approx, *exact;
+
+  exact = open_file (file_name, WEIGHTS_SUFFIX, "rb", MAGIC_WGHT,
+		     MG_ABORT);  /* [RPAP - Feb 97: WIN32 Port] */
+
+  /* calculate U and L */
+  L = 1e300;
+  U = 0;
+  for (i = 0; i < NumPara; i++)
+    {
+      float wgt;
+      fread ((char *) &wgt, sizeof (wgt), 1, exact);
+      NTOHF(wgt);  /* [RPAP - Jan 97: Endian Ordering] */
+      wgt = sqrt (wgt);
+      if (wgt > U)
+	U = wgt;
+      if (wgt > 0 && wgt < L)
+	L = wgt;
+
+    }
+  fseek (exact, sizeof (u_long), SEEK_SET);
+
+  B = pow (U / L, pow (2.0, -(double) bits));
+
+  fprintf (stderr, "L = %f\n", L);
+  fprintf (stderr, "U = %f\n", U);
+  fprintf (stderr, "B = %f\n", B);
+
+
+
+  approx = create_file (file_name, APPROX_WEIGHTS_SUFFIX, "wb",
+			MAGIC_WGHT_APPROX, MG_ABORT);  /* [RPAP - Feb 97: WIN32 Port] */
+
+  fwrite ((char *) &bits, sizeof (bits), 1, approx);
+  HTOND(L);  /* [RPAP - Jan 97: Endian Ordering] */
+  HTOND(B);  /* [RPAP - Jan 97: Endian Ordering] */
+  fwrite ((char *) &L, sizeof (L), 1, approx);
+  fwrite ((char *) &B, sizeof (B), 1, approx);
+  NTOHD(L);  /* [RPAP - Jan 97: Endian Ordering] */
+  NTOHD(B);  /* [RPAP - Jan 97: Endian Ordering] */
+
+  max = bits == 32 ? 0xffffffff : (1 << bits) - 1;
+  for (buf = pos = i = 0; i < NumPara; i++)
+    {
+      unsigned long fx;
+      float wgt;
+      fread ((char *) &wgt, sizeof (wgt), 1, exact);
+      NTOHF(wgt);  /* [RPAP - Jan 97: Endian Ordering] */
+      wgt = sqrt (wgt);
+      if (wgt == 0)
+	{
+	  wgt = L;
+#ifndef QUIET
+	  Message ("Warning: Document %d had a weight of 0.", i);
+#endif
+	}
+      fx = (int) floor (log (wgt / L) / log (B));
+
+      if (fx > max)
+	fx = max;
+
+      buf |= (fx << pos);
+      pos += bits;
+
+      if (pos >= MAXBITS)
+	{
+	  HTONUL(buf);
+	  fwrite ((char *) &buf, sizeof (buf), 1, approx);
+	  buf = fx >> (bits - (pos - MAXBITS));
+	  pos = pos - MAXBITS;
+	}
+    }
+  if (pos > 0)
+    {
+      /* [RPAP - Jan 97: Endian Ordering] */
+      HTONUL(buf);
+      fwrite ((char *) &buf, sizeof (buf), 1, approx);
+    }
+
+  fclose (approx);
+  fclose (exact);
+}
+
+
+
+
+
+void 
+Make_text_idx_wgt (void)
+{
+  compressed_text_header cth;
+  int i;
+  FILE *idx_wgt, *idx, *para, *exact;
+
+  idx_wgt = create_file (file_name, TEXT_IDX_WGT_SUFFIX, "wb", MAGIC_TEXI_WGT,
+			 MG_ABORT);  /* [RPAP - Feb 97: WIN32 Port] */
+
+  /* [RJM 10/98 - Text Filename] */
+  idx = open_file (text_file_name, TEXT_IDX_SUFFIX, "rb", MAGIC_TEXI,
+		   MG_ABORT);  /* [RPAP - Feb 97: WIN32 Port] */
+  if (fread (&cth, sizeof (cth), 1, idx) != 1)
+    FatalError (1, "Unable to read header of index file");
+
+  /* [RPAP - Jan 97: Endian Ordering] */
+  NTOHUL(cth.num_of_docs);
+  NTOHD(cth.num_of_bytes); /* [RJM 07/97: 4G limit] */
+  NTOHUL(cth.num_of_words);
+  NTOHUL(cth.length_of_longest_doc);
+  NTOHD(cth.ratio);
+
+  exact = open_file (file_name, WEIGHTS_SUFFIX, "rb", MAGIC_WGHT,
+		     MG_ABORT);  /* [RPAP - Feb 97: WIN32 Port] */
+
+  get_NumPara ();
+  if (cth.num_of_docs != NumPara)
+    {
+      Message ("The number of documents does not equal "
+	       "the number of paragraphs.");
+      Message ("Using the \"%s.invf.paragraph\" file\n", file_name);
+      para = open_file (file_name, INVF_PARAGRAPH_SUFFIX, "rb", MAGIC_PARAGRAPH,
+			MG_ABORT);  /* [RPAP - Feb 97: WIN32 Port] */
+    }
+  else
+    para = NULL;
+
+  {
+    struct
+      {
+	unsigned long Start;
+	float Weight;
+      }
+    data;
+    for (i = 0; i < cth.num_of_docs; i++)
+      {
+	int count;
+	fread ((char *) &data.Start, sizeof (unsigned long), 1, idx);
+	if (para && i < cth.num_of_docs)
+	  {
+	    /* [RPAP - Jan 97: Endian Ordering] */
+	    fread ((char *) &count, sizeof (count), 1, para);
+	    NTOHSI(count);
+	  }
+	else
+	  count = 1;
+	while (count--)
+	  {
+	    fread ((char *) &data.Weight, sizeof (float), 1, exact);
+	    NTOHF(data.Weight);  /* [RPAP - Jan 97: Endian Ordering] */
+	    data.Weight = sqrt (data.Weight);
+	    HTONF(data.Weight);  /* [RPAP - Jan 97: Endian Ordering] */
+	    fwrite ((char *) &data, sizeof (data), 1, idx_wgt);
+	  }
+      }
+    /* Write out the extra entry for the idx file */
+    fread ((char *) &data.Start, sizeof (unsigned long), 1, idx);
+    data.Weight = 0;
+    fwrite((char*)&data, sizeof(data), 1, idx_wgt);
+  }
+
+  fclose (idx_wgt);
+  fclose (idx);
+  fclose (exact);
+  if (para)
+    fclose (para);
+}
Index: /main/tags/2.25/gsdl/packages/mg/src/text/mgdictlist.1
===================================================================
--- /main/tags/2.25/gsdl/packages/mg/src/text/mgdictlist.1	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/mg/src/text/mgdictlist.1	(revision 21064)
@@ -0,0 +1,72 @@
+.\"------------------------------------------------------------
+.\" Id - set Rv,revision, and Dt, Date using rcs-Id tag.
+.de Id
+.ds Rv \\$3
+.ds Dt \\$4
+..
+.Id $Id$
+.\"------------------------------------------------------------
+.TH mgdictlist 1 \*(Dt CITRI
+.SH NAME
+mgdictlist \- list the contents of a dictionary
+.SH SYNOPSIS
+.B mgdictlist
+[
+.B \-q
+]
+.I filename
+.SH DESCRIPTION
+.B mgdictlist
+lists the contents of either a compressed compression dictionary, a
+text statistics file, or a compressed stemmed dictionary.  Unlike all
+the other programs in the
+.BR mg (1)
+suite, it is necessary to specify the complete pathname of the
+dictionary to list.
+.SH OPTIONS
+The
+.I filename
+must be last.
+.TP "\w'\fIfilename\fP'u+2n"
+.B \-q
+Generate an abbreviated output (machine-readable rather than
+human-readable).
+.TP
+.I filename
+This is the name of the dictionary to list.
+.B mgdictlist
+automatically detects whether the file is a compressed compression
+dictionary, text statistics file, or a compressed stemmed dictionary.
+.SH FILES
+.TP 20
+.B *.text.dict
+Text statistics file.
+.TP
+.B *.text.dict
+Compressed compression dictionary.
+.TP
+.B *.invf.build
+Compressed stemmed dictionary.
+.SH "SEE ALSO"
+.na
+.BR mg (1),
+.BR mg_compression_dict (1),
+.BR mg_fast_comp_dict (1),
+.BR mg_get (1),
+.BR mg_invf_dict (1),
+.BR mg_invf_dump (1),
+.BR mg_invf_rebuild (1),
+.BR mg_passes (1),
+.BR mg_perf_hash_build (1),
+.BR mg_text_estimate (1),
+.BR mg_weights_build (1),
+.BR mgbilevel (1),
+.BR mgbuild (1),
+.BR mgfelics (1),
+.BR mgquery (1),
+.BR mgstat (1),
+.BR mgtic (1),
+.BR mgticbuild (1),
+.BR mgticdump (1),
+.BR mgticprune (1),
+.BR mgticstat (1).
Index: /main/tags/2.25/gsdl/packages/mg/src/text/mgdictlist.c
===================================================================
--- /main/tags/2.25/gsdl/packages/mg/src/text/mgdictlist.c	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/mg/src/text/mgdictlist.c	(revision 21064)
@@ -0,0 +1,405 @@
+/**************************************************************************
+ *
+ * mgdictlist.c -- Program to list a dictionary
+ * Copyright (C) 1994  Neil Sharman
+ *
+ * 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.
+ *
+ * $Id$
+ *
+ **************************************************************************/
+
+#include "sysfuncs.h"
+
+#include "messages.h"
+#include "memlib.h"
+#include "local_strings.h"
+#include "netorder.h"  /* [RPAP - Jan 97: Endian Ordering] */
+
+#include "mg_files.h"
+#include "text.h"
+#include "invf.h"
+#include "locallib.h"
+#include "words.h"
+
+/*
+   $Log$
+   Revision 1.1  1999/08/10 21:18:17  sjboddie
+   renamed mg-1.3d directory mg
+
+   Revision 1.2  1998/11/25 07:55:49  rjmcnab
+
+   Modified mg to that you can specify the stemmer you want
+   to use via a command line option. You specify it to
+   mg_passes during the build process. The number of the
+   stemmer that you used is stored within the inverted
+   dictionary header and the stemmed dictionary header so
+   the correct stemmer is used in later stages of building
+   and querying.
+
+   Revision 1.1  1998/11/17 09:35:24  rjmcnab
+   *** empty log message ***
+
+   * Revision 1.4  1994/11/29  00:32:07  tes
+   * Committing the new merged files and changes.
+   *
+   * Revision 1.3  1994/10/20  03:57:01  tes
+   * I have rewritten the boolean query optimiser and abstracted out the
+   * components of the boolean query.
+   *
+   * Revision 1.2  1994/09/20  04:41:56  tes
+   * For version 1.1
+   *
+ */
+
+static char *RCSID = "$Id$";
+
+
+int quick = 0;
+int no_of_words[2];
+u_long maxcodelen[2];
+
+char *dictname = "";
+
+
+
+
+void 
+DumpStemDict (FILE * f)
+{
+  struct invf_dict_header idh;
+  int i;
+  u_char prev[MAXSTEMLEN + 1];
+
+  fread (&idh, sizeof (idh), 1, f);
+
+  /* [RPAP - Jan 97: Endian Ordering] */
+  NTOHUL(idh.lookback);
+  NTOHUL(idh.dict_size);
+  NTOHUL(idh.total_bytes);
+  NTOHUL(idh.index_string_bytes);
+  NTOHD(idh.input_bytes); /* [RJM 07/97: 4G limit] */
+  NTOHUL(idh.num_of_docs);
+  NTOHUL(idh.static_num_of_docs);
+  NTOHUL(idh.num_of_words);
+  NTOHUL(idh.stemmer_num);
+  NTOHUL(idh.stem_method);
+
+  if (quick)
+    printf ("%ld\n", idh.dict_size);
+  else
+    {
+      printf ("# lookback           = %lu\n", idh.lookback);
+      printf ("# dict size          = %lu\n", idh.dict_size);
+      printf ("# total bytes        = %lu\n", idh.total_bytes);
+      printf ("# index string bytes = %lu\n", idh.index_string_bytes);
+      printf ("# input bytes        = %.0f\n", idh.input_bytes); /* [RJM 07/97: 4G limit] */
+      printf ("# num of docs        = %lu\n", idh.num_of_docs);
+      printf ("# static num of docs = %lu\n", idh.static_num_of_docs);
+      printf ("# num of words       = %lu\n", idh.num_of_words);
+      printf ("#\n");
+    }
+
+  for (i = 0; i < idh.dict_size; i++)
+    {
+      register unsigned long copy, suff;
+      unsigned long wcnt, fcnt;
+
+      /* build a new word on top of prev */
+      copy = getc (f);
+      suff = getc (f);
+      *prev = copy + suff;
+      fread (prev + copy + 1, sizeof (u_char), suff, f);
+
+      /* read other data, but no need to store it */
+      fread (&fcnt, sizeof (fcnt), 1, f);
+      fread (&wcnt, sizeof (wcnt), 1, f);
+
+      /* [RPAP - Jan 97: Endian Ordering] */
+      NTOHUL(fcnt);
+      NTOHUL(wcnt);
+
+      if (!quick)
+	{
+	  printf ("%d: %8ld ", i, wcnt);
+	  printf ("/ %5ld ", fcnt);
+	  printf ("%2d %2ld\t\"", *prev, copy);
+	}
+      printf ("%s", word2str (prev));
+      if (quick)
+	printf (" %ld %ld\n", wcnt, fcnt);
+      else
+	{
+	  putchar ('"');
+	  putchar ('\n');
+	}
+    }
+}
+
+
+
+
+void 
+ReadInWords (FILE * f)
+{
+  comp_frags_header cfh;
+  u_long *codes;
+  u_char prev[MAXSTEMLEN + 1];
+  int i;
+
+  if (Read_cfh (f, &cfh, NULL, NULL) == -1)
+    FatalError (1, "Unable to read in the dictionary");
+
+  printf ("#\n");
+  printf ("#   max code len       = %u\n", cfh.hd.maxcodelen);
+  printf ("#   total bytes        = %lu\n", cfh.uncompressed_size);
+  printf ("#\n");
+
+  if (!(codes = Generate_Huffman_Codes (&cfh.hd, NULL)))
+    FatalError (1, "no memory for huffman codes\n");
+
+  for (i = 0; i < cfh.hd.num_codes; i++)
+    {
+      register int val, copy, j, k;
+      char code[33];
+      val = fgetc (f);
+      copy = (val >> 4) & 0xf;
+      val &= 0xf;
+
+      fread (prev + copy + 1, sizeof (u_char), val, f);
+      *prev = val + copy;
+
+      for (k = 0, j = cfh.hd.clens[i] - 1; j >= 0; j--, k++)
+	code[k] = '0' + ((codes[i] >> j) & 1);
+      code[k] = '\0';
+
+      printf ("%d: %2d : %*s : \"%s\"\n", i, cfh.hd.clens[i],
+	      cfh.hd.maxcodelen, code, word2str (prev));
+    }
+  Xfree (codes);
+  Xfree (cfh.hd.clens);
+}
+
+
+void 
+ReadCharHuffman (FILE * f, char *title)
+{
+  int i;
+  huff_data hd;
+  u_long *codes;
+
+  if (Read_Huffman_Data (f, &hd, NULL, NULL) == -1)
+    FatalError (1, "Unable to read huffman data");
+
+  if (!(codes = Generate_Huffman_Codes (&hd, NULL)))
+    FatalError (1, "no memory for huffman codes\n");
+
+  printf ("#\n# %s\n#\n", title);
+  for (i = 0; i < hd.num_codes; i++)
+    if (hd.clens[i])
+      {
+	int j, k;
+	char code[33];
+	for (k = 0, j = hd.clens[i] - 1; j >= 0; j--, k++)
+	  code[k] = '0' + ((codes[i] >> j) & 1);
+	code[k] = '\0';
+	printf ("%2d : %*s : \"%s\"\n", hd.clens[i],
+		hd.maxcodelen, code, char2str (i));
+      }
+  Xfree (codes);
+  Xfree (hd.clens);
+}
+
+
+void 
+ReadLenHuffman (FILE * f, char *title)
+{
+  int i;
+  huff_data hd;
+  u_long *codes;
+
+  if (Read_Huffman_Data (f, &hd, NULL, NULL) == -1)
+    FatalError (1, "Unable to read huffman data");
+
+  if (!(codes = Generate_Huffman_Codes (&hd, NULL)))
+    FatalError (1, "no memory for huffman codes\n");
+
+  printf ("#\n# %s\n#\n", title);
+  for (i = 0; i < hd.num_codes; i++)
+    if (hd.clens[i])
+      {
+	int j, k;
+	char code[33];
+	for (k = 0, j = hd.clens[i] - 1; j >= 0; j--, k++)
+	  code[k] = '0' + ((codes[i] >> j) & 1);
+	code[k] = '\0';
+	printf ("%2d : %*s : %d\n", hd.clens[i],
+		hd.maxcodelen, code, i);
+      }
+  Xfree (codes);
+  Xfree (hd.clens);
+}
+
+
+
+
+
+void 
+DumpTextDict (FILE * f)
+{
+  struct compression_dict_header cdh;
+  int which;
+
+  if (Read_cdh (f, &cdh, NULL, NULL) == -1)
+    FatalError (1, "Unable to read dictionary header");
+  switch (cdh.dict_type)
+    {
+    case MG_COMPLETE_DICTIONARY:
+      printf ("# COMPLETE DICTIONARY\n");
+      break;
+    case MG_PARTIAL_DICTIONARY:
+      printf ("# PARTIAL DICTIONARY\n");
+      break;
+    case MG_SEED_DICTIONARY:
+      printf ("# SEED DICTIONARY\n");
+      break;
+    }
+  printf ("# num words          = %lu\n", cdh.num_words[1]);
+  printf ("# num word chars     = %lu\n", cdh.num_word_chars[1]);
+  printf ("# num non-words      = %lu\n", cdh.num_words[0]);
+  printf ("# num non-word chars = %lu\n", cdh.num_word_chars[0]);
+  printf ("# lookback           = %lu\n", cdh.lookback);
+
+  for (which = 0; which < 2; which++)
+    switch (cdh.dict_type)
+      {
+      case MG_COMPLETE_DICTIONARY:
+	{
+	  ReadInWords (f);
+	}
+	break;
+      case MG_PARTIAL_DICTIONARY:
+	{
+	  if (cdh.num_words[which])
+	    ReadInWords (f);
+
+	  ReadCharHuffman (f, "Characters");
+	  ReadLenHuffman (f, "Lengths");
+	}
+	break;
+      case MG_SEED_DICTIONARY:
+	{
+	  if (cdh.num_words[which])
+	    ReadInWords (f);
+
+	  ReadCharHuffman (f, "Characters");
+	  ReadLenHuffman (f, "Lengths");
+	}
+	break;
+      }
+}
+
+
+
+
+void 
+DumpStatsDict (FILE * f)
+{
+  int i;
+  compression_stats_header csh;
+
+  fread (&csh, sizeof (csh), 1, f);
+
+  for (i = 0; i < 2; i++)
+    {
+      int j;
+      frags_stats_header fsh;
+
+      fread (&fsh, sizeof (fsh), 1, f);
+
+      /* [RPAP - Jan 97: Endian Ordering] */
+      NTOHUL(fsh.num_frags);
+      NTOHUL(fsh.mem_for_frags);
+
+      if (!quick)
+	printf ("#\n# num %9s      = %lu\n#\n", i ? "words" : "non-words",
+		fsh.num_frags);
+
+      for (j = 0; j < fsh.num_frags; j++)
+	{
+	  u_char Word[16];
+	  u_long freq, occur_num;
+
+	  fread (&freq, sizeof (freq), 1, f);
+	  fread (&occur_num, sizeof (occur_num), 1, f);
+
+	  /* [RPAP - Jan 97: Endian Ordering] */
+	  NTOHUL(freq);
+	  NTOHUL(occur_num);
+
+	  Word[0] = fgetc (f);
+	  fread (Word + 1, Word[0], 1, f);
+	  printf ("%d: %7ld : %7ld : \"%s\"\n", j, freq,
+		  occur_num, word2str (Word));
+	}
+    }
+}
+
+
+int main (int argc, char **argv)
+{
+  FILE *fp;
+  unsigned long magic = 0;
+
+  if (argc < 2)
+    FatalError (1, "A file name must be specified");
+  dictname = argv[1];
+  if (strcmp (dictname, "-q") == 0)
+    {
+      quick = 1;
+      if (argc < 3)
+	FatalError (1, "A file name must be specified");
+      dictname = argv[2];
+    }
+  if (!(fp = fopen (dictname, "rb")))  /* [RPAP - Feb 97: WIN32 Port] */
+    FatalError (1, "Unable to open \"%s\"", dictname);
+
+  fread (&magic, sizeof (magic), 1, fp);
+
+  NTOHUL(magic);  /* [RPAP - Jan 97: Endian Ordering] */
+
+  switch (magic)
+    {
+    case MAGIC_STEM_BUILD:
+      if (!quick)
+	printf ("# Contents of STEM file \"%s\"\n#\n", dictname);
+      DumpStemDict (fp);
+      break;
+    case MAGIC_DICT:
+      if (!quick)
+	printf ("# Contents of DICT file \"%s\"\n#\n", dictname);
+      DumpTextDict (fp);
+      break;
+    case MAGIC_STATS_DICT:
+      if (!quick)
+	printf ("# Contents of STATS file \"%s\"\n#\n", dictname);
+      DumpStatsDict (fp);
+      break;
+    default:
+      FatalError (1, "Bad magic number. \"%s\" cannot be dumped", dictname);
+    }
+  fclose (fp);
+  return 0;
+}
Index: /main/tags/2.25/gsdl/packages/mg/src/text/mgquery.1
===================================================================
--- /main/tags/2.25/gsdl/packages/mg/src/text/mgquery.1	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/mg/src/text/mgquery.1	(revision 21064)
@@ -0,0 +1,693 @@
+.\"------------------------------------------------------------
+.\" Id - set Rv,revision, and Dt, Date using rcs-Id tag.
+.de Id
+.ds Rv \\$3
+.ds Dt \\$4
+..
+.Id $Id$
+.\"------------------------------------------------------------
+.TH mgquery 1 \*(Dt CITRI
+.SH NAME
+mgquery \- query program for the mg system
+.SH SYNOPSIS
+.B mgquery
+[
+.B \-h
+]
+[
+.B \-D
+]
+[
+.BI \-f " name"
+]
+[
+.BI \-d " directory"
+]
+.if n .ti +9n
+[
+.I collection-name
+]
+.SH DESCRIPTION
+.B mgquery
+enables users to make Boolean or ranked queries from a data base
+generated by the
+.BR mg (1)
+system.  It accepts queries from
+.I stdin
+and sends the retrieved documents to
+.IR stdout .
+Information on the resource usage of
+.B mgquery
+as it processes queries can be obtained interactively.
+.SH OPTIONS
+Options may appear in any order, but the
+.IR collection-name ,
+if specified, must be last.
+.TP "\w'\fB\-d\fP \fIdirectory\fP'u+2n"
+.B \-h
+This displays a usage line on
+.IR stderr .
+.TP
+.B \-D
+This option causes the entire text to be decompressed and sent to
+.IR stdout .
+.TP
+.BI \-f " name"
+This specifies the base name of the document collection that will be
+used.  If a collection with the specified base
+.I name
+does not exist, an error message will be displayed and
+.B mgquery
+will exit.
+.TP
+.BI \-d " directory"
+This specifies the directory where the document collection can be found.
+.SH USAGE
+Prior to processing the command line arguments, the
+.B mgquery
+program attempts to read in a startup script called
+.IR ./.mgrc .
+If that fails, it attempts to read in the file
+.IR $HOME/.mgrc .
+The startup file can only contain commands\(emno queries are
+permitted in the
+.I .mgrc
+file.  Lines starting with \*(lq\fB#\fP\*(rq in the file are comments.
+The most common use for the
+.I .mgrc
+file is to personalise the initial values of the predefined parameters
+with
+.B .set
+commands.
+.LP
+The input to
+.B mgquery
+consists of a series of input lines.  The backslash
+character
+.RB (\*(lq \e \*(rq)
+is used at the end of lines to indicate
+that input continues on the next line.
+.LP
+Input lines on which the first character is a dot
+.RB (\*(lq . \*(rq)
+are commands to the
+.B mgquery
+program.  Input lines that do not start with a dot are queries.
+.LP
+A query consists of two parts.  One part is a Boolean or ranked query
+that identifies documents.  The second part is a post-processing
+pattern matching operation.  Any text between the first speech mark
+(\*(lq) and the last speech mark (\*(rq) is considered to be a
+post-processing pattern.
+.SH COMMANDS
+The
+.B mgquery
+program can accept the following commands.
+.TP 17
+.B .help
+Display several pages of help text.
+.TP
+.B .quit
+Quit the program.
+.TP
+.B .warranty
+Display the
+.BR mg (1)
+warranty.
+.TP
+.B .conditions
+Display the conditions of use and distribution of
+.BR mg (1).
+.TP
+.BI ".set " "name value"
+Set the parameter
+.I name
+to the specified
+.IR value .
+If the parameter is a Boolean
+.I value
+and the
+.I value
+is omitted, the parameter will be inverted (i.e., if it was
+.IR true ,
+then it will change to
+.IR false ;
+if it was
+.IR false ,
+then it will change to
+.IR true ).
+.TP
+.BI ".unset " name
+Delete the parameter
+.I name
+from the currently-defined parameters.
+.TP
+.B .reset
+Reset the parameters to the state that they had after the processing
+of the
+.B mgquery
+command line.
+.TP
+.B .display
+Display the values of all the currently-defined parameters.
+.TP
+.B .push
+Push the currently-defined parameters onto a stack.
+.TP
+.B .pop
+Pops a set of parameters off the stack, replacing the currently-defined
+ones.
+.TP
+.BI ".output " arg
+This is used to specify where to send the text of the documents.  Once
+the
+.B .output
+command is specified, all subsequent output will be sent to the place
+specified by
+.IR arg .
+If
+.I arg
+is not specified subsequent output will be directed to
+.IR stdout .
+.I Arg
+may be any of the following.
+.RS
+.TP 13
+.BI "> " filename
+Send output to the specified file.
+.TP
+.BI ">> " filename
+Append output to the specified file.
+.TP
+.BI "| " command
+Pipe the output to
+.IR command ,
+which is executed by
+.IR sh .
+.RE
+.TP
+.BI ".input " arg
+This is used to specify where input (queries and commands) comes
+from.  Once the
+.B .input
+command is specified all subsequent input will be come from the place
+specified by
+.IR arg .
+If
+.I arg
+is not specified subsequent input will come from
+.IR stdin .
+.RS
+.TP 13
+.BI "< " filename
+Get input from the specified file.
+.TP
+.BI "| " command
+The input comes from the standard output of
+.IR command ,
+which is executed by
+.IR sh .
+.RE
+.SH PARAMETERS
+The following parameters are predefined and have special
+significance.  Each parameter will be followed by its default
+value.  Parameters are initialised before the
+.I .mgrc
+file is read or the command line arguments are processed.
+.TP 17
+.BI accumulator_method " `array'"
+This parameter is used during ranking, and specifies how the
+weight for each document should be accumulated.  The following
+methods are available:
+.IR array ,
+.IR splay_tree ,
+.IR hash_table ,
+and
+.IR list .
+.TP
+.BI briefstats " `off'"
+This is a Boolean parameter that determines whether the
+totals for disk, memory and time usage statistics will be
+displayed at the end of each query.
+.IR Note :
+this takes precedence over the parameters
+.BR diskstats ,
+.BR memstats " and " timestats .
+This parameter may take the values
+.IR yes ", " no ", "
+.IR true ", " false ", "
+.IR on " or " off .
+.TP
+.BI buffer " `1048576'"
+When the documents are being read in, they are read into a
+buffer of this size and then displayed from this buffer.  If
+the documents are larger than this buffer, the buffer is
+expanded automatically.  Having a large buffer gives a very
+slight performance improvement, because it allows the order of
+disk operations to be optimised.  The buffer size is measured
+in bytes.
+.TP
+.BI diskstats " `off'"
+This is a Boolean parameter that determines whether the disk
+usage statistics for the preceding query will be displayed
+after each query.  This parameter may take the values
+.IR yes ", " no ", "
+.IR true ", " false ", "
+.IR on " or " off .
+.TP
+.BI doc_sepstr " `---------------------------------- %n\en\'"
+This specifies the string that will be used to separate
+documents when they are displayed for `Boolean' or `docnums'
+queries.  The standard C escape character sequences
+may be used to place special characters in the
+string.  For example, a newline would be `\en'.  To include a `%',
+use the sequence `%%'.  To include the
+.BR mg (1)
+document number, use the sequence `%n'.  The following escape character
+sequences are available
+.nf
+.ta 1.7iL
+.B Sequence	Meaning
+`\e\e'	backslash
+`\eb'	backspace
+`\ef'	formfeed
+`\en'	newline
+`\er'	carriage return
+`\et'	tab
+`\e"'	speech marks
+`\e''	quote mark
+`\ex\fIhh\fP'	ASCII code in hexadecimal
+`\ennn'	ASCII code in octal
+.fi
+.TP
+.BI expert " `false'"
+If this is
+.IR true ,
+then much of the dialogue output is suppressed.  This parameter may
+take the values
+.IR yes ", " no ", "
+.IR true ", " false ", "
+.IR on " or " off .
+.TP
+.BI hash_tbl_size " `1000'"
+One of the options during ranking queries is to use a hash
+table to accumulate the weights for each document.  The hash
+table is a simple chained type.  This parameter specifies the
+size of the hash table and may take any value between 8 and
+268435456 (2^28).
+.TP
+.BI heads_length " `50'"
+When the mode is
+.BR heads ,
+this specifies the number of characters that will be output for each
+document.
+.TP
+.BI maxdocs " `all'"
+The maximum number of documents to display in response to a
+query.  This parameter may take on a numeric value between 1
+and 429467295 (2^32 - 1) or the word
+.IR all .
+.TP
+.BI maxparas " `1000'"
+The maximum number of paragraphs to identify during a ranked
+query with paragraph indexing.  After the paragraphs have been
+identified, the paragraphs are converted into documents, and
+because some of the paragraphs may refer to the same documents
+the final number of answers may be less than
+.BR maxparas .
+The
+.B maxdocs
+parameter will then be applied.  This parameter may take on a numeric
+value between 1 and 429467295 (2^32 - 1).
+.TP
+.BI max_accumulators " `50000'"
+This parameter limits the number of different paragraph and
+document numbers to be accumulated during ranked queries when
+the parameter
+.B accumulator_method
+is set to
+.IR splay_tree ,
+.IR hash_table ,
+or
+.IR list .
+This parameter may take any value between 8 and 268435456 (2^28).
+.TP
+.BI max_terms " `all'"
+This parameter limits the number of terms that will actually
+be used during a ranked query.  If more terms than the number
+specified by
+.B max_terms
+are entered, then the extra terms will be discarded.  If
+.B sorted_terms
+is on, then the limiting will be done after the terms have been
+sorted.  This parameter may take any value between 1 and 429467295
+(2^32 - 1), or the word
+.IR all.
+.TP
+.BI memstats " `off'"
+This is a Boolean parameter that determines whether the memory
+usage statistics for the preceding query will be displayed
+after each query.  This parameter may take the values
+.IR yes ", " no ", "
+.IR true ", " false ", "
+.IR on " or " off .
+.TP
+.BI mgdir " `.'"
+This is set to the directory where the
+.BR mg (1)
+data files may be found.  If
+the environment variable
+.B MGDATA
+exists, then this is instead initialised to the value of
+.BR MGDATA .
+The value of this parameter may be changed, either in the
+.I .mgrc
+file with a
+.BI ".set mgdir "directory
+command, or from the command line using the
+.BI \-d " directory"
+option.  Once the \*(lq\fB>\fP\*(rq prompt appears, changing this
+parameter will have no effect.
+.TP
+.BI mgname " `bible'"
+This is set to the name of the
+.BR mg (1)
+collection that is to be used for the session.  The value of this
+parameter may be changed, either in the
+.I .mgrc
+file with a
+.BI ".set mgname "name
+command, or from the command line using the
+.BI \-f " name"
+option.  Once the \*(lq\fB>\fP\*(rq prompt appears, changing this
+parameter will have no effect.
+.TP
+.BI mode " `text'"
+This specifies how documents should be displayed when they
+are retrieved.  It may take six different values:
+.IR text ,
+.IR hilite ,
+.IR docnums ,
+.IR heads ,
+.IR silent ,
+or
+.IR count .
+.I text
+displays the contents of the document.
+.I hilite
+displays the contents of the document and highlights any of the 
+stemmed query terms.
+.I docnums
+displays only the document numbers.
+.I heads
+is used to print out the head of each document.
+.I silent
+retrieves all the documents but displays nothing except how many
+documents were retrieved.  This mode is intended to be used in timing
+experiments.
+.I count
+does the minimum
+amount of work required to determine how many documents would
+be retrieved, but does not retrieve them.
+.TP
+.BI optimise_type " `1'"
+There are three types of boolean query optimisation (parse tree
+rearrangement). Type 0 leaves parse tree unaltered. Type 1 optimises
+for AND of terms and AND of OR of terms. Type 2 converts the tree
+into DNF (an experiment :-).
+.TP
+.BI pager " `more'"
+This is the name of the program that will be used to display
+the help and the retrieved documents.  If the environment
+variable
+.B PAGER
+is defined, then
+.B pager
+takes on that value.
+.TP
+.BI hilite_style " `bold'"
+This specifies the type of highlighting method.
+It may take one of two different values:
+.IR bold,
+or
+.IR underline.
+.TP
+.BI para_sepstr " `\en######## PARAGRAPH %n ########\en'"
+This specifies the string that will be used to separate paragraphs.
+The standard C escape character sequences may be used to place special
+characters in the string.  For example, a newline would be written
+as `\en'.  To include a `%', use the sequence `%%'.  To include the
+paragraph number within the document, use the sequence `%n'.
+.TP
+.BI para_start " `***** Weight = %w *****\en'"
+This specifies the string that will be used at the head of paragraphs
+for a paragraph-level index following a ranked query.  The standard
+C-language escape character sequences may be used to place special
+characters in the string.  For example, a newline would be written as
+`\en'.  To include a `%', use the sequence `%%'.  To include the
+paragraph weight, use the sequence `%w'.
+.TP
+.BI qfreq " `true'"
+This determine whether the ranked queries will take into account the
+number of times each query term is specified.  When this is
+.IR true ,
+the number of times a term appears in the query is used in the
+ranking.  When this is
+.IR false ,
+all query terms are assumed to occur only once.  This parameter may
+take the values
+.IR yes ", " no ", "
+.IR true ", " false ", "
+.IR on " or " off .
+.TP
+.BI query  " `Boolean'"
+This specifies the type of queries that are to be specified.
+It can take four different values:
+.IR Boolean ,
+.IR ranked ,
+.IR docnums " or " approx-ranked.
+.I Boolean
+is for Boolean queries.
+The
+.BR yacc (1)
+grammar for Boolean queries is as follows.
+.IP
+.nf
+        query   : or;
+.IP
+        or      : or '|' and
+                | and ;
+.IP
+        and     : and '&' not
+                | and not
+                | not ;
+.IP
+        not     : term
+                | '!' not ;
+.IP
+        term    : TERM
+                | '(' or ')' ;
+.fi
+.IP
+.IR ranked " and " approx-ranked
+are for queries ranked by the cosine measure.
+.I approx-ranked
+uses only the low-precision document lengths, and therefore only
+produces an approximation to full cosine ranking.
+.IP
+.nf
+        query   : TERM
+                | query TERM ;
+.fi
+.IP
+.I docnums
+allows the entry of document numbers.  Multiple numbers separated by
+spaces may be specified, or ranges separated by hyphens.
+.IP
+.nf
+        query   : range
+                | query range ;
+.IP
+        range   : num
+                | num '-' num ;
+.fi
+.TP
+.BI ranked_doc_sepstr " `-------------------------------- %n %w\en'"
+This specifies the string that will be used to separate documents when
+they are displayed for `ranked' or `approx-ranked' queries.  The
+standard C escape character sequences may be used to place special
+characters in the string.  For example, a newline would be written as
+`\en'.  To include a `%', use the sequence `%%'.  To include the
+.BR mg (1)
+document number, use the sequence `%n'.  To include the document
+weight, use the sequence `%w'.
+.TP
+.BI sizestats " `false'"
+If this is
+.IR true ,
+then various numbers are output at the end of each query indicating
+what went on during the query.  This parameter may take the values
+.IR yes ", " no ", "
+.IR true ", " false ", "
+.IR on " or " off .
+.TP
+.BI skip_dump " `skips.%d'"
+If this parameter is set, then a file will be produced in the current
+directory during ranked queries on skipped inverted files when
+.B accumulator_method
+is set to
+.IR splay_tree ,
+.IR hash_table ,
+or
+.IR list .
+The name of the file is the value of this parameter.  A `%d' in the
+file name will be replaced with the process id of
+.BR mgquery .
+This file will contain information about the usage of skips during the
+query processing.  This option is expensive; use
+.B .unset skip_dump
+to obtain optimal performance.
+.TP
+.BI sorted_terms " `on'"
+This specifies whether or not the terms should be sorted into
+decreasing occurrence in documents so that the least-often occurring
+terms are processed first when ranked queries are being done.  When
+this is
+.IR true ,
+the terms are sorted.  When this is
+.IR false ,
+the terms are not sorted, and are instead processed in order of
+occurrence.  This parameter may take the values
+.IR yes ", " no ", "
+.IR true ", " false ", "
+.IR on " or " off .
+.TP
+.BI stop_at_max_accum " `on'"
+This specifies what should happen when the maximum number of
+accumulators set by
+.B max_accumulators
+is reached.  When this is
+.IR true ,
+the processing of terms is stopped at the completion of the current
+term.  When this is
+.IR false ,
+processing continues but no new accumulators are created.  This
+parameter may take the values
+.IR yes ", " no ", "
+.IR true ", " false ", "
+.IR on " or " off .
+.TP
+.BI terminator " `'"
+This specifies the string that will be output after the last document
+from the previous query has been output.  The standard C escape
+character sequences may be used to place special characters in the
+string.  For example, a newline would be written as `\en'.  To include
+a `%', use the sequence `%%'.
+.TP
+.BI timestats " `false'"
+If this is
+.IR true ,
+then the time to process a query is displayed in both real time and
+CPU time.  This parameter may take the values
+.IR yes ", " no ", "
+.IR true ", " false ", "
+.IR on " or " off .
+.TP
+.BI verbatim " `off'"
+This is a Boolean parameter that determines whether the program
+should attempt to do a regular-expression match on the retrieved
+text.  If verbatim is
+.I on
+and a post-processing string is specified with the query, then the
+post-processing string will be searched for in the documents just
+before they are displayed.  If the string is found, the document will
+be displayed; if not, the document will not be displayed.  If verbatim
+is
+.IR off ,
+the post-processing string will be considered a regular expression
+as in
+.BR egrep (1)
+or
+.BR vi (1).
+E.g., if verbatim is
+.I on,
+\*(lq\fBand.*the\fP\*(rq will look for the 8-character sequence
+\*(lq\fBand.*the\fP\*(rq.  If verbatim is
+.IR off ,
+\*(lq\fBand.*the\fP\*(rq will look for the sequence
+\*(lq\fBand\fP\*(rq followed somewhere later in the document by the
+sequence \*(lq\fBthe\fP\*(rq.  This parameter may take the values
+.IR yes ", " no ", "
+.IR true ", " false ", "
+.IR on " or " off .
+.SH ENVIRONMENT
+.TP "\w'\fBMGDATA\fP'u+2n"
+.SB MGDATA
+If this environment variable exists, then its value is used as the
+default directory where the
+.BR mg (1)
+collection files are.  If this variable does not exist, then the
+directory \*(lq\fB.\fP\*(rq is used by default.  The command line
+option
+.BI \-d " directory"
+overrides the directory in
+.BR MGDATA .
+.SH FILES
+.TP 20
+.I .mgrc
+.B mgquery
+startup file
+.TP
+.B help.mg
+Help file for
+.BR mgquery .
+The contents of this file is displayed with the
+.B .help
+command.
+.TP
+.B *.invf
+Inverted file.
+.TP
+.B *.invf.dict
+The `on-disk' stemmed dictionary.
+.TP
+.B *.text
+Compressed documents.
+.TP
+.B *.text.dict
+Compression dictionary.
+.TP
+.B *.text.idx
+Index into the compressed documents.
+.TP
+.B *.text.idx.wgt
+Interleaved index into the compressed documents and document weights.
+.TP
+.B *.weight.approx
+Approximate document weights.
+.SH "SEE ALSO"
+.na
+.BR egrep (1),
+.BR mg (1),
+.BR mg_compression_dict (1),
+.BR mg_fast_comp_dict (1),
+.BR mg_get (1),
+.BR mg_invf_dict (1),
+.BR mg_invf_dump (1),
+.BR mg_invf_rebuild (1),
+.BR mg_passes (1),
+.BR mg_perf_hash_build (1),
+.BR mg_text_estimate (1),
+.BR mg_weights_build (1),
+.BR mgbilevel (1),
+.BR mgbuild (1),
+.BR mgdictlist (1),
+.BR mgfelics (1),
+.BR mgstat (1),
+.BR mgtic (1),
+.BR mgticbuild (1),
+.BR mgticdump (1),
+.BR mgticprune (1),
+.BR mgticstat (1),
+.BR vi (1),
+.BR yacc (1).
Index: /main/tags/2.25/gsdl/packages/mg/src/text/mgquery.c
===================================================================
--- /main/tags/2.25/gsdl/packages/mg/src/text/mgquery.c	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/mg/src/text/mgquery.c	(revision 21064)
@@ -0,0 +1,1495 @@
+/**************************************************************************
+ *
+ * mgquery.c -- The   M G Q U E R Y   program
+ * Copyright (C) 1994  Neil Sharman
+ *
+ * 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.
+ *
+ * $Id$
+ *
+ **************************************************************************/
+
+/*
+   $Log$
+   Revision 1.1  1999/08/10 21:18:18  sjboddie
+   renamed mg-1.3d directory mg
+
+   Revision 1.3  1999/01/08 00:33:46  rjmcnab
+
+   Enabled mg and the library software to read in more than one index
+   at a time.
+
+   Revision 1.2  1998/11/25 07:55:49  rjmcnab
+
+   Modified mg to that you can specify the stemmer you want
+   to use via a command line option. You specify it to
+   mg_passes during the build process. The number of the
+   stemmer that you used is stored within the inverted
+   dictionary header and the stemmed dictionary header so
+   the correct stemmer is used in later stages of building
+   and querying.
+
+   Revision 1.1  1998/11/17 09:35:29  rjmcnab
+   *** empty log message ***
+
+   * Revision 1.3  1994/10/20  03:57:02  tes
+   * I have rewritten the boolean query optimiser and abstracted out the
+   * components of the boolean query.
+   *
+   * Revision 1.2  1994/09/20  04:41:58  tes
+   * For version 1.1
+   *
+ */
+
+static char *RCSID = "$Id$";
+
+#include "sysfuncs.h"
+
+#if defined(HAVE_SYS_PROCFS_H) && defined(HAVE_PR_BRKSIZE) && \
+    (__STDC__ == 0)
+/* STDC test was included to allow cc -Xc on SunOS 5 to work */
+#define USE_PROCESS_MEM
+#endif
+
+#ifdef USE_PROCESS_MEM
+# include <sys/procfs.h>
+#endif
+
+#ifdef HAVE_GETRUSAGE
+# ifdef HAVE_SYS_TIME_H
+#  include <sys/time.h>
+# endif
+# include <sys/resource.h>
+#endif
+
+#ifndef HAVE_GETPAGESIZE
+# include "getpagesize.h"
+#endif
+ 
+#if WITH_REGEX
+# include <regex.h>
+#else
+# include <rx.h>
+#endif
+
+
+#include <stdarg.h>
+#include <signal.h>
+
+#include "messages.h"
+#include "timing.h"
+#include "memlib.h"
+#include "local_strings.h"  /* [RPAP - Feb 97: Term Frequency] */
+
+#include "filestats.h"
+#include "invf.h"
+#include "text.h"
+#include "mg.h"
+#include "lists.h"
+#include "backend.h"
+#include "environment.h"
+#include "globals.h"
+#include "read_line.h"
+#include "mg_errors.h"
+#include "commands.h"
+#include "text_get.h"
+#include "term_lists.h"
+#include "query_term_list.h"
+
+
+FILE *OutFile = NULL, *InFile = NULL;
+int OutPipe = 0, InPipe = 0;
+int Quitting = 0;
+
+/* [RPAP - Feb 97: NZDL Additions] */
+#if defined(PARADOCNUM) ||  defined(NZDL)
+int GetDocNumFromParaNum(query_data *qd, int paranum) {
+  int Documents = qd->td->cth.num_of_docs;
+  int *Paragraph = qd->paragraph;
+  int low = 1, high = Documents;
+  int mid = (low+high)/2;
+
+  while ((mid = (low+high)/2) >=1 && mid <= Documents)
+    {
+      if (paranum > Paragraph[mid])
+	low = mid+1;
+      else if (paranum <= Paragraph[mid-1])
+	high = mid-1;
+      else
+	return mid;
+    }
+  FatalError(1, "Bad paragraph number.\n");
+}
+#endif
+
+#ifdef TREC_MODE
+char *trec_ids = NULL;
+long *trec_paras = NULL;
+#endif
+
+static volatile int PagerRunning = 0;
+static volatile int Ctrl_C = 0;
+
+
+/*****************************************************************************/
+
+typedef enum
+  {
+    S_Time, S_Mem, S_Size, S_File
+  }
+S_Type;
+
+static struct Stat
+  {
+    S_Type typ;
+    char *name;
+    char *text;
+  }
+ *Stats = NULL;
+static int NumStats = 0;
+
+static void 
+Clear_Stats (void)
+{
+  if (Stats)
+    {
+      int i;
+      for (i = 0; i < NumStats; i++)
+	{
+	  if (Stats[i].name)
+	    Xfree (Stats[i].name);
+	  if (Stats[i].text)
+	    Xfree (Stats[i].text);
+	}
+      Xfree (Stats);
+      Stats = NULL;
+      NumStats = 0;
+    }
+}
+
+static void 
+Add_Stats (S_Type typ, char *name, char *fmt,...)
+{
+  char buf[1024];
+  va_list args;
+  va_start (args, fmt);
+  vsprintf (buf, fmt, args);
+  if (Stats)
+    Stats = Xrealloc (Stats, (++NumStats) * sizeof (*Stats));
+  else
+    Stats = Xmalloc ((++NumStats) * sizeof (*Stats));
+  Stats[NumStats - 1].typ = typ;
+  Stats[NumStats - 1].name = Xstrdup (name);
+  Stats[NumStats - 1].text = Xstrdup (buf);
+}
+
+static void 
+Display_Stats (FILE * f)
+{
+  static char *sep = "-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-="
+  "-=-=-=-=-=-=-=-=-=-=-";
+  char *names[] =
+  {"Time:  ", "Memory:", "Sizes: ", "Disk:  ", "       "};
+  int i, last_typ = -1;
+  size_t len = 0;
+  if (NumStats == 0)
+    return;
+  fprintf (f, "%s\n", sep);
+  for (i = 0; i < NumStats; i++)
+    if (strlen (Stats[i].name) > len)
+      len = strlen (Stats[i].name);
+  for (i = 0; i < NumStats; i++)
+    {
+      int typ = 4;
+      if (Stats[i].typ != last_typ)
+	typ = last_typ = Stats[i].typ;
+      fprintf (f, "%s %-*s %s\n", names[typ], (int) len, Stats[i].name, Stats[i].text);
+    }
+  fprintf (f, "%s\n", sep);
+}
+
+/*****************************************************************************/
+
+
+static void 
+QueryTimeStats (ProgTime * Start, ProgTime * invf, ProgTime * text)
+{
+  if (!BooleanEnv (GetEnv ("briefstats"), 0))
+    {
+      Add_Stats (S_Time, "invf", ElapsedTime (Start, invf));
+      Add_Stats (S_Time, "text", ElapsedTime (invf, text));
+    }
+  Add_Stats (S_Time, "total", ElapsedTime (Start, text));
+}
+
+static void 
+StartUpTimeStats (InitQueryTimes * iqt)
+{
+  if (!BooleanEnv (GetEnv ("briefstats"), 0))
+    {
+      Add_Stats (S_Time, "dict [stem]", ElapsedTime (&iqt->Start,
+						     &iqt->StemDict));
+      Add_Stats (S_Time, "weights", ElapsedTime (&iqt->StemDict,
+						 &iqt->ApproxWeights));
+      Add_Stats (S_Time, "dict [text]", ElapsedTime (&iqt->ApproxWeights,
+						     &iqt->CompDict));
+      Add_Stats (S_Time, "Inverted", ElapsedTime (&iqt->CompDict,
+						  &iqt->Invf));
+      Add_Stats (S_Time, "Compressed", ElapsedTime (&iqt->Invf,
+						    &iqt->Text));
+    }
+  Add_Stats (S_Time, "total", ElapsedTime (&iqt->Start, &iqt->Text));
+}
+
+
+
+
+#ifdef USE_PROCESS_MEM
+static u_long 
+process_mem (void)
+{
+  prstatus_t pr;
+  static int fd = -1;
+  if (fd == -1)
+    {
+      char buf[128];
+      sprintf (buf, "/proc/%ld", (long) getpid ());
+      fd = open (buf, O_RDONLY);
+    }
+  if (fd == -1 || ioctl (fd, PIOCSTATUS, &pr) == -1)
+    return 0;
+  return pr.pr_brksize;
+}
+#endif
+
+
+
+
+static void 
+MemStats (query_data * qd)
+{
+  if (!BooleanEnv (GetEnv ("briefstats"), 0))
+    {
+#ifdef HAVE_GETRUSAGE
+      struct rusage rusage;
+      getrusage (RUSAGE_SELF, &rusage);
+
+      Add_Stats (S_Mem, "process mem", "%7.3f Mb",
+	    (double) (rusage.ru_maxrss * getpagesize () / 1024.0 / 1024.0));
+#endif
+#ifdef USE_PROCESS_MEM
+      Add_Stats (S_Mem, "process mem", "%7.3f Mb",
+		 (double) (process_mem () / 1024.0 / 1024.0));
+#endif
+      Add_Stats (S_Mem, "dict [stem]", "%7.1f kB",
+		 (double) qd->sd->MemForStemDict / 1024);
+      Add_Stats (S_Mem, "dict [text]", "%7.1f kB",
+		 (double) qd->cd->MemForCompDict / 1024);
+      if (qd->awd)
+	Add_Stats (S_Mem, "weights", "%7.1f kB",
+		   (double) qd->awd->MemForWeights / 1024);
+    }
+  if (qd->awd)
+    Add_Stats (S_Mem, "total [peak]", "%7.1f kB",
+	       (double) (qd->max_mem_in_use + qd->sd->MemForStemDict +
+		   qd->cd->MemForCompDict + qd->awd->MemForWeights) / 1024);
+  else
+    Add_Stats (S_Mem, "total [peak]", "%7.1f kB",
+	       (double) (qd->max_mem_in_use + qd->sd->MemForStemDict +
+			 qd->cd->MemForCompDict) / 1024);
+
+}
+
+
+
+static void 
+SizeStats (query_data * qd)
+{
+  Add_Stats (S_Size, "skips", "%7d", qd->hops_taken);
+  Add_Stats (S_Size, "pointers", "%7d", qd->num_of_ptrs);
+  Add_Stats (S_Size, "accumulators", "%7d", qd->num_of_accum);
+  Add_Stats (S_Size, "terms", "%7d", qd->num_of_terms);
+  Add_Stats (S_Size, "answers", "%7d", qd->num_of_ans);
+  Add_Stats (S_Size, "index lookups", "%7d", qd->text_idx_lookups);
+}
+
+static void 
+TotalSizeStats (query_data * qd)
+{
+  Add_Stats (S_Size, "skips", "%7d", qd->tot_hops_taken);
+  Add_Stats (S_Size, "pointers", "%7d", qd->tot_num_of_ptrs);
+  Add_Stats (S_Size, "accumulators", "%7d", qd->tot_num_of_accum);
+  Add_Stats (S_Size, "terms", "%7d", qd->tot_num_of_terms);
+  Add_Stats (S_Size, "answers", "%7d", qd->tot_num_of_ans);
+  Add_Stats (S_Size, "index lookups", "%7d", qd->tot_text_idx_lookups);
+}
+
+
+static void 
+StatFile (File * F)
+{
+  static unsigned long NumBytes = 0, NumSeeks = 0, NumReads = 0;
+  if (F)
+    if ((int) F != -1)
+      {
+	if (!BooleanEnv (GetEnv ("briefstats"), 0))
+	  Add_Stats (S_File, F->name, "%7.1f kB (%3d seeks, %7d reads)",
+		   (double) F->Current.NumBytes / 1024, F->Current.NumSeeks,
+		     F->Current.NumReads);
+	NumBytes += F->Current.NumBytes;
+	NumSeeks += F->Current.NumSeeks;
+	NumReads += F->Current.NumReads;
+      }
+    else
+      {
+	Add_Stats (S_File, "total", "%7.1f kB (%3d seeks, %7d reads)",
+		   (double) NumBytes / 1024, NumSeeks, NumReads);
+	NumSeeks = NumReads = NumBytes = 0;
+      }
+
+}
+
+
+static void 
+File_Stats (query_data * qd)
+{
+  StatFile (qd->File_comp_dict);
+  StatFile (qd->File_fast_comp_dict);
+  StatFile (qd->File_text_idx_wgt);
+  StatFile (qd->File_text);
+  StatFile (qd->File_stem);
+
+  /* [RPAP - Jan 97: Stem Index Change] */
+  if (qd->sd->sdh.indexed)
+    {
+      StatFile (qd->File_stem1);
+      StatFile (qd->File_stem2);
+      StatFile (qd->File_stem3);
+    }
+
+  StatFile (qd->File_invf);
+  StatFile (qd->File_weight_approx);
+  StatFile (qd->File_text_idx);
+  StatFile ((File *) (-1));
+}
+
+
+char *
+get_query (query_data * qd)
+{
+  char *line, *LinePtr;
+  WritePrompt ();
+  do
+    {
+      do
+	{
+	  line = GetMultiLine ();
+	  if (line == NULL)
+	    {
+	      if (stdin == InFile)
+		return (NULL);	/* EOF */
+	      if (InPipe)
+/* [RPAP - Feb 97: WIN32 Port] */
+#ifdef __WIN32__
+		_pclose (InFile);
+#else
+		pclose (InFile);
+#endif
+	      else
+		fclose (InFile);
+	      InPipe = 0;
+	      InFile = stdin;
+	    }
+	}
+      while (line == NULL);
+      LinePtr = ProcessCommands (line, qd);
+      if (CommandsErrorStr)
+	fprintf (stderr, "%s\n", CommandsErrorStr);
+    }
+  while (*LinePtr == '\0' && !Quitting);
+  return (LinePtr);
+}
+
+
+/* This is executed when a SIGPIPE is detected
+   i.e. If some one quits out of the PAGER, this is executed */
+#ifdef HAVE_SIGCONTEXT
+static RETSIGTYPE 
+SIGPIPE_handler (int sig, int code,
+		 struct sigcontext *scp, char *addr)
+#else
+static RETSIGTYPE 
+SIGPIPE_handler (int sig)
+#endif
+{
+  /* [RPAP - Feb 97: WIN32 Port] */
+#ifdef __WIN32__
+  signal (sig, SIG_IGN);
+#else
+  signal (SIGPIPE, SIG_IGN);
+#endif
+  PagerRunning = 0;
+}
+
+/* This is executed when a SIGINT (i.e. CTRL-C) is detected */
+#ifdef  HAVE_SIGCONTEXT
+static RETSIGTYPE 
+SIGINT_handler (int sig, int code,
+		struct sigcontext *scp, char *addr)
+#else
+static RETSIGTYPE 
+SIGINT_handler (int sig)
+#endif
+{
+  Ctrl_C = 1;
+}
+
+
+
+static char *post_proc = NULL;
+
+
+
+void 
+GetPostProc (char *line)
+{
+  char *start, *finish;
+  if (post_proc)
+    {
+      Xfree (post_proc);
+      post_proc = NULL;
+    }
+  start = strchr (line, '\"');
+  finish = strrchr (line, '\"');
+  if (start != finish)
+    {
+      /* found a pattern */
+      *finish = '\0';
+      post_proc = Xstrdup (start + 1);
+      strcpy (start, finish + 1);
+      if (BooleanEnv (GetEnv ("verbatim"), 1) == 0)
+	{
+	  char *s;
+	  s = re_comp (post_proc);
+	  if (!s)
+	    {
+	      Xfree (post_proc);
+	      post_proc = NULL;
+	    }
+	}
+    }
+  else if (start != NULL)
+    {
+      /* found a single speech mark. Delete It. */
+      strcpy (start, start + 1);
+    }
+}
+
+int 
+PostProc (char *UDoc, int verbatim)
+{
+  if (!post_proc)
+    return 1;
+
+  if (verbatim) {
+    return (strstr (UDoc, post_proc) != NULL);
+  }
+  return re_exec ((char *) UDoc);
+}
+
+
+
+static DocEntry *
+in_chain (int para, int ip, DocEntry * dc)
+{
+  while (dc)
+    {
+      if (dc->DocNum - ip == para)
+	return dc;
+      dc = dc->Next;
+    }
+  return NULL;
+}
+
+/* num should be greater than or equal to 1 */
+int 
+RawDocOutput (query_data * qd, u_long num, FILE * Output)
+{
+  static last_pos = 0;
+  static u_char *c_buffer = 0;
+  static int buf_len = -1;
+  static u_char *uc_buffer = 0;
+  u_long pos, len;
+  int ULen;
+
+  FetchDocStart (qd, num, &pos, &len);
+
+  if ((int) len > buf_len)
+    {
+      if (c_buffer)
+	{
+	  Xfree (c_buffer);
+	  Xfree (uc_buffer);
+	}
+      if (!(c_buffer = Xmalloc (len)))
+	return -1;
+      if (!(uc_buffer = Xmalloc ((int) (qd->td->cth.ratio * 1.01 *
+					len) + 100)))
+	return -1;
+      buf_len = len;
+    }
+  if (last_pos != pos)
+    Fseek (qd->td->TextFile, pos, 0);
+  Fread (c_buffer, 1, len, qd->td->TextFile);
+  last_pos = pos + len;
+  DecodeText (qd->cd, c_buffer, len, uc_buffer, &ULen);
+  fwrite (uc_buffer, ULen, sizeof (u_char), Output);
+  return 0;
+}
+
+
+void 
+StringOut (FILE * Output, char *string,
+	   int intvalid, unsigned long intval,
+	   int floatvalid, double floatval)
+{
+  char *s;
+  for (s = string; *s; s++)
+    if (*s == '%' &&
+	(*(s + 1) == 'n' || *(s + 1) == 'w' || *(s + 1) == '%'))
+      {
+	s++;
+	switch (*s)
+	  {
+	  case 'n':
+	    if (intvalid)
+	      fprintf (Output, "%lu", intval);
+	    else
+	      fprintf (Output, "%%n");
+	    break;
+	  case 'w':
+	    if (floatvalid)
+	      fprintf (Output, "%f", floatval);
+	    else
+	      fprintf (Output, "%%w");
+	    break;
+	  case '%':
+	    fputc ('%', Output);
+	  }
+      }
+    else
+      fputc (*s, Output);
+}
+
+
+void 
+HeaderOut (FILE * Output, u_char * UDoc, unsigned long ULen, int heads_length)
+{
+  int i, space = 1, num = 0;
+  for (i = 0; i < ULen && num < heads_length; i++)
+    {
+      char c = UDoc[i];
+      if (c == '\02')
+	break;
+
+      if (isspace (c) || c == '\01' || c == '\03')
+	{
+	  if (!space)
+	    {
+	      fputc (' ', Output);
+	      num++;
+	    }
+	  space = 1;
+	}
+      else
+	{
+	  space = 0;
+	  fputc (c, Output);
+	  num++;
+	}
+    }
+}
+
+/* [RPAP - Feb 97: NZDL Additions] */
+#if defined(PARADOCNUM) || defined(NZDL)
+void PrintDocNum(FILE *output, char query_type,
+		 int docnum, int indexnum, float weight)
+{
+  if (query_type == 'R' || query_type == 'A')
+    fprintf(output, "%7d.%-7d  %6.4f\n", docnum, indexnum, weight);
+  else
+    fprintf(output, "%7d.%-7d\n", docnum, indexnum);
+}
+#endif
+
+static int 
+ProcessDocs (query_data * qd, int num, int verbatim,
+	     char OutputType, FILE * Output)
+{
+  int max_buf = 0;
+  int DocCount = 0;
+  char *doc_sepstr = NULL;
+  char *para_sepstr = NULL;
+  char *para_start = NULL;
+  int heads_length = atoi (GetDefEnv ("heads_length", "50"));
+  char QueryType = get_query_type ();
+  int need_text = (OutputType == OUTPUT_TEXT || OutputType == OUTPUT_HILITE ||
+		   OutputType == OUTPUT_HEADERS || OutputType == OUTPUT_SILENT || 
+		   post_proc); /* [RJM June 1997 -- fixing post retrieval scan] */
+
+  if (OutputType == OUTPUT_TEXT || OutputType == OUTPUT_HILITE)
+    {
+      if (QueryType == QUERY_APPROX || QueryType == QUERY_RANKED)
+	{
+	  doc_sepstr = de_escape_string (
+				    Xstrdup (GetDefEnv ("ranked_doc_sepstr",
+			   "---------------------------------- %n %w\\n")));
+	}
+      else
+	{
+	  doc_sepstr = de_escape_string (
+					  Xstrdup (GetDefEnv ("doc_sepstr",
+			      "---------------------------------- %n\\n")));
+	}
+      para_sepstr = de_escape_string (
+				       Xstrdup (GetDefEnv ("para_sepstr",
+				  "\\n######## PARAGRAPH %n ########\\n")));
+
+      para_start = de_escape_string (
+				      Xstrdup (GetDefEnv ("para_start",
+					    "***** Weight = %w *****\\n")));
+    }
+
+  if (need_text)
+    {
+      max_buf = atoi (GetDefEnv ("buffer", "1048576"));
+    }
+
+  do
+    {
+      u_char *UDoc = NULL;
+      unsigned long ULen;
+
+      if (need_text)
+	{
+	  /* load the compressed text */
+	  if (LoadCompressedText (qd, max_buf))
+	    {
+	      Message ("Unable to load compressed text.");
+	      FatalError (1, "This is probably due to lack of memory.");
+	    }
+
+	  /* uncompress the loaded text */
+	  UDoc = GetDocText (qd, &ULen);
+	  if (UDoc == NULL)
+	    FatalError (1, "UDoc is unexpectedly NULL");
+	}
+
+      if (!UDoc || PostProc ((char *) UDoc, verbatim))
+	{
+	  switch (OutputType)
+	    {
+	    case OUTPUT_COUNT:
+	    case OUTPUT_SILENT:
+	      break;
+	    case OUTPUT_DOCNUMS:	/* This prints out the docnums string */
+	      if (PagerRunning)
+		{
+
+/* [RPAP - Feb 97: NZDL Additions] */
+#if defined(PARADOCNUM) || defined(NZDL)
+		  int doc_num = GetDocNum(qd);
+
+		  if (qd->paragraph)
+		    {
+		      if (qd->id->ifh.InvfLevel == 3 &&
+			  (QueryType == 'R' || QueryType == 'A'))
+			{
+			  /* Print weights for each paragraph in document */
+			  
+
+			  int true_doc_num = GetDocNumFromParaNum(qd, doc_num);
+
+			  /* Get number of paragraphs in this document */
+
+			  int num_paragraphs = 
+			    qd->paragraph[true_doc_num]-qd->paragraph[true_doc_num-1];
+
+			  int init_para = FetchInitialParagraph(qd->td,
+								doc_num);
+			  DocEntry *de, *doc_chain = GetDocChain(qd);
+			  int i;
+
+			  for (i = 0; i < num_paragraphs; i++)
+			    {
+			      if ((de = in_chain(i, init_para, doc_chain)))
+				PrintDocNum(Output, QueryType,
+					    true_doc_num, init_para+i,
+					    de->Weight);
+			    }
+			}
+		      else
+			PrintDocNum(Output, QueryType,
+				    GetDocNumFromParaNum(qd, GetDocNum(qd)),
+				    GetDocNum(qd),
+				    GetDocWeight(qd));
+		    }
+		  else
+		    {
+		      PrintDocNum(Output, QueryType,
+				  doc_num, doc_num, GetDocWeight(qd));
+		    }
+#else
+		fprintf (Output, "%7d   %6.4f   %7lu\n", GetDocNum (qd),
+			 GetDocWeight (qd), GetDocCompLength (qd));
+#endif
+		}
+	      break;
+	    case OUTPUT_HEADERS:	/* This prints out the headers of the documents */
+	      if (PagerRunning)
+		fprintf (Output, "%d ", GetDocNum (qd));
+	      HeaderOut (Output, UDoc, ULen, heads_length);
+	      if (PagerRunning)
+		fputc ('\n', Output);
+	      break;
+#if TREC_MODE
+	    case OUTPUT_EXTRAS:	/* This prints out the docnums string */
+	      if (PagerRunning && trec_ids)
+		{
+		  long DN, PN = GetDocNum (qd) - 1;
+		  if (trec_paras)
+		    DN = trec_paras[PN];
+		  else
+		    DN = PN;
+		  fprintf (Output, "%-14.14s  %8ld  %10.5f\n",
+			   &trec_ids[DN * 14], PN + 1, GetDocWeight (qd));
+		}
+	      break;
+#endif
+	    case OUTPUT_TEXT:
+	    case OUTPUT_HILITE:
+	      {
+		int j, para = -1, curr_para = 0;
+		int init_para = -1;
+		DocEntry *de, *doc_chain = NULL;
+		register char ch = ' ';
+		register char lch = '\n';
+
+/* [RPAP - Feb 97: NZDL Additions] */
+#if defined(PARADOCNUM) || defined(NZDL)
+		if (qd->id->ifh.InvfLevel == 3)
+		  {
+		    init_para = FetchInitialParagraph(qd->td, GetDocNum(qd));
+		    
+		    StringOut(Output, para_sepstr, 
+			      1, init_para+curr_para,
+			      0, 0);
+
+		  }
+		else
+		  StringOut(Output, doc_sepstr, 
+			    1, GetDocNum(qd),
+			    QueryType == 'A' || QueryType == 'R',
+			    GetDocWeight(qd));
+
+#else
+		int p_on = 0;
+
+		if (PagerRunning)
+		  {
+		    StringOut (Output, doc_sepstr,
+			       1, GetDocNum (qd),
+			       QueryType == 'A' || QueryType == 'R',
+			       GetDocWeight (qd));
+		  }
+		if (qd->id->ifh.InvfLevel == 3)
+		  {
+		    init_para = FetchInitialParagraph (qd->td, GetDocNum (qd));
+		    doc_chain = GetDocChain (qd);
+		    para = GetDocNum (qd) - init_para;
+
+		    StringOut (Output, para_sepstr,
+			       1, curr_para + 1,
+			       0, 0);
+
+		    if ((de = in_chain (0, init_para, doc_chain)))
+		      StringOut (Output, para_start,
+				 0, 0,
+				 1, de->Weight);
+
+		    if (doc_chain->DocNum - init_para == 0)
+		      p_on = 1;
+		  }
+#endif
+		for (j = 0; j < ULen; j++)
+		  {
+		    ch = UDoc[j];
+		    switch (ch)
+		      {
+		      case '\02':
+			break;
+		      case '\01':
+			ch = '\n';
+		      case '\03':
+/* [RPAP - Feb 97: NZDL Additions] */
+#if defined(PARADOCNUM) || defined(NZDL)
+			/* print paragraph numbers only if this is
+			   a level 3 index */
+			if (qd->id->ifh.InvfLevel == 3)
+			  {
+			    curr_para++;
+			    StringOut(Output, para_sepstr, 
+				      1, init_para+curr_para,
+				      0, 0);
+			  }
+#else
+			p_on = 0;
+			curr_para++;
+			StringOut (Output, para_sepstr,
+				   1, curr_para + 1,
+				   0, 0);
+			lch = *(strchr (para_sepstr, '\0') - 1);
+			if ((de = in_chain (curr_para, init_para, doc_chain)))
+			  StringOut (Output, para_start,
+				     0, 0,
+				     1, de->Weight);
+			if (doc_chain &&
+			    doc_chain->DocNum - init_para == curr_para)
+			  p_on = 1;
+#endif
+			break;
+		      default:
+			{
+			  if (PagerRunning)
+			    {
+			      fputc (ch, Output);
+/* [RPAP - Feb 97: NZDL Additions] */
+#if !defined(PARADOCNUM) && !defined(NZDL)
+			      if (p_on && isprint (ch))
+				{
+				  fputc ('\b', Output);
+				  fputc ('_', Output);
+				}
+#endif
+			    }
+
+			  lch = ch;
+			}
+		      }
+		  }
+		if (PagerRunning && lch != '\n')
+		  fputc ('\n', Output);
+/* [RPAP - Feb 97: NZDL Additions] */
+#if !defined(PARADOCNUM) && !defined(NZDL)
+		p_on = 0;
+#endif
+	      }
+	    }
+	  if (PagerRunning)
+	    fflush (Output);
+
+	  DocCount++; /* moved within if statement [RJM June 1997 -- fixing post retrieval scan] */
+	}
+    }
+  while (NextDoc (qd) && PagerRunning && (!Ctrl_C));
+
+  if (need_text)
+    {
+      FreeTextBuffer (qd);
+    }
+
+  if (OutputType == OUTPUT_TEXT || OutputType == OUTPUT_HILITE)
+    {
+      Xfree (doc_sepstr);
+      Xfree (para_sepstr);
+      Xfree (para_start);
+    }
+
+  return (DocCount);
+}
+
+
+void 
+output_terminator (FILE * out)
+{
+  char *terminator = Xstrdup (GetDefEnv ("terminator", ""));
+  de_escape_string (terminator);
+  fputs (terminator, out);
+  Xfree (terminator);
+}
+
+
+
+
+/* MoreDocs () */
+/* Displays all documents in list  DocList. */
+/* Documents are fetched, then decompressed and displayed according to the */
+/* format implied in  FormString(). */
+
+/* [RPAP - Feb 97: WIN32 Port] */
+#ifdef __WIN32__
+# define HILITE_PAGER "mg_hilite_words.exe"
+#else
+# define HILITE_PAGER "mg_hilite_words"
+#endif
+
+#define MAX_HILITE_PAGER_STR 80	/* for command & its options */
+
+static void 
+MoreDocs (query_data * qd, char *Query, char OutputType)
+{
+  static char terms_str[MAXTERMSTRLEN + 1];
+  int DocCount = 0;		/* number of actual matches */
+  FILE *Output = NULL;
+  int using_pipe = 0;
+  char *pager = NULL;
+
+  Ctrl_C = 0;
+
+  qd->num_of_ans = qd->DL->num;
+
+  /* [RPAP - Feb 97: WIN32 Port] */
+#ifndef __WIN32__
+  signal (SIGPIPE, SIGPIPE_handler);
+#endif
+  signal (SIGINT, SIGINT_handler);
+
+  PagerRunning = 1;
+  if (isatty (fileno (OutFile)) && GetEnv ("pager") &&
+      OutputType != OUTPUT_HILITE &&
+      OutputType != OUTPUT_SILENT && OutputType != OUTPUT_COUNT)
+    {
+      pager = GetEnv ("pager");
+    }
+  else if (isatty (fileno (OutFile)) && OutputType == OUTPUT_HILITE)
+    {
+      /* concat the pager and its word argument strings */
+      ConvertTermsToString (qd->TL, terms_str);
+      pager = Xmalloc (MAX_HILITE_PAGER_STR + strlen (terms_str) + 1);
+      if (!pager)
+	{
+	  fprintf (stderr, "Unable to allocate memory for highlighting\n");
+	  return;
+	}
+      sprintf (pager, "%s --style=%s --pager=%s --stem_method=%ld --stemmer=%ld %s",
+	       HILITE_PAGER,
+	       GetEnv ("hilite_style"),
+	       GetEnv ("pager"),
+	       qd->sd->sdh.stem_method,
+	       qd->sd->sdh.stemmer_num,
+	       terms_str);
+
+    }
+  else
+    {
+      Output = OutFile;
+    }
+
+/* [RPAP - Feb 97: NZDL Additions] */
+#if defined(OUTPUTSTEMMEDWORDS) || defined(NZDL)
+  if (!isatty(fileno(OutFile)) && get_query_type() != QUERY_DOCNUMS)
+    {
+      ConvertTermsToString(qd->TL, terms_str);
+      fprintf(Output, "%s\n", terms_str);
+    }
+#endif
+  if (pager)
+    {
+/* [RPAP - Feb 97: WIN32 Port] */
+#ifdef __WIN32__
+      Output = _popen (pager, "w");
+#else
+      Output = popen (pager, "w");
+#endif
+      using_pipe = (Output != NULL);
+      if (!using_pipe)
+	{
+	  fprintf (stderr, "Unable to run \"%s\"\n", pager);
+	  return;
+	}
+    }
+
+
+  if (qd->DL->num > 0)
+    {
+      if (OutputType == OUTPUT_COUNT && !post_proc)
+	DocCount = qd->DL->num;
+      else {
+	DocCount = ProcessDocs (qd, qd->DL->num,
+				BooleanEnv (GetEnv ("verbatim"), 1),
+				OutputType, Output);
+      }
+    }
+
+  if (PagerRunning)
+    {
+      output_terminator (Output);
+      fflush (Output);
+    }
+
+  if (OutputType == OUTPUT_HILITE && pager)
+    free (pager);		/* as needed to malloc to create the pager string */
+
+  if (using_pipe)
+/* [RPAP - Feb 97: WIN32 Port] */
+#ifdef __WIN32__
+    _pclose (Output);
+#else
+    pclose (Output);
+#endif
+
+  if (qd->DL->num == 0)
+    fprintf (stderr, "No entries correspond to that query.\n");
+  else
+    {
+      if (OutputType == OUTPUT_COUNT)
+	fprintf (stderr, "%d documents match.\n", DocCount);
+      else
+	fprintf (stderr, "%d documents retrieved.\n", DocCount);
+    }
+
+  signal (SIGINT, SIG_DFL);
+}
+
+
+void 
+start_up_stats (query_data * qd, InitQueryTimes iqt)
+{
+  Clear_Stats ();
+  if (BooleanEnv (GetEnv ("timestats"), 0) ||
+      BooleanEnv (GetEnv ("briefstats"), 0))
+    StartUpTimeStats (&iqt);
+
+  if (BooleanEnv (GetEnv ("diskstats"), 0) ||
+      BooleanEnv (GetEnv ("briefstats"), 0))
+    File_Stats (qd);
+
+  if (BooleanEnv (GetEnv ("memstats"), 0) ||
+      BooleanEnv (GetEnv ("briefstats"), 0))
+    MemStats (qd);
+
+}
+
+
+void 
+shut_down_stats (query_data * qd, ProgTime * start,
+		 ProgTime * invf, ProgTime * text)
+{
+  Clear_Stats ();
+  if (BooleanEnv (GetEnv ("timestats"), 0) ||
+      BooleanEnv (GetEnv ("briefstats"), 0))
+    QueryTimeStats (start, invf, text);
+
+  if (BooleanEnv (GetEnv ("diskstats"), 0) ||
+      BooleanEnv (GetEnv ("briefstats"), 0))
+    {
+      TransFileStats (qd);
+      File_Stats (qd);
+    }
+
+  if (BooleanEnv (GetEnv ("sizestats"), 0))
+    TotalSizeStats (qd);
+}
+
+
+
+char *wordfreqword2str (u_char * s)
+{
+  static char buf[1024];
+  int i, len = (int) *s++;
+
+  for (i = 0; i < len; i++)
+    {
+      buf[i] = (char)s[i];
+    }
+  buf[len] = '\0';
+
+  return buf;
+}
+
+
+/* [RPAP - Feb 97: Term Frequency] */
+/*********************************
+ * PrintQueryTermFreq
+ *
+ * Prints the query terms and their respective frequencies within the collection
+ *********************************/
+void
+PrintQueryTermFreqs (QueryTermList *qtl)
+{
+  int i;
+
+  /* Print the number of terms */
+  fprintf (OutFile, "%d\n", qtl->num);
+
+  /* Print the terms and their respective frequency within the collection */
+  for (i = 0; i < qtl->num; i++)
+    if (qtl->QTE[i].stem_method == -1)
+      /* Using default stem method - don't print stem method beside term */
+      fprintf (OutFile, "%s %d\n", wordfreqword2str (qtl->QTE[i].Term), qtl->QTE[i].Count);
+    else
+      /* Term was forced with a stem, print stem method with term */
+      fprintf (OutFile, "%s#%d %d\n", wordfreqword2str (qtl->QTE[i].Term), qtl->QTE[i].stem_method, qtl->QTE[i].Count);
+}
+
+
+void 
+query (void)
+{
+  ProgTime TotalStartTime, TotalInvfTime, TotalTextTime;
+  InitQueryTimes iqt;
+  query_data *qd;
+
+  TotalStartTime.RealTime = TotalStartTime.CPUTime = 0;
+  TotalInvfTime.RealTime = TotalInvfTime.CPUTime = 0;
+  TotalTextTime.RealTime = TotalTextTime.CPUTime = 0;
+
+/* [RPAP - Feb 97: WIN32 Port] */
+#ifdef __WIN32__
+  qd = InitQuerySystem (GetDefEnv ("mgdir", ".\\"),
+                        GetDefEnv ("mgname", ""),
+			GetDefEnv ("textname", NULL), /* [RJM 06/97: text filename] */
+			&iqt);
+#else
+  qd = InitQuerySystem (GetDefEnv ("mgdir", "./"),
+                        GetDefEnv ("mgname", ""),
+			GetDefEnv ("textname", NULL), /* [RJM 06/97: text filename] */
+                        &iqt);
+#endif
+
+  if (!qd)
+    FatalError (1, mg_errorstrs[mg_errno], mg_error_data);
+  start_up_stats (qd, iqt);
+
+
+  while (1)
+    {
+      ProgTime StartTime, InvfTime, TextTime;
+      char QueryType;
+      char OutputType;
+      char *line;
+      ResetFileStats (qd);
+      qd->max_mem_in_use = qd->mem_in_use = 0;
+
+      qd->tot_hops_taken += qd->hops_taken;
+      qd->tot_num_of_ptrs += qd->num_of_ptrs;
+      qd->tot_num_of_accum += qd->num_of_accum;
+      qd->tot_num_of_terms += qd->num_of_terms;
+      qd->tot_num_of_ans += qd->num_of_ans;
+      qd->tot_text_idx_lookups += qd->text_idx_lookups;
+      qd->hops_taken = qd->num_of_ptrs = 0;
+      qd->num_of_accum = qd->num_of_ans = qd->num_of_terms = 0;
+      qd->text_idx_lookups = 0;
+
+      Display_Stats (stderr);
+      Clear_Stats ();
+      line = get_query (qd);
+      if (!line || Quitting)
+	break;
+
+      GetPostProc (line);
+
+      GetTime (&StartTime);
+
+      FreeQueryDocs (qd);
+
+      QueryType = get_query_type ();
+      OutputType = get_output_type ();
+      /* No point in hiliting words on a docnum query */
+      if (OutputType == OUTPUT_HILITE && QueryType == QUERY_DOCNUMS)
+	OutputType = OUTPUT_TEXT;
+
+      switch (QueryType)
+	{
+	case QUERY_BOOLEAN:
+	  {
+	    char *maxdocs;
+	    BooleanQueryInfo bqi;
+	    maxdocs = GetDefEnv ("maxdocs", "all");
+	    bqi.MaxDocsToRetrieve = strcmp (maxdocs, "all") ? atoi (maxdocs) : -1;
+	    /* [RPAP - Jan 97: Stem Index Change] */
+	    if (qd->sd->sdh.indexed)
+	      BooleanQuery (qd, line, &bqi, (BooleanEnv (GetEnv ("casefold"), 0) |
+					     (BooleanEnv (GetEnv ("stem"), 0) << 1)));
+	    else
+	      BooleanQuery (qd, line, &bqi, qd->sd->sdh.stem_method);
+
+	    break;
+	  }
+	case QUERY_APPROX:
+	case QUERY_RANKED:
+	  {
+	    char *maxdocs;
+	    char *maxterms;
+	    char *maxaccum;
+	    RankedQueryInfo rqi;
+	    maxdocs = GetDefEnv ("maxdocs", "all");
+	    maxterms = GetDefEnv ("max_terms", "all");
+	    maxaccum = GetDefEnv ("max_accumulators", "all");
+	    rqi.Sort = BooleanEnv (GetEnv ("sorted_terms"), 0);
+	    rqi.QueryFreqs = BooleanEnv (GetEnv ("qfreq"), 1);
+	    rqi.Exact = QueryType == QUERY_RANKED;
+	    rqi.MaxDocsToRetrieve = strcmp (maxdocs, "all") ? atoi (maxdocs) : -1;
+	    rqi.MaxTerms = strcmp (maxterms, "all") ? atoi (maxterms) : -1;
+	    rqi.MaxParasToRetrieve = rqi.MaxDocsToRetrieve;
+	    if (qd->id->ifh.InvfLevel == 3 && GetEnv ("maxparas"))
+	      rqi.MaxParasToRetrieve = atoi (GetEnv ("maxparas"));
+	    rqi.AccumMethod = toupper (*GetDefEnv ("accumulator_method", "A"));
+	    rqi.MaxAccums = strcmp (maxaccum, "all") ? atoi (maxaccum) : -1;
+	    rqi.HashTblSize = IntEnv (GetEnv ("hash_tbl_size"), 1000);
+	    rqi.StopAtMaxAccum = BooleanEnv (GetEnv ("stop_at_max_accum"), 0);
+	    rqi.skip_dump = GetEnv ("skip_dump");
+	    RankedQuery (qd, line, &rqi);
+	    break;
+	  }
+	case QUERY_DOCNUMS:
+	  {
+	    DocnumsQuery (qd, line);
+	    break;
+	  }
+	}
+
+      GetTime (&InvfTime);
+
+      /* [RPAP - Feb 97: Term Frequency] */
+      if (qd->QTL && BooleanEnv (GetEnv ("term_freq"), 0))
+	PrintQueryTermFreqs (qd->QTL);
+
+      if (qd->DL)
+	MoreDocs (qd, line, OutputType);
+
+      GetTime (&TextTime);
+
+      if (BooleanEnv (GetEnv ("timestats"), 0) ||
+	  BooleanEnv (GetEnv ("briefstats"), 0))
+	QueryTimeStats (&StartTime, &InvfTime, &TextTime);
+
+      if (BooleanEnv (GetEnv ("diskstats"), 0) ||
+	  BooleanEnv (GetEnv ("briefstats"), 0))
+	File_Stats (qd);
+
+      if (BooleanEnv (GetEnv ("memstats"), 0) ||
+	  BooleanEnv (GetEnv ("briefstats"), 0))
+	MemStats (qd);
+
+      if (BooleanEnv (GetEnv ("sizestats"), 0))
+	SizeStats (qd);
+
+      TotalInvfTime.RealTime += InvfTime.RealTime - StartTime.RealTime;
+      TotalInvfTime.CPUTime += InvfTime.CPUTime - StartTime.CPUTime;
+      TotalTextTime.RealTime += TextTime.RealTime - StartTime.RealTime;
+      TotalTextTime.CPUTime += TextTime.CPUTime - StartTime.CPUTime;
+    }
+
+  if (isatty (fileno (InFile)) && !Quitting)
+    fprintf (stderr, "\n");
+
+  shut_down_stats (qd, &TotalStartTime, &TotalInvfTime, &TotalTextTime);
+
+  Display_Stats (stderr);
+
+}
+
+
+void 
+search_for_collection (char *name)
+{
+/* [RPAP - Feb 97: WIN32 Port] */
+#ifdef __WIN32__
+  char *dir = GetDefEnv ("mgdir", ".\\");
+#else
+  char *dir = GetDefEnv ("mgdir", "./");
+#endif
+  char buffer[512];
+  struct stat stat_buf;
+  if (strrchr (dir, '/') && *(strrchr (dir, '/') + 1) != '\0')
+    {
+/* [RPAP - Feb 97: WIN32 Port] */
+#ifdef __WIN32__
+      sprintf (buffer, "%s", dir);
+#else
+      sprintf (buffer, "%s/", dir);
+#endif
+      SetEnv ("mgdir", buffer, NULL);
+      dir = GetEnv ("mgdir");
+    }
+
+  sprintf (buffer, "%s.text", name);
+  if (stat (buffer, &stat_buf) != -1)
+    {
+      if ((stat_buf.st_mode & S_IFREG) != 0)
+	{
+	  /* The name is a directory */
+	  SetEnv ("mgname", name, NULL);
+/* [RPAP - Feb 97: WIN32 Port] */
+#ifdef __WIN32__
+          SetEnv ("mgdir", ".\\", NULL);
+#else
+	  SetEnv ("mgdir", "./", NULL);
+#endif
+	  return;
+	}
+    }
+
+  sprintf (buffer, "%s%s", dir, name);
+  if (stat (buffer, &stat_buf) != -1)
+    {
+      if ((stat_buf.st_mode & S_IFDIR) != 0)
+	{
+	  /* The name is a directory */
+/* [RPAP - Feb 97: WIN32 Port] */
+#ifdef __WIN32__
+          sprintf (buffer, "%s%s", name, name);
+#else
+	  sprintf (buffer, "%s/%s", name, name);
+#endif
+	  SetEnv ("mgname", buffer, NULL);
+	  return;
+	}
+    }
+
+  /* Look in the current directory last */
+  if (stat (name, &stat_buf) != -1)
+    {
+      if ((stat_buf.st_mode & S_IFDIR) != 0)
+	{
+	  /* The name is a directory */
+/* [RPAP - Feb 97: WIN32 Port] */
+#ifdef __WIN32__
+          sprintf (buffer, "%s%s", name, name);
+          SetEnv ("mgdir", ".\\", NULL);
+#else
+	  sprintf (buffer, "%s/%s", name, name);
+          SetEnv ("mgdir", "./", NULL);
+#endif
+	  SetEnv ("mgname", buffer, NULL);
+	  return;
+	}
+    }
+
+  SetEnv ("mgname", name, NULL);
+}
+
+/* main () */
+/* Initialises global variables based on command line switches, and opens */
+/* files.  Then calls  query ()  to perform the querying. */
+int main (int argc, char **argv)
+{
+  ProgTime StartTime;
+  int decomp = 0;
+  int ch;
+
+  msg_prefix = argv[0];
+  GetTime (&StartTime);
+
+  /* Initialise the environment with default values */
+
+  InitEnv ();
+
+  read_mgrc_file ();
+
+  OutFile = stdout;
+  InFile = stdin;
+
+  opterr = 0;
+  /* [RJM 06/97: text filename] */
+  while ((ch = getopt (argc, argv, "Df:d:t:h")) != -1) {
+    switch (ch) {
+      case 'f':
+	SetEnv ("mgname", optarg, NULL);
+	break;
+      case 'd':
+	SetEnv ("mgdir", optarg, NULL);
+	break;
+      case 't': /* [RJM 06/97: text filename] */
+	SetEnv ("textname", optarg, NULL);
+	break;
+      case 'D':
+	decomp = 1;
+	break;
+      case 'h':
+      case '?':
+	fprintf (stderr, "usage: %s [-D] [-f base name of collection] "
+		 "[-t base name of files for text] " /* [RJM 06/97: text filename] */
+		 "[-d data directory] [collection]\n", argv[0]);
+	exit (1);
+    }      
+  }
+
+  PushEnv ();
+
+  if (decomp == 0)
+    {
+
+      Init_ReadLine ();
+
+      /* write a first prompt, let the user start thinking */
+      if (!BooleanEnv (GetEnv ("expert"), 0) && isatty (fileno (InFile)))
+	{
+	  fprintf (stderr, "\n\n\t     FULL TEXT RETRIEVAL QUERY PROGRAM\n");
+	  fprintf (stderr, "%24s%s\n\n", "", *"21 Mar 1994" == '%' ? __DATE__ : "21 Mar 1994");
+	  fprintf (stderr, "\n");
+	  fprintf (stderr, "  mgquery version " VERSION ", Copyright (C) 1994 Neil Sharman\n");
+	  fprintf (stderr, "  mgquery comes with ABSOLUTELY NO WARRANTY; for details type `.warranty'\n");
+	  fprintf (stderr, "  This is free software, and you are welcome to redistribute it\n");
+	  fprintf (stderr, "  under certain conditions; type `.conditions' for details.\n");
+	  fprintf (stderr, "\n");
+	}
+    }
+  if (optind < argc)
+    search_for_collection (argv[optind]);
+
+  if (decomp == 0)
+    {
+      query ();
+    }
+  else
+    {
+      int i;
+      InitQueryTimes iqt;
+      query_data *qd;
+
+/* [RPAP - Feb 97: WIN32 Port] */
+#ifdef __WIN32__
+      qd = InitQuerySystem (GetDefEnv ("mgdir", ".\\"),
+                            GetDefEnv ("mgname", ""),
+                            GetDefEnv ("textname", NULL), /* [RJM 06/97: text filename] */
+                            &iqt);
+#else
+      qd = InitQuerySystem (GetDefEnv ("mgdir", "./"),
+			    GetDefEnv ("mgname", ""),
+                            GetDefEnv ("textname", NULL), /* [RJM 06/97: text filename] */
+			    &iqt);
+#endif
+      if (!qd)
+	FatalError (1, mg_errorstrs[mg_errno], mg_error_data);
+
+
+      start_up_stats (qd, iqt);
+
+      Display_Stats (stderr);
+      for (i = 0; i < qd->td->cth.num_of_docs; i++)
+	{
+	  RawDocOutput (qd, i + 1, stdout);
+	  putc ('\2', stdout);
+	}
+      Message ("%s", ElapsedTime (&StartTime, NULL));
+
+      FinishQuerySystem (qd);
+    }
+
+  UninitEnv ();
+  return 0;
+}
Index: /main/tags/2.25/gsdl/packages/mg/src/text/mgstat.1
===================================================================
--- /main/tags/2.25/gsdl/packages/mg/src/text/mgstat.1	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/mg/src/text/mgstat.1	(revision 21064)
@@ -0,0 +1,131 @@
+.\"------------------------------------------------------------
+.\" Id - set Rv,revision, and Dt, Date using rcs-Id tag.
+.de Id
+.ds Rv \\$3
+.ds Dt \\$4
+..
+.Id $Id$
+.\"------------------------------------------------------------
+.TH mgstat 1 \*(Dt CITRI
+.SH NAME
+mgstat \- print out statistics about a document collection
+.SH SYNOPSIS
+.B mgstat
+[
+.B \-h
+]
+[
+.B \-E
+]
+[
+.BI \-d " directory"
+]
+.BI \-f " name"
+.SH DESCRIPTION
+.B mgstat
+prints out various statistics about an existing
+.BR mg (1)
+document collection.  Depending on the size of the collection, sizes
+will be printed in either kilobytes or megabytes.
+.SH OPTIONS
+Options may appear in any order.
+.TP "\w'\fB\-d\fP \fIdirectory\fP'u+2n"
+.B \-h
+This displays a usage line on
+.IR stdout .
+.TP
+.B \-E
+This option forces sizes to be printed in bytes rather than kilobytes
+or megabytes.
+.TP
+.BI \-d " directory"
+This specifies the directory where the document collection can be found.
+.TP
+.BI \-f " name"
+This specifies the base name of the document collection.
+.SH ENVIRONMENT
+.TP "\w'\fBMGDATA\fP'u+2n"
+.SB MGDATA
+If this environment variable exists, then its value is used as the
+default directory where the
+.BR mg (1)
+collection files are.  If this variable does not exist, then the
+directory \*(lq\fB.\fP\*(rq is used by default.  The command line
+option
+.BI \-d " directory"
+overrides the directory in
+.BR MGDATA .
+.SH FILES
+.TP 20
+.B *.text
+Compressed documents.
+.TP
+.B *.invf
+Inverted file.
+.TP
+.B *.text.idx.wgt
+Interleaved index into the compressed documents and document weights.
+.TP
+.B *.weight.approx
+Approximate document weights.
+.TP
+.B *.invf.dict.blocked
+Compressed stemmed dictionary and index into the inverted file merged
+into an inverted file.
+.TP
+.B *.text.dict.fast
+Fast loading compression dictionary.
+.TP
+.B *.text.dict
+Compressed compression dictionary.
+.TP
+.B *.invf.dict
+Compressed stemmed dictionary.
+.TP
+.B *.invf.idx
+The index into the inverted file.
+.TP
+.B *.text.stats
+Statistics about the text.
+.TP
+.B *.text.dict.aux
+Auxiliary compression dictionary.
+.TP
+.B *.text.idx
+Index into the compressed documents.
+.TP
+.B *.weight
+The exact weights file.
+.TP
+.B *.invf.chunk
+Maps stemmed terms from occurrence order to lexical order.
+.TP
+.B *.invf.chunk.trans
+Describes where the source text is broken up into chunks for the
+inversion pass.
+.TP
+.B *.invf.dict.hash
+A perfect hash function for the terms in the stemmed dictionary.
+.SH "SEE ALSO"
+.na
+.BR mg (1),
+.BR mg_compression_dict (1),
+.BR mg_fast_comp_dict (1),
+.BR mg_get (1),
+.BR mg_invf_dict (1),
+.BR mg_invf_dump (1),
+.BR mg_invf_rebuild (1),
+.BR mg_passes (1),
+.BR mg_perf_hash_build (1),
+.BR mg_text_estimate (1),
+.BR mg_weights_build (1),
+.BR mgbilevel (1),
+.BR mgbuild (1),
+.BR mgdictlist (1),
+.BR mgfelics (1),
+.BR mgquery (1),
+.BR mgtic (1),
+.BR mgticbuild (1),
+.BR mgticdump (1),
+.BR mgticprune (1),
+.BR mgticstat (1).
Index: /main/tags/2.25/gsdl/packages/mg/src/text/mgstat.c
===================================================================
--- /main/tags/2.25/gsdl/packages/mg/src/text/mgstat.c	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/mg/src/text/mgstat.c	(revision 21064)
@@ -0,0 +1,399 @@
+/**************************************************************************
+ *
+ * mgstat.c -- Program to generate statistics on a text collection
+ * Copyright (C) 1994  Neil Sharman
+ *
+ * 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.
+ *
+ * $Id$
+ *
+ **************************************************************************/
+
+#include "sysfuncs.h"
+
+#include "netorder.h"  /* [RPAP - Jan 97: Endian Ordering] */
+
+#include "mg_files.h"
+#include "locallib.h"
+#include "mg.h"
+#include "words.h"
+#include "invf.h"
+#include "text.h"
+
+
+/*
+   $Log$
+   Revision 1.1  1999/08/10 21:18:19  sjboddie
+   renamed mg-1.3d directory mg
+
+   Revision 1.2  1998/11/25 07:55:50  rjmcnab
+
+   Modified mg to that you can specify the stemmer you want
+   to use via a command line option. You specify it to
+   mg_passes during the build process. The number of the
+   stemmer that you used is stored within the inverted
+   dictionary header and the stemmed dictionary header so
+   the correct stemmer is used in later stages of building
+   and querying.
+
+   Revision 1.1  1998/11/17 09:35:31  rjmcnab
+   *** empty log message ***
+
+   * Revision 1.2  1994/09/20  04:41:59  tes
+   * For version 1.1
+   *
+ */
+
+static char *RCSID = "$Id$";
+
+char *search_for_collection (char *name);
+int process_file (char *, char *, int);
+void ProcessDict (char *);
+void ProcessStem (char *);
+long ProcessStemBlk (char *name);  /* [RPAP - Jan 97: Stem Index Change] */
+
+static double inputbytes = 0.0; /* [RJM 07/97: 4G limit] */
+static unsigned long total = 0;
+
+
+
+
+
+int main (int argc, char **argv)
+{
+  unsigned long sub_total;
+  int fast;
+  char *file_name = "";
+  int ch;
+  int exact = 0;
+  long indexed = 0; /* [RPAP - Jan 97: Stem Index Change] */
+  opterr = 0;
+  while ((ch = getopt (argc, argv, "Ehf:d:")) != -1)
+    switch (ch)
+      {
+      case 'E':
+	exact = 1;
+	break;
+      case 'f':		/* input file */
+	file_name = optarg;
+	break;
+      case 'd':
+	set_basepath (optarg);
+	break;
+      case 'h':
+      case '?':
+	fprintf (stderr, "usage: %s [-f input_file]"
+		 "[-d data directory] [-h]\n", argv[0]);
+	exit (1);
+      }
+
+  if (optind < argc)
+    file_name = search_for_collection (argv[optind]);
+
+  ProcessDict (file_name);
+  ProcessStem (file_name);
+  indexed = ProcessStemBlk (file_name); /* [RPAP - Jan 97: Stem Index Change] */
+
+  {
+    char Name[256];
+    char *s;
+    sprintf (Name, FILE_NAME_FORMAT, get_basepath (), file_name, "");
+    s = strrchr (Name, '/');
+    if (s)
+      *s = '\0';
+    printf ("\nThe collection is in \"%s\"\n", Name);
+  }
+
+
+  printf ("\n\t\tFiles required by mgquery\n");
+  process_file (file_name, TEXT_SUFFIX, exact);
+  process_file (file_name, INVF_SUFFIX, exact);
+  process_file (file_name, TEXT_IDX_WGT_SUFFIX, exact);
+  process_file (file_name, APPROX_WEIGHTS_SUFFIX, exact);
+  process_file (file_name, INVF_DICT_BLOCKED_SUFFIX, exact);
+
+  /* [RPAP - Jan 97: Stem Index Change] */
+  if (indexed)
+    {
+      process_file (file_name, INVF_DICT_BLOCKED_1_SUFFIX, exact);
+      process_file (file_name, INVF_DICT_BLOCKED_2_SUFFIX, exact);
+      process_file (file_name, INVF_DICT_BLOCKED_3_SUFFIX, exact);
+    }
+
+  fast = process_file (file_name, TEXT_DICT_FAST_SUFFIX, exact);
+  if (!fast)
+    {
+      process_file (file_name, TEXT_DICT_SUFFIX, exact);
+      process_file (file_name, TEXT_DICT_AUX_SUFFIX, exact);
+    }
+
+
+  process_file (NULL, "SUB TOTAL", exact);
+  sub_total = total;
+  total = 0;
+
+  printf ("\n\t\tFiles NOT required by mgquery\n");
+  if (fast)
+    {
+      process_file (file_name, TEXT_DICT_SUFFIX, exact);
+      process_file (file_name, TEXT_DICT_AUX_SUFFIX, exact);
+    }
+  process_file (file_name, INVF_DICT_SUFFIX, exact);
+  process_file (file_name, INVF_IDX_SUFFIX, exact);
+  process_file (file_name, TEXT_STATS_DICT_SUFFIX, exact);
+  process_file (file_name, TEXT_IDX_SUFFIX, exact);
+  process_file (file_name, WEIGHTS_SUFFIX, exact);
+  process_file (file_name, INVF_CHUNK_SUFFIX, exact);
+  process_file (file_name, INVF_CHUNK_TRANS_SUFFIX, exact);
+  process_file (file_name, INVF_DICT_HASH_SUFFIX, exact);
+  process_file (file_name, INVF_PARAGRAPH_SUFFIX, exact);
+  process_file (NULL, "SUB TOTAL", exact);
+  total += sub_total;
+  printf ("\n");
+  process_file (NULL, "TOTAL", exact);
+
+  return 0;
+}
+
+
+
+char *
+search_for_collection (char *name)
+{
+  char *dir = get_basepath ();
+  static char buffer[512];
+  struct stat stat_buf;
+
+  /* Look in the current directory first */
+  if (stat (name, &stat_buf) != -1)
+    {
+      if (S_ISDIR(stat_buf.st_mode))
+	{
+	  /* The name is a directory */
+	  sprintf (buffer, "%s/%s", name, name);
+	  set_basepath (".");
+	  return buffer;
+	}
+    }
+
+  sprintf (buffer, "%s.text", name);
+  if (stat (buffer, &stat_buf) != -1)
+    {
+      if (S_ISREG(stat_buf.st_mode))
+	{
+	  /* The name is a directory */
+	  set_basepath (".");
+	  return name;
+	}
+    }
+  sprintf (buffer, "%s/%s", dir, name);
+  if (stat (buffer, &stat_buf) != -1)
+    {
+      if (S_ISDIR(stat_buf.st_mode))
+	{
+	  /* The name is a directory */
+	  sprintf (buffer, "%s/%s", name, name);
+	  return buffer;
+	}
+    }
+  return name;
+}
+
+
+
+
+
+
+void 
+ProcessDict (char *name)
+{
+  FILE *f;
+  compression_dict_header cdh;
+  int have_cdh = 0;
+  compressed_text_header cth;
+  int have_cth = 0;
+
+  if ((f = open_file (name, TEXT_DICT_SUFFIX, "rb", MAGIC_DICT, MG_MESSAGE)))  /* [RPAP - Feb 97: WIN32 Port] */
+    {
+      Read_cdh (f, &cdh, NULL, NULL);
+      fclose (f);
+      have_cdh = 1;
+    }
+
+  if ((f = open_file (name, TEXT_SUFFIX, "rb", MAGIC_TEXT, MG_MESSAGE)))  /* [RPAP - Feb 97: WIN32 Port] */
+    {
+      fread ((char *) &cth, sizeof (cth), 1, f);
+
+      /* [RPAP - Jan 97: Endian Ordering] */
+      NTOHUL(cth.num_of_docs);
+      NTOHD(cth.num_of_bytes); /* [RJM 07/97: 4G limit] */
+      NTOHUL(cth.num_of_words);
+      NTOHUL(cth.length_of_longest_doc);
+      NTOHD(cth.ratio);
+
+      fclose (f);
+      have_cth = 1;
+    }
+
+  if (have_cth)
+    {
+      inputbytes = cth.num_of_bytes;
+      printf ("Input bytes                        : %10.0f, %8.2f Mbyte\n",
+	      cth.num_of_bytes, cth.num_of_bytes / 1024.0 / 1024.0); /* [RJM 07/97: 4G limit] */
+      printf ("Documents                          : %10lu\n", cth.num_of_docs);
+      printf ("Words in collection [dict]         : %10lu\n", cth.num_of_words);
+      printf ("Longest doc in collection [dict]   : %10lu characters\n",
+	      cth.length_of_longest_doc);
+      printf ("Maximum ratio                      : %10.2f\n", cth.ratio);
+    }
+
+  if (have_cdh)
+    {
+      printf ("Words in dict                      : %10lu\n", cdh.num_words[1]);
+      printf ("Non-words in dict                  : %10lu\n", cdh.num_words[0]);
+      printf ("Total chars of distinct words      : %10lu\n", cdh.num_word_chars[1]);
+      printf ("Total chars of distinct non-words  : %10lu\n", cdh.num_word_chars[0]);
+    }
+
+}
+
+
+
+
+
+
+
+
+void 
+ProcessStem (char *name)
+{
+  FILE *f;
+  struct invf_dict_header idh;
+
+  if (!(f = open_file (name, INVF_DICT_SUFFIX, "rb",
+		       MAGIC_STEM_BUILD, MG_MESSAGE)))  /* [RPAP - Feb 97: WIN32 Port] */
+    return;
+  fread ((char *) &idh, sizeof (idh), 1, f);
+  printf ("Words in collection [stem]         : %10ld\n", NTOHUL(idh.num_of_words));  /* [RPAP - Jan 97: Endian Ordering] */
+  printf ("Words in stem                      : %10ld\n", NTOHUL(idh.dict_size));  /* [RPAP - Jan 97: Endian Ordering] */
+  printf ("Indexed fragments                  : %10ld\n", NTOHUL(idh.num_of_docs));  /* [RPAP - Jan 97: Endian Ordering] */
+  printf ("Total chars of stem words          : %10ld\n", NTOHUL(idh.total_bytes));  /* [RPAP - Jan 97: Endian Ordering] */
+  fclose (f);
+}
+
+
+
+
+
+/* [RPAP - Jan 97: Stem Index Change] */
+long 
+ProcessStemBlk (char *name)
+{
+  FILE *f;
+  struct stem_dict_header sdh;
+
+  if (!(f = open_file (name, INVF_DICT_BLOCKED_SUFFIX, "rb",
+		       MAGIC_STEM, MG_MESSAGE)))  /* [RPAP - Feb 97: WIN32 Port] */
+    return 0;
+  fread ((char *) &sdh, sizeof (sdh), 1, f);
+  fclose (f);
+  return NTOHUL(sdh.indexed);  /* [RPAP - Jan 97: Endian Ordering] */
+}
+
+
+
+
+int 
+process_file (char *name, char *ext, int exact)
+{
+  static double scale = 0;
+  static char *units;
+  struct stat buf;
+  if (scale == 0)
+    {
+      /* So can get output in Mb or Kb, */
+      /* will divide by a scale of 1024(Kb) or 1024*1024(Mb) */
+      /* Note: if inputbytes==0, then use 1024 as default */
+      scale = inputbytes > 10 * 1000 * 1000 ? 1024 * 1024 : 1024;
+      units = scale == 1024 ? "Kb" : "Mb";
+    }
+  if (name)
+    {
+      char Name[256];
+      sprintf (Name, FILE_NAME_FORMAT, get_basepath (), name, ext);
+      if (!stat (Name, &buf))
+	{
+	  char fname[256];
+	  char *nam = strrchr (name, '/');
+	  nam = nam ? nam + 1 : name;
+	  sprintf (fname, "%s%s", nam, ext);
+
+	  if (inputbytes == 0.0)
+	    {
+	      if (exact)
+		printf ("%s%*s: %10ld bytes   %7.3f%%\n", fname,
+			35 - (int) strlen (fname), "",
+			buf.st_size,
+			100.0 * buf.st_size / inputbytes);
+	      else
+		printf ("%s%*s: %8.2f %s   %7.3f%%\n", fname,
+			35 - (int) strlen (fname), "",
+			buf.st_size / scale,
+			units,
+			100.0 * buf.st_size / inputbytes);
+	    }
+	  else
+	    {
+	      if (exact)
+		printf ("%s%*s: %10ld bytes\n", fname,
+			35 - (int) strlen (fname), "",
+			buf.st_size);
+	      else
+		printf ("%s%*s: %8.2f %s\n", fname,
+			35 - (int) strlen (fname), "",
+			buf.st_size / scale,
+			units);
+	    }
+	  total += buf.st_size;
+	  return 1;
+	}
+      else
+	return 0;
+    }
+  else
+    {
+      if (inputbytes == 0.0)
+	{
+	  if (exact)
+	    printf ("%-34s : %10ld bytes   %7.3f%%\n", ext,
+		    total,
+		    100.0 * total / inputbytes);
+	  else
+	    printf ("%-34s : %8.2f %s   %7.3f%%\n", ext,
+		    total / scale, units,
+		    100.0 * total / inputbytes);
+	}
+      else
+	{
+	  if (exact)
+	    printf ("%-34s : %10ld bytes\n", ext, total);
+	  else
+	    printf ("%-34s : %8.2f %s\n", ext,
+		    total / scale, units);
+	}
+    }
+  return 1;
+
+}
Index: /main/tags/2.25/gsdl/packages/mg/src/text/mgstemidxlist.1
===================================================================
--- /main/tags/2.25/gsdl/packages/mg/src/text/mgstemidxlist.1	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/mg/src/text/mgstemidxlist.1	(revision 21064)
@@ -0,0 +1,86 @@
+.\"------------------------------------------------------------
+.\" Id - set Rv,revision, and Dt, Date using rcs-Id tag.
+.de Id
+.ds Rv \\$3
+.ds Dt \\$4
+..
+.Id $Id$
+.\"------------------------------------------------------------
+.TH mgstemidxlist 1 \*(Dt CITRI
+.SH NAME
+mgstemidxlist \- dumps the stem index file to STDOUT in ASCII format
+.SH SYNOPSIS
+.B mgstemidxlist
+[
+.B \-h
+]
+[
+.BI \-d " directory"
+]
+.B \-s 1|2|3
+.BI \-f " name"
+.SH DESCRIPTION
+.B mgstemidxlist
+is a utility program which passes through the stem index and displays
+the information.  (This program was used for debugging but is included
+for completeness!)  The header information is printed out, then for each
+block in the file the block header is displayed.  For each word in the
+stem index, the output is formatted as:
+
+.RS
+.I number_of_references \*(lqword\*(rq
+.br
+.RS
+.I "->  number_of_cases block 3-in-4_block offset"
+.br
+.I "->  ..."
+.RE
+.RE
+.SH OPTIONS
+Options may appear in any order.
+.TP "\w'\fB\-d\fP \fIdirectory\fP'u+2n"
+.B \-h
+This displays a usage line on
+.IR stderr .
+.TP
+.B -s 1|2|3
+The stem index file with the associated stem method.
+.br
+1 = casefolded and non-stemmed
+.br
+2 = non-casefolded and stemmed
+.br
+3 = casefolded and stemmed
+.TP
+.BI \-d " directory"
+This specifies the directory where the document collection can be found.
+.TP
+.BI \-f " name"
+This specifies the base name of the document collection.
+.SH ENVIRONMENT
+.TP "\w'\fBMGDATA\fP'u+2n"
+.SB MGDATA
+If this environment variable exists, then its value is used as the
+default directory where the
+.BR mg (1)
+collection files are.  If this variable does not exist, then the
+directory \*(lq\fB.\fP\*(rq is used by default.  The command line
+option
+.BI \-d " directory"
+overrides the directory in
+.BR MGDATA .
+.SH FILES
+.TP 25
+.B *.invf.dict.blocked.1
+Stem index with stem index method 1.
+.TP
+.B *.invf.dict.blocked.2
+Stem index with stem index method 2.
+.TP
+.B *.invf.dict.blocked.3
+Stem index with stem index method 3.
+.SH "SEE ALSO"
+.na
+.BR mg (1),
+.BR mg_invf_dict (1),
+.BR mg_stem_idx (1).
Index: /main/tags/2.25/gsdl/packages/mg/src/text/mgstemidxlist.c
===================================================================
--- /main/tags/2.25/gsdl/packages/mg/src/text/mgstemidxlist.c	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/mg/src/text/mgstemidxlist.c	(revision 21064)
@@ -0,0 +1,245 @@
+/**************************************************************************
+ *
+ * mgstemidxlist.c -- Text dumper for the stem indexes
+ * Copyright (C) 1997  Ross Peeters
+ *
+ * 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.
+ *
+ **************************************************************************/
+
+#include "sysfuncs.h"
+
+#include "messages.h"
+#include "memlib.h"
+#include "local_strings.h"
+#include "netorder.h"  /* [RPAP - Jan 97: Endian Ordering] */
+
+#include "mg_files.h"
+#include "mg.h"
+#include "invf.h"
+#include "words.h"
+#include "backend.h"
+
+void
+read_3_in_4 (FILE * idbi)
+{
+  unsigned long i;
+  stemmed_idx *si;
+  u_char *buffer;
+  int block = 0;
+
+  if (!(si = Xmalloc (sizeof (stemmed_idx))))
+    {
+      return;
+    }
+
+  si->MemForStemIdx = 0;
+
+  fread (&(si->sih), sizeof (si->sih), 1, idbi);
+
+  /* [RPAP - Jan 97: Endian Ordering] */
+  NTOHUL(si->sih.lookback);
+  NTOHUL(si->sih.block_size);
+  NTOHUL(si->sih.num_blocks);
+  NTOHUL(si->sih.blocks_start);
+  NTOHUL(si->sih.index_chars);
+  NTOHUL(si->sih.num_of_words);
+
+  if (!(buffer = Xmalloc (si->sih.index_chars)))
+    {
+      Xfree (si);
+      return;
+    };
+  si->MemForStemIdx += si->sih.index_chars;
+
+  if (!(si->index = Xmalloc (si->sih.num_blocks * sizeof (*si->index))))
+    {
+      Xfree (si);
+      Xfree (buffer);
+      return;
+    };
+  si->MemForStemIdx += si->sih.num_blocks * sizeof (*si->index);
+
+  if (!(si->pos = Xmalloc (si->sih.num_blocks * sizeof (*si->pos))))
+    {
+      Xfree (si->index);
+      Xfree (si);
+      Xfree (buffer);
+      return;
+    };
+  si->MemForStemIdx += si->sih.num_blocks * sizeof (*si->pos);
+
+  if (!(si->buffer = Xmalloc (si->sih.block_size * sizeof (*si->buffer))))
+    {
+      Xfree (buffer);
+      Xfree (si->index);
+      Xfree (si->buffer);
+      Xfree (si);
+      return;
+    };
+  si->MemForStemIdx += si->sih.block_size * sizeof (*si->buffer);
+
+  si->active = -1;
+
+  for (i = 0; i < si->sih.num_blocks; i++)
+    {
+      register u_char len;
+      si->index[i] = buffer;
+      len = fgetc (idbi);
+      *buffer++ = len;
+      fread (buffer, sizeof (u_char), len, idbi);
+      buffer += len;
+      fread (&si->pos[i], sizeof (*si->pos), 1, idbi);
+      NTOHUL(si->pos[i]);  /* [RPAP - Jan 97: Endian Ordering] */
+    }
+
+  printf ("# lookback     = %lu\n", si->sih.lookback);
+  printf ("# block_size   = %lu\n", si->sih.block_size);
+  printf ("# num_blocks   = %lu\n", si->sih.num_blocks);
+  printf ("# blocks_start = %lu\n", si->sih.blocks_start);
+  printf ("# index_chars  = %lu\n", si->sih.index_chars);
+  printf ("# num_of_words = %lu\n", si->sih.num_of_words);
+
+  block = 0;
+  while (block < si->sih.num_blocks)
+    {
+      unsigned long *first_word;
+      unsigned short *num_words;
+      unsigned short *index;
+      long res;
+      u_char *base;
+      int num_indexes;
+
+      /* Read in next block */
+      fseek (idbi, si->pos[block] + si->sih.blocks_start, 0);
+      fread (si->buffer, si->sih.block_size, sizeof (u_char), idbi);
+      si->active = si->pos[block];
+
+      first_word = (unsigned long *) (si->buffer);
+      NTOHUL(*first_word);  /* [RPAP - Jan 97: Endian Ordering] */
+      num_words = (unsigned short *) (first_word + 1);
+      NTOHUS(*num_words);  /* [RPAP - Jan 97: Endian Ordering] */
+      index = num_words + 1;
+      num_indexes = ((*num_words - 1) / si->sih.lookback) + 1;
+
+      /* [RPAP - Jan 97: Endian Ordering] */
+      for (i = 0; i < num_indexes; i++)
+	NTOHUS(index[i]);
+
+      base = (u_char *) (index + num_indexes);
+      base += index[0];
+
+      printf ("\n# block      = %d\n", block);
+      printf ("# first_word = %lu\n", *first_word);
+      printf ("# num_words  = %u\n", *num_words);
+
+      res = 0;
+      while (res < *num_words)
+	{
+	  unsigned copy, suff;
+	  u_char prev[MAXSTEMLEN + 1];
+	  unsigned int num_entries, num_cases, blk;
+	  unsigned short blk_index, offset;
+
+	  /* Read word entry */
+	  copy = *base++;
+	  suff = *base++;
+	  bcopy ((char *) base, (char *) (prev + copy + 1), suff);
+	  *prev = copy + suff;
+	  base += suff;
+	  bcopy ((char *) base, (char *) &num_entries, sizeof (num_entries));
+	  base += sizeof (num_entries);
+	  NTOHUI(num_entries);  /* [RPAP - Jan 97: Endian Ordering] */
+	  printf ("%u \"%s\"\n", num_entries, word2str (prev));
+
+	  /* For all the PosEntries for the word... */
+	  for (i = 0; i < num_entries; i++)
+	    {
+	      bcopy ((char *) base, (char *) &num_cases, sizeof (num_cases));
+	      NTOHUI(num_cases);  /* [RPAP - Jan 97: Endian Ordering] */
+	      base += sizeof (num_cases);
+	      bcopy ((char *) base, (char *) &blk, sizeof (blk));
+	      NTOHUI(blk);  /* [RPAP - Jan 97: Endian Ordering] */
+	      base += sizeof (blk);
+	      bcopy ((char *) base, (char *) &blk_index, sizeof (blk_index));
+	      NTOHUS(blk_index);  /* [RPAP - Jan 97: Endian Ordering] */
+	      base += sizeof (blk_index);
+	      bcopy ((char *) base, (char *) &offset, sizeof (offset));
+	      NTOHUS(offset);  /* [RPAP - Jan 97: Endian Ordering] */
+	      base += sizeof (offset);
+
+	      printf ("    -> %4u %4u %4u %4u\n", num_cases, blk, blk_index, offset);
+	    }
+	  res++;
+	}
+      block++;
+    }
+  fclose (idbi);
+}
+
+int
+main (int argc, char **argv)
+{
+  FILE *idbi;
+  char *filename = "";
+  int ch;
+  int stem_method = 0;
+
+  msg_prefix = argv[0];
+  opterr = 0;
+  while ((ch = getopt (argc, argv, "f:d:hs:")) != -1)
+    switch (ch)
+      {
+      case 'f':		/* input file */
+	filename = optarg;
+	break;
+      case 'd':
+	set_basepath (optarg);
+	break;
+      case 's':
+	stem_method = atoi (optarg);
+	break;
+      case 'h':
+      case '?':
+	fprintf (stderr, "usage: %s [-d data directory] [-h] -s 1|2|3 -f name\n", argv[0]);
+	exit (1);
+      }
+
+  /* Open required files */
+  switch (stem_method)
+    {
+    case (1):
+      idbi = open_file (filename, INVF_DICT_BLOCKED_1_SUFFIX, "rb", MAGIC_STEM_1,
+			MG_ABORT);
+      break;
+    case (2):
+      idbi = open_file (filename, INVF_DICT_BLOCKED_2_SUFFIX, "rb", MAGIC_STEM_2,
+			MG_ABORT);
+      break;
+    case (3):
+      idbi = open_file (filename, INVF_DICT_BLOCKED_3_SUFFIX, "rb", MAGIC_STEM_3,
+			MG_ABORT);
+      break;
+    default:
+      FatalError (1, "Stem method must be 1, 2 or 3\n");
+    }
+
+  if (!idbi)
+    FatalError (1, "Could NOT open file");
+
+  read_3_in_4 (idbi);
+
+  return 0;
+}
Index: /main/tags/2.25/gsdl/packages/mg/src/text/query.docnums.c
===================================================================
--- /main/tags/2.25/gsdl/packages/mg/src/text/query.docnums.c	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/mg/src/text/query.docnums.c	(revision 21064)
@@ -0,0 +1,100 @@
+/**************************************************************************
+ *
+ * query.docnums.c -- Docnums query evaluation
+ * Copyright (C) 1994  Neil Sharman
+ *
+ * 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.
+ *
+ * $Id$
+ *
+ **************************************************************************/
+
+#include "sysfuncs.h"
+#include "filestats.h"
+#include "timing.h"
+
+#include "mg.h"
+#include "invf.h"
+#include "text.h"
+#include "lists.h"
+#include "backend.h"
+
+
+static DocList *
+AddToDocList (DocList * Docs, int res)
+{
+  int j;
+  /* Search the list for the word */
+  for (j = 0; j < Docs->num; j++)
+    if (Docs->DE[j].DocNum == res)
+      break;
+
+  /* Increment the weight if the word is in the list */
+  if (j < Docs->num)
+    Docs->DE[j].Weight++;
+  else
+    {
+      /* Create a new entry in the list for the new document */
+      Docs = ResizeDocList (Docs, Docs->num + 1);
+      Docs->DE[Docs->num].DocNum = res;
+      Docs->DE[Docs->num].Weight = 1;
+      Docs->DE[Docs->num].SeekPos = 0;
+      Docs->DE[Docs->num].Len = 0;
+      Docs->DE[Docs->num].CompTextBuffer = NULL;
+      Docs->DE[Docs->num].Next = NULL;
+      Docs->num++;
+    }
+  return (Docs);
+}
+
+void 
+DocnumsQuery (query_data * qd, char *QueryLine)
+{
+  DocList *Docs = MakeDocList (0);
+  unsigned long start = 0, finish;
+  int range = 0; /* is there a range or not ? */
+
+  /* find the start of the first word */
+  while (*QueryLine)
+    {
+      char *end;
+      finish = strtol (QueryLine, &end, 10);
+      if (end != (char *) QueryLine && finish >= 1 &&
+	  finish <= qd->sd->sdh.num_of_docs)
+	{
+	  unsigned long i;
+	  if (!range)
+	    start = finish;
+	  else
+	    range = 0;
+	  for (i = start; i <= finish; i++)
+	    Docs = AddToDocList (Docs, i);
+	  while (*end == ' ' || *end == '\t' || *end == '\n')
+	    end++;
+	  if (*end == '-')
+	    {
+	      start = finish;
+	      range = 1;
+	      end++;
+	    }
+	}
+      else
+	break;
+      QueryLine = end;
+    }
+  FreeQueryDocs (qd);
+
+  qd->DL = Docs;
+}
Index: /main/tags/2.25/gsdl/packages/mg/src/text/query.ranked.c
===================================================================
--- /main/tags/2.25/gsdl/packages/mg/src/text/query.ranked.c	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/mg/src/text/query.ranked.c	(revision 21064)
@@ -0,0 +1,991 @@
+/**************************************************************************
+ *
+ * query.ranked.c -- Ranked query evaluation
+ * Copyright (C) 1994  Neil Sharman
+ *
+ * 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.
+ *
+ * $Id$
+ *
+ **************************************************************************/
+
+#include "sysfuncs.h"
+
+#include "memlib.h"
+#include "filestats.h"
+#include "messages.h"
+#include "timing.h"
+#include "sptree.h"
+
+#include "mg.h"
+#include "invf.h"
+#include "text.h"
+#include "lists.h"
+#include "backend.h"
+#include "stem_search.h"
+#include "weights.h"
+#include "text_get.h"
+#include "invf_get.h"
+#include "words.h"
+#include "stemmer.h"
+#include "locallib.h"
+#include "environment.h"
+#include "term_lists.h"
+#include "local_strings.h"
+#include "query_term_list.h"  /* [RPAP - Feb 97: Term Frequency] */
+
+/*
+   $Log$
+   Revision 1.1  1999/08/10 21:18:20  sjboddie
+   renamed mg-1.3d directory mg
+
+   Revision 1.2  1998/11/25 07:55:50  rjmcnab
+
+   Modified mg to that you can specify the stemmer you want
+   to use via a command line option. You specify it to
+   mg_passes during the build process. The number of the
+   stemmer that you used is stored within the inverted
+   dictionary header and the stemmed dictionary header so
+   the correct stemmer is used in later stages of building
+   and querying.
+
+   Revision 1.1  1998/11/17 09:35:34  rjmcnab
+   *** empty log message ***
+
+   * Revision 1.4  1994/11/25  03:47:46  tes
+   * Committing files before adding the merge stuff.
+   *
+   * Revision 1.3  1994/10/20  03:57:03  tes
+   * I have rewritten the boolean query optimiser and abstracted out the
+   * components of the boolean query.
+   *
+   * Revision 1.2  1994/09/20  04:42:04  tes
+   * For version 1.1
+   *
+ */
+
+static char *RCSID = "$Id$";
+
+/*************************************************************************/
+
+typedef struct HeapEntry
+  {
+    float Weight;
+    float *OrgWeight;
+    int DocNum;
+    u_long SeekPos;		/* position in the text file in bytes */
+    u_long Len;			/* length of the document in bytes */
+  }
+HeapEntry;
+
+typedef int (*HeapComp) (HeapEntry *, HeapEntry *);
+
+typedef struct Heap
+  {
+    int NumItems;
+    int MaxSize;
+    HeapComp HC;
+    HeapEntry HE[1];
+  }
+Heap;
+
+
+Heap *
+Heap_Make (int size, HeapComp hc)
+{
+  Heap *H;
+  H = Xmalloc (sizeof (Heap) + (size - 1) * sizeof (HeapEntry));
+  if (!H)
+    return NULL;
+  H->NumItems = 0;
+  H->MaxSize = size;
+  H->HC = hc;
+  return H;
+}
+
+int 
+Heap_Size (Heap * H)
+{
+  return sizeof (Heap) + H->MaxSize * sizeof (HeapEntry);
+}
+
+HeapEntry *
+Heap_GetHead (Heap * H)
+{
+  if (H && H->NumItems)
+    return &H->HE[0];
+  else
+    return NULL;
+}
+
+
+
+void 
+Heap_Heapify (Heap * H, int i)
+{
+  register int curr, child;
+  curr = i;
+  child = curr * 2;
+  while (child <= H->NumItems)
+    {
+      if (child < H->NumItems && H->HC (&H->HE[child], &H->HE[child - 1]) > 0)
+	child++;
+      if (H->HC (&H->HE[curr - 1], &H->HE[child - 1]) < 0)
+	{
+	  HeapEntry temp = H->HE[child - 1];
+	  H->HE[child - 1] = H->HE[curr - 1];
+	  H->HE[curr - 1] = temp;
+	  curr = child;
+	  child = 2 * child;
+	}
+      else
+	break;
+    }
+}
+
+
+void 
+Heap_Build (Heap * H)
+{
+  register int i;
+  for (i = H->NumItems / 2; i > 0; i--)
+    Heap_Heapify (H, i);
+}
+
+
+void 
+Heap_Sort (Heap * H)
+{
+  register int i;
+  for (i = H->NumItems; i > 1; i--)
+    {
+      HeapEntry temp = H->HE[0];
+      H->HE[0] = H->HE[i - 1];
+      H->HE[i - 1] = temp;
+      H->NumItems--;
+      Heap_Heapify (H, 1);
+    }
+}
+
+
+void 
+Heap_DeleteHead (Heap * H)
+{
+  H->HE[0] = H->HE[--H->NumItems];
+  Heap_Heapify (H, 1);
+}
+
+int 
+Heap_Lesser (HeapEntry * a, HeapEntry * b)
+{
+  return (a->Weight > b->Weight ? -1 :
+	  (a->Weight == b->Weight ? 0 : 1));
+}
+
+
+int 
+Heap_Greater (HeapEntry * a, HeapEntry * b)
+{
+  return (a->Weight > b->Weight ? 1 :
+	  (a->Weight == b->Weight ? 0 : -1));
+}
+
+int 
+Make_Exact_Root (query_data * qd, Heap * H)
+{
+  int num = 0;
+  HeapEntry *he = H->HE;
+  while (he->SeekPos == 0)
+    {
+      he->Weight = he->Weight *
+	GetLowerApproxDocWeight (qd->awd, he->DocNum - 1) /
+	FetchDocStart (qd, he->DocNum, &he->SeekPos, &he->Len);
+      Heap_Heapify (H, 1);
+      num++;
+    }
+  return num;
+}
+
+void 
+Heap_Dump (Heap * H, int num)
+{
+  int i, l, lines, r;
+  if (num > H->NumItems)
+    num = H->NumItems;
+  lines = (num + 3) / 4;
+  for (l = 0; l < lines; l++)
+    for (r = 0; r < 4; r++)
+      {
+	i = lines * r + l;
+	if (i < num)
+	  fprintf (stderr, "[%2d] %7.4f", i, H->HE[i].Weight);
+	fprintf (stderr, r == 3 ? "\n" : "        ");
+      }
+  fprintf (stderr, "\n");
+}
+
+/*************************************************************************/
+
+
+
+
+
+
+int 
+doc_count_comp (const void *A, const void *B)
+{
+  const TermEntry *a = A;
+  const TermEntry *b = B;
+  return (a->WE.doc_count - b->WE.doc_count);
+}
+
+/* =========================================================================
+ * Function: ParseRankedQuery
+ * Description:
+ *      Takes a string query line and extracts the terms in the query
+ *      which exist in the stemmed dictionary.
+ *      Optionally sorts the terms into ascending order by doc. number.
+ * Input:
+ *      stemmed dictionary, query line, sort-flag
+ * Output:
+ *      A list of terms.
+ * ========================================================================= */
+
+/* [RPAP - Jan 97: Stem Index Change] */
+static TermList *
+ParseRankedQuery (stemmed_dict * sd, char *QueryLine, int Sort, int indexed,
+		  QueryTermList **query_term_list)  /* [RPAP - Feb 97: Term Frequency] */
+{
+  u_char Word[MAXSTEMLEN + 1];
+  u_char sWord[MAXSTEMLEN + 1];
+  u_char *end, *s_in;
+  int default_stem_method = 0;
+  TermList *Terms = MakeTermList(0);
+
+  s_in = (u_char *) QueryLine;
+  end = s_in + strlen ((char *) s_in) - 1;
+  *query_term_list = MakeQueryTermList(0);  /* [RPAP - Feb 97: Term Frequency] */
+
+  if (indexed)
+    default_stem_method = BooleanEnv (GetEnv ("casefold"), 0) | (BooleanEnv (GetEnv ("stem"), 0) << 1);
+  else
+    default_stem_method = sd->sdh.stem_method;
+
+  while (s_in <= end)
+    {
+      int j;
+      long num_entries, word_num;
+      unsigned long count, doc_count, invf_ptr, invf_len;
+      int weight_to_apply, stem_to_apply;
+      int method_using = -1;
+
+      /* 0=optional, 1=mustmatch */
+      int require_match = 0; /* [RJM 07/97: Ranked Required Terms] */
+
+      /* Skip over the non word separator taking note of any parameters */
+      PARSE_RANKED_NON_STEM_WORD (require_match, s_in, end); /* [RJM 07/97: Ranked Required Terms] */
+      if (s_in > end) break;
+
+      /* Get a word and stem it */
+      PARSE_STEM_WORD (Word, s_in, end);
+
+      /* Extract any parameters */
+      weight_to_apply = 1;
+      stem_to_apply = default_stem_method;
+      while (s_in <= end)
+	{
+	  int stem_param, weight_param, param_type;
+	  char param[MAXPARAMLEN + 1];
+
+	  param_type = 0;
+	  PARSE_OPT_TERM_PARAM (param, param_type, s_in, end);
+	  if (!param_type)
+	    break;
+
+	  switch (param_type)
+	    {
+	    case (WEIGHTPARAM):
+	      weight_param = atoi (param);
+	      if (errno != ERANGE && weight_param > 0)
+		weight_to_apply = weight_param;
+	      break;
+
+	    case (STEMPARAM):
+	      stem_param = atoi (param);
+	      if (errno != ERANGE && indexed && stem_param >= 0 && stem_param <= 3)
+		method_using = stem_to_apply = stem_param;
+	      break;
+	    }
+	}
+
+      bcopy ((char *) Word, (char *) sWord, *Word + 1);
+      stemmer (stem_to_apply, sd->sdh.stemmer_num, sWord);
+
+      if (!indexed || stem_to_apply == 0)
+	{
+	  /* Look for the word in the already identified terms */
+	  for (j = 0; j < Terms->num; j++)
+	    if (compare (Terms->TE[j].Word, Word) == 0)
+	      break;
+
+	  /* Increment the weight if the word is in the list */
+	  /* Update the require match attribute */
+	  if (j < Terms->num)
+	    {
+	      Terms->TE[j].Count = ((Terms->TE[j].Count + weight_to_apply > INT_MAX) ?
+				    INT_MAX : (Terms->TE[j].Count + weight_to_apply));
+	      Terms->TE[j].require_match = require_match; /* [RJM 07/97: Ranked Require match] */
+	      AddQueryTerm (query_term_list, Word, Terms->TE[j].WE.count, method_using);  /* [RPAP - Feb 97: Term Frequency] */
+	    }
+	  else
+	    {
+	      /* Look for it in the stemmed dictionary */
+	      if ((word_num = FindWord (sd, sWord, &count, &doc_count,
+					&invf_ptr, &invf_len)) != -1)
+		{
+		  /* Search the list for the word */
+		  for (j = 0; j < Terms->num; j++)
+		    if (Terms->TE[j].WE.word_num == word_num)
+		      break;
+
+		  /* Increment the weight if the word is in the list */
+		  if (j < Terms->num)
+		    {
+		      Terms->TE[j].Count = ((Terms->TE[j].Count + weight_to_apply > INT_MAX) ?
+					    INT_MAX : (Terms->TE[j].Count + weight_to_apply));
+		      Terms->TE[j].require_match = require_match; /* [RJM 07/97: Ranked Require match] */
+		      AddQueryTerm (query_term_list, Word, Terms->TE[j].WE.count, method_using);  /* [RPAP - Feb 97: Term Frequency] */
+		    }
+		  else
+		    {
+		      /* Create a new entry in the list for the new word */
+		      TermEntry te;
+
+		      te.WE.word_num = word_num;
+		      te.WE.count = count;
+		      te.WE.doc_count = doc_count;
+		      te.WE.max_doc_count = doc_count;
+		      te.WE.invf_ptr = invf_ptr;
+		      te.WE.invf_len = invf_len;
+		      te.Count = weight_to_apply;
+		      te.Word = copy_string (Word);
+		      if (!te.Word)
+			FatalError (1, "Could NOT create memory to add term");
+		      te.Stem = NULL;
+		      te.require_match = require_match;
+
+		      AddTermEntry (&Terms, &te);
+
+		      /* [RPAP - Feb 97: Term Frequency] */
+		      AddQueryTerm (query_term_list, Word, count, method_using);
+		    }
+		}
+	      /* [RPAP - Feb 97: Term Frequency] */
+	      else
+		AddQueryTerm (query_term_list, Word, 0, method_using);
+	    }
+	}
+      else
+	{
+	  int total_count = 0;  /* [RPAP - Feb 97: Term Frequency] */
+	  TermList *tempList = MakeTermList (0);
+	  if ((num_entries = FindWords (sd, sWord, stem_to_apply, &tempList)) > 0)
+	    {
+	      int i;
+	      u_long max_doc_count = 0;
+
+	      /* get the maximum doc count */
+	      for (i = 0; i < tempList->num; i++)
+		{
+		  if (tempList->TE[i].WE.doc_count > max_doc_count)
+		    max_doc_count = tempList->TE[i].WE.doc_count;
+		  total_count += tempList->TE[i].WE.count;  /* [RPAP - Feb 97: Term Frequency] */
+		}
+
+	      for (i = 0; i < tempList->num; i++)
+		{
+		  /* Look for the word(s) in the already identified terms */
+		  for (j = 0; j < Terms->num; j++) 
+		    {
+		      if (compare (Terms->TE[j].Word, tempList->TE[i].Word) == 0)
+			{
+			  /* found the word */
+			  /* Modify weight */
+			  Terms->TE[j].Count = ((Terms->TE[j].Count + weight_to_apply > INT_MAX) ?
+						INT_MAX : (Terms->TE[j].Count + weight_to_apply));
+			  if (Terms->TE[j].WE.max_doc_count < max_doc_count)
+			    Terms->TE[j].WE.max_doc_count = max_doc_count;
+			  break;
+			}
+		    }
+
+		  if (j == Terms->num)
+		    {
+		      /* word was not found */
+		      tempList->TE[i].WE.max_doc_count = max_doc_count;
+		      tempList->TE[i].Count = weight_to_apply;
+
+		      /* We cannot require a term to match if it is expanded */
+		      /* into multiple terms :-( */
+		      tempList->TE[i].require_match = 0; /* [RJM 07/97: Ranked Required Terms] */
+
+		      AddTermEntry (&Terms, &tempList->TE[i]);
+		    }
+		}
+	    }
+	  /* [RPAP - Feb 97: Term Frequency] */
+	  AddQueryTerm (query_term_list, Word, total_count, method_using);
+
+	  if (tempList != NULL) Xfree(tempList); /* [RJM 07/98: Memory Leak] */
+	} /* end indexed */
+    } /* end while */
+
+  if (Sort)
+    /* Sort the terms in ascending order by doc_count */
+    qsort (Terms->TE, Terms->num, sizeof (TermEntry), doc_count_comp);
+  return (Terms);
+}
+
+
+
+
+static int 
+DE_comp (void *a, void *b)
+{
+  return ((DocEntry *) a)->SeekPos - ((DocEntry *) b)->SeekPos;
+}
+
+
+
+
+
+/*
+ * This function is given a list of term numbers and it returns a list
+ * of document numbers based on the cosine document weighting system.
+ * This puts the entries in an array.
+ * inverted file.
+ * If MaxDocs == -1 then it means all 
+ */
+static DocList *
+CosineGet (query_data * qd, TermList * Terms, RankedQueryInfo * rqi) {
+  DocList *Docs;
+  float *AccumulatedWeights = NULL;
+  Splay_Tree *ST = NULL;
+  Splay_Tree *Para_ST = NULL;
+  Hash_Table *HT = NULL;
+  List_Table *LT = NULL;
+  Heap *H;
+  HeapEntry *he;
+  register float *fptr = NULL;
+  register Invf_Doc_Entry *ide = NULL;
+  register Invf_Doc_EntryH *ideh = NULL;
+  int BackEnd, NumExact, MaxExact, NumParas;
+  int MaxDocs = 0, MaxParas = 0;
+  int i;
+  Invf_Doc_Entry_Pool ide_pool;
+  ide_pool.pool = NULL;
+
+  qd->hops_taken = qd->num_of_ptrs = qd->num_of_accum = 0;
+
+  switch (rqi->AccumMethod)
+    {
+    case 'S':
+      ST = CosineDecodeSplay (qd, Terms, rqi, &ide_pool);
+      if (!ST)
+	return NULL;
+      break;
+    case 'A':
+      AccumulatedWeights = CosineDecode (qd, Terms, rqi);
+      if (!AccumulatedWeights)
+	return NULL;
+      break;
+    case 'H':
+      HT = CosineDecodeHash (qd, Terms, rqi);
+      if (!HT)
+	return NULL;
+      break;
+    case 'L':
+      LT = CosineDecodeList (qd, Terms, rqi);
+      if (!LT)
+	return NULL;
+      break;
+    }
+
+#if 0
+  if (rqi->UseSplayTree)
+    {
+
+      AccumulatedWeights = CosineDecode (qd, Terms, rqi);
+      fptr = AccumulatedWeights;
+      ide = SP_get_first (ST);
+      for (i = 0; i < qd->sd->sdh.num_of_docs; i++)
+	{
+	  if (AccumulatedWeights[i] != 0)
+	    {
+	      if (i != ide->DocNum)
+		fprintf (stderr, "Sum mismatch for %d %f %d %f\n", i + 1,
+			 AccumulatedWeights[i], ide->DocNum + 1, ide->Sum);
+	      ide = SP_get_next (ST);
+	    }
+	}
+    }
+#endif
+
+  switch (rqi->AccumMethod)
+    {
+    case 'S':
+      MaxParas = ST->no_of_items;
+      break;
+    case 'A':
+      {				/* count the number of non-zero document weights */
+	register int i = qd->sd->sdh.num_of_docs;
+	register float *d;
+	MaxParas = 0;
+	for (d = AccumulatedWeights; i; i--, d++)
+	  if (*d)
+	    MaxParas++;
+      }
+      break;
+    case 'H':
+      MaxParas = HT->num + HT->Suplimentary_Num;
+      break;
+    case 'L':
+      MaxParas = LT->num;
+      break;
+    }
+
+  if (rqi->MaxParasToRetrieve != -1 && MaxParas > rqi->MaxParasToRetrieve)
+    MaxParas = rqi->MaxParasToRetrieve;
+  MaxDocs = MaxParas;
+
+  /* Allocate memory for the heap */
+  Docs = MakeDocList (MaxDocs);
+  ChangeMemInUse (qd, sizeof (DocEntry) * MaxDocs);
+
+  H = Heap_Make (MaxDocs, Heap_Lesser);
+
+
+  /* Get the sums from the array divide the sums by the 
+     document weights which we retrieve from the ".idx.wgt" file and put
+     the resulting data into a heap */
+
+
+  he = H->HE;
+  H->NumItems = MaxDocs;
+  switch (rqi->AccumMethod)
+    {
+    case 'S':
+      {
+	ide = SP_get_first (ST);
+	for (i = 0; i < H->NumItems; i++, ide = SP_get_next (ST), he++)
+	  {
+	    he->DocNum = ide->DocNum + 1;
+	    he->OrgWeight = &ide->Sum;
+	    qd->num_of_accum++;
+	  }
+      }
+      break;
+    case 'A':
+      {
+	fptr = AccumulatedWeights;
+	for (i = 0; i < H->NumItems; i++, fptr++, he++)
+	  {
+	    he->DocNum = i + 1;
+	    he->OrgWeight = fptr;
+	    if (*fptr)
+	      qd->num_of_accum++;
+	  }
+      }
+      break;
+    case 'H':
+      {
+	ideh = HT->Head;
+	for (i = 0; i < H->NumItems; i++, ideh = ideh->next, he++)
+	  {
+	    he->DocNum = ideh->IDE.DocNum + 1;
+	    he->OrgWeight = &ideh->IDE.Sum;
+	    qd->num_of_accum++;
+	  }
+      }
+      break;
+    case 'L':
+      {
+	ide = LT->IDE;
+	for (i = 0; i < H->NumItems; i++, ide++, he++)
+	  {
+	    he->DocNum = ide->DocNum + 1;
+	    he->OrgWeight = &ide->Sum;
+	    qd->num_of_accum++;
+	  }
+      }
+      break;
+    }
+
+  he = H->HE;
+  for (i = 0; i < H->NumItems; i++, he++)
+    {
+      *he->OrgWeight /= GetLowerApproxDocWeight (qd->awd, he->DocNum - 1);
+      he->Weight = *he->OrgWeight;
+      *he->OrgWeight = 0;
+      he->SeekPos = he->Len = 0;
+    }
+
+  Heap_Build (H);
+
+  he = H->HE;
+  switch (rqi->AccumMethod)
+    {
+    case 'S':
+      {
+	for (i = MaxDocs; i < ST->no_of_items; i++, ide = SP_get_next (ST))
+	  {
+	    ide->Sum /= GetLowerApproxDocWeight (qd->awd, ide->DocNum);
+	    qd->num_of_accum++;
+	    if (ide->Sum <= he->Weight)
+	      continue;
+	    *he->OrgWeight = he->Weight;
+	    he->DocNum = ide->DocNum + 1;
+	    he->Weight = ide->Sum;
+	    he->OrgWeight = &ide->Sum;
+	    *he->OrgWeight = 0;
+	    Heap_Heapify (H, 1);
+	  }
+      }
+      break;
+    case 'A':
+      {
+	for (i = MaxDocs; i < qd->sd->sdh.num_of_docs; i++, fptr++)
+	  {
+	    if (!*fptr)
+	      continue;
+	    qd->num_of_accum++;
+	    *fptr /= GetLowerApproxDocWeight (qd->awd, i);
+	    if (*fptr <= he->Weight)
+	      continue;
+	    *he->OrgWeight = he->Weight;
+	    he->DocNum = i + 1;
+	    he->Weight = *fptr;
+	    he->OrgWeight = fptr;
+	    *he->OrgWeight = 0;
+	    Heap_Heapify (H, 1);
+	  }
+      }
+      break;
+    case 'H':
+      {
+	for (; ideh; ideh = ideh->next)
+	  {
+	    qd->num_of_accum++;
+	    ideh->IDE.Sum /=
+	      GetLowerApproxDocWeight (qd->awd, ideh->IDE.DocNum);
+	    if (ideh->IDE.Sum <= he->Weight)
+	      continue;
+	    *he->OrgWeight = he->Weight;
+	    he->DocNum = ideh->IDE.DocNum + 1;
+	    he->Weight = ideh->IDE.Sum;
+	    he->OrgWeight = &ideh->IDE.Sum;
+	    *he->OrgWeight = 0;
+	    Heap_Heapify (H, 1);
+	  }
+      }
+      break;
+    case 'L':
+      {
+	for (i = MaxDocs; i < LT->num; i++, ide++)
+	  {
+	    qd->num_of_accum++;
+	    ide->Sum /=
+	      GetLowerApproxDocWeight (qd->awd, ide->DocNum);
+	    if (ide->Sum <= he->Weight)
+	      continue;
+	    *he->OrgWeight = he->Weight;
+	    he->DocNum = ide->DocNum + 1;
+	    he->Weight = ide->Sum;
+	    he->OrgWeight = &ide->Sum;
+	    *he->OrgWeight = 0;
+	    Heap_Heapify (H, 1);
+	  }
+      }
+      break;
+    }
+
+
+  if (rqi->Exact && qd->id->ifh.InvfLevel != 3)
+    {
+      HeapEntry *he = H->HE;
+
+      for (i = 0; i < H->NumItems; i++, he++)
+	{
+	  he->Weight = he->Weight *
+	    GetLowerApproxDocWeight (qd->awd, he->DocNum - 1) /
+	    FetchDocStart (qd, he->DocNum, &he->SeekPos, &he->Len);
+	}
+
+      Heap_Build (H);
+
+      he = H->HE;
+
+      switch (rqi->AccumMethod)
+	{
+	case 'S':
+	  {
+	    ide = SP_get_first (ST);
+	    for (i = 0; i < ST->no_of_items; i++, ide = SP_get_next (ST))
+	      {
+		u_long SeekPos, Len;
+		float Weight;
+		if (!ide->Sum)
+		  continue;
+		if (ide->Sum <= he->Weight)
+		  continue;
+		Weight = ide->Sum *
+		  GetLowerApproxDocWeight (qd->awd, ide->DocNum) /
+		  FetchDocStart (qd, ide->DocNum + 1, &SeekPos, &Len);
+		if (Weight <= he->Weight)
+		  continue;
+		he->DocNum = ide->DocNum + 1;
+		he->OrgWeight = &ide->Sum;
+		he->Weight = Weight;
+		he->SeekPos = SeekPos;
+		he->Len = Len;
+		ide->Sum = 0;
+		Heap_Heapify (H, 1);
+	      }
+	  }
+	  break;
+
+	  /* up to here */
+
+	case 'A':
+	  {
+	    fptr = AccumulatedWeights;
+	    for (i = 0; i < qd->sd->sdh.num_of_docs; i++, fptr++)
+	      {
+		u_long SeekPos, Len;
+		float Weight;
+		if (!*fptr)
+		  continue;
+		if (*fptr <= he->Weight)
+		  continue;
+		Weight = *fptr *
+		  GetLowerApproxDocWeight (qd->awd, i) /
+		  FetchDocStart (qd, i + 1, &SeekPos, &Len);
+		if (Weight <= he->Weight)
+		  continue;
+		he->DocNum = i + 1;
+		he->OrgWeight = fptr;
+		he->Weight = Weight;
+		he->SeekPos = SeekPos;
+		he->Len = Len;
+		*fptr = 0;
+		Heap_Heapify (H, 1);
+	      }
+	  }
+	  break;
+	case 'H':
+	  {
+	    ideh = HT->Head;
+	    for (ideh = HT->Head; ideh; ideh = ideh->next)
+	      {
+		u_long SeekPos, Len;
+		float Weight;
+		if (!ideh->IDE.Sum)
+		  continue;
+		if (ideh->IDE.Sum <= he->Weight)
+		  continue;
+		Weight = ideh->IDE.Sum *
+		  GetLowerApproxDocWeight (qd->awd, ideh->IDE.DocNum) /
+		  FetchDocStart (qd, ideh->IDE.DocNum + 1, &SeekPos, &Len);
+		if (Weight <= he->Weight)
+		  continue;
+		he->DocNum = ideh->IDE.DocNum + 1;
+		he->OrgWeight = &ideh->IDE.Sum;
+		he->Weight = Weight;
+		he->SeekPos = SeekPos;
+		he->Len = Len;
+		ideh->IDE.Sum = 0;
+		Heap_Heapify (H, 1);
+	      }
+	  }
+	  break;
+	case 'L':
+	  {
+	    ide = LT->IDE;
+	    for (i = 0; i < LT->num; i++, ide++)
+	      {
+		u_long SeekPos, Len;
+		float Weight;
+		if (!ide->Sum)
+		  continue;
+		if (ide->Sum <= he->Weight)
+		  continue;
+		Weight = ide->Sum *
+		  GetLowerApproxDocWeight (qd->awd, ide->DocNum) /
+		  FetchDocStart (qd, ide->DocNum + 1, &SeekPos, &Len);
+		if (Weight <= he->Weight)
+		  continue;
+		he->DocNum = ide->DocNum + 1;
+		he->OrgWeight = &ide->Sum;
+		he->Weight = Weight;
+		he->SeekPos = SeekPos;
+		he->Len = Len;
+		ide->Sum = 0;
+		Heap_Heapify (H, 1);
+	      }
+	  }
+	  break;
+	}
+    }
+
+
+
+  H->HC = Heap_Greater;
+  Heap_Build (H);
+
+
+  MaxDocs = H->NumItems;
+  if (rqi->MaxDocsToRetrieve != -1 && MaxDocs > rqi->MaxDocsToRetrieve)
+    MaxDocs = rqi->MaxDocsToRetrieve;
+
+  /* Alarm */
+
+  he = H->HE;
+  BackEnd = H->NumItems - 1;
+  NumExact = 0;
+  MaxExact = H->NumItems;
+  NumParas = 0;
+  Para_ST = SP_createset (DE_comp);
+  while (H->NumItems && Docs->num < MaxDocs)
+    {
+      DocEntry DocEnt;
+      DocEntry *mem;
+
+      if (rqi->Exact)
+	{
+	  if (H->HE[0].SeekPos == 0)
+	    NumExact += Make_Exact_Root (qd, H);
+	}
+      else
+	FetchDocStart (qd, he->DocNum, &he->SeekPos, &he->Len);
+
+      NumParas++;
+
+      DocEnt.DocNum = he->DocNum;
+      DocEnt.Weight = he->Weight;
+      DocEnt.Len = he->Len;
+      DocEnt.SeekPos = he->SeekPos;
+      DocEnt.CompTextBuffer = NULL;
+      DocEnt.Next = NULL;
+
+      Heap_DeleteHead (H);
+
+      if (!(mem = SP_member (&DocEnt, Para_ST)))
+	{
+	  Docs->DE[Docs->num] = DocEnt;
+	  SP_insert (&Docs->DE[Docs->num], Para_ST);
+	  Docs->num++;
+	}
+      else
+	{
+	  DocEnt.Next = mem->Next;
+	  Docs->DE[BackEnd] = DocEnt;
+	  mem->Next = &Docs->DE[BackEnd--];
+	}
+    }
+  SP_freeset (Para_ST);
+
+  if (qd->id->ifh.InvfLevel == 3)
+    {
+      Message ("%d Paragraphs were required to get %d documents",
+	       NumParas, Docs->num);
+      if (NumExact == MaxExact)
+	{
+	  Message ("The exact weights of all %d paragraphs had to be calculated", MaxExact);
+	  Message ("to obtain %d paragraphs. This may mean that the the documents", NumParas);
+	  Message ("returned do not necessarly represent an exact cosine ranking.");
+	  Message ("This problem may be corrected by increasing \'maxparas\'.");
+	}
+    }
+#if 0
+  {
+    int i;
+    FILE *f = fopen ("top.paras", "w");
+    fprintf (f, "=========================\nTop Paragraphs\n");
+    for (i = 0; i < Docs->num; i++)
+      {
+	DocEntry *d;
+	fprintf (f, "<%d(%f)>  ", Heap[i].DocNum, Heap[i].Weight);
+	for (d = Heap[i].Next; d; d = d->Next)
+	  fprintf (f, "%d(%f)  ", d->DocNum, d->Weight);
+	fprintf (f, "\n");
+      }
+    fprintf (f, "=========================\n");
+    fclose (f);
+  }
+#endif
+
+  if (AccumulatedWeights)
+    {
+      Xfree (AccumulatedWeights);
+      ChangeMemInUse (qd, -sizeof (float) * qd->sd->sdh.num_of_docs);
+    }
+  if (ST)
+    {
+      int mem = ST->mem_in_use;
+      SP_freeset (ST);
+      ChangeMemInUse (qd, -mem);
+      free_ide_pool (qd, &ide_pool);
+    }
+  if (HT)
+    HT_free (qd, HT);
+
+  if (LT)
+    LT_free (qd, LT);
+
+  if (H) Xfree (H); /* [RJM 07/98: Memory Leak] */
+
+  return (Docs);
+}
+
+
+
+
+/* if MaxDocs == -1 it means all */
+void 
+RankedQuery (query_data *qd, char *Query, RankedQueryInfo *rqi)
+{
+  DocList *dl;
+
+  if (qd->TL)
+    FreeTermList (&(qd->TL));
+
+  /* [RPAP - Feb 97: Term Frequency] */
+  if (qd->QTL)
+    FreeQueryTermList (&(qd->QTL));
+
+  qd->TL = ParseRankedQuery (qd->sd, Query, rqi->Sort, qd->sd->sdh.indexed,  /* [RPAP - Jan 97: Stem Index Change] */
+			     &(qd->QTL));  /* [RPAP - Feb 97: Term Frequency] */
+
+  /*  PrintTermList (qd->TL, stderr); */
+
+  dl = CosineGet (qd, qd->TL, rqi);
+
+  if (!dl)
+    FatalError (1, "Out of memory\n");
+
+  FreeQueryDocs (qd);
+
+  qd->DL = dl;
+}
Index: /main/tags/2.25/gsdl/packages/mg/src/text/query_term_list.c
===================================================================
--- /main/tags/2.25/gsdl/packages/mg/src/text/query_term_list.c	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/mg/src/text/query_term_list.c	(revision 21064)
@@ -0,0 +1,225 @@
+/**************************************************************************
+ *
+ * filename -- description
+ * Copyright (C) 1994  Authors
+ *
+ * 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.
+ *
+ * $Id$
+ *
+ **************************************************************************/
+
+/*
+   $Log$
+   Revision 1.1  1999/08/10 21:18:21  sjboddie
+   renamed mg-1.3d directory mg
+
+   Revision 1.1  1998/11/17 09:35:36  rjmcnab
+   *** empty log message ***
+
+   * Revision 1.1  1994/10/20  03:57:07  tes
+   * I have rewritten the boolean query optimiser and abstracted out the
+   * components of the boolean query.
+   *
+ */
+
+#include "sysfuncs.h"
+
+#include "memlib.h"
+#include "local_strings.h"
+#include "query_term_list.h"
+#include "term_lists.h"  /* for MAXTERMSTRLEN */
+#include "messages.h"
+
+
+/* =========================================================================
+ * Function: MakeQueryTermList
+ * Description:
+ * Input:
+ * Output:
+ * ========================================================================= */
+QueryTermList *
+MakeQueryTermList (int n)
+{
+  QueryTermList *t;
+  int list_size = (n == 0 ? 1 : n);	/* always allocate at least one node */
+
+  t = Xmalloc (sizeof (QueryTermList) + (list_size - 1) * sizeof (QueryTermEntry));
+  if (!t)
+    FatalError (1, "Unable to allocate query term list");
+
+  t->num = n;
+  t->list_size = list_size;
+
+  return t;
+}
+
+/* =========================================================================
+ * Function: ResizeQueryTermList
+ * Description:
+ * Input:
+ * Output:
+ * ========================================================================= */
+
+#define GROWTH_FACTOR 2
+#define MIN_SIZE 2
+
+static void
+ResizeQueryTermList (QueryTermList ** query_list)
+{
+  QueryTermList *qtl = *query_list;
+
+  if (qtl->num > qtl->list_size)
+    {
+      if (qtl->list_size)
+	qtl->list_size *= GROWTH_FACTOR;
+      else
+	qtl->list_size = MIN_SIZE;
+    }
+  qtl = Xrealloc (qtl, sizeof (QueryTermList) + (qtl->list_size - 1) * sizeof (QueryTermEntry));
+
+  if (!qtl)
+    FatalError (1, "Unable to resize query term list");
+
+  *query_list = qtl;
+}
+
+/* =========================================================================
+ * Function: ConvertQueryTermsToString
+ * Description:
+ *      Convert term list into null-terminated string
+ * Input:
+ *      query_term_list = query list
+ * Output:
+ *      str = term string
+ * ========================================================================= */
+
+void
+ConvertQueryTermsToString (QueryTermList * query_term_list, char *str)
+{
+  int i = 0;
+  int total_len = 0;
+
+  /* terms_str should be preallocated */
+  if (!str)
+    return;
+
+  for (i = 0; i < query_term_list->num; i++)
+    {
+      unsigned char *word = query_term_list->QTE[i].Term;
+      int len = word[0];
+      total_len += len + 1;	/* +1 for space */
+      if (query_term_list->QTE[i].stem_method >= 0)
+	total_len += 2;         /* '#' and the stem number */
+      if (total_len > MAXTERMSTRLEN)
+	break;
+      strncpy (str, (char *) word + 1, len);
+      str += len;
+      if (query_term_list->QTE[i].stem_method >= 0)
+	{
+	  *str++ = '#';
+	  *str++ = '0' + query_term_list->QTE[i].stem_method;
+	}
+      if (i != (query_term_list->num) - 1)
+	{
+	  *str = ' ';
+	  str++;		/* add space gap */
+	}
+
+    }
+  *str = '\0';
+}
+
+/* =========================================================================
+ * Function: ResetTermList
+ * Description: 
+ * Input: 
+ * Output: 
+ * ========================================================================= */
+
+void
+ResetQueryTermList (QueryTermList ** qtl)
+{
+  if (*qtl)
+    FreeQueryTermList (qtl);
+  *qtl = MakeQueryTermList (0);
+}
+
+/* =========================================================================
+ * Function: AddQueryTermEntry
+ * Description: 
+ * Input: 
+ * Output: 
+ * ========================================================================= */
+
+int
+AddQueryTermEntry (QueryTermList ** query_term_list, QueryTermEntry * qte)
+{
+  QueryTermList *qtl = *query_term_list;
+
+  qtl->num++;
+  ResizeQueryTermList (query_term_list);
+  qtl = *query_term_list;
+
+  /* copy the structure contents */
+  bcopy ((char *) qte, (char *) &(qtl->QTE[qtl->num - 1]), sizeof (QueryTermEntry));
+
+  return qtl->num - 1;
+}
+
+
+
+/* =========================================================================
+ * Function: AddQueryTerm
+ * Description: 
+ * Input: 
+ * Output: 
+ * ========================================================================= */
+
+int
+AddQueryTerm (QueryTermList ** query_term_list, u_char * Term, int Count, int stem_method)
+{
+  /* Create a new entry in the list for the new word */
+  QueryTermEntry qte;
+
+  qte.Count = Count;
+  qte.stem_method = stem_method;
+  qte.Term = copy_string (Term);
+  if (!qte.Term)
+    FatalError (1, "Could NOT create memory to add term");
+
+  return AddQueryTermEntry (query_term_list, &qte);
+}
+
+/* =========================================================================
+ * Function: FreeQueryTermList
+ * Description:
+ * Input:
+ * Output:
+ * ========================================================================= */
+
+void
+FreeQueryTermList (QueryTermList ** the_qtl)
+{
+  int j;
+  QueryTermList *qtl = *the_qtl;
+
+  for (j = 0; j < qtl->num; j++)
+    if (qtl->QTE[j].Term)
+      Xfree (qtl->QTE[j].Term);
+  Xfree (qtl);
+
+  *the_qtl = NULL;
+}
Index: /main/tags/2.25/gsdl/packages/mg/src/text/query_term_list.h
===================================================================
--- /main/tags/2.25/gsdl/packages/mg/src/text/query_term_list.h	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/mg/src/text/query_term_list.h	(revision 21064)
@@ -0,0 +1,67 @@
+/**************************************************************************
+ *
+ * term_lists.h -- description
+ * Copyright (C) 1994  Authors
+ *
+ * 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.
+ *
+ * $Id$
+ *
+ **************************************************************************/
+
+/*
+   $Log$
+   Revision 1.1  1999/08/10 21:18:21  sjboddie
+   renamed mg-1.3d directory mg
+
+   Revision 1.1  1998/11/17 09:35:37  rjmcnab
+   *** empty log message ***
+
+   * Revision 1.1  1994/10/20  03:57:08  tes
+   * I have rewritten the boolean query optimiser and abstracted out the
+   * components of the boolean query.
+   *
+ */
+
+#ifndef QUERY_TERM_LIST_H
+#define QUERY_TERM_LIST_H
+
+#include "sysfuncs.h"
+
+typedef struct QueryTermEntry
+  {
+    int Count;			/* The number of times the word occurs in the query */
+    u_char *Term;		/* The query term */
+    int stem_method;            /* The steming method to apply to the term : -1 is default */
+  }
+QueryTermEntry;
+
+typedef struct QueryTermList
+  {
+    int list_size;
+    int num;
+    QueryTermEntry QTE[1];
+  }
+QueryTermList;
+
+/* --- prototypes --- */
+void ConvertQueryTermsToString (QueryTermList * query_term_list, char *str);
+int AddQueryTerm (QueryTermList ** query_term_list, u_char * Term, int Count, int stem_method);
+void ResetQueryTermList (QueryTermList ** tl);
+void FreeQueryTermList (QueryTermList ** the_qtl);
+QueryTermList *MakeQueryTermList (int n);
+
+
+#endif
Index: /main/tags/2.25/gsdl/packages/mg/src/text/read_line.c
===================================================================
--- /main/tags/2.25/gsdl/packages/mg/src/text/read_line.c	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/mg/src/text/read_line.c	(revision 21064)
@@ -0,0 +1,214 @@
+/**************************************************************************
+ *
+ * read_line.c -- Input line reading routines for mgquery
+ * Copyright (C) 1994  Neil Sharman
+ *
+ * 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.
+ *
+ * $Id$
+ *
+ **************************************************************************/
+
+#include "sysfuncs.h"
+#include "memlib.h"
+
+#ifdef GNU_READLINE
+#include "readline.h"
+#include "chardefs.h"
+#include "history.h"
+#endif
+
+
+#include "globals.h"
+#include "environment.h"
+#include "read_line.h"
+
+
+
+#ifdef GNU_READLINE
+int rl_bind_key (int, int (*)());
+
+
+void 
+Init_ReadLine (void)
+{
+  /* Make TAB just insert itself rather than do a file name completion */
+  rl_bind_key (TAB, rl_insert);
+}
+#else
+
+static FILE *rl_instream = NULL;
+static FILE *rl_outstream = NULL;
+
+void 
+Init_ReadLine (void)
+{
+  rl_instream = stdin;
+  rl_outstream = stdout;
+}
+
+static char *
+readline (char *pmt)
+{
+  static char buf[MAXLINEBUFFERLEN + 1];
+  char *s;
+
+  fprintf (rl_outstream, "%s", pmt);
+  s = fgets (buf, sizeof (buf), rl_instream);
+  if (s)
+    {
+      char *s1 = strrchr (s, '\n');
+      if (s1 && *(s1 + 1) == '\0')
+	*s1 = '\0';
+    }
+  return s ? Xstrdup (s) : NULL;
+}
+#endif
+
+/* WritePrompt() */
+/* Write out a prompt if user is a TTY */
+void 
+WritePrompt (void)
+{
+  if (isatty (fileno (InFile)))
+    {
+      if (!BooleanEnv (GetEnv ("expert"), 0))
+	fprintf (stderr, "Enter a command or query (.quit to terminate, .help for assistance).\n");
+    }
+}
+
+#ifdef GNU_READLINE
+static void memory_error_and_abort ();
+
+char *
+xmalloc (bytes)
+     int bytes;
+{
+  char *temp = (char *) Xmalloc (bytes);
+
+  if (!temp)
+    memory_error_and_abort ();
+  return (temp);
+}
+
+char *
+xrealloc (pointer, bytes)
+     char *pointer;
+     int bytes;
+{
+  char *temp;
+
+  if (!pointer)
+    temp = (char *) xmalloc (bytes);
+  else
+    temp = (char *) Xrealloc (pointer, bytes);
+
+  if (!temp)
+    memory_error_and_abort ();
+
+  return (temp);
+}
+
+static void
+memory_error_and_abort ()
+{
+  fprintf (stderr, "history: Out of virtual memory!\n");
+  abort ();
+}
+#endif
+
+
+/*
+ * This routine returns a pointer to the users entered line 
+ *
+ */
+static char *
+GetLine (char *pmt)
+{
+  static char *the_line = NULL;
+  if (the_line)
+    Xfree (the_line);
+  the_line = NULL;
+  rl_instream = InFile;
+  if (isatty (fileno (InFile)))
+    {
+      fputc ('\r', stderr);
+      if (!isatty (fileno (OutFile)))
+	rl_outstream = stderr;
+      else
+	rl_outstream = OutFile;
+      the_line = readline (pmt);
+    }
+  else
+    {
+      if (isatty (fileno (OutFile)))
+	{
+	  the_line = readline (pmt);
+	  fprintf (stderr, "%s\n", the_line ? the_line : "");
+	}
+      else
+	{
+	  the_line = readline ("");
+	  if (the_line)
+	    fprintf (stderr, "%s%s\n", pmt, the_line);
+	}
+    }
+#ifdef GNU_READLINE
+  if (the_line && *the_line)
+    add_history (the_line);
+#endif
+  return (the_line);
+}
+
+
+
+
+
+
+char *
+GetMultiLine (void)
+{
+  static char *line = NULL;
+  char *s;
+  if (line)
+    Xfree (line);
+  line = NULL;
+  if (!(s = GetLine ("> ")))
+    return (NULL);
+  if (!(line = Xstrdup (s)))
+    {
+      fprintf (stderr, "Unable to allocate memory for the line\n");
+      abort ();
+    }
+
+  while ((s = strrchr (line, '\\')) && *(s + 1) == '\0')
+    {
+      char *new;
+      *strrchr (line, '\\') = '\0';
+      if (!(s = GetLine ("? ")))
+	return (NULL);
+      if (!(new = Xmalloc (strlen (line) + strlen (s) + 2)))
+	{
+	  fprintf (stderr, "Unable to allocate memory for the line\n");
+	  abort ();
+	}
+      strcpy (new, line);
+      strcat (new, "\n");
+      strcat (new, s);
+      Xfree (line);
+      line = new;
+    }
+  return (line);
+}
Index: /main/tags/2.25/gsdl/packages/mg/src/text/read_line.h
===================================================================
--- /main/tags/2.25/gsdl/packages/mg/src/text/read_line.h	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/mg/src/text/read_line.h	(revision 21064)
@@ -0,0 +1,34 @@
+/**************************************************************************
+ *
+ * read_line.h -- Input line reading routines for mgquery
+ * Copyright (C) 1994  Neil Sharman
+ *
+ * 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.
+ *
+ * $Id$
+ *
+ **************************************************************************/
+
+
+#ifndef READ_LINE_H
+#define READ_LINE_H
+
+#define MAXLINEBUFFERLEN  65535
+
+void Init_ReadLine (void);
+void WritePrompt (void);
+char *GetMultiLine (void);
+
+#endif
Index: /main/tags/2.25/gsdl/packages/mg/src/text/stem_search.c
===================================================================
--- /main/tags/2.25/gsdl/packages/mg/src/text/stem_search.c	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/mg/src/text/stem_search.c	(revision 21064)
@@ -0,0 +1,772 @@
+/**************************************************************************
+ *
+ * stem_search.c -- Functions for searching the blocked stemmed dictionary
+ * Copyright (C) 1994  Neil Sharman
+ *
+ * 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.
+ *
+ * $Id$
+ *
+ **************************************************************************/
+
+#include "sysfuncs.h"
+
+#include "memlib.h"
+#include "messages.h"
+#include "filestats.h"
+#include "timing.h"
+#include "local_strings.h"
+#include "netorder.h"  /* [RPAP - Jan 97: Endian Ordering] */
+
+#include "mg.h"
+#include "invf.h"
+#include "text.h"
+#include "lists.h"
+#include "backend.h"
+#include "words.h"
+#include "locallib.h"
+#include "stem_search.h"
+#include "mg_errors.h"
+#include "term_lists.h"
+#include "stemmer.h"
+
+
+/*
+   $Log$
+   Revision 1.1  1999/08/10 21:18:22  sjboddie
+   renamed mg-1.3d directory mg
+
+   Revision 1.3  1999/07/02 00:18:55  rjmcnab
+   Changed so FindWords could be used in new ways.
+
+   Revision 1.2  1998/11/25 07:55:51  rjmcnab
+
+   Modified mg to that you can specify the stemmer you want
+   to use via a command line option. You specify it to
+   mg_passes during the build process. The number of the
+   stemmer that you used is stored within the inverted
+   dictionary header and the stemmed dictionary header so
+   the correct stemmer is used in later stages of building
+   and querying.
+
+   Revision 1.1  1998/11/17 09:35:39  rjmcnab
+   *** empty log message ***
+
+   * Revision 1.3  1994/10/20  03:57:04  tes
+   * I have rewritten the boolean query optimiser and abstracted out the
+   * components of the boolean query.
+   *
+   * Revision 1.2  1994/09/20  04:42:08  tes
+   * For version 1.1
+   *
+ */
+
+static char *RCSID = "$Id$";
+
+
+stemmed_dict *
+ReadStemDictBlk (File * stem_file)
+{
+  unsigned long i;
+  stemmed_dict *sd;
+  u_char *buffer;
+
+  if (!(sd = Xmalloc (sizeof (stemmed_dict))))
+    {
+      mg_errno = MG_NOMEM;
+      return (NULL);
+    }
+
+  sd->stem_file = stem_file;
+  sd->MemForStemDict = 0;
+
+  Fread (&sd->sdh, sizeof (sd->sdh), 1, stem_file);
+  /* [RPAP - Jan 97: Endian Ordering] */
+  NTOHUL(sd->sdh.lookback);
+  NTOHUL(sd->sdh.block_size);
+  NTOHUL(sd->sdh.num_blocks);
+  NTOHUL(sd->sdh.blocks_start);
+  NTOHUL(sd->sdh.index_chars);
+  NTOHUL(sd->sdh.num_of_docs);
+  NTOHUL(sd->sdh.static_num_of_docs);
+  NTOHUL(sd->sdh.num_of_words);
+  NTOHUL(sd->sdh.stem_method);
+  NTOHUL(sd->sdh.indexed);
+
+  if (!(buffer = Xmalloc (sd->sdh.index_chars)))
+    {
+      Xfree (sd);
+      mg_errno = MG_NOMEM;
+      return (NULL);
+    };
+  sd->MemForStemDict += sd->sdh.index_chars;
+
+  if (!(sd->index = Xmalloc (sd->sdh.num_blocks * sizeof (*sd->index))))
+    {
+      Xfree (sd);
+      Xfree (buffer);
+      mg_errno = MG_NOMEM;
+      return (NULL);
+    };
+  sd->MemForStemDict += sd->sdh.num_blocks * sizeof (*sd->index);
+
+  if (!(sd->pos = Xmalloc (sd->sdh.num_blocks * sizeof (*sd->pos))))
+    {
+      Xfree (sd);
+      Xfree (buffer);
+      Xfree (sd->index);
+      mg_errno = MG_NOMEM;
+      return (NULL);
+    };
+  sd->MemForStemDict += sd->sdh.num_blocks * sizeof (*sd->pos);
+
+  if (!(sd->buffer = Xmalloc (sd->sdh.block_size * sizeof (*sd->buffer))))
+    {
+      Xfree (sd);
+      Xfree (buffer);
+      Xfree (sd->index);
+      Xfree (sd->buffer);
+      mg_errno = MG_NOMEM;
+      return (NULL);
+    };
+  sd->MemForStemDict += sd->sdh.block_size * sizeof (*sd->buffer);
+
+  sd->active = -1;
+
+  for (i = 0; i < sd->sdh.num_blocks; i++)
+    {
+      register u_char len;
+      sd->index[i] = buffer;
+      len = Getc (stem_file);
+      *buffer++ = len;
+      Fread (buffer, sizeof (u_char), len, stem_file);
+      buffer += len;
+      Fread (&sd->pos[i], sizeof (*sd->pos), 1, stem_file);
+      NTOHUL(sd->pos[i]); /* [RPAP - Jan 97: Endian Ordering] */
+    }
+
+  mg_errno = MG_NOERROR;
+
+  /*  fprintf (stderr, "mem for stem dict = %i\n", sd->MemForStemDict); */
+
+  return sd;
+}
+
+
+/* [RPAP - Jan 97: Stem Index Change] */
+stemmed_idx *
+ReadStemIdxBlk (File * stem_idx_file)
+{
+  unsigned long i;
+  stemmed_idx *si;
+  u_char *buffer;
+
+  if (!(si = Xmalloc (sizeof (stemmed_idx))))
+    {
+      mg_errno = MG_NOMEM;
+      return (NULL);
+    }
+
+  si->stem_idx_file = stem_idx_file;
+  si->MemForStemIdx = 0;
+
+  Fread (&si->sih, sizeof (si->sih), 1, stem_idx_file);
+  /* [RPAP - Jan 97: Endian Ordering] */
+  NTOHUL(si->sih.lookback);
+  NTOHUL(si->sih.block_size);
+  NTOHUL(si->sih.num_blocks);
+  NTOHUL(si->sih.blocks_start);
+  NTOHUL(si->sih.index_chars);
+  NTOHUL(si->sih.num_of_words);
+
+  if (!(buffer = Xmalloc (si->sih.index_chars)))
+    {
+      Xfree (si);
+      mg_errno = MG_NOMEM;
+      return (NULL);
+    };
+  si->MemForStemIdx += si->sih.index_chars;
+
+  if (!(si->index = Xmalloc (si->sih.num_blocks * sizeof (*si->index))))
+    {
+      Xfree (si);
+      Xfree (buffer);
+      mg_errno = MG_NOMEM;
+      return (NULL);
+    };
+  si->MemForStemIdx += si->sih.num_blocks * sizeof (*si->index);
+
+  if (!(si->pos = Xmalloc (si->sih.num_blocks * sizeof (*si->pos))))
+    {
+      Xfree (si->index);
+      Xfree (si);
+      Xfree (buffer);
+      mg_errno = MG_NOMEM;
+      return (NULL);
+    };
+  si->MemForStemIdx += si->sih.num_blocks * sizeof (*si->pos);
+
+  if (!(si->buffer = Xmalloc (si->sih.block_size * sizeof (*si->buffer))))
+    {
+      Xfree (buffer);
+      Xfree (si->index);
+      Xfree (si->buffer);
+      Xfree (si);
+      mg_errno = MG_NOMEM;
+      return (NULL);
+    };
+  si->MemForStemIdx += si->sih.block_size * sizeof (*si->buffer);
+
+  si->active = -1;
+
+  for (i = 0; i < si->sih.num_blocks; i++)
+    {
+      register u_char len;
+      si->index[i] = buffer;
+      len = Getc (stem_idx_file);
+      *buffer++ = len;
+      Fread (buffer, sizeof (u_char), len, stem_idx_file);
+      buffer += len;
+      Fread (&si->pos[i], sizeof (*si->pos), 1, stem_idx_file);
+      NTOHUL(si->pos[i]);  /* [RPAP - Jan 97: Endian Ordering] */
+    }
+  mg_errno = MG_NOERROR;
+
+  /*  fprintf (stderr, "mem for stem idx = %i\n", si->MemForStemIdx); */
+
+  return si;
+}
+
+
+/* [RPAP - Jan 97: Stem Index Change] */
+/* word should be appropriately stemed */
+static int
+GetIdxBlock (stemmed_idx * si, u_char * word)
+{
+  register int lo = 0, hi = si->sih.num_blocks - 1;
+  register int mid = 0, c = 0;
+
+  while (lo <= hi)
+    {
+      mid = (lo + hi) / 2;
+      c = casecompare (word, si->index[mid]);
+      if (c < 0)
+	hi = mid - 1;
+      else if (c > 0)
+	lo = mid + 1;
+      else
+	return mid;
+    }
+  return hi < 0 ? 0 : (c < 0 ? mid - 1 : mid);
+}
+
+
+static int 
+GetBlock (stemmed_dict * sd, u_char * Word)
+{
+  register int lo = 0, hi = sd->sdh.num_blocks - 1;
+  register int mid = 0, c = 0;
+  while (lo <= hi)
+    {
+      mid = (lo + hi) / 2;
+      c = casecompare (Word, sd->index[mid]);  /* [RPAP - Jan 97: Stem Index Change] */
+      if (c < 0)
+	hi = mid - 1;
+      else if (c > 0)
+	lo = mid + 1;
+      else
+	return mid;
+    }
+  return hi < 0 ? 0 : (c < 0 ? mid - 1 : mid);
+}
+
+
+/*
+ * This function looks up a word in the stemmed dictionary, it returns -1
+ * if the word cound not be found, and 0 if it successfully finds the word.
+ * If count is non-null the ulong it is pointing to is set to the number of 
+ * occurances of the stemmed word in the collection. i.e wcnt.
+ * If doc_count is non-null the ulong it is pointing to is set to the number
+ * of documents that the word occurs in. i.e fcnt
+ * If invf_ptr is non-null the ulong it is pointing to is set to the position
+ * of the inverted file where the entry for this word start.
+ */
+int 
+FindWord (stemmed_dict * sd, u_char * Word, unsigned long *count,
+	  unsigned long *doc_count, unsigned long *invf_ptr,
+	  unsigned long *invf_len)
+{
+  register int lo, hi, mid, c;
+  register unsigned int res;
+  int block, num_indexes;
+  unsigned long *first_word, *last_invf_len;
+  unsigned short *num_words;
+  u_char *base;
+  unsigned short *index;
+  u_char prev[MAXSTEMLEN + 1];
+
+  block = GetBlock (sd, Word);
+  /* [RPAP - Jan 97: Endian Ordering] */
+  if (sd->active != sd->pos[block])
+    {
+      int i;
+
+      Fseek (sd->stem_file, sd->pos[block] + sd->sdh.blocks_start, 0);
+      Fread (sd->buffer, sd->sdh.block_size, sizeof (u_char), sd->stem_file);
+      sd->active = sd->pos[block];
+
+      /* [RPAP - Jan 97: Endian Ordering] */
+      first_word = (unsigned long *) (sd->buffer);
+      NTOHUL(*first_word);
+      last_invf_len = (unsigned long *) (first_word + 1);
+      NTOHUL(*last_invf_len);
+      num_words = (unsigned short *) (last_invf_len + 1);
+      NTOHUS(*num_words);
+      index = num_words + 1;
+      num_indexes = ((*num_words - 1) / sd->sdh.lookback) + 1;
+
+      for (i = 0; i < num_indexes; i++)
+	NTOHUS(index[i]);
+    }
+  else
+    {
+      first_word = (unsigned long *) (sd->buffer);
+      last_invf_len = (unsigned long *) (first_word + 1);
+      num_words = (unsigned short *) (last_invf_len + 1);
+      index = num_words + 1;
+      num_indexes = ((*num_words - 1) / sd->sdh.lookback) + 1;
+    }
+  base = (u_char *) (index + num_indexes);
+
+  lo = 0;
+  hi = num_indexes - 1;
+  while (lo <= hi)
+    {
+      mid = (lo + hi) / 2;
+      c = casecompare (Word, base + index[mid] + 1);  /* [RPAP - Jan 97: Stem Index Change] */
+      if (c < 0)
+	hi = mid - 1;
+      else if (c > 0)
+	lo = mid + 1;
+      else
+	{
+	  hi = mid;
+	  break;
+	}
+    }
+  if (hi < 0)
+    hi = 0;
+
+  res = hi * sd->sdh.lookback;
+  base += index[hi];
+
+  for (;;)
+    {
+      unsigned copy, suff;
+      unsigned long invfp;
+      if (res >= *num_words)
+	return (-1);
+      copy = *base++;
+      suff = *base++;
+      bcopy ((char *) base, (char *) (prev + copy + 1), suff);
+      base += suff;
+      *prev = copy + suff;
+
+      c = casecompare (Word, prev);   /* [RPAP - Jan 97: Stem Index Change] */
+      if (c < 0)
+	return (-1);
+
+      if (c == 0 && doc_count)
+	{
+	  bcopy ((char *) base, (char *) doc_count, sizeof (*doc_count));
+	  NTOHUL(*doc_count);  /* [RPAP - Jan 97: Endian Ordering] */
+	}
+      base += sizeof (*doc_count);
+
+      if (c == 0 && count)
+	{
+	  bcopy ((char *) base, (char *) count, sizeof (*count));
+	  NTOHUL(*count);  /* [RPAP - Jan 97: Endian Ordering] */
+	}
+      base += sizeof (*count);
+
+      if (c == 0 && invf_ptr)
+	{
+	  bcopy ((char *) base, (char *) &invfp, sizeof (invf_ptr));
+	  NTOHUL(invfp);  /* [RPAP - Jan 97: Endian Ordering] */
+	  *invf_ptr = invfp;
+	}
+      base += sizeof (*invf_ptr);
+
+      if (c == 0)
+	{
+	  /* Calculate invf_len is necessary */
+	  unsigned long next_invfp;
+	  if (!invf_len)
+	    return (*first_word + res);
+
+	  /* If the current word is the last word of the block the get the 
+	     length from last_invf_len */
+	  if (res == *num_words - 1)
+	    {
+	      *invf_len = *last_invf_len;
+	      return (*first_word + res);
+	    }
+
+	  /* Skip over most of the next word to get to the invf_ptr */
+	  base++;
+	  suff = *base++;
+	  base += suff + sizeof (unsigned long) * 2;
+	  bcopy ((char *) base, (char *) &next_invfp, sizeof (next_invfp));
+	  NTOHUL(next_invfp);  /* [RPAP - Jan 97: Endian Ordering] */
+	  *invf_len = next_invfp - invfp;
+	  return (*first_word + res);
+	}
+      res++;
+    }
+}
+
+
+/* [RPAP - Jan 97: Stem Index Change] */
+int 
+FindWords (stemmed_dict * sd, u_char * sWord, int stem_method, TermList ** tl)
+{
+  register unsigned int res;
+  unsigned int idx_res;
+  unsigned copy, suff;
+  int j, k;
+
+  int block, num_indexes;
+  unsigned long *first_word, *last_invf_len;
+  unsigned short *num_words;
+  u_char *base;
+  unsigned short *index;
+  u_char prev[MAXSTEMLEN + 1];
+
+  int idx_block, idx_num_indexes;
+  unsigned long *idx_first_word;
+  unsigned short *idx_num_words;
+  u_char *idx_base;
+  unsigned short *idx_index;
+  u_char idx_prev[MAXSTEMLEN + 1];
+
+  unsigned int num_entries, num_cases;
+  unsigned short blk_index, offset;
+  stemmed_idx * si = NULL;
+
+  /* handle stem_method 0 seperately */
+  if (stem_method == 0) {
+    TermEntry te;
+    if ((te.WE.word_num = FindWord (sd, sWord, &te.WE.count, &te.WE.doc_count,
+				   &te.WE.invf_ptr, &te.WE.invf_len)) != -1) {
+      te.WE.max_doc_count = te.WE.doc_count;
+
+      te.Count = 1;
+      te.Word = copy_string (sWord);
+      if (!te.Word)
+	FatalError (1, "Could NOT create memory to add term");
+      te.Stem = copy_string (sWord);
+      if (!te.Stem)
+	FatalError (1, "Could NOT create memory to add term");
+      /*      te.query_mask = NULL;*/
+      
+      AddTermEntry (tl, &te);
+      return (*tl)->num;
+      
+    } else {
+      /* didn't match */
+      return 0;
+    }
+  }
+  
+  if (stem_method == 1)
+    si = sd->stem1;
+  else if (stem_method == 2)
+    si = sd->stem2;
+  else
+    si = sd->stem3;
+
+  /* Locate block */
+  idx_block = GetIdxBlock (si, sWord);
+
+  /* [RPAP - Jan 97: Endian Ordering] */
+  if (si->active != si->pos[idx_block])
+    {
+      Fseek (si->stem_idx_file, si->pos[idx_block] + si->sih.blocks_start, 0);
+      Fread (si->buffer, si->sih.block_size, sizeof (u_char), si->stem_idx_file);
+      si->active = si->pos[idx_block];
+
+      idx_first_word = (unsigned long *) (si->buffer);
+      NTOHUL(*idx_first_word);  /* [RPAP - Jan 97: Endian Ordering] */
+      idx_num_words = (unsigned short *) (idx_first_word + 1);
+      NTOHUS(*idx_num_words);  /* [RPAP - Jan 97: Endian Ordering] */
+      idx_index = idx_num_words + 1;
+      idx_num_indexes = ((*idx_num_words - 1) / si->sih.lookback) + 1;
+
+      /* [RPAP - Jan 97: Endian Ordering] */
+      for (j = 0; j < idx_num_indexes; j++)
+	NTOHUS(idx_index[j]);
+    }
+  else
+    {
+      idx_first_word = (unsigned long *) (si->buffer);
+      idx_num_words = (unsigned short *) (idx_first_word + 1);
+      idx_index = idx_num_words + 1;
+      idx_num_indexes = ((*idx_num_words - 1) / si->sih.lookback) + 1;
+    }
+  idx_base = (u_char *) (idx_index + idx_num_indexes);
+  
+  {
+    /* Locate 3-in-4 block */
+    register int lo, hi, mid, c;
+    lo = 0;
+    hi = idx_num_indexes - 1;
+    while (lo <= hi)
+      {
+	mid = (lo + hi) / 2;
+	c = casecompare (sWord, idx_base + idx_index[mid] + 1);
+	if (c < 0)
+	  hi = mid - 1;
+	else if (c > 0)
+	  lo = mid + 1;
+	else
+	  {
+	    hi = mid;
+	    break;
+	  }
+      }
+    if (hi < 0)
+      hi = 0;
+
+    idx_res = hi * si->sih.lookback;
+    idx_base += idx_index[hi];
+  }
+
+  /* Locate actual word entry */
+  for (;;)
+    {
+      int c;
+      if (idx_res >= *idx_num_words)
+	return (-1);
+      copy = *idx_base++;
+      suff = *idx_base++;
+      bcopy ((char *) idx_base, (char *) (idx_prev + copy + 1), suff);
+      idx_base += suff;
+      *idx_prev = copy + suff;
+
+      c = casecompare (sWord, idx_prev);
+      if (c < 0)
+	return (-1);
+     
+      bcopy ((char *) idx_base, (char *) &num_entries, sizeof (num_entries));
+      NTOHUI(num_entries);  /* [RPAP - Jan 97: Endian Ordering] */
+      idx_base += sizeof (num_entries);
+      
+      if (c > 0)
+	idx_base += num_entries * (sizeof (num_cases) + sizeof (block) + 
+				   sizeof (blk_index) + sizeof (offset));
+
+      else
+	break;
+
+      idx_res++;
+    }
+
+  for (k = 0; k < num_entries; k++)
+    {
+      unsigned copy, suff;
+      unsigned long invfp;
+      /* Read next stem index pos */
+      bcopy ((char *) idx_base, (char *) &num_cases, sizeof (num_cases));
+      NTOHUI(num_cases);  /* [RPAP - Jan 97: Endian Ordering] */
+      idx_base += sizeof (num_cases);
+      bcopy ((char *) idx_base, (char *) &block, sizeof (block));
+      NTOHUI(block);  /* [RPAP - Jan 97: Endian Ordering] */
+      idx_base += sizeof (block);
+      bcopy ((char *) idx_base, (char *) &blk_index, sizeof (blk_index));
+      NTOHUS(blk_index);  /* [RPAP - Jan 97: Endian Ordering] */
+      idx_base += sizeof (blk_index);
+      bcopy ((char *) idx_base, (char *) &offset, sizeof (offset));
+      NTOHUS(offset);  /* [RPAP - Jan 97: Endian Ordering] */
+      idx_base += sizeof (offset);
+
+      /* [RPAP - Jan 97: Endian Ordering] */
+      if (sd->active != sd->pos[block])
+	{
+	  Fseek (sd->stem_file, sd->pos[block] + sd->sdh.blocks_start, 0);
+	  Fread (sd->buffer, sd->sdh.block_size, sizeof (u_char), sd->stem_file);
+	  sd->active = sd->pos[block];
+
+	  first_word = (unsigned long *) (sd->buffer);
+	  NTOHUL(*first_word);  /* [RPAP - Jan 97: Endian Ordering] */
+	  last_invf_len = (unsigned long *) (first_word + 1);
+	  NTOHUL(*last_invf_len);  /* [RPAP - Jan 97: Endian Ordering] */
+	  num_words = (unsigned short *) (last_invf_len + 1);
+	  NTOHUS(*num_words);  /* [RPAP - Jan 97: Endian Ordering] */
+	  index = num_words + 1;
+	  num_indexes = ((*num_words - 1) / sd->sdh.lookback) + 1;
+
+	  /* [RPAP - Jan 97: Endian Ordering] */
+	  for (j = 0; j < num_indexes; j++)
+	    NTOHUS(index[j]);
+	}
+      else
+	{
+	  first_word = (unsigned long *) (sd->buffer);
+	  last_invf_len = (unsigned long *) (first_word + 1);
+	  num_words = (unsigned short *) (last_invf_len + 1);
+	  index = num_words + 1;
+	  num_indexes = ((*num_words - 1) / sd->sdh.lookback) + 1;
+	}
+      base = (u_char *) (index + num_indexes);
+      
+      res = blk_index * sd->sdh.lookback;
+      base += index[blk_index];
+      
+      for (j = 0; j < offset; j++)
+	{
+	  copy = *base++;
+	  suff = *base++;
+	  bcopy ((char *) base, (char *) (prev + copy + 1), suff);
+	  base += suff;
+	  *prev = copy + suff;
+	  base += sizeof (unsigned long);   /* skip doc_count */
+	  base += sizeof (unsigned long);   /* skip count */
+	  base += sizeof (unsigned long);   /* skip invf_ptr */
+	  res++;
+	}
+
+      for (j = 0; j < num_cases; j++)
+	{
+	  TermEntry te;
+	  
+	  if (res >= *num_words)
+	    return (-1);
+	  copy = *base++;
+	  suff = *base++;
+	  bcopy ((char *) base, (char *) (prev + copy + 1), suff);
+	  base += suff;
+	  *prev = copy + suff;
+	      
+	  te.Word = copy_string (prev);
+	  if (!te.Word)
+	    FatalError (1, "Could NOT create memory to add term");
+	  te.Stem = copy_string (prev);
+	  if (!te.Stem)
+	    FatalError (1, "Could NOT create memory to add term");
+	  stemmer (2, sd->sdh.stemmer_num, te.Stem);
+
+	  te.Count = 1;
+	  te.WE.word_num = *first_word + res;
+	  bcopy ((char *) base, (char *) &te.WE.doc_count, sizeof (te.WE.doc_count));
+	  NTOHUL(te.WE.doc_count);  /* [RPAP - Jan 97: Endian Ordering] */
+	  te.WE.max_doc_count = te.WE.doc_count;
+	  base += sizeof (te.WE.doc_count);
+	      
+	  bcopy ((char *) base, (char *) &te.WE.count, sizeof (te.WE.count));
+	  NTOHUL(te.WE.count);
+	  base += sizeof (te.WE.count);
+	      
+	  bcopy ((char *) base, (char *) &invfp, sizeof (te.WE.invf_ptr));
+	  NTOHUL(invfp);  /* [RPAP - Jan 97: Endian Ordering] */
+	  te.WE.invf_ptr = invfp;
+	  base += sizeof (te.WE.invf_ptr);
+		
+	  /* If the current word is the last word of the block the get the 
+	     length from last_invf_len */
+	  if (res == *num_words - 1)
+	    te.WE.invf_len = *last_invf_len;
+	  else
+	    {
+	      unsigned long next_invfp;
+	      u_char *oldbase = base;
+		  
+	      /* Skip over most of the next word to get to the invf_ptr */
+	      base++;
+	      suff = *base++;
+	      base += suff + sizeof (unsigned long) * 2;
+	      bcopy ((char *) base, (char *) &next_invfp, sizeof (next_invfp));
+	      NTOHUL(next_invfp);  /* [RPAP - Jan 97: Endian Ordering] */
+	      te.WE.invf_len = next_invfp - invfp;
+	      base = oldbase;
+	    }
+	      
+	  /* Add term entry to term list */
+	  /*	  te.query_mask = NULL;*/
+	  AddTermEntry (tl, &te);
+	      
+	  if (res == *num_words - 1 && j + 1 < num_cases)
+	    {
+	      int ii;
+	      /* Read in next block */
+	      block++;
+	      Fseek (sd->stem_file, sd->pos[block] + sd->sdh.blocks_start, 0);
+	      Fread (sd->buffer, sd->sdh.block_size, sizeof (u_char), sd->stem_file);
+	      sd->active = sd->pos[block];
+
+	      first_word = (unsigned long *) (sd->buffer);
+	      NTOHUL(*first_word);  /* [RPAP - Jan 97: Endian Ordering] */
+	      last_invf_len = (unsigned long *) (first_word + 1);
+	      NTOHUL(*last_invf_len);  /* [RPAP - Jan 97: Endian Ordering] */
+	      num_words = (unsigned short *) (last_invf_len + 1);
+	      NTOHUS(*num_words);  /* [RPAP - Jan 97: Endian Ordering] */
+	      index = num_words + 1;
+	      num_indexes = ((*num_words - 1) / sd->sdh.lookback) + 1;
+
+	      /* [RPAP - Jan 97: Endian Ordering] */
+	      for (ii = 0; ii < num_indexes; ii++)
+		NTOHUS(index[ii]);
+
+	      base = (u_char *) (index + num_indexes);
+	      base += index[0];
+	      res = 0;
+	      blk_index = 0;
+	    }
+	  else
+	    res++;
+	} /* end for num_cases */
+    } /* end for num_entries */
+  return (*tl)->num;
+}
+
+
+void 
+FreeStemDict (stemmed_dict * sd)
+{
+  /* [RPAP - Jan 97: Stem Index Change] */
+  if (sd->stem1)
+    FreeStemIdx (sd->stem1);
+  if (sd->stem2)
+    FreeStemIdx (sd->stem2);
+  if (sd->stem3)
+    FreeStemIdx (sd->stem3);
+
+  Xfree (sd->index[0]);
+  Xfree (sd->index);
+  Xfree (sd->buffer);
+  Xfree (sd->pos);
+  Xfree (sd);
+}
+
+/* [RPAP - Jan 97: Stem Index Change] */
+void
+FreeStemIdx (stemmed_idx * si)
+{
+  Xfree (si->index[0]);
+  Xfree (si->index);
+  Xfree (si->buffer);
+  Xfree (si->pos);
+  Xfree (si);
+}
Index: /main/tags/2.25/gsdl/packages/mg/src/text/stem_search.h
===================================================================
--- /main/tags/2.25/gsdl/packages/mg/src/text/stem_search.h	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/mg/src/text/stem_search.h	(revision 21064)
@@ -0,0 +1,43 @@
+/**************************************************************************
+ *
+ * stem_search.h -- Functions for searching the blocked stemmed dictionary
+ * Copyright (C) 1994  Neil Sharman
+ *
+ * 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.
+ *
+ * $Id$
+ *
+ **************************************************************************/
+
+#ifndef H_STEM_SEARCH
+#define H_STEM_SEARCH
+
+stemmed_dict *ReadStemDictBlk (File * stem_file);
+
+stemmed_idx *ReadStemIdxBlk (File * stem_idx_file);
+
+int FindWord (stemmed_dict * sd, u_char * Word, unsigned long *count,
+	      unsigned long *doc_count, unsigned long *invf_ptr,
+	      unsigned long *invf_len);
+
+/* [RPAP - Jan 97: Stem Index Change] */
+int FindWords (stemmed_dict * sd, u_char * sWord, int stem_method, TermList ** tl);
+
+void FreeStemDict (stemmed_dict * sd);
+
+/* [RPAP - Jan 97: Stem Index Change] */
+void FreeStemIdx (stemmed_idx * si);
+
+#endif
Index: /main/tags/2.25/gsdl/packages/mg/src/text/stemmer.c
===================================================================
--- /main/tags/2.25/gsdl/packages/mg/src/text/stemmer.c	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/mg/src/text/stemmer.c	(revision 21064)
@@ -0,0 +1,142 @@
+/**************************************************************************
+ *
+ * stemmer.c -- The stemmer/case folder
+ * Copyright (C) 1994  Neil Sharman
+ *
+ * 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.
+ *
+ * $Id$
+ *
+ **************************************************************************/
+
+#include "sysfuncs.h"
+#include "stemmer.h"
+
+#include "lovinstem.h"
+#include "simplefrenchstem.h"
+#include "unitool.h"
+
+/*
+   $Log$
+   Revision 1.1  1999/08/10 21:18:23  sjboddie
+   renamed mg-1.3d directory mg
+
+   Revision 1.3  1998/12/17 09:12:54  rjmcnab
+
+   Altered mg to process utf-8 encoded Unicode. The main changes
+   are in the parsing of the input, the casefolding, and the stemming.
+
+   Revision 1.2  1998/11/25 07:55:51  rjmcnab
+
+   Modified mg to that you can specify the stemmer you want
+   to use via a command line option. You specify it to
+   mg_passes during the build process. The number of the
+   stemmer that you used is stored within the inverted
+   dictionary header and the stemmed dictionary header so
+   the correct stemmer is used in later stages of building
+   and querying.
+
+   Revision 1.1  1998/11/17 09:35:42  rjmcnab
+   *** empty log message ***
+
+   * Revision 1.3  1994/10/20  03:57:05  tes
+   * I have rewritten the boolean query optimiser and abstracted out the
+   * components of the boolean query.
+   *
+   * Revision 1.2  1994/09/20  04:42:10  tes
+   * For version 1.1
+   *
+ */
+
+static char *RCSID = "$Id$";
+
+
+#define LOVINSTEMMER        0
+#define SIMPLEFRENCHSTEMMER 1
+
+
+/* decode the utf-8 encoded unicode, casefold and then recode 
+ * making sure the final length doesn't exceed the original
+ * length */
+static void unicode_casefold (u_char *word) {
+  unsigned short out[256]; /* temp space */
+  int i;
+  int len;
+
+  /* decode */
+  utf8_word_to_unicode (word, out, 255);
+  len = out[0];
+
+  /* casefold and simplify-fold */
+  for (i=0; i<len; i++) {
+    out[i+1] = unicode_tosimplified(unicode_tolower(out[i+1]));
+  }
+
+  /* re-code */
+  unicode_to_utf8_word (out, word, word[0]+1);
+}
+
+
+int stemmernumber (u_char *stemmerdescription) {
+  u_char descript[MAX_STEM_DESCRIPTION_LEN];
+  int i;
+
+  /* copy and case-fold the description */
+  for (i=0; (stemmerdescription[i] != '\0') && 
+	 (i < MAX_STEM_DESCRIPTION_LEN-1); i++)
+    descript[i] = tolower (stemmerdescription[i]);
+  descript[i] = '\0';
+
+  /* map the description to its number */
+
+  if ((strcmp (descript, "0") == 0) ||
+      (strcmp (descript, "english") == 0) ||
+      (strcmp (descript, "lovin") == 0))
+    return LOVINSTEMMER;
+
+  if ((strcmp (descript, "1") == 1) ||
+      (strcmp (descript, "french") == 0) ||
+      (strcmp (descript, "simplefrench") == 0))
+    return SIMPLEFRENCHSTEMMER;
+
+  return -1;
+}
+
+
+
+/*
+ * Method 0 - Do not stem or case fold.
+ * Method 1 - Case fold.
+ * Method 2 - Stem.
+ * Method 3 - Case fold and stem.
+ *
+ * The stemmer number should be obtained using
+ * the stemmernumber function above.
+ */
+void 
+stemmer (int method, int stemmer, u_char *word) {
+  if (method & 1) {
+    unicode_casefold (word);
+  }
+
+  if (method & 2) {
+    switch (stemmer) {
+    case LOVINSTEMMER: lovinstem (word);
+      break;
+    case SIMPLEFRENCHSTEMMER: simplefrenchstem (word);
+      break;
+    }
+  }
+}
Index: /main/tags/2.25/gsdl/packages/mg/src/text/stemmer.h
===================================================================
--- /main/tags/2.25/gsdl/packages/mg/src/text/stemmer.h	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/mg/src/text/stemmer.h	(revision 21064)
@@ -0,0 +1,64 @@
+/**************************************************************************
+ *
+ * stemmer.h -- The stemmer/case folder
+ * Copyright (C) 1994  Neil Sharman
+ *
+ * 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.
+ *
+ * $Id$
+ *
+ **************************************************************************/
+
+#ifndef STEMMER_H
+#define STEMMER_H
+
+#include "sysfuncs.h"
+
+#define STEMMER_MASK 3
+#define MAX_STEM_DESCRIPTION_LEN 16
+
+/* stemmernumber will return the stemmer for
+ * a description of the stemmer. Stemmer descriptions
+ * are not case sensitive. Valid descriptions are:
+ *
+ *   'English'
+ *   'Lovin'
+ *   'French'
+ *   'SimpleFrench'
+ *
+ * More than one description might result in the same
+ * stemmer number (for example, for stemming 'English'
+ * we currently use the 'Lovin' stemmer).
+ *
+ * stemmerdescription is a normal C, null-terminated,
+ * string.
+ *
+ * stemmernumber will return -1 if it doesn't know the
+ * stemmer description.
+ */
+int stemmernumber (u_char *stemmerdescription);
+
+/*
+ * Method 0 - Do not stem or case fold.
+ * Method 1 - Case fold.
+ * Method 2 - Stem.
+ * Method 3 - Case fold and stem.
+ *
+ * The stemmer number should be obtained using function
+ * stemmernumber above.
+ */
+void stemmer (int method, int stemmer, u_char * word);
+
+#endif
Index: /main/tags/2.25/gsdl/packages/mg/src/text/term_lists.c
===================================================================
--- /main/tags/2.25/gsdl/packages/mg/src/text/term_lists.c	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/mg/src/text/term_lists.c	(revision 21064)
@@ -0,0 +1,331 @@
+/**************************************************************************
+ *
+ * filename -- description
+ * Copyright (C) 1994  Authors
+ *
+ * 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.
+ *
+ * $Id$
+ *
+ **************************************************************************/
+
+/*
+   $Log$
+   Revision 1.1  1999/08/10 21:18:24  sjboddie
+   renamed mg-1.3d directory mg
+
+   Revision 1.2  1998/11/25 07:55:52  rjmcnab
+
+   Modified mg to that you can specify the stemmer you want
+   to use via a command line option. You specify it to
+   mg_passes during the build process. The number of the
+   stemmer that you used is stored within the inverted
+   dictionary header and the stemmed dictionary header so
+   the correct stemmer is used in later stages of building
+   and querying.
+
+   Revision 1.1  1998/11/17 09:35:43  rjmcnab
+   *** empty log message ***
+
+   * Revision 1.1  1994/10/20  03:57:07  tes
+   * I have rewritten the boolean query optimiser and abstracted out the
+   * components of the boolean query.
+   *
+ */
+
+static char *RCSID = "$Id$";
+
+#include "sysfuncs.h"
+
+#include "memlib.h"
+#include "local_strings.h"
+#include "term_lists.h"
+#include "messages.h"
+#include "stemmer.h"
+
+TermList *query_term_list = NULL;
+
+/* =========================================================================
+ * Function: MakeTermList
+ * Description:
+ * Input:
+ * Output:
+ * ========================================================================= */
+TermList *
+MakeTermList (int n)
+{
+  TermList *t;
+  int list_size = (n == 0 ? 1 : n);	/* always allocate at least one node */
+
+  t = Xmalloc (sizeof (TermList) + (list_size - 1) * sizeof (TermEntry));
+  if (!t)
+    FatalError (1, "Unable to allocate term list");
+
+  t->num = n;
+  t->list_size = list_size;
+
+  return t;
+}
+
+/* =========================================================================
+ * Function: ResizeTermList
+ * Description:
+ * Input:
+ * Output:
+ * ========================================================================= */
+
+#define GROWTH_FACTOR 2
+#define MIN_SIZE 2
+
+static void
+ResizeTermList (TermList ** term_list)
+{
+  TermList *tl = *term_list;
+
+  if (tl->num > tl->list_size)
+    {
+      if (tl->list_size)
+	tl->list_size *= GROWTH_FACTOR;
+      else
+	tl->list_size = MIN_SIZE;
+    }
+  tl = Xrealloc (tl, sizeof (TermList) + (tl->list_size - 1) * sizeof (TermEntry));
+
+  if (!tl)
+    FatalError (1, "Unable to resize term list");
+
+  *term_list = tl;
+}
+
+/* =========================================================================
+ * Function: ConvertTermsToString
+ * Description:
+ *      Convert term list into null-terminated string
+ * Input:
+ *      query_term_list = term list
+ * Output:
+ *      str = term string
+ * ========================================================================= */
+
+void
+ConvertTermsToString (TermList * query_term_list, char *str)
+{
+  int i = 0;
+  int total_len = 0;
+
+  /* terms_str should be preallocated */
+  if (!str)
+    return;
+
+  for (i = 0; i < query_term_list->num; i++)
+    {
+      unsigned char *word = query_term_list->TE[i].Word;
+      int len = word[0];
+      total_len += len + 1;	/* +1 for space */
+      if (total_len > MAXTERMSTRLEN)
+	break;
+      strncpy (str, (char *) word + 1, len);
+      str += len;
+      if (i != (query_term_list->num) - 1)
+	{
+	  *str = ' ';
+	  str++;		/* add space gap */
+	}
+
+    }
+  *str = '\0';
+}
+
+/* =========================================================================
+ * Function: ResetTermList
+ * Description: 
+ * Input: 
+ * Output: 
+ * ========================================================================= */
+
+void
+ResetTermList (TermList ** tl)
+{
+  if (*tl)
+    FreeTermList (tl);
+  *tl = MakeTermList (0);
+}
+
+/* =========================================================================
+ * Function: AddTermEntry
+ * Description: 
+ * Input: 
+ * Output: 
+ * ========================================================================= */
+
+int
+AddTermEntry (TermList ** query_term_list, TermEntry * te)
+{
+  TermList *tl = *query_term_list;
+
+  tl->num++;
+  ResizeTermList (query_term_list);
+  tl = *query_term_list;
+
+  /* copy the structure contents */
+  bcopy ((char *) te, (char *) &(tl->TE[tl->num - 1]), sizeof (TermEntry));
+
+  return tl->num - 1;
+}
+
+
+
+/* =========================================================================
+ * Function: AddTerm
+ * Description: Used in boolean parser - see bool_tree   [RPAP - Feb 97: Term Frequency] 
+ * Input: 
+ * Output: 
+ * ========================================================================= */
+
+int
+AddTerm (TermList ** query_term_list, u_char * Word, int Count, int word_num,
+	 u_long count, u_long doc_count, u_long invf_ptr, u_long invf_len, int stemmer_num)  /* [RPAP - Feb 97: Term Frequency] */
+{
+  int j;
+  TermList *tl = *query_term_list;
+
+  /* Look for the word in the already identified terms */
+  for (j = 0; j < tl->num; j++)
+    {
+      TermEntry *te = &(tl->TE[j]);
+      if (compare (te->Word, Word) == 0)
+	{
+	  te->Count++;
+	  return j;
+	}
+    }
+
+
+  {
+    /* Create a new entry in the list for the new word */
+    TermEntry te;
+
+    /* [RPAP - Feb 97: Term Frequency] */
+    te.WE.word_num = word_num;
+    te.WE.count = count;
+    te.WE.doc_count = doc_count;
+    te.WE.max_doc_count = doc_count;   /* [RPAP - Jan 97: Stem Index Change] */
+    te.WE.invf_ptr = invf_ptr;
+    te.WE.invf_len = invf_len;
+    te.Count = Count;
+    te.Word = copy_string (Word);
+    if (!te.Word)
+      FatalError (1, "Could NOT create memory to add term");
+
+    /* [RPAP - Jan 97: Stem Index Change] */
+    te.Stem = copy_string (Word);
+    if (!te.Stem)
+      FatalError (1, "Could NOT create memory to add term");
+    stemmer (2, stemmer_num, te.Stem);
+
+    te.require_match = 0;  /* [RJM - 07/97: Ranked Required Terms] */
+
+    return AddTermEntry (query_term_list, &te);
+  }
+
+}
+
+/* =========================================================================
+ * Function: FreeTermList
+ * Description:
+ * Input:
+ * Output:
+ * ========================================================================= */
+
+void
+FreeTermList (TermList ** the_tl)
+{
+  int j;
+  TermList *tl = *the_tl;
+
+  for (j = 0; j < tl->num; j++)
+    {
+      if (tl->TE[j].Word)
+	Xfree (tl->TE[j].Word);
+      /* [RPAP - Jan 97: Stem Index Change] */
+      if (tl->TE[j].Stem)
+	Xfree (tl->TE[j].Stem);
+    }
+  Xfree (tl);
+
+  *the_tl = NULL;
+}
+
+/* =========================================================================
+ * Function: PrintWordEntry
+ * Description: 
+ * Input: 
+ * Output: 
+ * ========================================================================= */
+
+void
+PrintWordEntry (WordEntry * we, FILE * file)
+{
+  fprintf (file, "we->word_num = %d\n", we->word_num);
+  fprintf (file, "we->count = %ld\n", we->count);
+  fprintf (file, "we->doc_count = %ld\n", we->doc_count);
+  fprintf (file, "we->max_doc_count = %ld\n", we->max_doc_count);
+  fprintf (file, "we->invf_ptr = %ld\n", we->invf_ptr);
+  fprintf (file, "we->invf_len = %ld\n", we->invf_len);
+}
+
+/* =========================================================================
+ * Function: PrintTermEntry
+ * Description: 
+ * Input: 
+ * Output: 
+ * ========================================================================= */
+
+void
+PrintTermEntry (TermEntry * te, FILE * file)
+{
+
+  fprintf (file, "Term Entry\n");
+  fprintf (file, "te->Count = %d\n", te->Count);
+  fprintf (file, "te->Word = %s\n", str255_to_string (te->Word, NULL));
+  if (te->Stem != NULL)
+    fprintf (file, "te->Stem = %s\n", str255_to_string (te->Stem, NULL));  /* [RPAP - Jan 97: Stem Index Change] */
+  fprintf (file, "te->require_match = %i\n", te->require_match);  /* [RJM 07/97: Ranked Required Terms] */
+  PrintWordEntry (&(te->WE), file);
+
+}
+
+/* =========================================================================
+ * Function: PrintTermList
+ * Description: 
+ * Input: 
+ * Output: 
+ * ========================================================================= */
+
+void
+PrintTermList (TermList * tl, FILE * file)
+{
+  int i;
+
+  fprintf (file, "Term List\n");
+  fprintf (file, "tl->list_size = %d\n", tl->list_size);
+  fprintf (file, "tl->num = %d\n", tl->num);
+
+  for (i = 0; i < tl->num; i++)
+    {
+      fprintf (file, "[%d]\n", i);
+      PrintTermEntry (&(tl->TE[i]), file);
+    }
+}
Index: /main/tags/2.25/gsdl/packages/mg/src/text/term_lists.h
===================================================================
--- /main/tags/2.25/gsdl/packages/mg/src/text/term_lists.h	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/mg/src/text/term_lists.h	(revision 21064)
@@ -0,0 +1,102 @@
+/**************************************************************************
+ *
+ * term_lists.h -- description
+ * Copyright (C) 1994  Authors
+ *
+ * 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.
+ *
+ * $Id$
+ *
+ **************************************************************************/
+
+/*
+   $Log$
+   Revision 1.1  1999/08/10 21:18:24  sjboddie
+   renamed mg-1.3d directory mg
+
+   Revision 1.2  1998/11/25 07:55:52  rjmcnab
+
+   Modified mg to that you can specify the stemmer you want
+   to use via a command line option. You specify it to
+   mg_passes during the build process. The number of the
+   stemmer that you used is stored within the inverted
+   dictionary header and the stemmed dictionary header so
+   the correct stemmer is used in later stages of building
+   and querying.
+
+   Revision 1.1  1998/11/17 09:35:44  rjmcnab
+   *** empty log message ***
+
+   * Revision 1.1  1994/10/20  03:57:08  tes
+   * I have rewritten the boolean query optimiser and abstracted out the
+   * components of the boolean query.
+   *
+ */
+
+#ifndef TERM_LISTS_H
+#define TERM_LISTS_H
+
+#include "sysfuncs.h"
+
+#define MAXTERMSTRLEN 1023	/* maximum number of characters in term string */
+
+typedef struct WordEntry
+  {
+    int word_num;		/* Unique number for each different word */
+    u_long count;		/* Number of times the word occurs in the text */
+    u_long doc_count;		/* Number of documents that contain the word */
+    u_long max_doc_count;       /* [RPAP - Jan 97: Stem Index Change] */
+    u_long invf_ptr;		/* This is a byte position of the  
+				   inverted file entry corresponding to the word */
+    u_long invf_len;		/* This is the length of the inverted 
+				   file entry in bytes */
+  }
+WordEntry;
+
+typedef struct TermEntry
+  {
+    WordEntry WE;
+    int Count;			/* The number of times the word occurs in the query */
+    u_char *Word;		/* The word. */
+    u_char *Stem;               /* [RPAP - Jan 97: Stem Index Change] - The stemmed non-cf version of Word */
+    int require_match;          /* [RJM 07/97: Ranked Required Terms] 0=optional match, 1=must match */
+  }
+TermEntry;
+
+typedef struct TermList
+  {
+    int list_size;
+    int num;
+    TermEntry TE[1];
+  }
+TermList;
+
+#define GetNthWE(term_list, n) (&((term_list)->TE[(n)].WE))
+
+/* --- prototypes --- */
+void ConvertTermsToString (TermList * query_term_list, char *str);
+int AddTermEntry (TermList ** query_term_list, TermEntry * te);
+int AddTerm (TermList ** query_term_list, u_char * Word, int Count, int word_num,
+	     u_long count, u_long doc_count, u_long invf_ptr, u_long invf_len, /* [RPAP - Feb 97: Term Frequency] */
+	     int stemmer_num);  
+void ResetTermList (TermList ** tl);
+void FreeTermList (TermList ** the_tl);
+void PrintWordEntry (WordEntry * we, FILE * file);
+void PrintTermEntry (TermEntry * te, FILE * file);
+void PrintTermList (TermList * tl, FILE * file);
+TermList *MakeTermList (int n);
+
+
+#endif
Index: /main/tags/2.25/gsdl/packages/mg/src/text/text.h
===================================================================
--- /main/tags/2.25/gsdl/packages/mg/src/text/text.h	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/mg/src/text/text.h	(revision 21064)
@@ -0,0 +1,176 @@
+/**************************************************************************
+ *
+ * text.h -- Header file for compression related stuff
+ * Copyright (C) 1994  Neil Sharman
+ *
+ * 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.
+ *
+ * $Id$
+ *
+ **************************************************************************/
+
+
+
+#ifndef H_TEXT
+#define H_TEXT
+
+#include "huffman.h"
+
+
+
+
+
+/*****************************************************************************
+ *
+ * There are several different methods of compressing the text of the
+ * database. The following defines list the different methods of text
+ * compression
+ *
+ */
+
+
+/* The dictionary contains all the fragments that occur in the collection
+   i.e. escapes are not possible */
+#define MG_COMPLETE_DICTIONARY 0
+
+
+/* Certain words have been deleted from the dictionary. The words deleted
+   have been used to create the frequency huffman codes of the characters. 
+   This dictionary has an escape code and may be used to compress novel
+   words. This dictionary may fail if there is a novel character. */
+#define MG_PARTIAL_DICTIONARY 1
+
+
+/* This dictionary has an escape so that novel words and non-words can be 
+   coded. The method for coding the novel words and non-words is determined
+   by a dictionary parameter. */
+#define MG_SEED_DICTIONARY 2
+
+
+
+
+
+
+
+
+
+/*****************************************************************************
+ *
+ * With a seed dictionary there are several methods for coding the novel
+ * words and non-words the following defined values specify the different
+ * methods of coding.
+ *
+ */
+
+
+/* Code novel words and non-words character by character using huffman codes.
+   The huffman codes for the word and non-word lengths and characters are 
+   generated from the distribution of lengths and characters in the
+   dictionary. */
+#define MG_NOVEL_HUFFMAN_CHARS 0
+
+
+/* This method codes novel words using binary codes. The novel words are stored
+   in a auxillary dictionary which is built by pass two. */
+#define MG_NOVEL_BINARY 1
+
+
+/* This method codes novel words using delta codes. The novel words are stored
+   in a auxillary dictionary which is built by pass two. */
+#define MG_NOVEL_DELTA 2
+
+
+/* This method codes novel words using hybrid version of delta. The novel
+   words are stored in a auxillary dictionary which is built by pass two. */
+#define MG_NOVEL_HYBRID 3
+
+
+/* This method codes novel words using hybrid version of delta and a MTF
+   operation. The novel words are stored in a auxillary dictionary which
+   is built by pass two. */
+#define MG_NOVEL_HYBRID_MTF 4
+
+
+
+
+
+
+/* This specified an amount of extra space allocated in the
+   compression_dict_header for adding new parameters. As new
+   parameters are added this should be decreased. */
+#define TEXT_PARAMS 15
+
+
+
+typedef struct compression_dict_header
+  {
+    u_long dict_type;
+    u_long novel_method;
+    u_long params[TEXT_PARAMS];
+    u_long num_words[2];
+    u_long num_word_chars[2];
+    u_long lookback;
+  }
+compression_dict_header;
+
+
+typedef struct comp_frags_header
+  {
+    huff_data hd;
+    u_long uncompressed_size;
+    u_long huff_words_size[MAX_HUFFCODE_LEN + 1];
+  }
+comp_frags_header;
+
+
+
+typedef struct compressed_text_header
+  {
+    u_long num_of_docs;
+    u_long num_of_words;	/* number of words in collection */
+    double num_of_bytes; /* [RJM 07/97: 4G limit] */
+    double ratio;
+    u_long length_of_longest_doc;	/* (characters) */
+    u_long dummy;    /* added to make the structure the same on different architectures */
+  }
+compressed_text_header;
+
+
+typedef struct compression_stats_header
+  {
+    u_long num_docs;
+    u_long dummy;   /* added to make the structure the same on different architectures */
+    double num_bytes; /* [RJM 07/97: 4G limit] */
+  }
+compression_stats_header;
+
+
+typedef struct frags_stats_header
+  {
+    u_long num_frags;
+    u_long mem_for_frags;
+  }
+frags_stats_header;
+
+
+typedef struct aux_frags_header
+  {
+    u_long num_frags;
+    u_long mem_for_frags;
+  }
+aux_frags_header;
+
+
+#endif
Index: /main/tags/2.25/gsdl/packages/mg/src/text/text.pass1.c
===================================================================
--- /main/tags/2.25/gsdl/packages/mg/src/text/text.pass1.c	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/mg/src/text/text.pass1.c	(revision 21064)
@@ -0,0 +1,427 @@
+/**************************************************************************
+ *
+ * text.pass1.c -- Text compression (Pass 1)
+ * Copyright (C) 1994  Neil Sharman, Gary Eddy and Alistair Moffat
+ *
+ * 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.
+ *
+ * $Id$
+ *
+ **************************************************************************/
+
+#include "sysfuncs.h"
+
+#include "memlib.h"
+#include "messages.h"
+#include "huffman.h"
+#include "netorder.h"  /* [RPAP - Jan 97: Endian Ordering] */
+
+
+#include "mg_files.h"
+#include "mg.h"
+#include "build.h"
+#include "locallib.h"
+#include "words.h"
+#include "text.h"
+#include "hash.h"
+#include "local_strings.h"
+
+
+/*
+   $Log$
+   Revision 1.1  1999/08/10 21:18:25  sjboddie
+   renamed mg-1.3d directory mg
+
+   Revision 1.2  1998/12/17 09:12:54  rjmcnab
+
+   Altered mg to process utf-8 encoded Unicode. The main changes
+   are in the parsing of the input, the casefolding, and the stemming.
+
+   Revision 1.1  1998/11/17 09:35:46  rjmcnab
+   *** empty log message ***
+
+   * Revision 1.4  1994/11/25  03:47:47  tes
+   * Committing files before adding the merge stuff.
+   *
+   * Revision 1.3  1994/10/20  03:57:09  tes
+   * I have rewritten the boolean query optimiser and abstracted out the
+   * components of the boolean query.
+   *
+   * Revision 1.2  1994/09/20  04:42:13  tes
+   * For version 1.1
+   *
+ */
+
+static char *RCSID = "$Id$";
+
+
+#define POOL_SIZE 1024*1024
+#define INITIAL_HASH_SIZE 7927
+
+
+
+
+
+
+
+typedef struct hash_rec
+  {
+    unsigned long wcnt;		/* word frequency */
+    unsigned long occurance_num;
+    u_char *word;
+  }
+hash_rec;
+
+typedef struct dict_data
+  {
+    hash_rec *HashTable;
+    unsigned long HashSize;
+    unsigned long HashUsed;
+    unsigned long wordnum;
+    unsigned long words_read;
+    unsigned long bytes_diff;
+    huff_data hd;
+  }
+dict_data;
+
+
+
+static unsigned long LongestDoc = 0;
+static unsigned long occurance_num = 0;
+static dict_data DictData[2];
+
+static u_char *Pool;
+static int PoolLeft;
+static double inputbytes = 0; /* [RJM 07/97: 4G limit] */
+static unsigned long MaxMemInUse = 0;
+static unsigned long MemInUse = 0;
+static compression_stats_header csh =
+{0, 0.0}; /* [RJM 07/97: 4G limit] */
+
+
+static void 
+ChangeMem (int Change)
+{
+  MemInUse += Change;
+  if (MemInUse > MaxMemInUse)
+    MaxMemInUse = MemInUse;
+}
+
+
+
+
+int 
+init_text_1 (char *FileName)
+{
+  int which;
+
+  if (!(Pool = Xmalloc (POOL_SIZE)))
+    {
+      Message ("Unable to allocate memory for pool");
+      return (COMPERROR);
+    }
+  PoolLeft = POOL_SIZE;
+  ChangeMem (POOL_SIZE);
+
+  for (which = 1; which >= 0; which--)
+    {
+      u_char *word;
+      hash_rec *ent;
+      dict_data *dd = &DictData[which];
+
+      dd->wordnum = 0;
+      dd->words_read = 0;
+      dd->bytes_diff = 0;
+      dd->HashSize = INITIAL_HASH_SIZE;
+      dd->HashUsed = 0;
+
+      if (!(dd->HashTable = Xmalloc (sizeof (hash_rec) * dd->HashSize)))
+	{
+	  Message ("Unable to allocate memory for table");
+	  return (COMPERROR);
+	}
+      ChangeMem (sizeof (hash_rec) * dd->HashSize);
+      bzero ((char *) (dd->HashTable), sizeof (hash_rec) * dd->HashSize);
+
+      word = Pool;
+      *Pool++ = '\0';
+      PoolLeft--;
+      {
+	register u_char *wptr;
+	register int hsize = dd->HashSize;
+	register unsigned long hashval, step;
+
+	HASH (hashval, step, word, hsize);
+	wptr = (dd->HashTable + hashval)->word;
+	while (wptr)
+	  {
+	    hashval += step;
+	    if (hashval >= hsize)
+	      hashval -= hsize;
+	    wptr = (dd->HashTable + hashval)->word;
+	  }
+	ent = dd->HashTable + hashval;
+      }
+      ent->wcnt = 1;
+      ent->word = word;
+      dd->HashUsed = 1;
+    }
+  return (COMPALLOK);
+}
+
+
+
+
+int 
+process_text_1 (u_char * s_in, int l_in)
+{
+  int which;
+  u_char *end = s_in + l_in - 1;
+
+  if (l_in > LongestDoc)
+    LongestDoc = l_in;
+
+  csh.num_docs++;
+  csh.num_bytes += l_in;
+
+  which = inaword (s_in, end);
+  /*
+   ** Alternately parse off words and non-words from the input
+   ** stream beginning with a non-word. Each token is then
+   ** inserted into the set if it does not exist or has it's
+   ** frequency count incremented if it does.
+   */
+  for (; s_in <= end; which = !which)
+    {
+      u_char Word[MAXWORDLEN + 1];
+      dict_data *dd = &DictData[which];
+
+      /* First parse a word or non-word out of the string */
+      if (which)
+	PARSE_WORD (Word, s_in, end);
+      else
+	PARSE_NON_WORD (Word, s_in, end);
+
+      dd->wordnum++;
+      inputbytes += *Word;
+      dd->words_read++;
+
+      /* Search the hash table for Word */
+      {
+	register unsigned long hashval, step;
+	register int hsize = dd->HashSize;
+	HASH (hashval, step, Word, hsize);
+	for (;;)
+	  {
+	    register u_char *s1;
+	    register u_char *s2;
+	    register int len;
+	    register hash_rec *ent;
+	    ent = dd->HashTable + hashval;
+	    if (!ent->word)
+	      {
+		int len = *Word + 1;
+		if (len > PoolLeft)
+		  {
+		    if (!(Pool = Xmalloc (POOL_SIZE)))
+		      {
+			Message ("Unable to allocate memory for pool");
+			return (COMPERROR);
+		      }
+		    PoolLeft = POOL_SIZE;
+		    ChangeMem (POOL_SIZE);
+		  }
+		ent->occurance_num = occurance_num++;
+		ent->wcnt = 1;
+		ent->word = Pool;
+		memcpy (Pool, Word, len);
+		Pool += len;
+		PoolLeft -= len;
+		dd->HashUsed++;
+		dd->bytes_diff += Word[0];
+		break;
+	      }
+
+	    /* Compare the words */
+	    s1 = Word;
+	    s2 = ent->word;
+	    len = *s1 + 1;
+	    for (; len; len--)
+	      if (*s1++ != *s2++)
+		break;
+
+	    if (len)
+	      {
+		hashval = (hashval + step);
+		if (hashval >= hsize)
+		  hashval -= hsize;
+	      }
+	    else
+	      {
+		ent->wcnt++;
+		break;
+	      }
+	  }
+      }
+
+
+      if (dd->HashUsed >= dd->HashSize >> 1)
+	{
+	  hash_rec *ht;
+	  unsigned long size;
+	  unsigned long i;
+	  size = prime (dd->HashSize * 2);
+	  if (!(ht = Xmalloc (sizeof (hash_rec) * size)))
+	    {
+	      Message ("Unable to allocate memory for table");
+	      return (COMPERROR);
+	    }
+	  ChangeMem (sizeof (hash_rec) * size);
+	  bzero ((char *) ht, sizeof (hash_rec) * size);
+
+	  for (i = 0; i < dd->HashSize; i++)
+	    if (dd->HashTable[i].word)
+	      {
+		register u_char *wptr;
+		register unsigned long hashval, step;
+
+		wptr = dd->HashTable[i].word;
+		HASH (hashval, step, wptr, size);
+		wptr = (ht + hashval)->word;
+		while (wptr)
+		  {
+		    hashval += step;
+		    if (hashval >= size)
+		      hashval -= size;
+		    wptr = (ht + hashval)->word;
+		  }
+		ht[hashval] = dd->HashTable[i];
+	      }
+	  Xfree (dd->HashTable);
+	  ChangeMem (-sizeof (hash_rec) * dd->HashSize);
+	  dd->HashTable = ht;
+	  dd->HashSize = size;
+
+
+	}
+    }
+  return (COMPALLOK);
+}				/* encode */
+
+
+
+static int 
+PackHashTable (dict_data * dd)
+{
+  int s, d;
+  for (s = d = 0; s < dd->HashSize; s++)
+    if (dd->HashTable[s].word)
+      dd->HashTable[d++] = dd->HashTable[s];
+  ChangeMem (-sizeof (hash_rec) * dd->HashSize);
+  ChangeMem (sizeof (hash_rec) * dd->HashUsed);
+  if (!(dd->HashTable = Xrealloc (dd->HashTable,
+				  sizeof (hash_rec) * dd->HashUsed)))
+    {
+      Message ("Out of memory");
+      return COMPERROR;
+    }
+  dd->HashSize = dd->HashUsed;
+  return COMPALLOK;
+}
+
+
+
+
+
+static int 
+ent_comp (const void *s1, const void *s2)
+{
+  return casecompare (((hash_rec *) s1)->word, ((hash_rec *) s2)->word);
+}
+
+
+
+static void 
+WriteHashTable (FILE * fp, dict_data * dd)
+{
+  frags_stats_header fsh;
+  u_long j = 0;
+  u_char *curr;
+
+  if (PackHashTable (dd) == COMPERROR)
+    return;
+
+  qsort (dd->HashTable, dd->HashUsed, sizeof (hash_rec), ent_comp);
+
+  fsh.num_frags = dd->HashSize;
+  fsh.mem_for_frags = dd->HashSize;
+  for (j = 0; j < dd->HashSize; j++)
+    fsh.mem_for_frags += dd->HashTable[j].word[0];
+
+  /* [RPAP - Jan 97: Endian Ordering] */
+  HTONUL(fsh.num_frags);
+  HTONUL(fsh.mem_for_frags);
+
+  fwrite (&fsh, sizeof (fsh), 1, fp);
+
+  for (j = 0; j < dd->HashSize; j++)
+    {
+      curr = dd->HashTable[j].word;
+
+      /* [RPAP - Jan 97: Endian Ordering] */
+      HTONUL(dd->HashTable[j].wcnt);
+      HTONUL(dd->HashTable[j].occurance_num);
+
+      fwrite (&dd->HashTable[j].wcnt, sizeof (dd->HashTable[j].wcnt), 1, fp);
+      fwrite (&dd->HashTable[j].occurance_num,
+	      sizeof (dd->HashTable[j].occurance_num), 1, fp);
+
+      /* [RPAP - Jan 97: Endian Ordering] */
+      NTOHUL(dd->HashTable[j].wcnt);
+      NTOHUL(dd->HashTable[j].occurance_num);
+
+      fwrite (curr, sizeof (u_char), curr[0] + 1, fp);
+    }
+}
+
+
+int 
+done_text_1 (char *file_name)
+{
+  char *temp_str;
+  FILE *fp;
+
+  if (!(fp = create_file (file_name, TEXT_STATS_DICT_SUFFIX, "wb",
+			  MAGIC_STATS_DICT, MG_MESSAGE)))  /* [RPAP - Feb 97: WIN32 Port] */
+    return COMPERROR;
+
+  temp_str = msg_prefix;
+  msg_prefix = "text.pass1";
+
+  /* [RPAP - Jan 97: Endian Ordering] */
+  HTONUL(csh.num_docs);
+  HTOND(csh.num_bytes); /* [RJM 07/97: 4G limit] */
+
+  fwrite (&csh, sizeof (csh), 1, fp);
+
+  /* [RPAP - Jan 97: Endian Ordering] */
+  NTOHUL(csh.num_docs);
+  NTOHD(csh.num_bytes); /* [RJM 07/97: 4G limit] */
+
+  WriteHashTable (fp, &DictData[0]);
+  WriteHashTable (fp, &DictData[1]);
+  msg_prefix = temp_str;
+  return COMPALLOK;
+}				/* done_encode */
Index: /main/tags/2.25/gsdl/packages/mg/src/text/text.pass2.c
===================================================================
--- /main/tags/2.25/gsdl/packages/mg/src/text/text.pass2.c	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/mg/src/text/text.pass2.c	(revision 21064)
@@ -0,0 +1,776 @@
+/**************************************************************************
+ *
+ * text.pass2.c -- Text compression (Pass 2)
+ * Copyright (C) 1994  Neil Sharman, Gary Eddy and Alistair Moffat
+ *
+ * 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.
+ *
+ * $Id$
+ *
+ **************************************************************************/
+
+
+#include "sysfuncs.h"
+
+#include "memlib.h"
+#include "messages.h"
+#include "local_strings.h"
+#include "bitio_m_mem.h"
+#include "bitio_m.h"
+#include "huffman.h"
+#include "bitio_stdio.h"
+#include "huffman_stdio.h"
+#include "netorder.h"  /* [RPAP - Jan 97: Endian Ordering] */
+
+#include "mg.h"
+#include "mg_files.h"
+#include "build.h"
+#include "words.h"
+#include "text.h"
+#include "hash.h"
+#include "locallib.h"
+#include "comp_dict.h"
+
+
+
+
+/*
+   $Log$
+   Revision 1.1  1999/08/10 21:18:25  sjboddie
+   renamed mg-1.3d directory mg
+
+   Revision 1.2  1998/12/17 09:12:54  rjmcnab
+
+   Altered mg to process utf-8 encoded Unicode. The main changes
+   are in the parsing of the input, the casefolding, and the stemming.
+
+   Revision 1.1  1998/11/17 09:35:47  rjmcnab
+   *** empty log message ***
+
+   * Revision 1.3  1994/10/20  03:57:10  tes
+   * I have rewritten the boolean query optimiser and abstracted out the
+   * components of the boolean query.
+   *
+   * Revision 1.2  1994/09/20  04:42:14  tes
+   * For version 1.1
+   *
+ */
+
+static char *RCSID = "$Id$";
+
+#define POOL_SIZE 1024*256
+
+typedef struct char_pool
+  {
+    struct char_pool *next;
+    u_long left;
+    u_char *ptr;
+    u_char pool[POOL_SIZE];
+  }
+char_pool;
+
+typedef struct novel_hash_rec
+  {
+    u_long ordinal_num;
+    u_char *word;
+  }
+novel_hash_rec;
+
+
+#define INITIAL_HASH_SIZE 7927
+#define MAX_SWAPS 10000
+
+typedef struct novel_hash_table
+  {
+    novel_hash_rec *HashTable;
+    u_long HashSize, HashUsed;
+    char_pool *first_pool;
+    char_pool *pool;
+    u_long next_num, binary_start;
+    novel_hash_rec **code_to_nhr;
+  }
+novel_hash_table;
+
+
+static FILE *text, *text_idx;
+
+static u_char *comp_buffer;
+
+static u_long text_length;
+
+/* [RJM 07/97: 4G limit] */
+static double stats_in_tot_bytes = 0.0;
+static double stats_in_bytes = 0.0;
+static double stats_out_bytes = 0.0;
+
+
+static novel_hash_table nht[2];
+
+static u_long prefix_len = 0;
+
+int blk_start[2][33], blk_end[2][33];
+
+
+static char_pool *
+new_pool (char_pool * pool)
+{
+  char_pool *p = Xmalloc (sizeof (char_pool));
+  if (!p)
+    FatalError (1, "Unable to allocate memory for pool");
+  if (pool)
+    pool->next = p;
+  p->next = NULL;
+  p->left = POOL_SIZE;
+  p->ptr = p->pool;
+  return p;
+}
+
+
+
+int 
+init_text_2 (char *file_name)
+{
+  char path[512];
+  int i;
+
+  if (LoadCompressionDictionary (make_name (file_name, TEXT_DICT_SUFFIX,
+					    path)) == COMPERROR)
+    return COMPERROR;
+
+  if (!(text = create_file (file_name, TEXT_SUFFIX, "w+b",
+			    MAGIC_TEXT, MG_MESSAGE)))  /* [RPAP - Feb 97: WIN32 Port] */
+    return COMPERROR;
+
+  bzero ((char *) &cth, sizeof (cth));
+
+  if (fwrite (&cth, sizeof (cth), 1, text) != 1)
+    return COMPERROR;
+
+  text_length = sizeof (u_long) + sizeof (cth);
+
+  if (!(text_idx = create_file (file_name, TEXT_IDX_SUFFIX, "w+b",
+				MAGIC_TEXI, MG_MESSAGE)))  /* [RPAP - Feb 97: WIN32 Port] */
+    return COMPERROR;
+
+  if (fwrite (&cth, sizeof (cth), 1, text_idx) != 1)
+    return COMPERROR;
+
+  if (!(comp_buffer = Xmalloc (sizeof (u_char) * buf_size)))
+    {
+      Message ("No memory for compression buffer");
+      return (COMPERROR);
+    }
+
+#if 0
+  MaxMemInUse += sizeof (u_char) * buf_size;
+#endif
+
+  if (cdh.novel_method != MG_NOVEL_HUFFMAN_CHARS)
+    for (i = 0; i <= 1; i++)
+      {
+	nht[i].HashSize = INITIAL_HASH_SIZE;
+	nht[i].HashTable = Xmalloc (sizeof (novel_hash_rec) * nht[i].HashSize);
+	bzero ((char *) nht[i].HashTable,
+	       sizeof (novel_hash_rec) * nht[i].HashSize);
+	nht[i].HashUsed = 0;
+	nht[i].HashSize = INITIAL_HASH_SIZE;
+	nht[i].pool = nht[i].first_pool = new_pool (NULL);
+	nht[i].next_num = 1;
+	nht[i].binary_start = 1;
+	if (cdh.novel_method == MG_NOVEL_HYBRID_MTF)
+	  nht[i].code_to_nhr = Xmalloc (sizeof (novel_hash_rec *) *
+					((nht[i].HashSize >> 1) + 2));
+	else
+	  nht[i].code_to_nhr = NULL;
+	if (cdh.novel_method == MG_NOVEL_HYBRID ||
+	    cdh.novel_method == MG_NOVEL_HYBRID_MTF)
+	  {
+	    int num;
+	    num = 1;
+	    blk_start[i][0] = 0;
+	    blk_end[i][0] = cdh.num_words[i] - 1;
+	    while (num < 33)
+	      {
+		blk_start[i][num] = blk_end[i][num - 1] + 1;
+		blk_end[i][num] = blk_start[i][num] +
+		  (blk_end[i][num - 1] - blk_start[i][num - 1]) * 2;
+		num++;
+	      }
+	  }
+      }
+
+  return (COMPALLOK);
+}
+
+
+
+int 
+ic (void *a, void *b)
+{
+  return *((int *) a) - *((int *) b);
+}
+
+
+
+/* #define DOCDUMP 477 */
+
+int 
+process_text_2 (u_char * s_in, int l_in)
+{
+  int which, byte_length;
+  u_char *end = s_in + l_in - 1;
+  int novels_used[2];
+  int swaps[2][MAX_SWAPS];
+
+  which = inaword (s_in, end);
+
+  ENCODE_START (comp_buffer, buf_size)
+
+    ENCODE_BIT (which);
+
+  if (cdh.novel_method == MG_NOVEL_BINARY)
+    {
+      DELTA_ENCODE_L (nht[0].binary_start, prefix_len);
+      DELTA_ENCODE_L (nht[1].binary_start, prefix_len);
+    }
+
+  novels_used[0] = novels_used[1] = 0;
+
+#ifdef DOCDUMP
+  if (cth.num_of_docs == DOCDUMP)
+    {
+      printf ("---------------------------------------------------\n");
+      printf ("which = %d\n", which);
+    }
+#endif
+
+  for (; s_in <= end; which = !which)
+    {
+      u_char Word[MAXWORDLEN + 1];
+      int res;
+
+      if (which)
+	cth.num_of_words++;
+
+      /* First parse a word or non-word out of the string */
+      if (which)
+	PARSE_WORD (Word, s_in, end);
+      else
+	PARSE_NON_WORD (Word, s_in, end);
+
+#ifdef DOCDUMP
+      if (cth.num_of_docs == DOCDUMP)
+	{
+	  printf ("%sword : \"%.*s\"", which ? "    " : "non-", Word[0], Word + 1);
+	}
+#endif
+
+      /* Search the hash table for Word */
+      if (ht[which])
+	{
+	  register unsigned long hashval, step;
+	  register int tsize = ht[which]->size;
+	  register u_char **wptr;
+	  HASH (hashval, step, Word, tsize);
+	  for (;;)
+	    {
+	      register u_char *s1;
+	      register u_char *s2;
+	      register int len;
+	      wptr = ht[which]->table[hashval];
+	      if (wptr == NULL)
+		{
+		  res = COMPERROR;
+		  break;
+		}
+
+	      /* Compare the words */
+	      s1 = Word;
+	      s2 = *wptr;
+	      len = *s1 + 1;
+	      for (; len; len--)
+		if (*s1++ != *s2++)
+		  break;
+
+	      if (len)
+		{
+		  hashval += step;
+		  if (hashval >= tsize)
+		    hashval -= tsize;
+		}
+	      else
+		{
+		  res = ht[which]->table[hashval] - ht[which]->words;
+		  break;
+		}
+	    }
+	}
+      else
+	res = COMPERROR;
+      /* Check that the word was found in the dictionary */
+      if (res == COMPERROR)
+	{
+	  if (cdh.dict_type == MG_COMPLETE_DICTIONARY)
+	    {
+	      Message ("Unknown word \"%.*s\"\n", *Word, Word + 1);
+	      return (COMPERROR);
+	    }
+	  if (cdh.dict_type == MG_PARTIAL_DICTIONARY)
+	    {
+	      u_long i;
+	      if (ht[which])
+		{
+		  res = ht[which]->hd->num_codes - 1;
+		  HUFF_ENCODE (res, ht[which]->codes, ht[which]->hd->clens);
+		}
+	      HUFF_ENCODE (Word[0], lens_codes[which], lens_huff[which].clens);
+	      for (i = 0; i < Word[0]; i++)
+		HUFF_ENCODE (Word[i + 1], char_codes[which],
+			     char_huff[which].clens);
+	    }
+	  if (cdh.dict_type == MG_SEED_DICTIONARY)
+	    {
+	      if (ht[which])
+		{
+		  res = ht[which]->hd->num_codes - 1;
+		  HUFF_ENCODE (res, ht[which]->codes, ht[which]->hd->clens);
+		}
+	      switch (cdh.novel_method)
+		{
+		case MG_NOVEL_HUFFMAN_CHARS:
+		  {
+		    u_long i;
+		    HUFF_ENCODE (Word[0], lens_codes[which],
+				 lens_huff[which].clens);
+		    for (i = 0; i < Word[0]; i++)
+		      HUFF_ENCODE (Word[i + 1], char_codes[which],
+				   char_huff[which].clens);
+		  }
+		  break;
+		case MG_NOVEL_BINARY:
+		case MG_NOVEL_DELTA:
+		case MG_NOVEL_HYBRID:
+		case MG_NOVEL_HYBRID_MTF:
+		  {
+		    register unsigned long hashval, step;
+		    register novel_hash_table *h = &nht[which];
+		    register int hsize = h->HashSize;
+		    register novel_hash_rec *ent;
+		    HASH (hashval, step, Word, hsize);
+		    for (;;)
+		      {
+			register u_char *s1, *s2;
+			register int len;
+			ent = h->HashTable + hashval;
+			if (!ent->word)
+			  {
+			    int len = *Word + 1;
+			    if (len > h->pool->left)
+			      h->pool = new_pool (h->pool);
+			    ent->word = h->pool->ptr;
+			    ent->ordinal_num = h->next_num++;
+			    if (cdh.novel_method == MG_NOVEL_HYBRID_MTF)
+			      h->code_to_nhr[ent->ordinal_num - 1] = ent;
+			    memcpy (h->pool->ptr, Word, len);
+			    h->pool->ptr += len;
+			    h->pool->left -= len;
+			    h->HashUsed++;
+			    break;
+			  }
+			/* Compare the words */
+			s1 = Word;
+			s2 = ent->word;
+			len = *s1 + 1;
+			for (; len; len--)
+			  if (*s1++ != *s2++)
+			    break;
+
+			if (!len)
+			  break;
+
+			hashval = (hashval + step);
+			if (hashval >= hsize)
+			  hashval -= hsize;
+		      }
+
+		    switch (cdh.novel_method)
+		      {
+		      case MG_NOVEL_BINARY:
+			{
+			  BINARY_ENCODE (ent->ordinal_num, h->binary_start);
+			  if (ent->ordinal_num == h->binary_start)
+			    h->binary_start++;
+			}
+			break;
+		      case MG_NOVEL_DELTA:
+			{
+			  DELTA_ENCODE (ent->ordinal_num);
+			}
+			break;
+		      case MG_NOVEL_HYBRID:
+			{
+			  int k = 0;
+			  int j = ent->ordinal_num - 1;
+			  while (j > blk_end[which][k])
+			    k++;
+			  assert (j - blk_start[which][k] + 1 >= 1 &&
+				  j - blk_start[which][k] + 1 <=
+			       blk_end[which][k] - blk_start[which][k] + 1);
+
+			  GAMMA_ENCODE (k + 1);
+			  BINARY_ENCODE (j - blk_start[which][k] + 1,
+					 blk_end[which][k] -
+					 blk_start[which][k] + 1);
+			}
+			break;
+		      case MG_NOVEL_HYBRID_MTF:
+			{
+			  int k = 0;
+			  int j = ent->ordinal_num - 1;
+			  while (j > blk_end[which][k])
+			    k++;
+			  assert (j - blk_start[which][k] + 1 >= 1 &&
+				  j - blk_start[which][k] + 1 <=
+			       blk_end[which][k] - blk_start[which][k] + 1);
+			  GAMMA_ENCODE (k + 1);
+			  BINARY_ENCODE (j - blk_start[which][k] + 1,
+					 blk_end[which][k] -
+					 blk_start[which][k] + 1);
+
+			  if (ent->ordinal_num - 1 >= novels_used[which])
+			    {
+			      int a = novels_used[which];
+			      int b = ent->ordinal_num - 1;
+			      novel_hash_rec *temp;
+
+
+/*                            fprintf(stderr, "a = %d , b = %d\n", a, b);
+ */
+			      temp = h->code_to_nhr[a];
+			      h->code_to_nhr[a] = h->code_to_nhr[b];
+			      h->code_to_nhr[b] = temp;
+			      h->code_to_nhr[a]->ordinal_num = a + 1;
+			      h->code_to_nhr[b]->ordinal_num = b + 1;
+			      if (novels_used[which] == MAX_SWAPS)
+				FatalError (1, "Not enough mem for swapping");
+			      swaps[which][novels_used[which]] = b;
+			      novels_used[which]++;
+			    }
+			}
+			break;
+		      }
+		    if (h->HashUsed >= h->HashSize >> 1)
+		      {
+			novel_hash_rec *ht;
+			unsigned long size;
+			unsigned long i;
+			size = prime (h->HashSize * 2);
+			if (cdh.novel_method == MG_NOVEL_HYBRID_MTF)
+			  {
+			    Xfree (h->code_to_nhr);
+			    h->code_to_nhr = Xmalloc (sizeof (novel_hash_rec *) *
+						      ((size >> 1) + 2));
+			  }
+			if (!(ht = Xmalloc (sizeof (novel_hash_rec) * size)))
+			  {
+			    Message ("Unable to allocate memory for table");
+			    return (COMPERROR);
+			  }
+			bzero ((char *) ht, sizeof (novel_hash_rec) * size);
+
+			for (i = 0; i < h->HashSize; i++)
+			  if (h->HashTable[i].word)
+			    {
+			      register u_char *wptr;
+			      register unsigned long hashval, step;
+
+			      wptr = h->HashTable[i].word;
+			      HASH (hashval, step, wptr, size);
+			      wptr = (ht + hashval)->word;
+			      while (wptr)
+				{
+				  hashval += step;
+				  if (hashval >= size)
+				    hashval -= size;
+				  wptr = (ht + hashval)->word;
+				}
+			      ht[hashval] = h->HashTable[i];
+			      if (cdh.novel_method == MG_NOVEL_HYBRID_MTF)
+				h->code_to_nhr[ht[hashval].ordinal_num - 1] =
+				  &ht[hashval];
+			    }
+			Xfree (h->HashTable);
+			h->HashTable = ht;
+			h->HashSize = size;
+		      }
+		  }
+		  break;
+		}
+	    }
+	}
+      else
+	{
+	  HUFF_ENCODE (res, ht[which]->codes, ht[which]->hd->clens);
+#ifdef DOCDUMP
+	  if (cth.num_of_docs == DOCDUMP)
+	    {
+	      printf ("   %d %d\n", ht[which]->hd->clens[res],
+		      ht[which]->codes[res]);
+	    }
+#endif
+	}
+    }
+
+
+  /* Add a 1 bit onto the end of the buffer the remaining bits in the last
+     byte will all be zero */
+
+  ENCODE_BIT (1);
+
+  ENCODE_FLUSH;
+
+  byte_length = __pos - __base;
+  if (!__remaining)
+    {
+      Message ("The end of the buffer was probably overrun");
+      return COMPERROR;
+    }
+
+  ENCODE_DONE
+
+#ifdef DOCDUMP
+    if (cth.num_of_docs == DOCDUMP)
+    {
+      printf ("unused bits = %d\n", bits_unused);
+    }
+#endif
+
+  HTONUL(text_length);  /* [RPAP - Jan 97: Endian Ordering] */
+  fwrite (&text_length, sizeof (text_length), 1, text_idx);
+  NTOHUL(text_length);  /* [RPAP - Jan 97: Endian Ordering] */
+  text_length += byte_length;
+
+#ifdef DOCDUMP
+  if (cth.num_of_docs == DOCDUMP)
+    {
+      int i;
+      for (i = 0; i < byte_length; i++)
+	printf ("%02x ", comp_buffer[i]);
+      printf ("\n");
+    }
+#endif
+
+  if (cdh.novel_method == MG_NOVEL_HYBRID_MTF)
+    for (which = 0; which <= 1; which++)
+      for (novels_used[which]--; novels_used[which] >= 0; novels_used[which]--)
+	{
+	  int a = novels_used[which];
+	  int b = swaps[which][novels_used[which]];
+	  novel_hash_rec *temp;
+	  temp = nht[which].code_to_nhr[a];
+	  nht[which].code_to_nhr[a] = nht[which].code_to_nhr[b];
+	  nht[which].code_to_nhr[b] = temp;
+	  nht[which].code_to_nhr[a]->ordinal_num = a + 1;
+	  nht[which].code_to_nhr[b]->ordinal_num = b + 1;
+	}
+
+
+  fwrite (comp_buffer, sizeof (*comp_buffer), byte_length, text);
+
+  if ((double) l_in / (double) byte_length > cth.ratio)
+    cth.ratio = (double) l_in / (double) byte_length;
+
+  cth.num_of_docs++;
+  if (l_in > cth.length_of_longest_doc)
+    cth.length_of_longest_doc = l_in;
+
+  cth.num_of_bytes += l_in;
+
+  if (Comp_Stats)
+    {
+      stats_in_tot_bytes += l_in;
+      stats_in_bytes += l_in;
+      stats_out_bytes += byte_length;
+      if (stats_in_bytes >= comp_stat_point)
+	{
+	  fprintf (Comp_Stats, "%10.0f %10.0f %10.0f %f\n", stats_in_tot_bytes,
+		   stats_in_bytes, stats_out_bytes,
+		   (double) stats_out_bytes / (double) stats_in_bytes);
+	  stats_in_bytes = 0.0;
+	  stats_out_bytes = 0.0;
+	}
+    }
+
+  return COMPALLOK;
+}
+
+
+
+
+
+
+int 
+write_aux_dict (char *FileName)
+{
+  int i;
+  FILE *aux;
+  if (!(aux = create_file (FileName, TEXT_DICT_AUX_SUFFIX, "wb",
+			   MAGIC_AUX_DICT, MG_MESSAGE)))  /* [RPAP - Feb 97: WIN32 Port] */
+    return COMPERROR;
+
+  for (i = 0; i <= 1; i++)
+    {
+      aux_frags_header afh;
+      char_pool *cp;
+
+      afh.num_frags = nht[i].HashUsed;
+      afh.mem_for_frags = 0;
+      for (cp = nht[i].first_pool; cp; cp = cp->next)
+	afh.mem_for_frags += POOL_SIZE - cp->left;
+
+      /* [RPAP - Jan 97: Endian Ordering] */
+      HTONUL(afh.num_frags);
+      HTONUL(afh.mem_for_frags);
+
+      fwrite (&afh, sizeof (afh), 1, aux);
+
+      for (cp = nht[i].first_pool; cp; cp = cp->next)
+	fwrite (cp->pool, POOL_SIZE - cp->left, sizeof (u_char), aux);
+    }
+  fclose (aux);
+  return COMPALLOK;
+}
+
+
+void 
+estimate_compressed_aux_dict (void)
+{
+  int i;
+  u_long aux_compressed = 0, total_uncomp = 0;
+  for (i = 0; i <= 1; i++)
+    {
+      int j;
+      long chars[256], fchars[256];
+      long lens[16], flens[16];
+      char_pool *cp;
+      bzero ((char *) chars, sizeof (chars));
+      bzero ((char *) lens, sizeof (lens));
+      for (cp = nht[i].first_pool; cp; cp = cp->next)
+	{
+	  u_char *buf = cp->pool;
+	  while (buf != cp->ptr)
+	    {
+	      int len = *buf++;
+	      lens[len]++;
+	      total_uncomp += len + 4;
+	      for (; len; len--)
+		chars[*buf++]++;
+	    }
+	}
+      for (j = 0; j < 256; j++)
+	if (!chars[j] && PESINAWORD (j) == i)
+	  fchars[j] = 1;
+	else
+	  fchars[j] = chars[j];
+      for (j = 0; j < 16; j++)
+	if (!lens[j])
+	  flens[j] = 1;
+	else
+	  flens[j] = lens[j];
+
+      aux_compressed += (Calculate_Huffman_Size (16, flens, lens) +
+			 Calculate_Huffman_Size (256, fchars, chars)) / 8;
+
+    }
+
+  Message ("Aux dictionary (Uncompressed) %.2f Mb ( %u bytes   %0.3f %%)",
+	   total_uncomp / 1024.0 / 1024, total_uncomp,
+	   (total_uncomp * 100.0) / bytes_processed);
+  Message ("Aux dictionary (Compressed)   %.2f Mb ( %.0f bytes   %0.3f %%)",
+	   aux_compressed / 1024.0 / 1024, aux_compressed * 1.0,
+	   (aux_compressed * 100.0) / bytes_processed);
+}
+
+
+
+
+
+
+int 
+done_text_2 (char *FileName)
+{
+  if (Comp_Stats)
+    fprintf (Comp_Stats, "%10.0f %10.0f %10.0f %f\n", stats_in_tot_bytes,
+	     stats_in_bytes, stats_out_bytes,
+	     (double) stats_out_bytes / (double) stats_in_bytes);
+
+  HTONUL(text_length);  /* [RPAP - Jan 97: Endian Ordering] */
+  fwrite (&text_length, sizeof (text_length), 1, text_idx);
+  NTOHUL(text_length);  /* [RPAP - Jan 97: Endian Ordering] */
+
+  /* [RPAP - Jan 97: Endian Ordering] */
+  HTONUL(cth.num_of_docs);
+  HTOND(cth.num_of_bytes); /* [RJM 07/97: 4G limit] */
+  HTONUL(cth.num_of_words);
+  HTONUL(cth.length_of_longest_doc);
+  HTOND(cth.ratio);
+
+  if (fseek (text_idx, sizeof (u_long), SEEK_SET) == -1 ||
+      fwrite (&cth, sizeof (cth), 1, text_idx) != 1)
+    return COMPERROR;
+  fclose (text_idx);
+
+  if (fseek (text, sizeof (u_long), SEEK_SET) == -1 ||
+      fwrite (&cth, sizeof (cth), 1, text) != 1)
+    return COMPERROR;
+  fclose (text);
+
+  /* [RPAP - Jan 97: Endian Ordering] */
+  NTOHUL(cth.num_of_docs);
+  NTOHD(cth.num_of_bytes); /* [RJM 07/97: 4G limit] */
+  NTOHUL(cth.num_of_words);
+  NTOHUL(cth.length_of_longest_doc);
+  NTOHD(cth.ratio);
+  
+
+  Message ("Compressed Text %.2f Mb ( %u bytes   %0.3f %%)",
+	   text_length / 1024.0 / 1024.0, text_length,
+	   (text_length * 100.0) / bytes_processed);
+  Message ("Words portion of the dictionary %.2f Mb ( %.0f bytes   %0.3f %%)",
+	   Words_disk / 1024.0 / 1024, Words_disk * 1.0,
+	   (Words_disk * 100.0) / bytes_processed);
+
+  if (cdh.dict_type != MG_COMPLETE_DICTIONARY &&
+      (cdh.novel_method == MG_NOVEL_BINARY ||
+       cdh.novel_method == MG_NOVEL_DELTA ||
+       cdh.novel_method == MG_NOVEL_HYBRID ||
+       cdh.novel_method == MG_NOVEL_HYBRID_MTF))
+    {
+      if (write_aux_dict (FileName) == COMPERROR)
+	return COMPERROR;
+      estimate_compressed_aux_dict ();
+    }
+  else
+    {
+      if (cdh.dict_type != MG_COMPLETE_DICTIONARY)
+	Message ("Huffman info for chars in dictionary %.2f Mb"
+		 " ( %u bytes   %0.3f %%)",
+		 Chars_disk / 1024.0 / 1024, Chars_disk,
+		 (Chars_disk * 100.0) / bytes_processed);
+      unlink (make_name (FileName, TEXT_DICT_AUX_SUFFIX, NULL));
+    }
+
+  return (COMPALLOK);
+}
Index: /main/tags/2.25/gsdl/packages/mg/src/text/text_get.c
===================================================================
--- /main/tags/2.25/gsdl/packages/mg/src/text/text_get.c	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/mg/src/text/text_get.c	(revision 21064)
@@ -0,0 +1,1087 @@
+/**************************************************************************
+ *
+ * text_get.c -- Function for reading documents from the compressed text
+ * Copyright (C) 1994  Neil Sharman
+ *
+ * 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.
+ *
+ * $Id$
+ *
+ **************************************************************************/
+
+#include "sysfuncs.h"
+
+#include "memlib.h"
+#include "filestats.h"
+#include "timing.h"
+#include "messages.h"
+#include "netorder.h"  /* [RPAP - Jan 97: Endian Ordering] */
+
+#include "huffman.h"
+#include "bitio_m_mem.h"
+#include "bitio_m.h"
+#include "bitio_stdio.h"
+#include "huffman_stdio.h"
+
+#include "mg.h"
+#include "invf.h"
+#include "text.h"
+#include "lists.h"
+#include "backend.h"
+#include "text_get.h"
+#include "locallib.h"
+#include "words.h"
+#include "mg_errors.h"
+#include "local_strings.h"
+
+
+/*
+   $Log$
+   Revision 1.1  1999/08/10 21:18:26  sjboddie
+   renamed mg-1.3d directory mg
+
+   Revision 1.1  1998/11/17 09:35:48  rjmcnab
+   *** empty log message ***
+
+   * Revision 1.3  1994/10/20  03:57:11  tes
+   * I have rewritten the boolean query optimiser and abstracted out the
+   * components of the boolean query.
+   *
+   * Revision 1.2  1994/09/20  04:42:15  tes
+   * For version 1.1
+   *
+ */
+
+static char *RCSID = "$Id$";
+
+
+
+
+
+/* FetchDocStart () 
+ * Reads into DocEnt the starting position of the document in the *.text file
+ * Where the first document is document number 1
+ * It returns the true weight of the document.
+ */
+
+
+
+
+static double 
+FetchDocStartLev1 (text_data * td, u_long DN,
+		   u_long * seek_pos, u_long * len)
+{
+  unsigned long data[2];
+  /* [TS:Sep/94] Fixed up the seek call to give the correct offset */
+  Fseek (td->TextIdxFile,
+	 sizeof (unsigned long) * (DN - 1) +	/* the doc offsets */
+	 sizeof (unsigned long) +	/* the magic number */
+	 sizeof (compressed_text_header),	/* the header */
+	 0);
+  Fread ((char *) &data, sizeof (data), 1, td->TextIdxFile);
+  
+  /* [RPAP - Jan 97: Endian Ordering] */
+  NTOHUL(data[0]);
+  NTOHUL(data[1]);
+
+  *seek_pos = data[0];
+  *len = data[1] - data[0];
+  return (1.0);
+}
+
+#define MG_PAGE_SIZE 2048
+
+static int 
+LoadIdx (text_data * td, unsigned long DN)
+{
+  if (!td->idx_data)
+    {
+      td->idx_data = Xmalloc (sizeof (*(td->idx_data)) * MG_PAGE_SIZE);
+      if (!td->idx_data)
+	FatalError (1, "Out of memory in FDSL2");
+    }
+  if (td->current_pos == -1 || DN >= td->current_pos + MG_PAGE_SIZE - 1 ||
+      DN < td->current_pos)
+    {
+      int i, num;  /* [RPAP - Jan 97: Endian Ordering] */
+
+      long rn = (long) DN - (MG_PAGE_SIZE >> 1);
+      if (rn < 1)
+	rn = 1;
+      Fseek (td->TextIdxWgtFile, (sizeof (unsigned long) + sizeof (float)) *
+	       (rn - 1) + sizeof (unsigned long), 0);
+      num = Fread ((char *) td->idx_data, sizeof (*(td->idx_data)), MG_PAGE_SIZE, /* [RPAP - Jan 97: Endian Ordering] */
+		   td->TextIdxWgtFile);
+
+      /* [RPAP - Jan 97: Endian Ordering] */
+      for (i = 0; i < num; i++)
+	{
+	  NTOHUL(td->idx_data[i].Start);
+	  NTOHF(td->idx_data[i].Weight);
+	}
+
+      td->current_pos = rn;
+    }
+  return DN - td->current_pos;
+}
+
+static double 
+FDSL2 (text_data * td, unsigned long DN, unsigned long *Pos)
+{
+  unsigned long pos = LoadIdx (td, DN);
+  *Pos = td->idx_data[pos].Start;
+  return (td->idx_data[pos].Weight);
+}
+
+
+static double 
+FetchDocStartLev2 (text_data * td, u_long DN,
+		   u_long * seek_pos, u_long * len)
+{
+  double Weight;
+  unsigned long s1, s2;
+  Weight = FDSL2 (td, DN, &s1);
+  do
+    {
+      DN++;
+      FDSL2 (td, DN, &s2);
+    }
+  while (s2 == s1);
+  *seek_pos = s1;
+  *len = s2 - s1;
+  return (Weight);
+}
+
+
+
+
+double 
+FetchDocStart (query_data * qd, u_long DN, u_long * seek_pos, u_long * len)
+{
+  qd->text_idx_lookups++;
+  if (qd->td->TextIdxWgtFile)
+    return FetchDocStartLev2 (qd->td, DN, seek_pos, len);
+  else
+    return FetchDocStartLev1 (qd->td, DN, seek_pos, len);
+}
+
+unsigned long 
+FetchInitialParagraph (text_data * td, unsigned long ParaNum)
+{
+  if (td->TextIdxWgtFile)
+    {
+      unsigned long pos;
+      unsigned long start;
+      int PN = ParaNum - 1;
+      pos = LoadIdx (td, ParaNum);
+      start = td->idx_data[pos].Start;
+      while (PN > 0)
+	{
+	  pos = LoadIdx (td, PN);
+	  if (td->idx_data[pos].Start != start)
+	    return PN + 1;
+	  PN--;
+	}
+      return PN + 1;
+    }
+  else
+    return ParaNum;
+}
+
+
+
+/* FetchCompressed () 
+ * Reads into buffer DocBuff the compressed form of document DocNum. 
+ * Where the first document is document number 1
+ */
+int 
+FetchCompressed (query_data * qd, char **DocBuff, DocEntry * DocEnt)
+{
+  if (!DocEnt->SeekPos)
+    FetchDocStart (qd, DocEnt->DocNum, &DocEnt->SeekPos, &DocEnt->Len);
+  if (!(*DocBuff = Xmalloc (DocEnt->Len)))
+    return (-1);
+
+  if (Fseek (qd->td->TextFile, DocEnt->SeekPos, 0) == -1)
+    FatalError (1, "Error when seeking into text file");
+#if 0
+  printf ("Loading compressed text %d %d\n", DocEnt->SeekPos, DocEnt->Len);
+#endif
+  if (Fread (*DocBuff, 1, DocEnt->Len, qd->td->TextFile) != DocEnt->Len)
+    FatalError (1, "Error when reading data");
+
+  return (DocEnt->Len);
+
+}
+
+
+text_data *
+LoadTextData (File * text, File * text_idx_wgt, File * text_idx)
+{
+  text_data *td;
+
+  if (!(td = Xmalloc (sizeof (text_data))))
+    {
+      mg_errno = MG_NOMEM;
+      return (NULL);
+    }
+
+  td->TextFile = text;
+  td->TextIdxWgtFile = text_idx_wgt;
+  td->TextIdxFile = text_idx;
+  td->current_pos = -1;
+  td->idx_data = NULL;
+  Fread (&td->cth, sizeof (td->cth), 1, text);
+
+  /* [RPAP - Jan 97: Endian Ordering] */
+  NTOHUL(td->cth.num_of_docs);
+  NTOHD(td->cth.num_of_bytes); /* [RJM 07/97: 4G limit] */
+  NTOHUL(td->cth.num_of_words);
+  NTOHUL(td->cth.length_of_longest_doc);
+  NTOHD(td->cth.ratio);
+
+  return (td);
+}
+
+
+void 
+FreeTextData (text_data * td)
+{
+  if (td)
+    {
+      if (td->idx_data)
+	Xfree (td->idx_data);
+      Xfree (td);
+    }
+}
+
+
+static int 
+pts_comp (const void *A, const void *B)
+{
+  const DocEntry *const *a = A;
+  const DocEntry *const *b = B;
+  return (*a)->DocNum - (*b)->DocNum;
+}
+
+
+
+
+int 
+GetPosLens (query_data * qd, DocEntry * Docs, int num)
+{
+  DocEntry **pts;
+  int i, j;
+  if (!(pts = Xmalloc (num * sizeof (DocEntry *))))
+    {
+      mg_errno = MG_NOMEM;
+      return (-1);
+    }
+  for (i = j = 0; i < num; i++, Docs++)
+    if (!Docs->SeekPos)
+      pts[j++] = Docs;
+
+  if (j)
+    {
+      qsort (pts, j, sizeof (DocEntry *), pts_comp);
+      for (i = 0; i < j; i++)
+	FetchDocStart (qd, pts[i]->DocNum, &pts[i]->SeekPos, &pts[i]->Len);
+    }
+
+  Xfree (pts);
+  return (0);
+}
+
+
+
+
+
+int 
+LoadBuffers (query_data * qd, DocEntry * Docs, int max_mem, int num)
+{
+  DocEntry **pts;
+  int i, j;
+  int mem;
+
+  if (!num)
+    return (0);
+  if (!(pts = Xmalloc (num * sizeof (DocEntry *))))
+    {
+      mg_errno = MG_NOMEM;
+      return (-1);
+    }
+
+  mem = i = 0;
+  do
+    {
+      pts[i] = Docs;
+      mem += Docs->Len;
+      i++;
+      Docs++;
+    }
+  while (i < num && mem < max_mem);
+  if (i > 1)
+    qsort (pts, i, sizeof (DocEntry *), pts_comp);
+  for (j = 0; j < i; j++)
+    {
+      if (FetchCompressed (qd, &pts[j]->CompTextBuffer, pts[j]) == -1)
+	return (-1);
+      ChangeMemInUse (qd, pts[j]->Len);
+    }
+
+  Xfree (pts);
+
+  return (i);
+}
+
+
+
+
+
+void 
+FreeBuffers (query_data * qd, DocEntry * Docs, int num)
+{
+  int i;
+  for (i = 0; i < num; i++, Docs++)
+    if (Docs->CompTextBuffer)
+      {
+	Xfree (Docs->CompTextBuffer);
+	Docs->CompTextBuffer = NULL;
+	ChangeMemInUse (qd, -Docs->Len);
+      }
+}
+
+
+
+/****************************************************************************/
+
+static void 
+FreeAuxDict (auxiliary_dict * ad)
+{
+  if (!ad)
+    return;
+  if (ad->word_data[0])
+    Xfree (ad->word_data[0]);
+  if (ad->word_data[1])
+    Xfree (ad->word_data[1]);
+  if (ad->words[0])
+    Xfree (ad->words[0]);
+  if (ad->words[1])
+    Xfree (ad->words[1]);
+  Xfree (ad);
+}
+
+static auxiliary_dict *
+LoadAuxDict (compression_dict * cd, File * text_aux_dict)
+{
+  auxiliary_dict *ad;
+  int i;
+
+  if (!(ad = Xmalloc (sizeof (auxiliary_dict))))
+    {
+      mg_errno = MG_NOMEM;
+      return (NULL);
+    }
+
+  bzero ((char *) ad, sizeof (*ad));
+
+  for (i = 0; i <= 1; i++)
+    {
+      int j;
+      u_char *pos;
+
+      Fread (&ad->afh[i], sizeof (aux_frags_header), 1, text_aux_dict);
+
+      /* [RPAP - Jan 97: Endian Ordering] */
+      NTOHUL(ad->afh[i].num_frags);
+      NTOHUL(ad->afh[i].mem_for_frags);
+
+      if (!(ad->word_data[i] = Xmalloc (ad->afh[i].mem_for_frags)))
+	{
+	  mg_errno = MG_NOMEM;
+	  FreeAuxDict (ad);
+	  return (NULL);
+	}
+      if (!(ad->words[i] = Xmalloc (ad->afh[i].num_frags * sizeof (u_char *))))
+	{
+	  mg_errno = MG_NOMEM;
+	  FreeAuxDict (ad);
+	  return (NULL);
+	}
+
+      Fread (ad->word_data[i], ad->afh[i].mem_for_frags, sizeof (u_char),
+	     text_aux_dict);
+
+      pos = ad->word_data[i];
+      for (j = 0; j < ad->afh[i].num_frags; j++)
+	{
+	  ad->words[i][j] = pos;
+	  pos += *pos + 1;
+	}
+      if (cd->cdh.novel_method == MG_NOVEL_HYBRID ||
+	  cd->cdh.novel_method == MG_NOVEL_HYBRID_MTF)
+	{
+	  int num;
+	  num = 1;
+	  ad->blk_start[i][0] = 0;
+	  ad->blk_end[i][0] = cd->cdh.num_words[i] - 1;
+	  while (num < 33)
+	    {
+	      ad->blk_start[i][num] = ad->blk_end[i][num - 1] + 1;
+	      ad->blk_end[i][num] = ad->blk_start[i][num] +
+		(ad->blk_end[i][num - 1] - ad->blk_start[i][num - 1]) * 2;
+	      num++;
+	    }
+	}
+    }
+  return (ad);
+}
+
+
+
+
+
+
+static u_char ***
+ReadInWords (File * dict, compression_dict * cd,
+	     comp_frags_header * cfh, u_char ** escape)
+{
+  int i, lookback;
+  int ptrs_reqd = 0;
+  int mem_reqd = 0;
+  int num_set[MAX_HUFFCODE_LEN + 1];
+  u_char *next_word[MAX_HUFFCODE_LEN + 1];
+  u_char **vals;
+  u_char ***values;
+  u_char word[MAXWORDLEN + 1];
+  u_char last_word[MAX_HUFFCODE_LEN + 1][MAXWORDLEN + 1];
+
+  lookback = cd->cdh.lookback;
+
+  for (i = cfh->hd.mincodelen; i <= cfh->hd.maxcodelen; i++)
+    {
+      ptrs_reqd += (cfh->hd.lencount[i] + ((1 << lookback) - 1)) >> lookback;
+      mem_reqd += cfh->huff_words_size[i];
+    }
+
+  if (!(vals = Xmalloc (ptrs_reqd * sizeof (*vals))))
+    return (NULL);
+
+  if (!(values = Xmalloc ((MAX_HUFFCODE_LEN + 1) * sizeof (u_char **))))
+    return (NULL);
+
+  if (!(next_word[0] = Xmalloc (mem_reqd))) return (NULL);
+
+  cd->MemForCompDict += ptrs_reqd * sizeof (*vals) +
+    (MAX_HUFFCODE_LEN + 1) * sizeof (u_char **) +
+    mem_reqd;
+
+  values[0] = vals;
+  values[0][0] = next_word[0];
+  for (i = 1; i <= cfh->hd.maxcodelen; i++)
+    {
+      int next_start = (values[i - 1] - vals) +
+      ((cfh->hd.lencount[i - 1] + ((1 << lookback) - 1)) >> lookback);
+      values[i] = &vals[next_start];
+      next_word[i] = next_word[i - 1] + cfh->huff_words_size[i - 1];
+      values[i][0] = next_word[i];
+    }
+
+  bzero ((char *) num_set, sizeof (num_set));
+
+  for (i = 0; i < cfh->hd.num_codes; i++)
+    {
+      register int val, copy;
+      register int len = cfh->hd.clens[i];
+      val = Getc (dict);
+      copy = (val >> 4) & 0xf;
+      val &= 0xf;
+
+      Fread (word + copy + 1, sizeof (u_char), val, dict);
+      *word = val + copy;
+
+      if ((num_set[len] & ((1 << lookback) - 1)) == 0)
+	{
+	  values[len][num_set[len] >> lookback] = next_word[len];
+	  memcpy (next_word[len], word, *word + 1);
+	  if (escape && i == cfh->hd.num_codes - 1)
+	    *escape = next_word[len];
+	  next_word[len] += *word + 1;
+	}
+      else
+	{
+	  copy = prefixlen (last_word[len], word);
+	  memcpy (next_word[len] + 1, word + copy + 1, *word - copy);
+	  *next_word[len] = (copy << 4) + (*word - copy);
+	  if (escape && i == cfh->hd.num_codes - 1)
+	    *escape = next_word[len];
+	  next_word[len] += (*word - copy) + 1;
+	}
+      memcpy (last_word[len], word, *word + 1);
+      num_set[len]++;
+    }
+  if (cfh->hd.clens)
+    Xfree (cfh->hd.clens);
+  cfh->hd.clens = NULL;
+  return values;
+}
+
+
+static compression_dict *
+Load_Comp_Dict (File * dict, File * aux_dict)
+{
+  int which;
+  compression_dict *cd;
+
+  if (!(cd = Xmalloc (sizeof (compression_dict))))
+    {
+      mg_errno = MG_NOMEM;
+      return (NULL);
+    }
+
+  bzero ((char *) cd, sizeof (compression_dict));
+
+  cd->MemForCompDict = sizeof (compression_dict);
+
+  if (F_Read_cdh (dict, &cd->cdh, &cd->MemForCompDict, NULL) == -1)
+    return NULL;
+
+  for (which = 0; which < 2; which++)
+    switch (cd->cdh.dict_type)
+      {
+      case MG_COMPLETE_DICTIONARY:
+	{
+	  if (!(cd->cfh[which] = Xmalloc (sizeof (*cd->cfh[which]))))
+	    return NULL;
+	  cd->MemForCompDict += sizeof (*cd->cfh[which]);
+	  if (F_Read_cfh (dict, cd->cfh[which], &cd->MemForCompDict, NULL) == -1)
+	    return NULL;
+
+	  if (!(cd->values[which] = ReadInWords (dict, cd, cd->cfh[which],
+						 NULL)))
+	    return NULL;
+	  cd->escape[which] = NULL;
+
+	}
+	break;
+      case MG_PARTIAL_DICTIONARY:
+	{
+	  huff_data *hd;
+	  u_long **vals;
+	  if (cd->cdh.num_words[which])
+	    {
+	      if (!(cd->cfh[which] = Xmalloc (sizeof (*cd->cfh[which]))))
+		return NULL;
+	      cd->MemForCompDict += sizeof (*cd->cfh[which]);
+	      if (F_Read_cfh (dict, cd->cfh[which], &cd->MemForCompDict, NULL) == -1)
+		return NULL;
+
+	      if (!(cd->values[which] = ReadInWords (dict, cd, cd->cfh[which],
+						     &cd->escape[which])))
+		return NULL;
+	    }
+	  if (!(hd = Xmalloc (sizeof (huff_data))))
+	    return NULL;
+	  cd->MemForCompDict += sizeof (huff_data);
+	  if (F_Read_Huffman_Data (dict, hd, &cd->MemForCompDict, NULL) == -1)
+	    return NULL;
+	  if (!(vals = Generate_Huffman_Vals (hd, &cd->MemForCompDict)))
+	    return NULL;
+	  if (hd->clens)
+	    Xfree (hd->clens);
+	  hd->clens = NULL;
+	  cd->chars_huff[which] = hd;
+	  cd->chars_vals[which] = vals;
+	  if (!(hd = Xmalloc (sizeof (huff_data))))
+	    return NULL;
+	  cd->MemForCompDict += sizeof (huff_data);
+	  if (F_Read_Huffman_Data (dict, hd, &cd->MemForCompDict, NULL) == -1)
+	    return NULL;
+	  if (!(vals = Generate_Huffman_Vals (hd, &cd->MemForCompDict)))
+	    return NULL;
+	  cd->lens_huff[which] = hd;
+	  cd->lens_vals[which] = vals;
+	  if (hd->clens)
+	    Xfree (hd->clens);
+	  hd->clens = NULL;
+	}
+	break;
+      case MG_SEED_DICTIONARY:
+	{
+	  huff_data *hd;
+	  u_long **vals;
+	  if (cd->cdh.num_words[which])
+	    {
+	      if (!(cd->cfh[which] = Xmalloc (sizeof (*cd->cfh[which]))))
+		return NULL;
+	      cd->MemForCompDict += sizeof (*cd->cfh[which]);
+	      if (F_Read_cfh (dict, cd->cfh[which], &cd->MemForCompDict, NULL) == -1)
+		return NULL;
+
+	      if (!(cd->values[which] = ReadInWords (dict, cd, cd->cfh[which],
+						     &cd->escape[which])))
+		return NULL;
+	    }
+	  switch (cd->cdh.novel_method)
+	    {
+	    case MG_NOVEL_HUFFMAN_CHARS:
+	      if (!(hd = Xmalloc (sizeof (huff_data))))
+		return NULL;
+	      cd->chars_huff[which] = hd;
+	      cd->MemForCompDict += sizeof (huff_data);
+	      if (F_Read_Huffman_Data (dict, hd, &cd->MemForCompDict,
+				       NULL) == -1)
+		return NULL;
+	      if (!(vals = Generate_Huffman_Vals (hd, &cd->MemForCompDict)))
+		return NULL;
+	      cd->chars_vals[which] = vals;
+	      if (hd->clens)
+		Xfree (hd->clens);
+	      hd->clens = NULL;
+	      if (!(hd = Xmalloc (sizeof (huff_data))))
+		return NULL;
+	      cd->MemForCompDict += sizeof (huff_data);
+	      cd->lens_huff[which] = hd;
+	      if (F_Read_Huffman_Data (dict, hd, &cd->MemForCompDict
+				       ,NULL) == -1)
+		return NULL;
+	      if (!(vals = Generate_Huffman_Vals (hd, &cd->MemForCompDict)))
+		return NULL;
+	      cd->lens_vals[which] = vals;
+	      if (hd->clens)
+		Xfree (hd->clens);
+	      hd->clens = NULL;
+	      break;
+	    case MG_NOVEL_BINARY:
+	      break;
+	    case MG_NOVEL_DELTA:
+	      break;
+	    case MG_NOVEL_HYBRID:
+	      break;
+	    case MG_NOVEL_HYBRID_MTF:
+	      break;
+	    }
+	  break;
+	}
+      }
+
+  if (cd->cdh.novel_method == MG_NOVEL_BINARY ||
+      cd->cdh.novel_method == MG_NOVEL_DELTA ||
+      cd->cdh.novel_method == MG_NOVEL_HYBRID ||
+      cd->cdh.novel_method == MG_NOVEL_HYBRID_MTF)
+    {
+      if (!aux_dict)
+	{
+	  mg_errno = MG_NOFILE;
+	  FreeCompDict (cd);
+	  return (NULL);
+	}
+
+      if (!(cd->ad = LoadAuxDict (cd, aux_dict)))
+	{
+	  FreeCompDict (cd);
+	  return (NULL);
+	}
+    }
+
+
+  mg_errno = MG_NOERROR;
+
+  cd->fast_loaded = 0;
+  return (cd);
+}
+
+#define WORDNO(p, base) ((((char*)(p))-((char*)(base)))/sizeof(u_char*))
+
+#define IS_FIXUP(p) ((fixup[WORDNO(p,cd)/8] & (1<<(WORDNO(p, cd) & 7))) != 0)
+
+
+static compression_dict *
+Load_Fast_Comp_Dict (File * text_fast_comp_dict)
+{
+  compression_dict *cd;
+  u_long *p, *end;
+  u_char *fixup;
+  u_long mem;
+  u_long fixup_mem;
+  int i;  /* [RPAP - Jan 97: Endian Ordering] */
+
+  Fread (&mem, sizeof (mem), 1, text_fast_comp_dict);
+  NTOHUL(mem);  /* [RPAP - Jan 97: Endian Ordering] */
+  Fread (&fixup_mem, sizeof (fixup_mem), 1, text_fast_comp_dict);
+  NTOHUL(fixup_mem);  /* [RPAP - Jan 97: Endian Ordering] */
+  if (!(cd = Xmalloc (mem)))
+    {
+      mg_errno = MG_NOMEM;
+      return (NULL);
+    }
+
+  end = (u_long *) (((u_char *) cd) + mem);
+  Fread (cd, sizeof (u_char), mem, text_fast_comp_dict);
+
+  if (!(fixup = Xmalloc (fixup_mem)))
+    {
+      mg_errno = MG_NOMEM;
+      return (NULL);
+    }
+
+  Fread (fixup, fixup_mem, sizeof (u_char), text_fast_comp_dict);
+
+  for (p = (u_long *) cd; (u_long) p < (u_long) end; p++)
+    if (IS_FIXUP (p))
+      {
+	NTOHUL(*p);  /* [RPAP - Jan 97: Endian Ordering] */
+	*p = *p + (u_long) cd;
+      }
+
+  /* [RPAP - Jan 97: Endian Ordering] */
+  /* cdh */
+  NTOHUL(cd->cdh.dict_type);
+  NTOHUL(cd->cdh.novel_method);
+  for (i = 0; i < TEXT_PARAMS; i++)
+    NTOHUL(cd->cdh.params[i]);
+  NTOHUL(cd->cdh.num_words[0]);
+  NTOHUL(cd->cdh.num_words[1]);
+  NTOHUL(cd->cdh.num_word_chars[0]);
+  NTOHUL(cd->cdh.num_word_chars[1]);
+  NTOHUL(cd->cdh.lookback);
+  /* cfh */
+  for (i = 0; i <= 1; i++)
+    {
+      int j;
+
+      NTOHSI(cd->cfh[i]->hd.num_codes);
+      NTOHSI(cd->cfh[i]->hd.mincodelen);
+      NTOHSI(cd->cfh[i]->hd.maxcodelen);
+      for (j = 0; j < MAX_HUFFCODE_LEN + 1; j++)
+	{
+	  NTOHSI(cd->cfh[i]->hd.lencount[j]);
+	  NTOHUL(cd->cfh[i]->hd.min_code[j]);
+	}
+      NTOHUL(cd->cfh[i]->uncompressed_size);
+      for (j = 0; j < MAX_HUFFCODE_LEN + 1; j++)
+	NTOHUL(cd->cfh[i]->huff_words_size[j]);
+    }
+  NTOHUL(cd->MemForCompDict);
+  /* ad */
+  if (cd->cdh.novel_method == MG_NOVEL_BINARY ||
+      cd->cdh.novel_method == MG_NOVEL_DELTA ||
+      cd->cdh.novel_method == MG_NOVEL_HYBRID ||
+      cd->cdh.novel_method == MG_NOVEL_HYBRID_MTF)
+    for (i = 0; i <= 1; i++)
+      {
+	int j;
+	
+	NTOHUL(cd->ad->afh[i].num_frags);
+	NTOHUL(cd->ad->afh[i].mem_for_frags);
+	for (j = 0; j < 33; j++)
+	  {
+	    NTOHSI(cd->ad->blk_start[i][j]);
+	    NTOHSI(cd->ad->blk_end[i][j]);
+	  }
+      }
+  NTOHSI(cd->fast_loaded);
+
+  Xfree (fixup);
+  return (cd);
+}
+
+
+
+
+compression_dict *
+LoadCompDict (File * text_comp_dict,
+	      File * text_aux_dict,
+	      File * text_fast_comp_dict)
+{
+  return text_fast_comp_dict ?
+    Load_Fast_Comp_Dict (text_fast_comp_dict) :
+    Load_Comp_Dict (text_comp_dict, text_aux_dict);
+}
+
+
+
+
+void 
+FreeCompDict (compression_dict * cd)
+{
+  int which;
+  if (cd->fast_loaded)
+    {
+      Xfree (cd);
+      return;
+    }
+  for (which = 0; which < 2; which++)
+    {
+      if (cd->cfh[which])
+	Xfree (cd->cfh[which]);
+      if (cd->chars_huff[which])
+	Xfree (cd->chars_huff[which]);
+      if (cd->lens_huff[which])
+	Xfree (cd->lens_huff[which]);
+      if (cd->values[which])
+	{
+	  Xfree (cd->values[which][0][0]); /* [RJM 07/98: Memory Leak] */
+	  Xfree (cd->values[which][0]);
+	  Xfree (cd->values[which]);
+	}
+      if (cd->chars_vals[which])
+	{
+	  Xfree (cd->chars_vals[which][0]);
+	  Xfree (cd->chars_vals[which]);
+	}
+      if (cd->lens_vals[which])
+	{
+	  Xfree (cd->lens_vals[which][0]);
+	  Xfree (cd->lens_vals[which]);
+	}
+    }
+  if (cd->ad)
+    FreeAuxDict (cd->ad);
+  Xfree (cd);
+}
+
+
+
+
+
+#define MY_HUFF_DECODE(len, code, mcodes)				\
+  do {									\
+    register unsigned long *__min_code = (mcodes);			\
+    register unsigned long *__mclen = __min_code;			\
+    register unsigned long __code = 0;					\
+    do									\
+      {									\
+        DECODE_ADD(__code);						\
+      }									\
+    while (__code < *++__mclen);					\
+    (len) = __mclen - __min_code;					\
+    (code) = __code - *__mclen;						\
+  } while(0);
+
+
+/*#define DUMPDOC */
+
+#define MAX_SWAPS 10000
+
+int 
+DecodeText (compression_dict * cd,
+	    u_char * s_in, int l_in, u_char * s_out, int *l_out)
+{
+  auxiliary_dict *ad = cd->ad;
+  int which;
+  u_long num_bits, bits;
+  u_char *ptr = s_out;
+  static int num = 0;
+  u_long binary_start[2];
+  int novels_used[2];
+  int swaps[2][MAX_SWAPS];
+  novels_used[0] = novels_used[1] = 0;
+
+  {
+    unsigned char bf = s_in[l_in - 1];
+    num_bits = 1;
+    while ((bf & 1) != 1)
+      {
+	num_bits++;
+	bf >>= 1;
+      }
+    num_bits = l_in * 8 - num_bits;
+  }
+
+  DECODE_START (s_in, l_in)
+
+    which = DECODE_BIT;
+  bits = 1;
+
+  if (cd->cdh.novel_method == MG_NOVEL_BINARY)
+    {
+      DELTA_DECODE_L (binary_start[0], bits);
+      DELTA_DECODE_L (binary_start[1], bits);
+    }
+
+
+  while (bits < num_bits)
+    {
+      register unsigned code, len;
+      register int r;
+      register u_char *t, *b = NULL;
+      u_char word[MAXWORDLEN + 1];
+
+#ifdef DUMPDOC
+      printf ("\n%d %d  ", bits, num_bits);
+#endif
+      if (cd->cfh[which])
+	{
+	  MY_HUFF_DECODE (len, code, cd->cfh[which]->hd.min_code);
+	  bits += len;
+
+	  r = code & ((1 << cd->cdh.lookback) - 1);
+	  t = cd->values[which][len][code >> cd->cdh.lookback];
+
+	  /* step through from base pointer */
+	  b = word + 1;
+	  while (r--)
+	    {
+	      register int copy = *t >> 4;
+	      memcpy (word + copy + 1, t + 1, *t & 0xf);
+	      word[0] = copy + (*t & 0xf);
+	      t += ((*t) & 0xf) + 1;
+	    }
+	}
+      else
+	t = NULL;
+      if (t == cd->escape[which])
+	{
+	  switch (cd->cdh.novel_method)
+	    {
+	    case MG_NOVEL_HUFFMAN_CHARS:
+	      {
+		int len, i;
+		int c;
+		HUFF_DECODE_L (len, cd->lens_huff[which]->min_code,
+			       cd->lens_vals[which], bits);
+		for (i = 0; i < len; i++)
+		  {
+		    HUFF_DECODE_L (c, cd->chars_huff[which]->min_code,
+				   cd->chars_vals[which], bits);
+		    *ptr++ = c;
+		  }
+	      }
+	      break;
+	    case MG_NOVEL_BINARY:
+	    case MG_NOVEL_DELTA:
+	    case MG_NOVEL_HYBRID:
+	    case MG_NOVEL_HYBRID_MTF:
+	      {
+		int idx = 0, len;
+		u_char *base;
+		switch (cd->cdh.novel_method)
+		  {
+		  case MG_NOVEL_BINARY:
+		    {
+		      BINARY_DECODE_L (idx, binary_start[which], bits);
+		      if (idx == binary_start[which])
+			binary_start[which]++;
+		      idx--;
+		    }
+		    break;
+		  case MG_NOVEL_DELTA:
+		    {
+		      DELTA_DECODE_L (idx, bits);
+		      idx--;
+		    }
+		    break;
+		  case MG_NOVEL_HYBRID:
+		    {
+		      int k;
+		      GAMMA_DECODE_L (k, bits);
+		      k--;
+		      BINARY_DECODE_L (idx,
+				       ad->blk_end[which][k] -
+				       ad->blk_start[which][k] + 1, bits);
+		      idx += ad->blk_start[which][k] - 1;
+		    }
+		    break;
+		  case MG_NOVEL_HYBRID_MTF:
+		    {
+		      int k;
+		      GAMMA_DECODE_L (k, bits);
+		      k--;
+		      BINARY_DECODE_L (idx,
+				       ad->blk_end[which][k] -
+				       ad->blk_start[which][k] + 1, bits);
+		      idx += ad->blk_start[which][k] - 1;
+		      if (idx >= novels_used[which])
+			{
+			  u_char *temp;
+			  temp = ad->words[which][idx];
+			  ad->words[which][idx] =
+			    ad->words[which][novels_used[which]];
+			  ad->words[which][novels_used[which]] = temp;
+			  swaps[which][novels_used[which]] = idx;
+			  idx = novels_used[which]++;
+			}
+		    }
+		    break;
+		  }
+		base = ad->words[which][idx];
+		len = *base++;
+#ifdef DUMPDOC
+		printf ("[[");
+#endif
+		for (; len; len--)
+		  {
+		    *ptr++ = *base++;
+#ifdef DUMPDOC
+		    putchar (*(base - 1));
+#endif
+		  }
+#ifdef DUMPDOC
+		printf ("]]");
+#endif
+	      }
+	      break;
+	    }
+	}
+      else
+	{
+	  /* copy over the matching prefix */
+	  r = (*t >> 4);
+	  while (r--)
+#ifndef DUMPDOC
+	    *ptr++ = *b++;
+#else
+	    {
+	      *ptr = *b++;
+	      putchar (*ptr);
+	      ptr++;
+	    }
+#endif
+
+	  /* and the stored suffix */
+	  r = ((*t) & 0xf);
+	  while (r--)
+#ifndef DUMPDOC
+	    *ptr++ = *++t;
+#else
+	    {
+	      *ptr = *++t;
+	      putchar (*ptr);
+	      ptr++;
+	    }
+#endif
+	}
+      which = !which;
+    }
+
+  DECODE_DONE
+
+    * l_out = ptr - s_out;
+  num += *l_out + 1;
+
+  if (cd->cdh.novel_method == MG_NOVEL_HYBRID_MTF)
+    for (which = 0; which <= 1; which++)
+      for (novels_used[which]--; novels_used[which] >= 0; novels_used[which]--)
+	{
+	  int a = novels_used[which];
+	  int b = swaps[which][novels_used[which]];
+	  u_char *temp;
+	  temp = ad->words[which][a];
+	  ad->words[which][a] = ad->words[which][b];
+	  ad->words[which][b] = temp;
+	}
+  return (COMPALLOK);
+}
Index: /main/tags/2.25/gsdl/packages/mg/src/text/text_get.h
===================================================================
--- /main/tags/2.25/gsdl/packages/mg/src/text/text_get.h	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/mg/src/text/text_get.h	(revision 21064)
@@ -0,0 +1,67 @@
+/**************************************************************************
+ *
+ * text_get.h -- Function for reading documents from the compressed text
+ * Copyright (C) 1994  Neil Sharman
+ *
+ * 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.
+ *
+ * $Id$
+ *
+ **************************************************************************/
+
+#ifndef H_TEXT_GET
+#define H_TEXT_GET
+
+
+
+/* FetchDocStart () 
+ * Reads into DocEnt the starting position of the document in the *.text file
+ * Where the first document is document number 1
+ * It returns the true weight of the document.
+ */
+double FetchDocStart (query_data * qd, u_long DN, u_long * seek_pos, u_long * len);
+
+unsigned long FetchInitialParagraph (text_data * td, unsigned long ParaNum);
+
+
+/* FetchCompressed () 
+ * Reads into buffer DocBuff the compressed form of document DocNum. 
+ * Where the first document is document number 1
+ */
+int FetchCompressed (query_data * qd, char **DocBuff, DocEntry * DocEnt);
+
+text_data *LoadTextData (File * text, File * text_idx_wgt, File * text_idx);
+
+void FreeTextData (text_data * td);
+
+int GetPosLens (query_data * qd, DocEntry * Docs, int num);
+
+int LoadBuffers (query_data * qd, DocEntry * Docs, int max_mem, int num);
+
+void FreeBuffers (query_data * qd, DocEntry * Docs, int num);
+
+
+
+compression_dict *LoadCompDict (File * text_comp_dict,
+				File * text_aux_dict,
+				File * text_fast_comp_dict);
+
+void FreeCompDict (compression_dict * cd);
+
+
+int DecodeText (compression_dict * cd,
+		u_char * s_in, int l_in, u_char * s_out, int *l_out);
+
+#endif
Index: /main/tags/2.25/gsdl/packages/mg/src/text/warranty.h
===================================================================
--- /main/tags/2.25/gsdl/packages/mg/src/text/warranty.h	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/mg/src/text/warranty.h	(revision 21064)
@@ -0,0 +1,24 @@
+static char *warranty_str[] = {
+"			    NO WARRANTY\n",
+"\n",
+"  11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY\n",
+"FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW.  EXCEPT WHEN\n",
+"OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES\n",
+"PROVIDE THE PROGRAM \"AS IS\" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED\n",
+"OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF\n",
+"MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.  THE ENTIRE RISK AS\n",
+"TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU.  SHOULD THE\n",
+"PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,\n",
+"REPAIR OR CORRECTION.\n",
+"\n",
+"  12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING\n",
+"WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR\n",
+"REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,\n",
+"INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING\n",
+"OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED\n",
+"TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY\n",
+"YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER\n",
+"PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE\n",
+"POSSIBILITY OF SUCH DAMAGES.\n",
+"\n",
+"		     END OF TERMS AND CONDITIONS\n"};
Index: /main/tags/2.25/gsdl/packages/mg/src/text/warranty.src
===================================================================
--- /main/tags/2.25/gsdl/packages/mg/src/text/warranty.src	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/mg/src/text/warranty.src	(revision 21064)
@@ -0,0 +1,23 @@
+			    NO WARRANTY
+
+  11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
+FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW.  EXCEPT WHEN
+OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
+PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
+OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.  THE ENTIRE RISK AS
+TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU.  SHOULD THE
+PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
+REPAIR OR CORRECTION.
+
+  12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
+REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
+INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
+OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
+TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
+YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
+PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGES.
+
+		     END OF TERMS AND CONDITIONS
Index: /main/tags/2.25/gsdl/packages/mg/src/text/weights.c
===================================================================
--- /main/tags/2.25/gsdl/packages/mg/src/text/weights.c	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/mg/src/text/weights.c	(revision 21064)
@@ -0,0 +1,158 @@
+/**************************************************************************
+ *
+ * weights.c -- Functions for reading the weights file in mgquery
+ * Copyright (C) 1994  Neil Sharman
+ *
+ * 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.
+ *
+ * $Id$
+ *
+ **************************************************************************/
+
+#include "sysfuncs.h"
+
+#include "filestats.h"
+#include "memlib.h"
+#include "messages.h"
+#include "timing.h"
+#include "netorder.h"  /* [RPAP - Jan 97: Endian Ordering] */
+
+#include "mg.h"
+#include "invf.h"
+#include "text.h"
+#include "lists.h"
+#include "backend.h"
+#include "weights.h"
+#include "locallib.h"
+#include "mg_errors.h"
+
+#define MAXBITS (sizeof(unsigned long) * 8)
+
+/*
+   $Log$
+   Revision 1.1  1999/08/10 21:18:27  sjboddie
+   renamed mg-1.3d directory mg
+
+   Revision 1.1  1998/11/17 09:35:51  rjmcnab
+   *** empty log message ***
+
+   * Revision 1.2  1994/09/20  04:42:18  tes
+   * For version 1.1
+   *
+ */
+
+static char *RCSID = "$Id$";
+
+
+
+approx_weights_data *
+LoadDocWeights (File * weight_file,
+		unsigned long num_of_docs)
+{
+  approx_weights_data *awd;
+  int num;
+
+  if (!(awd = Xmalloc (sizeof (*awd))))
+    {
+      mg_errno = MG_NOMEM;
+      return (NULL);
+    }
+
+  Fseek (weight_file, sizeof (long), 0);
+  Fread (&awd->bits, sizeof (awd->bits), 1, weight_file);
+  Fread (&awd->L, sizeof (awd->L), 1, weight_file);
+  NTOHD(awd->L);  /* [RPAP - Jan 97: Endian Ordering] */
+  Fread (&awd->B, sizeof (awd->B), 1, weight_file);
+  NTOHD(awd->B);  /* [RPAP - Jan 97: Endian Ordering] */
+
+  awd->mask = awd->bits == 32 ? 0xffffffff : (1 << awd->bits) - 1;
+
+  num = (num_of_docs * awd->bits + 31) / 32;
+  if (!(awd->DocWeights = Xmalloc (sizeof (unsigned long) * num)))
+    {
+      Xfree (awd);
+      mg_errno = MG_NOMEM;
+      return (NULL);
+    }
+
+  Fread (awd->DocWeights, sizeof (unsigned long), num, weight_file);
+  {
+    /* [RPAP - Jan 97: Endian Ordering] */
+    unsigned long i;
+    for (i = 0; i < num; i++)
+      NTOHUL(awd->DocWeights[i]);
+  }
+
+  awd->MemForWeights = num * sizeof (unsigned long);
+  awd->num_of_docs = num_of_docs;
+
+  mg_errno = MG_NOERROR;
+
+  if (awd->bits <= 12)
+    {
+      int i, size = (1 << awd->bits);
+      if (!(awd->table = (float *) Xmalloc (size * sizeof (float))))
+	  return (awd);
+      awd->table[0] = awd->L;
+      for (i = 1; i < size; i++)
+	awd->table[i] = awd->table[i - 1] * awd->B;
+    }
+  else
+    awd->table = NULL;
+  return awd;
+}
+
+
+
+
+
+
+/*
+ * the first document in the collection has DocNum = 0
+ */
+float 
+GetLowerApproxDocWeight (approx_weights_data * awd, register int DocNum)
+{
+  register unsigned long c, Pos;
+  register unsigned long *dw;
+  if (awd == NULL)
+    return 1.0;
+#if 0
+  if (DocNum < 0 || DocNum >= awd->num_of_docs)
+    FatalError (1, "Something is wrong in \"GetDocWeight\" DocNum = %d\n",
+		DocNum);
+#endif
+  Pos = DocNum * awd->bits;
+  dw = &(awd->DocWeights[Pos / MAXBITS]);
+  Pos &= (MAXBITS - 1);
+  c = *dw >> Pos;
+  if (Pos + awd->bits > MAXBITS)
+    c |= *(dw + 1) << (MAXBITS - Pos);
+  c &= awd->mask;
+  if (awd->table)
+    return (awd->table[c]);
+  else
+    return (awd->L * pow (awd->B, (double) c));
+
+}
+
+void 
+FreeWeights (approx_weights_data * awd)
+{
+  Xfree (awd->DocWeights);
+  if (awd->table)
+    Xfree (awd->table);
+  Xfree (awd);
+}
Index: /main/tags/2.25/gsdl/packages/mg/src/text/weights.h
===================================================================
--- /main/tags/2.25/gsdl/packages/mg/src/text/weights.h	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/mg/src/text/weights.h	(revision 21064)
@@ -0,0 +1,34 @@
+/**************************************************************************
+ *
+ * weights.h -- Functions for reading the weights file in mgquery
+ * Copyright (C) 1994  Neil Sharman
+ *
+ * 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.
+ *
+ * $Id$
+ *
+ **************************************************************************/
+
+#ifndef H_WEIGHTS
+#define H_WEIGHTS
+
+approx_weights_data *LoadDocWeights (File * weight_file,
+				     unsigned long num_of_docs);
+
+float GetLowerApproxDocWeight (approx_weights_data * awd, register int DocNum);
+
+void FreeWeights (approx_weights_data * awd);
+
+#endif
Index: /main/tags/2.25/gsdl/packages/mg/src/text/words.c
===================================================================
--- /main/tags/2.25/gsdl/packages/mg/src/text/words.c	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/mg/src/text/words.c	(revision 21064)
@@ -0,0 +1,11 @@
+#include "words.h"
+
+
+/* Takes the place of the old INAWORD macro. It determines
+   whether a given place in a UTF-8 encoded Unicode string
+   is part of a word. */
+int inaword (const u_char *here, const u_char *end) {
+  unsigned short c;
+  if (parse_utf8_char(here, end, &c) > 0) return is_unicode_letdig (c);
+  return 0;
+}
Index: /main/tags/2.25/gsdl/packages/mg/src/text/words.h
===================================================================
--- /main/tags/2.25/gsdl/packages/mg/src/text/words.h	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/mg/src/text/words.h	(revision 21064)
@@ -0,0 +1,387 @@
+/**************************************************************************
+ *
+ * words.h -- Macros for parsing out words from the source text
+ * Copyright (C) 1994  Neil Sharman
+ *
+ * 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.
+ *
+ * $Id$
+ *
+ **************************************************************************/
+
+#include "sysfuncs.h"
+
+#include "unitool.h"
+
+
+/*
+ * This has been cleaned up by Tim Shimmin. 
+ */
+
+/*
+ * ---NOTE---
+ *
+ * "WORD" refers to a word in the compressed text.
+ * "STEM" or "STEM_WORD" refers to a word for indexing on
+ *
+ */
+
+#define MAXWORDLEN	15
+	/* Maximum length in bytes of any word or non-word. Note that
+	   variations to MAXWORDLEN may have dramatic effects on the rest
+	   of the program, as the length and the prefix match are packed
+	   together into a four bit nibble, and there is not check that
+	   this is possible, i.e., leave MAXWORDLEN alone... */
+
+#define MAXSTEMLEN	255
+	/* Maximum length in bytes of any stem. Note that
+	   variations to MAXSTEMLEN may have dramatic effects on the rest
+	   of the program, , i.e., leave MAXSTEMLEN alone... */
+
+#define MAXNUMERIC	4
+	/* Maximum number of numeric characters permitted in a word.
+	   This avoids long sequences of numbers creating just one
+	   word occurrence for each number. At most 10,000 all numeric
+	   words will be permitted. */
+
+/* [RPAP - Jan 97: Stem Index Change] */
+#define MAXPARAMLEN     20
+        /* Maximum number of bytes to read for a parameter value for a
+	   term in a query. */
+#define WEIGHTPARAM     '/'
+#define STEMPARAM       '#'
+
+/* [RJM 07/97: Ranked Required Terms] */
+#define MUSTMATCHPARAM     '+'
+
+
+#define PESINAWORD(c)      (isalnum(c) || ((c) >= 0x80 && (c) <= 0xff))
+        /* The definition of what characters are permitted in a word.
+	   This macro is pessimistic, you cannot tell from a particular
+	   byte above 0x80 whether it is a character or not. This function
+	   is needed by various functions relating to huffman coding
+	   where frequency counts need to be primed, it should not be
+	   used in parsing the UTF-8 encoded input. */
+
+int inaword (const u_char *here, const u_char *end);
+        /* Takes the place of the old INAWORD macro. It determines
+	   whether a given place in a UTF-8 encoded Unicode string
+	   is part of a word. */
+
+
+/* =========================================================================
+ * Macro: PARSE_WORD
+ * Description: 
+ *      Extract a word out for compressing text
+ * Input: 
+ *      s_in = string start in buffer
+ *      end = string end in buffer
+ * Output: 
+ *      Word = extracted word with length in 1st byte
+ *      s_in = ptr to next character in buffer yet to be processed
+ * ========================================================================= */
+#define PARSE_WORD(Word, s_in, end)                                \
+  do {                                                             \
+    register int charlength = 0;                                   \
+    register u_char *wptr = (Word)+1;                              \
+    register int length = 0;                                       \
+    register int numeric = 0;                                      \
+    unsigned short c;                                              \
+                                                                   \
+    charlength = parse_utf8_char((s_in),(end),&c);                 \
+                                                                   \
+    while (length+charlength <= MAXWORDLEN && charlength > 0 &&    \
+	   (is_unicode_letter(c) || (is_unicode_digit(c) &&        \
+				     ++numeric <= MAXNUMERIC))) {  \
+      while (charlength-- > 0) {                                   \
+        *wptr++ = *(s_in)++; length++;                             \
+      }                                                            \
+      charlength = parse_utf8_char((s_in),(end),&c);               \
+    }                                                              \
+    *(Word) = length;                                              \
+  }while(0)
+
+  /*  
+#define PARSE_WORD(Word, s_in, end)                                  \
+  do {                                                               \
+	  register u_char  *wptr = (Word)+1;                         \
+	  register int    length = 0;                                \
+	  register int    c = *(s_in);                               \
+	  register int	numeric = 0;                                 \
+                                                                     \
+	  while( length < MAXWORDLEN && INAWORD(c) && (s_in)<=(end)) \
+	    {                                                        \
+	      if ((numeric += INNUMBER(c)) > MAXNUMERIC)             \
+		break;                                               \
+	      *wptr++ = c;                                           \
+	      length++;                                              \
+	      c = *++(s_in);                                         \
+	    }                                                        \
+	  *(Word) = length;                                          \
+  }while(0)
+  */
+
+
+/* =========================================================================
+ * Macro: PARSE_NON_WORD
+ * Description: 
+ *      Extract a non-word out for storing compressed text
+ * Input: as above
+ * Output: as above
+ * ========================================================================= */
+#define PARSE_NON_WORD(Word, s_in, end)                            \
+  do {                                                             \
+    register int charlength = 0;                                   \
+    register u_char *wptr = (Word)+1;                              \
+    register int length = 0;                                       \
+    unsigned short c;                                              \
+                                                                   \
+    charlength = parse_utf8_char((s_in),(end),&c);                 \
+                                                                   \
+    while (length+charlength <= MAXWORDLEN && charlength > 0 &&    \
+	   !is_unicode_letdig(c)) {                                \
+      while (charlength-- > 0) {                                   \
+        *wptr++ = *(s_in)++; length++;                             \
+      }                                                            \
+      charlength = parse_utf8_char((s_in),(end),&c);               \
+    }                                                              \
+    *(Word) = length;                                              \
+  }while(0)
+
+    /*
+#define PARSE_NON_WORD(Word, s_in, end)                            \
+  do {                                                             \
+	  register u_char  *wptr = (Word)+1;                       \
+	  register int    length = 0;                              \
+	  register int    c = *(s_in);                             \
+                                                                   \
+	  while( length < MAXWORDLEN && !INAWORD(c) && (s_in)<=(end) ) \
+	    {                                                      \
+	      *wptr++ = c;                                         \
+	      length++;                                            \
+	      c = *++(s_in);                                       \
+	    }                                                      \
+	  *(Word) = length;                                        \
+  }while(0)
+    */
+
+
+/* =========================================================================
+ * Macro: PARSE_STEM_WORD 
+ * Description: 
+ *      Extracts out Word.      
+ * Input: 
+ *      s_in points to 1st letter in buffer to test
+ *      end points to last letter in buffer
+ * Output: 
+ *      s_in is modified to move to next word
+ *      Returns Word filled in with length in 1st byte.
+ * ========================================================================= */
+#define PARSE_STEM_WORD(Word, s_in, end)                           \
+  do {                                                             \
+    register int charlength = 0;                                   \
+    register u_char *wptr = (Word)+1;                              \
+    register int length = 0;                                       \
+    register int numeric = 0;                                      \
+    unsigned short c;                                              \
+                                                                   \
+    charlength = parse_utf8_char((s_in),(end),&c);                 \
+                                                                   \
+    while (length+charlength <= MAXSTEMLEN && charlength > 0 &&    \
+	   (is_unicode_letter(c) || (is_unicode_digit(c) &&        \
+				     ++numeric <= MAXNUMERIC))) {  \
+      while (charlength-- > 0) {                                   \
+        *wptr++ = *(s_in)++; length++;                             \
+      }                                                            \
+      charlength = parse_utf8_char((s_in),(end),&c);               \
+    }                                                              \
+    *(Word) = length;                                              \
+  }while(0)
+
+    /*
+#define PARSE_STEM_WORD(Word, s_in, end)                      \
+  do                                                          \
+    {                                                         \
+      register u_char  *wptr = (Word)+1;                      \
+      register int    length = 0;                             \
+      register int    c = *(s_in);                            \
+      register int    numeric = 0;                            \
+                                                              \
+      while ( length < MAXSTEMLEN && INAWORD(c) && (s_in)<=(end)) \
+        {                                                     \
+ 	  if ((numeric += INNUMBER(c)) > MAXNUMERIC)          \
+	    break;                                            \
+	  *wptr++ = c;                                        \
+	  length++;                                           \
+	  c = *++(s_in);                                      \
+	}                                                     \
+      *(Word) = length;                                       \
+    }while(0)
+    */
+
+
+/* =========================================================================
+ * Macro: PARSE_NON_STEM_WORD 
+ * Description: 
+ *      Eat up non-word. Do not store non-word.
+ *      It is not needed in index only in text !
+ *      
+ * Input: as above but no Word needed
+ * Output: as above
+ * ========================================================================= */
+#define PARSE_NON_STEM_WORD(s_in, end)                             \
+  do {                                                             \
+    register int charlength = 0;                                   \
+    unsigned short c;                                              \
+                                                                   \
+    charlength = parse_utf8_char((s_in),(end),&c);                 \
+                                                                   \
+    while (charlength > 0 && !is_unicode_letdig(c)) {              \
+      (s_in) += charlength;                                        \
+      charlength = parse_utf8_char((s_in),(end),&c);               \
+    }                                                              \
+  }while(0)
+
+    /*
+#define PARSE_NON_STEM_WORD(s_in, end)           \
+  do                                             \
+    {                                            \
+      while (!INAWORD(*(s_in)) && (s_in)<=(end)) \
+	(s_in)++;                                \
+    }while(0)
+    */
+
+
+/* =========================================================================
+ * Macro: PARSE_NON_STEM_WORD_OR_SGML_TAG 
+ * Description: 
+ *      Like PARSE_NON_STEM_WORD but also eats up SGML tags
+ * Input: as above
+ * Output: as above
+ * ========================================================================= */
+#define PARSE_NON_STEM_WORD_OR_SGML_TAG(s_in, end)                 \
+  do {                                                             \
+    register int charlength = 0;                                   \
+    unsigned short c;                                              \
+                                                                   \
+    charlength = parse_utf8_char((s_in),(end),&c);                 \
+                                                                   \
+    while (charlength > 0 && !is_unicode_letdig(c)) {              \
+      if (c == '<') {                                              \
+	while (charlength > 0 && c != '>') {                       \
+	  (s_in) += charlength;                                    \
+	  charlength = parse_utf8_char((s_in),(end),&c);           \
+	}                                                          \
+      }                                                            \
+      (s_in) += charlength;                                        \
+      charlength = parse_utf8_char((s_in),(end),&c);               \
+    }                                                              \
+  }while(0)
+
+    /*
+#define PARSE_NON_STEM_WORD_OR_SGML_TAG(s_in, end) \
+  do                                               \
+    {                                              \
+      register int    c = *(s_in);                 \
+                                                   \
+      while (!INAWORD(c) && (s_in)<=(end))         \
+        {                                          \
+	  if (c == '<')                            \
+            {                                      \
+	      while (c != '>' && (s_in)<=(end))    \
+		c = *++(s_in);                     \
+            }                                      \
+	  if ((s_in)<=(end))                       \
+	    c = *++(s_in);                         \
+	}                                          \
+    }while(0)
+    */
+
+
+/* =========================================================================
+ * Macro: PARSE_OPT_TERM_PARAM     [RPAP - Jan 97: Stem Index Change]
+ * Description: 
+ *      Extracts out optional paramater for query term.
+ *      Needed only in parsing the query line !
+ *
+ *      Note: that this function has not been converted to use UTF-8
+ *            as it should still work as it is (only uses ascii
+ *            characters)
+ *      
+ * Input: as above but no Word needed
+ * Output: as above
+ * ========================================================================= */
+#define PARSE_OPT_TERM_PARAM(Param, type, s_in, end)                       \
+  do                                                                       \
+    {                                                                      \
+	  register u_char  *wptr = (Param);                                \
+	  register int    length = 0;                                      \
+	  register int    c = *(s_in);                                     \
+                                                                           \
+          if (c == WEIGHTPARAM || c == STEMPARAM)                          \
+	    {                                                              \
+	      type = c;                                                    \
+	      c = *++(s_in);                                               \
+	      while( length < MAXPARAMLEN && isdigit(c) && (s_in)<=(end))  \
+		{                                                          \
+	           *wptr++ = c;                                            \
+	           length++;                                               \
+	           c = *++(s_in);                                          \
+	        }                                                          \
+	      *wptr = '\0';                                                \
+              for (; isdigit(c) && (s_in)<=(end); c = *++(s_in))           \
+                ;                                                          \
+            }							           \
+    }while(0)
+
+/* =========================================================================
+ * Macro: PARSE_RANKED_NON_STEM_WORD    [RJM 07/97: Ranked Required Terms]
+ * Description: 
+ *      Eat up non-word. Do not store non-word.
+ *      If come across a match requirement store it in require_match
+ *      It is not needed in index only in text !
+ *      
+ * Input: as above
+ * Output: the requirement mode for the next term. -1=must not match,
+ *      0=optional match, 1=must match
+ * ========================================================================= */
+#define PARSE_RANKED_NON_STEM_WORD(require_match, s_in, end)       \
+  do {                                                             \
+    register int charlength = 0;                                   \
+    unsigned short c;                                              \
+    (require_match) = 0;                                           \
+                                                                   \
+    charlength = parse_utf8_char((s_in),(end),&c);                 \
+                                                                   \
+    while (charlength > 0 && !is_unicode_letdig(c)) {              \
+      if (c == MUSTMATCHPARAM) (require_match) = 1;                \
+      (s_in) += charlength;                                        \
+      charlength = parse_utf8_char((s_in),(end),&c);               \
+    }                                                              \
+  }while(0)
+
+    /*
+#define PARSE_RANKED_NON_STEM_WORD(require_match, s_in, end)         \
+  do {                                            \
+    (require_match) = 0;                          \
+    while (!INAWORD(*(s_in)) && (s_in)<=(end)) {  \
+      if (*(s_in) == MUSTMATCHPARAM) {            \
+        (require_match) = 1;                      \
+      }                                           \
+      (s_in)++;                                   \
+    }                                             \
+  } while (0)
+    */
+
Index: /main/tags/2.25/gsdl/packages/mg/stamp-h.in
===================================================================
--- /main/tags/2.25/gsdl/packages/mg/stamp-h.in	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/mg/stamp-h.in	(revision 21064)
@@ -0,0 +1,1 @@
+timestamp
Index: /main/tags/2.25/gsdl/packages/mg/stemmerinterface.c
===================================================================
--- /main/tags/2.25/gsdl/packages/mg/stemmerinterface.c	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/mg/stemmerinterface.c	(revision 21064)
@@ -0,0 +1,39 @@
+#include "lib/lovinstem.h"
+#include <stdio.h>
+#include <ctype.h>
+
+int main () {
+  char word[256];
+  char c;
+  int len;
+
+  c = fgetc (stdin);
+  while (!feof (stdin)) {
+    /* output non words */
+    while (!feof (stdin) && !isalnum (c)) {
+      fputc (c, stdout);
+      c = fgetc (stdin);
+    }
+
+    /* get the word */
+    len = 0;
+    while (!feof (stdin) && isalnum (c) && len < 255) {
+      len++;
+      word[len] = c;
+      c = fgetc (stdin);
+    }
+    word[0] = len;
+
+    /* if we found a word stem and output it */
+    if (len > 0) {
+      lovinstem (word);
+      len = 0;
+      while (len < word[0]) {
+        len++;
+        fputc(word[len], stdout);
+      }
+    }
+  }
+}
+
+
Index: /main/tags/2.25/gsdl/packages/mg/sysfuncs.h
===================================================================
--- /main/tags/2.25/gsdl/packages/mg/sysfuncs.h	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/mg/sysfuncs.h	(revision 21064)
@@ -0,0 +1,357 @@
+/* System dependent definitions for GNU tar.
+   Copyright (C) 1994 Free Software Foundation, Inc.
+
+   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, 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.
+ */
+
+/*
+ * [TS:Aug/95]
+ * Based on code from system.h file in GNU's tar package 
+ *
+ */
+
+#ifndef SYSFUNCS_H
+#define SYSFUNCS_H
+
+/* [RPAP - Feb 97: WIN32 Port] */
+#ifdef HAVE_CONFIG_H
+# ifdef __WIN32__
+#  include <WIN32cfg.h>
+# else
+#  include <config.h>
+# endif
+#endif
+
+/* Declare alloca.  AIX requires this to be the first thing in the file.  */
+
+#ifdef __GNUC__
+#define alloca __builtin_alloca
+#else
+#if HAVE_ALLOCA_H
+#include <alloca.h>
+#else
+#ifdef _AIX
+#pragma alloca
+#else
+#ifndef alloca
+char *alloca ();
+#endif
+#endif
+#endif
+#endif
+
+#include <sys/types.h>
+
+/* ------------------------------------------------- */
+/* [TS:Aug/95]
+ * Some extra include files that mg needs
+ */
+#include <stdlib.h>
+#include <math.h>
+
+#ifndef log2
+# ifndef M_LN2
+#  define M_LN2 0.69314718055994530942
+# endif
+# define log2(x) (log(x)/M_LN2)
+#endif
+
+
+#ifndef HAVE_SETBUFFER
+# define setbuffer(f, b, s)  setvbuf(f, b, _IOFBF, s)
+#endif
+
+/* [RPAP - Feb 97: WIN32 Port] */
+#if defined(__MSDOS__)  && !defined(__WIN32__)
+# define SHORT_SUFFIX 1
+#endif
+
+
+
+#include <assert.h>
+
+/* ------------------------------------------------- */
+
+/* Declare a generic pointer type.  */
+#if __STDC__ || defined(__TURBOC__)
+#define voidstar void *
+#else
+#define voidstar char *
+#endif
+
+/* Declare ISASCII.  */
+
+#include <ctype.h>
+
+#if STDC_HEADERS
+#define ISASCII(Char) 1
+#else
+#ifdef isascii
+#define ISASCII(Char) isascii (Char)
+#else
+#if HAVE_ISASCII
+#define ISASCII(Char) isascii (Char)
+#else
+#define ISASCII(Char) 1
+#endif
+#endif
+#endif
+
+
+/* ------------------------------------------------- */
+/* [TS:Aug/95] 
+ * The following is copied from GNU Autoconf.Info (1.1)   
+ * It sets up the approriate string and memory functions.
+ */
+
+#if STDC_HEADERS || HAVE_STRING_H
+#include <string.h>
+   /* An ANSI string.h and pre-ANSI memory.h might conflict */
+#if !STDC_HEADERS && HAVE_MEMORY_H
+#include <memory.h>
+#endif /* not STDC_HEADERS and HAVE_MEMORY_H */
+#ifndef index
+#define index strchr
+#endif
+#ifndef rindex
+#define rindex strrchr
+#endif
+#ifndef bcopy
+#define bcopy(s, d, n) memcpy((d), (s), (n))
+#endif
+#ifndef bcmp
+#define bcmp(s1, s2, n) memcmp((s1), (s2), (n))
+#endif
+#ifndef bzero
+#define bzero(s, n) memset((s), 0, (n))
+#endif
+#else /* not STDC_HEADERS and not HAVE_STRING_H */
+#include <strings.h>
+   /* memory.h and strings.h conflict on some systems */
+#endif
+/* ------------------------------------------------- */
+
+
+/* Declare errno.  */
+
+#include <errno.h>
+#ifndef errno
+extern int errno;
+#endif
+
+/* Declare open parameters.  */
+
+#ifdef HAVE_FCNTL_H
+#include <fcntl.h>
+#else
+#include <sys/file.h>
+#endif
+
+#ifndef	O_BINARY
+#define O_BINARY 0
+#endif
+#ifndef O_CREAT
+#define O_CREAT 0
+#endif
+#ifndef	O_NDELAY
+#define O_NDELAY 0
+#endif
+#ifndef	O_RDONLY
+#define O_RDONLY 0
+#endif
+#ifndef O_RDWR
+#define O_RDWR 2
+#endif
+
+/* Declare file status routines and bits.  */
+
+#include <sys/stat.h>
+
+#ifdef STAT_MACROS_BROKEN
+#undef S_ISBLK
+#undef S_ISCHR
+#undef S_ISDIR
+#undef S_ISFIFO
+#undef S_ISLNK
+#undef S_ISMPB
+#undef S_ISMPC
+#undef S_ISNWK
+#undef S_ISREG
+#undef S_ISSOCK
+#endif
+
+/* On MSDOS, there are missing things from <sys/stat.h>.  */
+#if defined(__MSDOS__)
+#define S_ISUID 0
+#define S_ISGID 0
+#define S_ISVTX 0
+#endif
+
+#if defined(__GNUC__) && defined(__WIN32__)
+#include <limits.h>
+#endif
+
+#ifndef S_ISREG			/* POSIX.1 stat stuff missing */
+#define mode_t unsigned short
+#endif
+#if !defined(S_ISBLK) && defined(S_IFBLK)
+#define S_ISBLK(Mode) (((Mode) & S_IFMT) == S_IFBLK)
+#endif
+#if !defined(S_ISCHR) && defined(S_IFCHR)
+#define S_ISCHR(Mode) (((Mode) & S_IFMT) == S_IFCHR)
+#endif
+#if !defined(S_ISDIR) && defined(S_IFDIR)
+#define S_ISDIR(Mode) (((Mode) & S_IFMT) == S_IFDIR)
+#endif
+#if !defined(S_ISREG) && defined(S_IFREG)
+#define S_ISREG(Mode) (((Mode) & S_IFMT) == S_IFREG)
+#endif
+#if !defined(S_ISFIFO) && defined(S_IFIFO)
+#define S_ISFIFO(Mode) (((Mode) & S_IFMT) == S_IFIFO)
+#endif
+#if !defined(S_ISLNK) && defined(S_IFLNK)
+#define S_ISLNK(Mode) (((Mode) & S_IFMT) == S_IFLNK)
+#endif
+#if !defined(S_ISSOCK) && defined(S_IFSOCK)
+#define S_ISSOCK(Mode) (((Mode) & S_IFMT) == S_IFSOCK)
+#endif
+#if !defined(S_ISMPB) && defined(S_IFMPB)	/* V7 */
+#define S_ISMPB(Mode) (((Mode) & S_IFMT) == S_IFMPB)
+#define S_ISMPC(Mode) (((Mode) & S_IFMT) == S_IFMPC)
+#endif
+#if !defined(S_ISNWK) && defined(S_IFNWK)	/* HP/UX */
+#define S_ISNWK(Mode) (((Mode) & S_IFMT) == S_IFNWK)
+#endif
+
+#if !defined(S_ISCTG) && defined(S_IFCTG)	/* contiguous file */
+#define S_ISCTG(Mode) (((Mode) & S_IFMT) == S_IFCTG)
+#endif
+#if !defined(S_ISVTX)
+#define S_ISVTX 0001000
+#endif
+
+/* [RPAP - Feb 97: WIN32 Port] */
+#if !defined(_POSIX_SOURCE) && !defined(__WIN32__)
+#include <sys/param.h>
+#endif
+
+/* Include <unistd.h> before any preprocessor test of _POSIX_VERSION.  */
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+
+
+/* Declare standard functions.  */
+
+#ifdef STDC_HEADERS
+#include <stdlib.h>
+#else
+voidstar malloc ();
+voidstar realloc ();
+char *getenv ();
+#endif
+
+#include <stdio.h>
+
+#ifndef _POSIX_VERSION
+#ifdef __MSDOS__
+#include <io.h>
+#else
+off_t lseek ();
+#endif
+#endif
+
+#include <pathmax.h>
+
+/* Until getoptold function is declared in getopt.h, we need this here for
+   struct option.  */
+#include <getopt.h>
+
+#ifdef WITH_DMALLOC
+#undef HAVE_VALLOC
+#define DMALLOC_FUNC_CHECK
+#include <dmalloc.h>
+#endif
+
+/* Prototypes for external functions.  */
+
+#ifndef __P
+#if PROTOTYPES
+#define __P(Args) Args
+#else
+#define __P(Args) ()
+#endif
+#endif
+
+#if HAVE_LOCALE_H
+#include <locale.h>
+#endif
+#if !HAVE_SETLOCALE
+#define setlocale(Category, Locale)
+#endif
+
+#if ENABLE_NLS
+#include <libintl.h>
+#define _(Text) gettext (Text)
+#else
+#define textdomain(Domain)
+#define _(Text) Text
+#endif
+
+/* Library modules.  */
+
+#if (HAVE_VPRINTF || HAVE_DOPRNT) && __STDC__
+/*void error __P ((int, int, const char *,...));*/
+void error (int, int, const char *,...);
+#else
+void error (int, int, char *, char *, char *, char *, char *, char *, char *, char *, char *);
+#endif
+
+#ifndef HAVE_STRSTR
+char *strstr __P ((const char *, const char *));
+#endif
+
+/* [RB/TS:Oct/95] commented out. Used by lib/gmalloc.c - but it defines it anyway ???
+ *#ifndef HAVE_VALLOC
+ *#define valloc(Size) malloc (Size)
+ *#endif
+ */
+
+voidstar xmalloc __P ((size_t));
+voidstar xrealloc __P ((voidstar, size_t));
+char *xstrdup __P ((const char *));
+
+/* [TS:Aug/95] 
+ * These were required by files which referred 
+ * to these as function pointers. 
+ * e.g. huffman.c - fread,  mgfelics.c - fgetc
+ */
+#ifndef HAVE_FREAD_DECL
+extern size_t   fread __P ((void *, size_t, size_t, FILE *));
+#endif
+#ifndef HAVE_FGETC_DECL
+extern int      fgetc __P ((FILE *));
+#endif
+
+/* [RPAP - Feb 97: WIN32 Port] */
+#ifndef u_long
+# define u_long unsigned long
+#endif
+#ifndef u_char
+# define u_char unsigned char
+#endif
+
+
+#endif /* SYSFUNCS_H */
Index: /main/tags/2.25/gsdl/packages/mg/test/Makefile
===================================================================
--- /main/tags/2.25/gsdl/packages/mg/test/Makefile	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/mg/test/Makefile	(revision 21064)
@@ -0,0 +1,10 @@
+DISTFILES = Makefile q1 q2 q3 r1 r2 r3 mgrc1 mgrc2 mgrc3 testmg \
+            alice.sum simple_sum.c alice.len
+
+all: simple_sum
+
+dist:
+	ln $(DISTFILES) $(distdir)
+
+simple_sum: simple_sum.c
+	cc -o $@ $?
Index: /main/tags/2.25/gsdl/packages/mg/test/alice.len
===================================================================
--- /main/tags/2.25/gsdl/packages/mg/test/alice.len	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/mg/test/alice.len	(revision 21064)
@@ -0,0 +1,2 @@
+./mgdata/alice/alice.invf.dict.hash: 13256
+./mgdata/alice/alice.text.dict: 19321
Index: /main/tags/2.25/gsdl/packages/mg/test/alice.sum
===================================================================
--- /main/tags/2.25/gsdl/packages/mg/test/alice.sum	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/mg/test/alice.sum	(revision 21064)
@@ -0,0 +1,8 @@
+./mgdata/alice/alice.invf: 2618428 19209
+./mgdata/alice/alice.invf.chunk: 189460 2134
+./mgdata/alice/alice.invf.chunk.trans: 331998 2585
+./mgdata/alice/alice.invf.dict.blocked: 1030626 33214
+./mgdata/alice/alice.invf.idx: 309022 7572
+./mgdata/alice/alice.text: 5075885 40099
+./mgdata/alice/alice.text.idx: 185535 3380
+./mgdata/alice/alice.text.stats: 2432380 49146
Index: /main/tags/2.25/gsdl/packages/mg/test/mgrc1
===================================================================
--- /main/tags/2.25/gsdl/packages/mg/test/mgrc1	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/mg/test/mgrc1	(revision 21064)
@@ -0,0 +1,2 @@
+.set mode text
+.set query boolean
Index: /main/tags/2.25/gsdl/packages/mg/test/mgrc2
===================================================================
--- /main/tags/2.25/gsdl/packages/mg/test/mgrc2	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/mg/test/mgrc2	(revision 21064)
@@ -0,0 +1,2 @@
+.set mode text
+.set query ranked
Index: /main/tags/2.25/gsdl/packages/mg/test/mgrc3
===================================================================
--- /main/tags/2.25/gsdl/packages/mg/test/mgrc3	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/mg/test/mgrc3	(revision 21064)
@@ -0,0 +1,2 @@
+.set mode docnums
+.set query boolean
Index: /main/tags/2.25/gsdl/packages/mg/test/q1
===================================================================
--- /main/tags/2.25/gsdl/packages/mg/test/q1	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/mg/test/q1	(revision 21064)
@@ -0,0 +1,1 @@
+flamingo
Index: /main/tags/2.25/gsdl/packages/mg/test/q2
===================================================================
--- /main/tags/2.25/gsdl/packages/mg/test/q2	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/mg/test/q2	(revision 21064)
@@ -0,0 +1,1 @@
+flamingo
Index: /main/tags/2.25/gsdl/packages/mg/test/q3
===================================================================
--- /main/tags/2.25/gsdl/packages/mg/test/q3	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/mg/test/q3	(revision 21064)
@@ -0,0 +1,2 @@
+Rabbit & !(Alice | she)
+laser
Index: /main/tags/2.25/gsdl/packages/mg/test/r1
===================================================================
--- /main/tags/2.25/gsdl/packages/mg/test/r1	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/mg/test/r1	(revision 21064)
@@ -0,0 +1,46 @@
+> flamingo
+flamingo
+---------------------------------- 482
+  The chief difficulty Alice found at first was in managing her 
+flamingo:  she succeeded in getting its body tucked away, 
+comfortably enough, under her arm, with its legs hanging down, 
+but generally, just as she had got its neck nicely straightened 
+out, and was going to give the hedgehog a blow with its head, it 
+WOULD twist itself round and look up in her face, with such a 
+puzzled expression that she could not help bursting out laughing:  
+and when she had got its head down, and was going to begin again, 
+it was very provoking to find that the hedgehog had unrolled 
+itself, and was in the act of crawling away:  besides all this, 
+there was generally a ridge or furrow in the way wherever she 
+wanted to send the hedgehog to, and, as the doubled-up soldiers 
+were always getting up and walking off to other parts of the 
+ground, Alice soon came to the conclusion that it was a very 
+difficult game indeed. 
+---------------------------------- 487
+  Alice waited till the eyes appeared, and then nodded.  `It's no 
+use speaking to it,' she thought, `till its ears have come, or at 
+least one of them.'  In another minute the whole head appeared, 
+and then Alice put down her flamingo, and began an account of the 
+game, feeling very glad she had someone to listen to her.  The 
+Cat seemed to think that there was enough of it now in sight, and 
+no more of it appeared. 
+---------------------------------- 502
+  The hedgehog was engaged in a fight with another hedgehog, 
+which seemed to Alice an excellent opportunity for croqueting one 
+of them with the other:  the only difficulty was, that her 
+flamingo was gone across to the other side of the garden, where 
+Alice could see it trying in a helpless sort of way to fly up 
+into a tree. 
+---------------------------------- 503
+  By the time she had caught the flamingo and brought it back, 
+the fight was over, and both the hedgehogs were out of sight:  
+`but it doesn't matter much,' thought Alice, `as all the arches 
+are gone from the side of the ground.'  So she tucked it away 
+under her arm, that it might not escape again, and went back for 
+a little more conversation with her friend. 
+---------------------------------- 526
+  `I dare say you're wondering why I don't put my arm round your 
+waist,' the Duchess said after a pause:  `the reason is, that I'm 
+doubtful about the temper of your flamingo.  Shall I try the 
+experiment?' 
+5 documents retrieved.
Index: /main/tags/2.25/gsdl/packages/mg/test/r2
===================================================================
--- /main/tags/2.25/gsdl/packages/mg/test/r2	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/mg/test/r2	(revision 21064)
@@ -0,0 +1,46 @@
+> flamingo
+flamingo
+---------------------------------- 526 1.322623
+  `I dare say you're wondering why I don't put my arm round your 
+waist,' the Duchess said after a pause:  `the reason is, that I'm 
+doubtful about the temper of your flamingo.  Shall I try the 
+experiment?' 
+---------------------------------- 503 1.013693
+  By the time she had caught the flamingo and brought it back, 
+the fight was over, and both the hedgehogs were out of sight:  
+`but it doesn't matter much,' thought Alice, `as all the arches 
+are gone from the side of the ground.'  So she tucked it away 
+under her arm, that it might not escape again, and went back for 
+a little more conversation with her friend. 
+---------------------------------- 502 1.009519
+  The hedgehog was engaged in a fight with another hedgehog, 
+which seemed to Alice an excellent opportunity for croqueting one 
+of them with the other:  the only difficulty was, that her 
+flamingo was gone across to the other side of the garden, where 
+Alice could see it trying in a helpless sort of way to fly up 
+into a tree. 
+---------------------------------- 487 0.882496
+  Alice waited till the eyes appeared, and then nodded.  `It's no 
+use speaking to it,' she thought, `till its ears have come, or at 
+least one of them.'  In another minute the whole head appeared, 
+and then Alice put down her flamingo, and began an account of the 
+game, feeling very glad she had someone to listen to her.  The 
+Cat seemed to think that there was enough of it now in sight, and 
+no more of it appeared. 
+---------------------------------- 482 0.529432
+  The chief difficulty Alice found at first was in managing her 
+flamingo:  she succeeded in getting its body tucked away, 
+comfortably enough, under her arm, with its legs hanging down, 
+but generally, just as she had got its neck nicely straightened 
+out, and was going to give the hedgehog a blow with its head, it 
+WOULD twist itself round and look up in her face, with such a 
+puzzled expression that she could not help bursting out laughing:  
+and when she had got its head down, and was going to begin again, 
+it was very provoking to find that the hedgehog had unrolled 
+itself, and was in the act of crawling away:  besides all this, 
+there was generally a ridge or furrow in the way wherever she 
+wanted to send the hedgehog to, and, as the doubled-up soldiers 
+were always getting up and walking off to other parts of the 
+ground, Alice soon came to the conclusion that it was a very 
+difficult game indeed. 
+5 documents retrieved.
Index: /main/tags/2.25/gsdl/packages/mg/test/r3
===================================================================
--- /main/tags/2.25/gsdl/packages/mg/test/r3	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/mg/test/r3	(revision 21064)
@@ -0,0 +1,21 @@
+> Rabbit & !(Alice | she)
+Rabbit Alice she
+     14.14     
+    126.126    
+    143.143    
+    478.478    
+    701.701    
+    704.704    
+    705.705    
+    755.755    
+    774.774    
+    786.786    
+    788.788    
+    791.791    
+    793.793    
+    801.801    
+    803.803    
+15 documents retrieved.
+> laser
+laser
+No entries correspond to that query.
Index: /main/tags/2.25/gsdl/packages/mg/test/simple_sum.c
===================================================================
--- /main/tags/2.25/gsdl/packages/mg/test/simple_sum.c	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/mg/test/simple_sum.c	(revision 21064)
@@ -0,0 +1,100 @@
+/**************************************************************************
+ *
+ * sum.c -- byte summing program
+ * Copyright (C) 1995  Tim Shimmin
+ *
+ * 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.
+ *
+ * $Id$
+ *
+ **************************************************************************/
+
+/*
+$Log$
+Revision 1.1  1999/08/10 21:18:33  sjboddie
+renamed mg-1.3d directory mg
+
+Revision 1.1  1998/11/17 09:36:00  rjmcnab
+*** empty log message ***
+
+*/
+
+/*
+ * If given -l option then just prints the length.
+ * Normally prints the sum and the length for the file.
+ */
+
+static int length_only = 0;
+
+#include <stdio.h>
+
+void 
+output_sum(fname, input_file, output_file)
+char *fname;
+FILE *input_file;
+FILE *output_file;
+{
+  int ch = '\0';
+  unsigned long sum = 0;
+  unsigned long num_bytes = 0;
+
+  while((ch = getc(input_file))!=EOF){
+    sum += ch;
+    num_bytes++;
+  }
+
+  if (length_only)
+    fprintf(output_file, "%s: %ld\n", fname, num_bytes);
+  else
+    fprintf(output_file, "%s: %ld %ld\n", fname, sum, num_bytes);
+}
+
+void
+main(argc, argv)
+int argc;
+char *argv[];
+{
+  int i = 0;
+
+  /* use stdin */
+  if (argc == 1){
+    output_sum("-", stdin, stdout);
+    exit(0);
+  }
+
+  /* use args as file names for input */
+  for (i=1;i<argc; i++){
+    char *fname = argv[i];
+    FILE *input_file = NULL;
+    
+    if (!length_only && (argv[i][0] == '-') && (argv[i][1] =='l') ) 
+      { 
+        length_only = 1; 
+        continue;
+      }
+
+    input_file = fopen(fname, "r");
+    if (!input_file){
+      fprintf(stderr,"Could not open %s\n", fname);
+      continue;
+    }
+    else{
+      output_sum(fname, input_file, stdout);
+      fclose(input_file);
+    }
+  }/*for*/
+  exit(0);
+
+}
Index: /main/tags/2.25/gsdl/packages/w3mir/MIME-Base64-2.11/Base64.pm
===================================================================
--- /main/tags/2.25/gsdl/packages/w3mir/MIME-Base64-2.11/Base64.pm	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/w3mir/MIME-Base64-2.11/Base64.pm	(revision 21064)
@@ -0,0 +1,198 @@
+#
+# $Id$
+
+package MIME::Base64;
+
+=head1 NAME
+
+MIME::Base64 - Encoding and decoding of base64 strings
+
+=head1 SYNOPSIS
+
+ use MIME::Base64;
+
+ $encoded = encode_base64('Aladdin:open sesame');
+ $decoded = decode_base64($encoded);
+
+=head1 DESCRIPTION
+
+This module provides functions to encode and decode strings into the
+Base64 encoding specified in RFC 2045 - I<MIME (Multipurpose Internet
+Mail Extensions)>. The Base64 encoding is designed to represent
+arbitrary sequences of octets in a form that need not be humanly
+readable. A 65-character subset ([A-Za-z0-9+/=]) of US-ASCII is used,
+enabling 6 bits to be represented per printable character.
+
+The following functions are provided:
+
+=over 4
+
+=item encode_base64($str, [$eol])
+
+Encode data by calling the encode_base64() function.  The first
+argument is the string to encode.  The second argument is the line
+ending sequence to use (it is optional and defaults to C<"\n">).  The
+returned encoded string is broken into lines of no more than 76
+characters each and it will end with $eol unless it is empty.  Pass an
+empty string as second argument if you do not want the encoded string
+broken into lines.
+
+=item decode_base64($str)
+
+Decode a base64 string by calling the decode_base64() function.  This
+function takes a single argument which is the string to decode and
+returns the decoded data.
+
+Any character not part of the 65-character base64 subset set is
+silently ignored.  Characters occuring after a '=' padding character
+are never decoded.
+
+If the length of the string to decode (after ignoring
+non-base64 chars) is not a multiple of 4 or padding occurs too ealy,
+then a warning is generated if perl is running under C<-w>.
+
+=back
+
+If you prefer not to import these routines into your namespace you can
+call them as:
+
+    use MIME::Base64 ();
+    $encoded = MIME::Base64::encode($decoded);
+    $decoded = MIME::Base64::decode($encoded);
+
+=head1 DIAGNOSTICS
+
+The following warnings might be generated if perl is invoked with the
+C<-w> switch:
+
+=over 4
+
+=item Premature end of base64 data
+
+The number of characters to decode is not a multiple of 4.  Legal
+base64 data should be padded with one or two "=" characters to make
+its length a multiple of 4.  The decoded result will anyway be as if
+the padding was there.
+
+=item Premature padding of base64 data
+
+The '=' padding character occurs as the first or second character
+in a base64 quartet.
+
+=back
+
+=head1 EXAMPLES
+
+If you want to encode a large file, you should encode it in chunks
+that are a multiple of 57 bytes.  This ensures that the base64 lines
+line up and that you do not end up with padding in the middle. 57
+bytes of data fills one complete base64 line (76 == 57*4/3):
+
+   use MIME::Base64 qw(encode_base64);
+
+   open(FILE, "/var/log/wtmp") or die "$!";
+   while (read(FILE, $buf, 60*57)) {
+       print encode_base64($buf);
+   }
+
+or if you know you have enough memory
+
+   use MIME::Base64 qw(encode_base64);
+   local($/) = undef;  # slurp
+   print encode_base64(<STDIN>);
+
+=head1 COPYRIGHT
+
+Copyright 1995-1999 Gisle Aas.
+
+This library is free software; you can redistribute it and/or
+modify it under the same terms as Perl itself.
+
+Distantly based on LWP::Base64 written by Martijn Koster
+<m.koster@nexor.co.uk> and Joerg Reichelt <j.reichelt@nexor.co.uk> and
+code posted to comp.lang.perl <3pd2lp$6gf@wsinti07.win.tue.nl> by Hans
+Mulder <hansm@wsinti07.win.tue.nl>
+
+The XS implementation use code from metamail.  Copyright 1991 Bell
+Communications Research, Inc. (Bellcore)
+
+=cut
+
+use strict;
+use vars qw(@ISA @EXPORT $VERSION $OLD_CODE);
+
+require Exporter;
+require DynaLoader;
+@ISA = qw(Exporter DynaLoader);
+@EXPORT = qw(encode_base64 decode_base64);
+
+$VERSION = '2.11';
+
+eval { bootstrap MIME::Base64 $VERSION; };
+if ($@) {
+    # can't bootstrap XS implementation, use perl implementation
+    *encode_base64 = \&old_encode_base64;
+    *decode_base64 = \&old_decode_base64;
+
+    $OLD_CODE = $@;
+    #warn $@ if $^W;
+}
+
+# Historically this module has been implemented as pure perl code.
+# The XS implementation runs about 20 times faster, but the Perl
+# code might be more portable, so it is still here.
+
+use integer;
+
+sub old_encode_base64 ($;$)
+{
+    my $res = "";
+    my $eol = $_[1];
+    $eol = "\n" unless defined $eol;
+    pos($_[0]) = 0;                          # ensure start at the beginning
+    while ($_[0] =~ /(.{1,45})/gs) {
+	$res .= substr(pack('u', $1), 1);
+	chop($res);
+    }
+    $res =~ tr|` -_|AA-Za-z0-9+/|;               # `# help emacs
+    # fix padding at the end
+    my $padding = (3 - length($_[0]) % 3) % 3;
+    $res =~ s/.{$padding}$/'=' x $padding/e if $padding;
+    # break encoded string into lines of no more than 76 characters each
+    if (length $eol) {
+	$res =~ s/(.{1,76})/$1$eol/g;
+    }
+    $res;
+}
+
+
+sub old_decode_base64 ($)
+{
+    local($^W) = 0; # unpack("u",...) gives bogus warning in 5.00[123]
+
+    my $str = shift;
+    my $res = "";
+
+    $str =~ tr|A-Za-z0-9+=/||cd;            # remove non-base64 chars
+    if (length($str) % 4) {
+	require Carp;
+	Carp::carp("Length of base64 data not a multiple of 4")
+    }
+    $str =~ s/=+$//;                        # remove padding
+    $str =~ tr|A-Za-z0-9+/| -_|;            # convert to uuencoded format
+    while ($str =~ /(.{1,60})/gs) {
+	my $len = chr(32 + length($1)*3/4); # compute length byte
+	$res .= unpack("u", $len . $1 );    # uudecode
+    }
+    $res;
+}
+
+# Set up aliases so that these functions also can be called as
+#
+#    MIME::Base64::encode();
+#    MIME::Base64::decode();
+
+*encode = \&encode_base64;
+*decode = \&decode_base64;
+
+1;
Index: /main/tags/2.25/gsdl/packages/w3mir/MIME-Base64-2.11/Base64.xs
===================================================================
--- /main/tags/2.25/gsdl/packages/w3mir/MIME-Base64-2.11/Base64.xs	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/w3mir/MIME-Base64-2.11/Base64.xs	(revision 21064)
@@ -0,0 +1,215 @@
+/* $Id$
+
+Copyright 1997-1998 Gisle Aas
+
+This library is free software; you can redistribute it and/or
+modify it under the same terms as Perl itself.
+
+
+The tables and some of the code that used to be here was borrowed from
+metamail, which comes with this message:
+
+  Copyright (c) 1991 Bell Communications Research, Inc. (Bellcore)
+
+  Permission to use, copy, modify, and distribute this material 
+  for any purpose and without fee is hereby granted, provided 
+  that the above copyright notice and this permission notice 
+  appear in all copies, and that the name of Bellcore not be 
+  used in advertising or publicity pertaining to this 
+  material without the specific, prior written permission 
+  of an authorized representative of Bellcore.	BELLCORE 
+  MAKES NO REPRESENTATIONS ABOUT THE ACCURACY OR SUITABILITY 
+  OF THIS MATERIAL FOR ANY PURPOSE.  IT IS PROVIDED "AS IS", 
+  WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES.
+
+*/
+
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+#include "EXTERN.h"
+#include "perl.h"
+#include "XSUB.h"
+#ifdef __cplusplus
+}
+#endif
+
+#include "patchlevel.h"
+#if PATCHLEVEL <= 4 && !defined(PL_dowarn)
+   #define PL_dowarn dowarn
+#endif
+
+#define MAX_LINE  76 /* size of encoded lines */
+
+static char basis_64[] =
+   "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
+
+#define XX      255	/* illegal base64 char */
+#define EQ      254	/* padding */
+#define INVALID XX
+
+static unsigned char index_64[256] = {
+    XX,XX,XX,XX, XX,XX,XX,XX, XX,XX,XX,XX, XX,XX,XX,XX,
+    XX,XX,XX,XX, XX,XX,XX,XX, XX,XX,XX,XX, XX,XX,XX,XX,
+    XX,XX,XX,XX, XX,XX,XX,XX, XX,XX,XX,62, XX,XX,XX,63,
+    52,53,54,55, 56,57,58,59, 60,61,XX,XX, XX,EQ,XX,XX,
+    XX, 0, 1, 2,  3, 4, 5, 6,  7, 8, 9,10, 11,12,13,14,
+    15,16,17,18, 19,20,21,22, 23,24,25,XX, XX,XX,XX,XX,
+    XX,26,27,28, 29,30,31,32, 33,34,35,36, 37,38,39,40,
+    41,42,43,44, 45,46,47,48, 49,50,51,XX, XX,XX,XX,XX,
+
+    XX,XX,XX,XX, XX,XX,XX,XX, XX,XX,XX,XX, XX,XX,XX,XX,
+    XX,XX,XX,XX, XX,XX,XX,XX, XX,XX,XX,XX, XX,XX,XX,XX,
+    XX,XX,XX,XX, XX,XX,XX,XX, XX,XX,XX,XX, XX,XX,XX,XX,
+    XX,XX,XX,XX, XX,XX,XX,XX, XX,XX,XX,XX, XX,XX,XX,XX,
+    XX,XX,XX,XX, XX,XX,XX,XX, XX,XX,XX,XX, XX,XX,XX,XX,
+    XX,XX,XX,XX, XX,XX,XX,XX, XX,XX,XX,XX, XX,XX,XX,XX,
+    XX,XX,XX,XX, XX,XX,XX,XX, XX,XX,XX,XX, XX,XX,XX,XX,
+    XX,XX,XX,XX, XX,XX,XX,XX, XX,XX,XX,XX, XX,XX,XX,XX,
+};
+
+
+
+MODULE = MIME::Base64		PACKAGE = MIME::Base64
+
+SV*
+encode_base64(sv,...)
+	SV* sv
+	PROTOTYPE: $;$
+
+	PREINIT:
+	char *str;     /* string to encode */
+	SSize_t len;   /* length of the string */
+	char *eol;     /* the end-of-line sequence to use */
+	STRLEN eollen; /* length of the EOL sequence */
+	char *r;       /* result string */
+	STRLEN rlen;   /* length of result string */
+	unsigned char c1, c2, c3;
+	int chunk;
+
+	CODE:
+	str = SvPV(sv, rlen); /* SvPV(sv, len) gives warning for signed len */
+	len = (SSize_t)rlen;
+
+	/* set up EOL from the second argument if present, default to "\n" */
+	if (items > 1 && SvOK(ST(1))) {
+	    eol = SvPV(ST(1), eollen);
+	} else {
+	    eol = "\n";
+	    eollen = 1;
+	}
+
+	/* calculate the length of the result */
+	rlen = (len+2) / 3 * 4;	 /* encoded bytes */
+	if (rlen) {
+	    /* add space for EOL */
+	    rlen += ((rlen-1) / MAX_LINE + 1) * eollen;
+	}
+
+	/* allocate a result buffer */
+	RETVAL = newSV(rlen ? rlen : 1);
+	SvPOK_on(RETVAL);	
+	SvCUR_set(RETVAL, rlen);
+	r = SvPVX(RETVAL);
+
+	/* encode */
+	for (chunk=0; len > 0; len -= 3, chunk++) {
+	    if (chunk == (MAX_LINE/4)) {
+		char *c = eol;
+		char *e = eol + eollen;
+		while (c < e)
+		    *r++ = *c++;
+		chunk = 0;
+	    }
+	    c1 = *str++;
+	    c2 = *str++;
+	    *r++ = basis_64[c1>>2];
+	    *r++ = basis_64[((c1 & 0x3)<< 4) | ((c2 & 0xF0) >> 4)];
+	    if (len > 2) {
+		c3 = *str++;
+		*r++ = basis_64[((c2 & 0xF) << 2) | ((c3 & 0xC0) >>6)];
+		*r++ = basis_64[c3 & 0x3F];
+	    } else if (len == 2) {
+		*r++ = basis_64[(c2 & 0xF) << 2];
+		*r++ = '=';
+	    } else { /* len == 1 */
+		*r++ = '=';
+		*r++ = '=';
+	    }
+	}
+	if (rlen) {
+	    /* append eol to the result string */
+	    char *c = eol;
+	    char *e = eol + eollen;
+	    while (c < e)
+		*r++ = *c++;
+	}
+	*r = '\0';  /* every SV in perl should be NUL-terminated */
+
+	OUTPUT:
+	RETVAL
+
+SV*
+decode_base64(sv)
+	SV* sv
+	PROTOTYPE: $
+
+	PREINIT:
+	STRLEN len;
+	register unsigned char *str = (unsigned char*)SvPV(sv, len);
+	unsigned char const* end = str + len;
+	char *r;
+	unsigned char c[4];
+
+	CODE:
+	{
+	    /* always enough, but might be too much */
+	    STRLEN rlen = len * 3 / 4;
+	    RETVAL = newSV(rlen ? rlen : 1);
+	}
+        SvPOK_on(RETVAL);
+        r = SvPVX(RETVAL);
+
+	while (str < end) {
+	    int i = 0;
+            do {
+		unsigned char uc = index_64[*str++];
+		if (uc != INVALID)
+		    c[i++] = uc;
+
+		if (str == end) {
+		    if (i < 4) {
+			if (i && PL_dowarn)
+			    warn("Premature end of base64 data");
+			if (i < 2) goto thats_it;
+			if (i == 2) c[2] = EQ;
+			c[3] = EQ;
+		    }
+		    break;
+		}
+            } while (i < 4);
+	    
+	    if (c[0] == EQ || c[1] == EQ) {
+		if (PL_dowarn) warn("Premature padding of base64 data");
+		break;
+            }
+	    /* printf("c0=%d,c1=%d,c2=%d,c3=%d\n", c[0],c[1],c[2],c[3]);/**/
+
+	    *r++ = (c[0] << 2) | ((c[1] & 0x30) >> 4);
+
+	    if (c[2] == EQ)
+		break;
+	    *r++ = ((c[1] & 0x0F) << 4) | ((c[2] & 0x3C) >> 2);
+
+	    if (c[3] == EQ)
+		break;
+	    *r++ = ((c[2] & 0x03) << 6) | c[3];
+	}
+
+      thats_it:
+	SvCUR_set(RETVAL, r - SvPVX(RETVAL));
+	*r = '\0';
+
+	OUTPUT:
+	RETVAL
Index: /main/tags/2.25/gsdl/packages/w3mir/MIME-Base64-2.11/Changes
===================================================================
--- /main/tags/2.25/gsdl/packages/w3mir/MIME-Base64-2.11/Changes	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/w3mir/MIME-Base64-2.11/Changes	(revision 21064)
@@ -0,0 +1,119 @@
+1998-02-27   Gisle Aas <gisle@aas.no>
+
+   Release 2.11
+
+   Fixed bogues "Premature end of base64 data" warning.  Bug spotted
+   by Dwayne Jacques Fontenot.
+
+   Workaround for Redhat shipping trial releases of perl.
+
+
+
+1998-12-18   Gisle Aas <aas@sn.no>
+
+   Release 2.10
+
+   A tweak that should make compilation with some old perl5.00[23]
+   perls better.
+
+   A cast that make some compilers more happy.
+
+
+
+1998-11-13   Gisle Aas <aas@sn.no>
+
+   Release 2.09
+
+   The 2.08 release did not compile with perl5.005_53, because
+   all simple globals now need to be prefixed with "PL_".
+
+
+
+1998-10-22   Gisle Aas <aas@sn.no>
+
+   Release 2.08
+
+   Found another tweak to speed up decode_base64() with another 3%.
+
+   Improved MIME::Base64 documentation a little.
+
+
+
+1998-10-21   Gisle Aas <aas@sn.no>
+
+   Release 2.07
+
+   Faster and smarter C implementation of the decode_base64()
+   function.  The new decode_base64() was 25% faster when tested
+   on Linux, i586, gcc -O2.
+
+
+
+1998-07-15   Gisle Aas <aas@sn.no>
+
+   Release 2.06
+
+   The decode_base64() implemented in pure perl will only carp
+   (not croak) if length of data to decode is not a multiple 4.  This
+   actually made 'make test' fail after 'rm Base64.xs'.
+
+
+
+1998-01-27   Gisle Aas <aas@sn.no>
+
+   Release 2.05
+
+   The decode_base64() would previously allocate a too short buffer for the
+   result string when the trailing "==" padding was missing in the string to
+   be decoded.
+
+   The encode_base64() now allocate one byte less space in the result
+   strings returned.
+
+
+
+1997-12-02   Gisle Aas <aas@sn.no>
+
+   Release 2.04
+
+   Documentation expanded a bit.
+
+
+
+1997-07-10   Gisle Aas <aas@sn.no>
+
+   Release 2.03
+
+   Decode_base64() doesn't croak on premature ended data any more.
+   A warning is generated instead if running under -w.
+   
+
+
+1997-06-27   Gisle Aas <aas@sn.no>
+
+   Release 2.02
+
+   QuotedPrint fix by Roderick Schertler <roderick@argon.org>:
+
+      - Long lines were not broken unless they're at the beginning
+        of the text
+
+      - Lines near but not over 76 chars were broken when they
+        shouldn't be
+
+
+
+1997-06-13   Gisle Aas <aas@sn.no>
+
+   Release 2.01
+
+   Base64.xs: Avoid type convertion warnings with some compilers
+
+   Minor documentation updates
+
+
+
+1997-04-24   Gisle Aas <aas@sn.no>
+
+   Release 2.00, based on libwww-perl-5.08.
+
Index: /main/tags/2.25/gsdl/packages/w3mir/MIME-Base64-2.11/INSTALL.w3mir
===================================================================
--- /main/tags/2.25/gsdl/packages/w3mir/MIME-Base64-2.11/INSTALL.w3mir	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/w3mir/MIME-Base64-2.11/INSTALL.w3mir	(revision 21064)
@@ -0,0 +1,27 @@
+- You also have to get the MIME-Base64 package
+  (http://www.perl.com/CPAN/modules/by-module/MIME/)
+
+- Unpack it:
+
+    gzip -dc MIME-Base64-*.tar.gz | tar xvBf -
+
+- Install it:
+
+    cd MIME-Base64-*
+
+  Then, as above, either
+
+    perl Makefile.PL
+
+  or
+
+    perl Makefile.PL PREFIX=/some/dir
+
+  Continue:
+
+    make
+    make test      (it should print 'All tests successful.')
+    make install
+
+  Now MIME-Base64 should be installed and working.
+
Index: /main/tags/2.25/gsdl/packages/w3mir/MIME-Base64-2.11/MANIFEST
===================================================================
--- /main/tags/2.25/gsdl/packages/w3mir/MIME-Base64-2.11/MANIFEST	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/w3mir/MIME-Base64-2.11/MANIFEST	(revision 21064)
@@ -0,0 +1,9 @@
+Base64.pm	Bootstrap and perl implementation of MIME::Base64
+Base64.xs	Encoder and decoder written in C
+Changes		What's new
+MANIFEST	This file
+Makefile.PL	Writes the Makefile
+QuotedPrint.pm  MIME::QuotedPrint module, encoder and decoder
+README		Please do!
+t/base64.t	Test that it works
+t/quoted-print.t
Index: /main/tags/2.25/gsdl/packages/w3mir/MIME-Base64-2.11/Makefile.PL
===================================================================
--- /main/tags/2.25/gsdl/packages/w3mir/MIME-Base64-2.11/Makefile.PL	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/w3mir/MIME-Base64-2.11/Makefile.PL	(revision 21064)
@@ -0,0 +1,8 @@
+require 5.002;
+use ExtUtils::MakeMaker;
+
+WriteMakefile(
+    NAME	 => 'MIME::Base64',
+    VERSION_FROM => 'Base64.pm',
+    dist         => { COMPRESS => 'gzip -9f', SUFFIX => 'gz', },
+);
Index: /main/tags/2.25/gsdl/packages/w3mir/MIME-Base64-2.11/QuotedPrint.pm
===================================================================
--- /main/tags/2.25/gsdl/packages/w3mir/MIME-Base64-2.11/QuotedPrint.pm	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/w3mir/MIME-Base64-2.11/QuotedPrint.pm	(revision 21064)
@@ -0,0 +1,115 @@
+#
+# $Id$
+
+package MIME::QuotedPrint;
+
+=head1 NAME
+
+MIME::QuotedPrint - Encoding and decoding of quoted-printable strings
+
+=head1 SYNOPSIS
+
+ use MIME::QuotedPrint;
+
+ $encoded = encode_qp($decoded);
+ $decoded = decode_qp($encoded);
+
+=head1 DESCRIPTION
+
+This module provides functions to encode and decode strings into the
+Quoted-Printable encoding specified in RFC 2045 - I<MIME (Multipurpose
+Internet Mail Extensions)>.  The Quoted-Printable encoding is intended
+to represent data that largely consists of bytes that correspond to
+printable characters in the ASCII character set.  Non-printable
+characters (as defined by english americans) are represented by a
+triplet consisting of the character "=" followed by two hexadecimal
+digits.
+
+The following functions are provided:
+
+=over 4
+
+=item encode_qp($str)
+
+This function will return an encoded version of the string given as
+argument.
+
+Note that encode_qp() does not change newlines C<"\n"> to the CRLF
+sequence even though this might be considered the right thing to do
+(RFC 2045 (Q-P Rule #4)).
+
+=item decode_qp($str);
+
+This function will return the plain text version of the string given
+as argument.
+
+=back
+
+
+If you prefer not to import these routines into your namespace you can
+call them as:
+
+  use MIME::QuotedPrint ();
+  $encoded = MIME::QuotedPrint::encode($decoded);
+  $decoded = MIME::QuotedPrint::decode($encoded);
+
+=head1 COPYRIGHT
+
+Copyright 1995-1997 Gisle Aas.
+
+This library is free software; you can redistribute it and/or
+modify it under the same terms as Perl itself.
+
+=cut
+
+use strict;
+use vars qw(@ISA @EXPORT $VERSION);
+
+require Exporter;
+@ISA = qw(Exporter);
+@EXPORT = qw(encode_qp decode_qp);
+
+$VERSION = sprintf("%d.%02d", q$Revision$ =~ /(\d+)\.(\d+)/);
+
+
+sub encode_qp ($)
+{
+    my $res = shift;
+    $res =~ s/([^ \t\n!-<>-~])/sprintf("=%02X", ord($1))/eg;  # rule #2,#3
+    $res =~ s/([ \t]+)$/
+      join('', map { sprintf("=%02X", ord($_)) }
+		   split('', $1)
+      )/egm;                        # rule #3 (encode whitespace at eol)
+
+    # rule #5 (lines must be shorter than 76 chars, but we are not allowed
+    # to break =XX escapes.  This makes things complicated :-( )
+    my $brokenlines = "";
+    $brokenlines .= "$1=\n"
+	while $res =~ s/(.*?^[^\n]{73} (?:
+		 [^=\n]{2} (?! [^=\n]{0,1} $) # 75 not followed by .?\n
+		|[^=\n]    (?! [^=\n]{0,2} $) # 74 not followed by .?.?\n
+		|          (?! [^=\n]{0,3} $) # 73 not followed by .?.?.?\n
+	    ))//xsm;
+
+    "$brokenlines$res";
+}
+
+
+sub decode_qp ($)
+{
+    my $res = shift;
+    $res =~ s/[ \t]+?(\r?\n)/$1/g;  # rule #3 (trailing space must be deleted)
+    $res =~ s/=\r?\n//g;            # rule #5 (soft line breaks)
+    $res =~ s/=([\da-fA-F]{2})/pack("C", hex($1))/ge;
+    $res;
+}
+
+# Set up aliases so that these functions also can be called as
+#
+# MIME::QuotedPrint::encode();
+# MIME::QuotedPrint::decode();
+
+*encode = \&encode_qp;
+*decode = \&decode_qp;
+
+1;
Index: /main/tags/2.25/gsdl/packages/w3mir/MIME-Base64-2.11/README
===================================================================
--- /main/tags/2.25/gsdl/packages/w3mir/MIME-Base64-2.11/README	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/w3mir/MIME-Base64-2.11/README	(revision 21064)
@@ -0,0 +1,38 @@
+This package contains a base64 encoder/decoder and a quoted-printable
+encoder/decoder.  These encoding methods are specified in RFC 2045 -
+MIME (Multipurpose Internet Mail Extensions).
+
+The Base64 encoding is designed to represent arbitrary sequences of
+octets in a form that need not be humanly readable. A 65-character
+subset ([A-Za-z0-9+/=]) of US-ASCII is used, enabling 6 bits to be
+represented per printable character.
+
+The quoted-printable encoding is intended to represent data that
+largely consists of bytes that correspond to printable characters in
+the ASCII character set.  Non-printable characters are represented by
+a triplet consisting of the character "=" followed by two hexadecimal
+digits.
+
+The MIME::Base64 and MIME::QuotedPrint modules used to be part of
+libwww-perl package.  They are now distributed separately (as this
+package).  The main improvement is that the base64 encoder/decoder is
+implemented by XS functions.  This makes it about 20 times faster than
+the old implementation as pure Perl.
+
+In order to install and use this package you will need Perl version
+5.002 or better.  Installation as usual:
+
+   perl Makefile.PL
+   make
+   make test
+   make install
+
+The library can also be installed without XS support (for instance because
+you don't have a working C compiler installed).  Simply remove the Base64.xs
+file before running 'perl Makefile.PL' and everything should work the same,
+although encoding and decoding will be much slower.
+
+Copyright 1995-1999 Gisle Aas <gisle@aas.no>
+
+This library is free software; you can redistribute it and/or
+modify it under the same terms as Perl itself.
Index: /main/tags/2.25/gsdl/packages/w3mir/MIME-Base64-2.11/install.sh
===================================================================
--- /main/tags/2.25/gsdl/packages/w3mir/MIME-Base64-2.11/install.sh	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/w3mir/MIME-Base64-2.11/install.sh	(revision 21064)
@@ -0,0 +1,10 @@
+#!/bin/sh -v
+
+export PERL5LIB=$GSDLHOME/perllib/cpan/lib:$PERL5LIB
+export PATH=$GSDLHOME/perllib/cpan/bin:$PATH
+
+perl Makefile.PL PREFIX=$GSDLHOME/perllib/cpan
+
+make
+make test
+make install
Index: /main/tags/2.25/gsdl/packages/w3mir/MIME-Base64-2.11/t/base64.t
===================================================================
--- /main/tags/2.25/gsdl/packages/w3mir/MIME-Base64-2.11/t/base64.t	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/w3mir/MIME-Base64-2.11/t/base64.t	(revision 21064)
@@ -0,0 +1,362 @@
+use MIME::Base64;
+
+print "1..282\n";
+
+print "Testing MIME::Base64-", $MIME::Base64::VERSION, "\n";
+
+$testno = 1;
+
+encodeTest();
+decodeTest();
+
+# This used to generate a warning
+print "not " unless decode_base64(encode_base64("foo")) eq "foo";
+print "ok ", $testno++, "\n";
+
+sub encodeTest
+{
+    print "encode test\n";
+
+    my @encode_tests = (
+        [''    => ''],
+	['a'   => 'YQ=='],
+	['aa'  => 'YWE='],
+	['aaa' => 'YWFh'],
+
+	['aaa' => 'YWFh'],
+	['aaa' => 'YWFh'],
+	['aaa' => 'YWFh'],
+
+	["\000\377" => "AP8="],
+	["\377\000" => "/wA="],
+	["\000\000\000" => "AAAA"],
+
+	# from HTTP spec
+	['Aladdin:open sesame' => 'QWxhZGRpbjpvcGVuIHNlc2FtZQ=='],
+
+	['a' x 100 => 'YWFh' x 33 . 'YQ=='],
+
+	['Multipurpose Internet Mail Extensions: The Base64 Content-Transfer-Encoding is designed to represent sequences of octets in a form that is not humanly readable. '
+	=> "TXVsdGlwdXJwb3NlIEludGVybmV0IE1haWwgRXh0ZW5zaW9uczogVGhlIEJhc2U2NCBDb250ZW50LVRyYW5zZmVyLUVuY29kaW5nIGlzIGRlc2lnbmVkIHRvIHJlcHJlc2VudCBzZXF1ZW5jZXMgb2Ygb2N0ZXRzIGluIGEgZm9ybSB0aGF0IGlzIG5vdCBodW1hbmx5IHJlYWRhYmxlLiA="],
+
+	# All values
+	["\000" => "AA=="],
+	["\001" => "AQ=="],
+	["\002" => "Ag=="],
+	["\003" => "Aw=="],
+	["\004" => "BA=="],
+	["\005" => "BQ=="],
+	["\006" => "Bg=="],
+	["\007" => "Bw=="],
+	["\010" => "CA=="],
+	["\011" => "CQ=="],
+	["\012" => "Cg=="],
+	["\013" => "Cw=="],
+	["\014" => "DA=="],
+	["\015" => "DQ=="],
+	["\016" => "Dg=="],
+	["\017" => "Dw=="],
+	["\020" => "EA=="],
+	["\021" => "EQ=="],
+	["\022" => "Eg=="],
+	["\023" => "Ew=="],
+	["\024" => "FA=="],
+	["\025" => "FQ=="],
+	["\026" => "Fg=="],
+	["\027" => "Fw=="],
+	["\030" => "GA=="],
+	["\031" => "GQ=="],
+	["\032" => "Gg=="],
+	["\033" => "Gw=="],
+	["\034" => "HA=="],
+	["\035" => "HQ=="],
+	["\036" => "Hg=="],
+	["\037" => "Hw=="],
+	["\040" => "IA=="],
+	["\041" => "IQ=="],
+	["\042" => "Ig=="],
+	["\043" => "Iw=="],
+	["\044" => "JA=="],
+	["\045" => "JQ=="],
+	["\046" => "Jg=="],
+	["\047" => "Jw=="],
+	["\050" => "KA=="],
+	["\051" => "KQ=="],
+	["\052" => "Kg=="],
+	["\053" => "Kw=="],
+	["\054" => "LA=="],
+	["\055" => "LQ=="],
+	["\056" => "Lg=="],
+	["\057" => "Lw=="],
+	["\060" => "MA=="],
+	["\061" => "MQ=="],
+	["\062" => "Mg=="],
+	["\063" => "Mw=="],
+	["\064" => "NA=="],
+	["\065" => "NQ=="],
+	["\066" => "Ng=="],
+	["\067" => "Nw=="],
+	["\070" => "OA=="],
+	["\071" => "OQ=="],
+	["\072" => "Og=="],
+	["\073" => "Ow=="],
+	["\074" => "PA=="],
+	["\075" => "PQ=="],
+	["\076" => "Pg=="],
+	["\077" => "Pw=="],
+	["\100" => "QA=="],
+	["\101" => "QQ=="],
+	["\102" => "Qg=="],
+	["\103" => "Qw=="],
+	["\104" => "RA=="],
+	["\105" => "RQ=="],
+	["\106" => "Rg=="],
+	["\107" => "Rw=="],
+	["\110" => "SA=="],
+	["\111" => "SQ=="],
+	["\112" => "Sg=="],
+	["\113" => "Sw=="],
+	["\114" => "TA=="],
+	["\115" => "TQ=="],
+	["\116" => "Tg=="],
+	["\117" => "Tw=="],
+	["\120" => "UA=="],
+	["\121" => "UQ=="],
+	["\122" => "Ug=="],
+	["\123" => "Uw=="],
+	["\124" => "VA=="],
+	["\125" => "VQ=="],
+	["\126" => "Vg=="],
+	["\127" => "Vw=="],
+	["\130" => "WA=="],
+	["\131" => "WQ=="],
+	["\132" => "Wg=="],
+	["\133" => "Ww=="],
+	["\134" => "XA=="],
+	["\135" => "XQ=="],
+	["\136" => "Xg=="],
+	["\137" => "Xw=="],
+	["\140" => "YA=="],
+	["\141" => "YQ=="],
+	["\142" => "Yg=="],
+	["\143" => "Yw=="],
+	["\144" => "ZA=="],
+	["\145" => "ZQ=="],
+	["\146" => "Zg=="],
+	["\147" => "Zw=="],
+	["\150" => "aA=="],
+	["\151" => "aQ=="],
+	["\152" => "ag=="],
+	["\153" => "aw=="],
+	["\154" => "bA=="],
+	["\155" => "bQ=="],
+	["\156" => "bg=="],
+	["\157" => "bw=="],
+	["\160" => "cA=="],
+	["\161" => "cQ=="],
+	["\162" => "cg=="],
+	["\163" => "cw=="],
+	["\164" => "dA=="],
+	["\165" => "dQ=="],
+	["\166" => "dg=="],
+	["\167" => "dw=="],
+	["\170" => "eA=="],
+	["\171" => "eQ=="],
+	["\172" => "eg=="],
+	["\173" => "ew=="],
+	["\174" => "fA=="],
+	["\175" => "fQ=="],
+	["\176" => "fg=="],
+	["\177" => "fw=="],
+	["\200" => "gA=="],
+	["\201" => "gQ=="],
+	["\202" => "gg=="],
+	["\203" => "gw=="],
+	["\204" => "hA=="],
+	["\205" => "hQ=="],
+	["\206" => "hg=="],
+	["\207" => "hw=="],
+	["\210" => "iA=="],
+	["\211" => "iQ=="],
+	["\212" => "ig=="],
+	["\213" => "iw=="],
+	["\214" => "jA=="],
+	["\215" => "jQ=="],
+	["\216" => "jg=="],
+	["\217" => "jw=="],
+	["\220" => "kA=="],
+	["\221" => "kQ=="],
+	["\222" => "kg=="],
+	["\223" => "kw=="],
+	["\224" => "lA=="],
+	["\225" => "lQ=="],
+	["\226" => "lg=="],
+	["\227" => "lw=="],
+	["\230" => "mA=="],
+	["\231" => "mQ=="],
+	["\232" => "mg=="],
+	["\233" => "mw=="],
+	["\234" => "nA=="],
+	["\235" => "nQ=="],
+	["\236" => "ng=="],
+	["\237" => "nw=="],
+	["\240" => "oA=="],
+	["\241" => "oQ=="],
+	["\242" => "og=="],
+	["\243" => "ow=="],
+	["\244" => "pA=="],
+	["\245" => "pQ=="],
+	["\246" => "pg=="],
+	["\247" => "pw=="],
+	["\250" => "qA=="],
+	["\251" => "qQ=="],
+	["\252" => "qg=="],
+	["\253" => "qw=="],
+	["\254" => "rA=="],
+	["\255" => "rQ=="],
+	["\256" => "rg=="],
+	["\257" => "rw=="],
+	["\260" => "sA=="],
+	["\261" => "sQ=="],
+	["\262" => "sg=="],
+	["\263" => "sw=="],
+	["\264" => "tA=="],
+	["\265" => "tQ=="],
+	["\266" => "tg=="],
+	["\267" => "tw=="],
+	["\270" => "uA=="],
+	["\271" => "uQ=="],
+	["\272" => "ug=="],
+	["\273" => "uw=="],
+	["\274" => "vA=="],
+	["\275" => "vQ=="],
+	["\276" => "vg=="],
+	["\277" => "vw=="],
+	["\300" => "wA=="],
+	["\301" => "wQ=="],
+	["\302" => "wg=="],
+	["\303" => "ww=="],
+	["\304" => "xA=="],
+	["\305" => "xQ=="],
+	["\306" => "xg=="],
+	["\307" => "xw=="],
+	["\310" => "yA=="],
+	["\311" => "yQ=="],
+	["\312" => "yg=="],
+	["\313" => "yw=="],
+	["\314" => "zA=="],
+	["\315" => "zQ=="],
+	["\316" => "zg=="],
+	["\317" => "zw=="],
+	["\320" => "0A=="],
+	["\321" => "0Q=="],
+	["\322" => "0g=="],
+	["\323" => "0w=="],
+	["\324" => "1A=="],
+	["\325" => "1Q=="],
+	["\326" => "1g=="],
+	["\327" => "1w=="],
+	["\330" => "2A=="],
+	["\331" => "2Q=="],
+	["\332" => "2g=="],
+	["\333" => "2w=="],
+	["\334" => "3A=="],
+	["\335" => "3Q=="],
+	["\336" => "3g=="],
+	["\337" => "3w=="],
+	["\340" => "4A=="],
+	["\341" => "4Q=="],
+	["\342" => "4g=="],
+	["\343" => "4w=="],
+	["\344" => "5A=="],
+	["\345" => "5Q=="],
+	["\346" => "5g=="],
+	["\347" => "5w=="],
+	["\350" => "6A=="],
+	["\351" => "6Q=="],
+	["\352" => "6g=="],
+	["\353" => "6w=="],
+	["\354" => "7A=="],
+	["\355" => "7Q=="],
+	["\356" => "7g=="],
+	["\357" => "7w=="],
+	["\360" => "8A=="],
+	["\361" => "8Q=="],
+	["\362" => "8g=="],
+	["\363" => "8w=="],
+	["\364" => "9A=="],
+	["\365" => "9Q=="],
+	["\366" => "9g=="],
+	["\367" => "9w=="],
+	["\370" => "+A=="],
+	["\371" => "+Q=="],
+	["\372" => "+g=="],
+	["\373" => "+w=="],
+	["\374" => "/A=="],
+	["\375" => "/Q=="],
+	["\376" => "/g=="],
+	["\377" => "/w=="],
+    );
+
+    for $test (@encode_tests) {
+	my($plain, $expected) = ($$test[0], $$test[1]);
+
+	my $encoded = encode_base64($plain, '');
+	if ($encoded ne $expected) {
+	    print "test $testno ($plain): expected $expected, got $encoded\n";
+            print "not ";
+	}
+	my $decoded = decode_base64($encoded);
+	if ($decoded ne $plain) {
+	    print "test $testno ($plain): expected $expected, got $encoded\n";
+            print "not ";
+	}
+
+	# Try the old C versions too
+	if ($encoded ne MIME::Base64::old_encode_base64($plain, '')) {
+	    print "old_encode_base64 give different result.\n";
+	    print "not ";
+        }
+	if ($plain ne MIME::Base64::old_decode_base64($encoded)) {
+	    print "old_decode_base64 give different result.\n";
+	    print "not ";
+        }
+		
+	print "ok $testno\n";
+	$testno++;
+    }
+}
+
+sub decodeTest
+{
+    print "decode test:\n";
+    local $SIG{__WARN__} = sub { print $_[0] };  # avoid warnings on stderr
+
+    my @decode_tests = (
+	['YWE='   => 'aa'],
+	[' YWE='  => 'aa'],
+	['Y WE='  => 'aa'],
+	['YWE= '  => 'aa'],
+	["Y\nW\r\nE=" => 'aa'],
+
+	# These will generate some warnings
+        ['YWE=====' => 'aa'],    # extra padding
+	['YWE'      => 'aa'],    # missing padding
+        ['YWFh====' => 'aaa'],
+        ['YQ'       => 'a'],
+        ['Y'        => ''],
+        [''         => ''],
+        [undef()    => ''],
+    );
+
+    for $test (@decode_tests) {
+	my($encoded, $expected) = ($$test[0], $$test[1]);
+
+	my $decoded = decode_base64($encoded);
+	if ($decoded ne $expected) {
+	    die "test $testno ($encoded): expected $expected, got $decoded\n";
+	}
+	print "ok $testno\n";
+	$testno++;
+    }
+}
Index: /main/tags/2.25/gsdl/packages/w3mir/MIME-Base64-2.11/t/quoted-print.t
===================================================================
--- /main/tags/2.25/gsdl/packages/w3mir/MIME-Base64-2.11/t/quoted-print.t	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/w3mir/MIME-Base64-2.11/t/quoted-print.t	(revision 21064)
@@ -0,0 +1,106 @@
+#!/local/bin/perl -w
+
+use MIME::QuotedPrint;
+
+$x70 = "x" x 70;
+
+@tests =
+  (
+   # plain ascii should not be encoded
+   ["quoted printable"  =>
+    "quoted printable"],
+
+   # 8-bit chars should be encoded
+   ["våre kjære norske tegn bør æres" =>
+    "v=E5re kj=E6re norske tegn b=F8r =E6res"],
+
+   # trailing space should be encoded
+   ["  " => "=20=20"],
+   ["\tt\t" => "\tt=09"],
+   ["test  \ntest\n\t \t \n" => "test=20=20\ntest\n=09=20=09=20\n"],
+
+   # "=" is special an should be decoded
+   ["=\n" => "=3D\n"],
+   ["\0\xff" => "=00=FF"],
+
+   # Very long lines should be broken (not more than 76 chars
+   ["The Quoted-Printable encoding is intended to represent data that largly consists of octets that correspond to printable characters in the ASCII character set." =>
+    "The Quoted-Printable encoding is intended to represent data that largly con=
+sists of octets that correspond to printable characters in the ASCII charac=
+ter set."
+    ],
+
+   # Long lines after short lines were broken through 2.01.
+   ["short line
+In America, any boy may become president and I suppose that's just one of the risks he takes. -- Adlai Stevenson" =>
+    "short line
+In America, any boy may become president and I suppose that's just one of t=
+he risks he takes. -- Adlai Stevenson"],
+
+   # My (roderick@argon.org) first crack at fixing that bug failed for
+   # multiple long lines.
+   ["College football is a game which would be much more interesting if the faculty played instead of the students, and even more interesting if the
+trustees played.  There would be a great increase in broken arms, legs, and necks, and simultaneously an appreciable diminution in the loss to humanity. -- H. L. Mencken" =>
+    "College football is a game which would be much more interesting if the facu=
+lty played instead of the students, and even more interesting if the
+trustees played.  There would be a great increase in broken arms, legs, and=
+ necks, and simultaneously an appreciable diminution in the loss to humanit=
+y. -- H. L. Mencken"],
+
+   # Don't break a line that's near but not over 76 chars.
+   ["$x70!23"		=> "$x70!23"],
+   ["$x70!234"		=> "$x70!234"],
+   ["$x70!2345"		=> "$x70!2345"],
+   ["$x70!23456"	=> "$x70!23456"],
+   ["$x70!23\n"		=> "$x70!23\n"],
+   ["$x70!234\n"	=> "$x70!234\n"],
+   ["$x70!2345\n"	=> "$x70!2345\n"],
+   ["$x70!23456\n"	=> "$x70!23456\n"],
+
+   # Not allowed to break =XX escapes using soft line break
+   ["$x70===xxxx" => "$x70=3D=\n=3D=3Dxxxx"],
+   ["$x70!===xxx" => "$x70!=3D=\n=3D=3Dxxx"],
+   ["$x70!!===xx" => "$x70!!=3D=\n=3D=3Dxx"],
+   ["$x70!!!===x" => "$x70!!!=\n=3D=3D=3Dx"],
+   #                            ^
+   #                    70123456|
+   #                           max
+   #                        line width
+);
+
+$notests = @tests + 2;
+print "1..$notests\n";
+
+$testno = 0;
+for (@tests) {
+    $testno++;
+    ($plain, $encoded) = @$_;
+    $x = encode_qp($plain);
+    if ($x ne $encoded) {
+	print "Encode test failed\n";
+	print "Got:      '$x'\n";
+	print "Expected: '$encoded'\n";
+	print "not ok $testno\n";
+	next;
+    }
+    $x = decode_qp($encoded);
+    if ($x ne $plain) {
+	print "Decode test failed\n";
+	print "Got:      '$x'\n";
+	print "Expected: '$plain'\n";
+	print "not ok $testno\n";
+	next;
+    }
+    print "ok $testno\n";
+}
+
+# Some extra testing for a case that was wrong until libwww-perl-5.09
+print "not " unless decode_qp("foo  \n\nfoo =\n\nfoo=20\n\n") eq
+                                "foo\n\nfoo \nfoo \n\n";
+$testno++; print "ok $testno\n";
+
+# Same test but with "\r\n" terminated lines
+print "not " unless decode_qp("foo  \r\n\r\nfoo =\r\n\r\nfoo=20\r\n\r\n") eq
+                                "foo\r\n\r\nfoo \r\nfoo \r\n\r\n";
+$testno++; print "ok $testno\n";
+
Index: /main/tags/2.25/gsdl/packages/w3mir/libwww-perl-5.36/ChangeLog
===================================================================
--- /main/tags/2.25/gsdl/packages/w3mir/libwww-perl-5.36/ChangeLog	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/w3mir/libwww-perl-5.36/ChangeLog	(revision 21064)
@@ -0,0 +1,1535 @@
+Tue Aug  4 1998   Gisle Aas <aas@sn.no>
+
+ o  Release 5.36
+
+ o  The lwp-download script will call $ua->env_proxy now.
+
+ o  The lwp-request script allows content types (specified with the -c
+    option) with optional parameters like: multipart/mixed; boundary="--".
+
+ o  LWP::UserAgent will lowercase all authentication parameter names
+    before passing it to the authentication module.  Previous releases
+    ignored parameters like; Realm="Foo" (bacause Realm contained
+    upper case letters).
+
+ o  LWP::Protocol::ftp test for If-Modified-Since was wrong.
+
+ o  How the $url->abs method works can now be configured with the global
+    variables $URI::URL::ABS_ALLOW_RELATIVE_SCHEME and
+    $URI::URL::ABS_REMOTE_LEADING_DOTS.
+
+ o  The anonymous password guesser for ftp URLs will now call the external
+    `whoami` program any more.  Patch by Charles C. Fu <ccwf@bacchus.com>.
+
+ o  LWP::Protocol::http now allow dynamic requests without any
+    Content-Length specified when Content-Type is multipart/*
+
+ o  HTTP::Request::Common can now upload infinite files.
+    (Controlled by the $DYNAMIC_FILE_UPLOAD configuration variable.)
+
+
+
+Fri Jul 10 1998   Gisle Aas <aas@sn.no>
+
+ o  Release 5.35
+
+ o  More lwp-rget patches from David D. Kilzer <ddkilzer@madison.dseg.ti.com>.
+    Adds the following new options: --iis, --keepext, --tolower
+
+ o  LWP::MediaTypes patches from MacEachern <dougm@pobox.com>.  Adds new
+    functions: add_type(), add_encoding(), read_media_types()
+
+
+
+Tue Jul  7 1998   Gisle Aas <aas@sn.no>
+
+ o  Release 5.34
+
+ o  LWP::Protocol::ftp now try to use the MDTM command to support
+    the Last-Modified response header as well as
+    If-Modified-Since in requests.  Original and final patch by
+    Charles C. Fu <ccwf@bacchus.com>
+
+ o  $url->path_components will not escape "." any more.
+
+ o  WWW::RobotRules will now work for Mac text files too (lines delimited
+    by CR only).  Patch by Olly Betts <olly@muscat.co.uk>
+
+ o  lwp-rget support <area ..> links too.
+
+
+
+Thu May  7 1998   Gisle Aas <aas@sn.no>
+
+ o  Release 5.33
+
+ o  LWP::Simple::get() did try to handle too many of the 3xx
+    codes as redirect when it bypasses full LWP.
+
+ o  LWP::UserAgent->mirror will now use utime(2) to set the
+    file modification time corresponding to the Last-Modified
+    header.
+
+ o  LWP::Protocol::http will not modify the HTTP::Request that
+    it is processing.  This avoids sticky Host header for
+    redirects.
+
+ o  URI::Heuristic and lwp-download documentation update.
+
+
+
+Wed Apr 15 1998   Gisle Aas <aas@sn.no>
+
+ o  Release 5.32
+
+ o  Much improved HTTP::Daemon class. We now support persistent
+    connections.  Changes include:
+       - $c->get_request can be told to return after reading and
+         parsing headers only.
+       - $c->reason (new method)
+       - $c->read_buffer (new method)
+       - $c->proto_ge (new method)
+       - $c->force_last_request (new method)
+       - $c->send_response now support CODE reference content
+         and will use chunked transfer encoding for HTTP/1.1 clients.
+       - expanded the documentation.
+
+
+
+Fri Apr 10 1998   Gisle Aas <aas@sn.no>
+
+ o  Release 5.31
+
+ o  Makefile.PL now checks that HTML::HeadParser is present.
+
+ o  Updated HTTP::Cookies according to draft-ietf-http-state-man-mec-08.txt
+    It now supports the .local domain and value less 'port' attribute in
+    the Set-Cookie2 header.
+
+ o  HTTP::Headers update:
+       - $h->content_type now always return a defined value
+       - $h->header($field) will now concatenate multi-valued header
+         fields with "," as separator in scalar context.
+
+ o  HTTP::Request::Common update:
+       - used to destroy the content of the  hash/array arguments
+         passed to its constructor functions.
+       - allow a hash reference to specify form-data content.
+       - you can override Content-Disposition for form-data now.
+       - set content-encoding for files if applicable
+       - default boundary string is now always "--000"
+
+ o  LWP::UserAgent will not follow more than 13 redirects
+    automatically.
+
+
+
+Wed Apr  1 1998   Gisle Aas <aas@sn.no>
+
+ o  Release 5.30
+
+ o  Unbundled the following modules:
+
+       * HTML-Parser  (HTML::Parser, HTML::Entites, HTML::LinkExtor,...)
+       * HTML-Tree    (HTML::Element, HTML::TreeBuilder,...)
+       * Font-AFM     (Font::AFM, Font::Metrics::*)
+       * File-CounterFile
+
+ o  Simplified internal structure of HTML::Headers.  Hopefully,
+    nobody will notice.
+
+ o  New modules HTTP::Headers::Auth,  HTTP::Headers::ETag that adds
+    additional convenience methods to the HTTP::Headers class.
+
+ o  Removed split_etag_list() from HTTP::Headers::Util, in the hope
+    that nobody had starting using it.
+
+
+
+Tue Mar 24 1998   Gisle Aas <aas@sn.no>
+
+ o  Release 5.22
+
+ o  HTTP::Cookies made more compatible with Netscape cookies.  Allow
+    the domain to match host, allow dots in the part of the hostname
+    not covered by domain.  Don't quote the cookie value even when it
+    contains non-token chars.  Based on patch from Kartik Subbarao
+    <subbarao@computer.org>.
+
+ o  Updated HTTP::Status to reflect <draft-ietf-http-v11-spec-rev-03>.
+    RC_MOVED_TEMPORARILY renamed to RC_FOUND.  Added codes
+    RC_TEMPORARY_REDIRECT (307) and RC_EXPECTATION_FAILED (417).
+    Slightly more documentation too.
+
+ o  The split_header_words() function HTTP::Headers::Util could go
+    into infinite loop on some header values.  Implemented split_etag_list()
+    too.  Added more documentation and test script for this module.
+
+ o  LWP::Simple now switch to full LWP implementation even for systems
+    that force all environment keys to be upper case.  Modification
+    suggested by Dale Couch <dcouch@training.orl.lmco.com>.
+
+ o  LWP::UserAgent allows redirects to a relative URL with scheme to be
+    made.  Suggested by Chris W. Unger <cunger@cas.org>.
+
+ o  Applied dtd2pm.pl patches from <peterm@zeta.org.au>.  It can now
+    extract information from the HTML40.dtd
+
+
+
+Thu Mar 12 1998   Gisle Aas <aas@sn.no>
+
+ o  Release 5.21
+
+ o  lwp-rget patches from David D. Kilzer <ddkilzer@madison.dseg.ti.com>
+    (modified by Gisle).  Support the --hier  and the --auth options
+    and <frame>s.
+
+ o  File::CounterFile protect against bad $/ and $\ as suggested
+    by Frank Hoehne.
+ 
+ o  File::Listing used "next" when return was more appropriate.
+    Patch by erik@mediator.uni-c.dk.
+
+ o  HTML::Element support for multiple boolean attributes for a single
+    element.  Patch by Philip Guenther.
+
+ o  Can set $HTTP::Headers::TRANSLATE_UNDERSCORE to FALSE value to
+    suppress tr/_/-/ of header keys.
+
+ o  LWP::Protocol::http will not initialize the Host header if it is
+    already set. Patch by Ed Jordan.
+
+ o  LWP::Protocol::http did not handle responses with no header lines
+    correctly.  Patch by Daniel Buenzli <buenzli@rzu.unizh.ch>
+
+ o  $url->rel() handles path segments without leading "/" better.
+
+
+
+Fri Feb 13 1998   Gisle Aas <aas@sn.no>
+
+ o  Release 5.20
+
+ o  Fixed the "500 Offset outside string" bug that affected perl
+    5.004_03 and older version of Perl.
+
+ o  Fixed a documentation typo spotted by Michael Quaranta
+    <quaranta@vnet.IBM.COM>
+
+ o  HTTP::Date: Protect against croaking from timegm/timelocal.
+
+
+
+Mon Jan 26 1998   Gisle Aas <aas@sn.no>
+
+ o  Release 5.19
+
+ o  HTML::Parser does not call $self->text() callback for empty text
+    any more.
+
+ o  LWP::Protocol::https was noisy when connections failed and the
+    script was running with '-w' (noise inherited from IO::Socket::INET)
+
+ o  $ua->use_alarm(BOOL) now gives a warning if running with -w
+
+
+
+Tue Jan 20 1998   Gisle Aas <aas@sn.no>
+
+ o  Developer release 5.18_05
+
+ o  HTTPS support based on my Crypt-SSLeay module.  The Net-SSLeay module
+    is not supported any more.
+
+ o  lwp-request documentation typo spotted Martijn Koster.
+
+ o  Removed superfluous \\ in the URI::Escape regex. This was also
+    spotted by Martijn.
+
+ o  File::Listing now handles timezones correctly.
+
+ o  Added $VERSION to modules that was missing it.
+
+ o  Added 'use strict' to several modules that was missing it.
+
+ o  LWP::Protocol::http now adds the Client-Peer header to responses and
+    has hooks for more callbacks.
+
+ o  LWP::Protocol::https adds Client-SSL-Cipher, Client-SSL-Cert-Subject
+    and Client-SSL-Cert-Issuer headers to the response.  The requests can
+    also be made conditional based on the peer certificate using the
+    If-SSL-Cert-Subject header in requests.
+
+ o  HTML::Parse is back.  (It was even used in lwpcook.pod)
+
+
+
+Wed Dec 17 1997   Gisle Aas <aas@sn.no>
+
+ o  Developer release 5.18_04
+
+ o  Makefile.PL fix based on report from Pon Hwa Lin <koala@fragment.com>
+
+ o  lwp-request will now print the response code message with -s and -S
+    options.
+
+ o  Hide IO::Socket::INET noise when running under -w
+
+ o  Don't set 'Content-Length: 0' in HTTP requests.
+
+ o  LWP::Protocol::http now calls LWP::Debug::conns again
+
+
+
+Tue Dec 16 1997   Gisle Aas <aas@sn.no>
+
+ o  Developer release 5.18_03
+
+ o  Got rid of alarms() and replaced LWP::Socket with IO::Socket::INET.
+    New protocol implementations for http, https, gopher, nntp.
+    $ua->use_alarm() is now a noop.
+
+ o  LWP::Protocol::ftp patch from  Tony Finch <fanf@demon.net>.
+
+ o  Removed depreciated modules from the distibution; HTML::Parse,
+    LWP::Socket, LWP::SecureSocket, LWP::IO, LWP::TkIO.
+
+
+
+Fri Dec 12 1997   Gisle Aas <aas@sn.no>
+
+ o  Release 5.18
+
+ o  HTTP authorization patches from Tony Finch <fanf@demon.net>.
+    Allows "user:pass@" in HTTP URLs.
+
+ o  HTML::Parser patch by Brian McCauley <B.A.McCauley@bham.ac.uk>.
+    Pass original text to end() method.
+
+ o  The HTML::Parser->netscape_buggy_comment method is depreciated.
+    Use HTML::Parser->strict_comment instead.  The default value
+    has changed with the name.
+
+ o  Some HTML::Parser optimization tweaks.
+
+ o  New module named HTML::Filter
+
+ o  Updated HTTP::Headers to the latest HTTP spec.  Added knowledge
+    about the "Trailer", "Expect", "TE", "Accept-Range" headers.
+    "Public" header is gone.
+
+ o  Added some more header convenience methods: if_unmodified_since,
+    content_language, and proxy_authorization methods.
+
+ o  HTTP::{Request,Response}->clone can handle subclasses now.
+
+ o  HTTP::Request->url() can now undefine the URL.
+
+ o  HTTP::{Request,Response}->as_string format looks more like
+    the HTTP protocol formatting now.  Dashed lines above and
+    below is gone.
+
+ o  Documented HTTP::Response->status_line method
+
+ o  Compressed HTML::Response->error_as_HTML output
+
+ o  HTTP::Status updated to latest HTTP spec.  Added 
+    RC_REQUEST_RANGE_NOT_SATISFIABLE (416)
+
+
+
+Tue Dec  2 1997   Gisle Aas <aas@sn.no>
+
+ o  Release 5.17
+
+ o  All authentication handling moved out of LWP::UserAgent and into
+    LWP::Authen::Basic and LWP::Authen::Digest.  We now also support
+    PROXY_AUTHENTICATION_REQUIRED responses.
+
+ o  HTML::Formatter will always add a blank line for <br>.
+
+ o  Avoid use of uninitialized value in HTTP::Daemon.
+
+ o  HTTP::Date allows seconds when recognizing 'ls -l' dates.  This
+    allows us to parse syslog time stamps.
+
+ o  HTTP::Request::Common::POST allows a hash reference as second
+    argument (in addition to an array reference).
+
+ o  LWP::Simple will initialize the $ua if it is exported.
+
+ o  Various documentation updates.
+
+
+
+Fri Nov 21 1997   Gisle Aas <aas@sn.no>
+
+ o  Release 5.16
+
+ o  LWP::Simple::head() would die in array context because str2time
+    was not imported any more.
+
+ o  HTTP::Daemon->accept now takes an optional package argument like
+    IO::Socket->accept does.
+
+ o  Made HTTP::Request and HTTP::Response subclassable.
+
+ o  Added Proxy-Authorization example to lwpcook.
+
+
+
+Thu Nov  6 1997   Gisle Aas <aas@sn.no>
+
+ o  Release 5.15
+
+ o  New module URI::Heuristic
+
+ o  The lwp-request script now use URI::Heuristic for it's URL arguments.
+    It means that 'lwp-request perl' will not get a file called "./perl"
+    but will fetch the page "http://www.perl.com" or something similar.
+    If you want to get the file you have to prefix it with "./".  Full
+    URLs are never affected by this.
+
+ o  LWP::Simple::get() will bypass LWP for simple HTTP requests.  This
+    should make it somewhat faster.
+
+ o  LWP::RobotUA has a new method called $ua->use_sleep() that
+    controls how niceness towards the servers are enforced.
+    Previously $ua->use_alarm() used to control this, but this did
+    not work well on Win32 systems.
+
+ o  URI::URL::rel() will handle URLs to a fragment within the same
+    document better. Initial patch from Nicolai Langfeldt
+    <janl@math.uio.no>.
+
+ o  HTML::Element don't consider </th>, </tr> and </td> optional any
+    more.  I wonder how Netscape managed to not implement this
+    correctly all this time.
+
+ o  Added lots of modern tags to HTML::AsSubs.
+
+ o  HTTP::Request::Common will read uploaded files in binmode().
+    This should be better for Win32 systems.  Contributed by
+    <Steve_Kilbane@cegelecproj.co.uk>.
+
+
+
+Sun Oct 12 1997   Gisle Aas <aas@sn.no>
+
+ o  Release 5.14
+
+ o  HTML::Formatter patches from Andreas Gustafsson <gson@araneus.fi>.
+    The formatters handling of whitespace is much better now.  Thanks!
+
+ o  HTML::FormatText: can specify margins in the constructor.
+
+ o  URI::URL: the base will be absolutized internally now.
+
+ o  URI::URL will take advantage of void context provided by perl5.004.
+    This means that using $u->path and $u->query should be safer now.
+
+ o  URI::URL->print_on defaults to STDERR now (used to be STDOUT).
+
+ o  URI::URL: removed version 3 compatibility stuff ($COMPAT_VER_3).
+
+ o  $ua->mirror should work better on dosish systems (can not
+    rename when target file exists).
+
+ o  Typo in lwp-download prevented it from compiling.
+
+ o  Some minor documentations typos corrected.
+
+
+
+Sat Sep 20 1997   Gisle Aas <aas@sn.no>
+
+ o  Release 5.13
+
+ o  Brand new module called HTTP::Cookies.  It stores cookies
+    (Set-Cookie and Set-Cookie2 headers) from responses and can
+    create appropriate Cookie headers for requests.  It can also
+    share cookie files with Netscape.
+
+ o  LWP::UserAgent now support the cookie_jar() attribute.  When
+    set to an HTTP::Cookies object, it will automatically manage
+    the cookies sent to the servers.  Off by default.
+
+ o  New header utility functions in HTTP::Headers::Util.
+
+ o  Win32 and OS/2 patches for the lwp-xxx utilities.  Turn on
+    binary mode by default (option to turn it off), avoid modifying $0,
+    and don't be confused about suffixes in the script names.
+    Contributed by Ben Coleman <bcoleman@mindspring.com>
+
+ o  OpenVMS patch for Font:AFM by Brad Hughes <brad@tmc.naecker.com>
+
+
+
+Fri Sep  5 1997   Gisle Aas <aas@sn.no>
+
+ o  Release 5.12
+
+ o  decode_entities() would sometimes introduce ";" after
+    things that looked like they were entities.
+
+ o  HTML::LinkExtor knows about <applet code="...">
+
+ o  Patch from Gary Shea <shea@gtsdesign.com> that makes the
+    tests work even if perl is not called "perl"
+
+ o  HTTP::Date handles 12:00PM correctly now. Patch from
+    William York <william@mathworks.com>
+
+ o  HTTP::Request::Common don't quote the boundary string for
+    multipart/form-data messages any more.
+
+ o  Font::AFM works for encodings where .notdef is defined to
+    have some size.  Documentation and efficiency update.
+
+
+
+Wed Aug  6 1997   Gisle Aas <aas@sn.no>
+
+ o  Release 5.11
+
+ o  Perl version 5.004 is now required for libwww-perl.
+
+ o  Win32 patches from Gurusamy Sarathy <gsar@engin.umich.edu>.
+    Now passes all tests on that platform.
+
+ o  HTTPS support contributed by Josh Kronengold <mneme@mcny.com>
+
+ o  Support hex entities &#xFF;  HTML::Entities::(en|de)code only
+    modify their argument in void context.
+
+ o  Fixed formatter bug with <font> tags which did not specify size.
+
+ o  Better HTML::HeadParser documentation
+
+ o  Fixed HTML::LinkExtor documentation typo spotted by Martijn.
+
+ o  HTTP::Request::Common now use CRLF for multipart/form-data
+
+
+
+Fri Jun 20 1997   Gisle Aas <aas@sn.no>
+
+ o  Release 5.10
+
+ o  Make '+' a reserved URL character.  Decode unescaped '+' as
+    space in $url->query_form().
+
+ o  Use $Config{d_alarm} to determine default for $ua->use_alarm()
+
+
+
+Tue Jun 10 1997   Gisle Aas <aas@sn.no>
+
+ o  Release 5.09
+
+ o  Removed the MIME modules from the distribution.  They are distributed
+    separately now.
+
+ o  Added a new module called HTTP::Request::Common
+
+ o  Improved HTTP::Status documentation.  It is now also possible
+    to import the is_client_error/is_server_error functions.
+
+ o  LWP::MediaTypes::guess_media_type() can now take an optional
+    HTTP::Header parameter.
+
+ o  LWP::Protocol ensures that scheme is legal as module name.
+
+ o  LWP::Protocol::http is not as strict when trying to verify the
+    method name.  It now also accepts responses without a message
+    on the status line.
+
+ o  WWW::RobotRules::AnyDBM_File: Some DBMs fail to allow multiple
+    opens of the same file.  Patch from Mark James <jamesm@skate.org>
+
+ o  Created Bundle::LWP
+
+
+
+Sat Apr  5 1997   Gisle Aas <aas@sn.no>
+
+ o  Release 5.08
+
+ o  Made libwww-perl warning compatible with upcoming perl5.004beta2
+    (aka 5.003_98)
+
+ o  encode_base64() did not work properly if pos() of the string to
+    encode was different from 0.
+
+ o  HTML::Parser was confused about "</" when it did not start an end tag.
+
+ o  HTML::FormatPS will provide ISOLatin1Encoding in its output.
+
+ o  Calling HTML::LinkExtor->links will clear out old links.
+
+ o  url()->rel($base) would ignore the $base argument.
+
+ o  Don't croak() when setting url()->path().
+
+
+
+Tue Feb 11 1997   Gisle Aas <aas@sn.no>
+
+ o  Release 5.07
+
+ o  Can limit the size of the response content with $ua->max_size()
+
+ o  Added time2iso() functions to HTTP::Date.
+
+ o  Made LWP::Protocol::http more portable to the MacPerl. /./ match
+    different things on MacPerl.
+
+
+
+Mon Jan 27 1997   Gisle Aas <aas@sn.no>
+
+ o  Release 5.06
+
+ o  URI::URL is now compatible with perl5.004 overloading.
+
+ o  HTML::HeadParser makes X-Meta-Name headers for <meta> elements
+    that does not specify an 'http-equiv' attribute.
+
+ o  URI::URL::ftp does not die if Net::Domain is not installed and
+    you ask for an anonymous username or password.
+
+ o  WWW::RobotRules:  The robots.txt parser did not ignore comment lines
+    as it should.
+
+ o  LWP::Protocol::http is more forgiving towards servers that return
+    bad responses.
+
+ o  Allow "?" before search string in gopher URLs.
+
+ o  LWP::Protocol::file did not escape funny filenames when generating
+    HTML directory listings.
+
+ o  LWP::Protocol::ftp now gets the Content-Encoding correct. 'CODE'
+    content in PUT requests also work now.
+
+ o  Relative locations in redirects did not work with URI::URL::strict.
+
+ o  OS/2 portability patches from Ilya Zakharevich
+
+ o  LWP::Authen::* patch from Doug MacEachern
+
+ o  Support experimental data:- URLs
+
+ o  Some tests (those using HTTP::Daemon) now die more gracefully if
+    IO::* modules is not installed.
+
+
+
+Wed Dec  4 1996   Gisle Aas <aas@sn.no>
+
+ o  Release 5.05
+
+ o  LWP::UserAgent::simple_request: local($SIG{__DIE__}) protects us
+    against user defined die handlers.
+ 	
+ o  Use Net::Domain (instead of Sys::Hostname) to determine FQDN.  It
+    is used by URI::URL when it determines anonymous ftp login address.
+	
+ o  lwp-download: New program in the bin directory
+
+ o  HTML::Parser: Allow '_' in attribute names.  This makes it possible
+    to parse Netscape's bookmarks.html file.
+
+ o  HTTP::Daemon: Fixed chunked transfer encoding and multipart content
+    in get_request().  Support HTTP/0.9 clients.
+
+ o  Don't clobber regex variables when HTTP::Message delegates methods
+    to the header.
+
+ o  Base64::decode_base64 now checks that the length input string to
+    decode is a multiple of 4.
+
+ o  t/robot/rules-dbm.t clean up better and will use AnyDBM for dumping
+
+ o  File::CounterFile: $/ strikes again by Andreas König
+
+ o  File::Listing updates from William York <william@mathworks.com>. We
+    can now parse the MS-Windows ftp server listings.
+
+ o  HTTP::Date now supports the MS-Windows 'dir' date format.  Patch by
+    William York.
+
+ o  LWP::MediaTypes::media_suffix will return first type in scalar context.
+
+
+
+Tue Oct 22 1996   Gisle Aas <aas@sn.no>
+
+ o  Release 5.04
+
+ o  Added HTTP::Daemon.  This is a HTTP/1.1 server class.  This means
+    that libwww-perl no longer is a client library only.  The HTTP::Daemon
+    is also used in the new test suite.
+
+ o  HTTP::Message support the protocol() method.  Used by HTTP::Daemon.
+
+ o  HTTP::Response can be constructed with a header and content as
+    argument.
+
+ o  Typo corrections in the documentation.
+
+ o  File::Listing::parse_dir accepts "GMT" as timezone now.
+
+ o  HTML::Parser will call the start() method with two new parameters;
+    $attrseq, $origtext.
+
+ o  Integrated HTML::FormatPS patches from
+    Jim Stern <jstern@world.northgrum.com>
+
+ o  Class modules don't inherit from AutoLoader any more.  They just
+    import the AUTOLOAD method.
+
+ o  LWP::Protocol will untaints scheme before loading protocol module.
+
+ o  Digest does not send "opaque" if it was not present in the request.
+    The "Extension" header is not returned any more.
+
+ o  New method: $url->crack that will return a list of the various
+    elements in a URI::URL.
+
+ o  WWW::RobotRules did not use the agent() method when determining
+    who we are.  This affected WWW::RobotRules::AnyDBM_File parsing
+    for robots.txt.  Visit count did not increment for
+    WWW::RobotRules::InCore.
+
+
+
+Tue Oct  1 1996   Gisle Aas <aas@sn.no>
+
+ o  Release 5.03
+
+ o  Hakan Ardo's persistent robot rules is now part of the standard
+    distribution.  This is still experimental and might change in the
+    future.  It includes the new WWW::RobotRules::AnyDBM_File class
+    and updates to LWP::RobotUA.
+
+ o  HTML::Parser now supports buggy Netscape comment parsing.  Enable
+    it by calling $p->netscape_buggy_comment(1).  The previous version
+    of the parser could also (under very unlucky and unlikely
+    circumstances) call the $self->comment() method several times for
+    the same comment text.
+
+ o  HTML::Parser: Use new $p->eof to signal end of document instead of
+    $p->parse(undef).
+
+ o  HTML::Element::starttag() is now smarter about which quotes it
+    use around attribute values.
+
+ o  New HTTP::Response methods: current_age(), freshness_lifetime(),
+    is_fresh(), fresh_until().
+
+ o  HTTP::Message:  New method ($mess->content_ref) which will return
+    a reference to the current content.
+
+ o  URI::URL:  New method ($url->rel) which does the opposite of abs().
+    Example: url("http://host/a/b/c", "http://host/c/d/e")->rel would
+    return url("../../a/b/c", "http://host/c/d/e").  This was
+    suggested by Nicolai Langfeldt <janl@ifi.uio.no>
+
+ o  URI::URL:  $url->query_form can now take array references as value
+    specification.  For instance: $url->query_form(foo => ['bar', 'baz']
+
+ o  Avoid '"my" variable $var masks earlier declaration in same scope'
+    warnings in perl5.003_05.
+
+
+
+Wed Sep 11 1996   Gisle Aas <aas@sn.no>
+
+ o  Release 5.02
+
+ o  lwp-rget:  Initialize proxy settings from envirionment
+
+ o  HTML::Entities::encode_entities: Don't encode $ and %
+
+ o  HTML::LinkExtor::links: Now works when no links were found.
+
+ o  HTTP::Headers::as_string: Allow \n in header value
+
+
+
+Tue Aug  1 1996   Gisle Aas <aas@sn.no>
+
+ o  Release 5.01.
+
+ o  Updated ftp protocol module to be compatible with Net::FTP 
+    version 2.00 (the version found in libnet-1.00)
+
+ o  New HTML parser module called HTML::LinkExtor
+
+ o  Various documentation typo corrections.  Most of these contributed
+    by Bob Dalgleish.
+
+ o  HTML::HeadParser updates 'Content-Base' instead of 'Base'.  It also
+    updates the 'Link' header based on <link ...>
+
+ o  HTTP::Headers and HTTP::Status updated according to
+    draft-ietf-http-v11-spec-06
+
+ o  HTTP::Headers can now use "_" as alternative to "-" in field names.
+
+ o  HTTP::Response::base now looks for 'Content-Base',
+    'Content-Location' and 'Base' headers.
+
+ o  Avoid warning in LWP::MediaTypes if $ENV{HOME} is not defined.
+
+ o  The new $ua->parse_head() method can be used to turn off
+    automatic initialization of response headers from the <HEAD>
+    section of HTML documents.
+
+ o  Added eq() method for URI::URL objects
+
+ o  The HTML::Formatter recovers even if a handle method is not defined
+    for all tags found during traversal
+
+
+
+Sun May 26 1996   Gisle Aas <aas@sn.no>
+
+ o  Release 5.00.
+
+ o  LWP::Simple::head() now return something useful in scalar context.
+
+ o  Rewritten the HTML::Parse stuff.  Introduced the HTML::Parser class
+    that will tokenize a HTML document.  The rest of the old
+    HTML::Parse functionality has moved to HTML::TreeBuilder class.
+    Note, that the HTML stuff is still alpha.
+
+ o  Implemented HTML::HeadParser.  This is a lightweight parser for
+    the <HEAD> section of a HTML document.
+
+ o  HTML::Element had problem with presenting things like <foo
+    bar="bar">.
+
+ o  HTML::Entities: Included additional ISO-8859/1 entities listed in
+    RFC1866.
+
+ o  HTML::AsSubs exported 'header' instead of 'head'
+
+ o  We know about a few more of the HTML 3.2 element.
+
+ o  HTTP::Date had problems with years before 1970, because Time::Local
+    went into an infinite loop.  Check for this.
+
+ o  Added $header->title method.
+
+ o  Made $header->authorization_basic return "uname:passwd" in scalar
+    context
+
+ o  LWP::Protocol::collect() will let the HTML::HeadParser look at the
+    document content as it arrives.  This will initialize headers from
+    elements like <base href="...">, <title>...</title> and <meta
+    http-equiv="..." ...>.
+
+ o  Simplified $response->base implementation, because we don't have
+    to look into the content any more.
+
+ o  Added -quiet option to lwp-rget
+
+ o  Typo fixes and some documentation additions.
+
+
+
+Thu May  9 1996   Gisle Aas <aas@sn.no>
+
+ o  Release 5b13
+
+ o  Made URI::URL::strict(0) the default.  I got tired of all this
+    eval { } stuff just to recover.  The URI::URL::strict'ness also
+    determine if calling some standard method that happens to be
+    illegal for some protocol scheme will croak or just be ignored.
+
+ o  Ensure correct $INPUT_RECORD_SEPARATOR and $OUTPUT_RECORD_SEPARATOR
+    at places where we <> or print.
+
+ o  Always localize $_ before any 'while(<FILE>) {}'-loops
+
+ o  Implemented $protocol->collect_once() and simplified several
+    of the protocol implementations by using it.
+
+ o  The HTML parser used to get it wrong if you were unlucky about the
+    breakup of the text. An example of broken behaviour was this:
+
+        $html = parse_html "<!-- A comment -";
+        $html = parse_html "-> and some text.";
+
+ o  The HTML parser does not ignore whitespace-only text any more.
+
+ o  HTML::Parse warnings are now optional and turned off by default.
+
+ o  New start for $html->as_HTML().
+
+ o  Fixed some typos
+
+
+
+Wed Apr 24 1996   Gisle Aas <aas@sn.no>
+
+ o  Release 5b12
+
+ o  New utility program called 'lwp-rget'.
+
+ o  $response->base was broken for HTML documents
+
+ o  New fancy LWP::Debug import() method.  Can now turn on debugging with
+    "use LWP::Debug '+';"
+
+ o  Trap exceptions (die) from the response callback routine
+
+ o  The RobotUA now requires an e-mail address of the person reponsible
+    for the robot.
+
+ o  New $ua->from() method.
+
+ o  Support for gopher Index-Search (gopher type '7' requests).
+    Contributed by Harry Bochner <bochner@das.harvard.edu>
+
+ o  Cleaned up white-space usage in the source.
+
+
+
+Wed Apr  3 1996   Gisle Aas <aas@sn.no>
+
+ o  Release 5b11
+
+ o  Implemented a NNTP protocol module.  The library can now fetch and
+    post news articles.
+
+ o  More documentation
+
+ o  Don't look at the URI header for redirects
+
+ o  New $res->base() method for HTTP::Responses
+
+ o  Graham Barr's patch to File::Listing to make it more OO internally
+
+ o  content_type() return value is canonicalized
+
+ o  $ua->request() does not die on bad URLs any more
+
+ o  LWP::MediaTypes merge all media.types files that if finds
+
+ o  FTP request with content to file or callback did not work
+
+ o  The value of HTTP Host: header is now $url->netloc;
+
+ o  The URI::URL constructor now accept URLs wrapped up in "<>"
+
+ o  $url->abs() now has a second optional argument that makes it accept
+    that relative URLs can have scheme, i.e. treat "http:img.gif" as a
+    relative URL.
+
+ o  Added prototypes to the HTTP::Status::is_xxx() functions
+
+ o  Added prototypes to the MIME:: encoding/decoding functions
+
+ o  Always return scheme for mailto and news URLs (as_string)
+
+ o  RobotRules patches from Henry A Rowley.
+
+ o  More tests
+
+ o  <SMALL> and <BIG> again
+
+
+
+Thu Mar 14 1996   Gisle Aas <aas@sn.no>
+
+ o  Release 5b10
+
+ o  GET ftp://host/doc was never successful for normal files.
+
+ o  LWP::Socket: read_until() did not notice EOF condidtion.  I.e. if
+    a HTTP server closed the connection before any output was generated,
+    the we continued to read 0 bytes in a busy loop until the alarm()
+    killed us.
+
+ o  Added support for Digest Access Authentication.  Contributed by
+    Doug MacEachern <dougm@osf.org>.
+
+ o  Makefile.PL: check for MD5 library
+
+ o  No longer print message content in HTTP::Response::error_as_HTML()
+
+ o  Access to "file:/path" gave warning when the envirionment variable
+    no_proxy was set.
+
+ o  The http-post test sends a Content-Type header.  Some servers hang
+    if this header is missing.
+
+ o  HTML::Parse:
+     -   allow <SMALL> and <BIG> tags
+     -   allow empty attribute values
+
+
+
+Tue Mar  5 1996   Gisle Aas <aas@sn.no>
+
+ o  Release 5b9
+
+ o  Started to write on the libwww-perl cookbook (lwpcook.pod)
+
+ o  The URI::URL module now exports the function url().  This is an
+    alternative (easy to use) constructor function.
+
+ o  Expanding relative file URLs starting with "#" did not work.
+
+ o  Fixed autoloaded DESTROY problem by adding empty DESTROY routine
+    to URI::URL.
+
+ o  Does not try generate password for ftp-URLs unless the username is
+    "anonymous" or "ftp"
+
+ o  The LWP::Simple user agent proxy settings are intialized from
+    the proxy environment variables. 
+
+ o  LWP::Protocol::ftp: Use the Net::FTP library to access ftp servers.
+    Convert directories to HTML on request (Accept: text/html).
+
+ o  New module HTTP::Negotiate
+
+ o  New module File::Listing
+
+ o  HTTP::Date::str2time can parse a few more formats, like the 'ls -l'
+    format and ISO 8601.  The function now also takes an optional second
+    parameter which specify a default time zone.
+
+ o  Added prototypes to the HTTP::Date functions.
+
+ o  The library adds a timestamp to responses ("Client-Date")
+
+ o  HTTP::Status:  Updated to proposed HTTP/1.1
+
+ o  HTTP::Headers: Updated to proposed HTTP/1.1
+
+ o  LWP::Protocol::http:  Updated to HTTP/1.1 methods
+
+ o  Took out stringify overloading in HTML::Element.
+
+
+
+Mon Feb 26 1996   Gisle Aas <aas@sn.no>
+
+ o  Release 5b8
+
+ o  Renamed functions using thisStyleOfNames to this_style_of_names.
+    Provided a script called 'update_from_5b7'
+
+ o  Renamed the 'request' and 'mirror' scripts to 'lwp-request' and
+    'lwp-mirror'.  The GET, POST, HEAD aliases for 'lwp-request' are
+    the same.
+
+ o  Implemented LWP::RobotUA
+
+ o  Class name for RobotRules did not match the file name
+
+ o  URI::URL
+      - perl5.002gamma is required (because use vars).
+      - The leading slash in now part of the path if it is present.
+      - More documentation
+      - Use AutoLoader to speed things up.
+      - New class URI::URL::_login and made telnet, rlogin, tn3270
+        subclasses from this one.
+      - URI::URL::wais is better supported.
+      - URI::URL::news is better supported.
+      - New URI::URL::mailto methods: user/host
+
+ o  HTTP::Date::time2str now works correctly with '0' as argument
+
+ o  HTTP::Message delegates unknown methods to the headers.
+
+ o  HTTP::Request::uri is an alias for HTTP::Request::url.  Can set
+    the URL to undef.
+
+ o  Added convenience methods to HTTP::Headers for easy access to
+    frequently used headers.
+
+ o  Simplified LWP::Debug
+
+ o  Use standard AutoLoader for LWP::IO functions.
+
+ o  Played with the profiler (Devel::DProf) and made some things
+    go quicker.
+
+ o  Included the File::CounterFile module.  Excluded Mail::Cap module
+    as it is also part of the MailTools package.
+
+
+
+Mon Feb  5 1996   Gisle Aas <aas@sn.no>
+
+ o  Release 5b7
+
+ o  Perl5.002 is required now
+
+ o  Rewrite of the URI::URL module (version 4.00)
+      - escaping/unsafe stuff redone (and removed)
+      - URI::URL::_generic moved out of URL.pm
+      - netloc, path, params, query is now stored internally in escaped form
+      - new methods for URI::URL::_generic are:
+           epath
+           eparams
+           equery
+	   path_components
+           absolute_path
+      - new methods for URI::URL::http are:
+           keywords
+           query_form
+      - new methods for URI::URL::file are:
+           newlocal
+           local_path
+           unix_path
+           dos_path
+           mac_path
+           vms_path
+
+ o  URI::Escape now semi-compile regular expressions (by evaling an
+    anonymous sub).  Same techinque is also used in HTML::Entities.
+
+ o  HTTP::Date parser rewritten using regular expressions.
+
+ o  HTTP::Headers->as_string() now croaks if any field values
+    contain newline.
+
+ o  HTTP::Status constants use empty prototype.
+
+ o  Font metrics moved to a new subdirectory (lib/Font/Metrics)
+
+ o  Don't use the VERSION script any more (even if it was very clever)
+
+ o  HTML::Entities will now export the names decode_entities() and
+    encode_entities().
+
+ o  Andreas Koenig's black patch to HTML::Element.
+
+ o  The HTML::Formatter now knows about <menu> and <dir> tags
+
+ o  The construct "defined ref($arg)" did not work on perl5.002
+    becase ref now always return something defined.
+
+ o  LWP::UserAgent sends by default an 'User-Agent' header.
+
+ o  LWP::Simple sends 'User-Agent' header to servers.
+
+ o  Updated the LWP::Socket module to use the new Socket.pm interface.
+
+ o  LWP::Protocol::http sends the new HTTP/1.1 'Host' header.
+
+ o  LWP::Protocol::file use $url->local_path to get a file to open.
+    It also inserts a <BASE> tag in directories instead of a redirect.
+
+ o  MIME::Base64 routines can be called as MIME::Base64::encode() and
+    MIME::Base64::decode().  Same kind of thing for QuotedPrint.
+
+
+
+Mon Nov  6 1995   Gisle Aas <aas@oslonett.no>
+
+ o  Release 5b6
+
+ o  Installation should work better for those that still runs
+    perl4 as 'perl'.  The mirror script is not installed by
+    default.
+
+ o  LWP::Socket::_getaddress() Numerical IP adresses did not work.
+
+ o  LWP::Socket::pushback() did not work.  This also avoids the bad
+    pp_select() core dump from perl.
+
+ o  LWP::IO now also selects on socket exceptions.
+
+ o  HTML::Parse:  Ignore <!DOCTYPE ...> regardless for case.  Some
+    bad insertElement() calls made infinite loops.
+
+ o  The uri.t test works better for places where /tmp is a sym-link.
+
+
+
+Sat Sep 16 1995   Gisle Aas <aas@oslonett.no>
+
+ o  Release 5b5
+
+ o  newlocal URI::URL does not put "//localhost" into the URLs any
+    longer.
+
+ o  The request program: New -o option to reformat the HTML code
+    New -C option to provide credentials on the command line.
+    The -b option never worked.
+
+ o  LWP::Protocol::file now returns redirect for access to directories
+    where the trailing slash is missing.
+
+
+
+Thu Sep 14 1995   Gisle Aas <aas@oslonett.no>
+
+ o  Speedups and bug fixes in the HTML parser.  The parser now
+    understands some more depreciated tags (like <xmp> and <listing>).
+
+ o  HTML::Elements are now stingified using perl overloading.
+    The interface to the traverse() callback has changed.
+
+ o  Implemented HTML formatters for plain text and Postscript.
+
+ o  Added lib/Font stuff to support the Postscript formatter.
+
+ o  Inspired by Tim Bunce, I implemented the HTML::AsSubs module.
+    Don't know if it is really useful.
+
+ o  The local/get test does not use /etc/passwd any more.
+
+
+
+Thu Sep  7 1995   Gisle Aas <aas@oslonett.no>
+
+ o  Changed package name to libwww-perl-5xx
+
+ o  Made LWP::Protocol::ftp actually transfer data
+
+ o  Implemented methods for LWP::Socket to act as a server:
+    bind(), listen(), accept(), getsockname(), host(), port()
+
+
+
+Wed Sep  6 1995   Gisle Aas <aas@oslonett.no>
+
+ o  Release 0.04
+
+ o  Implemented modules to parse HTML.
+
+
+
+Mon Sep  4 1995   Gisle Aas <aas@oslonett.no>
+
+ o  Implemented Mail::Cap which will become part of the MailTools
+    package.
+
+ o  Moved Base64 to MIME::Base64.  Reimplemented MIME::Base64 by using
+    [un]pack("u",...)   Implemented LWP::MIME::QuotedPrint for
+    completness sake.  Routine names has changed as suggested by Tim
+    Bunce.
+
+ o  LWP::MediaType reads default types from media.types file.
+    guessMediaType() now also returns encodings.  New function mediaSuffix()
+
+ o  Pass $url to $ua->getBasicCredentials().  This also fixes security
+    hole with the old implementation of getBasicCredentials().
+
+ o  LWP::Protocol::file now sets Content-Encoding headers
+
+ o  Allow request content to be provided by a callback routine.
+
+ o  Fix bug that prevented response callback to work.  The first parameter
+    (data) is no longer a reference, because $_[0] is already a reference.
+    Don't callback unless successful response.  Callbacks during redirects
+    was confusing.
+
+ o  URI::URL.  Remove port from netloc if it is the default port.
+    Don't use anything, just require.
+
+ o  HTTP::Message->addContent() does not need a reference parameter.
+
+ o  LWP::Socket->open() has been renamed top LWP::Socket->connect()
+    LWP::Socket->close has gone.  Implemented new method LWP::Socket->read()
+    that returns as fast as it has some data to offer.  Implemented
+    LWP::Socket->pushback().
+
+ o  Does not die in LWP::UserAgent->request()
+
+ o  LWP::Socket now use LWP::IO for low level IO
+
+ o  Implemented LWP::TkIO as a replacement module for LWP::IO when using Tk.
+
+
+
+Thu Aug 17 1995   Gisle Aas <aas@oslonett.no>
+
+ o  $ua->redirectOK() for checking redirects
+
+ o  reorganized tests in the "t" directory.
+
+
+
+Fri Aug 11 1995   Gisle Aas <aas@oslonett.no>
+
+ o  Release 0.03
+
+ o  Included RobotRules.pm from Martijn Koster
+
+
+
+Thu Aug 10 1995   Gisle Aas <aas@oslonett.no>
+
+ o  New module URI::Escape (URI::URL use this module for default
+    escaping) that provide the uri_escape() and uri_unescape()
+    functions.
+
+ o  Setting $url->scheme now changes the class of the object.
+
+ o  Made $httpurl->user() and $httpurl->password() illegal.
+    Likewise for other URL schemes.
+
+
+
+
+Wed Aug  9 1995   Gisle Aas <aas@oslonett.no>
+
+ o  Reorganisation as discussed on <libwww-perl@ics.uci.edu>
+       LWP::Date       --> HTTP::Date
+       LWP::MIMEheader --> HTTP::Headers
+       LWP::StatusCode --> HTTP::Status
+       LWP::Message    --> HTTP::Message
+       LWP::Request    --> HTTP::Request
+       LWP::Response   --> HTTP::Response
+       LWP::MIMEtypes  --> LWP::MediaTypes
+
+ o  HTTP::Date parses ctime format with missing timezone as suggested
+    by Roy Fielding <fielding@beach.w3.org>
+
+ o  HTTP::Status and LWP::MediaTypes exports their functions by default.
+
+ o  Splitted up the URI::URL module.  Schemes are implemented by separate
+    files that are autoloaded when used.  Self test moved to "t/uri.t".
+
+
+       
+Mon Aug  7 1995   Gisle Aas <aas@oslonett.no>
+
+ o  Applied patch from Marc Hedlund <hedlund@best.com>
+       - Update the @header_order according to the August 3rd draft.
+       - Added Response Header fields: 'Location', 'Public', 'Retry-After',
+         'Server', and 'WWW-Authenticate'.
+       - Moved 'unknown header' handling from &scan to &header. The old
+         implementation was forcing all unknown header-words to begin with
+	 an uppercase (as it should be), but disallowed other uppercase
+	 letters.
+       - updates the status code messages under the August
+         3rd HTTP/1.0 draft.  '203' became 'Non-Authoritative Information',
+	 '303' became 'See Other', and a new code,
+	 '411 Authorization Refused', was added.
+
+ o  Can remove multiple headers with single removeHeader() call in MIMEheader.
+
+ o  Can assign multiple field/value pairs in header() method of MIMEheader.
+
+ o  A field with multiple values is printed as separate values in
+    MIMEheader::as_string().
+
+ o  LWP::Response contain new attributes: previous() and request().  These
+    attributes are updated by the UserAgent.
+
+ o  Appended \n to some die statements in Socket so that line numbers are
+    suppressed in error messages.
+
+ o  Made UserAgent::clone work for reference members
+
+ o  Check for redirect loops and multiple authorization failures by
+    examination of the response chain.
+
+ o  Use "\015\012" instead of "\r\n" in protocol modules.  Some systems
+    define \r and \n differently.
+
+ o  request program can now handle documents that needs autorization by
+    prompting the user for username/password. Added new -S option to print
+    request/response chain.
+
+
+  
+Tue Jul 25 1995   Gisle Aas <aas@oslonett.no>
+
+ o  Release 0.02
+
+ o  Included URI::URL in the release
+
+
+
+Mon Jul 24 1995   Gisle Aas <aas@oslonett.no>
+
+ o  Incorporated Makemake.PL and VERSION from Andreas Koenig <koenig@mind.de>
+    As a result of this the following things have changed:
+       - programs in "bin" are extracted from .PL-files
+       - reintroduced "lib"
+       - "test" has been renamed as "t"
+       - test programs in "t" has been made Test::Harness compatible
+       - we now have a MANIFEST file
+       - no more need fro update_version, make-dist, lwp-install
+
+ o  Renamed bin/get to bin/request.  Links to it are now all upper case.
+
+ o  Proxy support in bin/request (provided by Martijn Koster)
+
+ o  UserAgent can now load proxy settings from environment
+
+ o  LWP::Protocol::ftp is under way but not really finished
+
+
+
+Tue Jul 18 1995   Gisle Aas <aas@oslonett.no>
+
+ o  Implemented LWP::Protocol::gopher
+
+ o  Implemented LWP::Protocol::mailto
+
+ o  Fixed proxy typo
+
+
+
+Mon Jul 17 1995   Gisle Aas <aas@oslonett.no>
+
+ o  Made release 0.01
+
+
+
+Mon Jul 17 1995   Gisle Aas <aas@oslonett.no>
+
+ o  Don't loose first line of HTTP/0.9 requests
+
+ o  LWP::Socket use syswrite() for writing
+
+ o  Added RC_* documentation to LWP::StatusCode
+
+ o  LWP::Date now use hash to look up month numbers
+
+ o  Added -f option to "get"
+
+ o  Untabify
+
+ o  Added a "TODO" list
+
+ o  Fixed various typos
+
+
+
+Fri Jul 14 1995   Gisle Aas <aas@oslonett.no>
+
+ o  Reorganized directories.  Moved LWP.pm up.  Moved file.pm and http.pm
+    into the LWP::Protocol direcotory.  Moved LWP out of the lib directory
+    and removed lib.
+
+ o  Implemented the "get" and "mirror" scripts in the "bin" directory.
+
+ o  Implemented "install-lwp", "update_version" and "make-dist".  The library
+    version number is found in the VERSION file.
+
+ o  Always adds 1900 to the year in LWP::Date
+
+ o  In LWP::MIMEheader:  Implemented clone(), removeHeader() and scan() 
+    methods.  Reimplemented asString.  Removed asMIME().  Moved "Good
+    Practice" into this file, and reimplemented it.
+
+ o  Moved "header" and "content" into LWP::Message class.  This change made
+    LWP::Request and LWP::Response much simpler.  Made clone() method
+    actually work.
+
+ o  LWP::Protocol::implementor does not die if it cannot load package.
+
+ o  Moved UserAgent convenience methods into LWP::Simple.  Made LWP::Simple
+    export LWP::StatusCode symbols and functions.
+
+ o  Implemented $ua->isProtocolSupported($scheme) method.
+
+ o  Nicer directory listing in LWP::Protocol::file.pm
+
+ o  Rely on URI::URL 3.00 behaviour for $url->full_path
+
+ o  Library version number now in LWP.pm.  You should be able to say
+    "use LWP 1.0;" if you need at least this version.
+
+ o  Various cleanups and arranging layout as I like it.  Use fooBar-style
+    (as opposed to foo_bar stype) everywhere.  This means that as_string()
+    now is called asString().
+
+ o  Added more documentation.
+
+
+
+Wed Jun 14 1995   Gisle Aas <aas@oslonett.no>
+
+ o  Removed lot of rendundant & before function calls.
+
+ o  $this --> $self
+
+ o  &collector passes content as a reference, don't want to copy so much
+
+ o  parameterlist to collect callback has been rearranged
+
+ o  Response::addContent gets a reference to the data
+
+ o  Added some callback documentation to UserAgent.pm
+
+ o  Protocol::file now uses the collector
+
+ o  Introduced LWP::Simple
+
+
+
+Sun Jun 11 1995   Martijn Koster <m.koster@nexor.co.uk>
+
+ o  Added basic authentication support
+
+ o  Added mirroring of single documents
+
+ o  Change Protocol construction from whacky URL.pm (constructor returns
+    subclass) to more normal C++'ish way.
+
+
+
+Wed June 7 1995   Martijn Koster <m.koster@nexor.co.uk>
+
+ o  Minor cleanups from printed code inspection
+
+
+
+Wed May 24 1995   Martijn Koster <m.koster@nexor.co.uk>
+
+ o  Added redirection resolution
+
+ o  Added optional autoloading of protocols
+
+
+
+Tue May 23 1995   Martijn Koster <m.koster@nexor.co.uk>
+
+ o  Separated socket stuff into separate module
+
+ o  Added HTTP proxy support
+
+ o  Made alarm handling optional
+
+ o  Added a LWP::Message for completeness sake
+
+ o  Added LWP::MemberMixin to reduce code duplication
+
+ o  Cosmetic changes to LWP::Date
+
+ o  Renamed LWP::Error to LWP::StatusCode
+
+ o  Renamed LWP::MIME to LWP::MIMEtype
+
+ o  Changed the tests to cope with all this
+
+It's getting there...
+
+
+
+Mon May 22 1995   Martijn Koster <m.koster@nexor.co.uk>
+
+ o  Changed the socket reading to use sysread.  This will have to go
+    into a module of its own.
+
+
+
+Thu 18 May 1995   Martijn Koster <m.koster@nexor.co.uk>
+
+ o  Mentioned on libwww-perl that I had changed the classes around lots.
Index: /main/tags/2.25/gsdl/packages/w3mir/libwww-perl-5.36/INSTALL.w3mir
===================================================================
--- /main/tags/2.25/gsdl/packages/w3mir/libwww-perl-5.36/INSTALL.w3mir	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/w3mir/libwww-perl-5.36/INSTALL.w3mir	(revision 21064)
@@ -0,0 +1,48 @@
+
+- Get libwww-perl from CPAN 
+  (http://www.perl.com/CPAN/modules/by-module/WWW/).  W3mir does not work
+  with LWP 5.40 and later versions.  Please get an earlier version.
+  It also does not work with the new URI package.  Use the URI package
+  enclosed in the older LWP.
+
+- Unpack it:
+
+    gzip -dc libwww-perl-*.tar.gz | tar xvBf -
+
+- Install it.  W3mir does not require the whole libwww-perl package and
+  all the packages that goes with it to work so you may follow these
+  install instructions instead of the libwww-perl install instructions
+  to get an easier install which will work with w3mir.
+
+    cd libwww-perl-*
+
+  Are you going to install it in the standard perl place (you need to
+  be the system administrator to do this)? If so:
+
+    perl Makefile.PL
+
+  If not (if you are a user):
+
+    perl Makefile.PL PREFIX=/some/dir
+
+  /some/dir could be ~ (as in your home directory).
+
+  IF you are installing an old LWP just for w3mir you can install both
+  the old LWP, the Base64 module and w3mir in a special PREFIX
+  separate from your usual install PREFIX.  This ensures that w3mir will
+  access the older version of LWP and that other software will access
+  the newer version.  If you do this make sure you install all of LWP,
+  Base64 and w3mir with the same PREFIX.
+
+  This step might produce some complaints;  A standard perl
+  installation will typically get messages about missing these
+  modules: IO::Socket, NET::FTP and MD5.  None of these need be
+  installed to run w3mir and so any error messages about these may
+  safely be ignored.
+
+    make
+    make test      (robot/ua and local/http might fail, that's OK)
+    make install
+
+  Now libwww-perl should be installed and working.
+
Index: /main/tags/2.25/gsdl/packages/w3mir/libwww-perl-5.36/MANIFEST
===================================================================
--- /main/tags/2.25/gsdl/packages/w3mir/libwww-perl-5.36/MANIFEST	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/w3mir/libwww-perl-5.36/MANIFEST	(revision 21064)
@@ -0,0 +1,106 @@
+ChangeLog			History of this package
+MANIFEST			This file
+Makefile.PL			Makefile generator
+README				Get you started with this package
+TODO				The To-Do list for the library
+bin/lwp-download.PL             Writes bin/lwp-download script
+bin/lwp-mirror.PL		Writes bin/lwp-mirror script
+bin/lwp-request.PL		Writes bin/lwp-request script
+bin/lwp-rget.PL			Writes bin/lwp-rget script
+lwpcook.pod			Libwww-perl examples
+lib/Bundle/LWP.pm               Defines prereq modules
+lib/File/Listing.pm		Parse directory listings
+lib/HTTP/Cookies.pm             Cookie storage and management
+lib/HTTP/Daemon.pm		A simple httpd
+lib/HTTP/Date.pm		Date conversion routines
+lib/HTTP/Headers.pm		Class encapsulating HTTP Message headers
+lib/HTTP/Headers/Auth.pm	Some methods that deal with authorization.
+lib/HTTP/Headers/ETag.pm	Some methods that deal with entity tags
+lib/HTTP/Headers/Util.pm        Some utility functions for header values.
+lib/HTTP/Message.pm		Class encapsulating HTTP messages
+lib/HTTP/Negotiate.pm		Evaluate HTTP content negotiation algoritm
+lib/HTTP/Request.pm		Class encapsulating HTTP Requests
+lib/HTTP/Request/Common.pm      Generate common requests
+lib/HTTP/Response.pm		Class encapsulating HTTP Responses
+lib/HTTP/Status.pm		HTTP Status code processing
+lib/LWP.pm			Includes what you need
+lib/LWP/Authen/Basic.pm		Basic authentication scheme
+lib/LWP/Authen/Digest.pm	Digest authentication scheme
+lib/LWP/Debug.pm		Debugging support
+lib/LWP/MediaTypes.pm		Library for guessing media types
+lib/LWP/MemberMixin.pm		Helps you access %$self
+lib/LWP/Protocol.pm		Virtual base class for LWP protocols
+lib/LWP/Protocol/data.pm        Access to data URLs
+lib/LWP/Protocol/file.pm	Access local files
+lib/LWP/Protocol/ftp.pm		Access with the FTP protocol
+lib/LWP/Protocol/gopher.pm	Access with the Gopher protocol
+lib/LWP/Protocol/http.pm	Access with HTTP protocol
+lib/LWP/Protocol/https.pm	Access with HTTP protocol over SSL
+lib/LWP/Protocol/mailto.pm	Allows you to POST mail using sendmail
+lib/LWP/Protocol/nntp.pm	Handles access to news: and nntp: URLs
+lib/LWP/RobotUA.pm		Easy creation of conforming robots
+lib/LWP/Simple.pm		Procedural LWP interface
+lib/LWP/UserAgent.pm		A WWW UserAgent class
+lib/LWP/media.types		Mapping from file extentions media types
+lib/URI/Escape.pm		General URI escaping functions
+lib/URI/Heuristic.pm            User friendly URLs
+lib/URI/URL.pm			Class encapsulating URLs
+lib/URI/URL/_generic.pm		Implements generic hierarchical RL (RFC 1808)
+lib/URI/URL/_login.pm		Base class for telnet, tn3270 and rlogin
+lib/URI/URL/data.pm             Implements data URLs
+lib/URI/URL/file.pm		Implements file URLs
+lib/URI/URL/finger.pm		Implements finger URLs
+lib/URI/URL/ftp.pm		Implements ftp URLs
+lib/URI/URL/gopher.pm		Implements gopher URLs
+lib/URI/URL/http.pm		Implements http URLs
+lib/URI/URL/https.pm		Implements https URLs
+lib/URI/URL/mailto.pm		Implements mailto URLs
+lib/URI/URL/news.pm		Implements news URLs
+lib/URI/URL/nntp.pm		Implements nntp URLs
+lib/URI/URL/prospero.pm		Implements prospero URLs
+lib/URI/URL/rlogin.pm		Implements rlogin URLs
+lib/URI/URL/telnet.pm		Implements telnet URLs
+lib/URI/URL/tn3270.pm		Implements tn3270 URLs
+lib/URI/URL/wais.pm		Implements wais URLs
+lib/URI/URL/webster.pm		Implements webster URLs
+lib/URI/URL/whois.pm		Implements whois URLs
+lib/WWW/RobotRules.pm		Parse robot.txt files
+lib/WWW/RobotRules/AnyDBM_File.pm	Persistent robot rules
+t/README			How to run and set up tests
+t/TEST				Run tests
+t/base/common-req.t		Test HTTP::Request::Common module
+t/base/cookies.t                Test HTTP::Cookies module
+t/base/date.t			Test HTTP::Date module
+t/base/headers.t		Test HTTP::Headers module
+t/base/headers-auth.t		Test HTTP::Headers::Auth module
+t/base/headers-etag.t		Test HTTP::Headers::ETag module
+t/base/headers-util.t		Test HTTP::Headers::Util module
+t/base/listing.t		Test File::Listing module
+t/base/mediatypes.t		Test LWP::MediaTypes module
+t/base/message.t		Test HTTP::Request/HTTP::Response
+t/base/negotiate.t		Test HTTP::Negotiation module
+t/base/response.t		Test additional HTTP::Response methods
+t/base/status.t			Test HTTP::Status module
+t/local/autoload.t		Test autoloading of LWP::Protocol modules
+t/local/get.t			Try to get a local file
+t/local/http.t			Test http to local server
+t/local/protosub.t              Test with other protocol module
+t/net/cgi-bin/moved
+t/net/cgi-bin/nph-slowdata
+t/net/cgi-bin/slowread
+t/net/cgi-bin/test
+t/net/cgi-bin/timeout
+t/net/config.pl.dist		Suggested configuration for net tests
+t/net/http-get.t
+t/net/http-post.t
+t/net/http-timeout.t
+t/net/mirror.t
+t/net/moved.t
+t/net/proxy.t
+t/robot/rules-dbm.t		Test WWW::RobotRules::AnyDBM_File
+t/robot/rules.t			Test WWW::RobotRules
+t/robot/ua.t			Test LWP::RobotUA
+t/uri/abs-config.t              Test URI::URL configuration variables
+t/uri/base.t			Test URI::URL module
+t/uri/rel-base.t		Test URI::URL module some more
+t/uri/heuristic.t               Test URI::Heuristic module
Index: /main/tags/2.25/gsdl/packages/w3mir/libwww-perl-5.36/Makefile.PL
===================================================================
--- /main/tags/2.25/gsdl/packages/w3mir/libwww-perl-5.36/Makefile.PL	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/w3mir/libwww-perl-5.36/Makefile.PL	(revision 21064)
@@ -0,0 +1,184 @@
+# This -*- perl -*- script writes the Makefile for libwww-perl
+# $Id$
+
+require 5.004;
+use strict;
+
+#--- Configuration section ---
+
+my @programs_to_install = qw(lwp-request lwp-mirror lwp-rget lwp-download);
+my @request_aliases     = qw(GET HEAD POST);
+
+#--- End Configuration - You should not have to change anything below this line
+
+
+# Allow us to suppress all program installation with the -n (library only)
+# option.  This is for those that don't want to mess with the configuration
+# section of this file.
+use Getopt::Std;
+use vars qw($opt_n);
+unless (getopts("n")) {
+    die "Usage: $0 [-n]\n";
+}
+@programs_to_install = () if $opt_n;
+
+
+# Check for non-standard modules that are used by this library.
+$| = 1;
+my $missing_modules = 0;
+
+print "Checking for HTML::Parser..";
+eval {
+    require HTML::HeadParser;
+};
+if ($@) {
+    print " failed\n";
+    $missing_modules++;
+    print <<EOT;
+$@
+The HTML::Parser is needed to extract correct <BASE> information from
+HTML so that we can resolv relative links correctly.
+
+EOT
+    sleep(2);  # Don't hurry too much
+} else {
+    print " ok\n";
+}
+
+print "Checking for MIME::Base64..";
+eval {
+    require MIME::Base64;
+    #MIME::Base64->require_version('2.00');
+};
+if ($@) {
+    print " failed\n";
+    $missing_modules++;
+    print <<EOT;
+$@
+The Base64 encoding is used in authentication headers in HTTP.
+
+EOT
+    sleep(2);  # Don't hurry too much
+} else {
+    print " ok\n";
+}
+
+print "Checking for Net::FTP......";
+eval {
+    require Net::FTP;
+    Net::FTP->require_version('2.00');
+};
+if ($@) {
+    print " failed\n";
+    $missing_modules++;
+    print <<EOT;
+$@
+The libwww-perl library normally use the Net::FTP module when
+accessing ftp servers.  You would have to install this package or
+configure your application to use a proxy server for making ftp
+requests work.  Net::FTP is part of the 'libnet' distribution.
+
+EOT
+    sleep(2);  # Don't hurry too much
+} else {
+    print " ok\n";
+}
+
+print "Checking for MD5 ..........";
+eval {
+    require MD5;
+};
+if ($@) {
+    print " failed\n";
+    $missing_modules++;
+    print <<EOT;
+$@
+The MD5 library is needed if you want to be able use the experimental
+"Digest Access Authentication" scheme.  Since very few servers
+implement this authentication scheme, you should normally not worry
+too much about this.
+
+EOT
+} else {
+    print " ok\n";
+}
+
+print <<EOT if $missing_modules;
+The missing modules can be obtained from CPAN.  Visit
+<URL:http://www.perl.com/CPAN/> to find a CPAN site near you.
+
+EOT
+
+
+# Ok, now it is time to really generate the Makefile
+use ExtUtils::MakeMaker;
+
+WriteMakefile(
+   NAME          => 'libwww-perl',
+   VERSION_FROM  => 'lib/LWP.pm',
+   PL_FILES      => { map {("bin/$_.PL" => "bin/$_")} @programs_to_install },
+   EXE_FILES     => [ map {"bin/$_"} @programs_to_install ],
+   'clean'       => { FILES => '$(EXE_FILES)' },
+   'dist'        => { COMPRESS => 'gzip -9f', SUFFIX => 'gz', },
+);
+
+
+
+package MY;
+
+sub postamble
+{
+    my @m;
+    if (@request_aliases && grep($_ eq 'lwp-request', @programs_to_install)) {
+	push @m, "all ::\n";
+	if ($^O eq 'MSWin32') {
+	    push @m, "\t\$(FULLPERL) -e \"use Config; chdir q[\$(INST_EXE)]; "
+		    ."foreach (qw(@request_aliases)) { \" \\\n";
+	    push @m, <<'EOT';
+	-e "unlink \"$$_\"; " \
+	-e "system(\"copy lwp-request $$_\") && die; }"
+EOT
+	} else {
+	    push @m, "\t\$(FULLPERL) -e 'use Config; chdir q{\$(INST_EXE)}; "
+		    ."foreach (qw(@request_aliases)) {' \\\n";
+	    push @m, <<'EOT';
+	-e 'unlink "$$_";' \
+	-e 'system("$$Config{\"lns\"} lwp-request $$_") && die; }'
+EOT
+	}
+    }
+    join "", @m;
+}
+
+# What happens when we say 'make test'
+sub test
+{
+    q(
+TEST_VERBOSE=0
+
+test: all
+	$(FULLPERL) t/TEST $(TEST_VERBOSE)
+
+);
+}
+
+
+# Determine things that should *not* be installed
+sub libscan
+{
+    my($self, $path) = @_;
+    return '' if $path =~ m/.(pl|dtd|sgml)$/;
+    return '' if $path =~ m:\bCVS/:;
+    return '' if $path =~ m/~$/;
+    $path;
+}
+
+# Pass libwww-perl version number to pod2man
+sub manifypods
+{
+    my $self = shift;
+    my $ver = $self->{VERSION} || "";
+    local($_) = $self->SUPER::manifypods(@_);
+    s/pod2man\s*$/pod2man --release libwww-perl-$ver/m;
+    $_;
+}
Index: /main/tags/2.25/gsdl/packages/w3mir/libwww-perl-5.36/README
===================================================================
--- /main/tags/2.25/gsdl/packages/w3mir/libwww-perl-5.36/README	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/w3mir/libwww-perl-5.36/README	(revision 21064)
@@ -0,0 +1,124 @@
+                     L I B W W W - P E R L - 5
+                   -----------------------------
+
+Libwww-perl is a collection of Perl modules which provides a simple
+and consistent programming interface (API) to the World-Wide Web.  The
+main focus of the library is to provide classes and functions that
+allow you to write WWW clients, thus libwww-perl said to be a WWW
+client library. The library also contain modules that are of more
+general use and even classes that helps you implement simple HTTP
+servers.
+
+There are actually two versions of libwww-perl: one for Perl4, and one
+for Perl5. Both have a similar architecture, loosely based on the CERN
+Library of Common Code (nowadays known as 'w3c-libwww').
+
+The Perl4 version is still(?) maintained by Roy Fielding, and was the
+basis for tools such as MOMSpider. The perl4 version of libwww-perl
+and much more information about its libraries can be found at:
+http://www.ics.uci.edu/pub/websoft/libwww-perl/
+
+The Perl5 version (this package) is a complete rewrite for Perl5: the
+code is organized in Modules, provides an Object Oriented API, is
+updated for the latest HTTP and URL specification, and offers some
+extended functionality.
+
+Full HTTP/1.1 support is on its way.  Alpha releases of the LWPng
+package is currently available from CPAN.
+
+
+PREREQUISITES
+
+In order to install and use this package you will need Perl version
+5.004 or better.  Some modules within this package depend on other
+packages that are distributed separately from Perl.  We recommend that
+you have the following packages installed before you install
+libwww-perl:
+
+  MIME-Base64
+  HTML-Parser
+  libnet
+  MD5
+
+These packages should be available on CPAN.
+
+If you want to access sites using the https protocol, then you need to
+install the Crypt-SSLeay modules first.  (The Net::SSLeay module is not
+supported any more.)
+
+
+INSTALLATION
+
+You install libwww-perl, as you would install any perl module library,
+by running these commands:
+
+   perl Makefile.PL
+   make
+   make test
+   make install
+
+You can edit the configuration section of Makefile.PL to select which
+programs to install in addition to the library itself.  If you don't
+want to install any programs (only the library files) and don't want
+to mess with the Makefile.PL then pass the '-n' option to Makefile.PL:
+
+   perl Makefile.PL -n
+
+If you want to install a private copy of libwww-perl in your home
+directory, then you should try to produce the initial Makefile with
+something like this command:
+
+  perl Makefile.PL LIB=~/perl
+
+The Makefile.PL program will start out by checking your perl
+installation for a few packages that are recommended to be installed
+together with libwww-perl.
+
+Optional network tests are _not_ enabled automatically when you unpack
+this package.  Consult the t/README file for instructions on how to
+enable these tests.
+
+
+DOCUMENTATION
+
+See lib/LWP.pm for an overview of the library. See ChangeLog for
+recent changes.  POD style documentation is included in all modules
+and scripts.  These are normally converted to manual pages and
+installed as part of the "make install" process.  You should also be
+able to use the 'perldoc' utility to extract and read documentation
+from the module files directly.
+
+
+SUPPORT
+
+Question about how to use this library should be directed to the
+comp.lang.perl.modules USENET Newsgroup.  Bug reports and suggestions
+for improvements can be sendt to the <libwww-perl@ics.uci.edu> mailing
+list.  This mailing list is also the place for general discussions and
+development of the libwww-perl package.
+
+You can join the mailing list by sending a message to
+<libwww-perl-request@ics.uci.edu> with "Subscribe" as subject.
+            ^^^^^^^^
+
+AVAILABILITY
+
+The latest version of libwww-perl should always be available from:
+
+     http://www.linpro.no/lwp/
+
+The library is also available from the Comprehensive Perl Archive
+Network (CPAN).  Visit <URL:http://www.perl.com/CPAN/> to find a CPAN
+site near you.
+
+
+COPYRIGHT
+
+  © 1995-1998 Gisle Aas. All rights reserved.
+  © 1995 Martijn Koster. All rights reserved.
+
+This library is free software; you can redistribute it and/or modify
+it under the same terms as Perl itself.
+
+
+Enjoy!
Index: /main/tags/2.25/gsdl/packages/w3mir/libwww-perl-5.36/TODO
===================================================================
--- /main/tags/2.25/gsdl/packages/w3mir/libwww-perl-5.36/TODO	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/w3mir/libwww-perl-5.36/TODO	(revision 21064)
@@ -0,0 +1,46 @@
+                                            $Date$
+
+This is a list over things that we plan to implement in libwww-perl-5.
+The order of items does not reflect priority.
+
+  o  HTTP/1.1 support is on its way.  This also includes support of
+     multiple parallel connections.  Take a look at LWPng (aka
+     libwww-perl-6).
+
+  o  Provide initial credentials so that we don't always have to get a
+     401 response first.  Both for Basic and Digest authentication.  This
+     is in fact implemented for LWPng.
+
+  o  HTTP::Request::Common::POST() should be able to create large
+     file upload requests by making a closure content.
+
+  o  Support PICS??
+
+  o  Cache previous ftp connections.  "Keep-Alive"?
+
+  o  Support MOVE, DELETE method for ftp.
+
+  o  Support If-Modified-Since for ftp.
+
+  o  Use Mail::Send to implement LWP::Protocol::mailto.  Today we just
+     invoke sendmail directly, which is not very portable.
+
+  o  The lwp-request -o processing should check for Content-Encoding as
+     well as Content-Type.
+
+  o  The lwp-request script should optionally consult Mail::Cap for
+     handling of media types.
+
+  o  The lwp-request script should use the callback interface so that it
+     prints data as it is received.
+
+  o  The lwp-mirror script should be able to work recursively.
+
+  o  Include more useful programs
+
+  o  More documentation
+
+  o  More tests
+
+  o  Fix bugs, if there are any...
+
Index: /main/tags/2.25/gsdl/packages/w3mir/libwww-perl-5.36/bin/lwp-download.PL
===================================================================
--- /main/tags/2.25/gsdl/packages/w3mir/libwww-perl-5.36/bin/lwp-download.PL	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/w3mir/libwww-perl-5.36/bin/lwp-download.PL	(revision 21064)
@@ -0,0 +1,248 @@
+use Config;
+use File::Basename qw(basename dirname);
+chdir(dirname($0));
+($file = basename($0)) =~ s/\.PL$//;
+$file =~ s/\.pl$//
+	if ($Config{'osname'} eq 'VMS' or
+	    $Config{'osname'} eq 'OS2');  # "case-forgiving"
+open OUT,">$file" or die "Can't create $file: $!";
+chmod(0755, $file);
+print "Extracting $file (with variable substitutions)\n";
+
+print OUT <<"!GROK!THIS!";
+$Config{'startperl'} -w
+
+!GROK!THIS!
+
+print OUT <<'!NO!SUBS!';
+# $Id$
+
+=head1 NAME
+
+lwp-download - fetch large files from the net
+
+=head1 SYNOPSIS
+
+ lwp-download [-a] <url> [<local file>]
+
+=head1 DESCRIPTION
+
+The I<lwp-download> program will down load the document specified by the URL
+given as the first command line argument to a local file.  The local
+filename used to save the document is guessed from the URL unless
+specified as the second command line argument.
+
+The I<lwp-download> program is implemented using the I<libwww-perl>
+library.  It is better suited to down load big files than the
+I<lwp-request> program because it does not store the file in memory.
+Another benefit is that it will keep you updated about its progress
+and that you don't have much options to worry about.
+
+Use the C<-a> option to save the file in text (ascii) mode.  Might make a
+difference on dosish systems.
+
+=head1 EXAMPLE
+
+Fetch the newest and greatest perl version:
+
+ $ lwp-download http://www.perl.com/CPAN/src/latest.tar.gz
+ Saving to 'latest.tar.gz'...
+ 1.47 MB received in 22 seconds (68.7 KB/sec)
+
+=head1 AUTHOR
+
+Gisle Aas <gisle@aas.no>
+
+=cut
+
+use LWP::UserAgent;
+use LWP::MediaTypes;
+use URI::URL;
+use strict;
+
+my $progname = $0;
+$progname =~ s,.*/,,;    # only basename left in progname
+$progname =~ s/\.\w*$//; # strip extension if any
+
+#parse option
+use Getopt::Std;
+my %opts;
+unless (getopts('a', \%opts)) {
+    usage();
+}
+my $opt_a = $opts{a}; # save in binary mode
+
+my $url = url(shift || usage());
+my $argfile = shift;
+
+my $ua = new LWP::UserAgent;
+
+$ua->agent("lwp-download/0.1 " . $ua->agent);
+$ua->env_proxy;
+
+my $req = new HTTP::Request GET => $url;
+
+my $file;      # name of file we download into
+my $length;    # total number of bytes to download
+my $flength;   # formatted length
+my $size = 0;  # number of bytes received
+my $start_t;   # start time of download
+my $last_dur;  # time of last callback
+
+my $shown = 0; # have we called the show() function yet
+
+$SIG{INT} = sub { die "Interrupted\n"; };
+
+$| = 1;  # autoflush
+
+my $res = $ua->request($req,
+  sub {
+      unless($file) {
+	  my $res = $_[1];
+	  unless ($argfile) {
+	      # must find a suitable name to use.  First thing
+	      # to do is to look for the "Content-Disposition"
+	      # header defined by RFC1806.  This is also supported
+	      # by Netscape
+	      my $cd = $res->header("Content-Disposition");
+	      if ($cd && $cd =~ /\bfilename\s*=\s*(\S+)/) {
+		  $file = $1;
+		  $file =~ s/;$//;
+		  $file =~ s/^([\"\'])(.*)\1$/$2/;
+	      }
+		
+	      # if this fails we try to make something from the URL
+	      unless ($file) {
+		  my $req = $res->request;  # now always there
+		  my $rurl = $req ? $req->url : $url;
+		  
+		  $file = ($rurl->path_components)[-1];
+		  unless (length $file) {
+		      $file = "index";
+		      my $suffix = media_suffix($res->content_type);
+		      $file .= ".$suffix" if $suffix;
+		  } elsif ($rurl->scheme eq 'ftp' ||
+			   $file =~ /\.tgz$/      ||
+			   $file =~ /\.tar(\.(Z|gz))?$/
+			  ) {
+		      # leave the filename as it was
+		  } else {
+		      my $ct = guess_media_type($file);
+		      unless ($ct eq $res->content_type) {
+			  # need a better suffix for this type
+			  my $suffix = media_suffix($res->content_type);
+			  $file .= ".$suffix" if $suffix;
+		      }
+		  }
+	      }
+
+	      # Check if the file is already present
+	      if (-f $file && -t) {
+		  print "Overwrite $file? [y] ";
+		  my $ans = <STDIN>;
+		  exit if !defined($ans) || !($ans =~ /^y?\n/);
+	      } else {
+		  print "Saving to '$file'...\n";
+	      }
+	  } else {
+	      $file = $argfile;
+	  }
+	  open(FILE, ">$file") || die "Can't open $file: $!";
+          binmode FILE unless $opt_a;
+	  $length = $res->content_length;
+	  $flength = fbytes($length) if defined $length;
+	  $start_t = time;
+	  $last_dur = 0;
+      }
+      $size += length($_[0]);
+      print FILE $_[0];
+      if (defined $length) {
+	  my $dur  = time - $start_t;
+	  if ($dur != $last_dur) {  # don't update too often
+	      $last_dur = $dur;
+	      my $perc = $size / $length;
+	      my $speed;
+	      $speed = fbytes($size/$dur) . "/sec" if $dur > 3;
+	      my $secs_left = fduration($dur/$perc - $dur);
+	      $perc = int($perc*100);
+	      my $show = "$perc% of $flength";
+	      $show .= " (at $speed, $secs_left remaining)" if $speed;
+	      show($show);
+	  }
+      } else {
+	  show( fbytes($size) . " received");
+      }
+  }
+);
+
+if ($res->is_success || $res->message =~ /^Interrupted/) {
+    show("");  # clear text
+    print "\r";
+    print fbytes($size);
+    print " of ", fbytes($length) if defined($length) && $length != $size;
+    print " received";
+    my $dur = time - $start_t;
+    if ($dur) {
+	my $speed = fbytes($size/$dur) . "/sec";
+	print " in ", fduration($dur), " ($speed)";
+    }
+    print "\n";
+    my $died = $res->header("X-Died");
+    if ($died || !$res->is_success) {
+	if (-t) {
+	    print "Transfer aborted.  Delete $file? [n] ";
+	    my $ans = <STDIN>;
+	    unlink($file) if defined($ans) && $ans =~ /^y\n/;
+	} else {
+	    print "Transfer aborted, $file kept\n";
+	}
+    }
+} else {
+    print "\n" if $shown;
+    print "$progname: Can't download: ", $res->code, " ", $res->message, "\n";
+    exit 1;
+}
+
+
+sub fbytes
+{
+    my $n = int(shift);
+    if ($n >= 1024 * 1024) {
+	return sprintf "%.3g MB", $n / (1024.0 * 1024);
+    } elsif ($n >= 1024) {
+	return sprintf "%.3g KB", $n / 1024.0;
+    } else {
+	return "$n bytes";
+    }
+}
+
+sub fduration
+{
+    use integer;
+    my $secs = int(shift);
+    my $hours = $secs / (60*60);
+    $secs -= $hours * 60*60;
+    my $mins = $secs / 60;
+    $secs %= 60;
+    if ($hours) {
+	return "$hours hours $mins minutes";
+    } elsif ($mins >= 2) {
+	return "$mins minutes";
+    } else {
+	$secs += $mins * 60;
+	return "$secs seconds";
+    }
+}
+
+sub show
+{
+    my $mess = shift;
+    print "\r$mess", (" " x (75 - length $mess));
+    $shown++;
+}
+
+sub usage
+{
+    die "Usage: $progname [-a] <url> [<lpath>]\n";
+}
+!NO!SUBS!
Index: /main/tags/2.25/gsdl/packages/w3mir/libwww-perl-5.36/bin/lwp-mirror.PL
===================================================================
--- /main/tags/2.25/gsdl/packages/w3mir/libwww-perl-5.36/bin/lwp-mirror.PL	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/w3mir/libwww-perl-5.36/bin/lwp-mirror.PL	(revision 21064)
@@ -0,0 +1,120 @@
+use Config;
+use File::Basename qw(basename dirname);
+chdir(dirname($0));
+($file = basename($0)) =~ s/\.PL$//;
+$file =~ s/\.pl$//
+	if ($Config{'osname'} eq 'VMS' or
+	    $Config{'osname'} eq 'OS2');  # "case-forgiving"
+open OUT,">$file" or die "Can't create $file: $!";
+chmod(0755, $file);
+print "Extracting $file (with variable substitutions)\n";
+
+print OUT <<"!GROK!THIS!";
+$Config{'startperl'} -w
+
+!GROK!THIS!
+
+print OUT <<'!NO!SUBS!';
+# $Id$
+#
+# Simple mirror utility using LWP
+
+=head1 NAME
+
+lwp-mirror - Simple mirror utility for WWW
+
+=head1 SYNOPSIS
+
+ lwp-mirror [-v] [-t timeout] <url> <local file>
+
+=head1 DESCRIPTION
+
+This program can be used to mirror a document from a WWW server.  The
+document is only transfered if the remote copy is newer than the local
+copy.  If the local copy is newer nothing happens.
+
+Use the C<-v> option to print the version number of this program.
+
+The timeout value specified with the C<-t> option.  The timeout value
+is the time that the program will wait for response from the remote
+server before it fails.  The default unit for the timeout value is
+seconds.  You might append "m" or "h" to the timeout value to make it
+minutes or hours, repectively.
+
+Because this program is implemented using the LWP library, it only
+supports the protocols that LWP supports.
+
+=head1 SEE ALSO
+
+L<lwp-request>, L<LWP>
+
+=head1 AUTHOR
+
+Gisle Aas <aas@a.sn.no>
+
+=cut
+
+
+use LWP::Simple;
+use Getopt::Std;
+
+$progname = $0;
+$progname =~ s,.*/,,;  # use basename only
+$progname =~ s/\.\w*$//; #strip extension if any
+
+$VERSION = sprintf("%d.%02d", q$Revision$ =~ /(\d+)\.(\d+)/);
+
+$opt_h = undef;  # print usage
+$opt_v = undef;  # print version
+$opt_t = undef;  # timeout
+
+unless (getopts("hvt:")) {
+    usage();
+}
+
+if ($opt_v) {
+    require LWP;
+    my $DISTNAME = 'libwww-perl-' . LWP::Version();
+    die <<"EOT";
+This is lwp-mirror version $VERSION ($DISTNAME)
+
+Copyright 1995-1996, Gisle Aas.
+
+This program is free software; you can redistribute it and/or
+modify it under the same terms as Perl itself.
+EOT
+}
+
+$url  = shift or usage();
+$file = shift or usage();
+usage() if $opt_h or @ARGV;
+
+if (defined $opt_t) {
+    $opt_t =~ /^(\d+)([smh])?/;
+    die "$progname: Illegal timeout value!\n" unless defined $1;
+    $timeout = $1;
+    $timeout *= 60   if ($2 eq "m");
+    $timeout *= 3600 if ($2 eq "h");
+    $LWP::Simple::ua->timeout($timeout);
+}
+
+$rc = mirror($url, $file);
+
+if ($rc == 304) {
+    print STDERR "$progname: $file is up to date\n"
+} elsif (!is_success($rc)) {
+    print STDERR "$progname: $rc ", status_message($rc), "   ($url)\n";
+    exit 1;
+}
+exit;
+
+
+sub usage
+{
+    die <<"EOT";
+Usage: $progname [-options] <url> <file>
+    -v           print version number of program
+    -t <timeout> Set timeout value
+EOT
+}
+!NO!SUBS!
Index: /main/tags/2.25/gsdl/packages/w3mir/libwww-perl-5.36/bin/lwp-request.PL
===================================================================
--- /main/tags/2.25/gsdl/packages/w3mir/libwww-perl-5.36/bin/lwp-request.PL	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/w3mir/libwww-perl-5.36/bin/lwp-request.PL	(revision 21064)
@@ -0,0 +1,521 @@
+use Config;
+use File::Basename qw(basename dirname);
+chdir(dirname($0));
+($file = basename($0)) =~ s/\.PL$//;
+$file =~ s/\.pl$//
+	if ($Config{'osname'} eq 'VMS' or
+	    $Config{'osname'} eq 'OS2');  # "case-forgiving"
+open OUT,">$file" or die "Can't create $file: $!";
+chmod(0755, $file);
+print "Extracting $file (with variable substitutions)\n";
+
+print OUT <<"!GROK!THIS!";
+$Config{'startperl'} -w
+
+!GROK!THIS!
+
+print OUT <<'!NO!SUBS!';
+# $Id$
+#
+# Simple user agent using LWP library.
+
+=head1 NAME
+
+lwp-request, GET, HEAD, POST - Simple WWW user agent
+
+=head1 SYNOPSIS
+
+ lwp-request [-aeEdvhx] [-m method] [-b <base URL>] [-t <timeout>]
+             [-i <if-modified-since>] [-c <content-type>] [-C <credentials>]
+             [-p <proxy-url>] [-o <format>] <url>...
+
+=head1 DESCRIPTION
+
+This program can be used to send requests to WWW servers and your
+local file system. The request content for POST, PUT and CHECKIN
+methods is read from stdin.  The content of the response is printed on
+stdout.  Error messages are printed on stderr.  The program returns a
+status value indicating the number of URLs that failed.
+
+The options are:
+
+=over 4
+
+=item -m <method>
+
+Set which method to use for the request.  If this option is not used,
+then the method is derived from the name of the program.
+
+=item -f
+
+Force request through, even if the program believes that the method is
+illegal.  The server will probably reject the request.
+
+=item -b <url>
+
+This URL will be used as the base URL for the URLs that the method is
+applied to.  The base URL only takes effect for relative URLs.  If you
+do not provide this option and the URLs are relative, then they will
+be treated as files in the local file system.
+
+=item -t <timeout>
+
+Set the timeout value for the requests.  The timeout is the amount of
+time that the program will wait for a response from the remote server
+before it fails.  The default unit for the timeout value is seconds.
+You might append "m" or "h" to the timeout value to make it minutes or
+hours, respectively.  The default timeout is '3m', i.e. 3 minutes.
+
+=item -i <time>
+
+Set the If-Modified-Since header in the request. If I<time> it the
+name of a file, use the modification timestamp for this file. If
+I<time> is not a file, it is parsed as a literal date. Take a look at
+L<HTTP::Date> for recogniced formats.
+
+=item -c <content-type>
+
+Set the Content-Type for the request.  This option is only allowed for
+requests that take a content, i.e. POST, PUT and CHECKIN.  You can
+force methods to take content by using the C<-f> option together with
+C<-c>.  The default Content-Type for POST is
+C<application/x-www-form-urlencoded>.  The default Content-type for
+the others is C<text/plain>.
+
+=item -p <proxy-url>
+
+Set the proxy to be used for the requests.  The program also loads
+proxy settings from the environment.  You can disable this with the
+C<-P> option.
+
+=item -C <username>:<password>
+
+Provide credentials for documents that are protected by Basic
+Authentication.  If the document is protected and you did not specify
+the username and password with this option, then you will be prompted
+to provide these values.
+
+=back
+
+The following options controls what is displayed by the program:
+
+=over 4
+
+=item -u
+
+Print request method and absolute URL as requests are made.
+
+=item -U
+
+Print request headers in addition to request method and absolute URL.
+
+=item -s
+
+Print response status code.  This option is always on for HEAD requests.
+
+=item -S
+
+Print response status chain. This shows redirect and autorization
+requests that are handled by the library.
+
+=item -e
+
+Print response headers.  This option is always on for HEAD requests.
+
+=item -d
+
+Do B<not> print the content of the response.
+
+=item -o <format>
+
+Process HTML content in various ways before printing it.  If the
+content type of the response is not HTML, then this option has no
+effect.  The legal format values are; I<text>, I<ps>, I<links>,
+I<html> and I<dump>.
+
+If you specify the I<text> format then the HTML will be formatted as
+plain latin1 text.  If you specify the I<ps> format then it will be
+formatted as Postscript.
+
+The I<links> format will output all links found in the HTML document.
+Relative links will be expanded to absolute ones.
+
+The I<html> format will reformat the HTML code and the I<dump> format
+will just dump the HTML syntax tree.
+
+=item -v
+
+Print the version number of the program and quit.
+
+=item -h
+
+Print usage message and quit.
+
+=item -x
+
+Extra debugging output.
+
+=item -a
+
+Set text(ascii) mode for content input and output.  If this option is not 
+used, content input and output is done in binary mode.
+
+=back
+
+Because this program is implemented using the LWP library, it will
+only support the protocols that LWP supports.
+
+=head1 SEE ALSO
+
+L<lwp-mirror>, L<LWP>
+
+=head1 COPYRIGHT
+
+Copyright 1995-1997 Gisle Aas.
+
+This library is free software; you can redistribute it and/or
+modify it under the same terms as Perl itself.
+
+=head1 AUTHOR
+
+Gisle Aas <aas@sn.no>
+
+=cut
+
+$progname = $0;
+$progname =~ s,.*/,,;  # use basename only
+$progname =~ s/\.\w*$//; # strip extension, if any
+
+$VERSION = sprintf("%d.%02d", q$Revision$ =~ /(\d+)\.(\d+)/);
+
+
+require LWP;
+require LWP::Debug;
+require URI::URL;
+
+use URI::Heuristic qw(uf_url);
+
+use HTTP::Status qw(status_message);
+use HTTP::Date qw(time2str str2time);
+
+
+# This table lists the methods that are allowed.  It should really be
+# a superset for all methods supported for every scheme that may be
+# supported by the library.  Currently it might be a bit too HTTP
+# specific.  You might use the -f option to force a method through.
+#
+# "" = No content in request, "C" = Needs content in request
+#
+%allowed_methods = (
+    GET        => "",
+    HEAD       => "",
+    POST       => "C",
+    PUT        => "C",
+    DELETE     => "",
+    TRACE      => "",
+    OPTIONS    => "",
+);
+
+
+# We make our own specialization of LWP::UserAgent that asks for
+# user/password if document is protected.
+{
+    package RequestAgent;
+    @ISA = qw(LWP::UserAgent);
+
+    sub new
+    { 
+	my $self = LWP::UserAgent::new(@_);
+	$self->agent("lwp-request/$main::VERSION");
+	$self;
+    }
+
+    sub get_basic_credentials
+    {
+	my($self, $realm, $uri) = @_;
+	if ($main::opt_C) {
+	    return split(':', $main::opt_C, 2);
+	} elsif (-t) {
+	    my $netloc = $uri->netloc;
+	    print "Enter username for $realm at $netloc: ";
+	    my $user = <STDIN>;
+	    chomp($user);
+	    return (undef, undef) unless length $user;
+	    print "Password: ";
+	    system("stty -echo");
+	    my $password = <STDIN>;
+	    system("stty echo");
+	    print "\n";  # because we disabled echo
+	    chomp($password);
+	    return ($user, $password);
+	} else {
+	    return (undef, undef)
+	}
+    }
+}
+
+$method = uc(lc($progname) eq "lwp-request" ? "GET" : $progname);
+
+# Parse command line
+use Getopt::Std;
+
+$opt_a = undef;  # content i/o in text(ascii) mode
+$opt_m = undef;  # set method
+$opt_f = undef;  # make request even if method is not in %allowed_methods
+$opt_b = undef;  # base url
+$opt_t = undef;  # timeout
+$opt_i = undef;  # if-modified-since
+$opt_c = undef;  # content type for POST
+$opt_C = undef;  # credidentials for basic authorization
+
+$opt_u = undef;  # display method, URL and headers of request
+$opt_U = undef;  # display request headers also
+$opt_s = undef;  # display status code
+$opt_S = undef;  # display whole chain of status codes
+$opt_e = undef;  # display response headers (default for HEAD)
+$opt_d = undef;  # don't display content
+
+$opt_h = undef;  # print usage
+$opt_v = undef;  # print version
+
+$opt_x = undef;  # extra debugging info
+$opt_p = undef;  # proxy URL
+$opt_P = undef;  # don't load proxy setting from environment
+
+$opt_o = undef;  # output format
+
+unless (getopts("axhvuUsSedPp:b:t:i:c:C:m:fo:")) {
+    usage();
+}
+
+if ($opt_v) {
+    require LWP;
+    my $DISTNAME = 'libwww-perl-' . LWP::Version();
+    die <<"EOT";
+This is lwp-request version $VERSION ($DISTNAME)
+
+Copyright 1995-1997, Gisle Aas.
+
+This program is free software; you can redistribute it and/or
+modify it under the same terms as Perl itself.
+EOT
+}
+
+usage() if $opt_h || !@ARGV;
+
+LWP::Debug::level('+') if $opt_x;
+
+# Create the user agent object
+$ua = new RequestAgent;
+
+# Load proxy settings from *_proxy environment variables.
+$ua->env_proxy unless $opt_P;
+
+$method = uc($opt_m) if defined $opt_m;
+
+if ($opt_f) {
+    if ($opt_c) {
+        $allowed_methods{$method} = "C";  # force content
+    } else {
+        $allowed_methods{$method} = "";
+    }
+} elsif (!defined $allowed_methods{$method}) {
+    die "$progname: $method is not an allowed method\n";
+}
+
+if ($method eq "HEAD") {
+    $opt_s = 1;
+    $opt_e = 1 unless $opt_d;
+    $opt_d = 1;
+}
+
+if (defined $opt_t) {
+    $opt_t =~ /^(\d+)([smh])?/;
+    die "$progname: Illegal timeout value!\n" unless defined $1;
+    $timeout = $1;
+    $timeout *= 60   if ($2 eq "m");
+    $timeout *= 3600 if ($2 eq "h");
+    $ua->timeout($timeout);
+}
+
+if (defined $opt_i) {
+    if (-e $opt_i) {
+        $time = (stat _)[9];
+    } else {
+        $time = str2time($opt_i);
+        die "$progname: Illegal time syntax for -i option\n"
+            unless defined $time;
+    }
+    $opt_i = time2str($time);
+}
+
+$content = undef;
+if ($allowed_methods{$method} eq "C") {
+    # This request needs some content
+    unless (defined $opt_c) {
+        # set default content type
+        $opt_c = ($method eq "POST") ?
+              "application/x-www-form-urlencoded"
+            : "text/plain";
+    } else {
+        die "$progname: Illegal Content-type format\n"
+            unless $opt_c =~ m,^[\w\-]+/[\w\-]+(?:\s*;.*)?$,
+    }
+    print "Please enter content ($opt_c) to be ${method}ed:\n"
+        if -t;
+    binmode STDIN unless -t or $opt_a;
+    $content = join("", <STDIN>);
+} else {
+    die "$progname: Can't set Content-type for $method requests\n"
+        if defined $opt_c;
+}
+
+# Set up a request.  We will use the same request object for all URLs.
+$request = new HTTP::Request $method;
+$request->header('If-Modified-Since', $opt_i) if defined $opt_i;
+#$request->header('Accept', '*/*');
+if ($opt_c) { # will always be set for request that wants content
+    $request->header('Content-Type', $opt_c);
+    $request->header('Content-Length', length $content);  # Not really needed
+    $request->content($content);
+}
+
+
+$errors = 0;
+
+# Ok, now we perform the requests, one URL at a time
+while ($url = shift) {
+    # Create the URL object, but protect us against bad URLs
+    eval {
+	if ($url =~ /^\w+:/ || $opt_b) {  # is there any scheme specification
+	    $url = URI::URL->new($url, $opt_b);
+	} else {
+	    $url = uf_url($url);
+        }
+    };
+    if ($@) {
+	$@ =~ s/at\s+\S+\s+line\s\d+//;
+	print STDERR $@;
+	$errors++;
+	next;
+    }
+
+    $ua->proxy($url->scheme, $opt_p) if $opt_p;
+
+    # Send the request and get a response back from the server
+    $request->url($url);
+    $response = $ua->request($request);
+
+    if ($opt_u || $opt_U) {
+        my $url = $response->request->url->as_string;
+        print "$method $url\n";
+        print $response->request->headers_as_string, "\n" if $opt_U;
+    }
+
+    if ($opt_S) {
+	printResponseChain($response);
+    } elsif ($opt_s) {
+        print $response->status_line, "\n";
+    }
+
+    if ($opt_e) {
+        # Display headers
+        print $response->headers_as_string;
+        print "\n";  # separate headers and content
+    }
+
+    if ($response->is_success) {
+	unless ($opt_d) {
+	    if ($opt_o &&
+		$response->content_type eq 'text/html') {
+		require HTML::Parse;
+		my $html = HTML::Parse::parse_html($response->content);
+		{
+		    $opt_o eq 'ps' && do {
+			require HTML::FormatPS;
+			my $f = new HTML::FormatPS;
+			print $f->format($html);
+			last;
+		    };
+		    $opt_o eq 'text' && do {
+			require HTML::FormatText;
+			my $f = new HTML::FormatText;
+			print $f->format($html);
+			last;
+		    };
+		    $opt_o eq 'html' && do {
+			print $html->as_HTML;
+			last;
+		    };
+		    $opt_o eq 'links' && do {
+			my $base = $response->base;
+			for ( @{ $html->extract_links } ) {
+			    my($link, $elem) = @$_;
+			    my $tag = uc $elem->tag;
+			    $link = new URI::URL $link, $base;
+			    print "$tag\t", $link->abs->as_string, "\n";
+			}
+			last;
+		    };
+		    $opt_o eq 'dump' && do {
+			$html->dump;
+			last;
+		    };
+		    # It is bad to not notice this before now :-(
+		    die "Illegal -o option value ($opt_o)\n";
+		}
+	    } else {
+                binmode STDOUT unless $opt_a;
+		print $response->content;
+	    }
+	}
+    } else {
+        print STDERR $response->error_as_HTML unless $opt_d;
+        $errors++;
+    }
+}
+
+exit $errors;
+
+
+sub printResponseChain
+{
+    my($response) = @_;
+    return unless defined $response;
+    printResponseChain($response->previous);
+    my $method = $response->request->method;
+    my $url = $response->request->url->as_string;
+    my $code = $response->code;
+    print "$method $url --> ", $response->status_line, "\n";
+}
+
+
+sub usage
+{
+    die <<"EOT";
+Usage: $progname [-options] <url>...
+    -m <method>   use method for the request (default is '$method')
+    -f            make request even if $progname believes method is illegal
+    -b <base>     Use the specified URL as base
+    -t <timeout>  Set timeout value
+    -i <time>     Set the If-Modified-Since header on the request
+    -c <conttype> use this content-type for POST, PUT, CHECKIN
+    -a            Use text mode for content I/O
+    -p <proxyurl> use this as a proxy
+    -P            don't load proxy settings from environment
+
+    -u            Display method and URL before any response
+    -U            Display request headers (implies -u)
+    -s            Display response status code
+    -S            Display response status chain
+    -e            Display response headers
+    -d            Do not display content
+    -o <format>   Process HTML content in various ways
+
+    -v            Show program version
+    -h            Print this message
+
+    -x            Extra debugging output
+EOT
+}
+!NO!SUBS!
Index: /main/tags/2.25/gsdl/packages/w3mir/libwww-perl-5.36/bin/lwp-rget.PL
===================================================================
--- /main/tags/2.25/gsdl/packages/w3mir/libwww-perl-5.36/bin/lwp-rget.PL	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/w3mir/libwww-perl-5.36/bin/lwp-rget.PL	(revision 21064)
@@ -0,0 +1,600 @@
+use Config;
+use File::Basename qw(basename dirname);
+chdir(dirname($0));
+($file = basename($0)) =~ s/\.PL$//;
+$file =~ s/\.pl$//
+	if ($Config{'osname'} eq 'VMS' or
+	    $Config{'osname'} eq 'OS2');  # "case-forgiving"
+open OUT,">$file" or die "Can't create $file: $!";
+chmod(0755, $file);
+print "Extracting $file (with variable substitutions)\n";
+
+print OUT <<"!GROK!THIS!";
+$Config{'startperl'} -w
+
+!GROK!THIS!
+
+print OUT <<'!NO!SUBS!';
+#line 18
+
+=head1 NAME
+
+lwp-rget - Retrieve WWW documents recursively
+
+=head1 SYNOPSIS
+
+ lwp-rget [--verbose] [--auth=USER:PASS] [--depth=N] [--hier] [--iis]
+	  [--keepext=mime/type[,mime/type]] [--limit=N] [--nospace]
+	  [--prefix=URL] [--sleep=N] [--tolower] <URL>
+ lwp-rget --version
+
+=head1 DESCRIPTION
+
+This program will retrieve a document and store it in a local file.  It
+will follow any links found in the document and store these documents
+as well, patching links so that they refer to these local copies.
+This process continues until there are no more unvisited links or the
+process is stopped by the one or more of the limits which can be
+controlled by the command line arguments.
+
+This program is useful if you want to make a local copy of a
+collection of documents or want to do web reading off-line.
+
+All documents are stored as plain files in the current directory. The
+file names chosen are derived from the last component of URL paths.
+
+The options are:
+
+=over 3
+
+=item --auth=USER:PASS<n>
+
+Set the authentication credentials to user "USER" and password "PASS" if
+any restricted parts of the web site are hit.  If there are restricted
+parts of the web site and authentication credentials are not available,
+those pages will not be downloaded.
+
+=item --depth=I<n>
+
+Limit the recursive level. Embedded images are always loaded, even if
+they fall outside the I<--depth>. This means that one can use
+I<--depth=0> in order to fetch a single document together with all
+inline graphics.
+
+The default depth is 5.
+
+=item --hier
+
+Download files into a hierarchy that mimics the web site structure.
+The default is to put all files in the current directory.
+
+=item --iis
+
+Sends an "Accept: */*" on all URL requests as a workaround for a bug in
+IIS 2.0.  If no Accept MIME header is present, IIS 2.0 returns with a
+"406 No acceptable objects were found" error.  Also converts any back
+slashes (\\) in URLs to forward slashes (/).
+
+=item --keepext=I<mime/type[,mime/type]>
+
+Keeps the current extension for the list MIME types.  Useful when
+downloading text/plain documents that shouldn't all be translated to
+*.txt files.
+
+=item --limit=I<n>
+
+Limit the number of documents to get.  The default limit is 50.
+
+=item --nospace
+
+Changes spaces in all URLs to underscore characters (_).  Useful when
+downloading files from sites serving URLs with spaces in them.	Does not
+remove spaces from fragments, e.g., "file.html#somewhere in here".
+
+=item --prefix=I<url_prefix>
+
+Limit the links to follow. Only URLs that start the prefix string are
+followed.
+
+The default prefix is set as the "directory" of the initial URL to
+follow.	 For instance if we start lwp-rget with the URL
+C<http://www.sn.no/foo/bar.html>, then prefix will be set to
+C<http://www.sn.no/foo/>.
+
+Use C<--prefix=''> if you don't want the fetching to be limited by any
+prefix.
+
+=item --sleep=I<n>
+
+Sleep I<n> seconds before retrieving each document. This options allows
+you to go slowly, not loading the server you visiting too much.
+
+=item --tolower
+
+Translates all links to lowercase.  Useful when downloading files from
+IIS since it does not serve files in a case sensitive manner.
+
+=item --verbose
+
+Make more noise while running.
+
+=item --quiet
+
+Don't make any noise.
+
+=item --version
+
+Print program version number and quit.
+
+=item --help
+
+Print the usage message and quit.
+
+=back
+
+Before the program exits the name of the file, where the initial URL
+is stored, is printed on stdout.  All used filenames are also printed
+on stderr as they are loaded.  This printing can be suppressed with
+the I<--quiet> option.
+
+=head1 SEE ALSO
+
+L<lwp-request>, L<LWP>
+
+=head1 AUTHOR
+
+Gisle Aas <aas@sn.no>
+
+=cut
+
+use strict;
+
+use Getopt::Long    qw(GetOptions);
+use URI::URL	    qw(url);
+use LWP::MediaTypes qw(media_suffix);
+
+use vars qw($VERSION);
+use vars qw($MAX_DEPTH $MAX_DOCS $PREFIX $VERBOSE $QUIET $SLEEP $HIER $AUTH $IIS $TOLOWER $NOSPACE %KEEPEXT);
+
+my $progname = $0;
+$progname =~ s|.*/||;  # only basename left
+$progname =~ s/\.\w*$//; #strip extension if any
+
+$VERSION = sprintf("%d.%02d", q$Revision$ =~ /(\d+)\.(\d+)/);
+
+#$Getopt::Long::debug = 1;
+#$Getopt::Long::ignorecase = 0;
+
+# Defaults
+$MAX_DEPTH = 5;
+$MAX_DOCS  = 50;
+
+GetOptions('version'  => \&print_version,
+	   'help'     => \&usage,
+	   'depth=i'  => \$MAX_DEPTH,
+	   'limit=i'  => \$MAX_DOCS,
+	   'verbose!' => \$VERBOSE,
+	   'quiet!'   => \$QUIET,
+	   'sleep=i'  => \$SLEEP,
+	   'prefix:s' => \$PREFIX,
+	   'hier'     => \$HIER,
+	   'auth=s'   => \$AUTH,
+	   'iis'      => \$IIS,
+	   'tolower'  => \$TOLOWER,
+	   'nospace'  => \$NOSPACE,
+	   'keepext=s' => \$KEEPEXT{'OPT'},
+	  ) || usage();
+
+sub print_version {
+    require LWP;
+    my $DISTNAME = 'libwww-perl-' . LWP::Version();
+    print <<"EOT";
+This is lwp-rget version $VERSION ($DISTNAME)
+
+Copyright 1996-1998, Gisle Aas.
+
+This program is free software; you can redistribute it and/or
+modify it under the same terms as Perl itself.
+EOT
+    exit 0;
+}
+
+my $start_url = shift || usage();
+usage() if @ARGV;
+
+require LWP::UserAgent;
+my $ua = new LWP::UserAgent;
+$ua->agent("$progname/$VERSION " . $ua->agent);
+$ua->env_proxy;
+
+unless (defined $PREFIX) {
+    $PREFIX = url($start_url);	 # limit to URLs below this one
+    eval {
+	$PREFIX->eparams(undef);
+	$PREFIX->equery(undef);
+    };
+
+    $_ = $PREFIX->epath;
+    s|[^/]+$||;
+    $PREFIX->epath($_);
+    $PREFIX = $PREFIX->as_string;
+}
+
+%KEEPEXT = map { lc($_) => 1 } split(/\s*,\s*/, $KEEPEXT{'OPT'});
+
+print <<"" if $VERBOSE;
+START	  = $start_url
+MAX_DEPTH = $MAX_DEPTH
+MAX_DOCS  = $MAX_DOCS
+PREFIX	  = $PREFIX
+
+
+my $no_docs = 0;
+my %seen = ();	   # mapping from URL => local_file
+
+my $filename = fetch($start_url);
+print "$filename\n" unless $QUIET;
+
+sub fetch
+{
+    my($url, $type, $depth) = @_;
+
+    # Fix http://sitename.com/../blah/blah.html to
+    #	  http://sitename.com/blah/blah.html
+    $url = $url->as_string if (ref($url));
+    while ($url =~ s#(https?://[^/]+/)\.\.\/#$1#) {}
+
+    # Fix backslashes (\) in URL if $IIS defined
+    $url = fix_backslashes($url) if (defined $IIS);
+
+    $url = url($url) unless ref($url);
+    $type  ||= 'a';
+    # Might be the background attribute
+    $type = 'img' if ($type eq 'body' || $type eq 'td');
+    $depth ||= 0;
+
+    # Print the URL before we start checking...
+    my $out = (" " x $depth) . $url . " ";
+    $out .= "." x (60 - length($out));
+    print STDERR $out . " " if $VERBOSE;
+
+    # Can't get mailto things
+    if ($url->scheme eq 'mailto') {
+	print STDERR "*skipping mailto*\n" if $VERBOSE;
+	return $url->as_string;
+    }
+
+    # The $plain_url is a URL without the fragment part
+    my $plain_url = $url->clone;
+    $plain_url->frag(undef);
+
+    # Check PREFIX, but not for <IMG ...> links
+    if ($type ne 'img' and  $url->as_string !~ /^\Q$PREFIX/o) {
+	print STDERR "*outsider*\n" if $VERBOSE;
+	return $url->as_string;
+    }
+
+    # Translate URL to lowercase if $TOLOWER defined
+    $plain_url = to_lower($plain_url) if (defined $TOLOWER);
+
+    # If we already have it, then there is nothing to be done
+    my $seen = $seen{$plain_url->as_string};
+    if ($seen) {
+	my $frag = $url->frag;
+	$seen .= "#$frag" if defined($frag);
+	$seen = protect_frag_spaces($seen);
+	print STDERR "$seen (again)\n" if $VERBOSE;
+	return $seen;
+    }
+
+    # Too much or too deep
+    if ($depth > $MAX_DEPTH and $type ne 'img') {
+	print STDERR "*too deep*\n" if $VERBOSE;
+	return $url;
+    }
+    if ($no_docs > $MAX_DOCS) {
+	print STDERR "*too many*\n" if $VERBOSE;
+	return $url;
+    }
+
+    # Fetch document 
+    $no_docs++;
+    sleep($SLEEP) if $SLEEP;
+    my $req = HTTP::Request->new(GET => $url);
+    # See: http://ftp.sunet.se/pub/NT/mirror-microsoft/kb/Q163/7/74.TXT
+    $req->header ('Accept', '*/*') if (defined $IIS);  # GIF/JPG from IIS 2.0
+    $req->authorization_basic(split (/:/, $AUTH)) if (defined $AUTH);
+    my $res = $ua->request($req);
+
+    # Check outcome
+    if ($res->is_success) {
+	my $doc = $res->content;
+	my $ct = $res->content_type;
+	my $name = find_name($res->request->url, $ct);
+	print STDERR "$name\n" unless $QUIET;
+	$seen{$plain_url->as_string} = $name;
+
+	# If the file is HTML, then we look for internal links
+	if ($ct eq "text/html") {
+	    # Save an unprosessed version of the HTML document.	 This
+	    # both reserves the name used, and it also ensures that we
+	    # don't loose everything if this program is killed before
+	    # we finish.
+	    save($name, $doc);
+	    my $base = $res->base;
+
+	    # Follow and substitute links...
+	    $doc =~
+s/
+  (
+    <(img|a|body|area|frame|td)\b   # some interesting tag
+    [^>]+			    # still inside tag (not strictly correct)
+    \b(?:src|href|background)	    # some link attribute
+    \s*=\s*			    # =
+  )
+    (?:				    # scope of OR-ing
+	 (")([^"]*)"	|	    # value in double quotes  OR
+	 (')([^']*)'	|	    # value in single quotes  OR
+	    ([^\s>]+)		    # quoteless value
+    )
+/
+  new_link($1, lc($2), $3||$5, $4||$6||$7, $base, $name, $depth+1)
+/giex;
+	   # XXX
+	   # The regular expression above is not strictly correct.
+	   # It is not really possible to parse HTML with a single
+	   # regular expression, but it is faster.  Tags that might
+	   # confuse us include:
+	   #	<a alt="href" href=link.html>
+	   #	<a alt=">" href="link.html">
+	   #
+	}
+	save($name, $doc);
+	return $name;
+    } else {
+	print STDERR $res->code . " " . $res->message . "\n" if $VERBOSE;
+	$seen{$plain_url->as_string} = $url->as_string;
+	return $url->as_string;
+    }
+}
+
+sub new_link
+{
+    my($pre, $type, $quote, $url, $base, $localbase, $depth) = @_;
+
+    $url = protect_frag_spaces($url);
+
+    $url = fetch(url($url, $base)->abs, $type, $depth);
+    $url = url("file:$url", "file:$localbase")->rel
+	unless $url =~ /^[.+\-\w]+:/;
+
+    $url = unprotect_frag_spaces($url);
+
+    return $pre . $quote . $url . $quote;
+}
+
+
+sub protect_frag_spaces
+{
+    my ($url) = @_;
+
+    $url = $url->as_string if (ref($url));
+
+    if ($url =~ m/^([^#]*#)(.+)$/)
+    {
+      my ($base, $frag) = ($1, $2);
+      $frag =~ s/ /%20/g;
+      $url = $base . $frag;
+    }
+
+    return $url;
+}
+
+
+sub unprotect_frag_spaces
+{
+    my ($url) = @_;
+
+    $url = $url->as_string if (ref($url));
+
+    if ($url =~ m/^([^#]*#)(.+)$/)
+    {
+      my ($base, $frag) = ($1, $2);
+      $frag =~ s/%20/ /g;
+      $url = $base . $frag;
+    }
+
+    return $url;
+}
+
+
+sub fix_backslashes
+{
+    my ($url) = @_;
+    my ($base, $frag);
+
+    $url = $url->as_string if (ref($url));
+
+    if ($url =~ m/([^#]+)(#.*)/)
+    {
+      ($base, $frag) = ($1, $2);
+    }
+    else
+    {
+      $base = $url;
+      $frag = "";
+    }
+
+    $base =~ tr/\\/\//;
+    $base =~ s/%5[cC]/\//g;	# URL-encoded back slash is %5C
+
+    return $base . $frag;
+}
+
+
+sub to_lower
+{
+    my ($url) = @_;
+    my $was_object = 0;
+
+    if (ref($url))
+    {
+      $url = $url->as_string;
+      $was_object = 1;
+    }
+
+    if ($url =~ m/([^#]+)(#.*)/)
+    {
+      $url = lc($1) . $2;
+    }
+    else
+    {
+      $url = lc($url);
+    }
+
+    if ($was_object == 1)
+    {
+      return url($url);
+    }
+    else
+    {
+      return $url;
+    }
+}
+
+
+sub translate_spaces
+{
+    my ($url) = @_;
+    my ($base, $frag);
+
+    $url = $url->as_string if (ref($url));
+
+    if ($url =~ m/([^#]+)(#.*)/)
+    {
+      ($base, $frag) = ($1, $2);
+    }
+    else
+    {
+      $base = $url;
+      $frag = "";
+    }
+
+    $base =~ s/^ *//;	# Remove initial spaces from base
+    $base =~ s/ *$//;	# Remove trailing spaces from base
+
+    $base =~ tr/ /_/;
+    $base =~ s/%20/_/g; # URL-encoded space is %20
+
+    return $base . $frag;
+}
+
+
+sub mkdirp
+{
+    my($directory, $mode) = @_;
+    my @dirs = split(/\//, $directory);
+    my $path = shift(@dirs);   # build it as we go
+    my $result = 1;   # assume it will work
+
+    unless (-d $path) {
+	$result &&= mkdir($path, $mode);
+    }
+
+    foreach (@dirs) {
+	$path .= "/$_";
+	if ( ! -d $path) {
+	    $result &&= mkdir($path, $mode);
+	}
+    }
+
+    return $result;
+}
+
+
+sub find_name
+{
+    my($url, $type) = @_;
+    #print "find_name($url, $type)\n";
+
+    # Translate spaces in URL to underscores (_) if $NOSPACE defined
+    $url = translate_spaces($url) if (defined $NOSPACE);
+
+    # Translate URL to lowercase if $TOLOWER defined
+    $url = to_lower($url) if (defined $TOLOWER);
+
+    $url = url($url) unless ref($url);
+
+    my $path = $url->path;
+
+    # trim path until only the basename is left
+    $path =~ s|(.*/)||;
+    my $dirname = ".$1";
+    if (!$HIER) {
+	$dirname = "";
+    } elsif (! -d $dirname) {
+	mkdirp($dirname, 0775);
+    }
+
+    my $extra = "";  # something to make the name unique
+    my $suffix;
+
+    if ($KEEPEXT{lc($type)}) {
+        $suffix = ($path =~ m/\.(.*)/) ? $1 : "";
+    } else {
+        $suffix = media_suffix($type);
+    }
+
+    $path =~ s|\..*||;	# trim suffix
+    $path = "index" unless length $path;
+
+    while (1) {
+	# Construct a new file name
+	my $file = $dirname . $path . $extra;
+	$file .= ".$suffix" if $suffix;
+	# Check if it is unique
+	return $file unless -f $file;
+
+	# Try something extra
+	unless ($extra) {
+	    $extra = "001";
+	    next;
+	}
+	$extra++;
+    }
+}
+
+
+sub save
+{
+    my $name = shift;
+    #print "save($name,...)\n";
+    open(FILE, ">$name") || die "Can't save $name: $!";
+    binmode FILE;
+    print FILE $_[0];
+    close(FILE);
+}
+
+
+sub usage
+{
+    die <<"";
+Usage: $progname [options] <URL>
+Allowed options are:
+  --auth=USER:PASS  Set authentication credentials for web site
+  --depth=N	    Maximum depth to traverse (default is $MAX_DEPTH)
+  --hier	    Download into hierarchy (not all files into cwd)
+  --iis		    Workaround IIS 2.0 bug by sending "Accept: */*" MIME
+		    header; translates backslashes (\\) to forward slashes (/)
+  --keepext=type    Keep file extension for MIME types (comma-separated list)
+  --limit=N	    A limit on the number documents to get (default is $MAX_DOCS)
+  --nospace	    Translate spaces URLs (not #fragments) to underscores (_)
+  --version	    Print version number and quit
+  --verbose	    More output
+  --quiet	    No output
+  --sleep=SECS	    Sleep between gets, ie. go slowly
+  --prefix=PREFIX   Limit URLs to follow to those which begin with PREFIX
+  --tolower	    Translate all URLs to lowercase (useful with IIS servers)
+
+}
+!NO!SUBS!
Index: /main/tags/2.25/gsdl/packages/w3mir/libwww-perl-5.36/install.sh
===================================================================
--- /main/tags/2.25/gsdl/packages/w3mir/libwww-perl-5.36/install.sh	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/w3mir/libwww-perl-5.36/install.sh	(revision 21064)
@@ -0,0 +1,10 @@
+#!/bin/sh -v
+
+export PERL5LIB=$GSDLHOME/perllib/cpan/lib:$PERL5LIB
+export PATH=$GSDLHOME/perllib/cpan/bin:$PATH
+
+perl Makefile.PL PREFIX=$GSDLHOME/perllib/cpan
+
+make
+make test
+make install
Index: /main/tags/2.25/gsdl/packages/w3mir/libwww-perl-5.36/lib/Bundle/LWP.pm
===================================================================
--- /main/tags/2.25/gsdl/packages/w3mir/libwww-perl-5.36/lib/Bundle/LWP.pm	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/w3mir/libwww-perl-5.36/lib/Bundle/LWP.pm	(revision 21064)
@@ -0,0 +1,38 @@
+package Bundle::LWP;
+
+$VERSION = sprintf("%d.%02d", q$Revision$ =~ /(\d+)\.(\d+)/);
+
+1;
+
+__END__
+
+=head1 NAME
+
+Bundle::LWP - A bundle to install all libwww-perl related modules
+
+=head1 SYNOPSIS
+
+ perl -MCPAN -e 'install Bundle::LWP'
+
+=head1 CONTENTS
+
+Net::FTP 2.00      - If you want ftp://-support
+
+MIME::Base64       - Used in authentication headers
+
+MD5                - Needed to do Digest authentication
+
+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.
+
+
+=head1 AUTHOR
+
+Gisle Aas E<lt>aas@sn.no>
+
+=cut
Index: /main/tags/2.25/gsdl/packages/w3mir/libwww-perl-5.36/lib/File/Listing.pm
===================================================================
--- /main/tags/2.25/gsdl/packages/w3mir/libwww-perl-5.36/lib/File/Listing.pm	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/w3mir/libwww-perl-5.36/lib/File/Listing.pm	(revision 21064)
@@ -0,0 +1,314 @@
+#
+# $Id$
+
+package File::Listing;
+
+sub Version { $VERSION; }
+$VERSION = sprintf("%d.%02d", q$Revision$ =~ /(\d+)\.(\d+)/);
+
+=head1 NAME
+
+parse_dir - parse directory listing
+
+=head1 SYNOPSIS
+
+ use File::Listing;
+ for (parse_dir(`ls -l`)) {
+     ($name, $type, $size, $mtime, $mode) = @$_;
+     next if $type ne 'f'; # plain file
+     #...
+ }
+
+ # directory listing can also be read from a file
+ open(LISTING, "zcat ls-lR.gz|");
+ $dir = parse_dir(\*LISTING, '+0000');
+
+=head1 DESCRIPTION
+
+The parse_dir() routine can be used to parse directory
+listings. Currently it only understand Unix C<'ls -l'> and C<'ls -lR'>
+format.  It should eventually be able to most things you might get
+back from a ftp server file listing (LIST command), i.e. VMS listings,
+NT listings, DOS listings,...
+
+The first parameter to parse_dir() is the directory listing to parse.
+It can be a scalar, a reference to an array of directory lines or a
+glob representing a filehandle to read the directory listing from.
+
+The second parameter is the time zone to use when parsing time stamps
+in the listing. If this value is undefined, then the local time zone is
+assumed.
+
+The third parameter is the type of listing to assume.  The values will
+be strings like 'unix', 'vms', 'dos'.  Currently only 'unix' is
+implemented and this is also the default value.  Ideally, the listing
+type should be determined automatically.
+
+The fourth parameter specify how unparseable lines should be treated.
+Values can be 'ignore', 'warn' or a code reference.  Warn means that
+the perl warn() function will be called.  If a code reference is
+passed, then this routine will be called and the return value from it
+will be incorporated in the listing.  The default is 'ignore'.
+
+Only the first parameter is mandatory.  The parse_dir() prototype is
+($;$$$).
+
+The return value from parse_dir() is a list of directory entries.  In
+scalar context the return value is a reference to the list.  The
+directory entries are represented by an array consisting of [
+$filename, $filetype, $filesize, $filetime, $filemode ].  The
+$filetype value is one of the letters 'f', 'd', 'l' or '?'.  The
+$filetime value is converted to seconds since Jan 1, 1970.  The
+$filemode is a bitmask like the mode returned by stat().
+
+=head1 CREDITS
+
+Based on lsparse.pl (from Lee McLoughlin's ftp mirror package) and
+Net::FTP's parse_dir (Graham Barr).
+
+=cut
+
+require Exporter;
+@ISA = qw(Exporter);
+
+@EXPORT = qw(parse_dir);
+
+use strict;
+
+use Carp ();
+use HTTP::Date qw(str2time);
+
+sub parse_dir ($;$$$)
+{
+   my($dir, $tz, $fstype, $error) = @_;
+
+   $fstype ||= 'unix';
+   $fstype = "File::Listing::" . lc $fstype;
+
+   my @args = $_[0];
+   push(@args, $tz) if(@_ >= 2);
+   push(@args, $error) if(@_ >= 4);
+
+   $fstype->parse(@args);
+}
+
+sub line { Carp::croak("Not implemented yet"); }
+sub init { } # Dummy sub
+
+sub file_mode ($)
+{
+    # This routine was originally borrowed from Graham Barr's
+    # Net::FTP package.
+
+    local $_ = shift;
+    my $mode = 0;
+    my($type,$ch);
+
+    s/^(.)// and $type = $1;
+
+    while (/(.)/g) {
+	$mode <<= 1;
+	$mode |= 1 if $1 ne "-" &&
+		      $1 ne 'S' &&
+		      $1 ne 't' &&
+		      $1 ne 'T';
+    }
+
+    $type eq "d" and $mode |= 0040000 or	# Directory
+      $type eq "l" and $mode |= 0120000 or	# Symbolic Link
+	$mode |= 0100000;			# Regular File
+
+    $mode |= 0004000 if /^...s....../i;
+    $mode |= 0002000 if /^......s.../i;
+    $mode |= 0001000 if /^.........t/i;
+
+    $mode;
+}
+
+sub parse
+{
+   my($pkg, $dir, $tz, $error) = @_;
+
+   # First let's try to determine what kind of dir parameter we have
+   # received.  We allow both listings, reference to arrays and
+   # file handles to read from.
+
+   if (ref($dir) eq 'ARRAY') {
+       # Already splitted up
+   } elsif (ref($dir) eq 'GLOB') {
+       # A file handle
+   } elsif (ref($dir)) {
+      Carp::croak("Illegal argument to parse_dir()");
+   } elsif ($dir =~ /^\*\w+(::\w+)+$/) {
+      # This scalar looks like a file handle, so we assume it is
+   } else {
+      # A normal scalar listing
+      $dir = [ split(/\n/, $dir) ];
+   }
+
+   $pkg->init();
+
+   my @files = ();
+   if (ref($dir) eq 'ARRAY') {
+       for (@$dir) {
+	   push(@files, $pkg->line($_, $tz, $error));
+       }
+   } else {
+       local($_);
+       while (<$dir>) {
+	   chomp;
+	   push(@files, $pkg->line($_, $tz, $error));
+       }
+   }
+   wantarray ? @files : \@files;
+}
+
+
+package File::Listing::unix;
+
+use HTTP::Date qw(str2time);
+
+# A place to remember current directory from last line parsed.
+use vars qw($curdir);
+no strict qw(vars);
+
+@ISA = qw(File::Listing);
+
+
+sub init
+{
+    $curdir = '';
+}
+
+sub line
+{
+    shift; # package name
+    local($_) = shift;
+    my($tz, $error) = @_;
+
+    s/\015//g;
+    #study;
+
+    my ($kind, $size, $date, $name);
+    if (($kind, $size, $date, $name) =
+	/^([\-FlrwxsStTdD]{10})                   # Type and permission bits
+	 .*                                       # Graps
+	 \D(\d+)                                  # File size
+	 \s+                                      # Some space
+	 (\w{3}\s+\d+\s+(?:\d{1,2}:\d{2}|\d{4}))  # Date
+	 \s+                                      # Some more space
+	 (.*)$                                    # File name
+	/x )
+
+    {
+	return if $name eq '.' || $name eq '..';
+	$name = "$curdir/$name" if length $curdir;
+	my $type = '?';
+	if ($kind =~ /^l/ && $name =~ /(.*) -> (.*)/ ) {
+	    $name = $1;
+	    $type = "l $2";
+	} elsif ($kind =~ /^[\-F]/) { # (hopefully) a regular file
+	    $type = 'f';
+	} elsif ($kind =~ /^[dD]/) {
+	    $type = 'd';
+	    $size = undef;  # Don't believe the reported size
+	}
+	return [$name, $type, $size, str2time($date, $tz), 
+              File::Listing::file_mode($kind)];
+
+    } elsif (/^(.+):$/ && !/^[dcbsp].*\s.*\s.*:$/ ) {
+	my $dir = $1;
+	return () if $dir eq '.';
+	$curdir = $dir;
+	return ();
+    } elsif (/^[Tt]otal\s+(\d+)$/ || /^\s*$/) {
+	return ();
+    } elsif (/not found/    || # OSF1, HPUX, and SunOS return
+             # "$file not found"
+             /No such file/ || # IRIX returns
+             # "UX:ls: ERROR: Cannot access $file: No such file or directory"
+                               # Solaris returns
+             # "$file: No such file or directory"
+             /cannot find/     # Windows NT returns
+             # "The system cannot find the path specified."
+             ) {
+	return () unless defined $error;
+	&$error($_) if ref($error) eq 'CODE';
+	warn "Error: $_\n" if $error eq 'warn';
+	return ();
+    } elsif ($_ eq '') {       # AIX, and Linux return nothing
+	return () unless defined $error;
+	&$error("No such file or directory") if ref($error) eq 'CODE';
+	warn "Warning: No such file or directory\n" if $error eq 'warn';
+	return ();
+    } else {
+        # parse failed, check if the dosftp parse understands it
+        return(File::Listing::dosftp->line($_,$tz,$error));
+    }
+
+}
+
+package File::Listing::dosftp;
+
+use HTTP::Date qw(str2time);
+
+# A place to remember current directory from last line parsed.
+use vars qw($curdir);
+no strict qw(vars);
+
+@ISA = qw(File::Listing);
+
+sub init
+{
+    $curdir = '';
+}
+
+sub line
+{
+    shift; # package name
+    local($_) = shift;
+    my($tz, $error) = @_;
+
+    s/\015//g;
+
+    my ($kind, $size, $date, $name);
+
+    # 02-05-96  10:48AM                 1415 src.slf
+    # 09-10-96  09:18AM       <DIR>          sl_util
+    if (($date,$size_or_dir,$name) =
+        /^(\d\d-\d\d-\d\d\s+\d\d:\d\d\wM)         # Date and time info
+         \s+                                      # Some space
+         (<\w{3}>|\d+)                            # Dir or Size
+         \s+                                      # Some more space
+         (.+)$                                    # File name
+        /x )
+    {
+	return if $name eq '.' || $name eq '..';
+	$name = "$curdir/$name" if length $curdir;
+	my $type = '?';
+	if ($size_or_dir eq '<DIR>') {
+	    $type = "d";
+            $size = ""; # directories have no size in the pc listing
+        } else {
+	    $type = 'f';
+            $size = $size_or_dir;
+	}
+	return [$name, $type, $size, str2time($date, $tz),
+              File::Listing::file_mode($kind)];
+
+    } else {
+	return () unless defined $error;
+	&$error($_) if ref($error) eq 'CODE';
+	warn "Can't parse: $_\n" if $error eq 'warn';
+	return ();
+    }
+
+}
+
+package File::Listing::vms;
+@File::Listing::unix::ISA = qw(File::Listing);
+
+package File::Listing::netware;
+@File::Listing::unix::ISA = qw(File::Listing);
+
+1;
Index: /main/tags/2.25/gsdl/packages/w3mir/libwww-perl-5.36/lib/HTTP/Cookies.pm
===================================================================
--- /main/tags/2.25/gsdl/packages/w3mir/libwww-perl-5.36/lib/HTTP/Cookies.pm	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/w3mir/libwww-perl-5.36/lib/HTTP/Cookies.pm	(revision 21064)
@@ -0,0 +1,725 @@
+package HTTP::Cookies;
+
+# Based on draft-ietf-http-state-man-mec-08.txt and
+# http://www.netscape.com/newsref/std/cookie_spec.html
+
+use strict;
+use HTTP::Date qw(str2time time2str);
+use HTTP::Headers::Util qw(split_header_words join_header_words);
+use LWP::Debug ();
+
+use vars qw($VERSION);
+$VERSION = sprintf("%d.%02d", q$Revision$ =~ /(\d+)\.(\d+)/);
+
+=head1 NAME
+
+HTTP::Cookies - Cookie storage and management
+
+=head1 SYNOPSIS
+
+ use HTTP::Cookies;
+ $cookie_jar = HTTP::Cookies->new;
+
+ $cookie_jar->add_cookie_header($request);
+ $cookie_jar->extract_cookies($response);
+
+=head1 DESCRIPTION
+
+Cookies are a general mechanism which server side connections can use
+to both store and retrieve information on the client side of the
+connection.  For more information about cookies referrer to
+<URL:http://www.netscape.com/newsref/std/cookie_spec.html> and
+<URL:http://www.cookiecentral.com/>.  This module also implements the
+new style cookies as described in I<draft-ietf-http-state-man-mec-08.txt>.
+The two variants of cookies is supposed to be able to coexist happily.
+
+Instances of the class I<HTTP::Cookies> are able to store a collection
+of Set-Cookie2: and Set-Cookie:-headers and is able to use this
+information to initialize Cookie-headers in I<HTTP::Request> objects.
+The state of the I<HTTP::Cookies> can be saved and restored from
+files.
+
+=head1 METHODS
+
+The following methods are provided:
+
+=over 4
+
+=cut
+
+# A HTTP::Cookies object is a hash.  The main attribute is the
+# COOKIES 3 level hash:  $self->{COOKIES}{$domain}{$path}{$key}.
+
+
+=item $cookie_jar = HTTP::Cookies->new;
+
+The constructor.  Takes hash style parameters.  The following
+parameters are recognized:
+
+  file:            name of the file to restore and save cookies to
+  autosave:        should we save during destruction (bool)
+  ignore_discard:  save even cookies that are requested to be discarded (bool)
+
+Future parameters might include (not yet implemented):
+
+  max_cookies               300
+  max_cookies_per_domain    20
+  max_cookie_size           4096
+
+  no_cookies   list of domain names that we never return cookies to
+
+=cut
+
+sub new
+{
+    my $class = shift;
+    my $self = bless {
+	COOKIES => {},
+    }, $class;
+    my %cnf = @_;
+    for (keys %cnf) {
+	$self->{lc($_)} = $cnf{$_};
+    }
+    $self->load;
+    $self;
+}
+
+
+=item $cookie_jar->add_cookie_header($request);
+
+The add_cookie_header() method will set the appropriate Cookie:-header
+for the I<HTTP::Request> object given as argument.  The $request must
+have a valid url() attribute before this method is called.
+
+=cut
+
+sub add_cookie_header
+{
+    my $self = shift;
+    my $request = shift || return;
+    my $url = $request->url;
+    my $domain = $url->host;
+    $domain = "$domain.local" unless $domain =~ /\./;
+    my $secure_request = ($url->scheme eq "https");
+    my $req_path = $url->epath;
+    my $req_port = $url->port;
+    my $now = time();
+    $self->_normalize_path($req_path) if $req_path =~ /%/;
+
+    my @cval;    # cookie values for the "Cookie" header
+    my $set_ver;
+
+    while (($domain =~ tr/././) >= 2 || # must be at least 2 dots
+           $domain =~ /\.local$/)
+    {
+
+        LWP::Debug::debug("Checking $domain for cookies");
+	my $cookies = $self->{COOKIES}{$domain};
+	next unless $cookies;
+
+	# Want to add cookies corresponding to the most specific paths
+	# first (i.e. longest path first)
+	my $path;
+	for $path (sort {length($b) <=> length($a) } keys %$cookies) {
+            LWP::Debug::debug("- checking cookie path=$path");
+	    if (index($req_path, $path) != 0) {
+	        LWP::Debug::debug("  path $path:$req_path does not fit");
+		next;
+	    }
+
+	    my($key,$array);
+	    while (($key,$array) = each %{$cookies->{$path}}) {
+		my($version,$val,$port,$path_spec,$secure,$expires) = @$array;
+	        LWP::Debug::debug(" - checking cookie $key=$val");
+		if ($secure && !$secure_request) {
+		    LWP::Debug::debug("   not a secure requests");
+		    next;
+		}
+		if ($expires && $expires < $now) {
+		    LWP::Debug::debug("   expired");
+		    next;
+		}
+		if ($port) {
+		    my $found;
+		    if ($port =~ s/^_//) {
+			# The correponding Set-Cookie attribute was empty
+			$found++ if $port eq $req_port;
+			$port = "";
+		    } else {
+			my $p;
+			for $p (split(/,/, $port)) {
+			    $found++, last if $p eq $req_port;
+			}
+		    }
+		    unless ($found) {
+		        LWP::Debug::debug("   port $port:$req_port does not fit");
+			next;
+		    }
+		}
+	        LWP::Debug::debug("   it's a match");
+
+		# set version number of cookie header.
+	        # XXX: What should it be if multiple matching
+                #      Set-Cookie headers have different versions themselves
+		if (!$set_ver++) {
+		    if ($version >= 1) {
+			push(@cval, "\$Version=$version");
+		    } else {
+			$request->header(Cookie2 => "\$Version=1");
+		    }
+		}
+
+		# do we need to quote the value
+		if ($val =~ /\W/ && $version) {
+		    $val =~ s/([\\\"])/\\$1/g;
+		    $val = qq("$val");
+		}
+
+		# and finally remember this cookie
+		push(@cval, "$key=$val");
+		if ($version >= 1) {
+		    push(@cval, qq(\$Path="$path"))     if $path_spec;
+		    push(@cval, qq(\$Domain="$domain")) if $domain =~ /^\./;
+		    if (defined $port) {
+			my $p = '$Port';
+			$p .= qq(="$port") if length $port;
+			push(@cval, $p);
+		    }
+		}
+
+	    }
+        }
+
+    } continue {
+	# Try with a more general domain:  www.sol.no ==> .sol.no
+	$domain =~ s/^\.?[^.]*//;
+    }
+
+    $request->header(Cookie => join("; ", @cval)) if @cval;
+
+    $request;
+}
+
+
+=item $cookie_jar->extract_cookies($response);
+
+The extract_cookies() method will look for Set-Cookie: and
+Set-Cookie2:-headers in the I<HTTP::Response> object passed as
+argument.  If some of these headers are found they are used to update
+the state of the $cookie_jar.
+
+=cut
+
+sub extract_cookies
+{
+    my $self = shift;
+    my $response = shift || return;
+    my @set = split_header_words($response->_header("Set-Cookie2"));
+    my $netscape_cookies;
+    unless (@set) {
+	@set = $response->_header("Set-Cookie");
+	return $response unless @set;
+	$netscape_cookies++;
+    }
+
+    my $url = $response->request->url;
+    my $req_host = $url->host;
+    $req_host = "$req_host.local" unless $req_host =~ /\./;
+    my $req_port = $url->port;
+    my $req_path = $url->epath;
+    $self->_normalize_path($req_path) if $req_path =~ /%/;
+    
+    if ($netscape_cookies) {
+	# The old Netscape cookie format for Set-Cookie
+        # http://www.netscape.com/newsref/std/cookie_spec.html
+	# can for instance contain an unquoted "," in the expires
+	# field, so we have to use this ad-hoc parser.
+	my $now = time();
+	my @old = @set;
+	@set = ();
+	my $set;
+	for $set (@old) {
+	    my @cur;
+	    my $param;
+	    my $expires;
+	    for $param (split(/\s*;\s*/, $set)) {
+		my($k,$v) = split(/\s*=\s*/, $param, 2);
+		#print "$k => $v\n";
+		my $lc = lc($k);
+		if ($lc eq "expires") {
+		    push(@cur, "Max-Age" => str2time($v) - $now);
+		    $expires++;
+		} else {
+		    push(@cur, $k => $v);
+		}
+	    }
+	    push(@cur, "Port" => $req_port);
+	    push(@cur, "Discard" => undef) unless $expires;
+	    push(@cur, "Version" => 0);
+	    push(@set, \@cur);
+	}
+    }
+
+  SET_COOKIE:
+    for my $set (@set) {
+	next unless @$set >= 2;
+
+	my $key = shift @$set;
+	my $val = shift @$set;
+
+        LWP::Debug::debug("Set cookie $key => $val");
+
+	my %hash;
+	while (@$set) {
+	    my $k = shift @$set;
+	    my $v = shift @$set;
+	    my $lc = lc($k);
+	    # don't loose case distinction for unknown fields
+	    $k = $lc if $lc =~ /^(?:discard|domain|max-age|
+                                    path|port|secure|version)$/x;
+	    if ($k eq "discard" || $k eq "secure") {
+		$v = 1 unless defined $v;
+	    }
+	    next if exists $hash{$k};  # only first value is signigicant
+	    $hash{$k} = $v;
+	};
+
+	my %orig_hash = %hash;
+	my $version   = delete $hash{version};
+	$version = 1 unless defined($version);
+	my $discard   = delete $hash{discard};
+	my $secure    = delete $hash{secure};
+	my $maxage    = delete $hash{'max-age'};
+
+	# Check domain
+	my $domain  = delete $hash{domain};
+	if (defined($domain) && $domain ne $req_host) {
+	    if ($domain !~ /\./ && $domain ne "local") {
+	        LWP::Debug::debug("Domain $domain contains no dot");
+		next SET_COOKIE;
+	    }
+	    $domain = ".$domain" unless $domain =~ /^\./;
+	    if ($domain =~ /\.\d+$/) {
+	        LWP::Debug::debug("IP-address $domain illeagal as domain");
+		next SET_COOKIE;
+	    }
+	    my $len = length($domain);
+	    unless (substr($req_host, -$len) eq $domain) {
+	        LWP::Debug::debug("Domain $domain does not match host $req_host");
+		next SET_COOKIE;
+	    }
+	    my $hostpre = substr($req_host, 0, length($req_host) - $len);
+	    if ($hostpre =~ /\./ && !$netscape_cookies) {
+	        LWP::Debug::debug("Host prefix contain a dot: $hostpre => $domain");
+		next SET_COOKIE;
+	    }
+	} else {
+	    $domain = $req_host;
+	}
+
+	my $path = delete $hash{path};
+	my $path_spec;
+	if (defined $path) {
+	    $path_spec++;
+	    $self->_normalize_path($path) if $path =~ /%/;
+	    if (!$netscape_cookies &&
+                substr($req_path, 0, length($path)) ne $path) {
+	        LWP::Debug::debug("Path $path is not a prefix of $req_path");
+		next SET_COOKIE;
+	    }
+	} else {
+	    $path = $req_path;
+	    $path =~ s,/[^/]*$,,;
+	    $path = "/" unless length($path);
+	}
+
+	my $port;
+	if (exists $hash{port}) {
+	    $port = delete $hash{port};
+	    if (defined $port) {
+		$port =~ s/\s+//g;
+		my $found;
+		for my $p (split(/,/, $port)) {
+		    unless ($p =~ /^\d+$/) {
+		      LWP::Debug::debug("Bad port $port (not numeric)");
+			next SET_COOKIE;
+		    }
+		    $found++ if $p eq $req_port;
+		}
+		unless ($found) {
+		    LWP::Debug::debug("Request port ($req_port) not found in $port");
+		    next SET_COOKIE;
+		}
+	    } else {
+		$port = "_$req_port";
+	    }
+	}
+	$self->set_cookie($version,$key,$val,$path,$domain,$port,$path_spec,$secure,$maxage,$discard, \%hash)
+	    if $self->set_cookie_ok(\%orig_hash);
+    }
+
+    $response;
+}
+
+sub set_cookie_ok { 1 };
+
+=item $cookie_jar->set_cookie($version, $key, $val, $path, $domain, $port, $path_spec, $secure, $maxage, $discard, \%rest)
+
+The set_cookie() method updates the state of the $cookie_jar.  The
+$key, $val, $domain, $port and $path arguments are strings.  The
+$path_spec, $secure, $discard arguments are boolean values. The $maxage
+value is a number indicating number of seconds that this cookie will
+live.  A value <= 0 will delete this cookie.  The %rest are a place
+for various other attributes like "Comment" and "CommentURL".
+
+=cut
+
+sub set_cookie
+{
+    my $self = shift;
+    my($version,
+       $key, $val, $path, $domain, $port,
+       $path_spec, $secure, $maxage, $discard, $rest) = @_;
+
+    # there must always be at least 2 dots in a domain
+    return $self if ($domain =~ tr/././) < 2 &&
+                     $domain !~ /\.local$/;
+
+    # path and key can not be empty (key can't start with '$')
+    return $self if !defined($path) || $path !~ m,^/, ||
+	            !defined($key)  || $key  !~ m,[^\$],;
+
+    # ensure legal port
+    if (defined $port) {
+	return $self unless $port =~ /^_?\d+(?:,\d+)*$/;
+    }
+
+    my $expires;
+    if (defined $maxage) {
+	if ($maxage <= 0) {
+	    delete $self->{COOKIES}{$domain}{$path}{$key};
+	    return $self;
+	}
+	$expires = time() + $maxage;
+    }
+    $version = 0 unless defined $version;
+
+    my @array = ($version, $val,$port,
+		 $path_spec,
+		 $secure, $expires, $discard);
+    push(@array, {%$rest}) if defined($rest) && %$rest;
+    # trim off undefined values at end
+    pop(@array) while !defined $array[-1];
+
+    $self->{COOKIES}{$domain}{$path}{$key} = \@array;
+    $self;
+}
+
+=item $cookie_jar->save( [$file] );
+
+Calling this method file save the state of the $cookie_jar to a file.
+The state can then be restored later using the load() method.  If a
+filename is not specified we will use the name specified during
+construction.  If the attribute I<ignore_discared> is set, then we
+will even save cookies that are marked to be discarded.
+
+The default is to save a sequence of "Set-Cookie3" lines.  The
+"Set-Cookie3" is a proprietary LWP format, not known to be compatible
+with any other browser.  The I<HTTP::Cookies::Netscape> sub-class can
+be used to save in a format compatible with Netscape.
+
+=cut
+
+sub save
+{
+    my $self = shift;
+    my $file = shift || $self->{'file'} || return;
+    local(*FILE);
+    open(FILE, ">$file") or die "Can't open $file: $!";
+    print FILE "#LWP-Cookies-1.0\n";
+    print FILE $self->as_string(!$self->{ignore_discard});
+    close(FILE);
+    1;
+}
+
+=item $cookie_jar->load( [$file] );
+
+This method will read the cookies from the file and add them to the
+$cookie_jar.  The file must be in the format written by the save()
+method.
+
+=cut
+
+sub load
+{
+    my $self = shift;
+    my $file = shift || $self->{'file'} || return;
+    local(*FILE, $_);
+    open(FILE, $file) or return;
+    my $magic = <FILE>;
+    unless ($magic =~ /^\#LWP-Cookies-(\d+\.\d+)/) {
+	warn "$file does not seem to contain cookies";
+	return;
+    }
+    while (<FILE>) {
+	next unless s/^Set-Cookie3:\s*//;
+	chomp;
+	my $cookie;
+	for $cookie (split_header_words($_)) {
+	    my($key,$val) = splice(@$cookie, 0, 2);
+	    my %hash;
+	    while (@$cookie) {
+		my $k = shift @$cookie;
+		my $v = shift @$cookie;
+		$hash{$k} = $v;
+	    }
+	    my $version   = delete $hash{version};
+	    my $path      = delete $hash{path};
+	    my $domain    = delete $hash{domain};
+	    my $port      = delete $hash{port};
+	    my $expires   = str2time(delete $hash{expires});
+
+	    my $path_spec = exists $hash{path_spec}; delete $hash{path_spec};
+	    my $secure    = exists $hash{secure};    delete $hash{secure};
+	    my $discard   = exists $hash{discard};   delete $hash{discard};
+
+	    my @array =	($version,$val,$port,
+			 $path_spec,$secure,$expires,$discard);
+	    push(@array, \%hash) if %hash;
+	    $self->{COOKIES}{$domain}{$path}{$key} = \@array;
+	}
+    }
+    close(FILE);
+    1;
+}
+
+=item $cookie_jar->revert;
+
+Will revert to the state of last save.
+
+=cut
+
+sub revert
+{
+    my $self = shift;
+    $self->clear->load;
+    $self;
+}
+
+=item $cookie_jar->clear( [$domain, [$path, [$key] ] ]);
+
+Invoking this method without arguments will empty the whole
+$cookie_jar.  If given a single argument only cookies belonging to
+that domain will be removed.  If given two arguments, cookies
+belonging to the specified path within that domain is removed.  If
+given three arguments, then the cookie with the specified key, path
+and domain is removed.
+
+=cut
+
+sub clear
+{
+    my $self = shift;
+    if (@_ == 0) {
+	$self->{COOKIES} = {};
+    } elsif (@_ == 1) {
+	delete $self->{COOKIES}{$_[0]};
+    } elsif (@_ == 2) {
+	delete $self->{COOKIES}{$_[0]}{$_[1]};
+    } elsif (@_ == 3) {
+	delete $self->{COOKIES}{$_[0]}{$_[1]}{$_[2]};
+    } else {
+	require Carp;
+        Carp::carp('Usage: $c->clear([domain [,path [,key]]])');
+    }
+    $self;
+}
+
+sub DESTROY
+{
+    my $self = shift;
+    $self->save if $self->{'autosave'};
+}
+
+
+=item $cookie_jar->scan( \&callback );
+
+The argument is a subroutine that will be invoked for each cookie
+stored within the $cookie_jar.  The subroutine will be invoked with
+the following arguments:
+
+  0  version
+  1  key
+  2  val
+  3  path
+  4  domain
+  5  port
+  6  path_spec
+  7  secure
+  8  expires
+  9  discard
+ 10  hash
+
+=cut
+
+sub scan
+{
+    my($self, $cb) = @_;
+    my($domain,$path,$key);
+    for $domain (sort keys %{$self->{COOKIES}}) {
+	for $path (sort keys %{$self->{COOKIES}{$domain}}) {
+	    for $key (sort keys %{$self->{COOKIES}{$domain}{$path}}) {
+		my($version,$val,$port,$path_spec,
+		   $secure,$expires,$discard,$rest) =
+		       @{$self->{COOKIES}{$domain}{$path}{$key}};
+		$rest = {} unless defined($rest);
+		&$cb($version,$key,$val,$path,$domain,$port,
+		     $path_spec,$secure,$expires,$discard,$rest);
+	    }
+	}
+    }
+}
+
+=item $cookie_jar->as_string( [$skip_discard] );
+
+The as_string() method will return the state of the $cookie_jar
+represented as a sequence of "Set-Cookie3" header lines separated by
+"\n".  If given a argument that is TRUE, it will not return lines for
+cookies with the I<Discard> attribute.
+
+=cut
+
+sub as_string
+{
+    my($self, $skip_discard) = @_;
+    my @res;
+    $self->scan(sub {
+	my($version,$key,$val,$path,$domain,$port,
+	   $path_spec,$secure,$expires,$discard,$rest) = @_;
+	return if $discard && $skip_discard;
+	my @h = ($key, $val);
+	push(@h, "path", $path);
+	push(@h, "domain" => $domain);
+	push(@h, "port" => $port) if defined $port;
+	push(@h, "path_spec" => undef) if $path_spec;
+	push(@h, "secure" => undef) if $secure;
+	push(@h, "expires" => HTTP::Date::time2isoz($expires)) if $expires;
+	push(@h, "discard" => undef) if $discard;
+	my $k;
+	for $k (sort keys %$rest) {
+	    push(@h, $k, $rest->{$k});
+	}
+	push(@h, "version" => $version);
+	push(@res, "Set-Cookie3: " . join_header_words(\@h));
+    });
+    join("\n", @res, "");
+}
+
+
+sub _normalize_path  # so that plain string compare can be used
+{
+    shift;  # $self
+    my $x;
+    $_[0] =~ s/%([0-9a-fA-F][0-9a-fA-F])/
+	         $x = uc($1);
+                 $x eq "2F" || $x eq "25" ? "%$x" :
+                                            pack("c", hex($x));
+              /eg;
+    $_[0] =~ s/([\0-\x20\x7f-\xff])/sprintf("%%%02X",ord($1))/eg;
+}
+
+
+
+=back
+
+=head1 SUB CLASSES
+
+We also provide a subclass called I<HTTP::Cookies::Netscape> which make
+cookie loading and saving compatible with Netscape cookie files.  You
+should be able to have LWP share Netscape's cookies by constructing
+your $cookie_jar like this:
+
+ $cookie_jar = HTTP::Cookies::Netscape->new(
+                   File     => "$ENV{HOME}/.netscape/cookies",
+                   AutoSave => 1,
+               );
+
+Please note that the Netscape cookie file format is not able to store
+all the information available in the Set-Cookie2 headers, so you will
+probably loose some information if you save using this format.
+
+=cut
+
+package HTTP::Cookies::Netscape;
+
+use vars qw(@ISA);
+@ISA=qw(HTTP::Cookies);
+
+sub load
+{
+    my($self, $file) = @_;
+    $file ||= $self->{'file'} || return;
+    local(*FILE, $_);
+    my @cookies;
+    open(FILE, $file) || return;
+    my $magic = <FILE>;
+    unless ($magic =~ /^\# Netscape HTTP Cookie File/) {
+	warn "$file does not look like a netscape cookies file" if $^W;
+	close(FILE);
+	return;
+    }
+    my $now = time();
+    while (<FILE>) {
+	next if /^\s*\#/;
+	next if /^\s*$/;
+	chomp;
+	my($domain,$bool1,$path,$secure, $expires,$key,$val) = split(/\t/, $_);
+	$secure = ($secure eq "TRUE");
+	$self->set_cookie(undef,$key,$val,$path,$domain,undef,
+			  0,$secure,$expires-$now, 0);
+    }
+    close(FILE);
+    1;
+}
+
+sub save
+{
+    my($self, $file) = @_;
+    $file ||= $self->{'file'} || return;
+    local(*FILE, $_);
+    open(FILE, ">$file") || return;
+
+    print FILE <<EOT;
+# Netscape HTTP Cookie File
+# http://www.netscape.com/newsref/std/cookie_spec.html
+# This is a generated file!  Do not edit.
+
+EOT
+
+    my $now = time;
+    $self->scan(sub {
+	my($version,$key,$val,$path,$domain,$port,
+	   $path_spec,$secure,$expires,$discard,$rest) = @_;
+	return if $discard && !$self->{ignore_discard};
+	$expires ||= 0;
+	return if $now > $expires;
+	$secure = $secure ? "TRUE" : "FALSE";
+	my $bool = $domain =~ /^\./ ? "TRUE" : "FALSE";
+	print FILE join("\t", $domain, $bool, $path, $secure, $expires, $key, $val), "\n";
+    });
+    close(FILE);
+    1;
+}
+
+1;
+
+__END__
+
+=head1 COPYRIGHT
+
+Copyright 1997, Gisle Aas
+
+This library is free software; you can redistribute it and/or
+modify it under the same terms as Perl itself.
+
+=cut
Index: /main/tags/2.25/gsdl/packages/w3mir/libwww-perl-5.36/lib/HTTP/Daemon.pm
===================================================================
--- /main/tags/2.25/gsdl/packages/w3mir/libwww-perl-5.36/lib/HTTP/Daemon.pm	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/w3mir/libwww-perl-5.36/lib/HTTP/Daemon.pm	(revision 21064)
@@ -0,0 +1,805 @@
+# $Id$
+#
+
+use strict;
+
+package HTTP::Daemon;
+
+=head1 NAME
+
+HTTP::Daemon - a simple http server class
+
+=head1 SYNOPSIS
+
+  use HTTP::Daemon;
+  use HTTP::Status;
+
+  my $d = new HTTP::Daemon;
+  print "Please contact me at: <URL:", $d->url, ">\n";
+  while (my $c = $d->accept) {
+      while (my $r = $c->get_request) {
+	  if ($r->method eq 'GET' and $r->url->path eq "/xyzzy") {
+              # remember, this is *not* recommened practice :-)
+	      $c->send_file_response("/etc/passwd");
+	  } else {
+	      $c->send_error(RC_FORBIDDEN)
+	  }
+      }
+      $c->close;
+      undef($c);
+  }
+
+=head1 DESCRIPTION
+
+Instances of the I<HTTP::Daemon> class are HTTP/1.1 servers that
+listens on a socket for incoming requests. The I<HTTP::Daemon> is a
+sub-class of I<IO::Socket::INET>, so you can do socket operations
+directly on it too.
+
+The accept() method will return when a connection from a client is
+available. The returned value will be a reference to a object of the
+I<HTTP::Daemon::ClientConn> class which is another I<IO::Socket::INET>
+subclass. Calling the get_request() method on this object will read
+data from the client and return an I<HTTP::Request> object reference.
+
+This HTTP daemon does not fork(2) for you.  Your application, i.e. the
+user of the I<HTTP::Daemon> is reponsible for forking if that is
+desirable.  Also note that the user is responsible for generating
+responses that conforms to the HTTP/1.1 protocol.  The
+I<HTTP::Daemon::ClientConn> provide some methods that make this easier.
+
+=head1 METHODS
+
+The following is a list of methods that are new (or enhanced) relative
+to the I<IO::Socket::INET> base class.
+
+=over 4
+
+=cut
+
+
+use vars qw($VERSION @ISA $PROTO $DEBUG);
+
+$VERSION = sprintf("%d.%02d", q$Revision$ =~ /(\d+)\.(\d+)/);
+
+use IO::Socket ();
+@ISA=qw(IO::Socket::INET);
+
+$PROTO = "HTTP/1.1";
+
+=item $d = new HTTP::Daemon
+
+The object constructor takes the same parameters as the
+I<IO::Socket::INET> constructor.  It can be called without specifying
+any parameters. The daemon will then set up a listen queue of 5
+connections and allocate some random port number.  A server that want
+to bind to some specific address on the standard HTTP port will be
+constructed like this:
+
+  $d = new HTTP::Daemon
+        LocalAddr => 'www.someplace.com',
+        LocalPort => 80;
+
+=cut
+
+sub new
+{
+    my($class, %args) = @_;
+    $args{Listen} ||= 5;
+    $args{Proto}  ||= 'tcp';
+    my $self = $class->SUPER::new(%args);
+    return undef unless $self;
+
+    my $host = $args{LocalAddr};
+    unless ($host) {
+	require Sys::Hostname;
+	$host = Sys::Hostname::hostname();
+    }
+    ${*$self}{'httpd_server_name'} = $host;
+    $self;
+}
+
+
+=item $c = $d->accept([$pkg])
+
+Same as I<IO::Socket::accept> but will return an
+I<HTTP::Daemon::ClientConn> reference by default.  It will return
+undef if you have specified a timeout and no connection is made within
+that time.
+
+=cut
+
+sub accept
+{
+    my $self = shift;
+    my $pkg = shift || "HTTP::Daemon::ClientConn";
+    my $sock = $self->SUPER::accept($pkg);
+    ${*$sock}{'httpd_daemon'} = $self if $sock;
+    $sock;
+}
+
+
+=item $d->url
+
+Returns a URL string that can be used to access the server root.
+
+=cut
+
+sub url
+{
+    my $self = shift;
+    my $url = "http://";
+    $url .= ${*$self}{'httpd_server_name'};
+    my $port = $self->sockport;
+    $url .= ":$port" if $port != 80;
+    $url .= "/";
+    $url;
+}
+
+
+=item $d->product_tokens
+
+Returns the name that this server will use to identify itself.  This
+is the string that is sent with the I<Server> response header.  The
+main reason to have this method is that subclasses can override it if
+they want to use another product name.
+
+=cut
+
+sub product_tokens
+{
+    "libwww-perl-daemon/$HTTP::Daemon::VERSION";
+}
+
+
+package HTTP::Daemon::ClientConn;
+
+use vars qw(@ISA $DEBUG);
+use IO::Socket ();
+@ISA=qw(IO::Socket::INET);
+*DEBUG = \$HTTP::Daemon::DEBUG;
+
+use HTTP::Request  ();
+use HTTP::Response ();
+use HTTP::Status;
+use HTTP::Date qw(time2str);
+use URI::URL qw(url);
+use LWP::MediaTypes qw(guess_media_type);
+use Carp ();
+
+my $CRLF = "\015\012";   # "\r\n" is not portable
+my $HTTP_1_0 = _http_version("HTTP/1.0");
+my $HTTP_1_1 = _http_version("HTTP/1.1");
+
+=back
+
+The I<HTTP::Daemon::ClientConn> is also a I<IO::Socket::INET>
+subclass. Instances of this class are returned by the accept() method
+of the I<HTTP::Daemon>.  The following additional methods are
+provided:
+
+=over 4
+
+=item $c->get_request([$headers_only])
+
+This method will read data from the client and turn it into a
+I<HTTP::Request> object which is then returned.  It returns C<undef>
+if reading of the request fails.  If it fails, then the
+I<HTTP::Daemon::ClientConn> object ($c) should be discarded, and you
+should not call this method again.  The $c->reason method might give
+you some information on why $c->get_request returned C<undef>.
+
+The $c->get_request method support HTTP/1.1 request content bodies,
+including I<chunked> transfer encoding with footer and self delimiting
+I<multipart/*> content types.
+
+The $c->get_request method will normally not return until the whole
+request has been received from the client.  This might not be what you
+want if the request is an upload of a multi-mega-byte file (and with
+chunked transfer encoding HTTP can even support infinite request
+messages - uploading live audio for instance).  If you pass a TRUE
+value as the $headers_only argument, then $c->get_request will return
+immediately after parsing the request headers and you are responsible
+for reading the rest of the request content (and if you are going to
+call $c->get_request again on the same connection you better read the
+correct number of bytes).
+
+=cut
+
+sub get_request
+{
+    my($self, $only_headers) = @_;
+    if (${*$self}{'httpd_nomore'}) {
+        $self->reason("No more requests from this connection");
+	return;
+    }
+
+    $self->reason("");
+    my $buf = ${*$self}{'httpd_rbuf'};
+    $buf = "" unless defined $buf;
+    
+    my $timeout = $ {*$self}{'io_socket_timeout'};
+    my $fdset = "";
+    vec($fdset, $self->fileno, 1) = 1;
+    local($_);
+
+  READ_HEADER:
+    while (1) {
+	# loop until we have the whole header in $buf
+	$buf =~ s/^(?:\015?\012)+//;  # ignore leading blank lines
+	if ($buf =~ /\012/) {  # potential, has at least one line
+	    if ($buf =~ /^\w+[^\012]+HTTP\/\d+\.\d+\015?\012/) {
+		if ($buf =~ /\015?\012\015?\012/) {
+		    last READ_HEADER;  # we have it
+		} elsif (length($buf) > 16*1024) {
+		    $self->send_error(413); # REQUEST_ENTITY_TOO_LARGE
+		    $self->reason("Very long header");
+		    return;
+		}
+	    } else {
+		last READ_HEADER;  # HTTP/0.9 client
+	    }
+	} elsif (length($buf) > 16*1024) {
+	    $self->send_error(414); # REQUEST_URI_TOO_LARGE
+	    $self->reason("Very long first line");
+	    return;
+	}
+	print STDERR "Need more data for complete header\n" if $DEBUG;
+	return unless $self->_need_more($buf, $timeout, $fdset);
+    }
+    if ($buf !~ s/^(\w+)[ \t]+(\S+)(?:[ \t]+(HTTP\/\d+\.\d+))?[^\012]*\012//) {
+	$self->send_error(400);  # BAD_REQUEST
+	$self->reason("Bad request line");
+	return;
+    }
+    my $proto = $3 || "HTTP/0.9";
+    my $r = HTTP::Request->new($1, url($2, $self->daemon->url));
+    $r->protocol($proto);
+    ${*$self}{'httpd_client_proto'} = $proto = _http_version($proto);
+
+    if ($proto >= $HTTP_1_0) {
+	# we expect to find some headers
+	my($key, $val);
+      HEADER:
+	while ($buf =~ s/^([^\012]*)\012//) {
+	    $_ = $1;
+	    s/\015$//;
+	    if (/^([\w\-]+)\s*:\s*(.*)/) {
+		$r->push_header($key, $val) if $key;
+		($key, $val) = ($1, $2);
+	    } elsif (/^\s+(.*)/) {
+		$val .= " $1";
+	    } else {
+		last HEADER;
+	    }
+	}
+	$r->push_header($key, $val) if $key;
+    }
+
+    my $conn = $r->header('Connection');
+    if ($proto >= $HTTP_1_1) {
+	${*$self}{'httpd_nomore'}++ if $conn && lc($conn) =~ /\bclose\b/;
+    } else {
+	${*$self}{'httpd_nomore'}++ unless $conn &&
+                                           lc($conn) =~ /\bkeep-alive\b/;
+    }
+
+    if ($only_headers) {
+	${*$self}{'httpd_rbuf'} = $buf;
+        return $r;
+    }
+
+    # Find out how much content to read
+    my $te  = $r->header('Transfer-Encoding');
+    my $ct  = $r->header('Content-Type');
+    my $len = $r->header('Content-Length');
+
+    if ($te && lc($te) eq 'chunked') {
+	# Handle chunked transfer encoding
+	my $body = "";
+      CHUNK:
+	while (1) {
+	    print STDERR "Chunked\n" if $DEBUG;
+	    if ($buf =~ s/^([^\012]*)\012//) {
+		my $chunk_head = $1;
+		unless ($chunk_head =~ /^([0-9A-Fa-f]+)/) {
+		    $self->send_error(400);
+		    $self->reason("Bad chunk header $chunk_head");
+		    return;
+		}
+		my $size = hex($1);
+		last CHUNK if $size == 0;
+
+		my $missing = $size - length($buf) + 2; # 2=CRLF at chunk end
+		# must read until we have a complete chunk
+		while ($missing > 0) {
+		    print STDERR "Need $missing more bytes\n" if $DEBUG;
+		    my $n = $self->_need_more($buf, $timeout, $fdset);
+		    return unless $n;
+		    $missing -= $n;
+		}
+		$body .= substr($buf, 0, $size);
+		substr($buf, 0, $size+2) = '';
+
+	    } else {
+		# need more data in order to have a complete chunk header
+		return unless $self->_need_more($buf, $timeout, $fdset);
+	    }
+	}
+	$r->content($body);
+
+	# pretend it was a normal entity body
+	$r->remove_header('Transfer-Encoding');
+	$r->header('Content-Length', length($body));
+
+	my($key, $val);
+      FOOTER:
+	while (1) {
+	    if ($buf !~ /\012/) {
+		# need at least one line to look at
+		return unless $self->_need_more($buf, $timeout, $fdset);
+	    } else {
+		$buf =~ s/^([^\012]*)\012//;
+		$_ = $1;
+		s/\015$//;
+		if (/^([\w\-]+)\s*:\s*(.*)/) {
+		    $r->push_header($key, $val) if $key;
+		    ($key, $val) = ($1, $2);
+		} elsif (/^\s+(.*)/) {
+		    $val .= " $1";
+		} elsif (!length) {
+		    last FOOTER;
+		} else {
+		    $self->reason("Bad footer syntax");
+		    return;
+		}
+	    }
+	}
+	$r->push_header($key, $val) if $key;
+
+    } elsif ($te) {
+	$self->send_error(501); 	# Unknown transfer encoding
+	$self->reason("Unknown transfer encoding '$te'");
+	return;
+
+    } elsif ($ct && lc($ct) =~ m/^multipart\/\w+\s*;.*boundary\s*=\s*(\w+)/) {
+	# Handle multipart content type
+	my $boundary = "$CRLF--$1--$CRLF";
+	my $index;
+	while (1) {
+	    $index = index($buf, $boundary);
+	    last if $index >= 0;
+	    # end marker not yet found
+	    return unless $self->_need_more($buf, $timeout, $fdset);
+	}
+	$index += length($boundary);
+	$r->content(substr($buf, 0, $index));
+	substr($buf, 0, $index) = '';
+
+    } elsif ($len) {
+	# Plain body specified by "Content-Length"
+	my $missing = $len - length($buf);
+	while ($missing > 0) {
+	    print "Need $missing more bytes of content\n" if $DEBUG;
+	    my $n = $self->_need_more($buf, $timeout, $fdset);
+	    return unless $n;
+	    $missing -= $n;
+	}
+	if (length($buf) > $len) {
+	    $r->content(substr($buf,0,$len));
+	    substr($buf, 0, $len) = '';
+	} else {
+	    $r->content($buf);
+	    $buf='';
+	}
+    }
+    ${*$self}{'httpd_rbuf'} = $buf;
+
+    $r;
+}
+
+sub _need_more
+{
+    my $self = shift;
+    #my($buf,$timeout,$fdset) = @_;
+    if ($_[1]) {
+	my($timeout, $fdset) = @_[1,2];
+	print STDERR "select(,,,$timeout)\n" if $DEBUG;
+	my $n = select($fdset,undef,undef,$timeout);
+	unless ($n) {
+	    $self->reason(defined($n) ? "Timeout" : "select: $!");
+	    return;
+	}
+    }
+    print STDERR "sysread()\n" if $DEBUG;
+    my $n = sysread($self, $_[0], 2048, length($_[0]));
+    $self->reason(defined($n) ? "Client closed" : "sysread: $!") unless $n;
+    $n;
+}
+
+=item $c->read_buffer([$new_value])
+
+Bytes read by $c->get_request, but not used are placed in the I<read
+buffer>.  The next time $c->get_request is called it will consume the
+bytes in this buffer before reading more data from the network
+connection itself.  The read buffer is invalid after $c->get_request
+has returned an undefined value.
+
+If you handle the reading of the request content yourself you need to
+empty this buffer before you read more and you need to place
+unconsumed bytes here.  You also need this buffer if you implement
+services like I<101 Switching Protocols>.
+
+This method always return the old buffer content and can optionally
+update the buffer content if you pass it an argument.
+
+=cut
+
+sub read_buffer
+{
+    my $self = shift;
+    my $old = ${*$self}{'httpd_rbuf'};
+    if (@_) {
+	${*$self}{'httpd_rbuf'} = shift;
+    }
+    $old;
+}
+
+
+=item $c->reason
+
+When $c->get_request returns C<undef> you can obtain a short string
+describing why it happened by calling $c->reason.
+
+=cut
+
+sub reason
+{
+    my $self = shift;
+    my $old = ${*$self}{'httpd_reason'};
+    if (@_) {
+        ${*$self}{'httpd_reason'} = shift;
+    }
+    $old;
+}
+
+
+=item $c->proto_ge($proto)
+
+Returns TRUE if the client announced a protocol with version number
+greater or equal to the given argument.  The $proto argument can be a
+string like "HTTP/1.1" or just "1.1".
+
+=cut
+
+sub proto_ge
+{
+    my $self = shift;
+    ${*$self}{'httpd_client_proto'} >= _http_version(shift);
+}
+
+sub _http_version
+{
+    local($_) = shift;
+    return 0 unless m,^(?:HTTP/)?(\d+)\.(\d+)$,i;
+    $1 * 1000 + $2;
+}
+
+=item $c->antique_client
+
+Returns TRUE if the client speaks the HTTP/0.9 protocol.  No status
+code and no headers should be returned to such a client.  This should
+be the same as !$c->proto_ge("HTTP/1.0").
+
+=cut
+
+sub antique_client
+{
+    my $self = shift;
+    ${*$self}{'httpd_client_proto'} < $HTTP_1_0;
+}
+
+
+=item $c->force_last_request
+
+Make sure that $c->get_request will not try to read more requests off
+this connection.  If you generate a response that is not self
+delimiting, then you should signal this fact by calling this method.
+
+This attribute is turned on automatically if the client announce
+protocol HTTP/1.0 or worse and does not include a "Connection:
+Keep-Alive" header.  It is also turned on automatically when HTTP/1.1
+or better clients send the "Connection: close" request header.
+
+=cut
+
+sub force_last_request
+{
+    my $self = shift;
+    ${*$self}{'httpd_nomore'}++;
+}
+
+
+=item $c->send_status_line( [$code, [$mess, [$proto]]] )
+
+Sends the status line back to the client.  If $code is omitted 200 is
+assumed.  If $mess is omitted, then a message corresponding to $code
+is inserted.  If $proto is missing the content of the
+$HTTP::Daemon::PROTO variable is used.
+
+=cut
+
+sub send_status_line
+{
+    my($self, $status, $message, $proto) = @_;
+    return if $self->antique_client;
+    $status  ||= RC_OK;
+    $message ||= status_message($status) || "";
+    $proto   ||= $HTTP::Daemon::PROTO || "HTTP/1.1";
+    print $self "$proto $status $message$CRLF";
+}
+
+=item $c->send_crlf
+
+Send the CRLF sequence to the client.
+
+=cut
+
+
+sub send_crlf
+{
+    my $self = shift;
+    print $self $CRLF;
+}
+
+
+=item $c->send_basic_header( [$code, [$mess, [$proto]]] )
+
+Sends the status line and the "Date:" and "Server:" headers back to
+the client.  This header is assumed to be continued and does not end
+with an empty CRLF line.
+
+=cut
+
+sub send_basic_header
+{
+    my $self = shift;
+    return if $self->antique_client;
+    $self->send_status_line(@_);
+    print $self "Date: ", time2str(time), $CRLF;
+    my $product = $self->daemon->product_tokens;
+    print $self "Server: $product$CRLF" if $product;
+}
+
+
+=item $c->send_response( [$res] )
+
+Takes a I<HTTP::Response> object as parameter and write it back to the
+client as the response.  We try hard to make sure that the response is
+self delimiting so that the connection can stay persistent for further
+request/response exchanges.
+
+The content attribute of the I<HTTP::Response> object can be a normal
+string or a subroutine reference.  If it is a subroutine, then
+whatever this callback routine returns will be written back to the
+client as the response content.  The routine will be called until it
+return an undefined or empty value.  If the client is HTTP/1.1 aware
+then we will use the chunked transfer encoding for the response.
+
+=cut
+
+sub send_response
+{
+    my $self = shift;
+    my $res = shift;
+    if (!ref $res) {
+	$res ||= RC_OK;
+	$res = HTTP::Response->new($res, @_);
+    }
+    my $content = $res->content;
+    my $chunked;
+    unless ($self->antique_client) {
+	my $code = $res->code;
+	$self->send_basic_header($code, $res->message, $res->protocol);
+	if ($code =~ /^(1\d\d|[23]04)$/) {
+	    # make sure content is empty
+	    $res->remove_header("Content-Length");
+	    $content = "";
+	} elsif ($res->request && $res->request->method eq "HEAD") {
+	    # probably OK
+	} elsif (ref($content) eq "CODE") {
+	    if ($self->proto_ge("HTTP/1.1")) {
+		$res->push_header("Transfer-Encoding" => "chunked");
+		$chunked++;
+	    } else {
+		$self->force_last_request;
+	    }
+	} elsif (length($content)) {
+	    $res->header("Content-Length" => length($content));
+	} else {
+	    $self->force_last_request;
+	}
+	print $self $res->headers_as_string($CRLF);
+	print $self $CRLF;  # separates headers and content
+    }
+    if (ref($content) eq "CODE") {
+	while (1) {
+	    my $chunk = &$content();
+	    last unless defined($chunk) && length($chunk);
+	    if ($chunked) {
+		printf $self "%x%s%s%s", length($chunk), $CRLF, $chunk, $CRLF;
+	    } else {
+		print $self $chunk;
+	    }
+	}
+	print $self "0$CRLF$CRLF" if $chunked;  # no trailers either
+    } elsif (length $content) {
+	print $self $content;
+    }
+}
+
+
+=item $c->send_redirect( $loc, [$code, [$entity_body]] )
+
+Sends a redirect response back to the client.  The location ($loc) can
+be an absolute or a relative URL. The $code must be one the redirect
+status codes, and it defaults to "301 Moved Permanently"
+
+=cut
+
+sub send_redirect
+{
+    my($self, $loc, $status, $content) = @_;
+    $status ||= RC_MOVED_PERMANENTLY;
+    Carp::croak("Status '$status' is not redirect") unless is_redirect($status);
+    $self->send_basic_header($status);
+    $loc = url($loc, $self->daemon->url) unless ref($loc);
+    $loc = $loc->abs;
+    print $self "Location: $loc$CRLF";
+    if ($content) {
+	my $ct = $content =~ /^\s*</ ? "text/html" : "text/plain";
+	print $self "Content-Type: $ct$CRLF";
+    }
+    print $self $CRLF;
+    print $self $content if $content;
+    $self->force_last_request;  # no use keeping the connection open
+}
+
+
+=item $c->send_error( [$code, [$error_message]] )
+
+Send an error response back to the client.  If the $code is missing a
+"Bad Request" error is reported.  The $error_message is a string that
+is incorporated in the body of the HTML entity body.
+
+=cut
+
+sub send_error
+{
+    my($self, $status, $error) = @_;
+    $status ||= RC_BAD_REQUEST;
+    Carp::croak("Status '$status' is not an error") unless is_error($status);
+    my $mess = status_message($status);
+    $error  ||= "";
+    $mess = <<EOT;
+<title>$status $mess</title>
+<h1>$status $mess</h1>
+$error
+EOT
+    unless ($self->antique_client) {
+        $self->send_basic_header($status);
+        print $self "Content-Type: text/html$CRLF";
+	print $self "Content-Length: " . length($mess) . $CRLF;
+        print $self $CRLF;
+    }
+    print $self $mess;
+    $status;
+}
+
+
+=item $c->send_file_response($filename)
+
+Send back a response with the specified $filename as content.  If the
+file happen to be a directory we will try to generate an HTML index
+of it.
+
+=cut
+
+sub send_file_response
+{
+    my($self, $file) = @_;
+    if (-d $file) {
+	$self->send_dir($file);
+    } elsif (-f _) {
+	# plain file
+	local(*F);
+	sysopen(F, $file, 0) or 
+	  return $self->send_error(RC_FORBIDDEN);
+	my($ct,$ce) = guess_media_type($file);
+	my($size,$mtime) = (stat _)[7,9];
+	unless ($self->antique_client) {
+	    $self->send_basic_header;
+	    print $self "Content-Type: $ct$CRLF";
+	    print $self "Content-Encoding: $ce$CRLF" if $ce;
+	    print $self "Content-Length: $size$CRLF" if $size;
+	    print $self "Last-Modified: ", time2str($mtime), "$CRLF" if $mtime;
+	    print $self $CRLF;
+	}
+	$self->send_file(\*F);
+	return RC_OK;
+    } else {
+	$self->send_error(RC_NOT_FOUND);
+    }
+}
+
+
+sub send_dir
+{
+    my($self, $dir) = @_;
+    $self->send_error(RC_NOT_FOUND) unless -d $dir;
+    $self->send_error(RC_NOT_IMPLEMENTED);
+}
+
+
+=item $c->send_file($fd);
+
+Copies the file back to the client.  The file can be a string (which
+will be interpreted as a filename) or a reference to an I<IO::Handle>
+or glob.
+
+=cut
+
+sub send_file
+{
+    my($self, $file) = @_;
+    my $opened = 0;
+    if (!ref($file)) {
+	local(*F);
+	open(F, $file) || return undef;
+	binmode(F);
+	$file = \*F;
+	$opened++;
+    }
+    my $cnt = 0;
+    my $buf = "";
+    my $n;
+    while ($n = sysread($file, $buf, 8*1024)) {
+	last if !$n;
+	$cnt += $n;
+	print $self $buf;
+    }
+    close($file) if $opened;
+    $cnt;
+}
+
+
+=item $c->daemon
+
+Return a reference to the corresponding I<HTTP::Daemon> object.
+
+=cut
+
+sub daemon
+{
+    my $self = shift;
+    ${*$self}{'httpd_daemon'};
+}
+
+=back
+
+=head1 SEE ALSO
+
+RFC 2068
+
+L<IO::Socket>, L<Apache>
+
+=head1 COPYRIGHT
+
+Copyright 1996-1998, Gisle Aas
+
+This library is free software; you can redistribute it and/or
+modify it under the same terms as Perl itself.
+
+=cut
+
+1;
Index: /main/tags/2.25/gsdl/packages/w3mir/libwww-perl-5.36/lib/HTTP/Date.pm
===================================================================
--- /main/tags/2.25/gsdl/packages/w3mir/libwww-perl-5.36/lib/HTTP/Date.pm	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/w3mir/libwww-perl-5.36/lib/HTTP/Date.pm	(revision 21064)
@@ -0,0 +1,330 @@
+# $Id$
+#
+package HTTP::Date;
+
+=head1 NAME
+
+HTTP::Date - date conversion routines
+
+=head1 SYNOPSIS
+
+ use HTTP::Date;
+
+ $string = time2str($time);    # Format as GMT ASCII time
+ $time = str2time($string);    # convert ASCII date to machine time
+
+=head1 DESCRIPTION
+
+This module provides two functions that deal with the HTTP date
+format.  The following functions are provided:
+
+=over 4
+
+=item time2str([$time])
+
+The time2str() function converts a machine time (seconds since epoch)
+to a string.  If the function is called without an argument, it will
+use the current time.
+
+The string returned is in the format defined by the HTTP/1.0
+specification.  This is a fixed length subset of the format defined by
+RFC 1123, represented in Universal Time (GMT).  An example of this
+format is:
+
+   Thu, 03 Feb 1994 17:09:00 GMT
+
+=item str2time($str [, $zone])
+
+The str2time() function converts a string to machine time.  It returns
+C<undef> if the format is unrecognized, or the year is not between 1970
+and 2038.  The function is able to parse the following formats:
+
+ "Wed, 09 Feb 1994 22:23:32 GMT"       -- HTTP format
+ "Thu Feb  3 17:03:55 GMT 1994"        -- ctime(3) format
+ "Thu Feb  3 00:00:00 1994",           -- ANSI C asctime() format
+ "Tuesday, 08-Feb-94 14:15:29 GMT"     -- old rfc850 HTTP format
+ "Tuesday, 08-Feb-1994 14:15:29 GMT"   -- broken rfc850 HTTP format
+
+ "03/Feb/1994:17:03:55 -0700"   -- common logfile format
+ "09 Feb 1994 22:23:32 GMT"     -- HTTP format (no weekday)
+ "08-Feb-94 14:15:29 GMT"       -- rfc850 format (no weekday)
+ "08-Feb-1994 14:15:29 GMT"     -- broken rfc850 format (no weekday)
+
+ "1994-02-03 14:15:29 -0100"    -- ISO 8601 format
+ "1994-02-03 14:15:29"          -- zone is optional
+ "1994-02-03"                   -- only date
+ "1994-02-03T14:15:29"          -- Use T as separator
+ "19940203T141529Z"             -- ISO 8601 compact format
+ "19940203"                     -- only date
+
+ "08-Feb-94"         -- old rfc850 HTTP format    (no weekday, no time)
+ "08-Feb-1994"       -- broken rfc850 HTTP format (no weekday, no time)
+ "09 Feb 1994"       -- proposed new HTTP format  (no weekday, no time)
+ "03/Feb/1994"       -- common logfile format     (no time, no offset)
+
+ "Feb  3  1994"      -- Unix 'ls -l' format
+ "Feb  3 17:03"      -- Unix 'ls -l' format
+
+ "11-15-96  03:52PM" -- Windows 'dir' format
+
+The parser ignores leading and trailing whitespace.  It also allow the
+seconds to be missing and the month to be numerical in most formats.
+
+The str2time() function takes an optional second argument that
+specifies the default time zone to use when converting the date.  This
+zone specification should be numerical (like "-0800" or "+0100") or
+"GMT".  This parameter is ignored if the zone is specified in the date
+string itself.  It this parameter is missing, and the date string
+format does not contain any zone specification then the local time
+zone is assumed.
+
+If the year is missing, then we assume that the date is the first
+matching date I<before> current time.
+
+=back
+
+=head1 BUGS
+
+Non-numerical time zones (like MET, PST) are all treated like GMT.
+Do not use them.  HTTP does not use them.
+
+The str2time() function has been told how to parse far too many
+formats.  This makes the module name misleading. To be sure it is
+really misleading you can also import the time2iso() and time2isoz()
+functions.  They work like time2str() but produce ISO-8601 formated
+strings (YYYY-MM-DD hh:mm:ss).
+
+=head1 COPYRIGHT
+
+Copyright 1995-1997, Gisle Aas
+
+This library is free software; you can redistribute it and/or
+modify it under the same terms as Perl itself.
+
+=cut
+
+
+$VERSION = sprintf("%d.%02d", q$Revision$ =~ /(\d+)\.(\d+)/);
+sub Version { $VERSION; }
+
+require 5.002;
+require Exporter;
+@ISA = qw(Exporter);
+@EXPORT = qw(time2str str2time);
+@EXPORT_OK = qw(time2iso time2isoz);
+
+use Time::Local ();
+
+use strict;
+use vars qw(@DoW @MoY %MoY);
+
+#@DoW = qw(Sunday Monday Tuesday Wednesday Thursday Friday Saturday);
+@DoW = qw(Sun Mon Tue Wed Thu Fri Sat);
+@MoY = qw(Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec);
+# Build %MoY hash
+my $i = 0;
+foreach(@MoY) {
+   $MoY{lc $_} = $i++;
+}
+
+my($current_month, $current_year) = (localtime)[4, 5];
+
+
+
+
+sub time2str (;$)
+{
+   my $time = shift;
+   $time = time unless defined $time;
+   my ($sec, $min, $hour, $mday, $mon, $year, $wday) = gmtime($time);
+   sprintf("%s, %02d %s %04d %02d:%02d:%02d GMT",
+	   $DoW[$wday],
+	   $mday, $MoY[$mon], $year+1900,
+	   $hour, $min, $sec);
+}
+
+
+
+sub str2time ($;$)
+{
+   local($_) = shift;
+   return undef unless defined;
+   my($default_zone) = @_;
+
+   # Remove useless weekday, if it exists
+   s/^\s*(?:sun|mon|tue|wed|thu|fri|sat)\w*,?\s*//i;
+
+   my($day, $mon, $yr, $hr, $min, $sec, $tz, $aorp);
+   my $offset = 0;  # used when compensating for timezone
+
+ PARSEDATE: {
+      # Then we are able to check for most of the formats with this regexp
+      ($day,$mon,$yr,$hr,$min,$sec,$tz) =
+	/^\s*
+	 (\d\d?)               # day
+	    (?:\s+|[-\/])
+	 (\w+)                 # month
+	    (?:\s+|[-\/])
+	 (\d+)                 # year
+	 (?:
+	       (?:\s+|:)       # separator before clock
+	    (\d\d?):(\d\d)     # hour:min
+	    (?::(\d\d))?       # optional seconds
+	 )?                    # optional clock
+	    \s*
+	 ([-+]?\d{2,4}|GMT|gmt)? # timezone
+	    \s*$
+	/x
+	  and last PARSEDATE;
+
+      # Try the ctime and asctime format
+      ($mon, $day, $hr, $min, $sec, $tz, $yr) =
+	/^\s*                  # allow intial whitespace
+	 (\w{1,3})             # month
+	    \s+
+	 (\d\d?)               # day
+	    \s+
+	 (\d\d?):(\d\d)        # hour:min
+	 (?::(\d\d))?          # optional seconds
+	    \s+
+	 (?:(GMT|gmt)\s+)?     # optional GMT timezone
+	 (\d+)                 # year
+	    \s*$               # allow trailing whitespace
+	/x
+	  and last PARSEDATE;
+
+      # Then the Unix 'ls -l' date format
+      ($mon, $day, $yr, $hr, $min, $sec) =
+	/^\s*
+	 (\w{3})               # month
+	    \s+
+	 (\d\d?)               # day
+	    \s+
+	 (?:
+	    (\d\d\d\d) |       # year
+	    (\d{1,2}):(\d{2})  # hour:min
+            (?::(\d\d))?       # optional seconds
+	 )
+	 \s*$
+       /x
+	 and last PARSEDATE;
+
+      # ISO 8601 format '1996-02-29 12:00:00 -0100' and variants
+      ($yr, $mon, $day, $hr, $min, $sec, $tz) =
+	/^\s*
+	  (\d{4})              # year
+	     [-\/]?
+	  (\d\d?)              # numerical month
+	     [-\/]?
+	  (\d\d?)              # day
+	 (?:
+	       (?:\s+|:|T|-)   # separator before clock
+	    (\d\d?):?(\d\d)    # hour:min
+	    (?::?(\d\d))?      # optional seconds
+	 )?                    # optional clock
+	    \s*
+	 ([-+]?\d\d?:?(:?\d\d)?
+	  |Z|z)?               # timezone  (Z is "zero meridian", i.e. GMT)
+	    \s*$
+	/x
+	  and last PARSEDATE;
+
+      # Windows 'dir' 11-12-96  03:52PM
+      ($mon, $day, $yr, $hr, $min, $aorp) =
+        /^\s*
+          (\d{2})                # numerical month
+             -
+          (\d{2})                # day
+             -
+          (\d{2})                # year
+             \s+
+          (\d\d?):(\d\d)([apAP][mM])  # hour:min AM or PM
+             \s*$
+        /x
+          and last PARSEDATE;
+
+      # If it is not recognized by now we give up
+      return undef;
+   }
+
+   # Translate month name to number
+   if ($mon =~ /^\d+$/) {
+     # numeric month
+     return undef if $mon < 1 || $mon > 12;
+     $mon--;
+   } else {
+     $mon = lc $mon;
+     return undef unless exists $MoY{$mon};
+     $mon = $MoY{$mon};
+   }
+
+   # If the year is missing, we assume some date before the current,
+   # because these date are mostly present on "ls -l" listings.
+   unless (defined $yr) {
+	$yr = $current_year;
+	$yr-- if $mon > $current_month;
+    }
+
+   # Then we check if the year is acceptable
+   return undef if $yr > 99 && $yr < 1900;  # We ignore these years
+   $yr += 100 if $yr < 50;  # a stupid thing to do???
+   $yr -= 1900 if $yr >= 1900;
+   # The $yr is now relative to 1900 (as expected by timelocal())
+
+   # timelocal() seems to go into an infinite loop if it is given out
+   # of range parameters.  Let's check the year at least.
+
+   # Epoch counter maxes out in year 2038, assuming "time_t" is 32 bit
+   return undef if $yr > 138;
+   return undef if $yr <  70;  # 1970 is Unix epoch
+
+   # Compensate for AM/PM
+   if ($aorp) {
+       $aorp = uc $aorp;
+       $hr = 0 if $hr == 12 && $aorp eq 'AM';
+       $hr += 12 if $aorp eq 'PM' && $hr != 12;
+   }
+
+   # Make sure things are defined
+   for ($sec, $min, $hr) {  $_ = 0 unless defined   }
+
+   # Should we compensate for the timezone?
+   $tz = $default_zone unless defined $tz;
+   return eval {Time::Local::timelocal($sec, $min, $hr, $day, $mon, $yr)}
+     unless defined $tz;
+
+   # We can calculate offset for numerical time zones
+   if ($tz =~ /^([-+])?(\d\d?):?(\d\d)?$/) {
+       $offset = 3600 * $2;
+       $offset += 60 * $3 if $3;
+       $offset *= -1 if $1 && $1 ne '-';
+   }
+   eval{Time::Local::timegm($sec, $min, $hr, $day, $mon, $yr) + $offset};
+}
+
+
+
+# And then some bloat because I happen to like the ISO 8601 time
+# format.
+
+sub time2iso (;$)
+{
+   my $time = shift;
+   $time = time unless defined $time;
+   my($sec,$min,$hour,$mday,$mon,$year) = localtime($time);
+   sprintf("%04d-%02d-%02d %02d:%02d:%02d",
+	   $year+1900, $mon+1, $mday, $hour, $min, $sec);
+}
+
+
+sub time2isoz (;$)
+{
+    my $time = shift;
+    $time = time unless defined $time;
+    my($sec,$min,$hour,$mday,$mon,$year) = gmtime($time);
+    sprintf("%04d-%02d-%02d %02d:%02d:%02dZ",
+            $year+1900, $mon+1, $mday, $hour, $min, $sec);
+}
+
+1;
+
Index: /main/tags/2.25/gsdl/packages/w3mir/libwww-perl-5.36/lib/HTTP/Headers.pm
===================================================================
--- /main/tags/2.25/gsdl/packages/w3mir/libwww-perl-5.36/lib/HTTP/Headers.pm	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/w3mir/libwww-perl-5.36/lib/HTTP/Headers.pm	(revision 21064)
@@ -0,0 +1,540 @@
+#
+# $Id$
+
+package HTTP::Headers;
+
+=head1 NAME
+
+HTTP::Headers - Class encapsulating HTTP Message headers
+
+=head1 SYNOPSIS
+
+ require HTTP::Headers;
+ $h = new HTTP::Headers;
+
+=head1 DESCRIPTION
+
+The C<HTTP::Headers> class encapsulates HTTP-style message headers.
+The headers consist of attribute-value pairs, which may be repeated,
+and which are printed in a particular order.
+
+Instances of this class are usually created as member variables of the
+C<HTTP::Request> and C<HTTP::Response> classes, internal to the
+library.
+
+The following methods are available:
+
+=over 4
+
+=cut
+
+use strict;
+use vars qw($VERSION $TRANSLATE_UNDERSCORE);
+$VERSION = sprintf("%d.%02d", q$Revision$ =~ /(\d+)\.(\d+)/);
+
+use Carp ();
+
+# Could not use the AutoLoader becase several of the method names are
+# not unique in the first 8 characters.
+#use SelfLoader;
+
+
+# "Good Practice" order of HTTP message headers:
+#    - General-Headers
+#    - Request-Headers
+#    - Response-Headers
+#    - Entity-Headers
+# (From draft-ietf-http-v11-spec-rev-01, Nov 21, 1997)
+
+my @header_order = qw(
+   Cache-Control Connection Date Pragma Transfer-Encoding Upgrade Trailer Via
+
+   Accept Accept-Charset Accept-Encoding Accept-Language
+   Authorization Expect From Host
+   If-Modified-Since If-Match If-None-Match If-Range If-Unmodified-Since
+   Max-Forwards Proxy-Authorization Range Referer TE User-Agent
+
+   Accept-Ranges Age Location Proxy-Authenticate Retry-After Server Vary
+   Warning WWW-Authenticate
+
+   Allow Content-Base Content-Encoding Content-Language Content-Length
+   Content-Location Content-MD5 Content-Range Content-Type
+   ETag Expires Last-Modified
+);
+
+# Make alternative representations of @header_order.  This is used
+# for sorting and case matching.
+my $i = 0;
+my %header_order;
+my %standard_case;
+for (@header_order) {
+    my $lc = lc $_;
+    $header_order{$lc} = $i++;
+    $standard_case{$lc} = $_;
+}
+
+$TRANSLATE_UNDERSCORE = 1 unless defined $TRANSLATE_UNDERSCORE;
+
+
+
+=item $h = new HTTP::Headers
+
+Constructs a new C<HTTP::Headers> object.  You might pass some initial
+attribute-value pairs as parameters to the constructor.  I<E.g.>:
+
+ $h = new HTTP::Headers
+     Date         => 'Thu, 03 Feb 1994 00:00:00 GMT',
+     Content_Type => 'text/html; version=3.2',
+     Content_Base => 'http://www.sn.no/';
+
+=cut
+
+sub new
+{
+    my($class) = shift;
+    my $self = bless {}, $class;
+    $self->header(@_); # set up initial headers
+    $self;
+}
+
+
+=item $h->header($field [=> $value],...)
+
+Get or set the value of a header.  The header field name is not case
+sensitive.  To make the life easier for perl users who wants to avoid
+quoting before the => operator, you can use '_' as a synonym for '-'
+in header names (this behaviour can be suppressed by setting
+$HTTP::Headers::TRANSLATE_UNDERSCORE to a FALSE value).
+
+The header() method accepts multiple ($field => $value) pairs, so you
+can update several fields with a single invocation.
+
+The optional $value argument may be a scalar or a reference to a list
+of scalars. If the $value argument is undefined or not given, then the
+header is not modified.
+
+The old value of the last of the $field values is returned.
+Multi-valued fields will be concatenated with "," as separator in
+scalar context.
+
+ $header->header(MIME_Version => '1.0',
+		 User_Agent   => 'My-Web-Client/0.01');
+ $header->header(Accept => "text/html, text/plain, image/*");
+ $header->header(Accept => [qw(text/html text/plain image/*)]);
+ @accepts = $header->header('Accept');
+
+=cut
+
+sub header
+{
+    my $self = shift;
+    my($field, $val, @old);
+    while (($field, $val) = splice(@_, 0, 2)) {
+	@old = $self->_header($field, $val);
+    }
+    return @old if wantarray;
+    return $old[0] if @old <= 1;
+    join(", ", @old);
+}
+
+sub _header
+{
+    my($self, $field, $val, $push) = @_;
+    $field =~ tr/_/-/ if $TRANSLATE_UNDERSCORE;
+
+    # $push is only used interally sub push_header
+    Carp::croak('Need a field name') unless length($field);
+
+    my $lc_field = lc $field;
+    unless(defined $standard_case{$lc_field}) {
+	# generate a %stadard_case entry for this field
+	$field =~ s/\b(\w)/\u$1/g;
+	$standard_case{$lc_field} = $field;
+    }
+
+    my $h = $self->{$lc_field};
+    my @old = ref($h) ? @$h : (defined($h) ? ($h) : ());
+
+    if (defined $val) {
+	my @new = $push ? @old : ();
+	if (!ref($val)) {
+	    push(@new, $val);
+	} elsif (ref($val) eq 'ARRAY') {
+	    push(@new, @$val);
+	} else {
+	    Carp::croak("Unexpected field value $val");
+	}
+	$self->{$lc_field} = @new > 1 ? \@new : $new[0];
+    }
+    @old;
+}
+
+
+# Compare function which makes it easy to sort headers in the
+# recommended "Good Practice" order.
+sub _header_cmp
+{
+    # Unknown headers are assign a large value so that they are
+    # sorted last.  This also helps avoiding a warning from -w
+    # about comparing undefined values.
+    $header_order{$a} = 999 unless defined $header_order{$a};
+    $header_order{$b} = 999 unless defined $header_order{$b};
+
+    $header_order{$a} <=> $header_order{$b} || $a cmp $b;
+}
+
+
+=item $h->scan(\&doit)
+
+Apply a subroutine to each header in turn.  The callback routine is
+called with two parameters; the name of the field and a single value.
+If the header has more than one value, then the routine is called once
+for each value.  The field name passed to the callback routine has
+case as suggested by HTTP Spec, and the headers will be visited in the
+recommended "Good Practice" order.
+
+=cut
+
+sub scan
+{
+    my($self, $sub) = @_;
+    my $key;
+    foreach $key (sort _header_cmp keys %$self) {
+        next if $key =~ /^_/;
+	my $vals = $self->{$key};
+	if (ref($vals)) {
+	    my $val;
+	    for $val (@$vals) {
+		&$sub($standard_case{$key} || $key, $val);
+	    }
+	} else {
+	    &$sub($standard_case{$key} || $key, $vals);
+	}
+    }
+}
+
+
+=item $h->as_string([$endl])
+
+Return the header fields as a formatted MIME header.  Since it
+internally uses the C<scan()> method to build the string, the result
+will use case as suggested by HTTP Spec, and it will follow
+recommended "Good Practice" of ordering the header fieds.  Long header
+values are not folded. 
+
+The optional parameter specifies the line ending sequence to use.  The
+default is C<"\n">.  Embedded "\n" characters in the header will be
+substitued with this line ending sequence.
+
+=cut
+
+sub as_string
+{
+    my($self, $endl) = @_;
+    $endl = "\n" unless defined $endl;
+
+    my @result = ();
+    $self->scan(sub {
+	my($field, $val) = @_;
+	if ($val =~ /\n/) {
+	    # must handle header values with embedded newlines with care
+	    $val =~ s/\s+$//;          # trailing newlines and space must go
+	    $val =~ s/\n\n+/\n/g;      # no empty lines
+	    $val =~ s/\n([^\040\t])/\n $1/g;  # intial space for continuation
+	    $val =~ s/\n/$endl/g;      # substitute with requested line ending
+	}
+	push(@result, "$field: $val");
+    });
+
+    join($endl, @result, '');
+}
+
+
+# The remaining functions should autoloaded only when needed
+
+# A bug in 5.002gamma makes it risky to have POD text inside the
+# autoloaded section of the code, so we keep the documentation before
+# the __DATA__ token.
+
+=item $h->push_header($field, $val)
+
+Add a new field value of the specified header.  The header field name
+is not case sensitive.  The field need not already have a
+value. Previous values for the same field are retained.  The argument
+may be a scalar or a reference to a list of scalars.
+
+ $header->push_header(Accept => 'image/jpeg');
+
+=item $h->remove_header($field,...)
+
+This function removes the headers with the specified names.
+
+=item $h->clone
+
+Returns a copy of this HTTP::Headers object.
+
+=back
+
+=head1 CONVENIENCE METHODS
+
+The most frequently used headers can also be accessed through the
+following convenience methods.  These methods can both be used to read
+and to set the value of a header.  The header value is set if you pass
+an argument to the method.  The old header value is always returned.
+
+Methods that deal with dates/times always convert their value to system
+time (seconds since Jan 1, 1970) and they also expect this kind of
+value when the header value is set.
+
+=over 4
+
+=item $h->date
+
+This header represents the date and time at which the message was
+originated. I<E.g.>:
+
+  $h->date(time);  # set current date
+
+=item $h->expires
+
+This header gives the date and time after which the entity should be
+considered stale.
+
+=item $h->if_modified_since
+
+=item $h->if_unmodified_since
+
+This header is used to make a request conditional.  If the requested
+resource has (not) been modified since the time specified in this field,
+then the server will return a C<"304 Not Modified"> response instead of
+the document itself.
+
+=item $h->last_modified
+
+This header indicates the date and time at which the resource was last
+modified. I<E.g.>:
+
+  # check if document is more than 1 hour old
+  if ($h->last_modified < time - 60*60) {
+	...
+  }
+
+=item $h->content_type
+
+The Content-Type header field indicates the media type of the message
+content. I<E.g.>:
+
+  $h->content_type('text/html');
+
+The value returned will be converted to lower case, and potential
+parameters will be chopped off and returned as a separate value if in
+an array context.  This makes it safe to do the following:
+
+  if ($h->content_type eq 'text/html') {
+     # we enter this place even if the real header value happens to
+     # be 'TEXT/HTML; version=3.0'
+     ...
+  }
+
+=item $h->content_encoding
+
+The Content-Encoding header field is used as a modifier to the
+media type.  When present, its value indicates what additional
+encoding mechanism has been applied to the resource.
+
+=item $h->content_length
+
+A decimal number indicating the size in bytes of the message content.
+
+=item $h->content_language
+
+The natural language(s) of the intended audience for the message
+content.  The value is one or more language tags as defined by RFC
+1766.  Eg. "no" for Norwegian and "en-US" for US-English.
+
+=item $h->title
+
+The title of the document.  In libwww-perl this header will be
+initialized automatically from the E<lt>TITLE>...E<lt>/TITLE> element
+of HTML documents.  I<This header is no longer part of the HTTP
+standard.>
+
+=item $h->user_agent
+
+This header field is used in request messages and contains information
+about the user agent originating the request.  I<E.g.>:
+
+  $h->user_agent('Mozilla/1.2');
+
+=item $h->server
+
+The server header field contains information about the software being
+used by the originating server program handling the request.
+
+=item $h->from
+
+This header should contain an Internet e-mail address for the human
+user who controls the requesting user agent.  The address should be
+machine-usable, as defined by RFC822.  E.g.:
+
+  $h->from('Gisle Aas <aas@sn.no>');
+
+=item $h->referer
+
+Used to specify the address (URI) of the document from which the
+requested resouce address was obtained.
+
+=item $h->www_authenticate
+
+This header must be included as part of a "401 Unauthorized" response.
+The field value consist of a challenge that indicates the
+authentication scheme and parameters applicable to the requested URI.
+
+=item $h->proxy_authenticate
+
+This header must be included in a "407 Proxy Authentication Required"
+response.
+
+=item $h->authorization
+
+=item $h->proxy_authorization
+
+A user agent that wishes to authenticate itself with a server or a
+proxy, may do so by including these headers.
+
+=item $h->authorization_basic
+
+This method is used to get or set an authorization header that use the
+"Basic Authentication Scheme".  In array context it will return two
+values; the user name and the password.  In scalar context it will
+return I<"uname:password"> as a single string value.
+
+When used to set the header value, it expects two arguments.  I<E.g.>:
+
+  $h->authorization_basic($uname, $password);
+
+The method will croak if the $uname contains a colon ':'.
+
+=item $h->proxy_authorization_basic
+
+Same as authorization_basic() but will set the "Proxy-Authorization"
+header instead.
+
+=back
+
+=head1 COPYRIGHT
+
+Copyright 1995-1998 Gisle Aas.
+
+This library is free software; you can redistribute it and/or
+modify it under the same terms as Perl itself.
+
+=cut
+
+1;
+
+#__DATA__
+
+sub clone
+{
+    my $self = shift;
+    my $clone = new HTTP::Headers;
+    $self->scan(sub { $clone->push_header(@_);} );
+    $clone;
+}
+
+sub push_header
+{
+    Carp::croak('Usage: $h->push_header($field, $val)') if @_ != 3;
+    shift->_header(@_, 'PUSH');
+}
+
+
+sub remove_header
+{
+    my($self, @fields) = @_;
+    my $field;
+    foreach $field (@fields) {
+	$field =~ tr/_/-/ if $TRANSLATE_UNDERSCORE;
+	delete $self->{lc $field};
+    }
+}
+
+# Convenience access functions
+
+sub _date_header
+{
+    require HTTP::Date;
+    my($self, $header, $time) = @_;
+    my($old) = $self->_header($header);
+    if (defined $time) {
+	$self->_header($header, HTTP::Date::time2str($time));
+    }
+    HTTP::Date::str2time($old);
+}
+
+sub date                { shift->_date_header('Date',                @_); }
+sub expires             { shift->_date_header('Expires',             @_); }
+sub if_modified_since   { shift->_date_header('If-Modified-Since',   @_); }
+sub if_unmodified_since { shift->_date_header('If-Unmodified-Since', @_); }
+sub last_modified       { shift->_date_header('Last-Modified',       @_); }
+
+# This is used as a private LWP extention.  The Client-Date header is
+# added as a timestamp to a response when it has been received.
+sub client_date         { shift->_date_header('Client-Date',         @_); }
+
+# The retry_after field is dual format (can also be a expressed as
+# number of seconds from now), so we don't provide an easy way to
+# access it until we have know how both these interfaces can be
+# addressed.  One possibility is to return a negative value for
+# relative seconds and a positive value for epoch based time values.
+#sub retry_after       { shift->_date_header('Retry-After',       @_); }
+
+sub content_type      {
+  my $ct = (shift->_header('Content-Type', @_))[0];
+  return '' unless defined($ct) && length($ct);
+  my @ct = split(/\s*;\s*/, lc($ct));
+  wantarray ? @ct : $ct[0];
+}
+
+sub title             { (shift->_header('Title',            @_))[0] }
+sub content_encoding  { (shift->_header('Content-Encoding', @_))[0] }
+sub content_language  { (shift->_header('Content-Language', @_))[0] }
+sub content_length    { (shift->_header('Content-Length',   @_))[0] }
+
+sub user_agent        { (shift->_header('User-Agent',       @_))[0] }
+sub server            { (shift->_header('Server',           @_))[0] }
+
+sub from              { (shift->_header('From',             @_))[0] }
+sub referer           { (shift->_header('Referer',          @_))[0] }
+sub warning           { (shift->_header('Warning',          @_))[0] }
+
+sub www_authenticate  { (shift->_header('WWW-Authenticate', @_))[0] }
+sub authorization     { (shift->_header('Authorization',    @_))[0] }
+
+sub proxy_authenticate  { (shift->_header('Proxy-Authenticate',  @_))[0] }
+sub proxy_authorization { (shift->_header('Proxy-Authorization', @_))[0] }
+
+sub authorization_basic       { shift->_basic_auth("Authorization",       @_) }
+sub proxy_authorization_basic { shift->_basic_auth("Proxy-Authorization", @_) }
+
+sub _basic_auth {
+    require MIME::Base64;
+    my($self, $h, $user, $passwd) = @_;
+    my($old) = $self->_header($h);
+    if (defined $user) {
+	Carp::croak("Basic authorization user name can't contain ':'")
+	  if $user =~ /:/;
+	$passwd = '' unless defined $passwd;
+	$self->_header($h => 'Basic ' .
+                             MIME::Base64::encode("$user:$passwd", ''));
+    }
+    if (defined $old && $old =~ s/^\s*Basic\s+//) {
+	my $val = MIME::Base64::decode($old);
+	return $val unless wantarray;
+	return split(/:/, $val, 2);
+    }
+    return;
+}
+
+1;
Index: /main/tags/2.25/gsdl/packages/w3mir/libwww-perl-5.36/lib/HTTP/Headers/Auth.pm
===================================================================
--- /main/tags/2.25/gsdl/packages/w3mir/libwww-perl-5.36/lib/HTTP/Headers/Auth.pm	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/w3mir/libwww-perl-5.36/lib/HTTP/Headers/Auth.pm	(revision 21064)
@@ -0,0 +1,94 @@
+package HTTP::Headers::Auth;
+
+use strict;
+use vars qw($VERSION);
+$VERSION = sprintf("%d.%02d", q$Revision$ =~ /(\d+)\.(\d+)/);
+
+require HTTP::Headers;
+package HTTP::Headers;
+
+BEGIN {
+    # we provide a new (and better) implementations below
+    undef(&www_authenticate);
+    undef(&proxy_authenticate);
+}
+
+require HTTP::Headers::Util;
+
+sub _parse_authenticate
+{
+    my @ret;
+    for (HTTP::Headers::Util::split_header_words(@_)) {
+	if (!defined($_->[1])) {
+	    # this is a new auth scheme
+	    push(@ret, lc(shift @$_) => {});
+	    shift @$_;
+	}
+	if (@ret) {
+	    # this a new parameter pair for the last auth scheme
+	    while (@$_) {
+		my $k = lc(shift @$_);
+		my $v = shift @$_;
+	        $ret[-1]{$k} = $v;
+	    }
+	} else {
+	    # something wrong, parameter pair without any scheme seen
+	    # IGNORE
+	}
+    }
+    @ret;
+}
+
+sub _authenticate
+{
+    my $self = shift;
+    my $header = shift;
+    my @old = $self->_header($header);
+    if (@_) {
+	$self->remove_header($header);
+	my @new = @_;
+	while (@new) {
+	    my $a_scheme = shift(@new);
+	    if ($a_scheme =~ /\s/) {
+		# assume complete valid value, pass it through
+		$self->push_header($header, $a_scheme);
+	    } else {
+		my @param;
+		if (@new) {
+		    my $p = $new[0];
+		    if (ref($p) eq "ARRAY") {
+			@param = @$p;
+			shift(@new);
+		    } elsif (ref($p) eq "HASH") {
+			@param = %$p;
+			shift(@new);
+		    }
+		}
+		my $val = ucfirst(lc($a_scheme));
+		if (@param) {
+		    my $sep = " ";
+		    while (@param) {
+			my $k = shift @param;
+			my $v = shift @param;
+			if ($v =~ /[^0-9a-zA-Z]/ || lc($k) eq "realm") {
+			    # must quote the value
+			    $v =~ s,([\\\"]),\\$1,g;
+			    $v = qq("$v");
+			}
+			$val .= "$sep$k=$v";
+			$sep = ", ";
+		    }
+		}
+		$self->push_header($header, $val);
+	    }
+	}
+    }
+    return unless defined wantarray;
+    wantarray ? _parse_authenticate(@old) : join(", ", @old);
+}
+
+
+sub www_authenticate    { shift->_authenticate("WWW-Authenticate", @_)   }
+sub proxy_authenticate  { shift->_authenticate("Proxy-Authenticate", @_) }
+
+1;
Index: /main/tags/2.25/gsdl/packages/w3mir/libwww-perl-5.36/lib/HTTP/Headers/ETag.pm
===================================================================
--- /main/tags/2.25/gsdl/packages/w3mir/libwww-perl-5.36/lib/HTTP/Headers/ETag.pm	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/w3mir/libwww-perl-5.36/lib/HTTP/Headers/ETag.pm	(revision 21064)
@@ -0,0 +1,88 @@
+package HTTP::Header::ETag;
+
+use strict;
+use vars qw($VERSION);
+$VERSION = sprintf("%d.%02d", q$Revision$ =~ /(\d+)\.(\d+)/);
+
+require HTTP::Date;
+
+require HTTP::Headers;
+package HTTP::Headers;
+
+sub _etags
+{
+    my $self = shift;
+    my $header = shift;
+    my @old = _split_etag_list($self->_header($header));
+    if (@_) {
+	$self->_header($header => join(", ", _split_etag_list(@_)));
+    }
+    wantarray ? @old : join(", ", @old);
+}
+
+sub etag          { shift->_etags("ETag", @_); }
+sub if_match      { shift->_etags("If-Match", @_); }
+sub if_none_match { shift->_etags("If-None-Match", @_); }
+
+sub if_range {
+    # Either a date or an entity-tag
+    my $self = shift;
+    my @old = $self->_header("If-Range");
+    if (@_) {
+	my $new = shift;
+	if (!defined $new) {
+	    $self->remove_header("If-Range");
+	} elsif ($new =~ /^\d+$/) {
+	    $self->_date_header("If-Range", $new);
+	} else {
+	    $self->_etags("If-Range", $new);
+	}
+    }
+    return unless defined(wantarray);
+    for (@old) {
+	my $t = HTTP::Date::str2time($_);
+	$_ = $t if $t;
+    }
+    wantarray ? @old : join(", ", @old);
+}
+
+
+# Split a list of entity tag values.  The return value is a list
+# consisting of one element per entity tag.  Suitable for parsing
+# headers like C<If-Match>, C<If-None-Match>.  You might even want to
+# use it on C<ETag> and C<If-Range> entity tag values, because it will
+# normalize them to the common form.
+#
+#  entity-tag	  = [ weak ] opaque-tag
+#  weak		  = "W/"
+#  opaque-tag	  = quoted-string
+
+
+sub _split_etag_list
+{
+    my(@val) = @_;
+    my @res;
+    for (@val) {
+        while (length) {
+            my $weak = "";
+	    $weak = "W/" if s,^\s*[wW]/,,;
+            my $etag = "";
+	    if (s/^\s*(\"[^\"\\]*(?:\\.[^\"\\]*)*\")//) {
+		push(@res, "$weak$1");
+            } elsif (s/^\s*,//) {
+                push(@res, qq(W/"")) if $weak;
+            } elsif (s/^\s*([^,\s]+)//) {
+                $etag = $1;
+		$etag =~ s/([\"\\])/\\$1/g;
+	        push(@res, qq($weak"$etag"));
+            } elsif (s/^\s+// || !length) {
+                push(@res, qq(W/"")) if $weak;
+            } else {
+	 	die "This should not happen: '$_'";
+            }
+        }
+   }
+   @res;
+}
+
+1;
Index: /main/tags/2.25/gsdl/packages/w3mir/libwww-perl-5.36/lib/HTTP/Headers/Util.pm
===================================================================
--- /main/tags/2.25/gsdl/packages/w3mir/libwww-perl-5.36/lib/HTTP/Headers/Util.pm	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/w3mir/libwww-perl-5.36/lib/HTTP/Headers/Util.pm	(revision 21064)
@@ -0,0 +1,180 @@
+package HTTP::Headers::Util;
+
+use strict;
+use vars qw($VERSION @ISA @EXPORT_OK);
+
+$VERSION = sprintf("%d.%02d", q$Revision$ =~ /(\d+)\.(\d+)/);
+
+require Exporter;
+@ISA=qw(Exporter);
+
+@EXPORT_OK=qw(split_header_words join_header_words);
+
+=head1 NAME
+
+HTTP::Headers::Util - Header value parsing utility functions
+
+=head1 SYNOPSIS
+
+  use HTTP::Headers::Util qw(split_header_words);
+  @values = split_header_words($h->header("Content-Type"));
+
+=head1 DESCRIPTION
+
+This module provide a few functions that helps parsing and
+construction of valid HTTP header values.  None of the functions are
+exported by default.
+
+The following functions are provided:
+
+=over 4
+
+
+=item split_header_words( @header_values )
+
+This function will parse the header values given as argument into a
+list of anonymous arrays containing key/value pairs.  The function
+know how to deal with ",", ";" and "=" as well as quoted values after
+"=".  A list of space separated tokens are parsed as if they were
+separated by ";".
+
+If the @header_values passed as argument contains multiple values,
+then they are treated as if they were a single value separated by
+comma ",".
+
+This means that this function is useful to parse header fields that
+follow this syntax (BNF as from the HTTP/1.1 specification, but we relax
+the requirement for tokens).
+
+  headers           = #header
+  header            = (token | parameter) *( [";"] (token | parameter))
+
+  token             = 1*<any CHAR except CTLs or separators>
+  separators        = "(" | ")" | "<" | ">" | "@"
+                    | "," | ";" | ":" | "\" | <">
+                    | "/" | "[" | "]" | "?" | "="
+                    | "{" | "}" | SP | HT
+
+  quoted-string     = ( <"> *(qdtext | quoted-pair ) <"> )
+  qdtext            = <any TEXT except <">>
+  quoted-pair       = "\" CHAR
+
+  parameter         = attribute "=" value
+  attribute         = token
+  value             = token | quoted-string
+
+Each I<header> is represented by an anonymous array of key/value
+pairs.  If a token is recognized then the value will be C<undef>.
+Syntactically incorrect headers will not necessary be parsed as you
+would want.
+
+This is easier to describe with some examples:
+
+   split_header_words('foo="bar"; port="80,81"; discard, bar=baz')
+   split_header_words('text/html; charset="iso-8859-1");
+   split_header_words('Basic realm="\"foo\\bar\""');
+
+will return
+
+   [foo=>'bar', port=>'80,81', discard=> undef], [bar=>'baz' ]
+   ['text/html' => undef, charset => 'iso-8859-1']
+   [Basic => undef, realm => '"foo\bar"']
+
+=cut
+
+
+sub split_header_words
+{
+    my(@val) = @_;
+    my @res;
+    for (@val) {
+	my @cur;
+	while (length) {
+	    if (s/^\s*(=*[^\s=;,]+)//) {  # 'token' or parameter 'attribute'
+		push(@cur, $1);
+		# a quoted value
+		if (s/^\s*=\s*\"([^\"\\]*(?:\\.[^\"\\]*)*)\"//) {
+		    my $val = $1;
+		    $val =~ s/\\(.)/$1/g;
+		    push(@cur, $val);
+		# some unquoted value
+		} elsif (s/^\s*=\s*([^;,\s]*)//) {
+		    my $val = $1;
+		    $val =~ s/\s+$//;
+		    push(@cur, $val);
+		# no value, a lone token
+		} else {
+		    push(@cur, undef);
+		}
+	    } elsif (s/^\s*,//) {
+		push(@res, [@cur]) if @cur;
+		@cur = ();
+	    } elsif (s/^\s*;// || s/^\s+//) {
+		# continue
+	    } else {
+		die "This should not happen: '$_'";
+	    }
+	}
+	push(@res, \@cur) if @cur;
+    }
+    @res;
+}
+
+
+=item join_header_words( @arrays )
+
+This will do the opposite convertion of what split_header_words()
+does.  It takes a list of anonymous arrays as argument (or a list of
+key/value pairs) and produce a single header value.  Attribute values
+are quoted if needed.
+
+Example:
+
+   join_header_words(["text/plain" => undef, charset => "iso-8859/1"]);
+   join_header_words(""text/plain" => undef, charset => "iso-8859/1");
+
+will both return the string:
+
+   text/plain; charset="iso-8859/1"
+
+=cut
+
+sub join_header_words
+{
+    @_ = ([@_]) if @_ && !ref($_[0]);
+    my @res;
+    for (@_) {
+	my @cur = @$_;
+	my @attr;
+	while (@cur) {
+	    my $k = shift @cur;
+	    my $v = shift @cur;
+	    if (defined $v) {
+		if ($v =~ /^\w+$/) {
+		    $k .= "=$v";
+		} else {
+		    $v =~ s/([\"\\])/\\$1/g;  # escape " and \
+		    $k .= qq(="$v");
+		}
+	    }
+	    push(@attr, $k);
+	}
+	push(@res, join("; ", @attr)) if @attr;
+    }
+    join(", ", @res);
+}
+
+1;
+
+__END__
+
+=back
+
+=head1 COPYRIGHT
+
+Copyright 1997-1998, Gisle Aas
+
+This library is free software; you can redistribute it and/or
+modify it under the same terms as Perl itself.
+
+=cut
Index: /main/tags/2.25/gsdl/packages/w3mir/libwww-perl-5.36/lib/HTTP/Message.pm
===================================================================
--- /main/tags/2.25/gsdl/packages/w3mir/libwww-perl-5.36/lib/HTTP/Message.pm	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/w3mir/libwww-perl-5.36/lib/HTTP/Message.pm	(revision 21064)
@@ -0,0 +1,208 @@
+#
+# $Id$
+
+package HTTP::Message;
+
+=head1 NAME
+
+HTTP::Message - Class encapsulating HTTP messages
+
+=head1 SYNOPSIS
+
+ package HTTP::Request;  # or HTTP::Response
+ require HTTP::Message;
+ @ISA=qw(HTTP::Message);
+
+=head1 DESCRIPTION
+
+A C<HTTP::Message> object contains some headers and a content (body).
+The class is abstract, i.e. it only used as a base class for
+C<HTTP::Request> and C<HTTP::Response> and should never instantiated
+as itself.
+
+The following methods are available:
+
+=over 4
+
+=cut
+
+#####################################################################
+
+require HTTP::Headers;
+require Carp;
+use strict;
+use vars qw($VERSION $AUTOLOAD);
+$VERSION = sprintf("%d.%02d", q$Revision$ =~ /(\d+)\.(\d+)/);
+
+=item $mess = new HTTP::Message;
+
+This is the object constructor.  It should only be called internally
+by this library.  External code should construct C<HTTP::Request> or
+C<HTTP::Response> objects.
+
+=cut
+
+sub new
+{
+    my($class, $header, $content) = @_;
+    if (defined $header) {
+	Carp::croak("Bad header argument") unless ref $header;
+	$header = $header->clone;
+    } else {
+	$header = HTTP::Headers->new;
+    }
+    $content = '' unless defined $content;
+    bless {
+	'_headers' => $header,
+	'_content' => $content,
+    }, $class;
+}
+
+
+=item $mess->clone()
+
+Returns a copy of the object.
+
+=cut
+
+sub clone
+{
+    my $self  = shift;
+    my $clone = HTTP::Message->new($self->{'_headers'}, $self->{'_content'});
+    $clone;
+}
+
+=item $mess->protocol([$proto])
+
+Sets the HTTP protocol used for the message.  The protocol() is a string
+like "HTTP/1.0" or "HTTP/1.1".
+
+=cut
+
+sub protocol { shift->_elem('_protocol',  @_); }
+
+=item $mess->content([$content])
+
+The content() method sets the content if an argument is given.  If no
+argument is given the content is not touched.  In either case the
+previous content is returned.
+
+=item $mess->add_content($data)
+
+The add_content() methods appends more data to the end of the previous
+content.
+
+=cut
+
+sub content   { shift->_elem('_content',  @_); }
+
+sub add_content
+{
+    my $self = shift;
+    if (ref($_[0])) {
+	$self->{'_content'} .= ${$_[0]};  # for backwards compatability
+    } else {
+	$self->{'_content'} .= $_[0];
+    }
+}
+
+=item $mess->content_ref
+
+The content_ref() method will return a reference to content string.
+It can be more efficient to access the content this way if the content
+is huge, and it can be used for direct manipulation of the content,
+for instance:
+
+  ${$res->content_ref} =~ s/\bfoo\b/bar/g;
+
+=cut
+
+sub content_ref
+{
+    my $self = shift;
+    \$self->{'_content'};
+}
+
+sub as_string
+{
+    "";  # To be overridden in subclasses
+}
+
+=item $mess->headers;
+
+Return the embedded HTTP::Headers object.
+
+=item $mess->headers_as_string([$endl])
+
+Call the HTTP::Headers->as_string() method for the headers in the
+message.
+
+=cut
+
+sub headers            { shift->{'_headers'};                }
+sub headers_as_string  { shift->{'_headers'}->as_string(@_); }
+
+=back
+
+All unknown C<HTTP::Message> methods are delegated to the
+C<HTTP::Headers> object that is part of every message.  This allows
+convenient access to these methods.  Refer to L<HTTP::Headers> for
+details of these methods:
+
+  $mess->header($field => $val);
+  $mess->scan(\&doit);
+  $mess->push_header($field => $val);
+  $mess->remove_header($field);
+
+  $mess->date;
+  $mess->expires;
+  $mess->if_modified_since;
+  $mess->if_unmodified_since;
+  $mess->last_modified;
+  $mess->content_type;
+  $mess->content_encoding;
+  $mess->content_length;
+  $mess->content_language
+  $mess->title;
+  $mess->user_agent;
+  $mess->server;
+  $mess->from;
+  $mess->referer;
+  $mess->www_authenticate;
+  $mess->authorization;
+  $mess->proxy_authorization;
+  $mess->authorization_basic;
+  $mess->proxy_authorization_basic;
+
+=cut
+
+
+# delegate all other method calls the the _headers object.
+sub AUTOLOAD
+{
+    my $self = shift;
+    my $method = substr($AUTOLOAD, rindex($AUTOLOAD, '::')+2);
+    return if $method eq "DESTROY";
+    $self->{'_headers'}->$method(@_);
+}
+
+# Private method to access members in %$self
+sub _elem
+{
+    my $self = shift;
+    my $elem = shift;
+    my $old = $self->{$elem};
+    $self->{$elem} = $_[0] if @_;
+    return $old;
+}
+
+1;
+
+=head1 COPYRIGHT
+
+Copyright 1995-1997 Gisle Aas.
+
+This library is free software; you can redistribute it and/or
+modify it under the same terms as Perl itself.
+
+=cut
Index: /main/tags/2.25/gsdl/packages/w3mir/libwww-perl-5.36/lib/HTTP/Negotiate.pm
===================================================================
--- /main/tags/2.25/gsdl/packages/w3mir/libwww-perl-5.36/lib/HTTP/Negotiate.pm	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/w3mir/libwww-perl-5.36/lib/HTTP/Negotiate.pm	(revision 21064)
@@ -0,0 +1,505 @@
+# $Id$
+#
+
+package HTTP::Negotiate;
+
+$VERSION = sprintf("%d.%02d", q$Revision$ =~ /(\d+)\.(\d+)/);
+sub Version { $VERSION; }
+
+require 5.002;
+require Exporter;
+@ISA = qw(Exporter);
+@EXPORT = qw(choose);
+
+require HTTP::Headers;
+
+$DEBUG = 0;
+
+sub choose ($;$)
+{
+    my($variants, $request) = @_;
+    my(%accept);
+
+    unless (defined $request) {
+	# Create a request object from the CGI envirionment variables
+	$request = new HTTP::Headers;
+	$request->header('Accept', $ENV{HTTP_ACCEPT})
+	  if $ENV{HTTP_ACCEPT};
+	$request->header('Accept-Charset', $ENV{HTTP_ACCEPT_CHARSET})
+	  if $ENV{HTTP_ACCEPT_CHARSET};
+	$request->header('Accept-Encoding', $ENV{HTTP_ACCEPT_ENCODING})
+	  if $ENV{HTTP_ACCEPT_ENCODING};
+	$request->header('Accept-Language', $ENV{HTTP_ACCEPT_LANGUAGE})
+	  if $ENV{HTTP_ACCEPT_LANGUAGE};
+    }
+
+    # Get all Accept values from the request.  Build a hash initialized
+    # like this:
+    #
+    #   %accept = ( type =>     { 'audio/*'     => { q => 0.2, mbx => 20000 },
+    #                             'audio/basic' => { q => 1 },
+    #                           },
+    #               language => { 'no'          => { q => 1 },
+    #                           }
+    #             );
+
+    $request->scan(sub {
+	my($key, $val) = @_;
+	return unless $key =~ s/^Accept-?//;
+	my $type = lc $key;
+	$type = "type" unless length $key;
+	$val =~ s/\s+//g;
+	my $name;
+	for $name (split(/,/, $val)) {
+	    my(%param, $param);
+	    if ($name =~ s/;(.*)//) {
+		for $param (split(/;/, $1)) {
+		    my ($pk, $pv) = split(/=/, $param, 2);
+		    $param{$pk} = $pv;
+		}
+	    }
+	    $name = lc $name;
+	    if (defined $param{'q'}) {
+		$param{'q'} = 1 if $param{'q'} > 1;
+		$param{'q'} = 0 if $param{'q'} < 0;
+	    } else {
+		$param{'q'} = 1;
+	    }
+
+	    $param{'q'} = 1 unless defined $param{'q'};
+	    $accept{$type}{$name} = \%param;
+	}
+    });
+
+    # Check if any of the variants specify a language.  We do this
+    # because it influence how we treat those without (they default to
+    # 0.5 instead of 1).
+    my $any_lang = 0;
+    for $var (@$variants) {
+	if ($var->[5]) {
+	    $any_lang = 1;
+	    last;
+	}
+    }
+
+    if ($DEBUG) {
+	print "Netgotiantion parameters in the request\n";
+	for $type (keys %accept) {
+	    print " $type:\n";
+	    for $name (keys %{$accept{$type}}) {
+		print "    $name\n";
+		for $pv (keys %{$accept{$type}{$name}}) {
+		    print "      $pv = $accept{$type}{$name}{$pv}\n";
+		}
+	    }
+	}
+    }
+
+    my @Q = ();  # This is where we collect the results of the
+		 # quality calcualtions
+
+    # Calculate quality for all the variant's that are available.
+    for (@$variants) {
+	my($id, $qs, $ct, $enc, $cs, $lang, $bs) = @$_;
+	$qs = 1 unless defined $qs;
+	$bs = 0 unless defined $bs;
+	if ($DEBUG) {
+	    print "\nEvaluating $id ($ct)\n";
+	    printf "  qs   = %.3f\n", $qs;
+	    print  "  enc  = $enc\n"  if $enc && !ref($enc);
+	    print  "  enc  = @$enc\n" if $enc && ref($enc);
+	    print  "  cs   = $cs\n"   if $cs;
+	    print  "  lang = $lang\n" if $lang;
+	    print  "  bs   = $bs\n"   if $bs;
+	}
+
+	# Calculate encoding quality
+	my $qe = 1;
+	# If the variant has no assignes Content-Encoding, or if no
+	# Accept-Encoding field is present, then the value assigned
+	# is "qe=1".  If *all* of the variant's content encoddings
+	# are listed in the Accept-Encoding field, then the value
+	# assigned is "qw=1".  If *any* of the variant's content
+	# encodings are not listed in the provided Accept-Encoding
+	# field, then the value assigned is "qe=0"
+	if (exists $accept{'encoding'} && $enc) {
+	    my @enc = ref($enc) ? @$enc : ($enc);
+	    for (@enc) {
+		print "Is encoding $_ accepted? " if $DEBUG;
+		unless(exists $accept{'encoding'}{$_}) {
+		    print "no\n" if $DEBUG;
+		    $qe = 0;
+		    last;
+		} else {
+		    print "yes\n" if $DEBUG;
+		}
+	    }
+	}
+
+	# Calculate charset quality
+	my $qc  = 1;
+	# If the variant's media-type has not charset parameter,
+	# or the variant's charset is US-ASCII, or if no Accept-Charset
+	# field is present, then the value assigned is "qc=1".  If the
+	# variantæs charset is listed in the Accept-Charset field,
+	# then the value assigned is "qc=1.  Otherwise, if the variant's
+	# charset is not listed in the provided Accept-Encoding field,
+	# then the value assigned is "qc=0".
+	if (exists $accept{'charset'} && $cs && $cs ne 'us-ascii' ) {
+	    $qc = 0 unless $accept{'charset'}{$cs};
+	}
+
+	# Calculate language quality
+	my $ql  = 1;
+	if ($lang && exists $accept{'language'}) {
+	    my @lang = ref($lang) ? @$lang : ($lang);
+	    # If any of the variant's content languages are listed
+	    # in the Accept-Language field, the the value assigned is
+	    # the maximus of the "q" paramet values for thos language
+	    # tags.
+	    my $q = undef;
+	    for (@lang) {
+		next unless exists $accept{'language'}{$_};
+		my $this_q = $accept{'language'}{$_}{'q'};
+		$q = $this_q unless defined $q;
+		$q = $this_q if $this_q > $q;
+	    }
+	    unless (defined $q) {
+		# If there was no exact match and at least one of
+		# the Accept-Language field values is a complete
+		# subtag prefix of the content language tag(s), then
+		# the "q" parameter value of the largest matching
+		# prefix is used.
+		my $selected = undef;
+		for $al (keys %{ $accept{'language'} }) {
+		    if (substr($lang, 0, length($al)) eq $al) {
+			$selected = $al unless defined $selected;
+			$selected = $al if length($al) > length($selected);
+		    }
+		}
+		$q = $accept{'language'}{$selected}{'q'} if $selected;
+
+		# If none of the variant's content language tags or
+		# tag prefixes are listed in the provided
+		# Accept-Language field, then the value assigned
+		# is "ql=0.001"
+		$q = 0.001 unless defined $q;
+	    }
+	    $ql = $q;
+	} else {
+	    $ql = 0.5 if $any_lang && exists $accept{'language'};
+	}
+
+	my $q   = 1;
+	my $mbx = undef;
+	# If no Accept field is given, then the value assigned is "q=1".
+	# If at least one listed media range matches the variant's media
+	# type, then the "q" parameter value assigned to the most specific
+	# of those matched is used (e.g. "text/html;version=3.0" is more
+	# specific than "text/html", which is more specific than "text/*",
+	# which in turn is more specific than "*/*"). If not media range
+	# in the provided Accept field matches the variant's media type,
+	# then the value assigned is "q=0".
+	if (exists $accept{'type'} && $ct) {
+	    # First we clean up our content-type
+	    $ct =~ s/\s+//g;
+	    my $params = "";
+	    $params = $1 if $ct =~ s/;(.*)//;
+	    my($type, $subtype) = split("/", $ct, 2);
+	    my %param = ();
+	    for $param (split(/;/, $params)) {
+		my($pk,$pv) = split(/=/, $param, 2);
+		$param{$pk} = $pv;
+	    }
+
+	    my $sel_q = undef;
+	    my $sel_mbx = undef;
+	    my $sel_specificness = 0;
+
+	    ACCEPT_TYPE:
+	    for $at (keys %{ $accept{'type'} }) {
+		print "Consider $at...\n" if $DEBUG;
+		my($at_type, $at_subtype) = split("/", $at, 2);
+		# Is it a match on the type
+		next if $at_type    ne '*' && $at_type    ne $type;
+		next if $at_subtype ne '*' && $at_subtype ne $subtype;
+		my $specificness = 0;
+		$specificness++ if $at_type ne '*';
+		$specificness++ if $at_subtype ne '*';
+		# Let's see if content-type parameters also match
+		while (($pk, $pv) = each %param) {
+		    print "Check if $pk = $pv is true\n" if $DEBUG;
+		    next unless exists $accept{'type'}{$at}{$pk};
+		    next ACCEPT_TYPE
+		      unless $accept{'type'}{$at}{$pk} eq $pv;
+		    print "yes it is!!\n" if $DEBUG;
+		    $specificness++;
+		}
+		print "Hurray, type match with specificness = $specificness\n"
+		  if $DEBUG;
+
+		if (!defined($sel_q) || $sel_specificness < $specificness) {
+		    $sel_q   = $accept{'type'}{$at}{'q'};
+		    $sel_mbx = $accept{'type'}{$at}{'mbx'};
+		    $sel_specificness = $specificness;
+		}
+	    }
+	    $q   = $sel_q || 0;
+	    $mbx = $sel_mbx;
+	}
+
+	my $Q;
+	if (!defined($mbx) || $mbx >= $bs) {
+	    $Q = $qs * $qe * $qc * $ql * $q;
+	} else {
+	    $Q = 0;
+	    print "Variant's size is too large ==> Q=0\n" if $DEBUG;
+	}
+
+	if ($DEBUG) {
+	    $mbx = "undef" unless defined $mbx;
+	    printf "Q=%.3f", $Q;
+	    print "  (q=$q, mbx=$mbx, qe=$qe, qc=$qc, ql=$ql, qs=$qs)\n";
+	}
+
+	push(@Q, [$id, $Q, $bs]);
+    }
+
+
+    @Q = sort { $b->[1] <=> $a->[1] || $a->[2] <=> $b->[2] } @Q;
+
+    return @Q if wantarray;
+    return undef unless @Q;
+    return undef if $Q[0][1] == 0;
+    $Q[0][0];
+}
+
+1;
+
+__END__
+
+
+=head1 NAME
+
+choose - choose a variant of a document to serve (HTTP content negotiation)
+
+=head1 SYNOPSIS
+
+ use HTTP::Negotiate;
+
+ #  ID       QS     Content-Type   Encoding Char-Set        Lang   Size
+ $variants =
+  [['var1',  1.000, 'text/html',   undef,   'iso-8859-1',   'en',   3000],
+   ['var2',  0.950, 'text/plain',  'gzip',  'us-ascii',     'no',    400],
+   ['var3',  0.3,   'image/gif',   undef,   undef,          undef, 43555],
+  ];
+
+ @prefered = choose($variants, $request_headers);
+ $the_one  = choose($variants);
+
+=head1 DESCRIPTION
+
+This module provide a complete implementation of the HTTP content
+negotiation algorithm specified in F<draft-ietf-http-v11-spec-00.ps>
+chapter 12.  Content negotiation allows for the selection of a
+preferred content representation based upon attributes of the
+negotiable variants and the value of the various Accept* header fields
+in the request.
+
+The variants are ordered by preference by calling the function
+choose().
+
+The first parameter is a description of the variants that we can
+choose among.  The variants are described by a reference to an array.
+Each element in this array is an array with the values [$id, $qs,
+$content_type, $content_encoding, $charset, $content_language,
+$content_length].  The meaning of these values are described
+below. The $content_encoding and $content_language can be either a
+single scalar value or an array reference if there are several values.
+
+The second optional parameter is a reference to the request headers.
+This is used to look for "Accept*" headers.  You can pass a reference
+to either a HTTP::Request or a HTTP::Headers object.  If this
+parameter is missing, then the accept specification is initialized
+from the CGI environment variables HTTP_ACCEPT, HTTP_ACCEPT_CHARSET,
+HTTP_ACCEPT_ENCODING and HTTP_ACCEPT_LANGUAGE.
+
+In array context, choose() returns a list of variant
+identifier/calculated quality pairs.  The values are sorted by
+quality, highest quality first.  If the calculated quality is the same
+for two variants, then they are sorted by size (smallest first). I<E.g.>:
+
+  (['var1' => 1], ['var2', 0.3], ['var3' => 0]);
+
+Note that also zero quality variants are included in the return list
+even if these should never be served to the client.
+
+In scalar context, it returns the identifier of the variant with the
+highest score or C<undef> if none have non-zero quality.
+
+If the $HTTP::Negotiate::DEBUG variable is set to TRUE, then a lot of
+noise is generated on STDOUT during evaluation of choose().
+
+=head1 VARIANTS
+
+A variant is described by a list of the following values.  If the
+attribute does not make sense or is unknown for a variant, then use
+C<undef> instead.
+
+=over 3
+
+=item identifier
+
+This is just some string that you use as a name for the variant.  The
+identifier of the preferred variant is returned by choose().
+
+=item qs
+
+This is a number between 0.000 and 1.000 that describes the "source
+quality".  This is what F<draft-ietf-http-v11-spec-00.ps> says about this
+value:
+
+Source quality is measured by the content provider as representing the
+amount of degradation from the original source.  For example, a
+picture in JPEG form would have a lower qs when translated to the XBM
+format, and much lower qs when translated to an ASCII-art
+representation.  Note, however, that this is a function of the source
+- an original piece of ASCII-art may degrade in quality if it is
+captured in JPEG form.  The qs values should be assigned to each
+variant by the content provider; if no qs value has been assigned, the
+default is generally "qs=1".
+
+=item content-type
+
+This is the media type of the variant.  The media type does not
+include a charset attribute, but might contain other parameters.
+Examples are:
+
+  text/html
+  text/html;version=2.0
+  text/plain
+  image/gif
+  image/jpg
+
+=item content-encoding
+
+This is one or more content encodings that has been applied to the
+variant.  The content encoding is generally used as a modifier to the
+content media type.  The most common content encodings are:
+
+  gzip
+  compress
+
+=item content-charset
+
+This is the character set used when the variant contains textual
+content.  The charset value should generally be C<undef> or one of these:
+
+  us-ascii
+  iso-8859-1 ... iso-8859-9
+  iso-2022-jp
+  iso-2022-jp-2
+  iso-2022-kr
+  unicode-1-1
+  unicode-1-1-utf-7
+  unicode-1-1-utf-8
+
+=item content-language
+
+This describes one or more languages that are used in the variant.
+Language is described like this in F<draft-ietf-http-v11-spec-00.ps>: A
+language is in this context a natural language spoken, written, or
+otherwise conveyed by human beings for communication of information to
+other human beings.  Computer languages are explicitly excluded.
+
+The language tags are the same as those defined by RFC-1766.  Examples
+are:
+
+  no               Norwegian
+  en               International English
+  en-US            US English
+  en-cockney
+
+=item content-length
+
+This is the number of bytes used to represent the content.
+
+=back
+
+=head1 ACCEPT HEADERS
+
+The following Accept* headers can be used for describing content
+preferences in a request (This description is an edited extract from
+F<draft-ietf-http-v11-spec-00.ps>):
+
+=over 3
+
+=item Accept
+
+This header can be used to indicate a list of media ranges which are
+acceptable as a reponse to the request.  The "*" character is used to
+group media types into ranges, with "*/*" indicating all media types
+and "type/*" indicating all subtypes of that type.
+
+The parameter q is used to indicate the quality factor, which
+represents the user's preference for that range of media types.  The
+parameter mbx gives the maximum acceptable size of the response
+content. The default values are: q=1 and mbx=infinity. If no Accept
+header is present, then the client accepts all media types with q=1.
+
+For example:
+
+  Accept: audio/*;q=0.2;mbx=200000, audio/basic
+
+would mean: "I prefer audio/basic (of any size), but send me any audio
+type if it is the best available after an 80% mark-down in quality and
+its size is less than 200000 bytes"
+
+
+=item Accept-Charset
+
+Used to indicate what character sets are acceptable for the response.
+The "us-ascii" character set is assumed to be acceptable for all user
+agents.  If no Accept-Charset field is given, the default is that any
+charset is acceptable.  Example:
+
+  Accept-Charset: iso-8859-1, unicode-1-1
+
+
+=item Accept-Encoding
+
+Restricts the Content-Encoding values which are acceptable in the
+response.  If no Accept-Encoding field is present, the server may
+assume that the client will accept any content encoding.  An empty
+Accept-Encoding means that no content encoding is acceptable.  Example:
+
+  Accept-Encoding: compress, gzip
+
+
+=item Accept-Language
+
+This field is similar to Accept, but restrict the set of natural
+languages that are preferred as a response.  Each language may be
+given an associated quality value which represents an estimate of the
+user's comprehension of that language.  For example:
+
+  Accept-Language: no, en-gb;q=0.8, de;q=0.55
+
+would mean: "I prefer Norwegian, but will accept British English (with
+80% comprehension) or German (with 55% comprehension).
+
+=back
+
+
+=head1 COPYRIGHT
+
+Copyright 1996, Gisle Aas.
+
+This library is free software; you can redistribute it and/or
+modify it under the same terms as Perl itself.
+
+=head1 AUTHOR
+
+Gisle Aas <aas@sn.no>
+
+=cut
Index: /main/tags/2.25/gsdl/packages/w3mir/libwww-perl-5.36/lib/HTTP/Request.pm
===================================================================
--- /main/tags/2.25/gsdl/packages/w3mir/libwww-perl-5.36/lib/HTTP/Request.pm	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/w3mir/libwww-perl-5.36/lib/HTTP/Request.pm	(revision 21064)
@@ -0,0 +1,160 @@
+#
+# $Id$
+
+package HTTP::Request;
+
+=head1 NAME
+
+HTTP::Request - Class encapsulating HTTP Requests
+
+=head1 SYNOPSIS
+
+ require HTTP::Request;
+ $request = HTTP::Request->new(GET => 'http://www.oslonett.no/');
+
+=head1 DESCRIPTION
+
+C<HTTP::Request> is a class encapsulating HTTP style requests,
+consisting of a request line, some headers, and some (potentially empty)
+content. Note that the LWP library also uses this HTTP style requests
+for non-HTTP protocols.
+
+Instances of this class are usually passed to the C<request()> method
+of an C<LWP::UserAgent> object:
+
+ $ua = LWP::UserAgent->new;
+ $request = HTTP::Request->new(GET => 'http://www.oslonett.no/');
+ $response = $ua->request($request);
+
+C<HTTP::Request> is a subclass of C<HTTP::Message> and therefore
+inherits its methods.  The inherited methods often used are header(),
+push_header(), remove_header(), headers_as_string() and content().
+See L<HTTP::Message> for details.
+
+The following additional methods are available:
+
+=over 4
+
+=cut
+
+require HTTP::Message;
+@ISA = qw(HTTP::Message);
+$VERSION = sprintf("%d.%02d", q$Revision$ =~ /(\d+)\.(\d+)/);
+
+use URI::URL ();
+use strict;
+
+=item $r = HTTP::Request->new($method, $url, [$header, [$content]])
+
+Constructs a new C<HTTP::Request> object describing a request on the
+object C<$url> using method C<$method>.  The C<$url> argument can be
+either a string, or a reference to a C<URI::URL> object.  The $header
+argument should be a reference to an C<HTTP::Headers> object.
+
+=cut
+
+sub new
+{
+    my($class, $method, $url, $header, $content) = @_;
+    my $self = $class->SUPER::new($header, $content);
+    $self->method($method);
+    $self->url($url);
+    $self;
+}
+
+
+sub clone
+{
+    my $self = shift;
+    my $clone = bless $self->SUPER::clone, ref($self);
+    $clone->method($self->method);
+    $clone->url($self->url);
+    $clone;
+}
+
+
+=item $r->method([$val])
+
+=item $r->url([$val])
+
+These methods provide public access to the member variables containing
+respectively the method of the request and the URL object of the
+request.
+
+If an argument is given the member variable is given that as its new
+value. If no argument is given the value is not touched. In either
+case the previous value is returned.
+
+The url() method accept both a reference to a URI::URL object and a
+string as its argument.  If a string is given, then it should be
+parseable as an absolute URL.
+
+=cut
+
+sub method  { shift->_elem('_method', @_); }
+
+sub url
+{
+    my $self = shift;
+    my $old = $self->{'_url'};
+    if (@_) {
+	my $url = shift;
+	if (!defined $url) {
+	    # that's ok
+	} elsif (ref $url) {
+	    $url = $url->abs;
+	} else {
+	    $url = eval { URI::URL->new($url) };
+	}
+	$self->{'_url'} = $url;
+    }
+    $old;
+}
+
+*uri = \&url;  # this is the same for now
+
+=item $r->as_string()
+
+Method returning a textual representation of the request.
+Mainly useful for debugging purposes. It takes no arguments.
+
+=cut
+
+sub as_string
+{
+    my $self = shift;
+    my @result;
+    #push(@result, "---- $self -----");
+    my $req_line = $self->method || "[NO METHOD]";
+    my $url = $self->url;
+    $url = (defined $url) ? $url->as_string : "[NO URL]";
+    $req_line .= " $url";
+    my $proto = $self->protocol;
+    $req_line .= " $proto" if $proto;
+
+    push(@result, $req_line);
+    push(@result, $self->headers_as_string);
+    my $content = $self->content;
+    if (defined $content) {
+	push(@result, $content);
+    }
+    #push(@result, ("-" x 40));
+    join("\n", @result, "");
+}
+
+1;
+
+=back
+
+=head1 SEE ALSO
+
+L<HTTP::Headers>, L<HTTP::Message>, L<HTTP::Request::Common>
+
+=head1 COPYRIGHT
+
+Copyright 1995-1998 Gisle Aas.
+
+This library is free software; you can redistribute it and/or
+modify it under the same terms as Perl itself.
+
+=cut
Index: /main/tags/2.25/gsdl/packages/w3mir/libwww-perl-5.36/lib/HTTP/Request/Common.pm
===================================================================
--- /main/tags/2.25/gsdl/packages/w3mir/libwww-perl-5.36/lib/HTTP/Request/Common.pm	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/w3mir/libwww-perl-5.36/lib/HTTP/Request/Common.pm	(revision 21064)
@@ -0,0 +1,389 @@
+# $Id$
+#
+package HTTP::Request::Common;
+
+use strict;
+use vars qw(@EXPORT @EXPORT_OK $VERSION $DYNAMIC_FILE_UPLOAD);
+
+$DYNAMIC_FILE_UPLOAD ||= 0;  # make it defined (don't know why)
+
+require Exporter;
+*import = \&Exporter::import;
+@EXPORT =qw(GET HEAD PUT POST);
+@EXPORT_OK = qw($DYNAMIC_FILE_UPLOAD);
+
+require HTTP::Request;
+use Carp();
+
+$VERSION = sprintf("%d.%02d", q$Revision$ =~ /(\d+)\.(\d+)/);
+
+my $CRLF = "\015\012";   # "\r\n" is not portable
+
+sub GET  { _simple_req('GET',  @_); }
+sub HEAD { _simple_req('HEAD', @_); }
+sub PUT  { _simple_req('PUT' , @_); }
+
+sub POST
+{
+    my $url = shift;
+    my $req = HTTP::Request->new(POST => $url);
+    my $content;
+    $content = shift if @_ and ref $_[0];
+    my($k, $v);
+    while (($k,$v) = splice(@_, 0, 2)) {
+	if (lc($k) eq 'content') {
+	    $content = $v;
+	} else {
+	    $req->push_header($k, $v);
+	}
+    }
+    my $ct = $req->header('Content-Type');
+    unless ($ct) {
+	$ct = 'application/x-www-form-urlencoded';
+    } elsif ($ct eq 'form-data') {
+	$ct = 'multipart/form-data';
+    }
+
+    if (ref $content) {
+	if (lc($ct) eq 'multipart/form-data') {    #XXX: boundary="..."
+	    my $boundary;
+	    ($content, $boundary) = form_data($content, $boundary);
+	    $boundary = qq("$boundary") if $boundary =~ /\W/;
+	    $ct = qq(multipart/form-data; boundary=$boundary);
+	} else {
+	    # We use a temporary URI::URL object to format
+	    # the application/x-www-form-urlencoded content.
+	    require URI::URL;
+	    my $url = URI::URL->new('http:');
+	    $url->query_form(ref($content) eq "HASH" ? %$content : @$content);
+	    $content = $url->equery;
+	}
+    }
+
+    $req->header('Content-Type' => $ct);  # might be redundant
+    if (defined($content)) {
+	$req->header('Content-Length' =>
+		     length($content)) unless ref($content);
+	$req->content($content);
+    }
+    $req;
+}
+
+
+sub _simple_req
+{
+    my($method, $url) = splice(@_, 0, 2);
+    my $req = HTTP::Request->new($method => $url);
+    my($k, $v);
+    while (($k,$v) = splice(@_, 0, 2)) {
+	if (lc($k) eq 'content') {
+	    $req->add_content($v);
+	} else {
+	    $req->push_header($k, $v);
+	}
+    }
+    $req;
+}
+
+
+sub form_data   # RFC1867
+{
+    my($data, $boundary) = @_;
+    my @data = ref($data) eq "HASH" ? %$data : @$data;  # copy
+    my $fhparts;
+    my @parts;
+    my($k,$v);
+    while (($k,$v) = splice(@data, 0, 2)) {
+	if (!ref($v)) {
+	    $k =~ s/([\\\"])/\\$1/g;  # escape quotes and backslashes
+	    push(@parts,
+		 qq(Content-Disposition: form-data; name="$k"$CRLF$CRLF$v));
+	} else {
+	    my($file, $usename, @headers) = @$v;
+	    unless (defined $usename) {
+		$usename = $file;
+		$usename =~ s,.*/,, if defined($usename);
+	    }
+	    my $disp = qq(form-data; name="$k");
+	    $disp .= qq(; filename="$usename") if $usename;
+	    my $content = "";
+	    my $h = HTTP::Headers->new(@headers);
+	    my $ct = $h->header("Content-Type");
+	    if ($file) {
+		require Symbol;
+		my $fh = Symbol::gensym();
+		open($fh, $file) or Carp::croak("Can't open file $file: $!");
+		binmode($fh);
+		if ($DYNAMIC_FILE_UPLOAD) {
+		    # will read file later
+		    $content = $fh;
+		} else {
+		    local($/) = undef; # slurp files
+		    $content = <$fh>;
+		    close($fh);
+		    $h->header("Content-Length" => length($content));
+		}
+		unless ($ct) {
+		    require LWP::MediaTypes;
+		    $ct = LWP::MediaTypes::guess_media_type($file, $h);
+		}
+	    }
+	    if ($h->header("Content-Disposition")) {
+		# just to get it sorted first
+		$disp = $h->header("Content-Disposition");
+		$h->remove_header("Content-Disposition");
+	    }
+	    if ($h->header("Content")) {
+		$content = $h->header("Content");
+		$h->remove_header("Content");
+	    }
+	    my $head = join($CRLF, "Content-Disposition: $disp",
+			           $h->as_string($CRLF),
+			           "");
+	    if (ref $content) {
+		push(@parts, [$head, $content]);
+		$fhparts++;
+	    } else {
+		push(@parts, $head . $content);
+	    }
+	}
+    }
+    return "" unless @parts;
+
+    my $content;
+    if ($fhparts) {
+	$boundary = boundary(10) # hopefully enough randomness
+	    unless $boundary;
+
+	# add the boundaries to the @parts array
+	for (1..@parts-1) {
+	    splice(@parts, $_*2-1, 0, "$CRLF--$boundary$CRLF");
+	}
+	unshift(@parts, "--$boundary$CRLF");
+	push(@parts, "$CRLF--$boundary--$CRLF");
+
+	# set up a closure that will return content piecemeal
+	$content = sub {
+	    for (;;) {
+		return unless @parts;
+		my $p = shift @parts;
+		unless (ref $p) {
+		    $p .= shift @parts while @parts && !ref($parts[0]);
+		    return $p;
+		}
+		my($buf, $fh) = @$p;
+		my $n = read($fh, $buf, 2048, length($buf));
+		if ($n) {
+		    unshift(@parts, ["", $fh]);
+		} else {
+		    close($fh);
+		}
+		return $buf if length $buf;
+	    }
+	};
+
+    } else {
+	$boundary = boundary() unless $boundary;
+
+	my $bno = 0;
+      CHECK_BOUNDARY:
+	{
+	    for (@parts) {
+		if (index($_, "--$boundary") >= 0) {
+		    # must have a better boundary
+		    #warn "Need something better that '$boundary' as boundary\n";
+		    $boundary = boundary(++$bno);
+		    redo CHECK_BOUNDARY;
+		}
+	    }
+	    last;
+	}
+	$content = "--$boundary$CRLF" .
+	           join("$CRLF--$boundary$CRLF", @parts) .
+		   "$CRLF--$boundary--$CRLF";
+    }
+
+    wantarray ? ($content, $boundary) : $content;
+}
+
+
+sub boundary
+{
+    my $size = shift || return "000";
+    require MIME::Base64;
+    my $b = MIME::Base64::encode(join("", map chr(rand(256)), 1..$size*3), "");
+    $b =~ s/[\W]/X/g;  # ensure alnum only
+    $b;
+}
+
+1;
+
+__END__
+
+=head1 NAME
+
+HTTP::Request::Common - Construct common HTTP::Request objects
+
+=head1 SYNOPSIS
+
+  use HTTP::Request::Common;
+  $ua = LWP::UserAgent->new;
+  $ua->request(GET 'http://www.sn.no/');
+  $ua->request(POST 'http://somewhere/foo', [foo => bar, bar => foo]);
+
+=head1 DESCRIPTION
+
+This module provide functions that return newly created HTTP::Request
+objects.  These functions are usually more convenient to use than the
+standard HTTP::Request constructor for these common requests.  The
+following functions are provided.
+
+=over 4
+
+=item GET $url, Header => Value,...
+
+The GET() function returns a HTTP::Request object initialized with the
+GET method and the specified URL.  Without additional arguments it
+is exactly equivalent to the following call
+
+  HTTP::Request->new(GET => $url)
+
+but is less clutter.  It also reads better when used together with the
+LWP::UserAgent->request() method:
+
+  my $ua = new LWP::UserAgent;
+  my $res = $ua->request(GET 'http://www.sn.no')
+  if ($res->is_success) { ...
+
+You can also initialize the header values in the request by specifying
+some key/value pairs as optional arguments.  For instance:
+
+  $ua->request(GET 'http://www.sn.no',
+	           If_Match => 'foo',
+                   From     => 'gisle@aas.no',
+              );
+
+A header key called 'Content' is special and when seen the value will
+initialize the content part of the request instead of setting a header.
+
+=item HEAD $url, [Header => Value,...]
+
+Like GET() but the method in the request is HEAD.
+
+=item PUT $url, [Header => Value,...]
+
+Like GET() but the method in the request is PUT.
+
+=item POST $url, [$form_ref], [Header => Value,...]
+
+This works mostly like GET() with POST as method, but this function
+also takes a second optional array or hash reference parameter
+($form_ref).  This argument can be used to pass key/value pairs for
+the form content.  By default we will initialize a request using the
+C<application/x-www-form-urlencoded> content type.  This means that
+you can emulate a HTML E<lt>form> POSTing like this:
+
+  POST 'http://www.perl.org/survey.cgi',
+       [ name   => 'Gisle Aas',
+         email  => 'gisle@aas.no',
+         gender => 'M',
+         born   => '1964',
+         perc   => '3%',
+       ];
+
+This will create a HTTP::Request object that looks like this:
+
+  POST http://www.perl.org/survey.cgi
+  Content-Length: 66
+  Content-Type: application/x-www-form-urlencoded
+
+  name=Gisle%20Aas&email=gisle%40aas.no&gender=M&born=1964&perc=3%25
+
+The POST method also supports the C<multipart/form-data> content used
+for I<Form-based File Upload> as specified in RFC 1867.  You trigger
+this content format by specifying a content type of C<'form-data'> as
+one of the request headers.  If one of the values in the $form_ref is
+an array reference, then it is treated as a file part specification
+with the following interpretation:
+
+  [ $file, $filename, Header => Value... ]
+
+The first value in the array ($file) is the name of a file to open.
+This file will be read an its content placed in the request.  The
+routine will croak if the file can't be opened.  Use an C<undef> as $file
+value if you want to specify the content directly.  The $filename is
+the filename to report in the request.  If this value is undefined,
+then the basename of the $file will be used.  You can specify an empty
+string as $filename if you don't want any filename in the request.
+
+Sending my F<~/.profile> to the survey used as example above can be
+achieved by this:
+
+  POST 'http://www.perl.org/survey.cgi',
+       Content_Type => 'form-data',
+       Content      => [ name  => 'Gisle Aas',
+                         email => 'gisle@aas.no',
+                         gender => 'M',
+                         born   => '1964',
+                         init   => ["$ENV{HOME}/.profile"],
+                       ]
+
+This will create a HTTP::Request object that almost looks this (the
+boundary and the content of your F<~/.profile> is likely to be
+different):
+
+  POST http://www.perl.org/survey.cgi
+  Content-Length: 388
+  Content-Type: multipart/form-data; boundary="6G+f"
+
+  --6G+f
+  Content-Disposition: form-data; name="name"
+  
+  Gisle Aas
+  --6G+f
+  Content-Disposition: form-data; name="email"
+  
+  gisle@aas.no
+  --6G+f
+  Content-Disposition: form-data; name="gender"
+  
+  M
+  --6G+f
+  Content-Disposition: form-data; name="born"
+  
+  1964
+  --6G+f
+  Content-Disposition: form-data; name="init"; filename=".profile"
+  Content-Type: text/plain
+  
+  PATH=/local/perl/bin:$PATH
+  export PATH
+
+  --6G+f--
+
+If you set the $DYNAMIC_FILE_UPLOAD variable (exportable) to some TRUE
+value, then you get back a request object with a subroutine closure as
+the content attribute.  This subroutine will read the content of any
+files on demand and return it in suitable chunks.  This allow you to
+upload arbitrary big files without using lots of memory.  You can even
+upload infinite files like F</dev/audio> if you wish.  Another
+difference is that there will be no Content-Length header defined for
+the request if you use this feature.  Not all servers (or server
+applications) like this.
+
+=back
+
+=head1 SEE ALSO
+
+L<HTTP::Request>, L<LWP::UserAgent>
+
+
+=head1 COPYRIGHT
+
+Copyright 1997-1998, Gisle Aas
+
+This library is free software; you can redistribute it and/or
+modify it under the same terms as Perl itself.
+
+=cut
+
Index: /main/tags/2.25/gsdl/packages/w3mir/libwww-perl-5.36/lib/HTTP/Response.pm
===================================================================
--- /main/tags/2.25/gsdl/packages/w3mir/libwww-perl-5.36/lib/HTTP/Response.pm	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/w3mir/libwww-perl-5.36/lib/HTTP/Response.pm	(revision 21064)
@@ -0,0 +1,396 @@
+#
+# $Id$
+
+package HTTP::Response;
+
+
+=head1 NAME
+
+HTTP::Response - Class encapsulating HTTP Responses
+
+=head1 SYNOPSIS
+
+ require HTTP::Response;
+
+=head1 DESCRIPTION
+
+The C<HTTP::Response> class encapsulate HTTP style responses.  A
+response consist of a response line, some headers, and a (potential
+empty) content. Note that the LWP library will use HTTP style
+responses also for non-HTTP protocol schemes.
+
+Instances of this class are usually created and returned by the
+C<request()> method of an C<LWP::UserAgent> object:
+
+ #...
+ $response = $ua->request($request)
+ if ($response->is_success) {
+     print $response->content;
+ } else {
+     print $response->error_as_HTML;
+ }
+
+C<HTTP::Response> is a subclass of C<HTTP::Message> and therefore
+inherits its methods.  The inherited methods often used are header(),
+push_header(), remove_header(), headers_as_string(), and content().
+The header convenience methods are also available.  See
+L<HTTP::Message> for details.
+
+The following additional methods are available:
+
+=over 4
+
+=cut
+
+
+require HTTP::Message;
+@ISA = qw(HTTP::Message);
+$VERSION = sprintf("%d.%02d", q$Revision$ =~ /(\d+)\.(\d+)/);
+
+use HTTP::Status ();
+use URI::URL ();
+use strict;
+
+
+=item $r = HTTP::Response->new($rc, [$msg, [$header, [$content]]])
+
+Constructs a new C<HTTP::Response> object describing a response with
+response code C<$rc> and optional message C<$msg>.  The message is a
+short human readable single line string that explains the response
+code.
+
+=cut
+
+sub new
+{
+    my($class, $rc, $msg, $header, $content) = @_;
+    my $self = $class->SUPER::new($header, $content);
+    $self->code($rc);
+    $self->message($msg);
+    $self;
+}
+
+
+sub clone
+{
+    my $self = shift;
+    my $clone = bless $self->SUPER::clone, ref($self);
+    $clone->code($self->code);
+    $clone->message($self->message);
+    $clone->request($self->request->clone) if $self->request;
+    # we don't clone previous
+    $clone;
+}
+
+=item $r->code([$code])
+
+=item $r->message([$message])
+
+=item $r->request([$request])
+
+=item $r->previous([$previousResponse])
+
+These methods provide public access to the member variables.  The
+first two containing respectively the response code and the message
+of the response.
+
+The request attribute is a reference the request that gave this
+response.  It does not have to be the same request as passed to the
+$ua->request() method, because there might have been redirects and
+authorization retries in between.
+
+The previous attribute is used to link together chains of responses.
+You get chains of responses if the first response is redirect or
+unauthorized.
+
+=cut
+
+sub code      { shift->_elem('_rc',      @_); }
+sub message   { shift->_elem('_msg',     @_); }
+sub previous  { shift->_elem('_previous',@_); }
+sub request   { shift->_elem('_request', @_); }
+
+=item $r->status_line
+
+Returns the string "E<lt>code> E<lt>message>".  If the message attribute
+is not set then the official name of E<lt>code> (see L<HTTP::Status>)
+is substituted.
+
+=cut
+
+sub status_line
+{
+    my $self = shift;
+    my $code = $self->{'_rc'}  || "000";
+    my $mess = $self->{'_msg'} || HTTP::Status::status_message($code) || "?";
+    return "$code $mess";
+}
+
+=item $r->base
+
+Returns the base URL for this response.  The return value will be a
+reference to a URI::URL object.
+
+The base URL is obtained from one the following sources (in priority
+order):
+
+=over 4
+
+=item 1.
+
+Embedded in the document content, for instance <BASE HREF="...">
+in HTML documents.
+
+=item 2.
+
+A "Content-Base:" or a "Content-Location:" header in the response.
+
+For backwards compatability with older HTTP implementations we will
+also look for the "Base:" header.
+
+
+=item 3.
+
+The URL used to request this response. This might not be the original
+URL that was passed to $ua->request() method, because we might have
+received some redirect responses first.
+
+=back
+
+When the LWP protocol modules produce the HTTP::Response object, then
+any base URL embedded in the document (step 1) will already have
+initialized the "Content-Base:" header. This means that this method
+only perform the last 2 steps (the content is not always available
+either).
+
+=cut
+
+sub base
+{
+    my $self = shift;
+    my $base = $self->header('Content-Base')     ||  # HTTP/1.1
+               $self->header('Content-Location') ||  # HTTP/1.1
+               $self->header('Base')             ||  # backwards compatability HTTP/1.0
+               $self->request->url;
+    $base = URI::URL->new($base) unless ref $base;
+    $base;
+}
+
+
+=item $r->as_string
+
+Method returning a textual representation of the response.  Mainly
+useful for debugging purposes. It takes no arguments.
+
+=cut
+
+sub as_string
+{
+    require HTTP::Status;
+    my $self = shift;
+    my @result;
+    #push(@result, "---- $self ----");
+    my $code = $self->code;
+    my $status_message = HTTP::Status::status_message($code) || "Unknown code";
+    my $message = $self->message || "";
+
+    my $status_line = "$code";
+    my $proto = $self->protocol;
+    $status_line = "$proto $status_line" if $proto;
+    $status_line .= " ($status_message)" if $status_message ne $message;
+    $status_line .= " $message";
+    push(@result, $status_line);
+    push(@result, $self->headers_as_string);
+    my $content = $self->content;
+    if (defined $content) {
+	push(@result, $content);
+    }
+    #push(@result, ("-" x 40));
+    join("\n", @result, "");
+}
+
+=item $r->is_info
+
+=item $r->is_success
+
+=item $r->is_redirect
+
+=item $r->is_error
+
+These methods indicate if the response was informational, sucessful, a
+redirection, or an error.
+
+=cut
+
+sub is_info     { HTTP::Status::is_info     (shift->{'_rc'}); }
+sub is_success  { HTTP::Status::is_success  (shift->{'_rc'}); }
+sub is_redirect { HTTP::Status::is_redirect (shift->{'_rc'}); }
+sub is_error    { HTTP::Status::is_error    (shift->{'_rc'}); }
+
+
+=item $r->error_as_HTML()
+
+Return a string containing a complete HTML document indicating what
+error occurred.  This method should only be called when $r->is_error
+is TRUE.
+
+=cut
+
+sub error_as_HTML
+{
+    my $self = shift;
+    my $title = 'An Error Occurred';
+    my $body  = $self->status_line;
+    return <<EOM;
+<HTML>
+<HEAD><TITLE>$title</TITLE></HEAD>
+<BODY>
+<H1>$title</h1>
+$body
+</BODY>
+</HTML>
+EOM
+}
+
+
+=item $r->current_age
+
+This function will calculate the "current age" of the response as
+specified by E<lt>draft-ietf-http-v11-spec-07> section 13.2.3.  The
+age of a response is the time since it was sent by the origin server.
+The returned value is a number representing the age in seconds.
+
+=cut
+
+sub current_age
+{
+    my $self = shift;
+    # Implementation of <draft-ietf-http-v11-spec-07> section 13.2.3
+    # (age calculations)
+    my $response_time = $self->client_date;
+    my $date = $self->date;
+
+    my $age = 0;
+    if ($response_time && $date) {
+	$age = $response_time - $date;  # apparent_age
+	$age = 0 if $age < 0;
+    }
+
+    my $age_v = $self->header('Age');
+    if ($age_v && $age_v > $age) {
+	$age = $age_v;   # corrected_received_age
+    }
+
+    my $request = $self->request;
+    if ($request) {
+	my $request_time = $request->date;
+	if ($request_time) {
+	    # Add response_delay to age to get 'corrected_initial_age'
+	    $age += $response_time - $request_time;
+	}
+    }
+    if ($response_time) {
+	$age += time - $response_time;
+    }
+    return $age;
+}
+
+
+=item $r->freshness_lifetime
+
+This function will calculate the "freshness lifetime" of the response
+as specified by E<lt>draft-ietf-http-v11-spec-07> section 13.2.4.  The
+"freshness lifetime" is the length of time between the generation of a
+response and its expiration time.  The returned value is a number
+representing the freshness lifetime in seconds.
+
+If the response does not contain an "Expires" or a "Cache-Control"
+header, then this function will apply some simple heuristic based on
+'Last-Modified' to determine a suitable lifetime.
+
+=cut
+
+sub freshness_lifetime
+{
+    my $self = shift;
+
+    # First look for the Cache-Control: max-age=n header
+    my @cc = $self->header('Cache-Control');
+    if (@cc) {
+	my $cc;
+	for $cc (@cc) {
+	    my $cc_dir;
+	    for $cc_dir (split(/\s*,\s*/, $cc)) {
+		if ($cc_dir =~ /max-age\s*=\s*(\d+)/i) {
+		    return $1;
+		}
+	    }
+	}
+    }
+
+    # Next possibility is to look at the "Expires" header
+    my $date = $self->date || $self->client_date || time;      
+    my $expires = $self->expires;
+    unless ($expires) {
+	# Must apply heuristic expiration
+	my $last_modified = $self->last_modified;
+	if ($last_modified) {
+	    my $h_exp = ($date - $last_modified) * 0.10;  # 10% since last-mod
+	    if ($h_exp < 60) {
+		return 60;  # minimum
+	    } elsif ($h_exp > 24 * 3600) {
+		# Should give a warning if more than 24 hours according to
+		# <draft-ietf-http-v11-spec-07> section 13.2.4, but I don't
+		# know how to do it from this function interface, so I just
+		# make this the maximum value.
+		return 24 * 3600;
+	    }
+	    return $h_exp;
+	} else {
+	    return 3600;  # 1 hour is fallback when all else fails
+	}
+    }
+    return $expires - $date;
+}
+
+
+=item $r->is_fresh
+
+Returns TRUE if the response is fresh, based on the values of
+freshness_lifetime() and current_age().  If the response is not longer
+fresh, then it has to be refetched or revalidated by the origin
+server.
+
+=cut
+
+sub is_fresh
+{
+    my $self = shift;
+    $self->freshness_lifetime > $self->current_age;
+}
+
+
+=item $r->fresh_until
+
+Returns the time when this entiy is no longer fresh.
+
+=cut
+
+sub fresh_until
+{
+    my $self = shift;
+    return $self->freshness_lifetime - $self->current_age + time;
+}
+
+1;
+
+=back 
+
+=head1 COPYRIGHT
+
+Copyright 1995-1997 Gisle Aas.
+
+This library is free software; you can redistribute it and/or
+modify it under the same terms as Perl itself.
+
+=cut
Index: /main/tags/2.25/gsdl/packages/w3mir/libwww-perl-5.36/lib/HTTP/Status.pm
===================================================================
--- /main/tags/2.25/gsdl/packages/w3mir/libwww-perl-5.36/lib/HTTP/Status.pm	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/w3mir/libwww-perl-5.36/lib/HTTP/Status.pm	(revision 21064)
@@ -0,0 +1,233 @@
+#
+# $Id$
+
+package HTTP::Status;
+
+use strict;
+require 5.002;   # becase we use prototypes
+
+=head1 NAME
+
+HTTP::Status - HTTP Status code processing
+
+=head1 SYNOPSIS
+
+ use HTTP::Status;
+
+ if ($rc != RC_OK) {
+     print status_message($rc), "\n";
+ }
+
+ if (is_success($rc)) { ... }
+ if (is_error($rc)) { ... }
+ if (is_redirect($rc)) { ... }
+
+=head1 DESCRIPTION
+
+I<HTTP::Status> is a library of routines for defining and
+classification of HTTP status codes for libwww-perl.  Status codes are
+used to encode the overall outcome of a HTTP response message.  Codes
+correspond to those defined in F<draft-ietf-http-v11-spec-rev-03> (an
+update to RFC 2068).
+
+=head1 CONSTANTS
+
+The following constant functions can be used as mnemonic status code
+names:
+
+   RC_CONTINUE				(100)
+   RC_SWITCHING_PROTOCOLS		(101)
+
+   RC_OK				(200)
+   RC_CREATED				(201)
+   RC_ACCEPTED				(202)
+   RC_NON_AUTHORITATIVE_INFORMATION	(203)
+   RC_NO_CONTENT			(204)
+   RC_RESET_CONTENT			(205)
+   RC_PARTIAL_CONTENT			(206)
+
+   RC_MULTIPLE_CHOICES			(300)
+   RC_MOVED_PERMANENTLY			(301)
+   RC_FOUND				(302)
+   RC_SEE_OTHER				(303)
+   RC_NOT_MODIFIED			(304)
+   RC_USE_PROXY				(305)
+   RC_TEMPORARY_REDIRECT		(307)
+
+   RC_BAD_REQUEST			(400)
+   RC_UNAUTHORIZED			(401)
+   RC_PAYMENT_REQUIRED			(402)
+   RC_FORBIDDEN				(403)
+   RC_NOT_FOUND				(404)
+   RC_METHOD_NOT_ALLOWED		(405)
+   RC_NOT_ACCEPTABLE			(406)
+   RC_PROXY_AUTHENTICATION_REQUIRED	(407)
+   RC_REQUEST_TIMEOUT			(408)
+   RC_CONFLICT				(409)
+   RC_GONE				(410)
+   RC_LENGTH_REQUIRED			(411)
+   RC_PRECONDITION_FAILED		(412)
+   RC_REQUEST_ENTITY_TOO_LARGE		(413)
+   RC_REQUEST_URI_TOO_LARGE		(414)
+   RC_UNSUPPORTED_MEDIA_TYPE		(415)
+   RC_REQUEST_RANGE_NOT_SATISFIABLE     (416)
+   RC_EXPECTATION_FAILED		(417)
+
+   RC_INTERNAL_SERVER_ERROR		(500)
+   RC_NOT_IMPLEMENTED			(501)
+   RC_BAD_GATEWAY			(502)
+   RC_SERVICE_UNAVAILABLE		(503)
+   RC_GATEWAY_TIMEOUT			(504)
+   RC_HTTP_VERSION_NOT_SUPPORTED	(505)
+
+=cut
+
+#####################################################################
+
+use vars qw(@ISA @EXPORT @EXPORT_OK $VERSION);
+
+require Exporter;
+@ISA = qw(Exporter);
+@EXPORT = qw(is_info is_success is_redirect is_error status_message);
+@EXPORT_OK = qw(is_client_error is_server_error);
+$VERSION = sprintf("%d.%02d", q$Revision$ =~ /(\d+)\.(\d+)/);
+
+# Note also addition of mnemonics to @EXPORT below
+
+my %StatusCode = (
+    100 => 'Continue',
+    101 => 'Switching Protocols',
+    200 => 'OK',
+    201 => 'Created',
+    202 => 'Accepted',
+    203 => 'Non-Authoritative Information',
+    204 => 'No Content',
+    205 => 'Reset Content',
+    206 => 'Partial Content',
+    300 => 'Multiple Choices',
+    301 => 'Moved Permanently',
+    302 => 'Found',
+    303 => 'See Other',
+    304 => 'Not Modified',
+    305 => 'Use Proxy',
+    307 => 'Temporary Redirect',
+    400 => 'Bad Request',
+    401 => 'Unauthorized',
+    402 => 'Payment Required',
+    403 => 'Forbidden',
+    404 => 'Not Found',
+    405 => 'Method Not Allowed',
+    406 => 'Not Acceptable',
+    407 => 'Proxy Authentication Required',
+    408 => 'Request Timeout',
+    409 => 'Conflict',
+    410 => 'Gone',
+    411 => 'Length Required',
+    412 => 'Precondition Failed',
+    413 => 'Request Entity Too Large',
+    414 => 'Request-URI Too Large',
+    415 => 'Unsupported Media Type',
+    416 => 'Request Range Not Satisfiable',
+    417 => 'Expectation Failed',
+    500 => 'Internal Server Error',
+    501 => 'Not Implemented',
+    502 => 'Bad Gateway',
+    503 => 'Service Unavailable',
+    504 => 'Gateway Timeout',
+    505 => 'HTTP Version Not Supported',
+);
+
+my $mnemonicCode = '';
+my ($code, $message);
+while (($code, $message) = each %StatusCode) {
+    # create mnemonic subroutines
+    $message =~ tr/a-z \-/A-Z__/;
+    $mnemonicCode .= "sub RC_$message () { $code }\t";
+    # make them exportable
+    $mnemonicCode .= "push(\@EXPORT, 'RC_$message');\n";
+}
+# warn $mnemonicCode; # for development
+eval $mnemonicCode; # only one eval for speed
+die if $@;
+
+# backwards compatibility
+*RC_MOVED_TEMPORARILY = \&RC_FOUND;  # 302 was renamed in the standard
+push(@EXPORT, "RC_MOVED_TEMPORARILY");
+
+
+=head1 FUNCTIONS
+
+The following additional functions are provided.  Most of them are
+exported by default.
+
+=over 4
+
+=item status_message($code)
+
+The status_message() function will translate status codes to human
+readable strings. The string is the same as found in the constant
+names above.  If the $code is unknown, then C<undef> is returned.
+
+=cut
+
+sub status_message ($)
+{
+    $StatusCode{$_[0]};
+}
+
+=item is_info($code)
+
+Return TRUE if C<$code> is an I<Informational> status code.  This
+class of status code indicates a provisional response which can't have
+any content.
+
+=item is_success($code)
+
+Return TRUE if C<$code> is a I<Successful> status code.
+
+=item is_redirect($code)
+
+Return TRUE if C<$code> is a I<Redirection> status code. This class of
+status code indicates that further action needs to be taken by the
+user agent in order to fulfill the request.
+
+=item is_error($code)
+
+Return TRUE if C<$code> is an I<Error> status code.  The function
+return TRUE for both client error or a server error status codes.
+
+=item is_client_error($code)
+
+Return TRUE if C<$code> is an I<Client Error> status code. This class
+of status code is intended for cases in which the client seems to have
+erred.
+
+This function is B<not> exported by default.
+
+=item is_server_error($code)
+
+Return TRUE if C<$code> is an I<Server Error> status code. This class
+of status codes is intended for cases in which the server is aware
+that it has erred or is incapable of performing the request.
+
+This function is B<not> exported by default.
+
+=back
+
+=cut
+
+sub is_info         ($) { $_[0] >= 100 && $_[0] < 200; }
+sub is_success      ($) { $_[0] >= 200 && $_[0] < 300; }
+sub is_redirect     ($) { $_[0] >= 300 && $_[0] < 400; }
+sub is_error        ($) { $_[0] >= 400 && $_[0] < 600; }
+sub is_client_error ($) { $_[0] >= 400 && $_[0] < 500; }
+sub is_server_error ($) { $_[0] >= 500 && $_[0] < 600; }
+
+1;
+
+=head1 BUGS
+
+Wished @EXPORT_OK had been used instead of @EXPORT in the beginning.
+Now too much is exported by default.
+
+=cut
Index: /main/tags/2.25/gsdl/packages/w3mir/libwww-perl-5.36/lib/LWP.pm
===================================================================
--- /main/tags/2.25/gsdl/packages/w3mir/libwww-perl-5.36/lib/LWP.pm	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/w3mir/libwww-perl-5.36/lib/LWP.pm	(revision 21064)
@@ -0,0 +1,593 @@
+#
+# $Id$
+
+package LWP;
+
+$VERSION = "5.36";
+sub Version { $VERSION; }
+
+require 5.004;
+require LWP::UserAgent;  # this should load everything you need
+
+1;
+
+__END__
+
+=head1 NAME
+
+LWP - Library for WWW access in Perl
+
+=head1 SYNOPSIS
+
+  use LWP;
+  print "This is libwww-perl-$LWP::VERSION\n";
+
+
+=head1 DESCRIPTION
+
+Libwww-perl is a collection of Perl modules which provides a simple
+and consistent programming interface (API) to the World-Wide Web.  The
+main focus of the library is to provide classes and functions that
+allow you to write WWW clients, thus libwww-perl said to be a WWW
+client library. The library also contain modules that are of more
+general use.
+
+Most modules in this library are object oriented.  The user
+agent, requests sent and responses received from the WWW server are
+all represented by objects.  This makes a simple and powerful
+interface to these services.  The interface should be easy to extend
+and customize for your needs.
+
+The main features of the library are:
+
+=over 3
+
+=item *
+
+Contains various reusable components (modules) that can be
+used separately or together.
+
+=item *
+
+Provides an object oriented model of HTTP-style communication.  Within
+this framework we currently support access to http, https, gopher, ftp, news,
+file, and mailto resources.
+
+=item *
+
+The library be used through the full object oriented interface or
+through a very simple procedural interface.
+
+=item *
+
+Support the basic and digest authorization schemes.
+
+=item *
+
+Transparent redirect handling.
+
+=item *
+
+Supports access through proxy servers.
+
+=item *
+
+URL handling (both absolute and relative URLs are supported).
+
+=item *
+
+A parser for F<robots.txt> files and a framework for constructing robots.
+
+=item *
+
+The library can cooperate with Tk.  A simple Tk-based GUI browser
+called 'tkweb' is distributed with the Tk extension for perl.
+
+=item *
+
+An implementation of the HTTP content negotiation algorithm that can
+be used both in protocol modules and in server scripts (like CGI
+scripts).
+
+=item *
+
+It can deal with HTTP cookies.
+
+=item *
+
+A simple command line client application called C<lwp-request>.
+
+=back
+
+
+=head1 HTTP STYLE COMMUNICATION
+
+
+The libwww-perl library is based on HTTP style communication. This
+section try to describe what that means.
+
+Let us start with this quote from the HTTP specification document
+<URL:http://www.w3.org/pub/WWW/Protocols/>:
+
+=over 3
+
+=item
+
+The HTTP protocol is based on a request/response paradigm. A client
+establishes a connection with a server and sends a request to the
+server in the form of a request method, URI, and protocol version,
+followed by a MIME-like message containing request modifiers, client
+information, and possible body content. The server responds with a
+status line, including the message's protocol version and a success or
+error code, followed by a MIME-like message containing server
+information, entity meta-information, and possible body content.
+
+=back
+
+What this means to libwww-perl is that communication always take place
+through these steps: First a I<request> object is created and
+configured. This object is then passed to a server and we get a
+I<response> object in return that we can examine. A request is always
+independent of any previous requests, i.e. the service is stateless.
+The same simple model is used for any kind of service we want to
+access.
+
+For example, if we want to fetch a document from a remote file server,
+then we send it a request that contains a name for that document and
+the response will contain the document itself.  If we access a search
+engine, then the content of the request will contain the query
+parameters and the response will contain the query result.  If we want
+to send a mail message to somebody then we send a request object which
+contains our message to the mail server and the response object will
+contain an acknowledgment that tells us that the message has been
+accepted and will be forwarded to the recipient(s).
+
+It is as simple as that!
+
+
+=head2 The Request Object
+
+The request object has the class name C<HTTP::Request> in
+libwww-perl. The fact that the class name use C<HTTP::> as a name
+prefix only implies that we use the HTTP model of communication. It
+does not limit the kind of services we can try to pass this I<request>
+to.  For instance, we will send C<HTTP::Request>s both to ftp and
+gopher servers, as well as to the local file system.
+
+The main attributes of the request objects are:
+
+=over 3
+
+=item *
+
+The B<method> is a short string that tells what kind of
+request this is.  The most used methods are B<GET>, B<PUT>,
+B<POST> and B<HEAD>.
+
+=item *
+
+The B<url> is a string denoting the protocol, server and
+the name of the "document" we want to access.  The B<url> might
+also encode various other parameters.
+
+=item *
+
+The B<headers> contain additional information about the
+request and can also used to describe the content.  The headers
+is a set of keyword/value pairs.
+
+=item *
+
+The B<content> is an arbitrary amount of data.
+
+=back
+
+=head2 The Response Object
+
+The response object has the class name C<HTTP::Response> in
+libwww-perl.  The main attributes of objects of this class are:
+
+=over 3
+
+=item *
+
+The B<code> is a numerical value that encode the overall
+outcome of the request.
+
+=item *
+
+The B<message> is a short (human readable) string that
+corresponds to the I<code>.
+
+=item *
+
+The B<headers> contain additional information about the
+response and they also describe the content.
+
+=item *
+
+The B<content> is an arbitrary amount of data.
+
+=back
+
+Since we don't want to handle all possible I<code> values directly in
+our programs, the libwww-perl response object have methods that can be
+used to query what kind of response this is.  The most commonly used
+response classification methods are:
+
+=over 3
+
+=item is_success()
+
+The request was was successfully received, understood or accepted.
+
+=item is_error()
+
+The request failed.  The server or the resource might not be
+available, access to the resource might be denied or other things might
+have failed for some reason.
+
+=back
+
+=head2 The User Agent
+
+Let us assume that we have created a I<request> object. What do we
+actually do with it in order to receive a I<response>?
+
+The answer is that you pass it on to a I<user agent> object and this
+object will take care of all the things that need to be done
+(low-level communication and error handling). The user agent will give
+you back a I<response> object. The user agent represents your
+application on the network and it provides you with an interface that
+can accept I<requests> and will return I<responses>.
+
+You should think about the user agent as an interface layer between
+your application code and the network.  Through this interface you are
+able to access the various servers on the network.
+
+The libwww-perl class name for the user agent is
+C<LWP::UserAgent>. Every libwww-perl application that wants to
+communicate should create at least one object of this kind. The main
+method provided by this object is request(). This method takes an
+C<HTTP::Request> object as argument and will (eventually) return a
+C<HTTP::Response> object.
+
+The user agent has many other attributes that lets you
+configure how it will interact with the network and with your
+application code.
+
+=over 3
+
+=item *
+
+The B<timeout> specify how much time we give remote servers in
+creating responses before the library disconnect and creates an
+internal I<timeout> response.
+
+=item *
+
+The B<agent> specify the name that your application should use when it
+presents itself on the network.
+
+=item *
+
+The B<from> attribute can be set to the e-mail address of the person
+responsible for running the application.  If this is set, then the
+address will be sent to the servers with every request.
+
+=item *
+
+The B<parse_head> specify whether we should initialize response
+headers from the E<lt>head> section of HTML documents.
+
+=item *
+
+The B<proxy> and B<no_proxy> specify if and when communication should
+go through a proxy server. <URL:http://www.w3.org/pub/WWW/Proxies/>
+
+=item *
+
+The B<credentials> provide a way to set up user names and
+passwords that is needed to access certain services.
+
+=back
+
+Many applications would want even more control over how they interact
+with the network and they get this by specializing the
+C<LWP::UserAgent> by sub-classing.  The library provide a
+specialization called C<LWP::RobotUA> that is used by robot
+applications.
+
+=head2 An Example
+
+This example shows how the user agent, a request and a response are
+represented in actual perl code:
+
+  # Create a user agent object
+  use LWP::UserAgent;
+  $ua = new LWP::UserAgent;
+  $ua->agent("AgentName/0.1 " . $ua->agent);
+
+  # Create a request
+  my $req = new HTTP::Request POST => 'http://www.perl.com/cgi-bin/BugGlimpse';
+  $req->content_type('application/x-www-form-urlencoded');
+  $req->content('match=www&errors=0');
+
+  # Pass request to the user agent and get a response back
+  my $res = $ua->request($req);
+
+  # Check the outcome of the response
+  if ($res->is_success) {
+      print $res->content;
+  } else {
+      print "Bad luck this time\n";
+  }
+
+The $ua is created once when the application starts up.  New request
+objects are normally created for each request sent.
+
+
+=head1 NETWORK SUPPORT
+
+This section goes through the various protocol schemes and describe
+the HTTP style methods that are supported and the headers that might
+have any effect.
+
+For all requests, a "User-Agent" header is added and initialized from
+the $ua->agent value before the request is handed to the network
+layer.  In the same way, a "From" header is initialized from the
+$ua->from value.
+
+For all responses, the library will add a header called "Client-Date".
+This header will encode the time when the response was received by
+your application.  This format and semantics of the header is just
+like the server created "Date" header.  You can also encounter other
+"Client-XXX" headers.  They are all generated by the library
+internally and not something really passed on from the servers.
+
+=head2 HTTP Requests
+
+HTTP request are really just handed off to an HTTP server and it will
+decide what happens.  Few servers implement methods beside the usual
+"GET", "HEAD", "POST" and "PUT" but CGI-scripts can really implement
+any method they like.
+
+If the server is not available then the library will generate an
+internal error response.
+
+The library automatically adds a "Host" and a "Content-Length" header
+to the HTTP request before it is sent over the network.
+
+For GET request you might want to add the "If-Modified-Since" header
+to make the request conditional.
+
+For POST request you should add the "Content-Type" header.  When you
+try to emulate HTML E<lt>FORM> handling you should usually let the value
+of the "Content-Type" header be "application/x-www-form-urlencoded".
+See L<lwpcook> for examples of this.
+
+The libwww-perl HTTP implementation currently support the HTTP/1.0
+protocol.  HTTP/0.9 servers are also handled correctly.
+
+The library allows you to access proxy server through HTTP.  This
+means that you can set up the library to forward all types of request
+through the HTTP protocol module.  See L<LWP::UserAgent> for
+documentation of this.
+
+
+=head2 HTTPS Requests
+
+HTTPS requests are HTTP requests over an encrypted network connection
+using the SSL protocol developed by Netscape.  Everything about HTTP
+requests above also hold for HTTPS requests.  In addition the library
+will add the headers "Client-SSL-Cipher", "Client-SSL-Cert-Subject" and
+"Client-SSL-Cert-Issuer" to the response.  These headers denote the
+encryption method used and the name of the server owner.
+
+The request can contain the header "If-SSL-Cert-Subject" in order to
+make the request conditional on the content of the server certificate.
+If the certificate subject does not match, no request is sent to the
+server and an internally generated error response is returned.  The
+value of the "If-SSL-Cert-Subject" header is interpreted as a Perl
+regular expression.
+
+
+=head2 FTP Requests
+
+The library currently support GET, HEAD and PUT requests.  GET will
+retrieve a file or a directory listing from an FTP server.  PUT will
+store a file on a ftp server.
+
+You can specify a ftp account for servers that want this in addition
+user name and password.  This is specified by passing an "Account"
+header in the request.
+
+User name/password can be specified using basic authorization or be
+encoded in the URL.  Bad logins return an UNAUTHORIZED response with
+"WWW-Authenticate: Basic" and can be treated as basic authorization
+for HTTP.
+
+The library support ftp ASCII transfer mode by specifying the "type=a"
+parameter in the URL.
+
+Directory listings are by default returned unprocessed (as returned
+from the ftp server) with the content media type reported to be
+"text/ftp-dir-listing". The C<File::Listing> module provide functionality
+for parsing of these directory listing.
+
+The ftp module is also able to convert directory listings to HTML and
+this can be requested via the standard HTTP content negotiation
+mechanisms (add an "Accept: text/html" header in the request if you
+want this).
+
+The normal file retrievals, the "Content-Type" is guessed based on the
+file name suffix. See L<LWP::MediaTypes>.
+
+The "If-Modified-Since" request header works for servers that implement
+the MDTM command.  It will probably not work for directory listings though.
+
+Example:
+
+  $req = HTTP::Request->new(GET => 'ftp://me:passwd@ftp.some.where.com/');
+  $req->header(Accept => "text/html, */*;q=0.1");
+
+=head2 News Requests
+
+Access to the USENET News system is implemented through the NNTP
+protocol.  The name of the news server is obtained from the
+NNTP_SERVER environment variable and defaults to "news".  It is not
+possible to specify the hostname of the NNTP server in the news:-URLs.
+
+The library support GET and HEAD to retrieve news articles through the
+NNTP protocol.  You can also post articles to newsgroups by using
+(surprise!) the POST method.
+
+GET on newsgroups is not implemented yet.
+
+Examples:
+
+  $req = HTTP::Request->new(GET => 'news:abc1234@a.sn.no');
+
+  $req = HTTP::Request->new(POST => 'news:comp.lang.perl.test');
+  $req->header(Subject => 'This is a test',
+               From    => 'me@some.where.org');
+  $req->content(<<EOT);
+  This is the content of the message that we are sending to
+  the world.
+  EOT
+
+
+=head2 Gopher Request
+
+The library supports the GET and HEAD method for gopher request.  All
+request header values are ignored.  HEAD cheats and will return a
+response without even talking to server.
+
+Gopher menus are always converted to HTML.
+
+The response "Content-Type" is generated from the document type
+encoded (as the first letter) in the request URL path itself.
+
+Example:
+
+  $req = HTTP::Request->new(GET => 'gopher://gopher.sn.no/');
+
+
+
+=head2 File Request
+
+The library supports GET and HEAD methods for file requests.  The
+"If-Modified-Since" header is supported.  All other headers are
+ignored.  The I<host> component of the file URL must be empty or set
+to "localhost".  Any other I<host> value will be treated as an error.
+
+Directories are always converted to an HTML document.  For normal
+files, the "Content-Type" and "Content-Encoding" in the response are
+guessed based on the file suffix.
+
+Example:
+
+  $req = HTTP::Request->new(GET => 'file:/etc/passwd');
+
+
+=head2 Mailto Request
+
+You can send (aka "POST") mail messages using the library.  All
+headers specified for the request are passed on to the mail system.
+The "To" header is initialized from the mail address in the URL.
+
+Example:
+
+  $req = HTTP::Request->new(POST => 'mailto:libwww-perl-request@ics.uci.edu');
+  $req->header(Subject => "subscribe");
+  $req->content("Please subscribe me to the libwww-perl mailing list!\n");
+
+
+=head1 OVERVIEW OF CLASSES AND PACKAGES
+
+This table should give you a quick overview of the classes provided by the
+library. Indentation shows class inheritance.
+
+ LWP::MemberMixin   -- Access to member variables of Perl5 classes
+   LWP::UserAgent   -- WWW user agent class
+     LWP::RobotUA   -- When developing a robot applications
+   LWP::Protocol          -- Interface to various protocol schemes
+     LWP::Protocol::http  -- http:// access
+     LWP::Protocol::file  -- file:// access
+     LWP::Protocol::ftp   -- ftp:// access
+     ...
+
+ LWP::Authen::Basic -- Handle 401 and 407 responses
+ LWP::Authen::Digest
+
+ HTTP::Headers      -- MIME/RFC822 style header (used by HTTP::Message)
+ HTTP::Message      -- HTTP style message
+   HTTP::Request    -- HTTP request
+   HTTP::Response   -- HTTP response
+ HTTP::Daemon       -- A HTTP server class
+
+ URI::URL           -- Uniform Resource Locators
+
+ WWW::RobotRules    -- Parse robots.txt files
+   WWW::RobotRules::AnyDBM_File -- Persistent RobotRules
+
+The following modules provide various functions and definitions.
+
+ LWP                -- This file.  Library version number and documentation.
+ LWP::MediaTypes    -- MIME types configuration (text/html etc.)
+ LWP::Debug         -- Debug logging module
+ LWP::Simple        -- Simplified procedural interface for common functions
+ HTTP::Status       -- HTTP status code (200 OK etc)
+ HTTP::Date         -- Date parsing module for HTTP date formats
+ HTTP::Negotiate    -- HTTP content negotiation calculation
+ File::Listing      -- Parse directory listings
+
+
+=head1 MORE DOCUMENTATION
+
+All modules contain detailed information on the interfaces they
+provide.  The I<lwpcook> manpage is the libwww-perl cookbook that contain
+examples of typical usage of the library.  You might want to take a
+look at how the scripts C<lwp-request>, C<lwp-rget> and C<lwp-mirror>
+are implemented.
+
+=head1 BUGS
+
+The library can not handle multiple simultaneous requests yet.  Also,
+check out what's left in the TODO file.
+
+=head1 ACKNOWLEDGEMENTS
+
+This package owes a lot in motivation, design, and code, to the
+libwww-perl library for Perl 4, maintained by Roy Fielding
+E<lt>fielding@ics.uci.edu>.
+
+That package used work from Alberto Accomazzi, James Casey, Brooks
+Cutter, Martijn Koster, Oscar Nierstrasz, Mel Melchner, Gertjan van
+Oosten, Jared Rhine, Jack Shirazi, Gene Spafford, Marc VanHeyningen,
+Steven E. Brenner, Marion Hakanson, Waldemar Kebsch, Tony Sanders, and
+Larry Wall; see the libwww-perl-0.40 library for details.
+
+The primary architect for this Perl 5 library is Martijn Koster and
+Gisle Aas, with lots of help from Graham Barr, Tim Bunce, Andreas
+Koenig, Jared Rhine, and Jack Shirazi.
+
+
+=head1 COPYRIGHT
+
+  Copyright 1995-1998, Gisle Aas
+  Copyright 1995, Martijn Koster
+
+This library is free software; you can redistribute it and/or
+modify it under the same terms as Perl itself.
+
+=head1 AVAILABILITY
+
+The latest version of this library is likely to be available from:
+
+ http://www.sn.no/libwww-perl/
+
+The best place to discuss this code is on the
+<libwww-perl@ics.uci.edu> mailing list.
+
+=cut
Index: /main/tags/2.25/gsdl/packages/w3mir/libwww-perl-5.36/lib/LWP/Authen/Basic.pm
===================================================================
--- /main/tags/2.25/gsdl/packages/w3mir/libwww-perl-5.36/lib/LWP/Authen/Basic.pm	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/w3mir/libwww-perl-5.36/lib/LWP/Authen/Basic.pm	(revision 21064)
@@ -0,0 +1,36 @@
+package LWP::Authen::Basic;
+use strict;
+
+require MIME::Base64;
+
+sub authenticate
+{
+    my($class, $ua, $proxy, $auth_param, $response,
+       $request, $arg, $size) = @_;
+
+    my($user, $pass) = $ua->get_basic_credentials($auth_param->{realm},
+                                                  $request->url, $proxy);
+    return $response unless defined $user and defined $pass;
+
+    my $auth_header = $proxy ? "Proxy-Authorization" : "Authorization";
+    my $auth_value = "Basic " . MIME::Base64::encode("$user:$pass", "");
+
+    # Need to check this isn't a repeated fail!
+    my $r = $response;
+    while ($r) {
+	my $auth = $r->request->header($auth_header);
+	if ($auth && $auth eq $auth_value) {
+	    # here we know this failed before
+	    $response->header("Client-Warning" =>
+			      "Credentials for '$user' failed before");
+	    return $response;
+	}
+	$r = $r->previous;
+    }
+
+    my $referral = $request->clone;
+    $referral->header($auth_header => $auth_value);
+    return $ua->request($referral, $arg, $size, $response);
+}
+
+1;
Index: /main/tags/2.25/gsdl/packages/w3mir/libwww-perl-5.36/lib/LWP/Authen/Digest.pm
===================================================================
--- /main/tags/2.25/gsdl/packages/w3mir/libwww-perl-5.36/lib/LWP/Authen/Digest.pm	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/w3mir/libwww-perl-5.36/lib/LWP/Authen/Digest.pm	(revision 21064)
@@ -0,0 +1,73 @@
+package LWP::Authen::Digest;
+use strict;
+
+require MD5;
+
+sub authenticate
+{
+    my($class, $ua, $proxy, $auth_param, $response,
+       $request, $arg, $size) = @_;
+
+    my($user, $pass) = $ua->get_basic_credentials($auth_param->{realm},
+                                                  $request->url, $proxy);
+    return $response unless defined $user and defined $pass;
+
+    my $md5 = new MD5;
+
+    my(@digest);
+    $md5->add(join(":", $user, $auth_param->{realm}, $pass));
+    push(@digest, $md5->hexdigest);
+    $md5->reset;
+
+    push(@digest, $auth_param->{nonce});
+
+    $md5->add(join(":", $request->method, $request->url->path));
+    push(@digest, $md5->hexdigest);
+    $md5->reset;
+
+    $md5->add(join(":", @digest));
+    my($digest) = $md5->hexdigest;
+    $md5->reset;
+
+    my %resp = map { $_ => $auth_param->{$_} } qw(realm nonce opaque);
+    @resp{qw(username uri response)} = ($user, $request->url->path, $digest);
+
+    my(@order) = qw(username realm nonce uri response);
+    if($request->method =~ /^(?:POST|PUT)$/) {
+	$md5->add($request->content);
+	my $content = $md5->hexdigest;
+	$md5->reset;
+	$md5->add(join(":", @digest[0..1], $content));
+	$md5->reset;
+	$resp{"message-digest"} = $md5->hexdigest;
+	push(@order, "message-digest");
+    }
+    push(@order, "opaque");
+    my @pairs;
+    for (@order) {
+	next unless defined $resp{$_};
+	push(@pairs, "$_=" . qq("$resp{$_}"));
+    }
+
+    my $auth_header = $proxy ? "Proxy-Authorization" : "Authorization";
+    my $auth_value  = "Digest " . join(", ", @pairs);
+    
+    # Need to check this isn't a repeated fail!
+    my $r = $response;
+    while ($r) {
+	my $auth = $r->request->header($auth_header);
+	if ($auth && $auth eq $auth_value) {
+	    # here we know this failed before
+	    $response->header("Client-Warning" =>
+			      "Credentials for '$user' failed before");
+	    return $response;
+	}
+	$r = $r->previous;
+    }
+
+    my $referral = $request->clone;
+    $referral->header($auth_header => $auth_value);
+    return $ua->request($referral, $arg, $size, $response);
+}
+
+1;
Index: /main/tags/2.25/gsdl/packages/w3mir/libwww-perl-5.36/lib/LWP/Debug.pm
===================================================================
--- /main/tags/2.25/gsdl/packages/w3mir/libwww-perl-5.36/lib/LWP/Debug.pm	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/w3mir/libwww-perl-5.36/lib/LWP/Debug.pm	(revision 21064)
@@ -0,0 +1,129 @@
+#!/usr/local/bin/perl -w
+#
+# $Id$
+#
+package LWP::Debug;
+
+=head1 NAME
+
+LWP::Debug - debug routines for the libwww-perl library
+
+=head1 SYNOPSIS
+
+ use LWP::Debug qw(+ -conns);
+
+ # Used internally in the library
+ LWP::Debug::trace('send()');
+ LWP::Debug::debug('url ok');
+ LWP::Debug::conns("read $n bytes: $data");
+
+=head1 DESCRIPTION
+
+LWP::Debug provides tracing facilities. The trace(), debug() and
+conns() function are called within the library and they log
+information at increasing levels of detail. Which level of detail is
+actually printed is controlled with the C<level()> function.
+
+The following functions are available:
+
+=over 4
+
+=item level(...)
+
+The C<level()> function controls the level of detail being
+logged. Passing '+' or '-' indicates full and no logging
+respectively. Inidividual levels can switched on and of by passing the
+name of the level with a '+' or '-' prepended.  The levels are:
+
+  trace   : trace function calls
+  debug   : print debug messages
+  conns   : show all data transfered over the connections
+
+The LWP::Debug module provide a special import() method that allows
+you to pass the level() arguments with initial use statement.  If a
+use argument start with '+' or '-' then it is passed to the level
+function, else the name is exported as usual.  The following two
+statements are thus equivalent (if you ignore that the second pollutes
+your namespace):
+
+  use LWP::Debug qw(+);
+  use LWP::Debug qw(level); level('+');
+
+=item trace($msg)
+
+The C<trace()> function is used for tracing function
+calls. The package and calling subroutine name is
+printed along with the passed argument. This should
+be called at the start of every major function.
+
+=item debug($msg)
+
+The C<debug()> function is used for high-granularity
+reporting of state in functions.
+
+=item conns($msg)
+
+The C<conns()> function is used to show data being
+transferred over the connections. This may generate
+considerable output.
+
+=back
+
+=cut
+
+require Exporter;
+@ISA = qw(Exporter);
+@EXPORT_OK = qw(level trace debug conns);
+
+use Carp ();
+
+my @levels = qw(trace debug conns);
+%current_level = ();
+
+sub import
+{
+    my $pack = shift;
+    my $callpkg = caller(0);
+    my @symbols = ();
+    my @levels = ();
+    for (@_) {
+	if (/^[-+]/) {
+	    push(@levels, $_);
+	} else {
+	    push(@symbols, $_);
+	}
+    }
+    Exporter::export($pack, $callpkg, @symbols);
+    level(@levels);
+}
+
+sub level
+{
+    for (@_) {
+	if ($_ eq '+') {              # all on
+	    # switch on all levels
+	    %current_level = map { $_ => 1 } @levels;
+	} elsif ($_ eq '-') {           # all off
+	    %current_level = ();
+	} elsif (/^([-+])(\w+)$/) {
+	    $current_level{$2} = $1 eq '+';
+	} else {
+	    Carp::croak("Illegal level format $_");
+	}
+    }
+}
+
+sub trace  { _log(@_) if $current_level{'trace'}; }
+sub debug  { _log(@_) if $current_level{'debug'}; }
+sub conns  { _log(@_) if $current_level{'conns'}; }
+
+sub _log
+{
+    my $msg = shift;
+    $msg .= "\n" unless $msg =~ /\n$/;  # ensure trailing "\n"
+
+    my($package,$filename,$line,$sub) = caller(2);
+    print STDERR "$sub: $msg";
+}
+
+1;
Index: /main/tags/2.25/gsdl/packages/w3mir/libwww-perl-5.36/lib/LWP/MediaTypes.pm
===================================================================
--- /main/tags/2.25/gsdl/packages/w3mir/libwww-perl-5.36/lib/LWP/MediaTypes.pm	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/w3mir/libwww-perl-5.36/lib/LWP/MediaTypes.pm	(revision 21064)
@@ -0,0 +1,298 @@
+#
+# $Id$
+
+package LWP::MediaTypes;
+
+=head1 NAME
+
+LWP::MediaTypes - guess media type for a file or a URL
+
+=head1 SYNOPSIS
+
+ use LWP::MediaTypes qw(guess_media_type);
+ $type = guess_media_type("/tmp/foo.gif");
+
+=head1 DESCRIPTION
+
+This module provides functions for handling of media (also known as
+MIME) types and encodings.  The mapping from file extentions to media
+types is defined by the F<media.types> file.  If the F<~/.media.types>
+file exist it is used as a replacement.
+For backwards compatability we will also look for F<~/.mime.types>.
+
+The following functions are exported by default:
+
+=over 4
+
+=cut
+
+####################################################################
+
+require Exporter;
+@ISA = qw(Exporter);
+@EXPORT = qw(guess_media_type media_suffix);
+@EXPORT_OK = qw(add_type add_encoding);
+$VERSION = sprintf("%d.%02d", q$Revision$ =~ /(\d+)\.(\d+)/);
+
+require LWP::Debug;
+use strict;
+
+# note: These hashes will also be filled with the entries found in
+# the 'media.types' file.
+
+my %suffixType = (
+    'txt'   => 'text/plain',
+    'html'  => 'text/html',
+    'gif'   => 'image/gif',
+    'jpg'   => 'image/jpeg',
+);
+
+my %suffixExt = (
+    'text/plain' => 'txt',
+    'text/html'  => 'h',
+    'image/gif'  => 'gif',
+    'image/jpeg' => 'jpg',
+);
+
+#XXX: there should be some way to define this in the media.types files.
+my %suffixEncoding = (
+    'Z'   => 'compress',
+    'gz'  => 'gzip',
+    'hqx' => 'x-hqx',
+    'uu'  => 'x-uuencode',
+    'z'   => 'x-pack'
+);
+
+sub _dump {
+    require Data::Dumper;
+    Data::Dumper->new([\%suffixType, \%suffixExt, \%suffixEncoding],
+		      [qw(*suffixType *suffixExt *suffixEncoding)])->Dump;
+}
+
+read_media_types();
+
+
+
+=item guess_media_type($filename_or_url, [$header_to_modify])
+
+This function tries to guess media type and encoding for given file.
+It returns the content-type, which is a string like C<"text/html">.
+In array context it also returns any content-encodings applied (in the
+order used to encode the file).  You can pass a URI::URL object
+reference, instead of the file name, as the first parameter too.
+
+If the type can not be deduced from looking at the file name only,
+then guess_media_type() will let the C<-T> Perl operator take a look.
+If this works (and C<-T> returns a TRUE value) then we return
+I<text/plain> as the type, otherwise we return
+I<application/octet-stream> as the type.
+
+The optional second argument should be a reference to a HTTP::Headers
+object (or any object that implement the $obj->header method in a
+similar way).  When present we will set the values of the
+'Content-Type' and 'Content-Encoding' for this header.
+
+=cut
+
+sub guess_media_type
+{
+    my($file, $header) = @_;
+    return undef unless defined $file;
+
+    my $fullname;
+    if (ref($file)) {
+	# assume URI::URL object
+	$file = $file->path;
+	#XXX should handle non http:, file: or ftp: URLs differently
+    } else {
+	$fullname = $file;  # enable peek at actual file
+    }
+
+    my @encoding = ();
+    my $ct = undef;
+    for (file_exts($file)) {
+	# first check this dot part as encoding spec
+	if (exists $suffixEncoding{$_}) {
+	    unshift(@encoding, $suffixEncoding{$_});
+	    next;
+	}
+	if (exists $suffixEncoding{lc $_}) {
+	    unshift(@encoding, $suffixEncoding{lc $_});
+	    next;
+	}
+
+	# check content-type
+	if (exists $suffixType{$_}) {
+	    $ct = $suffixType{$_};
+	    last;
+	}
+	if (exists $suffixType{lc $_}) {
+	    $ct = $suffixType{lc $_};
+	    last;
+	}
+
+	# don't know nothing about this dot part, bail out
+	last;
+    }
+    unless (defined $ct) {
+	# Take a look at the file
+	if (defined $fullname) {
+	    $ct = (-T $fullname) ? "text/plain" : "application/octet-stream";
+	} else {
+	    $ct = "application/octet-stream";
+	}
+    }
+
+    if ($header) {
+	$header->header('Content-Type' => $ct);
+	$header->header('Content-Encoding' => \@encoding) if @encoding;
+    }
+
+    wantarray ? ($ct, @encoding) : $ct;
+}
+
+
+=item media_suffix($type,...)
+
+This function will return all suffixes that can be used to denote the
+specified media type(s).  Wildcard types can be used.  In scalar
+context it will return the first suffix found.
+
+Examples:
+
+  @suffixes = media_suffix('image/*', 'audio/basic');
+  $suffix = media_suffix('text/html');
+
+=cut
+
+sub media_suffix {
+    if (!wantarray && @_ == 1 && $_[0] !~ /\*/) {
+	return $suffixExt{$_[0]};
+    }
+    my(@type) = @_;
+    my(@suffix, $ext, $type);
+    foreach (@type) {
+	if (s/\*/.*/) {
+	    while(($ext,$type) = each(%suffixType)) {
+		push(@suffix, $ext) if $type =~ /^$_$/;
+	    }
+	} else {
+	    while(($ext,$type) = each(%suffixType)) {
+		push(@suffix, $ext) if $type eq $_;
+	    }
+	}
+    }
+    wantarray ? @suffix : $suffix[0];
+}
+
+
+sub file_exts 
+{
+    my($file) = @_;
+    $file =~ s,.*/,,;   # only basename left
+    my @parts = reverse split(/\./, $file);
+    pop(@parts);        # never concider first part
+    @parts;
+}
+
+
+=back
+
+The following functions are only exported by explict request:
+
+=over 4
+
+=item add_type($type, @exts)
+
+Associate a list of file extensions with the given media type.
+
+Example:
+
+    add_type("x-world/x-vrml" => qw(wrl vrml));
+
+=cut
+
+sub add_type 
+{
+    my($type, @exts) = @_;
+    for my $ext (@exts) {
+	$ext =~ s/^\.//;
+	$suffixType{$ext} = $type;
+    }
+    $suffixExt{$type} = $exts[0] if @exts;
+}
+
+
+=item add_encoding($type, @ext)
+
+Associate a list of file extensions with and encoding type.
+
+Example:
+
+ add_encoding("x-gzip" => "gz");
+
+=cut
+
+sub add_encoding
+{
+    my($type, @exts) = @_;
+    for my $ext (@exts) {
+	$ext =~ s/^\.//;
+	$suffixEncoding{$ext} = $type;
+    }
+}
+
+
+=item read_media_types(@files)
+
+Parse a media types file from disk and add the type mappings found there.
+
+Example:
+
+    read_media_types("conf/mime.types");
+
+=cut
+
+sub read_media_types 
+{
+    my(@files) = @_;
+
+    local($/, $_) = ("\n", undef);  # ensure correct $INPUT_RECORD_SEPARATOR
+
+    my @priv_files = ();
+    push(@priv_files, "$ENV{HOME}/.media.types", "$ENV{HOME}/.mime.types")
+	if defined $ENV{HOME};  # Some doesn't have a home (for instance Win32)
+
+    # Try to locate "media.types" file, and initialize %suffixType from it
+    my $typefile;
+    unless (@files) {
+	@files = map {"$_/LWP/media.types"} @INC;
+	push @files, @priv_files;
+    }
+    for $typefile (@files) {
+	local(*TYPE);
+	open(TYPE, $typefile) || next;
+        LWP::Debug::debug("Reading media types from $typefile");
+	while (<TYPE>) {
+	    next if /^\s*#/; # comment line
+	    next if /^\s*$/; # blank line
+	    s/#.*//;         # remove end-of-line comments
+	    my($type, @exts) = split(' ', $_);
+	    add_type($type, @exts);
+	}
+	close(TYPE);
+    }
+}
+
+1;
+
+=back 
+
+=head1 COPYRIGHT
+
+Copyright 1995-1998 Gisle Aas.
+
+This library is free software; you can redistribute it and/or
+modify it under the same terms as Perl itself.
+
+=cut
Index: /main/tags/2.25/gsdl/packages/w3mir/libwww-perl-5.36/lib/LWP/MemberMixin.pm
===================================================================
--- /main/tags/2.25/gsdl/packages/w3mir/libwww-perl-5.36/lib/LWP/MemberMixin.pm	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/w3mir/libwww-perl-5.36/lib/LWP/MemberMixin.pm	(revision 21064)
@@ -0,0 +1,46 @@
+#
+# $Id$
+
+package LWP::MemberMixin;
+
+=head1 NAME
+
+LWP::MemberMixin - Member access mixin class
+
+=head1 SYNOPSIS
+
+ package Foo;
+ require LWP::MemberMixin;
+ @ISA=qw(LWP::MemberMixin);
+
+=head1 DESCRIPTION
+
+A mixin class to get methods that provide easy access to member
+variables in the %$self.
+Ideally there should be better Perl langauge support for this.
+
+There is only one method provided:
+
+=over 4
+
+=item _elem($elem [, $val])
+
+Internal method to get/set the value of member variable
+C<$elem>. If C<$val> is defined it is used as the new value
+for the member variable.  If it is undefined the current
+value is not touched. In both cases the previous value of
+the member variable is returned.
+
+=back
+
+=cut
+
+sub _elem
+{
+    my($self, $elem, $val) = @_;
+    my $old = $self->{$elem};
+    $self->{$elem} = $val if defined $val;
+    return $old;
+}
+
+1;
Index: /main/tags/2.25/gsdl/packages/w3mir/libwww-perl-5.36/lib/LWP/Protocol.pm
===================================================================
--- /main/tags/2.25/gsdl/packages/w3mir/libwww-perl-5.36/lib/LWP/Protocol.pm	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/w3mir/libwww-perl-5.36/lib/LWP/Protocol.pm	(revision 21064)
@@ -0,0 +1,303 @@
+# $Id$
+
+package LWP::Protocol;
+
+=head1 NAME
+
+LWP::Protocol - Base class for LWP protocols
+
+=head1 SYNOPSIS
+
+ package LWP::Protocol::foo;
+ require LWP::Protocol;
+ @ISA=qw(LWP::Protocol);
+
+=head1 DESCRIPTION
+
+This class is used a the base class for all protocol implementations
+supported by the LWP library.
+
+When creating an instance of this class using
+C<LWP::Protocol::create($url)>, and you get an initialised subclass
+appropriate for that access method. In other words, the
+LWP::Protocol::create() function calls the constructor for one of its
+subclasses.
+
+All derived LWP::Protocol classes need to override the request()
+method which is used to service a request. The overridden method can
+make use of the collect() function to collect together chunks of data
+as it is received.
+
+The following methods and functions are provided:
+
+=over 4
+
+=cut
+
+#####################################################################
+
+require LWP::MemberMixin;
+@ISA = qw(LWP::MemberMixin);
+$VERSION = sprintf("%d.%02d", q$Revision$ =~ /(\d+)\.(\d+)/);
+
+use strict;
+use Carp ();
+use HTTP::Status 'RC_INTERNAL_SERVER_ERROR';
+require HTML::HeadParser;
+
+my %ImplementedBy = (); # scheme => classname
+
+
+=item $prot = new HTTP::Protocol;
+
+The LWP::Protocol constructor is inherited by subclasses. As this is a
+virtual base class this method should B<not> be called directly.
+
+=cut
+
+sub new
+{
+    my($class) = @_;
+
+    my $self = bless {
+	'timeout' => 0,
+	'parse_head' => 1,
+    }, $class;
+    $self;
+}
+
+
+=item $prot = LWP::Protocol::create($url)
+
+Create an object of the class implementing the protocol to handle the
+given scheme. This is a function, not a method. It is more an object
+factory than a constructor. This is the function user agents should
+use to access protocols.
+
+=cut
+
+sub create
+{
+    my $scheme = shift;
+    my $impclass = LWP::Protocol::implementor($scheme) or
+	Carp::croak("Protocol scheme '$scheme' is not supported");
+
+    # hand-off to scheme specific implementation sub-class
+    return $impclass->new($scheme);
+}
+
+
+=item $class = LWP::Protocol::implementor($scheme, [$class])
+
+Get and/or set implementor class for a scheme.  Returns '' if the
+specified scheme is not supported.
+
+=cut
+
+sub implementor
+{
+    my($scheme, $impclass) = @_;
+
+    if ($impclass) {
+	$ImplementedBy{$scheme} = $impclass;
+    }
+    my $ic = $ImplementedBy{$scheme};
+    return $ic if $ic;
+
+    return '' unless $scheme =~ /^([.+\-\w]+)$/;  # check valid URL schemes
+    $scheme = $1; # untaint
+    $scheme =~ s/[.+\-]/_/g;  # make it a legal module name
+
+    # scheme not yet known, look for a 'use'd implementation
+    $ic = "LWP::Protocol::$scheme";  # default location
+    $ic = "LWP::Protocol::nntp" if $scheme eq 'news'; #XXX ugly hack
+    no strict 'refs';
+    # check we actually have one for the scheme:
+    unless (defined @{"${ic}::ISA"}) {
+	# try to autoload it
+	eval "require $ic";
+	if ($@) {
+	    if ($@ =~ /^Can't locate/) { #' #emacs get confused by '
+		$ic = '';
+	    } else {
+		die "$@\n";
+	    }
+	}
+    }
+    $ImplementedBy{$scheme} = $ic if $ic;
+    $ic;
+}
+
+
+=item $prot->request(...)
+
+ $response = $protocol->request($request, $proxy, undef);
+ $response = $protocol->request($request, $proxy, '/tmp/sss');
+ $response = $protocol->request($request, $proxy, \&callback, 1024);
+
+Dispactches a request over the protocol, and returns a response
+object. This method needs to be overridden in subclasses.  Referer to
+L<LWP::UserAgent> for description of the arguments.
+
+=cut
+
+sub request
+{
+    my($self, $request, $proxy, $arg, $size, $timeout) = @_;
+    Carp::croak('LWP::Protocol::request() needs to be overridden in subclasses');
+}
+
+
+=item $prot->timeout($seconds)
+
+Get and set the timeout value in seconds
+
+
+=item $prot->parse_head($yesno)
+
+Should we initialize response headers from the <head> section of HTML
+documents.
+
+=cut
+
+sub timeout    { shift->_elem('timeout',    @_); }
+sub parse_head { shift->_elem('parse_head', @_); }
+sub max_size   { shift->_elem('max_size',   @_); }
+
+
+=item $prot->collect($arg, $response, $collector)
+
+Called to collect the content of a request, and process it
+appropriately into a scalar, file, or by calling a callback.  If $arg
+is undefined, then the content is stored within the $response.  If
+$arg is a simple scalar, then $arg is interpreted as a file name and
+the content is written to this file.  If $arg is a reference to a
+routine, then content is passed to this routine.
+
+The $collector is a routine that will be called and which is
+reponsible for returning pieces (as ref to scalar) of the content to
+process.  The $collector signals EOF by returning a reference to an
+empty sting.
+
+The return value from collect() is the $response object reference.
+
+B<Note:> We will only use the callback or file argument if
+$response->is_success().  This avoids sendig content data for
+redirects and authentization responses to the callback which would be
+confusing.
+
+=cut
+
+sub collect
+{
+    my ($self, $arg, $response, $collector) = @_;
+    my $content;
+    my($parse_head, $timeout, $max_size) =
+      @{$self}{qw(parse_head timeout max_size)};
+
+    my $parser;
+    if ($parse_head && $response->content_type eq 'text/html') {
+	$parser = HTML::HeadParser->new($response->{'_headers'});
+    }
+    my $content_size = 0;
+
+    if (!defined($arg) || !$response->is_success) {
+	# scalar
+	while ($content = &$collector, length $$content) {
+	    if ($parser) {
+		$parser->parse($$content) or undef($parser);
+	    }
+	    LWP::Debug::debug("read " . length($$content) . " bytes");
+	    $response->add_content($$content);
+	    $content_size += length($$content);
+	    if ($max_size && $content_size > $max_size) {
+		LWP::Debug::debug("Aborting because size limit exceeded");
+		my $tot = $response->header("Content-Length") || 0;
+		$response->header("X-Content-Range", "bytes 0-$content_size/$tot");
+		last;
+	    }
+	}
+    }
+    elsif (!ref($arg)) {
+	# filename
+	open(OUT, ">$arg") or
+	    return new HTTP::Response RC_INTERNAL_SERVER_ERROR,
+			  "Cannot write to '$arg': $!";
+        binmode(OUT);
+        local($\) = ""; # ensure standard $OUTPUT_RECORD_SEPARATOR
+	while ($content = &$collector, length $$content) {
+	    if ($parser) {
+		$parser->parse($$content) or undef($parser);
+	    }
+	    LWP::Debug::debug("read " . length($$content) . " bytes");
+	    print OUT $$content;
+	    $content_size += length($$content);
+	    if ($max_size && $content_size > $max_size) {
+		LWP::Debug::debug("Aborting because size limit exceeded");
+		my $tot = $response->header("Content-Length") || 0;
+		$response->header("X-Content-Range", "bytes 0-$content_size/$tot");
+		last;
+	    }
+	}
+	close(OUT);
+    }
+    elsif (ref($arg) eq 'CODE') {
+	# read into callback
+	while ($content = &$collector, length $$content) {
+	    if ($parser) {
+		$parser->parse($$content) or undef($parser);
+	    }
+	    LWP::Debug::debug("read " . length($$content) . " bytes");
+            eval {
+		&$arg($$content, $response, $self);
+	    };
+	    if ($@) {
+	        chomp($@);
+		$response->header('X-Died' => $@);
+		last;
+	    }
+	}
+    }
+    else {
+	return new HTTP::Response RC_INTERNAL_SERVER_ERROR,
+				  "Unexpected collect argument  '$arg'";
+    }
+    $response;
+}
+
+
+=item $prot->collect_once($arg, $response, $content)
+
+Can be called when the whole response content is available as
+$content.  This will invoke collect() with a collector callback that
+returns a reference to $content the first time and an empty string the
+next.
+
+=cut
+
+sub collect_once
+{
+    my($self, $arg, $response) = @_;
+    my $content = \ $_[3];
+    my $first = 1;
+    $self->collect($arg, $response, sub {
+	return $content if $first--;
+	return \ "";
+    });
+}
+
+1;
+
+=head1 SEE ALSO
+
+Inspect the F<LWP/Protocol/file.pm> and F<LWP/Protocol/http.pm> files
+for examples of usage.
+
+=head1 COPYRIGHT
+
+Copyright 1995-1997 Gisle Aas.
+
+This library is free software; you can redistribute it and/or
+modify it under the same terms as Perl itself.
+
+=cut
Index: /main/tags/2.25/gsdl/packages/w3mir/libwww-perl-5.36/lib/LWP/Protocol/data.pm
===================================================================
--- /main/tags/2.25/gsdl/packages/w3mir/libwww-perl-5.36/lib/LWP/Protocol/data.pm	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/w3mir/libwww-perl-5.36/lib/LWP/Protocol/data.pm	(revision 21064)
@@ -0,0 +1,53 @@
+#
+# $Id$
+#
+# Implements access to data:-URLs as specified in
+# draft-masinter-url-data-02.txt
+
+package LWP::Protocol::data;
+
+require HTTP::Response;
+require HTTP::Status;
+
+require LWP::Protocol;
+@ISA = qw(LWP::Protocol);
+
+use HTTP::Date qw(time2str);
+require LWP;  # needs version number
+
+sub request
+{
+    my($self, $request, $proxy, $arg, $size) = @_;
+
+    # check proxy
+    if (defined $proxy)
+    {
+	return new HTTP::Response &HTTP::Status::RC_BAD_REQUEST,
+				  'You can not proxy with data';
+    }
+
+    # check method
+    if ($request->method ne 'GET') {
+	return new HTTP::Response &HTTP::Status::RC_BAD_REQUEST,
+				  'Library does not allow method ' .
+				  "$method for 'data:' URLs";
+    }
+
+    my $url = $request->url;
+    my $response = new HTTP::Response &HTTP::Status::RC_OK, "Document follows";
+
+    my($media_type, $params) = $url->media_type;
+    $media_type .= ";$params" if $params;
+
+    my $data = $url->data;
+    $response->header('Content-Type'   => $media_type,
+		      'Content-Length' => length($data),
+		      'Date'           => time2str(time),
+		      'Server'         => "libwww-perl-internal/$LWP::VERSION"
+		     );
+    $response->content($data);
+
+    return $response;
+}
+
+1;
Index: /main/tags/2.25/gsdl/packages/w3mir/libwww-perl-5.36/lib/LWP/Protocol/file.pm
===================================================================
--- /main/tags/2.25/gsdl/packages/w3mir/libwww-perl-5.36/lib/LWP/Protocol/file.pm	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/w3mir/libwww-perl-5.36/lib/LWP/Protocol/file.pm	(revision 21064)
@@ -0,0 +1,154 @@
+#
+# $Id$
+
+package LWP::Protocol::file;
+
+require LWP::Protocol;
+require LWP::MediaTypes;
+require HTTP::Request;
+require HTTP::Response;
+require HTTP::Status;
+require HTTP::Date;
+
+require URI::Escape;
+require HTML::Entities;
+
+use Carp;
+
+@ISA = qw(LWP::Protocol);
+
+
+sub request
+{
+    my($self, $request, $proxy, $arg, $size) = @_;
+
+    LWP::Debug::trace('()');
+
+    $size = 4096 unless defined $size and $size > 0;
+
+    # check proxy
+    if (defined $proxy)
+    {
+	return new HTTP::Response &HTTP::Status::RC_BAD_REQUEST,
+				  'You can not proxy through the filesystem';
+    }
+
+    # check method
+    $method = $request->method;
+
+    unless ($method eq 'GET' || $method eq 'HEAD') {
+	return new HTTP::Response &HTTP::Status::RC_BAD_REQUEST,
+				  'Library does not allow method ' .
+				  "$method for 'file:' URLs";
+    }
+
+    # check url
+    my $url = $request->url;
+
+    my $scheme = $url->scheme;
+    if ($scheme ne 'file') {
+	return new HTTP::Response &HTTP::Status::RC_INTERNAL_SERVER_ERROR,
+				  "LWP::file::request called for '$scheme'";
+    }
+
+    my $host = $url->host;
+    if ($host and $host !~ /^localhost$/i) {
+	return new HTTP::Response &HTTP::Status::RC_BAD_REQUEST_CLIENT,
+				  'Only file://localhost/ allowed';
+    }
+
+    # URL OK, look at file
+    my $path  = $url->local_path;
+
+    # test file exists and is readable
+    unless (-e $path) {
+	return new HTTP::Response &HTTP::Status::RC_NOT_FOUND,
+				  "File `$path' does not exist";
+    }
+    unless (-r _) {
+	return new HTTP::Response &HTTP::Status::RC_FORBIDDEN,
+				  'User does not have read permission';
+    }
+
+    # looks like file exists
+    my($dev,$ino,$mode,$nlink,$uid,$gid,$rdev,$filesize,
+       $atime,$mtime,$ctime,$blksize,$blocks)
+	    = stat(_);
+
+    # XXX should check Accept headers?
+
+    # check if-modified-since
+    my $ims = $request->header('If-Modified-Since');
+    if (defined $ims) {
+	my $time = HTTP::Date::str2time($ims);
+	if (defined $time and $time >= $mtime) {
+	    return new HTTP::Response &HTTP::Status::RC_NOT_MODIFIED,
+				      "$method $path";
+	}
+    }
+
+    # Ok, should be an OK response by now...
+    $response = new HTTP::Response &HTTP::Status::RC_OK;
+
+    # fill in response headers
+    $response->header('Last-Modified', HTTP::Date::time2str($mtime));
+
+    if (-d _) {         # If the path is a directory, process it
+	# generate the HTML for directory
+	opendir(D, $path) or
+	   return new HTTP::Response &HTTP::Status::RC_INTERNAL_SERVER_ERROR,
+				     "Cannot read directory '$path': $!";
+	my(@files) = sort readdir(D);
+	closedir(D);
+
+	# Make directory listing
+	for (@files) {
+	    $_ .= "/" if -d "$path/$_";
+	    my $furl = URI::Escape::uri_escape($_);
+	    my $desc = HTML::Entities::encode($_);
+	    $_ = qq{<LI><A HREF="$furl">$desc</A>};
+	}
+	# Ensure that the base URL is "/" terminated
+	my $base = $url->clone;
+	unless ($base->epath =~ m|/$|) {
+	    $base->epath($base->epath . "/");
+	}
+	my $html = join("\n",
+			"<HTML>\n<HEAD>",
+			"<TITLE>Directory $path</TITLE>",
+			"<BASE HREF=\"$base\">",
+			"</HEAD>\n<BODY>",
+			"<H1>Directory listing of $path</H1>",
+			"<UL>", @files, "</UL>",
+			"</BODY>\n</HTML>\n");
+
+	$response->header('Content-Type',   'text/html');
+	$response->header('Content-Length', length $html);
+
+	return $self->collect_once($arg, $response, $html);
+
+    } else {            # path is a regular file
+	my($type, @enc) = LWP::MediaTypes::guess_media_type($path);
+	$response->header('Content-Type',   $type) if $type;
+	$response->header('Content-Length', $filesize);
+	for (@enc) {
+	    $response->push_header('Content-Encoding', $_);
+	}
+
+	# read the file
+	open(F, $path) or return new
+	   HTTP::Response(&HTTP::Status::RC_INTERNAL_SERVER_ERROR,
+			  "Cannot read file '$path': $!");
+	$response =  $self->collect($arg, $response, sub {
+	    my $content = "";
+	    my $bytes = sysread(F, $content, $size);
+	    return \$content if $bytes > 0;
+	    return \ "";
+	});
+	close(F);
+    }
+
+    $response;
+}
+
+1;
Index: /main/tags/2.25/gsdl/packages/w3mir/libwww-perl-5.36/lib/LWP/Protocol/ftp.pm
===================================================================
--- /main/tags/2.25/gsdl/packages/w3mir/libwww-perl-5.36/lib/LWP/Protocol/ftp.pm	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/w3mir/libwww-perl-5.36/lib/LWP/Protocol/ftp.pm	(revision 21064)
@@ -0,0 +1,396 @@
+#
+# $Id$
+
+# Implementation of the ftp protocol (RFC 959). We let the Net::FTP
+# package do all the dirty work.
+
+package LWP::Protocol::ftp;
+
+use Carp ();
+
+use HTTP::Status ();
+use HTTP::Negotiate ();
+use HTTP::Response ();
+use LWP::MediaTypes ();
+use File::Listing ();
+
+require LWP::Protocol;
+@ISA = qw(LWP::Protocol);
+
+use strict;
+eval {
+    require Net::FTP;
+    Net::FTP->require_version(2.00);
+};
+my $init_failed = $@;
+
+
+sub request
+{
+    my($self, $request, $proxy, $arg, $size, $timeout) = @_;
+
+    $size = 4096 unless $size;
+
+    LWP::Debug::trace('()');
+
+    # check proxy
+    if (defined $proxy)
+    {
+	return HTTP::Response->new(&HTTP::Status::RC_BAD_REQUEST,
+				   'You can not proxy through the ftp');
+    }
+
+    my $url = $request->url;
+    if ($url->scheme ne 'ftp') {
+	my $scheme = $url->scheme;
+	return HTTP::Response->new(&HTTP::Status::RC_INTERNAL_SERVER_ERROR,
+		       "LWP::Protocol::ftp::request called for '$scheme'");
+    }
+
+    # check method
+    my $method = $request->method;
+
+    unless ($method eq 'GET' || $method eq 'HEAD' || $method eq 'PUT') {
+	return HTTP::Response->new(&HTTP::Status::RC_BAD_REQUEST,
+				   'Library does not allow method ' .
+				   "$method for 'ftp:' URLs");
+    }
+
+    if ($init_failed) {
+	return HTTP::Response->new(&HTTP::Status::RC_INTERNAL_SERVER_ERROR,
+				   $init_failed);
+    }
+
+    my $host     = $url->host;
+    my $port     = $url->port;
+    my $user     = $url->user;
+    my $password = $url->password;
+
+    # If a basic autorization header is present than we prefer these over
+    # the username/password specified in the URL.
+    {
+	my($u,$p) = $request->authorization_basic;
+	if (defined $u) {
+	    $user = $u;
+	    $password = $p;
+	}
+    }
+
+    # We allow the account to be specified in the "Account" header
+    my $acct     = $request->header('Account');
+
+    # try to make a connection
+    my $ftp = Net::FTP->new($host, Port => $port);
+    unless ($ftp) {
+       $@ =~ s/^Net::FTP: //;
+       return HTTP::Response->new(&HTTP::Status::RC_INTERNAL_SERVER_ERROR, $@);
+    }
+
+    # Create an initial response object
+    my $response = HTTP::Response->new(&HTTP::Status::RC_OK,
+				       "Document follows");
+    $response->request($request);
+
+    my $mess = $ftp->message;  # welcome message
+    LWP::Debug::debug($mess);
+    $mess =~ s|\n.*||s; # only first line left
+    $mess =~ s|\s*ready\.?$||;
+    # Make the version number more HTTP like
+    $mess =~ s|\s*\(Version\s*|/| and $mess =~ s|\)$||;
+    $response->header("Server", $mess);
+
+    $ftp->timeout($timeout) if $timeout;
+
+    LWP::Debug::debug("Logging in as $user (password $password)...");
+    unless ($ftp->login($user, $password, $acct)) {
+	# Unauthorized.  Let's fake a RC_UNAUTHORIZED response
+	my $res =  HTTP::Response->new(&HTTP::Status::RC_UNAUTHORIZED,
+				       scalar($ftp->message));
+	$res->header("WWW-Authenticate", qq(Basic Realm="FTP login"));
+	return $res;
+    }
+    LWP::Debug::debug($ftp->message);
+
+    # Get & fix the path
+    my @path =  $url->path_components;
+    shift(@path);  # There will always be an empty first component
+    pop(@path) while @path && $path[-1] eq '';  # remove empty tailing comps
+    my $remote_file = pop(@path);
+    $remote_file = '' unless defined $remote_file;
+
+    my $params = $url->params;
+    if (defined($params) && $params eq 'type=a') {
+	$ftp->ascii;
+    } else {
+	$ftp->binary;
+    }
+
+    for (@path) {
+	LWP::Debug::debug("CWD $_");
+	unless ($ftp->cwd($_)) {
+	    return HTTP::Response->new(&HTTP::Status::RC_NOT_FOUND,
+				       "Can't chdir to $_");
+	}
+    }
+
+    if ($method eq 'GET' || $method eq 'HEAD') {
+	LWP::Debug::debug("MDTM");
+	if (my $mod_time = $ftp->mdtm($remote_file)) {
+	    $response->last_modified($mod_time);
+	    if (my $ims = $request->if_modified_since) {
+		if ($mod_time <= $ims) {
+		    $response->code(&HTTP::Status::RC_NOT_MODIFIED);
+		    $response->message("Not modified");
+		    return $response;
+		}
+	    }
+	}
+
+	my $data;  # the data handle
+	LWP::Debug::debug("retrieve file?");
+	if (length($remote_file) and $data = $ftp->retr($remote_file)) {
+	    my($type, @enc) = LWP::MediaTypes::guess_media_type($remote_file);
+	    $response->header('Content-Type',   $type) if $type;
+	    for (@enc) {
+		$response->push_header('Content-Encoding', $_);
+	    }
+	    my $mess = $ftp->message;
+	    LWP::Debug::debug($mess);
+	    if ($mess =~ /\((\d+)\s+bytes\)/) {
+		$response->header('Content-Length', "$1");
+	    }
+
+	    if ($method ne 'HEAD') {
+		# Read data from server
+		$response = $self->collect($arg, $response, sub {
+		    my $content = '';
+		    my $result = $data->read($content, $size);
+		    return \$content;
+		} );
+	    }
+	    unless ($data->close) {
+		# Something did not work too well
+		if ($method ne 'HEAD') {
+		    $response->code(&HTTP::Status::RC_INTERNAL_SERVER_ERROR);
+		    $response->message("FTP close response: " . $ftp->code .
+				       " " . $ftp->message);
+		}
+	    }
+	} elsif (!length($remote_file) || $ftp->code == 550) {
+	    # 550 not a plain file, try to list instead
+	    if (length($remote_file) && !$ftp->cwd($remote_file)) {
+		LWP::Debug::debug("chdir before listing failed");
+		return HTTP::Response->new(&HTTP::Status::RC_NOT_FOUND,
+					   "File '$remote_file' not found");
+	    }
+
+	    # It should now be safe to try to list the directory
+	    LWP::Debug::debug("dir");
+	    my @lsl = $ftp->dir;
+
+	    # Try to figure out if the user want us to convert the
+	    # directory listing to HTML.
+	    my @variants =
+	      (
+	       ['html',  0.60, 'text/html'            ],
+	       ['dir',   1.00, 'text/ftp-dir-listing' ]
+	      );
+	    #$HTTP::Negotiate::DEBUG=1;
+	    my $prefer = HTTP::Negotiate::choose(\@variants, $request);
+
+	    my $content = '';
+
+	    if (!defined($prefer)) {
+		return HTTP::Response->new(&HTTP::Status::RC_NOT_ACCEPTABLE,
+			       "Neither HTML nor directory listing wanted");
+	    } elsif ($prefer eq 'html') {
+		$response->header('Content-Type' => 'text/html');
+		$content = "<HEAD><TITLE>File Listing</TITLE>\n";
+		my $base = $request->url->clone;
+		my $path = $base->epath;
+		$base->epath("$path/") unless $path =~ m|/$|;
+		$content .= qq(<BASE HREF="$base">\n</HEAD>\n);
+		$content .= "<BODY>\n<UL>\n";
+		for (File::Listing::parse_dir(\@lsl, 'GMT')) {
+		    my($name, $type, $size, $mtime, $mode) = @$_;
+		    $content .= qq(  <LI> <a href="$name">$name</a>);
+		    $content .= " $size bytes" if $type eq 'f';
+		    $content .= "\n";
+		}
+		$content .= "</UL></body>\n";
+	    } else {
+		$response->header('Content-Type', 'text/ftp-dir-listing');
+		$content = join("\n", @lsl, '');
+	    }
+
+	    $response->header('Content-Length', length($content));
+
+	    if ($method ne 'HEAD') {
+		$response = $self->collect_once($arg, $response, $content);
+	    }
+	} else {
+	    my $res = HTTP::Response->new(&HTTP::Status::RC_BAD_REQUEST,
+			  "FTP return code " . $ftp->code);
+	    $res->content_type("text/plain");
+	    $res->content($ftp->message);
+	    return $res;
+	}
+    } elsif ($method eq 'PUT') {
+	# method must be PUT
+	unless (length($remote_file)) {
+	    return HTTP::Response->new(&HTTP::Status::RC_BAD_REQUEST,
+				       "Must have a file name to PUT to");
+	}
+	my $data;
+	if ($data = $ftp->stor($remote_file)) {
+	    LWP::Debug::debug($ftp->message);
+	    LWP::Debug::debug("$data");
+	    my $content = $request->content;
+	    my $bytes = 0;
+	    if (defined $content) {
+		if (ref($content) eq 'SCALAR') {
+		    $bytes = $data->write($$content, length($$content));
+		} elsif (ref($content) eq 'CODE') {
+		    my($buf, $n);
+		    while (length($buf = &$content)) {
+			$n = $data->write($buf, length($buf));
+			last unless $n;
+			$bytes += $n;
+		    }
+		} elsif (!ref($content)) {
+		    if (defined $content && length($content)) {
+			$bytes = $data->write($content, length($content));
+		    }
+		} else {
+		    die "Bad content";
+		}
+	    }
+	    $data->close;
+	    LWP::Debug::debug($ftp->message);
+
+	    $response->code(&HTTP::Status::RC_CREATED);
+	    $response->header('Content-Type', 'text/plain');
+	    $response->content("$bytes bytes stored as $remote_file on $host\n")
+
+	} else {
+	    my $res = HTTP::Response->new(&HTTP::Status::RC_BAD_REQUEST,
+					  "FTP return code " . $ftp->code);
+	    $res->content_type("text/plain");
+	    $res->content($ftp->message);
+	    return $res;
+	}
+    } else {
+	return HTTP::Response->new(&HTTP::Status::RC_BAD_REQUEST,
+				   "Illegal method $method");
+    }
+
+    $response;
+}
+
+1;
+
+__END__
+
+# This is what RFC 1738 has to say about FTP access:
+# --------------------------------------------------
+#
+# 3.2. FTP
+#
+#    The FTP URL scheme is used to designate files and directories on
+#    Internet hosts accessible using the FTP protocol (RFC959).
+#
+#    A FTP URL follow the syntax described in Section 3.1.  If :<port> is
+#    omitted, the port defaults to 21.
+#
+# 3.2.1. FTP Name and Password
+#
+#    A user name and password may be supplied; they are used in the ftp
+#    "USER" and "PASS" commands after first making the connection to the
+#    FTP server.  If no user name or password is supplied and one is
+#    requested by the FTP server, the conventions for "anonymous" FTP are
+#    to be used, as follows:
+#
+#         The user name "anonymous" is supplied.
+#
+#         The password is supplied as the Internet e-mail address
+#         of the end user accessing the resource.
+#
+#    If the URL supplies a user name but no password, and the remote
+#    server requests a password, the program interpreting the FTP URL
+#    should request one from the user.
+#
+# 3.2.2. FTP url-path
+#
+#    The url-path of a FTP URL has the following syntax:
+#
+#         <cwd1>/<cwd2>/.../<cwdN>/<name>;type=<typecode>
+#
+#    Where <cwd1> through <cwdN> and <name> are (possibly encoded) strings
+#    and <typecode> is one of the characters "a", "i", or "d".  The part
+#    ";type=<typecode>" may be omitted. The <cwdx> and <name> parts may be
+#    empty. The whole url-path may be omitted, including the "/"
+#    delimiting it from the prefix containing user, password, host, and
+#    port.
+#
+#    The url-path is interpreted as a series of FTP commands as follows:
+#
+#       Each of the <cwd> elements is to be supplied, sequentially, as the
+#       argument to a CWD (change working directory) command.
+#
+#       If the typecode is "d", perform a NLST (name list) command with
+#       <name> as the argument, and interpret the results as a file
+#       directory listing.
+#
+#       Otherwise, perform a TYPE command with <typecode> as the argument,
+#       and then access the file whose name is <name> (for example, using
+#       the RETR command.)
+#
+#    Within a name or CWD component, the characters "/" and ";" are
+#    reserved and must be encoded. The components are decoded prior to
+#    their use in the FTP protocol.  In particular, if the appropriate FTP
+#    sequence to access a particular file requires supplying a string
+#    containing a "/" as an argument to a CWD or RETR command, it is
+#    necessary to encode each "/".
+#
+#    For example, the URL <URL:ftp://myname@host.dom/%2Fetc/motd> is
+#    interpreted by FTP-ing to "host.dom", logging in as "myname"
+#    (prompting for a password if it is asked for), and then executing
+#    "CWD /etc" and then "RETR motd". This has a different meaning from
+#    <URL:ftp://myname@host.dom/etc/motd> which would "CWD etc" and then
+#    "RETR motd"; the initial "CWD" might be executed relative to the
+#    default directory for "myname". On the other hand,
+#    <URL:ftp://myname@host.dom//etc/motd>, would "CWD " with a null
+#    argument, then "CWD etc", and then "RETR motd".
+#
+#    FTP URLs may also be used for other operations; for example, it is
+#    possible to update a file on a remote file server, or infer
+#    information about it from the directory listings. The mechanism for
+#    doing so is not spelled out here.
+#
+# 3.2.3. FTP Typecode is Optional
+#
+#    The entire ;type=<typecode> part of a FTP URL is optional. If it is
+#    omitted, the client program interpreting the URL must guess the
+#    appropriate mode to use. In general, the data content type of a file
+#    can only be guessed from the name, e.g., from the suffix of the name;
+#    the appropriate type code to be used for transfer of the file can
+#    then be deduced from the data content of the file.
+#
+# 3.2.4 Hierarchy
+#
+#    For some file systems, the "/" used to denote the hierarchical
+#    structure of the URL corresponds to the delimiter used to construct a
+#    file name hierarchy, and thus, the filename will look similar to the
+#    URL path. This does NOT mean that the URL is a Unix filename.
+#
+# 3.2.5. Optimization
+#
+#    Clients accessing resources via FTP may employ additional heuristics
+#    to optimize the interaction. For some FTP servers, for example, it
+#    may be reasonable to keep the control connection open while accessing
+#    multiple URLs from the same server. However, there is no common
+#    hierarchical model to the FTP protocol, so if a directory change
+#    command has been given, it is impossible in general to deduce what
+#    sequence should be given to navigate to another directory for a
+#    second retrieval, if the paths are different.  The only reliable
+#    algorithm is to disconnect and reestablish the control connection.
Index: /main/tags/2.25/gsdl/packages/w3mir/libwww-perl-5.36/lib/LWP/Protocol/gopher.pm
===================================================================
--- /main/tags/2.25/gsdl/packages/w3mir/libwww-perl-5.36/lib/LWP/Protocol/gopher.pm	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/w3mir/libwww-perl-5.36/lib/LWP/Protocol/gopher.pm	(revision 21064)
@@ -0,0 +1,215 @@
+#
+# $Id$
+
+# Implementation of the gopher protocol (RFC 1436)
+#
+# This code is based on 'wwwgopher.pl,v 0.10 1994/10/17 18:12:34 shelden'
+# which in turn is a vastly modified version of Oscar's http'get()
+# dated 28/3/94 in <ftp://cui.unige.ch/PUBLIC/oscar/scripts/http.pl>
+# including contributions from Marc van Heyningen and Martijn Koster.
+#
+
+package LWP::Protocol::gopher;
+
+use strict;
+use vars qw(@ISA);
+
+require HTTP::Response;
+require HTTP::Status;
+require IO::Socket;
+require IO::Select;
+
+require LWP::Protocol;
+@ISA = qw(LWP::Protocol);
+
+
+my %gopher2mimetype = (
+    '0' => 'text/plain',                # 0 file
+    '1' => 'text/html',                 # 1 menu
+					# 2 CSO phone-book server
+					# 3 Error
+    '4' => 'application/mac-binhex40',  # 4 BinHexed Macintosh file
+    '5' => 'application/zip',           # 5 DOS binary archive of some sort
+    '6' => 'application/octet-stream',  # 6 UNIX uuencoded file.
+    '7' => 'text/html',                 # 7 Index-Search server
+					# 8 telnet session
+    '9' => 'application/octet-stream',  # 9 binary file
+    'h' => 'text/html',                 # html
+    'g' => 'image/gif',                 # gif
+    'I' => 'image/*',                   # some kind of image
+);
+
+my %gopher2encoding = (
+    '6' => 'x_uuencode',                # 6 UNIX uuencoded file.
+);
+
+sub request
+{
+    my($self, $request, $proxy, $arg, $size, $timeout) = @_;
+
+    LWP::Debug::trace('()');
+
+    $size = 4096 unless $size;
+
+    # check proxy
+    if (defined $proxy) {
+	return HTTP::Response->new(&HTTP::Status::RC_BAD_REQUEST,
+				   'You can not proxy through the gopher');
+    }
+
+    my $url = $request->url;
+    die "bad scheme" if $url->scheme ne 'gopher';
+
+
+    my $method = $request->method;
+    unless ($method eq 'GET' || $method eq 'HEAD') {
+	return HTTP::Response->new(&HTTP::Status::RC_BAD_REQUEST,
+				   'Library does not allow method ' .
+				   "$method for 'gopher:' URLs");
+    }
+
+    my $gophertype = $url->gtype;
+    unless (exists $gopher2mimetype{$gophertype}) {
+	return HTTP::Response->new(&HTTP::Status::RC_NOT_IMPLEMENTED,
+				   'Library does not support gophertype ' .
+				   $gophertype);
+    }
+
+    my $response = HTTP::Response->new(&HTTP::Status::RC_OK, "OK");
+    $response->header('Content-type' => $gopher2mimetype{$gophertype}
+					|| 'text/plain');
+    $response->header('Content-Encoding' => $gopher2encoding{$gophertype})
+	if exists $gopher2encoding{$gophertype};
+
+    if ($method eq 'HEAD') {
+	# XXX: don't even try it so we set this header
+	$response->header('Client-Warning' => 'Client answer only');
+	return $response;
+    }
+    
+    if ($gophertype eq '7' && ! $url->search) {
+      # the url is the prompt for a gopher search; supply boiler-plate
+      return $self->collect_once($arg, $response, <<"EOT");
+<HEAD>
+<TITLE>Gopher Index</TITLE>
+<ISINDEX>
+</HEAD>
+<BODY>
+<H1>$url<BR>Gopher Search</H1>
+This is a searchable Gopher index.
+Use the search function of your browser to enter search terms.
+</BODY>
+EOT
+    }
+
+    my $host = $url->host;
+    my $port = $url->port;
+
+    my $requestLine = "";
+
+    my $selector = $url->selector;
+    if (defined $selector) {
+	$requestLine .= $selector;
+	my $search = $url->search;
+	if (defined $search) {
+	    $requestLine .= "\t$search";
+	    my $string = $url->string;
+	    if (defined $string) {
+		$requestLine .= "\t$string";
+	    }
+	}
+    }
+    $requestLine .= "\015\012";
+
+    # potential request headers are just ignored
+
+    # Ok, lets make the request
+    my $socket = IO::Socket::INET->new(PeerAddr => $host,
+				       PeerPort => $port,
+				       Timeout  => $timeout);
+    die "Can't connect to $host:$port" unless $socket;
+    my $sel = IO::Select->new($socket);
+
+    {
+	die "write timeout" if $timeout && !$sel->can_write($timeout);
+	my $n = syswrite($socket, $requestLine, length($requestLine));
+	die $! unless defined($n);
+	die "short write" if $n != length($requestLine);
+    }
+
+    my $user_arg = $arg;
+
+    # must handle menus in a special way since they are to be
+    # converted to HTML.  Undefing $arg ensures that the user does
+    # not see the data before we get a change to convert it.
+    $arg = undef if $gophertype eq '1' || $gophertype eq '7';
+
+    # collect response
+    my $buf = '';
+    $response = $self->collect($arg, $response, sub {
+	die "read timeout" if $timeout && !$sel->can_read($timeout);
+        my $n = sysread($socket, $buf, $size);
+	die $! unless defined($n);
+	return \$buf;
+      } );
+
+    # Convert menu to HTML and return data to user.
+    if ($gophertype eq '1' || $gophertype eq '7') {
+	my $content = menu2html($response->content);
+	if (defined $user_arg) {
+	    $response = $self->collect_once($user_arg, $response, $content);
+	} else {
+	    $response->content($content);
+	}
+    }
+
+    $response;
+}
+
+
+sub gopher2url
+{
+    my($gophertype, $path, $host, $port) = @_;
+
+    my $url;
+
+    if ($gophertype eq '8' || $gophertype eq 'T') {
+	# telnet session
+	$url = URI::URL->new($gophertype eq '8' ? 'telnet:' : 'tn3270:');
+	$url->user($path) if defined $path;
+    } else {
+	$path = URI::Escape::uri_escape($path);
+	$url = URI::URL->new("gopher:/$gophertype$path");
+    }
+    $url->host($host);
+    $url->port($port);
+    $url;
+}
+
+sub menu2html {
+    my($menu) = @_;
+
+    $menu =~ s/\015//g;  # remove carriage return
+    my $tmp = <<"EOT";
+<HTML>
+<HEAD>
+   <TITLE>Gopher menu</TITLE>
+</HEAD>
+<BODY>
+<H1>Gopher menu</H1>
+EOT
+    for (split("\n", $menu)) {
+	last if /^\./;
+	my($pretty, $path, $host, $port) = split("\t");
+
+	$pretty =~ s/^(.)//;
+	my $type = $1;
+
+	my $url = gopher2url($type, $path, $host, $port)->as_string;
+	$tmp .= qq{<A HREF="$url">$pretty</A><BR>\n};
+    }
+    $tmp .= "</BODY>\n</HTML>\n";
+    $tmp;
+}
+
+1;
Index: /main/tags/2.25/gsdl/packages/w3mir/libwww-perl-5.36/lib/LWP/Protocol/http.pm
===================================================================
--- /main/tags/2.25/gsdl/packages/w3mir/libwww-perl-5.36/lib/LWP/Protocol/http.pm	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/w3mir/libwww-perl-5.36/lib/LWP/Protocol/http.pm	(revision 21064)
@@ -0,0 +1,252 @@
+#
+# $Id$
+
+package LWP::Protocol::http;
+
+require LWP::Debug;
+require HTTP::Response;
+require HTTP::Status;
+require IO::Socket;
+require IO::Select;
+
+require LWP::Protocol;
+@ISA = qw(LWP::Protocol);
+
+use strict;
+my $CRLF         = "\015\012";     # how lines should be terminated;
+				   # "\r\n" is not correct on all systems, for
+				   # instance MacPerl defines it to "\012\015"
+
+sub _new_socket
+{
+    my($self, $host, $port, $timeout) = @_;
+
+    local($^W) = 0;  # IO::Socket::INET can be noisy
+    my $sock = IO::Socket::INET->new(PeerAddr => $host,
+				     PeerPort => $port,
+				     Proto    => 'tcp',
+				     Timeout  => $timeout,
+				    );
+    unless ($sock) {
+	# IO::Socket::INET leaves additional error messages in $@
+	$@ =~ s/^.*?: //;
+	die "Can't connect to $host:$port ($@)";
+    }
+    $sock;
+}
+
+
+sub _check_sock
+{
+    #my($self, $req, $sock) = @_;
+}
+
+sub _get_sock_info
+{
+    my($self, $res, $sock) = @_;
+    $res->header("Client-Peer" =>
+		 $sock->peerhost . ":" . $sock->peerport);
+}
+
+
+sub request
+{
+    my($self, $request, $proxy, $arg, $size, $timeout) = @_;
+    LWP::Debug::trace('()');
+
+    $size ||= 4096;
+
+    # check method
+    my $method = $request->method;
+    unless ($method =~ /^[A-Za-z0-9_!\#\$%&\'*+\-.^\`|~]+$/) {  # HTTP token
+	return new HTTP::Response &HTTP::Status::RC_BAD_REQUEST,
+				  'Library does not allow method ' .
+				  "$method for 'http:' URLs";
+    }
+
+    my $url = $request->url;
+    my($host, $port, $fullpath);
+
+    # Check if we're proxy'ing
+    if (defined $proxy) {
+	# $proxy is an URL to an HTTP server which will proxy this request
+	$host = $proxy->host;
+	$port = $proxy->port;
+	$fullpath = $url->as_string;
+    }
+    else {
+	$host = $url->host;
+	$port = $url->port;
+	$fullpath = $url->full_path;
+    }
+
+    # connect to remote site
+    my $socket = $self->_new_socket($host, $port, $timeout);
+    $self->_check_sock($request, $socket);
+	    
+    my $sel = IO::Select->new($socket) if $timeout;
+
+    my $request_line = "$method $fullpath HTTP/1.0$CRLF";
+
+    my $h = $request->headers->clone;
+    my $cont_ref = $request->content_ref;
+    $cont_ref = $$cont_ref if ref($$cont_ref);
+    my $ctype = ref($cont_ref);
+
+    # If we're sending content we *have* to specify a content length
+    # otherwise the server won't know a messagebody is coming.
+    if ($ctype eq 'CODE') {
+	die 'No Content-Length header for request with dynamic content'
+	    unless defined($h->header('Content-Length')) ||
+		   $h->content_type =~ /^multipart\//;
+	# For HTTP/1.1 we could have used chunked transfer encoding...
+    } else {
+	$h->header('Content-Length' => length $$cont_ref)
+	        if defined($$cont_ref) && length($$cont_ref);
+    }
+    
+    # HTTP/1.1 will require us to send the 'Host' header, so we might
+    # as well start now.
+    my $hhost = $url->netloc;
+    $hhost =~ s/^([^\@]*)\@//;  # get rid of potential "user:pass@"
+    $h->header('Host' => $hhost) unless defined $h->header('Host');
+
+    # add authorization header if we need them.  HTTP URLs do
+    # not really support specification of user and password, but
+    # we allow it.
+    if (defined($1) && not $h->header('Authorization')) {
+	$h->authorization_basic($url->user, $url->password);
+    }
+
+    my $buf = $request_line . $h->as_string($CRLF) . $CRLF;
+    my $n;  # used for return value from syswrite/sysread
+
+    die "write timeout" if $timeout && !$sel->can_write($timeout);
+    $n = $socket->syswrite($buf, length($buf));
+    die $! unless defined($n);
+    die "short write" unless $n == length($buf);
+    LWP::Debug::conns($buf);
+
+    if ($ctype eq 'CODE') {
+	while ( ($buf = &$cont_ref()), defined($buf) && length($buf)) {
+	    die "write timeout" if $timeout && !$sel->can_write($timeout);
+	    $n = $socket->syswrite($buf, length($buf));
+	    die $! unless defined($n);
+	    die "short write" unless $n == length($buf);
+	    LWP::Debug::conns($buf);
+	}
+    } elsif (defined($$cont_ref) && length($$cont_ref)) {
+	die "write timeout" if $timeout && !$sel->can_write($timeout);
+	$n = $socket->syswrite($$cont_ref, length($$cont_ref));
+	die $! unless defined($n);
+	die "short write" unless $n == length($$cont_ref);
+	LWP::Debug::conns($buf);
+    }
+    
+    # read response line from server
+    LWP::Debug::debug('reading response');
+
+    my $response;
+    $buf = '';
+
+    # Inside this loop we will read the response line and all headers
+    # found in the response.
+    while (1) {
+	{
+	    die "read timeout" if $timeout && !$sel->can_read($timeout);
+	    $n = $socket->sysread($buf, $size, length($buf));
+	    die $! unless defined($n);
+	    die "unexpected EOF before status line seen" unless $n;
+	    LWP::Debug::conns($buf);
+	}
+	if ($buf =~ s/^(HTTP\/\d+\.\d+)[ \t]+(\d+)[ \t]*([^\012]*)\012//) {
+	    # HTTP/1.0 response or better
+	    my($ver,$code,$msg) = ($1, $2, $3);
+	    $msg =~ s/\015$//;
+	    LWP::Debug::debug("$ver $code $msg");
+	    $response = HTTP::Response->new($code, $msg);
+	    $response->protocol($ver);
+
+	    # ensure that we have read all headers.  The headers will be
+	    # terminated by two blank lines
+	    until ($buf =~ /^\015?\012/ || $buf =~ /\015?\012\015?\012/) {
+		# must read more if we can...
+		LWP::Debug::debug("need more header data");
+		die "read timeout" if $timeout && !$sel->can_read($timeout);
+		$n = $socket->sysread($buf, $size, length($buf));
+		die $! unless defined($n);
+		die "unexpected EOF before all headers seen" unless $n;
+		#LWP::Debug::conns($buf);
+	    }
+
+	    # now we start parsing the headers.  The strategy is to
+	    # remove one line at a time from the beginning of the header
+	    # buffer ($res).
+	    my($key, $val);
+	    while ($buf =~ s/([^\012]*)\012//) {
+		my $line = $1;
+
+		# if we need to restore as content when illegal headers
+		# are found.
+		my $save = "$line\012"; 
+
+		$line =~ s/\015$//;
+		last unless length $line;
+
+		if ($line =~ /^([a-zA-Z0-9_\-]+)\s*:\s*(.*)/) {
+		    $response->push_header($key, $val) if $key;
+		    ($key, $val) = ($1, $2);
+		} elsif ($line =~ /^\s+(.*)/) {
+		    unless ($key) {
+			$response->header("Client-Warning" =>
+					 => "Illegal continuation header");
+			$buf = "$save$buf";
+			last;
+		    }
+		    $val .= " $1";
+		} else {
+		    $response->header("Client-Warning" =>
+				      "Illegal header '$line'");
+		    $buf = "$save$buf";
+		    last;
+		}
+	    }
+	    $response->push_header($key, $val) if $key;
+	    last;
+
+	} elsif ((length($buf) >= 5 and $buf !~ /^HTTP\//) or
+		 $buf =~ /\012/ ) {
+	    # HTTP/0.9 or worse
+	    LWP::Debug::debug("HTTP/0.9 assume OK");
+	    $response = HTTP::Response->new(&HTTP::Status::RC_OK, "OK");
+	    $response->protocol('HTTP/0.9');
+	    last;
+
+	} else {
+	    # need more data
+	    LWP::Debug::debug("need more status line data");
+	}
+    };
+    $response->request($request);
+    $self->_get_sock_info($response, $socket);
+
+
+    my $usebuf = length($buf) > 0;
+    $response = $self->collect($arg, $response, sub {
+        if ($usebuf) {
+	    $usebuf = 0;
+	    return \$buf;
+	}
+	die "read timeout" if $timeout && !$sel->can_read($timeout);
+	my $n = $socket->sysread($buf, $size);
+	die $! unless defined($n);
+	#LWP::Debug::conns($buf);
+	return \$buf;
+	} );
+
+    $socket->close;
+
+    $response;
+}
+
+1;
Index: /main/tags/2.25/gsdl/packages/w3mir/libwww-perl-5.36/lib/LWP/Protocol/https.pm
===================================================================
--- /main/tags/2.25/gsdl/packages/w3mir/libwww-perl-5.36/lib/LWP/Protocol/https.pm	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/w3mir/libwww-perl-5.36/lib/LWP/Protocol/https.pm	(revision 21064)
@@ -0,0 +1,59 @@
+#
+# $Id$
+
+use strict;
+
+package LWP::Protocol::https;
+require Net::SSL;  # from Crypt-SSLeay
+
+use vars qw(@ISA);
+
+require LWP::Protocol::http;
+@ISA=qw(LWP::Protocol::http);
+
+sub _new_socket
+{
+    my($self, $host, $port, $timeout) = @_;
+    local($^W) = 0;  # IO::Socket::INET can be noisy
+    my $sock = Net::SSL->new(PeerAddr => $host,
+			     PeerPort => $port,
+			     Proto    => 'tcp',
+			     Timeout  => $timeout,
+			    );
+    unless ($sock) {
+	# IO::Socket::INET leaves additional error messages in $@
+	$@ =~ s/^.*?: //;
+	die "Can't connect to $host:$port ($@)";
+    }
+    $sock;
+}
+
+sub _check_sock
+{
+    my($self, $req, $sock) = @_;
+    my $check = $req->header("If-SSL-Cert-Subject");
+    if (defined $check) {
+	my $cert = $sock->get_peer_certificate ||
+	    die "Missing SSL certificate";
+	my $subject = $cert->subject_name;
+	die "Bad SSL certificate subject: '$subject' !~ /$check/"
+	    unless $subject =~ /$check/;
+	$req->remove_header("If-SSL-Cert-Subject");  # don't pass it on
+    }
+}
+
+sub _get_sock_info
+{
+    my $self = shift;
+    $self->SUPER::_get_sock_info(@_);
+    my($res, $sock) = @_;
+    $res->header("Client-SSL-Cipher" => $sock->get_cipher);
+    my $cert = $sock->get_peer_certificate;
+    if ($cert) {
+	$res->header("Client-SSL-Cert-Subject" => $cert->subject_name);
+	$res->header("Client-SSL-Cert-Issuer" => $cert->issuer_name);
+    }
+    $res->header("Client-SSL-Warning" => "Peer certificate not verified");
+}
+
+1;
Index: /main/tags/2.25/gsdl/packages/w3mir/libwww-perl-5.36/lib/LWP/Protocol/mailto.pm
===================================================================
--- /main/tags/2.25/gsdl/packages/w3mir/libwww-perl-5.36/lib/LWP/Protocol/mailto.pm	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/w3mir/libwww-perl-5.36/lib/LWP/Protocol/mailto.pm	(revision 21064)
@@ -0,0 +1,87 @@
+#
+# $Id$
+#
+# This module implements the mailto protocol.  It is just a simple
+# frontend to the Unix sendmail program.  In the long run this module
+# will built using the Mail::Send module.
+
+package LWP::Protocol::mailto;
+
+require LWP::Protocol;
+require HTTP::Request;
+require HTTP::Response;
+require HTTP::Status;
+
+use Carp;
+
+@ISA = qw(LWP::Protocol);
+
+$SENDMAIL = "/usr/lib/sendmail";
+
+
+sub request
+{
+    my($self, $request, $proxy, $arg, $size) = @_;
+
+    # check proxy
+    if (defined $proxy)
+    {
+	return new HTTP::Response &HTTP::Status::RC_BAD_REQUEST,
+				  'You can not proxy with mail';
+    }
+
+    # check method
+    $method = $request->method;
+
+    if ($method ne 'POST') {
+	return new HTTP::Response &HTTP::Status::RC_BAD_REQUEST,
+				  'Library does not allow method ' .
+				  "$method for 'mailto:' URLs";
+    }
+
+    # check url
+    my $url = $request->url;
+
+    my $scheme = $url->scheme;
+    if ($scheme ne 'mailto') {
+	return new HTTP::Response &HTTP::Status::RC_INTERNAL_SERVER_ERROR,
+				  "LWP::file::request called for '$scheme'";
+    }
+    unless (-x $SENDMAIL) {
+	return new HTTP::Response &HTTP::Status::RC_INTERNAL_SERVER_ERROR,
+				  "You don't have $SENDMAIL";
+    }
+
+    open(SENDMAIL, "| $SENDMAIL -oi -t") or
+	return new HTTP::Response &HTTP::Status::RC_INTERNAL_SERVER_ERROR,
+				  "Can't run $SENDMAIL: $!";
+
+    my $addr = $url->encoded822addr;
+
+    $request->header('To', $addr);
+    print SENDMAIL $request->headers_as_string;
+    print SENDMAIL "\n";
+    my $content = $request->content;
+    if (defined $content) {
+	my $contRef = ref($content) ? $content : \$content;
+	if (ref($contRef) eq 'SCALAR') {
+	    print SENDMAIL $$contRef;
+	} elsif (ref($contRef) eq 'CODE') {
+	    # Callback provides data
+	    my $d;
+	    while (length($d = &$contRef)) {
+		print SENDMAIL $d;
+	    }
+	}
+    }
+    close(SENDMAIL);
+
+    my $response = new HTTP::Response &HTTP::Status::RC_ACCEPTED,
+				     'Mail accepted by sendmail';
+    $response->header('Content-Type', 'text/plain');
+    $response->content("Mail sent to <$addr>\n");
+
+    return $response;
+}
+
+1;
Index: /main/tags/2.25/gsdl/packages/w3mir/libwww-perl-5.36/lib/LWP/Protocol/nntp.pm
===================================================================
--- /main/tags/2.25/gsdl/packages/w3mir/libwww-perl-5.36/lib/LWP/Protocol/nntp.pm	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/w3mir/libwww-perl-5.36/lib/LWP/Protocol/nntp.pm	(revision 21064)
@@ -0,0 +1,142 @@
+#
+# $Id$
+
+# Implementation of the Network News Transfer Protocol (RFC 977)
+#
+
+package LWP::Protocol::nntp;
+
+require LWP::Protocol;
+@ISA = qw(LWP::Protocol);
+
+require LWP::Debug;
+require HTTP::Response;
+require HTTP::Status;
+require Net::NNTP;
+
+use strict;
+
+
+sub request
+{
+    my($self, $request, $proxy, $arg, $size, $timeout) = @_;
+
+    LWP::Debug::trace('()');
+
+    $size = 4096 unless $size;
+
+    # Check for proxy
+    if (defined $proxy) {
+	return HTTP::Response->new(&HTTP::Status::RC_BAD_REQUEST,
+				   'You can not proxy through NNTP');
+    }
+
+    # Check that the scheme is as expected
+    my $url = $request->url;
+    my $scheme = $url->scheme;
+    unless ($scheme eq 'news') {
+	return HTTP::Response->new(&HTTP::Status::RC_INTERNAL_SERVER_ERROR,
+				   "LWP::Protocol::nntp::request called for '$scheme'");
+    }
+
+    # check for a valid method
+    my $method = $request->method;
+    unless ($method eq 'GET' || $method eq 'HEAD' || $method eq 'POST') {
+	return HTTP::Response->new(&HTTP::Status::RC_BAD_REQUEST,
+				   'Library does not allow method ' .
+				   "$method for 'news:' URLs");
+    }
+
+    # extract the identifier and check against posting to an article
+    my $groupart = $url->groupart;
+    my $is_art = $groupart =~ /@/;
+
+    if ($is_art && $method eq 'POST') {
+	return HTTP::Response->new(&HTTP::Status::RC_BAD_REQUEST,
+				   "Can't post to an article <$groupart>");
+    }
+
+    my $nntp = Net::NNTP->new(undef,
+			      #Port    => 18574,
+			      Timeout => $timeout,
+			      #Debug   => 1,
+			     );
+    die "Can't connect to nntp server" unless $nntp;
+
+    # Check the initial welcome message from the NNTP server
+    if ($nntp->status != 2) {
+	return HTTP::Response->new(&HTTP::Status::RC_SERVICE_UNAVAILABLE,
+				   $nntp->message);
+    }
+    my $response = HTTP::Response->new(&HTTP::Status::RC_OK, "OK");
+
+    my $mess = $nntp->message;
+    LWP::Debug::debug($mess);
+
+    # Try to extract server name from greating message.
+    # Don't know if this works well for a large class of servers, but
+    # this works for our server.
+    $mess =~ s/\s+ready\b.*//;
+    $mess =~ s/^\S+\s+//;
+    $response->header(Server => $mess);
+
+
+    # First we handle posting of articles
+    if ($method eq 'POST') {
+	return HTTP::Response->new(&HTTP::Status::RC_NOT_IMPLEMENTED,
+				   "POST not implemented yet");
+    }
+
+    # The method must be "GET" or "HEAD" by now
+    if (!$is_art) {
+	if (!$nntp->group($groupart)) {
+	    return HTTP::Response->new(&HTTP::Status::RC_NOT_FOUND,
+				       $nntp->message);
+	}
+	return HTTP::Response->new(&HTTP::Status::RC_NOT_IMPLEMENTED,
+				   "GET newsgroup not implemented yet");
+    }
+
+    # Send command to server to retrieve an article (or just the headers)
+    my $get = $method eq 'HEAD' ? "head" : "article";
+    my $art = $nntp->$get("<$groupart>");
+    unless ($art) {
+	return HTTP::Response->new(&HTTP::Status::RC_NOT_FOUND,
+				   $nntp->message);
+    }
+    LWP::Debug::debug($nntp->message);
+    
+    # Parse headers
+    my($key, $val);
+    while ($_ = shift @$art) {
+	if (/^\s+$/) {
+	    last;  # end of headers
+	} elsif (/^(\S+):\s*(.*)/) {
+	    $response->push_header($key, $val) if $key;
+	    ($key, $val) = ($1, $2);
+	} elsif (/^\s+(.*)/) {
+	    next unless $key;
+	    $val .= $1;
+	} else {
+	    unshift(@$art, $_);
+	    last;
+	}
+    }
+    $response->push_header($key, $val) if $key;
+
+    # Ensure that there is a Content-Type header
+    $response->header("Content-Type", "text/plain")
+	unless $response->header("Content-Type");
+
+    # Collect the body
+    $response = $self->collect_once($arg, $response, join("", @$art))
+      if @$art;
+
+    # Say godbye to the server
+    $nntp->quit;
+    $nntp = undef;
+
+    $response;
+}
+
+1;
Index: /main/tags/2.25/gsdl/packages/w3mir/libwww-perl-5.36/lib/LWP/RobotUA.pm
===================================================================
--- /main/tags/2.25/gsdl/packages/w3mir/libwww-perl-5.36/lib/LWP/RobotUA.pm	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/w3mir/libwww-perl-5.36/lib/LWP/RobotUA.pm	(revision 21064)
@@ -0,0 +1,285 @@
+# $Id$
+
+package LWP::RobotUA;
+
+require LWP::UserAgent;
+@ISA = qw(LWP::UserAgent);
+$VERSION = sprintf("%d.%02d", q$Revision$ =~ /(\d+)\.(\d+)/);
+
+require WWW::RobotRules;
+require HTTP::Request;
+require HTTP::Response;
+
+use Carp ();
+use LWP::Debug ();
+use HTTP::Status ();
+use HTTP::Date qw(time2str);
+use strict;
+
+=head1 NAME
+
+LWP::RobotUA - A class for Web Robots
+
+=head1 SYNOPSIS
+
+  require LWP::RobotUA;
+  $ua = new LWP::RobotUA 'my-robot/0.1', 'me@foo.com';
+  $ua->delay(10);  # be very nice, go slowly
+  ...
+  # just use it just like a normal LWP::UserAgent
+  $res = $ua->request($req);
+
+=head1 DESCRIPTION
+
+This class implements a user agent that is suitable for robot
+applications.  Robots should be nice to the servers they visit.  They
+should consult the F<robots.txt> file to ensure that they are welcomed
+and they should not send too frequent requests.
+
+But, before you consider writing a robot take a look at
+<URL:http://info.webcrawler.com/mak/projects/robots/robots.html>.
+
+When you use a I<LWP::RobotUA> as your user agent, then you do not
+really have to think about these things yourself.  Just send requests
+as you do when you are using a normal I<LWP::UserAgent> and this
+special agent will make sure you are nice.
+
+=head1 METHODS
+
+The LWP::RobotUA is a sub-class of LWP::UserAgent and implements the
+same methods. In addition the following methods are provided:
+
+=over 4
+
+=cut
+
+
+#
+# Additional attributes in addition to those found in LWP::UserAgent:
+#
+# $self->{'delay'}    Required delay between request to the same
+#                     server in minutes.
+#
+# $self->{'rules'}     A WWW::RobotRules object
+#
+
+
+=item $ua = LWP::RobotUA->new($agent_name, $from, [$rules])
+
+Your robot's name and the mail address of the human responsible for
+the robot (i.e. you) is required by the constructor.
+
+Optionally it allows you to specify the I<WWW::RobotRules> object to
+use.
+
+=cut
+
+sub new
+{
+    my($class,$name,$from,$rules) = @_;
+
+    Carp::croak('LWP::RobotUA name required') unless $name;
+    Carp::croak('LWP::RobotUA from address required') unless $from;
+
+    my $self = new LWP::UserAgent;
+    $self = bless $self, $class;
+
+    $self->{'delay'} = 1;   # minutes
+    $self->{'agent'} = $name;
+    $self->{'from'}  = $from;
+    $self->{'use_sleep'} = 1;
+
+    if ($rules) {
+	$rules->agent($name);
+	$self->{'rules'} = $rules;
+    } else {
+	$self->{'rules'} = new WWW::RobotRules $name;
+    }
+
+    $self;
+}
+
+
+=item $ua->delay([$minutes])
+
+Set the minimum delay between requests to the same server.  The
+default is 1 minute.
+
+=item $ua->use_sleep([$boolean])
+
+Get/set a value indicating wether the UA should sleep() if request
+arrive to fast (before $ua->delay minutes has passed).  The default is
+TRUE.  If this value is FALSE then an internal SERVICE_UNAVAILABLE
+response will be generated.  It will have an Retry-After header that
+indicate when it is OK to send another request to this server.
+
+=cut
+
+sub delay     { shift->_elem('delay',     @_); }
+sub use_sleep { shift->_elem('use_sleep', @_); }
+
+sub agent
+{
+    my $self = shift;
+    my $old = $self->SUPER::agent(@_);
+    if (@_) {
+	# Changing our name means to start fresh
+	$self->{'rules'}->agent($self->{'agent'}); 
+    }
+    $old;
+}
+
+
+=item $ua->rules([$rules])
+
+Set/get which I<WWW::RobotRules> object to use. 
+
+=cut
+
+sub rules {
+    my $self = shift;
+    my $old = $self->_elem('rules', @_);
+    $self->{'rules'}->agent($self->{'agent'}) if @_;
+    $old;
+}
+
+
+=item $ua->no_visits($netloc)
+
+Returns the number of documents fetched from this server host. Yes I
+know, this method should probably have been named num_visits() or
+something like that :-(
+
+=cut
+
+sub no_visits
+{
+    my($self, $netloc) = @_;
+    $self->{'rules'}->no_visits($netloc);
+}
+
+*host_count = \&no_visits;  # backwards compatibility with LWP-5.02
+
+
+=item $ua->host_wait($netloc)
+
+Returns the number of seconds (from now) you must wait before you can
+make a new request to this host.
+
+=cut
+
+sub host_wait
+{
+    my($self, $netloc) = @_;
+    return undef unless defined $netloc;
+    my $last = $self->{'rules'}->last_visit($netloc);
+    if ($last) {
+	my $wait = int($self->{'delay'} * 60 - (time - $last));
+	$wait = 0 if $wait < 0;
+	return $wait;
+    }
+    return 0;
+}
+
+
+sub simple_request
+{
+    my($self, $request, $arg, $size) = @_;
+
+    LWP::Debug::trace('()');
+
+    # Do we try to access a new server?
+    my $allowed = $self->{'rules'}->allowed($request->url);
+
+    if ($allowed < 0) {
+	LWP::Debug::debug("Host is not visited before, or robots.txt expired.");
+	# fetch "robots.txt"
+	my $robot_url = $request->url->clone;
+	$robot_url->path("robots.txt");
+	$robot_url->params(undef);
+	$robot_url->query(undef);
+	LWP::Debug::debug("Requesting $robot_url");
+
+	# make access to robot.txt legal since this will be a recursive call
+	$self->{'rules'}->parse($robot_url, ""); 
+
+	my $robot_req = new HTTP::Request 'GET', $robot_url;
+	my $robot_res = $self->request($robot_req);
+	my $fresh_until = $robot_res->fresh_until;
+	if ($robot_res->is_success) {
+	    LWP::Debug::debug("Parsing robot rules");
+	    $self->{'rules'}->parse($robot_url, $robot_res->content, 
+				    $fresh_until);
+	} else {
+	    LWP::Debug::debug("No robots.txt file found");
+	    $self->{'rules'}->parse($robot_url, "", $fresh_until);
+	}
+
+	# recalculate allowed...
+	$allowed = $self->{'rules'}->allowed($request->url);
+    }
+
+    # Check rules
+    unless ($allowed) {
+	return new HTTP::Response
+	  &HTTP::Status::RC_FORBIDDEN, 'Forbidden by robots.txt';
+    }
+
+    my $netloc = $request->url->netloc;
+    my $wait = $self->host_wait($netloc);
+
+    if ($wait) {
+	LWP::Debug::debug("Must wait $wait seconds");
+	if ($self->{'use_sleep'}) {
+	    sleep($wait)
+	} else {
+	    my $res = new HTTP::Response
+	      &HTTP::Status::RC_SERVICE_UNAVAILABLE, 'Please, slow down';
+	    $res->header('Retry-After', time2str(time + $wait));
+	    return $res;
+	}
+    }
+
+    # Perform the request
+    my $res = $self->SUPER::simple_request($request, $arg, $size);
+
+    $self->{'rules'}->visit($netloc);
+
+    $res;
+}
+
+
+=item $ua->as_string
+
+Returns a text that describe the state of the UA.
+Mainly useful for debugging.
+
+=cut
+
+sub as_string
+{
+    my $self = shift;
+    my @s;
+    push(@s, "Robot: $self->{'agent'} operated by $self->{'from'}  [$self]");
+    push(@s, "    Minimum delay: " . int($self->{'delay'}*60) . "s");
+    push(@s, "    Will sleep if too early") if $self->{'use_sleep'};
+    push(@s, "    Rules = $self->{'rules'}");
+    join("\n", @s, '');
+}
+
+1;
+
+=back
+
+=head1 SEE ALSO
+
+L<LWP::UserAgent>, L<WWW::RobotRules>
+
+=head1 COPYRIGHT
+
+Copyright 1996-1997 Gisle Aas.
+
+This library is free software; you can redistribute it and/or
+modify it under the same terms as Perl itself.
+
+=cut
Index: /main/tags/2.25/gsdl/packages/w3mir/libwww-perl-5.36/lib/LWP/Simple.pm
===================================================================
--- /main/tags/2.25/gsdl/packages/w3mir/libwww-perl-5.36/lib/LWP/Simple.pm	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/w3mir/libwww-perl-5.36/lib/LWP/Simple.pm	(revision 21064)
@@ -0,0 +1,329 @@
+#
+# $Id$
+
+=head1 NAME
+
+get, head, getprint, getstore, mirror - Procedural LWP interface
+
+=head1 SYNOPSIS
+
+ perl -MLWP::Simple -e 'getprint "http://www.sn.no"'
+
+ use LWP::Simple;
+ $content = get("http://www.sn.no/")
+ if (mirror("http://www.sn.no/", "foo") == RC_NOT_MODIFIED) {
+     ...
+ }
+
+ if (is_success(getprint("http://www.sn.no/"))) {
+     ...
+ }
+
+=head1 DESCRIPTION
+
+This interface is intended for those who want a simplified view of the
+libwww-perl library.  It should also be suitable for one-liners.  If
+you need more control or access to the header fields in the requests
+sent and responses received you should use the full object oriented
+interface provided by the C<LWP::UserAgent> module.
+
+The following functions are provided (and exported) by this module:
+
+=over 3
+
+=item get($url)
+
+The get() function will fetch the document identified by the given URL
+and return it.  It returns C<undef> if it fails.  The $url argument can
+be either a simple string or a reference to a URI::URL object.
+
+You will not be able to examine the response code or response headers
+(like 'Content-Type') when you are accessing the web using this
+function.  If you need this information you should use the full OO
+interface (see L<LWP::UserAgent>).
+
+=item head($url)
+
+Get document headers. Returns the following 5 values if successful:
+($content_type, $document_length, $modified_time, $expires, $server)
+
+Returns an empty list if it fails.  In scalar context returns TRUE if
+successful.
+
+=item getprint($url)
+
+Get and print a document identified by a URL. The document is printed
+on STDOUT as data is received from the network.  If the request fails,
+then the status code and message is printed on STDERR.  The return
+value is the HTTP response code.
+
+=item getstore($url, $file)
+
+Gets a document identified by a URL and stores it in the file. The
+return value is the HTTP response code.
+
+=item mirror($url, $file)
+
+Get and store a document identified by a URL, using
+I<If-modified-since>, and checking of the I<Content-Length>.  Returns
+the HTTP response code.
+
+=back
+
+This module also exports the HTTP::Status constants and procedures.
+These can be used when you check the response code from getprint(),
+getstore() and mirror().  The constants are:
+
+   RC_CONTINUE
+   RC_SWITCHING_PROTOCOLS
+   RC_OK
+   RC_CREATED
+   RC_ACCEPTED
+   RC_NON_AUTHORITATIVE_INFORMATION
+   RC_NO_CONTENT
+   RC_RESET_CONTENT
+   RC_PARTIAL_CONTENT
+   RC_MULTIPLE_CHOICES
+   RC_MOVED_PERMANENTLY
+   RC_MOVED_TEMPORARILY
+   RC_SEE_OTHER
+   RC_NOT_MODIFIED
+   RC_USE_PROXY
+   RC_BAD_REQUEST
+   RC_UNAUTHORIZED
+   RC_PAYMENT_REQUIRED
+   RC_FORBIDDEN
+   RC_NOT_FOUND
+   RC_METHOD_NOT_ALLOWED
+   RC_NOT_ACCEPTABLE
+   RC_PROXY_AUTHENTICATION_REQUIRED
+   RC_REQUEST_TIMEOUT
+   RC_CONFLICT
+   RC_GONE
+   RC_LENGTH_REQUIRED
+   RC_PRECONDITION_FAILED
+   RC_REQUEST_ENTITY_TOO_LARGE
+   RC_REQUEST_URI_TOO_LARGE
+   RC_UNSUPPORTED_MEDIA_TYPE
+   RC_INTERNAL_SERVER_ERROR
+   RC_NOT_IMPLEMENTED
+   RC_BAD_GATEWAY
+   RC_SERVICE_UNAVAILABLE
+   RC_GATEWAY_TIMEOUT
+   RC_HTTP_VERSION_NOT_SUPPORTED
+
+The HTTP::Status classification functions are:
+
+=over 3
+
+=item is_success($rc)
+
+Check if response code indicated successfull request.
+
+=item is_error($rc)
+
+Check if response code indicated that an error occured.
+
+=back
+
+The module will also export the LWP::UserAgent object as C<$ua> if you
+ask for it explicitly.
+
+The user agent created by this module will identify itself as
+"LWP::Simple/#.##" (where "#.##" is the libwww-perl version number)
+and will initialize its proxy defaults from the environment (by
+calling $ua->env_proxy).
+
+=head1 SEE ALSO
+
+L<LWP>, L<LWP::UserAgent>, L<HTTP::Status>, L<lwp-request>,
+L<lwp-mirror>
+
+=cut
+
+
+package LWP::Simple;
+
+use strict;
+use vars qw($ua %loop_check $FULL_LWP @EXPORT @EXPORT_OK $VERSION);
+
+require Exporter;
+
+@EXPORT = qw(get head getprint getstore mirror);
+@EXPORT_OK = qw($ua);
+
+# I really hate this.  I was a bad idea to do it in the first place.
+# Wonder how to get rid of it???  (It even makes LWP::Simple 7% slower
+# for trivial tests)
+use HTTP::Status;
+push(@EXPORT, @HTTP::Status::EXPORT);
+
+
+$VERSION = sprintf("%d.%02d", q$Revision$ =~ /(\d+)\.(\d+)/);
+$FULL_LWP++ if grep {lc($_) eq "http_proxy"} keys %ENV;
+
+
+sub import
+{
+    my $pkg = shift;
+    my $callpkg = caller;
+    if (grep $_ eq '$ua', @_) {
+	$FULL_LWP++;
+	_init_ua();
+    }
+    Exporter::export($pkg, $callpkg, @_);
+}
+
+
+sub _init_ua
+{
+    require LWP;
+    require LWP::UserAgent;
+    require HTTP::Status;
+    require HTTP::Date;
+    $ua = new LWP::UserAgent;  # we create a global UserAgent object
+    my $ver = $LWP::VERSION = $LWP::VERSION;  # avoid warning
+    $ua->agent("LWP::Simple/$LWP::VERSION");
+    $ua->env_proxy;
+}
+
+
+sub get ($)
+{
+    %loop_check = ();
+    goto \&_get;
+}
+
+
+sub get_old ($)
+{
+    my($url) = @_;
+    _init_ua() unless $ua;
+
+    my $request = HTTP::Request->new(GET => $url);
+    my $response = $ua->request($request);
+
+    return $response->content if $response->is_success;
+    return undef;
+}
+
+
+sub head ($)
+{
+    my($url) = @_;
+    _init_ua() unless $ua;
+
+    my $request = HTTP::Request->new(HEAD => $url);
+    my $response = $ua->request($request);
+
+    if ($response->is_success) {
+	return $response unless wantarray;
+	return ($response->header('Content-Type'),
+		$response->header('Content-Length'),
+		HTTP::Date::str2time($response->header('Last-Modified')),
+		HTTP::Date::str2time($response->header('Expires')),
+		$response->header('Server'),
+	       );
+    }
+    return;
+}
+
+
+sub getprint ($)
+{
+    my($url) = @_;
+    _init_ua() unless $ua;
+
+    my $request = HTTP::Request->new(GET => $url);
+    local($\) = ""; # ensure standard $OUTPUT_RECORD_SEPARATOR
+    my $response = $ua->request($request, sub { print $_[0] });
+    unless ($response->is_success) {
+	print STDERR $response->status_line, " <URL:$url>\n";
+    }
+    $response->code;
+}
+
+
+sub getstore ($$)
+{
+    my($url, $file) = @_;
+    _init_ua() unless $ua;
+
+    my $request = HTTP::Request->new(GET => $url);
+    my $response = $ua->request($request, $file);
+
+    $response->code;
+}
+
+
+sub mirror ($$)
+{
+    my($url, $file) = @_;
+    _init_ua() unless $ua;
+    my $response = $ua->mirror($url, $file);
+    $response->code;
+}
+
+
+sub _get
+{
+    my $url = shift;
+    my $ret;
+    if (!$FULL_LWP && $url =~ m,^http://([^/:]+)(?::(\d+))?(/\S*)?$,) {
+	my $host = $1;
+	my $port = $2 || 80;
+	my $path = $3;
+	$path = "/" unless defined($path);
+	return _trivial_http_get($host, $port, $path);
+    } else {
+        _init_ua() unless $ua;
+	my $request = HTTP::Request->new(GET => $url);
+	my $response = $ua->request($request);
+	return $response->is_success ? $response->content : undef;
+    }
+}
+
+
+sub _trivial_http_get
+{
+   my($host, $port, $path) = @_;
+   #print "HOST=$host, PORT=$port, PATH=$path\n";
+
+   require IO::Socket;
+   local($^W) = 0;
+   my $sock = IO::Socket::INET->new(PeerAddr => $host,
+                                    PeerPort => $port,
+                                    Proto    => 'tcp',
+                                    Timeout  => 60) || return;
+   $sock->autoflush;
+   my $netloc = $host;
+   $netloc .= ":$port" if $port != 80;
+   print $sock join("\015\012" =>
+                    "GET $path HTTP/1.0",
+                    "Host: $netloc",
+                    "User-Agent: lwp-trivial/$VERSION",
+                    "", "");
+
+   my $buf = "";
+   my $n;
+   1 while $n = sysread($sock, $buf, 8*1024, length($buf));
+   return undef unless defined($n);
+
+   if ($buf =~ m,^HTTP/\d+\.\d+\s+(\d+)[^\012]*\012,) {
+       my $code = $1;
+       #print "CODE=$code\n$buf\n";
+       if ($code =~ /^30[1237]/ && $buf =~ /\012Location:\s*(\S+)/) {
+           # redirect
+           my $url = $1;
+           return undef if $loop_check{$url}++;
+           return _get($url);
+       }
+       return undef unless $code =~ /^2/;
+       $buf =~ s/.+?\015?\012\015?\012//s;  # zap header
+   }
+
+   return $buf;
+}
+
+
+1;
Index: /main/tags/2.25/gsdl/packages/w3mir/libwww-perl-5.36/lib/LWP/UserAgent.pm
===================================================================
--- /main/tags/2.25/gsdl/packages/w3mir/libwww-perl-5.36/lib/LWP/UserAgent.pm	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/w3mir/libwww-perl-5.36/lib/LWP/UserAgent.pm	(revision 21064)
@@ -0,0 +1,732 @@
+# $Id$
+
+package LWP::UserAgent;
+use strict;
+
+=head1 NAME
+
+LWP::UserAgent - A WWW UserAgent class
+
+=head1 SYNOPSIS
+
+ require LWP::UserAgent;
+ $ua = new LWP::UserAgent;
+
+ $request = new HTTP::Request('GET', 'file://localhost/etc/motd');
+
+ $response = $ua->request($request); # or
+ $response = $ua->request($request, '/tmp/sss'); # or
+ $response = $ua->request($request, \&callback, 4096);
+
+ sub callback { my($data, $response, $protocol) = @_; .... }
+
+=head1 DESCRIPTION
+
+The C<LWP::UserAgent> is a class implementing a simple World-Wide Web
+user agent in Perl. It brings together the HTTP::Request,
+HTTP::Response and the LWP::Protocol classes that form the rest of the
+core of libwww-perl library. For simple uses this class can be used
+directly to dispatch WWW requests, alternatively it can be subclassed
+for application-specific behaviour.
+
+In normal usage the application creates a UserAgent object, and then
+configures it with values for timeouts proxies, name, etc. The next
+step is to create an instance of C<HTTP::Request> for the request that
+needs to be performed. This request is then passed to the UserAgent
+request() method, which dispatches it using the relevant protocol,
+and returns a C<HTTP::Response> object.
+
+The basic approach of the library is to use HTTP style communication
+for all protocol schemes, i.e. you will receive an C<HTTP::Response>
+object also for gopher or ftp requests.  In order to achieve even more
+similarities with HTTP style communications, gopher menus and file
+directories will be converted to HTML documents.
+
+The request() method can process the content of the response in one of
+three ways: in core, into a file, or into repeated calls of a
+subroutine.  You choose which one by the kind of value passed as the
+second argument to request().
+
+The in core variant simply returns the content in a scalar attribute
+called content() of the response object, and is suitable for small
+HTML replies that might need further parsing.  This variant is used if
+the second argument is missing (or is undef).
+
+The filename variant requires a scalar containing a filename as the
+second argument to request(), and is suitable for large WWW objects
+which need to be written directly to the file, without requiring large
+amounts of memory. In this case the response object returned from
+request() will have empty content().  If the request fails, then the
+content() might not be empty, and the file will be untouched.
+
+The subroutine variant requires a reference to callback routine as the
+second argument to request() and it can also take an optional chuck
+size as third argument.  This variant can be used to construct
+"pipe-lined" processing, where processing of received chuncks can
+begin before the complete data has arrived.  The callback function is
+called with 3 arguments: the data received this time, a reference to
+the response object and a reference to the protocol object.  The
+response object returned from request() will have empty content().  If
+the request fails, then the the callback routine will not have been
+called, and the response->content() might not be empty.
+
+The request can be aborted by calling die() within the callback
+routine.  The die message will be available as the "X-Died" special
+response header field.
+
+The library also accepts that you put a subroutine reference as
+content in the request object.  This subroutine should return the
+content (possibly in pieces) when called.  It should return an empty
+string when there is no more content.
+
+=head1 METHODS
+
+The following methods are available:
+
+=over 4
+
+=cut
+
+
+use vars qw(@ISA $VERSION);
+
+require LWP::MemberMixin;
+@ISA = qw(LWP::MemberMixin);
+$VERSION = sprintf("%d.%02d", q$Revision$ =~ /(\d+)\.(\d+)/);
+
+
+require URI::URL;
+require HTTP::Request;
+require HTTP::Response;
+
+use HTTP::Date ();
+
+use LWP ();
+use LWP::Debug ();
+use LWP::Protocol ();
+
+use Carp ();
+
+use AutoLoader ();
+*AUTOLOAD = \&AutoLoader::AUTOLOAD;  # import the AUTOLOAD method
+
+
+=item $ua = new LWP::UserAgent;
+
+Constructor for the UserAgent.  Returns a reference to a
+LWP::UserAgent object.
+
+=cut
+
+sub new
+{
+    my($class, $init) = @_;
+    LWP::Debug::trace('()');
+
+    my $self;
+    if (ref $init) {
+	$self = $init->clone;
+    } else {
+	$self = bless {
+		'agent'       => "libwww-perl/$LWP::VERSION",
+		'from'        => undef,
+		'timeout'     => 3*60,
+		'proxy'       => undef,
+		'cookie_jar'  => undef,
+		'use_eval'    => 1,
+                'parse_head'  => 1,
+                'max_size'    => undef,
+		'no_proxy'    => [],
+	}, $class;
+    }
+}
+
+
+=item $ua->simple_request($request, [$arg [, $size]])
+
+This method dispatches a single WWW request on behalf of a user, and
+returns the response received.  The C<$request> should be a reference
+to a C<HTTP::Request> object with values defined for at least the
+method() and url() attributes.
+
+If C<$arg> is a scalar it is taken as a filename where the content of
+the response is stored.
+
+If C<$arg> is a reference to a subroutine, then this routine is called
+as chunks of the content is received.  An optional C<$size> argument
+is taken as a hint for an appropriate chunk size.
+
+If C<$arg> is omitted, then the content is stored in the response
+object itself.
+
+=cut
+
+sub simple_request
+{
+    my($self, $request, $arg, $size) = @_;
+    local($SIG{__DIE__});  # protect agains user defined die handlers
+
+    my($method, $url) = ($request->method, $request->url);
+
+    # Check that we have a METHOD and a URL first
+    return HTTP::Response->new(&HTTP::Status::RC_BAD_REQUEST, "Method missing")
+	unless $method;
+    return HTTP::Response->new(&HTTP::Status::RC_BAD_REQUEST, "URL missing")
+	unless $url;
+
+    LWP::Debug::trace("$method $url");
+
+    # Locate protocol to use
+    my $scheme = '';
+    my $proxy = $self->_need_proxy($url);
+    if (defined $proxy) {
+	$scheme = $proxy->scheme;
+    } else {
+	$scheme = $url->scheme;
+    }
+    my $protocol;
+    eval {
+	$protocol = LWP::Protocol::create($scheme);
+    };
+    if ($@) {
+	$@ =~ s/\s+at\s+\S+\s+line\s+\d+\.?\s*//;  # remove file/line number
+	return HTTP::Response->new(&HTTP::Status::RC_NOT_IMPLEMENTED, $@)
+    }
+
+    # Extract fields that will be used below
+    my ($agent, $from, $timeout, $cookie_jar,
+        $use_eval, $parse_head, $max_size) =
+      @{$self}{qw(agent from timeout cookie_jar
+                  use_eval parse_head max_size)};
+
+    # Set User-Agent and From headers if they are defined
+    $request->header('User-Agent' => $agent) if $agent;
+    $request->header('From' => $from) if $from;
+    $cookie_jar->add_cookie_header($request) if $cookie_jar;
+
+    # Transfer some attributes to the protocol object
+    $protocol->parse_head($parse_head);
+    $protocol->max_size($max_size);
+    
+    my $response;
+    if ($use_eval) {
+	# we eval, and turn dies into responses below
+	eval {
+	    $response = $protocol->request($request, $proxy,
+					   $arg, $size, $timeout);
+	};
+	if ($@) {
+	    $@ =~ s/\s+at\s+\S+\s+line\s+\d+\.?\s*//;
+	    $response =
+	      HTTP::Response->new(&HTTP::Status::RC_INTERNAL_SERVER_ERROR,
+				  $@);
+	}
+    } else {
+	$response = $protocol->request($request, $proxy,
+				       $arg, $size, $timeout);
+	# XXX: Should we die unless $response->is_success ???
+    }
+
+    $response->request($request);  # record request for reference
+    $cookie_jar->extract_cookies($response) if $cookie_jar;
+    $response->header("Client-Date" => HTTP::Date::time2str(time));
+    return $response;
+}
+
+
+=item $ua->request($request, $arg [, $size])
+
+Process a request, including redirects and security.  This method may
+actually send several different simple reqeusts.
+
+The arguments are the same as for C<simple_request()>.
+
+=cut
+
+sub request
+{
+    my($self, $request, $arg, $size, $previous) = @_;
+
+    LWP::Debug::trace('()');
+
+    my $response = $self->simple_request($request, $arg, $size);
+
+    my $code = $response->code;
+    $response->previous($previous) if defined $previous;
+
+    LWP::Debug::debug('Simple result: ' . HTTP::Status::status_message($code));
+
+    if ($code == &HTTP::Status::RC_MOVED_PERMANENTLY or
+	$code == &HTTP::Status::RC_MOVED_TEMPORARILY) {
+
+	# Make a copy of the request and initialize it with the new URI
+	my $referral = $request->clone;
+
+	# And then we update the URL based on the Location:-header.
+	# Some servers erroneously return a relative URL for redirects,
+	# so make it absolute if it not already is.
+	my $referral_uri = (URI::URL->new($response->header('Location'),
+					  $response->base))->abs(undef,1);
+
+	$referral->url($referral_uri);
+
+	return $response unless $self->redirect_ok($referral);
+
+	# Check for loop in the redirects
+	my $count = 0;
+	my $r = $response;
+	while ($r) {
+	    if (++$count > 13 ||
+                $r->request->url->as_string eq $referral_uri->as_string) {
+		$response->header("Client-Warning" =>
+				  "Redirect loop detected");
+		return $response;
+	    }
+	    $r = $r->previous;
+	}
+
+	return $self->request($referral, $arg, $size, $response);
+
+    } elsif ($code == &HTTP::Status::RC_UNAUTHORIZED ||
+	     $code == &HTTP::Status::RC_PROXY_AUTHENTICATION_REQUIRED
+	    )
+    {
+	my $proxy = ($code == &HTTP::Status::RC_PROXY_AUTHENTICATION_REQUIRED);
+	my $ch_header = $proxy ?  "Proxy-Authenticate" : "WWW-Authenticate";
+	my $challenge = $response->header($ch_header);
+	unless (defined $challenge) {
+	    $response->header("Client-Warning" => 
+			      "Missing Authenticate header");
+	    return $response;
+	}
+
+	require HTTP::Headers::Util;
+	$challenge =~ tr/,/;/;  # "," is used to separate auth-params!!
+	($challenge) = HTTP::Headers::Util::split_header_words($challenge);
+	my $scheme = lc(shift(@$challenge));
+	shift(@$challenge); # no value
+	$challenge = { @$challenge };  # make rest into a hash
+	for (keys %$challenge) {       # make sure all keys are lower case
+	    $challenge->{lc $_} = delete $challenge->{$_};
+	}
+
+	unless ($scheme =~ /^([a-z]+(?:-[a-z]+)*)$/) {
+	    $response->header("Client-Warning" => 
+			      "Bad authentication scheme '$scheme'");
+	    return $response;
+	}
+	$scheme = $1;  # untainted now
+	my $class = "LWP::Authen::\u$scheme";
+	$class =~ s/-/_/g;
+	
+	no strict 'refs';
+	unless (defined %{"$class\::"}) {
+	    # try to load it
+	    eval "require $class";
+	    if ($@) {
+		if ($@ =~ /^Can\'t locate/) {
+		    $response->header("Client-Warning" =>
+				      "Unsupport authentication scheme '$scheme'");
+		} else {
+		    $response->header("Client-Warning" => $@);
+		}
+		return $response;
+	    }
+	}
+	return $class->authenticate($self, $proxy, $challenge, $response,
+				    $request, $arg, $size);
+    }
+    return $response;
+}
+
+
+=item $ua->redirect_ok
+
+This method is called by request() before it tries to do any
+redirects.  It should return a true value if the redirect is allowed
+to be performed. Subclasses might want to override this.
+
+The default implementation will return FALSE for POST request and TRUE
+for all others.
+
+=cut
+
+sub redirect_ok
+{
+    # draft-ietf-http-v10-spec-02.ps from www.ics.uci.edu, specify:
+    #
+    # If the 30[12] status code is received in response to a request using
+    # the POST method, the user agent must not automatically redirect the
+    # request unless it can be confirmed by the user, since this might change
+    # the conditions under which the request was issued.
+
+    my($self, $request) = @_;
+    return 0 if $request->method eq "POST";
+    1;
+}
+
+
+=item $ua->credentials($netloc, $realm, $uname, $pass)
+
+Set the user name and password to be used for a realm.  It is often more
+useful to specialize the get_basic_credentials() method instead.
+
+=cut
+
+sub credentials
+{
+    my($self, $netloc, $realm, $uid, $pass) = @_;
+    @{ $self->{'basic_authentication'}{$netloc}{$realm} } = ($uid, $pass);
+}
+
+
+=item $ua->get_basic_credentials($realm, $uri, [$proxy])
+
+This is called by request() to retrieve credentials for a Realm
+protected by Basic Authentication or Digest Authentication.
+
+Should return username and password in a list.  Return undef to abort
+the authentication resolution atempts.
+
+This implementation simply checks a set of pre-stored member
+variables. Subclasses can override this method to e.g. ask the user
+for a username/password.  An example of this can be found in
+C<lwp-request> program distributed with this library.
+
+=cut
+
+sub get_basic_credentials
+{
+    my($self, $realm, $uri, $proxy) = @_;
+    return if $proxy;
+
+    my $netloc = $uri->netloc;
+    if (exists $self->{'basic_authentication'}{$netloc}{$realm}) {
+	return @{ $self->{'basic_authentication'}{$netloc}{$realm} };
+    }
+
+    return (undef, undef);
+}
+
+
+=item $ua->agent([$product_id])
+
+Get/set the product token that is used to identify the user agent on
+the network.  The agent value is sent as the "User-Agent" header in
+the requests. The default agent name is "libwww-perl/#.##", where
+"#.##" is substitued with the version numer of this library.
+
+The user agent string should be one or more simple product identifiers
+with an optional version number separated by the "/" character.
+Examples are:
+
+  $ua->agent('Checkbot/0.4 ' . $ua->agent);
+  $ua->agent('Mozilla/5.0');
+
+=item $ua->from([$email_address])
+
+Get/set the Internet e-mail address for the human user who controls
+the requesting user agent.  The address should be machine-usable, as
+defined in RFC 822.  The from value is send as the "From" header in
+the requests.  There is no default.  Example:
+
+  $ua->from('aas@sn.no');
+
+=item $ua->timeout([$secs])
+
+Get/set the timeout value in seconds. The default timeout() value is
+180 seconds, i.e. 3 minutes.
+
+=item $ua->cookie_jar([$cookies])
+
+Get/set the I<HTTP::Cookies> object to use.  The default is to have no
+cookie_jar, i.e. never automatically add "Cookie" headers to the
+requests.
+
+=item $ua->parse_head([$boolean])
+
+Get/set a value indicating wether we should initialize response
+headers from the E<lt>head> section of HTML documents. The default is
+TRUE.  Do not turn this off, unless you know what you are doing.
+
+=item $ua->max_size([$bytes])
+
+Get/set the size limit for response content.  The default is undef,
+which means that there is not limit.  If the returned response content
+is only partial, because the size limit was exceeded, then a
+"X-Content-Range" header will be added to the response.
+
+=cut
+
+sub timeout    { shift->_elem('timeout',   @_); }
+sub agent      { shift->_elem('agent',     @_); }
+sub from       { shift->_elem('from',      @_); }
+sub cookie_jar { shift->_elem('cookie_jar',@_); }
+sub parse_head { shift->_elem('parse_head',@_); }
+sub max_size   { shift->_elem('max_size',  @_); }
+
+# depreciated
+sub use_eval   { shift->_elem('use_eval',  @_); }
+sub use_alarm
+{
+    Carp::carp("LWP::UserAgent->use_alarm(BOOL) is a no-op")
+	if @_ > 1 && $^W;
+    "";
+}
+
+
+# Declarations of AutoLoaded methods
+sub clone;
+sub is_protocol_supported;
+sub mirror;
+sub proxy;
+sub env_proxy;
+sub no_proxy;
+sub _need_proxy;
+
+
+1;
+__END__
+
+
+=item $ua->clone;
+
+Returns a copy of the LWP::UserAgent object
+
+=cut
+
+
+sub clone
+{
+    my $self = shift;
+    my $copy = bless { %$self }, ref $self;  # copy most fields
+
+    # elements that are references must be handled in a special way
+    $copy->{'no_proxy'} = [ @{$self->{'no_proxy'}} ];  # copy array
+
+    $copy;
+}
+
+
+=item $ua->is_protocol_supported($scheme)
+
+You can use this method to query if the library currently support the
+specified C<scheme>.  The C<scheme> might be a string (like 'http' or
+'ftp') or it might be an URI::URL object reference.
+
+=cut
+
+sub is_protocol_supported
+{
+    my($self, $scheme) = @_;
+    if (ref $scheme) {
+	# assume we got a reference to an URI::URL object
+	$scheme = $scheme->abs->scheme;
+    } else {
+	Carp::croak("Illeal scheme '$scheme' passed to is_protocol_supported")
+	    if $scheme =~ /\W/;
+	$scheme = lc $scheme;
+    }
+    return LWP::Protocol::implementor($scheme);
+}
+
+
+=item $ua->mirror($url, $file)
+
+Get and store a document identified by a URL, using If-Modified-Since,
+and checking of the Content-Length.  Returns a reference to the
+response object.
+
+=cut
+
+sub mirror
+{
+    my($self, $url, $file) = @_;
+
+    LWP::Debug::trace('()');
+    my $request = new HTTP::Request('GET', $url);
+
+    if (-e $file) {
+	my($mtime) = (stat($file))[9];
+	if($mtime) {
+	    $request->header('If-Modified-Since' =>
+			     HTTP::Date::time2str($mtime));
+	}
+    }
+    my $tmpfile = "$file-$$";
+
+    my $response = $self->request($request, $tmpfile);
+    if ($response->is_success) {
+
+	my $file_length = (stat($tmpfile))[7];
+	my($content_length) = $response->header('Content-length');
+
+	if (defined $content_length and $file_length < $content_length) {
+	    unlink($tmpfile);
+	    die "Transfer truncated: " .
+		"only $file_length out of $content_length bytes received\n";
+	} elsif (defined $content_length and $file_length > $content_length) {
+	    unlink($tmpfile);
+	    die "Content-length mismatch: " .
+		"expected $content_length bytes, got $file_length\n";
+	} else {
+	    # OK
+	    if (-e $file) {
+		# Some dosish systems fail to rename if the target exists
+		chmod 0777, $file;
+		unlink $file;
+	    }
+	    rename($tmpfile, $file) or
+		die "Cannot rename '$tmpfile' to '$file': $!\n";
+
+	    if (my $lm = $response->last_modified) {
+		# make sure the file has the same last modification time
+		utime $lm, $lm, $file;
+	    }
+	}
+    } else {
+	unlink($tmpfile);
+    }
+    return $response;
+}
+
+=item $ua->proxy(...)
+
+Set/retrieve proxy URL for a scheme:
+
+ $ua->proxy(['http', 'ftp'], 'http://proxy.sn.no:8001/');
+ $ua->proxy('gopher', 'http://proxy.sn.no:8001/');
+
+The first form specifies that the URL is to be used for proxying of
+access methods listed in the list in the first method argument,
+i.e. 'http' and 'ftp'.
+
+The second form shows a shorthand form for specifying
+proxy URL for a single access scheme.
+
+=cut
+
+sub proxy
+{
+    my($self, $key, $proxy) = @_;
+
+    LWP::Debug::trace("$key, $proxy");
+
+    if (!ref($key)) {   # single scalar passed
+	my $old = $self->{'proxy'}{$key};
+	$self->{'proxy'}{$key} = $proxy;
+	return $old;
+    } elsif (ref($key) eq 'ARRAY') {
+	for(@$key) {    # array passed
+	    $self->{'proxy'}{$_} = $proxy;
+	}
+    }
+    return undef;
+}
+
+=item $ua->env_proxy()
+
+Load proxy settings from *_proxy environment variables.  You might
+specify proxies like this (sh-syntax):
+
+  gopher_proxy=http://proxy.my.place/
+  wais_proxy=http://proxy.my.place/
+  no_proxy="my.place"
+  export gopher_proxy wais_proxy no_proxy
+
+Csh or tcsh users should use the C<setenv> command to define these
+envirionment variables.
+
+=cut
+
+sub env_proxy {
+    my ($self) = @_;
+    my($k,$v);
+    while(($k, $v) = each %ENV) {
+	$k = lc($k);
+	next unless $k =~ /^(.*)_proxy$/;
+	$k = $1;
+	if ($k eq 'no') {
+	    $self->no_proxy(split(/\s*,\s*/, $v));
+	}
+	else {
+	    $self->proxy($k, $v);
+	}
+    }
+}
+
+=item $ua->no_proxy($domain,...)
+
+Do not proxy requests to the given domains.  Calling no_proxy without
+any domains clears the list of domains. Eg:
+
+ $ua->no_proxy('localhost', 'no', ...);
+
+=cut
+
+sub no_proxy {
+    my($self, @no) = @_;
+    if (@no) {
+	push(@{ $self->{'no_proxy'} }, @no);
+    }
+    else {
+	$self->{'no_proxy'} = [];
+    }
+}
+
+
+# Private method which returns the URL of the Proxy configured for this
+# URL, or undefined if none is configured.
+sub _need_proxy
+{
+    my($self, $url) = @_;
+
+    $url = new URI::URL($url) unless ref $url;
+
+    LWP::Debug::trace("($url)");
+
+    # check the list of noproxies
+
+    if (@{ $self->{'no_proxy'} }) {
+	my $host = $url->host;
+	return undef unless defined $host;
+	my $domain;
+	for $domain (@{ $self->{'no_proxy'} }) {
+	    if ($host =~ /$domain$/) {
+		LWP::Debug::trace("no_proxy configured");
+		return undef;
+	    }
+	}
+    }
+
+    # Currently configured per scheme.
+    # Eventually want finer granularity
+
+    my $scheme = $url->scheme;
+    if (exists $self->{'proxy'}{$scheme}) {
+
+	LWP::Debug::debug('Proxied');
+	return new URI::URL($self->{'proxy'}{$scheme});
+    }
+
+    LWP::Debug::debug('Not proxied');
+    undef;
+}
+
+1;
+
+=back
+
+=head1 SEE ALSO
+
+See L<LWP> for a complete overview of libwww-perl5.  See F<lwp-request> and
+F<lwp-mirror> for examples of usage.
+
+=head1 COPYRIGHT
+
+Copyright 1995-1997 Gisle Aas.
+
+This library is free software; you can redistribute it and/or
+modify it under the same terms as Perl itself.
+
+=cut
Index: /main/tags/2.25/gsdl/packages/w3mir/libwww-perl-5.36/lib/LWP/media.types
===================================================================
--- /main/tags/2.25/gsdl/packages/w3mir/libwww-perl-5.36/lib/LWP/media.types	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/w3mir/libwww-perl-5.36/lib/LWP/media.types	(revision 21064)
@@ -0,0 +1,120 @@
+# $Id$
+#
+# This file defines the mapping from file name extentions to media types.
+# Media types where the subtype does not have the "x-" prefix should be
+# registered by IANA:
+#
+#   ftp://www.isi.edu/in-notes/iana/assignments/media-types/
+#
+# See also: RFC-1590
+
+# Text formats
+text/html			html htm
+text/plain			txt text pm el c h cc hh cxx hxx f90
+text/richtext			rtx
+text/tab-separated-values	tsv
+
+text/x-setext			etx
+text/x-pod			pod			# Perl documentation
+
+# Image formats
+image/png			png
+image/gif			gif			# Compuserve
+image/ief			ief
+image/jpeg			jpeg jpg jpe jfif
+image/tiff			tiff tif
+
+image/x-cmu-raster		ras
+image/x-portable-anymap		pnm
+image/x-portable-bitmap		pbm
+image/x-portable-graymap	pgm
+image/x-portable-pixmap		ppm
+image/x-rgb			rgb			# SGI IRIS
+image/x-xbitmap			xbm			# X Windows
+image/x-xpixmap			xpm			# X Windows
+image/x-xwindowdump		xwd			# X Windows
+image/x-bmp			bmp			# MS Windows
+image/x-targa			tga
+image/x-fits			fts
+
+
+# Audio formats
+audio/basic			au snd
+audio/x-aiff			aif aiff aifc
+audio/x-wav			wav			# MS Windows
+audio/x-mpeg-2			mp2			# MPEG layer 2 audio
+
+# Video formats
+video/mpeg			mpeg mpg mpe
+video/quicktime			qt
+video/x-msvideo			avi
+video/x-sgi-movie		mov
+
+# Message
+message/rfc822			mail
+message/partial
+message/external-body
+message/news			art
+
+# Applications
+application/octet-stream	bin
+application/postscript		ai eps ps
+application/oda			oda
+application/atomicmail
+application/andrew-insert
+application/slate
+application/wita
+application/dec-dx
+application/dca-rtf
+application/activemessage
+application/rtf			rft			# MS Word
+application/applefile
+application/mac-binhex40	hqx
+application/news-message-id
+application/news-transmission
+application/wordperfect5.1
+application/pdf			pdf
+application/zip			zip
+application/macwriteii
+application/msword
+application/remote-printing
+application/mathematica
+application/cybercash
+application/commonground
+application/iges
+application/riscos
+application/eshop
+
+application/x-mif		mif			# FrameMaker
+application/x-maker		fm
+application/x-csh		csh
+application/x-dvi		dvi
+application/x-hdf		hdf
+application/x-latex		latex
+application/x-netcdf		nc cdf
+application/x-sh		sh
+application/x-tcl		tcl
+application/x-perl		pl
+application/x-tex		tex
+application/x-texinfo		texinfo texi
+application/x-troff		t tr roff
+application/x-troff-man		man 1 2 3 4 5 6 7 8
+application/x-troff-me		me
+application/x-troff-ms		ms
+application/x-wais-source	src
+application/x-bcpio		bcpio
+application/x-cpio		cpio
+application/x-gtar		gtar			# GNU tar
+application/x-shar		shar
+application/x-sv4cpio		sv4cpio
+application/x-sv4crc		sv4crc
+application/x-tar		tar
+application/x-ustar		ustar
+
+# Multipart
+multipart/mixed
+multipart/alternative
+multipart/digest
+multipart/parallel
+multipart/appledouble
+multipart/header-set
Index: /main/tags/2.25/gsdl/packages/w3mir/libwww-perl-5.36/lib/URI/Escape.pm
===================================================================
--- /main/tags/2.25/gsdl/packages/w3mir/libwww-perl-5.36/lib/URI/Escape.pm	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/w3mir/libwww-perl-5.36/lib/URI/Escape.pm	(revision 21064)
@@ -0,0 +1,119 @@
+#
+# $Id$
+#
+
+package URI::Escape;
+use strict;
+
+=head1 NAME
+
+URI::Escape - Escape and unescape unsafe characters
+
+=head1 SYNOPSIS
+
+ use URI::Escape;
+ $safe = uri_escape("10% is enough\n");
+ $verysafe = uri_escape("foo", "\0-\377");
+ $str  = uri_unescape($safe);
+
+=head1 DESCRIPTION
+
+This module provide functions to escape and unescape URI strings.
+Some characters are regarded as "unsafe" and must be escaped in
+accordance with RFC 1738.  Escaped characters are represented by a
+triplet consisting of the character "%" followed by two hexadecimal
+digits.  The following functions are provided (and exported by
+default):
+
+=over 4
+
+=item uri_escape($string, [$unsafe])
+
+This function replaces all unsafe characters in the $string with their
+escape sequence and return the result.
+
+The uri_escape() function takes an optional second argument that
+overrides the set of characters that are to be escaped.  The set is
+specified as a string that can be used in a regular expression
+character class (between [ ]).  E.g.:
+
+  \x00-\x1f\x7f-\xff          # all control and hi-bit characters
+  a-z                         # all lower case characters
+  ^A-Za-z                     # everything not a letter
+
+The default set of characters to be escaped is:
+
+  \x00-\x20"#%;<>?{}|\\^~`\[\]\x7F-\xFF
+
+=item uri_unescape($string)
+
+Returns a string with all %XX sequences replaced with the actual
+character.
+
+=back
+
+The module can also export the %escapes hash which contains the
+mapping from all characters to the corresponding escape code.
+
+=head1 SEE ALSO
+
+L<URI::URL>
+
+
+=head1 COPYRIGHT
+
+Copyright 1995-1997 Gisle Aas.
+
+This program is free software; you can redistribute it and/or modify
+it under the same terms as Perl itself.
+
+=cut
+
+use vars qw(@ISA @EXPORT @EXPORT_OK $VERSION);
+use vars qw(%escapes);
+
+require Exporter;
+@ISA = qw(Exporter);
+@EXPORT = qw(uri_escape uri_unescape);
+@EXPORT_OK = qw(%escapes);
+$VERSION = sprintf("%d.%02d", q$Revision$ =~ /(\d+)\.(\d+)/);
+
+use Carp ();
+
+# Build a char->hex map
+for (0..255) {
+    $escapes{chr($_)} = sprintf("%%%02X", $_);
+}
+
+my %subst;  # compiled patternes
+
+sub uri_escape
+{
+    my($text, $patn) = @_;
+    return undef unless defined $text;
+    if (defined $patn){
+	unless (exists  $subst{$patn}) {
+	    # Because we can't compile regex we fake it with a cached sub
+	    $subst{$patn} =
+	      eval "sub {\$_[0] =~ s/([$patn])/\$escapes{\$1}/g; }";
+	    Carp::croak("uri_escape: $@") if $@;
+	}
+	&{$subst{$patn}}($text);
+    } else {
+	# Default unsafe characters. (RFC1738 section 2.2)
+	$text =~ s/([\x00-\x20\"#%;<>?{}|\\^~`\[\]\x7F-\xFF])/$escapes{$1}/g;
+    }
+    $text;
+}
+
+sub uri_unescape
+{
+    # Note from RFC1630:  "Sequences which start with a percent sign
+    # but are not followed by two hexadecimal characters are reserved
+    # for future extension"
+    my @copy = @_;
+    for (@copy) { s/%([\dA-Fa-f]{2})/chr(hex($1))/eg; }
+    wantarray ? @copy : $copy[0];
+}
+
+1;
Index: /main/tags/2.25/gsdl/packages/w3mir/libwww-perl-5.36/lib/URI/Heuristic.pm
===================================================================
--- /main/tags/2.25/gsdl/packages/w3mir/libwww-perl-5.36/lib/URI/Heuristic.pm	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/w3mir/libwww-perl-5.36/lib/URI/Heuristic.pm	(revision 21064)
@@ -0,0 +1,191 @@
+package URI::Heuristic;
+
+# $Id$
+
+=head1 NAME
+
+uf_urlstr - Expand URL using heuristics
+
+=head1 SYNOPSIS
+
+ use URI::Heuristic qw(uf_urlstr);
+ $url = uf_urlstr("perl");             # http://www.perl.com
+ $url = uf_urlstr("www.sol.no/sol");   # http://www.sol.no/sol
+ $url = uf_urlstr("aas");              # http://www.aas.no
+ $url = uf_urlstr("ftp.funet.fi");     # ftp://ftp.funet.fi
+ $url = uf_urlstr("/etc/passwd");      # file:/etc/passwd
+
+=head1 DESCRIPTION
+
+This module provide functions that expand strings into real absolute
+URLs using some builtin heuristics.  Strings that already represent
+absolute URLs (i.e. start with a C<scheme:> part) are never modified
+and are returned unchanged.  The main use of these functions are to
+allow abbreviated URLs similar to what many web browsers allow for URLs
+typed in by the user.
+
+The following functions are provided:
+
+=over 4
+
+=item uf_urlstr($str)
+
+The uf_urlstr() function will try to make the string passed as
+argument into a proper absolute URL string.  The "uf_" prefix stands
+for "User Friendly".
+
+=item uf_url($str)
+
+This functions work the same way as uf_urlstr() but it will
+return a C<URI::URL> object.
+
+=back
+
+=head1 ENVIRONMENT
+
+If the hostname portion of a URL does not contain any dots, then
+certain qualified guesses will be made.  These guesses are governed be
+the following two environment variables.
+
+=over 10
+
+=item COUNTRY
+
+This is the two letter country code (ISO 3166) for your location.  If
+the domain name of your host ends with two letters, then it is taken
+to be the default country. See also L<Locale::Country>.
+
+=item URL_GUESS_PATTERN
+
+Contain a space separated list of URL patterns to try.  The string
+"ACME" is for some reason used as a placeholder for the host name in
+the URL provided.  Example:
+
+ URL_GUESS_PATTERN="www.ACME.no www.ACME.se www.ACME.com"
+ export URL_GUESS_PATTERN
+
+Specifying URL_GUESS_PATTERN disables any guessing rules based on
+country.  An empty URL_GUESS_PATTERN disables any guessing that
+involves host name lookups.
+
+=back
+
+=head1 COPYRIGHT
+
+Copyright 1997-1998, Gisle Aas
+
+This library is free software; you can redistribute it and/or
+modify it under the same terms as Perl itself.
+
+=cut
+
+use strict;
+
+use vars qw(@EXPORT_OK $VERSION $MY_COUNTRY %LOCAL_GUESSING $DEBUG);
+
+require Exporter;
+*import = \&Exporter::import;
+@EXPORT_OK = qw(uf_url uf_urlstr);
+$VERSION = sprintf("%d.%02d", q$Revision$ =~ /(\d+)\.(\d+)/);
+
+eval {
+    require Net::Domain;
+    my $fqdn = Net::Domain::hostfqdn();
+    $MY_COUNTRY = lc($1) if $fqdn =~ /\.([a-zA-Z]{2})$/;
+
+    # Some other heuristics to guess country?  Perhaps looking
+    # at some environment variable (LANG, LC_ALL, ???)
+    $MY_COUNTRY = $ENV{COUNTRY} if exists $ENV{COUNTRY};
+};
+
+%LOCAL_GUESSING =
+(
+ 'us' => [qw(www.ACME.gov www.ACME.mil)],
+ 'uk' => [qw(www.ACME.co.uk www.ACME.org.uk www.ACME.ac.uk)],
+ 'au' => [qw(www.ACME.com.au www.ACME.org.au www.ACME.edu.au)],
+ 'il' => [qw(www.ACME.co.il www.ACME.org.il www.ACME.net.il)],
+ # send corrections and new entries to <aas@sn.no>
+);
+
+
+sub uf_url ($)
+{
+    require URI::URL;
+    URI::URL->new(uf_urlstr($_[0]));
+}
+
+
+sub uf_urlstr ($)
+{
+    local($_) = @_;
+    print STDERR "uf_urlstr: resolving $_\n" if $DEBUG;
+    return unless defined;
+
+    s/^\s+//;
+    s/\s+$//;
+
+    if (/^(www|web|home)\./) {
+	$_ = "http://$_";
+
+    } elsif (/^(ftp|gopher|news|wais|http|https)\./) {
+	$_ = "$1://$_";
+
+    } elsif (m,^/,      ||          # absolute file name
+	     m,^\.\.?/, ||          # relative file name
+	     m,^[a-zA-Z]:[/\\],)    # dosish file name
+    {
+	$_ = "file:$_";
+
+    } elsif (/^\w+([\.\-]\w+)*\@(\w+\.)+\w{2,3}$/) {
+	$_ = "mailto:$_";
+
+    } elsif (!/^[.+\-\w]+:/) {      # no scheme specified
+	if (s/^(\w+(?:\.\w+)*)([\/:\?\#]|$)/$2/) {
+	    my $host = $1;
+
+	    if ($host !~ /\./ && $host ne "localhost") {
+		my @guess;
+		if (exists $ENV{URL_GUESS_PATTERN}) {
+		    @guess = map { s/\bACME\b/$host/; $_ }
+		             split(' ', $ENV{URL_GUESS_PATTERN});
+		} else {
+		    if ($MY_COUNTRY) {
+			my $special = $LOCAL_GUESSING{$MY_COUNTRY};
+			if ($special) {
+			    my @special = @$special;
+			    push(@guess, map { s/\bACME\b/$host/; $_ }
+                                               @special);
+			} else {
+			    push(@guess, "www.$host.$MY_COUNTRY");
+			}
+		    }
+		    push(@guess, map "www.$host.$_",
+			             "com", "org", "net", "edu", "int");
+		}
+
+
+		my $guess;
+		for $guess (@guess) {
+		    print STDERR "uf_urlstr: gethostbyname('$guess')..."
+		      if $DEBUG;
+		    if (gethostbyname($guess)) {
+			print STDERR "yes\n" if $DEBUG;
+			$host = $guess;
+			last;
+		    }
+		    print STDERR "no\n" if $DEBUG;
+		}
+	    }
+	    $_ = "http://$host$_";
+
+	} else {
+	    # pure junk, just return it unchanged...
+
+	}
+    }
+    print STDERR "uf_urlstr: ==> $_\n" if $DEBUG;
+
+    $_;
+}
+
+1;
Index: /main/tags/2.25/gsdl/packages/w3mir/libwww-perl-5.36/lib/URI/URL.pm
===================================================================
--- /main/tags/2.25/gsdl/packages/w3mir/libwww-perl-5.36/lib/URI/URL.pm	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/w3mir/libwww-perl-5.36/lib/URI/URL.pm	(revision 21064)
@@ -0,0 +1,949 @@
+package URI::URL;
+
+$VERSION = "4.15";   # $Date$
+sub Version { $VERSION; }
+
+require 5.004;
+
+require Exporter;
+@ISA = qw(Exporter);
+@EXPORT = qw(url);
+
+require AutoLoader;
+*AUTOLOAD = \&AutoLoader::AUTOLOAD;
+
+use Carp ();
+
+# Basic lexical elements, taken from RFC 1738:
+#
+#  safe         = "$" | "-" | "_" | "." | "+"
+#  extra        = "!" | "*" | "'" | "(" | ")" | ","
+#  national     = "{" | "}" | "|" | "\" | "^" | "~" | "[" | "]" | "`"
+#  punctuation  = "<" | ">" | "#" | "%" | <">
+#  reserved     = ";" | "/" | "?" | ":" | "@" | "&" | "="
+#  escape       = "%" hex hex
+#  unreserved   = alpha | digit | safe | extra
+#  uchar        = unreserved | escape
+#  xchar        = unreserved | reserved | escape
+
+# draft-fielding-url-syntax-05.txt adds '+' to the reserved chars and
+# takes '~' out
+
+use strict;
+use vars qw($reserved $reserved_no_slash $reserved_no_form $unsafe
+	    $Debug $Strict_URL
+	   );
+
+$reserved          = ";\\/?:\\@&=+#%"; # RFC 1738 reserved pluss '#' and '%'
+$reserved_no_slash = ";?:\\@&=+#%";    # used when escaping path
+$reserved_no_form  = ";\\/?:\\@#%";    # used when escaping params and query
+
+# This is the unsafe characters (excluding those reserved)
+$unsafe   = "\x00-\x20{}|\\\\^\\[\\]`<>\"\x7F-\xFF";
+#$unsafe .= "~";  # according to RFC1738 but not to common practice
+
+$Debug         = 0;     # set to 1 to print URLs on creation
+$Strict_URL    = 0;     # see new()
+
+use overload ( '""' => 'as_string', 'fallback' => 1 );
+
+my %Implementor = (); # mapping from scheme to implementation class
+
+
+# Easy to use constructor
+sub url ($;$)
+{
+    URI::URL->new(@_);
+}
+
+
+# URI::URL objects are implemented as blessed hashes:
+#
+# Each of the URL components (scheme, netloc, user, password, host,
+# port, path, params, query, fragment) are stored under their
+# name. The netloc, path, params and query is stored in quoted
+# (escaped) form.  The others is stored unquoted (unescaped).
+#
+# Netloc is special since it is rendundant (same as
+# "user:password@host:port") and must be kept in sync with those.
+#
+# The '_str' key stores a cached stringified version of the URL
+# (by definition in quoted form).
+# The '_base' key stores the optional base of a relative URL.
+#
+# The '_orig_url' is used while debugging is on.
+#
+# Subclasses may add their own keys but must take great care to
+# avoid names which might be used in later verions of this module.
+
+sub new
+{
+    my($class, $init, $base) = @_;
+
+    my $self;
+    if (ref $init) {
+	$self = $init->clone;
+	$self->base($base) if $base;
+    } else {
+	$init = "" unless defined $init;
+	# RFC 1738 appendix suggest that we just ignore extra whitespace
+	$init =~ s/\s+//g;
+	# Also get rid of any <URL: > wrapper
+	$init =~ s/^<(?:URL:)?(.*)>$/$1/;
+
+	# We need a scheme to determine which class to use
+	my($scheme) = $init =~ m/^([.+\-\w]+):/;
+	if (!$scheme and $base){ # get scheme from base
+	    if (ref $base){ # may be object or just a string
+		$scheme = $base->scheme;
+	    } else {
+		$scheme = $1 if $base =~ m/^([.+\-\w]+):/;
+	    }
+	}
+	unless($scheme){
+	    Carp::croak("Unable to determine scheme for '$init'")
+		if $Strict_URL;
+	    $scheme = 'http';
+	}
+	my $impclass = URI::URL::implementor($scheme);
+	unless ($impclass) {
+	    Carp::croak("URI::URL scheme '$scheme' is not supported")
+		if $Strict_URL;
+	    # use generic as fallback
+	    require URI::URL::_generic;
+	    URI::URL::implementor($scheme, 'URI::URL::_generic');
+	    $impclass = 'URI::URL::_generic';
+	}
+
+	# hand-off to scheme specific implementation sub-class
+	$self->{'_orig_url'} = $init if $Debug;
+	$self = $impclass->new($init, $base);
+    }
+    $self->print_on('STDERR') if $Debug;
+    return $self;
+}
+
+
+sub clone
+{
+    my $self = shift;
+    # this work as long as none of the components are references themselves
+    bless { %$self }, ref $self;
+}
+
+
+sub implementor
+{
+    my($scheme, $impclass) = @_;
+    unless (defined $scheme) {
+	require URI::URL::_generic;
+	return 'URI::URL::_generic';
+    }
+
+    $scheme = lc($scheme);
+    if ($impclass) {
+	$impclass->_init_implementor($scheme);
+	my $old = $Implementor{$scheme};
+	$Implementor{$scheme} = $impclass;
+	return $old;
+    }
+
+    my $ic = $Implementor{$scheme};
+    return $ic if $ic;
+
+    # scheme not yet known, look for internal or
+    # preloaded (with 'use') implementation
+    $ic = "URI::URL::$scheme";  # default location
+    no strict 'refs';
+    # check we actually have one for the scheme:
+    unless (defined @{"${ic}::ISA"}) {
+	# Try to load it
+	eval { require "URI/URL/$scheme.pm"; };
+	die $@ if $@ && $@ !~ /Can\'t locate/;
+	$ic = '' unless defined @{"${ic}::ISA"};
+    }
+    if ($ic) {
+	$ic->_init_implementor($scheme);
+	$Implementor{$scheme} = $ic;
+    }
+    $ic;
+}
+
+
+sub _init_implementor
+{
+    my($class, $scheme) = @_;
+    # Remember that one implementor class may actually
+    # serve to implement several URL schemes.
+
+    if ($] < 5.003_17) {
+	no strict qw(refs);
+	# Setup overloading inheritace - experimental
+	%{"${class}::OVERLOAD"} = %URI::URL::OVERLOAD
+	    unless defined %{"${class}::OVERLOAD"};
+    }
+}
+
+
+# This private method help us implement access to the elements in the
+# URI::URL object hash (%$self).  You can set up access to an element
+# with a routine similar to this one:
+#
+#  sub component { shift->_elem('component', @_); }
+
+sub _elem
+{
+    my $self = shift;
+    my $elem = shift;
+    my $old = $self->{$elem};
+    if (@_) {
+	$self->{$elem} = shift;
+	$self->{'_str'} = '';        # void cached string
+    }
+    $old;
+}
+
+
+# Make all standard methods available to all kinds of URLs.  This allow
+# us to call these without to much worry when URI::URL::strict(0);
+
+sub bad_method;
+
+*netloc       = \&bad_method;
+*user         = \&bad_method;
+*password     = \&bad_method;
+*host         = \&bad_method;
+*port         = \&bad_method;
+*default_port = \&bad_method;
+
+*full_path    = \&bad_method;
+*epath        = \&bad_method;
+*eparams      = \&bad_method;
+*equery       = \&bad_method;
+
+*path         = \&bad_method;
+*path_components = \&bad_method;
+*params       = \&bad_method;
+*query        = \&bad_method;
+*frag         = \&bad_method;
+
+
+#
+# A U T O  L O A D I N G
+#
+# The rest of the methods are autoloaded because they should be less
+# frequently used.  We define stubs here so that inheritance works as
+# it should.
+sub newlocal;
+sub strict;
+sub base;
+sub scheme;
+sub crack;
+sub abs;
+sub rel;
+sub as_string;
+sub eq;
+sub print_on;
+
+# Don't need DESTROY but avoid trying to AUTOLOAD it.
+sub DESTROY { }
+
+1;
+__END__
+
+sub newlocal
+{
+    require URI::URL::file;
+    my $class = shift;
+    URI::URL::file->newlocal(@_);  # pass it on the the file class
+}
+
+sub strict
+{
+    return $Strict_URL unless @_;
+    my $old = $Strict_URL;
+    $Strict_URL = $_[0];
+    $old;
+}
+
+# Access some attributes of a URL object:
+sub base {
+    my $self = shift;
+    my $base  = $self->{'_base'};
+
+    if (@_) { # set
+	my $new_base = shift;
+	$new_base = $new_base->abs if ref($new_base);  # unsure absoluteness
+	$self->{_base} = $new_base;
+    }
+    return unless defined wantarray;
+
+    # The base attribute supports 'lazy' conversion from URL strings
+    # to URL objects. Strings may be stored but when a string is
+    # fetched it will automatically be converted to a URL object.
+    # The main benefit is to make it much cheaper to say:
+    #   new URI::URL $random_url_string, 'http:'
+    if (defined($base) && !ref($base)) {
+	$base = new URI::URL $base;
+	$self->_elem('_base', $base); # set new object
+    }
+    $base;
+}
+
+sub scheme {
+    my $self = shift;
+    my $old = $self->{'scheme'};
+    if (@_) {
+	my $new_scheme = shift;
+	if (defined($new_scheme) && length($new_scheme)) {
+	    # reparse URL with new scheme
+	    my $str = $self->as_string;
+	    $str =~ s/^[\w+\-.]+://;
+	    my $newself = new URI::URL "$new_scheme:$str";
+	    %$self = %$newself;
+	    bless $self, ref($newself);
+	} else {
+	    $self->{'scheme'} = undef;
+	}
+    }
+    $old;
+}
+
+sub crack
+{
+    # should be overridden by subclasses
+    my $self = shift;
+    ($self->scheme,  # 0: scheme
+     undef,          # 1: user
+     undef,          # 2: passwd
+     undef,          # 3: host
+     undef,          # 4: port
+     undef,          # 5: path
+     undef,          # 6: params
+     undef,          # 7: query
+     undef           # 8: fragment
+    )
+}
+
+# These are overridden by _generic (this is just a noop for those schemes that
+# do not wish to be a subclass of URI::URL::_generic)
+sub abs { shift->clone; }
+sub rel { shift->clone; }
+
+# This method should always be overridden in subclasses
+sub as_string {
+    "<URL>";
+}
+
+# Compare two URLs, subclasses will provide a more correct implementation
+sub eq {
+    my($self, $other) = @_;
+    $other = URI::URL->new($other, $self) unless ref $other;
+    ref($self) eq ref($other) &&
+      $self->scheme eq $other->scheme &&
+      $self->as_string eq $other->as_string;  # Case-sensitive
+}
+
+# This is set up as an alias for various methods
+sub bad_method {
+    my $self = shift;
+    my $scheme = $self->scheme;
+    Carp::croak("Illegal method called for $scheme: URL")
+	if $Strict_URL;
+    # Carp::carp("Illegal method called for $scheme: URL")
+    #     if $^W;
+    undef;
+}
+
+sub print_on
+{
+    no strict qw(refs);  # because we use strings as filehandles
+    my $self = shift;
+    my $fh = shift || 'STDERR';
+    my($k, $v);
+    print $fh "Dump of URI::URL $self...\n";
+    foreach $k (sort keys %$self){
+	$v = $self->{$k};
+	$v = 'UNDEF' unless defined $v;
+	print $fh "  $k\t'$v'\n";
+    }
+}
+
+1;
+
+
+#########################################################################
+#### D O C U M E N T A T I O N
+#########################################################################
+
+=head1 NAME
+
+URI::URL - Uniform Resource Locators (absolute and relative)
+
+=head1 SYNOPSIS
+
+ use URI::URL;
+
+ # Constructors
+ $url1 = new URI::URL 'http://www.perl.com/%7Euser/gisle.gif';
+ $url2 = new URI::URL 'gisle.gif', 'http://www.com/%7Euser';
+ $url3 = url 'http://www.sn.no/'; # handy constructor
+ $url4 = $url2->abs;       # get absolute url using base
+ $url5 = $url2->abs('http:/other/path');
+ $url6 = newlocal URI::URL 'test';
+
+ # Stringify URL
+ $str1 = $url->as_string;  # complete escaped URL string
+ $str2 = $url->full_path;  # escaped path+params+query
+ $str3 = "$url";           # use operator overloading
+
+ # Retrieving Generic-RL components:
+ $scheme   = $url->scheme;
+ $netloc   = $url->netloc; # see user,password,host,port below
+ $path     = $url->path;
+ $params   = $url->params;
+ $query    = $url->query;
+ $frag     = $url->frag;
+
+ # Accessing elements in their escaped form
+ $path     = $url->epath;
+ $params   = $url->eparams;
+ $query    = $url->equery;
+
+ # Retrieving Network location (netloc) components:
+ $user     = $url->user;
+ $password = $url->password;
+ $host     = $url->host;
+ $port     = $url->port;   # returns default if not defined
+
+ # Retrieve escaped path components as an array
+ @path     = $url->path_components;
+
+ # HTTP query-string access methods
+ @keywords = $url->keywords;
+ @form     = $url->query_form;
+
+ # All methods above can set the field values, e.g:
+ $url->scheme('http');
+ $url->host('www.w3.org');
+ $url->port($url->default_port);
+ $url->base($url5);                      # use string or object
+ $url->keywords(qw(dog bones));
+
+ # File methods
+ $url = new URI::URL "file:/foo/bar";
+ open(F, $url->local_path) or die;
+
+ # Compare URLs
+ if ($url->eq("http://www.sn.no")) or die;
+
+=head1 DESCRIPTION
+
+This module implements the URI::URL class representing Uniform
+Resource Locators (URL). URLs provide a compact string representation
+for resources available via the Internet. Both absolute (RFC 1738) and
+relative (RFC 1808) URLs are supported.
+
+URI::URL objects are created by calling new(), which takes as argument
+a string representation of the URL or an existing URL object reference
+to be cloned. Specific individual elements can then be accessed via
+the scheme(), user(), password(), host(), port(), path(), params(),
+query() and frag() methods.  In addition escaped versions of the path,
+params and query can be accessed with the epath(), eparams() and
+equery() methods.  Note that some URL schemes will support all these
+methods.
+
+The object constructor new() must be able to determine the scheme for
+the URL.  If a scheme is not specified in the URL itself, it will use
+the scheme specified by the base URL. If no base URL scheme is defined
+then new() will croak if URI::URL::strict(1) has been invoked,
+otherwise I<http> is silently assumed.  Once the scheme has been
+determined new() then uses the implementor() function to determine
+which class implements that scheme.  If no implementor class is
+defined for the scheme then new() will croak if URI::URL::strict(1)
+has been invoked, otherwise the internal generic URL class is assumed.
+
+Internally defined schemes are implemented by the
+URI::URL::I<scheme_name> module.  The URI::URL::implementor() function
+can be used to explicitly set the class used to implement a scheme if
+you want to override this.
+
+
+=head1 HOW AND WHEN TO ESCAPE
+
+
+=over 3
+
+=item This is an edited extract from a URI specification:
+
+The printability requirement has been met by specifying a safe set of
+characters, and a general escaping scheme for encoding "unsafe"
+characters. This "safe" set is suitable, for example, for use in
+electronic mail.  This is the canonical form of a URI.
+
+There is a conflict between the need to be able to represent many
+characters including spaces within a URI directly, and the need to be
+able to use a URI in environments which have limited character sets
+or in which certain characters are prone to corruption. This conflict
+has been resolved by use of an hexadecimal escaping method which may
+be applied to any characters forbidden in a given context. When URLs
+are moved between contexts, the set of characters escaped may be
+enlarged or reduced unambiguously.  The canonical form for URIs has
+all white spaces encoded.
+
+=item Notes:
+
+A URL string I<must>, by definition, consist of escaped
+components. Complete URLs are always escaped.
+
+The components of a URL string must be I<individually> escaped.  Each
+component of a URL may have a separate requirements regarding what
+must be escaped, and those requirements are also dependent on the URL
+scheme.
+
+Never escape an already escaped component string.
+
+=back
+
+This implementation expects an escaped URL string to be passed to
+new() and will return a fully escaped URL string from as_string()
+and full_path().
+
+Individual components can be manipulated in unescaped or escaped
+form. The following methods return/accept unescaped strings:
+
+    scheme                  path
+    user                    params
+    password                query
+    host                    frag
+    port
+
+The following methods return/accept partial I<escaped> strings:
+
+    netloc                  eparams
+    epath                   equery
+
+I<Partial escaped> means that only reserved characters
+(i.e. ':', '@', '/', ';', '?', '=', '&' in addition to '%', '.' and '#')
+needs to be escaped when they are to be treated as normal characters.
+I<Fully escaped> means that all unsafe characters are escaped. Unsafe
+characters are all all control characters (%00-%1F and %7F), all 8-bit
+characters (%80-%FF) as well
+as '{', '}', '|', '\', '^', '[', ']' '`', '"', '<' and '>'.
+Note that the character '~' is B<not> considered
+unsafe by this library as it is common practice to use it to reference
+personal home pages, but it is still unsafe according to RFC 1738.
+
+=head1 ADDING NEW URL SCHEMES
+
+New URL schemes or alternative implementations for existing schemes
+can be added to your own code. To create a new scheme class use code
+like:
+
+   package MYURL::foo;
+   @ISA = (URI::URL::implementor());   # inherit from generic scheme
+
+The 'URI::URL::implementor()' function call with no parameters returns
+the name of the class which implements the generic URL scheme
+behaviour (typically C<URI::URL::_generic>). All hierarchical schemes
+should be derived from this class.
+
+Your class can then define overriding methods (e.g., new(), _parse()
+as required).
+
+To register your new class as the implementor for a specific scheme
+use code like:
+
+   URI::URL::implementor('x-foo', 'MYURL::foo');
+
+Any new URL created for scheme 'x-foo' will be implemented by your
+C<MYURL::foo> class. Existing URLs will not be affected.
+
+
+=head1 FUNCTIONS
+
+=over 3
+
+=item $url = URI::URL->new( $url_string [, $base_url] )
+
+This is the object constructor.  It will create a new URI::URL object,
+initialized from the URL string.
+
+=item $url = URI::URL->newlocal($path);
+
+Returns an URL object that denotes a path within the local filesystem.
+Paths not starting with '/' are interpreted relative to the current
+working directory.  This constructor always return an absolute 'file'
+URL.
+
+=item $url = url($url_string, [, $base_url])
+
+Alternative constructor function.  The url() function is exported by
+the URI::URL module and is easier both to type and read than calling
+C<URI::URL->new> directly.  Useful for constructs like this:
+
+   $h = url($str)->host;
+
+This function is just a wrapper for URI::URL->new.
+
+=item URI::URL::strict($bool)
+
+If strict is true then we croak on errors.  The function returns the
+previous value.
+
+=item URI::URL::implementor([$scheme, [$class]])
+
+Use this function to get or set implementor class for a scheme.
+Returns '' if specified scheme is not supported.  Returns generic URL
+class if no scheme specified.
+
+=back
+
+=head1 METHODS
+
+This section describes the methods available for an URI::URL object.
+Note that some URL schemes will disallow some of these methods and
+will croak if they are used.  Some URL schemes add additional methods
+that are described in the sections to follow.
+
+Attribute access methods marked with (*) can take an optional argument
+to set the value of the attribute, and they always return the old
+value.
+
+=over 3
+
+=item $url->abs([$base])
+
+The abs() method attempts to return a new absolute URI::URL object
+for a given URL.  In order to convert a relative URL into an absolute
+one, a I<base> URL is required. You can associate a default base with a
+URL either by passing a I<base> to the new() constructor when a
+URI::URL is created or using the base() method on the object later.
+Alternatively you can specify a one-off base as a parameter to the
+abs() method.
+
+The rel() method will do the opposite transformation.
+
+Some older parsers used to allow the scheme name to be present in the
+relative URL if it was the same as the base URL scheme.  RFC1808 says
+that this should be avoided, but you can enable this old behaviour by
+setting the $URI::URL::ABS_ALLOW_RELATIVE_SCHEME variable to a TRUE
+value.  The difference is demonstrated by the following examples:
+
+  url("http:foo")->abs("http://host/a/b")     ==>  "http:foo"
+
+  local $URI::URL::ABS_ALLOW_RELATIVE_SCHEME = 1;
+  url("http:foo")->abs("http://host/a/b")     ==>  "http:/host/a/foo"
+
+You can also have the abs() method ignore if there is too many ".."
+segments in the relative URL by setting
+$URI::URL::ABS_REMOTE_LEADING_DOTS to a TRUE value.  The difference is
+demonstrated by the following examples:
+
+  url("../../../foo")->abs("http://host/a/b")   ==> "http://host/../../foo"
+
+  local $URI::URL::ABS_REMOTE_LEADING_DOTS = 1;
+  url("../../../foo")->abs("http://host/a/b")   ==> "http://host/foo"
+
+
+=item $url->as_string
+
+Returns a string representing the URL in its canonical form.  All
+unsafe characters will be escaped.  This method is overloaded as the
+perl "stringify" operator, which means that URLs can be used as
+strings in many contexts.
+
+=item $url->base (*)
+
+Get/set the base URL associated with the current URI::URL object.  The
+base URL matters when you call the abs() method.
+
+=item $url->clone
+
+Returns a copy of the current URI::URL object.
+
+=item $url->crack
+
+Return a 9 element array with the following content:
+
+   0: $url->scheme *)
+   1: $url->user
+   2: $url->password
+   3: $url->host
+   4: $url->port
+   5: $url->epath
+   6: $url->eparams
+   7: $url->equery
+   8: $url->frag
+
+All elements except I<scheme> will be undefined if the corresponding
+URL part is not available.
+
+B<Note:> The scheme (first element) returned by crack will aways be
+defined.  This is different from what the $url->scheme returns, since
+it will return I<undef> for relative URLs.
+
+=item $url->default_port
+
+Returns the default port number for the URL scheme that the URI::URL
+belongs too.
+
+=item $url->eparams (*)
+
+Get/set the URL parameters in escaped form.
+
+=item $url->epath (*)
+
+Get/set the URL path in escaped form.
+
+=item $url->eq($other_url)
+
+Compare two URLs to decide if they match or not.  The rules for how
+comparison is made varies for different parts of the URLs; scheme and
+netloc comparison is case-insensitive, and escaped chars match their
+%XX encoding unless they are "reserved" or "unsafe".
+
+=item $url->equery (*)
+
+Get/set the URL query string in escaped form.
+
+=item $url->full_path
+
+Returns the string "/path;params?query".  This is the string that is
+passed to a remote server in order to access the document.
+
+=item $url->frag (*)
+
+Get/set the fragment (unescaped)
+
+=item $url->host (*)
+
+Get/set the host (unescaped)
+
+=item $url->netloc (*)
+
+Get/set the network location in escaped form.  Setting the network
+location will affect 'user', 'password', 'host' and 'port'.
+
+=item $url->params (*)
+
+Get/set the URL parameters (unescaped)
+
+=item $url->password (*)
+
+Get/set the password (unescaped)
+
+=item $url->path (*)
+
+Get/set the path (unescaped).  This method will croak if any of the
+path components in the return value contain the "/" character.  You
+should use the epath() method to be safe.
+
+=item $url->path_components (*)
+
+Get/set the path using a list of unescaped path components.  The
+return value will loose the distinction beween '.' and '%2E'.  When
+setting a value, a '.' is converted to be a literal '.' and is
+therefore encoded as '%2E'.
+
+=item $url->port (*)
+
+Get/set the network port (unescaped)
+
+=item $url->rel([$base])
+
+Return a relative URL if possible.  This is the opposite of what the
+abs() method does.  For instance:
+
+   url("http://www.math.uio.no/doc/mail/top.html",
+       "http://www.math.uio.no/doc/linux/")->rel
+
+will return a relative URL with path set to "../mail/top.html" and
+with the same base as the original URL.
+
+If the original URL already is relative or the scheme or netloc does
+not match the base, then a copy of the original URL is returned.
+
+
+=item $url->print_on(*FILEHANDLE);
+
+Prints a verbose presentation of the contents of the URL object to
+the specified file handle (default STDERR).  Mainly useful for
+debugging.
+
+=item $url->scheme (*)
+
+Get/set the scheme for the URL.
+
+=item $url->query (*)
+
+Get/set the query string (unescaped).  This method will croak if the
+string returned contains both '+' and '%2B' or '=' together with '%3D'
+or '%26'.  You should use the equery() method to be safe.
+
+=item $url->user (*)
+
+Get/set the URL user name (unescaped)
+
+=back
+
+=head1 HTTP METHODS
+
+For I<http> URLs you may also access the query string using the
+keywords() and the query_form() methods.  Both will croak if the query
+is not of the correct format.  The encodings look like this:
+
+  word1+word2+word3..        # keywords
+  key1=val1&key2=val2...     # query_form
+
+Note: These functions does not return the old value when they are used
+to set a value of the query string.
+
+=over 3
+
+=item $url->keywords (*)
+
+The keywords() method returns a list of unescaped strings.  The method
+can also be used to set the query string by passing in the keywords as
+individual arguments to the method.
+
+=item $url->query_form (*)
+
+The query_form() method return a list of unescaped key/value pairs.
+If you assign the return value to a hash you might loose some values
+if the key is repeated (which it is allowed to do).
+
+This method can also be used to set the query sting of the URL like this:
+
+  $url->query_form(foo => 'bar', foo => 'baz', equal => '=');
+
+If the value part of a key/value pair is a reference to an array, then
+it will be converted to separate key/value pairs for each value.  This
+means that these two calls are equal:
+
+  $url->query_form(foo => 'bar', foo => 'baz');
+  $url->query_form(foo => ['bar', 'baz']);
+
+=back
+
+=head1 FILE METHODS
+
+The I<file> URLs implement the local_path() method that returns a path
+suitable for access to files within the current filesystem.  These
+methods can B<not> be used to set the path of the URL.
+
+=over 3
+
+=item $url->local_path
+
+This method is really just an alias for one of the methods below
+depending on what system you run on.
+
+=item $url->unix_path
+
+Returns a path suitable for use on a Unix system.  This method will
+croak if any of the path segments contains a "/" or a NULL character.
+
+=item $url->dos_path
+
+Returns a path suitable for use on a MS-DOS or MS-Windows system.
+
+=item $url->mac_path
+
+Returns a path suitable for use on a Macintosh system.
+
+=item $url->vms_path
+
+Returns a path suitable for use on a VMS system.  VMS is a trademark
+of Digital.
+
+=back
+
+=head1 GOPHER METHODS
+
+The methods access the parts that are specific for the gopher URLs.
+These methods access different parts of the $url->path.
+
+=over 3
+
+=item $url->gtype (*)
+
+=item $url->selector (*)
+
+=item $url->search (*)
+
+=item $url->string (*)
+
+=back
+
+=head1 NEWS METHODS
+
+=over 3
+
+=item $url->group (*)
+
+=item $url->article (*)
+
+=back
+
+=head1 WAIS METHODS
+
+The methods access the parts that are specific for the wais URLs.
+These methods access different parts of the $url->path.
+
+=over 3
+
+=item $url->database (*)
+
+=item $url->wtype (*)
+
+=item $url->wpath (*)
+
+=back
+
+=head1 MAILTO METHODS
+
+=over 3
+
+=item $url->address (*)
+
+The mail address can also be accessed with the netloc() method.
+
+=back
+
+
+=head1 WHAT A URL IS NOT
+
+URL objects do not, and should not, know how to 'get' or 'put' the
+resources they specify locations for, anymore than a postal address
+'knows' anything about the postal system. The actual access/transfer
+should be achieved by some form of transport agent class (see
+L<LWP::UserAgent>). The agent class can use the URL class, but should
+not be a subclass of it.
+
+=head1 AUTHORS / ACKNOWLEDGMENTS
+
+This module is (distantly) based on the C<wwwurl.pl> code in the
+libwww-perl distribution developed by Roy Fielding
+<fielding@ics.uci.edu>, as part of the Arcadia project at the
+University of California, Irvine, with contributions from Brooks
+Cutter.
+
+Gisle Aas <aas@sn.no>, Tim Bunce <Tim.Bunce@ig.co.uk>, Roy Fielding
+<fielding@ics.uci.edu> and Martijn Koster <m.koster@webcrawler.com>
+(in English alphabetical order) have collaborated on the complete
+rewrite for Perl 5, with input from other people on the libwww-perl
+mailing list.
+
+If you have any suggestions, bug reports, fixes, or enhancements, send
+them to the libwww-perl mailing list at <libwww-perl@ics.uci.edu>.
+
+=head1 COPYRIGHT
+
+Copyright 1995-1997 Gisle Aas.
+Copyright 1995 Martijn Koster.
+
+This program is free software; you can redistribute it and/or modify
+it under the same terms as Perl itself.
+
+=cut
Index: /main/tags/2.25/gsdl/packages/w3mir/libwww-perl-5.36/lib/URI/URL/_generic.pm
===================================================================
--- /main/tags/2.25/gsdl/packages/w3mir/libwww-perl-5.36/lib/URI/URL/_generic.pm	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/w3mir/libwww-perl-5.36/lib/URI/URL/_generic.pm	(revision 21064)
@@ -0,0 +1,514 @@
+#####################################################################
+#
+#       Internal pre-defined generic scheme support
+#
+# In this implementation all schemes are subclassed from
+# URI::URL::_generic. This turns out to have reasonable mileage.
+# See also draft-ietf-uri-relative-url-06.txt
+
+package URI::URL::_generic;           # base support for generic-RL's
+require URI::URL;
+@ISA = qw(URI::URL);
+
+use URI::Escape qw(uri_escape uri_unescape %escapes);
+
+
+sub new {                               # inherited by subclasses
+    my($class, $init, $base) = @_;
+    my $url = bless { }, $class;        # create empty object
+    $url->_parse($init);                # parse $init into components
+    $url->base($base) if $base;
+    $url;
+}
+
+
+# Generic-RL parser
+# See draft-ietf-uri-relative-url-06.txt Section 2
+
+sub _parse {
+    my($self, $u, @comps) = @_;
+    return unless defined $u;
+
+    # Deside which components to parse (scheme & path is manatory)
+    @comps = qw(netloc query params frag) unless (@comps);
+    my %parse = map {$_ => 1} @comps;
+
+    # This parsing code is based on
+    #   draft-ietf-uri-relative-url-06.txt Section 2.4
+
+    # 2.4.1
+    $self->{'frag'} = uri_unescape($1)
+      if $parse{'frag'} && $u =~ s/#(.*)$//;
+    # 2.4.2
+    $self->{'scheme'} = lc($1) if $u =~ s/^\s*([\w\+\.\-]+)://;
+    # 2.4.3
+    $self->netloc("$1")	# passing $1 directly fails if netloc is autoloaded
+      if $parse{'netloc'} && $u =~ s!^//([^/]*)!!;
+    # 2.4.4
+    $self->{'query'} = $1
+      if $parse{'query'} && $u =~ s/\?(.*)//;
+    # 2.4.5
+    $self->{'params'} = $1
+      if $parse{'params'} && $u =~ s/;(.*)//;
+
+    # 2.4.6
+    #
+    # RFC 1738 says:
+    #
+    #     Note that the "/" between the host (or port) and the
+    #     url-path is NOT part of the url-path.
+    #
+    # however, RFC 1808, 2.4.6. says:
+    #
+    #    Even though the initial slash is not part of the URL path,
+    #    the parser must remember whether or not it was present so
+    #    that later processes can differentiate between relative
+    #    and absolute paths.  Often this is done by simply storing
+    #    he preceding slash along with the path.
+    #
+    # In version < 4.01 of URI::URL we used to strip the leading
+    # "/" when asked for $self->path().  This created problems for
+    # the consitency of the interface, so now we just consider the
+    # slash to be part of the path and we also make an empty path
+    # default to "/".
+
+    # we don't test for $parse{path} becase it is mandatory
+    $self->{'path'} = $u;
+}
+
+
+# Generic-RL stringify
+#
+sub as_string
+{
+    my $self = shift;
+    return $self->{'_str'} if $self->{'_str'};
+
+    my($scheme, $netloc, $frag) = @{$self}{qw(scheme netloc frag)};
+
+    my $u = $self->full_path(1);  # path+params+query
+
+    # rfc 1808 says:
+    #    Note that the fragment identifier (and the "#" that precedes
+    #    it) is not considered part of the URL.  However, since it is
+    #    commonly used within the same string context as a URL, a parser
+    #    must be able to recognize the fragment when it is present and
+    #    set it aside as part of the parsing process.
+    $u .= "#" . uri_escape($frag, $URI::URL::unsafe) if defined $frag;
+
+    $u = "//$netloc$u" if defined $netloc;
+    $u = "$scheme:$u" if $scheme;
+    # Inline: uri_escape($u, $URI::URL::unsafe);
+    $u =~ s/([$URI::URL::unsafe])/$escapes{$1}/go;
+    $self->{'_str'} = $u;  # set cache and return
+}
+
+# Generic-RL stringify full path "path;params?query"
+#
+sub full_path
+{
+    my($self, $dont_escape)  = @_;
+    my($path, $params, $query) = @{$self}{'path', 'params', 'query'};
+    my $p = '';
+    $p .= $path if defined $path;
+    # see comment in _parse 2.4.6 about the next line
+    $p = "/$p" if defined($self->{netloc}) && $p !~ m:^/:;
+    $p .= ";$params" if defined $params;
+    $p .= "?$query"  if defined $query;
+    return $p if $dont_escape;
+    # Inline: URI::Escape::uri_escape($p, $URI::URL::unsafe);
+    $p =~ s/([$URI::URL::unsafe])/$escapes{$1}/go;
+    $p;
+}
+
+# default_port()
+#
+# subclasses will usually want to override this
+#
+sub default_port { undef; }
+
+
+#####################################################################
+#
+# Methods to handle URL's elements
+
+# These methods always return the current value,
+# so you can use $url->path to read the current value.
+# If a new value is passed, e.g. $url->path('foo'),
+# it also sets the new value, and returns the previous value.
+# Use $url->path(undef) to set the value to undefined.
+
+sub netloc {
+    my $self = shift;
+    my $old = $self->_elem('netloc', @_);
+    return $old unless @_;
+
+    # update fields derived from netloc
+    my $nl = $self->{'netloc'} || '';
+    if ($nl =~ s/^([^:@]*):?(.*?)@//){
+	$self->{'user'}     = uri_unescape($1);
+	$self->{'password'} = uri_unescape($2) if $2 ne '';
+    }
+    if ($nl =~ /^([^:]*):?(\d*)$/){
+	my $port = $2;
+	# Since this happes so frequently, we inline this call:
+	#    my $host = uri_unescape($1);
+	my $host = $1;
+	$host =~ s/%([\dA-Fa-f]{2})/chr(hex($1))/eg;
+	$self->{'host'} = $host;
+	if ($port ne '') {
+	    $self->{'port'} = $port;
+	    if ($self->default_port == $port) {
+		$self->{'netloc'} =~ s/:\d+//;
+	    }
+	} elsif (defined $self->{'netloc'}) {
+	    $self->{'netloc'} =~ s/:$//;  # handle empty port spec
+	}
+    }
+    $self->{'_str'} = '';
+    $old;
+}
+
+
+# A U T O  L O A D E R
+# Don't remove this comment, it keeps AutoSplit happy!!
+# @ISA = qw(AutoLoader)
+#
+# The rest of the methods are only loaded on demand.  Stubs are neccesary
+# for inheritance to work.
+
+#sub netloc;  # because netloc is used by the _parse()
+sub user;
+sub password;
+sub host;
+sub port;
+sub _netloc_elem;
+sub epath;
+sub path;
+sub path_components;
+sub eparams;
+sub params;
+sub equery;
+sub query;
+sub frag;
+sub crack;
+sub abs;
+sub rel;
+sub eq;
+
+1;
+__END__
+
+
+# Fields derived from generic netloc:
+sub user     { shift->_netloc_elem('user',    @_); }
+sub password { shift->_netloc_elem('password',@_); }
+sub host     { shift->_netloc_elem('host',    @_); }
+
+sub port {
+    my $self = shift;
+    my $old = $self->_netloc_elem('port', @_);
+    defined($old) ? $old : $self->default_port;
+}
+
+sub _netloc_elem {
+    my($self, $elem, @val) = @_;
+    my $old = $self->_elem($elem, @val);
+    return $old unless @val;
+
+    # update the 'netloc' element
+    my $nl = '';
+    my $host = $self->{'host'};
+    if (defined $host) {  # can't be any netloc without any host
+	my $user = $self->{'user'};
+	$nl .= uri_escape($user, $URI::URL::reserved) if defined $user;
+	$nl .= ":" . uri_escape($self->{'password'}, $URI::URL::reserved)
+	  if defined($user) and defined($self->{'password'});
+	$nl .= '@' if length $nl;
+	$nl .= uri_escape($host, $URI::URL::reserved);
+	my $port = $self->{'port'};
+	$nl .= ":$port" if defined($port) && $port != $self->default_port;
+    }
+    $self->{'netloc'} = $nl;
+    $self->{'_str'} = '';
+    $old;
+}
+
+sub epath {
+     my $self = shift;
+     my $old = $self->_elem('path', @_);
+     return '/' if !defined($old) || !length($old);
+     return "/$old" if $old !~ m|^/| && defined $self->{'netloc'};
+     $old;
+}
+
+sub path {
+    my $self = shift;
+    my $old = $self->_elem('path',
+		      map uri_escape($_, $URI::URL::reserved_no_slash), @_);
+    return unless defined wantarray;
+    return '/' if !defined($old) || !length($old);
+    Carp::croak("Path components contain '/' (you must call epath)")
+	if $old =~ /%2[fF]/ and !@_;
+    $old = "/$old" if $old !~ m|^/| && defined $self->{'netloc'};
+    return uri_unescape($old);
+}
+
+sub path_components {
+    my $self = shift;
+    my $old = $self->{'path'};
+    $old = '' unless defined $old;
+    $old = "/$old" if $old !~ m|^/| && defined $self->{'netloc'};
+    if (@_) {
+	$self->_elem('path',
+		     join("/", map {uri_escape($_, $URI::URL::reserved)} @_));
+    }
+    map { uri_unescape($_) } split("/", $old, -1);
+}
+
+sub eparams  { shift->_elem('params',  @_); }
+
+sub params {
+    my $self = shift;
+    my $old = $self->_elem('params', map {uri_escape($_,$URI::URL::reserved_no_form)} @_);
+    return uri_unescape($old) if defined $old;
+    undef;
+}
+
+sub equery   { shift->_elem('query',   @_); }
+
+sub query {
+    my $self = shift;
+    my $old = $self->_elem('query', map { uri_escape($_, $URI::URL::reserved_no_form) } @_);
+    if (defined(wantarray) && defined($old)) {
+	if ($old =~ /%(?:26|2[bB]|3[dD])/) {  # contains escaped '=' '&' or '+'
+	    my $mess;
+	    for ($old) {
+		$mess = "Query contains both '+' and '%2B'"
+		  if /\+/ && /%2[bB]/;
+		$mess = "Form query contains escaped '=' or '&'"
+		  if /=/  && /%(?:3[dD]|26)/;
+	    }
+	    if ($mess) {
+		Carp::croak("$mess (you must call equery)");
+	    }
+	}
+	# Now it should be safe to unescape the string without loosing
+	# information
+	return uri_unescape($old);
+    }
+    undef;
+
+}
+
+# No efrag method because the fragment is always stored unescaped
+sub frag     { shift->_elem('frag', @_); }
+
+sub crack
+{
+    my $self = shift;
+    return $self unless wantarray;
+    my @c = @{$self}{qw(scheme user password host port path params query frag)};
+    if (!$c[0]) {
+	# try to determine scheme
+	my $base = $self->base;
+	$c[0] = $base->scheme if $base;
+	$c[0] ||= 'http';  # last resort, default in URI::URL::new
+    }
+    $c[4] ||= $self->default_port;
+    @c;
+}
+
+# Generic-RL: Resolving Relative URL into an Absolute URL
+#
+# Based on RFC1808 section 4
+#
+sub abs
+{
+    my($self, $base, $allow_relative_scheme) = @_;
+    $allow_relative_scheme = $URI::URL::ABS_ALLOW_RELATIVE_SCHEME if @_ < 3;
+    my $embed = $self->clone;
+
+    $base = $self->base unless $base;      # default to default base
+    return $embed unless $base;            # we have no base (step1)
+
+    $base = new URI::URL $base unless ref $base; # make obj if needed
+
+    my($scheme, $host, $path, $params, $query, $frag) =
+	@{$embed}{qw(scheme host path params query frag)};
+
+    # just use base if we are empty             (2a)
+    return $base->clone
+      unless grep(defined($_) && $_ ne '',
+		  $scheme,$host,$port,$path,$params,$query,$frag);
+
+    # if we have a scheme we must already be absolute   (2b),
+    #
+    # but sec. 5.2 also says: Some older parsers allow the scheme name
+    # to be present in a relative URL if it is the same as the base
+    # URL scheme.  This is considered to be a loophole in prior
+    # specifications of the partial URLs and should be avoided by
+    # future parsers.
+    #
+    # The old behavoir can be enabled by passing a TRUE value to the
+    # $allow_relative_scheme parameter.
+    return $embed if $scheme &&
+      (!$allow_relative_scheme || $scheme ne $base->{'scheme'});
+
+    $embed->{'_str'} = '';                      # void cached string
+    $embed->{'scheme'} = $base->{'scheme'};     # (2c)
+
+    return $embed if $embed->{'netloc'};        # (3)
+    $embed->netloc($base->{'netloc'});          # (3)
+
+    return $embed if $path =~ m:^/:;            # (4)
+
+    if ($path eq '') {                          # (5)
+	$embed->{'path'} = $base->{'path'};     # (5)
+
+	return $embed if defined $embed->{'params'}; # (5a)
+	$embed->{'params'} = $base->{'params'};      # (5a)
+
+	return $embed if defined $embed->{'query'};  # (5b)
+	$embed->{'query'} = $base->{'query'};        # (5b)
+
+	return $embed;
+    }
+
+    # (Step 6)  # draft 6 suggests stack based approach
+
+    my $basepath = $base->{'path'};
+    my $relpath  = $embed->{'path'};
+
+    $basepath =~ s!^/!!;
+    $basepath =~ s!/$!/.!;                # prevent empty segment
+    my @path = split('/', $basepath);     # base path into segments
+    pop(@path);                           # remove last segment
+
+    $relpath =~ s!/$!/.!;                 # prevent empty segment
+
+    push(@path, split('/', $relpath));    # append relative segments
+
+    my @newpath = ();
+    my $isdir = 0;
+    my $segment;
+
+    foreach $segment (@path) {            # left to right
+	if ($segment eq '.') {            # ignore "same" directory
+	    $isdir = 1;
+	}
+	elsif ($segment eq '..') {
+	    $isdir = 1;
+	    my $last = pop(@newpath);
+	    if (!defined $last) {         # nothing to pop
+		push(@newpath, $segment); # so must append
+	    }
+	    elsif ($last eq '..') {       # '..' cannot match '..'
+		# so put back again, and append
+		push(@newpath, $last, $segment);
+	    }
+	    #else
+		# it was a component,
+		# keep popped
+	} else {
+	    $isdir = 0;
+	    push(@newpath, $segment);
+	}
+    }
+
+    if ($URI::URL::ABS_REMOTE_LEADING_DOTS) {
+	shift @newpath while @newpath && $newpath[0] =~ /^\.\.?$/;
+    }
+
+    $embed->{'path'} = '/' . join('/', @newpath) .
+	($isdir && @newpath ? '/' : '');
+
+    $embed;
+}
+
+# The oposite of $url->abs.  Return a URL as much relative as possible
+sub rel {
+    my($self, $base) = @_;
+    my $rel = $self->clone;
+    $base = $self->base unless $base;
+    return $rel unless $base;
+    $base = new URI::URL $base unless ref $base;
+    $rel->base($base);
+
+    my($scheme, $netloc, $path) = @{$rel}{qw(scheme netloc path)};
+    if (!defined($scheme) && !defined($netloc)) {
+	# it is already relative
+	return $rel;
+    }
+
+    my($bscheme, $bnetloc, $bpath) = @{$base}{qw(scheme netloc path)};
+    for ($bscheme, $bnetloc, $netloc) { $_ = '' unless defined }
+
+    unless ($scheme eq $bscheme && $netloc eq $bnetloc) {
+	# different location, can't make it relative
+	return $rel;
+    }
+
+    for ($path, $bpath) {  $_ = "/$_" unless m,^/,; }
+
+    # Make it relative by eliminating scheme and netloc
+    $rel->{'scheme'} = undef;
+    $rel->netloc(undef);
+
+    # This loop is based on code from Nicolai Langfeldt <janl@ifi.uio.no>.
+    # First we calculate common initial path components length ($li).
+    my $li = 1;
+    while (1) {
+	my $i = index($path, '/', $li);
+	last if $i < 0 ||
+                $i != index($bpath, '/', $li) ||
+	        substr($path,$li,$i-$li) ne substr($bpath,$li,$i-$li);
+	$li=$i+1;
+    }
+    # then we nuke it from both paths
+    substr($path, 0,$li) = '';
+    substr($bpath,0,$li) = '';
+
+    if ($path eq $bpath && defined($rel->frag) && !defined($rel->equery)) {
+        $rel->epath('');
+    } else {
+        # Add one "../" for each path component left in the base path
+        $path = ('../' x $bpath =~ tr|/|/|) . $path;
+	$path = "./" if $path eq "";
+        $rel->epath($path);
+    }
+
+    $rel;
+}
+
+
+# Compare two URLs
+sub eq {
+    my($self, $other) = @_;
+    local($^W) = 0; # avoid warnings if we compare undef values
+    $other = URI::URL->new($other, $self) unless ref $other;
+
+    # Compare scheme and netloc
+    return 0 if ref($self) ne ref($other);                # must be same class
+    return 0 if $self->scheme ne $other->scheme;          # Always lower case
+    return 0 if lc($self->netloc) ne lc($other->netloc);  # Case-insensitive
+
+    # Compare full_path:
+    # According to <draft-ietf-http-v11-spec-05>:
+    # Characters other than those in the "reserved" and "unsafe" sets
+    # are equivalent to their %XX encodings.
+    my $fp1 = $self->full_path;
+    my $fp2 = $other->full_path;
+    for ($fp1, $fp2) {
+	s,%([\dA-Fa-f]{2}),
+	  my $x = $1;
+	  my $c = chr(hex($x));
+	  $c =~ /^[;\/?:\@&=+\"\#%<>\0-\040\177]/ ? "%\L$x" : $c;
+	,eg;
+    }
+    return 0 if $fp1 ne $fp2;
+    return 0 if $self->frag ne $other->frag;
+    1;
+}
+
+1;
Index: /main/tags/2.25/gsdl/packages/w3mir/libwww-perl-5.36/lib/URI/URL/_login.pm
===================================================================
--- /main/tags/2.25/gsdl/packages/w3mir/libwww-perl-5.36/lib/URI/URL/_login.pm	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/w3mir/libwww-perl-5.36/lib/URI/URL/_login.pm	(revision 21064)
@@ -0,0 +1,25 @@
+package URI::URL::_login;
+require URI::URL::_generic;
+@ISA = qw(URI::URL::_generic);
+
+
+# Generic terminal logins.  This is used as a base class for 'telnet',
+# 'tn3270', and 'rlogin' URL schemes.
+
+
+sub _parse {
+    my($self, $init) = @_;
+    # All we want from _generic is the 'netloc' handling.
+    $self->URI::URL::_generic::_parse($init, 'netloc');
+}
+
+
+*path      = \&URI::URL::bad_method;
+*epath     = \&URI::URL::bad_method;
+*query     = \&URI::URL::bad_method;
+*equery    = \&URI::URL::bad_method;
+*params    = \&URI::URL::bad_method;
+*eparams   = \&URI::URL::bad_method;
+*frag      = \&URI::URL::bad_method;
+
+1;
Index: /main/tags/2.25/gsdl/packages/w3mir/libwww-perl-5.36/lib/URI/URL/data.pm
===================================================================
--- /main/tags/2.25/gsdl/packages/w3mir/libwww-perl-5.36/lib/URI/URL/data.pm	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/w3mir/libwww-perl-5.36/lib/URI/URL/data.pm	(revision 21064)
@@ -0,0 +1,160 @@
+package URI::URL::data;
+
+# Implements data:-URLs as specified in draft-masinter-url-data-02.txt
+#
+# Abstract
+#
+# A new URL scheme, "data", is defined. It allows inclusion of small
+# data items as "immediate" data, as if it had been included externally.
+#
+# Description
+#
+# Some applications that use URLs also have a need to embed (small)
+# media type data directly inline. This document defines a new URL
+# scheme that would work like 'immediate addressing'. The URLs are of
+# the form:
+#
+#        data:[<mediatype>][;base64],<data>
+#
+
+require URI::URL;
+@ISA = qw(URI::URL);
+
+use URI::Escape;
+use MIME::Base64 ();
+
+# as defined in rfc1522.txt
+my $tspecial  = qq(()<>@,;:/[]?.=);
+my $tokenchar = qq([^\\s\000-\037\177-\377\Q$tspecial\E]);
+
+
+sub new {
+    my($class, $init, $base) = @_;
+
+    my $self = bless { }, $class;
+
+    $self->{'scheme'} = lc($1) if $init =~ s/^\s*([\w\+\.\-]+)://;
+    $self->{'frag'} = $1 if $init =~ s/\#(.*)$//;
+
+    my $type = "";
+    if ($init =~ s/^($tokenchar+\/$tokenchar+)//o) {
+	$type = $1;
+    }
+    while ($init =~ s/^;($tokenchar+)=([^,;]*)//o) {
+	# XXX should we unescape the parst
+	$type .= ";$1=$2";
+    }
+
+    $self->{'media_type'} = $type;
+
+    my $base64;
+    if ($init =~ s/^;base64//i) {
+	$base64 = 1;
+    }
+    
+    $init =~ s/^,//;
+    if ($base64) {
+	$self->{'base64'} = uri_unescape($init);
+    } else {
+	$self->{'data'} = uri_unescape($init);
+    }
+    $self->base($base) if $base;
+    $self;
+}
+
+sub media_type
+{
+    my $self = shift;
+    my $old = $self->{'media_type'};
+    if (@_) {
+	$self->{'media_type'} = shift || "";
+	delete $self->{'_str'};
+    }
+    my($type, $param) = split(/;/, $old, 2);
+    if ($type) {
+	$type = lc $type;
+    } else {
+	$type = "text/plain";
+	$param = "charset=US-ASCII" unless $param;
+    }
+    if (wantarray) {
+	return ($type, $param);
+    } else {
+	return $type;
+    }
+}
+
+sub data
+{
+    my $self = shift;
+    my $old_data;
+    my $old_base64;
+    $old_data = $self->{'data'};
+    $old_base64 = $self->{'base64'};
+    if (@_) {
+	if ($_[1]) { # base64 flag
+	    $self->{'base64'} = $_[0];
+	    delete $self->{'data'};
+	} else {
+	    $self->{'data'} = $_[0];
+	    delete $self->{'base64'};
+	}
+	delete $self->{'_str'};
+    }
+    unless (defined $old_data) {
+	$old_data = MIME::Base64::decode($old_base64);
+	$self->{'data'} = $old_data unless @_;
+    }
+    $old_data;
+}
+
+
+sub crack
+{
+    my $self = shift;
+    ($self->{'scheme'}
+     || 'data',          # scheme
+     undef,              # user
+     undef,              # passwd
+     undef,              # host
+     undef,              # port
+     $self->data,        # path
+     $self->{'media_type'},  # params
+     undef,              # query
+     $self->{'frag'}     # fragment
+    )
+}
+
+sub as_string {
+    my $self = shift;
+    return $self->{'_str'} if $self->{'_str'};
+    my $str = ($self->{'scheme'} || 'data') . ":";
+    $str .= $self->{'media_type'};
+    if (defined $self->{'base64'}) {
+	$str .= ";base64,$self->{'base64'}";
+    } else {
+	my $urlenc = uri_escape($self->{'data'});
+	my $base64 = MIME::Base64::encode($self->{'data'});
+	if (length($base64) + 7 < length($urlenc)) {
+	    $str .= ";base64,$base64";
+	    $self->{'base64'} = $base64;
+	} else {
+	    $str .= ",$urlenc";
+	}
+    }
+    $self->{'_str'} = $str;
+}
+
+sub eq {
+    my($self, $other) = @_;
+    return 0 if ref($self) ne ref($other);
+    return 0 if $self->scheme ne $other->scheme;
+
+    my $mt1 = join(";", $self->media_type);
+    my $mt2 = join(";", $other->media_type);
+    return 0 if $mt1 ne $mt2;
+
+    $self->data eq $other->data;
+}
+
+1;
Index: /main/tags/2.25/gsdl/packages/w3mir/libwww-perl-5.36/lib/URI/URL/file.pm
===================================================================
--- /main/tags/2.25/gsdl/packages/w3mir/libwww-perl-5.36/lib/URI/URL/file.pm	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/w3mir/libwww-perl-5.36/lib/URI/URL/file.pm	(revision 21064)
@@ -0,0 +1,165 @@
+package URI::URL::file;
+require URI::URL::_generic;
+@ISA = qw(URI::URL::_generic);
+
+require Carp;
+require Config;
+
+# First we try to determine what kind of system we run on
+my $os = $Config::Config{'osname'};
+OS: {
+    $ostype = 'vms', last if $os eq 'VMS';
+    $ostype = 'dos', last if $os =~ /^(?:os2|mswin32|msdos)$/i;
+    $ostype = 'mac', last if $os eq "Mac";
+    $ostype = 'unix';  # The default
+}
+# NOTE: If you add more types to this list, remember to add a xxx_path
+# method as well.
+
+# This is the BNF found in RFC 1738:
+#
+# fileurl        = "file://" [ host | "localhost" ] "/" fpath
+# fpath          = fsegment *[ "/" fsegment ]
+# fsegment       = *[ uchar | "?" | ":" | "@" | "&" | "=" ]
+# Note that fsegment can contain '?' (query) but not ';' (param)
+
+sub _parse {
+    my($self, $init) = @_;
+    # The file URL can't have query
+    $self->URI::URL::_generic::_parse($init, qw(netloc path params frag));
+}
+
+# sub local_path { ... }
+#
+# Returns a path suitable for use on the local system (we just
+# set up an alias (derived from $ostype) to one of the path methods
+# defined below)
+*local_path = \&{$ostype . "_path"};
+
+*query  = \&URI::URL::bad_method;
+*equery = \&URI::URL::bad_method;
+
+# A U T O  L O A D E R
+# Don't remove this comment, it keeps AutoSplit happy!!
+# @ISA = qw(AutoLoader)
+#
+# These methods are autoloaded as needed
+sub newlocal;
+sub unix_path;
+sub dos_path ;
+sub mac_path ;
+sub vms_path ;
+1;
+__END__
+
+sub newlocal {
+    my($class, $path) = @_;
+
+    Carp::croak("Only implemented for Unix and OS/2 file systems")
+      unless $ostype eq "unix" or $^O =~ /os2|mswin32/i;
+    # XXX: Should implement the same thing for other systems
+
+    my $url = new URI::URL "file:";
+    unless (defined $path and
+    	    ($path =~ m:^/: or 
+	     ($^O eq 'os2' and Cwd::sys_is_absolute($path)) or
+	     ($^O eq 'MSWin32' and $path =~ m<^[A-Za-z]:[\\/]|^[\\/]{2}>))) {
+	require Cwd;
+	my $cwd = Cwd::fastcwd();
+	$cwd =~ s:/?$:/:; # force trailing slash on dir
+	$path = (defined $path) ? $cwd . $path : $cwd;
+    }
+    $url->path($path);
+    $url;
+}
+
+sub unix_path
+{
+    my $self = shift;
+    my @p;
+    for ($self->path_components) {
+	Carp::croak("Path component contains '/' or '\0'") if m|[\0/]|;
+	if (@p) {
+	    next unless length $_;   # skip empty path segments
+	    next if $_ eq '.';       # skip these too
+	    if ($_ eq '..' && $p[-1] ne '..') {  # go up one level
+		pop(@p) if $p[-1] ne '';
+		next;
+	    }
+	}
+	push(@p, $_);
+    }
+    shift(@p) if @p > 1 && $p[0] eq '.';   # './' rendundant if there is more
+    return '/' if !@p || (@p == 1 && $p[0] eq '');
+    join('/', @p);
+}
+
+sub dos_path
+{
+    my $self = shift;
+    my @p;
+    for ($self->path_components) {
+	Carp::croak("Path component contains '/' or '\\'") if m|[/\\]|;
+	push(@p, uc $_);
+    }
+    my $p = join("\\", @p);
+    $p =~ s/^\\([A-Z]:)/$1/;  # Fix drive letter specification
+    $p;
+}
+
+sub mac_path
+{
+    my $self = shift;
+    my @p;
+    for ($self->path_components) {
+	Carp::croak("Path component contains ':'") if /:/;
+	# XXX: Should probably want to do something about ".." and "."
+	# path segments.  I don't know how these are represented in
+	# the Machintosh file system.  If these are valid file names
+	# then we should split the path ourself, as $u->path_components
+	# loose the distinction between '.' and '%2E'.
+	push(@p, $_);
+    }
+    if (@p && $p[0] eq '') {
+	shift @p;
+    } else {
+	unshift(@p, '');
+    }
+    join(':', @p);
+}
+
+sub vms_path
+{
+    # ????? Can some VMS people please redo this function ??????
+
+    # This is implemented based on what RFC1738 (sec 3.10) says in the
+    # VMS file example:
+    #
+    #  DISK$USER:[MY.NOTES]NOTE123456.TXT
+    #
+    #      that might become
+    #
+    #  file:/disk$user/my/notes/note12345.txt
+    #
+    # BEWARE: I don't have a VMS machine myself so this is pure guesswork!!!
+
+    my $self = shift;
+    my @p = $self->path_components;
+    my $abs = 0;
+    if (@p && $p[0] eq '') {
+	shift @p;
+	$abs = 1;
+    }
+    # First I assume there must be a dollar in a disk spesification
+    my $p = '';
+    $p = uc(shift(@p)) . ":"  if @p && $p[0] =~ /\$/;
+    my $file = pop(@p);
+    $p .= "[" . join(".", map{uc($_)} @p) . "]" if @p;
+    $p .= uc $file;
+    # XXX: How is an absolute path different from a relative one??
+    $p =~ s/\[/[./ unless $abs;
+    # XXX: How is a directory denoted??
+    $p;
+}
+
+1;
Index: /main/tags/2.25/gsdl/packages/w3mir/libwww-perl-5.36/lib/URI/URL/finger.pm
===================================================================
--- /main/tags/2.25/gsdl/packages/w3mir/libwww-perl-5.36/lib/URI/URL/finger.pm	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/w3mir/libwww-perl-5.36/lib/URI/URL/finger.pm	(revision 21064)
@@ -0,0 +1,6 @@
+package URI::URL::finger;
+require URI::URL::_generic;
+@ISA = qw(URI::URL::_generic);
+
+sub default_port { 79 }
+1;
Index: /main/tags/2.25/gsdl/packages/w3mir/libwww-perl-5.36/lib/URI/URL/ftp.pm
===================================================================
--- /main/tags/2.25/gsdl/packages/w3mir/libwww-perl-5.36/lib/URI/URL/ftp.pm	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/w3mir/libwww-perl-5.36/lib/URI/URL/ftp.pm	(revision 21064)
@@ -0,0 +1,76 @@
+package URI::URL::ftp;
+require URI::URL::_generic;
+@ISA = qw(URI::URL::_generic);
+
+sub default_port { 21 }
+
+sub _parse {
+    my($self, $init) = @_;
+    # The ftp URLs can't have any query string
+    $self->URI::URL::_generic::_parse($init, qw(netloc path params frag));
+    1;
+}
+
+
+sub user
+{
+    my($self, @val) = @_;
+    my $old = $self->SUPER::user(@val);
+    defined $old ? $old : "anonymous";
+}
+
+BEGIN {
+    $whoami = undef;
+    $fqdn   = undef;
+}
+
+sub password
+{
+    my($self, @val) = @_;
+    my $old = $self->SUPER::password(@val);
+    unless (defined $old) {
+	my $user = $self->user;
+	if ($user eq 'anonymous' || $user eq 'ftp') {
+	    # anonymous ftp login password
+	    unless (defined $fqdn) {
+		eval {
+		    require Net::Domain;
+		    $fqdn = Net::Domain::hostfqdn();
+		};
+		if ($@) {
+		    $fqdn = '';
+		}
+	    }
+	    unless (defined $whoami) {
+		$whoami = $ENV{USER} || $ENV{LOGNAME} || $ENV{USERNAME};
+		unless ($whoami) {
+		    if ($^O eq 'MSWin32') { $whoami = Win32::LoginName() }
+		    else {
+		        $whoami = getlogin || getpwuid($<) || 'unknown';
+		    }
+		}
+	    }
+	    $old = "$whoami\@$fqdn";
+	} else {
+	    $old = "";
+	}
+    }
+    $old;
+}
+
+sub crack
+{
+    my $self = shift;
+    my @c = $self->SUPER::crack;
+    if ($c[3] && !$c[1]) {
+	# hostname defined, but user is undefined
+	$c[1] = $self->user;
+	$c[2] = $self->password;
+    }
+    @c;
+}
+
+*query  = \&URI::URL::bad_method;
+*equery = \&URI::URL::bad_method;
+
+1;
Index: /main/tags/2.25/gsdl/packages/w3mir/libwww-perl-5.36/lib/URI/URL/gopher.pm
===================================================================
--- /main/tags/2.25/gsdl/packages/w3mir/libwww-perl-5.36/lib/URI/URL/gopher.pm	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/w3mir/libwww-perl-5.36/lib/URI/URL/gopher.pm	(revision 21064)
@@ -0,0 +1,82 @@
+package URI::URL::gopher;
+require URI::URL::_generic;
+@ISA = qw(URI::URL::_generic);
+
+use URI::Escape qw(uri_unescape);
+
+sub default_port { 70 }
+
+sub _parse {
+    my($self, $init)   = @_;
+    $self->URI::URL::_generic::_parse($init, qw(netloc path));
+    $self->_parse_gopherpath;
+}
+
+sub path {
+    my $self = shift;
+    my $old = $self->URI::URL::_generic::path(@_);
+    return $old unless @_;
+    $self->_parse_gopherpath;
+    $old;
+}
+
+sub epath {
+    my $self = shift;
+    my $old = $self->URI::URL::_generic::epath(@_);
+    return $old unless @_;
+    $self->_parse_gopherpath;
+    $old;
+}
+
+sub _parse_gopherpath {
+    my $self = shift;
+    my $p = $self->{'path'};
+    # not according to RFC1738, but many popular browsers accept
+    # gopher URLs with a '?' before the search string.
+    $p =~ s/\?/\t/;
+    $p = uri_unescape($p);
+
+    if (defined($p) && $p ne '/' && $p =~ s!^/?(.)!!) {
+	$self->{'gtype'} = $1;
+    } else {
+	$self->{'gtype'} = "1";
+	$p = "";
+    }
+
+    delete $self->{'selector'};
+    delete $self->{'search'};
+    delete $self->{'string'};
+
+    my @parts = split(/\t/, $p, 3);
+    $self->{'selector'} = shift @parts if @parts;
+    $self->{'search'}   = shift @parts if @parts;
+    $self->{'string'}   = shift @parts if @parts;
+}
+
+
+sub gtype    { shift->_path_elem('gtype',    @_); }
+sub selector { shift->_path_elem('selector', @_); }
+sub search   { shift->_path_elem('search',   @_); }
+sub string   { shift->_path_elem('string',   @_); }
+
+sub _path_elem {
+    my($self, $elem, @val) = @_;
+    my $old = $self->_elem($elem, @val);
+    return $old unless @val;
+
+    # construct new path based on elements
+    my $path = "/$self->{'gtype'}";
+    $path .= "$self->{'selector'}" if defined $self->{'selector'};
+    $path .= "\t$self->{'search'}" if defined $self->{'search'};
+    $path .= "\t$self->{'string'}" if defined $self->{'string'};
+    $self->{'path'} = $path;
+
+    $old;
+}
+
+*params  = \&URI::URL::bad_method;
+*qparams = \&URI::URL::bad_method;
+*query   = \&URI::URL::bad_method;
+*equery  = \&URI::URL::bad_method;
+
+1;
Index: /main/tags/2.25/gsdl/packages/w3mir/libwww-perl-5.36/lib/URI/URL/http.pm
===================================================================
--- /main/tags/2.25/gsdl/packages/w3mir/libwww-perl-5.36/lib/URI/URL/http.pm	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/w3mir/libwww-perl-5.36/lib/URI/URL/http.pm	(revision 21064)
@@ -0,0 +1,57 @@
+package URI::URL::http;
+require URI::URL::_generic;
+@ISA = qw(URI::URL::_generic);
+
+sub default_port { 80 }
+
+require Carp;
+
+# @ISA = qw(AutoLoader)      # This comment is needed by AutoSplit.
+sub keywords;
+sub query_form;
+1;
+__END__
+
+# Handle ...?dog+bones type of query
+sub keywords {
+    my $self = shift;
+    $old = $self->{'query'};
+    if (@_) {
+	# Try to set query string
+	$self->equery(join('+', map { URI::Escape::uri_escape($_, $URI::URL::reserved) } @_));
+    }
+    return if !defined($old) || !defined(wantarray);
+
+    Carp::croak("Query is not keywords") if $old =~ /=/;
+    map { URI::Escape::uri_unescape($_) } split(/\+/, $old);
+}
+
+# Handle ...?foo=bar&bar=foo type of query
+sub query_form {
+    my $self = shift;
+    $old = $self->{'query'};
+    if (@_) {
+	# Try to set query string
+	my @query;
+	my($key,$vals);
+        my $esc = $URI::URL::reserved . $URI::URL::unsafe;
+	while (($key,$vals) = splice(@_, 0, 2)) {
+	    $key = '' unless defined $key;
+	    $key =  URI::Escape::uri_escape($key, $esc);
+	    $vals = [$vals] unless ref($vals) eq 'ARRAY';
+	    my $val;
+	    for $val (@$vals) {
+		$val = '' unless defined $val;
+		$val = URI::Escape::uri_escape($val, $esc);
+		push(@query, "$key=$val");
+	    }
+	}
+	$self->equery(join('&', @query));
+    }
+    return if !defined($old) || length($old) == 0 || !defined(wantarray);
+    Carp::croak("Query is not a form") unless $old =~ /=/;
+    map { s/\+/ /g; URI::Escape::uri_unescape($_) }
+	 map { /=/ ? split(/=/, $_, 2) : ($_ => '')} split(/&/, $old);
+}
+
+1;
Index: /main/tags/2.25/gsdl/packages/w3mir/libwww-perl-5.36/lib/URI/URL/https.pm
===================================================================
--- /main/tags/2.25/gsdl/packages/w3mir/libwww-perl-5.36/lib/URI/URL/https.pm	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/w3mir/libwww-perl-5.36/lib/URI/URL/https.pm	(revision 21064)
@@ -0,0 +1,6 @@
+package URI::URL::https;
+require URI::URL::http;
+@ISA = qw(URI::URL::http);
+
+sub default_port { 443 }
+1;
Index: /main/tags/2.25/gsdl/packages/w3mir/libwww-perl-5.36/lib/URI/URL/mailto.pm
===================================================================
--- /main/tags/2.25/gsdl/packages/w3mir/libwww-perl-5.36/lib/URI/URL/mailto.pm	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/w3mir/libwww-perl-5.36/lib/URI/URL/mailto.pm	(revision 21064)
@@ -0,0 +1,78 @@
+package URI::URL::mailto;
+require URI::URL;
+@ISA = qw(URI::URL);
+
+use URI::Escape;
+
+sub new {
+    my($class, $init, $base) = @_;
+
+    my $self = bless { }, $class;
+    $self->{'scheme'} = lc($1) if $init =~ s/^\s*([\w\+\.\-]+)://;
+    $self->{'address'} = uri_unescape($init);
+    $self->base($base) if $base;
+    $self;
+}
+
+sub address { shift->_elem('address', @_); }
+
+# can use these as aliases
+*encoded822addr = \&address;   # URI::URL v3 compatibility
+*netloc         = \&address;
+
+sub user {
+    my $self = shift;
+    $old = $self->{'address'};
+    if (@_) {
+	my $new = $old;
+	$new =~ s/.*\@?/$_[0]\@/;
+	$self->{'address'} = $new;
+    }
+    $old =~ s/\@.*//;
+    $old;
+}
+
+sub host {
+    my $self = shift;
+    $old = $self->{'address'};
+    if (@_) {
+	my $new = $old;
+	$new =~ s/\@.*/\@$_[0]/;
+	$self->{'address'} = $new;
+    }
+    $old =~ s/.*\@//;
+    $old;
+}
+
+sub crack
+{
+    my $self = shift;
+    ('mailto',           # scheme
+     $self->user,        # user
+     undef,              # passwd
+     $self->host,        # host
+     undef,              # port
+     $self->{'address'}, # path
+     undef,              # params
+     undef,              # query
+     undef               # fragment
+    )
+}
+
+sub as_string {
+    my $self = shift;
+    my $str = ($self->{'scheme'} || "mailto") . ":";
+    $str .= uri_escape($self->{'address'}) if defined $self->{'address'};
+    $str;
+}
+
+sub eq {
+    my($self, $other) = @_;
+    $other = URI::URL->new($other) unless ref $other;
+
+    # Mail adresses are case-insensitive
+    $self->scheme eq $other->scheme &&
+      lc($self->{'address'}) eq lc($other->{'address'});
+}
+
+1;
Index: /main/tags/2.25/gsdl/packages/w3mir/libwww-perl-5.36/lib/URI/URL/news.pm
===================================================================
--- /main/tags/2.25/gsdl/packages/w3mir/libwww-perl-5.36/lib/URI/URL/news.pm	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/w3mir/libwww-perl-5.36/lib/URI/URL/news.pm	(revision 21064)
@@ -0,0 +1,73 @@
+package URI::URL::news;
+require URI::URL;
+@ISA = qw(URI::URL);
+
+use URI::Escape;
+
+sub new {
+    my($class, $init, $base) = @_;
+    my $self = bless { }, $class;
+    $self->{'scheme'}  = lc($1) if $init =~ s/^\s*([\w\+\.\-]+)://;
+    $self->groupart(uri_unescape($init));
+    $self->base($base) if $base;
+    $self;
+}
+
+sub groupart {
+    my $self = shift;
+    my $old = $self->{'path'};
+    if (@_) {
+	my $p = shift;
+	if (defined $p && $p =~ /\@/) {
+	    # it is an message id
+	    $p =~ s/^<(.*)>$/$1/;  # "<" and ">" should not be part of it
+	}
+	$self->{'path'} = $p;
+    }
+    $old;
+}
+
+*path = \&groupart;
+
+sub article   {
+    my $self = shift;
+    Carp::croak("Illegal article id name (does not contain '\@')")
+      if @_ && $_[0] !~ /\@/;
+    my $old = $self->groupart(@_);
+    return undef if $old !~ /\@/;
+    $old;
+}
+
+
+sub group {
+    my $self = shift;
+    Carp::croak("Illegal group name (contains '\@')")
+      if @_ && $_[0] =~ /\@/;
+    my $old = $self->groupart(@_);
+    return undef if $old =~ /\@/;
+    $old;
+}
+
+sub crack
+{
+    my $self = shift;
+    ('news',             # scheme
+     undef,              # user
+     undef,              # passwd
+     undef,              # host
+     undef,              # port
+     $self->{'path'},    # path
+     undef,              # params
+     undef,              # query
+     undef               # fragment
+    )
+}
+
+
+sub as_string {
+    my $self = shift;
+    my $scheme = $self->{'scheme'} || "news";
+    "$scheme:" . uri_escape($self->{'path'});
+}
+
+1;
Index: /main/tags/2.25/gsdl/packages/w3mir/libwww-perl-5.36/lib/URI/URL/nntp.pm
===================================================================
--- /main/tags/2.25/gsdl/packages/w3mir/libwww-perl-5.36/lib/URI/URL/nntp.pm	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/w3mir/libwww-perl-5.36/lib/URI/URL/nntp.pm	(revision 21064)
@@ -0,0 +1,44 @@
+package URI::URL::nntp;
+require URI::URL::_generic;
+@ISA = qw(URI::URL::_generic);
+
+use URI::Escape;
+
+sub default_port { 119 }
+
+sub _parse {
+    my($self, $init) = @_;
+    $self->URI::URL::_generic::_parse($init, qw(netloc path frag));
+
+    my @parts = $self->path_components;
+    shift @parts if @parts && $parts[0] eq '';
+
+    $self->{'group'} = uri_unescape($parts[0]);
+    $self->{'digits'}= uri_unescape($parts[1]);
+}
+
+sub group   { shift->_elem('group',  @_); }
+sub digits  { shift->_elem('digits', @_); }
+sub article { shift->_elem('digits', @_); }
+
+sub as_string {
+    my $self = shift;
+    my $str = "$self->{'scheme'}:";
+    $str .= "//$self->{'netloc'}" if defined $self->{'netloc'};
+    $str .= "/" . uri_escape($self->{'group'}) . "/" .
+		  uri_escape($self->{'digits'});
+    $str;
+}
+
+# Standard methods are not legal for nntp URLs
+*path      = \&URI::URL::bad_method;
+*epath     = \&URI::URL::bad_method;
+*query     = \&URI::URL::bad_method;
+*equery    = \&URI::URL::bad_method;
+*params    = \&URI::URL::bad_method;
+*eparams   = \&URI::URL::bad_method;
+*frag      = \&URI::URL::bad_method;
+*user      = \&URI::URL::bad_method;
+*password  = \&URI::URL::bad_method;
+
+1;
Index: /main/tags/2.25/gsdl/packages/w3mir/libwww-perl-5.36/lib/URI/URL/prospero.pm
===================================================================
--- /main/tags/2.25/gsdl/packages/w3mir/libwww-perl-5.36/lib/URI/URL/prospero.pm	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/w3mir/libwww-perl-5.36/lib/URI/URL/prospero.pm	(revision 21064)
@@ -0,0 +1,27 @@
+package URI::URL::prospero;
+require URI::URL::_generic;
+@ISA = qw(URI::URL::_generic);
+
+# RFC 1738 says:
+#
+#   A prospero URLs takes the form:
+#
+#      prospero://<host>:<port>/<hsoname>;<field>=<value>
+#
+#   where <host> and <port> are as described in Section 3.1. If :<port>
+#   is omitted, the port defaults to 1525. No username or password is
+#   allowed.
+#
+#   The <hsoname> is the host-specific object name in the Prospero
+#   protocol, suitably encoded.  This name is opaque and interpreted by
+#   the Prospero server.  The semicolon ";" is reserved and may not
+#   appear without quoting in the <hsoname>.
+
+sub default_port { 1525 }       # says rfc1738, section 3.11
+
+sub _parse {
+    my($self, $init) = @_;
+    $self->URI::URL::_generic::_parse($init, qw(netloc path params frag));
+}
+
+1;
Index: /main/tags/2.25/gsdl/packages/w3mir/libwww-perl-5.36/lib/URI/URL/rlogin.pm
===================================================================
--- /main/tags/2.25/gsdl/packages/w3mir/libwww-perl-5.36/lib/URI/URL/rlogin.pm	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/w3mir/libwww-perl-5.36/lib/URI/URL/rlogin.pm	(revision 21064)
@@ -0,0 +1,7 @@
+package URI::URL::rlogin;
+require URI::URL::_login;
+@ISA = qw(URI::URL::_login);
+
+sub default_port { 513 }
+
+1;
Index: /main/tags/2.25/gsdl/packages/w3mir/libwww-perl-5.36/lib/URI/URL/telnet.pm
===================================================================
--- /main/tags/2.25/gsdl/packages/w3mir/libwww-perl-5.36/lib/URI/URL/telnet.pm	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/w3mir/libwww-perl-5.36/lib/URI/URL/telnet.pm	(revision 21064)
@@ -0,0 +1,7 @@
+package URI::URL::telnet;
+require URI::URL::_login;
+@ISA = qw(URI::URL::_login);
+
+sub default_port { 23 }
+
+1;
Index: /main/tags/2.25/gsdl/packages/w3mir/libwww-perl-5.36/lib/URI/URL/tn3270.pm
===================================================================
--- /main/tags/2.25/gsdl/packages/w3mir/libwww-perl-5.36/lib/URI/URL/tn3270.pm	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/w3mir/libwww-perl-5.36/lib/URI/URL/tn3270.pm	(revision 21064)
@@ -0,0 +1,7 @@
+package URI::URL::tn3270;
+require URI::URL::_login;
+@ISA = qw(URI::URL::_login);
+
+# sub default_port { 0 }
+
+1;
Index: /main/tags/2.25/gsdl/packages/w3mir/libwww-perl-5.36/lib/URI/URL/wais.pm
===================================================================
--- /main/tags/2.25/gsdl/packages/w3mir/libwww-perl-5.36/lib/URI/URL/wais.pm	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/w3mir/libwww-perl-5.36/lib/URI/URL/wais.pm	(revision 21064)
@@ -0,0 +1,50 @@
+package URI::URL::wais;
+require URI::URL::_generic;
+@ISA = qw(URI::URL::_generic);
+
+use URI::Escape;
+
+# RFC 1738 says:
+#
+#   A WAIS URL takes one of the following forms:
+#
+#     wais://<host>:<port>/<database>
+#     wais://<host>:<port>/<database>?<search>
+#     wais://<host>:<port>/<database>/<wtype>/<wpath>
+#
+#   where <host> and <port> are as described in Section 3.1. If :<port>
+#   is omitted, the port defaults to 210.  The first form designates a
+#   WAIS database that is available for searching. The second form
+#   designates a particular search.  <database> is the name of the WAIS
+#   database being queried.
+
+
+sub default_port { 210 }
+
+sub _parse {
+    my($self, $init) = @_;
+    $self->URI::URL::_generic::_parse($init, qw(netloc path query frag));
+}
+
+# Set the path component with the specified number
+sub _path_comp
+{
+    my $self = shift;
+    my $no   = shift;
+    my @p = $self->path_components;
+    shift(@p) if @p && $p[0] eq '';
+    my $old = $p[$no];
+    if (@_) {
+	$p[$no] = $_[0];
+	$self->path_components(@p);
+    }
+    $old;
+}
+
+sub database { shift->_path_comp(0, @_); }
+sub wtype    { shift->_path_comp(1, @_); }
+sub wpath    { shift->_path_comp(2, @_); }
+
+*params   = \&URI::URL::bad_method;
+*eparams  = \&URI::URL::bad_method;
+1;
Index: /main/tags/2.25/gsdl/packages/w3mir/libwww-perl-5.36/lib/URI/URL/webster.pm
===================================================================
--- /main/tags/2.25/gsdl/packages/w3mir/libwww-perl-5.36/lib/URI/URL/webster.pm	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/w3mir/libwww-perl-5.36/lib/URI/URL/webster.pm	(revision 21064)
@@ -0,0 +1,6 @@
+package URI::URL::webster;
+require URI::URL::_generic;
+@ISA = qw(URI::URL::_generic);
+
+sub default_port { 765 }
+1;
Index: /main/tags/2.25/gsdl/packages/w3mir/libwww-perl-5.36/lib/URI/URL/whois.pm
===================================================================
--- /main/tags/2.25/gsdl/packages/w3mir/libwww-perl-5.36/lib/URI/URL/whois.pm	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/w3mir/libwww-perl-5.36/lib/URI/URL/whois.pm	(revision 21064)
@@ -0,0 +1,6 @@
+package URI::URL::whois;
+require URI::URL::_generic;
+@ISA = qw(URI::URL::_generic);
+
+sub default_port { 43 }
+1;
Index: /main/tags/2.25/gsdl/packages/w3mir/libwww-perl-5.36/lib/WWW/RobotRules.pm
===================================================================
--- /main/tags/2.25/gsdl/packages/w3mir/libwww-perl-5.36/lib/WWW/RobotRules.pm	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/w3mir/libwww-perl-5.36/lib/WWW/RobotRules.pm	(revision 21064)
@@ -0,0 +1,364 @@
+# $Id$
+
+package WWW::RobotRules;
+
+=head1 NAME
+
+WWW::RobotsRules - Parse robots.txt files
+
+=head1 SYNOPSIS
+
+ require WWW::RobotRules;
+ my $robotsrules = new WWW::RobotRules 'MOMspider/1.0';
+
+ use LWP::Simple qw(get);
+
+ $url = "http://some.place/robots.txt";
+ my $robots_txt = get $url;
+ $robotsrules->parse($url, $robots_txt);
+
+ $url = "http://some.other.place/robots.txt";
+ my $robots_txt = get $url;
+ $robotsrules->parse($url, $robots_txt);
+
+ # Now we are able to check if a URL is valid for those servers that
+ # we have obtained and parsed "robots.txt" files for.
+ if($robotsrules->allowed($url)) {
+     $c = get $url;
+     ...
+ }
+
+=head1 DESCRIPTION
+
+This module parses a F<robots.txt> file as specified in
+"A Standard for Robot Exclusion", described in
+<URL:http://info.webcrawler.com/mak/projects/robots/norobots.html>
+Webmasters can use the F<robots.txt> file to disallow conforming
+robots access to parts of their WWW server.
+
+The parsed file is kept in the WWW::RobotRules object, and this object
+provide methods to check if access to a given URL is prohibited.  The
+same WWW::RobotRules object can parse multiple F<robots.txt> files.
+
+The following methods are provided:
+
+=over 4
+
+=cut
+
+$VERSION = sprintf("%d.%02d", q$Revision$ =~ /(\d+)\.(\d+)/);
+sub Version { $VERSION; }
+
+
+use URI::URL ();
+use strict;
+
+
+=item $rules = new WWW::RobotRules 'MOMspider/1.0'
+
+This is the constructor for WWW::RobotRules objects.  The first 
+argument given to new() is the name of the robot. 
+
+=cut
+
+sub new {
+    my($class, $ua) = @_;
+
+    # This ugly hack is needed to ensure backwards compatability.
+    # The "WWW::RobotRules" class is now really abstract.
+    $class = "WWW::RobotRules::InCore" if $class eq "WWW::RobotRules";
+
+    my $self = bless { }, $class;
+    $self->agent($ua);
+    $self;
+}
+
+
+=item $rules->parse($url, $content, $fresh_until)
+
+The parse() method takes as arguments the URL that was used to
+retrieve the F</robots.txt> file, and the contents of the file.
+
+=cut
+
+sub parse {
+    my($self, $url, $txt, $fresh_until) = @_;
+
+    $url = new URI::URL $url unless ref($url);	# make it URL
+    my $netloc = $url->netloc;
+
+    $self->clear_rules($netloc);
+    $self->fresh_until($netloc, $fresh_until || (time + 365*24*3600));
+
+    my $ua;
+    my $is_me = 0;		# 1 iff this record is for me
+    my $is_anon = 0;		# 1 iff this record is for *
+    my @me_disallowed = ();	# rules disallowed for me
+    my @anon_disallowed = ();	# rules disallowed for *
+
+    # blank lines are significant, so turn CRLF into LF to avoid generating
+    # false ones
+    $txt =~ s/\015\012/\012/g;
+
+    # split at \012 (LF) or \015 (CR) (Mac text files have just CR for EOL)
+    for(split(/[\012\015]/, $txt)) {
+
+	# Lines containing only a comment are discarded completely, and
+        # therefore do not indicate a record boundary.
+	next if /^\s*\#/;
+
+	s/\s*\#.*//;        # remove comments at end-of-line
+
+	if (/^\s*$/) {	    # blank line
+	    last if $is_me; # That was our record. No need to read the rest.
+	    $is_anon = 0;
+	}
+        elsif (/^User-Agent:\s*(.*)/i) {
+	    $ua = $1;
+	    $ua =~ s/\s+$//;
+	    if ($is_me) {
+		# This record already had a User-agent that
+		# we matched, so just continue.
+	    }
+	    elsif ($ua eq '*') {
+		$is_anon = 1;
+	    }
+	    elsif($self->is_me($ua)) {
+		$is_me = 1;
+	    }
+	}
+	elsif (/^Disallow:\s*(.*)/i) {
+	    unless (defined $ua) {
+		warn "RobotRules: Disallow without preceding User-agent\n";
+		$is_anon = 1;  # assume that User-agent: * was intended
+	    }
+	    my $disallow = $1;
+	    $disallow =~ s/\s+$//;
+	    if (length $disallow) {
+		$disallow = URI::URL->new($disallow, $url)->full_path;
+	    }
+
+	    if ($is_me) {
+		push(@me_disallowed, $disallow);
+	    }
+	    elsif ($is_anon) {
+		push(@anon_disallowed, $disallow);
+	    }
+	}
+	else {
+	    warn "RobotRules: Unexpected line: $_\n";
+	}
+    }
+
+    if ($is_me) {
+	$self->push_rules($netloc, @me_disallowed);
+    } else {
+	$self->push_rules($netloc, @anon_disallowed);
+    }
+}
+
+# is_me()
+#
+# Returns TRUE if the given name matches the
+# name of this robot
+#
+sub is_me {
+    my($self, $ua) = @_;
+    my $me = $self->agent;
+    return index(lc($ua), lc($me)) >= 0;
+}
+
+=item $rules->allowed($url)
+
+Returns TRUE if this robot is allowed to retrieve this URL.
+
+=cut
+
+sub allowed {
+    my($self, $url) = @_;
+    $url = URI::URL->new($url) unless ref $url;	# make it URL
+
+    my $netloc = $url->netloc;
+
+    my $fresh_until = $self->fresh_until($netloc);
+    return -1 if !defined($fresh_until) || $fresh_until < time;
+
+    my $str = $url->full_path;
+    my $rule;
+    for $rule ($self->rules($netloc)) {
+	return 1 unless length $rule;
+	return 0 if index($str, $rule) == 0;
+    }
+    return 1;
+}
+
+# The following methods must be provided by the subclass.
+sub agent;
+sub visit;
+sub no_visits;
+sub last_visits;
+sub fresh_until;
+sub push_rules;
+sub clear_rules;
+sub rules;
+sub dump;
+
+package WWW::RobotRules::InCore;
+
+use vars qw(@ISA);
+@ISA = qw(WWW::RobotRules);
+
+=item $rules->agent([$name])
+
+Get/set the agent name. NOTE: Changing the agent name will clear the robots.txt
+rules and expire times out of the cache.
+
+=cut
+
+sub agent {
+    my ($self, $name) = @_;
+    my $old = $self->{'ua'};
+    if ($name) {
+	delete $self->{'loc'};   # all old info is now stale
+	$name =~ s!/?\s*\d+.\d+\s*$!!;  # loose version
+	$self->{'ua'}=$name;
+    }
+    $old;
+}
+
+sub visit {
+    my($self, $netloc, $time) = @_;
+    $time ||= time;
+    $self->{'loc'}{$netloc}{'last'} = $time;
+    
+    my $count = \$self->{'loc'}{$netloc}{'count'};
+    if (!defined $$count) {
+	$$count = 1;
+    } else {
+	$$count++;
+    }
+}
+
+sub no_visits {
+    my ($self, $netloc) = @_;
+    $self->{'loc'}{$netloc}{'count'};
+}
+
+sub last_visit {
+    my ($self, $netloc) = @_;
+    $self->{'loc'}{$netloc}{'last'};
+}
+
+sub fresh_until {
+    my ($self, $netloc, $fresh_until) = @_;
+    my $old = $self->{'loc'}{$netloc}{'fresh'};
+    if (defined $fresh_until) {
+	$self->{'loc'}{$netloc}{'fresh'} = $fresh_until;
+    }
+    $old;
+}
+
+sub push_rules {
+    my($self, $netloc, @rules) = @_;
+    push (@{$self->{'loc'}{$netloc}{'rules'}}, @rules);
+}
+
+sub clear_rules {
+    my($self, $netloc) = @_;
+    delete $self->{'loc'}{$netloc}{'rules'};
+}
+
+sub rules {
+    my($self, $netloc) = @_;
+    if (defined $self->{'loc'}{$netloc}{'rules'}) {
+	return @{$self->{'loc'}{$netloc}{'rules'}};
+    } else {
+	return ();
+    }
+}
+
+sub dump
+{
+    my $self = shift;
+    for (keys %$self) {
+	next if $_ eq 'loc';
+	print "$_ = $self->{$_}\n";
+    }
+    for (keys %{$self->{'loc'}}) {
+	my @rules = $self->rules($_);
+	print "$_: ", join("; ", @rules), "\n";
+	
+    }
+}
+
+1;
+
+__END__
+
+=back
+
+=head1 ROBOTS.TXT
+
+The format and semantics of the "/robots.txt" file are as follows
+(this is an edited abstract of
+<URL:http://info.webcrawler.com/mak/projects/robots/norobots.html>):
+
+The file consists of one or more records separated by one or more
+blank lines. Each record contains lines of the form
+
+  <field-name>: <value>
+
+The field name is case insensitive.  Text after the '#' character on a
+line is ignored during parsing.  This is used for comments.  The
+following <field-names> can be used:
+
+=over 3
+
+=item User-Agent
+
+The value of this field is the name of the robot the record is
+describing access policy for.  If more than one I<User-Agent> field is
+present the record describes an identical access policy for more than
+one robot. At least one field needs to be present per record.  If the
+value is '*', the record describes the default access policy for any
+robot that has not not matched any of the other records.
+
+=item Disallow
+
+The value of this field specifies a partial URL that is not to be
+visited. This can be a full path, or a partial path; any URL that
+starts with this value will not be retrieved
+
+=back
+
+=head1 ROBOTS.TXT EXAMPLES
+
+The following example "/robots.txt" file specifies that no robots
+should visit any URL starting with "/cyberworld/map/" or "/tmp/":
+
+  User-agent: *
+  Disallow: /cyberworld/map/ # This is an infinite virtual URL space
+  Disallow: /tmp/ # these will soon disappear
+
+This example "/robots.txt" file specifies that no robots should visit
+any URL starting with "/cyberworld/map/", except the robot called
+"cybermapper":
+
+  User-agent: *
+  Disallow: /cyberworld/map/ # This is an infinite virtual URL space
+
+  # Cybermapper knows where to go.
+  User-agent: cybermapper
+  Disallow:
+
+This example indicates that no robots should visit this site further:
+
+  # go away
+  User-agent: *
+  Disallow: /
+
+=head1 SEE ALSO
+
+L<LWP::RobotUA>, L<WWW::RobotRules::AnyDBM_File>
+
+=cut
Index: /main/tags/2.25/gsdl/packages/w3mir/libwww-perl-5.36/lib/WWW/RobotRules/AnyDBM_File.pm
===================================================================
--- /main/tags/2.25/gsdl/packages/w3mir/libwww-perl-5.36/lib/WWW/RobotRules/AnyDBM_File.pm	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/w3mir/libwww-perl-5.36/lib/WWW/RobotRules/AnyDBM_File.pm	(revision 21064)
@@ -0,0 +1,170 @@
+# $Id$
+
+package WWW::RobotRules::AnyDBM_File;
+
+require  WWW::RobotRules;
+@ISA = qw(WWW::RobotRules);
+$VERSION = sprintf("%d.%02d", q$Revision$ =~ /(\d+)\.(\d+)/);
+
+use Carp ();
+use AnyDBM_File;
+use Fcntl;
+use strict;
+
+=head1 NAME
+
+WWW::RobotRules::AnyDBM_File - Persistent RobotRules
+
+=head1 SYNOPSIS
+
+ require WWW::RobotRules::AnyDBM_File;
+ require LWP::RobotUA;
+
+ # Create a robot useragent that uses a diskcaching RobotRules
+ my $rules = new WWW::RobotRules::AnyDBM_File 'my-robot/1.0', 'cachefile';
+ my $ua = new WWW::RobotUA 'my-robot/1.0', 'me@foo.com', $rules;
+
+ # Then just use $ua as usual
+ $res = $ua->request($req);
+
+=head1 DESCRIPTION
+
+This is a subclass of I<WWW::RobotRules> that uses the AnyDBM_File
+package to implement persistent diskcaching of F<robots.txt> and host
+visit information.
+
+The constructor (the new() method) takes an extra argument specifying
+the name of the DBM file to use.  If the DBM file already exists, then
+you can specify undef as agent name as the name can be obtained from
+the DBM database.
+
+=cut
+
+sub new 
+{ 
+  my ($class, $ua, $file) = @_;
+  Carp::croak('WWW::RobotRules::AnyDBM_File filename required') unless $file;
+
+  my $self = bless { }, $class;
+  $self->{'filename'} = $file;
+  tie %{$self->{'dbm'}}, 'AnyDBM_File', $file, O_CREAT|O_RDWR, 0640
+    or Carp::croak("Can't open $file: $!");
+  
+  if ($ua) {
+      $self->agent($ua);
+  } else {
+      # Try to obtain name from DBM file
+      $ua = $self->{'dbm'}{"|ua-name|"};
+      Carp::croak("No agent name specified") unless $ua;
+  }
+
+  $self;
+}
+
+sub agent {
+    my($self, $newname) = @_;
+    my $old = $self->{'dbm'}{"|ua-name|"};
+    if (defined $newname) {
+	$newname =~ s!/?\s*\d+.\d+\s*$!!;  # loose version
+	unless ($old && $old eq $newname) {
+	# Old info is now stale.
+	    my $file = $self->{'filename'};
+	    untie %{$self->{'dbm'}};
+	    tie %{$self->{'dbm'}}, 'AnyDBM_File', $file, O_TRUNC|O_RDWR, 0640;
+	    $self->{'dbm'}{"|ua-name|"} = $newname;
+	}
+    }
+    $old;
+}
+
+sub no_visits {
+    my ($self, $netloc) = @_;
+    my $t = $self->{'dbm'}{"$netloc|vis"};
+    return 0 unless $t;
+    (split(/;\s*/, $t))[0];
+}
+
+sub last_visit {
+    my ($self, $netloc) = @_;
+    my $t = $self->{'dbm'}{"$netloc|vis"};
+    return undef unless $t;
+    (split(/;\s*/, $t))[1];
+}
+
+sub fresh_until {
+    my ($self, $netloc, $fresh) = @_;
+    my $old = $self->{'dbm'}{"$netloc|exp"};
+    if ($old) {
+	$old =~ s/;.*//;  # remove cleartext
+    }
+    if (defined $fresh) {
+	$fresh .= "; " . localtime($fresh);
+	$self->{'dbm'}{"$netloc|exp"} = $fresh;
+    }
+    $old;
+}
+
+sub visit {
+    my($self, $netloc, $time) = @_;
+    $time ||= time;
+
+    my $count = 0;
+    my $old = $self->{'dbm'}{"$netloc|vis"};
+    if ($old) {
+	my $last;
+	($count,$last) = split(/;\s*/, $old);
+	$time = $last if $last > $time;
+    }
+    $count++;
+    $self->{'dbm'}{"$netloc|vis"} = "$count; $time; " . localtime($time);
+}
+
+sub push_rules {
+    my($self, $netloc, @rules) = @_;
+    my $cnt = 1;
+    $cnt++ while $self->{'dbm'}{"$netloc|r$cnt"};
+
+    foreach (@rules) {
+	$self->{'dbm'}{"$netloc|r$cnt"} = $_;
+	$cnt++;
+    }
+}
+
+sub clear_rules {
+    my($self, $netloc) = @_;
+    my $cnt = 1;
+    while ($self->{'dbm'}{"$netloc|r$cnt"}) {
+	delete $self->{'dbm'}{"$netloc|r$cnt"};
+	$cnt++;
+    }
+}
+
+sub rules {
+    my($self, $netloc) = @_;
+    my @rules = ();
+    my $cnt = 1;
+    while (1) {
+	my $rule = $self->{'dbm'}{"$netloc|r$cnt"};
+	last unless $rule;
+	push(@rules, $rule);
+	$cnt++;
+    }
+    @rules;
+}
+
+sub dump
+{
+}
+
+1;
+
+=head1 SEE ALSO
+
+L<WWW::RobotRules>, L<LWP::RobotUA>
+
+=head1 AUTHORS
+
+Hakan Ardo E<lt>hakan@munin.ub2.lu.se>, Gisle Aas E<lt>aas@sn.no>
+
+=cut
+
Index: /main/tags/2.25/gsdl/packages/w3mir/libwww-perl-5.36/lwpcook.pod
===================================================================
--- /main/tags/2.25/gsdl/packages/w3mir/libwww-perl-5.36/lwpcook.pod	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/w3mir/libwww-perl-5.36/lwpcook.pod	(revision 21064)
@@ -0,0 +1,343 @@
+=head1 NAME
+
+lwpcook - libwww-perl cookbook
+
+=head1 DESCRIPTION
+
+This document contain some examples that show typical usage of the
+libwww-perl library.  You should consult the documentation for the
+individual modules for more detail.
+
+All examples should be runnable programs. You can, in most cases, test
+the code sections by piping the program text directly to perl.
+
+
+
+=head1 GET
+
+It is very easy to use this library to just fetch documents from the
+net.  The LWP::Simple module provides the get() function that return
+the document specified by its URL argument:
+
+  use LWP::Simple;
+  $doc = get 'http://www.sn.no/libwww-perl/';
+
+or, as a perl one-liner using the getprint() function:
+
+  perl -MLWP::Simple -e 'getprint "http://www.sn.no/libwww-perl/"'
+
+or, how about fetching the latest perl by running this command:
+
+  perl -MLWP::Simple -e '
+    getstore "ftp://ftp.sunet.se/pub/lang/perl/CPAN/src/latest.tar.gz",
+             "perl.tar.gz"'
+
+You will probably first want to find a CPAN site closer to you by
+running something like the following command:
+
+  perl -MLWP::Simple -e 'getprint "http://www.perl.com/perl/CPAN/CPAN.html"'
+
+Enough of this simple stuff!  The LWP object oriented interface gives
+you more control over the request sent to the server.  Using this
+interface you have full control over headers sent and how you want to
+handle the response returned.
+
+  use LWP::UserAgent;
+  $ua = new LWP::UserAgent;
+  $ua->agent("$0/0.1 " . $ua->agent);
+  # $ua->agent("Mozilla/8.0") # pretend we are very capable browser
+
+  $req = new HTTP::Request 'GET' => 'http://www.sn.no/libwww-perl';
+  $req->header('Accept' => 'text/html');
+
+  # send request
+  $res = $ua->request($req);
+
+  # check the outcome
+  if ($res->is_success) {
+     print $res->content;
+  } else {
+     print "Error: " . $res->status_line . "\n";
+  }
+
+The lwp-request program (alias GET) that is distributed with the
+library can also be used to fetch documents from WWW servers.
+  
+
+
+=head1 HEAD
+
+If you just want to check if a document is present (i.e. the URL is
+valid) try to run code that looks like this:
+
+  use LWP::Simple;
+
+  if (head($url)) {
+     # ok document exists
+  }
+
+The head() function really returns a list of meta-information about
+the document.  The first three values of the list returned are the
+document type, the size of the document, and the age of the document.
+
+More control over the request or access to all header values returned
+require that you use the object oriented interface described for GET
+above.  Just s/GET/HEAD/g.
+
+
+=head1 POST
+
+There is no simple procedural interface for posting data to a WWW server.  You
+must use the object oriented interface for this. The most common POST
+operation is to access a WWW form application:
+
+  use LWP::UserAgent;
+  $ua = new LWP::UserAgent;
+
+  my $req = new HTTP::Request 'POST','http://www.perl.com/cgi-bin/BugGlimpse';
+  $req->content_type('application/x-www-form-urlencoded');
+  $req->content('match=www&errors=0');
+
+  my $res = $ua->request($req);
+  print $res->as_string;
+
+Lazy people use the HTTP::Request::Common module to set up a suitable
+POST request message (it handles all the escaping issues) and has a
+suitable default for the content_type:
+
+  use HTTP::Request::Common qw(POST);
+  use LWP::UserAgent;
+  $ua = new LWP::UserAgent;
+
+  my $req = POST 'http://www.perl.com/cgi-bin/BugGlimpse',
+                [ search => 'www', errors => 0 ];
+
+  print $ua->request($req)->as_string;
+
+The lwp-request program (alias POST) that is distributed with the
+library can also be used for posting data.
+
+
+
+=head1 PROXIES
+
+Some sites use proxies to go through fire wall machines, or just as
+cache in order to improve performance.  Proxies can also be used for
+accessing resources through protocols not supported directly (or
+supported badly :-) by the libwww-perl library.
+
+You should initialize your proxy setting before you start sending
+requests:
+
+  use LWP::UserAgent;
+  $ua = new LWP::UserAgent;
+  $ua->env_proxy; # initialize from environment variables
+  # or
+  $ua->proxy(ftp  => 'http://proxy.myorg.com');
+  $ua->proxy(wais => 'http://proxy.myorg.com');
+  $ua->no_proxy(qw(no se fi));
+
+  my $req = new HTTP::Request 'wais://xxx.com/';
+  print $ua->request($req)->as_string;
+
+The LWP::Simple interface will call env_proxy() for you automatically.
+Applications that use the $ua->env_proxy() method will normally not
+use the $ua->proxy() and $ua->no_proxy() methods.
+
+Some proxies also require that you send it a username/password in
+order to let requests through.  You should be able to add the
+required header, with something like this:
+
+ use LWP::UserAgent;
+
+ $ua = new LWP::UserAgent;
+ $ua->proxy(['http', 'ftp'] => 'http://proxy.myorg.com');
+
+ $req = new HTTP::Request 'GET',"http://www.perl.com";
+ $req->proxy_authorization_basic("proxy_user", "proxy_password");
+
+ $res = $ua->request($req);
+ print $res->content if $res->is_success;
+
+Replace C<proxy.myorg.com>, C<proxy_user> and
+C<proxy_password> with something suitable for your site.
+
+
+=head1 ACCESS TO PROTECTED DOCUMENTS
+
+Documents protected by basic authorization can easily be accessed
+like this:
+
+  use LWP::UserAgent;
+  $ua = new LWP::UserAgent;
+  $req = new HTTP::Request GET => 'http://www.sn.no/secret/';
+  $req->authorization_basic('aas', 'mypassword');
+  print $ua->request($req)->as_string;
+
+The other alternative is to provide a subclass of I<LWP::UserAgent> that
+overrides the get_basic_credentials() method. Study the I<lwp-request>
+program for an example of this.
+
+
+=head1 MIRRORING
+
+If you want to mirror documents from a WWW server, then try to run
+code similar to this at regular intervals:
+
+  use LWP::Simple;
+
+  %mirrors = (
+     'http://www.sn.no/'             => 'sn.html',
+     'http://www.perl.com/'          => 'perl.html',
+     'http://www.sn.no/libwww-perl/' => 'lwp.html',
+     'gopher://gopher.sn.no/'        => 'gopher.html',
+  );
+
+  while (($url, $localfile) = each(%mirrors)) {
+     mirror($url, $localfile);
+  }
+
+Or, as a perl one-liner:
+
+  perl -MLWP::Simple -e 'mirror("http://www.perl.com/", "perl.html")';
+
+The document will not be transfered unless it has been updated.
+
+
+
+=head1 LARGE DOCUMENTS
+
+If the document you want to fetch is too large to be kept in memory,
+then you have two alternatives.  You can instruct the library to write
+the document content to a file (second $ua->request() argument is a file
+name):
+
+  use LWP::UserAgent;
+  $ua = new LWP::UserAgent;
+
+  my $req = new HTTP::Request 'GET',
+                'http://www.sn.no/~aas/perl/www/libwww-perl-5.00.tar.gz';
+  $res = $ua->request($req, "libwww-perl.tar.gz");
+  if ($res->is_success) {
+     print "ok\n";
+  }
+
+Or you can process the document as it arrives (second $ua->request()
+argument is a code reference):
+
+  use LWP::UserAgent;
+  $ua = new LWP::UserAgent;
+  $URL = 'ftp://ftp.unit.no/pub/rfc/rfc-index.txt';
+
+  my $expected_length;
+  my $bytes_received = 0;
+  $ua->request(HTTP::Request->new('GET', $URL),
+               sub {
+                   my($chunk, $res) = @_;
+                   $bytes_received += length($chunk);
+	           unless (defined $expected_length) {
+	              $expected_length = $res->content_length || 0;
+                   }
+		   if ($expected_length) {
+		        printf STDERR "%d%% - ",
+	                          100 * $bytes_received / $expected_length;
+                   }
+	           print STDERR "$bytes_received bytes received\n";
+
+                   # XXX Should really do something with the chunk itself
+	           # print $chunk;
+               });
+
+
+
+=head1 HTML FORMATTING
+
+It is easy to convert HTML code to "readable" text.
+
+  use LWP::Simple;
+  use HTML::Parse;
+  print parse_html(get 'http://www.sn.no/libwww-perl/')->format;
+
+
+
+=head1 PARSE URLS
+
+To access individual elements of a URL, try this:
+
+  use URI::URL;
+  $host = url("http://www.sn.no/")->host;
+
+or
+
+  use URI::URL;
+  $u = url("ftp://ftp.sn.no/test/aas;type=i");
+  print "Protocol scheme is ", $u->scheme, "\n";
+  print "Host is ", $u->host, " at port ", $u->port, "\n";
+
+or even
+
+  use URI::URL;
+  my($host,$port) = (url("ftp://ftp.sn.no/test/aas;type=i")->crack)[3,4];
+
+
+=head1 EXPAND RELATIVE URLS
+
+This code reads URLs and print expanded version.
+
+  use URI::URL;
+  $BASE = "http://www.sn.no/some/place?query";
+  while (<>) {
+     print url($_, $BASE)->abs->as_string, "\n";
+  }
+
+We can expand URLs in an HTML document by using the parser to build a
+tree that we then traverse:
+
+  %link_elements =
+  (
+   'a'    => 'href',
+   'img'  => 'src',
+   'form' => 'action',
+   'link' => 'href',
+  );
+
+  use HTML::Parse;
+  use URI::URL;
+
+  $BASE = "http://somewhere/root/";
+  $h = parse_htmlfile("xxx.html");
+  $h->traverse(\&expand_urls, 1);
+
+  print $h->as_HTML;
+
+  sub expand_urls
+  {
+     my($e, $start) = @_;
+     return 1 unless $start;
+     my $attr = $link_elements{$e->tag};
+     return 1 unless defined $attr;
+     my $url = $e->attr($attr);
+     return 1 unless defined $url;
+     $e->attr($attr, url($url, $BASE)->abs->as_string);
+  }
+
+
+
+=head1 BASE URL
+
+If you want to resolve relative links in a page you will have to
+determine which base URL to use.  The HTTP::Response objects now has a
+base() method.
+
+  $BASE = $res->base;
+
+
+
+=head1 COPYRIGHT
+
+Copyright 1996-1997, Gisle Aas
+
+This library is free software; you can redistribute it and/or
+modify it under the same terms as Perl itself.
+
+
Index: /main/tags/2.25/gsdl/packages/w3mir/libwww-perl-5.36/t/README
===================================================================
--- /main/tags/2.25/gsdl/packages/w3mir/libwww-perl-5.36/t/README	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/w3mir/libwww-perl-5.36/t/README	(revision 21064)
@@ -0,0 +1,24 @@
+Self test suite for the libwww-perl library
+-------------------------------------------
+
+Tests are invoked by running the ./TEST script, but usually you run
+the tests with "make test" at the top libwww-perl directory.  Use -v
+option for verbose tests.  You might run an individual test like this:
+
+  ./TEST -v base/date
+
+or all tests in a directory like this
+
+  ./TEST base
+
+You enable network tests by creating the "net/config.pl" file.  A good
+start is to make a copy of the "net/config.pl.dist" file.  For network
+tests you should also make a link from the cgi-bin directory of your
+http server to the "net/cgi-bin" directory.  You might also have to
+check that the interpreter line (#!.../perl) in the scripts is ok for
+your system.  The following setup works for my site:
+
+  ln -s `pwd`/net/cgi-bin ~www/cgi-bin/lwp
+  cp net/config.pl.dist net/config.pl
+  emacs net/config.pl                        # fix if necessary
+  ./TEST net
Index: /main/tags/2.25/gsdl/packages/w3mir/libwww-perl-5.36/t/TEST
===================================================================
--- /main/tags/2.25/gsdl/packages/w3mir/libwww-perl-5.36/t/TEST	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/w3mir/libwww-perl-5.36/t/TEST	(revision 21064)
@@ -0,0 +1,39 @@
+#!/usr/local/bin/perl
+
+# This script is run Test::Harness on the tests found under the
+# "t" directory.
+
+# First we check if we already are within the "t" directory
+unless (-d "base") {
+    # try to move into test directory
+    chdir "t" or die "Can't chdir: $!";
+
+    # fix all relative library locations
+    foreach (@INC) {
+	$_ = "../$_" unless m,^/,;
+    }
+}
+# Pick up the library files from the ../blib directory
+unshift(@INC, "../blib/lib", "../blib/arch");
+#print "@INC\n";
+
+
+use Test::Harness;
+$Test::Harness::verbose = shift
+  if $ARGV[0] =~ /^\d+$/ || $ARGV[0] eq "-v";
+
+if (@ARGV) {
+    for (@ARGV) {
+	if (-d $_) {
+	    push(@tests, <$_/*.t>);
+	} else {
+            $_ .= ".t" unless /\.t$/;
+	    push(@tests, $_);
+	}
+    }
+} else {
+    @tests = (<base/*.t>, <uri/*.t>, <robot/*.t>, <local/*.t>);
+    push(@tests, <net/*.t>) if -f "net/config.pl";
+}
+
+runtests @tests;
Index: /main/tags/2.25/gsdl/packages/w3mir/libwww-perl-5.36/t/base/common-req.t
===================================================================
--- /main/tags/2.25/gsdl/packages/w3mir/libwww-perl-5.36/t/base/common-req.t	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/w3mir/libwww-perl-5.36/t/base/common-req.t	(revision 21064)
@@ -0,0 +1,193 @@
+print "1..19\n";
+
+use HTTP::Request::Common;
+
+$r = GET 'http://www.sn.no/';
+print $r->as_string;
+
+print "not " unless $r->method eq "GET" and $r->url eq "http://www.sn.no/";
+print "ok 1\n";
+
+$r = HEAD "http://www.sn.no/",
+     If_Match => 'abc',
+     From => 'aas@sn.no';
+print $r->as_string;
+
+print "not " unless $r->method eq "HEAD" and $r->url->eq("http://www.sn.no");
+print "ok 2\n";
+
+print "not " unless $r->header('If-Match') eq "abc" and $r->header("from") eq "aas\@sn.no";
+print "ok 3\n";
+
+$r = PUT "http://www.sn.no",
+     Content => 'foo';
+print $r->as_string;
+
+print "not " unless $r->method eq "PUT" and $r->url->netloc eq "www.sn.no";
+print "ok 4\n";
+
+print "not " if defined($r->header("Content"));
+print "ok 5\n";
+
+print "not " unless ${$r->content_ref} eq "foo" and
+                    $r->content eq "foo";
+print "ok 6\n";
+
+#--- Test POST requests ---
+
+$r = POST "http://www.sn.no", [foo => 'bar',
+                               baz => [qw(a b c)],
+                               foo => 'zoo=&',
+                               "space " => " + ",
+                              ],
+                              bar => 'foo';
+print $r->as_string;
+
+print "not " unless $r->method eq "POST" and
+                    $r->content_type eq "application/x-www-form-urlencoded" and
+                    $r->content_length == 58 and
+                    $r->header("bar") eq "foo";
+print "ok 7\n";
+
+print "not " unless $r->content eq "foo=bar&baz=a&baz=b&baz=c&foo=zoo%3D%26&space%20=%20%2B%20";
+print "ok 8\n";
+
+$r = POST "mailto:gisle\@aas.no",
+     Subject => "Heisan",
+     Content_Type => "text/plain",
+     Content => "Howdy\n";
+print $r->as_string;
+
+print "not " unless $r->method eq "POST" and
+                    $r->header("Subject") eq "Heisan" and
+                    $r->content eq "Howdy\n" and
+	            $r->content_type eq "text/plain";
+print "ok 9\n";
+
+#
+# POST for File upload
+#
+$file = "test-$$";
+open(FILE, ">$file") or die "Can't create $file: $!";
+print FILE "foo\nbar\nbaz\n";
+close(FILE);
+
+$r = POST 'http://www.perl.org/survey.cgi',
+       Content_Type => 'form-data',
+       Content      => [ name  => 'Gisle Aas',
+                         email => 'gisle@aas.no',
+                         gender => 'm',
+                         born   => '1964',
+                         file   => [$file],
+                       ];
+print $r->as_string;
+
+unlink($file) or warn "Can't unlink $file: $!";
+
+print "not " unless $r->method eq "POST" and
+	            $r->url->path eq "/survey.cgi" and
+                    $r->content_type eq "multipart/form-data" and
+	            $r->header(Content_type) =~ /boundary="?([^"]+)"?/;
+print "ok 10\n";
+$boundary = $1;
+
+$c = $r->content;
+$c =~ s/\r//g;
+@c = split(/--\Q$boundary/, $c);
+print "$c[5]\n";
+
+print "not " unless @c == 7 and $c[6] =~ /^--\n/;  # 5 parts + header & trailer
+print "ok 11\n";
+
+print "not " unless $c[2] =~ /^Content-Disposition:\s*form-data;\s*name="email"/m and
+                    $c[2] =~ /^gisle\@aas.no$/m;
+print "ok 12\n";
+
+print "not " unless $c[5] =~ /^Content-Disposition:\s*form-data;\s*name="file";\s*filename="$file"/m and
+	            $c[5] =~ /^Content-Type:\s*text\/plain$/m and
+	            $c[5] =~ /^foo\nbar\nbaz/m;
+print "ok 13\n";
+
+$r = POST 'http://www.perl.org/survey.cgi',
+      [ file => [ undef, "xxx", Content_type => "text/html", Content => "<h1>Hello, world!</h1>" ]],
+      Content_type => 'multipart/form-data';
+print $r->as_string;
+
+print "not " unless $r->content =~ /^--\S+\015\012Content-Disposition:\s*form-data;\s*name="file";\s*filename="xxx"/m and
+	            $r->content =~ /^Content-Type: text\/html/m and
+	            $r->content =~ /^<h1>Hello, world/m;
+print "ok 14\n";
+
+
+$r = POST 'http://www.perl.org/survey.cgi',
+      Content_type => 'multipart/form-data',
+      Content => [ file => [ undef, undef, Content => "foo"]];
+print $r->as_string;
+
+print "not " if $r->content =~ /filename=/;
+print "ok 15\n";
+
+
+# The POST routine can now also take a hash reference.
+my %hash = (foo => 42, bar => 24);
+$r = POST 'http://www.perl.org/survey.cgi', \%hash;
+print $r->as_string;
+print "not " unless $r->content =~ /foo=42/ &&
+                    $r->content =~ /bar=24/ &&
+                    $r->content_type eq "application/x-www-form-urlencoded" &&
+                    $r->content_length == 13;
+print "ok 16\n";
+
+ 
+#
+# POST for File upload
+#
+use HTTP::Request::Common qw($DYNAMIC_FILE_UPLOAD);
+
+$file = "test-$$";
+open(FILE, ">$file") or die "Can't create $file: $!";
+for (1..1000) {
+   print FILE "a" .. "z";
+}
+close(FILE);
+
+$DYNAMIC_FILE_UPLOAD++;
+$r = POST 'http://www.perl.org/survey.cgi',
+       Content_Type => 'form-data',
+       Content      => [ name  => 'Gisle Aas',
+                         email => 'gisle@aas.no',
+                         gender => 'm',
+                         born   => '1964',
+                         file   => [$file],
+                       ];
+print $r->as_string;
+
+print "not " unless $r->method eq "POST" and
+	            $r->url->path eq "/survey.cgi" and
+                    $r->content_type eq "multipart/form-data" and
+	            $r->header(Content_type) =~ /boundary="?([^"]+)"?/ and
+		    ref($r->content) eq "CODE";
+print "ok 17\n";
+$boundary = $1;
+
+print "not " unless length($boundary) > 10;
+print "ok 18\n";
+
+$code = $r->content;
+my $chunk;
+my @chunks;
+while (defined($chunk = &$code) && length $chunk) {
+   push(@chunks, $chunk);
+}
+
+unlink($file) or warn "Can't unlink $file: $!";
+
+$_ = join("", @chunks);
+
+print int(@chunks), " chunks, total size is ", length($_), " bytes\n";
+
+# should be close to expected size and number of chunks
+print "not " unless abs(@chunks - 15 < 3) and
+                    abs(length($_) - 26589) < 20;
+print "ok 19\n";
+
Index: /main/tags/2.25/gsdl/packages/w3mir/libwww-perl-5.36/t/base/cookies.t
===================================================================
--- /main/tags/2.25/gsdl/packages/w3mir/libwww-perl-5.36/t/base/cookies.t	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/w3mir/libwww-perl-5.36/t/base/cookies.t	(revision 21064)
@@ -0,0 +1,515 @@
+print "1..32\n";
+
+#use LWP::Debug '+';
+
+use HTTP::Cookies;
+use HTTP::Request;
+use HTTP::Response;
+
+#-------------------------------------------------------------------
+# First we check that it works for the original example at
+# http://www.netscape.com/newsref/std/cookie_spec.html
+
+# Client requests a document, and receives in the response:
+# 
+#       Set-Cookie: CUSTOMER=WILE_E_COYOTE; path=/; expires=Wednesday, 09-Nov-99 23:12:40 GMT
+# 
+# When client requests a URL in path "/" on this server, it sends:
+# 
+#       Cookie: CUSTOMER=WILE_E_COYOTE
+# 
+# Client requests a document, and receives in the response:
+# 
+#       Set-Cookie: PART_NUMBER=ROCKET_LAUNCHER_0001; path=/
+# 
+# When client requests a URL in path "/" on this server, it sends:
+# 
+#       Cookie: CUSTOMER=WILE_E_COYOTE; PART_NUMBER=ROCKET_LAUNCHER_0001
+# 
+# Client receives:
+# 
+#       Set-Cookie: SHIPPING=FEDEX; path=/fo
+# 
+# When client requests a URL in path "/" on this server, it sends:
+# 
+#       Cookie: CUSTOMER=WILE_E_COYOTE; PART_NUMBER=ROCKET_LAUNCHER_0001
+# 
+# When client requests a URL in path "/foo" on this server, it sends:
+# 
+#       Cookie: CUSTOMER=WILE_E_COYOTE; PART_NUMBER=ROCKET_LAUNCHER_0001; SHIPPING=FEDEX
+# 
+# The last Cookie is buggy, because both specifications says that the
+# most specific cookie must be sent first.  SHIPPING=FEDEX is the
+# most specific and should thus be first.
+
+$c = HTTP::Cookies->new;
+
+$req = HTTP::Request->new(GET => "http://www.acme.com/");
+
+$res = HTTP::Response->new(200, "OK");
+$res->request($req);
+$res->header("Set-Cookie" => "CUSTOMER=WILE_E_COYOTE; path=/; expires=Wednesday, 09-Nov-99 23:12:40 GMT");
+$c->extract_cookies($res);
+
+$req = HTTP::Request->new(GET => "http://www.acme.com/");
+$c->add_cookie_header($req);
+
+print "not " unless $req->header("Cookie") eq "CUSTOMER=WILE_E_COYOTE" &&
+                    $req->header("Cookie2") eq "\$Version=1";
+print "ok 1\n";
+
+$res->request($req);
+$res->header("Set-Cookie" => "PART_NUMBER=ROCKET_LAUNCHER_0001; path=/");
+$c->extract_cookies($res);
+
+$req = HTTP::Request->new(GET => "http://www.acme.com/foo/bar");
+$c->add_cookie_header($req);
+
+$h = $req->header("Cookie");
+print "not " unless $h =~ /PART_NUMBER=ROCKET_LAUNCHER_0001/ &&
+                    $h =~ /CUSTOMER=WILE_E_COYOTE/;
+print "ok 2\n";
+
+$res->request($req);
+$res->header("Set-Cookie", "SHIPPING=FEDEX; path=/foo");
+$c->extract_cookies($res);
+
+$req = HTTP::Request->new(GET => "http://www.acme.com/");
+$c->add_cookie_header($req);
+
+$h = $req->header("Cookie");
+print "not " unless $h =~ /PART_NUMBER=ROCKET_LAUNCHER_0001/ &&
+	            $h =~ /CUSTOMER=WILE_E_COYOTE/ &&
+	            $h !~ /SHIPPING=FEDEX/;
+print "ok 3\n";
+
+
+$req = HTTP::Request->new(GET => "http://www.acme.com/foo/");
+$c->add_cookie_header($req);
+
+$h = $req->header("Cookie");
+print "not " unless $h =~ /PART_NUMBER=ROCKET_LAUNCHER_0001/ &&
+	            $h =~ /CUSTOMER=WILE_E_COYOTE/ &&
+		    $h =~ /^SHIPPING=FEDEX;/;
+print "ok 4\n";
+
+print $c->as_string;
+
+
+# Second Example transaction sequence:
+# 
+# Assume all mappings from above have been cleared.
+# 
+# Client receives:
+# 
+#       Set-Cookie: PART_NUMBER=ROCKET_LAUNCHER_0001; path=/
+# 
+# When client requests a URL in path "/" on this server, it sends:
+# 
+#       Cookie: PART_NUMBER=ROCKET_LAUNCHER_0001
+# 
+# Client receives:
+# 
+#       Set-Cookie: PART_NUMBER=RIDING_ROCKET_0023; path=/ammo
+# 
+# When client requests a URL in path "/ammo" on this server, it sends:
+# 
+#       Cookie: PART_NUMBER=RIDING_ROCKET_0023; PART_NUMBER=ROCKET_LAUNCHER_0001
+# 
+#       NOTE: There are two name/value pairs named "PART_NUMBER" due to
+#       the inheritance of the "/" mapping in addition to the "/ammo" mapping. 
+
+$c = HTTP::Cookies->new;  # clear it
+
+$req = HTTP::Request->new(GET => "http://www.acme.com/");
+$res = HTTP::Response->new(200, "OK");
+$res->request($req);
+$res->header("Set-Cookie", "PART_NUMBER=ROCKET_LAUNCHER_0001; path=/");
+
+$c->extract_cookies($res);
+
+$req = HTTP::Request->new(GET => "http://www.acme.com/");
+$c->add_cookie_header($req);
+
+print "not " unless $req->header("Cookie") eq "PART_NUMBER=ROCKET_LAUNCHER_0001";
+print "ok 5\n";
+
+$res->request($req);
+$res->header("Set-Cookie", "PART_NUMBER=RIDING_ROCKET_0023; path=/ammo");
+$c->extract_cookies($res);
+
+$req = HTTP::Request->new(GET => "http://www.acme.com/ammo");
+$c->add_cookie_header($req);
+
+print "not " unless $req->header("Cookie") =~
+       /^PART_NUMBER=RIDING_ROCKET_0023;\s*PART_NUMBER=ROCKET_LAUNCHER_0001/;
+print "ok 6\n";
+
+print $c->as_string;
+undef($c);
+
+
+#-------------------------------------------------------------------
+# When there are no "Set-Cookie" header, then even responses
+# without any request URLs connected should be allowed.
+
+$c = HTTP::Cookies->new;
+$c->extract_cookies(HTTP::Response->new("200", "OK"));
+print "not " if count_cookies($c) != 0;
+print "ok 7\n";
+
+
+#-------------------------------------------------------------------
+# Then we test with the examples from draft-ietf-http-state-man-mec-03.txt
+#
+# 5.  EXAMPLES
+
+$c = HTTP::Cookies->new;
+
+# 
+# 5.1  Example 1
+# 
+# Most detail of request and response headers has been omitted.  Assume
+# the user agent has no stored cookies.
+# 
+#   1.  User Agent -> Server
+# 
+#       POST /acme/login HTTP/1.1
+#       [form data]
+# 
+#       User identifies self via a form.
+# 
+#   2.  Server -> User Agent
+# 
+#       HTTP/1.1 200 OK
+#       Set-Cookie2: Customer="WILE_E_COYOTE"; Version="1"; Path="/acme"
+# 
+#       Cookie reflects user's identity.
+
+$cookie = interact($c, 'http://www.acme.com/acme/login',
+                       'Customer="WILE_E_COYOTE"; Version="1"; Path="/acme"');
+print "not " if $cookie;
+print "ok 8\n";
+
+# 
+#   3.  User Agent -> Server
+# 
+#       POST /acme/pickitem HTTP/1.1
+#       Cookie: $Version="1"; Customer="WILE_E_COYOTE"; $Path="/acme"
+#       [form data]
+# 
+#       User selects an item for ``shopping basket.''
+# 
+#   4.  Server -> User Agent
+# 
+#       HTTP/1.1 200 OK
+#       Set-Cookie2: Part_Number="Rocket_Launcher_0001"; Version="1";
+#               Path="/acme"
+# 
+#       Shopping basket contains an item.
+
+$cookie = interact($c, 'http://www.acme.com/acme/pickitem',
+		       'Part_Number="Rocket_Launcher_0001"; Version="1"; Path="/acme"');
+print "not " unless $cookie =~ m(^\$Version="?1"?; Customer="?WILE_E_COYOTE"?; \$Path="/acme"$);
+print "ok 9\n";
+
+# 
+#   5.  User Agent -> Server
+# 
+#       POST /acme/shipping HTTP/1.1
+#       Cookie: $Version="1";
+#               Customer="WILE_E_COYOTE"; $Path="/acme";
+#               Part_Number="Rocket_Launcher_0001"; $Path="/acme"
+#       [form data]
+# 
+#       User selects shipping method from form.
+# 
+#   6.  Server -> User Agent
+# 
+#       HTTP/1.1 200 OK
+#       Set-Cookie2: Shipping="FedEx"; Version="1"; Path="/acme"
+# 
+#       New cookie reflects shipping method.
+
+$cookie = interact($c, "http://www.acme.com/acme/shipping",
+		   'Shipping="FedEx"; Version="1"; Path="/acme"');
+
+print "not " unless $cookie =~ /^\$Version="?1"?;/ &&
+     $cookie =~ /Part_Number="?Rocket_Launcher_0001"?;\s*\$Path="\/acme"/ &&
+     $cookie =~ /Customer="?WILE_E_COYOTE"?;\s*\$Path="\/acme"/;
+print "ok 10\n";
+
+# 
+#   7.  User Agent -> Server
+# 
+#       POST /acme/process HTTP/1.1
+#       Cookie: $Version="1";
+#               Customer="WILE_E_COYOTE"; $Path="/acme";
+#               Part_Number="Rocket_Launcher_0001"; $Path="/acme";
+#               Shipping="FedEx"; $Path="/acme"
+#       [form data]
+# 
+#       User chooses to process order.
+# 
+#   8.  Server -> User Agent
+# 
+#       HTTP/1.1 200 OK
+# 
+#       Transaction is complete.
+
+$cookie = interact($c, "http://www.acme.com/acme/process");
+print "FINAL COOKIE: $cookie\n";
+print "not " unless $cookie =~ /Shipping="?FedEx"?;\s*\$Path="\/acme"/ &&
+                    $cookie =~ /WILE_E_COYOTE/;
+print "ok 11\n";
+
+# 
+# The user agent makes a series of requests on the origin server, after
+# each of which it receives a new cookie.  All the cookies have the same
+# Path attribute and (default) domain.  Because the request URLs all have
+# /acme as a prefix, and that matches the Path attribute, each request
+# contains all the cookies received so far.
+
+print $c->as_string;
+
+
+# 5.2  Example 2
+# 
+# This example illustrates the effect of the Path attribute.  All detail
+# of request and response headers has been omitted.  Assume the user agent
+# has no stored cookies.
+
+$c = HTTP::Cookies->new;
+
+# Imagine the user agent has received, in response to earlier requests,
+# the response headers
+# 
+# Set-Cookie2: Part_Number="Rocket_Launcher_0001"; Version="1";
+#         Path="/acme"
+# 
+# and
+# 
+# Set-Cookie2: Part_Number="Riding_Rocket_0023"; Version="1";
+#         Path="/acme/ammo"
+
+interact($c, "http://www.acme.com/acme/ammo/specific",
+             'Part_Number="Rocket_Launcher_0001"; Version="1"; Path="/acme"',
+             'Part_Number="Riding_Rocket_0023"; Version="1"; Path="/acme/ammo"');
+
+# A subsequent request by the user agent to the (same) server for URLs of
+# the form /acme/ammo/...  would include the following request header:
+# 
+# Cookie: $Version="1";
+#         Part_Number="Riding_Rocket_0023"; $Path="/acme/ammo";
+#         Part_Number="Rocket_Launcher_0001"; $Path="/acme"
+# 
+# Note that the NAME=VALUE pair for the cookie with the more specific Path
+# attribute, /acme/ammo, comes before the one with the less specific Path
+# attribute, /acme.  Further note that the same cookie name appears more
+# than once.
+
+$cookie = interact($c, "http://www.acme.com/acme/ammo/...");
+print "not " unless $cookie =~ /Riding_Rocket_0023.*Rocket_Launcher_0001/;
+print "ok 12\n";
+
+# A subsequent request by the user agent to the (same) server for a URL of
+# the form /acme/parts/ would include the following request header:
+# 
+# Cookie: $Version="1"; Part_Number="Rocket_Launcher_0001"; $Path="/acme"
+# 
+# Here, the second cookie's Path attribute /acme/ammo is not a prefix of
+# the request URL, /acme/parts/, so the cookie does not get forwarded to
+# the server.
+
+$cookie = interact($c, "http://www.acme.com/acme/parts/");
+print "not " unless $cookie =~ /Rocket_Launcher_0001/ &&
+		    $cookie !~ /Riding_Rocket_0023/;
+print "ok 13\n";
+
+print $c->as_string;
+
+#-----------------------------------------------------------------------
+
+# Test rejection of Set-Cookie2 responses based on domain, path or port
+
+$c = HTTP::Cookies->new;
+
+# illegal domain (no embedded dots)
+$cookie = interact($c, "http://www.acme.com", 'foo=bar; domain=".com"');
+print "not " if count_cookies($c) > 0;
+print "ok 14\n";
+
+# legal domain
+$cookie = interact($c, "http://www.acme.com", 'foo=bar; domain="acme.com"');
+print "not " if count_cookies($c) != 1;
+print "ok 15\n";
+
+# illegal domain (host prefix "www.a" contains a dot)
+$cookie = interact($c, "http://www.a.acme.com", 'foo=bar; domain="acme.com"');
+print "not " if count_cookies($c) != 1;
+print "ok 16\n";
+
+# legal domain
+$cookie = interact($c, "http://www.a.acme.com", 'foo=bar; domain=".a.acme.com"');
+print "not " if count_cookies($c) != 2;
+print "ok 17\n";
+
+# can't use a IP-address as domain
+$cookie = interact($c, "http://125.125.125.125", 'foo=bar; domain="125.125.125"');
+print "not " if count_cookies($c) != 2;
+print "ok 18\n";
+
+# illegal path (must be prefix of request path)
+$cookie = interact($c, "http://www.sol.no", 'foo=bar; domain=".sol.no"; path="/foo"');
+print "not " if count_cookies($c) != 2;
+print "ok 19\n";
+
+# legal path
+$cookie = interact($c, "http://www.sol.no/foo/bar", 'foo=bar; domain=".sol.no"; path="/foo"');
+print "not " if count_cookies($c) != 3;
+print "ok 20\n";
+
+# illegal port (request-port not in list)
+$cookie = interact($c, "http://www.sol.no", 'foo=bar; domain=".sol.no"; port="90,100"');
+print "not " if count_cookies($c) != 3;
+print "ok 21\n";
+
+# legal port
+$cookie = interact($c, "http://www.sol.no", 'foo=bar; domain=".sol.no"; port="90,100, 80,8080"; max-age=100; Comment = "Just kidding! (\"|\\\\) "');
+print "not " if count_cookies($c) != 4;
+print "ok 22\n";
+
+# port attribute without any value (current port)
+$cookie = interact($c, "http://www.sol.no", 'foo9=bar; domain=".sol.no"; port; max-age=100;');
+print "not " if count_cookies($c) != 5;
+print "ok 23\n";
+
+# encoded path
+$cookie = interact($c, "http://www.sol.no/foo/", 'foo8=bar; path="/%66oo"');
+print "not " if count_cookies($c) != 6;
+print "ok 24\n";
+
+my $file = "lwp-cookies-$$.txt";
+$c->save($file);
+$old = $c->as_string;
+undef($c);
+
+$c = HTTP::Cookies->new;
+$c->load($file);
+unlink($file) || warn "Can't unlink $file: $!";
+
+print "not " unless $old eq $c->as_string;
+print "ok 25\n";
+
+undef($c);
+
+#
+# Try some URL encodings of the PATHs
+#
+$c = HTTP::Cookies->new;
+interact($c, "http://www.acme.com/foo%2f%25/%40%40%0Anew%E5/%E5", 'foo  =   bar; version    =   1');
+print $c->as_string;
+
+$cookie = interact($c, "http://www.acme.com/foo%2f%25/@@%0anewå/æøå", "bar=baz; path=\"/foo/\"; version=1");
+print "not " unless $cookie =~ /foo=bar/ && $cookie =~ /^\$version=\"?1\"?/i;
+print "ok 26\n";
+
+$cookie = interact($c, "http://www.acme.com/foo/%25/@@%0anewå/æøå");
+print "not " if $cookie;
+print "ok 27\n";
+
+undef($c);
+
+#
+# Try to use the Netscape cookie file format for saving
+#
+$file = "cookies-$$.txt";
+$c = HTTP::Cookies::Netscape->new(file => $file);
+interact($c, "http://www.acme.com/", "foo1=bar; max-age=100");
+interact($c, "http://www.acme.com/", "foo2=bar; port=\"80\"; max-age=100; Discard; Version=1");
+interact($c, "http://www.acme.com/", "foo3=bar; secure; Version=1");
+$c->save;
+undef($c);
+
+$c = HTTP::Cookies::Netscape->new(file => $file);
+print "not " unless count_cookies($c) == 1;     # 2 of them discarded on save
+print "ok 28\n";
+
+print "not " unless $c->as_string =~ /foo1=bar/;
+print "ok 29\n";
+undef($c);
+unlink($file);
+
+
+#
+# Some additional Netscape cookies test
+#
+$c = HTTP::Cookies->new;
+$req = HTTP::Request->new(POST => "http://foo.bar.acme.com/foo");
+
+# Netscape allows a host part that contains dots
+$res = HTTP::Response->new(200, "OK");
+$res->header(set_cookie => 'Customer=WILE_E_COYOTE; domain=.acme.com');
+$res->request($req);
+$c->extract_cookies($res);
+
+# and that the domain is the same as the host without adding a leading
+# dot to the domain.  Should not quote even if strange chars are used
+# in the cookie value.
+$res = HTTP::Response->new(200, "OK");
+$res->header(set_cookie => 'PART_NUMBER=3,4; domain=foo.bar.acme.com');
+$res->request($req);
+$c->extract_cookies($res);
+
+print $c->as_string;
+
+$req = HTTP::Request->new(POST => "http://foo.bar.acme.com/foo");
+$c->add_cookie_header($req);
+#print $req->as_string;
+print "not " unless $req->header("Cookie") =~ /PART_NUMBER=3,4/ &&
+	            $req->header("Cookie") =~ /Customer=WILE_E_COYOTE/;
+print "ok 30\n";
+
+
+
+# Test handling of local intranet hostnames without a dot
+$c->clear;
+print "---\n";
+#require LWP::Debug;
+#LWP::Debug::level('+');
+
+interact($c, "http://example/", "foo1=bar; PORT; Discard;");
+$_=interact($c, "http://example/", 'foo2=bar; domain=".local"');
+print "not " unless /foo1=bar/;
+print "ok 31\n";
+
+$_=interact($c, "http://example/", 'foo3=bar');
+$_=interact($c, "http://example/");
+print "Cookie: $_\n";
+print "not " unless /foo2=bar/ && count_cookies($c) == 3;
+print "ok 32\n";
+print $c->as_string;
+
+#-------------------------------------------------------------------
+
+sub interact
+{
+    my $c = shift;
+    my $url = shift;
+    my $req = HTTP::Request->new(POST => $url);
+    $c->add_cookie_header($req);
+    my $cookie = $req->header("Cookie");
+    my $res = HTTP::Response->new(200, "OK");
+    $res->request($req);
+    for (@_) { $res->push_header("Set-Cookie2" => $_) }
+    $c->extract_cookies($res);
+    return $cookie;
+}
+
+sub count_cookies
+{
+    my $c = shift;
+    my $no = 0;
+    $c->scan(sub { $no++ });
+    $no;
+}
Index: /main/tags/2.25/gsdl/packages/w3mir/libwww-perl-5.36/t/base/date.t
===================================================================
--- /main/tags/2.25/gsdl/packages/w3mir/libwww-perl-5.36/t/base/date.t	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/w3mir/libwww-perl-5.36/t/base/date.t	(revision 21064)
@@ -0,0 +1,165 @@
+use HTTP::Date;
+
+print "1..59\n";
+
+$no = 1;
+$| = 1;
+sub ok {
+   print "not " if $_[0];
+   print "ok $no\n";
+   $no++;
+}
+
+# test str2time for supported dates
+my(@tests) =
+(
+ 'Thu Feb  3 00:00:00 GMT 1994',        # ctime format
+ 'Thu Feb  3 00:00:00 1994',            # same as ctime, except no TZ
+
+ 'Thu, 03 Feb 1994 00:00:00 GMT',       # proposed new HTTP format
+ 'Thursday, 03-Feb-94 00:00:00 GMT',    # old rfc850 HTTP format
+ 'Thursday, 03-Feb-1994 00:00:00 GMT',  # broken rfc850 HTTP format
+
+ '03/Feb/1994:00:00:00 0000',   # common logfile format
+ '03/Feb/1994:01:00:00 +0100',  # common logfile format
+ '02/Feb/1994:23:00:00 -0100',  # common logfile format
+
+ '03 Feb 1994 00:00:00 GMT',    # HTTP format (no weekday)
+ '03-Feb-94 00:00:00 GMT',      # old rfc850 (no weekday)
+ '03-Feb-1994 00:00:00 GMT',    # broken rfc850 (no weekday)
+ '03-Feb-1994 00:00 GMT',       # broken rfc850 (no weekday, no seconds)
+ '03-Feb-1994 00:00',           # VMS dir listing format
+
+ '03-Feb-94',    # old rfc850 HTTP format    (no weekday, no time)
+ '03-Feb-1994',  # broken rfc850 HTTP format (no weekday, no time)
+ '03 Feb 1994',  # proposed new HTTP format  (no weekday, no time)
+ '03/Feb/1994',  # common logfile format     (no time, no offset)
+
+ #'Feb  3 00:00',     # Unix 'ls -l' format (can't really test it here)
+ 'Feb  3 1994',       # Unix 'ls -l' format
+
+ "02-03-94  12:00AM", # Windows 'dir' format
+
+ # ISO 8601 formats
+ '1994-02-03 00:00:00 +0000',
+ '1994-02-03',
+ '19940203',
+ '1994-02-03T00:00:00+0000',
+ '1994-02-02T23:00:00-0100',
+ '1994-02-02T23:00:00-01:00',
+ '1994-02-03T00:00:00 Z',
+ '19940203T000000Z',
+ '199402030000',
+
+ # A few tests with extra space at various places
+ '  03/Feb/1994      ',
+ '  03   Feb   1994  0:00  ',
+);
+
+my $time = 760233600;  # assume broken POSIX counting of seconds
+for (@tests) {
+    if (/GMT/i) {
+	$t = str2time($_);
+    } else {
+	$t = str2time($_, "GMT");
+    }
+    $t = "UNDEF" unless defined $t;
+    print "'$_'  =>  $t\n";
+    print $@ if $@;
+    print "not " if $t eq 'UNDEF' || $t != $time;
+    ok;
+}
+
+# test time2str
+die "time2str failed"
+    unless time2str($time) eq 'Thu, 03 Feb 1994 00:00:00 GMT';
+
+# test the 'ls -l' format with missing year$
+# round to nearest minute 3 days ago.
+$time = int((time - 3 * 24*60*60) /60)*60;
+($min, $hr, $mday, $mon) = (localtime $time)[1,2,3,4];
+$mon = (qw(Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec))[$mon];
+$str = sprintf("$mon %02d %02d:%02d", $mday, $hr, $min);
+$t = str2time($str);
+$t = "UNDEF" unless defined $t;
+print "'$str'  =>  $t ($time)\n";
+print "not " if $t != $time;
+ok;
+
+# try some out of bounds date and some garbage.
+for ('03-Feb-1969', '03-Feb-2039',
+     undef, '', 'Garbage',
+     'Mandag 16. September 1996',
+     'Thu Feb  3 00:00:00 CET 1994',
+     'Thu, 03 Feb 1994 00:00:00 CET',
+     'Wednesday, 31-Dec-69 23:59:59 GMT',
+
+     '1980-00-01',
+     '1980-13-01',
+     '1980-01-00',
+     '1980-01-32',
+     '1980-01-01 25:00:00',
+     '1980-01-01 00:61:00',
+     '1980-01-01 00:00:61',
+    )
+{
+    my $bad = 0;
+    eval {
+	if (defined str2time $_) {
+	    print "str2time($_) is not undefined\n";
+	    $bad++;
+	}
+    };
+    print defined($_) ? "'$_'\n" : "undef\n";
+    print $@ if $@;
+    print "not " if $bad;
+    ok;
+}
+
+print "Testing AM/PM gruff...\n";
+
+$t = time2iso(str2time("11-12-96  0:00AM"));print "$t\n";
+ok($t ne "1996-11-12 00:00:00");
+
+$t = time2iso(str2time("11-12-96 12:00AM"));print "$t\n";
+ok($t ne "1996-11-12 00:00:00");
+
+$t = time2iso(str2time("11-12-96  0:00PM"));print "$t\n";
+ok($t ne "1996-11-12 12:00:00");
+
+$t = time2iso(str2time("11-12-96 12:00PM"));print "$t\n";
+ok($t ne "1996-11-12 12:00:00");
+
+
+$t = time2iso(str2time("11-12-96  1:05AM"));print "$t\n";
+ok($t ne "1996-11-12 01:05:00");
+
+$t = time2iso(str2time("11-12-96 12:05AM"));print "$t\n";
+ok($t ne "1996-11-12 00:05:00");
+
+$t = time2iso(str2time("11-12-96  1:05PM"));print "$t\n";
+ok($t ne "1996-11-12 13:05:00");
+
+$t = time2iso(str2time("11-12-96 12:05PM"));print "$t\n";
+ok($t ne "1996-11-12 12:05:00");
+
+
+
+# Test the str2iso routines
+use HTTP::Date qw(time2iso time2isoz);
+
+print "Testing time2iso functions\n";
+
+$a = time2iso;
+$b = time2iso(500000);
+print "LOCAL $a  $b\n";
+$az = time2isoz;
+$bz = time2isoz(500000);
+print "GMT   $az $bz\n";
+
+for ($a,  $b)  { ok if /^\d{4}-\d\d-\d\d \d\d:\d\d:\d\d$/;  }
+for ($az, $bz) { ok if /^\d{4}-\d\d-\d\d \d\d:\d\d:\d\dZ$/; }
+
+
+
+print "HTTP::Date $HTTP::Date::VERSION tested ok\n";
Index: /main/tags/2.25/gsdl/packages/w3mir/libwww-perl-5.36/t/base/headers-auth.t
===================================================================
--- /main/tags/2.25/gsdl/packages/w3mir/libwww-perl-5.36/t/base/headers-auth.t	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/w3mir/libwww-perl-5.36/t/base/headers-auth.t	(revision 21064)
@@ -0,0 +1,40 @@
+print "1..4\n";
+
+use HTTP::Response;
+use HTTP::Headers::Auth;
+
+$res = HTTP::Response->new(401);
+$res->push_header(WWW_Authenticate => qq(Foo realm="WallyWorld", foo=bar, Bar realm="WallyWorld2"));
+$res->push_header(WWW_Authenticate => qq(Basic Realm="WallyWorld", foo=bar, bar=baz));
+
+print $res->as_string;
+
+%auth = $res->www_authenticate;
+
+print "not " unless keys(%auth) == 3;
+print "ok 1\n";
+
+print "not " unless $auth{basic}{realm} eq "WallyWorld" &&
+                    $auth{bar}{realm} eq "WallyWorld2";
+print "ok 2\n";
+
+$a = $res->www_authenticate;
+print "not " unless $a eq 'Foo realm="WallyWorld", foo=bar, Bar realm="WallyWorld2", Basic Realm="WallyWorld", foo=bar, bar=baz';
+print "ok 3\n";
+
+$res->www_authenticate("Basic realm=foo1");
+print $res->as_string;
+
+$res->www_authenticate(Basic => {realm => foo2});
+print $res->as_string;
+
+$res->www_authenticate(Basic => [realm => foo3, foo=>33],
+Digest => {nonce=>"bar", foo=>'foo'});
+print $res->as_string;
+
+$_ = $res->as_string;
+
+print "not " unless /WWW-Authenticate: Basic realm="foo3", foo=33/ &&
+                    /WWW-Authenticate: Digest nonce=bar, foo=foo/;
+print "ok 4\n";
+
Index: /main/tags/2.25/gsdl/packages/w3mir/libwww-perl-5.36/t/base/headers-etag.t
===================================================================
--- /main/tags/2.25/gsdl/packages/w3mir/libwww-perl-5.36/t/base/headers-etag.t	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/w3mir/libwww-perl-5.36/t/base/headers-etag.t	(revision 21064)
@@ -0,0 +1,28 @@
+print "1..4\n";
+
+require HTTP::Headers::ETag;
+
+$h = HTTP::Headers->new;
+$h->etag("tag1");
+print "not " unless $h->etag eq qq("tag1");
+print "ok 1\n";
+
+$h->etag("w/tag2");
+print "not " unless $h->etag eq qq(W/"tag2");
+print "ok 2\n";
+
+$h->if_match(qq(W/"foo", bar, baz), "bar");
+$h->if_none_match(333);
+
+$h->if_range("tag3");
+print "not " unless $h->if_range eq qq("tag3");
+print "ok 3\n";
+
+$t = time;
+$h->if_range($t);
+print "not " unless $h->if_range == $t;
+print "ok 4\n";
+
+
+print $h->as_string;
+
Index: /main/tags/2.25/gsdl/packages/w3mir/libwww-perl-5.36/t/base/headers-util.t
===================================================================
--- /main/tags/2.25/gsdl/packages/w3mir/libwww-perl-5.36/t/base/headers-util.t	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/w3mir/libwww-perl-5.36/t/base/headers-util.t	(revision 21064)
@@ -0,0 +1,61 @@
+use strict;
+use HTTP::Headers::Util qw(split_header_words join_header_words);
+
+my $extra_tests = 2;
+
+my @s_tests = (
+
+   ["foo"                     => "foo"],
+   ["foo=bar"                 => "foo=bar"],
+   ["   foo   "               => "foo"],
+   ["foo="                    => 'foo=""'],
+   ["foo=bar bar=baz"         => "foo=bar; bar=baz"],
+   ["foo=bar;bar=baz"         => "foo=bar; bar=baz"],
+   ['foo bar baz'             => "foo; bar; baz"],
+   ['foo="\"" bar="\\\\"'     => 'foo="\""; bar="\\\\"'],
+   ['foo,,,bar'               => 'foo, bar'],
+   ['foo=bar,bar=baz'         => 'foo=bar, bar=baz'],
+
+   ['text/html; charset=iso-8859-1' =>
+    'text/html; charset="iso-8859-1"'],
+
+   ['foo="bar"; port="80,81"; discard, bar=baz' =>
+    'foo=bar; port="80,81"; discard, bar=baz'],
+
+   ['Basic realm="\"foo\\\\bar\""' =>
+    'Basic; realm="\"foo\\\\bar\""'],
+);
+
+print "1..", @s_tests + $extra_tests, "\n";
+
+my $testno = 1;
+
+print "split_header_words() tests\n";
+for (@s_tests) {
+   my($arg, $expect) = @$_;
+   my @arg = ref($arg) ? @$arg : $arg;
+
+   my $res = join_header_words(split_header_words(@arg));
+   if ($res ne $expect) {
+       print "\nUnexpected result: '$res'\n";
+       print "         Expected: '$expect'\n";
+       print "  when parsing '", join(", ", @arg), "'\n";
+       eval {
+	   require Data::Dumper;
+           my @p = split_header_words(@arg);
+           print Data::Dumper::Dumper(\@p);
+       };
+       print "not ";
+   }
+   print "ok ", $testno++, "\n";
+}
+
+
+print "Extra tests\n";
+# some extra tests
+print "not " unless join_header_words("foo" => undef, "bar" => "baz")
+                    eq "foo; bar=baz";
+print "ok ", $testno++, "\n";
+
+print "not " unless join_header_words() eq "";
+print "ok ", $testno++, "\n";
Index: /main/tags/2.25/gsdl/packages/w3mir/libwww-perl-5.36/t/base/headers.t
===================================================================
--- /main/tags/2.25/gsdl/packages/w3mir/libwww-perl-5.36/t/base/headers.t	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/w3mir/libwww-perl-5.36/t/base/headers.t	(revision 21064)
@@ -0,0 +1,128 @@
+require HTTP::Headers;
+
+print "1..11\n";
+
+$h = new HTTP::Headers
+	mime_version  => "1.0",
+	content_type  => "text/html";
+
+$h->header(URI => "http://www.oslonett.no/");
+
+if ($h->header("MIME-Version") eq "1.0") {
+    print "ok 1\n";
+} else {
+    print "not ok 1\n";
+}
+
+if ($h->header('Uri') =~ /^http:/) {
+    print "ok 2\n";
+} else {
+    print "not ok 2\n";
+}
+
+
+$h->header("MY-header" => "foo",
+	   "Date" => "somedate",
+	   "Accept" => ["text/plain", "image/*"],
+	  );
+$h->push_header("accept" => "audio/basic");
+
+if ($h->header("date") eq "somedate") {
+     print "ok 3\n";
+}
+
+@accept = $h->header("accept");
+if (@accept == 3) {
+    print "ok 4\n";
+}
+
+$h->remove_header("uri", "date");
+
+
+$str = $h->as_string;
+print "\nHeader looks like this now:\n$str\n";
+
+$lines = ($str =~ tr/\n/\n/);
+
+if ($lines == 6) {
+    print "ok 5\n";
+} else {
+    print "Header has $lines lines\n";
+    print "not ok 5\n";
+}
+
+$h2 = $h->clone;
+
+$h->header("accept", "*/*");
+$h->remove_header("my-header");
+
+@accept = $h2->header("accept");
+if (@accept == 3) {
+    print "ok 6\n";
+}
+
+@accept = $h->header("accept");
+if (@accept == 1) {
+    print "ok 7\n";
+}
+
+# Check order of headers, but first remove this one
+$h2->remove_header('mime_version');
+
+# and add this general header
+$h2->header(Connection => 'close');
+
+@x = ();
+$h2->scan(sub {push(@x, shift);});
+
+$str = join(";", @x);
+$expected = "Connection;Accept;Accept;Accept;Content-Type;MY-Header";
+
+if ($str eq $expected) {
+    print "ok 8\n";
+} else {
+    print "Headers are '$str',\nexpected    '$expected'\n";
+    print "not ok 8\n";
+}
+
+# Check headers with embedded newlines:
+
+$h = new HTTP::Headers
+	a => "foo\n\n",
+	b => "foo\nbar",
+	c => "foo\n\nbar\n\n",
+	d => "foo\n\tbar";
+$str = $h->as_string("<<\n");
+print "-----\n$str------\n";
+
+print "not " unless $str =~ /^A:\s*foo<<\n
+                              B:\s*foo<<\n
+	                        \s+bar<<\n
+                              C:\s*foo<<\n
+                                \s+bar<<\n
+	                      D:\s*foo<<\n
+                                \t bar<<\n
+                             $/x;
+print "ok 9\n";
+
+
+# Check with FALSE $HTML::Headers::TRANSLATE_UNDERSCORE
+
+local($HTTP::Headers::TRANSLATE_UNDERSCORE);
+$HTTP::Headers::TRANSLATE_UNDERSCORE = undef;  # avoid -w warning
+
+$h = HTTP::Headers->new;
+
+$h->header(abc_abc   => "foo");
+$h->header("abc-abc" => "bar");
+
+#print $h->as_string;
+
+print "not " unless $h->header("ABC_ABC") eq "foo" &&
+                    $h->header("ABC-ABC") eq "bar";
+print "ok 10\n";
+
+$h->remove_header("Abc_Abc");
+print "not " unless !defined($h->header("abc_abc")) &&
+                    $h->header("ABC-ABC") eq "bar";
+print "ok 11\n";
Index: /main/tags/2.25/gsdl/packages/w3mir/libwww-perl-5.36/t/base/listing.t
===================================================================
--- /main/tags/2.25/gsdl/packages/w3mir/libwww-perl-5.36/t/base/listing.t	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/w3mir/libwww-perl-5.36/t/base/listing.t	(revision 21064)
@@ -0,0 +1,86 @@
+print "1..6\n";
+
+
+use File::Listing;
+
+$dir = <<'EOL';
+total 68
+drwxr-xr-x   4 aas      users        1024 Mar 16 15:47 .
+drwxr-xr-x  11 aas      users        1024 Mar 15 19:22 ..
+drwxr-xr-x   2 aas      users        1024 Mar 16 15:47 CVS
+-rw-r--r--   1 aas      users        2384 Feb 26 21:14 Debug.pm
+-rw-r--r--   1 aas      users        2145 Feb 26 20:09 IO.pm
+-rw-r--r--   1 aas      users        3960 Mar 15 18:05 MediaTypes.pm
+-rw-r--r--   1 aas      users         792 Feb 26 20:12 MemberMixin.pm
+drwxr-xr-x   3 aas      users        1024 Mar 15 18:05 Protocol
+-rw-r--r--   1 aas      users        5613 Feb 26 20:16 Protocol.pm
+-rw-r--r--   1 aas      users        5963 Feb 26 21:27 RobotUA.pm
+-rw-r--r--   1 aas      users        5071 Mar 16 12:25 Simple.pm
+-rw-r--r--   1 aas      users        8817 Mar 15 18:05 Socket.pm
+-rw-r--r--   1 aas      users        2121 Feb  5 14:22 TkIO.pm
+-rw-r--r--   1 aas      users       19628 Mar 15 18:05 UserAgent.pm
+-rw-r--r--   1 aas      users        2841 Feb  5 19:06 media.types
+
+CVS:
+total 5
+drwxr-xr-x   2 aas      users        1024 Mar 16 15:47 .
+drwxr-xr-x   4 aas      users        1024 Mar 16 15:47 ..
+-rw-r--r--   1 aas      users         545 Mar 16 15:47 Entries
+-rw-r--r--   1 aas      users          39 Mar 10 09:05 Repository
+-rw-r--r--   1 aas      users          19 Mar 10 09:05 Root
+
+Protocol:
+total 37
+drwxr-xr-x   3 aas      users        1024 Mar 15 18:05 .
+drwxr-xr-x   4 aas      users        1024 Mar 16 15:47 ..
+drwxr-xr-x   2 aas      users        1024 Mar 15 18:05 CVS
+-rw-r--r--   1 aas      users        4646 Feb 26 20:13 file.pm
+-rw-r--r--   1 aas      users       13006 Mar 15 18:05 ftp.pm
+-rw-r--r--   1 aas      users        5935 Mar  6 10:29 gopher.pm
+-rw-r--r--   1 aas      users        5453 Mar  6 10:29 http.pm
+-rw-r--r--   1 aas      users        2365 Feb 26 20:13 mailto.pm
+
+Protocol/CVS:
+total 5
+drwxr-xr-x   2 aas      users        1024 Mar 15 18:05 .
+drwxr-xr-x   3 aas      users        1024 Mar 15 18:05 ..
+-rw-r--r--   1 aas      users         238 Mar 15 18:05 Entries
+-rw-r--r--   1 aas      users          48 Mar 10 09:05 Repository
+-rw-r--r--   1 aas      users          19 Mar 10 09:05 Root
+EOL
+
+@dir = parse_dir($dir, undef, 'unix');
+
+print int(@dir) ." lines found\n";
+@dir != 25 && print "not ";
+print "ok 1\n";
+
+for (@dir) {
+   ($name, $type, $size, $mtime, $mode) = @$_;
+   $size ||= 0;  # ensure that it is defined
+   printf "%-25s $type %6d  ", $name, $size;
+   print scalar(localtime($mtime));
+   printf "  %06o", $mode;
+   print "\n";
+}
+
+# Pick out the Socket.pm line as the sample we check carefully
+($name, $type, $size, $mtime, $mode) = @{$dir[9]};
+
+$name eq "Socket.pm" || print "not ";
+print "ok 2\n";
+
+$type eq "f" || print "not ";
+print "ok 3\n";
+
+$size == 8817 || print "not ";
+print "ok 4\n";
+
+# Must be careful when checking the time stamps because we don't know
+# which year if this script lives for a long time.
+$timestring = scalar(localtime($mtime));
+$timestring =~ /Mar\s+15\s+18:05/ or print "not ";
+print "ok 5\n";
+
+$mode == 0100644 || print "not ";
+print "ok 6\n";
Index: /main/tags/2.25/gsdl/packages/w3mir/libwww-perl-5.36/t/base/mediatypes.t
===================================================================
--- /main/tags/2.25/gsdl/packages/w3mir/libwww-perl-5.36/t/base/mediatypes.t	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/w3mir/libwww-perl-5.36/t/base/mediatypes.t	(revision 21064)
@@ -0,0 +1,87 @@
+use LWP::MediaTypes;
+
+require URI::URL;
+
+$url1 = new URI::URL 'http://www/foo/test.gif?search+x#frag';
+$url2 = new URI::URL 'http:test';
+
+$file = "/etc/passwd";
+-r $file or $file = "./README";
+
+@tests =
+(
+ ["/this.dir/file.html" => "text/html",],
+ ["test.gif.htm"        => "text/html",],
+ ["test.txt.gz"         => "text/plain", "gzip"],
+ ["gif.foo"             => "application/octet-stream",],
+ ["lwp-0.03.tar.Z"      => "application/x-tar", "compress"],
+ [$file		        => "text/plain",],
+ ["/random/file"        => "application/octet-stream",],
+ ["/dev/null"	        => "text/plain",],
+ [$url1	        	=> "image/gif",],
+ [$url2	        	=> "application/octet-stream",],
+ ["x.ppm.Z.UU"		=> "image/x-portable-pixmap","compress","x-uuencode",],
+);
+
+$notests = @tests + 3;
+print "1..$notests\n";
+
+if (-f "$ENV{HOME}/.mime.types") {
+   warn "
+The MediaTypes test might fail because you have a private ~/.mime.types file
+If you get a failed test, try to move it away while testing.
+";
+}
+
+
+$testno = 1;
+for (@tests) {
+    ($file, $expectedtype, @expectedEnc) = @$_;
+    $type1 = guess_media_type($file);
+    ($type, @enc) = guess_media_type($file);
+    if ($type1 ne $type) {
+       print "guess_media_type does not return same content-type in scalar and array conext.\n";
+	next;
+    }
+    $type = "undef" unless defined $type;
+    if ($type eq $expectedtype and "@enc" eq "@expectedEnc") {
+	print "ok $testno\n";
+    } else {
+	print "expected '$expectedtype' for '$file', got '$type'\n";
+	print "encoding: expected: '@expectedEnc', got '@enc'\n"
+	  if @expectedEnc || @enc;
+	print "nok ok $testno\n";
+    }
+    $testno++;
+}
+
+@imgSuffix = media_suffix('image/*');
+print "Image suffixes: @imgSuffix\n";
+
+print "\n";
+require HTTP::Response;
+$r = new HTTP::Response 200, "Document follows";
+$r->title("file.tar.gz.uu");
+guess_media_type($r->title, $r);
+print $r->as_string;
+
+print "not " unless $r->content_type eq "application/x-tar";
+print "ok $testno\n"; $testno++;
+
+@enc = $r->header("Content-Encoding");
+print "not " unless "@enc" eq "gzip x-uuencode";
+print "ok $testno\n"; $testno++;
+
+#
+use LWP::MediaTypes qw(add_type add_encoding);
+add_type("x-world/x-vrml", qw(wrl vrml));
+add_encoding("x-gzip" => "gz");
+add_encoding(rot13 => "r13");
+
+@x = guess_media_type("foo.vrml.r13.gz");
+#print "@x\n";
+print "not " unless "@x" eq "x-world/x-vrml rot13 x-gzip";
+print "ok $testno\n"; $testno++;
+
+#print LWP::MediaTypes::_dump();
+
Index: /main/tags/2.25/gsdl/packages/w3mir/libwww-perl-5.36/t/base/message.t
===================================================================
--- /main/tags/2.25/gsdl/packages/w3mir/libwww-perl-5.36/t/base/message.t	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/w3mir/libwww-perl-5.36/t/base/message.t	(revision 21064)
@@ -0,0 +1,104 @@
+print "1..15\n";
+
+require HTTP::Request;
+require HTTP::Response;
+
+$req = new HTTP::Request 'GET', "http://www.sn.no/";
+$req->header(
+	"if-modified-since" => "Thu, 03 Feb 1994 00:00:00 GMT",
+	"mime-version"      => "1.0");
+
+$str = $req->as_string;
+
+print $str;
+
+$str =~ /^GET/m || print "not ";
+print "ok 1\n";
+
+$req->header("MIME-Version") eq "1.0" || print "not ";
+print "ok 2\n";
+
+$req->content("gisle");
+$req->add_content(" aas");
+$req->add_content(\ " old interface is depreciated");
+
+${$req->content_ref} =~ s/\s+is\s+depreciated//;
+
+print "Content is: ", $req->content, "\n";
+
+$req->content eq "gisle aas old interface" || print "not ";
+print "ok 3\n";
+
+$req->if_modified_since == 760233600 || print "not ";
+print "ok 4\n";
+
+$time = time;
+
+$req->date($time);
+$timestr = gmtime($time);
+($month) = ($timestr =~ /^\S+\s+(\S+)/);  # extract month;
+
+print "These should represent the same time:\n\t", $req->header('Date'), "\n\t$timestr\n";
+
+$req->header('Date') =~ /\Q$month/ || print "not ";
+print "ok 5\n";
+
+$req->authorization_basic("gisle", "passwd");
+$auth = $req->header("Authorization");
+
+print "$auth\n";
+$auth =~ /Z2lzbGU6cGFzc3dk/ || print "not ";
+print "ok 6\n";
+
+($user, $pass) = $req->authorization_basic;
+($user eq "gisle" && $pass eq "passwd") || print "not ";
+print "ok 7\n";
+
+# Check the response
+$res = new HTTP::Response 200, "This message";
+
+$html = $res->error_as_HTML;
+print $html;
+
+($html =~ /<head>/i && $html =~ /This message/) || print "not ";
+print "ok 8\n";
+
+$res->is_success || print "not ";
+print "ok 9\n";
+
+$res->content_type("text/html;version=3.0");
+$res->content("<html>...</html>\n");
+
+$res2 = $res->clone;
+
+print $res2->as_string;
+
+$res2->header("cOntent-TYPE") eq "text/html;version=3.0" || print "not ";
+print "ok 10\n";
+
+$res2->code == 200 || print "not ";
+print "ok 11\n";
+
+$res2->content =~ />\.\.\.</ || print "not ";
+print "ok 12\n";
+
+# Check the base method:
+
+$res = new HTTP::Response 200, "This message";
+$res->request($req);
+$res->content_type("image/gif");
+
+$res->base eq "http://www.sn.no/" || print "not ";
+print "ok 13\n";
+
+$res->header('Base', 'http://www.sn.no/xxx/');
+
+$res->base eq "http://www.sn.no/xxx/" || print "not ";
+print "ok 14\n";
+
+# Check the AUTLOAD delegate method with regular expressions
+"This string contains text/html" =~ /(\w+\/\w+)/;
+$res->content_type($1);
+
+$res->content_type eq "text/html" || print "not ";
+print "ok 15\n";
Index: /main/tags/2.25/gsdl/packages/w3mir/libwww-perl-5.36/t/base/negotiate.t
===================================================================
--- /main/tags/2.25/gsdl/packages/w3mir/libwww-perl-5.36/t/base/negotiate.t	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/w3mir/libwww-perl-5.36/t/base/negotiate.t	(revision 21064)
@@ -0,0 +1,105 @@
+print "1..3\n";
+
+use HTTP::Request;
+use HTTP::Negotiate;
+
+
+$no = 1;
+sub ok
+{
+    print "ok " . $no++ . "\n";
+}
+
+sub not_ok
+{
+    print "not ";
+    ok;
+}
+
+
+ #  ID       QS     Content-Type             Encoding     Char-Set      Lang    Size
+ $variants =
+  [
+   ['var1',  0.950, 'text/plain',           ['uuencode',
+					     'compress'], 'iso-8859-2', 'se',    400],
+   ['var2',  1.000, 'text/html;version=2.0', 'gzip',      'iso-8859-1', 'en',   3000],
+   ['var3',  0.333, 'image/gif',            undef,        undef,        undef, 43555],
+ ];
+
+
+# First we try a request with not accept headers
+$request = new HTTP::Request 'GET', 'http://localhost/';
+@a = choose($variants, $request);
+show_res(@a);
+expect(\@a, [['var2' => 1],
+	     ['var1' => 0.95],
+	     ['var3' => 0.333]
+	    ]
+);
+
+
+$a = choose($variants, $request);
+print "The chosen one is '$a'\n";
+if ($a eq 'var2') {
+    ok;
+} else {
+    not_ok;
+}
+
+#------------------
+
+$request = new HTTP::Request 'GET', 'http://localhost/';
+$request->header('Accept', 'text/plain; q=0.55, image/gif; mbx=10000');
+$request->push_header('Accept', 'text/*; q=0.25');
+$request->header('Accept-Language', 'no, en');
+$request->header('Accept-Charset', 'iso-8859-1');
+$request->header('Accept-Encoding', 'gzip');
+
+@a = choose($variants, $request);
+show_res(@a);
+expect(\@a, [['var2' => 0.25],
+	     ['var1' => 0],
+	     ['var3' => 0]
+	    ]
+);
+
+
+
+
+#------------------
+
+sub expect
+{
+    my($res, $exp) = @_;
+    do {
+	$a = shift @$res;
+	$b = shift @$exp;
+	last if defined($a) ne defined($b);
+	if (defined($a)) {
+	    ($va, $qa) = @$a;
+	    ($vb, $qb) = @$b;
+	    if ($va ne $vb) {
+		print "$va == $vb ?\n";
+		not_ok;
+		return;
+	    }
+	    if (abs($qa - $qb) > 0.002) {
+		print "$qa ~= $qb ?\n";
+		not_ok;
+		return;
+	    }
+	}
+
+    } until (!defined($a) || !defined($b));
+    return not_ok if defined($a) ne defined($b);
+    ok;
+}
+
+sub show_res
+{
+    print "-------------\n";
+    for (@_) {
+	printf "%-6s %.3f\n", @$_;
+    }
+    print "-------------\n";
+}
Index: /main/tags/2.25/gsdl/packages/w3mir/libwww-perl-5.36/t/base/response.t
===================================================================
--- /main/tags/2.25/gsdl/packages/w3mir/libwww-perl-5.36/t/base/response.t	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/w3mir/libwww-perl-5.36/t/base/response.t	(revision 21064)
@@ -0,0 +1,86 @@
+
+# Test extra HTTP::Response methods.  Basic operation is tested in the
+# message.t test suite.
+
+
+print "1..7\n";
+
+
+use HTTP::Date;
+use HTTP::Request;
+use HTTP::Response;
+
+my $time = time;
+
+$req = HTTP::Request->new(GET => 'http://www.sn.no');
+$req->date($time - 30);
+
+$r = new HTTP::Response 200, "OK";
+$r->client_date($time - 20);
+$r->date($time - 25);
+$r->last_modified($time - 5000000);
+$r->request($req);
+
+print $r->as_string;
+
+$current_age = $r->current_age;
+
+if ($current_age < 35  || $current_age > 40) {
+    print "not ";
+}
+print "ok 1\n";
+
+$freshness_lifetime = $r->freshness_lifetime;
+if ($freshness_lifetime < 12 * 3600) {
+    print "not ";
+}
+print "ok 2\n";
+
+$is_fresh = $r->is_fresh;
+
+print "not " unless $is_fresh;
+print "ok 3\n";
+
+print "current_age        = $current_age\n";
+print "freshness_lifetime = $freshness_lifetime\n";
+print "response is ";
+print "not " unless $is_fresh;
+print "fresh\n";
+
+
+print "it will be fresh is ";
+print $freshness_lifetime - $current_age;
+print " more seconds\n";
+
+# OK, now we add an Expires header
+$r->expires($time);
+print $r->as_string;
+
+$freshness_lifetime = $r->freshness_lifetime;
+print "freshness_lifetime = $freshness_lifetime\n";
+print "not " unless $freshness_lifetime == 25;
+print "ok 4\n";
+$r->remove_header('expires');
+
+# Now we try the 'Age' header and the Cache-Contol:
+
+$r->header('Age', 300);
+$r->push_header('Cache-Control', 'junk');
+$r->push_header(Cache_Control => 'max-age = 10');
+
+print $r->as_string;
+
+$current_age = $r->current_age;
+$freshness_lifetime = $r->freshness_lifetime;
+
+print "current_age        = $current_age\n";
+print "freshness_lifetime = $freshness_lifetime\n";
+
+print "not " if $current_age < 300;
+print "ok 5\n";
+
+print "not " if $freshness_lifetime != 10;
+print "ok 6\n";
+
+print "not " unless $r->fresh_until;  # should return something
+print "ok 7\n";
Index: /main/tags/2.25/gsdl/packages/w3mir/libwww-perl-5.36/t/base/status.t
===================================================================
--- /main/tags/2.25/gsdl/packages/w3mir/libwww-perl-5.36/t/base/status.t	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/w3mir/libwww-perl-5.36/t/base/status.t	(revision 21064)
@@ -0,0 +1,32 @@
+use HTTP::Status;
+
+print "1..8\n";
+
+200 == RC_OK || print "not ";
+print "ok 1\n";
+
+is_success(RC_ACCEPTED) || print "not ";
+print "ok 2\n";
+
+is_error(RC_BAD_REQUEST) || print "not ";
+print "ok 3\n";
+
+is_redirect(RC_MOVED_PERMANENTLY) || print "not ";
+print "ok 4\n";
+
+is_success(RC_NOT_FOUND) && print "not ";
+print "ok 5\n";
+
+$mess = status_message(0);
+
+defined $mess && print "not ";
+print "ok 6\n";
+
+$mess = status_message(200);
+
+if ($mess =~ /ok/i) {
+    print "ok 7\n";
+}
+
+is_info(RC_CONTINUE) || print "not ";
+print "ok 8\n";
Index: /main/tags/2.25/gsdl/packages/w3mir/libwww-perl-5.36/t/local/autoload.t
===================================================================
--- /main/tags/2.25/gsdl/packages/w3mir/libwww-perl-5.36/t/local/autoload.t	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/w3mir/libwww-perl-5.36/t/local/autoload.t	(revision 21064)
@@ -0,0 +1,30 @@
+#
+# See if autoloading of protocol schemes work
+#
+
+print "1..1\n";
+
+require LWP::UserAgent;
+# note no LWP::Protocol::file;
+
+# localhost will not work on win32 (when networking is disabled)
+$url = $^O eq 'MSWin32' ? 'file:.' : 'file://localhost/';
+
+print "Trying to fetch " . (new URI::URL $url)->local_path . " ...\n";
+
+my $ua = new LWP::UserAgent;    # create a useragent to test
+
+$ua->timeout(30);               # timeout in seconds
+#$ua->use_alarm(0);               # don't use alarms
+#$ua->use_eval(0);                # don't eval, just die when thing go wrong
+				# (easier to read while debugging)
+
+my $request = new HTTP::Request('GET', $url);
+
+my $response = $ua->request($request, undef, undef);
+if ($response->is_success) {
+    print "ok 1\n";
+} else {
+    print $response->error_as_HTML;
+    print "not ok 1\n";
+}
Index: /main/tags/2.25/gsdl/packages/w3mir/libwww-perl-5.36/t/local/get.t
===================================================================
--- /main/tags/2.25/gsdl/packages/w3mir/libwww-perl-5.36/t/local/get.t	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/w3mir/libwww-perl-5.36/t/local/get.t	(revision 21064)
@@ -0,0 +1,85 @@
+#
+# Test retrieving a file with a 'file://' URL,
+#
+
+# First locate some suitable tmp-dir.  We need an absolute path.
+$TMPDIR = undef;
+for ("/tmp/", "/var/tmp", "/usr/tmp", "/local/tmp") {
+    if (open(TEST, ">$_/test-$$")) {
+        close(TEST);
+	unlink("$_/test-$$");
+	$TMPDIR = $_;
+	last;
+    }
+}
+$TMPDIR ||= $ENV{TEMP} if $^O eq 'MSWin32';
+unless ($TMPDIR) {
+   # Can't run any tests
+   print "1..0\n";
+   print "ok 1\n";
+   exit;
+}
+$TMPDIR =~ tr|\\|/|;
+print "1..2\n";
+
+use LWP::Simple;
+require LWP::Protocol::file;
+
+my $orig = "$TMPDIR/lwp-orig-$$";          # local file
+my $copy = "$TMPDIR/lwp-copy-$$"; 	    # downloaded copy
+
+# First we create the original
+open(OUT, ">$orig") or die "Cannot open $orig: $!";
+for (1..100) {
+    print OUT "This is line $_ of $orig\n";
+}
+close(OUT);
+
+
+# Then we make a test using getprint(), so we need to capture stdout
+open (OUT, ">$copy") or die "Cannot open $copy: $!";
+select(OUT);
+
+# do the retrieval
+getprint("file://localhost" . ($orig =~ m|^/| ? $orig : "/$orig"));
+
+close(OUT);
+select(STDOUT);
+
+# read and compare the files
+open(IN, $orig) or die "Cannot open '$orig': $!";
+undef($/);
+$origtext = <IN>;
+close(IN);
+open(IN, $copy) or die "Cannot open '$copy': $!";
+undef($/);
+$copytext = <IN>;
+close(IN);
+
+unlink($copy);
+
+if ($origtext eq $copytext) {
+    print "ok 1\n";
+} else {
+    print "not ok 1\n";
+}
+
+
+# Test getstore() function
+
+getstore("file:$orig", $copy);
+
+# Take a look at the new copy
+open(IN, $copy) or die "Cannot open '$copy': $!";
+undef($/);
+$copytext = <IN>;
+close(IN);
+
+unlink($orig);
+unlink($copy);
+
+if ($origtext eq $copytext) {
+    print "ok 2\n";
+} else {
+    print "not ok 2\n";
+}
Index: /main/tags/2.25/gsdl/packages/w3mir/libwww-perl-5.36/t/local/http.t
===================================================================
--- /main/tags/2.25/gsdl/packages/w3mir/libwww-perl-5.36/t/local/http.t	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/w3mir/libwww-perl-5.36/t/local/http.t	(revision 21064)
@@ -0,0 +1,319 @@
+$| = 1; # autoflush
+
+require IO::Socket;  # make sure this work before we try to make a HTTP::Daemon
+
+# First we make ourself a daemon in another process
+my $D = shift || '';
+if ($D eq 'daemon') {
+
+    require HTTP::Daemon;
+
+    my $d = new HTTP::Daemon Timeout => 10;
+
+    print "Please to meet you at: <URL:", $d->url, ">\n";
+    open(STDOUT, ">/dev/null");
+
+    while ($c = $d->accept) {
+	$r = $c->get_request;
+	if ($r) {
+	    my $p = ($r->url->path_components)[1];
+	    my $func = lc("httpd_" . $r->method . "_$p");
+	    if (defined &$func) {
+		&$func($c, $r);
+	    } else {
+		$c->send_error(404);
+	    }
+	}
+	$c = undef;  # close connection
+    }
+    print STDERR "HTTP Server terminated\n";
+    exit;
+}
+else {
+    use Config;
+    open(DAEMON, "$Config{'perlpath'} local/http.t daemon |") or die "Can't exec daemon: $!";
+}
+
+print "1..18\n";
+
+
+my $greeting = <DAEMON>;
+$greeting =~ /(<[^>]+>)/;
+
+require URI::URL;
+URI::URL->import;
+my $base = new URI::URL $1;
+
+print "Will access HTTP server at $base\n";
+
+require LWP::UserAgent;
+require HTTP::Request;
+$ua = new LWP::UserAgent;
+$ua->agent("Mozilla/0.01 " . $ua->agent);
+$ua->from('gisle@aas.no');
+
+#----------------------------------------------------------------
+print "Bad request...\n";
+$req = new HTTP::Request GET => url("/not_found", $base);
+$req->header(X_Foo => "Bar");
+$res = $ua->request($req);
+
+print "not " unless $res->is_error
+                and $res->code == 404
+                and $res->message =~ /not\s+found/i;
+print "ok 1\n";
+# we also expect a few headers
+print "not " if !$res->server and !$res->date;
+print "ok 2\n";
+
+#----------------------------------------------------------------
+print "Simple echo...\n";
+sub httpd_get_echo
+{
+    my($c, $req) = @_;
+    $c->send_basic_header(200);
+    print $c "Content-Type: text/plain\015\012";
+    $c->send_crlf;
+    print $c $req->as_string;
+}
+
+$req = new HTTP::Request GET => url("/echo/path_info?query", $base);
+$req->push_header(Accept => 'text/html');
+$req->push_header(Accept => 'text/plain; q=0.9');
+$req->push_header(Accept => 'image/*');
+$req->if_modified_since(time - 300);
+$req->header(Long_text => 'This is a very long header line
+which is broken between
+more than one line.');
+$req->header(X_Foo => "Bar");
+
+$res = $ua->request($req);
+#print $res->as_string;
+
+print "not " unless $res->is_success
+               and  $res->code == 200 && $res->message eq "OK";
+print "ok 3\n";
+
+$_ = $res->content;
+@accept = /^Accept:\s*(.*)/mg;
+
+print "not " unless /^From:\s*gisle\@aas\.no$/m
+                and /^Host:/m
+                and @accept == 3
+	        and /^Accept:\s*text\/html/m
+	        and /^Accept:\s*text\/plain/m
+	        and /^Accept:\s*image\/\*/m
+		and /^If-Modified-Since:\s*\w{3},\s+\d+/m
+                and /^Long-Text:\s*This.*broken between/m
+		and /^X-Foo:\s*Bar$/m
+		and /^User-Agent:\s*Mozilla\/0.01/m;
+print "ok 4\n";
+
+#----------------------------------------------------------------
+print "Send file...\n";
+
+my $file = "test-$$.html";
+open(FILE, ">$file") or die "Can't create $file: $!";
+binmode FILE or die "Can't binmode $file: $!";
+print FILE <<EOT;
+<html><title>En prøve</title>
+<h1>Dette er en testfil</h1>
+Jeg vet ikke hvor stor fila behøver å være heller, men dette
+er sikkert nok i massevis.
+EOT
+close(FILE);
+
+sub httpd_get_file
+{
+    my($c, $r) = @_;
+    my %form = $r->url->query_form;
+    my $file = $form{'name'};
+    $c->send_file_response($file);
+    unlink($file);
+}
+
+$req = new HTTP::Request GET => url("/file?name=$file", $base);
+$res = $ua->request($req);
+#print $res->as_string;
+
+print "not " unless $res->is_success
+                and $res->content_type eq 'text/html'
+		and $res->content_length == 147
+		and $res->title eq 'En prøve'
+		and $res->content =~ /å være/;
+print "ok 5\n";		
+
+
+# A second try on the same file, should fail because we unlink it
+$res = $ua->request($req);
+#print $res->as_string;
+print "not " unless $res->is_error
+                and $res->code == 404;   # not found
+print "ok 6\n";
+		
+# Then try to list current directory
+$req = new HTTP::Request GET => url("/file?name=.", $base);
+$res = $ua->request($req);
+#print $res->as_string;
+print "not " unless $res->code == 501;   # NYI
+print "ok 7\n";
+
+
+#----------------------------------------------------------------
+print "Check redirect...\n";
+sub httpd_get_redirect
+{
+   my($c) = @_;
+   $c->send_redirect("/echo/redirect");
+}
+
+$req = new HTTP::Request GET => url("/redirect/foo", $base);
+$res = $ua->request($req);
+#print $res->as_string;
+
+print "not " unless $res->is_success
+                and $res->content =~ m|/echo/redirect|;
+print "ok 8\n";
+print "not " unless $res->previous->is_redirect
+                and $res->previous->code == 301;
+print "ok 9\n";
+
+# Let's test a redirect loop too
+sub httpd_get_redirect2 { shift->send_redirect("/redirect3/") }
+sub httpd_get_redirect3 { shift->send_redirect("/redirect4/") }
+sub httpd_get_redirect4 { shift->send_redirect("/redirect5/") }
+sub httpd_get_redirect5 { shift->send_redirect("/redirect6/") }
+sub httpd_get_redirect6 { shift->send_redirect("/redirect2/") }
+
+$req->url(url("/redirect2", $base));
+$res = $ua->request($req);
+#print $res->as_string;
+print "not " unless $res->is_redirect
+                and $res->header("Client-Warning") =~ /loop detected/i;
+print "ok 10\n";
+$i = 1;
+while ($res->previous) {
+   $i++;
+   $res = $res->previous;
+}
+print "not " unless $i == 6;
+print "ok 11\n";
+
+#----------------------------------------------------------------
+print "Check basic authorization...\n";
+sub httpd_get_basic
+{
+    my($c, $r) = @_;
+    #print STDERR $r->as_string;
+    my($u,$p) = $r->authorization_basic;
+    if (defined($u) && $u eq 'ok 12' && $p eq 'xyzzy') {
+        $c->send_basic_header(200);
+	print $c "Content-Type: text/plain";
+	$c->send_crlf;
+	$c->send_crlf;
+	$c->print("$u\n");
+    } else {
+        $c->send_basic_header(401);
+	$c->print("WWW-Authenticate: Basic realm=\"libwww-perl\"\015\012");
+	$c->send_crlf;
+    }
+}
+
+{
+   package MyUA; @ISA=qw(LWP::UserAgent);
+   sub get_basic_credentials {
+      my($self, $realm, $uri, $proxy) = @_;
+      my $x =  $uri->rel($base);
+      if ($realm eq "libwww-perl" && $uri->rel($base) eq "basic") {
+	  return ("ok 12", "xyzzy");
+      } else {
+          return undef;
+      }
+   }
+}
+$req = new HTTP::Request GET => url("/basic", $base);
+$res = MyUA->new->request($req);
+#print $res->as_string;
+
+print "not " unless $res->is_success;
+print $res->content;
+
+# Let's try with a $ua that does not pass out credentials
+$res = $ua->request($req);
+print "not " unless $res->code == 401;
+print "ok 13\n";
+
+# Let's try to set credentials for this realm
+$ua->credentials($req->url->netloc, "libwww-perl", "ok 12", "xyzzy");
+$res = $ua->request($req);
+print "not " unless $res->is_success;
+print "ok 14\n";
+
+# Then illegal credentials
+$ua->credentials($req->url->netloc, "libwww-perl", "user", "passwd");
+$res = $ua->request($req);
+print "not " unless $res->code == 401;
+print "ok 15\n";
+
+
+#----------------------------------------------------------------
+print "Check proxy...\n";
+sub httpd_get_proxy
+{
+   my($c,$r) = @_;
+   if ($r->method eq "GET" and
+       $r->url->scheme eq "ftp") {
+       $c->send_basic_header(200);
+       $c->send_crlf;
+   } else {
+       $c->send_error;
+   }
+}
+
+$ua->proxy(ftp => $base);
+$req = new HTTP::Request GET => "ftp://ftp.perl.com/proxy";
+$res = $ua->request($req);
+#print $res->as_string;
+print "not " unless $res->is_success;
+print "ok 16\n";
+
+#----------------------------------------------------------------
+print "Check POSTing...\n";
+sub httpd_post_echo
+{
+   my($c,$r) = @_;
+   $c->send_basic_header;
+   $c->print("Content-Type: text/plain");
+   $c->send_crlf;
+   $c->send_crlf;
+   $c->print($r->as_string);
+}
+
+$req = new HTTP::Request POST => url("/echo/foo", $base);
+$req->content_type("application/x-www-form-urlencoded");
+$req->content("foo=bar&bar=test");
+$res = $ua->request($req);
+#print $res->as_string;
+
+$_ = $res->content;
+print "not " unless $res->is_success
+                and /^Content-Length:\s*16$/mi
+		and /^Content-Type:\s*application\/x-www-form-urlencoded$/mi
+		and /^foo=bar&bar=test/m;
+print "ok 17\n";		
+
+#----------------------------------------------------------------
+print "Terminating server...\n";
+sub httpd_get_quit
+{
+    my($c) = @_;
+    $c->send_error(503, "Bye, bye");
+    exit;  # terminate HTTP server
+}
+
+$req = new HTTP::Request GET => url("/quit", $base);
+$res = $ua->request($req);
+
+print "not " unless $res->code == 503 and $res->content =~ /Bye, bye/;
+print "ok 18\n";
+
Index: /main/tags/2.25/gsdl/packages/w3mir/libwww-perl-5.36/t/local/protosub.t
===================================================================
--- /main/tags/2.25/gsdl/packages/w3mir/libwww-perl-5.36/t/local/protosub.t	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/w3mir/libwww-perl-5.36/t/local/protosub.t	(revision 21064)
@@ -0,0 +1,73 @@
+#!perl
+
+print "1..6\n";
+
+# This test tries to make a custom protocol implementation by
+# subclassing of LWP::Protocol.
+
+
+use LWP::UserAgent ();
+use LWP::Protocol ();
+
+LWP::Protocol::implementor(http => 'myhttp');
+
+$ua = LWP::UserAgent->new;
+$ua->proxy('ftp' => "http://www.sn.no/");
+
+$req = HTTP::Request->new(GET => 'ftp://foo/');
+$req->header(Cookie => "perl=cool");
+
+$res = $ua->request($req);
+
+print $res->as_string;
+
+print "not " unless $res->code == 200;
+print "ok 5\n";
+print "not " unless $res->content eq "Howdy\n";
+print "ok 6\n";
+exit;
+
+
+#----------------------------------
+package myhttp;
+
+BEGIN {
+   @ISA=qw(LWP::Protocol);
+}
+
+sub new
+{
+    my $class = shift;
+    print "CTOR: $class->new(@_)\n";
+    my($prot) = @_;
+    print "not " unless $prot eq "http";
+    print "ok 1\n";
+    my $self = $class->SUPER::new(@_);
+    for (keys %$self) {
+	print "$_: $self->{$_}\n";
+    }
+    $self;
+}
+
+sub request
+{
+    my $self = shift;
+    print "REQUEST: $self->request(",
+       join(",", (map defined($_)? $_ : "UNDEF", @_)), ")\n";
+
+    my($request, $proxy, $arg, $size, $timeout) = @_;
+    print $request->as_string;
+
+    print "not " unless $proxy eq "http://www.sn.no/";
+    print "ok 2\n";
+    print "not " unless $request->url eq "ftp://foo/";
+    print "ok 3\n";
+    print "not " unless $request->header("cookie") eq "perl=cool";
+    print "ok 4\n";
+
+    my $res = HTTP::Response->new(200 => "OK");
+    $res->content_type("text/plain");
+    $res->date(time);
+    $self->collect_once($arg, $res, "Howdy\n");
+    $res;
+}
Index: /main/tags/2.25/gsdl/packages/w3mir/libwww-perl-5.36/t/net/cgi-bin/moved
===================================================================
--- /main/tags/2.25/gsdl/packages/w3mir/libwww-perl-5.36/t/net/cgi-bin/moved	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/w3mir/libwww-perl-5.36/t/net/cgi-bin/moved	(revision 21064)
@@ -0,0 +1,4 @@
+#!/bin/sh
+
+echo "Location: http://$SERVER_NAME:$SERVER_PORT/"
+echo
Index: /main/tags/2.25/gsdl/packages/w3mir/libwww-perl-5.36/t/net/cgi-bin/nph-slowdata
===================================================================
--- /main/tags/2.25/gsdl/packages/w3mir/libwww-perl-5.36/t/net/cgi-bin/nph-slowdata	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/w3mir/libwww-perl-5.36/t/net/cgi-bin/nph-slowdata	(revision 21064)
@@ -0,0 +1,26 @@
+#!/usr/local/bin/perl
+
+# This script outputs some data slowly. It can be used to check that
+# pipelined processing of response content really works.  We use syswrite
+# so that the script will notice when the connection is broken.
+
+out("HTTP/1.0 200 OK\r
+Content-Type: text/plain\r
+\r
+");
+
+for (1..5) {
+    out("The number is now $_\n");
+    sleep(1);
+}
+exit;
+
+
+sub out
+{
+    my $data = shift;
+    my $l = length $data;
+    if (syswrite(STDOUT, $data, $l) != $l) {
+	exit 1;
+    }
+}
Index: /main/tags/2.25/gsdl/packages/w3mir/libwww-perl-5.36/t/net/cgi-bin/slowread
===================================================================
--- /main/tags/2.25/gsdl/packages/w3mir/libwww-perl-5.36/t/net/cgi-bin/slowread	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/w3mir/libwww-perl-5.36/t/net/cgi-bin/slowread	(revision 21064)
@@ -0,0 +1,31 @@
+#!/usr/local/bin/perl
+
+# You might post large amount of data to this script.  It will read
+# it slowly.
+
+{ local($!) = 1; print "Content-Type: text/plain\n\n"; }
+
+$len = $ENV{CONTENT_LENGTH};
+
+unless ($len) {
+    system "env";
+    exit;
+}
+
+$size = 20;  # chunk size
+
+$content = '';
+$bytes = 0;
+
+sleep(1);
+while ($len > 0) {
+    $n = sysread(STDIN, $b, $size);
+    last if $n <= 0;
+    $len -= $n;
+    $bytes += $n;
+    $content .= $b;
+    sleep(1);
+}
+print "$bytes bytes read\n";
+
+	
Index: /main/tags/2.25/gsdl/packages/w3mir/libwww-perl-5.36/t/net/cgi-bin/test
===================================================================
--- /main/tags/2.25/gsdl/packages/w3mir/libwww-perl-5.36/t/net/cgi-bin/test	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/w3mir/libwww-perl-5.36/t/net/cgi-bin/test	(revision 21064)
@@ -0,0 +1,28 @@
+#!/usr/local/bin/perl
+
+$| = 1;
+print "Content-type: text/plain
+
+";
+
+if (@ARGV) {
+    print "ARGS: ";
+    print join(", ", map { $_ = qq{"$_"} } @ARGV);
+    print "\n\n";
+} else {
+    print "No command line arguments passed to script\n\n";
+}
+
+while (($key,$val) = each %ENV) {
+   print "$key=$val\n";
+}
+
+if ($ENV{CONTENT_LENGTH}) {
+    $len = $ENV{CONTENT_LENGTH};
+    while ($len) {
+	$n = sysread(STDIN, $content, $len, length $content);
+	last unless defined $n;
+	$len -= $n;
+    }
+    print "\nContent\n-------\n$content";
+}
Index: /main/tags/2.25/gsdl/packages/w3mir/libwww-perl-5.36/t/net/cgi-bin/timeout
===================================================================
--- /main/tags/2.25/gsdl/packages/w3mir/libwww-perl-5.36/t/net/cgi-bin/timeout	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/w3mir/libwww-perl-5.36/t/net/cgi-bin/timeout	(revision 21064)
@@ -0,0 +1,7 @@
+#!/bin/sh
+
+sleep 20;
+
+echo "Content-type: text/plain"
+echo
+echo "Test"
Index: /main/tags/2.25/gsdl/packages/w3mir/libwww-perl-5.36/t/net/config.pl.dist
===================================================================
--- /main/tags/2.25/gsdl/packages/w3mir/libwww-perl-5.36/t/net/config.pl.dist	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/w3mir/libwww-perl-5.36/t/net/config.pl.dist	(revision 21064)
@@ -0,0 +1,10 @@
+package net;
+
+# Configure these for you local system
+$httpserver  = "localhost:80";
+$cgidir      = "/cgi-bin/lwp";
+
+# Used for proxy test
+$ftp_proxy = "http://localhost/";
+
+1;
Index: /main/tags/2.25/gsdl/packages/w3mir/libwww-perl-5.36/t/net/http-get.t
===================================================================
--- /main/tags/2.25/gsdl/packages/w3mir/libwww-perl-5.36/t/net/http-get.t	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/w3mir/libwww-perl-5.36/t/net/http-get.t	(revision 21064)
@@ -0,0 +1,43 @@
+#!/usr/local/bin/perl -w
+#
+# Check GET via HTTP.
+#
+
+print "1..2\n";
+
+require "net/config.pl";
+require LWP::Protocol::http;
+require LWP::UserAgent;
+
+my $ua = new LWP::UserAgent;    # create a useragent to test
+
+$netloc = $net::httpserver;
+$script = $net::cgidir . "/test";
+
+$url = new URI::URL("http://$netloc$script?query");
+
+my $request = new HTTP::Request('GET', $url);
+
+print "GET $url\n\n";
+
+my $response = $ua->request($request, undef, undef);
+
+my $str = $response->as_string;
+
+print "$str\n";
+
+if ($response->is_success and $str =~ /^REQUEST_METHOD=GET$/m) {
+    print "ok 1\n";
+} else {
+    print "not ok 1\n";
+}
+
+if ($str =~ /^QUERY_STRING=query$/m) {
+    print "ok 2\n";
+} else {
+    print "not ok 2\n";
+}
+
+# avoid -w warning
+$dummy = $net::httpserver;
+$dummy = $net::cgidir;
Index: /main/tags/2.25/gsdl/packages/w3mir/libwww-perl-5.36/t/net/http-post.t
===================================================================
--- /main/tags/2.25/gsdl/packages/w3mir/libwww-perl-5.36/t/net/http-post.t	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/w3mir/libwww-perl-5.36/t/net/http-post.t	(revision 21064)
@@ -0,0 +1,44 @@
+#!/usr/local/bin/perl -w
+#
+# Check POST via HTTP.
+#
+
+print "1..2\n";
+
+require "net/config.pl";
+require LWP::Protocol::http;
+require LWP::UserAgent;
+
+$netloc = $net::httpserver;
+$script = $net::cgidir . "/test";
+
+my $ua = new LWP::UserAgent;    # create a useragent to test
+
+$url = new URI::URL("http://$netloc$script");
+
+my $form = 'searchtype=Substring';
+
+my $request = new HTTP::Request('POST', $url, undef, $form);
+$request->header('Content-Type', 'application/x-www-form-urlencoded');
+
+my $response = $ua->request($request, undef, undef);
+
+my $str = $response->as_string;
+
+print "$str\n";
+
+if ($response->is_success and $str =~ /^REQUEST_METHOD=POST$/m) {
+    print "ok 1\n";
+} else {
+    print "not ok 1\n";
+}
+
+if ($str =~ /^CONTENT_LENGTH=(\d+)$/m && $1 == length($form)) {
+    print "ok 2\n";
+} else {
+    print "not ok 2\n";
+}
+
+# avoid -w warning
+$dummy = $net::httpserver;
+$dummy = $net::cgidir;
Index: /main/tags/2.25/gsdl/packages/w3mir/libwww-perl-5.36/t/net/http-timeout.t
===================================================================
--- /main/tags/2.25/gsdl/packages/w3mir/libwww-perl-5.36/t/net/http-timeout.t	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/w3mir/libwww-perl-5.36/t/net/http-timeout.t	(revision 21064)
@@ -0,0 +1,41 @@
+#
+# Check timeouts via HTTP.
+#
+
+print "1..1\n";
+
+require "net/config.pl";
+require HTTP::Status;
+require LWP::Protocol::http;
+require LWP::UserAgent;
+
+my $ua = new LWP::UserAgent;    # create a useragent to test
+
+$ua->timeout(4);
+
+$netloc = $net::httpserver;
+$script = $net::cgidir . "/timeout";
+
+$url = new URI::URL("http://$netloc$script");
+
+my $request = new HTTP::Request('GET', $url);
+
+print $request->as_string;
+
+my $response = $ua->request($request, undef);
+
+my $str = $response->as_string;
+
+print "$str\n";
+
+if ($response->is_error and
+    $str =~ /timeout/) {
+    print "ok 1\n";
+}
+else {
+    print "nok ok 1\n";
+}
+
+# avoid -w warning
+$dummy = $net::httpserver;
+$dummy = $net::cgidir;
Index: /main/tags/2.25/gsdl/packages/w3mir/libwww-perl-5.36/t/net/mirror.t
===================================================================
--- /main/tags/2.25/gsdl/packages/w3mir/libwww-perl-5.36/t/net/mirror.t	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/w3mir/libwww-perl-5.36/t/net/mirror.t	(revision 21064)
@@ -0,0 +1,34 @@
+#
+# Test mirroring a file
+#
+
+require "net/config.pl";
+require LWP::Protocol::http;
+require LWP::UserAgent;
+require HTTP::Status;
+
+print "1..2\n";
+
+my $ua = new LWP::UserAgent;    # create a useragent to test
+
+my $url = "http://$net::httpserver/";
+my $copy = "lwp-test-$$"; # downloaded copy
+
+my $response = $ua->mirror($url, $copy);
+
+if ($response->code == &HTTP::Status::RC_OK) {
+    print "ok 1\n";
+} else {
+    print "not ok 1\n";
+}
+
+# OK, so now do it again, should get Not-Modified
+$response = $ua->mirror($url, $copy);
+if ($response->code == &HTTP::Status::RC_NOT_MODIFIED) {
+    print "ok 2\n";
+} else {
+    print "nok ok 2\n";
+}
+unlink($copy);
+
+$net::httpserver = $net::httpserver;  # avoid -w warning
Index: /main/tags/2.25/gsdl/packages/w3mir/libwww-perl-5.36/t/net/moved.t
===================================================================
--- /main/tags/2.25/gsdl/packages/w3mir/libwww-perl-5.36/t/net/moved.t	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/w3mir/libwww-perl-5.36/t/net/moved.t	(revision 21064)
@@ -0,0 +1,34 @@
+#!/usr/local/bin/perl -w
+#
+
+print "1..1\n";
+
+require "net/config.pl";
+require LWP::Debug;
+require LWP::UserAgent;
+
+$url = "http://$net::httpserver$net::cgidir/moved";
+
+#LWP::Debug::level('+trace');
+
+my $ua = new LWP::UserAgent;    # create a useragent to test
+$ua->timeout(30);               # timeout in seconds
+
+my $request = new HTTP::Request('GET', $url);
+
+print $request->as_string;
+
+my $response = $ua->request($request, undef, undef);
+
+print $response->as_string, "\n";
+
+if ($response->is_success) {
+    print "ok 1\n";
+} else {
+    print "not ok 1\n";
+}
+
+
+# avoid -w warning
+$dummy = $net::httpserver;
+$dummy = $net::cgidir;
Index: /main/tags/2.25/gsdl/packages/w3mir/libwww-perl-5.36/t/net/proxy.t
===================================================================
--- /main/tags/2.25/gsdl/packages/w3mir/libwww-perl-5.36/t/net/proxy.t	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/w3mir/libwww-perl-5.36/t/net/proxy.t	(revision 21064)
@@ -0,0 +1,36 @@
+#!/usr/local/bin/perl -w
+#
+# Test retrieving a file with a 'ftp://' URL,
+# via a HTTP proxy.
+#
+
+print "1..1\n";
+
+require "net/config.pl";
+unless (defined $net::ftp_proxy) {
+    print "not ok 1\n";
+    exit 0;
+}
+
+require LWP::Debug;
+require LWP::UserAgent;
+
+#LWP::Debug::level('+');
+
+my $ua = new LWP::UserAgent;    # create a useragent to test
+
+$ua->proxy('ftp', $net::ftp_proxy);
+
+my $url = new URI::URL('ftp://ftp.uninett.no/');
+
+my $request = new HTTP::Request('GET', $url);
+
+my $response = $ua->request($request, undef, undef);
+
+my $str = $response->as_string;
+
+if ($response->is_success) {
+    print "ok 1\n";
+} else {
+    print "not ok 1\n";
+}
Index: /main/tags/2.25/gsdl/packages/w3mir/libwww-perl-5.36/t/robot/rules-dbm.t
===================================================================
--- /main/tags/2.25/gsdl/packages/w3mir/libwww-perl-5.36/t/robot/rules-dbm.t	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/w3mir/libwww-perl-5.36/t/robot/rules-dbm.t	(revision 21064)
@@ -0,0 +1,128 @@
+
+print "1..13\n";
+
+
+use WWW::RobotRules::AnyDBM_File;
+
+$file = "test-$$";
+
+$r = new WWW::RobotRules::AnyDBM_File "myrobot/2.0", $file;
+
+$r->parse("http://www.aas.no/robots.txt", "");
+
+$r->visit("www.aas.no");
+
+print "not " if $r->no_visits("www.aas.no") != 1;
+print "ok 1\n";
+
+
+$r->push_rules("www.sn.no", "/aas", "/per");
+$r->push_rules("www.sn.no", "/god", "/old");
+
+@r = $r->rules("www.sn.no");
+print "Rules: @r\n";
+
+print "not " if "@r" ne "/aas /per /god /old";
+print "ok 2\n";
+
+$r->clear_rules("per");
+$r->clear_rules("www.sn.no");
+
+@r = $r->rules("www.sn.no");
+print "Rules: @r\n";
+
+print "not " if "@r" ne "";
+print "ok 3\n";
+
+$r->visit("www.aas.no", time+10);
+$r->visit("www.sn.no");
+
+print "No visits: ", $r->no_visits("www.aas.no"), "\n";
+print "Last visit: ", $r->last_visit("www.aas.no"), "\n";
+print "Fresh until: ", $r->fresh_until("www.aas.no"), "\n";
+
+print "not " if $r->no_visits("www.aas.no") != 2;
+print "ok 4\n";
+
+print "not " if abs($r->last_visit("www.sn.no") - time) > 2;
+print "ok 5\n";
+
+$r = undef;
+
+# Try to reopen the database without a name specified
+$r = new WWW::RobotRules::AnyDBM_File undef, $file;
+$r->visit("www.aas.no");
+
+print "not " if $r->no_visits("www.aas.no") != 3;
+print "ok 6\n";
+
+print "Agent-Name: ", $r->agent, "\n";
+print "not " if $r->agent ne "myrobot";
+print "ok 7\n";
+
+$r = undef;
+
+print "*** Dump of database ***\n";
+tie(%cat, AnyDBM_File, $file, 0, 0644) or die "Can't tie: $!";
+while (($key,$val) = each(%cat)) {
+    print "$key\t$val\n";
+}
+print "******\n";
+
+untie %cat;
+
+# Try to open database with a different agent name
+$r = new WWW::RobotRules::AnyDBM_File "MOMSpider/2.0", $file;
+
+print "not " if $r->no_visits("www.sn.no");
+print "ok 8\n";
+
+# Try parsing
+$r->parse("http://www.sn.no:8080/robots.txt", <<EOT, (time + 3));
+
+User-Agent: *
+Disallow: /
+
+User-Agent: Momspider
+Disallow: /foo
+Disallow: /bar
+
+EOT
+
+@r = $r->rules("www.sn.no:8080");
+print "not " if "@r" ne "/foo /bar";
+print "ok 9\n";
+
+print "not " if $r->allowed("http://www.sn.no") >= 0;
+print "ok 10\n";
+
+print "not " if $r->allowed("http://www.sn.no:8080/foo/gisle");
+print "ok 11\n";
+
+sleep(5);  # wait until file has expired
+print "not " if $r->allowed("http://www.sn.no:8080/foo/gisle") >= 0;
+print "ok 12\n";
+
+
+$r = undef;
+
+print "*** Dump of database ***\n";
+tie(%cat, AnyDBM_File, $file, 0, 0644) or die "Can't tie: $!";
+while (($key,$val) = each(%cat)) {
+    print "$key\t$val\n";
+}
+print "******\n";
+
+untie %cat;			# Otherwise the next line fails on DOSish
+
+unlink "$file", "$file.pag", "$file.dir", "$file.db";
+
+# Try open a an emty database without specifying a name
+eval { 
+   $r = new WWW::RobotRules::AnyDBM_File undef, $file;
+};
+print $@;
+print "not " unless $@;  # should fail
+print "ok 13\n";
+
+unlink "$file", "$file.pag", "$file.dir", "$file.db";
Index: /main/tags/2.25/gsdl/packages/w3mir/libwww-perl-5.36/t/robot/rules.t
===================================================================
--- /main/tags/2.25/gsdl/packages/w3mir/libwww-perl-5.36/t/robot/rules.t	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/w3mir/libwww-perl-5.36/t/robot/rules.t	(revision 21064)
@@ -0,0 +1,138 @@
+#!/local/bin/perl
+
+=head1 NAME
+
+robot-rules.t
+
+=head1 DESCRIPTION
+
+Test a number of different A</robots.txt> files against a number
+of different User-agents.
+
+=cut
+
+require WWW::RobotRules;
+use Carp;
+use strict;
+
+print "1..26\n"; # for Test::Harness
+
+# We test a number of different /robots.txt files,
+#
+
+my $content1 = <<EOM;
+# http://foo/robots.txt
+User-agent: *
+Disallow: /private
+Disallow: http://foo/also_private
+
+User-agent: MOMspider
+Disallow:
+EOM
+
+my $content2 = <<EOM;
+# http://foo/robots.txt
+User-agent: MOMspider
+ # comment which should be ignored
+Disallow: /private
+EOM
+
+my $content3 = <<EOM;
+# http://foo/robots.txt
+EOM
+
+my $content4 = <<EOM;
+# http://foo/robots.txt
+User-agent: *
+Disallow: /private
+
+User-agent: MOMspider
+Disallow: /this
+
+User-agent: Another
+Disallow: /that
+EOM
+
+# and a number of different robots:
+
+my @tests1 = (
+	   [$content1, 'MOMspider' =>
+	    1 => 'http://foo/private' => 1,
+	    2 => 'http://foo/also_private' => 1,
+	   ],
+
+	   [$content1, 'Wubble' =>
+	    3 => 'http://foo/private' => 0,
+	    4 => 'http://foo/also_private' => 0,
+	    5 => 'http://foo/other' => 1,
+	   ],
+
+	   [$content2, 'MOMspider' =>
+	    6 => 'http://foo/private' => 0,
+	    7 => 'http://foo/other' => 1,
+	   ],
+
+	   [$content2, 'Wubble' =>
+	    8  => 'http://foo/private' => 1,
+	    9  => 'http://foo/also_private' => 1,
+	    10 => 'http://foo/other' => 1,
+	   ],
+
+	   [$content3, 'MOMspider' =>
+	    11 => 'http://foo/private' => 1,
+	    12 => 'http://foo/other' => 1,
+	   ],
+
+	   [$content3, 'Wubble' =>
+	    13 => 'http://foo/private' => 1,
+	    14 => 'http://foo/other' => 1,
+	   ],
+
+	   [$content4, 'MOMspider' =>
+	    15 => 'http://foo/private' => 1,
+	    16 => 'http://foo/this' => 0,
+	    17 => 'http://foo/that' => 1,
+	   ],
+
+	   [$content4, 'Another' =>
+	    18 => 'http://foo/private' => 1,
+	    19 => 'http://foo/this' => 1,
+	    20 => 'http://foo/that' => 0,
+	   ],
+
+	   [$content4, 'Wubble' =>
+	    21 => 'http://foo/private' => 0,
+	    22 => 'http://foo/this' => 1,
+	    23 => 'http://foo/that' => 1,
+	   ],
+
+	   [$content4, 'Another/1.0' =>
+	    24 => 'http://foo/private' => 1,
+	    25 => 'http://foo/this' => 1,
+	    26 => 'http://foo/that' => 0,
+	   ],
+
+	   # when adding tests, remember to increase
+	   # the maximum at the top
+
+	  );
+
+my $t;
+
+for $t (@tests1) {
+    my ($content, $ua) = splice(@$t, 0, 2);
+
+    my $robotsrules = new WWW::RobotRules($ua);
+    $robotsrules->parse('http://foo/robots.txt', $content);
+
+    my ($num, $path, $expected);
+    while(($num, $path, $expected) = splice(@$t, 0, 3)) {
+	my $allowed = $robotsrules->allowed($path);
+	$allowed = 1 if $allowed;
+	if($allowed != $expected) {
+	    $robotsrules->dump;
+	    confess "Test Failed: $ua => $path ($allowed != $expected)";
+	}
+	print "ok $num\n";
+    }
+}
Index: /main/tags/2.25/gsdl/packages/w3mir/libwww-perl-5.36/t/robot/ua.t
===================================================================
--- /main/tags/2.25/gsdl/packages/w3mir/libwww-perl-5.36/t/robot/ua.t	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/w3mir/libwww-perl-5.36/t/robot/ua.t	(revision 21064)
@@ -0,0 +1,135 @@
+$| = 1; # autoflush
+
+require IO::Socket;  # make sure this work before we try to make a HTTP::Daemon
+
+# First we make ourself a daemon in another process
+my $D = shift || '';
+if ($D eq 'daemon') {
+
+    require HTTP::Daemon;
+
+    my $d = new HTTP::Daemon Timeout => 10;
+
+    print "Please to meet you at: <URL:", $d->url, ">\n";
+    open(STDOUT, $^O eq 'MSWin32' ? ">nul" : ">/dev/null");
+
+    while ($c = $d->accept) {
+	$r = $c->get_request;
+	if ($r) {
+	    my $p = ($r->url->path_components)[1];
+	    $p =~ s/\W//g;
+	    my $func = lc("httpd_" . $r->method . "_$p");
+	    #print STDERR "Calling $func...\n";
+            if (defined &$func) {
+		&$func($c, $r);
+	    } else {
+		$c->send_error(404);
+	    }
+	}
+	$c = undef;  # close connection
+    }
+    print STDERR "HTTP Server terminated\n";
+    exit;
+}
+else {
+    use Config;
+    open(DAEMON , "$Config{'perlpath'} robot/ua.t daemon |") or die "Can't exec daemon: $!";
+}
+
+print "1..7\n";
+
+
+$greating = <DAEMON>;
+$greating =~ /(<[^>]+>)/;
+
+require URI::URL;
+URI::URL->import;
+my $base = new URI::URL $1;
+
+print "Will access HTTP server at $base\n";
+
+require LWP::RobotUA;
+require HTTP::Request;
+$ua = new LWP::RobotUA 'lwp-spider/0.1', 'gisle@aas.no';
+$ua->delay(0.05);  # rather quick robot
+
+#----------------------------------------------------------------
+sub httpd_get_robotstxt
+{
+   my($c,$r) = @_;
+   $c->send_basic_header;
+   $c->print("Content-Type: text/plain");
+   $c->send_crlf;
+   $c->send_crlf;
+   $c->print("User-Agent: *
+Disallow: /private
+
+");
+}
+
+sub httpd_get_someplace
+{
+   my($c,$r) = @_;
+   $c->send_basic_header;
+   $c->print("Content-Type: text/plain");
+   $c->send_crlf;
+   $c->send_crlf;
+   $c->print("Okidok\n");
+}
+
+$req = new HTTP::Request GET => url("/someplace", $base);
+$res = $ua->request($req);
+#print $res->as_string;
+print "not " unless $res->is_success;
+print "ok 1\n";
+
+$req = new HTTP::Request GET => url("/private/place", $base);
+$res = $ua->request($req);
+#print $res->as_string;
+print "not " unless $res->code == 403
+                and $res->message =~ /robots.txt/;
+print "ok 2\n";
+
+$req = new HTTP::Request GET => url("/foo", $base);
+$res = $ua->request($req);
+#print $res->as_string;
+print "not " unless $res->code == 404;  # not found
+print "ok 3\n";
+
+# Let the robotua generate "Service unavailable/Retry After response";
+$ua->delay(1);
+$ua->use_sleep(0);
+$req = new HTTP::Request GET => url("/foo", $base);
+$res = $ua->request($req);
+#print $res->as_string;
+print "not " unless $res->code == 503   # Unavailable
+                and $res->header("Retry-After");
+print "ok 4\n";
+
+#----------------------------------------------------------------
+print "Terminating server...\n";
+sub httpd_get_quit
+{
+    my($c) = @_;
+    $c->send_error(503, "Bye, bye");
+    exit;  # terminate HTTP server
+}
+
+$ua->delay(0);
+$req = new HTTP::Request GET => url("/quit", $base);
+$res = $ua->request($req);
+
+print "not " unless $res->code == 503 and $res->content =~ /Bye, bye/;
+print "ok 5\n";
+
+#---------------------------------------------------------------
+$ua->delay(1);
+
+# host_wait() should be around 60s now
+print "not " unless abs($ua->host_wait($base->netloc) - 60) < 5;
+print "ok 6\n";
+
+# Number of visits to this place should be 
+print "not " unless $ua->no_visits($base->netloc) == 4;
+print "ok 7\n";
+
Index: /main/tags/2.25/gsdl/packages/w3mir/libwww-perl-5.36/t/uri/abs-config.t
===================================================================
--- /main/tags/2.25/gsdl/packages/w3mir/libwww-perl-5.36/t/uri/abs-config.t	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/w3mir/libwww-perl-5.36/t/uri/abs-config.t	(revision 21064)
@@ -0,0 +1,35 @@
+print "1..6\n";
+
+use URI::URL qw(url);
+
+# Test configuration via some global variables.
+
+$URI::URL::ABS_REMOTE_LEADING_DOTS = 1;
+$URI::URL::ABS_ALLOW_RELATIVE_SCHEME = 1;
+
+$u1 = url("../../../../abc", "http://web/a/b");
+
+print "not " unless $u1->abs->as_string eq "http://web/abc";
+print "ok 1\n";
+
+{
+    local $URI::URL::ABS_REMOTE_LEADING_DOTS;
+    print "not " unless $u1->abs->as_string eq "http://web/../../../abc";
+    print "ok 2\n";
+}
+
+
+$u1 = url("http:../../../../abc", "http://web/a/b");
+print "not " unless $u1->abs->as_string eq "http://web/abc";
+print "ok 3\n";
+
+{
+   local $URI::URL::ABS_ALLOW_RELATIVE_SCHEME;
+   print "not " unless $u1->abs->as_string eq "http:../../../../abc";
+   print "ok 4\n";
+   print "not " unless $u1->abs(undef,1)->as_string eq "http://web/abc";
+   print "ok 5\n";
+}
+
+print "not " unless $u1->abs(undef,0)->as_string eq "http:../../../../abc";
+print "ok 6\n";
Index: /main/tags/2.25/gsdl/packages/w3mir/libwww-perl-5.36/t/uri/base.t
===================================================================
--- /main/tags/2.25/gsdl/packages/w3mir/libwww-perl-5.36/t/uri/base.t	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/w3mir/libwww-perl-5.36/t/uri/base.t	(revision 21064)
@@ -0,0 +1,955 @@
+#!/local/bin/perl -w
+
+use URI::URL qw(url);
+use URI::Escape qw(uri_escape uri_unescape);
+
+use Carp;
+
+# _expect()
+#
+# Handy low-level object method tester which we insert as a method
+# in the URI::URL class
+#
+sub URI::URL::_expect {
+    my($self, $method, $expect, @args) = @_;
+    my $result = $self->$method(@args);
+    $expect = 'UNDEF' unless defined $expect;
+    $result = 'UNDEF' unless defined $result;
+    return 1 if $expect eq $result;
+    warn "'$self'->$method(@args) = '$result' " .
+		"(expected '$expect')\n";
+    $self->print_on('STDERR');
+    confess "Test Failed";
+}
+
+package main;
+
+# Must ensure that there is no relative paths in @INC because we will
+# chdir in the newlocal tests.
+chomp($pwd = ($^O =~ /mswin32/i ? `cd` : `pwd`));
+for (@INC) {
+    next if m|^/| or $^O =~ /os2|mswin32/i and m|^\w:[\\/]|;
+    print "Turn lib path $_ into $pwd/$_\n";
+    $_ = "$pwd/$_";
+
+}
+
+$| = 1;
+
+print "1..8\n";  # for Test::Harness
+
+# Do basic tests first.
+# Dies if an error has been detected, prints "ok" otherwise.
+
+print "Self tests for URI::URL version $URI::URL::VERSION...\n";
+
+scheme_parse_test();
+print "ok 1\n";
+
+parts_test();
+print "ok 2\n";
+
+escape_test();
+print "ok 3\n";
+
+newlocal_test();
+print "ok 4\n";
+
+absolute_test();
+print "ok 5\n";
+
+eq_test();
+print "ok 6\n";
+
+# Let's test makeing our own things
+URI::URL::strict(0);
+# This should work after URI::URL::strict(0)
+$url = new URI::URL "x-myscheme:something";
+# Since no implementor is registered for 'x-myscheme' then it will
+# be handeled by the URI::URL::_generic class
+$url->_expect('as_string' => 'x-myscheme:something');
+$url->_expect('path' => 'something');
+URI::URL::strict(1);
+
+# Let's try to make our URL subclass
+{
+    package MyURL;
+    @ISA = URI::URL::implementor();
+
+    sub _parse {
+	my($self, $init) = @_;
+	$self->URI::URL::_generic::_parse($init, qw(netloc path));
+    }
+
+    sub foo {
+	my $self = shift;
+	print ref($self)."->foo called for $self\n";
+    }
+}
+# Let's say that it implements the 'x-a+b.c' scheme (alias 'x-foo')
+URI::URL::implementor('x-a+b.c', 'MyURL');
+URI::URL::implementor('x-foo', 'MyURL');
+
+# Now we are ready to try our new URL scheme
+$url = new URI::URL 'x-a+b.c://foo/bar;a?b';
+$url->_expect('as_string', 'x-a+b.c://foo/bar;a?b');
+$url->_expect('path', '/bar;a?b');
+$url->foo;
+$newurl = new URI::URL 'xxx', $url;
+$newurl->foo;
+$url = new URI::URL 'yyy', 'x-foo:';
+$url->foo;
+
+print "ok 7\n";
+
+# Test the new wash&go constructor
+print "not " if url("../foo.html", "http://www.sn.no/a/b")->abs->as_string
+		ne 'http://www.sn.no/foo.html';
+print "ok 8\n";
+
+print "URI::URL version $URI::URL::VERSION ok\n";
+
+exit 0;
+
+
+
+
+#####################################################################
+#
+# scheme_parse_test()
+#
+# test parsing and retrieval methods
+
+sub scheme_parse_test {
+
+    print "scheme_parse_test:\n";
+
+    $tests = {
+	'hTTp://web1.net/a/b/c/welcome#intro'
+	=> {    'scheme'=>'http', 'host'=>'web1.net', 'port'=>80,
+		'path'=>'/a/b/c/welcome', 'frag'=>'intro','query'=>undef,
+		'epath'=>'/a/b/c/welcome', 'equery'=>undef,
+		'params'=>undef, 'eparams'=>undef,
+		'as_string'=>'http://web1.net/a/b/c/welcome#intro',
+		'full_path' => '/a/b/c/welcome' },
+
+	'http://web:1/a?query+text'
+	=> {    'scheme'=>'http', 'host'=>'web', 'port'=>1,
+		'path'=>'/a', 'frag'=>undef, 'query'=>'query+text' },
+
+	'http://web.net/'
+	=> {    'scheme'=>'http', 'host'=>'web.net', 'port'=>80,
+		'path'=>'/', 'frag'=>undef, 'query'=>undef,
+		'full_path' => '/',
+		'as_string' => 'http://web.net/' },
+
+	'http://web.net'
+	=> {    'scheme'=>'http', 'host'=>'web.net', 'port'=>80,
+		'path'=>'/', 'frag'=>undef, 'query'=>undef,
+		'full_path' => '/',
+		'as_string' => 'http://web.net/' },
+
+	'http:0'
+	 => {   'scheme'=>'http', 'path'=>'0', 'query'=>undef,
+		'as_string'=>'http:0', 'full_path'=>'0', },
+
+	'http:/0?0'
+	 => {   'scheme'=>'http', 'path'=>'/0', 'query'=>'0',
+		'as_string'=>'http:/0?0', 'full_path'=>'/0?0', },
+
+	'http://0:0/0/0;0?0#0'
+	 => {   'scheme'=>'http', 'host'=>'0', 'port'=>'0',
+		'path' => '/0/0', 'query'=>'0', 'params'=>'0',
+		'netloc'=>'0:0',
+		'frag'=>0, 'as_string'=>'http://0:0/0/0;0?0#0' },
+
+	'ftp://0%3A:%40@h:0/0?0'
+	=>  {   'scheme'=>'ftp', 'user'=>'0:', 'password'=>'@',
+		'host'=>'h', 'port'=>'0', 'path'=>'/0?0',
+		'query'=>undef, params=>undef,
+		'netloc'=>'0%3A:%40@h:0',
+		'as_string'=>'ftp://0%3A:%40@h:0/0?0' },
+
+	'ftp://usr:pswd@web:1234/a/b;type=i'
+	=> {    'host'=>'web', 'port'=>1234, 'path'=>'/a/b',
+		'user'=>'usr', 'password'=>'pswd',
+		'params'=>'type=i',
+		'as_string'=>'ftp://usr:pswd@web:1234/a/b;type=i' },
+
+	'ftp://host/a/b'
+	=> {    'host'=>'host', 'port'=>21, 'path'=>'/a/b',
+		'user'=>'anonymous',
+		'as_string'=>'ftp://host/a/b' },
+
+	'file://host/fseg/fs?g/fseg'
+	# don't escape ? for file: scheme
+	=> {    'host'=>'host', 'path'=>'/fseg/fs?g/fseg',
+		'as_string'=>'file://host/fseg/fs?g/fseg' },
+
+	'gopher://host'
+	=> {     'gtype'=>'1', 'as_string' => 'gopher://host/', },
+
+	'gopher://host/'
+	=> {     'gtype'=>'1', 'as_string' => 'gopher://host/', },
+
+	'gopher://gopher/2a_selector'
+	=> {    'gtype'=>'2', 'selector'=>'a_selector',
+		'as_string' => 'gopher://gopher/2a_selector', },
+
+	'mailto:libwww-perl@ics.uci.edu'
+	=> {    'address'       => 'libwww-perl@ics.uci.edu',
+		'encoded822addr'=> 'libwww-perl@ics.uci.edu',
+		'user'          => 'libwww-perl',
+		'host'          => 'ics.uci.edu',
+		'as_string'     => 'mailto:libwww-perl@ics.uci.edu', },
+
+	'news:*'
+	=> {    'groupart'=>'*', 'group'=>'*', as_string=>'news:*' },
+	'news:comp.lang.perl'
+	=> {    'group'=>'comp.lang.perl' },
+	'news:perl-faq/module-list-1-794455075@ig.co.uk'
+	=> {    'article'=>
+		    'perl-faq/module-list-1-794455075@ig.co.uk' },
+
+	'nntp://news.com/comp.lang.perl/42'
+	=> {    'group'=>'comp.lang.perl', 'digits'=>42 },
+
+	'telnet://usr:pswd@web:12345/'
+	=> {    'user'=>'usr', 'password'=>'pswd', 'host'=>'web' },
+	'rlogin://aas@a.sn.no'
+	=> {    'user'=>'aas', 'host'=>'a.sn.no' },
+	'tn3270://aas@ibm'
+	=> {    'user'=>'aas', 'host'=>'ibm',
+		'as_string'=>'tn3270://aas@ibm/'},
+
+	'wais://web.net/db'
+	=> { 'database'=>'db' },
+	'wais://web.net/db?query'
+	=> { 'database'=>'db', 'query'=>'query' },
+	'wais://usr:pswd@web.net/db/wt/wp'
+	=> {    'database'=>'db', 'wtype'=>'wt', 'wpath'=>'wp',
+		'password'=>'pswd' },
+    };
+
+    foreach $url_str (sort keys %$tests ){
+	print "Testing '$url_str'\n";
+	my $url = new URI::URL $url_str;
+	my $tests = $tests->{$url_str};
+	while( ($method, $exp) = each %$tests ){
+	    $exp = 'UNDEF' unless defined $exp;
+	    $url->_expect($method, $exp);
+	}
+    }
+}
+
+
+#####################################################################
+#
+# parts_test()          (calls netloc_test test)
+#
+# Test individual component part access functions
+#
+sub parts_test {
+    print "parts_test:\n";
+
+    # test storage part access/edit methods (netloc, user, password,
+    # host and port are tested by &netloc_test)
+
+    $url = new URI::URL 'file://web/orig/path';
+    $url->scheme('http');
+    $url->path('1info');
+    $url->query('key words');
+    $url->frag('this');
+    $url->_expect('as_string' => 'http://web/1info?key%20words#this');
+
+    $url->epath('%2f/%2f');
+    $url->equery('a=%26');
+    $url->_expect('full_path' => '/%2f/%2f?a=%26');
+
+    # At this point it should be impossible to access the members path()
+    # and query() without complaints.
+    eval { my $p = $url->path; print "Path is $p\n"; };
+    die "Path exception failed" unless $@;
+    eval { my $p = $url->query; print "Query is $p\n"; };
+    die "Query exception failed" unless $@;
+
+    # but we should still be able to set it 
+    $url->path("howdy");
+    $url->_expect('as_string' => 'http://web/howdy?a=%26#this');
+
+    # Test the path_components function
+    $url = new URI::URL 'file:%2f/%2f';
+    my $p;
+    $p = join('-', $url->path_components);
+    die "\$url->path_components returns '$p', expected '/-/'"
+      unless $p eq "/-/";
+    $url->host("localhost");
+    $p = join('-', $url->path_components);
+    die "\$url->path_components returns '$p', expected '-/-/'"
+      unless $p eq "-/-/";
+    $url->epath("/foo/bar/");
+    $p = join('-', $url->path_components);
+    die "\$url->path_components returns '$p', expected '-foo-bar-'"
+      unless $p eq "-foo-bar-";
+    $url->path_components("", "/etc", "\0", "..", "øse", "");
+    $url->_expect('full_path' => '/%2Fetc/%00/../%F8se/');
+
+    # Setting undef
+    $url = new URI::URL 'http://web/p;p?q#f';
+    $url->epath(undef);
+    $url->equery(undef);
+    $url->eparams(undef);
+    $url->frag(undef);
+    $url->_expect('as_string' => 'http://web/');
+
+    # Test http query access methods
+    $url->keywords('dog');
+    $url->_expect('as_string' => 'http://web/?dog');
+    $url->keywords(qw(dog bones));
+    $url->_expect('as_string' => 'http://web/?dog+bones');
+    $url->keywords(0,0);
+    $url->_expect('as_string' => 'http://web/?0+0');
+    $url->keywords('dog', 'bones', '#+=');
+    $url->_expect('as_string' => 'http://web/?dog+bones+%23%2B%3D');
+    $a = join(":", $url->keywords);
+    die "\$url->keywords did not work (returned '$a')" unless $a eq 'dog:bones:#+=';
+    # calling query_form is an error
+    eval { my $foo = $url->query_form; };
+    die "\$url->query_form should croak since query contains keywords not a form."
+      unless $@;
+
+    $url->query_form(a => 'foo', b => 'bar');
+    $url->_expect('as_string' => 'http://web/?a=foo&b=bar');
+    my %a = $url->query_form;
+    die "\$url->query_form did not work"
+      unless $a{a} eq 'foo' && $a{b} eq 'bar';
+
+    $url->query_form(a => undef, a => 'foo', '&=' => '&=+');
+    $url->_expect('as_string' => 'http://web/?a=&a=foo&%26%3D=%26%3D%2B');
+
+    my @a = $url->query_form;
+    die "Wrong length" unless @a == 6;
+    die "Bad keys from query_form"
+      unless $a[0] eq 'a' && $a[2] eq 'a' && $a[4] eq '&=';
+    die "Bad values from query_form"
+      unless $a[1] eq '' && $a[3] eq 'foo' && $a[5] eq '&=+';
+
+    # calling keywords is an error
+    eval { my $foo = $url->keywords; };
+    die "\$url->keywords should croak when query is a form"
+      unless $@;
+    # Try this odd one
+    $url->equery('&=&=b&a=&a&a=b=c&&a=b');
+    @a = $url->query_form;
+    #print join(":", @a), "\n";
+    die "Wrong length" unless @a == 16;
+    die "Wrong sequence" unless $a[4]  eq ""  && $a[5]  eq "b" &&
+                                $a[10] eq "a" && $a[11] eq "b=c";
+
+    # Try array ref values in the key value pairs
+    $url->query_form(a => ['foo', 'bar'], b => 'foo', c => ['bar', 'foo']);
+    $url->_expect('as_string', 'http://web/?a=foo&a=bar&b=foo&c=bar&c=foo');
+
+
+    netloc_test();
+    port_test();
+
+    $url->query(undef);
+    $url->_expect('query', undef);
+
+    $url = new URI::URL 'gopher://gopher/';
+    $url->port(33);
+    $url->gtype("3");
+    $url->selector("S");
+    $url->search("query");
+    $url->_expect('as_string', 'gopher://gopher:33/3S%09query');
+
+    $url->epath("45%09a");
+    $url->_expect('gtype' => '4');
+    $url->_expect('selector' => '5');
+    $url->_expect('search' => 'a');
+    $url->_expect('string' => undef);
+    $url->_expect('path' => "/45\ta");
+    $url->path("00\t%09gisle");
+    $url->_expect('search', '%09gisle');
+
+    # Let's test som other URL schemes
+    $url = new URI::URL 'news:';
+    $url->group("comp.lang.perl.misc");
+    $url->_expect('as_string' => 'news:comp.lang.perl.misc');
+    $url->article('<1234@a.sn.no>');
+    $url->_expect('as_string' => 'news:1234@a.sn.no'); # "<" and ">" are gone
+    # This one should be illegal
+    eval { $url->article("no.perl"); };
+    die "This one should really complain" unless $@;
+
+    $url = new URI::URL 'mailto:';
+    $url->user("aas");
+    $url->host("a.sn.no");
+    $url->_expect("as_string" => 'mailto:aas@a.sn.no');
+    $url->address('foo@bar');
+    $url->_expect("host" => 'bar');
+    $url->_expect("user" => 'foo');
+
+    $url = new URI::URL 'wais://host/database/wt/wpath';
+    $url->database('foo');
+    $url->_expect('as_string' => 'wais://host/foo/wt/wpath');
+    $url->wtype('bar');
+    $url->_expect('as_string' => 'wais://host/foo/bar/wpath');
+
+    # Test crack method for various URLs
+    my(@crack, $crack);
+    @crack = URI::URL->new("http://host/path;param?query#frag")->crack;
+    die "Cracked result should be 9 elements" unless @crack == 9;
+    $crack = join("*", map { defined($_) ? $_ : "UNDEF" } @crack);
+    print "Cracked result: $crack\n";
+    die "Bad crack result" unless
+      $crack eq "http*UNDEF*UNDEF*host*80*/path*param*query*frag";
+
+    @crack = URI::URL->new("foo/bar", "ftp://aas\@ftp.sn.no/")->crack;
+    die "Cracked result should be 9 elements" unless @crack == 9;
+    $crack = join("*", map { defined($_) ? $_ : "UNDEF" } @crack);
+    print "Cracked result: $crack\n";
+    die "Bad crack result" unless
+      $crack eq "ftp*UNDEF*UNDEF*UNDEF*21*foo/bar*UNDEF*UNDEF*UNDEF";
+
+    @crack = URI::URL->new('ftp://u:p@host/q?path')->crack;
+    die "Cracked result should be 9 elements" unless @crack == 9;
+    $crack = join("*", map { defined($_) ? $_ : "UNDEF" } @crack);
+    print "Cracked result: $crack\n";
+    die "Bad crack result" unless
+      $crack eq "ftp*u*p*host*21*/q?path*UNDEF*UNDEF*UNDEF";
+
+    @crack = URI::URL->new("ftp://ftp.sn.no/pub")->crack;    # Test anon ftp
+    die "Cracked result should be 9 elements" unless @crack == 9;
+    die "No passwd in anonymous crack" unless $crack[2];
+    $crack[2] = 'passwd';  # easier to test when we know what it is
+    $crack = join("*", map { defined($_) ? $_ : "UNDEF" } @crack);
+    print "Cracked result: $crack\n";
+    die "Bad crack result" unless
+      $crack eq "ftp*anonymous*passwd*ftp.sn.no*21*/pub*UNDEF*UNDEF*UNDEF";
+
+    @crack = URI::URL->new('mailto:aas@sn.no')->crack;
+    die "Cracked result should be 9 elements" unless @crack == 9;
+    $crack = join("*", map { defined($_) ? $_ : "UNDEF" } @crack);
+    print "Cracked result: $crack\n";
+    die "Bad crack result" unless
+      $crack eq "mailto*aas*UNDEF*sn.no*UNDEF*aas\@sn.no*UNDEF*UNDEF*UNDEF";
+
+    @crack = URI::URL->new('news:comp.lang.perl.misc')->crack;
+    die "Cracked result should be 9 elements" unless @crack == 9;
+    $crack = join("*", map { defined($_) ? $_ : "UNDEF" } @crack);
+    print "Cracked result: $crack\n";
+    die "Bad crack result" unless
+      $crack eq "news*UNDEF*UNDEF*UNDEF*UNDEF*comp.lang.perl.misc*UNDEF*UNDEF*UNDEF";
+}
+
+#
+# netloc_test()
+#
+# Test automatic netloc synchronisation
+#
+sub netloc_test {
+    print "netloc_test:\n";
+
+    my $url = new URI::URL 'ftp://anonymous:p%61ss@håst:12345';
+    $url->_expect('user', 'anonymous');
+    $url->_expect('password', 'pass');
+    $url->_expect('host', 'håst');
+    $url->_expect('port', 12345);
+    # Can't really know how netloc is represented since it is partially escaped
+    #$url->_expect('netloc', 'anonymous:pass@hst:12345');
+    $url->_expect('as_string' => 'ftp://anonymous:p%61ss@h%E5st:12345/');
+
+    # The '0' is sometimes tricky to get right
+    $url->user(0);
+    $url->password(0);
+    $url->host(0);
+    $url->port(0);
+    $url->_expect('netloc' => '0:0@0:0');
+    $url->host(undef);
+    $url->_expect('netloc' => '');
+    $url->host('h');
+    $url->user(undef);
+    $url->_expect('netloc' => 'h:0');
+    $url->user('');
+    $url->_expect('netloc' => ':0@h:0');
+    $url->password('');
+    $url->_expect('netloc' => ':@h:0');
+    $url->user('foo');
+    $url->_expect('netloc' => 'foo:@h:0');
+
+    # Let's try a simple one
+    $url->user('nemo');
+    $url->password('p2');
+    $url->host('hst2');
+    $url->port(2);
+    $url->_expect('netloc' => 'nemo:p2@hst2:2');
+
+    $url->user(undef);
+    $url->password(undef);
+    $url->port(undef);
+    $url->_expect('netloc' => 'hst2');
+    $url->_expect('port' => '21');  # the default ftp port
+
+    $url->port(21);
+    $url->_expect('netloc' => 'hst2');
+
+    # Let's try some reserved chars
+    $url->user("@");
+    $url->password(":-#-;-/-?");
+    $url->_expect('as_string' => 'ftp://%40:%3A-%23-%3B-%2F-%3F@hst2/');
+
+}
+
+#
+# port_test()
+#
+# Test port behaviour
+#
+sub port_test {
+    print "port_test:\n";
+
+    $url = URI::URL->new('http://foo/root/dir/');
+    my $port = $url->port;
+    die "Port undefined" unless defined $port;
+    die "Wrong port $port" unless $port == 80;
+    die "Wrong string" unless $url->as_string eq
+	'http://foo/root/dir/';
+
+    $url->port(8001);
+    $port = $url->port;
+    die "Port undefined" unless defined $port;
+    die "Wrong port $port" unless $port == 8001;
+    die "Wrong string" unless $url->as_string eq
+	'http://foo:8001/root/dir/';
+
+    $url->port(80);
+    $port = $url->port;
+    die "Port undefined" unless defined $port;
+    die "Wrong port $port" unless $port == 80;
+    die "Wrong string" unless $url->as_string eq
+	'http://foo/root/dir/';
+
+    $url->port(8001);
+    $url->port(undef);
+    $port = $url->port;
+    die "Port undefined" unless defined $port;
+    die "Wrong port $port" unless $port == 80;
+    die "Wrong string" unless $url->as_string eq
+	'http://foo/root/dir/';
+}
+
+
+#####################################################################
+#
+# escape_test()
+#
+# escaping functions
+
+sub escape_test {
+    print "escape_test:\n";
+
+    # supply escaped URL
+    $url = new URI::URL 'http://web/this%20has%20spaces';
+    # check component is unescaped
+    $url->_expect('path', '/this has spaces');
+
+    # modify the unescaped form
+    $url->path('this ALSO has spaces');
+    # check whole url is escaped
+    $url->_expect('as_string',
+		  'http://web/this%20ALSO%20has%20spaces');
+
+    $url = new URI::URL uri_escape('http://web/try %?#" those');
+    $url->_expect('as_string',
+		  'http://web/try%20%25%3F%23%22%20those');
+
+    my $all = pack('c*',0..255);
+    my $esc = uri_escape($all);
+    my $new = uri_unescape($esc);
+    die "uri_escape->uri_unescape mismatch" unless $all eq $new;
+    $url->path($all);
+    $url->_expect('full_path' => '/%00%01%02%03%04%05%06%07%08%09%0A%0B%0C%0D%0E%0F%10%11%12%13%14%15%16%17%18%19%1A%1B%1C%1D%1E%1F%20!%22%23$%25%26\'()*%2B,-./0123456789%3A%3B%3C%3D%3E%3F%40ABCDEFGHIJKLMNOPQRSTUVWXYZ%5B%5C%5D%5E_%60abcdefghijklmnopqrstuvwxyz%7B%7C%7D~%7F%80%81%82%83%84%85%86%87%88%89%8A%8B%8C%8D%8E%8F%90%91%92%93%94%95%96%97%98%99%9A%9B%9C%9D%9E%9F%A0%A1%A2%A3%A4%A5%A6%A7%A8%A9%AA%AB%AC%AD%AE%AF%B0%B1%B2%B3%B4%B5%B6%B7%B8%B9%BA%BB%BC%BD%BE%BF%C0%C1%C2%C3%C4%C5%C6%C7%C8%C9%CA%CB%CC%CD%CE%CF%D0%D1%D2%D3%D4%D5%D6%D7%D8%D9%DA%DB%DC%DD%DE%DF%E0%E1%E2%E3%E4%E5%E6%E7%E8%E9%EA%EB%EC%ED%EE%EF%F0%F1%F2%F3%F4%F5%F6%F7%F8%F9%FA%FB%FC%FD%FE%FF');
+
+    # test escaping uses uppercase (preferred by rfc1837)
+    $url = new URI::URL 'file://h/';
+    $url->path(chr(0x7F));
+    $url->_expect('as_string', 'file://h/%7F');
+
+    # reserved characters differ per scheme
+
+    ## XXX is this '?' allowed to be unescaped
+    $url = new URI::URL 'file://h/test?ing';
+    $url->_expect('path', '/test?ing');
+
+    $url = new URI::URL 'file://h/';
+    $url->epath('question?mark');
+    $url->_expect('as_string', 'file://h/question?mark');
+    # XXX Why should this be any different???
+    #     Perhaps we should not expect too much :-)
+    $url->path('question?mark');
+    $url->_expect('as_string', 'file://h/question%3Fmark');
+
+    # See what happens when set different elements to this ugly sting
+    my $reserved = ';/?:@&=#%';
+    $url->path($reserved . "foo");
+    $url->_expect('as_string', 'file://h/%3B/%3F%3A%40%26%3D%23%25foo');
+
+    $url->scheme('http');
+    $url->path('');
+    $url->_expect('as_string', 'http://h/');
+    $url->query($reserved);
+    $url->params($reserved);
+    $url->frag($reserved);
+    $url->_expect('as_string', 'http://h/;%3B%2F%3F%3A%40&=%23%25?%3B%2F%3F%3A%40&=%23%25#;/?:@&=#%');
+
+    $str = $url->as_string;
+    $url = new URI::URL $str;
+    die "URL changed" if $str ne $url->as_string;
+
+    $url = new URI::URL 'ftp:foo';
+    $url->user($reserved);
+    $url->host($reserved);
+    $url->_expect('as_string', 'ftp://%3B%2F%3F%3A%40%26%3D%23%25@%3B%2F%3F%3A%40%26%3D%23%25/foo');
+
+}
+
+
+#####################################################################
+#
+# newlocal_test()
+#
+
+sub newlocal_test {
+    print "newlocal_test:\n";
+    my $pwd = ($^O eq 'MSWin32' ? 'cd' : (-e '/bin/pwd' ? '/bin/pwd' : 'pwd'));
+    my $tmpdir = ($^O eq 'MSWin32' ? $ENV{TEMP} : '/tmp');
+    $tmpdir =~ tr|\\|/|;
+
+    my $savedir = `$pwd`;     # we don't use Cwd.pm because we want to check
+			      # that it get require'd corretly by URL.pm
+    chomp $savedir;
+
+    # cwd
+    chdir($tmpdir) or die $!;
+    my $dir = `$pwd`; $dir =~ tr|\\|/|;
+    chomp $dir; $dir = uri_escape($dir, ':');
+    $url = newlocal URI::URL;
+    $url->_expect('as_string', URI::URL->new("file:$dir/")->as_string);
+
+    print "Local directory is ". $url->local_path . "\n";
+
+    # absolute dir
+    chdir('/') or die $!;
+    $url = newlocal URI::URL '/usr/';
+    $url->_expect('as_string', 'file:/usr/');
+
+    # absolute file
+    $url = newlocal URI::URL '/vmunix';
+    $url->_expect('as_string', 'file:/vmunix');
+
+    # relative file
+    chdir($tmpdir) or die $!;
+    $dir = `$pwd`; $dir =~ tr|\\|/|;
+    chomp $dir; $dir = uri_escape($dir, ':');
+    $url = newlocal URI::URL 'foo';
+    $url->_expect('as_string', "file:$dir/foo");
+
+    # relative dir
+    chdir($tmpdir) or die $!;
+    $dir = `$pwd`; $dir =~ tr|\\|/|;
+    chomp $dir; $dir = uri_escape($dir, ':');
+    $url = newlocal URI::URL 'bar/';
+    $url->_expect('as_string', "file:$dir/bar/");
+
+    # 0
+    chdir('/') or die $!;
+    $dir = `$pwd`; $dir =~ tr|\\|/|;
+    chomp $dir; $dir = uri_escape($dir, ':');
+    $url = newlocal URI::URL '0';
+    $url->_expect('as_string', "file:${dir}0");
+
+    # Test access methods for file URLs
+    $url = new URI::URL 'file:/c:/dos';
+    $url->_expect('dos_path', 'C:\\DOS');
+    $url->_expect('unix_path', '/c:/dos');
+    $url->_expect('vms_path', '[C:]DOS');
+    eval { $url->mac_path; };  # This is not allowed since we have ':' in path
+    die "Mac_path generated when it should fail." unless $@;
+    $url = new URI::URL 'file:/foo/bar';
+    $url->_expect('unix_path', '/foo/bar');
+    $url->_expect('mac_path', 'foo:bar');
+
+    # Some edge cases
+    $url = new URI::URL 'file:';
+    $url->_expect('unix_path', '/');
+    $url = new URI::URL 'file:/';
+    $url->_expect('unix_path', '/');
+    $url = new URI::URL 'file:.';
+    $url->_expect('unix_path', '.');
+    $url = new URI::URL 'file:./foo';
+    $url->_expect('unix_path', 'foo');
+    $url = new URI::URL 'file:0';
+    $url->_expect('unix_path', '0');
+    $url = new URI::URL 'file:../../foo';
+    $url->_expect('unix_path', '../../foo');
+    $url = new URI::URL 'file:foo/../bar';
+    $url->_expect('unix_path', 'bar');
+
+    # Relative files
+    $url = new URI::URL 'file:foo/b%61r/Note.txt';
+    $url->_expect('unix_path', 'foo/bar/Note.txt');
+    $url->_expect('mac_path', ':foo:bar:Note.txt');
+    $url->_expect('dos_path', 'FOO\\BAR\\NOTE.TXT');
+    $url->_expect('vms_path', '[.FOO.BAR]NOTE.TXT');
+
+    # The VMS path found in RFC 1738 (section 3.10)
+    $url = new URI::URL 'file://vms.host.edu/disk$user/my/notes/note12345.txt';
+    $url->_expect('vms_path', 'DISK$USER:[MY.NOTES]NOTE12345.TXT');
+    $url->_expect('mac_path', 'disk$user:my:notes:note12345.txt');
+
+    chdir($savedir) or die $!;
+}
+
+
+#####################################################################
+#
+# absolute_test()
+#
+sub absolute_test {
+
+    print "Test relative/absolute URI::URL parsing:\n";
+
+    # Tests from draft-ietf-uri-relative-url-06.txt
+    # Copied verbatim from the draft, parsed below
+
+    @URI::URL::g::ISA = qw(URI::URL::_generic); # for these tests
+
+    my $base = 'http://a/b/c/d;p?q#f';
+
+    $absolute_tests = <<EOM;
+5.1.  Normal Examples
+
+      g:h        = <URL:g:h>
+      g          = <URL:http://a/b/c/g>
+      ./g        = <URL:http://a/b/c/g>
+      g/         = <URL:http://a/b/c/g/>
+      /g         = <URL:http://a/g>
+      //g        = <URL:http://g>
+      ?y         = <URL:http://a/b/c/d;p?y>
+      g?y        = <URL:http://a/b/c/g?y>
+      g?y/./x    = <URL:http://a/b/c/g?y/./x>
+      #s         = <URL:http://a/b/c/d;p?q#s>
+      g#s        = <URL:http://a/b/c/g#s>
+      g#s/./x    = <URL:http://a/b/c/g#s/./x>
+      g?y#s      = <URL:http://a/b/c/g?y#s>
+      ;x         = <URL:http://a/b/c/d;x>
+      g;x        = <URL:http://a/b/c/g;x>
+      g;x?y#s    = <URL:http://a/b/c/g;x?y#s>
+      .          = <URL:http://a/b/c/>
+      ./         = <URL:http://a/b/c/>
+      ..         = <URL:http://a/b/>
+      ../        = <URL:http://a/b/>
+      ../g       = <URL:http://a/b/g>
+      ../..      = <URL:http://a/>
+      ../../     = <URL:http://a/>
+      ../../g    = <URL:http://a/g>
+
+5.2.  Abnormal Examples
+
+   Although the following abnormal examples are unlikely to occur
+   in normal practice, all URL parsers should be capable of resolving
+   them consistently.  Each example uses the same base as above.
+
+   An empty reference resolves to the complete base URL:
+
+      <>         = <URL:http://a/b/c/d;p?q#f>
+
+   Parsers must be careful in handling the case where there are more
+   relative path ".." segments than there are hierarchical levels in
+   the base URL's path.  Note that the ".." syntax cannot be used to
+   change the <net_loc> of a URL.
+
+     ../../../g = <URL:http://a/../g>
+     ../../../../g = <URL:http://a/../../g>
+
+   Similarly, parsers must avoid treating "." and ".." as special
+   when they are not complete components of a relative path.
+
+      /./g       = <URL:http://a/./g>
+      /../g      = <URL:http://a/../g>
+      g.         = <URL:http://a/b/c/g.>
+      .g         = <URL:http://a/b/c/.g>
+      g..        = <URL:http://a/b/c/g..>
+      ..g        = <URL:http://a/b/c/..g>
+
+   Less likely are cases where the relative URL uses unnecessary or
+   nonsensical forms of the "." and ".." complete path segments.
+
+      ./../g     = <URL:http://a/b/g>
+      ./g/.      = <URL:http://a/b/c/g/>
+      g/./h      = <URL:http://a/b/c/g/h>
+      g/../h     = <URL:http://a/b/c/h>
+
+   Finally, some older parsers allow the scheme name to be present in
+   a relative URL if it is the same as the base URL scheme.  This is
+   considered to be a loophole in prior specifications of partial
+   URLs [1] and should be avoided by future parsers.
+
+      http:g     = <URL:http:g>
+      http:      = <URL:http:>
+EOM
+    # convert text to list like
+    # @absolute_tests = ( ['g:h' => 'g:h'], ...)
+
+    for $line (split("\n", $absolute_tests)) {
+	next unless $line =~ /^\s{6}/;
+	if ($line =~ /^\s+(\S+)\s*=\s*<URL:([^>]*)>/) {
+	    my($rel, $abs) = ($1, $2);
+	    $rel = '' if $rel eq '<>';
+	    push(@absolute_tests, [$rel, $abs]);
+	}
+	else {
+	    warn "illegal line '$line'";
+	}
+    }
+
+    # add some extra ones for good measure
+
+    push(@absolute_tests, ['x/y//../z' => 'http://a/b/c/x/y/z'],
+			  ['1'         => 'http://a/b/c/1'    ],
+			  ['0'         => 'http://a/b/c/0'    ],
+			  ['/0'        => 'http://a/0'        ],
+			  ['%2e/a'     => 'http://a/b/c/%2e/a'],  # %2e is '.'
+			  ['%2e%2e/a'  => 'http://a/b/c/%2e%2e/a'],
+	);
+
+    print "  Relative    +  Base  =>  Expected Absolute URL\n";
+    print "================================================\n";
+    for $test (@absolute_tests) {
+	my($rel, $abs) = @$test;
+	my $abs_url = new URI::URL $abs;
+	my $abs_str = $abs_url->as_string;
+
+	printf("  %-10s  +  $base  =>  %s\n", $rel, $abs);
+	my $u   = new URI::URL $rel, $base;
+	my $got = $u->abs;
+	$got->_expect('as_string', $abs_str);
+    }
+
+    # bug found and fixed in 1.9 by "J.E. Fritz" <FRITZ@gems.vcu.edu>
+    $base = new URI::URL 'http://host/directory/file';
+    my $relative = new URI::URL 'file', $base;
+    my $result = $relative->abs;
+
+    my ($a, $b) = ($base->path, $result->path);
+	die "'$a' and '$b' should be the same" unless $a eq $b;
+
+    # Counter the expectation of least surprise,
+    # section 6 of the draft says the URL should
+    # be canonicalised, rather than making a simple
+    # substitution of the last component.
+    # Better doublecheck someone hasn't "fixed this bug" :-)
+    $base = new URI::URL 'http://host/dir1/../dir2/file';
+    $relative = new URI::URL 'file', $base;
+    $result = $relative->abs;
+    die 'URL not canonicalised' unless $result eq 'http://host/dir2/file';
+
+    print "--------\n";
+    # Test various other kinds of URLs and how they like to be absolutized
+    for (["http://abc/", "news:45664545", "http://abc/"],
+	 ["news:abc",    "http://abc/",   "news:abc"],
+	 ["abc",         "file:/test?aas", "file:/abc"],
+	 ["gopher:",     "",               "gopher:"],
+	 ["?foo",        "http://abc/a",   "http://abc/a?foo"],
+	 ["?foo",        "file:/abc",      "file:/?foo"],
+	 ["#foo",        "http://abc/a",   "http://abc/a#foo"],
+	 ["#foo",        "file:a",         "file:a#foo"],
+	 ["#foo",        "file:/a",         "file:/a#foo"],
+	 ["#foo",        "file:/a",         "file:/a#foo"],
+	 ["#foo",        "file://localhost/a", "file://localhost/a#foo"],
+	 ['123@sn.no',   "news:comp.lang.perl.misc", 'news:123@sn.no'],
+	 ['no.perl',     'news:123@sn.no',           'news:no.perl'],
+	 ['mailto:aas@a.sn.no', "http://www.sn.no/", 'mailto:aas@a.sn.no'],
+
+	 # Test absolutizing with old behaviour.
+	 ['http:foo',     'http://h/a/b',   'http://h/a/foo'],
+	 ['http:/foo',    'http://h/a/b',   'http://h/foo'],
+	 ['http:?foo',    'http://h/a/b',   'http://h/a/b?foo'],
+	 ['http:#foo',    'http://h/a/b',   'http://h/a/b#foo'],
+	 ['http:?foo#bar','http://h/a/b',   'http://h/a/b?foo#bar'],
+	 ['file:/foo',    'http://h/a/b',   'file:/foo'],
+
+	)
+    {
+	my($url, $base, $expected_abs) = @$_;
+	my $rel = new URI::URL $url, $base;
+	my $abs = $rel->abs($base, 1);
+	printf("  %-12s+  $base  =>  %s\n", $rel, $abs);
+	$abs->_expect('as_string', $expected_abs);
+    }
+    print "absolute test ok\n";
+
+    # Test relative function
+    for (
+	 ["http://abc/a",   "http://abc",        "a"],
+	 ["http://abc/a",   "http://abc/b",      "a"],
+	 ["http://abc/a?q", "http://abc/b",      "a?q"],
+	 ["http://abc/a;p", "http://abc/b",      "a;p"],
+	 ["http://abc/a",   "http://abc/a/b/c/", "../../../a"],
+         ["http://abc/a/",  "http://abc/a/",     "./"],
+         ["http://abc/a#f", "http://abc/a",      "#f"],
+
+	 ["file:/etc/motd", "file:/",            "etc/motd"],
+	 ["file:/etc/motd", "file:/etc/passwd",  "motd"],
+	 ["file:/etc/motd", "file:/etc/rc2.d/",  "../motd"],
+	 ["file:/etc/motd", "file:/usr/lib/doc", "../../etc/motd"],
+         ["file:",          "file:/etc/",        "../"],
+         ["file:foo",       "file:/etc/",        "../foo"],
+
+	 ["mailto:aas",     "http://abc",        "mailto:aas"],
+
+	 # Nicolai Langfeldt's original example
+	 ["http://www.math.uio.no/doc/mail/top.html",
+	  "http://www.math.uio.no/doc/linux/", "../mail/top.html"],
+        )
+    {
+	my($abs, $base, $expect) = @$_;
+	printf "url('$abs', '$base')->rel eq '$expect'\n";
+	my $rel = URI::URL->new($abs, $base)->rel;
+	$rel->_expect('as_string', $expect);
+    }
+    print "relative test ok\n";
+}
+
+
+sub eq_test
+{
+    my $u1 = new URI::URL 'http://abc.com:80/~smith/home.html';
+    my $u2 = new URI::URL 'http://ABC.com/%7Esmith/home.html';
+    my $u3 = new URI::URL 'http://ABC.com:/%7esmith/home.html';
+
+    # Test all permutations of these tree
+    $u1->eq($u2) or die "1: $u1 ne $u2";
+    $u1->eq($u3) or die "2: $u1 ne $u3";
+    $u2->eq($u1) or die "3: $u2 ne $u1";
+    $u2->eq($u3) or die "4: $u2 ne $u3";
+    $u3->eq($u1) or die "5: $u3 ne $u1";
+    $u3->eq($u2) or die "6: $u3 ne $u2";
+
+    # Test empty path
+    my $u4 = new URI::URL 'http://www.sn.no';
+    $u4->eq("HTTP://WWW.SN.NO:80/") or die "7: $u4";
+    $u4->eq("http://www.sn.no:81") and die "8: $u4";
+
+    # Test mailto
+    my $u5 = new URI::URL 'mailto:AAS@SN.no';
+    $u5->eq('mailto:aas@sn.no') or die "9: $u5";
+
+    # Test reserved char
+    my $u6 = new URI::URL 'ftp://ftp/%2Fetc';
+    $u6->eq("ftp://ftp/%2fetc") or die "10: $u6";
+    $u6->eq("ftp://ftp://etc") and die "11: $u6";
+}
+
Index: /main/tags/2.25/gsdl/packages/w3mir/libwww-perl-5.36/t/uri/heuristic.t
===================================================================
--- /main/tags/2.25/gsdl/packages/w3mir/libwww-perl-5.36/t/uri/heuristic.t	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/w3mir/libwww-perl-5.36/t/uri/heuristic.t	(revision 21064)
@@ -0,0 +1,61 @@
+print "1..14\n";
+
+use URI::Heuristic qw(uf_urlstr uf_url);
+$URI::Heuristic::DEBUG++;
+open(STDERR, ">&STDOUT");  # redirect STDERR
+
+print "not " unless uf_urlstr("http://www.sn.no/") eq "http://www.sn.no/";
+print "ok 1\n";
+
+print "not " unless uf_urlstr("/etc/passwd") eq "file:/etc/passwd";
+print "ok 2\n";
+
+print "not " unless uf_urlstr("./foo.txt") eq "file:./foo.txt";
+print "ok 3\n";
+
+print "not " unless uf_urlstr("ftp.aas.no/lwp.tar.gz") eq "ftp://ftp.aas.no/lwp.tar.gz";
+print "ok 4\n";
+
+print "not " unless uf_urlstr("C:\\CONFIG.SYS") eq "file:C:\\CONFIG.SYS";
+print "ok 5\n";
+
+if (gethostbyname("www.netscape.com")) {
+    # DNS probably work, lets run test 6..8
+
+    $URI::Heuristic::MY_COUNTRY = "no";
+    print "not " unless uf_urlstr("perl/camel.gif") eq "http://www.perl.com/camel.gif";
+    print "ok 6\n";
+
+    $URI::Heuristic::MY_COUNTRY = "uk";
+    print "not " unless uf_urlstr("perl/camel.gif") eq "http://www.perl.co.uk/camel.gif";
+    print "ok 7\n";
+   
+    $ENV{URL_GUESS_PATTERN} = "www.ACME.org www.ACME.com";
+    print "not " unless uf_urlstr("perl") eq "http://www.perl.org";
+    print "ok 8\n";
+
+} else {
+    # don't make the inocent worry
+    print "Skipping test 6-8 because DNS does not work\n";
+    for (6..8) { print "ok $_\n"; }
+
+}
+
+$ENV{URL_GUESS_PATTERN} = "";
+print "not " unless uf_urlstr("perl") eq "http://perl";
+print "ok 9\n";
+
+print "not " unless uf_urlstr("http:80") eq "http:80";
+print "ok 10\n";
+
+print "not " unless uf_urlstr("mailto:gisle\@aas.no") eq "mailto:gisle\@aas.no";
+print "ok 11\n";
+
+print "not " unless uf_urlstr("gisle\@aas.no") eq "mailto:gisle\@aas.no";
+print "ok 12\n";
+
+print "not " unless uf_urlstr("Gisle.Aas\@aas.perl.org") eq "mailto:Gisle.Aas\@aas.perl.org";
+print "ok 13\n";
+
+print "not " unless uf_url("gopher.sn.no")->scheme eq "gopher";
+print "ok 14\n";
Index: /main/tags/2.25/gsdl/packages/w3mir/libwww-perl-5.36/t/uri/rel-base.t
===================================================================
--- /main/tags/2.25/gsdl/packages/w3mir/libwww-perl-5.36/t/uri/rel-base.t	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/w3mir/libwww-perl-5.36/t/uri/rel-base.t	(revision 21064)
@@ -0,0 +1,24 @@
+print "1..3\n";
+
+use URI::URL;
+
+# We used to have problems with URLs that used a base that was
+# not absolute itself.
+
+$u1 = url("/foo/bar", "http://www.acme.com/");
+$u2 = url("../foo/", $u1);
+$u3 = url("zoo/foo", $u2);
+
+$a1 = $u1->abs->as_string;
+$a2 = $u2->abs->as_string;
+$a3 = $u3->abs->as_string;
+
+print "$a1\n$a2\n$a3\n";
+
+print "not " unless $a1 eq "http://www.acme.com/foo/bar";
+print "ok 1\n";
+print "not " unless $a2 eq "http://www.acme.com/foo/";
+print "ok 2\n";
+print "not " unless $a3 eq "http://www.acme.com/foo/zoo/foo";
+print "ok 3\n";
+
Index: /main/tags/2.25/gsdl/packages/w3mir/w3mir-1.0.8/Artistic
===================================================================
--- /main/tags/2.25/gsdl/packages/w3mir/w3mir-1.0.8/Artistic	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/w3mir/w3mir-1.0.8/Artistic	(revision 21064)
@@ -0,0 +1,131 @@
+
+
+
+
+			 The "Artistic License"
+
+				Preamble
+
+The intent of this document is to state the conditions under which a
+Package may be copied, such that the Copyright Holder maintains some
+semblance of artistic control over the development of the package,
+while giving the users of the package the right to use and distribute
+the Package in a more-or-less customary fashion, plus the right to make
+reasonable modifications.
+
+Definitions:
+
+	"Package" refers to the collection of files distributed by the
+	Copyright Holder, and derivatives of that collection of files
+	created through textual modification.
+
+	"Standard Version" refers to such a Package if it has not been
+	modified, or has been modified in accordance with the wishes
+	of the Copyright Holder as specified below.
+
+	"Copyright Holder" is whoever is named in the copyright or
+	copyrights for the package.
+
+	"You" is you, if you're thinking about copying or distributing
+	this Package.
+
+	"Reasonable copying fee" is whatever you can justify on the
+	basis of media cost, duplication charges, time of people involved,
+	and so on.  (You will not be required to justify it to the
+	Copyright Holder, but only to the computing community at large
+	as a market that must bear the fee.)
+
+	"Freely Available" means that no fee is charged for the item
+	itself, though there may be fees involved in handling the item.
+	It also means that recipients of the item may redistribute it
+	under the same conditions they received it.
+
+1. You may make and give away verbatim copies of the source form of the
+Standard Version of this Package without restriction, provided that you
+duplicate all of the original copyright notices and associated disclaimers.
+
+2. You may apply bug fixes, portability fixes and other modifications
+derived from the Public Domain or from the Copyright Holder.  A Package
+modified in such a way shall still be considered the Standard Version.
+
+3. You may otherwise modify your copy of this Package in any way, provided
+that you insert a prominent notice in each changed file stating how and
+when you changed that file, and provided that you do at least ONE of the
+following:
+
+    a) place your modifications in the Public Domain or otherwise make them
+    Freely Available, such as by posting said modifications to Usenet or
+    an equivalent medium, or placing the modifications on a major archive
+    site such as uunet.uu.net, or by allowing the Copyright Holder to include
+    your modifications in the Standard Version of the Package.
+
+    b) use the modified Package only within your corporation or organization.
+
+    c) rename any non-standard executables so the names do not conflict
+    with standard executables, which must also be provided, and provide
+    a separate manual page for each non-standard executable that clearly
+    documents how it differs from the Standard Version.
+
+    d) make other distribution arrangements with the Copyright Holder.
+
+4. You may distribute the programs of this Package in object code or
+executable form, provided that you do at least ONE of the following:
+
+    a) distribute a Standard Version of the executables and library files,
+    together with instructions (in the manual page or equivalent) on where
+    to get the Standard Version.
+
+    b) accompany the distribution with the machine-readable source of
+    the Package with your modifications.
+
+    c) give non-standard executables non-standard names, and clearly
+    document the differences in manual pages (or equivalent), together
+    with instructions on where to get the Standard Version.
+
+    d) make other distribution arrangements with the Copyright Holder.
+
+5. You may charge a reasonable copying fee for any distribution of this
+Package.  You may charge any fee you choose for support of this
+Package.  You may not charge a fee for this Package itself.  However,
+you may distribute this Package in aggregate with other (possibly
+commercial) programs as part of a larger (possibly commercial) software
+distribution provided that you do not advertise this Package as a
+product of your own.  You may embed this Package's interpreter within
+an executable of yours (by linking); this shall be construed as a mere
+form of aggregation, provided that the complete Standard Version of the
+interpreter is so embedded.
+
+6. The scripts and library files supplied as input to or produced as
+output from the programs of this Package do not automatically fall
+under the copyright of this Package, but belong to whomever generated
+them, and may be sold commercially, and may be aggregated with this
+Package.  If such scripts or library files are aggregated with this
+Package via the so-called "undump" or "unexec" methods of producing a
+binary executable image, then distribution of such an image shall
+neither be construed as a distribution of this Package nor shall it
+fall under the restrictions of Paragraphs 3 and 4, provided that you do
+not represent such an executable image as a Standard Version of this
+Package.
+
+7. C subroutines (or comparably compiled subroutines in other
+languages) supplied by you and linked into this Package in order to
+emulate subroutines and variables of the language defined by this
+Package shall not be considered part of this Package, but are the
+equivalent of input as in Paragraph 6, provided these subroutines do
+not change the language in any way that would cause it to fail the
+regression tests for the language.
+
+8. Aggregation of this Package with a commercial distribution is always
+permitted provided that the use of this Package is embedded; that is,
+when no overt attempt is made to make this Package's interfaces visible
+to the end user of the commercial distribution.  Such use shall not be
+construed as a distribution of this Package.
+
+9. The name of the Copyright Holder may not be used to endorse or promote
+products derived from this software without specific prior written permission.
+
+10. THIS PACKAGE IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR
+IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+
+				The End
Index: /main/tags/2.25/gsdl/packages/w3mir/w3mir-1.0.8/Changes
===================================================================
--- /main/tags/2.25/gsdl/packages/w3mir/w3mir-1.0.8/Changes	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/w3mir/w3mir-1.0.8/Changes	(revision 21064)
@@ -0,0 +1,51 @@
+Fixes in 1.0.6:
+- -f works with binary files
+- w3mir will no longer use 'Referer: (commandline)' when a URL is derived
+  from the commandline/config file.
+- More errormessage fixes
+- Fixed install instructions to warn against LWP 5.40.
+
+Fixes in 1.0.5: 
+- Better error-messaged in -quiet mode 
+- Fixed quoting. Both " and ' quotes in documents are accepted. 
+- Fixed timeout handling. 
+- Fixed broken connection handling. Incomplete documents are 
+  deleted and retried.
+- Fixed URL mangling problem. In 1.0.3 URLs like ``foo.html#bar'' would
+  be rewritten to ``#bar''. This is quite bad and makes a lot of mirrors
+  un-useable. 
+- -v now prints LWPs version as well as w3mirs version
+
+Features/bugs in 1.0.5 
+- As earlier, w3mir does not support cookies. I have received a patch for
+  basic cookie support but have not yet incorporated it due to
+  time-restraints.
+- There actually exists web servers that break the HTTP standard rather
+  thoroughly by not sending a Content-type header (this is mandatory in
+  the standard). W3mir will not discover that a HTML file is HTML in this
+  case and will not extract URLs from it.
+- If you rewrite the ending filename URLs with Apply rules (as in 
+  index.htm -> index.html) and there are links to index.htm#foo the link
+  will be incorrect after mirroring. The solution is to avoid those
+  kinds of rules. This was meant to be fixed in 1.0.3 (which broke it as
+  described above), I will fix it when I get more time. The fix is to
+  remove the #fragment part of URLs when they pass thru the apply
+  machinery. Patches accepted. 
+
+Fixes in 1.0.3: 
+- The -R/remove option to remove files is no longer more destructive
+  than intended.
+- Files with 'unsafe' characters in their filename is now saved as
+  "foo bar" instead of "foo%20bar" 
+- The -B switch works once again. 
+
+Fixes in 1.0.2: 
+- W3mir now only newline converts HTML files, all other files are handled
+  as binary. This should ensure file-integrety even when working with
+   mis-configured servers. 
+
+Fixes in 1.0.1: 
+-fa option and corresponding configuration file directive works again. 
+- Added -nnc option and a corresponding configuration file directive. It
+  disables newline conversions, which could corrupt files the Webserver
+  mis-declares. The HOWTO explains the uses of -nnc 
Index: /main/tags/2.25/gsdl/packages/w3mir/w3mir-1.0.8/INSTALL
===================================================================
--- /main/tags/2.25/gsdl/packages/w3mir/w3mir-1.0.8/INSTALL	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/w3mir/w3mir-1.0.8/INSTALL	(revision 21064)
@@ -0,0 +1,117 @@
+This is how you install w3mir on a Unix system. Please see the file
+INSTALL.w32 for install instructions for win32 systems.
+
+INSTALLING PREREQUISITES:
+
+The prerequisites are the perl packages libwww-perl, and MIME-Base64.
+The w3mir install procedure will check for their presence and complain
+if they are not there, so if you are unsure what you have you might
+skip this part for now.
+
+- Get libwww-perl from CPAN 
+  (http://www.perl.com/CPAN/modules/by-module/WWW/).  W3mir does not work
+  with LWP 5.40 and later versions.  Please get an earlier version.
+  It also does not work with the new URI package.  Use the URI package
+  enclosed in the older LWP.
+
+- Unpack it:
+
+    gzip -dc libwww-perl-*.tar.gz | tar xvBf -
+
+- Install it.  W3mir does not require the whole libwww-perl package and
+  all the packages that goes with it to work so you may follow these
+  install instructions instead of the libwww-perl install instructions
+  to get an easier install which will work with w3mir.
+
+    cd libwww-perl-*
+
+  Are you going to install it in the standard perl place (you need to
+  be the system administrator to do this)? If so:
+
+    perl Makefile.PL
+
+  If not (if you are a user):
+
+    perl Makefile.PL PREFIX=/some/dir
+
+  /some/dir could be ~ (as in your home directory).
+
+  IF you are installing an old LWP just for w3mir you can install both
+  the old LWP, the Base64 module and w3mir in a special PREFIX
+  separate from your usual install PREFIX.  This ensures that w3mir will
+  access the older version of LWP and that other software will access
+  the newer version.  If you do this make sure you install all of LWP,
+  Base64 and w3mir with the same PREFIX.
+
+  This step might produce some complaints;  A standard perl
+  installation will typically get messages about missing these
+  modules: IO::Socket, NET::FTP and MD5.  None of these need be
+  installed to run w3mir and so any error messages about these may
+  safely be ignored.
+
+    make
+    make test      (robot/ua and local/http might fail, that's OK)
+    make install
+
+  Now libwww-perl should be installed and working.
+
+- You also have to get the MIME-Base64 package
+  (http://www.perl.com/CPAN/modules/by-module/MIME/)
+
+- Unpack it:
+
+    gzip -dc MIME-Base64-*.tar.gz | tar xvBf -
+
+- Install it:
+
+    cd MIME-Base64-*
+
+  Then, as above, either
+
+    perl Makefile.PL
+
+  or
+
+    perl Makefile.PL PREFIX=/some/dir
+
+  Continue:
+
+    make
+    make test      (it should print 'All tests successful.')
+    make install
+
+  Now MIME-Base64 should be installed and working.
+
+INSTALLING W3MIR:
+
+- Get w3mir (http://www.math.uio.no/~janl/w3mir/ or from CPAN)
+
+- Unpack it:
+
+     gzip -dc w3mir-*.tar.gz | tar xvBf -
+
+- Install it:
+
+     cd w3mir-*
+
+  Are you going to install it in the standard perl place? (You
+  probably need to be the system administrator to do this.)  If so:
+
+    perl Makefile.PL
+
+  If not (if you're a user):
+
+    perl Makefile.PL PREFIX=/some/dir
+
+  /some/dir could be ~ (as in your home directory).
+
+  then
+
+     make
+     make install
+
+w3mir should now be installed correctly.  And if it's installed in
+your path you can even run it.  If you use csh or tcsh you want to run
+'rehash' before the shell will find it.
+
+1999/04/14 - Nicolai Langfeldt
Index: /main/tags/2.25/gsdl/packages/w3mir/w3mir-1.0.8/INSTALL.w32
===================================================================
--- /main/tags/2.25/gsdl/packages/w3mir/w3mir-1.0.8/INSTALL.w32	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/w3mir/w3mir-1.0.8/INSTALL.w32	(revision 21064)
@@ -0,0 +1,92 @@
+This file contains installation instructions for two different ports
+of Perl to win32.  One port is known as the 'ActivePerl' port, the
+other is known as 'the GS port'.
+
+********************************* ActivePerl **********************************
+
+This was written and submitted by Roland Bauer.  Thanks.  I have
+edited them slightly.
+
+How to install w3mir on Win95/AS-port (April 1999):
+===================================================
+
++ get and install winzip from http://www.winzip.com/
++ get and install ActivePerl (now Build 509) from http://www.activestate.com/
++ get nmake.exe from 
+  ftp://ftp.microsoft.com/Softlib/MSLFILES/nmake15.exe
+  (or set switch make=nmake to make=dmake in Config.pm
+  and get dmake from GS port)
+
++ perl makefile.pl
++ nmake
++ nmake install
+
++ perl w3mir -h
++ perl w3mir http://xx.zz.zz/dir/
+
+
+Caveats:
+========
+
++ archive 1.0.6 from CPAN seems to be corrupted
+
++ &mkdir does not seem to work with dos-paths
+like 'D:/DIR1/DIR2'
+(so it is not possible to save to another harddisk)
+
+*********************************** GS Perl ***********************************
+
+These win32 installation instructions were written by Paul Hsiao and
+slightly edited by me. My thanks to Paul. It was current as of
+22-May-1998.
+
+
+WINZIP DOWNLOAD INSTRUCTIONS
+
+    The WinZip program can be accessed from the "Start" button, if the
+    program came with your system.  This software can be obtained from:
+ 
+                http://www.winzip.com/
+ 
+    Follow the installation instructions for the WinZip software as needed.
+
+ 
+PERL DOWNLOAD INSTRUCTIONS
+ 
+    The w3mir code will need access to version 5.003 or higher of the 
+    Perl interpreter and LWP library extensions in order for it to run. 
+    This software can be obtained from:
+ 
+                ftp://sunsite.uio.no/pub/languages/perl/CPAN/ports/win32/Standard
+ 
+    From this URL, select perl5.00402-bindist04-bc.tar.gz and download
+    to your PC into a folder of your choice.  In the folder, run WinZip
+    on this file.  For MS Windows 95, you need to update the registration: 
+    open C:\autoexec.bat  and add a line
+
+                path %path%;C:\Perl\bin;       
+    (C:\Perl\ is the path of the perl folder)  
+
+
+W3MIR DOWNLOAD AND INSTALLATION INSTRUCTIONS
+
+    You already have w3mir. Right? Unpack the .tar.gz file with
+    winzip.
+ 
+    Open a DOS prompt screen and go to the w3mir folder:
+ 
+        cd C:\w3mir-1.0.3
+ 
+    Type the install command for w3mir:
+ 
+        perl.exe Makefile.PL
+        make
+        make install
+ 
+    To test w3mir, type:
+ 
+    perl w3mir -h
+ 
+    If the screen displays all options (about 25 options), then 
+    w3mir is installed correctly.
+
Index: /main/tags/2.25/gsdl/packages/w3mir/w3mir-1.0.8/MANIFEST
===================================================================
--- /main/tags/2.25/gsdl/packages/w3mir/w3mir-1.0.8/MANIFEST	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/w3mir/w3mir-1.0.8/MANIFEST	(revision 21064)
@@ -0,0 +1,15 @@
+Artistic
+Changes
+INSTALL
+INSTALL.w32
+MANIFEST
+Makefile.PL
+README
+example.cfg
+multiscope.cfg
+w3mir.PL
+w3mir-HOWTO.html
+w3mfix.PL
+htmlop.pm
+w3http.pm
+w3pdfuri.pm
Index: /main/tags/2.25/gsdl/packages/w3mir/w3mir-1.0.8/Makefile.PL
===================================================================
--- /main/tags/2.25/gsdl/packages/w3mir/w3mir-1.0.8/Makefile.PL	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/w3mir/w3mir-1.0.8/Makefile.PL	(revision 21064)
@@ -0,0 +1,116 @@
+# -*-perl-*-
+# Makefile.PL for w3mir.
+# Note that the file 'MANIFEST' is quite significant in this context
+#
+# Notes:  Should unpack any tar.gz files in current directory and install
+#   them with identical arguments to Makefile.PL to this invocation.
+#   This is especially for making installation of w3mir easy 
+#   by installing libwww-perl and mime-base64 for the user before
+#   installing w3mir.  Cool eh?  That would require some changes.
+#
+# - janl 18/4/1997
+#
+# 19/04/99 janl: Added 'clean' target on tip from  Lupe Christoph
+#	and LWP max-version check to the LWP detection.
+# 
+
+# First just write the Makefile
+use ExtUtils::MakeMaker;
+
+WriteMakefile(
+    NAME	=> 'w3mir',
+    VERSION_FROM => 'w3mir.PL', # finds $VERSION
+    EXE_FILES => [ 'w3mir', 'w3mfix' ],
+    clean => { FILES => 'w3mir w3mfix' },
+    dist => { COMPRESS => 'gzip -f9', SUFFIX => 'gz' },
+);
+
+print "\n";
+
+# Find value of INSTALLSITELIB
+
+&read_makefile;
+$islib = resolve_make_var('INSTALLSITELIB');
+
+# Check for prerequisites
+
+$| = 1;
+my $missing_modules = 0;
+
+# libwww-perl
+print "Checking for libwww-perl:";
+
+eval "use lib '$islib'; require LWP;";
+
+if (!defined($LWP::VERSION)) {
+  print ' failed
+
+libwww seems to be missing.
+
+';
+  $missing_modules++;
+  sleep(2);
+} elsif ($LWP::VERSION<5.08 or $LWP::VERSION>=5.40) {
+  print ' failed
+
+libwww is version ',$LWP::VERSION,', I need version 5.08 to 5.39.
+Please see the INSTALL file.
+
+';
+  $missing_modules++;
+  sleep(2);
+} else {  
+  print " ok\n\n";
+}
+
+# MIME::Base64
+print "Checking for MIME::Base64:";
+
+eval "use lib '$islib'; require MIME::Base64;";
+
+if (!defined(&MIME::Base64::encode)) {
+  print ' failed
+
+MIME::Base64 seems to be missing.
+
+';
+  $missing_modules++;
+  sleep(2);
+} else {
+  print " ok\n\n";
+}
+
+
+print 'Please see the INSTALL file for instructions on how to get the
+missing/too old modules.
+
+' if $missing_modules;
+
+
+sub resolve_make_var ($) {
+
+  my($var) = shift @_;
+  my($val) = $make{$var};
+
+#  print "Resolving: ",$var,"=",$val,"\n";
+  
+  while ($val =~ s~\$\((\S+)\)~$make{$1}~g) {}
+#  print "Resolved: $var: $make{$var} -> $val\n";
+  $val;
+}
+
+
+sub read_makefile {
+
+  open(MAKEFILE, 'Makefile') || 
+    die "Could not open Makefile for reading: $!\n";
+
+  while (<MAKEFILE>) {
+    chomp;
+    next unless m/^([A-Z]+)\s*=\s*(\S+)$/;
+    $make{$1}=$2;
+#    print "Makevar: $1 = $2\n";
+  }
+
+  close(MAKEFILE)
+}
Index: /main/tags/2.25/gsdl/packages/w3mir/w3mir-1.0.8/README
===================================================================
--- /main/tags/2.25/gsdl/packages/w3mir/w3mir-1.0.8/README	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/w3mir/w3mir-1.0.8/README	(revision 21064)
@@ -0,0 +1,133 @@
+PROPAGANDA:
+
+See http://www.math.uio.no/~janl/w3mir/ for propaganda.
+
+--------------------------------------------------------------------------
+Q: Where can I get a new version of w3mir?
+A: The w3mir homepage is at http://www.math.uio.no/~janl/w3mir/.
+   W3mir is also distributed on CPAN: http://www.perl.com/
+
+Q: Are there any mailing lists?
+A: Yes, see below.
+
+Q: Should I subscribe to any of the mailinglists?
+A: Yes, if you use w3mir at all you should subscribe to 
+   w3mir-info@usit.uio.no, send e-mail to janl@math.uio.no to be
+   subscribed.
+
+Q: I found a bug!
+A: See below.
+
+Q: How do it...
+A: There is a w3mir-HOWTO.html file in the distribution.  Read it.
+
+--------------------------------------------------------------------------
+BUGS:
+
+- -lc switch does not work too well.
+
+Please see below for how to report bugs.
+
+--------------------------------------------------------------------------
+FEATURES (NOT bugs):
+
+- URLs with two /es ('//') in the path component does not work
+  as some might expect.  According to my reading of the http/url spec.
+  it is an illegal construct, which is a Good Thing, because I don't
+  know how to handle it if it's legal.
+- If you start at http://foo/bar/ then index.html might be gotten twice.
+- Some documents point to a point above the server root, i.e.,
+  http://some.server/../stuff.html.  Netscape, and other browsers, in
+  defiance of the URL standard documents will change the URL to
+  http://some.server/stuff.html.  W3mir will not.
+
+--------------------------------------------------------------------------
+MAIL LISTS, REPORTING BUGS:
+
+Please send ideas (see todo lists further down please) and bug reports
+to w3mir-core@usit.uio.no, please include URL and command line/config
+file that triggered the bug. w3mir-info@usit.uio.no is mainly used for
+announcing new versions or bugs to w3mir users. You will get more
+information following that list than anywhere else. And it's very low
+volume. To subscribe to these lists email janl@math.uio.no. The
+w3mir-core list is intended for w3mir hackers only.
+
+--------------------------------------------------------------------------
+COPYRIGTHS:
+
+w3mir, w3http.pm, w3pdfuri.pm and htmlop.pm are free but it is
+Copyrighted by the various involved hackers.  If you want to copy,
+hack or distribte w3mir you can do that providing you comply with the
+'Artistic License' enclosed in the w3mir distribution in the file
+named Artistic.
+
+--------------------------------------------------------------------------
+CREDITS:
+
+- Oscar Nierstrasz: Wrote htget
+- Gorm Haug Eriksen: Started w3mir on the foundations of htget,
+	contributed code later.
+- Nicolai Langfeldt: Learning from Oscar and Gorms mistakes, rewrote
+  everything.
+- Chris Szurgot: Adapting to win32, good ideas and code contribs, 
+  Debugging.  And criticism.
+- Rik Faith: Uses w3mir extensively, not shy about complaining and
+  commenting and suggesting.  
+- The libwww-perl author(s) that made adding some new featres
+  ridicolously easy.
+
+--------------------------------------------------------------------------
+TODO LIST:
+
+* TODO, version 1.1:
+
+Some of these are speculative, some others are very useful.
+
+- CSS parsing/support at the same level as HTML
+- Full support for APPLETS/OBJECT tags.
+- Alias rules.  These would enable w3mir to map ukoln.bath.ac.uk and 
+  bubl.bath.ac.uk to www.ukoln.ac.uk and know that the objects contained
+  in these are all the same.  Another use would be to mirror from a mirror
+  instead of the _real_ site, since the original site to which you have
+  references are on a slow link while the mirror is on a fast link.
+- FTP support (easy if through a http style ftp proxy, but is that what
+  we want?)
+- SHTTP/SSL support
+- Add a 3rd argument to URL/Also that denotes the depth of documents to
+  be retrived under each, this would autimatically generate fetch/ignore
+  rules.  How well these work would be dependent on the order of the
+  URL/Also directives though.  Must be documented.
+- Retrive recursively until N-th order links are reached.  This
+  differs siginificantly from directory recursion which we do now.  When
+  this is done w3mir should also know the difference between inline and
+  external links, inline links should always be retrived.  Trivia question:
+  What order is needed to reach every findable document on the web from
+  Yahoo?
+- Integrate with cvs or rcs (or other version controll system) to make
+  retriver able to reproduce mirrored site for any given date.
+- Some text processing:  Adding and removing text/sgml comments when suitable
+  options and tags are found.
+- Put retrival date-stamps as comments in html files, to document the when
+  and how of how this document was retrived.
+- Example: If you're mirroring a site primarily to get to the papers, but
+  the site has n versions of each paper: foo.ps.gz, foo.ps.Z, foo.dvi.gz
+  foo.dvi.Z, foo.tar.gz, foo.zip and you only need one version.  Implement
+  a way to get only one version of documents provided in multipele versions,
+  something like multi axis preference list to get only the most attractive
+  version of the doc.
+- Logging of retrivals to file, need to change every print to a functioncall.
+- Your suggestion here.
+
+* TODO, http related
+- Use Keep-alive.  Then we should probably stop using 30 second pauses
+  between document retrivals.
+- HTTP/1.1?  HTTP/1.1 servers should do keep-alive even with 1.0 requests.
+- Separate quenes for each server, interleave requests.
+- Authentication is only done if challenged now.  If a document in a
+  directory needs authentication it is very likely that all other documents
+  in that directory and subdirectories require authentication.
+
+* If perl gets threads:
+- Make the retrival and analysis engines separate threads, and have each
+  one retrival thread pr. method/server/port and do paralell retrivals.
+- This makes http/1.1 easier too.
Index: /main/tags/2.25/gsdl/packages/w3mir/w3mir-1.0.8/example.cfg
===================================================================
--- /main/tags/2.25/gsdl/packages/w3mir/w3mir-1.0.8/example.cfg	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/w3mir/w3mir-1.0.8/example.cfg	(revision 21064)
@@ -0,0 +1,120 @@
+# This is a example w3mir config file.  The file and options are fully
+# documented in the w3mir man page, and a lot is spelled out in the 
+# w3mir-HOWTO.  This file might not be completely updated, but the man
+# page should be.
+#
+# Comment lines start with '#'.  Comments are not allowed at end of
+# lines.  The keywords are not casesensitive, but some settings are,
+# notably fetch/ignore/apply settings, as well as the urls given.
+#
+# Available options: recurse, no-date-check, only-nonexistent, list-urls,
+# lowercase.  It is not default to recurse.  Options must be the
+# first directive to appear in the config file.
+# The options directive needs to be the first directive in the config file
+# and there can only be one.
+Options: recurse
+# Multipele options:
+# Options: recurse, only-nonexistent
+# This directive was previously named 'Fetch-options'
+#
+# Start here:
+URL: http://www.stud.ifi.uio.no/~janl/
+#
+#
+# How much noise to make, one of quiet, brief or chatty.  Default is brief
+#Verbosity: brief
+#
+# Initial referer.  Some servers are very picky....
+#Initial-Referer: http://foo.bar/
+#
+# Headers to disable for anonymitys sake: 
+#Disable-headers: referer, user
+#
+# Nicenes, robotrules can be true or false
+#Robot-Rules: true
+# Default pause between http connections is now 0 seconds 
+# Pause: 0
+# Pause between retries, in seconds.  If w3mir runs as a once-a-day thing
+# this can and should be high.  I suggest at least one hour (3600 seconds).
+#Retry-Pause: 600
+# How many times a failed retrival is retried.
+#Retries: 3
+#
+# URL selection.  Order is significant, first Fetch/Ignore rule overrides
+# later rules.  Supply as many as you want.  If not matched by ignore rules
+# a doc is gotten.  
+#Fetch: *.html
+#
+# Ignore urls we can't copy anyway.  Actually w3mir can copy
+# many cgi things with no problems.  But not always.
+Ignore: *.cgi
+Ignore: *-cgi
+Ignore: *.map
+#
+# RE variants are full perl REs.  Mix freely with the others.  These
+# must be legal perl REs, including the starting m and any
+# options you want, like 'i'.
+#
+#Fetch-RE: m/jpeg/
+#Ignore-RE: m/\.gif$/
+#
+# URL manipulation.  _All_ rules are applied in order.  If lowercasing
+# options is given that is done first.  This must be a legal perl
+# substitution RE.  Including the starting s and any options you want,
+# like 'g' and 'i'.
+#
+# This changes the name of all .gif files to .fif
+#Apply: s/\.gif$/.fif/
+#
+# HTTP Proxy server:
+#HTTP-Proxy: www-cache.uio.no:3128
+#
+# HTTP Proxy options: 
+# - 'revalidate': Force proxy to revalidate cached documents.
+# - 'refresh': Force proxy to get cached documents from server _again_.
+# - 'no-store': Use if the contents of the documents is sensitive.
+# - 'no-pragma': Force use of HTTP/1.1 'Cache-Control:' header.
+# If only 'refresh' is specified the default is to use the 'Pragma: no-cache'
+# HTTP/1.0 header, this can be overruled with the 'no-pragma' option.
+# You can be fairly sure any proxy will understand 'refresh', ONLY HTTP/1.1
+# proxies will understand 'revalidate' and 'no-store'.
+#proxy-options: refresh
+#
+# HTTP Proxy authentication.  The mechanism  is simpleminded, we either need
+# to authenticate ourselves with the proxy or not, and there can only be
+# one user/password tuple, domain/realm information is ignored...
+# HTTP-Proxy-user: foo
+# HTTP-Proxy-passwd: bar
+#
+# What to do with files, one of save, stdout or forget.
+#File-disposition: save
+#
+# Debug level
+#Debug: 0|1|2
+#
+# Umask, if not the default
+#Umask: 077
+#
+# HTML document editing options
+#Header: Mirrored from http://www.ifi.uio.no/~janl/ts/
+#Remove-nomirror: true
+#
+# Authentication:
+#Auth-domain: server:port/realm
+#Auth-user: me
+#Auth-passwd: my_password
+#
+# You can use '*' in place of server:port and/or realm:
+#Auth-domain: */*
+#Auth-user: otherme
+#Auth-passwd: otherpassword
+#
+
+# 'Fixup' is done by the external w3mfix program.  If you want a
+# mirror that's browseable in a filesystem (as opposed to via a http
+# server) just put this in:
+Fixup: run
+
+# Related is this, what is the name of the file the http server serves
+# when a directory URL is requested?  w3mir default is index.html.
+#Index-name: welcome.html
Index: /main/tags/2.25/gsdl/packages/w3mir/w3mir-1.0.8/htmlop.pm
===================================================================
--- /main/tags/2.25/gsdl/packages/w3mir/w3mir-1.0.8/htmlop.pm	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/w3mir/w3mir-1.0.8/htmlop.pm	(revision 21064)
@@ -0,0 +1,656 @@
+# -*-perl-*-
+# htmlop.pl: Do operations on html documents.
+$VERSION=0.2.4;
+#
+# Original source from Bjørn Borud, without it I would not have atempted
+# this. In this incarnation it bears no resemblance to Bjørns code.
+# - Nicolai Langfeldt 18/11/95.
+# 
+# htmlop.pl does operations on html files, possebly many at a time.
+# Operations:
+# - Absolitify urls
+# - Relativify urls
+# - Gather list of urls
+# - Callback with url
+# - Canonify document w.r.t. SGML.
+#
+# Authors:
+# - Nicolai Langfeldt (janl@ifi.uio.no)
+# - Chris Szurgot (szurgot@itribe.net)
+#
+# Changes:
+# janl    18/11/95 - Initial version
+# szurgot 09/02/96 - Code in htmlop'process to remove <BASE> Tag if we are 
+#                    returning the form. An unchanged base destroys local 
+#                    fragments.
+# janl    22/02/96 - Added URLSUB functions.  <BASE> will only be removed from
+#		     the returned doc, never from the origninal doc.
+# janl    16/05/96 - Removed I* options and added single NODOC option/modifier
+#		     to replace them.
+# janl	  09/09/96 - Added URLPROC and NREL opcodes, for a better URL
+#		     processing model. -> 0.1.7
+# janl    24/09/96 - Various cosmetics, no longer inserting a !SGML tag,
+#		     only !DOCTYPE and HTML tags. -> 0.1.8
+# janl    11/10/96 - URLs in HTML 3.2 tags are now found.
+# janl     6/11/96 - Added netscape SCRIPT tag.
+# janl    20/11/96 - 'BORDER' is different from 'BORDER=0' -> 0.1.10
+# janl    06/11/96 - Added userdata argument to URLPROC.
+#   			Added SAVEURLS and USESAVED opcodes. -> 0.1.11
+# janl    11/04/97 - Changed to URI::URL and got into strict harness
+# janl	  13/04/97 - Fixed comment processing, extended it to processing
+#			directives. Bug reported by Chris Johnson. -> 0.1.12
+# janl    08/04/97 - Made ISMAP into ISMAP=, bad! -> 0.1.13
+# janl	  23/05/97 - Treating <script> and <style> as verbatim -> 0.1.14
+# janl	  06/06/97 - Canonify: <!SGML tag confused it and !DOCTYPE was mangled
+#			-> 0.1.15
+# janl	  30/07/97 - Now supporting <BASE> tag.
+#		   - Added TAGCALLBACK opcode -> 0.1.16
+# janl    16/10/97 - Empty string must be quoted, reported by Bart Barenburg
+#			-> 0.1.17
+# janl	  01/12/97 - More HTML URL tags/attributes recognized (Greg Lindhorst) 
+# janl	  13/12/97 - Can't delete the whole <BASE> tag.  Netscape has
+#		     extended it for frame use.  So only delete the HREF
+#		     attr -> 0.1.18
+# janl    01/01/98 - Realized applet/object support can't work and changed
+#		     so it's able to work, if conditions are right.
+# janl    04/01/98 - Added html 4.0 tags and attributes.
+# janl    08/02/98 - Hacked for speed.  Went from 43s to 9s on a 170K
+#		     document -> 0.2.  Thanks to Rune Frøysa who taunted me.
+# janl	  09/04/98 - More tolerant about what constitutes a newline -> 0.2.1
+# janl	  09/05/98 - Export %isdir -> 0.2.2
+# janl    13/04/99 - Remove leading /../ sequences in path component in
+#		     ABS code. -> 0.2.3
+# janl    28/05/99 - The code was buggy, now it's not. -> 0.2.4
+
+package htmlop;
+
+use URI::URL;
+
+use strict;
+# Global variables
+use vars qw($ABS $REL $LIST $CANON $URLSUB $NODOC $URLPROC $NREL);
+use vars qw($SAVEURL $USESAVED $TAGCALLBACK $debug %isdir);
+
+# These are for the smartrel routines
+my $url_origin;
+my $doc_top;
+my $doc_top_re;
+my $choped_url_or;
+
+# HTML operation codes for process_html.  The first argument is the
+# html document to do operations on.  It will not be changed.  If
+# NODOC is not passed a new document edited as specified will be
+# returned.  No more than one document will be returned by one
+# invocation of htmlop.
+
+$ABS = 1;			# Absolutify urls. Arg: Origin. The
+                                # ABS function absolutifies URLS,
+                                # assuming they are relative to the
+                                # argument.
+				# If a <BASE> tag is found the origin
+				# given by it will be used instead of
+				# the arguemnt given.
+
+$REL = 2;			# Relativize all urls. Arg: Origin.
+                                # The REL function simply removes the
+                                # argument string from any urls
+                                # matching it.  For this reason the
+                                # origin string is interprated as a
+                                # RE, which may have unexpected
+                                # results, unless RE specials are
+                                # escaped, which they should be.
+
+$LIST = 3;			# List all urls, Ret: urls
+
+$CANON = 4;			# See that missing opening (and
+                                # ending) SGML tags are injected.
+
+$URLSUB = 5;			# Do regular expression substitution
+                                # on urls.  Arg: RE, substitute.
+
+$NODOC = 6;			# Do not return a rebuilt document.
+                                # Saves memory, and time
+
+# NOTE: I SUSPECT URLPROC IS BROKEN IF A BASE TAG APPEARS IN THE TEXT.
+# THE URL PROCESSOR NEEDS TO BE PASSED htmlop::process' IDEA OF WHAT THE
+# BASE URL IS.
+
+$URLPROC = 7;			# Apply function on urls (process
+                                # urls).  Arg: Pointer to function to
+				# apply, userdata.  The function will
+				# be passed the url, modified by any
+				# previous operations and the
+				# userdata.  The function must return
+				# the new url.
+
+$NREL = 8;			# New relativisation function, works
+                                # much better than the old one. Arg:
+                                # Origin, Top.
+
+$SAVEURL = 9;			# Save urls in tag with modified name.
+				# Arg: attribute prefix.
+				# Example: <a href=foo> becomes
+				# <a href=foo w3mir-href=foo> if no other
+				# processing of the url is done.
+
+$USESAVED = 10;			# Use saved urls. Arg: attribute prefix
+
+$TAGCALLBACK = 11;		# Procedure to call for each Tag.
+				# Args: procedure, userdata (one item)
+
+				# Args to procedure: userdata, Base
+				# URL, tag name, reference to array of
+				# URL attributes, reference to hash of
+				# all attributes.  The base url is
+				# derived from the one used in ABS or
+				# the BASE tag.
+
+$debug=0;			# Debugging level in this package
+
+# process_html returns a array.  The first component of the array is
+# the new html document. The rest of the array is the urls.  If a
+# document is not to be returned a empty string is returned. If a url
+# list is not to be returned a empty array is returned.
+
+# HERE BE DRAGONS:
+
+# Where to find URLs in various tags.  The second compoent is a array
+# reference.
+
+my(%urls) = (
+	HEAD    => [ 'PROFILE' ],
+        BLOCKQUOTE => [ 'CITE' ],
+        Q 	=> [ 'CITE' ],
+        INS	=> [ 'CITE' ],
+	DEL	=> [ 'CITE' ],
+	A	=> [ 'HREF' ] ,
+	IMG	=> [ 'SRC' ,'LOWSRC' ,'USEMAP', 'LONGDESC' ] ,
+	EMBED	=> [ 'SRC' ],
+	FRAME	=> [ 'SRC', 'LONGDESC' ],
+        IFRAME  => [ 'SRC', 'LONGDESC' ],
+	BODY	=> [ 'BACKGROUND' ],
+	AREA	=> [ 'HREF' ],
+	LINK	=> [ 'HREF' ],
+
+	# The APPLET and OBJECT tags do not fit into my model for URL
+	# manipulation.  Just looking at CODEBASE might work, if the
+	# URL it names is a browseable directory...
+	APPLET	=> [ 'CODEBASE' ],  # If the codebase dir is browseable
+	OBJECT  => [ 'CODEBASE' ],  # Ditto.  Can't handle DATA attribute now
+
+	INPUT	=> [ 'SRC', 'USEMAP' ],
+	MAP	=> [ 'HREF' ],
+	SCRIPT	=> [ 'SRC', 'FOR' ],# 'FOR's semantics is not defined, the
+				    # attribute is just reserved for possible
+				    # future use...
+	BGSOUND => [ 'SRC' ],
+	FORM	=> [ 'ACTION' ],    # Is this asking for trouble?
+				    # Maybe it should just be absolutized...
+	     			    # On the other hand: It's CGI...
+	);
+
+my(%relative) = (
+	# Identify URL attributes containing urls that are relative to
+	# the named URL attribute.   When processing these they should
+        # be absolitized and then relativized relative to the BASE attribute.
+        # This is just window dressing for now; it is not used for anything.
+
+	# ARCHIVE is really a URI _list_.
+	CODEBASE => [ 'CLASSID', 'DATA', 'CODE', 'ARCHIVE' ],
+        );
+
+%isdir = (
+	# These tags refer to directories:
+	CODEBASE => 1
+	);
+
+# Tags that enclose bits we want to leave absolutely alone because they
+# are not very like HTML, or some such.
+
+# The material between the start and end tags is copied with no
+# processing at all.  The end tag is left to be processed.
+# The endtag match is case insensitive.
+my(%verbatim) = (
+        SCRIPT	=> quotemeta('</SCRIPT>'),	# Embeded scripts
+	STYLE	=> quotemeta('</STYLE>'),	# Embeded stylesheet
+	);
+
+# These are the functions that pick the HTML to pieces.  It will not
+# work esp. good on a random SGML document since the HTML application
+# of SGML has simpler quoting than it might.
+
+sub gettoken {
+  # Get one token from the argument, removing it from the argument.
+  # BUG: There should be whitespace at the end of the examined string.
+  my($c,$token,$i);
+  
+  # Skip whitespace and newlines
+  return '' unless defined(@_) && defined($_[0]);
+  $_[0] =~ s/^[\r\n\s]*//;
+  
+  return '' if ($_[0] eq '');
+  
+  $c = substr($_[0],0,1);
+  substr($_[0],0,1)='';
+  
+  if ($c eq '"' || $c eq "\'") { # Quoted material
+    $i=index($_[0],$c);
+    # End-quote missing, just gobble the rest of the doc
+    $i=length($_[0]) if $i == -1;
+    # Extract and remove token
+    $token=substr($_[0],0,$i);
+    substr($_[0],0,$i+1)='';
+  } elsif ($c eq '=') {
+    $token='=';
+  } else {			# Non-quoted material, ends in whitespace or =
+    $_[0] =~ m/[=\s\n\r]/;
+    $_[0] = $&.$';
+    $token=$c.$`;
+  }
+  # print "Token: '$token'\t\tRest: '",$_[0],"'\n";
+  return $token;
+}
+
+
+sub tagtoken {
+  # Pick the tag to pieces (also knonw as tokens). Return an
+  # associative array of attributes.  The attribute-names are changed
+  # to uppercase.  The attribute-values are left as is.
+  my($tok,$lasttok,%tokens);
+  # Append a space, gettoken needs it - silly? Yes! 
+  # Change it to test on boundrary things rather than ...?
+  $_[0].=' ';
+
+  $lasttok='';
+  while (1) {
+    last if (($tok=uc &gettoken($_[0])) eq '');
+
+    if ($tok eq '=') {
+#      print STDERR " -bad html-" if ($lasttok eq '');
+      $tokens{$lasttok}.=&gettoken($_[0]);
+      print STDERR "STORED: $lasttok = ",$tokens{$lasttok},"\n" if $debug;
+    } else {
+      $tokens{$tok}=undef;
+      $lasttok=$tok;
+    }
+  }
+  return %tokens;
+}
+
+
+sub gettag {
+  # Pick out the following things from the remaining html doc:
+  # Everything leading up to the first tag.  The first tag, and its
+  # contents.  Modify @_ directly to reduce number of copies of
+  # possebly huge documents kept in memory at once.  Return the body,
+  # the tag name, and the attributes (associative array)
+  my(%attr,$tagn,$tagc,$body,$tag,$doc);
+
+  $doc=\$_[0];
+
+  my($start,$end,$length);
+  
+  $start=index($$doc,'<');
+
+  if ($start<$[) {
+    # EOF
+    $body=$$doc;
+    $$doc='';
+    return ($body,'',());
+  }
+
+  $end=index($$doc,'>',$start+1);
+  
+  if ($end<$[) {
+    # This sucks, found no end of the tag...
+    $body=$$doc;
+    $$doc='';
+    return ($body,'',());
+  }
+
+  $length=$end-$start-1;
+
+  $body=substr($$doc,0,$start);
+  $tag=substr($$doc,$start+1,$length);
+
+  # This shortens the string in each itteration, some kind of mechanism
+  # to do it once in a while would speed things up further.  HOWEVER, when
+  # I tried to code this all I got was a _nasty_ memory leak.
+  substr($$doc,0,$end+1)='';
+
+#  print STDERR "------\n";
+  
+#  print STDERR "BODY: /$body/\n";
+  print STDERR "COMPLETE TAG: /$tag/\n" if $debug;
+#  print STDERR "REST: /",substr($$doc,0,20),"/\n";
+
+#  print STDERR "------\n";
+
+  # Examine tag contents
+  if ($tag =~ /^([!?]--)/ || $tag =~ /^(!\w+)/) {
+    # Comment or processing dicective, handle specially
+    $tagn=$&;
+    $tagc=$';
+    return ($body,$tagn,("$tagc",undef));
+  }
+
+  # Everything else
+  ($tagn,$tagc) = split(/[\s\n\r]+/,$tag,2);
+  $tagn="\U$tagn";
+
+  return ($body,$tagn,()) if !defined($tagc);
+  
+  return ($body,$tagn,&tagtoken($tagc));
+}
+
+
+# This is meant for general consumption:
+
+sub process {
+  # Process a html file.  Into one end you put a html file.  Out
+  # of the other end you get something dependent on the operations
+  # you specified.
+  # I cannot gobble my arguments. I need to examine them several times.
+  
+  my($arg,$doc,$i,$retdoc,$canon,$newdoc,@urllist,$Q,$cont);
+  my($origin,$baseurl);
+  
+  $origin=$baseurl='';
+
+  $retdoc=$canon=0;
+  
+  # Get the document from the argument list
+  $doc=shift(@_);
+  
+  $retdoc=1;
+  $i=0;
+  # Argument checking
+  while (defined($arg=$_[$i++])) {
+    if (! ($arg =~ /^\d+$/)) {
+      print STDERR "ERROR IN HTMLOP::process:\n";
+      print STDERR "Args: ",join(',',@_),"\n";
+      print STDERR "ARG: $arg is not a opcode.\n";
+      exit(1);
+    }
+    if ($arg == $ABS) {
+      $baseurl=$origin=$_[$i++];
+    } elsif ($arg == $REL || $arg == $SAVEURL || $arg == $USESAVED) {
+      $i++; # Skip one arg
+    } elsif ($arg == $URLSUB || $arg == $NREL || $arg == $URLPROC ||
+	     $arg == $TAGCALLBACK ) {
+      $i += 2; # Skip two args
+    } elsif ($arg == $LIST) { 
+      # do nothing
+    } elsif ($arg == $CANON) {
+      $canon=1;
+    } elsif ($arg == $NODOC) {
+      $retdoc=0;
+    } else {
+      die "htmlop: Incorrect invocation of html_process\n";
+    }
+  }
+  
+  my($endhtml)=0;	# Have we seen </html>?
+  my($SGML)=1;		# 1: !DOCTYPE not seen, 2: !DOCTYPE seen, -1: it's OK
+
+  # These are used to store the tag components
+  my($textpart);
+  my($tagname);
+  my(%attrval);
+
+  my($wholetag);	# The whole tag, put together again
+  my($moretag);		# TMP storage of tag attributes
+  my($attr);		# Looping thru attributes, misnomer.
+  my($RE);
+  my($subst);
+  my($prefix);
+  my($fun);		# Function to apply to url
+  my($verbatim)='';
+  my($url_o,$path);		# URL object Used in ABS to remove leading ..
+
+  # Welcome to the machine
+
+  $newdoc='';
+  while ($doc ne '') {
+    ($textpart,$tagname,%attrval)=&gettag($doc);
+    
+    # Process the tag
+    { # Need a way to get out of this, last is my friend
+      # 'Canonize'
+      if ($canon) {
+	$endhtml=1 if ($tagname eq '/HTML');
+	if ($SGML!=-1 && $canon && $tagname ne '!--' && $tagname ne '!SGML') {
+	  $wholetag=$tagname;
+	  $moretag=join('',keys %attrval);
+	  $wholetag.=' '.$moretag if ($moretag ne '');
+	  if ($SGML==1) {
+	    $SGML=2;
+	    if ($tagname eq '!DOCTYPE') {
+	      $tagname=$wholetag;
+	      %attrval=();
+	      last;
+	    }
+
+	    # We have no idea what DTD this doc follows so we put in
+	    # something kinda non-comitting
+	    $newdoc.='<!DOCTYPE HTML PUBLIC "html.dtd">'."\n";
+	  }
+	  if ($SGML==2) {
+	    $SGML=-1;
+	    if ($tagname eq 'HTML') {
+	      $tagname=$wholetag;
+	      %attrval=();
+	      last;
+	    }
+	    $newdoc.='<HTML>'."\n";
+	  }
+	}			# sgml!=-1
+      }				#canon
+
+      # Tack on text part before I bail out, if wanted
+      $newdoc.=$textpart if $retdoc;
+
+      if ($tagname eq 'BASE') {
+	if (exists($attrval{'HREF'})) {
+	  if ($origin) {
+	    $baseurl=(url($attrval{'HREF'})->abs($origin,1))->as_string;
+	  } else {
+	    $baseurl=$attrval{'HREF'};
+	  }
+	  # Get rid of the HREF attribute.  Netscape 4.0 puts (other) stuff
+	  # into BASE that is not found in the HTML 4.0 spec.
+	  delete $attrval{'HREF'};
+	  print STDERR "\nBase tag: $baseurl\n" if $debug;
+	}
+      }
+
+      # URL processing
+      $i=0;
+      while (defined($arg=$_[$i])) {
+	if (! ($arg =~ /^\d+$/)) {
+	  print STDERR "Args: ",join(',',@_),"\n";
+	  print STDERR "ARG: $arg ($i) is not a opcode.\n";
+	  exit(1);
+	}
+	$i++;
+	if ($arg == $ABS) {
+	  $origin=$baseurl || $_[$i++];
+	  $i++;
+	  # Want it to be a URL object
+	  $origin=url $origin unless ref $origin;
+	  print STDERR 'ABS: ',$origin->as_string,"\n" if $debug;
+	  next unless defined($urls{$tagname});
+	  foreach $attr (@{$urls{$tagname}}) {
+	    if (defined($attrval{$attr})) {
+	      # Ugly: Remove leading /../ sequences in path component
+	      $url_o=url($attrval{$attr})->abs($origin,1);
+	      if (defined($path=$url_o->path)) {
+		# mailto: URLs does not have path components
+		$path =~ s~/\.\.(?=/)~~g;
+		$url_o->path($path);
+	      }
+	      $attrval{$attr}=$url_o->as_string;
+	    }
+	  }
+	} elsif ($arg == $REL) {
+	  $origin=$_[$i++];
+	  # Want it to be a string
+	  $origin=$origin->as_string if ref $origin;
+	  print STDERR 'REL: ',$origin,"\n" if $debug;
+	  next unless defined($urls{$tagname});
+	  foreach $attr (@{$urls{$tagname}}) {
+	    $attrval{$attr} =~ s/^$origin//
+	      if defined($attrval{$attr});
+	  }
+	} elsif ($arg == $URLSUB) {
+	  $RE=$_[$i++];
+	  $subst=$_[$i++];
+	  warn "URLSUB: $RE -> $subst\n" if $debug;
+	  next unless defined($urls{$tagname});
+	  foreach $attr (@{$urls{$tagname}}) {
+	    $attrval{$attr} =~ s/$RE/$subst/
+	      if defined($attrval{$attr});
+	  }
+	} elsif ($arg == $LIST) {
+	  warn "LIST;\n" if $debug;
+	  next unless exists($urls{$tagname});
+	  foreach $attr (@{$urls{$tagname}}) {
+	    if (exists($attrval{$attr})) {
+	      $attrval{$attr}.='/'
+		if $isdir{$attr} && $attrval{$attr} =~ m~[^/]$~;
+	      push(@urllist,$attrval{$attr});
+	    }
+	  }
+	} elsif ($arg == $SAVEURL) {
+	  warn "SAVEURL;\n" if $debug;
+	  $prefix=$_[$i++];
+	  next unless exists($urls{$tagname});
+	  foreach $attr (@{$urls{$tagname}}) {
+	    $attrval{"$prefix$attr"}=$attrval{$attr}
+	      if defined($attrval{$attr});
+	  }
+	} elsif ($arg == $USESAVED) {
+	  warn "USESAVED;\n" if $debug;
+	  $prefix=$_[$i++];
+	  next unless exists($urls{$tagname});
+	  foreach $attr (@{$urls{$tagname}}) {
+	    $attrval{$attr}=$attrval{"$prefix$attr"}
+	      if (defined($attrval{"$prefix$attr"}));
+	    # bug compatability, drop sometime after w3mir 1.0
+	    $attrval{$attr}=$attrval{"$prefix-$attr"}
+	      if (defined($attrval{"$prefix-$attr"}));
+	  }
+	} elsif ($arg == $NODOC) {
+	  warn "NODOC;\n" if $debug;
+	} elsif ($arg == $CANON) {
+	  warn "CANON;\n" if $debug;
+	} elsif ($arg == $URLPROC || $arg == $NREL) {
+	  # Apply a function to all urls.
+	  # NREL = Special case of $URLPROC, apply internal function.
+	  if ($arg == $URLPROC) {
+	    warn "URLPROC;\n" if $debug;
+	    $fun=$_[$i++];
+	    $arg=$_[$i++];
+	  } else {
+	    $fun=\&smartrel;
+	    $arg=undef;
+	    $url_origin=$_[$i++];
+	    $doc_top=$_[$i++];
+	    $doc_top_re=quotemeta $doc_top;
+	    ($choped_url_or=$url_origin) =~ s/^$doc_top_re//;
+	    warn "NREL $url_origin $doc_top\n" if $debug;
+	  }
+
+	  next unless (defined($urls{$tagname}));
+
+	  foreach $attr (@{$urls{$tagname}}) {
+	    $attrval{$attr}=&$fun($attrval{$attr},$arg)
+	      if defined($attrval{$attr});
+	  }
+	} elsif ($arg == $TAGCALLBACK) {
+	  $fun=$_[$i++];
+	  $arg=$_[$i++];
+	  warn "TAGCALLBACK($tagname);\n" if $debug;
+	  &$fun($arg,$baseurl,$tagname, 
+		(defined($urls{$tagname})?($urls{$tagname}):undef),
+		\%attrval);
+	} else {
+	  print STDERR "Internal error. opcode: $arg, i: $i, args: ",
+	  join(',',@_),"\n";
+	}
+      }
+      last;
+    }
+
+    # That ends URL processing
+
+    # Was this a verbatim leadin tag?  If yes, atempt to fish out text
+    # between here and the end tag, (minimal match) and substitute it
+    # with nothing.  The end tag is kept.  And the fished out text is
+    # re-inserted in the result with no changes.
+
+    $verbatim=$1 
+      if defined($verbatim{$tagname}) &&
+	($doc =~ s/^(.*?)($verbatim{$tagname})/$2/is);
+    
+    # Tack on the tag, if wanted.
+    if ($retdoc) {
+      if ($tagname) {
+	$newdoc.='<'.$tagname;
+	foreach $attr (keys %attrval) {
+	  $newdoc.=' '.$attr;
+	  if (defined($cont=$attrval{$attr})) {
+	    $Q='"';
+	    $Q="'" if $cont =~ m/\"/;
+	    $newdoc.='='.$Q.$cont.$Q;
+	  }
+	}
+	$newdoc.='>'.$verbatim;
+	$verbatim='';
+      }
+    }
+    print STDERR "NEW: $newdoc\n" if $debug > 2;
+  }
+  $newdoc.="</HTML>\n" if ($canon && !$endhtml);
+  return ($newdoc,@urllist);
+}
+
+
+sub smartrel {
+  # 'smart' relativisation function, uses .. to refer to things up to
+  # $doc_top level.  Outside that scope it stays absolute.
+  #
+  # The rel function itself is now in libwww-perl
+  
+  my($url_o)=@_;
+
+  return if (!(defined($url_o) && $url_o));
+  
+  $url_o=url $url_o unless ref $url_o;
+
+#  print STDERR "\nsmartrel: $url_o->as_string\n",
+#                 "    from: $url_origin\n",
+#                 "  within: $doc_top\n";
+  
+  # Check if within scope of our doc
+  $url_o = $url_o->rel($url_origin)
+    if $url_o->as_string =~ m/^$doc_top_re/;
+
+  return $url_o->as_string;
+}
+
+
+sub smart_setup {
+  # Setup routine for smartrel.
+
+  ($url_origin,$doc_top) = @_;
+
+  $url_origin=$url_origin->as_string if ref $url_origin;
+  $doc_top=$doc_top->as_string if ref $doc_top;
+
+  $doc_top_re=quotemeta $doc_top;
+
+  ($choped_url_or=$url_origin) =~ s/^$doc_top_re//;
+}
+
+1;
Index: /main/tags/2.25/gsdl/packages/w3mir/w3mir-1.0.8/install.sh
===================================================================
--- /main/tags/2.25/gsdl/packages/w3mir/w3mir-1.0.8/install.sh	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/w3mir/w3mir-1.0.8/install.sh	(revision 21064)
@@ -0,0 +1,9 @@
+#!/bin/sh -v
+
+export PERL5LIB=$GSDLHOME/perllib/cpan/lib:$PERL5LIB
+export PATH=$GSDLHOME/perllib/cpan/bin:$PATH
+
+perl Makefile.PL PREFIX=$GSDLHOME/perllib/cpan
+
+make
+make install
Index: /main/tags/2.25/gsdl/packages/w3mir/w3mir-1.0.8/multiscope.cfg
===================================================================
--- /main/tags/2.25/gsdl/packages/w3mir/w3mir-1.0.8/multiscope.cfg	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/w3mir/w3mir-1.0.8/multiscope.cfg	(revision 21064)
@@ -0,0 +1,46 @@
+# This file is meant to illustrate multiscope retrival.
+#
+# Available options: recurse, no-date-check, only-nonexistent, list-urls,
+# lowercase.  It is not default to recurse.  options must be the 
+# first directive in the the config file.
+Options: recurse
+# This directive was previously known as 'Fetch-options'
+#
+# This is the two argument form of URL:.  It fetches the first into the second
+URL: http://www.math.uio.no/~janl/ math/janl
+#
+# These says that any documents refered to that lives under these places
+# should be gotten too.  Into the named directories.  Two arguments are
+# required for 'Also:'.
+Also: http://www.math.uio.no/drift/personer/ math/drift
+Also: http://www.stud.ifi.uio.no/~janl/ ifi/janl
+Also: http://www.mi.uib.no/~nicolai/ math-uib/nicolai
+#
+# A more typical use would perhaps be:
+#   URL: http://www.math.uio.no/~janl/ janl
+#   Also: http://www.math.uio.no/images/ images
+# which would retrive the images refered to under
+# http://www.math.uio.no/~janl/ into a directory called images
+#
+# CD here before doing any work
+#cd: janlhomes
+#
+# Default pause is now 0.
+#Pause: 0
+#
+# Ignore urls we can't copy anyway.  Actually w3mir can copy
+# many cgi things with no problems.  But not always.
+Ignore: *.cgi
+Ignore: *-cgi
+Ignore: *.map
+#
+# Run fixup to get a filesystem browseable mirror
+Fixup: run
+# The options above will result in this directory hierarchy under
+# where you started w3mir:
+#
+# w3mir/math/janl		files from http://www.math.uio.no/~janl
+# w3mir/math/drift		from http://www.math.uio.no/drift/personer/
+# w3mir/ifi/janl		from http://www.stud.ifi.uio.no/~janl/
+# w3mir/math-uib/nicolai	from http://www.mi.uib.no/~nicolai/
+#
Index: /main/tags/2.25/gsdl/packages/w3mir/w3mir-1.0.8/w3http.pm
===================================================================
--- /main/tags/2.25/gsdl/packages/w3mir/w3mir-1.0.8/w3http.pm	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/w3mir/w3mir-1.0.8/w3http.pm	(revision 21064)
@@ -0,0 +1,765 @@
+# -*- perl -*-
+# w3http.pm	--- send http requests, janl's 12" mix for w3mir
+#
+$VERSION=1.0.22;
+#
+# This implements http/1.0 requests.  We'll have problems with http/0.9
+# This is in no way specific to w3mir.
+#
+# IMPORTANT: The caller should initialize the C locale for some of the
+#   things here to work correctly (specifically the strftime function).
+#
+# This is a rewrite of http.pl by Oscar Nierstrasz; I copied the code he he
+# copied from the camel book.  Some functions written by Gorm Haug Eriksen
+# (gorm@usit.uio.no) has been used as is.
+#
+# Contributors:
+#   Nicolai Langfeldt, janl@ifi.uio.no
+#   Gorm Haug Eriksen, gorm@usit.uio.no
+#   Chris Szurgot, szurgot@itribe.net
+#   Bernhard Weisshuh, bkw@weisshuhn.de
+# Copying and modification is governed by the "Artistic License" enclosed in
+# the w3mir distribution
+#
+# gorm :
+# &w3http::get_last_modified  return the last modified stamp on a file in
+#                         the right format for use with http
+#
+# janl:
+# &http::query: Send a http query.  A completely general function to send a
+#   http query.  Will extract header values, http response code and, optionaly,
+#   convert text files to local linefeed format.
+#
+# Variables to examine after a query
+# $w3http::document: The document returned by the query, if any.
+# $w3http::doclen: The length of the document
+# $w3http::result: The numerical http result code.  It may take these values:
+# - Normal HTTP reply codes
+# -  98: OS error, permanent, errormessage in $!
+# -  99: Other permanent error: see $restext.
+# - 100: Transient error: Timeout/connection broken
+# $w3http::restext: The english(?) HTTP result or w3http generated message
+# $w3http::header: The http header returned.
+# $w3http::plaintexthtml: 1 if this doc is non-content-encoded text/html
+#	(as opposed to content-encoding: compressed content-type: text/html
+#       which needs decompression before we can inspect the html) 
+#	The tests are somewhat longwinded so I do it just once here.
+# %w3http::headval: Associative array of header values
+# $w3http::headval{'CONTENT-TYPE'}: Derived content type, stripped of charset
+#		qualifiers and other distractions.
+# $w3http::xfbytes: Transfered bytes, cumulative.  Document part only.
+# $w3http::headbytes: Bytes of headers received, cumulative.
+#
+# Variables that change http's behaviour/requests:
+# $w3http::agent: User agent, default is basename of $0
+# $w3http::from: Request is from, default is user@host
+# $w3http::version: The http version to use, only 1.0 is known to me.
+# $w3http::timeout: How long to wait for new data to arrive, default is 600sec
+# $w3http::buflen: Network read buffer size, default is 4096.  It might give a
+#	speedup to tune this for specific servers' so it matches their send
+#	size.  This size can be detected if we want to, I think.
+# $w3http::debug: 1 debuging output, 2, more, 3 queries and replies
+# $w3http::verbose: 0: say nothing, 1: print progress info
+# $w3http::convert: Convert text/* documents to local newline convention?
+#	The default is to do it.
+# $w3http::proxyserver: The name of the proxyserver to use.
+# $w3http::proxyport: The port of the proxyserver to use. 0 if no proxyserver.
+# $w3http::proxyuser: If this is set proxy authentication will be used.
+# $w3http::proxypasswd: The password for proxy authentication
+#
+# Things gotten from main:
+# - $main::win32: 1 if win32 restrictions apply to this system
+# - $main::nulldevice: Bit sink file/device on this system.
+#
+# History (european date format dd/mm/yy):
+#     janl ??/??/95 -- Rewrite finished
+#  szurgot ??/??/95 -- Win32 compatability
+#     janl 16/05/96 -- Added SAVEBIN option, based on idea by szurgot
+#  szurgot 03/05/96 -- Corrected typo in check for content-length against
+#                      retreive document length. Added test for zero-length
+#		       documents (Not retreived because not-modified)
+#  szurgot 19/05/96 -- Win32 adaptions, fixes.
+#     janl 19/05/96 -- Chris won an argument, and janl simplified http 
+#		       retrival loop (-> version 1.0.4)
+#     janl 09/09/96 -- Incorporated a patch submited by Michael Kriby -> 1.0.5
+#     janl 16/09/96 -- Support for authorization. -> 1.0.6
+#     janl 27/09/96 -- Support for Accept header, lack pointed out by
+# 			charles@ermine.ox.ac.uk: ... HTTP/1.1 (§14.1) says 
+#			``If no Accept header field is present, then it is
+#			assumed that the client accepts all media types,
+#			earlier versions of the protocol suggest that only
+#			text/plain and text/html will be offered by default.''
+#			This contradicts my memory of a http/1.0 draft.
+#			Also added $ACCEPT option.
+#     janl 20/10/96 -- Now uses HTTP::Date to produce HTTP timestamps -> 1.0.7
+#     janl 27/10/96 -- Didn't use to check if gethostbyname worked -> 1.0.8
+#     janl 02/12/96 -- Forgot a unlink when renaming temporary files.
+#     janl 21/02/97 -- Multipele $ACCEPT options work. -> 1.0.9
+#     janl 19/03/97 -- Now issues Host: header -> 1.0.10
+#     janl 10/04/97 -- Changed from wwwurl to URI::URL, and various related
+#                      changes. -> 1.0.11
+#     janl 09/05/97 -- Microsoft ISS servers are _so_ broken -> 1.0.12
+#                      (don't close the write end of the HTTP socket after
+#			sending a query to them)
+#     janl 12/05/97 -- New version of perl caught some typos, fixed
+#			longstanding bug in the newline conversion bit.
+#			-> 1.0.13
+#     janl 06/06/97 -- Demand Loading of MIME::BASE64 -> 1.0.14
+#     janl 01/12/97 -- FAT filesystems drops LSB of modtime.  Patch from
+#			Greg Lindhorst (gregli@microsoft.com)
+#                   -- whoami does not exist on win32, hardwire a default
+#			value (unknown) (also Greg L.) -> 1.0.15
+#     janl 01/22/98 -- Proxy authentication as outlined by Christian Geuer
+#     janl 02/20/98 -- Complex 'content-type' headers handled. -> 1.0.17
+#     janl 04/20/98 -- Only newline convert text/html, everything else is
+#			handled as binary. -> 1.0.18
+#     janl 12/05/98 -- Store tmpfile in its final destination directory
+#			avoiding asking movefile move it across filesystems.
+#			-> 1.0.19
+#     janl 01/08/98 -- Timeout fix from Michael Gusev, also flag short doc
+#			as error.
+#     janl 24/09/98 -- Better error handling -> 1.0.20
+#     bkw  17/12/98 -- Fixed problem with tempfile-generation when
+#                      running in forget-mode (-f)
+#     janl 05/01/99 -- Referer: dropped if argument not true -> 1.0.21
+#     janl 13/04/99 -- Added workaround for broken win32 perl resolving.
+
+package w3http;
+
+require 5.002;
+use Socket;
+use HTTP::Date;
+use Sys::Hostname;
+use URI::URL;
+
+# Suplementary libwww-perl:
+sub URI::URL::_generic::basename {
+  my $self = shift;
+  my @p = $self->path_components;
+  my $old = $p[-1];
+  if (@_) {
+    splice(@p, -1, 1, shift);
+    $self->path_components(@p)
+  }
+  $old;
+}
+
+
+END { 
+  # Remove tmp file and such in here.  That means that main:: gotta catch
+  # interrupt signals and exit on them, so ENDs are executed.
+}
+
+use strict;
+# Global variables, we want to share them:
+use vars qw($GET $HEAD $GETURL $HEADURL $IFMOD $IFMODF $AUTHORIZ $REFERER);
+use vars qw($SAVEBIN $ACCEPT $NOUSER $FREEHEAD $agent $version $timeout);
+use vars qw($debug $convert $proxyserver $proxyport $xfbytes $headbytes);
+use vars qw($verbose $result $restext $header $document);
+use vars qw($plaintexthtml %headval $progress $doclen $proxyuser);
+use vars qw($proxypasswd);
+
+my $hasAlarm;   # Win32 does not have any alarm
+my $chime;	# Has the alarm gone off yet?
+my %address;	# My own DNS cache
+my $savALRM;	# Saved ALRM handler
+my $savPIPE;	# Saved PIPE handler
+
+# The main:: program should detect if we're running on win32 or not,
+# somehow
+if ($main::win32) {
+  warn "win32\n";
+  # Compensate for lacks of win32 perl. 
+  $hasAlarm=0;
+  # Seems to be unavailable in win32/perl5.001.  It has to be in 5.003!
+#  eval "sub sockaddr_in {
+#	($port, $thataddr) = @_;
+#	$sockaddr = 'S n a4 x8';
+#	return pack($sockaddr, &AF_INET, $port, $thataddr);
+#    }";
+} else {
+  $hasAlarm=1;
+}
+
+
+# Find out some things
+my $thishost = hostname();
+my $proto = getprotobyname("tcp");
+
+(my $name, undef) = gethostbyname($thishost);
+chomp(my $user = $ENV{'LOGNAME'} || $ENV{'USER'} || `whoami` || 'unknown');
+my $from   = "$user\@$name";
+
+my $nl = "\r\n";
+# Default values, change by assignment in using-program.
+$agent  = $0; $agent =~ s~.*/~~; # Basename 
+$version= "1.0";
+$timeout= 600;			# Timeout while waiting for data/connection
+my $buflen = 4096;		# recv buffer length
+$debug = 0;			# Debuging output?
+$convert = 1;			# Convert newlines of text docs to local format
+$proxyserver='';		# Proxy server.
+$proxyport=0;			# Proxy server port. 0 if no proxy.
+$proxyuser='';			# Username for proxy authentication
+$proxypasswd='';		# Password for proxy authentication
+$xfbytes=0;			# 0 bytes transfered, cumulative
+$headbytes=0;			# 0 bytes of headers, cumulative
+$doclen=0;			# 0 bytes in doc, pr. document
+my $tmpfile="w3mir$$.tmp";	# Temporary filename
+$verbose=0;			# Verbosenes, 0: silent, 1: progress info
+
+# Query opcodes
+$GET = 1;			# GET query. Arg: host,port,path
+$HEAD = 2;			# HEAD query. Arg: host,port,path
+$GETURL = 3;			# GET query. Arg: url
+$HEADURL = 4;			# HEAD query. Arg: url
+# Here we lack PUT, which is not implemented
+# Modify query thus:
+$IFMOD = 101;			# If-modified after: Arg: HTTP-date-str
+$IFMODF = 102;			# If-modified after file: Arg: local-file-name
+$AUTHORIZ= 103;			# Basic authorization. Arg: 'user:password'
+$REFERER = 104;			# Referer: Arg: Referer 
+$SAVEBIN = 105;			# Write binary files to disk. Arg: File name
+				# If this opcode is used then main must provide
+				# a &main::movefile(oldname,newname) procedure
+				# that handles moving the tmp file to the
+				# final name/location.
+$ACCEPT  = 106;			# Accept header value: Arg: value
+$NOUSER  = 107;			# Don't insert user header.  Arg: none
+$FREEHEAD= 999;			# Freeform header, one line.  Arg: header
+
+sub query {
+  # Build and send a HTTP query.  And also receive response - janl 95/09/18
+  #
+  # Return codes: 0 if it didn't work.  1 if it did work.
+  # HTTP style result code in w3http::$result and message in w3http::$restext
+  
+  # We do next to no argument type checking btw.
+  
+  my($host,$port,$request,$query,$method,$inp,$linp,$saveto,$save,$arg);
+  my($start,$wantbytes,$thataddr,$err,$headb,$tmpf,$ldoc,$nouser,$q,$accept);
+  my($origreq,$req_o,$plaintext);
+  
+  # Something ought to be said
+  $result=99;
+  $restext='w3http: internal error';
+  $nouser=0;
+  
+  if ($version ne '1.0') {
+    warn "Unknown HTTP version $version, no request sent\n";
+    return 0;
+  }
+  
+  $accept=$saveto=$query='';
+  
+  # Find out what to ask for
+  
+  while (defined($arg=shift)) {
+    if ($arg == $GET) {
+      $host=shift;
+      $port=shift;
+      $request=shift;
+      $req_o=url 'http://'.$host.':'.$port.$request;
+      if ($proxyport) {
+	$query.='GET http://'.$req_o->as_string;
+      } else {
+	$query.='GET '.$req_o->epath;
+      }
+      $query.=' HTTP/'.$version.$nl;
+    } elsif ($arg == $HEAD) {
+      $host=shift;
+      $port=shift;
+      $request=shift;
+      $req_o=url 'http://'.$host.':'.$port.$request;
+      if ($proxyport) {
+	$query.='HEAD '.$req_o->as_string;
+      } else {
+	$query.='HEAD '.$req_o->epath;
+      }
+      $query.=' HTTP/'.$version.$nl;
+    } elsif ($arg == $GETURL) {
+      $req_o=shift;
+      $req_o=url $req_o unless ref $req_o;
+      ($method,undef,undef,$host,$port,$request,undef,$q) = $req_o->crack;
+      if ($proxyport) {
+	$query.='GET '.$req_o->as_string;
+      } else {
+	$q=$req_o->equery;
+	$query.='GET '.$request.($q?"?$q":'');
+      }
+      $query.=' HTTP/'.$version.$nl;
+    } elsif ($arg == $HEADURL) {
+      $req_o=shift;
+      $req_o=url $req_o unless ref $req_o;
+      if ($proxyport) {
+	$query.='HEAD '.$req_o->as_string;
+      } else {
+	$q=$req_o->equery;
+	$query.='HEAD '.$req_o->epath.($q?"?$q":'');
+      }
+      $query.=' HTTP/'.$version.$nl;
+    } elsif ($arg == $IFMOD) {
+      $query.='If-Modified-Since: '.(shift).$nl;
+    } elsif ($arg == $IFMODF) {
+      $query.='If-Modified-Since: '.&last_modified(shift).$nl;
+    } elsif ($arg == $AUTHORIZ) {
+      # Demand-load MIME::Base64
+      if (!defined(&MIME::Base64::encode)) {
+	eval "use MIME::Base64;";
+	die "w3http: Could not load MIME::Base64 module necessary for authentication\n"
+	  unless defined(&MIME::Base64::encode);
+      }
+      $query.='Authorization: Basic '.MIME::Base64::encode(shift,'').$nl;
+    } elsif ($arg == $REFERER) {
+      my($referer)=shift;
+      $query.='Referer: '.$referer.$nl if $referer;
+    } elsif ($arg == $SAVEBIN) {
+      $saveto=shift;
+    } elsif ($arg == $ACCEPT) {
+      $accept.='Accept: '.(shift).$nl;
+    } elsif ($arg == $NOUSER) {
+      $nouser=1;
+    } elsif ($arg == $FREEHEAD) {
+      $query.=(shift).$nl;
+    } else {
+      warn "Unknown http query opcode: $arg\n";
+    } 
+    # Insert the last parts of the query:
+  }
+  
+  $query.='Host: '.$req_o->netloc.$nl;
+  $query.='From: '.$from.$nl unless $nouser;
+
+  $accept='Accept: */*'.$nl unless $accept;
+
+  if ($proxyport) {
+    # Use proxy instead of originserver
+    $host=$proxyserver;
+    $port=$proxyport;
+
+    # Add authentication stuff to query
+    if ($proxyuser) {
+      # Demand-load MIME::Base64
+      if (!defined(&MIME::Base64::encode)) {
+	eval "use MIME::Base64;";
+	die "w3http: Could not load MIME::Base64 module necessary for authentication\n"
+	  unless defined(&MIME::Base64::encode);
+      }
+      
+      $query.='Proxy-Authorization: Basic '.
+	MIME::Base64::encode($proxyuser.':'.$proxypasswd);
+
+      print STDERR "\nProxyuser: [$proxyuser]\nProxypasswd: [$proxypasswd]\n"
+	if $debug>=2;
+    }
+  }
+  
+  $query.='User-Agent: '.$agent.$nl.$accept.$nl;
+  
+  # If we're using proxy then set up things...
+  print STDERR "\nQUERY:\n",$query,"---\n" if $debug>=2;
+
+  # win32 fix: this should be added in case of troubles with
+  # gethostbyname. possible reason: nameserver down?
+  if ($host =~ /^\d+(\.\d+){3}$/) {
+    # in case gethostbyname will not work ... ;-)
+    $address{$host} = pack 'C4', (split /\./, $host);
+  }
+  
+  # Find out who to ask, check if we know already
+  if (exists($address{$host})) {
+    # We know
+    $thataddr=$address{$host};
+  } else {
+    # Cache miss, get and remember.
+    (my $fqdn, undef, undef, undef, $thataddr) = gethostbyname($host);
+    # Hostname lookup failure?  Cache even misses.
+    if (defined($fqdn)) {
+      print STDERR "Lookup of $host:\nFQDN: $fqdn\n"
+	if $debug;
+      $address{$host}=$thataddr;
+      $address{$fqdn}=$thataddr if $fqdn ne $host;
+    } else {
+      $thataddr=$address{$host}=undef;
+    }
+  }    
+
+  # Check if lookup failure, return
+  if (!defined($thataddr)) {
+    $restext='Host lookup failure';
+    return;
+  }
+
+  $port=80 unless defined($port) && $port;
+
+  # When connected we might receive SIGPIPE.  I'm not sure if the
+  # default behaviour of dying is beneficial in that case.  If we get
+  # alarm a timeout has expired.
+  $savPIPE = $SIG{'PIPE'};
+  $savALRM = $SIG{'ALRM'};
+
+  $chime=0;			# There has been no alarm yet
+  $SIG{'ALRM'} = \&timeout;
+  $SIG{'PIPE'} = \&ignore;
+
+  # Close the socket, just in case, and ignore error returns
+  close(FS);
+  
+  socket(FS, AF_INET, SOCK_STREAM, $proto) or return &oserror;
+  warn "Got my socks on\n" if $debug;
+  
+  my $paddr = sockaddr_in($port, $thataddr);
+  connect(FS, $paddr) or return &oserror;
+  warn "Connected\n" if $debug;
+  
+  # Arrange timeout
+  alarm($timeout) if $hasAlarm;
+  
+  # We have, in fact, received SIGPIPE on this line:
+  send(FS,$query,0) or return &oserror;
+
+  if ($chime) {
+    $result=100;
+    $restext='timeout sending query';
+    return &resetsign;
+  }
+  
+  $header='';
+  $document='';
+  $inp=' 'x$buflen;
+  $doclen=$chime=$plaintext=$plaintexthtml=$save=0;
+
+  # Breaks some M$ ISS servers:
+  # shutdown(FS,1);  # Half-close socket, sending now not allowed
+  
+  print STDERR ", receiving header" if $verbose>0;
+  
+  # Retrive HTTP response HEADER.  Why do I use recv and not <FS>?
+  # Because then the timeout can work correctly!
+  while (1) {
+    # Set up alarm to ensure recv returns within a reasonable timeframe
+    alarm($timeout) if $hasAlarm;
+    $err = recv(FS,$inp,$buflen,0);
+    # recv returned, cancel alarm.
+    alarm(0) if $hasAlarm;
+    
+    # If there has been a timeout, then we quit now.  The recv man page
+    # does not seem to allow recv to return the bytes received up to
+    # the timeout.
+    if ($chime) {
+      $result=100;  
+      $restext='timeout fetching document';
+      $!=0;
+      if ($save) {
+	unlink($tmpf) || 
+	  warn "Could not unlink $tmpf: $!\n";
+      }
+      return &resetsign;
+    }
+    
+    # recv returnes the undefined value on error
+    if (!defined($err)) {
+      warn "Error in recv: $!\n";
+      last;
+    }
+    
+    $linp=length($inp);
+    
+    # If the returned input was 0 in length then we've gotten to the 
+    # end of the response.
+    last unless $linp;
+    
+    # Accounting
+    $xfbytes += $linp;
+    $doclen += $linp;
+    
+    # Accumulate input
+    $header.=$inp;
+
+    # eof(SOCKET) has strange semantics it seems
+    # last if eof(FS);
+    
+    # Check if header is complete
+    last if ($header =~ m/(\r?\n\r?\n)/);
+  }
+  
+  if (length($header)==0) {
+    $restext='the HTTP reply header is empty!';
+    return &resetsign;
+  }
+  
+  if ($header =~ m/(\r?\n\r?\n)/) {
+    $header=$`;
+    $document=$';
+  } else {
+    $header=$document;
+  }
+  
+  # Adjust accounting
+  $headb = length($header)+length($1);
+  $headbytes += $headb;
+  $xfbytes -= $headb;
+  $doclen -= $headb;
+  
+  # Pick headers to pieces
+  ($result,$restext,%headval)=&analyze_header($header);
+
+  print STDERR "REPLY:\n",$header,"\n---\n" if $debug>=2;
+
+  # Check if the document is a non-encoded text document. The contents
+  # could be (x-)?compress or (x-)gzip coded (compressed in other
+  # words).
+  
+  $plaintext=defined($headval{'CONTENT-TYPE'}) &&
+    (substr($headval{'CONTENT-TYPE'},0,5) eq 'text/' || 0) &&
+      !defined($headval{'content-encoding'});
+  $plaintexthtml=$plaintext && 
+    ($headval{'CONTENT-TYPE'} eq 'text/html');
+  
+  if ($result==200) {
+    
+    # Save this to a file, or not?  Never save html files.
+    if ($saveto && !$plaintexthtml) {
+      # We're going to save this document directly into a file.  This
+      # stresses the VM less when getting the large binares so often
+      # found at cool sites.
+      $save=1;
+
+      # Find a temporary filename
+      $tmpf=url "file:$saveto";
+      $tmpf->basename($tmpfile);
+      $tmpf=$tmpf->unix_path;
+      
+      # Find suitable final filename, one with no URL escapes
+      $saveto=(url "file:$saveto")->unix_path;
+
+      # If output to stdout then send it directly there rather than
+      # using disk unnecesarily.
+      $tmpf='-' if ($saveto eq '-');
+
+      # If output is nulldevice (running -f), use it also for tmpfile,
+      # since it would otherwise try to create it in /dev under unix.
+      $tmpf=$main::nulldevice if ($saveto eq $main::nulldevice);
+      
+      warn "USING TMPFILE: $tmpf\n" if $debug;
+      
+      open(SAVE,">$tmpf") || 
+	die "Could not open tmp file: $tmpf: $!\n";
+      binmode SAVE;		# It's a binary file...
+    }
+    
+    if ($verbose>0) {
+      print STDERR ", document";
+      print STDERR "->disk" if $save;
+    }
+    
+    # Now retrive document itself.  Se comments in header loop
+    $start=time;
+    $wantbytes = defined($headval{'content-length'})?
+      $headval{'content-length'}:0;
+    
+    $ldoc=length($document);
+    
+    while (1) {
+      alarm($timeout) if $hasAlarm;
+      recv(FS,$inp,$buflen,0);
+      alarm(0) if $hasAlarm;
+      
+      if ($chime) {
+	$result=100;
+	$restext='timeout fetching document';
+	$!=0;
+	if ($save) {
+	  unlink($tmpf) || 
+	    warn "Could not unlink $tmpf: $!\n";
+	}
+	return &resetsign;
+      }
+      
+      $linp=length($inp);
+      
+      last unless $linp || $ldoc;
+      $ldoc = 0;
+      
+      $xfbytes += $linp;
+      $doclen += $linp;
+      
+      if ($verbose>0 && time-$start>5) {
+	# Write progress info ... 
+	if ($wantbytes) {
+	  $progress = sprintf " %3d%%", $doclen/$wantbytes*100;
+	} else {
+	  $progress = sprintf " %d", $doclen;
+	}
+	print STDERR $progress, "\ch"x(length($progress));
+	# ...every 5 seconds
+	$start=time;
+      }
+      
+      $document.=$inp;
+      
+      if ($save) {
+	$err = print SAVE $document;
+	die "Error writing $tmpf: $!\n" unless $err;
+	$document='';
+      }
+
+      # The eof test seems to work very oddly for sockets.
+      # last if eof(FS);
+    }
+
+    close(FS);  # Close socket completely
+    
+    print STDERR "DOCUMENT:\n----\n",$document,"\n----\n" if $debug>=255;
+  
+    if ($wantbytes &&
+	$wantbytes != $doclen) {
+      $result=100;
+      $restext='transfer error; too many bytes in document';
+      $restext='document was incomplete' if ($wantbytes > $doclen) ;
+      print STDERR "SHORT DOCUMENT" if $debug>=16;
+      if ($save) {
+	unlink($tmpf) || warn "Could not unlink $tmpf: $!\n";
+      }
+      return &resetsign;
+    }
+    
+    # warn "XFB: $xfbytes, DL: $doclen\n";
+    if ($save) {
+      close(SAVE);
+      &main::movefile($tmpf,$saveto);
+    }
+    
+    # If this is a non-encoded text file and we're supposed to convert
+    # foreign newlines then we do it. It would be faster to do this
+    # with each chunk of input in the input loop, but this gives us
+    # two problems:
+    # - A \r\n newline could be split into two chunks.  Thus escaping
+    #   newline conversion.
+    # - It messes up the received bytes accounting rather badly.
+    #
+    # This used to be a test for $plaintext, the problem is that too
+    # many documents were typed as text/plain and so we corrupted
+    # binary files. This is bad. So now we're more paranoid about it:
+    # Only HTML gets converted.
+    if ($convert && $plaintexthtml) {
+      # Change non unix newlines to unix newlines. bare \r is known
+      # from macintosh (they hadta be different didn't they?), \r\n is
+      # known as 'network format' and from numerous systems, among
+      # them ms-dos.
+      $document =~ s~\r~\n~g unless $document =~ s~\r\n~\n~g;
+      warn "Newlines converted(?)\n" if $debug;
+    }
+    
+  }				# if $result == 200
+  
+  &resetsign;
+  return 1;
+}
+
+
+sub analyze_header {
+  my($header)=@_;
+  my($result,$restext,%headval,$hdln,$key,$value);
+  
+  # Summary of the http spec on headers (with my comments):
+  # - Each header line ends in CRLF (or just LF, or maybe even just CR,
+  #   anyways, it's easier if all is LF).
+  $header =~ s/\r/\n/mg unless $header =~ s/\r\n/\n/mg;
+  # - If a line starts with space then it's a continuation of the previous
+  #   line (these I fold into one line).
+  $header =~ s/\n\s/ /mg;
+  # - The header field names are case insensitive (so I convert them to
+  #   lowercase)
+  # - A field may appear twice, that is equivalent to listing the values
+  #   in a comma separated list (so I fold them into a comma separated list)n
+  # - The field name and the field value are separated by ': '
+  ($result,$restext) = $header =~ m~^HTTP/\d\.\d (\d\d\d) (.*)~;
+  # Shave off http result code from the header
+  $header =~ s~^.*\n~~;
+  
+  warn "Header:\n$header\n---\n" if $debug>=3;
+  
+  warn "Result: $result, Text: $restext\n" if $debug>=2;
+  
+  %headval=();
+  
+  foreach $hdln (split(/\r?\n/m,$header)) {
+    ($key,$value)=split(': ',$hdln,2);
+    $key="\L$key";
+    # Strip leading&trailing space off the reply, some servers use
+    # copious space after.
+    $value =~ s/^\s+|\s+$//g;
+    print STDERR "K: '$key', V: '$value'\n" if $debug>=2;
+    if (defined($headval{$key})) {
+      $headval{$key}.=", ".$value;
+    } else {
+      $headval{$key}=$value;
+    }
+  }
+
+  # See if there are any type parameters in the content-type header
+  # and if so remove them.
+  if (defined($headval{'content-type'})) {
+    my $val=$headval{'content-type'};
+    ($val,undef)=split(';',$val,2) if ($val =~ /;/);
+    $headval{'CONTENT-TYPE'}=$val;
+  }
+  
+  return ($result,$restext,%headval);
+}
+
+
+sub last_modified {
+  # will return the last modified time for a local file as a HTTP
+  # timestamp.
+  
+  my(@tmp) = stat($_[0]);	# file doesn't exist ok to fetch
+
+  # FAT file systems strip the LSB of the file time.  Add it back in
+  # here before asking the server about a modified file.  The only way
+  # this can fail is if the newer server file was saved one second
+  # after the first version (very unlikely).  This isn't needed for
+  # NTFS file systems, but there is no good portable Perl way to
+  # determine the file system type.
+  $tmp[9] = $tmp[9] | 1 if ( $main::win32 );
+
+  # now we got the last modified in a 32 bit integer.  time to convert
+  # it and return
+  return time2str($tmp[9]);
+}
+
+
+sub timeout {
+  # Set timeout flag.  The using procedure has to set other result codes.
+  $chime=1;			# When this is 1 then the alarm has gone off
+  print STDERR "TIMEOUT!!!!\n" if $debug>=16;
+}
+
+
+sub ignore {
+  warn "I got SIGPIPE, ignoring it...\n";
+}
+
+
+sub resetsign {
+  return 0 if !defined($savALRM);
+  $SIG{'ALRM'}=$savALRM;
+  undef $savALRM;
+#  $SIG{'PIPE'}=$savPIPE;
+  return 0;
+}
+
+
+sub oserror {
+  
+  resetsign;
+
+  $result=98;
+  $restext='w3http: OS error';
+  return 0;
+
+}
+
+
+1;
Index: /main/tags/2.25/gsdl/packages/w3mir/w3mir-1.0.8/w3mfix.PL
===================================================================
--- /main/tags/2.25/gsdl/packages/w3mir/w3mir-1.0.8/w3mfix.PL	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/w3mir/w3mir-1.0.8/w3mfix.PL	(revision 21064)
@@ -0,0 +1,1070 @@
+# -*-perl-*-
+
+use Config;
+
+&read_makefile;
+$fullperl = resolve_make_var('FULLPERL') || $Config{'perlpath'};
+$islib = resolve_make_var('INSTALLSITELIB');
+
+$name = $0;
+$name =~ s~^.*/~~;
+$name =~ s~.PL$~~;
+
+open(OUT,"> $name") || 
+  die "Could open $name for writing: $!\n";
+
+print "writing $name\n";
+
+while (<DATA>) {
+  if (m~^\#!/.*/perl.*$~o) {
+    # This substitutes the path perl was installed at on this system
+    # _and_ removed any (-w) options.
+    print OUT "#!",$fullperl,$1,"\n";
+    next;
+  }
+  if (/^use lib/o) {
+    # This substitutes the actuall library install path
+    print OUT "use lib '$islib';\n";
+    next;
+  }
+  print OUT;
+}
+
+close(OUT);
+
+# Make it executable too, and writeable
+chmod 0755, $name;
+
+#### The library
+
+sub resolve_make_var ($) {
+
+  my($var) = shift @_;
+  my($val) = $make{$var};
+
+#  print "Resolving: ",$var,"=",$val,"\n";
+  
+  while ($val =~ s~\$\((\S+)\)~$make{$1}~g) {}
+#  print "Resolved: $var: $make{$var} -> $val\n";
+  $val;
+}
+
+
+sub read_makefile {
+
+  open(MAKEFILE, 'Makefile') || 
+    die "Could not open Makefile for reading: $!\n";
+
+  while (<MAKEFILE>) {
+    chomp;
+    next unless m/^([A-Z]+)\s*=\s*(\S+)$/;
+    $make{$1}=$2;
+#    print "Makevar: $1 = $2\n";
+  }
+
+  close(MAKEFILE)
+}
+
+__END__
+#!/local/bin/perl5 -w
+# Perl 5.002 or later.  w3mir is mostly tested with perl 5.004
+#
+# You might want to change or comment out this:
+use lib '/hom/janl/lib/perl';
+#
+# Can perform the following fixes:
+# - Rewrite redirected to URLs
+# - change .../ into .../index.html (or .../Welcome.html)
+# - change external links to point to some helpfull .html file ---- NOT IMPLEMENTED
+# - change links to documents not retrived to point to some helpfull
+#   .html file --- NOT IMPLEMENTED
+# - After adding a 'Also' directive we can edit the urls pointing to within
+#   the new space of the retrival scope, making the pointers consistent.
+
+# Method: 
+# 1 Gather list of all URLs to be rewritten:
+#   - Redirects: Just read the .redirs file
+#   - .../ into .../index.html: All can be found in the .referers file
+#     Remember to rewrite missing / redirects too...
+#   - external links: in the .referers file too
+#   - non-retrived documents: What files should be here (according to
+#	.referers file) but are not?
+# 2 Gather list of all documents needing editing
+# 3 Edit them
+#
+# 09/05/98 janl		- Only rewrite .../ to .../$indexname if the attribute
+#			  does not refer to a directory. -> 0.6.2
+# 12/05/98 janl		- Use ->local_path to determine filename -> 0.6.3
+# 22/05/98 janl		- .../#foo was not being rewritten to 
+#			  .../$indexname#foo -> 0.6.4
+#
+require 5.002;
+
+use vars qw($win32);
+
+# To figure out what kind of system this is
+BEGIN {
+  use Config;
+  $win32 = ( $Config{'osname'} eq 'MSWin32' ); 
+}
+
+use Carp;
+use htmlop;
+use URI::URL;
+use URI::Escape;
+
+use strict;
+
+my $VERSION;
+$VERSION='0.6.5';
+
+my $debug=0;			# Not debugging
+my $verbose=0;
+
+my $indexname='index.html';
+my $chdirto='';			# Place to chdir to after reading
+                                # config file
+
+my $infoloss=0;			# 1 if any URL translations (which
+                                # cause information loss) are in
+                                # effect.  If this is true we use the
+                                # SAVEURL operation.  What to get, and
+                                # not.  Text of user supplied
+                                # fetch/ignore rules
+
+my $doindex=1;			# append $indexname to /$ ?
+
+my $editthis='';		# Edit references matching this expression.
+
+my $files=0;			# How many files have I edited?
+my $rc='';
+
+my $rule_text="# User defined fetch/ignore rules\n";
+# Code ref to the rule procedure
+my $rule_code;
+
+# Code to prefix and postfix the generated code.  Prefix should make
+# $_ contain the url to match.  Postfix should return 1, the default
+# is to get the url/file.
+my $rule_prefix='$rule_code = sub { local($_) = shift;'."\n";
+my $rule_postfix=' return 1; } ';
+
+# Scope tests generated by URL/Also directives in cfg. The scope code
+# is just like the rule code, but used for program generated
+# fetch/ignore rules related to multiscope retrival.
+my $scope_fetch="# Automatic fetch rules for multiscope retrival\n";
+my $scope_ignore="# Automatic ignore rules for multiscope retrival\n";
+my $scope_code;
+
+my $scope_prefix='$scope_code = sub { local($_) = shift;'."\n";
+my $scope_postfix=' return 0; } ';
+
+# Function to apply to urls, se rule comments.
+my $user_apply_code;	# User specified apply code
+my $apply_code;		# w3mirs apply code
+my $apply_prefix='$apply_code = sub { local($_) = @_;'."\n";
+my $apply_lc=' $_ = lc $_; ';
+my $apply_postfix=' return $_; } ';
+my @user_apply;		# List of users apply rules.
+my @internal_apply;	# List of w3mirs apply rules.
+
+
+my $iinline='';			# inline RE code to make RE caseinsensitive 
+my $ipost='';			# RE postfix to make it caseinsensitive
+my $lc=0;			# Convert urls/filenames to lowercase?
+my $abs=0;			# Absolutify URLs?
+my $fixrc='';			# Name of w3mfix config file
+my $fixup=0;			# Do things needed to run fixup
+my $r=0;			# Recurse? no recursion = absolutify links
+my %rum_referers=();		# Array of referers, key: rum_url
+my %rum_redirected=();		# Array of redirected url: key: original url
+my %lf_edited=();		# Edited this file yet?
+my $list;			# List url on STDOUT?
+
+my %stat=();			# stat($lf_url): 'd' for dir, 'f' for others
+
+# ######################### Libwww-perl addons:
+
+sub URI::URL::_generic::unix_path {
+  my $self = (shift)->clone;
+
+  $self->frag(undef);
+  $self->scheme("file");
+  $self->unix_path;
+}
+
+
+sub URI::URL::_generic::basename {
+  my $self = shift;
+  my @p = $self->path_components;
+  my $old = $p[-1];
+  if (@_) {
+    splice(@p, -1, 1, shift);
+    $self->path_components(@p)
+  }
+  $old;
+}
+
+
+sub URI::URL::_generic::path_components {
+    my $self = shift;
+    my $old = $self->{'path'};
+    $old = '' unless defined $old;
+    $old = "/$old" if $old !~ m|^/| && defined $self->{'netloc'};
+    if (@_) {
+	$self->_elem('path',
+		     join("/", map { uri_escape($_,$URI::URL::reserved)
+				   } @_));
+    }
+    map { uri_unescape($_) } split("/", $old, -1);
+}
+
+
+# ######################### Configuration/argument parsing
+
+sub parse_args {
+  my $f;
+  my $i;
+
+  $i=0;
+
+  while ($f=shift) {
+    $i++;
+    # This is a demonstration against Getopts::Long.
+    if ($f =~ s/^-+//) {
+      $verbose=-1,next if $f eq 'q'; 		# Quiet
+      $verbose=1,next if $f eq 'c';		# Chatty
+      die "w3mfix version $VERSION\n" if $f eq 'v';	# Version
+      die "rtfm\n" if ($f eq 'help' || $f eq 'h' || $f eq '?');
+
+      if ($f eq 'editref') {
+	die "Sorry, can only have one -editref pr. run\n"
+	  if $editthis;
+	$editthis=quotemeta(shift);
+	next;
+      }
+
+      if ($f eq 'd') {	# Debugging level
+	$f=shift;
+	unless (($debug = $f) > 0) {
+	  die "w3mfix: debug level must be a number greater than zero.\n";
+	}
+	next;
+      }
+
+      # Those were all the options...
+      warn "w3mfix: Unknown option: -$f.  Use -h for usage info.\n";
+      exit(1);
+    } else {
+      # If we get this far then ... it's a configuration file name:
+      $rc = $f;
+      die "w3mfix: Got a non-option argument that wasn't the name of a\n".
+	"(configuration) file either\n"
+	  unless -f $f;
+    }
+  }
+}
+
+
+sub parse_cfg_file {
+  # Read the configuration file.  Aborts on errors.
+  # Ignores w3mir options w3mfix does not need itself.
+
+  my ( $file ) = @_ ;
+  my ($key, $value, $authserver,$authrealm,$authuser,$authpasswd);
+  my $i;
+
+  die "w3mfix: config file $file is not a file.\n" unless -f $file;
+  open(CFGF, $file) || die "Could not open config file $file: $!\n";
+
+  # print STDERR "Reading $file\n";
+
+  $i=0;
+
+  while (<CFGF>) {
+    # Trim off various junk
+    chomp;
+    s/^#.*//;
+    s/^\s+|\s$//g;
+    # Anything left?
+    next if $_ eq '';
+    # Examine remains
+    $i++;
+    ($key, $value) = split(/\s*:\s*/,$_,2);
+    $key = lc $key;
+
+    # These are no-ops in w3mfix
+    next if ( $key eq 'initial-referer' );
+    next if ( $key eq 'header' );
+    next if ( $key eq 'pause' );
+    next if ( $key eq 'retry-pause' );
+    next if ( $key eq 'retries' );
+    next if ( $key eq 'robot-rules' );
+    next if ( $key eq 'remove-nomirror' );
+    next if ( $key eq 'file-disposition' );
+    next if ( $key eq 'http-proxy' );
+    next if ( $key eq 'proxy-options' );
+    next if ( $key eq 'auth-domain' );
+    next if ( $key eq 'auth-user' );
+    next if ( $key eq 'auth-passwd' );
+    next if ( $key eq 'disable-headers' );
+    next if ( $key eq 'agent' );
+
+    $debug=numeric($value),next if ( $key eq 'debug' );
+    umask(numeric($value)),next if ( $key eq 'umask' );
+    $indexname=$value,next if ($key eq 'index-name');
+    $verbose=nway($value,'quiet','brief','chatty')-1,next
+      if ( $key eq 'verbosity' );
+
+    if ( $key eq 'cd' ) {
+      $chdirto=$value;
+      next;
+    }
+
+    if ($key eq 'url') {
+      my ($rum_url_o,$lf_dir,$rum_reurl,$rum_rebase);
+
+      # A two argument URL: line?
+      if ($value =~ m/^(.+)\s+(.+)/i) {
+	# Two arguments.
+	$rum_url_o=url $1;
+	# The last is a directory, it must end in /
+	$lf_dir=$2;
+	$lf_dir.='/' unless $lf_dir =~ m~/$~;
+
+	# The first is a URL, make it more canonical, find the base.
+	# The namespace confusion in this section is correct.(??)
+	$rum_rebase = quotemeta( ($rum_url_o->as_string =~ m~^(.*/)~)[0] );
+
+	# print "URL: ",$rum_url_o->as_string,"\n";
+	# print "Base: $rum_rebase\n";
+
+	# Translate from rum space to lf space:
+	push(@internal_apply,"s/^".$rum_rebase."/".quotemeta($lf_dir)."/");
+
+	# That translation could lead to information loss.
+	$infoloss=1;
+
+	# Fetch rules tests the rum_url_o->as_string.  Fetch whatever
+	# matches the base.
+	$scope_fetch.="return 1 if m/^".$rum_rebase."/".$ipost.";\n";
+
+	# Ignore whatever did not match the base.
+	$scope_ignore.="return 0 if m/^".
+	  quotemeta("http://".$rum_url_o->netloc."/")."/".$ipost.";\n";
+
+      } else {
+	# $rum_url_o=root_quene($value);
+
+	$rum_url_o=url $value;
+
+	$rum_rebase = quotemeta( ($rum_url_o->as_string =~ m~^(.*/)~)[0] );
+
+	# Translate from rum space to lf space:
+	push(@internal_apply,"s/^".$rum_rebase."//");
+
+	$scope_fetch.="return 1 if m/^".$rum_rebase."/".$ipost.";\n";
+	$scope_ignore.="return 0 if m/^".
+	  quotemeta("http://".$rum_url_o->netloc."/")."/".$ipost.";\n";
+      }
+      next;
+    }
+
+    if ($key eq 'also' || $key eq 'also-quene') {
+      if ($value =~ m/^(.+)\s+(.+)/i) {
+	my ($rum_url_o,$lf_dir,$rum_reurl,$rum_rebase);
+	# Two arguments.
+	$rum_url_o=url $1;
+	$rum_url_o->host(lc $rum_url_o->host);
+	# The last is a directory, it must end in /
+	$lf_dir=$2;
+	$lf_dir.='/' unless $lf_dir =~ m~/$~;
+
+	# The first is a URL, find the base
+	$rum_rebase = quotemeta( ($rum_url_o->as_string =~ m~^(.*/)~)[0] );
+
+	# Ok, now we can transform and select stuff the right way
+	push(@internal_apply,"s/^".$rum_rebase."/".quotemeta($lf_dir)."/");
+	$infoloss=1;
+
+	# Fetch rules tests the rum_url_o->as_string.  Fetch whatever
+	# matches the base.
+	$scope_fetch.="return 1 if m/^".$rum_rebase."/".$ipost.";\n";
+
+	# Ignore whatever did not match the base.  This cures problem
+	# with '..' from base in in rum space pointing within the the
+	# scope in ra space.  We introduced a extra level (or more) of
+	# directories with the apply above.  Must do same with 'Also:'
+	# directives.
+	$scope_ignore.="return 0 if m/^".
+	  quotemeta("http://".$rum_url_o->netloc."/")."/".$ipost.";\n";
+      } else {
+	die "Also: requires 2 arguments\n";
+      }
+      next;
+    }
+
+    if ($key eq 'quene') {
+      # root_quene($value);
+      next;
+    }
+
+    if ($key eq 'ignore-re' || $key eq 'fetch-re') {
+      # Check that it's a re, better that I am strict than for perl to
+      # make compilation errors.
+      unless ($value =~ /^m(.).*\1[gimosx]*$/) {
+	print STDERR "w3mfix: $value is not a recognized regular expression\n";
+	exit 1;
+      }
+    }
+
+    if ($key eq 'fetch' || $key eq 'fetch-re') {
+      my $expr=$value;
+      $expr = wild_re($expr).$ipost if ($key eq 'fetch');
+      $rule_text.=' return 1 if '.$expr.";\n";
+      next;
+    }
+
+    if ($key eq 'ignore' || $key eq 'ignore-re') {
+      my $expr=$value;
+      $expr = wild_re($expr).$ipost if ($key eq 'ignore');
+      $rule_text.=' return 0 if '.$expr.";\n";
+      next;
+    }
+
+
+    if ($key eq 'apply') {
+      unless ($value =~ /^s(.).*\1.*\1[gimosxe]*$/) {
+	print STDERR
+	  "w3mfix: '$value' is not a recognized regular expression\n";
+	exit 1;
+      }
+      push(@user_apply,$value) ;
+      $infoloss=1;
+      next;
+    }
+
+    if ($key eq 'options') {
+      
+      my($val,$nval);
+      foreach $val (split(/\s*,\s*/,lc $value)) {
+	if ($i==1) {
+	  $nval=nway($val,'recurse','no-date-check','only-nonexistent',
+		     'list-urls','lowercase','remove','batch','read-urls',
+		     'abs');
+	  $r=1,next if $nval==0;
+	  next if $nval==1;
+	  next if $nval==2;
+	  $list=1,next if $nval==3;
+	  if ($nval==4) {
+	    $lc=1;
+	    $iinline=($lc?"(?i)":"");
+	    $ipost=($lc?"i":"");
+	    next ;
+	  }
+	  next if $nval==5;
+	  next if $nval==6;
+	  next if $nval==7;
+	  $abs=1,next if $nval==8;
+        } else {
+	  die "w3mfix: options must be the first directive in the config file.\n";
+	}
+      }
+    }
+
+    if ($key eq 'fixup') {
+
+#      chomp($fixrc=`pwd` || '.');
+#      $fixrc.="/$file";
+#      warn "Fixrc: $fixrc\n";
+#      $fixup=1;
+
+      my($val,$nval);
+      foreach $val (split(/\s*,\s*/,lc $value)) {
+	$nval=nway($val,'on','run','noindex');
+	next if $nval==0;
+	next if $nval==1;
+	$doindex=0 if $nval==2;
+	# Ignore everyting else
+      }
+    }
+
+  }
+  close(CFGF);
+}
+
+sub wild_re {
+  # Here we translate unix wildcard subset to to perlre
+  local($_) = shift;
+  s#\*#\.\*#;
+  s#\?#\.#;
+  s#([\/\(\)\\\|\{\}\+)\$\^])#\\$1#g;
+  return $_ = '/'.$_.'/';
+}
+
+
+sub numeric {
+  # Check if argument is numeric?
+  my ( $number ) = @_ ;
+  return oct($number) if ($number =~ /\d+/ || $number =~ /\d+.\d+/);
+  die "Expected a number, got \"$number\"\n";
+}
+
+
+sub boolean {
+  my ( $boolean ) = @_ ;
+
+  $boolean = lc $boolean;
+
+  return 0 if ($boolean eq 'false' || $boolean eq 'off' || $boolean eq '0');
+  return 1 if ($boolean eq 'true' || $boolean eq 'on' || $boolean eq '1');
+  die "Expected a boolean, got \"$boolean\"\n";
+}
+
+
+sub nway {
+  my ( $value ) = shift;
+  my ( @values ) = @_;
+  my ( $val ) = 0;
+
+  $value = lc $value;
+  while (@_) {
+    return $val if $value eq shift;
+    $val++;
+  }
+  die "Expected one of ".join(", ",@values).", got \"$value\"\n";
+}
+
+
+sub stat {
+
+  my $file = shift;
+
+  if (exists($stat{$file})) {
+    print STDERR "++Cache hit: $file\n" if $debug;
+  } else {
+    stat($file);
+    if (-e _) {
+      $stat{$file}=(-d _)?'d':'f';
+    } else {
+      $stat{$file}='n';
+    }
+    print STDERR "--Cache miss: $file\n" if $debug;
+  }
+  return $stat{$file};
+}
+
+# ######################## Read 'state' files ##############################
+
+sub read_state {
+
+  my $reffile='.referers';
+  my $refered;
+  my @referers;
+
+  $reffile="referers" if $win32;
+
+  print STDERR "reading $reffile\n" if $verbose>0;
+  open(REFERERS,"< $reffile") ||
+    die "Could not open $reffile for reading: $!\n";
+
+  while (<REFERERS>) {
+    chomp;
+    ($refered,undef,@referers) = split(/\s+/);
+    $rum_referers{$refered}= [ @referers ];
+    # print STDERR $refered," <- ",join(' and ',@referers),"\n";
+  }
+
+  close(REFERERS);
+
+
+  # Read redirection report
+
+  my $redirfile='.redirs';
+  my $wrong;
+  my $right;
+  my $tmp;
+
+  $redirfile="redirs" if $win32;
+
+  print STDERR "reading $redirfile\n" if $verbose>0;
+  open(REDIRS,"< $redirfile") ||
+    die "Could not open $redirfile for reading: $!\n";
+
+  while (<REDIRS>) {
+    chomp;
+    ($wrong,undef,$right) = split(/\s+/);
+
+    $rum_redirected{$wrong}=$right;
+  }
+
+  close(REDIRS);
+}
+
+# ######################### Process every single tag ########################
+
+sub process_tag {
+  # Process a tag in html file
+  my $lf_referer = shift;
+  my $base_url = shift;
+  my $tag_name = shift;
+  my $url_attrs = shift;
+
+  # Retrun quickly if no URL attributes
+  return unless defined($url_attrs);
+
+  my $attrs = shift;
+
+  # Information loss through apply or processing in this procedure?
+  my $il = $infoloss; 
+  my $redirs;
+  my $stat;
+
+  my $rum_url;	# The absolute URL
+  my $lf_url;	# The local filesystem url
+  my $lf_url_o; # ... and it's object
+  my $key;
+  my $orig_rum_url;
+#  my $debug = 1;
+
+#  print STDERR "\nProcess Tag: $tag_name, URL attributes: ", join(', ',@{$url_attrs}),"\nOrigin:",$base_url,"\n"; # if $debug>2;
+
+  substr($lf_referer,0,0)='./' unless substr($lf_referer,0,1) eq '/';
+
+  foreach $key (@{$url_attrs}) {
+    if (defined($$attrs{$key})) {
+      $orig_rum_url=$rum_url=$$attrs{$key};
+
+      print STDERR "\n$key = $rum_url\n" if $debug;
+
+      # Apply redirects:
+      $redirs=0;
+      if (exists($rum_redirected{$rum_url})) {
+	$il=1;
+	while (exists($rum_redirected{$rum_url})) {
+	  die "Too many redirects in a row\n" if $redirs++>32;
+	  print STDERR "$rum_url -> ".$rum_redirected{$rum_url}."\n"
+	    if $debug;
+	  $rum_url=$rum_redirected{$rum_url};
+	}
+      }
+
+      # Apply program/user apply rules
+      $lf_url=apply($rum_url);
+
+      if (defined($lf_url)) {
+	# Apply directory/file check here
+	$stat=&stat($lf_url);
+
+	if ($stat eq 'f' && $lf_url =~ m~/$~) {
+	  # It's a file, remove trailing /
+	  print STDERR "****** File / fixup of $lf_url\n" if $debug;
+	  $il=1;
+	  substr($lf_url,length($lf_url)) = '';
+	} elsif ($stat eq 'd' && !($lf_url =~ m~/$~) ) {
+	  # It's a directory, add a trailing /
+	  print STDERR "****** Directory / fixup of $lf_url\n" if $debug;
+	  $il=1;
+	  $lf_url .= '/';
+	}
+
+	substr($lf_url,0,0)='./' unless substr($lf_url,0,1) eq '/';
+
+	$lf_url_o=url $lf_url;
+	my $tmp=$lf_url_o->clone;
+	$tmp->basename($indexname);
+
+	if ( $doindex && $lf_url_o->basename eq "" && 
+	     &stat($tmp->unix_path) eq 'f' &&
+	     !$htmlop::isdir{$key}) {
+	  $lf_url_o=$tmp;
+	  $il=1;
+	  print STDERR "indexname adjusted to ",$lf_url_o->as_string,"\n"
+	    if $debug;
+	}
+		 
+	# Save new value in the hash, make it a file url to get 'rel' working
+	$lf_url_o->scheme('file');
+	$$attrs{$key} = ($lf_url_o->rel("file:".$lf_referer))->as_string;
+
+	printf STDERR "Saved ".$$attrs{$key}."\n" if $debug;
+
+	# If there is potential information loss save the old value too
+	$$attrs{"W3MIR".$key}=$orig_rum_url if $il;
+
+      } elsif ($redirs>0) {
+	$$attrs{$key}=$rum_url;
+	print STDERR "Saved ".$$attrs{$key}."\n" if $debug;
+	$$attrs{"W3MIR".$key}=$orig_rum_url;
+      }
+    }
+  }
+}
+
+
+# ###################### Edit the URLs in one file... ########################
+
+sub edit_html_file {
+  # Check if it's a html file.  I know this tag is in all html
+  # files, because w3mir put it there.
+
+  my($lf_url)=shift;
+  my($rum_url)=shift;
+
+  # Figure out the filename for our local filesystem.
+  $lf_url.=$indexname if $lf_url =~ m~/$~ || $lf_url eq '';
+
+  # Stuff in need of unquoting?
+  $lf_url = (url "file:$lf_url")->local_path if $lf_url =~ /\%\d\d/;
+
+  if (exists($lf_edited{$lf_url})) {
+    print STDERR "Already edited $lf_url\n" if $debug;
+    return ;
+  }
+
+  $lf_edited{$lf_url}=1;
+
+  my $page;
+  my $newpage;
+  my $read;
+  my $atime;
+  my $mtime;
+
+  # dev  uno   mode  nlink uid   gid   rdev  size  atime mtime
+  (undef,undef,undef,undef,undef,undef,undef,undef,$atime,$mtime)
+    = stat($lf_url);
+
+  if (!open(TMPF,"< $lf_url\n")) {
+    warn "Cannot read $lf_url: $!\n" if $verbose>=0;
+    return;
+  }
+
+  $read=sysread(TMPF,$page,10240,0);
+  close(TMPF);
+
+  if (! $page =~ /<HTML/i) {
+    print STDERR "$lf_url is not html\n" if $verbose>0;
+    return ;
+  }
+
+  $files++;
+
+  print STDERR "w3mfix: $lf_url" if $verbose>=0;
+  
+  print STDERR "$lf_url is a html file\n" if $debug;
+
+  print STDERR " reading" if $verbose>0;
+  
+  open(TMPF,$lf_url) || 
+    die "Could not open $lf_url for reading: $!\n";
+  # read the whole file.
+  {
+    local($/)=undef;
+    $page = <TMPF>;
+  }
+  close(TMPF);
+
+  print STDERR " ",length($page)," bytes" if $verbose>0;
+
+  # It's a html document
+
+  print STDERR ", editing" if $verbose>0;
+
+  ($newpage,undef) = 
+    &htmlop::process($page, # $htmlop::NODOC,
+		     $htmlop::ABS,$rum_url,
+		     $htmlop::USESAVED,'W3MIR',
+		     $htmlop::TAGCALLBACK,\&process_tag,$lf_url);
+
+  open(TMPF,">$lf_url") ||
+    die "\nCould not open $lf_url for writing: $!\n";
+  
+  print STDERR ", saving" if $verbose>0;
+
+  if (length($newpage)) {
+    # This is ODD: close does not seem to flush the buffers.  So we
+    # force the issue.
+    local($|)=1;
+    print TMPF $newpage || 
+      die "\nCould not write to $lf_url (disk full?): $!\n";
+  }
+
+  close(TMPF) || 
+    die "\nCould not close $lf_url after writing: $!\n";
+
+  # Set times back to what they were.
+  utime $atime,$mtime,$lf_url;
+
+  print STDERR ".\n" if $verbose>=0;
+}
+
+# ############################### Scope test
+
+sub want_this {
+  # Find out if we want the url passed.  Just pass it on to the
+  # generated functions.
+  my($rum_url)=shift;
+
+  # Does scope rule want this?
+  return &$scope_code($rum_url) &&
+    # Does user rule want this too?
+    &$rule_code($rum_url) 
+  
+}
+
+# ############################### Apply the apply rules
+
+sub user_apply {
+  # Apply the user apply rules
+  return &$user_apply_code(shift);
+}
+
+
+sub internal_apply {
+  # Apply the w3mir generated apply rules
+  return &$apply_code(shift);
+}
+
+
+sub apply {
+  # Apply the user apply rules.  Then if URL is wanted return result of
+  # w3mir apply rules.  Return the undefined value otherwise.
+
+  my $url = user_apply(shift);
+
+  return undef unless want_this($url);
+
+  internal_apply($url);
+}
+
+# ############################### Decide what URLs to edit
+
+sub edit_as_needed {
+  my $rum_redirected;
+  my $rum_url;
+  my $o_rum_url;
+  my $rum_referer;
+  my $lf_url;
+  my $foo;
+  my $redirs;
+
+  if ($editthis) {
+
+    # Find the URLs that match $edithis
+    foreach $o_rum_url (keys %rum_referers) {
+      # Work on them if they (now) fall within the scope of retrival
+      $redirs=0;
+      $rum_url=$o_rum_url;
+      if (exists($rum_redirected{$o_rum_url})) {
+	while (exists($rum_redirected{$rum_url})) {
+	  die "Too many redirects in a row\n" if $redirs++>32;
+	  print STDERR "$rum_url -> ".$rum_redirected{$rum_url}."\n"
+	    if $debug;
+	  $rum_url=$rum_redirected{$rum_url};
+	}
+      }
+      next unless $rum_url =~ /$editthis/io;
+      next unless want_this($rum_url);
+      # Find and edit the documents containing references to $o_rum_url
+      foreach $rum_referer (@{$rum_referers{$o_rum_url}}) {
+	next if $rum_referer eq '(commandline)';
+	$lf_url=apply($rum_referer);
+	next unless defined($lf_url);
+	edit_html_file($lf_url,$rum_referer);
+      }
+    }
+    
+    # Don't do anything else when invoked thus
+    return;
+  }
+
+  if ($doindex) {
+    # Edit everything that refers anything with trailing /
+    foreach $rum_url (grep(/\/$/,keys %rum_referers)) {
+      foreach $rum_referer (@{$rum_referers{$rum_url}}) {
+	next if $rum_referer eq '(commandline)';
+	$lf_url=apply($rum_referer);
+	next unless defined($lf_url);
+	edit_html_file($lf_url,$rum_referer);
+      }
+    }
+  }
+
+  # Edit only redirected stuff
+  foreach $rum_redirected (keys %rum_redirected) {
+    # print "Redirected $rum_redirected\n";
+    foreach $rum_url (@{$rum_referers{$rum_redirected}}) {
+      # print "- Found in $rum_url\n";
+      $lf_url=apply($rum_url);
+      next unless defined($lf_url);
+      edit_html_file($lf_url,$rum_url);
+    }
+  }
+}
+
+# ############################### 'main'
+
+&parse_args(@ARGV);
+
+if (!$rc) {
+  $rc='.w3mirc';
+  $rc='w3mir.ini' if $win32;
+}
+
+print STDERR "w3mfix: rc file: $rc\n" if $verbose>0;
+
+&parse_cfg_file($rc);
+
+# $chdirto is ignored, w3mir already did it
+
+# Compile second order code
+
+# - The rum scope tests
+my $full_rules=$scope_prefix.$scope_fetch.$scope_ignore.$scope_postfix;
+eval $full_rules;
+
+# warn "Scope rules:\n-------------\n$full_rules\n---------------\n";
+
+die "Program generated rules did not compile.  The code is:\n----\n".
+  $full_rules."\n----\n"
+  if !defined($scope_code);
+
+$full_rules=$rule_prefix.$rule_text.$rule_postfix;
+eval $full_rules;
+
+# warn "User rules:\n-------------\n$full_rules\n---------------\n";
+
+# - The user specified rum tests
+die "Ignore/Fetch rules did not compile.  The code is:\n----\n".
+  $full_rules."\n----\n"
+  if !defined($rule_code);
+
+# - The user specified apply rules
+
+my $full_apply=$apply_prefix.($lc?$apply_lc:'').
+  join($ipost.";\n",@user_apply).(($#user_apply>=0)?$ipost:"").";\n".
+  $apply_postfix;
+eval $full_apply;
+
+die "User apply rules did not compile. The code is:
+----
+".$full_apply."
+----\n" if !defined($apply_code);
+
+$user_apply_code=$apply_code;
+
+# - The w3mir generated apply rules
+
+$full_apply=$apply_prefix.($lc?$apply_lc:'').
+  join($ipost.";\n",@internal_apply).(($#internal_apply>=0)?$ipost:"").";\n".
+  $apply_postfix;
+eval $full_apply;
+
+die "Internal apply rules did not compile.  The code is:
+----
+".$full_apply."
+----\n" if !defined($apply_code);
+
+&read_state;
+
+&edit_as_needed;
+
+exit 0;
+__END__
+# -*- perl -*-  There must be a blank line here:
+
+=head1 NAME
+
+w3mfix - fixup program for w3mir
+
+=head1 SYNOPSIS
+
+B<w3mfix> [B<options>] [B<configuration-file>]
+
+=head1 DESCRIPTION
+
+B<w3mfix> is the companion program to L<w3mir>.  It can be used for
+several URL editing operations usefull in different situations.  
+
+When starting B<w3mfix> will read it's configuration file.  It's name is 
+either .w3mirc (w3mir.ini on win32) or specified on the commandline.
+
+B<w3mfix> is controlled by the 'Fixup' directive of the configuration
+file (described in the L<w3mir> documentation).  B<w3mfix> is also
+affected by 'Index-name' and the one special commandline option it
+knows, as well as the directives/options controlling verbosity and
+debugging information.
+
+=head1 DESCRIPTION
+
+B<w3mfix> can rewrite URLs in these ways:
+
+=over 4
+
+=item * Rewrite URLs that resutled in redirects to point to the place
+redirected to.  This is needed in all cases and will always be fixed
+by B<w3mfix>.
+
+=item * Change URLs ending in .../ into .../index.html (or
+.../Welcome.html).  This is, probably, not needed when the mirror is
+meant do be used with a web-server.  It is usefull for browsing
+directly from disk or CDROM, but in this case it's, most often,
+required.  To disable this specify the I<noindex> option with the
+'Fixup' directive.
+
+The default is to transform URLs ending in .../ into .../index.html.
+
+To controll the name of the index file use the I<Index-name> directive
+as documented in L<w3mir>
+
+=item * Change URL links to documents outside the mirror to point to
+some local document.  Could be usefull if the mirror is destined for a
+CDROM to be used on a unconnected machine.
+
+THIS IS NOT YET IMPLEMENTED
+
+=item * Change URL links to documents that L<w3mir> was
+unable/forbidden to retrive to point to some local document.  Pointing
+these to a nice informative document is probably better than random
+error messages from the browser.
+
+THIS IS NOT YET IMPLEMENTED
+
+=item * And, least, but far from last, B<w3mfix> can be used to
+prepare an established mirror for enlargement.
+
+This feature is used thus: Add the new site or subsite to be mirrored
+on the configuration file (by adding B<Also:> and B<Also-quene:>
+directives).  Then run B<w3mfix> with the B<-editref> option.  When
+the B<-editref> option is specified B<w3mfix> will not perform any
+other editing tasks.
+
+E.g.; To add I<http://www.yahoo.com/Science/Artificial_Life/> to your
+mirror add something like
+
+	  Also: http://www.yahoo.com/Science/Artificial_Life/ yahoo
+
+to the configuration file, then run w3mfix:
+
+	  w3mfix -editref www.yahoo.com/Science/Artificial_Life
+
+This will cause all references to
+I<www.yahoo.com/Science/Artificial_Life> (and under) to be edited so they
+point to within the mirror.  After B<w3mfix> has finished you can run
+L<w3mir> in the normal manner.
+
+=back
+
+=head1 BUGS
+
+Naah.
+
+=head1 SEE ALSO
+
+L<w3mir>
+
+=head1 AUTHORS
+
+B<w3mir>s authors can be reached at I<w3mir-core@usit.uio.no>.
+B<w3mir>s home page is at http://www.math.uio.no/~janl/w3mir/
+
Index: /main/tags/2.25/gsdl/packages/w3mir/w3mir-1.0.8/w3mir-HOWTO.html
===================================================================
--- /main/tags/2.25/gsdl/packages/w3mir/w3mir-1.0.8/w3mir-HOWTO.html	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/w3mir/w3mir-1.0.8/w3mir-HOWTO.html	(revision 21064)
@@ -0,0 +1,943 @@
+<!doctype html public "-//W3C//DTD HTML 4.0//EN">
+<html>
+<head>
+<title>W3MIR HOWTO</title>
+<style type="text/css">
+<!--
+  body { background-color: white }
+  h1, h2, h3, b { font-family: sans-serif }
+  .red { color: red }
+-->
+</style>
+<body>
+<h1>W3MIR HOWTO</h1>
+
+<p><b>Corresponding to w3mir version 1.0.2 and above</b>
+
+<p>W3mir is an all purpose WWW copying and mirroring program.  Its
+main focus is copying complete directory structures keeping your copy
+browseable through a web server, or directly off a disk or CDROM if
+you want.  W3mir will fix URLs that are redirected and everything else
+that needs to be fixed to make your copy browseable.  But it also does
+odd jobs, retrieving single documents, batch getting several documents
+and more.  You may tell w3mir not to change anything in the retrieved
+documents.  W3mir has been in development quite a long time so you
+find options to do a lot of things needed when copying things off the
+web.
+
+<p>With w3mir you may copy the entire contents a web server.  Or just
+a directory hierarchy, or several related hierarchies off as many
+servers as you like.  They don't even have to be related.
+
+<p>W3mir supports HTML4, and has partial support for CSS, Java,
+ActiveX and Adobe Acrobat (PDF) files.  And it works on Win32
+machines.
+
+<p><b>Warning:</b> W3mir enables you to copy a lot of things off the
+Web, but remember, the things you retrieve might be copyrighted and
+the copy you make with w3mir might in fact be illegal to make and
+posses.
+
+<hr>
+
+<h2><a name="contents">Contents</a></h2>
+
+<p><a href="#intro">README</a> (You want to read this!  <b
+class="red">Really!</b>)
+
+<p><b>How do I...</b>
+<ol>
+  <li><p><a href="#copy">copy a file?</a>
+  <li><p><a href="#recurse">copy a directory hierarchy?</a>
+  <li><p><a href="#resources">copy the needed resource files from another
+    directory hierarchy?</a>
+  <li><p><a href="#ignore">avoid copying files I don't want or copy only
+    files I want?</a>
+  <li><p><a href="#rm">remove the files that are no longer on the
+    original site from the mirror?</a>
+  <li><p><a href="#depth">limit how deep w3mir will recurse?</a>
+  <li><p><a href="#memory">limit w3mirs memory usage?</a>
+  <li><p><a href="#multi">copy files from multiple sites?</a>
+  <li><p><a href="#alias">copy files from one server with several names?</a>
+  <li><p><a href="#aborted">restart a mirror process after stopping it
+    prematurely?</a>
+  <li><p><a href="#enlarge">enlarge or prune an established mirror?</a>
+  <li><p><a href="#cat">'cat' a file?</a>
+  <li><p><a href="#list">list URLs in a document?</a>
+  <li><p><a href="#robots">disable robots.txt obedience?</a>
+  <li><p><a href="#corrupt">stop w3mir from corrupting binary files?</a>
+  <li><p><a href="#auth">copy a site that wants user-name and password?</a>
+  <li><p><a href="#mauth">access a site that wants several different
+    user-names and passwords?</a>
+  <li><p><a href="#proxy">use a proxy server?</a>
+  <li><p><a href="#pauth">authenticate myself to a proxy server?</a>
+  <li><p><a href="#proxytweak">ensure that the proxy server ...?</a>
+  <li><p><a href="#batchget">batch get files with w3mir?</a>
+  <li><p><a href="#cgi">handle CGI?</a>
+  <li><p><a href="#imap">handle server side image-maps?</a>
+  <li><p><a href="#java">handle Java and ActiveX?</a>
+  <li><p><a href="#script">handle java-script and other script languages?</a>
+  <li><p><a href="#css">handle the other things with 'partial support'?</a>
+  <li><p><a href="#anon">keep my identity secret?</a>
+  <li><p><a href="#ns">pretend that I'm using Netscape, Internet
+    Explorer or Lynx?</a>
+  <li><p><a href="#other">do other things?</a>
+</ol>
+
+<hr>
+
+<h2><a name="intro">README</a></h2>
+
+<p>W3mir may be used in two, main, ways:
+
+<ul>
+  <li><p>To copy something random once.
+  <li><p>To keep a local mirror of some remote site
+</ul>
+
+<p>To copy something random once there is a high likeliness you can
+just start w3mir with some simple options and it will do the job you
+want it to.  Providing that the remote site is not too complex and
+your expectations of the copy aren't high :-) This is what wget, the
+gnu w3 mirroring program, does and is good at.
+
+<h3>Configuration file</h3>
+
+<p>Once you want to keep a copy of a remote site up-to-date over time,
+mirror something with server side image-maps, redirects or
+authentication you have to write a configuration file for w3mir.  This
+is what w3mir is good at, compared to wget.  Writing the file is not
+hard, and there are two example files in the w3mir distribution.  It
+will also be explained here.  The configuration file is typically
+called <tt>.w3mirc</tt> (<tt>w3mir.ini</tt> on win32 machines), and
+can be written with a simple text editor.  It is kept in the top
+directory of the mirror, where w3mir will find it when it starts.
+Please refer to the <a href="#contents">contents</a> for how to handle
+a specific problem with a configuration file.
+
+<hr>
+
+<h2>The answers:</h2>
+
+<hr>
+
+<h3><a name="copy">How do I copy a file?</a></h3>
+
+<p>To copy the top page off www.starwars.com:
+
+<p><tt>w3mir http://www.starwars.com/</tt>
+
+<p><b>Note:</b> it is <em>important</em> that you give the trailing
+slash for server names and directories.
+
+<hr>
+
+<h3><a name="recurse">How to I copy a directory hierarchy?</a></h3>
+
+<p>To copy the entire stuff about episode I from www.starwars.com
+which is stored in <tt>http://www.starwars.com/episode-i/</tt> (I don't
+recommend this, it's quite a lot of data):
+
+<p><tt>w3mir -r http://www.starwars.com/episode-i/</tt>
+
+<p>The corresponding configuration file is simple:
+
+<pre>
+Options: recurse
+URL: http://www.starwars.com/episode-i/
+Fixup: run
+</pre>
+
+<p>The <tt>-r</tt> option makes w3mir recurse down from the starting
+point.  It will only copy all the documents under
+http://www.starwars.com/episode-i/ that it sees referenced from those
+same documents.  W3mir will <em>not</em> retrieve documents from
+http://www.starwars.com/ because it is considered to be 'over' the
+starting point.
+
+<p>The command-line will get you a copy that is definitely browseable
+via a WEB server, and possibly browseable directly from a CDROM or
+hard-disk.  To ensure that it is browseable from CDROM and disk you
+need to use a configuration file with the <tt>Fixup: run</tt> line in.
+It causes w3mir to edit anything that needs editing after the mirror
+has completed, including fixing URLs that caused redirects.  The dirty
+work is done by w3mirs helper program w3mfix.  The directive will
+cause w3mfix to be run each time w3mir completes the mirror.
+
+<p><b>Note:</b> it is <em>important</em> that you give the trailing
+slash after the directory name.  Specifying
+<tt>http://www.starwars.com/episode-i</tt> and
+<tt>http://www.starwars.com/episode-i/</tt> is quite different in
+w3mirs eyes.  In the former case episode-i is considered to be a
+document within the / (top) directory of www.starwars.com and w3mir
+will recurse from /, which is a lot more than you wanted.  In the
+latter case w3mir understands that episode-i is a directory and will
+consider that directory to be the staring point, which is what you
+wanted.
+
+<hr>
+
+<h3><a name="resources">How do I copy the needed resource files from
+another directory hierarchy?</a></h3>
+
+<p>Some sites store their documents in one place, and puts their
+banners, icons and such in a separate directory called
+<tt>/images</tt>, <tt>/banners</tt>, <tt>/icons</tt>,
+<tt>/resources</tt> or some such.  Unless you retrieve these as well as
+the documents things will probably not be too colorful.  So, imagine
+that the starwars site stored all the images in one holding directory
+called <tt>/imagery</tt> and you want to copy all the stuff in it that
+the episode-i pages need.  Then you do this:
+
+<pre>
+Options: recurse
+URL: http://www.starwars.com/episode-i/ episode-i
+Also: http://www.starwars.com/imagery/ imagery
+Fixup: run
+</pre>
+
+<p>There are two changes here compared to the simpler file we started
+with: There is an extra argument at the end of the URL directive.  It
+tells w3mir to store everything gotten from
+<tt>http://www.starwars.com/episode-i/</tt> in the subdirectory
+<tt>episode-i</tt>.  The directory can be omitted, but I think its
+neater this way.  Then the new directive 'Also:'.  It tells w3mir that
+you also want whatever the documents under
+<tt>http://www.starwars.com/episode-i/</tt> references under
+<tt>http://www.starwars.com/imagery/</tt>.
+
+<p><b>Note:</b> this will only get stuff that was used by the
+documents under <tt>http://www.starwars.com/episode-i/</tt>, anything
+stored under <tt>http://www.starwars.com/imagery/</tt> which is not
+used will not be retrieved. If you want everything under
+<tt>imagery</tt> to be retrived use the <tt>Also-quene:</tt>
+directive.
+
+<hr>
+
+<h3><a name="ignore">How do I avoid copying files I don't want or copy
+only files I want?</a></h3>
+
+<p>To control what files w3mir copies you can use the
+<tt>Ignore:</tt>, <tt>Fetch:</tt>, <tt>Ignore-RE:</tt> and
+<tt>Fetch-RE:</tt> directives in the configuration file.  The embeded
+references to any file you chose to ignore, i.e., not copy, will point
+at the original site, <em>not</em> to the mirror.  This means that the
+mirror user may still get ahold of the file from the original source
+by simply clicking if she so desires.
+
+<p>If a site contains huge .wav audio files that you are not
+interested in you put
+
+<pre>
+Ignore: *.wav
+</pre>
+
+<p>in the configuration file.  You may ignore as many different
+filename patterns as you want.  If you are mirroring a site you want
+very few, specific files from, say all HTML (named
+<em>something</em><tt>.html</tt>) and all Mpeg video files (named
+<em>something</em><tt>.mpg</tt>) you can write this:
+
+<pre>
+Fetch: *.html
+Fetch: *.mpg
+Ignore: *
+</pre>
+
+<p>W3mir will test each filename against each Fetch/Ignore rule in
+sequence.  A html file will match the first line and be fetched.  Any
+mpg file will match the second line and be fetched.  All other files
+will match the third line, and be ignored.  This last line is needed
+because the default is to get any files which are not ignored.  By
+arranging fetch and ignore rules carefully you may retrieve exactly
+the filename patterns you want and not retrieve anything else.
+
+<p>If you decide you also want all Mpeg Layer 3 audio files
+(<em>something.</em><tt>mp3</tt>) from the site, after the mirror has
+been established.  Then you add this:
+
+<pre>
+Fetch: *.mp3
+</pre>
+
+<p>as the third line, making the <tt>Ignore: *</tt> line the forth and
+last.  Then you must fix all references to .mp3 files within the
+mirror by running w3mfix thus:
+
+<pre>
+w3mfix -editref .mp3
+</pre>
+
+<p>which will edit all references to .mp3 files, pointing them the
+right place, on your disk. Ditto when you remove a fetch rule, or add
+or remove an ignore rule. See the answer about <a
+href="#enlarge">enlarging and pruning</a> mirrors for more examples of
+using <tt>w3mfix -editme ...</tt>
+
+<p><b>Note:</b> when retrieving only a very limited set of files, as
+in the example above, you <em>must</em> retrieve the html files,
+because how else will w3mir find URLs of files to retrieve? Only html
+files contain links to other files.
+
+<p>Similarly, you may chose to not mirror whole branches of the
+original site.  If you for example mirror my home-pages, and you decide
+not to mirror the comics pages you can put
+
+<pre>
+Ignore: /ts/
+</pre>
+
+<p>or more precisely
+
+<pre>
+Ignore: http://www.ifi.uio.no/~janl/ts/
+</pre>
+
+<p>in the configuration file.  If you do this after having established
+the mirror you use w3mfix to fix the references:
+
+<pre>
+w3mfix -editref /ts/
+</pre>
+
+<p><tt>Fetch:</tt> and <tt>Ignore:</tt> rules can only use a very
+limited subset of the Unix wild-cards.  w3mir understands only '?',
+'*', and '[a-z]' ranges.
+
+<p><tt>Ignore-RE:</tt> and <tt>Fetch-RE:</tt> are the same as
+<tt>Fetch:</tt> and <tt>Ignore:</tt> except that they give you access
+to the full power of Regular Expressions to make rules for that to get
+or not to get. They support perls superset of the normal Unix regular
+expression syntax.  They must be completely specified, including the
+prefixed m, a delimiter of your choice (except the paired delimiters:
+parenthesis, brackets and braces), and any of the RE modifiers. I.e.,
+
+<pre>
+Ignore-RE: m/.gif$/i
+</pre>
+
+<p>or
+
+<pre>
+Ignore-RE: m~/.*/.*/.*/~
+</pre>
+
+<p>and so on.  "#" cannot be used as delimiter as it is the comment
+character in the configuration file.
+
+<p>There are some traps when using <tt>Ignore-RE</tt> and
+<tt>Fetch-RE</tt>, please see their documentation in <tt>mandoc
+w3mir</tt> for a more complete explanation.
+
+<hr>
+
+<h3><a name="depth">How do I limit how deep w3mir will recurse?</a></h3>
+
+<p>W3mir has no explicit mechanism to limit the depth of recursion,
+but the same result can be achieved with a simple <tt>Ignore</tt> rule:
+
+<pre>
+Ignore: /*/*/*/*/*/*/
+</pre>
+
+<p>This will ignore any URLs that contain at least 7 slashes ("/").
+Note that a URL contains three slashes that does not have anything to
+do with depth:
+
+<pre>
+http://www.ifi.uio.no/
+</pre>
+
+<p>so only the surplus slashes are used for depth in this match.  In the
+example above the limit is 4 levels from the top.  The
+<tt>Ignore:</tt> rule that is used to limit recursion depth must be
+listed before any <tt>Fetch:</tt> rules to be effective.
+
+<hr>
+
+<h3><a name="memory">How do I limit w3mirs memory usage?</a></h3>
+
+<p>In a mirror consisting of <em>many</em> files, such as a archive of
+an active mailinglist w3mir will build a very large referer table, in
+part for w3mir to use in the <tt>Referer:</tt> header and in part for
+w3mfix to use in fixing references.
+
+<p>If you disable both the <tt>Referer:</tt> header and don't use
+w3mfix w3mir will not build a referer table.  You do this in the
+configuration file:
+
+<pre>
+Disable-headers: referer
+Fixup: off
+</pre>
+
+<p>Please note the potential problems of turning off fixup described
+earlier in this howto.  There are normaly no problems associated with
+simple sites, but if there are redirects fixup <em>is</em> needed for
+a consistent mirror.
+
+<hr>
+
+<h3><a name="rm">How do I remove the files are no longer on the
+original site from the mirror?</a></h3>
+
+<p>Over time the site you mirror will add files, and quite possibly
+remove files.  Or you might introduce new <tt>Ignore:</tt> rules after
+establishing the mirror that reduces the files wanted in the mirror.
+
+<p>By default w3mir will not delete such old files, some people might
+want to keep the files even if they are removed from the original
+site.  To remove the old/unwanted files you add 'remove' to the
+<tt>Options:</tt> line.
+
+<hr>
+
+<h3><a name="multi">How do I copy files from multiple sites?</a></h3>
+
+<p>In the answer to the previous question we see how to mirror several
+related sites.  For example, say you want to mirror all my home-pages
+into one mirror:
+
+<pre>
+Option: recurse
+URL: http://www.math.uio.no/~janl/ math/janl
+Also: http://www.math.uio.no/drift/personer/ math/drift
+Also: http://www.ifi.uio.no/~janl/ ifi/janl
+Also: http://www.mi.uib.no/~nicolai/ math-uib/nicolai
+</pre>
+
+<p>As in the previous example this will only get documents that are
+referenced.  Any documents that are stored at these location but to
+which w3mir finds no references will not be retrieved.  So this will
+fail if the sites are not in any way related, or if you wanted
+<em>everything</em> stored at each site.
+
+<p>To mirror unrelated sites, or get it all you may specify that the
+given URL should be considered a starting-point as well:
+
+<pre>
+Also-quene: http://www.math.uio.no/drift/personer/ math/drift
+</pre>
+
+<p>and, if you want to add an additional starting-point within a already
+named site:
+
+<pre>
+Quene: http://www.math.uio.no/drift/personer/foo.html
+</pre>
+
+<p>Armed with that you should be able to get pretty much anything you
+like.
+
+<hr>
+
+<h3><a name="alias">How do I copy files from one server with several
+names?</a></h3>
+
+<p>Simple, the same way you mirror several servers with different
+names. The math department at University of Oslo has a web server
+known under two names: math-www.uio.no and www.math.uio.no, and both
+names are used in documents stored on it. To copy the whole server,
+one time only, give these URL and Also lines:
+
+<pre>
+URL: http://www.math.uio.no/ .
+Also: http://math-www.uio.no/ .
+</pre>
+
+<p>Note the period/dot (.) at the end of each line.  It means that
+w3mir will store the files in the current directory, i.e. documents
+from both servers will be stored in the same place.  But since w3mir
+asks to only get documents that are newer than the ones it already has
+any document gotten from the server under the www.math.uio.no name
+will not be gotten from the math-www.uio.no name as well.  ... w3mir
+will ask for the document, but the server will tell w3mir that its
+copy is current and there will be no additional transfer of the
+document.
+
+<hr>
+
+<h3><a name="enlarge">How do I enlarge or prune an established
+mirror?</a></h3>
+
+<p>This only works if you use a configuration file.
+
+<p>If you want to add a site or directory to a mirror you simply add
+the needed <tt>Also:</tt> or <tt>Also-Quene:</tt> to the configuration
+file and then you run w3mfix manually, with the -editref option.  If,
+you for example have established a mirror of my home-pages, but want to
+add my wife's home-page you add this
+
+<pre>
+Also: http://www.ifi.uio.no/~annen/ ifi/annen
+</pre>
+
+<p>to the configuration shown earlier.  Then you run w3mfix, and you want
+it to fix all URLs referencing her home-page, the distinguishing
+characteristic is the name 'annen':
+
+<pre>
+w3mfix -editref annen
+</pre>
+
+<p>but 
+
+<pre>
+w3mirx -editref http://www.ifi.uio.no/~annen/
+</pre>
+
+<p>would work too, but it's a lot more to type.  This fixes all the
+references to her home-page so that they point to the mirror instead of
+the original pages.
+
+<p>To prune (cut out something) a mirror you do the same.  Make the
+change in the configuration file and run 'w3mfix -editme ...' to fix
+the references to that which you removed.
+
+<hr>
+
+<h3><a name="cat">How do I 'cat' a file?</a></h3>
+
+<p>W3mir will output the fetched document to its standard output
+(normally your screen/window) if you specify the '-s' command line
+option.  The corresponding configuration file directive is 
+
+<pre>
+File-Disposition: stdout
+</pre>
+
+<hr>
+
+<h3><a name="list">How do I list URLs in a document?</a></h3>
+
+<p>To list the URLs in http://www.math.uio.no/:
+
+<pre>
+w3mir -q -f -l http://www.math.uio.no/
+</pre>
+
+<p>The <tt>-q</tt> switch causes w3mir to produce no other output
+which would disturb the URL listing.  The <tt>-f</tt> switch tells
+w3mir to forget the document once it has been analyzed, i.e., not save
+it on disk.  And finally, the <tt>-l</tt> switch makes w3mir list the
+URLs in the document.  You may combine <tt>-l</tt> with <tt>-r</tt>
+and you need not use it with <tt>-f</tt>.
+
+<p>In the configuration file you put <tt>list</tt> on the
+<tt>Options:</tt> line.
+
+<hr>
+
+<h3><a name="aborted">How to I restart a mirror process after stopping
+it prematurely?</a></h3>
+
+<p>You may just rerun the same command once more.  But that makes
+w3mir request all the documents you have already once more to see if a
+more recent version is available on the server.  You can save time by
+using the <tt>-fs</tt> (Fetch Some) option.  This makes w3mir only
+request documents it does not find on your disk.  E.g.:
+
+<p><tt>w3mir -fs -r http://www.starwars.com/</tt>
+
+<p>This is not something you would normally put in the configuration
+file, but you can, by adding 'only-nonexistent' on the 'Options:' line.
+
+<hr>
+
+<h3><a name="robots">How do I disable robots.txt obedience?</a></h3>
+
+<p>Normally w3mir will read and obey each sites robots.txt file,
+because w3mir wants to be a nice tool. However robots.txt was designed
+with something slightly different than the normal use of w3mir in
+mind, so if you want w3mir to disregard the robot rules you can use
+<tt>-drr</tt> (Disable Robot Rules) on the command-line, or the line
+
+<pre>
+Robot-Rules: off
+</pre>
+
+<p>in the configuration file.  The robot exclusion standard is
+described in <a
+href="http://info.webcrawler.com/mak/projects/robots/norobots.html">http://info.webcrawler.com/mak/projects/robots/norobots.htm</a>.
+
+<hr>
+
+<h3><a name="corrupt">How do I stop w3mir from corrupting binary
+files?</a></h3>
+     
+<p>During the normal course of events w3mir converts the newline
+format of fetched HTML documents to your systems native newline
+format. On Unix a newline consists of a single ASCII LF character, on
+Macintoshes it's a single ASCII CR character and on Dos/Windows it's a
+ASCII CR/LF pair. W3mir understands all these and all HTML files are
+saved in the format your operating system prefers.
+
+<p>If, and this is very unlikely, a web server identifies a binary
+file as HTML w3mir will very likely corrupt the file. If you discover
+a file which is obviously ruined in the mirror, but is not ruined when
+you view it on the original site do this:
+
+<ol>
+
+<li>Notify the webmaster on the original site that the file has the
+wrong MIME type
+
+<li>Use the <tt>-nnc</tt> (No Newline Conversion) option on the
+command line, or
+
+<pre>
+Options: no-newline-conv
+</pre>
+
+in the configuration file.
+
+<li>Remove the corrupt file(s).
+
+<li>Run "<tt>w3mir -fs</tt>...", to fetch only the deleted file(s)
+again.
+
+</ol>
+
+<hr>
+
+<h3><a name="auth">How do I copy a site that wants user-name and
+password?</a></h3>
+
+<p>This can only be done with a configuration file.  Being able to
+give this on the command-line would give the user-name and password away
+to other users of the system, so the ability to give authentication
+information that way has not been put in w3mir.
+
+<p>In the configuration file you put:
+
+<pre>
+Auth-domain: */*
+Auth-user: me
+Auth-passwd: my-password
+</pre>
+
+<p>This will cause w3mir to give the user-name and password each time
+the server asks.  There is no way to make w3mir give the user-name and
+password each time no matter if the server asks or not.
+
+<hr>
+
+<h3><a name="mauth">How do I access a site that wants several
+different user-names and passwords?</a></h3>
+
+<p>If you have several user-names and passwords across
+the server(s) that are copied you need a slightly more advanced
+version of this that associates each user-name/password with a
+authentication "domain".  "Domain" is a HTTP concept.  It is simply a
+grouping of files and documents within a "realm".  One file or a whole
+directory hierarchy can belong to a realm.  One server may have many
+realms.  A user may have separate passwords for each realm, or the
+same password for all the realms the user has access to.  A
+combination of a server name, server port and a realm is called a
+domain.
+
+<pre>
+Auth-domain: theserver:theport/therealm
+Auth-user: me
+Auth-passwd: my-password
+
+Auth-domain: theserver:theport/otherrealm
+Auth-user: other-me
+Auth-password: other-password
+</pre>
+
+W3mir will tell you what the name of the realm is if it is unable to
+authenticate itself with the server. You may also use '*' as the realm
+name if you only copy documents from one realm on that server.
+
+<hr>
+
+<h3><a name="proxy">How do I use a proxy server?</a></h3>
+
+<p>On some secured sites you have to access the Internet through proxy
+servers to get out of the internal network.
+
+<p>A proxy server has a host name, and a port you must use. On the
+command line you simply specify <tt>-P proxy-host-name:proxy-port</tt>. In
+the configuration file you put this:
+
+<pre>
+HTTP-Proxy: proxy-host-name:proxyport
+</pre>
+
+<p>The main advantage of working through proxy servers other than
+security is that you take advantage of any caching the proxy server
+which can speed up retrievals enormously.
+
+<p>Another use of the proxy option is to "prime" the proxy servers
+cache.  I.e. you can use w3mir to fetch the documents through the proxy
+server to ensure that the documents are cached there later when you
+want to read them with your browser.  If you also specify 
+
+<pre>
+File-Disposition: forget
+</pre>
+
+<p>it won't even use any space on your disk, w3mir will just process
+the documents looking for URLs and then <em>not</em> save them.
+
+<hr>
+
+<h3><a name="pauth">How do I authenticate myself to a proxy
+server?</a></h3>
+
+<p>Some proxy servers demands a user-name and password to let you use
+them.  W3mir does not support the domain concept in connection with
+proxy authentication because the author cannot imagine that it will be
+needed.  You need to put this in your configuration file:
+
+<pre>
+HTTP-Proxy-user: proxy-username
+HTTP-Proxy-passwd: proxy-password
+</pre>
+
+<hr>
+
+<h3><a name="proxytweak">How do I ensure that the proxy server
+...?</a></h3>
+
+<p>HTTP/1.0 proxy servers may be told to not use its current copy of
+a document if you specify the <tt>-pflush</tt> command-line option.  Or 
+
+<pre>
+Proxy-Options: refresh
+</pre>
+
+<p>in the configuration file.  This is useful if the proxy has an old
+copy of some document and does not realize that a newer version exists
+on the origin site.  W3mir uses the HTTP/1.0 version of this command
+by default.  You can force w3mir to use the HTTP/1.1 version by adding
+<tt>no-pragma</tt> to the line.  If you do this it will not work at
+all as you want unless the server knows the HTTP/1.1 protocol.
+
+
+<p>HTTP/1.1 proxy servers can be manipulated in a few more ways.  The
+configuration file <tt>Proxy-Options:</tt> directive also takes
+<tt>revalidate</tt> and <tt>no-store</tt> options.  The former tells
+the proxy server to check if there is any newer version available.
+This is, in principle, more network friendly than the <tt>refresh</tt>
+option since it will only cause a copy if there is a newer file
+available.  The <tt>no-store</tt> option tells the proxy server to not
+store the documents you transfer.  This might be useful if the
+documents are 'sensitive' or something like that, but if the proxy
+server does not understand HTTP/1.1 it will not obey this option, and
+it might store the document anyway because the functionality is not
+implemented, so you should not count on this to work.
+
+<hr>
+
+<h3><a name="batchget">How do I batch get files with w3mir?</a></h3>
+
+<p>Normally when fetching files w3mir will process each html (and PDF)
+file to find URLs in them for further retrievals.  This is
+time-consuming, and not always wanted.  Sometimes you simply want to
+get a file, or more, and save it, untouched:
+
+<pre>
+w3mir -B http://www.starwars.com/ http://www.ifi.uio.no/~janl/
+</pre>
+
+<p>There is a companion switch for <tt>-B</tt>, namely <tt>-I</tt>, it
+makes w3mir read URLs from its standard input, one pr. line.  Thus you
+can use w3mir in a pipe to batch get several files whose URLs you find
+in some way.  This is a stupid example:
+
+<pre>
+w3mir -q -l -f http://www.ifi.uio.no/ | w3mir -I -B
+</pre>
+
+<p><tt>-B</tt> may also be used with <tt>-r</tt>, but the only effect
+it will have then is to save the html files unchanged on disk, because
+to recurse w3mir <em>has</em> to examine all the html the documents
+for URLs.
+
+<p><b>Please note</b> that using <tt>-B</tt> combined with <tt>-r</tt>
+for mirroring will probably lead to a unstable mirror, because w3mir
+does not get a chance to manipulate the URLs in the documents as it
+needs to be able to maintain a mirror later, and most important of
+all, w3mir needs all html files to contain a &lt;HTML&gt; tag to be
+able to recognize a HTML file as a HTML file. When running with the
+<tt>-B</tt> switch w3mir will not ensure the presence of this and thus
+we must rely on the original documents author to be nice. This is a
+bad bet. In other words, <b>don't use <tt>-B</tt> for recursive
+mirroring</b>, only for batch copying/mirroring of single documents.
+
+<hr>
+
+<h3><a name="cgi">How do I handle CGI?</a></h3>
+
+<p>There is no way w3mir can duplicate the process that happens on the
+Web server when it comes to CGI.  For some CGI programs w3mir can
+simply copy the output and store on disk.  For other CGI programs this
+is not possible, and the only way out is to make w3mir not get the
+involved files using Ignore rules in the configuration file.  These
+will avoid a lot of cgi programs:
+
+<pre>
+Ignore: *.cgi
+Ignore: *-cgi
+</pre>
+
+<p>You might have to add other/more rules for some sites if they have
+other naming conventions or if it's simply impossible to tell from the
+file-name if it's a CGI or not.
+
+<p>When you add ignore rules this causes two things:
+
+<ol>
+<li><p>W3mir will not retrieve documents matching the rules
+<li><p>W3mir will make all references to matching documents point to
+  the site you mirrored from instead of pointing to a non-existent
+  file in the mirror.
+</ol>
+
+<hr>
+
+<h3><a name="imap">How do I handle server side image-maps?</a></h3>
+
+<p>Server side image-maps is yet another thing it's impossible for
+w3mir to relate to.  w3mir simply cannot handle them.  Put ignore
+rules in the configuration file:
+
+<pre>
+Ignore: *.map
+</pre>
+
+<p>W3mir has full support for client side image-maps though.
+
+<hr>
+
+<h3><a name="java">How do I handle Java and ActiveX?</a></h3>
+
+<p>Java and Active X objects are are included in html pages with a
+<tt>&lt;OBJECT&gt;</tt> or <tt>&lt;APPLET&gt;</tt> tag.  W3mir can
+handle these on one condition: The CODEBASE attribute names the
+directory where the program stores its resources (such as
+subprograms, graphic files, sound, text, and so on) and w3mir must
+have read access to this directory.  Otherwise w3mir is without hope,
+it's impossible to extract the name of the resources the program needs
+in any reliable way.
+
+<p>HTML4 supports a attribute that enumerates the resources the
+program needs, w3mir is not able to use this yet.
+
+<hr>
+
+<h3><a name="script">How do I handle java-script and other script
+languages?</a></h3>
+
+<p>W3mir does its best to pass scripts (java-script, perl-script,
+etc...) embedded in the HTML undamaged.  It cannot, however, extract
+any URLs the script generates and the browser would cause the document
+to refer to or embed in a page. 
+
+<p>It will however work if the script generates relative references
+and there is some other way for w3mir to access the referenced file in
+some other manner.  Or if the script generates absolute references and
+the person browsing the mirror has access to the site named, then the
+user will be able to browse the referenced documents via that other
+server.
+
+<hr>
+
+<h3><a name="css">How to I handle the other things with 'partial
+support'</a></h3>
+
+<p>W3mir has partial support for CSS.  This means that
+<tt>&lt;style&gt</tt> tags and the enclosed style data are passed
+undamaged by w3mir.  W3mir will also retrieve the external CSSes named
+in HTML documents.  But w3mir will <em>not</em> (yet) analyze the
+CSSes data to find URLs of other resources (such as fonts) named in
+these.
+
+<p>W3mir also has partial support for Adobe Acrobat (PDF) files.  This
+means that w3mir can extract URLs from PDF files, and get the named
+documents if you want them.  But w3mir cannot edit those URLs so that
+the PDF files point to the mirror instead of wherever on the original
+site they were pointing.  If the PDF files contain absolute URLs they
+will continue pointing to where they were pointing before.  However,
+if the PDF files contain relative references things will work out.
+
+<p>The reason that URLs in PDF files cannot be edited is that they are
+binary and contain byte pointers.  If the URLs length is changed the
+byte pointers will point to the wrong place in the document.  Writing
+code to correct these pointers would be quite complex.  But if you
+write it I will use it.
+
+<hr>
+
+<h3><a name="anon">How do I keep my identity secret?</a></h3>
+
+<p>The HTTP protocol has a header, <tt>User:</tt> which is recommended
+to use by robots, such as w3mir.  Another way to track you is looking
+at the 'Referer:' header w3mir gives in HTTP requests.  Both can be
+disabled:
+
+<pre>
+Disable-headers: referer, user
+</pre>
+
+<p>If you in addition use a proxy server that many other users use
+there is little probability you can be tracked (easily) by the server
+you are copying things from.  You are however much easier to track
+from the logs in the proxy server.  And a court order is quite likely
+to get you tracked in spite of any precautions you take.  
+
+<p>W3mir does not support cookies and thus you cannot be tracked with
+the help of that mechanism.
+
+<hr>
+
+<h3><a name="ns">How do I pretend that I'm using Netscape, Internet
+Explorer or Lynx?</a></h3>
+
+<p>Some web sites give you different documents when you ask for a
+specific URL based on what browser you use, or even what OS you appear
+to be using.  w3mir identifies itself with a string that looks like
+this:
+
+<p><tt>w3mir/<em>version</em>-<em>release-date</em></tt>
+
+<p>Netscape identifies itself with strings that look something like
+this:
+
+<p><tt>Mozilla/3.01 (X11; I; Linux 2.0.30 i586)</tt>
+
+<p>and Internet Explorer says it's something like this:
+
+<p><tt>Mozilla/2.0 (compatible; MSIE 3.02; Windows NT)</tt>
+
+<p>and Lynx says something like this
+
+<p><tt>Lynx/2.6  libwww-FM/2.14</tt>
+
+<p>You can change w3mirs identification with <tt>-agent 'string'</tt>
+on the command line.  In the configuration file you put
+
+<pre>
+Agent: Mozilla/3.01 (X11; I; Linux 2.0.30 i586)
+</pre>
+
+<p>to pretend w3mir is netscape 3.01.
+
+<hr>
+
+<h3><a name="other">How do I do other things?</a></h3>
+
+<p>This document is by no means a complete list of the things you can
+do with w3mir.  The w3mir man page (<tt>man w3mir</tt> or <tt>perldoc
+w3mir</tt> lists more things, and goes into more detail of how things
+work so you can use the knowledge to do neat things.  There are
+several things mentioned only in the man-page that helps you with
+tricky multi-server mirroring, and gives you better control of what to
+get and not to get and under what name to save it on disk.  And a
+couple of other things...
+
+<hr>
+<address>Nicolai Langfeldt 9/7/1998</address>
Index: /main/tags/2.25/gsdl/packages/w3mir/w3mir-1.0.8/w3mir.PL
===================================================================
--- /main/tags/2.25/gsdl/packages/w3mir/w3mir-1.0.8/w3mir.PL	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/w3mir/w3mir-1.0.8/w3mir.PL	(revision 21064)
@@ -0,0 +1,3291 @@
+# -*-perl-*-
+
+use Config;
+
+&read_makefile;
+$fullperl = resolve_make_var('FULLPERL') || $Config{'perlpath'};
+$islib = resolve_make_var('INSTALLSITELIB');
+
+$name = $0;
+$name =~ s~^.*/~~;
+$name =~ s~.PL$~~;
+
+open(OUT,"> $name") || 
+  die "Could open $name for writing: $!\n";
+
+print "writing $name\n";
+
+while (<DATA>) {
+  if (m~^\#!/.*/perl.*$~o) {
+    # This substitutes the path perl was installed at on this system
+    # _and_ removed any (-w) options.
+    print OUT "#!",$fullperl,$1,"\n";
+    next;
+  }
+  if (/^use lib/o) {
+    # This substitutes the actuall library install path
+    print OUT "use lib '$islib';\n";
+    next;
+  }
+  print OUT;
+}
+
+close(OUT);
+
+# Make it executable too, and writeable
+chmod 0755, $name;
+
+#### The library
+
+sub resolve_make_var ($) {
+
+  my($var) = shift @_;
+  my($val) = $make{$var};
+
+#  print "Resolving: ",$var,"=",$val,"\n";
+  
+  while ($val =~ s~\$\((\S+)\)~$make{$1}~g) {}
+#  print "Resolved: $var: $make{$var} -> $val\n";
+  $val;
+}
+
+
+sub read_makefile {
+
+  open(MAKEFILE, 'Makefile') || 
+    die "Could not open Makefile for reading: $!\n";
+
+  while (<MAKEFILE>) {
+    chomp;
+    next unless m/^([A-Z]+)\s*=\s*(\S+)$/;
+    $make{$1}=$2;
+#    print "Makevar: $1 = $2\n";
+  }
+
+  close(MAKEFILE)
+}
+
+__END__
+#!/local/bin/perl5 -w
+# Perl 5.002 or later.  w3mir is mostly tested with perl 5.004
+#
+# You might want to change or comment out this:
+use lib '/hom/janl/lib/perl';
+#
+# Once upon a long time ago this was Oscar Nierstrasz's
+# <oscar@cui.unige.ch> htget script.
+#
+# Retrieves HTML pages, creating local copies in the _current_ 
+# directory. The script will check for the last-modified stamp on the
+# document, and will not fetch it if the document isn't changed.
+#
+# Bug list is in w3mir-README.
+#
+# Test cases for janl to use:
+#   w3mir -r -fs http://www.eff.org/ - infinite recursion!
+#     --- but cursory examination seems to indicate confused server...
+#   http://java.sun.com/progGuide/index.html check out the img things.
+#
+# Copyright Holders:
+#   Nicolai Langfeldt, janl@ifi.uio.no
+#   Gorm Haug Eriksen, gorm@usit.uio.no
+#   Chris Szurgot, szurgot@itribe.net
+#   Ed Jordan, ed@olympus.itl.net
+#   Alex Knowles, aknowles@avs.com aka ark.
+# Copying and modification is governed by the "Artistic License" enclosed in
+# the w3mir distribution
+#
+# History (European format date: dd/mm/yy):
+#  oscar 25/03/94 -- added -s option to send output to stdout
+#  oscar 28/03/94 -- made HTTP 1.0 the default
+#  oscar 30/05/94 -- special handling of directory URLs missing a trailing "/"
+#   gorm 20/02/95 -- added mirror capacity + fixed a couple of bugs
+#   janl 28/03/95 -- added a working commandline parser.
+#   janl 18/09/95 -- Changed to use a net http library.  Removed dependency of
+#		     url.pl.
+#   janl 19/09/95 -- Extensive rewrite. Simplified a lot, works better. 
+#		     HTML files are now saved in a new and improved manner,
+#		     which means they can be recognized as such w/o fancy
+#		     filename extention type rules.
+# szurgot 27/01/96-- Added "Plaintextmode" wrapper to binmode PAGE. 
+#                    binmode page is required under Win32, but broke modified
+#                    checking
+#                 -- Minor change added ; to "# '" strings for Emacs cperl-mode
+# szurgot 07/02/96-- When reading in local file for checking of URLs changed
+#                    local ($/) =0; to equal undef;
+#   janl 08/02/96 -- Added szurgot's changes and changed them :-)
+# szurgot 09/02/96-- Added code to strip /#.*$/ from urls when reading from 
+#                    local file
+#                 -- Added hasAlarm variable to w3http.pl. Set to 1 if you have
+#                    alarm(). 0 otherwise.
+#                 -- Moved code setting up the valid extensions list into the
+#                    args processing where it belonged
+#   janl 20/02/96 -- Added szurgot changes again.
+#		  -- Make timeout code work.
+#   		  -- and made another win32 test.
+#   janl 19/03/96 -- Worked through the code for handling not-modified 
+#    		     documents, it was a bit shabby after htmlop was intro'ed.
+#   janl 20/03/96 -- -l fix
+#   janl 23/04/96 -- Added -fs by request (by Rik Faith)
+#   janl 16/05/96 -- Made -R mandatory, added use and support for
+#			w3http::SAVEBIN
+# szurgot 19/05/96-- Win95 adaptions.
+#   janl 19/05/96 -- -C did not exactly work as expected.  Thanks to Petr
+#		     Novak for bug descriptions.
+#   janl 19/05/96 -- Changed logic for @didntget, @got and so on to use
+#		     @queue and %urlstat.
+#   janl 09/09/96 -- Removed -R switch.
+#   janl 14/09/96 -- Added ir (initial referer) switch
+#   janl 21/09/96 -- Made retry code saner.  There probably needs to be a
+#                    sleep before retry comencing switch.  When no tty is
+#                    present it should be fairly long.
+#   gorm 15/09/96 -- Added cr (check robot) switch. Default to 1 (on)
+#   janl 22/09/96 -- Modified gorms patch to use WWW::RobotRules.  Changed
+#		     robot switch to be consistent with current w3mir
+#                    practice.
+#   janl 27/09/96 -- Spelling corrections from charles.curran@ox.ac.uk
+#                 -- Folded in manual diffs from ark.
+#    ark 24/09/96 -- Simple facilities to edit the incomming file(s)
+#   janl 27/09/96 -- Added switch to enable <!--NOMIRROR--> editing and
+#		     foolproofed ark's patch a bit.
+#   janl 02/10/96 -- Added -umask switch.
+#		  -- Redirected documents did not have a meaningful referer
+#		     value (it was undefined).
+#		  -- Got w3mir into strict discipline, found some typos...
+#   janl 20/10/96 -- Mtime is preserved
+#   janl 21/10/96 -- -lc switch added.  Mtime preservation works better.
+#   janl 06/11/96 -- Treat 301 like 302.
+#   janl 02/12/96 -- Added config file code, fetch/ignore rules, apply
+#   janl 04/12/96 -- Better checking of config input.
+#   janl 06/12/96 -- Putting together the URL selection/editing brains.
+#   janl 07/12/96 -- Checking out some bugs.  Adding multiscope options.
+#   janl 12/12/96 -- Adding to and defeaturing the multiscope options.
+#   janl 13/12/96 -- Continuing work in multiscope stuff
+#                 -- Unreferenced file and empty directory removal works.
+#   janl 19/02/97 -- Can extract urls from adobe acrobat pdf files :-)
+#		     Important: It does _not_ edit urls, so they still
+#		     point at the original site(s).
+#   janl 21/02/97 -- Fix -lc bug related to case and the apply things.
+#		  -- only use SAVEURL if needed
+#   janl 11/03/97 -- Finish work on SAVEURL conditional.
+#		  -- Fixed directory removal code.
+#                 -- parse_args did not abort when unknown option/argument
+#		     was specified.
+#   janl 12/03/97 -- Made test case for -lc.  Didn't work.  Fixed it.  I think.
+#		     Realized we have bug w.r.t. hostname caseing.
+#   janl 13/03/97 -- All redirected to URLs within scope are now queued.  
+#		     That should make the mirror more complete, but it won't
+#		     help browsability when it comes to the redirected doc.
+#		  -- Moved robot retrival to the inside of the mirror loop
+#		     since we now possebly mirror several sites.
+#		  -- Changed 'fetch-options' to 'options'.
+#                 -- Added 'proxy-options'/-pflush to controll proxy server(s).
+#   janl 09/04/97 -- Started using URI::URL.
+#   janl 11/04/97 -- Debugging and using URI::URL more correctly various places
+#   janl 09/05/97 -- Added --agent switch
+#   janl 12/05/97 -- Simplified scope checks for root URL, changed URL 'apply'
+#		     processing.
+#		  -- Small output formating fix in the robot rules code.
+#		  -- Version is now 0.99
+#   janl 14/05/97 -- htmpop no-longer puts '<!DOCTYPE...' into doc, so check 
+#		     for '<HTML' instead
+#   janl 11/06/97 -- Made :port optional in server part of auth-domain.
+#			Always removing :80 from server part to match netloc.
+#   janl 22/07/97 -- More debugging of rewrite for new features -B, -I.
+#   janl 01/08/97 -- Fixed bug in RE quoting for Ignore/Fetch
+#   janl 04/08/97 -- s/writepage/write_page/g
+#   janl 07/09/97 -- 0.99b1 is released
+#   janl 19/09/97 -- Kaj Hejer discovers omissions in non-html-url-mining code.
+#                 -- 0.99b2 is released
+#   janl 24/09/97 -- Matt Chapman found bug in realm-name extraction.
+#   janl 10/10/97 -- Referer: header supression supressed User: header instead
+#		  -- Added fixup handling, writes .redirs and .referers
+#		     (no dot in win32)
+#  		  -- Read .w3mirc (w3mir.ini on win32) if present
+#		  -- Stop file removal code from removing these files
+#   janl 16/10/97 -- process_tag was mangling url attributes in tags with more
+#		     than one of them.  Problem found by Robert L. Binkley
+#   janl 04/12/97 -- Fixed problem with authentication, misplaced +
+#		  -- default inter-docuent pause is 0.  I figure it's better
+#		     to keep one httpd occupied in a steady stream than to
+#		     wait for it to die before we talk to it again.
+#   janl 13/12/97 -- The arguments to index.html in the form of index.html/foo
+#		     handling code was incomplete.  To make it complete would
+#		     have been hard, so it was removed.
+#		  -- If a URL changes from file to directory or vice versa
+#		     this is now handled.
+#   janl 11/01/98 -- PDF files with no URLs does not cause warnings now.
+#		  -- Close REFERERS and REDIRECTS before calling w3mfix
+#   janl 22/01/98 -- Proxy authentication as outlined by Christian Geuer
+#   janl 04/02/98 -- Version 1pre1
+#   janl 18/02/98 -- Fixed wild_re after tip by Prentiss Riddle.
+#		  -- Version 1pre2
+#   janl 20/02/98 -- w3http updated to handle complex content-types.
+#		  -- Fix wild_re more, bug noted by James Dumser
+#		  -- 1.0pre3
+#   janl 18/03/98 -- Version 1.0 is released
+#   janl 09/04/98 -- Added feature so user can disable newline conversion.
+#   janl 20/04/98 -- Only convert newlines in HTML files. -> 1.0.2
+#   janl 09/05/98 -- More carefull clean_disk code.
+#		  -- Check if the redirected URL was a root url, if so
+#		     issue a warning and exit.
+#   janl 12/05/98 -- use ->unix_path instead of ->as_string to derive local
+#		     filename.
+#   janl 25/05/98 -- -B didn't work too well.
+#   janl 09/07/98 -- Redirect to fragment broke us, less broken now -> 1.0.4
+#   janl 24/09/98 -- Better errormessages on errors -> 1.0.5
+#   janl 21/11/98 -- Fix errormessages better.
+#   janl 05/01/99 -- Drop 'Referer: (commandline)'
+#   janl 13/04/99 -- Add initial referer to root urls in batch mode.
+#
+# Variable name discipline:
+# - remote, umodified URL.  Variables prefixed 'rum_'
+# - local, filesystem.  Variables prefixed 'lf_'.
+# Use these prefixes so we know what we're working with at all times.
+# Also, URL objects are postfixed _o
+#
+# The apply rules and scope rules work this way:
+# - First apply the user rules to the remote url.
+# - Check if document is within scope after this.
+# - Then apply w3mir's rules to the result.  This results is the local,
+#   filesystem, name.
+#
+# We use features introduced in 5.002.
+require 5.002;
+
+# win32 and $nulldevice need to be globals, other modules use them.
+use vars qw($win32 $nulldevice);
+
+# To figure out what kind of system this is
+BEGIN {
+  use Config;
+  $win32 = ( $Config{'osname'} eq 'MSWin32' ); 
+}
+# More ways to die:
+use Carp;
+# Http module:
+use w3http;
+# html url extraction and manupulation:
+use htmlop;
+# Extract urls from adobe acrobat pdf files:
+use w3pdfuri;
+# Date computer:
+use HTTP::Date;
+# URLs:
+use URI::URL;
+# For flush method
+use FileHandle;
+
+# Full discipline:
+use strict;
+
+# Set params in the http package, HTTP protocol version:
+$w3http::version="1.0";
+
+# The defaults should be for a robotic http agent on good behaviour.
+my $debug=0;			# Debug level
+my $verbose=0;			# Verbosity level, -1 = quiet, 0 = normal, 1...
+my $pause=0;			# Pause between http requests
+my $retryPause=600;		# Pause between retries. 10 minutes.
+my $retry=3;			# Max 3 stabs pr. url.
+my $r=0;			# Recurse? no recursion = absolutify links
+my $remove=0;			# Remove files that are not there?
+my $s=0;			# 0: save on disk 1: stdout 2: just forget 'em
+my $useauth=0;			# Use authorization
+my %authdata;			# Authorization data
+my $check_robottxt = 1;		# Check robots.txt
+my $do_referer = 1;		# Send referers header
+my $do_user = 1;		# Send user header
+my $cache_header = '';		# The cache-control/pragma: no-cache header
+my $using_proxy = 0;		# Using proxy server or not?
+my $batch=0;			# Batch get URLs?
+my $read_urls=0;		# Get urls from STDIN?
+my $abs=0;			# Absolutify URLs?
+my $immediate_redir=0;		# Immediately follow a redirect?
+my @root_urls;			# This is where we start, the root documents
+my @root_dirs;			# The corresponding directories.  for remove
+my $chdirto='';			# Place to chdir to after reading config file
+my %nodelete=();		# Files that should not be deleted
+my $numarg=0;			# Number of arguments accepted.
+
+# Fixup related things
+my $fixrc='';			# Name of w3mfix config file
+my $fixup=1;			# Do things needed to run fixup
+my $runfix=0;			# Run w3mfix for user?
+my $fixopen=0;			# Fixup files open?
+
+my $indexname='index.html';
+
+my $VERSION;
+$VERSION='1.0.8';
+$w3http::agent = my $w3mir_agent = "w3mir/$VERSION-1999-05-28";
+my $iref='';			# Initial referer.  Must evaluate to false
+
+# Derived settings	
+my $mine_urls=0;		# Mine URLs from documents?
+my $process_urls=0;		# Perform (URL) processing of documents?
+
+# Queue of urls to get.
+my @rum_queue = ();
+my @urls = ();
+# URL status map.
+my %rum_urlstat = ();
+# Status codes:
+my $QUEUED   = 0;		# Queued but not gotten yet.
+my $TERROR   = 100;		# Transient error, retry later
+my $HLERR    = 101;		# Permanent error, give up
+my $GOTIT    = 200;		# Gotten. Note similarity to http result code
+my $NOTMOD   = 304;		# Not modified.
+# Negative codes for nonexistent files, easier to check.
+my $NEVERMIND= -1;		# Don't want it
+my $REDIR    = -302;		# Does not exist, redirected
+my $ENOTFND  = -404;		# Does not exist.
+my $OTHERERR = -600;		# Some other error happened
+my $FROBOTS  = -601;		# Forbidden by robots.txt rule
+
+# Directory/files survey:
+my %lf_file;		# What files are present in FS?  Disposition?  One of:
+my $FILEDEL=0;		# Delete file
+my $FILEHERE=1;		# File present in filesystem only
+my $FILETHERE=2;	# File present on server too.
+my %lf_dir;		# Number of files/dirs in dir.  If 0 dir is 
+			# eligible for deletion.
+
+my %fiddled=();		# If a file becomes a directory or a directory
+                        # becomes a file it is considered fiddled and
+                        # w3mir will not fiddle with it again in this
+                        # run.
+
+# Bitbucket device, very OS dependent.
+$nulldevice='/dev/null';
+$nulldevice='nul:' if ($win32);
+
+# What to get, and not.
+# Text of user supplied fetch/ignore rules
+my $rule_text=" # User defined fetch/ignore rules\n";
+# Code ref to the rule procedure
+my $rule_code;
+
+# Code to prefix and postfix the generated code.  Prefix should make
+# $_ contain the url to match.  Postfix should return 1, the default
+# is to get the url/file.
+my $rule_prefix='$rule_code = sub { local($_) = shift;'."\n";
+my $rule_postfix=" return 1;\n}";
+
+# Scope tests generated by URL/Also directives in cfg. The scope code
+# is just like the rule code, but used for program generated
+# fetch/ignore rules related to multiscope retrival.
+my $scope_fetch=" # Automatic fetch rules for multiscope retrival\n";
+my $scope_ignore=" # Automatic ignore rules for multiscope retrival\n";
+my $scope_code;
+
+my $scope_prefix='$scope_code = sub { local($_) = shift;'."\n";
+my $scope_postfix=" return 0;\n}";
+
+# Function to apply to urls, se rule comments.
+my $user_apply_code;	# User specified apply code
+my $apply_code;		# w3mirs apply code
+my $apply_prefix='$apply_code = sub { local($_) = @_;'."\n";
+my $apply_lc=' $_ = lc $_; ';
+my $apply_postfix='  return $_;'."\n}";
+my @user_apply;		# List of users apply rules.
+my @internal_apply;	# List of w3mirs apply rules.
+
+my $infoloss=0;		# 1 if any URL translations (which cause
+                        # information loss) are in effect.  If this is
+                        # true we use the SAVEURL operation.
+my $list;		# List url on STDOUT?
+my $edit;		# Edit doc? Remove <!--NOMIRROR>...<!--/NOMIRROR-->
+my $header;		# Text to insert in header
+my $lc=0;		# Convert urls/filenames to lowercase?
+my $fetch=0;		# What to fetch: -1: Some, 0: not modified 1: all
+my $convertnl=1;	# Convert newlines?
+
+# Non text/html formats we can extract urls from.  Function must take one
+# argument: the filename.
+my %knownformats = ( 'application/pdf', \&w3pdfuri::list,
+		     'application/x-pdf', \&w3pdfuri::list,
+		   );
+
+# Known 'magic numbers' of the known formats.  The value is used as
+# key in %knownformats.  the key part is a exact match for the
+# following <string> beginning at the first byte of the file.
+# This should probably be made more flexible, but not until we need it.
+
+my %knownmagic = ( '%PDF-', 'application/pdf' );
+
+my $iinline='';	# inline RE code to make RE caseinsensitive 
+my $ipost='';	# RE postfix to make it caseinsensitive
+
+usage() unless parse_args(@ARGV);
+
+{
+  my $w3mirc='.w3mirc';
+  
+  $w3mirc='w3mir.ini' if $win32;
+  
+  if (-f $w3mirc) {
+    parse_cfg_file($w3mirc);
+    $nodelete{$w3mirc}=1;
+  }
+}
+
+# Check arguments and options
+if ($#root_urls>=0) {
+  # OK
+} else {
+  print "URLs: $#rum_queue\n";
+  usage("No URLs given");
+}
+
+# Are we converting newlines today?
+$w3http::convert=0 unless $convertnl;
+
+if ($chdirto) {
+  &mkdir($chdirto.'/this-is-not-created-odd-or-what');
+  chdir($chdirto) || 
+    die "w3mir: Can't change working directory to '$chdirto': $!\n";
+}
+
+$SIG{'INT'}=sub { print STDERR "\nCaught SIGINT!\n"; exit 1; };
+$SIG{'QUIT'}=sub { print STDERR "\nCaught SIGQUIT!\n"; exit 1; };
+$SIG{'HUP'}=sub { print STDERR "\nCaught SIGHUP!\n"; exit 1; };
+
+&open_fixup if $fixup;
+
+# Derive how much document processing we should do.
+$mine_urls=( $r || $list );
+$process_urls=(!$batch && !$edit && !$header);
+# $abs can be set explicitly with -abs, and implicitly if not recursing
+$abs = 1 unless $r;
+print "Absolute references\n" if $abs && $debug;
+
+# Cache_controll specified but proxy not in use?
+die "w3mir: If you want to control a cache, use a proxy server!\n"
+  if ($cache_header && !$using_proxy);
+
+# Compile the second order code
+
+# - The rum scope tests
+my $full_rules=$scope_prefix.$scope_fetch.$scope_ignore.$scope_postfix;
+# warn "Scope rules:\n-------------\n$full_rules\n---------------\n";
+eval $full_rules;
+
+die "w3mir: Program generated rules did not compile.\nPlease report to w3mir-core\@usit.uio.no.  The code is:\n----\n".
+  $full_rules."\n----\n"
+  if !defined($scope_code);
+
+$full_rules=$rule_prefix.$rule_text.$rule_postfix;
+# warn "Fetch rules:\n-------------\n$full_rules\n---------------\n";
+eval $full_rules;
+
+# - The user specified rum tests
+die "w3mir: Ignore/Fetch rules did not compile.\nPlease report to w3mir-core\@usit.uio.no.  The code is:\n----\n".
+  $full_rules."\n----\n"
+  if !defined($rule_code);
+
+# - The user specified apply rules
+
+my $full_apply=$apply_prefix.($lc?$apply_lc:'').
+  join($ipost.";\n",@user_apply).(($#user_apply>=0)?$ipost:"").";\n".
+  $apply_postfix;
+eval $full_apply;
+
+die "w3mir: User apply rules did not compile.\nPlease report to w3mir-core\@usit.uio.no. The code is:
+----
+".$full_apply."
+----\n" if !defined($apply_code);
+
+$user_apply_code=$apply_code;
+
+# - The w3mir generated apply rules
+
+$full_apply=$apply_prefix.($lc?$apply_lc:'').
+  join($ipost.";\n",@internal_apply).(($#internal_apply>=0)?$ipost:"").";\n".
+  $apply_postfix;
+eval $full_apply;
+
+die "Internal apply rules did not compile.  The code is:
+----
+".$full_apply."
+----\n" if !defined($apply_code);
+
+# - Information loss via -lc?  There are other sources as well.
+$infoloss=1 if $lc;
+
+warn "Infoloss is $infoloss\n" if $debug;
+
+# More setup:
+
+$w3http::debug=$debug;
+
+$w3http::verbose=$verbose;
+
+my %rum_referers=();	# Array of referers, key: rum_url
+my $Robot_Blob;		# WWW::RobotsRules object, decides if rum_url is 
+			# forbidden to access for us.
+my $rum_url_o;		# rum url, mostly the current, the one we're getting
+my %gotrobots;		# Did I get robots.txt from site? key: url->netloc
+my($authuser,$authpass);# Username and password for authentication with server
+my @rum_newurls;	# List of rum_urls in document
+
+if ($check_robottxt) {
+  # Eval is only way to defer loading of module until we know it's needed?
+  eval 'use WWW::RobotRules;';
+
+  die "Could not load WWW::RobotRules, try -drr switch\n"
+    unless defined(&WWW::RobotRules::parse);
+
+  $Robot_Blob = new WWW::RobotRules $w3mir_agent;
+}
+
+# We have several main-modes of operation.  Here we select one
+if ($r) {
+
+  die "w3mir: No URLs?  Try 'w3mir -h' for help.\n"
+    if $#root_urls==-1;
+
+  warn "Recursive retrival comencing\n" if $debug;
+
+  die "w3mir: Sorry, you cannot combine -r/recurse with -I/read_urls\n"
+    if $read_urls;
+
+  # Recursive
+  my $url;
+  foreach $url (@root_urls) {
+    warn "Root url dequeued: $url\n" if $debug;
+    if (want_this($url)) {
+      queue($url);
+      &add_referer($url,$iref);
+    } else {
+      die "w3mir: Inconsistent configuration: Specified $url is not inside retrival scope\n";
+    }
+  }
+  mirror();
+
+} else {
+  if ($batch) {
+    warn "Batch retrival commencing\n" if $debug;
+    # Batch get
+    if ($read_urls) { 
+      # Get URLs from <STDIN>
+      while (<STDIN>) {
+	chomp;
+	&add_referer($_,$iref);
+	batch_get($_);
+      }
+    } else {
+      # Get URLs from commandline
+      my $url;
+      foreach $url (@root_urls) {
+	&add_referer($url,$iref);
+      }
+      foreach $url (@root_urls) {
+	batch_get($url);
+      }
+    }
+  } else {
+    warn "Single url retrival commencing\n" if $debug;
+
+    # A single URL, with all processing on
+    die "w3mir: You specified several URLs and not -B/batch\n"
+      if $#root_urls>0;
+    queue($root_urls[0]);
+    &add_referer($root_urls[0],$iref);
+    mirror();
+  }
+}
+
+&close_fixup if $fixup;
+
+# This should clean up files:
+&clean_disk if $remove;
+
+warn "w3mir: That's all (".$w3http::xfbytes.'+',$w3http::headbytes.
+  " bytes of it).\n" unless $verbose<0;
+
+if ($runfix) {
+  eval 'use Config;';
+  warn "Running w3mfix\n";
+  if ($win32) {
+    system($Config{'perlpath'}." w3mfix $fixrc");
+  } else {
+    system("w3mfix $fixrc");
+  }
+}
+
+exit 0;
+
+sub get_document {
+  # Get one document by HTTP ($1/rum_url_o).  Save in given filename ($2).
+  # Possebly returning references found in the document.  Caller must
+  # set up referer array, check wantedness and everything else.  We
+  # handle authentication here though.
+
+  my($rum_url_o)=shift;
+  my($lf_url)=shift;
+  croak("\$rum_url_o is empty") if !defined($rum_url_o) || !$rum_url_o;
+  croak("$lf_url is empty") if !defined($lf_url) || !$lf_url;
+
+  # Make sure it's an object
+  $rum_url_o = url $rum_url_o 
+    unless ref $rum_url_o;
+  
+  # Derive a filename from the url, the filename contains no URL-quoting
+  my($lf_name) = (url "file:$lf_url")->unix_path;
+
+  # Make all intermediate directories
+  &mkdir($lf_name) if $s==0;
+
+  my($rum_as_string) = $rum_url_o->as_string;
+
+  print STDERR "GET_DOCUMENT: '",$rum_as_string,"' -> '",$lf_name,"'\n"
+    if $debug;
+
+  my $hostport;
+  my $www_auth='';	# Value of that http reply header
+  my $page_ref;
+  my @rum_newurls;	# List of URLs extracted
+  my $url_extractor;
+  my $do_query;		# Do query or not?
+
+  if (defined($rum_urlstat{$rum_as_string}) && 
+      $rum_urlstat{$rum_as_string}>0) {
+    warn "w3mir: Internal error, ".$rum_as_string.
+      " queued several times\n";
+    next;
+  }
+
+  # Goto here if we want to retry b/c of authentication
+  try_again:
+
+  # Start building the extra http::query arguments again
+  my @EXTRASTUFF=();
+
+  # We'll start by assuming that we're doing the query.
+  $do_query=1;
+    
+  # If we're not checking the timestamp, or the file does not exist
+  # then we get the file unconditionally.  Otherwise we only want it
+  # if it's updated.
+
+  if ($fetch==1) {
+    # Nothing do do?
+  } else {
+    if (-f $lf_name) {
+      if ($fetch==-1) {
+	print STDERR "w3mir: ".($infoloss?$rum_as_string:$lf_name).
+	  ", already have it" if $verbose>=0;
+	if (!$mine_urls) {
+	  # If -fs and the file exists and we don't need to mine URLs
+	  # we're finished!
+	  warn "Already have it, no mining, returning!\n" if $debug;
+	  print STDERR "\n" if $verbose>=0;
+	  return;
+	}
+	$w3http::result=1304;	# Pretend it was 'not modified'
+	$do_query=0;
+      } else {
+	push(@EXTRASTUFF,$w3http::IFMODF,$lf_name);
+      }
+    }
+  }
+
+  if ($do_query) {
+
+    # Does the server want authorization for this file?  $www_auth is
+    # only set if authentication was requested the first time around.
+
+    # For testing:
+    # $www_auth='Basic realm="foo"';
+
+    if ($www_auth) {
+      my($authdata,$method,$realm);
+
+      ($method,$realm)= $www_auth =~ m/^(\S+)\s+realm=\"([^\"]+)\"/i;
+      $method=lc $method;
+      $realm=lc $realm;
+      die "w3mir: '$method' authentication needed, don't know that.\n"
+	if ($method ne 'basic');
+      
+      $hostport = $rum_url_o->netloc;
+      $authdata=$authdata{$hostport}{$realm} || $authdata{$hostport}{'*'} ||
+	$authdata{'*'}{$realm} || $authdata{'*'}{'*'};
+
+      if ($authdata) {
+	push(@EXTRASTUFF,$w3http::AUTHORIZ,$authdata);
+      } else {
+	print STDERR "w3mir: No authorization data for $hostport/$realm\n";
+	$rum_urlstat{$rum_as_string}=$NEVERMIND;
+	next;
+      }
+    }
+    
+    push(@EXTRASTUFF,$w3http::FREEHEAD,$cache_header)
+      if ($cache_header);
+
+    # Insert referer header data if at all
+    push(@EXTRASTUFF,$w3http::REFERER,$rum_referers{$rum_as_string}[0])
+      if ($do_referer && exists($rum_referers{$rum_as_string}));
+
+    push(@EXTRASTUFF,$w3http::NOUSER)
+      unless ($do_user);
+
+    # YES, $lf_url is right, w3http::query handles this like an url so
+    # the quoting must all be in place.
+    my $binfile=$lf_url;
+    $binfile='-' if $s==1;
+    $binfile=$nulldevice if $s==2;
+
+    if ($pause) {
+      print STDERR "w3mir: sleeping\n" if $verbose>0;
+      sleep($pause);
+    }
+
+    print STDERR "w3mir: ".($infoloss?$rum_as_string:$lf_name) 
+      unless $verbose<0;
+    print STDERR "\nFile: $lf_name\n" if $debug;
+
+    &w3http::query($w3http::GETURL,$rum_as_string,
+		   $w3http::SAVEBIN,$binfile,
+		   @EXTRASTUFF);
+
+    print STDERR "w3http::result: '",$w3http::result,
+    "' doc size: ", length($w3http::document),
+    " doc type: -",$w3http::headval{'CONTENT-TYPE'},
+    "- plaintexthtml: ",$w3http::plaintexthtml,"\n"
+      if $debug;
+
+    print "Result: ",$w3http::result," Recurse: $r, html: ",
+    $w3http::plaintexthtml,"\n" 
+      if $debug;
+
+  } # if $do_query
+    
+  if ($w3http::result==200) { # 200 OK 
+    $rum_urlstat{$rum_as_string}=$GOTIT;
+
+    if ($mine_urls || $process_urls) {
+
+      if ($w3http::plaintexthtml) {
+	# Only do URL manipulations if this is a html document with no
+	# special content-encoding.  We do not handle encodings, yet.
+
+	my $page;
+
+	print STDERR ($process_urls)?", processing":", url mining"
+	  if $verbose>0;
+	  
+	print STDERR "\nurl:'$lf_url'\n" 
+	  if $debug;
+
+	print "\nMining URLs: $mine_urls, Process: $process_urls\n" 
+	  if $debug;
+	    
+	($page,@rum_newurls) = 
+	  &htmlop::process($w3http::document,
+			   # Only get a new document if wanted
+			   $process_urls?():($htmlop::NODOC),
+			   $htmlop::CANON,
+			   $htmlop::ABS,$rum_url_o,
+			   # Only list urls if wanted
+			   $mine_urls?($htmlop::LIST):(),
+
+			   # If user wants absolute URLs do not
+			   # relativize them
+
+			   $abs?
+			   ():
+			   (
+			    $htmlop::TAGCALLBACK,\&process_tag,$lf_url,
+			    )
+			  );
+
+#	print "URL: ",join("\nURL: ",@rum_newurls),"\n";
+
+	if ($process_urls) {
+	  $page_ref=\$page;
+	  $w3http::document='';
+	} else {
+	  $page_ref=\$w3http::document;
+	}
+
+      } elsif ($s == 0 &&
+	       ($url_extractor = 
+		$knownformats{$w3http::headval{'CONTENT-TYPE'}})) {
+
+	# The knownformats extractors only work on disk files so write
+	# doc to disk if not there already (non-html text will not be)
+	write_page($lf_name,$w3http::document,1);
+
+	# Now we try our hand at fetching URIs from non-html files.
+	print STDERR ", mining URLs" if $verbose>=1;
+	@rum_newurls = &$url_extractor($lf_name);
+	# warn "URLs from PDF: ",join(', ',@rum_newurls),"\n";
+      }
+      
+      
+    } # if ($mine_urls || $process_urls)
+
+#    print "page_ref defined: ",defined($page_ref),"\n";
+#    print "plaintext: ",$w3http::plaintext,"\n";
+
+    $page_ref=\$w3http::document 
+      if !defined($page_ref) && $w3http::plaintexthtml;
+
+    if ($w3http::plaintexthtml) {
+      # ark: this is where I want to do my changes to the page strip
+      # out the <!--NOMIRROR-->...<!--/NOMIRROR--> Stuff.
+      $$page_ref=~ s/<(!--)?\s*NO\s*MIRROR\s*(--)?>[^\000]*?<(!--)?\s*\/NO\s*MIRROR\s*(--)?>//g 
+	if $edit;
+	  
+      if ($header) {
+	# ark: insert a header string at the start of the page
+	my $mirrorstr=$header;
+	$mirrorstr =~ s/\$url/$rum_as_string/g;
+	insert_at_start( $mirrorstr, $page_ref );
+      }
+    }
+
+    write_page($lf_name,$page_ref,0);
+
+    # print "New urls: ",join("\n",@rum_newurls),"\n";
+
+    return @rum_newurls;
+  }
+
+  if ($w3http::result==304 || #  304 Not modified
+      $w3http::result==1304) { # 1304 Have it
+
+    { 
+      # last = out of nesting
+
+      my $rum_urlstat;
+      my $rum_newurls;
+      
+      @rum_newurls=();
+      
+      print STDERR ", not modified"
+	if $verbose>=0 && $w3http::result==304;
+      
+      $rum_urlstat{$rum_as_string}=$NOTMOD;
+
+      last unless $mine_urls;
+      
+      $rum_newurls=get_references($lf_name);
+
+      # print "New urls: ",ref($rum_newurls),"\n";
+      
+      if (!ref($rum_newurls)) {
+	last;
+      } elsif (ref($rum_newurls) eq 'SCALAR') {
+	$page_ref=$rum_newurls;
+      } elsif (ref($rum_newurls) eq 'ARRAY') {
+	@rum_newurls=@$rum_newurls;
+	last;
+      } else {
+	die "\nw3mir: internal error: Unknown return type from get_references\n";
+      }
+      
+      # Check if it's a html file.  I know this tag is in all html
+      # files, because I put it there as I pull them in.
+      last unless $$page_ref =~ /<HTML/i;
+      
+      warn "$lf_name is a html file\n" if $debug;
+      
+      # It's a html document
+      print STDERR ", mining URLs" if $verbose>=1;
+      
+      # This will give us a list of absolute urls
+      (undef,@rum_newurls) = 
+	&htmlop::process($$page_ref,$htmlop::NODOC,
+			 $htmlop::ABS,$rum_as_string,
+			 $htmlop::USESAVED,'W3MIR',
+			 $htmlop::LIST);
+    }
+
+    print STDERR "\n" if $verbose>=0;
+    return @rum_newurls;
+  }
+	
+  if ($w3http::result==302 || $w3http::result==301) { # Redirect
+    # Cern and NCSA httpd sends 302 'redirect' if a ending / is
+    # forgotten on a url.  More recent httpds send 301 'permanent
+    # redirect' in this case.  Here we check if the difference in URLs
+    # is just a / and if so push the url again with the / added.  This
+    # code only works if the http server has the right idea about its
+    # own name.
+    #
+    # 18/3/97: Added code to queue redirected-to-URLs that are within
+    # the scope of the retrival.
+    my $new_rum_url;
+
+    $rum_urlstat{$rum_as_string}=$REDIR;
+
+    # Absolutify the new url, it might be relative to the requested
+    # document.  That's a ugly wart on some servers/admins.
+    $new_rum_url=url $w3http::headval{'location'};
+    $new_rum_url=$new_rum_url->abs($rum_url_o);
+
+    print REDIRS $rum_as_string,' -> ',$new_rum_url->as_string,"\n"
+      if $fixup;
+
+    if ($immediate_redir) {
+      print STDERR " =>> ",$new_rum_url->as_string,", getting that instead\n";
+      return get_document($new_rum_url,$lf_url);
+    }
+
+    # Some redirect to a fragment of another doc...
+    $new_rum_url->frag(undef);
+    $new_rum_url=$new_rum_url->as_string;
+
+    if ($rum_as_string.'/' eq $new_rum_url) {
+      if (grep { $rum_as_string eq $_; } @root_urls) {
+	print STDERR "\nw3mir: missing / in a start URL detected.  Please fix commandline/config file.\n";
+	exit(1);
+      }
+      print STDERR ", missing /\n";
+      queue($new_rum_url);
+      # Initialize referer to something meaningful
+      $rum_referers{$new_rum_url}=$rum_referers{$rum_as_string};
+    } else {
+      print STDERR " =>> $new_rum_url";
+      if (want_this($new_rum_url)) {
+	print STDERR ", getting that\n";
+	queue($new_rum_url);
+	$rum_referers{$new_rum_url}=$rum_referers{$rum_as_string};
+      } else {
+	print STDERR ", don't want it\n";
+      }
+    }
+    return ();
+  }
+
+  if ($w3http::result==403 || # Forbidden
+      $w3http::result==404 || # Not found
+      $w3http::result==406 || # Not Acceptable, hmm, belongs here?
+      $w3http::result==410) { # Gone - no forwarding address known
+
+    $rum_urlstat{$rum_as_string}=$ENOTFND;
+    &handleerror;
+    print STDERR "Was refered from: ",
+      join(',',@{$rum_referers{$rum_as_string}}),
+      "\n" if defined(@{$rum_referers{$rum_as_string}});
+    return ();
+  }
+
+  if ($w3http::result==407) {
+    # Proxy authentication requested
+    die "Proxy server requests authentication but failed to return the\n".
+      "REQUIRED Proxy-Authenticate header for this condition\n"
+	unless exists($w3http::headval{'proxy-authenticate'});
+
+    die "Proxy authentication is required for ".$w3http::headval{'proxy-authenticate'}."\n";
+  }
+
+  if ($w3http::result==401) {
+    # A www-authenticate reply header should acompany a 401 message.
+    if (!exists($w3http::headval{'www-authenticate'})) {
+      warn "w3mir: Server indicated authentication failure but gave no www-authenticate reply\n";
+      $rum_urlstat{$rum_as_string}=$NEVERMIND;
+    } else {
+      # Unauthorized
+      if ($www_auth) {
+	# Failed when authorization data was supplied.
+	$rum_urlstat{$rum_as_string}=$NEVERMIND;
+	print STDERR ", authorization failed data needed for ",
+	$w3http::headval{'www-authenticate'},"\n"
+	  if ($verbose>=0);
+      } else {
+	if ($useauth) {
+	  # First time failure, send back and retry at once with some known
+	  # user/passwd.
+	  $www_auth=$w3http::headval{'www-authenticate'};
+	  print STDERR ", retrying with authorization\n" unless $verbose<0;
+	  goto try_again;
+	} else {
+	  print ", authorization needed: ",
+	    $w3http::headval{'www-authenticate'},"\n";
+	  $rum_urlstat{$rum_as_string}=$NEVERMIND;
+	}
+      }
+    }
+    return ();
+  }
+   
+  # Something else.  
+  &handleerror;
+}
+
+
+sub robot_check {
+  # Check if URL is allowed by robots.txt, if we respect it at all
+  # that is.  Return 1 it allowed, 0 otherwise.
+
+  my($rum_url_o)=shift;
+  my $hostport;
+
+  if ($check_robottxt) {
+    
+    $hostport = $rum_url_o->netloc;
+    if (!exists($gotrobots{$hostport})) {
+      # Get robots.txt from the server
+      $gotrobots{$hostport}=1;
+      my $robourl="http://$hostport/robots.txt";
+      print STDERR "w3mir: $robourl" if ($verbose>=0);
+      &w3http::query($w3http::GETURL,$robourl);
+      $w3http::document='' if ($w3http::result != 200);
+      print STDERR ", processing" if $verbose>=1;
+      print STDERR "\n" if ($verbose>=0);
+      $Robot_Blob->parse($robourl,$w3http::document);
+    }
+
+    if (!$Robot_Blob->allowed($rum_url_o->as_string)) {
+      # It is forbidden
+      $rum_urlstat{$rum_url_o->as_string}=$FROBOTS;
+      warn "w3mir: ",$rum_url_o->as_string,": forbidden by robots.txt\n";
+      return 0;
+    }
+  }
+  return 1;
+}
+
+
+
+sub batch_get {
+  # Batch get _one_ document.
+  my $rum_url=shift;
+  my $lf_url;
+
+  $rum_url_o = url $rum_url;
+
+  return unless robot_check($rum_url_o);
+
+  ($lf_url=$rum_url) =~ s~.*/~~;
+  if (!defined($lf_url) || $lf_url eq '') {
+    ($lf_url=$rum_url) =~ s~/$~~;
+    $lf_url =~ s~.*/~~;
+    $lf_url .= "-$indexname";
+  }
+
+  warn "Batch get: $rum_url -> $lf_url\n" if $debug;
+
+  $immediate_redir=1; # Do follow redirects immediately
+
+  get_document($rum_url,$lf_url);
+}
+
+
+
+sub mirror {
+  # Mirror (or get) the requested url(s). Possibly recursively.
+  # Working from whatever cwd is at invocation we'll retrieve all
+  # files under it in the file hierarchy.
+  
+  my $rum_url;	# URL of the document we're getting now, defined at main level
+  my $lf_url;	# rum_url after apply - and 
+  my $new_lf_url;
+  my @new_rum_urls;
+  my $rum_ref;
+  
+  while (defined($rum_url = pop(@rum_queue))) {
+
+    warn "mirror: Poped $rum_url from queue\n" if $debug;
+
+    # Unwanted URLs should not be queued
+    die "Found url $rum_url that I don't want in queue!\n" 
+      unless defined($lf_url=apply($rum_url));
+
+    $rum_url_o = url $rum_url;
+
+    next unless robot_check($rum_url_o);
+
+    # Figure out the filename for our local filesystem.
+    $lf_url.=$indexname if $lf_url =~ m~/$~ || $lf_url eq '';
+
+    @new_rum_urls = get_document($rum_url_o,$lf_url);
+
+    print join("\n",@new_rum_urls),"\n" if ($list);
+
+    if ($r) {
+      foreach $rum_ref (@new_rum_urls) {
+	# warn "Recursive url: $rum_ref\n";
+	$new_lf_url=apply($rum_ref);
+	next unless $new_lf_url;
+
+	# warn "Want it\n";
+	$rum_ref =~ s/\#.*$//s;		# Clip off section marks
+	
+	add_referer($rum_ref,$rum_url_o->as_string);
+	queue($rum_ref);
+      }
+    }
+
+    @new_rum_urls=();
+
+    # Is the URL queue empty? Are there outstanding retries?  Refill
+    # the queue from the retry list.
+    if ($#rum_queue<0 && $retry-->0) {
+      foreach $rum_url_o (keys %rum_urlstat) {
+	$rum_url_o = url $rum_url_o;
+	if ($rum_urlstat{$rum_url_o->as_string}==100) {
+	  push(@rum_queue,$rum_url_o->as_string);
+	  $rum_urlstat{$rum_url_o->as_string}=0;
+	}
+      }
+      if ($#rum_queue>=0) {
+	warn "w3mir: Sleeping before retrying.  $retry more times left\n"
+	  if $verbose>=0;
+	sleep($retryPause);
+      }
+    }
+
+  }
+}
+
+
+sub get_references {
+  # Get references from a non-html-on-disk file.  Return references if
+  # we know how to find them.  Return reference do the complete page
+  # if it's html.  Return single numerical 0 if unknown format.
+
+  my($lf_url)=shift;
+  my($urlextractor)=shift;
+
+  my $read; # Buffer of stuff read from file to check filetype
+  my $magic;
+  my $url_extractor;
+  my $rum_ref;
+  my $page;
+
+  warn "w3mir: Looking at local $lf_url\n" if $debug;
+	
+  # Open file and read the first 10kilobytes for file-type-test
+  # purposes.
+  if (!open(TMPF,$lf_url)) {
+    warn "Unable to open $lf_url for reading: $!\n";
+    last;
+  }
+	
+  $page=' 'x10240;
+  $read=sysread(TMPF,$page,length($page),0);
+  close(TMPF);
+	
+  die "Error reading $lf_url: $!\n" if (!defined($read));
+
+  if (!defined($url_extractor)) {
+    $url_extractor=0;
+
+    # Check file against list of magic numbers.
+    foreach $magic (keys %knownmagic) {
+      if (substr($page,0,length($magic)) eq $magic) {
+	$url_extractor = $knownformats{$knownmagic{$magic}};
+	last;
+      }
+    }
+  }
+
+  # Found a extraction method, apply.
+  if ($url_extractor) {
+    print STDERR ", mining URLs" if $verbose>=1;
+    return [&$url_extractor($lf_url)];
+  }
+
+  if ($page =~ /<HTML/i) {
+    open(TMPF,$lf_url) || 
+      die "Could not open $lf_url for reading: $!\n";
+    # read the whole file.
+    local($/)=undef;
+    $page = <TMPF>;
+    close(TMPF);
+    return \$page;
+  }
+
+  return 0;
+}
+
+
+sub open_fixup {
+  # Open the referers and redirects files
+
+  my $reffile='.referers';
+  my $redirfile='.redirs';
+
+  if ($win32) {
+    $reffile="referers";
+    $redirfile="redirs";
+  }
+
+  $nodelete{$reffile} = $nodelete{$redirfile} = 1;
+
+  open(REDIRS,"> $redirfile") || 
+    die "Could not open $redirfile for writing: $!\n";
+
+  autoflush REDIRS 1;
+
+  open(REFERERS,"> $reffile") ||
+    die "Could not open $reffile for writing: $!\n";
+
+  $fixopen=1;
+  eval 'END { close_fixup; 0; }';
+}
+
+
+sub close_fixup {
+  # Close the fixup data files.  In the case of the referer file also
+  # write the entire content
+
+  return unless $fixopen;
+
+  my $referer;
+
+  foreach $referer (keys %rum_referers) {
+    print REFERERS $referer," <- ",join(' ',@{$rum_referers{$referer}}),"\n";
+  }
+
+  close(REFERERS) || warn "Error closing referers file: $!\n";
+  close(REDIRS) || warn "Error closing redirects file: $!\n";
+  $fixopen=0;
+}
+
+
+sub clean_disk {
+  # This procedure removes files that are not present on the server(s)
+  # anymore.
+  
+  # - To avoid removing files that were not fetched due to network
+  #   problems we only do blanket removal IFF all documents were
+  #   fetched w/o problems, eventually.  
+  # - In any case we can remove files the server said were not found
+
+  # The strategy has three main parts:
+  # 1. Find all files we have
+  # 2. Find what files we ought to have
+  # 3. Remove the difference
+  
+  my $complete_retrival=1;	# Flag saying IFF all documents were fetched
+  my $urlstat;			# Tmp storage
+  my $rum_url;
+  my $lf_url;
+  my $lf_dir;
+  my $dirs_to_remove;
+
+  # For fileremoval code
+  eval "use File::Find;" unless defined(&find);
+
+  die "w3mir: Could not load File::Find module.  Don't use -R switch.\n"
+    unless defined(&find);
+  
+  # This to shut up -w
+  $lf_dir=$File::Find::dir;
+
+  # ***** 1. Find out what files we have *****
+  #
+  # This does two things:  For each file or directory found:
+  # - Increases entry count for the container directory
+  # - If it's a file: $lf_file{relative_path}=$FILEHERE;
+
+  chop(@root_dirs);
+  print STDERR "Looking in: ",join(", ",@root_dirs),"\n" if $debug;
+
+  find(\&find_files,@root_dirs);
+
+  # ***** 2. Find out what files we ought to have *****
+  #
+  # First we loop over %rum_urlstat to determine what files are not
+  # present on the server(s).
+  foreach $rum_url (keys %rum_urlstat) {
+    # Figure out name of local file from rum_url
+    next unless defined($lf_url=apply($rum_url));
+
+    $lf_url.=$indexname if $lf_url =~ m~/$~ || $lf_url eq '';
+
+    # find prefixes ./, we must too.
+    $lf_url="./".$lf_url unless substr($lf_url,0,1) eq '/';
+
+    # Ignore if file does not exist here.
+    next unless exists($lf_file{$lf_url});
+    
+    # The apply rules can map several remote files to same local
+    # file.  If we decided to keep file already we stay with that.
+    next if $lf_file{$lf_url}==$FILETHERE;
+    
+    $urlstat=$rum_urlstat{$rum_url};
+
+    # Figure out the status code.
+    if ($urlstat==$GOTIT || $urlstat==$NOTMOD) {
+      # Present on server.  Keep.
+      $lf_file{$lf_url}=$FILETHERE;
+      next;
+    } elsif ($urlstat==$ENOTFND || $urlstat==$NEVERMIND ) {
+      # One of: not on server, can't get, don't want, access forbiden:
+      # Schedule for removal.
+      $lf_file{$lf_url}=$FILEDEL if exists($lf_file{$lf_url});
+      next;
+    } elsif ($urlstat==$OTHERERR || $urlstat==$TERROR) {
+      # Some error occured transfering.
+      $complete_retrival=0;	# The retrival was not complete. Delete less
+    } elsif ($urlstat==$QUEUED) {
+      warn "w3mir: Internal inconsistency, $rum_url marked as queued after retrival terminated\n";
+      $complete_retrival=0;	# Fishy. Be conservative about removing
+    } else {
+      $complete_retrival=0;
+      warn "w3mir: Warning: $rum_url is marked as $urlstat.\n".
+	"w3mir: Please report to w3mir-core\@usit.uio.no.\n";
+    }
+  }				# foreach %rum_urlstat
+
+  # ***** 3. Remove the difference *****
+
+  # Loop over all found files:
+  # - Should we have this file?
+  # - If not: Remove file and decrease directory entry count
+  # Loop as long as there are directories with 0 entry count:
+  # - Loop over all directories with 0 entry count:
+  #   - Remove directory
+  #   - Decrease entry count of parent
+  
+  warn "w3mir: Some error occured, conservative file removal\n"
+    if !$complete_retrival && $verbose>=0;
+
+  # Remove all files we don't want removed from list of files present:
+  foreach $lf_url (keys %nodelete) {
+    print STDERR "Not deleting: $lf_url\n" if $verbose>=1;
+    delete $lf_file{$lf_url} || delete $lf_file{'./'.$lf_url};
+  }
+  
+  # Remove files
+  foreach $lf_url (keys %lf_file) {
+    if (($complete_retrival && $lf_file{$lf_url}==$FILEHERE) ||
+	($lf_file{$lf_url} == $FILEDEL)) {
+      if (unlink $lf_url) {
+	($lf_dir)= $lf_url =~ m~^(.+)/~;
+	$lf_dir{$lf_dir}--;
+	$dirs_to_remove=1 if ($lf_dir{$lf_dir}==0);
+	warn "w3mir: removed file $lf_url\n" if $verbose>=0;
+      } else {
+	warn "w3mir: removal of file $lf_url failed: $!\n";
+      }
+    }
+  }
+  
+  # Remove empty directories
+  while ($dirs_to_remove) {
+    $dirs_to_remove=0;
+    foreach $lf_url (keys %lf_dir) {
+      next if $lf_url eq '.';
+      if ($lf_dir{$lf_url}==0) {
+	if (rmdir($lf_url)) {
+	  warn "w3mir: removed directory $lf_dir\n" if $verbose>=0;
+	  delete $lf_dir{$lf_url};
+	  ($lf_dir)= $lf_url =~ m~^(.+)/~;
+	  $lf_dir{$lf_dir}--;
+	  $dirs_to_remove=1 if ($lf_dir{$lf_dir}==0);
+	} else {
+	  warn "w3mir: removal of directory $lf_dir failed: $!\n";
+	}
+      }
+    }
+  }
+}
+
+
+sub find_files {
+  # This is called by the find procedure for every file/dir found.
+  
+  # This builds two hashes:
+  # lf_file{<file>}: 1: file exists
+  # lf_dir{<dir>): Number of files in directory.
+  
+  lstat($_);
+
+  $lf_dir{$File::Find::dir}++;
+
+  if (-f _) {
+    $lf_file{$File::Find::name}=$FILEHERE;
+  } elsif (-d _) {
+    # null
+    # Bug: If an empty directory exists it will not be removed
+  } else {
+    warn "w3mir: File $File::Find::name has unknown type.  Ignoring.\n";
+  }
+  return 0;
+  
+}
+
+
+sub handleerror {
+  # Handle error status of last http connection, will set the rum_urlstat
+  # appropriately and print a error message.
+
+  my $msg;
+  
+  if ($verbose<0) {
+    $msg="w3mir: ".$rum_url_o->as_string.": ";
+  } else {
+    $msg=": ";
+  }
+
+  if ($w3http::result == 98) {
+    # OS/Network error
+    $msg .= "$!";
+    $rum_urlstat{$rum_url_o->as_string}=$OTHERERR;
+  } elsif ($w3http::result == 100) {
+    # Some kind of error connecting or sending request
+    $msg .= $w3http::restext || "Timeout";
+    $rum_urlstat{$rum_url_o->as_string}=$TERROR;
+  } else {
+    # Other HTTP error
+    $rum_urlstat{$rum_url_o->as_string}=$OTHERERR;
+    $msg .= " ".$w3http::result." ".$w3http::restext;
+    $msg .= " =>> ".$w3http::headval{'location'}
+    if (defined($w3http::headval{'location'}));
+  }
+  print STDERR "$msg\n";
+}
+
+
+sub queue {
+  # Queue given url if appropriate and create a status entry for it
+  my($rum_url_o)=url $_[0];
+
+  croak("BUG: undefined \$rum_url_o")
+    if !defined($rum_url_o);
+
+  croak("BUG: undefined \$rum_url_o->as_string")
+    if !defined($rum_url_o->as_string);
+
+  croak("BUG: ".$rum_url_o->as_string." (fragnent) queued")
+    if $rum_url_o->as_string =~ /\#/;
+  
+  return if exists($rum_urlstat{$rum_url_o->as_string});
+  return unless want_this($rum_url_o->as_string);
+
+  warn "QUEUED: ",$rum_url_o->as_string,"\n" if $debug;
+  
+  # Note lack of scope checks.
+  $rum_urlstat{$rum_url_o->as_string}=$QUEUED;
+  push(@rum_queue,$rum_url_o->as_string);
+}
+
+
+sub root_queue {
+  # Queue function for root urls and directories.  One or the other might
+  # be boolean false, in that case, don't queue it.
+
+  my $root_url_o;
+
+  my($root_url)=shift;
+  my($root_dir)=shift;
+
+  die "w3mir: No fragments in start URLs :".$root_url."\n"
+    if $root_url =~ /\#/;
+
+  if ($root_dir) {
+    print "Root dir: $root_dir\n" if $debug;
+    $root_dir="./$root_dir" unless substr($root_dir,0,1) eq '/' or
+      substr($root_dir,0,2) eq './';
+    push(@root_dirs,$root_dir);
+  }
+
+
+  if ($root_url) {
+    $root_url_o=url $root_url;
+
+    # URL canonification, or what we do of it at least.
+    $root_url_o->host($root_url_o->host);
+
+    warn "Root queue: ".$root_url_o->as_string."\n" if $debug;
+
+    push(@root_urls,$root_url_o->as_string); 
+
+    return $root_url_o;
+ }
+
+}
+
+
+sub write_page {
+  # write a retrieved page to wherever it's supposed to be written.
+  # Added difficulty: all files but plaintext files have already been
+  # written to disk in w3http.
+  
+  # $s == 0 save to disk
+  # $s == 1 dump to stdout
+  # $s == 2 forget
+
+  my($lf_name,$page_ref,$silent) = @_;
+  my($verb);
+
+  if ($silent) {
+    $verb=-1;
+  } else {
+    $verb=$verbose;
+  }
+
+#  confess("\n\$page_ref undefined") if !defined($page_ref);
+  
+  if ($w3http::plaintexthtml) {
+    # I have it in memory
+    if ($s==0) {
+      print STDERR ", saving" if $verb>0;
+
+      while (-d $lf_name) {
+	# This will run once, maybe twice, $fiddled will be canged the
+	# first time
+	if (exists($fiddled{$lf_name})) {
+	  warn "Cannot save $lf_name, there is a directory in the way\n";
+	  return;
+	}
+
+	$fiddled{$lf_name}=1;
+
+	rm_rf($lf_name);
+	print STDERR "w3mir: $lf_name" if $verbose>=0;
+      }
+
+      if (!open(PAGE,">$lf_name")) {
+	warn "\nw3mir: can't open $lf_name for writing: $!\n";
+	return;
+      }
+      if (!$convertnl) {
+	binmode PAGE;
+	warn "BINMODE\n" if $debug;
+      }
+      if ($$page_ref ne '') {
+	print PAGE $$page_ref || die "w3mir: Error writing $lf_name: $!\n";
+      }
+      close(PAGE) || die "w3mir: Error closing $lf_name: $!\n";
+      print STDERR ": ", length($$page_ref), " bytes\n"
+	if $verb>=0;
+      setmtime($lf_name,$w3http::headval{'last-modified'})
+	if exists($w3http::headval{'last-modified'});
+    } elsif ($s==1) {
+      print $$page_ref ;
+    } elsif ($s==2) {
+      print STDERR ", got and forgot it.\n" unless $verb<0;
+    }
+  } else {
+    # Already written by http module, just emit a message if wanted
+    if ($s==0) {
+      print STDERR ": ",$w3http::doclen," bytes\n"
+	if $verb>=0;
+      setmtime($lf_name,$w3http::headval{'last-modified'})
+	  if exists($w3http::headval{'last-modified'});
+    } elsif ($s==2) {
+      print STDERR ", got and forgot it.\n" if $verb>=0;
+    }
+  }
+}
+
+
+sub setmtime {
+  # Set mtime of the given file
+  my($file,$time)=@_;
+  my($tm_sec,$tm_min,$tm_hour,$tm_mday,$tm_mon,$tm_year,$tm_wday,$tm_yday,
+     $tm_isdst,$tics);
+
+  $tm_isdst=0;
+  $tm_yday=-1;
+
+  carp("\$time is undefined"),return if !defined($time);
+
+  $tics=str2time($time);
+  utime(time, $tics, $file) || 
+      warn "Could not change mtime of $file: $!\n";
+}
+
+
+sub movefile {
+  # Rename a file.  Note that copy is not a good alternative, since
+  # copying over NFS is something we want to Avoid.
+
+  # Returns 0 if failure and 1 in case of sucess.
+
+  (my $old,my $new) = @_;
+
+  # Remove anything that might have the name already.
+  if (-d $new) {
+    print STDERR "\n" if $verbose>=0;
+    rm_rf($new);
+    $fiddled{$new}=1;
+    print STDERR "w3mir: $new" if $verbose>=0;
+  } elsif (-e $new) {
+    $fiddled{$new}=1;
+    if (unlink($new)) {
+      print STDERR "\nw3mir: removed $new\nw3mir: $new"
+	if $verbose>=0;
+    } else {
+      return 0;
+    }
+
+  }
+
+  if ($new ne '-' && $new ne $nulldevice) {
+    warn "MOVING $old -> $new\n" if $debug;
+    rename($old,$new) || 
+      warn "Could not rename $old to $new: $!\n",return 0;
+  }
+  return 1;
+}
+
+
+sub mkdir {
+  # Make all intermediate directories needed for a file, the file name
+  # is expected to be included in the argument!
+
+  # Reasons for not using File::Path::mkpath:
+  # - I already wrote this.
+  # - I get to be able to produce as good and precise errormessages as
+  #   unix and perl will allow me.  mkpath will not.
+  # - It's easier to find out if it worked or not.
+  
+  my($file) = @_;
+  my(@dirs) = split("/",$file);
+  my $path;
+  my $dir;
+  my $moved=0;
+
+  if (!$dirs[0]) {
+    shift @dirs;
+    $path='';
+  } else {
+    $path = '.';
+  }
+
+  # This removes the last element of the array, it's meant to shave
+  # off the file name leaving only the directory name, as a
+  # convenience, for the caller.
+  pop @dirs;
+  foreach $dir (@dirs) {
+    $path .= "/$dir";
+    stat($path);
+    # only make if it isn't already there
+    next if -d _;
+
+    while (!-d _) {
+      if (exists($fiddled{$path})) {
+	warn "Cannot make directory $path, there is a file in the way.\n";
+	return;
+      }
+
+      $fiddled{$path}=1;
+
+      if (!-e _) {
+	mkdir($path,0777);
+	last;
+      }
+
+      if (unlink($path)) {
+	warn "w3mir: removed file $path\n" if $verbose>=0;
+      } else {
+	warn "Unable to remove $path: $!\n";
+	next;
+      }
+    
+      warn "mkdir $path\n" if $debug;
+      mkdir($path,0777) ||
+	warn "Unable to create directory $path: $!\n";
+
+      stat($path);
+    }
+  }
+}
+
+
+sub add_referer {
+  # Add a referer to the list of referers of a document.  Unless it's
+  # already there.
+  # Don't mail me if you (only) think this is a bit like a toungetwiser:
+
+  # Don't remember referers if BOTH fixup and referer header is disabled.
+  return if $fixup==0 && $do_referer==0;
+
+  my($rum_referee,$rum_referer) = @_ ;
+  my $re_rum_referer;
+
+  if (exists($rum_referers{$rum_referee})) {
+    $re_rum_referer=quotemeta $rum_referer;
+    if (!grep(m/^$re_rum_referer$/,@{$rum_referers{$rum_referee}})) {
+      push(@{$rum_referers{$rum_referee}},$rum_referer);
+      # warn "$rum_referee <- $rum_referer pushed\n";
+    } else {
+      # warn "$rum_referee <- $rum_referer NOT pushed\n";
+    }
+  } else {
+    $rum_referers{$rum_referee}=[$rum_referer];
+    # warn "$rum_referee <- $rum_referer pushed\n";
+  }
+}
+
+
+sub user_apply {
+  # Apply the user apply rules
+
+  return &$user_apply_code(shift);
+
+# Debug version:
+#  my ($foo,$bar);
+#  $foo=shift;
+#  $bar=&$apply_code($foo);
+#  print STDERR "Apply: $foo -> $bar\n";
+#  return $bar;
+}
+
+sub internal_apply {
+  # Apply the w3mir generated apply rules
+
+  return &$apply_code(shift);
+}
+
+
+sub apply {
+  # Apply the user apply rules.  Then if URL is wanted return result of
+  # w3mir apply rules.  Return the undefined value otherwise.
+
+  my $url = user_apply(shift);
+
+  return undef unless want_this($url);
+
+  internal_apply($url);
+}
+
+
+sub want_this {
+  # Find out if we want the url passed.  Just pass it on to the
+  # generated functions.
+  my($rum_url)=shift;
+
+  # What about robot rules?
+
+  # Does scope rule want this?
+  return &$scope_code($rum_url) &&
+    # Does user rule want this too?
+    &$rule_code($rum_url) 
+  
+}
+
+
+sub process_tag {
+  # Process a tag in html file
+  my $lf_referer = shift;	# User argument
+  my $base_url = shift;		# Not used... why not?
+  my $tag_name = shift;
+  my $url_attrs = shift;
+
+  # Retrun quickly if no URL attributes
+  return unless defined($url_attrs);
+
+  my $attrs = shift;
+
+  my $rum_url;	# The absolute URL
+  my $lf_url;	# The local filesystem url
+  my $lf_url_o; # ... and it's object
+  my $key;
+
+  print STDERR "\nProcess Tag: $tag_name, URL attributes: ", 
+  join(', ',@{$url_attrs}),"\nbase_url: ",$base_url,"\nlf_referer: ",
+  $lf_referer,"\n" 
+    if $debug>2;
+
+  $lf_referer =~ s~^/~~;
+  $lf_referer = "file:/$lf_referer";
+
+  foreach $key (@{$url_attrs}) {
+    if (defined($$attrs{$key})) {
+      $rum_url=$$attrs{$key};
+      printf STDERR "$key = $rum_url\n" if $debug;
+      $lf_url=apply($rum_url);
+      if (defined($lf_url)) {
+
+	printf STDERR "Transformed to $lf_url\n" if $debug>2;
+
+	$lf_url =~ s~^/~~;  # Remove leading / to avoid doubeling
+	$lf_url_o=url "file:/$lf_url";
+
+	# Save new value in the hash
+	$$attrs{$key}=($lf_url_o->rel($lf_referer))->as_string;
+	print STDERR "New value: ",$$attrs{$key},"\n" if $debug>2;
+
+	# If there is potential information loss save the old value too
+	$$attrs{"W3MIR".$key}=$rum_url if $infoloss;
+      }
+    }
+  }
+}
+
+
+sub version {
+  eval 'require LWP;';
+  print $w3mir_agent,"\n";
+  print "LWP version ",$LWP::VERSION,"\n" if defined $LWP::VERSION;
+  print "Perl version: ",$],"\n";
+  exit(0);
+}
+
+
+sub parse_args {
+  my $f;
+  my $i;
+
+  $i=0;
+
+  while ($f=shift) {
+    $i++;
+    $numarg++;
+    # This is a demonstration against Getopts::Long.
+    if ($f =~ s/^-+//) {
+      $s=1,next if $f eq 's';			# Stdout
+      $r=1,next if $f eq 'r';			# Recurse
+      $fetch=1,next if $f eq 'fa';		# Fetch all, no date test
+      $fetch=-1,next if $f eq 'fs';	# Fetch those we don't already have.
+      $verbose=-1,next if $f eq 'q'; 		# Quiet
+      $verbose=1,next if $f eq 'c';		# Chatty
+      &version,next if $f eq 'v';		# Version
+      $pause=shift,next if $f eq 'p';		# Pause between requests
+      $retryPause=shift,next if $f eq 'rp';	# Pause between retries.
+      $s=2,$convertnl=0,next if $f eq 'f';	# Forget
+      $retry=shift,next if $f eq 't';		# reTry
+      $list=1,next if $f eq 'l';		# List urls
+      $iref=shift,next if $f eq 'ir';		# Initial referer
+      $check_robottxt = 0,next if $f eq 'drr';	# Disable robots.txt rules.
+      umask(oct(shift)),next if $f eq 'umask';
+      parse_cfg_file(shift),next if $f eq 'cfgfile';
+      usage(),exit 0 if ($f eq 'help' || $f eq 'h' || $f eq '?');
+      $remove=1,next if $f eq 'R';
+      $cache_header = 'Pragma: no-cache',next if $f eq 'pflush';
+      $w3http::agent=$w3mir_agent=shift,next if $f eq 'agent';
+      $abs=1,next if $f eq 'abs';
+      $convertnl=0,$batch=1,next if $f eq 'B';
+      $read_urls = 1,next if $f eq 'I';
+      $convertnl=0,next if $f eq 'nnc';
+
+      if ($f eq 'lc') {
+	if ($i == 1) {
+	  $lc=1;
+	  $iinline=($lc?"(?i)":"");
+	  $ipost=($lc?"i":"");
+	  next;
+	} else {
+	  die "w3mir: -lc must be the first argument on the commandline.\n";
+	}
+      }
+
+      if ($f eq 'P') {				# Proxy
+	($w3http::proxyserver,$w3http::proxyport)= 
+	  shift =~ /([^:]+):?(\d+)?/;
+	$w3http::proxyport=80 unless $w3http::proxyport;
+	$using_proxy=1;
+	next;
+      }
+    
+      if ($f eq 'd') {		# Debugging level
+	$f=shift;
+	unless (($debug = $f) > 0) {
+	  die "w3mir: debug level must be a number greater than zero.\n";
+	}
+	next;
+      }
+
+      # Those were all the options...
+      warn "w3mir: Unknown option: -$f.  Use -h for usage info.\n";
+      exit(1);
+      
+    } elsif ($f =~ /^http:/) {
+      my ($rum_url_o,$rum_reurl,$rum_rebase,$server);
+
+      $rum_url_o=root_queue($f,'./');
+
+      $rum_rebase = quotemeta( ($rum_url_o->as_string =~ m~^(.*/)~)[0] );
+
+      push(@internal_apply,"s/^".$rum_rebase."//");
+      $scope_fetch.="return 1 if m/^".$rum_rebase."/".$ipost.";\n";
+      $scope_ignore.="return 0 if m/^".
+	quotemeta("http://".$rum_url_o->netloc."/")."/".$ipost.";\n";
+
+    } else {
+      # If we get this far then the commandline is broken
+      warn "Unknown commandline argument: $f.  Use -h for usage info.\n";
+      $numarg--;
+      exit(1);
+    }
+  }
+  return 1;
+}
+
+
+sub parse_cfg_file {
+  # Read the configuration file.  Aborts on errors.  Not good to
+  # mirror something using the wrong config.
+
+  my ( $file ) = @_ ;
+  my ($key, $value, $authserver,$authrealm,$authuser,$authpasswd);
+  my $i;
+
+  die "w3mir: config file $file is not a file.\n" unless -f $file;
+  open(CFGF, $file) || die "Could not open config file $file: $!\n";
+
+  $i=0;
+
+  while (<CFGF>) {
+    # Trim off various junk
+    chomp;
+    s/^#.*//;
+    s/^\s+|\s$//g;
+    # Anything left?
+    next if $_ eq '';
+    # Examine remains
+    $i++;
+    $numarg++;
+
+    ($key, $value) = split(/\s*:\s*/,$_,2);
+    $key = lc $key;
+
+    $iref=$value,next if ( $key eq 'initial-referer' );
+    $header=$value,next if ( $key eq 'header' );
+    $pause=numeric($value),next if ( $key eq 'pause' );
+    $retryPause=numeric($value),next if ( $key eq 'retry-pause' );
+    $debug=numeric($value),next if ( $key eq 'debug' );
+    $retry=numeric($value),next if ( $key eq 'retries' );
+    umask(numeric($value)),next if ( $key eq 'umask' );
+    $check_robottxt=boolean($value),next if ( $key eq 'robot-rules' );
+    $edit=boolean($value),next if ($key eq 'remove-nomirror');
+    $indexname=$value,next if ($key eq 'index-name');
+    $s=nway($value,'save','stdout','forget'),next 
+      if ( $key eq 'file-disposition' );
+    $verbose=nway($value,'quiet','brief','chatty')-1,next
+      if ( $key eq 'verbosity' );
+    $w3http::proxyuser=$value,next if $key eq 'http-proxy-user';
+    $w3http::proxypasswd=$value,next if $key eq 'http-proxy-passwd';
+
+    if ( $key eq 'cd' ) {
+      $chdirto=$value;
+      warn "Use of 'cd' is discouraged\n" unless $verbose==-1;
+      next;
+    }
+    
+    if ($key eq 'http-proxy') {
+      ($w3http::proxyserver,$w3http::proxyport)= 
+	$value =~ /([^:]+):?(\d+)?/;
+      $w3http::proxyport=80 unless $w3http::proxyport;
+      $using_proxy=1;
+      next;
+    }
+
+    if ($key eq 'proxy-options') {
+      my($val,$nval,@popts,$pragma);
+      $pragma=1;
+      foreach $val (split(/\s*,\*/,lc $value)) {
+	$nval=nway($val,'no-pragma','revalidate','refresh','no-store',);
+	# Force use of Cache-control: header
+	$pragma=0 if ($nval==0);
+	# use to force proxy to revalidate
+	$pragma=0,push(@popts,'max-age=0') if ($nval==1);
+	# use to force proxy to refresh
+	push(@popts,'no-cache') if ($nval==2);
+	# use if information transfered is sensitive
+	$pragma=0,push(@popts,'no-store') if ($nval==3);
+      }
+      $cache_header=($pragma?'Pragma: ':'Cache-control: ').join(', ',@popts);
+      next;
+    }
+
+
+    if ($key eq 'url') {
+      my ($rum_url_o,$lf_dir,$rum_reurl,$rum_rebase);
+
+      # A two argument URL: line?
+      if ($value =~ m/^(.+)\s+(.+)/i) {
+	# Two arguments.
+	# The last is a directory, it must end in /
+	$lf_dir=$2;
+	$lf_dir.='/' unless $lf_dir =~ m~/$~;
+
+	$rum_url_o=root_queue($1,$lf_dir);
+
+	# The first is a URL, make it more canonical, find the base.
+	# The namespace confusion in this section is correct.(??)
+	$rum_rebase = quotemeta( ($rum_url_o->as_string =~ m~^(.*/)~)[0] );
+
+	# print "URL: ",$rum_url_o->as_string,"\n";
+	# print "Base: $rum_rebase\n";
+
+	# Translate from rum space to lf space:
+	push(@internal_apply,"s/^".$rum_rebase."/".quotemeta($lf_dir)."/");
+
+	# That translation could lead to information loss.
+	$infoloss=1;
+
+	# Fetch rules tests the rum_url_o->as_string.  Fetch whatever
+	# matches the base.
+	$scope_fetch.="return 1 if m/^".$rum_rebase."/".$ipost.";\n";
+
+	# Ignore whatever did not match the base.
+	$scope_ignore.="return 0 if m/^".
+	  quotemeta("http://".$rum_url_o->netloc."/")."/".$ipost.";\n";
+
+      } else {
+	$rum_url_o=root_queue($value,'./');
+
+	$rum_rebase = quotemeta( ($rum_url_o->as_string =~ m~^(.*/)~)[0] );
+
+	# Translate from rum space to lf space:
+	push(@internal_apply,"s/^".$rum_rebase."//");
+
+	$scope_fetch.="return 1 if m/^".$rum_rebase."/".$ipost.";\n";
+	$scope_ignore.="return 0 if m/^".
+	  quotemeta("http://".$rum_url_o->netloc."/")."/".$ipost.";\n";
+      }
+      next;
+    }
+
+    if ($key eq 'also-quene') {
+      print STDERR 
+	"Found 'also-quene' keyword, please replace with 'also-queue'\n";
+      $key='also-queue';
+    }
+
+    if ($key eq 'also' || $key eq 'also-queue') {
+      if ($value =~ m/^(.+)\s+(.+)/i) {
+	my ($rum_url_o,$lf_dir,$rum_reurl,$rum_rebase);
+	# Two arguments.
+	# The last is a directory, it must end in /
+	# print STDERR "URL ",$1," DIR ",$2,"\n";
+	$lf_dir=$2;
+	$lf_dir.='/' unless $lf_dir =~ m~/$~;
+
+	if ($key eq 'also-queue') {
+	  $rum_url_o=root_queue($1,$lf_dir);
+	} else {
+	  root_queue("",$lf_dir);
+	  $rum_url_o=url $1;
+	  $rum_url_o->host(lc $rum_url_o->host);
+	}
+
+	# The first is a URL, find the base
+	$rum_rebase = quotemeta( ($rum_url_o->as_string =~ m~^(.*/)~)[0] );
+
+#	print "URL: $rum_url_o->as_string\n";
+#	print "Base: $rum_rebase\n";
+#	print "Server: $server\n";
+
+	# Ok, now we can transform and select stuff the right way
+	push(@internal_apply,"s/^".$rum_rebase."/".quotemeta($lf_dir)."/");
+	$infoloss=1;
+
+	# Fetch rules tests the rum_url_o->as_string.  Fetch whatever
+	# matches the base.
+	$scope_fetch.="return 1 if m/^".$rum_rebase."/".$ipost.";\n";
+
+	# Ignore whatever did not match the base.  This cures problem
+	# with '..' from base in in rum space pointing within the the
+	# scope in ra space.  We introduced a extra level (or more) of
+	# directories with the apply above.  Must do same with 'Also:'
+	# directives.
+	$scope_ignore.="return 0 if m/^".
+	  quotemeta("http://".$rum_url_o->netloc."/")."/".$ipost.";\n";
+      } else {
+	die "Also: requires 2 arguments\n";
+      }
+      next;
+    }
+
+    if ($key eq 'quene') {
+      print STDERR "Found 'quene' keyword, please replace with 'queue'\n";
+      $key='queue';
+    }
+
+    if ($key eq 'queue') {
+      root_queue($value,"");
+      next;
+    }
+
+    if ($key eq 'ignore-re' || $key eq 'fetch-re') {
+      # Check that it's a re, better that I am strict than for perl to
+      # make compilation errors.
+      unless ($value =~ /^m(.).*\1[gimosx]*$/) {
+	print STDERR "w3mir: $value is not a recognized regular expression\n";
+	exit 1;
+      }
+      # Fall-through to next cases!
+    }
+
+    if ($key eq 'fetch' || $key eq 'fetch-re') {
+      my $expr=$value;
+      $expr = wild_re($expr).$ipost if ($key eq 'fetch');
+      $rule_text.=' return 1 if '.$expr.";\n";
+      next;
+    }
+
+    if ($key eq 'ignore' || $key eq 'ignore-re') {
+      my $expr=$value;
+      $expr = wild_re($expr).$ipost if ($key eq 'ignore');
+      # print STDERR "Ignore expression: $expr\n";
+      $rule_text.=' return 0 if '.$expr.";\n";
+      next;
+    }
+
+
+    if ($key eq 'apply') {
+      unless ($value =~ /^s(.).*\1.*\1[gimosxe]*$/) {
+	print STDERR
+	  "w3mir: '$value' is not a recognized regular expression\n";
+	exit 1;
+      }
+      push(@user_apply,$value) ;
+      $infoloss=1;
+      next;
+    }
+
+    if ($key eq 'agent') {
+      $w3http::agent=$w3mir_agent=$value;
+      next;
+    }
+
+    # The authorization stuff:
+    if ($key eq 'auth-domain') {
+      $useauth=1;
+      ($authserver, $authrealm) = split('/',$value,2);
+      die "w3mir: server part of auth-domain has format server[:port]\n"
+	unless $authserver =~ /^(\S+(:\d+)?)$|^\*$/;
+      $authserver =~ s/:80$//;
+      die "w3mir: auth-domain '$value' is not valid\n"
+	if !defined($authserver) || !defined($authrealm);
+      $authrealm=lc $authrealm;
+    }
+
+    $authuser=$value if ($key eq 'auth-user');
+    $authpasswd=$value if ($key eq 'auth-passwd');
+
+    # Got a full authentication spec?
+    if ($authserver && $authrealm && $authuser && $authpasswd) {
+      $authdata{$authserver}{$authrealm}=$authuser.":".$authpasswd;
+      print "Authentication for $authserver/$authrealm is ".
+	"$authuser/$authpasswd\n" if $verbose>=0;
+      # exit;
+      # Invalidate tmp vars
+      $authserver=$authrealm=$authuser=$authpasswd=undef;
+      next;
+    }
+
+    next if $key eq 'auth-user' || $key eq 'auth-passwd' || 
+      $key eq 'auth-domain';
+
+    if ($key eq 'fetch-options') {
+      warn "w3mir: The 'fetch-options' directive has been renamed to 'options'\nw3mir: Please change your configuration file.\n";
+      $key='options';
+      # Fall through to 'options'!
+    }
+
+    if ($key eq 'options') {
+      
+      my($val,$nval);
+      foreach $val (split(/\s*,\s*/,lc $value)) {
+	if ($i==1) {
+	  $nval=nway($val,'recurse','no-date-check','only-nonexistent',
+		     'list-urls','lowercase','remove','batch','read-urls',
+		     'abs','no-newline-conv');
+	  $r=1,next if $nval==0;
+	  $fetch=1,next if $nval==1;
+	  $fetch=-1,next if $nval==2;
+	  $list=1,next if $nval==3;
+	  if ($nval==4) {
+	    $lc=1;
+	    $iinline=($lc?"(?i)":"");
+	    $ipost=($lc?"i":"");
+	    next ;
+	  }
+	  $remove=1,next if $nval==5;
+	  $convertnl=0,$batch=1,next if $nval==6;
+	  $read_urls=1,next if $nval==7;
+	  $abs=1,next if $nval==8;
+	  $convertnl=0,next if $nval==9;
+        } else {
+	    die "w3mir: options must be the first directive in the config file.\n";
+	}
+      }
+      next;
+    }
+
+    if ($key eq 'disable-headers') {
+      my($val,$nval);
+      foreach $val (split(/\s*,\s*/,lc $value)) {
+	$nval=nway($val,'referer','user');
+	$do_referer=0,next if $nval==0;
+	$do_user=0,next if $nval==1;
+      }
+      next;
+    }
+
+
+    if ($key eq 'fixup') {
+
+      $fixrc="$file";
+      # warn "Fixrc: $fixrc\n";
+
+      my($val,$nval);
+      foreach $val (split(/\s*,\s*/,lc $value)) {
+	$nval=nway($val,'on','run','noindex','off');
+	$runfix=1,next if $nval==1;
+	# Disable fixup
+	$fixup=0,next if $nval==3;
+	# Ignore everyting else
+      }
+      next;
+    }
+
+    die "w3mir: Unrecognized directive ('$key') in config file $file at line $.\n";
+
+  }
+  close(CFGF);
+
+  if (defined($w3http::proxypasswd) && $w3http::proxyuser) {
+    warn "Proxy authentication: ".$w3http::proxyuser.":".
+      $w3http::proxypasswd."\n" if $verbose>=0;
+  }
+
+}
+
+
+sub wild_re {
+  # Here we translate unix wildcard subset to to perlre
+  local($_) = shift;
+
+  # Quote anything that's RE and not wildcard: / ( ) \ | { } + $ ^
+  s~([\/\(\)\\\|\{\}\+)\$\^])~\\$1~g;
+  # . -> \.
+  s~\.~\\.~g;
+  # * -> .*
+  s~\*~\.\*~g;
+  # ? -> .
+  s~\?~\.~g;
+
+  # print STDERR "wild_re: $_\n";
+
+  return $_ = '/'.$_.'/';
+}
+
+
+sub numeric {
+  # Check if argument is numeric?
+  my ( $number ) = @_ ;
+  return oct($number) if ($number =~ /\d+/ || $number =~ /\d+.\d+/);
+  die "Expected a number, got \"$number\"\n";
+}
+
+
+sub boolean {
+  my ( $boolean ) = @_ ;
+
+  $boolean = lc $boolean;
+
+  return 0 if ($boolean eq 'false' || $boolean eq 'off' || $boolean eq '0');
+  return 1 if ($boolean eq 'true' || $boolean eq 'on' || $boolean eq '1');
+  die "Expected a boolean, got \"$boolean\"\n";
+}
+
+
+sub nway {
+  my ( $value ) = shift;
+  my ( @values ) = @_;
+  my ( $val ) = 0;
+
+  $value = lc $value;
+  while (@_) {
+    return $val if $value eq shift;
+    $val++;
+  }
+  die "Expected one of ".join(", ",@values).", got \"$value\"\n";
+}
+
+
+sub insert_at_start {
+  # ark: inserts the first arg at the top of the html in the second arg
+  # janl: The second arg must be a reference to a scalar.
+  my( $str, $text_ref ) = @_;
+  my( @possible ) =("<BODY.*?>", "</HEAD.*?>", "</TITLE.*?>", "<HTML.*?>" );
+  my( $f, $done );
+  
+  $done=0;
+  @_=@possible;
+  
+  while( $done!=1 && ($f=shift) ){
+    print "Searching for: $f\n";
+    if( $$text_ref =~ /$f/i ){
+      print "found it!\n";
+      $$text_ref =~ s/($f)/$1\n$str/i;
+      $done=1;
+    }
+  }
+}
+
+
+
+sub rm_rf {
+  # Recursively remove directories and other files
+  # File::Path::rmtree does a similar thing but the messages are wrong
+
+  my($remove)=shift;
+
+  eval "use File::Find;" unless defined(&finddepth);
+
+  die "w3mir: Could not load File::Find module when trying to remove $remove\n"
+    unless defined(&find);
+
+  finddepth(\&remove_everything,$remove);
+
+  if (rmdir($remove)) {
+    print STDERR "\nw3mir: removed directory $remove\n" if $verbose>=0;
+  } else {
+    print STDERR "w3mir: could not remove $remove: $!\n";
+  }
+}
+
+
+sub remove_everything {
+  # This does the removal
+  ((-d && rmdir($_)) || unlink($_)) && $verbose>=0 &&
+    print STDERR "w3mir: removed $File::Find::name\n";
+}
+
+
+
+sub usage {
+  my($message)=shift @_;
+
+  print STDERR "w3mir: $message\n" if $message;
+  
+  die 'w3mir: usage: w3mir [options] <single-http-url>
+          or: w3mir -B [-I] [options] [<http-urls>]
+
+    Options :
+	-agent <agent>	- Set the agent name.  Default is w3mir
+	-abs		- Force all URLs to be absolute.
+	-B		- Batch-get documents.
+	-I		- The URLs to get are read from standard input.
+	-c		- be more Chatty.
+	-cfgfile <file> - Read config from file
+	-d <debug-level>- set debug level to 1 or 2
+	-drr		- Disable robots.txt rules.
+	-f		- Forget all files, nothing is saved to disk.
+	-fa		- Fetch All, will not check timestamps.
+	-fs		- Fetch Some, do not fetch the files we already have.
+	-ir <referer>	- Initial referer.  For picky servers.
+	-l		- List URLs in the documents retrived.
+	-lc		- Convert all URLs (and filenames) to lowercase.
+				This does not work reliably.
+	-p <n>		- Pause n seconds before retriving each doc.
+	-q		- Quiet, error-messages only
+        -rp <n>		- Retry Pause in seconds.
+	-P <server:port>- Use host/port for proxy http requests
+        -pflush		- Flush proxy server.
+	-r		- Recursive mirroring.
+        -R		- Remove files not referenced or not present on server.
+	-s		- Send output to stdout instead of file
+	-t <n>		- How many times to (re)try getting a failed doc?
+        -umask <umask>  - Set umask for mirroring, must be usual octal format.
+	-nnc		- No Newline Conversion.  Disable newline conversions.
+	-v		- Show w3mir version.
+';
+}
+__END__
+# -*- perl -*- There must be a blank line here
+
+=head1 NAME
+
+w3mir - all purpose HTTP-copying and mirroring tool
+
+=head1 SYNOPSIS
+
+B<w3mir> [B<options>] [I<HTTP-URL>]
+
+B<w3mir> B<-B> [B<options>] <I<HTTP-URLS>>
+
+B<w3mir> is a all purpose HTTP copying and mirroring tool.  The
+main focus of B<w3mir> is to create and maintain a browsable copy of
+one, or several, remote WWW site(s).
+
+Used to the max w3mir can retrive the contents of several related
+sites and leave the mirror browseable via a local web server, or from
+a filesystem, such as directly from a CDROM.  
+
+B<w3mir> has options for all operations that are simple enough for
+options.  For authentication and passwords, multiple site retrievals
+and such you will have to resort to a L</CONFIGURATION-FILE>.  If
+browsing from a filesystem references ending in '/' needs to be
+rewritten to end in '/index.html', and in any case, if there are URLs
+that are redirected will need to be changed to make the mirror
+browseable, see the documentation of B<Fixup> in the
+L</CONFIGURATION-FILE> secton.
+
+B<w3mir>s default behavior is to do as little as possible and to be as
+nice as possible to the server(s) it is getting documents from.  You
+will need to read through the options list to make B<w3mir> do more
+complex, and, useful things.  Most of the things B<w3mir> can do is
+also documented in the w3mir-HOWTO which is available at the B<w3mir>
+home-page (F<http://www.math.uio.no/~janl/w3mir/>) as well as in the
+w3mir distribution bundle.
+
+=head1 DESCRIPTION
+
+You may specify many options and one HTTP-URL on the w3mir
+command line.
+
+A single HTTP URL I<must> be specified either on the command line or
+in a B<URL> directive in a configuration file.  If the URL refers to a
+directory it I<must> end with a "/", otherwise you might get surprised
+at what gets retrieved (e.g. rather more than you expect).
+
+Options must be prefixed with at least one - as shown below, you can
+use more if you want to. B<-cfgfile> is equivalent to B<--cfgfile> or
+even B<------cfgfile>.  Options cannot be I<clustered>, i.e., B<-r -R>
+is not equivalent to B<-rR>.
+
+=over 4
+
+=item B<-h> | B<-help> | B<-?>
+
+prints a brief summary of all command line options and exits.
+
+=item B<-cfgfile> F<file>
+
+Makes B<w3mir> read the given configuration file.  See the next section
+for how to write such a file.
+
+=item B<-r>
+
+Puts B<w3mir> into recursive mode.  The default is to fetch only one
+document and then quit.  'I<recursive>' mode means that all the
+documents linked to the given document that are fetched, and all they
+link to in turn and so on.  But only I<Iff> they are in the same
+directory or under the same directory as the start document.  Any
+document that is in or under the starting documents directory is said
+to be within the I<scope of retrieval>.
+
+=item B<-fa>
+
+Fetch All.  Normally B<w3mir> will only get the document if it has been
+updated since the last time it was fetched.  This switch turns that
+check off.
+
+=item B<-fs>
+
+Fetch Some.  Not the opposite of B<-fa>, but rather, fetch the ones we
+don't have already.  This is handy to restart copying of a site
+incompletely copied by earlier, interrupted, runs of B<w3mir>.
+
+=item B<-p> I<n>
+
+Pause for I<n> seconds between getting each document.  The default is
+30 seconds.
+
+=item B<-rp> I<n>
+
+Retry Pause, in seconds.  When B<w3mir> fails to get a document for some
+technical reason (timeout mainly) the document will be queued for a
+later retry.  The retry pause is how long B<w3mir> waits between
+finishing a mirror pass before starting a new one to get the still
+missing documents.  This should be a long time, so network conditions
+have a chance to get better.  The default is 600 seconds (10 minutes),
+which might be a bit too short, for batch running B<w3mir> I would
+suggest an hour (3600 seconds) or more.
+
+=item B<-t> I<n>
+
+Number of reTries.  If B<w3mir> cannot get all the documents by the
+I<n>th retry B<w3mir> gives up.  The default is 3.
+
+=item B<-drr>
+
+Disable Robot Rules.  The robot exclusion standard is described in
+http://info.webcrawler.com/mak/projects/robots/norobots.html.  By
+default B<w3mir> honors this standard.  This option causes B<w3mir> to
+ignore it.
+
+=item B<-nnc>
+
+No Newline Conversion.  Normally w3mir converts the newline format of
+all files that the web server says is a text file.  However, not all
+web servers are reliable, and so binary files may become corrupted due
+to the newline conversion w3mir performs.  Use this option to stop
+w3mir from converting newlines.  This also causes the file to be
+regarded as binary when written to disk, to disable the implicit
+newline conversion when saving text files on most non-Unix systems.
+
+This will probably be on by default in version 1.1 of w3mir, but not
+in version 1.0.
+
+=item B<-R>
+
+Remove files.  Normally B<w3mir> will not remove files that are no
+longer on the server/part of the retrieved web of files.  When this
+option is specified all files no longer needed or found on the servers
+will be removed.  If B<w3mir> fails to get a document for I<any> other
+reason the file will not be removed.
+
+=item B<-B>
+
+Batch fetch documents whose URLs are given on the commandline.
+
+In combination with the B<-r> and/or B<-l> switch all HTML and PDF
+documents will be mined for URLs, but the documents will be saved on
+disk unchanged.  When used with the B<-r> switch only one single URL
+is allowed.  When not used with the B<-r> switch no HTML/URL
+processing will be performed at all.  When the B<-B> switch is used
+with B<-r> w3mir will not do repeated mirrorings reliably since the
+changes w3mir needs to do, in the documents, to work reliably are not
+done.  In any case it's best not to use B<-R> in combination with
+B<-B> since that can result in deleting rather more documents than
+expected.  Hwowever, if the person writing the documents being copied
+is good about making references relative and placing the <HTML> tag at
+the beginning of documents there is a fair chance that things will
+work even so.  But I wouln't bet on it.  It will, however, work
+reliably for repeated mirroring if the B<-r> switch is not used.
+
+When the B<-B> switch is specified redirects for a given document will
+be followed no matter where they point.  The redirected-to document
+will be retrieved in the place of the original document.  This is a
+potential weakness, since w3mir can be directed to fetch any document
+anywhere on the web.
+
+Unless used with B<-r> all retrived files will be stored in one
+directory using the remote filename as the local filename.  I.e.,
+F<http://foo/bar/gazonk.html> will be saved as F<gazonk.html>.
+F<http://foo/bar/> will be saved as F<bar-index.html> so as to avoid
+name colitions for the common case of URLs ending in /.
+
+=item B<-I>
+
+This switch can only be used with the B<-B> switch, and only after it
+on the commandline or configuration file.  When given w3mir will get
+URLs from standard input (i.e., w3mir can be used as the end of a pipe
+that produces URLs.)  There should only be one URL pr. line of input.
+
+=item B<-q>
+
+Quiet.  Turns off all informational messages, only errors will be
+output.
+
+=item B<-c>
+
+Chatty.  B<w3mir> will output more progress information.  This can be
+used if you're watching B<w3mir> work.
+
+=item B<-v>
+
+Version.  Output B<w3mir>s version.
+
+=item B<-s>
+
+Copy the given document(s) to STDOUT.
+
+=item B<-f>
+
+Forget.  The retrieved documents are not saved on disk, they are just
+forgotten.  This can be used to prime the cache in proxy servers, or
+not save documents you just want to list the URLs in (see B<-l>).
+
+=item B<-l>
+
+List the URLs referred to in the retrieved document(s) on STDOUT.
+
+=item B<-umask> I<n>
+
+Sets the umask, i.e., the permission bits of all retrieved files.  The
+number is taken as octal unless it starts with a 0x, in which case
+it's taken as hexadecimal.  No matter what you set this to make sure
+you get write as well as read access to created files and directories.
+
+Typical values are: 
+
+=over 8
+
+=item 022
+
+let everyone read the files (and directories), only you can change
+them. 
+
+=item 027
+
+you and everyone in the same file-group as you can read, only you can
+change them.
+
+=item 077
+
+only you can read the files, only you can change them.
+
+=item 0
+
+everyone can read, write and change everything.
+
+=back
+
+The default is whatever was set when B<w3mir> was invoked.  022 is a
+reasonable value.
+
+This option has no meaning, or effect, on Win32 platforms.
+
+=item B<-P> I<server:port>
+
+Use the given server and port is a HTTP proxy server.  If no port is
+given port 80 is assumed (this is the normal HTTP port).  This is
+useful if you are inside a firewall, or use a proxy server to save
+bandwidth.
+
+=item B<-pflush>
+
+Proxy flush, force the proxy server to flush it's cache and re-get the
+document from the source.  The I<Pragma: no-cache> HTTP/1.0 header is
+used to implement this.
+
+=item B<-ir> I<referrer>
+
+Initial Referrer.  Set the referrer of the first retrieved document.
+Some servers are reluctant to serve certain documents unless this is
+set right.
+
+=item B<-agent> I<agent>
+
+Set the HTTP User-Agent fields value.  Some servers will serve
+different documents according to the WWW browsers capabilities.
+B<w3mir> normally has B<w3mir>/I<version> in this header field.
+Netscape uses things like B<Mozilla/3.01 (X11; I; Linux 2.0.30 i586)>
+and MSIE uses things like B<Mozilla/2.0 (compatible; MSIE 3.02;
+Windows NT)> (remember to enclose agent strings with spaces in with
+double quotes ("))
+
+=item B<-lc>
+
+Lower Case URLs. Some OSes, like W95 and NT, are not case sensitive
+when it comes to filenames.  Thus web masters using such OSes can case
+filenames differently in different places (apps.html, Apps.html,
+APPS.HTML).  If you mirror to a Unix machine this can result in one
+file on the server becoming many in the mirror.  This option
+lowercases all filenames so the mirror corresponds better with the
+server.
+
+If given it must be the first option on the command line.
+
+This option does not work perfectly.  Most especially for mixed case
+host-names.
+
+=item B<-d> I<n>
+
+Set the debug level.  A debug level higher than 0 will produce lots of
+extra output for debugging purposes.
+
+=item B<-abs>
+
+Force all URLs to be absolute.  If you retrive
+F<http://www.ifi.uio.no/~janl/index.html> and it references foo.html
+the referense is absolutified into
+F<http://www.ifi.uio.no/~janl/foo.html>.  In other words, you get
+absolute references to the origin site if you use this option.
+
+=back
+
+=head1 CONFIGURATION-FILE
+
+Most things can be mirrored with a (long) command line.  But multi
+server mirroring, authentication and some other things are only
+available through a configuration file.  A configuration file can
+either be specified with the B<-cfgfile> switch, but w3mir also looks
+for .w3mirc (w3mir.ini on Win32 platforms) in the directory where
+w3mir is started from.
+
+The configuration file consists of lines of comments and directives.
+A directive consists of a keyword followed by a colon (:) and then one
+or several arguments.
+
+ # This is a comment.  And the next line is a directive:
+ Options: recurse, remove
+
+A comment can only start at the beginning of a line.  The directive
+keywords are not case-sensitive, but the arguments I<might> be.
+
+=over 4
+
+=item Options: I<recurse> | I<no-date-check> | I<only-nonexistent> | I<list-urls> | I<lowercase> | I<remove> | I<batch> | I<input-urls> | I<no-newline-conv>
+
+This must be the first directive in a configuration file.  
+
+=over 8
+
+=item I<recurse>
+
+see B<-r> switch.
+
+=item I<no-date-check>
+
+see B<-fa> switch.
+
+=item I<only-nonexistent>
+
+see B<-fs> switch.
+
+=item I<list-urls>
+
+see B<-l> option.
+
+=item I<lowercase>
+
+see B<-lc> option. 
+
+=item I<remove>
+
+see B<-R> option.
+
+=item I<batch>
+
+see B<-B> option.
+
+=item I<input-urls>
+
+see B<-I> option.
+
+=item I<no-newline-conv>
+
+see B<-nnc> option.
+
+=back
+
+=item URL: I<HTTP-URL> [I<target-directory>]
+
+The URL directive may only appear once in any configuration file.
+
+Without the optional target directory argument it corresponds directly
+to the I<single-HTTP-URL> argument on the command line.  
+
+If the optional target directory is given all documents from under the
+given URL will be stored in that directory, and under.  The target
+directory is most likely only specified if the B<Also> directive is
+also specified.
+
+If the URL given refers to a directory it I<must> end in a "/",
+otherwise you might get quite surprised at what gets retrieved.
+
+Either one URL: directive or the single-HTTP-URL at the command-line
+I<must> be given.
+
+=item Also: I<HTTP-URL directory>
+
+This directive is only meaningful if the I<recurse> (or B<-r>)
+option is given.
+
+The directive enlarges the scope of a recursive retrieval to contain
+the given HTTP-URL and all documents in the same directory or under.
+Any documents retrieved because of this directive will be stored in the
+given directory of the mirror.
+
+In practice this means that if the documents to be retrieved are stored
+on several servers, or in several hierarchies on one server or any
+combination of those.  Then the B<Also> directive ensures that we get
+everything into one single mirror.
+
+This also means that if you're retrieving
+
+  URL: http://www.foo.org/gazonk/
+
+but it has inline icons or images stored in http://www.foo.org/icons/
+which you will also want to get, then that will be retrieved as well by
+entering
+
+  Also: http://www.foo.org/icons/ icons
+
+As with the URL directive, if the URL refers to a directory it I<must>
+end in a "/".
+
+Another use for it is when mirroring sites that have several names
+that all refer to the same (logical) server:
+
+  URL: http://www.midifest.com/
+  Also: http://midifest.com/ .
+
+At this point in time B<w3mir> has no mechanism to easily enlarge the
+scope of a mirror after it has been established.  That means that you
+should survey the documents you are going to retrieve to find out what
+icons, graphics and other things they refer to that you want.  And
+what other sites you might like to retrieve.  If you find out that
+something is missing you will have to delete the whole mirror, add the
+needed B<Also> directives and then reestablish the mirror.  This lack
+of flexibility in what to retrieve will be addressed at a later date.
+
+See also the B<Also-quene> directive.
+
+=item Also-quene: I<HTTP-URL directory>
+
+This is like Also, except that the URL itself is also quened.  The
+Also directive will not cause any documents to be retrived UNLESS they
+are referenced by some other document w3mir has already retrived.
+
+=item Quene: I<HTTP-URL>
+
+This is quenes the URL for retrival, but does not enlarge the scope of
+the retrival.  If the URL is outside the scope of retrival it will not
+be retrived anyway.
+
+The observant reader will see that B<Also-quene> is like B<Also>
+combined with B<Quene>.
+
+=item Initial-referer: I<referer>
+
+see B<-ir> option.
+
+=item Ignore: F<wildcard>
+
+=item Fetch: F<wildcard>
+
+=item Ignore-RE: F<regular-expression>
+
+=item Fetch-RE: F<regular-expression>
+
+These four are used to set up rules about which documents, within the
+scope of retrieval, should be gotten and which not.  The default is to
+get I<anything> that is within the scope of retrieval.  That may not
+be practical though.  This goes for CGI scripts, and especially server
+side image maps and other things that are executed/evaluated on the
+server.  There might be other things you want unfetched as well.
+
+B<w3mir> stores the I<Ignore>/I<Fetch> rules in a list.  When a
+document is considered for retrieval the URL is checked against the
+list in the same order that the rules appeared in the configuration
+file.  If the URL matches any rule the search stops at once.  If it
+matched a I<Ignore> rule the document is not fetched and any URLs in
+other documents pointing to it will point to the document at the
+original server (not inside the mirror).  If it matched a I<Fetch>
+rule the document is gotten.  If not matched by any ruøes the document
+is gotten.
+
+The F<wildcard>s are a very limited subset of Unix-wildcards.
+B<w3mir> understands only 'I<?>', 'I<*>', and 'I<[x-y]>' ranges.
+
+The F<perl-regular-expression> is perls superset of the normal Unix
+regular expression syntax.  They must be completely specified,
+including the prefixed m, a delimiter of your choice (except the
+paired delimiters: parenthesis, brackets and braces), and any of the
+RE modifiers. E.g.,
+
+  Ignore-RE: m/.gif$/i
+
+or
+
+  Ignore-RE: m~/.*/.*/.*/~
+
+and so on.  "#" cannot be used as delimiter as it is the comment
+character in the configuration file.  This also has the bad
+side-effect of making you unable to match fragment names (#foobar)
+directly.  Fortunately perl allows writing ``#'' as ``\043''.
+
+You must be very carefull of using the RE anchors (``^'' and ``$''
+with the RE versions of these and the I<Apply> directive. Given the
+rules:
+
+  Fetch-RE: m/foobar.cgi$/
+  Ignore: *.cgi
+
+the all files called ``foobar.cgi'' will be fetched. However, if the
+file is referenced as ``foobar.cgi?query=mp3'' it will I<not> be
+fetched since the ``$'' anchor will prevent it from matching the
+I<Fetch-RE> directive and then it will match the I<Ignore> directive
+instead. If you want to match ``foobar.cgi'' but not ``foobar.cgifu''
+you can use perls ``\b'' character class which matches a word
+boundrary:
+
+  Fetch-RE: m/foobar.cgi\b/
+  Ignore: *.cgi
+
+which will get ``foobar.cgi'' as well as ``foobar.cgi?query=mp3'' but
+not ``foobar.cgifu''. BUT, you must keep in mind that a lot of
+diffetent characters make a word boundrary, maybe something more
+subtle is needed.
+
+=item Apply: I<regular-expression>
+
+This is used to change a URL into another URL.  It is a potentially
+I<very> powerful feature, and it also provides ample chance for you to
+shoot your own foot. The whole aparatus is somewhat tenative, if you
+find there is a need for changes in how Apply rules work please
+E-mail. If you are going to use this feature please read the
+documentation for I<Fetch-RE> and I<Ignore-RE> first.
+
+The B<Apply> expressions are applied, in sequence, to the URLs in
+their absolute form. I.e., with the whole
+http://host:port/dir/ec/tory/file URL. It is only after this B<w3mir>
+checks if a document is within the scope of retrieval or not. That
+means that B<Apply> rules can be used to change certain URLs to fall
+inside the scope of retrieval, and vice versa.
+
+The I<regular-expression> is perls superset of the usual Unix regular
+expressions for substitution.  As with I<Fetch> and I<Ignore> rules it
+must be specified fully, with the I<s> and delimiting character.  It
+has the same restrictions with regards to delimiters. E.g.,
+
+  Apply: s~/foo/~/bar/~i
+
+to translate the path element I<foo> to I<bar> in all URLs.
+
+"#" cannot be used as delimiter as it is the comment character in the
+configuration file.
+
+Please note that w3mir expects that URLs identifying 'directories'
+keep idenfifying directories after application of Apply rules.  Ditto
+for files.
+
+=item Agent: I<agent>
+
+see B<-agent> option.
+
+=item Pause: I<n>
+
+see B<-p> option.
+
+=item Retry-Pause: I<n>
+
+see B<-rp> option.
+
+=item Retries: I<n>
+
+see B<-t> option.
+
+=item debug: I<n>
+
+see B<-d> option.
+
+=item umask I<n>
+
+see B<-umask> option.
+
+=item Robot-Rules: I<on> | I<off>
+
+Turn robot rules on of off.  See B<-drr> option.
+
+=item Remove-Nomirror: I<on> | I<off>
+
+If this is enabled sections between two consecutive
+
+  <!--NO MIRROR-->
+
+comments in a mirrored document will be removed.  This editing is
+performed even if batch getting is specified.
+
+=item Header: I<html/text>
+
+Insert this I<complete> html/text into the start of the document.
+This will be done even if batch is specified.
+
+=item File-Disposition: I<save> | I<stdout> | I<forget>
+
+What to do with a retrieved file.  The I<save> alternative is default.
+The two others correspond to the B<-s> and B<-f> options.  Only one
+may be specified.
+
+=item Verbosity: I<quiet> | I<brief> | I<chatty>
+
+How much B<w3mir> informs you of it's progress.  I<Brief> is the
+default.  The two others correspond to the B<-q> and B<-c> switches.
+
+=item Cd: I<directory>
+
+Change to given directory before starting work.  If it does not exist
+it will be quietly created.  Using this option breaks the 'fixup'
+code so consider not using it, ever.
+
+=item HTTP-Proxy: I<server:port>
+
+see the B<-P> switch.
+
+=item HTTP-Proxy-user: I<username>
+
+=item HTTP-Proxy-passwd: I<password>
+
+These two are is used to activate authentication with the proxy
+server.  L<w3mir> only supports I<basic> proxy autentication, and is
+quite simpleminded about it, if proxy authentication is on L<w3mir>
+will always give it to the proxy.  The domain concept is not supported
+with proxy-authentication.
+
+=item Proxy-Options: I<no-pragma> | I<revalidate> | I<refresh> | I<no-store>
+
+Set proxy options.  There are two ways to pass proxy options, HTTP/1.0
+compatible and HTTP/1.1 compatible.  Newer proxy-servers will
+understand the 1.1 way as well as 1.0.  With old proxy-servers only
+the 1.0 way will work.  L<w3mir> will prefer the 1.0 way.
+
+The only 1.0 compatible proxy-option is I<refresh>, it corresponds to
+the B<-pflush> option and forces the proxy server to pass the request
+to a upstream server to retrieve a I<fresh> copy of the document. 
+
+The I<no-pragma> option forces w3mir to use the HTTP/1.1 proxy
+control header, use this only with servers you know to be new,
+otherwise it won't work at all.  Use of any option but I<refresh> will
+also cause HTTP/1.1 to be used.  
+
+I<revalidate> forces the proxy server to contact the upstream server
+to validate that it has a fresh copy of the document.  This is nicer
+to the net than I<refresh> option which forces re-get of the document
+no matter if the server has a fresh copy already.
+
+I<no-store> forbids the proxy from storing the document in other than
+in transient storage.  This can be used when transferring sensitive
+documents, but is by no means any warranty that the document can't be
+found on any storage device on the proxy-server after the transfer.
+Cryptography, if legal in your contry, is the solution if you want the
+contents to be secret.
+
+I<refresh> corresponds to the HTTP/1.0 header I<Pragma: no-cache> or
+the identical HTTP/1.1 I<Cache-control> option.  I<revalidate> and
+I<no-store> corresponds to I<max-age=0> and I<no-store> respectively.
+
+=item Authorization
+
+B<w3mir> supports only the I<basic> authentication of HTTP/1.0.  This
+method can assign a password to a given user/server/I<realm>.  The
+"user" is your user-name on the server.  The "server" is the server.
+The I<realm> is a HTTP concept.  It is simply a grouping of files and
+documents.  One file or a whole directory hierarchy can belong to a
+realm.  One server may have many realms.  A user may have separate
+passwords for each realm, or the same password for all the realms the
+user has access to.  A combination of a server and a realm is called a
+I<domain>.
+
+=over 8
+
+=item Auth-Domain: I<server:port/realm>
+
+Give the server and port, and the belonging realm (making a domain)
+that the following authentication data holds for.  You may specify "*"
+wildcard for either of I<server:port> and I<realm>, this will work
+well if you only have one usernme and password on all the servers
+mirrored.
+
+=item Auth-User: I<user>
+
+Your user-name.
+
+=item Auth-Passwd: I<password>
+
+Your password.
+
+=back
+
+These three directives may be repeated, in clusters, as many times as
+needed to give the necessary authentication information
+
+=item Disable-Headers: I<referer> | I<user>
+
+Stop B<w3mir> from sending the given headers.  This can be used for
+anonymity, making your retrievals harder to track.  It will be even
+harder if you specify a generic B<Agent>, like Netscape.
+
+=item Fixup: I<...>
+
+This directive controls some aspects of the separate program w3mfix.
+w3mfix uses the same configuration file as w3mir since it needs a lot
+of the information in the B<w3mir> configuration file to do it's work
+correctly.  B<w3mfix> is used to make mirrors more browseable on
+filesystems (disk or CDROM), and to fix redirected URLs and some other
+URL editing.  If you want a mirror to be browseable of disk or CDROM
+you almost certainly need to run w3mfix.  In many cases it is not
+necessary when you run a mirror to be used through a WWW server.
+
+To make B<w3mir> write the data files B<w3mfix> needs, and do nothing
+else, simply put
+
+=over 8
+
+  Fixup: on
+
+=back
+
+in the configuration file.  To make B<w3mir> run B<w3mfix>
+automatically after each time B<w3mir> has completed a mirror run
+specify
+
+=over 8
+
+  Fixup: run
+
+=back
+
+L<w3mfix> is documented in a separate man page in a effort to not
+prolong I<this> manpage unnecessarily.
+
+=item Index-name: I<name-of-index-file>
+
+When retriving URLs ending in '/' w3mir needs to append a filename to
+store it localy.  The default value for this is 'index.html' (this is
+the most used, its use originated in the NCSA HTTPD as far as I know).
+Some WWW servers use the filename 'Welcome.html' or 'welcome.html'
+instead (this was the default in the old CERN HTTPD).  And servers
+running on limited OSes frequently use 'index.htm'.  To keep things
+consistent and sane w3mir and the server should use the same name.
+Put
+
+  Index-name: welcome.html
+
+when mirroring from a site that uses that convention.
+
+When doing a multiserver retrival where the servers use two or more
+different names for this you should use B<Apply> rules to make the
+names consistent within the mirror.
+
+When making a mirror for use with a WWW server, the mirror should use
+the same name as the new server for this, to acomplish that
+B<Index-name> should be combined with B<Apply>.
+
+Here is an example of use in the to latter cases when Welcome.html is
+the prefered I<index> name:
+
+  Index-name: Welcome.html
+  Apply: s~/index.html$~/Welcome.html~
+
+Similarly, if index.html is the prefered I<index> name.
+
+  Apply: s~/Welcome.html~/index.html~
+
+I<Index-name> is not needed since index.html is the default index name.
+
+=back
+
+=head1 EXAMPLES
+
+=over 4
+
+=item * Just get the latest Dr-Fun if it has been changed since the last
+time
+
+ w3mir http://sunsite.unc.edu/Dave/Dr-Fun/latest.jpg
+
+=item * Recursively fetch everything on the Star Wars site, remove
+what is no longer at the server from the mirror:
+
+ w3mir -R -r http://www.starwars.com/
+
+=item * Fetch the contents of the Sega site through a proxy, pausing
+for 30 seconds between each document
+
+ w3mir -r -p 30 -P www.foo.org:4321 http://www.sega.com/
+
+=item * Do everything according to F<w3mir.cfg>
+
+ w3mir -cfgfile w3mir.cfg
+
+=item * A simple configuration file
+
+ # Remember, options first, as many as you like, comma separated
+ Options: recurse, remove
+ #
+ # Start here:
+ URL: http://www.starwars.com/
+ #
+ # Speed things up
+ Pause: 0
+ #
+ # Don't get junk
+ Ignore: *.cgi
+ Ignore: *-cgi
+ Ignore: *.map
+ #
+ # Proxy:
+ HTTP-Proxy: www.foo.org:4321
+ #
+ # You _should_ cd away from the directory where the config file is.
+ cd: starwars
+ #
+ # Authentication:
+ Auth-domain: server:port/realm
+ Auth-user: me
+ Auth-passwd: my_password
+ #
+ # You can use '*' in place of server:port and/or realm:
+ Auth-domain: */*
+ Auth-user: otherme
+ Auth-user: otherpassword
+
+=item Also:
+
+ # Retrive all of janl's home pages:
+ Options: recurse
+ #
+ # This is the two argument form of URL:.  It fetches the first into the second
+ URL: http://www.math.uio.no/~janl/ math/janl
+ #
+ # These says that any documents refered to that lives under these places
+ # should be gotten too.  Into the named directories.  Two arguments are
+ # required for 'Also:'.
+ Also: http://www.math.uio.no/drift/personer/ math/drift
+ Also: http://www.ifi.uio.no/~janl/ ifi/janl
+ Also: http://www.mi.uib.no/~nicolai/ math-uib/nicolai
+ #
+ # The options above will result in this directory hierarchy under
+ # where you started w3mir:
+ # w3mir/math/janl		files from http://www.math.uio.no/~janl
+ # w3mir/math/drift		from http://www.math.uio.no/drift/personer/
+ # w3mir/ifi/janl		from http://www.ifi.uio.no/~janl/
+ # w3mir/math-uib/nicolai	from http://www.mi.uib.no/~nicolai/
+
+=item Ignore-RE and Fetch-RE
+
+ # Get only jpeg/jpg files, no gifs
+ Fetch-RE: m/\.jp(e)?g$/
+ Ignore-RE: m/\.gif$/
+
+=item Apply
+
+As I said earlier, B<Apply> has not been used for Real Work yet, that
+I know of.  But B<Apply> I<could>, be used to map all web servers at
+the university of Oslo inside the scope of retrieval very easily:
+
+  # Start at the main server
+  URL: http://www.uio.no/
+  # Change http://*.uio.no and http://129.240.* to be a subdirectory
+  # of http://www.uio.no/.
+  Apply: s~^http://(.*\.uio\.no(?:\d+)?)/~http://www.uio.no/$1/~i
+  Apply: s~^http://(129\.240\.[^:]*(?:\d+)?)/~http://www.uio.no/$1/~i
+
+
+=back
+
+There are two rather extensive example files in the B<w3mir> distribution.
+
+=head1 BUGS
+
+=over 4
+
+=item The -lc switch does not work too well.
+
+=back
+
+=head1 FEATURES
+
+These are not bugs.
+
+=over 4
+
+=item URLs with two /es ('//') in the path component does not work as
+some might expect.  According to my reading of the URL spec. it is an
+illegal construct, which is a Good Thing, because I don't know how to
+handle it if it's legal.
+
+=item If you start at http://foo/bar/ then index.html might be gotten
+twice.
+
+=item Some documents point to a point above the server root, i.e.,
+http://some.server/../stuff.html.  Netscape, and other browsers, in
+defiance of the URL standard documents will change the URL to
+http://some.server/stuff.html.  W3mir will not.
+
+=item Authentication is I<only> tried if the server requests it.  This
+might lead to a lot of extra connections going up and down, but that's
+the way it's gotta work for now.
+
+=back
+
+=head1 SEE ALSO
+
+L<w3mfix>
+
+=head1 AUTHORS
+
+B<w3mir>s authors can be reached at I<w3mir-core@usit.uio.no>.
+B<w3mir>s home page is at http://www.math.uio.no/~janl/w3mir/
Index: /main/tags/2.25/gsdl/packages/w3mir/w3mir-1.0.8/w3pdfuri.pm
===================================================================
--- /main/tags/2.25/gsdl/packages/w3mir/w3mir-1.0.8/w3pdfuri.pm	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/w3mir/w3mir-1.0.8/w3pdfuri.pm	(revision 21064)
@@ -0,0 +1,64 @@
+# -*- perl -*-
+#
+# w3pdfuri.pm -- extract uris from a adobe acrobat pdf file.
+#     version 0.1
+$VERSION=0.1;
+#
+# Assumptions:
+# - File starts with %PDF
+# - All URLS match this RE: ^\/URI\s+\(([^)]*)\)\s*$  (found by inspection of
+#   one (1) pdf file (the reader.pdf in the acrobat distribution).
+# - pdf files are potentially very large, so we read it from disk
+#   record by record.
+# - Record separator is ^M
+#
+# History:
+# - 19/02/97 janl: Version 0.1, seems to work with PDF-1.2
+#
+
+package w3pdfuri;
+
+use strict;
+
+sub list ($) {
+  my ($file) = @_;
+
+  my @urls=();
+  local($/)="\r";
+
+  unless (open(PDF,"< $file")) {
+    warn "Could not open $file for input: $!\n";
+    return;
+  }
+
+  $_ = <PDF>;
+  unless (/^%PDF-/) {
+    warn "$file is not a PDF file.\n";
+    close(PDF);
+    return;
+  }
+  
+  while (<PDF>) {
+    chomp;
+    push(@urls,$1) if (m~^/URI\s+\(([^)]*)\)\s*$~);
+  }
+
+  close(PDF);
+
+  return @urls;
+}
+
+1;
+
+__END__
+
+# Test code
+print "reader.pdf: ",
+  join(",",list("/local/lib/acrobat/Reader/help/reader.pdf")),"\n";
+print "Acrobat.pdf: ",
+  join(",",list("/local/lib/acrobat/Reader/Acrobat.pdf")),"\n";
+print "License.pdf: ",
+  join(",",list("/local/lib/acrobat/Reader/License.pdf")),"\n";
+print "MapTypes.pdf: ",
+  join(",",list("/local/lib/acrobat/Reader/MapTypes.pdf")),"\n";
+list("/etc/services");
Index: /main/tags/2.25/gsdl/packages/wincrypt/COPYING.LIB
===================================================================
--- /main/tags/2.25/gsdl/packages/wincrypt/COPYING.LIB	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/wincrypt/COPYING.LIB	(revision 21064)
@@ -0,0 +1,501 @@
+GNU LIBRARY GENERAL PUBLIC LICENSE
+**********************************
+
+                         Version 2, June 1991
+
+     Copyright (C) 1991 Free Software Foundation, Inc.
+     59 Temple Place -- Suite 330, Boston, MA 02111-1307, USA
+     
+     Everyone is permitted to copy and distribute verbatim copies
+     of this license document, but changing it is not allowed.
+     
+     [This is the first released version of the library GPL.  It is
+      numbered 2 because it goes with version 2 of the ordinary GPL.]
+
+Preamble
+========
+
+   The licenses for most software are designed to take away your
+freedom to share and change it.  By contrast, the GNU General Public
+Licenses are intended to guarantee your freedom to share and change
+free software--to make sure the software is free for all its users.
+
+   This license, the Library General Public License, applies to some
+specially designated Free Software Foundation software, and to any
+other libraries whose authors decide to use it.  You can use it for
+your libraries, too.
+
+   When we speak of free software, we are referring to freedom, not
+price.  Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+this service if you wish), that you receive source code or can get it
+if you want it, that you can change the software or use pieces of it in
+new free programs; and that you know you can do these things.
+
+   To protect your rights, we need to make restrictions that forbid
+anyone to deny you these rights or to ask you to surrender the rights.
+These restrictions translate to certain responsibilities for you if you
+distribute copies of the library, or if you modify it.
+
+   For example, if you distribute copies of the library, whether gratis
+or for a fee, you must give the recipients all the rights that we gave
+you.  You must make sure that they, too, receive or can get the source
+code.  If you link a program with the library, you must provide
+complete object files to the recipients so that they can relink them
+with the library, after making changes to the library and recompiling
+it.  And you must show them these terms so they know their rights.
+
+   Our method of protecting your rights has two steps: (1) copyright
+the library, and (2) offer you this license which gives you legal
+permission to copy, distribute and/or modify the library.
+
+   Also, for each distributor's protection, we want to make certain
+that everyone understands that there is no warranty for this free
+library.  If the library is modified by someone else and passed on, we
+want its recipients to know that what they have is not the original
+version, so that any problems introduced by others will not reflect on
+the original authors' reputations.
+
+   Finally, any free program is threatened constantly by software
+patents.  We wish to avoid the danger that companies distributing free
+software will individually obtain patent licenses, thus in effect
+transforming the program into proprietary software.  To prevent this,
+we have made it clear that any patent must be licensed for everyone's
+free use or not licensed at all.
+
+   Most GNU software, including some libraries, is covered by the
+ordinary GNU General Public License, which was designed for utility
+programs.  This license, the GNU Library General Public License,
+applies to certain designated libraries.  This license is quite
+different from the ordinary one; be sure to read it in full, and don't
+assume that anything in it is the same as in the ordinary license.
+
+   The reason we have a separate public license for some libraries is
+that they blur the distinction we usually make between modifying or
+adding to a program and simply using it.  Linking a program with a
+library, without changing the library, is in some sense simply using
+the library, and is analogous to running a utility program or
+application program.  However, in a textual and legal sense, the linked
+executable is a combined work, a derivative of the original library,
+and the ordinary General Public License treats it as such.
+
+   Because of this blurred distinction, using the ordinary General
+Public License for libraries did not effectively promote software
+sharing, because most developers did not use the libraries.  We
+concluded that weaker conditions might promote sharing better.
+
+   However, unrestricted linking of non-free programs would deprive the
+users of those programs of all benefit from the free status of the
+libraries themselves.  This Library General Public License is intended
+to permit developers of non-free programs to use free libraries, while
+preserving your freedom as a user of such programs to change the free
+libraries that are incorporated in them.  (We have not seen how to
+achieve this as regards changes in header files, but we have achieved
+it as regards changes in the actual functions of the Library.)  The
+hope is that this will lead to faster development of free libraries.
+
+   The precise terms and conditions for copying, distribution and
+modification follow.  Pay close attention to the difference between a
+"work based on the library" and a "work that uses the library".  The
+former contains code derived from the library, while the latter only
+works together with the library.
+
+   Note that it is possible for a library to be covered by the ordinary
+General Public License rather than by this special one.
+
+    TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+  0. This License Agreement applies to any software library which
+     contains a notice placed by the copyright holder or other
+     authorized party saying it may be distributed under the terms of
+     this Library General Public License (also called "this License").
+     Each licensee is addressed as "you".
+
+     A "library" means a collection of software functions and/or data
+     prepared so as to be conveniently linked with application programs
+     (which use some of those functions and data) to form executables.
+
+     The "Library", below, refers to any such software library or work
+     which has been distributed under these terms.  A "work based on the
+     Library" means either the Library or any derivative work under
+     copyright law: that is to say, a work containing the Library or a
+     portion of it, either verbatim or with modifications and/or
+     translated straightforwardly into another language.  (Hereinafter,
+     translation is included without limitation in the term
+     "modification".)
+
+     "Source code" for a work means the preferred form of the work for
+     making modifications to it.  For a library, complete source code
+     means all the source code for all modules it contains, plus any
+     associated interface definition files, plus the scripts used to
+     control compilation and installation of the library.
+
+     Activities other than copying, distribution and modification are
+     not covered by this License; they are outside its scope.  The act
+     of running a program using the Library is not restricted, and
+     output from such a program is covered only if its contents
+     constitute a work based on the Library (independent of the use of
+     the Library in a tool for writing it).  Whether that is true
+     depends on what the Library does and what the program that uses
+     the Library does.
+
+  1. You may copy and distribute verbatim copies of the Library's
+     complete source code as you receive it, in any medium, provided
+     that you conspicuously and appropriately publish on each copy an
+     appropriate copyright notice and disclaimer of warranty; keep
+     intact all the notices that refer to this License and to the
+     absence of any warranty; and distribute a copy of this License
+     along with the Library.
+
+     You may charge a fee for the physical act of transferring a copy,
+     and you may at your option offer warranty protection in exchange
+     for a fee.
+
+  2. You may modify your copy or copies of the Library or any portion
+     of it, thus forming a work based on the Library, and copy and
+     distribute such modifications or work under the terms of Section 1
+     above, provided that you also meet all of these conditions:
+
+       a. The modified work must itself be a software library.
+
+       b. You must cause the files modified to carry prominent notices
+          stating that you changed the files and the date of any change.
+
+       c. You must cause the whole of the work to be licensed at no
+          charge to all third parties under the terms of this License.
+
+       d. If a facility in the modified Library refers to a function or
+          a table of data to be supplied by an application program that
+          uses the facility, other than as an argument passed when the
+          facility is invoked, then you must make a good faith effort
+          to ensure that, in the event an application does not supply
+          such function or table, the facility still operates, and
+          performs whatever part of its purpose remains meaningful.
+
+          (For example, a function in a library to compute square roots
+          has a purpose that is entirely well-defined independent of the
+          application.  Therefore, Subsection 2d requires that any
+          application-supplied function or table used by this function
+          must be optional: if the application does not supply it, the
+          square root function must still compute square roots.)
+
+     These requirements apply to the modified work as a whole.  If
+     identifiable sections of that work are not derived from the
+     Library, and can be reasonably considered independent and separate
+     works in themselves, then this License, and its terms, do not
+     apply to those sections when you distribute them as separate
+     works.  But when you distribute the same sections as part of a
+     whole which is a work based on the Library, the distribution of
+     the whole must be on the terms of this License, whose permissions
+     for other licensees extend to the entire whole, and thus to each
+     and every part regardless of who wrote it.
+
+     Thus, it is not the intent of this section to claim rights or
+     contest your rights to work written entirely by you; rather, the
+     intent is to exercise the right to control the distribution of
+     derivative or collective works based on the Library.
+
+     In addition, mere aggregation of another work not based on the
+     Library with the Library (or with a work based on the Library) on
+     a volume of a storage or distribution medium does not bring the
+     other work under the scope of this License.
+
+  3. You may opt to apply the terms of the ordinary GNU General Public
+     License instead of this License to a given copy of the Library.
+     To do this, you must alter all the notices that refer to this
+     License, so that they refer to the ordinary GNU General Public
+     License, version 2, instead of to this License.  (If a newer
+     version than version 2 of the ordinary GNU General Public License
+     has appeared, then you can specify that version instead if you
+     wish.)  Do not make any other change in these notices.
+
+     Once this change is made in a given copy, it is irreversible for
+     that copy, so the ordinary GNU General Public License applies to
+     all subsequent copies and derivative works made from that copy.
+
+     This option is useful when you wish to copy part of the code of
+     the Library into a program that is not a library.
+
+  4. You may copy and distribute the Library (or a portion or
+     derivative of it, under Section 2) in object code or executable
+     form under the terms of Sections 1 and 2 above provided that you
+     accompany it with the complete corresponding machine-readable
+     source code, which must be distributed under the terms of Sections
+     1 and 2 above on a medium customarily used for software
+     interchange.
+
+     If distribution of object code is made by offering access to copy
+     from a designated place, then offering equivalent access to copy
+     the source code from the same place satisfies the requirement to
+     distribute the source code, even though third parties are not
+     compelled to copy the source along with the object code.
+
+  5. A program that contains no derivative of any portion of the
+     Library, but is designed to work with the Library by being
+     compiled or linked with it, is called a "work that uses the
+     Library".  Such a work, in isolation, is not a derivative work of
+     the Library, and therefore falls outside the scope of this License.
+
+     However, linking a "work that uses the Library" with the Library
+     creates an executable that is a derivative of the Library (because
+     it contains portions of the Library), rather than a "work that
+     uses the library".  The executable is therefore covered by this
+     License.  Section 6 states terms for distribution of such
+     executables.
+
+     When a "work that uses the Library" uses material from a header
+     file that is part of the Library, the object code for the work may
+     be a derivative work of the Library even though the source code is
+     not.  Whether this is true is especially significant if the work
+     can be linked without the Library, or if the work is itself a
+     library.  The threshold for this to be true is not precisely
+     defined by law.
+
+     If such an object file uses only numerical parameters, data
+     structure layouts and accessors, and small macros and small inline
+     functions (ten lines or less in length), then the use of the object
+     file is unrestricted, regardless of whether it is legally a
+     derivative work.  (Executables containing this object code plus
+     portions of the Library will still fall under Section 6.)
+
+     Otherwise, if the work is a derivative of the Library, you may
+     distribute the object code for the work under the terms of Section
+     6.  Any executables containing that work also fall under Section 6,
+     whether or not they are linked directly with the Library itself.
+
+  6. As an exception to the Sections above, you may also compile or
+     link a "work that uses the Library" with the Library to produce a
+     work containing portions of the Library, and distribute that work
+     under terms of your choice, provided that the terms permit
+     modification of the work for the customer's own use and reverse
+     engineering for debugging such modifications.
+
+     You must give prominent notice with each copy of the work that the
+     Library is used in it and that the Library and its use are covered
+     by this License.  You must supply a copy of this License.  If the
+     work during execution displays copyright notices, you must include
+     the copyright notice for the Library among them, as well as a
+     reference directing the user to the copy of this License.  Also,
+     you must do one of these things:
+
+       a. Accompany the work with the complete corresponding
+          machine-readable source code for the Library including
+          whatever changes were used in the work (which must be
+          distributed under Sections 1 and 2 above); and, if the work
+          is an executable linked with the Library, with the complete
+          machine-readable "work that uses the Library", as object code
+          and/or source code, so that the user can modify the Library
+          and then relink to produce a modified executable containing
+          the modified Library.  (It is understood that the user who
+          changes the contents of definitions files in the Library will
+          not necessarily be able to recompile the application to use
+          the modified definitions.)
+
+       b. Accompany the work with a written offer, valid for at least
+          three years, to give the same user the materials specified in
+          Subsection 6a, above, for a charge no more than the cost of
+          performing this distribution.
+
+       c. If distribution of the work is made by offering access to copy
+          from a designated place, offer equivalent access to copy the
+          above specified materials from the same place.
+
+       d. Verify that the user has already received a copy of these
+          materials or that you have already sent this user a copy.
+
+     For an executable, the required form of the "work that uses the
+     Library" must include any data and utility programs needed for
+     reproducing the executable from it.  However, as a special
+     exception, the source code distributed need not include anything
+     that is normally distributed (in either source or binary form)
+     with the major components (compiler, kernel, and so on) of the
+     operating system on which the executable runs, unless that
+     component itself accompanies the executable.
+
+     It may happen that this requirement contradicts the license
+     restrictions of other proprietary libraries that do not normally
+     accompany the operating system.  Such a contradiction means you
+     cannot use both them and the Library together in an executable
+     that you distribute.
+
+  7. You may place library facilities that are a work based on the
+     Library side-by-side in a single library together with other
+     library facilities not covered by this License, and distribute
+     such a combined library, provided that the separate distribution
+     of the work based on the Library and of the other library
+     facilities is otherwise permitted, and provided that you do these
+     two things:
+
+       a. Accompany the combined library with a copy of the same work
+          based on the Library, uncombined with any other library
+          facilities.  This must be distributed under the terms of the
+          Sections above.
+
+       b. Give prominent notice with the combined library of the fact
+          that part of it is a work based on the Library, and explaining
+          where to find the accompanying uncombined form of the same
+          work.
+
+  8. You may not copy, modify, sublicense, link with, or distribute the
+     Library except as expressly provided under this License.  Any
+     attempt otherwise to copy, modify, sublicense, link with, or
+     distribute the Library is void, and will automatically terminate
+     your rights under this License.  However, parties who have
+     received copies, or rights, from you under this License will not
+     have their licenses terminated so long as such parties remain in
+     full compliance.
+
+  9. You are not required to accept this License, since you have not
+     signed it.  However, nothing else grants you permission to modify
+     or distribute the Library or its derivative works.  These actions
+     are prohibited by law if you do not accept this License.
+     Therefore, by modifying or distributing the Library (or any work
+     based on the Library), you indicate your acceptance of this
+     License to do so, and all its terms and conditions for copying,
+     distributing or modifying the Library or works based on it.
+
+ 10. Each time you redistribute the Library (or any work based on the
+     Library), the recipient automatically receives a license from the
+     original licensor to copy, distribute, link with or modify the
+     Library subject to these terms and conditions.  You may not impose
+     any further restrictions on the recipients' exercise of the rights
+     granted herein.  You are not responsible for enforcing compliance
+     by third parties to this License.
+
+ 11. If, as a consequence of a court judgment or allegation of patent
+     infringement or for any other reason (not limited to patent
+     issues), conditions are imposed on you (whether by court order,
+     agreement or otherwise) that contradict the conditions of this
+     License, they do not excuse you from the conditions of this
+     License.  If you cannot distribute so as to satisfy simultaneously
+     your obligations under this License and any other pertinent
+     obligations, then as a consequence you may not distribute the
+     Library at all.  For example, if a patent license would not permit
+     royalty-free redistribution of the Library by all those who
+     receive copies directly or indirectly through you, then the only
+     way you could satisfy both it and this License would be to refrain
+     entirely from distribution of the Library.
+
+     If any portion of this section is held invalid or unenforceable
+     under any particular circumstance, the balance of the section is
+     intended to apply, and the section as a whole is intended to apply
+     in other circumstances.
+
+     It is not the purpose of this section to induce you to infringe any
+     patents or other property right claims or to contest validity of
+     any such claims; this section has the sole purpose of protecting
+     the integrity of the free software distribution system which is
+     implemented by public license practices.  Many people have made
+     generous contributions to the wide range of software distributed
+     through that system in reliance on consistent application of that
+     system; it is up to the author/donor to decide if he or she is
+     willing to distribute software through any other system and a
+     licensee cannot impose that choice.
+
+     This section is intended to make thoroughly clear what is believed
+     to be a consequence of the rest of this License.
+
+ 12. If the distribution and/or use of the Library is restricted in
+     certain countries either by patents or by copyrighted interfaces,
+     the original copyright holder who places the Library under this
+     License may add an explicit geographical distribution limitation
+     excluding those countries, so that distribution is permitted only
+     in or among countries not thus excluded.  In such case, this
+     License incorporates the limitation as if written in the body of
+     this License.
+
+ 13. The Free Software Foundation may publish revised and/or new
+     versions of the Library General Public License from time to time.
+     Such new versions will be similar in spirit to the present version,
+     but may differ in detail to address new problems or concerns.
+
+     Each version is given a distinguishing version number.  If the
+     Library specifies a version number of this License which applies
+     to it and "any later version", you have the option of following
+     the terms and conditions either of that version or of any later
+     version published by the Free Software Foundation.  If the Library
+     does not specify a license version number, you may choose any
+     version ever published by the Free Software Foundation.
+
+ 14. If you wish to incorporate parts of the Library into other free
+     programs whose distribution conditions are incompatible with these,
+     write to the author to ask for permission.  For software which is
+     copyrighted by the Free Software Foundation, write to the Free
+     Software Foundation; we sometimes make exceptions for this.  Our
+     decision will be guided by the two goals of preserving the free
+     status of all derivatives of our free software and of promoting
+     the sharing and reuse of software generally.
+
+                                NO WARRANTY
+
+ 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO
+     WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE
+     LAW.  EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT
+     HOLDERS AND/OR OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT
+     WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT
+     NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+     FITNESS FOR A PARTICULAR PURPOSE.  THE ENTIRE RISK AS TO THE
+     QUALITY AND PERFORMANCE OF THE LIBRARY IS WITH YOU.  SHOULD THE
+     LIBRARY PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY
+     SERVICING, REPAIR OR CORRECTION.
+
+ 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN
+     WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY
+     MODIFY AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE
+     LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL,
+     INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR
+     INABILITY TO USE THE LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF
+     DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU
+     OR THIRD PARTIES OR A FAILURE OF THE LIBRARY TO OPERATE WITH ANY
+     OTHER SOFTWARE), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN
+     ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
+
+                      END OF TERMS AND CONDITIONS
+
+How to Apply These Terms to Your New Libraries
+==============================================
+
+   If you develop a new library, and you want it to be of the greatest
+possible use to the public, we recommend making it free software that
+everyone can redistribute and change.  You can do so by permitting
+redistribution under these terms (or, alternatively, under the terms of
+the ordinary General Public License).
+
+   To apply these terms, attach the following notices to the library.
+It is safest to attach them to the start of each source file to most
+effectively convey the exclusion of warranty; and each file should have
+at least the "copyright" line and a pointer to where the full notice is
+found.
+
+     ONE LINE TO GIVE THE LIBRARY'S NAME AND AN IDEA OF WHAT IT DOES.
+     Copyright (C) YEAR  NAME OF AUTHOR
+     
+     This library is free software; you can redistribute it and/or modify it
+     under the terms of the GNU Library General Public License as published
+     by the Free Software Foundation; either version 2 of the License, or (at
+     your option) any later version.
+     
+     This library is distributed in the hope that it will be useful, but
+     WITHOUT ANY WARRANTY; without even the implied warranty of
+     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+     Library General Public License for more details.
+     
+     You should have received a copy of the GNU General Public License along
+     with this program; if not, write to the Free Software Foundation, Inc.,
+     59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.
+
+   Also add information on how to contact you by electronic and paper
+mail.
+
+   You should also get your employer (if you work as a programmer) or
+your school, if any, to sign a "copyright disclaimer" for the library,
+if necessary.  Here is a sample; alter the names:
+
+     Yoyodyne, Inc., hereby disclaims all copyright interest in the library
+     `Frob' (a library for tweaking knobs) written by James Random Hacker.
+     
+     SIGNATURE OF TY COON, 1 April 1990
+     Ty Coon, President of Vice
+
+   That's all there is to it!
+
Index: /main/tags/2.25/gsdl/packages/wincrypt/README
===================================================================
--- /main/tags/2.25/gsdl/packages/wincrypt/README	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/wincrypt/README	(revision 21064)
@@ -0,0 +1,40 @@
+		INTRODUCTION
+
+There's port of glibc DES crypt() routines to the CygWin32b18(gcc2.7.2), 
+particulary Ultra Fast Crypt by Michael Glad, email: glad@daimi.aau.dk.
+See README.UFC for more info on it. 
+Also the crypt() function itself has hole to call MD5 based crypt 
+through special salt, but MD5 sources I have can't pass selftests. 
+Port has been made by Alexey Truhan, email: sweer@rkb.lv. 
+It is covered by the GNU library license version 2, 
+see the file 'COPYING.LIB'.
+Port has been tested on SunOS5.5(gcc2.6.0) and Linux2.0.32(gcc.2. also. 
+
+		INSTALL
+
+First, compile the sources: 
+	gcc -c -I. *.c 
+will work. 
+Than you may place .o files wherever you want, make them a library 
+(libcrypt.a/.so as for UNIX), do not forget placing headers in your INCLUDE
+path.
+That's all, folks.   
+		
+		DETAILS 
+
+This can be linked with GLibC MD5 library with no effort, I think. 
+I have not tested reentrant version - crypt_r(), it may have wrong name.
+
+The package consists of: 
+	Files originally lived under sysdeps/unix in the 
+glibc-crypt-2.0.tgz which can be downloaded from any GNU site. 
+Unfortunatelly the sources seems to be stripped to compile good only is 
+a part of GNU LibC, so there're some minor changes. Now it works (tested 
+SunOS5.5, RedHat5.0, CygWin32b18) and produces identical results on all 
+the systems mentioned compiled with gcc 2.6.0 and higher.  
+	Some headers from GLibC2.0 source tree, which are missing as
+for CygWin, plus some missing macro definitions:
+features.h
+gnu/stubs.h
+sys/cdefs.h
+ 
Index: /main/tags/2.25/gsdl/packages/wincrypt/README.UFC
===================================================================
--- /main/tags/2.25/gsdl/packages/wincrypt/README.UFC	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/wincrypt/README.UFC	(revision 21064)
@@ -0,0 +1,237 @@
+
+
+	UFC-crypt: ultra fast 'crypt' implementation
+	============================================
+
+	@(#)README	2.27 11 Sep 1996
+
+Design goals/non goals:
+----------------------
+
+- Crypt implementation plugin compatible with crypt(3)/fcrypt.
+
+- High performance when used for password cracking.
+
+- Portable to most 32/64 bit machines.
+
+- Startup time/mixed salt performance not critical.
+
+Features of the implementation:
+------------------------------
+
+- On most machines, UFC-crypt runs 30-60 times faster than crypt(3) when
+  invoked repeated times with the same salt and varying passwords.
+
+- With mostly constant salts, performance is about two to three times
+  that of the default fcrypt implementation shipped with Alec
+  Muffets 'Crack' password cracker. For instructions on how to
+  plug UFC-crypt into 'Crack', see below.
+
+- With alternating salts, performance is only about twice
+  that of crypt(3).
+
+- Tested on 680x0, 386, SPARC, MIPS, HP-PA, Convex, Cray,
+  Pyramid and IBM RS/6000 systems as well as with gcc on IBM PS/2(DOS)
+  and Linux on a 386 PC.
+
+- Requires 165 kb for tables.
+
+- UFC-crypt is known to have compilation problems with some micro computer
+  C compilers (e.g. Turbo C++) due to its table sizes. Flame the vendors
+  for placing arbitrary limitations on their products. Use & support the
+  GNU C compiler, gcc.
+
+- Also includes 'fcrypt16' - the function used with DEC's enhanced
+  security setup.
+
+Author & licensing etc
+----------------------
+
+UFC-crypt is created by Michael Glad, email: glad@daimi.aau.dk, and has
+been donated to the Free Software Foundation, Inc. It is covered by the
+GNU library license version 2, see the file 'COPYING'.
+
+NOTES FOR USERS OUTSIDE THE US:
+------------------------------
+
+The US government limits the export of DES based software/hardware.
+This software is written in Aarhus, Denmark. It can therefore be retrieved
+from ftp sites outside the US without breaking US law. Please do not
+ftp it from american sites.
+
+Installing UFC-crypt
+--------------------
+
+Installing as GNU crypt Library:
+**********************(********
+
+Unpack the library  in some place.  The simplest place is the toplevel
+directory of the GNU C library sources.  Now mention `crypt' as on
+of the add-ons used for GNU libc.  I.e., when the sources are in the
+toplevel source directory simply run the `configure' script of the
+*libc* as:
+
+  configure --enable-add-ons=crypt,XXX <usual configure options>
+
+where XXX are the names of possibly existing other add-ons.
+
+That's all.
+
+
+Ordinary UNIX install
+*********************
+
+Copy the file
+
+	Makefile.non-gnu
+
+to
+
+	Makefile
+
+Edit Makefile setting the variables
+
+CRYPT:	The encryption module to use; crypt.o should always work.
+        If compiling for one of the machines for which special support
+	is available, select the appropriate module.
+
+CC:	The compiler to use.
+
+OFLAGS: The highest level of optimization available.
+
+Now run 'make'. UFC-crypt is compiled into 'libufc.a'. A test program: ufc
+is also linked. Try it out: './ufc 1' to test proper operation.
+
+For a more thorough test, run 'make tests'. This compiles and invokes
+a DES validation suite as well as two benchmark programs comparing
+UFC-crypt with the native crypt(3) implementation.
+
+If your friendly vendor has omitted crypt(3) from libc, compilation of
+the native benchmark program 'speedc' will fail. Compilation of the
+'speed*' programs may also fail as they use timer facilities not present
+in the same form in all UNIX implementations. If so is, you may choose to
+ run '/bin/time ./ufc 10000' and divide the CPU time used by 10000.
+
+'libufc.a' can be linked into your applications. It is compatible with
+both crypt(3) and the fcrypt shipped with Alec Muffett's Crack program.
+
+DOS install
+***********
+
+UFC-crypt compiles under DOS at least with MSC 6.00A. To compile,
+move 'patchlevel.h' to 'pl.h', 'ufc-crypt.h' to 'ufc.h' and 'crypt_util.c'
+to 'cryptutl.c'. When compiling, define the macro 'DOS' ( -DDOS ).
+You should compile & link the programs by hand. Refer to the Makefile to
+see which modules is needed for a program. You should be able to compile &
+run the verification programs 'cert' and 'ufc' but not the benchmark program
+'speedf'. For benchmarking, measure the running time of 'ufc 10000'.
+Having compiled the modules, you can link 'cryptutl.o' and 'crypt.o' into
+your application programs or put them into a library.
+
+Installing UFC-crypt into Crack:
+*******************************
+
+Crack Release 4.0a: in 'Sources/Makefile', change the CRACKCRYPT macro
+		    to a path leading to 'libufc.a' and invoke the Crack
+		    script as usual.
+
+4.1 and later:      Crack knows about UFC-crypt. Refer to the Crack docs
+		    for instructions.
+
+Benchmark table:
+---------------
+
+The table shows how many operations per second UFC-crypt can
+do on various machines.
+
+|--------------|-------------------------------------------|
+|Machine       |  SUN*  SUN*   HP*     DecStation   HP     |
+|              | 3/50   ELC  9000/425e    3100    9000/720 |
+|--------------|-------------------------------------------|
+| Crypt(3)/sec |  4.6    30     15         25        57    |
+| Ufc/sec      |  220   990    780       1015      3500    |
+|--------------|-------------------------------------------|
+| Speedup      |   48    30     52         40        60    |
+|--------------|-------------------------------------------|
+
+*) Compiled using special assembly language support module.
+
+It seems as if performance is limited by CPU bus and data cache capacity.
+This also makes the benchmarks debatable compared to a real test with
+UFC-crypt wired into Crack. However, the table gives an outline of
+what can be expected.
+
+Optimizations:
+-------------
+
+Here are the optimizations used relative to an ordinary implementation
+such as the one said to be used in crypt(3).
+
+Major optimizations
+*******************
+
+- Keep data packed as bits in integer variables -- allows for
+  fast permutations & parallel xor's in CPU hardware.
+
+- Let adjacent final & initial permutations collapse.
+
+- Keep working data in 'E expanded' format all the time.
+
+- Implement DES 'f' function mostly by table lookup
+
+- Calculate the above function on 12 bit basis rather than 6
+  as would be the most natural.
+
+- Implement setup routines so that performance is limited by the DES
+  inner loops only.
+
+- Instead of doing salting in the DES inner loops, modify the above tables
+  each time a new salt is seen. According to the BSD crypt code this is
+  ugly :-)
+
+Minor (dirty) optimizations
+***************************
+
+- combine iterations of DES inner loop so that DES only loops
+  8 times. This saves a lot of variable swapping.
+
+- Implement key access by a walking pointer rather than coding
+  as array indexing.
+
+- As described, the table based f function uses a 3 dimensional array:
+
+	sb ['number of 12 bit segment']['12 bit index']['48 bit half index']
+
+  Code the routine with 4 (one dimensional) vectors.
+
+- Design the internal data format & uglify the DES loops so that
+  the compiler does not need to do bit shifts when indexing vectors.
+
+Portability issues
+******************
+
+UFC-crypt does not need to know the byte endianness of the machine is runs on.
+
+To speed up the DES inner loop, it does a dirty trick requiring the
+availability of a integer flavoured data type occupying exactly 32 (or 64)
+bits. This is normally the case of 'long'. The header file 'ufc-crypt.h'
+contains typedefs for this type. If you have to change it (or any other part)
+to get things working, please drop me a note.
+
+UFC-crypt can take advantage of 64 bit integers. At the moment, it is
+configured to do so automatically for Convex & Cray machines.
+
+Revision history
+****************
+
+UFC patchlevel 0: base version; released to alt.sources on Sep 24 1991
+UFC patchlevel 1: patch released to alt.sources on Sep 27 1991.
+		  No longer rebuilds sb tables when seeing a new salt.
+UFC-crypt pl0:	  Essentially UFC pl 1. Released to comp.sources.misc
+		  on Oct 22 1991.
+UFC-crypt pl1:    Released to comp.sources.misc in march 1992
+		  * setkey/encrypt routines added
+		  * added validation/benchmarking programs
+		  * reworked keyschedule setup code
+		  * memory demands reduced
+		  * 64 bit support added
Index: /main/tags/2.25/gsdl/packages/wincrypt/crypt-entry.c
===================================================================
--- /main/tags/2.25/gsdl/packages/wincrypt/crypt-entry.c	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/wincrypt/crypt-entry.c	(revision 21064)
@@ -0,0 +1,159 @@
+/*
+ * UFC-crypt: ultra fast crypt(3) implementation
+ *
+ * Copyright (C) 1991, 1992, 1993, 1996, 1997 Free Software Foundation, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; see the file COPYING.LIB.  If not,
+ * write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ *
+ * crypt entry points
+ *
+ * @(#)crypt-entry.c	1.2 12/20/96
+ *
+ */
+
+#ifdef DEBUG
+#include <stdio.h>
+#endif
+#include <string.h>
+
+#ifndef STATIC
+#define STATIC static
+#endif
+
+#ifndef DOS
+#include "pl.h"
+#include "ufc-crypt.h"
+#else
+/*
+ * Thanks to greg%wind@plains.NoDak.edu (Greg W. Wettstein)
+ * for DOS patches
+ */
+#include "pl.h"
+#include "ufc.h"
+#endif
+#include "crypt.h"
+#include "crypt-private.h"
+
+/* Prototypes for local functions.  */
+/*#if __STDC__ - 0*/
+#ifndef __GNU_LIBRARY__
+void _ufc_clearmem (char *start, int cnt);
+#else
+#define _ufc_clearmem(start, cnt)   memset(start, 0, cnt)
+#endif
+extern void _ufc_setup_salt_r (__const char *s, struct crypt_data *__data);
+extern void _ufc_mk_keytab_r (char *key, struct crypt_data *__data);
+extern void _ufc_dofinalperm_r (ufc_long *res, struct crypt_data *__data);
+extern void _ufc_output_conversion_r (ufc_long v1, ufc_long v2,
+				      __const char *salt,
+				      struct crypt_data *__data);
+
+extern char *__md5_crypt_r (const char *key, const char *salt, char *buffer,
+			    int buflen);
+extern char *__md5_crypt (const char *key, const char *salt);
+/*#endif*/
+
+/* Define our magic string to mark salt for MD5 encryption
+   replacement.  This is meant to be the same as for other MD5 based
+   encryption implementations.  */
+static const char md5_salt_prefix[] = "$1$";
+
+/* For use by the old, non-reentrant routines (crypt/encrypt/setkey)  */
+extern struct crypt_data _ufc_foobar;
+
+/*
+ * UNIX crypt function
+ */
+
+char *
+crypt_r (key, salt, data)
+     const char *key;
+     const char *salt;
+     struct crypt_data *data;
+{
+  ufc_long res[4];
+  char ktab[9];
+  ufc_long xx = 25; /* to cope with GCC long long compiler bugs */
+
+#ifdef _LIBC
+  /* Try to find out whether we have to use MD5 encryption replacement.  */
+  if (strncmp (md5_salt_prefix, salt, sizeof (md5_salt_prefix) - 1) == 0)
+    return __md5_crypt_r (key, salt, (char *) data,
+			  sizeof (struct crypt_data));
+#endif
+
+  /*
+   * Hack DES tables according to salt
+   */
+  _ufc_setup_salt_r (salt, data);
+
+  /*
+   * Setup key schedule
+   */
+  _ufc_clearmem (ktab, (int) sizeof (ktab));
+  (void) strncpy (ktab, key, 8);
+  _ufc_mk_keytab_r (ktab, data);
+
+  /*
+   * Go for the 25 DES encryptions
+   */
+  _ufc_clearmem ((char*) res, (int) sizeof (res));
+  _ufc_doit_r (xx,  data, &res[0]);
+
+  /*
+   * Do final permutations
+   */
+  _ufc_dofinalperm_r (res, data);
+
+  /*
+   * And convert back to 6 bit ASCII
+   */
+  _ufc_output_conversion_r (res[0], res[1], salt, data);
+  return data->crypt_3_buf;
+}
+#ifdef _LIBC
+weak_alias (__crypt_r, crypt_r)
+#endif
+char *
+crypt (key, salt)
+     const char *key;
+     const char *salt;
+{
+#ifdef _LIBC
+  /* Try to find out whether we have to use MD5 encryption replacement.  */
+  if (strncmp (md5_salt_prefix, salt, sizeof (md5_salt_prefix) - 1) == 0)
+    return __md5_crypt (key, salt);
+#endif
+
+  return crypt_r (key, salt, &_ufc_foobar);
+}
+
+
+/*
+ * To make fcrypt users happy.
+ * They don't need to call init_des.
+ */
+#ifdef _LIBC
+weak_alias (crypt, fcrypt)
+#else
+char *
+__fcrypt (key, salt)
+     const char *key;
+     const char *salt;
+{
+  return crypt (key, salt);
+}
+#endif
Index: /main/tags/2.25/gsdl/packages/wincrypt/crypt-private.h
===================================================================
--- /main/tags/2.25/gsdl/packages/wincrypt/crypt-private.h	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/wincrypt/crypt-private.h	(revision 21064)
@@ -0,0 +1,43 @@
+/*
+ * UFC-crypt: ultra fast crypt(3) implementation
+ *
+ * Copyright (C) 1991, 1992, 1993, 1996, 1997 Free Software Foundation, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; see the file COPYING.LIB.  If not,
+ * write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ *
+ * @(#)crypt-private.h	1.4 12/20/96
+ */
+
+/* Prototypes for local functions in libcrypt.h.  */
+
+/*#ifdef __STDC__*/
+/* crypt.c */
+extern void _ufc_doit_r (ufc_long itr, struct crypt_data *__data,
+			 ufc_long *res);
+
+
+/* crypt_util.c */
+extern void __init_des_r (struct crypt_data *__data);
+extern void __init_des (void);
+extern char *fcrypt (__const char *key, __const char *salt);
+
+extern void _ufc_setup_salt_r (__const char *s, struct crypt_data *__data);
+extern void _ufc_mk_keytab_r (char *key, struct crypt_data *__data);
+extern void _ufc_dofinalperm_r (ufc_long *res, struct crypt_data *__data);
+extern void _ufc_output_conversion_r (ufc_long v1, ufc_long v2,
+				      __const char *salt,
+				      struct crypt_data *__data);
+/*#endif*/
Index: /main/tags/2.25/gsdl/packages/wincrypt/crypt.c
===================================================================
--- /main/tags/2.25/gsdl/packages/wincrypt/crypt.c	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/wincrypt/crypt.c	(revision 21064)
@@ -0,0 +1,122 @@
+/*
+ * UFC-crypt: ultra fast crypt(3) implementation
+ *
+ * Copyright (C) 1991, 1992, 1993, 1996 Free Software Foundation, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; see the file COPYING.LIB.  If not,
+ * write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ *
+ * @(#)crypt.c	2.25 12/20/96
+ *
+ * Semiportable C version
+ *
+ */
+
+/* #define __USE_GNU */
+
+#include "ufc.h"
+#include "crypt.h"
+#include "crypt-private.h"
+
+#ifdef _UFC_32_
+
+/*
+ * 32 bit version
+ */
+
+#define SBA(sb, v) (*(long32*)((char*)(sb)+(v)))
+
+void
+_ufc_doit_r(itr, __data, res)
+     ufc_long itr, *res;
+     struct crypt_data *__data;
+{
+  int i;
+  long32 s, *k;
+  long32 *sb01 = (long32*)__data->sb0;
+  long32 *sb23 = (long32*)__data->sb2;
+  long32 l1, l2, r1, r2;
+
+  l1 = (long32)res[0]; l2 = (long32)res[1];
+  r1 = (long32)res[2]; r2 = (long32)res[3];
+
+  while(itr--) {
+    k = (long32*)__data->keysched;
+    for(i=8; i--; ) {
+      s = *k++ ^ r1;
+      l1 ^= SBA(sb01, s & 0xffff); l2 ^= SBA(sb01, (s & 0xffff)+4);
+      l1 ^= SBA(sb01, s >>= 16  ); l2 ^= SBA(sb01, (s         )+4);
+      s = *k++ ^ r2;
+      l1 ^= SBA(sb23, s & 0xffff); l2 ^= SBA(sb23, (s & 0xffff)+4);
+      l1 ^= SBA(sb23, s >>= 16  ); l2 ^= SBA(sb23, (s         )+4);
+
+      s = *k++ ^ l1;
+      r1 ^= SBA(sb01, s & 0xffff); r2 ^= SBA(sb01, (s & 0xffff)+4);
+      r1 ^= SBA(sb01, s >>= 16  ); r2 ^= SBA(sb01, (s         )+4);
+      s = *k++ ^ l2;
+      r1 ^= SBA(sb23, s & 0xffff); r2 ^= SBA(sb23, (s & 0xffff)+4);
+      r1 ^= SBA(sb23, s >>= 16  ); r2 ^= SBA(sb23, (s         )+4);
+    }
+    s=l1; l1=r1; r1=s; s=l2; l2=r2; r2=s;
+  }
+  res[0] = l1; res[1] = l2; res[2] = r1; res[3] = r2;
+}
+
+#endif
+
+#ifdef _UFC_64_
+
+/*
+ * 64 bit version
+ */
+
+#define SBA(sb, v) (*(long64*)((char*)(sb)+(v)))
+
+void
+_ufc_doit_r(itr, __data, res)
+     ufc_long itr, *res;
+     struct crypt_data *__data;
+{
+  int i;
+  long64 l, r, s, *k;
+  register long64 *sb01 = (long64*)__data->sb0;
+  register long64 *sb23 = (long64*)__data->sb2;
+
+  l = (((long64)res[0]) << 32) | ((long64)res[1]);
+  r = (((long64)res[2]) << 32) | ((long64)res[3]);
+
+  while(itr--) {
+    k = (long64*)__data->keysched;
+    for(i=8; i--; ) {
+      s = *k++ ^ r;
+      l ^= SBA(sb23, (s       ) & 0xffff);
+      l ^= SBA(sb23, (s >>= 16) & 0xffff);
+      l ^= SBA(sb01, (s >>= 16) & 0xffff);
+      l ^= SBA(sb01, (s >>= 16)         );
+
+      s = *k++ ^ l;
+      r ^= SBA(sb23, (s       ) & 0xffff);
+      r ^= SBA(sb23, (s >>= 16) & 0xffff);
+      r ^= SBA(sb01, (s >>= 16) & 0xffff);
+      r ^= SBA(sb01, (s >>= 16)         );
+    }
+    s=l; l=r; r=s;
+  }
+
+  res[0] = l >> 32; res[1] = l & 0xffffffff;
+  res[2] = r >> 32; res[3] = r & 0xffffffff;
+}
+
+#endif
Index: /main/tags/2.25/gsdl/packages/wincrypt/crypt.h
===================================================================
--- /main/tags/2.25/gsdl/packages/wincrypt/crypt.h	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/wincrypt/crypt.h	(revision 21064)
@@ -0,0 +1,95 @@
+/*
+ * UFC-crypt: ultra fast crypt(3) implementation
+ *
+ * Copyright (C) 1991, 1992, 1993, 1996, 1997 Free Software Foundation, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with the GNU C Library; see the file COPYING.LIB.  If not,
+ * write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ *
+ * @(#)crypt.h	1.5 12/20/96
+ *
+ */
+
+#ifndef _CRYPT_H
+#define _CRYPT_H	1
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+
+#include "features.h"
+
+#ifndef __BEGIN_DECLS
+#define __BEGIN_DECLS
+#endif
+#ifndef __P
+#define __P(x) x
+#endif
+#ifndef __END_DECLS
+#define __END_DECLS
+#endif
+
+__BEGIN_DECLS
+
+/* Encrypt at most 8 characters from KEY using salt to perturb DES.  */
+extern char *crypt __P ((__const char *__key, __const char *__salt));
+
+/* Setup DES tables according KEY.  */
+extern void setkey __P ((__const char *__key));
+
+/* Encrypt data in BLOCK in place if EDFLAG is zero; otherwise decrypt
+   block in place.  */
+extern void encrypt __P ((char *__block, int __edflag));
+
+struct crypt_data
+  {
+    char keysched[16 * 8];
+    char sb0[32768];
+    char sb1[32768];
+    char sb2[32768];
+    char sb3[32768];
+    /* end-of-aligment-critical-data */
+    char crypt_3_buf[14];
+    char current_salt[2];
+    long int current_saltbits;
+    int  direction, initialized;
+  };
+
+#ifdef __USE_GNU
+/* Reentrant versions of the functions above.  The additional argument
+   points to a structure where the results are placed in.  */
+
+extern char *__crypt_r __P ((__const char *__key, __const char *__salt,
+			     struct crypt_data *__data));
+extern char *crypt_r __P ((__const char *__key, __const char *__salt,
+			   struct crypt_data *__data));
+
+extern void __setkey_r __P ((__const char *__key, struct crypt_data *__data));
+extern void setkey_r __P ((__const char *__key, struct crypt_data *__data));
+
+extern void __encrypt_r __P ((char *__block, int __edflag,
+			      struct crypt_data *__data));
+extern void encrypt_r __P ((char *__block, int __edflag,
+			    struct crypt_data *__data));
+#endif
+
+__END_DECLS
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif	/* crypt.h */
Index: /main/tags/2.25/gsdl/packages/wincrypt/cryptutl.c
===================================================================
--- /main/tags/2.25/gsdl/packages/wincrypt/cryptutl.c	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/wincrypt/cryptutl.c	(revision 21064)
@@ -0,0 +1,921 @@
+/*
+ * UFC-crypt: ultra fast crypt(3) implementation
+ *
+ * Copyright (C) 1991, 1992, 1993, 1996, 1997 Free Software Foundation, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; see the file COPYING.LIB.  If not,
+ * write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ *
+ * @(#)crypt_util.c	2.56 12/20/96
+ *
+ * Support routines
+ *
+ */
+
+#ifdef DEBUG
+#include <stdio.h>
+#endif
+#include <string.h>
+
+#ifndef STATIC
+#define STATIC static
+#endif
+
+#ifndef DOS
+#include "pl.h"
+#include "ufc.h"
+#else
+/*
+ * Thanks to greg%wind@plains.NoDak.edu (Greg W. Wettstein)
+ * for DOS patches
+ */
+#include "pl.h"
+#include "ufc.h"
+#endif
+#include "crypt.h"
+#include "crypt-private.h"
+
+
+#undef __GNU_LIBRARY__
+
+/* Prototypes for local functions.  */
+#if __STDC__ - 0
+#ifndef __GNU_LIBRARY__
+void _ufc_clearmem (char *start, int cnt);
+void _ufc_copymem (char *from, char *to, int cnt);
+#endif
+#ifdef _UFC_32_
+STATIC void shuffle_sb (long32 *k, ufc_long saltbits);
+#else
+STATIC void shuffle_sb (long64 *k, ufc_long saltbits);
+#endif
+#endif
+
+
+static const char patchlevel_str[] = PATCHLEVEL;
+
+/*
+ * Permutation done once on the 56 bit
+ *  key derived from the original 8 byte ASCII key.
+ */
+static const int pc1[56] = {
+  57, 49, 41, 33, 25, 17,  9,  1, 58, 50, 42, 34, 26, 18,
+  10,  2, 59, 51, 43, 35, 27, 19, 11,  3, 60, 52, 44, 36,
+  63, 55, 47, 39, 31, 23, 15,  7, 62, 54, 46, 38, 30, 22,
+  14,  6, 61, 53, 45, 37, 29, 21, 13,  5, 28, 20, 12,  4
+};
+
+/*
+ * How much to rotate each 28 bit half of the pc1 permutated
+ *  56 bit key before using pc2 to give the i' key
+ */
+static const int rots[16] = {
+  1, 1, 2, 2, 2, 2, 2, 2, 1, 2, 2, 2, 2, 2, 2, 1
+};
+
+/*
+ * Permutation giving the key
+ * of the i' DES round
+ */
+static const int pc2[48] = {
+  14, 17, 11, 24,  1,  5,  3, 28, 15,  6, 21, 10,
+  23, 19, 12,  4, 26,  8, 16,  7, 27, 20, 13,  2,
+  41, 52, 31, 37, 47, 55, 30, 40, 51, 45, 33, 48,
+  44, 49, 39, 56, 34, 53, 46, 42, 50, 36, 29, 32
+};
+
+/*
+ * The E expansion table which selects
+ * bits from the 32 bit intermediate result.
+ */
+static const int esel[48] = {
+  32,  1,  2,  3,  4,  5,  4,  5,  6,  7,  8,  9,
+   8,  9, 10, 11, 12, 13, 12, 13, 14, 15, 16, 17,
+  16, 17, 18, 19, 20, 21, 20, 21, 22, 23, 24, 25,
+  24, 25, 26, 27, 28, 29, 28, 29, 30, 31, 32,  1
+};
+
+/*
+ * Permutation done on the
+ * result of sbox lookups
+ */
+static const int perm32[32] = {
+  16,  7, 20, 21, 29, 12, 28, 17,  1, 15, 23, 26,  5, 18, 31, 10,
+  2,   8, 24, 14, 32, 27,  3,  9, 19, 13, 30,  6, 22, 11,  4, 25
+};
+
+/*
+ * The sboxes
+ */
+static const int sbox[8][4][16]= {
+        { { 14,  4, 13,  1,  2, 15, 11,  8,  3, 10,  6, 12,  5,  9,  0,  7 },
+          {  0, 15,  7,  4, 14,  2, 13,  1, 10,  6, 12, 11,  9,  5,  3,  8 },
+          {  4,  1, 14,  8, 13,  6,  2, 11, 15, 12,  9,  7,  3, 10,  5,  0 },
+          { 15, 12,  8,  2,  4,  9,  1,  7,  5, 11,  3, 14, 10,  0,  6, 13 }
+        },
+
+        { { 15,  1,  8, 14,  6, 11,  3,  4,  9,  7,  2, 13, 12,  0,  5, 10 },
+          {  3, 13,  4,  7, 15,  2,  8, 14, 12,  0,  1, 10,  6,  9, 11,  5 },
+          {  0, 14,  7, 11, 10,  4, 13,  1,  5,  8, 12,  6,  9,  3,  2, 15 },
+          { 13,  8, 10,  1,  3, 15,  4,  2, 11,  6,  7, 12,  0,  5, 14,  9 }
+        },
+
+        { { 10,  0,  9, 14,  6,  3, 15,  5,  1, 13, 12,  7, 11,  4,  2,  8 },
+          { 13,  7,  0,  9,  3,  4,  6, 10,  2,  8,  5, 14, 12, 11, 15,  1 },
+          { 13,  6,  4,  9,  8, 15,  3,  0, 11,  1,  2, 12,  5, 10, 14,  7 },
+          {  1, 10, 13,  0,  6,  9,  8,  7,  4, 15, 14,  3, 11,  5,  2, 12 }
+        },
+
+        { {  7, 13, 14,  3,  0,  6,  9, 10,  1,  2,  8,  5, 11, 12,  4, 15 },
+          { 13,  8, 11,  5,  6, 15,  0,  3,  4,  7,  2, 12,  1, 10, 14,  9 },
+          { 10,  6,  9,  0, 12, 11,  7, 13, 15,  1,  3, 14,  5,  2,  8,  4 },
+          {  3, 15,  0,  6, 10,  1, 13,  8,  9,  4,  5, 11, 12,  7,  2, 14 }
+        },
+
+        { {  2, 12,  4,  1,  7, 10, 11,  6,  8,  5,  3, 15, 13,  0, 14,  9 },
+          { 14, 11,  2, 12,  4,  7, 13,  1,  5,  0, 15, 10,  3,  9,  8,  6 },
+          {  4,  2,  1, 11, 10, 13,  7,  8, 15,  9, 12,  5,  6,  3,  0, 14 },
+          { 11,  8, 12,  7,  1, 14,  2, 13,  6, 15,  0,  9, 10,  4,  5,  3 }
+        },
+
+        { { 12,  1, 10, 15,  9,  2,  6,  8,  0, 13,  3,  4, 14,  7,  5, 11 },
+          { 10, 15,  4,  2,  7, 12,  9,  5,  6,  1, 13, 14,  0, 11,  3,  8 },
+          {  9, 14, 15,  5,  2,  8, 12,  3,  7,  0,  4, 10,  1, 13, 11,  6 },
+          {  4,  3,  2, 12,  9,  5, 15, 10, 11, 14,  1,  7,  6,  0,  8, 13 }
+        },
+
+        { {  4, 11,  2, 14, 15,  0,  8, 13,  3, 12,  9,  7,  5, 10,  6,  1 },
+          { 13,  0, 11,  7,  4,  9,  1, 10, 14,  3,  5, 12,  2, 15,  8,  6 },
+          {  1,  4, 11, 13, 12,  3,  7, 14, 10, 15,  6,  8,  0,  5,  9,  2 },
+          {  6, 11, 13,  8,  1,  4, 10,  7,  9,  5,  0, 15, 14,  2,  3, 12 }
+        },
+
+        { { 13,  2,  8,  4,  6, 15, 11,  1, 10,  9,  3, 14,  5,  0, 12,  7 },
+          {  1, 15, 13,  8, 10,  3,  7,  4, 12,  5,  6, 11,  0, 14,  9,  2 },
+          {  7, 11,  4,  1,  9, 12, 14,  2,  0,  6, 10, 13, 15,  3,  5,  8 },
+          {  2,  1, 14,  7,  4, 10,  8, 13, 15, 12,  9,  0,  3,  5,  6, 11 }
+        }
+};
+
+/*
+ * This is the initial
+ * permutation matrix
+ */
+static const int initial_perm[64] = {
+  58, 50, 42, 34, 26, 18, 10,  2, 60, 52, 44, 36, 28, 20, 12, 4,
+  62, 54, 46, 38, 30, 22, 14,  6, 64, 56, 48, 40, 32, 24, 16, 8,
+  57, 49, 41, 33, 25, 17,  9,  1, 59, 51, 43, 35, 27, 19, 11, 3,
+  61, 53, 45, 37, 29, 21, 13,  5, 63, 55, 47, 39, 31, 23, 15, 7
+};
+
+/*
+ * This is the final
+ * permutation matrix
+ */
+static const int final_perm[64] = {
+  40,  8, 48, 16, 56, 24, 64, 32, 39,  7, 47, 15, 55, 23, 63, 31,
+  38,  6, 46, 14, 54, 22, 62, 30, 37,  5, 45, 13, 53, 21, 61, 29,
+  36,  4, 44, 12, 52, 20, 60, 28, 35,  3, 43, 11, 51, 19, 59, 27,
+  34,  2, 42, 10, 50, 18, 58, 26, 33,  1, 41,  9, 49, 17, 57, 25
+};
+
+#define ascii_to_bin(c) ((c)>='a'?(c-59):(c)>='A'?((c)-53):(c)-'.')
+#define bin_to_ascii(c) ((c)>=38?((c)-38+'a'):(c)>=12?((c)-12+'A'):(c)+'.')
+
+static const ufc_long BITMASK[24] = {
+  0x40000000, 0x20000000, 0x10000000, 0x08000000, 0x04000000, 0x02000000,
+  0x01000000, 0x00800000, 0x00400000, 0x00200000, 0x00100000, 0x00080000,
+  0x00004000, 0x00002000, 0x00001000, 0x00000800, 0x00000400, 0x00000200,
+  0x00000100, 0x00000080, 0x00000040, 0x00000020, 0x00000010, 0x00000008
+};
+
+static const unsigned char bytemask[8]  = {
+  0x80, 0x40, 0x20, 0x10, 0x08, 0x04, 0x02, 0x01
+};
+
+static const ufc_long longmask[32] = {
+  0x80000000, 0x40000000, 0x20000000, 0x10000000,
+  0x08000000, 0x04000000, 0x02000000, 0x01000000,
+  0x00800000, 0x00400000, 0x00200000, 0x00100000,
+  0x00080000, 0x00040000, 0x00020000, 0x00010000,
+  0x00008000, 0x00004000, 0x00002000, 0x00001000,
+  0x00000800, 0x00000400, 0x00000200, 0x00000100,
+  0x00000080, 0x00000040, 0x00000020, 0x00000010,
+  0x00000008, 0x00000004, 0x00000002, 0x00000001
+};
+
+/*
+ * do_pc1: permform pc1 permutation in the key schedule generation.
+ *
+ * The first   index is the byte number in the 8 byte ASCII key
+ *  -  second    -      -    the two 28 bits halfs of the result
+ *  -  third     -   selects the 7 bits actually used of each byte
+ *
+ * The result is kept with 28 bit per 32 bit with the 4 most significant
+ * bits zero.
+ */
+static ufc_long do_pc1[8][2][128];
+
+/*
+ * do_pc2: permform pc2 permutation in the key schedule generation.
+ *
+ * The first   index is the septet number in the two 28 bit intermediate values
+ *  -  second    -    -  -  septet values
+ *
+ * Knowledge of the structure of the pc2 permutation is used.
+ *
+ * The result is kept with 28 bit per 32 bit with the 4 most significant
+ * bits zero.
+ */
+static ufc_long do_pc2[8][128];
+
+/*
+ * eperm32tab: do 32 bit permutation and E selection
+ *
+ * The first index is the byte number in the 32 bit value to be permuted
+ *  -  second  -   is the value of this byte
+ *  -  third   -   selects the two 32 bit values
+ *
+ * The table is used and generated internally in init_des to speed it up
+ */
+static ufc_long eperm32tab[4][256][2];
+
+/*
+ * efp: undo an extra e selection and do final
+ *      permutation giving the DES result.
+ *
+ *      Invoked 6 bit a time on two 48 bit values
+ *      giving two 32 bit longs.
+ */
+static ufc_long efp[16][64][2];
+
+/*
+ * For use by the old, non-reentrant routines
+ * (crypt/encrypt/setkey)
+ */
+struct crypt_data _ufc_foobar;
+
+#ifdef __GNU_LIBRARY__
+#include <libc-lock.h>
+
+__libc_lock_define_initialized (static, _ufc_tables_lock)
+#endif
+
+#ifdef DEBUG
+
+void
+_ufc_prbits(a, n)
+     ufc_long *a;
+     int n;
+{
+  ufc_long i, j, t, tmp;
+  n /= 8;
+  for(i = 0; i < n; i++) {
+    tmp=0;
+    for(j = 0; j < 8; j++) {
+      t=8*i+j;
+      tmp|=(a[t/24] & BITMASK[t % 24])?bytemask[j]:0;
+    }
+    (void)printf("%02x ",tmp);
+  }
+  printf(" ");
+}
+
+static void
+_ufc_set_bits(v, b)
+     ufc_long v;
+     ufc_long *b;
+{
+  ufc_long i;
+  *b = 0;
+  for(i = 0; i < 24; i++) {
+    if(v & longmask[8 + i])
+      *b |= BITMASK[i];
+  }
+}
+
+#endif
+
+#ifndef __GNU_LIBRARY__
+/*
+ * Silly rewrites of 'bzero'/'memset'. I do so
+ * because some machines don't have
+ * bzero and some don't have memset.
+ */
+
+void
+_ufc_clearmem(start, cnt)
+     char *start;
+     int cnt;
+{
+  while(cnt--)
+    *start++ = '\0';
+}
+
+void
+_ufc_copymem(from, to, cnt)
+     char *from, *to;
+     int cnt;
+{
+  while(cnt--)
+    *to++ = *from++;
+}
+#else
+#define _ufc_clearmem(start, cnt)   memset(start, 0, cnt)
+#define _ufc_copymem(from, to, cnt) memcpy(to, from, cnt)
+#endif
+
+/* lookup a 6 bit value in sbox */
+
+#define s_lookup(i,s) sbox[(i)][(((s)>>4) & 0x2)|((s) & 0x1)][((s)>>1) & 0xf];
+
+/*
+ * Initialize unit - may be invoked directly
+ * by fcrypt users.
+ */
+
+void
+__init_des_r(__data)
+     struct crypt_data *__data;
+{
+  int comes_from_bit;
+  int bit, sg;
+  ufc_long j;
+  ufc_long mask1, mask2;
+  int e_inverse[64];
+  static volatile int small_tables_initialized = 0;
+
+#ifdef _UFC_32_
+  long32 *sb[4];
+  sb[0] = (long32*)__data->sb0; sb[1] = (long32*)__data->sb1;
+  sb[2] = (long32*)__data->sb2; sb[3] = (long32*)__data->sb3;
+#endif
+#ifdef _UFC_64_
+  long64 *sb[4];
+  sb[0] = (long64*)__data->sb0; sb[1] = (long64*)__data->sb1;
+  sb[2] = (long64*)__data->sb2; sb[3] = (long64*)__data->sb3;
+#endif
+
+  if(small_tables_initialized == 0) {
+#ifdef __GNU_LIBRARY__
+    __libc_lock_lock (_ufc_tables_lock);
+    if(small_tables_initialized)
+      goto small_tables_done;
+#endif
+
+    /*
+     * Create the do_pc1 table used
+     * to affect pc1 permutation
+     * when generating keys
+     */
+    _ufc_clearmem((char*)do_pc1, (int)sizeof(do_pc1));
+    for(bit = 0; bit < 56; bit++) {
+      comes_from_bit  = pc1[bit] - 1;
+      mask1 = bytemask[comes_from_bit % 8 + 1];
+      mask2 = longmask[bit % 28 + 4];
+      for(j = 0; j < 128; j++) {
+	if(j & mask1)
+	  do_pc1[comes_from_bit / 8][bit / 28][j] |= mask2;
+      }
+    }
+
+    /*
+     * Create the do_pc2 table used
+     * to affect pc2 permutation when
+     * generating keys
+     */
+    _ufc_clearmem((char*)do_pc2, (int)sizeof(do_pc2));
+    for(bit = 0; bit < 48; bit++) {
+      comes_from_bit  = pc2[bit] - 1;
+      mask1 = bytemask[comes_from_bit % 7 + 1];
+      mask2 = BITMASK[bit % 24];
+      for(j = 0; j < 128; j++) {
+	if(j & mask1)
+	  do_pc2[comes_from_bit / 7][j] |= mask2;
+      }
+    }
+
+    /*
+     * Now generate the table used to do combined
+     * 32 bit permutation and e expansion
+     *
+     * We use it because we have to permute 16384 32 bit
+     * longs into 48 bit in order to initialize sb.
+     *
+     * Looping 48 rounds per permutation becomes
+     * just too slow...
+     *
+     */
+
+    _ufc_clearmem((char*)eperm32tab, (int)sizeof(eperm32tab));
+    for(bit = 0; bit < 48; bit++) {
+      ufc_long mask1,comes_from;
+      comes_from = perm32[esel[bit]-1]-1;
+      mask1      = bytemask[comes_from % 8];
+      for(j = 256; j--;) {
+	if(j & mask1)
+	  eperm32tab[comes_from / 8][j][bit / 24] |= BITMASK[bit % 24];
+      }
+    }
+
+    /*
+     * Create an inverse matrix for esel telling
+     * where to plug out bits if undoing it
+     */
+    for(bit=48; bit--;) {
+      e_inverse[esel[bit] - 1     ] = bit;
+      e_inverse[esel[bit] - 1 + 32] = bit + 48;
+    }
+
+    /*
+     * create efp: the matrix used to
+     * undo the E expansion and effect final permutation
+     */
+    _ufc_clearmem((char*)efp, (int)sizeof efp);
+    for(bit = 0; bit < 64; bit++) {
+      int o_bit, o_long;
+      ufc_long word_value, mask1, mask2;
+      int comes_from_f_bit, comes_from_e_bit;
+      int comes_from_word, bit_within_word;
+
+      /* See where bit i belongs in the two 32 bit long's */
+      o_long = bit / 32; /* 0..1  */
+      o_bit  = bit % 32; /* 0..31 */
+
+      /*
+       * And find a bit in the e permutated value setting this bit.
+       *
+       * Note: the e selection may have selected the same bit several
+       * times. By the initialization of e_inverse, we only look
+       * for one specific instance.
+       */
+      comes_from_f_bit = final_perm[bit] - 1;         /* 0..63 */
+      comes_from_e_bit = e_inverse[comes_from_f_bit]; /* 0..95 */
+      comes_from_word  = comes_from_e_bit / 6;        /* 0..15 */
+      bit_within_word  = comes_from_e_bit % 6;        /* 0..5  */
+
+      mask1 = longmask[bit_within_word + 26];
+      mask2 = longmask[o_bit];
+
+      for(word_value = 64; word_value--;) {
+	if(word_value & mask1)
+	  efp[comes_from_word][word_value][o_long] |= mask2;
+      }
+    }
+    small_tables_initialized = 1;
+#ifdef __GNU_LIBRARY__
+small_tables_done:
+    __libc_lock_unlock(_ufc_tables_lock);
+#endif
+  }
+
+  /*
+   * Create the sb tables:
+   *
+   * For each 12 bit segment of an 48 bit intermediate
+   * result, the sb table precomputes the two 4 bit
+   * values of the sbox lookups done with the two 6
+   * bit halves, shifts them to their proper place,
+   * sends them through perm32 and finally E expands
+   * them so that they are ready for the next
+   * DES round.
+   *
+   */
+
+  _ufc_clearmem((char*)__data->sb0, (int)sizeof(__data->sb0));
+  _ufc_clearmem((char*)__data->sb1, (int)sizeof(__data->sb1));
+  _ufc_clearmem((char*)__data->sb2, (int)sizeof(__data->sb2));
+  _ufc_clearmem((char*)__data->sb3, (int)sizeof(__data->sb3));
+
+  for(sg = 0; sg < 4; sg++) {
+    int j1, j2;
+    int s1, s2;
+
+    for(j1 = 0; j1 < 64; j1++) {
+      s1 = s_lookup(2 * sg, j1);
+      for(j2 = 0; j2 < 64; j2++) {
+	ufc_long to_permute, inx;
+
+	s2         = s_lookup(2 * sg + 1, j2);
+	to_permute = (((ufc_long)s1 << 4)  |
+		      (ufc_long)s2) << (24 - 8 * (ufc_long)sg);
+
+#ifdef _UFC_32_
+	inx = ((j1 << 6)  | j2) << 1;
+	sb[sg][inx  ]  = eperm32tab[0][(to_permute >> 24) & 0xff][0];
+	sb[sg][inx+1]  = eperm32tab[0][(to_permute >> 24) & 0xff][1];
+	sb[sg][inx  ] |= eperm32tab[1][(to_permute >> 16) & 0xff][0];
+	sb[sg][inx+1] |= eperm32tab[1][(to_permute >> 16) & 0xff][1];
+	sb[sg][inx  ] |= eperm32tab[2][(to_permute >>  8) & 0xff][0];
+	sb[sg][inx+1] |= eperm32tab[2][(to_permute >>  8) & 0xff][1];
+	sb[sg][inx  ] |= eperm32tab[3][(to_permute)       & 0xff][0];
+	sb[sg][inx+1] |= eperm32tab[3][(to_permute)       & 0xff][1];
+#endif
+#ifdef _UFC_64_
+	inx = ((j1 << 6)  | j2);
+	sb[sg][inx]  =
+	  ((long64)eperm32tab[0][(to_permute >> 24) & 0xff][0] << 32) |
+	   (long64)eperm32tab[0][(to_permute >> 24) & 0xff][1];
+	sb[sg][inx] |=
+	  ((long64)eperm32tab[1][(to_permute >> 16) & 0xff][0] << 32) |
+	   (long64)eperm32tab[1][(to_permute >> 16) & 0xff][1];
+	sb[sg][inx] |=
+	  ((long64)eperm32tab[2][(to_permute >>  8) & 0xff][0] << 32) |
+	   (long64)eperm32tab[2][(to_permute >>  8) & 0xff][1];
+	sb[sg][inx] |=
+	  ((long64)eperm32tab[3][(to_permute)       & 0xff][0] << 32) |
+	   (long64)eperm32tab[3][(to_permute)       & 0xff][1];
+#endif
+      }
+    }
+  }
+
+  __data->initialized++;
+}
+
+void
+__init_des()
+{
+  __init_des_r(&_ufc_foobar);
+}
+
+/*
+ * Process the elements of the sb table permuting the
+ * bits swapped in the expansion by the current salt.
+ */
+
+#ifdef _UFC_32_
+STATIC void
+shuffle_sb(k, saltbits)
+     long32 *k;
+     ufc_long saltbits;
+{
+  ufc_long j;
+  long32 x;
+  for(j=4096; j--;) {
+    x = (k[0] ^ k[1]) & (long32)saltbits;
+    *k++ ^= x;
+    *k++ ^= x;
+  }
+}
+#endif
+
+#ifdef _UFC_64_
+STATIC void
+shuffle_sb(k, saltbits)
+     long64 *k;
+     ufc_long saltbits;
+{
+  ufc_long j;
+  long64 x;
+  for(j=4096; j--;) {
+    x = ((*k >> 32) ^ *k) & (long64)saltbits;
+    *k++ ^= (x << 32) | x;
+  }
+}
+#endif
+
+/*
+ * Setup the unit for a new salt
+ * Hopefully we'll not see a new salt in each crypt call.
+ */
+
+void
+_ufc_setup_salt_r(s, __data)
+     __const char *s;
+     struct crypt_data *__data;
+{
+  ufc_long i, j, saltbits;
+
+  if(__data->initialized == 0)
+    __init_des_r(__data);
+
+  if(s[0] == __data->current_salt[0] && s[1] == __data->current_salt[1])
+    return;
+  __data->current_salt[0] = s[0]; __data->current_salt[1] = s[1];
+
+  /*
+   * This is the only crypt change to DES:
+   * entries are swapped in the expansion table
+   * according to the bits set in the salt.
+   */
+  saltbits = 0;
+  for(i = 0; i < 2; i++) {
+    long c=ascii_to_bin(s[i]);
+    for(j = 0; j < 6; j++) {
+      if((c >> j) & 0x1)
+	saltbits |= BITMASK[6 * i + j];
+    }
+  }
+
+  /*
+   * Permute the sb table values
+   * to reflect the changed e
+   * selection table
+   */
+#ifdef _UFC_32_
+#define LONGG long32*
+#endif
+#ifdef _UFC_64_
+#define LONGG long64*
+#endif
+
+  shuffle_sb((LONGG)__data->sb0, __data->current_saltbits ^ saltbits);
+  shuffle_sb((LONGG)__data->sb1, __data->current_saltbits ^ saltbits);
+  shuffle_sb((LONGG)__data->sb2, __data->current_saltbits ^ saltbits);
+  shuffle_sb((LONGG)__data->sb3, __data->current_saltbits ^ saltbits);
+
+  __data->current_saltbits = saltbits;
+}
+
+void
+_ufc_mk_keytab_r(key, __data)
+     char *key;
+     struct crypt_data *__data;
+{
+  ufc_long v1, v2, *k1;
+  int i;
+#ifdef _UFC_32_
+  long32 v, *k2;
+  k2 = (long32*)__data->keysched;
+#endif
+#ifdef _UFC_64_
+  long64 v, *k2;
+  k2 = (long64*)__data->keysched;
+#endif
+
+  v1 = v2 = 0; k1 = &do_pc1[0][0][0];
+  for(i = 8; i--;) {
+    v1 |= k1[*key   & 0x7f]; k1 += 128;
+    v2 |= k1[*key++ & 0x7f]; k1 += 128;
+  }
+
+  for(i = 0; i < 16; i++) {
+    k1 = &do_pc2[0][0];
+
+    v1 = (v1 << rots[i]) | (v1 >> (28 - rots[i]));
+    v  = k1[(v1 >> 21) & 0x7f]; k1 += 128;
+    v |= k1[(v1 >> 14) & 0x7f]; k1 += 128;
+    v |= k1[(v1 >>  7) & 0x7f]; k1 += 128;
+    v |= k1[(v1      ) & 0x7f]; k1 += 128;
+
+#ifdef _UFC_32_
+    *k2++ = (v | 0x00008000);
+    v = 0;
+#endif
+#ifdef _UFC_64_
+    v = (v << 32);
+#endif
+
+    v2 = (v2 << rots[i]) | (v2 >> (28 - rots[i]));
+    v |= k1[(v2 >> 21) & 0x7f]; k1 += 128;
+    v |= k1[(v2 >> 14) & 0x7f]; k1 += 128;
+    v |= k1[(v2 >>  7) & 0x7f]; k1 += 128;
+    v |= k1[(v2      ) & 0x7f];
+
+#ifdef _UFC_32_
+    *k2++ = (v | 0x00008000);
+#endif
+#ifdef _UFC_64_
+    *k2++ = v | 0x0000800000008000l;
+#endif
+  }
+
+  __data->direction = 0;
+}
+
+/*
+ * Undo an extra E selection and do final permutations
+ */
+
+void
+_ufc_dofinalperm_r(res, __data)
+     ufc_long *res;
+     struct crypt_data *__data;
+{
+  ufc_long v1, v2, x;
+  ufc_long l1,l2,r1,r2;
+
+  l1 = res[0]; l2 = res[1];
+  r1 = res[2]; r2 = res[3];
+
+  x = (l1 ^ l2) & __data->current_saltbits; l1 ^= x; l2 ^= x;
+  x = (r1 ^ r2) & __data->current_saltbits; r1 ^= x; r2 ^= x;
+
+  v1=v2=0; l1 >>= 3; l2 >>= 3; r1 >>= 3; r2 >>= 3;
+
+  v1 |= efp[15][ r2         & 0x3f][0]; v2 |= efp[15][ r2 & 0x3f][1];
+  v1 |= efp[14][(r2 >>= 6)  & 0x3f][0]; v2 |= efp[14][ r2 & 0x3f][1];
+  v1 |= efp[13][(r2 >>= 10) & 0x3f][0]; v2 |= efp[13][ r2 & 0x3f][1];
+  v1 |= efp[12][(r2 >>= 6)  & 0x3f][0]; v2 |= efp[12][ r2 & 0x3f][1];
+
+  v1 |= efp[11][ r1         & 0x3f][0]; v2 |= efp[11][ r1 & 0x3f][1];
+  v1 |= efp[10][(r1 >>= 6)  & 0x3f][0]; v2 |= efp[10][ r1 & 0x3f][1];
+  v1 |= efp[ 9][(r1 >>= 10) & 0x3f][0]; v2 |= efp[ 9][ r1 & 0x3f][1];
+  v1 |= efp[ 8][(r1 >>= 6)  & 0x3f][0]; v2 |= efp[ 8][ r1 & 0x3f][1];
+
+  v1 |= efp[ 7][ l2         & 0x3f][0]; v2 |= efp[ 7][ l2 & 0x3f][1];
+  v1 |= efp[ 6][(l2 >>= 6)  & 0x3f][0]; v2 |= efp[ 6][ l2 & 0x3f][1];
+  v1 |= efp[ 5][(l2 >>= 10) & 0x3f][0]; v2 |= efp[ 5][ l2 & 0x3f][1];
+  v1 |= efp[ 4][(l2 >>= 6)  & 0x3f][0]; v2 |= efp[ 4][ l2 & 0x3f][1];
+
+  v1 |= efp[ 3][ l1         & 0x3f][0]; v2 |= efp[ 3][ l1 & 0x3f][1];
+  v1 |= efp[ 2][(l1 >>= 6)  & 0x3f][0]; v2 |= efp[ 2][ l1 & 0x3f][1];
+  v1 |= efp[ 1][(l1 >>= 10) & 0x3f][0]; v2 |= efp[ 1][ l1 & 0x3f][1];
+  v1 |= efp[ 0][(l1 >>= 6)  & 0x3f][0]; v2 |= efp[ 0][ l1 & 0x3f][1];
+
+  res[0] = v1; res[1] = v2;
+}
+
+/*
+ * crypt only: convert from 64 bit to 11 bit ASCII
+ * prefixing with the salt
+ */
+
+void
+_ufc_output_conversion_r(v1, v2, salt, __data)
+     ufc_long v1, v2;
+     __const char *salt;
+     struct crypt_data *__data;
+{
+  int i, s, shf;
+
+  __data->crypt_3_buf[0] = salt[0];
+  __data->crypt_3_buf[1] = salt[1] ? salt[1] : salt[0];
+
+  for(i = 0; i < 5; i++) {
+    shf = (26 - 6 * i); /* to cope with MSC compiler bug */
+    __data->crypt_3_buf[i + 2] = bin_to_ascii((v1 >> shf) & 0x3f);
+  }
+
+  s  = (v2 & 0xf) << 2;
+  v2 = (v2 >> 2) | ((v1 & 0x3) << 30);
+
+  for(i = 5; i < 10; i++) {
+    shf = (56 - 6 * i);
+    __data->crypt_3_buf[i + 2] = bin_to_ascii((v2 >> shf) & 0x3f);
+  }
+
+  __data->crypt_3_buf[12] = bin_to_ascii(s);
+  __data->crypt_3_buf[13] = 0;
+}
+
+
+/*
+ * UNIX encrypt function. Takes a bitvector
+ * represented by one byte per bit and
+ * encrypt/decrypt according to edflag
+ */
+
+void
+__encrypt_r(__block, __edflag, __data)
+     char *__block;
+     int __edflag;
+     struct crypt_data *__data;
+{
+  ufc_long l1, l2, r1, r2, res[4];
+  int i;
+#ifdef _UFC_32_
+  long32 *kt;
+  kt = (long32*)__data->keysched;
+#endif
+#ifdef _UFC_64_
+  long64 *kt;
+  kt = (long64*)__data->keysched;
+#endif
+
+  /*
+   * Undo any salt changes to E expansion
+   */
+  _ufc_setup_salt_r("..", __data);
+
+  /*
+   * Reverse key table if
+   * changing operation (encrypt/decrypt)
+   */
+  if((__edflag == 0) != (__data->direction == 0)) {
+    for(i = 0; i < 8; i++) {
+#ifdef _UFC_32_
+      long32 x;
+      x = kt[2 * (15-i)];
+      kt[2 * (15-i)] = kt[2 * i];
+      kt[2 * i] = x;
+
+      x = kt[2 * (15-i) + 1];
+      kt[2 * (15-i) + 1] = kt[2 * i + 1];
+      kt[2 * i + 1] = x;
+#endif
+#ifdef _UFC_64_
+      long64 x;
+      x = kt[15-i];
+      kt[15-i] = kt[i];
+      kt[i] = x;
+#endif
+      }
+    __data->direction = __edflag;
+  }
+
+  /*
+   * Do initial permutation + E expansion
+   */
+  i = 0;
+  for(l1 = 0; i < 24; i++) {
+    if(__block[initial_perm[esel[i]-1]-1])
+      l1 |= BITMASK[i];
+  }
+  for(l2 = 0; i < 48; i++) {
+    if(__block[initial_perm[esel[i]-1]-1])
+      l2 |= BITMASK[i-24];
+  }
+
+  i = 0;
+  for(r1 = 0; i < 24; i++) {
+    if(__block[initial_perm[esel[i]-1+32]-1])
+      r1 |= BITMASK[i];
+  }
+  for(r2 = 0; i < 48; i++) {
+    if(__block[initial_perm[esel[i]-1+32]-1])
+      r2 |= BITMASK[i-24];
+  }
+
+  /*
+   * Do DES inner loops + final conversion
+   */
+  res[0] = l1; res[1] = l2;
+  res[2] = r1; res[3] = r2;
+  _ufc_doit_r((ufc_long)1, __data, &res[0]);
+
+  /*
+   * Do final permutations
+   */
+  _ufc_dofinalperm_r(res, __data);
+
+  /*
+   * And convert to bit array
+   */
+  l1 = res[0]; r1 = res[1];
+  for(i = 0; i < 32; i++) {
+    *__block++ = (l1 & longmask[i]) != 0;
+  }
+  for(i = 0; i < 32; i++) {
+    *__block++ = (r1 & longmask[i]) != 0;
+  }
+}
+#ifdef _LIBC
+weak_alias (__encrypt_r, encrypt_r)
+#endif 
+
+void
+encrypt(__block, __edflag)
+     char *__block;
+     int __edflag;
+{
+  __encrypt_r(__block, __edflag, &_ufc_foobar);
+}
+
+
+/*
+ * UNIX setkey function. Take a 64 bit DES
+ * key and setup the machinery.
+ */
+
+void
+__setkey_r(__key, __data)
+     __const char *__key;
+     struct crypt_data *__data;
+{
+  int i,j;
+  unsigned char c;
+  unsigned char ktab[8];
+
+  _ufc_setup_salt_r("..", __data); /* be sure we're initialized */
+
+  for(i = 0; i < 8; i++) {
+    for(j = 0, c = 0; j < 8; j++)
+      c = c << 1 | *__key++;
+    ktab[i] = c >> 1;
+  }
+  _ufc_mk_keytab_r(ktab, __data);
+}
+#ifdef _LIBC
+weak_alias (__setkey_r, setkey_r)
+#endif
+
+void
+setkey(__key)
+     __const char *__key;
+{
+  __setkey_r(__key, &_ufc_foobar);
+}
Index: /main/tags/2.25/gsdl/packages/wincrypt/features.h
===================================================================
--- /main/tags/2.25/gsdl/packages/wincrypt/features.h	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/wincrypt/features.h	(revision 21064)
@@ -0,0 +1,223 @@
+/* Copyright (C) 1991, 92, 93, 95, 96, 97 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Library General Public License as
+   published by the Free Software Foundation; either version 2 of the
+   License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Library General Public License for more details.
+
+   You should have received a copy of the GNU Library General Public
+   License along with the GNU C Library; see the file COPYING.LIB.  If not,
+   write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+   Boston, MA 02111-1307, USA.  */
+
+#ifndef	_FEATURES_H
+
+#define	_FEATURES_H	1
+
+/* These are defined by the user (or the compiler)
+   to specify the desired environment:
+
+   __STRICT_ANSI__	ISO Standard C.
+   _POSIX_SOURCE	IEEE Std 1003.1.
+   _POSIX_C_SOURCE	If ==1, like _POSIX_SOURCE; if >=2 add IEEE Std 1003.2;
+			if >=199309L, add IEEE Std 1003.1b-1993
+   _XOPEN_SOURCE	Includes POSIX and XPG things.
+   _XOPEN_SOURCE_EXTENDED XPG things and X/Open Unix extensions.
+   _BSD_SOURCE		ISO C, POSIX, and 4.3BSD things.
+   _SVID_SOURCE		ISO C, POSIX, and SVID things.
+   _GNU_SOURCE		All of the above, plus GNU extensions.
+   _REENTRANT		Select additionally reentrant object.
+   _THREAD_SAFE		Same as _REENTRANT, often used by other systems.
+
+   The `-ansi' switch to the GNU C compiler defines __STRICT_ANSI__.
+   If none of these are defined, the default is all but _GNU_SOURCE.
+   If more than one of these are defined, they accumulate.
+   For example __STRICT_ANSI__, _POSIX_SOURCE and _POSIX_C_SOURCE
+   together give you ISO C, 1003.1, and 1003.2, but nothing else.
+
+   These are defined by this file and are used by the
+   header files to decide what to declare or define:
+
+   __USE_POSIX		Define IEEE Std 1003.1 things.
+   __USE_POSIX2		Define IEEE Std 1003.2 things.
+   __USE_POSIX199309	Define IEEE Std 1003.1b things.
+   __USE_XOPEN		Define XPG things.
+   __USE_XOPEN_EXTENDED	Define X/Open Unix things.
+   __USE_BSD		Define 4.3BSD things.
+   __USE_SVID		Define SVID things.
+   __USE_MISC		Define things common to BSD and System V Unix.
+   __USE_GNU		Define GNU extensions.
+   __USE_REENTRANT	Define reentrant/thread-safe *_r functions.
+   __FAVOR_BSD		Favor 4.3BSD things in cases of conflict.
+
+   The macros `__GNU_LIBRARY__', `__GLIBC__', and `__GLIBC_MINOR__' are
+   defined by this file unconditionally.  `__GNU_LIBRARY__' is provided
+   only for compatibility.  All new code should use the other symbols
+   to test for features.
+
+   All macros listed above as possibly being defined by this file are
+   explicitly undefined if they are not explicitly defined.
+   Feature-test macros that are not defined by the user or compiler
+   but are implied by the other feature-test macros defined (or by the
+   lack of any definitions) are defined by the file.  */
+
+
+/* Undefine everything, so we get a clean slate.  */
+#undef	__USE_POSIX
+#undef	__USE_POSIX2
+#undef	__USE_POSIX199309
+#undef	__USE_XOPEN
+#undef	__USE_XOPEN_EXTENDED
+#undef	__USE_BSD
+#undef	__USE_SVID
+#undef	__USE_MISC
+#undef	__USE_GNU
+#undef	__USE_REENTRANT
+#undef	__FAVOR_BSD
+#undef	__KERNEL_STRICT_NAMES
+
+/* Suppress kernel-name space pollution unless user expressedly asks
+   for it.  */
+#ifndef _LOOSE_KERNEL_NAMES
+# define __KERNEL_STRICT_NAMES
+#endif
+
+/* Always use ISO C things.  */
+#define	__USE_ANSI	1
+#define _POSIX_SOURCE
+
+/* If _BSD_SOURCE was defined by the user, favor BSD over POSIX.  */
+#if defined _BSD_SOURCE && \
+    !(defined _POSIX_SOURCE || defined _POSIX_C_SOURCE || \
+      defined _XOPEN_SOURCE || defined _XOPEN_SOURCE_EXTENDED || \
+      defined _GNU_SOURCE || defined _SVID_SOURCE)
+# define __FAVOR_BSD	1
+#endif
+
+/* If _GNU_SOURCE was defined by the user, turn on all the other features.  */
+#ifdef _GNU_SOURCE
+#undef	_POSIX_SOURCE
+#define	_POSIX_SOURCE	1
+#undef	_POSIX_C_SOURCE
+#define	_POSIX_C_SOURCE	199309L
+#undef	_XOPEN_SOURCE
+#define	_XOPEN_SOURCE	1
+#undef	_XOPEN_SOURCE_EXTENDED
+#define	_XOPEN_SOURCE_EXTENDED	1
+#undef	_BSD_SOURCE
+#define	_BSD_SOURCE	1
+#undef	_SVID_SOURCE
+#define	_SVID_SOURCE	1
+#endif
+
+/* If nothing (other than _GNU_SOURCE) is defined,
+   define _BSD_SOURCE and _SVID_SOURCE.  */
+#if (!defined __STRICT_ANSI__ && !defined _POSIX_SOURCE && \
+     !defined _POSIX_C_SOURCE && !defined _XOPEN_SOURCE && \
+     !defined _XOPEN_SOURCE_EXTENDED && !defined _BSD_SOURCE && \
+     !defined _SVID_SOURCE)
+#define	_BSD_SOURCE	1
+#define	_SVID_SOURCE	1
+#endif
+
+/* If none of the ANSI/POSIX macros are defined, use POSIX.1 and POSIX.2
+   (and IEEE Std 1003.1b-1993 unless _XOPEN_SOURCE is defined).  */
+#if (!defined __STRICT_ANSI__ && !defined _POSIX_SOURCE && \
+     !defined _POSIX_C_SOURCE)
+#define	_POSIX_SOURCE	1
+#ifdef _XOPEN_SOURCE
+#define	_POSIX_C_SOURCE	2
+#else
+#define	_POSIX_C_SOURCE	199309L
+#endif
+#endif
+
+#if defined _POSIX_SOURCE || _POSIX_C_SOURCE >= 1 || defined _XOPEN_SOURCE
+#define	__USE_POSIX	1
+#endif
+
+#if defined _POSIX_C_SOURCE && _POSIX_C_SOURCE >= 2 || defined _XOPEN_SOURCE
+#define	__USE_POSIX2	1
+#endif
+
+#if defined _POSIX_C_SOURCE && _POSIX_C_SOURCE >= 199309L
+#define	__USE_POSIX199309	1
+#endif
+
+#ifdef	_XOPEN_SOURCE
+#define	__USE_XOPEN	1
+#ifdef	_XOPEN_SOURCE_EXTENDED
+#define	__USE_XOPEN_EXTENDED	1
+#endif
+#endif
+
+#if defined _BSD_SOURCE || defined _SVID_SOURCE
+#define	__USE_MISC	1
+#endif
+
+#ifdef	_BSD_SOURCE
+#define	__USE_BSD	1
+#endif
+
+#ifdef	_SVID_SOURCE
+#define	__USE_SVID	1
+#endif
+
+#ifdef	_GNU_SOURCE
+#define	__USE_GNU	1
+#endif
+
+#if defined _REENTRANT || defined _THREAD_SAFE
+#define __USE_REENTRANT	1
+#endif
+
+
+/* This macro indicates that the installed library is the GNU C Library.
+   For historic reasons the value now is 6 and this will stay from now
+   on.  The use of this variable is deprecated.  Use __GLIBC__ and
+   __GLIBC_MINOR__ now (see below) when you want to test for a specific
+   GNU C library version and use the values in <gnu/lib-names.h> to get
+   the sonames of the shared libraries.  */
+#undef  __GNU_LIBRARY__
+#define __GNU_LIBRARY__ 6
+
+/* Major and minor version number of the GNU C library package.  Use
+   these macros to test for features in specific releases.  */
+#define	__GLIBC__	2
+#define	__GLIBC_MINOR__	0
+
+
+#if !defined __GNUC__ || __GNUC__ < 2
+/* In GCC version 2, (__extension__ EXPR) will not complain
+   about GCC extensions used in EXPR under -ansi or -pedantic.  */
+#define	__extension__
+#endif
+
+
+/* This is here only because every header file already includes this one.  */
+#ifndef __ASSEMBLER__
+#include "sys/cdefs.h"
+#endif
+
+/* This is here only because every header file already includes this one.  */
+#ifndef _LIBC
+/* Get the definitions of all the appropriate `__stub_FUNCTION' symbols.
+   <gnu/stubs.h> contains `#define __stub_FUNCTION' when FUNCTION is a stub
+   which will always return failure (and set errno to ENOSYS).
+
+   We avoid including <gnu/stubs.h> when compiling the C library itself to
+   avoid a dependency loop.  stubs.h depends on every object file.  If
+   this #include were done for the library source code, then every object
+   file would depend on stubs.h.  */
+
+#include "gnu/stubs.h"
+#endif
+
+
+#endif	/* features.h  */
Index: /main/tags/2.25/gsdl/packages/wincrypt/gnu/stubs.h
===================================================================
--- /main/tags/2.25/gsdl/packages/wincrypt/gnu/stubs.h	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/wincrypt/gnu/stubs.h	(revision 21064)
@@ -0,0 +1,30 @@
+/* This file is automatically generated.
+   It defines a symbol `__stub_FUNCTION' for each function
+   in the C library which is a stub, meaning it will fail
+   every time called, usually setting errno to ENOSYS.  */
+#define __stub___ieee754_j0l
+#define __stub___ieee754_j1l
+#define __stub___ieee754_jnl
+#define __stub___ieee754_lgammal_r
+#define __stub___ieee754_rem_pio2l
+#define __stub___ieee754_y0l
+#define __stub___ieee754_y1l
+#define __stub___ieee754_ynl
+#define __stub___kernel_cosl
+#define __stub___kernel_rem_pio2l
+#define __stub___kernel_sinl
+#define __stub___kernel_tanl
+#define __stub_chflags
+#define __stub_erfcl
+#define __stub_erfl
+#define __stub_fchflags
+#define __stub_fexecve
+#define __stub_gtty
+#define __stub_lchown
+#define __stub_madvise
+#define __stub_revoke
+#define __stub_setlogin
+#define __stub_sigaltstack
+#define __stub_sigstack
+#define __stub_sstk
+#define __stub_stty
Index: /main/tags/2.25/gsdl/packages/wincrypt/pl.h
===================================================================
--- /main/tags/2.25/gsdl/packages/wincrypt/pl.h	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/wincrypt/pl.h	(revision 21064)
@@ -0,0 +1,25 @@
+/*
+ * UFC-crypt: ultra fast crypt(3) implementation
+ *
+ * Copyright (C) 1991, 1992, 1993, 1996 Free Software Foundation, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; see the file COPYING.LIB.  If not,
+ * write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ *
+ * @(#)patchlevel.h	1.13 9/10/96
+ *
+ */
+
+#define PATCHLEVEL "UFC-crypt, patchlevel 1e, @(#)patchlevel.h	1.13 9/10/96"
Index: /main/tags/2.25/gsdl/packages/wincrypt/sys/cdefs.h
===================================================================
--- /main/tags/2.25/gsdl/packages/wincrypt/sys/cdefs.h	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/wincrypt/sys/cdefs.h	(revision 21064)
@@ -0,0 +1,105 @@
+/* Copyright (C) 1992, 93, 94, 95, 96 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Library General Public License as
+   published by the Free Software Foundation; either version 2 of the
+   License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Library General Public License for more details.
+
+   You should have received a copy of the GNU Library General Public
+   License along with the GNU C Library; see the file COPYING.LIB.  If not,
+   write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+   Boston, MA 02111-1307, USA.  */
+
+#ifndef	_SYS_CDEFS_H
+
+#define	_SYS_CDEFS_H	1
+#include "features.h"
+
+/* Some user header file might have defined this before.  */
+#undef	__P
+
+#ifdef __GNUC__
+
+#define	__P(args)	args	/* GCC can always grok prototypes.  */
+#define	__DOTS		, ...
+
+#else	/* Not GCC.  */
+
+#define	__inline		/* No inline functions.  */
+
+#if (defined (__STDC__) && __STDC__) || defined (__cplusplus)
+
+#define	__P(args)	args
+#define	__const		const
+#define	__signed	signed
+#define	__volatile	volatile
+#define	__DOTS		, ...
+
+#else	/* Not ANSI C or C++.  */
+
+#define	__P(args)	()	/* No prototypes.  */
+#define	__const			/* No ANSI C keywords.  */
+#define	__signed
+#define	__volatile
+#define	__DOTS
+
+#endif	/* ANSI C or C++.  */
+
+#endif	/* GCC.  */
+
+/* For these things, GCC behaves the ANSI way normally,
+   and the non-ANSI way under -traditional.  */
+
+#if defined (__STDC__) && __STDC__
+
+#define	__CONCAT(x,y)	x ## y
+#define	__STRING(x)	#x
+
+/* This is not a typedef so `const __ptr_t' does the right thing.  */
+#define __ptr_t void *
+#define __long_double_t  long double
+
+#else
+
+#define	__CONCAT(x,y)	x/**/y
+#define	__STRING(x)	"x"
+
+#define __ptr_t char *
+#define __long_double_t  long double
+
+/* The BSD header files use the ANSI keywords unmodified (this means that
+   old programs may lose if they use the new keywords as identifiers), but
+   those names are not available under -traditional.  We define them to
+   their __ versions, which are taken care of above.  */
+#ifdef	__USE_BSD
+#define	const		__const
+#define	signed		__signed
+#define	volatile	__volatile
+#endif
+
+#endif	/* __STDC__ */
+
+
+/* C++ needs to know that types and declarations are C, not C++.  */
+#ifdef	__cplusplus
+#define	__BEGIN_DECLS	extern "C" {
+#define	__END_DECLS	}
+#else
+#define	__BEGIN_DECLS
+#define	__END_DECLS
+#endif
+
+/* GCC2 has various useful declarations that can be made with the
+   `__attribute__' syntax.  All of the ways we use this do fine if
+   they are omitted for compilers that don't understand it.  */
+#if !defined (__GNUC__) || __GNUC__ < 2
+#define __attribute__(xyz)	/* Ignore.  */
+#endif
+
+#endif	 /* sys/cdefs.h */
Index: /main/tags/2.25/gsdl/packages/wincrypt/ufc.h
===================================================================
--- /main/tags/2.25/gsdl/packages/wincrypt/ufc.h	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/wincrypt/ufc.h	(revision 21064)
@@ -0,0 +1,131 @@
+/*
+ * UFC-crypt: ultra fast crypt(3) implementation
+ *
+ * Copyright (C) 1991, 1992, 1993, 1996, 1997 Free Software Foundation, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; see the file COPYING.LIB.  If not,
+ * write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ *
+ * @(#)ufc-crypt.h	1.27 12/20/96
+ *
+ * Definitions of datatypes
+ *
+ */
+
+#ifndef __GNUC__
+#define __const
+#ifndef __STDC__
+#define const
+#define volatile
+#endif
+#endif
+
+/*
+ * Requirements for datatypes:
+ *
+ * A datatype 'ufc_long' of at least 32 bit
+ * *and*
+ *   A type 'long32' of exactly 32 bits (_UFC_32_)
+ *   *or*
+ *   A type 'long64' of exactly 64 bits (_UFC_64_)
+ *
+ * 'int' is assumed to be at least 8 bit
+ */
+
+/*
+ * #ifdef's for various architectures
+ */
+
+#ifdef cray
+/* thanks to <hutton@opus.sdsc.edu> (Tom Hutton)  for testing */
+typedef unsigned long ufc_long;
+typedef unsigned long long64;
+#define _UFC_64_
+#endif
+
+#if defined convex || defined __convexc__
+/* thanks to pcl@convex.oxford.ac.uk (Paul Leyland) for testing */
+typedef unsigned long ufc_long;
+typedef long long     long64;
+#define _UFC_64_
+#endif
+
+#ifdef __sgi
+#if _MIPS_SZLONG == 64
+typedef unsigned long ufc_long;
+typedef long     long64;
+#define _UFC_64_
+#else
+typedef unsigned long ufc_long;
+typedef int     long32;
+#define _UFC_32_
+#endif
+#endif
+
+/*
+ * Thanks to <iglesias@draco.acs.uci.edu> (Mike Iglesias)
+ */
+
+#ifdef __alpha
+typedef unsigned long ufc_long;
+typedef unsigned long long64;
+#define _UFC_64_
+#endif
+
+#if defined __sparc__ && defined __arch64__
+typedef unsigned long ufc_long;
+typedef unsigned long long64;
+#define _UFC_64_
+#endif
+
+/*
+ * For debugging 64 bit code etc with 'gcc'
+ */
+
+#ifdef GCC3232
+typedef unsigned long ufc_long;
+typedef unsigned long long32;
+#define _UFC_32_
+#endif
+
+#ifdef GCC3264
+typedef unsigned long ufc_long;
+typedef long long     long64;
+#define _UFC_64_
+#endif
+
+#ifdef GCC6432
+typedef long long ufc_long;
+typedef unsigned long long32;
+#define _UFC_32_
+#endif
+
+#ifdef GCC6464
+typedef long long     ufc_long;
+typedef long long     long64;
+#define _UFC_64_
+#endif
+
+/*
+ * Catch all for 99.95% of all UNIX machines
+ */
+
+#ifndef _UFC_64_
+#ifndef _UFC_32_
+#define _UFC_32_
+typedef unsigned long ufc_long;
+typedef unsigned long long32;
+#endif
+#endif
Index: /main/tags/2.25/gsdl/packages/wingdbm/Makefile.in
===================================================================
--- /main/tags/2.25/gsdl/packages/wingdbm/Makefile.in	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/wingdbm/Makefile.in	(revision 21064)
@@ -0,0 +1,84 @@
+
+srcdir = c:\home\rjmcnab\humanity\gdbm
+VPATH = $(srcdir)
+
+AR = lib
+CC = cl
+#CFLAGS = -g -O
+CPPFLAGS =
+DEFS = -DHAVE_CONFIG_H -D__WIN32__ -D_LITTLE_ENDIAN
+LDFLAGS =
+
+o = .obj
+
+.SUFFIXES:
+.SUFFIXES: .c .$o
+
+.c.$o:
+	$(CC) -c $(CPPFLAGS) $(DEFS) -I. -I$(srcdir) $(CFLAGS) $<
+
+
+PROGS = gdbm.lib testgdbm.exe
+
+GDBM_CF = gdbmopen.c gdbmdelete.c gdbmfetch.c  gdbmstore.c gdbmclose.c \
+	gdbmreorg.c gdbmseq.c gdbmsync.c gdbmerrno.c gdbmexists.c gdbmsetopt.c \
+	bucket.c falloc.c findkey.c global.c hash.c update.c \
+	version.c
+
+TEST_CF = testgdbm.c
+
+GDBM_OF = gdbmopen.$o gdbmdelete.$o gdbmfetch.$o  gdbmstore.$o gdbmclose.$o \
+	gdbmreorg.$o gdbmseq.$o gdbmsync.$o gdbmerrno.$o gdbmexists.$o gdbmsetopt.$o \
+	bucket.$o falloc.$o findkey.$o global.$o hash.$o update.$o \
+	version.$o
+     
+SRCS = $(GDBM_CF) $(TEST_CF)
+
+OBJS = $(GDBM_OF)
+
+HDRS = gdbmdefs.h extern.h gdbmerrno.h systems.h gdbmconst.h \
+	proto.h
+
+all: gdbm.lib
+
+progs: $(PROGS)
+
+gdbm.lib: $(OBJS) gdbm.h
+	del gdbm.lib
+	$(AR) /out:gdbm.lib $(OBJS) 
+
+testgdbm.exe: testgdbm.$o gdbm.lib
+	$(CC) $(LDFLAGS) /Fe"testgdbm.exe" testgdbm.$o gdbm.lib
+
+
+clean:
+	rm -f $(PROGS) *.$o core junk*
+
+
+# gdbm files
+gdbmclose.$o:	autoconf.h gdbmdefs.h 
+gdbmdelete.$o:	autoconf.h gdbmdefs.h gdbmerrno.h 
+gdbmfetch.$o:	autoconf.h gdbmdefs.h gdbmerrno.h 
+gdbmopen.$o:	autoconf.h gdbmdefs.h gdbmerrno.h 
+gdbmreorg.$o:	autoconf.h gdbmdefs.h gdbmerrno.h extern.h
+gdbmseq.$o:	autoconf.h gdbmdefs.h 
+gdbmstore.$o:	autoconf.h gdbmdefs.h gdbmerrno.h 
+
+# gdbm support files
+bucket.$o:	autoconf.h gdbmdefs.h
+falloc.$o:	autoconf.h gdbmdefs.h
+findkey.$o:	autoconf.h gdbmdefs.h
+global.$o:	autoconf.h gdbmdefs.h gdbmerrno.h 
+hash.$o:		autoconf.h gdbmdefs.h
+update.$o:	autoconf.h gdbmdefs.h
+version.$o:
+extern.h:
+gdbmdefs.h:	gdbmconst.h systems.h
+	touch gdbmdefs.h
+
+# other programs
+testgdbm.$o:	autoconf.h gdbmdefs.h extern.h gdbmerrno.h systems.h
+testdbm.$o:	autoconf.h
+testndbm.$o:	autoconf.h ndbm.h
+tdbm.$o:		autoconf.h
+conv2gdbm.$o:	autoconf.h gdbm.h
Index: /main/tags/2.25/gsdl/packages/wingdbm/alloca.c
===================================================================
--- /main/tags/2.25/gsdl/packages/wingdbm/alloca.c	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/wingdbm/alloca.c	(revision 21064)
@@ -0,0 +1,465 @@
+/* alloca.c -- allocate automatically reclaimed memory
+   (Mostly) portable public-domain implementation -- D A Gwyn
+
+   This implementation of the PWB library alloca function,
+   which is used to allocate space off the run-time stack so
+   that it is automatically reclaimed upon procedure exit,
+   was inspired by discussions with J. Q. Johnson of Cornell.
+   J.Otto Tennant <jot@cray.com> contributed the Cray support.
+
+   There are some preprocessor constants that can
+   be defined when compiling for your specific system, for
+   improved efficiency; however, the defaults should be okay.
+
+   The general concept of this implementation is to keep
+   track of all alloca-allocated blocks, and reclaim any
+   that are found to be deeper in the stack than the current
+   invocation.  This heuristic does not reclaim storage as
+   soon as it becomes invalid, but it will do so eventually.
+
+   As a special case, alloca(0) reclaims storage without
+   allocating any.  It is a good idea to use alloca(0) in
+   your main control loop, etc. to force garbage collection.  */
+
+/* include system configuration before all else. */
+#include "autoconf.h"
+
+#if HAVE_STDLIB_H
+#include <stdlib.h>
+#endif
+
+/* If compiling with GCC, this file's not needed.  */
+#ifndef alloca
+
+#ifdef emacs
+#ifdef static
+/* actually, only want this if static is defined as ""
+   -- this is for usg, in which emacs must undefine static
+   in order to make unexec workable
+   */
+#ifndef STACK_DIRECTION
+you
+lose
+-- must know STACK_DIRECTION at compile-time
+#endif /* STACK_DIRECTION undefined */
+#endif /* static */
+#endif /* emacs */
+
+/* If your stack is a linked list of frames, you have to
+   provide an "address metric" ADDRESS_FUNCTION macro.  */
+
+#ifdef CRAY
+long i00afunc ();
+#define ADDRESS_FUNCTION(arg) (char *) i00afunc (&(arg))
+#else
+#define ADDRESS_FUNCTION(arg) &(arg)
+#endif
+
+#if __STDC__
+typedef void *pointer;
+#else
+typedef char *pointer;
+#endif
+
+#ifndef NULL
+#define	NULL	0
+#endif
+
+/* Define STACK_DIRECTION if you know the direction of stack
+   growth for your system; otherwise it will be automatically
+   deduced at run-time.
+
+   STACK_DIRECTION > 0 => grows toward higher addresses
+   STACK_DIRECTION < 0 => grows toward lower addresses
+   STACK_DIRECTION = 0 => direction of growth unknown  */
+
+#ifndef STACK_DIRECTION
+#define	STACK_DIRECTION	0	/* Direction unknown.  */
+#endif
+
+#if STACK_DIRECTION != 0
+
+#define	STACK_DIR	STACK_DIRECTION	/* Known at compile-time.  */
+
+#else /* STACK_DIRECTION == 0; need run-time code.  */
+
+static int stack_dir;		/* 1 or -1 once known.  */
+#define	STACK_DIR	stack_dir
+
+static void
+find_stack_direction ()
+{
+  static char *addr = NULL;	/* Address of first `dummy', once known.  */
+  auto char dummy;		/* To get stack address.  */
+
+  if (addr == NULL)
+    {				/* Initial entry.  */
+      addr = ADDRESS_FUNCTION (dummy);
+
+      find_stack_direction ();	/* Recurse once.  */
+    }
+  else
+    {
+      /* Second entry.  */
+      if (ADDRESS_FUNCTION (dummy) > addr)
+	stack_dir = 1;		/* Stack grew upward.  */
+      else
+	stack_dir = -1;		/* Stack grew downward.  */
+    }
+}
+
+#endif /* STACK_DIRECTION == 0 */
+
+/* An "alloca header" is used to:
+   (a) chain together all alloca'ed blocks;
+   (b) keep track of stack depth.
+
+   It is very important that sizeof(header) agree with malloc
+   alignment chunk size.  The following default should work okay.  */
+
+#ifndef	ALIGN_SIZE
+#define	ALIGN_SIZE	sizeof(double)
+#endif
+
+typedef union hdr
+{
+  char align[ALIGN_SIZE];	/* To force sizeof(header).  */
+  struct
+    {
+      union hdr *next;		/* For chaining headers.  */
+      char *deep;		/* For stack depth measure.  */
+    } h;
+} header;
+
+static header *last_alloca_header = NULL;	/* -> last alloca header.  */
+
+/* Return a pointer to at least SIZE bytes of storage,
+   which will be automatically reclaimed upon exit from
+   the procedure that called alloca.  Originally, this space
+   was supposed to be taken from the current stack frame of the
+   caller, but that method cannot be made to work for some
+   implementations of C, for example under Gould's UTX/32.  */
+
+pointer
+alloca (size)
+     unsigned size;
+{
+  auto char probe;		/* Probes stack depth: */
+  register char *depth = ADDRESS_FUNCTION (probe);
+
+#if STACK_DIRECTION == 0
+  if (STACK_DIR == 0)		/* Unknown growth direction.  */
+    find_stack_direction ();
+#endif
+
+  /* Reclaim garbage, defined as all alloca'd storage that
+     was allocated from deeper in the stack than currently. */
+
+  {
+    register header *hp;	/* Traverses linked list.  */
+
+    for (hp = last_alloca_header; hp != NULL;)
+      if ((STACK_DIR > 0 && hp->h.deep > depth)
+	  || (STACK_DIR < 0 && hp->h.deep < depth))
+	{
+	  register header *np = hp->h.next;
+
+	  free ((pointer) hp);	/* Collect garbage.  */
+
+	  hp = np;		/* -> next header.  */
+	}
+      else
+	break;			/* Rest are not deeper.  */
+
+    last_alloca_header = hp;	/* -> last valid storage.  */
+  }
+
+  if (size == 0)
+    return NULL;		/* No allocation required.  */
+
+  /* Allocate combined header + user data storage.  */
+
+  {
+    register pointer new = malloc (sizeof (header) + size);
+    /* Address of header.  */
+
+    ((header *) new)->h.next = last_alloca_header;
+    ((header *) new)->h.deep = depth;
+
+    last_alloca_header = (header *) new;
+
+    /* User storage begins just after header.  */
+
+    return (pointer) ((char *) new + sizeof (header));
+  }
+}
+
+#ifdef CRAY
+
+#ifdef DEBUG_I00AFUNC
+#include <stdio.h>
+#endif
+
+#ifndef CRAY_STACK
+#define CRAY_STACK
+#ifndef CRAY2
+/* Stack structures for CRAY-1, CRAY X-MP, and CRAY Y-MP */
+struct stack_control_header
+  {
+    long shgrow:32;		/* Number of times stack has grown.  */
+    long shaseg:32;		/* Size of increments to stack.  */
+    long shhwm:32;		/* High water mark of stack.  */
+    long shsize:32;		/* Current size of stack (all segments).  */
+  };
+
+/* The stack segment linkage control information occurs at
+   the high-address end of a stack segment.  (The stack
+   grows from low addresses to high addresses.)  The initial
+   part of the stack segment linkage control information is
+   0200 (octal) words.  This provides for register storage
+   for the routine which overflows the stack.  */
+
+struct stack_segment_linkage
+  {
+    long ss[0200];		/* 0200 overflow words.  */
+    long sssize:32;		/* Number of words in this segment.  */
+    long ssbase:32;		/* Offset to stack base.  */
+    long:32;
+    long sspseg:32;		/* Offset to linkage control of previous
+				   segment of stack.  */
+    long:32;
+    long sstcpt:32;		/* Pointer to task common address block.  */
+    long sscsnm;		/* Private control structure number for
+				   microtasking.  */
+    long ssusr1;		/* Reserved for user.  */
+    long ssusr2;		/* Reserved for user.  */
+    long sstpid;		/* Process ID for pid based multi-tasking.  */
+    long ssgvup;		/* Pointer to multitasking thread giveup.  */
+    long sscray[7];		/* Reserved for Cray Research.  */
+    long ssa0;
+    long ssa1;
+    long ssa2;
+    long ssa3;
+    long ssa4;
+    long ssa5;
+    long ssa6;
+    long ssa7;
+    long sss0;
+    long sss1;
+    long sss2;
+    long sss3;
+    long sss4;
+    long sss5;
+    long sss6;
+    long sss7;
+  };
+
+#else /* CRAY2 */
+/* The following structure defines the vector of words
+   returned by the STKSTAT library routine.  */
+struct stk_stat
+  {
+    long now;			/* Current total stack size.  */
+    long maxc;			/* Amount of contiguous space which would
+				   be required to satisfy the maximum
+				   stack demand to date.  */
+    long high_water;		/* Stack high-water mark.  */
+    long overflows;		/* Number of stack overflow ($STKOFEN) calls.  */
+    long hits;			/* Number of internal buffer hits.  */
+    long extends;		/* Number of block extensions.  */
+    long stko_mallocs;		/* Block allocations by $STKOFEN.  */
+    long underflows;		/* Number of stack underflow calls ($STKRETN).  */
+    long stko_free;		/* Number of deallocations by $STKRETN.  */
+    long stkm_free;		/* Number of deallocations by $STKMRET.  */
+    long segments;		/* Current number of stack segments.  */
+    long maxs;			/* Maximum number of stack segments so far.  */
+    long pad_size;		/* Stack pad size.  */
+    long current_address;	/* Current stack segment address.  */
+    long current_size;		/* Current stack segment size.  This
+				   number is actually corrupted by STKSTAT to
+				   include the fifteen word trailer area.  */
+    long initial_address;	/* Address of initial segment.  */
+    long initial_size;		/* Size of initial segment.  */
+  };
+
+/* The following structure describes the data structure which trails
+   any stack segment.  I think that the description in 'asdef' is
+   out of date.  I only describe the parts that I am sure about.  */
+
+struct stk_trailer
+  {
+    long this_address;		/* Address of this block.  */
+    long this_size;		/* Size of this block (does not include
+				   this trailer).  */
+    long unknown2;
+    long unknown3;
+    long link;			/* Address of trailer block of previous
+				   segment.  */
+    long unknown5;
+    long unknown6;
+    long unknown7;
+    long unknown8;
+    long unknown9;
+    long unknown10;
+    long unknown11;
+    long unknown12;
+    long unknown13;
+    long unknown14;
+  };
+
+#endif /* CRAY2 */
+#endif /* not CRAY_STACK */
+
+#ifdef CRAY2
+/* Determine a "stack measure" for an arbitrary ADDRESS.
+   I doubt that "lint" will like this much. */
+
+static long
+i00afunc (long *address)
+{
+  struct stk_stat status;
+  struct stk_trailer *trailer;
+  long *block, size;
+  long result = 0;
+
+  /* We want to iterate through all of the segments.  The first
+     step is to get the stack status structure.  We could do this
+     more quickly and more directly, perhaps, by referencing the
+     $LM00 common block, but I know that this works.  */
+
+  STKSTAT (&status);
+
+  /* Set up the iteration.  */
+
+  trailer = (struct stk_trailer *) (status.current_address
+				    + status.current_size
+				    - 15);
+
+  /* There must be at least one stack segment.  Therefore it is
+     a fatal error if "trailer" is null.  */
+
+  if (trailer == 0)
+    abort ();
+
+  /* Discard segments that do not contain our argument address.  */
+
+  while (trailer != 0)
+    {
+      block = (long *) trailer->this_address;
+      size = trailer->this_size;
+      if (block == 0 || size == 0)
+	abort ();
+      trailer = (struct stk_trailer *) trailer->link;
+      if ((block <= address) && (address < (block + size)))
+	break;
+    }
+
+  /* Set the result to the offset in this segment and add the sizes
+     of all predecessor segments.  */
+
+  result = address - block;
+
+  if (trailer == 0)
+    {
+      return result;
+    }
+
+  do
+    {
+      if (trailer->this_size <= 0)
+	abort ();
+      result += trailer->this_size;
+      trailer = (struct stk_trailer *) trailer->link;
+    }
+  while (trailer != 0);
+
+  /* We are done.  Note that if you present a bogus address (one
+     not in any segment), you will get a different number back, formed
+     from subtracting the address of the first block.  This is probably
+     not what you want.  */
+
+  return (result);
+}
+
+#else /* not CRAY2 */
+/* Stack address function for a CRAY-1, CRAY X-MP, or CRAY Y-MP.
+   Determine the number of the cell within the stack,
+   given the address of the cell.  The purpose of this
+   routine is to linearize, in some sense, stack addresses
+   for alloca.  */
+
+static long
+i00afunc (long address)
+{
+  long stkl = 0;
+
+  long size, pseg, this_segment, stack;
+  long result = 0;
+
+  struct stack_segment_linkage *ssptr;
+
+  /* Register B67 contains the address of the end of the
+     current stack segment.  If you (as a subprogram) store
+     your registers on the stack and find that you are past
+     the contents of B67, you have overflowed the segment.
+
+     B67 also points to the stack segment linkage control
+     area, which is what we are really interested in.  */
+
+  stkl = CRAY_STACKSEG_END ();
+  ssptr = (struct stack_segment_linkage *) stkl;
+
+  /* If one subtracts 'size' from the end of the segment,
+     one has the address of the first word of the segment.
+
+     If this is not the first segment, 'pseg' will be
+     nonzero.  */
+
+  pseg = ssptr->sspseg;
+  size = ssptr->sssize;
+
+  this_segment = stkl - size;
+
+  /* It is possible that calling this routine itself caused
+     a stack overflow.  Discard stack segments which do not
+     contain the target address.  */
+
+  while (!(this_segment <= address && address <= stkl))
+    {
+#ifdef DEBUG_I00AFUNC
+      fprintf (stderr, "%011o %011o %011o\n", this_segment, address, stkl);
+#endif
+      if (pseg == 0)
+	break;
+      stkl = stkl - pseg;
+      ssptr = (struct stack_segment_linkage *) stkl;
+      size = ssptr->sssize;
+      pseg = ssptr->sspseg;
+      this_segment = stkl - size;
+    }
+
+  result = address - this_segment;
+
+  /* If you subtract pseg from the current end of the stack,
+     you get the address of the previous stack segment's end.
+     This seems a little convoluted to me, but I'll bet you save
+     a cycle somewhere.  */
+
+  while (pseg != 0)
+    {
+#ifdef DEBUG_I00AFUNC
+      fprintf (stderr, "%011o %011o\n", pseg, size);
+#endif
+      stkl = stkl - pseg;
+      ssptr = (struct stack_segment_linkage *) stkl;
+      size = ssptr->sssize;
+      pseg = ssptr->sspseg;
+      result += size;
+    }
+  return (result);
+}
+
+#endif /* not CRAY2 */
+#endif /* CRAY */
+
+#endif /* no alloca */
Index: /main/tags/2.25/gsdl/packages/wingdbm/autoconf.h
===================================================================
--- /main/tags/2.25/gsdl/packages/wingdbm/autoconf.h	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/wingdbm/autoconf.h	(revision 21064)
@@ -0,0 +1,85 @@
+/* autoconf.h.in.  Generated automatically from configure.in by autoheader.  */
+
+#define MSDOS
+
+/* Define if using alloca.c.  */
+#undef C_ALLOCA
+
+/* Define to empty if the keyword does not work.  */
+#undef const
+
+/* Define to one of _getb67, GETB67, getb67 for Cray-2 and Cray-YMP systems.
+   This function is required for alloca.c support on those systems.  */
+#undef CRAY_STACKSEG_END
+
+/* Define if you have alloca.h and it should be used (not Ultrix).  */
+#undef HAVE_ALLOCA_H
+
+/* Define if your struct stat has st_blksize.  */
+#undef HAVE_ST_BLKSIZE
+
+/* Define if int is 16 bits instead of 32.  */
+#undef INT_16_BITS
+
+/* Define if long int is 64 bits.  */
+#undef LONG_64_BITS
+
+/* Define to `long' if <sys/types.h> doesn't define.  */
+#undef off_t
+
+/* If using the C implementation of alloca, define if you know the
+   direction of stack growth for your system; otherwise it will be
+   automatically deduced at run-time.
+	STACK_DIRECTION > 0 => grows toward higher addresses
+	STACK_DIRECTION < 0 => grows toward lower addresses
+	STACK_DIRECTION = 0 => direction of growth unknown
+ */
+#undef STACK_DIRECTION
+
+/* Define if your processor stores words with the most significant
+   byte first (like Motorola and SPARC, unlike Intel and VAX).  */
+#undef WORDS_BIGENDIAN
+
+/* Define if you have bcopy.  */
+#undef HAVE_BCOPY
+
+/* Define if you have flock.  */
+#undef HAVE_FLOCK
+
+/* Define if you have fsync.  */
+#undef HAVE_FSYNC
+
+/* Define if you have ftruncate.  */
+#undef HAVE_FTRUNCATE
+
+/* Define if you have rename.  */
+#define HAVE_RENAME 1
+
+/* Define if you have the <fcntl.h> header file.  */
+#define HAVE_FCNTL_H 1
+
+/* Define if you have the <memory.h> header file.  */
+#define HAVE_MEMORY_H 1
+
+/* Define if you have the <stdlib.h> header file.  */
+#define HAVE_STDLIB_H 1
+
+/* Define if you have the <string.h> header file.  */
+#define HAVE_STRING_H 1
+
+/* Define if you have the <sys/file.h> header file.  */
+#undef HAVE_SYS_FILE_H
+
+/* Define if you have the <sys/types.h> header file.  */
+#define HAVE_SYS_TYPES_H 1
+
+/* Define if you have the <unistd.h> header file.  */
+#undef HAVE_UNISTD_H
+
+/* Define if you have the dbm library (-ldbm).  */
+#undef HAVE_LIBDBM
+
+/* Define if you have the ndbm library (-lndbm).  */
+#undef HAVE_LIBNDBM
+
+
Index: /main/tags/2.25/gsdl/packages/wingdbm/bucket.c
===================================================================
--- /main/tags/2.25/gsdl/packages/wingdbm/bucket.c	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/wingdbm/bucket.c	(revision 21064)
@@ -0,0 +1,336 @@
+/* bucket.c - The routines for playing with hash buckets. */
+
+/*  This file is part of GDBM, the GNU data base manager, by Philip A. Nelson.
+    Copyright (C) 1990, 1991, 1993  Free Software Foundation, Inc.
+
+    GDBM 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, or (at your option)
+    any later version.
+
+    GDBM 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 GDBM; see the file COPYING.  If not, write to
+    the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+
+    You may contact the author by:
+       e-mail:  phil@cs.wwu.edu
+      us-mail:  Philip A. Nelson
+                Computer Science Department
+                Western Washington University
+                Bellingham, WA 98226
+       
+*************************************************************************/
+
+
+/* include system configuration before all else. */
+#include "autoconf.h"
+#include "gdbmdefs.h"
+
+
+/* Initializing a new hash buckets sets all bucket entries to -1 hash value. */
+void
+_gdbm_new_bucket (dbf, bucket, bits)
+     gdbm_file_info *dbf;
+     hash_bucket *bucket;
+     int bits;
+{
+  int index;
+  
+  /* Initialize the avail block. */
+  bucket->av_count = 0;
+
+  /* Set the information fields first. */
+  bucket->bucket_bits = bits;
+  bucket->count = 0;
+  
+  /* Initialize all bucket elements. */
+  for (index = 0; index < dbf->header->bucket_elems; index++)
+    bucket->h_table[index].hash_value = -1;
+}
+
+
+
+/* Find a bucket for DBF that is pointed to by the bucket directory from
+   location DIR_INDEX.   The bucket cache is first checked to see if it
+   is already in memory.  If not, a bucket may be tossed to read the new
+   bucket.  In any case, the requested bucket is make the "current" bucket
+   and dbf->bucket points to the correct bucket. */
+
+void
+_gdbm_get_bucket (dbf, dir_index)
+     gdbm_file_info *dbf;
+     word_t dir_index;
+{
+  off_t bucket_adr;	/* The address of the correct hash bucket.  */
+  int   num_bytes;	/* The number of bytes read. */
+  off_t	file_pos;	/* The return address for lseek. */
+  register int index;	/* Loop index. */
+
+  /* Initial set up. */
+  dbf->bucket_dir = dir_index;
+  bucket_adr = dbf->dir [dir_index];
+  
+  if (dbf->bucket_cache == NULL)
+    {
+      if(_gdbm_init_cache(dbf, DEFAULT_CACHESIZE) == -1)
+        _gdbm_fatal(dbf, "couldn't init cache");
+    }
+
+  /* Is that one is not already current, we must find it. */
+  if (dbf->cache_entry->ca_adr != bucket_adr)
+    {
+      /* Look in the cache. */
+      for (index = 0; index < dbf->cache_size; index++)
+        {
+	  if (dbf->bucket_cache[index].ca_adr == bucket_adr)
+	    {
+	      dbf->bucket = dbf->bucket_cache[index].ca_bucket;
+	      dbf->cache_entry = &dbf->bucket_cache[index];
+	      return;
+	    }
+        }
+
+      /* It is not in the cache, read it from the disk. */
+      dbf->last_read = (dbf->last_read + 1) % dbf->cache_size;
+      if (dbf->bucket_cache[dbf->last_read].ca_changed)
+	_gdbm_write_bucket (dbf, &dbf->bucket_cache[dbf->last_read]);
+      dbf->bucket_cache[dbf->last_read].ca_adr = bucket_adr;
+      dbf->bucket = dbf->bucket_cache[dbf->last_read].ca_bucket;
+      dbf->cache_entry = &dbf->bucket_cache[dbf->last_read];
+      dbf->cache_entry->ca_data.elem_loc = -1;
+      dbf->cache_entry->ca_changed = FALSE;
+
+      /* Read the bucket. */
+      file_pos = lseek (dbf->desc, bucket_adr, L_SET);
+      if (file_pos != bucket_adr)
+	_gdbm_fatal (dbf, "lseek error");
+
+      num_bytes = read (dbf->desc, dbf->bucket, dbf->header->bucket_size);
+      if (num_bytes != dbf->header->bucket_size)
+	_gdbm_fatal (dbf, "read error");
+    }
+
+  return;
+}
+
+
+/* Split the current bucket.  This includes moving all items in the bucket to
+   a new bucket.  This doesn't require any disk reads because all hash values
+   are stored in the buckets.  Splitting the current bucket may require
+   doubling the size of the hash directory.  */
+void
+_gdbm_split_bucket (dbf, next_insert)
+     gdbm_file_info *dbf;
+     word_t next_insert;
+{
+  hash_bucket *bucket[2]; 	/* Pointers to the new buckets. */
+
+  int          new_bits;	/* The number of bits for the new buckets. */
+  int	       cache_0;		/* Location in the cache for the buckets. */
+  int	       cache_1;
+  off_t        adr_0;		/* File address of the new bucket 0. */
+  off_t        adr_1;		/* File address of the new bucket 1. */
+  avail_elem   old_bucket;	/* Avail Struct for the old bucket. */
+
+  off_t        dir_start0;	/* Used in updating the directory. */
+  off_t        dir_start1;
+  off_t        dir_end;
+
+  off_t       *new_dir;		/* Pointer to the new directory. */
+  off_t        dir_adr; 	/* Address of the new directory. */
+  int          dir_size;	/* Size of the new directory. */
+  off_t        old_adr[31]; 	/* Address of the old directories. */
+  int          old_size[31]; 	/* Size of the old directories. */
+  int	       old_count;	/* Number of old directories. */
+
+  int          index;		/* Used in array indexing. */
+  int          index1;		/* Used in array indexing. */
+  int          elem_loc;	/* Location in new bucket to put element. */
+  bucket_element *old_el;	/* Pointer into the old bucket. */
+  int	       select;		/* Used to index bucket during movement. */
+
+
+  /* No directories are yet old. */
+  old_count = 0;
+
+  if (dbf->bucket_cache == NULL)
+    {
+      if(_gdbm_init_cache(dbf, DEFAULT_CACHESIZE) == -1)
+        _gdbm_fatal(dbf, "couldn't init cache");
+    }
+ 
+  while (dbf->bucket->count == dbf->header->bucket_elems)
+    {
+      /* Initialize the "new" buckets in the cache. */
+      do
+	{
+	  dbf->last_read = (dbf->last_read + 1) % dbf->cache_size;
+	  cache_0 = dbf->last_read;
+	}      
+      while (dbf->bucket_cache[cache_0].ca_bucket == dbf->bucket);
+      bucket[0] = dbf->bucket_cache[cache_0].ca_bucket;
+      if (dbf->bucket_cache[cache_0].ca_changed)
+	_gdbm_write_bucket (dbf, &dbf->bucket_cache[cache_0]);
+      do
+	{
+	  dbf->last_read = (dbf->last_read + 1) % dbf->cache_size;
+	  cache_1 = dbf->last_read;
+	}      
+      while (dbf->bucket_cache[cache_1].ca_bucket == dbf->bucket);
+      bucket[1] = dbf->bucket_cache[cache_1].ca_bucket;
+      if (dbf->bucket_cache[cache_1].ca_changed)
+	_gdbm_write_bucket (dbf, &dbf->bucket_cache[cache_1]);
+      new_bits = dbf->bucket->bucket_bits+1;
+      _gdbm_new_bucket (dbf, bucket[0], new_bits);
+      _gdbm_new_bucket (dbf, bucket[1], new_bits);
+      adr_0 = _gdbm_alloc (dbf, dbf->header->bucket_size); 
+      dbf->bucket_cache[cache_0].ca_adr = adr_0;
+      adr_1 = _gdbm_alloc (dbf, dbf->header->bucket_size);
+      dbf->bucket_cache[cache_1].ca_adr = adr_1;
+
+      
+      
+      /* Double the directory size if necessary. */
+      if (dbf->header->dir_bits == dbf->bucket->bucket_bits)
+	{
+	  dir_size = dbf->header->dir_size * 2;
+	  dir_adr  = _gdbm_alloc (dbf, dir_size);
+	  new_dir  = (off_t *) malloc (dir_size);
+	  if (new_dir == NULL) _gdbm_fatal (dbf, "malloc error");
+	  for (index = 0;
+	  	(unsigned int)index < dbf->header->dir_size/sizeof (off_t); index++)
+	    {
+	      new_dir[2*index]   = dbf->dir[index];
+	      new_dir[2*index+1] = dbf->dir[index];
+	    }
+	  
+	  /* Update header. */
+	  old_adr[old_count] = dbf->header->dir;
+	  dbf->header->dir = dir_adr;
+	  old_size[old_count] = dbf->header->dir_size;
+	  dbf->header->dir_size = dir_size;
+	  dbf->header->dir_bits = new_bits;
+	  old_count++;
+	  
+	  /* Now update dbf.  */
+	  dbf->header_changed = TRUE;
+	  dbf->bucket_dir *= 2;
+	  free (dbf->dir);
+	  dbf->dir = new_dir;
+	}
+
+      /* Copy all elements in dbf->bucket into the new buckets. */
+      for (index = 0; index < dbf->header->bucket_elems; index++)
+	{
+	  old_el = & (dbf->bucket->h_table[index]);
+	  select = (old_el->hash_value >> (31-new_bits)) & 1;
+	  elem_loc = old_el->hash_value % dbf->header->bucket_elems;
+	  while (bucket[select]->h_table[elem_loc].hash_value != -1)
+	    elem_loc = (elem_loc + 1) % dbf->header->bucket_elems;
+	  bucket[select]->h_table[elem_loc] = *old_el;
+	  bucket[select]->count += 1;
+	}
+      
+      /* Allocate avail space for the bucket[1]. */
+      bucket[1]->bucket_avail[0].av_adr
+	= _gdbm_alloc (dbf, dbf->header->block_size);
+      bucket[1]->bucket_avail[0].av_size = dbf->header->block_size;
+      bucket[1]->av_count = 1;
+      
+      /* Copy the avail elements in dbf->bucket to bucket[0]. */
+      bucket[0]->av_count = dbf->bucket->av_count;
+      index = 0;
+      index1 = 0;
+      if (bucket[0]->av_count == BUCKET_AVAIL)
+	{
+	  /* The avail is full, move the first one to bucket[1]. */
+	  _gdbm_put_av_elem (dbf->bucket->bucket_avail[0],
+			     bucket[1]->bucket_avail,
+			     &bucket[1]->av_count);
+	  index = 1;
+	  bucket[0]->av_count --;
+	}
+      for (; index < dbf->bucket->av_count; index++)
+	{
+	  bucket[0]->bucket_avail[index1++] = dbf->bucket->bucket_avail[index];
+	}
+      
+      /* Update the directory.  We have new file addresses for both buckets. */
+      dir_start1 = (dbf->bucket_dir >> (dbf->header->dir_bits - new_bits)) | 1;
+      dir_end = (dir_start1 + 1) << (dbf->header->dir_bits - new_bits);
+      dir_start1 = dir_start1 << (dbf->header->dir_bits - new_bits);
+      dir_start0 = dir_start1 - (dir_end - dir_start1);
+      for (index = dir_start0; index < dir_start1; index++)
+	dbf->dir[index] = adr_0;
+      for (index = dir_start1; index < dir_end; index++)
+	dbf->dir[index] = adr_1;
+      
+      
+      /* Set changed flags. */
+      dbf->bucket_cache[cache_0].ca_changed = TRUE;
+      dbf->bucket_cache[cache_1].ca_changed = TRUE;
+      dbf->bucket_changed = TRUE;
+      dbf->directory_changed = TRUE;
+      dbf->second_changed = TRUE;
+      
+      /* Update the cache! */
+      dbf->bucket_dir = next_insert >> (31-dbf->header->dir_bits);
+      
+      /* Invalidate old cache entry. */
+      old_bucket.av_adr  = dbf->cache_entry->ca_adr;
+      old_bucket.av_size = dbf->header->bucket_size;
+      dbf->cache_entry->ca_adr = 0;
+      dbf->cache_entry->ca_changed = FALSE;
+      
+      /* Set dbf->bucket to the proper bucket. */
+      if (dbf->dir[dbf->bucket_dir] == adr_0)
+	{
+	  dbf->bucket = bucket[0];
+	  dbf->cache_entry = &dbf->bucket_cache[cache_0];
+	  _gdbm_put_av_elem (old_bucket,
+			     bucket[1]->bucket_avail,
+			     &bucket[1]->av_count);
+	}
+      else
+	{
+	  dbf->bucket = bucket[1];
+	  dbf->cache_entry = &dbf->bucket_cache[cache_1];
+	  _gdbm_put_av_elem (old_bucket,
+			     bucket[0]->bucket_avail,
+			     &bucket[0]->av_count);
+	}
+      
+    }
+
+  /* Get rid of old directories. */
+  for (index = 0; index < old_count; index++)
+    _gdbm_free (dbf, old_adr[index], old_size[index]);
+}
+
+
+/* The only place where a bucket is written.  CA_ENTRY is the
+   cache entry containing the bucket to be written. */
+
+void
+_gdbm_write_bucket (dbf, ca_entry)
+     gdbm_file_info *dbf;
+     cache_elem *ca_entry;
+{
+  int  num_bytes;	/* The return value for write. */
+  off_t file_pos;	/* The return value for lseek. */
+  
+  file_pos = lseek (dbf->desc, ca_entry->ca_adr, L_SET);
+  if (file_pos != ca_entry->ca_adr)
+    _gdbm_fatal (dbf, "lseek error");
+  num_bytes = write (dbf->desc, ca_entry->ca_bucket, dbf->header->bucket_size);
+  if (num_bytes != dbf->header->bucket_size)
+    _gdbm_fatal (dbf, "write error");
+  ca_entry->ca_changed = FALSE;
+  ca_entry->ca_data.hash_val = -1;
+  ca_entry->ca_data.elem_loc = -1;
+}
Index: /main/tags/2.25/gsdl/packages/wingdbm/close.c
===================================================================
--- /main/tags/2.25/gsdl/packages/wingdbm/close.c	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/wingdbm/close.c	(revision 21064)
@@ -0,0 +1,55 @@
+/* close.c - Close the "original" style database. */
+
+/*  This file is part of GDBM, the GNU data base manager, by Philip A. Nelson.
+    Copyright (C) 1993  Free Software Foundation, Inc.
+
+    GDBM 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, or (at your option)
+    any later version.
+
+    GDBM 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 GDBM; see the file COPYING.  If not, write to
+    the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+
+    You may contact the original author by:
+       e-mail:  phil@cs.wwu.edu
+      us-mail:  Philip A. Nelson
+                Computer Science Department
+                Western Washington University
+                Bellingham, WA 98226
+       
+    The author of this file is:
+       e-mail:  downsj@csos.orst.edu
+
+*************************************************************************/
+
+
+/* include system configuration before all else. */
+#include "autoconf.h"
+
+#include "gdbmdefs.h"
+#include "extern.h"
+
+
+/* it's unclear whether dbmclose() is *always* a void function in old
+   C libraries. we use int, here. */
+
+int
+dbmclose()
+{
+  if (_gdbm_file != NULL)
+    {
+      gdbm_close (_gdbm_file);
+      _gdbm_file = NULL;
+      if (_gdbm_memory.dptr != NULL) free(_gdbm_memory.dptr);
+      _gdbm_memory.dptr = NULL;
+      _gdbm_memory.dsize = 0;
+    }
+  return (0);
+}
Index: /main/tags/2.25/gsdl/packages/wingdbm/extern.h
===================================================================
--- /main/tags/2.25/gsdl/packages/wingdbm/extern.h	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/wingdbm/extern.h	(revision 21064)
@@ -0,0 +1,35 @@
+/* extern.h - The collection of external definitions needed. */
+
+/*  This file is part of GDBM, the GNU data base manager, by Philip A. Nelson.
+    Copyright (C) 1990, 1991, 1993  Free Software Foundation, Inc.
+
+    GDBM 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, or (at your option)
+    any later version.
+
+    GDBM 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 GDBM; see the file COPYING.  If not, write to
+    the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+
+    You may contact the author by:
+       e-mail:  phil@cs.wwu.edu
+      us-mail:  Philip A. Nelson
+                Computer Science Department
+                Western Washington University
+                Bellingham, WA 98226
+       
+*************************************************************************/
+
+
+/* The global variables used for the "original" interface. */
+extern gdbm_file_info  *_gdbm_file;
+
+/* Memory for return data for the "original" interface. */
+extern datum _gdbm_memory;
+extern char *_gdbm_fetch_val;
Index: /main/tags/2.25/gsdl/packages/wingdbm/falloc.c
===================================================================
--- /main/tags/2.25/gsdl/packages/wingdbm/falloc.c	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/wingdbm/falloc.c	(revision 21064)
@@ -0,0 +1,422 @@
+/* falloc.c - The file space management routines for dbm. */
+
+/*  This file is part of GDBM, the GNU data base manager, by Philip A. Nelson.
+    Copyright (C) 1990, 1991, 1993, 1994  Free Software Foundation, Inc.
+
+    GDBM 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, or (at your option)
+    any later version.
+
+    GDBM 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 GDBM; see the file COPYING.  If not, write to
+    the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+
+    You may contact the author by:
+       e-mail:  phil@cs.wwu.edu
+      us-mail:  Philip A. Nelson
+                Computer Science Department
+                Western Washington University
+                Bellingham, WA 98226
+       
+*************************************************************************/
+
+
+/* AIX demands this be the very first thing in the file. */
+#if !defined(__GNUC__) && defined(_AIX)
+ #pragma alloca
+#endif
+
+/* include system configuration before all else. */
+#include "autoconf.h"
+
+#include "gdbmdefs.h"
+
+
+/* The forward definitions for this file.  See the functions for
+   the definition of the function. */
+
+static avail_elem get_elem _ARGS((int, avail_elem [], int *));
+static avail_elem get_block _ARGS((int, gdbm_file_info *));
+static void push_avail_block _ARGS((gdbm_file_info *));
+static void pop_avail_block _ARGS((gdbm_file_info *));
+static void adjust_bucket_avail _ARGS((gdbm_file_info *));
+
+/* Allocate space in the file DBF for a block NUM_BYTES in length.  Return
+   the file address of the start of the block.  
+
+   Each hash bucket has a fixed size avail table.  We first check this
+   avail table to satisfy the request for space.  In most cases we can
+   and this causes changes to be only in the current hash bucket.
+   Allocation is done on a first fit basis from the entries.  If a
+   request can not be satisfied from the current hash bucket, then it is
+   satisfied from the file header avail block.  If nothing is there that
+   has enough space, another block at the end of the file is allocated
+   and the unused portion is returned to the avail block.  This routine
+   "guarantees" that an allocation does not cross a block boundary unless
+   the size is larger than a single block.  The avail structure is
+   changed by this routine if a change is needed.  If an error occurs,
+   the value of 0 will be returned.  */
+
+off_t
+_gdbm_alloc (dbf, num_bytes)
+     gdbm_file_info *dbf;
+     int num_bytes;
+{
+  off_t file_adr;		/* The address of the block. */
+  avail_elem av_el;		/* For temporary use. */
+
+  /* The current bucket is the first place to look for space. */
+  av_el = get_elem (num_bytes, dbf->bucket->bucket_avail,
+		    &dbf->bucket->av_count);
+
+  /* If we did not find some space, we have more work to do. */
+  if (av_el.av_size == 0)
+    {
+      /* Is the header avail block empty and there is something on the stack. */
+      if ((dbf->header->avail.count == 0)
+          && (dbf->header->avail.next_block != 0))
+        pop_avail_block (dbf);
+
+      /* check the header avail table next */
+      av_el = get_elem (num_bytes, dbf->header->avail.av_table,
+      			&dbf->header->avail.count);
+      if (av_el.av_size == 0)
+        /* Get another full block from end of file. */
+        av_el = get_block (num_bytes, dbf);
+
+      dbf->header_changed = TRUE;
+    }
+
+  /* We now have the place from which we will allocate the new space. */
+  file_adr = av_el.av_adr;
+
+  /* Put the unused space back in the avail block. */
+  av_el.av_adr += num_bytes;
+  av_el.av_size -= num_bytes;
+  _gdbm_free (dbf, av_el.av_adr, av_el.av_size);
+
+  /* Return the address. */
+  return file_adr;
+  
+}
+
+
+
+/* Free space of size NUM_BYTES in the file DBF at file address FILE_ADR.  Make
+   it avaliable for reuse through _gdbm_alloc.  This routine changes the
+   avail structure.  The value TRUE is returned if there were errors.  If no
+   errors occured, the value FALSE is returned. */
+
+void
+_gdbm_free (dbf, file_adr, num_bytes)
+     gdbm_file_info *dbf;
+     off_t file_adr;
+     int num_bytes;
+{
+  avail_elem temp;
+
+  /* Is it too small to worry about? */
+  if (num_bytes <= IGNORE_SIZE)
+    return;
+
+  /* Initialize the avail element. */
+  temp.av_size = num_bytes;
+  temp.av_adr = file_adr;
+
+  /* Is the freed space large or small? */
+  if (num_bytes >= dbf->header->block_size)
+    {
+      if (dbf->header->avail.count == dbf->header->avail.size)
+	{
+	  push_avail_block (dbf);
+	}
+      _gdbm_put_av_elem (temp, dbf->header->avail.av_table,
+			 &dbf->header->avail.count);
+      dbf->header_changed = TRUE;
+    }
+  else
+    {
+      /* Try to put into the current bucket. */
+      if (dbf->bucket->av_count < BUCKET_AVAIL)
+	_gdbm_put_av_elem (temp, dbf->bucket->bucket_avail,
+			   &dbf->bucket->av_count);
+      else
+	{
+	  if (dbf->header->avail.count == dbf->header->avail.size)
+	    {
+	      push_avail_block (dbf);
+	    }
+	  _gdbm_put_av_elem (temp, dbf->header->avail.av_table,
+			     &dbf->header->avail.count);
+	  dbf->header_changed = TRUE;
+	}
+    }
+
+  if (dbf->header_changed)
+    adjust_bucket_avail (dbf);
+
+  /* All work is done. */
+  return;
+}
+
+
+
+/* The following are all utility routines needed by the previous two. */
+
+
+/* Gets the avail block at the top of the stack and loads it into the
+   active avail block.  It does a "free" for itself! */
+
+static void
+pop_avail_block (dbf)
+     gdbm_file_info *dbf;
+{
+  int  num_bytes;		/* For use with the read system call. */
+  off_t file_pos;		/* For use with the lseek system call. */
+  avail_elem temp;
+
+  /* Set up variables. */
+  temp.av_adr = dbf->header->avail.next_block;
+  temp.av_size = ( ( (dbf->header->avail.size * sizeof (avail_elem)) >> 1)
+		  + sizeof (avail_block));
+
+  /* Read the block. */
+  file_pos = lseek (dbf->desc, temp.av_adr, L_SET);
+  if (file_pos != temp.av_adr)  _gdbm_fatal (dbf, "lseek error");
+  num_bytes = read (dbf->desc, &dbf->header->avail, temp.av_size);
+  if (num_bytes != temp.av_size) _gdbm_fatal (dbf, "read error");
+
+  /* We changed the header. */
+  dbf->header_changed = TRUE;
+
+  /* Free the previous avail block. */
+  _gdbm_put_av_elem (temp, dbf->header->avail.av_table,
+		     &dbf->header->avail.count);
+}
+
+
+/* Splits the header avail block and pushes half onto the avail stack. */
+
+static void
+push_avail_block (dbf)
+     gdbm_file_info *dbf;
+{
+  int  num_bytes;
+  int  av_size;
+  off_t av_adr;
+  int  index;
+  off_t file_pos;
+  avail_block *temp;
+  avail_elem  new_loc;
+ 
+
+  /* Caclulate the size of the split block. */
+  av_size = ( (dbf->header->avail.size * sizeof (avail_elem)) >> 1)
+            + sizeof (avail_block);
+
+  /* Get address in file for new av_size bytes. */
+  new_loc = get_elem (av_size, dbf->header->avail.av_table,
+		      &dbf->header->avail.count);
+  if (new_loc.av_size == 0)
+    new_loc = get_block (av_size, dbf);
+  av_adr = new_loc.av_adr;
+
+
+  /* Split the header block. */
+  temp = (avail_block *) alloca (av_size);
+#ifdef MSDOS
+  if (temp == (avail_block *) 0)
+    {
+      fprintf (stderr, "Error: alloca() failed in gdbm (%s).\n", __FILE__);
+      exit (-2);
+    }
+#endif /* MSDOS */  /* Set the size to be correct AFTER the pop_avail_block. */
+  temp->size = dbf->header->avail.size;
+  temp->count = 0;
+  temp->next_block = dbf->header->avail.next_block;
+  dbf->header->avail.next_block = av_adr;
+  for (index = 1; index < dbf->header->avail.count; index++)
+    if ( (index & 0x1) == 1)	/* Index is odd. */
+      temp->av_table[temp->count++] = dbf->header->avail.av_table[index];
+    else
+      dbf->header->avail.av_table[index>>1]
+	= dbf->header->avail.av_table[index];
+
+  /* Update the header avail count to previous size divided by 2. */
+  dbf->header->avail.count >>= 1;
+
+  /* Free the unneeded space. */
+  new_loc.av_adr += av_size;
+  new_loc.av_size -= av_size;
+  _gdbm_free (dbf, new_loc.av_adr, new_loc.av_size);
+
+  /* Update the disk. */
+  file_pos = lseek (dbf->desc, av_adr, L_SET);
+  if (file_pos != av_adr) _gdbm_fatal (dbf, "lseek error");
+  num_bytes = write (dbf->desc, temp, av_size);
+  if (num_bytes != av_size) _gdbm_fatal (dbf, "write error");
+
+}
+
+
+
+/* Get_elem returns an element in the AV_TABLE block which is
+   larger than SIZE.  AV_COUNT is the number of elements in the
+   AV_TABLE.  If an item is found, it extracts it from the AV_TABLE
+   and moves the other elements up to fill the space. If no block is 
+   found larger than SIZE, get_elem returns a size of zero.  This
+   routine does no I/O. */
+
+static avail_elem
+get_elem (size, av_table, av_count)
+     int size;
+     avail_elem av_table[];
+     int *av_count;
+{
+  int index;			/* For searching through the avail block. */
+  avail_elem val;		/* The default return value. */
+
+  /* Initialize default return value. */
+  val.av_adr = 0;
+  val.av_size = 0;
+
+  /* Search for element.  List is sorted by size. */
+  index = 0;
+  while (index < *av_count && av_table[index].av_size < size)
+    {
+      index++;
+    }
+
+  /* Did we find one of the right size? */
+  if (index >= *av_count)
+    return val;
+
+  /* Ok, save that element and move all others up one. */
+  val = av_table[index];
+  *av_count -= 1;
+  while (index < *av_count)
+    {
+      av_table[index] = av_table[index+1];
+      index++;
+    }
+
+  return val;
+}
+
+
+/* This routine inserts a single NEW_EL into the AV_TABLE block in
+   sorted order. This routine does no I/O. */
+
+int
+_gdbm_put_av_elem (new_el, av_table, av_count)
+     avail_elem new_el;
+     avail_elem av_table[];
+     int *av_count;
+{
+  int index;			/* For searching through the avail block. */
+  int index1;
+
+  /* Is it too small to deal with? */
+  if (new_el.av_size <= IGNORE_SIZE)
+    return FALSE; 
+
+  /* Search for place to put element.  List is sorted by size. */
+  index = 0;
+  while (index < *av_count && av_table[index].av_size < new_el.av_size)
+    {
+      index++;
+    }
+
+  /* Move all others up one. */
+  index1 = *av_count-1;
+  while (index1 >= index)
+    {
+      av_table[index1+1] = av_table[index1];
+      index1--;
+    }
+  
+  /* Add the new element. */
+  av_table[index] = new_el;
+
+  /* Increment the number of elements. */
+  *av_count += 1;  
+
+  return TRUE;
+}
+
+
+
+
+
+/* Get_block "allocates" new file space and the end of the file.  This is
+   done in integral block sizes.  (This helps insure that data smaller than
+   one block size is in a single block.)  Enough blocks are allocated to
+   make sure the number of bytes allocated in the blocks is larger than SIZE.
+   DBF contains the file header that needs updating.  This routine does
+   no I/O.  */
+
+static avail_elem
+get_block (size, dbf)
+     int size;
+     gdbm_file_info *dbf;
+{
+  avail_elem val;
+
+  /* Need at least one block. */
+  val.av_adr  = dbf->header->next_block;
+  val.av_size = dbf->header->block_size;
+
+  /* Get enough blocks to fit the need. */
+  while (val.av_size < size)
+    val.av_size += dbf->header->block_size;
+
+  /* Update the header and return. */
+  dbf->header->next_block += val.av_size;
+
+  /* We changed the header. */
+  dbf->header_changed = TRUE;
+
+  return val;
+  
+}
+
+
+/*  When the header already needs writing, we can make sure the current
+    bucket has its avail block as close to 1/2 full as possible. */
+static void
+adjust_bucket_avail (dbf)
+     gdbm_file_info *dbf;
+{
+  int third = BUCKET_AVAIL / 3;
+  avail_elem av_el;
+
+  /* Can we add more entries to the bucket? */
+  if (dbf->bucket->av_count < third)
+    {
+      if (dbf->header->avail.count > 0)
+	{
+	  dbf->header->avail.count -= 1;
+	  av_el = dbf->header->avail.av_table[dbf->header->avail.count];
+	  _gdbm_put_av_elem (av_el, dbf->bucket->bucket_avail,
+			     &dbf->bucket->av_count);
+	  dbf->bucket_changed = TRUE;
+	}
+      return;
+    }
+
+  /* Is there too much in the bucket? */
+  while (dbf->bucket->av_count > BUCKET_AVAIL-third
+	 && dbf->header->avail.count < dbf->header->avail.size)
+    {
+      av_el = get_elem (0, dbf->bucket->bucket_avail, &dbf->bucket->av_count);
+      _gdbm_put_av_elem (av_el, dbf->header->avail.av_table,
+			 &dbf->header->avail.count);
+      dbf->bucket_changed = TRUE;
+    }
+}
Index: /main/tags/2.25/gsdl/packages/wingdbm/findkey.c
===================================================================
--- /main/tags/2.25/gsdl/packages/wingdbm/findkey.c	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/wingdbm/findkey.c	(revision 21064)
@@ -0,0 +1,160 @@
+/* findkey.c - The routine that finds a key entry in the file. */
+
+/*  This file is part of GDBM, the GNU data base manager, by Philip A. Nelson.
+    Copyright (C) 1990, 1991, 1993  Free Software Foundation, Inc.
+
+    GDBM 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, or (at your option)
+    any later version.
+
+    GDBM 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 GDBM; see the file COPYING.  If not, write to
+    the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+
+    You may contact the author by:
+       e-mail:  phil@cs.wwu.edu
+      us-mail:  Philip A. Nelson
+                Computer Science Department
+                Western Washington University
+                Bellingham, WA 98226
+       
+*************************************************************************/
+
+
+/* include system configuration before all else. */
+#include "autoconf.h"
+
+#include "gdbmdefs.h"
+
+
+/* Read the data found in bucket entry ELEM_LOC in file DBF and
+   return a pointer to it.  Also, cache the read value. */
+
+char *
+_gdbm_read_entry (dbf, elem_loc)
+     gdbm_file_info *dbf;
+     int elem_loc;
+{
+  int num_bytes;		/* For seeking and reading. */
+  int key_size;
+  int data_size;
+  off_t file_pos;
+  data_cache_elem *data_ca;
+
+  /* Is it already in the cache? */
+  if (dbf->cache_entry->ca_data.elem_loc == elem_loc)
+    return dbf->cache_entry->ca_data.dptr;
+
+  /* Set sizes and pointers. */
+  key_size = dbf->bucket->h_table[elem_loc].key_size;
+  data_size = dbf->bucket->h_table[elem_loc].data_size;
+  data_ca = &dbf->cache_entry->ca_data;
+  
+  /* Set up the cache. */
+  if (data_ca->dptr != NULL) free (data_ca->dptr);
+  data_ca->key_size = key_size;
+  data_ca->data_size = data_size;
+  data_ca->elem_loc = elem_loc;
+  data_ca->hash_val = dbf->bucket->h_table[elem_loc].hash_value;
+  if (key_size+data_size == 0)
+    data_ca->dptr = (char *) malloc (1);
+  else
+    data_ca->dptr = (char *) malloc (key_size+data_size);
+  if (data_ca->dptr == NULL) _gdbm_fatal (dbf, "malloc error");
+
+
+  /* Read into the cache. */
+  file_pos = lseek (dbf->desc,
+		    dbf->bucket->h_table[elem_loc].data_pointer, L_SET);
+  if (file_pos != dbf->bucket->h_table[elem_loc].data_pointer)
+    _gdbm_fatal (dbf, "lseek error");
+  num_bytes = read (dbf->desc, data_ca->dptr, key_size+data_size);
+  if (num_bytes != key_size+data_size) _gdbm_fatal (dbf, "read error");
+  
+  return data_ca->dptr;
+}
+
+
+
+/* Find the KEY in the file and get ready to read the associated data.  The
+   return value is the location in the current hash bucket of the KEY's
+   entry.  If it is found, a pointer to the data and the key are returned
+   in DPTR.  If it is not found, the value -1 is returned.  Since find
+   key computes the hash value of key, that value */
+int
+_gdbm_findkey (dbf, key, dptr, new_hash_val)
+     gdbm_file_info *dbf;
+     datum key;
+     char **dptr;
+     word_t *new_hash_val;		/* The new hash value. */
+{
+  word_t bucket_hash_val;	/* The hash value from the bucket. */
+  char  *file_key;		/* The complete key as stored in the file. */
+  int    elem_loc;		/* The location in the bucket. */
+  int    home_loc;		/* The home location in the bucket. */
+  int    key_size;		/* Size of the key on the file.  */
+
+  /* Compute hash value and load proper bucket.  */
+  *new_hash_val = _gdbm_hash (key);
+  _gdbm_get_bucket (dbf, *new_hash_val>> (31-dbf->header->dir_bits));
+
+  /* Is the element the last one found for this bucket? */
+  if (dbf->cache_entry->ca_data.elem_loc != -1 
+      && *new_hash_val == dbf->cache_entry->ca_data.hash_val
+      && dbf->cache_entry->ca_data.key_size == key.dsize
+      && dbf->cache_entry->ca_data.dptr != NULL
+      && bcmp (dbf->cache_entry->ca_data.dptr, key.dptr, key.dsize) == 0)
+    {
+      /* This is it. Return the cache pointer. */
+      *dptr = dbf->cache_entry->ca_data.dptr+key.dsize;
+      return dbf->cache_entry->ca_data.elem_loc;
+    }
+      
+  /* It is not the cached value, search for element in the bucket. */
+  elem_loc = *new_hash_val % dbf->header->bucket_elems;
+  home_loc = elem_loc;
+  bucket_hash_val = dbf->bucket->h_table[elem_loc].hash_value;
+  while (bucket_hash_val != -1)
+    {
+      key_size = dbf->bucket->h_table[elem_loc].key_size;
+      if (bucket_hash_val != *new_hash_val
+	 || key_size != key.dsize
+	 || bcmp (dbf->bucket->h_table[elem_loc].key_start, key.dptr,
+			(SMALL < key_size ? SMALL : key_size)) != 0) 
+	{
+	  /* Current elem_loc is not the item, go to next item. */
+	  elem_loc = (elem_loc + 1) % dbf->header->bucket_elems;
+	  if (elem_loc == home_loc) return -1;
+	  bucket_hash_val = dbf->bucket->h_table[elem_loc].hash_value;
+	}
+      else
+	{
+	  /* This may be the one we want.
+	     The only way to tell is to read it. */
+	  file_key = _gdbm_read_entry (dbf, elem_loc);
+	  if (bcmp (file_key, key.dptr, key_size) == 0)
+	    {
+	      /* This is the item. */
+	      *dptr = file_key+key.dsize;
+	      return elem_loc;
+	    }
+	  else
+	    {
+	      /* Not the item, try the next one.  Return if not found. */
+	      elem_loc = (elem_loc + 1) % dbf->header->bucket_elems;
+	      if (elem_loc == home_loc) return -1;
+	      bucket_hash_val = dbf->bucket->h_table[elem_loc].hash_value;
+	    }
+	}
+    }
+
+  /* If we get here, we never found the key. */
+  return -1;
+
+}
Index: /main/tags/2.25/gsdl/packages/wingdbm/gdbm.h
===================================================================
--- /main/tags/2.25/gsdl/packages/wingdbm/gdbm.h	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/wingdbm/gdbm.h	(revision 21064)
@@ -0,0 +1,343 @@
+/* gdbm.h  -  The include file for dbm users.  */
+
+/*  This file is part of GDBM, the GNU data base manager, by Philip A. Nelson.
+    Copyright (C) 1990, 1991, 1993  Free Software Foundation, Inc.
+
+    GDBM 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, or (at your option)
+    any later version.
+
+    GDBM 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 GDBM; see the file COPYING.  If not, write to
+    the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+
+    You may contact the author by:
+       e-mail:  phil@cs.wwu.edu
+      us-mail:  Philip A. Nelson
+                Computer Science Department
+                Western Washington University
+                Bellingham, WA 98226
+       
+*************************************************************************/
+
+
+/* Protection for multiple includes. */
+#ifndef _GDBM_H_
+#define _GDBM_H_
+
+/* Parameters to gdbm_open for READERS, WRITERS, and WRITERS who
+   can create the database. */
+#define  GDBM_READER  0		/* A reader. */
+#define  GDBM_WRITER  1		/* A writer. */
+#define  GDBM_WRCREAT 2		/* A writer.  Create the db if needed. */
+#define  GDBM_NEWDB   3		/* A writer.  Always create a new db. */
+#define  GDBM_FAST    16	/* Write fast! => No fsyncs. */
+
+/* Parameters to gdbm_store for simple insertion or replacement in the
+   case that the key is already in the database. */
+#define  GDBM_INSERT  0		/* Never replace old data with new. */
+#define  GDBM_REPLACE 1		/* Always replace old data with new. */
+
+/* Parameters to gdbm_setopt, specifing the type of operation to perform. */
+#define  GDBM_CACHESIZE 1       /* Set the cache size. */
+#define  GDBM_FASTMODE  2       /* Toggle fast mode. */
+
+/* The data and key structure.  This structure is defined for compatibility. */
+typedef struct {
+	char *dptr;
+	int   dsize;
+      } datum;
+
+
+/* The available file space is stored in an "avail" table.  The one with
+   most activity is contained in the file header. (See below.)  When that
+   one filles up, it is split in half and half is pushed on an "avail
+   stack."  When the active avail table is empty and the "avail stack" is
+   not empty, the top of the stack is popped into the active avail table. */
+
+/* The following structure is the element of the avaliable table.  */
+typedef struct {
+  	int   av_size;		/* The size of the available block. */
+	off_t  av_adr;		/* The file address of the available block. */
+      } avail_elem;
+
+/* This is the actual table. The in-memory images of the avail blocks are
+   allocated by malloc using a calculated size.  */
+typedef struct {
+	int   size;		/* The number of avail elements in the table.*/
+	int   count;		/* The number of entries in the table. */
+	off_t next_block;	/* The file address of the next avail block. */
+	avail_elem av_table[1]; /* The table.  Make it look like an array.  */
+      } avail_block;
+
+/* The dbm file header keeps track of the current location of the hash
+   directory and the free space in the file.  */
+
+typedef struct {
+	word_t header_magic;  /* 0x13579ace to make sure the header is good. */
+	int   block_size;    /* The  optimal i/o blocksize from stat. */
+	off_t dir;	     /* File address of hash directory table. */
+	int   dir_size;	     /* Size in bytes of the table.  */
+	int   dir_bits;	     /* The number of address bits used in the table.*/
+	int   bucket_size;   /* Size in bytes of a hash bucket struct. */
+	int   bucket_elems;  /* Number of elements in a hash bucket. */
+	off_t next_block;    /* The next unallocated block address. */
+	avail_block avail;   /* This must be last because of the psuedo
+				array in avail.  This avail grows to fill
+				the entire block. */
+      }  gdbm_file_header;
+
+
+/* The dbm hash bucket element contains the full 31 bit hash value, the
+   "pointer" to the key and data (stored together) with their sizes.  It also
+   has a small part of the actual key value.  It is used to verify the first
+   part of the key has the correct value without having to read the actual
+   key. */
+
+typedef struct {
+	word_t hash_value;	/* The complete 31 bit value. */
+	char  key_start[SMALL];	/* Up to the first SMALL bytes of the key.  */
+	off_t data_pointer;	/* The file address of the key record. The
+				   data record directly follows the key.  */
+	int   key_size;		/* Size of key data in the file. */
+	int   data_size;	/* Size of associated data in the file. */
+      } bucket_element;
+
+
+/* A bucket is a small hash table.  This one consists of a number of
+   bucket elements plus some bookkeeping fields.  The number of elements
+   depends on the optimum blocksize for the storage device and on a
+   parameter given at file creation time.  This bucket takes one block.
+   When one of these tables gets full, it is split into two hash buckets.
+   The contents are split between them by the use of the first few bits
+   of the 31 bit hash function.  The location in a bucket is the hash
+   value modulo the size of the bucket.  The in-memory images of the
+   buckets are allocated by malloc using a calculated size depending of
+   the file system buffer size.  To speed up write, each bucket will have
+   BUCKET_AVAIL avail elements with the bucket. */
+
+typedef struct {
+        int   av_count;		   /* The number of bucket_avail entries. */
+        avail_elem bucket_avail[BUCKET_AVAIL];  /* Distributed avail. */
+	int   bucket_bits;	   /* The number of bits used to get here. */
+	int   count;		   /* The number of element buckets full. */
+	bucket_element h_table[1]; /* The table.  Make it look like an array.*/
+      } hash_bucket;
+
+/* We want to keep from reading buckets as much as possible.  The following is
+   to implement a bucket cache.  When full, buckets will be dropped in a
+   least recently read from disk order.  */
+
+/* To speed up fetching and "sequential" access, we need to implement a
+   data cache for key/data pairs read from the file.  To find a key, we
+   must exactly match the key from the file.  To reduce overhead, the
+   data will be read at the same time.  Both key and data will be stored
+   in a data cache.  Each bucket cached will have a one element data
+   cache.  */
+
+typedef struct {
+        word_t hash_val;
+	int   data_size;
+	int   key_size;
+	char *dptr;
+	int   elem_loc;
+      }  data_cache_elem;
+
+typedef struct {
+        hash_bucket *   ca_bucket;
+	off_t           ca_adr;
+	char		ca_changed;   /* Data in the bucket changed. */
+	data_cache_elem ca_data;
+      } cache_elem;
+
+
+
+/* This final structure contains all main memory based information for
+   a gdbm file.  This allows multiple gdbm files to be opened at the same
+   time by one program. */
+
+typedef struct {
+	/* Global variables and pointers to dynamic variables used by gdbm.  */
+
+  	/* The file name. */
+	char *name;
+
+	/* The reader/writer status. */
+	int read_write;
+
+	/* Fast_write is set to 1 if no fsyncs are to be done. */
+	int fast_write;
+
+	/* The fatal error handling routine. */
+	void (*fatal_err) ();
+
+	/* The gdbm file descriptor which is set in gdbm_open.  */
+	int  desc;
+
+	/* The file header holds information about the database. */
+	gdbm_file_header *header;
+
+	/* The hash table directory from extendible hashing.  See Fagin et al, 
+	   ACM Trans on Database Systems, Vol 4, No 3. Sept 1979, 315-344 */
+	off_t *dir;
+
+	/* The bucket cache. */
+	cache_elem *bucket_cache;
+	int cache_size;
+	int last_read;
+
+	/* Points to the current hash bucket in the cache. */
+	hash_bucket *bucket;
+
+	/* The directory entry used to get the current hash bucket. */
+	word_t bucket_dir;
+
+	/* Pointer to the current bucket's cache entry. */
+	cache_elem *cache_entry;
+
+
+	/* Bookkeeping of things that need to be written back at the
+	   end of an update. */
+	char  header_changed;
+	char  directory_changed;
+	char  bucket_changed;
+	char  second_changed;
+	
+      } gdbm_file_info;
+
+/* The file information header. This is good enough for most applications. */
+#define GDBM_FILE gdbm_file_info *
+/* typedef struct {int dummy[10];} *GDBM_FILE;*/
+
+/* Determine if the C(++) compiler requires complete function prototype  */
+#if  __STDC__ || defined(__cplusplus) || defined(c_plusplus)
+#define GDBM_Proto(x) x
+#else
+#define GDBM_Proto(x) ()
+#endif /* NeedFunctionPrototypes */
+
+/* External variable, the gdbm build release string. */
+extern char *gdbm_version;	
+
+
+/* GDBM C++ support */
+#if defined(__cplusplus) || defined(c_plusplus)
+extern "C" {
+#endif
+
+/* These are the routines! */
+
+extern GDBM_FILE gdbm_open GDBM_Proto((
+     char *file,
+     int  block_size,
+     int  flags,
+     int  mode,
+     void (*fatal_func)(),
+	 int need_filelock
+));
+
+extern void gdbm_close GDBM_Proto((
+     GDBM_FILE dbf
+));
+
+extern int gdbm_store GDBM_Proto((
+     GDBM_FILE dbf,
+     datum key,
+     datum content,
+     int flags
+));
+
+extern datum gdbm_fetch GDBM_Proto((
+     GDBM_FILE dbf,
+     datum key
+));
+
+extern int gdbm_delete GDBM_Proto((
+     GDBM_FILE dbf,
+     datum key
+));
+
+extern datum gdbm_firstkey GDBM_Proto((
+     GDBM_FILE dbf
+));
+
+extern datum gdbm_nextkey GDBM_Proto((
+     GDBM_FILE dbf,
+     datum key
+));
+
+extern int gdbm_reorganize GDBM_Proto((
+     GDBM_FILE dbf
+));
+
+extern void gdbm_sync GDBM_Proto((
+     GDBM_FILE dbf
+));
+
+extern int gdbm_exists GDBM_Proto((
+     GDBM_FILE dbf,
+     datum key
+));
+
+extern int gdbm_setopt GDBM_Proto((
+     GDBM_FILE dbf,
+     int optflag,
+     int *optval,
+     int optlen
+));
+
+#if defined(__cplusplus) || defined(c_plusplus)
+}
+#endif
+
+/* gdbm sends back the following error codes in the variable gdbm_errno. */
+typedef enum {	GDBM_NO_ERROR,
+		GDBM_MALLOC_ERROR,
+		GDBM_BLOCK_SIZE_ERROR,
+		GDBM_FILE_OPEN_ERROR,
+		GDBM_FILE_WRITE_ERROR,
+		GDBM_FILE_SEEK_ERROR,
+		GDBM_FILE_READ_ERROR,
+		GDBM_BAD_MAGIC_NUMBER,
+		GDBM_EMPTY_DATABASE,
+		GDBM_CANT_BE_READER,
+	        GDBM_CANT_BE_WRITER,
+		GDBM_READER_CANT_DELETE,
+		GDBM_READER_CANT_STORE,
+		GDBM_READER_CANT_REORGANIZE,
+		GDBM_UNKNOWN_UPDATE,
+		GDBM_ITEM_NOT_FOUND,
+		GDBM_REORGANIZE_FAILED,
+		GDBM_CANNOT_REPLACE,
+		GDBM_ILLEGAL_DATA,
+		GDBM_OPT_ALREADY_SET,
+		GDBM_OPT_ILLEGAL}
+	gdbm_error;
+
+extern gdbm_error gdbm_errno;
+
+
+/* extra prototypes */
+
+/* GDBM C++ support */
+#if defined(__cplusplus) || defined(c_plusplus)
+extern "C" {
+#endif
+
+extern const char *gdbm_strerror GDBM_Proto((
+     gdbm_error error
+));
+
+#if defined(__cplusplus) || defined(c_plusplus)
+}
+#endif
+
+#endif
+
+
Index: /main/tags/2.25/gsdl/packages/wingdbm/gdbmclose.c
===================================================================
--- /main/tags/2.25/gsdl/packages/wingdbm/gdbmclose.c	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/wingdbm/gdbmclose.c	(revision 21064)
@@ -0,0 +1,73 @@
+/* gdbmclose.c - Close a previously opened dbm file. */
+
+/*  This file is part of GDBM, the GNU data base manager, by Philip A. Nelson.
+    Copyright (C) 1990, 1991, 1993  Free Software Foundation, Inc.
+
+    GDBM 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, or (at your option)
+    any later version.
+
+    GDBM 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 GDBM; see the file COPYING.  If not, write to
+    the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+
+    You may contact the author by:
+       e-mail:  phil@cs.wwu.edu
+      us-mail:  Philip A. Nelson
+                Computer Science Department
+                Western Washington University
+                Bellingham, WA 98226
+       
+*************************************************************************/
+
+
+/* AIX demands this be the very first thing in the file. */
+#if !defined(__GNUC__) && defined(_AIX)
+ #pragma alloca
+#endif
+
+/* include system configuration before all else. */
+#include "autoconf.h"
+
+#include "gdbmdefs.h"
+
+/* Close the dbm file and free all memory associated with the file DBF.
+   Before freeing members of DBF, check and make sure that they were
+   allocated.  */
+
+void
+gdbm_close (dbf)
+     gdbm_file_info *dbf;
+{
+  register int index;	/* For freeing the bucket cache. */
+
+  /* Make sure the database is all on disk. */
+  if (dbf->read_write == GDBM_WRITER)
+    fsync (dbf->desc);
+
+  /* Close the file and free all malloced memory. */
+  if (dbf->need_filelock) {
+	  UNLOCK_FILE(dbf);
+  }
+  close (dbf->desc);
+  free (dbf->name);
+  if (dbf->dir != NULL) free (dbf->dir);
+
+  if (dbf->bucket_cache != NULL) {
+    for (index = 0; index < dbf->cache_size; index++) {
+      if (dbf->bucket_cache[index].ca_bucket != NULL)
+	free (dbf->bucket_cache[index].ca_bucket);
+      if (dbf->bucket_cache[index].ca_data.dptr != NULL)
+	free (dbf->bucket_cache[index].ca_data.dptr);
+    }
+    free (dbf->bucket_cache);
+  }
+  if ( dbf->header != NULL ) free (dbf->header);
+  free (dbf);
+}
Index: /main/tags/2.25/gsdl/packages/wingdbm/gdbmconst.h
===================================================================
--- /main/tags/2.25/gsdl/packages/wingdbm/gdbmconst.h	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/wingdbm/gdbmconst.h	(revision 21064)
@@ -0,0 +1,60 @@
+/* gdbmconst.h - The constants defined for use in gdbm. */
+
+/*  This file is part of GDBM, the GNU data base manager, by Philip A. Nelson.
+    Copyright (C) 1990, 1991, 1993  Free Software Foundation, Inc.
+
+    GDBM 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, or (at your option)
+    any later version.
+
+    GDBM 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 GDBM; see the file COPYING.  If not, write to
+    the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+
+    You may contact the author by:
+       e-mail:  phil@cs.wwu.edu
+      us-mail:  Philip A. Nelson
+                Computer Science Department
+                Western Washington University
+                Bellingham, WA 98226
+       
+*************************************************************************/
+
+/* Start with the constant definitions.  */
+#define  TRUE    1
+#define  FALSE   0
+
+/* Parameters to gdbm_open. */
+#define  GDBM_READER  0		/* READERS only. */
+#define  GDBM_WRITER  1		/* READERS and WRITERS.  Can not create. */
+#define  GDBM_WRCREAT 2		/* If not found, create the db. */
+#define  GDBM_NEWDB   3		/* ALWAYS create a new db.  (WRITER) */
+#define  GDBM_FAST    16	/* Write fast! => No fsyncs. */
+
+/* Parameters to gdbm_store for simple insertion or replacement in the
+   case a key to store is already in the database. */
+#define  GDBM_INSERT  0		/* Do not overwrite data in the database. */
+#define  GDBM_REPLACE 1		/* Replace the old value with the new value. */
+
+/* Parameters to gdbm_setopt, specifing the type of operation to perform. */
+#define	 GDBM_CACHESIZE	1	/* Set the cache size. */
+#define  GDBM_FASTMODE	2	/* Turn on or off fast mode. */
+
+/* In freeing blocks, we will ignore any blocks smaller (and equal) to
+   IGNORE_SIZE number of bytes. */
+#define IGNORE_SIZE 4
+
+/* The number of key bytes kept in a hash bucket. */
+#define SMALL    4
+
+/* The number of bucket_avail entries in a hash bucket. */
+#define BUCKET_AVAIL 6
+
+/* The size of the bucket cache. */
+#define DEFAULT_CACHESIZE  100
Index: /main/tags/2.25/gsdl/packages/wingdbm/gdbmdefs.h
===================================================================
--- /main/tags/2.25/gsdl/packages/wingdbm/gdbmdefs.h	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/wingdbm/gdbmdefs.h	(revision 21064)
@@ -0,0 +1,200 @@
+/* gdbmdefs.h - The include file for dbm.  Defines structure and constants. */
+
+/*  This file is part of GDBM, the GNU data base manager, by Philip A. Nelson.
+    Copyright (C) 1990, 1991, 1993  Free Software Foundation, Inc.
+
+    GDBM 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, or (at your option)
+    any later version.
+
+    GDBM 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 GDBM; see the file COPYING.  If not, write to
+    the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+
+    You may contact the author by:
+       e-mail:  phil@cs.wwu.edu
+      us-mail:  Philip A. Nelson
+                Computer Science Department
+                Western Washington University
+                Bellingham, WA 98226
+*************************************************************************/
+
+#include "systems.h"
+#include "gdbmconst.h"
+
+/* The type definitions are next.  */
+
+/* The data and key structure.  This structure is defined for compatibility. */
+
+typedef struct {
+	char *dptr;
+	int   dsize;
+      } datum;
+
+
+/* The available file space is stored in an "avail" table.  The one with
+   most activity is contained in the file header. (See below.)  When that
+   one filles up, it is split in half and half is pushed on an "avail
+   stack."  When the active avail table is empty and the "avail stack" is
+   not empty, the top of the stack is popped into the active avail table. */
+
+/* The following structure is the element of the avaliable table.  */
+typedef struct {
+  	int   av_size;		/* The size of the available block. */
+	off_t  av_adr;		/* The file address of the available block. */
+      } avail_elem;
+
+/* This is the actual table. The in-memory images of the avail blocks are
+   allocated by malloc using a calculated size.  */
+typedef struct {
+	int   size;		/* The number of avail elements in the table.*/
+	int   count;		/* The number of entries in the table. */
+	off_t next_block;	/* The file address of the next avail block. */
+	avail_elem av_table[1]; /* The table.  Make it look like an array.  */
+      } avail_block;
+
+/* The dbm file header keeps track of the current location of the hash
+   directory and the free space in the file.  */
+
+typedef struct {
+	word_t header_magic;  /* 0x13579ace to make sure the header is good. */
+	int   block_size;    /* The  optimal i/o blocksize from stat. */
+	off_t dir;	     /* File address of hash directory table. */
+	int   dir_size;	     /* Size in bytes of the table.  */
+	int   dir_bits;	     /* The number of address bits used in the table.*/
+	int   bucket_size;   /* Size in bytes of a hash bucket struct. */
+	int   bucket_elems;  /* Number of elements in a hash bucket. */
+	off_t next_block;    /* The next unallocated block address. */
+	avail_block avail;   /* This must be last because of the psuedo
+				array in avail.  This avail grows to fill
+				the entire block. */
+      }  gdbm_file_header;
+
+
+/* The dbm hash bucket element contains the full 31 bit hash value, the
+   "pointer" to the key and data (stored together) with their sizes.  It also
+   has a small part of the actual key value.  It is used to verify the first
+   part of the key has the correct value without having to read the actual
+   key. */
+
+typedef struct {
+	word_t hash_value;	/* The complete 31 bit value. */
+	char  key_start[SMALL];	/* Up to the first SMALL bytes of the key.  */
+	off_t data_pointer;	/* The file address of the key record. The
+				   data record directly follows the key.  */
+	int   key_size;		/* Size of key data in the file. */
+	int   data_size;	/* Size of associated data in the file. */
+      } bucket_element;
+
+
+/* A bucket is a small hash table.  This one consists of a number of
+   bucket elements plus some bookkeeping fields.  The number of elements
+   depends on the optimum blocksize for the storage device and on a
+   parameter given at file creation time.  This bucket takes one block.
+   When one of these tables gets full, it is split into two hash buckets.
+   The contents are split between them by the use of the first few bits
+   of the 31 bit hash function.  The location in a bucket is the hash
+   value modulo the size of the bucket.  The in-memory images of the
+   buckets are allocated by malloc using a calculated size depending of
+   the file system buffer size.  To speed up write, each bucket will have
+   BUCKET_AVAIL avail elements with the bucket. */
+
+typedef struct {
+        int   av_count;		   /* The number of bucket_avail entries. */
+        avail_elem bucket_avail[BUCKET_AVAIL];  /* Distributed avail. */
+	int   bucket_bits;	   /* The number of bits used to get here. */
+	int   count;		   /* The number of element buckets full. */
+	bucket_element h_table[1]; /* The table.  Make it look like an array.*/
+      } hash_bucket;
+
+/* We want to keep from reading buckets as much as possible.  The following is
+   to implement a bucket cache.  When full, buckets will be dropped in a
+   least recently read from disk order.  */
+
+/* To speed up fetching and "sequential" access, we need to implement a
+   data cache for key/data pairs read from the file.  To find a key, we
+   must exactly match the key from the file.  To reduce overhead, the
+   data will be read at the same time.  Both key and data will be stored
+   in a data cache.  Each bucket cached will have a one element data
+   cache.  */
+
+typedef struct {
+        word_t hash_val;
+	int   data_size;
+	int   key_size;
+	char *dptr;
+	int   elem_loc;
+      }  data_cache_elem;
+
+typedef struct {
+        hash_bucket *   ca_bucket;
+	off_t           ca_adr;
+	char		ca_changed;   /* Data in the bucket changed. */
+	data_cache_elem ca_data;
+      } cache_elem;
+
+
+
+/* This final structure contains all main memory based information for
+   a gdbm file.  This allows multiple gdbm files to be opened at the same
+   time by one program. */
+
+typedef struct {
+	/* Global variables and pointers to dynamic variables used by gdbm.  */
+
+  	/* The file name. */
+	char *name;
+
+	/* The reader/writer status. */
+	int read_write;
+
+	/* Fast_write is set to 1 if no fsyncs are to be done. */
+	int fast_write;
+
+	/* The fatal error handling routine. */
+	void (*fatal_err) ();
+
+    int need_filelock;
+
+	/* The gdbm file descriptor which is set in gdbm_open.  */
+	int  desc;
+
+	/* The file header holds information about the database. */
+	gdbm_file_header *header;
+
+	/* The hash table directory from extendible hashing.  See Fagin et al, 
+	   ACM Trans on Database Systems, Vol 4, No 3. Sept 1979, 315-344 */
+	off_t *dir;
+
+	/* The bucket cache. */
+	cache_elem *bucket_cache;
+	int cache_size;
+	int last_read;
+
+	/* Points to the current hash bucket in the cache. */
+	hash_bucket *bucket;
+
+	/* The directory entry used to get the current hash bucket. */
+	word_t bucket_dir;
+
+	/* Pointer to the current bucket's cache entry. */
+	cache_elem *cache_entry;
+
+
+	/* Bookkeeping of things that need to be written back at the
+	   end of an update. */
+	char  header_changed;
+	char  directory_changed;
+	char  bucket_changed;
+	char  second_changed;
+	
+      } gdbm_file_info;
+
+/* Now define all the routines in use. */
+#include "proto.h"
Index: /main/tags/2.25/gsdl/packages/wingdbm/gdbmdelete.c
===================================================================
--- /main/tags/2.25/gsdl/packages/wingdbm/gdbmdelete.c	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/wingdbm/gdbmdelete.c	(revision 21064)
@@ -0,0 +1,119 @@
+/* gdbmdelete.c - Remove the key and its associated data from the database. */
+
+/*  This file is part of GDBM, the GNU data base manager, by Philip A. Nelson.
+    Copyright (C) 1990, 1991, 1993  Free Software Foundation, Inc.
+
+    GDBM 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, or (at your option)
+    any later version.
+
+    GDBM 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 GDBM; see the file COPYING.  If not, write to
+    the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+
+    You may contact the author by:
+       e-mail:  phil@cs.wwu.edu
+      us-mail:  Philip A. Nelson
+                Computer Science Department
+                Western Washington University
+                Bellingham, WA 98226
+       
+*************************************************************************/
+
+
+/* include system configuration before all else. */
+#include "autoconf.h"
+
+#include "gdbmdefs.h"
+#include "gdbmerrno.h"
+
+/* Remove the KEYed item and the KEY from the database DBF.  The file on disk
+   is updated to reflect the structure of the new database before returning
+   from this procedure.  */
+
+int
+gdbm_delete (dbf, key)
+     gdbm_file_info *dbf;
+     datum key;
+{
+  int elem_loc;		/* The location in the current hash bucket. */
+  int last_loc;		/* Last location emptied by the delete.  */
+  int home;		/* Home position of an item. */
+  bucket_element elem;  /* The element to be deleted. */
+  char *find_data;	/* Return pointer from findkey. */
+  word_t hash_val;	/* Returned by findkey. */
+  off_t free_adr;       /* Temporary stroage for address and size. */
+  int   free_size;
+
+  /* First check to make sure this guy is a writer. */
+  if (dbf->read_write != GDBM_WRITER)
+    {
+      gdbm_errno = GDBM_READER_CANT_DELETE;
+      return -1;
+    }
+
+  /* Initialize the gdbm_errno variable. */
+  gdbm_errno = GDBM_NO_ERROR;
+
+  /* Find the item. */
+  elem_loc = _gdbm_findkey (dbf, key, &find_data, &hash_val);
+  if (elem_loc == -1)
+    {
+      gdbm_errno = GDBM_ITEM_NOT_FOUND;
+      return -1;
+    }
+
+  /* Save the element.  */
+  elem = dbf->bucket->h_table[elem_loc];
+
+  /* Delete the element.  */
+  dbf->bucket->h_table[elem_loc].hash_value = -1;
+  dbf->bucket->count -= 1;
+
+  /* Move other elements to guarantee that they can be found. */
+  last_loc = elem_loc;
+  elem_loc = (elem_loc + 1) % dbf->header->bucket_elems;
+  while (elem_loc != last_loc
+	 && dbf->bucket->h_table[elem_loc].hash_value != -1)
+    {
+      home = dbf->bucket->h_table[elem_loc].hash_value
+	     % dbf->header->bucket_elems;
+      if ( (last_loc < elem_loc && (home <= last_loc || home > elem_loc))
+	  || (last_loc > elem_loc && home <= last_loc && home > elem_loc))
+	
+	{
+	  dbf->bucket->h_table[last_loc] = dbf->bucket->h_table[elem_loc];
+	  dbf->bucket->h_table[elem_loc].hash_value = -1;
+	  last_loc = elem_loc;
+	}
+      elem_loc = (elem_loc + 1) % dbf->header->bucket_elems;
+    }
+
+  /* Free the file space. */
+  free_adr = elem.data_pointer;
+  free_size = elem.key_size + elem.data_size;
+  _gdbm_free (dbf, free_adr, free_size);
+
+  /* Set the flags. */
+  dbf->bucket_changed = TRUE;
+
+  /* Clear out the data cache for the current bucket. */
+  if (dbf->cache_entry->ca_data.dptr != NULL)
+    {
+      free (dbf->cache_entry->ca_data.dptr);
+      dbf->cache_entry->ca_data.dptr = NULL;
+    }
+  dbf->cache_entry->ca_data.hash_val = -1;
+  dbf->cache_entry->ca_data.key_size = 0;
+  dbf->cache_entry->ca_data.elem_loc = -1;
+
+  /* Do the writes. */
+  _gdbm_end_update (dbf);
+  return 0;  
+}
Index: /main/tags/2.25/gsdl/packages/wingdbm/gdbmerrno.c
===================================================================
--- /main/tags/2.25/gsdl/packages/wingdbm/gdbmerrno.c	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/wingdbm/gdbmerrno.c	(revision 21064)
@@ -0,0 +1,62 @@
+/* gdbmerrno.c - convert gdbm errors into english. */
+
+/*  This file is part of GDBM, the GNU data base manager, by Philip A. Nelson.
+    Copyright (C) 1993  Free Software Foundation, Inc.
+
+    GDBM 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, or (at your option)
+    any later version.
+
+    GDBM 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 GDBM; see the file COPYING.  If not, write to
+    the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+
+    You may contact the original author by:
+       e-mail:  phil@cs.wwu.edu
+      us-mail:  Philip A. Nelson
+                Computer Science Department
+                Western Washington University
+                Bellingham, WA 98226
+       
+    The author of this file is:
+       e-mail:  downsj@csos.orst.edu
+
+*************************************************************************/
+
+
+/* include system configuration before all else. */
+#include "autoconf.h"
+
+#include "gdbmerrno.h"
+
+/* this is not static so that applications may access the array if they
+   like. it must be in the same order as the error codes! */
+
+const char * const gdbm_errlist[] = {
+  "No error", "Malloc error", "Block size error", "File open error",
+  "File write error", "File seek error", "File read error",
+  "Bad magic number", "Empty database", "Can't be reader", "Can't be writer",
+  "Reader can't delete", "Reader can't store", "Reader can't reorganize",
+  "Unknown update", "Item not found", "Reorganize failed", "Cannot replace",
+  "Illegal data", "Option already set", "Illegal option"
+};
+
+const char *
+gdbm_strerror(error)
+    gdbm_error error;
+{
+  if(((int)error < 0) || ((int)error > 18))
+    {
+      return("Unkown error");
+    }
+  else
+    {
+      return(gdbm_errlist[(int)error]);
+    }
+}
Index: /main/tags/2.25/gsdl/packages/wingdbm/gdbmerrno.h
===================================================================
--- /main/tags/2.25/gsdl/packages/wingdbm/gdbmerrno.h	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/wingdbm/gdbmerrno.h	(revision 21064)
@@ -0,0 +1,54 @@
+/* gdbmerrno.h - The enumeration type describing all the dbm errors. */
+
+/*  This file is part of GDBM, the GNU data base manager, by Philip A. Nelson.
+    Copyright (C) 1990, 1991, 1993  Free Software Foundation, Inc.
+
+    GDBM 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, or (at your option)
+    any later version.
+
+    GDBM 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 GDBM; see the file COPYING.  If not, write to
+    the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+
+    You may contact the author by:
+       e-mail:  phil@wwu.edu
+      us-mail:  Philip A. Nelson
+                Computer Science Department
+                Western Washington University
+                Bellingham, WA 98226
+       
+*************************************************************************/
+
+
+/* gdbm sends back the following error codes in the variable gdbm_errno. */
+typedef enum {	GDBM_NO_ERROR,
+		GDBM_MALLOC_ERROR,
+		GDBM_BLOCK_SIZE_ERROR,
+		GDBM_FILE_OPEN_ERROR,
+		GDBM_FILE_WRITE_ERROR,
+		GDBM_FILE_SEEK_ERROR,
+		GDBM_FILE_READ_ERROR,
+		GDBM_BAD_MAGIC_NUMBER,
+		GDBM_EMPTY_DATABASE,
+		GDBM_CANT_BE_READER,
+	        GDBM_CANT_BE_WRITER,
+		GDBM_READER_CANT_DELETE,
+		GDBM_READER_CANT_STORE,
+		GDBM_READER_CANT_REORGANIZE,
+		GDBM_UNKNOWN_UPDATE,
+		GDBM_ITEM_NOT_FOUND,
+		GDBM_REORGANIZE_FAILED,
+		GDBM_CANNOT_REPLACE,
+		GDBM_ILLEGAL_DATA,
+		GDBM_OPT_ALREADY_SET,
+		GDBM_OPT_ILLEGAL}
+	gdbm_error;
+
+extern gdbm_error gdbm_errno;
Index: /main/tags/2.25/gsdl/packages/wingdbm/gdbmexists.c
===================================================================
--- /main/tags/2.25/gsdl/packages/wingdbm/gdbmexists.c	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/wingdbm/gdbmexists.c	(revision 21064)
@@ -0,0 +1,51 @@
+/* gdbmexists.c - Check to see if a key exists */
+
+/*  This file is part of GDBM, the GNU data base manager, by Philip A. Nelson.
+    Copyright (C) 1993  Free Software Foundation, Inc.
+
+    GDBM 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 1, or (at your option)
+    any later version.
+
+    GDBM 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 GDBM; see the file COPYING.  If not, write to
+    the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+
+    You may contact the original author by:
+       e-mail:  phil@cs.wwu.edu
+      us-mail:  Philip A. Nelson
+                Computer Science Department
+                Western Washington University
+                Bellingham, WA 98226
+       
+    The author of this file is:
+       e-mail:  downsj@csos.orst.edu
+
+*************************************************************************/
+
+
+/* include system configuration before all else. */
+#include "autoconf.h"
+
+#include "gdbmdefs.h"
+#include "gdbmerrno.h"
+
+/* this is nothing more than a wrapper around _gdbm_findkey(). the
+   point? it doesn't alloate any memory. */
+
+int
+gdbm_exists (dbf, key)
+    gdbm_file_info *dbf;
+    datum key;
+{
+char *find_data;		/* dummy */
+word_t hash_val;		/* dummy */
+
+  return (_gdbm_findkey (dbf, key, &find_data, &hash_val) >= 0);
+}
Index: /main/tags/2.25/gsdl/packages/wingdbm/gdbmfetch.c
===================================================================
--- /main/tags/2.25/gsdl/packages/wingdbm/gdbmfetch.c	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/wingdbm/gdbmfetch.c	(revision 21064)
@@ -0,0 +1,81 @@
+/* gdbmfetch.c - Find a key and return the associated data.  */
+
+/*  This file is part of GDBM, the GNU data base manager, by Philip A. Nelson.
+    Copyright (C) 1990, 1991, 1993  Free Software Foundation, Inc.
+
+    GDBM 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, or (at your option)
+    any later version.
+
+    GDBM 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 GDBM; see the file COPYING.  If not, write to
+    the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+
+    You may contact the author by:
+       e-mail:  phil@cs.wwu.edu
+      us-mail:  Philip A. Nelson
+                Computer Science Department
+                Western Washington University
+                Bellingham, WA 98226
+       
+*************************************************************************/
+
+
+/* AIX demands this be the very first thing in the file. */
+#if !defined(__GNUC__) && defined(_AIX)
+ #pragma alloca
+#endif
+
+/* include system configuration before all else. */
+#include "autoconf.h"
+
+#include "gdbmdefs.h"
+#include "gdbmerrno.h"
+
+/* Look up a given KEY and return the information associated with that KEY.
+   The pointer in the structure that is  returned is a pointer to dynamically
+   allocated memory block.  */
+
+datum
+gdbm_fetch (dbf, key)
+     gdbm_file_info *dbf;
+     datum key;
+{
+  datum  return_val;		/* The return value. */
+  int    elem_loc;		/* The location in the bucket. */
+  char  *find_data;		/* Returned from find_key. */
+  word_t   hash_val;		/* Returned from find_key. */
+
+  /* Set the default return value. */
+  return_val.dptr  = NULL;
+  return_val.dsize = 0;
+
+  /* Initialize the gdbm_errno variable. */
+  gdbm_errno = GDBM_NO_ERROR;
+
+  /* Find the key and return a pointer to the data. */
+  elem_loc = _gdbm_findkey (dbf, key, &find_data, &hash_val);
+
+  /* Copy the data if the key was found.  */
+  if (elem_loc >= 0)
+    {
+      /* This is the item.  Return the associated data. */
+      return_val.dsize = dbf->bucket->h_table[elem_loc].data_size;
+      if (return_val.dsize == 0)
+	return_val.dptr = (char *) malloc (1);
+      else
+	return_val.dptr = (char *) malloc (return_val.dsize);
+      if (return_val.dptr == NULL) _gdbm_fatal (dbf, "malloc error");
+      bcopy (find_data, return_val.dptr, return_val.dsize);
+    }
+
+  /* Check for an error and return. */
+  if (return_val.dptr == NULL) gdbm_errno = GDBM_ITEM_NOT_FOUND;
+  return return_val;
+}
Index: /main/tags/2.25/gsdl/packages/wingdbm/gdbmopen.c
===================================================================
--- /main/tags/2.25/gsdl/packages/wingdbm/gdbmopen.c	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/wingdbm/gdbmopen.c	(revision 21064)
@@ -0,0 +1,453 @@
+/* gdbmopen.c - Open the dbm file and initialize data structures for use. */
+
+/*  This file is part of GDBM, the GNU data base manager, by Philip A. Nelson.
+    Copyright (C) 1990, 1991, 1993  Free Software Foundation, Inc.
+
+    GDBM 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, or (at your option)
+    any later version.
+
+    GDBM 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 GDBM; see the file COPYING.  If not, write to
+    the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+
+    You may contact the author by:
+       e-mail:  phil@cs.wwu.edu
+      us-mail:  Philip A. Nelson
+                Computer Science Department
+                Western Washington University
+                Bellingham, WA 98226
+       
+*************************************************************************/
+
+
+/* AIX demands this be the very first thing in the file. */
+#if !defined(__GNUC__) && defined(_AIX)
+ #pragma alloca
+#endif
+
+/* include system configuration before all else. */
+#include "autoconf.h"
+
+#include "gdbmdefs.h"
+#include "gdbmerrno.h"
+
+/* Initialize dbm system.  FILE is a pointer to the file name.  If the file
+   has a size of zero bytes, a file initialization procedure is performed,
+   setting up the initial structure in the file.  BLOCK_SIZE is used during
+   initialization to determine the size of various constructs.  If the value
+   is less than 512, the file system blocksize is used, otherwise the value
+   of BLOCK_SIZE is used.  BLOCK_SIZE is ignored if the file has previously
+   initialized.  If FLAGS is set to GDBM_READ the user wants to just
+   read the database and any call to dbm_store or dbm_delete will fail. Many
+   readers can access the database at the same time.  If FLAGS is set to
+   GDBM_WRITE, the user wants both read and write access to the database and
+   requires exclusive access.  If FLAGS is GDBM_WRCREAT, the user wants
+   both read and write access to the database and if the database does not
+   exist, create a new one.  If FLAGS is GDBM_NEWDB, the user want a
+   new database created, regardless of whether one existed, and wants read
+   and write access to the new database.  Any error detected will cause a 
+   return value of null and an approprate value will be in gdbm_errno.  If
+   no errors occur, a pointer to the "gdbm file descriptor" will be
+   returned. */
+   
+
+gdbm_file_info *
+gdbm_open (file, block_size, flags, mode, fatal_func, need_filelock)
+     char *file;
+     int  block_size;
+     int  flags;
+     int  mode;
+     void (*fatal_func) ();
+	 int need_filelock;
+{
+  gdbm_file_info *dbf;		/* The record to return. */
+  struct stat file_stat;	/* Space for the stat information. */
+  int         len;		/* Length of the file name. */
+  int         num_bytes;	/* Used in reading and writing. */
+  off_t       file_pos;		/* Used with seeks. */
+  int	      lock_val;         /* Returned by the flock call. */
+  int	      file_block_size;	/* Block size to use for a new file. */
+  int 	      index;		/* Used as a loop index. */
+  char        need_trunc;	/* Used with GDBM_NEWDB and locking to avoid
+				   truncating a file from under a reader. */
+
+  /* Initialize the gdbm_errno variable. */
+  gdbm_errno = GDBM_NO_ERROR;
+
+  /* Allocate new info structure. */
+  dbf = (gdbm_file_info *) malloc (sizeof (gdbm_file_info));
+  if (dbf == NULL)
+    {
+      gdbm_errno = GDBM_MALLOC_ERROR;
+      return NULL;
+    }
+
+  /* Initialize some fields for known values.  This is done so gdbm_close
+     will work if called before allocating some structures. */
+  dbf->need_filelock = need_filelock;
+  dbf->dir  = NULL;
+  dbf->bucket = NULL;
+  dbf->header = NULL;
+  dbf->bucket_cache = NULL;
+  dbf->cache_size = 0;
+  
+  /* Save name of file. */
+  len = strlen (file);
+  dbf->name = (char *) malloc (len + 1);
+  if (dbf->name == NULL)
+    {
+      free (dbf);
+      gdbm_errno = GDBM_MALLOC_ERROR;
+      return NULL;
+    }
+  strcpy (dbf->name, file);
+
+  /* Initialize the fatal error routine. */
+  dbf->fatal_err = fatal_func;
+
+  /* Check for fast writers. */
+  if (flags & GDBM_FAST)
+    {
+      dbf->fast_write = TRUE;
+      flags -= GDBM_FAST;
+    }
+  else
+    {
+      dbf->fast_write = FALSE;
+    }
+  
+  /* Open the file. */
+  need_trunc = FALSE;
+  if (flags == GDBM_READER)
+    {
+      dbf->desc = open (dbf->name, O_RDONLY|O_BINARY, 0);
+    }
+  else if (flags == GDBM_WRITER)
+    {
+      dbf->desc = open (dbf->name, O_RDWR|O_BINARY, 0);
+    }
+  else if (flags == GDBM_NEWDB)
+    {
+      dbf->desc = open (dbf->name, O_RDWR|O_CREAT|O_BINARY, mode);
+      flags = GDBM_WRITER;
+      need_trunc = TRUE;
+    }
+  else
+    {
+      dbf->desc = open (dbf->name, O_RDWR|O_CREAT|O_BINARY, mode);
+      flags = GDBM_WRITER;
+    }
+  if (dbf->desc < 0)
+    {
+      free (dbf->name);
+      free (dbf);
+      gdbm_errno = GDBM_FILE_OPEN_ERROR;
+      return NULL;
+    }
+
+  /* Get the status of the file. */
+  fstat (dbf->desc, &file_stat);
+
+  /* Lock the file in the approprate way. */
+  if (flags == GDBM_READER)
+    {
+      if (file_stat.st_size == 0)
+	{
+	  close (dbf->desc);
+	  free (dbf->name);
+	  free (dbf);
+	  gdbm_errno = GDBM_EMPTY_DATABASE;
+	  return NULL;
+	}
+      /* Sets lock_val to 0 for success.  See systems.h. */
+	  if (dbf->need_filelock) {
+	      READLOCK_FILE(dbf);
+	  } else {
+		  lock_val = 0;
+	  }
+    }
+  else
+    {
+      /* Sets lock_val to 0 for success.  See systems.h. */
+	  if (dbf->need_filelock) {
+		WRITELOCK_FILE(dbf);
+	  } else {
+		  lock_val = 0;
+	  }
+    }
+  if (lock_val != 0)
+    {
+      close (dbf->desc);
+      free (dbf->name);
+      free (dbf);
+      if (flags == GDBM_READER)
+	gdbm_errno = GDBM_CANT_BE_READER;
+      else
+	gdbm_errno = GDBM_CANT_BE_WRITER;
+      return NULL;
+    }
+
+  /* Record the kind of user. */
+  dbf->read_write = flags;
+
+  /* If we do have a write lock and it was a GDBM_NEWDB, it is 
+     now time to truncate the file. */
+  if (need_trunc && file_stat.st_size != 0)
+    {
+      TRUNCATE (dbf);
+      fstat (dbf->desc, &file_stat);
+    }
+
+  /* Decide if this is a new file or an old file. */
+  if (file_stat.st_size == 0)
+    {
+
+      /* This is a new file.  Create an empty database.  */
+
+      /* Start with the blocksize. */
+      if (block_size < 512)
+	file_block_size = STATBLKSIZE;
+      else
+	file_block_size = block_size;
+
+      /* Get space for the file header. */
+      dbf->header = (gdbm_file_header *) malloc (file_block_size);
+      if (dbf->header == NULL)
+	{
+	  gdbm_close (dbf);
+	  gdbm_errno = GDBM_MALLOC_ERROR;
+	  return NULL;
+	}
+
+      /* Set the magic number and the block_size. */
+      dbf->header->header_magic = 0x13579ace;
+      dbf->header->block_size = file_block_size;
+     
+      /* Create the initial hash table directory.  */
+      dbf->header->dir_size = 8 * sizeof (off_t);
+      dbf->header->dir_bits = 3;
+      while (dbf->header->dir_size < dbf->header->block_size)
+	{
+	  dbf->header->dir_size <<= 1;
+	  dbf->header->dir_bits += 1;
+	}
+
+      /* Check for correct block_size. */
+      if (dbf->header->dir_size != dbf->header->block_size)
+	{
+	  gdbm_close (dbf);
+	  gdbm_errno = GDBM_BLOCK_SIZE_ERROR;
+	  return NULL;
+	}
+
+      /* Allocate the space for the directory. */
+      dbf->dir = (off_t *) malloc (dbf->header->dir_size);
+      if (dbf->dir == NULL)
+	{
+	  gdbm_close (dbf);
+	  gdbm_errno = GDBM_MALLOC_ERROR;
+	  return NULL;
+	}
+      dbf->header->dir = dbf->header->block_size;
+
+      /* Create the first and only hash bucket. */
+      dbf->header->bucket_elems =
+	(dbf->header->block_size - sizeof (hash_bucket))
+	/ sizeof (bucket_element) + 1;
+      dbf->header->bucket_size  = dbf->header->block_size;
+#if !defined(sgi)
+      dbf->bucket = (hash_bucket *) (alloca (dbf->header->bucket_size));
+#else	/* sgi */
+      /* The SGI C compiler doesn't accept the previous form. */
+      {
+        hash_bucket *ptr;
+	ptr = (hash_bucket *) (alloca (dbf->header->bucket_size));
+	dbf->bucket = ptr;
+      }
+#endif	/* sgi */
+      if (dbf->bucket == NULL)
+	{
+	  gdbm_close (dbf);
+	  gdbm_errno = GDBM_MALLOC_ERROR;
+	  return NULL;
+	}
+      _gdbm_new_bucket (dbf, dbf->bucket, 0);
+      dbf->bucket->av_count = 1;
+      dbf->bucket->bucket_avail[0].av_adr = 3*dbf->header->block_size;
+      dbf->bucket->bucket_avail[0].av_size = dbf->header->block_size;
+
+      /* Set table entries to point to hash buckets. */
+      for (index = 0; index < dbf->header->dir_size / sizeof (off_t); index++)
+	dbf->dir[index] = 2*dbf->header->block_size;
+
+      /* Initialize the active avail block. */
+      dbf->header->avail.size
+	= ( (dbf->header->block_size - sizeof (gdbm_file_header))
+	 / sizeof (avail_elem)) + 1;
+      dbf->header->avail.count = 0;
+      dbf->header->avail.next_block = 0;
+      dbf->header->next_block  = 4*dbf->header->block_size;
+
+      /* Write initial configuration to the file. */
+      /* Block 0 is the file header and active avail block. */
+      num_bytes = write (dbf->desc, dbf->header, dbf->header->block_size);
+      if (num_bytes != dbf->header->block_size)
+	{
+	  gdbm_close (dbf);
+	  gdbm_errno = GDBM_FILE_WRITE_ERROR;
+	  return NULL;
+	}
+
+      /* Block 1 is the initial bucket directory. */
+      num_bytes = write (dbf->desc, dbf->dir, dbf->header->dir_size);
+      if (num_bytes != dbf->header->dir_size)
+	{
+	  gdbm_close (dbf);
+	  gdbm_errno = GDBM_FILE_WRITE_ERROR;
+	  return NULL;
+	}
+
+      /* Block 2 is the only bucket. */
+      num_bytes = write (dbf->desc, dbf->bucket, dbf->header->bucket_size);
+      if (num_bytes != dbf->header->bucket_size)
+	{
+	  gdbm_close (dbf);
+	  gdbm_errno = GDBM_FILE_WRITE_ERROR;
+	  return NULL;
+	}
+
+      /* Wait for initial configuration to be written to disk. */
+      fsync (dbf->desc);
+
+    }
+  else
+    {
+      /* This is an old database.  Read in the information from the file
+	 header and initialize the hash directory. */
+
+      gdbm_file_header partial_header;  /* For the first part of it. */
+
+      /* Read the partial file header. */
+      num_bytes = read (dbf->desc, &partial_header, sizeof (gdbm_file_header));
+      if (num_bytes != sizeof (gdbm_file_header))
+	{
+	  gdbm_close (dbf);
+	  gdbm_errno = GDBM_FILE_READ_ERROR;
+	  return NULL;
+	}
+
+      /* Is the magic number good? */
+      if (partial_header.header_magic != 0x13579ace)
+	{
+	  gdbm_close (dbf);
+	  gdbm_errno = GDBM_BAD_MAGIC_NUMBER;
+	  return NULL;
+	}
+
+      /* It is a good database, read the entire header. */
+      dbf->header = (gdbm_file_header *) malloc (partial_header.block_size);
+      if (dbf->header == NULL)
+	{
+	  gdbm_close (dbf);
+	  gdbm_errno = GDBM_MALLOC_ERROR;
+	  return NULL;
+	}
+      bcopy (&partial_header, dbf->header, sizeof (gdbm_file_header));
+      num_bytes = read (dbf->desc, &dbf->header->avail.av_table[1],
+			dbf->header->block_size-sizeof (gdbm_file_header));
+      if (num_bytes != dbf->header->block_size-sizeof (gdbm_file_header))
+	{
+	  gdbm_close (dbf);
+	  gdbm_errno = GDBM_FILE_READ_ERROR;
+	  return NULL;
+	}
+	
+      /* Allocate space for the hash table directory.  */
+      dbf->dir = (off_t *) malloc (dbf->header->dir_size);
+      if (dbf->dir == NULL)
+	{
+	  gdbm_close (dbf);
+	  gdbm_errno = GDBM_MALLOC_ERROR;
+	  return NULL;
+	}
+
+      /* Read the hash table directory. */
+      file_pos = lseek (dbf->desc, dbf->header->dir, L_SET);
+      if (file_pos != dbf->header->dir)
+	{
+	  gdbm_close (dbf);
+	  gdbm_errno = GDBM_FILE_SEEK_ERROR;
+	  return NULL;
+	}
+
+      num_bytes = read (dbf->desc, dbf->dir, dbf->header->dir_size);
+      if (num_bytes != dbf->header->dir_size)
+	{
+	  gdbm_close (dbf);
+	  gdbm_errno = GDBM_FILE_READ_ERROR;
+	  return NULL;
+	}
+
+    }
+      
+  /* Finish initializing dbf. */
+  dbf->last_read = -1;
+  dbf->bucket = NULL;
+  dbf->bucket_dir = 0;
+  dbf->cache_entry = NULL;
+  dbf->header_changed = FALSE;
+  dbf->directory_changed = FALSE;
+  dbf->bucket_changed = FALSE;
+  dbf->second_changed = FALSE;
+  
+  /* Everything is fine, return the pointer to the file
+     information structure.  */
+  return dbf;
+
+}
+
+/* initialize the bucket cache. */
+int
+_gdbm_init_cache(dbf, size)
+    gdbm_file_info *dbf;
+    int size;
+{
+register int index;
+
+  if (dbf->bucket_cache == NULL)
+    {
+      dbf->bucket_cache = (cache_elem *) malloc(sizeof(cache_elem) * size);
+      if(dbf->bucket_cache == NULL)
+        {
+          gdbm_errno = GDBM_MALLOC_ERROR;
+          return(-1);
+        }
+      dbf->cache_size = size;
+
+      for(index = 0; index < size; index++)
+        {
+          (dbf->bucket_cache[index]).ca_bucket
+            = (hash_bucket *) malloc (dbf->header->bucket_size);
+          if ((dbf->bucket_cache[index]).ca_bucket == NULL)
+	    {
+              gdbm_errno = GDBM_MALLOC_ERROR;
+	      return(-1);
+            }
+          (dbf->bucket_cache[index]).ca_adr = 0;
+          (dbf->bucket_cache[index]).ca_changed = FALSE;
+          (dbf->bucket_cache[index]).ca_data.hash_val = -1;
+          (dbf->bucket_cache[index]).ca_data.elem_loc = -1;
+          (dbf->bucket_cache[index]).ca_data.dptr = NULL;
+        }
+      dbf->bucket = dbf->bucket_cache[0].ca_bucket;
+      dbf->cache_entry = &dbf->bucket_cache[0];
+    }
+  return(0);
+}
Index: /main/tags/2.25/gsdl/packages/wingdbm/gdbmreorg.c
===================================================================
--- /main/tags/2.25/gsdl/packages/wingdbm/gdbmreorg.c	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/wingdbm/gdbmreorg.c	(revision 21064)
@@ -0,0 +1,224 @@
+/* gdbmreorg.c - Reorganize the database file. */
+
+/*  This file is part of GDBM, the GNU data base manager, by Philip A. Nelson.
+    Copyright (C) 1990, 1991, 1993  Free Software Foundation, Inc.
+
+    GDBM 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, or (at your option)
+    any later version.
+
+    GDBM 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 GDBM; see the file COPYING.  If not, write to
+    the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+
+    You may contact the author by:
+       e-mail:  phil@cs.wwu.edu
+      us-mail:  Philip A. Nelson
+                Computer Science Department
+                Western Washington University
+                Bellingham, WA 98226
+       
+************************************************************************/
+
+
+/* AIX demands this be the very first thing in the file. */
+#if !defined(__GNUC__) && defined(_AIX)
+ #pragma alloca
+#endif
+
+/* include system configuration before all else. */
+#include "autoconf.h"
+
+#include "gdbmdefs.h"
+#include "gdbmerrno.h"
+#include "extern.h"
+
+#if !HAVE_RENAME
+
+/* Rename takes OLD_NAME and renames it as NEW_NAME.  If it can not rename
+   the file a non-zero value is returned.  OLD_NAME is guaranteed to
+   remain if it can't be renamed. It assumes NEW_NAME always exists (due
+   to being used in gdbm). */
+
+static int
+rename (old_name, new_name)
+     char* old_name;
+     char* new_name;
+{
+  if (unlink (new_name) != 0)   
+    return -1;
+
+  if (link (old_name, new_name) != 0)
+    return -1;
+  
+  unlink (old_name);
+  return 0;
+
+}
+#endif
+
+
+
+/* Reorganize the database.  This requires creating a new file and inserting
+   all the elements in the old file DBF into the new file.  The new file
+   is then renamed to the same name as the old file and DBF is updated to
+   contain all the correct information about the new file.  If an error
+   is detected, the return value is negative.  The value zero is returned
+   after a successful reorganization. */
+
+int
+gdbm_reorganize (dbf)
+     gdbm_file_info *dbf;
+
+{
+  gdbm_file_info *new_dbf;		/* The new file. */
+  char *new_name;			/* A temporary name. */
+  int  len;				/* Used in new_name construction. */
+  datum key, nextkey, data;		/* For the sequential sweep. */
+  struct stat fileinfo;			/* Information about the file. */
+  int  index;				/* Use in moving the bucket cache. */
+
+
+  /* Readers can not reorganize! */
+  if (dbf->read_write == GDBM_READER)
+    {
+      gdbm_errno = GDBM_READER_CANT_REORGANIZE;
+      return -1;
+    }
+  
+  /* Initialize the gdbm_errno variable. */
+  gdbm_errno = GDBM_NO_ERROR;
+
+  /* Construct new name for temporary file. */
+  len = strlen (dbf->name);
+  new_name = (char *) alloca (len + 3);
+  if (new_name == NULL)
+    {
+      gdbm_errno = GDBM_MALLOC_ERROR;
+      return -1;
+    }
+  strcpy (&new_name[0], dbf->name);
+  new_name[len+2] = 0;
+  new_name[len+1] = '#';
+  while ( (len > 0) && new_name[len-1] != '/')
+    {
+      new_name[len] = new_name[len-1];
+      len -= 1;
+    }
+  new_name[len] = '#';
+
+  /* Get the mode for the old file and open the new database.
+     The "fast" mode is used because the reorganization will fail
+     unless we create a complete copy of the database. */
+  fstat (dbf->desc, &fileinfo);
+  new_dbf = gdbm_open (new_name, dbf->header->block_size,
+		       GDBM_WRCREAT | GDBM_FAST,
+		       fileinfo.st_mode, dbf->fatal_err);
+
+  if (new_dbf == NULL)
+    {
+      gdbm_errno = GDBM_REORGANIZE_FAILED;
+      return -1;
+    }
+
+  
+  /* For each item in the old database, add an entry in the new. */
+  key = gdbm_firstkey (dbf);
+
+  while (key.dptr != NULL)
+    {
+      data = gdbm_fetch (dbf, key);
+      if (data.dptr != NULL)
+ 	{
+	  /* Add the data to the new file. */
+	  if (gdbm_store (new_dbf, key, data, GDBM_INSERT) != 0)
+	    {
+	      gdbm_close (new_dbf);
+	      gdbm_errno = GDBM_REORGANIZE_FAILED;
+	      unlink (new_name);
+	      return -1;
+	    }
+ 	}
+      else
+ 	{
+	  /* ERROR! Abort and don't finish reorganize. */
+	  gdbm_close (new_dbf);
+	  gdbm_errno = GDBM_REORGANIZE_FAILED;
+	  unlink (new_name);
+	  return -1;
+ 	}
+      nextkey = gdbm_nextkey (dbf, key);
+      free (key.dptr);
+      free (data.dptr);
+      key = nextkey;
+    }
+
+  /* Write everything. */
+  _gdbm_end_update (new_dbf);
+  gdbm_sync (new_dbf);
+
+
+  /* Move the new file to old name. */
+
+#ifdef MSDOS
+  if (close (new_dbf->desc)
+      || unlink (dbf->name)
+      || rename (new_name, dbf->name)
+      || (new_dbf->desc = open (dbf->name, O_RDWR|O_BINARY)) < 0)
+#else /* not MSDOS */
+  if (rename (new_name, dbf->name) != 0)
+#endif /* not MSDOS */
+   {
+      gdbm_errno = GDBM_REORGANIZE_FAILED;
+      gdbm_close (new_dbf);
+      return -1;
+    }
+
+  /* Fix up DBF to have the correct information for the new file. */
+  if (dbf->need_filelock) {
+	  UNLOCK_FILE(dbf);
+  }
+  close (dbf->desc);
+  free (dbf->header);
+  free (dbf->dir);
+
+  if (dbf->bucket_cache != NULL) {
+    for (index = 0; index < dbf->cache_size; index++) {
+      if (dbf->bucket_cache[index].ca_bucket != NULL)
+	free (dbf->bucket_cache[index].ca_bucket);
+      if (dbf->bucket_cache[index].ca_data.dptr != NULL)
+	free (dbf->bucket_cache[index].ca_data.dptr);
+    }
+    free (dbf->bucket_cache);
+  }
+
+  dbf->desc           = new_dbf->desc;
+  dbf->header         = new_dbf->header;
+  dbf->dir            = new_dbf->dir;
+  dbf->bucket         = new_dbf->bucket;
+  dbf->bucket_dir     = new_dbf->bucket_dir;
+  dbf->last_read      = new_dbf->last_read;
+  dbf->bucket_cache   = new_dbf->bucket_cache;
+  dbf->cache_size     = new_dbf->cache_size;
+  dbf->header_changed    = new_dbf->header_changed;
+  dbf->directory_changed = new_dbf->directory_changed;
+  dbf->bucket_changed    = new_dbf->bucket_changed;
+  dbf->second_changed    = new_dbf->second_changed;
+      
+  free (new_dbf);
+
+  /* Make sure the new database is all on disk. */
+  fsync (dbf->desc);
+
+  /* Force the right stuff for a correct bucket cache. */
+  dbf->cache_entry    = &dbf->bucket_cache[0];
+  _gdbm_get_bucket (dbf, 0);
+
+  return 0;
+}
Index: /main/tags/2.25/gsdl/packages/wingdbm/gdbmseq.c
===================================================================
--- /main/tags/2.25/gsdl/packages/wingdbm/gdbmseq.c	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/wingdbm/gdbmseq.c	(revision 21064)
@@ -0,0 +1,146 @@
+/* gdbmseq.c - Routines to visit all keys.  Not in sorted order. */
+
+/*  This file is part of GDBM, the GNU data base manager, by Philip A. Nelson.
+    Copyright (C) 1990, 1991, 1993  Free Software Foundation, Inc.
+
+    GDBM 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, or (at your option)
+    any later version.
+
+    GDBM 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 GDBM; see the file COPYING.  If not, write to
+    the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+
+    You may contact the author by:
+       e-mail:  phil@cs.wwu.edu
+      us-mail:  Philip A. Nelson
+                Computer Science Department
+                Western Washington University
+                Bellingham, WA 98226
+       
+*************************************************************************/
+
+
+/* include system configuration before all else. */
+#include "autoconf.h"
+
+#include "gdbmdefs.h"
+#include "gdbmerrno.h"
+
+/* Special extern for this file. */
+extern char *_gdbm_read_entry _ARGS((gdbm_file_info *, int));
+
+
+/* Find and read the next entry in the hash structure for DBF starting
+   at ELEM_LOC of the current bucket and using RETURN_VAL as the place to
+   put the data that is found. */
+
+static void
+get_next_key (dbf, elem_loc, return_val)
+     gdbm_file_info *dbf;
+     int elem_loc;
+     datum *return_val;
+{
+  int   found;			/* Have we found the next key. */
+  char  *find_data;		/* Data pointer returned by find_key. */
+
+  /* Find the next key. */
+  found = FALSE;
+  while (!found)
+    {
+      /* Advance to the next location in the bucket. */
+      elem_loc++;
+      if (elem_loc == dbf->header->bucket_elems)
+	{
+	  /* We have finished the current bucket, get the next bucket.  */
+	  elem_loc = 0;
+
+	  /* Find the next bucket.  It is possible several entries in
+	     the bucket directory point to the same bucket. */
+	  while (dbf->bucket_dir < dbf->header->dir_size / sizeof (off_t)
+		 && dbf->cache_entry->ca_adr == dbf->dir[dbf->bucket_dir])
+	    dbf->bucket_dir++;
+
+	  /* Check to see if there was a next bucket. */
+	  if (dbf->bucket_dir < dbf->header->dir_size / sizeof (off_t))
+	    _gdbm_get_bucket (dbf, dbf->bucket_dir);	      
+	  else
+	    /* No next key, just return. */
+	    return ;
+	}
+      found = dbf->bucket->h_table[elem_loc].hash_value != -1;
+    }
+  
+  /* Found the next key, read it into return_val. */
+  find_data = _gdbm_read_entry (dbf, elem_loc);
+  return_val->dsize = dbf->bucket->h_table[elem_loc].key_size;
+  if (return_val->dsize == 0)
+    return_val->dptr = (char *) malloc (1);
+  else
+    return_val->dptr = (char *) malloc (return_val->dsize);
+  if (return_val->dptr == NULL) _gdbm_fatal (dbf, "malloc error");
+  bcopy (find_data, return_val->dptr, return_val->dsize);
+}
+
+
+/* Start the visit of all keys in the database.  This produces something in
+   hash order, not in any sorted order.  */
+
+datum
+gdbm_firstkey (dbf)
+     gdbm_file_info *dbf;
+{
+  datum return_val;		/* To return the first key. */
+
+  /* Set the default return value for not finding a first entry. */
+  return_val.dptr = NULL;
+
+  /* Initialize the gdbm_errno variable. */
+  gdbm_errno = GDBM_NO_ERROR;
+
+  /* Get the first bucket.  */
+  _gdbm_get_bucket (dbf, 0);
+
+  /* Look for first entry. */
+  get_next_key (dbf, -1, &return_val);
+
+  return return_val;
+}
+
+
+/* Continue visiting all keys.  The next key following KEY is returned. */
+
+datum
+gdbm_nextkey (dbf, key)
+     gdbm_file_info *dbf;
+     datum key;
+{
+  datum  return_val;		/* The return value. */
+  int    elem_loc;		/* The location in the bucket. */
+  char  *find_data;		/* Data pointer returned by _gdbm_findkey. */
+  word_t hash_val;		/* Returned by _gdbm_findkey. */
+
+  /* Initialize the gdbm_errno variable. */
+  gdbm_errno = GDBM_NO_ERROR;
+
+  /* Set the default return value for no next entry. */
+  return_val.dptr = NULL;
+
+  /* Do we have a valid key? */
+  if (key.dptr == NULL) return return_val;
+
+  /* Find the key.  */
+  elem_loc = _gdbm_findkey (dbf, key, &find_data, &hash_val);
+  if (elem_loc == -1) return return_val;
+
+  /* Find the next key. */  
+  get_next_key (dbf, elem_loc, &return_val);
+
+  return return_val;
+}
Index: /main/tags/2.25/gsdl/packages/wingdbm/gdbmsetopt.c
===================================================================
--- /main/tags/2.25/gsdl/packages/wingdbm/gdbmsetopt.c	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/wingdbm/gdbmsetopt.c	(revision 21064)
@@ -0,0 +1,78 @@
+/* gdbmsetopt.c - set options pertaining to a GDBM descriptor. */
+
+/*  This file is part of GDBM, the GNU data base manager, by Philip A. Nelson.
+    Copyright (C) 1993, 1994  Free Software Foundation, Inc.
+
+    GDBM 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, or (at your option)
+    any later version.
+
+    GDBM 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 GDBM; see the file COPYING.  If not, write to
+    the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+
+    You may contact the original author by:
+       e-mail:  phil@cs.wwu.edu
+      us-mail:  Philip A. Nelson
+                Computer Science Department
+                Western Washington University
+                Bellingham, WA 98226
+       
+    The author of this file is:
+       e-mail:  downsj@csos.orst.edu
+
+*************************************************************************/
+
+
+/* include system configuration before all else. */
+#include "autoconf.h"
+
+#include "gdbmdefs.h"
+#include "gdbmerrno.h"
+
+/* operate on an already open descriptor. */
+
+/* ARGSUSED */
+int
+gdbm_setopt(dbf, optflag, optval, optlen)
+    gdbm_file_info *dbf;	/* descriptor to operate on. */
+    int optflag;		/* option to set. */
+    int *optval;		/* pointer to option value. */
+    int optlen;			/* size of optval. */
+{
+  switch(optflag)
+    {
+      case GDBM_CACHESIZE:
+        /* here, optval will point to the new size of the cache. */
+        if (dbf->bucket_cache != NULL)
+          {
+            gdbm_errno = GDBM_OPT_ALREADY_SET;
+            return(-1);
+          }
+
+        return(_gdbm_init_cache(dbf, ((*optval) > 9) ? (*optval) : 10));
+
+      case GDBM_FASTMODE:
+      	/* here, optval will point to either true or false. */
+	if ((*optval != TRUE) && (*optval != FALSE))
+	  {
+	    gdbm_errno = GDBM_OPT_ILLEGAL;
+	    return(-1);
+	  }
+
+	dbf->fast_write = *optval;
+	break;
+
+      default:
+        gdbm_errno = GDBM_OPT_ILLEGAL;
+        return(-1);
+    }
+
+  return(0);
+}
Index: /main/tags/2.25/gsdl/packages/wingdbm/gdbmstore.c
===================================================================
--- /main/tags/2.25/gsdl/packages/wingdbm/gdbmstore.c	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/wingdbm/gdbmstore.c	(revision 21064)
@@ -0,0 +1,167 @@
+/* gdbmstore.c - Add a new key/data pair to the database. */
+
+/*  This file is part of GDBM, the GNU data base manager, by Philip A. Nelson.
+    Copyright (C) 1990, 1991, 1993  Free Software Foundation, Inc.
+
+    GDBM 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, or (at your option)
+    any later version.
+
+    GDBM 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 GDBM; see the file COPYING.  If not, write to
+    the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+
+    You may contact the author by:
+       e-mail:  phil@cs.wwu.edu
+      us-mail:  Philip A. Nelson
+                Computer Science Department
+                Western Washington University
+                Bellingham, WA 98226
+       
+*************************************************************************/
+
+
+/* AIX demands this be the very first thing in the file. */
+#if !defined(__GNUC__) && defined(_AIX)
+ #pragma alloca
+#endif
+
+/* include system configuration before all else. */
+#include "autoconf.h"
+
+#include "gdbmdefs.h"
+#include "gdbmerrno.h"
+
+
+/* Add a new element to the database.  CONTENT is keyed by KEY.  The
+   file on disk is updated to reflect the structure of the new database
+   before returning from this procedure.  The FLAGS define the action to
+   take when the KEY is already in the database.  The value GDBM_REPLACE
+   asks that the old data be replaced by the new CONTENT.  The value
+   GDBM_INSERT asks that an error be returned and no action taken.  A
+   return value of 0 means no errors.  A return value of -1 means that
+   the item was not stored in the data base because the caller was not an
+   official writer. A return value of 0 means that the item was not stored
+   because the argument FLAGS was GDBM_INSERT and the KEY was already in
+   the database. */
+
+int
+gdbm_store (dbf, key, content, flags)
+     gdbm_file_info *dbf;
+     datum key;
+     datum content;
+     int flags;
+{
+  word_t new_hash_val;		/* The new hash value. */
+  int  elem_loc;		/* The location in hash bucket. */
+  off_t file_adr;		/* The address of new space in the file.  */
+  off_t file_pos;		/* The position after a lseek. */
+  int  num_bytes;		/* Used for error detection. */
+  off_t free_adr;		/* For keeping track of a freed section. */
+  int  free_size;
+
+  /* char *write_data; */	/* To write both key and data in 1 call. */
+  /* char *src;	*/		/* Used to prepare write_data. */
+  /* char *dst;	*/		/* Used to prepare write_data. */
+  /* int   cnt;	*/		/* Counter for loops to fill write_data. */
+  int   new_size;		/* Used in allocating space. */
+  char *temp;			/* Used in _gdbm_findkey call. */
+
+
+  /* First check to make sure this guy is a writer. */
+  if (dbf->read_write != GDBM_WRITER)
+    {
+      gdbm_errno = GDBM_READER_CANT_STORE;
+      return -1;
+    }
+
+  /* Check for illegal data values.  A NULL dptr field is illegal because
+     NULL dptr returned by a lookup procedure indicates an error. */
+  if ((key.dptr == NULL) || (content.dptr == NULL))
+    {
+      gdbm_errno = GDBM_ILLEGAL_DATA;
+      return -1;
+    }
+
+  /* Initialize the gdbm_errno variable. */
+  gdbm_errno = GDBM_NO_ERROR;
+
+  /* Look for the key in the file.
+     A side effect loads the correct bucket and calculates the hash value. */
+  elem_loc = _gdbm_findkey (dbf, key, &temp, &new_hash_val);
+
+
+  /* Did we find the item? */
+  if (elem_loc != -1)
+    {
+      if (flags == GDBM_REPLACE)
+	{
+	  /* Just replace the data. */
+	  free_adr = dbf->bucket->h_table[elem_loc].data_pointer;
+	  free_size = dbf->bucket->h_table[elem_loc].key_size
+	              + dbf->bucket->h_table[elem_loc].data_size;
+	  _gdbm_free (dbf, free_adr, free_size);
+	}
+      else
+	{
+	  gdbm_errno = GDBM_CANNOT_REPLACE;
+	  return 1;
+	}
+    }
+
+
+  /* Get the file address for the new space.
+     (Current bucket's free space is first place to look.) */
+  new_size = key.dsize+content.dsize;
+  file_adr = _gdbm_alloc (dbf, new_size);
+
+  /* If this is a new entry in the bucket, we need to do special things. */
+  if (elem_loc == -1)
+    {
+      if (dbf->bucket->count == dbf->header->bucket_elems)
+	{
+	  /* Split the current bucket. */
+	  _gdbm_split_bucket (dbf, new_hash_val);
+	}
+      
+      /* Find space to insert into bucket and set elem_loc to that place. */
+      elem_loc = new_hash_val % dbf->header->bucket_elems;
+      while (dbf->bucket->h_table[elem_loc].hash_value != -1)
+	{  elem_loc = (elem_loc + 1) % dbf->header->bucket_elems; }
+
+      /* We now have another element in the bucket.  Add the new information.*/
+      dbf->bucket->count += 1;
+      dbf->bucket->h_table[elem_loc].hash_value = new_hash_val;
+      bcopy (key.dptr, dbf->bucket->h_table[elem_loc].key_start,
+	     (SMALL < key.dsize ? SMALL : key.dsize));
+    }
+
+
+  /* Update current bucket data pointer and sizes. */
+  dbf->bucket->h_table[elem_loc].data_pointer = file_adr;
+  dbf->bucket->h_table[elem_loc].key_size = key.dsize;
+  dbf->bucket->h_table[elem_loc].data_size = content.dsize;
+
+  /* Write the data to the file. */
+  file_pos = lseek (dbf->desc, file_adr, L_SET);
+  if (file_pos != file_adr) _gdbm_fatal (dbf, "lseek error");
+  num_bytes = write (dbf->desc, key.dptr, key.dsize);
+  if (num_bytes != key.dsize) _gdbm_fatal (dbf, "write error");
+  num_bytes = write (dbf->desc, content.dptr, content.dsize);
+  if (num_bytes != content.dsize) _gdbm_fatal (dbf, "write error");
+
+  /* Current bucket has changed. */
+  dbf->cache_entry->ca_changed = TRUE;
+  dbf->bucket_changed = TRUE;
+
+  /* Write everything that is needed to the disk. */
+  _gdbm_end_update (dbf);
+  return 0;
+  
+}
Index: /main/tags/2.25/gsdl/packages/wingdbm/gdbmsync.c
===================================================================
--- /main/tags/2.25/gsdl/packages/wingdbm/gdbmsync.c	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/wingdbm/gdbmsync.c	(revision 21064)
@@ -0,0 +1,49 @@
+/* gdbmsync.c - Sync the disk with the in memory state. */
+
+/*  This file is part of GDBM, the GNU data base manager, by Philip A. Nelson.
+    Copyright (C) 1990, 1991, 1993  Free Software Foundation, Inc.
+
+    GDBM 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, or (at your option)
+    any later version.
+
+    GDBM 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 GDBM; see the file COPYING.  If not, write to
+    the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+
+    You may contact the author by:
+       e-mail:  phil@cs.wwu.edu
+      us-mail:  Philip A. Nelson
+                Computer Science Department
+                Western Washington University
+                Bellingham, WA 98226
+       
+*************************************************************************/
+
+
+/* include system configuration before all else. */
+#include "autoconf.h"
+
+#include "gdbmdefs.h"
+#include "gdbmerrno.h"
+
+/* Make sure the database is all on disk. */
+
+void
+gdbm_sync (dbf)
+     gdbm_file_info *dbf;
+{
+
+  /* Initialize the gdbm_errno variable. */
+  gdbm_errno = GDBM_NO_ERROR;
+
+  /* Do the sync on the file. */
+  fsync (dbf->desc);
+
+}
Index: /main/tags/2.25/gsdl/packages/wingdbm/getopt.c
===================================================================
--- /main/tags/2.25/gsdl/packages/wingdbm/getopt.c	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/wingdbm/getopt.c	(revision 21064)
@@ -0,0 +1,735 @@
+/* Getopt for GNU.
+   NOTE: getopt is now part of the C library, so if you don't know what
+   "Keep this file name-space clean" means, talk to roland@gnu.ai.mit.edu
+   before changing it!
+
+   Copyright (C) 1987, 88, 89, 90, 91, 92, 1993
+   	Free Software Foundation, Inc.
+
+   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, 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, 675 Mass Ave, Cambridge, MA 02139, USA.  */
+
+
+/* NOTE!!!  AIX requires this to be the first thing in the file.
+   Do not put ANYTHING before it!  */
+#if !defined (__GNUC__) && defined (_AIX)
+ #pragma alloca
+#endif
+
+#include "autoconf.h"
+
+#ifdef __GNUC__
+#define alloca __builtin_alloca
+#else /* not __GNUC__ */
+#if defined (HAVE_ALLOCA_H) || (defined(sparc) && (defined(sun) || (!defined(USG) && !defined(SVR4) && !defined(__svr4__))))
+#include <alloca.h>
+#else
+#ifndef _AIX
+char *alloca ();
+#endif
+#endif /* alloca.h */
+#endif /* not __GNUC__ */
+
+#if !__STDC__ && !defined(const) && IN_GCC
+#define const
+#endif
+
+/* This tells Alpha OSF/1 not to define a getopt prototype in <stdio.h>.  */
+#ifndef _NO_PROTO
+#define _NO_PROTO
+#endif
+
+#include <string.h>
+#include <stdio.h>
+
+/* Comment out all this code if we are using the GNU C Library, and are not
+   actually compiling the library itself.  This code is part of the GNU C
+   Library, but also included in many other GNU distributions.  Compiling
+   and linking in this code is a waste when using the GNU C library
+   (especially if it is a shared library).  Rather than having every GNU
+   program understand `configure --with-gnu-libc' and omit the object files,
+   it is simpler to just do this in the source for each such file.  */
+
+#if defined (_LIBC) || !defined (__GNU_LIBRARY__)
+
+
+/* This needs to come after some library #include
+   to get __GNU_LIBRARY__ defined.  */
+#ifdef	__GNU_LIBRARY__
+#undef	alloca
+/* Don't include stdlib.h for non-GNU C libraries because some of them
+   contain conflicting prototypes for getopt.  */
+#include <stdlib.h>
+#else	/* Not GNU C library.  */
+#define	__alloca	alloca
+#endif	/* GNU C library.  */
+
+/* If GETOPT_COMPAT is defined, `+' as well as `--' can introduce a
+   long-named option.  Because this is not POSIX.2 compliant, it is
+   being phased out.  */
+/* #define GETOPT_COMPAT */
+
+/* This version of `getopt' appears to the caller like standard Unix `getopt'
+   but it behaves differently for the user, since it allows the user
+   to intersperse the options with the other arguments.
+
+   As `getopt' works, it permutes the elements of ARGV so that,
+   when it is done, all the options precede everything else.  Thus
+   all application programs are extended to handle flexible argument order.
+
+   Setting the environment variable POSIXLY_CORRECT disables permutation.
+   Then the behavior is completely standard.
+
+   GNU application programs can use a third alternative mode in which
+   they can distinguish the relative order of options and other arguments.  */
+
+#include "getopt.h"
+
+/* For communication from `getopt' to the caller.
+   When `getopt' finds an option that takes an argument,
+   the argument value is returned here.
+   Also, when `ordering' is RETURN_IN_ORDER,
+   each non-option ARGV-element is returned here.  */
+
+char *optarg = 0;
+
+/* Index in ARGV of the next element to be scanned.
+   This is used for communication to and from the caller
+   and for communication between successive calls to `getopt'.
+
+   On entry to `getopt', zero means this is the first call; initialize.
+
+   When `getopt' returns EOF, this is the index of the first of the
+   non-option elements that the caller should itself scan.
+
+   Otherwise, `optind' communicates from one call to the next
+   how much of ARGV has been scanned so far.  */
+
+/* XXX 1003.2 says this must be 1 before any call.  */
+int optind = 0;
+
+/* The next char to be scanned in the option-element
+   in which the last option character we returned was found.
+   This allows us to pick up the scan where we left off.
+
+   If this is zero, or a null string, it means resume the scan
+   by advancing to the next ARGV-element.  */
+
+static char *nextchar;
+
+/* Callers store zero here to inhibit the error message
+   for unrecognized options.  */
+
+int opterr = 1;
+
+/* Set to an option character which was unrecognized.
+   This must be initialized on some systems to avoid linking in the
+   system's own getopt implementation.  */
+
+int optopt = '?';
+
+/* Describe how to deal with options that follow non-option ARGV-elements.
+
+   If the caller did not specify anything,
+   the default is REQUIRE_ORDER if the environment variable
+   POSIXLY_CORRECT is defined, PERMUTE otherwise.
+
+   REQUIRE_ORDER means don't recognize them as options;
+   stop option processing when the first non-option is seen.
+   This is what Unix does.
+   This mode of operation is selected by either setting the environment
+   variable POSIXLY_CORRECT, or using `+' as the first character
+   of the list of option characters.
+
+   PERMUTE is the default.  We permute the contents of ARGV as we scan,
+   so that eventually all the non-options are at the end.  This allows options
+   to be given in any order, even with programs that were not written to
+   expect this.
+
+   RETURN_IN_ORDER is an option available to programs that were written
+   to expect options and other ARGV-elements in any order and that care about
+   the ordering of the two.  We describe each non-option ARGV-element
+   as if it were the argument of an option with character code 1.
+   Using `-' as the first character of the list of option characters
+   selects this mode of operation.
+
+   The special argument `--' forces an end of option-scanning regardless
+   of the value of `ordering'.  In the case of RETURN_IN_ORDER, only
+   `--' can cause `getopt' to return EOF with `optind' != ARGC.  */
+
+static enum
+{
+  REQUIRE_ORDER, PERMUTE, RETURN_IN_ORDER
+} ordering;
+
+
+#ifdef	__GNU_LIBRARY__
+/* We want to avoid inclusion of string.h with non-GNU libraries
+   because there are many ways it can cause trouble.
+   On some systems, it contains special magic macros that don't work
+   in GCC.  */
+#include <string.h>
+#define	my_index	strchr
+#define	my_bcopy(src, dst, n)	memcpy ((dst), (src), (n))
+#else
+
+/* Avoid depending on library functions or files
+   whose names are inconsistent.  */
+
+char *getenv ();
+
+static char *
+my_index (str, chr)
+     const char *str;
+     int chr;
+{
+  while (*str)
+    {
+      if (*str == chr)
+	return (char *) str;
+      str++;
+    }
+  return 0;
+}
+
+static void
+my_bcopy (from, to, size)
+     const char *from;
+     char *to;
+     int size;
+{
+  int i;
+  for (i = 0; i < size; i++)
+    to[i] = from[i];
+}
+#endif				/* GNU C library.  */
+
+
+/* Handle permutation of arguments.  */
+
+/* Describe the part of ARGV that contains non-options that have
+   been skipped.  `first_nonopt' is the index in ARGV of the first of them;
+   `last_nonopt' is the index after the last of them.  */
+
+static int first_nonopt;
+static int last_nonopt;
+
+/* Exchange two adjacent subsequences of ARGV.
+   One subsequence is elements [first_nonopt,last_nonopt)
+   which contains all the non-options that have been skipped so far.
+   The other is elements [last_nonopt,optind), which contains all
+   the options processed since those non-options were skipped.
+
+   `first_nonopt' and `last_nonopt' are relocated so that they describe
+   the new indices of the non-options in ARGV after they are moved.  */
+
+static void
+exchange (argv)
+     char **argv;
+{
+  int nonopts_size = (last_nonopt - first_nonopt) * sizeof (char *);
+  char **temp = (char **) __alloca (nonopts_size);
+
+  /* Interchange the two blocks of data in ARGV.  */
+
+  my_bcopy ((char *) &argv[first_nonopt], (char *) temp, nonopts_size);
+  my_bcopy ((char *) &argv[last_nonopt], (char *) &argv[first_nonopt],
+	    (optind - last_nonopt) * sizeof (char *));
+  my_bcopy ((char *) temp,
+	    (char *) &argv[first_nonopt + optind - last_nonopt],
+	    nonopts_size);
+
+  /* Update records for the slots the non-options now occupy.  */
+
+  first_nonopt += (optind - last_nonopt);
+  last_nonopt = optind;
+}
+
+
+/* Scan elements of ARGV (whose length is ARGC) for option characters
+   given in OPTSTRING.
+
+   If an element of ARGV starts with '-', and is not exactly "-" or "--",
+   then it is an option element.  The characters of this element
+   (aside from the initial '-') are option characters.  If `getopt'
+   is called repeatedly, it returns successively each of the option characters
+   from each of the option elements.
+
+   If `getopt' finds another option character, it returns that character,
+   updating `optind' and `nextchar' so that the next call to `getopt' can
+   resume the scan with the following option character or ARGV-element.
+
+   If there are no more option characters, `getopt' returns `EOF'.
+   Then `optind' is the index in ARGV of the first ARGV-element
+   that is not an option.  (The ARGV-elements have been permuted
+   so that those that are not options now come last.)
+
+   OPTSTRING is a string containing the legitimate option characters.
+   If an option character is seen that is not listed in OPTSTRING,
+   return '?' after printing an error message.  If you set `opterr' to
+   zero, the error message is suppressed but we still return '?'.
+
+   If a char in OPTSTRING is followed by a colon, that means it wants an arg,
+   so the following text in the same ARGV-element, or the text of the following
+   ARGV-element, is returned in `optarg'.  Two colons mean an option that
+   wants an optional arg; if there is text in the current ARGV-element,
+   it is returned in `optarg', otherwise `optarg' is set to zero.
+
+   If OPTSTRING starts with `-' or `+', it requests different methods of
+   handling the non-option ARGV-elements.
+   See the comments about RETURN_IN_ORDER and REQUIRE_ORDER, above.
+
+   Long-named options begin with `--' instead of `-'.
+   Their names may be abbreviated as long as the abbreviation is unique
+   or is an exact match for some defined option.  If they have an
+   argument, it follows the option name in the same ARGV-element, separated
+   from the option name by a `=', or else the in next ARGV-element.
+   When `getopt' finds a long-named option, it returns 0 if that option's
+   `flag' field is nonzero, the value of the option's `val' field
+   if the `flag' field is zero.
+
+   The elements of ARGV aren't really const, because we permute them.
+   But we pretend they're const in the prototype to be compatible
+   with other systems.
+
+   LONGOPTS is a vector of `struct option' terminated by an
+   element containing a name which is zero.
+
+   LONGIND returns the index in LONGOPT of the long-named option found.
+   It is only valid when a long-named option has been found by the most
+   recent call.
+
+   If LONG_ONLY is nonzero, '-' as well as '--' can introduce
+   long-named options.  */
+
+int
+_getopt_internal (argc, argv, optstring, longopts, longind, long_only)
+     int argc;
+     char *const *argv;
+     const char *optstring;
+     const struct option *longopts;
+     int *longind;
+     int long_only;
+{
+  int option_index;
+
+  optarg = 0;
+
+  /* Initialize the internal data when the first call is made.
+     Start processing options with ARGV-element 1 (since ARGV-element 0
+     is the program name); the sequence of previously skipped
+     non-option ARGV-elements is empty.  */
+
+  if (optind == 0)
+    {
+      first_nonopt = last_nonopt = optind = 1;
+
+      nextchar = NULL;
+
+      /* Determine how to handle the ordering of options and nonoptions.  */
+
+      if (optstring[0] == '-')
+	{
+	  ordering = RETURN_IN_ORDER;
+	  ++optstring;
+	}
+      else if (optstring[0] == '+')
+	{
+	  ordering = REQUIRE_ORDER;
+	  ++optstring;
+	}
+      else if (getenv ("POSIXLY_CORRECT") != NULL)
+	ordering = REQUIRE_ORDER;
+      else
+	ordering = PERMUTE;
+    }
+
+  if (nextchar == NULL || *nextchar == '\0')
+    {
+      if (ordering == PERMUTE)
+	{
+	  /* If we have just processed some options following some non-options,
+	     exchange them so that the options come first.  */
+
+	  if (first_nonopt != last_nonopt && last_nonopt != optind)
+	    exchange ((char **) argv);
+	  else if (last_nonopt != optind)
+	    first_nonopt = optind;
+
+	  /* Now skip any additional non-options
+	     and extend the range of non-options previously skipped.  */
+
+	  while (optind < argc
+		 && (argv[optind][0] != '-' || argv[optind][1] == '\0')
+#ifdef GETOPT_COMPAT
+		 && (longopts == NULL
+		     || argv[optind][0] != '+' || argv[optind][1] == '\0')
+#endif				/* GETOPT_COMPAT */
+		 )
+	    optind++;
+	  last_nonopt = optind;
+	}
+
+      /* Special ARGV-element `--' means premature end of options.
+	 Skip it like a null option,
+	 then exchange with previous non-options as if it were an option,
+	 then skip everything else like a non-option.  */
+
+      if (optind != argc && !strcmp (argv[optind], "--"))
+	{
+	  optind++;
+
+	  if (first_nonopt != last_nonopt && last_nonopt != optind)
+	    exchange ((char **) argv);
+	  else if (first_nonopt == last_nonopt)
+	    first_nonopt = optind;
+	  last_nonopt = argc;
+
+	  optind = argc;
+	}
+
+      /* If we have done all the ARGV-elements, stop the scan
+	 and back over any non-options that we skipped and permuted.  */
+
+      if (optind == argc)
+	{
+	  /* Set the next-arg-index to point at the non-options
+	     that we previously skipped, so the caller will digest them.  */
+	  if (first_nonopt != last_nonopt)
+	    optind = first_nonopt;
+	  return EOF;
+	}
+
+      /* If we have come to a non-option and did not permute it,
+	 either stop the scan or describe it to the caller and pass it by.  */
+
+      if ((argv[optind][0] != '-' || argv[optind][1] == '\0')
+#ifdef GETOPT_COMPAT
+	  && (longopts == NULL
+	      || argv[optind][0] != '+' || argv[optind][1] == '\0')
+#endif				/* GETOPT_COMPAT */
+	  )
+	{
+	  if (ordering == REQUIRE_ORDER)
+	    return EOF;
+	  optarg = argv[optind++];
+	  return 1;
+	}
+
+      /* We have found another option-ARGV-element.
+	 Start decoding its characters.  */
+
+      nextchar = (argv[optind] + 1
+		  + (longopts != NULL && argv[optind][1] == '-'));
+    }
+
+  if (longopts != NULL
+      && ((argv[optind][0] == '-'
+	   && (argv[optind][1] == '-' || long_only))
+#ifdef GETOPT_COMPAT
+	  || argv[optind][0] == '+'
+#endif				/* GETOPT_COMPAT */
+	  ))
+    {
+      const struct option *p;
+      char *s = nextchar;
+      int exact = 0;
+      int ambig = 0;
+      const struct option *pfound = NULL;
+      int indfound;
+
+      while (*s && *s != '=')
+	s++;
+
+      /* Test all options for either exact match or abbreviated matches.  */
+      for (p = longopts, option_index = 0; p->name;
+	   p++, option_index++)
+	if (!strncmp (p->name, nextchar, s - nextchar))
+	  {
+	    if ((unsigned int)(s - nextchar) == strlen (p->name))
+		{ 
+		/* Exact match found.  */
+		pfound = p;
+		indfound = option_index;
+		exact = 1;
+		break;
+	      }
+	    else if (pfound == NULL)
+	      {
+		/* First nonexact match found.  */
+		pfound = p;
+		indfound = option_index;
+	      }
+	    else
+	      /* Second nonexact match found.  */
+	      ambig = 1;
+	  }
+
+      if (ambig && !exact)
+	{
+	  if (opterr)
+	    fprintf (stderr, "%s: option `%s' is ambiguous\n",
+		     argv[0], argv[optind]);
+	  nextchar += strlen (nextchar);
+	  optind++;
+	  return '?';
+	}
+
+      if (pfound != NULL)
+	{
+	  option_index = indfound;
+	  optind++;
+	  if (*s)
+	    {
+	      /* Don't test has_arg with >, because some C compilers don't
+		 allow it to be used on enums.  */
+	      if (pfound->has_arg)
+		optarg = s + 1;
+	      else
+		{
+		  if (opterr)
+		    {
+		      if (argv[optind - 1][1] == '-')
+			/* --option */
+			fprintf (stderr,
+				 "%s: option `--%s' doesn't allow an argument\n",
+				 argv[0], pfound->name);
+		      else
+			/* +option or -option */
+			fprintf (stderr,
+			     "%s: option `%c%s' doesn't allow an argument\n",
+			     argv[0], argv[optind - 1][0], pfound->name);
+		    }
+		  nextchar += strlen (nextchar);
+		  return '?';
+		}
+	    }
+	  else if (pfound->has_arg == 1)
+	    {
+	      if (optind < argc)
+		optarg = argv[optind++];
+	      else
+		{
+		  if (opterr)
+		    fprintf (stderr, "%s: option `%s' requires an argument\n",
+			     argv[0], argv[optind - 1]);
+		  nextchar += strlen (nextchar);
+		  return optstring[0] == ':' ? ':' : '?';
+		}
+	    }
+	  nextchar += strlen (nextchar);
+	  if (longind != NULL)
+	    *longind = option_index;
+	  if (pfound->flag)
+	    {
+	      *(pfound->flag) = pfound->val;
+	      return 0;
+	    }
+	  return pfound->val;
+	}
+      /* Can't find it as a long option.  If this is not getopt_long_only,
+	 or the option starts with '--' or is not a valid short
+	 option, then it's an error.
+	 Otherwise interpret it as a short option.  */
+      if (!long_only || argv[optind][1] == '-'
+#ifdef GETOPT_COMPAT
+	  || argv[optind][0] == '+'
+#endif				/* GETOPT_COMPAT */
+	  || my_index (optstring, *nextchar) == NULL)
+	{
+	  if (opterr)
+	    {
+	      if (argv[optind][1] == '-')
+		/* --option */
+		fprintf (stderr, "%s: unrecognized option `--%s'\n",
+			 argv[0], nextchar);
+	      else
+		/* +option or -option */
+		fprintf (stderr, "%s: unrecognized option `%c%s'\n",
+			 argv[0], argv[optind][0], nextchar);
+	    }
+	  nextchar = (char *) "";
+	  optind++;
+	  return '?';
+	}
+    }
+
+  /* Look at and handle the next option-character.  */
+
+  {
+    char c = *nextchar++;
+    char *temp = my_index (optstring, c);
+
+    /* Increment `optind' when we start to process its last character.  */
+    if (*nextchar == '\0')
+      ++optind;
+
+    if (temp == NULL || c == ':')
+      {
+	if (opterr)
+	  {
+#if 0
+	    if (c < 040 || c >= 0177)
+	      fprintf (stderr, "%s: unrecognized option, character code 0%o\n",
+		       argv[0], c);
+	    else
+	      fprintf (stderr, "%s: unrecognized option `-%c'\n", argv[0], c);
+#else
+	    /* 1003.2 specifies the format of this message.  */
+	    fprintf (stderr, "%s: illegal option -- %c\n", argv[0], c);
+#endif
+	  }
+	optopt = c;
+	return '?';
+      }
+    if (temp[1] == ':')
+      {
+	if (temp[2] == ':')
+	  {
+	    /* This is an option that accepts an argument optionally.  */
+	    if (*nextchar != '\0')
+	      {
+		optarg = nextchar;
+		optind++;
+	      }
+	    else
+	      optarg = 0;
+	    nextchar = NULL;
+	  }
+	else
+	  {
+	    /* This is an option that requires an argument.  */
+	    if (*nextchar != '\0')
+	      {
+		optarg = nextchar;
+		/* If we end this ARGV-element by taking the rest as an arg,
+		   we must advance to the next element now.  */
+		optind++;
+	      }
+	    else if (optind == argc)
+	      {
+		if (opterr)
+		  {
+#if 0
+		    fprintf (stderr, "%s: option `-%c' requires an argument\n",
+			     argv[0], c);
+#else
+		    /* 1003.2 specifies the format of this message.  */
+		    fprintf (stderr, "%s: option requires an argument -- %c\n",
+			     argv[0], c);
+#endif
+		  }
+		optopt = c;
+		if (optstring[0] == ':')
+		  c = ':';
+		else
+		  c = '?';
+	      }
+	    else
+	      /* We already incremented `optind' once;
+		 increment it again when taking next ARGV-elt as argument.  */
+	      optarg = argv[optind++];
+	    nextchar = NULL;
+	  }
+      }
+    return c;
+  }
+}
+
+int
+getopt (argc, argv, optstring)
+     int argc;
+     char *const *argv;
+     const char *optstring;
+{
+  return _getopt_internal (argc, argv, optstring,
+			   (const struct option *) 0,
+			   (int *) 0,
+			   0);
+}
+
+#endif	/* _LIBC or not __GNU_LIBRARY__.  */
+
+
+#ifdef TEST
+
+/* Compile with -DTEST to make an executable for use in testing
+   the above definition of `getopt'.  */
+
+int
+main (argc, argv)
+     int argc;
+     char **argv;
+{
+  int c;
+  int digit_optind = 0;
+
+  while (1)
+    {
+      int this_option_optind = optind ? optind : 1;
+
+      c = getopt (argc, argv, "abc:d:0123456789");
+      if (c == EOF)
+	break;
+
+      switch (c)
+	{
+	case '0':
+	case '1':
+	case '2':
+	case '3':
+	case '4':
+	case '5':
+	case '6':
+	case '7':
+	case '8':
+	case '9':
+	  if (digit_optind != 0 && digit_optind != this_option_optind)
+	    printf ("digits occur in two different argv-elements.\n");
+	  digit_optind = this_option_optind;
+	  printf ("option %c\n", c);
+	  break;
+
+	case 'a':
+	  printf ("option a\n");
+	  break;
+
+	case 'b':
+	  printf ("option b\n");
+	  break;
+
+	case 'c':
+	  printf ("option c with value `%s'\n", optarg);
+	  break;
+
+	case '?':
+	  break;
+
+	default:
+	  printf ("?? getopt returned character code 0%o ??\n", c);
+	}
+    }
+
+  if (optind < argc)
+    {
+      printf ("non-option ARGV-elements: ");
+      while (optind < argc)
+	printf ("%s ", argv[optind++]);
+      printf ("\n");
+    }
+
+  exit (0);
+}
+
+#endif /* TEST */
Index: /main/tags/2.25/gsdl/packages/wingdbm/getopt.h
===================================================================
--- /main/tags/2.25/gsdl/packages/wingdbm/getopt.h	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/wingdbm/getopt.h	(revision 21064)
@@ -0,0 +1,129 @@
+/* Declarations for getopt.
+   Copyright (C) 1989, 1990, 1991, 1992, 1993 Free Software Foundation, Inc.
+
+   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, 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, 675 Mass Ave, Cambridge, MA 02139, USA.  */
+
+#ifndef _GETOPT_H
+#define _GETOPT_H 1
+
+#ifdef	__cplusplus
+extern "C" {
+#endif
+
+/* For communication from `getopt' to the caller.
+   When `getopt' finds an option that takes an argument,
+   the argument value is returned here.
+   Also, when `ordering' is RETURN_IN_ORDER,
+   each non-option ARGV-element is returned here.  */
+
+extern char *optarg;
+
+/* Index in ARGV of the next element to be scanned.
+   This is used for communication to and from the caller
+   and for communication between successive calls to `getopt'.
+
+   On entry to `getopt', zero means this is the first call; initialize.
+
+   When `getopt' returns EOF, this is the index of the first of the
+   non-option elements that the caller should itself scan.
+
+   Otherwise, `optind' communicates from one call to the next
+   how much of ARGV has been scanned so far.  */
+
+extern int optind;
+
+/* Callers store zero here to inhibit the error message `getopt' prints
+   for unrecognized options.  */
+
+extern int opterr;
+
+/* Set to an option character which was unrecognized.  */
+
+extern int optopt;
+
+/* Describe the long-named options requested by the application.
+   The LONG_OPTIONS argument to getopt_long or getopt_long_only is a vector
+   of `struct option' terminated by an element containing a name which is
+   zero.
+
+   The field `has_arg' is:
+   no_argument		(or 0) if the option does not take an argument,
+   required_argument	(or 1) if the option requires an argument,
+   optional_argument 	(or 2) if the option takes an optional argument.
+
+   If the field `flag' is not NULL, it points to a variable that is set
+   to the value given in the field `val' when the option is found, but
+   left unchanged if the option is not found.
+
+   To have a long-named option do something other than set an `int' to
+   a compiled-in constant, such as set a value from `optarg', set the
+   option's `flag' field to zero and its `val' field to a nonzero
+   value (the equivalent single-letter option character, if there is
+   one).  For long options that have a zero `flag' field, `getopt'
+   returns the contents of the `val' field.  */
+
+struct option
+{
+#if	__STDC__
+  const char *name;
+#else
+  char *name;
+#endif
+  /* has_arg can't be an enum because some compilers complain about
+     type mismatches in all the code that assumes it is an int.  */
+  int has_arg;
+  int *flag;
+  int val;
+};
+
+/* Names for the values of the `has_arg' field of `struct option'.  */
+
+#define	no_argument		0
+#define required_argument	1
+#define optional_argument	2
+
+#if __STDC__
+#if defined(__GNU_LIBRARY__)
+/* Many other libraries have conflicting prototypes for getopt, with
+   differences in the consts, in stdlib.h.  To avoid compilation
+   errors, only prototype getopt for the GNU C library.  */
+extern int getopt (int argc, char *const *argv, const char *shortopts);
+#else /* not __GNU_LIBRARY__ */
+extern int getopt ();
+#endif /* not __GNU_LIBRARY__ */
+extern int getopt_long (int argc, char *const *argv, const char *shortopts,
+		        const struct option *longopts, int *longind);
+extern int getopt_long_only (int argc, char *const *argv,
+			     const char *shortopts,
+		             const struct option *longopts, int *longind);
+
+/* Internal only.  Users should not call this directly.  */
+extern int _getopt_internal (int argc, char *const *argv,
+			     const char *shortopts,
+		             const struct option *longopts, int *longind,
+			     int long_only);
+#else /* not __STDC__ */
+extern int getopt ();
+extern int getopt_long ();
+extern int getopt_long_only ();
+
+extern int _getopt_internal ();
+#endif /* not __STDC__ */
+
+#ifdef	__cplusplus
+}
+#endif
+
+#endif /* _GETOPT_H */
Index: /main/tags/2.25/gsdl/packages/wingdbm/global.c
===================================================================
--- /main/tags/2.25/gsdl/packages/wingdbm/global.c	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/wingdbm/global.c	(revision 21064)
@@ -0,0 +1,78 @@
+/* global.c - The external variables needed for "original" interface and
+   error messages. */
+
+/*  This file is part of GDBM, the GNU data base manager, by Philip A. Nelson.
+    Copyright (C) 1990, 1991, 1993  Free Software Foundation, Inc.
+
+    GDBM 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, or (at your option)
+    any later version.
+
+    GDBM 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 GDBM; see the file COPYING.  If not, write to
+    the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+
+    You may contact the author by:
+       e-mail:  phil@cs.wwu.edu
+      us-mail:  Philip A. Nelson
+                Computer Science Department
+                Western Washington University
+                Bellingham, WA 98226
+       
+*************************************************************************/
+
+
+/* include system configuration before all else. */
+#include "autoconf.h"
+
+#include "gdbmdefs.h"
+#include "gdbmerrno.h"
+
+#include <io.h>
+#include <windows.h>
+
+/* The global variables used for the "original" interface. */
+gdbm_file_info  *_gdbm_file = NULL;
+
+/* Memory for return data for the "original" interface. */
+datum _gdbm_memory = {NULL, 0};	/* Used by firstkey and nextkey. */
+char *_gdbm_fetch_val = NULL;	/* Used by fetch. */
+
+/* The dbm error number is placed in the variable GDBM_ERRNO. */
+gdbm_error gdbm_errno = GDBM_NO_ERROR;
+
+
+/* a simple locking function for windows that uses file descriptors */
+int my_locking(int fh, int lmode, long lockoffset, long nbytes) {
+	int result = -1;
+	int trys = 10;
+
+	lseek (fh, lockoffset, L_SET);
+
+	while (trys > 0 && result != 0) {
+		if (lmode == MY_UNLOCK) {
+			if (UnlockFile((HANDLE)_get_osfhandle(fh),lockoffset,0,nbytes,0))
+				result = 0;
+
+		} else if (lmode == MY_READLOCK) {
+/*			if (LockFileEx((HANDLE)_get_osfhandle(fh),0,0,nbytes,0,0))*/
+			if (LockFile((HANDLE)_get_osfhandle(fh),lockoffset,0,nbytes,0))
+				result = 0;
+
+		} else if (lmode == MY_WRITELOCK) {
+			if (LockFile((HANDLE)_get_osfhandle(fh),lockoffset,0,nbytes,0))
+				result = 0;
+		}
+
+		Sleep(100L);
+		trys--;
+	}
+
+	return result;
+}
Index: /main/tags/2.25/gsdl/packages/wingdbm/hash.c
===================================================================
--- /main/tags/2.25/gsdl/packages/wingdbm/hash.c	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/wingdbm/hash.c	(revision 21064)
@@ -0,0 +1,62 @@
+/* hash.c - The gdbm hash function. */
+
+/*  This file is part of GDBM, the GNU data base manager, by Philip A. Nelson.
+    Copyright (C) 1990, 1991, 1993  Free Software Foundation, Inc.
+
+    GDBM 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, or (at your option)
+    any later version.
+
+    GDBM 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 GDBM; see the file COPYING.  If not, write to
+    the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+
+    You may contact the author by:
+       e-mail:  phil@cs.wwu.edu
+      us-mail:  Philip A. Nelson
+                Computer Science Department
+                Western Washington University
+                Bellingham, WA 98226
+       
+*************************************************************************/
+
+
+/* include system configuration before all else. */
+#include "autoconf.h"
+
+#include "gdbmdefs.h"
+
+
+/* This hash function computes a 31 bit value.  The value is used to index
+   the hash directory using the top n bits.  It is also used in a hash bucket
+   to find the home position of the element by taking the value modulo the
+   bucket hash table size. */
+
+word_t
+_gdbm_hash (key)
+     datum key;
+{
+#if LONG_64_BITS || !INT_16_BITS
+  unsigned int value;	/* Used to compute the hash value.  */
+#else
+  unsigned long value;	/* Used to compute the hash value.  */
+#endif
+  int   index;		/* Used to cycle through random values. */
+
+
+  /* Set the initial value from key. */
+  value = 0x238F13AF * key.dsize;
+  for (index = 0; index < key.dsize; index++)
+    value = (value + (key.dptr[index] << (index*5 % 24))) & 0x7FFFFFFF;
+
+  value = (1103515243 * value + 12345) & 0x7FFFFFFF;  
+
+  /* Return the value. */
+  return((word_t) value);
+}
Index: /main/tags/2.25/gsdl/packages/wingdbm/proto.h
===================================================================
--- /main/tags/2.25/gsdl/packages/wingdbm/proto.h	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/wingdbm/proto.h	(revision 21064)
@@ -0,0 +1,87 @@
+/* proto.h - The prototypes for the dbm routines. */
+
+/*  This file is part of GDBM, the GNU data base manager, by Philip A. Nelson.
+    Copyright (C) 1990, 1991, 1993  Free Software Foundation, Inc.
+
+    GDBM 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, or (at your option)
+    any later version.
+
+    GDBM 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 GDBM; see the file COPYING.  If not, write to
+    the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+
+    You may contact the author by:
+       e-mail:  phil@cs.wwu.edu
+      us-mail:  Philip A. Nelson
+                Computer Science Department
+                Western Washington University
+                Bellingham, WA 98226
+
+*************************************************************************/
+
+
+/* Define our _PROTOTYPE macro. */
+
+#ifdef _ARGS
+#undef _ARGS
+#endif
+
+#ifdef __STDC__
+#define _ARGS(args) args
+#else
+#define _ARGS(args) ()
+#endif
+
+
+/* From bucket.c */
+void _gdbm_new_bucket    _ARGS((gdbm_file_info *dbf, hash_bucket *bucket,
+				int bits ));
+void _gdbm_get_bucket    _ARGS((gdbm_file_info *dbf, word_t dir_index ));
+void _gdbm_split_bucket  _ARGS((gdbm_file_info *dbf, word_t next_insert ));
+void _gdbm_write_bucket  _ARGS((gdbm_file_info *dbf, cache_elem *ca_entry ));
+
+/* From falloc.c */
+off_t _gdbm_alloc       _ARGS((gdbm_file_info *dbf, int num_bytes ));
+void _gdbm_free         _ARGS((gdbm_file_info *dbf, off_t file_adr,
+			       int num_bytes ));
+int  _gdbm_put_av_elem  _ARGS((avail_elem new_el, avail_elem av_table [],
+			       int *av_count ));
+
+/* From findkey.c */
+char *_gdbm_read_entry  _ARGS((gdbm_file_info *dbf, int elem_loc));
+int _gdbm_findkey       _ARGS((gdbm_file_info *dbf, datum key,  char **dptr,
+			       word_t *new_hash_val));
+
+/* From hash.c */
+word_t _gdbm_hash _ARGS((datum key ));
+
+/* From update.c */
+void _gdbm_end_update   _ARGS((gdbm_file_info *dbf ));
+int _gdbm_fatal         _ARGS((gdbm_file_info *dbf, char *val ));
+
+/* From gdbmopen.c */
+int _gdbm_init_cache	_ARGS((gdbm_file_info *dbf, int size));
+
+/* The user callable routines.... */
+void  gdbm_close	  _ARGS((gdbm_file_info *dbf ));
+int   gdbm_delete	  _ARGS((gdbm_file_info *dbf, datum key ));
+datum gdbm_fetch	  _ARGS((gdbm_file_info *dbf, datum key ));
+gdbm_file_info *gdbm_open _ARGS((char *file, int block_size,
+				 int flags, int mode,
+				 void (*fatal_func) (void), int need_filelock));
+int   gdbm_reorganize	  _ARGS((gdbm_file_info *dbf ));
+datum gdbm_firstkey       _ARGS((gdbm_file_info *dbf ));
+datum gdbm_nextkey        _ARGS((gdbm_file_info *dbf, datum key ));
+int   gdbm_store          _ARGS((gdbm_file_info *dbf, datum key,
+				 datum content, int flags ));
+int   gdbm_exists	  _ARGS((gdbm_file_info *dbf, datum key));
+void  gdbm_sync		  _ARGS((gdbm_file_info *dbf));
+int   gdbm_setopt	  _ARGS((gdbm_file_info *dbf, int optflag,
+				 int *optval, int optlen));
Index: /main/tags/2.25/gsdl/packages/wingdbm/systems.h
===================================================================
--- /main/tags/2.25/gsdl/packages/wingdbm/systems.h	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/wingdbm/systems.h	(revision 21064)
@@ -0,0 +1,195 @@
+/* systems.h - Most of the system dependant code and defines are here. */
+
+/*  This file is part of GDBM, the GNU data base manager, by Philip A. Nelson.
+    Copyright (C) 1990, 1991, 1993  Free Software Foundation, Inc.
+
+    GDBM 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, or (at your option)
+    any later version.
+
+    GDBM 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 GDBM; see the file COPYING.  If not, write to
+    the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+
+    You may contact the author by:
+       e-mail:  phil@wwu.edu
+      us-mail:  Philip A. Nelson
+                Computer Science Department
+                Western Washington University
+                Bellingham, WA 98226
+       
+*************************************************************************/
+
+
+#ifdef __GNUC__
+#define alloca	__builtin_alloca
+#else	/* not __GNUC__ */
+#ifdef HAVE_ALLOCA_H
+#include <alloca.h>
+#endif	/* not HAVE_ALLOCA_H */
+#endif 	/* not __GNUC__ */
+
+/* Include all system headers first. */
+#if HAVE_SYS_TYPES_H
+#include <sys/types.h>
+#endif
+
+#include <stdio.h>
+#if HAVE_SYS_FILE_H
+#include <sys/file.h>
+#endif
+
+#include <sys/stat.h>
+#if HAVE_STDLIB_H
+#include <stdlib.h>
+#endif
+
+#if HAVE_STRING_H
+#include <string.h>
+#else
+#include <strings.h>
+#endif
+
+#if HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+
+#if HAVE_FCNTL_H
+#include <fcntl.h>
+#endif
+
+#ifndef SEEK_SET
+#define SEEK_SET        0
+#endif
+
+#ifndef L_SET
+#define L_SET SEEK_SET
+#endif
+
+/* Do we have flock?  (BSD...) */
+
+#if HAVE_FLOCK
+
+#ifndef LOCK_SH
+#define LOCK_SH	1
+#endif
+
+#ifndef LOCK_EX
+#define LOCK_EX	2
+#endif
+
+#ifndef LOCK_NB
+#define LOCK_NB 4
+#endif
+
+#ifndef LOCK_UN
+#define LOCK_UN 8
+#endif
+
+#define UNLOCK_FILE(dbf) flock (dbf->desc, LOCK_UN)
+#define READLOCK_FILE(dbf) lock_val = flock (dbf->desc, LOCK_SH + LOCK_NB)
+#define WRITELOCK_FILE(dbf) lock_val = flock (dbf->desc, LOCK_EX + LOCK_NB)
+
+#else
+
+#ifdef MSDOS
+#define MY_UNLOCK    0
+#define MY_READLOCK  1
+#define MY_WRITELOCK 2
+int my_locking(int fh, int lmode, long lockoffset, long nbytes);
+
+#define UNLOCK_FILE(dbf)    my_locking(dbf->desc,MY_UNLOCK,0,10)
+#define READLOCK_FILE(dbf)  lock_val=my_locking(dbf->desc,MY_READLOCK,0,10)
+#define WRITELOCK_FILE(dbf)	lock_val=my_locking(dbf->desc,MY_WRITELOCK,0,10)
+
+#else
+/* Assume it is done like System V. */
+
+#define UNLOCK_FILE(dbf) \
+	{					\
+	  struct flock flock;			\
+	  flock.l_type = F_UNLCK;		\
+	  flock.l_whence = SEEK_SET;		\
+	  flock.l_start = flock.l_len = 0L;	\
+	  fcntl (dbf->desc, F_SETLK, &flock);	\
+	}
+#define READLOCK_FILE(dbf) \
+	{					\
+	  struct flock flock;			\
+	  flock.l_type = F_RDLCK;		\
+	  flock.l_whence = SEEK_SET;			\
+	  flock.l_start = flock.l_len = 0L;	\
+	  lock_val = fcntl (dbf->desc, F_SETLK, &flock);	\
+	}
+#define WRITELOCK_FILE(dbf) \
+	{					\
+	  struct flock flock;			\
+	  flock.l_type = F_WRLCK;		\
+	  flock.l_whence = SEEK_SET;			\
+	  flock.l_start = flock.l_len = 0L;	\
+	  lock_val = fcntl (dbf->desc, F_SETLK, &flock);	\
+	}
+#endif
+#endif
+
+/* Do we have bcopy?  */
+#if !HAVE_BCOPY
+#if HAVE_MEMORY_H
+#include <memory.h>
+#endif
+#define bcmp(d1, d2, n)	memcmp(d1, d2, n)
+#define bcopy(d1, d2, n) memcpy(d2, d1, n)
+#endif
+
+/* Do we have fsync? */
+#if !HAVE_FSYNC
+#ifdef MSDOS
+#define fsync(f)
+#else
+#define fsync(f) {sync(); sync();}
+#endif
+#endif
+
+/* Default block size.  Some systems do not have blocksize in their
+   stat record. This code uses the BSD blocksize from stat. */
+
+#if HAVE_ST_BLKSIZE
+#define STATBLKSIZE file_stat.st_blksize
+#else
+#define STATBLKSIZE 1024
+#endif
+
+/* Do we have ftruncate? */
+#if HAVE_FTRUNCATE
+#define TRUNCATE(dbf) ftruncate (dbf->desc, 0)
+#else
+#define TRUNCATE(dbf) close( open (dbf->name, O_RDWR|O_TRUNC|O_BINARY, mode));
+#endif
+
+/* Do we have 32bit or 64bit longs? */
+#if LONG_64_BITS || !INT_16_BITS
+typedef int word_t;
+#else
+typedef long word_t;
+#endif
+
+
+#include <io.h>
+
+#ifdef __GNUC__
+#define alloca __builtin_alloca
+#else /* not __GNUC__ */
+#if defined (HAVE_ALLOCA_H) || (defined(sparc) && (defined(sun) || (!defined(USG) && !defined(SVR4) && !defined(__svr4__))))
+#include <alloca.h>
+#else
+#ifndef _AIX
+char *alloca ();
+#endif
+#endif /* alloca.h */
+#endif /* not __GNUC__ */
Index: /main/tags/2.25/gsdl/packages/wingdbm/testgdbm.c
===================================================================
--- /main/tags/2.25/gsdl/packages/wingdbm/testgdbm.c	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/wingdbm/testgdbm.c	(revision 21064)
@@ -0,0 +1,546 @@
+/* testgdbm.c - Driver program to test the database routines and to
+   help debug gdbm.  Uses inside information to show "system" information */
+
+/*  This file is part of GDBM, the GNU data base manager, by Philip A. Nelson.
+    Copyright (C) 1990, 1991, 1993  Free Software Foundation, Inc.
+
+    GDBM 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, or (at your option)
+    any later version.
+
+    GDBM 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 GDBM; see the file COPYING.  If not, write to
+    the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+
+    You may contact the author by:
+       e-mail:  phil@cs.wwu.edu
+      us-mail:  Philip A. Nelson
+                Computer Science Department
+                Western Washington University
+                Bellingham, WA 98226
+       
+*************************************************************************/
+
+
+/* AIX demands this be the very first thing in the file. */
+#if !defined(__GNUC__) && defined(_AIX)
+ #pragma alloca
+#endif
+
+/* include system configuration before all else. */
+#include "autoconf.h"
+
+#include "gdbmdefs.h"
+#include "gdbmerrno.h"
+#include "extern.h"
+
+#include "getopt.h"
+
+extern const char * gdbm_version;
+
+extern const char *gdbm_strerror _ARGS((gdbm_error));
+
+gdbm_file_info *gdbm_file;
+
+/* Debug procedure to print the contents of the current hash bucket. */
+void
+print_bucket (bucket, mesg)
+     hash_bucket *bucket;
+     char *mesg;
+{
+  int  index;
+
+  printf ("******* %s **********\n\nbits = %d\ncount= %d\nHash Table:\n",
+	 mesg, bucket->bucket_bits, bucket->count);
+  printf ("     #    hash value     key size    data size     data adr  home\n");
+  for (index = 0; index < gdbm_file->header->bucket_elems; index++)
+    printf ("  %4d  %12x  %11d  %11d  %11d %5d\n", index,
+	   bucket->h_table[index].hash_value,
+	   bucket->h_table[index].key_size,
+	   bucket->h_table[index].data_size,
+	   bucket->h_table[index].data_pointer,
+	   bucket->h_table[index].hash_value % gdbm_file->header->bucket_elems);
+
+  printf ("\nAvail count = %1d\n", bucket->av_count);
+  printf ("Avail  adr     size\n");
+  for (index = 0; index < bucket->av_count; index++)
+    printf ("%9d%9d\n", bucket->bucket_avail[index].av_adr,
+	                bucket->bucket_avail[index].av_size);
+}
+
+
+void
+_gdbm_print_avail_list (dbf)
+     gdbm_file_info *dbf;
+{
+  int temp;
+  int size;
+  avail_block *av_stk;
+ 
+  /* Print the the header avail block.  */
+  printf ("\nheader block\nsize  = %d\ncount = %d\n",
+	  dbf->header->avail.size, dbf->header->avail.count);
+  for (temp = 0; temp < dbf->header->avail.count; temp++)
+    {
+      printf ("  %15d   %10d \n", dbf->header->avail.av_table[temp].av_size,
+	      dbf->header->avail.av_table[temp].av_adr);
+    }
+
+  /* Initialize the variables for a pass throught the avail stack. */
+  temp = dbf->header->avail.next_block;
+  size = ( ( (dbf->header->avail.size * sizeof (avail_elem)) >> 1)
+	  + sizeof (avail_block));
+  av_stk = (avail_block *) alloca (size);
+
+  /* Print the stack. */
+  while (FALSE)
+    {
+      lseek (dbf->desc, temp, L_SET);
+      read  (dbf->desc, av_stk, size);
+
+      /* Print the block! */
+      printf ("\nblock = %d\nsize  = %d\ncount = %d\n", temp,
+	      av_stk->size, av_stk->count);
+      for (temp = 0; temp < av_stk->count; temp++)
+	{
+	  printf ("  %15d   %10d \n", av_stk->av_table[temp].av_size,
+	    av_stk->av_table[temp].av_adr);
+	}
+      temp = av_stk->next_block;
+    }
+}
+
+void
+_gdbm_print_bucket_cache (dbf)
+     gdbm_file_info *dbf;
+{
+  register int index;
+  char changed;
+ 
+  if (dbf->bucket_cache != NULL) {
+    printf(
+      "Bucket Cache (size %d):\n  Index:  Address  Changed  Data_Hash \n",
+      dbf->cache_size);
+    for (index=0; index < dbf->cache_size; index++) {
+      changed = dbf->bucket_cache[index].ca_changed;
+      printf ("  %5d:  %7d  %7s  %x\n",
+	      index,
+	      dbf->bucket_cache[index].ca_adr,
+	      (changed ? "True" : "False"),
+	      dbf->bucket_cache[index].ca_data.hash_val);
+    }
+  } else
+    printf("Bucket cache has not been initialized.\n");
+}
+
+void
+usage (s)
+     char *s;
+{
+  printf(
+      "Usage: %s [-r or -nf] [-b block-size] [-c cache-size] [-g gdbm-file]\n",
+      s);
+  exit (2);
+}
+
+void
+print_keydatum (kd)
+  datum kd;
+{
+  char data[10240];
+  int num = kd.dsize;
+
+  if (num > 10230) num = 10230;
+  strncpy (data, kd.dptr, num);
+  data[num]='\0';
+  printf ("key is  ->\"%s\"\n", data);
+}
+
+void
+print_valuedatum (kd)
+  datum kd;
+{
+  char data[10240];
+  int num = kd.dsize;
+
+  if (num > 10230) num = 10230;
+  strncpy (data, kd.dptr, num);
+  data[num]='\0';
+  printf ("data is  ->\"%s\"\n", data);
+}
+
+
+/* The test program allows one to call all the routines plus the hash function.
+   The commands are single letter commands.  The user is prompted for all other
+   information.  See the help command (?) for a list of all commands. */
+
+int
+main (argc, argv)
+     int argc;
+     char *argv[];
+
+{
+
+  char  cmd_ch;
+
+  datum key_data;
+  datum data_data;
+  datum return_data;
+
+  char key_line[500];
+  char data_line[1000];
+
+  char done = FALSE;
+  int  opt;
+  char reader = FALSE;
+  char newdb = FALSE;
+  int  fast  = 0;
+
+  int  cache_size = DEFAULT_CACHESIZE;
+  int  block_size = 0;
+
+  char *file_name = NULL;
+
+
+  /* Argument checking. */
+  opterr = 0;
+  while ((opt = getopt (argc, argv, "frnc:b:g:")) != -1)
+    switch (opt) {
+    case 'f':  fast = GDBM_FAST;
+               if (reader) usage (argv[0]);
+               break;
+    case 'r':  reader = TRUE;
+               if (newdb) usage (argv[0]);
+               break;
+    case 'n':  newdb = TRUE;
+               if (reader) usage (argv[0]);
+               break;
+    case 'c':  cache_size = atoi(optarg);
+    	       break;
+    case 'b':  block_size = atoi(optarg);
+               break;
+    case 'g':  file_name = optarg;
+               break;
+    default:  usage(argv[0]);
+    }
+
+  if(file_name == NULL) 
+    file_name = "junk.gdbm";
+
+  /* Initialize variables. */
+  key_data.dptr = NULL;
+  data_data.dptr = data_line;
+
+  if (reader)
+    {
+      gdbm_file = gdbm_open (file_name, block_size, GDBM_READER, 00664, NULL);
+    }
+  else if (newdb)
+    {
+      gdbm_file =
+    	gdbm_open (file_name, block_size, GDBM_NEWDB | fast, 00664, NULL);
+    }
+  else
+    {
+      gdbm_file =
+    	gdbm_open (file_name, block_size, GDBM_WRCREAT | fast, 00664, NULL);
+    }
+  if (gdbm_file == NULL)
+    {
+      printf("gdbm_open failed, %s\n", gdbm_strerror(gdbm_errno));
+      exit (2);
+    }
+
+  if (gdbm_setopt(gdbm_file, GDBM_CACHESIZE, &cache_size, sizeof(int)) == -1)
+    {
+      printf("gdbm_setopt failed, %s\n", gdbm_strerror(gdbm_errno));
+      exit(2);
+    }
+
+  /* Welcome message. */
+  printf ("\nWelcome to the gdbm test program.  Type ? for help.\n\n");
+  
+  while (!done)
+    {
+      printf ("com -> ");
+      cmd_ch = getchar ();
+      if (cmd_ch != '\n')
+	{
+	  char temp;
+	  do
+	      temp = getchar ();
+	  while (temp != '\n' && temp != EOF);
+	}
+      if (cmd_ch == EOF) cmd_ch = 'q';
+      switch (cmd_ch)
+	{
+	
+	/* Standard cases found in all test{dbm,ndbm,gdbm} programs. */
+	case '\n':
+	  printf ("\n");
+	  break;
+
+	case 'c':
+	  {
+	    int temp;
+	    temp = 0;
+	    if (key_data.dptr != NULL) free (key_data.dptr);
+	    return_data = gdbm_firstkey (gdbm_file);
+	    while (return_data.dptr != NULL)
+	      {
+		temp++;
+		key_data = return_data;
+		return_data = gdbm_nextkey (gdbm_file, key_data);
+		free (key_data.dptr);
+	      }
+	    printf ("There are %d items in the database.\n\n", temp);
+	    key_data.dptr = NULL;
+	  }
+	  break;
+
+	case 'd':
+	  if (key_data.dptr != NULL) free (key_data.dptr);
+	  printf ("key -> ");
+	  gets (key_line);
+	  key_data.dptr = key_line;
+	  key_data.dsize = strlen (key_line);
+	  /*	  key_data.dsize = strlen (key_line)+1;*/
+	  if (gdbm_delete (gdbm_file, key_data) != 0)
+	    printf ("Item not found or deleted\n");
+	  printf ("\n");
+	  key_data.dptr = NULL;
+	  break;
+
+	case 'f':
+	  if (key_data.dptr != NULL) free (key_data.dptr);
+	  printf ("key -> ");
+	  gets (key_line);
+	  key_data.dptr = key_line;
+	  key_data.dsize = strlen (key_line);
+	  /*	  key_data.dsize = strlen (key_line)+1;*/
+	  return_data = gdbm_fetch (gdbm_file, key_data);
+	  if (return_data.dptr != NULL)
+	    {
+	      print_valuedatum(return_data);
+	      /*	      printf ("data is ->%s\n\n", return_data.dptr); */
+	      free (return_data.dptr);
+	    }
+	  else
+	    printf ("No such item found.\n\n");
+	  key_data.dptr = NULL;
+	  break;
+
+	case 'n':
+	  if (key_data.dptr != NULL) free (key_data.dptr);
+	  printf ("key -> ");
+	  gets (key_line);
+	  key_data.dptr = key_line;
+	  key_data.dsize = strlen (key_line);
+	  /*	  key_data.dsize = strlen (key_line)+1;*/
+	  return_data = gdbm_nextkey (gdbm_file, key_data);
+	  if (return_data.dptr != NULL)
+	    {
+	      key_data = return_data;
+	      print_keydatum(key_data);
+	      /*	      printf ("key is  ->%s\n", key_data.dptr); */
+	      return_data = gdbm_fetch (gdbm_file, key_data);
+	      print_valuedatum(return_data);
+	      /*	      printf ("data is ->%s\n\n", return_data.dptr); */
+	      free (return_data.dptr);
+	    }
+	  else
+	    {
+	      printf ("No such item found.\n\n");
+	      key_data.dptr = NULL;
+	    }
+	  break;
+
+	case 'q':
+	  done = TRUE;
+	  break;
+
+	case 's':
+	  if (key_data.dptr != NULL) free (key_data.dptr);
+	  printf ("key -> ");
+	  gets (key_line);
+	  key_data.dptr = key_line;
+	  key_data.dsize = strlen (key_line);
+	  /*	  key_data.dsize = strlen (key_line)+1;*/
+	  printf ("data -> ");
+	  gets (data_line);
+	  data_data.dsize = strlen (data_line);
+	  /* data_data.dsize = strlen (data_line)+1;*/
+	  if (gdbm_store (gdbm_file, key_data, data_data, GDBM_REPLACE) != 0)
+	    printf ("Item not inserted. \n");
+	  printf ("\n");
+	  key_data.dptr = NULL;
+	  break;
+
+	case '1':
+	  if (key_data.dptr != NULL) free (key_data.dptr);
+	  key_data = gdbm_firstkey (gdbm_file);
+	  if (key_data.dptr != NULL)
+	    {
+	      print_keydatum(key_data);
+	      /*	      printf ("key is  ->%s\n", key_data.dptr); */
+	      return_data = gdbm_fetch (gdbm_file, key_data);
+	      print_valuedatum(return_data);
+	      /*	      printf ("data is ->%s\n\n", return_data.dptr); */
+	      free (return_data.dptr);
+	    }
+	  else
+	    printf ("No such item found.\n\n");
+	  break;
+
+	case '2':
+	  return_data = gdbm_nextkey (gdbm_file, key_data);
+	  if (return_data.dptr != NULL)
+	    {
+	      free (key_data.dptr);
+	      key_data = return_data;
+	      print_keydatum(key_data);
+	      /*	      printf ("key is  ->%s\n", key_data.dptr); */
+	      return_data = gdbm_fetch (gdbm_file, key_data);
+	      print_valuedatum(return_data);
+	      /*	      printf ("data is ->%s\n\n", return_data.dptr); */
+	      free (return_data.dptr);
+	    }
+	  else
+	    printf ("No such item found.\n\n");
+	  break;
+
+
+	/* Special cases for the testgdbm program. */
+	case 'r':
+	  {
+	    if (gdbm_reorganize (gdbm_file))
+	      printf ("Reorganization failed. \n\n");
+	    else
+	      printf ("Reorganization succeeded. \n\n");
+	  }
+	  break;
+
+	case 'A':
+	  _gdbm_print_avail_list (gdbm_file);
+	  printf ("\n");
+	  break;
+
+	case 'B':
+	  {
+	    int temp;
+	    char number[80];
+
+	    printf ("bucket? ");
+	    gets (number);
+	    sscanf (number,"%d",&temp);
+
+	    if (temp >= gdbm_file->header->dir_size /4)
+	      {
+		printf ("Not a bucket. \n\n");
+		break;
+	      }
+	    _gdbm_get_bucket (gdbm_file, temp);
+	  }
+	  printf ("Your bucket is now ");
+
+	case 'C':
+	  print_bucket (gdbm_file->bucket, "Current bucket");
+	  printf ("\n current directory entry = %d.\n", gdbm_file->bucket_dir);
+	  printf (" current bucket address  = %d.\n\n",
+		  gdbm_file->cache_entry->ca_adr);
+	  break;
+
+	case 'D':
+	  printf ("Hash table directory.\n");
+	  printf ("  Size =  %d.  Bits = %d. \n\n",gdbm_file->header->dir_size,
+		  gdbm_file->header->dir_bits);
+	  {
+	    int temp;
+
+	    for (temp = 0; temp < gdbm_file->header->dir_size / 4; temp++)
+	      {
+		printf ("  %10d:  %12d\n", temp, gdbm_file->dir[temp]);
+		if ( (temp+1) % 20 == 0 && isatty (0))
+		  {
+		    printf ("*** CR to continue: ");
+		    while (getchar () != '\n') /* Do nothing. */;
+		  }
+	      }
+	  }
+	  printf ("\n");
+	  break;
+
+	case 'F':
+	  {
+	    printf ("\nFile Header: \n\n");
+	    printf ("  table        = %d\n", gdbm_file->header->dir);
+	    printf ("  table size   = %d\n", gdbm_file->header->dir_size);
+	    printf ("  table bits   = %d\n", gdbm_file->header->dir_bits);
+	    printf ("  block size   = %d\n", gdbm_file->header->block_size);
+	    printf ("  bucket elems = %d\n", gdbm_file->header->bucket_elems);
+	    printf ("  bucket size  = %d\n", gdbm_file->header->bucket_size);
+	    printf ("  header magic = %x\n", gdbm_file->header->header_magic);
+	    printf ("  next block   = %d\n", gdbm_file->header->next_block);
+	    printf ("  avail size   = %d\n", gdbm_file->header->avail.size);
+	    printf ("  avail count  = %d\n", gdbm_file->header->avail.count);
+	    printf ("  avail nx blk = %d\n", gdbm_file->header->avail.next_block);
+	    printf ("\n");
+	  }
+	  break;
+
+        case 'H':
+	  if (key_data.dptr != NULL) free (key_data.dptr);
+	  printf ("key -> ");
+	  gets (key_line);
+	  key_data.dptr = key_line;
+	  key_data.dsize = strlen (key_line)+1;
+	  printf ("hash value = %x. \n\n", _gdbm_hash (key_data));
+	  key_data.dptr = NULL;
+	  break;
+
+	case 'K':
+	  _gdbm_print_bucket_cache (gdbm_file);
+	  break;
+
+	case 'V':
+	  printf ("%s\n\n", gdbm_version);
+	  break;
+
+	case '?':
+	  printf ("c - count (number of entries)\n");
+	  printf ("d - delete\n");
+	  printf ("f - fetch\n");
+	  printf ("n - nextkey\n");
+	  printf ("q - quit\n");
+	  printf ("s - store\n");
+	  printf ("1 - firstkey\n");
+	  printf ("2 - nextkey on last key (from n, 1 or 2)\n\n");
+
+	  printf ("r - reorganize\n");
+	  printf ("A - print avail list\n");
+	  printf ("B - get and print current bucket n\n");
+	  printf ("C - print current bucket\n");
+	  printf ("D - print hash directory\n");
+	  printf ("F - print file header\n");
+	  printf ("H - hash value of key\n");
+	  printf ("K - print the bucket cache\n");
+	  printf ("V - print version of gdbm\n");
+	  break;
+
+	default:
+	  printf ("What? \n\n");
+	  break;
+
+	}
+    }
+
+  /* Quit normally. */
+  exit (0);
+
+}
Index: /main/tags/2.25/gsdl/packages/wingdbm/update.c
===================================================================
--- /main/tags/2.25/gsdl/packages/wingdbm/update.c	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/wingdbm/update.c	(revision 21064)
@@ -0,0 +1,126 @@
+/* update.c - The routines for updating the file to a consistent state. */
+
+/*  This file is part of GDBM, the GNU data base manager, by Philip A. Nelson.
+    Copyright (C) 1990, 1991, 1993  Free Software Foundation, Inc.
+
+    GDBM 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, or (at your option)
+    any later version.
+
+    GDBM 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 GDBM; see the file COPYING.  If not, write to
+    the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+
+    You may contact the author by:
+       e-mail:  phil@cs.wwu.edu
+      us-mail:  Philip A. Nelson
+                Computer Science Department
+                Western Washington University
+                Bellingham, WA 98226
+       
+*************************************************************************/
+
+
+/* include system configuration before all else. */
+#include "autoconf.h"
+
+#include "gdbmdefs.h"
+
+static void write_header _ARGS((gdbm_file_info *));
+
+/* This procedure writes the header back to the file described by DBF. */
+
+static void
+write_header (dbf)
+     gdbm_file_info *dbf;
+{
+  int  num_bytes;	/* Return value for write. */
+  off_t file_pos;	/* Return value for lseek. */
+
+  file_pos = lseek (dbf->desc, 0L, L_SET);
+  if (file_pos != 0) _gdbm_fatal (dbf, "lseek error");
+  num_bytes = write (dbf->desc, dbf->header, dbf->header->block_size);
+  if (num_bytes != dbf->header->block_size)
+    _gdbm_fatal (dbf, "write error");
+
+  /* Wait for all output to be done. */
+  if (!dbf->fast_write)
+    fsync (dbf->desc);
+}
+
+
+/* After all changes have been made in memory, we now write them
+   all to disk. */
+void
+_gdbm_end_update (dbf)
+     gdbm_file_info *dbf;
+{
+  int  num_bytes;	/* Return value for write. */
+  off_t file_pos;	/* Return value for lseek. */
+  
+  
+  /* Write the current bucket. */
+  if (dbf->bucket_changed && (dbf->cache_entry != NULL))
+    {
+      _gdbm_write_bucket (dbf, dbf->cache_entry);
+      dbf->bucket_changed = FALSE;
+    }
+
+  /* Write the other changed buckets if there are any. */
+  if (dbf->second_changed)
+    {
+      if(dbf->bucket_cache != NULL)
+        {
+          register int index;
+
+          for (index = 0; index < dbf->cache_size; index++)
+	    {
+	      if (dbf->bucket_cache[index].ca_changed)
+	        _gdbm_write_bucket (dbf, &dbf->bucket_cache[index]);
+            }
+        }
+      dbf->second_changed = FALSE;
+    }
+  
+  /* Write the directory. */
+  if (dbf->directory_changed)
+    {
+      file_pos = lseek (dbf->desc, dbf->header->dir, L_SET);
+      if (file_pos != dbf->header->dir) _gdbm_fatal (dbf, "lseek error");
+      num_bytes = write (dbf->desc, dbf->dir, dbf->header->dir_size);
+      if (num_bytes != dbf->header->dir_size)
+	_gdbm_fatal (dbf, "write error");
+      dbf->directory_changed = FALSE;
+      if (!dbf->header_changed && !dbf->fast_write)
+	fsync (dbf->desc);
+    }
+
+  /* Final write of the header. */
+  if (dbf->header_changed)
+    {
+      write_header (dbf);
+      dbf->header_changed = FALSE;
+    }
+}
+
+
+/* If a fatal error is detected, come here and exit. VAL tells which fatal
+   error occured. */
+int
+_gdbm_fatal (dbf, val)
+     gdbm_file_info *dbf;
+     char *val;
+{
+  if (dbf->fatal_err != NULL)
+    (*dbf->fatal_err) (val);
+  else
+    fprintf (stderr, "gdbm fatal: %s.\n", val);
+  exit (-1);
+  /* NOTREACHED */
+}
Index: /main/tags/2.25/gsdl/packages/wingdbm/version.c
===================================================================
--- /main/tags/2.25/gsdl/packages/wingdbm/version.c	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/wingdbm/version.c	(revision 21064)
@@ -0,0 +1,33 @@
+/* version.c - This is file contains the version number for gdbm source. */
+
+/*  This file is part of GDBM, the GNU data base manager, by Philip A. Nelson.
+    Copyright (C) 1990, 1991, 1993  Free Software Foundation, Inc.
+
+    GDBM 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, or (at your option)
+    any later version.
+
+    GDBM 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 GDBM; see the file COPYING.  If not, write to
+    the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+
+    You may contact the author by:
+       e-mail:  phil@cs.wwu.edu
+      us-mail:  Philip A. Nelson
+                Computer Science Department
+                Western Washington University
+                Bellingham, WA 98226
+       
+*************************************************************************/
+
+#include "autoconf.h"
+
+/* Keep a string with the version number in it! */
+const char * gdbm_version =
+	"This is GDBM version 1.7.3, as of May 19, 1994.";
Index: /main/tags/2.25/gsdl/packages/wingdbm/win32.mak
===================================================================
--- /main/tags/2.25/gsdl/packages/wingdbm/win32.mak	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/wingdbm/win32.mak	(revision 21064)
@@ -0,0 +1,69 @@
+###########################################################################
+#
+# win32 makefile -- wingdbm
+# A component of the Greenstone digital library software
+# from the New Zealand Digital Library Project at the
+# University of Waikato, New Zealand.
+#
+# Copyright (C) 1999  The 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.
+#
+###########################################################################
+
+GSDLHOME = d:\home\dl\gsdl
+srcdir = $(GSDLHOME)\packages\wingdbm
+
+AR = lib
+CC = cl
+CPPFLAGS =
+DEFS = -D__WIN32__
+LDFLAGS =
+
+COMPILE = $(CC) -c $(CPPFLAGS) $(DEFS) -I. -I$(srcdir) $(CFLAGS)
+LINK = $(CC) $(LDFLAGS)
+
+o = .obj
+
+.SUFFIXES:
+.SUFFIXES: .c $o
+
+.c$o:
+	$(COMPILE) $<
+
+HEADERS = gdbmdefs.h extern.h gdbmerrno.h systems.h gdbmconst.h \
+          proto.h
+
+SOURCES = gdbmopen.c gdbmdelete.c gdbmfetch.c  gdbmstore.c gdbmclose.c \
+	  gdbmreorg.c gdbmseq.c gdbmsync.c gdbmerrno.c gdbmexists.c gdbmsetopt.c \
+	  bucket.c falloc.c findkey.c global.c hash.c update.c \
+	  version.c alloca.c
+
+OBJECTS = gdbmopen$o gdbmdelete$o gdbmfetch$o  gdbmstore$o gdbmclose$o \
+	  gdbmreorg$o gdbmseq$o gdbmsync$o gdbmerrno$o gdbmexists$o gdbmsetopt$o \
+	  bucket$o falloc$o findkey$o global$o hash$o update$o \
+	  version$o alloca$o
+
+all: gdbm.lib
+
+gdbm.lib: $(OBJECTS) gdbm.h
+	  del gdbm.lib
+	  $(AR) /out:gdbm.lib $(OBJECTS) 
+
+install:
+
+clean:
+	del gdbm.lib *$o
Index: /main/tags/2.25/gsdl/packages/yaz/CHANGELOG
===================================================================
--- /main/tags/2.25/gsdl/packages/yaz/CHANGELOG	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/yaz/CHANGELOG	(revision 21064)
@@ -0,0 +1,541 @@
+Possible compatibility problems with earlier versions marked with '*'.
+
+--- 1.6 2000/03/03
+
+Added configure option --enable-comp/disable-comp to control use
+of YAZ ASN.1 compiler. Use --disable-comp to use the old *coders
+located in sub directory asn.
+
+YAZ ASN.1 compiler renamed to yaz-comp in sub directory. It's installed
+in ${exec_prefix}/bin along with the other programs yaz-client and
+yaz-ztest.
+
+GNU automake used to maintain makefiles.
+
+Added several OID's.
+
+Changed retrieval module so that we can load records with no abstract
+syntax defined. Tagpaths in these records are fully composed of string
+tags.
+
+Implemented ISO ILL protocol. Refer to stuff in sub directory ill.
+
+--- 1.5 1999/12/10
+
+On UNIX, the generated makefile now supports a proper 'make install'.
+The prefix can be set via GNU configure to set the install location
+(default is /usr/local).
+
+* YAZ programs client and ztest were renamed to yaz-client and
+yaz-ztest to avoid conflicts when users install YAZ in "standard"
+locations, such as /usr/bin,/usr/local/bin,etc.
+
+* YAZ Header files were moved from include to include/yaz. YAZ Header
+files are referred to as include <yaz/log.h> rather than <log.h>.
+The YAZ include path (-I ..) is therefore the same as before. Programmers
+should update their #include statements or use -Ipath/include/yaz
+instead. The main motivation for doing this change is that YAZ header files
+can be installed in "standard" locations /usr/include,/usr/local/include 
+without introducing conflicts, since ALL YAZ header files are stored
+in subdirectory yaz (under /usr/include for example).
+
+Compilation of YAZ for WIN32 is now handled by an nmake-style makefile 
+rather than project/workspace files. We switched because project files
+are incompatible between Visual C++ 5 and 6. Refer to windows.txt for
+details.
+
+Changed name of logging function, logf, to yaz_log, to prevent name
+clash with some math-log functions. The YAZ header log.h defines logf
+to yaz_log (#define) so there should be no incompatibilities by this
+modification.
+
+Added bend_start/bend_stop handlers for server. These handler are
+called on start/stop of server. For windows they are called whenever
+a service is started/stopped.
+
+* YAZ now auto-generates decoders/encoders for the Z39.50 protocol using
+a fairly small ASN.1 compiler written in Tcl. The compiler is located
+in util/yc.tcl. The auto-generated C code structures are, in a few
+cases, incompatible with the old decoders. There are differences in the
+following C structures Z_DiagRec, Z_External, Z_SortRequest, Z_SortResponse,
+Z_AttributesPlusTerm, Z_ProximityOperator, Z_DefaultDiagFormat.
+The preprocessor variable ASN_COMPILED is defined when the compiled
+ASN.1 is being used. Encoder/decoder routines as well as the Z39.50
+protocol ASN.1 is located sub directory <tt>z39.50</tt>. If you
+wish to use the old encoders/decoders you can specify --disable-yc
+for configure.
+
+Assigned OID for old DB Update (VAL_DBUPDATE0). Updated YAZ compiled
+version so that it supports both new - and old version of DB Update
+
+* Added 'name' parameter to ODR encoder/decoder routines to facilitate
+pretty ODR print. Updated whole Z39.50 encoder/decoder to reflect the
+change. The name parameter can be set to 0 in which no name is specified
+for the construction. The macros odr_implicit and odr_explicit sets name
+parameter to zero for the construction involved. New macros
+odr_implicit_tag and odr_explicit_tag are similar to the others,
+except that a name parameter is added. For programmers' that don't use
+ODR they probably only need to change the call to z_APDU and z_External.
+
+Added access control facility by interfacing the TCP wrapper library.
+YAZ automatically attempts to find the TCP wrapper Library (-lwrap) and
+tcpd.h on Unix systems. For the server, option -d<daemon> specifies the
+name of the daemon and enables the access control as specified in
+hosts.allow/hosts.deny. Refer to man pages tcpd(8) and hosts_access(5).
+
+Fixed memory leak in ccl_find_str and ccl_qual_rm. Thanks to Hans van
+den Dool <H.M.vdnDool@kub.nl>.
+
+Added reference ID parameter to most functions in server API - refer
+to backend.h. Thanks to Hans van den Dool <H.M.vdnDool@kub.nl>.
+
+Changed name of ccl library to libccl.a (was ccl.a).
+
+Fixed bug in decoder for Explain (Category TargetInfo).
+
+Added support for GNU readline in client. Thanks to Jacob Poulsen
+<ja7@dbc.dk>. GNU configure attempts to detect if readline is available.
+
+* CHANGED DEFINITION OF ES: UPDATE (INCLUDING THE OID) to reflect the
+new definition from the ZIG. NOTE THIS IF YOU HAVE AN UPDATE
+IMPLEMENTATION! This change was made to the development version before
+the ZIG decided to retract the amendment. If any users MUST be
+compatible with the original Update definition, PLEASE CONTACT US, and
+we will include a separate definition corresponding to the old Update
+ES. Note that because of the change to the ASN.1 of the
+TaskPackageRecordStructure we cannot define a single structure that
+will support both versions.
+
+* Added const modifier to buffer parameter for some ODR/BER encoding
+routines: ber_dectag, ber_declen, odp_more_chunks, completeBER,
+completeWAIS, odr_dumpBER.
+
+Fixed bug in client.c which caused a crash when a scanResponse didn't
+contain positionOfTerm.
+
+* Fixed inconsistency in the ScanResponse/ListEntries protocol. This
+* will cause an error in a client if a non-YAZ target sends both a
+* list of Scan entries and non-surrogate diagnostics.
+
+Retrieval module enhancements. Tag sets may be typed in the reference
+to it. From the .abs-file the "tagset" directive takes a third optional
+integer type for the tag set referenced. From a .tag-file the "include"
+directive takes a third optional type as well. The old "type" directive
+in the tag set itself is still recognized but acts as the default type
+for the tag set.
+
+Backend interface change. Individual Scan terms returned from bend_scan
+may also be tagged as Surrogate Diagnostics. Refer to struct scan_entry
+in include/backend.h.
+
+Retrieval module enhancements. Multiple tag sets and attribute sets may
+be specified in abstract syntax specs. Revised the error/warning for
+logging messages reported by the retrieval module when reading the
+various spec files.
+
+Object Identifier system (oid_..) changed. The API is backwards
+compatible but the oid-routines now allocates new OID's when needed.
+Raw OID's may be specified in oid_getvalbyname.
+
+YAZ now uses GNU configure to generate Makefile(s).
+
+* Minor changes in some of the member names of DeleteResultSetRequest and
+DeleteResultSetResponse. See include/proto.h.
+
+* Changed some C definitions regarding EXPLAIN record syntax (prt-exp.h)
+and added member 'languages' in TargetInfo (which was missing).
+
+Changed the way attribute sets are handled in the retrieval
+module. These are now cached, just like the abstract syntaxes
+(schemas).
+
+Changed YAZ so that it links with compiled ASN.1.
+
+Added Explain-schema definitions and mapping routines. The following
+Explain categories have been implemented: AttributeDetails,
+AttributeSetInfo, DatabaseInfo, CategoryList and TargetInfo.
+
+Fixed minor bug in Windows version of Server Library.
+
+--- 1.4pl2+ 1998/4/17 (Released with Zebra)
+
+Added Extended Services to server (backend.h). Thanks to Charles Woodfield.
+
+Added EXTERNAL: UNIverse Resource Report (non-standard).
+
+Implemened odr_enum and odr_set_of functions to handle ASN.1 types
+ENUMERATED and SET OF.
+
+* Added 'const' to some of the char pointer arguments for the
+functions, data1_read_node, data1_getelementbytagname,
+data1_insert_taggeddata, data1_getesetbyname, data1_getelementbyname,
+data1_get_absyn.
+
+Fixed bug in data1_insert_taggeddata - the last_child member of
+parent wasn't initialised.
+
+* Changed data1_read_record and data1_read_node so that the supplied
+"SGML"-buffer is read-only. In particular the resulting data1 - tree
+doesn't refer to any parts of the "SGML"-buffer.
+
+Fixed bug in server library (Windows version of statserv_remove).
+
+* Changed code so that it compiles as C++. The type definition
+of Odr_fun which is a member of Odr_arm was changed. The result is,
+that an explicit typecast is needed for the fun pointer when
+using Odr_arm - as in:
+    {1, -1, -1, Z_IdAuthentication_idPass, (Odr_fun)z_IdPass},
+
+Updated TagSet-G and -M definitions (tagsetm.tag and tagsetg.tag).
+
+Implemented the new structured date and time definition as approved
+by the ZIG. Added schemaId element to the specificTag in Espec-1
+(also approved at the last ZIG). Thanks to RVDM.
+
+Added some Object identifiers (RVDM).
+
+Changed the Update Extended Service (RVDM).
+
+Added command "refid" to client which specifies referenceId for
+the following requests.
+
+Implemented extended service handling for server. See ztest.c
+for an example as well as backend.h. New handlers are registerd
+in the Init handler.
+
+* Changed interface for sort in server.
+
+Added new members to statserv_options_block. It allows a server
+to read options from another source than just the command line. Thanks
+to Charles Woodfield.
+
+* Changed definition of Z_Triple in file prt-grs.h - member boolean
+renamed to zboolean. Some C++ compilers complained about the name.
+
+Minor changes to gils.abs. Added index 's' (sort) on title
+and date/time-last-modified.
+
+--- 1.4pl2 1998/1/30
+
+Fixed bug in server library regarding inetd mode (-i). This bug
+was introduced by release 1.4.
+
+--- 1.4pl1 1998/1/29
+
+Added sort facility in client and backend server interface.
+
+Fixed problem with dependencies in Makefile(s).
+
+Fixed bugs for encoders/decoders of extended services and 
+SearchInfoReport.
+
+Implemented sub-tree feature for schemas. Sub-trees are
+referenced in *.abs-files. See explain.abs for an example
+of the use of this feature.
+
+Modified bib1.att; local attributes for ANY didn't include
+ANY itself (only affects use of the retrieval module).
+
+Fixed bug in plain SGML reader in function data1_read_node:
+tags with prefix "var" was incorrectly interpreted as variants.
+
+Added feature "sub-schemas" to enable references to - and definitions
+of - group of elements.
+
+* Removed member parent from type data1_element (in data1.h).
+
+Implemented function odr_nullval() that returns the value of
+ODR_NULLVAL.
+
+* Removed member num_children from data1_node (in data1.h).
+
+Made NT service interface part of the server library. The
+function statserv_main uses the NT service when required and
+calls the statserv_start / statserv_close routines.
+
+Routine zget_SearchRequest and zget_PresentRequest fills
+resultSetName/Id member with "default" instead of "Default".
+
+Fixed memory leak in server. Request queue member wasn't freed.
+
+Fixed nmem_exit so that memory is freed.
+
+--- 1.4 1997/10/2
+
+Revised the CCL parser utility to be thread safe.
+
+Added function, oid_ent_to_oid, to replace the function 
+oid_getoidbyent, which is not thread safe.
+
+* Added nmem_init and nmem_exit to initialize and release
+NMEM resources. Function nmem_init should be called once in the
+initial thread before NMEM/ODR is used. statserv.c and client.c
+have been changed accordingly. The change was necessary to make
+NMEM thread safe. The NMEM memory pool is shared amongst threads
+in a process. Unix-based applications will still work fine without
+calling this.
+
+Added NT Services interface for the the Z39.50 (statserv) Server. 
+Refer to the ztest.c source on the usage.
+
+Windows 95/NT port using MSVC5.0. Project files are included in the
+distribution.
+
+* Defined new 'global' handle for the retrieval (data1) system. The
+new handled, data1_handle, describes the state of the data1 system.
+This handle is passed as first argument to virtually all
+data1 related routines. The functions data1_create and data1_destroy
+creates and destroys a data1 handle respectively.
+
+Added ODR encode stream member to all backend request structures
+init, search, scan etc. This stream should be used to allocate all
+memory used for the response when thread safe operation is needed.
+
+Changed the comstack utility, cs_addstr, to be thread safe. The
+returned hostname string returned by the function is now part the
+COMSTACK instance.
+
+Added comstack utility, cs_straddr, which replaces the tcpip_strtoaddr
+function. The cs_straddr takes a COMSTACK handle as argument, so this
+function must be used after cs_create and before bind/connect.
+This function is thread safe.
+
+Moved test server to 'ztest' directory - generic server code still
+in 'server' directory.
+
+Made prefix query (pquery.c) utility thread safe.
+
+Added new function modifier YAZ_EXPORT to 'export' public DLL
+functions when using windows (see include/yconfig.h).
+
+Added definitions to the OID database (util/oid.c) (RVDM).
+
+Added new BIB-1 diagnostic messages to the handler diagbib1_str.
+
+Added call to ccl_rpn_delete in client program.
+
+Added ODR argument to ccl_rpn_query and ccl_scan_query to provide
+release of RPN structure.
+
+Added support for C++, headers uses extern "C" for public definitions.
+With input from RVDM.
+
+In handling of SEQUENCE OF: Counter set to zero when SEQUENCE OF is absent.
+Thanks to Ronald van der Meer (RVDM).
+
+Added initializers (zget_ routines) for a number of PDUs. Thanks to RVDM.
+
+Added support for private extensions to the OID database
+(oid_setprivateoids()). Thanks to RVDM.
+    
+Added optional, physical ANY (key replication)
+
+Fixed null-reference problem in GRS-1 output filter.
+
+Proximity operator added to Prefix Query Format (PQF).
+
+In test client command "base" accepts multiple databases.
+
+Fixed bug in cs_close stack that caused trouble with WINSOCK.
+
+--- 1.3 1996/10/11
+
+Fixed tagging bug in ResourceReportResponse PDU encoder/decode.
+
+Smallish bug-fixes in the new encoders/decoders (explain).
+
+Bug fixed in DeleteRequest.
+
+Fixed tagging bug of type 101 query in SearchRequest-Query PDU encoder/decoder.
+
+Fixed tagging bug in ResourceReportResponse PDU encoder/decode.
+
+Added SOIF syntax (using private OID for now) to retrieval module and client.
+
+Added Update extended service.
+
+Added SearchResult-1 additional info structure.
+
+Added optional CCL (ISO8777) interpreter as separate module. Available
+in linemode client.
+
+--- 1.2 1996/6/10 (1st anniversary release)
+
+Added Summary record syntax. Lightly tested.
+
+Added OPAC record syntax. Untested.
+
+Added ResourceReport service encoders/decoders. Untested.
+
+Fixed bug in z_Unit - wrong tagging on unitSystem.
+
+Fixed bug in the DiagRecs decoder.
+
+Added options for max PDU size and session timeout to frontend-server.
+
+Added documentation of query-language parsers and other supporting utilities.
+
+[frontend-server] Added Attribute set to the bend_scanrequest API.
+
+[frontend-server] NextResultSetPosition was sometimes set incorrectly when
+surrogate diagnostics were generated.
+
+[retrieval] Allow multiple local values for attribute.
+
+[retrieval] Allow multiple attributes per element in .abs files. index type.
+
+[retrieval] Added Summary tagset, abstract syntax, and d1-node/ASN filter.
+
+--- 1.1pl2  1996/4/10
+
+Minor changes, mostly specific to Zebra's requirements (retrieval)
+
+--- 1.1  1996/2/20
+
+Repaired bug in frontend server when running multiple listening
+endpoints in dynamic mode.
+
+z_External() now won't break if a known, ASN.1 value comes encapsulated
+in an octet-string. The value will pass through unmodified in an Odr_oct.
+
+Added a bit of code to the demo client to decode & display
+ASN.1-structured records represented in the octet-aligned branch of
+the EXTERNAL CHOICE. Thanks to CAS for prodding us to finally do this.
+
+Added z_ext_getentbyref() to the ASN module. Doc updated.
+
+* Completed the SCAN definition in the ASN module. This may break SCAN
+code based on older YAZ-versions at compile-time. The fix is easy -
+look in proto.h.
+
+* Added 'displayTerm' and OtherInformation to the TermInfo structure
+under the SCAN definition. Remember to initialize this, server-people.
+
+Comstack should now support the WAIS protocol in TCP/IP mode. Note
+that this does not extend to ODR and ASN.
+
+Comstack allows insertion of established socket (primarily for
+inetd-operation of servers). Doc updated.
+
+Front-end server can now start from the inetd in TCP mode. Doc
+updated.
+
+--- 1.0pl4 1996/1/24
+
+Added Sort PDU.
+
+Fixed small problem in SUTRS-filter. A newline was sometimes inserted before
+the rank and record number.
+
+Adjustments to the frontend server.
+
+Fixed diagnostic BER dumper. It ignored the file argument.
+
+--- 1.0pl3 1996/1/2
+
+Various changes to retrieval module.
+
+Changed the union discriminators of the protocol files from enums to
+ints paired with #defines.
+
+*Changed oident.class to oident.oclass to avoid a reserved word in C++
+ compilers.
+
+*Changed operator in the RPN structure to 'roperator', again to avoid a
+ conflict with C++.
+
+Fixed problems in Explain decoders/encoders.
+
+--- 1.0pl2 1995/12/6
+
+Memory bug in log module fixed.
+
+--- 1.0pl1 1995/12/5
+
+Occasional malloc() of 0 bytes fixed in d1_espec.c.
+
+Bug in Explain DatabaseInfo module fixed.
+
+Some '\r' snuck into one or two of the ret'l config tables. A curse on Windows.
+
+--- 1.0 1995/11/28
+
+The shift to v1.0 signals that we now consider the *core* functionality
+of YAZ reasonably stable (the core being more or less equivalent to
+Z39.50-1992). Some of the really nifty v3 stuff is still not heavily
+tested (Explain not at all - though that will happen soonish).
+
+Minor changes to code to support Windows port.
+
+Various minor changes after we're getting to use GRS-1 & co. more.
+
+Added Espec-1 format.
+
+Added VisibleString field body type to GRS-1. It is illegal acc. to my copy
+of the protocol and it cannot be selected when encoding (maps into 'string'
+when decoding). Needed to talk to some servers.
+
+Demo client can request simple element set names.
+
+Added Diagnostic Format encoders/decoders.
+
+Added simple Close handling to frontend server (no hooks for resource
+reporting yet), and demonstration client.
+
+Added cs_addrstr() command to COMSTACK to retrieve peer hostname/address.
+
+--- 1.0b3 1995/08/24
+
+Fixed bug in the frontend-server. The numberOfRecordsReturned field was
+handled incorrectly when records were requested in the searchResponse. This
+will only affect you if you use the frontend-server.
+
+Added GRS-1 encoders/decoders to the service-level API. Lightly tested.
+Test-client will ask for and print GRS1. Ztest will return dummy records
+on request.
+
+Added Explain encoders/decoders to the service-level API. Untested.
+
+Added Extended Services: Item Order encoders and decoders to the Service-
+level API. Untested. We could use a recent copy of the pertinent bits
+of the ILL protocol to add those bits.
+
+Added diagnostic format 1 encoders/decoders to the service-level API.
+Untested.
+
+Moved pretty-printing of structure-wrappers ({..}) from odr_seq.c to
+odr_cons.c, which causes a more correct output.
+
+Fixed handling of searchRequest in frontend server. NextResultSetPosition
+was always set to 0 when no records were requested in the searchRequest.
+
+* Added better external-handling. This shouldn't harm old code that
+*encodes* externals. It can break code that looks for a
+'single-ASN1-type' representation, since those types that are known
+are now decoded immediately. Look at the SUTRS sample code in
+seshigh.c and client.c. Documentation updated.
+
+Handling of structured records in bend_fetchresponse. Length -1 marks
+structured record, type is deduced from format field.
+
+--- 1.0b2 1995/06/27
+Fairly quick maintenance release to add SUTRS support.
+
+Fixed handling of SUTRS records in the demonstration client.
+
+* Added format field to the bend_fetchrequest and bend_fetchresponce
+structures of the backend API (frontend server). When the record is
+returned, the value of the format field is mapped to an OID. The
+value VAL_SUTRS will also cause a slightly different ASN.1 packaging
+of the record. The special value VAL_NONE in the bend_request means
+that no specific format was requested by the client. Documentation
+updated accordingly. Test server (ztest) will return a fixed dummy
+SUTRS record if your client requests SUTRS.
+
+Documentation updated accordingly.
+
+You can now set external libraries and RANLIB support in the top-level
+Makefile.
+
+--- 1.0b 1995/06/19
+First public release.
Index: /main/tags/2.25/gsdl/packages/yaz/LICENSE
===================================================================
--- /main/tags/2.25/gsdl/packages/yaz/LICENSE	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/yaz/LICENSE	(revision 21064)
@@ -0,0 +1,26 @@
+/*
+ * Copyright (c) 1995-2000, Index Data.
+ *
+ * Permission to use, copy, modify, distribute, and sell this software and
+ * its documentation, in whole or in part, for any purpose, is hereby granted,
+ * provided that:
+ *
+ * 1. This copyright and permission notice appear in all copies of the
+ * software and its documentation. Notices of copyright or attribution
+ * which appear at the beginning of any file must remain unchanged.
+ *
+ * 2. The names of Index Data or the individual authors may not be used to
+ * endorse or promote products derived from this software without specific
+ * prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED "AS IS" AND WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS, IMPLIED, OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY
+ * WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
+ * IN NO EVENT SHALL INDEX DATA BE LIABLE FOR ANY SPECIAL, INCIDENTAL,
+ * INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND, OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER OR
+ * NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF
+ * LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
+ * OF THIS SOFTWARE.
+ *
+ */
Index: /main/tags/2.25/gsdl/packages/yaz/Makefile.am
===================================================================
--- /main/tags/2.25/gsdl/packages/yaz/Makefile.am	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/yaz/Makefile.am	(revision 21064)
@@ -0,0 +1,26 @@
+AUTOMAKE_OPTIONS = foreign 
+
+DIST_SUBDIRS=util odr z39.50 asn ill zutil comstack ccl tab retrieval server lib include client ztest doc
+
+SUBDIRS = @SUBDIRS_VAR@
+
+noinst_SCRIPTS = yaz-config
+SPEC_FILE=$(PACKAGE).spec
+EXTRA_DIST=$(SPEC_FILE) README LICENSE CHANGELOG TODO windows.txt
+
+yaz-config:
+	@echo "#!/bin/sh" >yaz-config
+	@echo "# YAZ settings for developers" >>yaz-config
+	@echo "YAZBIN=\"`pwd`/bin\"" >>yaz-config
+	@echo "YAZTAB=\"`pwd`/tab\"" >>yaz-config
+	@echo "YAZLIB=\"-L`pwd`/lib -lyaz @LIBS@\"" >>yaz-config
+	@echo "YAZINC=\"-I`pwd`/include\"" >>yaz-config
+	chmod +x yaz-config
+
+dist-hook:
+	mkdir $(distdir)/win
+	-cp $(srcdir)/win/* $(distdir)/win
+
+rpm: $(PACKAGE)-$(VERSION).tar.gz
+	cp $(PACKAGE)-$(VERSION).tar.gz /usr/src/redhat/SOURCES
+	rpm -ba $(SPEC_FILE)
Index: /main/tags/2.25/gsdl/packages/yaz/Makefile.in
===================================================================
--- /main/tags/2.25/gsdl/packages/yaz/Makefile.in	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/yaz/Makefile.in	(revision 21064)
@@ -0,0 +1,351 @@
+# Makefile.in generated automatically by automake 1.4 from Makefile.am
+
+# Copyright (C) 1994, 1995-8, 1999 Free Software Foundation, Inc.
+# This Makefile.in is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
+# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE.
+
+
+SHELL = @SHELL@
+
+srcdir = @srcdir@
+top_srcdir = @top_srcdir@
+VPATH = @srcdir@
+prefix = @prefix@
+exec_prefix = @exec_prefix@
+
+bindir = @bindir@
+sbindir = @sbindir@
+libexecdir = @libexecdir@
+datadir = @datadir@
+sysconfdir = @sysconfdir@
+sharedstatedir = @sharedstatedir@
+localstatedir = @localstatedir@
+libdir = @libdir@
+infodir = @infodir@
+mandir = @mandir@
+includedir = @includedir@
+oldincludedir = /usr/include
+
+DESTDIR =
+
+pkgdatadir = $(datadir)/@PACKAGE@
+pkglibdir = $(libdir)/@PACKAGE@
+pkgincludedir = $(includedir)/@PACKAGE@
+
+top_builddir = .
+
+ACLOCAL = @ACLOCAL@
+AUTOCONF = @AUTOCONF@
+AUTOMAKE = @AUTOMAKE@
+AUTOHEADER = @AUTOHEADER@
+
+INSTALL = @INSTALL@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@ $(AM_INSTALL_PROGRAM_FLAGS)
+INSTALL_DATA = @INSTALL_DATA@
+INSTALL_SCRIPT = @INSTALL_SCRIPT@
+transform = @program_transform_name@
+
+NORMAL_INSTALL = :
+PRE_INSTALL = :
+POST_INSTALL = :
+NORMAL_UNINSTALL = :
+PRE_UNINSTALL = :
+POST_UNINSTALL = :
+ASNMODULE = @ASNMODULE@
+CC = @CC@
+CPP = @CPP@
+ILLLIB = @ILLLIB@
+ILLMODULE = @ILLMODULE@
+MAKEINFO = @MAKEINFO@
+PACKAGE = @PACKAGE@
+RANLIB = @RANLIB@
+SUBDIRS_VAR = @SUBDIRS_VAR@
+VERSION = @VERSION@
+have_sgml2html = @have_sgml2html@
+have_sgml2latex = @have_sgml2latex@
+have_sgml2txt = @have_sgml2txt@
+
+AUTOMAKE_OPTIONS = foreign 
+
+DIST_SUBDIRS = util odr z39.50 asn ill zutil comstack ccl tab retrieval server lib include client ztest doc
+
+SUBDIRS = @SUBDIRS_VAR@
+
+noinst_SCRIPTS = yaz-config
+SPEC_FILE = $(PACKAGE).spec
+EXTRA_DIST = $(SPEC_FILE) README LICENSE CHANGELOG TODO windows.txt
+ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
+mkinstalldirs = $(SHELL) $(top_srcdir)/mkinstalldirs
+CONFIG_CLEAN_FILES = 
+SCRIPTS =  $(noinst_SCRIPTS)
+
+DIST_COMMON =  README Makefile.am Makefile.in TODO aclocal.m4 configure \
+configure.in install-sh missing mkinstalldirs
+
+
+DISTFILES = $(DIST_COMMON) $(SOURCES) $(HEADERS) $(TEXINFOS) $(EXTRA_DIST)
+
+TAR = gtar
+GZIP_ENV = --best
+all: all-redirect
+.SUFFIXES:
+$(srcdir)/Makefile.in: Makefile.am $(top_srcdir)/configure.in $(ACLOCAL_M4) 
+	cd $(top_srcdir) && $(AUTOMAKE) --foreign --include-deps Makefile
+
+Makefile: $(srcdir)/Makefile.in  $(top_builddir)/config.status
+	cd $(top_builddir) \
+	  && CONFIG_FILES=$@ CONFIG_HEADERS= $(SHELL) ./config.status
+
+$(ACLOCAL_M4):  configure.in 
+	cd $(srcdir) && $(ACLOCAL)
+
+config.status: $(srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
+	$(SHELL) ./config.status --recheck
+$(srcdir)/configure: $(srcdir)/configure.in $(ACLOCAL_M4) $(CONFIGURE_DEPENDENCIES)
+	cd $(srcdir) && $(AUTOCONF)
+
+# This directory's subdirectories are mostly independent; you can cd
+# into them and run `make' without going through this Makefile.
+# To change the values of `make' variables: instead of editing Makefiles,
+# (1) if the variable is set in `config.status', edit `config.status'
+#     (which will cause the Makefiles to be regenerated when you run `make');
+# (2) otherwise, pass the desired values on the `make' command line.
+
+@SET_MAKE@
+
+all-recursive install-data-recursive install-exec-recursive \
+installdirs-recursive install-recursive uninstall-recursive  \
+check-recursive installcheck-recursive info-recursive dvi-recursive:
+	@set fnord $(MAKEFLAGS); amf=$$2; \
+	dot_seen=no; \
+	target=`echo $@ | sed s/-recursive//`; \
+	list='$(SUBDIRS)'; for subdir in $$list; do \
+	  echo "Making $$target in $$subdir"; \
+	  if test "$$subdir" = "."; then \
+	    dot_seen=yes; \
+	    local_target="$$target-am"; \
+	  else \
+	    local_target="$$target"; \
+	  fi; \
+	  (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) $$local_target) \
+	   || case "$$amf" in *=*) exit 1;; *k*) fail=yes;; *) exit 1;; esac; \
+	done; \
+	if test "$$dot_seen" = "no"; then \
+	  $(MAKE) $(AM_MAKEFLAGS) "$$target-am" || exit 1; \
+	fi; test -z "$$fail"
+
+mostlyclean-recursive clean-recursive distclean-recursive \
+maintainer-clean-recursive:
+	@set fnord $(MAKEFLAGS); amf=$$2; \
+	dot_seen=no; \
+	rev=''; list='$(SUBDIRS)'; for subdir in $$list; do \
+	  rev="$$subdir $$rev"; \
+	  test "$$subdir" = "." && dot_seen=yes; \
+	done; \
+	test "$$dot_seen" = "no" && rev=". $$rev"; \
+	target=`echo $@ | sed s/-recursive//`; \
+	for subdir in $$rev; do \
+	  echo "Making $$target in $$subdir"; \
+	  if test "$$subdir" = "."; then \
+	    local_target="$$target-am"; \
+	  else \
+	    local_target="$$target"; \
+	  fi; \
+	  (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) $$local_target) \
+	   || case "$$amf" in *=*) exit 1;; *k*) fail=yes;; *) exit 1;; esac; \
+	done && test -z "$$fail"
+tags-recursive:
+	list='$(SUBDIRS)'; for subdir in $$list; do \
+	  test "$$subdir" = . || (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) tags); \
+	done
+
+tags: TAGS
+
+ID: $(HEADERS) $(SOURCES) $(LISP)
+	list='$(SOURCES) $(HEADERS)'; \
+	unique=`for i in $$list; do echo $$i; done | \
+	  awk '    { files[$$0] = 1; } \
+	       END { for (i in files) print i; }'`; \
+	here=`pwd` && cd $(srcdir) \
+	  && mkid -f$$here/ID $$unique $(LISP)
+
+TAGS: tags-recursive $(HEADERS) $(SOURCES)  $(TAGS_DEPENDENCIES) $(LISP)
+	tags=; \
+	here=`pwd`; \
+	list='$(SUBDIRS)'; for subdir in $$list; do \
+   if test "$$subdir" = .; then :; else \
+	    test -f $$subdir/TAGS && tags="$$tags -i $$here/$$subdir/TAGS"; \
+   fi; \
+	done; \
+	list='$(SOURCES) $(HEADERS)'; \
+	unique=`for i in $$list; do echo $$i; done | \
+	  awk '    { files[$$0] = 1; } \
+	       END { for (i in files) print i; }'`; \
+	test -z "$(ETAGS_ARGS)$$unique$(LISP)$$tags" \
+	  || (cd $(srcdir) && etags $(ETAGS_ARGS) $$tags  $$unique $(LISP) -o $$here/TAGS)
+
+mostlyclean-tags:
+
+clean-tags:
+
+distclean-tags:
+	-rm -f TAGS ID
+
+maintainer-clean-tags:
+
+distdir = $(PACKAGE)-$(VERSION)
+top_distdir = $(distdir)
+
+# This target untars the dist file and tries a VPATH configuration.  Then
+# it guarantees that the distribution is self-contained by making another
+# tarfile.
+distcheck: dist
+	-rm -rf $(distdir)
+	GZIP=$(GZIP_ENV) $(TAR) zxf $(distdir).tar.gz
+	mkdir $(distdir)/=build
+	mkdir $(distdir)/=inst
+	dc_install_base=`cd $(distdir)/=inst && pwd`; \
+	cd $(distdir)/=build \
+	  && ../configure --srcdir=.. --prefix=$$dc_install_base \
+	  && $(MAKE) $(AM_MAKEFLAGS) \
+	  && $(MAKE) $(AM_MAKEFLAGS) dvi \
+	  && $(MAKE) $(AM_MAKEFLAGS) check \
+	  && $(MAKE) $(AM_MAKEFLAGS) install \
+	  && $(MAKE) $(AM_MAKEFLAGS) installcheck \
+	  && $(MAKE) $(AM_MAKEFLAGS) dist
+	-rm -rf $(distdir)
+	@banner="$(distdir).tar.gz is ready for distribution"; \
+	dashes=`echo "$$banner" | sed s/./=/g`; \
+	echo "$$dashes"; \
+	echo "$$banner"; \
+	echo "$$dashes"
+dist: distdir
+	-chmod -R a+r $(distdir)
+	GZIP=$(GZIP_ENV) $(TAR) chozf $(distdir).tar.gz $(distdir)
+	-rm -rf $(distdir)
+dist-all: distdir
+	-chmod -R a+r $(distdir)
+	GZIP=$(GZIP_ENV) $(TAR) chozf $(distdir).tar.gz $(distdir)
+	-rm -rf $(distdir)
+distdir: $(DISTFILES)
+	-rm -rf $(distdir)
+	mkdir $(distdir)
+	-chmod 777 $(distdir)
+	@for file in $(DISTFILES); do \
+	  d=$(srcdir); \
+	  if test -d $$d/$$file; then \
+	    cp -pr $$/$$file $(distdir)/$$file; \
+	  else \
+	    test -f $(distdir)/$$file \
+	    || ln $$d/$$file $(distdir)/$$file 2> /dev/null \
+	    || cp -p $$d/$$file $(distdir)/$$file || :; \
+	  fi; \
+	done
+	for subdir in $(DIST_SUBDIRS); do \
+	  if test "$$subdir" = .; then :; else \
+	    test -d $(distdir)/$$subdir \
+	    || mkdir $(distdir)/$$subdir \
+	    || exit 1; \
+	    chmod 777 $(distdir)/$$subdir; \
+	    (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) top_distdir=../$(distdir) distdir=../$(distdir)/$$subdir distdir) \
+	      || exit 1; \
+	  fi; \
+	done
+	$(MAKE) $(AM_MAKEFLAGS) top_distdir="$(top_distdir)" distdir="$(distdir)" dist-hook
+info-am:
+info: info-recursive
+dvi-am:
+dvi: dvi-recursive
+check-am: all-am
+check: check-recursive
+installcheck-am:
+installcheck: installcheck-recursive
+install-exec-am:
+install-exec: install-exec-recursive
+
+install-data-am:
+install-data: install-data-recursive
+
+install-am: all-am
+	@$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
+install: install-recursive
+uninstall-am:
+uninstall: uninstall-recursive
+all-am: Makefile $(SCRIPTS)
+all-redirect: all-recursive
+install-strip:
+	$(MAKE) $(AM_MAKEFLAGS) AM_INSTALL_PROGRAM_FLAGS=-s install
+installdirs: installdirs-recursive
+installdirs-am:
+
+
+mostlyclean-generic:
+
+clean-generic:
+
+distclean-generic:
+	-rm -f Makefile $(CONFIG_CLEAN_FILES)
+	-rm -f config.cache config.log stamp-h stamp-h[0-9]*
+
+maintainer-clean-generic:
+mostlyclean-am:  mostlyclean-tags mostlyclean-generic
+
+mostlyclean: mostlyclean-recursive
+
+clean-am:  clean-tags clean-generic mostlyclean-am
+
+clean: clean-recursive
+
+distclean-am:  distclean-tags distclean-generic clean-am
+
+distclean: distclean-recursive
+	-rm -f config.status
+
+maintainer-clean-am:  maintainer-clean-tags maintainer-clean-generic \
+		distclean-am
+	@echo "This command is intended for maintainers to use;"
+	@echo "it deletes files that may require special tools to rebuild."
+
+maintainer-clean: maintainer-clean-recursive
+	-rm -f config.status
+
+.PHONY: install-data-recursive uninstall-data-recursive \
+install-exec-recursive uninstall-exec-recursive installdirs-recursive \
+uninstalldirs-recursive all-recursive check-recursive \
+installcheck-recursive info-recursive dvi-recursive \
+mostlyclean-recursive distclean-recursive clean-recursive \
+maintainer-clean-recursive tags tags-recursive mostlyclean-tags \
+distclean-tags clean-tags maintainer-clean-tags distdir info-am info \
+dvi-am dvi check check-am installcheck-am installcheck install-exec-am \
+install-exec install-data-am install-data install-am install \
+uninstall-am uninstall all-redirect all-am all installdirs-am \
+installdirs mostlyclean-generic distclean-generic clean-generic \
+maintainer-clean-generic clean mostlyclean distclean maintainer-clean
+
+
+yaz-config:
+	@echo "#!/bin/sh" >yaz-config
+	@echo "# YAZ settings for developers" >>yaz-config
+	@echo "YAZBIN=\"`pwd`/bin\"" >>yaz-config
+	@echo "YAZTAB=\"`pwd`/tab\"" >>yaz-config
+	@echo "YAZLIB=\"-L`pwd`/lib -lyaz @LIBS@\"" >>yaz-config
+	@echo "YAZINC=\"-I`pwd`/include\"" >>yaz-config
+	chmod +x yaz-config
+
+dist-hook:
+	mkdir $(distdir)/win
+	-cp $(srcdir)/win/* $(distdir)/win
+
+rpm: $(PACKAGE)-$(VERSION).tar.gz
+	cp $(PACKAGE)-$(VERSION).tar.gz /usr/src/redhat/SOURCES
+	rpm -ba $(SPEC_FILE)
+
+# Tell versions [3.59,3.63) of GNU make to not export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:
Index: /main/tags/2.25/gsdl/packages/yaz/README.gsdl
===================================================================
--- /main/tags/2.25/gsdl/packages/yaz/README.gsdl	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/yaz/README.gsdl	(revision 21064)
@@ -0,0 +1,16 @@
+The YAZ toolkit is used by the GSDL receptionist
+when acting as a z39.50 client.
+
+Two files are linked against: 
+ client/yaz_client.o, which was modified from Index Data's sample 
+	client code, and
+
+ lib/libyaz.a, which contains all the z39.50 and MARC formatting code.
+	There is probably a lot of stuff in this library that does
+	not need to be there for our purposes, but for now it is,
+	merely wasting some disk space and some compile-time CPU.
+
+
+
+John McPherson
+3 August 2000
Index: /main/tags/2.25/gsdl/packages/yaz/README.yaz
===================================================================
--- /main/tags/2.25/gsdl/packages/yaz/README.yaz	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/yaz/README.yaz	(revision 21064)
@@ -0,0 +1,141 @@
+
+Copyright (C) 1995-2000, Index Data ApS.
+See the file LICENSE for details.
+
+Compilation and installation instructions for YAZ 
+
+The primary output of the source here is the lib/libyaz.a library,
+which contains support functions for implementing the server or client
+role of Z39.50/SR.
+
+Windows programmers: refer to the file windows.txt which describes how
+to build the software using Microsoft Visual C++.
+
+On Unix, GNU configure is used to configure YAZ and generate Makefiles.
+Type "./configure", then "make" to build YAZ.
+
+Two test-programs of interest are generated when you type 'make' at the
+top level: ztest/yaz-ztest and client/yaz-client. Ztest is a dummy
+database server which returns canned responses to all queries. It's good
+for verifying that the protocol works ok, and ztest.c shows an
+implementation of a 'backend' interface.
+
+yaz-client is a linemode Z39.50 client. It supports a fair amount of the
+functionality of Z39.50v2/SR, but some things you need to enable or
+disable by recompilation. Its primary purpose is to excersise the
+package, and verify that the protocol works OK. It can be started by
+typing
+
+  yaz-client tcp:<hostname>:<port>[/<database>]
+
+at the UNIX prompt, to connect to a Z39.50 server.
+
+Use '?' to get a list of the available commands.
+
+The current query language for the find command is a bit awkward, but
+functional:
+
+ query     ::= ['@attrset' <attribute-set>] rpn
+ rpn       ::= complex | simple | attr rpn
+ complex   ::= operator rpn rpn
+ operator  ::= '@and' | '@or' | '@not' | '@prox' proximity
+ simple    ::= term | set.
+ term      ::= <word> | '"' <term> ... '"'.
+ set       ::= '@set' <setname>.
+ attr      ::= '@attr' [<attribute-set>] <number> '=' <number>.
+ proximity ::= exclusion distance ordered relation which unit
+ exclusion ::= '1' | '0' | 'void'
+ distance  ::= <number>
+ ordered   ::= '1' | '0'
+ relation  ::= <number>
+ which     ::= 'known' | 'private'
+ unit      ::= <number>
+
+Eg.:
+
+ Andersen
+
+ "Hans Andersen"
+
+ @and @attr 1=1 andersen @attr 1=4 @attr 4=2 duckling
+
+ @attrset Bib-1 @and @attr GILS 2=2008 Washington @attr 1=21 weather
+
+The sort command takes a sequence of sort specifications. A sort
+specification holds a field (sort criteria) and is followed by flags.
+If the sort critieria includes = it is assumed that the sort SortKey
+is of type sortAttributes using Bib-1. The integer before the = is
+the attribute type and the integer following the = is the attribute
+value. If no = is in the SortKey it is treated as a sortfield-type
+of type InternationalString. Flags observed are s (sort case
+sensitive), i (sort case insensitive), < (ascending), > (descending).
+Eg.:
+   1=4   i<                  (use is title, insensitive, ascending).
+   Title s>                  (String Title, sensitive, descending).
+
+The directories:
+
+doc     - Documentation.
+
+util    - Various little utility functions. Logging, memory debugging,
+	primitive ISO 2709 presentation for the yaz-client, etc. You'll
+	find the ASN.1 Compiler for YAZ here as well (yc.tcl).
+
+odr	- Open Data Representation. This module implements the BER
+	encoding rules. Documentation is found in the files odr-use.man
+	and odr.txt.
+
+asn     - This module implements the Z39.50/SR protocol. The best way
+	to find out how it works is to look in the sample
+	client/server code in server/seshigh.c. The interface is still
+        wholly described by the file proto.h which defines structure
+        and type definitions for each of the types introduced in the
+        protocol specification.
+
+z39.50  - This module implements the Z39.50 protocol. This module
+        does the same job as the 'asn' module except that the source
+        files are auto-generated using an YAZ' ASN.1 Compiler (YC).
+
+zutil   - This module implements a collection of Z39.50 utilities, such
+        as query parsing, EXTERNAL handling, etc.
+
+ill     - This module implements the ISO ILL protocol.
+
+comstack - This module implements the transport transparency
+	stack (COMSTACK). The comstack implements a generic interface
+	for exchanging BER-encoded records over a network. It supports
+	the 'American' mode of exchanging the records straight over
+	TCP/IP, and uses Peter Furniss' XTIMOSI package over RFC1006.
+	Look for documentation in the file comstack.man.
+
+rfc1006 - Xtimosi requires an implementation of the OSI transport
+	layer with an XTI-based API. Some systems (HP and DEC,
+	notably) provide this. For others, we provide an
+	implementation of the RFC1006 protocol (which is what
+	ISODE-based implementations often use). This module is not
+	needed if you don't use xtimosi, and it's not included in the
+	libyaz.a library.
+
+server  - This is the implementation of the server frontend. It
+	provides event-handling and server managament functions,
+	and calls the backend primitives (best documentation of these
+	is in the file include/backend.h).
+
+client  - A demonstration client. If we come upon a good design for a
+	higher level client API, that will live here.
+
+ztest   - A demonstration server that implements a backend.
+
+include - The various header files.
+
+lib     - The libraries. Primarily libyaz.a. The makefile gathers the
+          libraries from previous modules into libyaz.a.
+
+To get more information or assistance, send mail to yaz-help@indexdata.dk.
+
+We maintain a mailing-list for the purpose of announcing new versions of
+the software, bug-reports, discussion etc. You can sign up by sending
+mail to yaz-request@indexdata.dk and include the following command
+command in your email:
+    subscribe yaz-l
+
Index: /main/tags/2.25/gsdl/packages/yaz/TODO
===================================================================
--- /main/tags/2.25/gsdl/packages/yaz/TODO	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/yaz/TODO	(revision 21064)
@@ -0,0 +1,5 @@
+
+Complete Unicode support.
+
+Complete EXPLAIN support in retrieval module.
+
Index: /main/tags/2.25/gsdl/packages/yaz/aclocal.m4
===================================================================
--- /main/tags/2.25/gsdl/packages/yaz/aclocal.m4	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/yaz/aclocal.m4	(revision 21064)
@@ -0,0 +1,104 @@
+dnl aclocal.m4 generated automatically by aclocal 1.4
+
+dnl Copyright (C) 1994, 1995-8, 1999 Free Software Foundation, Inc.
+dnl This file is free software; the Free Software Foundation
+dnl gives unlimited permission to copy and/or distribute it,
+dnl with or without modifications, as long as this notice is preserved.
+
+dnl This program is distributed in the hope that it will be useful,
+dnl but WITHOUT ANY WARRANTY, to the extent permitted by law; without
+dnl even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+dnl PARTICULAR PURPOSE.
+
+# Do all the work for Automake.  This macro actually does too much --
+# some checks are only needed if your package does certain things.
+# But this isn't really a big deal.
+
+# serial 1
+
+dnl Usage:
+dnl AM_INIT_AUTOMAKE(package,version, [no-define])
+
+AC_DEFUN(AM_INIT_AUTOMAKE,
+[AC_REQUIRE([AC_PROG_INSTALL])
+PACKAGE=[$1]
+AC_SUBST(PACKAGE)
+VERSION=[$2]
+AC_SUBST(VERSION)
+dnl test to see if srcdir already configured
+if test "`cd $srcdir && pwd`" != "`pwd`" && test -f $srcdir/config.status; then
+  AC_MSG_ERROR([source directory already configured; run "make distclean" there first])
+fi
+ifelse([$3],,
+AC_DEFINE_UNQUOTED(PACKAGE, "$PACKAGE", [Name of package])
+AC_DEFINE_UNQUOTED(VERSION, "$VERSION", [Version number of package]))
+AC_REQUIRE([AM_SANITY_CHECK])
+AC_REQUIRE([AC_ARG_PROGRAM])
+dnl FIXME This is truly gross.
+missing_dir=`cd $ac_aux_dir && pwd`
+AM_MISSING_PROG(ACLOCAL, aclocal, $missing_dir)
+AM_MISSING_PROG(AUTOCONF, autoconf, $missing_dir)
+AM_MISSING_PROG(AUTOMAKE, automake, $missing_dir)
+AM_MISSING_PROG(AUTOHEADER, autoheader, $missing_dir)
+AM_MISSING_PROG(MAKEINFO, makeinfo, $missing_dir)
+AC_REQUIRE([AC_PROG_MAKE_SET])])
+
+#
+# Check to make sure that the build environment is sane.
+#
+
+AC_DEFUN(AM_SANITY_CHECK,
+[AC_MSG_CHECKING([whether build environment is sane])
+# Just in case
+sleep 1
+echo timestamp > conftestfile
+# Do `set' in a subshell so we don't clobber the current shell's
+# arguments.  Must try -L first in case configure is actually a
+# symlink; some systems play weird games with the mod time of symlinks
+# (eg FreeBSD returns the mod time of the symlink's containing
+# directory).
+if (
+   set X `ls -Lt $srcdir/configure conftestfile 2> /dev/null`
+   if test "[$]*" = "X"; then
+      # -L didn't work.
+      set X `ls -t $srcdir/configure conftestfile`
+   fi
+   if test "[$]*" != "X $srcdir/configure conftestfile" \
+      && test "[$]*" != "X conftestfile $srcdir/configure"; then
+
+      # If neither matched, then we have a broken ls.  This can happen
+      # if, for instance, CONFIG_SHELL is bash and it inherits a
+      # broken ls alias from the environment.  This has actually
+      # happened.  Such a system could not be considered "sane".
+      AC_MSG_ERROR([ls -t appears to fail.  Make sure there is not a broken
+alias in your environment])
+   fi
+
+   test "[$]2" = conftestfile
+   )
+then
+   # Ok.
+   :
+else
+   AC_MSG_ERROR([newly created file is older than distributed files!
+Check your system clock])
+fi
+rm -f conftest*
+AC_MSG_RESULT(yes)])
+
+dnl AM_MISSING_PROG(NAME, PROGRAM, DIRECTORY)
+dnl The program must properly implement --version.
+AC_DEFUN(AM_MISSING_PROG,
+[AC_MSG_CHECKING(for working $2)
+# Run test in a subshell; some versions of sh will print an error if
+# an executable is not found, even if stderr is redirected.
+# Redirect stdin to placate older versions of autoconf.  Sigh.
+if ($2 --version) < /dev/null > /dev/null 2>&1; then
+   $1=$2
+   AC_MSG_RESULT(found)
+else
+   $1="$3/missing $2"
+   AC_MSG_RESULT(missing)
+fi
+AC_SUBST($1)])
+
Index: /main/tags/2.25/gsdl/packages/yaz/asn/Makefile.am
===================================================================
--- /main/tags/2.25/gsdl/packages/yaz/asn/Makefile.am	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/yaz/asn/Makefile.am	(revision 21064)
@@ -0,0 +1,8 @@
+## $Id$
+
+noinst_LIBRARIES=libasn.a
+
+libasn_a_SOURCES = proto.c prt-rsc.c prt-acc.c prt-exp.c prt-grs.c prt-exd.c \
+	prt-dia.c prt-esp.c prt-arc.c prt-add.c prt-dat.c prt-univ.c
+
+INCLUDES=-I../include
Index: /main/tags/2.25/gsdl/packages/yaz/asn/Makefile.in
===================================================================
--- /main/tags/2.25/gsdl/packages/yaz/asn/Makefile.in	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/yaz/asn/Makefile.in	(revision 21064)
@@ -0,0 +1,268 @@
+# Makefile.in generated automatically by automake 1.4 from Makefile.am
+
+# Copyright (C) 1994, 1995-8, 1999 Free Software Foundation, Inc.
+# This Makefile.in is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
+# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE.
+
+
+SHELL = @SHELL@
+
+srcdir = @srcdir@
+top_srcdir = @top_srcdir@
+VPATH = @srcdir@
+prefix = @prefix@
+exec_prefix = @exec_prefix@
+
+bindir = @bindir@
+sbindir = @sbindir@
+libexecdir = @libexecdir@
+datadir = @datadir@
+sysconfdir = @sysconfdir@
+sharedstatedir = @sharedstatedir@
+localstatedir = @localstatedir@
+libdir = @libdir@
+infodir = @infodir@
+mandir = @mandir@
+includedir = @includedir@
+oldincludedir = /usr/include
+
+DESTDIR =
+
+pkgdatadir = $(datadir)/@PACKAGE@
+pkglibdir = $(libdir)/@PACKAGE@
+pkgincludedir = $(includedir)/@PACKAGE@
+
+top_builddir = ..
+
+ACLOCAL = @ACLOCAL@
+AUTOCONF = @AUTOCONF@
+AUTOMAKE = @AUTOMAKE@
+AUTOHEADER = @AUTOHEADER@
+
+INSTALL = @INSTALL@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@ $(AM_INSTALL_PROGRAM_FLAGS)
+INSTALL_DATA = @INSTALL_DATA@
+INSTALL_SCRIPT = @INSTALL_SCRIPT@
+transform = @program_transform_name@
+
+NORMAL_INSTALL = :
+PRE_INSTALL = :
+POST_INSTALL = :
+NORMAL_UNINSTALL = :
+PRE_UNINSTALL = :
+POST_UNINSTALL = :
+ASNMODULE = @ASNMODULE@
+CC = @CC@
+CPP = @CPP@
+ILLLIB = @ILLLIB@
+ILLMODULE = @ILLMODULE@
+MAKEINFO = @MAKEINFO@
+PACKAGE = @PACKAGE@
+RANLIB = @RANLIB@
+SUBDIRS_VAR = @SUBDIRS_VAR@
+VERSION = @VERSION@
+have_sgml2html = @have_sgml2html@
+have_sgml2latex = @have_sgml2latex@
+have_sgml2txt = @have_sgml2txt@
+
+noinst_LIBRARIES = libasn.a
+
+libasn_a_SOURCES = proto.c prt-rsc.c prt-acc.c prt-exp.c prt-grs.c prt-exd.c 	prt-dia.c prt-esp.c prt-arc.c prt-add.c prt-dat.c prt-univ.c
+
+
+INCLUDES = -I../include
+mkinstalldirs = $(SHELL) $(top_srcdir)/mkinstalldirs
+CONFIG_CLEAN_FILES = 
+LIBRARIES =  $(noinst_LIBRARIES)
+
+
+DEFS = @DEFS@ -I. -I$(srcdir) 
+CPPFLAGS = @CPPFLAGS@
+LDFLAGS = @LDFLAGS@
+LIBS = @LIBS@
+libasn_a_LIBADD = 
+libasn_a_OBJECTS =  proto.o prt-rsc.o prt-acc.o prt-exp.o prt-grs.o \
+prt-exd.o prt-dia.o prt-esp.o prt-arc.o prt-add.o prt-dat.o prt-univ.o
+AR = ar
+CFLAGS = @CFLAGS@
+COMPILE = $(CC) $(DEFS) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
+CCLD = $(CC)
+LINK = $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(LDFLAGS) -o $@
+DIST_COMMON =  Makefile.am Makefile.in
+
+
+DISTFILES = $(DIST_COMMON) $(SOURCES) $(HEADERS) $(TEXINFOS) $(EXTRA_DIST)
+
+TAR = gtar
+GZIP_ENV = --best
+SOURCES = $(libasn_a_SOURCES)
+OBJECTS = $(libasn_a_OBJECTS)
+
+all: all-redirect
+.SUFFIXES:
+.SUFFIXES: .S .c .o .s
+$(srcdir)/Makefile.in: Makefile.am $(top_srcdir)/configure.in $(ACLOCAL_M4) 
+	cd $(top_srcdir) && $(AUTOMAKE) --gnu --include-deps asn/Makefile
+
+Makefile: $(srcdir)/Makefile.in  $(top_builddir)/config.status
+	cd $(top_builddir) \
+	  && CONFIG_FILES=$(subdir)/$@ CONFIG_HEADERS= $(SHELL) ./config.status
+
+
+mostlyclean-noinstLIBRARIES:
+
+clean-noinstLIBRARIES:
+	-test -z "$(noinst_LIBRARIES)" || rm -f $(noinst_LIBRARIES)
+
+distclean-noinstLIBRARIES:
+
+maintainer-clean-noinstLIBRARIES:
+
+.c.o:
+	$(COMPILE) -c $<
+
+.s.o:
+	$(COMPILE) -c $<
+
+.S.o:
+	$(COMPILE) -c $<
+
+mostlyclean-compile:
+	-rm -f *.o core *.core
+
+clean-compile:
+
+distclean-compile:
+	-rm -f *.tab.c
+
+maintainer-clean-compile:
+
+libasn.a: $(libasn_a_OBJECTS) $(libasn_a_DEPENDENCIES)
+	-rm -f libasn.a
+	$(AR) cru libasn.a $(libasn_a_OBJECTS) $(libasn_a_LIBADD)
+	$(RANLIB) libasn.a
+
+tags: TAGS
+
+ID: $(HEADERS) $(SOURCES) $(LISP)
+	list='$(SOURCES) $(HEADERS)'; \
+	unique=`for i in $$list; do echo $$i; done | \
+	  awk '    { files[$$0] = 1; } \
+	       END { for (i in files) print i; }'`; \
+	here=`pwd` && cd $(srcdir) \
+	  && mkid -f$$here/ID $$unique $(LISP)
+
+TAGS:  $(HEADERS) $(SOURCES)  $(TAGS_DEPENDENCIES) $(LISP)
+	tags=; \
+	here=`pwd`; \
+	list='$(SOURCES) $(HEADERS)'; \
+	unique=`for i in $$list; do echo $$i; done | \
+	  awk '    { files[$$0] = 1; } \
+	       END { for (i in files) print i; }'`; \
+	test -z "$(ETAGS_ARGS)$$unique$(LISP)$$tags" \
+	  || (cd $(srcdir) && etags $(ETAGS_ARGS) $$tags  $$unique $(LISP) -o $$here/TAGS)
+
+mostlyclean-tags:
+
+clean-tags:
+
+distclean-tags:
+	-rm -f TAGS ID
+
+maintainer-clean-tags:
+
+distdir = $(top_builddir)/$(PACKAGE)-$(VERSION)/$(subdir)
+
+subdir = asn
+
+distdir: $(DISTFILES)
+	@for file in $(DISTFILES); do \
+	  d=$(srcdir); \
+	  if test -d $$d/$$file; then \
+	    cp -pr $$/$$file $(distdir)/$$file; \
+	  else \
+	    test -f $(distdir)/$$file \
+	    || ln $$d/$$file $(distdir)/$$file 2> /dev/null \
+	    || cp -p $$d/$$file $(distdir)/$$file || :; \
+	  fi; \
+	done
+
+info-am:
+info: info-am
+dvi-am:
+dvi: dvi-am
+check-am: all-am
+check: check-am
+installcheck-am:
+installcheck: installcheck-am
+install-exec-am:
+install-exec: install-exec-am
+
+install-data-am:
+install-data: install-data-am
+
+install-am: all-am
+	@$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
+install: install-am
+uninstall-am:
+uninstall: uninstall-am
+all-am: Makefile $(LIBRARIES)
+all-redirect: all-am
+install-strip:
+	$(MAKE) $(AM_MAKEFLAGS) AM_INSTALL_PROGRAM_FLAGS=-s install
+installdirs:
+
+
+mostlyclean-generic:
+
+clean-generic:
+
+distclean-generic:
+	-rm -f Makefile $(CONFIG_CLEAN_FILES)
+	-rm -f config.cache config.log stamp-h stamp-h[0-9]*
+
+maintainer-clean-generic:
+mostlyclean-am:  mostlyclean-noinstLIBRARIES mostlyclean-compile \
+		mostlyclean-tags mostlyclean-generic
+
+mostlyclean: mostlyclean-am
+
+clean-am:  clean-noinstLIBRARIES clean-compile clean-tags clean-generic \
+		mostlyclean-am
+
+clean: clean-am
+
+distclean-am:  distclean-noinstLIBRARIES distclean-compile \
+		distclean-tags distclean-generic clean-am
+
+distclean: distclean-am
+
+maintainer-clean-am:  maintainer-clean-noinstLIBRARIES \
+		maintainer-clean-compile maintainer-clean-tags \
+		maintainer-clean-generic distclean-am
+	@echo "This command is intended for maintainers to use;"
+	@echo "it deletes files that may require special tools to rebuild."
+
+maintainer-clean: maintainer-clean-am
+
+.PHONY: mostlyclean-noinstLIBRARIES distclean-noinstLIBRARIES \
+clean-noinstLIBRARIES maintainer-clean-noinstLIBRARIES \
+mostlyclean-compile distclean-compile clean-compile \
+maintainer-clean-compile tags mostlyclean-tags distclean-tags \
+clean-tags maintainer-clean-tags distdir info-am info dvi-am dvi check \
+check-am installcheck-am installcheck install-exec-am install-exec \
+install-data-am install-data install-am install uninstall-am uninstall \
+all-redirect all-am all installdirs mostlyclean-generic \
+distclean-generic clean-generic maintainer-clean-generic clean \
+mostlyclean distclean maintainer-clean
+
+
+# Tell versions [3.59,3.63) of GNU make to not export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:
Index: /main/tags/2.25/gsdl/packages/yaz/asn/proto.c
===================================================================
--- /main/tags/2.25/gsdl/packages/yaz/asn/proto.c	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/yaz/asn/proto.c	(revision 21064)
@@ -0,0 +1,1843 @@
+/*
+ * Copyright (c) 1995-1999, Index Data
+ * See the file LICENSE for details.
+ * Sebastian Hammer, Adam Dickmeiss
+ *
+ * $Log$
+ * Revision 1.1  2000/08/03 03:09:45  johnmcp
+ * Added the YAZ toolkit source to the packages directory (for z39.50 stuff)
+ *
+ * Revision 1.61  1999/11/30 13:47:10  adam
+ * Improved installation. Moved header files to include/yaz.
+ *
+ * Revision 1.60  1999/06/11 16:45:59  adam
+ * Fixed minor bug in ScanRequest encoder.
+ *
+ * Revision 1.59  1999/04/21 11:46:00  adam
+ * Fixed bug in {en,de}coder for OtherInformation.
+ *
+ * Revision 1.58  1999/04/20 09:56:47  adam
+ * Added 'name' paramter to encoder/decoder routines (typedef Odr_fun).
+ * Modified all encoders/decoders to reflect this change.
+ *
+ * Revision 1.57  1998/10/20 13:55:37  quinn
+ * Fixed Scan bug in asn and client
+ *
+ * Revision 1.56  1998/08/19 16:10:04  adam
+ * Changed som member names of DeleteResultSetRequest/Response.
+ *
+ * Revision 1.55  1998/02/11 11:53:32  adam
+ * Changed code so that it compiles as C++.
+ *
+ * Revision 1.54  1996/11/11 13:14:46  adam
+ * Fixed tagging bug in z_ProximityOperator.
+ *
+ * Revision 1.53  1996/10/09 15:54:55  quinn
+ * Added SearchInfoReport
+ *
+ * Revision 1.52  1996/10/08  12:56:57  adam
+ * Bug fix: tagging of type 101 query.
+ *
+ * Revision 1.51  1996/07/26  14:07:21  quinn
+ * Small
+ *
+ * Revision 1.50  1996/07/26  13:36:15  quinn
+ * Various smallish
+ *
+ * Revision 1.49  1996/07/06  19:58:28  quinn
+ * System headerfiles gathered in yconfig
+ *
+ * Revision 1.48  1996/06/10  08:53:33  quinn
+ * Added Summary,OPAC,ResourceReport
+ *
+ * Revision 1.47  1996/05/29  15:47:50  quinn
+ * Fixed in bug DiagRecs decoder. Thanks to Linda Harris.
+ *
+ * Revision 1.46  1996/04/10  11:39:42  quinn
+ * Fixed bug in UserInfo
+ *
+ * Revision 1.45  1996/02/23  10:00:25  quinn
+ * Fixes to SCAN
+ *
+ * Revision 1.44  1996/02/20  12:51:41  quinn
+ * Completed SCAN. Fixed problems with EXTERNAL.
+ *
+ * Revision 1.43  1996/02/10  12:22:49  quinn
+ * Work on SCAN
+ *
+ * Revision 1.42  1996/01/22  09:46:31  quinn
+ * Added Sort PDU. Moved StringList to main protocol file.
+ *
+ * Revision 1.41  1996/01/10  15:21:24  quinn
+ * Added links to access control PDUs
+ *
+ * Revision 1.40  1996/01/02  11:46:40  quinn
+ * Changed 'operator' to 'roperator' to avoid C++ conflict.
+ *
+ * Revision 1.39  1995/09/29  17:11:53  quinn
+ * Smallish
+ *
+ * Revision 1.38  1995/09/27  15:02:40  quinn
+ * Modified function heads & prototypes.
+ *
+ * Revision 1.37  1995/08/21  09:10:15  quinn
+ * Smallish fixes to suppport new formats.
+ *
+ * Revision 1.36  1995/08/15  11:59:39  quinn
+ * Updated External
+ *
+ * Revision 1.35  1995/08/10  08:53:59  quinn
+ * Added Explain
+ *
+ * Revision 1.34  1995/06/19  17:01:48  quinn
+ * This should bring us in sync with the version distributed as 1.0b
+ *
+ * Revision 1.33  1995/06/19  13:39:56  quinn
+ * *** empty log message ***
+ *
+ * Revision 1.32  1995/06/19  12:37:28  quinn
+ * Fixed a bug in the compspec.
+ *
+ * Revision 1.31  1995/06/16  13:15:56  quinn
+ * Fixed Defaultdiagformat.
+ *
+ * Revision 1.30  1995/06/15  15:42:01  quinn
+ * Fixed some v3 bugs
+ *
+ * Revision 1.29  1995/06/15  07:44:49  quinn
+ * Moving to v3.
+ *
+ * Revision 1.28  1995/06/14  15:26:35  quinn
+ * *** empty log message ***
+ *
+ * Revision 1.27  1995/06/07  14:36:22  quinn
+ * Added CLOSE
+ *
+ * Revision 1.26  1995/06/02  09:49:13  quinn
+ * Adding access control
+ *
+ * Revision 1.25  1995/05/25  11:00:08  quinn
+ * *** empty log message ***
+ *
+ * Revision 1.24  1995/05/22  13:58:18  quinn
+ * Fixed an ODR_NULLVAL.
+ *
+ * Revision 1.23  1995/05/22  11:30:18  quinn
+ * Adding Z39.50-1992 stuff to proto.c. Adding zget.c
+ *
+ * Revision 1.22  1995/05/17  08:40:56  quinn
+ * Added delete. Fixed some sequence_begins. Smallish.
+ *
+ * Revision 1.21  1995/05/16  08:50:24  quinn
+ * License, documentation, and memory fixes
+ *
+ * Revision 1.20  1995/05/15  11:55:25  quinn
+ * Smallish.
+ *
+ * Revision 1.19  1995/04/11  11:58:35  quinn
+ * Fixed bug.
+ *
+ * Revision 1.18  1995/04/11  11:52:02  quinn
+ * Fixed possible buf in proto.c
+ *
+ * Revision 1.17  1995/04/10  10:22:22  quinn
+ * Added SCAN.
+ *
+ * Revision 1.16  1995/03/30  10:26:43  quinn
+ * Added Term structure
+ *
+ * Revision 1.15  1995/03/30  09:08:39  quinn
+ * Added Resource control protocol
+ *
+ * Revision 1.14  1995/03/29  08:06:13  quinn
+ * Added a few v3 elements
+ *
+ * Revision 1.13  1995/03/20  11:26:52  quinn
+ * *** empty log message ***
+ *
+ * Revision 1.12  1995/03/20  09:45:09  quinn
+ * Working towards v3
+ *
+ * Revision 1.11  1995/03/17  10:17:25  quinn
+ * Added memory management.
+ *
+ * Revision 1.10  1995/03/15  11:17:40  quinn
+ * Fixed some return-checks from choice.. need better ay to handle those..
+ *
+ * Revision 1.9  1995/03/15  08:37:06  quinn
+ * Fixed protocol bugs.
+ *
+ * Revision 1.8  1995/03/14  16:59:24  quinn
+ * Fixed OPTIONAL flag in attributeelement
+ *
+ * Revision 1.7  1995/03/07  16:29:33  quinn
+ * Added authentication stuff.
+ *
+ * Revision 1.6  1995/03/01  14:46:03  quinn
+ * Fixed protocol bug in 8777query.
+ *
+ * Revision 1.5  1995/02/14  11:54:22  quinn
+ * Fixing include.
+ *
+ * Revision 1.4  1995/02/10  15:54:30  quinn
+ * Small adjustments.
+ *
+ * Revision 1.3  1995/02/09  15:51:39  quinn
+ * Works better now.
+ *
+ * Revision 1.2  1995/02/06  21:26:07  quinn
+ * Repaired this evening's damages..
+ *
+ * Revision 1.1  1995/02/06  16:44:47  quinn
+ * First hack at Z/SR protocol
+ *
+ */
+
+#include <yaz/odr.h>
+
+#include <yaz/proto.h>
+
+/* ---------------------- GLOBAL DEFS ------------------- */
+
+/*
+ * We'll use a general octetstring here, since string operations are
+ * clumsy on long strings.
+ */
+int z_SUTRS(ODR o, Odr_oct **p, int opt, const char *name)
+{
+    return odr_implicit(o, odr_octetstring, p, ODR_UNIVERSAL,
+	ODR_GENERALSTRING, opt);
+}
+
+int z_ReferenceId(ODR o, Z_ReferenceId **p, int opt, const char *name)
+{
+    return odr_implicit(o, odr_octetstring, (Odr_oct**) p, ODR_CONTEXT, 2,
+			opt);
+}
+
+int z_DatabaseName(ODR o, Z_DatabaseName **p, int opt, const char *name)
+{
+    return odr_implicit(o, odr_visiblestring, (char **) p, ODR_CONTEXT, 105,
+	opt);
+}
+
+int z_ResultSetId(ODR o, char **p, int opt, const char *name)
+{
+    return odr_implicit(o, odr_visiblestring, (char **) p, ODR_CONTEXT, 31,
+	opt);
+}
+
+int z_ElementSetName(ODR o, char **p, int opt, const char *name)
+{
+    return odr_implicit(o, odr_visiblestring, p, ODR_CONTEXT, 103, opt);
+}
+
+int z_UserInformationField(ODR o, Z_External **p, int opt, const char *name)
+{
+    return odr_explicit(o, z_External, (Z_External **)p, ODR_CONTEXT,
+    	11, opt);
+}
+
+int z_InternationalString(ODR o, char **p, int opt, const char *name)
+{
+    return odr_generalstring(o, p, opt, 0);
+}
+
+int z_InfoCategory(ODR o, Z_InfoCategory **p, int opt, const char *name)
+{
+    if (!odr_sequence_begin(o, p, sizeof(**p), 0))
+    	return opt && odr_ok(o);
+    return
+    	odr_implicit(o, odr_oid, &(*p)->categoryTypeId, ODR_CONTEXT, 1, 1) &&
+	odr_implicit(o, odr_integer, &(*p)->categoryValue, ODR_CONTEXT, 2,
+		     0) &&
+	odr_sequence_end(o);
+}
+
+int z_OtherInformationUnit(ODR o, Z_OtherInformationUnit **p, int opt,
+			   const char *name)
+{
+    static Odr_arm arm[] =
+    {
+    	{ODR_IMPLICIT, ODR_CONTEXT, 2, Z_OtherInfo_characterInfo,
+	 odr_visiblestring, 0},
+	{ODR_IMPLICIT, ODR_CONTEXT, 3, Z_OtherInfo_binaryInfo,
+	 (Odr_fun)odr_octetstring, 0},
+	{ODR_IMPLICIT, ODR_CONTEXT, 4, Z_OtherInfo_externallyDefinedInfo,
+	 (Odr_fun)z_External, 0},
+	{ODR_IMPLICIT, ODR_CONTEXT, 5, Z_OtherInfo_oid,
+	 (Odr_fun)odr_oid, 0},
+	{-1, -1, -1, -1, 0, 0}
+    };
+
+    if (!odr_sequence_begin(o, p, sizeof(**p), name))
+    	return opt && odr_ok(o);
+    return
+    	odr_implicit(o, z_InfoCategory, &(*p)->category, ODR_CONTEXT, 1, 1) &&
+	odr_choice(o, arm, &(*p)->information, &(*p)->which, name) &&
+	odr_sequence_end(o);
+}
+    
+int z_OtherInformation(ODR o, Z_OtherInformation **p, int opt,
+		       const char *name)
+{
+    if (!odr_initmember (o, p, sizeof(**p)))
+	return opt && odr_ok(o);
+    odr_implicit_settag(o, ODR_CONTEXT, 201);
+    if (odr_sequence_of(o, (Odr_fun)z_OtherInformationUnit, &(*p)->list,
+	&(*p)->num_elements, name))
+	return 1;
+    *p = 0;
+    return opt && odr_ok(o);
+}
+
+int z_StringOrNumeric(ODR o, Z_StringOrNumeric **p, int opt, const char *name)
+{
+    static Odr_arm arm[] =
+    {
+    	{ODR_IMPLICIT, ODR_CONTEXT, 1, Z_StringOrNumeric_string,
+	 odr_visiblestring, 0},
+	{ODR_IMPLICIT, ODR_CONTEXT, 2, Z_StringOrNumeric_numeric,
+	 (Odr_fun)odr_integer, 0},
+	{-1, -1, -1, -1, 0, 0}
+    };
+
+    if (o->direction == ODR_DECODE)
+    	*p = (Z_StringOrNumeric *)odr_malloc(o, sizeof(**p));
+    else if (!*p)
+    	return opt;
+    if (odr_choice(o, arm, &(*p)->u, &(*p)->which, 0))
+    	return 1;
+    *p = 0;
+    return opt && odr_ok(o);
+}
+
+/*
+ * check tagging!!
+ */
+int z_Unit(ODR o, Z_Unit **p, int opt, const char *name)
+{
+    if (!odr_sequence_begin(o, p, sizeof(**p), 0))
+    	return opt && odr_ok(o);
+    return
+    	odr_explicit(o, z_InternationalString, &(*p)->unitSystem, ODR_CONTEXT,
+	    1, 1) &&
+	odr_explicit(o, z_StringOrNumeric, &(*p)->unitType, ODR_CONTEXT,
+	    2, 1) &&
+	odr_explicit(o, z_StringOrNumeric, &(*p)->unit, ODR_CONTEXT, 3, 1) &&
+	odr_implicit(o, odr_integer, &(*p)->scaleFactor, ODR_CONTEXT, 4, 1) &&
+	odr_sequence_end(o);
+}
+
+int z_IntUnit(ODR o, Z_IntUnit **p, int opt, const char *name)
+{
+    if (!odr_sequence_begin(o, p, sizeof(**p), 0))
+    	return opt && odr_ok(o);
+    return
+    	odr_implicit(o, odr_integer, &(*p)->value, ODR_CONTEXT, 1, 0) &&
+	odr_implicit(o, z_Unit, &(*p)->unitUsed, ODR_CONTEXT, 2, 0) &&
+	odr_sequence_end(o);
+}
+
+int z_StringList(ODR o, Z_StringList **p, int opt, const char *name)
+{
+    if (o->direction == ODR_DECODE)
+	*p = (Z_StringList *)odr_malloc(o, sizeof(**p));
+    else if (!*p)
+	return opt;
+    if (odr_sequence_of(o, (Odr_fun)z_InternationalString, &(*p)->strings,
+	&(*p)->num_strings, 0))
+	return 1;
+    *p = 0;
+    return opt && odr_ok(o);
+}
+
+/* ---------------------- INITIALIZE SERVICE ------------------- */
+
+#if 1
+int z_NSRAuthentication(ODR o, Z_NSRAuthentication **p, int opt,
+			const char *name)
+{
+    if (!odr_sequence_begin(o, p, sizeof(**p), 0))
+    	return opt && odr_ok(o);
+    return
+    	odr_visiblestring(o, &(*p)->user, 0, 0) &&
+    	odr_visiblestring(o, &(*p)->password, 0, 0) &&
+    	odr_visiblestring(o, &(*p)->account, 0, 0) &&
+    	odr_sequence_end(o);
+}
+#endif
+
+int z_IdPass(ODR o, Z_IdPass **p, int opt, const char *name)
+{
+    if (!odr_sequence_begin(o, p, sizeof(**p), 0))
+    	return opt && odr_ok(o);
+    return
+    	odr_implicit(o, odr_visiblestring, &(*p)->groupId, ODR_CONTEXT, 0,
+		     1) &&
+    	odr_implicit(o, odr_visiblestring, &(*p)->userId, ODR_CONTEXT, 1, 1) &&
+    	odr_implicit(o, odr_visiblestring, &(*p)->password, ODR_CONTEXT, 2,
+	    1) &&
+    	odr_sequence_end(o);
+}
+
+int z_StrAuthentication(ODR o, char **p, int opt, const char *name)
+{
+    return odr_visiblestring(o, p, opt, 0);
+}
+
+int z_IdAuthentication(ODR o, Z_IdAuthentication **p, int opt,
+		       const char *name)
+{
+    static Odr_arm arm[] =
+    {
+	{-1, -1, -1, Z_IdAuthentication_open, z_StrAuthentication, 0},
+	{-1, -1, -1, Z_IdAuthentication_idPass, (Odr_fun)z_IdPass, 0},
+	{-1, -1, -1, Z_IdAuthentication_anonymous, (Odr_fun)odr_null, 0},
+	{-1, -1, -1, Z_IdAuthentication_other, (Odr_fun)z_External, 0},
+	{-1, -1, -1, -1, 0, 0}
+    };
+
+    if (o->direction == ODR_DECODE)
+    	*p = (Z_IdAuthentication *)odr_malloc(o, sizeof(**p));
+    else if (!*p)
+    	return opt;
+
+    if (odr_choice(o, arm, &(*p)->u, &(*p)->which, 0))
+    	return 1;
+    *p = 0;
+    return opt && odr_ok(o);
+}
+
+int z_InitRequest(ODR o, Z_InitRequest **p, int opt, const char *name)
+{
+    Z_InitRequest *pp;
+
+    if (!odr_sequence_begin(o, p, sizeof(**p), 0))
+    	return opt && odr_ok(o);
+    pp = *p;
+    return
+    	z_ReferenceId(o, &pp->referenceId, 1, 0) &&
+    	odr_implicit(o, odr_bitstring, &pp->protocolVersion,
+		     ODR_CONTEXT, 3, 0) &&
+	odr_implicit(o, odr_bitstring, &pp->options, ODR_CONTEXT, 4, 0) &&
+	odr_implicit(o, odr_integer, &pp->preferredMessageSize, ODR_CONTEXT,
+		     5, 0) &&
+	odr_implicit(o, odr_integer, &pp->maximumRecordSize,
+		     ODR_CONTEXT, 6, 0) &&
+	odr_explicit(o, z_IdAuthentication, &pp->idAuthentication,
+		     ODR_CONTEXT, 7, 1) &&
+	odr_implicit(o, odr_visiblestring, &pp->implementationId,
+		     ODR_CONTEXT, 110, 1) &&
+	odr_implicit(o, odr_visiblestring, &pp->implementationName,
+		     ODR_CONTEXT, 111, 1) &&
+	odr_implicit(o, odr_visiblestring, &pp->implementationVersion,
+	    ODR_CONTEXT, 112, 1) &&
+	z_UserInformationField(o, &pp->userInformationField, 1, 0) &&
+	z_OtherInformation(o, &(*p)->otherInfo, 1, 0) &&
+	odr_sequence_end(o);
+}
+
+int z_InitResponse(ODR o, Z_InitResponse **p, int opt, const char *name)
+{
+    Z_InitResponse *pp;
+
+    if (!odr_sequence_begin(o, p, sizeof(**p), 0))
+    	return opt && odr_ok(o);
+    pp = *p;
+    return
+    	z_ReferenceId(o, &pp->referenceId, 1, 0) &&
+    	odr_implicit(o, odr_bitstring, &pp->protocolVersion,
+		     ODR_CONTEXT, 3, 0) &&
+	odr_implicit(o, odr_bitstring, &pp->options, ODR_CONTEXT, 4, 0) &&
+	odr_implicit(o, odr_integer, &pp->preferredMessageSize,
+		     ODR_CONTEXT, 5, 0) &&
+	odr_implicit(o, odr_integer, &pp->maximumRecordSize,
+		     ODR_CONTEXT, 6, 0) &&
+	odr_implicit(o, odr_bool, &pp->result, ODR_CONTEXT, 12, 0) &&
+	odr_implicit(o, odr_visiblestring, &pp->implementationId,
+		     ODR_CONTEXT, 110, 1) &&
+	odr_implicit(o, odr_visiblestring, &pp->implementationName,
+		     ODR_CONTEXT, 111, 1) &&
+	odr_implicit(o, odr_visiblestring, &pp->implementationVersion,
+		     ODR_CONTEXT, 112, 1) &&
+	z_UserInformationField(o, &pp->userInformationField, 1, 0) &&
+	z_OtherInformation(o, &(*p)->otherInfo, 1, 0) &&
+	odr_sequence_end(o);
+}
+
+/* ------------------ RESOURCE CONTROL ----------------*/
+
+int z_TriggerResourceControlRequest(ODR o, Z_TriggerResourceControlRequest **p,
+				    int opt, const char *name)
+{
+    if (!odr_sequence_begin(o, p, sizeof(**p), 0))
+    	return opt && odr_ok(o);
+    return
+    	z_ReferenceId(o, &(*p)->referenceId, 1, 0) &&
+	odr_implicit(o, odr_integer, &(*p)->requestedAction, ODR_CONTEXT,
+	    46, 0) &&
+	odr_implicit(o, odr_oid, &(*p)->prefResourceReportFormat,
+	    ODR_CONTEXT, 47, 1) &&
+	odr_implicit(o, odr_bool, &(*p)->resultSetWanted, ODR_CONTEXT,
+	    48, 1) &&
+	z_OtherInformation(o, &(*p)->otherInfo, 1, 0) &&
+	odr_sequence_end(o);
+}
+
+int z_ResourceControlRequest(ODR o, Z_ResourceControlRequest **p, int opt,
+			     const char *name)
+{
+    if (!odr_sequence_begin(o, p, sizeof(**p), 0))
+    	return opt && odr_ok(o);
+    return
+    	z_ReferenceId(o, &(*p)->referenceId, 1, 0) &&
+	odr_implicit(o, odr_bool, &(*p)->suspendedFlag, ODR_CONTEXT, 39, 1)&&
+	odr_explicit(o, z_External, &(*p)->resourceReport, ODR_CONTEXT,
+	    40, 1) &&
+	odr_implicit(o, odr_integer, &(*p)->partialResultsAvailable,
+	    ODR_CONTEXT, 41, 1) &&
+	odr_implicit(o, odr_bool, &(*p)->responseRequired, ODR_CONTEXT,
+	    42, 0) &&
+	odr_implicit(o, odr_bool, &(*p)->triggeredRequestFlag,
+	    ODR_CONTEXT, 43, 1) &&
+	z_OtherInformation(o, &(*p)->otherInfo, 1, 0) &&
+	odr_sequence_end(o);
+}
+
+int z_ResourceControlResponse(ODR o, Z_ResourceControlResponse **p, int opt,
+			      const char *name)
+{
+    if (!odr_sequence_begin(o, p, sizeof(**p), 0))
+    	return opt && odr_ok(o);
+    return
+    	z_ReferenceId(o, &(*p)->referenceId, 1, 0) &&
+	odr_implicit(o, odr_bool, &(*p)->continueFlag, ODR_CONTEXT, 44, 0) &&
+	odr_implicit(o, odr_bool, &(*p)->resultSetWanted, ODR_CONTEXT,
+	    45, 1) &&
+	z_OtherInformation(o, &(*p)->otherInfo, 1, 0) &&
+	odr_sequence_end(o);
+}
+
+/* ------------------------ SEARCH SERVICE ----------------------- */
+
+int z_DatabaseSpecificUnit(ODR o, Z_DatabaseSpecificUnit **p, int opt,
+			   const char *name)
+{
+    if (!odr_sequence_begin(o, p, sizeof(**p), 0))
+    	return opt && odr_ok(o);
+    return
+    	z_DatabaseName(o, &(*p)->databaseName, 0, 0) &&
+    	z_ElementSetName(o, &(*p)->elementSetName, 0, 0) &&
+    	odr_sequence_end(o);
+}
+
+int z_DatabaseSpecific(ODR o, Z_DatabaseSpecific **p, int opt,
+		       const char *name)
+{
+    if (o->direction == ODR_DECODE)
+    	*p = (Z_DatabaseSpecific *)odr_malloc(o, sizeof(**p));
+    else if (!*p)
+    	return opt;
+
+    odr_implicit_settag(o, ODR_CONTEXT, 1);
+    if (odr_sequence_of(o, (Odr_fun)z_DatabaseSpecificUnit, &(*p)->elements,
+    	&(*p)->num_elements, 0))
+    	return 1;
+    *p = 0;
+    return 0;
+}
+
+int z_ElementSetNames(ODR o, Z_ElementSetNames **p, int opt, const char *name)
+{
+    static Odr_arm arm[] =
+    {
+    	{ODR_IMPLICIT, ODR_CONTEXT, 0, Z_ElementSetNames_generic,
+	    z_ElementSetName, 0},
+	{ODR_IMPLICIT, ODR_CONTEXT, 1, Z_ElementSetNames_databaseSpecific,
+	    (Odr_fun)z_DatabaseSpecific, 0},
+	{-1, -1, -1, -1, 0}
+    };
+
+    if (o->direction == ODR_DECODE)
+    	*p = (Z_ElementSetNames *)odr_malloc(o, sizeof(**p));
+    else if (!*p)
+    	return opt && odr_ok(o);
+
+    if (odr_choice(o, arm, &(*p)->u, &(*p)->which, 0))
+    	return 1;
+    *p = 0;
+    return 0;
+}
+
+/* ----------------------- RPN QUERY -----------------------*/
+
+int z_ComplexAttribute(ODR o, Z_ComplexAttribute **p, int opt,
+		       const char *name)
+{
+    if (!odr_sequence_begin(o, p, sizeof(**p), 0))
+    	return opt && odr_ok(o);
+    return
+    	odr_implicit_settag(o, ODR_CONTEXT, 1) &&
+    	odr_sequence_of(o, (Odr_fun)z_StringOrNumeric, &(*p)->list,
+	    &(*p)->num_list, 0) &&
+	odr_implicit_settag(o, ODR_CONTEXT, 2) &&
+	(odr_sequence_of(o, (Odr_fun)odr_integer, &(*p)->semanticAction,
+	    &(*p)->num_semanticAction, 0) || odr_ok(o)) &&
+	odr_sequence_end(o);
+}
+
+int z_AttributeElement(ODR o, Z_AttributeElement **p, int opt,
+		       const char *name)
+{
+    static Odr_arm arm[] =
+    {
+    	{ODR_IMPLICIT, ODR_CONTEXT, 121, Z_AttributeValue_numeric,
+	    (Odr_fun)odr_integer, 0},
+	{ODR_IMPLICIT, ODR_CONTEXT, 224, Z_AttributeValue_complex,
+	    (Odr_fun)z_ComplexAttribute, 0},
+	{-1, -1, -1, -1, 0, 0}
+    };
+    if (!odr_sequence_begin(o, p, sizeof(**p), 0))
+    	return opt && odr_ok(o);
+    return
+    	odr_implicit(o, odr_oid, &(*p)->attributeSet, ODR_CONTEXT, 1, 1) &&
+    	odr_implicit(o, odr_integer, &(*p)->attributeType, ODR_CONTEXT,
+	    120, 0) &&
+	odr_choice(o, arm, &(*p)->value, &(*p)->which, 0) &&
+    	odr_sequence_end(o);
+}
+
+int z_Term(ODR o, Z_Term **p, int opt, const char *name)
+{
+    static Odr_arm arm[] =
+    {
+    	{ODR_IMPLICIT, ODR_CONTEXT, 45, Z_Term_general,
+	 (Odr_fun)odr_octetstring, 0},
+	{ODR_IMPLICIT, ODR_CONTEXT, 215, Z_Term_numeric,
+	 (Odr_fun)odr_integer, 0},
+	{ODR_IMPLICIT, ODR_CONTEXT, 216, Z_Term_characterString,
+	    odr_visiblestring, 0},
+	{ODR_IMPLICIT, ODR_CONTEXT, 217, Z_Term_oid, (Odr_fun)odr_oid, 0},
+	{ODR_IMPLICIT, ODR_CONTEXT, 218, Z_Term_dateTime, odr_cstring, 0},
+	{ODR_IMPLICIT, ODR_CONTEXT, 219, Z_Term_external,
+	 (Odr_fun) z_External, 0},
+	/* add intUnit here */
+	{ODR_IMPLICIT, ODR_CONTEXT, 221, Z_Term_null, (Odr_fun)odr_null, 0},
+    	{-1, -1, -1, -1, 0, 0}
+    };
+
+    if (o->direction ==ODR_DECODE)
+    	*p = (Z_Term *)odr_malloc(o, sizeof(**p));
+    else if (!*p)
+    	return opt;
+    if (odr_choice(o, arm, &(*p)->u, &(*p)->which, 0))
+    	return 1;
+    *p = 0;
+    return opt && odr_ok(o);
+}
+
+int z_AttributesPlusTerm(ODR o, Z_AttributesPlusTerm **p, int opt,
+			 const char *name)
+{
+    if (!(odr_implicit_settag(o, ODR_CONTEXT, 102) &&
+    	odr_sequence_begin(o, p, sizeof(**p), 0)))
+    	return opt && odr_ok(o);
+    return
+    	odr_implicit_settag(o, ODR_CONTEXT, 44) &&
+    	odr_sequence_of(o, (Odr_fun)z_AttributeElement, &(*p)->attributeList,
+	    &(*p)->num_attributes, 0) &&
+	z_Term(o, &(*p)->term, 0, 0) &&
+	odr_sequence_end(o);
+}
+
+int z_ResultSetPlusAttributes(ODR o, Z_ResultSetPlusAttributes **p, int opt,
+			      const char *name)
+{
+    if (!(odr_implicit_settag(o, ODR_CONTEXT, 214) &&
+    	odr_sequence_begin(o, p, sizeof(**p), 0)))
+    	return opt && odr_ok(o);
+    return
+    	z_ResultSetId(o, &(*p)->resultSet, 0, 0) &&
+    	odr_implicit_settag(o, ODR_CONTEXT, 44) &&
+    	odr_sequence_of(o, (Odr_fun)z_AttributeElement, &(*p)->attributeList,
+	    &(*p)->num_attributes, 0) &&
+	odr_sequence_end(o);
+}
+
+int z_ProximityOperator(ODR o, Z_ProximityOperator **p, int opt,
+			const char *name)
+{
+    static Odr_arm arm[] =
+    {
+    	{ODR_IMPLICIT, ODR_CONTEXT, 1, Z_ProxCode_known,
+	 (Odr_fun)odr_integer, 0},
+    	{ODR_IMPLICIT, ODR_CONTEXT, 2, Z_ProxCode_private,
+	 (Odr_fun)odr_integer, 0},
+    	{-1, -1, -1, -1, 0, 0}
+    };
+
+    if (!odr_sequence_begin(o, p, sizeof(**p), 0))
+    	return opt && odr_ok(o);
+    return
+    	odr_implicit(o, odr_bool, &(*p)->exclusion, ODR_CONTEXT, 1, 1) &&
+	odr_implicit(o, odr_integer, &(*p)->distance, ODR_CONTEXT, 2, 0) &&
+	odr_implicit(o, odr_bool, &(*p)->ordered, ODR_CONTEXT, 3, 0) &&
+	odr_implicit(o, odr_integer, &(*p)->relationType, ODR_CONTEXT, 4, 0) &&
+	odr_constructed_begin(o, &(*p)->proximityUnitCode,
+			      ODR_CONTEXT, 5, 0) &&
+	odr_choice(o, arm, &(*p)->proximityUnitCode, &(*p)->which, 0) &&
+	odr_constructed_end(o) &&
+	odr_sequence_end(o);
+}
+
+int z_Operator(ODR o, Z_Operator **p, int opt, const char *name)
+{
+    static Odr_arm arm[] =
+    {
+    	{ODR_IMPLICIT, ODR_CONTEXT, 0, Z_Operator_and, (Odr_fun)odr_null, 0},
+    	{ODR_IMPLICIT, ODR_CONTEXT, 1, Z_Operator_or, (Odr_fun)odr_null, 0},
+    	{ODR_IMPLICIT, ODR_CONTEXT, 2, Z_Operator_and_not,
+	 (Odr_fun)odr_null, 0},
+    	{ODR_IMPLICIT, ODR_CONTEXT, 3, Z_Operator_prox,
+	 (Odr_fun)z_ProximityOperator, 0},
+    	{-1, -1, -1, -1, 0, 0}
+    };
+
+    if (!*p && o->direction != ODR_DECODE)
+    	return opt;
+    if (!odr_constructed_begin(o, p, ODR_CONTEXT, 46, 0))
+    	return opt && odr_ok(o);
+    if (o->direction == ODR_DECODE)
+    	*p = (Z_Operator *)odr_malloc(o, sizeof(**p));
+
+    if (odr_choice(o, arm, &(*p)->u, &(*p)->which, 0) &&
+    	odr_constructed_end(o))
+    	return 1;
+    *p = 0;
+    return opt && odr_ok(o);
+}
+
+int z_Operand(ODR o, Z_Operand **p, int opt, const char *name)
+{
+    static Odr_arm arm[] =
+    {
+    	{-1, -1, -1, Z_Operand_APT, (Odr_fun)z_AttributesPlusTerm, 0},
+    	{-1, -1, -1, Z_Operand_resultSetId, (Odr_fun)z_ResultSetId, 0},
+    	{-1, -1, -1, Z_Operand_resultAttr,
+	 (Odr_fun)z_ResultSetPlusAttributes, 0},
+    	{-1, -1, -1, -1, 0, 0}
+    };
+
+    if (o->direction == ODR_DECODE)
+    	*p = (Z_Operand *)odr_malloc(o, sizeof(**p));
+    else if (!*p)
+    	return opt;
+    if (odr_choice(o, arm, &(*p)->u, &(*p)->which, 0))
+    	return 1;
+    *p = 0;
+    return opt && odr_ok(o);
+}
+
+int z_RPNStructure(ODR o, Z_RPNStructure **p, int opt, const char *name);
+
+int z_Complex(ODR o, Z_Complex **p, int opt, const char *name)
+{
+    if (!odr_sequence_begin(o, p, sizeof(**p), 0))
+    	return opt && odr_ok(o);
+    return
+    	z_RPNStructure(o, &(*p)->s1, 0, 0) &&
+    	z_RPNStructure(o, &(*p)->s2, 0, 0) &&
+    	z_Operator(o, &(*p)->roperator, 0, 0) &&
+    	odr_sequence_end(o);
+}
+
+int z_RPNStructure(ODR o, Z_RPNStructure **p, int opt, const char *name)
+{
+    static Odr_arm arm[] = 
+    {
+    	{ODR_EXPLICIT, ODR_CONTEXT, 0, Z_RPNStructure_simple,
+	 (Odr_fun)z_Operand, 0},
+    	{ODR_IMPLICIT, ODR_CONTEXT, 1, Z_RPNStructure_complex,
+	 (Odr_fun)z_Complex, 0},
+    	{-1 -1, -1, -1, 0, 0}
+    };
+
+    if (o->direction == ODR_DECODE)
+    	*p = (Z_RPNStructure *)odr_malloc(o, sizeof(**p));
+    else if (!*p)
+    	return opt;
+    if (odr_choice(o, arm, &(*p)->u, &(*p)->which, 0))
+    	return 1;
+    *p = 0;
+    return opt && odr_ok(o);
+}
+
+int z_RPNQuery(ODR o, Z_RPNQuery **p, int opt, const char *name)
+{
+    if (!odr_sequence_begin(o, p, sizeof(**p), 0))
+    	return opt && odr_ok(o);
+    return
+    	odr_oid(o, &(*p)->attributeSetId, 0, 0) &&
+    	z_RPNStructure(o, &(*p)->RPNStructure, 0, 0) &&
+    	odr_sequence_end(o);
+}
+
+/* -----------------------END RPN QUERY ----------------------- */
+
+int z_Query(ODR o, Z_Query **p, int opt, const char *name)
+{
+    static Odr_arm arm[] = 
+    {
+    	{ODR_IMPLICIT, ODR_CONTEXT, 1, Z_Query_type_1,
+	 (Odr_fun)z_RPNQuery, 0},
+    	{ODR_EXPLICIT, ODR_CONTEXT, 2, Z_Query_type_2,
+	 (Odr_fun)odr_octetstring, 0},
+    	{ODR_IMPLICIT, ODR_CONTEXT, 101, Z_Query_type_101,
+	 (Odr_fun)z_RPNQuery, 0},
+    	{-1, -1, -1, -1, 0, 0}
+    };
+
+    if (o->direction == ODR_DECODE)
+    	*p = (Z_Query *)odr_malloc(o, sizeof(**p));
+    else if (!*p)
+    	return opt;
+    if (odr_choice(o, arm, &(*p)->u, &(*p)->which, 0))
+    	return 1;
+    *p = 0;
+    return opt && odr_ok(o);
+}
+
+int z_SearchRequest(ODR o, Z_SearchRequest **p, int opt, const char *name)
+{
+    Z_SearchRequest *pp;
+
+    if (!odr_sequence_begin(o, p, sizeof(**p), 0))
+    	return opt && odr_ok(o);
+    pp = *p;
+    return
+    	z_ReferenceId(o, &pp->referenceId, 1, 0) &&
+    	odr_implicit(o, odr_integer, &pp->smallSetUpperBound, ODR_CONTEXT,
+	    13, 0) &&
+	odr_implicit(o, odr_integer, &pp->largeSetLowerBound, ODR_CONTEXT,
+	    14, 0) &&
+	odr_implicit(o, odr_integer, &pp->mediumSetPresentNumber, ODR_CONTEXT,
+	    15, 0) &&
+	odr_implicit(o, odr_bool, &pp->replaceIndicator, ODR_CONTEXT, 16, 1) &&
+	odr_implicit(o, odr_visiblestring, &pp->resultSetName, ODR_CONTEXT,
+	    17, 9) &&
+	odr_implicit_settag(o, ODR_CONTEXT, 18) &&
+	odr_sequence_of(o, z_DatabaseName, &pp->databaseNames,
+	    &pp->num_databaseNames, 0) &&
+	odr_explicit(o, z_ElementSetNames, &pp->smallSetElementSetNames,
+	    ODR_CONTEXT, 100, 1) &&
+	odr_explicit(o, z_ElementSetNames, &pp->mediumSetElementSetNames,
+	    ODR_CONTEXT, 101, 1) &&
+	odr_implicit(o, odr_oid, &pp->preferredRecordSyntax,
+	    ODR_CONTEXT, 104, 1) &&
+	odr_explicit(o, z_Query, &pp->query, ODR_CONTEXT, 21, 0) &&
+	odr_implicit_tag(o, z_OtherInformation, &(*p)->additionalSearchInfo,
+	    ODR_CONTEXT, 203, 1, 0) &&
+	z_OtherInformation(o, &(*p)->otherInfo, 1, 0) &&
+	odr_sequence_end(o);
+}
+
+/* ------------------------ RECORD ------------------------- */
+
+int z_DatabaseRecord(ODR o, Z_DatabaseRecord **p, int opt, const char *name)
+{
+    return z_External(o, (Z_External **) p, opt, 0);
+}
+
+int z_DefaultDiagFormat(ODR o, Z_DefaultDiagFormat **p, int opt,
+			const char *name)
+{
+    static Odr_arm arm[] =
+    {
+    	{-1, -1, -1, Z_DiagForm_v2AddInfo, odr_visiblestring, 0},
+	{-1, -1, -1, Z_DiagForm_v3AddInfo, z_InternationalString, 0},
+    	{ODR_IMPLICIT, ODR_CONTEXT, ODR_VISIBLESTRING, Z_DiagForm_v2AddInfo,
+	    odr_visiblestring, 0}, /* To cater to a bug in the CNIDR servers */
+	{-1, -1, -1, -1, 0, 0}
+    };
+    if (!odr_sequence_begin(o, p, sizeof(**p), 0))
+    	return opt && odr_ok(o);
+    return
+    	odr_oid(o, &(*p)->diagnosticSetId, 1, 0) && /* SHOULD NOT BE OPT! */
+    	odr_integer(o, &(*p)->condition, 0, 0) &&
+	/*
+	 * I no longer recall what server tagged the addinfo.. but it isn't
+	 * hurting anyone, so...
+	 * We need to turn it into a choice, or something, because of
+	 * that damn generalstring in v3.
+	 */
+	odr_choice(o, arm, &(*p)->addinfo, &(*p)->which, 0) &&
+    	odr_sequence_end(o);
+}
+
+int z_DiagRec(ODR o, Z_DiagRec **p, int opt, const char *name)
+{
+    static Odr_arm arm[] = 
+    {
+    	{-1, -1, -1, Z_DiagRec_defaultFormat, (Odr_fun)z_DefaultDiagFormat, 0},
+    	{-1, -1, -1, Z_DiagRec_externallyDefined, (Odr_fun)z_External, 0},
+    	{-1, -1, -1, -1, 0, 0}
+    };
+
+    if (o->direction == ODR_DECODE)
+    	*p = (Z_DiagRec *)odr_malloc(o, sizeof(**p));
+    else if (!*p)
+    	return opt;
+    if (odr_choice(o, arm, &(*p)->u, &(*p)->which, 0))
+    	return 1;
+    *p = 0;
+    return opt && odr_ok(o);
+}
+
+int z_DiagRecs(ODR o, Z_DiagRecs **p, int opt, const char *name)
+{
+    if (o->direction == ODR_DECODE)
+    	*p = (Z_DiagRecs *)odr_malloc(o, sizeof(**p));
+    else if (!*p)
+    	return opt;
+
+	if (odr_sequence_of(o, (Odr_fun)z_DiagRec, &(*p)->diagRecs,
+    	&(*p)->num_diagRecs, 0))
+    	return 1;
+    *p = 0;
+    return opt && odr_ok(o);
+}
+
+int z_NamePlusRecord(ODR o, Z_NamePlusRecord **p, int opt, const char *name)
+{
+    static Odr_arm arm[] =
+    {
+    	{ODR_EXPLICIT, ODR_CONTEXT, 1, Z_NamePlusRecord_databaseRecord,
+	    (Odr_fun)z_DatabaseRecord, 0},
+	{ODR_EXPLICIT, ODR_CONTEXT, 2, Z_NamePlusRecord_surrogateDiagnostic,
+	    (Odr_fun)z_DiagRec, 0},
+	{-1, -1, -1, -1, 0, 0}
+    };
+
+    if (!odr_sequence_begin(o, p, sizeof(**p), 0))
+    	return opt && odr_ok(o);
+    return
+    	odr_implicit(o, z_DatabaseName, &(*p)->databaseName, ODR_CONTEXT,
+	    0, 1) &&
+	odr_constructed_begin(o, &(*p)->u, ODR_CONTEXT, 1, 0) &&
+	odr_choice(o, arm, &(*p)->u, &(*p)->which, 0) &&
+	odr_constructed_end(o) &&
+	odr_sequence_end(o);
+}
+
+int z_NamePlusRecordList(ODR o, Z_NamePlusRecordList **p, int opt,
+			 const char *name)
+{
+    if (o->direction == ODR_DECODE)
+    	*p = (Z_NamePlusRecordList *)odr_malloc(o, sizeof(**p));
+    else if (!*p)
+    	return opt;
+    if (odr_sequence_of(o, (Odr_fun)z_NamePlusRecord, &(*p)->records,
+	&(*p)->num_records, 0))
+    	return 1;
+    *p = 0;
+    return 0;
+}
+
+int z_Records(ODR o, Z_Records **p, int opt, const char *name)
+{
+    static Odr_arm arm[] = 
+    {
+    	{ODR_IMPLICIT, ODR_CONTEXT, 28, Z_Records_DBOSD,
+	 (Odr_fun)z_NamePlusRecordList, 0},
+    	{ODR_IMPLICIT, ODR_CONTEXT, 130, Z_Records_NSD,
+	 (Odr_fun)z_DiagRec, 0},
+    	{ODR_IMPLICIT, ODR_CONTEXT, 205, Z_Records_multipleNSD,
+	    (Odr_fun)z_DiagRecs, 0},
+    	{-1, -1, -1, -1, 0, 0}
+    };
+
+    if (o->direction == ODR_DECODE)
+    	*p = (Z_Records *)odr_malloc(o, sizeof(**p));
+    else if (!*p)
+    	return opt;
+    if (odr_choice(o, arm, &(*p)->u, &(*p)->which, 0))
+    	return 1;
+    *p = 0;
+    return opt && odr_ok(o);
+}
+
+/* ------------------------ ACCESS CTRL SERVICE ----------------------- */
+
+int z_AccessControlRequest(ODR o, Z_AccessControlRequest **p, int opt,
+			   const char *name)
+{
+    static Odr_arm arm[] = 
+    {
+	{ODR_IMPLICIT, ODR_CONTEXT, 37, Z_AccessRequest_simpleForm,
+	    (Odr_fun)odr_octetstring, 0},
+	{ODR_EXPLICIT, ODR_CONTEXT, 0, Z_AccessRequest_externallyDefined,
+	    (Odr_fun)z_External, 0},
+    	{-1, -1, -1, -1, 0, 0}
+    };
+    if (!odr_sequence_begin(o, p, sizeof(**p), 0))
+    	return opt && odr_ok(o);
+    return
+    	z_ReferenceId(o, &(*p)->referenceId, 1, 0) &&
+	odr_choice(o, arm, &(*p)->u, &(*p)->which, 0) &&
+	z_OtherInformation(o, &(*p)->otherInfo, 1, 0) &&
+	odr_sequence_end(o);
+}
+
+int z_AccessControlResponse(ODR o, Z_AccessControlResponse **p, int opt,
+			    const char *name)
+{
+    static Odr_arm arm[] = 
+    {
+	{ODR_IMPLICIT, ODR_CONTEXT, 38, Z_AccessResponse_simpleForm,
+	    (Odr_fun)odr_octetstring, 0},
+	{ODR_EXPLICIT, ODR_CONTEXT, 0, Z_AccessResponse_externallyDefined,
+	    (Odr_fun)z_External, 0},
+    	{-1, -1, -1, -1, 0, 0}
+    };
+    if (!odr_sequence_begin(o, p, sizeof(**p), 0))
+    	return opt && odr_ok(o);
+    return
+    	z_ReferenceId(o, &(*p)->referenceId, 1, 0) &&
+	odr_choice(o, arm, &(*p)->u, &(*p)->which, 0) &&
+	odr_explicit(o, z_DiagRec, &(*p)->diagnostic, ODR_CONTEXT, 223, 1) &&
+	z_OtherInformation(o, &(*p)->otherInfo, 1, 0) &&
+	odr_sequence_end(o);
+}
+
+/* ------------------------ SCAN SERVICE -------------------- */
+
+int z_AttributeList(ODR o, Z_AttributeList **p, int opt, const char *name)
+{
+    if (o->direction == ODR_DECODE)
+    	*p = (Z_AttributeList *)odr_malloc(o, sizeof(**p));
+    else if (!*p)
+    	return opt;
+
+    odr_implicit_settag(o, ODR_CONTEXT, 44);
+    if (odr_sequence_of(o, (Odr_fun)z_AttributeElement, &(*p)->attributes,
+    	&(*p)->num_attributes, 0))
+    	return 1;
+    *p = 0;
+    return opt && odr_ok(o);
+}
+
+/*
+ * This is a temporary hack. We don't know just *what* old version of the
+ * protocol willow uses, so we'll just patiently wait for them to update
+ */
+static int willow_scan = 0;
+
+int z_WillowAttributesPlusTerm(ODR o, Z_AttributesPlusTerm **p, int opt,
+			       const char *name)
+{
+    if (!*p && o->direction != ODR_DECODE)
+    	return opt;
+    if (!odr_constructed_begin(o, p, ODR_CONTEXT, 4, 0))
+    {
+    	o->t_class = -1;
+    	return opt && odr_ok(o);
+    }
+    if (!odr_constructed_begin(o, p, ODR_CONTEXT, 1, 0))
+    	return 0;
+    if (!odr_constructed_begin(o, p, ODR_UNIVERSAL, ODR_SEQUENCE, 0))
+    	return 0;
+    if (!odr_implicit_settag(o, ODR_CONTEXT, 44))
+    	return 0;
+    if (o->direction == ODR_DECODE)
+    	*p = (Z_AttributesPlusTerm*)odr_malloc(o, sizeof(**p));
+    if (!odr_sequence_of(o, (Odr_fun)z_AttributeElement, &(*p)->attributeList,
+	&(*p)->num_attributes, 0))
+	return 0;
+    if (!odr_sequence_end(o) || !odr_sequence_end(o))
+    	return 0;
+    if (!z_Term(o, &(*p)->term, 0, 0))
+    	return 0;
+    if (!odr_constructed_end(o))
+    	return 0;
+    willow_scan = 1;
+    return 1;
+}
+
+int z_AlternativeTerm(ODR o, Z_AlternativeTerm **p, int opt, const char *name)
+{
+    if (o->direction == ODR_DECODE)
+    	*p = (Z_AlternativeTerm *)odr_malloc(o, sizeof(**p));
+    else if (!*p)
+    {
+    	o->t_class = -1;
+    	return opt && odr_ok(o);
+    }
+
+    if (odr_sequence_of(o, (Odr_fun)z_AttributesPlusTerm, &(*p)->terms,
+    	&(*p)->num_terms, 0))
+    	return 1;
+    *p = 0;
+    return opt && !o->error;
+}
+
+int z_ByDatabase(ODR o, Z_ByDatabase **p, int opt, const char *name)
+{
+    if (!odr_sequence_begin(o, p, sizeof(**p), 0))
+	return opt && odr_ok(o);
+    return
+        z_DatabaseName(o, &(*p)->db, 1, 0) &&
+	odr_implicit(o, odr_integer, &(*p)->num, ODR_CONTEXT, 1, 1) &&
+	z_OtherInformation(o, &(*p)->otherDbInfo, 1, 0) &&
+	odr_sequence_end(o);
+}
+
+int z_ByDatabaseList(ODR o, Z_ByDatabaseList **p, int opt, const char *name)
+{
+    if (!odr_initmember(o, p, sizeof(**p)))
+	return opt && odr_ok(o);
+    if (odr_sequence_of(o, (Odr_fun)z_ByDatabase, &(*p)->elements,
+			&(*p)->num_elements, 0))
+	return 1;
+    *p = 0;
+    return opt && odr_ok(o);
+}
+
+int z_ScanOccurrences(ODR o, Z_ScanOccurrences **p, int opt, const char *name)
+{
+    Odr_arm arm[] =
+    {
+	{ODR_EXPLICIT, ODR_CONTEXT, 2, Z_ScanOccurrences_global,
+	 (Odr_fun)odr_integer, 0},
+	{ODR_EXPLICIT, ODR_CONTEXT, 3, Z_ScanOccurrences_byDatabase,
+	    (Odr_fun)z_ByDatabaseList, 0},
+	{-1, -1, -1, -1, 0, 0}
+    };
+
+    if (!odr_initmember(o, p, sizeof(**p)))
+	return opt && odr_ok(o);
+    if (odr_choice(o, arm, &(*p)->u, &(*p)->which, 0))
+	return 1;
+    *p = 0;
+    return opt && odr_ok(o);
+}
+
+int z_OccurrenceByAttributesElem(ODR o, Z_OccurrenceByAttributesElem **p,
+    int opt, const char *name)
+{
+    if (!odr_sequence_begin(o, p, sizeof(**p), 0))
+	return opt && odr_ok(o);
+    return
+        odr_explicit(o, z_AttributeList, &(*p)->attributes, ODR_CONTEXT,
+	    1, 1) &&
+	z_ScanOccurrences(o, &(*p)->occurrences, 1, 0) &&
+	z_OtherInformation(o, &(*p)->otherOccurInfo, 1, 0) &&
+	odr_sequence_end(o);
+}
+
+int z_OccurrenceByAttributes(ODR o, Z_OccurrenceByAttributes **p, int opt, const char *name)
+{
+    if (!odr_initmember(o, p, sizeof(**p)))
+	return opt && odr_ok(o);
+    if (!odr_sequence_of(o, (Odr_fun)z_OccurrenceByAttributesElem,
+			 &(*p)->elements, &(*p)->num_elements, 0))
+	return 1;
+    *p = 0;
+    return opt && odr_ok(o);
+}
+
+int z_TermInfo(ODR o, Z_TermInfo **p, int opt, const char *name)
+{
+    if (!odr_sequence_begin(o, p, sizeof(**p), 0))
+    	return opt && odr_ok(o);
+    return
+    	(willow_scan ? 
+    	    odr_implicit(o, z_Term, &(*p)->term, ODR_CONTEXT, 1, 0) :
+	    z_Term(o, &(*p)->term, 0, 0)) &&
+	odr_implicit(o, z_InternationalString, &(*p)->displayTerm, ODR_CONTEXT,
+	    0, 1) &&
+	z_AttributeList(o, &(*p)->suggestedAttributes, 1, 0) &&
+	odr_implicit(o, z_AlternativeTerm, &(*p)->alternativeTerm,
+	    ODR_CONTEXT, 4, 1) &&
+	odr_implicit(o, odr_integer, &(*p)->globalOccurrences, ODR_CONTEXT,
+	    2, 1) &&
+	odr_implicit(o, z_OccurrenceByAttributes, &(*p)->byAttributes,
+	    ODR_CONTEXT, 3, 1) &&
+	z_OtherInformation(o, &(*p)->otherTermInfo, 1, 0) &&
+	odr_sequence_end(o);
+}
+
+int z_Entry(ODR o, Z_Entry **p, int opt, const char *name)
+{
+    static Odr_arm arm[] =
+    {
+	{ODR_IMPLICIT, ODR_CONTEXT, 1, Z_Entry_termInfo,
+	 (Odr_fun)z_TermInfo, 0},
+	{ODR_EXPLICIT, ODR_CONTEXT, 2, Z_Entry_surrogateDiagnostic,
+	    (Odr_fun)z_DiagRec, 0},
+	{-1, -1, -1, -1, 0, 0}
+    };
+
+    if (o->direction == ODR_DECODE)
+    	*p = (Z_Entry *)odr_malloc(o, sizeof(**p));
+    else if (!*p)
+    	return opt;
+
+    if (odr_choice(o, arm, &(*p)->u, &(*p)->which, 0))
+    	return 1;
+    *p = 0;
+    return opt && odr_ok(o);
+}
+
+int z_ListEntries (ODR o, Z_ListEntries **p, int opt, const char *name)
+{
+    if (!odr_sequence_begin (o, p, sizeof(**p), 0))
+	return opt && odr_ok (o);
+    return
+	odr_implicit_settag (o, ODR_CONTEXT, 1) &&
+	(odr_sequence_of(o, (Odr_fun) z_Entry, &(*p)->entries,
+			 &(*p)->num_entries, 0) || odr_ok(o)) &&
+	odr_implicit_settag (o, ODR_CONTEXT, 2) &&
+	(odr_sequence_of(o, (Odr_fun) z_DiagRec,
+			 &(*p)->nonsurrogateDiagnostics,
+			 &(*p)->num_nonsurrogateDiagnostics, 0) 
+	 || odr_ok(o)) &&
+	odr_sequence_end (o);
+}
+
+int z_ScanRequest(ODR o, Z_ScanRequest **p, int opt, const char *name)
+{
+    if (!odr_sequence_begin(o, p, sizeof(**p), 0))
+    	return opt && odr_ok(o);
+    willow_scan = 0;
+    return
+    	z_ReferenceId(o, &(*p)->referenceId, 1, 0) &&
+	odr_implicit_settag(o, ODR_CONTEXT, 3) &&
+	odr_sequence_of(o, z_DatabaseName, &(*p)->databaseNames,
+			&(*p)->num_databaseNames, 0) &&
+	odr_oid(o, &(*p)->attributeSet, 1, 0) &&
+	(z_AttributesPlusTerm(o, &(*p)->termListAndStartPoint, 1, 0) ?
+	 ((*p)->termListAndStartPoint ? 1 : 
+	  z_WillowAttributesPlusTerm(o, &(*p)->termListAndStartPoint, 0, 0))
+	 : 0) &&
+	odr_implicit(o, odr_integer, &(*p)->stepSize, ODR_CONTEXT, 5, 1) &&
+	odr_implicit(o, odr_integer, &(*p)->numberOfTermsRequested,
+		     ODR_CONTEXT, 6, 0) &&
+	odr_implicit(o, odr_integer, &(*p)->preferredPositionInResponse,
+		     ODR_CONTEXT, 7, 1) &&
+	z_OtherInformation(o, &(*p)->otherInfo, 1, "otherInfo") &&
+	odr_sequence_end(o);
+}
+
+int z_ScanResponse(ODR o, Z_ScanResponse **p, int opt, const char *name)
+{
+    if (!odr_sequence_begin(o, p, sizeof(**p), 0))
+    	return opt && odr_ok(o);
+    return
+    	z_ReferenceId(o, &(*p)->referenceId, 1, 0) &&
+	odr_implicit(o, odr_integer, &(*p)->stepSize, ODR_CONTEXT, 3, 1) &&
+	odr_implicit(o, odr_integer, &(*p)->scanStatus, ODR_CONTEXT, 4, 0) &&
+	odr_implicit(o, odr_integer, &(*p)->numberOfEntriesReturned,
+		     ODR_CONTEXT, 5, 0) &&
+	odr_implicit(o, odr_integer, &(*p)->positionOfTerm,
+		     ODR_CONTEXT, 6, 1) &&
+	odr_implicit(o, z_ListEntries, &(*p)->entries, ODR_CONTEXT, 7, 1) &&
+	odr_implicit(o, odr_oid, &(*p)->attributeSet, ODR_CONTEXT, 8, 1) &&
+	z_OtherInformation(o, &(*p)->otherInfo, 1, 0) &&
+	odr_sequence_end(o);
+}
+
+/* ------------------------ SEARCHRESPONSE ----------------*/
+
+int z_NumberOfRecordsReturned(ODR o, int **p, int opt, const char *name)
+{
+    return odr_implicit(o, odr_integer, p, ODR_CONTEXT, 24, opt);
+}
+
+int z_NextResultSetPosition(ODR o, int **p, int opt, const char *name)
+{
+    return odr_implicit(o, odr_integer, p, ODR_CONTEXT, 25, opt);
+}
+
+int z_PresentStatus(ODR o, int **p, int opt, const char *name)
+{
+    return odr_implicit(o, odr_integer, p, ODR_CONTEXT, 27, opt);
+}
+
+int z_SearchResponse(ODR o, Z_SearchResponse **p, int opt, const char *name)
+{
+    Z_SearchResponse *pp;
+
+    if (!odr_sequence_begin(o, p, sizeof(**p), 0))
+    	return opt && odr_ok(o);
+    pp = *p;
+    return
+    	z_ReferenceId(o, &pp->referenceId, 1, 0) &&
+    	odr_implicit(o, odr_integer, &pp->resultCount, ODR_CONTEXT, 23, 0) &&
+    	z_NumberOfRecordsReturned(o, &pp->numberOfRecordsReturned, 0, 0) &&
+    	z_NextResultSetPosition(o, &pp->nextResultSetPosition, 0, 0) &&
+    	odr_implicit(o, odr_bool, &pp->searchStatus, ODR_CONTEXT, 22, 0) &&
+    	odr_implicit(o, odr_integer, &pp->resultSetStatus,
+		     ODR_CONTEXT, 26, 1) &&
+    	z_PresentStatus(o, &pp->presentStatus, 1, 0) &&
+    	z_Records(o, &pp->records, 1, 0) &&
+	odr_implicit(o, z_OtherInformation, &(*p)->additionalSearchInfo,
+		     ODR_CONTEXT, 203, 1) &&
+	z_OtherInformation(o, &(*p)->otherInfo, 1, 0) &&
+	odr_sequence_end(o);
+}
+
+/* --------------------- PRESENT SERVICE ---------------------- */
+
+int z_ElementSpec(ODR o, Z_ElementSpec **p, int opt, const char *name)
+{
+    static Odr_arm arm[] =
+    {
+    	{ODR_IMPLICIT, ODR_CONTEXT, 1, Z_ElementSpec_elementSetName,
+	    odr_visiblestring, 0},
+	{ODR_IMPLICIT, ODR_CONTEXT, 2, Z_ElementSpec_externalSpec,
+	    (Odr_fun)z_External, 0},
+	{-1, -1, -1, -1, 0, 0}
+    };
+
+    if (o->direction == ODR_DECODE)
+    	*p = (Z_ElementSpec *)odr_malloc(o, sizeof(**p));
+    else if (!*p)
+    	return opt;
+
+    if (odr_choice(o, arm, &(*p)->u, &(*p)->which, 0))
+    	return 1;
+    *p = 0;
+    return opt && odr_ok(o);
+}
+
+int z_Specification(ODR o, Z_Specification **p, int opt, const char *name)
+{
+    if (!odr_sequence_begin(o, p, sizeof(**p), 0))
+    	return opt && odr_ok(o);
+    return
+    	odr_implicit(o, odr_oid, &(*p)->schema, ODR_CONTEXT, 1, 1) &&
+	z_ElementSpec(o, &(*p)->elementSpec, 1, 0) &&
+	odr_sequence_end(o);
+}
+
+int z_DbSpecific(ODR o, Z_DbSpecific **p, int opt, const char *name)
+{
+    if (!odr_sequence_begin(o, p, sizeof(**p), 0))
+    	return opt && odr_ok(o);
+    return
+    	odr_explicit(o, z_DatabaseName, &(*p)->databaseName, ODR_CONTEXT,
+	    1, 0) &&
+	odr_implicit(o, z_Specification, &(*p)->spec, ODR_CONTEXT, 2, 0) &&
+	odr_sequence_end(o);
+}
+
+int z_CompSpec(ODR o, Z_CompSpec **p, int opt, const char *name)
+{
+    if (!odr_sequence_begin(o, p, sizeof(**p), 0))
+    	return opt && odr_ok(o);
+    return
+    	odr_implicit(o, odr_bool, &(*p)->selectAlternativeSyntax, ODR_CONTEXT,
+		     1, 0) &&
+	odr_implicit(o, z_Specification, &(*p)->generic, ODR_CONTEXT, 2, 1) &&
+	odr_implicit_settag(o, ODR_CONTEXT, 3) &&
+	(odr_sequence_of(o, (Odr_fun)z_DbSpecific, &(*p)->dbSpecific,
+			 &(*p)->num_dbSpecific, 0) || odr_ok(o)) &&
+	odr_implicit_settag(o, ODR_CONTEXT, 4) &&
+	(odr_sequence_of(o, (Odr_fun)odr_oid, &(*p)->recordSyntax,
+			 &(*p)->num_recordSyntax, 0) || odr_ok(o)) &&
+	odr_sequence_end(o);
+}
+
+int z_RecordComposition(ODR o, Z_RecordComposition **p, int opt,
+			const char *name)
+{
+    static Odr_arm arm[] =
+    {
+    	{ODR_EXPLICIT, ODR_CONTEXT, 19, Z_RecordComp_simple,
+	 (Odr_fun)z_ElementSetNames, 0},
+	{ODR_IMPLICIT, ODR_CONTEXT, 209, Z_RecordComp_complex,
+	 (Odr_fun)z_CompSpec, 0},
+	{-1, -1, -1, -1, 0, 0}
+    };
+    
+    if (o->direction == ODR_DECODE)
+    	*p = (Z_RecordComposition *)odr_malloc(o, sizeof(**p));
+    else if (!*p)
+    	return opt;
+    
+    if (odr_choice(o, arm, &(*p)->u, &(*p)->which, 0))
+    	return 1;
+    *p = 0;
+    return opt && odr_ok(o);
+}
+
+int z_Range(ODR o, Z_Range **p, int opt, const char *name)
+{
+    if (!odr_sequence_begin(o, p, sizeof(**p), 0))
+    	return opt && odr_ok(o);
+    return
+    	odr_implicit(o, odr_integer, &(*p)->startingPosition,
+		     ODR_CONTEXT, 1, 0) &&
+	odr_implicit(o, odr_integer, &(*p)->numberOfRecords,
+		     ODR_CONTEXT, 2, 0) &&
+	odr_sequence_end(o);
+}
+
+int z_PresentRequest(ODR o, Z_PresentRequest **p, int opt, const char *name)
+{
+    Z_PresentRequest *pp;
+    
+    if (!odr_sequence_begin(o, p, sizeof(**p), 0))
+    	return opt && odr_ok(o);
+    pp = *p;
+    return
+    	z_ReferenceId(o, &pp->referenceId, 1, 0) &&
+    	z_ResultSetId(o, &pp->resultSetId, 0, 0) &&
+    	odr_implicit(o, odr_integer, &pp->resultSetStartPoint,
+		     ODR_CONTEXT, 30, 0) &&
+	odr_implicit(o, odr_integer, &pp->numberOfRecordsRequested,
+		     ODR_CONTEXT, 29, 0) &&
+	odr_implicit_settag(o, ODR_CONTEXT, 212) &&
+	(odr_sequence_of(o, (Odr_fun)z_Range, &(*p)->additionalRanges,
+			 &(*p)->num_ranges, 0) || odr_ok(o)) &&
+	z_RecordComposition(o, &(*p)->recordComposition, 1, 0) &&
+	odr_implicit(o, odr_oid, &(*p)->preferredRecordSyntax, ODR_CONTEXT,
+		     104, 1) &&
+	odr_implicit(o, odr_integer, &(*p)->maxSegmentCount, ODR_CONTEXT,
+		     204, 1) &&
+	odr_implicit(o, odr_integer, &(*p)->maxRecordSize, ODR_CONTEXT,
+		     206, 1) &&
+	odr_implicit(o, odr_integer, &(*p)->maxSegmentSize, ODR_CONTEXT,
+		     207, 1) &&
+	z_OtherInformation(o, &(*p)->otherInfo, 1, 0) &&
+	odr_sequence_end(o);
+}
+
+int z_PresentResponse(ODR o, Z_PresentResponse **p, int opt, const char *name)
+{
+    Z_PresentResponse *pp;
+
+    if (!odr_sequence_begin(o, p, sizeof(**p), 0))
+    	return opt && odr_ok(o);
+    pp = *p;
+    return
+    	z_ReferenceId(o, &pp->referenceId, 1, 0) &&
+    	z_NumberOfRecordsReturned(o, &pp->numberOfRecordsReturned, 0, 0) &&
+    	z_NextResultSetPosition(o, &pp->nextResultSetPosition, 0, 0) &&
+    	z_PresentStatus(o, &pp->presentStatus, 0, 0) &&
+    	z_Records(o, &pp->records, 1, 0) &&
+	z_OtherInformation(o, &(*p)->otherInfo, 1, 0) &&
+    	odr_sequence_end(o);
+}
+
+/* ----------------------DELETE -------------------------- */
+
+int z_DeleteSetStatus(ODR o, int **p, int opt, const char *name)
+{
+    return odr_implicit(o, odr_integer, p, ODR_CONTEXT, 33, opt);
+}
+
+int z_ListStatus(ODR o, Z_ListStatus **p, int opt, const char *name)
+{
+    if (!odr_sequence_begin(o, p, sizeof(**p), 0))
+    	return opt && odr_ok(o);
+    return
+    	z_ResultSetId(o, &(*p)->id, 0, 0) &&
+	z_DeleteSetStatus(o, &(*p)->status, 0, 0) &&
+	odr_sequence_end(o);
+}
+
+int z_DeleteResultSetRequest(ODR o, Z_DeleteResultSetRequest **p, int opt,
+			     const char *name)
+{
+    if (!odr_sequence_begin(o, p, sizeof(**p), 0))
+    	return opt && odr_ok(o);
+    return
+    	z_ReferenceId(o, &(*p)->referenceId, 1, 0) &&
+	odr_implicit(o, odr_integer, &(*p)->deleteFunction, ODR_CONTEXT, 32,
+	    0) &&
+	(odr_sequence_of(o, z_ResultSetId, &(*p)->resultSetList,
+			 &(*p)->num_resultSetList, 0) || odr_ok(o)) &&
+	z_OtherInformation(o, &(*p)->otherInfo, 1, 0) &&
+	odr_sequence_end(o);
+}
+
+int z_ListStatuses (ODR o, Z_ListStatuses **p, int opt, const char *name)
+{
+    if (!odr_initmember (o, p, sizeof(**p)))
+        return opt && odr_ok(o);
+    if (odr_sequence_of (o, (Odr_fun) z_ListStatus, &(*p)->elements,
+			 &(*p)->num, 0))
+        return 1;
+    *p = 0;
+    return opt && odr_ok(o);
+}
+
+int z_DeleteResultSetResponse(ODR o, Z_DeleteResultSetResponse **p, int opt,
+			      const char *name)
+{
+    if (!odr_sequence_begin(o, p, sizeof(**p), 0))
+    	return opt && odr_ok(o);
+    return
+    	z_ReferenceId(o, &(*p)->referenceId, 1, 0) &&
+	odr_implicit(o, z_DeleteSetStatus, &(*p)->deleteOperationStatus,
+		     ODR_CONTEXT, 0, 0) &&
+        odr_implicit (o, z_ListStatuses,
+		      &(*p)->deleteListStatuses, ODR_CONTEXT, 1, 1) &&
+	odr_implicit(o, odr_integer, &(*p)->numberNotDeleted, ODR_CONTEXT,
+		     34, 1) &&
+        odr_implicit (o, z_ListStatuses,
+		      &(*p)->bulkStatuses, ODR_CONTEXT, 35, 1) &&
+	odr_implicit(o, odr_visiblestring, &(*p)->deleteMessage, ODR_CONTEXT,
+		     36, 1) &&
+	z_OtherInformation(o, &(*p)->otherInfo, 1, 0) &&
+	odr_sequence_end(o);
+}
+
+/* ------------------------ SEGMENT SERVICE -------------- */
+
+int z_Segment(ODR o, Z_Segment **p, int opt, const char *name)
+{
+    if (!odr_sequence_begin(o, p, sizeof(**p), 0))
+    	return opt && odr_ok(o);
+    return
+    	z_ReferenceId(o, &(*p)->referenceId, 1, 0) &&
+	odr_implicit(o, odr_integer, &(*p)->numberOfRecordsReturned,
+		     ODR_CONTEXT, 24, 0) &&
+	odr_implicit_settag(o, ODR_CONTEXT, 0) &&
+	odr_sequence_of(o, (Odr_fun)z_NamePlusRecord, &(*p)->segmentRecords,
+			&(*p)->num_segmentRecords, 0) &&
+	z_OtherInformation(o, &(*p)->otherInfo, 1, 0) &&
+	odr_sequence_end(o);
+}
+
+/* ------------------------ CLOSE SERVICE ---------------- */
+
+int z_Close(ODR o, Z_Close **p, int opt, const char *name)
+{
+    if (!odr_sequence_begin(o, p, sizeof(**p), 0))
+    	return opt && odr_ok(o);
+    return
+    	z_ReferenceId(o, &(*p)->referenceId, 1, 0) &&
+	odr_implicit(o, odr_integer, &(*p)->closeReason, ODR_CONTEXT, 211, 0)
+	&&
+	odr_implicit(o, odr_visiblestring, &(*p)->diagnosticInformation,
+		     ODR_CONTEXT, 3, 1) &&
+	odr_implicit(o, odr_oid, &(*p)->resourceReportFormat, ODR_CONTEXT,
+		     4, 1) &&
+	odr_implicit(o, z_External, &(*p)->resourceReport, ODR_CONTEXT,
+		     5, 1) &&
+	z_OtherInformation(o, &(*p)->otherInfo, 1, 0) &&
+	odr_sequence_end(o);
+}
+
+/* ------------------------ APDU ------------------------- */
+
+int z_Permissions(ODR o, Z_Permissions **p, int opt, const char *name)
+{
+    if (!odr_sequence_begin(o, p, sizeof(**p), 0))
+        return opt && odr_ok(o);
+    return
+        odr_implicit(o, z_InternationalString, &(*p)->userId, ODR_CONTEXT,
+		     1, 0) &&
+	odr_implicit_settag(o, ODR_CONTEXT, 2) &&
+	odr_sequence_of(o, (Odr_fun)odr_integer, &(*p)->allowableFunctions,
+			&(*p)->num_allowableFunctions, 0) &&
+	odr_sequence_end(o);
+}
+
+int z_ExtendedServicesRequest(ODR o, Z_ExtendedServicesRequest **p, int opt,
+			      const char *name)
+{
+    if (!odr_sequence_begin(o, p, sizeof(**p), 0))
+        return opt && odr_ok(o);
+    return
+        z_ReferenceId(o, &(*p)->referenceId, 1, 0) &&
+        odr_implicit(o, odr_integer, &(*p)->function, ODR_CONTEXT, 3, 0) &&
+        odr_implicit(o, odr_oid, &(*p)->packageType, ODR_CONTEXT, 4, 0) &&
+        odr_implicit(o, z_InternationalString, &(*p)->packageName,
+		     ODR_CONTEXT, 5, 1) &&
+        odr_implicit(o, z_InternationalString, &(*p)->userId,
+		     ODR_CONTEXT, 6, 1) &&
+        odr_implicit(o, z_IntUnit, &(*p)->retentionTime,
+		     ODR_CONTEXT, 7, 1) &&
+        odr_implicit(o, z_Permissions, &(*p)->permissions,
+		     ODR_CONTEXT, 8, 1) &&
+        odr_implicit(o, z_InternationalString, &(*p)->description,
+		     ODR_CONTEXT, 9, 1) &&
+        odr_implicit(o, z_External, &(*p)->taskSpecificParameters,
+		     ODR_CONTEXT, 10, 1) &&
+        odr_implicit(o, odr_integer, &(*p)->waitAction,
+		     ODR_CONTEXT, 11, 0) &&
+        z_ElementSetName(o, &(*p)->elements, 1, 0) &&
+        z_OtherInformation(o, &(*p)->otherInfo, 1, 0) &&
+        odr_sequence_end(o);
+}
+
+int z_ExtendedServicesResponse(ODR o, Z_ExtendedServicesResponse **p, int opt,
+			       const char *name)
+{
+    if (!odr_sequence_begin(o, p, sizeof(**p), 0))
+        return opt && odr_ok(o);
+    return
+        z_ReferenceId(o, &(*p)->referenceId, 1, 0) &&
+        odr_implicit(o, odr_integer, &(*p)->operationStatus, ODR_CONTEXT,
+		     3, 0) &&
+	odr_implicit_settag(o, ODR_CONTEXT, 4) &&
+	(odr_sequence_of(o, (Odr_fun)z_DiagRec, &(*p)->diagnostics,
+			 &(*p)->num_diagnostics, 0) || odr_ok(o)) &&
+        odr_implicit(o, z_External, &(*p)->taskPackage, ODR_CONTEXT, 5, 1) &&
+        z_OtherInformation(o, &(*p)->otherInfo, 1, 0) &&
+        odr_sequence_end(o);
+}
+
+/* ------------------------ SORT ------------------------- */
+
+int z_SortAttributes(ODR o, Z_SortAttributes **p, int opt, const char *name)
+{
+    if (!odr_sequence_begin(o, p, sizeof(**p), 0))
+	return opt && odr_ok(o);
+    return
+        odr_oid(o, &(*p)->id, 0, 0) &&
+	z_AttributeList(o, &(*p)->list, 0, 0) &&
+	odr_sequence_end(o);
+}
+
+int z_SortKey(ODR o, Z_SortKey **p, int opt, const char *name)
+{
+    static Odr_arm arm[] =
+    {
+	{ODR_IMPLICIT, ODR_CONTEXT, 0, Z_SortKey_sortField,
+	 z_InternationalString, 0},
+	{ODR_IMPLICIT, ODR_CONTEXT, 1, Z_SortKey_elementSpec,
+	 (Odr_fun)z_Specification, 0},
+	{ODR_IMPLICIT, ODR_CONTEXT, 2, Z_SortKey_sortAttributes,
+	 (Odr_fun)z_SortAttributes, 0},
+	{-1, -1, -1, -1, 0}
+    };
+
+    if (!odr_initmember(o, p, sizeof(**p)))
+	return opt && odr_ok(o);
+    if (odr_choice(o, arm, &(*p)->u, &(*p)->which, 0))
+	return 1;
+    *p = 0;
+    return opt && odr_ok(o);
+}
+
+int z_SortDbSpecific(ODR o, Z_SortDbSpecific **p, int opt, const char *name)
+{
+    if (!odr_sequence_begin(o, p, sizeof(**p), 0))
+	return opt && odr_ok(o);
+    return
+        z_DatabaseName(o, &(*p)->databaseName, 0, 0) &&
+	z_SortKey(o, &(*p)->dbSort, 0, 0) &&
+	odr_sequence_end(o);
+}
+
+int z_SortDbSpecificList(ODR o, Z_SortDbSpecificList **p, int opt,
+			 const char *name)
+{
+    if (!odr_initmember(o, p, sizeof(**p)))
+	return opt && odr_ok(o);
+    if (odr_sequence_of(o, (Odr_fun)z_SortDbSpecific, &(*p)->dbSpecific,
+			&(*p)->num_dbSpecific, 0))
+	return 1;
+    *p = 0;
+    return opt && odr_ok(o);
+}
+
+int z_SortElement(ODR o, Z_SortElement **p, int opt, const char *name)
+{
+    static Odr_arm arm[] =
+    {
+	{ODR_EXPLICIT, ODR_CONTEXT, 1, Z_SortElement_generic,
+	 (Odr_fun)z_SortKey, 0},
+	{ODR_IMPLICIT, ODR_CONTEXT, 2, Z_SortElement_databaseSpecific,
+	 (Odr_fun)z_SortDbSpecificList, 0},
+	{-1, -1, -1, -1, 0, 0}
+    };
+    
+    if (!odr_initmember(o, p, sizeof(**p)))
+	return opt && odr_ok(o);
+    if (odr_choice(o, arm, &(*p)->u, &(*p)->which, 0))
+	return 1;
+    *p = 0;
+    return opt && odr_ok(o);
+}
+
+int z_SortMissingValueAction(ODR o, Z_SortMissingValueAction **p, int opt,
+			     const char *name)
+{
+    static Odr_arm arm[] =
+    {
+	{ODR_IMPLICIT, ODR_CONTEXT, 1, Z_SortMissingValAct_abort,
+	 (Odr_fun)odr_null, 0},
+	{ODR_IMPLICIT, ODR_CONTEXT, 2, Z_SortMissingValAct_null,
+	 (Odr_fun)odr_null, 0},
+	{ODR_IMPLICIT, ODR_CONTEXT, 3, Z_SortMissingValAct_valData,
+	 (Odr_fun)odr_octetstring, 0},
+	{-1, -1, -1, -1, 0, 0}
+    };
+    
+    if (!odr_initmember(o, p, sizeof(**p)))
+	return opt && odr_ok(o);
+    if (odr_choice(o, arm, &(*p)->u, &(*p)->which, 0))
+	return 1;
+    *p = 0;
+    return opt && odr_ok(o);
+}
+
+int z_SortKeySpec(ODR o, Z_SortKeySpec **p, int opt, const char *name)
+{
+    if (!odr_sequence_begin(o, p, sizeof(**p), 0))
+	return opt && odr_ok(o);
+    return
+        z_SortElement(o, &(*p)->sortElement, 0, 0) &&
+	odr_implicit(o, odr_integer, &(*p)->sortRelation, ODR_CONTEXT, 1, 0) &&
+	odr_implicit(o, odr_integer, &(*p)->caseSensitivity,
+		     ODR_CONTEXT, 2, 0) &&
+	odr_explicit(o, z_SortMissingValueAction, &(*p)->missingValueAction,
+		     ODR_CONTEXT, 3, 1) &&
+	odr_sequence_end(o);
+}
+
+int z_SortResponse(ODR o, Z_SortResponse **p, int opt, const char *name)
+{
+    if (!odr_sequence_begin(o, p, sizeof(**p), 0))
+	return opt && odr_ok(o);
+    return
+        z_ReferenceId(o, &(*p)->referenceId, 1, 0) &&
+	odr_implicit(o, odr_integer, &(*p)->sortStatus, ODR_CONTEXT,
+		     3, 0) &&
+	odr_implicit(o, odr_integer, &(*p)->resultSetStatus, ODR_CONTEXT,
+		     4, 1) &&
+	odr_implicit(o, z_DiagRecs, &(*p)->diagnostics, ODR_CONTEXT, 5, 1) &&
+	z_OtherInformation(o, &(*p)->otherInfo, 1, 0) &&
+	odr_sequence_end(o);
+}
+
+int z_SortKeySpecList(ODR o, Z_SortKeySpecList **p, int opt, const char *name)
+{
+    if (!odr_initmember(o, p, sizeof(**p)))
+	return opt && odr_ok(o);
+    if (odr_sequence_of(o, (Odr_fun)z_SortKeySpec, &(*p)->specs,
+			&(*p)->num_specs, 0))
+	return 1;
+    *p = 0;
+    return opt && odr_ok(o);
+}
+
+int z_SortRequest(ODR o, Z_SortRequest **p, int opt, const char *name)
+{
+    if (!odr_sequence_begin(o, p, sizeof(**p), 0))
+	return opt && odr_ok(o);
+    return
+        z_ReferenceId(o, &(*p)->referenceId, 1, 0) &&
+	odr_implicit(o, z_StringList, &(*p)->inputResultSetNames, 
+		     ODR_CONTEXT, 3, 0) &&
+	odr_implicit(o, z_InternationalString, &(*p)->sortedResultSetName,
+		     ODR_CONTEXT, 4, 0) &&
+	odr_implicit(o, z_SortKeySpecList, &(*p)->sortSequence, ODR_CONTEXT,
+		     5, 0) &&
+	z_OtherInformation(o, &(*p)->otherInfo, 1, 0) &&
+	odr_sequence_end(o);
+}
+
+/* ---------------------- Resource Report ---------------- */
+
+int z_ResourceReportRequest(ODR o, Z_ResourceReportRequest **p, int opt,
+			    const char *name)
+{
+    if (!odr_sequence_begin(o, p, sizeof(**p), 0))
+	return opt && odr_ok(o);
+    return
+        z_ReferenceId(o, &(*p)->referenceId, 1, 0) &&
+	odr_implicit(o, z_ReferenceId, &(*p)->opId, ODR_CONTEXT, 210, 1) &&
+	odr_implicit(o, odr_oid, &(*p)->prefResourceReportFormat, ODR_CONTEXT,
+		     49, 1) &&
+	z_OtherInformation(o, &(*p)->otherInfo, 1, 0) &&
+	odr_sequence_end(o);
+}
+
+int z_ResourceReportResponse(ODR o, Z_ResourceReportResponse **p, int opt,
+			     const char *name)
+{
+    if (!odr_sequence_begin(o, p, sizeof(**p), 0))
+	return opt && odr_ok(o);
+    return
+        z_ReferenceId(o, &(*p)->referenceId, 1, 0) &&
+	odr_implicit(o, odr_integer, &(*p)->resourceReportStatus,
+		     ODR_CONTEXT, 50, 0) &&
+	odr_explicit(o, z_External, &(*p)->resourceReport, ODR_CONTEXT,
+		     51, 1) &&
+	z_OtherInformation(o, &(*p)->otherInfo, 1, 0) &&
+	odr_sequence_end(o);
+}
+
+/* ------------------------ APDU ------------------------- */
+
+int z_APDU(ODR o, Z_APDU **p, int opt, const char *name)
+{
+    static Odr_arm arm[] =
+    {
+    	{ODR_IMPLICIT, ODR_CONTEXT, 20, Z_APDU_initRequest,
+	 (Odr_fun)z_InitRequest, 0},
+    	{ODR_IMPLICIT, ODR_CONTEXT, 21, Z_APDU_initResponse,
+	 (Odr_fun)z_InitResponse, 0},
+    	{ODR_IMPLICIT, ODR_CONTEXT, 22, Z_APDU_searchRequest,
+	 (Odr_fun)z_SearchRequest, 0},
+    	{ODR_IMPLICIT, ODR_CONTEXT, 23, Z_APDU_searchResponse,
+	 (Odr_fun)z_SearchResponse, 0},
+    	{ODR_IMPLICIT, ODR_CONTEXT, 24, Z_APDU_presentRequest,
+	 (Odr_fun)z_PresentRequest, 0},
+    	{ODR_IMPLICIT, ODR_CONTEXT, 25, Z_APDU_presentResponse,
+	 (Odr_fun)z_PresentResponse, 0},
+	{ODR_IMPLICIT, ODR_CONTEXT, 26, Z_APDU_deleteResultSetRequest,
+	 (Odr_fun)z_DeleteResultSetRequest, 0},
+	{ODR_IMPLICIT, ODR_CONTEXT, 27, Z_APDU_deleteResultSetResponse,
+	 (Odr_fun)z_DeleteResultSetResponse, 0},
+	{ODR_IMPLICIT, ODR_CONTEXT, 28, Z_APDU_accessControlRequest,
+	 (Odr_fun)z_AccessControlRequest, 0},
+	{ODR_IMPLICIT, ODR_CONTEXT, 29, Z_APDU_accessControlResponse,
+	 (Odr_fun)z_AccessControlResponse, 0},
+    	{ODR_IMPLICIT, ODR_CONTEXT, 30, Z_APDU_resourceControlRequest,
+	 (Odr_fun)z_ResourceControlRequest, 0},
+    	{ODR_IMPLICIT, ODR_CONTEXT, 31, Z_APDU_resourceControlResponse,
+	 (Odr_fun)z_ResourceControlResponse, 0},
+    	{ODR_IMPLICIT, ODR_CONTEXT, 32, Z_APDU_triggerResourceControlRequest,
+	 (Odr_fun)z_TriggerResourceControlRequest, 0},
+	{ODR_IMPLICIT, ODR_CONTEXT, 33, Z_APDU_resourceReportRequest,
+	 (Odr_fun)z_ResourceReportRequest, 0},
+	{ODR_IMPLICIT, ODR_CONTEXT, 34, Z_APDU_resourceReportResponse,
+	 (Odr_fun)z_ResourceReportResponse, 0},
+	{ODR_IMPLICIT, ODR_CONTEXT, 35, Z_APDU_scanRequest,
+	 (Odr_fun)z_ScanRequest, 0},
+	{ODR_IMPLICIT, ODR_CONTEXT, 36, Z_APDU_scanResponse,
+	 (Odr_fun)z_ScanResponse, 0},
+	{ODR_IMPLICIT, ODR_CONTEXT, 43, Z_APDU_sortRequest,
+	 (Odr_fun)z_SortRequest, 0},
+	{ODR_IMPLICIT, ODR_CONTEXT, 44, Z_APDU_sortResponse,
+	 (Odr_fun)z_SortResponse, 0},
+	{ODR_IMPLICIT, ODR_CONTEXT, 45, Z_APDU_segmentRequest,
+	 (Odr_fun)z_Segment, 0},
+	{ODR_IMPLICIT, ODR_CONTEXT, 46, Z_APDU_extendedServicesRequest,
+	 (Odr_fun)z_ExtendedServicesRequest, 0},
+	{ODR_IMPLICIT, ODR_CONTEXT, 47, Z_APDU_extendedServicesResponse,
+	 (Odr_fun)z_ExtendedServicesResponse},
+	{ODR_IMPLICIT, ODR_CONTEXT, 48, Z_APDU_close,
+	 (Odr_fun)z_Close, 0},
+    	{-1, -1, -1, -1, 0, 0}
+    };
+    
+    if (o->direction == ODR_DECODE)
+    	*p = (Z_APDU *)odr_malloc(o, sizeof(**p));
+    odr_setlenlen(o, 5);
+    if (!odr_choice(o, arm, &(*p)->u, &(*p)->which, name))
+    {
+    	if (o->direction == ODR_DECODE)
+	    *p = 0;
+	return opt && odr_ok(o);
+    }
+    return 1;
+}
Index: /main/tags/2.25/gsdl/packages/yaz/asn/prt-acc.c
===================================================================
--- /main/tags/2.25/gsdl/packages/yaz/asn/prt-acc.c	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/yaz/asn/prt-acc.c	(revision 21064)
@@ -0,0 +1,205 @@
+/*
+ * Copyright (c) 1995-1999, Index Data.
+ * See the file LICENSE for details.
+ * Sebastian Hammer, Adam Dickmeiss
+ *
+ * $Log$
+ * Revision 1.1  2000/08/03 03:09:46  johnmcp
+ * Added the YAZ toolkit source to the packages directory (for z39.50 stuff)
+ *
+ * Revision 1.9  1999/11/30 13:47:11  adam
+ * Improved installation. Moved header files to include/yaz.
+ *
+ * Revision 1.8  1999/04/20 09:56:47  adam
+ * Added 'name' paramter to encoder/decoder routines (typedef Odr_fun).
+ * Modified all encoders/decoders to reflect this change.
+ *
+ * Revision 1.7  1998/02/11 11:53:32  adam
+ * Changed code so that it compiles as C++.
+ *
+ * Revision 1.6  1998/01/05 09:04:57  adam
+ * Fixed bugs in encoders/decoders - Not operator (!) missing.
+ *
+ * Revision 1.5  1995/09/29 17:11:53  quinn
+ * Smallish
+ *
+ * Revision 1.4  1995/09/27  15:02:41  quinn
+ * Modified function heads & prototypes.
+ *
+ * Revision 1.3  1995/08/15  11:59:41  quinn
+ * Updated External
+ *
+ * Revision 1.2  1995/06/05  10:52:05  quinn
+ * Fixed some negligences.
+ *
+ * Revision 1.1  1995/06/02  09:49:15  quinn
+ * Adding access control
+ *
+ *
+ */
+
+#include <yaz/proto.h>
+
+int z_Encryption1(ODR o, Z_Encryption1 **p, int opt, const char *name)
+{
+    if (!odr_sequence_begin(o, p, sizeof(**p), 0))
+    	return opt && odr_ok(o);
+    return
+    	odr_implicit(o, odr_octetstring, &(*p)->cryptType,
+		     ODR_CONTEXT, 1, 1) &&
+	odr_implicit(o, odr_octetstring, &(*p)->credential,
+		     ODR_CONTEXT, 2, 1) &&
+	odr_implicit(o, odr_octetstring, &(*p)->data, ODR_CONTEXT, 3, 0) &&
+	odr_sequence_end(o);
+}
+
+int z_EnumeratedPrompt1(ODR o, Z_EnumeratedPrompt1 **p, int opt,
+			const char *name)
+{
+    if (!odr_sequence_begin(o, p, sizeof(**p), 0))
+    	return opt && odr_ok(o);
+    return
+    	odr_implicit(o, odr_integer, &(*p)->type, ODR_CONTEXT, 1, 0) &&
+	odr_implicit(o, odr_visiblestring, &(*p)->suggestedString, ODR_CONTEXT,
+		     2, 1) &&
+	odr_sequence_end(o);
+}
+
+int z_PromptId1(ODR o, Z_PromptId1 **p, int opt, const char *name)
+{
+    static Odr_arm arm[] =
+    {
+    	{ODR_IMPLICIT, ODR_CONTEXT, 1, Z_PromptId1_enumeratedPrompt,
+	 (Odr_fun)z_EnumeratedPrompt1, 0},
+	{ODR_IMPLICIT, ODR_CONTEXT, 2, Z_PromptId1_nonEnumeratedPrompt,
+	 odr_visiblestring, 0},
+	{-1, -1, -1, -1, 0, 0}
+    };
+    
+    if (o->direction == ODR_DECODE)
+    	*p = (Z_PromptId1 *)odr_malloc(o, sizeof(**p));
+    else if (!*p)
+    	return opt;
+    if (odr_choice(o, arm, &(*p)->u, &(*p)->which, 0))
+    	return 1;
+    *p = 0;
+    return opt && odr_ok(o);
+}
+
+int z_PromptInfo1(ODR o, Z_PromptInfo1 **p, int opt, const char *name)
+{
+    static Odr_arm arm[] =
+    {
+    	{ODR_IMPLICIT, ODR_CONTEXT, 1, Z_Challenge1_character,
+	 odr_visiblestring, 0},
+	{ODR_IMPLICIT, ODR_CONTEXT, 2, Z_Challenge1_encrypted,
+	 (Odr_fun)z_Encryption1, 0},
+	{-1, -1, -1, -1, 0, 0}
+    };
+    
+    if (o->direction == ODR_DECODE)
+    	*p = (Z_PromptInfo1 *)odr_malloc(o, sizeof(**p));
+    else if (!*p)
+    	return opt;
+    if (odr_choice(o, arm, &(*p)->u, &(*p)->which, 0))
+    	return 1;
+    *p = 0;
+    return opt && odr_ok(o);
+}
+
+int z_ChallengeUnit1(ODR o, Z_ChallengeUnit1 **p, int opt, const char *name)
+{
+    if (!odr_sequence_begin(o, p, sizeof(**p), 0))
+    	return opt && odr_ok(o);
+    return
+    	odr_explicit(o, z_PromptId1, &(*p)->promptId, ODR_CONTEXT, 1, 0) &&
+	odr_implicit(o, odr_visiblestring, &(*p)->defaultResponse,
+		     ODR_CONTEXT, 2, 1) &&
+	odr_explicit(o, z_PromptInfo1, &(*p)->promptInfo,
+		     ODR_CONTEXT, 3, 1) &&
+	odr_implicit(o, odr_visiblestring, &(*p)->regExpr,
+		     ODR_CONTEXT, 4, 1) &&
+	odr_implicit(o, odr_null, &(*p)->responseRequired,
+		     ODR_CONTEXT, 5, 1) &&
+	odr_implicit_settag(o, ODR_CONTEXT, 6) &&
+	(odr_sequence_of(o, odr_visiblestring, &(*p)->allowedValues,
+			 &(*p)->num_values, 0) || odr_ok(o)) &&
+	odr_implicit(o, odr_null, &(*p)->shouldSave, ODR_CONTEXT, 7, 1) &&
+	odr_implicit(o, odr_integer, &(*p)->dataType, ODR_CONTEXT, 8, 1) &&
+	odr_implicit(o, z_External, &(*p)->diagnostic, ODR_CONTEXT, 9, 1) &&
+	odr_sequence_end(o);
+}
+
+int z_Challenge1(ODR o, Z_Challenge1 **p, int opt, const char *name)
+{
+    if (o->direction == ODR_ENCODE)
+    	*p = (Z_Challenge1 *)odr_malloc(o, sizeof(**p));
+    else if (!*p)
+    	return opt;
+    if (odr_sequence_of(o, (Odr_fun)z_ChallengeUnit1, &(*p)->list,
+			&(*p)->num_challenges, 0))
+	return 1;
+    *p = 0;
+    return opt && odr_ok(o);
+}
+
+int z_ResponseUnit1(ODR o, Z_ResponseUnit1 **p, int opt, const char *name)
+{
+    static Odr_arm arm[] = 
+    {
+    	{ODR_IMPLICIT, ODR_CONTEXT, 1, Z_Response1_string,
+	 odr_visiblestring, 0},
+	{ODR_IMPLICIT, ODR_CONTEXT, 2, Z_Response1_accept,
+	 (Odr_fun)odr_bool, 0},
+	{ODR_IMPLICIT, ODR_CONTEXT, 3, Z_Response1_acknowledge,
+	 (Odr_fun)odr_null, 0},
+	{ODR_EXPLICIT, ODR_CONTEXT, 4, Z_Response1_diagnostic,
+	 (Odr_fun)z_DiagRec, 0},
+	{ODR_IMPLICIT, ODR_CONTEXT, 5, Z_Response1_encrypted,
+	 (Odr_fun)z_Encryption1, 0},
+	{-1, -1, -1, -1, 0, 0}
+    };
+    
+    if (!odr_sequence_begin(o, p, sizeof(**p), 0))
+    	return opt && odr_ok(o);
+    return
+    	odr_explicit(o, z_PromptId1, &(*p)->promptId, ODR_CONTEXT, 1, 0) &&
+	odr_constructed_begin(o, p, ODR_CONTEXT, 2, 0) &&
+	odr_choice(o, arm, &(*p)->u, &(*p)->which, 0) &&
+	odr_constructed_end(o) &&
+	odr_sequence_end(o);
+}
+
+int z_Response1(ODR o, Z_Response1 **p, int opt, const char *name)
+{
+    if (o->direction == ODR_ENCODE)
+    	*p = (Z_Response1 *)odr_malloc(o, sizeof(**p));
+    else if (!*p)
+    	return opt;
+    if (odr_sequence_of(o, (Odr_fun)z_ResponseUnit1, &(*p)->list,
+			&(*p)->num_responses, 0))
+	return 1;
+    *p = 0;
+    return opt && odr_ok(o);
+}
+
+int z_PromptObject1(ODR o, Z_PromptObject1 **p, int opt, const char *name)
+{
+    static Odr_arm arm[] =
+    {
+    	{ODR_IMPLICIT, ODR_CONTEXT, 1, Z_PromptObject1_challenge,
+	 (Odr_fun)z_Challenge1, 0},
+	{ODR_IMPLICIT, ODR_CONTEXT, 2, Z_PromptObject1_response,
+	 (Odr_fun)z_Response1, 0},
+	{-1, -1, -1, -1, 0, 0}
+    };
+    
+    if (o->direction == ODR_DECODE)
+    	*p = (Z_PromptObject1 *)odr_malloc(o, sizeof(**p));
+    else if (!*p)
+    	return opt;
+    if (odr_choice(o, arm, &(*p)->u, &(*p)->which, 0))
+    	return 1;
+    *p = 0;
+    return opt && odr_ok(o);
+}
Index: /main/tags/2.25/gsdl/packages/yaz/asn/prt-add.c
===================================================================
--- /main/tags/2.25/gsdl/packages/yaz/asn/prt-add.c	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/yaz/asn/prt-add.c	(revision 21064)
@@ -0,0 +1,145 @@
+/*
+ * Copyright (c) 1995-1999, Index Data
+ * See the file LICENSE for details.
+ * Sebastian Hammer, Adam Dickmeiss
+ *
+ * $Log$
+ * Revision 1.1  2000/08/03 03:09:47  johnmcp
+ * Added the YAZ toolkit source to the packages directory (for z39.50 stuff)
+ *
+ * Revision 1.6  1999/11/30 13:47:11  adam
+ * Improved installation. Moved header files to include/yaz.
+ *
+ * Revision 1.5  1999/04/20 09:56:47  adam
+ * Added 'name' paramter to encoder/decoder routines (typedef Odr_fun).
+ * Modified all encoders/decoders to reflect this change.
+ *
+ * Revision 1.4  1998/02/11 11:53:32  adam
+ * Changed code so that it compiles as C++.
+ *
+ * Revision 1.3  1998/01/05 09:04:57  adam
+ * Fixed bugs in encoders/decoders - Not operator (!) missing.
+ *
+ * Revision 1.2  1997/04/30 08:52:02  quinn
+ * Null
+ *
+ * Revision 1.1  1996/10/10  11:52:18  quinn
+ * Added SearchResult additionalInfo
+ *
+ *
+ */
+
+#include <yaz/proto.h>
+
+int z_ResultsByDBList (ODR o, Z_ResultsByDBList **p, int opt, const char *name)
+{
+    if (!odr_initmember (o, p, sizeof(**p)))
+        return opt && odr_ok(o);
+    if (odr_sequence_of (o, z_DatabaseName, &(*p)->elements,
+        &(*p)->num, 0))
+        return 1;
+    *p = 0;
+    return opt && odr_ok(o);
+}
+
+int z_ResultsByDB_elem (ODR o, Z_ResultsByDB_elem **p, int opt,
+			const char *name)
+{
+    static Odr_arm arm[] = {
+        {ODR_IMPLICIT, ODR_CONTEXT, 1, Z_ResultsByDB_all,
+	 (Odr_fun)odr_null, 0},
+        {ODR_IMPLICIT, ODR_CONTEXT, 2, Z_ResultsByDB_list,
+	 (Odr_fun)z_ResultsByDBList, 0},
+        {-1, -1, -1, -1, 0, 0}
+    };
+    if (!odr_sequence_begin (o, p, sizeof(**p), 0))
+        return opt && odr_ok (o);
+    return
+        odr_constructed_begin (o, &(*p)->u, ODR_CONTEXT, 1, 0) &&
+        odr_choice (o, arm, &(*p)->u, &(*p)->which, 0) &&
+        odr_constructed_end (o) &&
+        odr_implicit (o, odr_integer,
+		      &(*p)->count, ODR_CONTEXT, 2, 1) &&
+        odr_implicit (o, z_InternationalString,
+		      &(*p)->resultSetName, ODR_CONTEXT, 3, 1) &&
+        odr_sequence_end (o);
+}
+
+int z_ResultsByDB (ODR o, Z_ResultsByDB **p, int opt, const char *name)
+{
+    if (!odr_initmember (o, p, sizeof(**p)))
+        return opt && odr_ok(o);
+    if (odr_sequence_of (o, (Odr_fun)z_ResultsByDB_elem, &(*p)->elements,
+			 &(*p)->num, 0))
+        return 1;
+    *p = 0;
+    return opt && odr_ok(o);
+}
+
+int z_QueryExpressionTerm (ODR o, Z_QueryExpressionTerm **p, int opt,
+			   const char *name)
+{
+    if (!odr_sequence_begin (o, p, sizeof(**p), 0))
+        return opt && odr_ok (o);
+    return
+        odr_explicit (o, z_Term,
+		      &(*p)->queryTerm, ODR_CONTEXT, 1, 0) &&
+        odr_implicit (o, z_InternationalString,
+		      &(*p)->termComment, ODR_CONTEXT, 2, 1) &&
+        odr_sequence_end (o);
+}
+
+int z_QueryExpression (ODR o, Z_QueryExpression **p, int opt,
+		       const char *name)
+{
+    static Odr_arm arm[] = {
+        {ODR_IMPLICIT, ODR_CONTEXT, 1, Z_QueryExpression_term,
+         (Odr_fun)z_QueryExpressionTerm, 0},
+        {ODR_EXPLICIT, ODR_CONTEXT, 2, Z_QueryExpression_query,
+	 (Odr_fun)z_Query, 0},
+        {-1, -1, -1, -1, 0, 0}
+    };
+    if (!odr_initmember(o, p, sizeof(**p)))
+        return opt && odr_ok(o);
+    if (odr_choice(o, arm, &(*p)->u, &(*p)->which, 0))
+        return 1;
+    *p = 0;
+    return opt && odr_ok(o);
+}
+
+int z_SearchInfoReport_elem (ODR o, Z_SearchInfoReport_elem **p, int opt,
+			     const char *name)
+{
+    if (!odr_sequence_begin (o, p, sizeof(**p), 0))
+        return opt && odr_ok (o);
+    return
+        odr_implicit (o, z_InternationalString,
+		      &(*p)->subqueryId, ODR_CONTEXT, 1, 1) &&
+        odr_implicit (o, odr_bool,
+		      &(*p)->fullQuery, ODR_CONTEXT, 2, 0) &&
+        odr_explicit (o, z_QueryExpression,
+		      &(*p)->subqueryExpression, ODR_CONTEXT, 3, 1) &&
+        odr_explicit (o, z_QueryExpression,
+		      &(*p)->subqueryInterpretation, ODR_CONTEXT, 4, 1) &&
+        odr_explicit (o, z_QueryExpression,
+		      &(*p)->subqueryRecommendation, ODR_CONTEXT, 5, 1) &&
+        odr_implicit (o, odr_integer,
+		      &(*p)->subqueryCount, ODR_CONTEXT, 6, 1) &&
+        odr_implicit (o, z_IntUnit,
+		      &(*p)->subqueryWeight, ODR_CONTEXT, 7, 1) &&
+        odr_implicit (o, z_ResultsByDB,
+		      &(*p)->resultsByDB, ODR_CONTEXT, 8, 1) &&
+        odr_sequence_end (o);
+}
+
+int z_SearchInfoReport (ODR o, Z_SearchInfoReport **p, int opt,
+			const char *name)
+{
+    if (!odr_initmember (o, p, sizeof(**p)))
+        return opt && odr_ok(o);
+    if (odr_sequence_of (o, (Odr_fun)z_SearchInfoReport_elem, &(*p)->elements,
+			 &(*p)->num, 0))
+        return 1;
+    *p = 0;
+    return opt && odr_ok(o);
+}
Index: /main/tags/2.25/gsdl/packages/yaz/asn/prt-arc.c
===================================================================
--- /main/tags/2.25/gsdl/packages/yaz/asn/prt-arc.c	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/yaz/asn/prt-arc.c	(revision 21064)
@@ -0,0 +1,200 @@
+/*
+ * Copyright (c) 1995-1999, Index Data.
+ * See the file LICENSE for details.
+ * Sebastian Hammer, Adam Dickmeiss
+ *
+ * $Log$
+ * Revision 1.1  2000/08/03 03:09:47  johnmcp
+ * Added the YAZ toolkit source to the packages directory (for z39.50 stuff)
+ *
+ * Revision 1.4  1999/11/30 13:47:11  adam
+ * Improved installation. Moved header files to include/yaz.
+ *
+ * Revision 1.3  1999/04/20 09:56:47  adam
+ * Added 'name' paramter to encoder/decoder routines (typedef Odr_fun).
+ * Modified all encoders/decoders to reflect this change.
+ *
+ * Revision 1.2  1998/02/11 11:53:32  adam
+ * Changed code so that it compiles as C++.
+ *
+ * Revision 1.1  1996/06/10 08:55:20  quinn
+ * Added Summary, OPAC
+ *
+ *
+ */
+
+#include <yaz/proto.h>
+
+/* ----------------------- Summary Record --------------- */
+
+int z_FormatSpec(ODR o, Z_FormatSpec **p, int opt, const char *name)
+{
+    if (!odr_sequence_begin(o, p, sizeof(**p), 0))
+	return opt && odr_ok(o);
+    return
+        odr_implicit(o, z_InternationalString, &(*p)->type,
+		     ODR_CONTEXT, 1, 0) &&
+	odr_implicit(o, odr_integer, &(*p)->size, ODR_CONTEXT, 2, 1) &&
+	odr_implicit(o, odr_integer, &(*p)->bestPosn, ODR_CONTEXT, 3, 1) &&
+	odr_sequence_end(o);
+}
+
+int z_BriefBib(ODR o, Z_BriefBib **p, int opt, const char *name)
+{
+    if (!odr_sequence_begin(o, p, sizeof(**p), 0))
+	return opt && odr_ok(o);
+    return
+        odr_implicit(o, z_InternationalString, &(*p)->title,
+		     ODR_CONTEXT, 1, 0) &&
+	odr_implicit(o, z_InternationalString, &(*p)->author,
+		     ODR_CONTEXT, 2, 1) &&
+	odr_implicit(o, z_InternationalString, &(*p)->callNumber,
+		     ODR_CONTEXT, 3, 1) &&
+	odr_implicit(o, z_InternationalString, &(*p)->recordType,
+		     ODR_CONTEXT, 4, 1) &&
+	odr_implicit(o, z_InternationalString, &(*p)->bibliographicLevel,
+		     ODR_CONTEXT, 5, 1) &&
+	odr_implicit_settag(o, ODR_CONTEXT, 6) &&
+	(odr_sequence_of(o, (Odr_fun)z_FormatSpec, &(*p)->format,
+			 &(*p)->num_format, 0) ||
+	 odr_ok(o)) &&
+	odr_implicit(o, z_InternationalString, &(*p)->publicationPlace,
+		     ODR_CONTEXT, 7, 1) &&
+	odr_implicit(o, z_InternationalString, &(*p)->publicationDate,
+		     ODR_CONTEXT, 8, 1) &&
+	odr_implicit(o, z_InternationalString, &(*p)->targetSystemKey,
+		     ODR_CONTEXT, 9, 1) &&
+	odr_implicit(o, z_InternationalString, &(*p)->satisfyingElement,
+		     ODR_CONTEXT, 10, 1) &&
+	odr_implicit(o, odr_integer, &(*p)->rank,
+		     ODR_CONTEXT, 11, 1) &&
+	odr_implicit(o, z_InternationalString, &(*p)->documentId,
+		     ODR_CONTEXT, 12, 1) &&
+	odr_implicit(o, z_InternationalString, &(*p)->abstract,
+		     ODR_CONTEXT, 13, 1) &&
+	z_OtherInformation(o, &(*p)->otherInfo, 1, 0) &&
+	odr_sequence_end(o);
+}
+
+/* ----------------------- Summary Record --------------- */
+
+int z_CircRecord(ODR o, Z_CircRecord **p, int opt, const char *name)
+{
+    if (!odr_sequence_begin(o, p, sizeof(**p), 0))
+	return opt && odr_ok(o);
+    return
+        odr_implicit(o, odr_bool, &(*p)->availableNow, ODR_CONTEXT, 1, 0) &&
+        odr_implicit(o, z_InternationalString, &(*p)->availabilityDate,
+		     ODR_CONTEXT, 2, 1) &&
+        odr_implicit(o, z_InternationalString, &(*p)->availableThru,
+		     ODR_CONTEXT, 3, 1) &&
+        odr_implicit(o, z_InternationalString, &(*p)->restrictions,
+		     ODR_CONTEXT, 4, 1) &&
+        odr_implicit(o, z_InternationalString, &(*p)->itemId,
+		     ODR_CONTEXT, 5, 1) &&
+	odr_implicit(o, odr_bool, &(*p)->renewable, ODR_CONTEXT, 6, 0) &&
+	odr_implicit(o, odr_bool, &(*p)->onHold, ODR_CONTEXT, 7, 0) &&
+        odr_implicit(o, z_InternationalString, &(*p)->enumAndChron,
+		     ODR_CONTEXT, 8, 1) &&
+        odr_implicit(o, z_InternationalString, &(*p)->midspine,
+		     ODR_CONTEXT, 9, 1) &&
+        odr_implicit(o, z_InternationalString, &(*p)->temporaryLocation,
+		     ODR_CONTEXT, 10, 1) &&
+	odr_sequence_end(o);
+}
+
+int z_Volume(ODR o, Z_Volume **p, int opt, const char *name)
+{
+    if (!odr_sequence_begin(o, p, sizeof(**p), 0))
+	return opt && odr_ok(o);
+    return
+        odr_implicit(o, z_InternationalString, &(*p)->enumeration,
+		     ODR_CONTEXT, 1, 1) &&
+        odr_implicit(o, z_InternationalString, &(*p)->chronology,
+		     ODR_CONTEXT, 2, 1) &&
+        odr_implicit(o, z_InternationalString, &(*p)->enumAndChron,
+		     ODR_CONTEXT, 3, 1) &&
+	odr_sequence_end(o);
+}
+
+int z_HoldingsAndCircData(ODR o, Z_HoldingsAndCircData **p, int opt,
+			  const char *name)
+{
+    if (!odr_sequence_begin(o, p, sizeof(**p), 0))
+	return opt && odr_ok(o);
+    return
+        odr_implicit(o, z_InternationalString, &(*p)->typeOfRecord,
+		     ODR_CONTEXT, 1, 1) &&
+        odr_implicit(o, z_InternationalString, &(*p)->encodingLevel,
+		     ODR_CONTEXT, 2, 1) &&
+        odr_implicit(o, z_InternationalString, &(*p)->format,
+		     ODR_CONTEXT, 3, 1) &&
+        odr_implicit(o, z_InternationalString, &(*p)->receiptAcqStatus,
+		     ODR_CONTEXT, 4, 1) &&
+        odr_implicit(o, z_InternationalString, &(*p)->generalRetention,
+		     ODR_CONTEXT, 5, 1) &&
+        odr_implicit(o, z_InternationalString, &(*p)->completeness,
+		     ODR_CONTEXT, 6, 1) &&
+        odr_implicit(o, z_InternationalString, &(*p)->dateOfReport,
+		     ODR_CONTEXT, 7, 1) &&
+        odr_implicit(o, z_InternationalString, &(*p)->nucCode,
+		     ODR_CONTEXT, 8, 1) &&
+        odr_implicit(o, z_InternationalString, &(*p)->localLocation,
+		     ODR_CONTEXT, 9, 1) &&
+        odr_implicit(o, z_InternationalString, &(*p)->shelvingLocation,
+		     ODR_CONTEXT, 10, 1) &&
+        odr_implicit(o, z_InternationalString, &(*p)->callNumber,
+		     ODR_CONTEXT, 11, 1) &&
+        odr_implicit(o, z_InternationalString, &(*p)->shelvingData,
+		     ODR_CONTEXT, 12, 1) &&
+        odr_implicit(o, z_InternationalString, &(*p)->copyNumber,
+		     ODR_CONTEXT, 13, 1) &&
+        odr_implicit(o, z_InternationalString, &(*p)->publicNote,
+		     ODR_CONTEXT, 14, 1) &&
+        odr_implicit(o, z_InternationalString, &(*p)->reproductionNote,
+		     ODR_CONTEXT, 15, 1) &&
+        odr_implicit(o, z_InternationalString, &(*p)->termsUseRepro,
+		     ODR_CONTEXT, 16, 1) &&
+        odr_implicit(o, z_InternationalString, &(*p)->enumAndChron,
+		     ODR_CONTEXT, 17, 1) &&
+	odr_implicit_settag(o, ODR_CONTEXT, 18) &&
+	(odr_sequence_of(o, (Odr_fun)z_Volume, &(*p)->volumes,
+			 &(*p)->num_volumes, 0) ||
+	 odr_ok(o)) &&
+	odr_implicit_settag(o, ODR_CONTEXT, 19) &&
+	(odr_sequence_of(o, (Odr_fun)z_CircRecord, &(*p)->circulationData,
+			 &(*p)->num_circulationData, 0) || odr_ok(o)) &&
+	odr_sequence_end(o);
+}
+
+int z_HoldingsRecord(ODR o, Z_HoldingsRecord **p, int opt, const char *name)
+{
+    static Odr_arm arm[] =
+    {
+	{ODR_IMPLICIT, ODR_CONTEXT, 1, Z_HoldingsRecord_marcHoldingsRecord,
+	 (Odr_fun)z_External, 0},
+	{ODR_IMPLICIT, ODR_CONTEXT, 2, Z_HoldingsRecord_holdingsAndCirc,
+	 (Odr_fun)z_HoldingsAndCircData, 0},
+	{-1, -1, -1, -1, 0, 0}
+    };
+    
+    if (!odr_initmember(o, p, sizeof(**p)))
+	return opt && odr_ok(o);
+    if (odr_choice(o, arm, &(*p)->u, &(*p)->which, 0))
+	return 1;
+    *p = 0;
+    return opt && odr_ok(o);
+}
+
+int z_OPACRecord(ODR o, Z_OPACRecord **p, int opt, const char *name)
+{
+    if (!odr_sequence_begin(o, p, sizeof(**p), 0))
+	return opt && odr_ok(o);
+    return
+        odr_implicit(o, z_External, &(*p)->bibliographicRecord,
+		     ODR_CONTEXT, 1, 1) &&
+	odr_implicit_settag(o, ODR_CONTEXT, 2) &&
+	(odr_sequence_of(o, (Odr_fun)z_HoldingsRecord, &(*p)->holdingsData,
+			 &(*p)->num_holdingsData, 0) || odr_ok(o)) &&
+	odr_sequence_end(o);
+}
Index: /main/tags/2.25/gsdl/packages/yaz/asn/prt-dat.c
===================================================================
--- /main/tags/2.25/gsdl/packages/yaz/asn/prt-dat.c	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/yaz/asn/prt-dat.c	(revision 21064)
@@ -0,0 +1,193 @@
+/*
+ * This file is part of the YAZ toolkit:
+ * Copyright (c) 1998-1999, Index Data.
+ * See the file LICENSE for details.
+ * Sebastian Hammer, Adam Dickmeiss
+ *
+ * Contribution by Ronald van Der Meer (RVDM):
+ *  Databasix Information Systems B.V., Utrecht, The Netherlands.
+ *
+ * $Log$
+ * Revision 1.1  2000/08/03 03:09:48  johnmcp
+ * Added the YAZ toolkit source to the packages directory (for z39.50 stuff)
+ *
+ * Revision 1.4  1999/11/30 13:47:11  adam
+ * Improved installation. Moved header files to include/yaz.
+ *
+ * Revision 1.3  1999/04/20 09:56:47  adam
+ * Added 'name' paramter to encoder/decoder routines (typedef Odr_fun).
+ * Modified all encoders/decoders to reflect this change.
+ *
+ * Revision 1.2  1998/02/11 11:53:32  adam
+ * Changed code so that it compiles as C++.
+ *
+ * Revision 1.1  1998/02/10 15:31:46  adam
+ * Implemented date and time structure. Changed the Update Extended
+ * Service.
+ *
+ */
+
+#include <yaz/proto.h>
+
+int z_MonthAndDay(ODR o, Z_MonthAndDay **p, int opt, const char *name)
+{
+    if (!odr_sequence_begin(o, p, sizeof(**p), 0))
+	return opt && odr_ok(o);
+    return
+	odr_implicit(o, odr_integer, &(*p)->month, ODR_CONTEXT, 2, 0) &&
+	odr_implicit(o, odr_integer, &(*p)->day, ODR_CONTEXT, 3, 1) &&
+	odr_sequence_end(o);
+}
+
+int z_Quarter(ODR o, Z_Quarter **p, int opt, const char *name)
+{
+    static Odr_arm arm[] =
+    {
+	{ODR_IMPLICIT, ODR_CONTEXT, 1, Z_Quarter_first,
+	 (Odr_fun)odr_null, 0},
+	{ODR_IMPLICIT, ODR_CONTEXT, 2, Z_Quarter_second,
+	 (Odr_fun)odr_null, 0},
+	{ODR_IMPLICIT, ODR_CONTEXT, 3, Z_Quarter_third,
+	 (Odr_fun)odr_null, 0},
+	{ODR_IMPLICIT, ODR_CONTEXT, 4, Z_Quarter_fourth,
+	 (Odr_fun)odr_null, 0},
+	{-1, -1, -1, -1, 0, 0}
+    };
+    
+    if (!odr_initmember(o, p, sizeof(**p)))
+	return opt && odr_ok(o);
+    if (odr_choice(o, arm, &(*p)->u, &(*p)->which, 0))
+	return 1;
+    *p = 0;
+    return opt && odr_ok(o);
+}
+
+int z_Season(ODR o, Z_Season **p, int opt, const char *name)
+{
+    static Odr_arm arm[] =
+    {
+	{ODR_IMPLICIT, ODR_CONTEXT, 1, Z_Season_winter,
+	 (Odr_fun)odr_null, 0},
+	{ODR_IMPLICIT, ODR_CONTEXT, 2, Z_Season_spring,
+	 (Odr_fun)odr_null, 0},
+	{ODR_IMPLICIT, ODR_CONTEXT, 3, Z_Season_summer,
+	 (Odr_fun)odr_null, 0},
+	{ODR_IMPLICIT, ODR_CONTEXT, 4, Z_Season_autumn,
+	 (Odr_fun)odr_null, 0},
+	{-1, -1, -1, -1, 0, 0}
+    };
+
+    if (!odr_initmember(o, p, sizeof(**p)))
+	return opt && odr_ok(o);
+    if (odr_choice(o, arm, &(*p)->u, &(*p)->which, 0))
+	return 1;
+    *p = 0;
+    return opt && odr_ok(o);
+}
+
+int z_PartOfYear(ODR o, Z_PartOfYear **p, int opt, const char *name)
+{
+    static Odr_arm arm[] =
+    {
+	{ODR_IMPLICIT, ODR_CONTEXT, 1, Z_PartOfYear_monthAndDay,
+	 (Odr_fun) z_MonthAndDay, 0},
+	{ODR_IMPLICIT, ODR_CONTEXT, 2, Z_PartOfYear_julianDay,
+	 (Odr_fun) odr_integer, 0},
+	{ODR_IMPLICIT, ODR_CONTEXT, 3, Z_PartOfYear_weekNumber,
+	 (Odr_fun) odr_integer, 0},
+	{ODR_IMPLICIT, ODR_CONTEXT, 4, Z_PartOfYear_quarter,
+	 (Odr_fun) z_Quarter, 0},
+	{ODR_IMPLICIT, ODR_CONTEXT, 5, Z_PartOfYear_season,
+	 (Odr_fun) z_Season, 0},
+	{-1, -1, -1, -1, 0, 0}
+    };
+    
+    if (!odr_initmember(o, p, sizeof(**p)))
+	return opt && odr_ok(o);
+    if (odr_choice(o, arm, &(*p)->u, &(*p)->which, 0))
+	return 1;
+    *p = 0;
+    return opt && odr_ok(o);
+}
+
+int z_Era(ODR o, Z_Era **p, int opt, const char *name)
+{
+    static Odr_arm arm[] =
+    {
+	{ODR_IMPLICIT, ODR_CONTEXT, 1, Z_Era_decade, (Odr_fun)odr_null, 0},
+	{ODR_IMPLICIT, ODR_CONTEXT, 2, Z_Era_century, (Odr_fun)odr_null, 0},
+	{ODR_IMPLICIT, ODR_CONTEXT, 3, Z_Era_millennium, (Odr_fun)odr_null, 0},
+	{-1, -1, -1, -1, 0, 0}
+    };
+    
+    if (!odr_initmember(o, p, sizeof(**p)))
+	return opt && odr_ok(o);
+    if (odr_choice(o, arm, &(*p)->u, &(*p)->which, 0))
+	return 1;
+    *p = 0;
+    return opt && odr_ok(o);
+}
+
+int z_DateFlags(ODR o, Z_DateFlags **p, int opt, const char *name)
+{
+    if (!odr_sequence_begin(o, p, sizeof(**p), 0))
+	return opt && odr_ok(o);
+    return
+	odr_implicit(o, odr_null, &(*p)->circa, ODR_CONTEXT, 1, 1) &&
+	odr_implicit(o, z_Era, &(*p)->era, ODR_CONTEXT, 2, 1) &&
+	odr_sequence_end(o);
+}
+
+int z_Date(ODR o, Z_Date **p, int opt, const char *name)
+{
+    if (!odr_sequence_begin(o, p, sizeof(**p), 0))
+	return opt && odr_ok(o);
+    return
+	odr_implicit(o, odr_integer, &(*p)->year, ODR_CONTEXT, 1, 0) &&
+	odr_implicit(o, z_PartOfYear, &(*p)->partOfYear, ODR_CONTEXT, 1, 1) &&
+	odr_implicit(o, z_DateFlags, &(*p)->flags, ODR_CONTEXT, 2, 1) &&
+	odr_sequence_end(o);
+}
+
+int z_Zone(ODR o, Z_Zone **p, int opt, const char *name)
+{
+    static Odr_arm arm[] =
+    {
+	{ODR_IMPLICIT, ODR_CONTEXT, 1, Z_Zone_local, (Odr_fun)odr_null, 0},
+	{ODR_IMPLICIT, ODR_CONTEXT, 2, Z_Zone_utc, (Odr_fun)odr_null, 0},
+	{ODR_IMPLICIT, ODR_CONTEXT, 3, Z_Zone_utcOffset,
+	 (Odr_fun)odr_integer, 0},
+	{-1, -1, -1, -1, 0, 0}
+    };
+    
+    if (!odr_initmember(o, p, sizeof(**p)))
+	return opt && odr_ok(o);
+    if (odr_choice(o, arm, &(*p)->u, &(*p)->which, 0))
+	return 1;
+    *p = 0;
+    return opt && odr_ok(o);
+}
+
+int z_Time(ODR o, Z_Time **p, int opt, const char *name)
+{
+    if (!odr_sequence_begin(o, p, sizeof(**p), 0))
+	return opt && odr_ok(o);
+    return
+	odr_implicit(o, odr_integer, &(*p)->hour, ODR_CONTEXT, 1, 0) &&
+	odr_implicit(o, odr_integer, &(*p)->minute, ODR_CONTEXT, 2, 1) &&
+	odr_implicit(o, odr_integer, &(*p)->second, ODR_CONTEXT, 3, 1) &&
+	odr_implicit(o, z_IntUnit, &(*p)->partOfSecond, ODR_CONTEXT, 4, 1) &&
+	odr_implicit(o, z_Zone, &(*p)->zone, ODR_CONTEXT, 5, 1) &&
+	odr_sequence_end(o);
+}
+
+int z_DateTime(ODR o, Z_DateTime **p, int opt, const char *name)
+{
+    if (!odr_sequence_begin(o, p, sizeof(**p), 0))
+	return opt && odr_ok(o);
+    return
+	odr_implicit(o, z_Date, &(*p)->z3950Date, ODR_CONTEXT, 1, 1) &&
+	odr_implicit(o, z_Time, &(*p)->z3950Time, ODR_CONTEXT, 2, 1) &&
+	odr_sequence_end(o);
+}
+
Index: /main/tags/2.25/gsdl/packages/yaz/asn/prt-dia.c
===================================================================
--- /main/tags/2.25/gsdl/packages/yaz/asn/prt-dia.c	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/yaz/asn/prt-dia.c	(revision 21064)
@@ -0,0 +1,423 @@
+/*
+ * Copyright (c) 1995-1999, Index Data.
+ * See the file LICENSE for details.
+ * Sebastian Hammer, Adam Dickmeiss
+ *
+ * $Log$
+ * Revision 1.1  2000/08/03 03:09:49  johnmcp
+ * Added the YAZ toolkit source to the packages directory (for z39.50 stuff)
+ *
+ * Revision 1.7  1999/11/30 13:47:11  adam
+ * Improved installation. Moved header files to include/yaz.
+ *
+ * Revision 1.6  1999/04/20 09:56:47  adam
+ * Added 'name' paramter to encoder/decoder routines (typedef Odr_fun).
+ * Modified all encoders/decoders to reflect this change.
+ *
+ * Revision 1.5  1998/02/11 11:53:32  adam
+ * Changed code so that it compiles as C++.
+ *
+ * Revision 1.4  1996/01/22 09:46:34  quinn
+ * Added Sort PDU. Moved StringList to main protocol file.
+ *
+ * Revision 1.3  1995/09/29  17:11:54  quinn
+ * Smallish
+ *
+ * Revision 1.2  1995/09/27  15:02:41  quinn
+ * Modified function heads & prototypes.
+ *
+ * Revision 1.1  1995/08/29  11:19:31  quinn
+ * Added Diagnostic Format
+ *
+ *
+ */
+
+#include <yaz/proto.h>
+
+int z_TooMany(ODR o, Z_TooMany **p, int opt, const char *name)
+{
+    if (!odr_sequence_begin(o, p, sizeof(**p), 0))
+	return opt && odr_ok(o);
+    return
+        odr_implicit(o, odr_integer, &(*p)->tooManyWhat, ODR_CONTEXT, 1, 0) &&
+	odr_implicit(o, odr_integer, &(*p)->max, ODR_CONTEXT, 2, 1) &&
+	odr_sequence_end(o);
+}
+
+int z_BadSpec(ODR o, Z_BadSpec **p, int opt, const char *name)
+{
+    if (!odr_sequence_begin(o, p, sizeof(**p), 0))
+	return opt && odr_ok(o);
+    return
+        odr_implicit(o, z_Specification, &(*p)->spec, ODR_CONTEXT, 1, 0) &&
+	odr_implicit(o, z_DatabaseName, &(*p)->db, ODR_CONTEXT, 2, 1) &&
+	odr_implicit_settag(o, ODR_CONTEXT, 3) &&
+	(odr_sequence_of(o, (Odr_fun)z_Specification, &(*p)->goodOnes,
+	    &(*p)->num_goodOnes, 0) || odr_ok(o)) &&
+	odr_sequence_end(o);
+}
+
+int z_DbUnavailWhy(ODR o, Z_DbUnavailWhy **p, int opt, const char *name)
+{
+    if (!odr_sequence_begin(o, p, sizeof(**p), 0))
+	return opt && odr_ok(o);
+    return
+        odr_implicit(o, odr_integer, &(*p)->reasonCode, ODR_CONTEXT, 1, 1) &&
+	odr_implicit(o, z_InternationalString, &(*p)->message, ODR_CONTEXT,
+	    2, 1) &&
+	odr_sequence_end(o);
+}
+
+int z_DbUnavail(ODR o, Z_DbUnavail **p, int opt, const char *name)
+{
+    if (!odr_sequence_begin(o, p, sizeof(**p), 0))
+	return opt && odr_ok(o);
+    return
+        odr_implicit(o, z_DatabaseName, &(*p)->db, ODR_CONTEXT, 1, 0) &&
+	odr_implicit(o, z_DbUnavailWhy, &(*p)->why, ODR_CONTEXT, 2, 0) &&
+	odr_sequence_end(o);
+}
+
+int z_Attribute(ODR o, Z_Attribute **p, int opt, const char *name)
+{
+    if (!odr_sequence_begin(o, p, sizeof(**p), 0))
+	return opt && odr_ok(o);
+    return
+        odr_implicit(o, odr_oid, &(*p)->id, ODR_CONTEXT, 1, 0) &&
+	odr_implicit(o, odr_integer, &(*p)->type, ODR_CONTEXT, 2, 1) &&
+	odr_implicit(o, odr_integer, &(*p)->value, ODR_CONTEXT, 3, 1) &&
+	odr_explicit(o, z_Term, &(*p)->term, ODR_CONTEXT, 4, 1) &&
+	odr_sequence_end(o);
+}
+
+int z_AttCombo(ODR o, Z_AttCombo **p, int opt, const char *name)
+{
+    if (!odr_sequence_begin(o, p, sizeof(**p), 0))
+	return opt && odr_ok(o);
+    return
+	odr_implicit(o, z_AttributeList, &(*p)->unsupportedCombination,
+	    ODR_CONTEXT, 1, 0) &&
+	odr_implicit_settag(o, ODR_CONTEXT, 2) &&
+	(odr_sequence_of(o, (Odr_fun)z_AttributeList, &(*p)->alternatives,
+	    &(*p)->num_alternatives, 0) || odr_ok(o)) &&
+	odr_sequence_end(o);
+}
+
+int z_DiagTerm(ODR o, Z_DiagTerm **p, int opt, const char *name)
+{
+    if (!odr_sequence_begin(o, p, sizeof(**p), 0))
+	return opt && odr_ok(o);
+    return
+    	odr_implicit(o, odr_integer, &(*p)->problem, ODR_CONTEXT, 1, 1) &&
+	odr_explicit(o, z_Term, &(*p)->term, ODR_CONTEXT, 2, 0) &&
+	odr_sequence_end(o);
+}
+
+int z_Proximity(ODR o, Z_Proximity **p, int opt, const char *name)
+{
+    static Odr_arm arm[] =
+    {
+	{ODR_IMPLICIT, ODR_CONTEXT, 1, Z_Proximity_resultSets,
+	 (Odr_fun)odr_null, 0},
+	{ODR_IMPLICIT, ODR_CONTEXT, 2, Z_Proximity_badSet,
+	    (Odr_fun)z_InternationalString, 0},
+	{ODR_IMPLICIT, ODR_CONTEXT, 3, Z_Proximity_relation,
+	 (Odr_fun)odr_integer, 0},
+	{ODR_IMPLICIT, ODR_CONTEXT, 4, Z_Proximity_unit,
+	 (Odr_fun)odr_integer, 0},
+	{ODR_IMPLICIT, ODR_CONTEXT, 5, Z_Proximity_distance,
+	 (Odr_fun)odr_integer, 0},
+	{ODR_EXPLICIT, ODR_CONTEXT, 6, Z_Proximity_attributes,
+	 (Odr_fun)z_AttributeList, 0},
+	{ODR_IMPLICIT, ODR_CONTEXT, 7, Z_Proximity_ordered,
+	 (Odr_fun)odr_null, 0},
+	{ODR_IMPLICIT, ODR_CONTEXT, 8, Z_Proximity_exclusion,
+	 (Odr_fun)odr_null, 0},
+	{-1, -1, -1, -1, 0, 0}
+    };
+    
+    if (o->direction == ODR_DECODE)
+	*p = (Z_Proximity *)odr_malloc(o, sizeof(**p));
+    else if (!*p)
+	return opt;
+    if (odr_choice(o, arm, &(*p)->u, &(*p)->which, 0))
+	return 1;
+    *p = 0;
+    return opt && odr_ok(o);
+}
+
+int z_AttrListList(ODR o, Z_AttrListList **p, int opt, const char *name)
+{
+    if (o->direction == ODR_DECODE)
+	*p = (Z_AttrListList *)odr_malloc(o, sizeof(**p));
+    else if (!*p)
+	return opt;
+    if (odr_sequence_of(o, (Odr_fun)z_AttributeList, &(*p)->lists,
+			&(*p)->num_lists, 0))
+	return 1;
+    *p = 0;
+    return opt && odr_ok(o);
+}
+
+int z_Scan(ODR o, Z_Scan **p, int opt, const char *name)
+{
+    static Odr_arm arm[] =
+    {
+	{ODR_IMPLICIT, ODR_CONTEXT, 0, Z_ScanD_nonZeroStepSize,
+	 (Odr_fun)odr_null, 0},
+	{ODR_IMPLICIT, ODR_CONTEXT, 1, Z_ScanD_specifiedStepSize,
+	 (Odr_fun)odr_null, 0},
+	{ODR_IMPLICIT, ODR_CONTEXT, 3, Z_ScanD_termList1,
+	 (Odr_fun)odr_null, 0},
+	{ODR_IMPLICIT, ODR_CONTEXT, 4, Z_ScanD_termList2,
+	 (Odr_fun)z_AttrListList, 0},
+	{ODR_IMPLICIT, ODR_CONTEXT, 5, Z_ScanD_posInResponse,
+	 (Odr_fun)odr_integer, 0},
+	{ODR_IMPLICIT, ODR_CONTEXT, 6, Z_ScanD_resources,
+	 (Odr_fun)odr_null, 0},
+	{ODR_IMPLICIT, ODR_CONTEXT, 7, Z_ScanD_endOfList,
+	 (Odr_fun)odr_null, 0},
+	{-1, -1, -1, -1, 0, 0}
+    };
+    
+    if (o->direction == ODR_DECODE)
+	*p = (Z_Scan *)odr_malloc(o, sizeof(**p));
+    else if (!*p)
+	return opt;
+    if (odr_choice(o, arm, &(*p)->u, &(*p)->which, 0))
+	return 1;
+    *p = 0;
+    return opt && odr_ok(o);
+}
+
+int z_Sort(ODR o, Z_Sort **p, int opt, const char *name)
+{
+    static Odr_arm arm[] =
+    {
+	{ODR_IMPLICIT, ODR_CONTEXT, 0, Z_SortD_sequence,
+	 (Odr_fun)odr_null, 0},
+	{ODR_IMPLICIT, ODR_CONTEXT, 1, Z_SortD_noRsName,
+	 (Odr_fun)odr_null, 0},
+	{ODR_IMPLICIT, ODR_CONTEXT, 2, Z_SortD_tooMany,
+	 (Odr_fun)odr_integer, 0},
+	{ODR_IMPLICIT, ODR_CONTEXT, 3, Z_SortD_incompatible,
+	 (Odr_fun)odr_null, 0},
+	{ODR_IMPLICIT, ODR_CONTEXT, 4, Z_SortD_generic,
+	 (Odr_fun)odr_null, 0},
+	{ODR_IMPLICIT, ODR_CONTEXT, 5, Z_SortD_dbSpecific,
+	 (Odr_fun)odr_null, 0},
+#if 0
+	{ODR_EXPLICIT, ODR_CONTEXT, 6, Z_SortD_sortElement,
+	 (Odr_fun)z_SortElement, 0},
+#endif
+	{ODR_IMPLICIT, ODR_CONTEXT, 7, Z_SortD_key,
+	 (Odr_fun)odr_integer, 0},
+	{ODR_IMPLICIT, ODR_CONTEXT, 8, Z_SortD_action,
+	 (Odr_fun)odr_null, 0},
+	{ODR_IMPLICIT, ODR_CONTEXT, 9, Z_SortD_illegal,
+	 (Odr_fun)odr_integer, 0},
+	{ODR_IMPLICIT, ODR_CONTEXT, 10, Z_SortD_inputTooLarge,
+	 (Odr_fun)z_StringList, 0},
+	{ODR_IMPLICIT, ODR_CONTEXT, 11, Z_SortD_aggregateTooLarge,
+	 (Odr_fun)odr_null, 0},
+	{-1, -1, -1, -1, 0, 0}
+    };
+
+    if (o->direction == ODR_DECODE)
+	*p = (Z_Sort *)odr_malloc(o, sizeof(**p));
+    else if (!*p)
+	return opt;
+    if (odr_choice(o, arm, &(*p)->u, &(*p)->which, 0))
+	return 1;
+    *p = 0;
+    return opt && odr_ok(o);
+}
+
+int z_Segmentation(ODR o, Z_Segmentation **p, int opt, const char *name)
+{
+    static Odr_arm arm[] =
+    {
+	{ODR_IMPLICIT, ODR_CONTEXT, 0, Z_SegmentationD_segments,
+	 (Odr_fun)odr_null, 0},
+	{-1, -1, -1, -1, 0, 0}
+    };
+
+    if (o->direction == ODR_DECODE)
+	*p = (Z_Segmentation *)odr_malloc(o, sizeof(**p));
+    else if (!*p)
+	return opt;
+    if (odr_choice(o, arm, &(*p)->u, &(*p)->which, 0))
+	return 1;
+    *p = 0;
+    return opt && odr_ok(o);
+}
+
+int z_ExtServices(ODR o, Z_ExtServices **p, int opt, const char *name)
+{
+    static Odr_arm arm[] =
+    {
+	{ODR_IMPLICIT, ODR_CONTEXT, 0, Z_ExtServicesD_req,
+	 (Odr_fun)odr_integer, 0},
+	{ODR_IMPLICIT, ODR_CONTEXT, 1, Z_ExtServicesD_permission,
+	 (Odr_fun)odr_integer, 0},
+	{ODR_IMPLICIT, ODR_CONTEXT, 2, Z_ExtServicesD_immediate,
+	 (Odr_fun)odr_integer, 0},
+	{-1, -1, -1, -1, 0, 0}
+    };
+    
+    if (o->direction == ODR_DECODE)
+	*p = (Z_ExtServices *)odr_malloc(o, sizeof(**p));
+    else if (!*p)
+	return opt;
+    if (odr_choice(o, arm, &(*p)->u, &(*p)->which, 0))
+	return 1;
+    *p = 0;
+    return opt && odr_ok(o);
+}
+
+int z_OidList(ODR o, Z_OidList **p, int opt, const char *name)
+{
+    if (o->direction == ODR_DECODE)
+	*p = (Z_OidList *)odr_malloc(o, sizeof(**p));
+    else if (!*p)
+	return opt;
+    if (odr_sequence_of(o, (Odr_fun)odr_oid, &(*p)->oids, &(*p)->num_oids, 0))
+	return 1;
+    *p = 0;
+    return opt && odr_ok(o);
+}
+
+int z_AccessCtrl(ODR o, Z_AccessCtrl **p, int opt, const char *name)
+{
+    static Odr_arm arm[] =
+    {
+	{ODR_IMPLICIT, ODR_CONTEXT, 1, Z_AccessCtrlD_noUser,
+	 (Odr_fun)odr_null, 0},
+	{ODR_IMPLICIT, ODR_CONTEXT, 2, Z_AccessCtrlD_refused,
+	 (Odr_fun)odr_null, 0},
+	{ODR_IMPLICIT, ODR_CONTEXT, 3, Z_AccessCtrlD_simple,
+	 (Odr_fun)odr_null, 0},
+	{ODR_IMPLICIT, ODR_CONTEXT, 4, Z_AccessCtrlD_oid,
+	 (Odr_fun)z_OidList, 0},
+	{ODR_IMPLICIT, ODR_CONTEXT, 5, Z_AccessCtrlD_alternative,
+	 (Odr_fun)z_OidList, 0},
+	{ODR_IMPLICIT, ODR_CONTEXT, 6, Z_AccessCtrlD_pwdInv,
+	 (Odr_fun)odr_null, 0},
+	{ODR_IMPLICIT, ODR_CONTEXT, 7, Z_AccessCtrlD_pwdExp,
+	 (Odr_fun)odr_null, 0},
+	{-1, -1, -1, -1, 0, 0}
+    };
+
+    if (o->direction == ODR_DECODE)
+	*p = (Z_AccessCtrl *)odr_malloc(o, sizeof(**p));
+    else if (!*p)
+	return opt;
+    if (odr_choice(o, arm, &(*p)->u, &(*p)->which, 0))
+	return 1;
+    *p = 0;
+    return opt && odr_ok(o);
+}
+
+int z_RecordSyntax(ODR o, Z_RecordSyntax **p, int opt, const char *name)
+{
+    if (!odr_sequence_begin(o, p, sizeof(**p), 0))
+	return opt && odr_ok(o);
+    return
+    	odr_implicit(o, odr_oid, &(*p)->unsupportedSyntax,
+		     ODR_CONTEXT, 1, 0) &&
+	odr_implicit_settag(o, ODR_CONTEXT, 2) &&
+	(odr_sequence_of(o, (Odr_fun)odr_oid, &(*p)->suggestedAlternatives,
+			 &(*p)->num_suggestedAlternatives, 0) || odr_ok(o)) &&
+	odr_sequence_end(o);
+}
+
+int z_DiagFormat(ODR o, Z_DiagFormat **p, int opt, const char *name)
+{
+    static Odr_arm arm[] =
+    {
+	{ODR_IMPLICIT, ODR_CONTEXT, 1000, Z_DiagFormat_tooMany,
+	 (Odr_fun)z_TooMany, 0},
+	{ODR_IMPLICIT, ODR_CONTEXT, 1001, Z_DiagFormat_badSpec,
+	 (Odr_fun)z_BadSpec, 0},
+	{ODR_IMPLICIT, ODR_CONTEXT, 1002, Z_DiagFormat_dbUnavail,
+	 (Odr_fun)z_DbUnavail, 0},
+	{ODR_IMPLICIT, ODR_CONTEXT, 1003, Z_DiagFormat_unSupOp,
+	 (Odr_fun)odr_integer, 0},
+	{ODR_IMPLICIT, ODR_CONTEXT, 1004, Z_DiagFormat_attribute,
+	 (Odr_fun)z_Attribute, 0},
+	{ODR_IMPLICIT, ODR_CONTEXT, 1005, Z_DiagFormat_attCombo,
+	 (Odr_fun)z_AttCombo, 0},
+	{ODR_IMPLICIT, ODR_CONTEXT, 1006, Z_DiagFormat_term,
+	 (Odr_fun)z_DiagTerm, 0},
+	{ODR_EXPLICIT, ODR_CONTEXT, 1007, Z_DiagFormat_proximity,
+	 (Odr_fun)z_Proximity, 0},
+	{ODR_EXPLICIT, ODR_CONTEXT, 1008, Z_DiagFormat_scan,
+	 (Odr_fun)z_Scan, 0},
+	{ODR_EXPLICIT, ODR_CONTEXT, 1009, Z_DiagFormat_sort,
+	 (Odr_fun)z_Sort, 0},
+	{ODR_EXPLICIT, ODR_CONTEXT, 1010, Z_DiagFormat_segmentation,
+	 (Odr_fun)z_Segmentation, 0},
+	{ODR_EXPLICIT, ODR_CONTEXT, 1011, Z_DiagFormat_extServices,
+	 (Odr_fun)z_ExtServices, 0},
+	{ODR_EXPLICIT, ODR_CONTEXT, 1012, Z_DiagFormat_accessCtrl,
+	 (Odr_fun)z_AccessCtrl, 0},
+	{ODR_IMPLICIT, ODR_CONTEXT, 1013, Z_DiagFormat_recordSyntax,
+	 (Odr_fun)z_RecordSyntax, 0},
+	{-1, -1, -1, -1, 0, 0}
+    };
+
+    if (o->direction == ODR_DECODE)
+	*p = (Z_DiagFormat *)odr_malloc(o, sizeof(**p));
+    else if (!*p)
+	return opt;
+    if (odr_choice(o, arm, &(*p)->u, &(*p)->which, 0))
+	return 1;
+    *p = 0;
+    return opt && odr_ok(o);
+}
+
+int z_Diagnostic(ODR o, Z_Diagnostic **p, int opt, const char *name)
+{
+    static Odr_arm arm[] =
+    {
+	{ODR_IMPLICIT, ODR_CONTEXT, 1, Z_Diagnostic_defaultDiagRec,
+	 (Odr_fun)z_DefaultDiagFormat, 0},
+	{ODR_EXPLICIT, ODR_CONTEXT, 2, Z_Diagnostic_explicitDiagnostic,
+	 (Odr_fun)z_DiagFormat, 0},
+	{-1, -1, -1, -1, 0, 0}
+    };
+    
+    if (o->direction == ODR_DECODE)
+	*p = (Z_Diagnostic *)odr_malloc(o, sizeof(**p));
+    else if (!*p)
+	return opt;
+    if (odr_choice(o, arm, &(*p)->u, &(*p)->which, 0))
+	return 1;
+    *p = 0;
+    return opt && odr_ok(o);
+}
+
+int z_DiagnosticUnit(ODR o, Z_DiagnosticUnit **p, int opt, const char *name)
+{
+    if (!odr_sequence_begin(o, p, sizeof(**p), 0))
+	return opt && odr_ok(o);
+    return
+    	odr_explicit(o, z_Diagnostic, &(*p)->diagnostic, ODR_CONTEXT, 1, 1) &&
+	odr_implicit(o, z_InternationalString, &(*p)->message,
+		     ODR_CONTEXT, 2, 1) &&
+	odr_sequence_end(o);
+}
+
+int z_DiagnosticFormat(ODR o, Z_DiagnosticFormat **p, int opt,
+		       const char *name)
+{
+    if (o->direction == ODR_DECODE)
+	*p = (Z_DiagnosticFormat *)odr_malloc(o, sizeof(**p));
+    else if (!*p)
+	return opt;
+    if (odr_sequence_of(o, (Odr_fun)z_DiagnosticUnit, &(*p)->diagnostics,
+	&(*p)->num_diagnostics, 0))
+	return 1;
+    *p = 0;
+    return opt && odr_ok(o);
+}
Index: /main/tags/2.25/gsdl/packages/yaz/asn/prt-esp.c
===================================================================
--- /main/tags/2.25/gsdl/packages/yaz/asn/prt-esp.c	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/yaz/asn/prt-esp.c	(revision 21064)
@@ -0,0 +1,214 @@
+/*
+ * Copyright (c) 1995-1999, Index Data.
+ * See the file LICENSE for details.
+ * Sebastian Hammer, Adam Dickmeiss
+ *
+ * $Log$
+ * Revision 1.1  2000/08/03 03:09:49  johnmcp
+ * Added the YAZ toolkit source to the packages directory (for z39.50 stuff)
+ *
+ * Revision 1.5  1999/11/30 13:47:11  adam
+ * Improved installation. Moved header files to include/yaz.
+ *
+ * Revision 1.4  1999/04/20 09:56:47  adam
+ * Added 'name' paramter to encoder/decoder routines (typedef Odr_fun).
+ * Modified all encoders/decoders to reflect this change.
+ *
+ * Revision 1.3  1998/02/11 11:53:32  adam
+ * Changed code so that it compiles as C++.
+ *
+ * Revision 1.2  1998/02/10 15:31:46  adam
+ * Implemented date and time structure. Changed the Update Extended
+ * Service.
+ *
+ * Revision 1.1  1995/10/12 10:34:37  quinn
+ * Added Espec-1.
+ *
+ *
+ */
+
+#include <yaz/proto.h>
+
+int z_OccurValues(ODR o, Z_OccurValues **p, int opt, const char *name)
+{
+    if (!odr_sequence_begin(o, p, sizeof(**p), 0))
+	return opt && odr_ok(o);
+    return
+    	odr_implicit(o, odr_integer, &(*p)->start, ODR_CONTEXT, 1, 0) &&
+	odr_implicit(o, odr_integer, &(*p)->howMany, ODR_CONTEXT, 2, 1) &&
+	odr_sequence_end(o);
+}
+
+int z_Occurrences(ODR o, Z_Occurrences **p, int opt, const char *name)
+{
+    static Odr_arm arm[] =
+    {
+	{ODR_IMPLICIT, ODR_CONTEXT, 1, Z_Occurrences_all,
+	 (Odr_fun)odr_null, 0},
+	{ODR_IMPLICIT, ODR_CONTEXT, 2, Z_Occurrences_last,
+	 (Odr_fun)odr_null, 0},
+	{ODR_IMPLICIT, ODR_CONTEXT, 3, Z_Occurrences_values,
+	 (Odr_fun)z_OccurValues, 0},
+	{-1, -1, -1, -1, 0, 0}
+    };
+    
+    if (o->direction == ODR_DECODE)
+	*p = (Z_Occurrences *)odr_malloc(o, sizeof(**p));
+    else if (!*p)
+	return opt;
+    if (odr_choice(o, arm, &(*p)->u, &(*p)->which, 0))
+	return 1;
+    *p = 0;
+    return opt && odr_ok(o);
+}
+
+int z_SpecificTag(ODR o, Z_SpecificTag **p, int opt, const char *name)
+{
+    if (!odr_sequence_begin(o, p, sizeof(**p), 0))
+	return opt && odr_ok(o);
+    return
+        odr_implicit(o, odr_oid, &(*p)->schemaId, ODR_CONTEXT, 0, 1) &&
+        odr_implicit(o, odr_integer, &(*p)->tagType, ODR_CONTEXT, 1, 1) &&
+	odr_explicit(o, z_StringOrNumeric, &(*p)->tagValue, ODR_CONTEXT,
+		     2, 0) &&
+	odr_explicit(o, z_Occurrences, &(*p)->occurrences,
+		     ODR_CONTEXT, 3, 1) &&
+	odr_sequence_end(o);
+}
+
+int z_ETagUnit(ODR o, Z_ETagUnit **p, int opt, const char *name)
+{
+    static Odr_arm arm[] =
+    {
+	{ODR_IMPLICIT, ODR_CONTEXT, 1, Z_ETagUnit_specificTag,
+	 (Odr_fun)z_SpecificTag, 0},
+	{ODR_EXPLICIT, ODR_CONTEXT, 2, Z_ETagUnit_wildThing,
+	 (Odr_fun)z_Occurrences, 0},
+	{ODR_IMPLICIT, ODR_CONTEXT, 3, Z_ETagUnit_wildPath,
+	 (Odr_fun)odr_null, 0},
+	{-1, -1, -1 -1, 0, 0}
+    };
+    
+    if (o->direction == ODR_DECODE)
+	*p = (Z_ETagUnit *)odr_malloc(o, sizeof(**p));
+    else if (!*p)
+	return opt;
+    if (odr_choice(o, arm, &(*p)->u, &(*p)->which, 0))
+	return 1;
+    *p = 0;
+    return opt && odr_ok(o);
+}
+
+int z_ETagPath(ODR o, Z_ETagPath **p, int opt, const char *name)
+{
+    if (o->direction == ODR_DECODE)
+	*p = (Z_ETagPath *)odr_malloc(o, sizeof(**p));
+    else if (!*p)
+	return opt;
+    if (odr_sequence_of(o, (Odr_fun)z_ETagUnit, &(*p)->tags,
+			&(*p)->num_tags, 0))
+	return 1;
+    *p = 0;
+    return opt && odr_ok(o);
+}
+
+int z_SimpleElement(ODR o, Z_SimpleElement **p, int opt, const char *name)
+{
+    if (!odr_sequence_begin(o, p, sizeof(**p), 0))
+	return opt && odr_ok(o);
+    return
+    	odr_implicit(o, z_ETagPath, &(*p)->path, ODR_CONTEXT, 1, 0) &&
+	odr_implicit(o, z_Variant, &(*p)->variantRequest,
+		     ODR_CONTEXT, 2, 1) &&
+	odr_sequence_end(o);
+}
+
+int z_CompoPrimitives(ODR o, Z_CompoPrimitives **p, int opt, const char *name)
+{
+    if (o->direction == ODR_DECODE)
+	*p = (Z_CompoPrimitives *)odr_malloc(o, sizeof(**p));
+    else if (!*p)
+	return opt;
+    if (odr_sequence_of(o, z_InternationalString, &(*p)->primitives,
+			&(*p)->num_primitives, 0))
+	return 1;
+    *p = 0;
+    return opt && odr_ok(o);
+}
+
+int z_CompoSpecs(ODR o, Z_CompoSpecs **p, int opt, const char *name)
+{
+    if (o->direction == ODR_DECODE)
+	*p = (Z_CompoSpecs *)odr_malloc(o, sizeof(**p));
+    else if (!*p)
+	return opt;
+    if (odr_sequence_of(o, (Odr_fun)z_SimpleElement, &(*p)->specs,
+			&(*p)->num_specs, 0))
+	return 1;
+    *p = 0;
+    return opt && odr_ok(o);
+}
+
+int z_CompositeElement(ODR o, Z_CompositeElement **p, int opt,
+		       const char *name)
+{
+    static Odr_arm arm[] =
+    {
+	{ODR_IMPLICIT, ODR_CONTEXT, 1, Z_CompoElement_primitives,
+	 (Odr_fun)z_CompoPrimitives, 0},
+	{ODR_IMPLICIT, ODR_CONTEXT, 2, Z_CompoElement_specs,
+	 (Odr_fun)z_CompoSpecs, 0},
+	{-1, -1, -1, -1, 0, 0}
+    };
+    
+    if (!odr_sequence_begin(o, p, sizeof(**p), 0))
+	return opt && odr_ok(o);
+    return
+        odr_constructed_begin(o, &(*p)->elementList, ODR_CONTEXT, 1, 0) &&
+	odr_choice(o, arm, &(*p)->elementList, &(*p)->which, 0) &&
+	odr_constructed_end(o) &&
+	odr_implicit(o, z_ETagPath, &(*p)->deliveryTag, ODR_CONTEXT, 2, 0) &&
+	odr_implicit(o, z_Variant, &(*p)->variantRequest, ODR_CONTEXT, 3, 1) &&
+	odr_sequence_end(o);
+}
+
+int z_ElementRequest(ODR o, Z_ElementRequest **p, int opt, const char *name)
+{
+    static Odr_arm arm[] =
+    {
+	{ODR_IMPLICIT, ODR_CONTEXT, 1, Z_ERequest_simpleElement,
+	 (Odr_fun)z_SimpleElement, 0},
+	{ODR_IMPLICIT, ODR_CONTEXT, 2, Z_ERequest_compositeElement,
+	 (Odr_fun)z_CompositeElement, 0},
+	{-1, -1, -1 -1, 0, 0}
+    };
+    
+    if (o->direction == ODR_DECODE)
+	*p = (Z_ElementRequest *)odr_malloc(o, sizeof(**p));
+    else if (!*p)
+	return opt;
+    if (odr_choice(o, arm, &(*p)->u, &(*p)->which, 0))
+	return 1;
+    *p = 0;
+    return opt && odr_ok(o);
+}
+
+int z_Espec1(ODR o, Z_Espec1 **p, int opt, const char *name)
+{
+    if (!odr_sequence_begin(o, p, sizeof(**p), 0))
+	return opt && odr_ok(o);
+    return
+        odr_implicit_settag(o, ODR_CONTEXT, 1) &&
+	(odr_sequence_of(o, z_InternationalString, &(*p)->elementSetNames,
+			 &(*p)->num_elementSetNames, 0) || odr_ok(o)) &&
+	odr_implicit(o, odr_oid, &(*p)->defaultVariantSetId,
+		     ODR_CONTEXT, 2, 1) &&
+	odr_implicit(o, z_Variant, &(*p)->defaultVariantRequest,
+		     ODR_CONTEXT, 3, 1) &&
+	odr_implicit(o, odr_integer, &(*p)->defaultTagType,
+		     ODR_CONTEXT, 4, 1) &&
+	odr_implicit_settag(o, ODR_CONTEXT, 5) &&
+	(odr_sequence_of(o, (Odr_fun)z_ElementRequest, &(*p)->elements,
+			 &(*p)->num_elements, 0) || odr_ok(o)) &&
+	odr_sequence_end(o);
+}
Index: /main/tags/2.25/gsdl/packages/yaz/asn/prt-exd.c
===================================================================
--- /main/tags/2.25/gsdl/packages/yaz/asn/prt-exd.c	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/yaz/asn/prt-exd.c	(revision 21064)
@@ -0,0 +1,417 @@
+/*
+ * Copyright (c) 1995-1999, Index Data.
+ * See the file LICENSE for details.
+ * Sebastian Hammer, Adam Dickmeiss
+ *
+ * $Log$
+ * Revision 1.1  2000/08/03 03:09:50  johnmcp
+ * Added the YAZ toolkit source to the packages directory (for z39.50 stuff)
+ *
+ * Revision 1.11  1999/11/30 13:47:11  adam
+ * Improved installation. Moved header files to include/yaz.
+ *
+ * Revision 1.10  1999/05/26 13:49:12  adam
+ * DB Update implemented in client (very basic).
+ *
+ * Revision 1.9  1999/04/20 09:56:48  adam
+ * Added 'name' paramter to encoder/decoder routines (typedef Odr_fun).
+ * Modified all encoders/decoders to reflect this change.
+ *
+ * Revision 1.8  1998/02/11 11:53:32  adam
+ * Changed code so that it compiles as C++.
+ *
+ * Revision 1.7  1998/02/10 15:31:46  adam
+ * Implemented date and time structure. Changed the Update Extended
+ * Service.
+ *
+ * Revision 1.6  1998/01/05 09:04:57  adam
+ * Fixed bugs in encoders/decoders - Not operator (!) missing.
+ *
+ * Revision 1.5  1997/04/30 08:52:02  quinn
+ * Null
+ *
+ * Revision 1.4  1996/10/10  12:35:12  quinn
+ * Added Update extended service.
+ *
+ * Revision 1.3  1995/09/29  17:11:54  quinn
+ * Smallish
+ *
+ * Revision 1.2  1995/09/27  15:02:41  quinn
+ * Modified function heads & prototypes.
+ *
+ * Revision 1.1  1995/08/21  09:16:32  quinn
+ * Added Extended services + Item Order
+ *
+ *
+ */
+
+#include <yaz/proto.h>
+
+int z_TaskPackage(ODR o, Z_TaskPackage **p, int opt, const char *name)
+{
+    if (!odr_sequence_begin(o, p, sizeof(**p), 0))
+        return opt && odr_ok(o);
+    return
+        odr_implicit(o, odr_oid, &(*p)->packageType, ODR_CONTEXT, 1, 0) &&
+        odr_implicit(o, z_InternationalString, &(*p)->packageName,
+		     ODR_CONTEXT, 2, 1) &&
+        odr_implicit(o, z_InternationalString, &(*p)->userId,
+		     ODR_CONTEXT, 3, 1) &&
+        odr_implicit(o, z_IntUnit, &(*p)->retentionTime, ODR_CONTEXT, 4, 1) &&
+        odr_implicit(o, z_Permissions, &(*p)->permissions,
+		     ODR_CONTEXT, 5, 1) &&
+        odr_implicit(o, z_InternationalString, &(*p)->description,
+		     ODR_CONTEXT, 6, 1) &&
+        odr_implicit(o, odr_octetstring, &(*p)->targetReference,
+		     ODR_CONTEXT, 7, 0) &&
+        odr_implicit(o, odr_generalizedtime, &(*p)->creationDateTime,
+		     ODR_CONTEXT, 8, 1) &&
+        odr_implicit(o, odr_integer, &(*p)->taskStatus,
+		     ODR_CONTEXT, 9, 0) &&
+	odr_implicit_settag(o, ODR_CONTEXT, 10) &&
+	(odr_sequence_of(o, (Odr_fun)z_DiagRec, &(*p)->packageDiagnostics,
+			 &(*p)->num_packageDiagnostics, 0) || odr_ok(o)) &&
+        odr_implicit(o, z_External, &(*p)->taskSpecificParameters,
+		     ODR_CONTEXT, 11, 0) &&
+	odr_sequence_end(o);
+}
+
+/* ----------------------- ITEM ORDER --------------------- */
+
+int z_IOTargetPart(ODR o, Z_IOTargetPart **p, int opt, const char *name)
+{
+    if (!odr_sequence_begin(o, p, sizeof(**p), 0))
+	return opt && odr_ok(o);
+    return
+    	odr_implicit(o, z_External, &(*p)->itemRequest, ODR_CONTEXT, 1, 1) &&
+	odr_implicit(o, z_External, &(*p)->statusOrErrorReport, ODR_CONTEXT,
+	    2, 0) &&
+	odr_implicit(o, odr_integer, &(*p)->auxiliaryStatus, ODR_CONTEXT,
+	    3, 1) &&
+	odr_sequence_end(o);
+}
+
+int z_IOResultSetItem(ODR o, Z_IOResultSetItem **p, int opt, const char *name)
+{
+    if (!odr_sequence_begin(o, p, sizeof(**p), 0))
+	return opt && odr_ok(o);
+    return
+    	odr_implicit(o, z_InternationalString, &(*p)->resultSetId, ODR_CONTEXT,
+	    1, 0) &&
+	odr_implicit(o, odr_integer, &(*p)->item, ODR_CONTEXT, 2, 1) &&
+	odr_sequence_end(o);
+}
+
+int z_IOOriginPartNotToKeep(ODR o, Z_IOOriginPartNotToKeep **p, int opt,
+			    const char *name)
+{
+    if (!odr_sequence_begin(o, p, sizeof(**p), 0))
+	return opt && odr_ok(o);
+    return
+    	odr_implicit(o, z_IOResultSetItem, &(*p)->resultSetItem, ODR_CONTEXT,
+	    1, 0) &&
+	odr_implicit(o, z_External, &(*p)->itemRequest, ODR_CONTEXT, 2, 1) &&
+	odr_sequence_end(o);
+}
+
+int z_IOContact(ODR o, Z_IOContact **p, int opt, const char *name)
+{
+    if (!odr_sequence_begin(o, p, sizeof(**p), 0))
+	return opt && odr_ok(o);
+    return
+    	odr_implicit(o, z_InternationalString, &(*p)->name, ODR_CONTEXT,
+	    1, 1) &&
+	odr_implicit(o, z_InternationalString, &(*p)->phone, ODR_CONTEXT,
+	    2, 1) &&
+	odr_implicit(o, z_InternationalString, &(*p)->email, ODR_CONTEXT,
+	    3, 1) &&
+	odr_sequence_end(o);
+}
+
+int z_IOCreditCardInfo(ODR o, Z_IOCreditCardInfo **p, int opt,
+		       const char *name)
+{
+    if (!odr_sequence_begin(o, p, sizeof(**p), 0))
+	return opt && odr_ok(o);
+    return
+    	odr_implicit(o, z_InternationalString, &(*p)->nameOnCard, ODR_CONTEXT,
+	    1, 0) &&
+	odr_implicit(o, z_InternationalString, &(*p)->expirationDate,
+	    ODR_CONTEXT, 2, 0) &&
+	odr_implicit(o, z_InternationalString, &(*p)->cardNumber, ODR_CONTEXT,
+	    3, 0) &&
+	odr_sequence_end(o);
+}
+
+int z_IOBilling(ODR o, Z_IOBilling **p, int opt, const char *name)
+{
+    static Odr_arm arm[] =
+    {
+	{ODR_IMPLICIT, ODR_CONTEXT, 0, Z_IOBilling_billInvoice,
+	 (Odr_fun)odr_null, 0},
+	{ODR_IMPLICIT, ODR_CONTEXT, 1, Z_IOBilling_prepay,
+	 (Odr_fun)odr_null, 0},
+	{ODR_IMPLICIT, ODR_CONTEXT, 2, Z_IOBilling_depositAccount,
+	 (Odr_fun)odr_null, 0},
+	{ODR_IMPLICIT, ODR_CONTEXT, 3, Z_IOBilling_creditCard,
+	 (Odr_fun)z_IOCreditCardInfo, 0},
+	{ODR_IMPLICIT, ODR_CONTEXT, 4, Z_IOBilling_cardInfoPreviouslySupplied,
+	 (Odr_fun)odr_null, 0},
+	{ODR_IMPLICIT, ODR_CONTEXT, 5, Z_IOBilling_privateKnown,
+	 (Odr_fun)odr_null, 0},
+	{ODR_IMPLICIT, ODR_CONTEXT, 6, Z_IOBilling_privateNotKnown,
+	 (Odr_fun)z_External, 0},
+	{-1, -1, -1, -1, 0, 0}
+    };
+    
+    if (!odr_sequence_begin(o, p, sizeof(**p), 0))
+	return opt && odr_ok(o);
+    return
+        odr_constructed_begin(o, &(*p)->paymentMethod,
+			      ODR_CONTEXT, 1, 0) &&
+	odr_choice(o, arm, &(*p)->paymentMethod, &(*p)->which, 0) &&
+	odr_constructed_end(o) &&
+	odr_implicit(o, z_InternationalString, &(*p)->customerReference,
+		     ODR_CONTEXT, 2, 1) &&
+	odr_implicit(o, z_InternationalString, &(*p)->customerPONumber,
+		     ODR_CONTEXT, 3, 1) &&
+	odr_sequence_end(o);
+}
+
+int z_IOOriginPartToKeep(ODR o, Z_IOOriginPartToKeep **p, int opt,
+			 const char *name)
+{
+    if (!odr_sequence_begin(o, p, sizeof(**p), 0))
+	return opt && odr_ok(o);
+    return
+        odr_implicit(o, z_External, &(*p)->supplDescription,
+		     ODR_CONTEXT, 1, 1) &&
+	odr_implicit(o, z_IOContact, &(*p)->contact, ODR_CONTEXT, 2, 1) &&
+	odr_implicit(o, z_IOBilling, &(*p)->addlBilling,
+		     ODR_CONTEXT, 3, 1) &&
+	odr_sequence_end(o);
+}
+
+int z_IORequest(ODR o, Z_IORequest **p, int opt, const char *name)
+{
+    if (!odr_sequence_begin(o, p, sizeof(**p), 0))
+	return opt && odr_ok(o);
+    return 
+    	odr_implicit(o, z_IOOriginPartToKeep, &(*p)->toKeep,
+		     ODR_CONTEXT, 1, 1) &&
+	odr_implicit(o, z_IOOriginPartNotToKeep, &(*p)->notToKeep,
+		     ODR_CONTEXT, 2, 0) &&
+	odr_sequence_end(o);
+}
+
+int z_IOTaskPackage(ODR o, Z_IOTaskPackage **p, int opt, const char *name)
+{
+    if (!odr_sequence_begin(o, p, sizeof(**p), 0))
+	return opt && odr_ok(o);
+    return
+        odr_implicit(o, z_IOOriginPartToKeep, &(*p)->originPart,
+		     ODR_CONTEXT, 1, 1) &&
+	odr_implicit(o, z_IOTargetPart, &(*p)->targetPart,
+		     ODR_CONTEXT, 2, 0) &&
+	odr_sequence_end(o);
+}
+
+int z_ItemOrder(ODR o, Z_ItemOrder **p, int opt, const char *name)
+{
+    static Odr_arm arm[] =
+    {
+	{ODR_IMPLICIT, ODR_CONTEXT, 1, Z_ItemOrder_esRequest,
+	 (Odr_fun)z_IORequest, 0},
+	{ODR_IMPLICIT, ODR_CONTEXT, 2, Z_ItemOrder_taskPackage,
+	 (Odr_fun)z_IOTaskPackage, 0},
+	{-1, -1, -1, -1, 0, 0}
+    };
+    
+    if (o->direction == ODR_DECODE)
+	*p = (Z_ItemOrder *)odr_malloc(o, sizeof(**p));
+    else if (!*p)
+	return opt;
+    if (odr_choice(o, arm, &(*p)->u, &(*p)->which, 0))
+	return 1;
+    *p = 0;
+    return opt && odr_ok(o);
+}
+
+/* ----------------------- ITEM UPDATE -------------------- */
+
+int z_IUSuppliedRecordsId (ODR o, Z_IUSuppliedRecordsId **p, int opt,
+			   const char *name)
+{
+    static Odr_arm arm[] = {
+        {ODR_IMPLICIT, ODR_CONTEXT, 1, Z_IUSuppliedRecordsId_timeStamp,
+         odr_generalizedtime, 0},
+        {ODR_IMPLICIT, ODR_CONTEXT, 2, Z_IUSuppliedRecordsId_versionNumber,
+         z_InternationalString, 0},
+        {ODR_IMPLICIT, ODR_CONTEXT, 3, Z_IUSuppliedRecordsId_previousVersion,
+         (Odr_fun)odr_external, 0},
+        {-1, -1, -1, -1, 0, 0}
+    };
+    if (!odr_initmember(o, p, sizeof(**p)))
+        return opt && odr_ok(o);
+    if (odr_choice(o, arm, &(*p)->u, &(*p)->which, 0))
+        return 1;
+    *p = 0;
+    return opt && odr_ok(o);
+}
+
+int z_IUCorrelationInfo (ODR o, Z_IUCorrelationInfo **p, int opt,
+			 const char *name)
+{
+    if (!odr_sequence_begin (o, p, sizeof(**p), 0))
+        return opt && odr_ok (o);
+    return
+        odr_implicit (o, z_InternationalString,
+		      &(*p)->note, ODR_CONTEXT, 1, 1) &&
+        odr_implicit (o, odr_integer,
+		      &(*p)->id, ODR_CONTEXT, 2, 1) &&
+        odr_sequence_end (o);
+}
+
+int z_IUSuppliedRecords_elem (ODR o, Z_IUSuppliedRecords_elem **p, int opt,
+			      const char *name)
+{
+    static Odr_arm arm[] = {
+        {ODR_IMPLICIT, ODR_CONTEXT, 1, Z_IUSuppliedRecords_number,
+         (Odr_fun)odr_integer, 0},
+        {ODR_IMPLICIT, ODR_CONTEXT, 2, Z_IUSuppliedRecords_string,
+         (Odr_fun)z_InternationalString, 0},
+        {ODR_IMPLICIT, ODR_CONTEXT, 3, Z_IUSuppliedRecords_opaque,
+         (Odr_fun)odr_octetstring, 0},
+        {-1, -1, -1, -1, 0, 0}
+    };
+    if (!odr_sequence_begin (o, p, sizeof(**p), 0))
+        return opt && odr_ok (o);
+    return
+        ((odr_constructed_begin (o, &(*p)->u, ODR_CONTEXT, 1, 0) &&
+	  odr_choice (o, arm, &(*p)->u, &(*p)->which, 0) &&
+	  odr_constructed_end (o)) || odr_ok(o)) &&
+        odr_explicit (o, z_IUSuppliedRecordsId,
+		      &(*p)->supplementalId, ODR_CONTEXT, 2, 1) &&
+        odr_implicit (o, z_IUCorrelationInfo,
+		      &(*p)->correlationInfo, ODR_CONTEXT, 3, 1) &&
+        odr_implicit (o, z_External,
+		      &(*p)->record, ODR_CONTEXT, 4, 0) &&
+        odr_sequence_end (o);
+}
+
+int z_IUSuppliedRecords (ODR o, Z_IUSuppliedRecords **p, int opt,
+			 const char *name)
+{
+    if (!odr_initmember (o, p, sizeof(**p)))
+        return opt && odr_ok(o);
+    if (odr_sequence_of (o, (Odr_fun)z_IUSuppliedRecords_elem, &(*p)->elements,
+			 &(*p)->num, 0))
+        return 1;
+    *p = 0;
+    return opt && odr_ok(o);
+}
+
+int z_IUTaskPackageRecordStructure (ODR o, Z_IUTaskPackageRecordStructure **p,
+				    int opt, const char *name)
+{
+    static Odr_arm arm[] = {
+        {ODR_IMPLICIT, ODR_CONTEXT, 1, Z_IUTaskPackageRecordStructure_record,
+         (Odr_fun)odr_external, 0},
+        {ODR_EXPLICIT, ODR_CONTEXT, 2,
+	 Z_IUTaskPackageRecordStructure_surrogateDiagnostics,
+         (Odr_fun)z_DiagRecs, 0},
+        {-1, -1, -1, -1, 0, 0}
+    };
+    if (!odr_sequence_begin (o, p, sizeof(**p), 0))
+        return opt && odr_ok (o);
+    return
+        ((odr_constructed_begin (o, &(*p)->u, ODR_CONTEXT, 1, 0) &&
+	  odr_choice (o, arm, &(*p)->u, &(*p)->which, 0) &&
+	  odr_constructed_end (o)) || odr_ok(o)) &&
+        odr_implicit (o, z_IUCorrelationInfo,
+		      &(*p)->correlationInfo, ODR_CONTEXT, 2, 1) &&
+        odr_implicit (o, odr_integer,
+		      &(*p)->recordStatus, ODR_CONTEXT, 3, 0) &&
+	odr_implicit (o, z_DiagRecs, 
+		      &(*p)->supplementalDiagnostics, ODR_CONTEXT, 4, 1) &&
+        odr_sequence_end (o);
+}
+
+int z_IUOriginPartToKeep (ODR o, Z_IUOriginPartToKeep **p, int opt,
+			  const char *name)
+{
+    if (!odr_sequence_begin (o, p, sizeof(**p), 0))
+        return opt && odr_ok (o);
+    return
+        odr_implicit (o, odr_integer,
+		      &(*p)->action, ODR_CONTEXT, 1, 0) &&
+        odr_implicit (o, z_InternationalString,
+		      &(*p)->databaseName, ODR_CONTEXT, 2, 0) &&
+        odr_implicit (o, odr_oid,
+		      &(*p)->schema, ODR_CONTEXT, 3, 1) &&
+        odr_implicit (o, z_InternationalString,
+		      &(*p)->elementSetName, ODR_CONTEXT, 4, 1) &&
+	odr_implicit (o, odr_external,
+		      &(*p)->actionQualifier, ODR_CONTEXT, 5, 1) &&
+        odr_sequence_end (o);
+}
+
+int z_IUTargetPart (ODR o, Z_IUTargetPart **p, int opt, const char *name)
+{
+    if (!odr_sequence_begin (o, p, sizeof(**p), 0))
+        return opt && odr_ok (o);
+    return
+        odr_implicit (o, odr_integer,
+		      &(*p)->updateStatus, ODR_CONTEXT, 1, 0) &&
+        odr_implicit_settag (o, ODR_CONTEXT, 2) &&
+        (odr_sequence_of(o, (Odr_fun)z_DiagRec, &(*p)->globalDiagnostics,
+			 &(*p)->num_globalDiagnostics, 0) || odr_ok(o)) &&
+        odr_implicit_settag (o, ODR_CONTEXT, 3) &&
+        odr_sequence_of(o, (Odr_fun)z_IUTaskPackageRecordStructure,
+			&(*p)->taskPackageRecords,
+			&(*p)->num_taskPackageRecords, 0) &&
+        odr_sequence_end (o);
+}
+
+int z_IUUpdateEsRequest (ODR o, Z_IUUpdateEsRequest **p, int opt,
+			 const char *name)
+{
+    if (!odr_sequence_begin (o, p, sizeof(**p), 0))
+        return opt && odr_ok (o);
+    return
+        odr_explicit (o, z_IUOriginPartToKeep,
+		      &(*p)->toKeep, ODR_CONTEXT, 1, 0) &&
+        odr_explicit (o, z_IUSuppliedRecords,
+		      &(*p)->notToKeep, ODR_CONTEXT, 2, 0) &&
+        odr_sequence_end (o);
+}
+
+int z_IUUpdateTaskPackage (ODR o, Z_IUUpdateTaskPackage **p, int opt,
+			   const char *name)
+{
+    if (!odr_sequence_begin (o, p, sizeof(**p), 0))
+        return opt && odr_ok (o);
+    return
+        odr_explicit (o, z_IUOriginPartToKeep,
+		      &(*p)->originPart, ODR_CONTEXT, 1, 0) &&
+        odr_explicit (o, z_IUTargetPart,
+		      &(*p)->targetPart, ODR_CONTEXT, 2, 0) &&
+        odr_sequence_end (o);
+}
+
+int z_IUUpdate (ODR o, Z_IUUpdate **p, int opt, const char *name)
+{
+    static Odr_arm arm[] = {
+        {ODR_IMPLICIT, ODR_CONTEXT, 1, Z_IUUpdate_esRequest,
+         (Odr_fun)z_IUUpdateEsRequest, 0},
+        {ODR_IMPLICIT, ODR_CONTEXT, 2, Z_IUUpdate_taskPackage,
+         (Odr_fun)z_IUUpdateTaskPackage, 0},
+        {-1, -1, -1, -1, 0, 0}
+    };
+    if (!odr_initmember(o, p, sizeof(**p)))
+        return opt && odr_ok(o);
+    if (odr_choice(o, arm, &(*p)->u, &(*p)->which, 0))
+        return 1;
+    *p = 0;
+    return opt && odr_ok(o);
+}
Index: /main/tags/2.25/gsdl/packages/yaz/asn/prt-exp.c
===================================================================
--- /main/tags/2.25/gsdl/packages/yaz/asn/prt-exp.c	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/yaz/asn/prt-exp.c	(revision 21064)
@@ -0,0 +1,1568 @@
+/*
+ * Copyright (c) 1995-1999, Index Data.
+ * See the file LICENSE for details.
+ * Sebastian Hammer, Adam Dickmeiss
+ *
+ * $Log$
+ * Revision 1.1  2000/08/03 03:09:51  johnmcp
+ * Added the YAZ toolkit source to the packages directory (for z39.50 stuff)
+ *
+ * Revision 1.13  1999/11/30 13:47:11  adam
+ * Improved installation. Moved header files to include/yaz.
+ *
+ * Revision 1.12  1999/04/20 09:56:48  adam
+ * Added 'name' paramter to encoder/decoder routines (typedef Odr_fun).
+ * Modified all encoders/decoders to reflect this change.
+ *
+ * Revision 1.11  1999/03/18 12:57:13  adam
+ * Fixed bug in TargetInfo encoder/decoder.
+ *
+ * Revision 1.10  1998/05/18 13:06:52  adam
+ * Changed the way attribute sets are handled by the retriaval module.
+ * Extended Explain conversion / schema.
+ * Modified server and client to work with ASN.1 compiled protocol handlers.
+ *
+ * Revision 1.9  1998/02/11 11:53:32  adam
+ * Changed code so that it compiles as C++.
+ *
+ * Revision 1.8  1996/01/02 11:46:41  quinn
+ * Changed 'operator' to 'roperator' to avoid C++ conflict.
+ *
+ * Revision 1.7  1995/12/14  16:28:07  quinn
+ * More explain stuff.
+ *
+ * Revision 1.6  1995/12/14  11:09:09  quinn
+ * Fixed bug in tagging.
+ *
+ * Revision 1.5  1995/12/05  11:15:50  quinn
+ * Work.
+ *
+ * Revision 1.4  1995/09/29  17:11:54  quinn
+ * Smallish
+ *
+ * Revision 1.3  1995/09/27  15:02:42  quinn
+ * Modified function heads & prototypes.
+ *
+ * Revision 1.2  1995/08/15  11:59:43  quinn
+ * Updated External
+ *
+ * Revision 1.1  1995/08/10  08:54:02  quinn
+ * Added Explain
+ *
+ *
+ */
+
+#include <yaz/proto.h>
+
+int z_LanguageCode(ODR o, char **p, int opt, const char *name);
+int z_CommonInfo(ODR o, Z_CommonInfo **p, int opt, const char *name);
+int z_HumanStringUnit(ODR o, Z_HumanStringUnit **p, int opt, const char *name);
+int z_HumanString(ODR o, Z_HumanString **p, int opt, const char *name);
+int z_IconObjectUnit(ODR o, Z_IconObjectUnit **p, int opt, const char *name);
+int z_IconObject(ODR o, Z_IconObject **p, int opt, const char *name);
+int z_ContactInfo(ODR o, Z_ContactInfo **p, int opt, const char *name);
+int z_NetworkAddressIA(ODR o, Z_NetworkAddressIA **p, int opt,
+		       const char *name);
+int z_NetworkAddressOPA(ODR o, Z_NetworkAddressOPA **p, int opt,
+			const char *name);
+int z_NetworkAddressOther(ODR o, Z_NetworkAddressOther **p, int opt,
+			  const char *name);
+int z_NetworkAddress(ODR o, Z_NetworkAddress **p, int opt, const char *name);
+int z_AccessInfo(ODR o, Z_AccessInfo **p, int opt, const char *name);
+int z_QueryTypeDetails(ODR o, Z_QueryTypeDetails **p, int opt,
+		       const char *name);
+int z_PrivateCapOperator(ODR o, Z_PrivateCapOperator **p, int opt,
+			 const char *name);
+int z_PrivateCapabilities(ODR o, Z_PrivateCapabilities **p, int opt,
+			  const char *name);
+int z_RpnCapabilities(ODR o, Z_RpnCapabilities **p, int opt, const char *name);
+int z_Iso8777Capabilities(ODR o, Z_Iso8777Capabilities **p, int opt,
+			  const char *name);
+int z_ProxSupportPrivate(ODR o, Z_ProxSupportPrivate **p, int opt,
+			 const char *name);
+int z_ProxSupportUnit(ODR o, Z_ProxSupportUnit **p, int opt, const char *name);
+int z_ProximitySupport(ODR o, Z_ProximitySupport **p, int opt,
+		       const char *name);
+int z_SearchKey(ODR o, Z_SearchKey **p, int opt, const char *name);
+int z_AccessRestrictionsUnit(ODR o, Z_AccessRestrictionsUnit **p, int opt,
+			     const char *name);
+int z_AccessRestrictions(ODR o, Z_AccessRestrictions **p, int opt,
+			 const char *name);
+int z_CostsOtherCharge(ODR o, Z_CostsOtherCharge **p, int opt,
+		       const char *name);
+int z_Costs(ODR o, Z_Costs **p, int opt, const char *name);
+int z_Charge(ODR o, Z_Charge **p, int opt, const char *name);
+int z_DatabaseList(ODR o, Z_DatabaseList **p, int opt, const char *name);
+int z_AttributeCombinations(ODR o, Z_AttributeCombinations **p, int opt,
+			    const char *name);
+int z_AttributeCombination(ODR o, Z_AttributeCombination **p, int opt,
+			   const char *name);
+int z_AttributeValueList(ODR o, Z_AttributeValueList **p, int opt,
+			 const char *name);
+int z_AttributeOccurrence(ODR o, Z_AttributeOccurrence **p, int opt,
+			  const char *name);
+int z_AttributeValue(ODR o, Z_AttributeValue **p, int opt, const char *name);
+int z_TargetInfo(ODR o, Z_TargetInfo **p, int opt, const char *name);
+int z_DatabaseInfo(ODR o, Z_DatabaseInfo **p, int opt, const char *name);
+int z_TagTypeMapping(ODR o, Z_TagTypeMapping **p, int opt, const char *name);
+int z_SchemaInfo(ODR o, Z_SchemaInfo **p, int opt, const char *name);
+int z_ElementInfo(ODR o, Z_ElementInfo **p, int opt, const char *name);
+int z_PathUnit(ODR o, Z_PathUnit **p, int opt, const char *name);
+int z_Path(ODR o, Z_Path **p, int opt, const char *name);
+int z_ElementInfoList(ODR o, Z_Path **p, int opt, const char *name);
+int z_ElementDataType(ODR o, Z_ElementDataType **p, int opt, const char *name);
+int z_TagSetInfoElements(ODR o, Z_TagSetInfoElements **p, int opt,
+			 const char *name);
+int z_TagSetInfo(ODR o, Z_TagSetInfo **p, int opt, const char *name);
+int z_RecordSyntaxInfo(ODR o, Z_RecordSyntaxInfo **p, int opt,
+		       const char *name);
+int z_AttributeSetInfo(ODR o, Z_AttributeSetInfo **p, int opt,
+		       const char *name);
+int z_AttributeType(ODR o, Z_AttributeType **p, int opt, const char *name);
+int z_AttributeDescription(ODR o, Z_AttributeDescription **p, int opt,
+			   const char *name);
+int z_TermListElement(ODR o, Z_TermListElement **p, int opt, const char *name);
+int z_TermListInfo(ODR o, Z_TermListInfo **p, int opt, const char *name);
+int z_ExtendedServicesInfo(ODR o, Z_ExtendedServicesInfo **p, int opt,
+			   const char *name);
+int z_AttributeDetails(ODR o, Z_AttributeDetails **p, int opt,
+		       const char *name);
+int z_AttributeSetDetails(ODR o, Z_AttributeSetDetails **p, int opt,
+			  const char *name);
+int z_AttributeTypeDetails(ODR o, Z_AttributeTypeDetails **p, int opt,
+			   const char *name);
+int z_OmittedAttributeInterpretation(ODR o,
+				     Z_OmittedAttributeInterpretation **p,
+				     int opt, const char *name);
+int z_EScanInfo(ODR o, Z_EScanInfo **p, int opt, const char *name);
+int z_TermListDetails(ODR o, Z_TermListDetails **p, int opt, const char *name);
+int z_ElementSetDetails(ODR o, Z_ElementSetDetails **p, int opt,
+			const char *name);
+int z_RetrievalRecordDetails(ODR o, Z_RetrievalRecordDetails **p, int opt,
+			     const char *name);
+int z_PerElementDetails(ODR o, Z_PerElementDetails **p, int opt,
+			const char *name);
+int z_RecordTag(ODR o, Z_RecordTag **p, int opt, const char *name);
+int z_SortDetails(ODR o, Z_SortDetails **p, int opt, const char *name);
+int z_SortKeyDetails(ODR o, Z_SortKeyDetails **p, int opt, const char *name);
+int z_ProcessingInformation(ODR o, Z_ProcessingInformation **p, int opt,
+			    const char *name);
+int z_VariantSetInfo(ODR o, Z_VariantSetInfo **p, int opt, const char *name);
+int z_VariantClass(ODR o, Z_VariantClass **p, int opt, const char *name);
+int z_VariantType(ODR o, Z_VariantType **p, int opt, const char *name);
+int z_VariantValue(ODR o, Z_VariantValue **p, int opt, const char *name);
+int z_ValueSetEnumerated(ODR o, Z_ValueSetEnumerated **p, int opt,
+			 const char *name);
+int z_ValueSet(ODR o, Z_ValueSet **p, int opt, const char *name);
+int z_ValueRange(ODR o, Z_ValueRange **p, int opt, const char *name);
+int z_ValueDescription(ODR o, Z_ValueDescription **p, int opt,
+		       const char *name);
+int z_UnitInfo(ODR o, Z_UnitInfo **p, int opt, const char *name);
+int z_UnitType(ODR o, Z_UnitType **p, int opt, const char *name);
+int z_Units(ODR o, Z_Units **p, int opt, const char *name);
+int z_CategoryList(ODR o, Z_CategoryList **p, int opt, const char *name);
+int z_CategoryInfo(ODR o, Z_CategoryInfo **p, int opt, const char *name);
+int z_ExplainRecord(ODR o, Z_ExplainRecord **p, int opt, const char *name);
+
+int z_LanguageCode(ODR o, char **p, int opt, const char *name)
+{
+    return z_InternationalString(o, p, opt, 0);
+}
+
+int z_CommonInfo(ODR o, Z_CommonInfo **p, int opt, const char *name)
+{
+    if (!odr_sequence_begin(o, p, sizeof(**p), 0))
+        return opt && odr_ok(o);
+    return
+        odr_implicit(o, odr_generalizedtime, &(*p)->dateAdded,
+		     ODR_CONTEXT, 0, 1) &&
+        odr_implicit(o, odr_generalizedtime, &(*p)->dateChanged,
+		     ODR_CONTEXT, 1, 1) &&
+        odr_implicit(o, odr_generalizedtime, &(*p)->expiry,
+		     ODR_CONTEXT, 2, 1) &&
+        odr_implicit(o, z_LanguageCode, &(*p)->humanStringLanguage,
+		     ODR_CONTEXT, 3, 1) &&
+        z_OtherInformation(o, &(*p)->otherInfo, 1, 0) &&
+        odr_sequence_end(o);
+}
+
+int z_HumanStringUnit(ODR o, Z_HumanStringUnit **p, int opt, const char *name)
+{
+    if (!odr_sequence_begin(o, p, sizeof(**p), 0))
+        return opt && odr_ok(o);
+    return
+        odr_implicit(o, z_LanguageCode, &(*p)->language, ODR_CONTEXT, 0, 1) &&
+        odr_implicit(o, z_InternationalString, &(*p)->text, ODR_CONTEXT,
+		     1, 0) &&
+        odr_sequence_end(o);
+}
+
+int z_HumanString(ODR o, Z_HumanString **p, int opt, const char *name)
+{
+    if (!odr_initmember(o, p, sizeof(**p)))
+	return opt && odr_ok(o);
+    if (odr_sequence_of(o, (Odr_fun)z_HumanStringUnit, &(*p)->strings,
+			&(*p)->num_strings, 0))
+	return 1;
+    *p = 0;
+    return opt && odr_ok(o);
+}
+
+int z_IconObjectUnit(ODR o, Z_IconObjectUnit **p, int opt, const char *name)
+{
+    static Odr_arm arm[] = 
+    {
+    	{ODR_IMPLICIT, ODR_CONTEXT, 1, Z_IconObjectUnit_ianaType,
+	 z_InternationalString, 0},
+	{ODR_IMPLICIT, ODR_CONTEXT, 2, Z_IconObjectUnit_z3950type,
+	 z_InternationalString, 0},
+	{ODR_IMPLICIT, ODR_CONTEXT, 3, Z_IconObjectUnit_otherType,
+	 z_InternationalString, 0},
+	{-1, -1, -1, -1, 0, 0}
+    };
+
+    if (!odr_sequence_begin(o, p, sizeof(**p), 0))
+        return opt && odr_ok(o);
+    return
+    	odr_constructed_begin(o, &(*p)->bodyType, ODR_CONTEXT, 1, 0) &&
+	odr_choice(o, arm, &(*p)->bodyType, &(*p)->which, 0) &&
+	odr_constructed_end(o) &&
+        odr_implicit(o, odr_octetstring, &(*p)->content, ODR_CONTEXT, 2, 0) &&
+        odr_sequence_end(o);
+}
+
+int z_IconObject(ODR o, Z_IconObject **p, int opt, const char *name)
+{
+    if (!odr_initmember(o, p, sizeof(**p)))
+	return opt && odr_ok(o);
+    if (odr_sequence_of(o, (Odr_fun)z_IconObjectUnit, &(*p)->elements,
+    	&(*p)->num, 0))
+	return 1;
+    *p = 0;
+    return opt && odr_ok(o);
+}
+
+int z_ContactInfo(ODR o, Z_ContactInfo **p, int opt, const char *name)
+{
+    if (!odr_sequence_begin(o, p, sizeof(**p), 0))
+        return opt && odr_ok(o);
+    return
+        odr_implicit(o, z_InternationalString, &(*p)->name,
+		     ODR_CONTEXT, 0, 1) &&
+        odr_implicit(o, z_HumanString, &(*p)->description,
+		     ODR_CONTEXT, 1, 1) &&
+        odr_implicit(o, z_HumanString, &(*p)->address,
+		     ODR_CONTEXT, 2, 1) &&
+        odr_implicit(o, z_InternationalString, &(*p)->email,
+		     ODR_CONTEXT, 3, 1) &&
+        odr_implicit(o, z_InternationalString, &(*p)->phone,
+		     ODR_CONTEXT, 4, 1) &&
+	odr_sequence_end(o);
+}
+
+int z_NetworkAddressIA(ODR o, Z_NetworkAddressIA **p, int opt,
+		       const char *name)
+{
+    if (!odr_sequence_begin(o, p, sizeof(**p), 0))
+    	return opt;
+    return
+        odr_implicit(o, z_InternationalString, &(*p)->hostAddress,
+		     ODR_CONTEXT, 0, 0) &&
+        odr_implicit(o, odr_integer, &(*p)->port, ODR_CONTEXT, 1, 0) &&
+	odr_sequence_end(o);
+}
+
+int z_NetworkAddressOPA(ODR o, Z_NetworkAddressOPA **p, int opt,
+			const char *name)
+{
+    if (!odr_sequence_begin(o, p, sizeof(**p), 0))
+    	return opt;
+    return
+        odr_implicit(o, z_InternationalString, &(*p)->pSel,
+		     ODR_CONTEXT, 0, 0) &&
+        odr_implicit(o, z_InternationalString, &(*p)->sSel,
+		     ODR_CONTEXT, 1, 1) &&
+        odr_implicit(o, z_InternationalString, &(*p)->tSel,
+		     ODR_CONTEXT, 2, 1) &&
+        odr_implicit(o, z_InternationalString, &(*p)->nSap,
+		     ODR_CONTEXT, 3, 0) &&
+	odr_sequence_end(o);
+}
+
+int z_NetworkAddressOther(ODR o, Z_NetworkAddressOther **p, int opt,
+			  const char *name)
+{
+    if (!odr_sequence_begin(o, p, sizeof(**p), 0))
+    	return opt;
+    return
+        odr_implicit(o, z_InternationalString, &(*p)->type,
+		     ODR_CONTEXT, 0, 0) &&
+        odr_implicit(o, z_InternationalString, &(*p)->address,
+		     ODR_CONTEXT, 1, 0) &&
+	odr_sequence_end(o);
+}
+
+int z_NetworkAddress(ODR o, Z_NetworkAddress **p, int opt, const char *name)
+{
+    static Odr_arm arm[] =
+    {
+    	{ODR_IMPLICIT, ODR_CONTEXT, 0, Z_NetworkAddress_iA,
+	 (Odr_fun)z_NetworkAddressIA, 0},
+	{ODR_IMPLICIT, ODR_CONTEXT, 1, Z_NetworkAddress_oPA,
+	 (Odr_fun)z_NetworkAddressOPA, 0},
+	{ODR_IMPLICIT, ODR_CONTEXT, 2, Z_NetworkAddress_other,
+	    (Odr_fun)z_NetworkAddressOther, 0},
+	{-1, -1, -1, -1, 0, 0}
+    };
+
+    if (!odr_initmember(o, p, sizeof(**p)))
+	return opt && odr_ok(o);
+    if (odr_choice(o, arm, &(*p)->u, &(*p)->which, 0))
+    	return 1;
+    *p = 0;
+    return opt && odr_ok(o);
+}
+
+int z_AccessInfo(ODR o, Z_AccessInfo **p, int opt, const char *name)
+{
+    if (!odr_sequence_begin(o, p, sizeof(**p), 0))
+        return opt && odr_ok(o);
+    return
+	odr_implicit_settag(o, ODR_CONTEXT, 0) &&
+	(odr_sequence_of(o, (Odr_fun)z_QueryTypeDetails,
+			 &(*p)->queryTypesSupported,
+			 &(*p)->num_queryTypesSupported, 0) || odr_ok(o)) &&
+	odr_implicit_settag(o, ODR_CONTEXT, 1) &&
+	(odr_sequence_of(o, (Odr_fun)odr_oid, &(*p)->diagnosticsSets,
+			 &(*p)->num_diagnosticsSets, 0) || odr_ok(o)) &&
+	odr_implicit_settag(o, ODR_CONTEXT, 2) &&
+	(odr_sequence_of(o, (Odr_fun)odr_oid, &(*p)->attributeSetIds,
+			 &(*p)->num_attributeSetIds, 0) || odr_ok(o)) &&
+	odr_implicit_settag(o, ODR_CONTEXT, 3) &&
+	(odr_sequence_of(o, (Odr_fun)odr_oid, &(*p)->schemas,
+			 &(*p)->num_schemas, 0) ||
+	 odr_ok(o)) &&
+	odr_implicit_settag(o, ODR_CONTEXT, 4) &&
+	(odr_sequence_of(o, (Odr_fun)odr_oid, &(*p)->recordSyntaxes,
+			 &(*p)->num_recordSyntaxes, 0) || odr_ok(o)) &&
+	odr_implicit_settag(o, ODR_CONTEXT, 5) &&
+	(odr_sequence_of(o, (Odr_fun)odr_oid, &(*p)->resourceChallenges,
+			 &(*p)->num_resourceChallenges, 0) || odr_ok(o)) &&
+        odr_implicit(o, z_AccessRestrictions, &(*p)->restrictedAccess,
+		     ODR_CONTEXT, 6, 1) &&
+        odr_implicit(o, z_Costs, &(*p)->costInfo, ODR_CONTEXT, 8, 1) &&
+	odr_implicit_settag(o, ODR_CONTEXT, 9) &&
+	(odr_sequence_of(o, (Odr_fun)odr_oid, &(*p)->variantSets,
+			 &(*p)->num_variantSets, 0) || odr_ok(o)) &&
+	odr_implicit_settag(o, ODR_CONTEXT, 10) &&
+	(odr_sequence_of(o, (Odr_fun)z_ElementSetName, &(*p)->elementSetNames,
+			 &(*p)->num_elementSetNames, 0) || odr_ok(o)) &&
+	odr_implicit_settag(o, ODR_CONTEXT, 11) &&
+	(odr_sequence_of(o, (Odr_fun)z_InternationalString, &(*p)->unitSystems,
+			 &(*p)->num_unitSystems, 0) || odr_ok(o)) &&
+	odr_sequence_end(o);
+}
+
+int z_QueryTypeDetails(ODR o, Z_QueryTypeDetails **p, int opt,
+		       const char *name)
+{
+    static Odr_arm arm[] =
+    {
+	{ODR_IMPLICIT, ODR_CONTEXT, 0, Z_QueryTypeDetails_private,
+	 (Odr_fun)z_PrivateCapabilities, 0},
+	{ODR_IMPLICIT, ODR_CONTEXT, 1, Z_QueryTypeDetails_rpn,
+	 (Odr_fun)z_RpnCapabilities, 0},
+	{ODR_IMPLICIT, ODR_CONTEXT, 2, Z_QueryTypeDetails_iso8777,
+	 (Odr_fun)z_Iso8777Capabilities, 0},
+	{ODR_IMPLICIT, ODR_CONTEXT, 3, Z_QueryTypeDetails_z39_58,
+	 (Odr_fun)z_HumanString, 0},
+	{ODR_IMPLICIT, ODR_CONTEXT, 4, Z_QueryTypeDetails_erpn,
+	 (Odr_fun)z_RpnCapabilities, 0},
+	{ODR_IMPLICIT, ODR_CONTEXT, 5, Z_QueryTypeDetails_rankedList,
+	 (Odr_fun)z_HumanString, 0},
+	{-1, -1, -1, -1, 0, 0}
+    };
+
+    if (!odr_initmember(o, p, sizeof(**p)))
+	return opt && odr_ok(o);
+    if (odr_choice(o, arm, &(*p)->u, &(*p)->which, 0))
+	return 1;
+    *p = 0;
+    return opt && odr_ok(o);
+}
+
+int z_PrivateCapOperator(ODR o, Z_PrivateCapOperator **p, int opt,
+			 const char *name)
+{
+    if (!odr_sequence_begin(o, p, sizeof(**p), 0))
+        return opt && odr_ok(o);
+    return
+        odr_implicit(o, z_InternationalString, &(*p)->roperator,
+		     ODR_CONTEXT, 0, 0) &&
+        odr_implicit(o, z_HumanString, &(*p)->description,
+		     ODR_CONTEXT, 1, 1) &&
+	odr_sequence_end(o);
+}
+
+int z_PrivateCapabilities(ODR o, Z_PrivateCapabilities **p, int opt,
+			  const char *name)
+{
+    if (!odr_sequence_begin(o, p, sizeof(**p), 0))
+    	return opt && odr_ok(o);
+    return
+    	odr_implicit_settag(o, ODR_CONTEXT, 0) &&
+	(odr_sequence_of(o, (Odr_fun)z_PrivateCapOperator, &(*p)->operators,
+			 &(*p)->num_operators, 0) || odr_ok(o)) &&
+	odr_implicit_settag(o, ODR_CONTEXT, 1) &&
+	(odr_sequence_of(o, (Odr_fun)z_SearchKey, &(*p)->searchKeys,
+			 &(*p)->num_searchKeys, 0) || odr_ok(o)) &&
+	odr_implicit_settag(o, ODR_CONTEXT, 2) &&
+	(odr_sequence_of(o, (Odr_fun)z_HumanString, &(*p)->description,
+			 &(*p)->num_description, 0) || odr_ok(o)) &&
+        odr_sequence_end(o);
+}
+
+int z_RpnCapabilities(ODR o, Z_RpnCapabilities **p, int opt, const char *name)
+{
+    if (!odr_sequence_begin(o, p, sizeof(**p), 0))
+        return opt && odr_ok(o);
+    return
+	odr_implicit_settag(o, ODR_CONTEXT, 0) &&
+	(odr_sequence_of(o, (Odr_fun)odr_integer, &(*p)->operators,
+			 &(*p)->num_operators, 0) || odr_ok(o)) &&
+        odr_implicit(o, odr_bool, &(*p)->resultSetAsOperandSupported,
+		     ODR_CONTEXT, 1, 0) &&
+        odr_implicit(o, odr_bool, &(*p)->restrictionOperandSupported,
+		     ODR_CONTEXT, 2, 0) &&
+        odr_implicit(o, z_ProximitySupport, &(*p)->proximity, ODR_CONTEXT,
+		     3, 1) &&
+        odr_sequence_end(o);
+}
+
+int z_Iso8777Capabilities(ODR o, Z_Iso8777Capabilities **p, int opt,
+			  const char *name)
+{
+    if (!odr_sequence_begin(o, p, sizeof(**p), 0))
+        return opt && odr_ok(o);
+    return
+	odr_implicit_settag(o, ODR_CONTEXT, 0) &&
+	odr_sequence_of(o, (Odr_fun)z_SearchKey, &(*p)->searchKeys,
+			&(*p)->num_searchKeys, 0) &&
+        odr_implicit(o, z_HumanString, &(*p)->restrictions, ODR_CONTEXT,
+		     1, 1) &&
+        odr_sequence_end(o);
+}
+
+int z_ProxSupportPrivate(ODR o, Z_ProxSupportPrivate **p, int opt,
+			 const char *name)
+{
+    if (!odr_sequence_begin(o, p, sizeof(**p), 0))
+    	return opt && odr_ok(o);
+    return
+    	odr_implicit(o, odr_integer, &(*p)->unit, ODR_CONTEXT, 0, 0) &&
+	odr_implicit(o, z_HumanString, &(*p)->description,
+		     ODR_CONTEXT, 1, 1) &&
+	odr_sequence_end(o);
+}
+
+int z_ProxSupportUnit(ODR o, Z_ProxSupportUnit **p, int opt, const char *name)
+{
+    static Odr_arm arm[] =
+    {
+    	{ODR_IMPLICIT, ODR_CONTEXT, 1, Z_ProxSupportUnit_known,
+	 (Odr_fun)odr_integer, 0},
+	{ODR_IMPLICIT, ODR_CONTEXT, 2, Z_ProxSupportUnit_private,
+	 (Odr_fun)z_ProxSupportPrivate, 0},
+	{-1, -1, -1, -1, 0, 0}
+    };
+    
+    if (!odr_initmember(o, p, sizeof(**p)))
+	return opt && odr_ok(o);
+    if (odr_choice(o, arm, &(*p)->u, &(*p)->which, 0))
+    	return 1;
+    *p = 0;
+    return opt && odr_ok(o);
+}
+
+int z_ProximitySupport(ODR o, Z_ProximitySupport **p, int opt,
+		       const char *name)
+{
+    if (!odr_sequence_begin(o, p, sizeof(**p), 0))
+        return opt && odr_ok(o);
+    return
+    	odr_implicit(o, odr_bool, &(*p)->anySupport, ODR_CONTEXT, 0, 0) &&
+	odr_implicit_settag(o, ODR_CONTEXT, 1) &&
+	(odr_sequence_of(o, (Odr_fun)z_ProxSupportUnit, &(*p)->unitsSupported,
+			 &(*p)->num_unitsSupported, 0) || odr_ok(o)) &&
+        odr_sequence_end(o);
+}
+
+int z_SearchKey(ODR o, Z_SearchKey **p, int opt, const char *name)
+{
+    if (!odr_sequence_begin(o, p, sizeof(**p), 0))
+        return opt && odr_ok(o);
+    return
+        odr_implicit(o, z_InternationalString, &(*p)->searchKey,
+		     ODR_CONTEXT, 0, 0) &&
+        odr_implicit(o, z_HumanString, &(*p)->description,
+		     ODR_CONTEXT, 1, 1) &&
+        odr_sequence_end(o);
+}
+
+int z_AccessRestrictionsUnit(ODR o, Z_AccessRestrictionsUnit **p, int opt,
+			     const char *name)
+{
+    if (!odr_sequence_begin(o, p, sizeof(**p), 0))
+        return opt && odr_ok(o);
+    return
+        odr_explicit(o, odr_integer, &(*p)->accessType, ODR_CONTEXT, 0, 0) &&
+        odr_implicit(o, z_HumanString, &(*p)->accessText, ODR_CONTEXT, 1, 1) &&
+	odr_implicit_settag(o, ODR_CONTEXT, 2) &&
+	(odr_sequence_of(o, (Odr_fun)odr_oid, &(*p)->accessChallenges,
+			 &(*p)->num_accessChallenges, 0) || odr_ok(o)) &&
+        odr_sequence_end(o);
+}
+
+int z_AccessRestrictions(ODR o, Z_AccessRestrictions **p, int opt,
+			 const char *name)
+{
+    if (!odr_initmember(o, p, sizeof(**p)))
+	return opt && odr_ok(o);
+    if (odr_sequence_of(o, (Odr_fun)z_AccessRestrictionsUnit, &(*p)->elements,
+			&(*p)->num, 0))
+	return 1;
+    *p = 0;
+    return opt && odr_ok(o);
+}
+
+int z_CostsOtherCharge(ODR o, Z_CostsOtherCharge **p, int opt,
+		       const char *name)
+{
+    if (!odr_sequence_begin(o, p, sizeof(**p), 0))
+    	return opt && odr_ok(o);
+    return
+        odr_implicit(o, z_HumanString, &(*p)->forWhat, ODR_CONTEXT, 1, 0) &&
+        odr_implicit(o, z_Charge, &(*p)->charge, ODR_CONTEXT, 2, 1) &&
+        odr_sequence_end(o);
+}
+
+int z_Costs(ODR o, Z_Costs **p, int opt, const char *name)
+{
+    if (!odr_sequence_begin(o, p, sizeof(**p), 0))
+        return opt && odr_ok(o);
+    return
+        odr_implicit(o, z_Charge, &(*p)->connectCharge, ODR_CONTEXT, 0, 1) &&
+        odr_implicit(o, z_Charge, &(*p)->connectTime, ODR_CONTEXT, 1, 1) &&
+        odr_implicit(o, z_Charge, &(*p)->displayCharge, ODR_CONTEXT, 2, 1) &&
+        odr_implicit(o, z_Charge, &(*p)->searchCharge, ODR_CONTEXT, 3, 1) &&
+        odr_implicit(o, z_Charge, &(*p)->subscriptCharge, ODR_CONTEXT, 4, 1) &&
+	odr_implicit_settag(o, ODR_CONTEXT, 5) &&
+	(odr_sequence_of(o, (Odr_fun)z_CostsOtherCharge, &(*p)->otherCharges,
+			 &(*p)->num_otherCharges, 0) || odr_ok(o)) &&
+        odr_sequence_end(o);
+}
+
+int z_Charge(ODR o, Z_Charge **p, int opt, const char *name)
+{
+    if (!odr_sequence_begin(o, p, sizeof(**p), 0))
+        return opt && odr_ok(o);
+    return
+        odr_implicit(o, z_IntUnit, &(*p)->cost, ODR_CONTEXT, 1, 0) &&
+        odr_implicit(o, z_Unit, &(*p)->perWhat, ODR_CONTEXT, 2, 1) &&
+        odr_implicit(o, z_HumanString, &(*p)->text, ODR_CONTEXT, 3, 1) &&
+        odr_sequence_end(o);
+}
+
+int z_DatabaseList(ODR o, Z_DatabaseList **p, int opt, const char *name)
+{
+    if (!odr_initmember(o, p, sizeof(**p)))
+	return opt && odr_ok(o);
+    if (odr_sequence_of(o, z_DatabaseName, &(*p)->databases,
+	&(*p)->num_databases, 0))
+	return 1;
+    *p = 0;
+    return opt && odr_ok(o);
+}
+
+int z_AttributeCombinations(ODR o, Z_AttributeCombinations **p, int opt,
+			    const char *name)
+{
+    if (!odr_sequence_begin(o, p, sizeof(**p), 0))
+        return opt && odr_ok(o);
+    return
+        odr_implicit(o, odr_oid, &(*p)->defaultAttributeSet,
+		     ODR_CONTEXT, 0, 0) &&
+	odr_implicit_settag(o, ODR_CONTEXT, 1) &&
+	odr_sequence_of(o, (Odr_fun)z_AttributeCombination,
+			&(*p)->legalCombinations,
+			&(*p)->num_legalCombinations, 0) &&
+        odr_sequence_end(o);
+}
+
+int z_AttributeCombination(ODR o, Z_AttributeCombination **p, int opt,
+			   const char *name)
+{
+    if (!odr_initmember(o, p, sizeof(**p)))
+	return opt && odr_ok(o);
+    if (odr_sequence_of(o, (Odr_fun)z_AttributeOccurrence, &(*p)->occurrences,
+			&(*p)->num_occurrences, 0))
+	return 1;
+    *p = 0;
+    return opt && odr_ok(o);
+}
+
+int z_AttributeValueList(ODR o, Z_AttributeValueList **p, int opt,
+			 const char *name)
+{
+    if (!odr_initmember(o, p, sizeof(**p)))
+	return opt && odr_ok(o);
+    if (odr_sequence_of(o, (Odr_fun)z_StringOrNumeric, &(*p)->attributes,
+			&(*p)->num_attributes, 0))
+	return 1;
+    *p = 0;
+    return opt && odr_ok(o);
+}
+
+int z_AttributeOccurrence(ODR o, Z_AttributeOccurrence **p, int opt,
+			  const char *name)
+{
+    static Odr_arm arm[] =
+    {
+    	{ODR_IMPLICIT, ODR_CONTEXT, 3, Z_AttributeOcc_any_or_none,
+	 (Odr_fun)odr_null, 0},
+	{ODR_IMPLICIT, ODR_CONTEXT, 4, Z_AttributeOcc_specific,
+	 (Odr_fun)z_AttributeValueList, 0},
+	{-1, -1, -1, -1, 0, 0}
+    };
+    
+    if (!odr_sequence_begin(o, p, sizeof(**p), 0))
+        return opt && odr_ok(o);
+    return
+        odr_implicit(o, odr_oid, &(*p)->attributeSet, ODR_CONTEXT, 0, 1) &&
+        odr_implicit(o, odr_integer, &(*p)->attributeType,
+		     ODR_CONTEXT, 1, 0) &&
+        odr_implicit(o, odr_null, &(*p)->mustBeSupplied, ODR_CONTEXT, 2, 1) &&
+	odr_choice(o, arm, &(*p)->attributeValues, &(*p)->which, 0) &&
+        odr_sequence_end(o);
+}
+
+int z_AttributeValue(ODR o, Z_AttributeValue **p, int opt, const char *name)
+{
+    if (!odr_sequence_begin(o, p, sizeof(**p), 0))
+        return opt && odr_ok(o);
+    return
+        odr_explicit(o, z_StringOrNumeric, &(*p)->value, ODR_CONTEXT, 0, 0) &&
+        odr_implicit(o, z_HumanString, &(*p)->description,
+		     ODR_CONTEXT, 1, 1) &&
+	odr_implicit_settag(o, ODR_CONTEXT, 2) &&
+	(odr_sequence_of(o, (Odr_fun)z_StringOrNumeric, &(*p)->subAttributes,
+			 &(*p)->num_subAttributes, 0) || odr_ok(o)) &&
+	odr_implicit_settag(o, ODR_CONTEXT, 3) &&
+	(odr_sequence_of(o, (Odr_fun)z_StringOrNumeric, &(*p)->superAttributes,
+			 &(*p)->num_superAttributes, 0) || odr_ok(o)) &&
+        odr_implicit(o, odr_null, &(*p)->partialSupport, ODR_CONTEXT, 4, 1) &&
+	odr_sequence_end(o);
+}
+
+
+
+int z_TargetInfo(ODR o, Z_TargetInfo **p, int opt, const char *name)
+{
+    if (!odr_sequence_begin(o, p, sizeof(**p), 0))
+        return opt && odr_ok(o);
+    return
+        odr_implicit(o, z_CommonInfo, &(*p)->commonInfo,
+		     ODR_CONTEXT, 0, 1) &&
+	odr_implicit(o, z_InternationalString, &(*p)->name,
+		     ODR_CONTEXT, 1, 0) &&
+        odr_implicit(o, z_HumanString, &(*p)->recentNews,
+		     ODR_CONTEXT, 2, 1) &&
+        odr_implicit(o, z_IconObject, &(*p)->icon,
+		     ODR_CONTEXT, 3, 1) &&
+        odr_implicit(o, odr_bool, &(*p)->namedResultSets,
+		     ODR_CONTEXT, 4, 0) &&
+        odr_implicit(o, odr_bool, &(*p)->multipleDBsearch,
+		     ODR_CONTEXT, 5, 0) &&
+        odr_implicit(o, odr_integer, &(*p)->maxResultSets,
+		     ODR_CONTEXT, 6, 1) &&
+        odr_implicit(o, odr_integer, &(*p)->maxResultSize,
+		     ODR_CONTEXT, 7, 1) &&
+        odr_implicit(o, odr_integer, &(*p)->maxTerms,
+		     ODR_CONTEXT, 8, 1) &&
+        odr_implicit(o, z_IntUnit, &(*p)->timeoutInterval,
+		     ODR_CONTEXT, 9, 1) &&
+        odr_implicit(o, z_HumanString, &(*p)->welcomeMessage,
+		     ODR_CONTEXT, 10, 1) &&
+        odr_implicit(o, z_ContactInfo, &(*p)->contactInfo,
+		     ODR_CONTEXT, 11, 1) &&
+        odr_implicit(o, z_HumanString, &(*p)->description,
+		     ODR_CONTEXT, 12, 1) &&
+	odr_implicit_settag(o, ODR_CONTEXT, 13) &&
+	(odr_sequence_of(o, z_InternationalString, &(*p)->nicknames,
+			 &(*p)->num_nicknames, 0) || odr_ok(o)) &&
+        odr_implicit(o, z_HumanString, &(*p)->usageRest,
+		     ODR_CONTEXT, 14, 1) &&
+        odr_implicit(o, z_HumanString, &(*p)->paymentAddr,
+		     ODR_CONTEXT, 15, 1) &&
+        odr_implicit(o, z_HumanString, &(*p)->hours, ODR_CONTEXT, 16, 1) &&
+	odr_implicit_settag(o, ODR_CONTEXT, 17) &&
+	(odr_sequence_of(o, (Odr_fun)z_DatabaseList, &(*p)->dbCombinations,
+			 &(*p)->num_dbCombinations, 0) || odr_ok(o)) &&
+	odr_implicit_settag(o, ODR_CONTEXT, 18) &&
+	(odr_sequence_of(o, (Odr_fun)z_NetworkAddress, &(*p)->addresses,
+			 &(*p)->num_addresses, 0) || odr_ok(o)) &&
+        odr_implicit_settag (o, ODR_CONTEXT, 101) &&
+        (odr_sequence_of(o, (Odr_fun) z_InternationalString, &(*p)->languages,
+			 &(*p)->num_languages, 0) || odr_ok(o)) &&
+        odr_implicit(o, z_AccessInfo, &(*p)->commonAccessInfo,
+		     ODR_CONTEXT, 19, 1) &&
+        odr_sequence_end(o);
+}
+
+int z_DatabaseInfo(ODR o, Z_DatabaseInfo **p, int opt, const char *name)
+{
+    static Odr_arm arm[] =
+    {
+    	{ODR_IMPLICIT, ODR_CONTEXT, 0, Z_DatabaseInfo_actualNumber,
+	 (Odr_fun)odr_integer, 0},
+	{ODR_IMPLICIT, ODR_CONTEXT, 1, Z_DatabaseInfo_approxNumber,
+	 (Odr_fun)odr_integer, 0},
+	{-1, -1, -1, -1, 0, 0}
+    };
+
+    if (!odr_sequence_begin(o, p, sizeof(**p), 0))
+        return opt && odr_ok(o);
+    return
+        odr_implicit(o, z_CommonInfo, &(*p)->commonInfo, ODR_CONTEXT, 0, 1) &&
+        odr_implicit(o, z_DatabaseName, &(*p)->name, ODR_CONTEXT, 1, 0) &&
+        odr_implicit(o, odr_null, &(*p)->explainDatabase, ODR_CONTEXT, 2, 1) &&
+	odr_implicit_settag(o, ODR_CONTEXT, 3) &&
+	(odr_sequence_of(o, z_DatabaseName, &(*p)->nicknames,
+	    &(*p)->num_nicknames, 0) || odr_ok(o)) &&
+        odr_implicit(o, z_IconObject, &(*p)->icon, ODR_CONTEXT, 4, 1) &&
+        odr_implicit(o, odr_bool, &(*p)->userFee, ODR_CONTEXT, 5, 0) &&
+        odr_implicit(o, odr_bool, &(*p)->available, ODR_CONTEXT, 6, 0) &&
+        odr_implicit(o, z_HumanString, &(*p)->titleString,
+		     ODR_CONTEXT, 7, 1) &&
+	odr_implicit_settag(o, ODR_CONTEXT, 8) &&
+	(odr_sequence_of(o, (Odr_fun)z_HumanString, &(*p)->keywords,
+			 &(*p)->num_keywords, 0) || odr_ok(o)) &&
+        odr_implicit(o, z_HumanString, &(*p)->description,
+		     ODR_CONTEXT, 9, 1) &&
+        odr_implicit(o, z_DatabaseList, &(*p)->associatedDbs,
+		     ODR_CONTEXT, 10, 1) &&
+        odr_implicit(o, z_DatabaseList, &(*p)->subDbs, ODR_CONTEXT, 11, 1) &&
+        odr_implicit(o, z_HumanString, &(*p)->disclaimers,
+		     ODR_CONTEXT, 12, 1) &&
+        odr_implicit(o, z_HumanString, &(*p)->news, ODR_CONTEXT, 13, 1) &&
+	((odr_constructed_begin(o, &(*p)->u.actualNumber,
+				ODR_CONTEXT, 14, 0) &&
+	  odr_choice(o, arm, &(*p)->u.actualNumber, &(*p)->which, 0) &&
+	  odr_constructed_end(o)) || odr_ok(o)) &&
+        odr_implicit(o, z_HumanString, &(*p)->defaultOrder,
+		     ODR_CONTEXT, 15, 1) &&
+        odr_implicit(o, odr_integer, &(*p)->avRecordSize,
+		     ODR_CONTEXT, 16, 1) &&
+        odr_implicit(o, odr_integer, &(*p)->maxRecordSize,
+		     ODR_CONTEXT, 17, 1) &&
+        odr_implicit(o, z_HumanString, &(*p)->hours, ODR_CONTEXT, 18, 1) &&
+        odr_implicit(o, z_HumanString, &(*p)->bestTime, ODR_CONTEXT, 19, 1) &&
+        odr_implicit(o, odr_generalizedtime, &(*p)->lastUpdate,
+		     ODR_CONTEXT, 20, 1) &&
+        odr_implicit(o, z_IntUnit, &(*p)->updateInterval,
+		     ODR_CONTEXT, 21, 1) &&
+        odr_implicit(o, z_HumanString, &(*p)->coverage, ODR_CONTEXT, 22, 1) &&
+        odr_implicit(o, odr_bool, &(*p)->proprietary, ODR_CONTEXT, 23, 1) &&
+        odr_implicit(o, z_HumanString, &(*p)->copyrightText,
+		     ODR_CONTEXT, 24, 1) &&
+        odr_implicit(o, z_HumanString, &(*p)->copyrightNotice,
+		     ODR_CONTEXT, 25, 1) &&
+        odr_implicit(o, z_ContactInfo, &(*p)->producerContactInfo,
+		     ODR_CONTEXT, 26, 1) &&
+        odr_implicit(o, z_ContactInfo, &(*p)->supplierContactInfo,
+		     ODR_CONTEXT, 27, 1) &&
+        odr_implicit(o, z_ContactInfo, &(*p)->submissionContactInfo,
+		     ODR_CONTEXT, 28, 1) &&
+        odr_implicit(o, z_AccessInfo, &(*p)->accessInfo, ODR_CONTEXT, 29, 1) &&
+        odr_sequence_end(o);
+}
+
+int z_TagTypeMapping(ODR o, Z_TagTypeMapping **p, int opt, const char *name)
+{
+    if (!odr_sequence_begin(o, p, sizeof(**p), 0))
+    	return opt;
+    return
+    	odr_implicit(o, odr_integer, &(*p)->tagType, ODR_CONTEXT, 0, 0) &&
+	odr_implicit(o, odr_oid, &(*p)->tagSet, ODR_CONTEXT, 1, 1) &&
+	odr_implicit(o, odr_null, &(*p)->defaultTagType, ODR_CONTEXT, 2, 1) &&
+	odr_sequence_end(o);
+}
+
+int z_SchemaInfo(ODR o, Z_SchemaInfo **p, int opt, const char *name)
+{
+    if (!odr_sequence_begin(o, p, sizeof(**p), 0))
+        return opt && odr_ok(o);
+    return
+        odr_implicit(o, z_CommonInfo, &(*p)->commonInfo, ODR_CONTEXT, 0, 1) &&
+        odr_implicit(o, odr_oid, &(*p)->schema, ODR_CONTEXT, 1, 0) &&
+        odr_implicit(o, z_InternationalString, &(*p)->name, ODR_CONTEXT,
+	    2, 0) &&
+        odr_implicit(o, z_HumanString, &(*p)->description,
+		     ODR_CONTEXT, 3, 1) &&
+	odr_implicit_settag(o, ODR_CONTEXT, 4) &&
+	(odr_sequence_of(o, (Odr_fun)z_TagTypeMapping, &(*p)->tagTypeMapping,
+			 &(*p)->num_tagTypeMapping, 0) || odr_ok(o)) &&
+	odr_implicit_settag(o, ODR_CONTEXT, 5) &&
+	(odr_sequence_of(o, (Odr_fun)z_ElementInfo, &(*p)->recordStructure,
+			 &(*p)->num_recordStructure, 0) || odr_ok(o)) &&
+        odr_sequence_end(o);
+}
+
+int z_ElementInfo(ODR o, Z_ElementInfo **p, int opt, const char *name)
+{
+    if (!odr_sequence_begin(o, p, sizeof(**p), 0))
+        return opt && odr_ok(o);
+    return
+        odr_implicit(o, z_InternationalString, &(*p)->elementName,
+		     ODR_CONTEXT, 1, 0) &&
+        odr_implicit(o, z_Path, &(*p)->elementTagPath, ODR_CONTEXT, 2, 0) &&
+        odr_explicit(o, z_ElementDataType, &(*p)->dataType,
+		     ODR_CONTEXT, 3, 1) &&
+        odr_implicit(o, odr_bool, &(*p)->required, ODR_CONTEXT, 4, 0) &&
+        odr_implicit(o, odr_bool, &(*p)->repeatable, ODR_CONTEXT, 5, 0) &&
+        odr_implicit(o, z_HumanString, &(*p)->description,
+		     ODR_CONTEXT, 6, 1) &&
+        odr_sequence_end(o);
+}
+
+int z_PathUnit(ODR o, Z_PathUnit **p, int opt, const char *name)
+{
+    if (!odr_sequence_begin(o, p, sizeof(**p), 0))
+    	return opt;
+    return
+    	odr_implicit(o, odr_integer, &(*p)->tagType, ODR_CONTEXT, 1, 0) &&
+	odr_explicit(o, z_StringOrNumeric, &(*p)->tagValue,
+		     ODR_CONTEXT, 2, 0) &&
+	odr_sequence_end(o);
+}
+
+int z_Path(ODR o, Z_Path **p, int opt, const char *name)
+{
+    if (!odr_initmember(o, p, sizeof(**p)))
+	return opt && odr_ok(o);
+    odr_implicit_settag(o, ODR_CONTEXT, 201);
+    if (odr_sequence_of(o, (Odr_fun)z_OtherInformationUnit, &(*p)->list,
+			&(*p)->num, 0))
+	return 1;
+    *p = 0;
+    return opt && odr_ok(o);
+}
+
+int z_ElementInfoList(ODR o, Z_Path **p, int opt, const char *name)
+{
+    if (!odr_initmember(o, p, sizeof(**p)))
+	return opt && odr_ok(o);
+    odr_implicit_settag(o, ODR_CONTEXT, 201);
+    if (odr_sequence_of(o, (Odr_fun)z_OtherInformationUnit, &(*p)->list,
+			&(*p)->num, 0))
+	return 1;
+    *p = 0;
+    return opt && odr_ok(o);
+}
+
+int z_ElementDataType(ODR o, Z_ElementDataType **p, int opt, const char *name)
+{
+    static Odr_arm arm[] =
+    {
+    	{ODR_IMPLICIT, ODR_CONTEXT, 0, Z_ElementDataType_primitive,
+	 (Odr_fun)odr_integer, 0},
+	{ODR_IMPLICIT, ODR_CONTEXT, 1, Z_ElementDataType_structured,
+	 (Odr_fun)z_ElementInfoList, 0},
+	{-1, -1, -1, -1, 0, 0}
+    };
+    
+    if (!odr_initmember(o, p, sizeof(**p)))
+	return opt && odr_ok(o);
+    if (odr_choice(o, arm, &(*p)->u, &(*p)->which, 0))
+    	return 1;
+    *p = 0;
+    return opt && odr_ok(o);
+}
+
+int z_TagSetInfoElements(ODR o, Z_TagSetInfoElements **p, int opt,
+			 const char *name)
+{
+    if (!odr_sequence_begin(o, p, sizeof(**p), 0))
+    	return opt;
+    return
+    	odr_implicit(o, z_InternationalString, &(*p)->elementname,
+		     ODR_CONTEXT, 1, 0) &&
+	odr_implicit_settag(o, ODR_CONTEXT, 2) &&
+	(odr_sequence_of(o, z_InternationalString, &(*p)->nicknames,
+			 &(*p)->num_nicknames, 0) || odr_ok(o)) &&
+	odr_explicit(o, z_StringOrNumeric, &(*p)->elementTag,
+		     ODR_CONTEXT, 3, 0) &&
+	odr_implicit(o, z_HumanString, &(*p)->description,
+		     ODR_CONTEXT, 4, 1) &&
+	odr_implicit(o, odr_integer, &(*p)->dataType, ODR_CONTEXT, 5, 1) &&
+	z_OtherInformation(o, &(*p)->otherTagInfo, 1, 0) &&
+   	odr_sequence_end(o);
+}
+
+int z_TagSetInfo(ODR o, Z_TagSetInfo **p, int opt, const char *name)
+{
+    if (!odr_sequence_begin(o, p, sizeof(**p), 0))
+        return opt && odr_ok(o);
+    return
+        odr_implicit(o, z_CommonInfo, &(*p)->commonInfo, ODR_CONTEXT, 0, 1) &&
+        odr_implicit(o, odr_oid, &(*p)->tagSet, ODR_CONTEXT, 1, 0) &&
+        odr_implicit(o, z_InternationalString, &(*p)->name,
+		     ODR_CONTEXT, 2, 0) &&
+        odr_implicit(o, z_HumanString, &(*p)->description,
+		     ODR_CONTEXT, 3, 1) &&
+	odr_implicit_settag(o, ODR_CONTEXT, 4) &&
+	(odr_sequence_of(o, (Odr_fun)z_TagSetInfoElements, &(*p)->elements,
+			 &(*p)->num_elements, 0) || odr_ok(o)) &&
+        odr_sequence_end(o);
+}
+
+int z_RecordSyntaxInfo(ODR o, Z_RecordSyntaxInfo **p, int opt,
+		       const char *name)
+{
+    if (!odr_sequence_begin(o, p, sizeof(**p), 0))
+        return opt && odr_ok(o);
+    return
+        odr_implicit(o, z_CommonInfo, &(*p)->commonInfo, ODR_CONTEXT, 0, 1) &&
+        odr_implicit(o, odr_oid, &(*p)->recordSyntax, ODR_CONTEXT, 1, 0) &&
+        odr_implicit(o, z_InternationalString, &(*p)->name,
+		     ODR_CONTEXT, 2, 0) &&
+	odr_implicit_settag(o, ODR_CONTEXT, 3) &&
+	(odr_sequence_of(o, (Odr_fun)odr_oid, &(*p)->transferSyntaxes,
+			 &(*p)->num_transferSyntaxes, 0) || odr_ok(o)) &&
+        odr_implicit(o, z_HumanString, &(*p)->description,
+		     ODR_CONTEXT, 4, 1) &&
+        odr_implicit(o, z_InternationalString, &(*p)->asn1Module,
+		     ODR_CONTEXT, 5, 1) &&
+	odr_implicit_settag(o, ODR_CONTEXT, 6) &&
+	(odr_sequence_of(o, (Odr_fun)z_ElementInfo, &(*p)->abstractStructure,
+	    &(*p)->num_abstractStructure, 0) || odr_ok(o)) &&
+        odr_sequence_end(o);
+}
+
+int z_AttributeSetInfo(ODR o, Z_AttributeSetInfo **p, int opt,
+		       const char *name)
+{
+    if (!odr_sequence_begin(o, p, sizeof(**p), 0))
+        return opt && odr_ok(o);
+    return
+        odr_implicit(o, z_CommonInfo, &(*p)->commonInfo, ODR_CONTEXT, 0, 1) &&
+        odr_implicit(o, odr_oid, &(*p)->attributeSet, ODR_CONTEXT, 1, 0) &&
+        odr_implicit(o, z_InternationalString, &(*p)->name,
+		     ODR_CONTEXT, 2, 0) &&
+	odr_implicit_settag(o, ODR_CONTEXT, 3) &&
+	(odr_sequence_of(o, (Odr_fun)z_AttributeType, &(*p)->attributes,
+			 &(*p)->num_attributes, 0) || odr_ok(o)) &&
+        odr_implicit(o, z_HumanString, &(*p)->description,
+		     ODR_CONTEXT, 4, 1) &&
+        odr_sequence_end(o);
+}
+
+int z_AttributeType(ODR o, Z_AttributeType **p, int opt, const char *name)
+{
+    if (!odr_sequence_begin(o, p, sizeof(**p), 0))
+        return opt && odr_ok(o);
+    return
+        odr_implicit(o, z_InternationalString, &(*p)->name,
+		     ODR_CONTEXT, 0, 1) &&
+        odr_implicit(o, z_HumanString, &(*p)->description,
+		     ODR_CONTEXT, 1, 1) &&
+        odr_implicit(o, odr_integer, &(*p)->attributeType,
+		     ODR_CONTEXT, 2, 0) &&
+	odr_implicit_settag(o, ODR_CONTEXT, 3) &&
+	odr_sequence_of(o, (Odr_fun)z_AttributeDescription,
+			&(*p)->attributeValues,
+			&(*p)->num_attributeValues, 0) &&
+        odr_sequence_end(o);
+}
+
+int z_AttributeDescription(ODR o, Z_AttributeDescription **p, int opt,
+			   const char *name)
+{
+    if (!odr_sequence_begin(o, p, sizeof(**p), 0))
+        return opt && odr_ok(o);
+    return
+        odr_implicit(o, z_InternationalString, &(*p)->name,
+		     ODR_CONTEXT, 0, 1) &&
+        odr_implicit(o, z_HumanString, &(*p)->description,
+		     ODR_CONTEXT, 1, 1) &&
+        odr_explicit(o, z_StringOrNumeric, &(*p)->attributeValue,
+		     ODR_CONTEXT, 2, 0) &&
+	odr_implicit_settag(o, ODR_CONTEXT, 3) &&
+	(odr_sequence_of(o, (Odr_fun)z_StringOrNumeric,
+			 &(*p)->equivalentAttributes,
+			 &(*p)->num_equivalentAttributes, 0) || odr_ok(o)) &&
+        odr_sequence_end(o);
+}
+
+int z_TermListElement(ODR o, Z_TermListElement **p, int opt, const char *name)
+{
+    if (!odr_sequence_begin(o, p, sizeof(**p), 0))
+    	return opt && odr_ok(o);
+    return
+        odr_implicit(o, z_InternationalString, &(*p)->name,
+		     ODR_CONTEXT, 1, 0) &&
+        odr_implicit(o, z_HumanString, &(*p)->title, ODR_CONTEXT, 2, 1) &&
+        odr_implicit(o, odr_integer, &(*p)->searchCost, ODR_CONTEXT, 3, 1) &&
+        odr_implicit(o, odr_bool, &(*p)->scanable, ODR_CONTEXT, 4, 0) &&
+	odr_implicit_settag(o, ODR_CONTEXT, 5) &&
+	(odr_sequence_of(o, z_InternationalString, &(*p)->broader,
+			 &(*p)->num_broader, 0) || odr_ok(o)) &&
+	odr_implicit_settag(o, ODR_CONTEXT, 6) &&
+	(odr_sequence_of(o, z_InternationalString, &(*p)->narrower,
+			 &(*p)->num_narrower, 0) || odr_ok(o)) &&
+	odr_sequence_end(o);
+}
+
+int z_TermListInfo(ODR o, Z_TermListInfo **p, int opt, const char *name)
+{
+    if (!odr_sequence_begin(o, p, sizeof(**p), 0))
+        return opt && odr_ok(o);
+    return
+        odr_implicit(o, z_CommonInfo, &(*p)->commonInfo, ODR_CONTEXT, 0, 1) &&
+        odr_implicit(o, z_DatabaseName, &(*p)->databaseName,
+		     ODR_CONTEXT, 1, 0) &&
+ 	odr_implicit_settag(o, ODR_CONTEXT, 2) &&
+	(odr_sequence_of(o, (Odr_fun)z_TermListElement, &(*p)->termLists,
+			 &(*p)->num_termLists, 0) || odr_ok(o)) &&
+        odr_sequence_end(o);
+}
+
+int z_ExtendedServicesInfo(ODR o, Z_ExtendedServicesInfo **p, int opt,
+			   const char *name)
+{
+    if (!odr_sequence_begin(o, p, sizeof(**p), 0))
+        return opt && odr_ok(o);
+    return
+        odr_implicit(o, z_CommonInfo, &(*p)->commonInfo, ODR_CONTEXT, 0, 1) &&
+        odr_implicit(o, odr_oid, &(*p)->type, ODR_CONTEXT, 1, 0) &&
+        odr_implicit(o, z_InternationalString, &(*p)->name,
+		     ODR_CONTEXT, 2, 1) &&
+        odr_implicit(o, odr_bool, &(*p)->privateType, ODR_CONTEXT, 3, 0) &&
+        odr_implicit(o, odr_bool, &(*p)->restrictionsApply,
+		     ODR_CONTEXT, 5, 0) &&
+        odr_implicit(o, odr_bool, &(*p)->feeApply, ODR_CONTEXT, 6, 0) &&
+        odr_implicit(o, odr_bool, &(*p)->available, ODR_CONTEXT, 7, 0) &&
+        odr_implicit(o, odr_bool, &(*p)->retentionSupported,
+		     ODR_CONTEXT, 8, 0) &&
+        odr_implicit(o, odr_integer, &(*p)->waitAction, ODR_CONTEXT, 9, 0) &&
+        odr_implicit(o, z_HumanString, &(*p)->description,
+		     ODR_CONTEXT, 10, 1) &&
+        odr_implicit(o, z_External, &(*p)->specificExplain,
+		     ODR_CONTEXT, 11, 1) &&
+        odr_implicit(o, z_InternationalString, &(*p)->esASN,
+		     ODR_CONTEXT, 12, 1) &&
+        odr_sequence_end(o);
+}
+
+int z_AttributeDetails(ODR o, Z_AttributeDetails **p, int opt,
+		       const char *name)
+{
+    if (!odr_sequence_begin(o, p, sizeof(**p), 0))
+        return opt && odr_ok(o);
+    return
+        odr_implicit(o, z_CommonInfo, &(*p)->commonInfo, ODR_CONTEXT, 0, 1) &&
+        odr_implicit(o, z_DatabaseName, &(*p)->databaseName,
+		     ODR_CONTEXT, 1, 0) &&
+	odr_implicit_settag(o, ODR_CONTEXT, 2) &&
+	(odr_sequence_of(o, (Odr_fun)z_AttributeSetDetails,
+			 &(*p)->attributesBySet,
+			 &(*p)->num_attributesBySet, 0) && odr_ok(o)) &&
+        odr_implicit(o, z_AttributeCombinations, &(*p)->attributeCombinations,
+		     ODR_CONTEXT, 3, 1) &&
+        odr_sequence_end(o);
+}
+
+int z_AttributeSetDetails(ODR o, Z_AttributeSetDetails **p, int opt,
+			  const char *name)
+{
+    if (!odr_sequence_begin(o, p, sizeof(**p), 0))
+        return opt && odr_ok(o);
+    return
+        odr_implicit(o, odr_oid, &(*p)->attributeSet,
+		     ODR_CONTEXT, 0, 0) &&
+	odr_implicit_settag(o, ODR_CONTEXT, 1) &&
+	odr_sequence_of(o, (Odr_fun)z_AttributeTypeDetails,
+			&(*p)->attributesByType,
+			&(*p)->num_attributesByType, 0) &&
+        odr_sequence_end(o);
+}
+
+int z_AttributeTypeDetails(ODR o, Z_AttributeTypeDetails **p, int opt,
+			   const char *name)
+{
+    if (!odr_sequence_begin(o, p, sizeof(**p), 0))
+        return opt && odr_ok(o);
+    return
+        odr_implicit(o, odr_integer, &(*p)->attributeType,
+		     ODR_CONTEXT, 0, 0) &&
+        odr_implicit(o, z_OmittedAttributeInterpretation,
+		     &(*p)->defaultIfOmitted,
+		     ODR_CONTEXT, 1, 1) &&
+	odr_implicit_settag(o, ODR_CONTEXT, 2) &&
+	(odr_sequence_of(o, (Odr_fun)z_AttributeValue, &(*p)->attributeValues,
+			 &(*p)->num_attributeValues, 0) || odr_ok(o)) &&
+        odr_sequence_end(o);
+}
+
+int z_OmittedAttributeInterpretation(ODR o,
+				     Z_OmittedAttributeInterpretation **p,
+				     int opt, const char *name)
+{
+    if (!odr_sequence_begin(o, p, sizeof(**p), 0))
+        return opt && odr_ok(o);
+    return
+        odr_explicit(o, z_StringOrNumeric, &(*p)->defaultValue,
+		     ODR_CONTEXT, 0, 1) &&
+        odr_implicit(o, z_HumanString, &(*p)->defaultDescription,
+		     ODR_CONTEXT, 1, 1) &&
+        odr_sequence_end(o);
+}
+
+int z_EScanInfo(ODR o, Z_EScanInfo **p, int opt, const char *name)
+{
+    if (!odr_sequence_begin(o, p, sizeof(**p), 0))
+        return opt && odr_ok(o);
+    return
+        odr_implicit(o, odr_integer, &(*p)->maxStepSize, ODR_CONTEXT, 0, 1) &&
+        odr_implicit(o, z_HumanString, &(*p)->collatingSequence,
+		     ODR_CONTEXT, 1, 1) &&
+        odr_implicit(o, odr_bool, &(*p)->increasing, ODR_CONTEXT, 2, 1) &&
+	odr_sequence_end(o);
+}
+
+int z_TermListDetails(ODR o, Z_TermListDetails **p, int opt, const char *name)
+{
+    if (!odr_sequence_begin(o, p, sizeof(**p), 0))
+        return opt && odr_ok(o);
+    return
+        odr_implicit(o, z_CommonInfo, &(*p)->commonInfo, ODR_CONTEXT, 0, 1) &&
+        odr_implicit(o, z_InternationalString, &(*p)->termListName,
+		     ODR_CONTEXT, 1, 0) &&
+        odr_implicit(o, z_HumanString, &(*p)->description,
+		     ODR_CONTEXT, 2, 1) &&
+        odr_implicit(o, z_AttributeCombinations, &(*p)->attributes,
+		     ODR_CONTEXT, 3, 1) &&
+	odr_implicit(o, z_EScanInfo, &(*p)->scanInfo, ODR_CONTEXT, 4, 1) &&
+        odr_implicit(o, odr_integer, &(*p)->estNumberTerms,
+		     ODR_CONTEXT, 5, 1) &&
+	odr_implicit_settag(o, ODR_CONTEXT, 6) &&
+	(odr_sequence_of(o, (Odr_fun)z_Term, &(*p)->sampleTerms,
+	    &(*p)->num_sampleTerms, 0) || odr_ok(o)) &&
+        odr_sequence_end(o);
+}
+
+int z_ElementSetDetails(ODR o, Z_ElementSetDetails **p, int opt,
+			const char *name)
+{
+    if (!odr_sequence_begin(o, p, sizeof(**p), 0))
+        return opt && odr_ok(o);
+    return
+        odr_implicit(o, z_CommonInfo, &(*p)->commonInfo, ODR_CONTEXT, 0, 1) &&
+        odr_implicit(o, z_DatabaseName, &(*p)->databaseName,
+		     ODR_CONTEXT, 1, 0) &&
+        odr_implicit(o, z_ElementSetName, &(*p)->elementSetName,
+		     ODR_CONTEXT, 2, 0) &&
+        odr_implicit(o, odr_oid, &(*p)->recordSyntax, ODR_CONTEXT, 3, 0) &&
+        odr_implicit(o, odr_oid, &(*p)->schema, ODR_CONTEXT, 4, 0) &&
+        odr_implicit(o, z_HumanString, &(*p)->description,
+		     ODR_CONTEXT, 5, 1) &&
+	odr_implicit_settag(o, ODR_CONTEXT, 6) &&
+	(odr_sequence_of(o, (Odr_fun)z_PerElementDetails,
+			 &(*p)->detailsPerElement,
+			 &(*p)->num_detailsPerElement, 0) || odr_ok(o)) &&
+        odr_sequence_end(o);
+}
+
+int z_RetrievalRecordDetails(ODR o, Z_RetrievalRecordDetails **p, int opt,
+			     const char *name)
+{
+    if (!odr_sequence_begin(o, p, sizeof(**p), 0))
+        return opt && odr_ok(o);
+    return
+        odr_implicit(o, z_CommonInfo, &(*p)->commonInfo, ODR_CONTEXT, 0, 1) &&
+        odr_implicit(o, z_DatabaseName, &(*p)->databaseName,
+		     ODR_CONTEXT, 1, 0) &&
+        odr_implicit(o, odr_oid, &(*p)->schema, ODR_CONTEXT, 2, 0) &&
+        odr_implicit(o, odr_oid, &(*p)->recordSyntax, ODR_CONTEXT, 3, 0) &&
+        odr_implicit(o, z_HumanString, &(*p)->description,
+		     ODR_CONTEXT, 4, 1) &&
+	odr_implicit_settag(o, ODR_CONTEXT, 5) &&
+	(odr_sequence_of(o, (Odr_fun)z_PerElementDetails,
+			 &(*p)->detailsPerElement,
+			 &(*p)->num_detailsPerElement, 0) || odr_ok(o)) &&
+        odr_sequence_end(o);
+}
+
+int z_PerElementDetails(ODR o, Z_PerElementDetails **p, int opt,
+			const char *name)
+{
+    if (!odr_sequence_begin(o, p, sizeof(**p), 0))
+        return opt && odr_ok(o);
+    return
+        odr_implicit(o, z_InternationalString, &(*p)->name,
+		     ODR_CONTEXT, 0, 1) &&
+        odr_implicit(o, z_RecordTag, &(*p)->recordTag, ODR_CONTEXT, 1, 1) &&
+	odr_implicit_settag(o, ODR_CONTEXT, 2) &&
+	(odr_sequence_of(o, (Odr_fun)z_Path, &(*p)->schemaTags,
+			 &(*p)->num_schemaTags, 0) ||
+	 odr_ok(o)) &&
+        odr_implicit(o, odr_integer, &(*p)->maxSize, ODR_CONTEXT, 3, 1) &&
+        odr_implicit(o, odr_integer, &(*p)->minSize, ODR_CONTEXT, 4, 1) &&
+        odr_implicit(o, odr_integer, &(*p)->avgSize, ODR_CONTEXT, 5, 1) &&
+        odr_implicit(o, odr_integer, &(*p)->fixedSize, ODR_CONTEXT, 6, 1) &&
+        odr_implicit(o, odr_bool, &(*p)->repeatable, ODR_CONTEXT, 8, 0) &&
+        odr_implicit(o, odr_bool, &(*p)->required, ODR_CONTEXT, 9, 0) &&
+        odr_implicit(o, z_HumanString, &(*p)->description,
+		     ODR_CONTEXT, 12, 1) &&
+        odr_implicit(o, z_HumanString, &(*p)->contents, ODR_CONTEXT, 13, 1) &&
+        odr_implicit(o, z_HumanString, &(*p)->billingInfo,
+		     ODR_CONTEXT, 14, 1) &&
+        odr_implicit(o, z_HumanString, &(*p)->restrictions,
+		     ODR_CONTEXT, 15, 1) &&
+	odr_implicit_settag(o, ODR_CONTEXT, 16) &&
+	(odr_sequence_of(o, z_InternationalString, &(*p)->alternateNames,
+			 &(*p)->num_alternateNames, 0) || odr_ok(o)) &&
+	odr_implicit_settag(o, ODR_CONTEXT, 17) &&
+	(odr_sequence_of(o, z_InternationalString, &(*p)->genericNames,
+			 &(*p)->num_genericNames, 0) || odr_ok(o)) &&
+        odr_implicit(o, z_AttributeCombinations, &(*p)->searchAccess,
+		     ODR_CONTEXT, 18, 1) &&
+        odr_sequence_end(o);
+}
+
+int z_RecordTag(ODR o, Z_RecordTag **p, int opt, const char *name)
+{
+    if (!odr_sequence_begin(o, p, sizeof(**p), 0))
+        return opt && odr_ok(o);
+    return
+        odr_explicit(o, z_StringOrNumeric, &(*p)->qualifier,
+		     ODR_CONTEXT, 0, 1) &&
+        odr_explicit(o, z_StringOrNumeric, &(*p)->tagValue,
+		     ODR_CONTEXT, 1, 0) &&
+        odr_sequence_end(o);
+}
+
+int z_SortDetails(ODR o, Z_SortDetails **p, int opt, const char *name)
+{
+    if (!odr_sequence_begin(o, p, sizeof(**p), 0))
+        return opt && odr_ok(o);
+    return
+        odr_implicit(o, z_CommonInfo, &(*p)->commonInfo, ODR_CONTEXT, 0, 1) &&
+        odr_implicit(o, z_DatabaseName, &(*p)->databaseName,
+		     ODR_CONTEXT, 1, 0) &&
+	odr_implicit_settag(o, ODR_CONTEXT, 2) &&
+	(odr_sequence_of(o, (Odr_fun)z_SortKeyDetails, &(*p)->sortKeys,
+			 &(*p)->num_sortKeys, 0) || odr_ok(o)) &&
+        odr_sequence_end(o);
+}
+
+int z_SortKeyDetails (ODR o, Z_SortKeyDetails **p, int opt, const char *name)
+{
+    static Odr_arm arm[] = {
+	{ODR_IMPLICIT, ODR_CONTEXT, 0, Z_SortKeyDetails_character,
+	 (Odr_fun) odr_null, 0},
+	{ODR_IMPLICIT, ODR_CONTEXT, 1, Z_SortKeyDetails_numeric,
+	 (Odr_fun) odr_null, 0},
+	{ODR_IMPLICIT, ODR_CONTEXT, 2, Z_SortKeyDetails_structured,
+	 (Odr_fun) z_HumanString, 0},
+	{-1, -1, -1, -1, (Odr_fun) 0, 0}
+    };
+    if (!odr_sequence_begin (o, p, sizeof(**p), 0))
+	return opt && odr_ok (o);
+    return
+	odr_implicit (o, z_HumanString,
+		      &(*p)->description, ODR_CONTEXT, 0, 1) &&
+	odr_implicit_settag (o, ODR_CONTEXT, 1) &&
+	(odr_sequence_of(o, (Odr_fun) z_Specification,
+			 &(*p)->elementSpecifications,
+			 &(*p)->num_elementSpecifications, 0) || odr_ok(o)) &&
+	odr_implicit (o, z_AttributeCombinations,
+		      &(*p)->attributeSpecifications, ODR_CONTEXT, 2, 1) &&
+	((odr_constructed_begin (o, &(*p)->u, ODR_CONTEXT, 3, 0) &&
+	  odr_choice (o, arm, &(*p)->u, &(*p)->which, 0) &&
+	  odr_constructed_end (o)) || odr_ok(o)) &&
+	odr_implicit (o, odr_integer,
+		      &(*p)->caseSensitivity, ODR_CONTEXT, 4, 1) &&
+	odr_sequence_end (o);
+}
+
+int z_ProcessingInformation(ODR o, Z_ProcessingInformation **p, int opt,
+			    const char *name)
+{
+    if (!odr_sequence_begin(o, p, sizeof(**p), 0))
+        return opt && odr_ok(o);
+    return
+        odr_implicit(o, z_CommonInfo, &(*p)->commonInfo, ODR_CONTEXT, 0, 1) &&
+        odr_implicit(o, z_DatabaseName, &(*p)->databaseName,
+		     ODR_CONTEXT, 1, 0) &&
+        odr_implicit(o, odr_integer, &(*p)->processingContext,
+		     ODR_CONTEXT, 2, 0) &&
+        odr_implicit(o, z_InternationalString, &(*p)->name,
+		     ODR_CONTEXT, 3, 0) &&
+        odr_implicit(o, odr_oid, &(*p)->oid, ODR_CONTEXT, 4, 0) &&
+        odr_implicit(o, z_HumanString, &(*p)->description,
+		     ODR_CONTEXT, 5, 1) &&
+        odr_implicit(o, z_External, &(*p)->instructions, ODR_CONTEXT, 6, 1) &&
+        odr_sequence_end(o);
+}
+
+int z_VariantSetInfo(ODR o, Z_VariantSetInfo **p, int opt, const char *name)
+{
+    if (!odr_sequence_begin(o, p, sizeof(**p), 0))
+        return opt && odr_ok(o);
+    return
+        odr_implicit(o, z_CommonInfo, &(*p)->commonInfo, ODR_CONTEXT, 0, 1) &&
+        odr_implicit(o, odr_oid, &(*p)->variantSet, ODR_CONTEXT, 1, 0) &&
+        odr_implicit(o, z_InternationalString, &(*p)->name,
+		     ODR_CONTEXT, 2, 0) &&
+	odr_implicit_settag(o, ODR_CONTEXT, 3) &&
+	(odr_sequence_of(o, (Odr_fun)z_VariantClass, &(*p)->variants,
+			 &(*p)->num_variants, 0) || odr_ok(o)) &&
+        odr_sequence_end(o);
+}
+
+int z_VariantClass(ODR o, Z_VariantClass **p, int opt, const char *name)
+{
+    if (!odr_sequence_begin(o, p, sizeof(**p), 0))
+        return opt && odr_ok(o);
+    return
+        odr_implicit(o, z_InternationalString, &(*p)->name,
+		     ODR_CONTEXT, 0, 1) &&
+        odr_implicit(o, z_HumanString, &(*p)->description,
+		     ODR_CONTEXT, 1, 1) &&
+        odr_implicit(o, odr_integer, &(*p)->variantClass, ODR_CONTEXT, 2, 0) &&
+	odr_implicit_settag(o, ODR_CONTEXT, 3) &&
+	odr_sequence_of(o, (Odr_fun)z_VariantType, &(*p)->variantTypes,
+			&(*p)->num_variantTypes, 0) &&
+        odr_sequence_end(o);
+}
+
+int z_VariantType(ODR o, Z_VariantType **p, int opt, const char *name)
+{
+    if (!odr_sequence_begin(o, p, sizeof(**p), 0))
+        return opt && odr_ok(o);
+    return
+        odr_implicit(o, z_InternationalString, &(*p)->name,
+		     ODR_CONTEXT, 0, 1) &&
+        odr_implicit(o, z_HumanString, &(*p)->description,
+		     ODR_CONTEXT, 1, 1) &&
+        odr_implicit(o, odr_integer, &(*p)->variantType,
+		     ODR_CONTEXT, 2, 0) &&
+        odr_implicit(o, z_VariantValue, &(*p)->variantValue,
+		     ODR_CONTEXT, 3, 1) &&
+        odr_sequence_end(o);
+}
+
+int z_VariantValue(ODR o, Z_VariantValue **p, int opt, const char *name)
+{
+    if (!odr_sequence_begin(o, p, sizeof(**p), 0))
+        return opt && odr_ok(o);
+    return
+        odr_explicit(o, odr_integer, &(*p)->dataType, ODR_CONTEXT, 0, 0) &&
+        odr_explicit(o, z_ValueSet, &(*p)->values, ODR_CONTEXT, 1, 1) &&
+	odr_sequence_end(o);
+}
+
+int z_ValueSetEnumerated(ODR o, Z_ValueSetEnumerated **p, int opt,
+			 const char *name)
+{
+    if (!odr_initmember(o, p, sizeof(**p)))
+	return opt && odr_ok(o);
+    if (odr_sequence_of(o, (Odr_fun)z_ValueDescription, &(*p)->elements,
+			&(*p)->num, 0))
+	return 1;
+    *p = 0;
+    return opt && odr_ok(o);
+}
+    
+int z_ValueSet(ODR o, Z_ValueSet **p, int opt, const char *name)
+{
+    static Odr_arm arm[] =
+    {
+    	{ODR_IMPLICIT, ODR_CONTEXT, 0, Z_ValueSet_range,
+	 (Odr_fun)z_ValueRange, 0},
+	{ODR_IMPLICIT, ODR_CONTEXT, 1, Z_ValueSet_enumerated,
+	 (Odr_fun)z_ValueSetEnumerated, 0},
+	{-1, -1, -1, -1, 0, 0}
+    };
+    
+    if (!odr_initmember(o, p, sizeof(**p)))
+	return opt && odr_ok(o);
+    if (odr_choice(o, arm, &(*p)->u, &(*p)->which, 0))
+    	return 1;
+    *p = 0;
+    return opt && odr_ok(o);
+}
+
+int z_ValueRange(ODR o, Z_ValueRange **p, int opt, const char *name)
+{
+    if (!odr_sequence_begin(o, p, sizeof(**p), 0))
+        return opt && odr_ok(o);
+    return
+        odr_explicit(o, z_ValueDescription, &(*p)->lower, ODR_CONTEXT, 0, 1) &&
+        odr_explicit(o, z_ValueDescription, &(*p)->upper, ODR_CONTEXT, 1, 1) &&
+	odr_sequence_end(o);
+}
+
+int z_ValueDescription(ODR o, Z_ValueDescription **p, int opt,
+		       const char *name)
+{
+    static Odr_arm arm[] =
+    {
+    	{ODR_NONE, -1, -1, Z_ValueDescription_integer,
+	 (Odr_fun)odr_integer, 0},
+	{ODR_NONE, -1, -1, Z_ValueDescription_string,
+	 (Odr_fun)z_InternationalString, 0},
+	{ODR_NONE, -1, -1, Z_ValueDescription_octets,
+	 (Odr_fun)odr_octetstring, 0},
+	{ODR_NONE, -1, -1, Z_ValueDescription_oid,
+	 (Odr_fun)odr_oid, 0},
+	{ODR_IMPLICIT, ODR_CONTEXT, 1, Z_ValueDescription_unit,
+	 (Odr_fun)z_Unit, 0},
+	{ODR_IMPLICIT, ODR_CONTEXT, 2, Z_ValueDescription_valueAndUnit,
+	 (Odr_fun)z_IntUnit, 0},
+	{-1, -1, -1, -1, 0, 0}
+    };
+    
+    if (!odr_initmember(o, p, sizeof(**p)))
+	return opt && odr_ok(o);
+    if (odr_choice(o, arm, &(*p)->u, &(*p)->which, 0))
+    	return 1;
+    *p = 0;
+    return opt && odr_ok(o);
+}
+
+int z_UnitInfo(ODR o, Z_UnitInfo **p, int opt, const char *name)
+{
+    if (!odr_sequence_begin(o, p, sizeof(**p), 0))
+        return opt && odr_ok(o);
+    return
+        odr_implicit(o, z_CommonInfo, &(*p)->commonInfo, ODR_CONTEXT, 0, 1) &&
+        odr_implicit(o, z_InternationalString, &(*p)->unitSystem,
+		     ODR_CONTEXT, 1, 0) &&
+        odr_implicit(o, z_HumanString, &(*p)->description,
+		     ODR_CONTEXT, 2, 1) &&
+	odr_implicit_settag(o, ODR_CONTEXT, 3) &&
+	(odr_sequence_of(o,  (Odr_fun)z_UnitType, &(*p)->units, 
+			 &(*p)->num_units, 0) ||
+	 odr_ok(o)) &&
+        odr_sequence_end(o);
+}
+
+int z_UnitType(ODR o, Z_UnitType **p, int opt, const char *name)
+{
+    if (!odr_sequence_begin(o, p, sizeof(**p), 0))
+        return opt && odr_ok(o);
+    return
+        odr_implicit(o, z_InternationalString, &(*p)->name,
+		     ODR_CONTEXT, 0, 1) &&
+        odr_implicit(o, z_HumanString, &(*p)->description,
+		     ODR_CONTEXT, 1, 1) &&
+        odr_explicit(o, z_StringOrNumeric, &(*p)->unitType,
+		     ODR_CONTEXT, 2, 0) &&
+	odr_implicit_settag(o, ODR_CONTEXT, 3) &&
+	odr_sequence_of(o, (Odr_fun)z_Units, &(*p)->units,
+			&(*p)->num_units, 0) &&
+        odr_sequence_end(o);
+}
+
+int z_Units(ODR o, Z_Units **p, int opt, const char *name)
+{
+    if (!odr_sequence_begin(o, p, sizeof(**p), 0))
+        return opt && odr_ok(o);
+    return
+        odr_implicit(o, z_InternationalString, &(*p)->name,
+		     ODR_CONTEXT, 0, 1) &&
+        odr_implicit(o, z_HumanString, &(*p)->description,
+		     ODR_CONTEXT, 1, 1) &&
+        odr_explicit(o, z_StringOrNumeric, &(*p)->unit,
+		     ODR_CONTEXT, 2, 0) &&
+        odr_sequence_end(o);
+}
+
+int z_CategoryList(ODR o, Z_CategoryList **p, int opt, const char *name)
+{
+    if (!odr_sequence_begin(o, p, sizeof(**p), 0))
+        return opt && odr_ok(o);
+    return
+        odr_implicit(o, z_CommonInfo, &(*p)->commonInfo, ODR_CONTEXT, 0, 1) &&
+	odr_implicit_settag(o, ODR_CONTEXT, 1) &&
+	odr_sequence_of(o, (Odr_fun)z_CategoryInfo, &(*p)->categories,
+			&(*p)->num_categories, 0) &&
+        odr_sequence_end(o);
+}
+
+int z_CategoryInfo(ODR o, Z_CategoryInfo **p, int opt, const char *name)
+{
+    if (!odr_sequence_begin(o, p, sizeof(**p), 0))
+        return opt && odr_ok(o);
+    return
+        odr_implicit(o, z_InternationalString, &(*p)->category,
+		     ODR_CONTEXT, 1, 0) &&
+        odr_implicit(o, z_InternationalString, &(*p)->originalCategory,
+		     ODR_CONTEXT, 2, 1) &&
+        odr_implicit(o, z_HumanString, &(*p)->description,
+		     ODR_CONTEXT, 3, 1) &&
+        odr_implicit(o, z_InternationalString, &(*p)->asn1Module,
+		     ODR_CONTEXT, 4, 1) &&
+        odr_sequence_end(o);
+}
+
+int z_ExplainRecord(ODR o, Z_ExplainRecord **p, int opt, const char *name)
+{
+    static Odr_arm arm[] =
+    {
+    	{ODR_IMPLICIT, ODR_CONTEXT, 0, Z_Explain_targetInfo,
+	 (Odr_fun)z_TargetInfo, 0},
+	{ODR_IMPLICIT, ODR_CONTEXT, 1, Z_Explain_databaseInfo,
+	 (Odr_fun)z_DatabaseInfo, 0},
+	{ODR_IMPLICIT, ODR_CONTEXT, 2, Z_Explain_schemaInfo,
+	 (Odr_fun)z_SchemaInfo, 0},
+	{ODR_IMPLICIT, ODR_CONTEXT, 3, Z_Explain_tagSetInfo,
+	 (Odr_fun)z_TagSetInfo, 0},
+	{ODR_IMPLICIT, ODR_CONTEXT, 4, Z_Explain_recordSyntaxInfo,
+	 (Odr_fun)z_RecordSyntaxInfo, 0},
+	{ODR_IMPLICIT, ODR_CONTEXT, 5, Z_Explain_attributeSetInfo,
+	 (Odr_fun)z_AttributeSetInfo, 0},
+	{ODR_IMPLICIT, ODR_CONTEXT, 6, Z_Explain_termListInfo,
+	 (Odr_fun)z_TermListInfo, 0},
+	{ODR_IMPLICIT, ODR_CONTEXT, 7, Z_Explain_extendedServicesInfo,
+	 (Odr_fun)z_ExtendedServicesInfo, 0},
+	{ODR_IMPLICIT, ODR_CONTEXT, 8, Z_Explain_attributeDetails,
+	 (Odr_fun)z_AttributeDetails, 0},
+	{ODR_IMPLICIT, ODR_CONTEXT, 9, Z_Explain_termListDetails,
+	 (Odr_fun)z_TermListDetails, 0},
+	{ODR_IMPLICIT, ODR_CONTEXT, 10, Z_Explain_elementSetDetails,
+	 (Odr_fun)z_ElementSetDetails, 0},
+	{ODR_IMPLICIT, ODR_CONTEXT, 11, Z_Explain_retrievalRecordDetails,
+	 (Odr_fun)z_RetrievalRecordDetails, 0},
+	{ODR_IMPLICIT, ODR_CONTEXT, 12, Z_Explain_sortDetails,
+	 (Odr_fun)z_SortDetails, 0},
+	{ODR_IMPLICIT, ODR_CONTEXT, 13, Z_Explain_processing,
+	 (Odr_fun)z_ProcessingInformation, 0},
+	{ODR_IMPLICIT, ODR_CONTEXT, 14, Z_Explain_variants,
+	 (Odr_fun)z_VariantSetInfo, 0},
+	{ODR_IMPLICIT, ODR_CONTEXT, 15, Z_Explain_units,
+	 (Odr_fun)z_UnitInfo, 0},
+	{ODR_IMPLICIT, ODR_CONTEXT, 100, Z_Explain_categoryList,
+	 (Odr_fun)z_CategoryList, 0},
+	{-1, -1, -1, -1, 0, 0}
+    };
+    
+    if (!odr_initmember(o, p, sizeof(**p)))
+	return opt && odr_ok(o);
+    if (odr_choice(o, arm, &(*p)->u, &(*p)->which, 0))
+    	return 1;
+    *p = 0;
+    return opt && odr_ok(o);
+}
Index: /main/tags/2.25/gsdl/packages/yaz/asn/prt-grs.c
===================================================================
--- /main/tags/2.25/gsdl/packages/yaz/asn/prt-grs.c	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/yaz/asn/prt-grs.c	(revision 21064)
@@ -0,0 +1,270 @@
+/*
+ * Copyright (c) 1995-1999, Index Data.
+ * See the file LICENSE for details.
+ * Sebastian Hammer, Adam Dickmeiss
+ *
+ * $Log$
+ * Revision 1.1  2000/08/03 03:09:52  johnmcp
+ * Added the YAZ toolkit source to the packages directory (for z39.50 stuff)
+ *
+ * Revision 1.9  1999/11/30 13:47:11  adam
+ * Improved installation. Moved header files to include/yaz.
+ *
+ * Revision 1.8  1999/04/20 09:56:48  adam
+ * Added 'name' paramter to encoder/decoder routines (typedef Odr_fun).
+ * Modified all encoders/decoders to reflect this change.
+ *
+ * Revision 1.7  1998/02/11 11:53:32  adam
+ * Changed code so that it compiles as C++.
+ *
+ * Revision 1.6  1997/05/14 06:53:23  adam
+ * C++ support.
+ *
+ * Revision 1.5  1995/10/18 16:12:20  quinn
+ * Added a couple of special cases to handle the WAIS server.
+ *
+ * Revision 1.4  1995/09/29  17:11:55  quinn
+ * Smallish
+ *
+ * Revision 1.3  1995/09/27  15:02:43  quinn
+ * Modified function heads & prototypes.
+ *
+ * Revision 1.2  1995/08/28  10:58:58  quinn
+ * Added extra choice-entry to data to catch visiblestring.
+ *
+ * Revision 1.1  1995/08/17  12:47:09  quinn
+ * Added GRS-1.
+ *
+ *
+ */
+
+#include <yaz/proto.h>
+
+int z_TaggedElement(ODR o, Z_TaggedElement **p, int opt, const char *name);
+int z_ElementData(ODR o, Z_ElementData **p, int opt, const char *name);
+int z_ElementMetaData(ODR o, Z_ElementMetaData **p, int opt, const char *name);
+int z_TagUnit(ODR o, Z_TagUnit **p, int opt, const char *name);
+int z_TagPath(ODR o, Z_TagPath **p, int opt, const char *name);
+int z_Order(ODR o, Z_Order **p, int opt, const char *name);
+int z_Usage(ODR o, Z_Usage **p, int opt, const char *name);
+int z_HitVector(ODR o, Z_HitVector **p, int opt, const char *name);
+int z_Triple(ODR o, Z_Triple **p, int opt, const char *name);
+int z_Variant(ODR o, Z_Variant **p, int opt, const char *name);
+
+int z_GenericRecord(ODR o, Z_GenericRecord **p, int opt, const char *name)
+{
+    if (o->direction == ODR_DECODE)
+	*p = (Z_GenericRecord *)odr_malloc(o, sizeof(**p));
+    else if (!*p)
+	return opt;
+    if (odr_sequence_of(o, (Odr_fun)z_TaggedElement, &(*p)->elements,
+			&(*p)->num_elements, 0))
+	return 1;
+    *p = 0;
+    return opt && odr_ok(o);
+}
+
+int z_TaggedElement(ODR o, Z_TaggedElement **p, int opt, const char *name)
+{
+    if (!odr_sequence_begin(o, p, sizeof(**p), 0))
+        return opt && odr_ok(o);
+    return
+        odr_implicit(o, odr_integer, &(*p)->tagType,
+		     ODR_CONTEXT, 1, 1) &&
+        odr_explicit(o, z_StringOrNumeric, &(*p)->tagValue,
+		     ODR_CONTEXT, 2, 0) &&
+        odr_implicit(o, odr_integer, &(*p)->tagOccurrence,
+		     ODR_CONTEXT, 3, 1) &&
+        odr_explicit(o, z_ElementData, &(*p)->content,
+		     ODR_CONTEXT, 4, 0) &&
+        odr_implicit(o, z_ElementMetaData, &(*p)->metaData,
+		     ODR_CONTEXT, 5, 1) &&
+        odr_implicit(o, z_Variant, &(*p)->appliedVariant, ODR_CONTEXT, 6, 1) &&
+	odr_sequence_end(o);
+}
+
+int z_ElementData(ODR o, Z_ElementData **p, int opt, const char *name)
+{
+    static Odr_arm arm[] =
+    {
+	{ODR_NONE, -1, -1, Z_ElementData_octets,
+	 (Odr_fun)odr_octetstring, 0},
+	{ODR_NONE, -1, -1, Z_ElementData_numeric,
+	 (Odr_fun)odr_integer, 0},
+	{ODR_NONE, -1, -1, Z_ElementData_date,
+	 (Odr_fun)odr_generalizedtime, 0},
+	{ODR_NONE, -1, -1, Z_ElementData_ext,
+	 (Odr_fun)z_External, 0},
+	{ODR_NONE, -1, -1, Z_ElementData_string,
+	 (Odr_fun)z_InternationalString, 0},
+	/* The entry below provides some backwards compatibility */
+	{ODR_NONE, -1, -1, Z_ElementData_string,
+	 (Odr_fun)odr_visiblestring, 0},
+	{ODR_NONE, -1, -1, Z_ElementData_trueOrFalse,
+	 (Odr_fun)odr_bool, 0},
+	{ODR_NONE, -1, -1, Z_ElementData_oid,
+	 (Odr_fun)odr_oid, 0},
+	{ODR_IMPLICIT, ODR_CONTEXT, 1, Z_ElementData_intUnit,
+	 (Odr_fun)z_IntUnit, 0},
+	{ODR_IMPLICIT, ODR_CONTEXT, 2, Z_ElementData_elementNotThere,
+	 (Odr_fun)odr_null, 0},
+	{ODR_IMPLICIT, ODR_CONTEXT, 3, Z_ElementData_elementEmpty,
+	 (Odr_fun)odr_null, 0},
+	{ODR_IMPLICIT, ODR_CONTEXT, 4, Z_ElementData_noDataRequested,
+	 (Odr_fun)odr_null, 0},
+	{ODR_IMPLICIT, ODR_CONTEXT, 5, Z_ElementData_diagnostic,
+	 (Odr_fun)z_External, 0},
+	{ODR_EXPLICIT, ODR_CONTEXT, 6, Z_ElementData_subtree,
+	 (Odr_fun)z_GenericRecord, 0},
+	{-1, -1, -1, -1, 0, 0}
+    };
+    
+    if (o->direction == ODR_DECODE)
+	*p = (Z_ElementData *)odr_malloc(o, sizeof(**p));
+    else if (!*p)
+	return opt;
+    if (odr_choice(o, arm, &(*p)->u, &(*p)->which, 0))
+	return 1;
+    *p = 0;
+    return opt && odr_ok(o);
+}
+
+int z_ElementMetaData(ODR o, Z_ElementMetaData **p, int opt, const char *name)
+{
+    if (!odr_sequence_begin(o, p, sizeof(**p), 0))
+        return opt && odr_ok(o);
+    return
+        odr_implicit(o, z_Order, &(*p)->seriesOrder, ODR_CONTEXT, 1, 1) &&
+        odr_implicit(o, z_Usage, &(*p)->usageRight, ODR_CONTEXT, 2, 1) &&
+	odr_implicit_settag(o, ODR_CONTEXT, 3) &&
+	(odr_sequence_of(o, (Odr_fun)z_HitVector, &(*p)->hits,
+			 &(*p)->num_hits, 0) ||
+	 odr_ok(o)) &&
+        odr_implicit(o, z_InternationalString, &(*p)->displayName,
+		     ODR_CONTEXT, 4, 1) &&
+	odr_implicit_settag(o, ODR_CONTEXT, 5) &&
+	(odr_sequence_of(o, (Odr_fun)z_Variant, &(*p)->supportedVariants,
+			 &(*p)->num_supportedVariants, 0) || odr_ok(o)) &&
+        odr_implicit(o, z_InternationalString, &(*p)->message,
+		     ODR_CONTEXT, 6, 1) &&
+        odr_implicit(o, odr_octetstring, &(*p)->elementDescriptor,
+		     ODR_CONTEXT, 7, 1) &&
+        odr_implicit(o, z_TagPath, &(*p)->surrogateFor, ODR_CONTEXT, 8, 1) &&
+        odr_implicit(o, z_TagPath, &(*p)->surrogateElement,
+		     ODR_CONTEXT, 9, 1) &&
+        odr_implicit(o, z_External, &(*p)->other, ODR_CONTEXT, 99, 1) &&
+        odr_sequence_end(o);
+}
+
+int z_TagUnit(ODR o, Z_TagUnit **p, int opt, const char *name)
+{
+    if (!odr_sequence_begin(o, p, sizeof(**p), 0))
+        return opt && odr_ok(o);
+    return
+        odr_implicit(o, odr_integer, &(*p)->tagType, ODR_CONTEXT, 1, 1) &&
+        odr_explicit(o, z_StringOrNumeric, &(*p)->tagValue,
+		     ODR_CONTEXT, 2, 0) &&
+        odr_implicit(o, odr_integer, &(*p)->tagOccurrence,
+		     ODR_CONTEXT, 3, 1) &&
+        odr_sequence_end(o);
+}
+
+int z_TagPath(ODR o, Z_TagPath **p, int opt, const char *name)
+{
+    if (o->direction == ODR_DECODE)
+	*p = (Z_TagPath *)odr_malloc(o, sizeof(**p));
+    else if (!*p)
+	return opt;
+    if (odr_sequence_of(o, (Odr_fun)z_TagUnit, &(*p)->tags,
+			&(*p)->num_tags, 0))
+	return 1;
+    *p = 0;
+    return opt && odr_ok(o);
+}
+
+int z_Order(ODR o, Z_Order **p, int opt, const char *name)
+{
+    if (!odr_sequence_begin(o, p, sizeof(**p), 0))
+        return opt && odr_ok(o);
+    return
+        odr_implicit(o, odr_bool, &(*p)->ascending, ODR_CONTEXT, 1, 0) &&
+        odr_implicit(o, odr_integer, &(*p)->order, ODR_CONTEXT, 2, 0) &&
+        odr_sequence_end(o);
+}
+
+int z_Usage(ODR o, Z_Usage **p, int opt, const char *name)
+{
+    if (!odr_sequence_begin(o, p, sizeof(**p), 0))
+        return opt && odr_ok(o);
+    return
+        odr_implicit(o, odr_integer, &(*p)->type, ODR_CONTEXT, 1, 0) &&
+        odr_implicit(o, z_InternationalString, &(*p)->restriction, ODR_CONTEXT,
+		     2, 1) &&
+        odr_sequence_end(o);
+}
+
+int z_HitVector(ODR o, Z_HitVector **p, int opt, const char *name)
+{
+    if (!odr_sequence_begin(o, p, sizeof(**p), 0))
+        return opt && odr_ok(o);
+    return
+        z_Term(o, &(*p)->satisfier, 1, 0) &&
+        odr_implicit(o, z_IntUnit, &(*p)->offsetIntoElement,
+		     ODR_CONTEXT, 1, 1) &&
+        odr_implicit(o, z_IntUnit, &(*p)->length, ODR_CONTEXT, 2, 1) &&
+        odr_implicit(o, odr_integer, &(*p)->hitRank, ODR_CONTEXT, 3, 1) &&
+        odr_implicit(o, odr_octetstring, &(*p)->targetToken, ODR_CONTEXT,
+		     4, 1) &&
+        odr_sequence_end(o);
+}
+
+int z_Triple(ODR o, Z_Triple **p, int opt, const char *name)
+{
+    static Odr_arm arm[] =
+    {
+	{ODR_NONE, -1, -1, Z_Triple_integer,
+	 (Odr_fun)odr_integer, 0},
+	{ODR_NONE, -1, -1, Z_Triple_internationalString,
+	 (Odr_fun)z_InternationalString, 0},
+	/* The entry below provides some backwards compatibility */
+	{ODR_NONE, -1, -1, Z_Triple_internationalString,
+	 (Odr_fun)odr_visiblestring, 0},
+	{ODR_NONE, -1, -1, Z_Triple_octetString,
+	 (Odr_fun)odr_octetstring, 0},
+	{ODR_NONE, -1, -1, Z_Triple_oid,
+	 (Odr_fun)odr_oid, 0},
+	{ODR_NONE, -1, -1, Z_Triple_boolean,
+	 (Odr_fun)odr_bool, 0},
+	{ODR_NONE, -1, -1, Z_Triple_null,
+	 (Odr_fun)odr_null, 0},
+	{ODR_IMPLICIT, ODR_CONTEXT, 1, Z_Triple_unit,
+	 (Odr_fun)z_Unit, 0},
+	{ODR_IMPLICIT, ODR_CONTEXT, 2, Z_Triple_valueAndUnit,
+	 (Odr_fun)z_IntUnit, 0},
+	{-1, -1, -1, -1, 0, 0}
+    };
+    
+    if (!odr_sequence_begin(o, p, sizeof(**p), 0))
+	return opt && odr_ok(o);
+    return
+    	odr_implicit(o, odr_oid, &(*p)->variantSetId, ODR_CONTEXT, 0, 1) &&
+	odr_implicit(o, odr_integer, &(*p)->zclass, ODR_CONTEXT, 1, 0) &&
+	odr_implicit(o, odr_integer, &(*p)->type, ODR_CONTEXT, 2, 0) &&
+	odr_constructed_begin(o, &(*p)->value, ODR_CONTEXT, 3, 0) &&
+	odr_choice(o, arm, &(*p)->value, &(*p)->which, 0) &&
+	odr_constructed_end(o) &&
+	odr_sequence_end(o);
+}
+
+int z_Variant(ODR o, Z_Variant **p, int opt, const char *name)
+{
+    if (!odr_sequence_begin(o, p, sizeof(**p), 0))
+        return opt && odr_ok(o);
+    return
+        odr_implicit(o, odr_oid, &(*p)->globalVariantSetId,
+		     ODR_CONTEXT, 1, 1) &&
+	odr_implicit_settag(o, ODR_CONTEXT, 2) &&
+	odr_sequence_of(o, (Odr_fun)z_Triple, &(*p)->triples,
+			&(*p)->num_triples, 0) &&
+	odr_sequence_end(o);
+}
Index: /main/tags/2.25/gsdl/packages/yaz/asn/prt-rsc.c
===================================================================
--- /main/tags/2.25/gsdl/packages/yaz/asn/prt-rsc.c	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/yaz/asn/prt-rsc.c	(revision 21064)
@@ -0,0 +1,94 @@
+/*
+ * Copyright (c) 1995-1999, Index Data.
+ * See the file LICENSE for details.
+ * Sebastian Hammer, Adam Dickmeiss
+ *
+ * $Log$
+ * Revision 1.1  2000/08/03 03:09:52  johnmcp
+ * Added the YAZ toolkit source to the packages directory (for z39.50 stuff)
+ *
+ * Revision 1.8  1999/11/30 13:47:11  adam
+ * Improved installation. Moved header files to include/yaz.
+ *
+ * Revision 1.7  1999/04/20 09:56:48  adam
+ * Added 'name' paramter to encoder/decoder routines (typedef Odr_fun).
+ * Modified all encoders/decoders to reflect this change.
+ *
+ * Revision 1.6  1998/02/11 11:53:32  adam
+ * Changed code so that it compiles as C++.
+ *
+ * Revision 1.5  1995/09/29 17:11:55  quinn
+ * Smallish
+ *
+ * Revision 1.4  1995/09/27  15:02:43  quinn
+ * Modified function heads & prototypes.
+ *
+ * Revision 1.3  1995/06/02  09:49:15  quinn
+ * Adding access control
+ *
+ * Revision 1.2  1995/06/01  14:34:53  quinn
+ * Work
+ *
+ * Revision 1.1  1995/06/01  11:22:17  quinn
+ * Resource control
+ *
+ *
+ */
+
+#include <yaz/proto.h>
+
+/* -------------------- Resource 1 ------------------------- */
+
+int z_Estimate1(ODR o, Z_Estimate1 **p, int opt, const char *name)
+{
+    if (!odr_sequence_begin(o, p, sizeof(**p), 0))
+    	return opt && odr_ok(o);
+    return
+    	odr_implicit(o, odr_integer, &(*p)->type, ODR_CONTEXT, 1, 0) &&
+	odr_implicit(o, odr_integer, &(*p)->value, ODR_CONTEXT, 2, 0) &&
+	odr_implicit(o, odr_integer, &(*p)->currencyCode, ODR_CONTEXT, 3, 1) &&
+	odr_sequence_end(o);
+}
+
+int z_ResourceReport1(ODR o, Z_ResourceReport1 **p, int opt, const char *name)
+{
+    if (!odr_sequence_begin(o, p, sizeof(**p), 0))
+    	return opt && odr_ok(o);
+    return
+    	odr_implicit_settag(o, ODR_CONTEXT, 1) &&
+	odr_sequence_of(o, (Odr_fun)z_Estimate1, &(*p)->estimates,
+			&(*p)->num_estimates, 0) &&
+	odr_implicit(o, odr_visiblestring, &(*p)->message,
+		     ODR_CONTEXT, 2, 0) &&
+	odr_sequence_end(o);
+}
+
+/* -------------------- Resource 2 ------------------------- */
+
+/* int z_StringOrNumeric(ODR, Z_StringOrNumeric **, int); */
+/* int z_IntUnit(ODR, Z_IntUnit **, int); */
+
+int z_Estimate2(ODR o, Z_Estimate2 **p, int opt, const char *name)
+{
+    if (!odr_sequence_begin(o, p, sizeof(**p), 0))
+    	return opt && odr_ok(o);
+    return
+    	odr_explicit(o, z_StringOrNumeric, &(*p)->type, ODR_CONTEXT, 1, 0) &&
+	odr_implicit(o, z_IntUnit, &(*p)->value, ODR_CONTEXT, 2, 0) &&
+	odr_sequence_end(o);
+}
+
+int z_ResourceReport2(ODR o, Z_ResourceReport2 **p, int opt, const char *name)
+{
+    if (!odr_sequence_begin(o, p, sizeof(**p), 0))
+	return opt && odr_ok(o);
+    return
+	odr_implicit_settag(o, ODR_CONTEXT, 1) &&
+	(odr_sequence_of(o, (Odr_fun)z_Estimate2, &(*p)->estimates,
+			 &(*p)->num_estimates, 0) || odr_ok(o)) &&
+	odr_implicit(o, odr_visiblestring, &(*p)->message,
+		     ODR_CONTEXT, 2, 1) &&
+	odr_sequence_end(o);
+}
+
+
Index: /main/tags/2.25/gsdl/packages/yaz/asn/prt-univ.c
===================================================================
--- /main/tags/2.25/gsdl/packages/yaz/asn/prt-univ.c	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/yaz/asn/prt-univ.c	(revision 21064)
@@ -0,0 +1,61 @@
+/*
+ * Copyright (c) 1998-1999, Index Data.
+ * See the file LICENSE for details.
+ * Sebastian Hammer, Adam Dickmeiss
+ *
+ * $Log$
+ * Revision 1.1  2000/08/03 03:09:53  johnmcp
+ * Added the YAZ toolkit source to the packages directory (for z39.50 stuff)
+ *
+ * Revision 1.3  1999/11/30 13:47:11  adam
+ * Improved installation. Moved header files to include/yaz.
+ *
+ * Revision 1.2  1999/04/20 09:56:48  adam
+ * Added 'name' paramter to encoder/decoder routines (typedef Odr_fun).
+ * Modified all encoders/decoders to reflect this change.
+ *
+ * Revision 1.1  1998/03/20 14:46:06  adam
+ * Added UNIverse Resource Reports.
+ *
+ */
+
+#include <yaz/proto.h>
+
+int z_UniverseReportHits (ODR o, Z_UniverseReportHits **p, int opt,
+			  const char *name)
+{
+    if (!odr_sequence_begin (o, p, sizeof(**p), 0))
+	return opt && odr_ok (o);
+    return
+	z_StringOrNumeric(o, &(*p)->database, 0, 0) &&
+	z_StringOrNumeric(o, &(*p)->hits, 0, 0) &&
+	odr_sequence_end (o);
+}
+
+int z_UniverseReportDuplicate (ODR o, Z_UniverseReportDuplicate **p, int opt,
+			       const char *name)
+{
+    if (!odr_sequence_begin (o, p, sizeof(**p), 0))
+	return opt && odr_ok (o);
+    return
+	z_StringOrNumeric(o, &(*p)->hitno, 0, 0) &&
+	odr_sequence_end (o);
+}
+
+int z_UniverseReport (ODR o, Z_UniverseReport **p, int opt, const char *name)
+{
+    static Odr_arm arm[] = {
+	{ODR_IMPLICIT, ODR_CONTEXT, 0, Z_UniverseReport_databaseHits,
+	 (Odr_fun) z_UniverseReportHits, 0},
+	{ODR_IMPLICIT, ODR_CONTEXT, 1, Z_UniverseReport_duplicate,
+	 (Odr_fun) z_UniverseReportDuplicate, 0},
+	{-1, -1, -1, -1, (Odr_fun) 0, 0}
+    };
+    if (!odr_sequence_begin (o, p, sizeof(**p), 0))
+	return opt && odr_ok (o);
+    return
+	odr_integer(o, &(*p)->totalHits, 0, 0) &&
+	odr_choice (o, arm, &(*p)->u, &(*p)->which, 0) &&
+	odr_sequence_end (o);
+}
+
Index: /main/tags/2.25/gsdl/packages/yaz/ccl/Makefile.am
===================================================================
--- /main/tags/2.25/gsdl/packages/yaz/ccl/Makefile.am	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/yaz/ccl/Makefile.am	(revision 21064)
@@ -0,0 +1,12 @@
+## $Id$
+
+noinst_LIBRARIES = libccl.a
+
+noinst_PROGRAMS = cclsh
+
+INCLUDES=-I../include
+
+libccl_a_SOURCES = cclfind.c ccltoken.c cclerrms.c cclqual.c cclptree.c \
+  cclqfile.c cclstr.c
+cclsh_SOURCES=cclsh.c
+cclsh_LDADD = libccl.a
Index: /main/tags/2.25/gsdl/packages/yaz/ccl/Makefile.in
===================================================================
--- /main/tags/2.25/gsdl/packages/yaz/ccl/Makefile.in	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/yaz/ccl/Makefile.in	(revision 21064)
@@ -0,0 +1,295 @@
+# Makefile.in generated automatically by automake 1.4 from Makefile.am
+
+# Copyright (C) 1994, 1995-8, 1999 Free Software Foundation, Inc.
+# This Makefile.in is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
+# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE.
+
+
+SHELL = @SHELL@
+
+srcdir = @srcdir@
+top_srcdir = @top_srcdir@
+VPATH = @srcdir@
+prefix = @prefix@
+exec_prefix = @exec_prefix@
+
+bindir = @bindir@
+sbindir = @sbindir@
+libexecdir = @libexecdir@
+datadir = @datadir@
+sysconfdir = @sysconfdir@
+sharedstatedir = @sharedstatedir@
+localstatedir = @localstatedir@
+libdir = @libdir@
+infodir = @infodir@
+mandir = @mandir@
+includedir = @includedir@
+oldincludedir = /usr/include
+
+DESTDIR =
+
+pkgdatadir = $(datadir)/@PACKAGE@
+pkglibdir = $(libdir)/@PACKAGE@
+pkgincludedir = $(includedir)/@PACKAGE@
+
+top_builddir = ..
+
+ACLOCAL = @ACLOCAL@
+AUTOCONF = @AUTOCONF@
+AUTOMAKE = @AUTOMAKE@
+AUTOHEADER = @AUTOHEADER@
+
+INSTALL = @INSTALL@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@ $(AM_INSTALL_PROGRAM_FLAGS)
+INSTALL_DATA = @INSTALL_DATA@
+INSTALL_SCRIPT = @INSTALL_SCRIPT@
+transform = @program_transform_name@
+
+NORMAL_INSTALL = :
+PRE_INSTALL = :
+POST_INSTALL = :
+NORMAL_UNINSTALL = :
+PRE_UNINSTALL = :
+POST_UNINSTALL = :
+ASNMODULE = @ASNMODULE@
+CC = @CC@
+CPP = @CPP@
+ILLLIB = @ILLLIB@
+ILLMODULE = @ILLMODULE@
+MAKEINFO = @MAKEINFO@
+PACKAGE = @PACKAGE@
+RANLIB = @RANLIB@
+SUBDIRS_VAR = @SUBDIRS_VAR@
+VERSION = @VERSION@
+have_sgml2html = @have_sgml2html@
+have_sgml2latex = @have_sgml2latex@
+have_sgml2txt = @have_sgml2txt@
+
+noinst_LIBRARIES = libccl.a
+
+noinst_PROGRAMS = cclsh
+
+INCLUDES = -I../include
+
+libccl_a_SOURCES = cclfind.c ccltoken.c cclerrms.c cclqual.c cclptree.c   cclqfile.c cclstr.c
+
+cclsh_SOURCES = cclsh.c
+cclsh_LDADD = libccl.a
+mkinstalldirs = $(SHELL) $(top_srcdir)/mkinstalldirs
+CONFIG_CLEAN_FILES = 
+LIBRARIES =  $(noinst_LIBRARIES)
+
+
+DEFS = @DEFS@ -I. -I$(srcdir) 
+CPPFLAGS = @CPPFLAGS@
+LDFLAGS = @LDFLAGS@
+LIBS = @LIBS@
+libccl_a_LIBADD = 
+libccl_a_OBJECTS =  cclfind.o ccltoken.o cclerrms.o cclqual.o cclptree.o \
+cclqfile.o cclstr.o
+AR = ar
+PROGRAMS =  $(noinst_PROGRAMS)
+
+cclsh_OBJECTS =  cclsh.o
+cclsh_DEPENDENCIES =  libccl.a
+cclsh_LDFLAGS = 
+CFLAGS = @CFLAGS@
+COMPILE = $(CC) $(DEFS) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
+CCLD = $(CC)
+LINK = $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(LDFLAGS) -o $@
+DIST_COMMON =  README Makefile.am Makefile.in
+
+
+DISTFILES = $(DIST_COMMON) $(SOURCES) $(HEADERS) $(TEXINFOS) $(EXTRA_DIST)
+
+TAR = gtar
+GZIP_ENV = --best
+SOURCES = $(libccl_a_SOURCES) $(cclsh_SOURCES)
+OBJECTS = $(libccl_a_OBJECTS) $(cclsh_OBJECTS)
+
+all: all-redirect
+.SUFFIXES:
+.SUFFIXES: .S .c .o .s
+$(srcdir)/Makefile.in: Makefile.am $(top_srcdir)/configure.in $(ACLOCAL_M4) 
+	cd $(top_srcdir) && $(AUTOMAKE) --gnu --include-deps ccl/Makefile
+
+Makefile: $(srcdir)/Makefile.in  $(top_builddir)/config.status
+	cd $(top_builddir) \
+	  && CONFIG_FILES=$(subdir)/$@ CONFIG_HEADERS= $(SHELL) ./config.status
+
+
+mostlyclean-noinstLIBRARIES:
+
+clean-noinstLIBRARIES:
+	-test -z "$(noinst_LIBRARIES)" || rm -f $(noinst_LIBRARIES)
+
+distclean-noinstLIBRARIES:
+
+maintainer-clean-noinstLIBRARIES:
+
+.c.o:
+	$(COMPILE) -c $<
+
+.s.o:
+	$(COMPILE) -c $<
+
+.S.o:
+	$(COMPILE) -c $<
+
+mostlyclean-compile:
+	-rm -f *.o core *.core
+
+clean-compile:
+
+distclean-compile:
+	-rm -f *.tab.c
+
+maintainer-clean-compile:
+
+libccl.a: $(libccl_a_OBJECTS) $(libccl_a_DEPENDENCIES)
+	-rm -f libccl.a
+	$(AR) cru libccl.a $(libccl_a_OBJECTS) $(libccl_a_LIBADD)
+	$(RANLIB) libccl.a
+
+mostlyclean-noinstPROGRAMS:
+
+clean-noinstPROGRAMS:
+	-test -z "$(noinst_PROGRAMS)" || rm -f $(noinst_PROGRAMS)
+
+distclean-noinstPROGRAMS:
+
+maintainer-clean-noinstPROGRAMS:
+
+cclsh: $(cclsh_OBJECTS) $(cclsh_DEPENDENCIES)
+	@rm -f cclsh
+	$(LINK) $(cclsh_LDFLAGS) $(cclsh_OBJECTS) $(cclsh_LDADD) $(LIBS)
+
+tags: TAGS
+
+ID: $(HEADERS) $(SOURCES) $(LISP)
+	list='$(SOURCES) $(HEADERS)'; \
+	unique=`for i in $$list; do echo $$i; done | \
+	  awk '    { files[$$0] = 1; } \
+	       END { for (i in files) print i; }'`; \
+	here=`pwd` && cd $(srcdir) \
+	  && mkid -f$$here/ID $$unique $(LISP)
+
+TAGS:  $(HEADERS) $(SOURCES)  $(TAGS_DEPENDENCIES) $(LISP)
+	tags=; \
+	here=`pwd`; \
+	list='$(SOURCES) $(HEADERS)'; \
+	unique=`for i in $$list; do echo $$i; done | \
+	  awk '    { files[$$0] = 1; } \
+	       END { for (i in files) print i; }'`; \
+	test -z "$(ETAGS_ARGS)$$unique$(LISP)$$tags" \
+	  || (cd $(srcdir) && etags $(ETAGS_ARGS) $$tags  $$unique $(LISP) -o $$here/TAGS)
+
+mostlyclean-tags:
+
+clean-tags:
+
+distclean-tags:
+	-rm -f TAGS ID
+
+maintainer-clean-tags:
+
+distdir = $(top_builddir)/$(PACKAGE)-$(VERSION)/$(subdir)
+
+subdir = ccl
+
+distdir: $(DISTFILES)
+	@for file in $(DISTFILES); do \
+	  d=$(srcdir); \
+	  if test -d $$d/$$file; then \
+	    cp -pr $$/$$file $(distdir)/$$file; \
+	  else \
+	    test -f $(distdir)/$$file \
+	    || ln $$d/$$file $(distdir)/$$file 2> /dev/null \
+	    || cp -p $$d/$$file $(distdir)/$$file || :; \
+	  fi; \
+	done
+
+info-am:
+info: info-am
+dvi-am:
+dvi: dvi-am
+check-am: all-am
+check: check-am
+installcheck-am:
+installcheck: installcheck-am
+install-exec-am:
+install-exec: install-exec-am
+
+install-data-am:
+install-data: install-data-am
+
+install-am: all-am
+	@$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
+install: install-am
+uninstall-am:
+uninstall: uninstall-am
+all-am: Makefile $(LIBRARIES) $(PROGRAMS)
+all-redirect: all-am
+install-strip:
+	$(MAKE) $(AM_MAKEFLAGS) AM_INSTALL_PROGRAM_FLAGS=-s install
+installdirs:
+
+
+mostlyclean-generic:
+
+clean-generic:
+
+distclean-generic:
+	-rm -f Makefile $(CONFIG_CLEAN_FILES)
+	-rm -f config.cache config.log stamp-h stamp-h[0-9]*
+
+maintainer-clean-generic:
+mostlyclean-am:  mostlyclean-noinstLIBRARIES mostlyclean-compile \
+		mostlyclean-noinstPROGRAMS mostlyclean-tags \
+		mostlyclean-generic
+
+mostlyclean: mostlyclean-am
+
+clean-am:  clean-noinstLIBRARIES clean-compile clean-noinstPROGRAMS \
+		clean-tags clean-generic mostlyclean-am
+
+clean: clean-am
+
+distclean-am:  distclean-noinstLIBRARIES distclean-compile \
+		distclean-noinstPROGRAMS distclean-tags \
+		distclean-generic clean-am
+
+distclean: distclean-am
+
+maintainer-clean-am:  maintainer-clean-noinstLIBRARIES \
+		maintainer-clean-compile \
+		maintainer-clean-noinstPROGRAMS maintainer-clean-tags \
+		maintainer-clean-generic distclean-am
+	@echo "This command is intended for maintainers to use;"
+	@echo "it deletes files that may require special tools to rebuild."
+
+maintainer-clean: maintainer-clean-am
+
+.PHONY: mostlyclean-noinstLIBRARIES distclean-noinstLIBRARIES \
+clean-noinstLIBRARIES maintainer-clean-noinstLIBRARIES \
+mostlyclean-compile distclean-compile clean-compile \
+maintainer-clean-compile mostlyclean-noinstPROGRAMS \
+distclean-noinstPROGRAMS clean-noinstPROGRAMS \
+maintainer-clean-noinstPROGRAMS tags mostlyclean-tags distclean-tags \
+clean-tags maintainer-clean-tags distdir info-am info dvi-am dvi check \
+check-am installcheck-am installcheck install-exec-am install-exec \
+install-data-am install-data install-am install uninstall-am uninstall \
+all-redirect all-am all installdirs mostlyclean-generic \
+distclean-generic clean-generic maintainer-clean-generic clean \
+mostlyclean distclean maintainer-clean
+
+
+# Tell versions [3.59,3.63) of GNU make to not export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:
Index: /main/tags/2.25/gsdl/packages/yaz/ccl/README
===================================================================
--- /main/tags/2.25/gsdl/packages/yaz/ccl/README	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/yaz/ccl/README	(revision 21064)
@@ -0,0 +1,15 @@
+CCL test module
+
+This module is required to parse the queries given to the 'cli'
+test program. It is *not* a part of the YAZ module, and it is
+distributed under a different license.
+
+Eventually, the products of the EUROPAGATE will be made available to
+the general public, free of charge (the exact nature of the license is
+unknown at this point). Until then, you should *NOT* distribute copies
+of this software to organisations that are not partners in EUROPAGATE.
+
+If you need to distribute copies of YAZ to organisations which are not
+partners in EUROPAGATE, you should remove this module, and, if
+necessary, modify yazlib/tst.c to work wihout it. The test program is
+not essential to the general working of YAZ.
Index: /main/tags/2.25/gsdl/packages/yaz/ccl/cclerrms.c
===================================================================
--- /main/tags/2.25/gsdl/packages/yaz/ccl/cclerrms.c	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/yaz/ccl/cclerrms.c	(revision 21064)
@@ -0,0 +1,118 @@
+/*
+ * Copyright (c) 1995, the EUROPAGATE consortium (see below).
+ *
+ * The EUROPAGATE consortium members are:
+ *
+ *    University College Dublin
+ *    Danmarks Teknologiske Videnscenter
+ *    An Chomhairle Leabharlanna
+ *    Consejo Superior de Investigaciones Cientificas
+ *
+ * Permission to use, copy, modify, distribute, and sell this software and
+ * its documentation, in whole or in part, for any purpose, is hereby granted,
+ * provided that:
+ *
+ * 1. This copyright and permission notice appear in all copies of the
+ * software and its documentation. Notices of copyright or attribution
+ * which appear at the beginning of any file must remain unchanged.
+ *
+ * 2. The names of EUROPAGATE or the project partners may not be used to
+ * endorse or promote products derived from this software without specific
+ * prior written permission.
+ *
+ * 3. Users of this software (implementors and gateway operators) agree to
+ * inform the EUROPAGATE consortium of their use of the software. This
+ * information will be used to evaluate the EUROPAGATE project and the
+ * software, and to plan further developments. The consortium may use
+ * the information in later publications.
+ * 
+ * 4. Users of this software agree to make their best efforts, when
+ * documenting their use of the software, to acknowledge the EUROPAGATE
+ * consortium, and the role played by the software in their work.
+ *
+ * THIS SOFTWARE IS PROVIDED "AS IS" AND WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS, IMPLIED, OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY
+ * WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
+ * IN NO EVENT SHALL THE EUROPAGATE CONSORTIUM OR ITS MEMBERS BE LIABLE
+ * FOR ANY SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF
+ * ANY KIND, OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA
+ * OR PROFITS, WHETHER OR NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND
+ * ON ANY THEORY OF LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE
+ * USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ */
+/*
+ * Europagate, 1995
+ *
+ * $Log$
+ * Revision 1.1  2000/08/03 03:09:55  johnmcp
+ * Added the YAZ toolkit source to the packages directory (for z39.50 stuff)
+ *
+ * Revision 1.8  1999/11/30 13:47:11  adam
+ * Improved installation. Moved header files to include/yaz.
+ *
+ * Revision 1.7  1998/02/11 11:53:33  adam
+ * Changed code so that it compiles as C++.
+ *
+ * Revision 1.6  1997/09/29 08:56:37  adam
+ * Changed CCL parser to be thread safe. New type, CCL_parser, declared
+ * and a create/destructers ccl_parser_create/ccl_parser/destory has
+ * been added.
+ *
+ * Revision 1.5  1997/04/30 08:52:06  quinn
+ * Null
+ *
+ * Revision 1.4  1996/10/11  15:00:24  adam
+ * CCL parser from Europagate Email gateway 1.0.
+ *
+ * Revision 1.8  1995/05/16  09:39:25  adam
+ * LICENSE.
+ *
+ * Revision 1.7  1995/04/17  09:31:40  adam
+ * Improved handling of qualifiers. Aliases or reserved words.
+ *
+ * Revision 1.6  1995/02/23  08:31:59  adam
+ * Changed header.
+ *
+ * Revision 1.4  1995/02/14  16:20:54  adam
+ * Qualifiers are read from a file now.
+ *
+ * Revision 1.3  1995/02/14  10:25:56  adam
+ * The constructions 'qualifier rel term ...' implemented.
+ *
+ * Revision 1.2  1995/02/13  15:15:06  adam
+ * Added handling of qualifiers. Not finished yet.
+ *
+ * Revision 1.1  1995/02/13  12:35:20  adam
+ * First version of CCL. Qualifiers aren't handled yet.
+ *
+ */
+
+/* Chas: Required for the correct definition of ccl_err_msg */
+#include <yaz/yaz-ccl.h>
+
+static char *err_msg_array[] = {
+    "Ok",
+    "Search word expected",
+    "')' expected",
+    "Set name expected",
+    "Operator expected",
+    "Unbalanced ')'",
+    "Unknown qualifier",
+    "Qualifiers applied twice",
+    "'=' expected",
+    "Bad relation",
+    "Left truncation not supported",
+    "Both left - and right truncation not supported",
+    "Right truncation not supported"
+};
+
+/*
+ * ccl_err_msg: return name of CCL error
+ * ccl_errno:   Error no.
+ * return:      Name of error.
+ */
+const char *ccl_err_msg (int ccl_errno)
+{
+    return err_msg_array[ccl_errno];
+}
Index: /main/tags/2.25/gsdl/packages/yaz/ccl/cclfind.c
===================================================================
--- /main/tags/2.25/gsdl/packages/yaz/ccl/cclfind.c	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/yaz/ccl/cclfind.c	(revision 21064)
@@ -0,0 +1,907 @@
+/*
+ * Copyright (c) 1995, the EUROPAGATE consortium (see below).
+ *
+ * The EUROPAGATE consortium members are:
+ *
+ *    University College Dublin
+ *    Danmarks Teknologiske Videnscenter
+ *    An Chomhairle Leabharlanna
+ *    Consejo Superior de Investigaciones Cientificas
+ *
+ * Permission to use, copy, modify, distribute, and sell this software and
+ * its documentation, in whole or in part, for any purpose, is hereby granted,
+ * provided that:
+ *
+ * 1. This copyright and permission notice appear in all copies of the
+ * software and its documentation. Notices of copyright or attribution
+ * which appear at the beginning of any file must remain unchanged.
+ *
+ * 2. The names of EUROPAGATE or the project partners may not be used to
+ * endorse or promote products derived from this software without specific
+ * prior written permission.
+ *
+ * 3. Users of this software (implementors and gateway operators) agree to
+ * inform the EUROPAGATE consortium of their use of the software. This
+ * information will be used to evaluate the EUROPAGATE project and the
+ * software, and to plan further developments. The consortium may use
+ * the information in later publications.
+ * 
+ * 4. Users of this software agree to make their best efforts, when
+ * documenting their use of the software, to acknowledge the EUROPAGATE
+ * consortium, and the role played by the software in their work.
+ *
+ * THIS SOFTWARE IS PROVIDED "AS IS" AND WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS, IMPLIED, OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY
+ * WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
+ * IN NO EVENT SHALL THE EUROPAGATE CONSORTIUM OR ITS MEMBERS BE LIABLE
+ * FOR ANY SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF
+ * ANY KIND, OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA
+ * OR PROFITS, WHETHER OR NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND
+ * ON ANY THEORY OF LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE
+ * USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ */
+/* CCL find (to rpn conversion)
+ * Europagate, 1995
+ *
+ * $Log$
+ * Revision 1.1  2000/08/03 03:09:56  johnmcp
+ * Added the YAZ toolkit source to the packages directory (for z39.50 stuff)
+ *
+ * Revision 1.15  2000/02/24 23:49:13  adam
+ * Fixed memory allocation problem.
+ *
+ * Revision 1.14  2000/01/31 13:15:21  adam
+ * Removed uses of assert(3). Cleanup of ODR. CCL parser update so
+ * that some characters are not surrounded by spaces in resulting term.
+ * ILL-code updates.
+ *
+ * Revision 1.13  1999/12/22 13:13:32  adam
+ * Search terms may include "operators" without causing error.
+ *
+ * Revision 1.12  1999/11/30 13:47:11  adam
+ * Improved installation. Moved header files to include/yaz.
+ *
+ * Revision 1.11  1999/03/31 11:15:37  adam
+ * Fixed memory leaks in ccl_find_str and ccl_qual_rm.
+ *
+ * Revision 1.10  1998/02/11 11:53:33  adam
+ * Changed code so that it compiles as C++.
+ *
+ * Revision 1.9  1997/09/29 08:56:37  adam
+ * Changed CCL parser to be thread safe. New type, CCL_parser, declared
+ * and a create/destructers ccl_parser_create/ccl_parser/destory has
+ * been added.
+ *
+ * Revision 1.8  1997/09/01 08:48:11  adam
+ * New windows NT/95 port using MSV5.0. Only a few changes made
+ * to avoid warnings.
+ *
+ * Revision 1.7  1997/05/14 06:53:26  adam
+ * C++ support.
+ *
+ * Revision 1.6  1997/04/30 08:52:06  quinn
+ * Null
+ *
+ * Revision 1.5  1996/10/11  15:00:24  adam
+ * CCL parser from Europagate Email gateway 1.0.
+ *
+ * Revision 1.16  1996/01/08  08:41:13  adam
+ * Removed unused function.
+ *
+ * Revision 1.15  1995/07/20  08:14:34  adam
+ * Qualifiers were observed too often. Instead tokens are treated as
+ * qualifiers only when separated by comma.
+ *
+ * Revision 1.14  1995/05/16  09:39:26  adam
+ * LICENSE.
+ *
+ * Revision 1.13  1995/04/17  09:31:42  adam
+ * Improved handling of qualifiers. Aliases or reserved words.
+ *
+ * Revision 1.12  1995/03/20  15:27:43  adam
+ * Minor changes.
+ *
+ * Revision 1.11  1995/02/23  08:31:59  adam
+ * Changed header.
+ *
+ * Revision 1.9  1995/02/16  13:20:06  adam
+ * Spell fix.
+ *
+ * Revision 1.8  1995/02/14  19:59:42  adam
+ * Removed a syntax error.
+ *
+ * Revision 1.7  1995/02/14  19:55:10  adam
+ * Header files ccl.h/cclp.h are gone! They have been merged an
+ * moved to ../include/ccl.h.
+ * Node kind(s) in ccl_rpn_node have changed names.
+ *
+ * Revision 1.6  1995/02/14  16:20:55  adam
+ * Qualifiers are read from a file now.
+ *
+ * Revision 1.5  1995/02/14  14:12:41  adam
+ * Ranges for ordered qualfiers implemented (e.g. pd=1980-1990).
+ *
+ * Revision 1.4  1995/02/14  13:16:29  adam
+ * Left and/or right truncation implemented.
+ *
+ * Revision 1.3  1995/02/14  10:25:56  adam
+ * The constructions 'qualifier rel term ...' implemented.
+ *
+ * Revision 1.2  1995/02/13  15:15:07  adam
+ * Added handling of qualifiers. Not finished yet.
+ *
+ * Revision 1.1  1995/02/13  12:35:20  adam
+ * First version of CCL. Qualifiers aren't handled yet.
+ *
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <yaz/ccl.h>
+
+/* returns type of current lookahead */
+#define KIND (cclp->look_token->kind)
+
+/* move one token forward */
+#define ADVANCE cclp->look_token = cclp->look_token->next
+
+/* 
+ * qual_val_type: test for existance of attribute type/value pair.
+ * qa:     Attribute array
+ * type:   Type of attribute to search for
+ * value:  Value of attribute to seach for
+ * return: 1 if found; 0 otherwise.
+ */
+static int qual_val_type (struct ccl_rpn_attr **qa, int type, int value)
+{
+    int i;
+    struct ccl_rpn_attr *q;
+
+    if (!qa)
+        return 0;
+    for (i = 0;  (q=qa[i]); i++)
+        while (q)
+	{
+            if (q->type == type && q->value == value)
+	        return 1;
+	    q = q->next;
+	}
+    return 0;
+}
+
+/*
+ * strxcat: concatenate strings.
+ * n:      Null-terminated Destination string 
+ * src:    Source string to be appended (not null-terminated)
+ * len:    Length of source string.
+ */
+static void strxcat (char *n, const char *src, int len)
+{
+    while (*n)
+	n++;
+    while (--len >= 0)
+	*n++ = *src++;
+    *n = '\0';
+}
+
+/*
+ * copy_token_name: Return copy of CCL token name
+ * tp:      Pointer to token info.
+ * return:  malloc(3) allocated copy of token name.
+ */
+static char *copy_token_name (struct ccl_token *tp)
+{
+    char *str = (char *)malloc (tp->len + 1);
+    ccl_assert (str);
+    memcpy (str, tp->name, tp->len);
+    str[tp->len] = '\0';
+    return str;
+}
+
+/*
+ * mk_node: Create RPN node.
+ * kind:   Type of node.
+ * return: pointer to allocated node.
+ */
+static struct ccl_rpn_node *mk_node (int kind)
+{
+    struct ccl_rpn_node *p;
+    p = (struct ccl_rpn_node *)malloc (sizeof(*p));
+    ccl_assert (p);
+    p->kind = kind;
+    return p;
+}
+
+/*
+ * ccl_rpn_delete: Delete RPN tree.
+ * rpn:   Pointer to tree.
+ */
+void ccl_rpn_delete (struct ccl_rpn_node *rpn)
+{
+    struct ccl_rpn_attr *attr, *attr1;
+    if (!rpn)
+        return;
+    switch (rpn->kind)
+    {
+    case CCL_RPN_AND:
+    case CCL_RPN_OR:
+    case CCL_RPN_NOT:
+        ccl_rpn_delete (rpn->u.p[0]);
+        ccl_rpn_delete (rpn->u.p[1]);
+        break;
+    case CCL_RPN_TERM:
+        free (rpn->u.t.term);
+        for (attr = rpn->u.t.attr_list; attr; attr = attr1)
+        {
+            attr1 = attr->next;
+            free (attr);
+        }
+        break;
+    case CCL_RPN_SET:
+        free (rpn->u.setname);
+        break;
+    case CCL_RPN_PROX:
+        ccl_rpn_delete (rpn->u.p[0]);
+        ccl_rpn_delete (rpn->u.p[1]);
+        break;
+    }
+    free (rpn);
+}
+
+static struct ccl_rpn_node *find_spec (CCL_parser cclp,
+				       struct ccl_rpn_attr **qa);
+
+static int is_term_ok (int look, int *list)
+{
+    for (;*list >= 0; list++)
+        if (look == *list)
+            return 1;
+    return 0;
+}
+
+static struct ccl_rpn_node *search_terms (CCL_parser cclp,
+					  struct ccl_rpn_attr **qa);
+
+/*
+ * add_attr: Add attribute (type/value) to RPN term node.
+ * p:     RPN node of type term.
+ * type:  Type of attribute
+ * value: Value of attribute
+ */
+static void add_attr (struct ccl_rpn_node *p, int type, int value)
+{
+    struct ccl_rpn_attr *n;
+
+    n = (struct ccl_rpn_attr *)malloc (sizeof(*n));
+    ccl_assert (n);
+    n->type = type;
+    n->value = value;
+    n->next = p->u.t.attr_list;
+    p->u.t.attr_list = n;
+}
+
+/*
+ * search_term: Parse CCL search term. 
+ * cclp:   CCL Parser
+ * qa:     Qualifier attributes already applied.
+ * return: pointer to node(s); NULL on error.
+ */
+static struct ccl_rpn_node *search_term_x (CCL_parser cclp,
+					   struct ccl_rpn_attr **qa,
+                                           int *term_list)
+{
+    struct ccl_rpn_attr *qa_tmp[2];
+    struct ccl_rpn_node *p;
+    struct ccl_token *lookahead = cclp->look_token;
+    int len = 0;
+    size_t no, i;
+    int left_trunc = 0;
+    int right_trunc = 0;
+    int mid_trunc = 0;
+    int relation_value = -1;
+    int position_value = -1;
+    int structure_value = -1;
+    int truncation_value = -1;
+    int completeness_value = -1;
+
+    if (!is_term_ok(KIND, term_list))
+    {
+        cclp->error_code = CCL_ERR_TERM_EXPECTED;
+        return NULL;
+    }
+    /* create the term node, but wait a moment before adding the term */
+    p = mk_node (CCL_RPN_TERM);
+    p->u.t.attr_list = NULL;
+    p->u.t.term = NULL;
+
+    if (!qa)
+    {
+        /* no qualifier(s) applied. Use 'term' if it is defined */
+
+        qa = qa_tmp;
+	ccl_assert (qa);
+	qa[0] = ccl_qual_search (cclp, "term", 4);
+	qa[1] = NULL;
+    }
+
+    /* go through all attributes and add them to the attribute list */
+    for (i=0; qa && qa[i]; i++)
+    {
+        struct ccl_rpn_attr *attr;
+
+        for (attr = qa[i]; attr; attr = attr->next)
+            if (attr->value > 0)
+	    {   /* deal only with REAL attributes (positive) */
+	        switch (attr->type)
+		{
+		case CCL_BIB1_REL:
+		    if (relation_value != -1)
+		        continue;
+		    relation_value = attr->value;
+		    break;
+		case CCL_BIB1_POS:
+		    if (position_value != -1)
+		        continue;
+		    position_value = attr->value;
+		    break;
+		case CCL_BIB1_STR:
+		    if (structure_value != -1)
+		        continue;
+		    structure_value = attr->value;
+		    break;
+		case CCL_BIB1_TRU:
+		    if (truncation_value != -1)
+		        continue;
+		    truncation_value = attr->value;
+		    break;
+		case CCL_BIB1_COM:
+		    if (completeness_value != -1)
+		        continue;
+		    completeness_value = attr->value;
+		    break;
+		}
+                add_attr (p, attr->type, attr->value);
+	    }
+    }
+    /* go through each TERM token. If no truncation attribute is yet
+       met, then look for left/right truncation markers (?) and
+       set left_trunc/right_trunc/mid_trunc accordingly */
+    for (no = 0; is_term_ok(lookahead->kind, term_list); no++)
+    {
+        for (i = 0; i<lookahead->len; i++)
+            if (truncation_value == -1 && lookahead->name[i] == '?')
+            {
+                if (no == 0 && i == 0 && lookahead->len >= 1)
+                    left_trunc = 1;
+                else if (!is_term_ok(lookahead->next->kind, term_list) &&
+                         i == lookahead->len-1 && i >= 1)
+                    right_trunc = 1;
+                else
+                    mid_trunc = 1;
+            }
+        len += 1+lookahead->len;
+	lookahead = lookahead->next;
+    }
+    /* len now holds the number of characters in the RPN term */
+    /* no holds the number of CCL tokens (1 or more) */
+
+    if (structure_value == -1 && 
+        qual_val_type (qa, CCL_BIB1_STR, CCL_BIB1_STR_WP))
+    {   /* no structure attribute met. Apply either structure attribute 
+           WORD or PHRASE depending on number of CCL tokens */
+        if (no == 1)
+            add_attr (p, CCL_BIB1_STR, 2);
+        else
+            add_attr (p, CCL_BIB1_STR, 1);
+    }
+
+    /* make the RPN token */
+    p->u.t.term = (char *)malloc (len);
+    ccl_assert (p->u.t.term);
+    p->u.t.term[0] = '\0';
+    for (i = 0; i<no; i++)
+    {
+        const char *src_str = cclp->look_token->name;
+        int src_len = cclp->look_token->len;
+        
+        if (i == 0 && left_trunc)
+        {
+            src_len--;
+            src_str++;
+        }
+        else if (i == no-1 && right_trunc)
+            src_len--;
+        if (src_len)
+        {
+            int len = strlen(p->u.t.term);
+            if (len &&
+                !strchr("-+", *src_str) &&
+                !strchr("-+", p->u.t.term[len-1]))
+            {
+                strcat (p->u.t.term, " ");
+            }
+        }
+	strxcat (p->u.t.term, src_str, src_len);
+        ADVANCE;
+    }
+    if (left_trunc && right_trunc)
+    {
+        if (!qual_val_type (qa, CCL_BIB1_TRU, CCL_BIB1_TRU_CAN_BOTH))
+        {
+            cclp->error_code = CCL_ERR_TRUNC_NOT_BOTH;
+            ccl_rpn_delete (p);
+            return NULL;
+        }
+        add_attr (p, CCL_BIB1_TRU, 3);
+    }
+    else if (right_trunc)
+    {
+        if (!qual_val_type (qa, CCL_BIB1_TRU, CCL_BIB1_TRU_CAN_RIGHT))
+        {
+            cclp->error_code = CCL_ERR_TRUNC_NOT_RIGHT;
+            ccl_rpn_delete (p);
+            return NULL;
+        }
+        add_attr (p, CCL_BIB1_TRU, 1);
+    }
+    else if (left_trunc)
+    {
+        if (!qual_val_type (qa, CCL_BIB1_TRU, CCL_BIB1_TRU_CAN_LEFT))
+        {
+            cclp->error_code = CCL_ERR_TRUNC_NOT_LEFT;
+            ccl_rpn_delete (p);
+            return NULL;
+        }
+        add_attr (p, CCL_BIB1_TRU, 2);
+    }
+    else
+    {
+        if (qual_val_type (qa, CCL_BIB1_TRU, CCL_BIB1_TRU_CAN_NONE))
+            add_attr (p, CCL_BIB1_TRU, 100);
+    }
+    return p;
+}
+
+static struct ccl_rpn_node *search_term (CCL_parser cclp,
+					 struct ccl_rpn_attr **qa)
+{
+    static int list[] = {CCL_TOK_TERM, CCL_TOK_COMMA, -1};
+    return search_term_x(cclp, qa, list);
+}
+
+/*
+ * qualifiers: Parse CCL qualifiers and search terms. 
+ * cclp:   CCL Parser
+ * la:     Token pointer to RELATION token.
+ * qa:     Qualifier attributes already applied.
+ * return: pointer to node(s); NULL on error.
+ */
+static struct ccl_rpn_node *qualifiers (CCL_parser cclp, struct ccl_token *la,
+                                        struct ccl_rpn_attr **qa)
+{
+    struct ccl_token *lookahead = cclp->look_token;
+    struct ccl_rpn_attr **ap;
+    int no = 0;
+    int i, rel;
+#if 0
+    if (qa)
+    {
+        cclp->error_code = CCL_ERR_DOUBLE_QUAL;
+        return NULL;
+    }
+#endif
+    for (lookahead = cclp->look_token; lookahead != la;
+	 lookahead=lookahead->next)
+        no++;
+    if (qa)
+        for (i=0; qa[i]; i++)
+	    no++;
+    ap = (struct ccl_rpn_attr **)malloc ((no+1) * sizeof(*ap));
+    ccl_assert (ap);
+    for (i = 0; cclp->look_token != la; i++)
+    {
+        ap[i] = ccl_qual_search (cclp, cclp->look_token->name,
+				 cclp->look_token->len);
+        if (!ap[i])
+        {
+            cclp->error_code = CCL_ERR_UNKNOWN_QUAL;
+            free (ap);
+            return NULL;
+        }
+        ADVANCE;
+        if (KIND == CCL_TOK_COMMA)
+            ADVANCE;
+    }
+    if (qa)
+        while (*qa)
+	    ap[i++] = *qa++;
+    ap[i] = NULL;
+    if (!qual_val_type (ap, CCL_BIB1_REL, CCL_BIB1_REL_ORDER))
+    {                
+        /* unordered relation */
+        struct ccl_rpn_node *p;
+        if (KIND != CCL_TOK_EQ)
+        {
+            cclp->error_code = CCL_ERR_EQ_EXPECTED;
+            free (ap);
+            return NULL;
+        }
+        ADVANCE;
+        if (KIND == CCL_TOK_LP)
+        {
+            ADVANCE;
+            if (!(p = find_spec (cclp, ap)))
+            {
+                free (ap);
+                return NULL;
+            }
+            if (KIND != CCL_TOK_RP)
+            {
+                cclp->error_code = CCL_ERR_RP_EXPECTED;
+                ccl_rpn_delete (p);
+                free (ap);
+                return NULL;
+            }
+            ADVANCE;
+        }
+        else
+            p = search_terms (cclp, ap);
+        free (ap);
+        return p;
+    }
+    /* ordered relation ... */
+    rel = 0;
+    if (cclp->look_token->len == 1)
+    {
+        if (cclp->look_token->name[0] == '<')
+            rel = 1;
+        else if (cclp->look_token->name[0] == '=')
+            rel = 3;
+        else if (cclp->look_token->name[0] == '>')
+            rel = 5;
+    }
+    else if (cclp->look_token->len == 2)
+    {
+        if (!memcmp (cclp->look_token->name, "<=", 2))
+            rel = 2;
+        else if (!memcmp (cclp->look_token->name, ">=", 2))
+            rel = 4;
+        else if (!memcmp (cclp->look_token->name, "<>", 2))
+            rel = 6;
+    }
+    if (!rel)
+        cclp->error_code = CCL_ERR_BAD_RELATION;
+    else
+    {
+        struct ccl_rpn_node *p;
+
+        ADVANCE;                      /* skip relation */
+        if (KIND == CCL_TOK_TERM &&
+	    cclp->look_token->next->kind == CCL_TOK_MINUS)
+        {
+            struct ccl_rpn_node *p1;
+            if (!(p1 = search_term (cclp, ap)))
+	    {
+	        free (ap);
+	        return NULL;
+	    }
+            ADVANCE;                   /* skip '-' */
+            if (KIND == CCL_TOK_TERM)  /* = term - term  ? */
+            {
+                struct ccl_rpn_node *p2;
+                
+                if (!(p2 = search_term (cclp, ap)))
+		{
+                    ccl_rpn_delete (p1);
+		    free (ap);
+		    return NULL;
+		}
+                p = mk_node (CCL_RPN_AND);
+                p->u.p[0] = p1;
+                add_attr (p1, CCL_BIB1_REL, 4);
+                p->u.p[1] = p2;
+                add_attr (p2, CCL_BIB1_REL, 2);
+                free (ap);
+                return p;
+            }
+            else                       /* = term -    */
+            {
+                add_attr (p1, CCL_BIB1_REL, 4);
+                free (ap);
+                return p1;
+            }
+        }
+        else if (KIND == CCL_TOK_MINUS)   /* = - term  ? */
+        {
+            ADVANCE;
+            if (!(p = search_term (cclp, ap)))
+	    {
+	        free (ap);
+		return NULL;
+	    }
+            add_attr (p, CCL_BIB1_REL, 2);
+            free (ap);
+            return p;
+        }
+	else if (KIND == CCL_TOK_LP)
+	{
+            ADVANCE;
+            if (!(p = find_spec (cclp, ap)))
+            {
+                free (ap);
+                return NULL;
+            }
+            if (KIND != CCL_TOK_RP)
+            {
+                cclp->error_code = CCL_ERR_RP_EXPECTED;
+                ccl_rpn_delete (p);
+                free (ap);
+                return NULL;
+            }
+            ADVANCE;
+	    free (ap);
+	    return p;
+	}
+	else
+	{
+            if (!(p = search_terms (cclp, ap)))
+	    {
+	        free (ap);
+		return NULL;
+	    }
+            add_attr (p, CCL_BIB1_REL, rel);
+	    free (ap);
+	    return p;
+	}
+        cclp->error_code = CCL_ERR_TERM_EXPECTED;
+    }
+    free (ap);
+    return NULL;
+}
+
+/*
+ * search_terms: Parse CCL search terms - including proximity.
+ * cclp:   CCL Parser
+ * qa:     Qualifier attributes already applied.
+ * return: pointer to node(s); NULL on error.
+ */
+static struct ccl_rpn_node *search_terms (CCL_parser cclp,
+					  struct ccl_rpn_attr **qa)
+{
+    static int list[] = {
+        CCL_TOK_TERM, CCL_TOK_COMMA,CCL_TOK_EQ,
+        CCL_TOK_REL, CCL_TOK_MINUS, -1};
+    struct ccl_rpn_node *p1, *p2, *pn;
+    p1 = search_term_x (cclp, qa, list);
+    if (!p1)
+        return NULL;
+    while (1)
+    {
+	if (KIND == CCL_TOK_PROX)
+	{
+	    ADVANCE;
+	    p2 = search_term_x (cclp, qa, list);
+            if (!p2)
+            {
+                ccl_rpn_delete (p1);
+                return NULL;
+            }
+	    pn = mk_node (CCL_RPN_PROX);
+	    pn->u.p[0] = p1;
+	    pn->u.p[1] = p2;
+	    p1 = pn;
+	}
+	else if (is_term_ok(KIND, list))
+	{
+	    p2 = search_term_x (cclp, qa, list);
+            if (!p2)
+            {
+                ccl_rpn_delete (p1);
+                return NULL;
+            }
+	    pn = mk_node (CCL_RPN_PROX);
+	    pn->u.p[0] = p1;
+	    pn->u.p[1] = p2;
+	    p1 = pn;
+	}
+	else
+	    break;
+    }
+    return p1;
+}
+
+/*
+ * search_elements: Parse CCL search elements
+ * cclp:   CCL Parser
+ * qa:     Qualifier attributes already applied.
+ * return: pointer to node(s); NULL on error.
+ */
+static struct ccl_rpn_node *search_elements (CCL_parser cclp,
+					     struct ccl_rpn_attr **qa)
+{
+    struct ccl_rpn_node *p1;
+    struct ccl_token *lookahead;
+    if (KIND == CCL_TOK_LP)
+    {
+	ADVANCE;
+	p1 = find_spec (cclp, qa);
+        if (!p1)
+            return NULL;
+        if (KIND != CCL_TOK_RP)
+        {
+            cclp->error_code = CCL_ERR_RP_EXPECTED;
+            ccl_rpn_delete (p1);
+            return NULL;
+        }
+	ADVANCE;
+	return p1;
+    }
+    else if (KIND == CCL_TOK_SET)
+    {
+	ADVANCE;
+        if (KIND == CCL_TOK_EQ)
+            ADVANCE;
+        if (KIND != CCL_TOK_TERM)
+        {
+            cclp->error_code = CCL_ERR_SETNAME_EXPECTED;
+            return NULL;
+        }
+	p1 = mk_node (CCL_RPN_SET);
+	p1->u.setname = copy_token_name (cclp->look_token);
+	ADVANCE;
+	return p1;
+    }
+    lookahead = cclp->look_token;
+
+    while (lookahead->kind==CCL_TOK_TERM)
+    {
+        lookahead = lookahead->next;
+        if (lookahead->kind == CCL_TOK_REL || lookahead->kind == CCL_TOK_EQ)
+	    return qualifiers (cclp, lookahead, qa);
+        if (lookahead->kind != CCL_TOK_COMMA)
+            break;
+        lookahead = lookahead->next;
+    }
+    return search_terms (cclp, qa);
+}
+
+/*
+ * find_spec: Parse CCL find specification
+ * cclp:   CCL Parser
+ * qa:     Qualifier attributes already applied.
+ * return: pointer to node(s); NULL on error.
+ */
+static struct ccl_rpn_node *find_spec (CCL_parser cclp,
+				       struct ccl_rpn_attr **qa)
+{
+    struct ccl_rpn_node *p1, *p2, *pn;
+    if (!(p1 = search_elements (cclp, qa)))
+        return NULL;
+    while (1)
+    {
+	switch (KIND)
+	{
+	case CCL_TOK_AND:
+	    ADVANCE;
+	    p2 = search_elements (cclp, qa);
+            if (!p2)
+            {
+                ccl_rpn_delete (p1);
+                return NULL;
+            }
+	    pn = mk_node (CCL_RPN_AND);
+	    pn->u.p[0] = p1;
+	    pn->u.p[1] = p2;
+	    p1 = pn;
+	    continue;
+	case CCL_TOK_OR:
+	    ADVANCE;
+	    p2 = search_elements (cclp, qa);
+            if (!p2)
+            {
+                ccl_rpn_delete (p1);
+                return NULL;
+            }
+	    pn = mk_node (CCL_RPN_OR);
+	    pn->u.p[0] = p1;
+	    pn->u.p[1] = p2;
+	    p1 = pn;
+	    continue;
+	case CCL_TOK_NOT:
+	    ADVANCE;
+	    p2 = search_elements (cclp, qa);
+            if (!p2)
+            {
+                ccl_rpn_delete (p1);
+                return NULL;
+            }
+	    pn = mk_node (CCL_RPN_NOT);
+	    pn->u.p[0] = p1;
+	    pn->u.p[1] = p2;
+	    p1 = pn;
+	    continue;
+	}
+	break;
+    }
+    return p1;
+}
+
+struct ccl_rpn_node *ccl_parser_find (CCL_parser cclp, struct ccl_token *list)
+{
+    struct ccl_rpn_node *p;
+
+    cclp->look_token = list;
+    p = find_spec (cclp, NULL);
+    if (p && KIND != CCL_TOK_EOL)
+    {
+        if (KIND == CCL_TOK_RP)
+            cclp->error_code = CCL_ERR_BAD_RP;
+        else
+            cclp->error_code = CCL_ERR_OP_EXPECTED;
+        ccl_rpn_delete (p);
+        p = NULL;
+    }
+    cclp->error_pos = cclp->look_token->name;
+    if (p)
+        cclp->error_code = CCL_ERR_OK;
+    else
+        cclp->error_code = cclp->error_code;
+    return p;
+}
+
+/*
+ * ccl_find: Parse CCL find - token representation
+ * bibset:  Bibset to be used for the parsing
+ * list:    List of tokens
+ * error:   Pointer to integer. Holds error no. on completion.
+ * pos:     Pointer to char position. Holds approximate error position.
+ * return:  RPN tree on successful completion; NULL otherwise.
+ */
+struct ccl_rpn_node *ccl_find (CCL_bibset bibset, struct ccl_token *list,
+                               int *error, const char **pos)
+{
+    struct ccl_rpn_node *p;
+    CCL_parser cclp = ccl_parser_create ();
+
+    cclp->bibset = bibset;
+
+    p = ccl_parser_find (cclp, list);
+
+    *error = cclp->error_code;
+    *pos = cclp->error_pos;
+
+    ccl_parser_destroy (cclp);
+
+    return p;
+}
+
+/*
+ * ccl_find_str: Parse CCL find - string representation
+ * bibset:  Bibset to be used for the parsing
+ * str:     String to be parsed
+ * error:   Pointer to integer. Holds error no. on completion.
+ * pos:     Pointer to char position. Holds approximate error position.
+ * return:  RPN tree on successful completion; NULL otherwise.
+ */
+struct ccl_rpn_node *ccl_find_str (CCL_bibset bibset, const char *str,
+                                   int *error, int *pos)
+{
+    CCL_parser cclp = ccl_parser_create ();
+    struct ccl_token *list;
+    struct ccl_rpn_node *p;
+
+    cclp->bibset = bibset;
+
+    list = ccl_parser_tokenize (cclp, str);
+    p = ccl_parser_find (cclp, list);
+
+    *error = cclp->error_code;
+    if (*error)
+        *pos = cclp->error_pos - str;
+    ccl_parser_destroy (cclp);
+    ccl_token_del (list);
+    return p;
+}
Index: /main/tags/2.25/gsdl/packages/yaz/ccl/cclptree.c
===================================================================
--- /main/tags/2.25/gsdl/packages/yaz/ccl/cclptree.c	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/yaz/ccl/cclptree.c	(revision 21064)
@@ -0,0 +1,138 @@
+/*
+ * Copyright (c) 1995, the EUROPAGATE consortium (see below).
+ *
+ * The EUROPAGATE consortium members are:
+ *
+ *    University College Dublin
+ *    Danmarks Teknologiske Videnscenter
+ *    An Chomhairle Leabharlanna
+ *    Consejo Superior de Investigaciones Cientificas
+ *
+ * Permission to use, copy, modify, distribute, and sell this software and
+ * its documentation, in whole or in part, for any purpose, is hereby granted,
+ * provided that:
+ *
+ * 1. This copyright and permission notice appear in all copies of the
+ * software and its documentation. Notices of copyright or attribution
+ * which appear at the beginning of any file must remain unchanged.
+ *
+ * 2. The names of EUROPAGATE or the project partners may not be used to
+ * endorse or promote products derived from this software without specific
+ * prior written permission.
+ *
+ * 3. Users of this software (implementors and gateway operators) agree to
+ * inform the EUROPAGATE consortium of their use of the software. This
+ * information will be used to evaluate the EUROPAGATE project and the
+ * software, and to plan further developments. The consortium may use
+ * the information in later publications.
+ * 
+ * 4. Users of this software agree to make their best efforts, when
+ * documenting their use of the software, to acknowledge the EUROPAGATE
+ * consortium, and the role played by the software in their work.
+ *
+ * THIS SOFTWARE IS PROVIDED "AS IS" AND WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS, IMPLIED, OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY
+ * WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
+ * IN NO EVENT SHALL THE EUROPAGATE CONSORTIUM OR ITS MEMBERS BE LIABLE
+ * FOR ANY SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF
+ * ANY KIND, OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA
+ * OR PROFITS, WHETHER OR NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND
+ * ON ANY THEORY OF LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE
+ * USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ */
+/* CCL print rpn tree - infix notation
+ * Europagate, 1995
+ *
+ * $Log$
+ * Revision 1.1  2000/08/03 03:09:56  johnmcp
+ * Added the YAZ toolkit source to the packages directory (for z39.50 stuff)
+ *
+ * Revision 1.7  2000/01/31 13:15:21  adam
+ * Removed uses of assert(3). Cleanup of ODR. CCL parser update so
+ * that some characters are not surrounded by spaces in resulting term.
+ * ILL-code updates.
+ *
+ * Revision 1.6  1999/11/30 13:47:11  adam
+ * Improved installation. Moved header files to include/yaz.
+ *
+ * Revision 1.5  1997/04/30 08:52:06  quinn
+ * Null
+ *
+ * Revision 1.4  1996/10/11  15:00:25  adam
+ * CCL parser from Europagate Email gateway 1.0.
+ *
+ * Revision 1.6  1995/05/16  09:39:26  adam
+ * LICENSE.
+ *
+ * Revision 1.5  1995/02/23  08:31:59  adam
+ * Changed header.
+ *
+ * Revision 1.3  1995/02/15  17:42:16  adam
+ * Minor changes of the api of this module. FILE* argument added
+ * to ccl_pr_tree.
+ *
+ * Revision 1.2  1995/02/14  19:55:11  adam
+ * Header files ccl.h/cclp.h are gone! They have been merged an
+ * moved to ../include/ccl.h.
+ * Node kind(s) in ccl_rpn_node have changed names.
+ *
+ * Revision 1.1  1995/02/14  10:25:56  adam
+ * The constructions 'qualifier rel term ...' implemented.
+ *
+ */
+
+#include <stdio.h>
+#include <string.h>
+
+#include <yaz/ccl.h>
+
+void ccl_pr_tree (struct ccl_rpn_node *rpn, FILE *fd_out)
+{
+
+    switch (rpn->kind)
+    {
+    case CCL_RPN_TERM:
+	fprintf (fd_out, "\"%s\"", rpn->u.t.term);
+        if (rpn->u.t.attr_list)
+        {
+            struct ccl_rpn_attr *attr;
+            for (attr = rpn->u.t.attr_list; attr; attr = attr->next)
+                fprintf (fd_out, " %d=%d", attr->type, attr->value);
+        }
+	break;
+    case CCL_RPN_AND:
+	fprintf (fd_out, "(");
+	ccl_pr_tree (rpn->u.p[0], fd_out);
+	fprintf (fd_out, ") and (");
+	ccl_pr_tree (rpn->u.p[1], fd_out);
+	fprintf (fd_out, ")");
+	break;
+    case CCL_RPN_OR:
+	fprintf (fd_out, "(");
+	ccl_pr_tree (rpn->u.p[0], fd_out);
+	fprintf (fd_out, ") or (");
+	ccl_pr_tree (rpn->u.p[1], fd_out);
+	fprintf (fd_out, ")");
+	break;
+    case CCL_RPN_NOT:
+	fprintf (fd_out, "(");
+	ccl_pr_tree (rpn->u.p[0], fd_out);
+	fprintf (fd_out, ") not (");
+	ccl_pr_tree (rpn->u.p[1], fd_out);
+	fprintf (fd_out, ")");
+	break;
+    case CCL_RPN_SET:
+	fprintf (fd_out, "set=%s", rpn->u.setname);
+	break;
+    case CCL_RPN_PROX:
+	fprintf (fd_out, "(");
+	ccl_pr_tree (rpn->u.p[0], fd_out);
+	fprintf (fd_out, ") prox (");
+	ccl_pr_tree (rpn->u.p[1], fd_out);
+	fprintf (fd_out, ")");
+	break;
+    default:
+	ccl_assert (0);
+    }
+}
Index: /main/tags/2.25/gsdl/packages/yaz/ccl/cclqfile.c
===================================================================
--- /main/tags/2.25/gsdl/packages/yaz/ccl/cclqfile.c	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/yaz/ccl/cclqfile.c	(revision 21064)
@@ -0,0 +1,193 @@
+/*
+ * Copyright (c) 1995, the EUROPAGATE consortium (see below).
+ *
+ * The EUROPAGATE consortium members are:
+ *
+ *    University College Dublin
+ *    Danmarks Teknologiske Videnscenter
+ *    An Chomhairle Leabharlanna
+ *    Consejo Superior de Investigaciones Cientificas
+ *
+ * Permission to use, copy, modify, distribute, and sell this software and
+ * its documentation, in whole or in part, for any purpose, is hereby granted,
+ * provided that:
+ *
+ * 1. This copyright and permission notice appear in all copies of the
+ * software and its documentation. Notices of copyright or attribution
+ * which appear at the beginning of any file must remain unchanged.
+ *
+ * 2. The names of EUROPAGATE or the project partners may not be used to
+ * endorse or promote products derived from this software without specific
+ * prior written permission.
+ *
+ * 3. Users of this software (implementors and gateway operators) agree to
+ * inform the EUROPAGATE consortium of their use of the software. This
+ * information will be used to evaluate the EUROPAGATE project and the
+ * software, and to plan further developments. The consortium may use
+ * the information in later publications.
+ * 
+ * 4. Users of this software agree to make their best efforts, when
+ * documenting their use of the software, to acknowledge the EUROPAGATE
+ * consortium, and the role played by the software in their work.
+ *
+ * THIS SOFTWARE IS PROVIDED "AS IS" AND WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS, IMPLIED, OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY
+ * WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
+ * IN NO EVENT SHALL THE EUROPAGATE CONSORTIUM OR ITS MEMBERS BE LIABLE
+ * FOR ANY SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF
+ * ANY KIND, OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA
+ * OR PROFITS, WHETHER OR NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND
+ * ON ANY THEORY OF LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE
+ * USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ */
+/* CCL qualifiers
+ * Europagate, 1995
+ *
+ * $Log$
+ * Revision 1.1  2000/08/03 03:09:57  johnmcp
+ * Added the YAZ toolkit source to the packages directory (for z39.50 stuff)
+ *
+ * Revision 1.4  2000/01/31 13:15:21  adam
+ * Removed uses of assert(3). Cleanup of ODR. CCL parser update so
+ * that some characters are not surrounded by spaces in resulting term.
+ * ILL-code updates.
+ *
+ * Revision 1.3  1999/11/30 13:47:11  adam
+ * Improved installation. Moved header files to include/yaz.
+ *
+ * Revision 1.2  1997/04/30 08:52:06  quinn
+ * Null
+ *
+ * Revision 1.1  1996/10/11  15:00:25  adam
+ * CCL parser from Europagate Email gateway 1.0.
+ *
+ * Revision 1.3  1995/05/16  09:39:26  adam
+ * LICENSE.
+ *
+ * Revision 1.2  1995/05/11  14:03:56  adam
+ * Changes in the reading of qualifier(s). New function: ccl_qual_fitem.
+ * New variable ccl_case_sensitive, which controls whether reserved
+ * words and field names are case sensitive or not.
+ *
+ * Revision 1.1  1995/04/17  09:31:45  adam
+ * Improved handling of qualifiers. Aliases or reserved words.
+ *
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <yaz/ccl.h>
+
+void ccl_qual_fitem (CCL_bibset bibset, const char *cp, const char *qual_name)
+{
+    char qual_type[128];
+    int no_scan;
+    int pair[128];
+    int pair_no = 0;
+
+    while (1)
+    {
+        char *qual_value;
+        char *split;
+        
+        if (sscanf (cp, "%s%n", qual_type, &no_scan) != 1)
+            break;
+        
+        if (!(split = strchr (qual_type, '=')))
+            break;
+        cp += no_scan;
+        
+        *split++ = '\0';
+        while (1)
+        {
+            int type, value;
+
+            qual_value = split;
+            if ((split = strchr (qual_value, ',')))
+                *split++ = '\0';
+            value = atoi (qual_value);
+            switch (qual_type[0])
+            {
+            case 'u':
+            case 'U':
+                type = CCL_BIB1_USE;
+                break;
+            case 'r':
+            case 'R':
+                type = CCL_BIB1_REL;
+                if (!ccl_stricmp (qual_value, "o"))
+                    value = CCL_BIB1_REL_ORDER;
+                break;                
+            case 'p':
+            case 'P':
+                type = CCL_BIB1_POS;
+                break;
+            case 's':
+            case 'S':
+                type = CCL_BIB1_STR;
+                if (!ccl_stricmp (qual_value, "pw"))
+                    value = CCL_BIB1_STR_WP;
+                break;                
+            case 't':
+            case 'T':
+                type = CCL_BIB1_TRU;
+                if (!ccl_stricmp (qual_value, "l"))
+                    value = CCL_BIB1_TRU_CAN_LEFT;
+                else if (!ccl_stricmp (qual_value, "r"))
+                    value = CCL_BIB1_TRU_CAN_RIGHT;
+                else if (!ccl_stricmp (qual_value, "b"))
+                    value = CCL_BIB1_TRU_CAN_BOTH;
+                else if (!ccl_stricmp (qual_value, "n"))
+                    value = CCL_BIB1_TRU_CAN_NONE;
+                break;                
+            case 'c':
+            case 'C':
+                type = CCL_BIB1_COM;
+                break;                
+            default:
+                type = atoi (qual_type);
+            }
+            pair[pair_no*2] = type;
+            pair[pair_no*2+1] = value;
+            pair_no++;
+            if (!split)
+                break;
+        }
+    }
+    ccl_qual_add (bibset, qual_name, pair_no, pair);
+}
+
+/*
+ * ccl_qual_file: Read bibset definition from file.
+ * bibset:  Bibset
+ * inf:     FILE pointer.
+ *
+ * Each line format is:
+ *  <name> <t>=<v> <t>=<v> ....
+ *  Where <name> is name of qualifier;
+ *  <t>=<v> is a attribute definition pair where <t> is one of: 
+ *     u(use), r(relation), p(position), t(truncation), c(completeness) 
+ *     or plain integer.
+ *  <v> is an integer or special pseudo-value.
+ */
+void ccl_qual_file (CCL_bibset bibset, FILE *inf)
+{
+    char line[256];
+    char *cp;
+    char qual_name[128];
+    int  no_scan;
+
+    while (fgets (line, 255, inf))
+    {
+        cp = line;
+        if (*cp == '#')
+            continue;        /* ignore lines starting with # */
+        if (sscanf (cp, "%s%n", qual_name, &no_scan) != 1)
+            continue;        /* also ignore empty lines */
+        cp += no_scan;
+        ccl_qual_fitem (bibset, cp, qual_name);
+    }
+}
Index: /main/tags/2.25/gsdl/packages/yaz/ccl/cclqual.c
===================================================================
--- /main/tags/2.25/gsdl/packages/yaz/ccl/cclqual.c	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/yaz/ccl/cclqual.c	(revision 21064)
@@ -0,0 +1,246 @@
+/*
+ * Copyright (c) 1995, the EUROPAGATE consortium (see below).
+ *
+ * The EUROPAGATE consortium members are:
+ *
+ *    University College Dublin
+ *    Danmarks Teknologiske Videnscenter
+ *    An Chomhairle Leabharlanna
+ *    Consejo Superior de Investigaciones Cientificas
+ *
+ * Permission to use, copy, modify, distribute, and sell this software and
+ * its documentation, in whole or in part, for any purpose, is hereby granted,
+ * provided that:
+ *
+ * 1. This copyright and permission notice appear in all copies of the
+ * software and its documentation. Notices of copyright or attribution
+ * which appear at the beginning of any file must remain unchanged.
+ *
+ * 2. The names of EUROPAGATE or the project partners may not be used to
+ * endorse or promote products derived from this software without specific
+ * prior written permission.
+ *
+ * 3. Users of this software (implementors and gateway operators) agree to
+ * inform the EUROPAGATE consortium of their use of the software. This
+ * information will be used to evaluate the EUROPAGATE project and the
+ * software, and to plan further developments. The consortium may use
+ * the information in later publications.
+ * 
+ * 4. Users of this software agree to make their best efforts, when
+ * documenting their use of the software, to acknowledge the EUROPAGATE
+ * consortium, and the role played by the software in their work.
+ *
+ * THIS SOFTWARE IS PROVIDED "AS IS" AND WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS, IMPLIED, OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY
+ * WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
+ * IN NO EVENT SHALL THE EUROPAGATE CONSORTIUM OR ITS MEMBERS BE LIABLE
+ * FOR ANY SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF
+ * ANY KIND, OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA
+ * OR PROFITS, WHETHER OR NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND
+ * ON ANY THEORY OF LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE
+ * USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ */
+/* CCL qualifiers
+ * Europagate, 1995
+ *
+ * $Log$
+ * Revision 1.1  2000/08/03 03:09:58  johnmcp
+ * Added the YAZ toolkit source to the packages directory (for z39.50 stuff)
+ *
+ * Revision 1.13  2000/01/31 13:15:21  adam
+ * Removed uses of assert(3). Cleanup of ODR. CCL parser update so
+ * that some characters are not surrounded by spaces in resulting term.
+ * ILL-code updates.
+ *
+ * Revision 1.12  1999/11/30 13:47:11  adam
+ * Improved installation. Moved header files to include/yaz.
+ *
+ * Revision 1.11  1999/03/31 11:15:37  adam
+ * Fixed memory leaks in ccl_find_str and ccl_qual_rm.
+ *
+ * Revision 1.10  1998/07/07 15:49:40  adam
+ * Added braces to avoid warning.
+ *
+ * Revision 1.9  1998/02/11 11:53:33  adam
+ * Changed code so that it compiles as C++.
+ *
+ * Revision 1.8  1997/09/29 08:56:38  adam
+ * Changed CCL parser to be thread safe. New type, CCL_parser, declared
+ * and a create/destructers ccl_parser_create/ccl_parser/destory has
+ * been added.
+ *
+ * Revision 1.7  1997/09/01 08:48:12  adam
+ * New windows NT/95 port using MSV5.0. Only a few changes made
+ * to avoid warnings.
+ *
+ * Revision 1.6  1997/04/30 08:52:07  quinn
+ * Null
+ *
+ * Revision 1.5  1996/10/11  15:00:25  adam
+ * CCL parser from Europagate Email gateway 1.0.
+ *
+ * Revision 1.9  1995/05/16  09:39:27  adam
+ * LICENSE.
+ *
+ * Revision 1.8  1995/05/11  14:03:57  adam
+ * Changes in the reading of qualifier(s). New function: ccl_qual_fitem.
+ * New variable ccl_case_sensitive, which controls whether reserved
+ * words and field names are case sensitive or not.
+ *
+ * Revision 1.7  1995/04/17  09:31:46  adam
+ * Improved handling of qualifiers. Aliases or reserved words.
+ *
+ * Revision 1.6  1995/02/23  08:32:00  adam
+ * Changed header.
+ *
+ * Revision 1.4  1995/02/14  19:55:12  adam
+ * Header files ccl.h/cclp.h are gone! They have been merged an
+ * moved to ../include/ccl.h.
+ * Node kind(s) in ccl_rpn_node have changed names.
+ *
+ * Revision 1.3  1995/02/14  16:20:56  adam
+ * Qualifiers are read from a file now.
+ *
+ * Revision 1.2  1995/02/14  10:25:56  adam
+ * The constructions 'qualifier rel term ...' implemented.
+ *
+ * Revision 1.1  1995/02/13  15:15:07  adam
+ * Added handling of qualifiers. Not finished yet.
+ *
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <yaz/ccl.h>
+
+/* Definition of CCL_bibset pointer */
+struct ccl_qualifiers {
+    struct ccl_qualifier *list;
+};
+
+/*
+ * ccl_qual_add: Add qualifier to Bibset. If qualifier already
+ *               exists, then attributes are appendend to old
+ *               definition.
+ * name:    name of qualifier
+ * no:      No of attribute type/value pairs.
+ * pairs:   Attributes. pairs[0] first type, pair[1] first value,
+ *          ... pair[2*no-2] last type, pair[2*no-1] last value.
+ */
+void ccl_qual_add (CCL_bibset b, const char *name, int no, int *pairs)
+{
+    struct ccl_qualifier *q;
+    struct ccl_rpn_attr **attrp;
+
+    ccl_assert (b);
+    for (q = b->list; q; q = q->next)
+        if (!strcmp (name, q->name))
+            break;
+    if (!q)
+    {
+        struct ccl_qualifier *new_qual =
+	    (struct ccl_qualifier *)malloc (sizeof(*new_qual));
+        ccl_assert (new_qual);
+        
+        new_qual->next = b->list;
+        b->list = new_qual;
+        
+        new_qual->name = (char *)malloc (strlen(name)+1);
+        ccl_assert (new_qual->name);
+        strcpy (new_qual->name, name);
+        attrp = &new_qual->attr_list;
+    }
+    else
+    {
+        attrp = &q->attr_list;
+        while (*attrp)
+            attrp = &(*attrp)->next;
+    }
+    while (--no >= 0)
+    {
+        struct ccl_rpn_attr *attr;
+
+        attr = (struct ccl_rpn_attr *)malloc (sizeof(*attr));
+        ccl_assert (attr);
+        attr->type = *pairs++;
+        attr->value = *pairs++;
+        *attrp = attr;
+        attrp = &attr->next;
+    }
+    *attrp = NULL;
+}
+
+/*
+ * ccl_qual_mk: Make new (empty) bibset.
+ * return:   empty bibset.
+ */
+CCL_bibset ccl_qual_mk (void)
+{
+    CCL_bibset b = (CCL_bibset)malloc (sizeof(*b));
+    ccl_assert (b);
+    b->list = NULL;     
+    return b;
+}
+
+/*
+ * ccl_qual_rm: Delete bibset.
+ * b:        pointer to bibset
+ */
+void ccl_qual_rm (CCL_bibset *b)
+{
+    struct ccl_qualifier *q, *q1;
+
+    if (!*b)
+        return;
+    for (q = (*b)->list; q; q = q1)
+    {
+        struct ccl_rpn_attr *attr, *attr1;
+
+        for (attr = q->attr_list; attr; attr = attr1)
+	{
+	    attr1 = attr->next;
+	    free (attr);
+	}
+        q1 = q->next;
+	free (q->name);
+	free (q);
+    }
+    free (*b);
+    *b = NULL;
+}
+
+/*
+ * ccl_qual_search: Search for qualifier in bibset.
+ * b:      Bibset
+ * name:   Name of qualifier to search for (need no null-termination)
+ * len:    Length of name.
+ * return: Attribute info. NULL if not found.
+ */
+struct ccl_rpn_attr *ccl_qual_search (CCL_parser cclp,
+				      const char *name, size_t len)
+{
+    struct ccl_qualifier *q;
+
+    ccl_assert (cclp);
+    if (!cclp->bibset)
+	return NULL;
+    for (q = cclp->bibset->list; q; q = q->next)
+        if (strlen(q->name) == len)
+        {
+            if (cclp->ccl_case_sensitive)
+            {
+                if (!memcmp (name, q->name, len))
+                    return q->attr_list;
+            }
+            else
+            {
+                if (!ccl_memicmp (name, q->name, len))
+                    return q->attr_list;
+            }
+        }
+    return NULL;
+}
+
Index: /main/tags/2.25/gsdl/packages/yaz/ccl/cclsh.c
===================================================================
--- /main/tags/2.25/gsdl/packages/yaz/ccl/cclsh.c	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/yaz/ccl/cclsh.c	(revision 21064)
@@ -0,0 +1,196 @@
+/*
+ * Copyright (c) 1995, the EUROPAGATE consortium (see below).
+ *
+ * The EUROPAGATE consortium members are:
+ *
+ *    University College Dublin
+ *    Danmarks Teknologiske Videnscenter
+ *    An Chomhairle Leabharlanna
+ *    Consejo Superior de Investigaciones Cientificas
+ *
+ * Permission to use, copy, modify, distribute, and sell this software and
+ * its documentation, in whole or in part, for any purpose, is hereby granted,
+ * provided that:
+ *
+ * 1. This copyright and permission notice appear in all copies of the
+ * software and its documentation. Notices of copyright or attribution
+ * which appear at the beginning of any file must remain unchanged.
+ *
+ * 2. The names of EUROPAGATE or the project partners may not be used to
+ * endorse or promote products derived from this software without specific
+ * prior written permission.
+ *
+ * 3. Users of this software (implementors and gateway operators) agree to
+ * inform the EUROPAGATE consortium of their use of the software. This
+ * information will be used to evaluate the EUROPAGATE project and the
+ * software, and to plan further developments. The consortium may use
+ * the information in later publications.
+ * 
+ * 4. Users of this software agree to make their best efforts, when
+ * documenting their use of the software, to acknowledge the EUROPAGATE
+ * consortium, and the role played by the software in their work.
+ *
+ * THIS SOFTWARE IS PROVIDED "AS IS" AND WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS, IMPLIED, OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY
+ * WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
+ * IN NO EVENT SHALL THE EUROPAGATE CONSORTIUM OR ITS MEMBERS BE LIABLE
+ * FOR ANY SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF
+ * ANY KIND, OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA
+ * OR PROFITS, WHETHER OR NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND
+ * ON ANY THEORY OF LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE
+ * USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ */
+/* CCL shell.
+ * Europagate 1995
+ *
+ * $Log$
+ * Revision 1.1  2000/08/03 03:09:58  johnmcp
+ * Added the YAZ toolkit source to the packages directory (for z39.50 stuff)
+ *
+ * Revision 1.6  2000/01/31 13:15:21  adam
+ * Removed uses of assert(3). Cleanup of ODR. CCL parser update so
+ * that some characters are not surrounded by spaces in resulting term.
+ * ILL-code updates.
+ *
+ * Revision 1.5  1999/12/16 23:36:19  adam
+ * Implemented ILL protocol. Minor updates ASN.1 compiler.
+ *
+ * Revision 1.4  1999/03/31 11:15:37  adam
+ * Fixed memory leaks in ccl_find_str and ccl_qual_rm.
+ *
+ * Revision 1.3  1997/04/30 08:52:07  quinn
+ * Null
+ *
+ * Revision 1.2  1996/10/11  15:00:25  adam
+ * CCL parser from Europagate Email gateway 1.0.
+ *
+ * Revision 1.11  1995/05/16  09:39:27  adam
+ * LICENSE.
+ *
+ * Revision 1.10  1995/05/11  14:03:57  adam
+ * Changes in the reading of qualifier(s). New function: ccl_qual_fitem.
+ * New variable ccl_case_sensitive, which controls whether reserved
+ * words and field names are case sensitive or not.
+ *
+ * Revision 1.9  1995/02/23  08:32:00  adam
+ * Changed header.
+ *
+ * Revision 1.7  1995/02/15  17:42:16  adam
+ * Minor changes of the api of this module. FILE* argument added
+ * to ccl_pr_tree.
+ *
+ * Revision 1.6  1995/02/14  19:55:13  adam
+ * Header files ccl.h/cclp.h are gone! They have been merged an
+ * moved to ../include/ccl.h.
+ * Node kind(s) in ccl_rpn_node have changed names.
+ *
+ * Revision 1.5  1995/02/14  16:20:57  adam
+ * Qualifiers are read from a file now.
+ *
+ * Revision 1.4  1995/02/14  14:12:42  adam
+ * Ranges for ordered qualfiers implemented (e.g. pd=1980-1990).
+ *
+ * Revision 1.3  1995/02/14  10:25:57  adam
+ * The constructions 'qualifier rel term ...' implemented.
+ *
+ * Revision 1.2  1995/02/13  15:15:07  adam
+ * Added handling of qualifiers. Not finished yet.
+ *
+ * Revision 1.1  1995/02/13  12:35:21  adam
+ * First version of CCL. Qualifiers aren't handled yet.
+ *
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+
+#include <yaz/ccl.h>
+
+static int debug = 0;
+static char *prog;
+
+int main (int argc, char **argv)
+{
+    CCL_bibset bibset;
+    FILE *bib_inf;
+    char *bib_fname;
+
+    prog = *argv;
+    bibset = ccl_qual_mk ();    
+    while (--argc > 0)
+    {
+        if (**++argv == '-')
+        {
+            switch (argv[0][1])
+            {
+            case 'd':
+                debug = 1;
+                break;
+            case 'b':
+                if (argv[0][2])
+                    bib_fname = argv[0]+2;
+                else if (argc > 0)
+                {
+                    --argc;
+                    bib_fname = *++argv;
+                }
+                else
+                {
+                    fprintf (stderr, "%s: missing bib filename\n", prog);
+                    exit (1);
+                }
+                bib_inf = fopen (bib_fname, "r");
+                if (!bib_inf)
+                {
+                    fprintf (stderr, "%s: cannot open %s\n", prog,
+                             bib_fname);
+                    exit (1);
+                }
+                ccl_qual_file (bibset, bib_inf);
+                fclose (bib_inf);
+                break;
+            default:
+                fprintf (stderr, "%s: unknown option '%s'\n",
+                    prog, *argv);
+                exit (1);
+            }
+        }
+        else
+        {
+            fprintf (stderr, "%s: no filenames, please\n", prog);
+            exit (1);
+        }
+    }
+    while (1)
+    {
+        char buf[80];
+        int i, error, pos;
+        struct ccl_rpn_node *rpn;
+
+	printf ("CCLSH>"); fflush (stdout);
+	if (!fgets (buf, 79, stdin))
+	    break;
+        for (i = 0; i<1; i++)
+        {
+	    rpn = ccl_find_str (bibset, buf, &error, &pos);
+            if (error)
+            {
+                printf ("%*s^ - ", 6+pos, " ");
+                printf ("%s\n", ccl_err_msg (error));
+            }
+            else
+            {
+		if (rpn && i == 0)
+		{
+		    ccl_pr_tree (rpn, stdout);
+		    putchar ('\n');
+		}
+            }
+            if (rpn)
+                ccl_rpn_delete(rpn);
+        }
+    }
+    putchar ('\n');
+    return 0;
+}
Index: /main/tags/2.25/gsdl/packages/yaz/ccl/cclstr.c
===================================================================
--- /main/tags/2.25/gsdl/packages/yaz/ccl/cclstr.c	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/yaz/ccl/cclstr.c	(revision 21064)
@@ -0,0 +1,119 @@
+/*
+ * Copyright (c) 1995, the EUROPAGATE consortium (see below).
+ *
+ * The EUROPAGATE consortium members are:
+ *
+ *    University College Dublin
+ *    Danmarks Teknologiske Videnscenter
+ *    An Chomhairle Leabharlanna
+ *    Consejo Superior de Investigaciones Cientificas
+ *
+ * Permission to use, copy, modify, distribute, and sell this software and
+ * its documentation, in whole or in part, for any purpose, is hereby granted,
+ * provided that:
+ *
+ * 1. This copyright and permission notice appear in all copies of the
+ * software and its documentation. Notices of copyright or attribution
+ * which appear at the beginning of any file must remain unchanged.
+ *
+ * 2. The names of EUROPAGATE or the project partners may not be used to
+ * endorse or promote products derived from this software without specific
+ * prior written permission.
+ *
+ * 3. Users of this software (implementors and gateway operators) agree to
+ * inform the EUROPAGATE consortium of their use of the software. This
+ * information will be used to evaluate the EUROPAGATE project and the
+ * software, and to plan further developments. The consortium may use
+ * the information in later publications.
+ * 
+ * 4. Users of this software agree to make their best efforts, when
+ * documenting their use of the software, to acknowledge the EUROPAGATE
+ * consortium, and the role played by the software in their work.
+ *
+ * THIS SOFTWARE IS PROVIDED "AS IS" AND WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS, IMPLIED, OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY
+ * WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
+ * IN NO EVENT SHALL THE EUROPAGATE CONSORTIUM OR ITS MEMBERS BE LIABLE
+ * FOR ANY SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF
+ * ANY KIND, OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA
+ * OR PROFITS, WHETHER OR NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND
+ * ON ANY THEORY OF LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE
+ * USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ */
+/* CCL string compare utilities
+ * Europagate, 1995
+ *
+ * $Log$
+ * Revision 1.1  2000/08/03 03:09:59  johnmcp
+ * Added the YAZ toolkit source to the packages directory (for z39.50 stuff)
+ *
+ * Revision 1.3  1999/11/30 13:47:11  adam
+ * Improved installation. Moved header files to include/yaz.
+ *
+ * Revision 1.2  1997/04/30 08:52:07  quinn
+ * Null
+ *
+ * Revision 1.1  1996/10/11  15:00:26  adam
+ * CCL parser from Europagate Email gateway 1.0.
+ *
+ * Revision 1.3  1996/01/24  10:11:19  adam
+ * Added include of stdlib.h.
+ *
+ * Revision 1.2  1995/05/16  09:39:27  adam
+ * LICENSE.
+ *
+ * Revision 1.1  1995/05/11  14:03:57  adam
+ * Changes in the reading of qualifier(s). New function: ccl_qual_fitem.
+ * New variable ccl_case_sensitive, which controls whether reserved
+ * words and field names are case sensitive or not.
+ *
+ */
+#include <ctype.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+#include <yaz/ccl.h>
+
+static int ccli_toupper (int c)
+{
+    return toupper (c);
+}
+
+int (*ccl_toupper)(int c) = NULL;
+
+int ccl_stricmp (const char *s1, const char *s2)
+{
+    if (!ccl_toupper)
+        ccl_toupper = ccli_toupper;
+    while (*s1 && *s2)
+    {
+        int c1, c2;
+        c1 = (*ccl_toupper)(*s1);
+        c2 = (*ccl_toupper)(*s2);
+        if (c1 != c2)
+            return c1 - c2;
+        s1++;
+        s2++;
+    }
+    return (*ccl_toupper)(*s1) - (*ccl_toupper)(*s2);
+}
+
+int ccl_memicmp (const char *s1, const char *s2, size_t n)
+{
+    if (!ccl_toupper)
+        ccl_toupper = ccli_toupper;
+    while (1)
+    {
+        int c1, c2;
+
+        c1 = (*ccl_toupper)(*s1);
+        c2 = (*ccl_toupper)(*s2);
+        if (n <= 1 || c1 != c2)
+            return c1 - c2;
+        s1++;
+        s2++;
+        --n;
+    }
+}
+
Index: /main/tags/2.25/gsdl/packages/yaz/ccl/ccltoken.c
===================================================================
--- /main/tags/2.25/gsdl/packages/yaz/ccl/ccltoken.c	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/yaz/ccl/ccltoken.c	(revision 21064)
@@ -0,0 +1,419 @@
+/*
+ * Copyright (c) 1995, the EUROPAGATE consortium (see below).
+ *
+ * The EUROPAGATE consortium members are:
+ *
+ *    University College Dublin
+ *    Danmarks Teknologiske Videnscenter
+ *    An Chomhairle Leabharlanna
+ *    Consejo Superior de Investigaciones Cientificas
+ *
+ * Permission to use, copy, modify, distribute, and sell this software and
+ * its documentation, in whole or in part, for any purpose, is hereby granted,
+ * provided that:
+ *
+ * 1. This copyright and permission notice appear in all copies of the
+ * software and its documentation. Notices of copyright or attribution
+ * which appear at the beginning of any file must remain unchanged.
+ *
+ * 2. The names of EUROPAGATE or the project partners may not be used to
+ * endorse or promote products derived from this software without specific
+ * prior written permission.
+ *
+ * 3. Users of this software (implementors and gateway operators) agree to
+ * inform the EUROPAGATE consortium of their use of the software. This
+ * information will be used to evaluate the EUROPAGATE project and the
+ * software, and to plan further developments. The consortium may use
+ * the information in later publications.
+ * 
+ * 4. Users of this software agree to make their best efforts, when
+ * documenting their use of the software, to acknowledge the EUROPAGATE
+ * consortium, and the role played by the software in their work.
+ *
+ * THIS SOFTWARE IS PROVIDED "AS IS" AND WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS, IMPLIED, OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY
+ * WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
+ * IN NO EVENT SHALL THE EUROPAGATE CONSORTIUM OR ITS MEMBERS BE LIABLE
+ * FOR ANY SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF
+ * ANY KIND, OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA
+ * OR PROFITS, WHETHER OR NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND
+ * ON ANY THEORY OF LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE
+ * USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ */
+/* CCL - lexical analysis
+ * Europagate, 1995
+ *
+ * $Log$
+ * Revision 1.1  2000/08/03 03:09:59  johnmcp
+ * Added the YAZ toolkit source to the packages directory (for z39.50 stuff)
+ *
+ * Revision 1.13  2000/02/08 10:39:53  adam
+ * Added a few functions to set name of operands, etc.
+ *
+ * Revision 1.12  2000/01/31 13:15:21  adam
+ * Removed uses of assert(3). Cleanup of ODR. CCL parser update so
+ * that some characters are not surrounded by spaces in resulting term.
+ * ILL-code updates.
+ *
+ * Revision 1.11  1999/11/30 13:47:11  adam
+ * Improved installation. Moved header files to include/yaz.
+ *
+ * Revision 1.10  1998/07/07 15:49:41  adam
+ * Added braces to avoid warning.
+ *
+ * Revision 1.9  1998/02/11 11:53:33  adam
+ * Changed code so that it compiles as C++.
+ *
+ * Revision 1.8  1997/09/29 08:56:38  adam
+ * Changed CCL parser to be thread safe. New type, CCL_parser, declared
+ * and a create/destructers ccl_parser_create/ccl_parser/destory has
+ * been added.
+ *
+ * Revision 1.7  1997/09/01 08:48:12  adam
+ * New windows NT/95 port using MSV5.0. Only a few changes made
+ * to avoid warnings.
+ *
+ * Revision 1.6  1997/04/30 08:52:07  quinn
+ * Null
+ *
+ * Revision 1.5  1996/10/11  15:00:26  adam
+ * CCL parser from Europagate Email gateway 1.0.
+ *
+ * Revision 1.10  1995/07/11  12:28:31  adam
+ * New function: ccl_token_simple (split into simple tokens) and
+ *  ccl_token_del (delete tokens).
+ *
+ * Revision 1.9  1995/05/16  09:39:28  adam
+ * LICENSE.
+ *
+ * Revision 1.8  1995/05/11  14:03:57  adam
+ * Changes in the reading of qualifier(s). New function: ccl_qual_fitem.
+ * New variable ccl_case_sensitive, which controls whether reserved
+ * words and field names are case sensitive or not.
+ *
+ * Revision 1.7  1995/04/19  12:11:24  adam
+ * Minor change.
+ *
+ * Revision 1.6  1995/04/17  09:31:48  adam
+ * Improved handling of qualifiers. Aliases or reserved words.
+ *
+ * Revision 1.5  1995/02/23  08:32:00  adam
+ * Changed header.
+ *
+ * Revision 1.3  1995/02/15  17:42:16  adam
+ * Minor changes of the api of this module. FILE* argument added
+ * to ccl_pr_tree.
+ *
+ * Revision 1.2  1995/02/14  19:55:13  adam
+ * Header files ccl.h/cclp.h are gone! They have been merged an
+ * moved to ../include/ccl.h.
+ * Node kind(s) in ccl_rpn_node have changed names.
+ *
+ * Revision 1.1  1995/02/13  12:35:21  adam
+ * First version of CCL. Qualifiers aren't handled yet.
+ *
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+
+#include <yaz/ccl.h>
+
+/*
+ * token_cmp: Compare token with keyword(s)
+ * kw:     Keyword list. Each keyword is separated by space.
+ * token:  CCL token.
+ * return: 1 if token string matches one of the keywords in list;
+ *         0 otherwise.
+ */
+static int token_cmp (CCL_parser cclp, const char *kw, struct ccl_token *token)
+{
+    const char *cp1 = kw;
+    const char *cp2;
+    if (!kw)
+        return 0;
+    while ((cp2 = strchr (cp1, ' ')))
+    {
+        if (token->len == (size_t) (cp2-cp1))
+        {
+            if (cclp->ccl_case_sensitive)
+            {
+                if (!memcmp (cp1, token->name, token->len))
+                    return 1;
+            }
+            else
+            {
+                if (!ccl_memicmp (cp1, token->name, token->len))
+                    return 1;
+            }
+        }
+	cp1 = cp2+1;
+    }
+    if (cclp->ccl_case_sensitive)
+        return token->len == strlen(cp1) 
+            && !memcmp (cp1, token->name, token->len);
+    return token->len == strlen(cp1) &&
+        !ccl_memicmp (cp1, token->name, token->len);
+}
+
+/*
+ * ccl_token_simple: tokenize CCL raw tokens
+ */
+struct ccl_token *ccl_token_simple (const char *command)
+{
+    const char *cp = command;
+    struct ccl_token *first = NULL;
+    struct ccl_token *last = NULL;
+
+    while (1)
+    {
+	while (*cp && strchr (" \t\r\n", *cp))
+	{
+	    cp++;
+	    continue;
+	}
+	if (!first)
+	{
+	    first = last = (struct ccl_token *)malloc (sizeof (*first));
+	    ccl_assert (first);
+	    last->prev = NULL;
+	}
+	else
+	{
+	    last->next = (struct ccl_token *)malloc (sizeof(*first));
+	    ccl_assert (last->next);
+	    last->next->prev = last;
+	    last = last->next;
+	}
+	last->next = NULL;
+	last->name = cp;
+	last->len = 1;
+	switch (*cp++)
+	{
+        case '\0':
+            last->kind = CCL_TOK_EOL;
+            return first;
+	case '\"':
+	    last->kind = CCL_TOK_TERM;
+	    last->name = cp;
+	    last->len = 0;
+	    while (*cp && *cp != '\"')
+	    {
+		cp++;
+		++ last->len;
+	    }
+	    if (*cp == '\"')
+		cp++;
+	    break;
+	default:
+	    while (*cp && !strchr (" \t\n\r", *cp))
+	    {
+		cp++;
+		++ last->len;
+	    }
+            last->kind = CCL_TOK_TERM;
+	}
+    }
+    return first;
+}
+
+
+/*
+ * ccl_tokenize: tokenize CCL command string.
+ * return: CCL token list.
+ */
+struct ccl_token *ccl_parser_tokenize (CCL_parser cclp, const char *command)
+{
+    const char *cp = command;
+    struct ccl_token *first = NULL;
+    struct ccl_token *last = NULL;
+
+    while (1)
+    {
+	while (*cp && strchr (" \t\r\n", *cp))
+	{
+	    cp++;
+	    continue;
+	}
+	if (!first)
+	{
+	    first = last = (struct ccl_token *)malloc (sizeof (*first));
+	    ccl_assert (first);
+	    last->prev = NULL;
+	}
+	else
+	{
+	    last->next = (struct ccl_token *)malloc (sizeof(*first));
+	    ccl_assert (last->next);
+	    last->next->prev = last;
+	    last = last->next;
+	}
+	last->next = NULL;
+	last->name = cp;
+	last->len = 1;
+	switch (*cp++)
+	{
+        case '\0':
+            last->kind = CCL_TOK_EOL;
+            return first;
+	case '(':
+	    last->kind = CCL_TOK_LP;
+	    break;
+	case ')':
+	    last->kind = CCL_TOK_RP;
+	    break;
+	case ',':
+	    last->kind = CCL_TOK_COMMA;
+	    break;
+	case '%':
+	case '!':
+	    last->kind = CCL_TOK_PROX;
+	    while (*cp == '%' || *cp == '!')
+	    {
+		++ last->len;
+		cp++;
+	    }
+	    break;
+	case '>':
+	case '<':
+	case '=':
+	    if (*cp == '=' || *cp == '<' || *cp == '>')
+	    {
+		cp++;
+		last->kind = CCL_TOK_REL;
+		++ last->len;
+	    }
+	    else if (cp[-1] == '=')
+		last->kind = CCL_TOK_EQ;
+	    else
+		last->kind = CCL_TOK_REL;
+	    break;
+	case '-':
+	    last->kind = CCL_TOK_MINUS;
+	    break;
+	case '\"':
+	    last->kind = CCL_TOK_TERM;
+	    last->name = cp;
+	    last->len = 0;
+	    while (*cp && *cp != '\"')
+	    {
+		cp++;
+		++ last->len;
+	    }
+	    if (*cp == '\"')
+		cp++;
+	    break;
+	default:
+	    while (*cp && !strchr ("(),%!><=- \t\n\r", *cp))
+	    {
+		cp++;
+		++ last->len;
+	    }
+	    if (token_cmp (cclp, cclp->ccl_token_and, last))
+	        last->kind = CCL_TOK_AND;
+	    else if (token_cmp (cclp, cclp->ccl_token_or, last))
+	        last->kind = CCL_TOK_OR;
+            else if (token_cmp (cclp, cclp->ccl_token_not, last))
+	        last->kind = CCL_TOK_NOT;
+	    else if (token_cmp (cclp, cclp->ccl_token_set, last))
+	        last->kind = CCL_TOK_SET;
+	    else
+		last->kind = CCL_TOK_TERM;
+	}
+    }
+    return first;
+}
+
+struct ccl_token *ccl_tokenize (const char *command)
+{
+    CCL_parser cclp = ccl_parser_create ();
+    struct ccl_token *list;
+
+    list = ccl_parser_tokenize (cclp, command);
+
+    ccl_parser_destroy (cclp);
+    return list;
+}
+
+/*
+ * ccl_token_del: delete CCL tokens
+ */
+void ccl_token_del (struct ccl_token *list)
+{
+    struct ccl_token *list1;
+
+    while (list) 
+    {
+        list1 = list->next;
+        free (list);
+        list = list1;
+    }
+}
+
+static char *ccl_strdup (const char *str)
+{
+    int len = strlen(str);
+    char *p = (char*) malloc (len+1);
+    strcpy (p, str);
+    return p;
+}
+
+CCL_parser ccl_parser_create (void)
+{
+    CCL_parser p = (CCL_parser)malloc (sizeof(*p));
+    if (!p)
+	return p;
+    p->look_token = NULL;
+    p->error_code = 0;
+    p->error_pos = NULL;
+    p->bibset = NULL;
+
+    p->ccl_token_and = ccl_strdup("and");
+    p->ccl_token_or = ccl_strdup("or");
+    p->ccl_token_not = ccl_strdup("not andnot");
+    p->ccl_token_set = ccl_strdup("set");
+    p->ccl_case_sensitive = 1;
+
+    return p;
+}
+
+void ccl_parser_destroy (CCL_parser p)
+{
+    if (!p)
+	return;
+    free (p->ccl_token_and);
+    free (p->ccl_token_or);
+    free (p->ccl_token_not);
+    free (p->ccl_token_set);
+    free (p);
+}
+
+void ccl_parser_set_op_and (CCL_parser p, const char *op)
+{
+    if (p && op)
+	p->ccl_token_and = ccl_strdup (op);
+}
+
+void ccl_parser_set_op_or (CCL_parser p, const char *op)
+{
+    if (p && op)
+	p->ccl_token_or = ccl_strdup (op);
+}
+void ccl_parser_set_op_not (CCL_parser p, const char *op)
+{
+    if (p && op)
+	p->ccl_token_not = ccl_strdup (op);
+}
+void ccl_parser_set_op_set (CCL_parser p, const char *op)
+{
+    if (p && op)
+	p->ccl_token_set = ccl_strdup (op);
+}
+
+void ccl_parser_set_case (CCL_parser p, int case_sensitivity_flag)
+{
+    if (p)
+	p->ccl_case_sensitive = case_sensitivity_flag;
+}
Index: /main/tags/2.25/gsdl/packages/yaz/client/Makefile.in
===================================================================
--- /main/tags/2.25/gsdl/packages/yaz/client/Makefile.in	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/yaz/client/Makefile.in	(revision 21064)
@@ -0,0 +1,16 @@
+CC= @CC@
+
+#INCLUDES = -I../include -DCCLRPN=1
+INCLUDES = -I../include
+
+OBJECTS = yaz_zclient.o
+
+yaz_zclient.o: yaz_zclient.c
+	$(CC) -c $(INCLUDES) $<
+
+all: $(OBJECTS)
+
+clean:
+	rm -f $(OBJECTS)
+distclean: clean
+	rm -f Makefile
Index: /main/tags/2.25/gsdl/packages/yaz/client/yaz_zclient.c
===================================================================
--- /main/tags/2.25/gsdl/packages/yaz/client/yaz_zclient.c	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/yaz/client/yaz_zclient.c	(revision 21064)
@@ -0,0 +1,2050 @@
+/*
+ * Copyright (c) 1995-2000, Index Data
+ * See the file LICENSE for details.
+ * Sebastian Hammer, Adam Dickmeiss
+ *
+ * $Log$
+ * Revision 1.1  2000/08/03 03:10:01  johnmcp
+ * Added the YAZ toolkit source to the packages directory (for z39.50 stuff)
+ *
+ * Revision 1.1.2.1  2000/05/24 23:24:29  johnmcp
+ * added some of the YAZ toolkit code for z39.50 client.
+ *
+ * Revision 1.95  2000/02/28 11:20:05  adam
+ * Using autoconf. New definitions: YAZ_BEGIN_CDECL/YAZ_END_CDECL.
+ *
+ */
+
+/* Modified for the GreenStone Digital Library project - johnmcp */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <ctype.h> /* for isdigit() */
+#include <time.h>
+
+/* don't need functions from here, maybe only the other header files:
+function atoi_n needed by marc_display()
+#include <yaz/yconfig.h>
+#include <yaz/xmalloc.h>
+#include <yaz/log.h>
+#include <yaz/tpath.h>
+#include <yaz/options.h>
+#include <yaz/wrbuf.h>
+#include <yaz/nmem.h>
+#include <yaz/readconf.h>
+*/
+#include <yaz/yaz-util.h>
+
+#include <yaz/tcpip.h>
+
+#include <yaz/proto.h>
+
+/* only defines marc_display[_ex] (), which could be inline. May need
+   yaz/yconfig.h header file */
+#include <yaz/marcdisp.h>
+#include <yaz/diagbib1.h>
+
+#include <yaz/pquery.h>
+
+#ifdef ASN_COMPILED
+#include <yaz/ill.h>
+#endif
+
+#if HAVE_READLINE_READLINE_H
+#include <readline/readline.h>
+#endif
+#if HAVE_READLINE_HISTORY_H
+#include <readline/history.h>
+#endif
+
+#define C_PROMPT "Z> "
+
+static ODR out, in, print;              /* encoding and decoding streams */
+static FILE *apdu_file = 0;
+static COMSTACK conn = 0;               /* our z-association */
+static Z_IdAuthentication *auth = 0;    /* our current auth definition */
+static char *databaseNames[128];
+static Z_External *record_last = 0;
+static int num_databaseNames = 0;
+static int setnumber = 0;               /* current result set number */
+static int smallSetUpperBound = 0;
+static int largeSetLowerBound = 1;
+static int mediumSetPresentNumber = 0;
+static Z_ElementSetNames *elementSetNames = 0; 
+static int setno = 1;                   /* current set offset */
+static enum oid_proto protocol = PROTO_Z3950;      /* current app protocol */
+static enum oid_value recordsyntax = VAL_USMARC;
+static enum oid_value schema = VAL_NONE;
+static int sent_close = 0;
+static NMEM session_mem = NULL;      /* memory handle for init-response */
+static Z_InitResponse *session = 0;     /* session parameters */
+static char last_scan[512] = "0";
+static FILE *marcdump = 0;
+static char *refid = NULL;
+/*johnmcp*/
+Z_InitResponse *z_initresponse;
+typedef enum {
+    QueryType_Prefix,
+    QueryType_CCL,
+    QueryType_CCL2RPN
+} QueryType;
+
+static QueryType queryType = QueryType_Prefix;
+/*static QueryType queryType = QueryType_CCL;*/
+
+static void send_apdu(Z_APDU *a)
+{
+    char *buf;
+    int len;
+
+    if (!z_APDU(out, &a, 0, 0))
+    {
+        odr_perror(out, "Encoding APDU");
+        exit(1);
+    }
+    if (apdu_file)
+    {
+        z_APDU(print, &a, 0, 0);
+        odr_reset(print);
+    }
+    buf = odr_getbuf(out, &len, 0);
+    /* printf ("sending APDU of size %d\n", len); */
+    if (cs_put(conn, buf, len) < 0)
+    {
+        fprintf(stderr, "cs_put: %s", cs_errmsg(cs_errno(conn)));
+        exit(1);
+    }
+    odr_reset(out); /* release the APDU structure  */
+}
+
+static void print_refid (Z_ReferenceId *id)
+{
+    if (id)
+    {
+	printf ("ReferenceId: '%.*s'\n", id->len, id->buf);
+    }
+}
+
+static Z_ReferenceId *set_refid (ODR out)
+{
+    Z_ReferenceId *id;
+    if (!refid)
+	return 0;
+    id = (Z_ReferenceId *) odr_malloc (out, sizeof(*id));
+    id->size = id->len = strlen(refid);
+    id->buf = (unsigned char *) odr_malloc (out, id->len);
+    memcpy (id->buf, refid, id->len);
+    return id;
+}   
+
+/* INIT SERVICE ------------------------------- */
+
+static void send_initRequest()
+{
+    Z_APDU *apdu = zget_APDU(out, Z_APDU_initRequest);
+    Z_InitRequest *req = apdu->u.initRequest;
+
+    ODR_MASK_SET(req->options, Z_Options_search);
+    ODR_MASK_SET(req->options, Z_Options_present);
+    ODR_MASK_SET(req->options, Z_Options_namedResultSets);
+    ODR_MASK_SET(req->options, Z_Options_triggerResourceCtrl);
+    ODR_MASK_SET(req->options, Z_Options_scan);
+    ODR_MASK_SET(req->options, Z_Options_sort);
+    ODR_MASK_SET(req->options, Z_Options_extendedServices);
+    ODR_MASK_SET(req->options, Z_Options_delSet);
+
+    ODR_MASK_SET(req->protocolVersion, Z_ProtocolVersion_1);
+    ODR_MASK_SET(req->protocolVersion, Z_ProtocolVersion_2);
+    ODR_MASK_SET(req->protocolVersion, Z_ProtocolVersion_3);
+
+    *req->maximumRecordSize = 1024*1024;
+    *req->preferredMessageSize = 1024*1024;
+
+    req->idAuthentication = auth;
+
+    send_apdu(apdu);
+}
+
+char *z_get_initResponse()
+{
+  char *buffer;
+  size_t needed_length;
+  char *text_id="ID: ";
+  char *text_name="<br>\nName: ";
+  char *text_ver="<br>\nVersion: ";
+  int counter;
+
+  buffer=NULL;
+    /* save session parameters for later use */
+  /*    session_mem = odr_extract_mem(in);
+	session = res; */
+    if (!*session->result)
+      return NULL;
+
+    /* work out total string length needed. Note strlen(NULL) is a bad thing
+       to do. */
+    needed_length=strlen(text_id)+strlen(text_name)+strlen(text_ver)+
+      (session->implementationId?strlen(session->implementationId):0) +
+      (session->implementationName?strlen(session->implementationName):0) +
+      (session->implementationVersion?strlen(session->implementationVersion)
+       :0) +
+      (session->userInformationField?
+       strlen(session->userInformationField->u.octet_aligned->buf):0) +
+      1 /* for null char */ ;
+    if ((buffer=malloc((sizeof(char *)) * needed_length))==NULL) {
+      fprintf(stderr,"Malloc failed while initialising z39.50 server\n");
+      return (NULL);
+    }
+    /* can't pass NULL to sprintf as a (char *) */
+    sprintf(buffer,"%s%s%s%s%s%s",
+	    session->implementationId?text_id:"",
+	    session->implementationId?session->implementationId:"",
+	    session->implementationName?text_name:"",
+	    session->implementationName?session->implementationName:"",
+	    session->implementationVersion?text_ver:"",
+	    session->implementationVersion?session->implementationVersion:""
+	    );
+
+    /* if version 3, also check the other-information parameter of the
+       response. (But check version is 3 first) */
+    if (session->otherInfo)
+      /**** From prt-proto.h *********** (comment added by johnmcp)
+       typedef struct Z_OtherInformationUnit
+       .   {  Z_InfoCategory *category;        / * OPTIONAL * /
+       .      int which;
+       #define Z_OtherInfo_characterInfo 0
+       #define Z_OtherInfo_binaryInfo 1
+       #define Z_OtherInfo_externallyDefinedInfo 2
+       #define Z_OtherInfo_oid 3
+       .      union
+       .        {
+       .          char *characterInfo; 
+       .          Odr_oct *binaryInfo;
+       .          Z_External *externallyDefinedInfo;
+       .          Odr_oid *oid;
+       .        } information;
+       .   } Z_OtherInformationUnit;
+       
+       typedef struct Z_OtherInformation
+       {
+       int num_elements;
+       Z_OtherInformationUnit **list;
+       } Z_OtherInformation;
+      ************/
+      for (counter=0;counter<session->otherInfo->num_elements;counter++)
+	if (session->otherInfo->list[counter]->which ==
+	    Z_OtherInfo_characterInfo)
+	  {
+	    /* add this extra string to our buffer */
+	    int where=strlen(buffer);
+	    buffer=realloc(buffer,where+
+			   strlen(session->otherInfo->list[counter]->
+				  information.characterInfo));
+	    strcpy(buffer+where,
+		   session->otherInfo->list[counter]->
+		   information.characterInfo);
+	  }
+    return (buffer);
+}
+
+static int cmd_base(char *arg)
+{
+    int i;
+    char *cp;
+
+    if (!*arg)
+    {
+        printf("Usage: base <database> <database> ...\n");
+        return 0;
+    }
+    for (i = 0; i<num_databaseNames; i++)
+        xfree (databaseNames[i]);
+    num_databaseNames = 0;
+    while (1)
+    {
+        if (!(cp = strchr(arg, ' ')))
+            cp = arg + strlen(arg);
+        if (cp - arg < 1)
+            break;
+        databaseNames[num_databaseNames] = (char *)xmalloc (1 + cp - arg);
+        memcpy (databaseNames[num_databaseNames], arg, cp - arg);
+        databaseNames[num_databaseNames++][cp - arg] = '\0';
+        if (!*cp)
+            break;
+        arg = cp+1;
+    }
+    return 1;
+}
+
+
+int z_cmd_open(char *host_and_port, char *base)
+{
+    void *add;
+    CS_TYPE t;
+
+    if (conn)
+    {
+        printf("Already connected.\n");
+
+	cs_close (conn);
+	conn = NULL;
+	if (session_mem)
+	{
+	    nmem_destroy (session_mem);
+	    session_mem = NULL;
+	}
+    }
+
+    cmd_base (base);
+    t = tcpip_type;
+    protocol = PROTO_Z3950;
+
+    if (!(conn = cs_create(t, 1, protocol)))
+    {
+        perror("cs_create");
+        return 1;
+    }
+    if (!(add = cs_straddr(conn, host_and_port)))
+    {
+	perror(host_and_port);
+	return 1;
+    }
+
+    if (cs_connect(conn, add) < 0)
+    {
+      perror("connect"); 
+      cs_close(conn);
+      conn = 0;
+      return 1;
+    }
+    /* if here, we connected OK */
+    send_initRequest();
+    return 0;
+}
+
+int cmd_authentication(char *arg)
+{
+    static Z_IdAuthentication au;
+    static char open[256];
+
+    if (!*arg)
+    {
+        printf("Auth field set to null\n");
+        auth = 0;
+        return 1;
+    }
+    auth = &au;
+    au.which = Z_IdAuthentication_open;
+    au.u.open = open;
+    strcpy(open, arg);
+    return 1;
+}
+
+/* SEARCH SERVICE ------------------------------ */
+
+static void display_variant(Z_Variant *v, int level)
+{
+    int i;
+
+    for (i = 0; i < v->num_triples; i++)
+    {
+	printf("%*sclass=%d,type=%d", level * 4, "", *v->triples[i]->zclass,
+	    *v->triples[i]->type);
+	if (v->triples[i]->which == Z_Triple_internationalString)
+	    printf(",value=%s\n", v->triples[i]->value.internationalString);
+	else
+	    printf("\n");
+    }
+}
+
+static void display_grs1(Z_GenericRecord *r, int level)
+{
+    int i;
+
+    if (!r)
+        return;
+    for (i = 0; i < r->num_elements; i++)
+    {
+        Z_TaggedElement *t;
+
+        printf("%*s", level * 4, "");
+        t = r->elements[i];
+        printf("(");
+        if (t->tagType)
+            printf("%d,", *t->tagType);
+        else
+            printf("?,");
+        if (t->tagValue->which == Z_StringOrNumeric_numeric)
+            printf("%d) ", *t->tagValue->u.numeric);
+        else
+            printf("%s) ", t->tagValue->u.string);
+        if (t->content->which == Z_ElementData_subtree)
+        {
+            printf("\n");
+            display_grs1(t->content->u.subtree, level+1);
+        }
+        else if (t->content->which == Z_ElementData_string)
+            printf("%s\n", t->content->u.string);
+        else if (t->content->which == Z_ElementData_numeric)
+	    printf("%d\n", *t->content->u.numeric);
+	else if (t->content->which == Z_ElementData_oid)
+	{
+	    int *ip = t->content->u.oid;
+	    oident *oent;
+
+	    if ((oent = oid_getentbyoid(t->content->u.oid)))
+		printf("OID: %s\n", oent->desc);
+	    else
+	    {
+		printf("{");
+		while (ip && *ip >= 0)
+		    printf(" %d", *(ip++));
+		printf(" }\n");
+	    }
+	}
+	else if (t->content->which == Z_ElementData_noDataRequested)
+	    printf("[No data requested]\n");
+	else if (t->content->which == Z_ElementData_elementEmpty)
+	    printf("[Element empty]\n");
+	else if (t->content->which == Z_ElementData_elementNotThere)
+	    printf("[Element not there]\n");
+	else
+            printf("??????\n");
+	if (t->appliedVariant)
+	    display_variant(t->appliedVariant, level+1);
+	if (t->metaData && t->metaData->supportedVariants)
+	{
+	    int c;
+
+	    printf("%*s---- variant list\n", (level+1)*4, "");
+	    for (c = 0; c < t->metaData->num_supportedVariants; c++)
+	    {
+		printf("%*svariant #%d\n", (level+1)*4, "", c);
+		display_variant(t->metaData->supportedVariants[c], level + 2);
+	    }
+	}
+    }
+}
+
+static void print_record(const unsigned char *buf, size_t len)
+{
+   size_t i;
+   for (i = 0; i<len; i++)
+       if ((buf[i] <= 126 && buf[i] >= 32) || strchr ("\n\r\t\f", buf[i]))
+           fputc (buf[i], stdout);
+       else
+           printf ("\\X%02X", buf[i]);
+   /* add newline if not already added ... */
+   if (i <= 0 || buf[i-1] != '\n')
+       fputc ('\n', stdout);
+}
+
+static void display_record(Z_DatabaseRecord *p)
+{
+    Z_External *r = (Z_External*) p;
+    oident *ent = oid_getentbyoid(r->direct_reference);
+
+    record_last = r;
+    /*
+     * Tell the user what we got.
+     */
+    if (r->direct_reference)
+    {
+        printf("Record type: ");
+        if (ent)
+            printf("%s\n", ent->desc);
+        else if (!odr_oid(print, &r->direct_reference, 0, 0))
+        {
+            odr_perror(print, "print oid");
+            odr_reset(print);
+        }
+    }
+    /* Check if this is a known, ASN.1 type tucked away in an octet string */
+    if (ent && r->which == Z_External_octet)
+    {
+	Z_ext_typeent *type = z_ext_getentbyref(ent->value);
+	void *rr;
+
+	if (type)
+	{
+	    /*
+	     * Call the given decoder to process the record.
+	     */
+	    odr_setbuf(in, (char*)p->u.octet_aligned->buf,
+		p->u.octet_aligned->len, 0);
+	    if (!(*type->fun)(in, (char **)&rr, 0, 0))
+	    {
+		odr_perror(in, "Decoding constructed record.");
+		fprintf(stderr, "[Near %d]\n", odr_offset(in));
+		fprintf(stderr, "Packet dump:\n---------\n");
+		odr_dumpBER(stderr, (char*)p->u.octet_aligned->buf,
+		    p->u.octet_aligned->len);
+		fprintf(stderr, "---------\n");
+		exit(1);
+	    }
+	    /*
+	     * Note: we throw away the original, BER-encoded record here.
+	     * Do something else with it if you want to keep it.
+	     */
+	    r->u.sutrs = (Z_SUTRS *) rr; /* we don't actually check the type here. */
+	    r->which = type->what;
+	}
+    }
+    if (ent && ent->value == VAL_SOIF)
+        print_record((const unsigned char *) r->u.octet_aligned->buf, r->u.octet_aligned->len);
+    else if (r->which == Z_External_octet && p->u.octet_aligned->len)
+    {
+      /* johnmcp - this is called for USmarc for demo server, at least */
+        const char *octet_buf = (char*)p->u.octet_aligned->buf;
+	if (ent->value == VAL_TEXT_XML || ent->value == VAL_APPLICATION_XML ||
+            ent->value == VAL_HTML)
+            print_record((const unsigned char *) octet_buf,
+                         p->u.octet_aligned->len);
+	else
+        {
+	  /* johnmcp - here marc_display does the work */
+            if (marc_display (octet_buf, NULL) <= 0)
+            {
+                printf ("ISO2709 decoding failed, dumping record as is:\n");
+                print_record((const unsigned char*) octet_buf,
+                              p->u.octet_aligned->len);
+            }
+        }
+        if (marcdump) /*here (false) */
+            fwrite (octet_buf, 1, p->u.octet_aligned->len, marcdump);
+    }
+    else if (ent && ent->value == VAL_SUTRS)
+    {
+        if (r->which != Z_External_sutrs)
+        {
+            printf("Expecting single SUTRS type for SUTRS.\n");
+            return;
+        }
+        print_record(r->u.sutrs->buf, r->u.sutrs->len);
+    }
+    else if (ent && ent->value == VAL_GRS1)
+    {
+        if (r->which != Z_External_grs1)
+        {
+            printf("Expecting single GRS type for GRS.\n");
+            return;
+        }
+        display_grs1(r->u.grs1, 0);
+    }
+    else 
+    {
+        printf("Unknown record representation.\n");
+        if (!z_External(print, &r, 0, 0))
+        {
+            odr_perror(print, "Printing external");
+            odr_reset(print);
+        }
+    }
+}
+
+
+static void display_diagrecs(Z_DiagRec **pp, int num)
+{
+    int i;
+    oident *ent;
+    Z_DefaultDiagFormat *r;
+
+    printf("Diagnostic message(s) from database:\n");
+    for (i = 0; i<num; i++)
+    {
+	Z_DiagRec *p = pp[i];
+	if (p->which != Z_DiagRec_defaultFormat)
+	{
+	    printf("Diagnostic record not in default format.\n");
+	    return;
+	}
+	else
+	    r = p->u.defaultFormat;
+	if (!(ent = oid_getentbyoid(r->diagnosticSetId)) ||
+	    ent->oclass != CLASS_DIAGSET || ent->value != VAL_BIB1)
+	    printf("Missing or unknown diagset\n");
+	printf("    [%d] %s", *r->condition, diagbib1_str(*r->condition));
+#ifdef ASN_COMPILED
+	switch (r->which)
+	{
+	case Z_DefaultDiagFormat_v2Addinfo:
+	    printf (" -- v2 addinfo '%s'\n", r->u.v2Addinfo);
+	    break;
+	case Z_DefaultDiagFormat_v3Addinfo:
+	    printf (" -- v3 addinfo '%s'\n", r->u.v3Addinfo);
+	    break;
+	}
+#else
+	if (r->addinfo && *r->addinfo)
+	    printf(" -- '%s'\n", r->addinfo);
+	else
+	    printf("\n");
+#endif
+    }
+}
+
+
+static void display_nameplusrecord(Z_NamePlusRecord *p)
+{
+    if (p->databaseName)
+        printf("[%s]", p->databaseName);
+    if (p->which == Z_NamePlusRecord_surrogateDiagnostic)
+        display_diagrecs(&p->u.surrogateDiagnostic, 1);
+    else if (p->which == Z_NamePlusRecord_databaseRecord)
+        display_record(p->u.databaseRecord);
+}
+
+static void display_records(Z_Records *p)
+{
+    int i;
+
+    if (p->which == Z_Records_NSD)
+    {
+#ifdef ASN_COMPILED
+	Z_DiagRec dr, *dr_p = &dr;
+	dr.which = Z_DiagRec_defaultFormat;
+	dr.u.defaultFormat = p->u.nonSurrogateDiagnostic;
+	display_diagrecs (&dr_p, 1);
+#else
+	display_diagrecs (&p->u.nonSurrogateDiagnostic, 1);
+#endif
+    }
+    else if (p->which == Z_Records_multipleNSD)
+	display_diagrecs (p->u.multipleNonSurDiagnostics->diagRecs,
+			  p->u.multipleNonSurDiagnostics->num_diagRecs);
+    else 
+    {
+        printf("Records: %d\n", p->u.databaseOrSurDiagnostics->num_records);
+        for (i = 0; i < p->u.databaseOrSurDiagnostics->num_records; i++)
+            display_nameplusrecord(p->u.databaseOrSurDiagnostics->records[i]);
+    }
+}
+
+
+static int send_searchRequest(char *arg)
+{
+    Z_APDU *apdu = zget_APDU(out, Z_APDU_searchRequest);
+    Z_SearchRequest *req = apdu->u.searchRequest;
+    Z_Query query;
+    int oid[OID_SIZE];
+    char setstring[100];
+    Z_RPNQuery *RPNquery;
+    /*    Odr_oct ccl_query; */
+
+    req->referenceId = set_refid (out);
+    if (!strcmp(arg, "@big")) /* strictly for troublemaking */
+    {
+        static unsigned char big[2100];
+        static Odr_oct bigo;
+
+        /* send a very big referenceid to test transport stack etc. */
+        memset(big, 'A', 2100);
+        bigo.len = bigo.size = 2100;
+        bigo.buf = big;
+        req->referenceId = &bigo;
+    }
+    
+    if (setnumber >= 0)
+    {
+        sprintf(setstring, "%d", ++setnumber);
+        req->resultSetName = setstring;
+    }
+    *req->smallSetUpperBound = smallSetUpperBound;
+    *req->largeSetLowerBound = largeSetLowerBound;
+    *req->mediumSetPresentNumber = mediumSetPresentNumber;
+    if (smallSetUpperBound > 0 || (largeSetLowerBound > 1 &&
+        mediumSetPresentNumber > 0))
+    {
+        oident prefsyn;
+
+        prefsyn.proto = protocol;
+        prefsyn.oclass = CLASS_RECSYN;
+        prefsyn.value = recordsyntax;
+        req->preferredRecordSyntax =
+            odr_oiddup(out, oid_ent_to_oid(&prefsyn, oid));
+        req->smallSetElementSetNames =
+            req->mediumSetElementSetNames = elementSetNames;
+    }
+    req->num_databaseNames = num_databaseNames;
+    req->databaseNames = databaseNames;
+
+    req->query = &query;
+    /* johnmcp - this is where we choose our query format. either ccl or rpn */
+    /*    switch (queryType)
+	  {
+	  case QueryType_Prefix: */
+    query.which = Z_Query_type_1;
+    RPNquery = p_query_rpn (out, protocol, arg);
+    if (!RPNquery)
+      {
+	printf("Prefix query error\n");
+	return (-1);
+      }
+    query.u.type_1 = RPNquery;
+    /* break;
+       case QueryType_CCL:
+       query.which = Z_Query_type_2;
+       query.u.type_2 = &ccl_query;
+       ccl_query.buf = (unsigned char*) arg;
+       ccl_query.len = strlen(arg);
+       break;
+       default:
+       printf ("Unsupported query type\n");
+       return 0;
+       }*/
+    send_apdu(apdu);
+    setno = 1;
+    /*    printf("Sent searchRequest.\n"); */
+    return 0;
+}
+
+static int process_searchResponse(Z_SearchResponse *res)
+{
+    print_refid (res->referenceId);
+    if (!(*res->searchStatus)) {
+      /* this should return an error instead of 0 docs found... one day... */
+      return 0;
+    }
+    setno += *res->numberOfRecordsReturned;
+    if (res->records)
+        display_records(res->records);
+    return *res->resultCount;
+}
+
+static void print_level(int iLevel)
+{
+    int i;
+    for (i = 0; i < iLevel * 4; i++)
+        printf(" ");
+}
+
+static void print_int(int iLevel, const char *pTag, int *pInt)
+{
+    if (pInt != NULL)
+    {
+        print_level(iLevel);
+        printf("%s: %d\n", pTag, *pInt);
+    }
+}
+
+static void print_string(int iLevel, const char *pTag, const char *pString)
+{
+    if (pString != NULL)
+    {
+        print_level(iLevel);
+        printf("%s: %s\n", pTag, pString);
+    }
+}
+
+static void print_oid(int iLevel, const char *pTag, Odr_oid *pOid)
+{
+    if (pOid != NULL)
+    {
+        int *pInt = pOid;
+
+        print_level(iLevel);
+        printf("%s:", pTag);
+        for (; *pInt != -1; pInt++)
+            printf(" %d", *pInt);
+        printf("\n");
+    }
+}
+
+static void print_referenceId(int iLevel, Z_ReferenceId *referenceId)
+{
+    if (referenceId != NULL)
+    {
+        int i;
+
+        print_level(iLevel);
+        printf("Ref Id (%d, %d): ", referenceId->len, referenceId->size);
+        for (i = 0; i < referenceId->len; i++)
+            printf("%c", referenceId->buf[i]);
+        printf("\n");
+    }
+}
+
+static void print_string_or_numeric(int iLevel, const char *pTag, Z_StringOrNumeric *pStringNumeric)
+{
+    if (pStringNumeric != NULL)
+    {
+        switch (pStringNumeric->which)
+        {
+            case Z_StringOrNumeric_string:
+                print_string(iLevel, pTag, pStringNumeric->u.string);
+                break;
+
+            case Z_StringOrNumeric_numeric:
+                print_int(iLevel, pTag, pStringNumeric->u.numeric);
+                break;
+
+            default:
+                print_level(iLevel);
+                printf("%s: valid type for Z_StringOrNumeric\n", pTag);
+                break;
+        }
+    }
+}
+
+static void print_universe_report_duplicate(int iLevel, Z_UniverseReportDuplicate *pUniverseReportDuplicate)
+{
+    if (pUniverseReportDuplicate != NULL)
+    {
+        print_level(iLevel);
+        printf("Universe Report Duplicate: \n");
+        iLevel++;
+        print_string_or_numeric(iLevel, "Hit No", pUniverseReportDuplicate->hitno);
+    }
+}
+
+static void print_universe_report_hits(int iLevel, Z_UniverseReportHits *pUniverseReportHits)
+{
+    if (pUniverseReportHits != NULL)
+    {
+        print_level(iLevel);
+        printf("Universe Report Hits: \n");
+        iLevel++;
+        print_string_or_numeric(iLevel, "Database", pUniverseReportHits->database);
+        print_string_or_numeric(iLevel, "Hits", pUniverseReportHits->hits);
+    }
+}
+
+static void print_universe_report(int iLevel, Z_UniverseReport *pUniverseReport)
+{
+    if (pUniverseReport != NULL)
+    {
+        print_level(iLevel);
+        printf("Universe Report: \n");
+        iLevel++;
+        print_int(iLevel, "Total Hits", pUniverseReport->totalHits);
+        switch (pUniverseReport->which)
+        {
+            case Z_UniverseReport_databaseHits:
+                print_universe_report_hits(iLevel, pUniverseReport->u.databaseHits);
+                break;
+
+            case Z_UniverseReport_duplicate:
+                print_universe_report_duplicate(iLevel, pUniverseReport->u.duplicate);
+                break;
+
+            default:
+                print_level(iLevel);
+                printf("Type: %d\n", pUniverseReport->which);
+                break;
+        }
+    }
+}
+
+static void print_external(int iLevel, Z_External *pExternal)
+{
+    if (pExternal != NULL)
+    {
+        print_level(iLevel);
+        printf("External: \n");
+        iLevel++;
+        print_oid(iLevel, "Direct Reference", pExternal->direct_reference);
+        print_int(iLevel, "InDirect Reference", pExternal->indirect_reference);
+        print_string(iLevel, "Descriptor", pExternal->descriptor);
+        switch (pExternal->which)
+        {
+            case Z_External_universeReport:
+                print_universe_report(iLevel, pExternal->u.universeReport);
+                break;
+
+            default:
+                print_level(iLevel);
+                printf("Type: %d\n", pExternal->which);
+                break;
+        }
+    }
+}
+
+static int process_resourceControlRequest (Z_ResourceControlRequest *req)
+{
+    printf ("Received ResourceControlRequest.\n");
+    print_referenceId(1, req->referenceId);
+    print_int(1, "Suspended Flag", req->suspendedFlag);
+    print_int(1, "Partial Results Available", req->partialResultsAvailable);
+    print_int(1, "Response Required", req->responseRequired);
+    print_int(1, "Triggered Request Flag", req->triggeredRequestFlag);
+    print_external(1, req->resourceReport);
+    return 0;
+}
+
+void process_ESResponse(Z_ExtendedServicesResponse *res)
+{
+    printf("process_ESResponse status=");
+    switch (*res->operationStatus)
+    {
+    case Z_ExtendedServicesResponse_done:
+	printf ("done\n");
+	break;
+    case Z_ExtendedServicesResponse_accepted:
+	printf ("accepted\n");
+	break;
+    case Z_ExtendedServicesResponse_failure:
+	printf ("failure\n");
+	display_diagrecs(res->diagnostics, res->num_diagnostics);
+	break;
+    }
+}
+
+#ifdef ASN_COMPILED
+
+const char *get_ill_element (void *clientData, const char *element)
+{
+    if (!strcmp (element, "ill,transaction-id,transaction-group-qualifier"))
+	return "1";
+    if (!strcmp (element, "ill,transaction-id,transaction-qualifier"))
+	return "1";
+    return 0;
+}
+
+#endif
+
+
+/* PRESENT SERVICE ----------------------------- */
+static int z_send_getbriefrecords(int starting, int set, int howmany) {
+    Z_APDU *apdu = zget_APDU(out, Z_APDU_presentRequest);
+    Z_PresentRequest *req = apdu->u.presentRequest;
+    Z_RecordComposition compo;
+    oident prefsyn;
+    int nos = 1;
+    int oid[OID_SIZE];
+    /*    char *p;*/
+    char setstring[100]; 
+
+    req->referenceId = set_refid (out);
+    nos = howmany;
+
+    setno = starting;
+    setnumber=1;
+    sprintf(setstring, "%d", setnumber);
+    req->resultSetId = setstring;
+    req->resultSetStartPoint = &setno;
+    req->numberOfRecordsRequested = &nos;
+    prefsyn.proto = protocol;
+    prefsyn.oclass = CLASS_RECSYN;
+    prefsyn.value = recordsyntax;
+    req->preferredRecordSyntax =
+	odr_oiddup (out, oid_ent_to_oid(&prefsyn, oid));
+
+    if (schema != VAL_NONE)
+    {
+        oident prefschema;
+
+        prefschema.proto = protocol;
+        prefschema.oclass = CLASS_SCHEMA;
+        prefschema.value = schema;
+
+	req->recordComposition = &compo;
+	compo.which = Z_RecordComp_complex;
+	compo.u.complex = (Z_CompSpec *)
+	    odr_malloc(out, sizeof(*compo.u.complex));
+	compo.u.complex->selectAlternativeSyntax = (bool_t *) 
+	    odr_malloc(out, sizeof(bool_t));
+	*compo.u.complex->selectAlternativeSyntax = 0;
+
+	compo.u.complex->generic = (Z_Specification *)
+	    odr_malloc(out, sizeof(*compo.u.complex->generic));
+	compo.u.complex->generic->schema = (Odr_oid *)
+	    odr_oiddup(out, oid_ent_to_oid(&prefschema, oid));
+	if (!compo.u.complex->generic->schema)
+	{
+	    /* OID wasn't a schema! Try record syntax instead. */
+	    prefschema.oclass = CLASS_RECSYN;
+	    compo.u.complex->generic->schema = (Odr_oid *)
+		odr_oiddup(out, oid_ent_to_oid(&prefschema, oid));
+	}
+	if (!elementSetNames)
+	    compo.u.complex->generic->elementSpec = 0;
+	else
+	{
+	    compo.u.complex->generic->elementSpec = (Z_ElementSpec *)
+		odr_malloc(out, sizeof(Z_ElementSpec));
+	    compo.u.complex->generic->elementSpec->which =
+		Z_ElementSpec_elementSetName;
+	    compo.u.complex->generic->elementSpec->u.elementSetName =
+		elementSetNames->u.generic;
+	}
+	compo.u.complex->num_dbSpecific = 0;
+	compo.u.complex->dbSpecific = 0;
+	compo.u.complex->num_recordSyntax = 0;
+	compo.u.complex->recordSyntax = 0;
+    }
+    else if (elementSetNames)
+    {
+        req->recordComposition = &compo;
+        compo.which = Z_RecordComp_simple;
+        compo.u.simple = elementSetNames;
+    }
+    send_apdu(apdu);
+    return 0;
+}
+
+void process_close(Z_Close *req)
+{
+    Z_APDU *apdu = zget_APDU(out, Z_APDU_close);
+    Z_Close *res = apdu->u.close;
+
+    static char *reasons[] =
+    {
+        "finished",
+        "shutdown",
+        "system problem",
+        "cost limit reached",
+        "resources",
+        "security violation",
+        "protocolError",
+        "lack of activity",
+        "peer abort",
+        "unspecified"
+    };
+
+    printf("Reason: %s, message: %s\n", reasons[*req->closeReason],
+        req->diagnosticInformation ? req->diagnosticInformation : "NULL");
+    if (sent_close)
+    {
+	cs_close (conn);
+	conn = NULL;
+	if (session_mem)
+	{
+	    nmem_destroy (session_mem);
+	    session_mem = NULL;
+	}
+	sent_close = 0;
+    }
+    else
+    {
+	*res->closeReason = Z_Close_finished;
+	send_apdu(apdu);
+	printf("Sent response.\n");
+	sent_close = 1;
+    }
+}
+
+
+
+int cmd_quit(char *arg)
+{
+    printf("See you later, alligator.\n");
+    exit(0);
+    return 0;
+}
+
+int cmd_cancel(char *arg)
+{
+    Z_APDU *apdu = zget_APDU(out, Z_APDU_triggerResourceControlRequest);
+    Z_TriggerResourceControlRequest *req =
+        apdu->u.triggerResourceControlRequest;
+    bool_t rfalse = 0;
+    
+    if (!conn)
+    {
+        printf("Session not initialized yet\n");
+        return 0;
+    }
+    if (!ODR_MASK_GET(session->options, Z_Options_triggerResourceCtrl))
+    {
+        printf("Target doesn't support cancel (trigger resource ctrl)\n");
+        return 0;
+    }
+    *req->requestedAction = Z_TriggerResourceCtrl_cancel;
+    req->resultSetWanted = &rfalse;
+
+    send_apdu(apdu);
+    printf("Sent cancel request\n");
+    return 2;
+}
+
+int send_scanrequest(char *string, int pp, int num)
+{
+    Z_APDU *apdu = zget_APDU(out, Z_APDU_scanRequest);
+    Z_ScanRequest *req = apdu->u.scanRequest;
+    
+    if (!(req->termListAndStartPoint =
+	  p_query_scan(out, protocol, &req->attributeSet, string)))
+    {
+	printf("Prefix query error\n");
+	return -1;
+    }
+    req->referenceId = set_refid (out);
+    req->num_databaseNames = num_databaseNames;
+    req->databaseNames = databaseNames;
+    req->numberOfTermsRequested = &num;
+    req->preferredPositionInResponse = &pp;
+    send_apdu(apdu);
+    return 2;
+}
+
+int send_sortrequest(char *arg, int newset)
+{
+    Z_APDU *apdu = zget_APDU(out, Z_APDU_sortRequest);
+    Z_SortRequest *req = apdu->u.sortRequest;
+    Z_SortKeySpecList *sksl = (Z_SortKeySpecList *)
+        odr_malloc (out, sizeof(*sksl));
+    char setstring[32];
+    char sort_string[32], sort_flags[32];
+    int off;
+    int oid[OID_SIZE];
+    oident bib1;
+
+    if (setnumber >= 0)
+	sprintf (setstring, "%d", setnumber);
+    else
+	sprintf (setstring, "default");
+
+    req->referenceId = set_refid (out);
+
+#ifdef ASN_COMPILED
+    req->num_inputResultSetNames = 1;
+    req->inputResultSetNames = (Z_InternationalString **)
+	odr_malloc (out, sizeof(*req->inputResultSetNames));
+    req->inputResultSetNames[0] = odr_strdup (out, setstring);
+#else
+    req->inputResultSetNames =
+	(Z_StringList *)odr_malloc (out, sizeof(*req->inputResultSetNames));
+    req->inputResultSetNames->num_strings = 1;
+    req->inputResultSetNames->strings =
+	(char **)odr_malloc (out, sizeof(*req->inputResultSetNames->strings));
+    req->inputResultSetNames->strings[0] =
+	odr_strdup (out, setstring);
+#endif
+
+    if (newset && setnumber >= 0)
+	sprintf (setstring, "%d", ++setnumber);
+
+    req->sortedResultSetName = odr_strdup (out, setstring);
+
+    req->sortSequence = sksl;
+    sksl->num_specs = 0;
+    sksl->specs = (Z_SortKeySpec **)odr_malloc (out, sizeof(sksl->specs) * 20);
+    
+    bib1.proto = protocol;
+    bib1.oclass = CLASS_ATTSET;
+    bib1.value = VAL_BIB1;
+    while ((sscanf (arg, "%31s %31s%n", sort_string, sort_flags, &off)) == 2 
+           && off > 1)
+    {
+	int i;
+	char *sort_string_sep;
+	Z_SortKeySpec *sks = (Z_SortKeySpec *)odr_malloc (out, sizeof(*sks));
+	Z_SortKey *sk = (Z_SortKey *)odr_malloc (out, sizeof(*sk));
+
+	arg += off;
+	sksl->specs[sksl->num_specs++] = sks;
+	sks->sortElement = (Z_SortElement *)odr_malloc (out, sizeof(*sks->sortElement));
+	sks->sortElement->which = Z_SortElement_generic;
+	sks->sortElement->u.generic = sk;
+	
+	if ((sort_string_sep = strchr (sort_string, '=')))
+	{
+	    Z_AttributeElement *el = (Z_AttributeElement *)odr_malloc (out, sizeof(*el));
+	    sk->which = Z_SortKey_sortAttributes;
+	    sk->u.sortAttributes =
+		(Z_SortAttributes *)odr_malloc (out, sizeof(*sk->u.sortAttributes));
+	    sk->u.sortAttributes->id = oid_ent_to_oid(&bib1, oid);
+	    sk->u.sortAttributes->list =
+		(Z_AttributeList *)odr_malloc (out, sizeof(*sk->u.sortAttributes->list));
+	    sk->u.sortAttributes->list->num_attributes = 1;
+	    sk->u.sortAttributes->list->attributes =
+		(Z_AttributeElement **)odr_malloc (out,
+			    sizeof(*sk->u.sortAttributes->list->attributes));
+	    sk->u.sortAttributes->list->attributes[0] = el;
+	    el->attributeSet = 0;
+	    el->attributeType = (int *)odr_malloc (out, sizeof(*el->attributeType));
+	    *el->attributeType = atoi (sort_string);
+	    el->which = Z_AttributeValue_numeric;
+	    el->value.numeric = (int *)odr_malloc (out, sizeof(*el->value.numeric));
+	    *el->value.numeric = atoi (sort_string_sep + 1);
+	}
+	else
+	{
+	    sk->which = Z_SortKey_sortField;
+	    sk->u.sortField = odr_strdup (out, sort_string);
+	}
+	sks->sortRelation = (int *)odr_malloc (out, sizeof(*sks->sortRelation));
+	*sks->sortRelation = Z_SortRelation_ascending;
+	sks->caseSensitivity = (int *)odr_malloc (out, sizeof(*sks->caseSensitivity));
+	*sks->caseSensitivity = Z_SortCase_caseSensitive;
+
+#ifdef ASN_COMPILED
+	sks->which = Z_SortKeySpec_null;
+	sks->u.null = odr_nullval ();
+#else
+	sks->missingValueAction = NULL;
+#endif
+
+	for (i = 0; sort_flags[i]; i++)
+	{
+	    switch (sort_flags[i])
+	    {
+	    case 'a':
+	    case 'A':
+	    case '>':
+		*sks->sortRelation = Z_SortRelation_descending;
+		break;
+	    case 'd':
+	    case 'D':
+	    case '<':
+		*sks->sortRelation = Z_SortRelation_ascending;
+		break;
+	    case 'i':
+	    case 'I':
+		*sks->caseSensitivity = Z_SortCase_caseInsensitive;
+		break;
+	    case 'S':
+	    case 's':
+		*sks->caseSensitivity = Z_SortCase_caseSensitive;
+		break;
+	    }
+	}
+    }
+    if (!sksl->num_specs)
+    {
+        printf ("Missing sort specifications\n");
+	return -1;
+    }
+    send_apdu(apdu);
+    return 2;
+}
+
+void display_term(Z_TermInfo *t)
+{
+    if (t->term->which == Z_Term_general)
+    {
+        printf("%.*s (%d)\n", t->term->u.general->len, t->term->u.general->buf,
+            t->globalOccurrences ? *t->globalOccurrences : -1);
+        sprintf(last_scan, "%.*s", t->term->u.general->len,
+            t->term->u.general->buf);
+    }
+    else
+        printf("Term type not general.\n");
+}
+
+void process_scanResponse(Z_ScanResponse *res)
+{
+    int i;
+    Z_Entry **entries = NULL;
+    int num_entries = 0;
+   
+    printf("Received ScanResponse\n"); 
+    print_refid (res->referenceId);
+    printf("%d entries", *res->numberOfEntriesReturned);
+    if (res->positionOfTerm)
+	printf (", position=%d", *res->positionOfTerm); 
+    printf ("\n");
+    if (*res->scanStatus != Z_Scan_success)
+        printf("Scan returned code %d\n", *res->scanStatus);
+    if (!res->entries)
+        return;
+    if ((entries = res->entries->entries))
+	num_entries = res->entries->num_entries;
+    for (i = 0; i < num_entries; i++)
+    {
+        int pos_term = res->positionOfTerm ? *res->positionOfTerm : -1;
+	if (entries[i]->which == Z_Entry_termInfo)
+	{
+	    printf("%c ", i + 1 == pos_term ? '*' : ' ');
+	    display_term(entries[i]->u.termInfo);
+	}
+	else
+	    display_diagrecs(&entries[i]->u.surrogateDiagnostic, 1);
+    }
+    if (res->entries->nonsurrogateDiagnostics)
+	display_diagrecs (res->entries->nonsurrogateDiagnostics,
+			  res->entries->num_nonsurrogateDiagnostics);
+}
+
+void process_sortResponse(Z_SortResponse *res)
+{
+    printf("Received SortResponse: status=");
+    switch (*res->sortStatus)
+    {
+    case Z_SortStatus_success:
+	printf ("success"); break;
+    case Z_SortStatus_partial_1:
+	printf ("partial"); break;
+    case Z_SortStatus_failure:
+	printf ("failure"); break;
+    default:
+	printf ("unknown (%d)", *res->sortStatus);
+    }
+    printf ("\n");
+    print_refid (res->referenceId);
+#ifdef ASN_COMPILED
+    if (res->diagnostics)
+        display_diagrecs(res->diagnostics,
+			 res->num_diagnostics);
+#else
+    if (res->diagnostics)
+        display_diagrecs(res->diagnostics->diagRecs,
+			 res->diagnostics->num_diagRecs);
+#endif
+}
+
+void process_deleteResultSetResponse (Z_DeleteResultSetResponse *res)
+{
+    printf("Got deleteResultSetResponse status=%d\n",
+	   *res->deleteOperationStatus);
+    if (res->deleteListStatuses)
+    {
+	int i;
+	for (i = 0; i < res->deleteListStatuses->num; i++)
+	{
+	    printf ("%s status=%d\n", res->deleteListStatuses->elements[i]->id,
+		    *res->deleteListStatuses->elements[i]->status);
+	}
+    }
+}
+
+int cmd_sort_generic(char *arg, int newset)
+{
+    if (!conn)
+    {
+        printf("Session not initialized yet\n");
+        return 0;
+    }
+    if (!ODR_MASK_GET(session->options, Z_Options_sort))
+    {
+        printf("Target doesn't support sort\n");
+        return 0;
+    }
+    if (*arg)
+    {
+        if (send_sortrequest(arg, newset) < 0)
+            return 0;
+	return 2;
+    }
+    return 0;
+}
+
+int cmd_sort(char *arg)
+{
+    return cmd_sort_generic (arg, 0);
+}
+
+int cmd_sort_newset (char *arg)
+{
+    return cmd_sort_generic (arg, 1);
+}
+
+int cmd_scan(char *arg)
+{
+    if (!conn)
+    {
+        printf("Session not initialized yet\n");
+        return 0;
+    }
+    if (!ODR_MASK_GET(session->options, Z_Options_scan))
+    {
+        printf("Target doesn't support scan\n");
+        return 0;
+    }
+    if (*arg)
+    {
+        if (send_scanrequest(arg, 1, 20) < 0)
+            return 0;
+    }
+    else
+        if (send_scanrequest(last_scan, 1, 20) < 0)
+            return 0;
+    return 2;
+}
+
+int cmd_schema(char *arg)
+{
+    if (!arg || !*arg)
+    {
+	schema = VAL_NONE;
+        return 1;
+    }
+    schema = oid_getvalbyname (arg);
+    if (schema == VAL_NONE)
+    {
+        printf ("unknown schema\n");
+        return 0;
+    }
+    return 1;
+}
+
+int cmd_format(char *arg)
+{
+    if (!arg || !*arg)
+    {
+        printf("Usage: format <recordsyntax>\n");
+        return 0;
+    }
+    recordsyntax = oid_getvalbyname (arg);
+    if (recordsyntax == VAL_NONE)
+    {
+        printf ("unknown record syntax\n");
+        return 0;
+    }
+    return 1;
+}
+
+int cmd_elements(char *arg)
+{
+    static Z_ElementSetNames esn;
+    static char what[100];
+
+    if (!arg || !*arg)
+    {
+	elementSetNames = 0;
+        return 1;
+    }
+    strcpy(what, arg);
+    esn.which = Z_ElementSetNames_generic;
+    esn.u.generic = what;
+    elementSetNames = &esn;
+    return 1;
+}
+
+int cmd_attributeset(char *arg)
+{
+    char what[100];
+
+    if (!arg || !*arg)
+    {
+	printf("Usage: attributeset <setname>\n");
+	return 0;
+    }
+    sscanf(arg, "%s", what);
+    if (p_query_attset (what))
+    {
+	printf("Unknown attribute set name\n");
+	return 0;
+    }
+    return 1;
+}
+
+int cmd_querytype (char *arg)
+{
+    if (!strcmp (arg, "ccl"))
+        queryType = QueryType_CCL;
+    else if (!strcmp (arg, "prefix") || !strcmp(arg, "rpn"))
+        queryType = QueryType_Prefix;
+    else
+    {
+        printf ("Querytype must be one of:\n");
+        printf (" prefix         - Prefix query\n");
+        printf (" ccl            - CCL query\n");
+        return 0;
+    }
+    return 1;
+}
+
+int cmd_refid (char *arg)
+{
+    xfree (refid);
+    refid = NULL;
+    if (*arg)
+    {
+	refid = (char *) xmalloc (strlen(arg)+1);
+	strcpy (refid, arg);
+    }
+    return 1;
+}
+
+int z_cmd_close(char *arg)
+{
+    Z_APDU *apdu;
+    Z_Close *req;
+    if (!conn)
+	return 1;
+
+    apdu = zget_APDU(out, Z_APDU_close);
+    req = apdu->u.close;
+    *req->closeReason = Z_Close_finished;
+    send_apdu(apdu);
+    sent_close = 1;
+    return 0;
+}
+
+void z_initialize(void)
+{
+    nmem_init();
+    if (!(out = odr_createmem(ODR_ENCODE)) ||
+        !(in = odr_createmem(ODR_DECODE)) ||
+        !(print = odr_createmem(ODR_PRINT)))
+    {
+        fprintf(stderr, "failed to allocate ODR streams\n");
+        exit(1);
+    }
+    setvbuf(stdout, 0, _IONBF, 0);
+    if (apdu_file)
+        odr_setprint(print, apdu_file);
+
+    cmd_base("Default");
+}
+
+static int z_getAPDU (Z_APDU **ret_apdu) {
+  int res;
+
+    char *netbuffer= 0;
+    int netbufferlen = 0;
+    Z_APDU *apdu;
+    
+    if ((res = cs_get(conn, &netbuffer, &netbufferlen)) < 0) {
+      perror("cs_get");
+      exit(1);
+    }
+    if (!res) {
+      printf("Target closed connection.\n");
+      exit(1);
+    }
+    odr_reset(in); /* release APDU from last round */
+    record_last = 0;
+    odr_setbuf(in, netbuffer, res, 0);
+    /* johnmcp */
+    if (!z_APDU(in, &apdu, 0, 0))
+      {
+	odr_perror(in, "Decoding incoming APDU");
+	fprintf(stderr, "[Near %d]\n", odr_offset(in));
+	fprintf(stderr, "Packet dump:\n---------\n");
+	odr_dumpBER(stderr, netbuffer, res);
+	fprintf(stderr, "---------\n");
+	if (apdu_file)
+	  z_APDU(print, &apdu, 0, 0);
+	exit(1);
+      }
+    if (apdu_file && !z_APDU(print, &apdu, 0, 0))
+      {
+	odr_perror(print, "Failed to print incoming APDU");
+	odr_reset(print);
+	return -1; /* was continue */
+      }
+    (*ret_apdu)=apdu;
+    return 0;
+}
+
+
+/* returns number found, arg is query string */
+int z_cmd_dosearch(char *arg)
+{
+  Z_APDU *apdu;
+  int matching;
+  int ret_val;
+  ret_val=send_searchRequest(arg);
+  if (ret_val==-1) {
+    /* prefix query error */
+    return (-1);
+  }
+  z_getAPDU(&apdu);
+  /* check return value??? */
+  if (apdu->which != Z_APDU_searchResponse)
+    {
+      printf("sendsearchRequest() was not replied with a searchResponse!\n");
+      return (-2);
+    }
+  /* let's keep going anyway... */
+  matching=process_searchResponse(apdu->u.searchResponse);
+  /* this assumes we want to take action on failure (-1) here rather than
+     whereever we were called from */
+  return (matching);
+}
+
+/* src must be NULL-terminated */
+static char *safeappendstr(char *dest, size_t *allocsize, 
+			  size_t *offset, char *src) {
+  /* allocsize is the amount of space currently allocated to dest,
+     offset is how far into dest we want to append src */
+  if (*offset + strlen(src) >= *allocsize) {
+    *allocsize+=strlen(src)+64; /* add some extra space to save on reallocs */
+    if ((dest=realloc(dest,*allocsize))==NULL) {
+      fprintf(stderr, "malloc failed while decoding marc record.\n");
+      return (NULL);
+    }
+  }
+  strcpy(dest+(*offset), src);
+  *offset+=strlen(src);
+  return (dest);
+}
+
+static char *getmarcfields(Z_DatabaseRecord *p, int titleonly) {
+  /* this code is based on marc_display(), with a couple of lines taken from
+     display_record() in the original client. */
+  /* if titleonly is non-zero, we only get a (the?) title field, otherwise
+     return the whole thing */
+  const char *buf=(char *)p->u.octet_aligned->buf;
+  char *title;      /* our string to return */
+  int title_maxlen=0; /* amount of space currently allocated */
+  int title_curlen=0;    /* amount of space actually used */
+  int entry_p;
+  int record_length;
+  int indicator_length;
+  int identifier_length;
+  int base_address;
+  int length_data_entry;
+  int length_starting;
+  int length_implementation;
+  FILE *outf;
+
+  /*  if (!outf) */
+  outf = stdout;
+
+  /* initialise our title. Start with 64 chars */
+  title_maxlen=64;
+  if((title=malloc(title_maxlen))==NULL) {
+    /* not quite sure where stderr will be going, but.... */
+    fprintf(stderr,"Malloc failed while decoding marc record\n");
+    return NULL;
+  }
+
+  if (!titleonly) {
+    strcpy(title,"<table border=1>\n");
+    title_curlen=strlen(title);
+  }
+  else  title_curlen=0;
+
+  record_length = atoi_n (buf, 5);
+  if (record_length < 25)
+    return (NULL); /* -1 */
+  if (isdigit(buf[10]))
+    indicator_length = atoi_n (buf+10, 1);
+  else
+    indicator_length = 2;
+  if (isdigit(buf[11]))
+    identifier_length = atoi_n (buf+11, 1);
+  else
+    identifier_length = 2;
+  base_address = atoi_n (buf+12, 4);
+  
+  length_data_entry = atoi_n (buf+20, 1);
+  length_starting = atoi_n (buf+21, 1);
+  length_implementation = atoi_n (buf+22, 1);
+  
+  if (0) /* debug */
+    {
+      fprintf (outf, "Record length         %5d\n", record_length);
+      fprintf (outf, "Indicator length      %5d\n", indicator_length);
+      fprintf (outf, "Identifier length     %5d\n", identifier_length);
+      fprintf (outf, "Base address          %5d\n", base_address);
+      fprintf (outf, "Length data entry     %5d\n", length_data_entry);
+      fprintf (outf, "Length starting       %5d\n", length_starting);
+      fprintf (outf, "Length implementation %5d\n", length_implementation);
+    }
+  for (entry_p = 24; buf[entry_p] != ISO2709_FS; )
+    {
+      entry_p += 3+length_data_entry+length_starting;
+      if (entry_p >= record_length)
+	return (NULL); /* -1 */
+    }
+  base_address = entry_p+1;
+  for (entry_p = 24; buf[entry_p] != ISO2709_FS; )
+    {
+      int data_length;
+      int data_offset;
+      int end_offset;
+      int i /*, j*/ ;
+      int startofstring;
+      int whichtag;
+      short int abbrtitle=0;
+      char tag[4];
+      memcpy (tag, buf+entry_p, 3);
+      entry_p += 3;
+      tag[3] = '\0';
+      whichtag=atoi(tag);
+      if (0) /* debug */
+	fprintf (outf, "Tag: ");
+      /* johnmcp 
+	 Relevant tags (for "main entry") - assume only one of these is set,
+	 as we will only return the first one found.
+	 100=personal name
+	 110=corporate name
+	 111=meeting name
+	 130=uniform title
+	 subfields: $a=personal name, $c=title/other, $d=date
+
+	 210=Abbreviated Title
+	 222=Key title
+	 240=uniform title
+	 243=collective uniform title
+	 245=title statement
+	 246=varying form of title
+	 247=former title or title variations
+	 subfields: $a=abbrev. title $b=qualifying info $2=source
+	 .          $6=linkage $8=link field and sequence number.
+      */
+      /*fprintf (outf, "%s ", tag); */
+      data_length = atoi_n (buf+entry_p, length_data_entry);
+      entry_p += length_data_entry;
+      data_offset = atoi_n (buf+entry_p, length_starting);
+      entry_p += length_starting;
+      i = data_offset + base_address;
+      end_offset = i+data_length-1;
+
+      if (0) /* debug */
+	fprintf (outf, " Ind: ");
+
+      /* memcmp (tag,"00",2) is true, then we DON'T have a control tag
+	 ie less than 10. */
+      /*if (memcmp (tag, "00", 2) && indicator_length)
+	{
+	for (j = 0; j<indicator_length; j++)
+	fprintf (outf, "%c", buf[i++]);
+	}
+      */
+      if (whichtag>=10) i+=indicator_length;
+      /* the control fields (<10) don't have leading chars. */
+
+
+      if (0) /* debug */
+	fprintf (outf, " Fields: ");
+
+      /* If we only want the title, then skip other fields */
+      if (titleonly &&(whichtag<200||whichtag>249)) {
+	/* skip this record */
+	continue;
+	i=end_offset;
+      }
+      
+      /* either titleonly is 0, or titleonly is 1 and whichtag is between
+	 200 and 249... */
+      if (!titleonly) {
+	/* print out what kind of tag this is */
+	char *tagname;
+	char *field_control1="<tr><td>Marc Control Number:</td><td>";
+	char *field_control3="<tr><td>Marc Organisation Code:</td><td>";
+	char *field_control5="<tr><td>Marc record Date Info.:</td><td>";
+	char *field_control8="<tr><td>Control Field (Marc info):</td><td>";
+	char *field_loc_nr="<tr><td>Lib. of Congress control #:</td><td>";
+	char *field_issn="<tr><td>ISSN Number:</td><td>";
+	char *field_catalog="<tr><td>Catalog agency:</td><td>";
+	char *field_lang="<tr><td>3-letter language code(s):</td><td>";
+	char *field_areacode="<tr><td>Geographic Area code:</td><td>";
+	char *field_cn_loc="<tr><td>Lib. of Congress Call #:</td><td>";
+	char *field_cn_dewdec="<tr><td>Dewey Decimal Call #:</td><td>";
+	char *field_cn_other="<tr><td>Other Classification Info.:</td><td>";
+	char *field_cn_gd="<tr><td>Govt. Document Call #:</td><td>";
+	char *field_personalname="<tr><td>Personal Name:</td><td>";
+	char *field_meetingname="<tr><td>Meeting Name:</td><td>";
+	char *field_maintitle="<tr><td>Title:</td><td>";
+	char *field_edition="<tr><td><Edition Information:</td><td>";
+	char *field_publication="<tr><td>Publication Info.:</td><td>";
+	char *field_physdesc="<tr><td>Physical Description:</td><td>";
+	char *field_series_title="<tr><td>Series Title:</td><td>";
+	char *field_series_statement="<tr><td>Series Statement:</td><td>";
+	char *field_note_general="<tr><td>Note:</td><td>";
+	char *field_note_bib="<tr><td>Bibliographic Note:</td><td>";
+	char *field_note_summary="<tr><td>Summary Note:</td><td>";
+	char *field_sub_note="<tr><td>Subject Notes:</td><td>";
+	char *field_sub_topic="<tr><td>Subject - Topic:</td><td>";
+	char *field_added_persname="<tr><td>Author Note - Name:</td><td>";
+	char *field_added_corpname="<tr><td>Author - Organisation:</td><td>";
+	char *field_uniform_title="<tr><td>Extra Title Information:</td><td>";
+	char *field_host_item="<tr><td>In:</td><td>";
+	char *field_series_corpname="<tr><td>Series - Organisation:</td><td>";
+	/*char *field_other="<tr><td>(other field):</td><td>";*/
+	char tag_num[100];
+	switch (whichtag) {
+	case (1): {tagname=field_control1;break;}
+	case (3): {tagname=field_control3;break;}
+	case (5): {tagname=field_control5;break;}
+	case (8): {tagname=field_control8;break;}
+	case (10): {tagname=field_loc_nr;break;}
+	case (20): {tagname=field_issn;break;}
+	case (40): {tagname=field_catalog;break;}
+	case (41): {tagname=field_lang;break;}
+	case (43): {tagname=field_areacode;break;}
+	case (50): {tagname=field_cn_loc;break;}
+	case (82): {tagname=field_cn_dewdec;break;}
+	case (84): {tagname=field_cn_other;break;}
+	case (86): {tagname=field_cn_gd;break;}
+	case (100): {tagname=field_personalname;break;}
+	case (111): {tagname=field_meetingname;break;}
+	case (245): {tagname=field_maintitle;break;}
+	case (250): {tagname=field_edition;break;}
+	case (260): {tagname=field_publication;break;}
+	case (300): {tagname=field_physdesc;break;}
+	case (440): {tagname=field_series_title;break;}
+	case (490): {tagname=field_series_statement;break;}
+	case (500): {tagname=field_note_general;break;}
+	case (504): {tagname=field_note_bib;break;}
+	case (520): {tagname=field_note_summary;break;}
+	case (630): {tagname=field_sub_note;break;}
+	case (650): {tagname=field_sub_topic;break;}
+	case (700): {tagname=field_added_persname;break;}
+	case (710): {tagname=field_added_corpname;break;}
+	case (730): {tagname=field_uniform_title;break;}
+	case (773): {tagname=field_host_item;break;}
+	case (810): {tagname=field_series_corpname;break;}
+	default: 
+	  if (whichtag>=90&&whichtag<=99)
+	    tagname="<tr><td>(obsolete field) Call #:</td><td>";
+	  else {
+	    /*tagname=field_other;*/
+	    
+	    /*.*********** Following line "causes" (ie exposes) a seg fault
+	      in realloc(title,...). What is causing this????.
+	      ANSWER: The trailing '\0' needs to be explicit :-)   */
+	    sprintf(tag_num,"<tr><td>(field %d)</td><td>\n\0",whichtag);
+	    tagname=tag_num;
+	  }
+	}
+
+	/* add the field type */
+	title=safeappendstr(title, &title_maxlen, &title_curlen, tagname);
+      }
+
+      /* go through current field in current record */
+      while (buf[i] != ISO2709_RS && buf[i] != ISO2709_FS && i < end_offset)
+	{
+	  /* this loop goes through byte by byte, to find end-of-field or
+	     end-of-record separator tags */
+
+	  /*	  if (memcmp (tag, "00", 2) && identifier_length)*/
+	  if ( ((titleonly==1&&whichtag==245)||(titleonly==0))
+	       && identifier_length)
+	    {
+	      if (buf[i]==ISO2709_IDFS) {
+		/*  this implies sub-fields for this field */
+		/* skip sub-field tag, but wrap $a sub-field with <b> & </b> 
+		   for HTML if titleonly==1 */
+		if (buf[i+1]=='a' && titleonly) {
+		  abbrtitle=1;
+		  title=safeappendstr(title,&title_maxlen,&title_curlen,"<b>");
+		}
+		i+=identifier_length; 
+	      }
+	      /* find end of this (sub-)field */
+	      startofstring=i;
+	      while (buf[i] != ISO2709_RS && buf[i] != ISO2709_IDFS &&
+		     buf[i] != ISO2709_FS && i < end_offset)
+		i++;
+		/*fprintf (outf, "%c", buf[i++]);*/
+
+	      /* this only happens the first time around */
+	      if (i==startofstring) continue;
+
+	      /* now put from $startofstring$ until $i$ into our 
+		 string to return */
+
+	      if (title_curlen+(i-startofstring)>=title_maxlen) {
+		/* we need to make more room - add max(64,needed) bytes */
+		if (title_curlen+(i-startofstring)-title_maxlen>63)
+		  title_maxlen+=(i-startofstring)+1;/*+1 for trailing \0 */
+		else
+		  title_maxlen+=64;
+		if ((title=realloc(title,title_maxlen))==NULL) {
+		  fprintf(stderr,"malloc failed decoding marc record\n");
+		  return (NULL);
+		}
+	      }
+
+	      strncpy(title+title_curlen,buf+startofstring,i-startofstring);
+	      title_curlen+=(i-startofstring);
+	      *(title+title_curlen)='\0';
+	      /* overwrite ISO2709_?S with \0 */
+	      /* *(title+title_curlen+i-startofstring)='\0';*/
+	      /*safeappendstr(title,&title_maxlen,
+		&title_curlen,buf+startofstring);*/
+
+	      /* if 'main' title, close HTML </B> tag */
+	      if (abbrtitle) {
+		title=safeappendstr(title,&title_maxlen,&title_curlen,"</b>");
+		abbrtitle=0;
+	      } 
+	      /* end of this marc sub--field                 
+		 buf[i]==ISO2709_RS if end of  record.
+		 buf[i]==ISO2709_FS if end of  field,
+		 buf[i]==ISO2709_IDFS if end of sub-field. */
+	      if (titleonly==0) {
+		if (buf[i]==ISO2709_IDFS) {
+		  /* there is a following sub-field, so only add whitespace */
+		  title=safeappendstr(title,&title_maxlen,&title_curlen," ");
+		}
+		else {
+		  /* end of record, so close HTML table row */
+		  title=safeappendstr(title, &title_maxlen, &title_curlen,
+				      "</td></tr>\n");
+		}
+	      }  /* end of  if (titleonly==0)                */
+	    }    /* end of  if ( ((titleonly==1&&.......     */
+	  else { /* whichtag not matched  (if titleonly)     */
+	    /*fprintf (outf, "%c", buf[i++]);*/
+	    /* skip this char for now - should ideally skip whole field */
+	    i++;
+	  }
+	} /* end of while loop - at end of field or record */
+      /*fprintf (outf, "\n");*/
+      /*if (i < end_offset)
+	fprintf (outf, "-- separator but not at end of field\n");
+	if (buf[i] != ISO2709_RS && buf[i] != ISO2709_FS)
+	fprintf (outf, "-- no separator at end of field\n");
+      */
+    }
+
+  /* at end of whole record. */
+  if (!titleonly) 
+    title=safeappendstr(title, &title_maxlen, &title_curlen, "</table>\n");
+  return (title);
+
+}
+static char *getrecordtitle(Z_DatabaseRecord *record) {
+  return(getmarcfields(record,1));
+}
+
+char *z_getfullRecord(int start) {
+  Z_APDU *apdu;
+  Z_DatabaseRecord *record;
+  char *fullrecord;
+
+  fullrecord=NULL;
+  z_send_getbriefrecords(start,1,1); /* for now, use getbriefrecords */
+  z_getAPDU(&apdu);
+  
+  if (apdu->which != Z_APDU_presentResponse) {
+    /* out-of-order packets.... */
+    fprintf(stderr,"Not a present response to present request\n");
+    return NULL;
+  }
+  
+  /* just do some double checking */
+  if (*apdu->u.presentResponse->numberOfRecordsReturned!=1 ||
+      !apdu->u.presentResponse->records ||
+      apdu->u.presentResponse->records->which!=Z_Records_DBOSD) {
+    /* something bad has happened... johnmcp */
+    fprintf (stderr,"Error occured in yaz while getting record (GSDL)\n");
+  }
+
+  record=apdu->u.presentResponse->records->u.databaseOrSurDiagnostics->
+    records[0]->u.databaseRecord;
+
+  return(getmarcfields(record,0));
+}
+
+char **z_getrecordTitles(/*int resultset,*/ int starting, int howmany) {
+  Z_APDU *apdu;
+  char **titles;
+  /* titles will be an array of strings. The first element will really
+     be an int, saying how many strings follow. Ie 1st string in titles[1] */
+  int count;
+  int i;
+
+  titles=NULL;
+
+  /* WE SHOULD SET THE RECORD FORMAT SOMEWHERE..... USMARC (default)
+     but may also want SUTRS support. */
+
+  /* sends a presentRequest - we need to know the set number - johnmcp */
+  z_send_getbriefrecords(starting, 1, howmany);
+  /* CHECK RETURN VALUE (currently only 0) */
+  
+
+  z_getAPDU(&apdu);
+  if (apdu->which != Z_APDU_presentResponse) {
+    /* we got out-of-sync.... */
+    fprintf(stderr,"Not a present response to present request\n");
+    return NULL;
+  }
+  
+  print_refid (apdu->u.presentResponse->referenceId);
+  count=*apdu->u.presentResponse->numberOfRecordsReturned;
+  setno += count;
+  if (apdu->u.presentResponse->records) {
+    /* extract the titles from each record, and return it as an array of 
+       strings */
+    if (count==1 &&
+	apdu->u.presentResponse->records->which!=Z_Records_DBOSD) {
+      /* apdu->u.presentResponse->records->which gives a type:
+	 1=databaseOrSurDiagnostics | 2=nonSurrogateDiagnostic | 
+	 3=multipleNonSurDiagnostics.
+	 Type 1 implies it is a database record. FROM z-core.h,
+      NOT prt-proto.h!!!!! */
+
+      /* for type 2:
+	 apdu->u.presentResponse->records->u.nonSurrogateDiagnostic->which:
+	 1=v2Addinfo | 2=v3Addinfo, and u.v[23]Addinfo is a (char *).
+
+      */
+      titles=malloc(sizeof(char *));
+      titles[0]=(char *)0;
+      /* could put error message and titles[1], and set titles[0] to -1. */
+
+
+    }
+    else /* more than 1 rec returned, so ?has? to be db records (dblcheck!!)*/
+      {
+	titles=malloc(sizeof(char *)*count + 1);
+	/* check malloc succeeded... */
+	titles[0]=(char *)count;
+	for (i=1;i<=count;i++) {
+	  titles[i]=getrecordtitle(apdu->u.presentResponse->records->
+				   u.databaseOrSurDiagnostics->records[i-1]->
+				   u.databaseRecord);
+	}
+      } 
+  }
+  else {
+    titles=malloc(sizeof(char *));
+    titles[0]=(char *)0;
+  }
+  /*  printf ("nextResultSetPosition = %d\n",
+   *apdu->u.presentResponse->nextResultSetPosition); */
+  return (titles);
+}
+
+
+int z_getnextAPDU()
+{
+  Z_APDU *apdu;
+  apdu=NULL;
+  
+  z_getAPDU(&apdu);
+  
+  switch(apdu->which)
+    {
+    case Z_APDU_initResponse:
+      /* save session parameters for later use */
+      session_mem = odr_extract_mem(in);
+      session=apdu->u.initResponse;
+      /*process_initResponse();*/
+      break;
+    case Z_APDU_searchResponse:
+      process_searchResponse(apdu->u.searchResponse);
+      break;
+    case Z_APDU_scanResponse:
+      process_scanResponse(apdu->u.scanResponse);
+      break;
+    case Z_APDU_presentResponse:
+      print_refid (apdu->u.presentResponse->referenceId);
+      setno +=
+	*apdu->u.presentResponse->numberOfRecordsReturned;
+      if (apdu->u.presentResponse->records)
+	display_records(apdu->u.presentResponse->records);
+      else
+	printf("No records.\n");
+      printf ("nextResultSetPosition = %d\n",
+	      *apdu->u.presentResponse->nextResultSetPosition);
+      break;
+    case Z_APDU_sortResponse:
+      process_sortResponse(apdu->u.sortResponse);
+      break;
+    case Z_APDU_extendedServicesResponse:
+      printf("Got extended services response\n");
+      process_ESResponse(apdu->u.extendedServicesResponse);
+      break;
+    case Z_APDU_close:
+      printf("Target has closed the association.\n");
+      process_close(apdu->u.close);
+      break;
+    case Z_APDU_resourceControlRequest:
+      process_resourceControlRequest
+	(apdu->u.resourceControlRequest);
+      break;
+    case Z_APDU_deleteResultSetResponse:
+      process_deleteResultSetResponse(apdu->u.
+				      deleteResultSetResponse);
+      break;
+    default:
+      printf("Received unknown APDU type (%d).\n", 
+	     apdu->which);
+      exit(1);
+    }
+  
+  /*while (conn && cs_more(conn));*/
+  return 0;
+}
Index: /main/tags/2.25/gsdl/packages/yaz/comstack/Makefile.am
===================================================================
--- /main/tags/2.25/gsdl/packages/yaz/comstack/Makefile.am	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/yaz/comstack/Makefile.am	(revision 21064)
@@ -0,0 +1,8 @@
+## $Id$
+
+noinst_LIBRARIES=libcomstack.a
+
+INCLUDES=-I../include
+
+libcomstack_a_SOURCES=comstack.c tcpip.c waislen.c 
+
Index: /main/tags/2.25/gsdl/packages/yaz/comstack/Makefile.in
===================================================================
--- /main/tags/2.25/gsdl/packages/yaz/comstack/Makefile.in	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/yaz/comstack/Makefile.in	(revision 21064)
@@ -0,0 +1,266 @@
+# Makefile.in generated automatically by automake 1.4 from Makefile.am
+
+# Copyright (C) 1994, 1995-8, 1999 Free Software Foundation, Inc.
+# This Makefile.in is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
+# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE.
+
+
+SHELL = @SHELL@
+
+srcdir = @srcdir@
+top_srcdir = @top_srcdir@
+VPATH = @srcdir@
+prefix = @prefix@
+exec_prefix = @exec_prefix@
+
+bindir = @bindir@
+sbindir = @sbindir@
+libexecdir = @libexecdir@
+datadir = @datadir@
+sysconfdir = @sysconfdir@
+sharedstatedir = @sharedstatedir@
+localstatedir = @localstatedir@
+libdir = @libdir@
+infodir = @infodir@
+mandir = @mandir@
+includedir = @includedir@
+oldincludedir = /usr/include
+
+DESTDIR =
+
+pkgdatadir = $(datadir)/@PACKAGE@
+pkglibdir = $(libdir)/@PACKAGE@
+pkgincludedir = $(includedir)/@PACKAGE@
+
+top_builddir = ..
+
+ACLOCAL = @ACLOCAL@
+AUTOCONF = @AUTOCONF@
+AUTOMAKE = @AUTOMAKE@
+AUTOHEADER = @AUTOHEADER@
+
+INSTALL = @INSTALL@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@ $(AM_INSTALL_PROGRAM_FLAGS)
+INSTALL_DATA = @INSTALL_DATA@
+INSTALL_SCRIPT = @INSTALL_SCRIPT@
+transform = @program_transform_name@
+
+NORMAL_INSTALL = :
+PRE_INSTALL = :
+POST_INSTALL = :
+NORMAL_UNINSTALL = :
+PRE_UNINSTALL = :
+POST_UNINSTALL = :
+ASNMODULE = @ASNMODULE@
+CC = @CC@
+CPP = @CPP@
+ILLLIB = @ILLLIB@
+ILLMODULE = @ILLMODULE@
+MAKEINFO = @MAKEINFO@
+PACKAGE = @PACKAGE@
+RANLIB = @RANLIB@
+SUBDIRS_VAR = @SUBDIRS_VAR@
+VERSION = @VERSION@
+have_sgml2html = @have_sgml2html@
+have_sgml2latex = @have_sgml2latex@
+have_sgml2txt = @have_sgml2txt@
+
+noinst_LIBRARIES = libcomstack.a
+
+INCLUDES = -I../include
+
+libcomstack_a_SOURCES = comstack.c tcpip.c waislen.c 
+mkinstalldirs = $(SHELL) $(top_srcdir)/mkinstalldirs
+CONFIG_CLEAN_FILES = 
+LIBRARIES =  $(noinst_LIBRARIES)
+
+
+DEFS = @DEFS@ -I. -I$(srcdir) 
+CPPFLAGS = @CPPFLAGS@
+LDFLAGS = @LDFLAGS@
+LIBS = @LIBS@
+libcomstack_a_LIBADD = 
+libcomstack_a_OBJECTS =  comstack.o tcpip.o waislen.o
+AR = ar
+CFLAGS = @CFLAGS@
+COMPILE = $(CC) $(DEFS) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
+CCLD = $(CC)
+LINK = $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(LDFLAGS) -o $@
+DIST_COMMON =  Makefile.am Makefile.in
+
+
+DISTFILES = $(DIST_COMMON) $(SOURCES) $(HEADERS) $(TEXINFOS) $(EXTRA_DIST)
+
+TAR = gtar
+GZIP_ENV = --best
+SOURCES = $(libcomstack_a_SOURCES)
+OBJECTS = $(libcomstack_a_OBJECTS)
+
+all: all-redirect
+.SUFFIXES:
+.SUFFIXES: .S .c .o .s
+$(srcdir)/Makefile.in: Makefile.am $(top_srcdir)/configure.in $(ACLOCAL_M4) 
+	cd $(top_srcdir) && $(AUTOMAKE) --gnu --include-deps comstack/Makefile
+
+Makefile: $(srcdir)/Makefile.in  $(top_builddir)/config.status
+	cd $(top_builddir) \
+	  && CONFIG_FILES=$(subdir)/$@ CONFIG_HEADERS= $(SHELL) ./config.status
+
+
+mostlyclean-noinstLIBRARIES:
+
+clean-noinstLIBRARIES:
+	-test -z "$(noinst_LIBRARIES)" || rm -f $(noinst_LIBRARIES)
+
+distclean-noinstLIBRARIES:
+
+maintainer-clean-noinstLIBRARIES:
+
+.c.o:
+	$(COMPILE) -c $<
+
+.s.o:
+	$(COMPILE) -c $<
+
+.S.o:
+	$(COMPILE) -c $<
+
+mostlyclean-compile:
+	-rm -f *.o core *.core
+
+clean-compile:
+
+distclean-compile:
+	-rm -f *.tab.c
+
+maintainer-clean-compile:
+
+libcomstack.a: $(libcomstack_a_OBJECTS) $(libcomstack_a_DEPENDENCIES)
+	-rm -f libcomstack.a
+	$(AR) cru libcomstack.a $(libcomstack_a_OBJECTS) $(libcomstack_a_LIBADD)
+	$(RANLIB) libcomstack.a
+
+tags: TAGS
+
+ID: $(HEADERS) $(SOURCES) $(LISP)
+	list='$(SOURCES) $(HEADERS)'; \
+	unique=`for i in $$list; do echo $$i; done | \
+	  awk '    { files[$$0] = 1; } \
+	       END { for (i in files) print i; }'`; \
+	here=`pwd` && cd $(srcdir) \
+	  && mkid -f$$here/ID $$unique $(LISP)
+
+TAGS:  $(HEADERS) $(SOURCES)  $(TAGS_DEPENDENCIES) $(LISP)
+	tags=; \
+	here=`pwd`; \
+	list='$(SOURCES) $(HEADERS)'; \
+	unique=`for i in $$list; do echo $$i; done | \
+	  awk '    { files[$$0] = 1; } \
+	       END { for (i in files) print i; }'`; \
+	test -z "$(ETAGS_ARGS)$$unique$(LISP)$$tags" \
+	  || (cd $(srcdir) && etags $(ETAGS_ARGS) $$tags  $$unique $(LISP) -o $$here/TAGS)
+
+mostlyclean-tags:
+
+clean-tags:
+
+distclean-tags:
+	-rm -f TAGS ID
+
+maintainer-clean-tags:
+
+distdir = $(top_builddir)/$(PACKAGE)-$(VERSION)/$(subdir)
+
+subdir = comstack
+
+distdir: $(DISTFILES)
+	@for file in $(DISTFILES); do \
+	  d=$(srcdir); \
+	  if test -d $$d/$$file; then \
+	    cp -pr $$/$$file $(distdir)/$$file; \
+	  else \
+	    test -f $(distdir)/$$file \
+	    || ln $$d/$$file $(distdir)/$$file 2> /dev/null \
+	    || cp -p $$d/$$file $(distdir)/$$file || :; \
+	  fi; \
+	done
+
+info-am:
+info: info-am
+dvi-am:
+dvi: dvi-am
+check-am: all-am
+check: check-am
+installcheck-am:
+installcheck: installcheck-am
+install-exec-am:
+install-exec: install-exec-am
+
+install-data-am:
+install-data: install-data-am
+
+install-am: all-am
+	@$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
+install: install-am
+uninstall-am:
+uninstall: uninstall-am
+all-am: Makefile $(LIBRARIES)
+all-redirect: all-am
+install-strip:
+	$(MAKE) $(AM_MAKEFLAGS) AM_INSTALL_PROGRAM_FLAGS=-s install
+installdirs:
+
+
+mostlyclean-generic:
+
+clean-generic:
+
+distclean-generic:
+	-rm -f Makefile $(CONFIG_CLEAN_FILES)
+	-rm -f config.cache config.log stamp-h stamp-h[0-9]*
+
+maintainer-clean-generic:
+mostlyclean-am:  mostlyclean-noinstLIBRARIES mostlyclean-compile \
+		mostlyclean-tags mostlyclean-generic
+
+mostlyclean: mostlyclean-am
+
+clean-am:  clean-noinstLIBRARIES clean-compile clean-tags clean-generic \
+		mostlyclean-am
+
+clean: clean-am
+
+distclean-am:  distclean-noinstLIBRARIES distclean-compile \
+		distclean-tags distclean-generic clean-am
+
+distclean: distclean-am
+
+maintainer-clean-am:  maintainer-clean-noinstLIBRARIES \
+		maintainer-clean-compile maintainer-clean-tags \
+		maintainer-clean-generic distclean-am
+	@echo "This command is intended for maintainers to use;"
+	@echo "it deletes files that may require special tools to rebuild."
+
+maintainer-clean: maintainer-clean-am
+
+.PHONY: mostlyclean-noinstLIBRARIES distclean-noinstLIBRARIES \
+clean-noinstLIBRARIES maintainer-clean-noinstLIBRARIES \
+mostlyclean-compile distclean-compile clean-compile \
+maintainer-clean-compile tags mostlyclean-tags distclean-tags \
+clean-tags maintainer-clean-tags distdir info-am info dvi-am dvi check \
+check-am installcheck-am installcheck install-exec-am install-exec \
+install-data-am install-data install-am install uninstall-am uninstall \
+all-redirect all-am all installdirs mostlyclean-generic \
+distclean-generic clean-generic maintainer-clean-generic clean \
+mostlyclean distclean maintainer-clean
+
+
+# Tell versions [3.59,3.63) of GNU make to not export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:
Index: /main/tags/2.25/gsdl/packages/yaz/comstack/comstack.c
===================================================================
--- /main/tags/2.25/gsdl/packages/yaz/comstack/comstack.c	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/yaz/comstack/comstack.c	(revision 21064)
@@ -0,0 +1,52 @@
+/*
+ * Copyright (c) 1995-1998, Index Data
+ * See the file LICENSE for details.
+ * Sebastian Hammer, Adam Dickmeiss
+ *
+ * $Log$
+ * Revision 1.1  2000/08/03 03:10:04  johnmcp
+ * Added the YAZ toolkit source to the packages directory (for z39.50 stuff)
+ *
+ * Revision 1.6  1999/11/30 13:47:11  adam
+ * Improved installation. Moved header files to include/yaz.
+ *
+ * Revision 1.5  1998/06/22 11:32:35  adam
+ * Added 'conditional cs_listen' feature.
+ *
+ * Revision 1.4  1997/09/29 07:16:14  adam
+ * Array cs_errlist no longer global.
+ *
+ * Revision 1.3  1997/09/01 08:49:14  adam
+ * New windows NT/95 port using MSV5.0. Minor changes only.
+ *
+ * Revision 1.2  1995/09/29 17:01:48  quinn
+ * More Windows work
+ *
+ * Revision 1.1  1995/06/14  09:58:20  quinn
+ * Renamed yazlib to comstack.
+ *
+ * Revision 1.2  1995/05/16  08:51:15  quinn
+ * License, documentation, and memory fixes
+ *
+ * Revision 1.1  1995/03/14  10:28:34  quinn
+ * Adding server-side support to tcpip.c and fixing bugs in nonblocking I/O
+ *
+ *
+ */
+
+#include <yaz/comstack.h>
+
+static const char *cs_errlist[] =
+{
+    "No error or unspecified error",
+    "System (lower-layer) error",
+    "Operation out of state",
+    "No data (operation would block)",
+    "New data while half of old buffer is on the line (flow control)",
+    "Permission denied"
+};
+
+const char *cs_errmsg(int n)
+{
+    return cs_errlist[n];
+}
Index: /main/tags/2.25/gsdl/packages/yaz/comstack/tcpip.c
===================================================================
--- /main/tags/2.25/gsdl/packages/yaz/comstack/tcpip.c	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/yaz/comstack/tcpip.c	(revision 21064)
@@ -0,0 +1,717 @@
+/*
+ * Copyright (c) 1995-1999, Index Data
+ * See the file LICENSE for details.
+ * Sebastian Hammer, Adam Dickmeiss
+ *
+ * $Log$
+ * Revision 1.1  2000/08/03 03:10:05  johnmcp
+ * Added the YAZ toolkit source to the packages directory (for z39.50 stuff)
+ *
+ * Revision 1.32  1999/11/30 13:47:11  adam
+ * Improved installation. Moved header files to include/yaz.
+ *
+ * Revision 1.31  1999/04/29 07:31:23  adam
+ * Changed tcpip_strtoaddr_ex so that only part 'till '/' is considered
+ * part of hostname.
+ *
+ * Revision 1.30  1999/04/20 09:56:48  adam
+ * Added 'name' paramter to encoder/decoder routines (typedef Odr_fun).
+ * Modified all encoders/decoders to reflect this change.
+ *
+ * Revision 1.29  1999/04/16 14:45:55  adam
+ * Added interface for tcpd wrapper for access control.
+ *
+ * Revision 1.28  1999/03/31 11:11:14  adam
+ * Function getprotobyname only called once. Minor change in tcpip_get
+ * to handle multi-threaded conditions.
+ *
+ * Revision 1.27  1999/02/02 13:57:31  adam
+ * Uses preprocessor define WIN32 instead of WINDOWS to build code
+ * for Microsoft WIN32.
+ *
+ * Revision 1.26  1999/01/08 11:23:14  adam
+ * Added const modifier to some of the BER/ODR encoding routines.
+ *
+ * Revision 1.25  1998/07/07 15:49:23  adam
+ * Added braces to avoid warning.
+ *
+ * Revision 1.24  1998/06/29 07:59:17  adam
+ * Minor fix.
+ *
+ * Revision 1.23  1998/06/23 15:37:50  adam
+ * Added type cast to prevent warning.
+ *
+ * Revision 1.22  1998/06/22 11:32:36  adam
+ * Added 'conditional cs_listen' feature.
+ *
+ * Revision 1.21  1998/05/20 09:55:32  adam
+ * Function tcpip_get treats EINPROGRESS error in the same way as
+ * EWOULDBLOCK. EINPROGRESS shouldn't be returned - but it is on
+ * Solaris in some cases.
+ *
+ * Revision 1.20  1998/05/18 10:10:40  adam
+ * Minor change to avoid C++ warning.
+ *
+ * Revision 1.19  1998/02/11 11:53:33  adam
+ * Changed code so that it compiles as C++.
+ *
+ * Revision 1.18  1997/09/29 07:15:25  adam
+ * Changed use of setsockopt to avoid warnings on MSVC.
+ *
+ * Revision 1.17  1997/09/17 12:10:30  adam
+ * YAZ version 1.4.
+ *
+ * Revision 1.16  1997/09/01 08:49:14  adam
+ * New windows NT/95 port using MSV5.0. Minor changes only.
+ *
+ * Revision 1.15  1997/05/14 06:53:33  adam
+ * C++ support.
+ *
+ * Revision 1.14  1997/05/01 15:06:32  adam
+ * Moved WINSOCK init. code to tcpip_init routine.
+ *
+ * Revision 1.13  1996/11/01 08:45:18  adam
+ * Bug fix: used close on MS-Windows. Fixed to closesocket.
+ *
+ * Revision 1.12  1996/07/06 19:58:30  quinn
+ * System headerfiles gathered in yconfig
+ *
+ * Revision 1.11  1996/02/23  10:00:39  quinn
+ * WAIS Work
+ *
+ * Revision 1.10  1996/02/20  12:52:11  quinn
+ * WAIS protocol support.
+ *
+ * Revision 1.9  1996/02/10  12:23:11  quinn
+ * Enablie inetd operations fro TCP/IP stack
+ *
+ * Revision 1.8  1995/11/01  13:54:27  quinn
+ * Minor adjustments
+ *
+ * Revision 1.7  1995/10/30  12:41:16  quinn
+ * Added hostname lookup for server.
+ *
+ * Revision 1.6  1995/09/29  17:12:00  quinn
+ * Smallish
+ *
+ * Revision 1.5  1995/09/29  17:01:48  quinn
+ * More Windows work
+ *
+ * Revision 1.4  1995/09/28  10:12:26  quinn
+ * Windows-support changes
+ *
+ * Revision 1.3  1995/09/27  15:02:45  quinn
+ * Modified function heads & prototypes.
+ *
+ * Revision 1.2  1995/06/15  12:30:06  quinn
+ * Added @ as hostname alias for INADDR ANY.
+ *
+ * Revision 1.1  1995/06/14  09:58:20  quinn
+ * Renamed yazlib to comstack.
+ *
+ * Revision 1.20  1995/05/16  08:51:16  quinn
+ * License, documentation, and memory fixes
+ *
+ * Revision 1.19  1995/04/10  10:24:08  quinn
+ * Some bug-fixes.
+ *
+ * Revision 1.18  1995/03/30  13:29:27  quinn
+ * Added REUSEADDR in tcpip_bind
+ *
+ * Revision 1.17  1995/03/27  08:36:10  quinn
+ * Some work on nonblocking operation in xmosi.c and rfct.c.
+ * Added protocol parameter to cs_create()
+ *
+ * Revision 1.16  1995/03/21  15:53:41  quinn
+ * Added rcvconnect
+ *
+ * Revision 1.15  1995/03/21  12:31:27  quinn
+ * Added check for EINPROGRESS on connect.
+ *
+ * Revision 1.14  1995/03/20  09:47:21  quinn
+ * Added server-side support to xmosi.c
+ * Fixed possible problems in rfct
+ * Other little mods
+ *
+ * Revision 1.13  1995/03/15  16:15:13  adam
+ * Removed p_write.
+ *
+ * Revision 1.12  1995/03/15  15:36:27  quinn
+ * Mods to support nonblocking I/O
+ *
+ * Revision 1.11  1995/03/15  08:37:57  quinn
+ * Now we're pretty much set for nonblocking I/O.
+ *
+ * Revision 1.10  1995/03/14  17:00:07  quinn
+ * Bug-fixes - added tracing info to tcpip.c
+ *
+ * Revision 1.9  1995/03/14  10:28:42  quinn
+ * Adding server-side support to tcpip.c and fixing bugs in nonblocking I/O
+ *
+ * Revision 1.8  1995/03/10  14:22:50  quinn
+ * Removed debug output.
+ *
+ * Revision 1.7  1995/03/10  11:44:59  quinn
+ * Fixes and debugging
+ *
+ * Revision 1.6  1995/03/07  10:26:55  quinn
+ * Initialized type field in the comstacks.
+ *
+ * Revision 1.5  1995/02/14  20:40:07  quinn
+ * Various stuff.
+ *
+ * Revision 1.4  1995/02/14  11:54:49  quinn
+ * Beginning to add full CCL.
+ *
+ * Revision 1.3  1995/02/10  18:58:10  quinn
+ * Fixed tcpip_get (formerly tcpip_read).
+ * Turned tst (cli) into a proper, event-driven thingy.
+ *
+ * Revision 1.2  1995/02/10  15:55:47  quinn
+ * Small things.
+ *
+ * Revision 1.1  1995/02/09  15:51:52  quinn
+ * Works better now.
+ *
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#ifndef WIN32
+#include <unistd.h>
+#endif
+#include <errno.h>
+#include <fcntl.h>
+
+#include <yaz/comstack.h>
+#include <yaz/tcpip.h>
+#include <yaz/log.h>
+
+/* Chas added the following, so we get the definition of completeBER */
+#include <yaz/odr.h>
+
+int tcpip_close(COMSTACK h);
+int tcpip_put(COMSTACK h, char *buf, int size);
+int tcpip_get(COMSTACK h, char **buf, int *bufsize);
+int tcpip_connect(COMSTACK h, void *address);
+int tcpip_more(COMSTACK h);
+int tcpip_rcvconnect(COMSTACK h);
+int tcpip_bind(COMSTACK h, void *address, int mode);
+int tcpip_listen(COMSTACK h, char *raddr, int *addrlen,
+		 int (*check_ip)(void *cd, const char *a, int len, int type),
+		 void *cd);
+
+COMSTACK tcpip_accept(COMSTACK h);
+char *tcpip_addrstr(COMSTACK h);
+void *tcpip_straddr(COMSTACK h, const char *str);
+
+#undef TRACE_TCPIP
+#ifdef TRACE_TCPIP
+#define TRC(x) x
+#else
+#define TRC(X)
+#endif
+
+typedef struct tcpip_state
+{
+    char *altbuf; /* alternate buffer for surplus data */
+    int altsize;  /* size as xmalloced */
+    int altlen;   /* length of data or 0 if none */
+
+    int written;  /* -1 if we aren't writing */
+    int towrite;  /* to verify against user input */
+    int (*complete)(const unsigned char *buf, int len); /* length/comple. */
+    struct sockaddr_in addr;  /* returned by cs_straddr */
+    char buf[128]; /* returned by cs_addrstr */
+} tcpip_state;
+
+#ifdef WIN32
+static int tcpip_init (void)
+{
+    static int initialized = 0;
+    if (!initialized)
+    {
+        WORD requested;
+        WSADATA wd;
+
+        requested = MAKEWORD(1, 1);
+        if (WSAStartup(requested, &wd))
+            return 0;
+        initialized = 1;
+    }
+    return 1;
+}
+#else
+
+static int proto_number = 0;
+
+static int tcpip_init (void)
+{
+    struct protoent *proto;
+    /* only call getprotobyname once, in case it allocates memory */
+    if (!(proto = getprotobyname("tcp")))
+	return 0;
+    proto_number = proto->p_proto;
+    return 1;
+}
+#endif
+/*
+ * This function is always called through the cs_create() macro.
+ * s >= 0: socket has already been established for us.
+ */
+COMSTACK tcpip_type(int s, int blocking, int protocol)
+{
+    COMSTACK p;
+    tcpip_state *state;
+    int new_socket;
+#ifdef WIN32
+    unsigned long tru = 1;
+#endif
+
+    if (!tcpip_init ())
+        return 0;
+    if (s < 0)
+    {
+#ifdef WIN32
+	if ((s = socket(AF_INET, SOCK_STREAM, 0)) < 0)
+	    return 0;
+#else
+	if ((s = socket(AF_INET, SOCK_STREAM, proto_number)) < 0)
+	    return 0;
+#endif
+	new_socket = 1;
+    }
+    else
+	new_socket = 0;
+    if (!(p = (struct comstack *)xmalloc(sizeof(struct comstack))))
+	return 0;
+    if (!(state = (struct tcpip_state *)(p->cprivate =
+                                         xmalloc(sizeof(tcpip_state)))))
+	return 0;
+
+#ifdef WIN32
+    if (!(p->blocking = blocking) && ioctlsocket(s, FIONBIO, &tru) < 0)
+#else
+    if (!(p->blocking = blocking) && fcntl(s, F_SETFL, O_NONBLOCK) < 0)
+#endif
+	return 0;
+
+    p->iofile = s;
+    p->type = tcpip_type;
+    p->protocol = (enum oid_proto) protocol;
+
+    p->f_connect = tcpip_connect;
+    p->f_rcvconnect = tcpip_rcvconnect;
+    p->f_get = tcpip_get;
+    p->f_put = tcpip_put;
+    p->f_close = tcpip_close;
+    p->f_more = tcpip_more;
+    p->f_bind = tcpip_bind;
+    p->f_listen = tcpip_listen;
+    p->f_accept = tcpip_accept;
+    p->f_addrstr = tcpip_addrstr;
+    p->f_straddr = tcpip_straddr;
+
+    p->state = new_socket ? CS_UNBND : CS_IDLE; /* state of line */
+    p->event = CS_NONE;
+    p->cerrno = 0;
+    p->stackerr = 0;
+
+    state->altbuf = 0;
+    state->altsize = state->altlen = 0;
+    state->towrite = state->written = -1;
+    if (protocol == PROTO_WAIS)
+	state->complete = completeWAIS;
+    else
+	state->complete = completeBER;
+
+    p->timeout = COMSTACK_DEFAULT_TIMEOUT;
+    TRC(fprintf(stderr, "Created new TCPIP comstack\n"));
+
+    return p;
+}
+
+int tcpip_strtoaddr_ex(const char *str, struct sockaddr_in *add)
+{
+    struct hostent *hp;
+    char *p, buf[512];
+    short int port = 210;
+    unsigned tmpadd;
+
+    if (!tcpip_init ())
+        return 0;
+    TRC(fprintf(stderr, "tcpip_strtoaddress: %s\n", str ? str : "NULL"));
+    add->sin_family = AF_INET;
+    strncpy(buf, str, 511);
+    buf[511] = 0;
+    if ((p = strchr(buf, '/')))
+        *p = 0;
+    if ((p = strchr(buf, ':')))
+    {
+        *p = 0;
+        port = atoi(p + 1);
+    }
+    add->sin_port = htons(port);
+    if (!strcmp("@", buf))
+        add->sin_addr.s_addr = INADDR_ANY;
+    else if ((hp = gethostbyname(buf)))
+        memcpy(&add->sin_addr.s_addr, *hp->h_addr_list,
+	       sizeof(struct in_addr));
+    else if ((tmpadd = (unsigned) inet_addr(buf)) != 0)
+        memcpy(&add->sin_addr.s_addr, &tmpadd, sizeof(struct in_addr));
+    else
+        return 0;
+    return 1;
+}
+
+void *tcpip_straddr(COMSTACK h, const char *str)
+{
+    tcpip_state *sp = (tcpip_state *)h->cprivate;
+
+    if (!tcpip_strtoaddr_ex (str, &sp->addr))
+	return 0;
+    return &sp->addr;
+}
+
+struct sockaddr_in *tcpip_strtoaddr(const char *str)
+{
+    static struct sockaddr_in add;
+    
+    if (!tcpip_strtoaddr_ex (str, &add))
+	return 0;
+    return &add;
+}
+
+int tcpip_more(COMSTACK h)
+{
+    tcpip_state *sp = (tcpip_state *)h->cprivate;
+    
+    return sp->altlen && (*sp->complete)((unsigned char *) sp->altbuf,
+	sp->altlen);
+}
+
+/*
+ * connect(2) will block (sometimes) - nothing we can do short of doing
+ * weird things like spawning subprocesses or threading or some weird junk
+ * like that.
+ */
+int tcpip_connect(COMSTACK h, void *address)
+{
+    struct sockaddr_in *add = (struct sockaddr_in *)address;
+
+    TRC(fprintf(stderr, "tcpip_connect\n"));
+    if (connect(h->iofile, (struct sockaddr *) add, sizeof(*add)) < 0)
+    {
+#ifdef WIN32
+        if (WSAGetLastError() == WSAEWOULDBLOCK)
+#else
+        if (errno == EINPROGRESS)
+#endif
+            return 1;
+        return -1;
+    }
+    h->state = CS_DATAXFER;
+    return 0;
+}
+
+/*
+ * nop
+ */
+int tcpip_rcvconnect(COMSTACK h)
+{
+    TRC(fprintf(stderr, "tcpip_rcvconnect\n"));
+    return 0;
+}
+
+int tcpip_bind(COMSTACK h, void *address, int mode)
+{
+    struct sockaddr *addr = (struct sockaddr *)address;
+#ifdef WIN32
+    BOOL one = 1;
+#else
+    unsigned long one = 1;
+#endif
+
+    TRC(fprintf(stderr, "tcpip_bind\n"));
+    if (setsockopt(h->iofile, SOL_SOCKET, SO_REUSEADDR, (char*) 
+	&one, sizeof(one)) < 0)
+    {
+        h->cerrno = CSYSERR;
+        return -1;
+    }
+    if (bind(h->iofile, addr, sizeof(struct sockaddr_in)) < 0)
+    {
+        h->cerrno = CSYSERR;
+        return -1;
+    }
+    if (mode == CS_SERVER && listen(h->iofile, 3) < 0)
+    {
+        h->cerrno = CSYSERR;
+        return -1;
+    }
+    h->state = CS_IDLE;
+    return 0;
+}
+
+int tcpip_listen(COMSTACK h, char *raddr, int *addrlen,
+		 int (*check_ip)(void *cd, const char *a, int len, int t),
+		 void *cd)
+{
+    struct sockaddr_in addr;
+    int len = sizeof(addr);
+
+    TRC(fprintf(stderr, "tcpip_listen pid=%d\n", getpid()));
+    if (h->state != CS_IDLE)
+    {
+        h->cerrno = CSOUTSTATE;
+        return -1;
+    }
+    if ((h->newfd = accept(h->iofile, (struct sockaddr*)&addr, &len)) < 0)
+    {
+#ifdef WIN32
+        if (WSAGetLastError() == WSAEWOULDBLOCK)
+#else
+        if (errno == EWOULDBLOCK)
+#endif
+
+            h->cerrno = CSNODATA;
+        else
+            h->cerrno = CSYSERR;
+        return -1;
+    }
+    if (addrlen && (size_t) (*addrlen) >= sizeof(struct sockaddr_in))
+        memcpy(raddr, &addr, *addrlen = sizeof(struct sockaddr_in));
+    else if (addrlen)
+        *addrlen = 0;
+    if (check_ip && (*check_ip)(cd, (const char *) &addr,
+        sizeof(addr), AF_INET))
+    {
+	h->cerrno = CSDENY;
+#ifdef WIN32
+        closesocket(h->newfd);
+#else
+        close(h->newfd);
+#endif
+	return -1;
+    }
+    h->state = CS_INCON;
+    return 0;
+}
+
+COMSTACK tcpip_accept(COMSTACK h)
+{
+    COMSTACK cnew;
+    tcpip_state *state, *st = (tcpip_state *)h->cprivate;
+#ifdef WIN32
+    unsigned long tru = 1;
+#endif
+
+    TRC(fprintf(stderr, "tcpip_accept\n"));
+    if (h->state != CS_INCON)
+    {
+        h->cerrno = CSOUTSTATE;
+        return 0;
+    }
+    if (!(cnew = (COMSTACK)xmalloc(sizeof(*cnew))))
+    {
+        h->cerrno = CSYSERR;
+        return 0;
+    }
+    memcpy(cnew, h, sizeof(*h));
+    cnew->iofile = h->newfd;
+    if (!(state = (tcpip_state *)
+	  (cnew->cprivate = xmalloc(sizeof(tcpip_state)))))
+    {
+        h->cerrno = CSYSERR;
+        return 0;
+    }
+#ifdef WIN32
+    if (!cnew->blocking && ioctlsocket(cnew->iofile, FIONBIO, &tru) < 0)
+#else
+    if (!cnew->blocking && fcntl(cnew->iofile, F_SETFL, O_NONBLOCK) < 0)
+#endif
+        return 0;
+    state->altbuf = 0;
+    state->altsize = state->altlen = 0;
+    state->towrite = state->written = -1;
+    state->complete = st->complete;
+    cnew->state = CS_DATAXFER;
+    h->state = CS_IDLE;
+    return cnew;
+}
+
+#define CS_TCPIP_BUFCHUNK 4096
+
+/*
+ * Return: -1 error, >1 good, len of buffer, ==1 incomplete buffer,
+ * 0=connection closed.
+ */
+int tcpip_get(COMSTACK h, char **buf, int *bufsize)
+{
+    tcpip_state *sp = (tcpip_state *)h->cprivate;
+    char *tmpc;
+    int tmpi, berlen, rest, req, tomove;
+    int hasread = 0, res;
+
+    TRC(fprintf(stderr, "tcpip_get: bufsize=%d\n", *bufsize));
+    if (sp->altlen) /* switch buffers */
+    {
+        TRC(fprintf(stderr, "  %d bytes in altbuf (0x%x)\n", sp->altlen,
+            (unsigned) sp->altbuf));
+        tmpc = *buf;
+        tmpi = *bufsize;
+        *buf = sp->altbuf;
+        *bufsize = sp->altsize;
+        hasread = sp->altlen;
+        sp->altlen = 0;
+        sp->altbuf = tmpc;
+        sp->altsize = tmpi;
+    }
+    while (!(berlen = (*sp->complete)((unsigned char *)*buf, hasread)))
+    {
+        if (!*bufsize)
+        {
+            if (!(*buf = (char *)xmalloc(*bufsize = CS_TCPIP_BUFCHUNK)))
+                return -1;
+        }
+        else if (*bufsize - hasread < CS_TCPIP_BUFCHUNK)
+            if (!(*buf =(char *)xrealloc(*buf, *bufsize *= 2)))
+                return -1;
+        if ((res = recv(h->iofile, *buf + hasread, CS_TCPIP_BUFCHUNK, 0)) < 0)
+	{
+#ifdef WIN32
+            if (WSAGetLastError() == WSAEWOULDBLOCK)
+		break;
+	    else
+		return -1;
+#else
+	    if (errno == EWOULDBLOCK
+#ifdef EINPROGRESS
+		|| errno == EINPROGRESS
+#endif
+		)
+		break;
+            else if (errno == 0)
+		continue;
+	    else
+                return -1;
+#endif
+	}
+        if (!res)
+            return 0;
+        hasread += res;
+        TRC(fprintf(stderr, "  res=%d, hasread=%d\n", res, hasread));
+    }
+    TRC(fprintf(stderr, "  Out of read loop with hasread=%d, berlen=%d\n",
+        hasread, berlen));
+    /* move surplus buffer (or everything if we didn't get a BER rec.) */
+    if (hasread > berlen)
+    {
+        tomove = req = hasread - berlen;
+        rest = tomove % CS_TCPIP_BUFCHUNK;
+        if (rest)
+            req += CS_TCPIP_BUFCHUNK - rest;
+        if (!sp->altbuf)
+        {
+            if (!(sp->altbuf = (char *)xmalloc(sp->altsize = req)))
+                return -1;
+        } else if (sp->altsize < req)
+            if (!(sp->altbuf =(char *)xrealloc(sp->altbuf, sp->altsize = req)))
+                return -1;
+        TRC(fprintf(stderr, "  Moving %d bytes to altbuf(0x%x)\n", tomove,
+            (unsigned) sp->altbuf));
+        memcpy(sp->altbuf, *buf + berlen, sp->altlen = tomove);
+    }
+    if (berlen < CS_TCPIP_BUFCHUNK - 1)
+        *(*buf + berlen) = '\0';
+    return berlen ? berlen : 1;
+}
+
+/*
+ * Returns 1, 0 or -1
+ * In nonblocking mode, you must call again with same buffer while
+ * return value is 1.
+ */
+int tcpip_put(COMSTACK h, char *buf, int size)
+{
+    int res;
+    struct tcpip_state *state = (struct tcpip_state *)h->cprivate;
+
+    TRC(fprintf(stderr, "tcpip_put: size=%d\n", size));
+    if (state->towrite < 0)
+    {
+        state->towrite = size;
+        state->written = 0;
+    }
+    else if (state->towrite != size)
+    {
+        h->cerrno = CSWRONGBUF;
+        return -1;
+    }
+    while (state->towrite > state->written)
+    {
+        if ((res = send(h->iofile, buf + state->written, size -
+            state->written, 0)) < 0)
+        {
+#ifdef WIN32
+            if (WSAGetLastError() == WSAEWOULDBLOCK)
+#else
+            if (errno == EAGAIN)
+#endif
+            {
+                TRC(fprintf(stderr, "  Flow control stop\n"));
+                return 1;
+            }
+            h->cerrno = CSYSERR;
+            return -1;
+        }
+        state->written += res;
+        TRC(fprintf(stderr, "  Wrote %d, written=%d, nbytes=%d\n",
+            res, state->written, size));
+    }
+    state->towrite = state->written = -1;
+    TRC(fprintf(stderr, "  Ok\n"));
+    return 0;
+}
+
+int tcpip_close(COMSTACK h)
+{
+    tcpip_state *sp = (struct tcpip_state *)h->cprivate;
+
+    TRC(fprintf(stderr, "tcpip_close\n"));
+    if (h->iofile != -1)
+#ifdef WIN32
+        closesocket(h->iofile);
+#else
+        close(h->iofile);
+#endif
+    if (sp->altbuf)
+        xfree(sp->altbuf);
+    xfree(sp);
+    xfree(h);
+    return 0;
+}
+
+char *tcpip_addrstr(COMSTACK h)
+{
+    struct sockaddr_in addr;
+    tcpip_state *sp = (struct tcpip_state *)h->cprivate;
+    char *r, *buf = sp->buf;
+    size_t len;
+    struct hostent *host;
+    
+    len = sizeof(addr);
+    if (getpeername(h->iofile, (struct sockaddr*) &addr, &len) < 0)
+    {
+	h->cerrno = CSYSERR;
+	return 0;
+    }
+    if ((host = gethostbyaddr((char*)&addr.sin_addr, sizeof(addr.sin_addr),
+			      AF_INET)))
+	r = (char*) host->h_name;
+    else
+	r = inet_ntoa(addr.sin_addr);
+    sprintf(buf, "tcp:%s", r);
+    return buf;
+}
Index: /main/tags/2.25/gsdl/packages/yaz/comstack/waislen.c
===================================================================
--- /main/tags/2.25/gsdl/packages/yaz/comstack/waislen.c	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/yaz/comstack/waislen.c	(revision 21064)
@@ -0,0 +1,49 @@
+/*
+ * Copyright (c) 1995-1999, Index Data.
+ * See the file LICENSE for details.
+ * Sebastian Hammer, Adam Dickmeiss
+ *
+ * $Log$
+ * Revision 1.1  2000/08/03 03:10:06  johnmcp
+ * Added the YAZ toolkit source to the packages directory (for z39.50 stuff)
+ *
+ * Revision 1.5  1999/11/30 13:47:11  adam
+ * Improved installation. Moved header files to include/yaz.
+ *
+ * Revision 1.4  1999/01/08 11:23:15  adam
+ * Added const modifier to some of the BER/ODR encoding routines.
+ *
+ * Revision 1.3  1996/02/29 14:23:13  adam
+ * Bug fix.
+ *
+ * Revision 1.2  1996/02/26  18:34:44  adam
+ * Bug fix.
+ *
+ * Revision 1.1  1996/02/20  13:02:58  quinn
+ * Wais length.
+ *
+ *
+ */
+
+#include <stdio.h>
+#include <yaz/comstack.h>
+#include <yaz/tcpip.h>
+/*
+ * Return length of WAIS package or 0
+ */
+int completeWAIS(const unsigned char *buf, int len)
+{
+    int i, lval = 0;
+
+    if (len < 25)
+	return 0;
+    if (*buf != '0')
+	return 0;
+    /* calculate length */
+    for (i = 0; i < 10; i++)
+	lval = lval * 10 + (buf[i] - '0');
+    lval += 25;
+    if (len >= lval)
+	return lval;
+    return 0;
+}
Index: /main/tags/2.25/gsdl/packages/yaz/config.status
===================================================================
--- /main/tags/2.25/gsdl/packages/yaz/config.status	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/yaz/config.status	(revision 21064)
@@ -0,0 +1,176 @@
+#! /bin/sh
+# Generated automatically by configure.
+# Run this file to recreate the current configuration.
+# This directory was configured as follows,
+# on host towai:
+#
+# ./configure 
+#
+# Compiler output produced by configure, useful for debugging
+# configure, is in ./config.log if it exists.
+
+ac_cs_usage="Usage: ./config.status [--recheck] [--version] [--help]"
+for ac_option
+do
+  case "$ac_option" in
+  -recheck | --recheck | --rechec | --reche | --rech | --rec | --re | --r)
+    echo "running ${CONFIG_SHELL-/bin/sh} ./configure  --no-create --no-recursion"
+    exec ${CONFIG_SHELL-/bin/sh} ./configure  --no-create --no-recursion ;;
+  -version | --version | --versio | --versi | --vers | --ver | --ve | --v)
+    echo "./config.status generated by autoconf version 2.13"
+    exit 0 ;;
+  -help | --help | --hel | --he | --h)
+    echo "$ac_cs_usage"; exit 0 ;;
+  *) echo "$ac_cs_usage"; exit 1 ;;
+  esac
+done
+
+ac_given_srcdir=.
+ac_given_INSTALL="/usr/bin/ginstall -c"
+
+trap 'rm -fr Makefile util/Makefile odr/Makefile z39.50/Makefile asn/Makefile ill/Makefile zutil/Makefile comstack/Makefile ccl/Makefile tab/Makefile retrieval/Makefile server/Makefile include/Makefile include/yaz/Makefile lib/Makefile client/Makefile ztest/Makefile doc/Makefile conftest*; exit 1' 1 2 15
+
+# Protect against being on the right side of a sed subst in config.status.
+sed 's/%@/@@/; s/@%/@@/; s/%g$/@g/; /@g$/s/[\\&%]/\\&/g;
+ s/@@/%@/; s/@@/@%/; s/@g$/%g/' > conftest.subs <<\CEOF
+/^[ 	]*VPATH[ 	]*=[^:]*$/d
+
+s%@SHELL@%/bin/sh%g
+s%@CFLAGS@%-Wall -O2%g
+s%@CPPFLAGS@%%g
+s%@CXXFLAGS@%%g
+s%@FFLAGS@%%g
+s%@DEFS@% -DPACKAGE=\"yaz\" -DVERSION=\"1.6\" -DHAVE_READLINE_READLINE_H=1 -DHAVE_READLINE_HISTORY_H=1 -DSTDC_HEADERS=1 %g
+s%@LDFLAGS@%%g
+s%@LIBS@% -lreadline -lhistory%g
+s%@exec_prefix@%${prefix}%g
+s%@prefix@%/usr/local%g
+s%@program_transform_name@%s,x,x,%g
+s%@bindir@%${exec_prefix}/bin%g
+s%@sbindir@%${exec_prefix}/sbin%g
+s%@libexecdir@%${exec_prefix}/libexec%g
+s%@datadir@%${prefix}/share%g
+s%@sysconfdir@%${prefix}/etc%g
+s%@sharedstatedir@%${prefix}/com%g
+s%@localstatedir@%${prefix}/var%g
+s%@libdir@%${exec_prefix}/lib%g
+s%@includedir@%${prefix}/include%g
+s%@oldincludedir@%/usr/include%g
+s%@infodir@%${prefix}/info%g
+s%@mandir@%${prefix}/man%g
+s%@INSTALL_PROGRAM@%${INSTALL}%g
+s%@INSTALL_SCRIPT@%${INSTALL_PROGRAM}%g
+s%@INSTALL_DATA@%${INSTALL} -m 644%g
+s%@PACKAGE@%yaz%g
+s%@VERSION@%1.6%g
+s%@ACLOCAL@%aclocal%g
+s%@AUTOCONF@%autoconf%g
+s%@AUTOMAKE@%automake%g
+s%@AUTOHEADER@%autoheader%g
+s%@MAKEINFO@%makeinfo%g
+s%@SET_MAKE@%%g
+s%@CC@%gcc%g
+s%@CPP@%gcc -E%g
+s%@RANLIB@%ranlib%g
+s%@have_sgml2txt@%no%g
+s%@have_sgml2latex@%no%g
+s%@have_sgml2html@%no%g
+s%@ASNMODULE@%z39.50%g
+s%@ILLMODULE@%ill%g
+s%@ILLLIB@%../ill/libill.a%g
+s%@SUBDIRS_VAR@%util odr z39.50 ill zutil comstack ccl tab retrieval server include lib client ztest %g
+
+CEOF
+
+# Split the substitutions into bite-sized pieces for seds with
+# small command number limits, like on Digital OSF/1 and HP-UX.
+ac_max_sed_cmds=90 # Maximum number of lines to put in a sed script.
+ac_file=1 # Number of current file.
+ac_beg=1 # First line for current file.
+ac_end=$ac_max_sed_cmds # Line after last line for current file.
+ac_more_lines=:
+ac_sed_cmds=""
+while $ac_more_lines; do
+  if test $ac_beg -gt 1; then
+    sed "1,${ac_beg}d; ${ac_end}q" conftest.subs > conftest.s$ac_file
+  else
+    sed "${ac_end}q" conftest.subs > conftest.s$ac_file
+  fi
+  if test ! -s conftest.s$ac_file; then
+    ac_more_lines=false
+    rm -f conftest.s$ac_file
+  else
+    if test -z "$ac_sed_cmds"; then
+      ac_sed_cmds="sed -f conftest.s$ac_file"
+    else
+      ac_sed_cmds="$ac_sed_cmds | sed -f conftest.s$ac_file"
+    fi
+    ac_file=`expr $ac_file + 1`
+    ac_beg=$ac_end
+    ac_end=`expr $ac_end + $ac_max_sed_cmds`
+  fi
+done
+if test -z "$ac_sed_cmds"; then
+  ac_sed_cmds=cat
+fi
+
+CONFIG_FILES=${CONFIG_FILES-"Makefile util/Makefile odr/Makefile z39.50/Makefile asn/Makefile ill/Makefile zutil/Makefile comstack/Makefile ccl/Makefile tab/Makefile retrieval/Makefile server/Makefile include/Makefile include/yaz/Makefile lib/Makefile client/Makefile ztest/Makefile doc/Makefile"}
+for ac_file in .. $CONFIG_FILES; do if test "x$ac_file" != x..; then
+  # Support "outfile[:infile[:infile...]]", defaulting infile="outfile.in".
+  case "$ac_file" in
+  *:*) ac_file_in=`echo "$ac_file"|sed 's%[^:]*:%%'`
+       ac_file=`echo "$ac_file"|sed 's%:.*%%'` ;;
+  *) ac_file_in="${ac_file}.in" ;;
+  esac
+
+  # Adjust a relative srcdir, top_srcdir, and INSTALL for subdirectories.
+
+  # Remove last slash and all that follows it.  Not all systems have dirname.
+  ac_dir=`echo $ac_file|sed 's%/[^/][^/]*$%%'`
+  if test "$ac_dir" != "$ac_file" && test "$ac_dir" != .; then
+    # The file is in a subdirectory.
+    test ! -d "$ac_dir" && mkdir "$ac_dir"
+    ac_dir_suffix="/`echo $ac_dir|sed 's%^\./%%'`"
+    # A "../" for each directory in $ac_dir_suffix.
+    ac_dots=`echo $ac_dir_suffix|sed 's%/[^/]*%../%g'`
+  else
+    ac_dir_suffix= ac_dots=
+  fi
+
+  case "$ac_given_srcdir" in
+  .)  srcdir=.
+      if test -z "$ac_dots"; then top_srcdir=.
+      else top_srcdir=`echo $ac_dots|sed 's%/$%%'`; fi ;;
+  /*) srcdir="$ac_given_srcdir$ac_dir_suffix"; top_srcdir="$ac_given_srcdir" ;;
+  *) # Relative path.
+    srcdir="$ac_dots$ac_given_srcdir$ac_dir_suffix"
+    top_srcdir="$ac_dots$ac_given_srcdir" ;;
+  esac
+
+  case "$ac_given_INSTALL" in
+  [/$]*) INSTALL="$ac_given_INSTALL" ;;
+  *) INSTALL="$ac_dots$ac_given_INSTALL" ;;
+  esac
+
+  echo creating "$ac_file"
+  rm -f "$ac_file"
+  configure_input="Generated automatically from `echo $ac_file_in|sed 's%.*/%%'` by configure."
+  case "$ac_file" in
+  *Makefile*) ac_comsub="1i\\
+# $configure_input" ;;
+  *) ac_comsub= ;;
+  esac
+
+  ac_file_inputs=`echo $ac_file_in|sed -e "s%^%$ac_given_srcdir/%" -e "s%:% $ac_given_srcdir/%g"`
+  sed -e "$ac_comsub
+s%@configure_input@%$configure_input%g
+s%@srcdir@%$srcdir%g
+s%@top_srcdir@%$top_srcdir%g
+s%@INSTALL@%$INSTALL%g
+" $ac_file_inputs | (eval "$ac_sed_cmds") > $ac_file
+fi; done
+rm -f conftest.s*
+
+
+
+exit 0
Index: /main/tags/2.25/gsdl/packages/yaz/configure
===================================================================
--- /main/tags/2.25/gsdl/packages/yaz/configure	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/yaz/configure	(revision 21064)
@@ -0,0 +1,2276 @@
+#! /bin/sh
+
+# Guess values for system-dependent variables and create Makefiles.
+# Generated automatically using autoconf version 2.13 
+# Copyright (C) 1992, 93, 94, 95, 96 Free Software Foundation, Inc.
+#
+# This configure script is free software; the Free Software Foundation
+# gives unlimited permission to copy, distribute and modify it.
+
+# Defaults:
+ac_help=
+ac_default_prefix=/usr/local
+# Any additions from configure.in:
+ac_help="$ac_help
+  --disable-comp          use old encoders, i.e. disable the YAZ ASN.1 Compiler"
+ac_help="$ac_help
+  --enable-tcpd           enable TCP wrapper for server if available"
+ac_help="$ac_help
+  --enable-threads        enable threads if available"
+
+# Initialize some variables set by options.
+# The variables have the same names as the options, with
+# dashes changed to underlines.
+build=NONE
+cache_file=./config.cache
+exec_prefix=NONE
+host=NONE
+no_create=
+nonopt=NONE
+no_recursion=
+prefix=NONE
+program_prefix=NONE
+program_suffix=NONE
+program_transform_name=s,x,x,
+silent=
+site=
+srcdir=
+target=NONE
+verbose=
+x_includes=NONE
+x_libraries=NONE
+bindir='${exec_prefix}/bin'
+sbindir='${exec_prefix}/sbin'
+libexecdir='${exec_prefix}/libexec'
+datadir='${prefix}/share'
+sysconfdir='${prefix}/etc'
+sharedstatedir='${prefix}/com'
+localstatedir='${prefix}/var'
+libdir='${exec_prefix}/lib'
+includedir='${prefix}/include'
+oldincludedir='/usr/include'
+infodir='${prefix}/info'
+mandir='${prefix}/man'
+
+# Initialize some other variables.
+subdirs=
+MFLAGS= MAKEFLAGS=
+SHELL=${CONFIG_SHELL-/bin/sh}
+# Maximum number of lines to put in a shell here document.
+ac_max_here_lines=12
+
+ac_prev=
+for ac_option
+do
+
+  # If the previous option needs an argument, assign it.
+  if test -n "$ac_prev"; then
+    eval "$ac_prev=\$ac_option"
+    ac_prev=
+    continue
+  fi
+
+  case "$ac_option" in
+  -*=*) ac_optarg=`echo "$ac_option" | sed 's/[-_a-zA-Z0-9]*=//'` ;;
+  *) ac_optarg= ;;
+  esac
+
+  # Accept the important Cygnus configure options, so we can diagnose typos.
+
+  case "$ac_option" in
+
+  -bindir | --bindir | --bindi | --bind | --bin | --bi)
+    ac_prev=bindir ;;
+  -bindir=* | --bindir=* | --bindi=* | --bind=* | --bin=* | --bi=*)
+    bindir="$ac_optarg" ;;
+
+  -build | --build | --buil | --bui | --bu)
+    ac_prev=build ;;
+  -build=* | --build=* | --buil=* | --bui=* | --bu=*)
+    build="$ac_optarg" ;;
+
+  -cache-file | --cache-file | --cache-fil | --cache-fi \
+  | --cache-f | --cache- | --cache | --cach | --cac | --ca | --c)
+    ac_prev=cache_file ;;
+  -cache-file=* | --cache-file=* | --cache-fil=* | --cache-fi=* \
+  | --cache-f=* | --cache-=* | --cache=* | --cach=* | --cac=* | --ca=* | --c=*)
+    cache_file="$ac_optarg" ;;
+
+  -datadir | --datadir | --datadi | --datad | --data | --dat | --da)
+    ac_prev=datadir ;;
+  -datadir=* | --datadir=* | --datadi=* | --datad=* | --data=* | --dat=* \
+  | --da=*)
+    datadir="$ac_optarg" ;;
+
+  -disable-* | --disable-*)
+    ac_feature=`echo $ac_option|sed -e 's/-*disable-//'`
+    # Reject names that are not valid shell variable names.
+    if test -n "`echo $ac_feature| sed 's/[-a-zA-Z0-9_]//g'`"; then
+      { echo "configure: error: $ac_feature: invalid feature name" 1>&2; exit 1; }
+    fi
+    ac_feature=`echo $ac_feature| sed 's/-/_/g'`
+    eval "enable_${ac_feature}=no" ;;
+
+  -enable-* | --enable-*)
+    ac_feature=`echo $ac_option|sed -e 's/-*enable-//' -e 's/=.*//'`
+    # Reject names that are not valid shell variable names.
+    if test -n "`echo $ac_feature| sed 's/[-_a-zA-Z0-9]//g'`"; then
+      { echo "configure: error: $ac_feature: invalid feature name" 1>&2; exit 1; }
+    fi
+    ac_feature=`echo $ac_feature| sed 's/-/_/g'`
+    case "$ac_option" in
+      *=*) ;;
+      *) ac_optarg=yes ;;
+    esac
+    eval "enable_${ac_feature}='$ac_optarg'" ;;
+
+  -exec-prefix | --exec_prefix | --exec-prefix | --exec-prefi \
+  | --exec-pref | --exec-pre | --exec-pr | --exec-p | --exec- \
+  | --exec | --exe | --ex)
+    ac_prev=exec_prefix ;;
+  -exec-prefix=* | --exec_prefix=* | --exec-prefix=* | --exec-prefi=* \
+  | --exec-pref=* | --exec-pre=* | --exec-pr=* | --exec-p=* | --exec-=* \
+  | --exec=* | --exe=* | --ex=*)
+    exec_prefix="$ac_optarg" ;;
+
+  -gas | --gas | --ga | --g)
+    # Obsolete; use --with-gas.
+    with_gas=yes ;;
+
+  -help | --help | --hel | --he)
+    # Omit some internal or obsolete options to make the list less imposing.
+    # This message is too long to be a string in the A/UX 3.1 sh.
+    cat << EOF
+Usage: configure [options] [host]
+Options: [defaults in brackets after descriptions]
+Configuration:
+  --cache-file=FILE       cache test results in FILE
+  --help                  print this message
+  --no-create             do not create output files
+  --quiet, --silent       do not print \`checking...' messages
+  --version               print the version of autoconf that created configure
+Directory and file names:
+  --prefix=PREFIX         install architecture-independent files in PREFIX
+                          [$ac_default_prefix]
+  --exec-prefix=EPREFIX   install architecture-dependent files in EPREFIX
+                          [same as prefix]
+  --bindir=DIR            user executables in DIR [EPREFIX/bin]
+  --sbindir=DIR           system admin executables in DIR [EPREFIX/sbin]
+  --libexecdir=DIR        program executables in DIR [EPREFIX/libexec]
+  --datadir=DIR           read-only architecture-independent data in DIR
+                          [PREFIX/share]
+  --sysconfdir=DIR        read-only single-machine data in DIR [PREFIX/etc]
+  --sharedstatedir=DIR    modifiable architecture-independent data in DIR
+                          [PREFIX/com]
+  --localstatedir=DIR     modifiable single-machine data in DIR [PREFIX/var]
+  --libdir=DIR            object code libraries in DIR [EPREFIX/lib]
+  --includedir=DIR        C header files in DIR [PREFIX/include]
+  --oldincludedir=DIR     C header files for non-gcc in DIR [/usr/include]
+  --infodir=DIR           info documentation in DIR [PREFIX/info]
+  --mandir=DIR            man documentation in DIR [PREFIX/man]
+  --srcdir=DIR            find the sources in DIR [configure dir or ..]
+  --program-prefix=PREFIX prepend PREFIX to installed program names
+  --program-suffix=SUFFIX append SUFFIX to installed program names
+  --program-transform-name=PROGRAM
+                          run sed PROGRAM on installed program names
+EOF
+    cat << EOF
+Host type:
+  --build=BUILD           configure for building on BUILD [BUILD=HOST]
+  --host=HOST             configure for HOST [guessed]
+  --target=TARGET         configure for TARGET [TARGET=HOST]
+Features and packages:
+  --disable-FEATURE       do not include FEATURE (same as --enable-FEATURE=no)
+  --enable-FEATURE[=ARG]  include FEATURE [ARG=yes]
+  --with-PACKAGE[=ARG]    use PACKAGE [ARG=yes]
+  --without-PACKAGE       do not use PACKAGE (same as --with-PACKAGE=no)
+  --x-includes=DIR        X include files are in DIR
+  --x-libraries=DIR       X library files are in DIR
+EOF
+    if test -n "$ac_help"; then
+      echo "--enable and --with options recognized:$ac_help"
+    fi
+    exit 0 ;;
+
+  -host | --host | --hos | --ho)
+    ac_prev=host ;;
+  -host=* | --host=* | --hos=* | --ho=*)
+    host="$ac_optarg" ;;
+
+  -includedir | --includedir | --includedi | --included | --include \
+  | --includ | --inclu | --incl | --inc)
+    ac_prev=includedir ;;
+  -includedir=* | --includedir=* | --includedi=* | --included=* | --include=* \
+  | --includ=* | --inclu=* | --incl=* | --inc=*)
+    includedir="$ac_optarg" ;;
+
+  -infodir | --infodir | --infodi | --infod | --info | --inf)
+    ac_prev=infodir ;;
+  -infodir=* | --infodir=* | --infodi=* | --infod=* | --info=* | --inf=*)
+    infodir="$ac_optarg" ;;
+
+  -libdir | --libdir | --libdi | --libd)
+    ac_prev=libdir ;;
+  -libdir=* | --libdir=* | --libdi=* | --libd=*)
+    libdir="$ac_optarg" ;;
+
+  -libexecdir | --libexecdir | --libexecdi | --libexecd | --libexec \
+  | --libexe | --libex | --libe)
+    ac_prev=libexecdir ;;
+  -libexecdir=* | --libexecdir=* | --libexecdi=* | --libexecd=* | --libexec=* \
+  | --libexe=* | --libex=* | --libe=*)
+    libexecdir="$ac_optarg" ;;
+
+  -localstatedir | --localstatedir | --localstatedi | --localstated \
+  | --localstate | --localstat | --localsta | --localst \
+  | --locals | --local | --loca | --loc | --lo)
+    ac_prev=localstatedir ;;
+  -localstatedir=* | --localstatedir=* | --localstatedi=* | --localstated=* \
+  | --localstate=* | --localstat=* | --localsta=* | --localst=* \
+  | --locals=* | --local=* | --loca=* | --loc=* | --lo=*)
+    localstatedir="$ac_optarg" ;;
+
+  -mandir | --mandir | --mandi | --mand | --man | --ma | --m)
+    ac_prev=mandir ;;
+  -mandir=* | --mandir=* | --mandi=* | --mand=* | --man=* | --ma=* | --m=*)
+    mandir="$ac_optarg" ;;
+
+  -nfp | --nfp | --nf)
+    # Obsolete; use --without-fp.
+    with_fp=no ;;
+
+  -no-create | --no-create | --no-creat | --no-crea | --no-cre \
+  | --no-cr | --no-c)
+    no_create=yes ;;
+
+  -no-recursion | --no-recursion | --no-recursio | --no-recursi \
+  | --no-recurs | --no-recur | --no-recu | --no-rec | --no-re | --no-r)
+    no_recursion=yes ;;
+
+  -oldincludedir | --oldincludedir | --oldincludedi | --oldincluded \
+  | --oldinclude | --oldinclud | --oldinclu | --oldincl | --oldinc \
+  | --oldin | --oldi | --old | --ol | --o)
+    ac_prev=oldincludedir ;;
+  -oldincludedir=* | --oldincludedir=* | --oldincludedi=* | --oldincluded=* \
+  | --oldinclude=* | --oldinclud=* | --oldinclu=* | --oldincl=* | --oldinc=* \
+  | --oldin=* | --oldi=* | --old=* | --ol=* | --o=*)
+    oldincludedir="$ac_optarg" ;;
+
+  -prefix | --prefix | --prefi | --pref | --pre | --pr | --p)
+    ac_prev=prefix ;;
+  -prefix=* | --prefix=* | --prefi=* | --pref=* | --pre=* | --pr=* | --p=*)
+    prefix="$ac_optarg" ;;
+
+  -program-prefix | --program-prefix | --program-prefi | --program-pref \
+  | --program-pre | --program-pr | --program-p)
+    ac_prev=program_prefix ;;
+  -program-prefix=* | --program-prefix=* | --program-prefi=* \
+  | --program-pref=* | --program-pre=* | --program-pr=* | --program-p=*)
+    program_prefix="$ac_optarg" ;;
+
+  -program-suffix | --program-suffix | --program-suffi | --program-suff \
+  | --program-suf | --program-su | --program-s)
+    ac_prev=program_suffix ;;
+  -program-suffix=* | --program-suffix=* | --program-suffi=* \
+  | --program-suff=* | --program-suf=* | --program-su=* | --program-s=*)
+    program_suffix="$ac_optarg" ;;
+
+  -program-transform-name | --program-transform-name \
+  | --program-transform-nam | --program-transform-na \
+  | --program-transform-n | --program-transform- \
+  | --program-transform | --program-transfor \
+  | --program-transfo | --program-transf \
+  | --program-trans | --program-tran \
+  | --progr-tra | --program-tr | --program-t)
+    ac_prev=program_transform_name ;;
+  -program-transform-name=* | --program-transform-name=* \
+  | --program-transform-nam=* | --program-transform-na=* \
+  | --program-transform-n=* | --program-transform-=* \
+  | --program-transform=* | --program-transfor=* \
+  | --program-transfo=* | --program-transf=* \
+  | --program-trans=* | --program-tran=* \
+  | --progr-tra=* | --program-tr=* | --program-t=*)
+    program_transform_name="$ac_optarg" ;;
+
+  -q | -quiet | --quiet | --quie | --qui | --qu | --q \
+  | -silent | --silent | --silen | --sile | --sil)
+    silent=yes ;;
+
+  -sbindir | --sbindir | --sbindi | --sbind | --sbin | --sbi | --sb)
+    ac_prev=sbindir ;;
+  -sbindir=* | --sbindir=* | --sbindi=* | --sbind=* | --sbin=* \
+  | --sbi=* | --sb=*)
+    sbindir="$ac_optarg" ;;
+
+  -sharedstatedir | --sharedstatedir | --sharedstatedi \
+  | --sharedstated | --sharedstate | --sharedstat | --sharedsta \
+  | --sharedst | --shareds | --shared | --share | --shar \
+  | --sha | --sh)
+    ac_prev=sharedstatedir ;;
+  -sharedstatedir=* | --sharedstatedir=* | --sharedstatedi=* \
+  | --sharedstated=* | --sharedstate=* | --sharedstat=* | --sharedsta=* \
+  | --sharedst=* | --shareds=* | --shared=* | --share=* | --shar=* \
+  | --sha=* | --sh=*)
+    sharedstatedir="$ac_optarg" ;;
+
+  -site | --site | --sit)
+    ac_prev=site ;;
+  -site=* | --site=* | --sit=*)
+    site="$ac_optarg" ;;
+
+  -srcdir | --srcdir | --srcdi | --srcd | --src | --sr)
+    ac_prev=srcdir ;;
+  -srcdir=* | --srcdir=* | --srcdi=* | --srcd=* | --src=* | --sr=*)
+    srcdir="$ac_optarg" ;;
+
+  -sysconfdir | --sysconfdir | --sysconfdi | --sysconfd | --sysconf \
+  | --syscon | --sysco | --sysc | --sys | --sy)
+    ac_prev=sysconfdir ;;
+  -sysconfdir=* | --sysconfdir=* | --sysconfdi=* | --sysconfd=* | --sysconf=* \
+  | --syscon=* | --sysco=* | --sysc=* | --sys=* | --sy=*)
+    sysconfdir="$ac_optarg" ;;
+
+  -target | --target | --targe | --targ | --tar | --ta | --t)
+    ac_prev=target ;;
+  -target=* | --target=* | --targe=* | --targ=* | --tar=* | --ta=* | --t=*)
+    target="$ac_optarg" ;;
+
+  -v | -verbose | --verbose | --verbos | --verbo | --verb)
+    verbose=yes ;;
+
+  -version | --version | --versio | --versi | --vers)
+    echo "configure generated by autoconf version 2.13"
+    exit 0 ;;
+
+  -with-* | --with-*)
+    ac_package=`echo $ac_option|sed -e 's/-*with-//' -e 's/=.*//'`
+    # Reject names that are not valid shell variable names.
+    if test -n "`echo $ac_package| sed 's/[-_a-zA-Z0-9]//g'`"; then
+      { echo "configure: error: $ac_package: invalid package name" 1>&2; exit 1; }
+    fi
+    ac_package=`echo $ac_package| sed 's/-/_/g'`
+    case "$ac_option" in
+      *=*) ;;
+      *) ac_optarg=yes ;;
+    esac
+    eval "with_${ac_package}='$ac_optarg'" ;;
+
+  -without-* | --without-*)
+    ac_package=`echo $ac_option|sed -e 's/-*without-//'`
+    # Reject names that are not valid shell variable names.
+    if test -n "`echo $ac_package| sed 's/[-a-zA-Z0-9_]//g'`"; then
+      { echo "configure: error: $ac_package: invalid package name" 1>&2; exit 1; }
+    fi
+    ac_package=`echo $ac_package| sed 's/-/_/g'`
+    eval "with_${ac_package}=no" ;;
+
+  --x)
+    # Obsolete; use --with-x.
+    with_x=yes ;;
+
+  -x-includes | --x-includes | --x-include | --x-includ | --x-inclu \
+  | --x-incl | --x-inc | --x-in | --x-i)
+    ac_prev=x_includes ;;
+  -x-includes=* | --x-includes=* | --x-include=* | --x-includ=* | --x-inclu=* \
+  | --x-incl=* | --x-inc=* | --x-in=* | --x-i=*)
+    x_includes="$ac_optarg" ;;
+
+  -x-libraries | --x-libraries | --x-librarie | --x-librari \
+  | --x-librar | --x-libra | --x-libr | --x-lib | --x-li | --x-l)
+    ac_prev=x_libraries ;;
+  -x-libraries=* | --x-libraries=* | --x-librarie=* | --x-librari=* \
+  | --x-librar=* | --x-libra=* | --x-libr=* | --x-lib=* | --x-li=* | --x-l=*)
+    x_libraries="$ac_optarg" ;;
+
+  -*) { echo "configure: error: $ac_option: invalid option; use --help to show usage" 1>&2; exit 1; }
+    ;;
+
+  *)
+    if test -n "`echo $ac_option| sed 's/[-a-z0-9.]//g'`"; then
+      echo "configure: warning: $ac_option: invalid host type" 1>&2
+    fi
+    if test "x$nonopt" != xNONE; then
+      { echo "configure: error: can only configure for one host and one target at a time" 1>&2; exit 1; }
+    fi
+    nonopt="$ac_option"
+    ;;
+
+  esac
+done
+
+if test -n "$ac_prev"; then
+  { echo "configure: error: missing argument to --`echo $ac_prev | sed 's/_/-/g'`" 1>&2; exit 1; }
+fi
+
+trap 'rm -fr conftest* confdefs* core core.* *.core $ac_clean_files; exit 1' 1 2 15
+
+# File descriptor usage:
+# 0 standard input
+# 1 file creation
+# 2 errors and warnings
+# 3 some systems may open it to /dev/tty
+# 4 used on the Kubota Titan
+# 6 checking for... messages and results
+# 5 compiler messages saved in config.log
+if test "$silent" = yes; then
+  exec 6>/dev/null
+else
+  exec 6>&1
+fi
+exec 5>./config.log
+
+echo "\
+This file contains any messages produced by compilers while
+running configure, to aid debugging if configure makes a mistake.
+" 1>&5
+
+# Strip out --no-create and --no-recursion so they do not pile up.
+# Also quote any args containing shell metacharacters.
+ac_configure_args=
+for ac_arg
+do
+  case "$ac_arg" in
+  -no-create | --no-create | --no-creat | --no-crea | --no-cre \
+  | --no-cr | --no-c) ;;
+  -no-recursion | --no-recursion | --no-recursio | --no-recursi \
+  | --no-recurs | --no-recur | --no-recu | --no-rec | --no-re | --no-r) ;;
+  *" "*|*"	"*|*[\[\]\~\#\$\^\&\*\(\)\{\}\\\|\;\<\>\?]*)
+  ac_configure_args="$ac_configure_args '$ac_arg'" ;;
+  *) ac_configure_args="$ac_configure_args $ac_arg" ;;
+  esac
+done
+
+# NLS nuisances.
+# Only set these to C if already set.  These must not be set unconditionally
+# because not all systems understand e.g. LANG=C (notably SCO).
+# Fixing LC_MESSAGES prevents Solaris sh from translating var values in `set'!
+# Non-C LC_CTYPE values break the ctype check.
+if test "${LANG+set}"   = set; then LANG=C;   export LANG;   fi
+if test "${LC_ALL+set}" = set; then LC_ALL=C; export LC_ALL; fi
+if test "${LC_MESSAGES+set}" = set; then LC_MESSAGES=C; export LC_MESSAGES; fi
+if test "${LC_CTYPE+set}"    = set; then LC_CTYPE=C;    export LC_CTYPE;    fi
+
+# confdefs.h avoids OS command line length limits that DEFS can exceed.
+rm -rf conftest* confdefs.h
+# AIX cpp loses on an empty file, so make sure it contains at least a newline.
+echo > confdefs.h
+
+# A filename unique to this package, relative to the directory that
+# configure is in, which we can look for to find out if srcdir is correct.
+ac_unique_file=include/yaz/yaz-version.h
+
+# Find the source files, if location was not specified.
+if test -z "$srcdir"; then
+  ac_srcdir_defaulted=yes
+  # Try the directory containing this script, then its parent.
+  ac_prog=$0
+  ac_confdir=`echo $ac_prog|sed 's%/[^/][^/]*$%%'`
+  test "x$ac_confdir" = "x$ac_prog" && ac_confdir=.
+  srcdir=$ac_confdir
+  if test ! -r $srcdir/$ac_unique_file; then
+    srcdir=..
+  fi
+else
+  ac_srcdir_defaulted=no
+fi
+if test ! -r $srcdir/$ac_unique_file; then
+  if test "$ac_srcdir_defaulted" = yes; then
+    { echo "configure: error: can not find sources in $ac_confdir or .." 1>&2; exit 1; }
+  else
+    { echo "configure: error: can not find sources in $srcdir" 1>&2; exit 1; }
+  fi
+fi
+srcdir=`echo "${srcdir}" | sed 's%\([^/]\)/*$%\1%'`
+
+# Prefer explicitly selected file to automatically selected ones.
+if test -z "$CONFIG_SITE"; then
+  if test "x$prefix" != xNONE; then
+    CONFIG_SITE="$prefix/share/config.site $prefix/etc/config.site"
+  else
+    CONFIG_SITE="$ac_default_prefix/share/config.site $ac_default_prefix/etc/config.site"
+  fi
+fi
+for ac_site_file in $CONFIG_SITE; do
+  if test -r "$ac_site_file"; then
+    echo "loading site script $ac_site_file"
+    . "$ac_site_file"
+  fi
+done
+
+if test -r "$cache_file"; then
+  echo "loading cache $cache_file"
+  . $cache_file
+else
+  echo "creating cache $cache_file"
+  > $cache_file
+fi
+
+ac_ext=c
+# CFLAGS is not in ac_cpp because -g, -O, etc. are not valid cpp options.
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='${CC-cc} -c $CFLAGS $CPPFLAGS conftest.$ac_ext 1>&5'
+ac_link='${CC-cc} -o conftest${ac_exeext} $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS 1>&5'
+cross_compiling=$ac_cv_prog_cc_cross
+
+ac_exeext=
+ac_objext=o
+if (echo "testing\c"; echo 1,2,3) | grep c >/dev/null; then
+  # Stardent Vistra SVR4 grep lacks -e, says ghazi@caip.rutgers.edu.
+  if (echo -n testing; echo 1,2,3) | sed s/-n/xn/ | grep xn >/dev/null; then
+    ac_n= ac_c='
+' ac_t='	'
+  else
+    ac_n=-n ac_c= ac_t=
+  fi
+else
+  ac_n= ac_c='\c' ac_t=
+fi
+
+
+ac_aux_dir=
+for ac_dir in $srcdir $srcdir/.. $srcdir/../..; do
+  if test -f $ac_dir/install-sh; then
+    ac_aux_dir=$ac_dir
+    ac_install_sh="$ac_aux_dir/install-sh -c"
+    break
+  elif test -f $ac_dir/install.sh; then
+    ac_aux_dir=$ac_dir
+    ac_install_sh="$ac_aux_dir/install.sh -c"
+    break
+  fi
+done
+if test -z "$ac_aux_dir"; then
+  { echo "configure: error: can not find install-sh or install.sh in $srcdir $srcdir/.. $srcdir/../.." 1>&2; exit 1; }
+fi
+ac_config_guess=$ac_aux_dir/config.guess
+ac_config_sub=$ac_aux_dir/config.sub
+ac_configure=$ac_aux_dir/configure # This should be Cygnus configure.
+
+# Find a good install program.  We prefer a C program (faster),
+# so one script is as good as another.  But avoid the broken or
+# incompatible versions:
+# SysV /etc/install, /usr/sbin/install
+# SunOS /usr/etc/install
+# IRIX /sbin/install
+# AIX /bin/install
+# AIX 4 /usr/bin/installbsd, which doesn't work without a -g flag
+# AFS /usr/afsws/bin/install, which mishandles nonexistent args
+# SVR4 /usr/ucb/install, which tries to use the nonexistent group "staff"
+# ./install, which can be erroneously created by make from ./install.sh.
+echo $ac_n "checking for a BSD compatible install""... $ac_c" 1>&6
+echo "configure:562: checking for a BSD compatible install" >&5
+if test -z "$INSTALL"; then
+if eval "test \"`echo '$''{'ac_cv_path_install'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+    IFS="${IFS= 	}"; ac_save_IFS="$IFS"; IFS=":"
+  for ac_dir in $PATH; do
+    # Account for people who put trailing slashes in PATH elements.
+    case "$ac_dir/" in
+    /|./|.//|/etc/*|/usr/sbin/*|/usr/etc/*|/sbin/*|/usr/afsws/bin/*|/usr/ucb/*) ;;
+    *)
+      # OSF1 and SCO ODT 3.0 have their own names for install.
+      # Don't use installbsd from OSF since it installs stuff as root
+      # by default.
+      for ac_prog in ginstall scoinst install; do
+        if test -f $ac_dir/$ac_prog; then
+	  if test $ac_prog = install &&
+            grep dspmsg $ac_dir/$ac_prog >/dev/null 2>&1; then
+	    # AIX install.  It has an incompatible calling convention.
+	    :
+	  else
+	    ac_cv_path_install="$ac_dir/$ac_prog -c"
+	    break 2
+	  fi
+	fi
+      done
+      ;;
+    esac
+  done
+  IFS="$ac_save_IFS"
+
+fi
+  if test "${ac_cv_path_install+set}" = set; then
+    INSTALL="$ac_cv_path_install"
+  else
+    # As a last resort, use the slow shell script.  We don't cache a
+    # path for INSTALL within a source directory, because that will
+    # break other packages using the cache if that directory is
+    # removed, or if the path is relative.
+    INSTALL="$ac_install_sh"
+  fi
+fi
+echo "$ac_t""$INSTALL" 1>&6
+
+# Use test -z because SunOS4 sh mishandles braces in ${var-val}.
+# It thinks the first close brace ends the variable substitution.
+test -z "$INSTALL_PROGRAM" && INSTALL_PROGRAM='${INSTALL}'
+
+test -z "$INSTALL_SCRIPT" && INSTALL_SCRIPT='${INSTALL_PROGRAM}'
+
+test -z "$INSTALL_DATA" && INSTALL_DATA='${INSTALL} -m 644'
+
+echo $ac_n "checking whether build environment is sane""... $ac_c" 1>&6
+echo "configure:615: checking whether build environment is sane" >&5
+# Just in case
+sleep 1
+echo timestamp > conftestfile
+# Do `set' in a subshell so we don't clobber the current shell's
+# arguments.  Must try -L first in case configure is actually a
+# symlink; some systems play weird games with the mod time of symlinks
+# (eg FreeBSD returns the mod time of the symlink's containing
+# directory).
+if (
+   set X `ls -Lt $srcdir/configure conftestfile 2> /dev/null`
+   if test "$*" = "X"; then
+      # -L didn't work.
+      set X `ls -t $srcdir/configure conftestfile`
+   fi
+   if test "$*" != "X $srcdir/configure conftestfile" \
+      && test "$*" != "X conftestfile $srcdir/configure"; then
+
+      # If neither matched, then we have a broken ls.  This can happen
+      # if, for instance, CONFIG_SHELL is bash and it inherits a
+      # broken ls alias from the environment.  This has actually
+      # happened.  Such a system could not be considered "sane".
+      { echo "configure: error: ls -t appears to fail.  Make sure there is not a broken
+alias in your environment" 1>&2; exit 1; }
+   fi
+
+   test "$2" = conftestfile
+   )
+then
+   # Ok.
+   :
+else
+   { echo "configure: error: newly created file is older than distributed files!
+Check your system clock" 1>&2; exit 1; }
+fi
+rm -f conftest*
+echo "$ac_t""yes" 1>&6
+if test "$program_transform_name" = s,x,x,; then
+  program_transform_name=
+else
+  # Double any \ or $.  echo might interpret backslashes.
+  cat <<\EOF_SED > conftestsed
+s,\\,\\\\,g; s,\$,$$,g
+EOF_SED
+  program_transform_name="`echo $program_transform_name|sed -f conftestsed`"
+  rm -f conftestsed
+fi
+test "$program_prefix" != NONE &&
+  program_transform_name="s,^,${program_prefix},; $program_transform_name"
+# Use a double $ so make ignores it.
+test "$program_suffix" != NONE &&
+  program_transform_name="s,\$\$,${program_suffix},; $program_transform_name"
+
+# sed with no file args requires a program.
+test "$program_transform_name" = "" && program_transform_name="s,x,x,"
+
+echo $ac_n "checking whether ${MAKE-make} sets \${MAKE}""... $ac_c" 1>&6
+echo "configure:672: checking whether ${MAKE-make} sets \${MAKE}" >&5
+set dummy ${MAKE-make}; ac_make=`echo "$2" | sed 'y%./+-%__p_%'`
+if eval "test \"`echo '$''{'ac_cv_prog_make_${ac_make}_set'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  cat > conftestmake <<\EOF
+all:
+	@echo 'ac_maketemp="${MAKE}"'
+EOF
+# GNU make sometimes prints "make[1]: Entering...", which would confuse us.
+eval `${MAKE-make} -f conftestmake 2>/dev/null | grep temp=`
+if test -n "$ac_maketemp"; then
+  eval ac_cv_prog_make_${ac_make}_set=yes
+else
+  eval ac_cv_prog_make_${ac_make}_set=no
+fi
+rm -f conftestmake
+fi
+if eval "test \"`echo '$ac_cv_prog_make_'${ac_make}_set`\" = yes"; then
+  echo "$ac_t""yes" 1>&6
+  SET_MAKE=
+else
+  echo "$ac_t""no" 1>&6
+  SET_MAKE="MAKE=${MAKE-make}"
+fi
+
+
+PACKAGE=yaz
+
+VERSION=1.6
+
+if test "`cd $srcdir && pwd`" != "`pwd`" && test -f $srcdir/config.status; then
+  { echo "configure: error: source directory already configured; run "make distclean" there first" 1>&2; exit 1; }
+fi
+cat >> confdefs.h <<EOF
+#define PACKAGE "$PACKAGE"
+EOF
+
+cat >> confdefs.h <<EOF
+#define VERSION "$VERSION"
+EOF
+
+
+
+missing_dir=`cd $ac_aux_dir && pwd`
+echo $ac_n "checking for working aclocal""... $ac_c" 1>&6
+echo "configure:718: checking for working aclocal" >&5
+# Run test in a subshell; some versions of sh will print an error if
+# an executable is not found, even if stderr is redirected.
+# Redirect stdin to placate older versions of autoconf.  Sigh.
+if (aclocal --version) < /dev/null > /dev/null 2>&1; then
+   ACLOCAL=aclocal
+   echo "$ac_t""found" 1>&6
+else
+   ACLOCAL="$missing_dir/missing aclocal"
+   echo "$ac_t""missing" 1>&6
+fi
+
+echo $ac_n "checking for working autoconf""... $ac_c" 1>&6
+echo "configure:731: checking for working autoconf" >&5
+# Run test in a subshell; some versions of sh will print an error if
+# an executable is not found, even if stderr is redirected.
+# Redirect stdin to placate older versions of autoconf.  Sigh.
+if (autoconf --version) < /dev/null > /dev/null 2>&1; then
+   AUTOCONF=autoconf
+   echo "$ac_t""found" 1>&6
+else
+   AUTOCONF="$missing_dir/missing autoconf"
+   echo "$ac_t""missing" 1>&6
+fi
+
+echo $ac_n "checking for working automake""... $ac_c" 1>&6
+echo "configure:744: checking for working automake" >&5
+# Run test in a subshell; some versions of sh will print an error if
+# an executable is not found, even if stderr is redirected.
+# Redirect stdin to placate older versions of autoconf.  Sigh.
+if (automake --version) < /dev/null > /dev/null 2>&1; then
+   AUTOMAKE=automake
+   echo "$ac_t""found" 1>&6
+else
+   AUTOMAKE="$missing_dir/missing automake"
+   echo "$ac_t""missing" 1>&6
+fi
+
+echo $ac_n "checking for working autoheader""... $ac_c" 1>&6
+echo "configure:757: checking for working autoheader" >&5
+# Run test in a subshell; some versions of sh will print an error if
+# an executable is not found, even if stderr is redirected.
+# Redirect stdin to placate older versions of autoconf.  Sigh.
+if (autoheader --version) < /dev/null > /dev/null 2>&1; then
+   AUTOHEADER=autoheader
+   echo "$ac_t""found" 1>&6
+else
+   AUTOHEADER="$missing_dir/missing autoheader"
+   echo "$ac_t""missing" 1>&6
+fi
+
+echo $ac_n "checking for working makeinfo""... $ac_c" 1>&6
+echo "configure:770: checking for working makeinfo" >&5
+# Run test in a subshell; some versions of sh will print an error if
+# an executable is not found, even if stderr is redirected.
+# Redirect stdin to placate older versions of autoconf.  Sigh.
+if (makeinfo --version) < /dev/null > /dev/null 2>&1; then
+   MAKEINFO=makeinfo
+   echo "$ac_t""found" 1>&6
+else
+   MAKEINFO="$missing_dir/missing makeinfo"
+   echo "$ac_t""missing" 1>&6
+fi
+
+
+# Extract the first word of "gcc", so it can be a program name with args.
+set dummy gcc; ac_word=$2
+echo $ac_n "checking for $ac_word""... $ac_c" 1>&6
+echo "configure:786: checking for $ac_word" >&5
+if eval "test \"`echo '$''{'ac_cv_prog_CC'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  if test -n "$CC"; then
+  ac_cv_prog_CC="$CC" # Let the user override the test.
+else
+  IFS="${IFS= 	}"; ac_save_ifs="$IFS"; IFS=":"
+  ac_dummy="$PATH"
+  for ac_dir in $ac_dummy; do
+    test -z "$ac_dir" && ac_dir=.
+    if test -f $ac_dir/$ac_word; then
+      ac_cv_prog_CC="gcc"
+      break
+    fi
+  done
+  IFS="$ac_save_ifs"
+fi
+fi
+CC="$ac_cv_prog_CC"
+if test -n "$CC"; then
+  echo "$ac_t""$CC" 1>&6
+else
+  echo "$ac_t""no" 1>&6
+fi
+
+if test -z "$CC"; then
+  # Extract the first word of "cc", so it can be a program name with args.
+set dummy cc; ac_word=$2
+echo $ac_n "checking for $ac_word""... $ac_c" 1>&6
+echo "configure:816: checking for $ac_word" >&5
+if eval "test \"`echo '$''{'ac_cv_prog_CC'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  if test -n "$CC"; then
+  ac_cv_prog_CC="$CC" # Let the user override the test.
+else
+  IFS="${IFS= 	}"; ac_save_ifs="$IFS"; IFS=":"
+  ac_prog_rejected=no
+  ac_dummy="$PATH"
+  for ac_dir in $ac_dummy; do
+    test -z "$ac_dir" && ac_dir=.
+    if test -f $ac_dir/$ac_word; then
+      if test "$ac_dir/$ac_word" = "/usr/ucb/cc"; then
+        ac_prog_rejected=yes
+	continue
+      fi
+      ac_cv_prog_CC="cc"
+      break
+    fi
+  done
+  IFS="$ac_save_ifs"
+if test $ac_prog_rejected = yes; then
+  # We found a bogon in the path, so make sure we never use it.
+  set dummy $ac_cv_prog_CC
+  shift
+  if test $# -gt 0; then
+    # We chose a different compiler from the bogus one.
+    # However, it has the same basename, so the bogon will be chosen
+    # first if we set CC to just the basename; use the full file name.
+    shift
+    set dummy "$ac_dir/$ac_word" "$@"
+    shift
+    ac_cv_prog_CC="$@"
+  fi
+fi
+fi
+fi
+CC="$ac_cv_prog_CC"
+if test -n "$CC"; then
+  echo "$ac_t""$CC" 1>&6
+else
+  echo "$ac_t""no" 1>&6
+fi
+
+  if test -z "$CC"; then
+    case "`uname -s`" in
+    *win32* | *WIN32*)
+      # Extract the first word of "cl", so it can be a program name with args.
+set dummy cl; ac_word=$2
+echo $ac_n "checking for $ac_word""... $ac_c" 1>&6
+echo "configure:867: checking for $ac_word" >&5
+if eval "test \"`echo '$''{'ac_cv_prog_CC'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  if test -n "$CC"; then
+  ac_cv_prog_CC="$CC" # Let the user override the test.
+else
+  IFS="${IFS= 	}"; ac_save_ifs="$IFS"; IFS=":"
+  ac_dummy="$PATH"
+  for ac_dir in $ac_dummy; do
+    test -z "$ac_dir" && ac_dir=.
+    if test -f $ac_dir/$ac_word; then
+      ac_cv_prog_CC="cl"
+      break
+    fi
+  done
+  IFS="$ac_save_ifs"
+fi
+fi
+CC="$ac_cv_prog_CC"
+if test -n "$CC"; then
+  echo "$ac_t""$CC" 1>&6
+else
+  echo "$ac_t""no" 1>&6
+fi
+ ;;
+    esac
+  fi
+  test -z "$CC" && { echo "configure: error: no acceptable cc found in \$PATH" 1>&2; exit 1; }
+fi
+
+echo $ac_n "checking whether the C compiler ($CC $CFLAGS $LDFLAGS) works""... $ac_c" 1>&6
+echo "configure:899: checking whether the C compiler ($CC $CFLAGS $LDFLAGS) works" >&5
+
+ac_ext=c
+# CFLAGS is not in ac_cpp because -g, -O, etc. are not valid cpp options.
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='${CC-cc} -c $CFLAGS $CPPFLAGS conftest.$ac_ext 1>&5'
+ac_link='${CC-cc} -o conftest${ac_exeext} $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS 1>&5'
+cross_compiling=$ac_cv_prog_cc_cross
+
+cat > conftest.$ac_ext << EOF
+
+#line 910 "configure"
+#include "confdefs.h"
+
+main(){return(0);}
+EOF
+if { (eval echo configure:915: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+  ac_cv_prog_cc_works=yes
+  # If we can't run a trivial program, we are probably using a cross compiler.
+  if (./conftest; exit) 2>/dev/null; then
+    ac_cv_prog_cc_cross=no
+  else
+    ac_cv_prog_cc_cross=yes
+  fi
+else
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  ac_cv_prog_cc_works=no
+fi
+rm -fr conftest*
+ac_ext=c
+# CFLAGS is not in ac_cpp because -g, -O, etc. are not valid cpp options.
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='${CC-cc} -c $CFLAGS $CPPFLAGS conftest.$ac_ext 1>&5'
+ac_link='${CC-cc} -o conftest${ac_exeext} $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS 1>&5'
+cross_compiling=$ac_cv_prog_cc_cross
+
+echo "$ac_t""$ac_cv_prog_cc_works" 1>&6
+if test $ac_cv_prog_cc_works = no; then
+  { echo "configure: error: installation or configuration problem: C compiler cannot create executables." 1>&2; exit 1; }
+fi
+echo $ac_n "checking whether the C compiler ($CC $CFLAGS $LDFLAGS) is a cross-compiler""... $ac_c" 1>&6
+echo "configure:941: checking whether the C compiler ($CC $CFLAGS $LDFLAGS) is a cross-compiler" >&5
+echo "$ac_t""$ac_cv_prog_cc_cross" 1>&6
+cross_compiling=$ac_cv_prog_cc_cross
+
+echo $ac_n "checking whether we are using GNU C""... $ac_c" 1>&6
+echo "configure:946: checking whether we are using GNU C" >&5
+if eval "test \"`echo '$''{'ac_cv_prog_gcc'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  cat > conftest.c <<EOF
+#ifdef __GNUC__
+  yes;
+#endif
+EOF
+if { ac_try='${CC-cc} -E conftest.c'; { (eval echo configure:955: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }; } | egrep yes >/dev/null 2>&1; then
+  ac_cv_prog_gcc=yes
+else
+  ac_cv_prog_gcc=no
+fi
+fi
+
+echo "$ac_t""$ac_cv_prog_gcc" 1>&6
+
+if test $ac_cv_prog_gcc = yes; then
+  GCC=yes
+else
+  GCC=
+fi
+
+ac_test_CFLAGS="${CFLAGS+set}"
+ac_save_CFLAGS="$CFLAGS"
+CFLAGS=
+echo $ac_n "checking whether ${CC-cc} accepts -g""... $ac_c" 1>&6
+echo "configure:974: checking whether ${CC-cc} accepts -g" >&5
+if eval "test \"`echo '$''{'ac_cv_prog_cc_g'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  echo 'void f(){}' > conftest.c
+if test -z "`${CC-cc} -g -c conftest.c 2>&1`"; then
+  ac_cv_prog_cc_g=yes
+else
+  ac_cv_prog_cc_g=no
+fi
+rm -f conftest*
+
+fi
+
+echo "$ac_t""$ac_cv_prog_cc_g" 1>&6
+if test "$ac_test_CFLAGS" = set; then
+  CFLAGS="$ac_save_CFLAGS"
+elif test $ac_cv_prog_cc_g = yes; then
+  if test "$GCC" = yes; then
+    CFLAGS="-g -O2"
+  else
+    CFLAGS="-g"
+  fi
+else
+  if test "$GCC" = yes; then
+    CFLAGS="-O2"
+  else
+    CFLAGS=
+  fi
+fi
+
+echo $ac_n "checking how to run the C preprocessor""... $ac_c" 1>&6
+echo "configure:1006: checking how to run the C preprocessor" >&5
+# On Suns, sometimes $CPP names a directory.
+if test -n "$CPP" && test -d "$CPP"; then
+  CPP=
+fi
+if test -z "$CPP"; then
+if eval "test \"`echo '$''{'ac_cv_prog_CPP'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+    # This must be in double quotes, not single quotes, because CPP may get
+  # substituted into the Makefile and "${CC-cc}" will confuse make.
+  CPP="${CC-cc} -E"
+  # On the NeXT, cc -E runs the code through the compiler's parser,
+  # not just through cpp.
+  cat > conftest.$ac_ext <<EOF
+#line 1021 "configure"
+#include "confdefs.h"
+#include <assert.h>
+Syntax Error
+EOF
+ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out"
+{ (eval echo configure:1027: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }
+ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"`
+if test -z "$ac_err"; then
+  :
+else
+  echo "$ac_err" >&5
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -rf conftest*
+  CPP="${CC-cc} -E -traditional-cpp"
+  cat > conftest.$ac_ext <<EOF
+#line 1038 "configure"
+#include "confdefs.h"
+#include <assert.h>
+Syntax Error
+EOF
+ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out"
+{ (eval echo configure:1044: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }
+ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"`
+if test -z "$ac_err"; then
+  :
+else
+  echo "$ac_err" >&5
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -rf conftest*
+  CPP="${CC-cc} -nologo -E"
+  cat > conftest.$ac_ext <<EOF
+#line 1055 "configure"
+#include "confdefs.h"
+#include <assert.h>
+Syntax Error
+EOF
+ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out"
+{ (eval echo configure:1061: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }
+ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"`
+if test -z "$ac_err"; then
+  :
+else
+  echo "$ac_err" >&5
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -rf conftest*
+  CPP=/lib/cpp
+fi
+rm -f conftest*
+fi
+rm -f conftest*
+fi
+rm -f conftest*
+  ac_cv_prog_CPP="$CPP"
+fi
+  CPP="$ac_cv_prog_CPP"
+else
+  ac_cv_prog_CPP="$CPP"
+fi
+echo "$ac_t""$CPP" 1>&6
+
+# Find a good install program.  We prefer a C program (faster),
+# so one script is as good as another.  But avoid the broken or
+# incompatible versions:
+# SysV /etc/install, /usr/sbin/install
+# SunOS /usr/etc/install
+# IRIX /sbin/install
+# AIX /bin/install
+# AIX 4 /usr/bin/installbsd, which doesn't work without a -g flag
+# AFS /usr/afsws/bin/install, which mishandles nonexistent args
+# SVR4 /usr/ucb/install, which tries to use the nonexistent group "staff"
+# ./install, which can be erroneously created by make from ./install.sh.
+echo $ac_n "checking for a BSD compatible install""... $ac_c" 1>&6
+echo "configure:1097: checking for a BSD compatible install" >&5
+if test -z "$INSTALL"; then
+if eval "test \"`echo '$''{'ac_cv_path_install'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+    IFS="${IFS= 	}"; ac_save_IFS="$IFS"; IFS=":"
+  for ac_dir in $PATH; do
+    # Account for people who put trailing slashes in PATH elements.
+    case "$ac_dir/" in
+    /|./|.//|/etc/*|/usr/sbin/*|/usr/etc/*|/sbin/*|/usr/afsws/bin/*|/usr/ucb/*) ;;
+    *)
+      # OSF1 and SCO ODT 3.0 have their own names for install.
+      # Don't use installbsd from OSF since it installs stuff as root
+      # by default.
+      for ac_prog in ginstall scoinst install; do
+        if test -f $ac_dir/$ac_prog; then
+	  if test $ac_prog = install &&
+            grep dspmsg $ac_dir/$ac_prog >/dev/null 2>&1; then
+	    # AIX install.  It has an incompatible calling convention.
+	    :
+	  else
+	    ac_cv_path_install="$ac_dir/$ac_prog -c"
+	    break 2
+	  fi
+	fi
+      done
+      ;;
+    esac
+  done
+  IFS="$ac_save_IFS"
+
+fi
+  if test "${ac_cv_path_install+set}" = set; then
+    INSTALL="$ac_cv_path_install"
+  else
+    # As a last resort, use the slow shell script.  We don't cache a
+    # path for INSTALL within a source directory, because that will
+    # break other packages using the cache if that directory is
+    # removed, or if the path is relative.
+    INSTALL="$ac_install_sh"
+  fi
+fi
+echo "$ac_t""$INSTALL" 1>&6
+
+# Use test -z because SunOS4 sh mishandles braces in ${var-val}.
+# It thinks the first close brace ends the variable substitution.
+test -z "$INSTALL_PROGRAM" && INSTALL_PROGRAM='${INSTALL}'
+
+test -z "$INSTALL_SCRIPT" && INSTALL_SCRIPT='${INSTALL_PROGRAM}'
+
+test -z "$INSTALL_DATA" && INSTALL_DATA='${INSTALL} -m 644'
+
+# Extract the first word of "ranlib", so it can be a program name with args.
+set dummy ranlib; ac_word=$2
+echo $ac_n "checking for $ac_word""... $ac_c" 1>&6
+echo "configure:1152: checking for $ac_word" >&5
+if eval "test \"`echo '$''{'ac_cv_prog_RANLIB'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  if test -n "$RANLIB"; then
+  ac_cv_prog_RANLIB="$RANLIB" # Let the user override the test.
+else
+  IFS="${IFS= 	}"; ac_save_ifs="$IFS"; IFS=":"
+  ac_dummy="$PATH"
+  for ac_dir in $ac_dummy; do
+    test -z "$ac_dir" && ac_dir=.
+    if test -f $ac_dir/$ac_word; then
+      ac_cv_prog_RANLIB="ranlib"
+      break
+    fi
+  done
+  IFS="$ac_save_ifs"
+  test -z "$ac_cv_prog_RANLIB" && ac_cv_prog_RANLIB=":"
+fi
+fi
+RANLIB="$ac_cv_prog_RANLIB"
+if test -n "$RANLIB"; then
+  echo "$ac_t""$RANLIB" 1>&6
+else
+  echo "$ac_t""no" 1>&6
+fi
+
+for ac_prog in sgml2txt
+do
+# Extract the first word of "$ac_prog", so it can be a program name with args.
+set dummy $ac_prog; ac_word=$2
+echo $ac_n "checking for $ac_word""... $ac_c" 1>&6
+echo "configure:1184: checking for $ac_word" >&5
+if eval "test \"`echo '$''{'ac_cv_prog_have_sgml2txt'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  if test -n "$have_sgml2txt"; then
+  ac_cv_prog_have_sgml2txt="$have_sgml2txt" # Let the user override the test.
+else
+  IFS="${IFS= 	}"; ac_save_ifs="$IFS"; IFS=":"
+  ac_dummy="$PATH"
+  for ac_dir in $ac_dummy; do
+    test -z "$ac_dir" && ac_dir=.
+    if test -f $ac_dir/$ac_word; then
+      ac_cv_prog_have_sgml2txt="$ac_prog"
+      break
+    fi
+  done
+  IFS="$ac_save_ifs"
+fi
+fi
+have_sgml2txt="$ac_cv_prog_have_sgml2txt"
+if test -n "$have_sgml2txt"; then
+  echo "$ac_t""$have_sgml2txt" 1>&6
+else
+  echo "$ac_t""no" 1>&6
+fi
+
+test -n "$have_sgml2txt" && break
+done
+test -n "$have_sgml2txt" || have_sgml2txt="no"
+
+for ac_prog in sgml2latex
+do
+# Extract the first word of "$ac_prog", so it can be a program name with args.
+set dummy $ac_prog; ac_word=$2
+echo $ac_n "checking for $ac_word""... $ac_c" 1>&6
+echo "configure:1219: checking for $ac_word" >&5
+if eval "test \"`echo '$''{'ac_cv_prog_have_sgml2latex'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  if test -n "$have_sgml2latex"; then
+  ac_cv_prog_have_sgml2latex="$have_sgml2latex" # Let the user override the test.
+else
+  IFS="${IFS= 	}"; ac_save_ifs="$IFS"; IFS=":"
+  ac_dummy="$PATH"
+  for ac_dir in $ac_dummy; do
+    test -z "$ac_dir" && ac_dir=.
+    if test -f $ac_dir/$ac_word; then
+      ac_cv_prog_have_sgml2latex="$ac_prog"
+      break
+    fi
+  done
+  IFS="$ac_save_ifs"
+fi
+fi
+have_sgml2latex="$ac_cv_prog_have_sgml2latex"
+if test -n "$have_sgml2latex"; then
+  echo "$ac_t""$have_sgml2latex" 1>&6
+else
+  echo "$ac_t""no" 1>&6
+fi
+
+test -n "$have_sgml2latex" && break
+done
+test -n "$have_sgml2latex" || have_sgml2latex="no"
+
+for ac_prog in sgml2html
+do
+# Extract the first word of "$ac_prog", so it can be a program name with args.
+set dummy $ac_prog; ac_word=$2
+echo $ac_n "checking for $ac_word""... $ac_c" 1>&6
+echo "configure:1254: checking for $ac_word" >&5
+if eval "test \"`echo '$''{'ac_cv_prog_have_sgml2html'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  if test -n "$have_sgml2html"; then
+  ac_cv_prog_have_sgml2html="$have_sgml2html" # Let the user override the test.
+else
+  IFS="${IFS= 	}"; ac_save_ifs="$IFS"; IFS=":"
+  ac_dummy="$PATH"
+  for ac_dir in $ac_dummy; do
+    test -z "$ac_dir" && ac_dir=.
+    if test -f $ac_dir/$ac_word; then
+      ac_cv_prog_have_sgml2html="$ac_prog"
+      break
+    fi
+  done
+  IFS="$ac_save_ifs"
+fi
+fi
+have_sgml2html="$ac_cv_prog_have_sgml2html"
+if test -n "$have_sgml2html"; then
+  echo "$ac_t""$have_sgml2html" 1>&6
+else
+  echo "$ac_t""no" 1>&6
+fi
+
+test -n "$have_sgml2html" && break
+done
+test -n "$have_sgml2html" || have_sgml2html="no"
+
+if test "$have_sgml2txt" = "no" -o "$have_sgml2latex" = "no" -o "$have_sgml2html" = "no"; then
+	DOCMODULE=""
+else
+	DOCMODULE="doc"
+fi
+
+
+
+# Check whether --enable-comp or --disable-comp was given.
+if test "${enable_comp+set}" = set; then
+  enableval="$enable_comp"
+  :
+else
+  enable_comp=yes
+fi
+
+if test "$enable_comp" = "yes"; then
+	ASNMODULE="z39.50"
+	ILLMODULE="ill"
+	ILLLIB=../ill/libill.a
+	ASN_MAKEFILES="z39.50/Makefile ill/Makefile"
+	cp -f include/yaz/z-proto.h include/yaz/proto.h
+else
+	ILLMODULE=""
+	ASNMODULE=asn
+	ILLLIB=""
+	ASN_MAKEFILES="asn/Makefile"
+	cp -f include/yaz/prt-proto.h include/yaz/proto.h
+fi
+checkBoth=0
+echo $ac_n "checking for connect""... $ac_c" 1>&6
+echo "configure:1315: checking for connect" >&5
+if eval "test \"`echo '$''{'ac_cv_func_connect'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  cat > conftest.$ac_ext <<EOF
+#line 1320 "configure"
+#include "confdefs.h"
+/* System header to define __stub macros and hopefully few prototypes,
+    which can conflict with char connect(); below.  */
+#include <assert.h>
+/* Override any gcc2 internal prototype to avoid an error.  */
+/* We use char because int might match the return type of a gcc2
+    builtin and then its argument prototype would still apply.  */
+char connect();
+
+int main() {
+
+/* The GNU C library defines this for functions which it implements
+    to always fail with ENOSYS.  Some functions are actually named
+    something starting with __ and the normal name is an alias.  */
+#if defined (__stub_connect) || defined (__stub___connect)
+choke me
+#else
+connect();
+#endif
+
+; return 0; }
+EOF
+if { (eval echo configure:1343: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+  rm -rf conftest*
+  eval "ac_cv_func_connect=yes"
+else
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -rf conftest*
+  eval "ac_cv_func_connect=no"
+fi
+rm -f conftest*
+fi
+
+if eval "test \"`echo '$ac_cv_func_'connect`\" = yes"; then
+  echo "$ac_t""yes" 1>&6
+  :
+else
+  echo "$ac_t""no" 1>&6
+fi
+
+if test "$ac_cv_func_connect" = "no"; then
+	echo $ac_n "checking for main in -lsocket""... $ac_c" 1>&6
+echo "configure:1364: checking for main in -lsocket" >&5
+ac_lib_var=`echo socket'_'main | sed 'y%./+-%__p_%'`
+if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  ac_save_LIBS="$LIBS"
+LIBS="-lsocket  $LIBS"
+cat > conftest.$ac_ext <<EOF
+#line 1372 "configure"
+#include "confdefs.h"
+
+int main() {
+main()
+; return 0; }
+EOF
+if { (eval echo configure:1379: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+  rm -rf conftest*
+  eval "ac_cv_lib_$ac_lib_var=yes"
+else
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -rf conftest*
+  eval "ac_cv_lib_$ac_lib_var=no"
+fi
+rm -f conftest*
+LIBS="$ac_save_LIBS"
+
+fi
+if eval "test \"`echo '$ac_cv_lib_'$ac_lib_var`\" = yes"; then
+  echo "$ac_t""yes" 1>&6
+  LIBS="$LIBS -lsocket"
+else
+  echo "$ac_t""no" 1>&6
+checkBoth=1
+fi
+
+fi
+if test "$checkBoth" = "1"; then
+	oldLibs=$LIBS
+	LIBS="$LIBS -lsocket -lnsl"
+	echo $ac_n "checking for accept""... $ac_c" 1>&6
+echo "configure:1405: checking for accept" >&5
+if eval "test \"`echo '$''{'ac_cv_func_accept'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  cat > conftest.$ac_ext <<EOF
+#line 1410 "configure"
+#include "confdefs.h"
+/* System header to define __stub macros and hopefully few prototypes,
+    which can conflict with char accept(); below.  */
+#include <assert.h>
+/* Override any gcc2 internal prototype to avoid an error.  */
+/* We use char because int might match the return type of a gcc2
+    builtin and then its argument prototype would still apply.  */
+char accept();
+
+int main() {
+
+/* The GNU C library defines this for functions which it implements
+    to always fail with ENOSYS.  Some functions are actually named
+    something starting with __ and the normal name is an alias.  */
+#if defined (__stub_accept) || defined (__stub___accept)
+choke me
+#else
+accept();
+#endif
+
+; return 0; }
+EOF
+if { (eval echo configure:1433: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+  rm -rf conftest*
+  eval "ac_cv_func_accept=yes"
+else
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -rf conftest*
+  eval "ac_cv_func_accept=no"
+fi
+rm -f conftest*
+fi
+
+if eval "test \"`echo '$ac_cv_func_'accept`\" = yes"; then
+  echo "$ac_t""yes" 1>&6
+  :
+else
+  echo "$ac_t""no" 1>&6
+LIBS=$oldLibs
+fi
+
+fi
+echo $ac_n "checking for gethostbyname""... $ac_c" 1>&6
+echo "configure:1455: checking for gethostbyname" >&5
+if eval "test \"`echo '$''{'ac_cv_func_gethostbyname'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  cat > conftest.$ac_ext <<EOF
+#line 1460 "configure"
+#include "confdefs.h"
+/* System header to define __stub macros and hopefully few prototypes,
+    which can conflict with char gethostbyname(); below.  */
+#include <assert.h>
+/* Override any gcc2 internal prototype to avoid an error.  */
+/* We use char because int might match the return type of a gcc2
+    builtin and then its argument prototype would still apply.  */
+char gethostbyname();
+
+int main() {
+
+/* The GNU C library defines this for functions which it implements
+    to always fail with ENOSYS.  Some functions are actually named
+    something starting with __ and the normal name is an alias.  */
+#if defined (__stub_gethostbyname) || defined (__stub___gethostbyname)
+choke me
+#else
+gethostbyname();
+#endif
+
+; return 0; }
+EOF
+if { (eval echo configure:1483: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+  rm -rf conftest*
+  eval "ac_cv_func_gethostbyname=yes"
+else
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -rf conftest*
+  eval "ac_cv_func_gethostbyname=no"
+fi
+rm -f conftest*
+fi
+
+if eval "test \"`echo '$ac_cv_func_'gethostbyname`\" = yes"; then
+  echo "$ac_t""yes" 1>&6
+  :
+else
+  echo "$ac_t""no" 1>&6
+echo $ac_n "checking for main in -lnsl""... $ac_c" 1>&6
+echo "configure:1501: checking for main in -lnsl" >&5
+ac_lib_var=`echo nsl'_'main | sed 'y%./+-%__p_%'`
+if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  ac_save_LIBS="$LIBS"
+LIBS="-lnsl  $LIBS"
+cat > conftest.$ac_ext <<EOF
+#line 1509 "configure"
+#include "confdefs.h"
+
+int main() {
+main()
+; return 0; }
+EOF
+if { (eval echo configure:1516: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+  rm -rf conftest*
+  eval "ac_cv_lib_$ac_lib_var=yes"
+else
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -rf conftest*
+  eval "ac_cv_lib_$ac_lib_var=no"
+fi
+rm -f conftest*
+LIBS="$ac_save_LIBS"
+
+fi
+if eval "test \"`echo '$ac_cv_lib_'$ac_lib_var`\" = yes"; then
+  echo "$ac_t""yes" 1>&6
+  LIBS="$LIBS -lnsl"
+else
+  echo "$ac_t""no" 1>&6
+fi
+
+fi
+
+echo $ac_n "checking for readline in -lreadline""... $ac_c" 1>&6
+echo "configure:1539: checking for readline in -lreadline" >&5
+ac_lib_var=`echo readline'_'readline | sed 'y%./+-%__p_%'`
+if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  ac_save_LIBS="$LIBS"
+LIBS="-lreadline  $LIBS"
+cat > conftest.$ac_ext <<EOF
+#line 1547 "configure"
+#include "confdefs.h"
+/* Override any gcc2 internal prototype to avoid an error.  */
+/* We use char because int might match the return type of a gcc2
+    builtin and then its argument prototype would still apply.  */
+char readline();
+
+int main() {
+readline()
+; return 0; }
+EOF
+if { (eval echo configure:1558: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+  rm -rf conftest*
+  eval "ac_cv_lib_$ac_lib_var=yes"
+else
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -rf conftest*
+  eval "ac_cv_lib_$ac_lib_var=no"
+fi
+rm -f conftest*
+LIBS="$ac_save_LIBS"
+
+fi
+if eval "test \"`echo '$ac_cv_lib_'$ac_lib_var`\" = yes"; then
+  echo "$ac_t""yes" 1>&6
+  LIBS="$LIBS -lreadline"
+else
+  echo "$ac_t""no" 1>&6
+fi
+
+if test "$ac_cv_lib_readline_readline" = "no"; then
+	echo $ac_n "checking for readline in -lreadline""... $ac_c" 1>&6
+echo "configure:1580: checking for readline in -lreadline" >&5
+ac_lib_var=`echo readline'_'readline | sed 'y%./+-%__p_%'`
+if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  ac_save_LIBS="$LIBS"
+LIBS="-lreadline  $LIBS"
+cat > conftest.$ac_ext <<EOF
+#line 1588 "configure"
+#include "confdefs.h"
+/* Override any gcc2 internal prototype to avoid an error.  */
+/* We use char because int might match the return type of a gcc2
+    builtin and then its argument prototype would still apply.  */
+char readline();
+
+int main() {
+readline()
+; return 0; }
+EOF
+if { (eval echo configure:1599: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+  rm -rf conftest*
+  eval "ac_cv_lib_$ac_lib_var=yes"
+else
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -rf conftest*
+  eval "ac_cv_lib_$ac_lib_var=no"
+fi
+rm -f conftest*
+LIBS="$ac_save_LIBS"
+
+fi
+if eval "test \"`echo '$ac_cv_lib_'$ac_lib_var`\" = yes"; then
+  echo "$ac_t""yes" 1>&6
+  LIBS="$LIBS -lreadline -ltermcap"
+else
+  echo "$ac_t""no" 1>&6
+fi
+
+fi
+echo $ac_n "checking for add_history in -lhistory""... $ac_c" 1>&6
+echo "configure:1621: checking for add_history in -lhistory" >&5
+ac_lib_var=`echo history'_'add_history | sed 'y%./+-%__p_%'`
+if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  ac_save_LIBS="$LIBS"
+LIBS="-lhistory  $LIBS"
+cat > conftest.$ac_ext <<EOF
+#line 1629 "configure"
+#include "confdefs.h"
+/* Override any gcc2 internal prototype to avoid an error.  */
+/* We use char because int might match the return type of a gcc2
+    builtin and then its argument prototype would still apply.  */
+char add_history();
+
+int main() {
+add_history()
+; return 0; }
+EOF
+if { (eval echo configure:1640: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+  rm -rf conftest*
+  eval "ac_cv_lib_$ac_lib_var=yes"
+else
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -rf conftest*
+  eval "ac_cv_lib_$ac_lib_var=no"
+fi
+rm -f conftest*
+LIBS="$ac_save_LIBS"
+
+fi
+if eval "test \"`echo '$ac_cv_lib_'$ac_lib_var`\" = yes"; then
+  echo "$ac_t""yes" 1>&6
+  LIBS="$LIBS -lhistory"
+else
+  echo "$ac_t""no" 1>&6
+fi
+
+if test "$ac_cv_lib_readline_readline" = "yes"; then
+	for ac_hdr in readline/readline.h readline/history.h
+do
+ac_safe=`echo "$ac_hdr" | sed 'y%./+-%__p_%'`
+echo $ac_n "checking for $ac_hdr""... $ac_c" 1>&6
+echo "configure:1665: checking for $ac_hdr" >&5
+if eval "test \"`echo '$''{'ac_cv_header_$ac_safe'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  cat > conftest.$ac_ext <<EOF
+#line 1670 "configure"
+#include "confdefs.h"
+#include <$ac_hdr>
+EOF
+ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out"
+{ (eval echo configure:1675: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }
+ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"`
+if test -z "$ac_err"; then
+  rm -rf conftest*
+  eval "ac_cv_header_$ac_safe=yes"
+else
+  echo "$ac_err" >&5
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -rf conftest*
+  eval "ac_cv_header_$ac_safe=no"
+fi
+rm -f conftest*
+fi
+if eval "test \"`echo '$ac_cv_header_'$ac_safe`\" = yes"; then
+  echo "$ac_t""yes" 1>&6
+    ac_tr_hdr=HAVE_`echo $ac_hdr | sed 'y%abcdefghijklmnopqrstuvwxyz./-%ABCDEFGHIJKLMNOPQRSTUVWXYZ___%'`
+  cat >> confdefs.h <<EOF
+#define $ac_tr_hdr 1
+EOF
+ 
+else
+  echo "$ac_t""no" 1>&6
+fi
+done
+
+fi
+# Check whether --enable-tcpd or --disable-tcpd was given.
+if test "${enable_tcpd+set}" = set; then
+  enableval="$enable_tcpd"
+  :
+fi
+
+if test "$enable_tcpd" = "yes"; then
+	echo $ac_n "checking for working tcpd.h""... $ac_c" 1>&6
+echo "configure:1710: checking for working tcpd.h" >&5
+	oldLibs=$LIBS
+	LIBS="$LIBS -lwrap -lnsl"
+	cat > conftest.$ac_ext <<EOF
+#line 1714 "configure"
+#include "confdefs.h"
+#include <syslog.h>
+	#include <tcpd.h>
+	int allow_severity = LOG_INFO;
+	int deny_severity = LOG_WARNING;
+int main() {
+struct request_info request_info; int i;
+	i = hosts_access(&request_info);
+; return 0; }
+EOF
+if { (eval echo configure:1725: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+  rm -rf conftest*
+  tcpd_ok=1
+else
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -rf conftest*
+  tcpd_ok=0
+fi
+rm -f conftest*
+	if test "$tcpd_ok" = "0"; then
+		echo "$ac_t""no" 1>&6
+		LIBS=$oldLibs
+	else
+		echo "$ac_t""yes" 1>&6
+		cat >> confdefs.h <<\EOF
+#define HAVE_TCPD_H 1
+EOF
+
+	fi
+fi
+echo $ac_n "checking for ANSI C header files""... $ac_c" 1>&6
+echo "configure:1747: checking for ANSI C header files" >&5
+if eval "test \"`echo '$''{'ac_cv_header_stdc'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  cat > conftest.$ac_ext <<EOF
+#line 1752 "configure"
+#include "confdefs.h"
+#include <stdlib.h>
+#include <stdarg.h>
+#include <string.h>
+#include <float.h>
+EOF
+ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out"
+{ (eval echo configure:1760: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }
+ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"`
+if test -z "$ac_err"; then
+  rm -rf conftest*
+  ac_cv_header_stdc=yes
+else
+  echo "$ac_err" >&5
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -rf conftest*
+  ac_cv_header_stdc=no
+fi
+rm -f conftest*
+
+if test $ac_cv_header_stdc = yes; then
+  # SunOS 4.x string.h does not declare mem*, contrary to ANSI.
+cat > conftest.$ac_ext <<EOF
+#line 1777 "configure"
+#include "confdefs.h"
+#include <string.h>
+EOF
+if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
+  egrep "memchr" >/dev/null 2>&1; then
+  :
+else
+  rm -rf conftest*
+  ac_cv_header_stdc=no
+fi
+rm -f conftest*
+
+fi
+
+if test $ac_cv_header_stdc = yes; then
+  # ISC 2.0.2 stdlib.h does not declare free, contrary to ANSI.
+cat > conftest.$ac_ext <<EOF
+#line 1795 "configure"
+#include "confdefs.h"
+#include <stdlib.h>
+EOF
+if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
+  egrep "free" >/dev/null 2>&1; then
+  :
+else
+  rm -rf conftest*
+  ac_cv_header_stdc=no
+fi
+rm -f conftest*
+
+fi
+
+if test $ac_cv_header_stdc = yes; then
+  # /bin/cc in Irix-4.0.5 gets non-ANSI ctype macros unless using -ansi.
+if test "$cross_compiling" = yes; then
+  :
+else
+  cat > conftest.$ac_ext <<EOF
+#line 1816 "configure"
+#include "confdefs.h"
+#include <ctype.h>
+#define ISLOWER(c) ('a' <= (c) && (c) <= 'z')
+#define TOUPPER(c) (ISLOWER(c) ? 'A' + ((c) - 'a') : (c))
+#define XOR(e, f) (((e) && !(f)) || (!(e) && (f)))
+int main () { int i; for (i = 0; i < 256; i++)
+if (XOR (islower (i), ISLOWER (i)) || toupper (i) != TOUPPER (i)) exit(2);
+exit (0); }
+
+EOF
+if { (eval echo configure:1827: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext} && (./conftest; exit) 2>/dev/null
+then
+  :
+else
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -fr conftest*
+  ac_cv_header_stdc=no
+fi
+rm -fr conftest*
+fi
+
+fi
+fi
+
+echo "$ac_t""$ac_cv_header_stdc" 1>&6
+if test $ac_cv_header_stdc = yes; then
+  cat >> confdefs.h <<\EOF
+#define STDC_HEADERS 1
+EOF
+
+fi
+
+if test "$ac_cv_header_stdc" = "no"; then
+	echo "configure: warning: Your system doesn't seem to support ANSI C" 1>&2
+fi
+# Check whether --enable-threads or --disable-threads was given.
+if test "${enable_threads+set}" = set; then
+  enableval="$enable_threads"
+  :
+fi
+
+if test "$enable_threads" = "yes"; then
+	for ac_hdr in pthread.h threads.h
+do
+ac_safe=`echo "$ac_hdr" | sed 'y%./+-%__p_%'`
+echo $ac_n "checking for $ac_hdr""... $ac_c" 1>&6
+echo "configure:1864: checking for $ac_hdr" >&5
+if eval "test \"`echo '$''{'ac_cv_header_$ac_safe'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  cat > conftest.$ac_ext <<EOF
+#line 1869 "configure"
+#include "confdefs.h"
+#include <$ac_hdr>
+EOF
+ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out"
+{ (eval echo configure:1874: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }
+ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"`
+if test -z "$ac_err"; then
+  rm -rf conftest*
+  eval "ac_cv_header_$ac_safe=yes"
+else
+  echo "$ac_err" >&5
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -rf conftest*
+  eval "ac_cv_header_$ac_safe=no"
+fi
+rm -f conftest*
+fi
+if eval "test \"`echo '$ac_cv_header_'$ac_safe`\" = yes"; then
+  echo "$ac_t""yes" 1>&6
+    ac_tr_hdr=HAVE_`echo $ac_hdr | sed 'y%abcdefghijklmnopqrstuvwxyz./-%ABCDEFGHIJKLMNOPQRSTUVWXYZ___%'`
+  cat >> confdefs.h <<EOF
+#define $ac_tr_hdr 1
+EOF
+ 
+else
+  echo "$ac_t""no" 1>&6
+fi
+done
+
+	echo $ac_n "checking for pthread_mutex_lock""... $ac_c" 1>&6
+echo "configure:1901: checking for pthread_mutex_lock" >&5
+if eval "test \"`echo '$''{'ac_cv_func_pthread_mutex_lock'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  cat > conftest.$ac_ext <<EOF
+#line 1906 "configure"
+#include "confdefs.h"
+/* System header to define __stub macros and hopefully few prototypes,
+    which can conflict with char pthread_mutex_lock(); below.  */
+#include <assert.h>
+/* Override any gcc2 internal prototype to avoid an error.  */
+/* We use char because int might match the return type of a gcc2
+    builtin and then its argument prototype would still apply.  */
+char pthread_mutex_lock();
+
+int main() {
+
+/* The GNU C library defines this for functions which it implements
+    to always fail with ENOSYS.  Some functions are actually named
+    something starting with __ and the normal name is an alias.  */
+#if defined (__stub_pthread_mutex_lock) || defined (__stub___pthread_mutex_lock)
+choke me
+#else
+pthread_mutex_lock();
+#endif
+
+; return 0; }
+EOF
+if { (eval echo configure:1929: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+  rm -rf conftest*
+  eval "ac_cv_func_pthread_mutex_lock=yes"
+else
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -rf conftest*
+  eval "ac_cv_func_pthread_mutex_lock=no"
+fi
+rm -f conftest*
+fi
+
+if eval "test \"`echo '$ac_cv_func_'pthread_mutex_lock`\" = yes"; then
+  echo "$ac_t""yes" 1>&6
+  :
+else
+  echo "$ac_t""no" 1>&6
+fi
+
+	if test "$ac_cv_func_pthread_mutex_lock" = "no"; then
+		echo $ac_n "checking for main in -lpthread""... $ac_c" 1>&6
+echo "configure:1950: checking for main in -lpthread" >&5
+ac_lib_var=`echo pthread'_'main | sed 'y%./+-%__p_%'`
+if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  ac_save_LIBS="$LIBS"
+LIBS="-lpthread  $LIBS"
+cat > conftest.$ac_ext <<EOF
+#line 1958 "configure"
+#include "confdefs.h"
+
+int main() {
+main()
+; return 0; }
+EOF
+if { (eval echo configure:1965: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+  rm -rf conftest*
+  eval "ac_cv_lib_$ac_lib_var=yes"
+else
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -rf conftest*
+  eval "ac_cv_lib_$ac_lib_var=no"
+fi
+rm -f conftest*
+LIBS="$ac_save_LIBS"
+
+fi
+if eval "test \"`echo '$ac_cv_lib_'$ac_lib_var`\" = yes"; then
+  echo "$ac_t""yes" 1>&6
+    ac_tr_lib=HAVE_LIB`echo pthread | sed -e 's/[^a-zA-Z0-9_]/_/g' \
+    -e 'y/abcdefghijklmnopqrstuvwxyz/ABCDEFGHIJKLMNOPQRSTUVWXYZ/'`
+  cat >> confdefs.h <<EOF
+#define $ac_tr_lib 1
+EOF
+
+  LIBS="-lpthread $LIBS"
+
+else
+  echo "$ac_t""no" 1>&6
+fi
+
+	fi
+	cat >> confdefs.h <<\EOF
+#define _REENTRANT 1
+EOF
+
+fi
+SUBDIRS_VAR="util odr $ASNMODULE $ILLMODULE zutil comstack ccl tab retrieval server include lib client ztest $DOCMODULE"
+
+trap '' 1 2 15
+cat > confcache <<\EOF
+# This file is a shell script that caches the results of configure
+# tests run on this system so they can be shared between configure
+# scripts and configure runs.  It is not useful on other systems.
+# If it contains results you don't want to keep, you may remove or edit it.
+#
+# By default, configure uses ./config.cache as the cache file,
+# creating it if it does not exist already.  You can give configure
+# the --cache-file=FILE option to use a different cache file; that is
+# what configure does when it calls configure scripts in
+# subdirectories, so they share the cache.
+# Giving --cache-file=/dev/null disables caching, for debugging configure.
+# config.status only pays attention to the cache file if you give it the
+# --recheck option to rerun configure.
+#
+EOF
+# The following way of writing the cache mishandles newlines in values,
+# but we know of no workaround that is simple, portable, and efficient.
+# So, don't put newlines in cache variables' values.
+# Ultrix sh set writes to stderr and can't be redirected directly,
+# and sets the high bit in the cache file unless we assign to the vars.
+(set) 2>&1 |
+  case `(ac_space=' '; set | grep ac_space) 2>&1` in
+  *ac_space=\ *)
+    # `set' does not quote correctly, so add quotes (double-quote substitution
+    # turns \\\\ into \\, and sed turns \\ into \).
+    sed -n \
+      -e "s/'/'\\\\''/g" \
+      -e "s/^\\([a-zA-Z0-9_]*_cv_[a-zA-Z0-9_]*\\)=\\(.*\\)/\\1=\${\\1='\\2'}/p"
+    ;;
+  *)
+    # `set' quotes correctly as required by POSIX, so do not add quotes.
+    sed -n -e 's/^\([a-zA-Z0-9_]*_cv_[a-zA-Z0-9_]*\)=\(.*\)/\1=${\1=\2}/p'
+    ;;
+  esac >> confcache
+if cmp -s $cache_file confcache; then
+  :
+else
+  if test -w $cache_file; then
+    echo "updating cache $cache_file"
+    cat confcache > $cache_file
+  else
+    echo "not updating unwritable cache $cache_file"
+  fi
+fi
+rm -f confcache
+
+trap 'rm -fr conftest* confdefs* core core.* *.core $ac_clean_files; exit 1' 1 2 15
+
+test "x$prefix" = xNONE && prefix=$ac_default_prefix
+# Let make expand exec_prefix.
+test "x$exec_prefix" = xNONE && exec_prefix='${prefix}'
+
+# Any assignment to VPATH causes Sun make to only execute
+# the first set of double-colon rules, so remove it if not needed.
+# If there is a colon in the path, we need to keep it.
+if test "x$srcdir" = x.; then
+  ac_vpsub='/^[ 	]*VPATH[ 	]*=[^:]*$/d'
+fi
+
+trap 'rm -f $CONFIG_STATUS conftest*; exit 1' 1 2 15
+
+# Transform confdefs.h into DEFS.
+# Protect against shell expansion while executing Makefile rules.
+# Protect against Makefile macro expansion.
+cat > conftest.defs <<\EOF
+s%#define \([A-Za-z_][A-Za-z0-9_]*\) *\(.*\)%-D\1=\2%g
+s%[ 	`~#$^&*(){}\\|;'"<>?]%\\&%g
+s%\[%\\&%g
+s%\]%\\&%g
+s%\$%$$%g
+EOF
+DEFS=`sed -f conftest.defs confdefs.h | tr '\012' ' '`
+rm -f conftest.defs
+
+
+# Without the "./", some shells look in PATH for config.status.
+: ${CONFIG_STATUS=./config.status}
+
+echo creating $CONFIG_STATUS
+rm -f $CONFIG_STATUS
+cat > $CONFIG_STATUS <<EOF
+#! /bin/sh
+# Generated automatically by configure.
+# Run this file to recreate the current configuration.
+# This directory was configured as follows,
+# on host `(hostname || uname -n) 2>/dev/null | sed 1q`:
+#
+# $0 $ac_configure_args
+#
+# Compiler output produced by configure, useful for debugging
+# configure, is in ./config.log if it exists.
+
+ac_cs_usage="Usage: $CONFIG_STATUS [--recheck] [--version] [--help]"
+for ac_option
+do
+  case "\$ac_option" in
+  -recheck | --recheck | --rechec | --reche | --rech | --rec | --re | --r)
+    echo "running \${CONFIG_SHELL-/bin/sh} $0 $ac_configure_args --no-create --no-recursion"
+    exec \${CONFIG_SHELL-/bin/sh} $0 $ac_configure_args --no-create --no-recursion ;;
+  -version | --version | --versio | --versi | --vers | --ver | --ve | --v)
+    echo "$CONFIG_STATUS generated by autoconf version 2.13"
+    exit 0 ;;
+  -help | --help | --hel | --he | --h)
+    echo "\$ac_cs_usage"; exit 0 ;;
+  *) echo "\$ac_cs_usage"; exit 1 ;;
+  esac
+done
+
+ac_given_srcdir=$srcdir
+ac_given_INSTALL="$INSTALL"
+
+trap 'rm -fr `echo "Makefile util/Makefile odr/Makefile z39.50/Makefile asn/Makefile ill/Makefile zutil/Makefile comstack/Makefile ccl/Makefile tab/Makefile retrieval/Makefile server/Makefile include/Makefile include/yaz/Makefile lib/Makefile client/Makefile ztest/Makefile doc/Makefile" | sed "s/:[^ ]*//g"` conftest*; exit 1' 1 2 15
+EOF
+cat >> $CONFIG_STATUS <<EOF
+
+# Protect against being on the right side of a sed subst in config.status.
+sed 's/%@/@@/; s/@%/@@/; s/%g\$/@g/; /@g\$/s/[\\\\&%]/\\\\&/g;
+ s/@@/%@/; s/@@/@%/; s/@g\$/%g/' > conftest.subs <<\\CEOF
+$ac_vpsub
+$extrasub
+s%@SHELL@%$SHELL%g
+s%@CFLAGS@%$CFLAGS%g
+s%@CPPFLAGS@%$CPPFLAGS%g
+s%@CXXFLAGS@%$CXXFLAGS%g
+s%@FFLAGS@%$FFLAGS%g
+s%@DEFS@%$DEFS%g
+s%@LDFLAGS@%$LDFLAGS%g
+s%@LIBS@%$LIBS%g
+s%@exec_prefix@%$exec_prefix%g
+s%@prefix@%$prefix%g
+s%@program_transform_name@%$program_transform_name%g
+s%@bindir@%$bindir%g
+s%@sbindir@%$sbindir%g
+s%@libexecdir@%$libexecdir%g
+s%@datadir@%$datadir%g
+s%@sysconfdir@%$sysconfdir%g
+s%@sharedstatedir@%$sharedstatedir%g
+s%@localstatedir@%$localstatedir%g
+s%@libdir@%$libdir%g
+s%@includedir@%$includedir%g
+s%@oldincludedir@%$oldincludedir%g
+s%@infodir@%$infodir%g
+s%@mandir@%$mandir%g
+s%@INSTALL_PROGRAM@%$INSTALL_PROGRAM%g
+s%@INSTALL_SCRIPT@%$INSTALL_SCRIPT%g
+s%@INSTALL_DATA@%$INSTALL_DATA%g
+s%@PACKAGE@%$PACKAGE%g
+s%@VERSION@%$VERSION%g
+s%@ACLOCAL@%$ACLOCAL%g
+s%@AUTOCONF@%$AUTOCONF%g
+s%@AUTOMAKE@%$AUTOMAKE%g
+s%@AUTOHEADER@%$AUTOHEADER%g
+s%@MAKEINFO@%$MAKEINFO%g
+s%@SET_MAKE@%$SET_MAKE%g
+s%@CC@%$CC%g
+s%@CPP@%$CPP%g
+s%@RANLIB@%$RANLIB%g
+s%@have_sgml2txt@%$have_sgml2txt%g
+s%@have_sgml2latex@%$have_sgml2latex%g
+s%@have_sgml2html@%$have_sgml2html%g
+s%@ASNMODULE@%$ASNMODULE%g
+s%@ILLMODULE@%$ILLMODULE%g
+s%@ILLLIB@%$ILLLIB%g
+s%@SUBDIRS_VAR@%$SUBDIRS_VAR%g
+
+CEOF
+EOF
+
+cat >> $CONFIG_STATUS <<\EOF
+
+# Split the substitutions into bite-sized pieces for seds with
+# small command number limits, like on Digital OSF/1 and HP-UX.
+ac_max_sed_cmds=90 # Maximum number of lines to put in a sed script.
+ac_file=1 # Number of current file.
+ac_beg=1 # First line for current file.
+ac_end=$ac_max_sed_cmds # Line after last line for current file.
+ac_more_lines=:
+ac_sed_cmds=""
+while $ac_more_lines; do
+  if test $ac_beg -gt 1; then
+    sed "1,${ac_beg}d; ${ac_end}q" conftest.subs > conftest.s$ac_file
+  else
+    sed "${ac_end}q" conftest.subs > conftest.s$ac_file
+  fi
+  if test ! -s conftest.s$ac_file; then
+    ac_more_lines=false
+    rm -f conftest.s$ac_file
+  else
+    if test -z "$ac_sed_cmds"; then
+      ac_sed_cmds="sed -f conftest.s$ac_file"
+    else
+      ac_sed_cmds="$ac_sed_cmds | sed -f conftest.s$ac_file"
+    fi
+    ac_file=`expr $ac_file + 1`
+    ac_beg=$ac_end
+    ac_end=`expr $ac_end + $ac_max_sed_cmds`
+  fi
+done
+if test -z "$ac_sed_cmds"; then
+  ac_sed_cmds=cat
+fi
+EOF
+
+cat >> $CONFIG_STATUS <<EOF
+
+CONFIG_FILES=\${CONFIG_FILES-"Makefile util/Makefile odr/Makefile z39.50/Makefile asn/Makefile ill/Makefile zutil/Makefile comstack/Makefile ccl/Makefile tab/Makefile retrieval/Makefile server/Makefile include/Makefile include/yaz/Makefile lib/Makefile client/Makefile ztest/Makefile doc/Makefile"}
+EOF
+cat >> $CONFIG_STATUS <<\EOF
+for ac_file in .. $CONFIG_FILES; do if test "x$ac_file" != x..; then
+  # Support "outfile[:infile[:infile...]]", defaulting infile="outfile.in".
+  case "$ac_file" in
+  *:*) ac_file_in=`echo "$ac_file"|sed 's%[^:]*:%%'`
+       ac_file=`echo "$ac_file"|sed 's%:.*%%'` ;;
+  *) ac_file_in="${ac_file}.in" ;;
+  esac
+
+  # Adjust a relative srcdir, top_srcdir, and INSTALL for subdirectories.
+
+  # Remove last slash and all that follows it.  Not all systems have dirname.
+  ac_dir=`echo $ac_file|sed 's%/[^/][^/]*$%%'`
+  if test "$ac_dir" != "$ac_file" && test "$ac_dir" != .; then
+    # The file is in a subdirectory.
+    test ! -d "$ac_dir" && mkdir "$ac_dir"
+    ac_dir_suffix="/`echo $ac_dir|sed 's%^\./%%'`"
+    # A "../" for each directory in $ac_dir_suffix.
+    ac_dots=`echo $ac_dir_suffix|sed 's%/[^/]*%../%g'`
+  else
+    ac_dir_suffix= ac_dots=
+  fi
+
+  case "$ac_given_srcdir" in
+  .)  srcdir=.
+      if test -z "$ac_dots"; then top_srcdir=.
+      else top_srcdir=`echo $ac_dots|sed 's%/$%%'`; fi ;;
+  /*) srcdir="$ac_given_srcdir$ac_dir_suffix"; top_srcdir="$ac_given_srcdir" ;;
+  *) # Relative path.
+    srcdir="$ac_dots$ac_given_srcdir$ac_dir_suffix"
+    top_srcdir="$ac_dots$ac_given_srcdir" ;;
+  esac
+
+  case "$ac_given_INSTALL" in
+  [/$]*) INSTALL="$ac_given_INSTALL" ;;
+  *) INSTALL="$ac_dots$ac_given_INSTALL" ;;
+  esac
+
+  echo creating "$ac_file"
+  rm -f "$ac_file"
+  configure_input="Generated automatically from `echo $ac_file_in|sed 's%.*/%%'` by configure."
+  case "$ac_file" in
+  *Makefile*) ac_comsub="1i\\
+# $configure_input" ;;
+  *) ac_comsub= ;;
+  esac
+
+  ac_file_inputs=`echo $ac_file_in|sed -e "s%^%$ac_given_srcdir/%" -e "s%:% $ac_given_srcdir/%g"`
+  sed -e "$ac_comsub
+s%@configure_input@%$configure_input%g
+s%@srcdir@%$srcdir%g
+s%@top_srcdir@%$top_srcdir%g
+s%@INSTALL@%$INSTALL%g
+" $ac_file_inputs | (eval "$ac_sed_cmds") > $ac_file
+fi; done
+rm -f conftest.s*
+
+EOF
+cat >> $CONFIG_STATUS <<EOF
+
+EOF
+cat >> $CONFIG_STATUS <<\EOF
+
+exit 0
+EOF
+chmod +x $CONFIG_STATUS
+rm -fr confdefs* $ac_clean_files
+test "$no_create" = yes || ${CONFIG_SHELL-/bin/sh} $CONFIG_STATUS || exit 1
+
Index: /main/tags/2.25/gsdl/packages/yaz/configure.in
===================================================================
--- /main/tags/2.25/gsdl/packages/yaz/configure.in	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/yaz/configure.in	(revision 21064)
@@ -0,0 +1,106 @@
+dnl YAZ Toolkit
+dnl (c) Index Data 1994-2000
+dnl See the file LICENSE for details.
+AC_INIT(include/yaz/yaz-version.h)
+AM_INIT_AUTOMAKE(yaz, 1.6)
+dnl
+dnl ------ Checking programs
+AC_PROG_CC
+AC_PROG_CPP
+AC_PROG_INSTALL
+AC_PROG_RANLIB
+AC_CHECK_PROGS(have_sgml2txt,sgml2txt,no)
+AC_CHECK_PROGS(have_sgml2latex,sgml2latex,no)
+AC_CHECK_PROGS(have_sgml2html,sgml2html,no)
+if test "$have_sgml2txt" = "no" -o "$have_sgml2latex" = "no" -o "$have_sgml2html" = "no"; then
+	DOCMODULE=""
+else
+	DOCMODULE="doc"
+fi
+dnl 
+dnl ----- yaz-comp: The Yaz Compiler
+AC_SUBST(ASNMODULE)
+AC_SUBST(ILLMODULE)
+AC_SUBST(ILLLIB)
+AC_ARG_ENABLE(comp,[  --disable-comp          use old encoders, i.e. disable the YAZ ASN.1 Compiler], , enable_comp=yes)
+if test "$enable_comp" = "yes"; then
+	ASNMODULE="z39.50"
+	ILLMODULE="ill"
+	ILLLIB=../ill/libill.a
+	ASN_MAKEFILES="z39.50/Makefile ill/Makefile"
+	cp -f include/yaz/z-proto.h include/yaz/proto.h
+else
+	ILLMODULE=""
+	ASNMODULE=asn
+	ILLLIB=""
+	ASN_MAKEFILES="asn/Makefile"
+	cp -f include/yaz/prt-proto.h include/yaz/proto.h
+fi
+dnl
+dnl ----- Sockets
+checkBoth=0
+AC_CHECK_FUNC(connect)
+if test "$ac_cv_func_connect" = "no"; then
+	AC_CHECK_LIB(socket, main, LIBS="$LIBS -lsocket", checkBoth=1)
+fi
+if test "$checkBoth" = "1"; then
+	oldLibs=$LIBS
+	LIBS="$LIBS -lsocket -lnsl"
+	AC_CHECK_FUNC(accept, , [LIBS=$oldLibs])
+fi
+AC_CHECK_FUNC(gethostbyname, , AC_CHECK_LIB(nsl, main, [LIBS="$LIBS -lnsl"]))
+dnl
+dnl ------ GNU Readline
+AC_CHECK_LIB(readline, readline, [LIBS="$LIBS -lreadline"])
+if test "$ac_cv_lib_readline_readline" = "no"; then
+	AC_CHECK_LIB(readline, readline, [LIBS="$LIBS -lreadline -ltermcap"])
+fi
+AC_CHECK_LIB(history, add_history, [LIBS="$LIBS -lhistory"])
+if test "$ac_cv_lib_readline_readline" = "yes"; then
+	AC_CHECK_HEADERS(readline/readline.h readline/history.h)
+fi
+dnl
+dnl ------ tcpd
+AC_ARG_ENABLE(tcpd,[  --enable-tcpd           enable TCP wrapper for server if available])
+if test "$enable_tcpd" = "yes"; then
+	AC_MSG_CHECKING(for working tcpd.h)
+	oldLibs=$LIBS
+	LIBS="$LIBS -lwrap -lnsl"
+	AC_TRY_LINK([#include <syslog.h>
+	#include <tcpd.h>
+	int allow_severity = LOG_INFO;
+	int deny_severity = LOG_WARNING;],
+	[struct request_info request_info; int i;
+	i = hosts_access(&request_info);],tcpd_ok=1, tcpd_ok=0)
+	if test "$tcpd_ok" = "0"; then
+		AC_MSG_RESULT(no)
+		LIBS=$oldLibs
+	else
+		AC_MSG_RESULT(yes)
+		AC_DEFINE(HAVE_TCPD_H)
+	fi
+fi
+dnl
+dnl ------ Headers
+AC_STDC_HEADERS
+if test "$ac_cv_header_stdc" = "no"; then
+	AC_MSG_WARN(Your system doesn't seem to support ANSI C)
+fi
+dnl
+dnl ------ Threads
+AC_ARG_ENABLE(threads, [  --enable-threads        enable threads if available])
+if test "$enable_threads" = "yes"; then
+	AC_CHECK_HEADERS(pthread.h threads.h)
+	AC_CHECK_FUNC(pthread_mutex_lock)
+	if test "$ac_cv_func_pthread_mutex_lock" = "no"; then
+		AC_CHECK_LIB(pthread, main)
+	fi
+	AC_DEFINE(_REENTRANT)
+fi
+dnl
+SUBDIRS_VAR="util odr $ASNMODULE $ILLMODULE zutil comstack ccl tab retrieval server include lib client ztest $DOCMODULE"
+AC_SUBST(SUBDIRS_VAR)
+dnl
+dnl ------ Makefiles
+dnl
+AC_OUTPUT(Makefile util/Makefile odr/Makefile z39.50/Makefile asn/Makefile ill/Makefile zutil/Makefile comstack/Makefile ccl/Makefile tab/Makefile retrieval/Makefile server/Makefile include/Makefile include/yaz/Makefile lib/Makefile client/Makefile ztest/Makefile doc/Makefile)
Index: /main/tags/2.25/gsdl/packages/yaz/doc/Makefile.am
===================================================================
--- /main/tags/2.25/gsdl/packages/yaz/doc/Makefile.am	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/yaz/doc/Makefile.am	(revision 21064)
@@ -0,0 +1,28 @@
+## $Id$
+
+docdir=$(pkgdatadir)/doc
+
+doc_DATA = \
+ yaz.sgml yaz.txt yaz.ps profiles.sgml profiles.txt profiles.ps yaz.html \
+ yaz-1.html yaz-2.html yaz-3.html yaz-4.html yaz-5.html \
+ yaz-6.html yaz-7.html yaz-8.html yaz-9.html
+
+EXTRA_DIST = \
+ yaz.sgml yaz.txt yaz.ps profiles.sgml profiles.txt profiles.ps yaz.html \
+ yaz-1.html yaz-2.html yaz-3.html yaz-4.html yaz-5.html \
+ yaz-6.html yaz-7.html yaz-8.html yaz-9.html
+
+yaz.txt: yaz.sgml
+	sgml2txt -f yaz.sgml
+
+yaz.ps: yaz.sgml
+	sgml2latex -o ps yaz.sgml
+
+profiles.txt: profiles.sgml
+	sgml2txt -f profiles.sgml
+
+profiles.ps: profiles.sgml
+	sgml2latex -o ps profiles.sgml
+
+yaz.html: yaz.sgml
+	sgml2html yaz.sgml
Index: /main/tags/2.25/gsdl/packages/yaz/doc/Makefile.in
===================================================================
--- /main/tags/2.25/gsdl/packages/yaz/doc/Makefile.in	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/yaz/doc/Makefile.in	(revision 21064)
@@ -0,0 +1,218 @@
+# Makefile.in generated automatically by automake 1.4 from Makefile.am
+
+# Copyright (C) 1994, 1995-8, 1999 Free Software Foundation, Inc.
+# This Makefile.in is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
+# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE.
+
+
+SHELL = @SHELL@
+
+srcdir = @srcdir@
+top_srcdir = @top_srcdir@
+VPATH = @srcdir@
+prefix = @prefix@
+exec_prefix = @exec_prefix@
+
+bindir = @bindir@
+sbindir = @sbindir@
+libexecdir = @libexecdir@
+datadir = @datadir@
+sysconfdir = @sysconfdir@
+sharedstatedir = @sharedstatedir@
+localstatedir = @localstatedir@
+libdir = @libdir@
+infodir = @infodir@
+mandir = @mandir@
+includedir = @includedir@
+oldincludedir = /usr/include
+
+DESTDIR =
+
+pkgdatadir = $(datadir)/@PACKAGE@
+pkglibdir = $(libdir)/@PACKAGE@
+pkgincludedir = $(includedir)/@PACKAGE@
+
+top_builddir = ..
+
+ACLOCAL = @ACLOCAL@
+AUTOCONF = @AUTOCONF@
+AUTOMAKE = @AUTOMAKE@
+AUTOHEADER = @AUTOHEADER@
+
+INSTALL = @INSTALL@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@ $(AM_INSTALL_PROGRAM_FLAGS)
+INSTALL_DATA = @INSTALL_DATA@
+INSTALL_SCRIPT = @INSTALL_SCRIPT@
+transform = @program_transform_name@
+
+NORMAL_INSTALL = :
+PRE_INSTALL = :
+POST_INSTALL = :
+NORMAL_UNINSTALL = :
+PRE_UNINSTALL = :
+POST_UNINSTALL = :
+ASNMODULE = @ASNMODULE@
+CC = @CC@
+CPP = @CPP@
+ILLLIB = @ILLLIB@
+ILLMODULE = @ILLMODULE@
+MAKEINFO = @MAKEINFO@
+PACKAGE = @PACKAGE@
+RANLIB = @RANLIB@
+SUBDIRS_VAR = @SUBDIRS_VAR@
+VERSION = @VERSION@
+have_sgml2html = @have_sgml2html@
+have_sgml2latex = @have_sgml2latex@
+have_sgml2txt = @have_sgml2txt@
+
+docdir = $(pkgdatadir)/doc
+
+doc_DATA =   yaz.sgml yaz.txt yaz.ps profiles.sgml profiles.txt profiles.ps yaz.html  yaz-1.html yaz-2.html yaz-3.html yaz-4.html yaz-5.html  yaz-6.html yaz-7.html yaz-8.html yaz-9.html
+
+
+EXTRA_DIST =   yaz.sgml yaz.txt yaz.ps profiles.sgml profiles.txt profiles.ps yaz.html  yaz-1.html yaz-2.html yaz-3.html yaz-4.html yaz-5.html  yaz-6.html yaz-7.html yaz-8.html yaz-9.html
+
+mkinstalldirs = $(SHELL) $(top_srcdir)/mkinstalldirs
+CONFIG_CLEAN_FILES = 
+DATA =  $(doc_DATA)
+
+DIST_COMMON =  Makefile.am Makefile.in
+
+
+DISTFILES = $(DIST_COMMON) $(SOURCES) $(HEADERS) $(TEXINFOS) $(EXTRA_DIST)
+
+TAR = gtar
+GZIP_ENV = --best
+all: all-redirect
+.SUFFIXES:
+$(srcdir)/Makefile.in: Makefile.am $(top_srcdir)/configure.in $(ACLOCAL_M4) 
+	cd $(top_srcdir) && $(AUTOMAKE) --gnu --include-deps doc/Makefile
+
+Makefile: $(srcdir)/Makefile.in  $(top_builddir)/config.status
+	cd $(top_builddir) \
+	  && CONFIG_FILES=$(subdir)/$@ CONFIG_HEADERS= $(SHELL) ./config.status
+
+
+install-docDATA: $(doc_DATA)
+	@$(NORMAL_INSTALL)
+	$(mkinstalldirs) $(DESTDIR)$(docdir)
+	@list='$(doc_DATA)'; for p in $$list; do \
+	  if test -f $(srcdir)/$$p; then \
+	    echo " $(INSTALL_DATA) $(srcdir)/$$p $(DESTDIR)$(docdir)/$$p"; \
+	    $(INSTALL_DATA) $(srcdir)/$$p $(DESTDIR)$(docdir)/$$p; \
+	  else if test -f $$p; then \
+	    echo " $(INSTALL_DATA) $$p $(DESTDIR)$(docdir)/$$p"; \
+	    $(INSTALL_DATA) $$p $(DESTDIR)$(docdir)/$$p; \
+	  fi; fi; \
+	done
+
+uninstall-docDATA:
+	@$(NORMAL_UNINSTALL)
+	list='$(doc_DATA)'; for p in $$list; do \
+	  rm -f $(DESTDIR)$(docdir)/$$p; \
+	done
+tags: TAGS
+TAGS:
+
+
+distdir = $(top_builddir)/$(PACKAGE)-$(VERSION)/$(subdir)
+
+subdir = doc
+
+distdir: $(DISTFILES)
+	@for file in $(DISTFILES); do \
+	  d=$(srcdir); \
+	  if test -d $$d/$$file; then \
+	    cp -pr $$/$$file $(distdir)/$$file; \
+	  else \
+	    test -f $(distdir)/$$file \
+	    || ln $$d/$$file $(distdir)/$$file 2> /dev/null \
+	    || cp -p $$d/$$file $(distdir)/$$file || :; \
+	  fi; \
+	done
+info-am:
+info: info-am
+dvi-am:
+dvi: dvi-am
+check-am: all-am
+check: check-am
+installcheck-am:
+installcheck: installcheck-am
+install-exec-am:
+install-exec: install-exec-am
+
+install-data-am: install-docDATA
+install-data: install-data-am
+
+install-am: all-am
+	@$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
+install: install-am
+uninstall-am: uninstall-docDATA
+uninstall: uninstall-am
+all-am: Makefile $(DATA)
+all-redirect: all-am
+install-strip:
+	$(MAKE) $(AM_MAKEFLAGS) AM_INSTALL_PROGRAM_FLAGS=-s install
+installdirs:
+	$(mkinstalldirs)  $(DESTDIR)$(docdir)
+
+
+mostlyclean-generic:
+
+clean-generic:
+
+distclean-generic:
+	-rm -f Makefile $(CONFIG_CLEAN_FILES)
+	-rm -f config.cache config.log stamp-h stamp-h[0-9]*
+
+maintainer-clean-generic:
+mostlyclean-am:  mostlyclean-generic
+
+mostlyclean: mostlyclean-am
+
+clean-am:  clean-generic mostlyclean-am
+
+clean: clean-am
+
+distclean-am:  distclean-generic clean-am
+
+distclean: distclean-am
+
+maintainer-clean-am:  maintainer-clean-generic distclean-am
+	@echo "This command is intended for maintainers to use;"
+	@echo "it deletes files that may require special tools to rebuild."
+
+maintainer-clean: maintainer-clean-am
+
+.PHONY: uninstall-docDATA install-docDATA tags distdir info-am info \
+dvi-am dvi check check-am installcheck-am installcheck install-exec-am \
+install-exec install-data-am install-data install-am install \
+uninstall-am uninstall all-redirect all-am all installdirs \
+mostlyclean-generic distclean-generic clean-generic \
+maintainer-clean-generic clean mostlyclean distclean maintainer-clean
+
+
+yaz.txt: yaz.sgml
+	sgml2txt -f yaz.sgml
+
+yaz.ps: yaz.sgml
+	sgml2latex -o ps yaz.sgml
+
+profiles.txt: profiles.sgml
+	sgml2txt -f profiles.sgml
+
+profiles.ps: profiles.sgml
+	sgml2latex -o ps profiles.sgml
+
+yaz.html: yaz.sgml
+	sgml2html yaz.sgml
+
+# Tell versions [3.59,3.63) of GNU make to not export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:
Index: /main/tags/2.25/gsdl/packages/yaz/doc/profiles.sgml
===================================================================
--- /main/tags/2.25/gsdl/packages/yaz/doc/profiles.sgml	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/yaz/doc/profiles.sgml	(revision 21064)
@@ -0,0 +1,666 @@
+<!doctype linuxdoc system>
+<article>
+<title>Specifying and Using Application (Database) Profiles
+<author>Index Data, <tt/info@indexdata.dk/
+<date>$Revision$
+<abstract>
+YAZ includes a subsystem to manage complex database records, driven
+by a set of configuration tables that reflect a given profile.
+Multiple database profiles can coexeist in the same server, or even
+the same database. The record management system is responsible for
+associating a given record with a specific profile, and processing it
+accordingly. This document describes the various file formats for data
+and configuration files which are used by the module.
+</abstract>
+
+<toc>
+
+<sect>Warnings
+
+<p>
+<itemize>
+<item>The subsystem descibed herein is under development. Not
+everything may work exactly as decribed, and details of the interface
+may change as the module matures.
+
+<item>The exact workings of the subsystem may depend on the
+application in which it is used. This document focuses on the use of
+the module in the <bf/Zebra/ information server which is distributed by Index
+Data as an independent package.
+</itemize>
+
+<sect>Introduction
+
+<p>
+The retrieval facilities of Z39.50 are extremely flexible and powerful.
+They allow any level of structuring of database records. They allow
+controlled re-use of attribute sets (for searching) and tag sets (for
+retrieval) between application profiles; they allow precise selection
+of the desired sub-elements of a database record; they allow different
+variants of a given data element to be represented and selected in a
+structured way; and finally they allow the exchange of any type and
+amount of data to be represented in a single database record.
+
+These powerful retrieval facilities are a recent addition to the
+protocol, and along with the flexible searching facilities, they make
+the protocol an extremely capable tool for precise, structured
+access to information systems. The retrieval facilities add new
+levels of flexibility and control to the protocol, which add to its
+value outside of its traditional domain of the library systems world.
+
+The new facilities, however, also add new complexity to the protocol,
+which is already troubles by a too-steep learning curve. We have seen
+many good projects severely hindered or even thwarted by the sheer
+complexity of implementing the Z39.50 protocol.
+
+At the same time, we feel that the most complex and powerful
+facilities of the protocol (Explain, structured retrieval, etc.), are
+also what the protocol needs to become more widespread, and to fulfill
+what we perceive to be its most noble potential: To provide
+everybody with standardised, well-structured access to the
+information resources of the world.
+
+The purpose of <bf/YAZ/, then, and of this module as well, is to
+<it/simplify/ the use of the protocol for programmers and
+administrators, by providing simple APIs and configuration systems to
+access the functionality of the protocol. The <bf/Retrieval/ module
+deals specifically with the advanced retrieval functions which were
+added to the protocol with version 3, or Z39.50-1994.
+
+<sect>Overview
+
+<sect1>External Data (record) Representation
+
+<p>
+The <bf/Retrieval/ module will eventually support a wide range of
+input formats, ranging from MARC data to USENET news archives. This
+section introduces what we think of as the <it/canonical/ format - the
+one that gives the most general access to the various elements of the
+retrieval functionality.
+
+The basic model presented by the Z39.50 retrieval system is that of a
+recursively defined tree structure, containing a list of tagged elements,
+which may in turn contain either data or more lists of tagged elements, and
+so forth.
+
+We elect to represent this structuring externally by using an
+&dquot;SGML-like&dquot; syntax. The <it/internal/ representation will
+be discussed later.
+
+Consider a record describing an information resource (such a record is
+sometimes known as a <it/locator record/). It might contain a field
+describing the distributor of the information resource, which might in
+turn be partitioned into various fields providing details about the
+distributor, like this:
+
+<tscreen><verb>
+<Distributor>
+    <Name> USGS/WRD &etago;Name>
+    <Organization> USGS/WRD &etago;Organization>
+    <Street-Address>
+	U.S. GEOLOGICAL SURVEY, 505 MARQUETTE, NW
+    &etago;Street-Address>
+    <City> ALBUQUERQUE &etago;City>
+    <State> NM &etago;State>
+    <Zip-Code> 87102 &etago;Zip-Code>
+    <Country> USA &etago;Country>
+    <Telephone> (505) 766-5560 &etago;Telephone>
+&etago;Distributor>
+</verb></tscreen>
+
+This is how data that the retrieval module reads from an input file
+might look.
+
+Depending on the database profile that is being used, it is likely
+that the data won't look like this when it's transmitted from the
+server to the client, however. Typically, the client will prefer to
+receive the data in a more rigid syntax, such as USMARC or GRS-1. To
+save transmission time and avoid ambiguities of language, the
+individual tags or field names, above, might be translated into
+numbers which are known by both the client and the server (by
+referring to a tag set).
+
+The retrieval module supports various types of conversions that might
+be carried out by the server based on requests from the client. To do
+this, it needs a set of configuration files to describe the
+application profile that the given record adheres to.
+
+<it>
+CAUTION: Because the tables described below serve the dual purpose of
+representing an external application profile and an internal database
+profile, the terminology and structuring used will sometimes be
+somewhat different from the one suggested in the the Z39.50-1995.
+</it>
+
+<sect1>The Abstract Syntax
+
+<p>
+The abstract syntax definition (ARS) is the focal point of the
+application profile description. For a given profile, it may state any
+or all of the following:
+
+<itemize>
+<item>The object identifier of the database schema associated with the
+profile, so that it can be referred to by the client.
+
+<item>The attribute set (which can possibly be a compound of multiple
+sets) which applies in the profile. This is used when indexing and
+searching the records belonging to the given profile.
+
+<item>The Tag set (again, this can consist of several different sets).
+This is used when reading the records from a file, to recognize the
+different tags, and when transmitting the record to the client -
+mapping the tags to their numerical representation, if they are
+known.
+
+<item>The variant set which is used in the profile. This provides a
+vocabulary for specifying the <it/forms/ of data that appear inside
+the records.
+
+<item>Element set names, which are a shorthand way for the client to
+ask for a subset of the data elements contained in a record. Element
+set names, in the retrieval module, are mapped to <it/element
+specifications/, which contain information equivalent to the
+<it/Espec-1/ syntax of Z39.50.
+
+<item>Map tables, which may specify mappings to <it/other/ database
+profiles, if desired.
+
+<item>Possibly, a set of rules describing the mapping of elements to a
+MARC representation.
+
+<item>A list of element description (this is the actual ARS of the
+profile), which lists the ways in which the various tags can be used
+and organized hierarchically.
+</itemize>
+
+Several of the entries above simply refer to other files, which describe the
+given objects.
+
+<sect>The Configuration Files
+
+<p>
+This section describes the syntax and use of the various tables which
+are used by the retrieval module.
+
+The number of different file types may appear daunting at first, but
+each type corresponds fairly clearly to a single aspect of the Z39.50
+retrieval facilities. Further, the average database administrator
+who's simply reusing an existing profile for which tables already
+exist, shouldn't have to worry too much about these tables.
+
+<sect1>The Abstract Syntax (.abs) Files
+
+<p>
+The name of this file type is slightly misleading, since, apart from
+the actual abstract syntax of the profile, it also includes most of
+the other definitions that go into a database profile.
+
+When a record in the canonical, SGML-like format is read from a file
+or from the database, the first tag of the file should reference the
+profile that governs the layout of the record. If the first tag of the
+record is <tt>&lt;gils&gt;</tt>, the system will look for the profile
+definition in the file <tt/gils.abs/. Profile definitions are cached,
+so they only have to be read once during the lifespan of the current
+process.
+
+The file may contain the following directives:
+
+<descrip>
+<tag>name <it/symbolic-name/</tag> This provides a shorthand name or
+description for the profile. Mostly useful for diagnostic purposes.
+
+<tag>reference <it/OID-name/</tag> The reference name of the OID for
+the profile. The reference names can be found in the <bf/util/
+module of <bf/YAZ/.
+
+<tag>attset <it/filename/</tag> The attribute set that is used for
+indexing and searching records belonging to this profile.
+
+<tag>tagset <it/filename/</tag> The tag set (if any) that describe
+that fields of the records.
+
+<tag>varset <it/filename/</tag> The variant set used in the profile.
+
+<tag>maptab <it/filename/</tag> (repeatable) This points to a
+conversion table that might be used if the client asks for the record
+in a different schema from the native one.
+
+<tag>marc <it/filename/</tag> Points to a file containing parameters
+for representing the record contents in the ISO2709 syntax. Read the
+description of the MARC representation facility below.
+
+<tag>esetname <it/name filename/</tag> (repeatable) Associates the
+given element set name with an element selection file. If an (@) is
+given in place of the filename, this corresponds to a null mapping for
+the given element set name.
+
+<tag>elm <it/path name attribute/</tag> (repeatable) Adds an element
+to the abstract record syntax of the schema. The <it/path/ follows the
+syntax which is suggested by the Z39.50 document - that is, a sequence
+of tags separated by slashes (/). Each tag is given as a
+comma-separated pair of tag type and -value surrounded by parenthesis.
+The <it/name/ is the name of the element, and the <it/attribute/
+specifies what attribute to use when indexing the element. A ! in
+place of the attribute name is equivalent to specifying an attribute
+name identical to the element name. A - in place of the attribute name
+specifies that no indexing is to take place for the given element.
+</descrip>
+
+<it>
+NOTE: The mechanism for controlling indexing is inadequate for
+complex databases, and will probably be moved into a separate
+configuration table eventually.
+</it>
+
+The following is an excerpt from the abstract syntax file for the GILS
+profile.
+
+<tscreen><verb>
+name gils
+reference GILS-schema
+attset gils.att
+tagset gils.tag
+varset var1.var
+
+maptab gils-usmarc.map
+
+# Element set names
+
+esetname VARIANT gils-variant.est  # for WAIS-compliance
+esetname B gils-b.est
+esetname G gils-g.est
+esetname W gils-b.est
+esetname F @
+
+elm (1,10)              rank                        -
+elm (1,12)              url                         -
+elm (1,14)              localControlNumber     Local-number
+elm (1,16)              dateOfLastModification Date/time-last-modified
+elm (2,1)               Title                       !
+elm (4,1)               controlIdentifier      Identifier-standard
+elm (2,6)               abstract               Abstract
+elm (4,51)              purpose                     !
+elm (4,52)              originator                  - 
+elm (4,53)              accessConstraints           !
+elm (4,54)              useConstraints              !
+elm (4,70)              availability                -
+elm (4,70)/(4,90)       distributor                 -
+elm (4,70)/(4,90)/(2,7) distributorName             !
+elm (4,70)/(4,90)/(2,10 distributorOrganization     !
+elm (4,70)/(4,90)/(4,2) distributorStreetAddress    !
+elm (4,70)/(4,90)/(4,3) distributorCity             !
+</verb></tscreen>
+
+<sect1>The Attribute Set (.att) Files
+
+<p>
+This file type describes the <bf/Use/ elements of an attribute set.
+It contains the following directives. 
+
+<descrip>
+
+<tag>name <it/symbolic-name/</tag> This provides a shorthand name or
+description for the attribute set. Mostly useful for diagnostic purposes.
+
+<tag>reference <it/OID-name/</tag> The reference name of the OID for
+the attribute set. The reference names can be found in the <bf/util/
+module of <bf/YAZ/.
+
+<tag>ordinal <it/integer/</tag> This value will be used to represent the
+attribute set in the index. Care should be taken that each attribute
+set has a unique ordinal value.
+
+<tag>include <it/filename/</tag> This directive, which can be
+repeated, is used to include another attribute set as a part of the
+current one. This is used when a new attribute set is defined as an
+extension to another set. For instance, many new attribute sets are
+defined as extensions to the <bf/bib-1/ set. This is an important
+feature of the retrieval system of Z39.50, as it ensures the highest
+possible level of interoperability, as those access points of your
+database which are derived from the external set (say, bib-1) can be used
+even by clients who are unaware of the new set.
+
+<tag>att <it/att-value att-name &lsqb;local-value&rsqb;/</tag> This
+repeatable directive
+introduces a new attribute to the set. The attribute value is stored
+in the index (unless a <it/local-value/ is given, in which case this
+is stored). The name is used to refer to the attribute from the
+<it/abstract syntax/.
+</descrip>
+
+This is an excerpt from the GILS attribute set definition. Notice how
+the file describing the <it/bib-1/ attribute set is referenced.
+
+<tscreen><verb>
+name gils
+reference GILS-attset
+include bib1.att
+ordinal 2
+
+att 2001		distributorName
+att 2002		indexTermsControlled
+att 2003		purpose
+att 2004		accessConstraints
+att 2005		useConstraints
+</verb></tscreen>
+
+<sect1>The Tag Set (.tag) Files
+
+<p>
+This file type defines the tagset of the profile, possibly by
+referencing other tag sets (most tag sets, for instance, will include
+tagsetG and tagsetM from the Z39.50 specification. The file may
+contain the following directives.
+
+<descrip>
+<tag>name <it/symbolic-name/</tag> This provides a shorthand name or
+description for the tag set. Mostly useful for diagnostic purposes.
+
+<tag>reference <it/OID-name/</tag> The reference name of the OID for
+the tag set. The reference names can be found in the <bf/util/
+module of <bf/YAZ/.
+
+<tag>type <it/integer/</tag> The type number of the tag within the schema
+profile.
+
+<tag>include <it/filename/</tag> (repeatable) This directive is used
+to include the definitions of other tag sets into the current one.
+
+<tag>tag <it/number names type/</tag> (repeatable) Introduces a new
+tag to the set. The <it/number/ is the tag number as used in the protocol
+(there is currently no mechanism for specifying string tags at this
+point, but this would be quick work to add). The <it/names/ parameter
+is a list of names by which the tag should be recognized in the input
+file format. The names should be separated by slashes (/). The
+<it/type/ is th recommended datatype of the tag. It should be one of
+the following:
+<itemize>
+<item>structured
+<item>string
+<item>numeric
+<item>bool
+<item>oid
+<item>generalizedtime
+<item>intunit
+<item>int
+<item>octetstring
+<item>null
+</itemize>
+</descrip>
+
+The following is an excerpt from the TagsetG definition file.
+
+<tscreen><verb>
+name tagsetg
+reference TagsetG
+type 2
+
+tag	1	title		string
+tag	2	author		string
+tag	3	publicationPlace string
+tag	4	publicationDate	string
+tag	5	documentId	string
+tag	6	abstract	string
+tag	7	name		string
+tag	8	date		generalizedtime
+tag	9	bodyOfDisplay	string
+tag	10	organization	string
+</verb></tscreen>
+
+<sect1>The Variant Set (.var) Files
+
+<p>
+The variant set file is a straightforward representation of the
+variant set definitions associated with the protocol. At present, only
+the <it/Variant-1/ set is known.
+
+These are the directives allowed in the file.
+
+<descrip>
+<tag>name <it/symbolic-name/</tag> This provides a shorthand name or
+description for the variant set. Mostly useful for diagnostic purposes.
+
+<tag>reference <it/OID-name/</tag> The reference name of the OID for
+the variant set, if one is required. The reference names can be found
+in the <bf/util/ module of <bf/YAZ/.
+
+<tag>class <it/integer class-name/</tag> (repeatable) Introduces a new
+class to the variant set.
+
+<tag>type <it/integer type-name datatype/</tag> (repeatable) Addes a
+new type to the current class (the one introduced by the most recent
+<bf/class/ directive). The type names belong to the same name space as
+the one used in the tag set definition file.
+</descrip>
+
+The following is an excerpt from the file describing the variant set
+<it/Variant-1/.
+
+<tscreen><verb>
+name variant-1
+reference Variant-1
+
+class 1 variantId
+
+  type	1	variantId		octetstring
+
+class 2 body
+
+  type	1	iana			string
+  type	2	z39.50			string
+  type	3	other			string
+</verb></tscreen>
+
+<sect1>The Element Set (.est) Files
+
+<p>
+The element set specification files describe a selection of a subset
+of the elements of a database record. The element selection mechanism
+is equivalent to the one supplied by the <it/Espec-1/ syntax of the
+Z39.50 specification. In fact, the internal representation of an
+element set specification is identical to the <it/Espec-1/ structure,
+and we'll refer you to the description of that structure for most of
+the detailed semantics of the directives below.
+
+<it>
+NOTE: Not all of the Espec-1 functionality has been implemented yet.
+The fields that are mentioned below all work as expected, unless
+otherwise is noted.
+</it>
+
+The directives available in the element set file are as follows:
+
+<descrip>
+<tag>defaultVariantSetId <it/OID-name/</tag> If variants are used in
+the following, this should provide the name of the variantset used
+(it's not currently possible to specify a different set in the
+individual variant request). In almost all cases (certainly all
+profiles known to us), the name <tt/Variant-1/ should be given here.
+
+<tag>defaultVariantRequest <it/variant-request/</tag> This directive
+provides a default variant request for
+use when the individual element requests (see below) do not contain a
+variant request. Variant requests consist of a blank-separated list of
+variant components. A variant compont is a comma-separated,
+parenthesized triple of variant class, type, and value (the two former
+values being represented as integers). The value can currently only be
+entered as a string (this will change to depend on the definition of
+the variant in question). The special value (@) is interpreted as a
+null value, however.
+
+<tag>simpleElement <it/path &lsqb;'variant' variant-request&rsqb;/</tag>
+This corresponds to a simple element request in <it/Espec-1/. The
+path consists of a sequence of tag-selectors, where each of these can
+consist of either:
+
+<itemize>
+<item>A simple tag, consisting of a comma-separated type-value pair in
+parenthesis, possibly followed by a colon (:) followed by an
+occurrences-specification (see below). The tag-value can be a number
+or a string. If the first character is an apostrophe ('), this forces
+the value to be interpreted as a string, even if it appears to be numerical.
+
+<item>A WildThing, represented as a question mark (?), possibly
+followed by a colon (:) followed by an occurrences specification (see
+below).
+
+<item>A WildPath, represented as an asterisk (*). Note that the last
+element of the path should not be a wildPath (wildpaths don't work in
+this version).
+</itemize>
+
+The occurrences-specification can be either the string <tt/all/, the
+string <tt/last/, or an explicit value-range. The value-range is
+represented as an integer (the starting point), possibly followed by a
+plus (+) and a second integer (the number of elements, default being
+one).
+
+The variant-request has the same syntax as the defaultVariantRequest
+above. Note that it may sometimes be useful to give an empty variant
+request, simlply to disable the default for a specific set of fields
+(we aren't certain if this is proper <it/Espec-1/, but it works in
+this implementation).
+</descrip>
+
+The following is an example of an element specification belonging to
+the GILS profile.
+
+<tscreen><verb>
+simpleelement (1,10)
+simpleelement (1,12)
+simpleelement (2,1)
+simpleelement (1,14)
+simpleelement (4,1)
+simpleelement (4,52)
+</verb></tscreen>
+
+<sect1>The Schema Mapping (.map) Files
+
+<p>
+Sometimes, the client might want to receive a database record in
+a schema that differs from the native schema of the record. For
+instance, a client might only know how to process WAIS records, while
+the database record is represented in a more specific schema, such as
+GILS. In this module, a mapping of data to one of the MARC formats is
+also thought of as a schema mapping (mapping the elements of the
+record into fields consistent with the given MARC specification, prior
+to actually converting the data to the ISO2709). This use of the
+object identifier for USMARC as a schema identifier represents an
+overloading of the OID which might not be entirely proper. However,
+it represents the dual role of schema and record syntax which
+is assumed by the MARC family in Z39.50.
+
+<it>
+NOTE: The schema-mapping functions are so far limited to a
+straightforward mapping of elements. This should be extended with
+mechanisms for conversions of the element contents, and conditional
+mappings of elements based on the record contents.
+</it>
+
+These are the directives of the schema mapping file format:
+
+<descrip>
+<tag>targetName <it/name/</tag> A symbolic name for the target schema
+of the table. Useful mostly for diagnostic purposes.
+
+<tag>targetRef <it/OID-name/</tag> An OID name for the target schema.
+This is used, for instance, by a server receiving a request to present
+a record in a different schema from the native one. The name, again,
+is found in the <bf/oid/ module of <bf/YAZ/.
+
+<tag>map <it/element-name target-path/</tag> (repeatable) Adds
+an element mapping rule to the table.
+</descrip>
+
+<sect1>The MARC (ISO2709) Representation (.mar) Files
+
+<p>
+This file provides rules for representing a record in the ISO2709
+format. The rules pertain mostly to the values of the constant-length
+header of the record.
+
+<it>NOTE: This will be described better.</it>
+
+<sect>The Input (Data) File Format
+
+<p>
+The retrieval module is designed to manage data derived from a
+variety of different input sources. When used on the client side, the
+source format may be GRS-1 ISO2709. On the server side, the source may
+be a structured ASCII file, augmented by a set of patterns that
+describe the structure of the document.
+
+What we think of as the native source format - the one that is
+guaranteed to provide complete access to the facilities of the module,
+is an &dquot;SGML-like&dquot; syntax, based on an inferred DTD, which
+is in turn based on the profile information from the various files
+mentioned in this document.
+
+Like SGML, an input record consists of tags and data. The tags are
+enclosed by brackets (&lt;...&gt;). As a general rule, each tag should
+be matched by a corresponding close tag, identified by the same tag
+name preceded by a slash (/).
+
+<sect>License
+
+<p>
+Copyright &copy; 1995-2000, Index Data.
+
+This is the Index Data &dquot;P&dquot; license - it applies exclusively to
+the record management module of the YAZ system, and to this
+document.
+
+Permission to use, copy, modify, distribute, and sell this software and
+its documentation, in whole or in part, for any purpose, is hereby granted,
+provided that:
+
+1. This copyright and permission notice appear in all copies of the
+software and its documentation. Notices of copyright or attribution
+which appear at the beginning of any file must remain unchanged.
+
+2. The names of Index Data or the individual authors may not be used to
+endorse or promote products derived from this software without specific
+prior written permission.
+
+THIS SOFTWARE IS PROVIDED "AS IS" AND WITHOUT WARRANTY OF ANY KIND,
+EXPRESS, IMPLIED, OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY
+WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
+IN NO EVENT SHALL INDEX DATA BE LIABLE FOR ANY SPECIAL, INCIDENTAL,
+INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND, OR ANY DAMAGES
+WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER OR
+NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF
+LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
+OF THIS SOFTWARE.
+
+<sect>About Index Data
+
+<p>
+Index Data is a consulting and software-development enterprise that
+specialises in library and information management systems. Our
+interests and expertise span a broad range of related fields, and one
+of our primary, long-term objectives is the development of a powerful
+information management
+system with open network interfaces and hypermedia capabilities.
+
+We make this software available free of charge, on a fairly unrestrictive
+license; as a service to the networking community, and to further the
+development of quality software for open network communication.
+
+We'll be happy to answer questions about the software, and about ourselves
+in general.
+
+<tscreen>
+Index Data
+Ryesgade 3
+DK-2200 Copenhagen N
+</tscreen>
+
+<p>
+<tscreen><verb>
+Phone: +45 3536 3672
+Fax  : +45 3536 0449
+Email: info@indexdata.dk
+</verb></tscreen>
+
+</article>
Index: /main/tags/2.25/gsdl/packages/yaz/doc/profiles.txt
===================================================================
--- /main/tags/2.25/gsdl/packages/yaz/doc/profiles.txt	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/yaz/doc/profiles.txt	(revision 21064)
@@ -0,0 +1,792 @@
+  Specifying and Using Application (Database) Profiles
+  Index Data, info@indexdata.dk
+  $Revision$
+
+  YAZ includes a subsystem to manage complex database records, driven by
+  a set of configuration tables that reflect a given profile.  Multiple
+  database profiles can coexeist in the same server, or even the same
+  database. The record management system is responsible for associating
+  a given record with a specific profile, and processing it accordingly.
+  This document describes the various file formats for data and configu-
+  ration files which are used by the module.
+  ______________________________________________________________________
+
+  Table of Contents
+
+
+  1. Warnings
+
+  2. Introduction
+
+  3. Overview
+
+     3.1 External Data (record) Representation
+     3.2 The Abstract Syntax
+
+  4. The Configuration Files
+
+     4.1 The Abstract Syntax (.abs) Files
+     4.2 The Attribute Set (.att) Files
+     4.3 The Tag Set (.tag) Files
+     4.4 The Variant Set (.var) Files
+     4.5 The Element Set (.est) Files
+     4.6 The Schema Mapping (.map) Files
+     4.7 The MARC (ISO2709) Representation (.mar) Files
+
+  5. The Input (Data) File Format
+
+  6. License
+
+  7. About Index Data
+
+
+
+  ______________________________________________________________________
+
+  1.  Warnings
+
+
+  o  The subsystem descibed herein is under development. Not everything
+     may work exactly as decribed, and details of the interface may
+     change as the module matures.
+
+  o  The exact workings of the subsystem may depend on the application
+     in which it is used. This document focuses on the use of the module
+     in the Zebra information server which is distributed by Index Data
+     as an independent package.
+
+
+  2.  Introduction
+
+  The retrieval facilities of Z39.50 are extremely flexible and
+  powerful.  They allow any level of structuring of database records.
+  They allow controlled re-use of attribute sets (for searching) and tag
+  sets (for retrieval) between application profiles; they allow precise
+  selection of the desired sub-elements of a database record; they allow
+  different variants of a given data element to be represented and
+  selected in a structured way; and finally they allow the exchange of
+  any type and amount of data to be represented in a single database
+  record.
+
+  These powerful retrieval facilities are a recent addition to the
+  protocol, and along with the flexible searching facilities, they make
+  the protocol an extremely capable tool for precise, structured access
+  to information systems. The retrieval facilities add new levels of
+  flexibility and control to the protocol, which add to its value
+  outside of its traditional domain of the library systems world.
+
+  The new facilities, however, also add new complexity to the protocol,
+  which is already troubles by a too-steep learning curve. We have seen
+  many good projects severely hindered or even thwarted by the sheer
+  complexity of implementing the Z39.50 protocol.
+
+  At the same time, we feel that the most complex and powerful
+  facilities of the protocol (Explain, structured retrieval, etc.), are
+  also what the protocol needs to become more widespread, and to fulfill
+  what we perceive to be its most noble potential: To provide everybody
+  with standardised, well-structured access to the information resources
+  of the world.
+
+  The purpose of YAZ, then, and of this module as well, is to simplify
+  the use of the protocol for programmers and administrators, by
+  providing simple APIs and configuration systems to access the
+  functionality of the protocol. The Retrieval module deals specifically
+  with the advanced retrieval functions which were added to the protocol
+  with version 3, or Z39.50-1994.
+
+
+  3.  Overview
+
+  3.1.  External Data (record) Representation
+
+  The Retrieval module will eventually support a wide range of input
+  formats, ranging from MARC data to USENET news archives. This section
+  introduces what we think of as the canonical format - the one that
+  gives the most general access to the various elements of the retrieval
+  functionality.
+
+  The basic model presented by the Z39.50 retrieval system is that of a
+  recursively defined tree structure, containing a list of tagged
+  elements, which may in turn contain either data or more lists of
+  tagged elements, and so forth.
+
+  We elect to represent this structuring externally by using an "SGML-
+  like" syntax. The internal representation will be discussed later.
+
+  Consider a record describing an information resource (such a record is
+  sometimes known as a locator record). It might contain a field
+  describing the distributor of the information resource, which might in
+  turn be partitioned into various fields providing details about the
+  distributor, like this:
+
+
+
+
+
+
+
+
+
+
+
+
+  <Distributor>
+      <Name> USGS/WRD </Name>
+      <Organization> USGS/WRD </Organization>
+      <Street-Address>
+          U.S. GEOLOGICAL SURVEY, 505 MARQUETTE, NW
+      </Street-Address>
+      <City> ALBUQUERQUE </City>
+      <State> NM </State>
+      <Zip-Code> 87102 </Zip-Code>
+      <Country> USA </Country>
+      <Telephone> (505) 766-5560 </Telephone>
+  </Distributor>
+
+
+
+
+  This is how data that the retrieval module reads from an input file
+  might look.
+
+  Depending on the database profile that is being used, it is likely
+  that the data won't look like this when it's transmitted from the
+  server to the client, however. Typically, the client will prefer to
+  receive the data in a more rigid syntax, such as USMARC or GRS-1. To
+  save transmission time and avoid ambiguities of language, the
+  individual tags or field names, above, might be translated into
+  numbers which are known by both the client and the server (by
+  referring to a tag set).
+
+  The retrieval module supports various types of conversions that might
+  be carried out by the server based on requests from the client. To do
+  this, it needs a set of configuration files to describe the
+  application profile that the given record adheres to.
+
+  CAUTION: Because the tables described below serve the dual purpose of
+  representing an external application profile and an internal database
+  profile, the terminology and structuring used will sometimes be
+  somewhat different from the one suggested in the the Z39.50-1995.
+
+
+  3.2.  The Abstract Syntax
+
+  The abstract syntax definition (ARS) is the focal point of the
+  application profile description. For a given profile, it may state any
+  or all of the following:
+
+
+  o  The object identifier of the database schema associated with the
+     profile, so that it can be referred to by the client.
+
+  o  The attribute set (which can possibly be a compound of multiple
+     sets) which applies in the profile. This is used when indexing and
+     searching the records belonging to the given profile.
+
+  o  The Tag set (again, this can consist of several different sets).
+     This is used when reading the records from a file, to recognize the
+     different tags, and when transmitting the record to the client -
+     mapping the tags to their numerical representation, if they are
+     known.
+
+  o  The variant set which is used in the profile. This provides a
+     vocabulary for specifying the forms of data that appear inside the
+     records.
+
+  o  Element set names, which are a shorthand way for the client to ask
+     for a subset of the data elements contained in a record. Element
+     set names, in the retrieval module, are mapped to element
+     specifications, which contain information equivalent to the Espec-1
+     syntax of Z39.50.
+
+  o  Map tables, which may specify mappings to other database profiles,
+     if desired.
+
+  o  Possibly, a set of rules describing the mapping of elements to a
+     MARC representation.
+
+  o  A list of element description (this is the actual ARS of the
+     profile), which lists the ways in which the various tags can be
+     used and organized hierarchically.
+
+  Several of the entries above simply refer to other files, which
+  describe the given objects.
+
+
+  4.  The Configuration Files
+
+  This section describes the syntax and use of the various tables which
+  are used by the retrieval module.
+
+  The number of different file types may appear daunting at first, but
+  each type corresponds fairly clearly to a single aspect of the Z39.50
+  retrieval facilities. Further, the average database administrator
+  who's simply reusing an existing profile for which tables already
+  exist, shouldn't have to worry too much about these tables.
+
+
+  4.1.  The Abstract Syntax (.abs) Files
+
+  The name of this file type is slightly misleading, since, apart from
+  the actual abstract syntax of the profile, it also includes most of
+  the other definitions that go into a database profile.
+
+  When a record in the canonical, SGML-like format is read from a file
+  or from the database, the first tag of the file should reference the
+  profile that governs the layout of the record. If the first tag of the
+  record is <gils>, the system will look for the profile definition in
+  the file gils.abs. Profile definitions are cached, so they only have
+  to be read once during the lifespan of the current process.
+
+  The file may contain the following directives:
+
+
+     name symbolic-name
+        This provides a shorthand name or description for the profile.
+        Mostly useful for diagnostic purposes.
+
+
+     reference OID-name
+        The reference name of the OID for the profile. The reference
+        names can be found in the util module of YAZ.
+
+
+     attset filename
+        The attribute set that is used for indexing and searching
+        records belonging to this profile.
+
+
+     tagset filename
+        The tag set (if any) that describe that fields of the records.
+
+
+     varset filename
+        The variant set used in the profile.
+     maptab filename
+        (repeatable) This points to a conversion table that might be
+        used if the client asks for the record in a different schema
+        from the native one.
+
+
+     marc filename
+        Points to a file containing parameters for representing the
+        record contents in the ISO2709 syntax. Read the description of
+        the MARC representation facility below.
+
+
+     esetname name filename
+        (repeatable) Associates the given element set name with an
+        element selection file. If an (@) is given in place of the
+        filename, this corresponds to a null mapping for the given
+        element set name.
+
+
+     elm path name attribute
+        (repeatable) Adds an element to the abstract record syntax of
+        the schema. The path follows the syntax which is suggested by
+        the Z39.50 document - that is, a sequence of tags separated by
+        slashes (/). Each tag is given as a comma-separated pair of tag
+        type and -value surrounded by parenthesis.  The name is the name
+        of the element, and the attribute specifies what attribute to
+        use when indexing the element. A ! in place of the attribute
+        name is equivalent to specifying an attribute name identical to
+        the element name. A - in place of the attribute name specifies
+        that no indexing is to take place for the given element.
+
+  NOTE: The mechanism for controlling indexing is inadequate for complex
+  databases, and will probably be moved into a separate configuration
+  table eventually.
+
+  The following is an excerpt from the abstract syntax file for the GILS
+  profile.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+  name gils
+  reference GILS-schema
+  attset gils.att
+  tagset gils.tag
+  varset var1.var
+
+  maptab gils-usmarc.map
+
+  # Element set names
+
+  esetname VARIANT gils-variant.est  # for WAIS-compliance
+  esetname B gils-b.est
+  esetname G gils-g.est
+  esetname W gils-b.est
+  esetname F @
+
+  elm (1,10)              rank                        -
+  elm (1,12)              url                         -
+  elm (1,14)              localControlNumber     Local-number
+  elm (1,16)              dateOfLastModification Date/time-last-modified
+  elm (2,1)               Title                       !
+  elm (4,1)               controlIdentifier      Identifier-standard
+  elm (2,6)               abstract               Abstract
+  elm (4,51)              purpose                     !
+  elm (4,52)              originator                  -
+  elm (4,53)              accessConstraints           !
+  elm (4,54)              useConstraints              !
+  elm (4,70)              availability                -
+  elm (4,70)/(4,90)       distributor                 -
+  elm (4,70)/(4,90)/(2,7) distributorName             !
+  elm (4,70)/(4,90)/(2,10 distributorOrganization     !
+  elm (4,70)/(4,90)/(4,2) distributorStreetAddress    !
+  elm (4,70)/(4,90)/(4,3) distributorCity             !
+
+
+
+
+
+  4.2.  The Attribute Set (.att) Files
+
+  This file type describes the Use elements of an attribute set.  It
+  contains the following directives.
+
+
+
+     name symbolic-name
+        This provides a shorthand name or description for the attribute
+        set. Mostly useful for diagnostic purposes.
+
+
+     reference OID-name
+        The reference name of the OID for the attribute set. The
+        reference names can be found in the util module of YAZ.
+
+
+     ordinal integer
+        This value will be used to represent the attribute set in the
+        index. Care should be taken that each attribute set has a unique
+        ordinal value.
+
+
+     include filename
+        This directive, which can be repeated, is used to include
+        another attribute set as a part of the current one. This is used
+        when a new attribute set is defined as an extension to another
+        set. For instance, many new attribute sets are defined as
+        extensions to the bib-1 set. This is an important feature of the
+        retrieval system of Z39.50, as it ensures the highest possible
+        level of interoperability, as those access points of your
+        database which are derived from the external set (say, bib-1)
+        can be used even by clients who are unaware of the new set.
+
+
+     att att-value att-name [local-value]
+        This repeatable directive introduces a new attribute to the set.
+        The attribute value is stored in the index (unless a local-value
+        is given, in which case this is stored). The name is used to
+        refer to the attribute from the abstract syntax.
+
+  This is an excerpt from the GILS attribute set definition. Notice how
+  the file describing the bib-1 attribute set is referenced.
+
+
+
+       name gils
+       reference GILS-attset
+       include bib1.att
+       ordinal 2
+
+       att 2001                distributorName
+       att 2002                indexTermsControlled
+       att 2003                purpose
+       att 2004                accessConstraints
+       att 2005                useConstraints
+
+
+
+
+
+  4.3.  The Tag Set (.tag) Files
+
+  This file type defines the tagset of the profile, possibly by
+  referencing other tag sets (most tag sets, for instance, will include
+  tagsetG and tagsetM from the Z39.50 specification. The file may
+  contain the following directives.
+
+
+     name symbolic-name
+        This provides a shorthand name or description for the tag set.
+        Mostly useful for diagnostic purposes.
+
+
+     reference OID-name
+        The reference name of the OID for the tag set. The reference
+        names can be found in the util module of YAZ.
+
+
+     type integer
+        The type number of the tag within the schema profile.
+
+
+     include filename
+        (repeatable) This directive is used to include the definitions
+        of other tag sets into the current one.
+
+
+     tag number names type
+        (repeatable) Introduces a new tag to the set. The number is the
+        tag number as used in the protocol (there is currently no
+        mechanism for specifying string tags at this point, but this
+        would be quick work to add). The names parameter is a list of
+        names by which the tag should be recognized in the input file
+        format. The names should be separated by slashes (/). The type
+        is th recommended datatype of the tag. It should be one of the
+        following:
+
+     o  structured
+
+     o  string
+
+     o  numeric
+
+     o  bool
+
+     o  oid
+
+     o  generalizedtime
+
+     o  intunit
+
+     o  int
+
+     o  octetstring
+
+     o  null
+
+  The following is an excerpt from the TagsetG definition file.
+
+
+
+       name tagsetg
+       reference TagsetG
+       type 2
+
+       tag     1       title           string
+       tag     2       author          string
+       tag     3       publicationPlace string
+       tag     4       publicationDate string
+       tag     5       documentId      string
+       tag     6       abstract        string
+       tag     7       name            string
+       tag     8       date            generalizedtime
+       tag     9       bodyOfDisplay   string
+       tag     10      organization    string
+
+
+
+
+
+  4.4.  The Variant Set (.var) Files
+
+  The variant set file is a straightforward representation of the
+  variant set definitions associated with the protocol. At present, only
+  the Variant-1 set is known.
+
+  These are the directives allowed in the file.
+
+
+     name symbolic-name
+        This provides a shorthand name or description for the variant
+        set. Mostly useful for diagnostic purposes.
+
+
+     reference OID-name
+        The reference name of the OID for the variant set, if one is
+        required. The reference names can be found in the util module of
+        YAZ.
+
+     class integer class-name
+        (repeatable) Introduces a new class to the variant set.
+
+
+     type integer type-name datatype
+        (repeatable) Addes a new type to the current class (the one
+        introduced by the most recent class directive). The type names
+        belong to the same name space as the one used in the tag set
+        definition file.
+
+  The following is an excerpt from the file describing the variant set
+  Variant-1.
+
+
+
+       name variant-1
+       reference Variant-1
+
+       class 1 variantId
+
+         type  1       variantId               octetstring
+
+       class 2 body
+
+         type  1       iana                    string
+         type  2       z39.50                  string
+         type  3       other                   string
+
+
+
+
+
+  4.5.  The Element Set (.est) Files
+
+  The element set specification files describe a selection of a subset
+  of the elements of a database record. The element selection mechanism
+  is equivalent to the one supplied by the Espec-1 syntax of the Z39.50
+  specification. In fact, the internal representation of an element set
+  specification is identical to the Espec-1 structure, and we'll refer
+  you to the description of that structure for most of the detailed
+  semantics of the directives below.
+
+  NOTE: Not all of the Espec-1 functionality has been implemented yet.
+  The fields that are mentioned below all work as expected, unless
+  otherwise is noted.
+
+  The directives available in the element set file are as follows:
+
+
+     defaultVariantSetId OID-name
+        If variants are used in the following, this should provide the
+        name of the variantset used (it's not currently possible to
+        specify a different set in the individual variant request). In
+        almost all cases (certainly all profiles known to us), the name
+        Variant-1 should be given here.
+
+
+     defaultVariantRequest variant-request
+        This directive provides a default variant request for use when
+        the individual element requests (see below) do not contain a
+        variant request. Variant requests consist of a blank-separated
+        list of variant components. A variant compont is a comma-
+        separated, parenthesized triple of variant class, type, and
+        value (the two former values being represented as integers). The
+        value can currently only be entered as a string (this will
+        change to depend on the definition of the variant in question).
+        The special value (@) is interpreted as a null value, however.
+
+
+     simpleElement path ['variant' variant-request]
+        This corresponds to a simple element request in Espec-1. The
+        path consists of a sequence of tag-selectors, where each of
+        these can consist of either:
+
+
+     o  A simple tag, consisting of a comma-separated type-value pair in
+        parenthesis, possibly followed by a colon (:) followed by an
+        occurrences-specification (see below). The tag-value can be a
+        number or a string. If the first character is an apostrophe ('),
+        this forces the value to be interpreted as a string, even if it
+        appears to be numerical.
+
+     o  A WildThing, represented as a question mark (?), possibly
+        followed by a colon (:) followed by an occurrences specification
+        (see below).
+
+     o  A WildPath, represented as an asterisk (*). Note that the last
+        element of the path should not be a wildPath (wildpaths don't
+        work in this version).
+
+        The occurrences-specification can be either the string all, the
+        string last, or an explicit value-range. The value-range is
+        represented as an integer (the starting point), possibly
+        followed by a plus (+) and a second integer (the number of
+        elements, default being one).
+
+        The variant-request has the same syntax as the
+        defaultVariantRequest above. Note that it may sometimes be
+        useful to give an empty variant request, simlply to disable the
+        default for a specific set of fields (we aren't certain if this
+        is proper Espec-1, but it works in this implementation).
+
+  The following is an example of an element specification belonging to
+  the GILS profile.
+
+
+
+       simpleelement (1,10)
+       simpleelement (1,12)
+       simpleelement (2,1)
+       simpleelement (1,14)
+       simpleelement (4,1)
+       simpleelement (4,52)
+
+
+
+
+
+  4.6.  The Schema Mapping (.map) Files
+
+  Sometimes, the client might want to receive a database record in a
+  schema that differs from the native schema of the record. For
+  instance, a client might only know how to process WAIS records, while
+  the database record is represented in a more specific schema, such as
+  GILS. In this module, a mapping of data to one of the MARC formats is
+  also thought of as a schema mapping (mapping the elements of the
+  record into fields consistent with the given MARC specification, prior
+  to actually converting the data to the ISO2709). This use of the
+  object identifier for USMARC as a schema identifier represents an
+  overloading of the OID which might not be entirely proper. However, it
+  represents the dual role of schema and record syntax which is assumed
+  by the MARC family in Z39.50.
+  NOTE: The schema-mapping functions are so far limited to a
+  straightforward mapping of elements. This should be extended with
+  mechanisms for conversions of the element contents, and conditional
+  mappings of elements based on the record contents.
+
+  These are the directives of the schema mapping file format:
+
+
+     targetName name
+        A symbolic name for the target schema of the table. Useful
+        mostly for diagnostic purposes.
+
+
+     targetRef OID-name
+        An OID name for the target schema.  This is used, for instance,
+        by a server receiving a request to present a record in a
+        different schema from the native one. The name, again, is found
+        in the oid module of YAZ.
+
+
+     map element-name target-path
+        (repeatable) Adds an element mapping rule to the table.
+
+
+  4.7.  The MARC (ISO2709) Representation (.mar) Files
+
+  This file provides rules for representing a record in the ISO2709
+  format. The rules pertain mostly to the values of the constant-length
+  header of the record.
+
+  NOTE: This will be described better.
+
+
+  5.  The Input (Data) File Format
+
+  The retrieval module is designed to manage data derived from a variety
+  of different input sources. When used on the client side, the source
+  format may be GRS-1 ISO2709. On the server side, the source may be a
+  structured ASCII file, augmented by a set of patterns that describe
+  the structure of the document.
+
+  What we think of as the native source format - the one that is
+  guaranteed to provide complete access to the facilities of the module,
+  is an "SGML-like" syntax, based on an inferred DTD, which is in turn
+  based on the profile information from the various files mentioned in
+  this document.
+
+  Like SGML, an input record consists of tags and data. The tags are
+  enclosed by brackets (<...>). As a general rule, each tag should be
+  matched by a corresponding close tag, identified by the same tag name
+  preceded by a slash (/).
+
+
+  6.  License
+
+  Copyright (C) 1995-2000, Index Data.
+
+  This is the Index Data "P" license - it applies exclusively to the
+  record management module of the YAZ system, and to this document.
+
+  Permission to use, copy, modify, distribute, and sell this software
+  and its documentation, in whole or in part, for any purpose, is hereby
+  granted, provided that:
+
+  1. This copyright and permission notice appear in all copies of the
+  software and its documentation. Notices of copyright or attribution
+  which appear at the beginning of any file must remain unchanged.
+
+  2. The names of Index Data or the individual authors may not be used
+  to endorse or promote products derived from this software without
+  specific prior written permission.
+
+  THIS SOFTWARE IS PROVIDED "AS IS" AND WITHOUT WARRANTY OF ANY KIND,
+  EXPRESS, IMPLIED, OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY
+  WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.  IN
+  NO EVENT SHALL INDEX DATA BE LIABLE FOR ANY SPECIAL, INCIDENTAL,
+  INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND, OR ANY DAMAGES
+  WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER OR NOT
+  ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF LIABILITY,
+  ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
+  SOFTWARE.
+
+
+  7.  About Index Data
+
+  Index Data is a consulting and software-development enterprise that
+  specialises in library and information management systems. Our
+  interests and expertise span a broad range of related fields, and one
+  of our primary, long-term objectives is the development of a powerful
+  information management system with open network interfaces and
+  hypermedia capabilities.
+
+  We make this software available free of charge, on a fairly
+  unrestrictive license; as a service to the networking community, and
+  to further the development of quality software for open network
+  communication.
+
+  We'll be happy to answer questions about the software, and about
+  ourselves in general.
+
+
+       Index Data Ryesgade 3 DK-2200 Copenhagen N
+
+
+
+
+
+       Phone: +45 3536 3672
+       Fax  : +45 3536 0449
+       Email: info@indexdata.dk
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
Index: /main/tags/2.25/gsdl/packages/yaz/doc/yaz-1.html
===================================================================
--- /main/tags/2.25/gsdl/packages/yaz/doc/yaz-1.html	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/yaz/doc/yaz-1.html	(revision 21064)
@@ -0,0 +1,93 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN">
+<HTML>
+<HEAD>
+ <META NAME="GENERATOR" CONTENT="SGML-Tools 1.0.9">
+ <TITLE>YAZ User's Guide and Reference: Introduction</TITLE>
+ <LINK HREF="yaz-2.html" REL=next>
+
+ <LINK HREF="yaz.html#toc1" REL=contents>
+</HEAD>
+<BODY>
+<A HREF="yaz-2.html">Next</A>
+Previous
+<A HREF="yaz.html#toc1">Contents</A>
+<HR>
+<H2><A NAME="s1">1. Introduction</A></H2>
+
+<P>The <B>YAZ</B> toolkit offers several different levels of access to the
+Z39.50 and SR protocols. The level that you need to use depends on
+your requirements, and the role (server or client) that you
+want to implement.
+<P>The basic level, which is independent of the role, consists of three
+primary interfaces:
+<P>
+<UL>
+<LI><B>ASN</B>, which provides a C representation of the Z39.50/SR protocol
+packages (PDUs).</LI>
+<LI><B>ODR</B>, which encodes and decodes the packages according to the BER
+specification.</LI>
+<LI><B>COMSTACK</B>, which exchanges the encoded packages with a peer process
+over a network.</LI>
+</UL>
+<P>The ASN module represents the ASN.1 definition of the
+SR/Z39.50 protocol. It establishes a set of type and
+structure definitions, with one structure for each of the top-level
+PDUs, and one structure or type for each of the contained ASN.1 types.
+For primitive types, or other types that are defined by the ASN.1
+standard itself (such as the EXTERNAL type), the C representation is provided
+by the <B>ODR</B> (Open Data Representation) subsystem.
+<P><B>ODR</B> is a basic mechanism for representing an
+ASN.1 type in the C programming language, and for implementing BER
+encoders and decoders for values of that type. The types defined in
+the <B>ASN</B>
+module generally have the prefix <CODE>Z_</CODE>, and a suffix corresponding to
+the name of the type in the ASN.1
+specification of the protocol (generally Z39.50-1995). In the case of
+base types (those originating in the ASN.1 standard itself), the prefix
+<CODE>Odr_</CODE> is sometimes seen. Either way, look for
+the actual definition in either <CODE>proto.h</CODE> (for the types from the
+protocol), <CODE>odr.h</CODE> (for the primitive ASN.1 types, or <CODE>odr_use.h</CODE> (for the
+ASN.1 <I>useful</I> types). The <B>ASN</B> library also provides functions (which
+are, in turn, defined using <B>ODR</B> primitives) for encoding and decoding data
+values. Their general form is
+<P>
+<BLOCKQUOTE><CODE>
+<PRE>
+int z_xxx(ODR o, Z_xxx **p, int optional, const char *name);
+</PRE>
+</CODE></BLOCKQUOTE>
+<P>(note the lower-case &quot;z&quot; in the function name)
+<P><I>NOTE: If you are using the premade definitions of the <B>ASN</B> module, and
+you are not adding new protocol of your own, the only parts of ODR
+that you need to worry about are documented in section
+<A HREF="yaz-5.html#odr-use">Using ODR</A>.</I>
+<P>When you have created a BER-encoded buffer, you can use the <B>COMSTACK</B>
+subsystem to transmit (or receive) data over the network. The <B>COMSTACK</B>
+module provides simple functions for establishing a connection
+(passively or actively, depending on the role of your application),
+and for exchanging BER-encoded PDUs over that connection. When you
+create a connection endpoint, you need to specify what transport to
+use (OSI or TCP/IP), and which protocol you want to use (SR or
+Z39.50). For the remainer of the connection's lifetime, you don't have
+to worry about the underlying transport protocol at all - the <B>COMSTACK</B>
+will ensure that the correct mechanism is used.
+<P>We call the combined interfaces to <B>ODR</B>, <B>ASN</B>, and <B>COMSTACK</B> the service
+level API. It's the API that most closely models the Z39.50/SR
+service/protocol definition, and it provides unlimited access to all
+fields and facilities of the protocol definitions.
+<P>The reason that the <B>YAZ</B> service-level API is a conglomerate of the
+APIs from three different submodules is twofold. First, we wanted to allow the
+user a choice of different options for each major task. For instance,
+if you don't like the protocol API provided by <B>ODR</B>/<B>ASN</B>, you
+can use SNACC or BERUtils instead, and still have the benefits of the
+transparent transport approach of the <B>COMSTACK</B> module. Secondly,
+we realise that you may have to fit the toolkit into an existing
+event-processing structure, in a way that
+is incompatible with the <B>COMSTACK</B> interface or some other part of <B>YAZ</B>.
+<P>
+<HR>
+<A HREF="yaz-2.html">Next</A>
+Previous
+<A HREF="yaz.html#toc1">Contents</A>
+</BODY>
+</HTML>
Index: /main/tags/2.25/gsdl/packages/yaz/doc/yaz-2.html
===================================================================
--- /main/tags/2.25/gsdl/packages/yaz/doc/yaz-2.html	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/yaz/doc/yaz-2.html	(revision 21064)
@@ -0,0 +1,177 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN">
+<HTML>
+<HEAD>
+ <META NAME="GENERATOR" CONTENT="SGML-Tools 1.0.9">
+ <TITLE>YAZ User's Guide and Reference: Compilation and Installation</TITLE>
+ <LINK HREF="yaz-3.html" REL=next>
+ <LINK HREF="yaz-1.html" REL=previous>
+ <LINK HREF="yaz.html#toc2" REL=contents>
+</HEAD>
+<BODY>
+<A HREF="yaz-3.html">Next</A>
+<A HREF="yaz-1.html">Previous</A>
+<A HREF="yaz.html#toc2">Contents</A>
+<HR>
+<H2><A NAME="s2">2. Compilation and Installation</A></H2>
+
+<P>The latest version of the software will generally be found at
+<P>
+<BLOCKQUOTE><CODE>
+<PRE>
+http://ftp.indexdata.dk/pub/yaz/
+</PRE>
+</CODE></BLOCKQUOTE>
+<P>We have tried our best to keep the software portable, and on many
+platforms, you should be able to compile everything with little or no changes.
+So far, the software has been ported
+to the following platforms with little or no difficulties.
+<P>
+<UL>
+<LI>Unix systems
+<UL>
+<LI>HP/UX</LI>
+<LI>SunOS/Solaris</LI>
+<LI>DEC Unix</LI>
+<LI>Linux</LI>
+<LI>IBM AIX</LI>
+<LI>Data General DG/UX (with some CFLAGS tinkering)</LI>
+<LI>SGI/IRIX</LI>
+<LI>DDE Supermax</LI>
+</UL>
+</LI>
+<LI>Non-unix systems
+<UL>
+<LI>Apple Macintosh (using the Codewarrior programming environment and the
+GUSI socket libraries)</LI>
+<LI>MS Windows 95/NT (Win32)</LI>
+<LI>IBM AS/400</LI>
+</UL>
+</LI>
+</UL>
+<P>If you move the software to other platforms, we'd be grateful if you'd
+let us know about it. If you run into difficulties, we will try to help if we
+can, and if you solve the problems, we would be happy to
+include your fixes in the next release. So far, we have mostly avoided
+#ifdefs for individual platforms, and we'd like to keep it that
+way as far as it makes sense.
+<P>We maintain a mailing-list for the purpose of announcing new releases and
+bug-fixes, as well as general discussion. Subscribe by sending mail to
+<CODE>yaz-request@indexdata.dk</CODE>. General questions and problems can be
+directed at <CODE>yaz-help@indexdata.dk</CODE>, or the address given at the top
+of this document.
+<P>
+<H2><A NAME="ss2.1">2.1 UNIX</A>
+</H2>
+
+<P>Note that if your system doesn't have a native ANSI C compiler, you may
+have to acquire one separately. We recommend gcc.
+<P>For UNIX we use GNU configure to create Makefiles for YAZ.
+Generally it should be sufficient to run configure without options:
+<P>
+<BLOCKQUOTE><CODE>
+<PRE>
+./configure
+</PRE>
+</CODE></BLOCKQUOTE>
+<P>The configure script attempts to use use the C compiler specified by
+the <CODE>CC</CODE> environment variable. If not set, GNU C will be used
+if it is available. The <CODE>CFLAGS</CODE> environment variable holds options
+to be passed to the C compiler. If you're using Bourne-compatible shell
+you may pass something like this to use a particular C compiler with
+optimization enabled:
+<BLOCKQUOTE><CODE>
+<PRE>
+  CC=/opt/ccs/bin/cc CFLAGS=-O ./configure
+</PRE>
+</CODE></BLOCKQUOTE>
+<P>To customize <B>YAZ</B> the configure script also accepts a set of options.
+The most important are:
+<P>
+<DL>
+<DT><B><CODE>-</CODE><CODE>-prefix </CODE>path</B><DD><P>Specifies installation prefix. This is
+only needed if you run <CODE>make install</CODE> later to perform a
+"system" installation. The prefix is <CODE>/usr/local</CODE> if not
+specified.
+<P>
+<DT><B><CODE>-</CODE><CODE>-enable-comp </CODE></B><DD><P>YAZ will be built using
+the ASN.1 compiler for YAZ (default). If you wish to use the
+old decoders (in sub directory asn) use <CODE>--disable-comp</CODE> instead.
+<P>
+<DT><B><CODE>-</CODE><CODE>-enable-threads</CODE></B><DD><P>YAZ will be built using
+POSIX threads. Specifically, <CODE>_REENTRANT</CODE> will be defined
+during compilation.
+</DL>
+<P>When configured, build the software by typing:
+<BLOCKQUOTE><CODE>
+<PRE>
+  make
+</PRE>
+</CODE></BLOCKQUOTE>
+<P>Developers that do modifications to <B>YAZ</B> may wish to run
+<CODE>make depend</CODE> as well to generate object-header file
+dependencies.
+<P>The following files are generated by make
+<DL>
+<DT><B><CODE>lib/libyaz.a</CODE></B><DD><P>The <B>YAZ</B> programmers' library.
+<P>
+<DT><B><CODE>ztest/yaz-ztest</CODE></B><DD><P>A test Z39.50 server.
+<P>
+<DT><B><CODE>client/yaz-client</CODE></B><DD><P>A command mode Z39.50 client.
+<P>
+<DT><B><CODE>yaz-config</CODE></B><DD><P>A Bourne-shell script that holds build
+settings for <B>YAZ</B>.
+<P>
+</DL>
+<P>If you wish to install <B>YAZ</B> in system directories such as /usr/local/bin,
+/usr/local/lib) you can type:
+<P>
+<BLOCKQUOTE><CODE>
+<PRE>
+  make install
+</PRE>
+</CODE></BLOCKQUOTE>
+<P>You probably need to have root access in order to perform this.
+You must specify the <CODE>--prefix</CODE> option for configure if you
+going to install in anything but /usr/local/.
+<P>
+<H2><A NAME="ss2.2">2.2 WIN32</A>
+</H2>
+
+<P><B>YAZ</B> is shipped with "makefiles" for the NMAKE tool that comes
+with Visual C++.
+<P>Start an MS-DOS prompt and switch the sub directory <CODE>WIN</CODE> where
+the file <CODE>makefile</CODE> is located. Customize the installation
+by editing the <CODE>makefile</CODE> file (for example by using notepad).
+<P>The following summarises the most important settings in that file:
+<P>
+<DL>
+<DT><B><CODE>NEW_Z3950</CODE></B><DD><P>If 1, the auto-generated decoder/encoders
+for Z39.50 as written by the ASN.1 compiler will be used. If 0, the old
+decoders for Z39.50 will be used. Note, when 1, the setting TCL should
+point to the Tcl shell on your system.
+<DT><B><CODE>DEBUG</CODE></B><DD><P>If set to 1, the software is
+compiled with debugging libraries. If set to 0, the software
+is compiled with release (non-debugging) libraries.
+</DL>
+<P>When satisfied with the settings in the makefile type
+<BLOCKQUOTE><CODE>
+<PRE>
+nmake
+</PRE>
+</CODE></BLOCKQUOTE>
+<P>The following is generated upon successful compilation:
+<DL>
+<DT><B><CODE>bin/yaz.dll</CODE></B><DD><P>A multithreaded DLL with everything
+except the frontend server library.
+<DT><B><CODE>lib/yaz.lib</CODE></B><DD><P>An import library for <CODE>yaz.dll</CODE>.
+<DT><B><CODE>lib/server.lib</CODE></B><DD><P>The frontend server library.
+<DT><B><CODE>bin/yaz-ztest.exe</CODE></B><DD><P>A test Z39.50 server.
+<DT><B><CODE>bin/yaz-client.exe</CODE></B><DD><P>A command mode Z39.50 client.
+</DL>
+<P>
+<HR>
+<A HREF="yaz-3.html">Next</A>
+<A HREF="yaz-1.html">Previous</A>
+<A HREF="yaz.html#toc2">Contents</A>
+</BODY>
+</HTML>
Index: /main/tags/2.25/gsdl/packages/yaz/doc/yaz-3.html
===================================================================
--- /main/tags/2.25/gsdl/packages/yaz/doc/yaz-3.html	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/yaz/doc/yaz-3.html	(revision 21064)
@@ -0,0 +1,512 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN">
+<HTML>
+<HEAD>
+ <META NAME="GENERATOR" CONTENT="SGML-Tools 1.0.9">
+ <TITLE>YAZ User's Guide and Reference: The ASN Module</TITLE>
+ <LINK HREF="yaz-4.html" REL=next>
+ <LINK HREF="yaz-2.html" REL=previous>
+ <LINK HREF="yaz.html#toc3" REL=contents>
+</HEAD>
+<BODY>
+<A HREF="yaz-4.html">Next</A>
+<A HREF="yaz-2.html">Previous</A>
+<A HREF="yaz.html#toc3">Contents</A>
+<HR>
+<H2><A NAME="s3">3. The ASN Module</A></H2>
+
+<H2><A NAME="ss3.1">3.1 Introduction</A>
+</H2>
+
+<P>The <B>ASN</B> module provides you with a set of C struct definitions for the
+various PDUs of the protocol, as well as for the complex types
+appearing within the PDUs. For the primitive data types, the C
+representation often takes the form of an ordinary C language type,
+such as <CODE>int</CODE>. For ASN.1 constructs that have no direct
+representation in C, such as general octet strings and bit strings,
+the <B>ODR</B> module (see section 
+<A HREF="yaz-5.html#odr">ODR</A>) provides auxiliary
+definitions.
+<P>
+<H2><A NAME="ss3.2">3.2 Preparing PDUs</A>
+</H2>
+
+<P>A structure representing a complex ASN.1 type doesn't in itself contain the
+members of that type. Instead, the structure contains <I>pointers</I> to
+the members of the type. This is necessary, in part, to allow a mechanism for
+specifying which of the optional structure (SEQUENCE) members are
+present, and which are not. It follows that you will need to somehow
+provide space for the individual members of the structure, and
+set the pointers to refer to the members.
+<P>The conversion routines don't care how you allocate and maintain your
+C structures - they just follow the pointers that you provide.
+Depending on the complexity of your application, and your personal
+taste, there are at least three different approaches that you may take
+when you allocate the structures.
+<P>
+<UL>
+<LI>You can use static or automatic local variables in the function that
+prepares the PDU. This is a simple approach, and it provides the most
+efficient form of memory management. While it works well for flat
+PDUs like the InitReqest, it will generally not be sufficient for say,
+the generation of an arbitrarily complex RPN query structure.</LI>
+<LI>You can individually create the structure and its members using the
+<CODE>malloc</CODE>(2) function. If you want to ensure that the data is freed when
+it is no longer needed, you will have to define a function that
+individually releases each member of a structure before freeing the
+structure itself.</LI>
+<LI>You can use the <CODE>odr_malloc()</CODE> function (see section 
+<A HREF="yaz-5.html#odr-use">Using ODR</A> for details). When you use <CODE>odr_malloc()</CODE>, you can release
+all of the
+allocated data in a single operation, independent of any pointers and
+relations between the data. <CODE>odr_malloc()</CODE> is based on a
+&quot;nibble-memory&quot;
+scheme, in which large portions of memory are allocated, and then
+gradually handed out with each call to <CODE>odr_malloc()</CODE>. The next time you
+call <CODE>odr_reset()</CODE>, all of the memory allocated since the last call is
+recycled for future use (actually, it is placed on a free-list).</LI>
+<LI>You can combine all of the methods described here. This will often be
+the most practical approach. For instance, you might use <CODE>odr_malloc()</CODE> to
+allocate an entire structure and some of its elements, while you leave
+other elements pointing to global or per-session default variables.</LI>
+</UL>
+<P>The <B>ASN</B> module provides an important aid in creating new PDUs. For
+each of the PDU types (say, <CODE>Z_InitRequest</CODE>), a function is provided
+that allocates and initializes an instance of that PDU type for you.
+In the case of the InitRequest, the function is simply named
+<CODE>zget_InitRequest()</CODE>, and it sets up reasonable default value for all of
+the mandatory members. The optional members are generally initialized to null
+pointers. This last aspect is very important: it ensures that if the
+PDU definitions are extended after you finish your implementation
+(to accommodate
+new versions of the protocol, say), you won't get into trouble with
+uninitialized pointers in your structures. The functions use
+<CODE>odr_malloc()</CODE> to
+allocate the PDUs and its members, so you can free everything again with a
+single call to <CODE>odr_reset()</CODE>. We strongly recommend that you use the
+<CODE>zget_*</CODE>
+functions whenever you are preparing a PDU (in a C++ API, the
+<CODE>zget_</CODE>
+functions would probably be promoted to constructors for the
+individual types).
+<P>The prototype for the individual PDU types generally look like this:
+<P>
+<BLOCKQUOTE><CODE>
+<PRE>
+Z_&lt;type> *zget_&lt;type>(ODR o);
+</PRE>
+</CODE></BLOCKQUOTE>
+<P>eg.:
+<P>
+<BLOCKQUOTE><CODE>
+<PRE>
+Z_InitRequest *zget_InitRequest(ODR o);
+</PRE>
+</CODE></BLOCKQUOTE>
+<P>The <B>ODR</B> handle should generally be your encoding stream, but it
+needn't be.
+<P>As well as the individual PDU functions, a function <CODE>zget_APDU()</CODE> is
+provided, which allocates a toplevel Z-APDU of the type requested:
+<P>
+<BLOCKQUOTE><CODE>
+<PRE>
+Z_APDU *zget_APDU(ODR o, int which);
+</PRE>
+</CODE></BLOCKQUOTE>
+<P>The <CODE>which</CODE> parameter is (of course) the discriminator belonging to the
+<CODE>Z_APDU</CODE> CHOICE type. All of the interface described here is provided by
+the <B>ASN</B> module, and you access it through the <CODE>proto.h</CODE> header file.
+<P>
+<H2><A NAME="oid"></A> <A NAME="ss3.3">3.3 Object Identifiers</A>
+</H2>
+
+<P>When you refer to object identifiers in your application, you need to
+be aware that SR and Z39.50 use two different set of OIDs to refer to
+the same objects. To handle this easily, <B>YAZ</B> provides a utility module
+to <B>ASN</B> which provides an internal representation of the OIDs used in
+both protocols. Each oid is described by a structure:
+<P>
+<BLOCKQUOTE><CODE>
+<PRE>
+typedef struct oident
+{
+    enum oid_proto proto;
+    enum oid_class class;
+    enum oid_value value;
+    int oidsuffix[OID_SIZE];
+    char *desc;
+} oident;
+</PRE>
+</CODE></BLOCKQUOTE>
+<P>The <CODE>proto</CODE> field can be set to either <CODE>PROTO_SR</CODE> or
+<CODE>PROTO_Z3950</CODE>. The <CODE>class</CODE> might be, say, <CODE>CLASS_RECSYN</CODE>, and the
+<CODE>value</CODE> might be <CODE>VAL_USMARC</CODE> for the USMARC record format. Functions
+<P>
+<BLOCKQUOTE><CODE>
+<PRE>
+int *oid_ent_to_oid(struct oident *ent, int *dst);
+struct oident *oid_getentbyoid(int *o);
+</PRE>
+</CODE></BLOCKQUOTE>
+<P>are provided to map between object identifiers and database entries.
+If you store a member of the <CODE>oid_proto</CODE> type in your association
+state information, it's a simple matter, at runtime, to generate the
+correct OID when you need it. For decoding, you can simply ignore the
+proto field, or if you're strict, you can verify that your peer is
+using the OID family from the correct protocol. The <CODE>desc</CODE> field is
+a short, human-readable name for the PDU, useful mainly for diagnostic
+output.
+<P><I>NOTE: The old function oid_getoidbyent still exists but is
+not thread safe. Use oid_ent_to_oid instead and pass an array of
+size OID_SIZE.</I>
+<P><I>NOTE: Plans are underway to merge the two protocols into a single
+definition, with one set of object identifiers. When this happens, the
+oid module will no longer be required to support protocol
+independence, but it should still be useful as a simple OID database.</I>
+<P>
+<H2><A NAME="ss3.4">3.4 EXTERNAL Data</A>
+</H2>
+
+<P>In order to achieve extensibility and adaptability to different
+application domains, the new version of the protocol defines many
+structures outside of the main ASN.1 specification, referencing them
+through ASN.1 EXTERNAL constructs. To simplify the construction and access
+to the externally referenced data, the <B>ASN</B> module defines a
+specialized version of the EXTERNAL construct, called <CODE>Z_External</CODE>.
+It is defined thus:
+<P>
+<BLOCKQUOTE><CODE>
+<PRE>
+typedef struct Z_External
+{
+    Odr_oid *direct_reference;
+    int *indirect_reference;
+    char *descriptor;
+    enum
+    {
+        /* Generic types */
+        Z_External_single = 0,
+        Z_External_octet,
+        Z_External_arbitrary,
+
+        /* Specific types */
+        Z_External_SUTRS,
+        Z_External_explainRecord,
+        Z_External_resourceReport1,
+        Z_External_resourceReport2
+
+        ...
+
+    } which;
+    union
+    {
+        /* Generic types */
+        Odr_any *single_ASN1_type;
+        Odr_oct *octet_aligned;
+        Odr_bitmask *arbitrary;
+
+        /* Specific types */
+        Z_SUTRS *sutrs;
+        Z_ExplainRecord *explainRecord;
+        Z_ResourceReport1 *resourceReport1;
+        Z_ResourceReport2 *resourceReport2;
+
+        ...
+
+    } u;
+} Z_External;
+</PRE>
+</CODE></BLOCKQUOTE>
+<P>When decoding, the <B>ASN</B> module will attempt to determine which
+syntax describes the data by looking at the reference fields
+(currently only the direct-reference). For ASN.1 structured data, you
+need only consult the <CODE>which</CODE> field to determine the type of data.
+You can the access  the data directly through the union. When
+constructing data for encoding, you set the union pointer to point to
+the data, and set the <CODE>which</CODE> field accordingly. Remember also to
+set the direct (or indirect) reference to the correct OID for the data
+type. For non-ASN.1 data such as MARC records, use the
+<CODE>octet_aligned</CODE> arm of the union.
+<P>Some servers return ASN.1 structured data values (eg. database
+records) as BER-encoded records placed in the <CODE>octet-aligned</CODE>
+branch of the EXTERNAL CHOICE. The ASN-module will <I>not</I>
+automatically decode these records. To help you decode the records in
+the application, the function
+<P>
+<BLOCKQUOTE><CODE>
+<PRE>
+Z_ext_typeent *z_ext_gettypebyref(oid_value ref);
+</PRE>
+</CODE></BLOCKQUOTE>
+<P>Can be used to retrieve information about the known, external data
+types. The function return a pointer to a static area, or NULL, if no
+match for the given direct reference is found. The <CODE>Z_ext_typeent</CODE>
+is defined as:
+<P>
+<BLOCKQUOTE><CODE>
+<PRE>
+typedef struct Z_ext_typeent
+{
+    oid_value dref;    /* the direct-reference OID value. */
+    int what;          /* discriminator value for the external CHOICE */
+    Odr_fun fun;       /* decoder function */
+} Z_ext_typeent;
+</PRE>
+</CODE></BLOCKQUOTE>
+<P>The <CODE>what</CODE> member contains the Z_External union discriminator value
+for the given type: For the SUTRS record syntax, the value would be
+<CODE>Z_External_sutrs</CODE>. The <CODE>fun</CODE> member contains a pointer to the
+function which encodes/decodes the given type. Again, for the SUTRS
+record syntax, the value of <CODE>fun</CODE> would be <CODE>z_SUTRS</CODE> (a function
+pointer).
+<P>If you receive an EXTERNAL which contains an octet-string value that
+you suspect of being an ASN.1-structured data value, you can use
+<CODE>z_ext_gettypebyref</CODE> to look for the provided direct-reference. If
+the return value is different from NULL, you can use the provided
+function to decode the BER string (see section 
+<A HREF="yaz-5.html#odr-use">Using ODR</A>). 
+<P>If you want to <I>send</I> EXTERNALs containing ASN.1-structured values
+in the occtet-aligned branch of the CHOICE, this is possible too.
+However, on the encoding phase, it requires a somewhat involved
+juggling around of the various buffers involved.
+<P>If you need to add new, externally defined data types, you must update
+the struct above, in the source file <CODE>prt-ext.h</CODE>, as well as the
+encoder/decoder in the file <CODE>prt-ext.c</CODE>. When changing the latter,
+remember to update both the <CODE>arm</CODE> arrary and the list <CODE>type_table</CODE>,
+which drives the CHOICE biasing that is necessary to tell the
+different, structured types apart on decoding.
+<P><I>NOTE: Eventually, the EXTERNAL processing will most likely
+automatically insert the correct OIDs or indirect-refs. First,
+however, we need to determine how application-context management
+(specifically the presentation-context-list) should fit into the
+various modules.</I>
+<P>
+<H2><A NAME="ss3.5">3.5 PDU Contents Table</A>
+</H2>
+
+<P>We include, for reference, a listing of the fields of each top-level
+PDU, as well as their default settings.
+<P>
+<PRE>
+Z_InitRequest
+-------------
+Field                        Type                Default value
+
+referenceId                  Z_ReferenceId       NULL
+protocolVersion              Odr_bitmask         Empty bitmask
+options                      Odr_bitmask         Empty bitmask
+preferredMessageSize         int                 30*1024
+maximumRecordSize            int                 30*1024
+idAuthentication             Z_IdAuthentication  NULL
+implementationId             char*               "YAZ (id=81)"
+implementationName           char*               "Index Data/YAZ"
+implementationVersion        char*               YAZ_VERSION
+userInformationField         Z_UserInformation   NULL
+otherInfo                    Z_OtherInformation  NULL
+
+Z_InitResponse
+--------------
+Field                        Type                Default value
+
+referenceId                  Z_ReferenceId       NULL
+protocolVersion              Odr_bitmask         Empty bitmask
+options                      Odr_bitmask         Empty bitmask
+preferredMessageSize         int                 30*1024
+maximumRecordSize            int                 30*1024
+result                       bool_t              TRUE
+implementationId             char*               "YAZ (id=81)"
+implementationName           char*               "Index Data/YAZ"
+implementationVersion        char*               YAZ_VERSION
+userInformationField         Z_UserInformat..    NULL
+otherInfo                    Z_OtherInformation  NULL
+
+Z_SearchRequest
+---------------
+Field                        Type                Default value
+
+referenceId                  Z_ReferenceId       NULL
+smallSetUpperBound           int                 0
+largeSetLowerBound           int                 1
+mediumSetPresentNumber       int                 0
+replaceIndicator             bool_t              TRUE
+resultSetName                char*               "default"
+num_databaseNames            int                 0
+databaseNames                char**              NULL
+smallSetElementSetNames      Z_ElementSetNames   NULL
+mediumSetElementSetNames     Z_ElementSetNames   NULL
+preferredRecordSyntax        Odr_oid             NULL
+query                        Z_Query             NULL
+additionalSearchInfo         Z_OtherInformation  NULL
+otherInfo                    Z_OtherInformation  NULL
+
+Z_SearchResponse
+----------------
+Field                        Type                Default value
+
+referenceId                  Z_ReferenceId       NULL
+resultCount                  int                 0
+numberOfRecordsReturned      int                 0
+nextResultSetPosition        int                 0
+searchStatus                 bool_t              TRUE
+resultSetStatus              int                 NULL
+presentStatus                int                 NULL
+records                      Z_Records           NULL
+additionalSearchInfo         Z_OtherInformation  NULL
+otherInfo                    Z_OtherInformation  NULL
+
+Z_PresentRequest
+----------------
+Field                        Type                Default value
+
+referenceId                  Z_ReferenceId       NULL
+resultSetId                  char*               "default"
+resultSetStartPoint          int                 1
+numberOfRecordsRequested     int                 10
+num_ranges                   int                 0
+additionalRanges             Z_Range             NULL
+recordComposition            Z_RecordComposition NULL
+preferredRecordSyntax        Odr_oid             NULL
+maxSegmentCount              int                 NULL
+maxRecordSize                int                 NULL
+maxSegmentSize               int                 NULL
+otherInfo                    Z_OtherInformation  NULL
+
+Z_PresentResponse
+-----------------
+Field                        Type                Default value
+
+referenceId                  Z_ReferenceId       NULL
+numberOfRecordsReturned      int                 0
+nextResultSetPosition        int                 0
+presentStatus                int                 Z_PRES_SUCCESS
+records                      Z_Records           NULL
+otherInfo                    Z_OtherInformation  NULL
+
+Z_DeleteResultSetRequest
+------------------------
+Field                        Type                Default value
+
+referenceId                  Z_ReferenceId       NULL
+deleteFunction               int                 Z_DeleteRequest_list
+num_ids                      int                 0
+resultSetList                char**              NULL
+otherInfo                    Z_OtherInformation  NULL
+
+Z_DeleteResultSetResponse
+-------------------------
+Field                        Type                Default value
+
+referenceId                  Z_ReferenceId       NULL
+deleteOperationStatus        int                 Z_DeleteStatus_success
+num_statuses                 int                 0
+deleteListStatuses           Z_ListStatus**      NULL
+numberNotDeleted             int                 NULL
+num_bulkStatuses             int                 0
+bulkStatuses                 Z_ListStatus        NULL
+deleteMessage                char*               NULL
+otherInfo                    Z_OtherInformation  NULL
+
+Z_ScanRequest
+-------------
+Field                        Type                Default value
+
+referenceId                  Z_ReferenceId       NULL
+num_databaseNames            int                 0
+databaseNames                char**              NULL
+attributeSet                 Odr_oid             NULL
+termListAndStartPoint        Z_AttributesPlus... NULL
+stepSize                     int                 NULL
+numberOfTermsRequested       int                 20
+preferredPositionInResponse  int                 NULL
+otherInfo                    Z_OtherInformation  NULL
+
+Z_ScanResponse
+--------------
+Field                        Type                Default value
+
+referenceId                  Z_ReferenceId       NULL
+stepSize                     int                 NULL
+scanStatus                   int                 Z_Scan_success
+numberOfEntriesReturned      int                 0
+positionOfTerm               int                 NULL
+entries                      Z_ListEntris        NULL
+attributeSet                 Odr_oid             NULL
+otherInfo                    Z_OtherInformation  NULL
+
+Z_TriggerResourceControlRequest
+-------------------------------
+Field                        Type                Default value
+
+referenceId                  Z_ReferenceId       NULL
+requestedAction              int                 Z_TriggerResourceCtrl_resou..
+prefResourceReportFormat     Odr_oid             NULL
+resultSetWanted              bool_t              NULL
+otherInfo                    Z_OtherInformation  NULL
+
+Z_ResourceControlRequest
+------------------------
+Field                        Type                Default value
+
+referenceId                  Z_ReferenceId       NULL
+suspendedFlag                bool_t              NULL
+resourceReport               Z_External          NULL
+partialResultsAvailable      int                 NULL
+responseRequired             bool_t              FALSE
+triggeredRequestFlag         bool_t              NULL
+otherInfo                    Z_OtherInformation  NULL
+
+Z_ResourceControlResponse
+-------------------------
+Field                        Type                Default value
+
+referenceId                  Z_ReferenceId       NULL
+continueFlag                 bool_t              TRUE
+resultSetWanted              bool_t              NULL
+otherInfo                    Z_OtherInformation  NULL
+
+Z_AccessControlRequest
+----------------------
+Field                        Type                Default value
+
+referenceId                  Z_ReferenceId       NULL
+which                        enum                Z_AccessRequest_simpleForm;
+u                            union               NULL
+otherInfo                    Z_OtherInformation  NULL
+
+Z_AccessControlResponse
+-----------------------
+Field                        Type                Default value
+
+referenceId                  Z_ReferenceId       NULL
+which                        enum                Z_AccessResponse_simpleForm
+u                            union               NULL
+diagnostic                   Z_DiagRec           NULL
+otherInfo                    Z_OtherInformation  NULL
+
+Z_Segment
+---------
+Field                        Type                Default value
+
+referenceId                  Z_ReferenceId       NULL
+numberOfRecordsReturned      int                 value=0
+num_segmentRecords           int                 0
+segmentRecords               Z_NamePlusRecord    NULL
+otherInfo                    Z_OtherInformation  NULL
+
+Z_Close
+-------
+Field                        Type                Default value
+
+referenceId                  Z_ReferenceId       NULL
+closeReason                  int                 Z_Close_finished
+diagnosticInformation        char*               NULL
+resourceReportFormat         Odr_oid             NULL
+resourceFormat               Z_External          NULL
+otherInfo                    Z_OtherInformation  NULL
+</PRE>
+<P>
+<HR>
+<A HREF="yaz-4.html">Next</A>
+<A HREF="yaz-2.html">Previous</A>
+<A HREF="yaz.html#toc3">Contents</A>
+</BODY>
+</HTML>
Index: /main/tags/2.25/gsdl/packages/yaz/doc/yaz-4.html
===================================================================
--- /main/tags/2.25/gsdl/packages/yaz/doc/yaz-4.html	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/yaz/doc/yaz-4.html	(revision 21064)
@@ -0,0 +1,564 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN">
+<HTML>
+<HEAD>
+ <META NAME="GENERATOR" CONTENT="SGML-Tools 1.0.9">
+ <TITLE>YAZ User's Guide and Reference: Supporting Tools</TITLE>
+ <LINK HREF="yaz-5.html" REL=next>
+ <LINK HREF="yaz-3.html" REL=previous>
+ <LINK HREF="yaz.html#toc4" REL=contents>
+</HEAD>
+<BODY>
+<A HREF="yaz-5.html">Next</A>
+<A HREF="yaz-3.html">Previous</A>
+<A HREF="yaz.html#toc4">Contents</A>
+<HR>
+<H2><A NAME="s4">4. Supporting Tools</A></H2>
+
+<P>In support of the service API - primarily the ASN module, which
+provides the programmatic interface to the Z39.50 APDUs, YAZ contains
+a collection of tools that support the development of applications.
+<P>
+<H2><A NAME="ss4.1">4.1 Query Syntax Parsers</A>
+</H2>
+
+<P>Since the type-1 (RPN) query structure has no direct, useful string
+representation, every origin application needs to provide some form of
+mapping from a local query notation or representation to a
+<CODE>Z_RPNQuery</CODE> structure. Some programmers will prefer to construct
+the query manually, perhaps using <CODE>odr_malloc()</CODE> to simplify memory
+management. The YAZ distribution includes two separate,
+query-generating tools that may be of use to you.
+<P>
+<H3>Prefix Query Format</H3>
+
+<P>Since RPN or reverse polish notation is really just a fancy way of
+describing a suffix notation format (operator follows operands), it
+would seem that the confusion is total when we now introduce a prefix
+notation for RPN. The reason is one of simple laziness - it's somewhat
+simpler to interpret a prefix format, and this utility was designed
+for maximum simplicity, to provide a baseline representation for use
+in simple test applications and scripting environments (like Tcl). The
+demonstration client included with YAZ uses the PQF.
+<P>The PQF is defined by the pquery module in the YAZ library. The
+<CODE>pquery.h</CODE> file provides the declaration of the functions
+<P>
+<BLOCKQUOTE><CODE>
+<PRE>
+Z_RPNQuery *p_query_rpn (ODR o, oid_proto proto, const char *qbuf);
+
+Z_AttributesPlusTerm *p_query_scan (ODR o, oid_proto proto,
+      Odr_oid **attributeSetP, const char *qbuf);
+
+int p_query_attset (const char *arg);
+</PRE>
+</CODE></BLOCKQUOTE>
+<P>The function <CODE>p_query_rpn()</CODE> takes as arguments an <B>ODR</B> stream
+(see section 
+<A HREF="yaz-5.html#odr">The ODR Module</A>) to provide a memory
+source (the structure created is released on the next call to
+<CODE>odr_reset()</CODE> on the stream/), a protocol identifier (one of the
+constants <CODE>PROTO_Z3950</CODE> and <CODE>PROTO_SR</CODE>), an attribute set
+reference, and finally a null-terminated string holding the query
+string.
+<P>If the parse went well, <CODE>p_query_rpn()</CODE> returns a pointer to a
+<CODE>Z_RPNQuery</CODE> structure which can be placed directly into a
+<CODE>Z_SearchRequest</CODE>.
+<P>The <CODE>p_query_attset</CODE> specifies which attribute set to use if
+the query doesn't specify one by the <CODE>@attrset</CODE> operator. The
+<CODE>p_query_attset</CODE> returns 0 if the argument is a valid attribute
+set specifier; otherwise the function returns -1.
+<P>The grammar of the PQF is as follows:
+<P>
+<BLOCKQUOTE><CODE>
+<PRE>
+Query ::= [ AttSet ] QueryStruct.
+
+AttSet ::= string.
+
+QueryStruct ::= { Attribute } Simple | Complex.
+
+Attribute ::= '@attr' AttributeType '=' AttributeValue.
+
+AttributeType ::= integer.
+
+AttributeValue ::= integer.
+
+Complex ::= Operator QueryStruct QueryStruct.
+
+Operator ::= '@and' | '@or' | '@not' | '@prox' Proximity.
+
+Simple ::= ResultSet | Term.
+
+ResultSet ::= '@set' string.
+
+Term ::= string | '"' string '"'.
+
+Proximity ::= Exclusion Distance Ordered Relation WhichCode UnitCode.
+
+Exclusion ::= '1' | '0' | 'void'.
+
+Distance ::= integer.
+
+Ordered ::= '1' | '0'.
+
+Relation ::= integer.
+
+WhichCode ::= 'known' | 'private' | integer.
+
+UnitCode ::= integer.
+</PRE>
+</CODE></BLOCKQUOTE>
+<P>You will note that the syntax above is a fairly faithful
+representation of RPN, except for the <CODE>Attibute</CODE>, which has been
+moved a step away from the term, allowing you to associate one or more
+attributes with an entire query structure. The parser will
+automatically apply the given attributes to each term as required.
+<P>The following are all examples of valid queries in the PQF.
+<P>
+<BLOCKQUOTE><CODE>
+<PRE>
+dylan
+
+"bob dylan"
+
+@or "dylan" "zimmerman"
+
+@set Result-1
+
+@or @and bob dylan @set Result-1
+
+@attr 4=1 @and @attr 1=1 "bob dylan" @attr 1=4 "slow train coming"
+
+@attr 4=1 @attr 1=4 "self portrait"
+
+@prox 0 3 1 2 k 2 dylan zimmerman
+</PRE>
+</CODE></BLOCKQUOTE>
+<P>
+<H3>Common Command Language</H3>
+
+<P>Not all users enjoy typing in prefix query structures and numerical
+attribute values, even in a minimalistic test client. In the library
+world, the more intuitive Common Command Language (or ISO 8777) has
+enjoyed some popularity - especially before the widespread
+availability of graphical interfaces. It is still useful in
+applications where you for some reason or other need to provide a
+symbolic language for expressing boolean query structures.
+<P>The EUROPAGATE research project working under the Libraries programme
+of the European Commission's DG XIII has, amongst other useful tools,
+implemented a general-purpose CCL parser which produces an output
+structure that can be trivially converted to the internal RPN
+representation of YAZ (The <CODE>Z_RPNQuery</CODE> structure). Since the CCL
+utility - along with the rest of the software produced by EUROPAGATE -
+is made freely available on a liberal license, it is included as a
+supplement to YAZ.
+<P>
+<H3>CCL Syntax</H3>
+
+<P>The CCL parser obeys the following grammar for the FIND argument.
+The syntax is annotated by in the lines prefixed by <CODE>--</CODE>.
+<P>
+<BLOCKQUOTE><CODE>
+<PRE>
+CCL-Find ::= CCL-Find Op Elements
+           | Elements.
+
+Op ::= "and" | "or" | "not"
+-- The above means that Elements are separated by boolean operators.
+
+Elements ::= '(' CCL-Find ')'
+           | Set
+           | Terms
+           | Qualifiers Relation Terms
+           | Qualifiers Relation '(' CCL-Find ')'
+           | Qualifiers '=' string '-' string
+-- Elements is either a recursive definition, a result set reference, a
+-- list of terms, qualifiers followed by terms, qualifiers followed
+-- by a recursive definition or qualifiers in a range (lower - upper).
+
+Set ::= 'set' = string
+-- Reference to a result set
+
+Terms ::= Terms Prox Term
+        | Term
+-- Proximity of terms.
+
+Term ::= Term string
+       | string
+-- This basically means that a term may include a blank
+
+Qualifiers ::= Qualifiers ',' string
+             | string
+-- Qualifiers is a list of strings separated by comma
+
+Relation ::= '=' | '>=' | '&lt;=' | '&lt;>' | '>' | '&lt;'
+-- Relational operators. This really doesn't follow the ISO8777
+-- standard.
+
+Prox ::= '%' | '!'
+-- Proximity operator
+</PRE>
+</CODE></BLOCKQUOTE>
+<P>The following queries are all valid:
+<P>
+<BLOCKQUOTE><CODE>
+<PRE>
+dylan
+
+"bob dylan"
+
+dylan or zimmerman
+
+set=1
+
+(dylan and bob) or set=1
+</PRE>
+</CODE></BLOCKQUOTE>
+
+Assuming that the qualifiers <CODE>ti</CODE>, <CODE>au</CODE> and <CODE>date</CODE> 
+are defined we may use:
+<BLOCKQUOTE><CODE>
+<PRE>
+ti=self portrait
+
+au=(bob dylan and slow train coming)
+
+date>1980 and (ti=((self portrait)))
+</PRE>
+</CODE></BLOCKQUOTE>
+<P>
+<H3>CCL Qualifiers</H3>
+
+<P>
+<P>Qualifiers are used to direct the search to a particular searchable
+index, such as title (ti) and author indexes (au). The CCL standard
+itself doesn't specify a particular set of qualifiers, but it does
+suggest a few short-hand notations. You can customize the CCL parser
+to support a particular set of qualifiers to relect the current target
+profile. Traditionally, a qualifier would map to a particular
+use-attribute within the BIB-1 attribute set. However, you could also
+define qualifiers that would set, for example, the
+structure-attribute.
+<P>Consider a scenario where the target support ranked searches in the
+title-index. In this case, the user could specify
+<BLOCKQUOTE><CODE>
+<PRE>
+ti,ranked=knuth computer
+</PRE>
+</CODE></BLOCKQUOTE>
+
+and the <CODE>ranked</CODE> would map to structure=free-form-text
+(4=105) and the <CODE>ti</CODE> would map to title (1=4).
+<P>A "profile" with a set predefined CCL qualifiers can be read from a
+file. The YAZ client reads its CCL qualifiers from a file named
+<CODE>default.bib</CODE>. Each line in the file has the form:
+<P><I>qualifier-name</I>    <I>type</I>=<I>val</I> <I>type</I>=<I>val</I> ...
+<P>where <I>qualifier-name</I> is the name of the qualifier to be used
+(eg. <CODE>ti</CODE>), <I>type</I> is a BIB-1 category type and <I>val</I> is the
+corresponding BIB-1 attribute value. The <I>type</I> can be either
+numeric or it may be either <CODE>u</CODE> (use), <CODE>r</CODE> (relation), <CODE>p</CODE>
+(position), <CODE>s</CODE> (structure), <CODE>t</CODE> (truncation) or <CODE>c</CODE>
+(completeness). The <I>qualifier-name</I> <CODE>term</CODE> has a special
+meaning. The types and values for this definition is used when <I>no</I>
+qualifier is present.
+<P>Consider the following definition:
+<BLOCKQUOTE><CODE>
+<PRE>
+ti       u=4 s=1
+au       u=1 s=1
+term     s=105
+</PRE>
+</CODE></BLOCKQUOTE>
+
+Two qualifiers are defined, <CODE>ti</CODE> and <CODE>au</CODE>. They both set the
+structure-attribute to phrase (1). <CODE>ti</CODE> sets the use-attribute to
+4. <CODE>au</CODE> sets the use-attribute to 1. When no qualifiers are used
+in the query the structure-attribute is set to free-form-text (105).
+<P>
+<H3>CCL API</H3>
+
+<P>
+<P>All public definitions can be found in the header file <CODE>ccl.h</CODE>.
+A profile identifier is of type <CODE>CCL_bibset</CODE>. A profile must be
+created with the call to the function <CODE>ccl_qual_mk</CODE> which returns
+a profile handle of type <CODE>CCL_bibset</CODE>.
+<P>To read a file containing qualifier definitions the function
+<CODE>ccl_qual_file</CODE> may be convenient. This function takes an already
+opened <CODE>FILE</CODE> handle pointer as argument along with a
+<CODE>CCL_bibset</CODE> handle.
+<P>To parse a simple string with a FIND query use the function
+<BLOCKQUOTE><CODE>
+<PRE>
+struct ccl_rpn_node *ccl_find_str (CCL_bibset bibset, const char *str,
+                                   int *error, int *pos);
+</PRE>
+</CODE></BLOCKQUOTE>
+
+which takes the CCL profile (<CODE>bibset</CODE>) and query (<CODE>str</CODE>) as
+input. Upon successful completion the RPN tree is returned. If an
+error eccur, such as a syntax error, the integer pointed to by
+<CODE>error</CODE> holds the error code and <CODE>pos</CODE> holds the offset inside
+query string in which the parsing failed.
+<P>An english representation of the error may be obtained by calling
+the <CODE>ccl_err_msg</CODE> function. The error codes are listed in
+<CODE>ccl.h</CODE>.
+<P>To convert the CCL RPN tree (type <CODE>struct ccl_rpn_node *</CODE>) to the
+Z_RPNQuery of YAZ the function <CODE>ccl_rpn_query</CODE> must be used. This
+function which is part of YAZ is implemented in <CODE>yaz-ccl.c</CODE>.
+After calling this function the CCL RPN tree is probably no longer
+needed. The <CODE>ccl_rpn_delete</CODE> destroys the CCL RPN tree.
+<P>A CCL profile may be destroyed by calling the <CODE>ccl_qual_rm</CODE>
+function.
+<P>The token names for the CCL operators may be changed by setting the
+globals (all type <CODE>char *</CODE>) <CODE>ccl_token_and</CODE>, <CODE>ccl_token_or</CODE>,
+<CODE>ccl_token_not</CODE> and <CODE>ccl_token_set</CODE>.
+An operator may have aliases, i.e. there may be more than one name for
+the operator. To do this, separate each alias with a space character.
+<P>
+<H2><A NAME="ss4.2">4.2 Object Identifiers</A>
+</H2>
+
+<P>The basic YAZ representation of an OID is an array of integers,
+terminated with the value -1. The <B>ODR</B> module provides two
+utility-functions to create and copy this type of data elements:
+<P>
+<BLOCKQUOTE><CODE>
+<PRE>
+Odr_oid *odr_getoidbystr(ODR o, char *str);
+</PRE>
+</CODE></BLOCKQUOTE>
+<P>Creates an OID based on a string-based representation using dots (.)
+to separate elements in the OID.
+<P>
+<BLOCKQUOTE><CODE>
+<PRE>
+Odr_oid *odr_oiddup(ODR odr, Odr_oid *o);
+</PRE>
+</CODE></BLOCKQUOTE>
+<P>Creates a copy of the OID referenced by the <I>o</I> parameter. Both
+functions take an <B>ODR</B> stream as parameter. This stream is used to
+allocate memory for the data elements, which is released on a
+subsequent call to <CODE>odr_reset()</CODE> on that stream.
+<P>The <B>OID</B> module provides a higher-level representation of the
+family of object identifers which describe the Z39.50 protocol and its
+related objects. The definition of the module interface is given in
+the <CODE>oid.h</CODE> file.
+<P>The interface is mainly based on the <CODE>oident</CODE> structure. The
+definition of this structure looks like this:
+<P>
+<BLOCKQUOTE><CODE>
+<PRE>
+typedef struct oident
+{
+    oid_proto proto;
+    oid_class oclass;
+    oid_value value;
+    int oidsuffix[OID_SIZE];
+    char *desc;
+} oident;
+</PRE>
+</CODE></BLOCKQUOTE>
+<P>The <I>proto</I> field takes one of the values
+<P>
+<BLOCKQUOTE><CODE>
+<PRE>
+PROTO_Z3950
+PROTO_SR
+</PRE>
+</CODE></BLOCKQUOTE>
+<P>If you don't care about talking to SR-based implementations (few
+exist, and they may become fewer still if and when the ISO SR and ANSI
+Z39.50 documents are merged into a single standard), you can ignore
+this field on incoming packages, and always set it to PROTO_Z3950
+for outgoing packages.
+<P>The <I>oclass</I> field takes one of the values
+<P>
+<BLOCKQUOTE><CODE>
+<PRE>
+CLASS_APPCTX
+CLASS_ABSYN
+CLASS_ATTSET
+CLASS_TRANSYN
+CLASS_DIAGSET
+CLASS_RECSYN
+CLASS_RESFORM
+CLASS_ACCFORM
+CLASS_EXTSERV
+CLASS_USERINFO
+CLASS_ELEMSPEC
+CLASS_VARSET
+CLASS_SCHEMA
+CLASS_TAGSET
+CLASS_GENERAL
+</PRE>
+</CODE></BLOCKQUOTE>
+<P>corresponding to the OID classes defined by the Z39.50 standard.
+<P>Finally, the <I>value</I> field takes one of the values
+<P>
+<BLOCKQUOTE><CODE>
+<PRE>
+VAL_APDU
+VAL_BER
+VAL_BASIC_CTX
+VAL_BIB1
+VAL_EXP1
+VAL_EXT1
+VAL_CCL1
+VAL_GILS
+VAL_WAIS
+VAL_STAS
+VAL_DIAG1
+VAL_ISO2709
+VAL_UNIMARC
+VAL_INTERMARC
+VAL_CCF
+VAL_USMARC
+VAL_UKMARC
+VAL_NORMARC
+VAL_LIBRISMARC
+VAL_DANMARC
+VAL_FINMARC
+VAL_MAB
+VAL_CANMARC
+VAL_SBN
+VAL_PICAMARC
+VAL_AUSMARC
+VAL_IBERMARC
+VAL_EXPLAIN
+VAL_SUTRS
+VAL_OPAC
+VAL_SUMMARY
+VAL_GRS0
+VAL_GRS1
+VAL_EXTENDED
+VAL_RESOURCE1
+VAL_RESOURCE2
+VAL_PROMPT1
+VAL_DES1
+VAL_KRB1
+VAL_PRESSET
+VAL_PQUERY
+VAL_PCQUERY
+VAL_ITEMORDER
+VAL_DBUPDATE
+VAL_EXPORTSPEC
+VAL_EXPORTINV
+VAL_NONE
+VAL_SETM
+VAL_SETG
+VAL_VAR1
+VAL_ESPEC1
+</PRE>
+</CODE></BLOCKQUOTE>
+<P>again, corresponding to the specific OIDs defined by the standard.
+<P>The <I>desc</I> field contains a brief, mnemonic name for the OID in
+question.
+<P>The function
+<P>
+<BLOCKQUOTE><CODE>
+<PRE>
+struct oident *oid_getentbyoid(int *o);
+</PRE>
+</CODE></BLOCKQUOTE>
+<P>takes as argument an OID, and returns a pointer to a static area
+containing an <CODE>oident</CODE> structure. You typically use this function
+when you receive a PDU containing an OID, and you wish to branch out
+depending on the specific OID value.
+<P>The function
+<P>
+<BLOCKQUOTE><CODE>
+<PRE>
+int *oid_ent_to_oid(struct oident *ent, int *dst);
+</PRE>
+</CODE></BLOCKQUOTE>
+<P>Takes as argument an <CODE>oident</CODE> structure - in which the <I>proto</I>,
+<I>oclass</I>, and <I>value</I> fields are assumed to be set correctly -
+and returns a pointer to a the buffer as given by <I>dst</I> 
+containing the base
+representation of the corresponding OID. The function returns
+NULL and the array dst is unchanged if a mapping couldn't place.
+The array <I>dst</I> should be at least of size <CODE>OID_SIZE</CODE>.
+<P>The <CODE>oid_ent_to_oid()</CODE> function can be used whenever you need to
+prepare a PDU containing one or more OIDs. The separation of the
+<I>protocol</I> element from the remainer of the OID-description makes
+it simple to write applications that can communicate with either
+Z39.50 or OSI SR-based applications.
+<P>The function
+<P>
+<BLOCKQUOTE><CODE>
+<PRE>
+oid_value oid_getvalbyname(const char *name);
+</PRE>
+</CODE></BLOCKQUOTE>
+<P>takes as argument a mnemonic OID name, and returns the <I>value</I>
+field of the first entry in the database that contains the given name
+in its <I>desc</I> field.
+<P>Finally, the module provides the following utility functions, whose
+meaning should be obvious:
+<P>
+<BLOCKQUOTE><CODE>
+<PRE>
+void oid_oidcpy(int *t, int *s);
+void oid_oidcat(int *t, int *s);
+int oid_oidcmp(int *o1, int *o2);
+int oid_oidlen(int *o);
+</PRE>
+</CODE></BLOCKQUOTE>
+<P><I>NOTE: The <B>OID</B> module has been criticized - and perhaps rightly so
+- for needlessly abstracting the
+representation of OIDs. Other toolkits use a simple
+string-representation of OIDs with good results. In practice, we have
+found the interface comfortable and quick to work with, and it is a
+simple matter (for what it's worth) to create applications compatible
+with both ISO SR and Z39.50. Finally, the use of the <CODE>oident</CODE>
+database is by no means mandatory. You can easily create your
+own system for representing OIDs, as long as it is compatible with the
+low-level integer-array representation of the ODR module.</I>
+<P>
+<H2><A NAME="ss4.3">4.3 Nibble Memory</A>
+</H2>
+
+<P>Sometimes when you need to allocate and construct a large,
+interconnected complex of structures, it can be a bit of a pain to
+release the associated memory again. For the structures describing the
+Z39.50 PDUs and related structures, it is convenient to use the
+memory-management system of the <B>ODR</B> subsystem (see
+<A HREF="yaz-5.html#odr-use">Using ODR</A>). However, in some circumstances
+where you might otherwise benefit from using a simple nibble memory
+management system, it may be impractical to use <CODE>odr_malloc()</CODE> and
+<B>odr_reset()</B>. For this purpose, the memory manager which also
+supports the <B>ODR</B> streams is made available in the <B>NMEM</B>
+module. The external interface to this module is given in the
+<CODE>nmem.h</CODE> file.
+<P>The following prototypes are given:
+<P>
+<BLOCKQUOTE><CODE>
+<PRE>
+NMEM nmem_create(void);
+void nmem_destroy(NMEM n);
+void *nmem_malloc(NMEM n, int size);
+void nmem_reset(NMEM n);
+int nmem_total(NMEM n);
+void nmem_init(void);
+</PRE>
+</CODE></BLOCKQUOTE>
+<P>The <CODE>nmem_create()</CODE> function returns a pointer to a memory control
+handle, which can be released again by <CODE>nmem_destroy()</CODE> when no
+longer needed. The function <CODE>nmem_malloc()</CODE> allocates a block of
+memory of the requested size. A call to <CODE>nmem_reset()</CODE> or
+<CODE>nmem_destroy()</CODE> will release all memory allocated on the handle
+since it was created (or since the last call to
+<CODE>nmem_reset()</CODE>. The function <CODE>nmem_total()</CODE> returns the number
+of bytes currently allocated on the handle.
+<P>Note that the nibble memory pool is shared amonst threads. Posix
+mutex'es and WIN32 Critical sections are introduced to keep the
+module thread safe. On WIN32 function <CODE>nmem_init()</CODE> initialises
+the Critical Section handle and should be called once before any
+other nmem function is used.
+<P>
+<HR>
+<A HREF="yaz-5.html">Next</A>
+<A HREF="yaz-3.html">Previous</A>
+<A HREF="yaz.html#toc4">Contents</A>
+</BODY>
+</HTML>
Index: /main/tags/2.25/gsdl/packages/yaz/doc/yaz-5.html
===================================================================
--- /main/tags/2.25/gsdl/packages/yaz/doc/yaz-5.html	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/yaz/doc/yaz-5.html	(revision 21064)
@@ -0,0 +1,996 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN">
+<HTML>
+<HEAD>
+ <META NAME="GENERATOR" CONTENT="SGML-Tools 1.0.9">
+ <TITLE>YAZ User's Guide and Reference: The ODR Module</TITLE>
+ <LINK HREF="yaz-6.html" REL=next>
+ <LINK HREF="yaz-4.html" REL=previous>
+ <LINK HREF="yaz.html#toc5" REL=contents>
+</HEAD>
+<BODY>
+<A HREF="yaz-6.html">Next</A>
+<A HREF="yaz-4.html">Previous</A>
+<A HREF="yaz.html#toc5">Contents</A>
+<HR>
+<H2><A NAME="odr"></A> <A NAME="s5">5. The ODR Module</A></H2>
+
+<H2><A NAME="ss5.1">5.1 Introduction</A>
+</H2>
+
+<P><B>ODR</B> is the BER-encoding/decoding subsystem of <B>YAZ</B>. Care as been taken
+to isolate <B>ODR</B> from the rest of the package - specifically from the
+transport interface. <B>ODR</B> may be used in any context where basic
+ASN.1/BER representations are used.
+<P>If you are only interested in writing a Z39.50 implementation based on
+the PDUs that are already provided with <B>YAZ</B>, you only need to concern
+yourself with the section on managing ODR streams (section
+<A HREF="#odr-use">Using ODR</A>). Only if you need to
+implement ASN.1 beyond that which has been provided, should you
+worry about the second half of the documentation
+(section 
+<A HREF="#odr-prog">Programming with ODR</A>). If you use
+one of the higher-level interfaces, you can skip this section entirely.
+<P>This is important, so we'll repeat it for emphasis: <I>You do not
+need to read section 
+<A HREF="#odr-prog">Programming with ODR</A> to
+implement Z39.50 with <B>YAZ</B>.</I>
+<P>If you need a part of the protocol that isn't already in <B>YAZ</B>, you
+should
+contact the authors before going to work on it yourself: We
+might already be working on it. Conversely, if you implement a useful
+part of the protocol before us, we'd be happy to include it in a
+future release.
+<P>
+<H2><A NAME="odr-use"></A> <A NAME="ss5.2">5.2 Using ODR</A>
+</H2>
+
+<P>
+<H3>ODR Streams</H3>
+
+<P>Conceptually, the ODR stream is the source of encoded data in the
+decoding mode; when encoding, it is the receptacle for the encoded
+data. Before you can use an ODR stream it must be allocated. This is
+done with the function
+<P>
+<BLOCKQUOTE><CODE>
+<PRE>
+ODR odr_createmem(int direction);
+</PRE>
+</CODE></BLOCKQUOTE>
+<P>The <CODE>odr_createmem()</CODE> function takes as argument one of three manifest
+constants: <CODE>ODR_ENCODE</CODE>, <CODE>ODR_DECODE</CODE>, or <CODE>ODR_PRINT</CODE>. An
+ODR stream can be
+in only one mode - it is not possible to change its mode once it's
+selected. Typically, your program will allocate at least two ODR
+streams - one for decoding, and one for encoding.
+<P>When you're done with the stream, you can use
+<P>
+<BLOCKQUOTE><CODE>
+<PRE>
+void odr_destroy(ODR o);
+</PRE>
+</CODE></BLOCKQUOTE>
+<P>to release the resources allocated for the stream.
+<P>
+<H3><A NAME="memory"></A> Memory Management</H3>
+
+<P>Two forms of memory management take place in the ODR system. The first
+one, which has to do with allocating little bits of memory (sometimes
+quite large bits of memory, actually) when a protocol package is
+decoded, and turned into a complex of interlinked structures. This
+section deals with this system, and how you can use it for your own
+purposes. The next section deals with the memory management which is
+required when encoding data - to make sure that a large enough buffer is
+available to hold the fully encoded PDU.
+<P>The <B>ODR</B> module has its own memory management system, which is
+used whenever memory is required. Specifically, it is used to allocate
+space for data when decoding incoming PDUs. You can use the memory
+system for your own purposes, by using the function
+<P>
+<BLOCKQUOTE><CODE>
+<PRE>
+void *odr_malloc(ODR o, int size);
+</PRE>
+</CODE></BLOCKQUOTE>
+<P>You can't use the normal <CODE>free</CODE>(2) routine to free memory allocated
+by this function, and <B>ODR</B> doesn't provide a parallel function. Instead,
+you can call
+<P>
+<BLOCKQUOTE><CODE>
+<PRE>
+void odr_reset(ODR o, int size);
+</PRE>
+</CODE></BLOCKQUOTE>
+<P>when you are done with the
+memory: Everything allocated since the last call to <CODE>odr_reset()</CODE> is
+released. The <CODE>odr_reset()</CODE> call is also required to clear up an
+error condition on a stream.
+<P>The function
+<P>
+<BLOCKQUOTE><CODE>
+<PRE>
+int odr_total(ODR o);
+</PRE>
+</CODE></BLOCKQUOTE>
+<P>returns the number of bytes allocated on the stream since the last call to
+<CODE>odr_reset()</CODE>.
+<P>The memory subsystem of <B>ODR</B> is fairly efficient at allocating and
+releasing little bits of memory. Rather than managing the individual,
+small bits of space, the system maintains a freelist of larger chunks
+of memory, which are handed out in small bits. This scheme is
+generally known as a <I>nibble memory</I> system. It is very useful for
+maintaing short-lived constructions such as protocol PDUs.
+<P>If you want to retain a bit of memory beyond the next call to
+<CODE>odr_reset()</CODE>, you can use the function
+<P>
+<BLOCKQUOTE><CODE>
+<PRE>
+ODR_MEM odr_extract_mem(ODR o);
+</PRE>
+</CODE></BLOCKQUOTE>
+<P>This function will give you control of the memory recently allocated
+on the ODR stream. The memory will live (past calls to <CODE>odr_reset()</CODE>),
+until you call the function
+<P>
+<BLOCKQUOTE><CODE>
+<PRE>
+void odr_release_mem(ODR_MEM p);
+</PRE>
+</CODE></BLOCKQUOTE>
+<P>The opaque <CODE>ODR_MEM</CODE> handle has no other purpose than referencing
+the memory block for you until you want to release it.
+<P>You can use <CODE>odr_extract_mem()</CODE> repeatedly between allocating data,
+to retain individual control of separate chunks of data.
+<P>
+<H3>Encoding and Decoding Data</H3>
+
+<P>When encoding data, the ODR stream will write the encoded octet string
+in an internal buffer. To retrieve the data, use the function
+<P>
+<BLOCKQUOTE><CODE>
+<PRE>
+char *odr_getbuf(ODR o, int *len, int *size);
+</PRE>
+</CODE></BLOCKQUOTE>
+<P>The integer pointed to by len is set to the length of the encoded
+data, and a pointer to that data is returned. *<CODE>size</CODE> is set to the size
+of the buffer (unless <CODE>size</CODE> is null, signalling that you are
+not interested in the size). The next call to a primitive function
+using the same ODR stream will overwrite the data, unless a different
+buffer has been supplied using the call
+<P>
+<BLOCKQUOTE><CODE>
+<PRE>
+void odr_setbuf(ODR o, char *buf, int len, int can_grow);
+</PRE>
+</CODE></BLOCKQUOTE>
+<P>which sets the encoding (or decoding) buffer used by <CODE>o</CODE> to
+<CODE>buf</CODE>,
+using the length <CODE>len</CODE>. Before a call to an encoding function,
+you can use <CODE>odr_setbuf()</CODE> to provide the stream with an encoding buffer
+of sufficient size (length). The <CODE>can_grow</CODE> parameter tells the encoding
+ODR stream whether it is allowed to use <CODE>realloc</CODE>(2) to increase the size
+of the buffer when necessary. The default condition of a new encoding
+stream is equivalent to the results of calling
+<P>
+<BLOCKQUOTE><CODE>
+<PRE>
+odr_setbuf(stream, 0, 0, 1);
+</PRE>
+</CODE></BLOCKQUOTE>
+<P>In this case, the stream will allocate and reallocate memory as
+necessary. The stream reallocates memory by repeatedly doubling the
+size of the buffer - the result is that the buffer will typically
+reach its maximum, working size with only a small number of reallocation
+operations. The memory is freed by the stream when the latter is destroyed,
+unless it was assigned by the user with the <CODE>can_grow</CODE>
+parameter set to zero (in this case, you are expected to retain
+control of the memory yourself).
+<P>To assume full control of an encoded buffer, you must first call
+<CODE>odr_getbuf()</CODE> to fetch the buffer and its length. Next, you should
+call <CODE>odr_setbuf()</CODE> to provide a different buffer (or a null
+pointer) to the stream. In the simplest case, you will reuse the same
+buffer over and over again, and you will just need to call
+<CODE>odr_getbuf()</CODE> after each encoding operation to get the length and
+address of the buffer. Note that the stream may reallocate the buffer
+during an encoding operation, so it is necessary to retrieve the
+correct address after each encoding operation.
+<P>It is important to realise that the ODR stream will not release this
+memory when you call <CODE>odr_reset()</CODE>: It will merely update its
+internal pointers to prepare for the encoding of a new data value.
+When the stream is released by the <CODE>odr_destroy()</CODE> function, the
+memory given to it by odr_setbuf will be released <I>only</I> if the
+<CODE>can_grow</CODE> parameter to <CODE>odr_setbuf()</CODE> was nonzero. The
+<CODE>can_grow</CODE> parameter, in other words, is a way of signalling who
+is to own the buffer, you or the ODR stream. If you never call
+<CODE>odr_setbuf()</CODE> on your encoding stream, which is typically the
+case, the buffer allocated by the stream will belong to the stream by
+default.
+<P>When you wish to decode data, you should first call <CODE>odr_setbuf()</CODE>, to
+tell the decoding stream where to find the encoded data, and how long
+the buffer is (the <CODE>can_grow</CODE> parameter is ignored by a decoding
+stream). After this, you can call the function corresponding to the
+data you wish to decode (eg, <CODE>odr_integer()</CODE> odr <CODE>z_APDU()</CODE>).
+<P>Examples of encoding/decoding functions:
+<P>
+<BLOCKQUOTE><CODE>
+<PRE>
+int odr_integer(ODR o, int **p, int optional, const char *name);
+
+int z_APDU(ODR o, Z_APDU **p, int optional, const char *name);
+</PRE>
+</CODE></BLOCKQUOTE>
+<P>If the data is absent (or
+doesn't match the tag corresponding to the type), the return value
+will be either 0 or 1 depending on the <CODE>optional</CODE> flag. If
+<CODE>optional</CODE>
+is 0 and the data is absent, an error flag will be raised in the
+stream, and you'll need to call <CODE>odr_reset()</CODE> before you can use the
+stream again. If <CODE>optional</CODE> is nonzero, the pointer <I>pointed to</I> by
+<CODE>p</CODE> will be set to the null value, and the function will return 1.
+The <CODE>name</CODE> argument is used to pretty-print the tag in question.
+It may be set to <CODE>NULL</CODE> if pretty-printing is not desired.
+<P>If the data value is found where it's expected, the pointer
+<I>pointed to</I> by the <CODE>p</CODE> argument will be set to point to the
+decoded type. The
+space for the type will be allocated and owned by the ODR stream, and
+it will live until you call <CODE>odr_reset()</CODE> on the stream. You cannot use
+<CODE>free</CODE>(2) to release the memory. You can decode several data elements
+(by repeated calls to <CODE>odr_setbuf()</CODE> and your decoding function), and
+new memory will be allocated each time. When you do call
+<CODE>odr_reset()</CODE>,
+everything decoded since the last call to <CODE>odr_reset()</CODE> will be
+released.
+<P>The use of the double indirection can be a little confusing at first
+(its purpose will become clear later on, hopefully),
+so an example is in order. We'll encode an integer value, and
+immediately decode it again using a different stream. A useless, but
+informative operation.
+<P>
+<BLOCKQUOTE><CODE>
+<PRE>
+void do_nothing_useful(int value)
+{
+    ODR encode, decode;
+    int *valp, *resvalp;
+    char *bufferp;
+    int len;
+
+    /* allocate streams */
+    if (!(encode = odr_createmem(ODR_ENCODE)))
+        return;
+    if (!(decode = odr_createmem(ODR_DECODE)))
+        return;
+
+    valp = &amp;value;
+    if (odr_integer(encode, &amp;valp, 0, 0) == 0)
+    {
+        printf("encoding went bad\n");
+        return;
+    }
+    bufferp = odr_getbuf(encode, &amp;len);
+    printf("length of encoded data is %d\n", len);
+
+    /* now let's decode the thing again */
+    odr_setbuf(decode, bufferp, len);
+    if (odr_integer(decode, &amp;resvalp, 0, 0) == 0)
+    {
+        printf("decoding went bad\n");
+        return;
+    }
+    printf("the value is %d\n", *resvalp);
+
+    /* clean up */
+    odr_destroy(encode);
+    odr_destroy(decode);
+}
+</PRE>
+</CODE></BLOCKQUOTE>
+<P>This looks like a lot of work, offhand. In practice, the ODR streams
+will typically be allocated once, in the beginning of your program (or at the
+beginning of a new network session), and the encoding and decoding
+will only take place in a few, isolated places in your program, so the
+overhead is quite manageable.
+<P>
+<H3>Diagnostics</H3>
+
+<P>The encoding/decoding functions all return 0 when an error occurs.
+Until you call <CODE>odr_reset()</CODE>, you cannot use the stream again, and
+any function called will immediately return 0.
+<P>To provide information to the programmer or administrator, the
+function
+<P>
+<BLOCKQUOTE><CODE>
+<PRE>
+void odr_perror(ODR o, char *message);
+</PRE>
+</CODE></BLOCKQUOTE>
+<P>is provided, which prints the <CODE>message</CODE> argument to <CODE>stderr</CODE>
+along with an error message from the stream.
+<P>You can also use the function
+<P>
+<BLOCKQUOTE><CODE>
+<PRE>
+int odr_geterror(ODR o);
+</PRE>
+</CODE></BLOCKQUOTE>
+<P>to get the current error number from the screen. The number will be
+one of these constants:
+<P>
+<DL>
+<DT><B>OMEMORY</B><DD><P>Memory allocation failed.
+<DT><B>OSYSERR</B><DD><P>A system- or library call has failed. The standard
+diagnostic variable <CODE>errno</CODE>
+should be examined to determine the actual error.
+<DT><B>OSPACE</B><DD><P>No more space for encoding. This will only occur when the user has
+explicitly provided a buffer for an encoding stream without allowing
+the system to allocate more space.
+<DT><B>OREQUIRED</B><DD><P>This is a common protocol error; A required data element was
+missing during
+encoding or decoding.
+<DT><B>OUNEXPECTED</B><DD><P>An unexpected data element was found during decoding.
+<DT><B>OOTHER</B><DD><P>Other error. This is typically an indication of misuse of
+the <B>ODR</B> system by the programmer, and also that the diagnostic
+system isn't as good as it should be, yet.
+</DL>
+<P>The character string array
+<P>
+<BLOCKQUOTE><CODE>
+<PRE>
+char *odr_errlist[]
+</PRE>
+</CODE></BLOCKQUOTE>
+<P>can be indexed by the error code to obtain a human-readable
+representation of the problem.
+<P>
+<H3>Summary and Synopsis</H3>
+
+<P>
+<BLOCKQUOTE><CODE>
+<PRE>
+#include &lt;odr.h>
+
+ODR odr_createmem(int direction);
+
+void odr_destroy(ODR o);
+
+void odr_reset(ODR o);
+
+char *odr_getbuf(ODR o, int *len);
+
+void odr_setbuf(ODR o, char *buf, int len);
+
+void *odr_malloc(ODR o, int size);
+
+ODR_MEM odr_extract_mem(ODR o);
+
+void odr_release_mem(ODR_MEM r);
+
+int odr_geterror(ODR o);
+
+void odr_perror(char *message);
+
+extern char *odr_errlist[];
+</PRE>
+</CODE></BLOCKQUOTE>
+<P>
+<H2><A NAME="odr-prog"></A> <A NAME="ss5.3">5.3 Programming with ODR</A>
+</H2>
+
+<P>The API of <B>ODR</B> is designed to reflect the structure of ASN.1, rather
+than BER itself. Future releases may be able to represent data in
+other external forms.
+<P>The interface is based loosely on that of the Sun Microsystems XDR routines.
+Specifically, each function which corresponds to an ASN.1 primitive
+type has a dual function. Depending on the settings of the ODR
+stream which is supplied as a parameter, the function may be used
+either to encode or decode data. The functions that can be built
+using these primitive functions, to represent more complex datatypes, share
+this quality. The result is that you only have to enter the definition
+for a type once - and you have the functionality of encoding, decoding
+(and pretty-printing) all in one unit. The resulting C source code is
+quite compact, and is a pretty straightforward representation of the
+source ASN.1 specification. Although no ASN.1 compiler is supplied
+with <B>ODR</B> at this time, it shouldn't be too difficult to write one, or
+perhaps even to adapt an existing compiler to output <B>ODR</B> routines
+(not surprisingly, writing encoders/decoders using <B>ODR</B> turns out
+to be boring work).
+<P>In many cases, the model of the XDR functions works quite well in this
+role. In
+others, it is less elegant. Most of the hassle comes from the optional
+SEQUENCE memebers which don't exist in XDR.
+<P>
+<H3>The Primitive ASN.1 Types</H3>
+
+<P>ASN.1 defines a number of primitive types (many of which correspond
+roughly to
+primitive types in structured programming languages, such as C).
+<P>
+<H3>INTEGER</H3>
+
+<P>The <B>ODR</B> function for encoding or decoding (or printing) the ASN.1
+INTEGER type looks like this:
+<P>
+<BLOCKQUOTE><CODE>
+<PRE>
+int odr_integer(ODR o, int **p, int optional, const char *name);
+</PRE>
+</CODE></BLOCKQUOTE>
+<P>(we don't allow values that can't be contained in a C integer.)
+<P>This form is typical of the primitive <B>ODR</B> functions. They are named
+after the type of data that they encode or decode. They take an
+ODR
+stream, an indirect reference to the type in question, and an
+<CODE>optional</CODE> flag (corresponding to the OPTIONAL keyword of ASN.1) as
+parameters. They all return an integer value of either one or zero.
+When you use the primitive functions to construct encoders for complex
+types of your own, you should follow this model as well. This
+ensures that your new types can be reused as elements in yet more
+complex types.
+<P>The <CODE>o</CODE> parameter should obviously refer to a properly
+initialized ODR
+stream of the right type (encoding/decoding/printing) for the
+operation that you wish to perform.
+<P>When encoding or printing, the function first looks at *<CODE>p</CODE>. If
+*<CODE>p</CODE> (the
+pointer pointed to by <CODE>p</CODE>) is a null pointer, this is taken to mean that
+the data element is absent. If the <CODE>optional</CODE> parameter is nonzero,
+the function will return one (signifying success) without any further
+processing. If the <CODE>optional</CODE> is zero, an internal error flag is
+set in the ODR stream, and the function will return 0. No further
+operations can be carried out on the stream without a call to
+the function <CODE>odr_reset()</CODE>.
+<P>If *<CODE>p</CODE> is not a null pointer, it is expected to point to an instance of
+the data type. The data will be subjected to the encoding rules, and
+the result will be placed in the buffer held by the ODR stream.
+<P>The other ASN.1 primitives have similar functions that operate in
+similar manners:
+<P>
+<H3>BOOLEAN</H3>
+
+<P>
+<BLOCKQUOTE><CODE>
+<PRE>
+int odr_bool(ODR o, bool_t **p, int optional, const char *name);
+</PRE>
+</CODE></BLOCKQUOTE>
+<P>
+<H3>REAL</H3>
+
+<P>Not defined.
+<P>
+<H3>NULL</H3>
+
+<P>
+<BLOCKQUOTE><CODE>
+<PRE>
+int odr_null(ODR o, bool_t **p, int optional, const char *name);
+</PRE>
+</CODE></BLOCKQUOTE>
+<P>In this case, the value of **p is not important. If *p is different
+from the null pointer, the null value is present, otherwise it's
+absent.
+<P>
+<H3>OCTET STRING</H3>
+
+<P>
+<BLOCKQUOTE><CODE>
+<PRE>
+typedef struct odr_oct
+{
+    unsigned char *buf;
+    int len;
+    int size;
+} Odr_oct;
+
+int odr_octetstring(ODR o, Odr_oct **p, int optional, const char *name);
+</PRE>
+</CODE></BLOCKQUOTE>
+<P>The <CODE>buf</CODE> field should point to the character array that holds the
+octetstring. The <CODE>len</CODE> field holds the actual length, while the
+<CODE>size</CODE>
+field gives the size of the allocated array (not of interest to you,
+in most cases). The character array need not be null terminated.
+<P>To make things a little easier, an alternative is given for string
+types that are not expected to contain embedded NULL characters (eg.
+VisibleString):
+<P>
+<BLOCKQUOTE><CODE>
+<PRE>
+int odr_cstring(ODR o, char **p, int optional, const char *name);
+</PRE>
+</CODE></BLOCKQUOTE>
+<P>Which encoded or decodes between OCTETSTRING representations and
+null-terminates C strings.
+<P>Functions are provided for the derived string types, eg:
+<P>
+<BLOCKQUOTE><CODE>
+<PRE>
+int odr_visiblestring(ODR o, char **p, int optional, const char *name);
+</PRE>
+</CODE></BLOCKQUOTE>
+<P>
+<H3>BIT STRING</H3>
+
+<P>
+<BLOCKQUOTE><CODE>
+<PRE>
+int odr_bitstring(ODR o, Odr_bitmask **p, int optional, const char *name);
+</PRE>
+</CODE></BLOCKQUOTE>
+<P>The opaque type <CODE>Odr_bitmask</CODE> is only suitable for holding relatively brief bit
+strings, eg. for options fields, etc. The constant
+<CODE>ODR_BITMASK_SIZE</CODE>
+multiplied by 8 gives the maximum possible number of bits.
+<P>A set of macros are provided for manipulating the
+<CODE>Odr_bitmask</CODE>
+type:
+<P>
+<BLOCKQUOTE><CODE>
+<PRE>
+void ODR_MASK_ZERO(Odr_bitmask *b);
+
+void ODR_MASK_SET(Odr_bitmask *b, int bitno);
+
+void ODR_MASK_CLEAR(Odr_bitmask *b, int bitno);
+
+int ODR_MASK_GET(Odr_bitmask *b, int bitno);
+</PRE>
+</CODE></BLOCKQUOTE>
+<P>The functions are modelled after the manipulation functions that
+accompany the <CODE>fd_set</CODE> type used by the <CODE>select</CODE>(2) call.
+<CODE>ODR_MASK_ZERO</CODE> should always be called first on a new bitmask, to
+initialize the bits to zero.
+<P>
+<H3>OBJECT IDENTIFIER</H3>
+
+<P>
+<BLOCKQUOTE><CODE>
+<PRE>
+int odr_oid(ODR o, Odr_oid **p, int optional, const char *name);
+</PRE>
+</CODE></BLOCKQUOTE>
+<P>The C OID represenation is simply an array of integers, terminated by
+the value -1 (the <CODE>Odr_oid</CODE> type is synonymous with the <CODE>int</CODE>
+type). We suggest that you use the OID database module (see section
+<A HREF="yaz-3.html#oid">Object Identifiers</A>) to handle object identifiers
+in your application.
+<P>
+<H3><A NAME="tag-prim"></A> Tagging Primitive Types</H3>
+
+<P>The simplest way of tagging a type is to use the <CODE>odr_implicit_tag()</CODE> or
+<CODE>odr_explicit_tag()</CODE> macros:
+<P>
+<BLOCKQUOTE><CODE>
+<PRE>
+int odr_implicit_tag(ODR o, Odr_fun fun, int class, int tag, int
+                     optional, const char *name);
+
+int odr_explicit_tag(ODR o, Odr_fun fun, int class, int tag,
+                     int optional, const char *name);
+</PRE>
+</CODE></BLOCKQUOTE>
+<P>To create a type derived from the integer type by implicit tagging, you
+might write:
+<P>
+<BLOCKQUOTE><CODE>
+<PRE>
+MyInt ::= [210] IMPLICIT INTEGER
+</PRE>
+</CODE></BLOCKQUOTE>
+<P>In the <B>ODR</B> system, this would be written like:
+<P>
+<BLOCKQUOTE><CODE>
+<PRE>
+int myInt(ODR o, int **p, int optional, const char *name)
+{
+    return odr_implicit_tag(o, odr_integer, p,
+                   ODR_CONTEXT, 210, optional, name);
+}
+</PRE>
+</CODE></BLOCKQUOTE>
+<P>The function <CODE>myInt()</CODE> can then be used like any of the primitive
+functions provided by ODR. Note that the behavior of
+<CODE>odr_explicit()</CODE>
+and <CODE>odr_implicit()</CODE> macros act exactly the same as the functions they
+are applied to - they respond to error conditions, etc, in the same
+manner - they simply have three extra parameters. The class parameter may
+take one of the values: <CODE>ODR_CONTEXT</CODE>, <CODE>ODR_PRIVATE</CODE>,
+<CODE>ODR_UNIVERSAL</CODE>, or
+<CODE>ODR_APPLICATION</CODE>.
+<P>
+<H3>Constructed Types</H3>
+
+<P>Constructed types are created by combining primitive types. The
+<B>ODR</B>
+system only implements the SEQUENCE and SEQUENCE OF constructions
+(although adding the rest of the container types should be simple
+enough, if the need arises).
+<P>For implementing SEQUENCEs, the functions
+<P>
+<BLOCKQUOTE><CODE>
+<PRE>
+int odr_sequence_begin(ODR o, void *p, int size, const char *name);
+int odr_sequence_end(ODR o);
+</PRE>
+</CODE></BLOCKQUOTE>
+<P>are provided.
+<P>The <CODE>odr_sequence_begin()</CODE> function should be called in the beginning of a
+function that implements a SEQUENCE type. Its parameters are the
+<B>ODR</B>
+stream, a pointer (to a pointer to the type you're implementing), and
+the <CODE>size</CODE> of the type (typically a C structure). On encoding, it
+returns 1 if *<CODE>p</CODE> is a null pointer. The <CODE>size</CODE> parameter is ignored. On
+decoding, it returns 1 if the type is found in the data stream.
+<CODE>size</CODE>
+bytes of memory are allocated, and *<CODE>p</CODE> is set to point to this space.
+<CODE>odr_sequence_end()</CODE> is called at the end of the complex function. Assume
+that a type is defined like this:
+<P>
+<BLOCKQUOTE><CODE>
+<PRE>
+MySequence ::= SEQUENCE {
+    intval INTEGER,
+    boolval BOOLEAN OPTIONAL }
+</PRE>
+</CODE></BLOCKQUOTE>
+<P>The corresponding ODR encoder/decoder function and the associated data
+structures could be written like this:
+<P>
+<BLOCKQUOTE><CODE>
+<PRE>
+typedef struct MySequence
+{
+    int *intval;
+    bool_t *boolval;
+} MySequence;
+
+int mySequence(ODR o, MySequence **p, int optional, const char *name)
+{
+    if (odr_sequence_begin(o, p, sizeof(**p), name) == 0)
+        return optional &amp;&amp; odr_ok(o);
+    return
+        odr_integer(o, &amp;(*p)->intval, 0, "intval") &amp;&amp;
+        odr_bool(o, &amp;(*p)->boolval, 1, "boolval") &amp;&amp;
+        odr_sequence_end(o);
+}
+</PRE>
+</CODE></BLOCKQUOTE>
+<P>Note the 1 in the call to <CODE>odr_bool()</CODE>, to mark that the sequence
+member is optional. If either of the member types had been tagged, the
+macros <CODE>odr_implicit()</CODE> or <CODE>odr_explicit()</CODE> could have been used.
+The new
+function can be used exactly like the standard functions provided with
+<B>ODR</B>. It will encode, decode or pretty-print a data value of the
+<CODE>MySequence</CODE> type. We like to name types with an initial capital, as
+done in ASN.1 definitions, and to name the corresponding function with
+the first character of the name in lower case. You could, of course,
+name your structures, types, and functions any way you please - as
+long as you're consistent, and your code is easily readable.
+<CODE>odr_ok</CODE> is
+just that - a predicate that returns the state of the stream. It is
+used to ensure that the behaviour of the new type is compatible with
+the interface of the primitive types.
+<P>
+<H3>Tagging Constructed Types</H3>
+
+<P><I>NOTE: See section 
+<A HREF="#tag-prim">Tagging Primitive types</A>
+for information on how to tag the primitive types, as well as types
+that are already defined.</I>
+<P>
+<H3>Implicit Tagging</H3>
+
+<P>Assume the type above had been defined as
+<P>
+<BLOCKQUOTE><CODE>
+<PRE>
+MySequence ::= [10] IMPLICIT SEQUENCE {
+    intval INTEGER,
+    boolval BOOLEAN OPTIONAL }
+</PRE>
+</CODE></BLOCKQUOTE>
+<P>You would implement this in <B>ODR</B> by calling the function
+<P>
+<BLOCKQUOTE><CODE>
+<PRE>
+int odr_implicit_settag(ODR o, int class, int tag);
+</PRE>
+</CODE></BLOCKQUOTE>
+<P>which overrides the tag of the type immediately following it. The
+macro <CODE>odr_implicit()</CODE> works by calling <CODE>odr_implicit_settag()</CODE>
+immediately
+before calling the function pointer argument. Your type function could
+look like this:
+<P>
+<BLOCKQUOTE><CODE>
+<PRE>
+int mySequence(ODR o, MySequence **p, int optional, const char *name)
+{
+    if (odr_implicit_settag(o, ODR_CONTEXT, 10) == 0 ||
+        odr_sequence_begin(o, p, sizeof(**p), name) == 0)
+        return optional &amp;&amp; odr_ok(o);
+    return
+        odr_integer(o, &amp;(*p)->intval, 0, "intval") &amp;&amp;
+        odr_bool(o, &amp;(*p)->boolval, 1, "boolval") &amp;&amp;
+        odr_sequence_end(o);
+}
+</PRE>
+</CODE></BLOCKQUOTE>
+<P>The definition of the structure <CODE>MySequence</CODE> would be the same.
+<P>
+<H3>Explicit Tagging</H3>
+
+<P>Explicit tagging of constructed types is a little more complicated,
+since you are in effect adding a level of construction to the data.
+<P>Assume the definition:
+<P>
+<BLOCKQUOTE><CODE>
+<PRE>
+MySequence ::= [10] IMPLICIT SEQUENCE {
+    intval INTEGER,
+    boolval BOOLEAN OPTIONAL }
+</PRE>
+</CODE></BLOCKQUOTE>
+<P>Since the new type has an extra level of construction, two new functions
+are needed to encapsulate the base type:
+<P>
+<BLOCKQUOTE><CODE>
+<PRE>
+int odr_constructed_begin(ODR o, void *p, int class, int tag,
+       const char *name);
+
+int odr_constructed_end(ODR o);
+</PRE>
+</CODE></BLOCKQUOTE>
+<P>Assume that the IMPLICIT in the type definition above were replaced
+with EXPLICIT (or that the IMPLICIT keyword were simply deleted, which
+would be equivalent). The structure definition would look the same,
+but the function would look like this:
+<P>
+<BLOCKQUOTE><CODE>
+<PRE>
+int mySequence(ODR o, MySequence **p, int optional, const char *name)
+{
+    if (odr_constructed_begin(o, p, ODR_CONTEXT, 10, name) == 0)
+        return optional &amp;&amp; odr_ok(o);
+    if (o->direction == ODR_DECODE)
+        *p = odr_malloc(o, sizeof(**p));
+    if (odr_sequence_begin(o, p, sizeof(**p), 0) == 0)
+    {
+        *p = 0; /* this is almost certainly a protocol error */
+        return 0;
+    }
+    return
+        odr_integer(o, &amp;(*p)->intval, 0, "intval") &amp;&amp;
+        odr_bool(o, &amp;(*p)->boolval, 1, "boolval") &amp;&amp;
+        odr_sequence_end(o) &amp;&amp;
+        odr_constructed_end(o);
+}
+</PRE>
+</CODE></BLOCKQUOTE>
+<P>Notice that the interface here gets kind of nasty. The reason is
+simple: Explicitly tagged, constructed types are fairly rare in
+the protocols that we care about, so the
+aesthetic annoyance (not to mention the dangers of a cluttered
+interface) is less than the time that would be required to develop a
+better interface. Nevertheless, it is far from satisfying, and it's a
+point that will be worked on in the future. One option for you would
+be to simply apply the <CODE>odr_explicit()</CODE> macro to the first function,
+and not
+have to worry about <CODE>odr_constructed_*</CODE> yourself. Incidentally, as you
+might have guessed, the <CODE>odr_sequence_</CODE> functions are themselves
+implemented using the <CODE>odr_constructed_</CODE> functions.
+<P>
+<H3>SEQUENCE OF</H3>
+
+<P>To handle sequences (arrays) of a apecific type, the function
+<P>
+<BLOCKQUOTE><CODE>
+<PRE>
+int odr_sequence_of(ODR o, int (*fun)(ODR o, void *p, int optional),
+                        void *p, int *num, const char *name);
+</PRE>
+</CODE></BLOCKQUOTE>
+<P>The <CODE>fun</CODE> parameter is a pointer to the decoder/encoder
+function of the type. <CODE>p</CODE> is a pointer to an array of pointers to your
+type. <CODE>num</CODE> is the number of elements in the array.
+<P>Assume a type
+<P>
+<BLOCKQUOTE><CODE>
+<PRE>
+MyArray ::= SEQUENCE OF INTEGER
+</PRE>
+</CODE></BLOCKQUOTE>
+<P>The C representation might be
+<P>
+<BLOCKQUOTE><CODE>
+<PRE>
+typedef struct MyArray
+{
+    int num_elements;
+    int **elements;
+} MyArray;
+</PRE>
+</CODE></BLOCKQUOTE>
+<P>And the function might look like
+<P>
+<BLOCKQUOTE><CODE>
+<PRE>
+int myArray(ODR o, MyArray **p, int optional, const char *name)
+{
+    if (o->direction == ODR_DECODE)
+        *p = odr_malloc(o, sizeof(**p));
+    if (odr_sequence_of(o, odr_integer, &amp;(*p)->elements,
+        &amp;(*p)->num_elements, name))
+        return 1;
+    *p = 0;
+    return optional &amp;&amp; odr_ok(o);
+}
+</PRE>
+</CODE></BLOCKQUOTE>
+<P>
+<H3>CHOICE Types</H3>
+
+<P>The choice type is used fairly often in some ASN.1 definitions, so
+some work has gone into streamlining its interface.
+<P>CHOICE types are handled by the function:
+<P>
+<BLOCKQUOTE><CODE>
+<PRE>
+int odr_choice(ODR o, Odr_arm arm[], void *p, void *whichp,
+               const char *name);
+</PRE>
+</CODE></BLOCKQUOTE>
+<P>The <CODE>arm</CODE> array is used to describe each of the possible types that the
+CHOICE type may assume. Internally in your application, the CHOICE
+type is represented as a discriminated union. That is, a C union
+accompanied by an integer (or enum) identifying the active 'arm' of
+the union. <CODE>whichp</CODE> is a pointer to the union discriminator. When
+encoding, it is examined to determine the current type. When decoding,
+it is set to reference the type that was found in the input stream.
+<P>The Odr_arm type is defined thus:
+<P>
+<BLOCKQUOTE><CODE>
+<PRE>
+typedef struct odr_arm
+{
+    int tagmode;
+    int class;
+    int tag;
+    int which;
+    Odr_fun fun;
+    char *name;
+} Odr_arm;
+</PRE>
+</CODE></BLOCKQUOTE>
+<P>The interpretation of the fields are:
+<P>
+<DL>
+<DT><B>tagmode</B><DD><P>Either <CODE>ODR_IMPLICIT</CODE>, <CODE>ODR_EXPLICIT</CODE>, or <CODE>ODR_NONE</CODE>
+(-1) to mark
+no tagging.
+<DT><B>class, tag</B><DD><P>The class and tag of the type (-1 if no tagging is
+used).
+<DT><B>which</B><DD><P>The value of the discriminator that corresponds to
+this CHOICE element. Typically, it will be a #defined constant, or
+an enum member.
+<DT><B>fun</B><DD><P>A pointer to a function that implements the type of
+the CHOICE member. It may be either a standard <B>ODR</B> type or a type
+defined by yourself.
+<DT><B>name</B><DD><P>Name of tag.
+</DL>
+<P>A handy way to prepare the array for use by the <CODE>odr_choice()</CODE> function
+is to
+define it as a static, initialized array in the beginning of your
+decoding/encoding function. Assume the type definition:
+<P>
+<BLOCKQUOTE><CODE>
+<PRE>
+MyChoice ::= CHOICE {
+    untagged INTEGER,
+    tagged   [99] IMPLICIT INTEGER,
+    other    BOOLEAN
+}
+</PRE>
+</CODE></BLOCKQUOTE>
+<P>Your C type might look like
+<P>
+<BLOCKQUOTE><CODE>
+<PRE>
+typedef struct MyChoice
+{
+    enum
+    {
+        MyChoice_untagged,
+        MyChoice_tagged,
+        MyChoice_other
+    } which;
+    union
+    {
+        int *untagged;
+        int *tagged;
+        bool_t *other;
+    } u;
+};
+</PRE>
+</CODE></BLOCKQUOTE>
+<P>And your function could look like this:
+<P>
+<BLOCKQUOTE><CODE>
+<PRE>
+int myChoice(ODR o, MyChoice **p, int optional, const char *name)
+{
+    static Odr_arm arm[] =
+    {
+        {-1, -1, -1, MyChoice_untagged, odr_integer, "untagged"},
+        {ODR_IMPLICIT, ODR_CONTEXT, 99, MyChoice_tagged, odr_integer, 
+                                                            "tagged"},
+        {-1, -1, -1, MyChoice_other, odr_boolean, "other"},
+        {-1, -1, -1, -1, 0}
+    };
+
+    if (o->direction == ODR_DECODE)
+        *p = odr_malloc(o, sizeof(**p);
+    else if (!*p)
+        return optional &amp;&amp; odr_ok(o);
+
+    if (odr_choice(o, arm, &amp;(*p)->u, &amp;(*p)->which), name)
+        return 1;
+    *p = 0;
+    return optional &amp;&amp; odr_ok(o);
+}
+</PRE>
+</CODE></BLOCKQUOTE>
+<P>In some cases (say, a non-optional choice which is a member of a sequence),
+you can &quot;embed&quot; the union and its discriminator in the structure
+belonging to the enclosing type, and you won't need to fiddle with
+memory allocation to create a separate structure to wrap the
+discriminator and union.
+<P>The corresponding function is somewhat nicer in the Sun XDR interface.
+Most of the complexity of this interface comes from the possibility of
+declaring sequence elements (including CHOICEs) optional.
+<P>The ASN.1 specifictions naturally requires that each member of a
+CHOICE have a distinct tag, so they can be told apart on decoding.
+Sometimes it can be useful to define a CHOICE that has multiple types
+that share the same tag. You'll need some other mechanism, perhaps
+keyed to the context of the CHOICE type. In effect, we would like to
+introduce a level of context-sensitiveness to our ASN.1 specification.
+When encoding an internal representation, we have no problem, as long
+as each CHOICE member has a distinct discriminator value. For
+decoding, we need a way to tell the choice function to look for a
+specific arm of the table. The function
+<P>
+<BLOCKQUOTE><CODE>
+<PRE>
+void odr_choice_bias(ODR o, int what);
+</PRE>
+</CODE></BLOCKQUOTE>
+<P>provides this functionality. When called, it leaves a notice for the
+next call to <CODE>odr_choice()</CODE> to be called on the decoding
+stream <CODE>o</CODE> that only the <CODE>arm</CODE> entry with a <CODE>which</CODE> field
+equal to <CODE>what</CODE> should be tried.
+<P>The most important application (perhaps the only one, really) is in
+the definition of application-specific EXTERNAL encoders/decoders
+which will automatically decode an ANY member given the direct or
+indirect reference.
+<P>
+<H2><A NAME="ss5.4">5.4 Debugging</A>
+</H2>
+
+<P>The protocol modules are suffering somewhat from a lack of diagnostic
+tools at the moment. Specifically ways to pretty-print PDUs that
+aren't recognized by the system. We'll include something to this end
+in a not-too-distant release. In the meantime, what we do when we get
+packages we don't understand is to compile the ODR module with
+<CODE>ODR_DEBUG</CODE> defined. This causes the module to dump tracing
+information as it processes data units. With this output and the
+protocol specification (Z39.50), it is generally fairly easy to see
+what goes wrong.
+<P>
+<HR>
+<A HREF="yaz-6.html">Next</A>
+<A HREF="yaz-4.html">Previous</A>
+<A HREF="yaz.html#toc5">Contents</A>
+</BODY>
+</HTML>
Index: /main/tags/2.25/gsdl/packages/yaz/doc/yaz-6.html
===================================================================
--- /main/tags/2.25/gsdl/packages/yaz/doc/yaz-6.html	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/yaz/doc/yaz-6.html	(revision 21064)
@@ -0,0 +1,562 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN">
+<HTML>
+<HEAD>
+ <META NAME="GENERATOR" CONTENT="SGML-Tools 1.0.9">
+ <TITLE>YAZ User's Guide and Reference: The COMSTACK Module</TITLE>
+ <LINK HREF="yaz-7.html" REL=next>
+ <LINK HREF="yaz-5.html" REL=previous>
+ <LINK HREF="yaz.html#toc6" REL=contents>
+</HEAD>
+<BODY>
+<A HREF="yaz-7.html">Next</A>
+<A HREF="yaz-5.html">Previous</A>
+<A HREF="yaz.html#toc6">Contents</A>
+<HR>
+<H2><A NAME="comstack"></A> <A NAME="s6">6. The COMSTACK Module</A></H2>
+
+<H2><A NAME="ss6.1">6.1 Introduction</A>
+</H2>
+
+<P>The <B>COMSTACK</B>
+subsystem provides a transparent interface to different types of transport
+stacks for the exchange of BER-encoded data. At present, the
+RFC1729 method (BER over TCP/IP), and Peter Furniss' XTImOSI
+stack are supported, but others may be added in time. The philosophy of the
+module is to provide a simple interface by hiding unused options and
+facilities of the underlying libraries. This is always done at the risk
+of losing generality, and it may prove that the interface will need
+extension later on.
+<P>The interface is implemented in such a fashion that only the
+sub-layers constructed to the transport methods that you wish to 
+use in your application are linked in.
+<P>You will note that even though simplicity was a goal in the design,
+the interface is still orders of magnitudes more complex than the
+transport systems found in many other packages. One reason is that
+the interface needs to support the somewhat different requirements of
+the different lower-layer communications stacks; another important reason is
+that the interface seeks to provide a more or less industrial-strength
+approach to asynchronous event-handling. When no function is allowed
+to block, things get more complex - particularly on the server
+side. We urge you to have a look at the demonstration client and server
+provided with the package. They are meant to be easily readable and
+instructive, while still being at least moderately useful.
+<P>
+<H2><A NAME="ss6.2">6.2 Common Functions</A>
+</H2>
+
+<H3>Managing Endpoints</H3>
+
+<P>
+<BLOCKQUOTE><CODE>
+<PRE>
+COMSTACK cs_create(CS_TYPE type, int blocking, int protocol);
+</PRE>
+</CODE></BLOCKQUOTE>
+<P>Creates an instance of the protocol stack - a communications endpoint.
+The
+<CODE>type</CODE>
+parameter determines the mode of communication. At present, the
+values
+<CODE>tcpip_type</CODE>
+and
+<CODE>mosi_type</CODE>
+are recognized. The function returns a null-pointer if a system error
+occurs. The <CODE>blocking</CODE> parameter should be one if you wish the
+association to operate in blocking mode, zero otherwise. The
+<CODE>protocol</CODE> field should be one of <CODE>PROTO_SR</CODE> or <CODE>PROTO_Z3950</CODE>.
+<P>
+<BLOCKQUOTE><CODE>
+<PRE>
+int cs_close(COMSTACK handle);
+</PRE>
+</CODE></BLOCKQUOTE>
+<P>Closes the connection (as elegantly as the lower layers will permit),
+and releases the resouces pointed to by the
+<CODE>handle</CODE>
+parameter. The
+<CODE>handle</CODE>
+should not be referenced again after this call.
+<P><I>NOTE:
+We really need a soft disconnect, don't we?</I>
+<P>
+<H3>Data Exchange</H3>
+
+<P>
+<BLOCKQUOTE><CODE>
+<PRE>
+int cs_put(COMSTACK handle, char *buf, int len);
+</PRE>
+</CODE></BLOCKQUOTE>
+<P>Sends
+<CODE>buf</CODE>
+down the wire. In blocking mode, this function will return only when a
+full buffer has been written, or an error has occurred. In nonblocking
+mode, it's possible that the function will be unable to send the full
+buffer at once, which will be indicated by a return value of 1. The
+function will keep track of the number of octets already written; you
+should call it repeatedly with the same values of <CODE>buf</CODE> and
+<CODE>len</CODE>, until the buffer has been transmitted. When a full buffer
+has been sent, the function will return 0 for success. -1 indicates
+an error condition (see below).
+<P>
+<BLOCKQUOTE><CODE>
+<PRE>
+int cs_get(COMSTACK handle, char **buf, int *size);
+</PRE>
+</CODE></BLOCKQUOTE>
+<P>Receives a PDU from the peer. Returns the number of bytes
+read. In nonblocking mode, it is possible that not all of the packet can be
+read at once. In this case, the function returns 1. To simplify the
+interface, the function is
+responsible for managing the size of the buffer. It will be reallocated
+if necessary to contain large packages, and will sometimes be moved
+around internally by the subsystem when partial packages are read. Before
+calling
+<CODE>cs_get</CODE>
+for the fist time, the buffer can be initialized to the null pointer,
+and the length should also be set to 0 - cs_get will perform a
+<CODE>malloc</CODE>(2)
+on the buffer for you. When a full buffer has been read, the size of
+the package is returned (which will always be greater than 1). -1
+indicates an error condition.
+<P>See also the
+<CODE>cs_more()</CODE>
+function below.
+<P>
+<BLOCKQUOTE><CODE>
+<PRE>
+int cs_more(COMSTACK handle);
+</PRE>
+</CODE></BLOCKQUOTE>
+<P>The <CODE>cs_more()</CODE> function should be used in conjunction with
+<CODE>cs_get</CODE>
+and
+<CODE>select</CODE>(2).
+The <CODE>cs_get()</CODE> function will sometimes (notably in the TCP/IP mode) read
+more than a single protocol package off the network. When this
+happens, the extra package is stored by the subsystem. After calling
+<CODE>cs_get()</CODE>, and before waiting for more input,
+You should always call
+<CODE>cs_more()</CODE>
+to check if there's a full protocol package already read. If
+<CODE>cs_more()</CODE>
+returns 1,
+<CODE>cs_get()</CODE>
+can be used to immediately fetch the new package. For the 
+mOSI
+subsystem, the function should always return 0, but if you want your
+stuff to be protocol independent, you should use it.
+<P><I>NOTE: The <CODE>cs_more()</CODE>
+function is required because the 
+RFC1729-method
+does not provide a way of separating individual PDUs, short of
+partially decoding the BER. Some other implementations will carefully
+nibble at the packet by calling
+<CODE>read</CODE>(2)
+several times. This was felt to be too inefficient (or at least
+clumsy) - hence the call for this extra function.</I>
+<P>
+<BLOCKQUOTE><CODE>
+<PRE>
+int cs_look(COMSTACK handle);
+</PRE>
+</CODE></BLOCKQUOTE>
+<P>This function is useful when you're operating in nonblocking
+mode. Call it when
+<CODE>select</CODE>(2)
+tells you there's something happening on the line. It returns one of
+the following values:
+<P>
+<DL>
+<DT><B>CS_NONE</B><DD><P>No event is pending. The data found on the line was
+not a complete package.
+<DT><B>CS_CONNECT</B><DD><P>A response to your connect request has been received. Call
+<CODE>cs_rcvconnect</CODE>
+to process the event and to finalize the connection establishment.
+<DT><B>CS_DISCON</B><DD><P>The other side has closed the connection (or maybe
+sent a disconnect
+request - but do we care? Maybe later). Call
+<CODE>cs_close</CODE> To close your end of the association as well.
+<DT><B>CS_LISTEN</B><DD><P>A connect request has been received. Call
+<CODE>cs_listen</CODE>
+to process the event.
+<DT><B>CS_DATA</B><DD><P>There's data to be found on the line. Call
+<CODE>cs_get</CODE>
+to get it.
+</DL>
+<P><I>NOTE:
+You should be aware that even if
+<CODE>cs_look()</CODE>
+tells you that there's an event event pending, the corresponding
+function may still return and tell you there was nothing to be found.
+This means that only part of a package was available for reading. The
+same event will show up again, when more data has arrived.</I>
+<P>
+<BLOCKQUOTE><CODE>
+<PRE>
+int cs_fileno(COMSTACK h);
+</PRE>
+</CODE></BLOCKQUOTE>
+<P>Returns the file descriptor of the association. Use this when
+file-level operations on the endpoint are required (<CODE>select</CODE>(2)
+operations, specifically).
+<P>
+<H2><A NAME="ss6.3">6.3 Client Side</A>
+</H2>
+
+<P>
+<BLOCKQUOTE><CODE>
+<PRE>
+int cs_connect(COMSTACK handle, void *address);
+</PRE>
+</CODE></BLOCKQUOTE>
+<P>Initiate a connection with the target at <CODE>address</CODE> (more on
+addresses below). The function will return 0 on success, and 1 if
+the operation does not complete immediately (this will only
+happen on a nonblocking endpoint). In this case, use
+<CODE>cs_rcvconnect</CODE> to complete the operation, when <CODE>select</CODE>(2)
+reports input pending on the association.
+<P>
+<BLOCKQUOTE><CODE>
+<PRE>
+int cs_rcvconnect(COMSTACK handle);
+</PRE>
+</CODE></BLOCKQUOTE>
+<P>Complete a connect operation initiated by <CODE>cs_connect()</CODE>. It will
+return 0 on success; 1 if the operation has not yet completed (in this
+case, call the function again later); -1 if an error has occured.
+<P>
+<H2><A NAME="ss6.4">6.4 Server Side</A>
+</H2>
+
+<P>To establish a server under the <CODE>inetd</CODE> server, you can use
+<P>
+<BLOCKQUOTE><CODE>
+<PRE>
+COMSTACK cs_createbysocket(int socket, CS_TYPE type, int blocking,
+                              int protocol);
+</PRE>
+</CODE></BLOCKQUOTE>
+<P>The <I>socket</I> parameter is an established socket (when your
+application is invoked from <CODE>inetd</CODE>, the socket will typically be
+0. The following parameters are identical to the ones for
+<CODE>cs_create</CODE>.
+<P>
+<BLOCKQUOTE><CODE>
+<PRE>
+int cs_bind(COMSTACK handle, void *address, int mode)
+</PRE>
+</CODE></BLOCKQUOTE>
+<P>Binds a local address to the endpoint. Read about addresses below. The
+<CODE>mode</CODE> parameter should be either <CODE>CS_CLIENT</CODE> or <CODE>CS_SERVER</CODE>.
+<P>
+<BLOCKQUOTE><CODE>
+<PRE>
+int cs_listen(COMSTACK handle, char *addr, int *addrlen);
+</PRE>
+</CODE></BLOCKQUOTE>
+<P>Call this to process incoming events on an endpoint that has been
+bound in listening mode. It will return 0 to indicate that the connect
+request has been received, 1 to signal a partial reception, and -1 to
+indicate an error condition.
+<P>
+<BLOCKQUOTE><CODE>
+<PRE>
+COMSTACK cs_accept(COMSTACK handle);
+</PRE>
+</CODE></BLOCKQUOTE>
+<P>This finalises the server-side association establishment, after
+cs_listen has completed successfully. It returns a new connection
+endpoint, which represents the new association. The application will
+typically wish to fork off a process to handle the association at this
+point, and continue listen for new connections on the old <CODE>handle</CODE>.
+<P>You can use the call
+<P>
+<BLOCKQUOTE><CODE>
+<PRE>
+char *cs_addrstr(COMSTACK);
+</PRE>
+</CODE></BLOCKQUOTE>
+<P>on an established connection to retrieve the hostname of the remote host.
+<P><I>NOTE: You may need to use this function with some care if your
+name server service is slow or unreliable</I>
+<P>
+<H2><A NAME="ss6.5">6.5 Addresses</A>
+</H2>
+
+<P>The low-level format of the addresses are different depending on the
+mode of communication you have chosen. A function is provided by each
+of the lower layers to map a user-friendly string-form address to the
+binary form required by the lower layers.
+<P>
+<BLOCKQUOTE><CODE>
+<PRE>
+struct sockaddr_in *tcpip_strtoaddr(char *str);
+
+struct netbuf *mosi_strtoaddr(char *str);
+</PRE>
+</CODE></BLOCKQUOTE>
+<P>The format for TCP/IP addresses is straightforward:
+<P>
+<BLOCKQUOTE><CODE>
+<PRE>
+&lt;host> [ ':' &lt;portnum> ]
+</PRE>
+</CODE></BLOCKQUOTE>
+<P>The <CODE>hostname</CODE> can be either a domain name or an IP address. The
+port number, if omitted, defaults to 210.
+<P>For OSI, the format is
+<P>
+<BLOCKQUOTE><CODE>
+<PRE>
+[ &lt;t-selector> '/' ] &lt;host> [ ':' &lt;port> ]
+</PRE>
+</CODE></BLOCKQUOTE>
+<P>The transport selector is given as an even number of hex digits.
+<P>You'll note that the address format for the OSI mode are just a subset
+of full presentation addresses. We use presentation addresses because
+xtimosi doesn't, in itself, allow access to the X.500 Directory
+service. We use a limited form, because we haven't yet come across an
+implementation that used more of the elements of a full p-address. It
+is a fairly simple matter to add the rest of the elements to the
+address format as needed, however: Xtimosi <I>does</I> support the full
+P-address structure.
+<P>In both transport modes, the special hostname &quot;@&quot; is mapped
+to any local address (the manifest constant INADDR_ANY). It is used
+to establish local listening endpoints in the server role.
+<P>When a connection has been established, you can use
+<P>
+<BLOCKQUOTE><CODE>
+<PRE>
+char cs_addrstr(COMSTACK h);
+</PRE>
+</CODE></BLOCKQUOTE>
+<P>to retrieve the host name of the peer system. The function returns a pointer
+to a static area, which is overwritten on the next call to the function.
+<P><I>NOTE: We have left the issue of X.500 name-to-address mapping open, for the
+moment. It would be a simple matter to provide a table-based mapping,
+if desired. Alternately, we could use the X.500 client-function that
+is provided with the ISODE (although this would defeat some of the
+purpose of using ThinOSI in the first place. We have been told that it
+should be within the realm of the possible to implement a lightweight
+implementation of the necessary X.500 client capabilities on top of
+ThinOSI. This would be the ideal solution, we feel. On the other hand, it
+still remains to be seen just what role the Directory will play in a world
+populated by ThinOSI and other pragmatic solutions.</I>
+<P>
+<H2><A NAME="ss6.6">6.6 Diagnostics</A>
+</H2>
+
+<P>All functions return -1 if an error occurs. Typically, the functions
+will return 0 on success, but the data exchange functions
+(<CODE>cs_get</CODE>, <CODE>cs_put</CODE>, <CODE>cs_more</CODE>)
+follow special rules. Consult their descriptions.
+<P>When a function (including the data exchange functions) reports an
+error condition,
+use the function
+<CODE>cs_errno()</CODE>
+to determine the cause of the
+problem. The function
+<P>
+<BLOCKQUOTE><CODE>
+<PRE>
+void cs_perror(COMSTACK handle char *message);
+</PRE>
+</CODE></BLOCKQUOTE>
+<P>works like
+<CODE>perror</CODE>(2)
+and prints the
+<CODE>message</CODE>
+argument, along with a system message, to
+<CODE>stderr</CODE>.
+Use the character array
+<P>
+<BLOCKQUOTE><CODE>
+<PRE>
+extern const char *cs_errlist[];
+</PRE>
+</CODE></BLOCKQUOTE>
+<P>to get hold of the message, if you want to process it differently.
+The function
+<P>
+<BLOCKQUOTE><CODE>
+<PRE>
+const char *cs_stackerr(COMSTACK handle);
+</PRE>
+</CODE></BLOCKQUOTE>
+<P>Returns an error message from the lower layer, if one has been
+provided.
+<P>
+<H2><A NAME="ss6.7">6.7 Enabling OSI Communication</A>
+</H2>
+
+<H3>Installing Xtimosi</H3>
+
+<P>Although you will have to download Peter Furniss' XTI/mOSI
+implementation for yourself, we've tried to make the integration as
+simple as possible.
+<P>The latest version of xtimosi will generally be under
+<P>
+<BLOCKQUOTE><CODE>
+<PRE>
+ftp://pluto.ulcc.ac.uk/ulcc/thinosi/xtimosi/
+</PRE>
+</CODE></BLOCKQUOTE>
+<P>When you have downloaded and unpacked the archive, it will (we assume)
+have created a directory called <CODE>xtimosi</CODE>. We suggest that you place
+this directory <I>in the same directory</I> where you unpacked the
+<B>YAZ</B>
+distribution. This way, you shouldn't have to fiddle with the
+makefiles of <CODE>YAZ</CODE> beyond uncommenting a few lines.
+<P>Go to <CODE>xtimosi/src</CODE>, and type &quot;<CODE>make libmosi.a</CODE>&quot;.
+This should generally
+create the library, ready to use.
+<P><B>CAVEAT</B>
+<P><I>The currently available release of xtimosi has some inherent
+problems that make it disfunction on certain platforms - eg. the
+Digital OSF/1 workstations. It is supposedly primarily a
+compiler problem, and we hope to see a release that is generally
+portable. While we can't guarantee that it can be brought to work
+on your platform, we'll be happy to talk to you about problems
+that you might see, and relay information to the author of the
+software. There are some signs that the <B>gcc</B> compiler is more
+likely to produce a fully functional library, but this hasn't
+been verified (we think that the problem is limited to the use
+of hexadecimal escape-codes used in strings, which are silently
+ignored by some compilers).</I>
+<P><I>A problem has been encountered in the communication with
+ISODE-based applications. If the ISODE presentation-user calls
+<CODE>PReadRequest()</CODE> with a timeout value different from <CODE>OK</CODE> or <CODE>NOTOK</CODE>,
+he will get an immediate TIMEOUT abort when receiving large (&gt;2041
+bytes, which is the SPDU-size that the ISODE likes to work with) packages
+from an xtimosi-based implementation (probably most
+other implementations as well, in fact). It seems to be a flaw in the
+ISODE API, and the workaround (for ISODE users) is to either not
+use an explicit timeout (switching to either blocking or
+nonblocking mode), or to check that the timer really has expired
+before closing the connection.</I>
+<P>The next step in the installation is to modify the makefile in the toplevel
+<B>YAZ</B>
+directory. The place to change is in the top of the file, and is
+clearly marked with a comment.
+<P>Now run <CODE>make</CODE> in the <B>YAZ</B> toplevel directory (do a
+&quot;<CODE>make clean</CODE>&quot; first, if the
+system has been previously made without OSI support). Use the <B>YAZ</B>
+<B>ztest</B>
+and <B>client</B> demo programs to verify that OSI communication works OK. Then,
+you can go ahead and try to talk to other implementations.
+<P><I>NOTE: Our interoperability experience is limited to version
+7 of the Nordic SR-Nett package, which has had several
+protocol errors fixed from the earlier releases. If you have
+problems or successes in interoperating with other
+implementations, we'd be glad to hear about it, or to help
+you make things work, as our resources allow.</I>
+<P>If you write your own applications based on <B>YAZ</B>, and you wish to
+include OSI support, the procedure is equally simple. You should
+include the <CODE>xmosi.h</CODE> header file in addition to <CODE>comstack.h</CODE>.
+<CODE>xmosi.h</CODE>
+will define the manifest constant <CODE>mosi_type</CODE>, which you should pass
+to the <CODE>cs_create()</CODE> function. In
+addition, you should use the function <CODE>mosi_strtoaddr()</CODE> rather than
+<CODE>tcpip_strtoaddr()</CODE> when you need to prepare an address.
+<P>When you link your application, you should include (after the
+<CODE>libyaz.a</CODE>
+library) the <CODE>libmosi.a</CODE> library, and the <CODE>librfc.a</CODE> library
+provided with
+<B>YAZ</B> (for OSI transport).
+<P>As always, it can be very useful, if not essential, to have a look at the
+example applications
+to see how things are done.
+<P>
+<H3>OSI Transport</H3>
+
+<P>Xtimosi requires an implementation of the OSI transport service under
+the X/OPEN XTI API. We provide an implementation of the RFC1006
+encapsulation of OSI/TP0 in TCP/IP (through the Berkeley Sockets API),
+as an independent part of <B>YAZ</B> (it's found under the <CODE>rfc1006</CODE>
+directory). If you have access to an OSI transport provider under XTI,
+you should be able to make that work too, although it may require
+tinkering with the <CODE>mosi_strtoaddr()</CODE> function.
+<P>
+<H3>Presentation Context Management</H3>
+
+<P>To simplify the implementation, we use Peter Furniss' alternative (PRF)
+option format
+for the Control of the presentation negotiation phase. This format
+is enabled by default when you
+compile xtimosi.
+<P>The current version of <B>YAZ</B> does <I>not</I> support presentation-layer
+negotiation of response record formats. The primary reason is that we
+have had access to no other SR or Z39.50 implementations over OSI that
+used this
+method. Secondarily, we believe that the EXPLAIN facility is a superior
+mechanism for relaying target capabilities in this respect. This is not to
+say that we have no intentions of supporting presentation context
+negotiation - we have just hitherto given it a lower priority than other
+aspects of the protocol.
+<P>One thing is certain: The addition of this capability to <B>YAZ</B> should
+have only a minimal impact on existing applications, and on the
+interface to the software in general. Most likely, we will add an extra
+layer of interface to the processing of EXPLAIN records, which will
+convert back and forth between <CODE>oident</CODE> records (see section
+<A HREF="yaz-3.html#oid">Object Identifiers</A>) and direct or indirect
+references, given the current association setup. Implementations based
+on any of the higher-level interfaces will most likely not have to be
+changed at all.
+<P>
+<H2><A NAME="ss6.8">6.8 Summary and Synopsis</A>
+</H2>
+
+<P>
+<BLOCKQUOTE><CODE>
+<PRE>
+#include &lt;comstack.h>
+
+#include &lt;tcpip.h>      /* this is for TCP/IP support   */
+#include &lt;xmosi.h>      /* and this is for mOSI support */
+
+COMSTACK cs_create(CS_TYPE type, int blocking, int protocol);
+
+COMSTACK cs_createbysocket(int s, CS_TYPE type, int blocking,
+                              int protocol);
+
+int cs_bind(COMSTACK handle, int mode);
+
+int cs_connect(COMSTACK handle, void *address);
+
+int cs_rcvconnect(COMSTACK handle);
+
+int cs_listen(COMSTACK handle);
+
+COMSTACK cs_accept(COMSTACK handle);
+
+int cs_put(COMSTACK handle, char *buf, int len);
+
+int cs_get(COMSTACK handle, char **buf, int *size);
+
+int cs_more(COMSTACK handle);
+
+int cs_close(COMSTACK handle);
+
+int cs_look(COMSTACK handle);
+
+struct sockaddr_in *tcpip_strtoaddr(char *str);
+
+struct netbuf *mosi_strtoaddr(char *str);
+
+extern int cs_errno;
+
+void cs_perror(COMSTACK handle char *message);
+
+const char *cs_stackerr(COMSTACK handle);
+
+extern const char *cs_errlist[];
+</PRE>
+</CODE></BLOCKQUOTE>
+<P>
+<HR>
+<A HREF="yaz-7.html">Next</A>
+<A HREF="yaz-5.html">Previous</A>
+<A HREF="yaz.html#toc6">Contents</A>
+</BODY>
+</HTML>
Index: /main/tags/2.25/gsdl/packages/yaz/doc/yaz-7.html
===================================================================
--- /main/tags/2.25/gsdl/packages/yaz/doc/yaz-7.html	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/yaz/doc/yaz-7.html	(revision 21064)
@@ -0,0 +1,548 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN">
+<HTML>
+<HEAD>
+ <META NAME="GENERATOR" CONTENT="SGML-Tools 1.0.9">
+ <TITLE>YAZ User's Guide and Reference: Making an IR Interface for Your Database with YAZ</TITLE>
+ <LINK HREF="yaz-8.html" REL=next>
+ <LINK HREF="yaz-6.html" REL=previous>
+ <LINK HREF="yaz.html#toc7" REL=contents>
+</HEAD>
+<BODY>
+<A HREF="yaz-8.html">Next</A>
+<A HREF="yaz-6.html">Previous</A>
+<A HREF="yaz.html#toc7">Contents</A>
+<HR>
+<H2><A NAME="server"></A> <A NAME="s7">7. Making an IR Interface for Your Database with YAZ</A></H2>
+
+<H2><A NAME="ss7.1">7.1 Introduction</A>
+</H2>
+
+<P><I>NOTE: If you aren't into documentation, a good way to learn how the
+backend interface works is to look at the backend.h file. Then,
+look at the small dummy-server in server/ztest.c. Finally, you can
+have a look at the seshigh.c file, which is where most of the
+logic of the frontend server is located. The backend.h file also
+makes a good reference, once you've chewed your way through
+the prose of this file.</I>
+<P>If you have a database system that you would like to make available by
+means of Z39.50/SR, <B>YAZ</B> basically offers your two options. You
+can use the APIs provided by the <B>ASN</B>, <B>ODR</B>, and <B>COMSTACK</B>
+modules to
+create and decode PDUs, and exchange them with a client. Using this
+low-level interface gives you access to all fields and options of the
+protocol, and you can construct your server as close to your existing
+database as you like. It is also a fairly involved process, requiring
+you to set up an event-handling mechanism, protocol state machine,
+etc. To simplify server implementation, we have implemented a compact
+and simple, but reasonably full-functioned server-frontend that will
+handle most of the protocol mechanics, while leaving you to
+concentrate on your database interface.
+<P><I>NOTE: The backend interface was designed in anticipation of a specific
+integration task, while still attempting to achieve some degree of
+generality. We realise fully that there are points where the
+interface can be improved significantly. If you have specific
+functions or parameters that you think could be useful, send us a
+mail (or better, sign on to the mailing list referred to in the
+toplevel README file). We will try to fit good suggestions into future
+releases, to the extent that it can be done without requiring
+too many structural changes in existing applications.</I>
+<P>
+<H2><A NAME="ss7.2">7.2 The Database Frontend</A>
+</H2>
+
+<P>We refer to this software as a generic database frontend. Your
+database system is the <I>backend database</I>, and the interface between
+the two is called the <I>backend API</I>. The backend API consists of a
+small number of function prototypes and structure definitions. You are
+required to provide the <B>main()</B> routine for the server (which can be
+quite simple), as well as functions to match each of the prototypes.
+The interface functions that you write can use any mechanism you like
+to communicate with your database system: You might link the whole
+thing together with your database application and access it by
+function calls; you might use IPC to talk to a database server
+somewhere; or you might link with third-party software that handles
+the communication for you (like a commercial database client library).
+At any rate, the functions will perform the tasks of:
+<P>
+<UL>
+<LI>Initialization.</LI>
+<LI>Searching.</LI>
+<LI>Fetching records.</LI>
+<LI>Scanning the database index (if you wish to implement SCAN).</LI>
+</UL>
+<P>(more functions will be added in time to support as much of
+Z39.50-1995 as possible).
+<P>Because the model where pipes or sockets are used to access the backend
+database is a fairly common one, we have added a mechanism that allows this
+communication to take place asynchronously. In this mode, the frontend
+server doesn't have to block while the backend database is processing
+a request, but can wait for additional PDUs from the client.
+<P>
+<H2><A NAME="ss7.3">7.3 The Backend API</A>
+</H2>
+
+<P>The headers files that you need to use the interface are in the
+include/ directory. They are called <CODE>statserv.h</CODE> and <CODE>backend.h</CODE>. They
+will include other files from the <CODE>include</CODE> directory, so you'll
+probably want to use the -I option of your compiler to tell it where
+to find the files. When you run <CODE>make</CODE> in the toplevel <B>YAZ</B> directory,
+everything you need to create your server is put the lib/libyaz.a
+library. If you want OSI as well, you'll also need to link in the
+<CODE>libmosi.a</CODE> library from the xtimosi distribution (see the mosi.txt
+file), a well as the <CODE>lib/librfc.a</CODE> library (to provide OSI transport
+over RFC1006/TCP).
+<P>
+<H2><A NAME="ss7.4">7.4 Your main() Routine</A>
+</H2>
+
+<P>As mentioned, your <B>main()</B> routine can be quite brief. If you want to
+initialize global parameters, or read global configuration tables,
+this is the place to do it. At the end of the routine, you should call
+the function
+<P>
+<BLOCKQUOTE><CODE>
+<PRE>
+int statserv_main(int argc, char **argv);
+</PRE>
+</CODE></BLOCKQUOTE>
+<P><B>Statserv_main</B> will establish listening sockets according to the
+parameters given. When connection requests are received, the event
+handler will typically <B>fork()</B> to handle the new request. If you do use
+global variables, you should be aware, then, that these cannot be
+shared between associations, unless you explicitly disallow forking by
+command line parameters (we advise against this for any purposes
+except debugging, as a crash or hang in the server process will affect
+all users currently signed on to the server).
+<P>The server provides a mechanism for controlling some of its behavior
+without using command-line options. The function
+<P>
+<BLOCKQUOTE><CODE>
+<PRE>
+statserv_options_block *statserv_getcontrol(void);
+</PRE>
+</CODE></BLOCKQUOTE>
+<P>Will return a pointer to a <CODE>struct statserv_options_block</CODE> describing
+the current default settings of the server. The structure contains
+these elements:
+<P>
+<DL>
+<DT><B>int dynamic</B><DD><P>A boolean value, which determines whether the server
+will fork on each incoming request (TRUE), or not (FALSE). Default is
+TRUE.
+<DT><B>int loglevel</B><DD><P>Set this by ORing the constants defined in include/log.h.
+<DT><B>char logfile[ODR_MAXNAME+1]</B><DD><P>File for diagnostic output
+(&quot;&quot;: stderr).
+<DT><B>char apdufile[ODR_MAXNAME+1]</B><DD><P>Name of file for logging incoming and
+outgoing APDUs (&quot;&quot;: don't log APDUs, &quot;-&quot;: <CODE>stderr</CODE>).
+<DT><B>char default_listen[1024]</B><DD><P>Same form as the command-line
+specification of listener address. &quot;&quot;: no default listener address.
+Default is to listen at &quot;tcp:@:9999&quot;. You can only
+specify one default listener address in this fashion.
+<DT><B>enum oid_proto default_proto;</B><DD><P>Either <CODE>PROTO_SR</CODE> or <CODE>PROTO_Z3950</CODE>.
+Default is <CODE>PROTO_Z39_50</CODE>.
+<DT><B>int idle_timeout;</B><DD><P>Maximum session idletime, in minutes. Zero indicates
+no (infinite) timeout. Default is 120 minutes.
+<DT><B>int maxrecordsize;</B><DD><P>Maximum permissible record (message) size. Default
+is 1Mb. This amount of memory will only be allocated if a client requests a
+very large amount of records in one operation (or a big record). Set it
+to a lower number
+if you are worried about resource consumption on your host system.
+<DT><B>char configname[ODR_MAXNAME+1]</B><DD><P>Passed to the backend when a
+new connection is received.
+<DT><B>char setuid[ODR_MAXNAME+1]</B><DD><P>Set user id to the user specified,
+after binding the listener addresses.
+</DL>
+<P>The pointer returned by <CODE>statserv_getcontrol</CODE> points to a static area.
+You are allowed to change the contents of the structure, but the
+changes will not take effect before you call
+<P>
+<BLOCKQUOTE><CODE>
+<PRE>
+void statserv_setcontrol(statserv_options_block *block);
+</PRE>
+</CODE></BLOCKQUOTE>
+<P>Note that you should generally update this structure <I>before</I> calling
+<CODE>statserv_main()</CODE>.
+<P>
+<H2><A NAME="ss7.5">7.5 The Backend Functions</A>
+</H2>
+
+<P>For each service of the protocol, the backend interface declares one or
+two functions. You are required to provide implementations of the
+functions representing the services that you wish to implement.
+<P>
+<BLOCKQUOTE><CODE>
+<PRE>
+bend_initresult *bend_init(bend_initrequest *r);
+</PRE>
+</CODE></BLOCKQUOTE>
+<P>This function is called once for each new connection request, after
+a new process has been forked, and an initRequest has been received
+from the client. The parameter and result structures are defined as
+<P>
+<BLOCKQUOTE><CODE>
+<PRE>
+typedef struct bend_initrequest
+{
+    char *configname;
+} bend_initrequest;
+
+typedef struct bend_initresult
+{
+    int errcode;       /* 0==OK */
+    char *errstring;   /* system error string or NULL */
+    void *handle;      /* private handle to the backend module */
+} bend_initresult;
+</PRE>
+</CODE></BLOCKQUOTE>
+<P>The <CODE>configname</CODE> of <CODE>bend_initrequest</CODE> is currently always set to
+&quot;default-config&quot;. We haven't had use for putting anything special in
+the initrequest yet, but something might go there if the need arises
+(account/password info would be obvious).
+<P>In general, the server frontend expects that the <CODE>bend_*result</CODE>
+pointer that you return is valid at least until the next call to a
+<CODE>bend_* function</CODE>. This applies to all of the functions described
+herein. The parameter structure passed to you in the call belongs to
+the server frontend, and you should not make assumptions about its
+contents after the current function call has completed. In other
+words, if you want to retain any of the contents of a request
+structure, you should copy them.
+<P>The <CODE>errcode</CODE> should be zero if the initialization of the backend went
+well. Any other value will be interpreted as an error. The
+<CODE>errstring</CODE> isn't used in the current version, but one option
+would be to stick it
+in the initResponse as a VisibleString. The <CODE>handle</CODE> is the most
+important parameter. It should be set to some value that uniquely
+identifies the current session to the backend implementation. It is
+used by the frontend server in any future calls to a backend function.
+The typical use is to set it to point to a dynamically allocated state
+structure that is private to your backend module.
+<P>
+<BLOCKQUOTE><CODE>
+<PRE>
+bend_searchresult *bend_search(void *handle, bend_searchrequest *r,
+                               int *fd);
+bend_searchresult *bend_searchresponse(void *handle);
+
+typedef struct bend_searchrequest
+{
+    char *setname;       /* name to give to this set */
+    int replace_set;     /* replace set, if it already exists */
+    int num_bases;       /* number of databases in list */
+    char **basenames;    /* databases to search */
+    Z_Query *query;      /* query structure */
+} bend_searchrequest;
+
+typedef struct bend_searchresult
+{
+    int hits;            /* number of hits */
+    int errcode;         /* 0==OK */
+    char *errstring;     /* system error string or NULL */
+} bend_searchresult;
+</PRE>
+</CODE></BLOCKQUOTE>
+<P>The first thing to notice about the search request interface (as well
+as all of the following requests), is that it consists of two separate
+functions. The idea is to provide a simple facility for
+asynchronous communication with the backend server. When a
+searchrequest comes in, the server frontend will fill out the
+<CODE>bend_searchrequest</CODE> tructure, and call the <CODE>bend_search
+function</CODE>. The <CODE>fd</CODE>
+argument will point to an integer variable. If you are able to do
+asynchronous I/O with your database server, you should set *<CODE>fd</CODE> to the
+file descriptor you use for the communication, and return a null
+pointer. The server frontend will then <CODE>select()</CODE> on the *<CODE>fd</CODE>,
+and will call
+<CODE>bend_searchresult</CODE> when it sees that data is available. If you don't
+support asynchronous I/O, you should return a pointer to the
+<CODE>bend_searchresult</CODE> immediately, and leave *<CODE>fd</CODE> untouched. This
+construction is common to all of the <CODE>bend_</CODE> functions (except
+<CODE>bend_init</CODE>). Note that you can choose to support this facility in none,
+any, or all of the <CODE>bend_</CODE> functions, and you can respond
+differently on each request at run-time. The server frontend will
+adapt accordingly.
+<P>The <CODE>bend_searchrequest</CODE> is a fairly close approximation of a protocol
+searchRequest PDU. The <CODE>setname</CODE> is the resultSetName from the protocol. You
+are required to establish a mapping between the set name and whatever
+your backend database likes to use. Similarly, the <CODE>replace_set</CODE> is a
+boolean value corresponding to the resultSetIndicator field in the
+protocol. <CODE>Num_bases/basenames</CODE> is a length of/array of character
+pointers to the database names provided by the client. The <CODE>query</CODE> is the 
+full query structure as defined in the protocol ASN.1 specification.
+It can be either of the possible query types, and it's up to you to
+determine if you can handle the provided query type. Rather than
+reproduce the C interface here, we'll refer you to the structure
+definitions in the file <CODE>include/proto.h</CODE>. If you want to look at the
+attributeSetId OID of the RPN query, you can either match it against
+your own internal tables, or you can use the <CODE>oid_getentbyoid</CODE> function
+provided by <B>YAZ</B>.
+<P>The result structure contains a number of hits, and an
+<CODE>errcode/errstring</CODE> pair. If an error occurs during the search, or if
+you're unhappy with the request, you should set the errcode to a value
+from the BIB-1 diagnostic set. The value will then be returned to the
+user in a nonsurrogate diagnostic record in the response. The
+<CODE>errstring</CODE>, if provided, will go in the addinfo field. Look at the
+protocol definition for the defined error codes, and the suggested
+uses of the addinfo field.
+<P>
+<BLOCKQUOTE><CODE>
+<PRE>
+bend_fetchresult *bend_fetch(void *handle, bend_fetchrequest *r,
+                             int *fd);
+bend_fetchresult *bend_fetchresponse(void *handle);
+
+typedef struct bend_fetchrequest
+{
+    char *setname;       /* set name */
+    int number;          /* record number */
+    oid_value format;
+} bend_fetchrequest;
+
+typedef struct bend_fetchresult
+{
+    char *basename;      /* name of database that provided record */
+    int len;             /* length of record */
+    char *record;        /* record */
+    int last_in_set;     /* is it?  */
+    oid_value format;
+    int errcode;         /* 0==success */
+    char *errstring;     /* system error string or NULL */
+} bend_fetchresult;
+</PRE>
+</CODE></BLOCKQUOTE>
+<P><I>NOTE: The <CODE>bend_fetchresponse()</CODE> function is not yet supported
+in this version of the software. Your implementation of <CODE>bend_fetch()</CODE>
+should always return a pointer to a <CODE>bend_fetchresult</CODE>.</I>
+<P>The frontend server calls <CODE>bend_fetch</CODE> when it needs database records to
+fulfill a searchRequest or a presentRequest. The <CODE>setname</CODE> is simply the
+name of the result set that holds the reference to the desired record.
+The <CODE>number</CODE> is the offset into the set (with 1 being the first record
+in the set). The <CODE>format</CODE> field is the record format requested by the
+client (See section 
+<A HREF="yaz-3.html#oid">Object Identifiers</A>). The value
+<CODE>VAL_NONE</CODE> indicates that the client did not request a specific format.
+The <CODE>stream</CODE> argument is an <B>ODR</B> stream which should be used for
+allocating space for structured data records. The stream will be reset when
+all records have been assembled, and the response package has been transmitted.
+For unstructured data, the backend is responsible for maintaining a static
+or dynamic buffer for the record between calls.
+<P>In the result structure, the <CODE>basename</CODE> is the name of the
+database that holds the
+record. <CODE>Len</CODE> is the length of the record returned, in bytes, and
+<CODE>record</CODE>
+is a pointer to the record. <CODE>Last_in_set</CODE> should be nonzero only if the
+record returned is the last one in the given result set. <CODE>Errcode</CODE> and
+<CODE>errstring</CODE>, if given, will currently be interpreted as a global error
+pertaining to the set, and will be returned in a
+nonSurrogateDiagnostic.
+<P><I>NOTE: This is silly. Add a flag to say which is which.</I>
+<P>If the <CODE>len</CODE> field has the value -1, then <CODE>record</CODE> is assumed to point
+to a constructed data type. The <CODE>format</CODE> field will be used to determine
+which encoder should be used to serialize the data.
+<P><I>NOTE: If your backend generates structured records, it should use
+<CODE>odr_malloc()</CODE> on the provided stream for allocating data: This allows
+the frontend server to keep track of the record sizes.</I>
+<P>The <CODE>format</CODE> field is mapped to an object identifier in the direct
+reference of the resulting EXTERNAL representation of the record.
+<P><I>NOTE: The current version of <B>YAZ</B> only supports the direct reference
+mode.</I>
+<P>
+<BLOCKQUOTE><CODE>
+<PRE>
+bend_deleteresult *bend_delete(void *handle, bend_deleterequest *r,
+                               int *fd);
+bend_deleteresult *bend_deleteresponse(void *handle);
+
+typedef struct bend_deleterequest
+{
+    char *setname;
+} bend_deleterequest;
+
+typedef struct bend_deleteresult
+{
+    int errcode;         /* 0==success */
+    char *errstring;     /* system error string or NULL */
+} bend_deleteresult;
+</PRE>
+</CODE></BLOCKQUOTE>
+<P><I>NOTE: The &quot;delete&quot; function is not yet supported
+in this version of the software.</I>
+<P><I>NOTE: The delete set function definition is rather primitive, mostly
+because we
+have had no practical need for it as of yet. If someone wants
+to provide a full delete service, we'd be happy to add the
+extra parameters that are required. Are there clients out there
+that will actually delete sets they no longer need?</I>
+<P>
+<BLOCKQUOTE><CODE>
+<PRE>
+bend_scanresult *bend_scan(void *handle, bend_scanrequest *r,
+    int *fd);
+bend_scanresult *bend_scanresponse(void *handle);
+
+typedef struct bend_scanrequest
+{
+    int num_bases;      /* number of elements in databaselist */
+    char **basenames;   /* databases to search */
+    Z_AttributesPlusTerm *term;
+    int term_position;  /* desired index of term in result list */
+    int num_entries;    /* number of entries requested */
+} bend_scanrequest;
+
+typedef struct bend_scanresult
+{
+    int num_entries;
+    struct scan_entry
+    {
+        char *term;
+        int occurrences;
+    } *entries;
+    int term_position;
+    enum
+    {
+        BEND_SCAN_SUCCESS,
+        BEND_SCAN_PARTIAL
+    } status;
+    int errcode;
+    char *errstring;
+} bend_scanresult;
+</PRE>
+</CODE></BLOCKQUOTE>
+<P><I>NOTE: The <CODE>bend_scanresponse()</CODE> function is not yet supported
+in this version of the software. Your implementation of <CODE>bend_scan()</CODE>
+should always return a pointer to a <CODE>bend_scanresult</CODE>.</I>
+<P>
+<H2><A NAME="ss7.6">7.6 Application Invocation</A>
+</H2>
+
+<P>The finished application has the following
+invocation syntax (by way of <CODE>statserv_main()</CODE>):
+<P>
+<BLOCKQUOTE><CODE>
+ 
+<PRE>
+appname [-szSu -a apdufile -l logfile -v loglevel]
+[listener ...]
+</PRE>
+ 
+</CODE></BLOCKQUOTE>
+<P>The options are
+<P>
+<DL>
+<DT><B>-a</B><DD><P>APDU file. Specify a file for dumping PDUs (for diagnostic purposes).
+The special name &quot;-&quot; sends output to <CODE>stderr</CODE>.
+<P>
+<DT><B>-S</B><DD><P>Don't fork on connection requests. This is good for debugging, but
+not recommended for real operation: Although the server is
+asynchronous and non-blocking, it can be nice to keep a software
+malfunction (okay then, a crash) from affecting all current users.
+<P>
+<DT><B>-s</B><DD><P>Use the SR protocol.
+<P>
+<DT><B>-z</B><DD><P>Use the Z39.50 protocol (default). These two options complement
+eachother. You can use both multiple times on the same command
+line, between listener-specifications (see below). This way, you
+can set up the server to listen for connections in both protocols
+concurrently, on different local ports.
+<P>
+<DT><B>-l</B><DD><P>The logfile.
+<P>
+<DT><B>-v</B><DD><P>The log level. Use a comma-separated list of members of the set
+{fatal,debug,warn,log,all,none}.
+<DT><B>-u</B><DD><P>Set user ID. Sets the real UID of the server process to that of the
+given user. It's useful if you aren't comfortable with having the
+server run as root, but you need to start it as such to bind a
+privileged port.
+<P>
+<DT><B>-w</B><DD><P>Working directory.
+<DT><B>-i</B><DD><P>Use this when running from the <CODE>inetd</CODE> server.
+<P>
+<DT><B>-t</B><DD><P>Idle session timeout, in minutes.
+<P>
+<DT><B>-k</B><DD><P>Maximum record size/message size, in kilobytes.
+<P>
+</DL>
+<P>A listener specification consists of a transport mode followed by a
+colon (:) followed by a listener address. The transport mode is
+either <CODE>osi</CODE> or <CODE>tcp</CODE>.
+<P>For TCP, an address has the form
+<P>
+<BLOCKQUOTE><CODE>
+<PRE>
+hostname | IP-number [: portnumber]
+</PRE>
+</CODE></BLOCKQUOTE>
+<P>The port number defaults to 210 (standard Z39.50 port).
+<P>For osi, the address form is
+<P>
+<BLOCKQUOTE><CODE>
+<PRE>
+[t-selector /] hostname | IP-number [: portnumber]
+</PRE>
+</CODE></BLOCKQUOTE>
+<P>The transport selector is given as a string of hex digits (with an even
+number of digits). The default port number is 102 (RFC1006 port).
+<P>Examples
+<P>
+<BLOCKQUOTE><CODE>
+<PRE>
+tcp:dranet.dra.com
+
+osi:0402/dbserver.osiworld.com:3000
+</PRE>
+</CODE></BLOCKQUOTE>
+<P>In both cases, the special hostname &quot;@&quot; is mapped to
+the address INADDR_ANY, which causes the server to listen on any local
+interface. To start the server listening on the registered ports for
+Z39.50 and SR over OSI/RFC1006, and to drop root privileges once the
+ports are bound, execute the server like this (from a root shell):
+<P>
+<BLOCKQUOTE><CODE>
+<PRE>
+my-server -u daemon tcp:@ -s osi:@
+</PRE>
+</CODE></BLOCKQUOTE>
+<P>You can replace <CODE>daemon</CODE> with another user, eg. your own account, or
+a dedicated IR server account. <CODE>my-server</CODE> should be the name of your
+server application. You can test the procedure with the <CODE>ztest</CODE>
+application.
+<P>
+<H2><A NAME="ss7.7">7.7 Summary and Synopsis</A>
+</H2>
+
+<P>
+<BLOCKQUOTE><CODE>
+<PRE>
+#include &lt;backend.h>
+
+bend_initresult *bend_init(bend_initrequest *r);
+
+bend_searchresult *bend_search(void *handle, bend_searchrequest *r,
+                                 int *fd);
+
+bend_searchresult *bend_searchresponse(void *handle);
+
+bend_fetchresult *bend_fetch(void *handle, bend_fetchrequest *r,
+                               int *fd);
+
+bend_fetchresult *bend_fetchresponse(void *handle);
+
+bend_scanresult *bend_scan(void *handle, bend_scanrequest *r, int *fd);
+
+bend_scanresult *bend_scanresponse(void *handle);
+
+bend_deleteresult *bend_delete(void *handle, bend_deleterequest *r,
+                                  int *fd);
+
+bend_deleteresult *bend_deleteresponse(void *handle);
+
+void bend_close(void *handle);
+</PRE>
+</CODE></BLOCKQUOTE>
+<P>
+<HR>
+<A HREF="yaz-8.html">Next</A>
+<A HREF="yaz-6.html">Previous</A>
+<A HREF="yaz.html#toc7">Contents</A>
+</BODY>
+</HTML>
Index: /main/tags/2.25/gsdl/packages/yaz/doc/yaz-8.html
===================================================================
--- /main/tags/2.25/gsdl/packages/yaz/doc/yaz-8.html	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/yaz/doc/yaz-8.html	(revision 21064)
@@ -0,0 +1,42 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN">
+<HTML>
+<HEAD>
+ <META NAME="GENERATOR" CONTENT="SGML-Tools 1.0.9">
+ <TITLE>YAZ User's Guide and Reference: Future Directions</TITLE>
+ <LINK HREF="yaz-9.html" REL=next>
+ <LINK HREF="yaz-7.html" REL=previous>
+ <LINK HREF="yaz.html#toc8" REL=contents>
+</HEAD>
+<BODY>
+<A HREF="yaz-9.html">Next</A>
+<A HREF="yaz-7.html">Previous</A>
+<A HREF="yaz.html#toc8">Contents</A>
+<HR>
+<H2><A NAME="s8">8. Future Directions</A></H2>
+
+<P>The software has been
+successfully ported to the Mac as well as Windows NT/95 - we'd like to
+test those ports better and make sure they work as they should.
+<P>We have a new and better version of the frontend server on the drawing
+board. Resources and external commitments will govern when we'll be
+able to do something real with it. Fetures should include greater
+flexibility, greter support for access/resource control, and easy
+support for Explain (possibly with Zebra as an extra database engine).
+<P>We now support all PDUs of Z39.50-1995. If there is one of the
+supporting structures that you need but can't find in the prt*.h
+files, send us a note; it may be on its way.
+<P>The 'retrieval' module needs to be finalized and documented. We think
+it can form a useful resource for people dealing with complex record
+structures, but for now, you'll mostly have to chew through the code
+yourself to make use of it. Not acceptable.
+<P>Other than that, YAZ generally moves in the directions which appear to
+make the most people happy (including ourselves, as prime users of the
+software). If there's something you'd like to see in here, then drop
+us a note and let's see what we can come up with.
+<P>
+<HR>
+<A HREF="yaz-9.html">Next</A>
+<A HREF="yaz-7.html">Previous</A>
+<A HREF="yaz.html#toc8">Contents</A>
+</BODY>
+</HTML>
Index: /main/tags/2.25/gsdl/packages/yaz/doc/yaz-9.html
===================================================================
--- /main/tags/2.25/gsdl/packages/yaz/doc/yaz-9.html	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/yaz/doc/yaz-9.html	(revision 21064)
@@ -0,0 +1,83 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN">
+<HTML>
+<HEAD>
+ <META NAME="GENERATOR" CONTENT="SGML-Tools 1.0.9">
+ <TITLE>YAZ User's Guide and Reference: License</TITLE>
+ <LINK HREF="yaz-10.html" REL=next>
+ <LINK HREF="yaz-8.html" REL=previous>
+ <LINK HREF="yaz.html#toc9" REL=contents>
+</HEAD>
+<BODY>
+<A HREF="yaz-10.html">Next</A>
+<A HREF="yaz-8.html">Previous</A>
+<A HREF="yaz.html#toc9">Contents</A>
+<HR>
+<H2><A NAME="s9">9. License</A></H2>
+
+<H2><A NAME="ss9.1">9.1 Index Data Copyright</A>
+</H2>
+
+<P>Copyright &copy; 1995-2000 Index Data.
+<P>Permission to use, copy, modify, distribute, and sell this software and
+its documentation, in whole or in part, for any purpose, is hereby granted,
+provided that:
+<P>1. This copyright and permission notice appear in all copies of the
+software and its documentation. Notices of copyright or attribution
+which appear at the beginning of any file must remain unchanged.
+<P>2. The names of Index Data or the individual authors may not be used to
+endorse or promote products derived from this software without specific
+prior written permission.
+<P>THIS SOFTWARE IS PROVIDED "AS IS" AND WITHOUT WARRANTY OF ANY KIND,
+EXPRESS, IMPLIED, OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY
+WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
+IN NO EVENT SHALL INDEX DATA BE LIABLE FOR ANY SPECIAL, INCIDENTAL,
+INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND, OR ANY DAMAGES
+WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER OR
+NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF
+LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
+OF THIS SOFTWARE.
+<P>
+<H2><A NAME="ss9.2">9.2 Additional Copyright Statements</A>
+</H2>
+
+<P>The optional CCL query language interpreter is covered by the following
+license:
+<P>Copyright &copy; 1995, the EUROPAGATE consortium (see below).
+<P>The EUROPAGATE consortium members are:
+<P>University College Dublin
+Danmarks Teknologiske Videnscenter
+An Chomhairle Leabharlanna
+Consejo Superior de Investigaciones Cientificas
+<P>Permission to use, copy, modify, distribute, and sell this software and
+its documentation, in whole or in part, for any purpose, is hereby granted,
+provided that:
+<P>1. This copyright and permission notice appear in all copies of the
+software and its documentation. Notices of copyright or attribution
+which appear at the beginning of any file must remain unchanged.
+<P>2. The names of EUROPAGATE or the project partners may not be used to
+endorse or promote products derived from this software without specific
+prior written permission.
+<P>3. Users of this software (implementors and gateway operators) agree to
+inform the EUROPAGATE consortium of their use of the software. This
+information will be used to evaluate the EUROPAGATE project and the
+software, and to plan further developments. The consortium may use
+the information in later publications.
+<P>4. Users of this software agree to make their best efforts, when
+documenting their use of the software, to acknowledge the EUROPAGATE
+consortium, and the role played by the software in their work.
+<P>THIS SOFTWARE IS PROVIDED "AS IS" AND WITHOUT WARRANTY OF ANY KIND,
+EXPRESS, IMPLIED, OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY
+WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
+IN NO EVENT SHALL THE EUROPAGATE CONSORTIUM OR ITS MEMBERS BE LIABLE
+FOR ANY SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF
+ANY KIND, OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA
+OR PROFITS, WHETHER OR NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND
+ON ANY THEORY OF LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE
+USE OR PERFORMANCE OF THIS SOFTWARE.
+<P>
+<HR>
+<A HREF="yaz-10.html">Next</A>
+<A HREF="yaz-8.html">Previous</A>
+<A HREF="yaz.html#toc9">Contents</A>
+</BODY>
+</HTML>
Index: /main/tags/2.25/gsdl/packages/yaz/doc/yaz.html
===================================================================
--- /main/tags/2.25/gsdl/packages/yaz/doc/yaz.html	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/yaz/doc/yaz.html	(revision 21064)
@@ -0,0 +1,108 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN">
+<HTML>
+<HEAD>
+ <META NAME="GENERATOR" CONTENT="SGML-Tools 1.0.9">
+ <TITLE>YAZ User's Guide and Reference</TITLE>
+ <LINK HREF="yaz-1.html" REL=next>
+
+
+</HEAD>
+<BODY>
+<A HREF="yaz-1.html">Next</A>
+Previous
+Contents
+<HR>
+<H1>YAZ User's Guide and Reference</H1>
+
+<H2>
+<A HREF="http://www.indexdata.dk/">Index Data</A>, <CODE>
+<A HREF="mailto:info@indexdata.dk">info@indexdata.dk</A></CODE></H2>$Revision$
+<P><HR>
+<EM>This document is the programmer's guide and reference to the YAZ
+package. YAZ is a compact toolkit that provides access to the
+Z39.50/SR protocol, as well as a set of higher-level tools for
+implementing the server and client roles, respectively.
+The documentation can be used on its own, or as a reference when looking
+at the example applications provided with the package.</EM>
+<HR>
+<P>
+<H2><A NAME="toc1">1.</A> <A HREF="yaz-1.html">Introduction</A></H2>
+
+<P>
+<H2><A NAME="toc2">2.</A> <A HREF="yaz-2.html">Compilation and Installation</A></H2>
+
+<UL>
+<LI><A HREF="yaz-2.html#ss2.1">2.1 UNIX</A>
+<LI><A HREF="yaz-2.html#ss2.2">2.2 WIN32</A>
+</UL>
+<P>
+<H2><A NAME="toc3">3.</A> <A HREF="yaz-3.html">The ASN Module</A></H2>
+
+<UL>
+<LI><A HREF="yaz-3.html#ss3.1">3.1 Introduction</A>
+<LI><A HREF="yaz-3.html#ss3.2">3.2 Preparing PDUs</A>
+<LI><A HREF="yaz-3.html#ss3.3">3.3 Object Identifiers</A>
+<LI><A HREF="yaz-3.html#ss3.4">3.4 EXTERNAL Data</A>
+<LI><A HREF="yaz-3.html#ss3.5">3.5 PDU Contents Table</A>
+</UL>
+<P>
+<H2><A NAME="toc4">4.</A> <A HREF="yaz-4.html">Supporting Tools</A></H2>
+
+<UL>
+<LI><A HREF="yaz-4.html#ss4.1">4.1 Query Syntax Parsers</A>
+<LI><A HREF="yaz-4.html#ss4.2">4.2 Object Identifiers</A>
+<LI><A HREF="yaz-4.html#ss4.3">4.3 Nibble Memory</A>
+</UL>
+<P>
+<H2><A NAME="toc5">5.</A> <A HREF="yaz-5.html">The ODR Module</A></H2>
+
+<UL>
+<LI><A HREF="yaz-5.html#ss5.1">5.1 Introduction</A>
+<LI><A HREF="yaz-5.html#ss5.2">5.2 Using ODR</A>
+<LI><A HREF="yaz-5.html#ss5.3">5.3 Programming with ODR</A>
+<LI><A HREF="yaz-5.html#ss5.4">5.4 Debugging</A>
+</UL>
+<P>
+<H2><A NAME="toc6">6.</A> <A HREF="yaz-6.html">The COMSTACK Module</A></H2>
+
+<UL>
+<LI><A HREF="yaz-6.html#ss6.1">6.1 Introduction</A>
+<LI><A HREF="yaz-6.html#ss6.2">6.2 Common Functions</A>
+<LI><A HREF="yaz-6.html#ss6.3">6.3 Client Side</A>
+<LI><A HREF="yaz-6.html#ss6.4">6.4 Server Side</A>
+<LI><A HREF="yaz-6.html#ss6.5">6.5 Addresses</A>
+<LI><A HREF="yaz-6.html#ss6.6">6.6 Diagnostics</A>
+<LI><A HREF="yaz-6.html#ss6.7">6.7 Enabling OSI Communication</A>
+<LI><A HREF="yaz-6.html#ss6.8">6.8 Summary and Synopsis</A>
+</UL>
+<P>
+<H2><A NAME="toc7">7.</A> <A HREF="yaz-7.html">Making an IR Interface for Your Database with YAZ</A></H2>
+
+<UL>
+<LI><A HREF="yaz-7.html#ss7.1">7.1 Introduction</A>
+<LI><A HREF="yaz-7.html#ss7.2">7.2 The Database Frontend</A>
+<LI><A HREF="yaz-7.html#ss7.3">7.3 The Backend API</A>
+<LI><A HREF="yaz-7.html#ss7.4">7.4 Your main() Routine</A>
+<LI><A HREF="yaz-7.html#ss7.5">7.5 The Backend Functions</A>
+<LI><A HREF="yaz-7.html#ss7.6">7.6 Application Invocation</A>
+<LI><A HREF="yaz-7.html#ss7.7">7.7 Summary and Synopsis</A>
+</UL>
+<P>
+<H2><A NAME="toc8">8.</A> <A HREF="yaz-8.html">Future Directions</A></H2>
+
+<P>
+<H2><A NAME="toc9">9.</A> <A HREF="yaz-9.html">License</A></H2>
+
+<UL>
+<LI><A HREF="yaz-9.html#ss9.1">9.1 Index Data Copyright</A>
+<LI><A HREF="yaz-9.html#ss9.2">9.2 Additional Copyright Statements</A>
+</UL>
+<P>
+<H2><A NAME="toc10">10.</A> <A HREF="yaz-10.html">About Index Data</A></H2>
+
+<HR>
+<A HREF="yaz-1.html">Next</A>
+Previous
+Contents
+</BODY>
+</HTML>
Index: /main/tags/2.25/gsdl/packages/yaz/doc/yaz.sgml
===================================================================
--- /main/tags/2.25/gsdl/packages/yaz/doc/yaz.sgml	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/yaz/doc/yaz.sgml	(revision 21064)
@@ -0,0 +1,3543 @@
+<!doctype linuxdoc system>
+<article>
+<title>YAZ User's Guide and Reference
+<author><htmlurl url="http://www.indexdata.dk/" name="Index Data">, <tt><htmlurl url="mailto:info@indexdata.dk" name="info@indexdata.dk"></>
+<date>$Revision$
+<abstract>
+This document is the programmer's guide and reference to the YAZ
+package. YAZ is a compact toolkit that provides access to the
+Z39.50/SR protocol, as well as a set of higher-level tools for
+implementing the server and client roles, respectively.
+The documentation can be used on its own, or as a reference when looking
+at the example applications provided with the package.
+</abstract>
+
+<toc>
+
+<sect>Introduction
+
+<p>
+The <bf/YAZ/ toolkit offers several different levels of access to the
+Z39.50 and SR protocols. The level that you need to use depends on
+your requirements, and the role (server or client) that you
+want to implement.
+
+The basic level, which is independent of the role, consists of three
+primary interfaces:
+
+<itemize>
+<item><bf/ASN/, which provides a C representation of the Z39.50/SR protocol
+packages (PDUs).
+<item><bf/ODR/, which encodes and decodes the packages according to the BER
+specification.
+<item><bf/COMSTACK/, which exchanges the encoded packages with a peer process
+over a network.
+</itemize>
+
+The ASN module represents the ASN.1 definition of the
+SR/Z39.50 protocol. It establishes a set of type and
+structure definitions, with one structure for each of the top-level
+PDUs, and one structure or type for each of the contained ASN.1 types.
+For primitive types, or other types that are defined by the ASN.1
+standard itself (such as the EXTERNAL type), the C representation is provided
+by the <bf/ODR/ (Open Data Representation) subsystem.
+
+<bf/ODR/ is a basic mechanism for representing an
+ASN.1 type in the C programming language, and for implementing BER
+encoders and decoders for values of that type. The types defined in
+the <bf/ASN/
+module generally have the prefix <tt/Z_/, and a suffix corresponding to
+the name of the type in the ASN.1
+specification of the protocol (generally Z39.50-1995). In the case of
+base types (those originating in the ASN.1 standard itself), the prefix
+<tt/Odr_/ is sometimes seen. Either way, look for
+the actual definition in either <tt/proto.h/ (for the types from the
+protocol), <tt/odr.h/ (for the primitive ASN.1 types, or <tt/odr_use.h/ (for the
+ASN.1 <it/useful/ types). The <bf/ASN/ library also provides functions (which
+are, in turn, defined using <bf/ODR/ primitives) for encoding and decoding data
+values. Their general form is
+
+<tscreen><verb>
+int z_xxx(ODR o, Z_xxx **p, int optional, const char *name);
+</verb></tscreen>
+
+(note the lower-case &dquot;z&dquot; in the function name)
+
+<it>
+NOTE: If you are using the premade definitions of the <bf/ASN/ module, and
+you are not adding new protocol of your own, the only parts of ODR
+that you need to worry about are documented in section
+<ref id="odr-use" name="Using ODR">.
+</it>
+
+When you have created a BER-encoded buffer, you can use the <bf/COMSTACK/
+subsystem to transmit (or receive) data over the network. The <bf/COMSTACK/
+module provides simple functions for establishing a connection
+(passively or actively, depending on the role of your application),
+and for exchanging BER-encoded PDUs over that connection. When you
+create a connection endpoint, you need to specify what transport to
+use (OSI or TCP/IP), and which protocol you want to use (SR or
+Z39.50). For the remainer of the connection's lifetime, you don't have
+to worry about the underlying transport protocol at all - the <bf/COMSTACK/
+will ensure that the correct mechanism is used.
+
+We call the combined interfaces to <bf/ODR/, <bf/ASN/, and <bf/COMSTACK/ the service
+level API. It's the API that most closely models the Z39.50/SR
+service/protocol definition, and it provides unlimited access to all
+fields and facilities of the protocol definitions.
+
+The reason that the <bf/YAZ/ service-level API is a conglomerate of the
+APIs from three different submodules is twofold. First, we wanted to allow the
+user a choice of different options for each major task. For instance,
+if you don't like the protocol API provided by <bf/ODR//<bf/ASN/, you
+can use SNACC or BERUtils instead, and still have the benefits of the
+transparent transport approach of the <bf/COMSTACK/ module. Secondly,
+we realise that you may have to fit the toolkit into an existing
+event-processing structure, in a way that
+is incompatible with the <bf/COMSTACK/ interface or some other part of <bf/YAZ/.
+
+<sect>Compilation and Installation
+
+<p>
+The latest version of the software will generally be found at
+
+<tscreen><verb>
+http://ftp.indexdata.dk/pub/yaz/
+</verb></tscreen>
+
+We have tried our best to keep the software portable, and on many
+platforms, you should be able to compile everything with little or no changes.
+So far, the software has been ported
+to the following platforms with little or no difficulties.
+
+<itemize>
+<item>Unix systems
+<itemize>
+<item>HP/UX
+<item>SunOS/Solaris
+<item>DEC Unix
+<item>Linux
+<item>IBM AIX
+<item>Data General DG/UX (with some CFLAGS tinkering)
+<item>SGI/IRIX
+<item>DDE Supermax
+</itemize>
+<item>Non-unix systems
+<itemize>
+<item>Apple Macintosh (using the Codewarrior programming environment and the
+GUSI socket libraries)
+<item>MS Windows 95/NT (Win32)
+<item>IBM AS/400
+</itemize>
+</itemize>
+
+If you move the software to other platforms, we'd be grateful if you'd
+let us know about it. If you run into difficulties, we will try to help if we
+can, and if you solve the problems, we would be happy to
+include your fixes in the next release. So far, we have mostly avoided
+&num;ifdefs for individual platforms, and we'd like to keep it that
+way as far as it makes sense.
+
+We maintain a mailing-list for the purpose of announcing new releases and
+bug-fixes, as well as general discussion. Subscribe by sending mail to
+<tt/yaz-request@indexdata.dk/. General questions and problems can be
+directed at <tt/yaz-help@indexdata.dk/, or the address given at the top
+of this document.
+
+<sect1>UNIX
+
+<p>
+Note that if your system doesn't have a native ANSI C compiler, you may
+have to acquire one separately. We recommend gcc.
+
+For UNIX we use GNU configure to create Makefiles for YAZ.
+Generally it should be sufficient to run configure without options:
+
+<tscreen><verb>
+./configure
+</verb></tscreen>
+
+The configure script attempts to use use the C compiler specified by
+the <tt/CC/ environment variable. If not set, GNU C will be used
+if it is available. The <tt/CFLAGS/ environment variable holds options
+to be passed to the C compiler. If you're using Bourne-compatible shell
+you may pass something like this to use a particular C compiler with
+optimization enabled:
+<tscreen><verb>
+  CC=/opt/ccs/bin/cc CFLAGS=-O ./configure
+</verb></tscreen>
+
+To customize <bf/YAZ/ the configure script also accepts a set of options.
+The most important are:
+
+<descrip>
+<tag><tt>-</tt><tt>-prefix </tt>path</tag> Specifies installation prefix. This is
+only needed if you run <tt>make install</tt> later to perform a
+"system" installation. The prefix is <tt>/usr/local</tt> if not
+specified.
+
+<tag><tt>-</tt><tt>-enable-comp </tt></tag> YAZ will be built using
+the ASN.1 compiler for YAZ (default). If you wish to use the
+old decoders (in sub directory asn) use <tt>--disable-comp</tt> instead.
+
+<tag><tt>-</tt><tt>-enable-threads</tt></tag> YAZ will be built using
+POSIX threads. Specifically, <tt>_REENTRANT</tt> will be defined
+during compilation.
+</descrip>
+
+When configured, build the software by typing:
+<tscreen><verb>
+  make
+</verb></tscreen>
+
+Developers that do modifications to <bf/YAZ/ may wish to run
+<tt>make depend</tt> as well to generate object-header file
+dependencies.
+
+The following files are generated by make
+<descrip>
+<tag><tt>lib/libyaz.a</tt></tag> The <bf/YAZ/ programmers' library.
+
+<tag><tt>ztest/yaz-ztest</tt></tag> A test Z39.50 server.
+
+<tag><tt>client/yaz-client</tt></tag> A command mode Z39.50 client.
+
+<tag><tt>yaz-config</tt></tag> A Bourne-shell script that holds build
+settings for <bf/YAZ/.
+
+</descrip>
+
+If you wish to install <bf/YAZ/ in system directories such as /usr/local/bin,
+/usr/local/lib) you can type:
+
+<tscreen><verb>
+  make install
+</verb></tscreen>
+
+You probably need to have root access in order to perform this.
+You must specify the <tt>--prefix</tt> option for configure if you
+going to install in anything but /usr/local/.
+
+<sect1>WIN32
+
+<p>
+<bf/YAZ/ is shipped with "makefiles" for the NMAKE tool that comes
+with Visual C++.
+
+Start an MS-DOS prompt and switch the sub directory <tt>WIN</tt> where
+the file <tt>makefile</tt> is located. Customize the installation
+by editing the <tt>makefile</tt> file (for example by using notepad).
+
+The following summarises the most important settings in that file:
+
+<descrip>
+<tag><tt>NEW_Z3950</tt></tag> If 1, the auto-generated decoder/encoders
+for Z39.50 as written by the ASN.1 compiler will be used. If 0, the old
+decoders for Z39.50 will be used. Note, when 1, the setting TCL should
+point to the Tcl shell on your system.
+<tag><tt>DEBUG</tt></tag> If set to 1, the software is
+compiled with debugging libraries. If set to 0, the software
+is compiled with release (non-debugging) libraries.
+</descrip>
+
+When satisfied with the settings in the makefile type
+<tscreen><verb>
+nmake
+</verb></tscreen>
+
+The following is generated upon successful compilation:
+<descrip>
+<tag><tt>bin/yaz.dll</tt></tag> A multithreaded DLL with everything
+except the frontend server library.
+<tag><tt>lib/yaz.lib</tt></tag> An import library for <tt>yaz.dll</tt>.
+<tag><tt>lib/server.lib</tt></tag> The frontend server library.
+<tag><tt>bin/yaz-ztest.exe</tt></tag> A test Z39.50 server.
+<tag><tt>bin/yaz-client.exe</tt></tag> A command mode Z39.50 client.
+</descrip>
+
+<sect>The ASN Module
+
+<sect1>Introduction
+
+<p>
+The <bf/ASN/ module provides you with a set of C struct definitions for the
+various PDUs of the protocol, as well as for the complex types
+appearing within the PDUs. For the primitive data types, the C
+representation often takes the form of an ordinary C language type,
+such as <tt/int/. For ASN.1 constructs that have no direct
+representation in C, such as general octet strings and bit strings,
+the <bf/ODR/ module (see section <ref id="odr" name="ODR">) provides auxiliary
+definitions.
+
+<sect1>Preparing PDUs
+
+<p>
+A structure representing a complex ASN.1 type doesn't in itself contain the
+members of that type. Instead, the structure contains <it/pointers/ to
+the members of the type. This is necessary, in part, to allow a mechanism for
+specifying which of the optional structure (SEQUENCE) members are
+present, and which are not. It follows that you will need to somehow
+provide space for the individual members of the structure, and
+set the pointers to refer to the members.
+
+The conversion routines don't care how you allocate and maintain your
+C structures - they just follow the pointers that you provide.
+Depending on the complexity of your application, and your personal
+taste, there are at least three different approaches that you may take
+when you allocate the structures.
+
+<itemize>
+<item>
+You can use static or automatic local variables in the function that
+prepares the PDU. This is a simple approach, and it provides the most
+efficient form of memory management. While it works well for flat
+PDUs like the InitReqest, it will generally not be sufficient for say,
+the generation of an arbitrarily complex RPN query structure.
+<item>
+You can individually create the structure and its members using the
+<tt/malloc/(2) function. If you want to ensure that the data is freed when
+it is no longer needed, you will have to define a function that
+individually releases each member of a structure before freeing the
+structure itself.
+<item>
+You can use the <tt/odr_malloc()/ function (see section <ref
+id="odr-use"
+name="Using ODR"> for details). When you use <tt/odr_malloc()/, you can release
+all of the
+allocated data in a single operation, independent of any pointers and
+relations between the data. <tt/odr_malloc()/ is based on a
+&dquot;nibble-memory&dquot;
+scheme, in which large portions of memory are allocated, and then
+gradually handed out with each call to <tt/odr_malloc()/. The next time you
+call <tt/odr_reset()/, all of the memory allocated since the last call is
+recycled for future use (actually, it is placed on a free-list).
+<item>
+You can combine all of the methods described here. This will often be
+the most practical approach. For instance, you might use <tt/odr_malloc()/ to
+allocate an entire structure and some of its elements, while you leave
+other elements pointing to global or per-session default variables.
+</itemize>
+
+The <bf/ASN/ module provides an important aid in creating new PDUs. For
+each of the PDU types (say, <tt/Z_InitRequest/), a function is provided
+that allocates and initializes an instance of that PDU type for you.
+In the case of the InitRequest, the function is simply named
+<tt/zget_InitRequest()/, and it sets up reasonable default value for all of
+the mandatory members. The optional members are generally initialized to null
+pointers. This last aspect is very important: it ensures that if the
+PDU definitions are extended after you finish your implementation
+(to accommodate
+new versions of the protocol, say), you won't get into trouble with
+uninitialized pointers in your structures. The functions use
+<tt/odr_malloc()/ to
+allocate the PDUs and its members, so you can free everything again with a
+single call to <tt/odr_reset()/. We strongly recommend that you use the
+<tt/zget_*/
+functions whenever you are preparing a PDU (in a C++ API, the
+<tt/zget_/
+functions would probably be promoted to constructors for the
+individual types).
+
+The prototype for the individual PDU types generally look like this:
+
+<tscreen><verb>
+Z_<type> *zget_<type>(ODR o);
+</verb></tscreen>
+
+eg.:
+
+<tscreen><verb>
+Z_InitRequest *zget_InitRequest(ODR o);
+</verb></tscreen>
+
+The <bf/ODR/ handle should generally be your encoding stream, but it
+needn't be.
+
+As well as the individual PDU functions, a function <tt/zget_APDU()/ is
+provided, which allocates a toplevel Z-APDU of the type requested:
+
+<tscreen><verb>
+Z_APDU *zget_APDU(ODR o, int which);
+</verb></tscreen>
+
+The <tt/which/ parameter is (of course) the discriminator belonging to the
+<tt/Z_APDU/ CHOICE type. All of the interface described here is provided by
+the <bf/ASN/ module, and you access it through the <tt/proto.h/ header file.
+
+<sect1>Object Identifiers<label id="oid">
+
+<p>
+When you refer to object identifiers in your application, you need to
+be aware that SR and Z39.50 use two different set of OIDs to refer to
+the same objects. To handle this easily, <bf/YAZ/ provides a utility module
+to <bf/ASN/ which provides an internal representation of the OIDs used in
+both protocols. Each oid is described by a structure:
+
+<tscreen><verb>
+typedef struct oident
+{
+    enum oid_proto proto;
+    enum oid_class class;
+    enum oid_value value;
+    int oidsuffix[OID_SIZE];
+    char *desc;
+} oident;
+</verb></tscreen>
+
+The <tt/proto/ field can be set to either <tt/PROTO_SR/ or
+<tt/PROTO_Z3950/. The <tt/class/ might be, say, <tt/CLASS_RECSYN/, and the
+<tt/value/ might be <tt/VAL_USMARC/ for the USMARC record format. Functions
+
+<tscreen><verb>
+int *oid_ent_to_oid(struct oident *ent, int *dst);
+struct oident *oid_getentbyoid(int *o);
+</verb></tscreen>
+
+are provided to map between object identifiers and database entries.
+If you store a member of the <tt/oid_proto/ type in your association
+state information, it's a simple matter, at runtime, to generate the
+correct OID when you need it. For decoding, you can simply ignore the
+proto field, or if you're strict, you can verify that your peer is
+using the OID family from the correct protocol. The <tt/desc/ field is
+a short, human-readable name for the PDU, useful mainly for diagnostic
+output.
+
+<it>
+NOTE: The old function oid_getoidbyent still exists but is
+not thread safe. Use oid_ent_to_oid instead and pass an array of
+size OID_SIZE.
+</it>
+
+<it>
+NOTE: Plans are underway to merge the two protocols into a single
+definition, with one set of object identifiers. When this happens, the
+oid module will no longer be required to support protocol
+independence, but it should still be useful as a simple OID database.
+</it>
+
+<sect1>EXTERNAL Data
+
+<p>
+In order to achieve extensibility and adaptability to different
+application domains, the new version of the protocol defines many
+structures outside of the main ASN.1 specification, referencing them
+through ASN.1 EXTERNAL constructs. To simplify the construction and access
+to the externally referenced data, the <bf/ASN/ module defines a
+specialized version of the EXTERNAL construct, called <tt/Z_External/.
+It is defined thus:
+
+<tscreen><verb>
+typedef struct Z_External
+{
+    Odr_oid *direct_reference;
+    int *indirect_reference;
+    char *descriptor;
+    enum
+    {
+	/* Generic types */
+	Z_External_single = 0,
+	Z_External_octet,
+	Z_External_arbitrary,
+
+	/* Specific types */
+	Z_External_SUTRS,
+	Z_External_explainRecord,
+	Z_External_resourceReport1,
+	Z_External_resourceReport2
+
+	...
+
+    } which;
+    union
+    {
+	/* Generic types */
+	Odr_any *single_ASN1_type;
+	Odr_oct *octet_aligned;
+	Odr_bitmask *arbitrary;
+
+	/* Specific types */
+	Z_SUTRS *sutrs;
+	Z_ExplainRecord *explainRecord;
+	Z_ResourceReport1 *resourceReport1;
+	Z_ResourceReport2 *resourceReport2;
+
+	...
+
+    } u;
+} Z_External;
+</verb></tscreen>
+
+When decoding, the <bf/ASN/ module will attempt to determine which
+syntax describes the data by looking at the reference fields
+(currently only the direct-reference). For ASN.1 structured data, you
+need only consult the <tt/which/ field to determine the type of data.
+You can the access  the data directly through the union. When
+constructing data for encoding, you set the union pointer to point to
+the data, and set the <tt/which/ field accordingly. Remember also to
+set the direct (or indirect) reference to the correct OID for the data
+type. For non-ASN.1 data such as MARC records, use the
+<tt/octet_aligned/ arm of the union.
+
+Some servers return ASN.1 structured data values (eg. database
+records) as BER-encoded records placed in the <tt/octet-aligned/
+branch of the EXTERNAL CHOICE. The ASN-module will <it/not/
+automatically decode these records. To help you decode the records in
+the application, the function
+
+<tscreen><verb>
+Z_ext_typeent *z_ext_gettypebyref(oid_value ref);
+</verb></tscreen>
+
+Can be used to retrieve information about the known, external data
+types. The function return a pointer to a static area, or NULL, if no
+match for the given direct reference is found. The <tt/Z_ext_typeent/
+is defined as:
+
+<tscreen><verb>
+typedef struct Z_ext_typeent
+{
+    oid_value dref;    /* the direct-reference OID value. */
+    int what;          /* discriminator value for the external CHOICE */
+    Odr_fun fun;       /* decoder function */
+} Z_ext_typeent;
+</verb></tscreen>
+
+The <tt/what/ member contains the Z_External union discriminator value
+for the given type: For the SUTRS record syntax, the value would be
+<tt/Z_External_sutrs/. The <tt/fun/ member contains a pointer to the
+function which encodes/decodes the given type. Again, for the SUTRS
+record syntax, the value of <tt/fun/ would be <tt/z_SUTRS/ (a function
+pointer).
+
+If you receive an EXTERNAL which contains an octet-string value that
+you suspect of being an ASN.1-structured data value, you can use
+<tt/z_ext_gettypebyref/ to look for the provided direct-reference. If
+the return value is different from NULL, you can use the provided
+function to decode the BER string (see section <ref id="odr-use"
+name="Using ODR">). 
+
+If you want to <it/send/ EXTERNALs containing ASN.1-structured values
+in the occtet-aligned branch of the CHOICE, this is possible too.
+However, on the encoding phase, it requires a somewhat involved
+juggling around of the various buffers involved.
+
+If you need to add new, externally defined data types, you must update
+the struct above, in the source file <tt/prt-ext.h/, as well as the
+encoder/decoder in the file <tt/prt-ext.c/. When changing the latter,
+remember to update both the <tt/arm/ arrary and the list <tt/type_table/,
+which drives the CHOICE biasing that is necessary to tell the
+different, structured types apart on decoding.
+
+<it>
+NOTE: Eventually, the EXTERNAL processing will most likely
+automatically insert the correct OIDs or indirect-refs. First,
+however, we need to determine how application-context management
+(specifically the presentation-context-list) should fit into the
+various modules.
+</it>
+
+<sect1>PDU Contents Table
+
+<p>
+We include, for reference, a listing of the fields of each top-level
+PDU, as well as their default settings.
+
+<verb>
+Z_InitRequest
+-------------
+Field                        Type                Default value
+
+referenceId                  Z_ReferenceId       NULL
+protocolVersion              Odr_bitmask         Empty bitmask
+options                      Odr_bitmask         Empty bitmask
+preferredMessageSize         int                 30*1024
+maximumRecordSize            int                 30*1024
+idAuthentication             Z_IdAuthentication  NULL
+implementationId             char*               "YAZ (id=81)"
+implementationName           char*               "Index Data/YAZ"
+implementationVersion        char*               YAZ_VERSION
+userInformationField         Z_UserInformation   NULL
+otherInfo                    Z_OtherInformation  NULL
+
+Z_InitResponse
+--------------
+Field                        Type                Default value
+
+referenceId                  Z_ReferenceId       NULL
+protocolVersion              Odr_bitmask         Empty bitmask
+options                      Odr_bitmask         Empty bitmask
+preferredMessageSize         int                 30*1024
+maximumRecordSize            int                 30*1024
+result                       bool_t              TRUE
+implementationId             char*               "YAZ (id=81)"
+implementationName           char*               "Index Data/YAZ"
+implementationVersion        char*               YAZ_VERSION
+userInformationField         Z_UserInformat..    NULL
+otherInfo                    Z_OtherInformation  NULL
+
+Z_SearchRequest
+---------------
+Field                        Type                Default value
+
+referenceId                  Z_ReferenceId       NULL
+smallSetUpperBound           int                 0
+largeSetLowerBound           int                 1
+mediumSetPresentNumber       int                 0
+replaceIndicator             bool_t              TRUE
+resultSetName                char*               "default"
+num_databaseNames            int                 0
+databaseNames                char**              NULL
+smallSetElementSetNames      Z_ElementSetNames   NULL
+mediumSetElementSetNames     Z_ElementSetNames   NULL
+preferredRecordSyntax        Odr_oid             NULL
+query                        Z_Query             NULL
+additionalSearchInfo         Z_OtherInformation  NULL
+otherInfo                    Z_OtherInformation  NULL
+
+Z_SearchResponse
+----------------
+Field                        Type                Default value
+
+referenceId                  Z_ReferenceId       NULL
+resultCount                  int                 0
+numberOfRecordsReturned      int                 0
+nextResultSetPosition        int                 0
+searchStatus                 bool_t              TRUE
+resultSetStatus              int                 NULL
+presentStatus                int                 NULL
+records                      Z_Records           NULL
+additionalSearchInfo         Z_OtherInformation  NULL
+otherInfo                    Z_OtherInformation  NULL
+
+Z_PresentRequest
+----------------
+Field                        Type                Default value
+
+referenceId                  Z_ReferenceId       NULL
+resultSetId                  char*               "default"
+resultSetStartPoint          int                 1
+numberOfRecordsRequested     int                 10
+num_ranges                   int                 0
+additionalRanges             Z_Range             NULL
+recordComposition            Z_RecordComposition NULL
+preferredRecordSyntax        Odr_oid             NULL
+maxSegmentCount              int                 NULL
+maxRecordSize                int                 NULL
+maxSegmentSize               int                 NULL
+otherInfo                    Z_OtherInformation  NULL
+
+Z_PresentResponse
+-----------------
+Field                        Type                Default value
+
+referenceId                  Z_ReferenceId       NULL
+numberOfRecordsReturned      int                 0
+nextResultSetPosition        int                 0
+presentStatus                int                 Z_PRES_SUCCESS
+records                      Z_Records           NULL
+otherInfo                    Z_OtherInformation  NULL
+
+Z_DeleteResultSetRequest
+------------------------
+Field                        Type                Default value
+
+referenceId                  Z_ReferenceId       NULL
+deleteFunction               int                 Z_DeleteRequest_list
+num_ids                      int                 0
+resultSetList                char**              NULL
+otherInfo                    Z_OtherInformation  NULL
+
+Z_DeleteResultSetResponse
+-------------------------
+Field                        Type                Default value
+
+referenceId                  Z_ReferenceId       NULL
+deleteOperationStatus        int                 Z_DeleteStatus_success
+num_statuses                 int                 0
+deleteListStatuses           Z_ListStatus**      NULL
+numberNotDeleted             int                 NULL
+num_bulkStatuses             int                 0
+bulkStatuses                 Z_ListStatus        NULL
+deleteMessage                char*               NULL
+otherInfo                    Z_OtherInformation  NULL
+
+Z_ScanRequest
+-------------
+Field                        Type                Default value
+
+referenceId                  Z_ReferenceId       NULL
+num_databaseNames            int                 0
+databaseNames                char**              NULL
+attributeSet                 Odr_oid             NULL
+termListAndStartPoint        Z_AttributesPlus... NULL
+stepSize                     int                 NULL
+numberOfTermsRequested       int                 20
+preferredPositionInResponse  int                 NULL
+otherInfo                    Z_OtherInformation  NULL
+
+Z_ScanResponse
+--------------
+Field                        Type                Default value
+
+referenceId                  Z_ReferenceId       NULL
+stepSize                     int                 NULL
+scanStatus                   int                 Z_Scan_success
+numberOfEntriesReturned      int                 0
+positionOfTerm               int                 NULL
+entries                      Z_ListEntris        NULL
+attributeSet                 Odr_oid             NULL
+otherInfo                    Z_OtherInformation  NULL
+
+Z_TriggerResourceControlRequest
+-------------------------------
+Field                        Type                Default value
+
+referenceId                  Z_ReferenceId       NULL
+requestedAction              int                 Z_TriggerResourceCtrl_resou..
+prefResourceReportFormat     Odr_oid             NULL
+resultSetWanted              bool_t              NULL
+otherInfo                    Z_OtherInformation  NULL
+
+Z_ResourceControlRequest
+------------------------
+Field                        Type                Default value
+
+referenceId                  Z_ReferenceId       NULL
+suspendedFlag                bool_t              NULL
+resourceReport               Z_External          NULL
+partialResultsAvailable      int                 NULL
+responseRequired             bool_t              FALSE
+triggeredRequestFlag         bool_t              NULL
+otherInfo                    Z_OtherInformation  NULL
+
+Z_ResourceControlResponse
+-------------------------
+Field                        Type                Default value
+
+referenceId                  Z_ReferenceId       NULL
+continueFlag                 bool_t              TRUE
+resultSetWanted              bool_t              NULL
+otherInfo                    Z_OtherInformation  NULL
+
+Z_AccessControlRequest
+----------------------
+Field                        Type                Default value
+
+referenceId                  Z_ReferenceId       NULL
+which                        enum                Z_AccessRequest_simpleForm;
+u                            union               NULL
+otherInfo                    Z_OtherInformation  NULL
+
+Z_AccessControlResponse
+-----------------------
+Field                        Type                Default value
+
+referenceId                  Z_ReferenceId       NULL
+which                        enum                Z_AccessResponse_simpleForm
+u                            union               NULL
+diagnostic                   Z_DiagRec           NULL
+otherInfo                    Z_OtherInformation  NULL
+
+Z_Segment
+---------
+Field                        Type                Default value
+
+referenceId                  Z_ReferenceId       NULL
+numberOfRecordsReturned      int                 value=0
+num_segmentRecords           int                 0
+segmentRecords               Z_NamePlusRecord    NULL
+otherInfo                    Z_OtherInformation  NULL
+
+Z_Close
+-------
+Field                        Type                Default value
+
+referenceId                  Z_ReferenceId       NULL
+closeReason                  int                 Z_Close_finished
+diagnosticInformation        char*               NULL
+resourceReportFormat         Odr_oid             NULL
+resourceFormat               Z_External          NULL
+otherInfo                    Z_OtherInformation  NULL
+</verb>
+
+<sect>Supporting Tools
+
+<p>
+In support of the service API - primarily the ASN module, which
+provides the programmatic interface to the Z39.50 APDUs, YAZ contains
+a collection of tools that support the development of applications.
+
+<sect1>Query Syntax Parsers
+
+<p>
+Since the type-1 (RPN) query structure has no direct, useful string
+representation, every origin application needs to provide some form of
+mapping from a local query notation or representation to a
+<tt/Z_RPNQuery/ structure. Some programmers will prefer to construct
+the query manually, perhaps using <tt/odr_malloc()/ to simplify memory
+management. The YAZ distribution includes two separate,
+query-generating tools that may be of use to you.
+
+<sect2>Prefix Query Format
+
+<p>
+Since RPN or reverse polish notation is really just a fancy way of
+describing a suffix notation format (operator follows operands), it
+would seem that the confusion is total when we now introduce a prefix
+notation for RPN. The reason is one of simple laziness - it's somewhat
+simpler to interpret a prefix format, and this utility was designed
+for maximum simplicity, to provide a baseline representation for use
+in simple test applications and scripting environments (like Tcl). The
+demonstration client included with YAZ uses the PQF.
+
+The PQF is defined by the pquery module in the YAZ library. The
+<tt/pquery.h/ file provides the declaration of the functions
+
+<tscreen><verb>
+Z_RPNQuery *p_query_rpn (ODR o, oid_proto proto, const char *qbuf);
+
+Z_AttributesPlusTerm *p_query_scan (ODR o, oid_proto proto,
+      Odr_oid **attributeSetP, const char *qbuf);
+
+int p_query_attset (const char *arg);
+</verb></tscreen>
+
+The function <tt/p_query_rpn()/ takes as arguments an <bf/ODR/ stream
+(see section <ref id="odr" name="The ODR Module">) to provide a memory
+source (the structure created is released on the next call to
+<tt/odr_reset()/ on the stream/), a protocol identifier (one of the
+constants <tt/PROTO_Z3950/ and <tt/PROTO_SR/), an attribute set
+reference, and finally a null-terminated string holding the query
+string.
+
+If the parse went well, <tt/p_query_rpn()/ returns a pointer to a
+<tt/Z_RPNQuery/ structure which can be placed directly into a
+<tt/Z_SearchRequest/.
+
+The <tt/p_query_attset/ specifies which attribute set to use if
+the query doesn't specify one by the <tt/@attrset/ operator. The
+<tt/p_query_attset/ returns 0 if the argument is a valid attribute
+set specifier; otherwise the function returns -1.
+
+The grammar of the PQF is as follows:
+
+<tscreen><verb>
+Query ::= &lsqb; AttSet &rsqb; QueryStruct.
+
+AttSet ::= string.
+
+QueryStruct ::= { Attribute } Simple | Complex.
+
+Attribute ::= '@attr' AttributeType '=' AttributeValue.
+
+AttributeType ::= integer.
+
+AttributeValue ::= integer.
+
+Complex ::= Operator QueryStruct QueryStruct.
+
+Operator ::= '@and' | '@or' | '@not' | '@prox' Proximity.
+
+Simple ::= ResultSet | Term.
+
+ResultSet ::= '@set' string.
+
+Term ::= string | '"' string '"'.
+
+Proximity ::= Exclusion Distance Ordered Relation WhichCode UnitCode.
+
+Exclusion ::= '1' | '0' | 'void'.
+
+Distance ::= integer.
+
+Ordered ::= '1' | '0'.
+
+Relation ::= integer.
+
+WhichCode ::= 'known' | 'private' | integer.
+
+UnitCode ::= integer.
+</verb></tscreen>
+
+You will note that the syntax above is a fairly faithful
+representation of RPN, except for the <tt/Attibute/, which has been
+moved a step away from the term, allowing you to associate one or more
+attributes with an entire query structure. The parser will
+automatically apply the given attributes to each term as required.
+
+The following are all examples of valid queries in the PQF.
+
+<tscreen><verb>
+dylan
+
+"bob dylan"
+
+@or "dylan" "zimmerman"
+
+@set Result-1
+
+@or @and bob dylan @set Result-1
+
+@attr 4=1 @and @attr 1=1 "bob dylan" @attr 1=4 "slow train coming"
+
+@attr 4=1 @attr 1=4 "self portrait"
+
+@prox 0 3 1 2 k 2 dylan zimmerman
+</verb></tscreen>
+
+<sect2>Common Command Language
+
+<p>
+Not all users enjoy typing in prefix query structures and numerical
+attribute values, even in a minimalistic test client. In the library
+world, the more intuitive Common Command Language (or ISO 8777) has
+enjoyed some popularity - especially before the widespread
+availability of graphical interfaces. It is still useful in
+applications where you for some reason or other need to provide a
+symbolic language for expressing boolean query structures.
+
+The EUROPAGATE research project working under the Libraries programme
+of the European Commission's DG XIII has, amongst other useful tools,
+implemented a general-purpose CCL parser which produces an output
+structure that can be trivially converted to the internal RPN
+representation of YAZ (The <tt/Z_RPNQuery/ structure). Since the CCL
+utility - along with the rest of the software produced by EUROPAGATE -
+is made freely available on a liberal license, it is included as a
+supplement to YAZ.
+
+<sect3>CCL Syntax
+<p>
+The CCL parser obeys the following grammar for the FIND argument.
+The syntax is annotated by in the lines prefixed by <tt/--/.
+
+<tscreen><verb>
+CCL-Find ::= CCL-Find Op Elements
+           | Elements.
+
+Op ::= "and" | "or" | "not"
+-- The above means that Elements are separated by boolean operators.
+
+Elements ::= '(' CCL-Find ')'
+           | Set
+           | Terms
+           | Qualifiers Relation Terms
+           | Qualifiers Relation '(' CCL-Find ')'
+           | Qualifiers '=' string '-' string
+-- Elements is either a recursive definition, a result set reference, a
+-- list of terms, qualifiers followed by terms, qualifiers followed
+-- by a recursive definition or qualifiers in a range (lower - upper).
+
+Set ::= 'set' = string
+-- Reference to a result set
+
+Terms ::= Terms Prox Term
+        | Term
+-- Proximity of terms.
+
+Term ::= Term string
+       | string
+-- This basically means that a term may include a blank
+
+Qualifiers ::= Qualifiers ',' string
+             | string
+-- Qualifiers is a list of strings separated by comma
+
+Relation ::= '=' | '>=' | '<=' | '<>' | '>' | '<'
+-- Relational operators. This really doesn't follow the ISO8777
+-- standard.
+
+Prox ::= '%' | '!'
+-- Proximity operator
+
+</verb></tscreen>
+
+The following queries are all valid:
+
+<tscreen><verb>
+dylan
+
+"bob dylan"
+
+dylan or zimmerman
+
+set=1
+
+(dylan and bob) or set=1
+
+</verb></tscreen>
+Assuming that the qualifiers <tt/ti/, <tt/au/ and <tt/date/ 
+are defined we may use:
+<tscreen><verb>
+ti=self portrait
+
+au=(bob dylan and slow train coming)
+
+date>1980 and (ti=((self portrait)))
+</verb></tscreen>
+
+<sect3>CCL Qualifiers
+<p>
+
+Qualifiers are used to direct the search to a particular searchable
+index, such as title (ti) and author indexes (au). The CCL standard
+itself doesn't specify a particular set of qualifiers, but it does
+suggest a few short-hand notations. You can customize the CCL parser
+to support a particular set of qualifiers to relect the current target
+profile. Traditionally, a qualifier would map to a particular
+use-attribute within the BIB-1 attribute set. However, you could also
+define qualifiers that would set, for example, the
+structure-attribute.
+
+Consider a scenario where the target support ranked searches in the
+title-index. In this case, the user could specify
+<tscreen><verb>
+ti,ranked=knuth computer
+</verb></tscreen>
+and the <tt/ranked/ would map to structure=free-form-text
+(4=105) and the <tt/ti/ would map to title (1=4).
+
+A "profile" with a set predefined CCL qualifiers can be read from a
+file. The YAZ client reads its CCL qualifiers from a file named
+<tt/default.bib/. Each line in the file has the form:
+
+<it/qualifier-name/    <it/type/=<it/val/ <it/type/=<it/val/ ...
+
+where <it/qualifier-name/ is the name of the qualifier to be used
+(eg. <tt/ti/), <it/type/ is a BIB-1 category type and <it/val/ is the
+corresponding BIB-1 attribute value. The <it/type/ can be either
+numeric or it may be either <tt/u/ (use), <tt/r/ (relation), <tt/p/
+(position), <tt/s/ (structure), <tt/t/ (truncation) or <tt/c/
+(completeness). The <it/qualifier-name/ <tt/term/ has a special
+meaning. The types and values for this definition is used when <it/no/
+qualifier is present.
+
+Consider the following definition:
+<tscreen><verb>
+ti       u=4 s=1
+au       u=1 s=1
+term     s=105
+</verb></tscreen>
+Two qualifiers are defined, <tt/ti/ and <tt/au/. They both set the
+structure-attribute to phrase (1). <tt/ti/ sets the use-attribute to
+4. <tt/au/ sets the use-attribute to 1. When no qualifiers are used
+in the query the structure-attribute is set to free-form-text (105).
+
+<sect3>CCL API
+<p>
+
+All public definitions can be found in the header file <tt/ccl.h/.
+A profile identifier is of type <tt/CCL_bibset/. A profile must be
+created with the call to the function <tt/ccl_qual_mk/ which returns
+a profile handle of type <tt/CCL_bibset/.
+
+To read a file containing qualifier definitions the function
+<tt/ccl_qual_file/ may be convenient. This function takes an already
+opened <tt/FILE/ handle pointer as argument along with a
+<tt/CCL_bibset/ handle.
+
+To parse a simple string with a FIND query use the function
+<tscreen><verb>
+struct ccl_rpn_node *ccl_find_str (CCL_bibset bibset, const char *str,
+                                   int *error, int *pos);
+</verb></tscreen>
+which takes the CCL profile (<tt/bibset/) and query (<tt/str/) as
+input. Upon successful completion the RPN tree is returned. If an
+error eccur, such as a syntax error, the integer pointed to by
+<tt/error/ holds the error code and <tt/pos/ holds the offset inside
+query string in which the parsing failed.
+
+An english representation of the error may be obtained by calling
+the <tt/ccl_err_msg/ function. The error codes are listed in
+<tt/ccl.h/.
+
+To convert the CCL RPN tree (type <tt/struct ccl_rpn_node */) to the
+Z_RPNQuery of YAZ the function <tt/ccl_rpn_query/ must be used. This
+function which is part of YAZ is implemented in <tt/yaz-ccl.c/.
+After calling this function the CCL RPN tree is probably no longer
+needed. The <tt/ccl_rpn_delete/ destroys the CCL RPN tree.
+
+A CCL profile may be destroyed by calling the <tt/ccl_qual_rm/
+function.
+
+The token names for the CCL operators may be changed by setting the
+globals (all type <tt/char */) <tt/ccl_token_and/, <tt/ccl_token_or/,
+<tt/ccl_token_not/ and <tt/ccl_token_set/.
+An operator may have aliases, i.e. there may be more than one name for
+the operator. To do this, separate each alias with a space character.
+
+<sect1>Object Identifiers
+
+<p>
+The basic YAZ representation of an OID is an array of integers,
+terminated with the value -1. The <bf/ODR/ module provides two
+utility-functions to create and copy this type of data elements:
+
+<tscreen><verb>
+Odr_oid *odr_getoidbystr(ODR o, char *str);
+</verb></tscreen>
+
+Creates an OID based on a string-based representation using dots (.)
+to separate elements in the OID.
+
+<tscreen><verb>
+Odr_oid *odr_oiddup(ODR odr, Odr_oid *o);
+</verb></tscreen>
+
+Creates a copy of the OID referenced by the <it/o/ parameter. Both
+functions take an <bf/ODR/ stream as parameter. This stream is used to
+allocate memory for the data elements, which is released on a
+subsequent call to <tt/odr_reset()/ on that stream.
+
+The <bf/OID/ module provides a higher-level representation of the
+family of object identifers which describe the Z39.50 protocol and its
+related objects. The definition of the module interface is given in
+the <tt/oid.h/ file.
+
+The interface is mainly based on the <tt/oident/ structure. The
+definition of this structure looks like this:
+
+<tscreen><verb>
+typedef struct oident
+{
+    oid_proto proto;
+    oid_class oclass;
+    oid_value value;
+    int oidsuffix[OID_SIZE];
+    char *desc;
+} oident;
+</verb></tscreen>
+
+The <it/proto/ field takes one of the values
+
+<tscreen><verb>
+PROTO_Z3950
+PROTO_SR
+</verb></tscreen>
+
+If you don't care about talking to SR-based implementations (few
+exist, and they may become fewer still if and when the ISO SR and ANSI
+Z39.50 documents are merged into a single standard), you can ignore
+this field on incoming packages, and always set it to PROTO_Z3950
+for outgoing packages.
+
+The <it/oclass/ field takes one of the values
+
+<tscreen><verb>
+CLASS_APPCTX
+CLASS_ABSYN
+CLASS_ATTSET
+CLASS_TRANSYN
+CLASS_DIAGSET
+CLASS_RECSYN
+CLASS_RESFORM
+CLASS_ACCFORM
+CLASS_EXTSERV
+CLASS_USERINFO
+CLASS_ELEMSPEC
+CLASS_VARSET
+CLASS_SCHEMA
+CLASS_TAGSET
+CLASS_GENERAL
+</verb></tscreen>
+
+corresponding to the OID classes defined by the Z39.50 standard.
+
+Finally, the <it/value/ field takes one of the values
+
+<tscreen><verb>
+VAL_APDU
+VAL_BER
+VAL_BASIC_CTX
+VAL_BIB1
+VAL_EXP1
+VAL_EXT1
+VAL_CCL1
+VAL_GILS
+VAL_WAIS
+VAL_STAS
+VAL_DIAG1
+VAL_ISO2709
+VAL_UNIMARC
+VAL_INTERMARC
+VAL_CCF
+VAL_USMARC
+VAL_UKMARC
+VAL_NORMARC
+VAL_LIBRISMARC
+VAL_DANMARC
+VAL_FINMARC
+VAL_MAB
+VAL_CANMARC
+VAL_SBN
+VAL_PICAMARC
+VAL_AUSMARC
+VAL_IBERMARC
+VAL_EXPLAIN
+VAL_SUTRS
+VAL_OPAC
+VAL_SUMMARY
+VAL_GRS0
+VAL_GRS1
+VAL_EXTENDED
+VAL_RESOURCE1
+VAL_RESOURCE2
+VAL_PROMPT1
+VAL_DES1
+VAL_KRB1
+VAL_PRESSET
+VAL_PQUERY
+VAL_PCQUERY
+VAL_ITEMORDER
+VAL_DBUPDATE
+VAL_EXPORTSPEC
+VAL_EXPORTINV
+VAL_NONE
+VAL_SETM
+VAL_SETG
+VAL_VAR1
+VAL_ESPEC1
+</verb></tscreen>
+
+again, corresponding to the specific OIDs defined by the standard.
+
+The <it/desc/ field contains a brief, mnemonic name for the OID in
+question.
+
+The function
+
+<tscreen><verb>
+struct oident *oid_getentbyoid(int *o);
+</verb></tscreen>
+
+takes as argument an OID, and returns a pointer to a static area
+containing an <tt/oident/ structure. You typically use this function
+when you receive a PDU containing an OID, and you wish to branch out
+depending on the specific OID value.
+
+The function
+
+<tscreen><verb>
+int *oid_ent_to_oid(struct oident *ent, int *dst);
+</verb></tscreen>
+
+Takes as argument an <tt/oident/ structure - in which the <it/proto/,
+<it/oclass/, and <it/value/ fields are assumed to be set correctly -
+and returns a pointer to a the buffer as given by <it/dst/ 
+containing the base
+representation of the corresponding OID. The function returns
+NULL and the array dst is unchanged if a mapping couldn't place.
+The array <it/dst/ should be at least of size <tt>OID_SIZE</tt>.
+
+The <tt/oid_ent_to_oid()/ function can be used whenever you need to
+prepare a PDU containing one or more OIDs. The separation of the
+<it/protocol/ element from the remainer of the OID-description makes
+it simple to write applications that can communicate with either
+Z39.50 or OSI SR-based applications.
+
+The function
+
+<tscreen><verb>
+oid_value oid_getvalbyname(const char *name);
+</verb></tscreen>
+
+takes as argument a mnemonic OID name, and returns the <it/value/
+field of the first entry in the database that contains the given name
+in its <it/desc/ field.
+
+Finally, the module provides the following utility functions, whose
+meaning should be obvious:
+
+<tscreen><verb>
+void oid_oidcpy(int *t, int *s);
+void oid_oidcat(int *t, int *s);
+int oid_oidcmp(int *o1, int *o2);
+int oid_oidlen(int *o);
+</verb></tscreen>
+
+<it>
+NOTE: The <bf/OID/ module has been criticized - and perhaps rightly so
+- for needlessly abstracting the
+representation of OIDs. Other toolkits use a simple
+string-representation of OIDs with good results. In practice, we have
+found the interface comfortable and quick to work with, and it is a
+simple matter (for what it's worth) to create applications compatible
+with both ISO SR and Z39.50. Finally, the use of the <tt/oident/
+database is by no means mandatory. You can easily create your
+own system for representing OIDs, as long as it is compatible with the
+low-level integer-array representation of the ODR module.
+</it>
+
+<sect1>Nibble Memory
+
+<p>
+Sometimes when you need to allocate and construct a large,
+interconnected complex of structures, it can be a bit of a pain to
+release the associated memory again. For the structures describing the
+Z39.50 PDUs and related structures, it is convenient to use the
+memory-management system of the <bf/ODR/ subsystem (see
+<ref id="odr-use" name="Using ODR">). However, in some circumstances
+where you might otherwise benefit from using a simple nibble memory
+management system, it may be impractical to use <tt/odr_malloc()/ and
+<bf/odr_reset()/. For this purpose, the memory manager which also
+supports the <bf/ODR/ streams is made available in the <bf/NMEM/
+module. The external interface to this module is given in the
+<tt/nmem.h/ file.
+
+The following prototypes are given:
+
+<tscreen><verb>
+NMEM nmem_create(void);
+void nmem_destroy(NMEM n);
+void *nmem_malloc(NMEM n, int size);
+void nmem_reset(NMEM n);
+int nmem_total(NMEM n);
+void nmem_init(void);
+</verb></tscreen>
+
+The <tt/nmem_create()/ function returns a pointer to a memory control
+handle, which can be released again by <tt/nmem_destroy()/ when no
+longer needed. The function <tt/nmem_malloc()/ allocates a block of
+memory of the requested size. A call to <tt/nmem_reset()/ or
+<tt/nmem_destroy()/ will release all memory allocated on the handle
+since it was created (or since the last call to
+<tt/nmem_reset()/. The function <tt/nmem_total()/ returns the number
+of bytes currently allocated on the handle.
+
+Note that the nibble memory pool is shared amonst threads. Posix
+mutex'es and WIN32 Critical sections are introduced to keep the
+module thread safe. On WIN32 function <tt/nmem_init()/ initialises
+the Critical Section handle and should be called once before any
+other nmem function is used.
+
+<sect>The ODR Module<label id="odr">
+
+<sect1>Introduction
+
+<p>
+<bf/ODR/ is the BER-encoding/decoding subsystem of <bf/YAZ/. Care as been taken
+to isolate <bf/ODR/ from the rest of the package - specifically from the
+transport interface. <bf/ODR/ may be used in any context where basic
+ASN.1/BER representations are used.
+
+If you are only interested in writing a Z39.50 implementation based on
+the PDUs that are already provided with <bf/YAZ/, you only need to concern
+yourself with the section on managing ODR streams (section
+<ref id="odr-use" name="Using ODR">). Only if you need to
+implement ASN.1 beyond that which has been provided, should you
+worry about the second half of the documentation
+(section <ref id="odr-prog" name="Programming with ODR">). If you use
+one of the higher-level interfaces, you can skip this section entirely.
+
+This is important, so we'll repeat it for emphasis: <it>You do not
+need to read section <ref id="odr-prog" name="Programming with ODR"> to
+implement Z39.50 with <bf/YAZ/.</it>
+
+If you need a part of the protocol that isn't already in <bf/YAZ/, you
+should
+contact the authors before going to work on it yourself: We
+might already be working on it. Conversely, if you implement a useful
+part of the protocol before us, we'd be happy to include it in a
+future release.
+
+<sect1>Using ODR<label id="odr-use">
+
+<p>
+<sect2>ODR Streams
+
+<p>
+Conceptually, the ODR stream is the source of encoded data in the
+decoding mode; when encoding, it is the receptacle for the encoded
+data. Before you can use an ODR stream it must be allocated. This is
+done with the function
+
+<tscreen><verb>
+ODR odr_createmem(int direction);
+</verb></tscreen>
+
+The <tt/odr_createmem()/ function takes as argument one of three manifest
+constants: <tt/ODR_ENCODE/, <tt/ODR_DECODE/, or <tt/ODR_PRINT/. An
+ODR stream can be
+in only one mode - it is not possible to change its mode once it's
+selected. Typically, your program will allocate at least two ODR
+streams - one for decoding, and one for encoding.
+
+When you're done with the stream, you can use
+
+<tscreen><verb>
+void odr_destroy(ODR o);
+</verb></tscreen>
+
+to release the resources allocated for the stream.
+
+<sect2>Memory Management<label id="memory">
+
+<p>
+Two forms of memory management take place in the ODR system. The first
+one, which has to do with allocating little bits of memory (sometimes
+quite large bits of memory, actually) when a protocol package is
+decoded, and turned into a complex of interlinked structures. This
+section deals with this system, and how you can use it for your own
+purposes. The next section deals with the memory management which is
+required when encoding data - to make sure that a large enough buffer is
+available to hold the fully encoded PDU.
+
+The <bf/ODR/ module has its own memory management system, which is
+used whenever memory is required. Specifically, it is used to allocate
+space for data when decoding incoming PDUs. You can use the memory
+system for your own purposes, by using the function
+
+<tscreen><verb>
+void *odr_malloc(ODR o, int size);
+</verb></tscreen>
+
+You can't use the normal <tt/free/(2) routine to free memory allocated
+by this function, and <bf/ODR/ doesn't provide a parallel function. Instead,
+you can call
+
+<tscreen><verb>
+void odr_reset(ODR o, int size);
+</verb></tscreen>
+
+when you are done with the
+memory: Everything allocated since the last call to <tt/odr_reset()/ is
+released. The <tt/odr_reset()/ call is also required to clear up an
+error condition on a stream.
+
+The function
+
+<tscreen><verb>
+int odr_total(ODR o);
+</verb></tscreen>
+
+returns the number of bytes allocated on the stream since the last call to
+<tt/odr_reset()/.
+
+The memory subsystem of <bf/ODR/ is fairly efficient at allocating and
+releasing little bits of memory. Rather than managing the individual,
+small bits of space, the system maintains a freelist of larger chunks
+of memory, which are handed out in small bits. This scheme is
+generally known as a <it/nibble memory/ system. It is very useful for
+maintaing short-lived constructions such as protocol PDUs.
+
+If you want to retain a bit of memory beyond the next call to
+<tt/odr_reset()/, you can use the function
+
+<tscreen><verb>
+ODR_MEM odr_extract_mem(ODR o);
+</verb></tscreen>
+
+This function will give you control of the memory recently allocated
+on the ODR stream. The memory will live (past calls to <tt/odr_reset()/),
+until you call the function
+
+<tscreen><verb>
+void odr_release_mem(ODR_MEM p);
+</verb></tscreen>
+
+The opaque <tt/ODR_MEM/ handle has no other purpose than referencing
+the memory block for you until you want to release it.
+
+You can use <tt/odr_extract_mem()/ repeatedly between allocating data,
+to retain individual control of separate chunks of data.
+
+<sect2>Encoding and Decoding Data
+
+<p>
+When encoding data, the ODR stream will write the encoded octet string
+in an internal buffer. To retrieve the data, use the function
+
+<tscreen><verb>
+char *odr_getbuf(ODR o, int *len, int *size);
+</verb></tscreen>
+
+The integer pointed to by len is set to the length of the encoded
+data, and a pointer to that data is returned. *<tt/size/ is set to the size
+of the buffer (unless <tt/size/ is null, signalling that you are
+not interested in the size). The next call to a primitive function
+using the same ODR stream will overwrite the data, unless a different
+buffer has been supplied using the call
+
+<tscreen><verb>
+void odr_setbuf(ODR o, char *buf, int len, int can_grow);
+</verb></tscreen>
+
+which sets the encoding (or decoding) buffer used by <tt/o/ to
+<tt/buf/,
+using the length <tt/len/. Before a call to an encoding function,
+you can use <tt/odr_setbuf()/ to provide the stream with an encoding buffer
+of sufficient size (length). The <tt/can_grow/ parameter tells the encoding
+ODR stream whether it is allowed to use <tt/realloc/(2) to increase the size
+of the buffer when necessary. The default condition of a new encoding
+stream is equivalent to the results of calling
+
+<tscreen><verb>
+odr_setbuf(stream, 0, 0, 1);
+</verb></tscreen>
+
+In this case, the stream will allocate and reallocate memory as
+necessary. The stream reallocates memory by repeatedly doubling the
+size of the buffer - the result is that the buffer will typically
+reach its maximum, working size with only a small number of reallocation
+operations. The memory is freed by the stream when the latter is destroyed,
+unless it was assigned by the user with the <tt/can_grow/
+parameter set to zero (in this case, you are expected to retain
+control of the memory yourself).
+
+To assume full control of an encoded buffer, you must first call
+<tt/odr_getbuf()/ to fetch the buffer and its length. Next, you should
+call <tt/odr_setbuf()/ to provide a different buffer (or a null
+pointer) to the stream. In the simplest case, you will reuse the same
+buffer over and over again, and you will just need to call
+<tt/odr_getbuf()/ after each encoding operation to get the length and
+address of the buffer. Note that the stream may reallocate the buffer
+during an encoding operation, so it is necessary to retrieve the
+correct address after each encoding operation.
+
+It is important to realise that the ODR stream will not release this
+memory when you call <tt/odr_reset()/: It will merely update its
+internal pointers to prepare for the encoding of a new data value.
+When the stream is released by the <tt/odr_destroy()/ function, the
+memory given to it by odr_setbuf will be released <it/only/ if the
+<tt/can_grow/ parameter to <tt/odr_setbuf()/ was nonzero. The
+<tt/can_grow/ parameter, in other words, is a way of signalling who
+is to own the buffer, you or the ODR stream. If you never call
+<tt/odr_setbuf()/ on your encoding stream, which is typically the
+case, the buffer allocated by the stream will belong to the stream by
+default.
+
+When you wish to decode data, you should first call <tt/odr_setbuf()/, to
+tell the decoding stream where to find the encoded data, and how long
+the buffer is (the <tt/can_grow/ parameter is ignored by a decoding
+stream). After this, you can call the function corresponding to the
+data you wish to decode (eg, <tt/odr_integer()/ odr <tt/z_APDU()/).
+
+Examples of encoding/decoding functions:
+
+<tscreen><verb>
+int odr_integer(ODR o, int **p, int optional, const char *name);
+
+int z_APDU(ODR o, Z_APDU **p, int optional, const char *name);
+</verb></tscreen>
+
+If the data is absent (or
+doesn't match the tag corresponding to the type), the return value
+will be either 0 or 1 depending on the <tt/optional/ flag. If
+<tt/optional/
+is 0 and the data is absent, an error flag will be raised in the
+stream, and you'll need to call <tt/odr_reset()/ before you can use the
+stream again. If <tt/optional/ is nonzero, the pointer <it/pointed to/ by
+<tt/p/ will be set to the null value, and the function will return 1.
+The <tt/name/ argument is used to pretty-print the tag in question.
+It may be set to <tt/NULL/ if pretty-printing is not desired.
+
+If the data value is found where it's expected, the pointer
+<it/pointed to/ by the <tt/p/ argument will be set to point to the
+decoded type. The
+space for the type will be allocated and owned by the ODR stream, and
+it will live until you call <tt/odr_reset()/ on the stream. You cannot use
+<tt/free/(2) to release the memory. You can decode several data elements
+(by repeated calls to <tt/odr_setbuf()/ and your decoding function), and
+new memory will be allocated each time. When you do call
+<tt/odr_reset()/,
+everything decoded since the last call to <tt/odr_reset()/ will be
+released.
+
+The use of the double indirection can be a little confusing at first
+(its purpose will become clear later on, hopefully),
+so an example is in order. We'll encode an integer value, and
+immediately decode it again using a different stream. A useless, but
+informative operation.
+
+<tscreen><verb>
+void do_nothing_useful(int value)
+{
+    ODR encode, decode;
+    int *valp, *resvalp;
+    char *bufferp;
+    int len;
+
+    /* allocate streams */
+    if (!(encode = odr_createmem(ODR_ENCODE)))
+    	return;
+    if (!(decode = odr_createmem(ODR_DECODE)))
+    	return;
+
+    valp = &ero;value;
+    if (odr_integer(encode, &ero;valp, 0, 0) == 0)
+    {
+    	printf("encoding went bad\n");
+	return;
+    }
+    bufferp = odr_getbuf(encode, &ero;len);
+    printf("length of encoded data is &percnt;d\n", len);
+
+    /* now let's decode the thing again */
+    odr_setbuf(decode, bufferp, len);
+    if (odr_integer(decode, &ero;resvalp, 0, 0) == 0)
+    {
+    	printf("decoding went bad\n");
+	return;
+    }
+    printf("the value is &percnt;d\n", *resvalp);
+
+    /* clean up */
+    odr_destroy(encode);
+    odr_destroy(decode);
+}
+</verb></tscreen>
+
+This looks like a lot of work, offhand. In practice, the ODR streams
+will typically be allocated once, in the beginning of your program (or at the
+beginning of a new network session), and the encoding and decoding
+will only take place in a few, isolated places in your program, so the
+overhead is quite manageable.
+
+<sect2>Diagnostics
+
+<p>
+The encoding/decoding functions all return 0 when an error occurs.
+Until you call <tt/odr_reset()/, you cannot use the stream again, and
+any function called will immediately return 0.
+
+To provide information to the programmer or administrator, the
+function
+
+<tscreen><verb>
+void odr_perror(ODR o, char *message);
+</verb></tscreen>
+
+is provided, which prints the <tt/message/ argument to <tt/stderr/
+along with an error message from the stream.
+
+You can also use the function
+
+<tscreen><verb>
+int odr_geterror(ODR o);
+</verb></tscreen>
+
+to get the current error number from the screen. The number will be
+one of these constants:
+
+<descrip>
+<tag/OMEMORY/Memory allocation failed.
+<tag/OSYSERR/A system- or library call has failed. The standard
+diagnostic variable <tt/errno/
+should be examined to determine the actual error.
+<tag/OSPACE/No more space for encoding. This will only occur when the user has
+explicitly provided a buffer for an encoding stream without allowing
+the system to allocate more space.
+<tag/OREQUIRED/This is a common protocol error; A required data element was
+missing during
+encoding or decoding.
+<tag/OUNEXPECTED/An unexpected data element was found during decoding.
+<tag/OOTHER/Other error. This is typically an indication of misuse of
+the <bf/ODR/ system by the programmer, and also that the diagnostic
+system isn't as good as it should be, yet.
+</descrip>
+
+The character string array
+
+<tscreen><verb>
+char *odr_errlist&lsqb;&rsqb;
+</verb></tscreen>
+
+can be indexed by the error code to obtain a human-readable
+representation of the problem.
+
+<sect2>Summary and Synopsis
+
+<p>
+<tscreen><verb>
+#include <odr.h>
+
+ODR odr_createmem(int direction);
+
+void odr_destroy(ODR o);
+
+void odr_reset(ODR o);
+
+char *odr_getbuf(ODR o, int *len);
+
+void odr_setbuf(ODR o, char *buf, int len);
+
+void *odr_malloc(ODR o, int size);
+
+ODR_MEM odr_extract_mem(ODR o);
+
+void odr_release_mem(ODR_MEM r);
+
+int odr_geterror(ODR o);
+
+void odr_perror(char *message);
+
+extern char *odr_errlist[];
+</verb></tscreen>
+
+<sect1>Programming with ODR<label id="odr-prog">
+
+<p>
+The API of <bf/ODR/ is designed to reflect the structure of ASN.1, rather
+than BER itself. Future releases may be able to represent data in
+other external forms.
+
+The interface is based loosely on that of the Sun Microsystems XDR routines.
+Specifically, each function which corresponds to an ASN.1 primitive
+type has a dual function. Depending on the settings of the ODR
+stream which is supplied as a parameter, the function may be used
+either to encode or decode data. The functions that can be built
+using these primitive functions, to represent more complex datatypes, share
+this quality. The result is that you only have to enter the definition
+for a type once - and you have the functionality of encoding, decoding
+(and pretty-printing) all in one unit. The resulting C source code is
+quite compact, and is a pretty straightforward representation of the
+source ASN.1 specification. Although no ASN.1 compiler is supplied
+with <bf/ODR/ at this time, it shouldn't be too difficult to write one, or
+perhaps even to adapt an existing compiler to output <bf/ODR/ routines
+(not surprisingly, writing encoders/decoders using <bf/ODR/ turns out
+to be boring work).
+
+In many cases, the model of the XDR functions works quite well in this
+role. In
+others, it is less elegant. Most of the hassle comes from the optional
+SEQUENCE memebers which don't exist in XDR.
+
+<sect2>The Primitive ASN.1 Types
+
+<p>
+ASN.1 defines a number of primitive types (many of which correspond
+roughly to
+primitive types in structured programming languages, such as C).
+
+<sect3>INTEGER
+
+<p>
+The <bf/ODR/ function for encoding or decoding (or printing) the ASN.1
+INTEGER type looks like this:
+
+<tscreen><verb>
+int odr_integer(ODR o, int **p, int optional, const char *name);
+</verb></tscreen>
+
+(we don't allow values that can't be contained in a C integer.)
+
+This form is typical of the primitive <bf/ODR/ functions. They are named
+after the type of data that they encode or decode. They take an
+ODR
+stream, an indirect reference to the type in question, and an
+<tt/optional/ flag (corresponding to the OPTIONAL keyword of ASN.1) as
+parameters. They all return an integer value of either one or zero.
+When you use the primitive functions to construct encoders for complex
+types of your own, you should follow this model as well. This
+ensures that your new types can be reused as elements in yet more
+complex types.
+
+The <tt/o/ parameter should obviously refer to a properly
+initialized ODR
+stream of the right type (encoding/decoding/printing) for the
+operation that you wish to perform.
+
+When encoding or printing, the function first looks at *<tt/p/. If
+*<tt/p/ (the
+pointer pointed to by <tt/p/) is a null pointer, this is taken to mean that
+the data element is absent. If the <tt/optional/ parameter is nonzero,
+the function will return one (signifying success) without any further
+processing. If the <tt/optional/ is zero, an internal error flag is
+set in the ODR stream, and the function will return 0. No further
+operations can be carried out on the stream without a call to
+the function <tt/odr_reset()/.
+
+If *<tt/p/ is not a null pointer, it is expected to point to an instance of
+the data type. The data will be subjected to the encoding rules, and
+the result will be placed in the buffer held by the ODR stream.
+
+The other ASN.1 primitives have similar functions that operate in
+similar manners:
+
+<sect3>BOOLEAN
+
+<p>
+<tscreen><verb>
+int odr_bool(ODR o, bool_t **p, int optional, const char *name);
+</verb></tscreen>
+
+<sect3>REAL
+
+<p>
+Not defined.
+
+<sect3>NULL
+
+<p>
+<tscreen><verb>
+int odr_null(ODR o, bool_t **p, int optional, const char *name);
+</verb></tscreen>
+
+In this case, the value of **p is not important. If *p is different
+from the null pointer, the null value is present, otherwise it's
+absent.
+
+<sect3>OCTET STRING
+
+<p>
+<tscreen><verb>
+typedef struct odr_oct
+{
+    unsigned char *buf;
+    int len;
+    int size;
+} Odr_oct;
+
+int odr_octetstring(ODR o, Odr_oct **p, int optional, const char *name);
+</verb></tscreen>
+
+The <tt/buf/ field should point to the character array that holds the
+octetstring. The <tt/len/ field holds the actual length, while the
+<tt/size/
+field gives the size of the allocated array (not of interest to you,
+in most cases). The character array need not be null terminated.
+
+To make things a little easier, an alternative is given for string
+types that are not expected to contain embedded NULL characters (eg.
+VisibleString):
+
+<tscreen><verb>
+int odr_cstring(ODR o, char **p, int optional, const char *name);
+</verb></tscreen>
+
+Which encoded or decodes between OCTETSTRING representations and
+null-terminates C strings.
+
+Functions are provided for the derived string types, eg:
+
+<tscreen><verb>
+int odr_visiblestring(ODR o, char **p, int optional, const char *name);
+</verb></tscreen>
+
+<sect3>BIT STRING
+
+<p>
+<tscreen><verb>
+int odr_bitstring(ODR o, Odr_bitmask **p, int optional, const char *name);
+</verb></tscreen>
+
+The opaque type <tt/Odr_bitmask/ is only suitable for holding relatively brief bit
+strings, eg. for options fields, etc. The constant
+<tt/ODR_BITMASK_SIZE/
+multiplied by 8 gives the maximum possible number of bits.
+
+A set of macros are provided for manipulating the
+<tt/Odr_bitmask/
+type:
+
+<tscreen><verb>
+void ODR_MASK_ZERO(Odr_bitmask *b);
+
+void ODR_MASK_SET(Odr_bitmask *b, int bitno);
+
+void ODR_MASK_CLEAR(Odr_bitmask *b, int bitno);
+
+int ODR_MASK_GET(Odr_bitmask *b, int bitno);
+</verb></tscreen>
+
+The functions are modelled after the manipulation functions that
+accompany the <tt/fd_set/ type used by the <tt/select/(2) call.
+<tt/ODR_MASK_ZERO/ should always be called first on a new bitmask, to
+initialize the bits to zero.
+
+<sect3>OBJECT IDENTIFIER
+
+<p>
+<tscreen><verb>
+int odr_oid(ODR o, Odr_oid **p, int optional, const char *name);
+</verb></tscreen>
+
+The C OID represenation is simply an array of integers, terminated by
+the value -1 (the <tt/Odr_oid/ type is synonymous with the <tt/int/
+type). We suggest that you use the OID database module (see section
+<ref id="oid" name="Object Identifiers">) to handle object identifiers
+in your application.
+
+<sect2>Tagging Primitive Types<label id="tag-prim">
+
+<p>
+The simplest way of tagging a type is to use the <tt/odr_implicit_tag()/ or
+<tt/odr_explicit_tag()/ macros:
+
+<tscreen><verb>
+int odr_implicit_tag(ODR o, Odr_fun fun, int class, int tag, int
+                     optional, const char *name);
+
+int odr_explicit_tag(ODR o, Odr_fun fun, int class, int tag,
+                     int optional, const char *name);
+</verb></tscreen>
+
+To create a type derived from the integer type by implicit tagging, you
+might write:
+
+<tscreen><verb>
+MyInt ::= &lsqb;210&rsqb; IMPLICIT INTEGER
+</verb></tscreen>
+
+In the <bf/ODR/ system, this would be written like:
+
+<tscreen><verb>
+int myInt(ODR o, int **p, int optional, const char *name)
+{
+    return odr_implicit_tag(o, odr_integer, p,
+                   ODR_CONTEXT, 210, optional, name);
+}
+</verb></tscreen>
+
+The function <tt/myInt()/ can then be used like any of the primitive
+functions provided by ODR. Note that the behavior of
+<tt/odr_explicit()/
+and <tt/odr_implicit()/ macros act exactly the same as the functions they
+are applied to - they respond to error conditions, etc, in the same
+manner - they simply have three extra parameters. The class parameter may
+take one of the values: <tt/ODR_CONTEXT/, <tt/ODR_PRIVATE/,
+<tt/ODR_UNIVERSAL/, or
+<tt/ODR_APPLICATION/.
+
+<sect2>Constructed Types
+
+<p>
+Constructed types are created by combining primitive types. The
+<bf/ODR/
+system only implements the SEQUENCE and SEQUENCE OF constructions
+(although adding the rest of the container types should be simple
+enough, if the need arises).
+
+For implementing SEQUENCEs, the functions
+
+<tscreen><verb>
+int odr_sequence_begin(ODR o, void *p, int size, const char *name);
+int odr_sequence_end(ODR o);
+</verb></tscreen>
+
+are provided.
+
+The <tt/odr_sequence_begin()/ function should be called in the beginning of a
+function that implements a SEQUENCE type. Its parameters are the
+<bf/ODR/
+stream, a pointer (to a pointer to the type you're implementing), and
+the <tt/size/ of the type (typically a C structure). On encoding, it
+returns 1 if *<tt/p/ is a null pointer. The <tt/size/ parameter is ignored. On
+decoding, it returns 1 if the type is found in the data stream.
+<tt/size/
+bytes of memory are allocated, and *<tt/p/ is set to point to this space.
+<tt/odr_sequence_end()/ is called at the end of the complex function. Assume
+that a type is defined like this:
+
+<tscreen><verb>
+MySequence ::= SEQUENCE {
+    intval INTEGER,
+    boolval BOOLEAN OPTIONAL }
+</verb></tscreen>
+
+The corresponding ODR encoder/decoder function and the associated data
+structures could be written like this:
+
+<tscreen><verb>
+typedef struct MySequence
+{
+    int *intval;
+    bool_t *boolval;
+} MySequence;
+
+int mySequence(ODR o, MySequence **p, int optional, const char *name)
+{
+    if (odr_sequence_begin(o, p, sizeof(**p), name) == 0)
+    	return optional &ero;&ero; odr_ok(o);
+    return
+    	odr_integer(o, &ero;(*p)->intval, 0, "intval") &ero;&ero;
+	odr_bool(o, &ero;(*p)->boolval, 1, "boolval") &ero;&ero;
+	odr_sequence_end(o);
+}
+</verb></tscreen>
+
+Note the 1 in the call to <tt/odr_bool()/, to mark that the sequence
+member is optional. If either of the member types had been tagged, the
+macros <tt/odr_implicit()/ or <tt/odr_explicit()/ could have been used.
+The new
+function can be used exactly like the standard functions provided with
+<bf/ODR/. It will encode, decode or pretty-print a data value of the
+<tt/MySequence/ type. We like to name types with an initial capital, as
+done in ASN.1 definitions, and to name the corresponding function with
+the first character of the name in lower case. You could, of course,
+name your structures, types, and functions any way you please - as
+long as you're consistent, and your code is easily readable.
+<tt/odr_ok/ is
+just that - a predicate that returns the state of the stream. It is
+used to ensure that the behaviour of the new type is compatible with
+the interface of the primitive types.
+
+<sect2>Tagging Constructed Types
+
+<p>
+<it>
+NOTE: See section <ref id="tag-prim" name="Tagging Primitive types">
+for information on how to tag the primitive types, as well as types
+that are already defined.
+</it>
+
+<sect3>Implicit Tagging
+
+<p>
+Assume the type above had been defined as
+
+<tscreen><verb>
+MySequence ::= &lsqb;10&rsqb; IMPLICIT SEQUENCE {
+    intval INTEGER,
+    boolval BOOLEAN OPTIONAL }
+</verb></tscreen>
+
+You would implement this in <bf/ODR/ by calling the function
+
+<tscreen><verb>
+int odr_implicit_settag(ODR o, int class, int tag);
+</verb></tscreen>
+
+which overrides the tag of the type immediately following it. The
+macro <tt/odr_implicit()/ works by calling <tt/odr_implicit_settag()/
+immediately
+before calling the function pointer argument. Your type function could
+look like this:
+
+<tscreen><verb>
+int mySequence(ODR o, MySequence **p, int optional, const char *name)
+{
+    if (odr_implicit_settag(o, ODR_CONTEXT, 10) == 0 ||
+    	odr_sequence_begin(o, p, sizeof(**p), name) == 0)
+    	return optional &ero;&ero; odr_ok(o);
+    return
+    	odr_integer(o, &ero;(*p)->intval, 0, "intval") &ero;&ero;
+	odr_bool(o, &ero;(*p)->boolval, 1, "boolval") &ero;&ero;
+	odr_sequence_end(o);
+}
+</verb></tscreen>
+
+The definition of the structure <tt/MySequence/ would be the same.
+
+<sect3>Explicit Tagging
+
+<p>
+Explicit tagging of constructed types is a little more complicated,
+since you are in effect adding a level of construction to the data.
+
+Assume the definition:
+
+<tscreen><verb>
+MySequence ::= &lsqb;10&rsqb; IMPLICIT SEQUENCE {
+    intval INTEGER,
+    boolval BOOLEAN OPTIONAL }
+</verb></tscreen>
+
+Since the new type has an extra level of construction, two new functions
+are needed to encapsulate the base type:
+
+<tscreen><verb>
+int odr_constructed_begin(ODR o, void *p, int class, int tag,
+       const char *name);
+
+int odr_constructed_end(ODR o);
+</verb></tscreen>
+
+Assume that the IMPLICIT in the type definition above were replaced
+with EXPLICIT (or that the IMPLICIT keyword were simply deleted, which
+would be equivalent). The structure definition would look the same,
+but the function would look like this:
+
+<tscreen><verb>
+int mySequence(ODR o, MySequence **p, int optional, const char *name)
+{
+    if (odr_constructed_begin(o, p, ODR_CONTEXT, 10, name) == 0)
+    	return optional &ero;&ero; odr_ok(o);
+    if (o->direction == ODR_DECODE)
+    	*p = odr_malloc(o, sizeof(**p));
+    if (odr_sequence_begin(o, p, sizeof(**p), 0) == 0)
+    {
+    	*p = 0; /* this is almost certainly a protocol error */
+    	return 0;
+    }
+    return
+    	odr_integer(o, &ero;(*p)->intval, 0, "intval") &ero;&ero;
+	odr_bool(o, &ero;(*p)->boolval, 1, "boolval") &ero;&ero;
+	odr_sequence_end(o) &ero;&ero;
+	odr_constructed_end(o);
+}
+</verb></tscreen>
+
+Notice that the interface here gets kind of nasty. The reason is
+simple: Explicitly tagged, constructed types are fairly rare in
+the protocols that we care about, so the
+aesthetic annoyance (not to mention the dangers of a cluttered
+interface) is less than the time that would be required to develop a
+better interface. Nevertheless, it is far from satisfying, and it's a
+point that will be worked on in the future. One option for you would
+be to simply apply the <tt/odr_explicit()/ macro to the first function,
+and not
+have to worry about <tt/odr_constructed_*/ yourself. Incidentally, as you
+might have guessed, the <tt/odr_sequence_/ functions are themselves
+implemented using the <tt/odr_constructed_/ functions.
+
+<sect2>SEQUENCE OF
+
+<p>
+To handle sequences (arrays) of a apecific type, the function
+
+<tscreen><verb>
+int odr_sequence_of(ODR o, int (*fun)(ODR o, void *p, int optional),
+                        void *p, int *num, const char *name);
+</verb></tscreen>
+
+The <tt/fun/ parameter is a pointer to the decoder/encoder
+function of the type. <tt/p/ is a pointer to an array of pointers to your
+type. <tt/num/ is the number of elements in the array.
+
+Assume a type
+
+<tscreen><verb>
+MyArray ::= SEQUENCE OF INTEGER
+</verb></tscreen>
+
+The C representation might be
+
+<tscreen><verb>
+typedef struct MyArray
+{
+    int num_elements;
+    int **elements;
+} MyArray;
+</verb></tscreen>
+
+And the function might look like
+
+<tscreen><verb>
+int myArray(ODR o, MyArray **p, int optional, const char *name)
+{
+    if (o->direction == ODR_DECODE)
+    	*p = odr_malloc(o, sizeof(**p));
+    if (odr_sequence_of(o, odr_integer, &ero;(*p)->elements,
+	&ero;(*p)->num_elements, name))
+	return 1;
+    *p = 0;
+    return optional &ero;&ero; odr_ok(o);
+}
+</verb></tscreen>
+
+<sect2>CHOICE Types
+
+<p>
+The choice type is used fairly often in some ASN.1 definitions, so
+some work has gone into streamlining its interface.
+
+CHOICE types are handled by the function:
+
+<tscreen><verb>
+int odr_choice(ODR o, Odr_arm arm&lsqb;&rsqb;, void *p, void *whichp,
+               const char *name);
+</verb></tscreen>
+
+The <tt/arm/ array is used to describe each of the possible types that the
+CHOICE type may assume. Internally in your application, the CHOICE
+type is represented as a discriminated union. That is, a C union
+accompanied by an integer (or enum) identifying the active 'arm' of
+the union. <tt/whichp/ is a pointer to the union discriminator. When
+encoding, it is examined to determine the current type. When decoding,
+it is set to reference the type that was found in the input stream.
+
+The Odr_arm type is defined thus:
+
+<tscreen><verb>
+typedef struct odr_arm
+{
+    int tagmode;
+    int class;
+    int tag;
+    int which;
+    Odr_fun fun;
+    char *name;
+} Odr_arm;
+</verb></tscreen>
+
+The interpretation of the fields are:
+
+<descrip>
+<tag/tagmode/Either <tt/ODR_IMPLICIT/, <tt/ODR_EXPLICIT/, or <tt/ODR_NONE/
+(-1) to mark
+no tagging.
+<tag/class, tag/The class and tag of the type (-1 if no tagging is
+used).
+<tag/which/The value of the discriminator that corresponds to
+this CHOICE element. Typically, it will be a &num;defined constant, or
+an enum member.
+<tag/fun/A pointer to a function that implements the type of
+the CHOICE member. It may be either a standard <bf/ODR/ type or a type
+defined by yourself.
+<tag/name/Name of tag.
+</descrip>
+
+A handy way to prepare the array for use by the <tt/odr_choice()/ function
+is to
+define it as a static, initialized array in the beginning of your
+decoding/encoding function. Assume the type definition:
+
+<tscreen><verb>
+MyChoice ::= CHOICE {
+    untagged INTEGER,
+    tagged   &lsqb;99&rsqb; IMPLICIT INTEGER,
+    other    BOOLEAN
+}
+</verb></tscreen>
+
+Your C type might look like
+
+<tscreen><verb>
+typedef struct MyChoice
+{
+    enum
+    {
+    	MyChoice_untagged,
+	MyChoice_tagged,
+	MyChoice_other
+    } which;
+    union
+    {
+    	int *untagged;
+	int *tagged;
+	bool_t *other;
+    } u;
+};
+</verb></tscreen>
+
+And your function could look like this:
+
+<tscreen><verb>
+int myChoice(ODR o, MyChoice **p, int optional, const char *name)
+{
+    static Odr_arm arm&lsqb;&rsqb; =
+    {
+    	{-1, -1, -1, MyChoice_untagged, odr_integer, "untagged"},
+    	{ODR_IMPLICIT, ODR_CONTEXT, 99, MyChoice_tagged, odr_integer, 
+                                                            "tagged"},
+	{-1, -1, -1, MyChoice_other, odr_boolean, "other"},
+	{-1, -1, -1, -1, 0}
+    };
+
+    if (o->direction == ODR_DECODE)
+    	*p = odr_malloc(o, sizeof(**p);
+    else if (!*p)
+    	return optional &ero;&ero; odr_ok(o);
+
+    if (odr_choice(o, arm, &ero;(*p)->u, &ero;(*p)->which), name)
+    	return 1;
+    *p = 0;
+    return optional &ero;&ero; odr_ok(o);
+}
+</verb></tscreen>
+
+In some cases (say, a non-optional choice which is a member of a sequence),
+you can &dquot;embed&dquot; the union and its discriminator in the structure
+belonging to the enclosing type, and you won't need to fiddle with
+memory allocation to create a separate structure to wrap the
+discriminator and union.
+
+The corresponding function is somewhat nicer in the Sun XDR interface.
+Most of the complexity of this interface comes from the possibility of
+declaring sequence elements (including CHOICEs) optional.
+
+The ASN.1 specifictions naturally requires that each member of a
+CHOICE have a distinct tag, so they can be told apart on decoding.
+Sometimes it can be useful to define a CHOICE that has multiple types
+that share the same tag. You'll need some other mechanism, perhaps
+keyed to the context of the CHOICE type. In effect, we would like to
+introduce a level of context-sensitiveness to our ASN.1 specification.
+When encoding an internal representation, we have no problem, as long
+as each CHOICE member has a distinct discriminator value. For
+decoding, we need a way to tell the choice function to look for a
+specific arm of the table. The function
+
+<tscreen><verb>
+void odr_choice_bias(ODR o, int what);
+</verb></tscreen>
+
+provides this functionality. When called, it leaves a notice for the
+next call to <tt/odr_choice()/ to be called on the decoding
+stream <tt/o/ that only the <tt/arm/ entry with a <tt/which/ field
+equal to <tt/what/ should be tried.
+
+The most important application (perhaps the only one, really) is in
+the definition of application-specific EXTERNAL encoders/decoders
+which will automatically decode an ANY member given the direct or
+indirect reference.
+
+<sect1>Debugging
+
+<p>
+The protocol modules are suffering somewhat from a lack of diagnostic
+tools at the moment. Specifically ways to pretty-print PDUs that
+aren't recognized by the system. We'll include something to this end
+in a not-too-distant release. In the meantime, what we do when we get
+packages we don't understand is to compile the ODR module with
+<tt/ODR_DEBUG/ defined. This causes the module to dump tracing
+information as it processes data units. With this output and the
+protocol specification (Z39.50), it is generally fairly easy to see
+what goes wrong.
+
+<sect>The COMSTACK Module<label id="comstack">
+
+<sect1>Introduction
+
+<p>
+The <bf/COMSTACK/
+subsystem provides a transparent interface to different types of transport
+stacks for the exchange of BER-encoded data. At present, the
+RFC1729 method (BER over TCP/IP), and Peter Furniss' XTImOSI
+stack are supported, but others may be added in time. The philosophy of the
+module is to provide a simple interface by hiding unused options and
+facilities of the underlying libraries. This is always done at the risk
+of losing generality, and it may prove that the interface will need
+extension later on.
+
+The interface is implemented in such a fashion that only the
+sub-layers constructed to the transport methods that you wish to 
+use in your application are linked in.
+
+You will note that even though simplicity was a goal in the design,
+the interface is still orders of magnitudes more complex than the
+transport systems found in many other packages. One reason is that
+the interface needs to support the somewhat different requirements of
+the different lower-layer communications stacks; another important reason is
+that the interface seeks to provide a more or less industrial-strength
+approach to asynchronous event-handling. When no function is allowed
+to block, things get more complex - particularly on the server
+side. We urge you to have a look at the demonstration client and server
+provided with the package. They are meant to be easily readable and
+instructive, while still being at least moderately useful.
+
+<sect1>Common Functions
+
+<sect2>Managing Endpoints
+
+<p>
+<tscreen><verb>
+COMSTACK cs_create(CS_TYPE type, int blocking, int protocol);
+</verb></tscreen>
+
+Creates an instance of the protocol stack - a communications endpoint.
+The
+<tt/type/
+parameter determines the mode of communication. At present, the
+values
+<tt/tcpip_type/
+and
+<tt/mosi_type/
+are recognized. The function returns a null-pointer if a system error
+occurs. The <tt/blocking/ parameter should be one if you wish the
+association to operate in blocking mode, zero otherwise. The
+<tt/protocol/ field should be one of <tt/PROTO_SR/ or <tt/PROTO_Z3950/.
+
+<tscreen><verb>
+int cs_close(COMSTACK handle);
+</verb></tscreen>
+
+Closes the connection (as elegantly as the lower layers will permit),
+and releases the resouces pointed to by the
+<tt/handle/
+parameter. The
+<tt/handle/
+should not be referenced again after this call.
+
+<it>
+NOTE:
+We really need a soft disconnect, don't we?
+</it>
+
+<sect2>Data Exchange
+
+<p>
+<tscreen><verb>
+int cs_put(COMSTACK handle, char *buf, int len);
+</verb></tscreen>
+
+Sends
+<tt/buf/
+down the wire. In blocking mode, this function will return only when a
+full buffer has been written, or an error has occurred. In nonblocking
+mode, it's possible that the function will be unable to send the full
+buffer at once, which will be indicated by a return value of 1. The
+function will keep track of the number of octets already written; you
+should call it repeatedly with the same values of <tt/buf/ and
+<tt/len/, until the buffer has been transmitted. When a full buffer
+has been sent, the function will return 0 for success. -1 indicates
+an error condition (see below).
+
+<tscreen><verb>
+int cs_get(COMSTACK handle, char **buf, int *size);
+</verb></tscreen>
+
+Receives a PDU from the peer. Returns the number of bytes
+read. In nonblocking mode, it is possible that not all of the packet can be
+read at once. In this case, the function returns 1. To simplify the
+interface, the function is
+responsible for managing the size of the buffer. It will be reallocated
+if necessary to contain large packages, and will sometimes be moved
+around internally by the subsystem when partial packages are read. Before
+calling
+<tt/cs_get/
+for the fist time, the buffer can be initialized to the null pointer,
+and the length should also be set to 0 - cs_get will perform a
+<tt/malloc/(2)
+on the buffer for you. When a full buffer has been read, the size of
+the package is returned (which will always be greater than 1). -1
+indicates an error condition.
+
+See also the
+<tt/cs_more()/
+function below.
+
+<tscreen><verb>
+int cs_more(COMSTACK handle);
+</verb></tscreen>
+
+The <tt/cs_more()/ function should be used in conjunction with
+<tt/cs_get/
+and
+<tt/select/(2).
+The <tt/cs_get()/ function will sometimes (notably in the TCP/IP mode) read
+more than a single protocol package off the network. When this
+happens, the extra package is stored by the subsystem. After calling
+<tt/cs_get()/, and before waiting for more input,
+You should always call
+<tt/cs_more()/
+to check if there's a full protocol package already read. If
+<tt/cs_more()/
+returns 1,
+<tt/cs_get()/
+can be used to immediately fetch the new package. For the 
+mOSI
+subsystem, the function should always return 0, but if you want your
+stuff to be protocol independent, you should use it.
+
+<it>
+NOTE: The <tt/cs_more()/
+function is required because the 
+RFC1729-method
+does not provide a way of separating individual PDUs, short of
+partially decoding the BER. Some other implementations will carefully
+nibble at the packet by calling
+<tt/read/(2)
+several times. This was felt to be too inefficient (or at least
+clumsy) - hence the call for this extra function.
+</it>
+
+<tscreen><verb>
+int cs_look(COMSTACK handle);
+</verb></tscreen>
+
+This function is useful when you're operating in nonblocking
+mode. Call it when
+<tt/select/(2)
+tells you there's something happening on the line. It returns one of
+the following values:
+
+<descrip>
+<tag/CS_NONE/No event is pending. The data found on the line was
+not a complete package.
+<tag/CS_CONNECT/A response to your connect request has been received. Call
+<tt/cs_rcvconnect/
+to process the event and to finalize the connection establishment.
+<tag/CS_DISCON/The other side has closed the connection (or maybe
+sent a disconnect
+request - but do we care? Maybe later). Call
+<tt/cs_close/ To close your end of the association as well.
+<tag/CS_LISTEN/A connect request has been received. Call
+<tt/cs_listen/
+to process the event.
+<tag/CS_DATA/There's data to be found on the line. Call
+<tt/cs_get/
+to get it.
+</descrip>
+
+<it>
+NOTE:
+You should be aware that even if
+<tt/cs_look()/
+tells you that there's an event event pending, the corresponding
+function may still return and tell you there was nothing to be found.
+This means that only part of a package was available for reading. The
+same event will show up again, when more data has arrived.
+</it>
+
+<tscreen><verb>
+int cs_fileno(COMSTACK h);
+</verb></tscreen>
+
+Returns the file descriptor of the association. Use this when
+file-level operations on the endpoint are required (<tt/select/(2)
+operations, specifically).
+
+<sect1>Client Side
+
+<p>
+<tscreen><verb>
+int cs_connect(COMSTACK handle, void *address);
+</verb></tscreen>
+
+Initiate a connection with the target at <tt/address/ (more on
+addresses below). The function will return 0 on success, and 1 if
+the operation does not complete immediately (this will only
+happen on a nonblocking endpoint). In this case, use
+<tt/cs_rcvconnect/ to complete the operation, when <tt/select/(2)
+reports input pending on the association.
+
+<tscreen><verb>
+int cs_rcvconnect(COMSTACK handle);
+</verb></tscreen>
+
+Complete a connect operation initiated by <tt/cs_connect()/. It will
+return 0 on success; 1 if the operation has not yet completed (in this
+case, call the function again later); -1 if an error has occured.
+
+<sect1>Server Side
+
+<p>
+To establish a server under the <tt/inetd/ server, you can use
+
+<tscreen><verb>
+COMSTACK cs_createbysocket(int socket, CS_TYPE type, int blocking,
+                              int protocol);
+</verb></tscreen>
+
+The <it/socket/ parameter is an established socket (when your
+application is invoked from <tt/inetd/, the socket will typically be
+0. The following parameters are identical to the ones for
+<tt/cs_create/.
+
+<tscreen><verb>
+int cs_bind(COMSTACK handle, void *address, int mode)
+</verb></tscreen>
+
+Binds a local address to the endpoint. Read about addresses below. The
+<tt/mode/ parameter should be either <tt/CS_CLIENT/ or <tt/CS_SERVER/.
+
+<tscreen><verb>
+int cs_listen(COMSTACK handle, char *addr, int *addrlen);
+</verb></tscreen>
+
+Call this to process incoming events on an endpoint that has been
+bound in listening mode. It will return 0 to indicate that the connect
+request has been received, 1 to signal a partial reception, and -1 to
+indicate an error condition.
+
+<tscreen><verb>
+COMSTACK cs_accept(COMSTACK handle);
+</verb></tscreen>
+
+This finalises the server-side association establishment, after
+cs_listen has completed successfully. It returns a new connection
+endpoint, which represents the new association. The application will
+typically wish to fork off a process to handle the association at this
+point, and continue listen for new connections on the old <tt/handle/.
+
+You can use the call
+
+<tscreen><verb>
+char *cs_addrstr(COMSTACK);
+</verb></tscreen>
+
+on an established connection to retrieve the hostname of the remote host.
+
+<it>NOTE: You may need to use this function with some care if your
+name server service is slow or unreliable</it>
+
+<sect1>Addresses
+
+<p>
+The low-level format of the addresses are different depending on the
+mode of communication you have chosen. A function is provided by each
+of the lower layers to map a user-friendly string-form address to the
+binary form required by the lower layers.
+
+<tscreen><verb>
+struct sockaddr_in *tcpip_strtoaddr(char *str);
+
+struct netbuf *mosi_strtoaddr(char *str);
+</verb></tscreen>
+
+The format for TCP/IP addresses is straightforward:
+
+<tscreen><verb>
+<host> &lsqb; ':' <portnum> &rsqb;
+</verb></tscreen>
+
+The <tt/hostname/ can be either a domain name or an IP address. The
+port number, if omitted, defaults to 210.
+
+For OSI, the format is
+
+<tscreen><verb>
+&lsqb; <t-selector> '/' &rsqb; <host> &lsqb; ':' <port> &rsqb;
+</verb></tscreen>
+
+The transport selector is given as an even number of hex digits.
+
+You'll note that the address format for the OSI mode are just a subset
+of full presentation addresses. We use presentation addresses because
+xtimosi doesn't, in itself, allow access to the X.500 Directory
+service. We use a limited form, because we haven't yet come across an
+implementation that used more of the elements of a full p-address. It
+is a fairly simple matter to add the rest of the elements to the
+address format as needed, however: Xtimosi <it/does/ support the full
+P-address structure.
+
+In both transport modes, the special hostname &dquot;@&dquot; is mapped
+to any local address (the manifest constant INADDR_ANY). It is used
+to establish local listening endpoints in the server role.
+
+When a connection has been established, you can use
+
+<tscreen><verb>
+char cs_addrstr(COMSTACK h);
+</verb></tscreen>
+
+to retrieve the host name of the peer system. The function returns a pointer
+to a static area, which is overwritten on the next call to the function.
+
+<it>
+NOTE: We have left the issue of X.500 name-to-address mapping open, for the
+moment. It would be a simple matter to provide a table-based mapping,
+if desired. Alternately, we could use the X.500 client-function that
+is provided with the ISODE (although this would defeat some of the
+purpose of using ThinOSI in the first place. We have been told that it
+should be within the realm of the possible to implement a lightweight
+implementation of the necessary X.500 client capabilities on top of
+ThinOSI. This would be the ideal solution, we feel. On the other hand, it
+still remains to be seen just what role the Directory will play in a world
+populated by ThinOSI and other pragmatic solutions.
+</it>
+
+<sect1>Diagnostics
+
+<p>
+All functions return -1 if an error occurs. Typically, the functions
+will return 0 on success, but the data exchange functions
+(<tt/cs_get/, <tt/cs_put/, <tt/cs_more/)
+follow special rules. Consult their descriptions.
+
+When a function (including the data exchange functions) reports an
+error condition,
+use the function
+<tt/cs_errno()/
+to determine the cause of the
+problem. The function
+
+<tscreen><verb>
+void cs_perror(COMSTACK handle char *message);
+</verb></tscreen>
+
+works like
+<tt/perror/(2)
+and prints the
+<tt/message/
+argument, along with a system message, to
+<tt/stderr/.
+Use the character array
+
+<tscreen><verb>
+extern const char *cs_errlist&lsqb;&rsqb;;
+</verb></tscreen>
+
+to get hold of the message, if you want to process it differently.
+The function
+
+<tscreen><verb>
+const char *cs_stackerr(COMSTACK handle);
+</verb></tscreen>
+
+Returns an error message from the lower layer, if one has been
+provided.
+
+<sect1>Enabling OSI Communication
+
+<sect2>Installing Xtimosi
+<p>
+Although you will have to download Peter Furniss' XTI/mOSI
+implementation for yourself, we've tried to make the integration as
+simple as possible.
+
+The latest version of xtimosi will generally be under
+
+<tscreen><verb>
+ftp://pluto.ulcc.ac.uk/ulcc/thinosi/xtimosi/
+</verb></tscreen>
+
+When you have downloaded and unpacked the archive, it will (we assume)
+have created a directory called <tt/xtimosi/. We suggest that you place
+this directory <it/in the same directory/ where you unpacked the
+<bf/YAZ/
+distribution. This way, you shouldn't have to fiddle with the
+makefiles of <tt/YAZ/ beyond uncommenting a few lines.
+
+Go to <tt>xtimosi/src</tt>, and type &dquot;<tt/make libmosi.a/&dquot;.
+This should generally
+create the library, ready to use.
+
+<bf/CAVEAT/
+
+<it>
+The currently available release of xtimosi has some inherent
+problems that make it disfunction on certain platforms - eg. the
+Digital OSF/1 workstations. It is supposedly primarily a
+compiler problem, and we hope to see a release that is generally
+portable. While we can't guarantee that it can be brought to work
+on your platform, we'll be happy to talk to you about problems
+that you might see, and relay information to the author of the
+software. There are some signs that the <bf/gcc/ compiler is more
+likely to produce a fully functional library, but this hasn't
+been verified (we think that the problem is limited to the use
+of hexadecimal escape-codes used in strings, which are silently
+ignored by some compilers).
+</it>
+
+<it>
+A problem has been encountered in the communication with
+ISODE-based applications. If the ISODE presentation-user calls
+<tt/PReadRequest()/ with a timeout value different from <tt/OK/ or <tt/NOTOK/,
+he will get an immediate TIMEOUT abort when receiving large (&gt;2041
+bytes, which is the SPDU-size that the ISODE likes to work with) packages
+from an xtimosi-based implementation (probably most
+other implementations as well, in fact). It seems to be a flaw in the
+ISODE API, and the workaround (for ISODE users) is to either not
+use an explicit timeout (switching to either blocking or
+nonblocking mode), or to check that the timer really has expired
+before closing the connection.
+</it>
+
+The next step in the installation is to modify the makefile in the toplevel
+<bf/YAZ/
+directory. The place to change is in the top of the file, and is
+clearly marked with a comment.
+
+Now run <tt/make/ in the <bf/YAZ/ toplevel directory (do a
+&dquot;<tt/make clean/&dquot; first, if the
+system has been previously made without OSI support). Use the <bf/YAZ/
+<bf/ztest/
+and <bf/client/ demo programs to verify that OSI communication works OK. Then,
+you can go ahead and try to talk to other implementations.
+
+<it>
+NOTE: Our interoperability experience is limited to version
+7 of the Nordic SR-Nett package, which has had several
+protocol errors fixed from the earlier releases. If you have
+problems or successes in interoperating with other
+implementations, we'd be glad to hear about it, or to help
+you make things work, as our resources allow.
+</it>
+
+If you write your own applications based on <bf/YAZ/, and you wish to
+include OSI support, the procedure is equally simple. You should
+include the <tt/xmosi.h/ header file in addition to <tt/comstack.h/.
+<tt/xmosi.h/
+will define the manifest constant <tt/mosi_type/, which you should pass
+to the <tt/cs_create()/ function. In
+addition, you should use the function <tt/mosi_strtoaddr()/ rather than
+<tt/tcpip_strtoaddr()/ when you need to prepare an address.
+
+When you link your application, you should include (after the
+<tt/libyaz.a/
+library) the <tt/libmosi.a/ library, and the <tt/librfc.a/ library
+provided with
+<bf/YAZ/ (for OSI transport).
+
+As always, it can be very useful, if not essential, to have a look at the
+example applications
+to see how things are done.
+
+<sect2>OSI Transport
+
+<p>
+Xtimosi requires an implementation of the OSI transport service under
+the X/OPEN XTI API. We provide an implementation of the RFC1006
+encapsulation of OSI/TP0 in TCP/IP (through the Berkeley Sockets API),
+as an independent part of <bf/YAZ/ (it's found under the <tt/rfc1006/
+directory). If you have access to an OSI transport provider under XTI,
+you should be able to make that work too, although it may require
+tinkering with the <tt/mosi_strtoaddr()/ function.
+
+<sect2>Presentation Context Management
+
+<p>
+To simplify the implementation, we use Peter Furniss' alternative (PRF)
+option format
+for the Control of the presentation negotiation phase. This format
+is enabled by default when you
+compile xtimosi.
+
+The current version of <bf/YAZ/ does <it/not/ support presentation-layer
+negotiation of response record formats. The primary reason is that we
+have had access to no other SR or Z39.50 implementations over OSI that
+used this
+method. Secondarily, we believe that the EXPLAIN facility is a superior
+mechanism for relaying target capabilities in this respect. This is not to
+say that we have no intentions of supporting presentation context
+negotiation - we have just hitherto given it a lower priority than other
+aspects of the protocol.
+
+One thing is certain: The addition of this capability to <bf/YAZ/ should
+have only a minimal impact on existing applications, and on the
+interface to the software in general. Most likely, we will add an extra
+layer of interface to the processing of EXPLAIN records, which will
+convert back and forth between <tt/oident/ records (see section
+<ref id="oid" name="Object Identifiers">) and direct or indirect
+references, given the current association setup. Implementations based
+on any of the higher-level interfaces will most likely not have to be
+changed at all.
+
+<sect1>Summary and Synopsis
+
+<p>
+<tscreen><verb>
+#include <comstack.h>
+
+#include <tcpip.h>      /* this is for TCP/IP support   */
+#include <xmosi.h>      /* and this is for mOSI support */
+
+COMSTACK cs_create(CS_TYPE type, int blocking, int protocol);
+
+COMSTACK cs_createbysocket(int s, CS_TYPE type, int blocking,
+                              int protocol);
+
+int cs_bind(COMSTACK handle, int mode);
+
+int cs_connect(COMSTACK handle, void *address);
+
+int cs_rcvconnect(COMSTACK handle);
+
+int cs_listen(COMSTACK handle);
+
+COMSTACK cs_accept(COMSTACK handle);
+
+int cs_put(COMSTACK handle, char *buf, int len);
+
+int cs_get(COMSTACK handle, char **buf, int *size);
+
+int cs_more(COMSTACK handle);
+
+int cs_close(COMSTACK handle);
+
+int cs_look(COMSTACK handle);
+
+struct sockaddr_in *tcpip_strtoaddr(char *str);
+
+struct netbuf *mosi_strtoaddr(char *str);
+
+extern int cs_errno;
+
+void cs_perror(COMSTACK handle char *message);
+
+const char *cs_stackerr(COMSTACK handle);
+
+extern const char *cs_errlist[];
+</verb></tscreen>
+
+<sect>Making an IR Interface for Your Database with YAZ<label id="server">
+
+<sect1>Introduction
+
+<p>
+<it>
+NOTE: If you aren't into documentation, a good way to learn how the
+backend interface works is to look at the backend.h file. Then,
+look at the small dummy-server in server/ztest.c. Finally, you can
+have a look at the seshigh.c file, which is where most of the
+logic of the frontend server is located. The backend.h file also
+makes a good reference, once you've chewed your way through
+the prose of this file.
+</it>
+
+If you have a database system that you would like to make available by
+means of Z39.50/SR, <bf/YAZ/ basically offers your two options. You
+can use the APIs provided by the <bf/ASN/, <bf/ODR/, and <bf/COMSTACK/
+modules to
+create and decode PDUs, and exchange them with a client. Using this
+low-level interface gives you access to all fields and options of the
+protocol, and you can construct your server as close to your existing
+database as you like. It is also a fairly involved process, requiring
+you to set up an event-handling mechanism, protocol state machine,
+etc. To simplify server implementation, we have implemented a compact
+and simple, but reasonably full-functioned server-frontend that will
+handle most of the protocol mechanics, while leaving you to
+concentrate on your database interface.
+
+<it>
+NOTE: The backend interface was designed in anticipation of a specific
+integration task, while still attempting to achieve some degree of
+generality. We realise fully that there are points where the
+interface can be improved significantly. If you have specific
+functions or parameters that you think could be useful, send us a
+mail (or better, sign on to the mailing list referred to in the
+toplevel README file). We will try to fit good suggestions into future
+releases, to the extent that it can be done without requiring
+too many structural changes in existing applications.
+</it>
+
+<sect1>The Database Frontend
+
+<p>
+We refer to this software as a generic database frontend. Your
+database system is the <it/backend database/, and the interface between
+the two is called the <it/backend API/. The backend API consists of a
+small number of function prototypes and structure definitions. You are
+required to provide the <bf/main()/ routine for the server (which can be
+quite simple), as well as functions to match each of the prototypes.
+The interface functions that you write can use any mechanism you like
+to communicate with your database system: You might link the whole
+thing together with your database application and access it by
+function calls; you might use IPC to talk to a database server
+somewhere; or you might link with third-party software that handles
+the communication for you (like a commercial database client library).
+At any rate, the functions will perform the tasks of:
+
+<itemize>
+<item>Initialization.
+<item>Searching.
+<item>Fetching records.
+<item>Scanning the database index (if you wish to implement SCAN).
+</itemize>
+
+(more functions will be added in time to support as much of
+Z39.50-1995 as possible).
+
+Because the model where pipes or sockets are used to access the backend
+database is a fairly common one, we have added a mechanism that allows this
+communication to take place asynchronously. In this mode, the frontend
+server doesn't have to block while the backend database is processing
+a request, but can wait for additional PDUs from the client.
+
+<sect1>The Backend API
+
+<p>
+The headers files that you need to use the interface are in the
+include/ directory. They are called <tt/statserv.h/ and <tt/backend.h/. They
+will include other files from the <tt/include/ directory, so you'll
+probably want to use the -I option of your compiler to tell it where
+to find the files. When you run <tt/make/ in the toplevel <bf/YAZ/ directory,
+everything you need to create your server is put the lib/libyaz.a
+library. If you want OSI as well, you'll also need to link in the
+<tt/libmosi.a/ library from the xtimosi distribution (see the mosi.txt
+file), a well as the <tt>lib/librfc.a</tt> library (to provide OSI transport
+over RFC1006/TCP).
+
+<sect1>Your main() Routine
+
+<p>
+As mentioned, your <bf/main()/ routine can be quite brief. If you want to
+initialize global parameters, or read global configuration tables,
+this is the place to do it. At the end of the routine, you should call
+the function
+
+<tscreen><verb>int statserv_main(int argc, char **argv);</verb></tscreen>
+
+<bf/Statserv_main/ will establish listening sockets according to the
+parameters given. When connection requests are received, the event
+handler will typically <bf/fork()/ to handle the new request. If you do use
+global variables, you should be aware, then, that these cannot be
+shared between associations, unless you explicitly disallow forking by
+command line parameters (we advise against this for any purposes
+except debugging, as a crash or hang in the server process will affect
+all users currently signed on to the server).
+
+The server provides a mechanism for controlling some of its behavior
+without using command-line options. The function
+
+<tscreen><verb>
+statserv_options_block *statserv_getcontrol(void);
+</verb></tscreen>
+
+Will return a pointer to a <tt/struct statserv_options_block/ describing
+the current default settings of the server. The structure contains
+these elements:
+
+<descrip>
+<tag/int dynamic/A boolean value, which determines whether the server
+will fork on each incoming request (TRUE), or not (FALSE). Default is
+TRUE.
+<tag/int loglevel/Set this by ORing the constants defined in include/log.h.
+<tag/char logfile&lsqb;ODR_MAXNAME+1&rsqb;/File for diagnostic output
+(&dquot;&dquot;: stderr).
+<tag/char apdufile&lsqb;ODR_MAXNAME+1&rsqb;/Name of file for logging incoming and
+outgoing APDUs (&dquot;&dquot;: don't log APDUs, &dquot;-&dquot;: <tt/stderr/).
+<tag/char default_listen&lsqb;1024&rsqb;/Same form as the command-line
+specification of listener address. &dquot;&dquot;: no default listener address.
+Default is to listen at &dquot;tcp:@:9999&dquot;. You can only
+specify one default listener address in this fashion.
+<tag/enum oid_proto default_proto;/Either <tt/PROTO_SR/ or <tt/PROTO_Z3950/.
+Default is <tt/PROTO_Z39_50/.
+<tag/int idle_timeout;/Maximum session idletime, in minutes. Zero indicates
+no (infinite) timeout. Default is 120 minutes.
+<tag/int maxrecordsize;/Maximum permissible record (message) size. Default
+is 1Mb. This amount of memory will only be allocated if a client requests a
+very large amount of records in one operation (or a big record). Set it
+to a lower number
+if you are worried about resource consumption on your host system.
+<tag/char configname&lsqb;ODR_MAXNAME+1&rsqb;/Passed to the backend when a
+new connection is received.
+<tag/char setuid&lsqb;ODR_MAXNAME+1&rsqb;/Set user id to the user specified,
+after binding the listener addresses.
+</descrip>
+
+The pointer returned by <tt/statserv_getcontrol/ points to a static area.
+You are allowed to change the contents of the structure, but the
+changes will not take effect before you call
+
+<tscreen><verb>
+void statserv_setcontrol(statserv_options_block *block);
+</verb></tscreen>
+
+Note that you should generally update this structure <it/before/ calling
+<tt/statserv_main()/.
+
+<sect1>The Backend Functions
+
+<p>
+For each service of the protocol, the backend interface declares one or
+two functions. You are required to provide implementations of the
+functions representing the services that you wish to implement.
+
+<tscreen><verb>bend_initresult *bend_init(bend_initrequest *r);</verb></tscreen>
+
+This function is called once for each new connection request, after
+a new process has been forked, and an initRequest has been received
+from the client. The parameter and result structures are defined as
+
+<tscreen>
+<verb>
+typedef struct bend_initrequest
+{
+    char *configname;
+} bend_initrequest;
+
+typedef struct bend_initresult
+{
+    int errcode;       /* 0==OK */
+    char *errstring;   /* system error string or NULL */
+    void *handle;      /* private handle to the backend module */
+} bend_initresult;
+</verb>
+</tscreen>
+
+The <tt/configname/ of <tt/bend_initrequest/ is currently always set to
+&dquot;default-config&dquot;. We haven't had use for putting anything special in
+the initrequest yet, but something might go there if the need arises
+(account/password info would be obvious).
+
+In general, the server frontend expects that the <tt/bend_*result/
+pointer that you return is valid at least until the next call to a
+<tt/bend_* function/. This applies to all of the functions described
+herein. The parameter structure passed to you in the call belongs to
+the server frontend, and you should not make assumptions about its
+contents after the current function call has completed. In other
+words, if you want to retain any of the contents of a request
+structure, you should copy them.
+
+The <tt/errcode/ should be zero if the initialization of the backend went
+well. Any other value will be interpreted as an error. The
+<tt/errstring/ isn't used in the current version, but one option
+would be to stick it
+in the initResponse as a VisibleString. The <tt/handle/ is the most
+important parameter. It should be set to some value that uniquely
+identifies the current session to the backend implementation. It is
+used by the frontend server in any future calls to a backend function.
+The typical use is to set it to point to a dynamically allocated state
+structure that is private to your backend module.
+
+<tscreen>
+<verb>
+bend_searchresult *bend_search(void *handle, bend_searchrequest *r,
+                               int *fd);
+bend_searchresult *bend_searchresponse(void *handle);
+
+typedef struct bend_searchrequest
+{
+    char *setname;       /* name to give to this set */
+    int replace_set;     /* replace set, if it already exists */
+    int num_bases;       /* number of databases in list */
+    char **basenames;    /* databases to search */
+    Z_Query *query;      /* query structure */
+} bend_searchrequest;
+
+typedef struct bend_searchresult
+{
+    int hits;            /* number of hits */
+    int errcode;         /* 0==OK */
+    char *errstring;     /* system error string or NULL */
+} bend_searchresult;
+</verb>
+</tscreen>
+
+The first thing to notice about the search request interface (as well
+as all of the following requests), is that it consists of two separate
+functions. The idea is to provide a simple facility for
+asynchronous communication with the backend server. When a
+searchrequest comes in, the server frontend will fill out the
+<tt/bend_searchrequest/ tructure, and call the <tt/bend_search
+function/. The <tt/fd/
+argument will point to an integer variable. If you are able to do
+asynchronous I/O with your database server, you should set *<tt/fd/ to the
+file descriptor you use for the communication, and return a null
+pointer. The server frontend will then <tt/select()/ on the *<tt/fd/,
+and will call
+<tt/bend_searchresult/ when it sees that data is available. If you don't
+support asynchronous I/O, you should return a pointer to the
+<tt/bend_searchresult/ immediately, and leave *<tt/fd/ untouched. This
+construction is common to all of the <tt/bend_/ functions (except
+<tt/bend_init/). Note that you can choose to support this facility in none,
+any, or all of the <tt/bend_/ functions, and you can respond
+differently on each request at run-time. The server frontend will
+adapt accordingly.
+
+The <tt/bend_searchrequest/ is a fairly close approximation of a protocol
+searchRequest PDU. The <tt/setname/ is the resultSetName from the protocol. You
+are required to establish a mapping between the set name and whatever
+your backend database likes to use. Similarly, the <tt/replace_set/ is a
+boolean value corresponding to the resultSetIndicator field in the
+protocol. <tt>Num_bases/basenames</tt> is a length of/array of character
+pointers to the database names provided by the client. The <tt/query/ is the 
+full query structure as defined in the protocol ASN.1 specification.
+It can be either of the possible query types, and it's up to you to
+determine if you can handle the provided query type. Rather than
+reproduce the C interface here, we'll refer you to the structure
+definitions in the file <tt>include/proto.h</tt>. If you want to look at the
+attributeSetId OID of the RPN query, you can either match it against
+your own internal tables, or you can use the <tt/oid_getentbyoid/ function
+provided by <bf/YAZ/.
+
+The result structure contains a number of hits, and an
+<tt>errcode/errstring</tt> pair. If an error occurs during the search, or if
+you're unhappy with the request, you should set the errcode to a value
+from the BIB-1 diagnostic set. The value will then be returned to the
+user in a nonsurrogate diagnostic record in the response. The
+<tt/errstring/, if provided, will go in the addinfo field. Look at the
+protocol definition for the defined error codes, and the suggested
+uses of the addinfo field.
+
+<tscreen>
+<verb>
+bend_fetchresult *bend_fetch(void *handle, bend_fetchrequest *r,
+                             int *fd);
+bend_fetchresult *bend_fetchresponse(void *handle);
+
+typedef struct bend_fetchrequest
+{
+    char *setname;       /* set name */
+    int number;          /* record number */
+    oid_value format;
+} bend_fetchrequest;
+
+typedef struct bend_fetchresult
+{
+    char *basename;      /* name of database that provided record */
+    int len;             /* length of record */
+    char *record;        /* record */
+    int last_in_set;     /* is it?  */
+    oid_value format;
+    int errcode;         /* 0==success */
+    char *errstring;     /* system error string or NULL */
+} bend_fetchresult;
+</verb>
+</tscreen>
+
+<it>
+NOTE: The <tt/bend_fetchresponse()/ function is not yet supported
+in this version of the software. Your implementation of <tt/bend_fetch()/
+should always return a pointer to a <tt/bend_fetchresult/.
+</it>
+
+The frontend server calls <tt/bend_fetch/ when it needs database records to
+fulfill a searchRequest or a presentRequest. The <tt/setname/ is simply the
+name of the result set that holds the reference to the desired record.
+The <tt/number/ is the offset into the set (with 1 being the first record
+in the set). The <tt/format/ field is the record format requested by the
+client (See section <ref id="oid" name="Object Identifiers">). The value
+<tt/VAL_NONE/ indicates that the client did not request a specific format.
+The <tt/stream/ argument is an <bf/ODR/ stream which should be used for
+allocating space for structured data records. The stream will be reset when
+all records have been assembled, and the response package has been transmitted.
+For unstructured data, the backend is responsible for maintaining a static
+or dynamic buffer for the record between calls.
+
+In the result structure, the <tt/basename/ is the name of the
+database that holds the
+record. <tt/Len/ is the length of the record returned, in bytes, and
+<tt/record/
+is a pointer to the record. <tt/Last_in_set/ should be nonzero only if the
+record returned is the last one in the given result set. <tt/Errcode/ and
+<tt/errstring/, if given, will currently be interpreted as a global error
+pertaining to the set, and will be returned in a
+nonSurrogateDiagnostic.
+
+<it>NOTE: This is silly. Add a flag to say which is which.</it>
+
+If the <tt/len/ field has the value -1, then <tt/record/ is assumed to point
+to a constructed data type. The <tt/format/ field will be used to determine
+which encoder should be used to serialize the data.
+
+<it>
+NOTE: If your backend generates structured records, it should use
+<tt/odr_malloc()/ on the provided stream for allocating data: This allows
+the frontend server to keep track of the record sizes.
+</it>
+
+The <tt/format/ field is mapped to an object identifier in the direct
+reference of the resulting EXTERNAL representation of the record.
+
+<it>NOTE: The current version of <bf/YAZ/ only supports the direct reference
+mode.</it>
+
+<tscreen>
+<verb>
+bend_deleteresult *bend_delete(void *handle, bend_deleterequest *r,
+                               int *fd);
+bend_deleteresult *bend_deleteresponse(void *handle);
+
+typedef struct bend_deleterequest
+{
+    char *setname;
+} bend_deleterequest;
+
+typedef struct bend_deleteresult
+{
+    int errcode;         /* 0==success */
+    char *errstring;     /* system error string or NULL */
+} bend_deleteresult;
+</verb>
+</tscreen>
+
+<it>
+NOTE: The &dquot;delete&dquot; function is not yet supported
+in this version of the software.
+</it>
+
+<it>
+NOTE: The delete set function definition is rather primitive, mostly
+because we
+have had no practical need for it as of yet. If someone wants
+to provide a full delete service, we'd be happy to add the
+extra parameters that are required. Are there clients out there
+that will actually delete sets they no longer need?
+</it>
+
+<tscreen>
+<verb>
+bend_scanresult *bend_scan(void *handle, bend_scanrequest *r,
+    int *fd);
+bend_scanresult *bend_scanresponse(void *handle);
+
+typedef struct bend_scanrequest
+{
+    int num_bases;      /* number of elements in databaselist */
+    char **basenames;   /* databases to search */
+    Z_AttributesPlusTerm *term;
+    int term_position;  /* desired index of term in result list */
+    int num_entries;    /* number of entries requested */
+} bend_scanrequest;
+
+typedef struct bend_scanresult
+{
+    int num_entries;
+    struct scan_entry
+    {
+    	char *term;
+	int occurrences;
+    } *entries;
+    int term_position;
+    enum
+    {
+    	BEND_SCAN_SUCCESS,
+	BEND_SCAN_PARTIAL
+    } status;
+    int errcode;
+    char *errstring;
+} bend_scanresult;
+</verb>
+</tscreen>
+
+<it>
+NOTE: The <tt/bend_scanresponse()/ function is not yet supported
+in this version of the software. Your implementation of <tt/bend_scan()/
+should always return a pointer to a <tt/bend_scanresult/.
+</it>
+
+<sect1>Application Invocation
+
+<p>
+The finished application has the following
+invocation syntax (by way of <tt/statserv_main()/):
+
+<tscreen> <verb>
+appname &lsqb;-szSu -a apdufile -l logfile -v loglevel&rsqb;
+&lsqb;listener ...&rsqb;
+</verb> </tscreen>
+
+The options are
+
+<descrip>
+<tag/-a/APDU file. Specify a file for dumping PDUs (for diagnostic purposes).
+The special name &dquot;-&dquot; sends output to <tt/stderr/.
+
+<tag/-S/Don't fork on connection requests. This is good for debugging, but
+not recommended for real operation: Although the server is
+asynchronous and non-blocking, it can be nice to keep a software
+malfunction (okay then, a crash) from affecting all current users.
+
+<tag/-s/Use the SR protocol.
+
+<tag/-z/Use the Z39.50 protocol (default). These two options complement
+eachother. You can use both multiple times on the same command
+line, between listener-specifications (see below). This way, you
+can set up the server to listen for connections in both protocols
+concurrently, on different local ports.
+
+<tag/-l/The logfile.
+
+<tag/-v/The log level. Use a comma-separated list of members of the set
+{fatal,debug,warn,log,all,none}.
+<tag/-u/Set user ID. Sets the real UID of the server process to that of the
+given user. It's useful if you aren't comfortable with having the
+server run as root, but you need to start it as such to bind a
+privileged port.
+
+<tag/-w/Working directory.
+<tag/-i/Use this when running from the <tt/inetd/ server.
+
+<tag/-t/Idle session timeout, in minutes.
+
+<tag/-k/Maximum record size/message size, in kilobytes.
+
+</descrip>
+
+A listener specification consists of a transport mode followed by a
+colon (:) followed by a listener address. The transport mode is
+either <tt/osi/ or <tt/tcp/.
+
+For TCP, an address has the form
+
+<tscreen><verb>
+hostname | IP-number &lsqb;: portnumber&rsqb;
+</verb></tscreen>
+
+The port number defaults to 210 (standard Z39.50 port).
+
+For osi, the address form is
+
+<tscreen><verb>
+&lsqb;t-selector /&rsqb; hostname | IP-number &lsqb;: portnumber&rsqb;
+</verb></tscreen>
+
+The transport selector is given as a string of hex digits (with an even
+number of digits). The default port number is 102 (RFC1006 port).
+
+Examples
+
+<tscreen>
+<verb>
+tcp:dranet.dra.com
+
+osi:0402/dbserver.osiworld.com:3000
+</verb>
+</tscreen>
+
+In both cases, the special hostname &dquot;@&dquot; is mapped to
+the address INADDR_ANY, which causes the server to listen on any local
+interface. To start the server listening on the registered ports for
+Z39.50 and SR over OSI/RFC1006, and to drop root privileges once the
+ports are bound, execute the server like this (from a root shell):
+
+<tscreen><verb>
+my-server -u daemon tcp:@ -s osi:@
+</verb></tscreen>
+
+You can replace <tt/daemon/ with another user, eg. your own account, or
+a dedicated IR server account. <tt/my-server/ should be the name of your
+server application. You can test the procedure with the <tt/ztest/
+application.
+
+<sect1>Summary and Synopsis
+
+<p>
+<tscreen><verb>
+#include <backend.h>
+
+bend_initresult *bend_init(bend_initrequest *r);
+
+bend_searchresult *bend_search(void *handle, bend_searchrequest *r,
+                                 int *fd);
+
+bend_searchresult *bend_searchresponse(void *handle);
+
+bend_fetchresult *bend_fetch(void *handle, bend_fetchrequest *r,
+                               int *fd);
+
+bend_fetchresult *bend_fetchresponse(void *handle);
+
+bend_scanresult *bend_scan(void *handle, bend_scanrequest *r, int *fd);
+
+bend_scanresult *bend_scanresponse(void *handle);
+
+bend_deleteresult *bend_delete(void *handle, bend_deleterequest *r,
+                                  int *fd);
+
+bend_deleteresult *bend_deleteresponse(void *handle);
+
+void bend_close(void *handle);
+</verb></tscreen>
+
+<sect>Future Directions
+
+<p>
+The software has been
+successfully ported to the Mac as well as Windows NT/95 - we'd like to
+test those ports better and make sure they work as they should.
+
+We have a new and better version of the frontend server on the drawing
+board. Resources and external commitments will govern when we'll be
+able to do something real with it. Fetures should include greater
+flexibility, greter support for access/resource control, and easy
+support for Explain (possibly with Zebra as an extra database engine).
+
+We now support all PDUs of Z39.50-1995. If there is one of the
+supporting structures that you need but can't find in the prt*.h
+files, send us a note; it may be on its way.
+
+The 'retrieval' module needs to be finalized and documented. We think
+it can form a useful resource for people dealing with complex record
+structures, but for now, you'll mostly have to chew through the code
+yourself to make use of it. Not acceptable.
+
+Other than that, YAZ generally moves in the directions which appear to
+make the most people happy (including ourselves, as prime users of the
+software). If there's something you'd like to see in here, then drop
+us a note and let's see what we can come up with.
+
+<sect>License
+
+<sect1>Index Data Copyright
+
+<p>
+Copyright &copy; 1995-2000 Index Data.
+
+Permission to use, copy, modify, distribute, and sell this software and
+its documentation, in whole or in part, for any purpose, is hereby granted,
+provided that:
+
+1. This copyright and permission notice appear in all copies of the
+software and its documentation. Notices of copyright or attribution
+which appear at the beginning of any file must remain unchanged.
+
+2. The names of Index Data or the individual authors may not be used to
+endorse or promote products derived from this software without specific
+prior written permission.
+
+THIS SOFTWARE IS PROVIDED "AS IS" AND WITHOUT WARRANTY OF ANY KIND,
+EXPRESS, IMPLIED, OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY
+WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
+IN NO EVENT SHALL INDEX DATA BE LIABLE FOR ANY SPECIAL, INCIDENTAL,
+INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND, OR ANY DAMAGES
+WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER OR
+NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF
+LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
+OF THIS SOFTWARE.
+
+<sect1>Additional Copyright Statements
+
+<p>
+The optional CCL query language interpreter is covered by the following
+license:
+
+Copyright &copy; 1995, the EUROPAGATE consortium (see below).
+
+The EUROPAGATE consortium members are:
+
+   University College Dublin
+   Danmarks Teknologiske Videnscenter
+   An Chomhairle Leabharlanna
+   Consejo Superior de Investigaciones Cientificas
+
+Permission to use, copy, modify, distribute, and sell this software and
+its documentation, in whole or in part, for any purpose, is hereby granted,
+provided that:
+
+1. This copyright and permission notice appear in all copies of the
+software and its documentation. Notices of copyright or attribution
+which appear at the beginning of any file must remain unchanged.
+
+2. The names of EUROPAGATE or the project partners may not be used to
+endorse or promote products derived from this software without specific
+prior written permission.
+
+3. Users of this software (implementors and gateway operators) agree to
+inform the EUROPAGATE consortium of their use of the software. This
+information will be used to evaluate the EUROPAGATE project and the
+software, and to plan further developments. The consortium may use
+the information in later publications.
+
+4. Users of this software agree to make their best efforts, when
+documenting their use of the software, to acknowledge the EUROPAGATE
+consortium, and the role played by the software in their work.
+
+THIS SOFTWARE IS PROVIDED "AS IS" AND WITHOUT WARRANTY OF ANY KIND,
+EXPRESS, IMPLIED, OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY
+WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
+IN NO EVENT SHALL THE EUROPAGATE CONSORTIUM OR ITS MEMBERS BE LIABLE
+FOR ANY SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF
+ANY KIND, OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA
+OR PROFITS, WHETHER OR NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND
+ON ANY THEORY OF LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE
+USE OR PERFORMANCE OF THIS SOFTWARE.
+
+<sect>About Index Data
+
+<p>
+Index Data is a consulting and software-development enterprise that
+specialises in library and information management systems. Our
+interests and expertise span a broad range of related fields, and one
+of our primary, long-term objectives is the development of a powerful
+information management
+system with open network interfaces and hypermedia capabilities.
+
+We make this software available free of charge, on a fairly unrestrictive
+license; as a service to the networking community, and to further the
+development of quality software for open network communication.
+
+We'll be happy to answer questions about the software, and about ourselves
+in general.
+
+<tscreen><verb>
+Index Data
+Ryesgade 3
+DK-2200 Copenhagen N
+</verb></tscreen>
+
+<p>
+<tscreen><verb>
+Phone: +45 3536 3672
+Fax  : +45 3536 0449
+Email: info@indexdata.dk
+</verb></tscreen>
+
+The <it>Hacker's Jargon File</it> has the following to say about the
+use of the
+prefix &dquot;YA&dquot; in the name of a software product.
+
+<it>
+Yet Another. adj. 1. Of your own work: A
+humorous allusion often used in titles to acknowledge that the
+topic is not original, though the content is.  As in &dquot;Yet Another
+AI Group&dquot; or &dquot;Yet Another Simulated Annealing Algorithm&dquot;.
+2. Of
+others' work: Describes something of which there are already far
+too many. 
+</it>
+
+</article>
Index: /main/tags/2.25/gsdl/packages/yaz/doc/yaz.txt
===================================================================
--- /main/tags/2.25/gsdl/packages/yaz/doc/yaz.txt	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/yaz/doc/yaz.txt	(revision 21064)
@@ -0,0 +1,4158 @@
+  YAZ User's Guide and Reference
+  Index Data, info@indexdata.dk
+  $Revision$
+
+  This document is the programmer's guide and reference to the YAZ pack-
+  age. YAZ is a compact toolkit that provides access to the Z39.50/SR
+  protocol, as well as a set of higher-level tools for implementing the
+  server and client roles, respectively.  The documentation can be used
+  on its own, or as a reference when looking at the example applications
+  provided with the package.
+  ______________________________________________________________________
+
+  Table of Contents
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+  1. Introduction
+
+  2. Compilation and Installation
+
+     2.1 UNIX
+     2.2 WIN32
+
+  3. The ASN Module
+
+     3.1 Introduction
+     3.2 Preparing PDUs
+     3.3 Object Identifiers
+     3.4 EXTERNAL Data
+     3.5 PDU Contents Table
+
+  4. Supporting Tools
+
+     4.1 Query Syntax Parsers
+        4.1.1 Prefix Query Format
+        4.1.2 Common Command Language
+           4.1.2.1 CCL Syntax
+           4.1.2.2 CCL Qualifiers
+           4.1.2.3 CCL API
+     4.2 Object Identifiers
+     4.3 Nibble Memory
+
+  5. The ODR Module
+
+     5.1 Introduction
+     5.2 Using ODR
+        5.2.1 ODR Streams
+        5.2.2 Memory Management
+        5.2.3 Encoding and Decoding Data
+        5.2.4 Diagnostics
+        5.2.5 Summary and Synopsis
+     5.3 Programming with ODR
+        5.3.1 The Primitive ASN.1 Types
+           5.3.1.1 INTEGER
+           5.3.1.2 BOOLEAN
+           5.3.1.3 REAL
+           5.3.1.4 NULL
+           5.3.1.5 OCTET STRING
+           5.3.1.6 BIT STRING
+           5.3.1.7 OBJECT IDENTIFIER
+        5.3.2 Tagging Primitive Types
+        5.3.3 Constructed Types
+        5.3.4 Tagging Constructed Types
+           5.3.4.1 Implicit Tagging
+           5.3.4.2 Explicit Tagging
+        5.3.5 SEQUENCE OF
+        5.3.6 CHOICE Types
+     5.4 Debugging
+
+  6. The COMSTACK Module
+
+     6.1 Introduction
+     6.2 Common Functions
+        6.2.1 Managing Endpoints
+        6.2.2 Data Exchange
+     6.3 Client Side
+     6.4 Server Side
+     6.5 Addresses
+     6.6 Diagnostics
+     6.7 Enabling OSI Communication
+        6.7.1 Installing Xtimosi
+        6.7.2 OSI Transport
+        6.7.3 Presentation Context Management
+     6.8 Summary and Synopsis
+
+  7. Making an IR Interface for Your Database with YAZ
+
+     7.1 Introduction
+     7.2 The Database Frontend
+     7.3 The Backend API
+     7.4 Your main() Routine
+     7.5 The Backend Functions
+     7.6 Application Invocation
+     7.7 Summary and Synopsis
+
+  8. Future Directions
+
+  9. License
+
+     9.1 Index Data Copyright
+     9.2 Additional Copyright Statements
+
+  10. About Index Data
+
+
+
+  ______________________________________________________________________
+
+  1.  Introduction
+
+  The YAZ toolkit offers several different levels of access to the
+  Z39.50 and SR protocols. The level that you need to use depends on
+  your requirements, and the role (server or client) that you want to
+  implement.
+
+  The basic level, which is independent of the role, consists of three
+  primary interfaces:
+
+
+  o  ASN, which provides a C representation of the Z39.50/SR protocol
+     packages (PDUs).
+
+  o  ODR, which encodes and decodes the packages according to the BER
+     specification.
+
+  o  COMSTACK, which exchanges the encoded packages with a peer process
+     over a network.
+
+  The ASN module represents the ASN.1 definition of the SR/Z39.50
+  protocol. It establishes a set of type and structure definitions, with
+  one structure for each of the top-level PDUs, and one structure or
+  type for each of the contained ASN.1 types.  For primitive types, or
+  other types that are defined by the ASN.1 standard itself (such as the
+  EXTERNAL type), the C representation is provided by the ODR (Open Data
+  Representation) subsystem.
+
+  ODR is a basic mechanism for representing an ASN.1 type in the C
+  programming language, and for implementing BER encoders and decoders
+  for values of that type. The types defined in the ASN module generally
+  have the prefix Z_, and a suffix corresponding to the name of the type
+  in the ASN.1 specification of the protocol (generally Z39.50-1995). In
+  the case of base types (those originating in the ASN.1 standard
+  itself), the prefix Odr_ is sometimes seen. Either way, look for the
+  actual definition in either proto.h (for the types from the protocol),
+  odr.h (for the primitive ASN.1 types, or odr_use.h (for the ASN.1
+  useful types). The ASN library also provides functions (which are, in
+  turn, defined using ODR primitives) for encoding and decoding data
+  values. Their general form is
+       int z_xxx(ODR o, Z_xxx **p, int optional, const char *name);
+
+
+
+
+  (note the lower-case "z" in the function name)
+
+  NOTE: If you are using the premade definitions of the ASN module, and
+  you are not adding new protocol of your own, the only parts of ODR
+  that you need to worry about are documented in section ``Using ODR''.
+
+  When you have created a BER-encoded buffer, you can use the COMSTACK
+  subsystem to transmit (or receive) data over the network. The COMSTACK
+  module provides simple functions for establishing a connection
+  (passively or actively, depending on the role of your application),
+  and for exchanging BER-encoded PDUs over that connection. When you
+  create a connection endpoint, you need to specify what transport to
+  use (OSI or TCP/IP), and which protocol you want to use (SR or
+  Z39.50). For the remainer of the connection's lifetime, you don't have
+  to worry about the underlying transport protocol at all - the COMSTACK
+  will ensure that the correct mechanism is used.
+
+  We call the combined interfaces to ODR, ASN, and COMSTACK the service
+  level API. It's the API that most closely models the Z39.50/SR
+  service/protocol definition, and it provides unlimited access to all
+  fields and facilities of the protocol definitions.
+
+  The reason that the YAZ service-level API is a conglomerate of the
+  APIs from three different submodules is twofold. First, we wanted to
+  allow the user a choice of different options for each major task. For
+  instance, if you don't like the protocol API provided by ODR/ASN, you
+  can use SNACC or BERUtils instead, and still have the benefits of the
+  transparent transport approach of the COMSTACK module. Secondly, we
+  realise that you may have to fit the toolkit into an existing event-
+  processing structure, in a way that is incompatible with the COMSTACK
+  interface or some other part of YAZ.
+
+
+  2.  Compilation and Installation
+
+  The latest version of the software will generally be found at
+
+
+
+       http://ftp.indexdata.dk/pub/yaz/
+
+
+
+
+  We have tried our best to keep the software portable, and on many
+  platforms, you should be able to compile everything with little or no
+  changes.  So far, the software has been ported to the following
+  platforms with little or no difficulties.
+
+
+  o  Unix systems
+
+  o  HP/UX
+
+  o  SunOS/Solaris
+
+  o  DEC Unix
+
+  o  Linux
+
+
+  o  IBM AIX
+
+  o  Data General DG/UX (with some CFLAGS tinkering)
+
+  o  SGI/IRIX
+
+  o  DDE Supermax
+
+  o  Non-unix systems
+
+  o  Apple Macintosh (using the Codewarrior programming environment and
+     the GUSI socket libraries)
+
+  o  MS Windows 95/NT (Win32)
+
+  o  IBM AS/400
+
+  If you move the software to other platforms, we'd be grateful if you'd
+  let us know about it. If you run into difficulties, we will try to
+  help if we can, and if you solve the problems, we would be happy to
+  include your fixes in the next release. So far, we have mostly avoided
+  #ifdefs for individual platforms, and we'd like to keep it that way as
+  far as it makes sense.
+
+  We maintain a mailing-list for the purpose of announcing new releases
+  and bug-fixes, as well as general discussion. Subscribe by sending
+  mail to yaz-request@indexdata.dk. General questions and problems can
+  be directed at yaz-help@indexdata.dk, or the address given at the top
+  of this document.
+
+
+  2.1.  UNIX
+
+  Note that if your system doesn't have a native ANSI C compiler, you
+  may have to acquire one separately. We recommend gcc.
+
+  For UNIX we use GNU configure to create Makefiles for YAZ.  Generally
+  it should be sufficient to run configure without options:
+
+
+
+       ./configure
+
+
+
+
+  The configure script attempts to use use the C compiler specified by
+  the CC environment variable. If not set, GNU C will be used if it is
+  available. The CFLAGS environment variable holds options to be passed
+  to the C compiler. If you're using Bourne-compatible shell you may
+  pass something like this to use a particular C compiler with
+  optimization enabled:
+
+
+         CC=/opt/ccs/bin/cc CFLAGS=-O ./configure
+
+
+
+
+  To customize YAZ the configure script also accepts a set of options.
+  The most important are:
+
+
+     --prefix path
+        Specifies installation prefix. This is only needed if you run
+        make install later to perform a "system" installation. The
+        prefix is /usr/local if not specified.
+
+
+     --enable-comp
+        YAZ will be built using the ASN.1 compiler for YAZ (default). If
+        you wish to use the old decoders (in sub directory asn) use
+        --disable-comp instead.
+
+
+     --enable-threads
+        YAZ will be built using POSIX threads. Specifically, _REENTRANT
+        will be defined during compilation.
+
+  When configured, build the software by typing:
+
+
+         make
+
+
+
+
+  Developers that do modifications to YAZ may wish to run make depend as
+  well to generate object-header file dependencies.
+
+  The following files are generated by make
+
+     lib/libyaz.a
+        The YAZ programmers' library.
+
+
+     ztest/yaz-ztest
+        A test Z39.50 server.
+
+
+     client/yaz-client
+        A command mode Z39.50 client.
+
+
+     yaz-config
+        A Bourne-shell script that holds build settings for YAZ.
+
+
+  If you wish to install YAZ in system directories such as
+  /usr/local/bin, /usr/local/lib) you can type:
+
+
+
+         make install
+
+
+
+
+  You probably need to have root access in order to perform this.  You
+  must specify the --prefix option for configure if you going to install
+  in anything but /usr/local/.
+
+
+  2.2.  WIN32
+
+  YAZ is shipped with "makefiles" for the NMAKE tool that comes with
+  Visual C++.
+
+  Start an MS-DOS prompt and switch the sub directory WIN where the file
+  makefile is located. Customize the installation by editing the
+  makefile file (for example by using notepad).
+
+  The following summarises the most important settings in that file:
+
+
+     NEW_Z3950
+        If 1, the auto-generated decoder/encoders for Z39.50 as written
+        by the ASN.1 compiler will be used. If 0, the old decoders for
+        Z39.50 will be used. Note, when 1, the setting TCL should point
+        to the Tcl shell on your system.
+
+     DEBUG
+        If set to 1, the software is compiled with debugging libraries.
+        If set to 0, the software is compiled with release (non-
+        debugging) libraries.
+
+  When satisfied with the settings in the makefile type
+
+
+       nmake
+
+
+
+
+  The following is generated upon successful compilation:
+
+     bin/yaz.dll
+        A multithreaded DLL with everything except the frontend server
+        library.
+
+     lib/yaz.lib
+        An import library for yaz.dll.
+
+     lib/server.lib
+        The frontend server library.
+
+     bin/yaz-ztest.exe
+        A test Z39.50 server.
+
+     bin/yaz-client.exe
+        A command mode Z39.50 client.
+
+
+  3.  The ASN Module
+
+  3.1.  Introduction
+
+  The ASN module provides you with a set of C struct definitions for the
+  various PDUs of the protocol, as well as for the complex types
+  appearing within the PDUs. For the primitive data types, the C
+  representation often takes the form of an ordinary C language type,
+  such as int. For ASN.1 constructs that have no direct representation
+  in C, such as general octet strings and bit strings, the ODR module
+  (see section ``ODR'') provides auxiliary definitions.
+
+
+  3.2.  Preparing PDUs
+
+  A structure representing a complex ASN.1 type doesn't in itself
+  contain the members of that type. Instead, the structure contains
+  pointers to the members of the type. This is necessary, in part, to
+  allow a mechanism for specifying which of the optional structure
+  (SEQUENCE) members are present, and which are not. It follows that you
+  will need to somehow provide space for the individual members of the
+  structure, and set the pointers to refer to the members.
+
+  The conversion routines don't care how you allocate and maintain your
+  C structures - they just follow the pointers that you provide.
+  Depending on the complexity of your application, and your personal
+  taste, there are at least three different approaches that you may take
+  when you allocate the structures.
+
+
+  o  You can use static or automatic local variables in the function
+     that prepares the PDU. This is a simple approach, and it provides
+     the most efficient form of memory management. While it works well
+     for flat PDUs like the InitReqest, it will generally not be
+     sufficient for say, the generation of an arbitrarily complex RPN
+     query structure.
+
+  o  You can individually create the structure and its members using the
+     malloc(2) function. If you want to ensure that the data is freed
+     when it is no longer needed, you will have to define a function
+     that individually releases each member of a structure before
+     freeing the structure itself.
+
+  o  You can use the odr_malloc() function (see section ``Using ODR''
+     for details). When you use odr_malloc(), you can release all of the
+     allocated data in a single operation, independent of any pointers
+     and relations between the data. odr_malloc() is based on a "nibble-
+     memory" scheme, in which large portions of memory are allocated,
+     and then gradually handed out with each call to odr_malloc(). The
+     next time you call odr_reset(), all of the memory allocated since
+     the last call is recycled for future use (actually, it is placed on
+     a free-list).
+
+  o  You can combine all of the methods described here. This will often
+     be the most practical approach. For instance, you might use
+     odr_malloc() to allocate an entire structure and some of its
+     elements, while you leave other elements pointing to global or per-
+     session default variables.
+
+  The ASN module provides an important aid in creating new PDUs. For
+  each of the PDU types (say, Z_InitRequest), a function is provided
+  that allocates and initializes an instance of that PDU type for you.
+  In the case of the InitRequest, the function is simply named
+  zget_InitRequest(), and it sets up reasonable default value for all of
+  the mandatory members. The optional members are generally initialized
+  to null pointers. This last aspect is very important: it ensures that
+  if the PDU definitions are extended after you finish your
+  implementation (to accommodate new versions of the protocol, say), you
+  won't get into trouble with uninitialized pointers in your structures.
+  The functions use odr_malloc() to allocate the PDUs and its members,
+  so you can free everything again with a single call to odr_reset(). We
+  strongly recommend that you use the zget_* functions whenever you are
+  preparing a PDU (in a C++ API, the zget_ functions would probably be
+  promoted to constructors for the individual types).
+
+  The prototype for the individual PDU types generally look like this:
+
+
+
+       Z_<type> *zget_<type>(ODR o);
+
+
+
+
+  eg.:
+
+
+
+       Z_InitRequest *zget_InitRequest(ODR o);
+
+
+  The ODR handle should generally be your encoding stream, but it
+  needn't be.
+
+  As well as the individual PDU functions, a function zget_APDU() is
+  provided, which allocates a toplevel Z-APDU of the type requested:
+
+
+
+       Z_APDU *zget_APDU(ODR o, int which);
+
+
+
+
+  The which parameter is (of course) the discriminator belonging to the
+  Z_APDU CHOICE type. All of the interface described here is provided by
+  the ASN module, and you access it through the proto.h header file.
+
+
+  3.3.  Object Identifiers
+
+  When you refer to object identifiers in your application, you need to
+  be aware that SR and Z39.50 use two different set of OIDs to refer to
+  the same objects. To handle this easily, YAZ provides a utility module
+  to ASN which provides an internal representation of the OIDs used in
+  both protocols. Each oid is described by a structure:
+
+
+
+       typedef struct oident
+       {
+           enum oid_proto proto;
+           enum oid_class class;
+           enum oid_value value;
+           int oidsuffix[OID_SIZE];
+           char *desc;
+       } oident;
+
+
+
+
+  The proto field can be set to either PROTO_SR or PROTO_Z3950. The
+  class might be, say, CLASS_RECSYN, and the value might be VAL_USMARC
+  for the USMARC record format. Functions
+
+
+
+       int *oid_ent_to_oid(struct oident *ent, int *dst);
+       struct oident *oid_getentbyoid(int *o);
+
+
+
+
+  are provided to map between object identifiers and database entries.
+  If you store a member of the oid_proto type in your association state
+  information, it's a simple matter, at runtime, to generate the correct
+  OID when you need it. For decoding, you can simply ignore the proto
+  field, or if you're strict, you can verify that your peer is using the
+  OID family from the correct protocol. The desc field is a short,
+  human-readable name for the PDU, useful mainly for diagnostic output.
+
+  NOTE: The old function oid_getoidbyent still exists but is not thread
+  safe. Use oid_ent_to_oid instead and pass an array of size OID_SIZE.
+
+  NOTE: Plans are underway to merge the two protocols into a single
+  definition, with one set of object identifiers. When this happens, the
+  oid module will no longer be required to support protocol
+  independence, but it should still be useful as a simple OID database.
+
+
+  3.4.  EXTERNAL Data
+
+  In order to achieve extensibility and adaptability to different
+  application domains, the new version of the protocol defines many
+  structures outside of the main ASN.1 specification, referencing them
+  through ASN.1 EXTERNAL constructs. To simplify the construction and
+  access to the externally referenced data, the ASN module defines a
+  specialized version of the EXTERNAL construct, called Z_External.  It
+  is defined thus:
+
+
+
+       typedef struct Z_External
+       {
+           Odr_oid *direct_reference;
+           int *indirect_reference;
+           char *descriptor;
+           enum
+           {
+               /* Generic types */
+               Z_External_single = 0,
+               Z_External_octet,
+               Z_External_arbitrary,
+
+               /* Specific types */
+               Z_External_SUTRS,
+               Z_External_explainRecord,
+               Z_External_resourceReport1,
+               Z_External_resourceReport2
+
+               ...
+
+           } which;
+           union
+           {
+               /* Generic types */
+               Odr_any *single_ASN1_type;
+               Odr_oct *octet_aligned;
+               Odr_bitmask *arbitrary;
+
+               /* Specific types */
+               Z_SUTRS *sutrs;
+               Z_ExplainRecord *explainRecord;
+               Z_ResourceReport1 *resourceReport1;
+               Z_ResourceReport2 *resourceReport2;
+
+               ...
+
+           } u;
+       } Z_External;
+
+
+
+
+  When decoding, the ASN module will attempt to determine which syntax
+  describes the data by looking at the reference fields (currently only
+  the direct-reference). For ASN.1 structured data, you need only
+  consult the which field to determine the type of data.  You can the
+  access  the data directly through the union. When constructing data
+  for encoding, you set the union pointer to point to the data, and set
+  the which field accordingly. Remember also to set the direct (or
+  indirect) reference to the correct OID for the data type. For non-
+  ASN.1 data such as MARC records, use the octet_aligned arm of the
+  union.
+
+  Some servers return ASN.1 structured data values (eg. database
+  records) as BER-encoded records placed in the octet-aligned branch of
+  the EXTERNAL CHOICE. The ASN-module will not automatically decode
+  these records. To help you decode the records in the application, the
+  function
+
+
+
+       Z_ext_typeent *z_ext_gettypebyref(oid_value ref);
+
+
+
+
+  Can be used to retrieve information about the known, external data
+  types. The function return a pointer to a static area, or NULL, if no
+  match for the given direct reference is found. The Z_ext_typeent is
+  defined as:
+
+
+
+       typedef struct Z_ext_typeent
+       {
+           oid_value dref;    /* the direct-reference OID value. */
+           int what;          /* discriminator value for the external CHOICE */
+           Odr_fun fun;       /* decoder function */
+       } Z_ext_typeent;
+
+
+
+
+  The what member contains the Z_External union discriminator value for
+  the given type: For the SUTRS record syntax, the value would be
+  Z_External_sutrs. The fun member contains a pointer to the function
+  which encodes/decodes the given type. Again, for the SUTRS record
+  syntax, the value of fun would be z_SUTRS (a function pointer).
+
+  If you receive an EXTERNAL which contains an octet-string value that
+  you suspect of being an ASN.1-structured data value, you can use
+  z_ext_gettypebyref to look for the provided direct-reference. If the
+  return value is different from NULL, you can use the provided function
+  to decode the BER string (see section ``Using ODR'').
+
+  If you want to send EXTERNALs containing ASN.1-structured values in
+  the occtet-aligned branch of the CHOICE, this is possible too.
+  However, on the encoding phase, it requires a somewhat involved
+  juggling around of the various buffers involved.
+
+  If you need to add new, externally defined data types, you must update
+  the struct above, in the source file prt-ext.h, as well as the
+  encoder/decoder in the file prt-ext.c. When changing the latter,
+  remember to update both the arm arrary and the list type_table, which
+  drives the CHOICE biasing that is necessary to tell the different,
+  structured types apart on decoding.
+
+  NOTE: Eventually, the EXTERNAL processing will most likely
+  automatically insert the correct OIDs or indirect-refs. First,
+  however, we need to determine how application-context management
+  (specifically the presentation-context-list) should fit into the
+  various modules.
+
+
+
+
+
+  3.5.  PDU Contents Table
+
+  We include, for reference, a listing of the fields of each top-level
+  PDU, as well as their default settings.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+  Z_InitRequest
+  -------------
+  Field                        Type                Default value
+
+  referenceId                  Z_ReferenceId       NULL
+  protocolVersion              Odr_bitmask         Empty bitmask
+  options                      Odr_bitmask         Empty bitmask
+  preferredMessageSize         int                 30*1024
+  maximumRecordSize            int                 30*1024
+  idAuthentication             Z_IdAuthentication  NULL
+  implementationId             char*               "YAZ (id=81)"
+  implementationName           char*               "Index Data/YAZ"
+  implementationVersion        char*               YAZ_VERSION
+  userInformationField         Z_UserInformation   NULL
+  otherInfo                    Z_OtherInformation  NULL
+
+  Z_InitResponse
+  --------------
+  Field                        Type                Default value
+
+  referenceId                  Z_ReferenceId       NULL
+  protocolVersion              Odr_bitmask         Empty bitmask
+  options                      Odr_bitmask         Empty bitmask
+  preferredMessageSize         int                 30*1024
+  maximumRecordSize            int                 30*1024
+  result                       bool_t              TRUE
+  implementationId             char*               "YAZ (id=81)"
+  implementationName           char*               "Index Data/YAZ"
+  implementationVersion        char*               YAZ_VERSION
+  userInformationField         Z_UserInformat..    NULL
+  otherInfo                    Z_OtherInformation  NULL
+
+  Z_SearchRequest
+  ---------------
+  Field                        Type                Default value
+
+  referenceId                  Z_ReferenceId       NULL
+  smallSetUpperBound           int                 0
+  largeSetLowerBound           int                 1
+  mediumSetPresentNumber       int                 0
+  replaceIndicator             bool_t              TRUE
+  resultSetName                char*               "default"
+  num_databaseNames            int                 0
+  databaseNames                char**              NULL
+  smallSetElementSetNames      Z_ElementSetNames   NULL
+  mediumSetElementSetNames     Z_ElementSetNames   NULL
+  preferredRecordSyntax        Odr_oid             NULL
+  query                        Z_Query             NULL
+  additionalSearchInfo         Z_OtherInformation  NULL
+  otherInfo                    Z_OtherInformation  NULL
+
+  Z_SearchResponse
+  ----------------
+  Field                        Type                Default value
+
+  referenceId                  Z_ReferenceId       NULL
+  resultCount                  int                 0
+  numberOfRecordsReturned      int                 0
+  nextResultSetPosition        int                 0
+  searchStatus                 bool_t              TRUE
+  resultSetStatus              int                 NULL
+  presentStatus                int                 NULL
+  records                      Z_Records           NULL
+  additionalSearchInfo         Z_OtherInformation  NULL
+  otherInfo                    Z_OtherInformation  NULL
+
+  Z_PresentRequest
+  ----------------
+  Field                        Type                Default value
+
+  referenceId                  Z_ReferenceId       NULL
+  resultSetId                  char*               "default"
+  resultSetStartPoint          int                 1
+  numberOfRecordsRequested     int                 10
+  num_ranges                   int                 0
+  additionalRanges             Z_Range             NULL
+  recordComposition            Z_RecordComposition NULL
+  preferredRecordSyntax        Odr_oid             NULL
+  maxSegmentCount              int                 NULL
+  maxRecordSize                int                 NULL
+  maxSegmentSize               int                 NULL
+  otherInfo                    Z_OtherInformation  NULL
+
+  Z_PresentResponse
+  -----------------
+  Field                        Type                Default value
+
+  referenceId                  Z_ReferenceId       NULL
+  numberOfRecordsReturned      int                 0
+  nextResultSetPosition        int                 0
+  presentStatus                int                 Z_PRES_SUCCESS
+  records                      Z_Records           NULL
+  otherInfo                    Z_OtherInformation  NULL
+
+  Z_DeleteResultSetRequest
+  ------------------------
+  Field                        Type                Default value
+
+  referenceId                  Z_ReferenceId       NULL
+  deleteFunction               int                 Z_DeleteRequest_list
+  num_ids                      int                 0
+  resultSetList                char**              NULL
+  otherInfo                    Z_OtherInformation  NULL
+
+  Z_DeleteResultSetResponse
+  -------------------------
+  Field                        Type                Default value
+
+  referenceId                  Z_ReferenceId       NULL
+  deleteOperationStatus        int                 Z_DeleteStatus_success
+  num_statuses                 int                 0
+  deleteListStatuses           Z_ListStatus**      NULL
+  numberNotDeleted             int                 NULL
+  num_bulkStatuses             int                 0
+  bulkStatuses                 Z_ListStatus        NULL
+  deleteMessage                char*               NULL
+  otherInfo                    Z_OtherInformation  NULL
+
+  Z_ScanRequest
+  -------------
+  Field                        Type                Default value
+
+  referenceId                  Z_ReferenceId       NULL
+  num_databaseNames            int                 0
+  databaseNames                char**              NULL
+  attributeSet                 Odr_oid             NULL
+  termListAndStartPoint        Z_AttributesPlus... NULL
+  stepSize                     int                 NULL
+  numberOfTermsRequested       int                 20
+  preferredPositionInResponse  int                 NULL
+  otherInfo                    Z_OtherInformation  NULL
+
+  Z_ScanResponse
+  --------------
+  Field                        Type                Default value
+
+  referenceId                  Z_ReferenceId       NULL
+  stepSize                     int                 NULL
+  scanStatus                   int                 Z_Scan_success
+  numberOfEntriesReturned      int                 0
+  positionOfTerm               int                 NULL
+  entries                      Z_ListEntris        NULL
+  attributeSet                 Odr_oid             NULL
+  otherInfo                    Z_OtherInformation  NULL
+
+  Z_TriggerResourceControlRequest
+  -------------------------------
+  Field                        Type                Default value
+
+  referenceId                  Z_ReferenceId       NULL
+  requestedAction              int                 Z_TriggerResourceCtrl_resou..
+  prefResourceReportFormat     Odr_oid             NULL
+  resultSetWanted              bool_t              NULL
+  otherInfo                    Z_OtherInformation  NULL
+
+  Z_ResourceControlRequest
+  ------------------------
+  Field                        Type                Default value
+
+  referenceId                  Z_ReferenceId       NULL
+  suspendedFlag                bool_t              NULL
+  resourceReport               Z_External          NULL
+  partialResultsAvailable      int                 NULL
+  responseRequired             bool_t              FALSE
+  triggeredRequestFlag         bool_t              NULL
+  otherInfo                    Z_OtherInformation  NULL
+
+  Z_ResourceControlResponse
+  -------------------------
+  Field                        Type                Default value
+
+  referenceId                  Z_ReferenceId       NULL
+  continueFlag                 bool_t              TRUE
+  resultSetWanted              bool_t              NULL
+  otherInfo                    Z_OtherInformation  NULL
+
+  Z_AccessControlRequest
+  ----------------------
+  Field                        Type                Default value
+
+  referenceId                  Z_ReferenceId       NULL
+  which                        enum                Z_AccessRequest_simpleForm;
+  u                            union               NULL
+  otherInfo                    Z_OtherInformation  NULL
+
+  Z_AccessControlResponse
+  -----------------------
+  Field                        Type                Default value
+
+  referenceId                  Z_ReferenceId       NULL
+  which                        enum                Z_AccessResponse_simpleForm
+  u                            union               NULL
+  diagnostic                   Z_DiagRec           NULL
+  otherInfo                    Z_OtherInformation  NULL
+
+  Z_Segment
+  ---------
+  Field                        Type                Default value
+  referenceId                  Z_ReferenceId       NULL
+  numberOfRecordsReturned      int                 value=0
+  num_segmentRecords           int                 0
+  segmentRecords               Z_NamePlusRecord    NULL
+  otherInfo                    Z_OtherInformation  NULL
+
+  Z_Close
+  -------
+  Field                        Type                Default value
+
+  referenceId                  Z_ReferenceId       NULL
+  closeReason                  int                 Z_Close_finished
+  diagnosticInformation        char*               NULL
+  resourceReportFormat         Odr_oid             NULL
+  resourceFormat               Z_External          NULL
+  otherInfo                    Z_OtherInformation  NULL
+
+
+
+
+  4.  Supporting Tools
+
+  In support of the service API - primarily the ASN module, which
+  provides the programmatic interface to the Z39.50 APDUs, YAZ contains
+  a collection of tools that support the development of applications.
+
+
+  4.1.  Query Syntax Parsers
+
+  Since the type-1 (RPN) query structure has no direct, useful string
+  representation, every origin application needs to provide some form of
+  mapping from a local query notation or representation to a Z_RPNQuery
+  structure. Some programmers will prefer to construct the query
+  manually, perhaps using odr_malloc() to simplify memory management.
+  The YAZ distribution includes two separate, query-generating tools
+  that may be of use to you.
+
+
+  4.1.1.  Prefix Query Format
+
+  Since RPN or reverse polish notation is really just a fancy way of
+  describing a suffix notation format (operator follows operands), it
+  would seem that the confusion is total when we now introduce a prefix
+  notation for RPN. The reason is one of simple laziness - it's somewhat
+  simpler to interpret a prefix format, and this utility was designed
+  for maximum simplicity, to provide a baseline representation for use
+  in simple test applications and scripting environments (like Tcl). The
+  demonstration client included with YAZ uses the PQF.
+
+  The PQF is defined by the pquery module in the YAZ library. The
+  pquery.h file provides the declaration of the functions
+
+
+
+       Z_RPNQuery *p_query_rpn (ODR o, oid_proto proto, const char *qbuf);
+
+       Z_AttributesPlusTerm *p_query_scan (ODR o, oid_proto proto,
+             Odr_oid **attributeSetP, const char *qbuf);
+
+       int p_query_attset (const char *arg);
+
+
+
+
+  The function p_query_rpn() takes as arguments an ODR stream (see
+  section ``The ODR Module'') to provide a memory source (the structure
+  created is released on the next call to odr_reset() on the stream/), a
+  protocol identifier (one of the constants PROTO_Z3950 and PROTO_SR),
+  an attribute set reference, and finally a null-terminated string
+  holding the query string.
+
+  If the parse went well, p_query_rpn() returns a pointer to a
+  Z_RPNQuery structure which can be placed directly into a
+  Z_SearchRequest.
+
+  The p_query_attset specifies which attribute set to use if the query
+  doesn't specify one by the @attrset operator. The p_query_attset
+  returns 0 if the argument is a valid attribute set specifier;
+  otherwise the function returns -1.
+
+  The grammar of the PQF is as follows:
+
+
+
+       Query ::= [ AttSet ] QueryStruct.
+
+       AttSet ::= string.
+
+       QueryStruct ::= { Attribute } Simple | Complex.
+
+       Attribute ::= '@attr' AttributeType '=' AttributeValue.
+
+       AttributeType ::= integer.
+
+       AttributeValue ::= integer.
+
+       Complex ::= Operator QueryStruct QueryStruct.
+
+       Operator ::= '@and' | '@or' | '@not' | '@prox' Proximity.
+
+       Simple ::= ResultSet | Term.
+
+       ResultSet ::= '@set' string.
+
+       Term ::= string | '"' string '"'.
+
+       Proximity ::= Exclusion Distance Ordered Relation WhichCode UnitCode.
+
+       Exclusion ::= '1' | '0' | 'void'.
+
+       Distance ::= integer.
+
+       Ordered ::= '1' | '0'.
+
+       Relation ::= integer.
+
+       WhichCode ::= 'known' | 'private' | integer.
+
+       UnitCode ::= integer.
+
+
+
+
+  You will note that the syntax above is a fairly faithful
+  representation of RPN, except for the Attibute, which has been moved a
+  step away from the term, allowing you to associate one or more
+  attributes with an entire query structure. The parser will
+  automatically apply the given attributes to each term as required.
+
+  The following are all examples of valid queries in the PQF.
+
+
+       dylan
+
+       "bob dylan"
+
+       @or "dylan" "zimmerman"
+
+       @set Result-1
+
+       @or @and bob dylan @set Result-1
+
+       @attr 4=1 @and @attr 1=1 "bob dylan" @attr 1=4 "slow train coming"
+
+       @attr 4=1 @attr 1=4 "self portrait"
+
+       @prox 0 3 1 2 k 2 dylan zimmerman
+
+
+
+
+
+  4.1.2.  Common Command Language
+
+  Not all users enjoy typing in prefix query structures and numerical
+  attribute values, even in a minimalistic test client. In the library
+  world, the more intuitive Common Command Language (or ISO 8777) has
+  enjoyed some popularity - especially before the widespread
+  availability of graphical interfaces. It is still useful in
+  applications where you for some reason or other need to provide a
+  symbolic language for expressing boolean query structures.
+
+  The EUROPAGATE research project working under the Libraries programme
+  of the European Commission's DG XIII has, amongst other useful tools,
+  implemented a general-purpose CCL parser which produces an output
+  structure that can be trivially converted to the internal RPN
+  representation of YAZ (The Z_RPNQuery structure). Since the CCL
+  utility - along with the rest of the software produced by EUROPAGATE -
+  is made freely available on a liberal license, it is included as a
+  supplement to YAZ.
+
+
+  4.1.2.1.  CCL Syntax
+
+  The CCL parser obeys the following grammar for the FIND argument.  The
+  syntax is annotated by in the lines prefixed by --.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+  CCL-Find ::= CCL-Find Op Elements
+             | Elements.
+
+  Op ::= "and" | "or" | "not"
+  -- The above means that Elements are separated by boolean operators.
+
+  Elements ::= '(' CCL-Find ')'
+             | Set
+             | Terms
+             | Qualifiers Relation Terms
+             | Qualifiers Relation '(' CCL-Find ')'
+             | Qualifiers '=' string '-' string
+  -- Elements is either a recursive definition, a result set reference, a
+  -- list of terms, qualifiers followed by terms, qualifiers followed
+  -- by a recursive definition or qualifiers in a range (lower - upper).
+
+  Set ::= 'set' = string
+  -- Reference to a result set
+
+  Terms ::= Terms Prox Term
+          | Term
+  -- Proximity of terms.
+
+  Term ::= Term string
+         | string
+  -- This basically means that a term may include a blank
+
+  Qualifiers ::= Qualifiers ',' string
+               | string
+  -- Qualifiers is a list of strings separated by comma
+
+  Relation ::= '=' | '>=' | '<=' | '<>' | '>' | '<'
+  -- Relational operators. This really doesn't follow the ISO8777
+  -- standard.
+
+  Prox ::= '%' | '!'
+  -- Proximity operator
+
+
+
+
+  The following queries are all valid:
+
+
+
+       dylan
+
+       "bob dylan"
+
+       dylan or zimmerman
+
+       set=1
+
+       (dylan and bob) or set=1
+
+
+
+
+  Assuming that the qualifiers ti, au and date are defined we may use:
+
+
+
+
+
+
+
+  ti=self portrait
+
+  au=(bob dylan and slow train coming)
+
+  date>1980 and (ti=((self portrait)))
+
+
+
+
+
+  4.1.2.2.  CCL Qualifiers
+
+
+  Qualifiers are used to direct the search to a particular searchable
+  index, such as title (ti) and author indexes (au). The CCL standard
+  itself doesn't specify a particular set of qualifiers, but it does
+  suggest a few short-hand notations. You can customize the CCL parser
+  to support a particular set of qualifiers to relect the current target
+  profile. Traditionally, a qualifier would map to a particular use-
+  attribute within the BIB-1 attribute set. However, you could also
+  define qualifiers that would set, for example, the structure-
+  attribute.
+
+  Consider a scenario where the target support ranked searches in the
+  title-index. In this case, the user could specify
+
+
+       ti,ranked=knuth computer
+
+
+
+
+  and the ranked would map to structure=free-form-text (4=105) and the
+  ti would map to title (1=4).
+
+  A "profile" with a set predefined CCL qualifiers can be read from a
+  file. The YAZ client reads its CCL qualifiers from a file named
+  default.bib. Each line in the file has the form:
+
+  qualifier-name    type=val type=val ...
+
+  where qualifier-name is the name of the qualifier to be used (eg. ti),
+  type is a BIB-1 category type and val is the corresponding BIB-1
+  attribute value. The type can be either numeric or it may be either u
+  (use), r (relation), p (position), s (structure), t (truncation) or c
+  (completeness). The qualifier-name term has a special meaning. The
+  types and values for this definition is used when no qualifier is
+  present.
+
+  Consider the following definition:
+
+
+       ti       u=4 s=1
+       au       u=1 s=1
+       term     s=105
+
+
+
+
+  Two qualifiers are defined, ti and au. They both set the structure-
+  attribute to phrase (1). ti sets the use-attribute to 4. au sets the
+  use-attribute to 1. When no qualifiers are used in the query the
+  structure-attribute is set to free-form-text (105).
+
+
+
+  4.1.2.3.  CCL API
+
+
+  All public definitions can be found in the header file ccl.h.  A
+  profile identifier is of type CCL_bibset. A profile must be created
+  with the call to the function ccl_qual_mk which returns a profile
+  handle of type CCL_bibset.
+
+  To read a file containing qualifier definitions the function
+  ccl_qual_file may be convenient. This function takes an already opened
+  FILE handle pointer as argument along with a CCL_bibset handle.
+
+  To parse a simple string with a FIND query use the function
+
+
+       struct ccl_rpn_node *ccl_find_str (CCL_bibset bibset, const char *str,
+                                          int *error, int *pos);
+
+
+
+
+  which takes the CCL profile (bibset) and query (str) as input. Upon
+  successful completion the RPN tree is returned. If an error eccur,
+  such as a syntax error, the integer pointed to by error holds the
+  error code and pos holds the offset inside query string in which the
+  parsing failed.
+
+  An english representation of the error may be obtained by calling the
+  ccl_err_msg function. The error codes are listed in ccl.h.
+
+  To convert the CCL RPN tree (type struct ccl_rpn_node *) to the
+  Z_RPNQuery of YAZ the function ccl_rpn_query must be used. This
+  function which is part of YAZ is implemented in yaz-ccl.c.  After
+  calling this function the CCL RPN tree is probably no longer needed.
+  The ccl_rpn_delete destroys the CCL RPN tree.
+
+  A CCL profile may be destroyed by calling the ccl_qual_rm function.
+
+  The token names for the CCL operators may be changed by setting the
+  globals (all type char *) ccl_token_and, ccl_token_or, ccl_token_not
+  and ccl_token_set.  An operator may have aliases, i.e. there may be
+  more than one name for the operator. To do this, separate each alias
+  with a space character.
+
+
+  4.2.  Object Identifiers
+
+  The basic YAZ representation of an OID is an array of integers,
+  terminated with the value -1. The ODR module provides two utility-
+  functions to create and copy this type of data elements:
+
+
+
+       Odr_oid *odr_getoidbystr(ODR o, char *str);
+
+
+
+
+  Creates an OID based on a string-based representation using dots (.)
+  to separate elements in the OID.
+
+
+
+       Odr_oid *odr_oiddup(ODR odr, Odr_oid *o);
+
+
+  Creates a copy of the OID referenced by the o parameter. Both
+  functions take an ODR stream as parameter. This stream is used to
+  allocate memory for the data elements, which is released on a
+  subsequent call to odr_reset() on that stream.
+
+  The OID module provides a higher-level representation of the family of
+  object identifers which describe the Z39.50 protocol and its related
+  objects. The definition of the module interface is given in the oid.h
+  file.
+
+  The interface is mainly based on the oident structure. The definition
+  of this structure looks like this:
+
+
+
+       typedef struct oident
+       {
+           oid_proto proto;
+           oid_class oclass;
+           oid_value value;
+           int oidsuffix[OID_SIZE];
+           char *desc;
+       } oident;
+
+
+
+
+  The proto field takes one of the values
+
+
+
+       PROTO_Z3950
+       PROTO_SR
+
+
+
+
+  If you don't care about talking to SR-based implementations (few
+  exist, and they may become fewer still if and when the ISO SR and ANSI
+  Z39.50 documents are merged into a single standard), you can ignore
+  this field on incoming packages, and always set it to PROTO_Z3950 for
+  outgoing packages.
+
+  The oclass field takes one of the values
+
+
+
+       CLASS_APPCTX
+       CLASS_ABSYN
+       CLASS_ATTSET
+       CLASS_TRANSYN
+       CLASS_DIAGSET
+       CLASS_RECSYN
+       CLASS_RESFORM
+       CLASS_ACCFORM
+       CLASS_EXTSERV
+       CLASS_USERINFO
+       CLASS_ELEMSPEC
+       CLASS_VARSET
+       CLASS_SCHEMA
+       CLASS_TAGSET
+       CLASS_GENERAL
+
+
+
+
+  corresponding to the OID classes defined by the Z39.50 standard.
+
+  Finally, the value field takes one of the values
+
+
+
+       VAL_APDU
+       VAL_BER
+       VAL_BASIC_CTX
+       VAL_BIB1
+       VAL_EXP1
+       VAL_EXT1
+       VAL_CCL1
+       VAL_GILS
+       VAL_WAIS
+       VAL_STAS
+       VAL_DIAG1
+       VAL_ISO2709
+       VAL_UNIMARC
+       VAL_INTERMARC
+       VAL_CCF
+       VAL_USMARC
+       VAL_UKMARC
+       VAL_NORMARC
+       VAL_LIBRISMARC
+       VAL_DANMARC
+       VAL_FINMARC
+       VAL_MAB
+       VAL_CANMARC
+       VAL_SBN
+       VAL_PICAMARC
+       VAL_AUSMARC
+       VAL_IBERMARC
+       VAL_EXPLAIN
+       VAL_SUTRS
+       VAL_OPAC
+       VAL_SUMMARY
+       VAL_GRS0
+       VAL_GRS1
+       VAL_EXTENDED
+       VAL_RESOURCE1
+       VAL_RESOURCE2
+       VAL_PROMPT1
+       VAL_DES1
+       VAL_KRB1
+       VAL_PRESSET
+       VAL_PQUERY
+       VAL_PCQUERY
+       VAL_ITEMORDER
+       VAL_DBUPDATE
+       VAL_EXPORTSPEC
+       VAL_EXPORTINV
+       VAL_NONE
+       VAL_SETM
+       VAL_SETG
+       VAL_VAR1
+       VAL_ESPEC1
+
+
+
+
+  again, corresponding to the specific OIDs defined by the standard.
+
+  The desc field contains a brief, mnemonic name for the OID in
+  question.
+
+  The function
+
+
+
+       struct oident *oid_getentbyoid(int *o);
+
+
+
+
+  takes as argument an OID, and returns a pointer to a static area
+  containing an oident structure. You typically use this function when
+  you receive a PDU containing an OID, and you wish to branch out
+  depending on the specific OID value.
+
+  The function
+
+
+
+       int *oid_ent_to_oid(struct oident *ent, int *dst);
+
+
+
+
+  Takes as argument an oident structure - in which the proto, oclass,
+  and value fields are assumed to be set correctly - and returns a
+  pointer to a the buffer as given by dst containing the base
+  representation of the corresponding OID. The function returns NULL and
+  the array dst is unchanged if a mapping couldn't place.  The array dst
+  should be at least of size OID_SIZE.
+
+  The oid_ent_to_oid() function can be used whenever you need to prepare
+  a PDU containing one or more OIDs. The separation of the protocol
+  element from the remainer of the OID-description makes it simple to
+  write applications that can communicate with either Z39.50 or OSI SR-
+  based applications.
+
+  The function
+
+
+
+       oid_value oid_getvalbyname(const char *name);
+
+
+
+
+  takes as argument a mnemonic OID name, and returns the value field of
+  the first entry in the database that contains the given name in its
+  desc field.
+
+  Finally, the module provides the following utility functions, whose
+  meaning should be obvious:
+
+
+
+       void oid_oidcpy(int *t, int *s);
+       void oid_oidcat(int *t, int *s);
+       int oid_oidcmp(int *o1, int *o2);
+       int oid_oidlen(int *o);
+
+
+
+
+  NOTE: The OID module has been criticized - and perhaps rightly so -
+  for needlessly abstracting the representation of OIDs. Other toolkits
+  use a simple string-representation of OIDs with good results. In
+  practice, we have found the interface comfortable and quick to work
+  with, and it is a simple matter (for what it's worth) to create
+  applications compatible with both ISO SR and Z39.50. Finally, the use
+  of the oident database is by no means mandatory. You can easily create
+  your own system for representing OIDs, as long as it is compatible
+  with the low-level integer-array representation of the ODR module.
+
+
+  4.3.  Nibble Memory
+
+  Sometimes when you need to allocate and construct a large,
+  interconnected complex of structures, it can be a bit of a pain to
+  release the associated memory again. For the structures describing the
+  Z39.50 PDUs and related structures, it is convenient to use the
+  memory-management system of the ODR subsystem (see ``Using ODR'').
+  However, in some circumstances where you might otherwise benefit from
+  using a simple nibble memory management system, it may be impractical
+  to use odr_malloc() and odr_reset(). For this purpose, the memory
+  manager which also supports the ODR streams is made available in the
+  NMEM module. The external interface to this module is given in the
+  nmem.h file.
+
+  The following prototypes are given:
+
+
+
+       NMEM nmem_create(void);
+       void nmem_destroy(NMEM n);
+       void *nmem_malloc(NMEM n, int size);
+       void nmem_reset(NMEM n);
+       int nmem_total(NMEM n);
+       void nmem_init(void);
+
+
+
+
+  The nmem_create() function returns a pointer to a memory control
+  handle, which can be released again by nmem_destroy() when no longer
+  needed. The function nmem_malloc() allocates a block of memory of the
+  requested size. A call to nmem_reset() or nmem_destroy() will release
+  all memory allocated on the handle since it was created (or since the
+  last call to nmem_reset(). The function nmem_total() returns the
+  number of bytes currently allocated on the handle.
+
+  Note that the nibble memory pool is shared amonst threads. Posix
+  mutex'es and WIN32 Critical sections are introduced to keep the module
+  thread safe. On WIN32 function nmem_init() initialises the Critical
+  Section handle and should be called once before any other nmem
+  function is used.
+
+
+  5.  The ODR Module
+
+  5.1.  Introduction
+
+  ODR is the BER-encoding/decoding subsystem of YAZ. Care as been taken
+  to isolate ODR from the rest of the package - specifically from the
+  transport interface. ODR may be used in any context where basic
+  ASN.1/BER representations are used.
+
+  If you are only interested in writing a Z39.50 implementation based on
+  the PDUs that are already provided with YAZ, you only need to concern
+  yourself with the section on managing ODR streams (section ``Using
+  ODR''). Only if you need to implement ASN.1 beyond that which has been
+  provided, should you worry about the second half of the documentation
+  (section ``Programming with ODR''). If you use one of the higher-level
+  interfaces, you can skip this section entirely.
+  This is important, so we'll repeat it for emphasis: You do not need to
+  read section ``Programming with ODR'' to implement Z39.50 with YAZ.
+
+  If you need a part of the protocol that isn't already in YAZ, you
+  should contact the authors before going to work on it yourself: We
+  might already be working on it. Conversely, if you implement a useful
+  part of the protocol before us, we'd be happy to include it in a
+  future release.
+
+
+  5.2.  Using ODR
+
+
+  5.2.1.  ODR Streams
+
+  Conceptually, the ODR stream is the source of encoded data in the
+  decoding mode; when encoding, it is the receptacle for the encoded
+  data. Before you can use an ODR stream it must be allocated. This is
+  done with the function
+
+
+
+       ODR odr_createmem(int direction);
+
+
+
+
+  The odr_createmem() function takes as argument one of three manifest
+  constants: ODR_ENCODE, ODR_DECODE, or ODR_PRINT. An ODR stream can be
+  in only one mode - it is not possible to change its mode once it's
+  selected. Typically, your program will allocate at least two ODR
+  streams - one for decoding, and one for encoding.
+
+  When you're done with the stream, you can use
+
+
+
+       void odr_destroy(ODR o);
+
+
+
+
+  to release the resources allocated for the stream.
+
+
+  5.2.2.  Memory Management
+
+  Two forms of memory management take place in the ODR system. The first
+  one, which has to do with allocating little bits of memory (sometimes
+  quite large bits of memory, actually) when a protocol package is
+  decoded, and turned into a complex of interlinked structures. This
+  section deals with this system, and how you can use it for your own
+  purposes. The next section deals with the memory management which is
+  required when encoding data - to make sure that a large enough buffer
+  is available to hold the fully encoded PDU.
+
+  The ODR module has its own memory management system, which is used
+  whenever memory is required. Specifically, it is used to allocate
+  space for data when decoding incoming PDUs. You can use the memory
+  system for your own purposes, by using the function
+
+
+
+       void *odr_malloc(ODR o, int size);
+
+
+  You can't use the normal free(2) routine to free memory allocated by
+  this function, and ODR doesn't provide a parallel function. Instead,
+  you can call
+
+
+
+       void odr_reset(ODR o, int size);
+
+
+
+
+  when you are done with the memory: Everything allocated since the last
+  call to odr_reset() is released. The odr_reset() call is also required
+  to clear up an error condition on a stream.
+
+  The function
+
+
+
+       int odr_total(ODR o);
+
+
+
+
+  returns the number of bytes allocated on the stream since the last
+  call to odr_reset().
+
+  The memory subsystem of ODR is fairly efficient at allocating and
+  releasing little bits of memory. Rather than managing the individual,
+  small bits of space, the system maintains a freelist of larger chunks
+  of memory, which are handed out in small bits. This scheme is
+  generally known as a nibble memory system. It is very useful for
+  maintaing short-lived constructions such as protocol PDUs.
+
+  If you want to retain a bit of memory beyond the next call to
+  odr_reset(), you can use the function
+
+
+
+       ODR_MEM odr_extract_mem(ODR o);
+
+
+
+
+  This function will give you control of the memory recently allocated
+  on the ODR stream. The memory will live (past calls to odr_reset()),
+  until you call the function
+
+
+
+       void odr_release_mem(ODR_MEM p);
+
+
+
+
+  The opaque ODR_MEM handle has no other purpose than referencing the
+  memory block for you until you want to release it.
+
+  You can use odr_extract_mem() repeatedly between allocating data, to
+  retain individual control of separate chunks of data.
+
+
+  5.2.3.  Encoding and Decoding Data
+
+  When encoding data, the ODR stream will write the encoded octet string
+  in an internal buffer. To retrieve the data, use the function
+       char *odr_getbuf(ODR o, int *len, int *size);
+
+
+
+
+  The integer pointed to by len is set to the length of the encoded
+  data, and a pointer to that data is returned. *size is set to the size
+  of the buffer (unless size is null, signalling that you are not
+  interested in the size). The next call to a primitive function using
+  the same ODR stream will overwrite the data, unless a different buffer
+  has been supplied using the call
+
+
+
+       void odr_setbuf(ODR o, char *buf, int len, int can_grow);
+
+
+
+
+  which sets the encoding (or decoding) buffer used by o to buf, using
+  the length len. Before a call to an encoding function, you can use
+  odr_setbuf() to provide the stream with an encoding buffer of
+  sufficient size (length). The can_grow parameter tells the encoding
+  ODR stream whether it is allowed to use realloc(2) to increase the
+  size of the buffer when necessary. The default condition of a new
+  encoding stream is equivalent to the results of calling
+
+
+
+       odr_setbuf(stream, 0, 0, 1);
+
+
+
+
+  In this case, the stream will allocate and reallocate memory as
+  necessary. The stream reallocates memory by repeatedly doubling the
+  size of the buffer - the result is that the buffer will typically
+  reach its maximum, working size with only a small number of
+  reallocation operations. The memory is freed by the stream when the
+  latter is destroyed, unless it was assigned by the user with the
+  can_grow parameter set to zero (in this case, you are expected to
+  retain control of the memory yourself).
+
+  To assume full control of an encoded buffer, you must first call
+  odr_getbuf() to fetch the buffer and its length. Next, you should call
+  odr_setbuf() to provide a different buffer (or a null pointer) to the
+  stream. In the simplest case, you will reuse the same buffer over and
+  over again, and you will just need to call odr_getbuf() after each
+  encoding operation to get the length and address of the buffer. Note
+  that the stream may reallocate the buffer during an encoding
+  operation, so it is necessary to retrieve the correct address after
+  each encoding operation.
+
+  It is important to realise that the ODR stream will not release this
+  memory when you call odr_reset(): It will merely update its internal
+  pointers to prepare for the encoding of a new data value.  When the
+  stream is released by the odr_destroy() function, the memory given to
+  it by odr_setbuf will be released only if the can_grow parameter to
+  odr_setbuf() was nonzero. The can_grow parameter, in other words, is a
+  way of signalling who is to own the buffer, you or the ODR stream. If
+  you never call odr_setbuf() on your encoding stream, which is
+  typically the case, the buffer allocated by the stream will belong to
+  the stream by default.
+
+  When you wish to decode data, you should first call odr_setbuf(), to
+  tell the decoding stream where to find the encoded data, and how long
+  the buffer is (the can_grow parameter is ignored by a decoding
+  stream). After this, you can call the function corresponding to the
+  data you wish to decode (eg, odr_integer() odr z_APDU()).
+
+  Examples of encoding/decoding functions:
+
+
+
+       int odr_integer(ODR o, int **p, int optional, const char *name);
+
+       int z_APDU(ODR o, Z_APDU **p, int optional, const char *name);
+
+
+
+
+  If the data is absent (or doesn't match the tag corresponding to the
+  type), the return value will be either 0 or 1 depending on the
+  optional flag. If optional is 0 and the data is absent, an error flag
+  will be raised in the stream, and you'll need to call odr_reset()
+  before you can use the stream again. If optional is nonzero, the
+  pointer pointed to by p will be set to the null value, and the
+  function will return 1.  The name argument is used to pretty-print the
+  tag in question.  It may be set to NULL if pretty-printing is not
+  desired.
+
+  If the data value is found where it's expected, the pointer pointed to
+  by the p argument will be set to point to the decoded type. The space
+  for the type will be allocated and owned by the ODR stream, and it
+  will live until you call odr_reset() on the stream. You cannot use
+  free(2) to release the memory. You can decode several data elements
+  (by repeated calls to odr_setbuf() and your decoding function), and
+  new memory will be allocated each time. When you do call odr_reset(),
+  everything decoded since the last call to odr_reset() will be
+  released.
+
+  The use of the double indirection can be a little confusing at first
+  (its purpose will become clear later on, hopefully), so an example is
+  in order. We'll encode an integer value, and immediately decode it
+  again using a different stream. A useless, but informative operation.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+  void do_nothing_useful(int value)
+  {
+      ODR encode, decode;
+      int *valp, *resvalp;
+      char *bufferp;
+      int len;
+
+      /* allocate streams */
+      if (!(encode = odr_createmem(ODR_ENCODE)))
+          return;
+      if (!(decode = odr_createmem(ODR_DECODE)))
+          return;
+
+      valp = &value;
+      if (odr_integer(encode, &valp, 0, 0) == 0)
+      {
+          printf("encoding went bad\n");
+          return;
+      }
+      bufferp = odr_getbuf(encode, &len);
+      printf("length of encoded data is %d\n", len);
+
+      /* now let's decode the thing again */
+      odr_setbuf(decode, bufferp, len);
+      if (odr_integer(decode, &resvalp, 0, 0) == 0)
+      {
+          printf("decoding went bad\n");
+          return;
+      }
+      printf("the value is %d\n", *resvalp);
+
+      /* clean up */
+      odr_destroy(encode);
+      odr_destroy(decode);
+  }
+
+
+
+
+  This looks like a lot of work, offhand. In practice, the ODR streams
+  will typically be allocated once, in the beginning of your program (or
+  at the beginning of a new network session), and the encoding and
+  decoding will only take place in a few, isolated places in your
+  program, so the overhead is quite manageable.
+
+
+  5.2.4.  Diagnostics
+
+  The encoding/decoding functions all return 0 when an error occurs.
+  Until you call odr_reset(), you cannot use the stream again, and any
+  function called will immediately return 0.
+
+  To provide information to the programmer or administrator, the
+  function
+
+
+
+       void odr_perror(ODR o, char *message);
+
+
+
+
+  is provided, which prints the message argument to stderr along with an
+  error message from the stream.
+
+
+  You can also use the function
+
+
+
+       int odr_geterror(ODR o);
+
+
+
+
+  to get the current error number from the screen. The number will be
+  one of these constants:
+
+
+     OMEMORY
+        Memory allocation failed.
+
+     OSYSERR
+        A system- or library call has failed. The standard diagnostic
+        variable errno should be examined to determine the actual error.
+
+     OSPACE
+        No more space for encoding. This will only occur when the user
+        has explicitly provided a buffer for an encoding stream without
+        allowing the system to allocate more space.
+
+     OREQUIRED
+        This is a common protocol error; A required data element was
+        missing during encoding or decoding.
+
+     OUNEXPECTED
+        An unexpected data element was found during decoding.
+
+     OOTHER
+        Other error. This is typically an indication of misuse of the
+        ODR system by the programmer, and also that the diagnostic
+        system isn't as good as it should be, yet.
+
+  The character string array
+
+
+
+       char *odr_errlist[]
+
+
+
+
+  can be indexed by the error code to obtain a human-readable
+  representation of the problem.
+
+
+  5.2.5.  Summary and Synopsis
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+  #include <odr.h>
+
+  ODR odr_createmem(int direction);
+
+  void odr_destroy(ODR o);
+
+  void odr_reset(ODR o);
+
+  char *odr_getbuf(ODR o, int *len);
+
+  void odr_setbuf(ODR o, char *buf, int len);
+
+  void *odr_malloc(ODR o, int size);
+
+  ODR_MEM odr_extract_mem(ODR o);
+
+  void odr_release_mem(ODR_MEM r);
+
+  int odr_geterror(ODR o);
+
+  void odr_perror(char *message);
+
+  extern char *odr_errlist[];
+
+
+
+
+
+  5.3.  Programming with ODR
+
+  The API of ODR is designed to reflect the structure of ASN.1, rather
+  than BER itself. Future releases may be able to represent data in
+  other external forms.
+
+  The interface is based loosely on that of the Sun Microsystems XDR
+  routines.  Specifically, each function which corresponds to an ASN.1
+  primitive type has a dual function. Depending on the settings of the
+  ODR stream which is supplied as a parameter, the function may be used
+  either to encode or decode data. The functions that can be built using
+  these primitive functions, to represent more complex datatypes, share
+  this quality. The result is that you only have to enter the definition
+  for a type once - and you have the functionality of encoding, decoding
+  (and pretty-printing) all in one unit. The resulting C source code is
+  quite compact, and is a pretty straightforward representation of the
+  source ASN.1 specification. Although no ASN.1 compiler is supplied
+  with ODR at this time, it shouldn't be too difficult to write one, or
+  perhaps even to adapt an existing compiler to output ODR routines (not
+  surprisingly, writing encoders/decoders using ODR turns out to be
+  boring work).
+
+  In many cases, the model of the XDR functions works quite well in this
+  role. In others, it is less elegant. Most of the hassle comes from the
+  optional SEQUENCE memebers which don't exist in XDR.
+
+
+  5.3.1.  The Primitive ASN.1 Types
+
+  ASN.1 defines a number of primitive types (many of which correspond
+  roughly to primitive types in structured programming languages, such
+  as C).
+
+
+  5.3.1.1.  INTEGER
+
+  The ODR function for encoding or decoding (or printing) the ASN.1
+  INTEGER type looks like this:
+       int odr_integer(ODR o, int **p, int optional, const char *name);
+
+
+
+
+  (we don't allow values that can't be contained in a C integer.)
+
+  This form is typical of the primitive ODR functions. They are named
+  after the type of data that they encode or decode. They take an ODR
+  stream, an indirect reference to the type in question, and an optional
+  flag (corresponding to the OPTIONAL keyword of ASN.1) as parameters.
+  They all return an integer value of either one or zero.  When you use
+  the primitive functions to construct encoders for complex types of
+  your own, you should follow this model as well. This ensures that your
+  new types can be reused as elements in yet more complex types.
+
+  The o parameter should obviously refer to a properly initialized ODR
+  stream of the right type (encoding/decoding/printing) for the
+  operation that you wish to perform.
+
+  When encoding or printing, the function first looks at *p. If *p (the
+  pointer pointed to by p) is a null pointer, this is taken to mean that
+  the data element is absent. If the optional parameter is nonzero, the
+  function will return one (signifying success) without any further
+  processing. If the optional is zero, an internal error flag is set in
+  the ODR stream, and the function will return 0. No further operations
+  can be carried out on the stream without a call to the function
+  odr_reset().
+
+  If *p is not a null pointer, it is expected to point to an instance of
+  the data type. The data will be subjected to the encoding rules, and
+  the result will be placed in the buffer held by the ODR stream.
+
+  The other ASN.1 primitives have similar functions that operate in
+  similar manners:
+
+
+  5.3.1.2.  BOOLEAN
+
+
+
+       int odr_bool(ODR o, bool_t **p, int optional, const char *name);
+
+
+
+
+
+  5.3.1.3.  REAL
+
+  Not defined.
+
+
+  5.3.1.4.  NULL
+
+
+
+       int odr_null(ODR o, bool_t **p, int optional, const char *name);
+
+
+
+
+  In this case, the value of **p is not important. If *p is different
+  from the null pointer, the null value is present, otherwise it's
+  absent.
+
+
+  5.3.1.5.  OCTET STRING
+
+
+
+       typedef struct odr_oct
+       {
+           unsigned char *buf;
+           int len;
+           int size;
+       } Odr_oct;
+
+       int odr_octetstring(ODR o, Odr_oct **p, int optional, const char *name);
+
+
+
+
+  The buf field should point to the character array that holds the
+  octetstring. The len field holds the actual length, while the size
+  field gives the size of the allocated array (not of interest to you,
+  in most cases). The character array need not be null terminated.
+
+  To make things a little easier, an alternative is given for string
+  types that are not expected to contain embedded NULL characters (eg.
+  VisibleString):
+
+
+
+       int odr_cstring(ODR o, char **p, int optional, const char *name);
+
+
+
+
+  Which encoded or decodes between OCTETSTRING representations and null-
+  terminates C strings.
+
+  Functions are provided for the derived string types, eg:
+
+
+
+       int odr_visiblestring(ODR o, char **p, int optional, const char *name);
+
+
+
+
+
+  5.3.1.6.  BIT STRING
+
+
+
+       int odr_bitstring(ODR o, Odr_bitmask **p, int optional, const char *name);
+
+
+
+
+  The opaque type Odr_bitmask is only suitable for holding relatively
+  brief bit strings, eg. for options fields, etc. The constant
+  ODR_BITMASK_SIZE multiplied by 8 gives the maximum possible number of
+  bits.
+
+  A set of macros are provided for manipulating the Odr_bitmask type:
+
+
+
+
+
+
+  void ODR_MASK_ZERO(Odr_bitmask *b);
+
+  void ODR_MASK_SET(Odr_bitmask *b, int bitno);
+
+  void ODR_MASK_CLEAR(Odr_bitmask *b, int bitno);
+
+  int ODR_MASK_GET(Odr_bitmask *b, int bitno);
+
+
+
+
+  The functions are modelled after the manipulation functions that
+  accompany the fd_set type used by the select(2) call.  ODR_MASK_ZERO
+  should always be called first on a new bitmask, to initialize the bits
+  to zero.
+
+
+  5.3.1.7.  OBJECT IDENTIFIER
+
+
+
+       int odr_oid(ODR o, Odr_oid **p, int optional, const char *name);
+
+
+
+
+  The C OID represenation is simply an array of integers, terminated by
+  the value -1 (the Odr_oid type is synonymous with the int type). We
+  suggest that you use the OID database module (see section ``Object
+  Identifiers'') to handle object identifiers in your application.
+
+
+  5.3.2.  Tagging Primitive Types
+
+  The simplest way of tagging a type is to use the odr_implicit_tag() or
+  odr_explicit_tag() macros:
+
+
+
+       int odr_implicit_tag(ODR o, Odr_fun fun, int class, int tag, int
+                            optional, const char *name);
+
+       int odr_explicit_tag(ODR o, Odr_fun fun, int class, int tag,
+                            int optional, const char *name);
+
+
+
+
+  To create a type derived from the integer type by implicit tagging,
+  you might write:
+
+
+
+       MyInt ::= [210] IMPLICIT INTEGER
+
+
+
+
+  In the ODR system, this would be written like:
+
+
+
+
+
+
+
+  int myInt(ODR o, int **p, int optional, const char *name)
+  {
+      return odr_implicit_tag(o, odr_integer, p,
+                     ODR_CONTEXT, 210, optional, name);
+  }
+
+
+
+
+  The function myInt() can then be used like any of the primitive
+  functions provided by ODR. Note that the behavior of odr_explicit()
+  and odr_implicit() macros act exactly the same as the functions they
+  are applied to - they respond to error conditions, etc, in the same
+  manner - they simply have three extra parameters. The class parameter
+  may take one of the values: ODR_CONTEXT, ODR_PRIVATE, ODR_UNIVERSAL,
+  or ODR_APPLICATION.
+
+
+  5.3.3.  Constructed Types
+
+  Constructed types are created by combining primitive types. The ODR
+  system only implements the SEQUENCE and SEQUENCE OF constructions
+  (although adding the rest of the container types should be simple
+  enough, if the need arises).
+
+  For implementing SEQUENCEs, the functions
+
+
+
+       int odr_sequence_begin(ODR o, void *p, int size, const char *name);
+       int odr_sequence_end(ODR o);
+
+
+
+
+  are provided.
+
+  The odr_sequence_begin() function should be called in the beginning of
+  a function that implements a SEQUENCE type. Its parameters are the ODR
+  stream, a pointer (to a pointer to the type you're implementing), and
+  the size of the type (typically a C structure). On encoding, it
+  returns 1 if *p is a null pointer. The size parameter is ignored. On
+  decoding, it returns 1 if the type is found in the data stream.  size
+  bytes of memory are allocated, and *p is set to point to this space.
+  odr_sequence_end() is called at the end of the complex function.
+  Assume that a type is defined like this:
+
+
+
+       MySequence ::= SEQUENCE {
+           intval INTEGER,
+           boolval BOOLEAN OPTIONAL }
+
+
+
+
+  The corresponding ODR encoder/decoder function and the associated data
+  structures could be written like this:
+
+
+
+
+
+
+
+
+  typedef struct MySequence
+  {
+      int *intval;
+      bool_t *boolval;
+  } MySequence;
+
+  int mySequence(ODR o, MySequence **p, int optional, const char *name)
+  {
+      if (odr_sequence_begin(o, p, sizeof(**p), name) == 0)
+          return optional && odr_ok(o);
+      return
+          odr_integer(o, &(*p)->intval, 0, "intval") &&
+          odr_bool(o, &(*p)->boolval, 1, "boolval") &&
+          odr_sequence_end(o);
+  }
+
+
+
+
+  Note the 1 in the call to odr_bool(), to mark that the sequence member
+  is optional. If either of the member types had been tagged, the macros
+  odr_implicit() or odr_explicit() could have been used.  The new
+  function can be used exactly like the standard functions provided with
+  ODR. It will encode, decode or pretty-print a data value of the
+  MySequence type. We like to name types with an initial capital, as
+  done in ASN.1 definitions, and to name the corresponding function with
+  the first character of the name in lower case. You could, of course,
+  name your structures, types, and functions any way you please - as
+  long as you're consistent, and your code is easily readable.  odr_ok
+  is just that - a predicate that returns the state of the stream. It is
+  used to ensure that the behaviour of the new type is compatible with
+  the interface of the primitive types.
+
+
+  5.3.4.  Tagging Constructed Types
+
+  NOTE: See section ``Tagging Primitive types'' for information on how
+  to tag the primitive types, as well as types that are already defined.
+
+
+  5.3.4.1.  Implicit Tagging
+
+  Assume the type above had been defined as
+
+
+
+       MySequence ::= [10] IMPLICIT SEQUENCE {
+           intval INTEGER,
+           boolval BOOLEAN OPTIONAL }
+
+
+
+
+  You would implement this in ODR by calling the function
+
+
+
+       int odr_implicit_settag(ODR o, int class, int tag);
+
+
+
+
+  which overrides the tag of the type immediately following it. The
+  macro odr_implicit() works by calling odr_implicit_settag()
+  immediately before calling the function pointer argument. Your type
+  function could look like this:
+       int mySequence(ODR o, MySequence **p, int optional, const char *name)
+       {
+           if (odr_implicit_settag(o, ODR_CONTEXT, 10) == 0 ||
+               odr_sequence_begin(o, p, sizeof(**p), name) == 0)
+               return optional && odr_ok(o);
+           return
+               odr_integer(o, &(*p)->intval, 0, "intval") &&
+               odr_bool(o, &(*p)->boolval, 1, "boolval") &&
+               odr_sequence_end(o);
+       }
+
+
+
+
+  The definition of the structure MySequence would be the same.
+
+
+  5.3.4.2.  Explicit Tagging
+
+  Explicit tagging of constructed types is a little more complicated,
+  since you are in effect adding a level of construction to the data.
+
+  Assume the definition:
+
+
+
+       MySequence ::= [10] IMPLICIT SEQUENCE {
+           intval INTEGER,
+           boolval BOOLEAN OPTIONAL }
+
+
+
+
+  Since the new type has an extra level of construction, two new
+  functions are needed to encapsulate the base type:
+
+
+
+       int odr_constructed_begin(ODR o, void *p, int class, int tag,
+              const char *name);
+
+       int odr_constructed_end(ODR o);
+
+
+
+
+  Assume that the IMPLICIT in the type definition above were replaced
+  with EXPLICIT (or that the IMPLICIT keyword were simply deleted, which
+  would be equivalent). The structure definition would look the same,
+  but the function would look like this:
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+  int mySequence(ODR o, MySequence **p, int optional, const char *name)
+  {
+      if (odr_constructed_begin(o, p, ODR_CONTEXT, 10, name) == 0)
+          return optional && odr_ok(o);
+      if (o->direction == ODR_DECODE)
+          *p = odr_malloc(o, sizeof(**p));
+      if (odr_sequence_begin(o, p, sizeof(**p), 0) == 0)
+      {
+          *p = 0; /* this is almost certainly a protocol error */
+          return 0;
+      }
+      return
+          odr_integer(o, &(*p)->intval, 0, "intval") &&
+          odr_bool(o, &(*p)->boolval, 1, "boolval") &&
+          odr_sequence_end(o) &&
+          odr_constructed_end(o);
+  }
+
+
+
+
+  Notice that the interface here gets kind of nasty. The reason is
+  simple: Explicitly tagged, constructed types are fairly rare in the
+  protocols that we care about, so the aesthetic annoyance (not to
+  mention the dangers of a cluttered interface) is less than the time
+  that would be required to develop a better interface. Nevertheless, it
+  is far from satisfying, and it's a point that will be worked on in the
+  future. One option for you would be to simply apply the odr_explicit()
+  macro to the first function, and not have to worry about
+  odr_constructed_* yourself. Incidentally, as you might have guessed,
+  the odr_sequence_ functions are themselves implemented using the
+  odr_constructed_ functions.
+
+
+  5.3.5.  SEQUENCE OF
+
+  To handle sequences (arrays) of a apecific type, the function
+
+
+
+       int odr_sequence_of(ODR o, int (*fun)(ODR o, void *p, int optional),
+                               void *p, int *num, const char *name);
+
+
+
+
+  The fun parameter is a pointer to the decoder/encoder function of the
+  type. p is a pointer to an array of pointers to your type. num is the
+  number of elements in the array.
+
+  Assume a type
+
+
+
+       MyArray ::= SEQUENCE OF INTEGER
+
+
+
+
+  The C representation might be
+
+
+
+
+
+
+  typedef struct MyArray
+  {
+      int num_elements;
+      int **elements;
+  } MyArray;
+
+
+
+
+  And the function might look like
+
+
+
+       int myArray(ODR o, MyArray **p, int optional, const char *name)
+       {
+           if (o->direction == ODR_DECODE)
+               *p = odr_malloc(o, sizeof(**p));
+           if (odr_sequence_of(o, odr_integer, &(*p)->elements,
+               &(*p)->num_elements, name))
+               return 1;
+           *p = 0;
+           return optional && odr_ok(o);
+       }
+
+
+
+
+
+  5.3.6.  CHOICE Types
+
+  The choice type is used fairly often in some ASN.1 definitions, so
+  some work has gone into streamlining its interface.
+
+  CHOICE types are handled by the function:
+
+
+
+       int odr_choice(ODR o, Odr_arm arm[], void *p, void *whichp,
+                      const char *name);
+
+
+
+
+  The arm array is used to describe each of the possible types that the
+  CHOICE type may assume. Internally in your application, the CHOICE
+  type is represented as a discriminated union. That is, a C union
+  accompanied by an integer (or enum) identifying the active 'arm' of
+  the union. whichp is a pointer to the union discriminator. When
+  encoding, it is examined to determine the current type. When decoding,
+  it is set to reference the type that was found in the input stream.
+
+  The Odr_arm type is defined thus:
+
+
+
+       typedef struct odr_arm
+       {
+           int tagmode;
+           int class;
+           int tag;
+           int which;
+           Odr_fun fun;
+           char *name;
+       } Odr_arm;
+
+
+  The interpretation of the fields are:
+
+
+     tagmode
+        Either ODR_IMPLICIT, ODR_EXPLICIT, or ODR_NONE (-1) to mark no
+        tagging.
+
+     class, tag
+        The class and tag of the type (-1 if no tagging is used).
+
+     which
+        The value of the discriminator that corresponds to this CHOICE
+        element. Typically, it will be a #defined constant, or an enum
+        member.
+
+     fun
+        A pointer to a function that implements the type of the CHOICE
+        member. It may be either a standard ODR type or a type defined
+        by yourself.
+
+     name
+        Name of tag.
+
+  A handy way to prepare the array for use by the odr_choice() function
+  is to define it as a static, initialized array in the beginning of
+  your decoding/encoding function. Assume the type definition:
+
+
+
+       MyChoice ::= CHOICE {
+           untagged INTEGER,
+           tagged   [99] IMPLICIT INTEGER,
+           other    BOOLEAN
+       }
+
+
+
+
+  Your C type might look like
+
+
+
+       typedef struct MyChoice
+       {
+           enum
+           {
+               MyChoice_untagged,
+               MyChoice_tagged,
+               MyChoice_other
+           } which;
+           union
+           {
+               int *untagged;
+               int *tagged;
+               bool_t *other;
+           } u;
+       };
+
+
+
+
+  And your function could look like this:
+
+
+
+
+  int myChoice(ODR o, MyChoice **p, int optional, const char *name)
+  {
+      static Odr_arm arm[] =
+      {
+          {-1, -1, -1, MyChoice_untagged, odr_integer, "untagged"},
+          {ODR_IMPLICIT, ODR_CONTEXT, 99, MyChoice_tagged, odr_integer,
+                                                              "tagged"},
+          {-1, -1, -1, MyChoice_other, odr_boolean, "other"},
+          {-1, -1, -1, -1, 0}
+      };
+
+      if (o->direction == ODR_DECODE)
+          *p = odr_malloc(o, sizeof(**p);
+      else if (!*p)
+          return optional && odr_ok(o);
+
+      if (odr_choice(o, arm, &(*p)->u, &(*p)->which), name)
+          return 1;
+      *p = 0;
+      return optional && odr_ok(o);
+  }
+
+
+
+
+  In some cases (say, a non-optional choice which is a member of a
+  sequence), you can "embed" the union and its discriminator in the
+  structure belonging to the enclosing type, and you won't need to
+  fiddle with memory allocation to create a separate structure to wrap
+  the discriminator and union.
+
+  The corresponding function is somewhat nicer in the Sun XDR interface.
+  Most of the complexity of this interface comes from the possibility of
+  declaring sequence elements (including CHOICEs) optional.
+
+  The ASN.1 specifictions naturally requires that each member of a
+  CHOICE have a distinct tag, so they can be told apart on decoding.
+  Sometimes it can be useful to define a CHOICE that has multiple types
+  that share the same tag. You'll need some other mechanism, perhaps
+  keyed to the context of the CHOICE type. In effect, we would like to
+  introduce a level of context-sensitiveness to our ASN.1 specification.
+  When encoding an internal representation, we have no problem, as long
+  as each CHOICE member has a distinct discriminator value. For
+  decoding, we need a way to tell the choice function to look for a
+  specific arm of the table. The function
+
+
+
+       void odr_choice_bias(ODR o, int what);
+
+
+
+
+  provides this functionality. When called, it leaves a notice for the
+  next call to odr_choice() to be called on the decoding stream o that
+  only the arm entry with a which field equal to what should be tried.
+
+  The most important application (perhaps the only one, really) is in
+  the definition of application-specific EXTERNAL encoders/decoders
+  which will automatically decode an ANY member given the direct or
+  indirect reference.
+
+
+
+
+
+  5.4.  Debugging
+
+  The protocol modules are suffering somewhat from a lack of diagnostic
+  tools at the moment. Specifically ways to pretty-print PDUs that
+  aren't recognized by the system. We'll include something to this end
+  in a not-too-distant release. In the meantime, what we do when we get
+  packages we don't understand is to compile the ODR module with
+  ODR_DEBUG defined. This causes the module to dump tracing information
+  as it processes data units. With this output and the protocol
+  specification (Z39.50), it is generally fairly easy to see what goes
+  wrong.
+
+
+  6.  The COMSTACK Module
+
+  6.1.  Introduction
+
+  The COMSTACK subsystem provides a transparent interface to different
+  types of transport stacks for the exchange of BER-encoded data. At
+  present, the RFC1729 method (BER over TCP/IP), and Peter Furniss'
+  XTImOSI stack are supported, but others may be added in time. The
+  philosophy of the module is to provide a simple interface by hiding
+  unused options and facilities of the underlying libraries. This is
+  always done at the risk of losing generality, and it may prove that
+  the interface will need extension later on.
+
+  The interface is implemented in such a fashion that only the sub-
+  layers constructed to the transport methods that you wish to use in
+  your application are linked in.
+
+  You will note that even though simplicity was a goal in the design,
+  the interface is still orders of magnitudes more complex than the
+  transport systems found in many other packages. One reason is that the
+  interface needs to support the somewhat different requirements of the
+  different lower-layer communications stacks; another important reason
+  is that the interface seeks to provide a more or less industrial-
+  strength approach to asynchronous event-handling. When no function is
+  allowed to block, things get more complex - particularly on the server
+  side. We urge you to have a look at the demonstration client and
+  server provided with the package. They are meant to be easily readable
+  and instructive, while still being at least moderately useful.
+
+
+  6.2.  Common Functions
+
+  6.2.1.  Managing Endpoints
+
+
+
+       COMSTACK cs_create(CS_TYPE type, int blocking, int protocol);
+
+
+
+
+  Creates an instance of the protocol stack - a communications endpoint.
+  The type parameter determines the mode of communication. At present,
+  the values tcpip_type and mosi_type are recognized. The function
+  returns a null-pointer if a system error occurs. The blocking
+  parameter should be one if you wish the association to operate in
+  blocking mode, zero otherwise. The protocol field should be one of
+  PROTO_SR or PROTO_Z3950.
+
+
+
+       int cs_close(COMSTACK handle);
+
+  Closes the connection (as elegantly as the lower layers will permit),
+  and releases the resouces pointed to by the handle parameter. The
+  handle should not be referenced again after this call.
+
+  NOTE: We really need a soft disconnect, don't we?
+
+
+  6.2.2.  Data Exchange
+
+
+
+       int cs_put(COMSTACK handle, char *buf, int len);
+
+
+
+
+  Sends buf down the wire. In blocking mode, this function will return
+  only when a full buffer has been written, or an error has occurred. In
+  nonblocking mode, it's possible that the function will be unable to
+  send the full buffer at once, which will be indicated by a return
+  value of 1. The function will keep track of the number of octets
+  already written; you should call it repeatedly with the same values of
+  buf and len, until the buffer has been transmitted. When a full buffer
+  has been sent, the function will return 0 for success. -1 indicates an
+  error condition (see below).
+
+
+
+       int cs_get(COMSTACK handle, char **buf, int *size);
+
+
+
+
+  Receives a PDU from the peer. Returns the number of bytes read. In
+  nonblocking mode, it is possible that not all of the packet can be
+  read at once. In this case, the function returns 1. To simplify the
+  interface, the function is responsible for managing the size of the
+  buffer. It will be reallocated if necessary to contain large packages,
+  and will sometimes be moved around internally by the subsystem when
+  partial packages are read. Before calling cs_get for the fist time,
+  the buffer can be initialized to the null pointer, and the length
+  should also be set to 0 - cs_get will perform a malloc(2) on the
+  buffer for you. When a full buffer has been read, the size of the
+  package is returned (which will always be greater than 1). -1
+  indicates an error condition.
+
+  See also the cs_more() function below.
+
+
+
+       int cs_more(COMSTACK handle);
+
+
+
+
+  The cs_more() function should be used in conjunction with cs_get and
+  select(2).  The cs_get() function will sometimes (notably in the
+  TCP/IP mode) read more than a single protocol package off the network.
+  When this happens, the extra package is stored by the subsystem. After
+  calling cs_get(), and before waiting for more input, You should always
+  call cs_more() to check if there's a full protocol package already
+  read. If cs_more() returns 1, cs_get() can be used to immediately
+  fetch the new package. For the mOSI subsystem, the function should
+  always return 0, but if you want your stuff to be protocol
+  independent, you should use it.
+
+  NOTE: The cs_more() function is required because the RFC1729-method
+  does not provide a way of separating individual PDUs, short of
+  partially decoding the BER. Some other implementations will carefully
+  nibble at the packet by calling read(2) several times. This was felt
+  to be too inefficient (or at least clumsy) - hence the call for this
+  extra function.
+
+
+
+       int cs_look(COMSTACK handle);
+
+
+
+
+  This function is useful when you're operating in nonblocking mode.
+  Call it when select(2) tells you there's something happening on the
+  line. It returns one of the following values:
+
+
+     CS_NONE
+        No event is pending. The data found on the line was not a
+        complete package.
+
+     CS_CONNECT
+        A response to your connect request has been received. Call
+        cs_rcvconnect to process the event and to finalize the
+        connection establishment.
+
+     CS_DISCON
+        The other side has closed the connection (or maybe sent a
+        disconnect request - but do we care? Maybe later). Call cs_close
+        To close your end of the association as well.
+
+     CS_LISTEN
+        A connect request has been received. Call cs_listen to process
+        the event.
+
+     CS_DATA
+        There's data to be found on the line. Call cs_get to get it.
+
+  NOTE: You should be aware that even if cs_look() tells you that
+  there's an event event pending, the corresponding function may still
+  return and tell you there was nothing to be found.  This means that
+  only part of a package was available for reading. The same event will
+  show up again, when more data has arrived.
+
+
+
+       int cs_fileno(COMSTACK h);
+
+
+
+
+  Returns the file descriptor of the association. Use this when file-
+  level operations on the endpoint are required (select(2) operations,
+  specifically).
+
+
+  6.3.  Client Side
+
+
+
+       int cs_connect(COMSTACK handle, void *address);
+
+
+
+  Initiate a connection with the target at address (more on addresses
+  below). The function will return 0 on success, and 1 if the operation
+  does not complete immediately (this will only happen on a nonblocking
+  endpoint). In this case, use cs_rcvconnect to complete the operation,
+  when select(2) reports input pending on the association.
+
+
+
+       int cs_rcvconnect(COMSTACK handle);
+
+
+
+
+  Complete a connect operation initiated by cs_connect(). It will return
+  0 on success; 1 if the operation has not yet completed (in this case,
+  call the function again later); -1 if an error has occured.
+
+
+  6.4.  Server Side
+
+  To establish a server under the inetd server, you can use
+
+
+
+       COMSTACK cs_createbysocket(int socket, CS_TYPE type, int blocking,
+                                     int protocol);
+
+
+
+
+  The socket parameter is an established socket (when your application
+  is invoked from inetd, the socket will typically be 0. The following
+  parameters are identical to the ones for cs_create.
+
+
+
+       int cs_bind(COMSTACK handle, void *address, int mode)
+
+
+
+
+  Binds a local address to the endpoint. Read about addresses below. The
+  mode parameter should be either CS_CLIENT or CS_SERVER.
+
+
+
+       int cs_listen(COMSTACK handle, char *addr, int *addrlen);
+
+
+
+
+  Call this to process incoming events on an endpoint that has been
+  bound in listening mode. It will return 0 to indicate that the connect
+  request has been received, 1 to signal a partial reception, and -1 to
+  indicate an error condition.
+
+
+
+       COMSTACK cs_accept(COMSTACK handle);
+
+
+
+
+  This finalises the server-side association establishment, after
+  cs_listen has completed successfully. It returns a new connection
+  endpoint, which represents the new association. The application will
+  typically wish to fork off a process to handle the association at this
+  point, and continue listen for new connections on the old handle.
+
+  You can use the call
+
+
+
+       char *cs_addrstr(COMSTACK);
+
+
+
+
+  on an established connection to retrieve the hostname of the remote
+  host.
+
+  NOTE: You may need to use this function with some care if your name
+  server service is slow or unreliable
+
+
+  6.5.  Addresses
+
+  The low-level format of the addresses are different depending on the
+  mode of communication you have chosen. A function is provided by each
+  of the lower layers to map a user-friendly string-form address to the
+  binary form required by the lower layers.
+
+
+
+       struct sockaddr_in *tcpip_strtoaddr(char *str);
+
+       struct netbuf *mosi_strtoaddr(char *str);
+
+
+
+
+  The format for TCP/IP addresses is straightforward:
+
+
+
+       <host> [ ':' <portnum> ]
+
+
+
+
+  The hostname can be either a domain name or an IP address. The port
+  number, if omitted, defaults to 210.
+
+  For OSI, the format is
+
+
+
+       [ <t-selector> '/' ] <host> [ ':' <port> ]
+
+
+
+
+  The transport selector is given as an even number of hex digits.
+
+  You'll note that the address format for the OSI mode are just a subset
+  of full presentation addresses. We use presentation addresses because
+  xtimosi doesn't, in itself, allow access to the X.500 Directory
+  service. We use a limited form, because we haven't yet come across an
+  implementation that used more of the elements of a full p-address. It
+  is a fairly simple matter to add the rest of the elements to the
+  address format as needed, however: Xtimosi does support the full P-
+  address structure.
+  In both transport modes, the special hostname "@" is mapped to any
+  local address (the manifest constant INADDR_ANY). It is used to
+  establish local listening endpoints in the server role.
+
+  When a connection has been established, you can use
+
+
+
+       char cs_addrstr(COMSTACK h);
+
+
+
+
+  to retrieve the host name of the peer system. The function returns a
+  pointer to a static area, which is overwritten on the next call to the
+  function.
+
+  NOTE: We have left the issue of X.500 name-to-address mapping open,
+  for the moment. It would be a simple matter to provide a table-based
+  mapping, if desired. Alternately, we could use the X.500 client-
+  function that is provided with the ISODE (although this would defeat
+  some of the purpose of using ThinOSI in the first place. We have been
+  told that it should be within the realm of the possible to implement a
+  lightweight implementation of the necessary X.500 client capabilities
+  on top of ThinOSI. This would be the ideal solution, we feel. On the
+  other hand, it still remains to be seen just what role the Directory
+  will play in a world populated by ThinOSI and other pragmatic
+  solutions.
+
+
+  6.6.  Diagnostics
+
+  All functions return -1 if an error occurs. Typically, the functions
+  will return 0 on success, but the data exchange functions (cs_get,
+  cs_put, cs_more) follow special rules. Consult their descriptions.
+
+  When a function (including the data exchange functions) reports an
+  error condition, use the function cs_errno() to determine the cause of
+  the problem. The function
+
+
+
+       void cs_perror(COMSTACK handle char *message);
+
+
+
+
+  works like perror(2) and prints the message argument, along with a
+  system message, to stderr.  Use the character array
+
+
+
+       extern const char *cs_errlist[];
+
+
+
+
+  to get hold of the message, if you want to process it differently.
+  The function
+
+
+
+       const char *cs_stackerr(COMSTACK handle);
+
+
+
+  Returns an error message from the lower layer, if one has been
+  provided.
+
+
+  6.7.  Enabling OSI Communication
+
+  6.7.1.  Installing Xtimosi
+
+  Although you will have to download Peter Furniss' XTI/mOSI
+  implementation for yourself, we've tried to make the integration as
+  simple as possible.
+
+  The latest version of xtimosi will generally be under
+
+
+
+       ftp://pluto.ulcc.ac.uk/ulcc/thinosi/xtimosi/
+
+
+
+
+  When you have downloaded and unpacked the archive, it will (we assume)
+  have created a directory called xtimosi. We suggest that you place
+  this directory in the same directory where you unpacked the YAZ
+  distribution. This way, you shouldn't have to fiddle with the
+  makefiles of YAZ beyond uncommenting a few lines.
+
+  Go to xtimosi/src, and type "make libmosi.a".  This should generally
+  create the library, ready to use.
+
+  CAVEAT
+
+  The currently available release of xtimosi has some inherent problems
+  that make it disfunction on certain platforms - eg. the Digital OSF/1
+  workstations. It is supposedly primarily a compiler problem, and we
+  hope to see a release that is generally portable. While we can't
+  guarantee that it can be brought to work on your platform, we'll be
+  happy to talk to you about problems that you might see, and relay
+  information to the author of the software. There are some signs that
+  the gcc compiler is more likely to produce a fully functional library,
+  but this hasn't been verified (we think that the problem is limited to
+  the use of hexadecimal escape-codes used in strings, which are
+  silently ignored by some compilers).
+
+  A problem has been encountered in the communication with ISODE-based
+  applications. If the ISODE presentation-user calls PReadRequest() with
+  a timeout value different from OK or NOTOK, he will get an immediate
+  TIMEOUT abort when receiving large (>2041 bytes, which is the SPDU-
+  size that the ISODE likes to work with) packages from an xtimosi-based
+  implementation (probably most other implementations as well, in fact).
+  It seems to be a flaw in the ISODE API, and the workaround (for ISODE
+  users) is to either not use an explicit timeout (switching to either
+  blocking or nonblocking mode), or to check that the timer really has
+  expired before closing the connection.
+
+  The next step in the installation is to modify the makefile in the
+  toplevel YAZ directory. The place to change is in the top of the file,
+  and is clearly marked with a comment.
+
+  Now run make in the YAZ toplevel directory (do a "make clean" first,
+  if the system has been previously made without OSI support). Use the
+  YAZ ztest and client demo programs to verify that OSI communication
+  works OK. Then, you can go ahead and try to talk to other
+  implementations.
+
+
+  NOTE: Our interoperability experience is limited to version 7 of the
+  Nordic SR-Nett package, which has had several protocol errors fixed
+  from the earlier releases. If you have problems or successes in
+  interoperating with other implementations, we'd be glad to hear about
+  it, or to help you make things work, as our resources allow.
+
+  If you write your own applications based on YAZ, and you wish to
+  include OSI support, the procedure is equally simple. You should
+  include the xmosi.h header file in addition to comstack.h.  xmosi.h
+  will define the manifest constant mosi_type, which you should pass to
+  the cs_create() function. In addition, you should use the function
+  mosi_strtoaddr() rather than tcpip_strtoaddr() when you need to
+  prepare an address.
+
+  When you link your application, you should include (after the libyaz.a
+  library) the libmosi.a library, and the librfc.a library provided with
+  YAZ (for OSI transport).
+
+  As always, it can be very useful, if not essential, to have a look at
+  the example applications to see how things are done.
+
+
+  6.7.2.  OSI Transport
+
+  Xtimosi requires an implementation of the OSI transport service under
+  the X/OPEN XTI API. We provide an implementation of the RFC1006
+  encapsulation of OSI/TP0 in TCP/IP (through the Berkeley Sockets API),
+  as an independent part of YAZ (it's found under the rfc1006
+  directory). If you have access to an OSI transport provider under XTI,
+  you should be able to make that work too, although it may require
+  tinkering with the mosi_strtoaddr() function.
+
+
+  6.7.3.  Presentation Context Management
+
+  To simplify the implementation, we use Peter Furniss' alternative
+  (PRF) option format for the Control of the presentation negotiation
+  phase. This format is enabled by default when you compile xtimosi.
+
+  The current version of YAZ does not support presentation-layer
+  negotiation of response record formats. The primary reason is that we
+  have had access to no other SR or Z39.50 implementations over OSI that
+  used this method. Secondarily, we believe that the EXPLAIN facility is
+  a superior mechanism for relaying target capabilities in this respect.
+  This is not to say that we have no intentions of supporting
+  presentation context negotiation - we have just hitherto given it a
+  lower priority than other aspects of the protocol.
+
+  One thing is certain: The addition of this capability to YAZ should
+  have only a minimal impact on existing applications, and on the
+  interface to the software in general. Most likely, we will add an
+  extra layer of interface to the processing of EXPLAIN records, which
+  will convert back and forth between oident records (see section
+  ``Object Identifiers'') and direct or indirect references, given the
+  current association setup. Implementations based on any of the higher-
+  level interfaces will most likely not have to be changed at all.
+
+
+  6.8.  Summary and Synopsis
+
+
+
+
+
+
+
+  #include <comstack.h>
+
+  #include <tcpip.h>      /* this is for TCP/IP support   */
+  #include <xmosi.h>      /* and this is for mOSI support */
+
+  COMSTACK cs_create(CS_TYPE type, int blocking, int protocol);
+
+  COMSTACK cs_createbysocket(int s, CS_TYPE type, int blocking,
+                                int protocol);
+
+  int cs_bind(COMSTACK handle, int mode);
+
+  int cs_connect(COMSTACK handle, void *address);
+
+  int cs_rcvconnect(COMSTACK handle);
+
+  int cs_listen(COMSTACK handle);
+
+  COMSTACK cs_accept(COMSTACK handle);
+
+  int cs_put(COMSTACK handle, char *buf, int len);
+
+  int cs_get(COMSTACK handle, char **buf, int *size);
+
+  int cs_more(COMSTACK handle);
+
+  int cs_close(COMSTACK handle);
+
+  int cs_look(COMSTACK handle);
+
+  struct sockaddr_in *tcpip_strtoaddr(char *str);
+
+  struct netbuf *mosi_strtoaddr(char *str);
+
+  extern int cs_errno;
+
+  void cs_perror(COMSTACK handle char *message);
+
+  const char *cs_stackerr(COMSTACK handle);
+
+  extern const char *cs_errlist[];
+
+
+
+
+
+  7.  Making an IR Interface for Your Database with YAZ
+
+  7.1.  Introduction
+
+  NOTE: If you aren't into documentation, a good way to learn how the
+  backend interface works is to look at the backend.h file. Then, look
+  at the small dummy-server in server/ztest.c. Finally, you can have a
+  look at the seshigh.c file, which is where most of the logic of the
+  frontend server is located. The backend.h file also makes a good
+  reference, once you've chewed your way through the prose of this file.
+
+  If you have a database system that you would like to make available by
+  means of Z39.50/SR, YAZ basically offers your two options. You can use
+  the APIs provided by the ASN, ODR, and COMSTACK modules to create and
+  decode PDUs, and exchange them with a client. Using this low-level
+  interface gives you access to all fields and options of the protocol,
+  and you can construct your server as close to your existing database
+  as you like. It is also a fairly involved process, requiring you to
+  set up an event-handling mechanism, protocol state machine, etc. To
+  simplify server implementation, we have implemented a compact and
+  simple, but reasonably full-functioned server-frontend that will
+  handle most of the protocol mechanics, while leaving you to
+  concentrate on your database interface.
+
+  NOTE: The backend interface was designed in anticipation of a specific
+  integration task, while still attempting to achieve some degree of
+  generality. We realise fully that there are points where the interface
+  can be improved significantly. If you have specific functions or
+  parameters that you think could be useful, send us a mail (or better,
+  sign on to the mailing list referred to in the toplevel README file).
+  We will try to fit good suggestions into future releases, to the
+  extent that it can be done without requiring too many structural
+  changes in existing applications.
+
+
+  7.2.  The Database Frontend
+
+  We refer to this software as a generic database frontend. Your
+  database system is the backend database, and the interface between the
+  two is called the backend API. The backend API consists of a small
+  number of function prototypes and structure definitions. You are
+  required to provide the main() routine for the server (which can be
+  quite simple), as well as functions to match each of the prototypes.
+  The interface functions that you write can use any mechanism you like
+  to communicate with your database system: You might link the whole
+  thing together with your database application and access it by
+  function calls; you might use IPC to talk to a database server
+  somewhere; or you might link with third-party software that handles
+  the communication for you (like a commercial database client library).
+  At any rate, the functions will perform the tasks of:
+
+
+  o  Initialization.
+
+  o  Searching.
+
+  o  Fetching records.
+
+  o  Scanning the database index (if you wish to implement SCAN).
+
+  (more functions will be added in time to support as much of
+  Z39.50-1995 as possible).
+
+  Because the model where pipes or sockets are used to access the
+  backend database is a fairly common one, we have added a mechanism
+  that allows this communication to take place asynchronously. In this
+  mode, the frontend server doesn't have to block while the backend
+  database is processing a request, but can wait for additional PDUs
+  from the client.
+
+
+  7.3.  The Backend API
+
+  The headers files that you need to use the interface are in the
+  include/ directory. They are called statserv.h and backend.h. They
+  will include other files from the include directory, so you'll
+  probably want to use the -I option of your compiler to tell it where
+  to find the files. When you run make in the toplevel YAZ directory,
+  everything you need to create your server is put the lib/libyaz.a
+  library. If you want OSI as well, you'll also need to link in the
+  libmosi.a library from the xtimosi distribution (see the mosi.txt
+  file), a well as the lib/librfc.a library (to provide OSI transport
+  over RFC1006/TCP).
+
+
+
+  7.4.  Your main() Routine
+
+  As mentioned, your main() routine can be quite brief. If you want to
+  initialize global parameters, or read global configuration tables,
+  this is the place to do it. At the end of the routine, you should call
+  the function
+
+
+
+       int statserv_main(int argc, char **argv);
+
+
+
+
+  Statserv_main will establish listening sockets according to the
+  parameters given. When connection requests are received, the event
+  handler will typically fork() to handle the new request. If you do use
+  global variables, you should be aware, then, that these cannot be
+  shared between associations, unless you explicitly disallow forking by
+  command line parameters (we advise against this for any purposes
+  except debugging, as a crash or hang in the server process will affect
+  all users currently signed on to the server).
+
+  The server provides a mechanism for controlling some of its behavior
+  without using command-line options. The function
+
+
+
+       statserv_options_block *statserv_getcontrol(void);
+
+
+
+
+  Will return a pointer to a struct statserv_options_block describing
+  the current default settings of the server. The structure contains
+  these elements:
+
+
+     int dynamic
+        A boolean value, which determines whether the server will fork
+        on each incoming request (TRUE), or not (FALSE). Default is
+        TRUE.
+
+     int loglevel
+        Set this by ORing the constants defined in include/log.h.
+
+     char logfile[ODR_MAXNAME+1]
+        File for diagnostic output ("": stderr).
+
+     char apdufile[ODR_MAXNAME+1]
+        Name of file for logging incoming and outgoing APDUs ("": don't
+        log APDUs, "-": stderr).
+
+     char default_listen[1024]
+        Same form as the command-line specification of listener address.
+        "": no default listener address.  Default is to listen at
+        "tcp:@:9999". You can only specify one default listener address
+        in this fashion.
+
+     enum oid_proto default_proto;
+        Either PROTO_SR or PROTO_Z3950.  Default is PROTO_Z39_50.
+
+     int idle_timeout;
+        Maximum session idletime, in minutes. Zero indicates no
+        (infinite) timeout. Default is 120 minutes.
+
+     int maxrecordsize;
+        Maximum permissible record (message) size. Default is 1Mb. This
+        amount of memory will only be allocated if a client requests a
+        very large amount of records in one operation (or a big record).
+        Set it to a lower number if you are worried about resource
+        consumption on your host system.
+
+     char configname[ODR_MAXNAME+1]
+        Passed to the backend when a new connection is received.
+
+     char setuid[ODR_MAXNAME+1]
+        Set user id to the user specified, after binding the listener
+        addresses.
+
+  The pointer returned by statserv_getcontrol points to a static area.
+  You are allowed to change the contents of the structure, but the
+  changes will not take effect before you call
+
+
+
+       void statserv_setcontrol(statserv_options_block *block);
+
+
+
+
+  Note that you should generally update this structure before calling
+  statserv_main().
+
+
+  7.5.  The Backend Functions
+
+  For each service of the protocol, the backend interface declares one
+  or two functions. You are required to provide implementations of the
+  functions representing the services that you wish to implement.
+
+
+
+       bend_initresult *bend_init(bend_initrequest *r);
+
+
+
+
+  This function is called once for each new connection request, after a
+  new process has been forked, and an initRequest has been received from
+  the client. The parameter and result structures are defined as
+
+
+
+       typedef struct bend_initrequest
+       {
+           char *configname;
+       } bend_initrequest;
+
+       typedef struct bend_initresult
+       {
+           int errcode;       /* 0==OK */
+           char *errstring;   /* system error string or NULL */
+           void *handle;      /* private handle to the backend module */
+       } bend_initresult;
+
+
+
+
+  The configname of bend_initrequest is currently always set to
+  "default-config". We haven't had use for putting anything special in
+  the initrequest yet, but something might go there if the need arises
+  (account/password info would be obvious).
+
+  In general, the server frontend expects that the bend_*result pointer
+  that you return is valid at least until the next call to a bend_*
+  function. This applies to all of the functions described herein. The
+  parameter structure passed to you in the call belongs to the server
+  frontend, and you should not make assumptions about its contents after
+  the current function call has completed. In other words, if you want
+  to retain any of the contents of a request structure, you should copy
+  them.
+
+  The errcode should be zero if the initialization of the backend went
+  well. Any other value will be interpreted as an error. The errstring
+  isn't used in the current version, but one option would be to stick it
+  in the initResponse as a VisibleString. The handle is the most
+  important parameter. It should be set to some value that uniquely
+  identifies the current session to the backend implementation. It is
+  used by the frontend server in any future calls to a backend function.
+  The typical use is to set it to point to a dynamically allocated state
+  structure that is private to your backend module.
+
+
+
+       bend_searchresult *bend_search(void *handle, bend_searchrequest *r,
+                                      int *fd);
+       bend_searchresult *bend_searchresponse(void *handle);
+
+       typedef struct bend_searchrequest
+       {
+           char *setname;       /* name to give to this set */
+           int replace_set;     /* replace set, if it already exists */
+           int num_bases;       /* number of databases in list */
+           char **basenames;    /* databases to search */
+           Z_Query *query;      /* query structure */
+       } bend_searchrequest;
+
+       typedef struct bend_searchresult
+       {
+           int hits;            /* number of hits */
+           int errcode;         /* 0==OK */
+           char *errstring;     /* system error string or NULL */
+       } bend_searchresult;
+
+
+
+
+  The first thing to notice about the search request interface (as well
+  as all of the following requests), is that it consists of two separate
+  functions. The idea is to provide a simple facility for asynchronous
+  communication with the backend server. When a searchrequest comes in,
+  the server frontend will fill out the bend_searchrequest tructure, and
+  call the bend_search function. The fd argument will point to an
+  integer variable. If you are able to do asynchronous I/O with your
+  database server, you should set *fd to the file descriptor you use for
+  the communication, and return a null pointer. The server frontend will
+  then select() on the *fd, and will call bend_searchresult when it sees
+  that data is available. If you don't support asynchronous I/O, you
+  should return a pointer to the bend_searchresult immediately, and
+  leave *fd untouched. This construction is common to all of the bend_
+  functions (except bend_init). Note that you can choose to support this
+  facility in none, any, or all of the bend_ functions, and you can
+  respond differently on each request at run-time. The server frontend
+  will adapt accordingly.
+
+  The bend_searchrequest is a fairly close approximation of a protocol
+  searchRequest PDU. The setname is the resultSetName from the protocol.
+  You are required to establish a mapping between the set name and
+  whatever your backend database likes to use. Similarly, the
+  replace_set is a boolean value corresponding to the resultSetIndicator
+  field in the protocol. Num_bases/basenames is a length of/array of
+  character pointers to the database names provided by the client. The
+  query is the full query structure as defined in the protocol ASN.1
+  specification.  It can be either of the possible query types, and it's
+  up to you to determine if you can handle the provided query type.
+  Rather than reproduce the C interface here, we'll refer you to the
+  structure definitions in the file include/proto.h. If you want to look
+  at the attributeSetId OID of the RPN query, you can either match it
+  against your own internal tables, or you can use the oid_getentbyoid
+  function provided by YAZ.
+
+  The result structure contains a number of hits, and an
+  errcode/errstring pair. If an error occurs during the search, or if
+  you're unhappy with the request, you should set the errcode to a value
+  from the BIB-1 diagnostic set. The value will then be returned to the
+  user in a nonsurrogate diagnostic record in the response. The
+  errstring, if provided, will go in the addinfo field. Look at the
+  protocol definition for the defined error codes, and the suggested
+  uses of the addinfo field.
+
+
+
+       bend_fetchresult *bend_fetch(void *handle, bend_fetchrequest *r,
+                                    int *fd);
+       bend_fetchresult *bend_fetchresponse(void *handle);
+
+       typedef struct bend_fetchrequest
+       {
+           char *setname;       /* set name */
+           int number;          /* record number */
+           oid_value format;
+       } bend_fetchrequest;
+
+       typedef struct bend_fetchresult
+       {
+           char *basename;      /* name of database that provided record */
+           int len;             /* length of record */
+           char *record;        /* record */
+           int last_in_set;     /* is it?  */
+           oid_value format;
+           int errcode;         /* 0==success */
+           char *errstring;     /* system error string or NULL */
+       } bend_fetchresult;
+
+
+
+
+  NOTE: The bend_fetchresponse() function is not yet supported in this
+  version of the software. Your implementation of bend_fetch() should
+  always return a pointer to a bend_fetchresult.
+
+  The frontend server calls bend_fetch when it needs database records to
+  fulfill a searchRequest or a presentRequest. The setname is simply the
+  name of the result set that holds the reference to the desired record.
+  The number is the offset into the set (with 1 being the first record
+  in the set). The format field is the record format requested by the
+  client (See section ``Object Identifiers''). The value VAL_NONE
+  indicates that the client did not request a specific format.  The
+  stream argument is an ODR stream which should be used for allocating
+  space for structured data records. The stream will be reset when all
+  records have been assembled, and the response package has been
+  transmitted.  For unstructured data, the backend is responsible for
+  maintaining a static or dynamic buffer for the record between calls.
+  In the result structure, the basename is the name of the database that
+  holds the record. Len is the length of the record returned, in bytes,
+  and record is a pointer to the record. Last_in_set should be nonzero
+  only if the record returned is the last one in the given result set.
+  Errcode and errstring, if given, will currently be interpreted as a
+  global error pertaining to the set, and will be returned in a
+  nonSurrogateDiagnostic.
+
+  NOTE: This is silly. Add a flag to say which is which.
+
+  If the len field has the value -1, then record is assumed to point to
+  a constructed data type. The format field will be used to determine
+  which encoder should be used to serialize the data.
+
+  NOTE: If your backend generates structured records, it should use
+  odr_malloc() on the provided stream for allocating data: This allows
+  the frontend server to keep track of the record sizes.
+
+  The format field is mapped to an object identifier in the direct
+  reference of the resulting EXTERNAL representation of the record.
+
+  NOTE: The current version of YAZ only supports the direct reference
+  mode.
+
+
+
+       bend_deleteresult *bend_delete(void *handle, bend_deleterequest *r,
+                                      int *fd);
+       bend_deleteresult *bend_deleteresponse(void *handle);
+
+       typedef struct bend_deleterequest
+       {
+           char *setname;
+       } bend_deleterequest;
+
+       typedef struct bend_deleteresult
+       {
+           int errcode;         /* 0==success */
+           char *errstring;     /* system error string or NULL */
+       } bend_deleteresult;
+
+
+
+
+  NOTE: The "delete" function is not yet supported in this version of
+  the software.
+
+  NOTE: The delete set function definition is rather primitive, mostly
+  because we have had no practical need for it as of yet. If someone
+  wants to provide a full delete service, we'd be happy to add the extra
+  parameters that are required. Are there clients out there that will
+  actually delete sets they no longer need?
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+  bend_scanresult *bend_scan(void *handle, bend_scanrequest *r,
+      int *fd);
+  bend_scanresult *bend_scanresponse(void *handle);
+
+  typedef struct bend_scanrequest
+  {
+      int num_bases;      /* number of elements in databaselist */
+      char **basenames;   /* databases to search */
+      Z_AttributesPlusTerm *term;
+      int term_position;  /* desired index of term in result list */
+      int num_entries;    /* number of entries requested */
+  } bend_scanrequest;
+
+  typedef struct bend_scanresult
+  {
+      int num_entries;
+      struct scan_entry
+      {
+          char *term;
+          int occurrences;
+      } *entries;
+      int term_position;
+      enum
+      {
+          BEND_SCAN_SUCCESS,
+          BEND_SCAN_PARTIAL
+      } status;
+      int errcode;
+      char *errstring;
+  } bend_scanresult;
+
+
+
+
+  NOTE: The bend_scanresponse() function is not yet supported in this
+  version of the software. Your implementation of bend_scan() should
+  always return a pointer to a bend_scanresult.
+
+
+  7.6.  Application Invocation
+
+  The finished application has the following invocation syntax (by way
+  of statserv_main()):
+
+
+
+
+       appname [-szSu -a apdufile -l logfile -v loglevel]
+       [listener ...]
+
+
+
+
+  The options are
+
+
+     -a APDU file. Specify a file for dumping PDUs (for diagnostic
+        purposes).  The special name "-" sends output to stderr.
+
+
+     -S Don't fork on connection requests. This is good for debugging,
+        but not recommended for real operation: Although the server is
+        asynchronous and non-blocking, it can be nice to keep a software
+        malfunction (okay then, a crash) from affecting all current
+        users.
+
+     -s Use the SR protocol.
+
+
+     -z Use the Z39.50 protocol (default). These two options complement
+        eachother. You can use both multiple times on the same command
+        line, between listener-specifications (see below). This way, you
+        can set up the server to listen for connections in both
+        protocols concurrently, on different local ports.
+
+
+     -l The logfile.
+
+
+     -v The log level. Use a comma-separated list of members of the set
+        {fatal,debug,warn,log,all,none}.
+
+     -u Set user ID. Sets the real UID of the server process to that of
+        the given user. It's useful if you aren't comfortable with
+        having the server run as root, but you need to start it as such
+        to bind a privileged port.
+
+
+     -w Working directory.
+
+     -i Use this when running from the inetd server.
+
+
+     -t Idle session timeout, in minutes.
+
+
+     -k Maximum record size/message size, in kilobytes.
+
+
+  A listener specification consists of a transport mode followed by a
+  colon (:) followed by a listener address. The transport mode is either
+  osi or tcp.
+
+  For TCP, an address has the form
+
+
+
+       hostname | IP-number [: portnumber]
+
+
+
+
+  The port number defaults to 210 (standard Z39.50 port).
+
+  For osi, the address form is
+
+
+
+       [t-selector /] hostname | IP-number [: portnumber]
+
+
+
+
+  The transport selector is given as a string of hex digits (with an
+  even number of digits). The default port number is 102 (RFC1006 port).
+
+  Examples
+
+
+
+
+
+  tcp:dranet.dra.com
+
+  osi:0402/dbserver.osiworld.com:3000
+
+
+
+
+  In both cases, the special hostname "@" is mapped to the address
+  INADDR_ANY, which causes the server to listen on any local interface.
+  To start the server listening on the registered ports for Z39.50 and
+  SR over OSI/RFC1006, and to drop root privileges once the ports are
+  bound, execute the server like this (from a root shell):
+
+
+
+       my-server -u daemon tcp:@ -s osi:@
+
+
+
+
+  You can replace daemon with another user, eg. your own account, or a
+  dedicated IR server account. my-server should be the name of your
+  server application. You can test the procedure with the ztest
+  application.
+
+
+  7.7.  Summary and Synopsis
+
+
+
+       #include <backend.h>
+
+       bend_initresult *bend_init(bend_initrequest *r);
+
+       bend_searchresult *bend_search(void *handle, bend_searchrequest *r,
+                                        int *fd);
+
+       bend_searchresult *bend_searchresponse(void *handle);
+
+       bend_fetchresult *bend_fetch(void *handle, bend_fetchrequest *r,
+                                      int *fd);
+
+       bend_fetchresult *bend_fetchresponse(void *handle);
+
+       bend_scanresult *bend_scan(void *handle, bend_scanrequest *r, int *fd);
+
+       bend_scanresult *bend_scanresponse(void *handle);
+
+       bend_deleteresult *bend_delete(void *handle, bend_deleterequest *r,
+                                         int *fd);
+
+       bend_deleteresult *bend_deleteresponse(void *handle);
+
+       void bend_close(void *handle);
+
+
+
+
+
+  8.  Future Directions
+
+  The software has been successfully ported to the Mac as well as
+  Windows NT/95 - we'd like to test those ports better and make sure
+  they work as they should.
+
+
+  We have a new and better version of the frontend server on the drawing
+  board. Resources and external commitments will govern when we'll be
+  able to do something real with it. Fetures should include greater
+  flexibility, greter support for access/resource control, and easy
+  support for Explain (possibly with Zebra as an extra database engine).
+
+  We now support all PDUs of Z39.50-1995. If there is one of the
+  supporting structures that you need but can't find in the prt*.h
+  files, send us a note; it may be on its way.
+
+  The 'retrieval' module needs to be finalized and documented. We think
+  it can form a useful resource for people dealing with complex record
+  structures, but for now, you'll mostly have to chew through the code
+  yourself to make use of it. Not acceptable.
+
+  Other than that, YAZ generally moves in the directions which appear to
+  make the most people happy (including ourselves, as prime users of the
+  software). If there's something you'd like to see in here, then drop
+  us a note and let's see what we can come up with.
+
+
+  9.  License
+
+  9.1.  Index Data Copyright
+
+  Copyright (C) 1995-2000 Index Data.
+
+  Permission to use, copy, modify, distribute, and sell this software
+  and its documentation, in whole or in part, for any purpose, is hereby
+  granted, provided that:
+
+  1. This copyright and permission notice appear in all copies of the
+  software and its documentation. Notices of copyright or attribution
+  which appear at the beginning of any file must remain unchanged.
+
+  2. The names of Index Data or the individual authors may not be used
+  to endorse or promote products derived from this software without
+  specific prior written permission.
+
+  THIS SOFTWARE IS PROVIDED "AS IS" AND WITHOUT WARRANTY OF ANY KIND,
+  EXPRESS, IMPLIED, OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY
+  WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.  IN
+  NO EVENT SHALL INDEX DATA BE LIABLE FOR ANY SPECIAL, INCIDENTAL,
+  INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND, OR ANY DAMAGES
+  WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER OR NOT
+  ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF LIABILITY,
+  ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
+  SOFTWARE.
+
+
+  9.2.  Additional Copyright Statements
+
+  The optional CCL query language interpreter is covered by the
+  following license:
+
+  Copyright (C) 1995, the EUROPAGATE consortium (see below).
+
+  The EUROPAGATE consortium members are:
+
+  University College Dublin Danmarks Teknologiske Videnscenter An
+  Chomhairle Leabharlanna Consejo Superior de Investigaciones
+  Cientificas
+
+  Permission to use, copy, modify, distribute, and sell this software
+  and its documentation, in whole or in part, for any purpose, is hereby
+  granted, provided that:
+  1. This copyright and permission notice appear in all copies of the
+  software and its documentation. Notices of copyright or attribution
+  which appear at the beginning of any file must remain unchanged.
+
+  2. The names of EUROPAGATE or the project partners may not be used to
+  endorse or promote products derived from this software without
+  specific prior written permission.
+
+  3. Users of this software (implementors and gateway operators) agree
+  to inform the EUROPAGATE consortium of their use of the software. This
+  information will be used to evaluate the EUROPAGATE project and the
+  software, and to plan further developments. The consortium may use the
+  information in later publications.
+
+  4. Users of this software agree to make their best efforts, when
+  documenting their use of the software, to acknowledge the EUROPAGATE
+  consortium, and the role played by the software in their work.
+
+  THIS SOFTWARE IS PROVIDED "AS IS" AND WITHOUT WARRANTY OF ANY KIND,
+  EXPRESS, IMPLIED, OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY
+  WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.  IN
+  NO EVENT SHALL THE EUROPAGATE CONSORTIUM OR ITS MEMBERS BE LIABLE FOR
+  ANY SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY
+  KIND, OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
+  PROFITS, WHETHER OR NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON
+  ANY THEORY OF LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE
+  OR PERFORMANCE OF THIS SOFTWARE.
+
+
+  10.  About Index Data
+
+  Index Data is a consulting and software-development enterprise that
+  specialises in library and information management systems. Our
+  interests and expertise span a broad range of related fields, and one
+  of our primary, long-term objectives is the development of a powerful
+  information management system with open network interfaces and
+  hypermedia capabilities.
+
+  We make this software available free of charge, on a fairly
+  unrestrictive license; as a service to the networking community, and
+  to further the development of quality software for open network
+  communication.
+
+  We'll be happy to answer questions about the software, and about
+  ourselves in general.
+
+
+
+       Index Data
+       Ryesgade 3
+       DK-2200 Copenhagen N
+
+
+
+
+
+
+
+       Phone: +45 3536 3672
+       Fax  : +45 3536 0449
+       Email: info@indexdata.dk
+
+
+
+
+
+  The Hacker's Jargon File has the following to say about the use of the
+  prefix "YA" in the name of a software product.
+
+  Yet Another. adj. 1. Of your own work: A humorous allusion often used
+  in titles to acknowledge that the topic is not original, though the
+  content is.  As in "Yet Another AI Group" or "Yet Another Simulated
+  Annealing Algorithm".  2. Of others' work: Describes something of
+  which there are already far too many.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
Index: /main/tags/2.25/gsdl/packages/yaz/ill/Makefile.am
===================================================================
--- /main/tags/2.25/gsdl/packages/yaz/ill/Makefile.am	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/yaz/ill/Makefile.am	(revision 21064)
@@ -0,0 +1,15 @@
+## $Id$
+
+INCLUDES=-I../include
+
+EXTRA_DIST=ill9702.asn item-req.asn ill.tcl
+
+noinst_LIBRARIES=libill.a
+
+libill_a_SOURCES=ill-core.c item-req.c ill-get.c
+
+ill-core.c ../include/yaz/ill-core.h: ill.tcl ill9702.asn ../util/yaz-comp
+	../util/yaz-comp -d ill.tcl -i yaz -I ../include $(YCFLAGS) ill9702.asn
+
+item-req.c ../include/yaz/item-req.h: ill.tcl item-req.asn ../util/yaz-comp
+	../util/yaz-comp -d ill.tcl -i yaz -I ../include $(YCFLAGS) item-req.asn
Index: /main/tags/2.25/gsdl/packages/yaz/ill/Makefile.in
===================================================================
--- /main/tags/2.25/gsdl/packages/yaz/ill/Makefile.in	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/yaz/ill/Makefile.in	(revision 21064)
@@ -0,0 +1,274 @@
+# Makefile.in generated automatically by automake 1.4 from Makefile.am
+
+# Copyright (C) 1994, 1995-8, 1999 Free Software Foundation, Inc.
+# This Makefile.in is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
+# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE.
+
+
+SHELL = @SHELL@
+
+srcdir = @srcdir@
+top_srcdir = @top_srcdir@
+VPATH = @srcdir@
+prefix = @prefix@
+exec_prefix = @exec_prefix@
+
+bindir = @bindir@
+sbindir = @sbindir@
+libexecdir = @libexecdir@
+datadir = @datadir@
+sysconfdir = @sysconfdir@
+sharedstatedir = @sharedstatedir@
+localstatedir = @localstatedir@
+libdir = @libdir@
+infodir = @infodir@
+mandir = @mandir@
+includedir = @includedir@
+oldincludedir = /usr/include
+
+DESTDIR =
+
+pkgdatadir = $(datadir)/@PACKAGE@
+pkglibdir = $(libdir)/@PACKAGE@
+pkgincludedir = $(includedir)/@PACKAGE@
+
+top_builddir = ..
+
+ACLOCAL = @ACLOCAL@
+AUTOCONF = @AUTOCONF@
+AUTOMAKE = @AUTOMAKE@
+AUTOHEADER = @AUTOHEADER@
+
+INSTALL = @INSTALL@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@ $(AM_INSTALL_PROGRAM_FLAGS)
+INSTALL_DATA = @INSTALL_DATA@
+INSTALL_SCRIPT = @INSTALL_SCRIPT@
+transform = @program_transform_name@
+
+NORMAL_INSTALL = :
+PRE_INSTALL = :
+POST_INSTALL = :
+NORMAL_UNINSTALL = :
+PRE_UNINSTALL = :
+POST_UNINSTALL = :
+ASNMODULE = @ASNMODULE@
+CC = @CC@
+CPP = @CPP@
+ILLLIB = @ILLLIB@
+ILLMODULE = @ILLMODULE@
+MAKEINFO = @MAKEINFO@
+PACKAGE = @PACKAGE@
+RANLIB = @RANLIB@
+SUBDIRS_VAR = @SUBDIRS_VAR@
+VERSION = @VERSION@
+have_sgml2html = @have_sgml2html@
+have_sgml2latex = @have_sgml2latex@
+have_sgml2txt = @have_sgml2txt@
+
+INCLUDES = -I../include
+
+EXTRA_DIST = ill9702.asn item-req.asn ill.tcl
+
+noinst_LIBRARIES = libill.a
+
+libill_a_SOURCES = ill-core.c item-req.c ill-get.c
+mkinstalldirs = $(SHELL) $(top_srcdir)/mkinstalldirs
+CONFIG_CLEAN_FILES = 
+LIBRARIES =  $(noinst_LIBRARIES)
+
+
+DEFS = @DEFS@ -I. -I$(srcdir) 
+CPPFLAGS = @CPPFLAGS@
+LDFLAGS = @LDFLAGS@
+LIBS = @LIBS@
+libill_a_LIBADD = 
+libill_a_OBJECTS =  ill-core.o item-req.o ill-get.o
+AR = ar
+CFLAGS = @CFLAGS@
+COMPILE = $(CC) $(DEFS) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
+CCLD = $(CC)
+LINK = $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(LDFLAGS) -o $@
+DIST_COMMON =  Makefile.am Makefile.in
+
+
+DISTFILES = $(DIST_COMMON) $(SOURCES) $(HEADERS) $(TEXINFOS) $(EXTRA_DIST)
+
+TAR = gtar
+GZIP_ENV = --best
+SOURCES = $(libill_a_SOURCES)
+OBJECTS = $(libill_a_OBJECTS)
+
+all: all-redirect
+.SUFFIXES:
+.SUFFIXES: .S .c .o .s
+$(srcdir)/Makefile.in: Makefile.am $(top_srcdir)/configure.in $(ACLOCAL_M4) 
+	cd $(top_srcdir) && $(AUTOMAKE) --gnu --include-deps ill/Makefile
+
+Makefile: $(srcdir)/Makefile.in  $(top_builddir)/config.status
+	cd $(top_builddir) \
+	  && CONFIG_FILES=$(subdir)/$@ CONFIG_HEADERS= $(SHELL) ./config.status
+
+
+mostlyclean-noinstLIBRARIES:
+
+clean-noinstLIBRARIES:
+	-test -z "$(noinst_LIBRARIES)" || rm -f $(noinst_LIBRARIES)
+
+distclean-noinstLIBRARIES:
+
+maintainer-clean-noinstLIBRARIES:
+
+.c.o:
+	$(COMPILE) -c $<
+
+.s.o:
+	$(COMPILE) -c $<
+
+.S.o:
+	$(COMPILE) -c $<
+
+mostlyclean-compile:
+	-rm -f *.o core *.core
+
+clean-compile:
+
+distclean-compile:
+	-rm -f *.tab.c
+
+maintainer-clean-compile:
+
+libill.a: $(libill_a_OBJECTS) $(libill_a_DEPENDENCIES)
+	-rm -f libill.a
+	$(AR) cru libill.a $(libill_a_OBJECTS) $(libill_a_LIBADD)
+	$(RANLIB) libill.a
+
+tags: TAGS
+
+ID: $(HEADERS) $(SOURCES) $(LISP)
+	list='$(SOURCES) $(HEADERS)'; \
+	unique=`for i in $$list; do echo $$i; done | \
+	  awk '    { files[$$0] = 1; } \
+	       END { for (i in files) print i; }'`; \
+	here=`pwd` && cd $(srcdir) \
+	  && mkid -f$$here/ID $$unique $(LISP)
+
+TAGS:  $(HEADERS) $(SOURCES)  $(TAGS_DEPENDENCIES) $(LISP)
+	tags=; \
+	here=`pwd`; \
+	list='$(SOURCES) $(HEADERS)'; \
+	unique=`for i in $$list; do echo $$i; done | \
+	  awk '    { files[$$0] = 1; } \
+	       END { for (i in files) print i; }'`; \
+	test -z "$(ETAGS_ARGS)$$unique$(LISP)$$tags" \
+	  || (cd $(srcdir) && etags $(ETAGS_ARGS) $$tags  $$unique $(LISP) -o $$here/TAGS)
+
+mostlyclean-tags:
+
+clean-tags:
+
+distclean-tags:
+	-rm -f TAGS ID
+
+maintainer-clean-tags:
+
+distdir = $(top_builddir)/$(PACKAGE)-$(VERSION)/$(subdir)
+
+subdir = ill
+
+distdir: $(DISTFILES)
+	@for file in $(DISTFILES); do \
+	  d=$(srcdir); \
+	  if test -d $$d/$$file; then \
+	    cp -pr $$/$$file $(distdir)/$$file; \
+	  else \
+	    test -f $(distdir)/$$file \
+	    || ln $$d/$$file $(distdir)/$$file 2> /dev/null \
+	    || cp -p $$d/$$file $(distdir)/$$file || :; \
+	  fi; \
+	done
+
+info-am:
+info: info-am
+dvi-am:
+dvi: dvi-am
+check-am: all-am
+check: check-am
+installcheck-am:
+installcheck: installcheck-am
+install-exec-am:
+install-exec: install-exec-am
+
+install-data-am:
+install-data: install-data-am
+
+install-am: all-am
+	@$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
+install: install-am
+uninstall-am:
+uninstall: uninstall-am
+all-am: Makefile $(LIBRARIES)
+all-redirect: all-am
+install-strip:
+	$(MAKE) $(AM_MAKEFLAGS) AM_INSTALL_PROGRAM_FLAGS=-s install
+installdirs:
+
+
+mostlyclean-generic:
+
+clean-generic:
+
+distclean-generic:
+	-rm -f Makefile $(CONFIG_CLEAN_FILES)
+	-rm -f config.cache config.log stamp-h stamp-h[0-9]*
+
+maintainer-clean-generic:
+mostlyclean-am:  mostlyclean-noinstLIBRARIES mostlyclean-compile \
+		mostlyclean-tags mostlyclean-generic
+
+mostlyclean: mostlyclean-am
+
+clean-am:  clean-noinstLIBRARIES clean-compile clean-tags clean-generic \
+		mostlyclean-am
+
+clean: clean-am
+
+distclean-am:  distclean-noinstLIBRARIES distclean-compile \
+		distclean-tags distclean-generic clean-am
+
+distclean: distclean-am
+
+maintainer-clean-am:  maintainer-clean-noinstLIBRARIES \
+		maintainer-clean-compile maintainer-clean-tags \
+		maintainer-clean-generic distclean-am
+	@echo "This command is intended for maintainers to use;"
+	@echo "it deletes files that may require special tools to rebuild."
+
+maintainer-clean: maintainer-clean-am
+
+.PHONY: mostlyclean-noinstLIBRARIES distclean-noinstLIBRARIES \
+clean-noinstLIBRARIES maintainer-clean-noinstLIBRARIES \
+mostlyclean-compile distclean-compile clean-compile \
+maintainer-clean-compile tags mostlyclean-tags distclean-tags \
+clean-tags maintainer-clean-tags distdir info-am info dvi-am dvi check \
+check-am installcheck-am installcheck install-exec-am install-exec \
+install-data-am install-data install-am install uninstall-am uninstall \
+all-redirect all-am all installdirs mostlyclean-generic \
+distclean-generic clean-generic maintainer-clean-generic clean \
+mostlyclean distclean maintainer-clean
+
+
+ill-core.c ../include/yaz/ill-core.h: ill.tcl ill9702.asn ../util/yaz-comp
+	../util/yaz-comp -d ill.tcl -i yaz -I ../include $(YCFLAGS) ill9702.asn
+
+item-req.c ../include/yaz/item-req.h: ill.tcl item-req.asn ../util/yaz-comp
+	../util/yaz-comp -d ill.tcl -i yaz -I ../include $(YCFLAGS) item-req.asn
+
+# Tell versions [3.59,3.63) of GNU make to not export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:
Index: /main/tags/2.25/gsdl/packages/yaz/ill/ill-core.c
===================================================================
--- /main/tags/2.25/gsdl/packages/yaz/ill/ill-core.c	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/yaz/ill/ill-core.c	(revision 21064)
@@ -0,0 +1,1754 @@
+/* Generated automatically by the YAZ ASN.1 Compiler 0.3 */
+/* Module-C: ISO-10161-ILL-1 */
+
+#include <yaz/ill-core.h>
+
+int ill_APDU (ODR o, ILL_APDU **p, int opt, const char *name)
+{
+	static Odr_arm arm[] = {
+		{-1, -1, -1, ILL_APDU_ILL_Request,
+		 (Odr_fun) ill_Request, "ILL_Request"},
+		{-1, -1, -1, ILL_APDU_Forward_Notification,
+		 (Odr_fun) ill_Forward_Notification, "Forward_Notification"},
+		{-1, -1, -1, ILL_APDU_Shipped,
+		 (Odr_fun) ill_Shipped, "Shipped"},
+		{-1, -1, -1, ILL_APDU_ILL_Answer,
+		 (Odr_fun) ill_Answer, "ILL_Answer"},
+		{-1, -1, -1, ILL_APDU_Conditional_Reply,
+		 (Odr_fun) ill_Conditional_Reply, "Conditional_Reply"},
+		{-1, -1, -1, ILL_APDU_Cancel,
+		 (Odr_fun) ill_Cancel, "Cancel"},
+		{-1, -1, -1, ILL_APDU_Cancel_Reply,
+		 (Odr_fun) ill_Cancel_Reply, "Cancel_Reply"},
+		{-1, -1, -1, ILL_APDU_Received,
+		 (Odr_fun) ill_Received, "Received"},
+		{-1, -1, -1, ILL_APDU_Recall,
+		 (Odr_fun) ill_Recall, "Recall"},
+		{-1, -1, -1, ILL_APDU_Returned,
+		 (Odr_fun) ill_Returned, "Returned"},
+		{-1, -1, -1, ILL_APDU_Checked_In,
+		 (Odr_fun) ill_Checked_In, "Checked_In"},
+		{-1, -1, -1, ILL_APDU_Overdue,
+		 (Odr_fun) ill_Overdue, "Overdue"},
+		{-1, -1, -1, ILL_APDU_Renew,
+		 (Odr_fun) ill_Renew, "Renew"},
+		{-1, -1, -1, ILL_APDU_Renew_Answer,
+		 (Odr_fun) ill_Renew_Answer, "Renew_Answer"},
+		{-1, -1, -1, ILL_APDU_Lost,
+		 (Odr_fun) ill_Lost, "Lost"},
+		{-1, -1, -1, ILL_APDU_Damaged,
+		 (Odr_fun) ill_Damaged, "Damaged"},
+		{-1, -1, -1, ILL_APDU_Message,
+		 (Odr_fun) ill_Message, "Message"},
+		{-1, -1, -1, ILL_APDU_Status_Query,
+		 (Odr_fun) ill_Status_Query, "Status_Query"},
+		{-1, -1, -1, ILL_APDU_Status_Or_Error_Report,
+		 (Odr_fun) ill_Status_Or_Error_Report, "Status_Or_Error_Report"},
+		{-1, -1, -1, ILL_APDU_Expired,
+		 (Odr_fun) ill_Expired, "Expired"},
+		{-1, -1, -1, -1, (Odr_fun) 0, 0}
+	};
+	if (!odr_initmember(o, p, sizeof(**p)))
+		return opt && odr_ok(o);
+	if (odr_choice(o, arm, &(*p)->u, &(*p)->which, name))
+		return 1;
+	*p = 0;
+	return opt && odr_ok(o);
+}
+
+int ill_Request (ODR o, ILL_Request **p, int opt, const char *name)
+{
+	if (!odr_constructed_begin (o, p, ODR_APPLICATION, 1, name))
+		return opt && odr_ok(o);
+	if (o->direction == ODR_DECODE)
+		*p = odr_malloc (o, sizeof(**p));
+	if (!odr_sequence_begin (o, p, sizeof(**p), 0))
+	{
+		*p = 0;
+		return 0;
+	}
+	return
+		odr_implicit_tag (o, odr_integer,
+			&(*p)->protocol_version_num, ODR_CONTEXT, 0, 0, "protocol_version_num") &&
+		odr_implicit_tag (o, ill_Transaction_Id,
+			&(*p)->transaction_id, ODR_CONTEXT, 1, 0, "transaction_id") &&
+		odr_implicit_tag (o, ill_Service_Date_Time,
+			&(*p)->service_date_time, ODR_CONTEXT, 2, 0, "service_date_time") &&
+		odr_implicit_tag (o, ill_System_Id,
+			&(*p)->requester_id, ODR_CONTEXT, 3, 1, "requester_id") &&
+		odr_implicit_tag (o, ill_System_Id,
+			&(*p)->responder_id, ODR_CONTEXT, 4, 1, "responder_id") &&
+		odr_implicit_tag (o, ill_Transaction_Type,
+			&(*p)->transaction_type, ODR_CONTEXT, 5, 0, "transaction_type") &&
+		odr_implicit_tag (o, ill_Delivery_Address,
+			&(*p)->delivery_address, ODR_CONTEXT, 6, 1, "delivery_address") &&
+		ill_Delivery_Service(o, &(*p)->delivery_service, 1, "delivery_service") &&
+		odr_implicit_tag (o, ill_Delivery_Address,
+			&(*p)->billing_address, ODR_CONTEXT, 8, 1, "billing_address") &&
+		odr_implicit_settag (o, ODR_CONTEXT, 9) &&
+		odr_sequence_of(o, (Odr_fun) ill_Service_Type, &(*p)->iLL_service_type,
+		  &(*p)->num_iLL_service_type, "iLL_service_type") &&
+		odr_explicit_tag (o, odr_external,
+			&(*p)->responder_specific_service, ODR_CONTEXT, 10, 1, "responder_specific_service") &&
+		odr_implicit_tag (o, ill_Requester_Optional_Messages_Type,
+			&(*p)->requester_optional_messages, ODR_CONTEXT, 11, 0, "requester_optional_messages") &&
+		odr_implicit_tag (o, ill_Search_Type,
+			&(*p)->search_type, ODR_CONTEXT, 12, 1, "search_type") &&
+		odr_implicit_settag (o, ODR_CONTEXT, 13) &&
+		(odr_sequence_of(o, (Odr_fun) ill_Supply_Medium_Info_Type, &(*p)->supply_medium_info_type,
+		  &(*p)->num_supply_medium_info_type, "supply_medium_info_type") || odr_ok(o)) &&
+		odr_implicit_tag (o, ill_Place_On_Hold_Type,
+			&(*p)->place_on_hold, ODR_CONTEXT, 14, 0, "place_on_hold") &&
+		odr_implicit_tag (o, ill_Client_Id,
+			&(*p)->client_id, ODR_CONTEXT, 15, 1, "client_id") &&
+		odr_implicit_tag (o, ill_Item_Id,
+			&(*p)->item_id, ODR_CONTEXT, 16, 0, "item_id") &&
+		odr_implicit_tag (o, ill_Supplemental_Item_Description,
+			&(*p)->supplemental_item_description, ODR_CONTEXT, 17, 1, "supplemental_item_description") &&
+		odr_implicit_tag (o, ill_Cost_Info_Type,
+			&(*p)->cost_info_type, ODR_CONTEXT, 18, 1, "cost_info_type") &&
+		odr_explicit_tag (o, ill_String,
+			&(*p)->copyright_compliance, ODR_CONTEXT, 19, 1, "copyright_compliance") &&
+		odr_implicit_tag (o, ill_Third_Party_Info_Type,
+			&(*p)->third_party_info_type, ODR_CONTEXT, 20, 1, "third_party_info_type") &&
+		odr_implicit_tag (o, odr_bool,
+			&(*p)->retry_flag, ODR_CONTEXT, 21, 0, "retry_flag") &&
+		odr_implicit_tag (o, odr_bool,
+			&(*p)->forward_flag, ODR_CONTEXT, 22, 0, "forward_flag") &&
+		odr_explicit_tag (o, ill_String,
+			&(*p)->requester_note, ODR_CONTEXT, 46, 1, "requester_note") &&
+		odr_explicit_tag (o, ill_String,
+			&(*p)->forward_note, ODR_CONTEXT, 47, 1, "forward_note") &&
+		odr_implicit_settag (o, ODR_CONTEXT, 49) &&
+		(odr_sequence_of(o, (Odr_fun) ill_Extension, &(*p)->iLL_request_extensions,
+		  &(*p)->num_iLL_request_extensions, "iLL_request_extensions") || odr_ok(o)) &&
+		odr_sequence_end (o) &&
+		odr_constructed_end (o);
+}
+
+int ill_Forward_Notification (ODR o, ILL_Forward_Notification **p, int opt, const char *name)
+{
+	if (!odr_constructed_begin (o, p, ODR_APPLICATION, 2, name))
+		return opt && odr_ok(o);
+	if (o->direction == ODR_DECODE)
+		*p = odr_malloc (o, sizeof(**p));
+	if (!odr_sequence_begin (o, p, sizeof(**p), 0))
+	{
+		*p = 0;
+		return 0;
+	}
+	return
+		odr_implicit_tag (o, odr_integer,
+			&(*p)->protocol_version_num, ODR_CONTEXT, 0, 0, "protocol_version_num") &&
+		odr_implicit_tag (o, ill_Transaction_Id,
+			&(*p)->transaction_id, ODR_CONTEXT, 1, 0, "transaction_id") &&
+		odr_implicit_tag (o, ill_Service_Date_Time,
+			&(*p)->service_date_time, ODR_CONTEXT, 2, 0, "service_date_time") &&
+		odr_implicit_tag (o, ill_System_Id,
+			&(*p)->requester_id, ODR_CONTEXT, 3, 1, "requester_id") &&
+		odr_implicit_tag (o, ill_System_Id,
+			&(*p)->responder_id, ODR_CONTEXT, 4, 0, "responder_id") &&
+		odr_implicit_tag (o, ill_System_Address,
+			&(*p)->responder_address, ODR_CONTEXT, 24, 1, "responder_address") &&
+		odr_implicit_tag (o, ill_System_Id,
+			&(*p)->intermediary_id, ODR_CONTEXT, 25, 0, "intermediary_id") &&
+		odr_explicit_tag (o, ill_String,
+			&(*p)->notification_note, ODR_CONTEXT, 48, 1, "notification_note") &&
+		odr_implicit_settag (o, ODR_CONTEXT, 49) &&
+		(odr_sequence_of(o, (Odr_fun) ill_Extension, &(*p)->forward_notification_extensions,
+		  &(*p)->num_forward_notification_extensions, "forward_notification_extensions") || odr_ok(o)) &&
+		odr_sequence_end (o) &&
+		odr_constructed_end (o);
+}
+
+int ill_Shipped (ODR o, ILL_Shipped **p, int opt, const char *name)
+{
+	if (!odr_constructed_begin (o, p, ODR_APPLICATION, 3, name))
+		return opt && odr_ok(o);
+	if (o->direction == ODR_DECODE)
+		*p = odr_malloc (o, sizeof(**p));
+	if (!odr_sequence_begin (o, p, sizeof(**p), 0))
+	{
+		*p = 0;
+		return 0;
+	}
+	return
+		odr_implicit_tag (o, odr_integer,
+			&(*p)->protocol_version_num, ODR_CONTEXT, 0, 0, "protocol_version_num") &&
+		odr_implicit_tag (o, ill_Transaction_Id,
+			&(*p)->transaction_id, ODR_CONTEXT, 1, 0, "transaction_id") &&
+		odr_implicit_tag (o, ill_Service_Date_Time,
+			&(*p)->service_date_time, ODR_CONTEXT, 2, 0, "service_date_time") &&
+		odr_implicit_tag (o, ill_System_Id,
+			&(*p)->requester_id, ODR_CONTEXT, 3, 1, "requester_id") &&
+		odr_implicit_tag (o, ill_System_Id,
+			&(*p)->responder_id, ODR_CONTEXT, 4, 1, "responder_id") &&
+		odr_implicit_tag (o, ill_System_Address,
+			&(*p)->responder_address, ODR_CONTEXT, 24, 1, "responder_address") &&
+		odr_implicit_tag (o, ill_System_Id,
+			&(*p)->intermediary_id, ODR_CONTEXT, 25, 1, "intermediary_id") &&
+		odr_implicit_tag (o, ill_System_Id,
+			&(*p)->supplier_id, ODR_CONTEXT, 26, 1, "supplier_id") &&
+		odr_implicit_tag (o, ill_Client_Id,
+			&(*p)->client_id, ODR_CONTEXT, 15, 1, "client_id") &&
+		odr_implicit_tag (o, ill_Transaction_Type,
+			&(*p)->transaction_type, ODR_CONTEXT, 5, 0, "transaction_type") &&
+		odr_implicit_tag (o, ill_Supplemental_Item_Description,
+			&(*p)->supplemental_item_description, ODR_CONTEXT, 17, 1, "supplemental_item_description") &&
+		odr_implicit_tag (o, ill_Shipped_Service_Type,
+			&(*p)->shipped_service_type, ODR_CONTEXT, 27, 0, "shipped_service_type") &&
+		odr_implicit_tag (o, ill_Responder_Optional_Messages_Type,
+			&(*p)->responder_optional_messages, ODR_CONTEXT, 28, 1, "responder_optional_messages") &&
+		odr_implicit_tag (o, ill_Supply_Details,
+			&(*p)->supply_details, ODR_CONTEXT, 29, 0, "supply_details") &&
+		odr_implicit_tag (o, ill_Postal_Address,
+			&(*p)->return_to_address, ODR_CONTEXT, 30, 1, "return_to_address") &&
+		odr_explicit_tag (o, ill_String,
+			&(*p)->responder_note, ODR_CONTEXT, 46, 1, "responder_note") &&
+		odr_implicit_settag (o, ODR_CONTEXT, 49) &&
+		(odr_sequence_of(o, (Odr_fun) ill_Extension, &(*p)->shipped_extensions,
+		  &(*p)->num_shipped_extensions, "shipped_extensions") || odr_ok(o)) &&
+		odr_sequence_end (o) &&
+		odr_constructed_end (o);
+}
+
+int ill_Answer (ODR o, ILL_Answer **p, int opt, const char *name)
+{
+	static Odr_arm arm[] = {
+		{ODR_EXPLICIT, ODR_CONTEXT, 1, ILL_Answer_conditional_results,
+		(Odr_fun) ill_Conditional_Results, "conditional_results"},
+		{ODR_EXPLICIT, ODR_CONTEXT, 2, ILL_Answer_retry_results,
+		(Odr_fun) ill_Retry_Results, "retry_results"},
+		{ODR_EXPLICIT, ODR_CONTEXT, 3, ILL_Answer_unfilled_results,
+		(Odr_fun) ill_Unfilled_Results, "unfilled_results"},
+		{ODR_EXPLICIT, ODR_CONTEXT, 4, ILL_Answer_locations_results,
+		(Odr_fun) ill_Locations_Results, "locations_results"},
+		{ODR_EXPLICIT, ODR_CONTEXT, 5, ILL_Answer_will_supply_results,
+		(Odr_fun) ill_Will_Supply_Results, "will_supply_results"},
+		{ODR_EXPLICIT, ODR_CONTEXT, 6, ILL_Answer_hold_placed_results,
+		(Odr_fun) ill_Hold_Placed_Results, "hold_placed_results"},
+		{ODR_EXPLICIT, ODR_CONTEXT, 7, ILL_Answer_estimate_results,
+		(Odr_fun) ill_Estimate_Results, "estimate_results"},
+		{-1, -1, -1, -1, (Odr_fun) 0, 0}
+	};
+	if (!odr_constructed_begin (o, p, ODR_APPLICATION, 4, name))
+		return opt && odr_ok(o);
+	if (o->direction == ODR_DECODE)
+		*p = odr_malloc (o, sizeof(**p));
+	if (!odr_sequence_begin (o, p, sizeof(**p), 0))
+	{
+		*p = 0;
+		return 0;
+	}
+	return
+		odr_implicit_tag (o, odr_integer,
+			&(*p)->protocol_version_num, ODR_CONTEXT, 0, 0, "protocol_version_num") &&
+		odr_implicit_tag (o, ill_Transaction_Id,
+			&(*p)->transaction_id, ODR_CONTEXT, 1, 0, "transaction_id") &&
+		odr_implicit_tag (o, ill_Service_Date_Time,
+			&(*p)->service_date_time, ODR_CONTEXT, 2, 0, "service_date_time") &&
+		odr_implicit_tag (o, ill_System_Id,
+			&(*p)->requester_id, ODR_CONTEXT, 3, 1, "requester_id") &&
+		odr_implicit_tag (o, ill_System_Id,
+			&(*p)->responder_id, ODR_CONTEXT, 4, 1, "responder_id") &&
+		odr_implicit_tag (o, ill_Transaction_Results,
+			&(*p)->transaction_results, ODR_CONTEXT, 31, 0, "transaction_results") &&
+		((odr_constructed_begin (o, &(*p)->u, ODR_CONTEXT, 32, "results_explanation") &&
+		odr_choice (o, arm, &(*p)->u, &(*p)->which, 0) &&
+		odr_constructed_end (o)) || odr_ok(o)) &&
+		odr_explicit_tag (o, odr_external,
+			&(*p)->responder_specific_results, ODR_CONTEXT, 33, 1, "responder_specific_results") &&
+		odr_implicit_tag (o, ill_Supplemental_Item_Description,
+			&(*p)->supplemental_item_description, ODR_CONTEXT, 17, 1, "supplemental_item_description") &&
+		odr_implicit_tag (o, ill_Send_To_List_Type,
+			&(*p)->send_to_list, ODR_CONTEXT, 23, 1, "send_to_list") &&
+		odr_implicit_tag (o, ill_Already_Tried_List_Type,
+			&(*p)->already_tried_list, ODR_CONTEXT, 34, 1, "already_tried_list") &&
+		odr_implicit_tag (o, ill_Responder_Optional_Messages_Type,
+			&(*p)->responder_optional_messages, ODR_CONTEXT, 28, 1, "responder_optional_messages") &&
+		odr_explicit_tag (o, ill_String,
+			&(*p)->responder_note, ODR_CONTEXT, 46, 1, "responder_note") &&
+		odr_implicit_settag (o, ODR_CONTEXT, 49) &&
+		(odr_sequence_of(o, (Odr_fun) ill_Extension, &(*p)->ill_answer_extensions,
+		  &(*p)->num_ill_answer_extensions, "ill_answer_extensions") || odr_ok(o)) &&
+		odr_sequence_end (o) &&
+		odr_constructed_end (o);
+}
+
+int ill_Conditional_Reply (ODR o, ILL_Conditional_Reply **p, int opt, const char *name)
+{
+	if (!odr_constructed_begin (o, p, ODR_APPLICATION, 5, name))
+		return opt && odr_ok(o);
+	if (o->direction == ODR_DECODE)
+		*p = odr_malloc (o, sizeof(**p));
+	if (!odr_sequence_begin (o, p, sizeof(**p), 0))
+	{
+		*p = 0;
+		return 0;
+	}
+	return
+		odr_implicit_tag (o, odr_integer,
+			&(*p)->protocol_version_num, ODR_CONTEXT, 0, 0, "protocol_version_num") &&
+		odr_implicit_tag (o, ill_Transaction_Id,
+			&(*p)->transaction_id, ODR_CONTEXT, 1, 0, "transaction_id") &&
+		odr_implicit_tag (o, ill_Service_Date_Time,
+			&(*p)->service_date_time, ODR_CONTEXT, 2, 0, "service_date_time") &&
+		odr_implicit_tag (o, ill_System_Id,
+			&(*p)->requester_id, ODR_CONTEXT, 3, 1, "requester_id") &&
+		odr_implicit_tag (o, ill_System_Id,
+			&(*p)->responder_id, ODR_CONTEXT, 4, 1, "responder_id") &&
+		odr_implicit_tag (o, odr_bool,
+			&(*p)->answer, ODR_CONTEXT, 35, 0, "answer") &&
+		odr_explicit_tag (o, ill_String,
+			&(*p)->requester_note, ODR_CONTEXT, 46, 1, "requester_note") &&
+		odr_implicit_settag (o, ODR_CONTEXT, 49) &&
+		(odr_sequence_of(o, (Odr_fun) ill_Extension, &(*p)->conditional_reply_extensions,
+		  &(*p)->num_conditional_reply_extensions, "conditional_reply_extensions") || odr_ok(o)) &&
+		odr_sequence_end (o) &&
+		odr_constructed_end (o);
+}
+
+int ill_Cancel (ODR o, ILL_Cancel **p, int opt, const char *name)
+{
+	if (!odr_constructed_begin (o, p, ODR_APPLICATION, 6, name))
+		return opt && odr_ok(o);
+	if (o->direction == ODR_DECODE)
+		*p = odr_malloc (o, sizeof(**p));
+	if (!odr_sequence_begin (o, p, sizeof(**p), 0))
+	{
+		*p = 0;
+		return 0;
+	}
+	return
+		odr_implicit_tag (o, odr_integer,
+			&(*p)->protocol_version_num, ODR_CONTEXT, 0, 0, "protocol_version_num") &&
+		odr_implicit_tag (o, ill_Transaction_Id,
+			&(*p)->transaction_id, ODR_CONTEXT, 1, 0, "transaction_id") &&
+		odr_implicit_tag (o, ill_Service_Date_Time,
+			&(*p)->service_date_time, ODR_CONTEXT, 2, 0, "service_date_time") &&
+		odr_implicit_tag (o, ill_System_Id,
+			&(*p)->requester_id, ODR_CONTEXT, 3, 1, "requester_id") &&
+		odr_implicit_tag (o, ill_System_Id,
+			&(*p)->responder_id, ODR_CONTEXT, 4, 1, "responder_id") &&
+		odr_explicit_tag (o, ill_String,
+			&(*p)->requester_note, ODR_CONTEXT, 46, 1, "requester_note") &&
+		odr_implicit_settag (o, ODR_CONTEXT, 49) &&
+		(odr_sequence_of(o, (Odr_fun) ill_Extension, &(*p)->cancel_extensions,
+		  &(*p)->num_cancel_extensions, "cancel_extensions") || odr_ok(o)) &&
+		odr_sequence_end (o) &&
+		odr_constructed_end (o);
+}
+
+int ill_Cancel_Reply (ODR o, ILL_Cancel_Reply **p, int opt, const char *name)
+{
+	if (!odr_constructed_begin (o, p, ODR_APPLICATION, 7, name))
+		return opt && odr_ok(o);
+	if (o->direction == ODR_DECODE)
+		*p = odr_malloc (o, sizeof(**p));
+	if (!odr_sequence_begin (o, p, sizeof(**p), 0))
+	{
+		*p = 0;
+		return 0;
+	}
+	return
+		odr_implicit_tag (o, odr_integer,
+			&(*p)->protocol_version_num, ODR_CONTEXT, 0, 0, "protocol_version_num") &&
+		odr_implicit_tag (o, ill_Transaction_Id,
+			&(*p)->transaction_id, ODR_CONTEXT, 1, 0, "transaction_id") &&
+		odr_implicit_tag (o, ill_Service_Date_Time,
+			&(*p)->service_date_time, ODR_CONTEXT, 2, 0, "service_date_time") &&
+		odr_implicit_tag (o, ill_System_Id,
+			&(*p)->requester_id, ODR_CONTEXT, 3, 1, "requester_id") &&
+		odr_implicit_tag (o, ill_System_Id,
+			&(*p)->responder_id, ODR_CONTEXT, 4, 1, "responder_id") &&
+		odr_implicit_tag (o, odr_bool,
+			&(*p)->answer, ODR_CONTEXT, 35, 0, "answer") &&
+		odr_explicit_tag (o, ill_String,
+			&(*p)->responder_note, ODR_CONTEXT, 46, 1, "responder_note") &&
+		odr_implicit_settag (o, ODR_CONTEXT, 49) &&
+		(odr_sequence_of(o, (Odr_fun) ill_Extension, &(*p)->cancel_reply_extensions,
+		  &(*p)->num_cancel_reply_extensions, "cancel_reply_extensions") || odr_ok(o)) &&
+		odr_sequence_end (o) &&
+		odr_constructed_end (o);
+}
+
+int ill_Received (ODR o, ILL_Received **p, int opt, const char *name)
+{
+	if (!odr_constructed_begin (o, p, ODR_APPLICATION, 8, name))
+		return opt && odr_ok(o);
+	if (o->direction == ODR_DECODE)
+		*p = odr_malloc (o, sizeof(**p));
+	if (!odr_sequence_begin (o, p, sizeof(**p), 0))
+	{
+		*p = 0;
+		return 0;
+	}
+	return
+		odr_implicit_tag (o, odr_integer,
+			&(*p)->protocol_version_num, ODR_CONTEXT, 0, 0, "protocol_version_num") &&
+		odr_implicit_tag (o, ill_Transaction_Id,
+			&(*p)->transaction_id, ODR_CONTEXT, 1, 0, "transaction_id") &&
+		odr_implicit_tag (o, ill_Service_Date_Time,
+			&(*p)->service_date_time, ODR_CONTEXT, 2, 0, "service_date_time") &&
+		odr_implicit_tag (o, ill_System_Id,
+			&(*p)->requester_id, ODR_CONTEXT, 3, 1, "requester_id") &&
+		odr_implicit_tag (o, ill_System_Id,
+			&(*p)->responder_id, ODR_CONTEXT, 4, 1, "responder_id") &&
+		odr_implicit_tag (o, ill_System_Id,
+			&(*p)->supplier_id, ODR_CONTEXT, 26, 1, "supplier_id") &&
+		odr_implicit_tag (o, ill_Supplemental_Item_Description,
+			&(*p)->supplemental_item_description, ODR_CONTEXT, 17, 1, "supplemental_item_description") &&
+		odr_implicit_tag (o, ill_ISO_Date,
+			&(*p)->date_received, ODR_CONTEXT, 36, 0, "date_received") &&
+		odr_implicit_tag (o, ill_Shipped_Service_Type,
+			&(*p)->shipped_service_type, ODR_CONTEXT, 27, 0, "shipped_service_type") &&
+		odr_explicit_tag (o, ill_String,
+			&(*p)->requester_note, ODR_CONTEXT, 46, 1, "requester_note") &&
+		odr_implicit_settag (o, ODR_CONTEXT, 49) &&
+		(odr_sequence_of(o, (Odr_fun) ill_Extension, &(*p)->received_extensions,
+		  &(*p)->num_received_extensions, "received_extensions") || odr_ok(o)) &&
+		odr_sequence_end (o) &&
+		odr_constructed_end (o);
+}
+
+int ill_Recall (ODR o, ILL_Recall **p, int opt, const char *name)
+{
+	if (!odr_constructed_begin (o, p, ODR_APPLICATION, 9, name))
+		return opt && odr_ok(o);
+	if (o->direction == ODR_DECODE)
+		*p = odr_malloc (o, sizeof(**p));
+	if (!odr_sequence_begin (o, p, sizeof(**p), 0))
+	{
+		*p = 0;
+		return 0;
+	}
+	return
+		odr_implicit_tag (o, odr_integer,
+			&(*p)->protocol_version_num, ODR_CONTEXT, 0, 0, "protocol_version_num") &&
+		odr_implicit_tag (o, ill_Transaction_Id,
+			&(*p)->transaction_id, ODR_CONTEXT, 1, 0, "transaction_id") &&
+		odr_implicit_tag (o, ill_Service_Date_Time,
+			&(*p)->service_date_time, ODR_CONTEXT, 2, 0, "service_date_time") &&
+		odr_implicit_tag (o, ill_System_Id,
+			&(*p)->requester_id, ODR_CONTEXT, 3, 1, "requester_id") &&
+		odr_implicit_tag (o, ill_System_Id,
+			&(*p)->responder_id, ODR_CONTEXT, 4, 1, "responder_id") &&
+		odr_explicit_tag (o, ill_String,
+			&(*p)->responder_note, ODR_CONTEXT, 46, 1, "responder_note") &&
+		odr_implicit_settag (o, ODR_CONTEXT, 49) &&
+		(odr_sequence_of(o, (Odr_fun) ill_Extension, &(*p)->recall_extensions,
+		  &(*p)->num_recall_extensions, "recall_extensions") || odr_ok(o)) &&
+		odr_sequence_end (o) &&
+		odr_constructed_end (o);
+}
+
+int ill_Returned (ODR o, ILL_Returned **p, int opt, const char *name)
+{
+	if (!odr_constructed_begin (o, p, ODR_APPLICATION, 10, name))
+		return opt && odr_ok(o);
+	if (o->direction == ODR_DECODE)
+		*p = odr_malloc (o, sizeof(**p));
+	if (!odr_sequence_begin (o, p, sizeof(**p), 0))
+	{
+		*p = 0;
+		return 0;
+	}
+	return
+		odr_implicit_tag (o, odr_integer,
+			&(*p)->protocol_version_num, ODR_CONTEXT, 0, 0, "protocol_version_num") &&
+		odr_implicit_tag (o, ill_Transaction_Id,
+			&(*p)->transaction_id, ODR_CONTEXT, 1, 0, "transaction_id") &&
+		odr_implicit_tag (o, ill_Service_Date_Time,
+			&(*p)->service_date_time, ODR_CONTEXT, 2, 0, "service_date_time") &&
+		odr_implicit_tag (o, ill_System_Id,
+			&(*p)->requester_id, ODR_CONTEXT, 3, 1, "requester_id") &&
+		odr_implicit_tag (o, ill_System_Id,
+			&(*p)->responder_id, ODR_CONTEXT, 4, 1, "responder_id") &&
+		odr_implicit_tag (o, ill_Supplemental_Item_Description,
+			&(*p)->supplemental_item_description, ODR_CONTEXT, 17, 1, "supplemental_item_description") &&
+		odr_implicit_tag (o, ill_ISO_Date,
+			&(*p)->date_returned, ODR_CONTEXT, 37, 0, "date_returned") &&
+		odr_explicit_tag (o, ill_Transportation_Mode,
+			&(*p)->returned_via, ODR_CONTEXT, 38, 1, "returned_via") &&
+		odr_implicit_tag (o, ill_Amount,
+			&(*p)->insured_for, ODR_CONTEXT, 39, 1, "insured_for") &&
+		odr_explicit_tag (o, ill_String,
+			&(*p)->requester_note, ODR_CONTEXT, 46, 1, "requester_note") &&
+		odr_implicit_settag (o, ODR_CONTEXT, 49) &&
+		(odr_sequence_of(o, (Odr_fun) ill_Extension, &(*p)->returned_extensions,
+		  &(*p)->num_returned_extensions, "returned_extensions") || odr_ok(o)) &&
+		odr_sequence_end (o) &&
+		odr_constructed_end (o);
+}
+
+int ill_Checked_In (ODR o, ILL_Checked_In **p, int opt, const char *name)
+{
+	if (!odr_constructed_begin (o, p, ODR_APPLICATION, 11, name))
+		return opt && odr_ok(o);
+	if (o->direction == ODR_DECODE)
+		*p = odr_malloc (o, sizeof(**p));
+	if (!odr_sequence_begin (o, p, sizeof(**p), 0))
+	{
+		*p = 0;
+		return 0;
+	}
+	return
+		odr_implicit_tag (o, odr_integer,
+			&(*p)->protocol_version_num, ODR_CONTEXT, 0, 0, "protocol_version_num") &&
+		odr_implicit_tag (o, ill_Transaction_Id,
+			&(*p)->transaction_id, ODR_CONTEXT, 1, 0, "transaction_id") &&
+		odr_implicit_tag (o, ill_Service_Date_Time,
+			&(*p)->service_date_time, ODR_CONTEXT, 2, 0, "service_date_time") &&
+		odr_implicit_tag (o, ill_System_Id,
+			&(*p)->requester_id, ODR_CONTEXT, 3, 1, "requester_id") &&
+		odr_implicit_tag (o, ill_System_Id,
+			&(*p)->responder_id, ODR_CONTEXT, 4, 1, "responder_id") &&
+		odr_implicit_tag (o, ill_ISO_Date,
+			&(*p)->date_checked_in, ODR_CONTEXT, 40, 0, "date_checked_in") &&
+		odr_explicit_tag (o, ill_String,
+			&(*p)->responder_note, ODR_CONTEXT, 46, 1, "responder_note") &&
+		odr_implicit_settag (o, ODR_CONTEXT, 49) &&
+		(odr_sequence_of(o, (Odr_fun) ill_Extension, &(*p)->checked_in_extensions,
+		  &(*p)->num_checked_in_extensions, "checked_in_extensions") || odr_ok(o)) &&
+		odr_sequence_end (o) &&
+		odr_constructed_end (o);
+}
+
+int ill_Overdue_Extension (ODR o, ILL_Overdue_Extension **p, int opt, const char *name)
+{
+	if (!odr_initmember (o, p, sizeof(**p)))
+		return opt && odr_ok(o);
+	if (odr_sequence_of (o, (Odr_fun) ill_Extension, &(*p)->elements,
+		&(*p)->num, name))
+		return 1;
+	*p = 0;
+	return opt && odr_ok(o);
+}
+
+int ill_Overdue (ODR o, ILL_Overdue **p, int opt, const char *name)
+{
+	if (!odr_constructed_begin (o, p, ODR_APPLICATION, 12, name))
+		return opt && odr_ok(o);
+	if (o->direction == ODR_DECODE)
+		*p = odr_malloc (o, sizeof(**p));
+	if (!odr_sequence_begin (o, p, sizeof(**p), 0))
+	{
+		*p = 0;
+		return 0;
+	}
+	return
+		odr_implicit_tag (o, odr_integer,
+			&(*p)->protocol_version_num, ODR_CONTEXT, 0, 0, "protocol_version_num") &&
+		odr_implicit_tag (o, ill_Transaction_Id,
+			&(*p)->transaction_id, ODR_CONTEXT, 1, 0, "transaction_id") &&
+		odr_implicit_tag (o, ill_Service_Date_Time,
+			&(*p)->service_date_time, ODR_CONTEXT, 2, 0, "service_date_time") &&
+		odr_implicit_tag (o, ill_System_Id,
+			&(*p)->requester_id, ODR_CONTEXT, 3, 1, "requester_id") &&
+		odr_implicit_tag (o, ill_System_Id,
+			&(*p)->responder_id, ODR_CONTEXT, 4, 1, "responder_id") &&
+		odr_implicit_tag (o, ill_Date_Due,
+			&(*p)->date_due, ODR_CONTEXT, 41, 0, "date_due") &&
+		odr_explicit_tag (o, ill_String,
+			&(*p)->responder_note, ODR_CONTEXT, 46, 1, "responder_note") &&
+		odr_explicit_tag (o, ill_Overdue_Extension,
+			&(*p)->overdue_extensions, ODR_CONTEXT, 49, 1, "overdue_extensions") &&
+		odr_sequence_end (o) &&
+		odr_constructed_end (o);
+}
+
+int ill_Renew (ODR o, ILL_Renew **p, int opt, const char *name)
+{
+	if (!odr_constructed_begin (o, p, ODR_APPLICATION, 13, name))
+		return opt && odr_ok(o);
+	if (o->direction == ODR_DECODE)
+		*p = odr_malloc (o, sizeof(**p));
+	if (!odr_sequence_begin (o, p, sizeof(**p), 0))
+	{
+		*p = 0;
+		return 0;
+	}
+	return
+		odr_implicit_tag (o, odr_integer,
+			&(*p)->protocol_version_num, ODR_CONTEXT, 0, 0, "protocol_version_num") &&
+		odr_implicit_tag (o, ill_Transaction_Id,
+			&(*p)->transaction_id, ODR_CONTEXT, 1, 0, "transaction_id") &&
+		odr_implicit_tag (o, ill_Service_Date_Time,
+			&(*p)->service_date_time, ODR_CONTEXT, 2, 0, "service_date_time") &&
+		odr_implicit_tag (o, ill_System_Id,
+			&(*p)->requester_id, ODR_CONTEXT, 3, 1, "requester_id") &&
+		odr_implicit_tag (o, ill_System_Id,
+			&(*p)->responder_id, ODR_CONTEXT, 4, 1, "responder_id") &&
+		odr_implicit_tag (o, ill_ISO_Date,
+			&(*p)->desired_due_date, ODR_CONTEXT, 42, 1, "desired_due_date") &&
+		odr_explicit_tag (o, ill_String,
+			&(*p)->requester_note, ODR_CONTEXT, 46, 1, "requester_note") &&
+		odr_implicit_settag (o, ODR_CONTEXT, 49) &&
+		(odr_sequence_of(o, (Odr_fun) ill_Extension, &(*p)->renew_extensions,
+		  &(*p)->num_renew_extensions, "renew_extensions") || odr_ok(o)) &&
+		odr_sequence_end (o) &&
+		odr_constructed_end (o);
+}
+
+int ill_Renew_Answer (ODR o, ILL_Renew_Answer **p, int opt, const char *name)
+{
+	if (!odr_constructed_begin (o, p, ODR_APPLICATION, 14, name))
+		return opt && odr_ok(o);
+	if (o->direction == ODR_DECODE)
+		*p = odr_malloc (o, sizeof(**p));
+	if (!odr_sequence_begin (o, p, sizeof(**p), 0))
+	{
+		*p = 0;
+		return 0;
+	}
+	return
+		odr_implicit_tag (o, odr_integer,
+			&(*p)->protocol_version_num, ODR_CONTEXT, 0, 0, "protocol_version_num") &&
+		odr_implicit_tag (o, ill_Transaction_Id,
+			&(*p)->transaction_id, ODR_CONTEXT, 1, 0, "transaction_id") &&
+		odr_implicit_tag (o, ill_Service_Date_Time,
+			&(*p)->service_date_time, ODR_CONTEXT, 2, 0, "service_date_time") &&
+		odr_implicit_tag (o, ill_System_Id,
+			&(*p)->requester_id, ODR_CONTEXT, 3, 1, "requester_id") &&
+		odr_implicit_tag (o, ill_System_Id,
+			&(*p)->responder_id, ODR_CONTEXT, 4, 1, "responder_id") &&
+		odr_implicit_tag (o, odr_bool,
+			&(*p)->answer, ODR_CONTEXT, 35, 0, "answer") &&
+		odr_implicit_tag (o, ill_Date_Due,
+			&(*p)->date_due, ODR_CONTEXT, 41, 1, "date_due") &&
+		odr_explicit_tag (o, ill_String,
+			&(*p)->responder_note, ODR_CONTEXT, 46, 1, "responder_note") &&
+		odr_implicit_settag (o, ODR_CONTEXT, 49) &&
+		(odr_sequence_of(o, (Odr_fun) ill_Extension, &(*p)->renew_answer_extensions,
+		  &(*p)->num_renew_answer_extensions, "renew_answer_extensions") || odr_ok(o)) &&
+		odr_sequence_end (o) &&
+		odr_constructed_end (o);
+}
+
+int ill_Lost (ODR o, ILL_Lost **p, int opt, const char *name)
+{
+	if (!odr_constructed_begin (o, p, ODR_APPLICATION, 15, name))
+		return opt && odr_ok(o);
+	if (o->direction == ODR_DECODE)
+		*p = odr_malloc (o, sizeof(**p));
+	if (!odr_sequence_begin (o, p, sizeof(**p), 0))
+	{
+		*p = 0;
+		return 0;
+	}
+	return
+		odr_implicit_tag (o, odr_integer,
+			&(*p)->protocol_version_num, ODR_CONTEXT, 0, 0, "protocol_version_num") &&
+		odr_implicit_tag (o, ill_Transaction_Id,
+			&(*p)->transaction_id, ODR_CONTEXT, 1, 0, "transaction_id") &&
+		odr_implicit_tag (o, ill_Service_Date_Time,
+			&(*p)->service_date_time, ODR_CONTEXT, 2, 0, "service_date_time") &&
+		odr_implicit_tag (o, ill_System_Id,
+			&(*p)->requester_id, ODR_CONTEXT, 3, 1, "requester_id") &&
+		odr_implicit_tag (o, ill_System_Id,
+			&(*p)->responder_id, ODR_CONTEXT, 4, 1, "responder_id") &&
+		odr_explicit_tag (o, ill_String,
+			&(*p)->note, ODR_CONTEXT, 46, 1, "note") &&
+		odr_implicit_settag (o, ODR_CONTEXT, 49) &&
+		(odr_sequence_of(o, (Odr_fun) ill_Extension, &(*p)->lost_extensions,
+		  &(*p)->num_lost_extensions, "lost_extensions") || odr_ok(o)) &&
+		odr_sequence_end (o) &&
+		odr_constructed_end (o);
+}
+
+int ill_Damaged (ODR o, ILL_Damaged **p, int opt, const char *name)
+{
+	if (!odr_constructed_begin (o, p, ODR_APPLICATION, 16, name))
+		return opt && odr_ok(o);
+	if (o->direction == ODR_DECODE)
+		*p = odr_malloc (o, sizeof(**p));
+	if (!odr_sequence_begin (o, p, sizeof(**p), 0))
+	{
+		*p = 0;
+		return 0;
+	}
+	return
+		odr_implicit_tag (o, odr_integer,
+			&(*p)->protocol_version_num, ODR_CONTEXT, 0, 0, "protocol_version_num") &&
+		odr_implicit_tag (o, ill_Transaction_Id,
+			&(*p)->transaction_id, ODR_CONTEXT, 1, 0, "transaction_id") &&
+		odr_implicit_tag (o, ill_Service_Date_Time,
+			&(*p)->service_date_time, ODR_CONTEXT, 2, 0, "service_date_time") &&
+		odr_implicit_tag (o, ill_System_Id,
+			&(*p)->requester_id, ODR_CONTEXT, 3, 1, "requester_id") &&
+		odr_implicit_tag (o, ill_System_Id,
+			&(*p)->responder_id, ODR_CONTEXT, 4, 1, "responder_id") &&
+		odr_implicit_tag (o, ill_Damaged_Details,
+			&(*p)->damaged_details, ODR_CONTEXT, 5, 1, "damaged_details") &&
+		odr_explicit_tag (o, ill_String,
+			&(*p)->note, ODR_CONTEXT, 46, 1, "note") &&
+		odr_implicit_settag (o, ODR_CONTEXT, 49) &&
+		(odr_sequence_of(o, (Odr_fun) ill_Extension, &(*p)->damaged_extensions,
+		  &(*p)->num_damaged_extensions, "damaged_extensions") || odr_ok(o)) &&
+		odr_sequence_end (o) &&
+		odr_constructed_end (o);
+}
+
+int ill_Message (ODR o, ILL_Message **p, int opt, const char *name)
+{
+	if (!odr_constructed_begin (o, p, ODR_APPLICATION, 17, name))
+		return opt && odr_ok(o);
+	if (o->direction == ODR_DECODE)
+		*p = odr_malloc (o, sizeof(**p));
+	if (!odr_sequence_begin (o, p, sizeof(**p), 0))
+	{
+		*p = 0;
+		return 0;
+	}
+	return
+		odr_implicit_tag (o, odr_integer,
+			&(*p)->protocol_version_num, ODR_CONTEXT, 0, 0, "protocol_version_num") &&
+		odr_implicit_tag (o, ill_Transaction_Id,
+			&(*p)->transaction_id, ODR_CONTEXT, 1, 0, "transaction_id") &&
+		odr_implicit_tag (o, ill_Service_Date_Time,
+			&(*p)->service_date_time, ODR_CONTEXT, 2, 0, "service_date_time") &&
+		odr_implicit_tag (o, ill_System_Id,
+			&(*p)->requester_id, ODR_CONTEXT, 3, 1, "requester_id") &&
+		odr_implicit_tag (o, ill_System_Id,
+			&(*p)->responder_id, ODR_CONTEXT, 4, 1, "responder_id") &&
+		odr_explicit_tag (o, ill_String,
+			&(*p)->note, ODR_CONTEXT, 46, 0, "note") &&
+		odr_implicit_settag (o, ODR_CONTEXT, 49) &&
+		(odr_sequence_of(o, (Odr_fun) ill_Extension, &(*p)->message_extensions,
+		  &(*p)->num_message_extensions, "message_extensions") || odr_ok(o)) &&
+		odr_sequence_end (o) &&
+		odr_constructed_end (o);
+}
+
+int ill_Status_Query (ODR o, ILL_Status_Query **p, int opt, const char *name)
+{
+	if (!odr_constructed_begin (o, p, ODR_APPLICATION, 18, name))
+		return opt && odr_ok(o);
+	if (o->direction == ODR_DECODE)
+		*p = odr_malloc (o, sizeof(**p));
+	if (!odr_sequence_begin (o, p, sizeof(**p), 0))
+	{
+		*p = 0;
+		return 0;
+	}
+	return
+		odr_implicit_tag (o, odr_integer,
+			&(*p)->protocol_version_num, ODR_CONTEXT, 0, 0, "protocol_version_num") &&
+		odr_implicit_tag (o, ill_Transaction_Id,
+			&(*p)->transaction_id, ODR_CONTEXT, 1, 0, "transaction_id") &&
+		odr_implicit_tag (o, ill_Service_Date_Time,
+			&(*p)->service_date_time, ODR_CONTEXT, 2, 0, "service_date_time") &&
+		odr_implicit_tag (o, ill_System_Id,
+			&(*p)->requester_id, ODR_CONTEXT, 3, 1, "requester_id") &&
+		odr_implicit_tag (o, ill_System_Id,
+			&(*p)->responder_id, ODR_CONTEXT, 4, 1, "responder_id") &&
+		odr_explicit_tag (o, ill_String,
+			&(*p)->note, ODR_CONTEXT, 46, 1, "note") &&
+		odr_implicit_settag (o, ODR_CONTEXT, 49) &&
+		(odr_sequence_of(o, (Odr_fun) ill_Extension, &(*p)->status_query_extensions,
+		  &(*p)->num_status_query_extensions, "status_query_extensions") || odr_ok(o)) &&
+		odr_sequence_end (o) &&
+		odr_constructed_end (o);
+}
+
+int ill_Status_Or_Error_Report (ODR o, ILL_Status_Or_Error_Report **p, int opt, const char *name)
+{
+	if (!odr_constructed_begin (o, p, ODR_APPLICATION, 19, name))
+		return opt && odr_ok(o);
+	if (o->direction == ODR_DECODE)
+		*p = odr_malloc (o, sizeof(**p));
+	if (!odr_sequence_begin (o, p, sizeof(**p), 0))
+	{
+		*p = 0;
+		return 0;
+	}
+	return
+		odr_implicit_tag (o, odr_integer,
+			&(*p)->protocol_version_num, ODR_CONTEXT, 0, 0, "protocol_version_num") &&
+		odr_implicit_tag (o, ill_Transaction_Id,
+			&(*p)->transaction_id, ODR_CONTEXT, 1, 0, "transaction_id") &&
+		odr_implicit_tag (o, ill_Service_Date_Time,
+			&(*p)->service_date_time, ODR_CONTEXT, 2, 0, "service_date_time") &&
+		odr_implicit_tag (o, ill_System_Id,
+			&(*p)->requester_id, ODR_CONTEXT, 3, 1, "requester_id") &&
+		odr_implicit_tag (o, ill_System_Id,
+			&(*p)->responder_id, ODR_CONTEXT, 4, 1, "responder_id") &&
+		odr_implicit_tag (o, ill_Reason_No_Report,
+			&(*p)->reason_no_report, ODR_CONTEXT, 43, 1, "reason_no_report") &&
+		odr_implicit_tag (o, ill_Status_Report,
+			&(*p)->status_report, ODR_CONTEXT, 44, 1, "status_report") &&
+		odr_implicit_tag (o, ill_Error_Report,
+			&(*p)->error_report, ODR_CONTEXT, 45, 1, "error_report") &&
+		odr_explicit_tag (o, ill_String,
+			&(*p)->note, ODR_CONTEXT, 46, 1, "note") &&
+		odr_implicit_settag (o, ODR_CONTEXT, 49) &&
+		(odr_sequence_of(o, (Odr_fun) ill_Extension, &(*p)->status_or_error_report_extensions,
+		  &(*p)->num_status_or_error_report_extensions, "status_or_error_report_extensions") || odr_ok(o)) &&
+		odr_sequence_end (o) &&
+		odr_constructed_end (o);
+}
+
+int ill_Expired (ODR o, ILL_Expired **p, int opt, const char *name)
+{
+	if (!odr_constructed_begin (o, p, ODR_APPLICATION, 20, name))
+		return opt && odr_ok(o);
+	if (o->direction == ODR_DECODE)
+		*p = odr_malloc (o, sizeof(**p));
+	if (!odr_sequence_begin (o, p, sizeof(**p), 0))
+	{
+		*p = 0;
+		return 0;
+	}
+	return
+		odr_implicit_tag (o, odr_integer,
+			&(*p)->protocol_version_num, ODR_CONTEXT, 0, 0, "protocol_version_num") &&
+		odr_implicit_tag (o, ill_Transaction_Id,
+			&(*p)->transaction_id, ODR_CONTEXT, 1, 0, "transaction_id") &&
+		odr_implicit_tag (o, ill_Service_Date_Time,
+			&(*p)->service_date_time, ODR_CONTEXT, 2, 0, "service_date_time") &&
+		odr_implicit_tag (o, ill_System_Id,
+			&(*p)->requester_id, ODR_CONTEXT, 3, 1, "requester_id") &&
+		odr_implicit_tag (o, ill_System_Id,
+			&(*p)->responder_id, ODR_CONTEXT, 4, 1, "responder_id") &&
+		odr_implicit_settag (o, ODR_CONTEXT, 49) &&
+		(odr_sequence_of(o, (Odr_fun) ill_Extension, &(*p)->expired_extensions,
+		  &(*p)->num_expired_extensions, "expired_extensions") || odr_ok(o)) &&
+		odr_sequence_end (o) &&
+		odr_constructed_end (o);
+}
+
+int ill_Account_Number (ODR o, ILL_Account_Number **p, int opt, const char *name)
+{
+	return ill_String (o, p, opt, name);
+}
+
+int ill_Already_Forwarded (ODR o, ILL_Already_Forwarded **p, int opt, const char *name)
+{
+	if (!odr_sequence_begin (o, p, sizeof(**p), name))
+		return opt && odr_ok (o);
+	return
+		odr_implicit_tag (o, ill_System_Id,
+			&(*p)->responder_id, ODR_CONTEXT, 0, 0, "responder_id") &&
+		odr_implicit_tag (o, ill_System_Address,
+			&(*p)->responder_address, ODR_CONTEXT, 1, 1, "responder_address") &&
+		odr_sequence_end (o);
+}
+
+int ill_Already_Tried_List_Type (ODR o, ILL_Already_Tried_List_Type **p, int opt, const char *name)
+{
+	if (!odr_initmember (o, p, sizeof(**p)))
+		return opt && odr_ok(o);
+	if (odr_sequence_of (o, (Odr_fun) ill_System_Id, &(*p)->elements,
+		&(*p)->num, name))
+		return 1;
+	*p = 0;
+	return opt && odr_ok(o);
+}
+
+int ill_Amount (ODR o, ILL_Amount **p, int opt, const char *name)
+{
+	if (!odr_sequence_begin (o, p, sizeof(**p), name))
+		return opt && odr_ok (o);
+	return
+		odr_implicit_tag (o, odr_visiblestring,
+			&(*p)->currency_code, ODR_CONTEXT, 0, 1, "currency_code") &&
+		odr_implicit_tag (o, ill_AmountString,
+			&(*p)->monetary_value, ODR_CONTEXT, 1, 0, "monetary_value") &&
+		odr_sequence_end (o);
+}
+
+int ill_AmountString (ODR o, ILL_AmountString **p, int opt, const char *name)
+{
+	return odr_visiblestring (o, p, opt, name);
+}
+
+int ill_Client_Id (ODR o, ILL_Client_Id **p, int opt, const char *name)
+{
+	if (!odr_sequence_begin (o, p, sizeof(**p), name))
+		return opt && odr_ok (o);
+	return
+		odr_explicit_tag (o, ill_String,
+			&(*p)->client_name, ODR_CONTEXT, 0, 1, "client_name") &&
+		odr_explicit_tag (o, ill_String,
+			&(*p)->client_status, ODR_CONTEXT, 1, 1, "client_status") &&
+		odr_explicit_tag (o, ill_String,
+			&(*p)->client_identifier, ODR_CONTEXT, 2, 1, "client_identifier") &&
+		odr_sequence_end (o);
+}
+
+int ill_Conditional_Results (ODR o, ILL_Conditional_Results **p, int opt, const char *name)
+{
+	if (!odr_sequence_begin (o, p, sizeof(**p), name))
+		return opt && odr_ok (o);
+	return
+		odr_implicit_tag (o, odr_enum,
+			&(*p)->conditions, ODR_CONTEXT, 0, 0, "conditions") &&
+		odr_implicit_tag (o, ill_ISO_Date,
+			&(*p)->date_for_reply, ODR_CONTEXT, 1, 1, "date_for_reply") &&
+		odr_implicit_settag (o, ODR_CONTEXT, 2) &&
+		(odr_sequence_of(o, (Odr_fun) ill_Location_Info, &(*p)->locations,
+		  &(*p)->num_locations, "locations") || odr_ok(o)) &&
+		ill_Delivery_Service(o, &(*p)->proposed_delivery_service, 1, "proposed_delivery_service") &&
+		odr_sequence_end (o);
+}
+
+int ill_Cost_Info_Type (ODR o, ILL_Cost_Info_Type **p, int opt, const char *name)
+{
+	if (!odr_sequence_begin (o, p, sizeof(**p), name))
+		return opt && odr_ok (o);
+	return
+		odr_explicit_tag (o, ill_Account_Number,
+			&(*p)->account_number, ODR_CONTEXT, 0, 1, "account_number") &&
+		odr_implicit_tag (o, ill_Amount,
+			&(*p)->maximum_cost, ODR_CONTEXT, 1, 1, "maximum_cost") &&
+		odr_implicit_tag (o, odr_bool,
+			&(*p)->reciprocal_agreement, ODR_CONTEXT, 2, 0, "reciprocal_agreement") &&
+		odr_implicit_tag (o, odr_bool,
+			&(*p)->will_pay_fee, ODR_CONTEXT, 3, 0, "will_pay_fee") &&
+		odr_implicit_tag (o, odr_bool,
+			&(*p)->payment_provided, ODR_CONTEXT, 4, 0, "payment_provided") &&
+		odr_sequence_end (o);
+}
+
+int ill_Current_State (ODR o, ILL_Current_State **p, int opt, const char *name)
+{
+	return odr_enum (o, p, opt, name);
+}
+
+int ill_Damaged_DetailsSpecific_units (ODR o, ILL_Damaged_DetailsSpecific_units **p, int opt, const char *name)
+{
+	if (!odr_initmember (o, p, sizeof(**p)))
+		return opt && odr_ok(o);
+	if (odr_sequence_of (o, (Odr_fun) odr_integer, &(*p)->elements,
+		&(*p)->num, name))
+		return 1;
+	*p = 0;
+	return opt && odr_ok(o);
+}
+
+int ill_Damaged_Details (ODR o, ILL_Damaged_Details **p, int opt, const char *name)
+{
+	static Odr_arm arm[] = {
+		{ODR_IMPLICIT, ODR_CONTEXT, 1, ILL_Damaged_Details_complete_document,
+		(Odr_fun) odr_null, "complete_document"},
+		{ODR_IMPLICIT, ODR_CONTEXT, 2, ILL_Damaged_Details_specific_units,
+		(Odr_fun) ill_Damaged_DetailsSpecific_units, "specific_units"},
+		{-1, -1, -1, -1, (Odr_fun) 0, 0}
+	};
+	if (!odr_sequence_begin (o, p, sizeof(**p), name))
+		return opt && odr_ok (o);
+	return
+		odr_implicit_tag (o, odr_oid,
+			&(*p)->document_type_id, ODR_CONTEXT, 0, 1, "document_type_id") &&
+		odr_choice (o, arm, &(*p)->u, &(*p)->which, 0) &&
+		odr_sequence_end (o);
+}
+
+int ill_Date_Due (ODR o, ILL_Date_Due **p, int opt, const char *name)
+{
+	if (!odr_sequence_begin (o, p, sizeof(**p), name))
+		return opt && odr_ok (o);
+	return
+		odr_implicit_tag (o, ill_ISO_Date,
+			&(*p)->date_due_field, ODR_CONTEXT, 0, 0, "date_due_field") &&
+		odr_implicit_tag (o, odr_bool,
+			&(*p)->renewable, ODR_CONTEXT, 1, 0, "renewable") &&
+		odr_sequence_end (o);
+}
+
+int ill_Delivery_Address (ODR o, ILL_Delivery_Address **p, int opt, const char *name)
+{
+	if (!odr_sequence_begin (o, p, sizeof(**p), name))
+		return opt && odr_ok (o);
+	return
+		odr_implicit_tag (o, ill_Postal_Address,
+			&(*p)->postal_address, ODR_CONTEXT, 0, 1, "postal_address") &&
+		odr_implicit_tag (o, ill_System_Address,
+			&(*p)->electronic_address, ODR_CONTEXT, 1, 1, "electronic_address") &&
+		odr_sequence_end (o);
+}
+
+int ill_Delivery_ServiceElectronic_delivery (ODR o, ILL_Delivery_ServiceElectronic_delivery **p, int opt, const char *name)
+{
+	if (!odr_initmember (o, p, sizeof(**p)))
+		return opt && odr_ok(o);
+	if (odr_sequence_of (o, (Odr_fun) ill_Electronic_Delivery_Service, &(*p)->elements,
+		&(*p)->num, name))
+		return 1;
+	*p = 0;
+	return opt && odr_ok(o);
+}
+
+int ill_Delivery_Service (ODR o, ILL_Delivery_Service **p, int opt, const char *name)
+{
+	static Odr_arm arm[] = {
+		{ODR_EXPLICIT, ODR_CONTEXT, 7, ILL_Delivery_Service_physical_delivery,
+		(Odr_fun) ill_Transportation_Mode, "physical_delivery"},
+		{ODR_IMPLICIT, ODR_CONTEXT, 50, ILL_Delivery_Service_electronic_delivery,
+		(Odr_fun) ill_Delivery_ServiceElectronic_delivery, "electronic_delivery"},
+		{-1, -1, -1, -1, (Odr_fun) 0, 0}
+	};
+	if (!odr_initmember(o, p, sizeof(**p)))
+		return opt && odr_ok(o);
+	if (odr_choice(o, arm, &(*p)->u, &(*p)->which, name))
+		return 1;
+	*p = 0;
+	return opt && odr_ok(o);
+}
+
+int ill_Electronic_Delivery_Service_0 (ODR o, ILL_Electronic_Delivery_Service_0 **p, int opt, const char *name)
+{
+	if (!odr_sequence_begin (o, p, sizeof(**p), name))
+		return opt && odr_ok (o);
+	return
+		odr_implicit_tag (o, odr_oid,
+			&(*p)->e_delivery_mode, ODR_CONTEXT, 0, 0, "e_delivery_mode") &&
+		odr_explicit_tag (o, odr_any,
+			&(*p)->e_delivery_parameters, ODR_CONTEXT, 1, 0, "e_delivery_parameters") &&
+		odr_sequence_end (o);
+}
+
+int ill_Electronic_Delivery_Service_1 (ODR o, ILL_Electronic_Delivery_Service_1 **p, int opt, const char *name)
+{
+	if (!odr_sequence_begin (o, p, sizeof(**p), name))
+		return opt && odr_ok (o);
+	return
+		odr_implicit_tag (o, odr_oid,
+			&(*p)->document_type_id, ODR_CONTEXT, 2, 0, "document_type_id") &&
+		odr_explicit_tag (o, odr_any,
+			&(*p)->document_type_parameters, ODR_CONTEXT, 3, 0, "document_type_parameters") &&
+		odr_sequence_end (o);
+}
+
+int ill_Electronic_Delivery_Service (ODR o, ILL_Electronic_Delivery_Service **p, int opt, const char *name)
+{
+	static Odr_arm arm[] = {
+		{ODR_IMPLICIT, ODR_CONTEXT, 0, ILL_Electronic_Delivery_Service_e_delivery_address,
+		(Odr_fun) ill_System_Address, "e_delivery_address"},
+		{ODR_IMPLICIT, ODR_CONTEXT, 1, ILL_Electronic_Delivery_Service_e_delivery_id,
+		(Odr_fun) ill_System_Id, "e_delivery_id"},
+		{-1, -1, -1, -1, (Odr_fun) 0, 0}
+	};
+	if (!odr_sequence_begin (o, p, sizeof(**p), name))
+		return opt && odr_ok (o);
+	return
+		odr_implicit_tag (o, ill_Electronic_Delivery_Service_0,
+			&(*p)->e_delivery_service, ODR_CONTEXT, 0, 1, "e_delivery_service") &&
+		odr_implicit_tag (o, ill_Electronic_Delivery_Service_1,
+			&(*p)->document_type, ODR_CONTEXT, 1, 1, "document_type") &&
+		odr_explicit_tag (o, ill_String,
+			&(*p)->e_delivery_description, ODR_CONTEXT, 4, 1, "e_delivery_description") &&
+		odr_constructed_begin (o, &(*p)->u, ODR_CONTEXT, 5, "e_delivery_details") &&
+		odr_choice (o, arm, &(*p)->u, &(*p)->which, 0) &&
+		odr_constructed_end (o) &&
+		odr_explicit_tag (o, ill_String,
+			&(*p)->name_or_code, ODR_CONTEXT, 6, 1, "name_or_code") &&
+		odr_implicit_tag (o, ill_ISO_Time,
+			&(*p)->delivery_time, ODR_CONTEXT, 7, 1, "delivery_time") &&
+		odr_sequence_end (o);
+}
+
+int ill_Error_Report (ODR o, ILL_Error_Report **p, int opt, const char *name)
+{
+	if (!odr_sequence_begin (o, p, sizeof(**p), name))
+		return opt && odr_ok (o);
+	return
+		odr_explicit_tag (o, ill_String,
+			&(*p)->correlation_information, ODR_CONTEXT, 0, 0, "correlation_information") &&
+		odr_implicit_tag (o, ill_Report_Source,
+			&(*p)->report_source, ODR_CONTEXT, 1, 0, "report_source") &&
+		odr_explicit_tag (o, ill_User_Error_Report,
+			&(*p)->user_error_report, ODR_CONTEXT, 2, 1, "user_error_report") &&
+		odr_explicit_tag (o, ill_Provider_Error_Report,
+			&(*p)->provider_error_report, ODR_CONTEXT, 3, 1, "provider_error_report") &&
+		odr_sequence_end (o);
+}
+
+int ill_Estimate_Results (ODR o, ILL_Estimate_Results **p, int opt, const char *name)
+{
+	if (!odr_sequence_begin (o, p, sizeof(**p), name))
+		return opt && odr_ok (o);
+	return
+		odr_explicit_tag (o, ill_String,
+			&(*p)->cost_estimate, ODR_CONTEXT, 0, 0, "cost_estimate") &&
+		odr_implicit_settag (o, ODR_CONTEXT, 1) &&
+		(odr_sequence_of(o, (Odr_fun) ill_Location_Info, &(*p)->locations,
+		  &(*p)->num_locations, "locations") || odr_ok(o)) &&
+		odr_sequence_end (o);
+}
+
+int ill_Extension (ODR o, ILL_Extension **p, int opt, const char *name)
+{
+	if (!odr_sequence_begin (o, p, sizeof(**p), name))
+		return opt && odr_ok (o);
+	return
+		odr_implicit_tag (o, odr_integer,
+			&(*p)->identifier, ODR_CONTEXT, 0, 0, "identifier") &&
+		odr_implicit_tag (o, odr_bool,
+			&(*p)->critical, ODR_CONTEXT, 1, 0, "critical") &&
+		odr_explicit_tag (o, odr_any,
+			&(*p)->item, ODR_CONTEXT, 2, 0, "item") &&
+		odr_sequence_end (o);
+}
+
+int ill_General_Problem (ODR o, ILL_General_Problem **p, int opt, const char *name)
+{
+	return odr_enum (o, p, opt, name);
+}
+
+int ill_History_Report (ODR o, ILL_History_Report **p, int opt, const char *name)
+{
+	if (!odr_sequence_begin (o, p, sizeof(**p), name))
+		return opt && odr_ok (o);
+	return
+		odr_implicit_tag (o, ill_ISO_Date,
+			&(*p)->date_requested, ODR_CONTEXT, 0, 1, "date_requested") &&
+		odr_explicit_tag (o, ill_String,
+			&(*p)->author, ODR_CONTEXT, 1, 1, "author") &&
+		odr_explicit_tag (o, ill_String,
+			&(*p)->title, ODR_CONTEXT, 2, 1, "title") &&
+		odr_explicit_tag (o, ill_String,
+			&(*p)->author_of_article, ODR_CONTEXT, 3, 1, "author_of_article") &&
+		odr_explicit_tag (o, ill_String,
+			&(*p)->title_of_article, ODR_CONTEXT, 4, 1, "title_of_article") &&
+		odr_implicit_tag (o, ill_ISO_Date,
+			&(*p)->date_of_last_transition, ODR_CONTEXT, 5, 0, "date_of_last_transition") &&
+		odr_implicit_tag (o, odr_enum,
+			&(*p)->most_recent_service, ODR_CONTEXT, 6, 0, "most_recent_service") &&
+		odr_implicit_tag (o, ill_ISO_Date,
+			&(*p)->date_of_most_recent_service, ODR_CONTEXT, 7, 0, "date_of_most_recent_service") &&
+		odr_implicit_tag (o, ill_System_Id,
+			&(*p)->initiator_of_most_recent_service, ODR_CONTEXT, 8, 0, "initiator_of_most_recent_service") &&
+		odr_implicit_tag (o, ill_Shipped_Service_Type,
+			&(*p)->shipped_service_type, ODR_CONTEXT, 9, 1, "shipped_service_type") &&
+		odr_implicit_tag (o, ill_Transaction_Results,
+			&(*p)->transaction_results, ODR_CONTEXT, 10, 1, "transaction_results") &&
+		odr_explicit_tag (o, ill_String,
+			&(*p)->most_recent_service_note, ODR_CONTEXT, 11, 1, "most_recent_service_note") &&
+		odr_sequence_end (o);
+}
+
+int ill_Hold_Placed_Results (ODR o, ILL_Hold_Placed_Results **p, int opt, const char *name)
+{
+	if (!odr_sequence_begin (o, p, sizeof(**p), name))
+		return opt && odr_ok (o);
+	return
+		odr_implicit_tag (o, ill_ISO_Date,
+			&(*p)->estimated_date_available, ODR_CONTEXT, 0, 0, "estimated_date_available") &&
+		odr_implicit_tag (o, ill_Medium_Type,
+			&(*p)->hold_placed_medium_type, ODR_CONTEXT, 1, 1, "hold_placed_medium_type") &&
+		odr_implicit_settag (o, ODR_CONTEXT, 2) &&
+		(odr_sequence_of(o, (Odr_fun) ill_Location_Info, &(*p)->locations,
+		  &(*p)->num_locations, "locations") || odr_ok(o)) &&
+		odr_sequence_end (o);
+}
+
+int ill_APDU_Type (ODR o, ILL_APDU_Type **p, int opt, const char *name)
+{
+	return odr_enum (o, p, opt, name);
+}
+
+int ill_Service_Type (ODR o, ILL_Service_Type **p, int opt, const char *name)
+{
+	return odr_enum (o, p, opt, name);
+}
+
+int ill_String (ODR o, ILL_String **p, int opt, const char *name)
+{
+	static Odr_arm arm[] = {
+		{-1, -1, -1, ILL_String_GeneralString,
+		 (Odr_fun) odr_generalstring, "GeneralString"},
+		{-1, -1, -1, ILL_String_EDIFACTString,
+		 (Odr_fun) ill_EDIFACTString, "EDIFACTString"},
+		{-1, -1, -1, -1, (Odr_fun) 0, 0}
+	};
+	if (!odr_initmember(o, p, sizeof(**p)))
+		return opt && odr_ok(o);
+	if (odr_choice(o, arm, &(*p)->u, &(*p)->which, name))
+		return 1;
+	*p = 0;
+	return opt && odr_ok(o);
+}
+
+int ill_Intermediary_Problem (ODR o, ILL_Intermediary_Problem **p, int opt, const char *name)
+{
+	return odr_enum (o, p, opt, name);
+}
+
+int ill_ISO_Date (ODR o, ILL_ISO_Date **p, int opt, const char *name)
+{
+	return odr_visiblestring (o, p, opt, name);
+}
+
+int ill_ISO_Time (ODR o, ILL_ISO_Time **p, int opt, const char *name)
+{
+	return odr_visiblestring (o, p, opt, name);
+}
+
+int ill_Item_Id (ODR o, ILL_Item_Id **p, int opt, const char *name)
+{
+	if (!odr_sequence_begin (o, p, sizeof(**p), name))
+		return opt && odr_ok (o);
+	return
+		odr_implicit_tag (o, odr_enum,
+			&(*p)->item_type, ODR_CONTEXT, 0, 1, "item_type") &&
+		odr_implicit_tag (o, ill_Medium_Type,
+			&(*p)->held_medium_type, ODR_CONTEXT, 1, 1, "held_medium_type") &&
+		odr_explicit_tag (o, ill_String,
+			&(*p)->call_number, ODR_CONTEXT, 2, 1, "call_number") &&
+		odr_explicit_tag (o, ill_String,
+			&(*p)->author, ODR_CONTEXT, 3, 1, "author") &&
+		odr_explicit_tag (o, ill_String,
+			&(*p)->title, ODR_CONTEXT, 4, 1, "title") &&
+		odr_explicit_tag (o, ill_String,
+			&(*p)->sub_title, ODR_CONTEXT, 5, 1, "sub_title") &&
+		odr_explicit_tag (o, ill_String,
+			&(*p)->sponsoring_body, ODR_CONTEXT, 6, 1, "sponsoring_body") &&
+		odr_explicit_tag (o, ill_String,
+			&(*p)->place_of_publication, ODR_CONTEXT, 7, 1, "place_of_publication") &&
+		odr_explicit_tag (o, ill_String,
+			&(*p)->publisher, ODR_CONTEXT, 8, 1, "publisher") &&
+		odr_explicit_tag (o, ill_String,
+			&(*p)->series_title_number, ODR_CONTEXT, 9, 1, "series_title_number") &&
+		odr_explicit_tag (o, ill_String,
+			&(*p)->volume_issue, ODR_CONTEXT, 10, 1, "volume_issue") &&
+		odr_explicit_tag (o, ill_String,
+			&(*p)->edition, ODR_CONTEXT, 11, 1, "edition") &&
+		odr_explicit_tag (o, ill_String,
+			&(*p)->publication_date, ODR_CONTEXT, 12, 1, "publication_date") &&
+		odr_explicit_tag (o, ill_String,
+			&(*p)->publication_date_of_component, ODR_CONTEXT, 13, 1, "publication_date_of_component") &&
+		odr_explicit_tag (o, ill_String,
+			&(*p)->author_of_article, ODR_CONTEXT, 14, 1, "author_of_article") &&
+		odr_explicit_tag (o, ill_String,
+			&(*p)->title_of_article, ODR_CONTEXT, 15, 1, "title_of_article") &&
+		odr_explicit_tag (o, ill_String,
+			&(*p)->pagination, ODR_CONTEXT, 16, 1, "pagination") &&
+		odr_explicit_tag (o, odr_external,
+			&(*p)->national_bibliography_no, ODR_CONTEXT, 17, 1, "national_bibliography_no") &&
+		odr_explicit_tag (o, ill_String,
+			&(*p)->iSBN, ODR_CONTEXT, 18, 1, "iSBN") &&
+		odr_explicit_tag (o, ill_String,
+			&(*p)->iSSN, ODR_CONTEXT, 19, 1, "iSSN") &&
+		odr_explicit_tag (o, odr_external,
+			&(*p)->system_no, ODR_CONTEXT, 20, 1, "system_no") &&
+		odr_explicit_tag (o, ill_String,
+			&(*p)->additional_no_letters, ODR_CONTEXT, 21, 1, "additional_no_letters") &&
+		odr_explicit_tag (o, ill_String,
+			&(*p)->verification_reference_source, ODR_CONTEXT, 22, 1, "verification_reference_source") &&
+		odr_sequence_end (o);
+}
+
+int ill_Location_Info (ODR o, ILL_Location_Info **p, int opt, const char *name)
+{
+	if (!odr_sequence_begin (o, p, sizeof(**p), name))
+		return opt && odr_ok (o);
+	return
+		odr_implicit_tag (o, ill_System_Id,
+			&(*p)->location_id, ODR_CONTEXT, 0, 0, "location_id") &&
+		odr_implicit_tag (o, ill_System_Address,
+			&(*p)->location_address, ODR_CONTEXT, 1, 1, "location_address") &&
+		odr_explicit_tag (o, ill_String,
+			&(*p)->location_note, ODR_CONTEXT, 2, 1, "location_note") &&
+		odr_sequence_end (o);
+}
+
+int ill_Locations_Results (ODR o, ILL_Locations_Results **p, int opt, const char *name)
+{
+	if (!odr_sequence_begin (o, p, sizeof(**p), name))
+		return opt && odr_ok (o);
+	return
+		odr_implicit_tag (o, ill_Reason_Locs_Provided,
+			&(*p)->reason_locs_provided, ODR_CONTEXT, 0, 1, "reason_locs_provided") &&
+		odr_implicit_settag (o, ODR_CONTEXT, 1) &&
+		odr_sequence_of(o, (Odr_fun) ill_Location_Info, &(*p)->locations,
+		  &(*p)->num_locations, "locations") &&
+		odr_sequence_end (o);
+}
+
+int ill_Medium_Type (ODR o, ILL_Medium_Type **p, int opt, const char *name)
+{
+	return odr_enum (o, p, opt, name);
+}
+
+int ill_Name_Of_Person_Or_Institution (ODR o, ILL_Name_Of_Person_Or_Institution **p, int opt, const char *name)
+{
+	static Odr_arm arm[] = {
+		{ODR_EXPLICIT, ODR_CONTEXT, 0, ILL_Name_Of_Person_Or_Institution_name_of_person,
+		(Odr_fun) ill_String, "name_of_person"},
+		{ODR_EXPLICIT, ODR_CONTEXT, 1, ILL_Name_Of_Person_Or_Institution_name_of_institution,
+		(Odr_fun) ill_String, "name_of_institution"},
+		{-1, -1, -1, -1, (Odr_fun) 0, 0}
+	};
+	if (!odr_initmember(o, p, sizeof(**p)))
+		return opt && odr_ok(o);
+	if (odr_choice(o, arm, &(*p)->u, &(*p)->which, name))
+		return 1;
+	*p = 0;
+	return opt && odr_ok(o);
+}
+
+int ill_Person_Or_Institution_Symbol (ODR o, ILL_Person_Or_Institution_Symbol **p, int opt, const char *name)
+{
+	static Odr_arm arm[] = {
+		{ODR_EXPLICIT, ODR_CONTEXT, 0, ILL_Person_Or_Institution_Symbol_person_symbol,
+		(Odr_fun) ill_String, "person_symbol"},
+		{ODR_EXPLICIT, ODR_CONTEXT, 1, ILL_Person_Or_Institution_Symbol_institution_symbol,
+		(Odr_fun) ill_String, "institution_symbol"},
+		{-1, -1, -1, -1, (Odr_fun) 0, 0}
+	};
+	if (!odr_initmember(o, p, sizeof(**p)))
+		return opt && odr_ok(o);
+	if (odr_choice(o, arm, &(*p)->u, &(*p)->which, name))
+		return 1;
+	*p = 0;
+	return opt && odr_ok(o);
+}
+
+int ill_Place_On_Hold_Type (ODR o, ILL_Place_On_Hold_Type **p, int opt, const char *name)
+{
+	return odr_enum (o, p, opt, name);
+}
+
+int ill_Postal_Address (ODR o, ILL_Postal_Address **p, int opt, const char *name)
+{
+	if (!odr_sequence_begin (o, p, sizeof(**p), name))
+		return opt && odr_ok (o);
+	return
+		odr_explicit_tag (o, ill_Name_Of_Person_Or_Institution,
+			&(*p)->name_of_person_or_institution, ODR_CONTEXT, 0, 1, "name_of_person_or_institution") &&
+		odr_explicit_tag (o, ill_String,
+			&(*p)->extended_postal_delivery_address, ODR_CONTEXT, 1, 1, "extended_postal_delivery_address") &&
+		odr_explicit_tag (o, ill_String,
+			&(*p)->street_and_number, ODR_CONTEXT, 2, 1, "street_and_number") &&
+		odr_explicit_tag (o, ill_String,
+			&(*p)->post_office_box, ODR_CONTEXT, 3, 1, "post_office_box") &&
+		odr_explicit_tag (o, ill_String,
+			&(*p)->city, ODR_CONTEXT, 4, 1, "city") &&
+		odr_explicit_tag (o, ill_String,
+			&(*p)->region, ODR_CONTEXT, 5, 1, "region") &&
+		odr_explicit_tag (o, ill_String,
+			&(*p)->country, ODR_CONTEXT, 6, 1, "country") &&
+		odr_explicit_tag (o, ill_String,
+			&(*p)->postal_code, ODR_CONTEXT, 7, 1, "postal_code") &&
+		odr_sequence_end (o);
+}
+
+int ill_Provider_Error_Report (ODR o, ILL_Provider_Error_Report **p, int opt, const char *name)
+{
+	static Odr_arm arm[] = {
+		{ODR_IMPLICIT, ODR_CONTEXT, 0, ILL_Provider_Error_Report_general_problem,
+		(Odr_fun) ill_General_Problem, "general_problem"},
+		{ODR_IMPLICIT, ODR_CONTEXT, 1, ILL_Provider_Error_Report_transaction_id_problem,
+		(Odr_fun) ill_Transaction_Id_Problem, "transaction_id_problem"},
+		{ODR_IMPLICIT, ODR_CONTEXT, 2, ILL_Provider_Error_Report_state_transition_prohibited,
+		(Odr_fun) ill_State_Transition_Prohibited, "state_transition_prohibited"},
+		{-1, -1, -1, -1, (Odr_fun) 0, 0}
+	};
+	if (!odr_initmember(o, p, sizeof(**p)))
+		return opt && odr_ok(o);
+	if (odr_choice(o, arm, &(*p)->u, &(*p)->which, name))
+		return 1;
+	*p = 0;
+	return opt && odr_ok(o);
+}
+
+int ill_Reason_Locs_Provided (ODR o, ILL_Reason_Locs_Provided **p, int opt, const char *name)
+{
+	return odr_enum (o, p, opt, name);
+}
+
+int ill_Reason_No_Report (ODR o, ILL_Reason_No_Report **p, int opt, const char *name)
+{
+	return odr_enum (o, p, opt, name);
+}
+
+int ill_Reason_Unfilled (ODR o, ILL_Reason_Unfilled **p, int opt, const char *name)
+{
+	return odr_enum (o, p, opt, name);
+}
+
+int ill_Report_Source (ODR o, ILL_Report_Source **p, int opt, const char *name)
+{
+	return odr_enum (o, p, opt, name);
+}
+
+int ill_Requester_Optional_Messages_Type (ODR o, ILL_Requester_Optional_Messages_Type **p, int opt, const char *name)
+{
+	if (!odr_sequence_begin (o, p, sizeof(**p), name))
+		return opt && odr_ok (o);
+	return
+		odr_implicit_tag (o, odr_bool,
+			&(*p)->can_send_RECEIVED, ODR_CONTEXT, 0, 0, "can_send_RECEIVED") &&
+		odr_implicit_tag (o, odr_bool,
+			&(*p)->can_send_RETURNED, ODR_CONTEXT, 1, 0, "can_send_RETURNED") &&
+		odr_implicit_tag (o, odr_enum,
+			&(*p)->requester_SHIPPED, ODR_CONTEXT, 2, 0, "requester_SHIPPED") &&
+		odr_implicit_tag (o, odr_enum,
+			&(*p)->requester_CHECKED_IN, ODR_CONTEXT, 3, 0, "requester_CHECKED_IN") &&
+		odr_sequence_end (o);
+}
+
+int ill_Responder_Optional_Messages_Type (ODR o, ILL_Responder_Optional_Messages_Type **p, int opt, const char *name)
+{
+	if (!odr_sequence_begin (o, p, sizeof(**p), name))
+		return opt && odr_ok (o);
+	return
+		odr_implicit_tag (o, odr_bool,
+			&(*p)->can_send_SHIPPED, ODR_CONTEXT, 0, 0, "can_send_SHIPPED") &&
+		odr_implicit_tag (o, odr_bool,
+			&(*p)->can_send_CHECKED_IN, ODR_CONTEXT, 1, 0, "can_send_CHECKED_IN") &&
+		odr_implicit_tag (o, odr_enum,
+			&(*p)->responder_RECEIVED, ODR_CONTEXT, 2, 0, "responder_RECEIVED") &&
+		odr_implicit_tag (o, odr_enum,
+			&(*p)->responder_RETURNED, ODR_CONTEXT, 3, 0, "responder_RETURNED") &&
+		odr_sequence_end (o);
+}
+
+int ill_Retry_Results (ODR o, ILL_Retry_Results **p, int opt, const char *name)
+{
+	if (!odr_sequence_begin (o, p, sizeof(**p), name))
+		return opt && odr_ok (o);
+	return
+		odr_implicit_tag (o, odr_enum,
+			&(*p)->reason_not_available, ODR_CONTEXT, 0, 1, "reason_not_available") &&
+		odr_implicit_tag (o, ill_ISO_Date,
+			&(*p)->retry_date, ODR_CONTEXT, 1, 1, "retry_date") &&
+		odr_implicit_settag (o, ODR_CONTEXT, 2) &&
+		(odr_sequence_of(o, (Odr_fun) ill_Location_Info, &(*p)->locations,
+		  &(*p)->num_locations, "locations") || odr_ok(o)) &&
+		odr_sequence_end (o);
+}
+
+int ill_Search_Type (ODR o, ILL_Search_Type **p, int opt, const char *name)
+{
+	if (!odr_sequence_begin (o, p, sizeof(**p), name))
+		return opt && odr_ok (o);
+	return
+		odr_explicit_tag (o, ill_String,
+			&(*p)->level_of_service, ODR_CONTEXT, 0, 1, "level_of_service") &&
+		odr_implicit_tag (o, ill_ISO_Date,
+			&(*p)->need_before_date, ODR_CONTEXT, 1, 1, "need_before_date") &&
+		odr_implicit_tag (o, odr_enum,
+			&(*p)->expiry_flag, ODR_CONTEXT, 2, 0, "expiry_flag") &&
+		odr_implicit_tag (o, ill_ISO_Date,
+			&(*p)->expiry_date, ODR_CONTEXT, 3, 1, "expiry_date") &&
+		odr_sequence_end (o);
+}
+
+int ill_Security_Problem (ODR o, ILL_Security_Problem **p, int opt, const char *name)
+{
+	return ill_String (o, p, opt, name);
+}
+
+int ill_Send_To_List_Type_s (ODR o, ILL_Send_To_List_Type_s **p, int opt, const char *name)
+{
+	if (!odr_sequence_begin (o, p, sizeof(**p), name))
+		return opt && odr_ok (o);
+	return
+		odr_implicit_tag (o, ill_System_Id,
+			&(*p)->system_id, ODR_CONTEXT, 0, 0, "system_id") &&
+		odr_explicit_tag (o, ill_Account_Number,
+			&(*p)->account_number, ODR_CONTEXT, 1, 1, "account_number") &&
+		odr_implicit_tag (o, ill_System_Address,
+			&(*p)->system_address, ODR_CONTEXT, 2, 1, "system_address") &&
+		odr_sequence_end (o);
+}
+
+int ill_Send_To_List_Type (ODR o, ILL_Send_To_List_Type **p, int opt, const char *name)
+{
+	if (!odr_initmember (o, p, sizeof(**p)))
+		return opt && odr_ok(o);
+	if (odr_sequence_of (o, (Odr_fun) ill_Send_To_List_Type_s, &(*p)->elements,
+		&(*p)->num, name))
+		return 1;
+	*p = 0;
+	return opt && odr_ok(o);
+}
+
+int ill_Service_Date_this (ODR o, ILL_Service_Date_this **p, int opt, const char *name)
+{
+	if (!odr_sequence_begin (o, p, sizeof(**p), name))
+		return opt && odr_ok (o);
+	return
+		odr_implicit_tag (o, ill_ISO_Date,
+			&(*p)->date, ODR_CONTEXT, 0, 0, "date") &&
+		odr_implicit_tag (o, ill_ISO_Time,
+			&(*p)->time, ODR_CONTEXT, 1, 1, "time") &&
+		odr_sequence_end (o);
+}
+
+int ill_Service_Date_original (ODR o, ILL_Service_Date_original **p, int opt, const char *name)
+{
+	if (!odr_sequence_begin (o, p, sizeof(**p), name))
+		return opt && odr_ok (o);
+	return
+		odr_implicit_tag (o, ill_ISO_Date,
+			&(*p)->date, ODR_CONTEXT, 0, 0, "date") &&
+		odr_implicit_tag (o, ill_ISO_Time,
+			&(*p)->time, ODR_CONTEXT, 1, 1, "time") &&
+		odr_sequence_end (o);
+}
+
+int ill_Service_Date_Time (ODR o, ILL_Service_Date_Time **p, int opt, const char *name)
+{
+	if (!odr_sequence_begin (o, p, sizeof(**p), name))
+		return opt && odr_ok (o);
+	return
+		odr_implicit_tag (o, ill_Service_Date_this,
+			&(*p)->date_time_of_this_service, ODR_CONTEXT, 0, 0, "date_time_of_this_service") &&
+		odr_implicit_tag (o, ill_Service_Date_original,
+			&(*p)->date_time_of_original_service, ODR_CONTEXT, 1, 1, "date_time_of_original_service") &&
+		odr_sequence_end (o);
+}
+
+int ill_Shipped_Service_Type (ODR o, ILL_Shipped_Service_Type **p, int opt, const char *name)
+{
+	return ill_Service_Type (o, p, opt, name);
+}
+
+int ill_State_Transition_Prohibited (ODR o, ILL_State_Transition_Prohibited **p, int opt, const char *name)
+{
+	if (!odr_sequence_begin (o, p, sizeof(**p), name))
+		return opt && odr_ok (o);
+	return
+		odr_implicit_tag (o, ill_APDU_Type,
+			&(*p)->aPDU_type, ODR_CONTEXT, 0, 0, "aPDU_type") &&
+		odr_implicit_tag (o, ill_Current_State,
+			&(*p)->current_state, ODR_CONTEXT, 1, 0, "current_state") &&
+		odr_sequence_end (o);
+}
+
+int ill_Status_Report (ODR o, ILL_Status_Report **p, int opt, const char *name)
+{
+	if (!odr_sequence_begin (o, p, sizeof(**p), name))
+		return opt && odr_ok (o);
+	return
+		odr_implicit_tag (o, ill_History_Report,
+			&(*p)->user_status_report, ODR_CONTEXT, 0, 0, "user_status_report") &&
+		odr_implicit_tag (o, ill_Current_State,
+			&(*p)->provider_status_report, ODR_CONTEXT, 1, 0, "provider_status_report") &&
+		odr_sequence_end (o);
+}
+
+int ill_Supplemental_Item_Description (ODR o, ILL_Supplemental_Item_Description **p, int opt, const char *name)
+{
+	if (!odr_initmember (o, p, sizeof(**p)))
+		return opt && odr_ok(o);
+	if (odr_sequence_of (o, (Odr_fun) odr_external, &(*p)->elements,
+		&(*p)->num, name))
+		return 1;
+	*p = 0;
+	return opt && odr_ok(o);
+}
+
+int ill_Supply_Details (ODR o, ILL_Supply_Details **p, int opt, const char *name)
+{
+	static Odr_arm arm[] = {
+		{ODR_EXPLICIT, ODR_CONTEXT, 5, ILL_Supply_Details_physical_delivery,
+		(Odr_fun) ill_Transportation_Mode, "physical_delivery"},
+		{ODR_IMPLICIT, ODR_CONTEXT, 50, ILL_Supply_Details_electronic_delivery,
+		(Odr_fun) ill_Electronic_Delivery_Service, "electronic_delivery"},
+		{-1, -1, -1, -1, (Odr_fun) 0, 0}
+	};
+	if (!odr_sequence_begin (o, p, sizeof(**p), name))
+		return opt && odr_ok (o);
+	return
+		odr_implicit_tag (o, ill_ISO_Date,
+			&(*p)->date_shipped, ODR_CONTEXT, 0, 1, "date_shipped") &&
+		odr_implicit_tag (o, ill_Date_Due,
+			&(*p)->date_due, ODR_CONTEXT, 1, 1, "date_due") &&
+		odr_implicit_tag (o, odr_integer,
+			&(*p)->chargeable_units, ODR_CONTEXT, 2, 1, "chargeable_units") &&
+		odr_implicit_tag (o, ill_Amount,
+			&(*p)->cost, ODR_CONTEXT, 3, 1, "cost") &&
+		odr_implicit_tag (o, odr_enum,
+			&(*p)->shipped_conditions, ODR_CONTEXT, 4, 1, "shipped_conditions") &&
+		(odr_choice (o, arm, &(*p)->u, &(*p)->which, 0) || odr_ok(o)) &&
+		odr_implicit_tag (o, ill_Amount,
+			&(*p)->insured_for, ODR_CONTEXT, 6, 1, "insured_for") &&
+		odr_implicit_tag (o, ill_Amount,
+			&(*p)->return_insurance_require, ODR_CONTEXT, 7, 1, "return_insurance_require") &&
+		odr_implicit_settag (o, ODR_CONTEXT, 8) &&
+		(odr_sequence_of(o, (Odr_fun) ill_Units_Per_Medium_Type, &(*p)->no_of_units_per_medium,
+		  &(*p)->num_no_of_units_per_medium, "no_of_units_per_medium") || odr_ok(o)) &&
+		odr_sequence_end (o);
+}
+
+int ill_Supply_Medium_Info_Type (ODR o, ILL_Supply_Medium_Info_Type **p, int opt, const char *name)
+{
+	if (!odr_sequence_begin (o, p, sizeof(**p), name))
+		return opt && odr_ok (o);
+	return
+		odr_implicit_tag (o, ill_Supply_Medium_Type,
+			&(*p)->supply_medium_type, ODR_CONTEXT, 0, 0, "supply_medium_type") &&
+		odr_explicit_tag (o, ill_String,
+			&(*p)->medium_characteristics, ODR_CONTEXT, 1, 1, "medium_characteristics") &&
+		odr_sequence_end (o);
+}
+
+int ill_Supply_Medium_Type (ODR o, ILL_Supply_Medium_Type **p, int opt, const char *name)
+{
+	return odr_enum (o, p, opt, name);
+}
+
+int ill_System_Address (ODR o, ILL_System_Address **p, int opt, const char *name)
+{
+	if (!odr_sequence_begin (o, p, sizeof(**p), name))
+		return opt && odr_ok (o);
+	return
+		odr_explicit_tag (o, ill_String,
+			&(*p)->telecom_service_identifier, ODR_CONTEXT, 0, 1, "telecom_service_identifier") &&
+		odr_explicit_tag (o, ill_String,
+			&(*p)->telecom_service_address, ODR_CONTEXT, 1, 1, "telecom_service_address") &&
+		odr_sequence_end (o);
+}
+
+int ill_System_Id (ODR o, ILL_System_Id **p, int opt, const char *name)
+{
+	if (!odr_sequence_begin (o, p, sizeof(**p), name))
+		return opt && odr_ok (o);
+	return
+		odr_explicit_tag (o, ill_Person_Or_Institution_Symbol,
+			&(*p)->person_or_institution_symbol, ODR_CONTEXT, 0, 1, "person_or_institution_symbol") &&
+		odr_explicit_tag (o, ill_Name_Of_Person_Or_Institution,
+			&(*p)->name_of_person_or_institution, ODR_CONTEXT, 1, 1, "name_of_person_or_institution") &&
+		odr_sequence_end (o);
+}
+
+int ill_Third_Party_Info_Type (ODR o, ILL_Third_Party_Info_Type **p, int opt, const char *name)
+{
+	if (!odr_sequence_begin (o, p, sizeof(**p), name))
+		return opt && odr_ok (o);
+	return
+		odr_implicit_tag (o, odr_bool,
+			&(*p)->permission_to_forward, ODR_CONTEXT, 0, 0, "permission_to_forward") &&
+		odr_implicit_tag (o, odr_bool,
+			&(*p)->permission_to_chain, ODR_CONTEXT, 1, 0, "permission_to_chain") &&
+		odr_implicit_tag (o, odr_bool,
+			&(*p)->permission_to_partition, ODR_CONTEXT, 2, 0, "permission_to_partition") &&
+		odr_implicit_tag (o, odr_bool,
+			&(*p)->permission_to_change_send_to_list, ODR_CONTEXT, 3, 0, "permission_to_change_send_to_list") &&
+		odr_implicit_tag (o, ill_System_Address,
+			&(*p)->initial_requester_address, ODR_CONTEXT, 4, 1, "initial_requester_address") &&
+		odr_implicit_tag (o, odr_enum,
+			&(*p)->preference, ODR_CONTEXT, 5, 0, "preference") &&
+		odr_implicit_tag (o, ill_Send_To_List_Type,
+			&(*p)->send_to_list, ODR_CONTEXT, 6, 1, "send_to_list") &&
+		odr_implicit_tag (o, ill_Already_Tried_List_Type,
+			&(*p)->already_tried_list, ODR_CONTEXT, 7, 1, "already_tried_list") &&
+		odr_sequence_end (o);
+}
+
+int ill_Transaction_Id (ODR o, ILL_Transaction_Id **p, int opt, const char *name)
+{
+	if (!odr_sequence_begin (o, p, sizeof(**p), name))
+		return opt && odr_ok (o);
+	return
+		odr_implicit_tag (o, ill_System_Id,
+			&(*p)->initial_requester_id, ODR_CONTEXT, 0, 1, "initial_requester_id") &&
+		odr_explicit_tag (o, ill_String,
+			&(*p)->transaction_group_qualifier, ODR_CONTEXT, 1, 0, "transaction_group_qualifier") &&
+		odr_explicit_tag (o, ill_String,
+			&(*p)->transaction_qualifier, ODR_CONTEXT, 2, 0, "transaction_qualifier") &&
+		odr_explicit_tag (o, ill_String,
+			&(*p)->sub_transaction_qualifier, ODR_CONTEXT, 3, 1, "sub_transaction_qualifier") &&
+		odr_sequence_end (o);
+}
+
+int ill_Transaction_Id_Problem (ODR o, ILL_Transaction_Id_Problem **p, int opt, const char *name)
+{
+	return odr_enum (o, p, opt, name);
+}
+
+int ill_Transaction_Results (ODR o, ILL_Transaction_Results **p, int opt, const char *name)
+{
+	return odr_enum (o, p, opt, name);
+}
+
+int ill_Transaction_Type (ODR o, ILL_Transaction_Type **p, int opt, const char *name)
+{
+	return odr_enum (o, p, opt, name);
+}
+
+int ill_Transportation_Mode (ODR o, ILL_Transportation_Mode **p, int opt, const char *name)
+{
+	return ill_String (o, p, opt, name);
+}
+
+int ill_Unable_To_Perform (ODR o, ILL_Unable_To_Perform **p, int opt, const char *name)
+{
+	return odr_enum (o, p, opt, name);
+}
+
+int ill_Unfilled_Results (ODR o, ILL_Unfilled_Results **p, int opt, const char *name)
+{
+	if (!odr_sequence_begin (o, p, sizeof(**p), name))
+		return opt && odr_ok (o);
+	return
+		odr_implicit_tag (o, ill_Reason_Unfilled,
+			&(*p)->reason_unfilled, ODR_CONTEXT, 0, 0, "reason_unfilled") &&
+		odr_implicit_settag (o, ODR_CONTEXT, 1) &&
+		(odr_sequence_of(o, (Odr_fun) ill_Location_Info, &(*p)->locations,
+		  &(*p)->num_locations, "locations") || odr_ok(o)) &&
+		odr_sequence_end (o);
+}
+
+int ill_Units_Per_Medium_Type (ODR o, ILL_Units_Per_Medium_Type **p, int opt, const char *name)
+{
+	if (!odr_sequence_begin (o, p, sizeof(**p), name))
+		return opt && odr_ok (o);
+	return
+		odr_explicit_tag (o, ill_Supply_Medium_Type,
+			&(*p)->medium, ODR_CONTEXT, 0, 0, "medium") &&
+		odr_explicit_tag (o, odr_integer,
+			&(*p)->no_of_units, ODR_CONTEXT, 1, 0, "no_of_units") &&
+		odr_sequence_end (o);
+}
+
+int ill_User_Error_Report (ODR o, ILL_User_Error_Report **p, int opt, const char *name)
+{
+	static Odr_arm arm[] = {
+		{ODR_IMPLICIT, ODR_CONTEXT, 0, ILL_User_Error_Report_already_forwarded,
+		(Odr_fun) ill_Already_Forwarded, "already_forwarded"},
+		{ODR_IMPLICIT, ODR_CONTEXT, 1, ILL_User_Error_Report_intermediary_problem,
+		(Odr_fun) ill_Intermediary_Problem, "intermediary_problem"},
+		{ODR_EXPLICIT, ODR_CONTEXT, 2, ILL_User_Error_Report_security_problem,
+		(Odr_fun) ill_Security_Problem, "security_problem"},
+		{ODR_IMPLICIT, ODR_CONTEXT, 3, ILL_User_Error_Report_unable_to_perform,
+		(Odr_fun) ill_Unable_To_Perform, "unable_to_perform"},
+		{-1, -1, -1, -1, (Odr_fun) 0, 0}
+	};
+	if (!odr_initmember(o, p, sizeof(**p)))
+		return opt && odr_ok(o);
+	if (odr_choice(o, arm, &(*p)->u, &(*p)->which, name))
+		return 1;
+	*p = 0;
+	return opt && odr_ok(o);
+}
+
+int ill_Will_Supply_Results (ODR o, ILL_Will_Supply_Results **p, int opt, const char *name)
+{
+	if (!odr_sequence_begin (o, p, sizeof(**p), name))
+		return opt && odr_ok (o);
+	return
+		odr_explicit_tag (o, odr_enum,
+			&(*p)->reason_will_supply, ODR_CONTEXT, 0, 0, "reason_will_supply") &&
+		odr_explicit_tag (o, ill_ISO_Date,
+			&(*p)->supply_date, ODR_CONTEXT, 1, 1, "supply_date") &&
+		odr_explicit_tag (o, ill_Postal_Address,
+			&(*p)->return_to_address, ODR_CONTEXT, 2, 1, "return_to_address") &&
+		odr_implicit_settag (o, ODR_CONTEXT, 3) &&
+		(odr_sequence_of(o, (Odr_fun) ill_Location_Info, &(*p)->locations,
+		  &(*p)->num_locations, "locations") || odr_ok(o)) &&
+		odr_explicit_tag (o, ill_Electronic_Delivery_Service,
+			&(*p)->electronic_delivery_service, ODR_CONTEXT, 4, 1, "electronic_delivery_service") &&
+		odr_sequence_end (o);
+}
+
+int ill_EDIFACTString (ODR o, ILL_EDIFACTString **p, int opt, const char *name)
+{
+	return odr_visiblestring (o, p, opt, name);
+}
+
+
Index: /main/tags/2.25/gsdl/packages/yaz/ill/ill-get.c
===================================================================
--- /main/tags/2.25/gsdl/packages/yaz/ill/ill-get.c	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/yaz/ill/ill-get.c	(revision 21064)
@@ -0,0 +1,557 @@
+/*
+ * Copyright (c) 1999-2000, Index Data.
+ * See the file LICENSE for details.
+ *
+ * $Log$
+ * Revision 1.1  2000/08/03 03:10:26  johnmcp
+ * Added the YAZ toolkit source to the packages directory (for z39.50 stuff)
+ *
+ * Revision 1.5  2000/02/24 08:52:01  adam
+ * Bug fix.
+ *
+ * Revision 1.4  2000/02/04 11:01:15  adam
+ * Added more elements.
+ *
+ * Revision 1.3  2000/01/31 13:15:21  adam
+ * Removed uses of assert(3). Cleanup of ODR. CCL parser update so
+ * that some characters are not surrounded by spaces in resulting term.
+ * ILL-code updates.
+ *
+ * Revision 1.2  2000/01/15 09:38:51  adam
+ * Implemented ill_get_ILLRequest. Added some type mappings for ILL protocol.
+ *
+ * Revision 1.1  1999/12/16 23:36:19  adam
+ * Implemented ILL protocol. Minor updates ASN.1 compiler.
+ *
+ */
+
+#include <yaz/ill.h>
+
+bool_t *ill_get_bool (struct ill_get_ctl *gc, const char *name,
+		      const char *sub, int val)
+{
+    ODR o = gc->odr;
+    char element[128];
+    const char *v;
+    bool_t *r = odr_malloc (o, sizeof(*r));
+    
+    strcpy(element, name);
+    if (sub)
+    {
+	strcat (element, ",");
+	strcat (element, sub);
+    }    
+
+    v = (gc->f)(gc->clientData, element);
+    if (v)
+	val = atoi(v);
+    else if (val < 0)
+	return 0;
+    *r = val;
+    return r;
+}
+
+int *ill_get_int (struct ill_get_ctl *gc, const char *name,
+		  const char *sub, int val)
+{
+    ODR o = gc->odr;
+    char element[128];
+    const char *v;
+    int *r = odr_malloc (o, sizeof(*r));
+    
+    strcpy(element, name);
+    if (sub)
+    {
+	strcat (element, ",");
+	strcat (element, sub);
+    }    
+    v = (gc->f)(gc->clientData, element);
+    if (v)
+	val = atoi(v);
+    *r = val;
+    return r;
+}
+
+int *ill_get_enumerated (struct ill_get_ctl *gc, const char *name,
+			 const char *sub, int val)
+{
+    return ill_get_int(gc, name, sub, val);
+}
+
+ILL_String *ill_get_ILL_String (struct ill_get_ctl *gc, const char *name,
+				const char *sub)
+{
+    ILL_String *r = (ILL_String *) odr_malloc (gc->odr, sizeof(*r));
+    char element[128];
+    const char *v;
+
+    strcpy(element, name);
+    if (sub)
+    {
+	strcat (element, ",");
+	strcat (element, sub);
+    }
+    v = (gc->f)(gc->clientData, element);
+    if (!v)
+	return 0;
+    r->which = ILL_String_GeneralString;
+    r->u.GeneralString = odr_strdup (gc->odr, v);
+    return r;
+}
+
+
+ILL_ISO_Date *ill_get_ILL_ISO_Date (struct ill_get_ctl *gc, const char *name,
+				    const char *sub, const char *val)
+{
+    char element[128];
+    const char *v;
+
+    strcpy(element, name);
+    if (sub)
+    {
+	strcat (element, ",");
+	strcat (element, sub);
+    }
+    v = (gc->f)(gc->clientData, element);
+    if (!v)
+	v = val;
+    if (!v)
+	return 0;
+    return odr_strdup (gc->odr, v);
+}
+
+ILL_ISO_Time *ill_get_ILL_ISO_Time (struct ill_get_ctl *gc, const char *name,
+				    const char *sub, const char *val)
+{
+    char element[128];
+    const char *v;
+
+    strcpy(element, name);
+    if (sub)
+    {
+	strcat (element, ",");
+	strcat (element, sub);
+    }
+    v = (gc->f)(gc->clientData, element);
+    if (!v)
+	v = val;
+    if (!v)
+	return 0;
+    return odr_strdup (gc->odr, v);
+}
+
+ILL_Person_Or_Institution_Symbol *ill_get_Person_Or_Insitution_Symbol (
+    struct ill_get_ctl *gc, const char *name, const char *sub)
+{
+    char element[128];
+    ODR o = gc->odr;
+    ILL_Person_Or_Institution_Symbol *p = odr_malloc (o, sizeof(*p));
+    
+    strcpy(element, name);
+    if (sub)
+    {
+	strcat (element, ",");
+	strcat (element, sub);
+    }
+    p->which = ILL_Person_Or_Institution_Symbol_person_symbol;
+    if ((p->u.person_symbol = ill_get_ILL_String (gc, element, "person")))
+	return p;
+
+    p->which = ILL_Person_Or_Institution_Symbol_institution_symbol;
+    if ((p->u.institution_symbol =
+	 ill_get_ILL_String (gc, element, "institution")))
+	return p;
+    return 0;
+}
+
+static ILL_Name_Of_Person_Or_Institution *ill_get_Name_Of_Person_Or_Institution(
+    struct ill_get_ctl *gc, const char *name, const char *sub)
+{
+    char element[128];
+    ODR o = gc->odr;
+    ILL_Name_Of_Person_Or_Institution *p = odr_malloc (o, sizeof(*p));
+    
+    strcpy(element, name);
+    if (sub)
+    {
+	strcat (element, ",");
+	strcat (element, sub);
+    }
+    p->which = ILL_Name_Of_Person_Or_Institution_name_of_person;
+    if ((p->u.name_of_person =
+	 ill_get_ILL_String (gc, element, "name-of-person")))
+	return p;
+
+    p->which = ILL_Name_Of_Person_Or_Institution_name_of_institution;
+    if ((p->u.name_of_institution =
+	 ill_get_ILL_String (gc, element, "name-of-institution")))
+	return p;
+    return 0;
+}
+    
+ILL_System_Id *ill_get_System_Id(struct ill_get_ctl *gc,
+				 const char *name, const char *sub)
+{
+    ODR o = gc->odr;
+    char element[128];
+    ILL_System_Id *p;
+    
+    strcpy(element, name);
+    if (sub)
+    {
+	strcat (element, ",");
+	strcat (element, sub);
+    }
+    p = (ILL_System_Id *) odr_malloc (o, sizeof(*p));
+    p->person_or_institution_symbol = ill_get_Person_Or_Insitution_Symbol (
+	gc, element, "person-or-institution-symbol");
+    p->name_of_person_or_institution = ill_get_Name_Of_Person_Or_Institution (
+	gc, element, "name-of-person-or-institution");
+    return p;
+}
+
+ILL_Transaction_Id *ill_get_Transaction_Id (struct ill_get_ctl *gc,
+					    const char *name, const char *sub)
+{
+    ODR o = gc->odr;
+    ILL_Transaction_Id *r = (ILL_Transaction_Id *) odr_malloc (o, sizeof(*r));
+    char element[128];
+    
+    strcpy(element, name);
+    if (sub)
+    {
+	strcat (element, ",");
+	strcat (element, sub);
+    }    
+    r->initial_requester_id =
+	ill_get_System_Id (gc, element, "initial-requester-id");
+    r->transaction_group_qualifier =
+	ill_get_ILL_String (gc, element, "transaction-group-qualifier");
+    r->transaction_qualifier =
+	ill_get_ILL_String (gc, element, "transaction-qualifier");
+    r->sub_transaction_qualifier =
+	ill_get_ILL_String (gc, element, "sub-transaction-qualifier");
+    return r;
+}
+
+
+ILL_Service_Date_this *ill_get_Service_Date_this (
+    struct ill_get_ctl *gc, const char *name, const char *sub)
+{
+    ODR o = gc->odr;
+    ILL_Service_Date_this *r =
+	(ILL_Service_Date_this *) odr_malloc (o, sizeof(*r));
+    char element[128];
+    
+    strcpy(element, name);
+    if (sub)
+    {
+	strcat (element, ",");
+	strcat (element, sub);
+    }
+    r->date = ill_get_ILL_ISO_Date (gc, element, "date", "20000101");
+    r->time = ill_get_ILL_ISO_Time (gc, element, "time", 0);
+    return r;
+}
+
+ILL_Service_Date_original *ill_get_Service_Date_original (
+    struct ill_get_ctl *gc, const char *name, const char *sub)
+{
+    ODR o = gc->odr;
+    ILL_Service_Date_original *r =
+	(ILL_Service_Date_original *) odr_malloc (o, sizeof(*r));
+    char element[128];
+    
+    strcpy(element, name);
+    if (sub)
+    {
+	strcat (element, ",");
+	strcat (element, sub);
+    }
+    r->date = ill_get_ILL_ISO_Date (gc, element, "date", 0);
+    r->time = ill_get_ILL_ISO_Time (gc, element, "time", 0);
+    if (!r->date && !r->time)
+	return 0;
+    return r;
+}
+
+ILL_Service_Date_Time *ill_get_Service_Date_Time (
+    struct ill_get_ctl *gc, const char *name, const char *sub)
+{
+    ODR o = gc->odr;
+    ILL_Service_Date_Time *r =
+	(ILL_Service_Date_Time *) odr_malloc (o, sizeof(*r));
+    char element[128];
+    
+    strcpy(element, name);
+    if (sub)
+    {
+	strcat (element, ",");
+	strcat (element, sub);
+    }    
+    r->date_time_of_this_service = ill_get_Service_Date_this (
+	gc, element, "this");
+    r->date_time_of_original_service = ill_get_Service_Date_original (
+	gc, element, "original");
+    return r;
+}
+
+ILL_Requester_Optional_Messages_Type *ill_get_Requester_Optional_Messages_Type (
+    struct ill_get_ctl *gc, const char *name, const char *sub)
+{
+    ODR o = gc->odr;
+    ILL_Requester_Optional_Messages_Type *r =
+	(ILL_Requester_Optional_Messages_Type *) odr_malloc (o, sizeof(*r));
+    char element[128];
+    
+    strcpy(element, name);
+    if (sub)
+    {
+	strcat (element, ",");
+	strcat (element, sub);
+    }
+    r->can_send_RECEIVED = ill_get_bool (gc, element, "can-send-RECEIVED", 0);
+    r->can_send_RETURNED = ill_get_bool (gc, element, "can-send-RETURNED", 0);
+    r->requester_SHIPPED =
+	ill_get_enumerated (gc, element, "requester-SHIPPED", 1);
+    r->requester_CHECKED_IN =
+	ill_get_enumerated (gc, element, "requester-CHECKED-IN", 1);
+    return r;
+}
+
+ILL_Item_Id *ill_get_Item_Id (
+    struct ill_get_ctl *gc, const char *name, const char *sub)   
+{
+    ODR o = gc->odr;
+    ILL_Item_Id *r = (ILL_Item_Id *) odr_malloc (o, sizeof(*r));
+    char element[128];
+    
+    strcpy(element, name);
+    if (sub)
+    {
+	strcat (element, ",");
+	strcat (element, sub);
+    }
+    r->item_type = ill_get_enumerated (gc, element, "item-type",
+				       ILL_Item_Id_monograph);
+    r->held_medium_type = 0;
+    r->call_number = ill_get_ILL_String(gc, element, "call-number");
+    r->author = ill_get_ILL_String(gc, element, "author");
+    r->title = ill_get_ILL_String(gc, element, "title");
+    r->sub_title = ill_get_ILL_String(gc, element, "sub-title");
+    r->sponsoring_body = ill_get_ILL_String(gc, element, "sponsoring-body");
+    r->place_of_publication =
+	ill_get_ILL_String(gc, element, "place-of-publication");
+    r->publisher = ill_get_ILL_String(gc, element, "publisher");
+    r->series_title_number =
+	ill_get_ILL_String(gc, element, "series-title-number");
+    r->volume_issue = ill_get_ILL_String(gc, element, "volume-issue");
+    r->edition = ill_get_ILL_String(gc, element, "edition");
+    r->publication_date = ill_get_ILL_String(gc, element, "publication-date");
+    r->publication_date_of_component =
+	ill_get_ILL_String(gc, element, "publication-date-of-component");
+    r->author_of_article = ill_get_ILL_String(gc, element,
+					      "author-of-article");
+    r->title_of_article = ill_get_ILL_String(gc, element, "title-or-article");
+    r->pagination = ill_get_ILL_String(gc, element, "pagination");
+    r->national_bibliography_no = 0;
+    r->iSBN = ill_get_ILL_String(gc, element, "ISBN");
+    r->iSSN = ill_get_ILL_String(gc, element, "ISSN");
+    r->system_no = 0;
+    r->additional_no_letters =
+	ill_get_ILL_String(gc, element, "additional-no-letters");
+    r->verification_reference_source = 
+	ill_get_ILL_String(gc, element, "verification-reference-source");
+    return r;
+}
+
+ILL_ItemRequest *ill_get_ItemRequest (
+    struct ill_get_ctl *gc, const char *name, const char *sub)
+{
+    ODR o = gc->odr;
+    ILL_ItemRequest *r = (ILL_ItemRequest *)odr_malloc(o, sizeof(*r));
+    return 0;
+}
+
+
+ILL_Client_Id *ill_get_Client_Id (
+    struct ill_get_ctl *gc, const char *name, const char *sub)
+{
+    char element[128];
+    ODR o = gc->odr;
+    ILL_Client_Id *r = (ILL_Client_Id *) odr_malloc(o, sizeof(*r));
+
+    strcpy(element, name);
+    if (sub)
+    {
+	strcat (element, ",");
+	strcat (element, sub);
+    }
+    r->client_name = ill_get_ILL_String (gc, element, "client-name");
+    r->client_status = ill_get_ILL_String (gc, element, "client-status");
+    r->client_identifier = ill_get_ILL_String (gc, element,
+					       "client-identifier");
+    return r;
+}
+
+ILL_Postal_Address *ill_get_Postal_Address (
+    struct ill_get_ctl *gc, const char *name, const char *sub)
+{
+    ODR o = gc->odr;
+    ILL_Postal_Address *r =
+	(ILL_Postal_Address *) odr_malloc(o, sizeof(*r));
+    char element[128];
+
+    strcpy(element, name);
+    if (sub)
+    {
+	strcat (element, ",");
+	strcat (element, sub);
+    }
+    r->name_of_person_or_institution = 
+	ill_get_Name_Of_Person_Or_Institution (
+	    gc, element, "name-of-person-or-institution");
+    r->extended_postal_delivery_address =
+	ill_get_ILL_String (
+	    gc, element, "extended-postal-delivery-address");
+    r->street_and_number =
+	ill_get_ILL_String (gc, element, "street-and-number");
+    r->post_office_box =
+	ill_get_ILL_String (gc, element, "post-office-box");
+    r->city = ill_get_ILL_String (gc, element, "city");
+    r->region = ill_get_ILL_String (gc, element, "region");
+    r->country = ill_get_ILL_String (gc, element, "country");
+    r->postal_code = ill_get_ILL_String (gc, element, "postal-code");
+    return r;
+}
+
+ILL_System_Address *ill_get_System_Address (
+    struct ill_get_ctl *gc, const char *name, const char *sub)
+{
+    ODR o = gc->odr;
+    ILL_System_Address *r =
+	(ILL_System_Address *) odr_malloc(o, sizeof(*r));
+    char element[128];
+    
+    strcpy(element, name);
+    if (sub)
+    {
+	strcat (element, ",");
+	strcat (element, sub);
+    }
+    r->telecom_service_identifier =
+	ill_get_ILL_String (gc, element, "telecom-service-identifier");
+    r->telecom_service_address =
+	ill_get_ILL_String (gc, element, "telecom-service-addreess");
+    return r;
+}
+
+ILL_Delivery_Address *ill_get_Delivery_Address (
+    struct ill_get_ctl *gc, const char *name, const char *sub)
+{
+    ODR o = gc->odr;
+    ILL_Delivery_Address *r =
+	(ILL_Delivery_Address *) odr_malloc(o, sizeof(*r));
+    char element[128];
+    
+    strcpy(element, name);
+    if (sub)
+    {
+	strcat (element, ",");
+	strcat (element, sub);
+    }
+    r->postal_address =
+	ill_get_Postal_Address (gc, element, "postal-address");
+    r->electronic_address =
+	ill_get_System_Address (gc, element, "electronic-address");
+    return r;
+}
+
+ILL_Search_Type *ill_get_Search_Type (
+    struct ill_get_ctl *gc, const char *name, const char *sub)
+{
+    ODR o = gc->odr;
+    ILL_Search_Type *r = (ILL_Search_Type *) odr_malloc(o, sizeof(*r));
+    char element[128];
+    
+    strcpy(element, name);
+    if (sub)
+    {
+	strcat (element, ",");
+	strcat (element, sub);
+    }
+    r->level_of_service = ill_get_ILL_String (gc, element, "level-of-service");
+    r->need_before_date = ill_get_ILL_ISO_Date (gc, element,
+						"need-before-date", 0);
+    r->expiry_date = ill_get_ILL_ISO_Date (gc, element, "expiry-date", 0);
+    r->expiry_flag = ill_get_enumerated (gc, element, "expiry-flag", 3);
+					 
+    return r;
+}
+
+ILL_Request *ill_get_ILLRequest (
+    struct ill_get_ctl *gc, const char *name, const char *sub)
+{
+    ODR o = gc->odr;
+    ILL_Request *r = (ILL_Request *) odr_malloc(o, sizeof(*r));
+    char element[128];
+    
+    strcpy(element, name);
+    if (sub)
+    {
+	strcat (element, ",");
+	strcat (element, sub);
+    }
+    r->protocol_version_num =
+	ill_get_enumerated (gc, element, "protocol-version-num", 
+			    ILL_Request_version_2);
+    
+    r->transaction_id = ill_get_Transaction_Id (gc, element, "transaction-id");
+    r->service_date_time =
+	ill_get_Service_Date_Time (gc, element, "service-date-time");
+    r->requester_id = ill_get_System_Id (gc, element, "requester-id");
+    r->responder_id = ill_get_System_Id (gc, element, "responder-id");
+    r->transaction_type =
+	ill_get_enumerated(gc, element, "transaction-type", 1);
+
+    r->delivery_address =
+	ill_get_Delivery_Address (gc, element, "delivery-address");
+    r->delivery_service = 0; /* TODO */
+    /* ill_get_Delivery_Service (gc, element, "delivery-service"); */
+    r->billing_address =
+	ill_get_Delivery_Address (gc, element, "billing-address");
+
+    r->num_iLL_service_type = 1;
+    r->iLL_service_type = (ILL_Service_Type **)
+	odr_malloc (o, sizeof(*r->iLL_service_type));
+    *r->iLL_service_type =
+	ill_get_enumerated (gc, element, "ill-service-type",
+			    ILL_Service_Type_copy_non_returnable);
+
+    r->responder_specific_service = 0;
+    r->requester_optional_messages =
+	ill_get_Requester_Optional_Messages_Type (
+	    gc, element,"requester-optional-messages");
+    r->search_type = 0;            /* TODO */
+    r->num_supply_medium_info_type = 0;
+    r->supply_medium_info_type = 0;
+
+    r->place_on_hold = ill_get_enumerated (
+	gc, element, "place-on-hold", 
+	ILL_Place_On_Hold_Type_according_to_responder_policy);
+    r->client_id = ill_get_Client_Id (gc, element, "client-id");
+			   
+    r->item_id = ill_get_Item_Id (gc, element, "item-id");
+    r->supplemental_item_description = 0;
+    r->cost_info_type = 0;
+    r->copyright_compliance =
+	ill_get_ILL_String(gc, element, "copyright-complicance");
+    r->third_party_info_type = 0;
+    r->retry_flag = ill_get_bool (gc, element, "retry-flag", 0);
+    r->forward_flag = ill_get_bool (gc, element, "forward-flag", 0);
+    r->requester_note = ill_get_ILL_String(gc, element, "requester-note");
+    r->forward_note = ill_get_ILL_String(gc, element, "forward-note");
+    r->num_iLL_request_extensions = 0;
+    r->iLL_request_extensions = 0;
+    return r;
+}
Index: /main/tags/2.25/gsdl/packages/yaz/ill/ill.tcl
===================================================================
--- /main/tags/2.25/gsdl/packages/yaz/ill/ill.tcl	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/yaz/ill/ill.tcl	(revision 21064)
@@ -0,0 +1,61 @@
+# Config File for ILL
+# $Id$
+# ----------------------------------------------------------
+# Prefix Specifications
+#  
+#    1: C function prefix
+#    2: C type prefix
+#    3: C preprocessor prefix
+
+# Default prefix
+set default-prefix {ill_ ILL_ ILL_}
+
+# ----------------------------------------------------------
+set m ISO-10161-ILL-1
+
+# Filename
+set filename($m) ill-core
+
+# Header initialization code
+set init($m,h) "
+"
+
+# Header body code
+set body($m,h) "
+#ifdef __cplusplus
+extern \"C\" \{
+#endif
+
+#ifdef __cplusplus
+\}
+#endif
+"
+
+# C body code
+set body($m,c) "
+"
+
+# Some mappings - that map ill_ILL_<name> to ill_<name>
+set map($m,ILL-APDU) APDU
+set map($m,ILL-Request) Request
+set map($m,ILL-Answer) Answer
+set map($m,ILL-String) String
+set map($m,ILL-APDU-Type) APDU_Type
+set map($m,ILL-Service-Type) Service_Type
+set map($m,Service_Date_Time_0) Service_Date_this
+set map($m,Service_Date_Time_1) Service_Date_original
+set map($m,Overdue_0) Overdue_Extension
+
+# ----------------------------------------------------------
+set m Z39.50-extendedService-ItemOrder-ItemRequest-1
+# Filename
+set filename($m) item-req
+
+# Mappings of a few basic types
+proc asnBasicPrintableString {} {
+    return {odr_visiblestring char}
+}
+
+proc asnBasicANY {} {
+    return {odr_any Odr_any}
+}
Index: /main/tags/2.25/gsdl/packages/yaz/ill/ill9702.asn
===================================================================
--- /main/tags/2.25/gsdl/packages/yaz/ill/ill9702.asn	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/yaz/ill/ill9702.asn	(revision 21064)
@@ -0,0 +1,1165 @@
+-- use of parameters and types is to be consistent with their definitions in clause 3
+
+ISO-10161-ILL-1 DEFINITIONS EXPLICIT TAGS ::=
+
+BEGIN
+-- ISO-10161-ILL-1 refers to the ILL ISO standard 10161 version 1
+-- and version 2 as specified in ISO standard 10161 Amendment 1
+
+ILL-APDU ::= CHOICE {
+	ILL-Request,
+	Forward-Notification,
+	Shipped,
+	ILL-Answer,
+	Conditional-Reply,
+	Cancel,
+	Cancel-Reply,
+	Received,
+	Recall,
+	Returned,
+	Checked-In,
+	Overdue,
+	Renew,
+	Renew-Answer,
+	Lost,
+	Damaged,
+	Message,
+	Status-Query,
+	Status-Or-Error-Report,
+	Expired
+	}
+
+-- The tagging scheme used in the APDU definitions is as follows:
+-- each named type that is a component type of an APDU definition is assigned a different tag
+-- that is unique within the set of APDU definitions.  Where these component types themselves
+-- have structure, the tagging within such type definitions has only local scope. 
+
+ILL-Request ::= [APPLICATION 1] SEQUENCE {
+	protocol-version-num	[0]	IMPLICIT INTEGER {
+				version-1 (1),
+				version-2 (2)
+				},
+	transaction-id	[1]	IMPLICIT Transaction-Id,
+	service-date-time	[2]	IMPLICIT Service-Date-Time,
+	requester-id	[3]	IMPLICIT System-Id OPTIONAL,
+		-- mandatory when using store-and-forward communications
+		-- optional when using connection-oriented communications
+	responder-id	[4]	IMPLICIT System-Id OPTIONAL,
+		-- mandatory when using store-and-forward communications
+		-- optional when using connection-oriented communications
+	transaction-type	[5]	IMPLICIT Transaction-Type DEFAULT 1,
+	delivery-address	[6]	IMPLICIT Delivery-Address OPTIONAL, 
+	delivery-service		Delivery-Service OPTIONAL,
+	billing-address	[8]	IMPLICIT Delivery-Address OPTIONAL,
+	iLL-service-type	[9]	IMPLICIT SEQUENCE SIZE (1..5) OF 
+				ILL-Service-Type,
+		-- this sequence is a list, in order of preference
+	responder-specific-service	[10]	EXTERNAL OPTIONAL,
+		-- use direct reference style
+	requester-optional-messages	[11]	IMPLICIT Requester-Optional-Messages-Type,
+	search-type	[12]	IMPLICIT Search-Type OPTIONAL,
+	supply-medium-info-type 	[13]	IMPLICIT SEQUENCE SIZE (1..7) OF
+				Supply-Medium-Info-Type OPTIONAL,
+		-- this sequence is a list, in order of preference,
+		-- with a maximum number of 7 entries
+	place-on-hold	[14]	IMPLICIT Place-On-Hold-Type DEFAULT 3,
+	client-id	[15]	IMPLICIT Client-Id OPTIONAL,     
+	item-id	[16]	IMPLICIT Item-Id,
+	supplemental-item-description	[17]	IMPLICIT Supplemental-Item-Description OPTIONAL,
+	cost-info-type	[18]	IMPLICIT Cost-Info-Type OPTIONAL,
+	copyright-compliance	[19]	ILL-String OPTIONAL,
+	third-party-info-type	[20]	IMPLICIT Third-Party-Info-Type OPTIONAL,
+		-- mandatory when initiating a FORWARD service or an
+		-- ILL-REQUEST service for a partitioned ILL sub-
+		-- transaction or when initiating an ILL-REQUEST service for
+		-- an ILL sub-transaction if the received ILL-REQUEST
+		-- included an "already-tried-list";optional otherwise
+	retry-flag	[21]	IMPLICIT BOOLEAN DEFAULT FALSE,
+	forward-flag	[22]	IMPLICIT BOOLEAN DEFAULT FALSE,
+	requester-note	[46]	ILL-String OPTIONAL,
+	forward-note	[47]	ILL-String OPTIONAL,
+	iLL-request-extensions 	[49]	IMPLICIT SEQUENCE OF Extension OPTIONAL
+ 	}
+
+Forward-Notification ::= [APPLICATION 2] SEQUENCE {
+	protocol-version-num	[0]	IMPLICIT INTEGER {
+				version-1 (1),
+				version-2 (2)
+				},
+	transaction-id	[1]	IMPLICIT Transaction-Id,   
+	service-date-time	[2]	IMPLICIT Service-Date-Time,
+	requester-id	[3]	IMPLICIT System-Id OPTIONAL,
+		-- mandatory when using store-and-forward communications
+		-- optional when using connection-oriented communications
+	responder-id	[4]	IMPLICIT System-Id,
+		-- mandatory in this APDU
+	responder-address	[24]	IMPLICIT System-Address OPTIONAL,
+	intermediary-id	[25]	IMPLICIT System-Id,
+	notification-note	[48]	ILL-String OPTIONAL,
+	forward-notification-extensions	[49]	IMPLICIT SEQUENCE OF Extension OPTIONAL
+	}
+
+Shipped ::= [APPLICATION 3] SEQUENCE {
+	protocol-version-num	[0]	IMPLICIT INTEGER {
+				version-1 (1),
+				version-2 (2)
+				},
+	transaction-id	[1]	IMPLICIT Transaction-Id,   
+	service-date-time	[2]	IMPLICIT Service-Date-Time,
+	requester-id	[3]	IMPLICIT System-Id OPTIONAL,
+		-- mandatory when using store-and-forward communications
+		-- optional when using connection-oriented communications
+	responder-id	[4]	IMPLICIT System-Id OPTIONAL,
+		-- mandatory when using store-and-forward communications
+		-- optional when using connection-oriented communications
+	responder-address	[24]	IMPLICIT System-Address OPTIONAL,
+	intermediary-id	[25]	IMPLICIT System-Id OPTIONAL,
+	supplier-id	[26]	IMPLICIT System-Id OPTIONAL,
+	client-id	[15]	IMPLICIT Client-Id OPTIONAL,
+	transaction-type	[5]	IMPLICIT Transaction-Type DEFAULT 1,
+	supplemental-item-description	[17]	IMPLICIT Supplemental-Item-Description OPTIONAL,
+	shipped-service-type	[27]	IMPLICIT Shipped-Service-Type,
+	responder-optional-messages	[28]	IMPLICIT Responder-Optional-Messages-Type
+				OPTIONAL,
+	supply-details	[29]	IMPLICIT Supply-Details,
+	return-to-address	[30]	IMPLICIT Postal-Address OPTIONAL,
+	responder-note	[46]	ILL-String OPTIONAL,
+	shipped-extensions	[49]	IMPLICIT SEQUENCE OF Extension OPTIONAL
+	}
+
+ILL-Answer ::= [APPLICATION 4] SEQUENCE {
+	protocol-version-num	[0]	IMPLICIT INTEGER {
+				version-1 (1),
+				version-2 (2)
+				},
+	transaction-id	[1]	IMPLICIT Transaction-Id,
+	service-date-time	[2]	IMPLICIT Service-Date-Time,
+	requester-id	[3]	IMPLICIT System-Id OPTIONAL,
+		-- mandatory when using store-and-forward communications
+		-- optional when using connection-oriented communications
+	responder-id	[4]	IMPLICIT System-Id OPTIONAL,
+		-- mandatory when using store-and-forward communications
+		-- optional when using connection-oriented communications
+	transaction-results	[31]	IMPLICIT Transaction-Results,
+	results-explanation	[32]	CHOICE {
+				conditional-results	[1] Conditional-Results,
+				-- chosen if transaction-results=CONDITIONAL
+				retry-results		[2] Retry-Results,
+				-- chosen if transaction-results=RETRY
+				unfilled-results	[3] Unfilled-Results,
+				--chosen if transaction-results=UNFILLED
+				locations-results	[4] Locations-Results,
+				-- chosen if transaction-results=LOCATIONS-PROVIDED
+	 			will-supply-results	[5] Will-Supply-Results,
+				-- chosen if transaction-results=WILL-SUPPLY
+				hold-placed-results	[6] Hold-Placed-Results,
+				-- chosen if transaction-results=HOLD-PLACED
+				estimate-results	[7] Estimate-Results
+				-- chosen if transaction-results=ESTIMATE
+				} OPTIONAL,
+		-- optional if transaction-results equals RETRY, UNFILLED,
+		-- WILL-SUPPLY or HOLD-PLACED;
+		-- required if transaction-results equals CONDITIONAL,
+		-- LOCATIONS-PROVIDED or ESTIMATE
+	responder-specific-results	[33]	EXTERNAL OPTIONAL,
+		-- this type is mandatory if results-explanation
+		-- chosen for any result 
+		-- has the value "responder-specific".
+	supplemental-item-description	[17]	IMPLICIT Supplemental-Item-Description OPTIONAL,
+	send-to-list	[23]	IMPLICIT Send-To-List-Type OPTIONAL,
+	already-tried-list	[34]	IMPLICIT Already-Tried-List-Type OPTIONAL,
+	responder-optional-messages	[28]	IMPLICIT Responder-Optional-Messages-Type
+				OPTIONAL,
+	responder-note	[46]	ILL-String OPTIONAL,
+	ill-answer-extensions	[49]	IMPLICIT SEQUENCE OF Extension OPTIONAL
+	}
+
+Conditional-Reply ::= [APPLICATION 5] SEQUENCE {
+	protocol-version-num	[0]	IMPLICIT INTEGER {
+				version-1 (1),
+				version-2 (2)
+				},
+	transaction-id	[1]	IMPLICIT Transaction-Id,
+	service-date-time	[2]	IMPLICIT Service-Date-Time,
+	requester-id	[3]	IMPLICIT System-Id OPTIONAL,
+		-- mandatory when using store-and-forward communications
+		-- optional when using connection-oriented communications
+	responder-id	[4]	IMPLICIT System-Id OPTIONAL,
+		-- mandatory when using store-and-forward communications
+		-- optional when using connection-oriented communications
+	answer	[35]	IMPLICIT BOOLEAN,
+	requester-note	[46]	ILL-String OPTIONAL,
+	conditional-reply-extensions	[49]	IMPLICIT SEQUENCE OF Extension OPTIONAL
+	}
+
+Cancel ::= [APPLICATION 6] SEQUENCE {
+	protocol-version-num	[0]	IMPLICIT INTEGER {
+				version-1 (1),
+				version-2 (2)
+				},
+	transaction-id	[1]	IMPLICIT Transaction-Id,
+	service-date-time	[2]	IMPLICIT Service-Date-Time,
+	requester-id	[3]	IMPLICIT System-Id OPTIONAL,
+		-- mandatory when using store-and-forward communications
+		-- optional when using connection-oriented communications
+	responder-id	[4]	IMPLICIT System-Id OPTIONAL,
+		-- mandatory when using store-and-forward communications
+		-- optional when using connection-oriented communications
+	requester-note	[46]	ILL-String OPTIONAL,
+	cancel-extensions	[49]	IMPLICIT SEQUENCE OF Extension OPTIONAL
+	}
+
+Cancel-Reply ::= [APPLICATION 7] SEQUENCE {
+	protocol-version-num	[0]	IMPLICIT INTEGER {
+				 version-1 (1),
+				 version-2 (2)
+				 },
+	transaction-id	[1]	IMPLICIT Transaction-Id,
+	service-date-time	[2]	IMPLICIT Service-Date-Time,
+	requester-id	[3]	IMPLICIT System-Id OPTIONAL,
+		-- mandatory when using store-and-forward communications
+		-- optional when using connection-oriented communications
+	responder-id	[4]	IMPLICIT System-Id OPTIONAL,
+		-- mandatory when using store-and-forward communications
+		-- optional when using connection-oriented communications
+	answer	[35]	IMPLICIT BOOLEAN,
+	responder-note	[46]	ILL-String OPTIONAL,
+	cancel-reply-extensions	[49]	IMPLICIT SEQUENCE OF Extension OPTIONAL
+	}
+
+Received ::= [APPLICATION 8] SEQUENCE { 
+	protocol-version-num	[0]	IMPLICIT INTEGER {
+			 version-1 (1),
+			 version-2 (2)
+			 },
+	transaction-id	[1]	IMPLICIT Transaction-Id,
+	service-date-time	[2]	IMPLICIT Service-Date-Time,
+	requester-id	[3]	IMPLICIT System-Id OPTIONAL,
+		-- mandatory when using store-and-forward communications
+		-- optional when using connection-oriented communications
+	responder-id	[4]	IMPLICIT System-Id OPTIONAL,
+		-- mandatory when using store-and-forward communications
+		-- optional when using connection-oriented communications
+	supplier-id	[26]	IMPLICIT System-Id OPTIONAL,
+	supplemental-item-description	[17]	IMPLICIT Supplemental-Item-Description OPTIONAL,
+	date-received	[36]	IMPLICIT ISO-Date,
+	shipped-service-type	[27]	IMPLICIT Shipped-Service-Type,
+	requester-note	[46]	ILL-String OPTIONAL,
+	received-extensions	[49]	IMPLICIT SEQUENCE OF Extension OPTIONAL
+	}
+
+Recall ::= [APPLICATION 9] SEQUENCE {  
+	protocol-version-num	[0]	IMPLICIT INTEGER {
+				version-1 (1),
+				version-2 (2)
+				},
+	transaction-id	[1]	IMPLICIT Transaction-Id,   
+	service-date-time	[2]	IMPLICIT Service-Date-Time,
+	requester-id	[3]	IMPLICIT System-Id OPTIONAL, 
+		-- mandatory when using store-and-forward communications
+		-- optional when using connection-oriented communications
+	responder-id	[4]	IMPLICIT System-Id OPTIONAL, 
+		-- mandatory when using store-and-forward communications
+		-- optional when using connection-oriented communications
+	responder-note	[46]	ILL-String OPTIONAL,
+	recall-extensions	[49]	IMPLICIT SEQUENCE OF Extension OPTIONAL
+	}
+
+Returned ::= [APPLICATION 10] SEQUENCE { 
+	protocol-version-num	[0]	IMPLICIT INTEGER {
+				version-1 (1),
+				version-2 (2)
+				},
+	transaction-id	[1]	IMPLICIT Transaction-Id,
+	service-date-time	[2]	IMPLICIT Service-Date-Time,
+	requester-id	[3]	IMPLICIT System-Id OPTIONAL,
+		-- mandatory when using store-and-forward communications
+		-- optional when using connection-oriented communications
+	responder-id	[4]	IMPLICIT System-Id OPTIONAL,
+		-- mandatory when using store-and-forward communications
+		-- optional when using connection-oriented communications
+	supplemental-item-description	[17]	IMPLICIT Supplemental-Item-Description OPTIONAL,
+	date-returned	[37]	IMPLICIT ISO-Date,
+	returned-via	[38]	Transportation-Mode OPTIONAL,
+	insured-for	[39]	IMPLICIT Amount OPTIONAL,
+	requester-note	[46]	ILL-String OPTIONAL,
+	returned-extensions	[49]	IMPLICIT SEQUENCE OF Extension OPTIONAL
+	}
+
+Checked-In ::= [APPLICATION 11] SEQUENCE {
+	protocol-version-num	[0]	IMPLICIT INTEGER {
+				version-1 (1),
+				version-2 (2)
+				},
+	transaction-id	[1]	IMPLICIT Transaction-Id,   
+	service-date-time	[2]	IMPLICIT Service-Date-Time,
+	requester-id	[3]	IMPLICIT System-Id OPTIONAL, 
+		-- mandatory when using store-and-forward communications
+		-- optional when using connection-oriented communications
+	responder-id	[4]	IMPLICIT System-Id OPTIONAL, 
+		-- mandatory when using store-and-forward communications
+		-- optional when using connection-oriented communications
+	date-checked-in	[40]	IMPLICIT ISO-Date,
+	responder-note	[46]	ILL-String OPTIONAL,
+	checked-in-extensions	[49]	IMPLICIT SEQUENCE OF Extension OPTIONAL
+	}
+
+Overdue ::= [APPLICATION 12] SEQUENCE { 
+	protocol-version-num	[0]	IMPLICIT INTEGER {
+				version-1 (1),
+				version-2 (2)
+				},
+	transaction-id	[1]	IMPLICIT Transaction-Id,
+	service-date-time	[2]	IMPLICIT Service-Date-Time,
+	requester-id	[3]	IMPLICIT System-Id OPTIONAL,
+		-- mandatory when using store-and-forward communications
+		-- optional when using connection-oriented communications
+	responder-id	[4]	IMPLICIT System-Id OPTIONAL,
+		-- mandatory when using store-and-forward communications
+		-- optional when using connection-oriented communications
+	date-due	[41]	IMPLICIT Date-Due,
+	responder-note	[46]	ILL-String OPTIONAL,
+	overdue-extensions	[49]	SEQUENCE OF Extension OPTIONAL
+	}
+
+Renew ::= [APPLICATION 13] SEQUENCE {
+	protocol-version-num	[0]	IMPLICIT INTEGER {
+				version-1 (1),
+				version-2 (2)
+				},
+	transaction-id	[1]	IMPLICIT Transaction-Id,   
+	service-date-time	[2]	IMPLICIT Service-Date-Time,
+	requester-id	[3]	IMPLICIT System-Id OPTIONAL,   
+		-- mandatory when using store-and-forward communications
+		-- optional when using connection-oriented communications
+	responder-id	[4]	IMPLICIT System-Id OPTIONAL,   
+		-- mandatory when using store-and-forward communications
+		-- optional when using connection-oriented communications
+	desired-due-date	[42]	IMPLICIT ISO-Date OPTIONAL,
+	requester-note	[46]	ILL-String OPTIONAL,
+	renew-extensions	[49]	IMPLICIT SEQUENCE OF Extension OPTIONAL
+	}
+
+Renew-Answer ::= [APPLICATION 14] SEQUENCE {
+	protocol-version-num	[0]	IMPLICIT INTEGER {
+				version-1 (1),
+				version-2 (2)
+				},
+	transaction-id	[1]	IMPLICIT Transaction-Id,   
+	service-date-time	[2]	IMPLICIT Service-Date-Time,
+	requester-id	[3]	IMPLICIT System-Id OPTIONAL,   
+		-- mandatory when using store-and-forward communications
+		-- optional when using connection-oriented communications
+	responder-id	[4]	IMPLICIT System-Id OPTIONAL,   
+		-- mandatory when using store-and-forward communications
+		-- optional when using connection-oriented communications
+	answer	[35]	IMPLICIT BOOLEAN,
+	date-due	[41]	IMPLICIT Date-Due OPTIONAL,
+	responder-note	[46]	ILL-String OPTIONAL,
+	renew-answer-extensions	[49]	IMPLICIT SEQUENCE OF Extension OPTIONAL
+	}
+
+Lost ::= [APPLICATION 15] SEQUENCE {
+	protocol-version-num	[0]	IMPLICIT INTEGER {
+				version-1 (1),
+				version-2 (2)
+				},
+	transaction-id	[1]	IMPLICIT Transaction-Id,   
+	service-date-time	[2]	IMPLICIT Service-Date-Time,
+	requester-id	[3]	IMPLICIT System-Id OPTIONAL,   
+		-- mandatory when using store-and-forward communications
+		-- optional when using connection-oriented communications
+	responder-id	[4]	IMPLICIT System-Id OPTIONAL,   
+		-- mandatory when using store-and-forward communications
+		-- optional when using connection-oriented communications
+	note	[46]	ILL-String OPTIONAL,
+	lost-extensions	[49]	IMPLICIT SEQUENCE OF Extension OPTIONAL
+	}
+
+Damaged ::= [APPLICATION 16] SEQUENCE { 
+	protocol-version-num	[0]	IMPLICIT INTEGER {
+				version-1 (1),
+				version-2 (2)
+				},
+	transaction-id	[1]	IMPLICIT Transaction-Id,
+	service-date-time	[2]	IMPLICIT Service-Date-Time,
+	requester-id	[3]	IMPLICIT System-Id OPTIONAL,
+		-- mandatory when using store-and-forward communications
+		-- optional when using connection-oriented communications
+	responder-id	[4]	IMPLICIT System-Id OPTIONAL, 
+		-- mandatory when using store-and-forward communications
+		-- optional when using connection-oriented communications
+	damaged-details	[5]	IMPLICIT Damaged-Details OPTIONAL,
+		-- this parameter may only be present in APDU's with a
+		-- protocol-version-num value of 2 or greater
+	note	[46]	ILL-String OPTIONAL,
+	damaged-extensions	[49]	IMPLICIT SEQUENCE OF Extension OPTIONAL
+	}
+
+Message ::= [APPLICATION 17] SEQUENCE { 
+	protocol-version-num	[0]	IMPLICIT INTEGER {
+				version-1 (1),
+				version-2 (2)
+				},
+	transaction-id	[1]	IMPLICIT Transaction-Id,   
+	service-date-time	[2]	IMPLICIT Service-Date-Time,
+	requester-id	[3]	IMPLICIT System-Id OPTIONAL,   
+		-- mandatory when using store-and-forward communications
+		-- optional when using connection-oriented communications
+	responder-id	[4]	IMPLICIT System-Id OPTIONAL,   
+		-- mandatory when using store-and-forward communications
+		-- optional when using connection-oriented communications
+	note	[46]	ILL-String,
+	message-extensions	[49]	IMPLICIT SEQUENCE OF Extension OPTIONAL
+	}
+
+Status-Query ::= [APPLICATION 18] SEQUENCE {
+	protocol-version-num	[0]	IMPLICIT INTEGER {
+				version-1 (1),
+				version-2 (2)
+				},
+	transaction-id	[1]	IMPLICIT Transaction-Id,
+	service-date-time	[2]	IMPLICIT Service-Date-Time,
+	requester-id	[3]	IMPLICIT System-Id OPTIONAL,
+		-- mandatory when using store-and-forward communications
+		-- optional when using connection-oriented communications
+	responder-id	[4]	IMPLICIT System-Id OPTIONAL,
+		-- mandatory when using store-and-forward communications
+		-- optional when using connection-oriented communications
+	note	[46]	ILL-String OPTIONAL,
+	status-query-extensions	[49]	IMPLICIT SEQUENCE OF Extension OPTIONAL
+	}
+
+Status-Or-Error-Report ::= [APPLICATION 19] SEQUENCE {
+	protocol-version-num	[0]	IMPLICIT INTEGER {
+				version-1 (1),
+				version-2 (2)
+				},
+	transaction-id	[1]	IMPLICIT Transaction-Id,   
+	service-date-time	[2]	IMPLICIT Service-Date-Time,
+	requester-id	[3]	IMPLICIT System-Id OPTIONAL,   
+		-- mandatory when using store-and-forward communications
+		-- optional when using connection-oriented communications
+	responder-id	[4]	IMPLICIT System-Id OPTIONAL,
+		-- mandatory when using store-and-forward communications
+		-- optional when using connection-oriented communications
+	reason-no-report	[43]	IMPLICIT Reason-No-Report OPTIONAL,
+		-- mandatory if no report is present;
+		-- not present otherwise
+	status-report	[44]	IMPLICIT Status-Report OPTIONAL,
+	error-report	[45]	IMPLICIT Error-Report OPTIONAL,
+	note	[46]	ILL-String OPTIONAL,
+	status-or-error-report-extensions	[49]	IMPLICIT SEQUENCE OF Extension OPTIONAL
+	}
+
+Expired ::= [APPLICATION 20] SEQUENCE {
+	protocol-version-num	[0]	IMPLICIT INTEGER {
+				version-1 (1),
+				version-2 (2)
+				},
+	transaction-id	[1]	IMPLICIT Transaction-Id,
+	service-date-time	[2]	IMPLICIT Service-Date-Time,
+	requester-id	[3]	IMPLICIT System-Id OPTIONAL,
+		-- mandatory when using store-and-forward communications
+		-- optional when using connection-oriented communications
+	responder-id	[4]	IMPLICIT System-Id OPTIONAL,
+		-- mandatory when using store-and-forward communications
+		-- optional when using connection-oriented communications
+	expired-extensions	[49]	IMPLICIT SEQUENCE OF Extension OPTIONAL
+	}
+
+Account-Number ::= ILL-String
+
+Already-Forwarded ::= SEQUENCE {
+	responder-id	[0]	IMPLICIT System-Id,
+	responder-address	[1]	IMPLICIT System-Address OPTIONAL
+	}	
+
+Already-Tried-List-Type ::= SEQUENCE OF System-Id
+
+Amount ::= SEQUENCE {
+	currency-code	[0]	IMPLICIT PrintableString (SIZE (3)) OPTIONAL,
+		-- values defined in ISO 4217-1981
+	monetary-value	[1]	IMPLICIT AmountString (SIZE (1..10))
+	}
+
+AmountString ::= PrintableString (FROM ("1"|"2"|"3"|"4"|"5"|"6"|"7"|"8"|"9"|"0"|" "|"."|","))
+
+Client-Id ::= SEQUENCE {
+	client-name	[0]	ILL-String OPTIONAL,
+	client-status	[1]	ILL-String OPTIONAL,
+	client-identifier	[2]	ILL-String OPTIONAL
+	}
+
+Conditional-Results ::= SEQUENCE {
+	conditions	[0]	IMPLICIT ENUMERATED {
+				cost-exceeds-limit 				(13),
+				charges 					(14),
+				prepayment-required 			(15),
+				lacks-copyright-compliance 			(16),
+				library-use-only 				(22),
+				no-reproduction 				(23),
+				client-signature-required 			(24),
+				special-collections-supervision-required	(25),
+				other 					(27),
+				responder-specific 				(28),
+				proposed-delivery-service 			(30) 
+				},
+	date-for-reply	[1]	IMPLICIT ISO-Date OPTIONAL,
+	locations	[2]	IMPLICIT SEQUENCE OF Location-Info OPTIONAL,
+	proposed-delivery-service		Delivery-Service OPTIONAL
+		-- this parameter specifies a proposed delivery service the
+		-- acceptance of which is a condition of supply.  It may be a
+		-- physical service or an electronic service.  This parameter
+		-- may only be present in APDUs with a 
+		-- protocol-version-num value of 2 or greater
+	}
+
+Cost-Info-Type ::= SEQUENCE {
+	account-number	[0]	Account-Number OPTIONAL,
+	maximum-cost	[1]	IMPLICIT Amount OPTIONAL,
+	reciprocal-agreement	[2]	IMPLICIT BOOLEAN DEFAULT FALSE,
+	will-pay-fee	[3]	IMPLICIT BOOLEAN DEFAULT FALSE,
+	payment-provided	[4]	IMPLICIT BOOLEAN DEFAULT FALSE
+	}
+
+Current-State ::= ENUMERATED {
+	nOT-SUPPLIED 	(1),
+	pENDING	(2),
+	iN-PROCESS	(3),
+	fORWARD	(4),
+	cONDITIONAL	(5),
+	cANCEL-PENDING 	(6),
+	cANCELLED	(7),
+	sHIPPED 	(8),
+	rECEIVED 	(9),
+	rENEW-PENDING 	(10),
+	nOT-RECEIVED-OVERDUE	(11),
+	rENEW-OVERDUE 	(12),
+	oVERDUE 	(13),
+	rETURNED 	(14),
+	cHECKED-IN	(15),
+	rECALL 	(16),
+	lOST 	(17),
+	uNKNOWN 	(18)
+	}
+
+Damaged-Details ::= SEQUENCE {
+	document-type-id	[0]	IMPLICIT OBJECT IDENTIFIER OPTIONAL,
+		-- identifies an OSI document type registered in accordance
+		-- with ISO 9834-2, for use in an automated environment
+	damaged-portion		CHOICE {
+				complete-document	[1]	IMPLICIT NULL,
+				specific-units	[2]	IMPLICIT SEQUENCE 
+									OF INTEGER
+				-- the nature and extent of a "unit" is implicit in the
+				-- value of document-type-id if one is supplied
+				}
+	}
+
+Date-Due ::= SEQUENCE {
+	date-due-field	[0]	IMPLICIT ISO-Date,
+	renewable	[1]	IMPLICIT BOOLEAN DEFAULT TRUE
+	}
+
+Delivery-Address ::= SEQUENCE {
+	postal-address	[0]	IMPLICIT Postal-Address OPTIONAL,
+	electronic-address	[1]	IMPLICIT System-Address OPTIONAL
+	}
+
+Delivery-Service ::= CHOICE {
+	physical-delivery	[7]	Transportation-Mode,
+	electronic-delivery	[50]	IMPLICIT SEQUENCE OF Electronic-Delivery-Service
+		-- electronic-delivery may only be present in APDUs
+		-- with a protocol-version-num value of 2 or greater
+	}
+
+Electronic-Delivery-Service ::= SEQUENCE {
+	-- the first four parameters are intended to be used in an automated
+	-- environment
+		e-delivery-service	[0] IMPLICIT SEQUENCE {
+		-- identifies the kind of electronic delivery service, e.g.
+		-- MOTIS IPM,FTAM, etc., using the assigned object
+		-- identifier for the standard e.g. {joint-iso-ccitt mhs-motis 
+		-- ipms}
+			e-delivery-mode	[0] IMPLICIT OBJECT IDENTIFIER,
+			e-delivery-parameters	[1] ANY DEFINED BY e-delivery-mode
+			} OPTIONAL,
+		document-type		[1] IMPLICIT SEQUENCE {
+			document-type-id		[2] IMPLICIT OBJECT IDENTIFIER,
+			-- identifies an OSI document type registered in accordance
+			-- with ISO 9834-2
+			document-type-parameters	[3] ANY DEFINED BY document-type-id
+			-- any parameters relating to the registered document type
+			} OPTIONAL,
+		e-delivery-description		[4] ILL-String OPTIONAL,
+		-- holds a human readable name or description of the
+		-- required electronic delivery service and document type;
+		-- this may also be used to identify an electronic delivery
+		-- service for which there is no object identifier.
+		-- This parameter may be present instead of, or in addition
+		-- to, the previous 4 parameters
+		e-delivery-details		[5] CHOICE {
+			e-delivery-address	[0] IMPLICIT System-Address,
+			e-delivery-id		[1] IMPLICIT System-Id
+			},
+		name-or-code		[6] ILL-String OPTIONAL,
+		-- holds a human-readable identifier or correlation
+		-- information for the document as shipped, e.g. a directory 
+		-- and/or file name or message-id
+		delivery-time		[7] IMPLICIT ISO-Time OPTIONAL
+		-- holds the requester's preferred delivery time or
+		-- the responder's proposed or actual delivery time
+		}
+
+Error-Report ::= SEQUENCE {
+	correlation-information	[0]	ILL-String,
+	report-source	[1]	IMPLICIT Report-Source,
+	user-error-report	[2]	User-Error-Report OPTIONAL,
+		-- mandatory if report-source is "user"; not present otherwise
+	provider-error-report	[3]	Provider-Error-Report OPTIONAL
+		-- mandatory if report-source is "provider"; not
+		-- present otherwise
+	}
+
+Estimate-Results ::= SEQUENCE {
+	cost-estimate	[0]	ILL-String,
+	locations	[1]	IMPLICIT SEQUENCE OF Location-Info OPTIONAL
+	}
+
+Extension ::= SEQUENCE {
+	identifier	[0]	IMPLICIT INTEGER,
+	critical	[1]	IMPLICIT BOOLEAN DEFAULT FALSE,
+	item	[2]	ANY DEFINED BY identifier
+	}
+
+General-Problem ::= ENUMERATED {
+	unrecognized-APDU 	(1),
+	mistyped-APDU 	(2),
+	badly-structured-APDU 	(3),
+	protocol-version-not-supported 	(4),
+	other 	(5)
+	}
+
+History-Report ::= SEQUENCE {
+	date-requested	[0]	IMPLICIT ISO-Date OPTIONAL,
+	author	[1]	ILL-String OPTIONAL,
+	title	[2]	ILL-String OPTIONAL,
+	author-of-article	[3]	ILL-String OPTIONAL,
+	title-of-article	[4]	ILL-String OPTIONAL,
+	date-of-last-transition 	[5]	IMPLICIT ISO-Date,
+	most-recent-service	[6]	IMPLICIT ENUMERATED {
+				iLL-REQUEST			(1),
+				fORWARD 				(21),
+				fORWARD-NOTIFICATION 		(2),
+				sHIPPED 				(3),
+				iLL-ANSWER 			(4),
+				cONDITIONAL-REPLY 		(5),
+				cANCEL 				(6),
+				cANCEL-REPLY 			(7),
+				rECEIVED 				(8),
+				rECALL 				(9),
+				rETURNED 				(10),
+				cHECKED-IN 			(11),
+				rENEW-ANSWER 			(14),
+				lOST 				(15),
+				dAMAGED 				(16),
+				mESSAGE 				(17),
+				sTATUS-QUERY 			(18),
+				sTATUS-OR-ERROR-REPORT	(19),
+				eXPIRED 				(20)
+				},
+	date-of-most-recent-service	[7]	IMPLICIT ISO-Date,
+	initiator-of-most-recent-service	[8]	IMPLICIT System-Id,
+	shipped-service-type	[9]	IMPLICIT Shipped-Service-Type OPTIONAL,
+		-- If the information is available, i.e. if a SHIPPED or
+		-- RECEIVED APDU has been sent or received, then the
+		-- value in this parameter shall be supplied.
+		-- Value must contain the most current information, e.g. if a
+		-- requester has received a SHIPPED APDU and then
+		-- invokes a RECEIVED.request, then the value from the
+		-- RECEIVED.request is used
+	transaction-results	[10]	IMPLICIT Transaction-Results OPTIONAL,
+		-- If the information is available, i.e. if an ILL-ANWSER
+		-- APDU has been sent or received, then the value in this
+		-- parameter shall be supplied.
+	most-recent-service-note	[11]	ILL-String OPTIONAL
+		-- If the information is available, i.e. if a note has been
+		-- supplied in the most recent service primitive, then the
+		-- value in this parameter shall be supplied.
+	}
+
+Hold-Placed-Results ::= SEQUENCE {
+	estimated-date-available	[0]	IMPLICIT ISO-Date,
+	hold-placed-medium-type	[1]	IMPLICIT Medium-Type OPTIONAL,
+	locations	[2]	IMPLICIT SEQUENCE OF Location-Info OPTIONAL
+	}
+
+ILL-APDU-Type ::= ENUMERATED {
+	iLL-REQUEST 	(1),
+	fORWARD-NOTIFICATION 	(2),
+	sHIPPED 	(3),
+	iLL-ANSWER 	(4),
+	cONDITIONAL-REPLY 	(5),
+	cANCEL 	(6),
+	cANCEL-REPLY 	(7),
+	rECEIVED 	(8),
+	rECALL 	(9),
+	rETURNED 	(10),
+	cHECKED-IN 	(11),
+	oVERDUE 	(12),
+	rENEW 	(13),
+	rENEW-ANSWER 	(14),
+	lOST 	(15),
+	dAMAGED 	(16),
+	mESSAGE 	(17),
+	sTATUS-QUERY 	(18),
+	sTATUS-OR-ERROR-REPORT	(19),
+	eXPIRED 	(20)
+	}
+
+ILL-Service-Type ::= ENUMERATED  {
+	loan 	(1),
+	copy-non-returnable 	(2),
+	locations 	(3),
+	estimate 	(4),
+	responder-specific 	(5)
+	}
+
+ILL-String ::= CHOICE {
+	GeneralString,
+	-- may contain any ISO registered G (graphic) and C
+	-- (control) character set
+	EDIFACTString
+	}
+	-- may not include leading or trailing spaces
+	-- may not consist only of space (" ") or non-printing 
+	-- characters
+
+Intermediary-Problem ::= ENUMERATED {
+	cannot-send-onward 	(1)
+	}
+
+ISO-Date ::= VisibleString
+	-- conforms to ISO 8601
+	-- length = 8
+	-- fixed
+	-- YYYYMMDD
+
+ISO-Time ::= VisibleString
+	-- conforms to ISO 8601
+	-- length = 6, 
+	-- fixed
+	-- HHMMSS
+	-- local time of person or institution invoking service
+
+Item-Id ::= SEQUENCE {
+	item-type	[0]	IMPLICIT ENUMERATED {
+				monograph	(1),
+				serial 	(2),
+				other	(3)
+				} OPTIONAL,
+	held-medium-type	[1]	IMPLICIT Medium-Type OPTIONAL,
+	call-number	[2]	ILL-String OPTIONAL,
+	author	[3]	ILL-String OPTIONAL,
+	title	[4]	ILL-String OPTIONAL,
+	sub-title	[5]	ILL-String OPTIONAL,
+	sponsoring-body	[6]	ILL-String OPTIONAL,
+	place-of-publication 	[7]	ILL-String OPTIONAL,
+	publisher	[8]	ILL-String OPTIONAL,
+	series-title-number 	[9]	ILL-String OPTIONAL,
+	volume-issue	[10]	ILL-String OPTIONAL,
+	edition	[11]	ILL-String OPTIONAL,
+	publication-date	[12]	ILL-String OPTIONAL,
+	publication-date-of-component	[13] ILL-String OPTIONAL,
+	author-of-article	[14]	ILL-String OPTIONAL,
+	title-of-article	[15]	ILL-String OPTIONAL,
+	pagination	[16]	ILL-String OPTIONAL,
+	national-bibliography-no	[17]	EXTERNAL OPTIONAL,
+	iSBN	[18]	ILL-String (SIZE (10)) OPTIONAL,
+		-- must conform to ISO 2108-1978
+	iSSN	[19]	ILL-String (SIZE (8)) OPTIONAL,
+		-- must conform to ISO 3297-1986
+	system-no	[20]	EXTERNAL OPTIONAL,
+	additional-no-letters	[21] ILL-String OPTIONAL,
+	verification-reference-source	[22] ILL-String OPTIONAL
+	}
+
+Location-Info ::= SEQUENCE {
+	location-id	[0]	IMPLICIT System-Id,
+	location-address	[1]	IMPLICIT System-Address OPTIONAL,
+	location-note	[2]	ILL-String OPTIONAL
+	}
+
+Locations-Results ::= SEQUENCE {
+	reason-locs-provided	[0]	IMPLICIT Reason-Locs-Provided OPTIONAL,
+	locations	[1]	IMPLICIT SEQUENCE OF Location-Info
+	}
+
+Medium-Type ::= ENUMERATED {
+	printed 	(1),
+	microform 	(3),
+	film-or-video-recording	(4),
+	audio-recording 	(5),
+	machine-readable 	(6),
+	other 	(7)
+	}
+
+Name-Of-Person-Or-Institution ::= CHOICE {
+	name-of-person	[0]	ILL-String,
+	name-of-institution	[1]	ILL-String
+	}
+
+Person-Or-Institution-Symbol ::= CHOICE {
+	person-symbol	[0]	ILL-String,
+	institution-symbol	[1]	ILL-String
+	}
+
+Place-On-Hold-Type ::= ENUMERATED {
+	yes 	(1),
+	no 	(2),
+	according-to-responder-policy	(3)
+	}
+
+Postal-Address ::= SEQUENCE {
+	name-of-person-or-institution	[0]	Name-Of-Person-Or-Institution OPTIONAL,
+	extended-postal-delivery-address [1]	ILL-String OPTIONAL,
+	street-and-number	[2]	ILL-String OPTIONAL,
+	post-office-box	[3]	ILL-String OPTIONAL,
+	city	[4]	ILL-String OPTIONAL,
+	region	[5]	ILL-String OPTIONAL,
+	country	[6]	ILL-String OPTIONAL,
+	postal-code	[7]	ILL-String OPTIONAL
+	}
+
+Provider-Error-Report ::= CHOICE {
+	general-problem	[0]	IMPLICIT General-Problem,
+	transaction-id-problem 	[1]	IMPLICIT Transaction-Id-Problem,
+	state-transition-prohibited	[2]	IMPLICIT State-Transition-Prohibited
+	}
+
+Reason-Locs-Provided ::= ENUMERATED {
+	in-use-on-loan 	(1),
+	in-process 	(2),
+	lost 	(3),
+	non-circulating 	(4),
+	not-owned 	(5),
+	on-order 	(6),
+	volume-issue-not-yet-available 	(7),
+	at-bindery 	(8),
+	lacking 	(9),
+	not-on-shelf 	(10),
+	on-reserve 	(11),
+	poor-condition 	(12),
+	cost-exceeds-limit 	(13),
+	on-hold 	(19),
+	other 	(27),
+	responder-specific 	(28) 
+	}
+
+Reason-No-Report ::= ENUMERATED {
+	temporary	(1),
+	permanent	(2)
+	}
+
+Reason-Unfilled ::= ENUMERATED {
+	in-use-on-loan	(1),
+	in-process	(2),
+	lost	(3),
+	non-circulating	(4),
+	not-owned	(5),
+	on-order	(6),
+	volume-issue-not-yet-available	(7),
+	at-bindery	(8),
+	lacking	(9),
+	not-on-shelf 	(10),
+	on-reserve	(11),
+	poor-condition	(12),
+	cost-exceeds-limit	(13),
+	charges	(14),
+	prepayment-required	(15),
+	lacks-copyright-compliance	(16),
+	not-found-as-cited	(17),
+	locations-not-found	(18),
+	on-hold	(19),
+	policy-problem	(20),
+	mandatory-messaging-not-supported	(21),
+	expiry-not-supported	(22) ,
+	requested-delivery-services-not-supported	(23),
+ 	preferred-delivery-time-not-possible	(24),
+	other	(27),
+	responder-specific	(28)
+	}
+
+Report-Source ::= ENUMERATED {
+	user	(1),
+	provider	(2)
+	}
+
+Requester-Optional-Messages-Type ::= SEQUENCE {
+	can-send-RECEIVED	[0]	IMPLICIT BOOLEAN,
+	can-send-RETURNED	[1]	IMPLICIT BOOLEAN,
+	requester-SHIPPED	[2]	IMPLICIT ENUMERATED {
+				requires	(1),
+				desires 	(2),
+				neither	(3)
+				},
+	requester-CHECKED-IN	[3]	IMPLICIT ENUMERATED {
+				requires 	(1),
+				desires 	(2),
+				neither 	(3)
+				}
+	}
+
+Responder-Optional-Messages-Type ::= SEQUENCE {
+	can-send-SHIPPED	[0]	IMPLICIT BOOLEAN,
+	can-send-CHECKED-IN	[1]	IMPLICIT BOOLEAN,
+	responder-RECEIVED	[2]	IMPLICIT ENUMERATED {
+				requires 	(1),
+				desires 	(2),
+				neither 	(3)
+				},
+	responder-RETURNED	[3]	IMPLICIT ENUMERATED {
+				requires 	(1),
+				desires 	(2),
+				neither 	(3)
+				}
+	}
+
+Retry-Results ::= SEQUENCE {
+	reason-not-available	[0]	IMPLICIT ENUMERATED {
+				in-use-on-loan 			(1),
+				in-process 				(2),
+				on-order 				(6),
+				volume-issue-not-yet-available	(7),
+				at-bindery 				(8),
+				cost-exceeds-limit 			(13),
+				charges 				(14),
+				prepayment-required 		(15),
+				lacks-copyright-compliance		(16),
+				not-found-as-cited 			(17),
+				on-hold 				(19),
+				other 				(27),
+				responder-specific 			(28)
+				} OPTIONAL,
+	retry-date	[1]	IMPLICIT ISO-Date OPTIONAL,
+	locations	[2]	IMPLICIT SEQUENCE OF Location-Info OPTIONAL
+	}
+
+Search-Type ::= SEQUENCE {
+	level-of-service	[0]	ILL-String (SIZE (1)) OPTIONAL,
+	need-before-date	[1]	IMPLICIT ISO-Date OPTIONAL,
+	expiry-flag	[2]	IMPLICIT ENUMERATED {
+				need-Before-Date	(1),
+				other-Date 		(2),
+				no-Expiry 		(3)
+				} DEFAULT 3,
+				-- value of "need-Before-Date" indicates that
+				-- need-before-date also specifies transaction expiry
+				-- date
+	expiry-date	[3]	IMPLICIT ISO-Date OPTIONAL
+		-- alternative expiry date can be used only when expiry-flag
+		-- is set to "Other-Date"
+	}
+
+Security-Problem ::= ILL-String
+
+Send-To-List-Type ::= SEQUENCE OF SEQUENCE {
+	system-id	[0]	IMPLICIT System-Id,
+	account-number	[1]	Account-Number OPTIONAL,
+	system-address	[2]	IMPLICIT System-Address OPTIONAL
+	}
+
+Service-Date-Time ::= SEQUENCE {
+	date-time-of-this-service 	[0]	IMPLICIT SEQUENCE {
+				date	[0]	IMPLICIT ISO-Date,
+				time	[1]	IMPLICIT ISO-Time OPTIONAL
+				-- mandatory for 2nd and subsequent services
+				-- invoked for a given 
+				-- ILL-transaction on the same day
+				},
+	date-time-of-original-service	[1]	IMPLICIT SEQUENCE {
+				date	[0]	IMPLICIT ISO-Date,
+				time	[1]	IMPLICIT ISO-Time OPTIONAL
+				} OPTIONAL
+	}
+
+Shipped-Service-Type ::= ILL-Service-Type (loan | copy-non-returnable)
+	-- subtype of ILL-Service-Type
+
+State-Transition-Prohibited ::= SEQUENCE {
+	aPDU-type	[0]	IMPLICIT ILL-APDU-Type,
+	current-state	[1]	IMPLICIT Current-State
+	}
+
+Status-Report ::= SEQUENCE {
+	user-status-report	[0]	IMPLICIT History-Report,
+	provider-status-report 	[1]	IMPLICIT Current-State
+	}
+
+Supplemental-Item-Description ::= SEQUENCE OF EXTERNAL
+	-- the syntax of supplementary item description information is defined outside this standard
+
+Supply-Details ::= SEQUENCE {
+	date-shipped	[0]	IMPLICIT ISO-Date OPTIONAL,
+	date-due	[1]	IMPLICIT Date-Due OPTIONAL,
+	chargeable-units	[2]	IMPLICIT INTEGER (1..9999) OPTIONAL,
+	cost	[3]	IMPLICIT Amount OPTIONAL,
+	shipped-conditions	[4]	IMPLICIT ENUMERATED {
+				library-use-only				(22),
+				no-reproduction				(23),
+				client-signature-required			(24),
+				special-collections-supervision-required	(25),
+				other					(27)
+				} OPTIONAL,
+	shipped-via		CHOICE {
+				physical-delivery	[5]	Transportation-Mode,
+				electronic-delivery	[50]	IMPLICIT
+							         Electronic-Delivery-Service
+				} OPTIONAL,
+		-- electronic-delivery may only be present in APDUs with a
+		-- protocol-version-num value of 2 or greater
+	insured-for	[6]	IMPLICIT Amount OPTIONAL,
+	return-insurance-require	[7]	IMPLICIT Amount OPTIONAL,
+	no-of-units-per-medium	[8]	IMPLICIT SEQUENCE OF Units-Per-Medium-Type 	
+				OPTIONAL
+	}
+
+Supply-Medium-Info-Type ::= SEQUENCE {
+	supply-medium-type  	[0]	IMPLICIT Supply-Medium-Type,
+	medium-characteristics 	[1]	ILL-String OPTIONAL
+	}
+
+Supply-Medium-Type ::= ENUMERATED {
+	printed	(1),
+	photocopy	(2),
+	microform	(3),
+	film-or-video-recording	(4),
+	audio-recording	(5),
+	machine-readable	(6),
+	other	(7)
+	}
+
+System-Address ::= SEQUENCE {
+	telecom-service-identifier	[0]	ILL-String OPTIONAL,
+	telecom-service-address	[1]	ILL-String OPTIONAL
+	}
+
+System-Id ::= SEQUENCE {
+	--at least one of the following must be present
+	person-or-institution-symbol	[0]	Person-Or-Institution-Symbol OPTIONAL,
+	name-of-person-or-institution	[1]	Name-Of-Person-Or-Institution OPTIONAL
+	}
+
+Third-Party-Info-Type ::= SEQUENCE {
+	permission-to-forward	[0]	IMPLICIT BOOLEAN DEFAULT FALSE,
+	permission-to-chain	[1]	IMPLICIT BOOLEAN DEFAULT FALSE,
+	permission-to-partition 	[2]	IMPLICIT BOOLEAN DEFAULT FALSE,
+	permission-to-change-send-to-list [3]	IMPLICIT BOOLEAN DEFAULT FALSE,
+	initial-requester-address 	[4]	IMPLICIT System-Address OPTIONAL,
+		-- mandatory when initiating a FORWARD service or an
+		-- ILL-REQUEST service for a partitioned ILL
+		-- sub-transaction; optional otherwise
+	preference	[5]	IMPLICIT ENUMERATED {
+				ordered	(1),
+				unordered	(2)
+				} DEFAULT 2,
+	send-to-list	[6]	IMPLICIT Send-To-List-Type OPTIONAL,
+	already-tried-list	[7]	IMPLICIT Already-Tried-List-Type OPTIONAL
+		-- mandatory when initiating a FORWARD service, or when
+		-- initiating an ILL-REQUEST service for an ILL
+		-- sub-transaction if the received ILL-REQUEST included an
+		-- "already-tried-list"; optional otherwise
+	}
+
+Transaction-Id ::= SEQUENCE {
+	initial-requester-id	[0]	IMPLICIT System-Id OPTIONAL,
+		-- mandatory for sub-transactions; not called
+		-- "requester-id" to distinguish id of initial-requester
+		--from id of requester of sub-transaction if there is one
+	transaction-group-qualifier	[1]	ILL-String,
+	transaction-qualifier	[2]	ILL-String,
+	sub-transaction-qualifier	[3]	ILL-String OPTIONAL
+		-- mandatory for sub-transactions
+	}
+
+Transaction-Id-Problem ::= ENUMERATED {
+	duplicate-transaction-id	(1),
+	invalid-transaction-id	(2),
+	unknown-transaction-id	(3)
+	}
+
+Transaction-Results ::= ENUMERATED {
+	conditional	(1),
+	retry	(2),
+	unfilled	(3),
+	locations-provided	(4),
+	will-supply	(5),
+	hold-placed	(6),
+	estimate	(7)
+	}
+
+Transaction-Type ::= ENUMERATED  {
+	simple	(1),
+	chained	(2),
+	partitioned	(3)
+	}
+
+Transportation-Mode ::= ILL-String
+
+Unable-To-Perform ::= ENUMERATED {
+	not-available	(1),
+	resource-limitation 	(2),
+	other 	(3)
+	}
+
+Unfilled-Results ::= SEQUENCE {
+	reason-unfilled	[0]	IMPLICIT Reason-Unfilled,
+	locations	[1]	IMPLICIT SEQUENCE OF Location-Info OPTIONAL
+	}
+
+Units-Per-Medium-Type ::= SEQUENCE {
+	medium	[0]	Supply-Medium-Type,
+	no-of-units	[1]	INTEGER (1..9999)
+	}
+
+User-Error-Report ::= CHOICE {
+	already-forwarded	[0]	IMPLICIT Already-Forwarded,
+	intermediary-problem	[1]	IMPLICIT Intermediary-Problem,
+	security-problem	[2]	Security-Problem,
+	unable-to-perform	[3]	IMPLICIT Unable-To-Perform
+	}
+
+
+Will-Supply-Results ::= SEQUENCE {
+	reason-will-supply 	[0]	ENUMERATED {
+				in-use-on-loan 		(1),
+				in-process 			(2),
+				on-order 			(6),
+				at-bindery 			(8),
+				on-hold 			(19),
+				being-processed-for-supply 	(26),
+				other 			(27),
+				responder-specific 		(28),
+				electronic-delivery 		(30)
+				},
+	supply-date	[1]	ISO-Date OPTIONAL,
+	return-to-address	[2]	Postal-Address OPTIONAL,
+	locations	[3]	IMPLICIT SEQUENCE OF Location-Info OPTIONAL,
+	electronic-delivery-service	[4] Electronic-Delivery-Service OPTIONAL
+		-- if present, this must be one of the services proposed by 
+		-- the requester
+	}
+
+EDIFACTString ::= VisibleString 
+	(FROM ("A"|"B"|"C"|"D"|"E"|"F"|"G"|"H"|
+	"I"|"J"|"K"|"L"|"M"|"N"|"O"|"P"|"Q"|"R"|"S"|"T"|"U"|
+	"V"|"W"|"X"|"Y"|"Z"|"a"|"b"|"c"|"d"|"e"|"f"|"g"|"h"|
+	"i"|"j"|"k"|"l"|"m"|"n"|"o"|"p"|"q"|"r"|"s"|"t"|"u"|
+	"v"|"w"|"x"|"y"|"z"|"1"|"2"|"3"|"4"|"5"|"6"|"7"|"8"|
+	"9"|"0"|" "|"."|","|"-"|"("|")"|"/"|"="|"!"|"""|"%"|"&"|
+	"*"|";"|"<"|">"|"'"|"+"|":"|"?"))
+
+END
+
+
Index: /main/tags/2.25/gsdl/packages/yaz/ill/item-req.asn
===================================================================
--- /main/tags/2.25/gsdl/packages/yaz/ill/item-req.asn	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/yaz/ill/item-req.asn	(revision 21064)
@@ -0,0 +1,58 @@
+Z39.50-extendedService-ItemOrder-ItemRequest-1 DEFINITIONS ::=
+BEGIN
+IMPORTS
+	Transaction-Id,
+	Service-Date-Time,
+	System-Id,
+	Transaction-Type,
+	Delivery-Address,
+	ILL-Service-Type,
+	Requester-Optional-Messages-Type,
+	Search-Type,
+	Supply-Medium-Info-Type,
+	Place-On-Hold-Type,
+	Client-Id,
+	Item-Id,
+	Supplemental-Item-Description,
+	Cost-Info-Type,
+	ILL-String,
+	Third-Party-Info-Type,
+	Extension
+FROM ISO-10161-ILL-1;
+
+ItemRequest ::=SEQUENCE {
+	protocol-version-num	[0]	IMPLICIT INTEGER {
+				version-1 (1),
+				version-2 (2)
+				},
+	transaction-id		[1]	IMPLICIT Transaction-Id OPTIONAL,
+	service-date-time	[2]	IMPLICIT Service-Date-Time OPTIONAL,
+	requester-id		[3]	IMPLICIT System-Id OPTIONAL,
+	responder-id		[4]	IMPLICIT System-Id OPTIONAL,
+	transaction-type	[5]	IMPLICIT Transaction-Type DEFAULT 1,
+	delivery-address	[6]	IMPLICIT Delivery-Address OPTIONAL, 
+	delivery-service		Delivery-Service OPTIONAL,
+	billing-address		[8]	IMPLICIT Delivery-Address OPTIONAL,
+	iLL-service-type	[9]	IMPLICIT SEQUENCE SIZE (1..5) OF 
+					ILL-Service-Type OPTIONAL,
+	responder-specific-service	[10]	EXTERNAL OPTIONAL,
+		-- use direct reference style
+	requester-optional-messages	[11]	IMPLICIT Requester-Optional-Messages-Type OPTIONAL,
+	search-type		[12]	IMPLICIT Search-Type OPTIONAL,
+	supply-medium-info-type [13]	IMPLICIT SEQUENCE SIZE (1..7) OF
+				Supply-Medium-Info-Type OPTIONAL,
+	place-on-hold		[14]	IMPLICIT Place-On-Hold-Type DEFAULT 3,
+	client-id		[15]	IMPLICIT Client-Id OPTIONAL,     
+	item-id			[16]	IMPLICIT Item-Id OPTIONAL,
+	supplemental-item-description	[17]	IMPLICIT Supplemental-Item-Description OPTIONAL,
+	cost-info-type		[18]	IMPLICIT Cost-Info-Type OPTIONAL,
+	copyright-compliance	[19]	ILL-String OPTIONAL,
+	third-party-info-type	[20]	IMPLICIT Third-Party-Info-Type OPTIONAL,
+	retry-flag		[21]	IMPLICIT BOOLEAN DEFAULT FALSE,
+	forward-flag		[22]	IMPLICIT BOOLEAN DEFAULT FALSE,
+	requester-note		[46]	ILL-String OPTIONAL,
+	forward-note		[47]	ILL-String OPTIONAL,
+	iLL-request-extensions 	[49]	IMPLICIT SEQUENCE OF Extension OPTIONAL
+ 	}
+END
+  
Index: /main/tags/2.25/gsdl/packages/yaz/ill/item-req.c
===================================================================
--- /main/tags/2.25/gsdl/packages/yaz/ill/item-req.c	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/yaz/ill/item-req.c	(revision 21064)
@@ -0,0 +1,66 @@
+/* Generated automatically by the YAZ ASN.1 Compiler 0.3 */
+/* Module-C: Z39.50-extendedService-ItemOrder-ItemRequest-1 */
+
+#include <yaz/item-req.h>
+
+int ill_ItemRequest (ODR o, ILL_ItemRequest **p, int opt, const char *name)
+{
+	if (!odr_sequence_begin (o, p, sizeof(**p), name))
+		return opt && odr_ok (o);
+	return
+		odr_implicit_tag (o, odr_integer,
+			&(*p)->protocol_version_num, ODR_CONTEXT, 0, 0, "protocol_version_num") &&
+		odr_implicit_tag (o, ill_Transaction_Id,
+			&(*p)->transaction_id, ODR_CONTEXT, 1, 1, "transaction_id") &&
+		odr_implicit_tag (o, ill_Service_Date_Time,
+			&(*p)->service_date_time, ODR_CONTEXT, 2, 1, "service_date_time") &&
+		odr_implicit_tag (o, ill_System_Id,
+			&(*p)->requester_id, ODR_CONTEXT, 3, 1, "requester_id") &&
+		odr_implicit_tag (o, ill_System_Id,
+			&(*p)->responder_id, ODR_CONTEXT, 4, 1, "responder_id") &&
+		odr_implicit_tag (o, ill_Transaction_Type,
+			&(*p)->transaction_type, ODR_CONTEXT, 5, 0, "transaction_type") &&
+		odr_implicit_tag (o, ill_Delivery_Address,
+			&(*p)->delivery_address, ODR_CONTEXT, 6, 1, "delivery_address") &&
+		ill_Delivery_Service(o, &(*p)->delivery_service, 1, "delivery_service") &&
+		odr_implicit_tag (o, ill_Delivery_Address,
+			&(*p)->billing_address, ODR_CONTEXT, 8, 1, "billing_address") &&
+		odr_implicit_settag (o, ODR_CONTEXT, 9) &&
+		(odr_sequence_of(o, (Odr_fun) ill_Service_Type, &(*p)->iLL_service_type,
+		  &(*p)->num_iLL_service_type, "iLL_service_type") || odr_ok(o)) &&
+		odr_explicit_tag (o, odr_external,
+			&(*p)->responder_specific_service, ODR_CONTEXT, 10, 1, "responder_specific_service") &&
+		odr_implicit_tag (o, ill_Requester_Optional_Messages_Type,
+			&(*p)->requester_optional_messages, ODR_CONTEXT, 11, 1, "requester_optional_messages") &&
+		odr_implicit_tag (o, ill_Search_Type,
+			&(*p)->search_type, ODR_CONTEXT, 12, 1, "search_type") &&
+		odr_implicit_settag (o, ODR_CONTEXT, 13) &&
+		(odr_sequence_of(o, (Odr_fun) ill_Supply_Medium_Info_Type, &(*p)->supply_medium_info_type,
+		  &(*p)->num_supply_medium_info_type, "supply_medium_info_type") || odr_ok(o)) &&
+		odr_implicit_tag (o, ill_Place_On_Hold_Type,
+			&(*p)->place_on_hold, ODR_CONTEXT, 14, 0, "place_on_hold") &&
+		odr_implicit_tag (o, ill_Client_Id,
+			&(*p)->client_id, ODR_CONTEXT, 15, 1, "client_id") &&
+		odr_implicit_tag (o, ill_Item_Id,
+			&(*p)->item_id, ODR_CONTEXT, 16, 1, "item_id") &&
+		odr_implicit_tag (o, ill_Supplemental_Item_Description,
+			&(*p)->supplemental_item_description, ODR_CONTEXT, 17, 1, "supplemental_item_description") &&
+		odr_implicit_tag (o, ill_Cost_Info_Type,
+			&(*p)->cost_info_type, ODR_CONTEXT, 18, 1, "cost_info_type") &&
+		odr_explicit_tag (o, ill_String,
+			&(*p)->copyright_compliance, ODR_CONTEXT, 19, 1, "copyright_compliance") &&
+		odr_implicit_tag (o, ill_Third_Party_Info_Type,
+			&(*p)->third_party_info_type, ODR_CONTEXT, 20, 1, "third_party_info_type") &&
+		odr_implicit_tag (o, odr_bool,
+			&(*p)->retry_flag, ODR_CONTEXT, 21, 0, "retry_flag") &&
+		odr_implicit_tag (o, odr_bool,
+			&(*p)->forward_flag, ODR_CONTEXT, 22, 0, "forward_flag") &&
+		odr_explicit_tag (o, ill_String,
+			&(*p)->requester_note, ODR_CONTEXT, 46, 1, "requester_note") &&
+		odr_explicit_tag (o, ill_String,
+			&(*p)->forward_note, ODR_CONTEXT, 47, 1, "forward_note") &&
+		odr_implicit_settag (o, ODR_CONTEXT, 49) &&
+		(odr_sequence_of(o, (Odr_fun) ill_Extension, &(*p)->iLL_request_extensions,
+		  &(*p)->num_iLL_request_extensions, "iLL_request_extensions") || odr_ok(o)) &&
+		odr_sequence_end (o);
+}
Index: /main/tags/2.25/gsdl/packages/yaz/include/Makefile.am
===================================================================
--- /main/tags/2.25/gsdl/packages/yaz/include/Makefile.am	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/yaz/include/Makefile.am	(revision 21064)
@@ -0,0 +1,6 @@
+## $Id$
+
+AUTOMAKE_OPTIONS = foreign 
+
+SUBDIRS = yaz
+
Index: /main/tags/2.25/gsdl/packages/yaz/include/Makefile.in
===================================================================
--- /main/tags/2.25/gsdl/packages/yaz/include/Makefile.in	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/yaz/include/Makefile.in	(revision 21064)
@@ -0,0 +1,281 @@
+# Makefile.in generated automatically by automake 1.4 from Makefile.am
+
+# Copyright (C) 1994, 1995-8, 1999 Free Software Foundation, Inc.
+# This Makefile.in is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
+# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE.
+
+
+SHELL = @SHELL@
+
+srcdir = @srcdir@
+top_srcdir = @top_srcdir@
+VPATH = @srcdir@
+prefix = @prefix@
+exec_prefix = @exec_prefix@
+
+bindir = @bindir@
+sbindir = @sbindir@
+libexecdir = @libexecdir@
+datadir = @datadir@
+sysconfdir = @sysconfdir@
+sharedstatedir = @sharedstatedir@
+localstatedir = @localstatedir@
+libdir = @libdir@
+infodir = @infodir@
+mandir = @mandir@
+includedir = @includedir@
+oldincludedir = /usr/include
+
+DESTDIR =
+
+pkgdatadir = $(datadir)/@PACKAGE@
+pkglibdir = $(libdir)/@PACKAGE@
+pkgincludedir = $(includedir)/@PACKAGE@
+
+top_builddir = ..
+
+ACLOCAL = @ACLOCAL@
+AUTOCONF = @AUTOCONF@
+AUTOMAKE = @AUTOMAKE@
+AUTOHEADER = @AUTOHEADER@
+
+INSTALL = @INSTALL@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@ $(AM_INSTALL_PROGRAM_FLAGS)
+INSTALL_DATA = @INSTALL_DATA@
+INSTALL_SCRIPT = @INSTALL_SCRIPT@
+transform = @program_transform_name@
+
+NORMAL_INSTALL = :
+PRE_INSTALL = :
+POST_INSTALL = :
+NORMAL_UNINSTALL = :
+PRE_UNINSTALL = :
+POST_UNINSTALL = :
+ASNMODULE = @ASNMODULE@
+CC = @CC@
+CPP = @CPP@
+ILLLIB = @ILLLIB@
+ILLMODULE = @ILLMODULE@
+MAKEINFO = @MAKEINFO@
+PACKAGE = @PACKAGE@
+RANLIB = @RANLIB@
+SUBDIRS_VAR = @SUBDIRS_VAR@
+VERSION = @VERSION@
+have_sgml2html = @have_sgml2html@
+have_sgml2latex = @have_sgml2latex@
+have_sgml2txt = @have_sgml2txt@
+
+AUTOMAKE_OPTIONS = foreign 
+
+SUBDIRS = yaz
+mkinstalldirs = $(SHELL) $(top_srcdir)/mkinstalldirs
+CONFIG_CLEAN_FILES = 
+DIST_COMMON =  Makefile.am Makefile.in
+
+
+DISTFILES = $(DIST_COMMON) $(SOURCES) $(HEADERS) $(TEXINFOS) $(EXTRA_DIST)
+
+TAR = gtar
+GZIP_ENV = --best
+all: all-redirect
+.SUFFIXES:
+$(srcdir)/Makefile.in: Makefile.am $(top_srcdir)/configure.in $(ACLOCAL_M4) 
+	cd $(top_srcdir) && $(AUTOMAKE) --foreign --include-deps include/Makefile
+
+Makefile: $(srcdir)/Makefile.in  $(top_builddir)/config.status
+	cd $(top_builddir) \
+	  && CONFIG_FILES=$(subdir)/$@ CONFIG_HEADERS= $(SHELL) ./config.status
+
+
+# This directory's subdirectories are mostly independent; you can cd
+# into them and run `make' without going through this Makefile.
+# To change the values of `make' variables: instead of editing Makefiles,
+# (1) if the variable is set in `config.status', edit `config.status'
+#     (which will cause the Makefiles to be regenerated when you run `make');
+# (2) otherwise, pass the desired values on the `make' command line.
+
+@SET_MAKE@
+
+all-recursive install-data-recursive install-exec-recursive \
+installdirs-recursive install-recursive uninstall-recursive  \
+check-recursive installcheck-recursive info-recursive dvi-recursive:
+	@set fnord $(MAKEFLAGS); amf=$$2; \
+	dot_seen=no; \
+	target=`echo $@ | sed s/-recursive//`; \
+	list='$(SUBDIRS)'; for subdir in $$list; do \
+	  echo "Making $$target in $$subdir"; \
+	  if test "$$subdir" = "."; then \
+	    dot_seen=yes; \
+	    local_target="$$target-am"; \
+	  else \
+	    local_target="$$target"; \
+	  fi; \
+	  (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) $$local_target) \
+	   || case "$$amf" in *=*) exit 1;; *k*) fail=yes;; *) exit 1;; esac; \
+	done; \
+	if test "$$dot_seen" = "no"; then \
+	  $(MAKE) $(AM_MAKEFLAGS) "$$target-am" || exit 1; \
+	fi; test -z "$$fail"
+
+mostlyclean-recursive clean-recursive distclean-recursive \
+maintainer-clean-recursive:
+	@set fnord $(MAKEFLAGS); amf=$$2; \
+	dot_seen=no; \
+	rev=''; list='$(SUBDIRS)'; for subdir in $$list; do \
+	  rev="$$subdir $$rev"; \
+	  test "$$subdir" = "." && dot_seen=yes; \
+	done; \
+	test "$$dot_seen" = "no" && rev=". $$rev"; \
+	target=`echo $@ | sed s/-recursive//`; \
+	for subdir in $$rev; do \
+	  echo "Making $$target in $$subdir"; \
+	  if test "$$subdir" = "."; then \
+	    local_target="$$target-am"; \
+	  else \
+	    local_target="$$target"; \
+	  fi; \
+	  (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) $$local_target) \
+	   || case "$$amf" in *=*) exit 1;; *k*) fail=yes;; *) exit 1;; esac; \
+	done && test -z "$$fail"
+tags-recursive:
+	list='$(SUBDIRS)'; for subdir in $$list; do \
+	  test "$$subdir" = . || (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) tags); \
+	done
+
+tags: TAGS
+
+ID: $(HEADERS) $(SOURCES) $(LISP)
+	list='$(SOURCES) $(HEADERS)'; \
+	unique=`for i in $$list; do echo $$i; done | \
+	  awk '    { files[$$0] = 1; } \
+	       END { for (i in files) print i; }'`; \
+	here=`pwd` && cd $(srcdir) \
+	  && mkid -f$$here/ID $$unique $(LISP)
+
+TAGS: tags-recursive $(HEADERS) $(SOURCES)  $(TAGS_DEPENDENCIES) $(LISP)
+	tags=; \
+	here=`pwd`; \
+	list='$(SUBDIRS)'; for subdir in $$list; do \
+   if test "$$subdir" = .; then :; else \
+	    test -f $$subdir/TAGS && tags="$$tags -i $$here/$$subdir/TAGS"; \
+   fi; \
+	done; \
+	list='$(SOURCES) $(HEADERS)'; \
+	unique=`for i in $$list; do echo $$i; done | \
+	  awk '    { files[$$0] = 1; } \
+	       END { for (i in files) print i; }'`; \
+	test -z "$(ETAGS_ARGS)$$unique$(LISP)$$tags" \
+	  || (cd $(srcdir) && etags $(ETAGS_ARGS) $$tags  $$unique $(LISP) -o $$here/TAGS)
+
+mostlyclean-tags:
+
+clean-tags:
+
+distclean-tags:
+	-rm -f TAGS ID
+
+maintainer-clean-tags:
+
+distdir = $(top_builddir)/$(PACKAGE)-$(VERSION)/$(subdir)
+
+subdir = include
+
+distdir: $(DISTFILES)
+	@for file in $(DISTFILES); do \
+	  d=$(srcdir); \
+	  if test -d $$d/$$file; then \
+	    cp -pr $$/$$file $(distdir)/$$file; \
+	  else \
+	    test -f $(distdir)/$$file \
+	    || ln $$d/$$file $(distdir)/$$file 2> /dev/null \
+	    || cp -p $$d/$$file $(distdir)/$$file || :; \
+	  fi; \
+	done
+	for subdir in $(SUBDIRS); do \
+	  if test "$$subdir" = .; then :; else \
+	    test -d $(distdir)/$$subdir \
+	    || mkdir $(distdir)/$$subdir \
+	    || exit 1; \
+	    chmod 777 $(distdir)/$$subdir; \
+	    (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) top_distdir=../$(top_distdir) distdir=../$(distdir)/$$subdir distdir) \
+	      || exit 1; \
+	  fi; \
+	done
+info-am:
+info: info-recursive
+dvi-am:
+dvi: dvi-recursive
+check-am: all-am
+check: check-recursive
+installcheck-am:
+installcheck: installcheck-recursive
+install-exec-am:
+install-exec: install-exec-recursive
+
+install-data-am:
+install-data: install-data-recursive
+
+install-am: all-am
+	@$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
+install: install-recursive
+uninstall-am:
+uninstall: uninstall-recursive
+all-am: Makefile
+all-redirect: all-recursive
+install-strip:
+	$(MAKE) $(AM_MAKEFLAGS) AM_INSTALL_PROGRAM_FLAGS=-s install
+installdirs: installdirs-recursive
+installdirs-am:
+
+
+mostlyclean-generic:
+
+clean-generic:
+
+distclean-generic:
+	-rm -f Makefile $(CONFIG_CLEAN_FILES)
+	-rm -f config.cache config.log stamp-h stamp-h[0-9]*
+
+maintainer-clean-generic:
+mostlyclean-am:  mostlyclean-tags mostlyclean-generic
+
+mostlyclean: mostlyclean-recursive
+
+clean-am:  clean-tags clean-generic mostlyclean-am
+
+clean: clean-recursive
+
+distclean-am:  distclean-tags distclean-generic clean-am
+
+distclean: distclean-recursive
+
+maintainer-clean-am:  maintainer-clean-tags maintainer-clean-generic \
+		distclean-am
+	@echo "This command is intended for maintainers to use;"
+	@echo "it deletes files that may require special tools to rebuild."
+
+maintainer-clean: maintainer-clean-recursive
+
+.PHONY: install-data-recursive uninstall-data-recursive \
+install-exec-recursive uninstall-exec-recursive installdirs-recursive \
+uninstalldirs-recursive all-recursive check-recursive \
+installcheck-recursive info-recursive dvi-recursive \
+mostlyclean-recursive distclean-recursive clean-recursive \
+maintainer-clean-recursive tags tags-recursive mostlyclean-tags \
+distclean-tags clean-tags maintainer-clean-tags distdir info-am info \
+dvi-am dvi check check-am installcheck-am installcheck install-exec-am \
+install-exec install-data-am install-data install-am install \
+uninstall-am uninstall all-redirect all-am all installdirs-am \
+installdirs mostlyclean-generic distclean-generic clean-generic \
+maintainer-clean-generic clean mostlyclean distclean maintainer-clean
+
+
+# Tell versions [3.59,3.63) of GNU make to not export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:
Index: /main/tags/2.25/gsdl/packages/yaz/include/yaz/Makefile.am
===================================================================
--- /main/tags/2.25/gsdl/packages/yaz/include/yaz/Makefile.am	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/yaz/include/yaz/Makefile.am	(revision 21064)
@@ -0,0 +1,17 @@
+## $Id$
+
+pkginclude_HEADERS= backend.h ccl.h comstack.h \
+ d1_attset.h d1_map.h data1.h diagbib1.h \
+ log.h logrpn.h marcdisp.h nmem.h odr.h oid.h options.h otherinfo.h \
+ pquery.h prt-ext.h readconf.h statserv.h tcpip.h tpath.h wrbuf.h xmalloc.h \
+ yaz-ccl.h yaz-util.h yaz-version.h yconfig.h proto.h \
+ \
+ ill.h ill-core.h item-req.h z-accdes1.h z-accform1.h \
+ z-acckrb1.h z-core.h z-date.h z-diag1.h z-espec1.h z-estask.h z-exp.h \
+ z-grs.h z-opac.h z-proto.h z-rrf1.h z-rrf2.h z-sum.h z-sutrs.h z-uifr1.h \
+ z-univ.h zes-expi.h zes-exps.h zes-order.h zes-pquery.h zes-psched.h \
+ \
+ zes-pset.h zes-update.h zes-update0.h \
+ prt-acc.h prt-add.h prt-arc.h prt-dat.h prt-dia.h prt-esp.h \
+ prt-exd.h prt-exp.h prt-grs.h prt-proto.h prt-rsc.h prt-univ.h
+
Index: /main/tags/2.25/gsdl/packages/yaz/include/yaz/Makefile.in
===================================================================
--- /main/tags/2.25/gsdl/packages/yaz/include/yaz/Makefile.in	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/yaz/include/yaz/Makefile.in	(revision 21064)
@@ -0,0 +1,222 @@
+# Makefile.in generated automatically by automake 1.4 from Makefile.am
+
+# Copyright (C) 1994, 1995-8, 1999 Free Software Foundation, Inc.
+# This Makefile.in is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
+# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE.
+
+
+SHELL = @SHELL@
+
+srcdir = @srcdir@
+top_srcdir = @top_srcdir@
+VPATH = @srcdir@
+prefix = @prefix@
+exec_prefix = @exec_prefix@
+
+bindir = @bindir@
+sbindir = @sbindir@
+libexecdir = @libexecdir@
+datadir = @datadir@
+sysconfdir = @sysconfdir@
+sharedstatedir = @sharedstatedir@
+localstatedir = @localstatedir@
+libdir = @libdir@
+infodir = @infodir@
+mandir = @mandir@
+includedir = @includedir@
+oldincludedir = /usr/include
+
+DESTDIR =
+
+pkgdatadir = $(datadir)/@PACKAGE@
+pkglibdir = $(libdir)/@PACKAGE@
+pkgincludedir = $(includedir)/@PACKAGE@
+
+top_builddir = ../..
+
+ACLOCAL = @ACLOCAL@
+AUTOCONF = @AUTOCONF@
+AUTOMAKE = @AUTOMAKE@
+AUTOHEADER = @AUTOHEADER@
+
+INSTALL = @INSTALL@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@ $(AM_INSTALL_PROGRAM_FLAGS)
+INSTALL_DATA = @INSTALL_DATA@
+INSTALL_SCRIPT = @INSTALL_SCRIPT@
+transform = @program_transform_name@
+
+NORMAL_INSTALL = :
+PRE_INSTALL = :
+POST_INSTALL = :
+NORMAL_UNINSTALL = :
+PRE_UNINSTALL = :
+POST_UNINSTALL = :
+ASNMODULE = @ASNMODULE@
+CC = @CC@
+CPP = @CPP@
+ILLLIB = @ILLLIB@
+ILLMODULE = @ILLMODULE@
+MAKEINFO = @MAKEINFO@
+PACKAGE = @PACKAGE@
+RANLIB = @RANLIB@
+SUBDIRS_VAR = @SUBDIRS_VAR@
+VERSION = @VERSION@
+have_sgml2html = @have_sgml2html@
+have_sgml2latex = @have_sgml2latex@
+have_sgml2txt = @have_sgml2txt@
+
+pkginclude_HEADERS = backend.h ccl.h comstack.h  d1_attset.h d1_map.h data1.h diagbib1.h  log.h logrpn.h marcdisp.h nmem.h odr.h oid.h options.h otherinfo.h  pquery.h prt-ext.h readconf.h statserv.h tcpip.h tpath.h wrbuf.h xmalloc.h  yaz-ccl.h yaz-util.h yaz-version.h yconfig.h proto.h   ill.h ill-core.h item-req.h z-accdes1.h z-accform1.h  z-acckrb1.h z-core.h z-date.h z-diag1.h z-espec1.h z-estask.h z-exp.h  z-grs.h z-opac.h z-proto.h z-rrf1.h z-rrf2.h z-sum.h z-sutrs.h z-uifr1.h  z-univ.h zes-expi.h zes-exps.h zes-order.h zes-pquery.h zes-psched.h   zes-pset.h zes-update.h zes-update0.h  prt-acc.h prt-add.h prt-arc.h prt-dat.h prt-dia.h prt-esp.h  prt-exd.h prt-exp.h prt-grs.h prt-proto.h prt-rsc.h prt-univ.h
+
+mkinstalldirs = $(SHELL) $(top_srcdir)/mkinstalldirs
+CONFIG_CLEAN_FILES = 
+HEADERS =  $(pkginclude_HEADERS)
+
+DIST_COMMON =  Makefile.am Makefile.in
+
+
+DISTFILES = $(DIST_COMMON) $(SOURCES) $(HEADERS) $(TEXINFOS) $(EXTRA_DIST)
+
+TAR = gtar
+GZIP_ENV = --best
+all: all-redirect
+.SUFFIXES:
+$(srcdir)/Makefile.in: Makefile.am $(top_srcdir)/configure.in $(ACLOCAL_M4) 
+	cd $(top_srcdir) && $(AUTOMAKE) --gnu --include-deps include/yaz/Makefile
+
+Makefile: $(srcdir)/Makefile.in  $(top_builddir)/config.status
+	cd $(top_builddir) \
+	  && CONFIG_FILES=$(subdir)/$@ CONFIG_HEADERS= $(SHELL) ./config.status
+
+
+install-pkgincludeHEADERS: $(pkginclude_HEADERS)
+	@$(NORMAL_INSTALL)
+	$(mkinstalldirs) $(DESTDIR)$(pkgincludedir)
+	@list='$(pkginclude_HEADERS)'; for p in $$list; do \
+	  if test -f "$$p"; then d= ; else d="$(srcdir)/"; fi; \
+	  echo " $(INSTALL_DATA) $$d$$p $(DESTDIR)$(pkgincludedir)/$$p"; \
+	  $(INSTALL_DATA) $$d$$p $(DESTDIR)$(pkgincludedir)/$$p; \
+	done
+
+uninstall-pkgincludeHEADERS:
+	@$(NORMAL_UNINSTALL)
+	list='$(pkginclude_HEADERS)'; for p in $$list; do \
+	  rm -f $(DESTDIR)$(pkgincludedir)/$$p; \
+	done
+
+tags: TAGS
+
+ID: $(HEADERS) $(SOURCES) $(LISP)
+	list='$(SOURCES) $(HEADERS)'; \
+	unique=`for i in $$list; do echo $$i; done | \
+	  awk '    { files[$$0] = 1; } \
+	       END { for (i in files) print i; }'`; \
+	here=`pwd` && cd $(srcdir) \
+	  && mkid -f$$here/ID $$unique $(LISP)
+
+TAGS:  $(HEADERS) $(SOURCES)  $(TAGS_DEPENDENCIES) $(LISP)
+	tags=; \
+	here=`pwd`; \
+	list='$(SOURCES) $(HEADERS)'; \
+	unique=`for i in $$list; do echo $$i; done | \
+	  awk '    { files[$$0] = 1; } \
+	       END { for (i in files) print i; }'`; \
+	test -z "$(ETAGS_ARGS)$$unique$(LISP)$$tags" \
+	  || (cd $(srcdir) && etags $(ETAGS_ARGS) $$tags  $$unique $(LISP) -o $$here/TAGS)
+
+mostlyclean-tags:
+
+clean-tags:
+
+distclean-tags:
+	-rm -f TAGS ID
+
+maintainer-clean-tags:
+
+distdir = $(top_builddir)/$(PACKAGE)-$(VERSION)/$(subdir)
+
+subdir = include/yaz
+
+distdir: $(DISTFILES)
+	@for file in $(DISTFILES); do \
+	  d=$(srcdir); \
+	  if test -d $$d/$$file; then \
+	    cp -pr $$/$$file $(distdir)/$$file; \
+	  else \
+	    test -f $(distdir)/$$file \
+	    || ln $$d/$$file $(distdir)/$$file 2> /dev/null \
+	    || cp -p $$d/$$file $(distdir)/$$file || :; \
+	  fi; \
+	done
+info-am:
+info: info-am
+dvi-am:
+dvi: dvi-am
+check-am: all-am
+check: check-am
+installcheck-am:
+installcheck: installcheck-am
+install-exec-am:
+install-exec: install-exec-am
+
+install-data-am: install-pkgincludeHEADERS
+install-data: install-data-am
+
+install-am: all-am
+	@$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
+install: install-am
+uninstall-am: uninstall-pkgincludeHEADERS
+uninstall: uninstall-am
+all-am: Makefile $(HEADERS)
+all-redirect: all-am
+install-strip:
+	$(MAKE) $(AM_MAKEFLAGS) AM_INSTALL_PROGRAM_FLAGS=-s install
+installdirs:
+	$(mkinstalldirs)  $(DESTDIR)$(pkgincludedir)
+
+
+mostlyclean-generic:
+
+clean-generic:
+
+distclean-generic:
+	-rm -f Makefile $(CONFIG_CLEAN_FILES)
+	-rm -f config.cache config.log stamp-h stamp-h[0-9]*
+
+maintainer-clean-generic:
+mostlyclean-am:  mostlyclean-tags mostlyclean-generic
+
+mostlyclean: mostlyclean-am
+
+clean-am:  clean-tags clean-generic mostlyclean-am
+
+clean: clean-am
+
+distclean-am:  distclean-tags distclean-generic clean-am
+
+distclean: distclean-am
+
+maintainer-clean-am:  maintainer-clean-tags maintainer-clean-generic \
+		distclean-am
+	@echo "This command is intended for maintainers to use;"
+	@echo "it deletes files that may require special tools to rebuild."
+
+maintainer-clean: maintainer-clean-am
+
+.PHONY: uninstall-pkgincludeHEADERS install-pkgincludeHEADERS tags \
+mostlyclean-tags distclean-tags clean-tags maintainer-clean-tags \
+distdir info-am info dvi-am dvi check check-am installcheck-am \
+installcheck install-exec-am install-exec install-data-am install-data \
+install-am install uninstall-am uninstall all-redirect all-am all \
+installdirs mostlyclean-generic distclean-generic clean-generic \
+maintainer-clean-generic clean mostlyclean distclean maintainer-clean
+
+
+# Tell versions [3.59,3.63) of GNU make to not export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:
Index: /main/tags/2.25/gsdl/packages/yaz/include/yaz/backend.h
===================================================================
--- /main/tags/2.25/gsdl/packages/yaz/include/yaz/backend.h	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/yaz/include/yaz/backend.h	(revision 21064)
@@ -0,0 +1,333 @@
+/*
+ * Copyright (c) 1995-2000, Index Data.
+ *
+ * Permission to use, copy, modify, distribute, and sell this software and
+ * its documentation, in whole or in part, for any purpose, is hereby granted,
+ * provided that:
+ *
+ * 1. This copyright and permission notice appear in all copies of the
+ * software and its documentation. Notices of copyright or attribution
+ * which appear at the beginning of any file must remain unchanged.
+ *
+ * 2. The name of Index Data or the individual authors may not be used to
+ * endorse or promote products derived from this software without specific
+ * prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED "AS IS" AND WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS, IMPLIED, OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY
+ * WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
+ * IN NO EVENT SHALL INDEX DATA BE LIABLE FOR ANY SPECIAL, INCIDENTAL,
+ * INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND, OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER OR
+ * NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF
+ * LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
+ * OF THIS SOFTWARE.
+ *
+ * $Log$
+ * Revision 1.1  2000/08/03 03:10:32  johnmcp
+ * Added the YAZ toolkit source to the packages directory (for z39.50 stuff)
+ *
+ * Revision 1.4  2000/02/28 11:20:06  adam
+ * Using autoconf. New definitions: YAZ_BEGIN_CDECL/YAZ_END_CDECL.
+ *
+ * Revision 1.3  2000/01/12 14:36:07  adam
+ * Added printing stream (ODR) for backend functions.
+ *
+ * Revision 1.2  1999/12/16 23:36:19  adam
+ * Implemented ILL protocol. Minor updates ASN.1 compiler.
+ *
+ * Revision 1.1  1999/11/30 13:47:11  adam
+ * Improved installation. Moved header files to include/yaz.
+ *
+ * Revision 1.28  1999/11/04 14:58:44  adam
+ * Added status elements for backend delete result set handler.
+ * Updated delete result result set command for client.
+ *
+ * Revision 1.27  1999/10/11 10:01:24  adam
+ * Implemented bend_sort_rr handler for frontend server.
+ *
+ * Revision 1.26  1999/06/17 10:54:44  adam
+ * Added facility to specify implementation version - and name
+ * for server.
+ *
+ * Revision 1.25  1999/06/01 14:29:12  adam
+ * Work on Extended Services.
+ *
+ * Revision 1.24  1999/03/31 11:18:24  adam
+ * Implemented odr_strdup. Added Reference ID to backend server API.
+ *
+ * Revision 1.23  1998/10/13 16:12:23  adam
+ * Added support for Surrogate Diagnostics for Scan Term entries.
+ *
+ * Revision 1.22  1998/09/02 12:41:51  adam
+ * Added decode stream in bend search structures.
+ *
+ * Revision 1.21  1998/07/20 12:38:41  adam
+ * Implemented delete result set service to server API.
+ *
+ * Revision 1.20  1998/05/27 16:57:06  adam
+ * Support for surrogate diagnostic records added for bend_fetch.
+ *
+ * Revision 1.19  1998/03/31 11:07:45  adam
+ * Furhter work on UNIverse resource report.
+ * Added Extended Services handling in frontend server.
+ *
+ * Revision 1.18  1998/02/10 11:03:56  adam
+ * Added support for extended handlers in backend server interface.
+ *
+ * Revision 1.17  1998/01/29 13:15:35  adam
+ * Implemented sort for the backend interface.
+ *
+ * Revision 1.16  1997/09/17 12:10:31  adam
+ * YAZ version 1.4.
+ *
+ */
+
+#ifndef BACKEND_H
+#define BACKEND_H
+
+#include <yaz/yconfig.h>
+#include <yaz/proto.h>
+#include <yaz/statserv.h>
+
+YAZ_BEGIN_CDECL
+    
+typedef struct request *bend_request;
+typedef struct association *bend_association;
+
+/* old search request input */ 
+typedef struct 
+{
+    char *setname;             /* name to give to this set */
+    int replace_set;           /* replace set, if it already exists */
+    int num_bases;             /* number of databases in list */
+    char **basenames;          /* databases to search */
+    Z_ReferenceId *referenceId;/* reference ID */
+    Z_Query *query;            /* query structure */
+    ODR stream;                /* encoding stream */
+    ODR decode;                /* decoding stream */
+    ODR print;                 /* printing stream */
+} bend_searchrequest;
+
+/* old search request output */
+typedef struct
+{
+    int hits;                  /* number of hits */
+    int errcode;               /* 0==OK */
+    char *errstring;           /* system error string or NULL */
+} bend_searchresult;
+
+/* extended search handler (rr = request response) */
+typedef struct {
+    char *setname;             /* name to give to this set */
+    int replace_set;           /* replace set, if it already exists */
+    int num_bases;             /* number of databases in list */
+    char **basenames;          /* databases to search */
+    Z_ReferenceId *referenceId;/* reference ID */
+    Z_Query *query;            /* query structure */
+    ODR stream;                /* encode stream */
+    ODR decode;                /* decode stream */
+    ODR print;                 /* print stream */
+
+    bend_request request;
+    bend_association association;
+    int *fd;
+    int hits;                  /* number of hits */
+    int errcode;               /* 0==OK */
+    char *errstring;           /* system error string or NULL */
+} bend_search_rr;
+
+/* extended present handler. Does not replace bend_fetch. */
+typedef struct {
+    char *setname;             /* set name */
+    int start;
+    int number;                /* record number */
+    oid_value format;          /* One of the CLASS_RECSYN members */
+    Z_ReferenceId *referenceId;/* reference ID */
+    Z_RecordComposition *comp; /* Formatting instructions */
+    ODR stream;                /* encoding stream - memory source if required */
+    ODR print;                 /* printing stream */
+    bend_request request;
+    bend_association association;
+
+    int hits;                  /* number of hits */
+    int errcode;               /* 0==OK */
+    char *errstring;           /* system error string or NULL */
+} bend_present_rr;
+
+YAZ_EXPORT bend_searchresult *bend_search(void *handle, bend_searchrequest *r,
+                                          int *fd);
+YAZ_EXPORT int bend_searchresponse(void *handle, bend_search_rr *bsrr);
+
+typedef struct
+{
+    char *setname;             /* set name */
+    int number;                /* record number */
+    Z_ReferenceId *referenceId;/* reference ID */
+    oid_value format;          /* One of the CLASS_RECSYN members */
+    Z_RecordComposition *comp; /* Formatting instructions */
+    ODR stream;                /* encoding stream - memory source if req */
+    ODR print;                 /* printing stream */
+    int surrogate_flag;        /* surrogate diagnostic flag (rw) */
+} bend_fetchrequest;
+
+typedef struct
+{
+    char *basename;            /* name of database that provided record */
+    int len;                   /* length of record or -1 if structured */
+    char *record;              /* record */
+    int last_in_set;           /* is it?  */
+    oid_value format;          /* format */
+    int errcode;               /* 0==success */
+    char *errstring;           /* system error string or NULL */
+} bend_fetchresult;
+
+YAZ_EXPORT bend_fetchresult *bend_fetch(void *handle, bend_fetchrequest *r,
+                                        int *fd);
+YAZ_EXPORT bend_fetchresult *bend_fetchresponse(void *handle);
+
+typedef struct
+{
+    int num_bases;      /* number of elements in databaselist */
+    char **basenames;   /* databases to search */
+    oid_value attributeset;
+    Z_ReferenceId *referenceId; /* reference ID */
+    Z_AttributesPlusTerm *term;
+    int term_position;  /* desired index of term in result list */
+    int num_entries;    /* number of entries requested */
+    ODR stream;         /* encoding stream - memory source if required */
+    ODR print;          /* printing stream */
+} bend_scanrequest;
+
+struct scan_entry {
+    char *term;         /* the returned scan term */
+    int occurrences;    /* no of occurrences or -1 if error (see below) */
+    int errcode;        /* Bib-1 diagnostic code; only used when occur.= -1 */
+    char *errstring;    /* Additional string */
+};
+
+typedef enum {
+    BEND_SCAN_SUCCESS,  /* ok */
+    BEND_SCAN_PARTIAL   /* not all entries could be found */
+} bend_scan_status;
+
+typedef struct bend_scanresult
+{
+    int num_entries;
+    struct scan_entry *entries;
+    int term_position;
+    bend_scan_status status;
+    int errcode;
+    char *errstring;
+} bend_scanresult;
+
+typedef struct bend_scan_rr {
+    int num_bases;      /* number of elements in databaselist */
+    char **basenames;   /* databases to search */
+    oid_value attributeset;
+    Z_ReferenceId *referenceId; /* reference ID */
+    Z_AttributesPlusTerm *term;
+    ODR stream;         /* encoding stream - memory source if required */
+    ODR print;          /* printing stream */
+
+    int term_position;  /* desired index of term in result list/returned */
+    int num_entries;    /* number of entries requested/returned */
+
+    struct scan_entry *entries;
+    bend_scan_status status;
+    int errcode;
+    char *errstring;
+} bend_scan_rr;
+
+YAZ_EXPORT bend_scanresult *bend_scan(void *handle, bend_scanrequest *r,
+                                      int *fd);
+YAZ_EXPORT bend_scanresult *bend_scanresponse(void *handle);
+
+/* delete handler */
+typedef struct bend_delete_rr {
+    int function;
+    int num_setnames;
+    char **setnames;
+    Z_ReferenceId *referenceId;
+    int delete_status;      /* status for the whole operation */
+    int *statuses;          /* status each set - indexed as setnames */
+    ODR stream;
+    ODR print; 
+} bend_delete_rr;
+
+/* close handler */
+YAZ_EXPORT void bend_close(void *handle);
+
+/* sort handler */
+typedef struct bend_sort_rr
+{
+    int num_input_setnames;
+    char **input_setnames;
+    char *output_setname;
+    Z_SortKeySpecList *sort_sequence;
+    ODR stream;
+    ODR print;
+    Z_ReferenceId *referenceId;/* reference ID */
+
+    int sort_status;
+    int errcode;
+    char *errstring;
+} bend_sort_rr;
+
+typedef struct bend_esrequest_rr
+{
+    int ItemNo;
+    Z_ExtendedServicesRequest *esr;
+    
+    ODR stream;                /* encoding stream */
+    ODR decode;                /* decoding stream */
+    ODR print;                 /* printing stream */
+    Z_ReferenceId *referenceId;/* reference ID */
+    bend_request request;
+    bend_association association;
+    int errcode;               /* 0==success, -1==accepted, >0 = failure */
+    char *errstring;           /* system error string or NULL */
+} bend_esrequest_rr;
+
+typedef struct bend_initrequest
+{
+    char *configname;
+    Z_IdAuthentication *auth;
+    ODR stream;                /* encoding stream */
+    ODR print;                 /* printing stream */
+    Z_ReferenceId *referenceId;/* reference ID */
+    
+    char *implementation_name;
+    char *implementation_version;
+    int (*bend_sort) (void *handle, bend_sort_rr *rr);
+    int (*bend_search) (void *handle, bend_search_rr *rr);
+    int (*bend_present) (void *handle, bend_present_rr *rr);
+    int (*bend_esrequest) (void *handle, bend_esrequest_rr *rr);
+    int (*bend_delete)(void *handle, bend_delete_rr *rr);
+    int (*bend_scan)(void *handle, bend_scan_rr *rr);
+} bend_initrequest;
+
+typedef struct bend_initresult
+{
+    int errcode;               /* 0==OK */
+    char *errstring;           /* system error string or NULL */
+    void *handle;              /* private handle to the backend module */
+} bend_initresult;
+
+YAZ_EXPORT bend_initresult *bend_init(bend_initrequest *r);
+
+YAZ_EXPORT void bend_request_send (bend_association a, bend_request req,
+				   Z_APDU *res);
+
+YAZ_EXPORT bend_request bend_request_mk (bend_association a);
+
+YAZ_EXPORT void bend_request_destroy (bend_request *req);
+
+YAZ_EXPORT Z_ReferenceId *bend_request_getid (ODR odr, bend_request req);
+YAZ_EXPORT int bend_backend_respond (bend_association a, bend_request req);
+YAZ_EXPORT void bend_request_setdata(bend_request r, void *p);
+YAZ_EXPORT void *bend_request_getdata(bend_request r);
+
+YAZ_END_CDECL
+
+#endif
Index: /main/tags/2.25/gsdl/packages/yaz/include/yaz/ccl.h
===================================================================
--- /main/tags/2.25/gsdl/packages/yaz/include/yaz/ccl.h	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/yaz/include/yaz/ccl.h	(revision 21064)
@@ -0,0 +1,343 @@
+/*
+ * Copyright (c) 1995, the EUROPAGATE consortium (see below).
+ *
+ * The EUROPAGATE consortium members are:
+ *
+ *    University College Dublin
+ *    Danmarks Teknologiske Videnscenter
+ *    An Chomhairle Leabharlanna
+ *    Consejo Superior de Investigaciones Cientificas
+ *
+ * Permission to use, copy, modify, distribute, and sell this software and
+ * its documentation, in whole or in part, for any purpose, is hereby granted,
+ * provided that:
+ *
+ * 1. This copyright and permission notice appear in all copies of the
+ * software and its documentation. Notices of copyright or attribution
+ * which appear at the beginning of any file must remain unchanged.
+ *
+ * 2. The names of EUROPAGATE or the project partners may not be used to
+ * endorse or promote products derived from this software without specific
+ * prior written permission.
+ *
+ * 3. Users of this software (implementors and gateway operators) agree to
+ * inform the EUROPAGATE consortium of their use of the software. This
+ * information will be used to evaluate the EUROPAGATE project and the
+ * software, and to plan further developments. The consortium may use
+ * the information in later publications.
+ * 
+ * 4. Users of this software agree to make their best efforts, when
+ * documenting their use of the software, to acknowledge the EUROPAGATE
+ * consortium, and the role played by the software in their work.
+ *
+ * THIS SOFTWARE IS PROVIDED "AS IS" AND WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS, IMPLIED, OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY
+ * WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
+ * IN NO EVENT SHALL THE EUROPAGATE CONSORTIUM OR ITS MEMBERS BE LIABLE
+ * FOR ANY SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF
+ * ANY KIND, OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA
+ * OR PROFITS, WHETHER OR NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND
+ * ON ANY THEORY OF LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE
+ * USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ */
+
+/*
+ * CCL - header file
+ *
+ * $Log$
+ * Revision 1.1  2000/08/03 03:10:32  johnmcp
+ * Added the YAZ toolkit source to the packages directory (for z39.50 stuff)
+ *
+ * Revision 1.3  2000/02/08 10:39:53  adam
+ * Added a few functions to set name of operands, etc.
+ *
+ * Revision 1.2  2000/01/31 13:15:21  adam
+ * Removed uses of assert(3). Cleanup of ODR. CCL parser update so
+ * that some characters are not surrounded by spaces in resulting term.
+ * ILL-code updates.
+ *
+ * Revision 1.1  1999/11/30 13:47:11  adam
+ * Improved installation. Moved header files to include/yaz.
+ *
+ * Revision 1.9  1998/02/11 11:53:33  adam
+ * Changed code so that it compiles as C++.
+ *
+ * Revision 1.8  1997/09/29 09:01:19  adam
+ * Changed CCL parser to be thread safe. New type, CCL-parser, declared
+ * and a create/destructor ccl_parser_create/ccl_parser_destroy has been
+ * added.
+ *
+ * Revision 1.7  1997/09/01 08:49:47  adam
+ * New windows NT/95 port using MSV5.0. To export DLL functions the
+ * YAZ_EXPORT modifier was added. Defined in yconfig.h.
+ *
+ * Revision 1.6  1997/05/14 06:53:37  adam
+ * C++ support.
+ *
+ * Revision 1.5  1997/04/30 08:52:08  quinn
+ * Null
+ *
+ * Revision 1.4  1996/10/11  15:02:26  adam
+ * CCL parser from Europagate Email gateway 1.0.
+ *
+ * Revision 1.10  1996/01/08  08:41:22  adam
+ * Minor changes.
+ *
+ * Revision 1.9  1995/07/20  08:15:16  adam
+ * Bug fix: Token value for comma and OR were the same!
+ *
+ * Revision 1.8  1995/07/11  12:28:34  adam
+ * New function: ccl_token_simple (split into simple tokens) and
+ *  ccl_token_del (delete tokens).
+ *
+ * Revision 1.7  1995/05/16  09:39:38  adam
+ * LICENSE.
+ *
+ * Revision 1.6  1995/05/11  14:04:03  adam
+ * Changes in the reading of qualifier(s). New function: ccl_qual_fitem.
+ * New variable ccl_case_sensitive, which controls whether reserved
+ * words and field names are case sensitive or not.
+ *
+ * Revision 1.5  1995/02/23  08:32:11  adam
+ * Changed header.
+ *
+ * Revision 1.3  1995/02/16  13:20:10  adam
+ * Spell fix.
+ *
+ * Revision 1.2  1995/02/15  17:43:08  adam
+ * Minor changes to the ccl interface. Bug fix in iso2709 module.
+ *
+ * Revision 1.1  1995/02/14  19:55:21  adam
+ * Header files ccl.h/cclp.h are gone! They have been merged an
+ * moved to ../include/ccl.h.
+ *
+ */
+
+#ifndef CCL_H
+#define CCL_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+    
+/* CCL error numbers */
+#define CCL_ERR_OK                0
+#define CCL_ERR_TERM_EXPECTED     1
+#define CCL_ERR_RP_EXPECTED       2
+#define CCL_ERR_SETNAME_EXPECTED  3
+#define CCL_ERR_OP_EXPECTED       4
+#define CCL_ERR_BAD_RP            5
+#define CCL_ERR_UNKNOWN_QUAL      6
+#define CCL_ERR_DOUBLE_QUAL       7
+#define CCL_ERR_EQ_EXPECTED       8
+#define CCL_ERR_BAD_RELATION      9
+#define CCL_ERR_TRUNC_NOT_LEFT   10
+#define CCL_ERR_TRUNC_NOT_BOTH   11
+#define CCL_ERR_TRUNC_NOT_RIGHT  12
+    
+/* attribute pair (type, value) */
+struct ccl_rpn_attr {
+    struct ccl_rpn_attr *next;
+    int type;
+    int value;
+};
+
+#define CCL_RPN_AND 1
+#define CCL_RPN_OR 2
+#define CCL_RPN_NOT 3
+#define CCL_RPN_TERM 4
+#define CCL_RPN_SET 5
+#define CCL_RPN_PROX 6
+
+/* RPN tree structure */
+struct ccl_rpn_node {
+    int kind;
+    union {
+	struct ccl_rpn_node *p[2];
+	struct {
+	    char *term;
+	    struct ccl_rpn_attr *attr_list;
+	} t;
+	char *setname;
+    } u;
+};
+
+typedef struct ccl_qualifiers *CCL_bibset;
+
+/* use (1)
+
+   relation (2)
+                            -1  none
+                             0  ordered
+                           1-6  relation (<, <=, =, >=, >, <>)
+
+   position (3)
+                            -1  none
+                             1  first in field
+                             2  first in sub field
+                             3  any position in field
+   structure (4)
+                            -1  none
+                             0  word/phrase auto select
+                             1  phrase
+                             2  word
+                             3  key
+                             4  year
+                             5  date (normalized)
+                             6  word list 
+                           100  date (un-normalized)
+                           101  name (normalized)
+                           102  name (un-normalized)
+   truncation (5)                            
+   completeness (6)
+*/
+
+#define CCL_BIB1_USE 1
+#define CCL_BIB1_REL 2
+#define CCL_BIB1_POS 3
+#define CCL_BIB1_STR 4
+#define CCL_BIB1_TRU 5
+#define CCL_BIB1_COM 6
+
+#define CCL_BIB1_STR_WP (-1)
+#define CCL_BIB1_REL_ORDER (-1)
+
+#define CCL_BIB1_TRU_CAN_LEFT (-1)
+#define CCL_BIB1_TRU_CAN_RIGHT (-2)
+#define CCL_BIB1_TRU_CAN_BOTH  (-3)
+#define CCL_BIB1_TRU_CAN_NONE  (-4)
+
+#define CCL_TOK_EOL   0
+#define CCL_TOK_TERM  1
+#define CCL_TOK_REL   2
+#define CCL_TOK_EQ    3
+#define CCL_TOK_PROX  4
+#define CCL_TOK_LP    5
+#define CCL_TOK_RP    6
+#define CCL_TOK_COMMA 7
+#define CCL_TOK_AND   8
+#define CCL_TOK_OR    9
+#define CCL_TOK_NOT   10
+#define CCL_TOK_MINUS 11
+#define CCL_TOK_SET   12
+
+/* CCL token */
+struct ccl_token {
+    char kind;
+    size_t len;
+    const char *name;
+    struct ccl_token *next;
+    struct ccl_token *prev;
+};
+
+/* CCL Qualifier */
+struct ccl_qualifier {
+    char *name;
+    struct ccl_rpn_attr *attr_list;
+    struct ccl_qualifier *next;
+};
+
+struct ccl_parser {
+/* current lookahead token */
+    struct ccl_token *look_token;
+    
+/* holds error code if error occur (and approx position of error) */
+    int error_code;
+    const char *error_pos;
+    
+/* current bibset */
+    CCL_bibset bibset;
+
+    char *ccl_token_and;
+    char *ccl_token_or;
+    char *ccl_token_not;
+    char *ccl_token_set;
+    int ccl_case_sensitive;
+};
+    
+typedef struct ccl_parser *CCL_parser;
+    
+/* Generate tokens from command string - obeys all CCL opererators */
+struct ccl_token *ccl_parser_tokenize (CCL_parser cclp,
+				       const char *command);
+struct ccl_token *ccl_tokenize (const char *command);
+    
+/* Generate tokens from command string - oebeys only simple tokens and 
+   quoted strings */
+struct ccl_token *ccl_token_simple (const char *command);
+
+/* Delete token list */
+void ccl_token_del (struct ccl_token *list);
+
+/* Parse CCL Find command - NULL-terminated string */
+struct ccl_rpn_node *ccl_find_str (CCL_bibset bibset,
+                                   const char *str, int *error, int *pos);
+
+/* Parse CCL Find command - Tokens read by ccl_tokenize */
+struct ccl_rpn_node *ccl_find (CCL_bibset abibset, struct ccl_token *list,
+                               int *error, const char **pos);
+
+/* Parse CCL Find command */
+struct ccl_rpn_node *ccl_parser_find (CCL_parser cclp, struct ccl_token *list);
+
+/* Set various OPs */
+void ccl_parser_set_op_and (CCL_parser p, const char *op);
+void ccl_parser_set_op_or (CCL_parser p, const char *op);
+void ccl_parser_set_op_not (CCL_parser p, const char *op);
+void ccl_parser_set_op_set (CCL_parser p, const char *op);
+
+void ccl_parser_set_case (CCL_parser p, int case_sensitivity_flag);
+
+/* Return english-readable error message */
+const char *ccl_err_msg (int ccl_errno);
+
+/* Delete RPN tree returned by ccl_find */
+void ccl_rpn_delete (struct ccl_rpn_node *rpn);
+
+/* Dump RPN tree in readable format to fd_out */
+void ccl_pr_tree (struct ccl_rpn_node *rpn, FILE *fd_out);
+
+/* Add CCL qualifier */
+void ccl_qual_add (CCL_bibset b, const char *name, int no, int *attr);
+
+/* Read CCL qualifier list spec from file inf */
+void ccl_qual_file (CCL_bibset bibset, FILE *inf);
+
+/* Add CCL qualifier by using single-line spec */
+void ccl_qual_fitem (CCL_bibset bibset, const char *cp, const char *qual_name);
+
+/* Make CCL qualifier set */
+CCL_bibset ccl_qual_mk (void);
+
+/* Delete CCL qualifier set */
+void ccl_qual_rm (CCL_bibset *b);
+
+/* Char-to-upper function */
+extern int (*ccl_toupper)(int c);
+
+/* String utilities */
+int ccl_stricmp (const char *s1, const char *s2);
+int ccl_memicmp (const char *s1, const char *s2, size_t n);
+
+/* Search for qualifier 'name' in set 'b'. */
+struct ccl_rpn_attr *ccl_qual_search (CCL_parser cclp, const char *name,
+                                      size_t len);
+
+/* Create CCL parser */
+CCL_parser ccl_parser_create (void);
+
+/* Destroy CCL parser */
+void ccl_parser_destroy (CCL_parser p);
+
+
+#ifndef ccl_assert
+#define ccl_assert(x) ;
+#endif
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
+
Index: /main/tags/2.25/gsdl/packages/yaz/include/yaz/comstack.h
===================================================================
--- /main/tags/2.25/gsdl/packages/yaz/include/yaz/comstack.h	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/yaz/include/yaz/comstack.h	(revision 21064)
@@ -0,0 +1,155 @@
+/*
+ * Copyright (c) 1995-2000, Index Data.
+ *
+ * Permission to use, copy, modify, distribute, and sell this software and
+ * its documentation, in whole or in part, for any purpose, is hereby granted,
+ * provided that:
+ *
+ * 1. This copyright and permission notice appear in all copies of the
+ * software and its documentation. Notices of copyright or attribution
+ * which appear at the beginning of any file must remain unchanged.
+ *
+ * 2. The name of Index Data or the individual authors may not be used to
+ * endorse or promote products derived from this software without specific
+ * prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED "AS IS" AND WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS, IMPLIED, OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY
+ * WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
+ * IN NO EVENT SHALL INDEX DATA BE LIABLE FOR ANY SPECIAL, INCIDENTAL,
+ * INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND, OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER OR
+ * NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF
+ * LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
+ * OF THIS SOFTWARE.
+ *
+ * $Id$
+ */
+
+#ifndef COMSTACK_H
+#define COMSTACK_H
+
+#include <yaz/yconfig.h>
+
+#ifndef _VMS_
+
+# ifdef WIN32
+
+#  include <winsock.h>
+
+# else /* #ifdef WIN32 */
+#  include <sys/types.h>
+#  include <sys/time.h>
+#  include <sys/wait.h>
+
+#  include <netinet/in.h>
+#  include <sys/socket.h>
+#  include <netdb.h>
+#  include <arpa/inet.h>
+
+#  ifdef _AIX
+#   include <sys/select.h>
+#  endif
+
+#  ifndef O_BINARY
+#   define O_BINARY 0
+#  endif
+
+# endif
+#endif /* ifndef _VMS_ */
+
+#include <yaz/oid.h>
+#include <yaz/xmalloc.h>
+
+YAZ_BEGIN_CDECL
+
+#define COMSTACK_DEFAULT_TIMEOUT -1  /* not used yet */
+
+struct comstack;
+typedef struct comstack *COMSTACK;
+typedef COMSTACK (*CS_TYPE)(int s, int blocking, int protocol);
+
+struct comstack
+{
+    CS_TYPE type;
+    int cerrno;     /* current error code of this stack */
+    char *stackerr;/* current lower-layer error string, or null if none */
+    int iofile;    /* UNIX file descriptor for iochannel */
+    int timeout;   /* how long to wait for trailing blocks (ignored for now) */
+    void *cprivate;/* state info for lower stack */
+    int more;      /* connection has extra data in buffer */
+    int state;     /* current state */
+#define CS_UNBND      0
+#define CS_IDLE       1
+#define CS_INCON      2
+#define CS_OUTCON     3
+#define CS_DATAXFER   4
+    int newfd;     /* storing new descriptor between listen and accept */
+    int blocking;  /* is this link (supposed to be) blocking? */
+    int event;     /* current event */
+#define CS_NONE       0
+#define CS_CONNECT    1
+#define CS_DISCON     2
+#define CS_LISTEN     3
+#define CS_DATA       4
+    enum oid_proto protocol;  /* what application protocol are we talking? */
+    int (*f_put)(COMSTACK handle, char *buf, int size);
+    int (*f_get)(COMSTACK handle, char **buf, int *bufsize);
+    int (*f_more)(COMSTACK handle);
+    int (*f_connect)(COMSTACK handle, void *address);
+    int (*f_rcvconnect)(COMSTACK handle);
+    int (*f_bind)(COMSTACK handle, void *address, int mode);
+#define CS_CLIENT 0
+#define CS_SERVER 1
+    int (*f_listen)(COMSTACK h, char *raddr, int *addrlen,
+		   int (*check_ip)(void *cd, const char *a, int len, int type),
+		   void *cd);
+    COMSTACK (*f_accept)(COMSTACK handle);
+    int (*f_close)(COMSTACK handle);
+    char *(*f_addrstr)(COMSTACK handle);
+    void *(*f_straddr)(COMSTACK handle, const char *str);
+};
+
+#define cs_put(handle, buf, size) ((*(handle)->f_put)(handle, buf, size))
+#define cs_get(handle, buf, size) ((*(handle)->f_get)(handle, buf, size))
+#define cs_more(handle) ((*(handle)->f_more)(handle))
+#define cs_connect(handle, address) ((*(handle)->f_connect)(handle, address))
+#define cs_rcvconnect(handle) ((*(handle)->f_rcvconnect)(handle))
+#define cs_bind(handle, ad, mo) ((*(handle)->f_bind)(handle, ad, mo))
+#define cs_listen(handle, ap, al) ((*(handle)->f_listen)(handle, ap, al, 0, 0))
+#define cs_listen_check(handle, ap, al, cf, cd) ((*(handle)->f_listen)(handle, ap, al, cf, cd))
+#define cs_accept(handle) ((*(handle)->f_accept)(handle))
+#define cs_close(handle) ((*(handle)->f_close)(handle))
+#define cs_create(type, blocking, proto) ((*type)(-1, blocking, proto))
+#define cs_createbysocket(sock, type, blocking, proto) \
+	((*type)(sock, blocking, proto))
+#define cs_type(handle) ((handle)->type)
+#define cs_fileno(handle) ((handle)->iofile)
+#define cs_stackerr(handle) ((handle)->stackerr)
+#define cs_getstate(handle) ((handle)->getstate)
+#define cs_errno(handle) ((handle)->cerrno)
+#define cs_getproto(handle) ((handle)->protocol)
+#define cs_addrstr(handle) ((*(handle)->f_addrstr)(handle))
+#define cs_straddr(handle, str) ((*(handle)->f_straddr)(handle, str))
+
+YAZ_EXPORT const char *cs_strerror(COMSTACK h);
+YAZ_EXPORT const char *cs_errmsg(int n);
+
+/*
+ * error management.
+ */
+
+#define CSNONE     0
+#define CSYSERR    1
+#define CSOUTSTATE 2
+#define CSNODATA   3
+#define CSWRONGBUF 4
+#define CSDENY     5
+
+/* backwards compatibility */
+#define CS_SR     PROTO_SR
+#define CS_Z3950  PROTO_Z3950
+
+YAZ_END_CDECL
+
+#endif
Index: /main/tags/2.25/gsdl/packages/yaz/include/yaz/d1_attset.h
===================================================================
--- /main/tags/2.25/gsdl/packages/yaz/include/yaz/d1_attset.h	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/yaz/include/yaz/d1_attset.h	(revision 21064)
@@ -0,0 +1,89 @@
+/*
+ * Copyright (c) 1995-2000, Index Data.
+ *
+ * Permission to use, copy, modify, distribute, and sell this software and
+ * its documentation, in whole or in part, for any purpose, is hereby granted,
+ * provided that:
+ *
+ * 1. This copyright and permission notice appear in all copies of the
+ * software and its documentation. Notices of copyright or attribution
+ * which appear at the beginning of any file must remain unchanged.
+ *
+ * 2. The names of Index Data or the individual authors may not be used to
+ * endorse or promote products derived from this software without specific
+ * prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED "AS IS" AND WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS, IMPLIED, OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY
+ * WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
+ * IN NO EVENT SHALL INDEX DATA BE LIABLE FOR ANY SPECIAL, INCIDENTAL,
+ * INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND, OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER OR
+ * NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF
+ * LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
+ * OF THIS SOFTWARE.
+ *
+ */
+
+#ifndef D1_ATTSET_H
+#define D1_ATTSET_H
+
+#include <yaz/oid.h>
+
+YAZ_BEGIN_CDECL
+
+/*
+ * This structure describes a attset, perhaps made up by inclusion
+ * (supersetting) of other attribute sets. When indexing and searching,
+ * we perform a normalisation, where we associate a given tag with
+ * the set that originally defined it, rather than the superset. This
+ * allows the most flexible access. Eg, the tags common to GILS and BIB-1
+ * should be searchable by both names.
+ */
+
+struct data1_attset;
+
+typedef struct data1_local_attribute
+{
+    int local;
+    struct data1_local_attribute *next;
+} data1_local_attribute;
+
+typedef struct data1_attset data1_attset;    
+typedef struct data1_att data1_att;
+typedef struct data1_attset_child data1_attset_child;
+
+struct data1_att
+{
+    data1_attset *parent;          /* attribute set */
+    char *name;                    /* symbolic name of this attribute */
+    int value;                     /* attribute value */
+    data1_local_attribute *locals; /* local index values */
+    data1_att *next;
+};
+
+struct data1_attset_child {
+    data1_attset *child;
+    data1_attset_child *next;
+};
+
+struct data1_attset
+{
+    char *name;          /* symbolic name */
+    oid_value reference;   /* external ID of attset */
+    data1_att *atts;          /* attributes */
+    data1_attset_child *children;  /* included attset */
+    data1_attset *next;       /* next in cache */
+};
+
+typedef struct data1_handle_info *data1_handle;
+
+YAZ_EXPORT data1_att *data1_getattbyname(data1_handle dh, data1_attset *s,
+					 char *name);
+YAZ_EXPORT data1_attset *data1_read_attset(data1_handle dh, const char *file);
+
+YAZ_EXPORT data1_attset *data1_empty_attset(data1_handle dh);
+
+YAZ_END_CDECL
+
+#endif
Index: /main/tags/2.25/gsdl/packages/yaz/include/yaz/d1_map.h
===================================================================
--- /main/tags/2.25/gsdl/packages/yaz/include/yaz/d1_map.h	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/yaz/include/yaz/d1_map.h	(revision 21064)
@@ -0,0 +1,67 @@
+/*
+ * Copyright (c) 1995-2000, Index Data.
+ *
+ * Permission to use, copy, modify, distribute, and sell this software and
+ * its documentation, in whole or in part, for any purpose, is hereby granted,
+ * provided that:
+ *
+ * 1. This copyright and permission notice appear in all copies of the
+ * software and its documentation. Notices of copyright or attribution
+ * which appear at the beginning of any file must remain unchanged.
+ *
+ * 2. The names of Index Data or the individual authors may not be used to
+ * endorse or promote products derived from this software without specific
+ * prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED "AS IS" AND WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS, IMPLIED, OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY
+ * WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
+ * IN NO EVENT SHALL INDEX DATA BE LIABLE FOR ANY SPECIAL, INCIDENTAL,
+ * INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND, OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER OR
+ * NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF
+ * LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
+ * OF THIS SOFTWARE.
+ *
+ */
+
+#ifndef D1_MAP_H
+#define D1_MAP_H
+
+YAZ_BEGIN_CDECL
+
+typedef struct data1_maptag
+{
+    int new_field;
+    int type;
+#define D1_MAPTAG_numeric 1
+#define D1_MAPTAG_string 2
+    int which;
+    union
+    {
+	int numeric;
+	char *string;
+    } value;
+    struct data1_maptag *next;
+} data1_maptag;
+
+typedef struct data1_mapunit
+{
+    int no_data;
+    char *source_element_name;
+    data1_maptag *target_path;
+    struct data1_mapunit *next;
+} data1_mapunit;
+
+typedef struct data1_maptab
+{
+    char *name;
+    oid_value target_absyn_ref;
+    char *target_absyn_name;
+    data1_mapunit *map;
+    struct data1_maptab *next;
+} data1_maptab;
+
+YAZ_END_CDECL
+
+#endif
Index: /main/tags/2.25/gsdl/packages/yaz/include/yaz/data1.h
===================================================================
--- /main/tags/2.25/gsdl/packages/yaz/include/yaz/data1.h	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/yaz/include/yaz/data1.h	(revision 21064)
@@ -0,0 +1,584 @@
+/*
+ * Copyright (c) 1995-2000, Index Data.
+ *
+ * Permission to use, copy, modify, distribute, and sell this software and
+ * its documentation, in whole or in part, for any purpose, is hereby granted,
+ * provided that:
+ *
+ * 1. This copyright and permission notice appear in all copies of the
+ * software and its documentation. Notices of copyright or attribution
+ * which appear at the beginning of any file must remain unchanged.
+ *
+ * 2. The names of Index Data or the individual authors may not be used to
+ * endorse or promote products derived from this software without specific
+ * prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED "AS IS" AND WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS, IMPLIED, OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY
+ * WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
+ * IN NO EVENT SHALL INDEX DATA BE LIABLE FOR ANY SPECIAL, INCIDENTAL,
+ * INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND, OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER OR
+ * NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF
+ * LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
+ * OF THIS SOFTWARE.
+ *
+ * $Log$
+ * Revision 1.1  2000/08/03 03:10:35  johnmcp
+ * Added the YAZ toolkit source to the packages directory (for z39.50 stuff)
+ *
+ * Revision 1.4  2000/02/28 11:20:06  adam
+ * Using autoconf. New definitions: YAZ_BEGIN_CDECL/YAZ_END_CDECL.
+ *
+ * Revision 1.3  2000/01/04 17:46:17  ian
+ * Added function to count occurences of a tag spec in a data1 tree.
+ *
+ * Revision 1.2  1999/12/21 14:16:19  ian
+ * Changed retrieval module to allow data1 trees with no associated absyn.
+ * Also added a simple interface for extracting values from data1 trees using
+ * a string based tagpath.
+ *
+ * Revision 1.1  1999/11/30 13:47:11  adam
+ * Improved installation. Moved header files to include/yaz.
+ *
+ * Revision 1.42  1999/10/21 12:06:28  adam
+ * Retrieval module no longer uses ctype.h - functions.
+ *
+ * Revision 1.41  1999/07/13 13:23:47  adam
+ * Non-recursive version of data1_read_node. data1_read_nodex reads
+ * stream of bytes (instead of buffer in memory).
+ *
+ * Revision 1.40  1998/11/03 10:14:12  adam
+ * Changed definition of data1 node so that it uses less space.
+ *
+ * Revision 1.39  1998/10/28 15:10:06  adam
+ * Added --with-yc option to configure. For the data1_node in data1.h:
+ * decreased size of localdata and removed member "line" which wasn't useful.
+ *
+ * Revision 1.38  1998/10/15 08:29:15  adam
+ * Tag set type may be specified in reference to it using "tagset"
+ * directive in .abs-files and "include" directive in .tag-files.
+ *
+ * Revision 1.37  1998/10/13 16:09:46  adam
+ * Added support for arbitrary OID's for tagsets, schemas and attribute sets.
+ * Added support for multiple attribute set references and tagset references
+ * from an abstract syntax file.
+ * Fixed many bad logs-calls in routines that read the various
+ * specifications regarding data1 (*.abs,*.att,...) and made the messages
+ * consistent whenever possible.
+ * Added extra 'lineno' argument to function readconf_line.
+ *
+ * Revision 1.36  1998/05/18 13:06:57  adam
+ * Changed the way attribute sets are handled by the retriaval module.
+ * Extended Explain conversion / schema.
+ * Modified server and client to work with ASN.1 compiled protocol handlers.
+ *
+ * Revision 1.35  1998/03/05 08:15:32  adam
+ * Implemented data1_add_insert_taggeddata utility which is more flexible
+ * than data1_insert_taggeddata.
+ *
+ * Revision 1.34  1998/02/27 14:08:04  adam
+ * Added const to some char pointer arguments.
+ * Reworked data1_read_node so that it doesn't create a tree with
+ * pointers to original "SGML"-buffer.
+ *
+ * Revision 1.33  1997/12/18 10:51:30  adam
+ * Implemented sub-trees feature for schemas - including forward
+ * references.
+ *
+ * Revision 1.32  1997/12/09 16:18:16  adam
+ * Work on EXPLAIN schema. First implementation of sub-schema facility
+ * in the *.abs files.
+ *
+ * Revision 1.31  1997/11/18 09:51:08  adam
+ * Removed element num_children from data1_node. Minor changes in
+ * data1 to Explain.
+ *
+ * Revision 1.30  1997/10/31 12:20:07  adam
+ * Improved memory debugging for xmalloc/nmem.c. References to NMEM
+ * instead of ODR in n ESPEC-1 handling in source d1_espec.c.
+ * Bug fix: missing fclose in data1_read_espec1.
+ *
+ * Revision 1.29  1997/10/27 13:54:18  adam
+ * Changed structure field in data1 node to be simple string which
+ * is "unknown" to the retrieval system itself.
+ *
+ * Revision 1.28  1997/10/06 09:37:53  adam
+ * Added prototype for data1_get_map_buf.
+ *
+ * Revision 1.27  1997/09/24 13:35:44  adam
+ * Added two members to data1_marctab to ease reading of weird MARC records.
+ *
+ * Revision 1.26  1997/09/17 12:10:32  adam
+ * YAZ version 1.4.
+ *
+ * Revision 1.25  1997/09/05 09:50:55  adam
+ * Removed global data1_tabpath - uses data1_get_tabpath() instead.
+ *
+ * Revision 1.24  1997/09/01 09:30:39  adam
+ * Added include of yaz-util.h.
+ *
+ * Revision 1.23  1997/09/01 08:58:04  adam
+ * Removed declaration of data1_matchstr since it's a macro.
+ *
+ * Revision 1.22  1997/09/01 08:49:48  adam
+ * New windows NT/95 port using MSV5.0. To export DLL functions the
+ * YAZ_EXPORT modifier was added. Defined in yconfig.h.
+ *
+ * Revision 1.21  1997/05/14 06:53:38  adam
+ * C++ support.
+ *
+ * Revision 1.20  1996/10/29 13:34:39  adam
+ * New functions to get/set data1_tabpath.
+ *
+ * Revision 1.19  1996/10/11 11:57:16  quinn
+ * Smallish
+ *
+ * Revision 1.18  1996/10/07  15:29:16  quinn
+ * Added SOIF support
+ *
+ * Revision 1.17  1996/07/06  19:58:32  quinn
+ * System headerfiles gathered in yconfig
+ *
+ * Revision 1.16  1996/06/10  08:55:34  quinn
+ * Added Summary. Unfinished work
+ *
+ * Revision 1.15  1996/06/03  09:46:03  quinn
+ * Added OID type.
+ *
+ * Revision 1.14  1996/05/09  07:27:11  quinn
+ * Multiple local values supported.
+ *
+ * Revision 1.13  1996/02/20  16:32:48  quinn
+ * Created util file.
+ *
+ * Revision 1.12  1996/01/18  09:46:34  adam
+ * Changed prototype for reader function parsed to data1_read_record.
+ *
+ * Revision 1.11  1995/12/15  16:19:45  quinn
+ * Added formatted_text.
+ *
+ * Revision 1.10  1995/12/14  11:09:43  quinn
+ * Work on Explain
+ *
+ * Revision 1.9  1995/12/13  15:32:47  quinn
+ * Added sgml-output.
+ *
+ * Revision 1.8  1995/12/13  13:44:23  quinn
+ * Modified Data1-system to use nmem
+ *
+ * Revision 1.7  1995/12/12  16:37:05  quinn
+ * Added destroy element to data1_node.
+ *
+ * Revision 1.6  1995/12/11  15:22:12  quinn
+ * Added last_child field to the node.
+ *
+ * Revision 1.5  1995/12/05  14:26:40  quinn
+ * Added global lbuf to data1_node.
+ *
+ * Revision 1.4  1995/11/13  09:27:29  quinn
+ * Fiddling with the variant stuff.
+ *
+ * Revision 1.3  1995/11/01  16:34:52  quinn
+ * Making data1 look for tables in data1_tabpath
+ *
+ * Revision 1.2  1995/11/01  13:54:35  quinn
+ * Minor adjustments
+ *
+ * Revision 1.1  1995/11/01  13:07:18  quinn
+ * Data1 module now lives in YAZ.
+ *
+ * Revision 1.13  1995/10/25  16:00:49  quinn
+ * USMARC support is now almost operational
+ *
+ * Revision 1.12  1995/10/16  14:02:59  quinn
+ * Changes to support element set names and espec1
+ *
+ * Revision 1.11  1995/10/13  16:05:10  quinn
+ * Adding Espec1-processing
+ *
+ * Revision 1.10  1995/10/11  14:53:46  quinn
+ * Work on variants.
+ *
+ * Revision 1.9  1995/10/10  16:27:59  quinn
+ * *** empty log message ***
+ *
+ * Revision 1.8  1995/10/06  16:44:14  quinn
+ * Work on attribute set mapping, etc.
+ *
+ * Revision 1.7  1995/10/06  12:58:36  quinn
+ * SUTRS support
+ *
+ * Revision 1.6  1995/10/04  09:29:51  quinn
+ * Adjustments to support USGS test data
+ *
+ * Revision 1.5  1995/10/03  17:56:44  quinn
+ * Fixing GRS code.
+ *
+ * Revision 1.4  1995/10/02  14:55:43  quinn
+ * *** empty log message ***
+ *
+ * Revision 1.3  1995/09/15  14:41:43  quinn
+ * GRS1 work
+ *
+ * Revision 1.2  1995/09/14  15:18:14  quinn
+ * Work
+ *
+ * Revision 1.1  1995/09/12  11:24:33  quinn
+ * Beginning to add code for structured records.
+ *
+ *
+ */
+
+#ifndef DATA1_H
+#define DATA1_H
+
+#include <stdio.h>
+
+#include <yaz/nmem.h>
+#include <yaz/oid.h>
+#include <yaz/proto.h>
+
+#include <yaz/d1_attset.h>
+#include <yaz/d1_map.h>
+#include <yaz/yaz-util.h>
+#include <yaz/wrbuf.h>
+
+#define d1_isspace(c) strchr(" \r\n\t\f", c)
+#define d1_isdigit(c) ((c) <= '9' && (c) >= '0')
+
+YAZ_BEGIN_CDECL
+
+#define data1_matchstr(s1, s2) yaz_matchstr(s1, s2)
+
+#define DATA1_MAX_SYMBOL 31
+
+typedef struct data1_name
+{
+    char *name;
+    struct data1_name *next;
+} data1_name;
+
+typedef struct data1_absyn_cache_info *data1_absyn_cache;
+typedef struct data1_attset_cache_info *data1_attset_cache;
+
+typedef enum data1_datatype
+{
+    DATA1K_unknown,
+    DATA1K_structured,
+    DATA1K_string,
+    DATA1K_numeric,
+    DATA1K_bool,
+    DATA1K_oid,
+    DATA1K_generalizedtime,
+    DATA1K_intunit,
+    DATA1K_int,
+    DATA1K_octetstring,
+    DATA1K_null
+} data1_datatype;
+
+typedef struct data1_marctab
+{
+    char *name;
+    oid_value reference;
+
+    char record_status[2];
+    char implementation_codes[5];
+    int  indicator_length;
+    int  identifier_length;
+    char user_systems[4];
+
+    int  length_data_entry;
+    int  length_starting;
+    int  length_implementation;
+    char future_use[2];
+
+    int  force_indicator_length;
+    int  force_identifier_length;
+    struct data1_marctab *next;
+} data1_marctab;
+
+typedef struct data1_esetname
+{
+    char *name;
+    Z_Espec1 *spec;
+    struct data1_esetname *next;
+} data1_esetname;
+
+/*
+ * Variant set definitions.
+ */
+
+typedef struct data1_vartype
+{
+    char *name;
+    struct data1_varclass *zclass;
+    int type;
+    data1_datatype datatype;
+    struct data1_vartype *next;
+} data1_vartype;
+
+typedef struct data1_varclass
+{
+    char *name;
+    struct data1_varset *set;
+    int zclass;
+    data1_vartype *types;
+    struct data1_varclass *next;
+} data1_varclass;
+
+typedef struct data1_varset
+{
+    char *name;
+    oid_value reference;
+    data1_varclass *classes;
+} data1_varset;
+
+/*
+ * Tagset definitions
+ */
+
+struct data1_tagset;
+
+typedef struct data1_tag
+{
+    data1_name *names;
+#define DATA1T_numeric 1
+#define DATA1T_string 2
+    int which;
+    union
+    {
+	int numeric;
+	char *string;
+    } value;
+    data1_datatype kind;
+
+    struct data1_tagset *tagset;
+    struct data1_tag *next;
+} data1_tag;
+
+typedef struct data1_tagset data1_tagset;
+
+struct data1_tagset
+{
+    int type;                        /* type of tagset in current context */
+    char *name;                      /* symbolic name */
+    oid_value reference;
+    data1_tag *tags;                 /* tags defined by this set */
+    data1_tagset *children;          /* children */
+    data1_tagset *next;              /* sibling */
+};
+
+typedef struct data1_termlist
+{
+    data1_att *att;
+    char *structure;
+    struct data1_termlist *next;
+} data1_termlist;
+
+/*
+ * abstract syntax specification
+ */
+
+typedef struct data1_element
+{
+    char *name;
+    data1_tag *tag;
+    data1_termlist *termlists;
+    char *sub_name;
+    struct data1_element *children;
+    struct data1_element *next;
+} data1_element;
+
+typedef struct data1_sub_elements {
+    char *name;
+    struct data1_sub_elements *next;
+    data1_element *elements;
+} data1_sub_elements;
+
+typedef struct data1_absyn
+{
+    char *name;
+    oid_value reference;
+    data1_tagset *tagset;
+    data1_attset *attset;
+    data1_varset *varset;
+    data1_esetname *esetnames;
+    data1_maptab *maptabs;
+    data1_marctab *marc;
+    data1_sub_elements *sub_elements;
+    data1_element *main_elements;
+} data1_absyn;
+
+/*
+ * record data node (tag/data/variant)
+ */
+
+typedef struct data1_node
+{
+    /* the root of a record (containing global data) */
+#define DATA1N_root 1 
+    /* a tag */
+#define DATA1N_tag  2       
+    /* some data under a leaf tag or variant */
+#define DATA1N_data 3
+    /* variant specification (a triple, actually) */
+#define DATA1N_variant 4
+    int which;
+
+    union
+    {
+	struct
+	{
+	    char *type;
+	    data1_absyn *absyn;  /* abstract syntax for this type */
+	} root;
+
+	struct 
+	{
+	    char *tag;
+	    data1_element *element;
+	    int no_data_requested;
+	    int get_bytes;
+	    unsigned node_selected : 1;
+	    unsigned make_variantlist : 1;
+	} tag;
+
+	struct
+	{
+	    char *data;      /* filename or data */
+	    int len;
+        /* text inclusion */
+#define DATA1I_inctxt 1
+        /* binary data inclusion */
+#define DATA1I_incbin 2
+        /* text data */
+#define DATA1I_text 3 
+        /* numerical data */
+#define DATA1I_num 4
+        /* object identifier */
+#define DATA1I_oid 5         
+            unsigned what:7;
+	    unsigned formatted_text : 1;   /* newlines are significant */
+	} data;
+
+	struct
+	{
+	    data1_vartype *type;
+	    char *value;
+	} variant;
+    } u;
+
+    void (*destroy)(struct data1_node *n);
+#define DATA1_LOCALDATA 12
+    char lbuf[DATA1_LOCALDATA]; /* small buffer for local data */
+    struct data1_node *next;
+    struct data1_node *child;
+    struct data1_node *last_child;
+    struct data1_node *parent;
+    struct data1_node *root;
+} data1_node;
+
+YAZ_EXPORT data1_handle data1_create (void);
+YAZ_EXPORT void data1_destroy(data1_handle dh);
+YAZ_EXPORT data1_node *get_parent_tag(data1_handle dh, data1_node *n);
+YAZ_EXPORT data1_node *data1_read_node(data1_handle dh, const char **buf,
+				       NMEM m);
+YAZ_EXPORT data1_node *data1_read_nodex (data1_handle dh, NMEM m,
+					 int (*get_byte)(void *fh), void *fh,
+					 WRBUF wrbuf);
+YAZ_EXPORT data1_node *data1_read_record(data1_handle dh, 
+					 int (*rf)(void *, char *, size_t),
+					 void *fh, NMEM m);
+YAZ_EXPORT data1_absyn *data1_read_absyn(data1_handle dh, const char *file);
+YAZ_EXPORT data1_tag *data1_gettagbynum(data1_handle dh,
+					data1_tagset *s,
+					int type, int value);
+YAZ_EXPORT data1_tagset *data1_empty_tagset (data1_handle dh);
+YAZ_EXPORT data1_tagset *data1_read_tagset(data1_handle dh, 
+					   const char *file,
+					   int type);
+YAZ_EXPORT data1_element *data1_getelementbytagname(data1_handle dh, 
+						    data1_absyn *abs,
+						    data1_element *parent,
+						    const char *tagname);
+YAZ_EXPORT Z_GenericRecord *data1_nodetogr(data1_handle dh, data1_node *n,
+					   int select, ODR o,
+					   int *len);
+YAZ_EXPORT data1_tag *data1_gettagbyname(data1_handle dh, data1_tagset *s,
+					 const char *name);
+YAZ_EXPORT void data1_free_tree(data1_handle dh, data1_node *t);
+YAZ_EXPORT char *data1_nodetobuf(data1_handle dh, data1_node *n,
+				 int select, int *len);
+YAZ_EXPORT data1_node *data1_insert_taggeddata(data1_handle dh,
+					       data1_node *root,
+					       data1_node *at,
+					       const char *tagname, NMEM m);
+YAZ_EXPORT data1_node *data1_add_taggeddata(data1_handle dh, data1_node *root,
+					    data1_node *at,
+					    const char *tagname, NMEM m);
+YAZ_EXPORT data1_datatype data1_maptype(data1_handle dh, char *t);
+YAZ_EXPORT data1_varset *data1_read_varset(data1_handle dh, const char *file);
+YAZ_EXPORT data1_vartype *data1_getvartypebyct(data1_handle dh,
+					       data1_varset *set,
+					       char *zclass, char *type);
+YAZ_EXPORT Z_Espec1 *data1_read_espec1(data1_handle dh, const char *file);
+YAZ_EXPORT int data1_doespec1(data1_handle dh, data1_node *n, Z_Espec1 *e);
+YAZ_EXPORT data1_esetname *data1_getesetbyname(data1_handle dh, 
+					       data1_absyn *a,
+					       const char *name);
+YAZ_EXPORT data1_element *data1_getelementbyname(data1_handle dh,
+						 data1_absyn *absyn,
+						 const char *name);
+YAZ_EXPORT data1_node *data1_mk_node(data1_handle dh, NMEM m);
+YAZ_EXPORT data1_absyn *data1_get_absyn(data1_handle dh, const char *name);
+YAZ_EXPORT data1_attset *data1_get_attset (data1_handle dh, const char *name);
+YAZ_EXPORT data1_maptab *data1_read_maptab(data1_handle dh, const char *file);
+YAZ_EXPORT data1_node *data1_map_record(data1_handle dh, data1_node *n,
+					data1_maptab *map, NMEM m);
+YAZ_EXPORT data1_marctab *data1_read_marctab (data1_handle dh,
+					      const char *file);
+YAZ_EXPORT char *data1_nodetomarc(data1_handle dh, data1_marctab *p,
+				  data1_node *n, int selected, int *len);
+YAZ_EXPORT char *data1_nodetoidsgml(data1_handle dh, data1_node *n,
+				    int select, int *len);
+YAZ_EXPORT Z_ExplainRecord *data1_nodetoexplain(data1_handle dh,
+						data1_node *n, int select,
+						ODR o);
+YAZ_EXPORT Z_BriefBib *data1_nodetosummary(data1_handle dh, 
+					   data1_node *n, int select,
+					   ODR o);
+YAZ_EXPORT char *data1_nodetosoif(data1_handle dh, data1_node *n, int select,
+				  int *len);
+YAZ_EXPORT void data1_set_tabpath(data1_handle dh, const char *path);
+YAZ_EXPORT const char *data1_get_tabpath(data1_handle dh);
+
+YAZ_EXPORT WRBUF data1_get_wrbuf (data1_handle dp);
+YAZ_EXPORT char **data1_get_read_buf (data1_handle dp, int **lenp);
+YAZ_EXPORT char **data1_get_map_buf (data1_handle dp, int **lenp);
+YAZ_EXPORT data1_absyn_cache *data1_absyn_cache_get (data1_handle dh);
+YAZ_EXPORT data1_attset_cache *data1_attset_cache_get (data1_handle dh);
+YAZ_EXPORT NMEM data1_nmem_get (data1_handle dh);
+YAZ_EXPORT void data1_pr_tree (data1_handle dh, data1_node *n, FILE *out);
+YAZ_EXPORT char *data1_insert_string (data1_handle dh, data1_node *res,
+				      NMEM m, const char *str);
+YAZ_EXPORT data1_node *data1_read_sgml (data1_handle dh, NMEM m,
+					const char *buf);
+YAZ_EXPORT void data1_absyn_trav (data1_handle dh, void *handle,
+				  void (*fh)(data1_handle dh,
+					     void *h, data1_absyn *a));
+
+YAZ_EXPORT data1_attset *data1_attset_search_id (data1_handle dh, int id);
+
+YAZ_EXPORT data1_node 
+*data1_add_insert_taggeddata(data1_handle dh, data1_node *root,
+                             data1_node *at, const char *tagname, NMEM m,
+                             int first_flag, int local_allowed);
+
+YAZ_EXPORT char *data1_getNodeValue(data1_node* node, char* pTagPath);
+YAZ_EXPORT data1_node *data1_LookupNode(data1_node* node, char* pTagPath);
+YAZ_EXPORT int data1_CountOccurences(data1_node* node, char* pTagPath);
+
+YAZ_END_CDECL
+
+#endif
Index: /main/tags/2.25/gsdl/packages/yaz/include/yaz/diagbib1.h
===================================================================
--- /main/tags/2.25/gsdl/packages/yaz/include/yaz/diagbib1.h	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/yaz/include/yaz/diagbib1.h	(revision 21064)
@@ -0,0 +1,71 @@
+/*
+ * Copyright (c) 1995-2000, Index Data.
+ *
+ * Permission to use, copy, modify, distribute, and sell this software and
+ * its documentation, in whole or in part, for any purpose, is hereby granted,
+ * provided that:
+ *
+ * 1. This copyright and permission notice appear in all copies of the
+ * software and its documentation. Notices of copyright or attribution
+ * which appear at the beginning of any file must remain unchanged.
+ *
+ * 2. The name of Index Data or the individual authors may not be used to
+ * endorse or promote products derived from this software without specific
+ * prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED "AS IS" AND WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS, IMPLIED, OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY
+ * WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
+ * IN NO EVENT SHALL INDEX DATA BE LIABLE FOR ANY SPECIAL, INCIDENTAL,
+ * INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND, OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER OR
+ * NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF
+ * LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
+ * OF THIS SOFTWARE.
+ *
+ * $Log$
+ * Revision 1.1  2000/08/03 03:10:35  johnmcp
+ * Added the YAZ toolkit source to the packages directory (for z39.50 stuff)
+ *
+ * Revision 1.2  2000/02/28 11:20:06  adam
+ * Using autoconf. New definitions: YAZ_BEGIN_CDECL/YAZ_END_CDECL.
+ *
+ * Revision 1.1  1999/11/30 13:47:11  adam
+ * Improved installation. Moved header files to include/yaz.
+ *
+ * Revision 1.6  1997/09/01 08:49:48  adam
+ * New windows NT/95 port using MSV5.0. To export DLL functions the
+ * YAZ_EXPORT modifier was added. Defined in yconfig.h.
+ *
+ * Revision 1.5  1997/05/14 06:53:39  adam
+ * C++ support.
+ *
+ * Revision 1.4  1995/09/29 17:12:02  quinn
+ * Smallish
+ *
+ * Revision 1.3  1995/09/27  15:02:47  quinn
+ * Modified function heads & prototypes.
+ *
+ * Revision 1.2  1995/05/16  08:50:30  quinn
+ * License, documentation, and memory fixes
+ *
+ * Revision 1.1  1995/03/30  09:39:40  quinn
+ * Moved .h files to include directory
+ *
+ * Revision 1.1  1995/03/15  13:46:09  adam
+ * New function diagbib1_str.
+ *
+ */
+
+#ifndef DIAGBIB1_H
+#define DIAGBIB1_H
+
+#include <yaz/yconfig.h>
+
+YAZ_BEGIN_CDECL
+
+YAZ_EXPORT const char *diagbib1_str (int code);
+
+YAZ_END_CDECL
+
+#endif
Index: /main/tags/2.25/gsdl/packages/yaz/include/yaz/ill-core.h
===================================================================
--- /main/tags/2.25/gsdl/packages/yaz/include/yaz/ill-core.h	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/yaz/include/yaz/ill-core.h	(revision 21064)
@@ -0,0 +1,1329 @@
+/* Generated automatically by the YAZ ASN.1 Compiler 0.3 */
+/* Module-H ISO-10161-ILL-1 */
+
+#ifndef ill_core_H
+#define ill_core_H
+
+#include <yaz/odr.h>
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+
+
+typedef struct ILL_APDU ILL_APDU;
+YAZ_EXPORT int ill_APDU (ODR o, ILL_APDU **p, int opt, const char *name);
+
+typedef struct ILL_Request ILL_Request;
+YAZ_EXPORT int ill_Request (ODR o, ILL_Request **p, int opt, const char *name);
+
+typedef struct ILL_Forward_Notification ILL_Forward_Notification;
+YAZ_EXPORT int ill_Forward_Notification (ODR o, ILL_Forward_Notification **p, int opt, const char *name);
+
+typedef struct ILL_Shipped ILL_Shipped;
+YAZ_EXPORT int ill_Shipped (ODR o, ILL_Shipped **p, int opt, const char *name);
+
+typedef struct ILL_Answer ILL_Answer;
+YAZ_EXPORT int ill_Answer (ODR o, ILL_Answer **p, int opt, const char *name);
+
+typedef struct ILL_Conditional_Reply ILL_Conditional_Reply;
+YAZ_EXPORT int ill_Conditional_Reply (ODR o, ILL_Conditional_Reply **p, int opt, const char *name);
+
+typedef struct ILL_Cancel ILL_Cancel;
+YAZ_EXPORT int ill_Cancel (ODR o, ILL_Cancel **p, int opt, const char *name);
+
+typedef struct ILL_Cancel_Reply ILL_Cancel_Reply;
+YAZ_EXPORT int ill_Cancel_Reply (ODR o, ILL_Cancel_Reply **p, int opt, const char *name);
+
+typedef struct ILL_Received ILL_Received;
+YAZ_EXPORT int ill_Received (ODR o, ILL_Received **p, int opt, const char *name);
+
+typedef struct ILL_Recall ILL_Recall;
+YAZ_EXPORT int ill_Recall (ODR o, ILL_Recall **p, int opt, const char *name);
+
+typedef struct ILL_Returned ILL_Returned;
+YAZ_EXPORT int ill_Returned (ODR o, ILL_Returned **p, int opt, const char *name);
+
+typedef struct ILL_Checked_In ILL_Checked_In;
+YAZ_EXPORT int ill_Checked_In (ODR o, ILL_Checked_In **p, int opt, const char *name);
+
+typedef struct ILL_Overdue_Extension ILL_Overdue_Extension;
+YAZ_EXPORT int ill_Overdue_Extension (ODR o, ILL_Overdue_Extension **p, int opt, const char *name);
+
+typedef struct ILL_Overdue ILL_Overdue;
+YAZ_EXPORT int ill_Overdue (ODR o, ILL_Overdue **p, int opt, const char *name);
+
+typedef struct ILL_Renew ILL_Renew;
+YAZ_EXPORT int ill_Renew (ODR o, ILL_Renew **p, int opt, const char *name);
+
+typedef struct ILL_Renew_Answer ILL_Renew_Answer;
+YAZ_EXPORT int ill_Renew_Answer (ODR o, ILL_Renew_Answer **p, int opt, const char *name);
+
+typedef struct ILL_Lost ILL_Lost;
+YAZ_EXPORT int ill_Lost (ODR o, ILL_Lost **p, int opt, const char *name);
+
+typedef struct ILL_Damaged ILL_Damaged;
+YAZ_EXPORT int ill_Damaged (ODR o, ILL_Damaged **p, int opt, const char *name);
+
+typedef struct ILL_Message ILL_Message;
+YAZ_EXPORT int ill_Message (ODR o, ILL_Message **p, int opt, const char *name);
+
+typedef struct ILL_Status_Query ILL_Status_Query;
+YAZ_EXPORT int ill_Status_Query (ODR o, ILL_Status_Query **p, int opt, const char *name);
+
+typedef struct ILL_Status_Or_Error_Report ILL_Status_Or_Error_Report;
+YAZ_EXPORT int ill_Status_Or_Error_Report (ODR o, ILL_Status_Or_Error_Report **p, int opt, const char *name);
+
+typedef struct ILL_Expired ILL_Expired;
+YAZ_EXPORT int ill_Expired (ODR o, ILL_Expired **p, int opt, const char *name);
+
+typedef struct ILL_Already_Forwarded ILL_Already_Forwarded;
+YAZ_EXPORT int ill_Already_Forwarded (ODR o, ILL_Already_Forwarded **p, int opt, const char *name);
+
+typedef struct ILL_Already_Tried_List_Type ILL_Already_Tried_List_Type;
+YAZ_EXPORT int ill_Already_Tried_List_Type (ODR o, ILL_Already_Tried_List_Type **p, int opt, const char *name);
+
+typedef struct ILL_Amount ILL_Amount;
+YAZ_EXPORT int ill_Amount (ODR o, ILL_Amount **p, int opt, const char *name);
+
+typedef char  ILL_AmountString;
+YAZ_EXPORT int ill_AmountString (ODR o, ILL_AmountString **p, int opt, const char *name);
+
+typedef struct ILL_Client_Id ILL_Client_Id;
+YAZ_EXPORT int ill_Client_Id (ODR o, ILL_Client_Id **p, int opt, const char *name);
+
+typedef struct ILL_Conditional_Results ILL_Conditional_Results;
+YAZ_EXPORT int ill_Conditional_Results (ODR o, ILL_Conditional_Results **p, int opt, const char *name);
+
+typedef struct ILL_Cost_Info_Type ILL_Cost_Info_Type;
+YAZ_EXPORT int ill_Cost_Info_Type (ODR o, ILL_Cost_Info_Type **p, int opt, const char *name);
+
+typedef int  ILL_Current_State;
+YAZ_EXPORT int ill_Current_State (ODR o, ILL_Current_State **p, int opt, const char *name);
+
+typedef struct ILL_Damaged_DetailsSpecific_units ILL_Damaged_DetailsSpecific_units;
+YAZ_EXPORT int ill_Damaged_DetailsSpecific_units (ODR o, ILL_Damaged_DetailsSpecific_units **p, int opt, const char *name);
+
+typedef struct ILL_Damaged_Details ILL_Damaged_Details;
+YAZ_EXPORT int ill_Damaged_Details (ODR o, ILL_Damaged_Details **p, int opt, const char *name);
+
+typedef struct ILL_Date_Due ILL_Date_Due;
+YAZ_EXPORT int ill_Date_Due (ODR o, ILL_Date_Due **p, int opt, const char *name);
+
+typedef struct ILL_Delivery_Address ILL_Delivery_Address;
+YAZ_EXPORT int ill_Delivery_Address (ODR o, ILL_Delivery_Address **p, int opt, const char *name);
+
+typedef struct ILL_Delivery_ServiceElectronic_delivery ILL_Delivery_ServiceElectronic_delivery;
+YAZ_EXPORT int ill_Delivery_ServiceElectronic_delivery (ODR o, ILL_Delivery_ServiceElectronic_delivery **p, int opt, const char *name);
+
+typedef struct ILL_Delivery_Service ILL_Delivery_Service;
+YAZ_EXPORT int ill_Delivery_Service (ODR o, ILL_Delivery_Service **p, int opt, const char *name);
+
+typedef struct ILL_Electronic_Delivery_Service_0 ILL_Electronic_Delivery_Service_0;
+YAZ_EXPORT int ill_Electronic_Delivery_Service_0 (ODR o, ILL_Electronic_Delivery_Service_0 **p, int opt, const char *name);
+
+typedef struct ILL_Electronic_Delivery_Service_1 ILL_Electronic_Delivery_Service_1;
+YAZ_EXPORT int ill_Electronic_Delivery_Service_1 (ODR o, ILL_Electronic_Delivery_Service_1 **p, int opt, const char *name);
+
+typedef struct ILL_Electronic_Delivery_Service ILL_Electronic_Delivery_Service;
+YAZ_EXPORT int ill_Electronic_Delivery_Service (ODR o, ILL_Electronic_Delivery_Service **p, int opt, const char *name);
+
+typedef struct ILL_Error_Report ILL_Error_Report;
+YAZ_EXPORT int ill_Error_Report (ODR o, ILL_Error_Report **p, int opt, const char *name);
+
+typedef struct ILL_Estimate_Results ILL_Estimate_Results;
+YAZ_EXPORT int ill_Estimate_Results (ODR o, ILL_Estimate_Results **p, int opt, const char *name);
+
+typedef struct ILL_Extension ILL_Extension;
+YAZ_EXPORT int ill_Extension (ODR o, ILL_Extension **p, int opt, const char *name);
+
+typedef int  ILL_General_Problem;
+YAZ_EXPORT int ill_General_Problem (ODR o, ILL_General_Problem **p, int opt, const char *name);
+
+typedef struct ILL_History_Report ILL_History_Report;
+YAZ_EXPORT int ill_History_Report (ODR o, ILL_History_Report **p, int opt, const char *name);
+
+typedef struct ILL_Hold_Placed_Results ILL_Hold_Placed_Results;
+YAZ_EXPORT int ill_Hold_Placed_Results (ODR o, ILL_Hold_Placed_Results **p, int opt, const char *name);
+
+typedef int  ILL_APDU_Type;
+YAZ_EXPORT int ill_APDU_Type (ODR o, ILL_APDU_Type **p, int opt, const char *name);
+
+typedef int  ILL_Service_Type;
+YAZ_EXPORT int ill_Service_Type (ODR o, ILL_Service_Type **p, int opt, const char *name);
+
+typedef struct ILL_String ILL_String;
+YAZ_EXPORT int ill_String (ODR o, ILL_String **p, int opt, const char *name);
+
+typedef ILL_String  ILL_Account_Number;
+YAZ_EXPORT int ill_Account_Number (ODR o, ILL_Account_Number **p, int opt, const char *name);
+
+typedef int  ILL_Intermediary_Problem;
+YAZ_EXPORT int ill_Intermediary_Problem (ODR o, ILL_Intermediary_Problem **p, int opt, const char *name);
+
+typedef char  ILL_ISO_Date;
+YAZ_EXPORT int ill_ISO_Date (ODR o, ILL_ISO_Date **p, int opt, const char *name);
+
+typedef char  ILL_ISO_Time;
+YAZ_EXPORT int ill_ISO_Time (ODR o, ILL_ISO_Time **p, int opt, const char *name);
+
+typedef struct ILL_Item_Id ILL_Item_Id;
+YAZ_EXPORT int ill_Item_Id (ODR o, ILL_Item_Id **p, int opt, const char *name);
+
+typedef struct ILL_Location_Info ILL_Location_Info;
+YAZ_EXPORT int ill_Location_Info (ODR o, ILL_Location_Info **p, int opt, const char *name);
+
+typedef struct ILL_Locations_Results ILL_Locations_Results;
+YAZ_EXPORT int ill_Locations_Results (ODR o, ILL_Locations_Results **p, int opt, const char *name);
+
+typedef int  ILL_Medium_Type;
+YAZ_EXPORT int ill_Medium_Type (ODR o, ILL_Medium_Type **p, int opt, const char *name);
+
+typedef struct ILL_Name_Of_Person_Or_Institution ILL_Name_Of_Person_Or_Institution;
+YAZ_EXPORT int ill_Name_Of_Person_Or_Institution (ODR o, ILL_Name_Of_Person_Or_Institution **p, int opt, const char *name);
+
+typedef struct ILL_Person_Or_Institution_Symbol ILL_Person_Or_Institution_Symbol;
+YAZ_EXPORT int ill_Person_Or_Institution_Symbol (ODR o, ILL_Person_Or_Institution_Symbol **p, int opt, const char *name);
+
+typedef int  ILL_Place_On_Hold_Type;
+YAZ_EXPORT int ill_Place_On_Hold_Type (ODR o, ILL_Place_On_Hold_Type **p, int opt, const char *name);
+
+typedef struct ILL_Postal_Address ILL_Postal_Address;
+YAZ_EXPORT int ill_Postal_Address (ODR o, ILL_Postal_Address **p, int opt, const char *name);
+
+typedef struct ILL_Provider_Error_Report ILL_Provider_Error_Report;
+YAZ_EXPORT int ill_Provider_Error_Report (ODR o, ILL_Provider_Error_Report **p, int opt, const char *name);
+
+typedef int  ILL_Reason_Locs_Provided;
+YAZ_EXPORT int ill_Reason_Locs_Provided (ODR o, ILL_Reason_Locs_Provided **p, int opt, const char *name);
+
+typedef int  ILL_Reason_No_Report;
+YAZ_EXPORT int ill_Reason_No_Report (ODR o, ILL_Reason_No_Report **p, int opt, const char *name);
+
+typedef int  ILL_Reason_Unfilled;
+YAZ_EXPORT int ill_Reason_Unfilled (ODR o, ILL_Reason_Unfilled **p, int opt, const char *name);
+
+typedef int  ILL_Report_Source;
+YAZ_EXPORT int ill_Report_Source (ODR o, ILL_Report_Source **p, int opt, const char *name);
+
+typedef struct ILL_Requester_Optional_Messages_Type ILL_Requester_Optional_Messages_Type;
+YAZ_EXPORT int ill_Requester_Optional_Messages_Type (ODR o, ILL_Requester_Optional_Messages_Type **p, int opt, const char *name);
+
+typedef struct ILL_Responder_Optional_Messages_Type ILL_Responder_Optional_Messages_Type;
+YAZ_EXPORT int ill_Responder_Optional_Messages_Type (ODR o, ILL_Responder_Optional_Messages_Type **p, int opt, const char *name);
+
+typedef struct ILL_Retry_Results ILL_Retry_Results;
+YAZ_EXPORT int ill_Retry_Results (ODR o, ILL_Retry_Results **p, int opt, const char *name);
+
+typedef struct ILL_Search_Type ILL_Search_Type;
+YAZ_EXPORT int ill_Search_Type (ODR o, ILL_Search_Type **p, int opt, const char *name);
+
+typedef ILL_String  ILL_Security_Problem;
+YAZ_EXPORT int ill_Security_Problem (ODR o, ILL_Security_Problem **p, int opt, const char *name);
+
+typedef struct ILL_Send_To_List_Type_s ILL_Send_To_List_Type_s;
+YAZ_EXPORT int ill_Send_To_List_Type_s (ODR o, ILL_Send_To_List_Type_s **p, int opt, const char *name);
+
+typedef struct ILL_Send_To_List_Type ILL_Send_To_List_Type;
+YAZ_EXPORT int ill_Send_To_List_Type (ODR o, ILL_Send_To_List_Type **p, int opt, const char *name);
+
+typedef struct ILL_Service_Date_this ILL_Service_Date_this;
+YAZ_EXPORT int ill_Service_Date_this (ODR o, ILL_Service_Date_this **p, int opt, const char *name);
+
+typedef struct ILL_Service_Date_original ILL_Service_Date_original;
+YAZ_EXPORT int ill_Service_Date_original (ODR o, ILL_Service_Date_original **p, int opt, const char *name);
+
+typedef struct ILL_Service_Date_Time ILL_Service_Date_Time;
+YAZ_EXPORT int ill_Service_Date_Time (ODR o, ILL_Service_Date_Time **p, int opt, const char *name);
+
+typedef ILL_Service_Type  ILL_Shipped_Service_Type;
+YAZ_EXPORT int ill_Shipped_Service_Type (ODR o, ILL_Shipped_Service_Type **p, int opt, const char *name);
+
+typedef struct ILL_State_Transition_Prohibited ILL_State_Transition_Prohibited;
+YAZ_EXPORT int ill_State_Transition_Prohibited (ODR o, ILL_State_Transition_Prohibited **p, int opt, const char *name);
+
+typedef struct ILL_Status_Report ILL_Status_Report;
+YAZ_EXPORT int ill_Status_Report (ODR o, ILL_Status_Report **p, int opt, const char *name);
+
+typedef struct ILL_Supplemental_Item_Description ILL_Supplemental_Item_Description;
+YAZ_EXPORT int ill_Supplemental_Item_Description (ODR o, ILL_Supplemental_Item_Description **p, int opt, const char *name);
+
+typedef struct ILL_Supply_Details ILL_Supply_Details;
+YAZ_EXPORT int ill_Supply_Details (ODR o, ILL_Supply_Details **p, int opt, const char *name);
+
+typedef struct ILL_Supply_Medium_Info_Type ILL_Supply_Medium_Info_Type;
+YAZ_EXPORT int ill_Supply_Medium_Info_Type (ODR o, ILL_Supply_Medium_Info_Type **p, int opt, const char *name);
+
+typedef int  ILL_Supply_Medium_Type;
+YAZ_EXPORT int ill_Supply_Medium_Type (ODR o, ILL_Supply_Medium_Type **p, int opt, const char *name);
+
+typedef struct ILL_System_Address ILL_System_Address;
+YAZ_EXPORT int ill_System_Address (ODR o, ILL_System_Address **p, int opt, const char *name);
+
+typedef struct ILL_System_Id ILL_System_Id;
+YAZ_EXPORT int ill_System_Id (ODR o, ILL_System_Id **p, int opt, const char *name);
+
+typedef struct ILL_Third_Party_Info_Type ILL_Third_Party_Info_Type;
+YAZ_EXPORT int ill_Third_Party_Info_Type (ODR o, ILL_Third_Party_Info_Type **p, int opt, const char *name);
+
+typedef struct ILL_Transaction_Id ILL_Transaction_Id;
+YAZ_EXPORT int ill_Transaction_Id (ODR o, ILL_Transaction_Id **p, int opt, const char *name);
+
+typedef int  ILL_Transaction_Id_Problem;
+YAZ_EXPORT int ill_Transaction_Id_Problem (ODR o, ILL_Transaction_Id_Problem **p, int opt, const char *name);
+
+typedef int  ILL_Transaction_Results;
+YAZ_EXPORT int ill_Transaction_Results (ODR o, ILL_Transaction_Results **p, int opt, const char *name);
+
+typedef int  ILL_Transaction_Type;
+YAZ_EXPORT int ill_Transaction_Type (ODR o, ILL_Transaction_Type **p, int opt, const char *name);
+
+typedef ILL_String  ILL_Transportation_Mode;
+YAZ_EXPORT int ill_Transportation_Mode (ODR o, ILL_Transportation_Mode **p, int opt, const char *name);
+
+typedef int  ILL_Unable_To_Perform;
+YAZ_EXPORT int ill_Unable_To_Perform (ODR o, ILL_Unable_To_Perform **p, int opt, const char *name);
+
+typedef struct ILL_Unfilled_Results ILL_Unfilled_Results;
+YAZ_EXPORT int ill_Unfilled_Results (ODR o, ILL_Unfilled_Results **p, int opt, const char *name);
+
+typedef struct ILL_Units_Per_Medium_Type ILL_Units_Per_Medium_Type;
+YAZ_EXPORT int ill_Units_Per_Medium_Type (ODR o, ILL_Units_Per_Medium_Type **p, int opt, const char *name);
+
+typedef struct ILL_User_Error_Report ILL_User_Error_Report;
+YAZ_EXPORT int ill_User_Error_Report (ODR o, ILL_User_Error_Report **p, int opt, const char *name);
+
+typedef struct ILL_Will_Supply_Results ILL_Will_Supply_Results;
+YAZ_EXPORT int ill_Will_Supply_Results (ODR o, ILL_Will_Supply_Results **p, int opt, const char *name);
+
+typedef char  ILL_EDIFACTString;
+YAZ_EXPORT int ill_EDIFACTString (ODR o, ILL_EDIFACTString **p, int opt, const char *name);
+#ifdef __cplusplus
+}
+#endif
+#ifdef __cplusplus
+extern "C" {
+#endif
+struct ILL_APDU {
+	int which;
+	union {
+		ILL_Request *ILL_Request;
+		ILL_Forward_Notification *Forward_Notification;
+		ILL_Shipped *Shipped;
+		ILL_Answer *ILL_Answer;
+		ILL_Conditional_Reply *Conditional_Reply;
+		ILL_Cancel *Cancel;
+		ILL_Cancel_Reply *Cancel_Reply;
+		ILL_Received *Received;
+		ILL_Recall *Recall;
+		ILL_Returned *Returned;
+		ILL_Checked_In *Checked_In;
+		ILL_Overdue *Overdue;
+		ILL_Renew *Renew;
+		ILL_Renew_Answer *Renew_Answer;
+		ILL_Lost *Lost;
+		ILL_Damaged *Damaged;
+		ILL_Message *Message;
+		ILL_Status_Query *Status_Query;
+		ILL_Status_Or_Error_Report *Status_Or_Error_Report;
+		ILL_Expired *Expired;
+#define ILL_APDU_ILL_Request 1
+#define ILL_APDU_Forward_Notification 2
+#define ILL_APDU_Shipped 3
+#define ILL_APDU_ILL_Answer 4
+#define ILL_APDU_Conditional_Reply 5
+#define ILL_APDU_Cancel 6
+#define ILL_APDU_Cancel_Reply 7
+#define ILL_APDU_Received 8
+#define ILL_APDU_Recall 9
+#define ILL_APDU_Returned 10
+#define ILL_APDU_Checked_In 11
+#define ILL_APDU_Overdue 12
+#define ILL_APDU_Renew 13
+#define ILL_APDU_Renew_Answer 14
+#define ILL_APDU_Lost 15
+#define ILL_APDU_Damaged 16
+#define ILL_APDU_Message 17
+#define ILL_APDU_Status_Query 18
+#define ILL_APDU_Status_Or_Error_Report 19
+#define ILL_APDU_Expired 20
+	} u;
+};
+
+struct ILL_Request {
+#define ILL_Request_version_1 1
+#define ILL_Request_version_2 2
+	int *protocol_version_num;
+	ILL_Transaction_Id *transaction_id;
+	ILL_Service_Date_Time *service_date_time;
+	ILL_System_Id *requester_id; /* OPT */
+	ILL_System_Id *responder_id; /* OPT */
+	ILL_Transaction_Type *transaction_type;
+	ILL_Delivery_Address *delivery_address; /* OPT */
+	ILL_Delivery_Service *delivery_service; /* OPT */
+	ILL_Delivery_Address *billing_address; /* OPT */
+	int num_iLL_service_type;
+	ILL_Service_Type **iLL_service_type;
+	Odr_external *responder_specific_service; /* OPT */
+	ILL_Requester_Optional_Messages_Type *requester_optional_messages;
+	ILL_Search_Type *search_type; /* OPT */
+	int num_supply_medium_info_type;
+	ILL_Supply_Medium_Info_Type **supply_medium_info_type; /* OPT */
+	ILL_Place_On_Hold_Type *place_on_hold;
+	ILL_Client_Id *client_id; /* OPT */
+	ILL_Item_Id *item_id;
+	ILL_Supplemental_Item_Description *supplemental_item_description; /* OPT */
+	ILL_Cost_Info_Type *cost_info_type; /* OPT */
+	ILL_String *copyright_compliance; /* OPT */
+	ILL_Third_Party_Info_Type *third_party_info_type; /* OPT */
+	bool_t *retry_flag;
+	bool_t *forward_flag;
+	ILL_String *requester_note; /* OPT */
+	ILL_String *forward_note; /* OPT */
+	int num_iLL_request_extensions;
+	ILL_Extension **iLL_request_extensions; /* OPT */
+};
+
+struct ILL_Forward_Notification {
+#define ILL_Forward_Notification_version_1 1
+#define ILL_Forward_Notification_version_2 2
+	int *protocol_version_num;
+	ILL_Transaction_Id *transaction_id;
+	ILL_Service_Date_Time *service_date_time;
+	ILL_System_Id *requester_id; /* OPT */
+	ILL_System_Id *responder_id;
+	ILL_System_Address *responder_address; /* OPT */
+	ILL_System_Id *intermediary_id;
+	ILL_String *notification_note; /* OPT */
+	int num_forward_notification_extensions;
+	ILL_Extension **forward_notification_extensions; /* OPT */
+};
+
+struct ILL_Shipped {
+#define ILL_Shipped_version_1 1
+#define ILL_Shipped_version_2 2
+	int *protocol_version_num;
+	ILL_Transaction_Id *transaction_id;
+	ILL_Service_Date_Time *service_date_time;
+	ILL_System_Id *requester_id; /* OPT */
+	ILL_System_Id *responder_id; /* OPT */
+	ILL_System_Address *responder_address; /* OPT */
+	ILL_System_Id *intermediary_id; /* OPT */
+	ILL_System_Id *supplier_id; /* OPT */
+	ILL_Client_Id *client_id; /* OPT */
+	ILL_Transaction_Type *transaction_type;
+	ILL_Supplemental_Item_Description *supplemental_item_description; /* OPT */
+	ILL_Shipped_Service_Type *shipped_service_type;
+	ILL_Responder_Optional_Messages_Type *responder_optional_messages; /* OPT */
+	ILL_Supply_Details *supply_details;
+	ILL_Postal_Address *return_to_address; /* OPT */
+	ILL_String *responder_note; /* OPT */
+	int num_shipped_extensions;
+	ILL_Extension **shipped_extensions; /* OPT */
+};
+
+struct ILL_Answer {
+#define ILL_Answer_version_1 1
+#define ILL_Answer_version_2 2
+	int *protocol_version_num;
+	ILL_Transaction_Id *transaction_id;
+	ILL_Service_Date_Time *service_date_time;
+	ILL_System_Id *requester_id; /* OPT */
+	ILL_System_Id *responder_id; /* OPT */
+	ILL_Transaction_Results *transaction_results;
+	int which;
+	union {
+		ILL_Conditional_Results *conditional_results;
+		ILL_Retry_Results *retry_results;
+		ILL_Unfilled_Results *unfilled_results;
+		ILL_Locations_Results *locations_results;
+		ILL_Will_Supply_Results *will_supply_results;
+		ILL_Hold_Placed_Results *hold_placed_results;
+		ILL_Estimate_Results *estimate_results;
+#define ILL_Answer_conditional_results 1
+#define ILL_Answer_retry_results 2
+#define ILL_Answer_unfilled_results 3
+#define ILL_Answer_locations_results 4
+#define ILL_Answer_will_supply_results 5
+#define ILL_Answer_hold_placed_results 6
+#define ILL_Answer_estimate_results 7
+	} u; /* OPT */
+	Odr_external *responder_specific_results; /* OPT */
+	ILL_Supplemental_Item_Description *supplemental_item_description; /* OPT */
+	ILL_Send_To_List_Type *send_to_list; /* OPT */
+	ILL_Already_Tried_List_Type *already_tried_list; /* OPT */
+	ILL_Responder_Optional_Messages_Type *responder_optional_messages; /* OPT */
+	ILL_String *responder_note; /* OPT */
+	int num_ill_answer_extensions;
+	ILL_Extension **ill_answer_extensions; /* OPT */
+};
+
+struct ILL_Conditional_Reply {
+#define ILL_Conditional_Reply_version_1 1
+#define ILL_Conditional_Reply_version_2 2
+	int *protocol_version_num;
+	ILL_Transaction_Id *transaction_id;
+	ILL_Service_Date_Time *service_date_time;
+	ILL_System_Id *requester_id; /* OPT */
+	ILL_System_Id *responder_id; /* OPT */
+	bool_t *answer;
+	ILL_String *requester_note; /* OPT */
+	int num_conditional_reply_extensions;
+	ILL_Extension **conditional_reply_extensions; /* OPT */
+};
+
+struct ILL_Cancel {
+#define ILL_Cancel_version_1 1
+#define ILL_Cancel_version_2 2
+	int *protocol_version_num;
+	ILL_Transaction_Id *transaction_id;
+	ILL_Service_Date_Time *service_date_time;
+	ILL_System_Id *requester_id; /* OPT */
+	ILL_System_Id *responder_id; /* OPT */
+	ILL_String *requester_note; /* OPT */
+	int num_cancel_extensions;
+	ILL_Extension **cancel_extensions; /* OPT */
+};
+
+struct ILL_Cancel_Reply {
+#define ILL_Cancel_Reply_version_1 1
+#define ILL_Cancel_Reply_version_2 2
+	int *protocol_version_num;
+	ILL_Transaction_Id *transaction_id;
+	ILL_Service_Date_Time *service_date_time;
+	ILL_System_Id *requester_id; /* OPT */
+	ILL_System_Id *responder_id; /* OPT */
+	bool_t *answer;
+	ILL_String *responder_note; /* OPT */
+	int num_cancel_reply_extensions;
+	ILL_Extension **cancel_reply_extensions; /* OPT */
+};
+
+struct ILL_Received {
+#define ILL_Received_version_1 1
+#define ILL_Received_version_2 2
+	int *protocol_version_num;
+	ILL_Transaction_Id *transaction_id;
+	ILL_Service_Date_Time *service_date_time;
+	ILL_System_Id *requester_id; /* OPT */
+	ILL_System_Id *responder_id; /* OPT */
+	ILL_System_Id *supplier_id; /* OPT */
+	ILL_Supplemental_Item_Description *supplemental_item_description; /* OPT */
+	ILL_ISO_Date *date_received;
+	ILL_Shipped_Service_Type *shipped_service_type;
+	ILL_String *requester_note; /* OPT */
+	int num_received_extensions;
+	ILL_Extension **received_extensions; /* OPT */
+};
+
+struct ILL_Recall {
+#define ILL_Recall_version_1 1
+#define ILL_Recall_version_2 2
+	int *protocol_version_num;
+	ILL_Transaction_Id *transaction_id;
+	ILL_Service_Date_Time *service_date_time;
+	ILL_System_Id *requester_id; /* OPT */
+	ILL_System_Id *responder_id; /* OPT */
+	ILL_String *responder_note; /* OPT */
+	int num_recall_extensions;
+	ILL_Extension **recall_extensions; /* OPT */
+};
+
+struct ILL_Returned {
+#define ILL_Returned_version_1 1
+#define ILL_Returned_version_2 2
+	int *protocol_version_num;
+	ILL_Transaction_Id *transaction_id;
+	ILL_Service_Date_Time *service_date_time;
+	ILL_System_Id *requester_id; /* OPT */
+	ILL_System_Id *responder_id; /* OPT */
+	ILL_Supplemental_Item_Description *supplemental_item_description; /* OPT */
+	ILL_ISO_Date *date_returned;
+	ILL_Transportation_Mode *returned_via; /* OPT */
+	ILL_Amount *insured_for; /* OPT */
+	ILL_String *requester_note; /* OPT */
+	int num_returned_extensions;
+	ILL_Extension **returned_extensions; /* OPT */
+};
+
+struct ILL_Checked_In {
+#define ILL_Checked_In_version_1 1
+#define ILL_Checked_In_version_2 2
+	int *protocol_version_num;
+	ILL_Transaction_Id *transaction_id;
+	ILL_Service_Date_Time *service_date_time;
+	ILL_System_Id *requester_id; /* OPT */
+	ILL_System_Id *responder_id; /* OPT */
+	ILL_ISO_Date *date_checked_in;
+	ILL_String *responder_note; /* OPT */
+	int num_checked_in_extensions;
+	ILL_Extension **checked_in_extensions; /* OPT */
+};
+
+struct ILL_Overdue_Extension {
+	int num;
+	ILL_Extension **elements;
+};
+
+struct ILL_Overdue {
+#define ILL_Overdue_version_1 1
+#define ILL_Overdue_version_2 2
+	int *protocol_version_num;
+	ILL_Transaction_Id *transaction_id;
+	ILL_Service_Date_Time *service_date_time;
+	ILL_System_Id *requester_id; /* OPT */
+	ILL_System_Id *responder_id; /* OPT */
+	ILL_Date_Due *date_due;
+	ILL_String *responder_note; /* OPT */
+	ILL_Overdue_Extension *overdue_extensions; /* OPT */
+};
+
+struct ILL_Renew {
+#define ILL_Renew_version_1 1
+#define ILL_Renew_version_2 2
+	int *protocol_version_num;
+	ILL_Transaction_Id *transaction_id;
+	ILL_Service_Date_Time *service_date_time;
+	ILL_System_Id *requester_id; /* OPT */
+	ILL_System_Id *responder_id; /* OPT */
+	ILL_ISO_Date *desired_due_date; /* OPT */
+	ILL_String *requester_note; /* OPT */
+	int num_renew_extensions;
+	ILL_Extension **renew_extensions; /* OPT */
+};
+
+struct ILL_Renew_Answer {
+#define ILL_Renew_Answer_version_1 1
+#define ILL_Renew_Answer_version_2 2
+	int *protocol_version_num;
+	ILL_Transaction_Id *transaction_id;
+	ILL_Service_Date_Time *service_date_time;
+	ILL_System_Id *requester_id; /* OPT */
+	ILL_System_Id *responder_id; /* OPT */
+	bool_t *answer;
+	ILL_Date_Due *date_due; /* OPT */
+	ILL_String *responder_note; /* OPT */
+	int num_renew_answer_extensions;
+	ILL_Extension **renew_answer_extensions; /* OPT */
+};
+
+struct ILL_Lost {
+#define ILL_Lost_version_1 1
+#define ILL_Lost_version_2 2
+	int *protocol_version_num;
+	ILL_Transaction_Id *transaction_id;
+	ILL_Service_Date_Time *service_date_time;
+	ILL_System_Id *requester_id; /* OPT */
+	ILL_System_Id *responder_id; /* OPT */
+	ILL_String *note; /* OPT */
+	int num_lost_extensions;
+	ILL_Extension **lost_extensions; /* OPT */
+};
+
+struct ILL_Damaged {
+#define ILL_Damaged_version_1 1
+#define ILL_Damaged_version_2 2
+	int *protocol_version_num;
+	ILL_Transaction_Id *transaction_id;
+	ILL_Service_Date_Time *service_date_time;
+	ILL_System_Id *requester_id; /* OPT */
+	ILL_System_Id *responder_id; /* OPT */
+	ILL_Damaged_Details *damaged_details; /* OPT */
+	ILL_String *note; /* OPT */
+	int num_damaged_extensions;
+	ILL_Extension **damaged_extensions; /* OPT */
+};
+
+struct ILL_Message {
+#define ILL_Message_version_1 1
+#define ILL_Message_version_2 2
+	int *protocol_version_num;
+	ILL_Transaction_Id *transaction_id;
+	ILL_Service_Date_Time *service_date_time;
+	ILL_System_Id *requester_id; /* OPT */
+	ILL_System_Id *responder_id; /* OPT */
+	ILL_String *note;
+	int num_message_extensions;
+	ILL_Extension **message_extensions; /* OPT */
+};
+
+struct ILL_Status_Query {
+#define ILL_Status_Query_version_1 1
+#define ILL_Status_Query_version_2 2
+	int *protocol_version_num;
+	ILL_Transaction_Id *transaction_id;
+	ILL_Service_Date_Time *service_date_time;
+	ILL_System_Id *requester_id; /* OPT */
+	ILL_System_Id *responder_id; /* OPT */
+	ILL_String *note; /* OPT */
+	int num_status_query_extensions;
+	ILL_Extension **status_query_extensions; /* OPT */
+};
+
+struct ILL_Status_Or_Error_Report {
+#define ILL_Status_Or_Error_Report_version_1 1
+#define ILL_Status_Or_Error_Report_version_2 2
+	int *protocol_version_num;
+	ILL_Transaction_Id *transaction_id;
+	ILL_Service_Date_Time *service_date_time;
+	ILL_System_Id *requester_id; /* OPT */
+	ILL_System_Id *responder_id; /* OPT */
+	ILL_Reason_No_Report *reason_no_report; /* OPT */
+	ILL_Status_Report *status_report; /* OPT */
+	ILL_Error_Report *error_report; /* OPT */
+	ILL_String *note; /* OPT */
+	int num_status_or_error_report_extensions;
+	ILL_Extension **status_or_error_report_extensions; /* OPT */
+};
+
+struct ILL_Expired {
+#define ILL_Expired_version_1 1
+#define ILL_Expired_version_2 2
+	int *protocol_version_num;
+	ILL_Transaction_Id *transaction_id;
+	ILL_Service_Date_Time *service_date_time;
+	ILL_System_Id *requester_id; /* OPT */
+	ILL_System_Id *responder_id; /* OPT */
+	int num_expired_extensions;
+	ILL_Extension **expired_extensions; /* OPT */
+};
+
+
+
+struct ILL_Already_Forwarded {
+	ILL_System_Id *responder_id;
+	ILL_System_Address *responder_address; /* OPT */
+};
+
+struct ILL_Already_Tried_List_Type {
+	int num;
+	ILL_System_Id **elements;
+};
+
+struct ILL_Amount {
+	char *currency_code; /* OPT */
+	ILL_AmountString *monetary_value;
+};
+
+
+
+struct ILL_Client_Id {
+	ILL_String *client_name; /* OPT */
+	ILL_String *client_status; /* OPT */
+	ILL_String *client_identifier; /* OPT */
+};
+
+struct ILL_Conditional_Results {
+#define ILL_Conditional_Results_cost_exceeds_limit 13
+#define ILL_Conditional_Results_charges 14
+#define ILL_Conditional_Results_prepayment_required 15
+#define ILL_Conditional_Results_lacks_copyright_compliance 16
+#define ILL_Conditional_Results_library_use_only 22
+#define ILL_Conditional_Results_no_reproduction 23
+#define ILL_Conditional_Results_client_signature_required 24
+#define ILL_Conditional_Results_special_collections_supervision_required 25
+#define ILL_Conditional_Results_other 27
+#define ILL_Conditional_Results_responder_specific 28
+#define ILL_Conditional_Results_proposed_delivery_service 30
+	int *conditions;
+	ILL_ISO_Date *date_for_reply; /* OPT */
+	int num_locations;
+	ILL_Location_Info **locations; /* OPT */
+	ILL_Delivery_Service *proposed_delivery_service; /* OPT */
+};
+
+struct ILL_Cost_Info_Type {
+	ILL_Account_Number *account_number; /* OPT */
+	ILL_Amount *maximum_cost; /* OPT */
+	bool_t *reciprocal_agreement;
+	bool_t *will_pay_fee;
+	bool_t *payment_provided;
+};
+
+#define ILL_Current_State_nOT_SUPPLIED 1
+#define ILL_Current_State_pENDING 2
+#define ILL_Current_State_iN_PROCESS 3
+#define ILL_Current_State_fORWARD 4
+#define ILL_Current_State_cONDITIONAL 5
+#define ILL_Current_State_cANCEL_PENDING 6
+#define ILL_Current_State_cANCELLED 7
+#define ILL_Current_State_sHIPPED 8
+#define ILL_Current_State_rECEIVED 9
+#define ILL_Current_State_rENEW_PENDING 10
+#define ILL_Current_State_nOT_RECEIVED_OVERDUE 11
+#define ILL_Current_State_rENEW_OVERDUE 12
+#define ILL_Current_State_oVERDUE 13
+#define ILL_Current_State_rETURNED 14
+#define ILL_Current_State_cHECKED_IN 15
+#define ILL_Current_State_rECALL 16
+#define ILL_Current_State_lOST 17
+#define ILL_Current_State_uNKNOWN 18
+
+struct ILL_Damaged_DetailsSpecific_units {
+	int num;
+	int **elements;
+};
+
+struct ILL_Damaged_Details {
+	Odr_oid *document_type_id; /* OPT */
+	int which;
+	union {
+		Odr_null *complete_document;
+		ILL_Damaged_DetailsSpecific_units *specific_units;
+#define ILL_Damaged_Details_complete_document 1
+#define ILL_Damaged_Details_specific_units 2
+	} u;
+};
+
+struct ILL_Date_Due {
+	ILL_ISO_Date *date_due_field;
+	bool_t *renewable;
+};
+
+struct ILL_Delivery_Address {
+	ILL_Postal_Address *postal_address; /* OPT */
+	ILL_System_Address *electronic_address; /* OPT */
+};
+
+struct ILL_Delivery_ServiceElectronic_delivery {
+	int num;
+	ILL_Electronic_Delivery_Service **elements;
+};
+
+struct ILL_Delivery_Service {
+	int which;
+	union {
+		ILL_Transportation_Mode *physical_delivery;
+		ILL_Delivery_ServiceElectronic_delivery *electronic_delivery;
+#define ILL_Delivery_Service_physical_delivery 1
+#define ILL_Delivery_Service_electronic_delivery 2
+	} u;
+};
+
+struct ILL_Electronic_Delivery_Service_0 {
+	Odr_oid *e_delivery_mode;
+	Odr_any *e_delivery_parameters;
+};
+
+struct ILL_Electronic_Delivery_Service_1 {
+	Odr_oid *document_type_id;
+	Odr_any *document_type_parameters;
+};
+
+struct ILL_Electronic_Delivery_Service {
+	ILL_Electronic_Delivery_Service_0 *e_delivery_service; /* OPT */
+	ILL_Electronic_Delivery_Service_1 *document_type; /* OPT */
+	ILL_String *e_delivery_description; /* OPT */
+	int which;
+	union {
+		ILL_System_Address *e_delivery_address;
+		ILL_System_Id *e_delivery_id;
+#define ILL_Electronic_Delivery_Service_e_delivery_address 1
+#define ILL_Electronic_Delivery_Service_e_delivery_id 2
+	} u;
+	ILL_String *name_or_code; /* OPT */
+	ILL_ISO_Time *delivery_time; /* OPT */
+};
+
+struct ILL_Error_Report {
+	ILL_String *correlation_information;
+	ILL_Report_Source *report_source;
+	ILL_User_Error_Report *user_error_report; /* OPT */
+	ILL_Provider_Error_Report *provider_error_report; /* OPT */
+};
+
+struct ILL_Estimate_Results {
+	ILL_String *cost_estimate;
+	int num_locations;
+	ILL_Location_Info **locations; /* OPT */
+};
+
+struct ILL_Extension {
+	int *identifier;
+	bool_t *critical;
+	Odr_any *item;
+};
+
+#define ILL_General_Problem_unrecognized_APDU 1
+#define ILL_General_Problem_mistyped_APDU 2
+#define ILL_General_Problem_badly_structured_APDU 3
+#define ILL_General_Problem_protocol_version_not_supported 4
+#define ILL_General_Problem_other 5
+
+struct ILL_History_Report {
+	ILL_ISO_Date *date_requested; /* OPT */
+	ILL_String *author; /* OPT */
+	ILL_String *title; /* OPT */
+	ILL_String *author_of_article; /* OPT */
+	ILL_String *title_of_article; /* OPT */
+	ILL_ISO_Date *date_of_last_transition;
+#define ILL_History_Report_iLL_REQUEST 1
+#define ILL_History_Report_fORWARD 21
+#define ILL_History_Report_fORWARD_NOTIFICATION 2
+#define ILL_History_Report_sHIPPED 3
+#define ILL_History_Report_iLL_ANSWER 4
+#define ILL_History_Report_cONDITIONAL_REPLY 5
+#define ILL_History_Report_cANCEL 6
+#define ILL_History_Report_cANCEL_REPLY 7
+#define ILL_History_Report_rECEIVED 8
+#define ILL_History_Report_rECALL 9
+#define ILL_History_Report_rETURNED 10
+#define ILL_History_Report_cHECKED_IN 11
+#define ILL_History_Report_rENEW_ANSWER 14
+#define ILL_History_Report_lOST 15
+#define ILL_History_Report_dAMAGED 16
+#define ILL_History_Report_mESSAGE 17
+#define ILL_History_Report_sTATUS_QUERY 18
+#define ILL_History_Report_sTATUS_OR_ERROR_REPORT 19
+#define ILL_History_Report_eXPIRED 20
+	int *most_recent_service;
+	ILL_ISO_Date *date_of_most_recent_service;
+	ILL_System_Id *initiator_of_most_recent_service;
+	ILL_Shipped_Service_Type *shipped_service_type; /* OPT */
+	ILL_Transaction_Results *transaction_results; /* OPT */
+	ILL_String *most_recent_service_note; /* OPT */
+};
+
+struct ILL_Hold_Placed_Results {
+	ILL_ISO_Date *estimated_date_available;
+	ILL_Medium_Type *hold_placed_medium_type; /* OPT */
+	int num_locations;
+	ILL_Location_Info **locations; /* OPT */
+};
+
+#define ILL_APDU_Type_iLL_REQUEST 1
+#define ILL_APDU_Type_fORWARD_NOTIFICATION 2
+#define ILL_APDU_Type_sHIPPED 3
+#define ILL_APDU_Type_iLL_ANSWER 4
+#define ILL_APDU_Type_cONDITIONAL_REPLY 5
+#define ILL_APDU_Type_cANCEL 6
+#define ILL_APDU_Type_cANCEL_REPLY 7
+#define ILL_APDU_Type_rECEIVED 8
+#define ILL_APDU_Type_rECALL 9
+#define ILL_APDU_Type_rETURNED 10
+#define ILL_APDU_Type_cHECKED_IN 11
+#define ILL_APDU_Type_oVERDUE 12
+#define ILL_APDU_Type_rENEW 13
+#define ILL_APDU_Type_rENEW_ANSWER 14
+#define ILL_APDU_Type_lOST 15
+#define ILL_APDU_Type_dAMAGED 16
+#define ILL_APDU_Type_mESSAGE 17
+#define ILL_APDU_Type_sTATUS_QUERY 18
+#define ILL_APDU_Type_sTATUS_OR_ERROR_REPORT 19
+#define ILL_APDU_Type_eXPIRED 20
+
+#define ILL_Service_Type_loan 1
+#define ILL_Service_Type_copy_non_returnable 2
+#define ILL_Service_Type_locations 3
+#define ILL_Service_Type_estimate 4
+#define ILL_Service_Type_responder_specific 5
+
+struct ILL_String {
+	int which;
+	union {
+		char *GeneralString;
+		ILL_EDIFACTString *EDIFACTString;
+#define ILL_String_GeneralString 1
+#define ILL_String_EDIFACTString 2
+	} u;
+};
+
+#define ILL_Intermediary_Problem_cannot_send_onward 1
+
+
+
+
+
+struct ILL_Item_Id {
+#define ILL_Item_Id_monograph 1
+#define ILL_Item_Id_serial 2
+#define ILL_Item_Id_other 3
+	int *item_type; /* OPT */
+	ILL_Medium_Type *held_medium_type; /* OPT */
+	ILL_String *call_number; /* OPT */
+	ILL_String *author; /* OPT */
+	ILL_String *title; /* OPT */
+	ILL_String *sub_title; /* OPT */
+	ILL_String *sponsoring_body; /* OPT */
+	ILL_String *place_of_publication; /* OPT */
+	ILL_String *publisher; /* OPT */
+	ILL_String *series_title_number; /* OPT */
+	ILL_String *volume_issue; /* OPT */
+	ILL_String *edition; /* OPT */
+	ILL_String *publication_date; /* OPT */
+	ILL_String *publication_date_of_component; /* OPT */
+	ILL_String *author_of_article; /* OPT */
+	ILL_String *title_of_article; /* OPT */
+	ILL_String *pagination; /* OPT */
+	Odr_external *national_bibliography_no; /* OPT */
+	ILL_String *iSBN; /* OPT */
+	ILL_String *iSSN; /* OPT */
+	Odr_external *system_no; /* OPT */
+	ILL_String *additional_no_letters; /* OPT */
+	ILL_String *verification_reference_source; /* OPT */
+};
+
+struct ILL_Location_Info {
+	ILL_System_Id *location_id;
+	ILL_System_Address *location_address; /* OPT */
+	ILL_String *location_note; /* OPT */
+};
+
+struct ILL_Locations_Results {
+	ILL_Reason_Locs_Provided *reason_locs_provided; /* OPT */
+	int num_locations;
+	ILL_Location_Info **locations;
+};
+
+#define ILL_Medium_Type_printed 1
+#define ILL_Medium_Type_microform 3
+#define ILL_Medium_Type_film_or_video_recording 4
+#define ILL_Medium_Type_audio_recording 5
+#define ILL_Medium_Type_machine_readable 6
+#define ILL_Medium_Type_other 7
+
+struct ILL_Name_Of_Person_Or_Institution {
+	int which;
+	union {
+		ILL_String *name_of_person;
+		ILL_String *name_of_institution;
+#define ILL_Name_Of_Person_Or_Institution_name_of_person 1
+#define ILL_Name_Of_Person_Or_Institution_name_of_institution 2
+	} u;
+};
+
+struct ILL_Person_Or_Institution_Symbol {
+	int which;
+	union {
+		ILL_String *person_symbol;
+		ILL_String *institution_symbol;
+#define ILL_Person_Or_Institution_Symbol_person_symbol 1
+#define ILL_Person_Or_Institution_Symbol_institution_symbol 2
+	} u;
+};
+
+#define ILL_Place_On_Hold_Type_yes 1
+#define ILL_Place_On_Hold_Type_no 2
+#define ILL_Place_On_Hold_Type_according_to_responder_policy 3
+
+struct ILL_Postal_Address {
+	ILL_Name_Of_Person_Or_Institution *name_of_person_or_institution; /* OPT */
+	ILL_String *extended_postal_delivery_address; /* OPT */
+	ILL_String *street_and_number; /* OPT */
+	ILL_String *post_office_box; /* OPT */
+	ILL_String *city; /* OPT */
+	ILL_String *region; /* OPT */
+	ILL_String *country; /* OPT */
+	ILL_String *postal_code; /* OPT */
+};
+
+struct ILL_Provider_Error_Report {
+	int which;
+	union {
+		ILL_General_Problem *general_problem;
+		ILL_Transaction_Id_Problem *transaction_id_problem;
+		ILL_State_Transition_Prohibited *state_transition_prohibited;
+#define ILL_Provider_Error_Report_general_problem 1
+#define ILL_Provider_Error_Report_transaction_id_problem 2
+#define ILL_Provider_Error_Report_state_transition_prohibited 3
+	} u;
+};
+
+#define ILL_Reason_Locs_Provided_in_use_on_loan 1
+#define ILL_Reason_Locs_Provided_in_process 2
+#define ILL_Reason_Locs_Provided_lost 3
+#define ILL_Reason_Locs_Provided_non_circulating 4
+#define ILL_Reason_Locs_Provided_not_owned 5
+#define ILL_Reason_Locs_Provided_on_order 6
+#define ILL_Reason_Locs_Provided_volume_issue_not_yet_available 7
+#define ILL_Reason_Locs_Provided_at_bindery 8
+#define ILL_Reason_Locs_Provided_lacking 9
+#define ILL_Reason_Locs_Provided_not_on_shelf 10
+#define ILL_Reason_Locs_Provided_on_reserve 11
+#define ILL_Reason_Locs_Provided_poor_condition 12
+#define ILL_Reason_Locs_Provided_cost_exceeds_limit 13
+#define ILL_Reason_Locs_Provided_on_hold 19
+#define ILL_Reason_Locs_Provided_other 27
+#define ILL_Reason_Locs_Provided_responder_specific 28
+
+#define ILL_Reason_No_Report_temporary 1
+#define ILL_Reason_No_Report_permanent 2
+
+#define ILL_Reason_Unfilled_in_use_on_loan 1
+#define ILL_Reason_Unfilled_in_process 2
+#define ILL_Reason_Unfilled_lost 3
+#define ILL_Reason_Unfilled_non_circulating 4
+#define ILL_Reason_Unfilled_not_owned 5
+#define ILL_Reason_Unfilled_on_order 6
+#define ILL_Reason_Unfilled_volume_issue_not_yet_available 7
+#define ILL_Reason_Unfilled_at_bindery 8
+#define ILL_Reason_Unfilled_lacking 9
+#define ILL_Reason_Unfilled_not_on_shelf 10
+#define ILL_Reason_Unfilled_on_reserve 11
+#define ILL_Reason_Unfilled_poor_condition 12
+#define ILL_Reason_Unfilled_cost_exceeds_limit 13
+#define ILL_Reason_Unfilled_charges 14
+#define ILL_Reason_Unfilled_prepayment_required 15
+#define ILL_Reason_Unfilled_lacks_copyright_compliance 16
+#define ILL_Reason_Unfilled_not_found_as_cited 17
+#define ILL_Reason_Unfilled_locations_not_found 18
+#define ILL_Reason_Unfilled_on_hold 19
+#define ILL_Reason_Unfilled_policy_problem 20
+#define ILL_Reason_Unfilled_mandatory_messaging_not_supported 21
+#define ILL_Reason_Unfilled_expiry_not_supported 22
+#define ILL_Reason_Unfilled_requested_delivery_services_not_supported 23
+#define ILL_Reason_Unfilled_preferred_delivery_time_not_possible 24
+#define ILL_Reason_Unfilled_other 27
+#define ILL_Reason_Unfilled_responder_specific 28
+
+#define ILL_Report_Source_user 1
+#define ILL_Report_Source_provider 2
+
+struct ILL_Requester_Optional_Messages_Type {
+	bool_t *can_send_RECEIVED;
+	bool_t *can_send_RETURNED;
+#define ILL_Requester_Optional_Messages_Type_requires 1
+#define ILL_Requester_Optional_Messages_Type_desires 2
+#define ILL_Requester_Optional_Messages_Type_neither 3
+	int *requester_SHIPPED;
+#define ILL_Requester_Optional_Messages_Type_requires 1
+#define ILL_Requester_Optional_Messages_Type_desires 2
+#define ILL_Requester_Optional_Messages_Type_neither 3
+	int *requester_CHECKED_IN;
+};
+
+struct ILL_Responder_Optional_Messages_Type {
+	bool_t *can_send_SHIPPED;
+	bool_t *can_send_CHECKED_IN;
+#define ILL_Responder_Optional_Messages_Type_requires 1
+#define ILL_Responder_Optional_Messages_Type_desires 2
+#define ILL_Responder_Optional_Messages_Type_neither 3
+	int *responder_RECEIVED;
+#define ILL_Responder_Optional_Messages_Type_requires 1
+#define ILL_Responder_Optional_Messages_Type_desires 2
+#define ILL_Responder_Optional_Messages_Type_neither 3
+	int *responder_RETURNED;
+};
+
+struct ILL_Retry_Results {
+#define ILL_Retry_Results_in_use_on_loan 1
+#define ILL_Retry_Results_in_process 2
+#define ILL_Retry_Results_on_order 6
+#define ILL_Retry_Results_volume_issue_not_yet_available 7
+#define ILL_Retry_Results_at_bindery 8
+#define ILL_Retry_Results_cost_exceeds_limit 13
+#define ILL_Retry_Results_charges 14
+#define ILL_Retry_Results_prepayment_required 15
+#define ILL_Retry_Results_lacks_copyright_compliance 16
+#define ILL_Retry_Results_not_found_as_cited 17
+#define ILL_Retry_Results_on_hold 19
+#define ILL_Retry_Results_other 27
+#define ILL_Retry_Results_responder_specific 28
+	int *reason_not_available; /* OPT */
+	ILL_ISO_Date *retry_date; /* OPT */
+	int num_locations;
+	ILL_Location_Info **locations; /* OPT */
+};
+
+struct ILL_Search_Type {
+	ILL_String *level_of_service; /* OPT */
+	ILL_ISO_Date *need_before_date; /* OPT */
+#define ILL_Search_Type_need_Before_Date 1
+#define ILL_Search_Type_other_Date 2
+#define ILL_Search_Type_no_Expiry 3
+	int *expiry_flag;
+	ILL_ISO_Date *expiry_date; /* OPT */
+};
+
+
+
+struct ILL_Send_To_List_Type_s {
+	ILL_System_Id *system_id;
+	ILL_Account_Number *account_number; /* OPT */
+	ILL_System_Address *system_address; /* OPT */
+};
+
+struct ILL_Send_To_List_Type {
+	int num;
+	ILL_Send_To_List_Type_s **elements;
+};
+
+struct ILL_Service_Date_this {
+	ILL_ISO_Date *date;
+	ILL_ISO_Time *time; /* OPT */
+};
+
+struct ILL_Service_Date_original {
+	ILL_ISO_Date *date;
+	ILL_ISO_Time *time; /* OPT */
+};
+
+struct ILL_Service_Date_Time {
+	ILL_Service_Date_this *date_time_of_this_service;
+	ILL_Service_Date_original *date_time_of_original_service; /* OPT */
+};
+
+
+
+struct ILL_State_Transition_Prohibited {
+	ILL_APDU_Type *aPDU_type;
+	ILL_Current_State *current_state;
+};
+
+struct ILL_Status_Report {
+	ILL_History_Report *user_status_report;
+	ILL_Current_State *provider_status_report;
+};
+
+struct ILL_Supplemental_Item_Description {
+	int num;
+	Odr_external **elements;
+};
+
+struct ILL_Supply_Details {
+	ILL_ISO_Date *date_shipped; /* OPT */
+	ILL_Date_Due *date_due; /* OPT */
+	int *chargeable_units; /* OPT */
+	ILL_Amount *cost; /* OPT */
+#define ILL_Supply_Details_library_use_only 22
+#define ILL_Supply_Details_no_reproduction 23
+#define ILL_Supply_Details_client_signature_required 24
+#define ILL_Supply_Details_special_collections_supervision_required 25
+#define ILL_Supply_Details_other 27
+	int *shipped_conditions; /* OPT */
+	int which;
+	union {
+		ILL_Transportation_Mode *physical_delivery;
+		ILL_Electronic_Delivery_Service *electronic_delivery;
+#define ILL_Supply_Details_physical_delivery 1
+#define ILL_Supply_Details_electronic_delivery 2
+	} u; /* OPT */
+	ILL_Amount *insured_for; /* OPT */
+	ILL_Amount *return_insurance_require; /* OPT */
+	int num_no_of_units_per_medium;
+	ILL_Units_Per_Medium_Type **no_of_units_per_medium; /* OPT */
+};
+
+struct ILL_Supply_Medium_Info_Type {
+	ILL_Supply_Medium_Type *supply_medium_type;
+	ILL_String *medium_characteristics; /* OPT */
+};
+
+#define ILL_Supply_Medium_Type_printed 1
+#define ILL_Supply_Medium_Type_photocopy 2
+#define ILL_Supply_Medium_Type_microform 3
+#define ILL_Supply_Medium_Type_film_or_video_recording 4
+#define ILL_Supply_Medium_Type_audio_recording 5
+#define ILL_Supply_Medium_Type_machine_readable 6
+#define ILL_Supply_Medium_Type_other 7
+
+struct ILL_System_Address {
+	ILL_String *telecom_service_identifier; /* OPT */
+	ILL_String *telecom_service_address; /* OPT */
+};
+
+struct ILL_System_Id {
+	ILL_Person_Or_Institution_Symbol *person_or_institution_symbol; /* OPT */
+	ILL_Name_Of_Person_Or_Institution *name_of_person_or_institution; /* OPT */
+};
+
+struct ILL_Third_Party_Info_Type {
+	bool_t *permission_to_forward;
+	bool_t *permission_to_chain;
+	bool_t *permission_to_partition;
+	bool_t *permission_to_change_send_to_list;
+	ILL_System_Address *initial_requester_address; /* OPT */
+#define ILL_Third_Party_Info_Type_ordered 1
+#define ILL_Third_Party_Info_Type_unordered 2
+	int *preference;
+	ILL_Send_To_List_Type *send_to_list; /* OPT */
+	ILL_Already_Tried_List_Type *already_tried_list; /* OPT */
+};
+
+struct ILL_Transaction_Id {
+	ILL_System_Id *initial_requester_id; /* OPT */
+	ILL_String *transaction_group_qualifier;
+	ILL_String *transaction_qualifier;
+	ILL_String *sub_transaction_qualifier; /* OPT */
+};
+
+#define ILL_Transaction_Id_Problem_duplicate_transaction_id 1
+#define ILL_Transaction_Id_Problem_invalid_transaction_id 2
+#define ILL_Transaction_Id_Problem_unknown_transaction_id 3
+
+#define ILL_Transaction_Results_conditional 1
+#define ILL_Transaction_Results_retry 2
+#define ILL_Transaction_Results_unfilled 3
+#define ILL_Transaction_Results_locations_provided 4
+#define ILL_Transaction_Results_will_supply 5
+#define ILL_Transaction_Results_hold_placed 6
+#define ILL_Transaction_Results_estimate 7
+
+#define ILL_Transaction_Type_simple 1
+#define ILL_Transaction_Type_chained 2
+#define ILL_Transaction_Type_partitioned 3
+
+
+
+#define ILL_Unable_To_Perform_not_available 1
+#define ILL_Unable_To_Perform_resource_limitation 2
+#define ILL_Unable_To_Perform_other 3
+
+struct ILL_Unfilled_Results {
+	ILL_Reason_Unfilled *reason_unfilled;
+	int num_locations;
+	ILL_Location_Info **locations; /* OPT */
+};
+
+struct ILL_Units_Per_Medium_Type {
+	ILL_Supply_Medium_Type *medium;
+	int *no_of_units;
+};
+
+struct ILL_User_Error_Report {
+	int which;
+	union {
+		ILL_Already_Forwarded *already_forwarded;
+		ILL_Intermediary_Problem *intermediary_problem;
+		ILL_Security_Problem *security_problem;
+		ILL_Unable_To_Perform *unable_to_perform;
+#define ILL_User_Error_Report_already_forwarded 1
+#define ILL_User_Error_Report_intermediary_problem 2
+#define ILL_User_Error_Report_security_problem 3
+#define ILL_User_Error_Report_unable_to_perform 4
+	} u;
+};
+
+struct ILL_Will_Supply_Results {
+#define ILL_Will_Supply_Results_in_use_on_loan 1
+#define ILL_Will_Supply_Results_in_process 2
+#define ILL_Will_Supply_Results_on_order 6
+#define ILL_Will_Supply_Results_at_bindery 8
+#define ILL_Will_Supply_Results_on_hold 19
+#define ILL_Will_Supply_Results_being_processed_for_supply 26
+#define ILL_Will_Supply_Results_other 27
+#define ILL_Will_Supply_Results_responder_specific 28
+#define ILL_Will_Supply_Results_electronic_delivery 30
+	int *reason_will_supply;
+	ILL_ISO_Date *supply_date; /* OPT */
+	ILL_Postal_Address *return_to_address; /* OPT */
+	int num_locations;
+	ILL_Location_Info **locations; /* OPT */
+	ILL_Electronic_Delivery_Service *electronic_delivery_service; /* OPT */
+};
+
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
Index: /main/tags/2.25/gsdl/packages/yaz/include/yaz/ill.h
===================================================================
--- /main/tags/2.25/gsdl/packages/yaz/include/yaz/ill.h	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/yaz/include/yaz/ill.h	(revision 21064)
@@ -0,0 +1,46 @@
+/*
+ * Copyright (c) 1999, Index Data
+ * See the file LICENSE for details.
+ *
+ * $Log$
+ * Revision 1.1  2000/08/03 03:10:37  johnmcp
+ * Added the YAZ toolkit source to the packages directory (for z39.50 stuff)
+ *
+ * Revision 1.4  2000/02/28 11:20:06  adam
+ * Using autoconf. New definitions: YAZ_BEGIN_CDECL/YAZ_END_CDECL.
+ *
+ * Revision 1.3  2000/01/31 13:15:21  adam
+ * Removed uses of assert(3). Cleanup of ODR. CCL parser update so
+ * that some characters are not surrounded by spaces in resulting term.
+ * ILL-code updates.
+ *
+ * Revision 1.2  2000/01/15 09:39:50  adam
+ * Implemented ill_get_ILLRequest. More ILL testing for client.
+ *
+ * Revision 1.1  1999/12/16 23:36:19  adam
+ * Implemented ILL protocol. Minor updates ASN.1 compiler.
+ *
+ */
+#ifndef ILL_H
+#define ILL_H
+
+#include <yaz/ill-core.h>
+#include <yaz/item-req.h>
+
+YAZ_BEGIN_CDECL
+
+struct ill_get_ctl {
+    ODR odr;
+    void *clientData;
+    const char *(*f)(void *clientData, const char *element);
+};
+    
+YAZ_EXPORT ILL_ItemRequest *ill_get_ItemRequest (
+    struct ill_get_ctl *gs, const char *name, const char *sub);
+
+YAZ_EXPORT ILL_Request *ill_get_ILLRequest (
+    struct ill_get_ctl *gs, const char *name, const char *sub);
+
+YAZ_END_CDECL
+
+#endif
Index: /main/tags/2.25/gsdl/packages/yaz/include/yaz/item-req.h
===================================================================
--- /main/tags/2.25/gsdl/packages/yaz/include/yaz/item-req.h	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/yaz/include/yaz/item-req.h	(revision 21064)
@@ -0,0 +1,58 @@
+/* Generated automatically by the YAZ ASN.1 Compiler 0.3 */
+/* Module-H Z39.50-extendedService-ItemOrder-ItemRequest-1 */
+
+#ifndef item_req_H
+#define item_req_H
+
+#include <yaz/odr.h>
+#include <yaz/ill-core.h>
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef struct ILL_ItemRequest ILL_ItemRequest;
+YAZ_EXPORT int ill_ItemRequest (ODR o, ILL_ItemRequest **p, int opt, const char *name);
+#ifdef __cplusplus
+}
+#endif
+#ifdef __cplusplus
+extern "C" {
+#endif
+struct ILL_ItemRequest {
+#define ILL_ItemRequest_version_1 1
+#define ILL_ItemRequest_version_2 2
+	int *protocol_version_num;
+	ILL_Transaction_Id *transaction_id; /* OPT */
+	ILL_Service_Date_Time *service_date_time; /* OPT */
+	ILL_System_Id *requester_id; /* OPT */
+	ILL_System_Id *responder_id; /* OPT */
+	ILL_Transaction_Type *transaction_type;
+	ILL_Delivery_Address *delivery_address; /* OPT */
+	ILL_Delivery_Service *delivery_service; /* OPT */
+	ILL_Delivery_Address *billing_address; /* OPT */
+	int num_iLL_service_type;
+	ILL_Service_Type **iLL_service_type; /* OPT */
+	Odr_external *responder_specific_service; /* OPT */
+	ILL_Requester_Optional_Messages_Type *requester_optional_messages; /* OPT */
+	ILL_Search_Type *search_type; /* OPT */
+	int num_supply_medium_info_type;
+	ILL_Supply_Medium_Info_Type **supply_medium_info_type; /* OPT */
+	ILL_Place_On_Hold_Type *place_on_hold;
+	ILL_Client_Id *client_id; /* OPT */
+	ILL_Item_Id *item_id; /* OPT */
+	ILL_Supplemental_Item_Description *supplemental_item_description; /* OPT */
+	ILL_Cost_Info_Type *cost_info_type; /* OPT */
+	ILL_String *copyright_compliance; /* OPT */
+	ILL_Third_Party_Info_Type *third_party_info_type; /* OPT */
+	bool_t *retry_flag;
+	bool_t *forward_flag;
+	ILL_String *requester_note; /* OPT */
+	ILL_String *forward_note; /* OPT */
+	int num_iLL_request_extensions;
+	ILL_Extension **iLL_request_extensions; /* OPT */
+};
+
+#ifdef __cplusplus
+}
+#endif
+#endif
Index: /main/tags/2.25/gsdl/packages/yaz/include/yaz/log.h
===================================================================
--- /main/tags/2.25/gsdl/packages/yaz/include/yaz/log.h	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/yaz/include/yaz/log.h	(revision 21064)
@@ -0,0 +1,139 @@
+/*
+ * Copyright (c) 1995-2000, Index Data.
+ *
+ * Permission to use, copy, modify, distribute, and sell this software and
+ * its documentation, in whole or in part, for any purpose, is hereby granted,
+ * provided that:
+ *
+ * 1. This copyright and permission notice appear in all copies of the
+ * software and its documentation. Notices of copyright or attribution
+ * which appear at the beginning of any file must remain unchanged.
+ *
+ * 2. The name of Index Data or the individual authors may not be used to
+ * endorse or promote products derived from this software without specific
+ * prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED "AS IS" AND WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS, IMPLIED, OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY
+ * WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
+ * IN NO EVENT SHALL INDEX DATA BE LIABLE FOR ANY SPECIAL, INCIDENTAL,
+ * INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND, OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER OR
+ * NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF
+ * LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
+ * OF THIS SOFTWARE.
+ *
+ * $Log$
+ * Revision 1.1  2000/08/03 03:10:38  johnmcp
+ * Added the YAZ toolkit source to the packages directory (for z39.50 stuff)
+ *
+ * Revision 1.2  2000/02/28 11:20:06  adam
+ * Using autoconf. New definitions: YAZ_BEGIN_CDECL/YAZ_END_CDECL.
+ *
+ * Revision 1.1  1999/11/30 13:47:11  adam
+ * Improved installation. Moved header files to include/yaz.
+ *
+ * Revision 1.15  1999/08/27 09:40:32  adam
+ * Renamed logf function to yaz_log. Removed VC++ project files.
+ *
+ * Revision 1.14  1998/10/28 10:26:59  adam
+ * New functions log_init_file, log_init_level, log_init_prefix.
+ *
+ * Revision 1.13  1998/10/13 16:11:11  adam
+ * Added printf-format check for logf when using GNUC.
+ *
+ * Revision 1.12  1997/09/04 07:59:02  adam
+ * Added include of xmalloc.h.
+ *
+ * Revision 1.11  1997/09/01 08:49:48  adam
+ * New windows NT/95 port using MSV5.0. To export DLL functions the
+ * YAZ_EXPORT modifier was added. Defined in yconfig.h.
+ *
+ * Revision 1.10  1997/05/14 06:53:40  adam
+ * C++ support.
+ *
+ * Revision 1.9  1997/05/01 15:06:42  adam
+ * Added log_mask_str_x routine.
+ *
+ * Revision 1.8  1996/05/01 12:45:00  quinn
+ * *** empty log message ***
+ *
+ * Revision 1.7  1996/02/05  12:24:26  adam
+ * Implemented log_event_{start,end}-functions.
+ *
+ * Revision 1.6  1995/10/10  16:27:06  quinn
+ * *** empty log message ***
+ *
+ * Revision 1.5  1995/09/29  17:12:03  quinn
+ * Smallish
+ *
+ * Revision 1.4  1995/09/27  15:02:47  quinn
+ * Modified function heads & prototypes.
+ *
+ * Revision 1.3  1995/06/19  12:38:25  quinn
+ * Reorganized include-files. Added small features.
+ *
+ * Revision 1.2  1995/05/16  08:50:31  quinn
+ * License, documentation, and memory fixes
+ *
+ * Revision 1.1  1995/03/30  09:39:41  quinn
+ * Moved .h files to include directory
+ *
+ * Revision 1.4  1994/09/28  13:07:22  adam
+ * Added log_mask_str.
+ *
+ * Revision 1.3  1994/08/18  08:18:45  quinn
+ * Added prefix to log_init.
+ *
+ * Revision 1.2  1994/08/17  14:27:46  quinn
+ * added LOG_ERRNO
+ *
+ * Revision 1.1  1994/08/17  13:22:52  quinn
+ * First version
+ *
+ */
+
+#ifndef LOG_H
+#define LOG_H
+
+#include <stdio.h>
+#include <yaz/yconfig.h>
+#include <yaz/xmalloc.h>
+
+YAZ_BEGIN_CDECL
+
+#define LOG_FATAL 0x0001
+#define LOG_DEBUG 0x0002
+#define LOG_WARN  0x0004
+#define LOG_LOG   0x0008
+#define LOG_ERRNO 0x0010     /* append strerror to message */
+#define LOG_FILE  0x0020
+
+#define LOG_ALL   0xffff
+
+#define LOG_DEFAULT_LEVEL (LOG_FATAL | LOG_ERRNO | LOG_LOG | LOG_WARN)
+
+#define logf yaz_log
+
+YAZ_EXPORT void log_init(int level, const char *prefix, const char *name);
+YAZ_EXPORT void log_init_file (const char *fname);
+YAZ_EXPORT void log_init_level (int level);
+YAZ_EXPORT void log_init_prefix (const char *prefix);
+
+YAZ_EXPORT void yaz_log(int level, const char *fmt, ...)
+#ifdef __GNUC__
+	__attribute__ ((format (printf, 2, 3)))
+#endif
+	;
+YAZ_EXPORT int log_mask_str (const char *str);
+YAZ_EXPORT int log_mask_str_x (const char *str, int level);
+YAZ_EXPORT FILE *log_file(void);
+
+YAZ_EXPORT void log_event_start (void (*func)(int level, const char *msg, void *info),
+	void *info);
+YAZ_EXPORT void log_event_end (void (*func)(int level, const char *msg, void *info),
+	void *info);
+
+YAZ_END_CDECL
+
+#endif
Index: /main/tags/2.25/gsdl/packages/yaz/include/yaz/logrpn.h
===================================================================
--- /main/tags/2.25/gsdl/packages/yaz/include/yaz/logrpn.h	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/yaz/include/yaz/logrpn.h	(revision 21064)
@@ -0,0 +1,35 @@
+/*
+ * Copyright (c) 1997-2000, Index Data.
+ * See the file LICENSE for details.
+ * Sebastian Hammer, Adam Dickmeiss
+ *
+ * $Log$
+ * Revision 1.1  2000/08/03 03:10:38  johnmcp
+ * Added the YAZ toolkit source to the packages directory (for z39.50 stuff)
+ *
+ * Revision 1.2  2000/02/28 11:20:06  adam
+ * Using autoconf. New definitions: YAZ_BEGIN_CDECL/YAZ_END_CDECL.
+ *
+ * Revision 1.1  1999/11/30 13:47:11  adam
+ * Improved installation. Moved header files to include/yaz.
+ *
+ * Revision 1.1  1998/11/16 16:02:32  adam
+ * Added loggin utilies, log_rpn_query and log_scan_term. These used
+ * to be part of Zebra.
+ *
+ */
+
+#ifndef LOG_RPN_H
+#define LOG_RPN_H
+
+#include <yaz/yconfig.h>
+#include <yaz/proto.h>
+
+YAZ_BEGIN_CDECL
+
+YAZ_EXPORT void log_rpn_query (Z_RPNQuery *rpn);
+YAZ_EXPORT void log_scan_term (Z_AttributesPlusTerm *zapt, oid_value ast);
+
+YAZ_END_CDECL
+
+#endif
Index: /main/tags/2.25/gsdl/packages/yaz/include/yaz/marcdisp.h
===================================================================
--- /main/tags/2.25/gsdl/packages/yaz/include/yaz/marcdisp.h	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/yaz/include/yaz/marcdisp.h	(revision 21064)
@@ -0,0 +1,79 @@
+/*
+ * Copyright (c) 1995-2000, Index Data.
+ *
+ * Permission to use, copy, modify, distribute, and sell this software and
+ * its documentation, in whole or in part, for any purpose, is hereby granted,
+ * provided that:
+ *
+ * 1. This copyright and permission notice appear in all copies of the
+ * software and its documentation. Notices of copyright or attribution
+ * which appear at the beginning of any file must remain unchanged.
+ *
+ * 2. The name of Index Data or the individual authors may not be used to
+ * endorse or promote products derived from this software without specific
+ * prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED "AS IS" AND WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS, IMPLIED, OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY
+ * WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
+ * IN NO EVENT SHALL INDEX DATA BE LIABLE FOR ANY SPECIAL, INCIDENTAL,
+ * INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND, OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER OR
+ * NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF
+ * LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
+ * OF THIS SOFTWARE.
+ *
+ * $Log$
+ * Revision 1.1  2000/08/03 03:10:39  johnmcp
+ * Added the YAZ toolkit source to the packages directory (for z39.50 stuff)
+ *
+ * Revision 1.2  2000/02/28 11:20:06  adam
+ * Using autoconf. New definitions: YAZ_BEGIN_CDECL/YAZ_END_CDECL.
+ *
+ * Revision 1.1  1999/11/30 13:47:11  adam
+ * Improved installation. Moved header files to include/yaz.
+ *
+ * Revision 1.8  1997/09/24 13:35:45  adam
+ * Added two members to data1_marctab to ease reading of weird MARC records.
+ *
+ * Revision 1.7  1997/09/04 07:57:51  adam
+ * Definition of ISO2709 control characters to this file.
+ *
+ * Revision 1.6  1997/09/01 08:49:49  adam
+ * New windows NT/95 port using MSV5.0. To export DLL functions the
+ * YAZ_EXPORT modifier was added. Defined in yconfig.h.
+ *
+ * Revision 1.5  1997/05/14 06:53:40  adam
+ * C++ support.
+ *
+ * Revision 1.4  1995/09/29 17:12:03  quinn
+ * Smallish
+ *
+ * Revision 1.3  1995/09/27  15:02:47  quinn
+ * Modified function heads & prototypes.
+ *
+ * Revision 1.2  1995/05/16  08:50:32  quinn
+ * License, documentation, and memory fixes
+ *
+ * Revision 1.1  1995/04/10  10:28:28  quinn
+ * Added copy of CCL.
+ *
+ */
+
+#ifndef MARCDISP_H
+#define MARCDISP_H
+
+#include <yaz/yconfig.h>
+
+YAZ_BEGIN_CDECL
+
+YAZ_EXPORT int marc_display (const char *buf, FILE *outf);
+YAZ_EXPORT int marc_display_ex (const char *buf, FILE *outf, int debug);
+
+#define ISO2709_RS 035
+#define ISO2709_FS 036
+#define ISO2709_IDFS 037
+
+YAZ_END_CDECL
+
+#endif
Index: /main/tags/2.25/gsdl/packages/yaz/include/yaz/nmem.h
===================================================================
--- /main/tags/2.25/gsdl/packages/yaz/include/yaz/nmem.h	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/yaz/include/yaz/nmem.h	(revision 21064)
@@ -0,0 +1,112 @@
+/*
+ * Copyright (c) 1995-2000, Index Data.
+ *
+ * Permission to use, copy, modify, distribute, and sell this software and
+ * its documentation, in whole or in part, for any purpose, is hereby granted,
+ * provided that:
+ *
+ * 1. This copyright and permission notice appear in all copies of the
+ * software and its documentation. Notices of copyright or attribution
+ * which appear at the beginning of any file must remain unchanged.
+ *
+ * 2. The names of Index Data or the individual authors may not be used to
+ * endorse or promote products derived from this software without specific
+ * prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED "AS IS" AND WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS, IMPLIED, OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY
+ * WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
+ * IN NO EVENT SHALL INDEX DATA BE LIABLE FOR ANY SPECIAL, INCIDENTAL,
+ * INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND, OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER OR
+ * NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF
+ * LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
+ * OF THIS SOFTWARE.
+ *
+ * $Log$
+ * Revision 1.1  2000/08/03 03:10:39  johnmcp
+ * Added the YAZ toolkit source to the packages directory (for z39.50 stuff)
+ *
+ * Revision 1.2  2000/02/28 11:20:06  adam
+ * Using autoconf. New definitions: YAZ_BEGIN_CDECL/YAZ_END_CDECL.
+ *
+ * Revision 1.1  1999/11/30 13:47:11  adam
+ * Improved installation. Moved header files to include/yaz.
+ *
+ * Revision 1.10  1998/10/19 15:24:20  adam
+ * New nmem utility, nmem_transfer, that transfer blocks from one
+ * NMEM to another.
+ *
+ * Revision 1.9  1998/10/13 16:00:17  adam
+ * Implemented nmem_critical_{enter,leave}.
+ *
+ * Revision 1.8  1998/07/20 12:35:59  adam
+ * Added more memory diagnostics (when NMEM_DEBUG is 1).
+ *
+ * Revision 1.7  1997/10/31 12:20:08  adam
+ * Improved memory debugging for xmalloc/nmem.c. References to NMEM
+ * instead of ODR in n ESPEC-1 handling in source d1_espec.c.
+ * Bug fix: missing fclose in data1_read_espec1.
+ *
+ */
+
+#ifndef NMEM_H
+#define NMEM_H
+#include <yaz/yconfig.h>
+
+#define NMEM_DEBUG 0
+
+#ifndef NMEM_DEBUG
+#define NMEM_DEBUG 0
+#endif
+
+YAZ_BEGIN_CDECL
+
+typedef struct nmem_block
+{
+    char *buf;              /* memory allocated in this block */
+    int size;               /* size of buf */
+    int top;                /* top of buffer */
+    struct nmem_block *next;
+} nmem_block;
+
+typedef struct nmem_control
+{
+    int total;
+    nmem_block *blocks;
+    struct nmem_control *next;
+} nmem_control;
+
+typedef struct nmem_control *NMEM;
+
+YAZ_EXPORT void nmem_reset(NMEM n);
+YAZ_EXPORT int nmem_total(NMEM n);
+YAZ_EXPORT char *nmem_strdup (NMEM mem, const char *src);
+YAZ_EXPORT void nmem_transfer (NMEM dst, NMEM src);
+
+YAZ_EXPORT void nmem_critical_enter (void);
+YAZ_EXPORT void nmem_critical_leave (void);
+
+#if NMEM_DEBUG
+
+YAZ_EXPORT NMEM nmem_create_f(const char *file, int line);
+YAZ_EXPORT void nmem_destroy_f(const char *file, int line, NMEM n);
+YAZ_EXPORT void *nmem_malloc_f(const char *file, int line, NMEM n, int size);
+#define nmem_create() nmem_create_f(__FILE__, __LINE__)
+#define nmem_destroy(x) nmem_destroy_f(__FILE__, __LINE__, (x))
+#define nmem_malloc(x, y) nmem_malloc_f(__FILE__, __LINE__, (x), (y))
+
+#else
+
+YAZ_EXPORT NMEM nmem_create(void);
+YAZ_EXPORT void nmem_destroy(NMEM n);
+YAZ_EXPORT void *nmem_malloc(NMEM n, int size);
+
+#endif
+
+YAZ_EXPORT void nmem_init (void);
+YAZ_EXPORT void nmem_exit (void);
+
+YAZ_END_CDECL
+
+#endif
Index: /main/tags/2.25/gsdl/packages/yaz/include/yaz/odr.h
===================================================================
--- /main/tags/2.25/gsdl/packages/yaz/include/yaz/odr.h	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/yaz/include/yaz/odr.h	(revision 21064)
@@ -0,0 +1,376 @@
+/*
+ * Copyright (c) 1995-2000, Index Data.
+ *
+ * Permission to use, copy, modify, distribute, and sell this software and
+ * its documentation, in whole or in part, for any purpose, is hereby granted,
+ * provided that:
+ *
+ * 1. This copyright and permission notice appear in all copies of the
+ * software and its documentation. Notices of copyright or attribution
+ * which appear at the beginning of any file must remain unchanged.
+ *
+ * 2. The name of Index Data or the individual authors may not be used to
+ * endorse or promote products derived from this software without specific
+ * prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED "AS IS" AND WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS, IMPLIED, OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY
+ * WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
+ * IN NO EVENT SHALL INDEX DATA BE LIABLE FOR ANY SPECIAL, INCIDENTAL,
+ * INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND, OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER OR
+ * NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF
+ * LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
+ * OF THIS SOFTWARE.
+ *
+ * $Id$
+ */
+
+#ifndef ODR_H
+#define ODR_H
+
+#include <stdio.h>
+#include <string.h>
+
+#include <yaz/yconfig.h>
+#include <yaz/nmem.h>
+
+YAZ_BEGIN_CDECL
+
+#ifndef bool_t
+#define bool_t int
+#endif
+
+/*
+ * Tag modes
+ */
+#define ODR_NONE -1
+#define ODR_IMPLICIT 0
+#define ODR_EXPLICIT 1
+
+/*
+ * Classes
+ */
+#define ODR_UNIVERSAL   0
+#define ODR_APPLICATION 1
+#define ODR_CONTEXT     2
+#define ODR_PRIVATE     3
+
+/*
+ * UNIVERSAL tags
+ */
+#define ODR_BOOLEAN     1
+#define ODR_INTEGER     2
+#define ODR_BITSTRING   3
+#define ODR_OCTETSTRING 4
+#define ODR_NULL        5
+#define ODR_OID         6
+#define ODR_ODESC       7
+#define ODR_EXTERNAL    8
+#define ODR_REAL        9
+#define ODR_ENUM        10
+#define ODR_SEQUENCE    16
+#define ODR_SET         17
+#define ODR_NUMERICSTRING   18
+#define ODR_PRINTABLESTRING 19
+#define ODR_GENERALIZEDTIME 24
+#define ODR_GRAPHICSTRING   25
+#define ODR_VISIBLESTRING   26
+#define ODR_GENERALSTRING   27
+
+/*
+ * odr stream directions
+ */
+#define ODR_DECODE      0
+#define ODR_ENCODE      1
+#define ODR_PRINT       2
+
+typedef struct odr_oct
+{
+    unsigned char *buf;
+    int len;
+    int size;
+} Odr_oct;
+
+typedef void Odr_null;
+extern Odr_null *ODR_NULLVAL;
+
+typedef Odr_oct Odr_any;
+
+typedef struct odr_bitmask
+{
+#define ODR_BITMASK_SIZE 256
+    unsigned char bits[ODR_BITMASK_SIZE];
+    int top;
+} Odr_bitmask;
+
+typedef int Odr_oid;   /* terminate by -1 */
+
+typedef struct odr_constack
+{
+    const unsigned char *base;   /* starting point of data */
+    int base_offset;
+    int len;                     /* length of data, if known, else -1
+                                        (decoding only) */
+    const unsigned char *lenb;   /* where to encode length */
+    int len_offset;
+    int lenlen;                  /* length of length-field */
+} odr_constack;
+
+#define ODR_S_SET     0
+#define ODR_S_CUR     1
+#define ODR_S_END     2
+
+typedef struct {      /* used to be statics in ber_tag... */
+    int lclass;
+    int ltag;
+    int br;
+    int lcons;
+} Odr_ber_tag;
+
+typedef struct odr
+{
+    int direction;       /* the direction of this stream */
+
+    int error;           /* current error state (0==OK) */
+
+    int can_grow;         /* are we allowed to reallocate */
+    unsigned char *buf;            /* memory handle */
+    int size;             /* current buffer size */
+
+    int pos;              /* current position */
+    int top;              /* top of buffer (max pos when decoding) */
+
+    const unsigned char *bp; /* position in buffer (decoding) */
+
+    int t_class;         /* implicit tagging (-1==default tag) */
+    int t_tag;
+
+    int enable_bias;     /* force choice enable flag */
+    int choice_bias;     /* force choice */
+    int lenlen;          /* force length-of-lenght (odr_setlen()) */
+
+    FILE *print;         /* output file for direction print */
+    int indent;          /* current indent level for printing */
+
+    NMEM mem;            /* memory handle for decoding (primarily) */
+
+    /* stack for constructed types */
+#define ODR_MAX_STACK 50
+    int stackp;          /* top of stack (-1 == initial state) */
+    odr_constack stack[ODR_MAX_STACK];
+
+    Odr_ber_tag odr_ber_tag;
+} *ODR;
+
+typedef int (*Odr_fun)(ODR, char **, int, const char *);
+
+typedef struct odr_arm
+{
+    int tagmode;
+    int zclass;
+    int tag;
+    int which;
+    Odr_fun fun;
+    char *name;
+} Odr_arm;
+
+/*
+ * Error control.
+ */
+#define ONONE           0
+#define OMEMORY         1
+#define OSYSERR         2
+#define OSPACE          3
+#define OREQUIRED       4
+#define OUNEXPECTED     5
+#define OOTHER          6
+#define OPROTO          7
+#define ODATA           8
+#define OSTACK          9
+#define OCONLEN        10
+#define OLENOV         11
+
+extern char *odr_errlist[];
+
+YAZ_EXPORT int odr_geterror(ODR o);
+YAZ_EXPORT void odr_perror(ODR o, char *message);
+YAZ_EXPORT void odr_setprint(ODR o, FILE *file);
+YAZ_EXPORT ODR odr_createmem(int direction);
+YAZ_EXPORT void odr_reset(ODR o);
+YAZ_EXPORT void odr_destroy(ODR o);
+YAZ_EXPORT void odr_setbuf(ODR o, char *buf, int len, int can_grow);
+YAZ_EXPORT char *odr_getbuf(ODR o, int *len, int *size);
+YAZ_EXPORT void *odr_malloc(ODR o, int size);
+YAZ_EXPORT char *odr_strdup(ODR o, const char *str);
+YAZ_EXPORT NMEM odr_extract_mem(ODR o);
+YAZ_EXPORT Odr_null *odr_nullval(void);
+#define odr_release_mem(m) nmem_destroy(m)
+#define ODR_MEM NMEM
+
+#define odr_implicit(o, t, p, cl, tg, opt)\
+        (odr_implicit_settag((o), cl, tg), t ((o), (p), (opt), 0) )
+
+#define odr_implicit_tag(o, t, p, cl, tg, opt, name)\
+        (odr_implicit_settag((o), cl, tg), t ((o), (p), (opt), name) )
+
+#define odr_explicit(o, t, p, cl, tg, opt)\
+        ((int) (odr_constructed_begin((o), (p), (cl), (tg), 0) ? \
+        t ((o), (p), (opt), 0) &&\
+        odr_constructed_end(o) : opt))
+
+#define odr_explicit_tag(o, t, p, cl, tg, opt, name)\
+        ((int) (odr_constructed_begin((o), (p), (cl), (tg), 0) ? \
+        t ((o), (p), (opt), name) &&\
+        odr_constructed_end(o) : opt))
+
+#define ODR_MASK_ZERO(mask)\
+    ((void) (memset((mask)->bits, 0, ODR_BITMASK_SIZE),\
+    (mask)->top = -1))
+
+#define ODR_MASK_SET(mask, num)\
+    (((mask)->bits[(num) >> 3] |= 0X80 >> ((num) & 0X07)),\
+    (mask)->top < (num) >> 3 ? ((mask)->top = (num) >> 3) : 0)
+
+#define ODR_MASK_CLEAR(mask, num)\
+    ((mask)->bits[(num) >> 3] &= ~(0X80 >> ((num) & 0X07)))
+
+#define ODR_MASK_GET(mask, num)  ( ((num) >> 3 <= (mask)->top) ? \
+    ((mask)->bits[(num) >> 3] & (0X80 >> ((num) & 0X07)) ? 1 : 0) : 0)
+
+/* Private macro.
+ * write a single character at the current position - grow buffer if
+ * necessary.
+ * (no, we're not usually this anal about our macros, but this baby is
+ *  next to unreadable without some indentation  :)
+ */
+#define odr_putc(o, c) \
+( \
+    ( \
+        (o)->pos < (o)->size ? \
+        ( \
+            (o)->buf[(o)->pos++] = (c), \
+            0 \
+        ) : \
+        ( \
+            odr_grow_block((o), 1) == 0 ? \
+            ( \
+                (o)->buf[(o)->pos++] = (c), \
+                0 \
+            ) : \
+            ( \
+                (o)->error = OSPACE, \
+                -1 \
+            ) \
+        ) \
+    ) == 0 ? \
+    ( \
+        (o)->pos > (o)->top ? \
+        ( \
+            (o)->top = (o)->pos, \
+            0 \
+        ) : \
+        0 \
+    ) : \
+        -1 \
+) \
+
+#define odr_tell(o) ((o)->pos)
+#define odr_offset(o) ((o)->bp - (o)->buf)
+#define odr_ok(o) (!(o)->error)
+#define odr_getmem(o) ((o)->mem)
+#define odr_setmem(o, v) ((o)->mem = (v))
+
+#define ODR_MAXNAME 256
+
+YAZ_EXPORT int ber_boolean(ODR o, int *val);
+YAZ_EXPORT int ber_tag(ODR o, void *p, int zclass, int tag,
+		       int *constructed, int opt);
+YAZ_EXPORT int ber_enctag(ODR o, int zclass, int tag, int constructed);
+YAZ_EXPORT int ber_dectag(const unsigned char *buf, int *zclass,
+			  int *tag, int *constructed);
+YAZ_EXPORT int odr_bool(ODR o, int **p, int opt, const char *name);
+YAZ_EXPORT int odr_integer(ODR o, int **p, int opt, const char *name);
+YAZ_EXPORT int odr_enum(ODR o, int **p, int opt, const char *name);
+YAZ_EXPORT int odr_implicit_settag(ODR o, int zclass, int tag);
+YAZ_EXPORT int ber_enclen(ODR o, int len, int lenlen, int exact);
+YAZ_EXPORT int ber_declen(const unsigned char *buf, int *len);
+YAZ_EXPORT void odr_prname(ODR o, const char *name);
+YAZ_EXPORT int ber_null(ODR o);
+YAZ_EXPORT int odr_null(ODR o, Odr_null **p, int opt, const char *name);
+YAZ_EXPORT int ber_integer(ODR o, int *val);
+YAZ_EXPORT int odr_constructed_begin(ODR o, void *p, int zclass, int tag,
+				     const char *name);
+YAZ_EXPORT int odr_constructed_end(ODR o);
+YAZ_EXPORT int odr_sequence_begin(ODR o, void *p, int size, const char *name);
+YAZ_EXPORT int odr_set_begin(ODR o, void *p, int size, const char *name);
+YAZ_EXPORT int odr_sequence_end(ODR o);
+YAZ_EXPORT int odr_set_end(ODR o);
+YAZ_EXPORT int ber_octetstring(ODR o, Odr_oct *p, int cons);
+YAZ_EXPORT int odr_octetstring(ODR o, Odr_oct **p, int opt, const char *name);
+YAZ_EXPORT int odp_more_chunks(ODR o, const unsigned char *base, int len);
+YAZ_EXPORT int odr_constructed_more(ODR o);
+YAZ_EXPORT int odr_bitstring(ODR o, Odr_bitmask **p, int opt,
+			     const char *name);
+YAZ_EXPORT int ber_bitstring(ODR o, Odr_bitmask *p, int cons);
+YAZ_EXPORT int odr_generalstring(ODR o, char **p, int opt, const char *name);
+YAZ_EXPORT int ber_oidc(ODR o, Odr_oid *p);
+YAZ_EXPORT int odr_oid(ODR o, Odr_oid **p, int opt, const char *name);
+YAZ_EXPORT int odr_choice(ODR o, Odr_arm arm[], void *p, void *whichp,
+			  const char *name);
+YAZ_EXPORT int odr_cstring(ODR o, char **p, int opt, const char *name);
+YAZ_EXPORT int odr_sequence_of(ODR o, Odr_fun type, void *p, int *num,
+			       const char *name);
+YAZ_EXPORT int odr_set_of(ODR o, Odr_fun type, void *p, int *num,
+			  const char *name);
+YAZ_EXPORT int odr_any(ODR o, Odr_any **p, int opt, const char *name);
+YAZ_EXPORT int ber_any(ODR o, Odr_any **p);
+YAZ_EXPORT int completeBER(const unsigned char *buf, int len);
+YAZ_EXPORT void odr_begin(ODR o);
+YAZ_EXPORT void odr_end(ODR o);
+YAZ_EXPORT Odr_oid *odr_oiddup(ODR odr, Odr_oid *o);
+YAZ_EXPORT Odr_oid *odr_oiddup_nmem(NMEM nmem, Odr_oid *o);
+YAZ_EXPORT int odr_grow_block(ODR b, int min_bytes);
+YAZ_EXPORT int odr_write(ODR o, unsigned char *buf, int bytes);
+YAZ_EXPORT int odr_seek(ODR o, int whence, int offset);
+YAZ_EXPORT int odr_dumpBER(FILE *f, const char *buf, int len);
+YAZ_EXPORT void odr_choice_bias(ODR o, int what);
+YAZ_EXPORT void odr_choice_enable_bias(ODR o, int mode);
+YAZ_EXPORT int odr_total(ODR o);
+YAZ_EXPORT char *odr_errmsg(int n);
+YAZ_EXPORT Odr_oid *odr_getoidbystr(ODR o, char *str);
+YAZ_EXPORT Odr_oid *odr_getoidbystr_nmem(NMEM o, char *str);
+YAZ_EXPORT int odr_initmember(ODR o, void *p, int size);
+YAZ_EXPORT int odr_peektag(ODR o, int *zclass, int *tag, int *cons);
+YAZ_EXPORT void odr_setlenlen(ODR o, int len);
+
+typedef struct Odr_external
+{
+    Odr_oid *direct_reference;       /* OPTIONAL */
+    int     *indirect_reference;     /* OPTIONAL */
+    char    *descriptor;             /* OPTIONAL */
+    int which;
+#define ODR_EXTERNAL_single 0
+#define ODR_EXTERNAL_octet 1
+#define ODR_EXTERNAL_arbitrary 2
+    union
+    {
+	Odr_any  *single_ASN1_type;
+	Odr_oct  *octet_aligned; 
+	Odr_bitmask *arbitrary;      /* we aren't really equipped for this*/
+    } u;
+} Odr_external;
+
+YAZ_EXPORT int odr_external(ODR o, Odr_external **p, int opt,
+			    const char *name);
+YAZ_EXPORT int odr_visiblestring(ODR o, char **p, int opt,
+				 const char *name);
+YAZ_EXPORT int odr_graphicstring(ODR o, char **p, int opt,
+				 const char *name);
+YAZ_EXPORT int odr_generalizedtime(ODR o, char **p, int opt,
+				   const char *name);
+YAZ_END_CDECL
+
+#include <yaz/xmalloc.h>
+
+#endif
Index: /main/tags/2.25/gsdl/packages/yaz/include/yaz/oid.h
===================================================================
--- /main/tags/2.25/gsdl/packages/yaz/include/yaz/oid.h	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/yaz/include/yaz/oid.h	(revision 21064)
@@ -0,0 +1,202 @@
+/*
+ * Copyright (c) 1995-2000, Index Data.
+ *
+ * Permission to use, copy, modify, distribute, and sell this software and
+ * its documentation, in whole or in part, for any purpose, is hereby granted,
+ * provided that:
+ *
+ * 1. This copyright and permission notice appear in all copies of the
+ * software and its documentation. Notices of copyright or attribution
+ * which appear at the beginning of any file must remain unchanged.
+ *
+ * 2. The name of Index Data or the individual authors may not be used to
+ * endorse or promote products derived from this software without specific
+ * prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED "AS IS" AND WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS, IMPLIED, OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY
+ * WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
+ * IN NO EVENT SHALL INDEX DATA BE LIABLE FOR ANY SPECIAL, INCIDENTAL,
+ * INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND, OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER OR
+ * NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF
+ * LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
+ * OF THIS SOFTWARE.
+ *
+ * $Id$
+ */
+
+#ifndef OID_H
+#define OID_H
+
+#include <yaz/yconfig.h>
+
+YAZ_BEGIN_CDECL
+
+#define OID_SIZE 20
+    
+typedef enum oid_proto
+{
+    PROTO_NOP=0,
+    PROTO_Z3950,
+    PROTO_SR,
+    PROTO_GENERAL,
+    PROTO_WAIS
+} oid_proto;
+
+typedef enum oid_class
+{
+    CLASS_NOP=0,
+    CLASS_APPCTX,
+    CLASS_ABSYN,
+    CLASS_ATTSET,
+    CLASS_TRANSYN,
+    CLASS_DIAGSET,
+    CLASS_RECSYN,
+    CLASS_RESFORM,
+    CLASS_ACCFORM,
+    CLASS_EXTSERV,
+    CLASS_USERINFO,
+    CLASS_ELEMSPEC,
+    CLASS_VARSET,
+    CLASS_SCHEMA,
+    CLASS_TAGSET,
+    CLASS_GENERAL
+} oid_class;
+
+typedef enum oid_value
+{
+    VAL_NOP=0,
+    VAL_APDU,
+    VAL_BER,
+    VAL_BASIC_CTX,
+    VAL_BIB1,
+    VAL_EXP1,
+    VAL_EXT1,
+    VAL_CCL1,
+    VAL_GILS,
+    VAL_WAIS,
+    VAL_STAS,
+    VAL_COLLECT1,
+    VAL_CIMI1,
+    VAL_GEO,
+    VAL_DIAG1,
+    VAL_ISO2709,
+    VAL_UNIMARC,
+    VAL_INTERMARC,
+    VAL_CCF,
+    VAL_USMARC,
+    VAL_UKMARC,
+    VAL_NORMARC,
+    VAL_LIBRISMARC,
+    VAL_DANMARC,
+    VAL_FINMARC,
+    VAL_MAB,
+    VAL_CANMARC,
+    VAL_SBN,
+    VAL_PICAMARC,
+    VAL_AUSMARC,
+    VAL_IBERMARC,
+    VAL_CATMARC,
+    VAL_MALMARC,
+    VAL_EXPLAIN,
+    VAL_SUTRS,
+    VAL_OPAC,
+    VAL_SUMMARY,
+    VAL_GRS0,
+    VAL_GRS1,
+    VAL_EXTENDED,
+    VAL_FRAGMENT,
+    VAL_RESOURCE1,
+    VAL_RESOURCE2,
+    VAL_PROMPT1,
+    VAL_DES1,
+    VAL_KRB1,
+    VAL_PRESSET,
+    VAL_PQUERY,
+    VAL_PCQUERY,
+    VAL_ITEMORDER,
+    VAL_DBUPDATE0,
+    VAL_DBUPDATE,
+    VAL_EXPORTSPEC,
+    VAL_EXPORTINV,
+    VAL_NONE,
+    VAL_SETM,
+    VAL_SETG,
+    VAL_VAR1,
+    VAL_ESPEC1,
+    VAL_SOIF,
+    VAL_SEARCHRES1,
+    VAL_THESAURUS,
+    VAL_CHARLANG,
+    VAL_USERINFO1,
+    VAL_MULTISRCH1,
+    VAL_MULTISRCH2,
+    VAL_DATETIME,
+    VAL_SQLRS,
+    VAL_PDF,
+    VAL_POSTSCRIPT,
+    VAL_HTML,
+    VAL_TIFF,
+    VAL_GIF,
+    VAL_JPEG,
+    VAL_PNG,
+    VAL_MPEG,
+    VAL_SGML,
+    VAL_TIFFB,
+    VAL_WAV,
+    VAL_UPDATEES,
+    VAL_TEXT_XML,
+    VAL_APPLICATION_XML,
+    VAL_UNIVERSE_REPORT,
+    VAL_PROXY,
+    VAL_COOKIE,
+    VAL_CLIENT_IP,
+    VAL_ISO_ILL_1,
+    VAL_ZBIG,
+    VAL_UTIL,
+    VAL_XD1,
+    VAL_ZTHES,
+    VAL_FIN1,
+    VAL_DAN1,
+    VAL_DIAG_ES,
+    VAL_DIAG_GENERAL,
+    VAL_JPMARC,
+    VAL_SWEMARC,
+    VAL_SIGLEMARC,
+    VAL_ISDSMARC,
+    VAL_RUSMARC,
+/* add new types here... */
+
+/* VAL_DYNAMIC must have highest value */
+    VAL_DYNAMIC,
+    VAL_MAX = VAL_DYNAMIC+30
+} oid_value;
+
+typedef struct oident
+{
+    oid_proto proto;
+    oid_class oclass;
+    oid_value value;
+    int oidsuffix[OID_SIZE];
+    char *desc;
+} oident;
+
+YAZ_EXPORT int *oid_getoidbyent(struct oident *ent);
+YAZ_EXPORT int *oid_ent_to_oid(struct oident *ent, int *dst);
+YAZ_EXPORT struct oident *oid_getentbyoid(int *o);
+YAZ_EXPORT void oid_oidcpy(int *t, int *s);
+YAZ_EXPORT void oid_oidcat(int *t, int *s);
+YAZ_EXPORT int oid_oidcmp(int *o1, int *o2);
+YAZ_EXPORT int oid_oidlen(int *o);
+YAZ_EXPORT oid_value oid_getvalbyname(const char *name);
+YAZ_EXPORT void oid_setprivateoids(oident *list);
+YAZ_EXPORT struct oident *oid_addent (int *oid, enum oid_proto proto,
+				      enum oid_class oclass,
+				      const char *desc, int value);
+YAZ_EXPORT void oid_init(void);
+YAZ_EXPORT void oid_exit(void);
+
+YAZ_END_CDECL
+
+#endif
Index: /main/tags/2.25/gsdl/packages/yaz/include/yaz/options.h
===================================================================
--- /main/tags/2.25/gsdl/packages/yaz/include/yaz/options.h	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/yaz/include/yaz/options.h	(revision 21064)
@@ -0,0 +1,78 @@
+/*
+ * Copyright (c) 1995-2000, Index Data.
+ *
+ * Permission to use, copy, modify, distribute, and sell this software and
+ * its documentation, in whole or in part, for any purpose, is hereby granted,
+ * provided that:
+ *
+ * 1. This copyright and permission notice appear in all copies of the
+ * software and its documentation. Notices of copyright or attribution
+ * which appear at the beginning of any file must remain unchanged.
+ *
+ * 2. The name of Index Data or the individual authors may not be used to
+ * endorse or promote products derived from this software without specific
+ * prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED "AS IS" AND WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS, IMPLIED, OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY
+ * WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
+ * IN NO EVENT SHALL INDEX DATA BE LIABLE FOR ANY SPECIAL, INCIDENTAL,
+ * INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND, OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER OR
+ * NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF
+ * LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
+ * OF THIS SOFTWARE.
+ *
+ * $Log$
+ * Revision 1.1  2000/08/03 03:10:41  johnmcp
+ * Added the YAZ toolkit source to the packages directory (for z39.50 stuff)
+ *
+ * Revision 1.2  2000/02/28 11:20:06  adam
+ * Using autoconf. New definitions: YAZ_BEGIN_CDECL/YAZ_END_CDECL.
+ *
+ * Revision 1.1  1999/11/30 13:47:11  adam
+ * Improved installation. Moved header files to include/yaz.
+ *
+ * Revision 1.6  1997/09/01 08:49:50  adam
+ * New windows NT/95 port using MSV5.0. To export DLL functions the
+ * YAZ_EXPORT modifier was added. Defined in yconfig.h.
+ *
+ * Revision 1.5  1997/05/14 06:53:43  adam
+ * C++ support.
+ *
+ * Revision 1.4  1995/09/29 17:12:05  quinn
+ * Smallish
+ *
+ * Revision 1.3  1995/09/27  15:02:48  quinn
+ * Modified function heads & prototypes.
+ *
+ * Revision 1.2  1995/05/16  08:50:36  quinn
+ * License, documentation, and memory fixes
+ *
+ * Revision 1.1  1995/03/30  09:39:42  quinn
+ * Moved .h files to include directory
+ *
+ * Revision 1.1  1995/03/27  08:35:19  quinn
+ * Created util library
+ * Added memory debugging module. Imported options-manager
+ *
+ * Revision 1.2  1994/08/16  16:16:03  adam
+ * bfile header created.
+ *
+ * Revision 1.1  1994/08/16  16:04:35  adam
+ * Added header file options.h
+ *
+ */
+
+#ifndef OPTIONS_H
+#define OPTIONS_H
+#include <yaz/yconfig.h>
+
+YAZ_BEGIN_CDECL
+
+YAZ_EXPORT int options (const char *desc, char **argv, int argc, char **arg);
+
+YAZ_END_CDECL
+
+#endif
+	
Index: /main/tags/2.25/gsdl/packages/yaz/include/yaz/otherinfo.h
===================================================================
--- /main/tags/2.25/gsdl/packages/yaz/include/yaz/otherinfo.h	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/yaz/include/yaz/otherinfo.h	(revision 21064)
@@ -0,0 +1,36 @@
+/*
+ * Copyright (c) 1999, Index Data
+ * See the file LICENSE for details.
+ * Sebastian Hammer, Adam Dickmeiss
+ *
+ * $Id$
+ */
+#ifndef OTHERINFO_H
+#define OTHERINFO_H
+
+#include <yaz/proto.h>
+
+YAZ_BEGIN_CDECL
+
+YAZ_EXPORT void yaz_oi_APDU(Z_APDU *apdu, Z_OtherInformation ***oip);
+YAZ_EXPORT    Z_OtherInformationUnit *yaz_oi_update (
+    Z_OtherInformation **otherInformationP, ODR odr,
+    int *oid, int categoryValue, int delete_flag);
+YAZ_EXPORT void yaz_oi_set_string_oid (
+    Z_OtherInformation **otherInformation, ODR odr,
+    int *oid, int categoryValue,
+    const char *str);
+YAZ_EXPORT void yaz_oi_set_string_oidval (
+    Z_OtherInformation **otherInformation, ODR odr,
+    int oidval, int categoryValue,
+    const char *str);
+YAZ_EXPORT char *yaz_oi_get_string_oid (
+    Z_OtherInformation **otherInformation,
+    int *oid, int categoryValue, int delete_flag);
+YAZ_EXPORT char *yaz_oi_get_string_oidval(
+    Z_OtherInformation **otherInformation,
+    int oidval, int categoryValue, int delete_flag);
+
+YAZ_END_CDECL
+
+#endif
Index: /main/tags/2.25/gsdl/packages/yaz/include/yaz/pquery.h
===================================================================
--- /main/tags/2.25/gsdl/packages/yaz/include/yaz/pquery.h	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/yaz/include/yaz/pquery.h	(revision 21064)
@@ -0,0 +1,80 @@
+/*
+ * Copyright (c) 1995-2000, Index Data.
+ *
+ * Permission to use, copy, modify, distribute, and sell this software and
+ * its documentation, in whole or in part, for any purpose, is hereby granted,
+ * provided that:
+ *
+ * 1. This copyright and permission notice appear in all copies of the
+ * software and its documentation. Notices of copyright or attribution
+ * which appear at the beginning of any file must remain unchanged.
+ *
+ * 2. The name of Index Data or the individual authors may not be used to
+ * endorse or promote products derived from this software without specific
+ * prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED "AS IS" AND WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS, IMPLIED, OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY
+ * WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
+ * IN NO EVENT SHALL INDEX DATA BE LIABLE FOR ANY SPECIAL, INCIDENTAL,
+ * INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND, OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER OR
+ * NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF
+ * LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
+ * OF THIS SOFTWARE.
+ *
+ * $Log$
+ * Revision 1.1  2000/08/03 03:10:42  johnmcp
+ * Added the YAZ toolkit source to the packages directory (for z39.50 stuff)
+ *
+ * Revision 1.2  2000/02/28 11:20:06  adam
+ * Using autoconf. New definitions: YAZ_BEGIN_CDECL/YAZ_END_CDECL.
+ *
+ * Revision 1.1  1999/11/30 13:47:11  adam
+ * Improved installation. Moved header files to include/yaz.
+ *
+ * Revision 1.8  1997/09/01 08:49:50  adam
+ * New windows NT/95 port using MSV5.0. To export DLL functions the
+ * YAZ_EXPORT modifier was added. Defined in yconfig.h.
+ *
+ * Revision 1.7  1997/05/14 06:53:43  adam
+ * C++ support.
+ *
+ * Revision 1.6  1996/08/12 14:09:24  adam
+ * Default prefix query attribute set defined by using p_query_attset.
+ *
+ * Revision 1.5  1996/03/15  11:01:46  adam
+ * Extra argument to p_query_rpn: protocol.
+ * Extra arguments to p_query_scan: protocol and attributeSet.
+ *
+ * Revision 1.4  1995/09/29  17:12:05  quinn
+ * Smallish
+ *
+ * Revision 1.3  1995/09/27  15:02:49  quinn
+ * Modified function heads & prototypes.
+ *
+ * Revision 1.2  1995/05/26  08:56:05  adam
+ * New function: p_query_scan.
+ *
+ * Revision 1.1  1995/05/22  15:31:05  adam
+ * New function, p_query_rpn, to convert from prefix (ascii) to rpn (asn).
+ *
+ */
+
+#ifndef PQUERY_H
+#define PQUERY_H
+
+#include <yaz/yconfig.h>
+#include <yaz/proto.h>
+
+YAZ_BEGIN_CDECL
+
+YAZ_EXPORT Z_RPNQuery *p_query_rpn (ODR o, oid_proto proto, const char *qbuf);
+
+YAZ_EXPORT Z_AttributesPlusTerm *p_query_scan (ODR o, oid_proto proto,
+           Odr_oid **attributeSetP, const char *qbuf);
+YAZ_EXPORT int p_query_attset (const char *arg);
+
+YAZ_END_CDECL
+
+#endif
Index: /main/tags/2.25/gsdl/packages/yaz/include/yaz/proto.h
===================================================================
--- /main/tags/2.25/gsdl/packages/yaz/include/yaz/proto.h	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/yaz/include/yaz/proto.h	(revision 21064)
@@ -0,0 +1,126 @@
+/*
+ * Copyright (c) 1998-2000, Index Data
+ * See the file LICENSE for details.
+ * Sebastian Hammer, Adam Dickmeiss
+ *
+ * $Log$
+ * Revision 1.1  2000/08/03 03:10:42  johnmcp
+ * Added the YAZ toolkit source to the packages directory (for z39.50 stuff)
+ *
+ * Revision 1.3  2000/02/28 11:20:06  adam
+ * Using autoconf. New definitions: YAZ_BEGIN_CDECL/YAZ_END_CDECL.
+ *
+ * Revision 1.2  1999/12/16 23:36:19  adam
+ * Implemented ILL protocol. Minor updates ASN.1 compiler.
+ *
+ * Revision 1.1  1999/11/30 13:47:11  adam
+ * Improved installation. Moved header files to include/yaz.
+ *
+ * Revision 1.2  1999/06/09 10:52:11  adam
+ * Added YAZ_EXPORT.
+ *
+ * Revision 1.1  1999/06/08 13:11:55  adam
+ * Fixed problem with proto.h.
+ *
+ * Revision 1.2  1999/04/20 10:37:04  adam
+ * Updated for ODR - added name parameter.
+ *
+ * Revision 1.1  1998/03/31 16:04:05  adam
+ * First version of proto.h which is almost compatible with the old one.
+ *
+ */
+#ifndef Z_PROTO_H
+#define Z_PROTO_H
+
+#define Z_95 1
+#define ASN_COMPILED 1
+
+#include <yaz/yaz-version.h>
+#include <yaz/z-accdes1.h>
+#include <yaz/z-accform1.h>
+#include <yaz/z-acckrb1.h>
+#include <yaz/z-core.h>
+#include <yaz/z-diag1.h>
+#include <yaz/z-espec1.h>
+#include <yaz/z-estask.h>
+#include <yaz/z-exp.h>
+#include <yaz/z-grs.h>
+#include <yaz/z-opac.h>
+#include <yaz/z-rrf1.h>
+#include <yaz/z-rrf2.h>
+#include <yaz/z-sum.h>
+#include <yaz/z-sutrs.h>
+#include <yaz/z-uifr1.h>
+#include <yaz/zes-expi.h>
+#include <yaz/zes-exps.h>
+#include <yaz/zes-order.h>
+#include <yaz/zes-pquery.h>
+#include <yaz/zes-psched.h>
+#include <yaz/zes-pset.h>
+#include <yaz/zes-update.h>
+#include <yaz/z-date.h>
+#include <yaz/z-univ.h>
+
+YAZ_BEGIN_CDECL
+
+#define Z_PRES_SUCCESS   Z_PresentStatus_success
+#define Z_PRES_PARTIAL_1 Z_PresentStatus_partial_1
+#define Z_PRES_PARTIAL_2 Z_PresentStatus_partial_2
+#define Z_PRES_PARTIAL_3 Z_PresentStatus_partial_3
+#define Z_PRES_PARTIAL_4 Z_PresentStatus_partial_4
+#define Z_PRES_FAILURE   Z_PresentStatus_failure
+
+#define Z_RES_SUBSET  Z_SearchResponse_subset
+#define Z_RES_INTERIM Z_SearchResponse_interim
+#define Z_RES_NONE    Z_SearchResponse_none
+
+#define Z_SortStatus_success Z_SortResponse_success 
+#define Z_SortStatus_partial_1 Z_SortResponse_partial_1
+#define Z_SortStatus_failure Z_SortResponse_failure
+
+#define Z_SortRelation_ascending            Z_SortKeySpec_ascending 
+#define Z_SortRelation_descending           Z_SortKeySpec_descending
+#define Z_SortRelation_ascendingByFreq      Z_SortKeySpec_ascendingByFrequency
+#define Z_SortRelation_descendingByFreq     Z_SortKeySpec_descendingByfrequency 
+
+#define Z_SortCase_caseSensitive            Z_SortKeySpec_caseSensitive
+#define Z_SortCase_caseInsensitive          Z_SortKeySpec_descendingByfrequency
+
+#define Z_TriggerResourceCtrl_resourceReport Z_TriggerResourceControlRequest_resourceReport
+#define Z_TriggerResourceCtrl_resourceControl  Z_TriggerResourceControlRequest_resourceControl
+#define Z_TriggerResourceCtrl_cancel Z_TriggerResourceControlRequest_cancel
+
+#define Z_DeleteRequest_list    Z_DeleteResultSetRequest_list
+#define Z_DeleteRequest_all     Z_DeleteResultSetRequest_all
+
+#define Z_AccessRequest_simpleForm Z_AccessControlRequest_simpleForm
+#define Z_AccessRequest_externallyDefined Z_AccessControlRequest_externallyDefined
+
+#define Z_AccessResponse_simpleForm Z_AccessControlResponse_simpleForm
+#define Z_AccessResponse_externallyDefined Z_AccessControlResponse_externallyDefined
+
+#define Z_ResourceReportStatus_success   Z_ResourceReportResponse_success
+#define Z_ResourceReportStatus_partial   Z_ResourceReportResponse_partial
+#define Z_ResourceReportStatus_failure_1 Z_ResourceReportResponse_failure_1
+#define Z_ResourceReportStatus_failure_2 Z_ResourceReportResponse_failure_2
+#define Z_ResourceReportStatus_failure_3 Z_ResourceReportResponse_failure_3
+#define Z_ResourceReportStatus_failure_4 Z_ResourceReportResponse_failure_4
+#define Z_ResourceReportStatus_failure_5 Z_ResourceReportResponse_failure_5
+#define Z_ResourceReportStatus_failure_6 Z_ResourceReportResponse_failure_6
+
+#define Z_SortResultSetStatus_empty       Z_SortResponse_empty
+#define Z_SortResultSetStatus_interim     Z_SortResponse_interim
+#define Z_SortResultSetStatus_unchanged   Z_SortResponse_unchanged
+#define Z_SortResultSetStatus_none        Z_SortResponse_none
+
+typedef Z_External Z_DatabaseRecord;
+typedef struct Z_IOItemOrder Z_ItemOrder;
+
+YAZ_EXPORT Z_APDU *zget_APDU(ODR o, int which);
+YAZ_EXPORT Z_Close *zget_Close (ODR o);
+
+YAZ_END_CDECL
+
+#include <yaz/prt-ext.h>
+
+#endif
Index: /main/tags/2.25/gsdl/packages/yaz/include/yaz/prt-acc.h
===================================================================
--- /main/tags/2.25/gsdl/packages/yaz/include/yaz/prt-acc.h	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/yaz/include/yaz/prt-acc.h	(revision 21064)
@@ -0,0 +1,184 @@
+/*
+ * Copyright (c) 1995, Index Data.
+ *
+ * Permission to use, copy, modify, distribute, and sell this software and
+ * its documentation, in whole or in part, for any purpose, is hereby granted,
+ * provided that:
+ *
+ * 1. This copyright and permission notice appear in all copies of the
+ * software and its documentation. Notices of copyright or attribution
+ * which appear at the beginning of any file must remain unchanged.
+ *
+ * 2. The name of Index Data or the individual authors may not be used to
+ * endorse or promote products derived from this software without specific
+ * prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED "AS IS" AND WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS, IMPLIED, OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY
+ * WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
+ * IN NO EVENT SHALL INDEX DATA BE LIABLE FOR ANY SPECIAL, INCIDENTAL,
+ * INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND, OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER OR
+ * NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF
+ * LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
+ * OF THIS SOFTWARE.
+ *
+ * $Log$
+ * Revision 1.1  2000/08/03 03:10:43  johnmcp
+ * Added the YAZ toolkit source to the packages directory (for z39.50 stuff)
+ *
+ * Revision 1.1  1999/11/30 13:47:11  adam
+ * Improved installation. Moved header files to include/yaz.
+ *
+ * Revision 1.9  1999/04/20 09:56:48  adam
+ * Added 'name' paramter to encoder/decoder routines (typedef Odr_fun).
+ * Modified all encoders/decoders to reflect this change.
+ *
+ * Revision 1.8  1997/09/01 08:49:51  adam
+ * New windows NT/95 port using MSV5.0. To export DLL functions the
+ * YAZ_EXPORT modifier was added. Defined in yconfig.h.
+ *
+ * Revision 1.7  1997/05/14 06:53:46  adam
+ * C++ support.
+ *
+ * Revision 1.6  1996/01/02 08:57:35  quinn
+ * Changed enums in the ASN.1 .h files to #defines. Changed oident.class to oclass
+ *
+ * Revision 1.5  1995/09/29  17:12:09  quinn
+ * Smallish
+ *
+ * Revision 1.4  1995/09/27  15:02:49  quinn
+ * Modified function heads & prototypes.
+ *
+ * Revision 1.3  1995/08/17  12:45:16  quinn
+ * Fixed minor problems with GRS-1. Added support in c&s.
+ *
+ * Revision 1.2  1995/08/15  12:00:13  quinn
+ * Updated External
+ *
+ * Revision 1.1  1995/06/02  09:49:49  quinn
+ * Add access control
+ *
+ *
+ */
+
+#ifndef PRT_ACC_H
+#define PRT_ACC_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef struct Z_Encryption1
+{
+    Odr_oct *cryptType;       /* OPTIONAL */
+    Odr_oct *credential;      /* OPTIONAL */
+    Odr_oct *data;
+} Z_Encryption1;
+
+typedef struct Z_EnumeratedPrompt1
+{
+    int *type;
+#define Z_Prompt1_groupId        0
+#define Z_Prompt1_userId         1
+#define Z_Prompt1_password       2
+#define Z_Prompt1_newPassword    3
+#define Z_Prompt1_copyright      4
+    char *suggestedString;       /* OPTIONAL */
+} Z_EnumeratedPrompt1;
+
+typedef struct Z_PromptId1
+{
+    int which;
+#define Z_PromptId1_enumeratedPrompt 0
+#define Z_PromptId1_nonEnumeratedPrompt 1
+    union
+    {
+    	Z_EnumeratedPrompt1 *enumeratedPrompt;
+	char *nonEnumeratedPrompt;
+    } u;
+} Z_PromptId1;
+
+typedef struct Z_PromptInfo1
+{
+    int which;
+#define Z_Challenge1_character 0
+#define Z_Challenge1_encrypted 1
+    union
+    {
+    	char *character;
+	Z_Encryption1 *encrypted;
+    } u;
+} Z_PromptInfo1;
+
+typedef struct Z_ChallengeUnit1
+{
+    Z_PromptId1 *promptId;
+    char *defaultResponse;           /* OPTIONAL */
+    Z_PromptInfo1 *promptInfo;       /* OPTIONAL */
+    char *regExpr;                   /* OPTIONAL */
+    Odr_null *responseRequired;      /* OPTIONAL */
+    int num_values;
+    char **allowedValues;            /* OPTIONAL */
+    Odr_null *shouldSave;            /* OPTIONAL */
+    int *dataType;                   /* OPTIONAL */
+#define Z_ChalDataType_integer       1
+#define Z_ChalDataType_date          2
+#define Z_ChalDataType_float         3
+#define Z_ChalDataType_alphaNumeric  4
+#define Z_ChalDataType_urlUrn        5
+#define Z_ChalDataType_boolean       6
+    Z_External *diagnostic;        /* OPTIONAL */
+} Z_ChallengeUnit1;
+
+typedef struct Z_Challenge1
+{
+    int num_challenges;
+    Z_ChallengeUnit1 **list;
+} Z_Challenge1;
+
+typedef struct Z_ResponseUnit1
+{
+    Z_PromptId1 *promptId;
+    int which;
+#define Z_Response1_string 0
+#define Z_Response1_accept 1
+#define Z_Response1_acknowledge 2
+#define Z_Response1_diagnostic 3
+#define Z_Response1_encrypted 4
+    union
+    {
+    	char *string;
+	bool_t *accept;
+	Odr_null *acknowledge;
+	Z_DiagRec *diagnostic;
+	Z_Encryption1 *encrypted;
+    } u;
+} Z_ResponseUnit1;
+
+typedef struct Z_Response1
+{
+    int num_responses;
+    Z_ResponseUnit1 **list;
+} Z_Response1;
+
+typedef struct Z_PromptObject1
+{
+    int which;
+#define Z_PromptObject1_challenge 0
+#define Z_PromptObject1_response 1
+    union
+    {
+    	Z_Challenge1 *challenge;
+	Z_Response1 *response;
+    } u;
+} Z_PromptObject1;
+
+YAZ_EXPORT int z_PromptObject1(ODR o, Z_PromptObject1 **p, int opt,
+			       const char *name);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
Index: /main/tags/2.25/gsdl/packages/yaz/include/yaz/prt-add.h
===================================================================
--- /main/tags/2.25/gsdl/packages/yaz/include/yaz/prt-add.h	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/yaz/include/yaz/prt-add.h	(revision 21064)
@@ -0,0 +1,123 @@
+/*
+ * Copyright (c) 1995, Index Data.
+ *
+ * Permission to use, copy, modify, distribute, and sell this software and
+ * its documentation, in whole or in part, for any purpose, is hereby granted,
+ * provided that:
+ *
+ * 1. This copyright and permission notice appear in all copies of the
+ * software and its documentation. Notices of copyright or attribution
+ * which appear at the beginning of any file must remain unchanged.
+ *
+ * 2. The name of Index Data or the individual authors may not be used to
+ * endorse or promote products derived from this software without specific
+ * prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED "AS IS" AND WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS, IMPLIED, OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY
+ * WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
+ * IN NO EVENT SHALL INDEX DATA BE LIABLE FOR ANY SPECIAL, INCIDENTAL,
+ * INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND, OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER OR
+ * NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF
+ * LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
+ * OF THIS SOFTWARE.
+ *
+ * $Log$
+ * Revision 1.1  2000/08/03 03:10:43  johnmcp
+ * Added the YAZ toolkit source to the packages directory (for z39.50 stuff)
+ *
+ * Revision 1.1  1999/11/30 13:47:11  adam
+ * Improved installation. Moved header files to include/yaz.
+ *
+ * Revision 1.4  1999/04/20 09:56:48  adam
+ * Added 'name' paramter to encoder/decoder routines (typedef Odr_fun).
+ * Modified all encoders/decoders to reflect this change.
+ *
+ * Revision 1.3  1997/05/14 06:53:46  adam
+ * C++ support.
+ *
+ * Revision 1.2  1997/04/30 08:52:09  quinn
+ * Null
+ *
+ * Revision 1.1  1996/10/10  11:51:58  quinn
+ * Added SerchResult additional info
+ *
+ *
+ */
+
+#ifndef PRT_ADD_H
+#define PRT_ADD_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef struct Z_QueryExpressionTerm
+{
+    Z_Term *queryTerm;
+    char *termComment;              /* OPTIONAL */
+} Z_QueryExpressionTerm;
+
+typedef struct Z_QueryExpression
+{
+    int which;
+#define Z_QueryExpression_term 1
+#define Z_QueryExpression_query 2
+    union {
+	Z_QueryExpressionTerm *term;
+	Z_Query *query;
+    } u;
+} Z_QueryExpression;
+
+typedef struct Z_ResultsByDBList
+{
+    int num;
+    Z_DatabaseName **elements;
+} Z_ResultsByDBList;
+
+typedef struct Z_ResultsByDB_elem
+{
+    int which;
+#define Z_ResultsByDB_all 1
+#define Z_ResultsByDB_list 2
+    union {
+        Odr_null *all;
+        Z_ResultsByDBList *list;
+    } u;
+    int *count;                           /* OPTIONAL */
+    char *resultSetName; /* OPTIONAL */
+} Z_ResultsByDB_elem;
+
+typedef struct Z_ResultsByDB
+{
+    int num;
+    Z_ResultsByDB_elem **elements;
+} Z_ResultsByDB;
+
+typedef struct Z_SearchInfoReport_elem
+{
+    char *subqueryId;                          /* OPTIONAL */
+    bool_t *fullQuery;
+    Z_QueryExpression *subqueryExpression;     /* OPTIONAL */
+    Z_QueryExpression *subqueryInterpretation; /* OPTIONAL */
+    Z_QueryExpression *subqueryRecommendation; /* OPTIONAL */
+    int *subqueryCount;                        /* OPTIONAL */
+    Z_IntUnit *subqueryWeight;                 /* OPTIONAL */
+    Z_ResultsByDB *resultsByDB;                /* OPTIONAL */
+} Z_SearchInfoReport_elem;
+
+typedef struct Z_SearchInfoReport
+{
+    int num;
+    Z_SearchInfoReport_elem **elements;
+} Z_SearchInfoReport;
+
+int z_SearchInfoReport (ODR o, Z_SearchInfoReport **p, int opt,
+			const char *name);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
Index: /main/tags/2.25/gsdl/packages/yaz/include/yaz/prt-arc.h
===================================================================
--- /main/tags/2.25/gsdl/packages/yaz/include/yaz/prt-arc.h	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/yaz/include/yaz/prt-arc.h	(revision 21064)
@@ -0,0 +1,138 @@
+/*
+ * Copyright (c) 1995,1996 Index Data.
+ *
+ * Permission to use, copy, modify, distribute, and sell this software and
+ * its documentation, in whole or in part, for any purpose, is hereby granted,
+ * provided that:
+ *
+ * 1. This copyright and permission notice appear in all copies of the
+ * software and its documentation. Notices of copyright or attribution
+ * which appear at the beginning of any file must remain unchanged.
+ *
+ * 2. The names of Index Data or the individual authors may not be used to
+ * endorse or promote products derived from this software without specific
+ * prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED "AS IS" AND WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS, IMPLIED, OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY
+ * WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
+ * IN NO EVENT SHALL INDEX DATA BE LIABLE FOR ANY SPECIAL, INCIDENTAL,
+ * INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND, OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER OR
+ * NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF
+ * LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
+ * OF THIS SOFTWARE.
+ *
+ */
+
+#ifndef PRT_ARC_H
+#define PRT_ARC_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* ------------------- Summary Record --------------------- */
+
+typedef struct Z_FormatSpec
+{
+    char *type;
+    int *size;                    /* OPTIONAL */
+    int *bestPosn;                /* OPTIONAL */
+} Z_FormatSpec;
+
+typedef struct Z_BriefBib
+{
+    char *title;
+    char *author;                  /* OPTIONAL */
+    char *callNumber;              /* OPTIONAL */
+    char *recordType;              /* OPTIONAL */
+    char *bibliographicLevel;      /* OPTIONAL */
+    int num_format;
+    Z_FormatSpec **format;         /* OPTIONAL */
+    char *publicationPlace;        /* OPTIONAL */
+    char *publicationDate;         /* OPTIONAL */
+    char *targetSystemKey;         /* OPTIONAL */
+    char *satisfyingElement;       /* OPTIONAL */
+    int *rank;                     /* OPTIONAL */
+    char *documentId;              /* OPTIONAL */
+    char *abstract;                /* OPTIONAL */
+    Z_OtherInformation *otherInfo; /* OPTIONAL */
+} Z_BriefBib;
+
+/* ------------------- OPAC Record --------------------- */
+
+typedef struct Z_CircRecord
+{
+    bool_t *availableNow;
+    char *availabilityDate;        /* OPTIONAL */
+    char *availableThru;           /* OPTIONAL */
+    char *restrictions;            /* OPTIONAL */
+    char *itemId;                  /* OPTIONAL */
+    bool_t *renewable;
+    bool_t *onHold;
+    char *enumAndChron;            /* OPTIONAL */
+    char *midspine;                /* OPTIONAL */
+    char *temporaryLocation;       /* OPTIONAL */
+} Z_CircRecord;
+
+typedef struct Z_Volume
+{
+    char *enumeration;             /* OPTIONAL */
+    char *chronology;              /* OPTIONAL */
+    char *enumAndChron;            /* OPTIONAL */
+} Z_Volume;
+
+typedef struct Z_HoldingsAndCircData
+{
+    char *typeOfRecord;            /* OPTIONAL */
+    char *encodingLevel;           /* OPTIONAL */
+    char *format;                  /* OPTIONAL */
+    char *receiptAcqStatus;        /* OPTIONAL */
+    char *generalRetention;        /* OPTIONAL */
+    char *completeness;            /* OPTIONAL */
+    char *dateOfReport;            /* OPTIONAL */
+    char *nucCode;                 /* OPTIONAL */
+    char *localLocation;           /* OPTIONAL */
+    char *shelvingLocation;        /* OPTIONAL */
+    char *callNumber;              /* OPTIONAL */
+    char *shelvingData;            /* OPTIONAL */
+    char *copyNumber;              /* OPTIONAL */
+    char *publicNote;              /* OPTIONAL */
+    char *reproductionNote;        /* OPTIONAL */
+    char *termsUseRepro;           /* OPTIONAL */
+    char *enumAndChron;            /* OPTIONAL */
+    int num_volumes;
+    Z_Volume **volumes;            /* OPTIONAL */
+    int num_circulationData;
+    Z_CircRecord **circulationData;/* OPTIONAL */
+} Z_HoldingsAndCircData;
+
+typedef struct Z_HoldingsRecord
+{
+    int which;
+#define Z_HoldingsRecord_marcHoldingsRecord    0
+#define Z_HoldingsRecord_holdingsAndCirc       1
+    union
+    {
+	Z_External *marcHoldingsRecord;
+	Z_HoldingsAndCircData *holdingsAndCirc;
+    } u;
+} Z_HoldingsRecord;
+
+typedef struct Z_OPACRecord
+{
+    Z_External *bibliographicRecord;   /* OPTIONAL */
+    int num_holdingsData;
+    Z_HoldingsRecord **holdingsData;   /* OPTIONAL */
+} Z_OPACRecord;
+
+YAZ_EXPORT int z_BriefBib(ODR o, Z_BriefBib **p, int opt, const char *name);
+YAZ_EXPORT int z_OPACRecord(ODR o, Z_OPACRecord **p, int opt,
+			    const char *name);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
Index: /main/tags/2.25/gsdl/packages/yaz/include/yaz/prt-dat.h
===================================================================
--- /main/tags/2.25/gsdl/packages/yaz/include/yaz/prt-dat.h	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/yaz/include/yaz/prt-dat.h	(revision 21064)
@@ -0,0 +1,154 @@
+/*
+ * This file is part of the YAZ toolkit:
+ * Copyright (c) 1998, Index Data.
+ * See the file LICENSE for details.
+ * Sebastian Hammer, Adam Dickmeiss
+ *
+ * Contribution by Ronald van Der Meer (RVDM):
+ *  Databasix Information Systems B.V., Utrecht, The Netherlands.
+ *
+ * $Log$
+ * Revision 1.1  2000/08/03 03:10:44  johnmcp
+ * Added the YAZ toolkit source to the packages directory (for z39.50 stuff)
+ *
+ * Revision 1.1  1999/11/30 13:47:11  adam
+ * Improved installation. Moved header files to include/yaz.
+ *
+ * Revision 1.2  1999/04/20 09:56:48  adam
+ * Added 'name' paramter to encoder/decoder routines (typedef Odr_fun).
+ * Modified all encoders/decoders to reflect this change.
+ *
+ * Revision 1.1  1998/02/10 15:31:52  adam
+ * Implemented date and time structure. Changed the Update Extended
+ * Service.
+ *
+ */
+
+#ifndef __PRT_DAT_H
+#define __PRT_DAT_H
+
+#include <yaz/yconfig.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef struct Z_MonthAndDay
+{
+    int *month;
+    int *day;                               /* OPTIONAL */
+} Z_MonthAndDay;
+
+typedef struct Z_Quarter
+{
+    int which;
+#define Z_Quarter_first		0
+#define Z_Quarter_second	1
+#define Z_Quarter_third		2
+#define Z_Quarter_fourth	3
+    union
+    {
+	Odr_null *first;
+	Odr_null *second;
+	Odr_null *third;
+	Odr_null *fourth;
+    } u;
+} Z_Quarter;
+
+typedef struct Z_Season
+{
+    int which;
+#define Z_Season_winter		0
+#define Z_Season_spring		1
+#define Z_Season_summer		2
+#define Z_Season_autumn		3
+    union
+    {
+	Odr_null *winter;
+	Odr_null *spring;
+	Odr_null *summer;
+	Odr_null *autumn;
+    } u;
+} Z_Season;
+
+typedef struct Z_PartOfYear
+{
+    int which;
+#define Z_PartOfYear_monthAndDay	0
+#define Z_PartOfYear_julianDay		1
+#define Z_PartOfYear_weekNumber		2
+#define Z_PartOfYear_quarter		3
+#define Z_PartOfYear_season		4
+    union
+    {
+	Z_MonthAndDay *monthAndDay;
+	int *julianDay; 
+	int *weekNumber; 
+	Z_Quarter *quarter;
+	Z_Season *season;
+    } u;
+} Z_PartOfYear;
+
+typedef struct Z_Era
+{
+    int which;
+#define Z_Era_decade		0
+#define Z_Era_century		1
+#define Z_Era_millennium	2
+    union
+    {
+	Odr_null *decade;
+	Odr_null *century;
+	Odr_null *millennium;
+    } u;
+} Z_Era;
+
+typedef struct Z_DateFlags
+{
+    Odr_null *circa;                        /* OPTIONAL */
+    Z_Era *era;                             /* OPTIONAL */
+} Z_DateFlags;
+
+typedef struct Z_Date
+{
+    int *year;
+    Z_PartOfYear *partOfYear;               /* OPTIONAL */
+    Z_DateFlags *flags;                     /* OPTIONAL */
+} Z_Date;
+
+typedef struct Z_Zone
+{
+    int which;
+#define Z_Zone_local		0
+#define Z_Zone_utc		1
+#define Z_Zone_utcOffset	2
+    union
+    {
+	Odr_null *local;
+	Odr_null *utc;
+	int *utcOffset;
+    } u;
+} Z_Zone;
+
+typedef struct Z_Time
+{
+    int *hour;
+    int *minute;                            /* OPTIONAL */
+    int *second;                            /* OPTIONAL */
+    Z_IntUnit *partOfSecond;                /* OPTIONAL */
+    Z_Zone *zone;                           /* OPTIONAL */
+} Z_Time;
+
+typedef struct Z_DateTime
+{
+    Z_Date *z3950Date;                      /* OPTIONAL */
+    Z_Time *z3950Time;                      /* OPTIONAL */
+} Z_DateTime;
+
+YAZ_EXPORT int z_DateTime(ODR o, Z_DateTime **p, int opt, const char *name);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
Index: /main/tags/2.25/gsdl/packages/yaz/include/yaz/prt-dia.h
===================================================================
--- /main/tags/2.25/gsdl/packages/yaz/include/yaz/prt-dia.h	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/yaz/include/yaz/prt-dia.h	(revision 21064)
@@ -0,0 +1,333 @@
+/*
+ * Copyright (c) 1995-1998, Index Data.
+ *
+ * Permission to use, copy, modify, distribute, and sell this software and
+ * its documentation, in whole or in part, for any purpose, is hereby granted,
+ * provided that:
+ *
+ * 1. This copyright and permission notice appear in all copies of the
+ * software and its documentation. Notices of copyright or attribution
+ * which appear at the beginning of any file must remain unchanged.
+ *
+ * 2. The names of Index Data or the individual authors may not be used to
+ * endorse or promote products derived from this software without specific
+ * prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED "AS IS" AND WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS, IMPLIED, OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY
+ * WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
+ * IN NO EVENT SHALL INDEX DATA BE LIABLE FOR ANY SPECIAL, INCIDENTAL,
+ * INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND, OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER OR
+ * NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF
+ * LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
+ * OF THIS SOFTWARE.
+ *
+ */
+
+#ifndef PRT_DIA_H
+#define PRT_DIA_H
+
+#include <yaz/yconfig.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef struct Z_TooMany
+{
+    int *tooManyWhat;
+#define Z_TooMany_argumentWords        1
+#define Z_TooMany_truncatedWords       2
+#define Z_TooMany_booleanOperators     3
+#define Z_TooMany_incompleteSubfields  4
+#define Z_TooMany_characters           5
+#define Z_TooMany_recordsRetrieved     6
+#define Z_TooMany_databasesSpecified   7
+#define Z_TooMany_resultSetsCreated    8
+#define Z_TooMany_indexTermsProcessed  9
+    int *max;                    /* OPTIONAL */
+} Z_TooMany;
+
+typedef struct Z_BadSpec
+{
+    Z_Specification *spec;
+    char *db;                    /* OPTIONAL */
+    int num_goodOnes;
+    Z_Specification **goodOnes;  /* OPTIONAL */
+} Z_BadSpec;
+
+typedef struct Z_DbUnavailWhy
+{
+    int *reasonCode;             /* OPTIONAL */
+#define Z_DbUnavail_doesNotExist         0
+#define Z_DbUnavail_existsButUnavail     1
+#define Z_DbUnavail_locked               2
+#define Z_DbUnavail_accessDenied         3
+    char *message;               /* OPTIONAL */
+} Z_DbUnavailWhy;
+
+typedef struct Z_DbUnavail
+{
+    char *db;
+    Z_DbUnavailWhy *why;         /* OPTIONAL */
+} Z_DbUnavail;
+
+typedef struct Z_Attribute
+{
+    Odr_oid *id;
+    int *type;                   /* OPTIONAL */
+    int *value;                  /* OPTIONAL */
+    Z_Term *term;                /* OPTIONAL */
+} Z_Attribute;
+
+typedef struct Z_AttCombo
+{
+    Z_AttributeList *unsupportedCombination;
+    int num_alternatives;
+    Z_AttributeList **alternatives;    /* OPTIONAL */
+} Z_AttCombo;
+
+typedef struct Z_DiagTerm 
+{
+    int *problem;                /* OPTIONAL */
+#define Z_DiagtermProb_codedValue     1
+#define Z_DiagtermProb_unparsable     2
+#define Z_DiagtermProb_tooShort       3
+#define Z_DiagtermProb_type           4
+    Z_Term *term;
+} Z_DiagTerm;
+
+typedef struct Z_Proximity
+{
+    int which;
+#define Z_Proximity_resultSets 0
+#define Z_Proximity_badSet 1
+#define Z_Proximity_relation 2
+#define Z_Proximity_unit 3
+#define Z_Proximity_distance 4
+#define Z_Proximity_attributes 5
+#define Z_Proximity_ordered 6
+#define Z_Proximity_exclusion 7
+    union
+    {
+	Odr_null *resultSets;
+	char *badSet;
+	int *relation;
+	int *unit;
+	int *distance;
+	Z_AttributeList *attributes;
+	Odr_null *ordered;
+	Odr_null *exclusion;
+    } u;
+} Z_Proximity;
+
+typedef struct Z_AttrListList
+{
+    int num_lists;
+    Z_AttributeList *lists;
+} Z_AttrListList;
+
+typedef struct Z_Scan
+{
+    int which;
+#define Z_ScanD_nonZeroStepSize 0
+#define Z_ScanD_specifiedStepSize 1
+#define Z_ScanD_termList1 2
+#define Z_ScanD_termList2 3
+#define Z_ScanD_posInResponse 4
+#define Z_ScanD_resources 5
+#define Z_ScanD_endOfList 6
+    union
+    {
+	Odr_null *nonZeroStepSize;
+	Odr_null *specifiedStepSize;
+	Odr_null *termList1;
+	Z_AttrListList *termList2;
+	int *posInResponse;
+#define Z_ScanPosInRsp_mustBeOne         1
+#define Z_ScanPosInRsp_mustBePositive    2
+#define Z_ScanPosInRsp_mustBeNonNegative 3
+#define Z_ScanPosInRsp_other             4
+	Odr_null *resources;
+	Odr_null *endOfList;
+    } u;
+} Z_Scan;
+
+typedef struct Z_Sort
+{
+    int which;
+#define Z_SortD_sequence 0
+#define Z_SortD_noRsName 1
+#define Z_SortD_tooMany 2
+#define Z_SortD_incompatible 3
+#define Z_SortD_generic 4
+#define Z_SortD_dbSpecific 5
+#define Z_SortD_sortElement 6
+#define Z_SortD_key 7
+#define Z_SortD_action 8
+#define Z_SortD_illegal 9
+#define Z_SortD_inputTooLarge 10
+#define Z_SortD_aggregateTooLarge 11
+    union
+    {
+	Odr_null *sequence;
+	Odr_null *noRsName;
+	int *tooMany;
+	Odr_null *incompatible;
+	Odr_null *generic;
+	Odr_null *dbSpecific;
+	int *key;
+#define Z_SortKey_tooMany       1
+#define Z_SortKey_duplicate     2
+	Odr_null *action;
+	int *illegal;
+#define Z_SortIllegal_relation  1
+#define Z_SortIllegal_case      2
+#define Z_SortIllegal_action    3
+#define Z_SortIllegal_sort      4
+	Z_StringList *inputTooLarge;
+	Odr_null *aggregateTooLarge;
+    } u;
+} Z_Sort;
+
+typedef struct Z_Segmentation
+{
+    int which;
+#define Z_SegmentationD_segments 0
+    union
+    {
+	Odr_null *segments;
+    } u;
+} Z_Segmentation;
+
+typedef struct Z_ExtServices
+{
+    int which;
+#define Z_ExtServicesD_req 0
+#define Z_ExtServicesD_permission 1
+#define Z_ExtServicesD_immediate 2
+    union
+    {
+	int *req;
+#define Z_ExtSrvReq_nameInUse           1
+#define Z_ExtSrvReq_noSuchname          2
+#define Z_ExtSrvReq_quota               3
+#define Z_ExtSrvReq_type                4
+	int *permission;
+#define Z_ExtSrvPerm_id                 1
+#define Z_ExtSrvPerm_modifyDelete       2
+	int *immediate;
+#define Z_ExtSrvImm_failed              1
+#define Z_ExtSrvImm_service             2
+#define Z_ExtSrvImm_parameters          3
+    } u;
+} Z_ExtServices;
+
+typedef struct Z_OidList
+{
+    int num_oids;
+    Odr_oid **oids;
+} Z_OidList;
+
+typedef struct Z_AccessCtrl
+{
+    int which;
+#define Z_AccessCtrlD_noUser 0
+#define Z_AccessCtrlD_refused 1
+#define Z_AccessCtrlD_simple 2
+#define Z_AccessCtrlD_oid 3
+#define Z_AccessCtrlD_alternative 4
+#define Z_AccessCtrlD_pwdInv 5
+#define Z_AccessCtrlD_pwdExp 6
+    union
+    {
+	Odr_null *noUser;
+	Odr_null *refused;
+	Odr_null *simple;
+	Z_OidList *oid;
+	Z_OidList *alternative;
+	Odr_null *pwdInv;
+	Odr_null *pwdExp;
+    } u;
+} Z_AccessCtrl;
+
+typedef struct Z_RecordSyntax
+{
+    Odr_oid *unsupportedSyntax;
+    int num_suggestedAlternatives;           /* OPTIONAL */
+    Odr_oid **suggestedAlternatives;           /* OPTIONAL */
+} Z_RecordSyntax;
+
+typedef struct Z_DiagFormat
+{
+    int which;
+#define Z_DiagFormat_tooMany 0
+#define Z_DiagFormat_badSpec 1
+#define Z_DiagFormat_dbUnavail 2
+#define Z_DiagFormat_unSupOp 3
+#define Z_DiagFormat_attribute 4
+#define Z_DiagFormat_attCombo 5
+#define Z_DiagFormat_term 6
+#define Z_DiagFormat_proximity 7
+#define Z_DiagFormat_scan 8
+#define Z_DiagFormat_sort 9
+#define Z_DiagFormat_segmentation 10
+#define Z_DiagFormat_extServices 11
+#define Z_DiagFormat_accessCtrl 12
+#define Z_DiagFormat_recordSyntax 13
+    union
+    {
+	Z_TooMany *tooMany;
+	Z_BadSpec *badSpec;
+	Z_DbUnavail *dbUnavail;
+	int *unSupOp;
+#define Z_UnSupOp_and             0
+#define Z_UnSupOp_or              1
+#define Z_UnSupOp_and_not         2
+#define Z_UnSupOp_prox            3
+	Z_Attribute *attribute;
+	Z_AttributeList *attCombo;
+	Z_DiagTerm *term;
+	Z_Proximity *proximity;
+	Z_Scan *scan;
+	Z_Sort *sort;
+	Z_Segmentation *segmentation;
+	Z_ExtServices *extServices;
+	Z_AccessCtrl *accessCtrl;
+	Z_RecordSyntax *recordSyntax;
+    } u;
+} Z_DiagFormat;
+
+typedef struct Z_Diagnostic
+{
+    int which;
+#define Z_Diagnostic_defaultDiagRec 0
+#define Z_Diagnostic_explicitDiagnostic 1
+    union 
+    {
+	Z_DefaultDiagFormat *defaultDiagRec;
+	Z_DiagFormat *explicitDiagnostic;
+    } u;
+} Z_Diagnostic;
+
+typedef struct Z_DiagnosticUnit
+{
+    Z_Diagnostic *diagnostic;                    /* OPTIONAL */
+    char *message;                               /* OPTIONAL */
+} Z_DiagnosticUnit;
+
+typedef struct Z_DiagnosticFormat
+{
+    int num_diagnostics;
+    Z_DiagnosticUnit **diagnostics;
+} Z_DiagnosticFormat;
+
+YAZ_EXPORT int z_DiagnosticFormat(ODR o, Z_DiagnosticFormat **p, int opt,
+				  const char *name);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
Index: /main/tags/2.25/gsdl/packages/yaz/include/yaz/prt-esp.h
===================================================================
--- /main/tags/2.25/gsdl/packages/yaz/include/yaz/prt-esp.h	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/yaz/include/yaz/prt-esp.h	(revision 21064)
@@ -0,0 +1,146 @@
+/*
+ * Copyright (c) 1995, Index Data.
+ *
+ * Permission to use, copy, modify, distribute, and sell this software and
+ * its documentation, in whole or in part, for any purpose, is hereby granted,
+ * provided that:
+ *
+ * 1. This copyright and permission notice appear in all copies of the
+ * software and its documentation. Notices of copyright or attribution
+ * which appear at the beginning of any file must remain unchanged.
+ *
+ * 2. The names of Index Data or the individual authors may not be used to
+ * endorse or promote products derived from this software without specific
+ * prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED "AS IS" AND WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS, IMPLIED, OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY
+ * WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
+ * IN NO EVENT SHALL INDEX DATA BE LIABLE FOR ANY SPECIAL, INCIDENTAL,
+ * INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND, OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER OR
+ * NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF
+ * LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
+ * OF THIS SOFTWARE.
+ *
+ */
+
+#ifndef PRT_ESP_H
+#define PRT_ESP_H
+
+#include <yaz/yconfig.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef struct Z_OccurValues
+{
+    int *start;
+    int *howMany;                     /* OPTIONAL */
+} Z_OccurValues;
+
+typedef struct Z_Occurrences
+{
+    int which;
+#define Z_Occurrences_all 0
+#define Z_Occurrences_last 1
+#define Z_Occurrences_values 2
+    union
+    {
+	Odr_null *all;
+	Odr_null *last;
+	Z_OccurValues *values;
+    } u;
+} Z_Occurrences;
+
+typedef struct Z_SpecificTag
+{
+    Odr_oid *schemaId;                      /* OPTIONAL */
+    int *tagType;                           /* OPTIONAL */
+    Z_StringOrNumeric *tagValue;
+    Z_Occurrences *occurrences;             /* OPTIONAL */
+} Z_SpecificTag;
+
+typedef struct Z_ETagUnit
+{
+    int which;
+#define Z_ETagUnit_specificTag 0
+#define Z_ETagUnit_wildThing 1
+#define Z_ETagUnit_wildPath 2
+    union
+    {
+	Z_SpecificTag *specificTag;
+	Z_Occurrences *wildThing;
+	Odr_null *wildPath;
+    } u;
+} Z_ETagUnit;
+
+typedef struct Z_ETagPath
+{
+    int num_tags;
+    Z_ETagUnit **tags;
+} Z_ETagPath;
+
+typedef struct Z_SimpleElement
+{
+    Z_ETagPath *path;
+    Z_Variant *variantRequest;           /* OPTIONAL */
+} Z_SimpleElement;
+
+typedef struct Z_CompoPrimitives
+{
+    int num_primitives;
+    char **primitives;
+} Z_CompoPrimitives;
+
+typedef struct Z_CompoSpecs
+{
+    int num_specs;
+    Z_SimpleElement **specs;
+} Z_CompoSpecs;
+
+typedef struct Z_CompositeElement
+{
+    int which;
+#define Z_CompoElement_primitives 0
+#define Z_CompoElement_specs 1
+    union
+    {
+	Z_CompoPrimitives *primitives;
+	Z_CompoSpecs *specs;
+    } elementList;
+    Z_ETagPath *deliveryTag;
+    Z_Variant *variantRequest;
+} Z_CompositeElement;
+
+typedef struct Z_ElementRequest
+{
+    int which;
+#define Z_ERequest_simpleElement 0
+#define Z_ERequest_compositeElement 1
+    union
+    {
+	Z_SimpleElement *simpleElement;
+	Z_CompositeElement *compositeElement;
+    } u;
+} Z_ElementRequest;
+
+typedef struct Z_Espec1
+{
+    int num_elementSetNames;
+    char **elementSetNames;               /* OPTIONAL */
+    Odr_oid *defaultVariantSetId;         /* OPTIONAL */
+    Z_Variant *defaultVariantRequest;     /* OPTIONAL */
+    int *defaultTagType;                  /* OPTIONAL */
+    int num_elements;
+    Z_ElementRequest **elements;           /* OPTIONAL */
+} Z_Espec1;
+
+YAZ_EXPORT int z_Espec1(ODR o, Z_Espec1 **p, int opt, const char *name);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
Index: /main/tags/2.25/gsdl/packages/yaz/include/yaz/prt-exd.h
===================================================================
--- /main/tags/2.25/gsdl/packages/yaz/include/yaz/prt-exd.h	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/yaz/include/yaz/prt-exd.h	(revision 21064)
@@ -0,0 +1,268 @@
+/*
+ * Copyright (c) 1995-1998, Index Data.
+ *
+ * Permission to use, copy, modify, distribute, and sell this software and
+ * its documentation, in whole or in part, for any purpose, is hereby granted,
+ * provided that:
+ *
+ * 1. This copyright and permission notice appear in all copies of the
+ * software and its documentation. Notices of copyright or attribution
+ * which appear at the beginning of any file must remain unchanged.
+ *
+ * 2. The names of Index Data or the individual authors may not be used to
+ * endorse or promote products derived from this software without specific
+ * prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED "AS IS" AND WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS, IMPLIED, OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY
+ * WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
+ * IN NO EVENT SHALL INDEX DATA BE LIABLE FOR ANY SPECIAL, INCIDENTAL,
+ * INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND, OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER OR
+ * NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF
+ * LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
+ * OF THIS SOFTWARE.
+ *
+ */
+
+#ifndef PRT_EXD_H
+#define PRT_EXD_H
+
+#include <yaz/yconfig.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef struct Z_TaskPackage
+{
+    Odr_oid *packageType;                 
+    char *packageName;                      /* OPTIONAL */
+    char *userId;                           /* OPTIONAL */
+    Z_IntUnit *retentionTime;               /* OPTIONAL */
+    Z_Permissions *permissions;             /* OPTIONAL */
+    char *description;                      /* OPTIONAL */
+    Odr_oct *targetReference;             
+    char *creationDateTime;    /* OPTIONAL */
+    int *taskStatus;                      
+#define Z_TaskPackage_pending             0
+#define Z_TaskPackage_active              1
+#define Z_TaskPackage_complete            2
+#define Z_TaskPackage_aborted             3
+    int num_packageDiagnostics;
+    Z_DiagRec **packageDiagnostics;         /* OPTIONAL */
+    Z_External *taskSpecificParameters;   
+} Z_TaskPackage;
+
+int z_TaskPackage(ODR o, Z_TaskPackage **p, int opt, const char *name);
+
+/* ----------------------- ITEM ORDER ------------------------- */
+
+typedef struct Z_IOTargetPart
+{
+    Z_External *itemRequest;                   /* OPTIONAL */
+    Z_External *statusOrErrorReport;
+    int *auxiliaryStatus;                      /* OPTIONAL */
+#define Z_IOTargetPart_notReceived        1
+#define Z_IOTargetPart_loanQueue          2
+#define Z_IOTargetPart_forwarded          3
+#define Z_IOTargetPart_unfilledCopyright  4
+#define Z_IOTargetPart_filledCopyright    1
+} Z_IOTargetPart;
+
+typedef struct Z_IOResultSetItem
+{
+    char *resultSetId;
+    int *item;
+} Z_IOResultSetItem;
+
+typedef struct Z_IOOriginPartNotToKeep
+{
+    Z_IOResultSetItem *resultSetItem;          /* OPTIONAL */
+    Z_External *itemRequest;                   /* OPTIONAL */
+} Z_IOOriginPartNotToKeep;
+
+typedef struct Z_IOContact
+{
+    char *name;                                /* OPTIONAL */
+    char *phone;                               /* OPTIONAL */
+    char *email;                               /* OPTIONAL */
+} Z_IOContact;
+
+typedef struct Z_IOCreditCardInfo
+{
+    char *nameOnCard;
+    char *expirationDate;
+    char *cardNumber;
+} Z_IOCreditCardInfo;
+
+typedef struct Z_IOBilling
+{
+    int which;
+#define Z_IOBilling_billInvoice 0
+#define Z_IOBilling_prepay 1
+#define Z_IOBilling_depositAccount 2
+#define Z_IOBilling_creditCard 3
+#define Z_IOBilling_cardInfoPreviouslySupplied 4
+#define Z_IOBilling_privateKnown 5
+#define Z_IOBilling_privateNotKnown 6
+    union
+    {
+	Odr_null *noinfo;
+	Z_IOCreditCardInfo *creditCard;
+	Z_External *privateNotKnown;
+    } paymentMethod;
+    char *customerReference;                        /* OPTIONAL */
+    char *customerPONumber;                         /* OPTIONAL */
+} Z_IOBilling;
+
+typedef struct Z_IOOriginPartToKeep
+{
+    Z_External *supplDescription;              /* OPTIONAL */
+    Z_IOContact *contact;                      /* OPTIONAL */
+    Z_IOBilling *addlBilling;                  /* OPTIONAL */
+} Z_IOOriginPartToKeep;
+
+typedef struct Z_IORequest
+{
+    Z_IOOriginPartToKeep *toKeep;              /* OPTIONAL */
+    Z_IOOriginPartNotToKeep *notToKeep;
+} Z_IORequest;
+
+typedef struct Z_IOTaskPackage
+{
+    Z_IOOriginPartToKeep *originPart;          /* OPTIONAL */
+    Z_IOTargetPart *targetPart;
+} Z_IOTaskPackage;
+
+typedef struct Z_ItemOrder
+{
+    int which;
+#define Z_ItemOrder_esRequest 0
+#define Z_ItemOrder_taskPackage 1
+    union
+    {
+	Z_IORequest *esRequest;
+	Z_IOTaskPackage *taskPackage;
+    } u;
+} Z_ItemOrder;
+
+int z_ItemOrder(ODR o, Z_ItemOrder **p, int opt, const char *name);
+
+/* ----------------------- ITEM UPDATE ------------------------ */
+
+typedef struct Z_IUSuppliedRecordsId
+{
+    int which;
+#define Z_IUSuppliedRecordsId_timeStamp 1
+#define Z_IUSuppliedRecordsId_versionNumber 2
+#define Z_IUSuppliedRecordsId_previousVersion 3
+    union {
+        char *timeStamp;
+        char *versionNumber;
+        Odr_external *previousVersion;
+    } u;
+} Z_IUSuppliedRecordsId;
+
+typedef struct Z_IUCorrelationInfo
+{
+    char *note; /* OPTIONAL */
+    int *id; /* OPTIONAL */
+} Z_IUCorrelationInfo;
+
+typedef struct Z_IUSuppliedRecords_elem
+{
+    int which;
+#define Z_IUSuppliedRecords_number 1
+#define Z_IUSuppliedRecords_string 2
+#define Z_IUSuppliedRecords_opaque 3
+    union {
+        int *number;
+        char *string;
+        Odr_oct *opaque;
+    } u; /* OPTIONAL */
+    Z_IUSuppliedRecordsId *supplementalId; /* OPTIONAL */
+    Z_IUCorrelationInfo *correlationInfo;    /* OPTIONAL */
+    Z_External *record;
+} Z_IUSuppliedRecords_elem;
+
+typedef struct Z_IUSuppliedRecords
+{
+    int num;
+    Z_IUSuppliedRecords_elem **elements;
+} Z_IUSuppliedRecords;
+
+typedef struct Z_IUOriginPartToKeep
+{
+    int *action;
+#define Z_IUOriginPartToKeep_recordInsert 1
+#define Z_IUOriginPartToKeep_recordReplace 2
+#define Z_IUOriginPartToKeep_recordDelete 3
+#define Z_IUOriginPartToKeep_elementUpdate 4
+#define Z_IUOriginPartToKeep_specialUpdate 5
+    char *databaseName;
+    Odr_oid *schema;               /* OPTIONAL */
+    char *elementSetName;          /* OPTIONAL */
+    Odr_external *actionQualifier; /* OPTIONAL */
+} Z_IUOriginPartToKeep;
+
+typedef struct Z_IUTaskPackageRecordStructure
+{
+    int which;
+#define Z_IUTaskPackageRecordStructure_record 1
+#define Z_IUTaskPackageRecordStructure_surrogateDiagnostics 2
+    union {
+        Odr_external *record;
+        Z_DiagRecs *surrogateDiagnostics;
+    } u; /* OPTIONAL */
+    Z_IUCorrelationInfo *correlationInfo; /* OPTIONAL */
+    int *recordStatus;
+#define Z_IUTaskPackageRecordStructureS_success 1
+#define Z_IUTaskPackageRecordStructureS_queued 2
+#define Z_IUTaskPackageRecordStructureS_inProcess 3
+#define Z_IUTaskPackageRecordStructureS_failure 4
+    Z_DiagRecs *supplementalDiagnostics;  /* OPTIONAL */
+} Z_IUTaskPackageRecordStructure;
+
+typedef struct Z_IUTargetPart
+{
+    int *updateStatus;
+#define Z_IUTargetPart_success 1
+#define Z_IUTargetPart_partial 2
+#define Z_IUTargetPart_failure 3
+    int num_globalDiagnostics;
+    Z_DiagRec **globalDiagnostics; /* OPTIONAL */
+    int num_taskPackageRecords;
+    Z_IUTaskPackageRecordStructure **taskPackageRecords;
+} Z_IUTargetPart;
+
+typedef struct Z_IUUpdateEsRequest
+{
+    Z_IUOriginPartToKeep *toKeep;
+    Z_IUSuppliedRecords *notToKeep;
+} Z_IUUpdateEsRequest;
+
+typedef struct Z_IUUpdateTaskPackage
+{
+    Z_IUOriginPartToKeep *originPart;
+    Z_IUTargetPart *targetPart;
+} Z_IUUpdateTaskPackage;
+
+typedef struct Z_IUUpdate
+{
+    int which;
+#define Z_IUUpdate_esRequest 1
+#define Z_IUUpdate_taskPackage 2
+    union {
+        Z_IUUpdateEsRequest *esRequest;
+        Z_IUUpdateTaskPackage *taskPackage;
+    } u;
+} Z_IUUpdate;
+
+YAZ_EXPORT int z_IUUpdate(ODR o, Z_IUUpdate **p, int opt, const char *name);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
Index: /main/tags/2.25/gsdl/packages/yaz/include/yaz/prt-exp.h
===================================================================
--- /main/tags/2.25/gsdl/packages/yaz/include/yaz/prt-exp.h	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/yaz/include/yaz/prt-exp.h	(revision 21064)
@@ -0,0 +1,1017 @@
+/*
+ * Copyright (c) 1995-1998, Index Data.
+ *
+ * Permission to use, copy, modify, distribute, and sell this software and
+ * its documentation, in whole or in part, for any purpose, is hereby granted,
+ * provided that:
+ *
+ * 1. This copyright and permission notice appear in all copies of the
+ * software and its documentation. Notices of copyright or attribution
+ * which appear at the beginning of any file must remain unchanged.
+ *
+ * 2. The names of Index Data or the individual authors may not be used to
+ * endorse or promote products derived from this software without specific
+ * prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED "AS IS" AND WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS, IMPLIED, OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY
+ * WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
+ * IN NO EVENT SHALL INDEX DATA BE LIABLE FOR ANY SPECIAL, INCIDENTAL,
+ * INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND, OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER OR
+ * NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF
+ * LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
+ * OF THIS SOFTWARE.
+ *
+ */
+
+#ifndef PRT_EXP_H
+#define PRT_EXP_H
+
+#include <yaz/yconfig.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef struct Z_CommonInfo
+{
+    char *dateAdded;           /* OPTIONAL */
+    char *dateChanged;         /* OPTIONAL */
+    char *expiry;              /* OPTIONAL */
+    char *humanStringLanguage;    /* OPTIONAL */
+    Z_OtherInformation *otherInfo;          /* OPTIONAL */
+} Z_CommonInfo;
+
+typedef struct Z_HumanStringUnit
+{
+    char *language;               /* OPTIONAL */
+    char *text;
+} Z_HumanStringUnit;
+
+typedef struct Z_HumanString
+{
+    int num_strings;
+    Z_HumanStringUnit **strings;
+} Z_HumanString;
+
+typedef struct Z_IconObjectUnit
+{
+    int which;
+#define Z_IconObjectUnit_ianaType 0
+#define Z_IconObjectUnit_z3950type 1
+#define Z_IconObjectUnit_otherType 2
+    char *bodyType;
+    Odr_oct *content;
+} Z_IconObjectUnit;
+
+typedef struct Z_IconObject
+{
+    int num;
+    Z_IconObjectUnit **elements;
+} Z_IconObject;
+
+typedef struct Z_ContactInfo
+{
+    char *name;                             /* OPTIONAL */
+    Z_HumanString *description;             /* OPTIONAL */
+    Z_HumanString *address;                 /* OPTIONAL */
+    char *email;                            /* OPTIONAL */
+    char *phone;                            /* OPTIONAL */
+} Z_ContactInfo;
+
+typedef struct Z_NetworkAddressIA
+{
+    char *hostAddress;
+    int *port;
+} Z_NetworkAddressIA;
+
+typedef struct Z_NetworkAddressOPA
+{
+    char *pSel;
+    char *sSel;                  /* OPTIONAL */
+    char *tSel;                  /* OPTIONAL */
+    char *nSap;
+} Z_NetworkAddressOPA;
+
+typedef struct Z_NetworkAddressOther
+{
+    char *type;
+    char *address;
+} Z_NetworkAddressOther;
+
+typedef struct Z_NetworkAddress
+{
+    int which;
+#define Z_NetworkAddress_iA 0
+#define Z_NetworkAddress_oPA 1
+#define Z_NetworkAddress_other 2
+    union
+    {
+    	Z_NetworkAddressIA *internetAddress;
+	Z_NetworkAddressOPA *osiPresentationAddress;
+	Z_NetworkAddressOther *other;
+    } u;
+} Z_NetworkAddress;
+
+typedef struct Z_PrivateCapOperator
+{
+    char *roperator;
+    Z_HumanString *description;             /* OPTIONAL */
+} Z_PrivateCapOperator;
+    
+typedef struct Z_SearchKey
+{
+    char *searchKey;
+    Z_HumanString *description;             /* OPTIONAL */
+} Z_SearchKey;
+
+typedef struct Z_PrivateCapabilities
+{
+    int num_operators;
+    Z_PrivateCapOperator **operators;      /* OPTIONAL */
+    int num_searchKeys;
+    Z_SearchKey **searchKeys;               /* OPTIONAL */
+    int num_description;
+    Z_HumanString **description;            /* OPTIONAL */
+} Z_PrivateCapabilities;
+
+typedef struct Z_ProxSupportPrivate
+{
+    int *unit;
+    Z_HumanString *description;             /* OPTIONAL */
+} Z_ProxSupportPrivate;
+
+typedef struct Z_ProxSupportUnit
+{
+    int which;
+#define Z_ProxSupportUnit_known 0
+#define Z_ProxSupportUnit_private 1
+    union
+    {
+    	int *known;
+	Z_ProxSupportPrivate *zprivate;
+    } u;
+} Z_ProxSupportUnit;
+
+typedef struct Z_ProximitySupport
+{
+    bool_t *anySupport;
+    int num_unitsSupported;
+    Z_ProxSupportUnit **unitsSupported;     /* OPTIONAL */
+} Z_ProximitySupport;
+
+typedef struct Z_RpnCapabilities
+{
+    int num_operators;
+    int **operators;                        /* OPTIONAL */
+    bool_t *resultSetAsOperandSupported;
+    bool_t *restrictionOperandSupported;
+    Z_ProximitySupport *proximity;          /* OPTIONAL */
+} Z_RpnCapabilities;
+
+typedef struct Z_Iso8777Capabilities
+{
+    int num_searchKeys;
+    Z_SearchKey **searchKeys;
+    Z_HumanString *restrictions;            /* OPTIONAL */
+} Z_Iso8777Capabilities;
+
+typedef struct Z_QueryTypeDetails
+{
+    int which;
+#define Z_QueryTypeDetails_private 0
+#define Z_QueryTypeDetails_rpn 1
+#define Z_QueryTypeDetails_iso8777 2
+#define Z_QueryTypeDetails_z39_58 3
+#define Z_QueryTypeDetails_erpn 4
+#define Z_QueryTypeDetails_rankedList 5
+    union
+    {
+	Z_PrivateCapabilities *zprivate;
+	Z_RpnCapabilities *rpn;
+	Z_Iso8777Capabilities *iso8777;
+	Z_HumanString *z3958;
+	Z_RpnCapabilities *erpn;
+	Z_HumanString *rankedList;
+    } u;
+} Z_QueryTypeDetails;
+
+typedef struct Z_AccessRestrictionsUnit
+{
+    int *accessType;
+#define Z_AccessRestrictionsUnit_any                 0
+#define Z_AccessRestrictionsUnit_search              1
+#define Z_AccessRestrictionsUnit_present             2
+#define Z_AccessRestrictionsUnit_specific_elements   3
+#define Z_AccessRestrictionsUnit_extended_services   4
+#define Z_AccessRestrictionsUnit_by_database         5
+    Z_HumanString *accessText;              /* OPTIONAL */
+    int num_accessChallenges;
+    Odr_oid **accessChallenges;             /* OPTIONAL */
+} Z_AccessRestrictionsUnit;
+
+typedef struct Z_AccessRestrictions
+{
+    int num;
+    Z_AccessRestrictionsUnit **elements;
+} Z_AccessRestrictions;
+
+typedef struct Z_Charge
+{
+    Z_IntUnit *cost;
+    Z_Unit *perWhat;                        /* OPTIONAL */
+    Z_HumanString *text;                    /* OPTIONAL */
+} Z_Charge;
+
+typedef struct Z_CostsOtherCharge
+{
+    Z_HumanString *forWhat;
+    Z_Charge *charge;
+} Z_CostsOtherCharge;
+
+typedef struct Z_Costs
+{
+    Z_Charge *connectCharge;                /* OPTIONAL */
+    Z_Charge *connectTime;                  /* OPTIONAL */
+    Z_Charge *displayCharge;                /* OPTIONAL */
+    Z_Charge *searchCharge;                 /* OPTIONAL */
+    Z_Charge *subscriptCharge;              /* OPTIONAL */
+    int num_otherCharges;
+    Z_CostsOtherCharge **otherCharges;      /* OPTIONAL */
+} Z_Costs;
+
+typedef struct Z_AccessInfo
+{
+    int num_queryTypesSupported;
+    Z_QueryTypeDetails **queryTypesSupported;  /* OPTIONAL */
+    int num_diagnosticsSets;
+    Odr_oid **diagnosticsSets;              /* OPTIONAL */
+    int num_attributeSetIds;
+    Odr_oid **attributeSetIds;     /* OPTIONAL */
+    int num_schemas;
+    Odr_oid **schemas;                      /* OPTIONAL */
+    int num_recordSyntaxes;
+    Odr_oid **recordSyntaxes;               /* OPTIONAL */
+    int num_resourceChallenges;
+    Odr_oid **resourceChallenges;           /* OPTIONAL */
+    Z_AccessRestrictions *restrictedAccess;  /* OPTIONAL */
+    Z_Costs *costInfo;                      /* OPTIONAL */
+    int num_variantSets;
+    Odr_oid **variantSets;                  /* OPTIONAL */
+    int num_elementSetNames;
+    char **elementSetNames;     /* OPTIONAL */
+    int num_unitSystems;
+    char **unitSystems;                     /* OPTIONAL */
+} Z_AccessInfo;
+
+typedef struct Z_DatabaseList
+{
+    int num_databases;
+    Z_DatabaseName **databases;
+} Z_DatabaseList;
+
+typedef struct Z_AttributeValueList
+{
+    int num_attributes;
+    Z_StringOrNumeric **attributes;
+} Z_AttributeValueList;
+
+typedef struct Z_AttributeOccurrence
+{
+    Odr_oid *attributeSet;         /* OPTIONAL */
+    int *attributeType;
+    Odr_null *mustBeSupplied;               /* OPTIONAL */
+    int which;
+#define Z_AttributeOcc_any_or_none 0
+#define Z_AttributeOcc_specific 1
+    union
+    {
+	Odr_null *any_or_none;
+	Z_AttributeValueList *specific;
+    } attributeValues;
+} Z_AttributeOccurrence;
+
+typedef struct Z_AttributeCombination
+{
+    int num_occurrences;
+    Z_AttributeOccurrence **occurrences;
+} Z_AttributeCombination;
+
+typedef struct Z_AttributeCombinations
+{
+    Odr_oid *defaultAttributeSet;
+    int num_legalCombinations;
+    Z_AttributeCombination **legalCombinations;
+} Z_AttributeCombinations;
+
+typedef struct Z_AttributeValue
+{
+    Z_StringOrNumeric *value;
+    Z_HumanString *description;             /* OPTIONAL */
+    int num_subAttributes;
+    Z_StringOrNumeric **subAttributes;      /* OPTIONAL */
+    int num_superAttributes;
+    Z_StringOrNumeric **superAttributes;    /* OPTIONAL */
+    Odr_null *partialSupport;               /* OPTIONAL */
+} Z_AttributeValue;
+
+typedef struct Z_TargetInfo
+{
+    Z_CommonInfo *commonInfo;               /* OPTIONAL */
+    /*
+     * key elements
+     */
+    char *name;
+    /*
+     * non-key brief elements
+     */
+    Z_HumanString *recentNews;             /* OPTIONAL */
+    Z_IconObject *icon;                     /* OPTIONAL */
+    bool_t *namedResultSets;
+    bool_t *multipleDBsearch;
+    int *maxResultSets;                     /* OPTIONAL */
+    int *maxResultSize;                     /* OPTIONAL */
+    int *maxTerms;                          /* OPTIONAL */
+    Z_IntUnit *timeoutInterval;             /* OPTIONAL */
+    Z_HumanString *welcomeMessage;          /* OPTIONAL */
+    /*
+     * non-brief elements
+     */
+    Z_ContactInfo *contactInfo;             /* OPTIONAL */
+    Z_HumanString *description;             /* OPTIONAL */
+    int num_nicknames;
+    char **nicknames;
+    Z_HumanString *usageRest;              /* OPTIONAL */
+    Z_HumanString *paymentAddr;             /* OPTIONAL */
+    Z_HumanString *hours;                   /* OPTIONAL */
+    int num_dbCombinations;
+    Z_DatabaseList **dbCombinations;        /* OPTIONAL */
+    int num_addresses;
+    Z_NetworkAddress **addresses;           /* OPTIONAL */
+    int num_languages;
+    char **languages;                       /* OPTIONAL */
+
+    Z_AccessInfo *commonAccessInfo;         /* OPTIONAL */
+} Z_TargetInfo;
+
+typedef struct Z_DatabaseInfo
+{
+    Z_CommonInfo *commonInfo;               /* OPTIONAL */
+    /*
+     * Key elements
+     */
+    Z_DatabaseName *name;
+    /* 
+     * Non-key elements.
+     */
+    Odr_null *explainDatabase;              /* OPTIONAL */
+    int num_nicknames;
+    Z_DatabaseName **nicknames;             /* OPTIONAL */
+    Z_IconObject *icon;                     /* OPTIONAL */
+    bool_t *userFee;
+    bool_t *available;
+    Z_HumanString *titleString;             /* OPTIONAL */
+    /*
+     * Non-brief elements.
+     */
+    int num_keywords;
+    Z_HumanString **keywords;               /* OPTIONAL */
+    Z_HumanString *description;             /* OPTIONAL */
+    Z_DatabaseList *associatedDbs;          /* OPTIONAL */
+    Z_DatabaseList *subDbs;                 /* OPTIONAL */
+    Z_HumanString *disclaimers;             /* OPTIONAL */
+    Z_HumanString *news;                    /* OPTIONAL */
+
+#if 1
+    int which;
+    union {
+	int *actualNumber;
+	int *approxNumber;
+#define Z_DatabaseInfo_actualNumber 1
+#define Z_DatabaseInfo_approxNumber 2
+    } u; /* OPT */
+
+#else
+    int recordCount_which;
+#define Z_DatabaseInfo_actualNumber 0
+#define Z_DatabaseInfo_approxNumber 1
+    int *recordCount;                       /* OPTIONAL */
+#endif
+    Z_HumanString *defaultOrder;            /* OPTIONAL */
+    int *avRecordSize;                      /* OPTIONAL */
+    int *maxRecordSize;                     /* OPTIONAL */
+    Z_HumanString *hours;                   /* OPTIONAL */
+    Z_HumanString *bestTime;                /* OPTIONAL */
+    char *lastUpdate;          /* OPTIONAL */
+    Z_IntUnit *updateInterval;              /* OPTIONAL */
+    Z_HumanString *coverage;                /* OPTIONAL */
+    bool_t *proprietary;                    /* OPTIONAL */
+    Z_HumanString *copyrightText;           /* OPTIONAL */
+    Z_HumanString *copyrightNotice;         /* OPTIONAL */
+    Z_ContactInfo *producerContactInfo;     /* OPTIONAL */
+    Z_ContactInfo *supplierContactInfo;     /* OPTIONAL */
+    Z_ContactInfo *submissionContactInfo;   /* OPTIONAL */
+    Z_AccessInfo *accessInfo;               /* OPTIONAL */
+} Z_DatabaseInfo;
+
+typedef struct Z_TagTypeMapping
+{
+    int *tagType;
+    Odr_oid *tagSet;                        /* OPTIONAL */
+    Odr_null *defaultTagType;               /* OPTIONAL */
+} Z_TagTypeMapping;
+
+typedef struct Z_PathUnit
+{
+    int *tagType;
+    Z_StringOrNumeric *tagValue;
+} Z_PathUnit;
+
+typedef struct Z_Path
+{
+    int num;
+    Z_PathUnit **list;
+} Z_Path;
+
+struct Z_ElementDataType;
+typedef struct Z_ElementDataType Z_ElementDataType;
+
+typedef struct Z_ElementInfo
+{
+    char *elementName;
+    Z_Path *elementTagPath;
+    Z_ElementDataType *dataType;            /* OPTIONAL */
+    bool_t *required;
+    bool_t *repeatable;
+    Z_HumanString *description;             /* OPTIONAL */
+} Z_ElementInfo;
+
+typedef struct Z_ElementInfoList
+{
+    int num;
+    Z_ElementInfo **list;
+} Z_ElementInfoList;
+
+struct Z_ElementDataType
+{
+    int which;
+#define Z_ElementDataType_primitive 0
+#define Z_ElementDataType_structured 1
+    union
+    {
+    	int *primitive;
+#define Z_PrimitiveDataType_octetString         0
+#define Z_PrimitiveDataType_numeric             1
+#define Z_PrimitiveDataType_date                2
+#define Z_PrimitiveDataType_external            3
+#define Z_PrimitiveDataType_string              4
+#define Z_PrimitiveDataType_trueOrFalse         5
+#define Z_PrimitiveDataType_oid                 6
+#define Z_PrimitiveDataType_intUnit             7
+#define Z_PrimitiveDataType_empty               8
+#define Z_PrimitiveDataType_noneOfTheAbove      100
+	Z_ElementInfoList *structured;
+    } u;
+};
+
+typedef struct Z_TagSetInfoElements
+{
+    char *elementname;
+    int num_nicknames;
+    char **nicknames;                       /* OPTIONAL */
+    Z_StringOrNumeric *elementTag;
+    Z_HumanString *description;             /* OPTIONAL */
+    int *dataType;                          /* OPTIONAL */
+    /* (value as in Z_PrimitiveElement) */
+    Z_OtherInformation *otherTagInfo;       /* OPTIONAL */
+} Z_TagSetInfoElements;
+
+typedef struct Z_SchemaInfo
+{
+    Z_CommonInfo *commonInfo;               /* OPTIONAL */
+    /*
+     * Key elements
+     */
+    Odr_oid *schema;
+    /*
+     * Non-key elements
+     */
+    char *name;
+    /*
+     * Non-brief elements
+     */
+    Z_HumanString *description;             /* OPTIONAL */
+    int num_tagTypeMapping;
+    Z_TagTypeMapping **tagTypeMapping;      /* OPTIONAL */
+    int num_recordStructure;
+    Z_ElementInfo **recordStructure;        /* OPTIONAL */
+} Z_SchemaInfo;
+
+
+typedef struct Z_TagSetInfo
+{
+    Z_CommonInfo *commonInfo;               /* OPTIONAL */
+    /*
+     * Key elements
+     */
+    Odr_oid *tagSet;
+    /*
+     * Non-key elements
+     */
+    char *name;
+    /*
+     * Non-brief elements
+     */
+    Z_HumanString *description;             /* OPTIONAL */
+    int num_elements;
+    Z_TagSetInfoElements **elements;        /* OPTIONAL */
+} Z_TagSetInfo;
+
+typedef struct Z_RecordSyntaxInfo
+{
+    Z_CommonInfo *commonInfo;               /* OPTIONAL */
+    /*
+     * Key elements
+     */
+    Odr_oid *recordSyntax;
+    /*
+     * Non-key elements
+     */
+    char *name;
+    /*
+     * Non-brief elements
+     */
+    int num_transferSyntaxes;
+    Odr_oid **transferSyntaxes;             /* OPTIONAL */
+    Z_HumanString *description;             /* OPTIONAL */
+    char *asn1Module;                       /* OPTIONAL */
+    int num_abstractStructure;
+    Z_ElementInfo **abstractStructure;      /* OPTIONAL */
+} Z_RecordSyntaxInfo;
+
+typedef struct Z_AttributeDescription
+{
+    char *name;                             /* OPTIONAL */
+    Z_HumanString *description;             /* OPTIONAL */
+    Z_StringOrNumeric *attributeValue;
+    int num_equivalentAttributes;
+    Z_StringOrNumeric **equivalentAttributes; /* OPTIONAL */
+} Z_AttributeDescription;
+
+typedef struct Z_AttributeType
+{
+    char *name;                             /* OPTIONAL */
+    Z_HumanString *description;             /* OPTIONAL */
+    int *attributeType;
+    int num_attributeValues;
+    Z_AttributeDescription **attributeValues;
+} Z_AttributeType;
+
+typedef struct Z_AttributeSetInfo
+{
+    Z_CommonInfo *commonInfo;               /* OPTIONAL */
+    /*
+     * Key elements
+     */
+    Odr_oid *attributeSet;
+    /*
+     * Non-key elements
+     */
+    char *name;
+    /*
+     * Non-brief elements
+     */
+    int num_attributes;
+    Z_AttributeType **attributes;           /* OPTIONAL */
+    Z_HumanString *description;             /* OPTIONAL */
+} Z_AttributeSetInfo;
+
+typedef struct Z_TermListElement
+{
+    char *name;
+    Z_HumanString *title;                   /* OPTIONAL */
+    int *searchCost;                        /* OPTIONAL */
+#define Z_TermListElement_optimized           0
+#define Z_TermListElement_normal              1
+#define Z_TermListElement_expensive           2
+#define Z_TermListElement_filter              3
+    bool_t *scanable;
+    int num_broader;
+    char **broader;                         /* OPTIONAL */
+    int num_narrower;
+    char **narrower;                        /* OPTIONAL */
+} Z_TermListElement;
+
+typedef struct Z_TermListInfo
+{
+    Z_CommonInfo *commonInfo;               /* OPTIONAL */
+    /*
+     * Key elements
+     */
+    Z_DatabaseName *databaseName;
+    /*
+     * Non-key elements
+     */
+    int num_termLists;
+    Z_TermListElement **termLists;
+} Z_TermListInfo;
+
+typedef struct Z_ExtendedServicesInfo
+{
+    Z_CommonInfo *commonInfo;               /* OPTIONAL */
+    /*
+     * Key elements
+     */
+    Odr_oid *type;
+    /*
+     * Non-key elements
+     */
+    char *name;                             /* OPTIONAL */
+    bool_t *privateType;
+    bool_t *restrictionsApply;
+    bool_t *feeApply;
+    bool_t *available;
+    bool_t *retentionSupported;
+    int *waitAction;
+#define Z_ExtendedServicesInfo_waitSupported       1
+#define Z_ExtendedServicesInfo_waitAlways          2
+#define Z_ExtendedServicesInfo_waitNotSupported    3
+#define Z_ExtendedServicesInfo_depends             4
+#define Z_ExtendedServicesInfo_notSaying           5
+    /*
+     * Non-brief elements
+     */
+    Z_HumanString *description;             /* OPTIONAL */
+    Z_External *specificExplain;          /* OPTIONAL */
+    char *esASN;                            /* OPTIONAL */
+} Z_ExtendedServicesInfo;
+
+typedef struct Z_OmittedAttributeInterpretation
+{
+    Z_StringOrNumeric *defaultValue;        /* OPTIONAL */
+    Z_HumanString *defaultDescription;      /* OPTIONAL */
+} Z_OmittedAttributeInterpretation;
+
+typedef struct Z_AttributeTypeDetails
+{
+    int *attributeType;
+    Z_OmittedAttributeInterpretation *defaultIfOmitted;  /* OPTIONAL */
+    int num_attributeValues;
+    Z_AttributeValue **attributeValues;     /* OPTIONAL */
+} Z_AttributeTypeDetails;
+
+typedef struct Z_AttributeSetDetails
+{
+    Odr_oid *attributeSet;
+    int num_attributesByType;
+    Z_AttributeTypeDetails **attributesByType;
+} Z_AttributeSetDetails;
+
+typedef struct Z_AttributeDetails
+{
+    Z_CommonInfo *commonInfo;               /* OPTIONAL */
+    /*
+     * Key details
+     */
+    Z_DatabaseName *databaseName;
+    /*
+     * Non-brief elements
+     */
+    int num_attributesBySet;
+    Z_AttributeSetDetails **attributesBySet;  /* OPTIONAL */
+    Z_AttributeCombinations *attributeCombinations;  /* OPTIONAL */
+} Z_AttributeDetails;
+
+typedef struct Z_EScanInfo
+{
+    int *maxStepSize;                       /* OPTIONAL */
+    Z_HumanString *collatingSequence;       /* OPTIONAL */
+    bool_t *increasing;                     /* OPTIONAL */
+} Z_EScanInfo;
+
+typedef struct Z_TermListDetails
+{
+    Z_CommonInfo *commonInfo;               /* OPTIONAL */
+    /*
+     * Key elements
+     */
+    char *termListName;
+    /*
+     * Non-brief elements
+     */
+    Z_HumanString *description;             /* OPTIONAL */
+    Z_AttributeCombinations *attributes;    /* OPTIONAL */
+    Z_EScanInfo *scanInfo;                  /* OPTIONAL */
+    int *estNumberTerms;                    /* OPTIONAL */
+    int num_sampleTerms;
+    Z_Term **sampleTerms;                   /* OPTIONAL */
+} Z_TermListDetails;
+
+typedef struct Z_RecordTag
+{
+    Z_StringOrNumeric *qualifier;           /* OPTIONAL */
+    Z_StringOrNumeric *tagValue;
+} Z_RecordTag;
+
+typedef struct Z_PerElementDetails
+{
+    char *name;                             /* OPTIONAL */
+    Z_RecordTag *recordTag;                 /* OPTIONAL */
+    int num_schemaTags;
+    Z_Path **schemaTags;                    /* OPTIONAL */
+    int *maxSize;                           /* OPTIONAL */
+    int *minSize;                           /* OPTIONAL */
+    int *avgSize;                           /* OPTIONAL */
+    int *fixedSize;                         /* OPTIONAL */
+    bool_t *repeatable;
+    bool_t *required;
+    Z_HumanString *description;             /* OPTIONAL */
+    Z_HumanString *contents;                /* OPTIONAL */
+    Z_HumanString *billingInfo;             /* OPTIONAL */
+    Z_HumanString *restrictions;            /* OPTIONAL */
+    int num_alternateNames;
+    char **alternateNames;                  /* OPTIONAL */
+    int num_genericNames;
+    char **genericNames;                    /* OPTIONAL */
+    Z_AttributeCombinations *searchAccess;  /* OPTIONAL */
+} Z_PerElementDetails;
+
+typedef struct Z_ElementSetDetails
+{
+    Z_CommonInfo *commonInfo;               /* OPTIONAL */
+    /*
+     * Key elements
+     */
+    Z_DatabaseName *databaseName;
+    char *elementSetName;
+    Odr_oid *recordSyntax;
+    /*
+     * Brief elements
+     */
+    Odr_oid *schema;
+    /*
+     * Non-brief elements
+     */
+    Z_HumanString *description;             /* OPTIONAL */
+    int num_detailsPerElement;
+    Z_PerElementDetails **detailsPerElement;  /* OPTIONAL */
+} Z_ElementSetDetails;
+
+typedef struct Z_RetrievalRecordDetails
+{
+    Z_CommonInfo *commonInfo;               /* OPTIONAL */
+    /*
+     * Key elements
+     */
+    Z_DatabaseName *databaseName;
+    Odr_oid *schema;
+    Odr_oid *recordSyntax;
+    /*
+     * Non-brief elements
+     */
+    Z_HumanString *description;             /* OPTIONAL */
+    int num_detailsPerElement;
+    Z_PerElementDetails **detailsPerElement;  /* OPTIONAL */
+} Z_RetrievalRecordDetails;
+
+typedef struct Z_SortKeyDetails
+{
+    Z_HumanString *description;                        /* OPTIONAL */
+    int num_elementSpecifications;
+    Z_Specification **elementSpecifications;           /* OPTIONAL */
+    Z_AttributeCombinations *attributeSpecifications;  /* OPTIONAL */
+    int which;
+#define Z_SortKeyDetails_character 0
+#define Z_SortKeyDetails_numeric 1
+#define Z_SortKeyDetails_structured 2
+    union
+    {
+	Odr_null *character;
+	Odr_null *numeric;
+	Z_HumanString *structured;
+    } u;
+    int *caseSensitivity;                              /* OPTIONAL */
+#define Z_SortKeyDetails_always              0
+#define Z_SortKeyDetails_never               1
+#define Z_SortKeyDetails_default_yes         2
+#define Z_SortKeyDetails_default_no          3
+} Z_SortKeyDetails;
+
+typedef struct Z_SortDetails
+{
+    Z_CommonInfo *commonInfo;               /* OPTIONAL */
+    /*
+     * Key elements
+     */
+    Z_DatabaseName *databaseName;
+    /* 
+     * Non-brief elements
+     */
+    int num_sortKeys;
+    Z_SortKeyDetails **sortKeys;            /* OPTIONAL */
+} Z_SortDetails;
+
+typedef struct Z_ProcessingInformation
+{
+    Z_CommonInfo *commonInfo;               /* OPTIONAL */
+    /*
+     * Key elements
+     */
+    Z_DatabaseName *databaseName;
+    int *processingContext;
+#define Z_ProcessingInformation_access               0
+#define Z_ProcessingInformation_search               1
+#define Z_ProcessingInformation_retrieval            2
+#define Z_ProcessingInformation_record_presentation  3
+#define Z_ProcessingInformation_record_handling      4
+    char *name;
+    Odr_oid *oid;
+    /*
+     * Non-brief elements
+     */
+    Z_HumanString *description;             /* OPTIONAL */
+    Z_External *instructions;             /* OPTIONAL */
+} Z_ProcessingInformation;
+
+typedef struct Z_ValueDescription
+{
+    int which;
+#define Z_ValueDescription_integer 0
+#define Z_ValueDescription_string 1
+#define Z_ValueDescription_octets 2
+#define Z_ValueDescription_oid 3
+#define Z_ValueDescription_unit 4
+#define Z_ValueDescription_valueAndUnit 5
+    union
+    {
+	int *integer;
+	char *string;
+	Odr_oct *octets;
+	Odr_oid *oid;
+	Z_Unit *unit;
+	Z_IntUnit *valueAndUnit;
+    } u;
+} Z_ValueDescription;
+
+typedef struct Z_ValueRange
+{
+    Z_ValueDescription *lower;              /* OPTIONAL */
+    Z_ValueDescription *upper;              /* OPTIONAL */
+} Z_ValueRange;
+
+typedef struct Z_ValueSetEnumerated
+{
+    int num;
+    Z_ValueDescription **elements;
+} Z_ValueSetEnumerated;
+
+typedef struct Z_ValueSet
+{
+    int which;
+#define Z_ValueSet_range 0
+#define Z_ValueSet_enumerated 1
+    union
+    {
+	Z_ValueRange *range;
+	Z_ValueSetEnumerated *enumerated;
+    } u;
+} Z_ValueSet;
+
+typedef struct Z_VariantValue
+{
+    int *dataType;
+    Z_ValueSet *values;                     /* OPTIONAL */
+} Z_VariantValue;
+
+typedef struct Z_VariantType
+{
+    char *name;                             /* OPTIONAL */
+    Z_HumanString *description;             /* OPTIONAL */
+    int *variantType;
+    Z_VariantValue *variantValue;           /* OPTIONAL */
+} Z_VariantType;
+
+typedef struct Z_VariantClass
+{
+    char *name;                             /* OPTIONAL */
+    Z_HumanString *description;             /* OPTIONAL */
+    int *variantClass;
+    int num_variantTypes;
+    Z_VariantType **variantTypes;
+} Z_VariantClass;
+
+typedef struct Z_VariantSetInfo
+{
+    Z_CommonInfo *commonInfo;               /* OPTIONAL */
+    /*
+     * Key elements
+     */
+    Odr_oid *variantSet;
+    /*
+     * Brief elements
+     */
+    char *name;
+    /*
+     * Non-brief elements
+     */
+    int num_variants;
+    Z_VariantClass **variants;              /* OPTIONAL */
+} Z_VariantSetInfo;
+
+typedef struct Z_Units
+{
+    char *name;                             /* OPTIONAL */
+    Z_HumanString *description;             /* OPTIONAL */
+    Z_StringOrNumeric *unit;
+} Z_Units;
+
+typedef struct Z_UnitType
+{
+    char *name;                             /* OPTIONAL */
+    Z_HumanString *description;             /* OPTIONAL */
+    Z_StringOrNumeric *unitType;
+    int num_units;
+    Z_Units **units;
+} Z_UnitType;
+
+typedef struct Z_UnitInfo
+{
+    Z_CommonInfo *commonInfo;               /* OPTIONAL */
+    /*
+     * Key elements
+     */
+    char *unitSystem;
+    /*
+     * Non-brief elements
+     */
+    Z_HumanString *description;             /* OPTIONAL */
+    int num_units;
+    Z_UnitType **units;                     /* OPTIONAL */
+} Z_UnitInfo;
+
+typedef struct Z_CategoryInfo
+{
+    char *category;
+    char *originalCategory;                 /* OPTIONAL */
+    Z_HumanString *description;             /* OPTIONAL */
+    char *asn1Module;                       /* OPTIONAL */
+} Z_CategoryInfo;
+
+typedef struct Z_CategoryList
+{
+    Z_CommonInfo *commonInfo;               /* OPTIONAL */
+    int num_categories;
+    Z_CategoryInfo **categories;
+} Z_CategoryList;
+
+typedef struct Z_ExplainRecord
+{
+    int which;
+#define Z_Explain_targetInfo 0
+#define Z_Explain_databaseInfo 1
+#define Z_Explain_schemaInfo 2
+#define Z_Explain_tagSetInfo 3
+#define Z_Explain_recordSyntaxInfo 4
+#define Z_Explain_attributeSetInfo 5
+#define Z_Explain_termListInfo 6
+#define Z_Explain_extendedServicesInfo 7
+#define Z_Explain_attributeDetails 8
+#define Z_Explain_termListDetails 9
+#define Z_Explain_elementSetDetails 10
+#define Z_Explain_retrievalRecordDetails 11
+#define Z_Explain_sortDetails 12
+#define Z_Explain_processing 13
+#define Z_Explain_variants 14
+#define Z_Explain_units 15
+#define Z_Explain_categoryList 16
+    union
+    {
+    	Z_TargetInfo *targetInfo;
+	Z_DatabaseInfo *databaseInfo;
+	Z_SchemaInfo *schemaInfo;
+	Z_TagSetInfo *tagSetInfo;
+	Z_RecordSyntaxInfo *recordSyntaxInfo;
+	Z_AttributeSetInfo *attributeSetInfo;
+	Z_TermListInfo *termListInfo;
+	Z_ExtendedServicesInfo *extendedServicesInfo;
+	Z_AttributeDetails *attributeDetails;
+	Z_TermListDetails *termListDetails;
+	Z_ElementSetDetails *elementSetDetails;
+	Z_RetrievalRecordDetails *retrievalRecordDetails;
+	Z_SortDetails *sortDetails;
+	Z_ProcessingInformation *processing;
+	Z_VariantSetInfo *variants;
+	Z_UnitInfo *units;
+	Z_CategoryList *categoryList;
+    } u;
+} Z_ExplainRecord;
+
+YAZ_EXPORT int z_ExplainRecord(ODR o, Z_ExplainRecord **p, int opt,
+			       const char *name);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
Index: /main/tags/2.25/gsdl/packages/yaz/include/yaz/prt-ext.h
===================================================================
--- /main/tags/2.25/gsdl/packages/yaz/include/yaz/prt-ext.h	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/yaz/include/yaz/prt-ext.h	(revision 21064)
@@ -0,0 +1,114 @@
+/*
+ * Copyright (c) 1995-1999, Index Data.
+ *
+ * Permission to use, copy, modify, distribute, and sell this software and
+ * its documentation, in whole or in part, for any purpose, is hereby granted,
+ * provided that:
+ *
+ * 1. This copyright and permission notice appear in all copies of the
+ * software and its documentation. Notices of copyright or attribution
+ * which appear at the beginning of any file must remain unchanged.
+ *
+ * 2. The names of Index Data or the individual authors may not be used to
+ * endorse or promote products derived from this software without specific
+ * prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED "AS IS" AND WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS, IMPLIED, OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY
+ * WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
+ * IN NO EVENT SHALL INDEX DATA BE LIABLE FOR ANY SPECIAL, INCIDENTAL,
+ * INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND, OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER OR
+ * NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF
+ * LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
+ * OF THIS SOFTWARE.
+ *
+ */
+
+/*
+ * Biased-choice External for Z39.50.
+ */
+
+#ifndef PRT_EXT_H
+#define PRT_EXT_H
+
+#include <yaz/yconfig.h>
+#include <yaz/oid.h>
+
+
+YAZ_BEGIN_CDECL
+
+/*
+ * Used to keep track of known External definitions (a loose approach
+ * to DEFINED_BY).
+ */
+
+typedef struct Z_ext_typeent
+{
+    oid_value dref;    /* the direct-reference OID value. */
+    int what;          /* discriminator value for the external CHOICE */
+    Odr_fun fun;       /* decoder function */
+} Z_ext_typeent;
+
+struct Z_External
+{
+    Odr_oid *direct_reference;
+    int *indirect_reference;
+    char *descriptor;
+    int which;
+/* Generic types */
+#define Z_External_single 0
+#define Z_External_octet 1
+#define Z_External_arbitrary 2
+/* Specific types */
+#define Z_External_sutrs 3
+#define Z_External_explainRecord 4
+#define Z_External_resourceReport1 5
+#define Z_External_resourceReport2 6
+#define Z_External_promptObject1 7
+#define Z_External_grs1 8
+#define Z_External_extendedService 9
+#define Z_External_itemOrder 10
+#define Z_External_diag1 11
+#define Z_External_espec1 12
+#define Z_External_summary 13
+#define Z_External_OPAC 14
+#define Z_External_searchResult1 15
+#define Z_External_update 16
+#define Z_External_dateTime 17
+#define Z_External_universeReport 18
+    union
+    {
+	/* Generic types */
+	Odr_any *single_ASN1_type;
+	Odr_oct *octet_aligned;
+	Odr_bitmask *arbitrary;
+
+	/* Specific types */
+	Z_SUTRS *sutrs;
+	Z_ExplainRecord *explainRecord;
+	Z_ResourceReport1 *resourceReport1;
+	Z_ResourceReport2 *resourceReport2;
+	Z_PromptObject1 *promptObject1;
+	Z_GenericRecord *grs1;
+	Z_TaskPackage *extendedService;
+	Z_ItemOrder *itemOrder;
+	Z_DiagnosticFormat *diag1;
+	Z_Espec1 *espec1;
+	Z_BriefBib *summary;
+	Z_SearchInfoReport *searchResult1;
+	Z_IUUpdate *update;
+	Z_DateTime *dateTime;
+    Z_UniverseReport *universeReport;
+    } u;
+};
+
+
+YAZ_EXPORT int z_External(ODR o, Z_External **p, int opt, const char *name);
+YAZ_EXPORT Z_ext_typeent *z_ext_getentbyref(oid_value val);
+YAZ_EXPORT Z_External *z_ext_record(ODR o, int format, const char *buf,
+				    int len);
+
+YAZ_END_CDECL
+
+#endif
Index: /main/tags/2.25/gsdl/packages/yaz/include/yaz/prt-grs.h
===================================================================
--- /main/tags/2.25/gsdl/packages/yaz/include/yaz/prt-grs.h	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/yaz/include/yaz/prt-grs.h	(revision 21064)
@@ -0,0 +1,186 @@
+/*
+ * Copyright (c) 1995-1998, Index Data.
+ *
+ * Permission to use, copy, modify, distribute, and sell this software and
+ * its documentation, in whole or in part, for any purpose, is hereby granted,
+ * provided that:
+ *
+ * 1. This copyright and permission notice appear in all copies of the
+ * software and its documentation. Notices of copyright or attribution
+ * which appear at the beginning of any file must remain unchanged.
+ *
+ * 2. The names of Index Data or the individual authors may not be used to
+ * endorse or promote products derived from this software without specific
+ * prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED "AS IS" AND WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS, IMPLIED, OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY
+ * WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
+ * IN NO EVENT SHALL INDEX DATA BE LIABLE FOR ANY SPECIAL, INCIDENTAL,
+ * INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND, OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER OR
+ * NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF
+ * LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
+ * OF THIS SOFTWARE.
+ *
+ */
+
+#ifndef PRT_GRS_H
+#define PRT_GRS_H
+
+#include <yaz/yconfig.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+struct Z_GenericRecord;
+typedef struct Z_GenericRecord Z_GenericRecord;
+
+typedef struct Z_ElementData
+{
+    int which;
+#define Z_ElementData_octets 0
+#define Z_ElementData_numeric 1
+#define Z_ElementData_date 2
+#define Z_ElementData_ext 3
+#define Z_ElementData_string 4
+#define Z_ElementData_trueOrFalse 5
+#define Z_ElementData_oid 6
+#define Z_ElementData_intUnit 7
+#define Z_ElementData_elementNotThere 8
+#define Z_ElementData_elementEmpty 9
+#define Z_ElementData_noDataRequested 10
+#define Z_ElementData_diagnostic 11
+#define Z_ElementData_subtree 12
+    union
+    {
+	Odr_oct *octets;                      
+	int *numeric;                         
+	char *date;             
+	Z_External *ext;                     
+	char *string;                         
+	bool_t *trueOrFalse;                  
+	Odr_oid *oid;                         
+	Z_IntUnit *intUnit;                  
+	Odr_null *elementNotThere;            
+	Odr_null *elementEmpty;               
+	Odr_null *noDataRequested;            
+	Z_External *diagnostic;              
+	Z_GenericRecord *subtree;            
+    } u;
+} Z_ElementData;
+
+typedef struct Z_Order
+{
+    bool_t *ascending;                    
+    int *order;                           
+} Z_Order;
+
+typedef struct Z_Usage
+{
+    int *type;                            
+#define Z_Usage_redistributable     1
+#define Z_Usage_restricted          2
+#define Z_Usage_licensePointer      3
+    char *restriction;                      /* OPTIONAL */
+} Z_Usage;
+
+typedef struct Z_HitVector
+{
+    Z_Term *satisfier;                      /* OPTIONAL */
+    Z_IntUnit *offsetIntoElement;           /* OPTIONAL */
+    Z_IntUnit *length;                      /* OPTIONAL */
+    int *hitRank;                           /* OPTIONAL */
+    Odr_oct *targetToken;                   /* OPTIONAL */
+} Z_HitVector;
+
+typedef struct Z_Triple
+{
+    Odr_oid *variantSetId;                  /* OPTIONAL */
+    int *zclass;
+    int *type;
+    int which;
+#define Z_Triple_integer 0
+#define Z_Triple_internationalString 1
+#define Z_Triple_octetString 2
+#define Z_Triple_oid 3
+#define Z_Triple_boolean 4
+#define Z_Triple_null 5
+#define Z_Triple_unit 6
+#define Z_Triple_valueAndUnit 7
+    union
+    {
+	int *integer;
+	char *internationalString;
+	Odr_oct *octetString;
+	Odr_oid *oid;
+	bool_t *zboolean;
+	Odr_null *null;
+	Z_Unit *unit;
+	Z_IntUnit *valueAndUnit;
+    } value;
+} Z_Triple;
+
+typedef struct Z_Variant
+{
+    Odr_oid *globalVariantSetId;            /* OPTIONAL */
+    int num_triples;
+    Z_Triple **triples;
+} Z_Variant;
+
+typedef struct Z_TagUnit
+{
+    int *tagType;                           /* OPTIONAL */
+    Z_StringOrNumeric *tagValue;         
+    int *tagOccurrence;                     /* OPTIONAL */
+} Z_TagUnit;
+
+typedef struct Z_TagPath
+{
+    int num_tags;
+    Z_TagUnit **tags;
+} Z_TagPath;
+
+typedef struct Z_ElementMetaData
+{
+    Z_Order *seriesOrder;                   /* OPTIONAL */
+    Z_Usage *usageRight;                    /* OPTIONAL */
+    int num_hits;
+    Z_HitVector **hits;                     /* OPTIONAL */
+    char *displayName;                      /* OPTIONAL */
+    int num_supportedVariants;
+    Z_Variant **supportedVariants;          /* OPTIONAL */
+    char *message;                          /* OPTIONAL */
+    Odr_oct *elementDescriptor;             /* OPTIONAL */
+    Z_TagPath *surrogateFor;                /* OPTIONAL */
+    Z_TagPath *surrogateElement;            /* OPTIONAL */
+    Z_External *other;                      /* OPTIONAL */
+} Z_ElementMetaData;
+
+typedef struct Z_TaggedElement
+{
+    int *tagType;                           /* OPTIONAL */
+    Z_StringOrNumeric *tagValue;         
+    int *tagOccurrence;                     /* OPTIONAL */
+    Z_ElementData *content;              
+    Z_ElementMetaData *metaData;            /* OPTIONAL */
+    Z_Variant *appliedVariant;              /* OPTIONAL */
+} Z_TaggedElement;
+
+struct Z_GenericRecord
+{
+    int num_elements;
+    Z_TaggedElement **elements;
+};
+
+YAZ_EXPORT int z_GenericRecord(ODR o, Z_GenericRecord **p, int opt,
+			       const char *name);
+YAZ_EXPORT int z_Variant(ODR o, Z_Variant **p, int opt,
+			 const char *name);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
Index: /main/tags/2.25/gsdl/packages/yaz/include/yaz/prt-proto.h
===================================================================
--- /main/tags/2.25/gsdl/packages/yaz/include/yaz/prt-proto.h	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/yaz/include/yaz/prt-proto.h	(revision 21064)
@@ -0,0 +1,1164 @@
+/*
+ * Copyright (c) 1995-2000, Index Data.
+ *
+ * Permission to use, copy, modify, distribute, and sell this software and
+ * its documentation, in whole or in part, for any purpose, is hereby granted,
+ * provided that:
+ *
+ * 1. This copyright and permission notice appear in all copies of the
+ * software and its documentation. Notices of copyright or attribution
+ * which appear at the beginning of any file must remain unchanged.
+ *
+ * 2. The name of Index Data or the individual authors may not be used to
+ * endorse or promote products derived from this software without specific
+ * prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED "AS IS" AND WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS, IMPLIED, OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY
+ * WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
+ * IN NO EVENT SHALL INDEX DATA BE LIABLE FOR ANY SPECIAL, INCIDENTAL,
+ * INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND, OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER OR
+ * NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF
+ * LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
+ * OF THIS SOFTWARE.
+ *
+ * $Id$
+ */
+
+#ifndef PRT_PROTO_H
+#define PRT_PROTO_H
+
+#include <yaz/yconfig.h>
+#include <yaz/odr.h>
+#include <yaz/oid.h>
+#include <yaz/yaz-version.h>
+
+YAZ_BEGIN_CDECL
+
+/* ----------------- GLOBAL AUXILIARY DEFS ----------------*/
+
+struct Z_External;
+typedef struct Z_External Z_External;
+
+typedef Odr_oct Z_ReferenceId;
+typedef char Z_DatabaseName;
+typedef char Z_ResultSetId;
+typedef Odr_oct Z_ResultsetId;
+
+typedef struct Z_InfoCategory
+{
+    Odr_oid *categoryTypeId;         /* OPTIONAL */
+    int *categoryValue;
+} Z_InfoCategory;
+
+typedef struct Z_OtherInformationUnit
+{
+    Z_InfoCategory *category;        /* OPTIONAL */
+    int which;
+#define Z_OtherInfo_characterInfo 0
+#define Z_OtherInfo_binaryInfo 1
+#define Z_OtherInfo_externallyDefinedInfo 2
+#define Z_OtherInfo_oid 3
+    union
+    {
+    	char *characterInfo; 
+	Odr_oct *binaryInfo;
+	Z_External *externallyDefinedInfo;
+	Odr_oid *oid;
+    } information;
+} Z_OtherInformationUnit;
+
+typedef struct Z_OtherInformation
+{
+    int num_elements;
+    Z_OtherInformationUnit **list;
+} Z_OtherInformation;
+
+typedef struct Z_StringOrNumeric
+{
+    int which;
+#define Z_StringOrNumeric_string 0
+#define Z_StringOrNumeric_numeric 1
+    union
+    {
+    	char *string;
+	int *numeric;
+    } u;
+} Z_StringOrNumeric;
+
+typedef struct Z_Unit
+{
+    char *unitSystem;               /* OPTIONAL */
+    Z_StringOrNumeric *unitType;    /* OPTIONAL */
+    Z_StringOrNumeric *unit;        /* OPTIONAL */
+    int *scaleFactor;               /* OPTIONAL */
+} Z_Unit;
+
+typedef struct Z_IntUnit
+{
+    int *value;
+    Z_Unit *unitUsed;
+} Z_IntUnit;
+
+typedef Odr_oct Z_SUTRS;
+
+typedef struct Z_StringList
+{
+    int num_strings;
+    char **strings;
+} Z_StringList;
+
+/* ----------------- INIT SERVICE  ----------------*/
+
+typedef struct
+{
+    char *groupId;       /* OPTIONAL */
+    char *userId;         /* OPTIONAL */
+    char *password;      /* OPTIONAL */
+} Z_IdPass;
+
+typedef struct Z_IdAuthentication
+{
+    int which;
+#define Z_IdAuthentication_open 0
+#define Z_IdAuthentication_idPass 1
+#define Z_IdAuthentication_anonymous 2
+#define Z_IdAuthentication_other 3
+    union
+    {
+    	char *open;
+    	Z_IdPass *idPass;
+    	Odr_null *anonymous;
+    	Z_External *other;
+    } u;
+} Z_IdAuthentication;
+
+#define Z_ProtocolVersion_1               0
+#define Z_ProtocolVersion_2               1
+#define Z_ProtocolVersion_3               2
+
+#define Z_Options_search                  0
+#define Z_Options_present                 1
+#define Z_Options_delSet                  2
+#define Z_Options_resourceReport          3
+#define Z_Options_triggerResourceCtrl     4
+#define Z_Options_resourceCtrl            5
+#define Z_Options_accessCtrl              6
+#define Z_Options_scan                    7
+#define Z_Options_sort                    8
+#define Z_Options_reserved                9
+#define Z_Options_extendedServices       10
+#define Z_Options_level_1Segmentation    11
+#define Z_Options_level_2Segmentation    12
+#define Z_Options_concurrentOperations   13
+#define Z_Options_namedResultSets        14
+
+typedef struct Z_InitRequest
+{
+    Z_ReferenceId *referenceId;                   /* OPTIONAL */
+    Odr_bitmask *protocolVersion;
+    Odr_bitmask *options;
+    int *preferredMessageSize;
+    int *maximumRecordSize;
+    Z_IdAuthentication* idAuthentication;        /* OPTIONAL */
+    char *implementationId;                      /* OPTIONAL */
+    char *implementationName;                    /* OPTIONAL */
+    char *implementationVersion;                 /* OPTIONAL */
+    Z_External *userInformationField;            /* OPTIONAL */
+    Z_OtherInformation *otherInfo;               /* OPTIONAL */
+} Z_InitRequest;
+
+typedef struct Z_InitResponse
+{
+    Z_ReferenceId *referenceId;    /* OPTIONAL */
+    Odr_bitmask *protocolVersion;
+    Odr_bitmask *options;
+    int *preferredMessageSize;
+    int *maximumRecordSize;
+    bool_t *result;
+    char *implementationId;      /* OPTIONAL */
+    char *implementationName;    /* OPTIONAL */
+    char *implementationVersion; /* OPTIONAL */
+    Z_External *userInformationField; /* OPTIONAL */
+    Z_OtherInformation *otherInfo;    /* OPTIONAL */
+} Z_InitResponse;
+
+typedef struct Z_NSRAuthentication
+{
+    char *user;
+    char *password;
+    char *account;
+} Z_NSRAuthentication;
+
+int z_NSRAuthentication(ODR o, Z_NSRAuthentication **p, int opt,
+			const char *name);
+
+int z_StrAuthentication(ODR o, char **p, int opt, const char *name);
+
+/* ------------------ SEARCH SERVICE ----------------*/
+
+typedef struct Z_DatabaseSpecificUnit
+{
+    char *databaseName;
+    char *elementSetName;
+} Z_DatabaseSpecificUnit;
+
+typedef struct Z_DatabaseSpecific
+{
+    int num_elements;
+    Z_DatabaseSpecificUnit **elements;
+} Z_DatabaseSpecific;
+
+typedef struct Z_ElementSetNames
+{
+    int which;
+#define Z_ElementSetNames_generic 0
+#define Z_ElementSetNames_databaseSpecific 1
+    union
+    {
+        char *generic;
+        Z_DatabaseSpecific *databaseSpecific;
+    } u;
+} Z_ElementSetNames;
+
+/* ---------------------- RPN QUERY --------------------------- */
+
+typedef struct Z_ComplexAttribute
+{
+    int num_list;
+    Z_StringOrNumeric **list;
+    int num_semanticAction;
+    int **semanticAction;           /* OPTIONAL */
+} Z_ComplexAttribute;
+
+typedef struct Z_AttributeElement
+{
+    Odr_oid *attributeSet;           /* OPTIONAL - v3 only */
+    int *attributeType;
+    int which;
+#define Z_AttributeValue_numeric 0
+#define Z_AttributeValue_complex 1
+    union
+    {
+    	int *numeric;
+	Z_ComplexAttribute *complex;
+    } value;
+} Z_AttributeElement;
+
+typedef struct Z_Term 
+{
+    int which;
+#define Z_Term_general 0
+#define Z_Term_numeric 1
+#define Z_Term_characterString 2
+#define Z_Term_oid 3
+#define Z_Term_dateTime 4
+#define Z_Term_external 5
+#define Z_Term_integerAndUnit 6
+#define Z_Term_null 7
+    union
+    {
+    	Odr_oct *general; /* this is required for v2 */
+    	int *numeric;
+    	char *characterString;
+    	Odr_oid *oid;
+    	char *dateTime;
+    	Z_External *external;
+    	/* Z_IntUnit *integerAndUnit; */
+    	Odr_null *null;
+    } u;
+} Z_Term;
+
+typedef struct Z_AttributesPlusTerm
+{
+    int num_attributes;
+    Z_AttributeElement **attributeList;
+    Z_Term *term;
+} Z_AttributesPlusTerm;
+
+typedef struct Z_ResultSetPlusAttributes
+{
+    char *resultSet;
+    int num_attributes;
+    Z_AttributeElement **attributeList;
+} Z_ResultSetPlusAttributes;
+
+typedef struct Z_ProximityOperator
+{
+    bool_t *exclusion;          /* OPTIONAL */
+    int *distance;
+    bool_t *ordered;
+    int *relationType;
+#define Z_Prox_lessThan           1
+#define Z_Prox_lessThanOrEqual    2
+#define Z_Prox_equal              3
+#define Z_Prox_greaterThanOrEqual 4
+#define Z_Prox_greaterThan        5
+#define Z_Prox_notEqual           6
+    int which;
+#define Z_ProxCode_known 0
+#define Z_ProxCode_private 1
+    int *proximityUnitCode;
+#define Z_ProxUnit_character       1
+#define Z_ProxUnit_word            2
+#define Z_ProxUnit_sentence        3
+#define Z_ProxUnit_paragraph       4
+#define Z_ProxUnit_section         5
+#define Z_ProxUnit_chapter         6
+#define Z_ProxUnit_document        7
+#define Z_ProxUnit_element         8
+#define Z_ProxUnit_subelement      9
+#define Z_ProxUnit_elementType    10
+#define Z_ProxUnit_byte           11   /* v3 only */
+} Z_ProximityOperator;
+
+typedef struct Z_Operator
+{
+    int which;
+#define Z_Operator_and 0
+#define Z_Operator_or 1
+#define Z_Operator_and_not 2
+#define Z_Operator_prox 3
+    union
+    {
+    	Odr_null *and;          /* these guys are nulls. */
+    	Odr_null *or;
+    	Odr_null *and_not;
+	Z_ProximityOperator *prox;
+    } u;
+} Z_Operator;
+
+typedef struct Z_Operand
+{
+    int which;
+#define Z_Operand_APT 0
+#define Z_Operand_resultSetId 1
+#define Z_Operand_resultAttr             /* v3 only */ 2
+    union
+    {
+    	Z_AttributesPlusTerm *attributesPlusTerm;
+    	Z_ResultSetId *resultSetId;
+	Z_ResultSetPlusAttributes *resultAttr;
+    } u;
+} Z_Operand;
+
+typedef struct Z_Complex
+{
+    struct Z_RPNStructure *s1;
+    struct Z_RPNStructure *s2;
+    Z_Operator *roperator;
+} Z_Complex;
+
+typedef struct Z_RPNStructure
+{
+    int which;
+#define Z_RPNStructure_simple 0
+#define Z_RPNStructure_complex 1
+    union
+    {
+    	Z_Operand *simple;
+    	Z_Complex *complex;
+    } u;
+} Z_RPNStructure;
+
+typedef struct Z_RPNQuery
+{
+    Odr_oid *attributeSetId;
+    Z_RPNStructure *RPNStructure;
+} Z_RPNQuery;
+
+/* -------------------------- SEARCHREQUEST -------------------------- */
+
+typedef struct Z_Query
+{
+    int which;
+#define Z_Query_type_1 1
+#define Z_Query_type_2 2
+#define Z_Query_type_101 3
+    union
+    {
+    	Z_RPNQuery *type_1;
+    	Odr_oct *type_2;
+	Z_RPNQuery *type_101;
+    } u;
+} Z_Query;
+
+typedef struct Z_SearchRequest
+{
+    Z_ReferenceId *referenceId;   /* OPTIONAL */
+    int *smallSetUpperBound;
+    int *largeSetLowerBound;
+    int *mediumSetPresentNumber;
+    bool_t *replaceIndicator;
+    char *resultSetName;
+    int num_databaseNames;
+    char **databaseNames;
+    Z_ElementSetNames *smallSetElementSetNames;    /* OPTIONAL */
+    Z_ElementSetNames *mediumSetElementSetNames;    /* OPTIONAL */
+    Odr_oid *preferredRecordSyntax;  /* OPTIONAL */
+    Z_Query *query;
+    Z_OtherInformation *additionalSearchInfo;       /* OPTIONAL */
+    Z_OtherInformation *otherInfo;                  /* OPTIONAL */
+} Z_SearchRequest;
+
+/* ------------------------ RECORD -------------------------- */
+
+typedef Z_External Z_DatabaseRecord;
+
+typedef struct Z_DefaultDiagFormat
+{
+    Odr_oid *diagnosticSetId; /* This is opt'l to interwork with bad targets */
+    int *condition;
+    /* until the whole character set issue becomes more definite,
+     * you can probably ignore this on input. */
+    int which;
+#define Z_DiagForm_v2AddInfo 0
+#define Z_DiagForm_v3AddInfo 1
+    char *addinfo;
+} Z_DefaultDiagFormat;
+
+typedef struct Z_DiagRec
+{
+    int which;
+#define Z_DiagRec_defaultFormat 0
+#define Z_DiagRec_externallyDefined 1
+    union
+    {
+    	Z_DefaultDiagFormat *defaultFormat;
+	Z_External *externallyDefined;
+    } u;
+} Z_DiagRec;
+
+typedef struct Z_DiagRecs
+{
+    int num_diagRecs;
+    Z_DiagRec **diagRecs;
+} Z_DiagRecs;
+
+typedef struct Z_NamePlusRecord
+{
+    char *databaseName;      /* OPTIONAL */
+    int which;
+#define Z_NamePlusRecord_databaseRecord 0
+#define Z_NamePlusRecord_surrogateDiagnostic 1
+    union
+    {
+    	Z_DatabaseRecord *databaseRecord;
+    	Z_DiagRec *surrogateDiagnostic;
+    } u;
+} Z_NamePlusRecord;
+
+typedef struct Z_NamePlusRecordList
+{
+    int num_records;
+    Z_NamePlusRecord **records;
+} Z_NamePlusRecordList;
+
+typedef struct Z_Records
+{
+    int which;
+#define Z_Records_DBOSD 0
+#define Z_Records_NSD 1
+#define Z_Records_multipleNSD 2
+    union
+    {
+    	Z_NamePlusRecordList *databaseOrSurDiagnostics;
+    	Z_DiagRec *nonSurrogateDiagnostic;
+	Z_DiagRecs *multipleNonSurDiagnostics;
+    } u;
+} Z_Records;
+
+/* ------------------------ SEARCHRESPONSE ------------------ */
+
+typedef struct Z_SearchResponse
+{
+    Z_ReferenceId *referenceId;       /* OPTIONAL */
+    int *resultCount;
+    int *numberOfRecordsReturned;
+    int *nextResultSetPosition;
+    bool_t *searchStatus;
+    int *resultSetStatus;              /* OPTIONAL */
+#define Z_RES_SUBSET        1
+#define Z_RES_INTERIM       2
+#define Z_RES_NONE          3
+    int *presentStatus;                /* OPTIONAL */
+#define Z_PRES_SUCCESS      0
+#define Z_PRES_PARTIAL_1    1
+#define Z_PRES_PARTIAL_2    2
+#define Z_PRES_PARTIAL_3    3
+#define Z_PRES_PARTIAL_4    4
+#define Z_PRES_FAILURE      5
+    Z_Records *records;                  /* OPTIONAL */
+    Z_OtherInformation *additionalSearchInfo;
+    Z_OtherInformation *otherInfo;
+} Z_SearchResponse;
+
+/* ------------------------- PRESENT SERVICE -----------------*/
+
+typedef struct Z_ElementSpec
+{
+    int which;
+#define Z_ElementSpec_elementSetName 0
+#define Z_ElementSpec_externalSpec 1
+    union
+    {
+    	char *elementSetName;
+	Z_External *externalSpec;
+    } u;
+} Z_ElementSpec;
+
+typedef struct Z_Specification
+{
+    Odr_oid *schema;                  /* OPTIONAL */
+    Z_ElementSpec *elementSpec;       /* OPTIONAL */
+} Z_Specification;
+
+typedef struct Z_DbSpecific
+{
+    char *databaseName;
+    Z_Specification *spec;
+} Z_DbSpecific;
+
+typedef struct Z_CompSpec
+{
+    bool_t *selectAlternativeSyntax;
+    Z_Specification *generic;            /* OPTIONAL */
+    int num_dbSpecific;
+    Z_DbSpecific **dbSpecific;           /* OPTIONAL */
+    int num_recordSyntax;
+    Odr_oid **recordSyntax;              /* OPTIONAL */
+} Z_CompSpec;
+
+typedef struct Z_RecordComposition
+{
+    int which;
+#define Z_RecordComp_simple 0
+#define Z_RecordComp_complex 1
+    union
+    {
+    	Z_ElementSetNames *simple;
+	Z_CompSpec *complex;
+    } u;
+} Z_RecordComposition;
+
+typedef struct Z_Range
+{
+    int *startingPosition;
+    int *numberOfRecords;
+} Z_Range;
+
+typedef struct Z_PresentRequest
+{
+    Z_ReferenceId *referenceId;              /* OPTIONAL */
+    Z_ResultSetId *resultSetId;
+    int *resultSetStartPoint;
+    int *numberOfRecordsRequested;
+    int num_ranges;
+    Z_Range **additionalRanges;              /* OPTIONAL */
+    Z_RecordComposition *recordComposition;  /* OPTIONAL */
+    Odr_oid *preferredRecordSyntax;  /* OPTIONAL */
+    int *maxSegmentCount;                 /* OPTIONAL */
+    int *maxRecordSize;                   /* OPTIONAL */
+    int *maxSegmentSize;                  /* OPTIONAL */
+    Z_OtherInformation *otherInfo;        /* OPTIONAL */
+} Z_PresentRequest;
+
+typedef struct Z_PresentResponse
+{
+    Z_ReferenceId *referenceId;        /* OPTIONAL */
+    int *numberOfRecordsReturned;
+    int *nextResultSetPosition;
+    int *presentStatus;
+    Z_Records *records;
+    Z_OtherInformation *otherInfo;     /* OPTIONAL */
+} Z_PresentResponse;
+
+/* ------------------ RESOURCE CONTROL ----------------*/
+
+typedef struct Z_TriggerResourceControlRequest
+{
+    Z_ReferenceId *referenceId;    /* OPTIONAL */
+    int *requestedAction;
+#define Z_TriggerResourceCtrl_resourceReport  1
+#define Z_TriggerResourceCtrl_resourceControl 2
+#define Z_TriggerResourceCtrl_cancel          3
+    Odr_oid *prefResourceReportFormat;  /* OPTIONAL */
+    bool_t *resultSetWanted;            /* OPTIONAL */
+    Z_OtherInformation *otherInfo;
+} Z_TriggerResourceControlRequest;
+
+typedef struct Z_ResourceControlRequest
+{
+    Z_ReferenceId *referenceId;    /* OPTIONAL */
+    bool_t *suspendedFlag;         /* OPTIONAL */
+    Z_External *resourceReport; /* OPTIONAL */
+    int *partialResultsAvailable;  /* OPTIONAL */
+#define Z_ResourceControlRequest_subset    1
+#define Z_ResourceControlRequest_interim   2
+#define Z_ResourceControlRequest_none      3
+    bool_t *responseRequired;
+    bool_t *triggeredRequestFlag;  /* OPTIONAL */
+    Z_OtherInformation *otherInfo;
+} Z_ResourceControlRequest;
+
+typedef struct Z_ResourceControlResponse
+{
+    Z_ReferenceId *referenceId;    /* OPTIONAL */
+    bool_t *continueFlag;
+    bool_t *resultSetWanted;       /* OPTIONAL */
+    Z_OtherInformation *otherInfo;
+} Z_ResourceControlResponse;
+
+
+/* ------------------ ACCESS CTRL SERVICE ----------------*/
+
+typedef struct Z_AccessControlRequest
+{
+    Z_ReferenceId *referenceId;           /* OPTIONAL */
+    int which;
+#define Z_AccessRequest_simpleForm 0
+#define Z_AccessRequest_externallyDefined 1
+    union
+    {
+    	Odr_oct *simpleForm;
+	Z_External *externallyDefined;
+    } u;
+    Z_OtherInformation *otherInfo;           /* OPTIONAL */
+} Z_AccessControlRequest;
+
+typedef struct Z_AccessControlResponse
+{
+    Z_ReferenceId *referenceId;              /* OPTIONAL */
+    int which;
+#define Z_AccessResponse_simpleForm 0
+#define Z_AccessResponse_externallyDefined 1
+    union
+    {
+    	Odr_oct *simpleForm;
+	Z_External *externallyDefined;
+    } u;
+    Z_DiagRec *diagnostic;                   /* OPTIONAL */
+    Z_OtherInformation *otherInfo;           /* OPTIONAL */
+} Z_AccessControlResponse;
+
+/* ------------------------ SCAN SERVICE -------------------- */
+
+typedef struct Z_AttributeList
+{
+    int num_attributes;
+    Z_AttributeElement **attributes;
+} Z_AttributeList;
+
+typedef struct Z_AlternativeTerm
+{
+    int num_terms;
+    Z_AttributesPlusTerm **terms;
+} Z_AlternativeTerm;
+
+typedef struct Z_ByDatabase
+{
+    char *db;
+    int *num;                           /* OPTIONAL */
+    Z_OtherInformation *otherDbInfo;    /* OPTIONAL */
+} Z_ByDatabase;
+
+typedef struct Z_ByDatabaseList
+{
+    int num_elements;
+    Z_ByDatabase **elements;
+} Z_ByDatabaseList;
+
+typedef struct Z_ScanOccurrences
+{
+    int which;
+#define Z_ScanOccurrences_global         0
+#define Z_ScanOccurrences_byDatabase     1
+    union
+    {
+	int *global;
+	Z_ByDatabaseList *byDatabase;
+    } u;
+
+} Z_ScanOccurrences;
+
+typedef struct Z_OccurrenceByAttributesElem
+{
+    Z_AttributeList *attributes;
+    Z_ScanOccurrences *occurrences;         /* OPTIONAL */
+    Z_OtherInformation *otherOccurInfo;      /* OPTIONAL */
+} Z_OccurrenceByAttributesElem;
+
+typedef struct Z_OccurrenceByAttributes
+{
+    int num_elements;
+    Z_OccurrenceByAttributesElem **elements;
+} Z_OccurrenceByAttributes;
+
+typedef struct Z_TermInfo
+{
+    Z_Term *term;
+    char *displayTerm;                     /* OPTIONAL */
+    Z_AttributeList *suggestedAttributes;  /* OPTIONAL */
+    Z_AlternativeTerm *alternativeTerm;    /* OPTIONAL */
+    int *globalOccurrences;                /* OPTIONAL */
+    Z_OccurrenceByAttributes *byAttributes; /* OPTIONAL */
+    Z_OtherInformation *otherTermInfo;      /* OPTIONAL */
+} Z_TermInfo;
+
+typedef struct Z_Entry
+{
+    int which;
+#define Z_Entry_termInfo 0
+#define Z_Entry_surrogateDiagnostic 1
+    union
+    {
+    	Z_TermInfo *termInfo;
+	Z_DiagRec *surrogateDiagnostic;
+    } u;
+} Z_Entry;
+
+#ifdef BUGGY_LISTENTRIES
+
+typedef struct Z_Entries
+{
+    int num_entries;
+    Z_Entry **entries;
+} Z_Entries;
+
+typedef struct Z_ListEntries
+{
+    int which;
+#define Z_ListEntries_entries 0
+#define Z_ListEntries_nonSurrogateDiagnostics 1
+    union
+    {
+    	Z_Entries *entries;
+	Z_DiagRecs *nonSurrogateDiagnostics;
+    } u;
+} Z_ListEntries;
+
+#endif
+
+typedef struct Z_ListEntries {
+	int num_entries;
+	Z_Entry **entries; /* OPT */
+	int num_nonsurrogateDiagnostics;
+	Z_DiagRec **nonsurrogateDiagnostics; /* OPT */
+} Z_ListEntries;
+
+typedef struct Z_ScanRequest
+{
+    Z_ReferenceId *referenceId;       /* OPTIONAL */
+    int num_databaseNames;
+    char **databaseNames;
+    Odr_oid *attributeSet;          /* OPTIONAL */
+    Z_AttributesPlusTerm *termListAndStartPoint;
+    int *stepSize;                    /* OPTIONAL */
+    int *numberOfTermsRequested;
+    int *preferredPositionInResponse;   /* OPTIONAL */
+    Z_OtherInformation *otherInfo;
+} Z_ScanRequest;
+
+typedef struct Z_ScanResponse
+{
+    Z_ReferenceId *referenceId;       /* OPTIONAL */
+    int *stepSize;                    /* OPTIONAL */
+    int *scanStatus;
+#define Z_Scan_success      0
+#define Z_Scan_partial_1    1
+#define Z_Scan_partial_2    2
+#define Z_Scan_partial_3    3
+#define Z_Scan_partial_4    4
+#define Z_Scan_partial_5    5
+#define Z_Scan_failure      6
+    int *numberOfEntriesReturned;
+    int *positionOfTerm;              /* OPTIONAL */
+    Z_ListEntries *entries;           /* OPTIONAL */
+    Odr_oid *attributeSet;            /* OPTIONAL */
+    Z_OtherInformation *otherInfo;
+} Z_ScanResponse; 
+
+
+/* ------------------------ DELETE -------------------------- */
+
+#define Z_DeleteStatus_success                          0
+#define Z_DeleteStatus_resultSetDidNotExist             1
+#define Z_DeleteStatus_previouslyDeletedByTarget        2
+#define Z_DeleteStatus_systemProblemAtTarget            3
+#define Z_DeleteStatus_accessNotAllowed                 4
+#define Z_DeleteStatus_resourceControlAtOrigin          5
+#define Z_DeleteStatus_resourceControlAtTarget          6
+#define Z_DeleteStatus_bulkDeleteNotSupported           7
+#define Z_DeleteStatus_notAllRsltSetsDeletedOnBulkDlte  8
+#define Z_DeleteStatus_notAllRequestedResultSetsDeleted 9
+#define Z_DeleteStatus_resultSetInUse                  10
+
+typedef struct Z_ListStatus
+{
+    Z_ResultSetId *id;
+    int *status;
+} Z_ListStatus;
+
+typedef struct Z_DeleteResultSetRequest
+{
+    Z_ReferenceId *referenceId;        /* OPTIONAL */
+    int *deleteFunction;
+#define Z_DeleteRequest_list    0
+#define Z_DeleteRequest_all     1
+    int num_resultSetList;
+    Z_ResultSetId **resultSetList;      /* OPTIONAL */
+    Z_OtherInformation *otherInfo;
+} Z_DeleteResultSetRequest;
+
+typedef struct Z_ListStatuses {
+    int num;
+    Z_ListStatus **elements;
+} Z_ListStatuses;
+
+typedef struct Z_DeleteResultSetResponse
+{
+    Z_ReferenceId *referenceId;        /* OPTIONAL */
+    int *deleteOperationStatus;
+    Z_ListStatuses *deleteListStatuses;/* OPTIONAL */
+    int *numberNotDeleted;             /* OPTIONAL */
+    Z_ListStatuses *bulkStatuses;      /* OPTIONAL */
+    char *deleteMessage;               /* OPTIONAL */
+    Z_OtherInformation *otherInfo;
+} Z_DeleteResultSetResponse;
+
+/* ------------------------ CLOSE SERVICE ------------------- */
+
+typedef struct Z_Close
+{
+    Z_ReferenceId *referenceId;         /* OPTIONAL */
+    int *closeReason;
+#define Z_Close_finished           0
+#define Z_Close_shutdown           1
+#define Z_Close_systemProblem      2
+#define Z_Close_costLimit          3
+#define Z_Close_resources          4
+#define Z_Close_securityViolation  5
+#define Z_Close_protocolError      6
+#define Z_Close_lackOfActivity     7
+#define Z_Close_peerAbort          8
+#define Z_Close_unspecified        9
+    char *diagnosticInformation;          /* OPTIONAL */
+    Odr_oid *resourceReportFormat;        /* OPTIONAL */
+    Z_External *resourceReport;         /* OPTIONAL */
+    Z_OtherInformation *otherInfo;        /* OPTIONAL */
+} Z_Close;
+
+/* ------------------------ SEGMENTATION -------------------- */
+
+typedef struct Z_Segment
+{
+    Z_ReferenceId *referenceId;   /* OPTIONAL */
+    int *numberOfRecordsReturned;
+    int num_segmentRecords;
+    Z_NamePlusRecord **segmentRecords;
+    Z_OtherInformation *otherInfo;  /* OPTIONAL */
+} Z_Segment;
+
+/* ----------------------- Extended Services ---------------- */
+
+typedef struct Z_Permissions
+{
+    char *userId;                         
+    int num_allowableFunctions;
+    int **allowableFunctions;             
+#define Z_Permissions_delete              1
+#define Z_Permissions_modifyContents      2
+#define Z_Permissions_modifyPermissions   3
+#define Z_Permissions_present             4
+#define Z_Permissions_invoke              5
+} Z_Permissions;
+
+typedef struct Z_ExtendedServicesRequest
+{
+    Z_ReferenceId *referenceId;             /* OPTIONAL */
+    int *function;                        
+#define Z_ExtendedServicesRequest_create              1
+#define Z_ExtendedServicesRequest_delete              2
+#define Z_ExtendedServicesRequest_modify              3
+    Odr_oid *packageType;                 
+    char *packageName;                      /* OPTIONAL */
+    char *userId;                           /* OPTIONAL */
+    Z_IntUnit *retentionTime;               /* OPTIONAL */
+    Z_Permissions *permissions;             /* OPTIONAL */
+    char *description;                      /* OPTIONAL */
+    Z_External *taskSpecificParameters;     /* OPTIONAL */
+    int *waitAction;                      
+#define Z_ExtendedServicesRequest_wait                1
+#define Z_ExtendedServicesRequest_waitIfPossible      2
+#define Z_ExtendedServicesRequest_dontWait            3
+#define Z_ExtendedServicesRequest_dontReturnPackage   4
+    char *elements;             /* OPTIONAL */
+    Z_OtherInformation *otherInfo;          /* OPTIONAL */
+} Z_ExtendedServicesRequest;
+
+typedef struct Z_ExtendedServicesResponse
+{
+    Z_ReferenceId *referenceId;             /* OPTIONAL */
+    int *operationStatus;                 
+#define Z_ExtendedServicesResponse_done                1
+#define Z_ExtendedServicesResponse_accepted            2
+#define Z_ExtendedServicesResponse_failure             3
+    int num_diagnostics;
+    Z_DiagRec **diagnostics;                /* OPTIONAL */
+    Z_External *taskPackage;                /* OPTIONAL */
+    Z_OtherInformation *otherInfo;          /* OPTIONAL */
+} Z_ExtendedServicesResponse;
+
+/* ------------------------ Sort --------------------------- */
+
+typedef struct Z_SortAttributes
+{
+    Odr_oid *id;
+    Z_AttributeList *list;
+} Z_SortAttributes;
+
+typedef struct Z_SortKey
+{
+    int which;
+#define Z_SortKey_sortField             0
+#define Z_SortKey_elementSpec           1
+#define Z_SortKey_sortAttributes        2
+    union
+    {
+	char *sortField;
+	Z_Specification *elementSpec;
+	Z_SortAttributes *sortAttributes;
+    } u;
+} Z_SortKey;
+
+typedef struct Z_SortDbSpecific
+{
+    char *databaseName;
+    Z_SortKey *dbSort;
+} Z_SortDbSpecific;
+
+typedef struct Z_SortDbSpecificList
+{
+    int num_dbSpecific;
+    Z_SortDbSpecific **dbSpecific;
+} Z_SortDbSpecificList;
+
+typedef struct Z_SortElement
+{
+    int which;
+#define Z_SortElement_generic               0
+#define Z_SortElement_databaseSpecific      1
+    union
+    {
+	Z_SortKey *generic;
+	Z_SortDbSpecificList *databaseSpecific;
+    } u;
+} Z_SortElement;
+
+typedef struct Z_SortMissingValueAction
+{
+    int which;
+#define Z_SortMissingValAct_abort           0
+#define Z_SortMissingValAct_null            1
+#define Z_SortMissingValAct_valData         2
+    union
+    {
+	Odr_null *abort;
+	Odr_null *null;
+	Odr_oct *valData;
+    } u;
+} Z_SortMissingValueAction;
+
+typedef struct Z_SortKeySpec
+{
+    Z_SortElement *sortElement;
+    int *sortRelation;
+#define Z_SortRelation_ascending            0
+#define Z_SortRelation_descending           1
+#define Z_SortRelation_ascendingByFreq      3
+#define Z_SortRelation_descendingByFreq     4
+    int *caseSensitivity;
+#define Z_SortCase_caseSensitive            0
+#define Z_SortCase_caseInsensitive          1
+    Z_SortMissingValueAction *missingValueAction;  /* OPTIONAL */
+} Z_SortKeySpec;
+
+typedef struct Z_SortResponse
+{
+    Z_ReferenceId *referenceId;             /* OPTIONAL */
+    int *sortStatus;
+#define Z_SortStatus_success              0
+#define Z_SortStatus_partial_1            1
+#define Z_SortStatus_failure              2
+    int *resultSetStatus;                   /* OPTIONAL */
+#define Z_SortResultSetStatus_empty       1
+#define Z_SortResultSetStatus_interim     2
+#define Z_SortResultSetStatus_unchanged   3
+#define Z_SortResultSetStatus_none        4
+    Z_DiagRecs *diagnostics;                /* OPTIONAL */
+    Z_OtherInformation *otherInfo;          /* OPTIONAL */
+} Z_SortResponse;
+
+typedef struct Z_SortKeySpecList
+{
+    int num_specs;
+    Z_SortKeySpec **specs;
+} Z_SortKeySpecList;
+
+typedef struct Z_SortRequest
+{
+    Z_ReferenceId *referenceId;             /* OPTIONAL */
+    Z_StringList *inputResultSetNames;
+    char *sortedResultSetName;
+    Z_SortKeySpecList *sortSequence;
+    Z_OtherInformation *otherInfo;          /* OPTIONAL */
+} Z_SortRequest;
+
+/* ----------------------- Resource Report ------------------ */
+
+typedef struct Z_ResourceReportRequest
+{
+    Z_ReferenceId *referenceId;             /* OPTIONAL */
+    Z_ReferenceId *opId;                    /* OPTIONAL */
+    Odr_oid *prefResourceReportFormat;      /* OPTIONAL */
+    Z_OtherInformation *otherInfo;          /* OPTIONAL */
+} Z_ResourceReportRequest;
+
+typedef struct Z_ResourceReportResponse
+{
+    Z_ReferenceId *referenceId;             /* OPTIONAL */
+    int *resourceReportStatus;
+#define Z_ResourceReportStatus_success   0
+#define Z_ResourceReportStatus_partial   1
+#define Z_ResourceReportStatus_failure_1 2
+#define Z_ResourceReportStatus_failure_2 3
+#define Z_ResourceReportStatus_failure_3 4
+#define Z_ResourceReportStatus_failure_4 5
+#define Z_ResourceReportStatus_failure_5 6
+#define Z_ResourceReportStatus_failure_6 7
+    Z_External *resourceReport;             /* OPTIONAL */
+    Z_OtherInformation *otherInfo;          /* OPTIONAL */
+} Z_ResourceReportResponse;
+
+/* ------------------------ APDU ---------------------------- */
+
+typedef struct Z_APDU
+{    
+    int which;
+#define Z_APDU_initRequest 0
+#define Z_APDU_initResponse 1
+#define Z_APDU_searchRequest 2
+#define Z_APDU_searchResponse 3
+#define Z_APDU_presentRequest 4
+#define Z_APDU_presentResponse 5
+#define Z_APDU_deleteResultSetRequest 6
+#define Z_APDU_deleteResultSetResponse 7
+#define Z_APDU_resourceControlRequest 8
+#define Z_APDU_resourceControlResponse 9
+#define Z_APDU_triggerResourceControlRequest 10
+#define Z_APDU_scanRequest 11
+#define Z_APDU_scanResponse 12
+#define Z_APDU_segmentRequest 13
+#define Z_APDU_extendedServicesRequest 14
+#define Z_APDU_extendedServicesResponse 15
+#define Z_APDU_close 16
+#define Z_APDU_accessControlRequest 17
+#define Z_APDU_accessControlResponse 18
+#define Z_APDU_sortRequest 20
+#define Z_APDU_sortResponse 21
+#define Z_APDU_resourceReportRequest 22
+#define Z_APDU_resourceReportResponse 23
+    union
+    {
+	Z_InitRequest  *initRequest;
+    	Z_InitResponse *initResponse;
+    	Z_SearchRequest *searchRequest;
+    	Z_SearchResponse *searchResponse;
+    	Z_PresentRequest *presentRequest;
+    	Z_PresentResponse *presentResponse;
+	Z_DeleteResultSetRequest *deleteResultSetRequest;
+	Z_DeleteResultSetResponse *deleteResultSetResponse;
+	Z_AccessControlRequest *accessControlRequest;
+	Z_AccessControlResponse *accessControlResponse;
+	Z_ResourceControlRequest *resourceControlRequest;
+	Z_ResourceControlResponse *resourceControlResponse;
+	Z_TriggerResourceControlRequest *triggerResourceControlRequest;
+	Z_ResourceReportRequest *resourceReportRequest;
+	Z_ResourceReportResponse *resourceReportResponse;
+	Z_ScanRequest *scanRequest;
+	Z_ScanResponse *scanResponse;
+	Z_SortRequest *sortRequest;
+	Z_SortResponse *sortResponse;
+	Z_Segment *segmentRequest;
+	Z_ExtendedServicesRequest *extendedServicesRequest;
+	Z_ExtendedServicesResponse *extendedServicesResponse;
+	Z_Close *close;
+    } u;
+} Z_APDU;
+
+#define z_APDU z_APDU_old
+
+YAZ_EXPORT int z_APDU(ODR o, Z_APDU **p, int opt, const char *name);
+YAZ_EXPORT int z_SUTRS(ODR o, Odr_oct **p, int opt, const char *name);
+
+YAZ_EXPORT Z_InitRequest *zget_InitRequest(ODR o);
+YAZ_EXPORT Z_InitResponse *zget_InitResponse(ODR o);
+YAZ_EXPORT Z_SearchRequest *zget_SearchRequest(ODR o);
+YAZ_EXPORT Z_SearchResponse *zget_SearchResponse(ODR o);
+YAZ_EXPORT Z_PresentRequest *zget_PresentRequest(ODR o);
+YAZ_EXPORT Z_PresentResponse *zget_PresentResponse(ODR o);
+YAZ_EXPORT Z_DeleteResultSetRequest *zget_DeleteResultSetRequest(ODR o);
+YAZ_EXPORT Z_DeleteResultSetResponse *zget_DeleteResultSetResponse(ODR o);
+YAZ_EXPORT Z_ScanRequest *zget_ScanRequest(ODR o);
+YAZ_EXPORT Z_ScanResponse *zget_ScanResponse(ODR o);
+YAZ_EXPORT Z_TriggerResourceControlRequest *zget_TriggerResourceControlRequest(ODR o);
+YAZ_EXPORT Z_ResourceControlRequest *zget_ResourceControlRequest(ODR o);
+YAZ_EXPORT Z_ResourceControlResponse *zget_ResourceControlResponse(ODR o);
+YAZ_EXPORT Z_Close *zget_Close(ODR o);
+YAZ_EXPORT int z_StringList(ODR o, Z_StringList **p, int opt,
+			    const char *name);
+YAZ_EXPORT int z_InternationalString(ODR o, char **p, int opt,
+				     const char *name);
+YAZ_EXPORT int z_OtherInformation(ODR o, Z_OtherInformation **p, int opt,
+				  const char *naem);
+YAZ_EXPORT int z_ElementSetName(ODR o, char **p, int opt, const char *name);
+YAZ_EXPORT int z_IntUnit(ODR o, Z_IntUnit **p, int opt, const char *name);
+YAZ_EXPORT int z_Unit(ODR o, Z_Unit **p, int opt, const char *name);
+YAZ_EXPORT int z_DatabaseName(ODR o, Z_DatabaseName **p, int opt,
+			      const char *name);
+YAZ_EXPORT int z_StringOrNumeric(ODR o, Z_StringOrNumeric **p, int opt,
+				 const char *name);
+YAZ_EXPORT int z_OtherInformationUnit(ODR o, Z_OtherInformationUnit **p,
+				      int opt, const char *name);
+YAZ_EXPORT int z_Term(ODR o, Z_Term **p, int opt, const char *name);
+YAZ_EXPORT int z_Specification(ODR o, Z_Specification **p, int opt,
+			       const char *name);
+YAZ_EXPORT int z_Permissions(ODR o, Z_Permissions **p, int opt,
+			     const char *name);
+YAZ_EXPORT int z_DiagRec(ODR o, Z_DiagRec **p, int opt, const char *name);
+YAZ_EXPORT int z_DiagRecs(ODR o, Z_DiagRecs **p, int opt, const char *name);
+YAZ_EXPORT int z_AttributeList(ODR o, Z_AttributeList **p, int opt,
+			       const char *name);
+YAZ_EXPORT int z_DefaultDiagFormat(ODR o, Z_DefaultDiagFormat **p, int opt,
+				   const char *name);
+YAZ_EXPORT Z_APDU *zget_APDU(ODR o, int which);
+YAZ_EXPORT int z_Query(ODR o, Z_Query **p, int opt, const char *name);
+
+YAZ_END_CDECL
+
+#include <yaz/prt-rsc.h>
+#include <yaz/prt-acc.h>
+#include <yaz/prt-exp.h>
+#include <yaz/prt-grs.h>
+#include <yaz/prt-arc.h>
+#include <yaz/prt-exd.h>
+#include <yaz/prt-dia.h>
+#include <yaz/prt-esp.h>
+#include <yaz/prt-add.h>
+
+#include <yaz/prt-dat.h>
+#include <yaz/prt-univ.h>
+#include <yaz/prt-ext.h>
+
+#endif
Index: /main/tags/2.25/gsdl/packages/yaz/include/yaz/prt-rsc.h
===================================================================
--- /main/tags/2.25/gsdl/packages/yaz/include/yaz/prt-rsc.h	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/yaz/include/yaz/prt-rsc.h	(revision 21064)
@@ -0,0 +1,123 @@
+/*
+ * Copyright (c) 1995, Index Data.
+ *
+ * Permission to use, copy, modify, distribute, and sell this software and
+ * its documentation, in whole or in part, for any purpose, is hereby granted,
+ * provided that:
+ *
+ * 1. This copyright and permission notice appear in all copies of the
+ * software and its documentation. Notices of copyright or attribution
+ * which appear at the beginning of any file must remain unchanged.
+ *
+ * 2. The name of Index Data or the individual authors may not be used to
+ * endorse or promote products derived from this software without specific
+ * prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED "AS IS" AND WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS, IMPLIED, OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY
+ * WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
+ * IN NO EVENT SHALL INDEX DATA BE LIABLE FOR ANY SPECIAL, INCIDENTAL,
+ * INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND, OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER OR
+ * NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF
+ * LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
+ * OF THIS SOFTWARE.
+ *
+ * $Log$
+ * Revision 1.1  2000/08/03 03:10:49  johnmcp
+ * Added the YAZ toolkit source to the packages directory (for z39.50 stuff)
+ *
+ * Revision 1.1  1999/11/30 13:47:11  adam
+ * Improved installation. Moved header files to include/yaz.
+ *
+ * Revision 1.7  1999/04/20 09:56:48  adam
+ * Added 'name' paramter to encoder/decoder routines (typedef Odr_fun).
+ * Modified all encoders/decoders to reflect this change.
+ *
+ * Revision 1.6  1997/05/14 06:53:50  adam
+ * C++ support.
+ *
+ * Revision 1.5  1995/09/29 17:12:11  quinn
+ * Smallish
+ *
+ * Revision 1.4  1995/09/27  15:02:52  quinn
+ * Modified function heads & prototypes.
+ *
+ * Revision 1.3  1995/08/17  12:45:17  quinn
+ * Fixed minor problems with GRS-1. Added support in c&s.
+ *
+ * Revision 1.2  1995/06/02  09:49:50  quinn
+ * Add access control
+ *
+ * Revision 1.1  1995/06/01  11:24:52  quinn
+ * Resource Control
+ *
+ *
+ */
+
+#ifndef PRT_RSC_H
+#define PRT_RSC_H
+
+#include <yaz/yconfig.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* -------------------- Resource-1 -------------------- */
+
+#define Z_EstimateType_currentSearchRecords           1
+#define Z_EstimateType_finalSearchRecords             2
+#define Z_EstimateType_currentPresentRecords          3
+#define Z_EstimateType_finalPresentRecords            4
+#define Z_EstimateType_currentOpTimeProcessing        5
+#define Z_EstimateType_finalOpTimeProcessing          6
+#define Z_EstimateType_currentAssocTime               7
+#define Z_EstimateType_currentOperationCost           8
+#define Z_EstimateType_finalOperationCost             9
+#define Z_EstimateType_currentAssocCost              10
+#define Z_EstimateType_finalOpTimeElapsed            11
+#define Z_EstimateType_percentComplete               12
+#define Z_EstimateType_currentSearchAssCost          13
+#define Z_EstimateType_currentPresentAssCost         14
+#define Z_EstimateType_currentConnectAssCost         15
+#define Z_EstimateType_currentOtherAssCost           16
+
+typedef struct Z_Estimate1
+{
+    int *type;
+    int *value;
+    int *currencyCode;             /* OPTIONAL */
+} Z_Estimate1;
+
+typedef struct Z_ResourceReport1
+{
+    int num_estimates;
+    Z_Estimate1 **estimates;
+    char *message;
+} Z_ResourceReport1;
+
+int z_ResourceReport1(ODR o, Z_ResourceReport1 **p, int opt, const char *name);
+
+/* -------------------- Resource-2 -------------------- */
+
+typedef struct Z_Estimate2
+{
+    Z_StringOrNumeric *type;      /* same as in estimate1, if numeric */
+    Z_IntUnit *value;
+} Z_Estimate2;
+
+typedef struct Z_ResourceReport2
+{
+    int num_estimates;
+    Z_Estimate2 **estimates;             /* OPTIONAL */
+    char *message;                       /* OPTIONAL */
+} Z_ResourceReport2;
+
+int z_ResourceReport2(ODR o, Z_ResourceReport2 **p, int opt, const char *name);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
Index: /main/tags/2.25/gsdl/packages/yaz/include/yaz/prt-univ.h
===================================================================
--- /main/tags/2.25/gsdl/packages/yaz/include/yaz/prt-univ.h	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/yaz/include/yaz/prt-univ.h	(revision 21064)
@@ -0,0 +1,76 @@
+/*
+ * Copyright (c) 1998
+ *
+ * Permission to use, copy, modify, distribute, and sell this software and
+ * its documentation, in whole or in part, for any purpose, is hereby granted,
+ * provided that:
+ *
+ * 1. This copyright and permission notice appear in all copies of the
+ * software and its documentation. Notices of copyright or attribution
+ * which appear at the beginning of any file must remain unchanged.
+ *
+ * 2. The names of Index Data or the individual authors may not be used to
+ * endorse or promote products derived from this software without specific
+ * prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED "AS IS" AND WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS, IMPLIED, OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY
+ * WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
+ * IN NO EVENT SHALL INDEX DATA BE LIABLE FOR ANY SPECIAL, INCIDENTAL,
+ * INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND, OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER OR
+ * NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF
+ * LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
+ * OF THIS SOFTWARE.
+ *
+ */
+
+#ifndef PRT_UNIV_H
+#define PRT_UNIV_H
+
+#include <yaz/yconfig.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* YC 0.1: Fri Mar 20 14:28:54 CET 1998 */
+/* Module-H ResourceReport-Format-Universe-1 */
+
+typedef struct Z_UniverseReportHits Z_UniverseReportHits;
+int z_UniverseReportHits (ODR o, Z_UniverseReportHits **p, int opt,
+			  const char *name);
+
+typedef struct Z_UniverseReportDuplicate Z_UniverseReportDuplicate;
+int z_UniverseReportDuplicate (ODR o, Z_UniverseReportDuplicate **p, int opt,
+			       const char *name);
+
+typedef struct Z_UniverseReport Z_UniverseReport;
+int z_UniverseReport (ODR o, Z_UniverseReport **p, int opt,
+		      const char *name);
+
+struct Z_UniverseReportHits {
+	Z_StringOrNumeric *database;
+	Z_StringOrNumeric *hits;
+};
+
+struct Z_UniverseReportDuplicate {
+	Z_StringOrNumeric *hitno;
+};
+
+struct Z_UniverseReport {
+	int *totalHits;
+	int which;
+	union {
+		Z_UniverseReportHits *databaseHits;
+		Z_UniverseReportDuplicate *duplicate;
+#define Z_UniverseReport_databaseHits 1
+#define Z_UniverseReport_duplicate 2
+	} u;
+};
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
Index: /main/tags/2.25/gsdl/packages/yaz/include/yaz/readconf.h
===================================================================
--- /main/tags/2.25/gsdl/packages/yaz/include/yaz/readconf.h	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/yaz/include/yaz/readconf.h	(revision 21064)
@@ -0,0 +1,19 @@
+
+#ifndef READCONF_H
+#define READCONF_H
+
+#include <stdio.h>
+#include <yaz/yconfig.h>
+
+YAZ_BEGIN_CDECL
+    
+YAZ_EXPORT int readconf(char *name, void *rprivate,
+                        int (*fun)(char *name, void *rprivate,
+				   int argc, char *argv[]));
+
+YAZ_EXPORT int readconf_line(FILE *f, int *lineno,
+			     char *line, int len, char *argv[], int num);
+    
+YAZ_END_CDECL
+
+#endif
Index: /main/tags/2.25/gsdl/packages/yaz/include/yaz/statserv.h
===================================================================
--- /main/tags/2.25/gsdl/packages/yaz/include/yaz/statserv.h	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/yaz/include/yaz/statserv.h	(revision 21064)
@@ -0,0 +1,149 @@
+/*
+ * Copyright (c) 1995-2000, Index Data.
+ *
+ * Permission to use, copy, modify, distribute, and sell this software and
+ * its documentation, in whole or in part, for any purpose, is hereby granted,
+ * provided that:
+ *
+ * 1. This copyright and permission notice appear in all copies of the
+ * software and its documentation. Notices of copyright or attribution
+ * which appear at the beginning of any file must remain unchanged.
+ *
+ * 2. The name of Index Data or the individual authors may not be used to
+ * endorse or promote products derived from this software without specific
+ * prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED "AS IS" AND WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS, IMPLIED, OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY
+ * WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
+ * IN NO EVENT SHALL INDEX DATA BE LIABLE FOR ANY SPECIAL, INCIDENTAL,
+ * INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND, OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER OR
+ * NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF
+ * LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
+ * OF THIS SOFTWARE.
+ *
+ * $Log$
+ * Revision 1.1  2000/08/03 03:10:50  johnmcp
+ * Added the YAZ toolkit source to the packages directory (for z39.50 stuff)
+ *
+ * Revision 1.2  2000/02/28 11:20:06  adam
+ * Using autoconf. New definitions: YAZ_BEGIN_CDECL/YAZ_END_CDECL.
+ *
+ * Revision 1.1  1999/11/30 13:47:11  adam
+ * Improved installation. Moved header files to include/yaz.
+ *
+ * Revision 1.17  1999/07/06 12:17:15  adam
+ * Added option -1 that runs server once (for profiling purposes).
+ *
+ * Revision 1.16  1999/06/10 11:45:30  adam
+ * Added bend_start, bend_stop handlers and removed pre_init.
+ * Handlers bend_start/bend_stop are called when service/daemon is
+ * started/stopped.
+ *
+ * Revision 1.15  1999/04/16 14:45:55  adam
+ * Added interface for tcpd wrapper for access control.
+ *
+ * Revision 1.14  1999/02/02 13:57:32  adam
+ * Uses preprocessor define WIN32 instead of WINDOWS to build code
+ * for Microsoft WIN32.
+ *
+ * Revision 1.13  1998/02/10 10:28:56  adam
+ * Added app_name, service_dependencies, service_display_name and
+ * options_func. options_func allows us to specify a different function
+ * to interogate the command line arguments. The other members allow us
+ * to pass the full service details accross to the service manager (CW).
+ *
+ * Revision 1.??? 1997/12/18   Chas
+ * Added app_name, service_dependencies, service_display_name and 
+ * options_func. options_func allows us to specify a different function 
+ * to interogate the command line arguments. The other members allow us
+ * to pass the full service details accross to the service manager.
+ *
+ * Revision 1.12  1997/11/07 13:31:47  adam
+ * Added NT Service name part of statserv_options_block. Moved NT
+ * service utility to server library.
+ *
+ * Revision 1.11  1997/10/27 14:03:01  adam
+ * Added new member to statserver_options_block, pre_init, which
+ * specifies a callback to be invoked after command line parsing and
+ * before the server listens for the first time.
+ *
+ * Revision 1.10  1997/09/01 09:31:26  adam
+ * Removed definition statserv_remove to eventl.h. (A hack really).
+ *
+ * Revision 1.9  1997/09/01 08:49:53  adam
+ * New windows NT/95 port using MSV5.0. To export DLL functions the
+ * YAZ_EXPORT modifier was added. Defined in yconfig.h.
+ *
+ * Revision 1.8  1997/05/14 06:53:51  adam
+ * C++ support.
+ *
+ * Revision 1.7  1995/09/29 17:12:12  quinn
+ * Smallish
+ *
+ * Revision 1.6  1995/09/27  15:02:53  quinn
+ * Modified function heads & prototypes.
+ *
+ * Revision 1.5  1995/06/19  12:38:31  quinn
+ * Reorganized include-files. Added small features.
+ *
+ * Revision 1.4  1995/06/15  07:45:08  quinn
+ * Moving to v3.
+ *
+ * Revision 1.3  1995/05/16  08:50:38  quinn
+ * License, documentation, and memory fixes
+ *
+ *
+ */
+
+#ifndef STATSERVER_H
+#define STATSERVER_H
+
+#include <yaz/yconfig.h>
+#include <yaz/odr.h>
+#include <yaz/oid.h>
+
+YAZ_BEGIN_CDECL
+    
+typedef struct statserv_options_block
+{
+    int dynamic;                  /* fork on incoming requests */
+    int one_shot;                 /* one session then exit(1) */
+    int loglevel;                 /* desired logging-level */
+    char apdufile[ODR_MAXNAME+1]; /* file for pretty-printed PDUs */
+    char logfile[ODR_MAXNAME+1];  /* file for diagnostic output */
+    char default_listen[1024];    /* 0 == no default listen */
+    enum oid_proto default_proto; /* PROTO_SR or PROTO_Z3950 */
+    int idle_timeout;             /* how many minutes to wait before closing */
+    int maxrecordsize;            /* maximum value for negotiation */
+    char configname[ODR_MAXNAME+1];  /* given to the backend in bend_init */
+    char setuid[ODR_MAXNAME+1];     /* setuid to this user after binding */
+    void (*bend_start)(struct statserv_options_block *p);
+    void (*bend_stop)(struct statserv_options_block *p);
+    int (*options_func)(int argc, char **argv);
+    int (*check_ip)(void *cd, const char *addr, int len, int type);
+    char daemon_name[128];
+    int inetd;                    /* Do we use the inet deamon or not */
+    
+#ifdef WIN32
+    /* We only have these members for the windows version */
+    /* They seemed a bit large to have them there in general */
+    char service_name[128];         /* NT Service Name */
+    char app_name[128];             /* Application Name */
+    char service_dependencies[128]; /* The services we are dependent on */
+    char service_display_name[128]; /* The service display name */
+#endif /* WIN32 */
+} statserv_options_block;
+    
+int statserv_main(int argc, char **argv);
+int statserv_start(int argc, char **argv);
+void statserv_closedown(void);
+statserv_options_block *statserv_getcontrol(void);
+void statserv_setcontrol(statserv_options_block *block);
+
+int check_ip_tcpd(void *cd, const char *addr, int len, int type);
+
+YAZ_END_CDECL
+
+#endif
Index: /main/tags/2.25/gsdl/packages/yaz/include/yaz/tcpip.h
===================================================================
--- /main/tags/2.25/gsdl/packages/yaz/include/yaz/tcpip.h	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/yaz/include/yaz/tcpip.h	(revision 21064)
@@ -0,0 +1,104 @@
+/*
+ * Copyright (c) 1995-2000, Index Data.
+ *
+ * Permission to use, copy, modify, distribute, and sell this software and
+ * its documentation, in whole or in part, for any purpose, is hereby granted,
+ * provided that:
+ *
+ * 1. This copyright and permission notice appear in all copies of the
+ * software and its documentation. Notices of copyright or attribution
+ * which appear at the beginning of any file must remain unchanged.
+ *
+ * 2. The name of Index Data or the individual authors may not be used to
+ * endorse or promote products derived from this software without specific
+ * prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED "AS IS" AND WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS, IMPLIED, OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY
+ * WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
+ * IN NO EVENT SHALL INDEX DATA BE LIABLE FOR ANY SPECIAL, INCIDENTAL,
+ * INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND, OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER OR
+ * NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF
+ * LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
+ * OF THIS SOFTWARE.
+ *
+ * $Log$
+ * Revision 1.1  2000/08/03 03:10:51  johnmcp
+ * Added the YAZ toolkit source to the packages directory (for z39.50 stuff)
+ *
+ * Revision 1.2  2000/02/28 11:20:06  adam
+ * Using autoconf. New definitions: YAZ_BEGIN_CDECL/YAZ_END_CDECL.
+ *
+ * Revision 1.1  1999/11/30 13:47:11  adam
+ * Improved installation. Moved header files to include/yaz.
+ *
+ * Revision 1.13  1999/06/16 11:55:24  adam
+ * Added APDU log to client.
+ *
+ * Revision 1.12  1999/01/08 11:23:19  adam
+ * Added const modifier to some of the BER/ODR encoding routines.
+ *
+ * Revision 1.11  1998/06/22 11:32:38  adam
+ * Added 'conditional cs_listen' feature.
+ *
+ * Revision 1.10  1998/05/18 13:07:01  adam
+ * Changed the way attribute sets are handled by the retriaval module.
+ * Extended Explain conversion / schema.
+ * Modified server and client to work with ASN.1 compiled protocol handlers.
+ *
+ * Revision 1.9  1997/09/01 08:49:54  adam
+ * New windows NT/95 port using MSV5.0. To export DLL functions the
+ * YAZ_EXPORT modifier was added. Defined in yconfig.h.
+ *
+ * Revision 1.8  1997/05/14 06:53:52  adam
+ * C++ support.
+ *
+ * Revision 1.7  1996/07/06 19:58:32  quinn
+ * System headerfiles gathered in yconfig
+ *
+ * Revision 1.6  1996/02/10  12:23:42  quinn
+ * Enable inetd operations fro TCP/IP stack
+ *
+ * Revision 1.5  1995/09/29  17:12:13  quinn
+ * Smallish
+ *
+ * Revision 1.4  1995/09/28  10:12:36  quinn
+ * Windows-support changes
+ *
+ * Revision 1.3  1995/09/27  15:02:53  quinn
+ * Modified function heads & prototypes.
+ *
+ * Revision 1.2  1995/05/16  08:50:39  quinn
+ * License, documentation, and memory fixes
+ *
+ * Revision 1.1  1995/03/30  09:39:43  quinn
+ * Moved .h files to include directory
+ *
+ * Revision 1.3  1995/03/27  08:36:11  quinn
+ * Some work on nonblocking operation in xmosi.c and rfct.c.
+ * Added protocol parameter to cs_create()
+ *
+ * Revision 1.2  1995/03/14  10:28:43  quinn
+ * Adding server-side support to tcpip.c and fixing bugs in nonblocking I/O
+ *
+ * Revision 1.1  1995/02/09  15:51:52  quinn
+ * Works better now.
+ *
+ */
+
+#ifndef TCPIP_H
+#define TCPIP_H
+
+#include <yaz/comstack.h>
+#include <yaz/oid.h>
+
+YAZ_BEGIN_CDECL
+
+YAZ_EXPORT int completeWAIS(const unsigned char *buf, int len);
+YAZ_EXPORT struct sockaddr_in *tcpip_strtoaddr(const char *str);
+YAZ_EXPORT COMSTACK tcpip_type(int s, int blocking, int protocol);
+
+YAZ_END_CDECL
+
+#endif
Index: /main/tags/2.25/gsdl/packages/yaz/include/yaz/tpath.h
===================================================================
--- /main/tags/2.25/gsdl/packages/yaz/include/yaz/tpath.h	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/yaz/include/yaz/tpath.h	(revision 21064)
@@ -0,0 +1,55 @@
+/*
+ * Copyright (c) 1995-2000, Index Data.
+ *
+ * Permission to use, copy, modify, distribute, and sell this software and
+ * its documentation, in whole or in part, for any purpose, is hereby granted,
+ * provided that:
+ *
+ * 1. This copyright and permission notice appear in all copies of the
+ * software and its documentation. Notices of copyright or attribution
+ * which appear at the beginning of any file must remain unchanged.
+ *
+ * 2. The names of Index Data or the individual authors may not be used to
+ * endorse or promote products derived from this software without specific
+ * prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED "AS IS" AND WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS, IMPLIED, OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY
+ * WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
+ * IN NO EVENT SHALL INDEX DATA BE LIABLE FOR ANY SPECIAL, INCIDENTAL,
+ * INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND, OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER OR
+ * NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF
+ * LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
+ * OF THIS SOFTWARE.
+ *
+ * $Log$
+ * Revision 1.1  2000/08/03 03:10:51  johnmcp
+ * Added the YAZ toolkit source to the packages directory (for z39.50 stuff)
+ *
+ * Revision 1.2  2000/02/28 11:20:06  adam
+ * Using autoconf. New definitions: YAZ_BEGIN_CDECL/YAZ_END_CDECL.
+ *
+ * Revision 1.1  1999/11/30 13:47:11  adam
+ * Improved installation. Moved header files to include/yaz.
+ *
+ * Revision 1.4  1997/10/31 12:20:08  adam
+ * Improved memory debugging for xmalloc/nmem.c. References to NMEM
+ * instead of ODR in n ESPEC-1 handling in source d1_espec.c.
+ * Bug fix: missing fclose in data1_read_espec1.
+ *
+ */
+
+#ifndef TPATH_H
+#define TPATH_H
+
+#include <yaz/yconfig.h>
+
+YAZ_BEGIN_CDECL
+
+YAZ_EXPORT FILE *yaz_path_fopen(const char *path,
+				const char *name, const char *mode);
+
+YAZ_END_CDECL
+
+#endif
Index: /main/tags/2.25/gsdl/packages/yaz/include/yaz/wrbuf.h
===================================================================
--- /main/tags/2.25/gsdl/packages/yaz/include/yaz/wrbuf.h	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/yaz/include/yaz/wrbuf.h	(revision 21064)
@@ -0,0 +1,82 @@
+/*
+ * Copyright (c) 1995-2000, Index Data.
+ *
+ * Permission to use, copy, modify, distribute, and sell this software and
+ * its documentation, in whole or in part, for any purpose, is hereby granted,
+ * provided that:
+ *
+ * 1. This copyright and permission notice appear in all copies of the
+ * software and its documentation. Notices of copyright or attribution
+ * which appear at the beginning of any file must remain unchanged.
+ *
+ * 2. The names of Index Data or the individual authors may not be used to
+ * endorse or promote products derived from this software without specific
+ * prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED "AS IS" AND WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS, IMPLIED, OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY
+ * WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
+ * IN NO EVENT SHALL INDEX DATA BE LIABLE FOR ANY SPECIAL, INCIDENTAL,
+ * INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND, OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER OR
+ * NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF
+ * LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
+ * OF THIS SOFTWARE.
+ *
+ * $Log$
+ * Revision 1.1  2000/08/03 03:10:52  johnmcp
+ * Added the YAZ toolkit source to the packages directory (for z39.50 stuff)
+ *
+ * Revision 1.2  2000/02/28 11:20:06  adam
+ * Using autoconf. New definitions: YAZ_BEGIN_CDECL/YAZ_END_CDECL.
+ *
+ * Revision 1.1  1999/11/30 13:47:11  adam
+ * Improved installation. Moved header files to include/yaz.
+ *
+ * Revision 1.8  1999/11/03 09:05:56  adam
+ * Implemented wrbuf_puts.
+ *
+ * Revision 1.7  1999/08/27 09:40:32  adam
+ * Renamed logf function to yaz_log. Removed VC++ project files.
+ *
+ * Revision 1.6  1997/10/31 12:20:08  adam
+ * Improved memory debugging for xmalloc/nmem.c. References to NMEM
+ * instead of ODR in n ESPEC-1 handling in source d1_espec.c.
+ * Bug fix: missing fclose in data1_read_espec1.
+ *
+ * Revision 1.5  1997/09/17 12:10:32  adam
+ * YAZ version 1.4.
+ *
+ */
+
+#ifndef WRBUF_H
+#define WRBUF_H
+
+#include <yaz/xmalloc.h>
+
+YAZ_BEGIN_CDECL
+
+typedef struct wrbuf
+{
+    char *buf;
+    int pos;
+    int size;
+} wrbuf, *WRBUF;
+
+YAZ_EXPORT WRBUF wrbuf_alloc(void);
+YAZ_EXPORT void wrbuf_free(WRBUF b, int free_buf);
+YAZ_EXPORT void wrbuf_rewind(WRBUF b);
+YAZ_EXPORT int wrbuf_grow(WRBUF b, int minsize);
+YAZ_EXPORT int wrbuf_write(WRBUF b, const char *buf, int size);
+YAZ_EXPORT int wrbuf_puts(WRBUF b, const char *buf);
+
+#define wrbuf_len(b) ((b)->pos)
+#define wrbuf_buf(b) ((b)->buf)
+
+#define wrbuf_putc(b, c) \
+    (((b)->pos >= (b)->size ? wrbuf_grow(b, 1) : 0),  \
+    (b)->buf[(b)->pos++] = (c), 0)
+
+YAZ_END_CDECL
+
+#endif
Index: /main/tags/2.25/gsdl/packages/yaz/include/yaz/xmalloc.h
===================================================================
--- /main/tags/2.25/gsdl/packages/yaz/include/yaz/xmalloc.h	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/yaz/include/yaz/xmalloc.h	(revision 21064)
@@ -0,0 +1,113 @@
+/*
+ * Copyright (c) 1995-2000, Index Data.
+ *
+ * Permission to use, copy, modify, distribute, and sell this software and
+ * its documentation, in whole or in part, for any purpose, is hereby granted,
+ * provided that:
+ *
+ * 1. This copyright and permission notice appear in all copies of the
+ * software and its documentation. Notices of copyright or attribution
+ * which appear at the beginning of any file must remain unchanged.
+ *
+ * 2. The names of Index Data or the individual authors may not be used to
+ * endorse or promote products derived from this software without specific
+ * prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED "AS IS" AND WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS, IMPLIED, OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY
+ * WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
+ * IN NO EVENT SHALL INDEX DATA BE LIABLE FOR ANY SPECIAL, INCIDENTAL,
+ * INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND, OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER OR
+ * NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF
+ * LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
+ * OF THIS SOFTWARE.
+ *
+ * $Log$
+ * Revision 1.1  2000/08/03 03:10:52  johnmcp
+ * Added the YAZ toolkit source to the packages directory (for z39.50 stuff)
+ *
+ * Revision 1.2  2000/02/28 11:20:06  adam
+ * Using autoconf. New definitions: YAZ_BEGIN_CDECL/YAZ_END_CDECL.
+ *
+ * Revision 1.1  1999/11/30 13:47:11  adam
+ * Improved installation. Moved header files to include/yaz.
+ *
+ * Revision 1.6  1999/07/13 13:24:53  adam
+ * Updated memory debugging memory allocatation routines.
+ *
+ * Revision 1.5  1998/07/20 12:36:22  adam
+ * Minor changes.
+ *
+ * Revision 1.4  1997/10/31 12:20:08  adam
+ * Improved memory debugging for xmalloc/nmem.c. References to NMEM
+ * instead of ODR in n ESPEC-1 handling in source d1_espec.c.
+ * Bug fix: missing fclose in data1_read_espec1.
+ *
+ * Revision 1.3  1997/09/01 08:49:54  adam
+ * New windows NT/95 port using MSV5.0. To export DLL functions the
+ * YAZ_EXPORT modifier was added. Defined in yconfig.h.
+ *
+ * Revision 1.2  1997/05/14 06:53:53  adam
+ * C++ support.
+ *
+ * Revision 1.1  1995/11/01 11:55:41  quinn
+ * Added xmalloc.c
+ *
+ * Revision 1.8  1995/10/16  14:03:07  quinn
+ * Changes to support element set names and espec1
+ *
+ * Revision 1.7  1994/10/05  10:15:18  quinn
+ * Added xrealloc.
+ *
+ * Revision 1.6  1994/09/26  16:31:24  adam
+ * Minor changes. xmalloc declares xcalloc now.
+ *
+ * Revision 1.5  1994/09/19  15:46:34  quinn
+ * Added stdlib.h
+ *
+ * Revision 1.4  1994/08/18  08:22:27  adam
+ * Res.h modified. xmalloc now declares xstrdup.
+ *
+ * Revision 1.3  1994/08/17  15:34:15  adam
+ * Initial version of resource manager.
+ *
+ * Revision 1.2  1994/08/17  14:09:48  quinn
+ * Small changes
+ *
+ * Revision 1.1  1994/08/17  13:39:07  adam
+ * Added xmalloc header.
+ *
+ * Revision 1.1  1994/08/16  16:16:02  adam
+ * bfile header created.
+ *
+ */
+
+#ifndef XMALLOC_H
+#define XMALLOC_H
+
+#include <sys/types.h>
+#include <stdlib.h>
+
+#include <yaz/yconfig.h>
+
+YAZ_BEGIN_CDECL
+
+#define xrealloc(o, x) xrealloc_f(o, x, __FILE__, __LINE__)
+#define xmalloc(x) xmalloc_f(x, __FILE__, __LINE__)
+#define xcalloc(x,y) xcalloc_f(x,y, __FILE__, __LINE__)
+#define xfree(x) xfree_f(x, __FILE__, __LINE__)
+#define xstrdup(s) xstrdup_f(s, __FILE__, __LINE__)
+#define xmalloc_trav(s) xmalloc_trav_f(s, __FILE__, __LINE__)
+    
+YAZ_EXPORT void *xrealloc_f (void *o, size_t size, const char *file, int line);
+YAZ_EXPORT void *xmalloc_f (size_t size, const char *file, int line);
+YAZ_EXPORT void *xcalloc_f (size_t nmemb, size_t size,
+			    const char *file, int line);
+YAZ_EXPORT char *xstrdup_f (const char *p, const char *file, int line);
+YAZ_EXPORT void xfree_f (void *p, const char *file, int line);
+YAZ_EXPORT void xmalloc_trav_f(const char *s, const char *file, int line);
+
+YAZ_END_CDECL
+
+#endif
Index: /main/tags/2.25/gsdl/packages/yaz/include/yaz/yaz-ccl.h
===================================================================
--- /main/tags/2.25/gsdl/packages/yaz/include/yaz/yaz-ccl.h	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/yaz/include/yaz/yaz-ccl.h	(revision 21064)
@@ -0,0 +1,78 @@
+/*
+ * Copyright (c) 1995-2000, Index Data.
+ *
+ * Permission to use, copy, modify, distribute, and sell this software and
+ * its documentation, in whole or in part, for any purpose, is hereby granted,
+ * provided that:
+ *
+ * 1. This copyright and permission notice appear in all copies of the
+ * software and its documentation. Notices of copyright or attribution
+ * which appear at the beginning of any file must remain unchanged.
+ *
+ * 2. The name of Index Data or the individual authors may not be used to
+ * endorse or promote products derived from this software without specific
+ * prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED "AS IS" AND WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS, IMPLIED, OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY
+ * WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
+ * IN NO EVENT SHALL INDEX DATA BE LIABLE FOR ANY SPECIAL, INCIDENTAL,
+ * INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND, OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER OR
+ * NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF
+ * LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
+ * OF THIS SOFTWARE.
+ *
+ * $Log$
+ * Revision 1.1  2000/08/03 03:10:53  johnmcp
+ * Added the YAZ toolkit source to the packages directory (for z39.50 stuff)
+ *
+ * Revision 1.3  2000/02/28 11:20:06  adam
+ * Using autoconf. New definitions: YAZ_BEGIN_CDECL/YAZ_END_CDECL.
+ *
+ * Revision 1.2  1999/12/20 15:20:13  adam
+ * Implemented ccl_pquery to convert from CCL tree to prefix query.
+ *
+ * Revision 1.1  1999/11/30 13:47:11  adam
+ * Improved installation. Moved header files to include/yaz.
+ *
+ * Revision 1.8  1997/09/01 08:49:54  adam
+ * New windows NT/95 port using MSV5.0. To export DLL functions the
+ * YAZ_EXPORT modifier was added. Defined in yconfig.h.
+ *
+ * Revision 1.7  1997/06/23 10:30:45  adam
+ * Added ODR stream as parameter to ccl_rpn_query and ccl_scan_query.
+ *
+ * Revision 1.6  1997/05/14 06:53:54  adam
+ * C++ support.
+ *
+ * Revision 1.5  1995/09/29 17:12:14  quinn
+ * Smallish
+ *
+ * Revision 1.4  1995/09/27  15:02:54  quinn
+ * Modified function heads & prototypes.
+ *
+ * Revision 1.3  1995/05/16  08:50:40  quinn
+ * License, documentation, and memory fixes
+ *
+ *
+ */
+
+#ifndef YAZ_CCL_H
+#define YAZ_CCL_H
+
+#include <yaz/yconfig.h>
+#include <yaz/proto.h>
+#include <yaz/ccl.h>
+#include <yaz/odr.h>
+#include <yaz/yaz-util.h>
+
+YAZ_BEGIN_CDECL
+
+YAZ_EXPORT Z_RPNQuery *ccl_rpn_query (ODR o, struct ccl_rpn_node *p);
+YAZ_EXPORT Z_AttributesPlusTerm *ccl_scan_query (ODR o, struct ccl_rpn_node *p);
+YAZ_EXPORT void ccl_pquery (WRBUF w, struct ccl_rpn_node *p);
+
+YAZ_END_CDECL
+
+#endif
Index: /main/tags/2.25/gsdl/packages/yaz/include/yaz/yaz-util.h
===================================================================
--- /main/tags/2.25/gsdl/packages/yaz/include/yaz/yaz-util.h	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/yaz/include/yaz/yaz-util.h	(revision 21064)
@@ -0,0 +1,55 @@
+/*
+ * Copyright (c) 1995-2000, Index Data.
+ * See the file LICENSE for details.
+ * Sebastian Hammer, Adam Dickmeiss
+ *
+ * $Log$
+ * Revision 1.1  2000/08/03 03:10:53  johnmcp
+ * Added the YAZ toolkit source to the packages directory (for z39.50 stuff)
+ *
+ * Revision 1.2  2000/02/28 11:20:06  adam
+ * Using autoconf. New definitions: YAZ_BEGIN_CDECL/YAZ_END_CDECL.
+ *
+ * Revision 1.1  1999/11/30 13:47:11  adam
+ * Improved installation. Moved header files to include/yaz.
+ *
+ * Revision 1.6  1997/10/27 13:52:46  adam
+ * Header yaz-util includes all YAZ utility header files.
+ *
+ * Revision 1.5  1997/09/04 07:58:36  adam
+ * Added prototype for atoi_n.
+ *
+ * Revision 1.4  1997/09/01 08:49:54  adam
+ * New windows NT/95 port using MSV5.0. To export DLL functions the
+ * YAZ_EXPORT modifier was added. Defined in yconfig.h.
+ *
+ * Revision 1.3  1997/05/14 06:53:54  adam
+ * C++ support.
+ *
+ * Revision 1.2  1996/02/20 17:58:09  adam
+ * Added const to yaz_matchstr.
+ *
+ * Revision 1.1  1996/02/20  16:32:49  quinn
+ * Created util file.
+ */
+
+#ifndef YAZ_UTIL_H
+#define YAZ_UTIL_H
+
+#include <yaz/yconfig.h>
+#include <yaz/xmalloc.h>
+#include <yaz/log.h>
+#include <yaz/tpath.h>
+#include <yaz/options.h>
+#include <yaz/wrbuf.h>
+#include <yaz/nmem.h>
+#include <yaz/readconf.h>
+
+YAZ_BEGIN_CDECL
+
+YAZ_EXPORT int yaz_matchstr(const char *s1, const char *s2);
+YAZ_EXPORT int atoi_n (const char *buf, int len);
+
+YAZ_END_CDECL
+
+#endif
Index: /main/tags/2.25/gsdl/packages/yaz/include/yaz/yaz-version.h
===================================================================
--- /main/tags/2.25/gsdl/packages/yaz/include/yaz/yaz-version.h	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/yaz/include/yaz/yaz-version.h	(revision 21064)
@@ -0,0 +1,93 @@
+/*
+ * Current software version.
+ *
+ * $Log$
+ * Revision 1.1  2000/08/03 03:10:54  johnmcp
+ * Added the YAZ toolkit source to the packages directory (for z39.50 stuff)
+ *
+ * Revision 1.2  2000/02/28 11:20:06  adam
+ * Using autoconf. New definitions: YAZ_BEGIN_CDECL/YAZ_END_CDECL.
+ *
+ * Revision 1.1  1999/11/30 13:47:11  adam
+ * Improved installation. Moved header files to include/yaz.
+ *
+ * Revision 1.18  1998/06/26 11:17:23  quinn
+ * v2+
+ *
+ * Revision 1.17  1998/01/30 15:32:57  adam
+ * 1.4pl2.
+ *
+ * Revision 1.16  1998/01/29 13:28:23  adam
+ * YAZ version 1.4pl1.
+ *
+ * Revision 1.15  1997/09/17 12:10:33  adam
+ * YAZ version 1.4.
+ *
+ * Revision 1.14  1997/04/30 08:52:09  quinn
+ * Null
+ *
+ * Revision 1.13  1996/10/11  15:06:55  quinn
+ * Version 1.3
+ *
+ * Revision 1.12  1996/06/10  08:57:50  quinn
+ * 1.2
+ *
+ * Revision 1.11  1996/04/10  11:40:33  quinn
+ * 1.1pl2
+ *
+ * Revision 1.10  1996/02/20  12:57:45  quinn
+ * V1.1
+ *
+ * Revision 1.9  1996/01/24  16:01:24  quinn
+ * pl4
+ *
+ * Revision 1.8  1996/01/02  11:46:50  quinn
+ * Changed 'operator' to 'roperator' to avoid C++ conflict.
+ * Moved to pl3
+ *
+ * Revision 1.7  1995/12/06  15:50:42  quinn
+ * 1.0pl2
+ *
+ * Revision 1.6  1995/12/05  11:15:57  quinn
+ * 1.0pl1
+ *
+ * Revision 1.5  1995/11/28  09:31:22  quinn
+ * Version 1.0
+ *
+ * Revision 1.4  1995/08/24  15:13:18  quinn
+ * Beta 3
+ *
+ * Revision 1.3  1995/06/27  13:12:07  quinn
+ * v1.0b2
+ * See CHANGELOG for update info now.
+ *
+ * Revision 1.2  1995/06/19  13:39:16  quinn
+ * 1.0 beta
+ * All of basic 1995 should be in place at this point. Some little features
+ * added to make the server more useful. BER dumper for bad protocol debugging.
+ * Etc. First major release. All following releases should come with
+ * a changelog.
+ *
+ * Revision 1.1  1995/06/14  12:34:55  quinn
+ * Moved version.h to include/
+ *
+ * Revision 1.4  1995/06/07  14:43:57  quinn
+ * Various work towards first public release. Specifically, the CLOSE
+ * service has been added.
+ *
+ * Revision 1.3  1995/05/29  09:52:38  quinn
+ * Second pre-release.
+ *
+ * Revision 1.2  1995/05/16  10:22:47  quinn
+ * 0.1 beta
+ * Fairly stable version with structure in place for asynchronous server
+ * activity (the backend doesn't have complete support for this yet).
+ *
+ * Revision 1.1  1995/05/16  08:49:38  quinn
+ * Introduced version control
+ *
+ */
+#ifndef YAZ_VERSION
+#define YAZ_VERSION "1.6"
+#endif
+
Index: /main/tags/2.25/gsdl/packages/yaz/include/yaz/yaz_zclient.h
===================================================================
--- /main/tags/2.25/gsdl/packages/yaz/include/yaz/yaz_zclient.h	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/yaz/include/yaz/yaz_zclient.h	(revision 21064)
@@ -0,0 +1,28 @@
+#ifndef YAZ_ZCLIENT_H
+#define YAZ_ZCLIENT_H
+/*#include "../include/yaz/z-core.h"*/
+
+extern void z_initialize(void);
+
+/* creates a connection, given a host and port, and database name */
+extern int z_cmd_open(char *host_and_port, char *base);
+
+/* returns number of records found */
+extern int z_cmd_dosearch(char *search);
+
+/* returns an array of strings containing record titles. The first element
+   is an int, saying how many titles follow (can be zero). NULL on error. */
+extern char **z_getrecordTitles(int start,int count);
+
+/* returns a string containing the whole marc record */
+extern char *z_getfullRecord(int record);
+
+/* close the connection */
+extern int z_cmd_close(char *arg);
+
+/* returns a string containing name, ID, etc, or NULL if not connected */
+extern char *z_get_initResponse(); 
+
+/* gets a generic response from the server */
+extern int z_getnextAPDU ();
+#endif
Index: /main/tags/2.25/gsdl/packages/yaz/include/yaz/yconfig.h
===================================================================
--- /main/tags/2.25/gsdl/packages/yaz/include/yaz/yconfig.h	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/yaz/include/yaz/yconfig.h	(revision 21064)
@@ -0,0 +1,33 @@
+/*
+ * Copyright (c) 1995-2000, Index Data.
+ * See the file LICENSE for details.
+ *
+ * $Id$
+ */
+
+#ifndef YCONFIG_H
+#define YCONFIG_H
+
+#ifndef YAZ_EXPORT
+# ifdef WIN32
+#  define YAZ_EXPORT __declspec(dllexport)
+# else
+#  define YAZ_EXPORT
+# endif
+#endif
+
+#ifndef WIN32
+# ifndef O_BINARY
+#  define O_BINARY 0
+# endif
+#endif
+
+#ifdef __cplusplus
+#define YAZ_BEGIN_CDECL extern "C" {
+#define YAZ_END_CDECL }
+#else
+#define YAZ_BEGIN_CDECL 
+#define YAZ_END_CDECL 
+#endif
+
+#endif
Index: /main/tags/2.25/gsdl/packages/yaz/include/yaz/z-accdes1.h
===================================================================
--- /main/tags/2.25/gsdl/packages/yaz/include/yaz/z-accdes1.h	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/yaz/include/yaz/z-accdes1.h	(revision 21064)
@@ -0,0 +1,42 @@
+/* Generated automatically by the YAZ ASN.1 Compiler 0.3 */
+/* Module-H AccessControlFormat-des-1 */
+
+#ifndef z_accdes1_H
+#define z_accdes1_H
+
+#include <yaz/odr.h>
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef struct Z_DES_RN_Object Z_DES_RN_Object;
+YAZ_EXPORT int z_DES_RN_Object (ODR o, Z_DES_RN_Object **p, int opt, const char *name);
+
+typedef struct Z_DRNType Z_DRNType;
+YAZ_EXPORT int z_DRNType (ODR o, Z_DRNType **p, int opt, const char *name);
+#ifdef __cplusplus
+}
+#endif
+#ifdef __cplusplus
+extern "C" {
+#endif
+struct Z_DES_RN_Object {
+	int which;
+	union {
+		Z_DRNType *challenge;
+		Z_DRNType *response;
+#define Z_DES_RN_Object_challenge 1
+#define Z_DES_RN_Object_response 2
+	} u;
+};
+
+struct Z_DRNType {
+	Odr_oct *userId; /* OPT */
+	Odr_oct *salt; /* OPT */
+	Odr_oct *randomNumber;
+};
+
+#ifdef __cplusplus
+}
+#endif
+#endif
Index: /main/tags/2.25/gsdl/packages/yaz/include/yaz/z-accform1.h
===================================================================
--- /main/tags/2.25/gsdl/packages/yaz/include/yaz/z-accform1.h	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/yaz/include/yaz/z-accform1.h	(revision 21064)
@@ -0,0 +1,134 @@
+/* Generated automatically by the YAZ ASN.1 Compiler 0.3 */
+/* Module-H AccessControlFormat-prompt-1 */
+
+#ifndef z_accform1_H
+#define z_accform1_H
+
+#include <yaz/odr.h>
+#include <yaz/z-core.h>
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef struct Z_PromptObject1 Z_PromptObject1;
+YAZ_EXPORT int z_PromptObject1 (ODR o, Z_PromptObject1 **p, int opt, const char *name);
+
+typedef struct Z_ChallengeUnit1 Z_ChallengeUnit1;
+YAZ_EXPORT int z_ChallengeUnit1 (ODR o, Z_ChallengeUnit1 **p, int opt, const char *name);
+
+typedef struct Z_Challenge1 Z_Challenge1;
+YAZ_EXPORT int z_Challenge1 (ODR o, Z_Challenge1 **p, int opt, const char *name);
+
+typedef struct Z_ResponseUnit1 Z_ResponseUnit1;
+YAZ_EXPORT int z_ResponseUnit1 (ODR o, Z_ResponseUnit1 **p, int opt, const char *name);
+
+typedef struct Z_Response1 Z_Response1;
+YAZ_EXPORT int z_Response1 (ODR o, Z_Response1 **p, int opt, const char *name);
+
+typedef struct Z_PromptIdEnumeratedPrompt Z_PromptIdEnumeratedPrompt;
+YAZ_EXPORT int z_PromptIdEnumeratedPrompt (ODR o, Z_PromptIdEnumeratedPrompt **p, int opt, const char *name);
+
+typedef struct Z_PromptId Z_PromptId;
+YAZ_EXPORT int z_PromptId (ODR o, Z_PromptId **p, int opt, const char *name);
+
+typedef struct Z_Encryption Z_Encryption;
+YAZ_EXPORT int z_Encryption (ODR o, Z_Encryption **p, int opt, const char *name);
+#ifdef __cplusplus
+}
+#endif
+#ifdef __cplusplus
+extern "C" {
+#endif
+struct Z_PromptObject1 {
+	int which;
+	union {
+		Z_Challenge1 *challenge;
+		Z_Response1 *response;
+#define Z_PromptObject1_challenge 1
+#define Z_PromptObject1_response 2
+	} u;
+};
+
+struct Z_ChallengeUnit1 {
+	Z_PromptId *promptId;
+	Z_InternationalString *defaultResponse; /* OPT */
+	int which;
+	union {
+		Z_InternationalString *character;
+		Z_Encryption *encrypted;
+#define Z_ChallengeUnit1_character 1
+#define Z_ChallengeUnit1_encrypted 2
+	} u; /* OPT */
+	Z_InternationalString *regExpr; /* OPT */
+	Odr_null *responseRequired; /* OPT */
+	int num_allowedValues;
+	Z_InternationalString **allowedValues; /* OPT */
+	Odr_null *shouldSave; /* OPT */
+#define Z_ChallengeUnit1_integer 1
+#define Z_ChallengeUnit1_date 2
+#define Z_ChallengeUnit1_float 3
+#define Z_ChallengeUnit1_alphaNumeric 4
+#define Z_ChallengeUnit1_url_urn 5
+#define Z_ChallengeUnit1_boolean 6
+	int *dataType; /* OPT */
+	Z_External *diagnostic; /* OPT */
+};
+
+struct Z_Challenge1 {
+	int num;
+	Z_ChallengeUnit1 **elements;
+};
+
+struct Z_ResponseUnit1 {
+	Z_PromptId *promptId;
+	int which;
+	union {
+		Z_InternationalString *string;
+		bool_t *accept;
+		Odr_null *acknowledge;
+		Z_DiagRec *diagnostic;
+		Z_Encryption *encrypted;
+#define Z_ResponseUnit1_string 1
+#define Z_ResponseUnit1_accept 2
+#define Z_ResponseUnit1_acknowledge 3
+#define Z_ResponseUnit1_diagnostic 4
+#define Z_ResponseUnit1_encrypted 5
+	} u;
+};
+
+struct Z_Response1 {
+	int num;
+	Z_ResponseUnit1 **elements;
+};
+
+struct Z_PromptIdEnumeratedPrompt {
+#define Z_PromptIdEnumeratedPrompt_groupId 0
+#define Z_PromptIdEnumeratedPrompt_userId 1
+#define Z_PromptIdEnumeratedPrompt_password 2
+#define Z_PromptIdEnumeratedPrompt_newPassword 3
+#define Z_PromptIdEnumeratedPrompt_copyright 4
+#define Z_PromptIdEnumeratedPrompt_sessionId 5
+	int *type;
+	Z_InternationalString *suggestedString; /* OPT */
+};
+
+struct Z_PromptId {
+	int which;
+	union {
+		Z_PromptIdEnumeratedPrompt *enumeratedPrompt;
+		Z_InternationalString *nonEnumeratedPrompt;
+#define Z_PromptId_enumeratedPrompt 1
+#define Z_PromptId_nonEnumeratedPrompt 2
+	} u;
+};
+
+struct Z_Encryption {
+	Odr_oct *cryptType; /* OPT */
+	Odr_oct *credential; /* OPT */
+	Odr_oct *data;
+};
+
+#ifdef __cplusplus
+}
+#endif
+#endif
Index: /main/tags/2.25/gsdl/packages/yaz/include/yaz/z-acckrb1.h
===================================================================
--- /main/tags/2.25/gsdl/packages/yaz/include/yaz/z-acckrb1.h	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/yaz/include/yaz/z-acckrb1.h	(revision 21064)
@@ -0,0 +1,51 @@
+/* Generated automatically by the YAZ ASN.1 Compiler 0.3 */
+/* Module-H AccessControlFormat-krb-1 */
+
+#ifndef z_acckrb1_H
+#define z_acckrb1_H
+
+#include <yaz/odr.h>
+#include <yaz/z-core.h>
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef struct Z_KRBObject Z_KRBObject;
+YAZ_EXPORT int z_KRBObject (ODR o, Z_KRBObject **p, int opt, const char *name);
+
+typedef struct Z_KRBRequest Z_KRBRequest;
+YAZ_EXPORT int z_KRBRequest (ODR o, Z_KRBRequest **p, int opt, const char *name);
+
+typedef struct Z_KRBResponse Z_KRBResponse;
+YAZ_EXPORT int z_KRBResponse (ODR o, Z_KRBResponse **p, int opt, const char *name);
+#ifdef __cplusplus
+}
+#endif
+#ifdef __cplusplus
+extern "C" {
+#endif
+struct Z_KRBObject {
+	int which;
+	union {
+		Z_KRBRequest *challenge;
+		Z_KRBResponse *response;
+#define Z_KRBObject_challenge 1
+#define Z_KRBObject_response 2
+	} u;
+};
+
+struct Z_KRBRequest {
+	Z_InternationalString *service;
+	Z_InternationalString *instance; /* OPT */
+	Z_InternationalString *realm; /* OPT */
+};
+
+struct Z_KRBResponse {
+	Z_InternationalString *userid; /* OPT */
+	Odr_oct *ticket;
+};
+
+#ifdef __cplusplus
+}
+#endif
+#endif
Index: /main/tags/2.25/gsdl/packages/yaz/include/yaz/z-core.h
===================================================================
--- /main/tags/2.25/gsdl/packages/yaz/include/yaz/z-core.h	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/yaz/include/yaz/z-core.h	(revision 21064)
@@ -0,0 +1,1220 @@
+/* Generated automatically by the YAZ ASN.1 Compiler 0.3 */
+/* Module-H Z39-50-APDU-1995 */
+
+#ifndef z_core_H
+#define z_core_H
+
+#include <yaz/odr.h>
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef struct Z_External Z_External;
+YAZ_EXPORT int z_External(ODR o, Z_External **p, int opt, const char *name);
+
+
+typedef struct Z_APDU Z_APDU;
+YAZ_EXPORT int z_APDU (ODR o, Z_APDU **p, int opt, const char *name);
+
+typedef struct Z_InitRequest Z_InitRequest;
+YAZ_EXPORT int z_InitRequest (ODR o, Z_InitRequest **p, int opt, const char *name);
+
+typedef struct Z_IdPass Z_IdPass;
+YAZ_EXPORT int z_IdPass (ODR o, Z_IdPass **p, int opt, const char *name);
+
+typedef struct Z_IdAuthentication Z_IdAuthentication;
+YAZ_EXPORT int z_IdAuthentication (ODR o, Z_IdAuthentication **p, int opt, const char *name);
+
+typedef struct Z_InitResponse Z_InitResponse;
+YAZ_EXPORT int z_InitResponse (ODR o, Z_InitResponse **p, int opt, const char *name);
+
+typedef Odr_bitmask  Z_ProtocolVersion;
+YAZ_EXPORT int z_ProtocolVersion (ODR o, Z_ProtocolVersion **p, int opt, const char *name);
+
+typedef Odr_bitmask  Z_Options;
+YAZ_EXPORT int z_Options (ODR o, Z_Options **p, int opt, const char *name);
+
+typedef struct Z_SearchRequest Z_SearchRequest;
+YAZ_EXPORT int z_SearchRequest (ODR o, Z_SearchRequest **p, int opt, const char *name);
+
+typedef struct Z_Query Z_Query;
+YAZ_EXPORT int z_Query (ODR o, Z_Query **p, int opt, const char *name);
+
+typedef struct Z_RPNQuery Z_RPNQuery;
+YAZ_EXPORT int z_RPNQuery (ODR o, Z_RPNQuery **p, int opt, const char *name);
+
+typedef struct Z_Complex Z_Complex;
+YAZ_EXPORT int z_Complex (ODR o, Z_Complex **p, int opt, const char *name);
+
+typedef struct Z_RPNStructure Z_RPNStructure;
+YAZ_EXPORT int z_RPNStructure (ODR o, Z_RPNStructure **p, int opt, const char *name);
+
+typedef struct Z_Operand Z_Operand;
+YAZ_EXPORT int z_Operand (ODR o, Z_Operand **p, int opt, const char *name);
+
+typedef struct Z_AttributesPlusTerm Z_AttributesPlusTerm;
+YAZ_EXPORT int z_AttributesPlusTerm (ODR o, Z_AttributesPlusTerm **p, int opt, const char *name);
+
+typedef struct Z_ResultSetPlusAttributes Z_ResultSetPlusAttributes;
+YAZ_EXPORT int z_ResultSetPlusAttributes (ODR o, Z_ResultSetPlusAttributes **p, int opt, const char *name);
+
+typedef struct Z_AttributeList Z_AttributeList;
+YAZ_EXPORT int z_AttributeList (ODR o, Z_AttributeList **p, int opt, const char *name);
+
+typedef struct Z_Term Z_Term;
+YAZ_EXPORT int z_Term (ODR o, Z_Term **p, int opt, const char *name);
+
+typedef struct Z_Operator Z_Operator;
+YAZ_EXPORT int z_Operator (ODR o, Z_Operator **p, int opt, const char *name);
+
+typedef struct Z_ComplexAttribute Z_ComplexAttribute;
+YAZ_EXPORT int z_ComplexAttribute (ODR o, Z_ComplexAttribute **p, int opt, const char *name);
+
+typedef struct Z_AttributeElement Z_AttributeElement;
+YAZ_EXPORT int z_AttributeElement (ODR o, Z_AttributeElement **p, int opt, const char *name);
+
+typedef struct Z_ProximityOperator Z_ProximityOperator;
+YAZ_EXPORT int z_ProximityOperator (ODR o, Z_ProximityOperator **p, int opt, const char *name);
+
+typedef int  Z_ProxUnit;
+YAZ_EXPORT int z_ProxUnit (ODR o, Z_ProxUnit **p, int opt, const char *name);
+
+typedef struct Z_SearchResponse Z_SearchResponse;
+YAZ_EXPORT int z_SearchResponse (ODR o, Z_SearchResponse **p, int opt, const char *name);
+
+typedef struct Z_RecordComposition Z_RecordComposition;
+YAZ_EXPORT int z_RecordComposition (ODR o, Z_RecordComposition **p, int opt, const char *name);
+
+typedef struct Z_PresentRequest Z_PresentRequest;
+YAZ_EXPORT int z_PresentRequest (ODR o, Z_PresentRequest **p, int opt, const char *name);
+
+typedef struct Z_Segment Z_Segment;
+YAZ_EXPORT int z_Segment (ODR o, Z_Segment **p, int opt, const char *name);
+
+typedef struct Z_PresentResponse Z_PresentResponse;
+YAZ_EXPORT int z_PresentResponse (ODR o, Z_PresentResponse **p, int opt, const char *name);
+
+typedef struct Z_NamePlusRecordList Z_NamePlusRecordList;
+YAZ_EXPORT int z_NamePlusRecordList (ODR o, Z_NamePlusRecordList **p, int opt, const char *name);
+
+typedef struct Z_DiagRecs Z_DiagRecs;
+YAZ_EXPORT int z_DiagRecs (ODR o, Z_DiagRecs **p, int opt, const char *name);
+
+typedef struct Z_Records Z_Records;
+YAZ_EXPORT int z_Records (ODR o, Z_Records **p, int opt, const char *name);
+
+typedef struct Z_NamePlusRecord Z_NamePlusRecord;
+YAZ_EXPORT int z_NamePlusRecord (ODR o, Z_NamePlusRecord **p, int opt, const char *name);
+
+typedef struct Z_FragmentSyntax Z_FragmentSyntax;
+YAZ_EXPORT int z_FragmentSyntax (ODR o, Z_FragmentSyntax **p, int opt, const char *name);
+
+typedef struct Z_DiagRec Z_DiagRec;
+YAZ_EXPORT int z_DiagRec (ODR o, Z_DiagRec **p, int opt, const char *name);
+
+typedef struct Z_DefaultDiagFormat Z_DefaultDiagFormat;
+YAZ_EXPORT int z_DefaultDiagFormat (ODR o, Z_DefaultDiagFormat **p, int opt, const char *name);
+
+typedef struct Z_Range Z_Range;
+YAZ_EXPORT int z_Range (ODR o, Z_Range **p, int opt, const char *name);
+
+typedef struct Z_DatabaseSpecificUnit Z_DatabaseSpecificUnit;
+YAZ_EXPORT int z_DatabaseSpecificUnit (ODR o, Z_DatabaseSpecificUnit **p, int opt, const char *name);
+
+typedef struct Z_DatabaseSpecific Z_DatabaseSpecific;
+YAZ_EXPORT int z_DatabaseSpecific (ODR o, Z_DatabaseSpecific **p, int opt, const char *name);
+
+typedef struct Z_ElementSetNames Z_ElementSetNames;
+YAZ_EXPORT int z_ElementSetNames (ODR o, Z_ElementSetNames **p, int opt, const char *name);
+
+typedef int  Z_PresentStatus;
+YAZ_EXPORT int z_PresentStatus (ODR o, Z_PresentStatus **p, int opt, const char *name);
+
+typedef struct Z_DbSpecific Z_DbSpecific;
+YAZ_EXPORT int z_DbSpecific (ODR o, Z_DbSpecific **p, int opt, const char *name);
+
+typedef struct Z_CompSpec Z_CompSpec;
+YAZ_EXPORT int z_CompSpec (ODR o, Z_CompSpec **p, int opt, const char *name);
+
+typedef struct Z_ElementSpec Z_ElementSpec;
+YAZ_EXPORT int z_ElementSpec (ODR o, Z_ElementSpec **p, int opt, const char *name);
+
+typedef struct Z_Specification Z_Specification;
+YAZ_EXPORT int z_Specification (ODR o, Z_Specification **p, int opt, const char *name);
+
+typedef struct Z_DeleteResultSetRequest Z_DeleteResultSetRequest;
+YAZ_EXPORT int z_DeleteResultSetRequest (ODR o, Z_DeleteResultSetRequest **p, int opt, const char *name);
+
+typedef struct Z_DeleteResultSetResponse Z_DeleteResultSetResponse;
+YAZ_EXPORT int z_DeleteResultSetResponse (ODR o, Z_DeleteResultSetResponse **p, int opt, const char *name);
+
+typedef struct Z_ListStatus Z_ListStatus;
+YAZ_EXPORT int z_ListStatus (ODR o, Z_ListStatus **p, int opt, const char *name);
+
+typedef struct Z_ListStatuses Z_ListStatuses;
+YAZ_EXPORT int z_ListStatuses (ODR o, Z_ListStatuses **p, int opt, const char *name);
+
+typedef int  Z_DeleteStatus;
+YAZ_EXPORT int z_DeleteStatus (ODR o, Z_DeleteStatus **p, int opt, const char *name);
+
+typedef struct Z_AccessControlRequest Z_AccessControlRequest;
+YAZ_EXPORT int z_AccessControlRequest (ODR o, Z_AccessControlRequest **p, int opt, const char *name);
+
+typedef struct Z_AccessControlResponse Z_AccessControlResponse;
+YAZ_EXPORT int z_AccessControlResponse (ODR o, Z_AccessControlResponse **p, int opt, const char *name);
+
+typedef struct Z_ResourceControlRequest Z_ResourceControlRequest;
+YAZ_EXPORT int z_ResourceControlRequest (ODR o, Z_ResourceControlRequest **p, int opt, const char *name);
+
+typedef struct Z_ResourceControlResponse Z_ResourceControlResponse;
+YAZ_EXPORT int z_ResourceControlResponse (ODR o, Z_ResourceControlResponse **p, int opt, const char *name);
+
+typedef struct Z_TriggerResourceControlRequest Z_TriggerResourceControlRequest;
+YAZ_EXPORT int z_TriggerResourceControlRequest (ODR o, Z_TriggerResourceControlRequest **p, int opt, const char *name);
+
+typedef struct Z_ResourceReportRequest Z_ResourceReportRequest;
+YAZ_EXPORT int z_ResourceReportRequest (ODR o, Z_ResourceReportRequest **p, int opt, const char *name);
+
+typedef struct Z_ResourceReportResponse Z_ResourceReportResponse;
+YAZ_EXPORT int z_ResourceReportResponse (ODR o, Z_ResourceReportResponse **p, int opt, const char *name);
+
+typedef Z_External  Z_ResourceReport;
+YAZ_EXPORT int z_ResourceReport (ODR o, Z_ResourceReport **p, int opt, const char *name);
+
+typedef Odr_oid  Z_ResourceReportId;
+YAZ_EXPORT int z_ResourceReportId (ODR o, Z_ResourceReportId **p, int opt, const char *name);
+
+typedef struct Z_ScanRequest Z_ScanRequest;
+YAZ_EXPORT int z_ScanRequest (ODR o, Z_ScanRequest **p, int opt, const char *name);
+
+typedef struct Z_ScanResponse Z_ScanResponse;
+YAZ_EXPORT int z_ScanResponse (ODR o, Z_ScanResponse **p, int opt, const char *name);
+
+typedef struct Z_ListEntries Z_ListEntries;
+YAZ_EXPORT int z_ListEntries (ODR o, Z_ListEntries **p, int opt, const char *name);
+
+typedef struct Z_Entry Z_Entry;
+YAZ_EXPORT int z_Entry (ODR o, Z_Entry **p, int opt, const char *name);
+
+typedef struct Z_TermInfo Z_TermInfo;
+YAZ_EXPORT int z_TermInfo (ODR o, Z_TermInfo **p, int opt, const char *name);
+
+typedef struct Z_byDatabaseList_s Z_byDatabaseList_s;
+YAZ_EXPORT int z_byDatabaseList_s (ODR o, Z_byDatabaseList_s **p, int opt, const char *name);
+
+typedef struct Z_byDatabaseList Z_byDatabaseList;
+YAZ_EXPORT int z_byDatabaseList (ODR o, Z_byDatabaseList **p, int opt, const char *name);
+
+typedef struct Z_OccurrenceByAttributesElem Z_OccurrenceByAttributesElem;
+YAZ_EXPORT int z_OccurrenceByAttributesElem (ODR o, Z_OccurrenceByAttributesElem **p, int opt, const char *name);
+
+typedef struct Z_OccurrenceByAttributes Z_OccurrenceByAttributes;
+YAZ_EXPORT int z_OccurrenceByAttributes (ODR o, Z_OccurrenceByAttributes **p, int opt, const char *name);
+
+typedef struct Z_SortKeySpecList Z_SortKeySpecList;
+YAZ_EXPORT int z_SortKeySpecList (ODR o, Z_SortKeySpecList **p, int opt, const char *name);
+
+typedef struct Z_SortRequest Z_SortRequest;
+YAZ_EXPORT int z_SortRequest (ODR o, Z_SortRequest **p, int opt, const char *name);
+
+typedef struct Z_SortResponse Z_SortResponse;
+YAZ_EXPORT int z_SortResponse (ODR o, Z_SortResponse **p, int opt, const char *name);
+
+typedef struct Z_SortKeySpec Z_SortKeySpec;
+YAZ_EXPORT int z_SortKeySpec (ODR o, Z_SortKeySpec **p, int opt, const char *name);
+
+typedef struct Z_SortDbSpecificList_s Z_SortDbSpecificList_s;
+YAZ_EXPORT int z_SortDbSpecificList_s (ODR o, Z_SortDbSpecificList_s **p, int opt, const char *name);
+
+typedef struct Z_SortDbSpecificList Z_SortDbSpecificList;
+YAZ_EXPORT int z_SortDbSpecificList (ODR o, Z_SortDbSpecificList **p, int opt, const char *name);
+
+typedef struct Z_SortElement Z_SortElement;
+YAZ_EXPORT int z_SortElement (ODR o, Z_SortElement **p, int opt, const char *name);
+
+typedef struct Z_SortAttributes Z_SortAttributes;
+YAZ_EXPORT int z_SortAttributes (ODR o, Z_SortAttributes **p, int opt, const char *name);
+
+typedef struct Z_SortKey Z_SortKey;
+YAZ_EXPORT int z_SortKey (ODR o, Z_SortKey **p, int opt, const char *name);
+
+typedef struct Z_ExtendedServicesRequest Z_ExtendedServicesRequest;
+YAZ_EXPORT int z_ExtendedServicesRequest (ODR o, Z_ExtendedServicesRequest **p, int opt, const char *name);
+
+typedef struct Z_ExtendedServicesResponse Z_ExtendedServicesResponse;
+YAZ_EXPORT int z_ExtendedServicesResponse (ODR o, Z_ExtendedServicesResponse **p, int opt, const char *name);
+
+typedef struct Z_Permissions_s Z_Permissions_s;
+YAZ_EXPORT int z_Permissions_s (ODR o, Z_Permissions_s **p, int opt, const char *name);
+
+typedef struct Z_Permissions Z_Permissions;
+YAZ_EXPORT int z_Permissions (ODR o, Z_Permissions **p, int opt, const char *name);
+
+typedef struct Z_Close Z_Close;
+YAZ_EXPORT int z_Close (ODR o, Z_Close **p, int opt, const char *name);
+
+typedef int  Z_CloseReason;
+YAZ_EXPORT int z_CloseReason (ODR o, Z_CloseReason **p, int opt, const char *name);
+
+typedef Odr_oct  Z_ReferenceId;
+YAZ_EXPORT int z_ReferenceId (ODR o, Z_ReferenceId **p, int opt, const char *name);
+
+typedef Odr_oid  Z_AttributeSetId;
+YAZ_EXPORT int z_AttributeSetId (ODR o, Z_AttributeSetId **p, int opt, const char *name);
+
+typedef struct Z_OtherInformationUnit Z_OtherInformationUnit;
+YAZ_EXPORT int z_OtherInformationUnit (ODR o, Z_OtherInformationUnit **p, int opt, const char *name);
+
+typedef struct Z_OtherInformation Z_OtherInformation;
+YAZ_EXPORT int z_OtherInformation (ODR o, Z_OtherInformation **p, int opt, const char *name);
+
+typedef struct Z_InfoCategory Z_InfoCategory;
+YAZ_EXPORT int z_InfoCategory (ODR o, Z_InfoCategory **p, int opt, const char *name);
+
+typedef struct Z_IntUnit Z_IntUnit;
+YAZ_EXPORT int z_IntUnit (ODR o, Z_IntUnit **p, int opt, const char *name);
+
+typedef struct Z_Unit Z_Unit;
+YAZ_EXPORT int z_Unit (ODR o, Z_Unit **p, int opt, const char *name);
+
+typedef char  Z_InternationalString;
+YAZ_EXPORT int z_InternationalString (ODR o, Z_InternationalString **p, int opt, const char *name);
+
+typedef Z_InternationalString  Z_ResultSetId;
+YAZ_EXPORT int z_ResultSetId (ODR o, Z_ResultSetId **p, int opt, const char *name);
+
+typedef Z_InternationalString  Z_ElementSetName;
+YAZ_EXPORT int z_ElementSetName (ODR o, Z_ElementSetName **p, int opt, const char *name);
+
+typedef Z_InternationalString  Z_DatabaseName;
+YAZ_EXPORT int z_DatabaseName (ODR o, Z_DatabaseName **p, int opt, const char *name);
+
+typedef struct Z_StringOrNumeric Z_StringOrNumeric;
+YAZ_EXPORT int z_StringOrNumeric (ODR o, Z_StringOrNumeric **p, int opt, const char *name);
+#ifdef __cplusplus
+}
+#endif
+#ifdef __cplusplus
+extern "C" {
+#endif
+struct Z_APDU {
+	int which;
+	union {
+		Z_InitRequest *initRequest;
+		Z_InitResponse *initResponse;
+		Z_SearchRequest *searchRequest;
+		Z_SearchResponse *searchResponse;
+		Z_PresentRequest *presentRequest;
+		Z_PresentResponse *presentResponse;
+		Z_DeleteResultSetRequest *deleteResultSetRequest;
+		Z_DeleteResultSetResponse *deleteResultSetResponse;
+		Z_AccessControlRequest *accessControlRequest;
+		Z_AccessControlResponse *accessControlResponse;
+		Z_ResourceControlRequest *resourceControlRequest;
+		Z_ResourceControlResponse *resourceControlResponse;
+		Z_TriggerResourceControlRequest *triggerResourceControlRequest;
+		Z_ResourceReportRequest *resourceReportRequest;
+		Z_ResourceReportResponse *resourceReportResponse;
+		Z_ScanRequest *scanRequest;
+		Z_ScanResponse *scanResponse;
+		Z_SortRequest *sortRequest;
+		Z_SortResponse *sortResponse;
+		Z_Segment *segmentRequest;
+		Z_ExtendedServicesRequest *extendedServicesRequest;
+		Z_ExtendedServicesResponse *extendedServicesResponse;
+		Z_Close *close;
+#define Z_APDU_initRequest 1
+#define Z_APDU_initResponse 2
+#define Z_APDU_searchRequest 3
+#define Z_APDU_searchResponse 4
+#define Z_APDU_presentRequest 5
+#define Z_APDU_presentResponse 6
+#define Z_APDU_deleteResultSetRequest 7
+#define Z_APDU_deleteResultSetResponse 8
+#define Z_APDU_accessControlRequest 9
+#define Z_APDU_accessControlResponse 10
+#define Z_APDU_resourceControlRequest 11
+#define Z_APDU_resourceControlResponse 12
+#define Z_APDU_triggerResourceControlRequest 13
+#define Z_APDU_resourceReportRequest 14
+#define Z_APDU_resourceReportResponse 15
+#define Z_APDU_scanRequest 16
+#define Z_APDU_scanResponse 17
+#define Z_APDU_sortRequest 18
+#define Z_APDU_sortResponse 19
+#define Z_APDU_segmentRequest 20
+#define Z_APDU_extendedServicesRequest 21
+#define Z_APDU_extendedServicesResponse 22
+#define Z_APDU_close 23
+	} u;
+};
+
+struct Z_InitRequest {
+	Z_ReferenceId *referenceId; /* OPT */
+	Z_ProtocolVersion *protocolVersion;
+	Z_Options *options;
+	int *preferredMessageSize;
+	int *maximumRecordSize;
+	Z_IdAuthentication *idAuthentication; /* OPT */
+	Z_InternationalString *implementationId; /* OPT */
+	Z_InternationalString *implementationName; /* OPT */
+	Z_InternationalString *implementationVersion; /* OPT */
+	Z_External *userInformationField; /* OPT */
+	Z_OtherInformation *otherInfo; /* OPT */
+};
+
+struct Z_IdPass {
+	Z_InternationalString *groupId; /* OPT */
+	Z_InternationalString *userId; /* OPT */
+	Z_InternationalString *password; /* OPT */
+};
+
+struct Z_IdAuthentication {
+	int which;
+	union {
+		char *open;
+		Z_IdPass *idPass;
+		Odr_null *anonymous;
+		Z_External *other;
+#define Z_IdAuthentication_open 1
+#define Z_IdAuthentication_idPass 2
+#define Z_IdAuthentication_anonymous 3
+#define Z_IdAuthentication_other 4
+	} u;
+};
+
+struct Z_InitResponse {
+	Z_ReferenceId *referenceId; /* OPT */
+	Z_ProtocolVersion *protocolVersion;
+	Z_Options *options;
+	int *preferredMessageSize;
+	int *maximumRecordSize;
+	bool_t *result;
+	Z_InternationalString *implementationId; /* OPT */
+	Z_InternationalString *implementationName; /* OPT */
+	Z_InternationalString *implementationVersion; /* OPT */
+	Z_External *userInformationField; /* OPT */
+	Z_OtherInformation *otherInfo; /* OPT */
+};
+
+#define Z_ProtocolVersion_1 0
+#define Z_ProtocolVersion_2 1
+#define Z_ProtocolVersion_3 2
+
+#define Z_Options_search 0
+#define Z_Options_present 1
+#define Z_Options_delSet 2
+#define Z_Options_resourceReport 3
+#define Z_Options_triggerResourceCtrl 4
+#define Z_Options_resourceCtrl 5
+#define Z_Options_accessCtrl 6
+#define Z_Options_scan 7
+#define Z_Options_sort 8
+#define Z_Options_extendedServices 10
+#define Z_Options_level_1Segmentation 11
+#define Z_Options_level_2Segmentation 12
+#define Z_Options_concurrentOperations 13
+#define Z_Options_namedResultSets 14
+
+struct Z_SearchRequest {
+	Z_ReferenceId *referenceId; /* OPT */
+	int *smallSetUpperBound;
+	int *largeSetLowerBound;
+	int *mediumSetPresentNumber;
+	bool_t *replaceIndicator;
+	Z_InternationalString *resultSetName;
+	int num_databaseNames;
+	Z_DatabaseName **databaseNames;
+	Z_ElementSetNames *smallSetElementSetNames; /* OPT */
+	Z_ElementSetNames *mediumSetElementSetNames; /* OPT */
+	Odr_oid *preferredRecordSyntax; /* OPT */
+	Z_Query *query;
+	Z_OtherInformation *additionalSearchInfo; /* OPT */
+	Z_OtherInformation *otherInfo; /* OPT */
+};
+
+struct Z_Query {
+	int which;
+	union {
+		void *type_0;
+		Z_RPNQuery *type_1;
+		Odr_oct *type_2;
+		Odr_oct *type_100;
+		Z_RPNQuery *type_101;
+		Odr_oct *type_102;
+#define Z_Query_type_0 1
+#define Z_Query_type_1 2
+#define Z_Query_type_2 3
+#define Z_Query_type_100 4
+#define Z_Query_type_101 5
+#define Z_Query_type_102 6
+	} u;
+};
+
+struct Z_RPNQuery {
+	Z_AttributeSetId *attributeSetId;
+	Z_RPNStructure *RPNStructure;
+};
+
+struct Z_Complex {
+	Z_RPNStructure *s1;
+	Z_RPNStructure *s2;
+	Z_Operator *roperator;
+};
+
+struct Z_RPNStructure {
+	int which;
+	union {
+		Z_Operand *simple;
+		Z_Complex *complex;
+#define Z_RPNStructure_simple 1
+#define Z_RPNStructure_complex 2
+	} u;
+};
+
+struct Z_Operand {
+	int which;
+	union {
+		Z_AttributesPlusTerm *attributesPlusTerm;
+		Z_ResultSetId *resultSetId;
+		Z_ResultSetPlusAttributes *resultAttr;
+#define Z_Operand_APT 1
+#define Z_Operand_resultSetId 2
+#define Z_Operand_resultAttr 3
+	} u;
+};
+
+struct Z_AttributesPlusTerm {
+	Z_AttributeList *attributes;
+	Z_Term *term;
+};
+
+struct Z_ResultSetPlusAttributes {
+	Z_ResultSetId *resultSet;
+	Z_AttributeList *attributes;
+};
+
+struct Z_AttributeList {
+	int num_attributes;
+	Z_AttributeElement **attributes;
+};
+
+struct Z_Term {
+	int which;
+	union {
+		Odr_oct *general;
+		int *numeric;
+		Z_InternationalString *characterString;
+		Odr_oid *oid;
+		char *dateTime;
+		Z_External *external;
+		Z_IntUnit *integerAndUnit;
+		Odr_null *null;
+#define Z_Term_general 1
+#define Z_Term_numeric 2
+#define Z_Term_characterString 3
+#define Z_Term_oid 4
+#define Z_Term_dateTime 5
+#define Z_Term_external 6
+#define Z_Term_integerAndUnit 7
+#define Z_Term_null 8
+	} u;
+};
+
+struct Z_Operator {
+	int which;
+	union {
+		Odr_null *and;
+		Odr_null *or;
+		Odr_null *and_not;
+		Z_ProximityOperator *prox;
+#define Z_Operator_and 1
+#define Z_Operator_or 2
+#define Z_Operator_and_not 3
+#define Z_Operator_prox 4
+	} u;
+};
+
+struct Z_ComplexAttribute {
+	int num_list;
+	Z_StringOrNumeric **list;
+	int num_semanticAction;
+	int **semanticAction; /* OPT */
+};
+
+struct Z_AttributeElement {
+	Z_AttributeSetId *attributeSet; /* OPT */
+	int *attributeType;
+	int which;
+	union {
+		int *numeric;
+		Z_ComplexAttribute *complex;
+#define Z_AttributeValue_numeric 1
+#define Z_AttributeValue_complex 2
+	} value;
+};
+
+struct Z_ProximityOperator {
+	bool_t *exclusion; /* OPT */
+	int *distance;
+	bool_t *ordered;
+#define Z_ProximityOperator_Prox_lessThan 1
+#define Z_ProximityOperator_Prox_lessThanOrEqual 2
+#define Z_ProximityOperator_Prox_equal 3
+#define Z_ProximityOperator_Prox_greaterThanOrEqual 4
+#define Z_ProximityOperator_Prox_greaterThan 5
+#define Z_ProximityOperator_Prox_notEqual 6
+	int *relationType;
+	int which;
+	union {
+		Z_ProxUnit *known;
+		int *zprivate;
+#define Z_ProximityOperator_known 1
+#define Z_ProximityOperator_private 2
+	} u;
+};
+
+#define Z_ProxUnit_character 1
+#define Z_ProxUnit_word 2
+#define Z_ProxUnit_sentence 3
+#define Z_ProxUnit_paragraph 4
+#define Z_ProxUnit_section 5
+#define Z_ProxUnit_chapter 6
+#define Z_ProxUnit_document 7
+#define Z_ProxUnit_element 8
+#define Z_ProxUnit_subelement 9
+#define Z_ProxUnit_elementType 10
+#define Z_ProxUnit_byte 11
+
+struct Z_SearchResponse {
+	Z_ReferenceId *referenceId; /* OPT */
+	int *resultCount;
+	int *numberOfRecordsReturned;
+	int *nextResultSetPosition;
+	bool_t *searchStatus;
+#define Z_SearchResponse_subset 1
+#define Z_SearchResponse_interim 2
+#define Z_SearchResponse_none 3
+	int *resultSetStatus; /* OPT */
+	Z_PresentStatus *presentStatus; /* OPT */
+	Z_Records *records; /* OPT */
+	Z_OtherInformation *additionalSearchInfo; /* OPT */
+	Z_OtherInformation *otherInfo; /* OPT */
+};
+
+struct Z_RecordComposition {
+	int which;
+	union {
+		Z_ElementSetNames *simple;
+		Z_CompSpec *complex;
+#define Z_RecordComp_simple 1
+#define Z_RecordComp_complex 2
+	} u;
+};
+
+struct Z_PresentRequest {
+	Z_ReferenceId *referenceId; /* OPT */
+	Z_ResultSetId *resultSetId;
+	int *resultSetStartPoint;
+	int *numberOfRecordsRequested;
+	int num_ranges;
+	Z_Range **additionalRanges; /* OPT */
+	Z_RecordComposition *recordComposition; /* OPT */
+	Odr_oid *preferredRecordSyntax; /* OPT */
+	int *maxSegmentCount; /* OPT */
+	int *maxRecordSize; /* OPT */
+	int *maxSegmentSize; /* OPT */
+	Z_OtherInformation *otherInfo; /* OPT */
+};
+
+struct Z_Segment {
+	Z_ReferenceId *referenceId; /* OPT */
+	int *numberOfRecordsReturned;
+	int num_segmentRecords;
+	Z_NamePlusRecord **segmentRecords;
+	Z_OtherInformation *otherInfo; /* OPT */
+};
+
+struct Z_PresentResponse {
+	Z_ReferenceId *referenceId; /* OPT */
+	int *numberOfRecordsReturned;
+	int *nextResultSetPosition;
+	Z_PresentStatus *presentStatus;
+	Z_Records *records; /* OPT */
+	Z_OtherInformation *otherInfo; /* OPT */
+};
+
+struct Z_NamePlusRecordList {
+	int num_records;
+	Z_NamePlusRecord **records;
+};
+
+struct Z_DiagRecs {
+	int num_diagRecs;
+	Z_DiagRec **diagRecs;
+};
+
+struct Z_Records {
+	int which;
+	union {
+		Z_NamePlusRecordList *databaseOrSurDiagnostics;
+		Z_DefaultDiagFormat *nonSurrogateDiagnostic;
+		Z_DiagRecs *multipleNonSurDiagnostics;
+#define Z_Records_DBOSD 1
+#define Z_Records_NSD 2
+#define Z_Records_multipleNSD 3
+	} u;
+};
+
+struct Z_NamePlusRecord {
+	Z_DatabaseName *databaseName; /* OPT */
+	int which;
+	union {
+		Z_External *databaseRecord;
+		Z_DiagRec *surrogateDiagnostic;
+		Z_FragmentSyntax *startingFragment;
+		Z_FragmentSyntax *intermediateFragment;
+		Z_FragmentSyntax *finalFragment;
+#define Z_NamePlusRecord_databaseRecord 1
+#define Z_NamePlusRecord_surrogateDiagnostic 2
+#define Z_NamePlusRecord_startingFragment 3
+#define Z_NamePlusRecord_intermediateFragment 4
+#define Z_NamePlusRecord_finalFragment 5
+	} u;
+};
+
+struct Z_FragmentSyntax {
+	int which;
+	union {
+		Z_External *externallyTagged;
+		Odr_oct *notExternallyTagged;
+#define Z_FragmentSyntax_externallyTagged 1
+#define Z_FragmentSyntax_notExternallyTagged 2
+	} u;
+};
+
+struct Z_DiagRec {
+	int which;
+	union {
+		Z_DefaultDiagFormat *defaultFormat;
+		Z_External *externallyDefined;
+#define Z_DiagRec_defaultFormat 1
+#define Z_DiagRec_externallyDefined 2
+	} u;
+};
+
+struct Z_DefaultDiagFormat {
+	Odr_oid *diagnosticSetId;
+	int *condition;
+	int which;
+	union {
+		char *v2Addinfo;
+		Z_InternationalString *v3Addinfo;
+#define Z_DefaultDiagFormat_v2Addinfo 1
+#define Z_DefaultDiagFormat_v3Addinfo 2
+	} u;
+};
+
+struct Z_Range {
+	int *startingPosition;
+	int *numberOfRecords;
+};
+
+struct Z_DatabaseSpecificUnit {
+	Z_DatabaseName *dbName;
+	Z_ElementSetName *esn;
+};
+
+struct Z_DatabaseSpecific {
+	int num;
+	Z_DatabaseSpecificUnit **elements;
+};
+
+struct Z_ElementSetNames {
+	int which;
+	union {
+		Z_InternationalString *generic;
+		Z_DatabaseSpecific *databaseSpecific;
+#define Z_ElementSetNames_generic 1
+#define Z_ElementSetNames_databaseSpecific 2
+	} u;
+};
+
+#define Z_PresentStatus_success 0
+#define Z_PresentStatus_partial_1 1
+#define Z_PresentStatus_partial_2 2
+#define Z_PresentStatus_partial_3 3
+#define Z_PresentStatus_partial_4 4
+#define Z_PresentStatus_failure 5
+
+struct Z_DbSpecific {
+	Z_DatabaseName *db;
+	Z_Specification *spec;
+};
+
+struct Z_CompSpec {
+	bool_t *selectAlternativeSyntax;
+	Z_Specification *generic; /* OPT */
+	int num_dbSpecific;
+	Z_DbSpecific **dbSpecific; /* OPT */
+	int num_recordSyntax;
+	Odr_oid **recordSyntax; /* OPT */
+};
+
+struct Z_ElementSpec {
+	int which;
+	union {
+		Z_InternationalString *elementSetName;
+		Z_External *externalSpec;
+#define Z_ElementSpec_elementSetName 1
+#define Z_ElementSpec_externalSpec 2
+	} u;
+};
+
+struct Z_Specification {
+	Odr_oid *schema; /* OPT */
+	Z_ElementSpec *elementSpec; /* OPT */
+};
+
+struct Z_DeleteResultSetRequest {
+	Z_ReferenceId *referenceId; /* OPT */
+#define Z_DeleteResultSetRequest_list 0
+#define Z_DeleteResultSetRequest_all 1
+	int *deleteFunction;
+	int num_resultSetList;
+	Z_ResultSetId **resultSetList; /* OPT */
+	Z_OtherInformation *otherInfo; /* OPT */
+};
+
+struct Z_DeleteResultSetResponse {
+	Z_ReferenceId *referenceId; /* OPT */
+	Z_DeleteStatus *deleteOperationStatus;
+	Z_ListStatuses *deleteListStatuses; /* OPT */
+	int *numberNotDeleted; /* OPT */
+	Z_ListStatuses *bulkStatuses; /* OPT */
+	Z_InternationalString *deleteMessage; /* OPT */
+	Z_OtherInformation *otherInfo; /* OPT */
+};
+
+struct Z_ListStatus {
+	Z_ResultSetId *id;
+	Z_DeleteStatus *status;
+};
+
+struct Z_ListStatuses {
+	int num;
+	Z_ListStatus **elements;
+};
+
+#define Z_DeleteStatus_success 0
+#define Z_DeleteStatus_resultSetDidNotExist 1
+#define Z_DeleteStatus_previouslyDeletedByTarget 2
+#define Z_DeleteStatus_systemProblemAtTarget 3
+#define Z_DeleteStatus_accessNotAllowed 4
+#define Z_DeleteStatus_resourceControlAtOrigin 5
+#define Z_DeleteStatus_resourceControlAtTarget 6
+#define Z_DeleteStatus_bulkDeleteNotSupported 7
+#define Z_DeleteStatus_notAllRsltSetsDeletedOnBulkDlte 8
+#define Z_DeleteStatus_notAllRequestedResultSetsDeleted 9
+#define Z_DeleteStatus_resultSetInUse 10
+
+struct Z_AccessControlRequest {
+	Z_ReferenceId *referenceId; /* OPT */
+	int which;
+	union {
+		Odr_oct *simpleForm;
+		Z_External *externallyDefined;
+#define Z_AccessControlRequest_simpleForm 1
+#define Z_AccessControlRequest_externallyDefined 2
+	} u;
+	Z_OtherInformation *otherInfo; /* OPT */
+};
+
+struct Z_AccessControlResponse {
+	Z_ReferenceId *referenceId; /* OPT */
+	int which;
+	union {
+		Odr_oct *simpleForm;
+		Z_External *externallyDefined;
+#define Z_AccessControlResponse_simpleForm 1
+#define Z_AccessControlResponse_externallyDefined 2
+	} u; /* OPT */
+	Z_DiagRec *diagnostic; /* OPT */
+	Z_OtherInformation *otherInfo; /* OPT */
+};
+
+struct Z_ResourceControlRequest {
+	Z_ReferenceId *referenceId; /* OPT */
+	bool_t *suspendedFlag; /* OPT */
+	Z_ResourceReport *resourceReport; /* OPT */
+#define Z_ResourceControlRequest_subset 1
+#define Z_ResourceControlRequest_interim 2
+#define Z_ResourceControlRequest_none 3
+	int *partialResultsAvailable; /* OPT */
+	bool_t *responseRequired;
+	bool_t *triggeredRequestFlag; /* OPT */
+	Z_OtherInformation *otherInfo; /* OPT */
+};
+
+struct Z_ResourceControlResponse {
+	Z_ReferenceId *referenceId; /* OPT */
+	bool_t *continueFlag;
+	bool_t *resultSetWanted; /* OPT */
+	Z_OtherInformation *otherInfo; /* OPT */
+};
+
+struct Z_TriggerResourceControlRequest {
+	Z_ReferenceId *referenceId; /* OPT */
+#define Z_TriggerResourceControlRequest_resourceReport 1
+#define Z_TriggerResourceControlRequest_resourceControl 2
+#define Z_TriggerResourceControlRequest_cancel 3
+	int *requestedAction;
+	Z_ResourceReportId *prefResourceReportFormat; /* OPT */
+	bool_t *resultSetWanted; /* OPT */
+	Z_OtherInformation *otherInfo; /* OPT */
+};
+
+struct Z_ResourceReportRequest {
+	Z_ReferenceId *referenceId; /* OPT */
+	Z_ReferenceId *opId; /* OPT */
+	Z_ResourceReportId *prefResourceReportFormat; /* OPT */
+	Z_OtherInformation *otherInfo; /* OPT */
+};
+
+struct Z_ResourceReportResponse {
+	Z_ReferenceId *referenceId; /* OPT */
+#define Z_ResourceReportResponse_success 0
+#define Z_ResourceReportResponse_partial 1
+#define Z_ResourceReportResponse_failure_1 2
+#define Z_ResourceReportResponse_failure_2 3
+#define Z_ResourceReportResponse_failure_3 4
+#define Z_ResourceReportResponse_failure_4 5
+#define Z_ResourceReportResponse_failure_5 6
+#define Z_ResourceReportResponse_failure_6 7
+	int *resourceReportStatus;
+	Z_ResourceReport *resourceReport; /* OPT */
+	Z_OtherInformation *otherInfo; /* OPT */
+};
+
+
+
+
+
+struct Z_ScanRequest {
+	Z_ReferenceId *referenceId; /* OPT */
+	int num_databaseNames;
+	Z_DatabaseName **databaseNames;
+	Z_AttributeSetId *attributeSet; /* OPT */
+	Z_AttributesPlusTerm *termListAndStartPoint;
+	int *stepSize; /* OPT */
+	int *numberOfTermsRequested;
+	int *preferredPositionInResponse; /* OPT */
+	Z_OtherInformation *otherInfo; /* OPT */
+};
+
+struct Z_ScanResponse {
+	Z_ReferenceId *referenceId; /* OPT */
+	int *stepSize; /* OPT */
+#define Z_Scan_success 0
+#define Z_Scan_partial_1 1
+#define Z_Scan_partial_2 2
+#define Z_Scan_partial_3 3
+#define Z_Scan_partial_4 4
+#define Z_Scan_partial_5 5
+#define Z_Scan_failure 6
+	int *scanStatus;
+	int *numberOfEntriesReturned;
+	int *positionOfTerm; /* OPT */
+	Z_ListEntries *entries; /* OPT */
+	Z_AttributeSetId *attributeSet; /* OPT */
+	Z_OtherInformation *otherInfo; /* OPT */
+};
+
+struct Z_ListEntries {
+	int num_entries;
+	Z_Entry **entries; /* OPT */
+	int num_nonsurrogateDiagnostics;
+	Z_DiagRec **nonsurrogateDiagnostics; /* OPT */
+};
+
+struct Z_Entry {
+	int which;
+	union {
+		Z_TermInfo *termInfo;
+		Z_DiagRec *surrogateDiagnostic;
+#define Z_Entry_termInfo 1
+#define Z_Entry_surrogateDiagnostic 2
+	} u;
+};
+
+struct Z_TermInfo {
+	Z_Term *term;
+	Z_InternationalString *displayTerm; /* OPT */
+	Z_AttributeList *suggestedAttributes; /* OPT */
+	int num_alternativeTerm;
+	Z_AttributesPlusTerm **alternativeTerm; /* OPT */
+	int *globalOccurrences; /* OPT */
+	Z_OccurrenceByAttributes *byAttributes; /* OPT */
+	Z_OtherInformation *otherTermInfo; /* OPT */
+};
+
+struct Z_byDatabaseList_s {
+	Z_DatabaseName *db;
+	int *num; /* OPT */
+	Z_OtherInformation *otherDbInfo; /* OPT */
+};
+
+struct Z_byDatabaseList {
+	int num;
+	Z_byDatabaseList_s **elements;
+};
+
+struct Z_OccurrenceByAttributesElem {
+	Z_AttributeList *attributes;
+	int which;
+	union {
+		int *global;
+		Z_byDatabaseList *byDatabase;
+#define Z_OccurrenceByAttributesElem_global 1
+#define Z_OccurrenceByAttributesElem_byDatabase 2
+	} u; /* OPT */
+	Z_OtherInformation *otherOccurInfo; /* OPT */
+};
+
+struct Z_OccurrenceByAttributes {
+	int num;
+	Z_OccurrenceByAttributesElem **elements;
+};
+
+struct Z_SortKeySpecList {
+	int num_specs;
+	Z_SortKeySpec **specs;
+};
+
+struct Z_SortRequest {
+	Z_ReferenceId *referenceId; /* OPT */
+	int num_inputResultSetNames;
+	Z_InternationalString **inputResultSetNames;
+	Z_InternationalString *sortedResultSetName;
+	Z_SortKeySpecList *sortSequence;
+	Z_OtherInformation *otherInfo; /* OPT */
+};
+
+struct Z_SortResponse {
+	Z_ReferenceId *referenceId; /* OPT */
+#define Z_SortResponse_success 0
+#define Z_SortResponse_partial_1 1
+#define Z_SortResponse_failure 2
+	int *sortStatus;
+#define Z_SortResponse_empty 1
+#define Z_SortResponse_interim 2
+#define Z_SortResponse_unchanged 3
+#define Z_SortResponse_none 4
+	int *resultSetStatus; /* OPT */
+	int num_diagnostics;
+	Z_DiagRec **diagnostics; /* OPT */
+	Z_OtherInformation *otherInfo; /* OPT */
+};
+
+struct Z_SortKeySpec {
+	Z_SortElement *sortElement;
+#define Z_SortKeySpec_ascending 0
+#define Z_SortKeySpec_descending 1
+#define Z_SortKeySpec_ascendingByFrequency 3
+#define Z_SortKeySpec_descendingByfrequency 4
+	int *sortRelation;
+#define Z_SortKeySpec_caseSensitive 0
+#define Z_SortKeySpec_caseInsensitive 1
+	int *caseSensitivity;
+	int which;
+	union {
+		Odr_null *abort;
+		Odr_null *null;
+		Odr_oct *missingValueData;
+#define Z_SortKeySpec_abort 1
+#define Z_SortKeySpec_null 2
+#define Z_SortKeySpec_missingValueData 3
+	} u; /* OPT */
+};
+
+struct Z_SortDbSpecificList_s {
+	Z_DatabaseName *databaseName;
+	Z_SortKey *dbSort;
+};
+
+struct Z_SortDbSpecificList {
+	int num;
+	Z_SortDbSpecificList_s **elements;
+};
+
+struct Z_SortElement {
+	int which;
+	union {
+		Z_SortKey *generic;
+		Z_SortDbSpecificList *databaseSpecific;
+#define Z_SortElement_generic 1
+#define Z_SortElement_databaseSpecific 2
+	} u;
+};
+
+struct Z_SortAttributes {
+	Z_AttributeSetId *id;
+	Z_AttributeList *list;
+};
+
+struct Z_SortKey {
+	int which;
+	union {
+		Z_InternationalString *sortField;
+		Z_Specification *elementSpec;
+		Z_SortAttributes *sortAttributes;
+#define Z_SortKey_sortField 1
+#define Z_SortKey_elementSpec 2
+#define Z_SortKey_sortAttributes 3
+	} u;
+};
+
+struct Z_ExtendedServicesRequest {
+	Z_ReferenceId *referenceId; /* OPT */
+#define Z_ExtendedServicesRequest_create 1
+#define Z_ExtendedServicesRequest_delete 2
+#define Z_ExtendedServicesRequest_modify 3
+	int *function;
+	Odr_oid *packageType;
+	Z_InternationalString *packageName; /* OPT */
+	Z_InternationalString *userId; /* OPT */
+	Z_IntUnit *retentionTime; /* OPT */
+	Z_Permissions *permissions; /* OPT */
+	Z_InternationalString *description; /* OPT */
+	Z_External *taskSpecificParameters; /* OPT */
+#define Z_ExtendedServicesRequest_wait 1
+#define Z_ExtendedServicesRequest_waitIfPossible 2
+#define Z_ExtendedServicesRequest_dontWait 3
+#define Z_ExtendedServicesRequest_dontReturnPackage 4
+	int *waitAction;
+	Z_ElementSetName *elements; /* OPT */
+	Z_OtherInformation *otherInfo; /* OPT */
+};
+
+struct Z_ExtendedServicesResponse {
+	Z_ReferenceId *referenceId; /* OPT */
+#define Z_ExtendedServicesResponse_done 1
+#define Z_ExtendedServicesResponse_accepted 2
+#define Z_ExtendedServicesResponse_failure 3
+	int *operationStatus;
+	int num_diagnostics;
+	Z_DiagRec **diagnostics; /* OPT */
+	Z_External *taskPackage; /* OPT */
+	Z_OtherInformation *otherInfo; /* OPT */
+};
+
+struct Z_Permissions_s {
+	Z_InternationalString *userId;
+#define Z_Permissions_s_delete 1
+#define Z_Permissions_s_modifyContents 2
+#define Z_Permissions_s_modifyPermissions 3
+#define Z_Permissions_s_present 4
+#define Z_Permissions_s_invoke 5
+	int num_allowableFunctions;
+	int **allowableFunctions;
+};
+
+struct Z_Permissions {
+	int num;
+	Z_Permissions_s **elements;
+};
+
+struct Z_Close {
+	Z_ReferenceId *referenceId; /* OPT */
+	Z_CloseReason *closeReason;
+	Z_InternationalString *diagnosticInformation; /* OPT */
+	Z_ResourceReportId *resourceReportFormat; /* OPT */
+	Z_ResourceReport *resourceReport; /* OPT */
+	Z_OtherInformation *otherInfo; /* OPT */
+};
+
+#define Z_Close_finished 0
+#define Z_Close_shutdown 1
+#define Z_Close_systemProblem 2
+#define Z_Close_costLimit 3
+#define Z_Close_resources 4
+#define Z_Close_securityViolation 5
+#define Z_Close_protocolError 6
+#define Z_Close_lackOfActivity 7
+#define Z_Close_peerAbort 8
+#define Z_Close_unspecified 9
+
+
+
+
+
+
+
+
+
+
+
+struct Z_OtherInformationUnit {
+	Z_InfoCategory *category; /* OPT */
+	int which;
+	union {
+		Z_InternationalString *characterInfo;
+		Odr_oct *binaryInfo;
+		Z_External *externallyDefinedInfo;
+		Odr_oid *oid;
+#define Z_OtherInfo_characterInfo 1
+#define Z_OtherInfo_binaryInfo 2
+#define Z_OtherInfo_externallyDefinedInfo 3
+#define Z_OtherInfo_oid 4
+	} information;
+};
+
+struct Z_OtherInformation {
+	int num_elements;
+	Z_OtherInformationUnit **list;
+};
+
+struct Z_InfoCategory {
+	Odr_oid *categoryTypeId; /* OPT */
+	int *categoryValue;
+};
+
+struct Z_IntUnit {
+	int *value;
+	Z_Unit *unitUsed;
+};
+
+struct Z_Unit {
+	Z_InternationalString *unitSystem; /* OPT */
+	Z_StringOrNumeric *unitType; /* OPT */
+	Z_StringOrNumeric *unit; /* OPT */
+	int *scaleFactor; /* OPT */
+};
+
+
+
+struct Z_StringOrNumeric {
+	int which;
+	union {
+		Z_InternationalString *string;
+		int *numeric;
+#define Z_StringOrNumeric_string 1
+#define Z_StringOrNumeric_numeric 2
+	} u;
+};
+
+#ifdef __cplusplus
+}
+#endif
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+int z_ANY_type_0 (ODR o, void **p, int opt);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
Index: /main/tags/2.25/gsdl/packages/yaz/include/yaz/z-date.h
===================================================================
--- /main/tags/2.25/gsdl/packages/yaz/include/yaz/z-date.h	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/yaz/include/yaz/z-date.h	(revision 21064)
@@ -0,0 +1,134 @@
+/* Generated automatically by the YAZ ASN.1 Compiler 0.3 */
+/* Module-H UserInfoFormat-dateTime */
+
+#ifndef z_date_H
+#define z_date_H
+
+#include <yaz/odr.h>
+#include <yaz/z-core.h>
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef struct Z_DateTime Z_DateTime;
+YAZ_EXPORT int z_DateTime (ODR o, Z_DateTime **p, int opt, const char *name);
+
+typedef struct Z_DateMonthAndDay Z_DateMonthAndDay;
+YAZ_EXPORT int z_DateMonthAndDay (ODR o, Z_DateMonthAndDay **p, int opt, const char *name);
+
+typedef struct Z_DateQuarter Z_DateQuarter;
+YAZ_EXPORT int z_DateQuarter (ODR o, Z_DateQuarter **p, int opt, const char *name);
+
+typedef struct Z_DateSeason Z_DateSeason;
+YAZ_EXPORT int z_DateSeason (ODR o, Z_DateSeason **p, int opt, const char *name);
+
+typedef struct Z_Era Z_Era;
+YAZ_EXPORT int z_Era (ODR o, Z_Era **p, int opt, const char *name);
+
+typedef struct Z_DateFlags Z_DateFlags;
+YAZ_EXPORT int z_DateFlags (ODR o, Z_DateFlags **p, int opt, const char *name);
+
+typedef struct Z_Date Z_Date;
+YAZ_EXPORT int z_Date (ODR o, Z_Date **p, int opt, const char *name);
+
+typedef struct Z_Time Z_Time;
+YAZ_EXPORT int z_Time (ODR o, Z_Time **p, int opt, const char *name);
+#ifdef __cplusplus
+}
+#endif
+#ifdef __cplusplus
+extern "C" {
+#endif
+struct Z_DateTime {
+	Z_Date *date; /* OPT */
+	Z_Time *time; /* OPT */
+};
+
+struct Z_DateMonthAndDay {
+	int *month;
+	int *day; /* OPT */
+};
+
+struct Z_DateQuarter {
+	int which;
+	union {
+		Odr_null *first;
+		Odr_null *second;
+		Odr_null *third;
+		Odr_null *fourth;
+#define Z_DateQuarter_first 1
+#define Z_DateQuarter_second 2
+#define Z_DateQuarter_third 3
+#define Z_DateQuarter_fourth 4
+	} u;
+};
+
+struct Z_DateSeason {
+	int which;
+	union {
+		Odr_null *winter;
+		Odr_null *spring;
+		Odr_null *summer;
+		Odr_null *autumn;
+#define Z_DateSeason_winter 1
+#define Z_DateSeason_spring 2
+#define Z_DateSeason_summer 3
+#define Z_DateSeason_autumn 4
+	} u;
+};
+
+struct Z_Era {
+	int which;
+	union {
+		Odr_null *decade;
+		Odr_null *century;
+		Odr_null *millennium;
+#define Z_Era_decade 1
+#define Z_Era_century 2
+#define Z_Era_millennium 3
+	} u;
+};
+
+struct Z_DateFlags {
+	Odr_null *circa; /* OPT */
+	Z_Era *era; /* OPT */
+};
+
+struct Z_Date {
+	int *year;
+	int which;
+	union {
+		Z_DateMonthAndDay *monthAndDay;
+		int *julianDay;
+		int *weekNumber;
+		Z_DateQuarter *quarter;
+		Z_DateSeason *season;
+#define Z_Date_monthAndDay 1
+#define Z_Date_julianDay 2
+#define Z_Date_weekNumber 3
+#define Z_Date_quarter 4
+#define Z_Date_season 5
+	} u; /* OPT */
+	Z_DateFlags *flags; /* OPT */
+};
+
+struct Z_Time {
+	int *hour;
+	int *minute; /* OPT */
+	int *second; /* OPT */
+	Z_IntUnit *partOfSecond; /* OPT */
+	int which;
+	union {
+		Odr_null *local;
+		Odr_null *utc;
+		int *utcOffset;
+#define Z_Time_local 1
+#define Z_Time_utc 2
+#define Z_Time_utcOffset 3
+	} u;
+};
+
+#ifdef __cplusplus
+}
+#endif
+#endif
Index: /main/tags/2.25/gsdl/packages/yaz/include/yaz/z-diag1.h
===================================================================
--- /main/tags/2.25/gsdl/packages/yaz/include/yaz/z-diag1.h	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/yaz/include/yaz/z-diag1.h	(revision 21064)
@@ -0,0 +1,354 @@
+/* Generated automatically by the YAZ ASN.1 Compiler 0.3 */
+/* Module-H DiagnosticFormatDiag1 */
+
+#ifndef z_diag1_H
+#define z_diag1_H
+
+#include <yaz/odr.h>
+#include <yaz/z-core.h>
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef struct Z_DiagnosticFormat_s Z_DiagnosticFormat_s;
+YAZ_EXPORT int z_DiagnosticFormat_s (ODR o, Z_DiagnosticFormat_s **p, int opt, const char *name);
+
+typedef struct Z_DiagnosticFormat Z_DiagnosticFormat;
+YAZ_EXPORT int z_DiagnosticFormat (ODR o, Z_DiagnosticFormat **p, int opt, const char *name);
+
+typedef struct Z_TooMany Z_TooMany;
+YAZ_EXPORT int z_TooMany (ODR o, Z_TooMany **p, int opt, const char *name);
+
+typedef struct Z_BadSpec Z_BadSpec;
+YAZ_EXPORT int z_BadSpec (ODR o, Z_BadSpec **p, int opt, const char *name);
+
+typedef struct Z_DbUnavail_0 Z_DbUnavail_0;
+YAZ_EXPORT int z_DbUnavail_0 (ODR o, Z_DbUnavail_0 **p, int opt, const char *name);
+
+typedef struct Z_DbUnavail Z_DbUnavail;
+YAZ_EXPORT int z_DbUnavail (ODR o, Z_DbUnavail **p, int opt, const char *name);
+
+typedef struct Z_Attribute Z_Attribute;
+YAZ_EXPORT int z_Attribute (ODR o, Z_Attribute **p, int opt, const char *name);
+
+typedef struct Z_AttCombo Z_AttCombo;
+YAZ_EXPORT int z_AttCombo (ODR o, Z_AttCombo **p, int opt, const char *name);
+
+typedef struct Z_DiagTerm Z_DiagTerm;
+YAZ_EXPORT int z_DiagTerm (ODR o, Z_DiagTerm **p, int opt, const char *name);
+
+typedef struct Z_Proximity Z_Proximity;
+YAZ_EXPORT int z_Proximity (ODR o, Z_Proximity **p, int opt, const char *name);
+
+typedef struct Z_AttrListList Z_AttrListList;
+YAZ_EXPORT int z_AttrListList (ODR o, Z_AttrListList **p, int opt, const char *name);
+
+typedef struct Z_Scan Z_Scan;
+YAZ_EXPORT int z_Scan (ODR o, Z_Scan **p, int opt, const char *name);
+
+typedef struct Z_StringList Z_StringList;
+YAZ_EXPORT int z_StringList (ODR o, Z_StringList **p, int opt, const char *name);
+
+typedef struct Z_Sort Z_Sort;
+YAZ_EXPORT int z_Sort (ODR o, Z_Sort **p, int opt, const char *name);
+
+typedef struct Z_Segmentation Z_Segmentation;
+YAZ_EXPORT int z_Segmentation (ODR o, Z_Segmentation **p, int opt, const char *name);
+
+typedef struct Z_ExtServices Z_ExtServices;
+YAZ_EXPORT int z_ExtServices (ODR o, Z_ExtServices **p, int opt, const char *name);
+
+typedef struct Z_OidList Z_OidList;
+YAZ_EXPORT int z_OidList (ODR o, Z_OidList **p, int opt, const char *name);
+
+typedef struct Z_AltOidList Z_AltOidList;
+YAZ_EXPORT int z_AltOidList (ODR o, Z_AltOidList **p, int opt, const char *name);
+
+typedef struct Z_AccessCtrl Z_AccessCtrl;
+YAZ_EXPORT int z_AccessCtrl (ODR o, Z_AccessCtrl **p, int opt, const char *name);
+
+typedef struct Z_RecordSyntax Z_RecordSyntax;
+YAZ_EXPORT int z_RecordSyntax (ODR o, Z_RecordSyntax **p, int opt, const char *name);
+
+typedef struct Z_DiagFormat Z_DiagFormat;
+YAZ_EXPORT int z_DiagFormat (ODR o, Z_DiagFormat **p, int opt, const char *name);
+#ifdef __cplusplus
+}
+#endif
+#ifdef __cplusplus
+extern "C" {
+#endif
+struct Z_DiagnosticFormat_s {
+	int which;
+	union {
+		Z_DefaultDiagFormat *defaultDiagRec;
+		Z_DiagFormat *explicitDiagnostic;
+#define Z_DiagnosticFormat_s_defaultDiagRec 1
+#define Z_DiagnosticFormat_s_explicitDiagnostic 2
+	} u; /* OPT */
+	Z_InternationalString *message; /* OPT */
+};
+
+struct Z_DiagnosticFormat {
+	int num;
+	Z_DiagnosticFormat_s **elements;
+};
+
+struct Z_TooMany {
+#define Z_TooMany_argumentWords 1
+#define Z_TooMany_truncatedWords 2
+#define Z_TooMany_booleanOperators 3
+#define Z_TooMany_incompleteSubfields 4
+#define Z_TooMany_characters 5
+#define Z_TooMany_recordsRetrieved 6
+#define Z_TooMany_dataBasesSpecified 7
+#define Z_TooMany_resultSetsCreated 8
+#define Z_TooMany_indexTermsProcessed 9
+	int *tooManyWhat;
+	int *max; /* OPT */
+};
+
+struct Z_BadSpec {
+	Z_Specification *spec;
+	Z_DatabaseName *db; /* OPT */
+	int num_goodOnes;
+	Z_Specification **goodOnes; /* OPT */
+};
+
+struct Z_DbUnavail_0 {
+#define Z_DbUnavail_0_doesNotExist 0
+#define Z_DbUnavail_0_existsButUnavail 1
+#define Z_DbUnavail_0_locked 2
+#define Z_DbUnavail_0_accessDenied 3
+	int *reasonCode; /* OPT */
+	Z_InternationalString *message; /* OPT */
+};
+
+struct Z_DbUnavail {
+	Z_DatabaseName *db;
+	Z_DbUnavail_0 *why;
+};
+
+struct Z_Attribute {
+	Odr_oid *id;
+	int *type; /* OPT */
+	int *value; /* OPT */
+	Z_Term *term; /* OPT */
+};
+
+struct Z_AttCombo {
+	Z_AttributeList *unsupportedCombination;
+	int num_recommendedAlternatives;
+	Z_AttributeList **recommendedAlternatives; /* OPT */
+};
+
+struct Z_DiagTerm {
+#define Z_DiagTerm_codedValue 1
+#define Z_DiagTerm_unparsable 2
+#define Z_DiagTerm_tooShort 3
+#define Z_DiagTerm_type 4
+	int *problem; /* OPT */
+	Z_Term *term;
+};
+
+struct Z_Proximity {
+	int which;
+	union {
+		Odr_null *resultSets;
+		Z_InternationalString *badSet;
+		int *relation;
+		int *unit;
+		int *distance;
+		Z_AttributeList *attributes;
+		Odr_null *ordered;
+		Odr_null *exclusion;
+#define Z_Proximity_resultSets 1
+#define Z_Proximity_badSet 2
+#define Z_Proximity_relation 3
+#define Z_Proximity_unit 4
+#define Z_Proximity_distance 5
+#define Z_Proximity_attributes 6
+#define Z_Proximity_ordered 7
+#define Z_Proximity_exclusion 8
+	} u;
+};
+
+struct Z_AttrListList {
+	int num;
+	Z_AttributeList **elements;
+};
+
+struct Z_Scan {
+	int which;
+	union {
+		Odr_null *nonZeroStepSize;
+		Odr_null *specifiedStepSize;
+		Odr_null *termList1;
+		Z_AttrListList *termList2;
+#define Z_Scan_mustBeOne 1
+#define Z_Scan_mustBePositive 2
+#define Z_Scan_mustBeNonNegative 3
+#define Z_Scan_other 4
+		int *posInResponse;
+		Odr_null *resources;
+		Odr_null *endOfList;
+#define Z_Scan_nonZeroStepSize 1
+#define Z_Scan_specifiedStepSize 2
+#define Z_Scan_termList1 3
+#define Z_Scan_termList2 4
+#define Z_Scan_posInResponse 5
+#define Z_Scan_resources 6
+#define Z_Scan_endOfList 7
+	} u;
+};
+
+struct Z_StringList {
+	int num;
+	Z_InternationalString **elements;
+};
+
+struct Z_Sort {
+	int which;
+	union {
+		Odr_null *sequence;
+		Odr_null *noRsName;
+		int *tooMany;
+		Odr_null *incompatible;
+		Odr_null *generic;
+		Odr_null *dbSpecific;
+		Z_SortElement *sortElement;
+#define Z_Sort_tooMany 1
+#define Z_Sort_duplicate 2
+		int *key;
+		Odr_null *action;
+#define Z_Sort_relation 1
+#define Z_Sort_case 2
+#define Z_Sort_action 3
+#define Z_Sort_sort 4
+		int *illegal;
+		Z_StringList *inputTooLarge;
+		Odr_null *aggregateTooLarge;
+#define Z_SortD_sequence 1
+#define Z_SortD_noRsName 2
+#define Z_SortD_tooMany 3
+#define Z_SortD_incompatible 4
+#define Z_SortD_generic 5
+#define Z_SortD_dbSpecific 6
+#define Z_SortD_sortElement 7
+#define Z_SortD_key 8
+#define Z_SortD_action 9
+#define Z_SortD_illegal 10
+#define Z_SortD_inputTooLarge 11
+#define Z_SortD_aggregateTooLarge 12
+	} u;
+};
+
+struct Z_Segmentation {
+	int which;
+	union {
+		Odr_null *segmentCount;
+		int *segmentSize;
+#define Z_Segmentation_segmentCount 1
+#define Z_Segmentation_segmentSize 2
+	} u;
+};
+
+struct Z_ExtServices {
+	int which;
+	union {
+#define Z_ExtServices_nameInUse 1
+#define Z_ExtServices_noSuchName 2
+#define Z_ExtServices_quota 3
+#define Z_ExtServices_type 4
+		int *req;
+#define Z_ExtServices_id 1
+#define Z_ExtServices_modifyDelete 2
+		int *permission;
+#define Z_ExtServices_failed 1
+#define Z_ExtServices_service 2
+#define Z_ExtServices_parameters 3
+		int *immediate;
+#define Z_ExtServices_req 1
+#define Z_ExtServices_permission 2
+#define Z_ExtServices_immediate 3
+	} u;
+};
+
+struct Z_OidList {
+	int num;
+	Odr_oid **elements;
+};
+
+struct Z_AltOidList {
+	int num;
+	Odr_oid **elements;
+};
+
+struct Z_AccessCtrl {
+	int which;
+	union {
+		Odr_null *noUser;
+		Odr_null *refused;
+		Odr_null *simple;
+		Z_OidList *oid;
+		Z_AltOidList *alternative;
+		Odr_null *pwdInv;
+		Odr_null *pwdExp;
+#define Z_AccessCtrl_noUser 1
+#define Z_AccessCtrl_refused 2
+#define Z_AccessCtrl_simple 3
+#define Z_AccessCtrl_oid 4
+#define Z_AccessCtrl_alternative 5
+#define Z_AccessCtrl_pwdInv 6
+#define Z_AccessCtrl_pwdExp 7
+	} u;
+};
+
+struct Z_RecordSyntax {
+	Odr_oid *unsupportedSyntax;
+	int num_suggestedAlternatives;
+	Odr_oid **suggestedAlternatives; /* OPT */
+};
+
+struct Z_DiagFormat {
+	int which;
+	union {
+		Z_TooMany *tooMany;
+		Z_BadSpec *badSpec;
+		Z_DbUnavail *dbUnavail;
+#define Z_DiagFormat_and 0
+#define Z_DiagFormat_or 1
+#define Z_DiagFormat_and_not 2
+#define Z_DiagFormat_prox 3
+		int *unSupOp;
+		Z_Attribute *attribute;
+		Z_AttCombo *attCombo;
+		Z_DiagTerm *term;
+		Z_Proximity *proximity;
+		Z_Scan *scan;
+		Z_Sort *sort;
+		Z_Segmentation *segmentation;
+		Z_ExtServices *extServices;
+		Z_AccessCtrl *accessCtrl;
+		Z_RecordSyntax *recordSyntax;
+#define Z_DiagFormat_tooMany 1
+#define Z_DiagFormat_badSpec 2
+#define Z_DiagFormat_dbUnavail 3
+#define Z_DiagFormat_unSupOp 4
+#define Z_DiagFormat_attribute 5
+#define Z_DiagFormat_attCombo 6
+#define Z_DiagFormat_term 7
+#define Z_DiagFormat_proximity 8
+#define Z_DiagFormat_scan 9
+#define Z_DiagFormat_sort 10
+#define Z_DiagFormat_segmentation 11
+#define Z_DiagFormat_extServices 12
+#define Z_DiagFormat_accessCtrl 13
+#define Z_DiagFormat_recordSyntax 14
+	} u;
+};
+
+#ifdef __cplusplus
+}
+#endif
+#endif
Index: /main/tags/2.25/gsdl/packages/yaz/include/yaz/z-espec1.h
===================================================================
--- /main/tags/2.25/gsdl/packages/yaz/include/yaz/z-espec1.h	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/yaz/include/yaz/z-espec1.h	(revision 21064)
@@ -0,0 +1,142 @@
+/* Generated automatically by the YAZ ASN.1 Compiler 0.3 */
+/* Module-H ElementSpecificationFormat-eSpec-1 */
+
+#ifndef z_espec1_H
+#define z_espec1_H
+
+#include <yaz/odr.h>
+#include <yaz/z-grs.h>
+#include <yaz/z-core.h>
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef struct Z_Espec1 Z_Espec1;
+YAZ_EXPORT int z_Espec1 (ODR o, Z_Espec1 **p, int opt, const char *name);
+
+typedef struct Z_ElementRequestCompositeElementPrimitives Z_ElementRequestCompositeElementPrimitives;
+YAZ_EXPORT int z_ElementRequestCompositeElementPrimitives (ODR o, Z_ElementRequestCompositeElementPrimitives **p, int opt, const char *name);
+
+typedef struct Z_ElementRequestCompositeElementSpecs Z_ElementRequestCompositeElementSpecs;
+YAZ_EXPORT int z_ElementRequestCompositeElementSpecs (ODR o, Z_ElementRequestCompositeElementSpecs **p, int opt, const char *name);
+
+typedef struct Z_ElementRequestCompositeElement Z_ElementRequestCompositeElement;
+YAZ_EXPORT int z_ElementRequestCompositeElement (ODR o, Z_ElementRequestCompositeElement **p, int opt, const char *name);
+
+typedef struct Z_ElementRequest Z_ElementRequest;
+YAZ_EXPORT int z_ElementRequest (ODR o, Z_ElementRequest **p, int opt, const char *name);
+
+typedef struct Z_SimpleElement Z_SimpleElement;
+YAZ_EXPORT int z_SimpleElement (ODR o, Z_SimpleElement **p, int opt, const char *name);
+
+typedef struct Z_SpecificTag Z_SpecificTag;
+YAZ_EXPORT int z_SpecificTag (ODR o, Z_SpecificTag **p, int opt, const char *name);
+
+typedef struct Z_ETagUnit Z_ETagUnit;
+YAZ_EXPORT int z_ETagUnit (ODR o, Z_ETagUnit **p, int opt, const char *name);
+
+typedef struct Z_ETagPath Z_ETagPath;
+YAZ_EXPORT int z_ETagPath (ODR o, Z_ETagPath **p, int opt, const char *name);
+
+typedef struct Z_OccurValues Z_OccurValues;
+YAZ_EXPORT int z_OccurValues (ODR o, Z_OccurValues **p, int opt, const char *name);
+
+typedef struct Z_Occurrences Z_Occurrences;
+YAZ_EXPORT int z_Occurrences (ODR o, Z_Occurrences **p, int opt, const char *name);
+#ifdef __cplusplus
+}
+#endif
+#ifdef __cplusplus
+extern "C" {
+#endif
+struct Z_Espec1 {
+	int num_elementSetNames;
+	Z_InternationalString **elementSetNames; /* OPT */
+	Odr_oid *defaultVariantSetId; /* OPT */
+	Z_Variant *defaultVariantRequest; /* OPT */
+	int *defaultTagType; /* OPT */
+	int num_elements;
+	Z_ElementRequest **elements; /* OPT */
+};
+
+struct Z_ElementRequestCompositeElementPrimitives {
+	int num;
+	Z_InternationalString **elements;
+};
+
+struct Z_ElementRequestCompositeElementSpecs {
+	int num;
+	Z_SimpleElement **elements;
+};
+
+struct Z_ElementRequestCompositeElement {
+	int which;
+	union {
+		Z_ElementRequestCompositeElementPrimitives *primitives;
+		Z_ElementRequestCompositeElementSpecs *specs;
+#define Z_ElementRequestCompositeElement_primitives 1
+#define Z_ElementRequestCompositeElement_specs 2
+	} u;
+	Z_ETagPath *deliveryTag;
+	Z_Variant *variantRequest; /* OPT */
+};
+
+struct Z_ElementRequest {
+	int which;
+	union {
+		Z_SimpleElement *simpleElement;
+		Z_ElementRequestCompositeElement *compositeElement;
+#define Z_ERequest_simpleElement 1
+#define Z_ERequest_compositeElement 2
+	} u;
+};
+
+struct Z_SimpleElement {
+	Z_ETagPath *path;
+	Z_Variant *variantRequest; /* OPT */
+};
+
+struct Z_SpecificTag {
+	int *tagType; /* OPT */
+	Z_StringOrNumeric *tagValue;
+	Z_Occurrences *occurrences; /* OPT */
+};
+
+struct Z_ETagUnit {
+	int which;
+	union {
+		Z_SpecificTag *specificTag;
+		Z_Occurrences *wildThing;
+		Odr_null *wildPath;
+#define Z_ETagUnit_specificTag 1
+#define Z_ETagUnit_wildThing 2
+#define Z_ETagUnit_wildPath 3
+	} u;
+};
+
+struct Z_ETagPath {
+	int num_tags;
+	Z_ETagUnit **tags;
+};
+
+struct Z_OccurValues {
+	int *start;
+	int *howMany; /* OPT */
+};
+
+struct Z_Occurrences {
+	int which;
+	union {
+		Odr_null *all;
+		Odr_null *last;
+		Z_OccurValues *values;
+#define Z_Occurrences_all 1
+#define Z_Occurrences_last 2
+#define Z_Occurrences_values 3
+	} u;
+};
+
+#ifdef __cplusplus
+}
+#endif
+#endif
Index: /main/tags/2.25/gsdl/packages/yaz/include/yaz/z-estask.h
===================================================================
--- /main/tags/2.25/gsdl/packages/yaz/include/yaz/z-estask.h	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/yaz/include/yaz/z-estask.h	(revision 21064)
@@ -0,0 +1,43 @@
+/* Generated automatically by the YAZ ASN.1 Compiler 0.3 */
+/* Module-H RecordSyntax-ESTaskPackage */
+
+#ifndef z_estask_H
+#define z_estask_H
+
+#include <yaz/odr.h>
+#include <yaz/z-core.h>
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef struct Z_TaskPackage Z_TaskPackage;
+YAZ_EXPORT int z_TaskPackage (ODR o, Z_TaskPackage **p, int opt, const char *name);
+#ifdef __cplusplus
+}
+#endif
+#ifdef __cplusplus
+extern "C" {
+#endif
+struct Z_TaskPackage {
+	Odr_oid *packageType;
+	Z_InternationalString *packageName; /* OPT */
+	Z_InternationalString *userId; /* OPT */
+	Z_IntUnit *retentionTime; /* OPT */
+	Z_Permissions *permissions; /* OPT */
+	Z_InternationalString *description; /* OPT */
+	Odr_oct *targetReference; /* OPT */
+	char *creationDateTime; /* OPT */
+#define Z_TaskPackage_pending 0
+#define Z_TaskPackage_active 1
+#define Z_TaskPackage_complete 2
+#define Z_TaskPackage_aborted 3
+	int *taskStatus;
+	int num_packageDiagnostics;
+	Z_DiagRec **packageDiagnostics; /* OPT */
+	Z_External *taskSpecificParameters;
+};
+
+#ifdef __cplusplus
+}
+#endif
+#endif
Index: /main/tags/2.25/gsdl/packages/yaz/include/yaz/z-exp.h
===================================================================
--- /main/tags/2.25/gsdl/packages/yaz/include/yaz/z-exp.h	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/yaz/include/yaz/z-exp.h	(revision 21064)
@@ -0,0 +1,1012 @@
+/* Generated automatically by the YAZ ASN.1 Compiler 0.3 */
+/* Module-H RecordSyntax-explain */
+
+#ifndef z_exp_H
+#define z_exp_H
+
+#include <yaz/odr.h>
+#include <yaz/z-core.h>
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef struct Z_ExplainRecord Z_ExplainRecord;
+YAZ_EXPORT int z_ExplainRecord (ODR o, Z_ExplainRecord **p, int opt, const char *name);
+
+typedef struct Z_TargetInfo Z_TargetInfo;
+YAZ_EXPORT int z_TargetInfo (ODR o, Z_TargetInfo **p, int opt, const char *name);
+
+typedef struct Z_DatabaseInfo Z_DatabaseInfo;
+YAZ_EXPORT int z_DatabaseInfo (ODR o, Z_DatabaseInfo **p, int opt, const char *name);
+
+typedef struct Z_TagTypeMapping Z_TagTypeMapping;
+YAZ_EXPORT int z_TagTypeMapping (ODR o, Z_TagTypeMapping **p, int opt, const char *name);
+
+typedef struct Z_SchemaInfo Z_SchemaInfo;
+YAZ_EXPORT int z_SchemaInfo (ODR o, Z_SchemaInfo **p, int opt, const char *name);
+
+typedef struct Z_ElementInfo Z_ElementInfo;
+YAZ_EXPORT int z_ElementInfo (ODR o, Z_ElementInfo **p, int opt, const char *name);
+
+typedef struct Z_PathUnit Z_PathUnit;
+YAZ_EXPORT int z_PathUnit (ODR o, Z_PathUnit **p, int opt, const char *name);
+
+typedef struct Z_Path Z_Path;
+YAZ_EXPORT int z_Path (ODR o, Z_Path **p, int opt, const char *name);
+
+typedef struct Z_ElementInfoList Z_ElementInfoList;
+YAZ_EXPORT int z_ElementInfoList (ODR o, Z_ElementInfoList **p, int opt, const char *name);
+
+typedef struct Z_ElementDataType Z_ElementDataType;
+YAZ_EXPORT int z_ElementDataType (ODR o, Z_ElementDataType **p, int opt, const char *name);
+
+typedef int  Z_PrimitiveDataType;
+YAZ_EXPORT int z_PrimitiveDataType (ODR o, Z_PrimitiveDataType **p, int opt, const char *name);
+
+typedef struct Z_TagSetElements Z_TagSetElements;
+YAZ_EXPORT int z_TagSetElements (ODR o, Z_TagSetElements **p, int opt, const char *name);
+
+typedef struct Z_TagSetInfo Z_TagSetInfo;
+YAZ_EXPORT int z_TagSetInfo (ODR o, Z_TagSetInfo **p, int opt, const char *name);
+
+typedef struct Z_RecordSyntaxInfo Z_RecordSyntaxInfo;
+YAZ_EXPORT int z_RecordSyntaxInfo (ODR o, Z_RecordSyntaxInfo **p, int opt, const char *name);
+
+typedef struct Z_AttributeSetInfo Z_AttributeSetInfo;
+YAZ_EXPORT int z_AttributeSetInfo (ODR o, Z_AttributeSetInfo **p, int opt, const char *name);
+
+typedef struct Z_AttributeType Z_AttributeType;
+YAZ_EXPORT int z_AttributeType (ODR o, Z_AttributeType **p, int opt, const char *name);
+
+typedef struct Z_AttributeDescription Z_AttributeDescription;
+YAZ_EXPORT int z_AttributeDescription (ODR o, Z_AttributeDescription **p, int opt, const char *name);
+
+typedef struct Z_TermListElement Z_TermListElement;
+YAZ_EXPORT int z_TermListElement (ODR o, Z_TermListElement **p, int opt, const char *name);
+
+typedef struct Z_TermListInfo Z_TermListInfo;
+YAZ_EXPORT int z_TermListInfo (ODR o, Z_TermListInfo **p, int opt, const char *name);
+
+typedef struct Z_ExtendedServicesInfo Z_ExtendedServicesInfo;
+YAZ_EXPORT int z_ExtendedServicesInfo (ODR o, Z_ExtendedServicesInfo **p, int opt, const char *name);
+
+typedef struct Z_AttributeDetails Z_AttributeDetails;
+YAZ_EXPORT int z_AttributeDetails (ODR o, Z_AttributeDetails **p, int opt, const char *name);
+
+typedef struct Z_AttributeSetDetails Z_AttributeSetDetails;
+YAZ_EXPORT int z_AttributeSetDetails (ODR o, Z_AttributeSetDetails **p, int opt, const char *name);
+
+typedef struct Z_AttributeTypeDetails Z_AttributeTypeDetails;
+YAZ_EXPORT int z_AttributeTypeDetails (ODR o, Z_AttributeTypeDetails **p, int opt, const char *name);
+
+typedef struct Z_OmittedAttributeInterpretation Z_OmittedAttributeInterpretation;
+YAZ_EXPORT int z_OmittedAttributeInterpretation (ODR o, Z_OmittedAttributeInterpretation **p, int opt, const char *name);
+
+typedef struct Z_AttributeValue Z_AttributeValue;
+YAZ_EXPORT int z_AttributeValue (ODR o, Z_AttributeValue **p, int opt, const char *name);
+
+typedef struct Z_EScanInfo Z_EScanInfo;
+YAZ_EXPORT int z_EScanInfo (ODR o, Z_EScanInfo **p, int opt, const char *name);
+
+typedef struct Z_TermListDetails Z_TermListDetails;
+YAZ_EXPORT int z_TermListDetails (ODR o, Z_TermListDetails **p, int opt, const char *name);
+
+typedef struct Z_ElementSetDetails Z_ElementSetDetails;
+YAZ_EXPORT int z_ElementSetDetails (ODR o, Z_ElementSetDetails **p, int opt, const char *name);
+
+typedef struct Z_RetrievalRecordDetails Z_RetrievalRecordDetails;
+YAZ_EXPORT int z_RetrievalRecordDetails (ODR o, Z_RetrievalRecordDetails **p, int opt, const char *name);
+
+typedef struct Z_PerElementDetails Z_PerElementDetails;
+YAZ_EXPORT int z_PerElementDetails (ODR o, Z_PerElementDetails **p, int opt, const char *name);
+
+typedef struct Z_RecordTag Z_RecordTag;
+YAZ_EXPORT int z_RecordTag (ODR o, Z_RecordTag **p, int opt, const char *name);
+
+typedef struct Z_SortDetails Z_SortDetails;
+YAZ_EXPORT int z_SortDetails (ODR o, Z_SortDetails **p, int opt, const char *name);
+
+typedef struct Z_SortKeyDetails Z_SortKeyDetails;
+YAZ_EXPORT int z_SortKeyDetails (ODR o, Z_SortKeyDetails **p, int opt, const char *name);
+
+typedef struct Z_ProcessingInformation Z_ProcessingInformation;
+YAZ_EXPORT int z_ProcessingInformation (ODR o, Z_ProcessingInformation **p, int opt, const char *name);
+
+typedef struct Z_VariantSetInfo Z_VariantSetInfo;
+YAZ_EXPORT int z_VariantSetInfo (ODR o, Z_VariantSetInfo **p, int opt, const char *name);
+
+typedef struct Z_VariantClass Z_VariantClass;
+YAZ_EXPORT int z_VariantClass (ODR o, Z_VariantClass **p, int opt, const char *name);
+
+typedef struct Z_VariantType Z_VariantType;
+YAZ_EXPORT int z_VariantType (ODR o, Z_VariantType **p, int opt, const char *name);
+
+typedef struct Z_VariantValue Z_VariantValue;
+YAZ_EXPORT int z_VariantValue (ODR o, Z_VariantValue **p, int opt, const char *name);
+
+typedef struct Z_ValueSetEnumerated Z_ValueSetEnumerated;
+YAZ_EXPORT int z_ValueSetEnumerated (ODR o, Z_ValueSetEnumerated **p, int opt, const char *name);
+
+typedef struct Z_ValueSet Z_ValueSet;
+YAZ_EXPORT int z_ValueSet (ODR o, Z_ValueSet **p, int opt, const char *name);
+
+typedef struct Z_ValueRange Z_ValueRange;
+YAZ_EXPORT int z_ValueRange (ODR o, Z_ValueRange **p, int opt, const char *name);
+
+typedef struct Z_ValueDescription Z_ValueDescription;
+YAZ_EXPORT int z_ValueDescription (ODR o, Z_ValueDescription **p, int opt, const char *name);
+
+typedef struct Z_UnitInfo Z_UnitInfo;
+YAZ_EXPORT int z_UnitInfo (ODR o, Z_UnitInfo **p, int opt, const char *name);
+
+typedef struct Z_UnitType Z_UnitType;
+YAZ_EXPORT int z_UnitType (ODR o, Z_UnitType **p, int opt, const char *name);
+
+typedef struct Z_Units Z_Units;
+YAZ_EXPORT int z_Units (ODR o, Z_Units **p, int opt, const char *name);
+
+typedef struct Z_CategoryList Z_CategoryList;
+YAZ_EXPORT int z_CategoryList (ODR o, Z_CategoryList **p, int opt, const char *name);
+
+typedef struct Z_CategoryInfo Z_CategoryInfo;
+YAZ_EXPORT int z_CategoryInfo (ODR o, Z_CategoryInfo **p, int opt, const char *name);
+
+typedef struct Z_CommonInfo Z_CommonInfo;
+YAZ_EXPORT int z_CommonInfo (ODR o, Z_CommonInfo **p, int opt, const char *name);
+
+typedef struct Z_HumanStringUnit Z_HumanStringUnit;
+YAZ_EXPORT int z_HumanStringUnit (ODR o, Z_HumanStringUnit **p, int opt, const char *name);
+
+typedef struct Z_HumanString Z_HumanString;
+YAZ_EXPORT int z_HumanString (ODR o, Z_HumanString **p, int opt, const char *name);
+
+typedef struct Z_IconObjectUnit Z_IconObjectUnit;
+YAZ_EXPORT int z_IconObjectUnit (ODR o, Z_IconObjectUnit **p, int opt, const char *name);
+
+typedef struct Z_IconObject Z_IconObject;
+YAZ_EXPORT int z_IconObject (ODR o, Z_IconObject **p, int opt, const char *name);
+
+typedef Z_InternationalString  Z_LanguageCode;
+YAZ_EXPORT int z_LanguageCode (ODR o, Z_LanguageCode **p, int opt, const char *name);
+
+typedef struct Z_ContactInfo Z_ContactInfo;
+YAZ_EXPORT int z_ContactInfo (ODR o, Z_ContactInfo **p, int opt, const char *name);
+
+typedef struct Z_NetworkAddressIA Z_NetworkAddressIA;
+YAZ_EXPORT int z_NetworkAddressIA (ODR o, Z_NetworkAddressIA **p, int opt, const char *name);
+
+typedef struct Z_NetworkAddressOPA Z_NetworkAddressOPA;
+YAZ_EXPORT int z_NetworkAddressOPA (ODR o, Z_NetworkAddressOPA **p, int opt, const char *name);
+
+typedef struct Z_NetworkAddressOther Z_NetworkAddressOther;
+YAZ_EXPORT int z_NetworkAddressOther (ODR o, Z_NetworkAddressOther **p, int opt, const char *name);
+
+typedef struct Z_NetworkAddress Z_NetworkAddress;
+YAZ_EXPORT int z_NetworkAddress (ODR o, Z_NetworkAddress **p, int opt, const char *name);
+
+typedef struct Z_AccessInfo Z_AccessInfo;
+YAZ_EXPORT int z_AccessInfo (ODR o, Z_AccessInfo **p, int opt, const char *name);
+
+typedef struct Z_QueryTypeDetails Z_QueryTypeDetails;
+YAZ_EXPORT int z_QueryTypeDetails (ODR o, Z_QueryTypeDetails **p, int opt, const char *name);
+
+typedef struct Z_PrivateCapOperator Z_PrivateCapOperator;
+YAZ_EXPORT int z_PrivateCapOperator (ODR o, Z_PrivateCapOperator **p, int opt, const char *name);
+
+typedef struct Z_PrivateCapabilities Z_PrivateCapabilities;
+YAZ_EXPORT int z_PrivateCapabilities (ODR o, Z_PrivateCapabilities **p, int opt, const char *name);
+
+typedef struct Z_RpnCapabilities Z_RpnCapabilities;
+YAZ_EXPORT int z_RpnCapabilities (ODR o, Z_RpnCapabilities **p, int opt, const char *name);
+
+typedef struct Z_Iso8777Capabilities Z_Iso8777Capabilities;
+YAZ_EXPORT int z_Iso8777Capabilities (ODR o, Z_Iso8777Capabilities **p, int opt, const char *name);
+
+typedef struct Z_ProxSupportPrivate Z_ProxSupportPrivate;
+YAZ_EXPORT int z_ProxSupportPrivate (ODR o, Z_ProxSupportPrivate **p, int opt, const char *name);
+
+typedef struct Z_ProxSupportUnit Z_ProxSupportUnit;
+YAZ_EXPORT int z_ProxSupportUnit (ODR o, Z_ProxSupportUnit **p, int opt, const char *name);
+
+typedef struct Z_ProximitySupport Z_ProximitySupport;
+YAZ_EXPORT int z_ProximitySupport (ODR o, Z_ProximitySupport **p, int opt, const char *name);
+
+typedef struct Z_SearchKey Z_SearchKey;
+YAZ_EXPORT int z_SearchKey (ODR o, Z_SearchKey **p, int opt, const char *name);
+
+typedef struct Z_AccessRestrictionsUnit Z_AccessRestrictionsUnit;
+YAZ_EXPORT int z_AccessRestrictionsUnit (ODR o, Z_AccessRestrictionsUnit **p, int opt, const char *name);
+
+typedef struct Z_AccessRestrictions Z_AccessRestrictions;
+YAZ_EXPORT int z_AccessRestrictions (ODR o, Z_AccessRestrictions **p, int opt, const char *name);
+
+typedef struct Z_CostsOtherCharge Z_CostsOtherCharge;
+YAZ_EXPORT int z_CostsOtherCharge (ODR o, Z_CostsOtherCharge **p, int opt, const char *name);
+
+typedef struct Z_Costs Z_Costs;
+YAZ_EXPORT int z_Costs (ODR o, Z_Costs **p, int opt, const char *name);
+
+typedef struct Z_Charge Z_Charge;
+YAZ_EXPORT int z_Charge (ODR o, Z_Charge **p, int opt, const char *name);
+
+typedef struct Z_DatabaseList Z_DatabaseList;
+YAZ_EXPORT int z_DatabaseList (ODR o, Z_DatabaseList **p, int opt, const char *name);
+
+typedef struct Z_AttributeCombinations Z_AttributeCombinations;
+YAZ_EXPORT int z_AttributeCombinations (ODR o, Z_AttributeCombinations **p, int opt, const char *name);
+
+typedef struct Z_AttributeCombination Z_AttributeCombination;
+YAZ_EXPORT int z_AttributeCombination (ODR o, Z_AttributeCombination **p, int opt, const char *name);
+
+typedef struct Z_AttributeValueList Z_AttributeValueList;
+YAZ_EXPORT int z_AttributeValueList (ODR o, Z_AttributeValueList **p, int opt, const char *name);
+
+typedef struct Z_AttributeOccurrence Z_AttributeOccurrence;
+YAZ_EXPORT int z_AttributeOccurrence (ODR o, Z_AttributeOccurrence **p, int opt, const char *name);
+#ifdef __cplusplus
+}
+#endif
+#ifdef __cplusplus
+extern "C" {
+#endif
+struct Z_ExplainRecord {
+	int which;
+	union {
+		Z_TargetInfo *targetInfo;
+		Z_DatabaseInfo *databaseInfo;
+		Z_SchemaInfo *schemaInfo;
+		Z_TagSetInfo *tagSetInfo;
+		Z_RecordSyntaxInfo *recordSyntaxInfo;
+		Z_AttributeSetInfo *attributeSetInfo;
+		Z_TermListInfo *termListInfo;
+		Z_ExtendedServicesInfo *extendedServicesInfo;
+		Z_AttributeDetails *attributeDetails;
+		Z_TermListDetails *termListDetails;
+		Z_ElementSetDetails *elementSetDetails;
+		Z_RetrievalRecordDetails *retrievalRecordDetails;
+		Z_SortDetails *sortDetails;
+		Z_ProcessingInformation *processing;
+		Z_VariantSetInfo *variants;
+		Z_UnitInfo *units;
+		Z_CategoryList *categoryList;
+#define Z_Explain_targetInfo 1
+#define Z_Explain_databaseInfo 2
+#define Z_Explain_schemaInfo 3
+#define Z_Explain_tagSetInfo 4
+#define Z_Explain_recordSyntaxInfo 5
+#define Z_Explain_attributeSetInfo 6
+#define Z_Explain_termListInfo 7
+#define Z_Explain_extendedServicesInfo 8
+#define Z_Explain_attributeDetails 9
+#define Z_Explain_termListDetails 10
+#define Z_Explain_elementSetDetails 11
+#define Z_Explain_retrievalRecordDetails 12
+#define Z_Explain_sortDetails 13
+#define Z_Explain_processing 14
+#define Z_Explain_variants 15
+#define Z_Explain_units 16
+#define Z_Explain_categoryList 17
+	} u;
+};
+
+struct Z_TargetInfo {
+	Z_CommonInfo *commonInfo; /* OPT */
+	Z_InternationalString *name;
+	Z_HumanString *recentNews; /* OPT */
+	Z_IconObject *icon; /* OPT */
+	bool_t *namedResultSets;
+	bool_t *multipleDBsearch;
+	int *maxResultSets; /* OPT */
+	int *maxResultSize; /* OPT */
+	int *maxTerms; /* OPT */
+	Z_IntUnit *timeoutInterval; /* OPT */
+	Z_HumanString *welcomeMessage; /* OPT */
+	Z_ContactInfo *contactInfo; /* OPT */
+	Z_HumanString *description; /* OPT */
+	int num_nicknames;
+	Z_InternationalString **nicknames; /* OPT */
+	Z_HumanString *usageRest; /* OPT */
+	Z_HumanString *paymentAddr; /* OPT */
+	Z_HumanString *hours; /* OPT */
+	int num_dbCombinations;
+	Z_DatabaseList **dbCombinations; /* OPT */
+	int num_addresses;
+	Z_NetworkAddress **addresses; /* OPT */
+	int num_languages;
+	Z_InternationalString **languages; /* OPT */
+	Z_AccessInfo *commonAccessInfo; /* OPT */
+};
+
+struct Z_DatabaseInfo {
+	Z_CommonInfo *commonInfo; /* OPT */
+	Z_DatabaseName *name;
+	Odr_null *explainDatabase; /* OPT */
+	int num_nicknames;
+	Z_DatabaseName **nicknames; /* OPT */
+	Z_IconObject *icon; /* OPT */
+	bool_t *userFee;
+	bool_t *available;
+	Z_HumanString *titleString; /* OPT */
+	int num_keywords;
+	Z_HumanString **keywords; /* OPT */
+	Z_HumanString *description; /* OPT */
+	Z_DatabaseList *associatedDbs; /* OPT */
+	Z_DatabaseList *subDbs; /* OPT */
+	Z_HumanString *disclaimers; /* OPT */
+	Z_HumanString *news; /* OPT */
+	int which;
+	union {
+		int *actualNumber;
+		int *approxNumber;
+#define Z_DatabaseInfo_actualNumber 1
+#define Z_DatabaseInfo_approxNumber 2
+	} u; /* OPT */
+	Z_HumanString *defaultOrder; /* OPT */
+	int *avRecordSize; /* OPT */
+	int *maxRecordSize; /* OPT */
+	Z_HumanString *hours; /* OPT */
+	Z_HumanString *bestTime; /* OPT */
+	char *lastUpdate; /* OPT */
+	Z_IntUnit *updateInterval; /* OPT */
+	Z_HumanString *coverage; /* OPT */
+	bool_t *proprietary; /* OPT */
+	Z_HumanString *copyrightText; /* OPT */
+	Z_HumanString *copyrightNotice; /* OPT */
+	Z_ContactInfo *producerContactInfo; /* OPT */
+	Z_ContactInfo *supplierContactInfo; /* OPT */
+	Z_ContactInfo *submissionContactInfo; /* OPT */
+	Z_AccessInfo *accessInfo; /* OPT */
+};
+
+struct Z_TagTypeMapping {
+	int *tagType;
+	Odr_oid *tagSet; /* OPT */
+	Odr_null *defaultTagType; /* OPT */
+};
+
+struct Z_SchemaInfo {
+	Z_CommonInfo *commonInfo; /* OPT */
+	Odr_oid *schema;
+	Z_InternationalString *name;
+	Z_HumanString *description; /* OPT */
+	int num_tagTypeMapping;
+	Z_TagTypeMapping **tagTypeMapping; /* OPT */
+	int num_recordStructure;
+	Z_ElementInfo **recordStructure; /* OPT */
+};
+
+struct Z_ElementInfo {
+	Z_InternationalString *elementName;
+	Z_Path *elementTagPath;
+	Z_ElementDataType *dataType; /* OPT */
+	bool_t *required;
+	bool_t *repeatable;
+	Z_HumanString *description; /* OPT */
+};
+
+struct Z_PathUnit {
+	int *tagType;
+	Z_StringOrNumeric *tagValue;
+};
+
+struct Z_Path {
+	int num;
+	Z_PathUnit **elements;
+};
+
+struct Z_ElementInfoList {
+	int num;
+	Z_ElementInfo **elements;
+};
+
+struct Z_ElementDataType {
+	int which;
+	union {
+		Z_PrimitiveDataType *primitive;
+		Z_ElementInfoList *structured;
+#define Z_ElementDataType_primitive 1
+#define Z_ElementDataType_structured 2
+	} u;
+};
+
+#define Z_PrimitiveDataType_octetString 0
+#define Z_PrimitiveDataType_numeric 1
+#define Z_PrimitiveDataType_date 2
+#define Z_PrimitiveDataType_external 3
+#define Z_PrimitiveDataType_string 4
+#define Z_PrimitiveDataType_trueOrFalse 5
+#define Z_PrimitiveDataType_oid 6
+#define Z_PrimitiveDataType_intUnit 7
+#define Z_PrimitiveDataType_empty 8
+#define Z_PrimitiveDataType_noneOfTheAbove 100
+
+struct Z_TagSetElements {
+	Z_InternationalString *elementname;
+	int num_nicknames;
+	Z_InternationalString **nicknames; /* OPT */
+	Z_StringOrNumeric *elementTag;
+	Z_HumanString *description; /* OPT */
+	Z_PrimitiveDataType *dataType; /* OPT */
+	Z_OtherInformation *otherTagInfo; /* OPT */
+};
+
+struct Z_TagSetInfo {
+	Z_CommonInfo *commonInfo; /* OPT */
+	Odr_oid *tagSet;
+	Z_InternationalString *name;
+	Z_HumanString *description; /* OPT */
+	int num_elements;
+	Z_TagSetElements **elements; /* OPT */
+};
+
+struct Z_RecordSyntaxInfo {
+	Z_CommonInfo *commonInfo; /* OPT */
+	Odr_oid *recordSyntax;
+	Z_InternationalString *name;
+	int num_transferSyntaxes;
+	Odr_oid **transferSyntaxes; /* OPT */
+	Z_HumanString *description; /* OPT */
+	Z_InternationalString *asn1Module; /* OPT */
+	int num_abstractStructure;
+	Z_ElementInfo **abstractStructure; /* OPT */
+};
+
+struct Z_AttributeSetInfo {
+	Z_CommonInfo *commonInfo; /* OPT */
+	Z_AttributeSetId *attributeSet;
+	Z_InternationalString *name;
+	int num_attributes;
+	Z_AttributeType **attributes; /* OPT */
+	Z_HumanString *description; /* OPT */
+};
+
+struct Z_AttributeType {
+	Z_InternationalString *name; /* OPT */
+	Z_HumanString *description; /* OPT */
+	int *attributeType;
+	int num_attributeValues;
+	Z_AttributeDescription **attributeValues;
+};
+
+struct Z_AttributeDescription {
+	Z_InternationalString *name; /* OPT */
+	Z_HumanString *description; /* OPT */
+	Z_StringOrNumeric *attributeValue;
+	int num_equivalentAttributes;
+	Z_StringOrNumeric **equivalentAttributes; /* OPT */
+};
+
+struct Z_TermListElement {
+	Z_InternationalString *name;
+	Z_HumanString *title; /* OPT */
+#define Z_TermListElement_optimized 0
+#define Z_TermListElement_normal 1
+#define Z_TermListElement_expensive 2
+#define Z_TermListElement_filter 3
+	int *searchCost; /* OPT */
+	bool_t *scanable;
+	int num_broader;
+	Z_InternationalString **broader; /* OPT */
+	int num_narrower;
+	Z_InternationalString **narrower; /* OPT */
+};
+
+struct Z_TermListInfo {
+	Z_CommonInfo *commonInfo; /* OPT */
+	Z_DatabaseName *databaseName;
+	int num_termLists;
+	Z_TermListElement **termLists;
+};
+
+struct Z_ExtendedServicesInfo {
+	Z_CommonInfo *commonInfo; /* OPT */
+	Odr_oid *type;
+	Z_InternationalString *name; /* OPT */
+	bool_t *privateType;
+	bool_t *restrictionsApply;
+	bool_t *feeApply;
+	bool_t *available;
+	bool_t *retentionSupported;
+#define Z_ExtendedServicesInfo_waitSupported 1
+#define Z_ExtendedServicesInfo_waitAlways 2
+#define Z_ExtendedServicesInfo_waitNotSupported 3
+#define Z_ExtendedServicesInfo_depends 4
+#define Z_ExtendedServicesInfo_notSaying 5
+	int *waitAction;
+	Z_HumanString *description; /* OPT */
+	Z_External *specificExplain; /* OPT */
+	Z_InternationalString *esASN; /* OPT */
+};
+
+struct Z_AttributeDetails {
+	Z_CommonInfo *commonInfo; /* OPT */
+	Z_DatabaseName *databaseName;
+	int num_attributesBySet;
+	Z_AttributeSetDetails **attributesBySet; /* OPT */
+	Z_AttributeCombinations *attributeCombinations; /* OPT */
+};
+
+struct Z_AttributeSetDetails {
+	Z_AttributeSetId *attributeSet;
+	int num_attributesByType;
+	Z_AttributeTypeDetails **attributesByType;
+};
+
+struct Z_AttributeTypeDetails {
+	int *attributeType;
+	Z_OmittedAttributeInterpretation *defaultIfOmitted; /* OPT */
+	int num_attributeValues;
+	Z_AttributeValue **attributeValues; /* OPT */
+};
+
+struct Z_OmittedAttributeInterpretation {
+	Z_StringOrNumeric *defaultValue; /* OPT */
+	Z_HumanString *defaultDescription; /* OPT */
+};
+
+struct Z_AttributeValue {
+	Z_StringOrNumeric *value;
+	Z_HumanString *description; /* OPT */
+	int num_subAttributes;
+	Z_StringOrNumeric **subAttributes; /* OPT */
+	int num_superAttributes;
+	Z_StringOrNumeric **superAttributes; /* OPT */
+	Odr_null *partialSupport; /* OPT */
+};
+
+struct Z_EScanInfo {
+	int *maxStepSize; /* OPT */
+	Z_HumanString *collatingSequence; /* OPT */
+	bool_t *increasing; /* OPT */
+};
+
+struct Z_TermListDetails {
+	Z_CommonInfo *commonInfo; /* OPT */
+	Z_InternationalString *termListName;
+	Z_HumanString *description; /* OPT */
+	Z_AttributeCombinations *attributes; /* OPT */
+	Z_EScanInfo *scanInfo; /* OPT */
+	int *estNumberTerms; /* OPT */
+	int num_sampleTerms;
+	Z_Term **sampleTerms; /* OPT */
+};
+
+struct Z_ElementSetDetails {
+	Z_CommonInfo *commonInfo; /* OPT */
+	Z_DatabaseName *databaseName;
+	Z_ElementSetName *elementSetName;
+	Odr_oid *recordSyntax;
+	Odr_oid *schema;
+	Z_HumanString *description; /* OPT */
+	int num_detailsPerElement;
+	Z_PerElementDetails **detailsPerElement; /* OPT */
+};
+
+struct Z_RetrievalRecordDetails {
+	Z_CommonInfo *commonInfo; /* OPT */
+	Z_DatabaseName *databaseName;
+	Odr_oid *schema;
+	Odr_oid *recordSyntax;
+	Z_HumanString *description; /* OPT */
+	int num_detailsPerElement;
+	Z_PerElementDetails **detailsPerElement; /* OPT */
+};
+
+struct Z_PerElementDetails {
+	Z_InternationalString *name; /* OPT */
+	Z_RecordTag *recordTag; /* OPT */
+	int num_schemaTags;
+	Z_Path **schemaTags; /* OPT */
+	int *maxSize; /* OPT */
+	int *minSize; /* OPT */
+	int *avgSize; /* OPT */
+	int *fixedSize; /* OPT */
+	bool_t *repeatable;
+	bool_t *required;
+	Z_HumanString *description; /* OPT */
+	Z_HumanString *contents; /* OPT */
+	Z_HumanString *billingInfo; /* OPT */
+	Z_HumanString *restrictions; /* OPT */
+	int num_alternateNames;
+	Z_InternationalString **alternateNames; /* OPT */
+	int num_genericNames;
+	Z_InternationalString **genericNames; /* OPT */
+	Z_AttributeCombinations *searchAccess; /* OPT */
+};
+
+struct Z_RecordTag {
+	Z_StringOrNumeric *qualifier; /* OPT */
+	Z_StringOrNumeric *tagValue;
+};
+
+struct Z_SortDetails {
+	Z_CommonInfo *commonInfo; /* OPT */
+	Z_DatabaseName *databaseName;
+	int num_sortKeys;
+	Z_SortKeyDetails **sortKeys; /* OPT */
+};
+
+struct Z_SortKeyDetails {
+	Z_HumanString *description; /* OPT */
+	int num_elementSpecifications;
+	Z_Specification **elementSpecifications; /* OPT */
+	Z_AttributeCombinations *attributeSpecifications; /* OPT */
+	int which;
+	union {
+		Odr_null *character;
+		Odr_null *numeric;
+		Z_HumanString *structured;
+#define Z_SortKeyDetails_character 1
+#define Z_SortKeyDetails_numeric 2
+#define Z_SortKeyDetails_structured 3
+	} u; /* OPT */
+#define Z_SortKeyDetails_always 0
+#define Z_SortKeyDetails_never 1
+#define Z_SortKeyDetails_default_yes 2
+#define Z_SortKeyDetails_default_no 3
+	int *caseSensitivity; /* OPT */
+};
+
+struct Z_ProcessingInformation {
+	Z_CommonInfo *commonInfo; /* OPT */
+	Z_DatabaseName *databaseName;
+#define Z_ProcessingInformation_access 0
+#define Z_ProcessingInformation_search 1
+#define Z_ProcessingInformation_retrieval 2
+#define Z_ProcessingInformation_record_presentation 3
+#define Z_ProcessingInformation_record_handling 4
+	int *processingContext;
+	Z_InternationalString *name;
+	Odr_oid *oid;
+	Z_HumanString *description; /* OPT */
+	Z_External *instructions; /* OPT */
+};
+
+struct Z_VariantSetInfo {
+	Z_CommonInfo *commonInfo; /* OPT */
+	Odr_oid *variantSet;
+	Z_InternationalString *name;
+	int num_variants;
+	Z_VariantClass **variants; /* OPT */
+};
+
+struct Z_VariantClass {
+	Z_InternationalString *name; /* OPT */
+	Z_HumanString *description; /* OPT */
+	int *variantClass;
+	int num_variantTypes;
+	Z_VariantType **variantTypes;
+};
+
+struct Z_VariantType {
+	Z_InternationalString *name; /* OPT */
+	Z_HumanString *description; /* OPT */
+	int *variantType;
+	Z_VariantValue *variantValue; /* OPT */
+};
+
+struct Z_VariantValue {
+	Z_PrimitiveDataType *dataType;
+	Z_ValueSet *values; /* OPT */
+};
+
+struct Z_ValueSetEnumerated {
+	int num;
+	Z_ValueDescription **elements;
+};
+
+struct Z_ValueSet {
+	int which;
+	union {
+		Z_ValueRange *range;
+		Z_ValueSetEnumerated *enumerated;
+#define Z_ValueSet_range 1
+#define Z_ValueSet_enumerated 2
+	} u;
+};
+
+struct Z_ValueRange {
+	Z_ValueDescription *lower; /* OPT */
+	Z_ValueDescription *upper; /* OPT */
+};
+
+struct Z_ValueDescription {
+	int which;
+	union {
+		int *integer;
+		Z_InternationalString *string;
+		Odr_oct *octets;
+		Odr_oid *oid;
+		Z_Unit *unit;
+		Z_IntUnit *valueAndUnit;
+#define Z_ValueDescription_integer 1
+#define Z_ValueDescription_string 2
+#define Z_ValueDescription_octets 3
+#define Z_ValueDescription_oid 4
+#define Z_ValueDescription_unit 5
+#define Z_ValueDescription_valueAndUnit 6
+	} u;
+};
+
+struct Z_UnitInfo {
+	Z_CommonInfo *commonInfo; /* OPT */
+	Z_InternationalString *unitSystem;
+	Z_HumanString *description; /* OPT */
+	int num_units;
+	Z_UnitType **units; /* OPT */
+};
+
+struct Z_UnitType {
+	Z_InternationalString *name; /* OPT */
+	Z_HumanString *description; /* OPT */
+	Z_StringOrNumeric *unitType;
+	int num_units;
+	Z_Units **units;
+};
+
+struct Z_Units {
+	Z_InternationalString *name; /* OPT */
+	Z_HumanString *description; /* OPT */
+	Z_StringOrNumeric *unit;
+};
+
+struct Z_CategoryList {
+	Z_CommonInfo *commonInfo; /* OPT */
+	int num_categories;
+	Z_CategoryInfo **categories;
+};
+
+struct Z_CategoryInfo {
+	Z_InternationalString *category;
+	Z_InternationalString *originalCategory; /* OPT */
+	Z_HumanString *description; /* OPT */
+	Z_InternationalString *asn1Module; /* OPT */
+};
+
+struct Z_CommonInfo {
+	char *dateAdded; /* OPT */
+	char *dateChanged; /* OPT */
+	char *expiry; /* OPT */
+	Z_LanguageCode *humanStringLanguage; /* OPT */
+	Z_OtherInformation *otherInfo; /* OPT */
+};
+
+struct Z_HumanStringUnit {
+	Z_LanguageCode *language; /* OPT */
+	Z_InternationalString *text;
+};
+
+struct Z_HumanString {
+	int num_strings;
+	Z_HumanStringUnit **strings;
+};
+
+struct Z_IconObjectUnit {
+	int which;
+	union {
+		Z_InternationalString *ianaType;
+		Z_InternationalString *z3950type;
+		Z_InternationalString *otherType;
+#define Z_IconObjectUnit_ianaType 1
+#define Z_IconObjectUnit_z3950type 2
+#define Z_IconObjectUnit_otherType 3
+	} u;
+	Odr_oct *content;
+};
+
+struct Z_IconObject {
+	int num;
+	Z_IconObjectUnit **elements;
+};
+
+
+
+struct Z_ContactInfo {
+	Z_InternationalString *name; /* OPT */
+	Z_HumanString *description; /* OPT */
+	Z_HumanString *address; /* OPT */
+	Z_InternationalString *email; /* OPT */
+	Z_InternationalString *phone; /* OPT */
+};
+
+struct Z_NetworkAddressIA {
+	Z_InternationalString *hostAddress;
+	int *port;
+};
+
+struct Z_NetworkAddressOPA {
+	Z_InternationalString *pSel;
+	Z_InternationalString *sSel; /* OPT */
+	Z_InternationalString *tSel; /* OPT */
+	Z_InternationalString *nSap;
+};
+
+struct Z_NetworkAddressOther {
+	Z_InternationalString *type;
+	Z_InternationalString *address;
+};
+
+struct Z_NetworkAddress {
+	int which;
+	union {
+		Z_NetworkAddressIA *internetAddress;
+		Z_NetworkAddressOPA *osiPresentationAddress;
+		Z_NetworkAddressOther *other;
+#define Z_NetworkAddress_iA 1
+#define Z_NetworkAddress_oPA 2
+#define Z_NetworkAddress_other 3
+	} u;
+};
+
+struct Z_AccessInfo {
+	int num_queryTypesSupported;
+	Z_QueryTypeDetails **queryTypesSupported; /* OPT */
+	int num_diagnosticsSets;
+	Odr_oid **diagnosticsSets; /* OPT */
+	int num_attributeSetIds;
+	Z_AttributeSetId **attributeSetIds; /* OPT */
+	int num_schemas;
+	Odr_oid **schemas; /* OPT */
+	int num_recordSyntaxes;
+	Odr_oid **recordSyntaxes; /* OPT */
+	int num_resourceChallenges;
+	Odr_oid **resourceChallenges; /* OPT */
+	Z_AccessRestrictions *restrictedAccess; /* OPT */
+	Z_Costs *costInfo; /* OPT */
+	int num_variantSets;
+	Odr_oid **variantSets; /* OPT */
+	int num_elementSetNames;
+	Z_ElementSetName **elementSetNames; /* OPT */
+	int num_unitSystems;
+	Z_InternationalString **unitSystems;
+};
+
+struct Z_QueryTypeDetails {
+	int which;
+	union {
+		Z_PrivateCapabilities *zprivate;
+		Z_RpnCapabilities *rpn;
+		Z_Iso8777Capabilities *iso8777;
+		Z_HumanString *z39_58;
+		Z_RpnCapabilities *erpn;
+		Z_HumanString *rankedList;
+#define Z_QueryTypeDetails_private 1
+#define Z_QueryTypeDetails_rpn 2
+#define Z_QueryTypeDetails_iso8777 3
+#define Z_QueryTypeDetails_z39_58 4
+#define Z_QueryTypeDetails_erpn 5
+#define Z_QueryTypeDetails_rankedList 6
+	} u;
+};
+
+struct Z_PrivateCapOperator {
+	Z_InternationalString *roperator;
+	Z_HumanString *description; /* OPT */
+};
+
+struct Z_PrivateCapabilities {
+	int num_operators;
+	Z_PrivateCapOperator **operators; /* OPT */
+	int num_searchKeys;
+	Z_SearchKey **searchKeys; /* OPT */
+	int num_description;
+	Z_HumanString **description; /* OPT */
+};
+
+struct Z_RpnCapabilities {
+	int num_operators;
+	int **operators; /* OPT */
+	bool_t *resultSetAsOperandSupported;
+	bool_t *restrictionOperandSupported;
+	Z_ProximitySupport *proximity; /* OPT */
+};
+
+struct Z_Iso8777Capabilities {
+	int num_searchKeys;
+	Z_SearchKey **searchKeys;
+	Z_HumanString *restrictions; /* OPT */
+};
+
+struct Z_ProxSupportPrivate {
+	int *unit;
+	Z_HumanString *description; /* OPT */
+};
+
+struct Z_ProxSupportUnit {
+	int which;
+	union {
+		int *known;
+		Z_ProxSupportPrivate *zprivate;
+#define Z_ProxSupportUnit_known 1
+#define Z_ProxSupportUnit_private 2
+	} u;
+};
+
+struct Z_ProximitySupport {
+	bool_t *anySupport;
+	int num_unitsSupported;
+	Z_ProxSupportUnit **unitsSupported; /* OPT */
+};
+
+struct Z_SearchKey {
+	Z_InternationalString *searchKey;
+	Z_HumanString *description; /* OPT */
+};
+
+struct Z_AccessRestrictionsUnit {
+#define Z_AccessRestrictionsUnit_any 0
+#define Z_AccessRestrictionsUnit_search 1
+#define Z_AccessRestrictionsUnit_present 2
+#define Z_AccessRestrictionsUnit_specific_elements 3
+#define Z_AccessRestrictionsUnit_extended_services 4
+#define Z_AccessRestrictionsUnit_by_database 5
+	int *accessType;
+	Z_HumanString *accessText; /* OPT */
+	int num_accessChallenges;
+	Odr_oid **accessChallenges; /* OPT */
+};
+
+struct Z_AccessRestrictions {
+	int num;
+	Z_AccessRestrictionsUnit **elements;
+};
+
+struct Z_CostsOtherCharge {
+	Z_HumanString *forWhat;
+	Z_Charge *charge;
+};
+
+struct Z_Costs {
+	Z_Charge *connectCharge; /* OPT */
+	Z_Charge *connectTime; /* OPT */
+	Z_Charge *displayCharge; /* OPT */
+	Z_Charge *searchCharge; /* OPT */
+	Z_Charge *subscriptCharge; /* OPT */
+	int num_otherCharges;
+	Z_CostsOtherCharge **otherCharges; /* OPT */
+};
+
+struct Z_Charge {
+	Z_IntUnit *cost;
+	Z_Unit *perWhat; /* OPT */
+	Z_HumanString *text; /* OPT */
+};
+
+struct Z_DatabaseList {
+	int num_databases;
+	Z_DatabaseName **databases;
+};
+
+struct Z_AttributeCombinations {
+	Z_AttributeSetId *defaultAttributeSet;
+	int num_legalCombinations;
+	Z_AttributeCombination **legalCombinations;
+};
+
+struct Z_AttributeCombination {
+	int num_occurrences;
+	Z_AttributeOccurrence **occurrences;
+};
+
+struct Z_AttributeValueList {
+	int num_attributes;
+	Z_StringOrNumeric **attributes;
+};
+
+struct Z_AttributeOccurrence {
+	Z_AttributeSetId *attributeSet; /* OPT */
+	int *attributeType;
+	Odr_null *mustBeSupplied; /* OPT */
+	int which;
+	union {
+		Odr_null *any_or_none;
+		Z_AttributeValueList *specific;
+#define Z_AttributeOcc_any_or_none 1
+#define Z_AttributeOcc_specific 2
+	} attributeValues;
+};
+
+#ifdef __cplusplus
+}
+#endif
+#endif
Index: /main/tags/2.25/gsdl/packages/yaz/include/yaz/z-grs.h
===================================================================
--- /main/tags/2.25/gsdl/packages/yaz/include/yaz/z-grs.h	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/yaz/include/yaz/z-grs.h	(revision 21064)
@@ -0,0 +1,178 @@
+/* Generated automatically by the YAZ ASN.1 Compiler 0.3 */
+/* Module-H RecordSyntax-generic */
+
+#ifndef z_grs_H
+#define z_grs_H
+
+#include <yaz/odr.h>
+#include <yaz/z-core.h>
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef struct Z_GenericRecord Z_GenericRecord;
+YAZ_EXPORT int z_GenericRecord (ODR o, Z_GenericRecord **p, int opt, const char *name);
+
+typedef struct Z_TaggedElement Z_TaggedElement;
+YAZ_EXPORT int z_TaggedElement (ODR o, Z_TaggedElement **p, int opt, const char *name);
+
+typedef struct Z_ElementData Z_ElementData;
+YAZ_EXPORT int z_ElementData (ODR o, Z_ElementData **p, int opt, const char *name);
+
+typedef struct Z_ElementMetaData Z_ElementMetaData;
+YAZ_EXPORT int z_ElementMetaData (ODR o, Z_ElementMetaData **p, int opt, const char *name);
+
+typedef struct Z_TagPath_s Z_TagPath_s;
+YAZ_EXPORT int z_TagPath_s (ODR o, Z_TagPath_s **p, int opt, const char *name);
+
+typedef struct Z_TagPath Z_TagPath;
+YAZ_EXPORT int z_TagPath (ODR o, Z_TagPath **p, int opt, const char *name);
+
+typedef struct Z_Order Z_Order;
+YAZ_EXPORT int z_Order (ODR o, Z_Order **p, int opt, const char *name);
+
+typedef struct Z_Usage Z_Usage;
+YAZ_EXPORT int z_Usage (ODR o, Z_Usage **p, int opt, const char *name);
+
+typedef struct Z_HitVector Z_HitVector;
+YAZ_EXPORT int z_HitVector (ODR o, Z_HitVector **p, int opt, const char *name);
+
+typedef struct Z_Triple Z_Triple;
+YAZ_EXPORT int z_Triple (ODR o, Z_Triple **p, int opt, const char *name);
+
+typedef struct Z_Variant Z_Variant;
+YAZ_EXPORT int z_Variant (ODR o, Z_Variant **p, int opt, const char *name);
+#ifdef __cplusplus
+}
+#endif
+#ifdef __cplusplus
+extern "C" {
+#endif
+struct Z_GenericRecord {
+	int num_elements;
+	Z_TaggedElement **elements;
+};
+
+struct Z_TaggedElement {
+	int *tagType; /* OPT */
+	Z_StringOrNumeric *tagValue;
+	int *tagOccurrence; /* OPT */
+	Z_ElementData *content;
+	Z_ElementMetaData *metaData; /* OPT */
+	Z_Variant *appliedVariant; /* OPT */
+};
+
+struct Z_ElementData {
+	int which;
+	union {
+		Odr_oct *octets;
+		int *numeric;
+		char *date;
+		Z_External *ext;
+		Z_InternationalString *string;
+		bool_t *trueOrFalse;
+		Odr_oid *oid;
+		Z_IntUnit *intUnit;
+		Odr_null *elementNotThere;
+		Odr_null *elementEmpty;
+		Odr_null *noDataRequested;
+		Z_External *diagnostic;
+		Z_GenericRecord *subtree;
+#define Z_ElementData_octets 1
+#define Z_ElementData_numeric 2
+#define Z_ElementData_date 3
+#define Z_ElementData_ext 4
+#define Z_ElementData_string 5
+#define Z_ElementData_trueOrFalse 6
+#define Z_ElementData_oid 7
+#define Z_ElementData_intUnit 8
+#define Z_ElementData_elementNotThere 9
+#define Z_ElementData_elementEmpty 10
+#define Z_ElementData_noDataRequested 11
+#define Z_ElementData_diagnostic 12
+#define Z_ElementData_subtree 13
+	} u;
+};
+
+struct Z_ElementMetaData {
+	Z_Order *seriesOrder; /* OPT */
+	Z_Usage *usageRight; /* OPT */
+	int num_hits;
+	Z_HitVector **hits; /* OPT */
+	Z_InternationalString *displayName; /* OPT */
+	int num_supportedVariants;
+	Z_Variant **supportedVariants; /* OPT */
+	Z_InternationalString *message; /* OPT */
+	Odr_oct *elementDescriptor; /* OPT */
+	Z_TagPath *surrogateFor; /* OPT */
+	Z_TagPath *surrogateElement; /* OPT */
+	Z_External *other; /* OPT */
+};
+
+struct Z_TagPath_s {
+	int *tagType; /* OPT */
+	Z_StringOrNumeric *tagValue;
+	int *tagOccurrence; /* OPT */
+};
+
+struct Z_TagPath {
+	int num;
+	Z_TagPath_s **elements;
+};
+
+struct Z_Order {
+	bool_t *ascending;
+	int *order;
+};
+
+struct Z_Usage {
+#define Z_Usage_redistributable 1
+#define Z_Usage_restricted 2
+#define Z_Usage_licensePointer 3
+	int *type;
+	Z_InternationalString *restriction; /* OPT */
+};
+
+struct Z_HitVector {
+	Z_Term *satisfier; /* OPT */
+	Z_IntUnit *offsetIntoElement; /* OPT */
+	Z_IntUnit *length; /* OPT */
+	int *hitRank; /* OPT */
+	Odr_oct *targetToken; /* OPT */
+};
+
+struct Z_Triple {
+	Odr_oid *variantSetId; /* OPT */
+	int *zclass;
+	int *type;
+	int which;
+	union {
+		int *integer;
+		Z_InternationalString *internationalString;
+		Odr_oct *octetString;
+		Odr_oid *objectIdentifier;
+		bool_t *boolean;
+		Odr_null *null;
+		Z_Unit *unit;
+		Z_IntUnit *valueAndUnit;
+#define Z_Triple_integer 1
+#define Z_Triple_internationalString 2
+#define Z_Triple_octetString 3
+#define Z_Triple_objectIdentifier 4
+#define Z_Triple_boolean 5
+#define Z_Triple_null 6
+#define Z_Triple_unit 7
+#define Z_Triple_valueAndUnit 8
+	} value;
+};
+
+struct Z_Variant {
+	Odr_oid *globalVariantSetId; /* OPT */
+	int num_triples;
+	Z_Triple **triples;
+};
+
+#ifdef __cplusplus
+}
+#endif
+#endif
Index: /main/tags/2.25/gsdl/packages/yaz/include/yaz/z-opac.h
===================================================================
--- /main/tags/2.25/gsdl/packages/yaz/include/yaz/z-opac.h	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/yaz/include/yaz/z-opac.h	(revision 21064)
@@ -0,0 +1,95 @@
+/* Generated automatically by the YAZ ASN.1 Compiler 0.3 */
+/* Module-H RecordSyntax-opac */
+
+#ifndef z_opac_H
+#define z_opac_H
+
+#include <yaz/odr.h>
+#include <yaz/z-core.h>
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef struct Z_OPACRecord Z_OPACRecord;
+YAZ_EXPORT int z_OPACRecord (ODR o, Z_OPACRecord **p, int opt, const char *name);
+
+typedef struct Z_HoldingsRecord Z_HoldingsRecord;
+YAZ_EXPORT int z_HoldingsRecord (ODR o, Z_HoldingsRecord **p, int opt, const char *name);
+
+typedef struct Z_HoldingsAndCircData Z_HoldingsAndCircData;
+YAZ_EXPORT int z_HoldingsAndCircData (ODR o, Z_HoldingsAndCircData **p, int opt, const char *name);
+
+typedef struct Z_Volume Z_Volume;
+YAZ_EXPORT int z_Volume (ODR o, Z_Volume **p, int opt, const char *name);
+
+typedef struct Z_CircRecord Z_CircRecord;
+YAZ_EXPORT int z_CircRecord (ODR o, Z_CircRecord **p, int opt, const char *name);
+#ifdef __cplusplus
+}
+#endif
+#ifdef __cplusplus
+extern "C" {
+#endif
+struct Z_OPACRecord {
+	Z_External *bibliographicRecord; /* OPT */
+	int num_holdingsData;
+	Z_HoldingsRecord **holdingsData; /* OPT */
+};
+
+struct Z_HoldingsRecord {
+	int which;
+	union {
+		Z_External *marcHoldingsRecord;
+		Z_HoldingsAndCircData *holdingsAndCirc;
+#define Z_HoldingsRecord_marcHoldingsRecord 1
+#define Z_HoldingsRecord_holdingsAndCirc 2
+	} u;
+};
+
+struct Z_HoldingsAndCircData {
+	Z_InternationalString *typeOfRecord; /* OPT */
+	Z_InternationalString *encodingLevel; /* OPT */
+	Z_InternationalString *format; /* OPT */
+	Z_InternationalString *receiptAcqStatus; /* OPT */
+	Z_InternationalString *generalRetention; /* OPT */
+	Z_InternationalString *completeness; /* OPT */
+	Z_InternationalString *dateOfReport; /* OPT */
+	Z_InternationalString *nucCode; /* OPT */
+	Z_InternationalString *localLocation; /* OPT */
+	Z_InternationalString *shelvingLocation; /* OPT */
+	Z_InternationalString *callNumber; /* OPT */
+	Z_InternationalString *shelvingData; /* OPT */
+	Z_InternationalString *copyNumber; /* OPT */
+	Z_InternationalString *publicNote; /* OPT */
+	Z_InternationalString *reproductionNote; /* OPT */
+	Z_InternationalString *termsUseRepro; /* OPT */
+	Z_InternationalString *enumAndChron; /* OPT */
+	int num_volumes;
+	Z_Volume **volumes; /* OPT */
+	int num_circulationData;
+	Z_CircRecord **circulationData; /* OPT */
+};
+
+struct Z_Volume {
+	Z_InternationalString *enumeration; /* OPT */
+	Z_InternationalString *chronology; /* OPT */
+	Z_InternationalString *enumAndChron; /* OPT */
+};
+
+struct Z_CircRecord {
+	bool_t *availableNow;
+	Z_InternationalString *availablityDate; /* OPT */
+	Z_InternationalString *availableThru; /* OPT */
+	Z_InternationalString *restrictions; /* OPT */
+	Z_InternationalString *itemId; /* OPT */
+	bool_t *renewable;
+	bool_t *onHold;
+	Z_InternationalString *enumAndChron; /* OPT */
+	Z_InternationalString *midspine; /* OPT */
+	Z_InternationalString *temporaryLocation; /* OPT */
+};
+
+#ifdef __cplusplus
+}
+#endif
+#endif
Index: /main/tags/2.25/gsdl/packages/yaz/include/yaz/z-proto.h
===================================================================
--- /main/tags/2.25/gsdl/packages/yaz/include/yaz/z-proto.h	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/yaz/include/yaz/z-proto.h	(revision 21064)
@@ -0,0 +1,126 @@
+/*
+ * Copyright (c) 1998-2000, Index Data
+ * See the file LICENSE for details.
+ * Sebastian Hammer, Adam Dickmeiss
+ *
+ * $Log$
+ * Revision 1.1  2000/08/03 03:11:01  johnmcp
+ * Added the YAZ toolkit source to the packages directory (for z39.50 stuff)
+ *
+ * Revision 1.3  2000/02/28 11:20:06  adam
+ * Using autoconf. New definitions: YAZ_BEGIN_CDECL/YAZ_END_CDECL.
+ *
+ * Revision 1.2  1999/12/16 23:36:19  adam
+ * Implemented ILL protocol. Minor updates ASN.1 compiler.
+ *
+ * Revision 1.1  1999/11/30 13:47:11  adam
+ * Improved installation. Moved header files to include/yaz.
+ *
+ * Revision 1.2  1999/06/09 10:52:11  adam
+ * Added YAZ_EXPORT.
+ *
+ * Revision 1.1  1999/06/08 13:11:55  adam
+ * Fixed problem with proto.h.
+ *
+ * Revision 1.2  1999/04/20 10:37:04  adam
+ * Updated for ODR - added name parameter.
+ *
+ * Revision 1.1  1998/03/31 16:04:05  adam
+ * First version of proto.h which is almost compatible with the old one.
+ *
+ */
+#ifndef Z_PROTO_H
+#define Z_PROTO_H
+
+#define Z_95 1
+#define ASN_COMPILED 1
+
+#include <yaz/yaz-version.h>
+#include <yaz/z-accdes1.h>
+#include <yaz/z-accform1.h>
+#include <yaz/z-acckrb1.h>
+#include <yaz/z-core.h>
+#include <yaz/z-diag1.h>
+#include <yaz/z-espec1.h>
+#include <yaz/z-estask.h>
+#include <yaz/z-exp.h>
+#include <yaz/z-grs.h>
+#include <yaz/z-opac.h>
+#include <yaz/z-rrf1.h>
+#include <yaz/z-rrf2.h>
+#include <yaz/z-sum.h>
+#include <yaz/z-sutrs.h>
+#include <yaz/z-uifr1.h>
+#include <yaz/zes-expi.h>
+#include <yaz/zes-exps.h>
+#include <yaz/zes-order.h>
+#include <yaz/zes-pquery.h>
+#include <yaz/zes-psched.h>
+#include <yaz/zes-pset.h>
+#include <yaz/zes-update.h>
+#include <yaz/z-date.h>
+#include <yaz/z-univ.h>
+
+YAZ_BEGIN_CDECL
+
+#define Z_PRES_SUCCESS   Z_PresentStatus_success
+#define Z_PRES_PARTIAL_1 Z_PresentStatus_partial_1
+#define Z_PRES_PARTIAL_2 Z_PresentStatus_partial_2
+#define Z_PRES_PARTIAL_3 Z_PresentStatus_partial_3
+#define Z_PRES_PARTIAL_4 Z_PresentStatus_partial_4
+#define Z_PRES_FAILURE   Z_PresentStatus_failure
+
+#define Z_RES_SUBSET  Z_SearchResponse_subset
+#define Z_RES_INTERIM Z_SearchResponse_interim
+#define Z_RES_NONE    Z_SearchResponse_none
+
+#define Z_SortStatus_success Z_SortResponse_success 
+#define Z_SortStatus_partial_1 Z_SortResponse_partial_1
+#define Z_SortStatus_failure Z_SortResponse_failure
+
+#define Z_SortRelation_ascending            Z_SortKeySpec_ascending 
+#define Z_SortRelation_descending           Z_SortKeySpec_descending
+#define Z_SortRelation_ascendingByFreq      Z_SortKeySpec_ascendingByFrequency
+#define Z_SortRelation_descendingByFreq     Z_SortKeySpec_descendingByfrequency 
+
+#define Z_SortCase_caseSensitive            Z_SortKeySpec_caseSensitive
+#define Z_SortCase_caseInsensitive          Z_SortKeySpec_descendingByfrequency
+
+#define Z_TriggerResourceCtrl_resourceReport Z_TriggerResourceControlRequest_resourceReport
+#define Z_TriggerResourceCtrl_resourceControl  Z_TriggerResourceControlRequest_resourceControl
+#define Z_TriggerResourceCtrl_cancel Z_TriggerResourceControlRequest_cancel
+
+#define Z_DeleteRequest_list    Z_DeleteResultSetRequest_list
+#define Z_DeleteRequest_all     Z_DeleteResultSetRequest_all
+
+#define Z_AccessRequest_simpleForm Z_AccessControlRequest_simpleForm
+#define Z_AccessRequest_externallyDefined Z_AccessControlRequest_externallyDefined
+
+#define Z_AccessResponse_simpleForm Z_AccessControlResponse_simpleForm
+#define Z_AccessResponse_externallyDefined Z_AccessControlResponse_externallyDefined
+
+#define Z_ResourceReportStatus_success   Z_ResourceReportResponse_success
+#define Z_ResourceReportStatus_partial   Z_ResourceReportResponse_partial
+#define Z_ResourceReportStatus_failure_1 Z_ResourceReportResponse_failure_1
+#define Z_ResourceReportStatus_failure_2 Z_ResourceReportResponse_failure_2
+#define Z_ResourceReportStatus_failure_3 Z_ResourceReportResponse_failure_3
+#define Z_ResourceReportStatus_failure_4 Z_ResourceReportResponse_failure_4
+#define Z_ResourceReportStatus_failure_5 Z_ResourceReportResponse_failure_5
+#define Z_ResourceReportStatus_failure_6 Z_ResourceReportResponse_failure_6
+
+#define Z_SortResultSetStatus_empty       Z_SortResponse_empty
+#define Z_SortResultSetStatus_interim     Z_SortResponse_interim
+#define Z_SortResultSetStatus_unchanged   Z_SortResponse_unchanged
+#define Z_SortResultSetStatus_none        Z_SortResponse_none
+
+typedef Z_External Z_DatabaseRecord;
+typedef struct Z_IOItemOrder Z_ItemOrder;
+
+YAZ_EXPORT Z_APDU *zget_APDU(ODR o, int which);
+YAZ_EXPORT Z_Close *zget_Close (ODR o);
+
+YAZ_END_CDECL
+
+#include <yaz/prt-ext.h>
+
+#endif
Index: /main/tags/2.25/gsdl/packages/yaz/include/yaz/z-rrf1.h
===================================================================
--- /main/tags/2.25/gsdl/packages/yaz/include/yaz/z-rrf1.h	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/yaz/include/yaz/z-rrf1.h	(revision 21064)
@@ -0,0 +1,59 @@
+/* Generated automatically by the YAZ ASN.1 Compiler 0.3 */
+/* Module-H ResourceReport-Format-Resource-1 */
+
+#ifndef z_rrf1_H
+#define z_rrf1_H
+
+#include <yaz/odr.h>
+#include <yaz/z-core.h>
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef struct Z_ResourceReport1 Z_ResourceReport1;
+YAZ_EXPORT int z_ResourceReport1 (ODR o, Z_ResourceReport1 **p, int opt, const char *name);
+
+typedef struct Z_Estimate1 Z_Estimate1;
+YAZ_EXPORT int z_Estimate1 (ODR o, Z_Estimate1 **p, int opt, const char *name);
+
+typedef int  Z_EstimateType;
+YAZ_EXPORT int z_EstimateType (ODR o, Z_EstimateType **p, int opt, const char *name);
+#ifdef __cplusplus
+}
+#endif
+#ifdef __cplusplus
+extern "C" {
+#endif
+struct Z_ResourceReport1 {
+	int num_estimates;
+	Z_Estimate1 **estimates;
+	Z_InternationalString *message;
+};
+
+struct Z_Estimate1 {
+	Z_EstimateType *type;
+	int *value;
+	int *currency_code; /* OPT */
+};
+
+#define Z_EstimateType_currentSearchRecords 1
+#define Z_EstimateType_finalSearchRecords 2
+#define Z_EstimateType_currentPresentRecords 3
+#define Z_EstimateType_finalPresentRecords 4
+#define Z_EstimateType_currentOpTimeProcessing 5
+#define Z_EstimateType_finalOpTimeProcessing 6
+#define Z_EstimateType_currentAssocTime 7
+#define Z_EstimateType_currentOperationCost 8
+#define Z_EstimateType_finalOperationCost 9
+#define Z_EstimateType_currentAssocCost 10
+#define Z_EstimateType_finalOpTimeElapsed 11
+#define Z_EstimateType_percentComplete 12
+#define Z_EstimateType_currentSearchAssocCost 13
+#define Z_EstimateType_currentPresentAssocCost 14
+#define Z_EstimateType_currentConnectAssocCost 15
+#define Z_EstimateType_currentOtherAssocCost 16
+
+#ifdef __cplusplus
+}
+#endif
+#endif
Index: /main/tags/2.25/gsdl/packages/yaz/include/yaz/z-rrf2.h
===================================================================
--- /main/tags/2.25/gsdl/packages/yaz/include/yaz/z-rrf2.h	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/yaz/include/yaz/z-rrf2.h	(revision 21064)
@@ -0,0 +1,38 @@
+/* Generated automatically by the YAZ ASN.1 Compiler 0.3 */
+/* Module-H ResourceReport-Format-Resource-2 */
+
+#ifndef z_rrf2_H
+#define z_rrf2_H
+
+#include <yaz/odr.h>
+#include <yaz/z-core.h>
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef struct Z_ResourceReport2 Z_ResourceReport2;
+YAZ_EXPORT int z_ResourceReport2 (ODR o, Z_ResourceReport2 **p, int opt, const char *name);
+
+typedef struct Z_Estimate2 Z_Estimate2;
+YAZ_EXPORT int z_Estimate2 (ODR o, Z_Estimate2 **p, int opt, const char *name);
+#ifdef __cplusplus
+}
+#endif
+#ifdef __cplusplus
+extern "C" {
+#endif
+struct Z_ResourceReport2 {
+	int num_estimates;
+	Z_Estimate2 **estimates; /* OPT */
+	Z_InternationalString *message; /* OPT */
+};
+
+struct Z_Estimate2 {
+	Z_StringOrNumeric *type;
+	Z_IntUnit *value;
+};
+
+#ifdef __cplusplus
+}
+#endif
+#endif
Index: /main/tags/2.25/gsdl/packages/yaz/include/yaz/z-sum.h
===================================================================
--- /main/tags/2.25/gsdl/packages/yaz/include/yaz/z-sum.h	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/yaz/include/yaz/z-sum.h	(revision 21064)
@@ -0,0 +1,51 @@
+/* Generated automatically by the YAZ ASN.1 Compiler 0.3 */
+/* Module-H RecordSyntax-summary */
+
+#ifndef z_sum_H
+#define z_sum_H
+
+#include <yaz/odr.h>
+#include <yaz/z-core.h>
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef struct Z_BriefBib Z_BriefBib;
+YAZ_EXPORT int z_BriefBib (ODR o, Z_BriefBib **p, int opt, const char *name);
+
+typedef struct Z_FormatSpec Z_FormatSpec;
+YAZ_EXPORT int z_FormatSpec (ODR o, Z_FormatSpec **p, int opt, const char *name);
+#ifdef __cplusplus
+}
+#endif
+#ifdef __cplusplus
+extern "C" {
+#endif
+struct Z_BriefBib {
+	Z_InternationalString *title;
+	Z_InternationalString *author; /* OPT */
+	Z_InternationalString *callNumber; /* OPT */
+	Z_InternationalString *recordType; /* OPT */
+	Z_InternationalString *bibliographicLevel; /* OPT */
+	int num_format;
+	Z_FormatSpec **format; /* OPT */
+	Z_InternationalString *publicationPlace; /* OPT */
+	Z_InternationalString *publicationDate; /* OPT */
+	Z_InternationalString *targetSystemKey; /* OPT */
+	Z_InternationalString *satisfyingElement; /* OPT */
+	int *rank; /* OPT */
+	Z_InternationalString *documentId; /* OPT */
+	Z_InternationalString *abstract; /* OPT */
+	Z_OtherInformation *otherInfo; /* OPT */
+};
+
+struct Z_FormatSpec {
+	Z_InternationalString *type;
+	int *size; /* OPT */
+	int *bestPosn; /* OPT */
+};
+
+#ifdef __cplusplus
+}
+#endif
+#endif
Index: /main/tags/2.25/gsdl/packages/yaz/include/yaz/z-sutrs.h
===================================================================
--- /main/tags/2.25/gsdl/packages/yaz/include/yaz/z-sutrs.h	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/yaz/include/yaz/z-sutrs.h	(revision 21064)
@@ -0,0 +1,36 @@
+/* Generated automatically by the YAZ ASN.1 Compiler 0.3 */
+/* Module-H RecordSyntax-SUTRS */
+
+#ifndef z_sutrs_H
+#define z_sutrs_H
+
+#include <yaz/odr.h>
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef Odr_oct Z_SUTRS;
+YAZ_EXPORT int z_SUTRS (ODR o, Odr_oct **p, int opt);
+
+#ifdef __cplusplus
+}
+#endif
+#include <yaz/z-core.h>
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef Z_InternationalString  Z_SutrsRecord;
+YAZ_EXPORT int z_SutrsRecord (ODR o, Z_SutrsRecord **p, int opt, const char *name);
+#ifdef __cplusplus
+}
+#endif
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+
+#ifdef __cplusplus
+}
+#endif
+#endif
Index: /main/tags/2.25/gsdl/packages/yaz/include/yaz/z-uifr1.h
===================================================================
--- /main/tags/2.25/gsdl/packages/yaz/include/yaz/z-uifr1.h	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/yaz/include/yaz/z-uifr1.h	(revision 21064)
@@ -0,0 +1,95 @@
+/* Generated automatically by the YAZ ASN.1 Compiler 0.3 */
+/* Module-H UserInfoFormat-searchResult-1 */
+
+#ifndef z_uifr1_H
+#define z_uifr1_H
+
+#include <yaz/odr.h>
+#include <yaz/z-core.h>
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef struct Z_SearchInfoReport_s Z_SearchInfoReport_s;
+YAZ_EXPORT int z_SearchInfoReport_s (ODR o, Z_SearchInfoReport_s **p, int opt, const char *name);
+
+typedef struct Z_SearchInfoReport Z_SearchInfoReport;
+YAZ_EXPORT int z_SearchInfoReport (ODR o, Z_SearchInfoReport **p, int opt, const char *name);
+
+typedef struct Z_ResultsByDB_sList Z_ResultsByDB_sList;
+YAZ_EXPORT int z_ResultsByDB_sList (ODR o, Z_ResultsByDB_sList **p, int opt, const char *name);
+
+typedef struct Z_ResultsByDB_s Z_ResultsByDB_s;
+YAZ_EXPORT int z_ResultsByDB_s (ODR o, Z_ResultsByDB_s **p, int opt, const char *name);
+
+typedef struct Z_ResultsByDB Z_ResultsByDB;
+YAZ_EXPORT int z_ResultsByDB (ODR o, Z_ResultsByDB **p, int opt, const char *name);
+
+typedef struct Z_QueryExpressionTerm Z_QueryExpressionTerm;
+YAZ_EXPORT int z_QueryExpressionTerm (ODR o, Z_QueryExpressionTerm **p, int opt, const char *name);
+
+typedef struct Z_QueryExpression Z_QueryExpression;
+YAZ_EXPORT int z_QueryExpression (ODR o, Z_QueryExpression **p, int opt, const char *name);
+#ifdef __cplusplus
+}
+#endif
+#ifdef __cplusplus
+extern "C" {
+#endif
+struct Z_SearchInfoReport_s {
+	Z_InternationalString *subqueryId; /* OPT */
+	bool_t *fullQuery;
+	Z_QueryExpression *subqueryExpression; /* OPT */
+	Z_QueryExpression *subqueryInterpretation; /* OPT */
+	Z_QueryExpression *subqueryRecommendation; /* OPT */
+	int *subqueryCount; /* OPT */
+	Z_IntUnit *subqueryWeight; /* OPT */
+	Z_ResultsByDB *resultsByDB; /* OPT */
+};
+
+struct Z_SearchInfoReport {
+	int num;
+	Z_SearchInfoReport_s **elements;
+};
+
+struct Z_ResultsByDB_sList {
+	int num;
+	Z_DatabaseName **elements;
+};
+
+struct Z_ResultsByDB_s {
+	int which;
+	union {
+		Odr_null *all;
+		Z_ResultsByDB_sList *list;
+#define Z_ResultsByDB_s_all 1
+#define Z_ResultsByDB_s_list 2
+	} u;
+	int *count; /* OPT */
+	Z_InternationalString *resultSetName; /* OPT */
+};
+
+struct Z_ResultsByDB {
+	int num;
+	Z_ResultsByDB_s **elements;
+};
+
+struct Z_QueryExpressionTerm {
+	Z_Term *queryTerm;
+	Z_InternationalString *termComment; /* OPT */
+};
+
+struct Z_QueryExpression {
+	int which;
+	union {
+		Z_QueryExpressionTerm *term;
+		Z_Query *query;
+#define Z_QueryExpression_term 1
+#define Z_QueryExpression_query 2
+	} u;
+};
+
+#ifdef __cplusplus
+}
+#endif
+#endif
Index: /main/tags/2.25/gsdl/packages/yaz/include/yaz/z-univ.h
===================================================================
--- /main/tags/2.25/gsdl/packages/yaz/include/yaz/z-univ.h	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/yaz/include/yaz/z-univ.h	(revision 21064)
@@ -0,0 +1,50 @@
+/* Generated automatically by the YAZ ASN.1 Compiler 0.3 */
+/* Module-H ResourceReport-Format-Universe-1 */
+
+#ifndef z_univ_H
+#define z_univ_H
+
+#include <yaz/odr.h>
+#include <yaz/z-core.h>
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef struct Z_UniverseReportHits Z_UniverseReportHits;
+YAZ_EXPORT int z_UniverseReportHits (ODR o, Z_UniverseReportHits **p, int opt, const char *name);
+
+typedef struct Z_UniverseReportDuplicate Z_UniverseReportDuplicate;
+YAZ_EXPORT int z_UniverseReportDuplicate (ODR o, Z_UniverseReportDuplicate **p, int opt, const char *name);
+
+typedef struct Z_UniverseReport Z_UniverseReport;
+YAZ_EXPORT int z_UniverseReport (ODR o, Z_UniverseReport **p, int opt, const char *name);
+#ifdef __cplusplus
+}
+#endif
+#ifdef __cplusplus
+extern "C" {
+#endif
+struct Z_UniverseReportHits {
+	Z_StringOrNumeric *database;
+	Z_StringOrNumeric *hits;
+};
+
+struct Z_UniverseReportDuplicate {
+	Z_StringOrNumeric *hitno;
+};
+
+struct Z_UniverseReport {
+	int *totalHits;
+	int which;
+	union {
+		Z_UniverseReportHits *databaseHits;
+		Z_UniverseReportDuplicate *duplicate;
+#define Z_UniverseReport_databaseHits 1
+#define Z_UniverseReport_duplicate 2
+	} u;
+};
+
+#ifdef __cplusplus
+}
+#endif
+#endif
Index: /main/tags/2.25/gsdl/packages/yaz/include/yaz/zes-expi.h
===================================================================
--- /main/tags/2.25/gsdl/packages/yaz/include/yaz/zes-expi.h	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/yaz/include/yaz/zes-expi.h	(revision 21064)
@@ -0,0 +1,105 @@
+/* Generated automatically by the YAZ ASN.1 Compiler 0.3 */
+/* Module-H ESFormat-ExportInvocation */
+
+#ifndef zes_expi_H
+#define zes_expi_H
+
+#include <yaz/odr.h>
+#include <yaz/z-core.h>
+#include <yaz/zes-exps.h>
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef struct Z_EIExportInvocationEsRequest Z_EIExportInvocationEsRequest;
+YAZ_EXPORT int z_EIExportInvocationEsRequest (ODR o, Z_EIExportInvocationEsRequest **p, int opt, const char *name);
+
+typedef struct Z_EIExportInvocationTaskPackage Z_EIExportInvocationTaskPackage;
+YAZ_EXPORT int z_EIExportInvocationTaskPackage (ODR o, Z_EIExportInvocationTaskPackage **p, int opt, const char *name);
+
+typedef struct Z_EIExportInvocation Z_EIExportInvocation;
+YAZ_EXPORT int z_EIExportInvocation (ODR o, Z_EIExportInvocation **p, int opt, const char *name);
+
+typedef struct Z_EIOriginPartToKeep Z_EIOriginPartToKeep;
+YAZ_EXPORT int z_EIOriginPartToKeep (ODR o, Z_EIOriginPartToKeep **p, int opt, const char *name);
+
+typedef struct Z_EIOriginPartNotToKeepRanges_s Z_EIOriginPartNotToKeepRanges_s;
+YAZ_EXPORT int z_EIOriginPartNotToKeepRanges_s (ODR o, Z_EIOriginPartNotToKeepRanges_s **p, int opt, const char *name);
+
+typedef struct Z_EIOriginPartNotToKeepRanges Z_EIOriginPartNotToKeepRanges;
+YAZ_EXPORT int z_EIOriginPartNotToKeepRanges (ODR o, Z_EIOriginPartNotToKeepRanges **p, int opt, const char *name);
+
+typedef struct Z_EIOriginPartNotToKeep Z_EIOriginPartNotToKeep;
+YAZ_EXPORT int z_EIOriginPartNotToKeep (ODR o, Z_EIOriginPartNotToKeep **p, int opt, const char *name);
+
+typedef struct Z_EITargetPart Z_EITargetPart;
+YAZ_EXPORT int z_EITargetPart (ODR o, Z_EITargetPart **p, int opt, const char *name);
+#ifdef __cplusplus
+}
+#endif
+#ifdef __cplusplus
+extern "C" {
+#endif
+struct Z_EIExportInvocationEsRequest {
+	Z_EIOriginPartToKeep *toKeep;
+	Z_EIOriginPartNotToKeep *notToKeep;
+};
+
+struct Z_EIExportInvocationTaskPackage {
+	Z_EIOriginPartToKeep *originPart;
+	Z_EITargetPart *targetPart; /* OPT */
+};
+
+struct Z_EIExportInvocation {
+	int which;
+	union {
+		Z_EIExportInvocationEsRequest *esRequest;
+		Z_EIExportInvocationTaskPackage *taskPackage;
+#define Z_EIExportInvocation_esRequest 1
+#define Z_EIExportInvocation_taskPackage 2
+	} u;
+};
+
+struct Z_EIOriginPartToKeep {
+	int which;
+	union {
+		Z_InternationalString *packageName;
+		Z_ESExportSpecification *packageSpec;
+#define Z_EIOriginPartToKeep_packageName 1
+#define Z_EIOriginPartToKeep_packageSpec 2
+	} u;
+	int *numberOfCopies;
+};
+
+struct Z_EIOriginPartNotToKeepRanges_s {
+	int *start;
+	int *count; /* OPT */
+};
+
+struct Z_EIOriginPartNotToKeepRanges {
+	int num;
+	Z_EIOriginPartNotToKeepRanges_s **elements;
+};
+
+struct Z_EIOriginPartNotToKeep {
+	Z_InternationalString *resultSetId;
+	int which;
+	union {
+		Odr_null *all;
+		Z_EIOriginPartNotToKeepRanges *ranges;
+#define Z_EIOriginPartNotToKeep_all 1
+#define Z_EIOriginPartNotToKeep_ranges 2
+	} u;
+};
+
+struct Z_EITargetPart {
+	Z_IntUnit *estimatedQuantity; /* OPT */
+	Z_IntUnit *quantitySoFar; /* OPT */
+	Z_IntUnit *estimatedCost; /* OPT */
+	Z_IntUnit *costSoFar; /* OPT */
+};
+
+#ifdef __cplusplus
+}
+#endif
+#endif
Index: /main/tags/2.25/gsdl/packages/yaz/include/yaz/zes-exps.h
===================================================================
--- /main/tags/2.25/gsdl/packages/yaz/include/yaz/zes-exps.h	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/yaz/include/yaz/zes-exps.h	(revision 21064)
@@ -0,0 +1,93 @@
+/* Generated automatically by the YAZ ASN.1 Compiler 0.3 */
+/* Module-H ESFormat-ExportSpecification */
+
+#ifndef zes_exps_H
+#define zes_exps_H
+
+#include <yaz/odr.h>
+#include <yaz/z-core.h>
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef struct Z_ESExportSpecificationEsRequest Z_ESExportSpecificationEsRequest;
+YAZ_EXPORT int z_ESExportSpecificationEsRequest (ODR o, Z_ESExportSpecificationEsRequest **p, int opt, const char *name);
+
+typedef struct Z_ESExportSpecificationTaskPackage Z_ESExportSpecificationTaskPackage;
+YAZ_EXPORT int z_ESExportSpecificationTaskPackage (ODR o, Z_ESExportSpecificationTaskPackage **p, int opt, const char *name);
+
+typedef struct Z_ESExportSpecification Z_ESExportSpecification;
+YAZ_EXPORT int z_ESExportSpecification (ODR o, Z_ESExportSpecification **p, int opt, const char *name);
+
+typedef struct Z_ESOriginPartToKeep Z_ESOriginPartToKeep;
+YAZ_EXPORT int z_ESOriginPartToKeep (ODR o, Z_ESOriginPartToKeep **p, int opt, const char *name);
+
+typedef struct Z_ESDestinationOther Z_ESDestinationOther;
+YAZ_EXPORT int z_ESDestinationOther (ODR o, Z_ESDestinationOther **p, int opt, const char *name);
+
+typedef struct Z_ESDestination Z_ESDestination;
+YAZ_EXPORT int z_ESDestination (ODR o, Z_ESDestination **p, int opt, const char *name);
+#ifdef __cplusplus
+}
+#endif
+#ifdef __cplusplus
+extern "C" {
+#endif
+struct Z_ESExportSpecificationEsRequest {
+	Z_ESOriginPartToKeep *toKeep;
+	Odr_null *notToKeep;
+};
+
+struct Z_ESExportSpecificationTaskPackage {
+	Z_ESOriginPartToKeep *originPart;
+	Odr_null *targetPart;
+};
+
+struct Z_ESExportSpecification {
+	int which;
+	union {
+		Z_ESExportSpecificationEsRequest *esRequest;
+		Z_ESExportSpecificationTaskPackage *taskPackage;
+#define Z_ESExportSpecification_esRequest 1
+#define Z_ESExportSpecification_taskPackage 2
+	} u;
+};
+
+struct Z_ESOriginPartToKeep {
+	Z_CompSpec *composition;
+	Z_ESDestination *exportDestination;
+};
+
+struct Z_ESDestinationOther {
+	Z_InternationalString *vehicle; /* OPT */
+	Z_InternationalString *destination;
+};
+
+struct Z_ESDestination {
+	int which;
+	union {
+		Z_InternationalString *phoneNumber;
+		Z_InternationalString *faxNumber;
+		Z_InternationalString *x400address;
+		Z_InternationalString *emailAddress;
+		Z_InternationalString *pagerNumber;
+		Z_InternationalString *ftpAddress;
+		Z_InternationalString *ftamAddress;
+		Z_InternationalString *printerAddress;
+		Z_ESDestinationOther *other;
+#define Z_ESDestination_phoneNumber 1
+#define Z_ESDestination_faxNumber 2
+#define Z_ESDestination_x400address 3
+#define Z_ESDestination_emailAddress 4
+#define Z_ESDestination_pagerNumber 5
+#define Z_ESDestination_ftpAddress 6
+#define Z_ESDestination_ftamAddress 7
+#define Z_ESDestination_printerAddress 8
+#define Z_ESDestination_other 9
+	} u;
+};
+
+#ifdef __cplusplus
+}
+#endif
+#endif
Index: /main/tags/2.25/gsdl/packages/yaz/include/yaz/zes-order.h
===================================================================
--- /main/tags/2.25/gsdl/packages/yaz/include/yaz/zes-order.h	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/yaz/include/yaz/zes-order.h	(revision 21064)
@@ -0,0 +1,132 @@
+/* Generated automatically by the YAZ ASN.1 Compiler 0.3 */
+/* Module-H ESFormat-ItemOrder */
+
+#ifndef zes_order_H
+#define zes_order_H
+
+#include <yaz/odr.h>
+#include <yaz/z-core.h>
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef struct Z_IORequest Z_IORequest;
+YAZ_EXPORT int z_IORequest (ODR o, Z_IORequest **p, int opt, const char *name);
+
+typedef struct Z_IOTaskPackage Z_IOTaskPackage;
+YAZ_EXPORT int z_IOTaskPackage (ODR o, Z_IOTaskPackage **p, int opt, const char *name);
+
+typedef struct Z_IOItemOrder Z_IOItemOrder;
+YAZ_EXPORT int z_IOItemOrder (ODR o, Z_IOItemOrder **p, int opt, const char *name);
+
+typedef struct Z_IOContact Z_IOContact;
+YAZ_EXPORT int z_IOContact (ODR o, Z_IOContact **p, int opt, const char *name);
+
+typedef struct Z_IOBilling Z_IOBilling;
+YAZ_EXPORT int z_IOBilling (ODR o, Z_IOBilling **p, int opt, const char *name);
+
+typedef struct Z_IOOriginPartToKeep Z_IOOriginPartToKeep;
+YAZ_EXPORT int z_IOOriginPartToKeep (ODR o, Z_IOOriginPartToKeep **p, int opt, const char *name);
+
+typedef struct Z_IOCreditCardInfo Z_IOCreditCardInfo;
+YAZ_EXPORT int z_IOCreditCardInfo (ODR o, Z_IOCreditCardInfo **p, int opt, const char *name);
+
+typedef struct Z_IOResultSetItem Z_IOResultSetItem;
+YAZ_EXPORT int z_IOResultSetItem (ODR o, Z_IOResultSetItem **p, int opt, const char *name);
+
+typedef struct Z_IOOriginPartNotToKeep Z_IOOriginPartNotToKeep;
+YAZ_EXPORT int z_IOOriginPartNotToKeep (ODR o, Z_IOOriginPartNotToKeep **p, int opt, const char *name);
+
+typedef struct Z_IOTargetPart Z_IOTargetPart;
+YAZ_EXPORT int z_IOTargetPart (ODR o, Z_IOTargetPart **p, int opt, const char *name);
+#ifdef __cplusplus
+}
+#endif
+#ifdef __cplusplus
+extern "C" {
+#endif
+struct Z_IORequest {
+	Z_IOOriginPartToKeep *toKeep; /* OPT */
+	Z_IOOriginPartNotToKeep *notToKeep;
+};
+
+struct Z_IOTaskPackage {
+	Z_IOOriginPartToKeep *originPart; /* OPT */
+	Z_IOTargetPart *targetPart;
+};
+
+struct Z_IOItemOrder {
+	int which;
+	union {
+		Z_IORequest *esRequest;
+		Z_IOTaskPackage *taskPackage;
+#define Z_IOItemOrder_esRequest 1
+#define Z_IOItemOrder_taskPackage 2
+	} u;
+};
+
+struct Z_IOContact {
+	Z_InternationalString *name; /* OPT */
+	Z_InternationalString *phone; /* OPT */
+	Z_InternationalString *email; /* OPT */
+};
+
+struct Z_IOBilling {
+	int which;
+	union {
+		Odr_null *billInvoice;
+		Odr_null *prepay;
+		Odr_null *depositAccount;
+		Z_IOCreditCardInfo *creditCard;
+		Odr_null *cardInfoPreviouslySupplied;
+		Odr_null *privateKnown;
+		Z_External *privateNotKnown;
+#define Z_IOBilling_billInvoice 1
+#define Z_IOBilling_prepay 2
+#define Z_IOBilling_depositAccount 3
+#define Z_IOBilling_creditCard 4
+#define Z_IOBilling_cardInfoPreviouslySupplied 5
+#define Z_IOBilling_privateKnown 6
+#define Z_IOBilling_privateNotKnown 7
+	} u;
+	Z_InternationalString *customerReference; /* OPT */
+	Z_InternationalString *customerPONumber; /* OPT */
+};
+
+struct Z_IOOriginPartToKeep {
+	Z_External *supplDescription; /* OPT */
+	Z_IOContact *contact; /* OPT */
+	Z_IOBilling *addlBilling; /* OPT */
+};
+
+struct Z_IOCreditCardInfo {
+	Z_InternationalString *nameOnCard;
+	Z_InternationalString *expirationDate;
+	Z_InternationalString *cardNumber;
+};
+
+struct Z_IOResultSetItem {
+	Z_InternationalString *resultSetId;
+	int *item;
+};
+
+struct Z_IOOriginPartNotToKeep {
+	Z_IOResultSetItem *resultSetItem; /* OPT */
+	Z_External *itemRequest; /* OPT */
+};
+
+struct Z_IOTargetPart {
+	Z_External *itemRequest; /* OPT */
+	Z_External *statusOrErrorReport; /* OPT */
+#define Z_IOTargetPart_notReceived 1
+#define Z_IOTargetPart_loanQueue 2
+#define Z_IOTargetPart_forwarded 3
+#define Z_IOTargetPart_unfilledCopyright 4
+#define Z_IOTargetPart_filledCopyright 5
+	int *auxiliaryStatus; /* OPT */
+};
+
+#ifdef __cplusplus
+}
+#endif
+#endif
Index: /main/tags/2.25/gsdl/packages/yaz/include/yaz/zes-pquery.h
===================================================================
--- /main/tags/2.25/gsdl/packages/yaz/include/yaz/zes-pquery.h	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/yaz/include/yaz/zes-pquery.h	(revision 21064)
@@ -0,0 +1,77 @@
+/* Generated automatically by the YAZ ASN.1 Compiler 0.3 */
+/* Module-H ESFormat-PersistentQuery */
+
+#ifndef zes_pquery_H
+#define zes_pquery_H
+
+#include <yaz/odr.h>
+#include <yaz/z-core.h>
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef struct Z_PQueryPersistentQueryEsRequest Z_PQueryPersistentQueryEsRequest;
+YAZ_EXPORT int z_PQueryPersistentQueryEsRequest (ODR o, Z_PQueryPersistentQueryEsRequest **p, int opt, const char *name);
+
+typedef struct Z_PQueryPersistentQueryTaskPackage Z_PQueryPersistentQueryTaskPackage;
+YAZ_EXPORT int z_PQueryPersistentQueryTaskPackage (ODR o, Z_PQueryPersistentQueryTaskPackage **p, int opt, const char *name);
+
+typedef struct Z_PQueryPersistentQuery Z_PQueryPersistentQuery;
+YAZ_EXPORT int z_PQueryPersistentQuery (ODR o, Z_PQueryPersistentQuery **p, int opt, const char *name);
+
+typedef struct Z_PQueryOriginPartToKeep Z_PQueryOriginPartToKeep;
+YAZ_EXPORT int z_PQueryOriginPartToKeep (ODR o, Z_PQueryOriginPartToKeep **p, int opt, const char *name);
+
+typedef struct Z_PQueryOriginPartNotToKeep Z_PQueryOriginPartNotToKeep;
+YAZ_EXPORT int z_PQueryOriginPartNotToKeep (ODR o, Z_PQueryOriginPartNotToKeep **p, int opt, const char *name);
+
+typedef Z_Query  Z_PQueryTargetPart;
+YAZ_EXPORT int z_PQueryTargetPart (ODR o, Z_PQueryTargetPart **p, int opt, const char *name);
+#ifdef __cplusplus
+}
+#endif
+#ifdef __cplusplus
+extern "C" {
+#endif
+struct Z_PQueryPersistentQueryEsRequest {
+	Z_PQueryOriginPartToKeep *toKeep; /* OPT */
+	Z_PQueryOriginPartNotToKeep *notToKeep;
+};
+
+struct Z_PQueryPersistentQueryTaskPackage {
+	Z_PQueryOriginPartToKeep *originPart; /* OPT */
+	Z_PQueryTargetPart *targetPart;
+};
+
+struct Z_PQueryPersistentQuery {
+	int which;
+	union {
+		Z_PQueryPersistentQueryEsRequest *esRequest;
+		Z_PQueryPersistentQueryTaskPackage *taskPackage;
+#define Z_PQueryPersistentQuery_esRequest 1
+#define Z_PQueryPersistentQuery_taskPackage 2
+	} u;
+};
+
+struct Z_PQueryOriginPartToKeep {
+	int num_dbNames;
+	Z_InternationalString **dbNames; /* OPT */
+	Z_OtherInformation *additionalSearchInfo; /* OPT */
+};
+
+struct Z_PQueryOriginPartNotToKeep {
+	int which;
+	union {
+		Z_InternationalString *package;
+		Z_Query *query;
+#define Z_PQueryOriginPartNotToKeep_package 1
+#define Z_PQueryOriginPartNotToKeep_query 2
+	} u;
+};
+
+
+
+#ifdef __cplusplus
+}
+#endif
+#endif
Index: /main/tags/2.25/gsdl/packages/yaz/include/yaz/zes-psched.h
===================================================================
--- /main/tags/2.25/gsdl/packages/yaz/include/yaz/zes-psched.h	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/yaz/include/yaz/zes-psched.h	(revision 21064)
@@ -0,0 +1,118 @@
+/* Generated automatically by the YAZ ASN.1 Compiler 0.3 */
+/* Module-H ESFormat-PeriodicQuerySchedule */
+
+#ifndef zes_psched_H
+#define zes_psched_H
+
+#include <yaz/odr.h>
+#include <yaz/z-core.h>
+#include <yaz/zes-exps.h>
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef struct Z_PQSPeriodicQueryScheduleEsRequest Z_PQSPeriodicQueryScheduleEsRequest;
+YAZ_EXPORT int z_PQSPeriodicQueryScheduleEsRequest (ODR o, Z_PQSPeriodicQueryScheduleEsRequest **p, int opt, const char *name);
+
+typedef struct Z_PQSPeriodicQueryScheduleTaskPackage Z_PQSPeriodicQueryScheduleTaskPackage;
+YAZ_EXPORT int z_PQSPeriodicQueryScheduleTaskPackage (ODR o, Z_PQSPeriodicQueryScheduleTaskPackage **p, int opt, const char *name);
+
+typedef struct Z_PQSPeriodicQuerySchedule Z_PQSPeriodicQuerySchedule;
+YAZ_EXPORT int z_PQSPeriodicQuerySchedule (ODR o, Z_PQSPeriodicQuerySchedule **p, int opt, const char *name);
+
+typedef struct Z_PQSOriginPartToKeep Z_PQSOriginPartToKeep;
+YAZ_EXPORT int z_PQSOriginPartToKeep (ODR o, Z_PQSOriginPartToKeep **p, int opt, const char *name);
+
+typedef struct Z_PQSOriginPartNotToKeep Z_PQSOriginPartNotToKeep;
+YAZ_EXPORT int z_PQSOriginPartNotToKeep (ODR o, Z_PQSOriginPartNotToKeep **p, int opt, const char *name);
+
+typedef struct Z_PQSTargetPart Z_PQSTargetPart;
+YAZ_EXPORT int z_PQSTargetPart (ODR o, Z_PQSTargetPart **p, int opt, const char *name);
+
+typedef struct Z_PQSPeriod Z_PQSPeriod;
+YAZ_EXPORT int z_PQSPeriod (ODR o, Z_PQSPeriod **p, int opt, const char *name);
+#ifdef __cplusplus
+}
+#endif
+#ifdef __cplusplus
+extern "C" {
+#endif
+struct Z_PQSPeriodicQueryScheduleEsRequest {
+	Z_PQSOriginPartToKeep *toKeep;
+	Z_PQSOriginPartNotToKeep *notToKeep;
+};
+
+struct Z_PQSPeriodicQueryScheduleTaskPackage {
+	Z_PQSOriginPartToKeep *originPart;
+	Z_PQSTargetPart *targetPart;
+};
+
+struct Z_PQSPeriodicQuerySchedule {
+	int which;
+	union {
+		Z_PQSPeriodicQueryScheduleEsRequest *esRequest;
+		Z_PQSPeriodicQueryScheduleTaskPackage *taskPackage;
+#define Z_PQSPeriodicQuerySchedule_esRequest 1
+#define Z_PQSPeriodicQuerySchedule_taskPackage 2
+	} u;
+};
+
+struct Z_PQSOriginPartToKeep {
+	bool_t *activeFlag;
+	int num_databaseNames;
+	Z_InternationalString **databaseNames; /* OPT */
+#define Z_PQSOriginPartToKeep_replace 1
+#define Z_PQSOriginPartToKeep_append 2
+#define Z_PQSOriginPartToKeep_createNew 3
+	int *resultSetDisposition; /* OPT */
+	Z_ESDestination *alertDestination; /* OPT */
+	int which;
+	union {
+		Z_InternationalString *packageName;
+		Z_ESExportSpecification *exportPackage;
+#define Z_PQSOriginPartToKeep_packageName 1
+#define Z_PQSOriginPartToKeep_exportPackage 2
+	} u; /* OPT */
+};
+
+struct Z_PQSOriginPartNotToKeep {
+	int which;
+	union {
+		Z_Query *actualQuery;
+		Z_InternationalString *packageName;
+#define Z_PQSOriginPartNotToKeep_actualQuery 1
+#define Z_PQSOriginPartNotToKeep_packageName 2
+	} u; /* OPT */
+	Z_PQSPeriod *originSuggestedPeriod; /* OPT */
+	char *expiration; /* OPT */
+	Z_InternationalString *resultSetPackage; /* OPT */
+};
+
+struct Z_PQSTargetPart {
+	Z_Query *actualQuery;
+	Z_PQSPeriod *targetStatedPeriod;
+	char *expiration; /* OPT */
+	Z_InternationalString *resultSetPackage; /* OPT */
+	char *lastQueryTime;
+	int *lastResultNumber;
+	int *numberSinceModify; /* OPT */
+};
+
+struct Z_PQSPeriod {
+	int which;
+	union {
+		Z_IntUnit *unit;
+		Odr_null *businessDaily;
+		Odr_null *continuous;
+		Z_InternationalString *other;
+#define Z_PQSPeriod_unit 1
+#define Z_PQSPeriod_businessDaily 2
+#define Z_PQSPeriod_continuous 3
+#define Z_PQSPeriod_other 4
+	} u;
+};
+
+#ifdef __cplusplus
+}
+#endif
+#endif
Index: /main/tags/2.25/gsdl/packages/yaz/include/yaz/zes-pset.h
===================================================================
--- /main/tags/2.25/gsdl/packages/yaz/include/yaz/zes-pset.h	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/yaz/include/yaz/zes-pset.h	(revision 21064)
@@ -0,0 +1,68 @@
+/* Generated automatically by the YAZ ASN.1 Compiler 0.3 */
+/* Module-H ESFormat-PersistentResultSet */
+
+#ifndef zes_pset_H
+#define zes_pset_H
+
+#include <yaz/odr.h>
+#include <yaz/z-core.h>
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef struct Z_PRPersistentResultSetEsRequest Z_PRPersistentResultSetEsRequest;
+YAZ_EXPORT int z_PRPersistentResultSetEsRequest (ODR o, Z_PRPersistentResultSetEsRequest **p, int opt, const char *name);
+
+typedef struct Z_PRPersistentResultSetTaskPackage Z_PRPersistentResultSetTaskPackage;
+YAZ_EXPORT int z_PRPersistentResultSetTaskPackage (ODR o, Z_PRPersistentResultSetTaskPackage **p, int opt, const char *name);
+
+typedef struct Z_PRPersistentResultSet Z_PRPersistentResultSet;
+YAZ_EXPORT int z_PRPersistentResultSet (ODR o, Z_PRPersistentResultSet **p, int opt, const char *name);
+
+typedef struct Z_PROriginPartNotToKeep Z_PROriginPartNotToKeep;
+YAZ_EXPORT int z_PROriginPartNotToKeep (ODR o, Z_PROriginPartNotToKeep **p, int opt, const char *name);
+
+typedef struct Z_PRTargetPart Z_PRTargetPart;
+YAZ_EXPORT int z_PRTargetPart (ODR o, Z_PRTargetPart **p, int opt, const char *name);
+#ifdef __cplusplus
+}
+#endif
+#ifdef __cplusplus
+extern "C" {
+#endif
+struct Z_PRPersistentResultSetEsRequest {
+	Odr_null *toKeep;
+	Z_PROriginPartNotToKeep *notToKeep; /* OPT */
+};
+
+struct Z_PRPersistentResultSetTaskPackage {
+	Odr_null *originPart;
+	Z_PRTargetPart *targetPart; /* OPT */
+};
+
+struct Z_PRPersistentResultSet {
+	int which;
+	union {
+		Z_PRPersistentResultSetEsRequest *esRequest;
+		Z_PRPersistentResultSetTaskPackage *taskPackage;
+#define Z_PRPersistentResultSet_esRequest 1
+#define Z_PRPersistentResultSet_taskPackage 2
+	} u;
+};
+
+struct Z_PROriginPartNotToKeep {
+	Z_InternationalString *originSuppliedResultSet; /* OPT */
+#define Z_PROriginPartNotToKeep_replace 1
+#define Z_PROriginPartNotToKeep_append 2
+	int *replaceOrAppend; /* OPT */
+};
+
+struct Z_PRTargetPart {
+	Z_InternationalString *targetSuppliedResultSet; /* OPT */
+	int *numberOfRecords; /* OPT */
+};
+
+#ifdef __cplusplus
+}
+#endif
+#endif
Index: /main/tags/2.25/gsdl/packages/yaz/include/yaz/zes-update.h
===================================================================
--- /main/tags/2.25/gsdl/packages/yaz/include/yaz/zes-update.h	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/yaz/include/yaz/zes-update.h	(revision 21064)
@@ -0,0 +1,163 @@
+/* Generated automatically by the YAZ ASN.1 Compiler 0.3 */
+/* Module-H ESFormat-Update */
+
+#ifndef zes_update_H
+#define zes_update_H
+
+#include <yaz/odr.h>
+#include <yaz/z-core.h>
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef struct Z_IUUpdateEsRequest Z_IUUpdateEsRequest;
+YAZ_EXPORT int z_IUUpdateEsRequest (ODR o, Z_IUUpdateEsRequest **p, int opt, const char *name);
+
+typedef struct Z_IUUpdateTaskPackage Z_IUUpdateTaskPackage;
+YAZ_EXPORT int z_IUUpdateTaskPackage (ODR o, Z_IUUpdateTaskPackage **p, int opt, const char *name);
+
+typedef struct Z_IUUpdate Z_IUUpdate;
+YAZ_EXPORT int z_IUUpdate (ODR o, Z_IUUpdate **p, int opt, const char *name);
+
+typedef struct Z_IUOriginPartToKeep Z_IUOriginPartToKeep;
+YAZ_EXPORT int z_IUOriginPartToKeep (ODR o, Z_IUOriginPartToKeep **p, int opt, const char *name);
+
+typedef struct Z_IUTargetPart Z_IUTargetPart;
+YAZ_EXPORT int z_IUTargetPart (ODR o, Z_IUTargetPart **p, int opt, const char *name);
+
+typedef struct Z_IUSuppliedRecordsId Z_IUSuppliedRecordsId;
+YAZ_EXPORT int z_IUSuppliedRecordsId (ODR o, Z_IUSuppliedRecordsId **p, int opt, const char *name);
+
+typedef struct Z_IUSuppliedRecords_elem Z_IUSuppliedRecords_elem;
+YAZ_EXPORT int z_IUSuppliedRecords_elem (ODR o, Z_IUSuppliedRecords_elem **p, int opt, const char *name);
+
+typedef struct Z_IUSuppliedRecords Z_IUSuppliedRecords;
+YAZ_EXPORT int z_IUSuppliedRecords (ODR o, Z_IUSuppliedRecords **p, int opt, const char *name);
+
+typedef Z_IUSuppliedRecords  Z_IUOriginPartNotToKeep;
+YAZ_EXPORT int z_IUOriginPartNotToKeep (ODR o, Z_IUOriginPartNotToKeep **p, int opt, const char *name);
+
+typedef struct Z_IUCorrelationInfo Z_IUCorrelationInfo;
+YAZ_EXPORT int z_IUCorrelationInfo (ODR o, Z_IUCorrelationInfo **p, int opt, const char *name);
+
+typedef struct Z_IUTaskPackageRecordStructureSurrogateDiagnostics Z_IUTaskPackageRecordStructureSurrogateDiagnostics;
+YAZ_EXPORT int z_IUTaskPackageRecordStructureSurrogateDiagnostics (ODR o, Z_IUTaskPackageRecordStructureSurrogateDiagnostics **p, int opt, const char *name);
+
+typedef struct Z_IUTaskPackageRecordStructure Z_IUTaskPackageRecordStructure;
+YAZ_EXPORT int z_IUTaskPackageRecordStructure (ODR o, Z_IUTaskPackageRecordStructure **p, int opt, const char *name);
+#ifdef __cplusplus
+}
+#endif
+#ifdef __cplusplus
+extern "C" {
+#endif
+struct Z_IUUpdateEsRequest {
+	Z_IUOriginPartToKeep *toKeep;
+	Z_IUOriginPartNotToKeep *notToKeep;
+};
+
+struct Z_IUUpdateTaskPackage {
+	Z_IUOriginPartToKeep *originPart;
+	Z_IUTargetPart *targetPart;
+};
+
+struct Z_IUUpdate {
+	int which;
+	union {
+		Z_IUUpdateEsRequest *esRequest;
+		Z_IUUpdateTaskPackage *taskPackage;
+#define Z_IUUpdate_esRequest 1
+#define Z_IUUpdate_taskPackage 2
+	} u;
+};
+
+struct Z_IUOriginPartToKeep {
+#define Z_IUOriginPartToKeep_recordInsert 1
+#define Z_IUOriginPartToKeep_recordReplace 2
+#define Z_IUOriginPartToKeep_recordDelete 3
+#define Z_IUOriginPartToKeep_elementUpdate 4
+#define Z_IUOriginPartToKeep_specialUpdate 5
+	int *action;
+	Z_InternationalString *databaseName;
+	Odr_oid *schema; /* OPT */
+	Z_InternationalString *elementSetName; /* OPT */
+	Z_External *actionQualifier; /* OPT */
+};
+
+
+
+struct Z_IUTargetPart {
+#define Z_IUTargetPart_success 1
+#define Z_IUTargetPart_partial 2
+#define Z_IUTargetPart_failure 3
+	int *updateStatus;
+	int num_globalDiagnostics;
+	Z_DiagRec **globalDiagnostics; /* OPT */
+	int num_taskPackageRecords;
+	Z_IUTaskPackageRecordStructure **taskPackageRecords;
+};
+
+struct Z_IUSuppliedRecordsId {
+	int which;
+	union {
+		char *timeStamp;
+		Z_InternationalString *versionNumber;
+		Z_External *previousVersion;
+#define Z_IUSuppliedRecordsId_timeStamp 1
+#define Z_IUSuppliedRecordsId_versionNumber 2
+#define Z_IUSuppliedRecordsId_previousVersion 3
+	} u;
+};
+
+struct Z_IUSuppliedRecords_elem {
+	int which;
+	union {
+		int *number;
+		Z_InternationalString *string;
+		Odr_oct *opaque;
+#define Z_IUSuppliedRecords_elem_number 1
+#define Z_IUSuppliedRecords_elem_string 2
+#define Z_IUSuppliedRecords_elem_opaque 3
+	} u; /* OPT */
+	Z_IUSuppliedRecordsId *supplementalId; /* OPT */
+	Z_IUCorrelationInfo *correlationInfo; /* OPT */
+	Z_External *record;
+};
+
+struct Z_IUSuppliedRecords {
+	int num;
+	Z_IUSuppliedRecords_elem **elements;
+};
+
+struct Z_IUCorrelationInfo {
+	Z_InternationalString *note; /* OPT */
+	int *id; /* OPT */
+};
+
+struct Z_IUTaskPackageRecordStructureSurrogateDiagnostics {
+	int num;
+	Z_DiagRec **elements;
+};
+
+struct Z_IUTaskPackageRecordStructure {
+	int which;
+	union {
+		Z_External *record;
+		Z_IUTaskPackageRecordStructureSurrogateDiagnostics *surrogateDiagnostics;
+#define Z_IUTaskPackageRecordStructure_record 1
+#define Z_IUTaskPackageRecordStructure_surrogateDiagnostics 2
+	} u; /* OPT */
+	Z_IUCorrelationInfo *correlationInfo; /* OPT */
+#define Z_IUTaskPackageRecordStructure_success 1
+#define Z_IUTaskPackageRecordStructure_queued 2
+#define Z_IUTaskPackageRecordStructure_inProcess 3
+#define Z_IUTaskPackageRecordStructure_failure 4
+	int *recordStatus;
+	int num_supplementalDiagnostics;
+	Z_DiagRec **supplementalDiagnostics; /* OPT */
+};
+
+#ifdef __cplusplus
+}
+#endif
+#endif
Index: /main/tags/2.25/gsdl/packages/yaz/include/yaz/zes-update0.h
===================================================================
--- /main/tags/2.25/gsdl/packages/yaz/include/yaz/zes-update0.h	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/yaz/include/yaz/zes-update0.h	(revision 21064)
@@ -0,0 +1,151 @@
+/* Generated automatically by the YAZ ASN.1 Compiler 0.3 */
+/* Module-H ESFormat-Update0 */
+
+#ifndef zes_update0_H
+#define zes_update0_H
+
+#include <yaz/odr.h>
+#include <yaz/z-core.h>
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef struct Z_IU0UpdateEsRequest Z_IU0UpdateEsRequest;
+YAZ_EXPORT int z_IU0UpdateEsRequest (ODR o, Z_IU0UpdateEsRequest **p, int opt, const char *name);
+
+typedef struct Z_IU0UpdateTaskPackage Z_IU0UpdateTaskPackage;
+YAZ_EXPORT int z_IU0UpdateTaskPackage (ODR o, Z_IU0UpdateTaskPackage **p, int opt, const char *name);
+
+typedef struct Z_IU0Update Z_IU0Update;
+YAZ_EXPORT int z_IU0Update (ODR o, Z_IU0Update **p, int opt, const char *name);
+
+typedef struct Z_IU0OriginPartToKeep Z_IU0OriginPartToKeep;
+YAZ_EXPORT int z_IU0OriginPartToKeep (ODR o, Z_IU0OriginPartToKeep **p, int opt, const char *name);
+
+typedef struct Z_IU0TargetPart Z_IU0TargetPart;
+YAZ_EXPORT int z_IU0TargetPart (ODR o, Z_IU0TargetPart **p, int opt, const char *name);
+
+typedef struct Z_IU0SuppliedRecordsId Z_IU0SuppliedRecordsId;
+YAZ_EXPORT int z_IU0SuppliedRecordsId (ODR o, Z_IU0SuppliedRecordsId **p, int opt, const char *name);
+
+typedef struct Z_IU0SuppliedRecords_elem Z_IU0SuppliedRecords_elem;
+YAZ_EXPORT int z_IU0SuppliedRecords_elem (ODR o, Z_IU0SuppliedRecords_elem **p, int opt, const char *name);
+
+typedef struct Z_IU0SuppliedRecords Z_IU0SuppliedRecords;
+YAZ_EXPORT int z_IU0SuppliedRecords (ODR o, Z_IU0SuppliedRecords **p, int opt, const char *name);
+
+typedef Z_IU0SuppliedRecords  Z_IU0OriginPartNotToKeep;
+YAZ_EXPORT int z_IU0OriginPartNotToKeep (ODR o, Z_IU0OriginPartNotToKeep **p, int opt, const char *name);
+
+typedef struct Z_IU0CorrelationInfo Z_IU0CorrelationInfo;
+YAZ_EXPORT int z_IU0CorrelationInfo (ODR o, Z_IU0CorrelationInfo **p, int opt, const char *name);
+
+typedef struct Z_IU0TaskPackageRecordStructure Z_IU0TaskPackageRecordStructure;
+YAZ_EXPORT int z_IU0TaskPackageRecordStructure (ODR o, Z_IU0TaskPackageRecordStructure **p, int opt, const char *name);
+#ifdef __cplusplus
+}
+#endif
+#ifdef __cplusplus
+extern "C" {
+#endif
+struct Z_IU0UpdateEsRequest {
+	Z_IU0OriginPartToKeep *toKeep;
+	Z_IU0OriginPartNotToKeep *notToKeep;
+};
+
+struct Z_IU0UpdateTaskPackage {
+	Z_IU0OriginPartToKeep *originPart;
+	Z_IU0TargetPart *targetPart;
+};
+
+struct Z_IU0Update {
+	int which;
+	union {
+		Z_IU0UpdateEsRequest *esRequest;
+		Z_IU0UpdateTaskPackage *taskPackage;
+#define Z_IU0Update_esRequest 1
+#define Z_IU0Update_taskPackage 2
+	} u;
+};
+
+struct Z_IU0OriginPartToKeep {
+#define Z_IU0OriginPartToKeep_recordInsert 1
+#define Z_IU0OriginPartToKeep_recordReplace 2
+#define Z_IU0OriginPartToKeep_recordDelete 3
+#define Z_IU0OriginPartToKeep_elementUpdate 4
+	int *action;
+	Z_InternationalString *databaseName;
+	Odr_oid *schema; /* OPT */
+	Z_InternationalString *elementSetName; /* OPT */
+};
+
+
+
+struct Z_IU0TargetPart {
+#define Z_IU0TargetPart_success 1
+#define Z_IU0TargetPart_partial 2
+#define Z_IU0TargetPart_failure 3
+	int *updateStatus;
+	int num_globalDiagnostics;
+	Z_DiagRec **globalDiagnostics; /* OPT */
+	int num_taskPackageRecords;
+	Z_IU0TaskPackageRecordStructure **taskPackageRecords;
+};
+
+struct Z_IU0SuppliedRecordsId {
+	int which;
+	union {
+		char *timeStamp;
+		Z_InternationalString *versionNumber;
+		Z_External *previousVersion;
+#define Z_IU0SuppliedRecordsId_timeStamp 1
+#define Z_IU0SuppliedRecordsId_versionNumber 2
+#define Z_IU0SuppliedRecordsId_previousVersion 3
+	} u;
+};
+
+struct Z_IU0SuppliedRecords_elem {
+	int which;
+	union {
+		int *number;
+		Z_InternationalString *string;
+		Odr_oct *opaque;
+#define Z_IU0SuppliedRecords_elem_number 1
+#define Z_IU0SuppliedRecords_elem_string 2
+#define Z_IU0SuppliedRecords_elem_opaque 3
+	} u; /* OPT */
+	Z_IU0SuppliedRecordsId *supplementalId; /* OPT */
+	Z_IU0CorrelationInfo *correlationInfo; /* OPT */
+	Z_External *record;
+};
+
+struct Z_IU0SuppliedRecords {
+	int num;
+	Z_IU0SuppliedRecords_elem **elements;
+};
+
+struct Z_IU0CorrelationInfo {
+	Z_InternationalString *note; /* OPT */
+	int *id; /* OPT */
+};
+
+struct Z_IU0TaskPackageRecordStructure {
+	int which;
+	union {
+		Z_External *record;
+		Z_DiagRec *diagnostic;
+#define Z_IU0TaskPackageRecordStructure_record 1
+#define Z_IU0TaskPackageRecordStructure_diagnostic 2
+	} u; /* OPT */
+	Z_IU0CorrelationInfo *correlationInfo; /* OPT */
+#define Z_IU0TaskPackageRecordStructure_success 1
+#define Z_IU0TaskPackageRecordStructure_queued 2
+#define Z_IU0TaskPackageRecordStructure_inProcess 3
+#define Z_IU0TaskPackageRecordStructure_failure 4
+	int *recordStatus;
+};
+
+#ifdef __cplusplus
+}
+#endif
+#endif
Index: /main/tags/2.25/gsdl/packages/yaz/install-sh
===================================================================
--- /main/tags/2.25/gsdl/packages/yaz/install-sh	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/yaz/install-sh	(revision 21064)
@@ -0,0 +1,250 @@
+#! /bin/sh
+#
+# install - install a program, script, or datafile
+# This comes from X11R5 (mit/util/scripts/install.sh).
+#
+# Copyright 1991 by the Massachusetts Institute of Technology
+#
+# Permission to use, copy, modify, distribute, and sell this software and its
+# documentation for any purpose is hereby granted without fee, provided that
+# the above copyright notice appear in all copies and that both that
+# copyright notice and this permission notice appear in supporting
+# documentation, and that the name of M.I.T. not be used in advertising or
+# publicity pertaining to distribution of the software without specific,
+# written prior permission.  M.I.T. makes no representations about the
+# suitability of this software for any purpose.  It is provided "as is"
+# without express or implied warranty.
+#
+# Calling this script install-sh is preferred over install.sh, to prevent
+# `make' implicit rules from creating a file called install from it
+# when there is no Makefile.
+#
+# This script is compatible with the BSD install script, but was written
+# from scratch.  It can only install one file at a time, a restriction
+# shared with many OS's install programs.
+
+
+# set DOITPROG to echo to test this script
+
+# Don't use :- since 4.3BSD and earlier shells don't like it.
+doit="${DOITPROG-}"
+
+
+# put in absolute paths if you don't have them in your path; or use env. vars.
+
+mvprog="${MVPROG-mv}"
+cpprog="${CPPROG-cp}"
+chmodprog="${CHMODPROG-chmod}"
+chownprog="${CHOWNPROG-chown}"
+chgrpprog="${CHGRPPROG-chgrp}"
+stripprog="${STRIPPROG-strip}"
+rmprog="${RMPROG-rm}"
+mkdirprog="${MKDIRPROG-mkdir}"
+
+transformbasename=""
+transform_arg=""
+instcmd="$mvprog"
+chmodcmd="$chmodprog 0755"
+chowncmd=""
+chgrpcmd=""
+stripcmd=""
+rmcmd="$rmprog -f"
+mvcmd="$mvprog"
+src=""
+dst=""
+dir_arg=""
+
+while [ x"$1" != x ]; do
+    case $1 in
+	-c) instcmd="$cpprog"
+	    shift
+	    continue;;
+
+	-d) dir_arg=true
+	    shift
+	    continue;;
+
+	-m) chmodcmd="$chmodprog $2"
+	    shift
+	    shift
+	    continue;;
+
+	-o) chowncmd="$chownprog $2"
+	    shift
+	    shift
+	    continue;;
+
+	-g) chgrpcmd="$chgrpprog $2"
+	    shift
+	    shift
+	    continue;;
+
+	-s) stripcmd="$stripprog"
+	    shift
+	    continue;;
+
+	-t=*) transformarg=`echo $1 | sed 's/-t=//'`
+	    shift
+	    continue;;
+
+	-b=*) transformbasename=`echo $1 | sed 's/-b=//'`
+	    shift
+	    continue;;
+
+	*)  if [ x"$src" = x ]
+	    then
+		src=$1
+	    else
+		# this colon is to work around a 386BSD /bin/sh bug
+		:
+		dst=$1
+	    fi
+	    shift
+	    continue;;
+    esac
+done
+
+if [ x"$src" = x ]
+then
+	echo "install:	no input file specified"
+	exit 1
+else
+	true
+fi
+
+if [ x"$dir_arg" != x ]; then
+	dst=$src
+	src=""
+	
+	if [ -d $dst ]; then
+		instcmd=:
+	else
+		instcmd=mkdir
+	fi
+else
+
+# Waiting for this to be detected by the "$instcmd $src $dsttmp" command
+# might cause directories to be created, which would be especially bad 
+# if $src (and thus $dsttmp) contains '*'.
+
+	if [ -f $src -o -d $src ]
+	then
+		true
+	else
+		echo "install:  $src does not exist"
+		exit 1
+	fi
+	
+	if [ x"$dst" = x ]
+	then
+		echo "install:	no destination specified"
+		exit 1
+	else
+		true
+	fi
+
+# If destination is a directory, append the input filename; if your system
+# does not like double slashes in filenames, you may need to add some logic
+
+	if [ -d $dst ]
+	then
+		dst="$dst"/`basename $src`
+	else
+		true
+	fi
+fi
+
+## this sed command emulates the dirname command
+dstdir=`echo $dst | sed -e 's,[^/]*$,,;s,/$,,;s,^$,.,'`
+
+# Make sure that the destination directory exists.
+#  this part is taken from Noah Friedman's mkinstalldirs script
+
+# Skip lots of stat calls in the usual case.
+if [ ! -d "$dstdir" ]; then
+defaultIFS='	
+'
+IFS="${IFS-${defaultIFS}}"
+
+oIFS="${IFS}"
+# Some sh's can't handle IFS=/ for some reason.
+IFS='%'
+set - `echo ${dstdir} | sed -e 's@/@%@g' -e 's@^%@/@'`
+IFS="${oIFS}"
+
+pathcomp=''
+
+while [ $# -ne 0 ] ; do
+	pathcomp="${pathcomp}${1}"
+	shift
+
+	if [ ! -d "${pathcomp}" ] ;
+        then
+		$mkdirprog "${pathcomp}"
+	else
+		true
+	fi
+
+	pathcomp="${pathcomp}/"
+done
+fi
+
+if [ x"$dir_arg" != x ]
+then
+	$doit $instcmd $dst &&
+
+	if [ x"$chowncmd" != x ]; then $doit $chowncmd $dst; else true ; fi &&
+	if [ x"$chgrpcmd" != x ]; then $doit $chgrpcmd $dst; else true ; fi &&
+	if [ x"$stripcmd" != x ]; then $doit $stripcmd $dst; else true ; fi &&
+	if [ x"$chmodcmd" != x ]; then $doit $chmodcmd $dst; else true ; fi
+else
+
+# If we're going to rename the final executable, determine the name now.
+
+	if [ x"$transformarg" = x ] 
+	then
+		dstfile=`basename $dst`
+	else
+		dstfile=`basename $dst $transformbasename | 
+			sed $transformarg`$transformbasename
+	fi
+
+# don't allow the sed command to completely eliminate the filename
+
+	if [ x"$dstfile" = x ] 
+	then
+		dstfile=`basename $dst`
+	else
+		true
+	fi
+
+# Make a temp file name in the proper directory.
+
+	dsttmp=$dstdir/#inst.$$#
+
+# Move or copy the file name to the temp name
+
+	$doit $instcmd $src $dsttmp &&
+
+	trap "rm -f ${dsttmp}" 0 &&
+
+# and set any options; do chmod last to preserve setuid bits
+
+# If any of these fail, we abort the whole thing.  If we want to
+# ignore errors from any of these, just make sure not to ignore
+# errors from the above "$doit $instcmd $src $dsttmp" command.
+
+	if [ x"$chowncmd" != x ]; then $doit $chowncmd $dsttmp; else true;fi &&
+	if [ x"$chgrpcmd" != x ]; then $doit $chgrpcmd $dsttmp; else true;fi &&
+	if [ x"$stripcmd" != x ]; then $doit $stripcmd $dsttmp; else true;fi &&
+	if [ x"$chmodcmd" != x ]; then $doit $chmodcmd $dsttmp; else true;fi &&
+
+# Now rename the file to the real destination.
+
+	$doit $rmcmd -f $dstdir/$dstfile &&
+	$doit $mvcmd $dsttmp $dstdir/$dstfile 
+
+fi &&
+
+
+exit 0
Index: /main/tags/2.25/gsdl/packages/yaz/lib/Makefile.am
===================================================================
--- /main/tags/2.25/gsdl/packages/yaz/lib/Makefile.am	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/yaz/lib/Makefile.am	(revision 21064)
@@ -0,0 +1,34 @@
+## $Id$
+
+lib_LIBRARIES = libyaz.a
+
+bin_SCRIPTS = yaz-config
+
+libyaz_a_SOURCES=
+
+LIB=libyaz.a
+
+YAZLIBS=../odr/libodr.a ../@ASNMODULE@/libasn.a ../comstack/libcomstack.a \
+ ../server/libserver.a ../zutil/libzutil.a ../util/libutil.a \
+ ../ccl/libccl.a ../retrieval/libret.a @ILLLIB@
+
+libyaz.a: $(YAZLIBS)
+	rm -f $(LIB)
+	for i in $(YAZLIBS); do echo $$i; ar x $$i; rm -f __*; done
+	ar qc $(LIB) *.o
+	rm -f *.o
+	$(RANLIB) $(LIB)
+
+#  Public libraries and header files
+LIBDIR=$(exec_prefix)/lib
+INCDIR=$(prefix)/include
+
+yaz-config: Makefile
+	@echo "#!/bin/sh" >yaz-config
+	@echo "# YAZ settings for developers" >>yaz-config
+	@echo "YAZBIN='$(bindir)'" >>yaz-config
+	@echo "YAZTAB='$(pkgdatadir)/tab'" >>yaz-config
+	@echo "YAZLIB='-L$(libdir) -lyaz $(LIBS)'" >>yaz-config
+	@echo "YAZINC='-I$(includedir)'" >>yaz-config
+	chmod +x yaz-config
+
Index: /main/tags/2.25/gsdl/packages/yaz/lib/Makefile.in
===================================================================
--- /main/tags/2.25/gsdl/packages/yaz/lib/Makefile.in	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/yaz/lib/Makefile.in	(revision 21064)
@@ -0,0 +1,299 @@
+# Makefile.in generated automatically by automake 1.4 from Makefile.am
+
+# Copyright (C) 1994, 1995-8, 1999 Free Software Foundation, Inc.
+# This Makefile.in is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
+# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE.
+
+
+SHELL = @SHELL@
+
+srcdir = @srcdir@
+top_srcdir = @top_srcdir@
+VPATH = @srcdir@
+prefix = @prefix@
+exec_prefix = @exec_prefix@
+
+bindir = @bindir@
+sbindir = @sbindir@
+libexecdir = @libexecdir@
+datadir = @datadir@
+sysconfdir = @sysconfdir@
+sharedstatedir = @sharedstatedir@
+localstatedir = @localstatedir@
+libdir = @libdir@
+infodir = @infodir@
+mandir = @mandir@
+includedir = @includedir@
+oldincludedir = /usr/include
+
+DESTDIR =
+
+pkgdatadir = $(datadir)/@PACKAGE@
+pkglibdir = $(libdir)/@PACKAGE@
+pkgincludedir = $(includedir)/@PACKAGE@
+
+top_builddir = ..
+
+ACLOCAL = @ACLOCAL@
+AUTOCONF = @AUTOCONF@
+AUTOMAKE = @AUTOMAKE@
+AUTOHEADER = @AUTOHEADER@
+
+INSTALL = @INSTALL@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@ $(AM_INSTALL_PROGRAM_FLAGS)
+INSTALL_DATA = @INSTALL_DATA@
+INSTALL_SCRIPT = @INSTALL_SCRIPT@
+transform = @program_transform_name@
+
+NORMAL_INSTALL = :
+PRE_INSTALL = :
+POST_INSTALL = :
+NORMAL_UNINSTALL = :
+PRE_UNINSTALL = :
+POST_UNINSTALL = :
+ASNMODULE = @ASNMODULE@
+CC = @CC@
+CPP = @CPP@
+ILLLIB = @ILLLIB@
+ILLMODULE = @ILLMODULE@
+MAKEINFO = @MAKEINFO@
+PACKAGE = @PACKAGE@
+RANLIB = @RANLIB@
+SUBDIRS_VAR = @SUBDIRS_VAR@
+VERSION = @VERSION@
+have_sgml2html = @have_sgml2html@
+have_sgml2latex = @have_sgml2latex@
+have_sgml2txt = @have_sgml2txt@
+
+lib_LIBRARIES = libyaz.a
+
+bin_SCRIPTS = yaz-config
+
+libyaz_a_SOURCES = 
+
+LIB = libyaz.a
+
+YAZLIBS = ../odr/libodr.a ../@ASNMODULE@/libasn.a ../comstack/libcomstack.a  ../server/libserver.a ../zutil/libzutil.a ../util/libutil.a  ../ccl/libccl.a ../retrieval/libret.a @ILLLIB@
+
+
+#  Public libraries and header files
+LIBDIR = $(exec_prefix)/lib
+INCDIR = $(prefix)/include
+mkinstalldirs = $(SHELL) $(top_srcdir)/mkinstalldirs
+CONFIG_CLEAN_FILES = 
+LIBRARIES =  $(lib_LIBRARIES)
+
+
+DEFS = @DEFS@ -I. -I$(srcdir) 
+CPPFLAGS = @CPPFLAGS@
+LDFLAGS = @LDFLAGS@
+LIBS = @LIBS@
+libyaz_a_LIBADD = 
+libyaz_a_OBJECTS = 
+AR = ar
+SCRIPTS =  $(bin_SCRIPTS)
+
+DIST_COMMON =  Makefile.am Makefile.in
+
+
+DISTFILES = $(DIST_COMMON) $(SOURCES) $(HEADERS) $(TEXINFOS) $(EXTRA_DIST)
+
+TAR = gtar
+GZIP_ENV = --best
+SOURCES = $(libyaz_a_SOURCES)
+OBJECTS = $(libyaz_a_OBJECTS)
+
+all: all-redirect
+.SUFFIXES:
+.SUFFIXES: .S .c .o .s
+$(srcdir)/Makefile.in: Makefile.am $(top_srcdir)/configure.in $(ACLOCAL_M4) 
+	cd $(top_srcdir) && $(AUTOMAKE) --gnu --include-deps lib/Makefile
+
+Makefile: $(srcdir)/Makefile.in  $(top_builddir)/config.status
+	cd $(top_builddir) \
+	  && CONFIG_FILES=$(subdir)/$@ CONFIG_HEADERS= $(SHELL) ./config.status
+
+
+mostlyclean-libLIBRARIES:
+
+clean-libLIBRARIES:
+	-test -z "$(lib_LIBRARIES)" || rm -f $(lib_LIBRARIES)
+
+distclean-libLIBRARIES:
+
+maintainer-clean-libLIBRARIES:
+
+install-libLIBRARIES: $(lib_LIBRARIES)
+	@$(NORMAL_INSTALL)
+	$(mkinstalldirs) $(DESTDIR)$(libdir)
+	@list='$(lib_LIBRARIES)'; for p in $$list; do \
+	  if test -f $$p; then \
+	    echo " $(INSTALL_DATA) $$p $(DESTDIR)$(libdir)/$$p"; \
+	    $(INSTALL_DATA) $$p $(DESTDIR)$(libdir)/$$p; \
+	  else :; fi; \
+	done
+	@$(POST_INSTALL)
+	@list='$(lib_LIBRARIES)'; for p in $$list; do \
+	  if test -f $$p; then \
+	    echo " $(RANLIB) $(DESTDIR)$(libdir)/$$p"; \
+	    $(RANLIB) $(DESTDIR)$(libdir)/$$p; \
+	  else :; fi; \
+	done
+
+uninstall-libLIBRARIES:
+	@$(NORMAL_UNINSTALL)
+	list='$(lib_LIBRARIES)'; for p in $$list; do \
+	  rm -f $(DESTDIR)$(libdir)/$$p; \
+	done
+
+.c.o:
+	$(COMPILE) -c $<
+
+.s.o:
+	$(COMPILE) -c $<
+
+.S.o:
+	$(COMPILE) -c $<
+
+mostlyclean-compile:
+	-rm -f *.o core *.core
+
+clean-compile:
+
+distclean-compile:
+	-rm -f *.tab.c
+
+maintainer-clean-compile:
+
+install-binSCRIPTS: $(bin_SCRIPTS)
+	@$(NORMAL_INSTALL)
+	$(mkinstalldirs) $(DESTDIR)$(bindir)
+	@list='$(bin_SCRIPTS)'; for p in $$list; do \
+	  if test -f $$p; then \
+	    echo " $(INSTALL_SCRIPT) $$p $(DESTDIR)$(bindir)/`echo $$p|sed '$(transform)'`"; \
+	    $(INSTALL_SCRIPT) $$p $(DESTDIR)$(bindir)/`echo $$p|sed '$(transform)'`; \
+	  else if test -f $(srcdir)/$$p; then \
+	    echo " $(INSTALL_SCRIPT) $(srcdir)/$$p $(DESTDIR)$(bindir)/`echo $$p|sed '$(transform)'`"; \
+	    $(INSTALL_SCRIPT) $(srcdir)/$$p $(DESTDIR)$(bindir)/`echo $$p|sed '$(transform)'`; \
+	  else :; fi; fi; \
+	done
+
+uninstall-binSCRIPTS:
+	@$(NORMAL_UNINSTALL)
+	list='$(bin_SCRIPTS)'; for p in $$list; do \
+	  rm -f $(DESTDIR)$(bindir)/`echo $$p|sed '$(transform)'`; \
+	done
+tags: TAGS
+TAGS:
+
+
+distdir = $(top_builddir)/$(PACKAGE)-$(VERSION)/$(subdir)
+
+subdir = lib
+
+distdir: $(DISTFILES)
+	@for file in $(DISTFILES); do \
+	  d=$(srcdir); \
+	  if test -d $$d/$$file; then \
+	    cp -pr $$/$$file $(distdir)/$$file; \
+	  else \
+	    test -f $(distdir)/$$file \
+	    || ln $$d/$$file $(distdir)/$$file 2> /dev/null \
+	    || cp -p $$d/$$file $(distdir)/$$file || :; \
+	  fi; \
+	done
+info-am:
+info: info-am
+dvi-am:
+dvi: dvi-am
+check-am: all-am
+check: check-am
+installcheck-am:
+installcheck: installcheck-am
+install-exec-am: install-libLIBRARIES install-binSCRIPTS
+install-exec: install-exec-am
+
+install-data-am:
+install-data: install-data-am
+
+install-am: all-am
+	@$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
+install: install-am
+uninstall-am: uninstall-libLIBRARIES uninstall-binSCRIPTS
+uninstall: uninstall-am
+all-am: Makefile $(LIBRARIES) $(SCRIPTS)
+all-redirect: all-am
+install-strip:
+	$(MAKE) $(AM_MAKEFLAGS) AM_INSTALL_PROGRAM_FLAGS=-s install
+installdirs:
+	$(mkinstalldirs)  $(DESTDIR)$(libdir) $(DESTDIR)$(bindir)
+
+
+mostlyclean-generic:
+
+clean-generic:
+
+distclean-generic:
+	-rm -f Makefile $(CONFIG_CLEAN_FILES)
+	-rm -f config.cache config.log stamp-h stamp-h[0-9]*
+
+maintainer-clean-generic:
+mostlyclean-am:  mostlyclean-libLIBRARIES mostlyclean-compile \
+		mostlyclean-generic
+
+mostlyclean: mostlyclean-am
+
+clean-am:  clean-libLIBRARIES clean-compile clean-generic mostlyclean-am
+
+clean: clean-am
+
+distclean-am:  distclean-libLIBRARIES distclean-compile \
+		distclean-generic clean-am
+
+distclean: distclean-am
+
+maintainer-clean-am:  maintainer-clean-libLIBRARIES \
+		maintainer-clean-compile maintainer-clean-generic \
+		distclean-am
+	@echo "This command is intended for maintainers to use;"
+	@echo "it deletes files that may require special tools to rebuild."
+
+maintainer-clean: maintainer-clean-am
+
+.PHONY: mostlyclean-libLIBRARIES distclean-libLIBRARIES \
+clean-libLIBRARIES maintainer-clean-libLIBRARIES uninstall-libLIBRARIES \
+install-libLIBRARIES mostlyclean-compile distclean-compile \
+clean-compile maintainer-clean-compile uninstall-binSCRIPTS \
+install-binSCRIPTS tags distdir info-am info dvi-am dvi check check-am \
+installcheck-am installcheck install-exec-am install-exec \
+install-data-am install-data install-am install uninstall-am uninstall \
+all-redirect all-am all installdirs mostlyclean-generic \
+distclean-generic clean-generic maintainer-clean-generic clean \
+mostlyclean distclean maintainer-clean
+
+
+libyaz.a: $(YAZLIBS)
+	rm -f $(LIB)
+	for i in $(YAZLIBS); do echo $$i; ar x $$i; rm -f __*; done
+	ar qc $(LIB) *.o
+	rm -f *.o
+	$(RANLIB) $(LIB)
+
+yaz-config: Makefile
+	@echo "#!/bin/sh" >yaz-config
+	@echo "# YAZ settings for developers" >>yaz-config
+	@echo "YAZBIN='$(bindir)'" >>yaz-config
+	@echo "YAZTAB='$(pkgdatadir)/tab'" >>yaz-config
+	@echo "YAZLIB='-L$(libdir) -lyaz $(LIBS)'" >>yaz-config
+	@echo "YAZINC='-I$(includedir)'" >>yaz-config
+	chmod +x yaz-config
+
+# Tell versions [3.59,3.63) of GNU make to not export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:
Index: /main/tags/2.25/gsdl/packages/yaz/lib/yaz-config
===================================================================
--- /main/tags/2.25/gsdl/packages/yaz/lib/yaz-config	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/yaz/lib/yaz-config	(revision 21064)
@@ -0,0 +1,6 @@
+#!/bin/sh
+# YAZ settings for developers
+YAZBIN='/usr/local/bin'
+YAZTAB='/usr/local/share/yaz/tab'
+YAZLIB='-L/usr/local/lib -lyaz -lreadline -lhistory'
+YAZINC='-I/usr/local/include'
Index: /main/tags/2.25/gsdl/packages/yaz/missing
===================================================================
--- /main/tags/2.25/gsdl/packages/yaz/missing	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/yaz/missing	(revision 21064)
@@ -0,0 +1,190 @@
+#! /bin/sh
+# Common stub for a few missing GNU programs while installing.
+# Copyright (C) 1996, 1997 Free Software Foundation, Inc.
+# Franc,ois Pinard <pinard@iro.umontreal.ca>, 1996.
+
+# 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, 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., 59 Temple Place - Suite 330, Boston, MA
+# 02111-1307, USA.
+
+if test $# -eq 0; then
+  echo 1>&2 "Try \`$0 --help' for more information"
+  exit 1
+fi
+
+case "$1" in
+
+  -h|--h|--he|--hel|--help)
+    echo "\
+$0 [OPTION]... PROGRAM [ARGUMENT]...
+
+Handle \`PROGRAM [ARGUMENT]...' for when PROGRAM is missing, or return an
+error status if there is no known handling for PROGRAM.
+
+Options:
+  -h, --help      display this help and exit
+  -v, --version   output version information and exit
+
+Supported PROGRAM values:
+  aclocal      touch file \`aclocal.m4'
+  autoconf     touch file \`configure'
+  autoheader   touch file \`config.h.in'
+  automake     touch all \`Makefile.in' files
+  bison        create \`y.tab.[ch]', if possible, from existing .[ch]
+  flex         create \`lex.yy.c', if possible, from existing .c
+  lex          create \`lex.yy.c', if possible, from existing .c
+  makeinfo     touch the output file
+  yacc         create \`y.tab.[ch]', if possible, from existing .[ch]"
+    ;;
+
+  -v|--v|--ve|--ver|--vers|--versi|--versio|--version)
+    echo "missing - GNU libit 0.0"
+    ;;
+
+  -*)
+    echo 1>&2 "$0: Unknown \`$1' option"
+    echo 1>&2 "Try \`$0 --help' for more information"
+    exit 1
+    ;;
+
+  aclocal)
+    echo 1>&2 "\
+WARNING: \`$1' is missing on your system.  You should only need it if
+         you modified \`acinclude.m4' or \`configure.in'.  You might want
+         to install the \`Automake' and \`Perl' packages.  Grab them from
+         any GNU archive site."
+    touch aclocal.m4
+    ;;
+
+  autoconf)
+    echo 1>&2 "\
+WARNING: \`$1' is missing on your system.  You should only need it if
+         you modified \`configure.in'.  You might want to install the
+         \`Autoconf' and \`GNU m4' packages.  Grab them from any GNU
+         archive site."
+    touch configure
+    ;;
+
+  autoheader)
+    echo 1>&2 "\
+WARNING: \`$1' is missing on your system.  You should only need it if
+         you modified \`acconfig.h' or \`configure.in'.  You might want
+         to install the \`Autoconf' and \`GNU m4' packages.  Grab them
+         from any GNU archive site."
+    files=`sed -n 's/^[ ]*A[CM]_CONFIG_HEADER(\([^)]*\)).*/\1/p' configure.in`
+    test -z "$files" && files="config.h"
+    touch_files=
+    for f in $files; do
+      case "$f" in
+      *:*) touch_files="$touch_files "`echo "$f" |
+				       sed -e 's/^[^:]*://' -e 's/:.*//'`;;
+      *) touch_files="$touch_files $f.in";;
+      esac
+    done
+    touch $touch_files
+    ;;
+
+  automake)
+    echo 1>&2 "\
+WARNING: \`$1' is missing on your system.  You should only need it if
+         you modified \`Makefile.am', \`acinclude.m4' or \`configure.in'.
+         You might want to install the \`Automake' and \`Perl' packages.
+         Grab them from any GNU archive site."
+    find . -type f -name Makefile.am -print |
+	   sed 's/\.am$/.in/' |
+	   while read f; do touch "$f"; done
+    ;;
+
+  bison|yacc)
+    echo 1>&2 "\
+WARNING: \`$1' is missing on your system.  You should only need it if
+         you modified a \`.y' file.  You may need the \`Bison' package
+         in order for those modifications to take effect.  You can get
+         \`Bison' from any GNU archive site."
+    rm -f y.tab.c y.tab.h
+    if [ $# -ne 1 ]; then
+        eval LASTARG="\${$#}"
+	case "$LASTARG" in
+	*.y)
+	    SRCFILE=`echo "$LASTARG" | sed 's/y$/c/'`
+	    if [ -f "$SRCFILE" ]; then
+	         cp "$SRCFILE" y.tab.c
+	    fi
+	    SRCFILE=`echo "$LASTARG" | sed 's/y$/h/'`
+	    if [ -f "$SRCFILE" ]; then
+	         cp "$SRCFILE" y.tab.h
+	    fi
+	  ;;
+	esac
+    fi
+    if [ ! -f y.tab.h ]; then
+	echo >y.tab.h
+    fi
+    if [ ! -f y.tab.c ]; then
+	echo 'main() { return 0; }' >y.tab.c
+    fi
+    ;;
+
+  lex|flex)
+    echo 1>&2 "\
+WARNING: \`$1' is missing on your system.  You should only need it if
+         you modified a \`.l' file.  You may need the \`Flex' package
+         in order for those modifications to take effect.  You can get
+         \`Flex' from any GNU archive site."
+    rm -f lex.yy.c
+    if [ $# -ne 1 ]; then
+        eval LASTARG="\${$#}"
+	case "$LASTARG" in
+	*.l)
+	    SRCFILE=`echo "$LASTARG" | sed 's/l$/c/'`
+	    if [ -f "$SRCFILE" ]; then
+	         cp "$SRCFILE" lex.yy.c
+	    fi
+	  ;;
+	esac
+    fi
+    if [ ! -f lex.yy.c ]; then
+	echo 'main() { return 0; }' >lex.yy.c
+    fi
+    ;;
+
+  makeinfo)
+    echo 1>&2 "\
+WARNING: \`$1' is missing on your system.  You should only need it if
+         you modified a \`.texi' or \`.texinfo' file, or any other file
+         indirectly affecting the aspect of the manual.  The spurious
+         call might also be the consequence of using a buggy \`make' (AIX,
+         DU, IRIX).  You might want to install the \`Texinfo' package or
+         the \`GNU make' package.  Grab either from any GNU archive site."
+    file=`echo "$*" | sed -n 's/.*-o \([^ ]*\).*/\1/p'`
+    if test -z "$file"; then
+      file=`echo "$*" | sed 's/.* \([^ ]*\) *$/\1/'`
+      file=`sed -n '/^@setfilename/ { s/.* \([^ ]*\) *$/\1/; p; q; }' $file`
+    fi
+    touch $file
+    ;;
+
+  *)
+    echo 1>&2 "\
+WARNING: \`$1' is needed, and you do not seem to have it handy on your
+         system.  You might have modified some files without having the
+         proper tools for further handling them.  Check the \`README' file,
+         it often tells you about the needed prerequirements for installing
+         this package.  You may also peek at any GNU archive site, in case
+         some other package would contain this missing \`$1' program."
+    exit 1
+    ;;
+esac
+
+exit 0
Index: /main/tags/2.25/gsdl/packages/yaz/mkinstalldirs
===================================================================
--- /main/tags/2.25/gsdl/packages/yaz/mkinstalldirs	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/yaz/mkinstalldirs	(revision 21064)
@@ -0,0 +1,39 @@
+#! /bin/sh
+# mkinstalldirs --- make directory hierarchy
+# Author: Noah Friedman <friedman@prep.ai.mit.edu>
+# Created: 1993-05-16
+# Public domain
+
+
+errstatus=0
+
+for file
+do
+   set fnord `echo ":$file" | sed -ne 's/^:\//#/;s/^://;s/\// /g;s/^#/\//;p'`
+   shift
+
+   pathcomp=
+   for d
+   do
+     pathcomp="$pathcomp$d"
+     case "$pathcomp" in
+       -* ) pathcomp=./$pathcomp ;;
+     esac
+
+     if test ! -d "$pathcomp"; then
+        echo "mkdir $pathcomp"
+
+        mkdir "$pathcomp" || lasterr=$?
+
+        if test ! -d "$pathcomp"; then
+  	  errstatus=$lasterr
+        fi
+     fi
+
+     pathcomp="$pathcomp/"
+   done
+done
+
+exit $errstatus
+
+# mkinstalldirs ends here
Index: /main/tags/2.25/gsdl/packages/yaz/odr/Makefile.am
===================================================================
--- /main/tags/2.25/gsdl/packages/yaz/odr/Makefile.am	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/yaz/odr/Makefile.am	(revision 21064)
@@ -0,0 +1,12 @@
+## $Id$
+
+noinst_LIBRARIES = libodr.a
+
+INCLUDES=-I../include
+
+libodr_a_SOURCES = odr_bool.c ber_bool.c ber_len.c ber_tag.c odr_util.c \
+        odr_null.c ber_null.c odr_int.c ber_int.c odr_tag.c odr_cons.c \
+        odr_seq.c odr_oct.c ber_oct.c odr_bit.c ber_bit.c odr_oid.c \
+        ber_oid.c odr_use.c odr_choice.c odr_any.c ber_any.c odr.c odr_mem.c \
+        dumpber.c odr_enum.c
+
Index: /main/tags/2.25/gsdl/packages/yaz/odr/Makefile.in
===================================================================
--- /main/tags/2.25/gsdl/packages/yaz/odr/Makefile.in	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/yaz/odr/Makefile.in	(revision 21064)
@@ -0,0 +1,271 @@
+# Makefile.in generated automatically by automake 1.4 from Makefile.am
+
+# Copyright (C) 1994, 1995-8, 1999 Free Software Foundation, Inc.
+# This Makefile.in is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
+# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE.
+
+
+SHELL = @SHELL@
+
+srcdir = @srcdir@
+top_srcdir = @top_srcdir@
+VPATH = @srcdir@
+prefix = @prefix@
+exec_prefix = @exec_prefix@
+
+bindir = @bindir@
+sbindir = @sbindir@
+libexecdir = @libexecdir@
+datadir = @datadir@
+sysconfdir = @sysconfdir@
+sharedstatedir = @sharedstatedir@
+localstatedir = @localstatedir@
+libdir = @libdir@
+infodir = @infodir@
+mandir = @mandir@
+includedir = @includedir@
+oldincludedir = /usr/include
+
+DESTDIR =
+
+pkgdatadir = $(datadir)/@PACKAGE@
+pkglibdir = $(libdir)/@PACKAGE@
+pkgincludedir = $(includedir)/@PACKAGE@
+
+top_builddir = ..
+
+ACLOCAL = @ACLOCAL@
+AUTOCONF = @AUTOCONF@
+AUTOMAKE = @AUTOMAKE@
+AUTOHEADER = @AUTOHEADER@
+
+INSTALL = @INSTALL@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@ $(AM_INSTALL_PROGRAM_FLAGS)
+INSTALL_DATA = @INSTALL_DATA@
+INSTALL_SCRIPT = @INSTALL_SCRIPT@
+transform = @program_transform_name@
+
+NORMAL_INSTALL = :
+PRE_INSTALL = :
+POST_INSTALL = :
+NORMAL_UNINSTALL = :
+PRE_UNINSTALL = :
+POST_UNINSTALL = :
+ASNMODULE = @ASNMODULE@
+CC = @CC@
+CPP = @CPP@
+ILLLIB = @ILLLIB@
+ILLMODULE = @ILLMODULE@
+MAKEINFO = @MAKEINFO@
+PACKAGE = @PACKAGE@
+RANLIB = @RANLIB@
+SUBDIRS_VAR = @SUBDIRS_VAR@
+VERSION = @VERSION@
+have_sgml2html = @have_sgml2html@
+have_sgml2latex = @have_sgml2latex@
+have_sgml2txt = @have_sgml2txt@
+
+noinst_LIBRARIES = libodr.a
+
+INCLUDES = -I../include
+
+libodr_a_SOURCES = odr_bool.c ber_bool.c ber_len.c ber_tag.c odr_util.c         odr_null.c ber_null.c odr_int.c ber_int.c odr_tag.c odr_cons.c         odr_seq.c odr_oct.c ber_oct.c odr_bit.c ber_bit.c odr_oid.c         ber_oid.c odr_use.c odr_choice.c odr_any.c ber_any.c odr.c odr_mem.c         dumpber.c odr_enum.c
+
+mkinstalldirs = $(SHELL) $(top_srcdir)/mkinstalldirs
+CONFIG_CLEAN_FILES = 
+LIBRARIES =  $(noinst_LIBRARIES)
+
+
+DEFS = @DEFS@ -I. -I$(srcdir) 
+CPPFLAGS = @CPPFLAGS@
+LDFLAGS = @LDFLAGS@
+LIBS = @LIBS@
+libodr_a_LIBADD = 
+libodr_a_OBJECTS =  odr_bool.o ber_bool.o ber_len.o ber_tag.o odr_util.o \
+odr_null.o ber_null.o odr_int.o ber_int.o odr_tag.o odr_cons.o \
+odr_seq.o odr_oct.o ber_oct.o odr_bit.o ber_bit.o odr_oid.o ber_oid.o \
+odr_use.o odr_choice.o odr_any.o ber_any.o odr.o odr_mem.o dumpber.o \
+odr_enum.o
+AR = ar
+CFLAGS = @CFLAGS@
+COMPILE = $(CC) $(DEFS) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
+CCLD = $(CC)
+LINK = $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(LDFLAGS) -o $@
+DIST_COMMON =  Makefile.am Makefile.in
+
+
+DISTFILES = $(DIST_COMMON) $(SOURCES) $(HEADERS) $(TEXINFOS) $(EXTRA_DIST)
+
+TAR = gtar
+GZIP_ENV = --best
+SOURCES = $(libodr_a_SOURCES)
+OBJECTS = $(libodr_a_OBJECTS)
+
+all: all-redirect
+.SUFFIXES:
+.SUFFIXES: .S .c .o .s
+$(srcdir)/Makefile.in: Makefile.am $(top_srcdir)/configure.in $(ACLOCAL_M4) 
+	cd $(top_srcdir) && $(AUTOMAKE) --gnu --include-deps odr/Makefile
+
+Makefile: $(srcdir)/Makefile.in  $(top_builddir)/config.status
+	cd $(top_builddir) \
+	  && CONFIG_FILES=$(subdir)/$@ CONFIG_HEADERS= $(SHELL) ./config.status
+
+
+mostlyclean-noinstLIBRARIES:
+
+clean-noinstLIBRARIES:
+	-test -z "$(noinst_LIBRARIES)" || rm -f $(noinst_LIBRARIES)
+
+distclean-noinstLIBRARIES:
+
+maintainer-clean-noinstLIBRARIES:
+
+.c.o:
+	$(COMPILE) -c $<
+
+.s.o:
+	$(COMPILE) -c $<
+
+.S.o:
+	$(COMPILE) -c $<
+
+mostlyclean-compile:
+	-rm -f *.o core *.core
+
+clean-compile:
+
+distclean-compile:
+	-rm -f *.tab.c
+
+maintainer-clean-compile:
+
+libodr.a: $(libodr_a_OBJECTS) $(libodr_a_DEPENDENCIES)
+	-rm -f libodr.a
+	$(AR) cru libodr.a $(libodr_a_OBJECTS) $(libodr_a_LIBADD)
+	$(RANLIB) libodr.a
+
+tags: TAGS
+
+ID: $(HEADERS) $(SOURCES) $(LISP)
+	list='$(SOURCES) $(HEADERS)'; \
+	unique=`for i in $$list; do echo $$i; done | \
+	  awk '    { files[$$0] = 1; } \
+	       END { for (i in files) print i; }'`; \
+	here=`pwd` && cd $(srcdir) \
+	  && mkid -f$$here/ID $$unique $(LISP)
+
+TAGS:  $(HEADERS) $(SOURCES)  $(TAGS_DEPENDENCIES) $(LISP)
+	tags=; \
+	here=`pwd`; \
+	list='$(SOURCES) $(HEADERS)'; \
+	unique=`for i in $$list; do echo $$i; done | \
+	  awk '    { files[$$0] = 1; } \
+	       END { for (i in files) print i; }'`; \
+	test -z "$(ETAGS_ARGS)$$unique$(LISP)$$tags" \
+	  || (cd $(srcdir) && etags $(ETAGS_ARGS) $$tags  $$unique $(LISP) -o $$here/TAGS)
+
+mostlyclean-tags:
+
+clean-tags:
+
+distclean-tags:
+	-rm -f TAGS ID
+
+maintainer-clean-tags:
+
+distdir = $(top_builddir)/$(PACKAGE)-$(VERSION)/$(subdir)
+
+subdir = odr
+
+distdir: $(DISTFILES)
+	@for file in $(DISTFILES); do \
+	  d=$(srcdir); \
+	  if test -d $$d/$$file; then \
+	    cp -pr $$/$$file $(distdir)/$$file; \
+	  else \
+	    test -f $(distdir)/$$file \
+	    || ln $$d/$$file $(distdir)/$$file 2> /dev/null \
+	    || cp -p $$d/$$file $(distdir)/$$file || :; \
+	  fi; \
+	done
+
+info-am:
+info: info-am
+dvi-am:
+dvi: dvi-am
+check-am: all-am
+check: check-am
+installcheck-am:
+installcheck: installcheck-am
+install-exec-am:
+install-exec: install-exec-am
+
+install-data-am:
+install-data: install-data-am
+
+install-am: all-am
+	@$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
+install: install-am
+uninstall-am:
+uninstall: uninstall-am
+all-am: Makefile $(LIBRARIES)
+all-redirect: all-am
+install-strip:
+	$(MAKE) $(AM_MAKEFLAGS) AM_INSTALL_PROGRAM_FLAGS=-s install
+installdirs:
+
+
+mostlyclean-generic:
+
+clean-generic:
+
+distclean-generic:
+	-rm -f Makefile $(CONFIG_CLEAN_FILES)
+	-rm -f config.cache config.log stamp-h stamp-h[0-9]*
+
+maintainer-clean-generic:
+mostlyclean-am:  mostlyclean-noinstLIBRARIES mostlyclean-compile \
+		mostlyclean-tags mostlyclean-generic
+
+mostlyclean: mostlyclean-am
+
+clean-am:  clean-noinstLIBRARIES clean-compile clean-tags clean-generic \
+		mostlyclean-am
+
+clean: clean-am
+
+distclean-am:  distclean-noinstLIBRARIES distclean-compile \
+		distclean-tags distclean-generic clean-am
+
+distclean: distclean-am
+
+maintainer-clean-am:  maintainer-clean-noinstLIBRARIES \
+		maintainer-clean-compile maintainer-clean-tags \
+		maintainer-clean-generic distclean-am
+	@echo "This command is intended for maintainers to use;"
+	@echo "it deletes files that may require special tools to rebuild."
+
+maintainer-clean: maintainer-clean-am
+
+.PHONY: mostlyclean-noinstLIBRARIES distclean-noinstLIBRARIES \
+clean-noinstLIBRARIES maintainer-clean-noinstLIBRARIES \
+mostlyclean-compile distclean-compile clean-compile \
+maintainer-clean-compile tags mostlyclean-tags distclean-tags \
+clean-tags maintainer-clean-tags distdir info-am info dvi-am dvi check \
+check-am installcheck-am installcheck install-exec-am install-exec \
+install-data-am install-data install-am install uninstall-am uninstall \
+all-redirect all-am all installdirs mostlyclean-generic \
+distclean-generic clean-generic maintainer-clean-generic clean \
+mostlyclean distclean maintainer-clean
+
+
+# Tell versions [3.59,3.63) of GNU make to not export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:
Index: /main/tags/2.25/gsdl/packages/yaz/odr/ber_any.c
===================================================================
--- /main/tags/2.25/gsdl/packages/yaz/odr/ber_any.c	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/yaz/odr/ber_any.c	(revision 21064)
@@ -0,0 +1,139 @@
+/*
+ * Copyright (c) 1995-2000, Index Data
+ * See the file LICENSE for details.
+ *
+ * $Log$
+ * Revision 1.1  2000/08/03 03:11:12  johnmcp
+ * Added the YAZ toolkit source to the packages directory (for z39.50 stuff)
+ *
+ * Revision 1.18  2000/02/29 13:44:55  adam
+ * Check for config.h (currently not generated).
+ *
+ * Revision 1.17  2000/01/31 13:15:21  adam
+ * Removed uses of assert(3). Cleanup of ODR. CCL parser update so
+ * that some characters are not surrounded by spaces in resulting term.
+ * ILL-code updates.
+ *
+ * Revision 1.16  1999/11/30 13:47:11  adam
+ * Improved installation. Moved header files to include/yaz.
+ *
+ * Revision 1.15  1999/01/08 11:23:20  adam
+ * Added const modifier to some of the BER/ODR encoding routines.
+ *
+ * Revision 1.14  1998/02/11 11:53:34  adam
+ * Changed code so that it compiles as C++.
+ *
+ * Revision 1.13  1997/05/14 06:53:56  adam
+ * C++ support.
+ *
+ * Revision 1.12  1995/09/29 17:12:15  quinn
+ * Smallish
+ *
+ * Revision 1.11  1995/09/27  15:02:54  quinn
+ * Modified function heads & prototypes.
+ *
+ * Revision 1.10  1995/05/16  08:50:42  quinn
+ * License, documentation, and memory fixes
+ *
+ * Revision 1.9  1995/04/18  08:15:12  quinn
+ * Added dynamic memory allocation on encoding (whew). Code is now somewhat
+ * neater. We'll make the same change for decoding one day.
+ *
+ * Revision 1.8  1995/04/17  09:37:42  quinn
+ * *** empty log message ***
+ *
+ * Revision 1.7  1995/03/17  10:17:39  quinn
+ * Added memory management.
+ *
+ * Revision 1.6  1995/03/08  12:12:02  quinn
+ * Added better error checking.
+ *
+ * Revision 1.5  1995/02/14  20:39:54  quinn
+ * Fixed bugs in completeBER and (serious one in) ber_oid.
+ *
+ * Revision 1.4  1995/02/14  11:54:33  quinn
+ * Adjustments.
+ *
+ * Revision 1.3  1995/02/10  18:57:24  quinn
+ * More in the way of error-checking.
+ *
+ * Revision 1.2  1995/02/10  15:55:28  quinn
+ * Bug fixes, mostly.
+ *
+ * Revision 1.1  1995/02/09  15:51:45  quinn
+ * Works better now.
+ *
+ */
+#if HAVE_CONFIG_H
+#include <config.h>
+#endif
+#include <yaz/odr.h>
+
+int ber_any(ODR o, Odr_any **p)
+{
+    int res;
+    int left = o->size - (o->bp - o->buf);
+
+    switch (o->direction)
+    {
+    	case ODR_DECODE:
+	    if ((res = completeBER(o->bp, left)) <= 0)        /* FIX THIS */
+	    {
+	    	o->error = OPROTO;
+	    	return 0;
+	    }
+	    (*p)->buf = (unsigned char *)odr_malloc(o, res);
+	    memcpy((*p)->buf, o->bp, res);
+	    (*p)->len = (*p)->size = res;
+	    o->bp += res;
+	    return 1;
+    	case ODR_ENCODE:
+	    if (odr_write(o, (*p)->buf, (*p)->len) < 0)
+	    	return 0;
+	    return 1;
+    	default: o->error = OOTHER; return 0;
+    }
+}
+
+/*
+ * Return length of BER-package or 0.
+ */
+int completeBER(const unsigned char *buf, int len)
+{
+    int res, ll, zclass, tag, cons;
+    const unsigned char *b = buf;
+    
+    if (!len)
+    	return 0;
+    if (!buf[0] && !buf[1])
+    	return 0;
+    if ((res = ber_dectag(b, &zclass, &tag, &cons)) <= 0)
+    	return 0;
+    if (res > len)
+    	return 0;
+    b += res;
+    len -= res;
+    if ((res = ber_declen(b, &ll)) <= 0)
+    	return 0;
+    if (res > len)
+    	return 0;
+    b += res;
+    len -= res;
+    if (ll >= 0)
+    	return (len >= ll ? ll + (b-buf) : 0);
+    if (!cons)
+    	return 0;    
+    /* constructed - cycle through children */
+    while (len >= 2)
+    {
+	if (*b == 0 && *(b + 1) == 0)
+	    break;
+	if (!(res = completeBER(b, len)))
+	    return 0;
+	b += res;
+	len -= res;
+    }
+    if (len < 2)
+    	return 0;
+    return (b - buf) + 2;
+}
Index: /main/tags/2.25/gsdl/packages/yaz/odr/ber_bit.c
===================================================================
--- /main/tags/2.25/gsdl/packages/yaz/odr/ber_bit.c	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/yaz/odr/ber_bit.c	(revision 21064)
@@ -0,0 +1,112 @@
+/*
+ * Copyright (c) 1995-2000, Index Data
+ * See the file LICENSE for details.
+ * Sebastian Hammer, Adam Dickmeiss
+ *
+ * $Log$
+ * Revision 1.1  2000/08/03 03:11:12  johnmcp
+ * Added the YAZ toolkit source to the packages directory (for z39.50 stuff)
+ *
+ * Revision 1.12  2000/02/29 13:44:55  adam
+ * Check for config.h (currently not generated).
+ *
+ * Revision 1.11  2000/01/31 13:15:21  adam
+ * Removed uses of assert(3). Cleanup of ODR. CCL parser update so
+ * that some characters are not surrounded by spaces in resulting term.
+ * ILL-code updates.
+ *
+ * Revision 1.10  1999/11/30 13:47:11  adam
+ * Improved installation. Moved header files to include/yaz.
+ *
+ * Revision 1.9  1999/04/20 09:56:48  adam
+ * Added 'name' paramter to encoder/decoder routines (typedef Odr_fun).
+ * Modified all encoders/decoders to reflect this change.
+ *
+ * Revision 1.8  1999/01/08 11:23:21  adam
+ * Added const modifier to some of the BER/ODR encoding routines.
+ *
+ * Revision 1.7  1995/09/29 17:12:16  quinn
+ * Smallish
+ *
+ * Revision 1.6  1995/09/27  15:02:54  quinn
+ * Modified function heads & prototypes.
+ *
+ * Revision 1.5  1995/05/16  08:50:43  quinn
+ * License, documentation, and memory fixes
+ *
+ * Revision 1.4  1995/04/18  08:15:13  quinn
+ * Added dynamic memory allocation on encoding (whew). Code is now somewhat
+ * neater. We'll make the same change for decoding one day.
+ *
+ * Revision 1.3  1995/03/08  12:12:04  quinn
+ * Added better error checking.
+ *
+ * Revision 1.2  1995/02/03  17:04:31  quinn
+ * *** empty log message ***
+ *
+ * Revision 1.1  1995/02/02  20:38:49  quinn
+ * Updates.
+ *
+ *
+ */
+#if HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <yaz/odr.h>
+
+int ber_bitstring(ODR o, Odr_bitmask *p, int cons)
+{
+    int res, len;
+    const unsigned char *base;
+
+    switch (o->direction)
+    {
+    	case ODR_DECODE:
+	    if ((res = ber_declen(o->bp, &len)) < 0)
+	    {
+	    	o->error = OPROTO;
+	    	return 0;
+	    }
+	    o->bp += res;
+	    if (cons)       /* fetch component strings */
+	    {
+	    	base = o->bp;
+	    	while (odp_more_chunks(o, base, len))
+		    if (!odr_bitstring(o, &p, 0, 0))
+		    	return 0;
+		return 1;
+	    }
+	    /* primitive bitstring */
+	    if (len < 0)
+	    {
+	    	o->error = OOTHER;
+	    	return 0;
+	    }
+	    if (len == 0)
+	    	return 1;
+	    if (len - 1 > ODR_BITMASK_SIZE)
+	    {
+	    	o->error = OOTHER;
+	    	return 0;
+	    }
+	    o->bp++;      /* silently ignore the unused-bits field */
+	    len--;
+	    memcpy(p->bits + p->top + 1, o->bp, len);
+	    p->top += len;
+	    o->bp += len;
+	    return 1;
+    	case ODR_ENCODE:
+	    if ((res = ber_enclen(o, p->top + 2, 5, 0)) < 0)
+	    	return 0;
+	    if (odr_putc(o, 0) < 0)    /* no unused bits here */
+	    	return 0;
+	    if (p->top < 0)
+	    	return 1;
+	    if (odr_write(o, p->bits, p->top + 1) < 0)
+	    	return 0;
+	    return 1;
+    	case ODR_PRINT: return 1;
+    	default: o->error = OOTHER; return 0;
+    }
+}
Index: /main/tags/2.25/gsdl/packages/yaz/odr/ber_bool.c
===================================================================
--- /main/tags/2.25/gsdl/packages/yaz/odr/ber_bool.c	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/yaz/odr/ber_bool.c	(revision 21064)
@@ -0,0 +1,92 @@
+/*
+ * Copyright (c) 1995-2000, Index Data
+ * See the file LICENSE for details.
+ * Sebastian Hammer, Adam Dickmeiss
+ *
+ * $Log$
+ * Revision 1.1  2000/08/03 03:11:13  johnmcp
+ * Added the YAZ toolkit source to the packages directory (for z39.50 stuff)
+ *
+ * Revision 1.11  2000/02/29 13:44:55  adam
+ * Check for config.h (currently not generated).
+ *
+ * Revision 1.10  2000/01/31 13:15:21  adam
+ * Removed uses of assert(3). Cleanup of ODR. CCL parser update so
+ * that some characters are not surrounded by spaces in resulting term.
+ * ILL-code updates.
+ *
+ * Revision 1.9  1999/11/30 13:47:11  adam
+ * Improved installation. Moved header files to include/yaz.
+ *
+ * Revision 1.8  1995/09/29 17:12:16  quinn
+ * Smallish
+ *
+ * Revision 1.7  1995/09/27  15:02:55  quinn
+ * Modified function heads & prototypes.
+ *
+ * Revision 1.6  1995/05/16  08:50:43  quinn
+ * License, documentation, and memory fixes
+ *
+ * Revision 1.5  1995/04/18  08:15:14  quinn
+ * Added dynamic memory allocation on encoding (whew). Code is now somewhat
+ * neater. We'll make the same change for decoding one day.
+ *
+ * Revision 1.4  1995/03/21  10:17:27  quinn
+ * Fixed little bug in decoder.
+ *
+ * Revision 1.3  1995/03/08  12:12:06  quinn
+ * Added better error checking.
+ *
+ * Revision 1.2  1995/02/09  15:51:45  quinn
+ * Works better now.
+ *
+ * Revision 1.1  1995/02/02  16:21:51  quinn
+ * First kick.
+ *
+ */
+
+#if HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <stdio.h>
+#include <yaz/odr.h>
+
+int ber_boolean(ODR o, int *val)
+{
+    int res, len;
+
+    switch (o->direction)
+    {
+    	case ODR_ENCODE:
+	    if (ber_enclen(o, 1, 1, 1) != 1)
+	    	return 0;
+	    if (odr_putc(o, *val) < 0)
+	    	return 0;
+#ifdef ODR_DEBUG
+	    fprintf(stderr, "[val=%d]\n", *val);
+#endif
+	    return 1;
+	case ODR_DECODE:
+	    if ((res = ber_declen(o->bp, &len)) < 0)
+	    {
+	    	o->error = OPROTO;
+		return 0;
+	    }
+	    if (len != 1)
+	    {
+	    	o->error = OPROTO;
+		return 0;
+	    }
+	    o->bp+= res;
+	    *val = *o->bp;
+	    o->bp++;
+#ifdef ODR_DEBUG
+	    fprintf(stderr, "[val=%d]\n", *val);
+#endif
+	    return 1;
+	case ODR_PRINT:
+	    return 1;
+	default: o->error = OOTHER; return 0;
+    }
+}
Index: /main/tags/2.25/gsdl/packages/yaz/odr/ber_int.c
===================================================================
--- /main/tags/2.25/gsdl/packages/yaz/odr/ber_int.c	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/yaz/odr/ber_int.c	(revision 21064)
@@ -0,0 +1,168 @@
+/*
+ * Copyright (c) 1995-2000, Index Data
+ * See the file LICENSE for details.
+ * Sebastian Hammer, Adam Dickmeiss
+ *
+ * $Log$
+ * Revision 1.1  2000/08/03 03:11:13  johnmcp
+ * Added the YAZ toolkit source to the packages directory (for z39.50 stuff)
+ *
+ * Revision 1.18  2000/02/29 13:44:55  adam
+ * Check for config.h (currently not generated).
+ *
+ * Revision 1.17  2000/02/28 11:20:06  adam
+ * Using autoconf. New definitions: YAZ_BEGIN_CDECL/YAZ_END_CDECL.
+ *
+ * Revision 1.16  2000/01/31 13:15:21  adam
+ * Removed uses of assert(3). Cleanup of ODR. CCL parser update so
+ * that some characters are not surrounded by spaces in resulting term.
+ * ILL-code updates.
+ *
+ * Revision 1.15  1999/11/30 13:47:11  adam
+ * Improved installation. Moved header files to include/yaz.
+ *
+ * Revision 1.14  1999/05/26 07:49:35  adam
+ * C++ compilation.
+ *
+ * Revision 1.13  1999/01/08 11:23:22  adam
+ * Added const modifier to some of the BER/ODR encoding routines.
+ *
+ * Revision 1.12  1996/07/06 19:58:33  quinn
+ * System headerfiles gathered in yconfig
+ *
+ * Revision 1.11  1995/09/29  17:12:16  quinn
+ * Smallish
+ *
+ * Revision 1.10  1995/09/29  17:01:50  quinn
+ * More Windows work
+ *
+ * Revision 1.9  1995/09/28  10:12:39  quinn
+ * Windows-support changes
+ *
+ * Revision 1.8  1995/09/27  15:02:55  quinn
+ * Modified function heads & prototypes.
+ *
+ * Revision 1.7  1995/05/16  08:50:44  quinn
+ * License, documentation, and memory fixes
+ *
+ * Revision 1.6  1995/04/18  08:15:14  quinn
+ * Added dynamic memory allocation on encoding (whew). Code is now somewhat
+ * neater. We'll make the same change for decoding one day.
+ *
+ * Revision 1.5  1995/03/27  15:01:44  quinn
+ * Added include of sys/types to further portability
+ *
+ * Revision 1.4  1995/03/08  12:12:07  quinn
+ * Added better error checking.
+ *
+ * Revision 1.3  1995/02/09  15:51:46  quinn
+ * Works better now.
+ *
+ * Revision 1.2  1995/02/07  17:52:58  quinn
+ * A damn mess, but now things work, I think.
+ *
+ * Revision 1.1  1995/02/02  16:21:52  quinn
+ * First kick.
+ *
+ */
+#if HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <string.h>
+
+#ifdef WIN32
+#include <winsock.h>
+#else
+#include <arpa/inet.h>
+#endif
+
+#include <yaz/odr.h>
+
+static int ber_encinteger(ODR o, int val);
+static int ber_decinteger(const unsigned char *buf, int *val);
+
+int ber_integer(ODR o, int *val)
+{
+    int res;
+
+    switch (o->direction)
+    {
+        case ODR_DECODE:
+            if ((res = ber_decinteger(o->bp, val)) <= 0)
+            {
+                o->error = OPROTO;
+                return 0;
+            }
+            o->bp += res;
+            return 1;
+        case ODR_ENCODE:
+            if ((res = ber_encinteger(o, *val)) < 0)
+                return 0;
+            return 1;
+        case ODR_PRINT: return 1;
+        default: o->error = OOTHER;  return 0;
+    }
+}
+
+/*
+ * Returns: number of bytes written or -1 for error (out of bounds).
+ */
+int ber_encinteger(ODR o, int val)
+{
+    int lenpos;
+    int a, len;
+    union { int i; unsigned char c[sizeof(int)]; } tmp;
+
+    lenpos = odr_tell(o);
+    if (odr_putc(o, 0) < 0)  /* dummy */
+        return -1;
+    tmp.i = htonl(val);   /* ensure that that we're big-endian */
+    for (a = 0; a < (int) sizeof(int) - 1; a++)  /* skip superfluous octets */
+        if (!((tmp.c[a] == 0 && !(tmp.c[a+1] & 0X80)) ||
+            (tmp.c[a] == 0XFF && (tmp.c[a+1] & 0X80))))
+            break;
+    len = sizeof(int) - a;
+    if (odr_write(o, (unsigned char*) tmp.c + a, len) < 0)
+        return -1;
+    odr_seek(o, ODR_S_SET, lenpos);
+    if (ber_enclen(o, len, 1, 1) != 1)
+        return -1;
+    odr_seek(o, ODR_S_END, 0);
+#ifdef ODR_DEBUG
+    fprintf(stderr, "[val=%d]", val);
+#endif
+    return 0;
+}
+
+/*
+ * Returns: Number of bytes read or 0 if no match, -1 if error.
+ */
+int ber_decinteger(const unsigned char *buf, int *val)
+{
+    const unsigned char *b = buf;
+    unsigned char fill;
+    int res, len, remains;
+    union { int i; unsigned char c[sizeof(int)]; } tmp;
+
+    if ((res = ber_declen(b, &len)) < 0)
+        return -1;
+    if (len > (int) sizeof(int))    /* let's be reasonable, here */
+        return -1;
+    b+= res;
+
+    remains = sizeof(int) - len;
+    memcpy(tmp.c + remains, b, len);
+    if (*b & 0X80)
+        fill = 0XFF;
+    else
+        fill = 0X00;
+    memset(tmp.c, fill, remains);
+    *val = ntohl(tmp.i);
+
+    b += len;
+#ifdef ODR_DEBUG
+    fprintf(stderr, "[val=%d]", *val);
+#endif
+    return b - buf;
+}
Index: /main/tags/2.25/gsdl/packages/yaz/odr/ber_len.c
===================================================================
--- /main/tags/2.25/gsdl/packages/yaz/odr/ber_len.c	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/yaz/odr/ber_len.c	(revision 21064)
@@ -0,0 +1,145 @@
+/*
+ * Copyright (C) 1995-2000, Index Data.
+ * See the file LICENSE for details.
+ * Sebastian Hammer, Adam Dickmeiss
+ *
+ * $Log$
+ * Revision 1.1  2000/08/03 03:11:14  johnmcp
+ * Added the YAZ toolkit source to the packages directory (for z39.50 stuff)
+ *
+ * Revision 1.9  2000/02/29 13:44:55  adam
+ * Check for config.h (currently not generated).
+ *
+ * Revision 1.8  1999/11/30 13:47:11  adam
+ * Improved installation. Moved header files to include/yaz.
+ *
+ * Revision 1.7  1999/01/08 11:23:23  adam
+ * Added const modifier to some of the BER/ODR encoding routines.
+ *
+ * Revision 1.6  1995/09/29 17:12:17  quinn
+ * Smallish
+ *
+ * Revision 1.5  1995/09/27  15:02:55  quinn
+ * Modified function heads & prototypes.
+ *
+ * Revision 1.4  1995/05/16  08:50:45  quinn
+ * License, documentation, and memory fixes
+ *
+ *
+ */
+#if HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <stdio.h>
+#include <yaz/odr.h>
+
+/*
+ * Encode BER length octets. If exact, lenlen is the exact desired
+ * encoding size, else, lenlen is the max available space. Len < 0 =
+ * Indefinite encoding.
+ * Returns: >0   success, number of bytes encoded.
+ * Returns: =0   success, indefinite start-marker set. 1 byte encoded.
+ * Returns: -1   failure, out of bounds.
+ */
+int ber_enclen(ODR o, int len, int lenlen, int exact)
+{
+    unsigned char octs[sizeof(int)];
+    int n = 0;
+    int lenpos, end;
+
+#ifdef ODR_DEBUG
+    fprintf(stderr, "[len=%d]", len);
+#endif
+    if (len < 0)      /* Indefinite */
+    {
+    	if (odr_putc(o, 0x80) < 0)
+	    return 0;
+#ifdef ODR_DEBUG
+	fprintf(stderr, "[indefinite]");
+#endif
+	return 0;
+    }
+    if (len <= 127 && (lenlen == 1 || !exact)) /* definite short form */
+    {
+    	if (odr_putc(o, (unsigned char) len) < 0)
+	    return 0;
+    	return 1;
+    }
+    if (lenlen == 1)
+    {
+    	if (odr_putc(o, 0x80) < 0)
+	    return 0;
+    	return 0;
+    }
+    /* definite long form */
+    do
+    {
+    	octs[n++] = len;
+    	len >>= 8;
+    }
+    while (len);
+    if (n >= lenlen)
+    	return -1;
+    lenpos = odr_tell(o); /* remember length-of-length position */
+    if (odr_putc(o, 0) < 0)  /* dummy */
+    	return 0;
+    if (exact)
+    	while (n < --lenlen)        /* pad length octets */
+	    if (odr_putc(o, 0) < 0)
+	    	return 0;
+    while (n--)
+    	if (odr_putc(o, octs[n]) < 0)
+	    return 0;
+    /* set length of length */
+    end = odr_tell(o);
+    odr_seek(o, ODR_S_SET, lenpos);
+    if (odr_putc(o, (end - lenpos - 1) | 0X80) < 0)
+    	return 0;
+    odr_seek(o, ODR_S_END, 0);
+    return odr_tell(o) - lenpos;
+}
+
+/*
+ * Decode BER length octets. Returns number of bytes read or -1 for error.
+ * After return:
+ * len = -1   indefinite.
+ * len >= 0    Length.
+ */
+int ber_declen(const unsigned char *buf, int *len)
+{
+    const unsigned char *b = buf;
+    int n;
+
+    if (*b == 0X80)     /* Indefinite */
+    {
+    	*len = -1;
+#ifdef ODR_DEBUG
+	fprintf(stderr, "[len=%d]", *len);
+#endif
+    	return 1;
+    }
+    if (!(*b & 0X80))   /* Definite short form */
+    {
+    	*len = (int) *b;
+#ifdef ODR_DEBUG
+	fprintf(stderr, "[len=%d]", *len);
+#endif
+    	return 1;
+    }
+    if (*b == 0XFF)     /* reserved value */
+	return -1;
+    /* indefinite long form */ 
+    n = *b & 0X7F;
+    *len = 0;
+    b++;
+    while (n--)
+    {
+    	*len <<= 8;
+    	*len |= *(b++);
+    }
+#ifdef ODR_DEBUG
+    fprintf(stderr, "[len=%d]", *len);
+#endif
+    return (b - buf);
+}
Index: /main/tags/2.25/gsdl/packages/yaz/odr/ber_null.c
===================================================================
--- /main/tags/2.25/gsdl/packages/yaz/odr/ber_null.c	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/yaz/odr/ber_null.c	(revision 21064)
@@ -0,0 +1,80 @@
+/*
+ * Copyright (c) 1995-2000, Index Data
+ * See the file LICENSE for details.
+ * Sebastian Hammer, Adam Dickmeiss
+ *
+ * $Log$
+ * Revision 1.1  2000/08/03 03:11:15  johnmcp
+ * Added the YAZ toolkit source to the packages directory (for z39.50 stuff)
+ *
+ * Revision 1.11  2000/02/29 13:44:55  adam
+ * Check for config.h (currently not generated).
+ *
+ * Revision 1.10  2000/01/31 13:15:21  adam
+ * Removed uses of assert(3). Cleanup of ODR. CCL parser update so
+ * that some characters are not surrounded by spaces in resulting term.
+ * ILL-code updates.
+ *
+ * Revision 1.9  1999/11/30 13:47:11  adam
+ * Improved installation. Moved header files to include/yaz.
+ *
+ * Revision 1.8  1995/09/29 17:12:18  quinn
+ * Smallish
+ *
+ * Revision 1.7  1995/09/27  15:02:55  quinn
+ * Modified function heads & prototypes.
+ *
+ * Revision 1.6  1995/05/22  11:32:01  quinn
+ * Fixing Interface to odr_null.
+ *
+ * Revision 1.5  1995/05/16  08:50:46  quinn
+ * License, documentation, and memory fixes
+ *
+ * Revision 1.4  1995/04/18  08:15:16  quinn
+ * Added dynamic memory allocation on encoding (whew). Code is now somewhat
+ * neater. We'll make the same change for decoding one day.
+ *
+ * Revision 1.3  1995/03/08  12:12:09  quinn
+ * Added better error checking.
+ *
+ * Revision 1.2  1995/02/09  15:51:46  quinn
+ * Works better now.
+ *
+ * Revision 1.1  1995/02/02  16:21:52  quinn
+ * First kick.
+ *
+ */
+#if HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <yaz/odr.h>
+
+/*
+ * BER-en/decoder for NULL type.
+ */
+int ber_null(ODR o)
+{
+    switch (o->direction)
+    {
+    	case ODR_ENCODE:
+	    if (odr_putc(o, 0X00) < 0)
+	    	return 0;
+#ifdef ODR_DEBUG
+	    fprintf(stderr, "[NULL]\n");
+#endif
+	    return 1;
+	case ODR_DECODE:
+	    if (*(o->bp++) != 0X00)
+	    {
+	    	o->error = OPROTO;
+	    	return 0;
+	    }
+#ifdef ODR_DEBUG
+	    fprintf(stderr, "[NULL]\n");
+#endif
+	    return 1;
+	case ODR_PRINT: return 1;
+	default: o->error = OOTHER; return 0;
+    }
+}
Index: /main/tags/2.25/gsdl/packages/yaz/odr/ber_oct.c
===================================================================
--- /main/tags/2.25/gsdl/packages/yaz/odr/ber_oct.c	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/yaz/odr/ber_oct.c	(revision 21064)
@@ -0,0 +1,121 @@
+/*
+ * Copyright (c) 1995-2000, Index Data
+ * See the file LICENSE for details.
+ * Sebastian Hammer, Adam Dickmeiss
+ *
+ * $Log$
+ * Revision 1.1  2000/08/03 03:11:15  johnmcp
+ * Added the YAZ toolkit source to the packages directory (for z39.50 stuff)
+ *
+ * Revision 1.16  2000/02/29 13:44:55  adam
+ * Check for config.h (currently not generated).
+ *
+ * Revision 1.15  2000/01/31 13:15:21  adam
+ * Removed uses of assert(3). Cleanup of ODR. CCL parser update so
+ * that some characters are not surrounded by spaces in resulting term.
+ * ILL-code updates.
+ *
+ * Revision 1.14  1999/11/30 13:47:11  adam
+ * Improved installation. Moved header files to include/yaz.
+ *
+ * Revision 1.13  1999/04/20 09:56:48  adam
+ * Added 'name' paramter to encoder/decoder routines (typedef Odr_fun).
+ * Modified all encoders/decoders to reflect this change.
+ *
+ * Revision 1.12  1999/01/08 11:23:24  adam
+ * Added const modifier to some of the BER/ODR encoding routines.
+ *
+ * Revision 1.11  1998/02/11 11:53:34  adam
+ * Changed code so that it compiles as C++.
+ *
+ * Revision 1.10  1995/09/29 17:12:18  quinn
+ * Smallish
+ *
+ * Revision 1.9  1995/09/27  15:02:55  quinn
+ * Modified function heads & prototypes.
+ *
+ * Revision 1.8  1995/05/16  08:50:47  quinn
+ * License, documentation, and memory fixes
+ *
+ * Revision 1.7  1995/04/18  08:15:17  quinn
+ * Added dynamic memory allocation on encoding (whew). Code is now somewhat
+ * neater. We'll make the same change for decoding one day.
+ *
+ * Revision 1.6  1995/03/17  10:17:41  quinn
+ * Added memory management.
+ *
+ * Revision 1.5  1995/03/08  12:12:10  quinn
+ * Added better error checking.
+ *
+ * Revision 1.4  1995/02/10  15:55:28  quinn
+ * Bug fixes, mostly.
+ *
+ * Revision 1.3  1995/02/03  17:04:34  quinn
+ * *** empty log message ***
+ *
+ * Revision 1.2  1995/02/02  20:38:50  quinn
+ * Updates.
+ *
+ * Revision 1.1  1995/02/02  16:21:52  quinn
+ * First kick.
+ *
+ */
+#if HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <yaz/odr.h>
+
+int ber_octetstring(ODR o, Odr_oct *p, int cons)
+{
+    int res, len;
+    const unsigned char *base;
+    unsigned char *c;
+
+    switch (o->direction)
+    {
+    	case ODR_DECODE:
+	    if ((res = ber_declen(o->bp, &len)) < 0)
+	    {
+	    	o->error = OPROTO;
+	    	return 0;
+	    }
+	    o->bp += res;
+	    if (cons)       /* fetch component strings */
+	    {
+	    	base = o->bp;
+	    	while (odp_more_chunks(o, base, len))
+		    if (!odr_octetstring(o, &p, 0, 0))
+		    	return 0;
+		return 1;
+	    }
+	    /* primitive octetstring */
+	    if (len < 0)
+	    {
+	    	o->error = OOTHER;
+	    	return 0;
+	    }
+	    if (len + 1 > p->size - p->len)
+	    {
+	    	c = (unsigned char *)odr_malloc(o, p->size += len + 1);
+	    	if (p->len)
+		    memcpy(c, p->buf, p->len);
+		p->buf = c;
+	    }
+	    if (len)
+		memcpy(p->buf + p->len, o->bp, len);
+	    p->len += len;
+	    o->bp += len;
+	    return 1;
+    	case ODR_ENCODE:
+	    if ((res = ber_enclen(o, p->len, 5, 0)) < 0)
+	    	return 0;
+	    if (p->len == 0)
+	    	return 1;
+	    if (odr_write(o, p->buf, p->len) < 0)
+	    	return 0;
+	    return 1;
+    	case ODR_PRINT: return 1;
+    	default: o->error = OOTHER; return 0;
+    }
+}
Index: /main/tags/2.25/gsdl/packages/yaz/odr/ber_oid.c
===================================================================
--- /main/tags/2.25/gsdl/packages/yaz/odr/ber_oid.c	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/yaz/odr/ber_oid.c	(revision 21064)
@@ -0,0 +1,148 @@
+/*
+ * Copyright (c) 1995-2000, Index Data
+ * See the file LICENSE for details.
+ * Sebastian Hammer, Adam Dickmeiss
+ *
+ * $Log$
+ * Revision 1.1  2000/08/03 03:11:16  johnmcp
+ * Added the YAZ toolkit source to the packages directory (for z39.50 stuff)
+ *
+ * Revision 1.12  2000/02/29 13:44:55  adam
+ * Check for config.h (currently not generated).
+ *
+ * Revision 1.11  2000/01/31 13:15:21  adam
+ * Removed uses of assert(3). Cleanup of ODR. CCL parser update so
+ * that some characters are not surrounded by spaces in resulting term.
+ * ILL-code updates.
+ *
+ * Revision 1.10  1999/11/30 13:47:11  adam
+ * Improved installation. Moved header files to include/yaz.
+ *
+ * Revision 1.9  1995/09/29 17:12:19  quinn
+ * Smallish
+ *
+ * Revision 1.8  1995/09/27  15:02:56  quinn
+ * Modified function heads & prototypes.
+ *
+ * Revision 1.7  1995/05/16  08:50:47  quinn
+ * License, documentation, and memory fixes
+ *
+ * Revision 1.6  1995/04/18  08:15:18  quinn
+ * Added dynamic memory allocation on encoding (whew). Code is now somewhat
+ * neater. We'll make the same change for decoding one day.
+ *
+ * Revision 1.5  1995/03/20  12:18:22  quinn
+ * Fixed bug in ber_oid
+ *
+ * Revision 1.4  1995/03/08  12:12:11  quinn
+ * Added better error checking.
+ *
+ * Revision 1.3  1995/03/01  08:40:56  quinn
+ * Smallish changes.
+ *
+ * Revision 1.2  1995/02/14  20:39:55  quinn
+ * Fixed bugs in completeBER and (serious one in) ber_oid.
+ *
+ * Revision 1.1  1995/02/03  17:04:36  quinn
+ * Initial revision
+ *
+ */
+#if HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <yaz/odr.h>
+
+int ber_oidc(ODR o, Odr_oid *p)
+{
+    int len, lenp, end;
+    int pos, n, res, id;
+    unsigned char octs[8];
+
+    switch (o->direction)
+    {
+	case ODR_DECODE:
+	    if ((res = ber_declen(o->bp, &len)) < 1)
+	    {
+	    	o->error = OPROTO;
+	    	return 0;
+	    }
+	    if (len < 0)
+	    {
+	    	o->error = OPROTO;
+	    	return 0;
+	    }
+	    o->bp += res;
+	    if (len == 0)
+	    {
+	    	*p = -1;
+	    	return 1;
+	    }
+	    p[0] = *o->bp / 40;
+	    if (p[0] > 2)
+	    	p[0] = 2;
+	    p[1] = *o->bp - p[0] * 40;
+	    o->bp++;
+	    pos = 2;
+	    len--;
+	    while (len)
+	    {
+	    	p[pos] = 0;
+	    	do
+	    	{
+		    if (!len)
+		    {
+		    	o->error = OPROTO;
+		    	return 0;
+		    }
+		    p[pos] <<= 7;
+		    p[pos] |= *o->bp & 0X7F;
+		    len--;
+		}
+		while (*(o->bp++) & 0X80);
+		pos++;
+	    }
+	    p[pos] = -1;
+	    return 1;
+    	case ODR_ENCODE:
+	    /* we'll allow ourselves the quiet luxury of only doing encodings
+    	       shorter than 127 */
+            lenp = odr_tell(o);
+	    if (odr_putc(o, 0) < 0)   /* dummy */
+	    	return 0;
+            if (p[0] < 0 && p[1] <= 0)
+	    {
+	    	o->error = ODATA;
+            	return 0;
+	    }
+	    for (pos = 1; p[pos] >= 0; pos++)
+	    {
+	    	id = pos > 1 ? p[pos] : p[0] * 40 + p[1];
+	    	n = 0;
+	    	do
+	    	{
+		    octs[n++] = id & 0X7F;
+		    id >>= 7;
+		}
+		while (id);
+		while (n--)
+		{
+		    unsigned char p;
+
+		    p = octs[n] | ((n > 0) << 7);
+		    if (odr_putc(o, p) < 0)
+		    	return 0;
+		}
+	    }
+	    end = odr_tell(o);
+	    odr_seek(o, ODR_S_SET, lenp);
+	    if (ber_enclen(o, (end - lenp) - 1, 1, 1) != 1)
+	    {
+	    	o->error = OOTHER;
+	    	return 0;
+	    }
+	    odr_seek(o, ODR_S_END, 0);
+	    return 1;
+    	default: o->error = OOTHER; return 0;
+    }
+}
Index: /main/tags/2.25/gsdl/packages/yaz/odr/ber_tag.c
===================================================================
--- /main/tags/2.25/gsdl/packages/yaz/odr/ber_tag.c	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/yaz/odr/ber_tag.c	(revision 21064)
@@ -0,0 +1,240 @@
+/*
+ * Copyright (c) 1995-2000, Index Data
+ * See the file LICENSE for details.
+ * Sebastian Hammer, Adam Dickmeiss
+ *
+ * $Log$
+ * Revision 1.1  2000/08/03 03:11:16  johnmcp
+ * Added the YAZ toolkit source to the packages directory (for z39.50 stuff)
+ *
+ * Revision 1.22  2000/02/29 13:44:55  adam
+ * Check for config.h (currently not generated).
+ *
+ * Revision 1.21  2000/01/31 13:15:21  adam
+ * Removed uses of assert(3). Cleanup of ODR. CCL parser update so
+ * that some characters are not surrounded by spaces in resulting term.
+ * ILL-code updates.
+ *
+ * Revision 1.20  1999/11/30 13:47:11  adam
+ * Improved installation. Moved header files to include/yaz.
+ *
+ * Revision 1.19  1999/01/08 11:23:25  adam
+ * Added const modifier to some of the BER/ODR encoding routines.
+ *
+ * Revision 1.18  1998/02/11 11:53:34  adam
+ * Changed code so that it compiles as C++.
+ *
+ * Revision 1.17  1997/09/30 09:33:10  adam
+ * Minor changes - removed indentation of ifdef.
+ *
+ * Revision 1.16  1997/09/17 12:10:33  adam
+ * YAZ version 1.4.
+ *
+ * Revision 1.15  1997/09/01 08:51:06  adam
+ * New windows NT/95 port using MSV5.0. Had to avoid a few static
+ * variables used in function ber_tag. These are now part of the
+ * ODR structure.
+ *
+ * Revision 1.14  1997/05/14 06:53:56  adam
+ * C++ support.
+ *
+ * Revision 1.13  1995/09/29 17:12:21  quinn
+ * Smallish
+ *
+ * Revision 1.12  1995/09/27  15:02:57  quinn
+ * Modified function heads & prototypes.
+ *
+ * Revision 1.11  1995/05/16  08:50:48  quinn
+ * License, documentation, and memory fixes
+ *
+ * Revision 1.10  1995/04/18  08:15:18  quinn
+ * Added dynamic memory allocation on encoding (whew). Code is now somewhat
+ * neater. We'll make the same change for decoding one day.
+ *
+ * Revision 1.9  1995/03/15  08:37:18  quinn
+ * Fixed protocol bugs.
+ *
+ * Revision 1.8  1995/03/10  11:44:40  quinn
+ * Fixed serious stack-bug in odr_cons_begin
+ *
+ * Revision 1.7  1995/03/08  12:12:13  quinn
+ * Added better error checking.
+ *
+ * Revision 1.6  1995/02/14  11:54:33  quinn
+ * Adjustments.
+ *
+ * Revision 1.5  1995/02/10  18:57:24  quinn
+ * More in the way of error-checking.
+ *
+ * Revision 1.4  1995/02/10  15:55:28  quinn
+ * Bug fixes, mostly.
+ *
+ * Revision 1.3  1995/02/09  15:51:46  quinn
+ * Works better now.
+ *
+ * Revision 1.2  1995/02/07  17:52:59  quinn
+ * A damn mess, but now things work, I think.
+ *
+ * Revision 1.1  1995/02/02  16:21:53  quinn
+ * First kick.
+ *
+ */
+#if HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <stdio.h>
+#include <yaz/odr.h>
+
+/* ber_tag
+ * On encoding:
+ *	if  p: write tag. return 1 (success) or -1 (error).
+ *	if !p: return 0.
+ * On decoding:
+ *      if tag && zclass match up, advance pointer and return 1. set cons.
+ *      else leave pointer unchanged. Return 0.
+ *
+ * Should perhaps be odr_tag?
+ */
+int ber_tag(ODR o, void *p, int zclass, int tag, int *constructed, int opt)
+{
+    Odr_ber_tag *odr_ber_tag = &o->odr_ber_tag;
+    int rd;
+    char **pp = (char **)p;
+
+    if (o->direction == ODR_DECODE)
+    	*pp = 0;
+    o->t_class = -1;
+    if (o->stackp < 0)
+    {
+    	odr_seek(o, ODR_S_SET, 0);
+        o->top = 0;
+    	o->bp = o->buf;
+        odr_ber_tag->lclass = -1;
+    }
+    switch (o->direction)
+    {
+    	case ODR_ENCODE:
+	        if (!*pp)
+	        {
+	    	    if (!opt)
+		        o->error = OREQUIRED;
+	    	    return 0;
+	        }
+	        if ((rd = ber_enctag(o, zclass, tag, *constructed)) < 0)
+    		    return -1;
+#ifdef ODR_DEBUG
+    	    fprintf(stderr, "\n[class=%d,tag=%d,cons=%d,stackp=%d]", zclass, tag,
+	            	*constructed, o->stackp);
+#endif
+	        return 1;
+
+    	case ODR_DECODE:
+	        if (o->stackp > -1 && !odr_constructed_more(o))
+            {
+	    	    if (!opt)
+		            o->error = OREQUIRED;
+	    	    return 0;
+	        }
+	        if (odr_ber_tag->lclass < 0)
+	        {
+	    	    if ((odr_ber_tag->br = ber_dectag(o->bp, &odr_ber_tag->lclass,
+                                     &odr_ber_tag->ltag, &odr_ber_tag->lcons)) <= 0)
+                {
+                    o->error = OPROTO;
+		            return 0;
+                }
+#ifdef ODR_DEBUG
+		    fprintf(stderr,
+			    "\n[class=%d,tag=%d,cons=%d,stackp=%d]",
+			    odr_ber_tag->lclass, odr_ber_tag->ltag,
+			    odr_ber_tag->lcons, o->stackp);
+#endif
+	        }
+	        if (zclass == odr_ber_tag->lclass && tag == odr_ber_tag->ltag)
+	        {
+	    	    o->bp += odr_ber_tag->br;
+	    	    *constructed = odr_ber_tag->lcons;
+	    	    odr_ber_tag->lclass = -1;
+	    	    return 1;
+	        }
+	        else
+	        {
+	    	    if (!opt)
+		            o->error = OREQUIRED;
+	    	    return 0;
+	        }
+    	case ODR_PRINT:
+		    if (!*pp && !opt)
+		        o->error = OREQUIRED;
+		    return *pp != 0;
+    	default:
+            o->error = OOTHER;
+            return 0;
+    }
+}
+
+/* ber_enctag
+ * BER-encode a zclass/tag/constructed package (identifier octets). Return
+ * number of bytes encoded, or -1 if out of bounds.
+ */
+int ber_enctag(ODR o, int zclass, int tag, int constructed)
+{
+    int cons = (constructed ? 1 : 0), n = 0;
+    unsigned char octs[sizeof(int)], b;
+
+    b = (zclass << 6) & 0XC0;
+    b |= (cons << 5) & 0X20;
+    if (tag <= 30)
+    {
+    	b |= tag & 0X1F;
+	if (odr_putc(o, b) < 0)
+	    return -1;
+    	return 1;
+    }
+    else
+    {
+	b |= 0X1F;
+	if (odr_putc(o, b) < 0)
+	    return -1;
+	do
+    	{
+	    octs[n++] = tag & 0X7F;
+	    tag >>= 7;
+	}
+	while (tag);
+	while (n--)
+	{
+	    unsigned char oo;
+
+	    oo = octs[n] | ((n > 0) << 7);
+	    if (odr_putc(o, oo) < 0)
+	    	return -1;
+	}
+	return 0;
+    }
+}
+
+/* ber_dectag
+ * Decode BER identifier octets. Return number of bytes read or -1 for error.
+ */
+int ber_dectag(const unsigned char *buf, int *zclass, int *tag, int *constructed)
+{
+    const unsigned char *b = buf;
+
+    *zclass = *b >> 6;
+    *constructed = (*b >> 5) & 0X01;
+    if ((*tag = *b & 0x1F) <= 30)
+    	return 1;
+    b++;
+    *tag = 0;
+    do
+    {
+    	*tag <<= 7;
+    	*tag |= *b & 0X7F;
+    	if (b - buf >= 5) /* Precaution */
+	    return -1;
+    }
+    while (*(b++) & 0X80);
+    return b - buf;
+}
Index: /main/tags/2.25/gsdl/packages/yaz/odr/dumpber.c
===================================================================
--- /main/tags/2.25/gsdl/packages/yaz/odr/dumpber.c	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/yaz/odr/dumpber.c	(revision 21064)
@@ -0,0 +1,154 @@
+/*
+ * Copyright (c) 1995-2000, Index Data.
+ * See the file LICENSE for details.
+ * Sebastian Hammer, Adam Dickmeiss
+ *
+ * $Log$
+ * Revision 1.1  2000/08/03 03:11:17  johnmcp
+ * Added the YAZ toolkit source to the packages directory (for z39.50 stuff)
+ *
+ * Revision 1.12  2000/02/29 13:44:55  adam
+ * Check for config.h (currently not generated).
+ *
+ * Revision 1.11  1999/11/30 13:47:11  adam
+ * Improved installation. Moved header files to include/yaz.
+ *
+ * Revision 1.10  1999/01/08 11:23:26  adam
+ * Added const modifier to some of the BER/ODR encoding routines.
+ *
+ * Revision 1.9  1998/01/14 09:53:26  quinn
+ * Added a bit more info to dump.
+ *
+ * Revision 1.8  1997/05/14 06:53:57  adam
+ * C++ support.
+ *
+ * Revision 1.7  1996/03/08 14:38:41  quinn
+ * Fixed output.
+ *
+ * Revision 1.6  1996/01/19  15:41:34  quinn
+ * dumpber was ignoring the file argument.
+ *
+ * Revision 1.5  1995/10/18  16:12:55  quinn
+ * Better diagnostics. Added special case in NULL to handle WAIS server.
+ *
+ * Revision 1.4  1995/09/29  17:12:21  quinn
+ * Smallish
+ *
+ * Revision 1.3  1995/09/27  15:02:57  quinn
+ * Modified function heads & prototypes.
+ *
+ * Revision 1.2  1995/06/27  13:20:51  quinn
+ * Fixed sign-clash. Non-fatal warning
+ *
+ * Revision 1.1  1995/06/19  12:38:45  quinn
+ * Added BER dumper.
+ *
+ *
+ */
+#if HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <stdio.h>
+#include <yaz/odr.h>
+
+static int do_dumpBER(FILE *f, const char *buf, int len, int level, int offset)
+{
+    int res, ll, zclass, tag, cons, lenlen, taglen;
+    const char *b = buf, *bp = buf;
+    
+    if (!len)
+    	return 0;
+    if (!buf[0] && !buf[1])
+    	return 0;
+    if ((res = ber_dectag((unsigned char*)b, &zclass, &tag, &cons)) <= 0)
+    	return 0;
+    if (res > len)
+    {
+    	fprintf(stderr, "Unexpected end of buffer\n");
+    	return 0;
+    }
+    fprintf(f, "%5d: %*s", offset, level * 4, "");
+    if (zclass == ODR_UNIVERSAL)
+    {
+    	static char *nl[] =
+	{
+	    "[Univ 0]", "BOOLEAN", "INTEGER", "BIT STRING", "OCTET STRING",
+	    "NULL", "OID", "OBJECT DESCIPTOR", "EXTERNAL", "REAL",
+	    "ENUM", "[UNIV 11]", "[UNIV 12]", "[UNIV 13]", "[UNIV 14]",
+	    "[UNIV 15]", "SEQUENCE", "SET", "NUMERICSTRING", "PRINTABLESTRING",
+	    "[UNIV 20]", "[UNIV 21]", "[UNIV 22]", "[UNIV 23]", "[UNIV 24]",
+	    "GRAPHICSTRING", "VISIBLESTRING", "GENERALSTRING", "[UNIV 28]"
+	};
+
+	if (tag < 28)
+	    fprintf(f, "%s", nl[tag]);
+	else
+	    fprintf(f, "[UNIV %d]", tag);
+    }
+    else if (zclass == ODR_CONTEXT)
+	fprintf(f, "[%d]", tag);
+    else
+	fprintf(f, "[%d:%d]", zclass, tag);
+    b += res;
+    taglen = res;
+    len -= res;
+    bp = b;
+    if ((res = ber_declen((unsigned char*)b, &ll)) <= 0)
+    {
+    	fprintf(f, "bad length\n");
+    	return 0;
+    }
+    if (res > len)
+    {
+    	fprintf(f, "Unexpected end of buffer\n");
+    	return 0;
+    }
+    lenlen = res;
+    b += res;
+    len -= res;
+    if (ll >= 0)
+    	fprintf(f, " len=%d", ll);
+    else
+    	fprintf(f, " len=?");
+    fprintf(f, "       tl=%d, ll=%d\n", taglen, lenlen);
+    if (!cons)
+    {
+    	if (ll < 0)
+	{
+	    fprintf(f, "Bad length on primitive type.\n");
+	    return 0;
+	}
+    	return ll + (b - buf);
+    }
+    if (ll >= 0)
+    	len = ll;
+    /* constructed - cycle through children */
+    while ((ll == -1 && len >= 2) || (ll >= 0 && len))
+    {
+	if (ll == -1 && *b == 0 && *(b + 1) == 0)
+	    break;
+	if (!(res = do_dumpBER(f, b, len, level + 1, offset + (b - buf))))
+	{
+	    fprintf(f, "Dump of content element failed.\n");
+	    return 0;
+	}
+	b += res;
+	len -= res;
+    }
+    if (ll == -1)
+    {
+    	if (len < 2)
+	{
+	    fprintf(f, "Buffer too short in indefinite lenght.\n");
+	    return 0;
+	}
+	return (b - buf) + 2;
+    }
+    return b - buf;
+}
+
+int odr_dumpBER(FILE *f, const char *buf, int len)
+{
+    return do_dumpBER(f, buf, len, 0, 0);
+}
Index: /main/tags/2.25/gsdl/packages/yaz/odr/odr.c
===================================================================
--- /main/tags/2.25/gsdl/packages/yaz/odr/odr.c	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/yaz/odr/odr.c	(revision 21064)
@@ -0,0 +1,236 @@
+/*
+ * Copyright (c) 1995-2000, Index Data
+ * See the file LICENSE for details.
+ *
+ * $Log$
+ * Revision 1.1  2000/08/03 03:11:17  johnmcp
+ * Added the YAZ toolkit source to the packages directory (for z39.50 stuff)
+ *
+ * Revision 1.33  2000/02/29 13:44:55  adam
+ * Check for config.h (currently not generated).
+ *
+ * Revision 1.32  2000/01/31 13:15:21  adam
+ * Removed uses of assert(3). Cleanup of ODR. CCL parser update so
+ * that some characters are not surrounded by spaces in resulting term.
+ * ILL-code updates.
+ *
+ * Revision 1.31  1999/11/30 13:47:11  adam
+ * Improved installation. Moved header files to include/yaz.
+ *
+ * Revision 1.30  1999/08/27 09:40:32  adam
+ * Renamed logf function to yaz_log. Removed VC++ project files.
+ *
+ * Revision 1.29  1999/04/27 08:34:10  adam
+ * Modified odr_destroy so that file is not closed when file is 0.
+ *
+ * Revision 1.28  1998/07/20 12:38:13  adam
+ * More LOG_DEBUG-diagnostics.
+ *
+ * Revision 1.27  1998/02/11 11:53:34  adam
+ * Changed code so that it compiles as C++.
+ *
+ * Revision 1.26  1997/11/24 11:33:56  adam
+ * Using function odr_nullval() instead of global ODR_NULLVAL when
+ * appropriate.
+ *
+ * Revision 1.25  1997/10/31 12:20:08  adam
+ * Improved memory debugging for xmalloc/nmem.c. References to NMEM
+ * instead of ODR in n ESPEC-1 handling in source d1_espec.c.
+ * Bug fix: missing fclose in data1_read_espec1.
+ *
+ * Revision 1.24  1997/09/01 08:51:07  adam
+ * New windows NT/95 port using MSV5.0. Had to avoid a few static
+ * variables used in function ber_tag. These are now part of the
+ * ODR structure.
+ *
+ * Revision 1.23  1997/04/30 08:52:10  quinn
+ * Null
+ *
+ * Revision 1.22  1996/10/08  12:58:17  adam
+ * New ODR function, odr_choice_enable_bias, to control behaviour of
+ * odr_choice_bias.
+ *
+ * Revision 1.21  1996/07/26  13:38:19  quinn
+ * Various smaller things. Gathered header-files.
+ *
+ * Revision 1.20  1995/11/08  17:41:32  quinn
+ * Smallish.
+ *
+ * Revision 1.19  1995/11/01  13:54:41  quinn
+ * Minor adjustments
+ *
+ * Revision 1.18  1995/09/29  17:12:22  quinn
+ * Smallish
+ *
+ * Revision 1.17  1995/09/29  17:01:50  quinn
+ * More Windows work
+ *
+ * Revision 1.16  1995/09/27  15:02:57  quinn
+ * Modified function heads & prototypes.
+ *
+ * Revision 1.15  1995/08/15  12:00:22  quinn
+ * Updated External
+ *
+ * Revision 1.14  1995/06/19  12:38:46  quinn
+ * Added BER dumper.
+ *
+ * Revision 1.13  1995/05/22  11:32:02  quinn
+ * Fixing Interface to odr_null.
+ *
+ * Revision 1.12  1995/05/16  08:50:49  quinn
+ * License, documentation, and memory fixes
+ *
+ * Revision 1.11  1995/05/15  11:56:08  quinn
+ * More work on memory management.
+ *
+ * Revision 1.10  1995/04/18  08:15:20  quinn
+ * Added dynamic memory allocation on encoding (whew). Code is now somewhat
+ * neater. We'll make the same change for decoding one day.
+ *
+ * Revision 1.9  1995/04/10  10:23:11  quinn
+ * Smallish changes.
+ *
+ * Revision 1.8  1995/03/17  10:17:43  quinn
+ * Added memory management.
+ *
+ * Revision 1.7  1995/03/10  11:44:41  quinn
+ * Fixed serious stack-bug in odr_cons_begin
+ *
+ * Revision 1.6  1995/03/08  12:12:15  quinn
+ * Added better error checking.
+ *
+ * Revision 1.5  1995/03/07  13:28:57  quinn
+ * *** empty log message ***
+ *
+ * Revision 1.4  1995/03/07  13:16:13  quinn
+ * Fixed bug in odr_reset
+ *
+ * Revision 1.3  1995/03/07  10:21:31  quinn
+ * odr_errno-->odr_error
+ *
+ * Revision 1.2  1995/03/07  10:19:05  quinn
+ * Addded some method functions to the ODR type.
+ *
+ * Revision 1.1  1995/03/07  09:23:15  quinn
+ * Installing top-level API and documentation.
+ *
+ *
+ */
+#if HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <stdio.h>
+#include <stdlib.h>
+
+#include <yaz/xmalloc.h>
+#include <yaz/odr.h>
+
+Odr_null *ODR_NULLVAL = "NULL";  /* the presence of a null value */
+
+Odr_null *odr_nullval (void)
+{
+    return ODR_NULLVAL;
+}
+
+char *odr_errlist[] =
+{
+    "No (unknown) error",
+    "Memory allocation failed",
+    "System error",
+    "No space in buffer",
+    "Required data element missing",
+    "Unexpected tag",
+    "Other error",
+    "Protocol error",
+    "Malformed data",
+    "Stack overflow",
+    "Length of constructed type different from sum of members",
+    "Overflow writing definite length of constructed type"
+};
+
+char *odr_errmsg(int n)
+{
+    return odr_errlist[n];
+}
+
+void odr_perror(ODR o, char *message)
+{
+    fprintf(stderr, "%s: %s\n", message, odr_errlist[o->error]);
+}
+
+int odr_geterror(ODR o)
+{
+    return o->error;
+}
+
+void odr_setprint(ODR o, FILE *file)
+{
+    o->print = file;
+}
+
+#include <yaz/log.h>
+
+ODR odr_createmem(int direction)
+{
+    ODR r;
+
+    if (!(r = (ODR)xmalloc(sizeof(*r))))
+        return 0;
+    r->direction = direction;
+    r->print = stderr;
+    r->buf = 0;
+    r->size = r->pos = r->top = 0;
+    r->can_grow = 1;
+    r->mem = nmem_create();
+    r->enable_bias = 1;
+    r->odr_ber_tag.lclass = -1;
+    odr_reset(r);
+    yaz_log (LOG_DEBUG, "odr_createmem dir=%d o=%p", direction, r);
+    return r;
+}
+
+void odr_reset(ODR o)
+{
+    o->error = ONONE;
+    o->bp = o->buf;
+    odr_seek(o, ODR_S_SET, 0);
+    o->top = 0;
+    o->t_class = -1;
+    o->t_tag = -1;
+    o->indent = 0;
+    o->stackp = -1;
+    nmem_reset(o->mem);
+    o->choice_bias = -1;
+    o->lenlen = 1;
+    yaz_log (LOG_DEBUG, "odr_reset o=%p", o);
+}
+    
+void odr_destroy(ODR o)
+{
+    nmem_destroy(o->mem);
+    if (o->buf && o->can_grow)
+       xfree(o->buf);
+    if (o->print && o->print != stderr)
+        fclose(o->print);
+    xfree(o);
+    yaz_log (LOG_DEBUG, "odr_destroy o=%p", o);
+}
+
+void odr_setbuf(ODR o, char *buf, int len, int can_grow)
+{
+    o->bp = (unsigned char *) buf;
+
+    o->buf = (unsigned char *) buf;
+    o->can_grow = can_grow;
+    o->top = o->pos = 0;
+    o->size = len;
+}
+
+char *odr_getbuf(ODR o, int *len, int *size)
+{
+    *len = o->top;
+    if (size)
+        *size = o->size;
+    return (char*) o->buf;
+}
Index: /main/tags/2.25/gsdl/packages/yaz/odr/odr_any.c
===================================================================
--- /main/tags/2.25/gsdl/packages/yaz/odr/odr_any.c	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/yaz/odr/odr_any.c	(revision 21064)
@@ -0,0 +1,72 @@
+/*
+ * Copyright (c) 1995-2000, Index Data
+ * See the file LICENSE for details.
+ * Sebastian Hammer, Adam Dickmeiss
+ *
+ * $Log$
+ * Revision 1.1  2000/08/03 03:11:18  johnmcp
+ * Added the YAZ toolkit source to the packages directory (for z39.50 stuff)
+ *
+ * Revision 1.10  2000/02/29 13:44:55  adam
+ * Check for config.h (currently not generated).
+ *
+ * Revision 1.9  1999/11/30 13:47:11  adam
+ * Improved installation. Moved header files to include/yaz.
+ *
+ * Revision 1.8  1999/04/20 09:56:48  adam
+ * Added 'name' paramter to encoder/decoder routines (typedef Odr_fun).
+ * Modified all encoders/decoders to reflect this change.
+ *
+ * Revision 1.7  1998/02/11 11:53:34  adam
+ * Changed code so that it compiles as C++.
+ *
+ * Revision 1.6  1995/09/29 17:12:22  quinn
+ * Smallish
+ *
+ * Revision 1.5  1995/09/27  15:02:58  quinn
+ * Modified function heads & prototypes.
+ *
+ * Revision 1.4  1995/05/16  08:50:50  quinn
+ * License, documentation, and memory fixes
+ *
+ * Revision 1.3  1995/03/17  10:17:46  quinn
+ * Added memory management.
+ *
+ * Revision 1.2  1995/03/08  12:12:18  quinn
+ * Added better error checking.
+ *
+ * Revision 1.1  1995/02/09  15:51:47  quinn
+ * Works better now.
+ *
+ */
+#if HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <yaz/odr.h>
+
+/*
+ * This is a catch-all type. It stuffs a random ostring (assumed to be properly
+ * encoded) into the stream, or reads a full data element. Implicit tagging
+ * does not work, and neither does the optional flag, unless the element
+ * is the last in a sequence.
+ */
+int odr_any(ODR o, Odr_any **p, int opt, const char *name)
+{
+    if (o->error)
+    	return 0;
+    if (o->direction == ODR_PRINT)
+    {
+	odr_prname(o, name);
+    	fprintf(o->print, "ANY (len=%d)\n", (*p)->len);
+    	return 1;
+    }
+    if (o->direction == ODR_DECODE)
+    	*p = (Odr_oct *)odr_malloc(o, sizeof(**p));
+    if (ber_any(o, p))
+    	return 1;
+    *p = 0;
+    if (!opt)
+    	o->error = OREQUIRED;
+    return opt;
+}    
Index: /main/tags/2.25/gsdl/packages/yaz/odr/odr_bit.c
===================================================================
--- /main/tags/2.25/gsdl/packages/yaz/odr/odr_bit.c	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/yaz/odr/odr_bit.c	(revision 21064)
@@ -0,0 +1,94 @@
+/*
+ * Copyright (c) 1995-2000, Index Data
+ * See the file LICENSE for details.
+ * Sebastian Hammer, Adam Dickmeiss
+ *
+ * $Log$
+ * Revision 1.1  2000/08/03 03:11:18  johnmcp
+ * Added the YAZ toolkit source to the packages directory (for z39.50 stuff)
+ *
+ * Revision 1.14  2000/02/29 13:44:55  adam
+ * Check for config.h (currently not generated).
+ *
+ * Revision 1.13  1999/11/30 13:47:11  adam
+ * Improved installation. Moved header files to include/yaz.
+ *
+ * Revision 1.12  1999/04/20 09:56:48  adam
+ * Added 'name' paramter to encoder/decoder routines (typedef Odr_fun).
+ * Modified all encoders/decoders to reflect this change.
+ *
+ * Revision 1.11  1998/02/11 11:53:34  adam
+ * Changed code so that it compiles as C++.
+ *
+ * Revision 1.10  1995/09/29 17:12:22  quinn
+ * Smallish
+ *
+ * Revision 1.9  1995/09/27  15:02:58  quinn
+ * Modified function heads & prototypes.
+ *
+ * Revision 1.8  1995/05/16  08:50:51  quinn
+ * License, documentation, and memory fixes
+ *
+ * Revision 1.7  1995/03/17  10:17:48  quinn
+ * Added memory management.
+ *
+ * Revision 1.6  1995/03/08  12:12:19  quinn
+ * Added better error checking.
+ *
+ * Revision 1.5  1995/02/10  18:57:25  quinn
+ * More in the way of error-checking.
+ *
+ * Revision 1.4  1995/02/09  15:51:47  quinn
+ * Works better now.
+ *
+ * Revision 1.3  1995/02/07  14:13:45  quinn
+ * Bug fixes.
+ *
+ * Revision 1.2  1995/02/03  17:04:37  quinn
+ * *** empty log message ***
+ *
+ * Revision 1.1  1995/02/02  20:38:50  quinn
+ * Updates.
+ *
+ *
+ */
+#if HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <string.h>
+#include <yaz/odr.h>
+
+/*
+ * Top level bitstring string en/decoder.
+ * Returns 1 on success, 0 on error.
+ */
+int odr_bitstring(ODR o, Odr_bitmask **p, int opt, const char *name)
+{
+    int res, cons = 0;
+
+    if (o->error)
+    	return 0;
+    if (o->t_class < 0)
+    {
+    	o->t_class = ODR_UNIVERSAL;
+    	o->t_tag = ODR_BITSTRING;
+    }
+    if ((res = ber_tag(o, p, o->t_class, o->t_tag, &cons, opt)) < 0)
+    	return 0;
+    if (!res)
+    	return opt;
+    if (o->direction == ODR_PRINT)
+    {
+	odr_prname(o, name);
+    	fprintf(o->print, "BITSTRING(len=%d)\n",(*p)->top + 1);
+    	return 1;
+    }
+    if (o->direction == ODR_DECODE)
+    {
+    	*p = (Odr_bitmask *)odr_malloc(o, sizeof(Odr_bitmask));
+    	memset((*p)->bits, 0, ODR_BITMASK_SIZE);
+    	(*p)->top = -1;
+    }
+    return ber_bitstring(o, *p, cons);
+}
Index: /main/tags/2.25/gsdl/packages/yaz/odr/odr_bool.c
===================================================================
--- /main/tags/2.25/gsdl/packages/yaz/odr/odr_bool.c	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/yaz/odr/odr_bool.c	(revision 21064)
@@ -0,0 +1,85 @@
+/*
+ * Copyright (c) 1995-2000, Index Data
+ * See the file LICENSE for details.
+ * Sebastian Hammer, Adam Dickmeiss
+ *
+ * $Log$
+ * Revision 1.1  2000/08/03 03:11:19  johnmcp
+ * Added the YAZ toolkit source to the packages directory (for z39.50 stuff)
+ *
+ * Revision 1.12  2000/02/29 13:44:55  adam
+ * Check for config.h (currently not generated).
+ *
+ * Revision 1.11  1999/11/30 13:47:11  adam
+ * Improved installation. Moved header files to include/yaz.
+ *
+ * Revision 1.10  1999/04/20 09:56:48  adam
+ * Added 'name' paramter to encoder/decoder routines (typedef Odr_fun).
+ * Modified all encoders/decoders to reflect this change.
+ *
+ * Revision 1.9  1998/02/11 11:53:34  adam
+ * Changed code so that it compiles as C++.
+ *
+ * Revision 1.8  1995/09/29 17:12:23  quinn
+ * Smallish
+ *
+ * Revision 1.7  1995/09/27  15:02:58  quinn
+ * Modified function heads & prototypes.
+ *
+ * Revision 1.6  1995/05/16  08:50:52  quinn
+ * License, documentation, and memory fixes
+ *
+ * Revision 1.5  1995/03/17  10:17:49  quinn
+ * Added memory management.
+ *
+ * Revision 1.4  1995/03/08  12:12:20  quinn
+ * Added better error checking.
+ *
+ * Revision 1.3  1995/02/10  18:57:25  quinn
+ * More in the way of error-checking.
+ *
+ * Revision 1.2  1995/02/09  15:51:47  quinn
+ * Works better now.
+ *
+ * Revision 1.1  1995/02/02  16:21:53  quinn
+ * First kick.
+ *
+ */
+#if HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <stdio.h>
+#include <yaz/odr.h>
+
+/*
+ * Top level boolean en/decoder.
+ * Returns 1 on success, 0 on error.
+ */
+int odr_bool(ODR o, int **p, int opt, const char *name)
+{
+    int res, cons = 0;
+
+    if (o->error)
+    	return 0;
+    if (o->t_class < 0)
+    {
+    	o->t_class = ODR_UNIVERSAL;
+    	o->t_tag = ODR_BOOLEAN;
+    }
+    if ((res = ber_tag(o, p, o->t_class, o->t_tag, &cons, opt)) < 0)
+    	return 0;
+    if (!res)
+    	return opt;
+    if (o->direction == ODR_PRINT)
+    {
+	odr_prname(o, name);
+    	fprintf(o->print, "%s\n", (**p ? "TRUE" : "FALSE"));
+    	return 1;
+    }
+    if (cons)
+    	return 0;
+    if (o->direction == ODR_DECODE)
+    	*p = (int *)odr_malloc(o, sizeof(int));
+    return ber_boolean(o, *p);
+}
Index: /main/tags/2.25/gsdl/packages/yaz/odr/odr_choice.c
===================================================================
--- /main/tags/2.25/gsdl/packages/yaz/odr/odr_choice.c	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/yaz/odr/odr_choice.c	(revision 21064)
@@ -0,0 +1,151 @@
+/*
+ * Copyright (c) 1995-2000, Index Data
+ * See the file LICENSE for details.
+ * Sebastian Hammer, Adam Dickmeiss
+ *
+ * $Log$
+ * Revision 1.1  2000/08/03 03:11:19  johnmcp
+ * Added the YAZ toolkit source to the packages directory (for z39.50 stuff)
+ *
+ * Revision 1.18  2000/02/29 13:44:55  adam
+ * Check for config.h (currently not generated).
+ *
+ * Revision 1.17  1999/11/30 13:47:11  adam
+ * Improved installation. Moved header files to include/yaz.
+ *
+ * Revision 1.16  1999/04/20 09:56:48  adam
+ * Added 'name' paramter to encoder/decoder routines (typedef Odr_fun).
+ * Modified all encoders/decoders to reflect this change.
+ *
+ * Revision 1.15  1998/02/11 11:53:34  adam
+ * Changed code so that it compiles as C++.
+ *
+ * Revision 1.14  1997/05/14 06:53:57  adam
+ * C++ support.
+ *
+ * Revision 1.13  1997/04/30 08:52:10  quinn
+ * Null
+ *
+ * Revision 1.12  1996/10/08  12:58:17  adam
+ * New ODR function, odr_choice_enable_bias, to control behaviour of
+ * odr_choice_bias.
+ *
+ * Revision 1.11  1995/09/29  17:12:23  quinn
+ * Smallish
+ *
+ * Revision 1.10  1995/09/27  15:02:58  quinn
+ * Modified function heads & prototypes.
+ *
+ * Revision 1.9  1995/08/15  12:00:23  quinn
+ * Updated External
+ *
+ * Revision 1.8  1995/06/19  17:01:51  quinn
+ * This should bring us in sync with the version distributed as 1.0b
+ *
+ * Revision 1.7  1995/06/19  13:06:50  quinn
+ * Fixed simple bug in the code to handle untagged choice elements.
+ *
+ * Revision 1.6  1995/05/16  08:50:53  quinn
+ * License, documentation, and memory fixes
+ *
+ * Revision 1.5  1995/03/18  12:16:31  quinn
+ * Minor changes.
+ *
+ * Revision 1.4  1995/03/14  16:59:38  quinn
+ * Added odr_constructed_more check
+ *
+ * Revision 1.3  1995/03/08  12:12:22  quinn
+ * Added better error checking.
+ *
+ * Revision 1.2  1995/02/09  15:51:48  quinn
+ * Works better now.
+ *
+ * Revision 1.1  1995/02/07  17:52:59  quinn
+ * A damn mess, but now things work, I think.
+ *
+ */
+#if HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <yaz/odr.h>
+
+int odr_choice(ODR o, Odr_arm arm[], void *p, void *whichp,
+	       const char *name)
+{
+    int i, cl = -1, tg, cn, *which = (int *)whichp, bias = o->choice_bias;
+
+    if (o->error)
+    	return 0;
+    if (o->direction != ODR_DECODE && !*(char**)p)
+    	return 0;
+    o->choice_bias = -1;
+
+    if (o->direction == ODR_PRINT)
+    {
+	if (name)
+	{
+	    odr_prname(o, name);
+	    fprintf (o->print, "choice\n");
+	}
+    }
+    for (i = 0; arm[i].fun; i++)
+    {
+    	if (o->direction == ODR_DECODE)
+	{
+	    if (bias >= 0 && bias != arm[i].which)
+		continue;
+    	    *which = arm[i].which;
+	}
+	else if (*which != arm[i].which)
+	    continue;
+
+    	if (arm[i].tagmode != ODR_NONE)
+    	{
+	    if (o->direction == ODR_DECODE && cl < 0)
+	    {
+	    	if (o->stackp > -1 && !odr_constructed_more(o))
+		    return 0;
+	    	if (ber_dectag(o->bp, &cl, &tg, &cn) <= 0)
+		    return 0;
+	    }
+	    else if (o->direction != ODR_DECODE)
+	    {
+	    	cl = arm[i].zclass;
+	    	tg = arm[i].tag;
+	    }
+	    if (tg == arm[i].tag && cl == arm[i].zclass)
+	    {
+	    	if (arm[i].tagmode == ODR_IMPLICIT)
+	    	{
+		    odr_implicit_settag(o, cl, tg);
+	    	    return (*arm[i].fun)(o, (char **)p, 0, arm[i].name);
+		}
+		/* explicit */
+		if (!odr_constructed_begin(o, p, cl, tg, 0))
+		    return 0;
+		return (*arm[i].fun)(o, (char **)p, 0, arm[i].name) &&
+		    odr_constructed_end(o);
+	    }
+	}
+	else  /* no tagging. Have to poll type */
+	{
+	    if ((*arm[i].fun)(o, (char **)p, 1, arm[i].name) && *(char**)p)
+	    	return 1;
+	}
+    }
+    *which = -1;
+    *(char*)p = 0;
+    return 0;
+}
+
+void odr_choice_bias(ODR o, int what)
+{
+    if (o->enable_bias)
+        o->choice_bias = what;
+}
+
+void odr_choice_enable_bias (ODR o, int mode)
+{
+    o->enable_bias = mode;
+}
Index: /main/tags/2.25/gsdl/packages/yaz/odr/odr_cons.c
===================================================================
--- /main/tags/2.25/gsdl/packages/yaz/odr/odr_cons.c	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/yaz/odr/odr_cons.c	(revision 21064)
@@ -0,0 +1,237 @@
+/*
+ * Copyright (c) 1995-2000, Index Data
+ * See the file LICENSE for details.
+ *
+ * $Log$
+ * Revision 1.1  2000/08/03 03:11:20  johnmcp
+ * Added the YAZ toolkit source to the packages directory (for z39.50 stuff)
+ *
+ * Revision 1.22  2000/02/29 13:44:55  adam
+ * Check for config.h (currently not generated).
+ *
+ * Revision 1.21  2000/01/31 13:15:21  adam
+ * Removed uses of assert(3). Cleanup of ODR. CCL parser update so
+ * that some characters are not surrounded by spaces in resulting term.
+ * ILL-code updates.
+ *
+ * Revision 1.20  1999/11/30 13:47:11  adam
+ * Improved installation. Moved header files to include/yaz.
+ *
+ * Revision 1.19  1999/04/20 09:56:48  adam
+ * Added 'name' paramter to encoder/decoder routines (typedef Odr_fun).
+ * Modified all encoders/decoders to reflect this change.
+ *
+ * Revision 1.18  1997/05/14 06:53:58  adam
+ * C++ support.
+ *
+ * Revision 1.17  1996/10/23 12:31:24  adam
+ * Added 'static' modifier to dummy variable in odr_constructed_begin.
+ *
+ * Revision 1.16  1996/07/26  13:38:20  quinn
+ * Various smaller things. Gathered header-files.
+ *
+ * Revision 1.15  1995/09/29  17:12:23  quinn
+ * Smallish
+ *
+ * Revision 1.14  1995/09/27  15:02:58  quinn
+ * Modified function heads & prototypes.
+ *
+ * Revision 1.13  1995/08/15  11:16:39  quinn
+ * Fixed pretty-printers.
+ *
+ * Revision 1.12  1995/06/19  12:38:47  quinn
+ * Added BER dumper.
+ *
+ * Revision 1.11  1995/05/16  08:50:53  quinn
+ * License, documentation, and memory fixes
+ *
+ * Revision 1.10  1995/04/18  08:15:21  quinn
+ * Added dynamic memory allocation on encoding (whew). Code is now somewhat
+ * neater. We'll make the same change for decoding one day.
+ *
+ * Revision 1.9  1995/03/28  09:15:49  quinn
+ * Fixed bug in the printing mode
+ *
+ * Revision 1.8  1995/03/15  11:18:04  quinn
+ * Fixed serious bug in odr_cons
+ *
+ * Revision 1.7  1995/03/10  11:44:41  quinn
+ * Fixed serious stack-bug in odr_cons_begin
+ *
+ * Revision 1.6  1995/03/08  12:12:23  quinn
+ * Added better error checking.
+ *
+ * Revision 1.5  1995/02/10  18:57:25  quinn
+ * More in the way of error-checking.
+ *
+ * Revision 1.4  1995/02/10  15:55:29  quinn
+ * Bug fixes, mostly.
+ *
+ * Revision 1.3  1995/02/09  15:51:48  quinn
+ * Works better now.
+ *
+ * Revision 1.2  1995/02/07  17:52:59  quinn
+ * A damn mess, but now things work, I think.
+ *
+ * Revision 1.1  1995/02/02  16:21:53  quinn
+ * First kick.
+ *
+ */
+#if HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <yaz/odr.h>
+
+void odr_setlenlen(ODR o, int len)
+{
+    o->lenlen = len;
+}
+
+int odr_constructed_begin(ODR o, void *p, int zclass, int tag,
+			  const char *name)
+{
+    int res;
+    int cons = 1;
+    int lenlen = o->lenlen;
+
+    if (o->error)
+    	return 0;
+    o->lenlen = 1; /* reset lenlen */
+    if (o->t_class < 0)
+    {
+	o->t_class = zclass;
+	o->t_tag = tag;
+    }
+    if ((res = ber_tag(o, p, o->t_class, o->t_tag, &cons, 1)) < 0)
+    	return 0;
+    if (!res || !cons)
+    	return 0;
+
+    if (o->stackp == ODR_MAX_STACK - 1)
+    {
+    	o->error = OSTACK;
+    	return 0;
+    }
+    o->stack[++(o->stackp)].lenb = o->bp;
+    o->stack[o->stackp].len_offset = odr_tell(o);
+#ifdef ODR_DEBUG
+    fprintf(stderr, "[cons_begin(%d)]", o->stackp);
+#endif
+    if (o->direction == ODR_ENCODE)
+    {
+	static unsigned char dummy[sizeof(int)+1];
+
+	o->stack[o->stackp].lenlen = lenlen;
+
+	if (odr_write(o, dummy, lenlen) < 0) /* dummy */
+	    return 0;
+    }
+    else if (o->direction == ODR_DECODE)
+    {
+    	if ((res = ber_declen(o->bp, &o->stack[o->stackp].len)) < 0)
+	    return 0;
+	o->stack[o->stackp].lenlen = res;
+	o->bp += res;
+    }
+    else if (o->direction == ODR_PRINT)
+    {
+	odr_prname(o, name);
+    	fprintf(o->print, "{\n");
+	o->indent++;
+    }
+    else
+    {
+    	o->error = OOTHER;
+	return 0;
+    }
+    o->stack[o->stackp].base = o->bp;
+    o->stack[o->stackp].base_offset = odr_tell(o);
+    return 1;
+}
+
+int odr_constructed_more(ODR o)
+{
+    if (o->error)
+    	return 0;
+    if (o->stackp < 0)
+    	return 0;
+    if (o->stack[o->stackp].len >= 0)
+    	return o->bp - o->stack[o->stackp].base < o->stack[o->stackp].len;
+    else
+    	return (!(*o->bp == 0 && *(o->bp + 1) == 0));
+}
+
+int odr_constructed_end(ODR o)
+{
+    int res;
+    int pos;
+
+    if (o->error)
+    	return 0;
+    if (o->stackp < 0)
+    {
+    	o->error = OOTHER;
+    	return 0;
+    }
+    switch (o->direction)
+    {
+    	case ODR_DECODE:
+	    if (o->stack[o->stackp].len < 0)
+	    {
+	    	if (*o->bp++ == 0 && *(o->bp++) == 0)
+	    	{
+		    o->stackp--;
+		    return 1;
+		}
+		else
+		{
+		    o->error = OOTHER;
+		    return 0;
+		}
+	    }
+	    else if (o->bp - o->stack[o->stackp].base !=
+		o->stack[o->stackp].len)
+	    {
+	    	o->error = OCONLEN;
+	    	return 0;
+	    }
+	    o->stackp--;
+	    return 1;
+    	case ODR_ENCODE:
+	    pos = odr_tell(o);
+	    odr_seek(o, ODR_S_SET, o->stack[o->stackp].len_offset);
+	    if ((res = ber_enclen(o, pos - o->stack[o->stackp].base_offset,
+		o->stack[o->stackp].lenlen, 1)) < 0)
+	    {
+		o->error = OLENOV;
+		return 0;
+	    }
+	    odr_seek(o, ODR_S_END, 0);
+	    if (res == 0)   /* indefinite encoding */
+	    {
+#ifdef ODR_DEBUG
+		fprintf(stderr, "[cons_end(%d): indefinite]", o->stackp);
+#endif
+		if (odr_putc(o, 0) < 0 || odr_putc(o, 0) < 0)
+		    return 0;
+	    }
+#ifdef ODR_DEBUG
+	    else
+	    {
+	    	fprintf(stderr, "[cons_end(%d): definite]", o->stackp);
+	    }
+#endif
+	    o->stackp--;
+	    return 1;
+    	case ODR_PRINT:
+	    o->stackp--;
+	    o->indent--;
+	    odr_prname(o, 0);
+	    fprintf(o->print, "}\n");
+	    return 1;
+    	default:
+	    o->error = OOTHER;
+	    return 0;
+    }
+}
Index: /main/tags/2.25/gsdl/packages/yaz/odr/odr_enum.c
===================================================================
--- /main/tags/2.25/gsdl/packages/yaz/odr/odr_enum.c	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/yaz/odr/odr_enum.c	(revision 21064)
@@ -0,0 +1,66 @@
+/*
+ * Copyright (c) 1995-2000, Index Data
+ * See the file LICENSE for details.
+ * Sebastian Hammer, Adam Dickmeiss
+ *
+ * $Log$
+ * Revision 1.1  2000/08/03 03:11:21  johnmcp
+ * Added the YAZ toolkit source to the packages directory (for z39.50 stuff)
+ *
+ * Revision 1.5  2000/02/29 13:44:55  adam
+ * Check for config.h (currently not generated).
+ *
+ * Revision 1.4  1999/11/30 13:47:11  adam
+ * Improved installation. Moved header files to include/yaz.
+ *
+ * Revision 1.3  1999/04/20 09:56:48  adam
+ * Added 'name' paramter to encoder/decoder routines (typedef Odr_fun).
+ * Modified all encoders/decoders to reflect this change.
+ *
+ * Revision 1.2  1999/01/08 11:23:27  adam
+ * Added const modifier to some of the BER/ODR encoding routines.
+ *
+ * Revision 1.1  1998/03/20 14:45:01  adam
+ * Implemented odr_enum and odr_set_of.
+ *
+ */
+#if HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <yaz/odr.h>
+
+/*
+ * Top level enum en/decoder.
+ * Returns 1 on success, 0 on error.
+ */
+int odr_enum(ODR o, int **p, int opt, const char *name)
+{
+    int res, cons = 0;
+
+    if (o->error)
+        return 0;
+    if (o->t_class < 0)
+    {
+        o->t_class = ODR_UNIVERSAL;
+        o->t_tag = ODR_ENUM;
+    }
+    if ((res = ber_tag(o, p, o->t_class, o->t_tag, &cons, opt)) < 0)
+        return 0;
+    if (!res)
+        return opt;
+    if (o->direction == ODR_PRINT)
+    {
+	odr_prname(o, name);
+        fprintf(o->print, "%d\n", **p);
+        return 1;
+    }
+    if (cons)
+    {
+        o->error = OPROTO;
+        return 0;
+    }
+    if (o->direction == ODR_DECODE)
+        *p = (int *)odr_malloc(o, sizeof(int));
+    return ber_integer(o, *p);
+}
Index: /main/tags/2.25/gsdl/packages/yaz/odr/odr_int.c
===================================================================
--- /main/tags/2.25/gsdl/packages/yaz/odr/odr_int.c	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/yaz/odr/odr_int.c	(revision 21064)
@@ -0,0 +1,96 @@
+/*
+ * Copyright (c) 1995-2000, Index Data
+ * See the file LICENSE for details.
+ * Sebastian Hammer, Adam Dickmeiss
+ *
+ * $Log$
+ * Revision 1.1  2000/08/03 03:11:21  johnmcp
+ * Added the YAZ toolkit source to the packages directory (for z39.50 stuff)
+ *
+ * Revision 1.15  2000/02/29 13:44:55  adam
+ * Check for config.h (currently not generated).
+ *
+ * Revision 1.14  1999/11/30 13:47:11  adam
+ * Improved installation. Moved header files to include/yaz.
+ *
+ * Revision 1.13  1999/04/20 09:56:48  adam
+ * Added 'name' paramter to encoder/decoder routines (typedef Odr_fun).
+ * Modified all encoders/decoders to reflect this change.
+ *
+ * Revision 1.12  1999/01/08 11:23:28  adam
+ * Added const modifier to some of the BER/ODR encoding routines.
+ *
+ * Revision 1.11  1998/02/11 11:53:34  adam
+ * Changed code so that it compiles as C++.
+ *
+ * Revision 1.10  1995/09/29 17:12:24  quinn
+ * Smallish
+ *
+ * Revision 1.9  1995/09/29  17:01:50  quinn
+ * More Windows work
+ *
+ * Revision 1.8  1995/09/27  15:02:59  quinn
+ * Modified function heads & prototypes.
+ *
+ * Revision 1.7  1995/05/16  08:50:54  quinn
+ * License, documentation, and memory fixes
+ *
+ * Revision 1.6  1995/03/17  10:17:51  quinn
+ * Added memory management.
+ *
+ * Revision 1.5  1995/03/08  12:12:25  quinn
+ * Added better error checking.
+ *
+ * Revision 1.4  1995/02/10  18:57:25  quinn
+ * More in the way of error-checking.
+ *
+ * Revision 1.3  1995/02/09  15:51:48  quinn
+ * Works better now.
+ *
+ * Revision 1.2  1995/02/07  14:13:45  quinn
+ * Bug fixes.
+ *
+ * Revision 1.1  1995/02/02  16:21:53  quinn
+ * First kick.
+ *
+ */
+#if HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <yaz/odr.h>
+
+/*
+ * Top level integer en/decoder.
+ * Returns 1 on success, 0 on error.
+ */
+int odr_integer(ODR o, int **p, int opt, const char *name)
+{
+    int res, cons = 0;
+
+    if (o->error)
+        return 0;
+    if (o->t_class < 0)
+    {
+        o->t_class = ODR_UNIVERSAL;
+        o->t_tag = ODR_INTEGER;
+    }
+    if ((res = ber_tag(o, p, o->t_class, o->t_tag, &cons, opt)) < 0)
+        return 0;
+    if (!res)
+        return opt;
+    if (o->direction == ODR_PRINT)
+    {
+	odr_prname(o, name);
+        fprintf(o->print, "%d\n", **p);
+        return 1;
+    }
+    if (cons)
+    {
+        o->error = OPROTO;
+        return 0;
+    }
+    if (o->direction == ODR_DECODE)
+        *p = (int *)odr_malloc(o, sizeof(int));
+    return ber_integer(o, *p);
+}
Index: /main/tags/2.25/gsdl/packages/yaz/odr/odr_mem.c
===================================================================
--- /main/tags/2.25/gsdl/packages/yaz/odr/odr_mem.c	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/yaz/odr/odr_mem.c	(revision 21064)
@@ -0,0 +1,160 @@
+/*
+ * Copyright (c) 1995-2000, Index Data
+ * See the file LICENSE for details.
+ *
+ * $Log$
+ * Revision 1.1  2000/08/03 03:11:22  johnmcp
+ * Added the YAZ toolkit source to the packages directory (for z39.50 stuff)
+ *
+ * Revision 1.18  2000/02/29 13:44:55  adam
+ * Check for config.h (currently not generated).
+ *
+ * Revision 1.17  2000/01/31 13:15:21  adam
+ * Removed uses of assert(3). Cleanup of ODR. CCL parser update so
+ * that some characters are not surrounded by spaces in resulting term.
+ * ILL-code updates.
+ *
+ * Revision 1.16  1999/11/30 13:47:11  adam
+ * Improved installation. Moved header files to include/yaz.
+ *
+ * Revision 1.15  1999/03/31 11:18:25  adam
+ * Implemented odr_strdup. Added Reference ID to backend server API.
+ *
+ * Revision 1.14  1998/07/20 12:38:15  adam
+ * More LOG_DEBUG-diagnostics.
+ *
+ * Revision 1.13  1998/02/11 11:53:34  adam
+ * Changed code so that it compiles as C++.
+ *
+ * Revision 1.12  1995/11/08 17:41:33  quinn
+ * Smallish.
+ *
+ * Revision 1.11  1995/11/01  13:54:43  quinn
+ * Minor adjustments
+ *
+ * Revision 1.10  1995/10/25  16:58:19  quinn
+ * Stupid bug in odr_malloc
+ *
+ * Revision 1.9  1995/10/13  16:08:08  quinn
+ * Added OID utility
+ *
+ * Revision 1.8  1995/09/29  17:12:24  quinn
+ * Smallish
+ *
+ * Revision 1.7  1995/09/27  15:02:59  quinn
+ * Modified function heads & prototypes.
+ *
+ * Revision 1.6  1995/08/21  09:10:41  quinn
+ * Smallish fixes to suppport new formats.
+ *
+ * Revision 1.5  1995/05/16  08:50:55  quinn
+ * License, documentation, and memory fixes
+ *
+ * Revision 1.4  1995/05/15  11:56:09  quinn
+ * More work on memory management.
+ *
+ * Revision 1.3  1995/04/18  08:15:21  quinn
+ * Added dynamic memory allocation on encoding (whew). Code is now somewhat
+ * neater. We'll make the same change for decoding one day.
+ *
+ * Revision 1.2  1995/03/17  10:17:52  quinn
+ * Added memory management.
+ *
+ * Revision 1.1  1995/03/14  10:27:40  quinn
+ * Modified makefile to use common lib
+ * Beginning to add memory management to odr
+ *
+ */
+#if HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <stdlib.h>
+#include <yaz/odr.h>
+#include <yaz/xmalloc.h>
+
+/* ------------------------ NIBBLE MEMORY ---------------------- */
+
+/*
+ * Extract the memory control block from o.
+ */
+NMEM odr_extract_mem(ODR o)
+{
+    NMEM r = o->mem;
+
+    o->mem = 0;
+    return r;
+}
+
+void *odr_malloc(ODR o, int size)
+{
+    if (o && !o->mem)
+	o->mem = nmem_create();
+    return nmem_malloc(o ? o->mem : 0, size);
+}
+
+char *odr_strdup(ODR o, const char *str)
+{
+    return nmem_strdup(o->mem, str);
+}
+
+int odr_total(ODR o)
+{
+    return o->mem ? nmem_total(o->mem) : 0;
+}
+
+/* ---------- memory management for data encoding ----------*/
+
+
+int odr_grow_block(ODR b, int min_bytes)
+{
+    int togrow;
+
+    if (!b->can_grow)
+    	return -1;
+    if (!b->size)
+    	togrow = 1024;
+    else
+    	togrow = b->size;
+    if (togrow < min_bytes)
+    	togrow = min_bytes;
+    if (b->size && !(b->buf =
+		     (unsigned char *) xrealloc(b->buf, b->size += togrow)))
+    	abort();
+    else if (!b->size && !(b->buf = (unsigned char *)
+			   xmalloc(b->size = togrow)))
+    	abort();
+#ifdef ODR_DEBUG
+    fprintf(stderr, "New size for encode_buffer: %d\n", b->size);
+#endif
+    return 0;
+}
+
+int odr_write(ODR o, unsigned char *buf, int bytes)
+{
+    if (o->pos + bytes >= o->size && odr_grow_block(o, bytes))
+    {
+    	o->error = OSPACE;
+	return -1;
+    }
+    memcpy(o->buf + o->pos, buf, bytes);
+    o->pos += bytes;
+    if (o->pos > o->top)
+    	o->top = o->pos;
+    return 0;
+}
+
+int odr_seek(ODR o, int whence, int offset)
+{
+    if (whence == ODR_S_CUR)
+    	offset += o->pos;
+    else if (whence == ODR_S_END)
+    	offset += o->top;
+    if (offset > o->size && odr_grow_block(o, offset - o->size))
+    {
+    	o->error = OSPACE;
+	return -1;
+    }
+    o->pos = offset;
+    return 0;
+}
Index: /main/tags/2.25/gsdl/packages/yaz/odr/odr_null.c
===================================================================
--- /main/tags/2.25/gsdl/packages/yaz/odr/odr_null.c	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/yaz/odr/odr_null.c	(revision 21064)
@@ -0,0 +1,95 @@
+/*
+ * Copyright (c) 1995-2000, Index Data
+ * See the file LICENSE for details.
+ * Sebastian Hammer, Adam Dickmeiss
+ *
+ * $Log$
+ * Revision 1.1  2000/08/03 03:11:22  johnmcp
+ * Added the YAZ toolkit source to the packages directory (for z39.50 stuff)
+ *
+ * Revision 1.13  2000/02/29 13:44:55  adam
+ * Check for config.h (currently not generated).
+ *
+ * Revision 1.12  1999/11/30 13:47:11  adam
+ * Improved installation. Moved header files to include/yaz.
+ *
+ * Revision 1.11  1999/04/20 09:56:48  adam
+ * Added 'name' paramter to encoder/decoder routines (typedef Odr_fun).
+ * Modified all encoders/decoders to reflect this change.
+ *
+ * Revision 1.10  1997/11/24 11:33:56  adam
+ * Using function odr_nullval() instead of global ODR_NULLVAL when
+ * appropriate.
+ *
+ * Revision 1.9  1995/10/18 16:12:56  quinn
+ * Better diagnostics. Added special case in NULL to handle WAIS server.
+ *
+ * Revision 1.8  1995/09/29  17:12:24  quinn
+ * Smallish
+ *
+ * Revision 1.7  1995/09/27  15:02:59  quinn
+ * Modified function heads & prototypes.
+ *
+ * Revision 1.6  1995/05/22  11:32:03  quinn
+ * Fixing Interface to odr_null.
+ *
+ * Revision 1.5  1995/05/16  08:50:56  quinn
+ * License, documentation, and memory fixes
+ *
+ * Revision 1.4  1995/03/08  12:12:26  quinn
+ * Added better error checking.
+ *
+ * Revision 1.3  1995/02/10  18:57:25  quinn
+ * More in the way of error-checking.
+ *
+ * Revision 1.2  1995/02/09  15:51:49  quinn
+ * Works better now.
+ *
+ * Revision 1.1  1995/02/02  16:21:54  quinn
+ * First kick.
+ *
+ */
+#if HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <yaz/odr.h>
+
+/*
+ * Top level null en/decoder.
+ * Returns 1 on success, 0 on error.
+ */
+int odr_null(ODR o, Odr_null **p, int opt, const char *name)
+{
+    int res, cons = 0;
+
+    if (o->error)
+    	return 0;
+    if (o->t_class < 0)
+    {
+    	o->t_class = ODR_UNIVERSAL;
+    	o->t_tag = ODR_NULL;
+    }
+    if ((res = ber_tag(o, p, o->t_class, o->t_tag, &cons, opt)) < 0)
+    	return 0;
+    if (!res)
+    	return opt;
+    if (o->direction == ODR_PRINT)
+    {
+	odr_prname(o, name);
+    	fprintf(o->print, "NULL\n");
+    	return 1;
+    }
+    if (cons)
+    {
+#ifdef ODR_STRICT_NULL
+    	o->error = OPROTO;
+    	return 0;
+#else
+	fprintf(stderr, "odr: Warning: Bad NULL\n");
+#endif
+    }
+    if (o->direction == ODR_DECODE)
+    	*p = odr_nullval();
+    return ber_null(o);
+}
Index: /main/tags/2.25/gsdl/packages/yaz/odr/odr_oct.c
===================================================================
--- /main/tags/2.25/gsdl/packages/yaz/odr/odr_oct.c	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/yaz/odr/odr_oct.c	(revision 21064)
@@ -0,0 +1,160 @@
+/*
+ * Copyright (c) 1995-2000, Index Data
+ * See the file LICENSE for details.
+ * Sebastian Hammer, Adam Dickmeiss
+ *
+ * $Log$
+ * Revision 1.1  2000/08/03 03:11:23  johnmcp
+ * Added the YAZ toolkit source to the packages directory (for z39.50 stuff)
+ *
+ * Revision 1.16  2000/02/29 13:44:55  adam
+ * Check for config.h (currently not generated).
+ *
+ * Revision 1.15  1999/11/30 13:47:11  adam
+ * Improved installation. Moved header files to include/yaz.
+ *
+ * Revision 1.14  1999/10/19 12:35:55  adam
+ * Better dump of OCTET STRING.
+ *
+ * Revision 1.13  1999/04/20 09:56:48  adam
+ * Added 'name' paramter to encoder/decoder routines (typedef Odr_fun).
+ * Modified all encoders/decoders to reflect this change.
+ *
+ * Revision 1.12  1998/02/11 11:53:34  adam
+ * Changed code so that it compiles as C++.
+ *
+ * Revision 1.11  1995/09/29 17:12:25  quinn
+ * Smallish
+ *
+ * Revision 1.10  1995/09/27  15:02:59  quinn
+ * Modified function heads & prototypes.
+ *
+ * Revision 1.9  1995/05/16  08:50:56  quinn
+ * License, documentation, and memory fixes
+ *
+ * Revision 1.8  1995/03/17  10:17:54  quinn
+ * Added memory management.
+ *
+ * Revision 1.7  1995/03/08  12:12:27  quinn
+ * Added better error checking.
+ *
+ * Revision 1.6  1995/02/10  18:57:26  quinn
+ * More in the way of error-checking.
+ *
+ * Revision 1.5  1995/02/09  15:51:49  quinn
+ * Works better now.
+ *
+ * Revision 1.4  1995/02/07  14:13:46  quinn
+ * Bug fixes.
+ *
+ * Revision 1.3  1995/02/03  17:04:38  quinn
+ * *** empty log message ***
+ *
+ * Revision 1.2  1995/02/02  20:38:51  quinn
+ * Updates.
+ *
+ * Revision 1.1  1995/02/02  16:21:54  quinn
+ * First kick.
+ *
+ */
+#if HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <yaz/odr.h>
+
+/*
+ * Top level octet string en/decoder.
+ * Returns 1 on success, 0 on error.
+ */
+int odr_octetstring(ODR o, Odr_oct **p, int opt, const char *name)
+{
+    int res, cons = 0;
+
+    if (o->error)
+    	return 0;
+    if (o->t_class < 0)
+    {
+    	o->t_class = ODR_UNIVERSAL;
+    	o->t_tag = ODR_OCTETSTRING;
+    }
+    if ((res = ber_tag(o, p, o->t_class, o->t_tag, &cons, opt)) < 0)
+    	return 0;
+    if (!res)
+    	return opt;
+    if (o->direction == ODR_PRINT)
+    {
+        int i;
+	odr_prname(o, name);
+    	fprintf(o->print, "OCTETSTRING(len=%d)", (*p)->len);
+        for (i = 0; i<(*p)->len; i++)
+        {
+	    if (i < 5 || i > ((*p)->len - 4))
+            {
+                fprintf (o->print, " %02X", (*p)->buf[i]);
+            }
+            else if (i == 5)
+                fprintf (o->print, " .. ");
+        }
+        fprintf(o->print, "\n");
+    	return 1;
+    }
+    if (o->direction == ODR_DECODE)
+    {
+    	*p = (Odr_oct *)odr_malloc(o, sizeof(Odr_oct));
+    	(*p)->size= 0;
+    	(*p)->len = 0;
+    	(*p)->buf = 0;
+    }
+    if (ber_octetstring(o, *p, cons))
+    	return 1;
+    o->error = OOTHER;
+    return 0;
+}
+
+/*
+ * Friendlier interface to octetstring.
+ */
+int odr_cstring(ODR o, char **p, int opt, const char *name)
+{
+    int cons = 0, res;
+    Odr_oct *t;
+
+    if (o->error)
+    	return 0;
+    if (o->t_class < 0)
+    {
+    	o->t_class = ODR_UNIVERSAL;
+    	o->t_tag = ODR_OCTETSTRING;
+    }
+    if ((res = ber_tag(o, p, o->t_class, o->t_tag, &cons, opt)) < 0)
+    	return 0;
+    if (!res)
+    	return opt;
+    if (o->direction == ODR_PRINT)
+    {
+    	odr_prname(o, name);
+    	fprintf(o->print, "'%s'\n", *p);
+    	return 1;
+    }
+    t = (Odr_oct *)odr_malloc(o, sizeof(Odr_oct));   /* wrapper for octstring */
+    if (o->direction == ODR_ENCODE)
+    {
+    	t->buf = (unsigned char *) *p;
+    	t->size = t->len = strlen(*p);
+    }
+    else
+    {
+	t->size= 0;
+	t->len = 0;
+	t->buf = 0;
+    }
+    if (!ber_octetstring(o, t, cons))
+    	return 0;
+    if (o->direction == ODR_DECODE)
+    {
+	*p = (char *) t->buf;
+	*(*p + t->len) = '\0';  /* ber_octs reserves space for this */
+    }
+    return 1;
+}
Index: /main/tags/2.25/gsdl/packages/yaz/odr/odr_oid.c
===================================================================
--- /main/tags/2.25/gsdl/packages/yaz/odr/odr_oid.c	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/yaz/odr/odr_oid.c	(revision 21064)
@@ -0,0 +1,106 @@
+/*
+ * Copyright (c) 1995-2000, Index Data
+ * See the file LICENSE for details.
+ * Sebastian Hammer, Adam Dickmeiss
+ *
+ * $Log$
+ * Revision 1.1  2000/08/03 03:11:23  johnmcp
+ * Added the YAZ toolkit source to the packages directory (for z39.50 stuff)
+ *
+ * Revision 1.16  2000/02/29 13:44:55  adam
+ * Check for config.h (currently not generated).
+ *
+ * Revision 1.15  1999/11/30 13:47:11  adam
+ * Improved installation. Moved header files to include/yaz.
+ *
+ * Revision 1.14  1999/04/20 09:56:48  adam
+ * Added 'name' paramter to encoder/decoder routines (typedef Odr_fun).
+ * Modified all encoders/decoders to reflect this change.
+ *
+ * Revision 1.13  1998/02/11 11:53:34  adam
+ * Changed code so that it compiles as C++.
+ *
+ * Revision 1.12  1995/09/29 17:12:25  quinn
+ * Smallish
+ *
+ * Revision 1.11  1995/09/27  15:03:00  quinn
+ * Modified function heads & prototypes.
+ *
+ * Revision 1.10  1995/05/29  08:11:44  quinn
+ * Moved oid from odr/asn to util.
+ *
+ * Revision 1.9  1995/05/16  08:50:57  quinn
+ * License, documentation, and memory fixes
+ *
+ * Revision 1.8  1995/03/17  10:17:55  quinn
+ * Added memory management.
+ *
+ * Revision 1.7  1995/03/08  12:12:29  quinn
+ * Added better error checking.
+ *
+ * Revision 1.6  1995/03/01  08:40:56  quinn
+ * Smallish changes.
+ *
+ * Revision 1.5  1995/02/10  18:57:26  quinn
+ * More in the way of error-checking.
+ *
+ * Revision 1.4  1995/02/10  15:55:29  quinn
+ * Bug fixes, mostly.
+ *
+ * Revision 1.3  1995/02/09  15:51:49  quinn
+ * Works better now.
+ *
+ * Revision 1.2  1995/02/07  14:13:46  quinn
+ * Bug fixes.
+ *
+ * Revision 1.1  1995/02/03  17:04:38  quinn
+ * Initial revision
+ *
+ *
+ */
+#if HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <yaz/odr.h>
+#include <yaz/oid.h>
+
+/*
+ * Top level oid en/decoder.
+ * Returns 1 on success, 0 on error.
+ */
+int odr_oid(ODR o, Odr_oid **p, int opt, const char *name)
+{
+    int res, cons = 0;
+
+    if (o->error)
+    	return 0;
+    if (o->t_class < 0)
+    {
+    	o->t_class = ODR_UNIVERSAL;
+    	o->t_tag = ODR_OID;
+    }
+    if ((res = ber_tag(o, p, o->t_class, o->t_tag, &cons, opt)) < 0)
+    	return 0;
+    if (!res)
+    	return opt;
+    if (cons)
+    {
+    	o->error = OPROTO;
+	return 0;
+    }
+    if (o->direction == ODR_PRINT)
+    {
+    	int i;
+
+	odr_prname(o, name);
+    	fprintf(o->print, "OID:");
+    	for (i = 0; (*p)[i] > -1; i++)
+	    fprintf(o->print, " %d", (*p)[i]);
+	fprintf(o->print, "\n");
+    	return 1;
+    }
+    if (o->direction == ODR_DECODE)
+    	*p = (int *)odr_malloc(o, OID_SIZE * sizeof(**p));
+    return ber_oidc(o, *p);
+}
Index: /main/tags/2.25/gsdl/packages/yaz/odr/odr_seq.c
===================================================================
--- /main/tags/2.25/gsdl/packages/yaz/odr/odr_seq.c	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/yaz/odr/odr_seq.c	(revision 21064)
@@ -0,0 +1,239 @@
+/*
+ * Copyright (c) 1995-2000, Index Data
+ * See the file LICENSE for details.
+ * Sebastian Hammer, Adam Dickmeiss
+ *
+ * $Log$
+ * Revision 1.1  2000/08/03 03:11:24  johnmcp
+ * Added the YAZ toolkit source to the packages directory (for z39.50 stuff)
+ *
+ * Revision 1.27  2000/02/29 13:44:55  adam
+ * Check for config.h (currently not generated).
+ *
+ * Revision 1.26  2000/01/31 13:15:21  adam
+ * Removed uses of assert(3). Cleanup of ODR. CCL parser update so
+ * that some characters are not surrounded by spaces in resulting term.
+ * ILL-code updates.
+ *
+ * Revision 1.25  1999/11/30 13:47:11  adam
+ * Improved installation. Moved header files to include/yaz.
+ *
+ * Revision 1.24  1999/04/20 09:56:48  adam
+ * Added 'name' paramter to encoder/decoder routines (typedef Odr_fun).
+ * Modified all encoders/decoders to reflect this change.
+ *
+ * Revision 1.23  1998/03/20 14:45:01  adam
+ * Implemented odr_enum and odr_set_of.
+ *
+ * Revision 1.22  1998/02/11 11:53:34  adam
+ * Changed code so that it compiles as C++.
+ *
+ * Revision 1.21  1997/11/24 11:33:56  adam
+ * Using function odr_nullval() instead of global ODR_NULLVAL when
+ * appropriate.
+ *
+ * Revision 1.20  1997/09/29 07:17:31  adam
+ * Added typecast to avoid warnings on MSVC.
+ *
+ * Revision 1.19  1997/06/23 10:31:11  adam
+ * Added RVDM's SEQUENCE OF patch again!
+ *
+ * Revision 1.18  1997/05/14 06:53:58  adam
+ * C++ support.
+ *
+ * Revision 1.17  1997/05/05 11:21:09  adam
+ * In handling of SEQUENCE OF: Counter set to zero when SEQUENCE
+ * OF isn't there at all.
+ *
+ * Revision 1.16  1995/09/29 17:12:26  quinn
+ * Smallish
+ *
+ * Revision 1.15  1995/09/27  15:03:00  quinn
+ * Modified function heads & prototypes.
+ *
+ * Revision 1.14  1995/08/15  11:16:39  quinn
+ * Fixed pretty-printers.
+ *
+ * Revision 1.13  1995/05/22  14:56:57  quinn
+ * Fixed problem in decoding empty sequence.
+ *
+ * Revision 1.12  1995/05/18  13:06:32  quinn
+ * Smallish.
+ *
+ * Revision 1.11  1995/05/17  08:41:54  quinn
+ * Small, hopefully insignificant change.
+ *
+ * Revision 1.10  1995/05/16  08:50:59  quinn
+ * License, documentation, and memory fixes
+ *
+ * Revision 1.9  1995/03/17  10:17:57  quinn
+ * Added memory management.
+ *
+ * Revision 1.8  1995/03/15  11:18:05  quinn
+ * Fixed serious bug in odr_cons
+ *
+ * Revision 1.7  1995/03/08  12:12:30  quinn
+ * Added better error checking.
+ *
+ * Revision 1.6  1995/02/10  15:55:29  quinn
+ * Bug fixes, mostly.
+ *
+ * Revision 1.5  1995/02/09  15:51:49  quinn
+ * Works better now.
+ *
+ * Revision 1.4  1995/02/07  17:53:00  quinn
+ * A damn mess, but now things work, I think.
+ *
+ * Revision 1.3  1995/02/07  14:13:46  quinn
+ * Bug fixes.
+ *
+ * Revision 1.2  1995/02/06  16:45:03  quinn
+ * Small mods.
+ *
+ * Revision 1.1  1995/02/02  16:21:54  quinn
+ * First kick.
+ *
+ */
+
+#if HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <yaz/odr.h>
+
+int odr_sequence_begin(ODR o, void *p, int size, const char *name)
+{
+    char **pp = (char**) p;
+
+    if (o->error)
+    	return 0;
+    if (o->t_class < 0)
+    {
+    	o->t_class = ODR_UNIVERSAL;
+    	o->t_tag = ODR_SEQUENCE;
+    }
+    if (o->direction == ODR_DECODE)
+    	*pp = 0;
+    if (odr_constructed_begin(o, p, o->t_class, o->t_tag, name))
+    {
+    	if (o->direction == ODR_DECODE && size)
+	    *pp = (char *)odr_malloc(o, size);
+    	return 1;
+    }
+    else
+    	return 0;
+}
+
+int odr_set_begin(ODR o, void *p, int size, const char *name)
+{
+    char **pp = (char**) p;
+
+    if (o->error)
+    	return 0;
+    if (o->t_class < 0)
+    {
+    	o->t_class = ODR_UNIVERSAL;
+    	o->t_tag = ODR_SET;
+    }
+    if (o->direction == ODR_DECODE)
+    	*pp = 0;
+    if (odr_constructed_begin(o, p, o->t_class, o->t_tag, name))
+    {
+    	if (o->direction == ODR_DECODE && size)
+	    *pp = (char *)odr_malloc(o, size);
+    	return 1;
+    }
+    else
+    	return 0;
+}
+
+int odr_sequence_end(ODR o)
+{
+    return odr_constructed_end(o);    
+}
+
+int odr_set_end(ODR o)
+{
+    return odr_constructed_end(o);    
+}
+
+static int odr_sequence_more(ODR o)
+{
+    return odr_constructed_more(o);
+}
+
+static int odr_sequence_x (ODR o, Odr_fun type, void *p, int *num)
+{
+    char ***pp = (char***) p;  /* for dereferencing */
+    char **tmp = 0;
+    int size = 0, i;
+
+    switch (o->direction)
+    {
+    	case ODR_DECODE:
+	    *num = 0;
+	    *pp = (char **)odr_nullval();
+	    while (odr_sequence_more(o))
+	    {
+		/* outgrown array? */
+		if (*num * (int) sizeof(void*) >= size)
+		{
+		    /* double the buffer size */
+		    tmp = (char **)odr_malloc(o, sizeof(void*) *
+					      (size += size ? size : 128));
+		    if (*num)
+		    {
+			memcpy(tmp, *pp, *num * sizeof(void*));
+			/*
+			 * For now, we just throw the old *p away, since we use
+			 * nibble memory anyway (disgusting, isn't it?).
+			 */
+		    }
+		    *pp = tmp;
+		}
+		if (!(*type)(o, (*pp) + *num, 0, 0))
+		    return 0;
+		(*num)++;
+	    }
+	    break;
+    	case ODR_ENCODE: case ODR_PRINT:
+#ifdef ODR_DEBUG
+	    fprintf(stderr, "[seqof: num=%d]", *num);
+#endif
+	    for (i = 0; i < *num; i++)
+	    {
+#ifdef ODR_DEBUG
+		fprintf(stderr, "[seqof: elem #%d]", i);
+#endif
+	    	if (!(*type)(o, *pp + i, 0, 0))
+		    return 0;
+	    }
+	    break;
+    	default:
+	    o->error = OOTHER;
+	    return 0;
+    }
+    return odr_sequence_end(o);
+}
+
+int odr_set_of(ODR o, Odr_fun type, void *p, int *num, const char *name)
+{
+    if (!odr_set_begin(o, p, 0, name)) {
+	if (o->direction == ODR_DECODE)
+	    *num = 0;
+    	return 0;
+    }
+    return odr_sequence_x (o, type, p, num);
+}
+
+int odr_sequence_of(ODR o, Odr_fun type, void *p, int *num,
+		    const char *name)
+{
+    if (!odr_sequence_begin(o, p, 0, name)) {
+	if (o->direction == ODR_DECODE)
+	    *num = 0;
+    	return 0;
+    }
+    return odr_sequence_x (o, type, p, num);
+}
+
Index: /main/tags/2.25/gsdl/packages/yaz/odr/odr_tag.c
===================================================================
--- /main/tags/2.25/gsdl/packages/yaz/odr/odr_tag.c	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/yaz/odr/odr_tag.c	(revision 21064)
@@ -0,0 +1,93 @@
+/*
+ * Copyright (c) 1995-2000, Index Data
+ * See the file LICENSE for details.
+ * Sebastian Hammer, Adam Dickmeiss
+ *
+ * $Log$
+ * Revision 1.1  2000/08/03 03:11:24  johnmcp
+ * Added the YAZ toolkit source to the packages directory (for z39.50 stuff)
+ *
+ * Revision 1.11  2000/02/29 13:44:55  adam
+ * Check for config.h (currently not generated).
+ *
+ * Revision 1.10  1999/11/30 13:47:11  adam
+ * Improved installation. Moved header files to include/yaz.
+ *
+ * Revision 1.9  1998/02/11 11:53:34  adam
+ * Changed code so that it compiles as C++.
+ *
+ * Revision 1.8  1997/05/14 06:53:59  adam
+ * C++ support.
+ *
+ * Revision 1.7  1996/02/20 12:52:54  quinn
+ * Added odr_peektag
+ *
+ * Revision 1.6  1995/12/14  16:28:26  quinn
+ * More explain stuff.
+ *
+ * Revision 1.5  1995/09/29  17:12:27  quinn
+ * Smallish
+ *
+ * Revision 1.4  1995/09/27  15:03:00  quinn
+ * Modified function heads & prototypes.
+ *
+ * Revision 1.3  1995/05/16  08:51:00  quinn
+ * License, documentation, and memory fixes
+ *
+ * Revision 1.2  1995/03/08  12:12:31  quinn
+ * Added better error checking.
+ *
+ * Revision 1.1  1995/02/02  16:21:54  quinn
+ * First kick.
+ *
+ */
+#if HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <yaz/odr.h>
+
+int odr_peektag(ODR o, int *zclass, int *tag, int *cons)
+{
+    if (o->direction != ODR_DECODE)
+    {
+	o->error = OOTHER;
+	return 0;
+    }
+    if (o->stackp > -1 && !odr_constructed_more(o))
+	return 0;
+    if (ber_dectag(o->bp, zclass, tag, cons) <= 0)
+    {
+	o->error = OREQUIRED;
+	return 0;
+    }
+    return 1;
+}
+
+int odr_implicit_settag(ODR o, int zclass, int tag)
+{
+    if (o->error)
+    	return 0;
+    if (o->t_class < 0)
+    {
+	o->t_class = zclass;
+	o->t_tag = tag;
+    }
+    return 1;
+}
+
+int odr_initmember(ODR o, void *p, int size)
+{
+    char **pp = (char **) p;
+
+    if (o->error)
+	return 0;
+    if (o->direction == ODR_DECODE)
+	*pp = (char *)odr_malloc(o, size);
+    else if (!*pp)
+    {
+	o->t_class = -1;
+	return 0;
+    }
+    return 1;
+}
Index: /main/tags/2.25/gsdl/packages/yaz/odr/odr_use.c
===================================================================
--- /main/tags/2.25/gsdl/packages/yaz/odr/odr_use.c	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/yaz/odr/odr_use.c	(revision 21064)
@@ -0,0 +1,103 @@
+/*
+ * Copyright (c) 1995-2000, Index Data
+ * See the file LICENSE for details.
+ * Sebastian Hammer, Adam Dickmeiss
+ *
+ * $Log$
+ * Revision 1.1  2000/08/03 03:11:25  johnmcp
+ * Added the YAZ toolkit source to the packages directory (for z39.50 stuff)
+ *
+ * Revision 1.11  2000/02/29 13:44:55  adam
+ * Check for config.h (currently not generated).
+ *
+ * Revision 1.10  1999/11/30 13:47:12  adam
+ * Improved installation. Moved header files to include/yaz.
+ *
+ * Revision 1.9  1999/04/20 09:56:48  adam
+ * Added 'name' paramter to encoder/decoder routines (typedef Odr_fun).
+ * Modified all encoders/decoders to reflect this change.
+ *
+ * Revision 1.8  1998/02/11 11:53:34  adam
+ * Changed code so that it compiles as C++.
+ *
+ * Revision 1.7  1995/09/29 17:12:27  quinn
+ * Smallish
+ *
+ * Revision 1.6  1995/09/27  15:03:00  quinn
+ * Modified function heads & prototypes.
+ *
+ * Revision 1.5  1995/08/10  08:54:47  quinn
+ * Added Explain.
+ *
+ * Revision 1.4  1995/06/16  13:16:12  quinn
+ * Fixed Defaultdiagformat.
+ *
+ * Revision 1.3  1995/05/16  08:51:00  quinn
+ * License, documentation, and memory fixes
+ *
+ * Revision 1.2  1995/02/09  15:51:50  quinn
+ * Works better now.
+ *
+ * Revision 1.1  1995/02/03  17:04:39  quinn
+ * Initial revision
+ *
+ */
+#if HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <yaz/odr.h>
+
+int odr_external(ODR o, Odr_external **p, int opt, const char *name)
+{
+    Odr_external *pp;
+    static Odr_arm arm[] =
+    {
+    	{ODR_EXPLICIT, ODR_CONTEXT, 0, ODR_EXTERNAL_single, 
+	 (Odr_fun)odr_any, "single"},
+    	{ODR_IMPLICIT, ODR_CONTEXT, 1, ODR_EXTERNAL_octet,
+	 (Odr_fun)odr_octetstring, "octet"},
+    	{ODR_IMPLICIT, ODR_CONTEXT, 2, ODR_EXTERNAL_arbitrary,
+	 (Odr_fun)odr_bitstring, "arbitrary"},
+    	{-1, -1, -1, -1, 0, 0}
+    };
+
+    odr_implicit_settag(o, ODR_UNIVERSAL, ODR_EXTERNAL);
+    if (!odr_sequence_begin(o, p, sizeof(Odr_external), name))
+    	return opt;
+    pp = *p;
+    return
+    	odr_oid(o, &pp->direct_reference, 1, "direct") &&
+    	odr_integer(o, &pp->indirect_reference, 1, "indirect") &&
+    	odr_graphicstring(o, &pp->descriptor, 1, "descriptor") &&
+    	odr_choice(o, arm, &pp->u, &pp->which, 0) &&
+	odr_sequence_end(o);
+}
+
+int odr_visiblestring(ODR o, char **p, int opt, const char *name)
+{
+    return odr_implicit_tag(o, odr_cstring, p, ODR_UNIVERSAL,
+			    ODR_VISIBLESTRING, opt, name);
+}    
+
+/*
+ * a char may not be sufficient to hold a general string, but we'll deal
+ * with that once we start looking more closely at UniCode & co.
+ */
+int odr_generalstring(ODR o, char **p, int opt, const char *name)
+{
+    return odr_implicit_tag(o, odr_cstring, p, ODR_UNIVERSAL,
+			    ODR_GENERALSTRING,opt, name);
+}    
+
+int odr_graphicstring(ODR o, char **p, int opt, const char *name)
+{
+    return odr_implicit_tag(o, odr_cstring, p, ODR_UNIVERSAL,
+			ODR_GRAPHICSTRING, opt, name);
+}    
+
+int odr_generalizedtime(ODR o, char **p, int opt, const char *name)
+{
+    return odr_implicit_tag(o, odr_cstring, p, ODR_UNIVERSAL,
+			    ODR_GENERALIZEDTIME, opt, name);
+}
Index: /main/tags/2.25/gsdl/packages/yaz/odr/odr_util.c
===================================================================
--- /main/tags/2.25/gsdl/packages/yaz/odr/odr_util.c	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/yaz/odr/odr_util.c	(revision 21064)
@@ -0,0 +1,115 @@
+/*
+ * Copyright (c) 1995-2000, Index Data
+ * See the file LICENSE for details.
+ *
+ * $Log$
+ * Revision 1.1  2000/08/03 03:11:26  johnmcp
+ * Added the YAZ toolkit source to the packages directory (for z39.50 stuff)
+ *
+ * Revision 1.19  2000/02/29 13:44:55  adam
+ * Check for config.h (currently not generated).
+ *
+ * Revision 1.18  2000/01/31 13:15:21  adam
+ * Removed uses of assert(3). Cleanup of ODR. CCL parser update so
+ * that some characters are not surrounded by spaces in resulting term.
+ * ILL-code updates.
+ *
+ * Revision 1.17  1999/11/30 13:47:12  adam
+ * Improved installation. Moved header files to include/yaz.
+ *
+ * Revision 1.16  1999/04/20 09:56:48  adam
+ * Added 'name' paramter to encoder/decoder routines (typedef Odr_fun).
+ * Modified all encoders/decoders to reflect this change.
+ *
+ * Revision 1.15  1999/01/08 11:23:29  adam
+ * Added const modifier to some of the BER/ODR encoding routines.
+ *
+ * Revision 1.14  1998/10/13 15:58:36  adam
+ * Minor fix in odr_getoidbystr_nmem.
+ *
+ * Revision 1.13  1998/02/11 11:53:34  adam
+ * Changed code so that it compiles as C++.
+ *
+ * Revision 1.12  1997/10/31 12:20:08  adam
+ * Improved memory debugging for xmalloc/nmem.c. References to NMEM
+ * instead of ODR in n ESPEC-1 handling in source d1_espec.c.
+ * Bug fix: missing fclose in data1_read_espec1.
+ *
+ */
+#if HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <stdlib.h>
+#include <string.h>
+#include <ctype.h>
+#include <yaz/odr.h>
+#include <yaz/oid.h>
+
+void odr_prname(ODR o, const char *name)
+{
+    if (name)
+	fprintf (o->print, "%*s%s ", o->indent*4, "", name);
+    else
+	fprintf (o->print, "%*s", o->indent*4, "");
+}
+
+int odp_more_chunks(ODR o, const unsigned char *base, int len)
+{
+    if (!len)
+    	return 0;
+    if (len < 0) /* indefinite length */
+    {
+	if (*o->bp == 0 && *(o->bp + 1) == 0)
+	{
+	    o->bp += 2;
+	    return 0;
+	}
+	else
+	    return 1;
+    }
+    else
+        return o->bp - base < len;
+}
+
+Odr_oid *odr_oiddup_nmem(NMEM nmem, Odr_oid *o)
+{
+    Odr_oid *r;
+
+    if (!o)
+    	return 0;
+    if (!(r = (int *)nmem_malloc(nmem, (oid_oidlen(o) + 1) * sizeof(int))))
+    	return 0;
+    oid_oidcpy(r, o);
+    return r;
+}
+
+Odr_oid *odr_oiddup(ODR odr, Odr_oid *o)
+{
+    return odr_oiddup_nmem (odr->mem, o);
+}
+
+Odr_oid *odr_getoidbystr_nmem(NMEM nmem, char *str)
+{
+    int num = 1, i = 0;
+    char *p = str;
+    Odr_oid *ret;
+
+    if (!isdigit(*str))
+	return 0;
+    while ((p = strchr(p, '.')))
+	num++, p++;
+    ret = (int *)nmem_malloc(nmem, sizeof(*ret)*(num + 1));
+    p = str;
+    do
+	ret[i++] = atoi(p);
+    while ((p = strchr(p, '.')) && *++p);
+    ret[i] = -1;
+    return ret;
+}
+
+Odr_oid *odr_getoidbystr(ODR o, char *str)
+{
+    return odr_getoidbystr_nmem (o->mem, str);
+}
+
Index: /main/tags/2.25/gsdl/packages/yaz/retrieval/Makefile.am
===================================================================
--- /main/tags/2.25/gsdl/packages/yaz/retrieval/Makefile.am	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/yaz/retrieval/Makefile.am	(revision 21064)
@@ -0,0 +1,10 @@
+## $Id$
+
+noinst_LIBRARIES=libret.a
+
+libret_a_SOURCES = d1_handle.c d1_read.c d1_attset.c d1_tagset.c d1_absyn.c \
+  d1_grs.c d1_sutrs.c d1_varset.c d1_espec.c d1_doespec.c d1_map.c d1_marc.c\
+  d1_write.c d1_expout.c d1_sumout.c d1_soif.c d1_prtree.c d1_if.c
+
+INCLUDES=-I../include 
+
Index: /main/tags/2.25/gsdl/packages/yaz/retrieval/Makefile.in
===================================================================
--- /main/tags/2.25/gsdl/packages/yaz/retrieval/Makefile.in	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/yaz/retrieval/Makefile.in	(revision 21064)
@@ -0,0 +1,270 @@
+# Makefile.in generated automatically by automake 1.4 from Makefile.am
+
+# Copyright (C) 1994, 1995-8, 1999 Free Software Foundation, Inc.
+# This Makefile.in is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
+# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE.
+
+
+SHELL = @SHELL@
+
+srcdir = @srcdir@
+top_srcdir = @top_srcdir@
+VPATH = @srcdir@
+prefix = @prefix@
+exec_prefix = @exec_prefix@
+
+bindir = @bindir@
+sbindir = @sbindir@
+libexecdir = @libexecdir@
+datadir = @datadir@
+sysconfdir = @sysconfdir@
+sharedstatedir = @sharedstatedir@
+localstatedir = @localstatedir@
+libdir = @libdir@
+infodir = @infodir@
+mandir = @mandir@
+includedir = @includedir@
+oldincludedir = /usr/include
+
+DESTDIR =
+
+pkgdatadir = $(datadir)/@PACKAGE@
+pkglibdir = $(libdir)/@PACKAGE@
+pkgincludedir = $(includedir)/@PACKAGE@
+
+top_builddir = ..
+
+ACLOCAL = @ACLOCAL@
+AUTOCONF = @AUTOCONF@
+AUTOMAKE = @AUTOMAKE@
+AUTOHEADER = @AUTOHEADER@
+
+INSTALL = @INSTALL@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@ $(AM_INSTALL_PROGRAM_FLAGS)
+INSTALL_DATA = @INSTALL_DATA@
+INSTALL_SCRIPT = @INSTALL_SCRIPT@
+transform = @program_transform_name@
+
+NORMAL_INSTALL = :
+PRE_INSTALL = :
+POST_INSTALL = :
+NORMAL_UNINSTALL = :
+PRE_UNINSTALL = :
+POST_UNINSTALL = :
+ASNMODULE = @ASNMODULE@
+CC = @CC@
+CPP = @CPP@
+ILLLIB = @ILLLIB@
+ILLMODULE = @ILLMODULE@
+MAKEINFO = @MAKEINFO@
+PACKAGE = @PACKAGE@
+RANLIB = @RANLIB@
+SUBDIRS_VAR = @SUBDIRS_VAR@
+VERSION = @VERSION@
+have_sgml2html = @have_sgml2html@
+have_sgml2latex = @have_sgml2latex@
+have_sgml2txt = @have_sgml2txt@
+
+noinst_LIBRARIES = libret.a
+
+libret_a_SOURCES = d1_handle.c d1_read.c d1_attset.c d1_tagset.c d1_absyn.c   d1_grs.c d1_sutrs.c d1_varset.c d1_espec.c d1_doespec.c d1_map.c d1_marc.c   d1_write.c d1_expout.c d1_sumout.c d1_soif.c d1_prtree.c d1_if.c
+
+
+INCLUDES = -I../include 
+mkinstalldirs = $(SHELL) $(top_srcdir)/mkinstalldirs
+CONFIG_CLEAN_FILES = 
+LIBRARIES =  $(noinst_LIBRARIES)
+
+
+DEFS = @DEFS@ -I. -I$(srcdir) 
+CPPFLAGS = @CPPFLAGS@
+LDFLAGS = @LDFLAGS@
+LIBS = @LIBS@
+libret_a_LIBADD = 
+libret_a_OBJECTS =  d1_handle.o d1_read.o d1_attset.o d1_tagset.o \
+d1_absyn.o d1_grs.o d1_sutrs.o d1_varset.o d1_espec.o d1_doespec.o \
+d1_map.o d1_marc.o d1_write.o d1_expout.o d1_sumout.o d1_soif.o \
+d1_prtree.o d1_if.o
+AR = ar
+CFLAGS = @CFLAGS@
+COMPILE = $(CC) $(DEFS) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
+CCLD = $(CC)
+LINK = $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(LDFLAGS) -o $@
+DIST_COMMON =  Makefile.am Makefile.in
+
+
+DISTFILES = $(DIST_COMMON) $(SOURCES) $(HEADERS) $(TEXINFOS) $(EXTRA_DIST)
+
+TAR = gtar
+GZIP_ENV = --best
+SOURCES = $(libret_a_SOURCES)
+OBJECTS = $(libret_a_OBJECTS)
+
+all: all-redirect
+.SUFFIXES:
+.SUFFIXES: .S .c .o .s
+$(srcdir)/Makefile.in: Makefile.am $(top_srcdir)/configure.in $(ACLOCAL_M4) 
+	cd $(top_srcdir) && $(AUTOMAKE) --gnu --include-deps retrieval/Makefile
+
+Makefile: $(srcdir)/Makefile.in  $(top_builddir)/config.status
+	cd $(top_builddir) \
+	  && CONFIG_FILES=$(subdir)/$@ CONFIG_HEADERS= $(SHELL) ./config.status
+
+
+mostlyclean-noinstLIBRARIES:
+
+clean-noinstLIBRARIES:
+	-test -z "$(noinst_LIBRARIES)" || rm -f $(noinst_LIBRARIES)
+
+distclean-noinstLIBRARIES:
+
+maintainer-clean-noinstLIBRARIES:
+
+.c.o:
+	$(COMPILE) -c $<
+
+.s.o:
+	$(COMPILE) -c $<
+
+.S.o:
+	$(COMPILE) -c $<
+
+mostlyclean-compile:
+	-rm -f *.o core *.core
+
+clean-compile:
+
+distclean-compile:
+	-rm -f *.tab.c
+
+maintainer-clean-compile:
+
+libret.a: $(libret_a_OBJECTS) $(libret_a_DEPENDENCIES)
+	-rm -f libret.a
+	$(AR) cru libret.a $(libret_a_OBJECTS) $(libret_a_LIBADD)
+	$(RANLIB) libret.a
+
+tags: TAGS
+
+ID: $(HEADERS) $(SOURCES) $(LISP)
+	list='$(SOURCES) $(HEADERS)'; \
+	unique=`for i in $$list; do echo $$i; done | \
+	  awk '    { files[$$0] = 1; } \
+	       END { for (i in files) print i; }'`; \
+	here=`pwd` && cd $(srcdir) \
+	  && mkid -f$$here/ID $$unique $(LISP)
+
+TAGS:  $(HEADERS) $(SOURCES)  $(TAGS_DEPENDENCIES) $(LISP)
+	tags=; \
+	here=`pwd`; \
+	list='$(SOURCES) $(HEADERS)'; \
+	unique=`for i in $$list; do echo $$i; done | \
+	  awk '    { files[$$0] = 1; } \
+	       END { for (i in files) print i; }'`; \
+	test -z "$(ETAGS_ARGS)$$unique$(LISP)$$tags" \
+	  || (cd $(srcdir) && etags $(ETAGS_ARGS) $$tags  $$unique $(LISP) -o $$here/TAGS)
+
+mostlyclean-tags:
+
+clean-tags:
+
+distclean-tags:
+	-rm -f TAGS ID
+
+maintainer-clean-tags:
+
+distdir = $(top_builddir)/$(PACKAGE)-$(VERSION)/$(subdir)
+
+subdir = retrieval
+
+distdir: $(DISTFILES)
+	@for file in $(DISTFILES); do \
+	  d=$(srcdir); \
+	  if test -d $$d/$$file; then \
+	    cp -pr $$/$$file $(distdir)/$$file; \
+	  else \
+	    test -f $(distdir)/$$file \
+	    || ln $$d/$$file $(distdir)/$$file 2> /dev/null \
+	    || cp -p $$d/$$file $(distdir)/$$file || :; \
+	  fi; \
+	done
+
+info-am:
+info: info-am
+dvi-am:
+dvi: dvi-am
+check-am: all-am
+check: check-am
+installcheck-am:
+installcheck: installcheck-am
+install-exec-am:
+install-exec: install-exec-am
+
+install-data-am:
+install-data: install-data-am
+
+install-am: all-am
+	@$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
+install: install-am
+uninstall-am:
+uninstall: uninstall-am
+all-am: Makefile $(LIBRARIES)
+all-redirect: all-am
+install-strip:
+	$(MAKE) $(AM_MAKEFLAGS) AM_INSTALL_PROGRAM_FLAGS=-s install
+installdirs:
+
+
+mostlyclean-generic:
+
+clean-generic:
+
+distclean-generic:
+	-rm -f Makefile $(CONFIG_CLEAN_FILES)
+	-rm -f config.cache config.log stamp-h stamp-h[0-9]*
+
+maintainer-clean-generic:
+mostlyclean-am:  mostlyclean-noinstLIBRARIES mostlyclean-compile \
+		mostlyclean-tags mostlyclean-generic
+
+mostlyclean: mostlyclean-am
+
+clean-am:  clean-noinstLIBRARIES clean-compile clean-tags clean-generic \
+		mostlyclean-am
+
+clean: clean-am
+
+distclean-am:  distclean-noinstLIBRARIES distclean-compile \
+		distclean-tags distclean-generic clean-am
+
+distclean: distclean-am
+
+maintainer-clean-am:  maintainer-clean-noinstLIBRARIES \
+		maintainer-clean-compile maintainer-clean-tags \
+		maintainer-clean-generic distclean-am
+	@echo "This command is intended for maintainers to use;"
+	@echo "it deletes files that may require special tools to rebuild."
+
+maintainer-clean: maintainer-clean-am
+
+.PHONY: mostlyclean-noinstLIBRARIES distclean-noinstLIBRARIES \
+clean-noinstLIBRARIES maintainer-clean-noinstLIBRARIES \
+mostlyclean-compile distclean-compile clean-compile \
+maintainer-clean-compile tags mostlyclean-tags distclean-tags \
+clean-tags maintainer-clean-tags distdir info-am info dvi-am dvi check \
+check-am installcheck-am installcheck install-exec-am install-exec \
+install-data-am install-data install-am install uninstall-am uninstall \
+all-redirect all-am all installdirs mostlyclean-generic \
+distclean-generic clean-generic maintainer-clean-generic clean \
+mostlyclean distclean maintainer-clean
+
+
+# Tell versions [3.59,3.63) of GNU make to not export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:
Index: /main/tags/2.25/gsdl/packages/yaz/retrieval/d1_absyn.c
===================================================================
--- /main/tags/2.25/gsdl/packages/yaz/retrieval/d1_absyn.c	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/yaz/retrieval/d1_absyn.c	(revision 21064)
@@ -0,0 +1,792 @@
+/*
+ * Copyright (c) 1995-1999, Index Data.
+ * See the file LICENSE for details.
+ * Sebastian Hammer, Adam Dickmeiss
+ *
+ * $Log$
+ * Revision 1.1  2000/08/03 03:11:27  johnmcp
+ * Added the YAZ toolkit source to the packages directory (for z39.50 stuff)
+ *
+ * Revision 1.27  1999/12/21 14:16:19  ian
+ * Changed retrieval module to allow data1 trees with no associated absyn.
+ * Also added a simple interface for extracting values from data1 trees using
+ * a string based tagpath.
+ *
+ * Revision 1.26  1999/11/30 13:47:12  adam
+ * Improved installation. Moved header files to include/yaz.
+ *
+ * Revision 1.25  1999/10/21 12:06:29  adam
+ * Retrieval module no longer uses ctype.h - functions.
+ *
+ * Revision 1.24  1999/08/27 09:40:32  adam
+ * Renamed logf function to yaz_log. Removed VC++ project files.
+ *
+ * Revision 1.23  1998/10/15 08:29:16  adam
+ * Tag set type may be specified in reference to it using "tagset"
+ * directive in .abs-files and "include" directive in .tag-files.
+ *
+ * Revision 1.22  1998/10/13 16:09:47  adam
+ * Added support for arbitrary OID's for tagsets, schemas and attribute sets.
+ * Added support for multiple attribute set references and tagset references
+ * from an abstract syntax file.
+ * Fixed many bad logs-calls in routines that read the various
+ * specifications regarding data1 (*.abs,*.att,...) and made the messages
+ * consistent whenever possible.
+ * Added extra 'lineno' argument to function readconf_line.
+ *
+ * Revision 1.21  1998/06/09 13:55:07  adam
+ * Minor changes.
+ *
+ * Revision 1.20  1998/05/18 13:07:02  adam
+ * Changed the way attribute sets are handled by the retriaval module.
+ * Extended Explain conversion / schema.
+ * Modified server and client to work with ASN.1 compiled protocol handlers.
+ *
+ * Revision 1.19  1998/03/05 08:15:32  adam
+ * Implemented data1_add_insert_taggeddata utility which is more flexible
+ * than data1_insert_taggeddata.
+ *
+ * Revision 1.18  1998/02/27 14:08:04  adam
+ * Added const to some char pointer arguments.
+ * Reworked data1_read_node so that it doesn't create a tree with
+ * pointers to original "SGML"-buffer.
+ *
+ * Revision 1.17  1998/02/11 11:53:34  adam
+ * Changed code so that it compiles as C++.
+ *
+ * Revision 1.16  1997/12/18 10:51:30  adam
+ * Implemented sub-trees feature for schemas - including forward
+ * references.
+ *
+ * Revision 1.15  1997/12/09 16:18:16  adam
+ * Work on EXPLAIN schema. First implementation of sub-schema facility
+ * in the *.abs files.
+ *
+ * Revision 1.14  1997/10/31 12:20:09  adam
+ * Improved memory debugging for xmalloc/nmem.c. References to NMEM
+ * instead of ODR in n ESPEC-1 handling in source d1_espec.c.
+ * Bug fix: missing fclose in data1_read_espec1.
+ *
+ * Revision 1.13  1997/10/27 13:54:18  adam
+ * Changed structure field in data1 node to be simple string which
+ * is "unknown" to the retrieval system itself.
+ *
+ * Revision 1.12  1997/09/17 12:10:34  adam
+ * YAZ version 1.4.
+ *
+ * Revision 1.11  1997/09/05 09:50:55  adam
+ * Removed global data1_tabpath - uses data1_get_tabpath() instead.
+ *
+ * Revision 1.10  1997/05/14 06:54:01  adam
+ * C++ support.
+ *
+ * Revision 1.9  1997/02/19 14:46:15  adam
+ * The "all" specifier only affects elements that are indexed (and not
+ * all elements).
+ *
+ * Revision 1.8  1997/01/02 10:47:59  quinn
+ * Added optional, physical ANY
+ *
+ * Revision 1.7  1996/06/10 08:56:01  quinn
+ * Work on Summary.
+ *
+ * Revision 1.6  1996/05/31  13:52:21  quinn
+ * Fixed uninitialized variable for local tags in abstract syntax.
+ *
+ * Revision 1.5  1996/05/09  07:27:43  quinn
+ * Multiple local attributes values supported.
+ *
+ * Revision 1.4  1996/05/01  12:45:28  quinn
+ * Support use of local tag names in abs file.
+ *
+ * Revision 1.3  1995/11/01  16:34:55  quinn
+ * Making data1 look for tables in data1_tabpath
+ *
+ * Revision 1.2  1995/11/01  13:54:44  quinn
+ * Minor adjustments
+ *
+ * Revision 1.1  1995/11/01  11:56:06  quinn
+ * Added Retrieval (data management) functions en masse.
+ *
+ */
+
+#include <stdio.h>
+#include <assert.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <yaz/oid.h>
+#include <yaz/log.h>
+#include <yaz/data1.h>
+
+#define D1_MAX_NESTING  128
+
+struct data1_absyn_cache_info 
+{
+    char *name;
+    data1_absyn *absyn;
+    data1_absyn_cache next;
+};
+
+struct data1_attset_cache_info 
+{
+    char *name;
+    data1_attset *attset;
+    data1_attset_cache next;
+};
+
+data1_absyn *data1_absyn_search (data1_handle dh, const char *name)
+{
+    data1_absyn_cache p = *data1_absyn_cache_get (dh);
+
+    while (p)
+    {
+	if (!strcmp (name, p->name))
+	    return p->absyn;
+	p = p->next;
+    }
+    return NULL;
+}
+
+void data1_absyn_trav (data1_handle dh, void *handle,
+		       void (*fh)(data1_handle dh, void *h, data1_absyn *a))
+{
+    data1_absyn_cache p = *data1_absyn_cache_get (dh);
+
+    while (p)
+    {
+	(*fh)(dh, handle, p->absyn);
+	p = p->next;
+    }
+}
+
+data1_absyn *data1_absyn_add (data1_handle dh, const char *name)
+{
+    char fname[512];
+    NMEM mem = data1_nmem_get (dh);
+
+    data1_absyn_cache p = (data1_absyn_cache)nmem_malloc (mem, sizeof(*p));
+    data1_absyn_cache *pp = data1_absyn_cache_get (dh);
+
+    sprintf(fname, "%s.abs", name);
+    p->absyn = data1_read_absyn (dh, fname);
+    p->name = nmem_strdup (mem, name);
+    p->next = *pp;
+    *pp = p;
+    return p->absyn;
+}
+
+data1_absyn *data1_get_absyn (data1_handle dh, const char *name)
+{
+    data1_absyn *absyn;
+
+    if (!(absyn = data1_absyn_search (dh, name)))
+	absyn = data1_absyn_add (dh, name);
+    return absyn;
+}
+
+data1_attset *data1_attset_search_name (data1_handle dh, const char *name)
+{
+    data1_attset_cache p = *data1_attset_cache_get (dh);
+
+    while (p)
+    {
+	if (!strcmp (name, p->name))
+	    return p->attset;
+	p = p->next;
+    }
+    return NULL;
+}
+
+data1_attset *data1_attset_search_id (data1_handle dh, int id)
+{
+    data1_attset_cache p = *data1_attset_cache_get (dh);
+
+    while (p)
+    {
+	if (id == p->attset->reference)
+	    return p->attset;
+	p = p->next;
+    }
+    return NULL;
+}
+
+data1_attset *data1_attset_add (data1_handle dh, const char *name)
+{
+    char fname[512], aname[512];
+    NMEM mem = data1_nmem_get (dh);
+    data1_attset *attset;
+
+    strcpy (aname, name);
+    sprintf(fname, "%s.att", name);
+    attset = data1_read_attset (dh, fname);
+    if (!attset)
+    {
+	char *cp;
+	attset = data1_read_attset (dh, name);
+	if (attset && (cp = strrchr (aname, '.')))
+	    *cp = '\0';
+    }
+    if (!attset)
+	yaz_log (LOG_WARN|LOG_ERRNO, "Couldn't load attribute set %s", name);
+    else
+    {
+	data1_attset_cache p = (data1_attset_cache)
+	    nmem_malloc (mem, sizeof(*p));
+	data1_attset_cache *pp = data1_attset_cache_get (dh);
+	
+	attset->name = p->name = nmem_strdup (mem, aname);
+	p->attset = attset;
+	p->next = *pp;
+	*pp = p;
+    }
+    return attset;
+}
+
+data1_attset *data1_get_attset (data1_handle dh, const char *name)
+{
+    data1_attset *attset;
+
+    if (!(attset = data1_attset_search_name (dh, name)))
+	attset = data1_attset_add (dh, name);
+    return attset;
+}
+
+data1_esetname *data1_getesetbyname(data1_handle dh, data1_absyn *a,
+				    const char *name)
+{
+    data1_esetname *r;
+
+    for (r = a->esetnames; r; r = r->next)
+	if (!data1_matchstr(r->name, name))
+	    return r;
+    return 0;
+}
+
+data1_element *data1_getelementbytagname (data1_handle dh, data1_absyn *abs,
+					  data1_element *parent,
+					  const char *tagname)
+{
+    data1_element *r;
+
+    /* It's now possible to have a data1 tree with no abstract syntax */
+    if ( !abs )
+        return 0;
+
+    if (!parent)
+        r = abs->main_elements;
+    else
+	r = parent->children;
+    assert (abs->main_elements);
+    for (; r; r = r->next)
+    {
+	data1_name *n;
+
+	for (n = r->tag->names; n; n = n->next)
+	    if (!data1_matchstr(tagname, n->name))
+		return r;
+    }
+    return 0;
+}
+
+data1_element *data1_getelementbyname (data1_handle dh, data1_absyn *absyn,
+				       const char *name)
+{
+    data1_element *r;
+
+    /* It's now possible to have a data1 tree with no abstract syntax */
+    if ( !absyn )
+        return 0;
+    
+    assert (absyn->main_elements);
+    for (r = absyn->main_elements; r; r = r->next)
+	if (!data1_matchstr(r->name, name))
+	    return r;
+    return 0;
+}
+
+
+void fix_element_ref (data1_handle dh, data1_absyn *absyn, data1_element *e)
+{
+    /* It's now possible to have a data1 tree with no abstract syntax */
+    if ( !absyn )
+        return;
+
+    for (; e; e = e->next)
+    {
+	if (!e->sub_name)
+	{
+	    if (e->children)
+		fix_element_ref (dh, absyn, e->children);
+	}
+	else
+	{
+	    data1_sub_elements *sub_e = absyn->sub_elements;
+	    while (sub_e && strcmp (e->sub_name, sub_e->name))
+		sub_e = sub_e->next;
+	    if (sub_e)
+		e->children = sub_e->elements;
+	    else
+		yaz_log (LOG_WARN, "Unresolved reference to sub-elements %s",
+		      e->sub_name);
+	}
+    }
+}
+
+data1_absyn *data1_read_absyn (data1_handle dh, const char *file)
+{
+    data1_sub_elements *cur_elements = NULL;
+    data1_absyn *res = 0;
+    FILE *f;
+    data1_element **ppl[D1_MAX_NESTING];
+    data1_esetname **esetpp;
+    data1_maptab **maptabp;
+    data1_marctab **marcp;
+    data1_termlist *all = 0;
+    data1_attset_child **attset_childp;
+    data1_tagset **tagset_childp;
+    int level = 0;
+    int lineno = 0;
+    int argc;
+    char *argv[50], line[512];
+
+    if (!(f = yaz_path_fopen(data1_get_tabpath (dh), file, "r")))
+    {
+	yaz_log(LOG_WARN|LOG_ERRNO, "Couldn't open %s", file);
+	return 0;
+    }
+    
+    res = (data1_absyn *) nmem_malloc(data1_nmem_get(dh), sizeof(*res));
+    res->name = 0;
+    res->reference = VAL_NONE;
+    res->tagset = 0;
+    tagset_childp = &res->tagset;
+
+    res->attset = data1_empty_attset (dh);
+    attset_childp =  &res->attset->children;
+
+    res->varset = 0;
+    res->esetnames = 0;
+    esetpp = &res->esetnames;
+    res->maptabs = 0;
+    maptabp = &res->maptabs;
+    res->marc = 0;
+    marcp = &res->marc;
+
+    res->sub_elements = NULL;
+    res->main_elements = NULL;
+
+    while ((argc = readconf_line(f, &lineno, line, 512, argv, 50)))
+    {
+	char *cmd = *argv;
+	if (!strcmp(cmd, "elm"))
+	{
+	    data1_element *new_element;
+	    int i;
+	    char *p, *sub_p, *path, *name, *termlists;
+	    int type, value;
+	    data1_termlist **tp;
+
+	    if (argc < 4)
+	    {
+		yaz_log(LOG_WARN, "%s:%d: Bad # of args to elm", file, lineno);
+		continue;
+	    }
+	    path = argv[1];
+	    name = argv[2];
+	    termlists = argv[3];
+
+	    if (!cur_elements)
+	    {
+                cur_elements = (data1_sub_elements *)
+		    nmem_malloc(data1_nmem_get(dh), sizeof(*cur_elements));
+	        cur_elements->next = res->sub_elements;
+		cur_elements->elements = NULL;
+		cur_elements->name = "main";
+		res->sub_elements = cur_elements;
+		
+		level = 0;
+    		ppl[level] = &cur_elements->elements;
+            }
+	    p = path;
+	    for (i = 0;; i++)
+	    {
+		char *e;
+
+		if ((e = strchr(p, '/')))
+		    p = e+1;
+		else
+		    break;
+	    }
+	    if (i > level + 1)
+	    {
+		yaz_log(LOG_WARN, "%s:%d: Bad level increase", file, lineno);
+		fclose(f);
+		return 0;
+	    }
+	    level = i;
+	    new_element = *ppl[level] = (data1_element *)
+		nmem_malloc(data1_nmem_get(dh), sizeof(*new_element));
+	    new_element->next = new_element->children = 0;
+	    new_element->tag = 0;
+	    new_element->termlists = 0;
+	    new_element->sub_name = 0;
+	    
+	    tp = &new_element->termlists;
+	    ppl[level] = &new_element->next;
+	    ppl[level+1] = &new_element->children;
+	    
+	    /* consider subtree (if any) ... */
+	    if ((sub_p = strchr (p, ':')) && sub_p[1])
+	    {
+		*sub_p++ = '\0';
+		new_element->sub_name =
+		    nmem_strdup (data1_nmem_get(dh), sub_p);		
+	    }
+	    /* well-defined tag */
+	    if (sscanf(p, "(%d,%d)", &type, &value) == 2)
+	    {
+		if (!res->tagset)
+		{
+		    yaz_log(LOG_WARN, "%s:%d: No tagset loaded", file, lineno);
+		    fclose(f);
+		    return 0;
+		}
+		if (!(new_element->tag = data1_gettagbynum (dh, res->tagset,
+							    type, value)))
+		{
+		    yaz_log(LOG_WARN, "%s:%d: Couldn't find tag %s in tagset",
+			 file, lineno, p);
+		    fclose(f);
+		    return 0;
+		}
+	    }
+	    /* private tag */
+	    else if (*p)
+	    {
+		data1_tag *nt =
+		    new_element->tag = (data1_tag *)
+		    nmem_malloc(data1_nmem_get (dh),
+				sizeof(*new_element->tag));
+		nt->which = DATA1T_string;
+		nt->value.string = nmem_strdup(data1_nmem_get (dh), p);
+		nt->names = (data1_name *)
+		    nmem_malloc(data1_nmem_get(dh), 
+				sizeof(*new_element->tag->names));
+		nt->names->name = nt->value.string;
+		nt->names->next = 0;
+		nt->kind = DATA1K_string;
+		nt->next = 0;
+		nt->tagset = 0;
+	    }
+	    else
+	    {
+		yaz_log(LOG_WARN, "%s:%d: Bad element", file, lineno);
+		fclose(f);
+		return 0;
+	    }
+	    /* parse termList definitions */
+	    p = termlists;
+	    if (*p == '-')
+		new_element->termlists = 0;
+	    else
+	    {
+		assert (res->attset);
+		do
+		{
+		    char attname[512], structure[512];
+		    int r;
+		    
+		    if (!(r = sscanf(p, "%511[^:,]:%511[^,]", attname,
+				     structure)))
+		    {
+			yaz_log(LOG_WARN,
+			     "%s:%d: Syntax error in termlistspec '%s'",
+			     file, lineno, p);
+			fclose(f);
+			return 0;
+		    }
+		    if (*attname == '!')
+			strcpy(attname, name);
+		    *tp = (data1_termlist *)
+			nmem_malloc(data1_nmem_get(dh), sizeof(**tp));
+		    (*tp)->next = 0;
+		    if (!((*tp)->att = data1_getattbyname(dh, res->attset,
+							  attname)))
+		    {
+			yaz_log(LOG_WARN,
+			     "%s:%d: Couldn't find att '%s' in attset",
+			     file, lineno, attname);
+			fclose(f);
+			return 0;
+		    }
+		    if (r < 2) /* is the structure qualified? */
+			(*tp)->structure = "w";
+		    else 
+		    {
+			(*tp)->structure = (char *)
+			    nmem_malloc (data1_nmem_get (dh),
+					 strlen(structure)+1);
+			strcpy ((*tp)->structure, structure);
+		    }
+		    tp = &(*tp)->next;
+		}
+		while ((p = strchr(p, ',')) && *(++p));
+	        *tp = all; /* append any ALL entries to the list */
+	    }
+	    new_element->name = nmem_strdup(data1_nmem_get (dh), name);
+	}
+ 	else if (!strcmp(cmd, "section"))
+	{
+	    char *name;
+	    
+	    if (argc < 2)
+	    {
+		yaz_log(LOG_WARN, "%s:%d: Bad # of args to section",
+		     file, lineno);
+		continue;
+	    }
+	    name = argv[1];
+	    
+            cur_elements = (data1_sub_elements *)
+		nmem_malloc(data1_nmem_get(dh), sizeof(*cur_elements));
+	    cur_elements->next = res->sub_elements;
+	    cur_elements->elements = NULL;
+	    cur_elements->name = nmem_strdup (data1_nmem_get(dh), name);
+	    res->sub_elements = cur_elements;
+	    
+	    level = 0;
+    	    ppl[level] = &cur_elements->elements;
+	}
+	else if (!strcmp(cmd, "all"))
+	{
+	    char *p;
+	    data1_termlist **tp = &all;
+	    
+	    if (all)
+	    {
+		yaz_log(LOG_WARN, "%s:%d: Too many 'all' directives - ignored",
+		     file, lineno);
+		continue;
+	    }
+
+	    if (argc != 2)
+	    {
+		yaz_log(LOG_WARN, "%s:%d: Bad # of args to 'all' directive",
+		     file, lineno);
+		continue;
+	    }
+	    p = argv[1];
+	    assert (res->attset);
+	    do
+	    {
+		char attname[512], structure[512];
+		int r;
+		
+		if (!(r = sscanf(p, "%511[^:,]:%511[^,]", attname,
+				 structure)))
+		{
+		    yaz_log(LOG_WARN, "%s:%d: Syntax error in termlistspec",
+			 file, lineno);
+		    fclose(f);
+		    return 0;
+		}
+		*tp = (data1_termlist *)
+		    nmem_malloc(data1_nmem_get(dh), sizeof(**tp));
+		if (!((*tp)->att =
+		      data1_getattbyname (dh, res->attset, attname)))
+		{
+		    yaz_log(LOG_WARN, "%s:%d: Couldn't find att '%s' in attset",
+			 file, lineno, attname);
+		    fclose(f);
+		    return 0;
+		}
+		if (r < 2) /* is the structure qualified? */
+		    (*tp)->structure = "w";
+		else 
+		{
+		    (*tp)->structure =
+			(char *)nmem_malloc (data1_nmem_get (dh),
+					     strlen(structure)+1);
+		    strcpy ((*tp)->structure, structure);
+		}
+		(*tp)->next = 0;
+		tp = &(*tp)->next;
+	    }
+	    while ((p = strchr(p, ',')) && *(++p));
+	}
+	else if (!strcmp(cmd, "name"))
+	{
+	    if (argc != 2)
+	    {
+		yaz_log(LOG_WARN, "%s:%d: Bad # of args to name directive",
+		     file, lineno);
+		continue;
+	    }
+	    res->name = nmem_strdup(data1_nmem_get(dh), argv[1]);
+	}
+	else if (!strcmp(cmd, "reference"))
+	{
+	    char *name;
+	    
+	    if (argc != 2)
+	    {
+		yaz_log(LOG_WARN, "%s:%d: Bad # of args to reference",
+		     file, lineno);
+		continue;
+	    }
+	    name = argv[1];
+	    if ((res->reference = oid_getvalbyname(name)) == VAL_NONE)
+	    {
+		yaz_log(LOG_WARN, "%s:%d: Unknown tagset ref '%s'", 
+		     file, lineno, name);
+		continue;
+	    }
+	}
+	else if (!strcmp(cmd, "attset"))
+	{
+	    char *name;
+	    data1_attset *attset;
+	    
+	    if (argc != 2)
+	    {
+		yaz_log(LOG_WARN, "%s:%d: Bad # of args to attset",
+		     file, lineno);
+		continue;
+	    }
+	    name = argv[1];
+	    if (!(attset = data1_get_attset (dh, name)))
+	    {
+		yaz_log(LOG_WARN, "%s:%d: Couldn't find attset  %s",
+		     file, lineno, name);
+		continue;
+	    }
+	    *attset_childp = (data1_attset_child *)
+		nmem_malloc (data1_nmem_get(dh), sizeof(**attset_childp));
+	    (*attset_childp)->child = attset;
+	    (*attset_childp)->next = 0;
+	    attset_childp = &(*attset_childp)->next;
+	}
+	else if (!strcmp(cmd, "tagset"))
+	{
+	    char *name;
+	    int type = 0;
+	    if (argc < 2)
+	    {
+		yaz_log(LOG_WARN, "%s:%d: Bad # of args to tagset",
+		     file, lineno);
+		continue;
+	    }
+	    name = argv[1];
+	    if (argc == 3)
+		type = atoi(argv[2]);
+	    *tagset_childp = data1_read_tagset (dh, name, type);
+	    if (!(*tagset_childp))
+	    {
+		yaz_log(LOG_WARN, "%s:%d: Couldn't load tagset %s",
+		     file, lineno, name);
+		continue;
+	    }
+	    tagset_childp = &(*tagset_childp)->next;
+	}
+	else if (!strcmp(cmd, "varset"))
+	{
+	    char *name;
+
+	    if (argc != 2)
+	    {
+		yaz_log(LOG_WARN, "%s:%d: Bad # of args in varset",
+		     file, lineno);
+		continue;
+	    }
+	    name = argv[1];
+	    if (!(res->varset = data1_read_varset (dh, name)))
+	    {
+		yaz_log(LOG_WARN, "%s:%d: Couldn't load Varset %s",
+		     file, lineno, name);
+		continue;
+	    }
+	}
+	else if (!strcmp(cmd, "esetname"))
+	{
+	    char *name, *fname;
+
+	    if (argc != 3)
+	    {
+		yaz_log(LOG_WARN, "%s:%d: Bad # of args in esetname",
+		     file, lineno);
+		continue;
+	    }
+	    name = argv[1];
+	    fname = argv[2];
+	    
+	    *esetpp = (data1_esetname *)
+		nmem_malloc(data1_nmem_get(dh), sizeof(**esetpp));
+	    (*esetpp)->name = nmem_strdup(data1_nmem_get(dh), name);
+	    (*esetpp)->next = 0;
+	    if (*fname == '@')
+		(*esetpp)->spec = 0;
+	    else if (!((*esetpp)->spec = data1_read_espec1 (dh, fname)))
+	    {
+		yaz_log(LOG_WARN, "%s:%d: Espec-1 read failed for %s",
+		     file, lineno, fname);
+		continue;
+	    }
+	    esetpp = &(*esetpp)->next;
+	}
+	else if (!strcmp(cmd, "maptab"))
+	{
+	    char *name;
+	    
+	    if (argc != 2)
+	    {
+		yaz_log(LOG_WARN, "%s:%d: Bad # of args for maptab",
+                     file, lineno);
+		continue;
+	    }
+	    name = argv[1];
+	    if (!(*maptabp = data1_read_maptab (dh, name)))
+	    {
+		yaz_log(LOG_WARN, "%s:%d: Couldn't load maptab %s",
+                     file, lineno, name);
+		continue;
+	    }
+	    maptabp = &(*maptabp)->next;
+	}
+	else if (!strcmp(cmd, "marc"))
+	{
+	    char *name;
+	    
+	    if (argc != 2)
+	    {
+		yaz_log(LOG_WARN, "%s:%d: Bad # or args for marc",
+		     file, lineno);
+		continue;
+	    }
+	    name = argv[1];
+	    if (!(*marcp = data1_read_marctab (dh, name)))
+	    {
+		yaz_log(LOG_WARN, "%s:%d: Couldn't read marctab %s",
+                     file, lineno, name);
+		continue;
+	    }
+	    marcp = &(*marcp)->next;
+	}
+	else
+	{
+	    yaz_log(LOG_WARN, "%s:%d: Unknown directive '%s'", file, lineno, cmd);
+	    continue;
+	}
+    }
+    fclose(f);
+    
+    for (cur_elements = res->sub_elements; cur_elements;
+	 cur_elements = cur_elements->next)
+    {
+	if (!strcmp (cur_elements->name, "main"))
+	    res->main_elements = cur_elements->elements;
+	fix_element_ref (dh, res, cur_elements->elements);
+    }
+    yaz_log (LOG_DEBUG, "%s: data1_read_absyn end", file);
+    return res;
+}
Index: /main/tags/2.25/gsdl/packages/yaz/retrieval/d1_attset.c
===================================================================
--- /main/tags/2.25/gsdl/packages/yaz/retrieval/d1_attset.c	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/yaz/retrieval/d1_attset.c	(revision 21064)
@@ -0,0 +1,234 @@
+/*
+ * Copyright (c) 1995-1999, Index Data.
+ * See the file LICENSE for details.
+ * Sebastian Hammer, Adam Dickmeiss
+ *
+ * $Log$
+ * Revision 1.1  2000/08/03 03:11:28  johnmcp
+ * Added the YAZ toolkit source to the packages directory (for z39.50 stuff)
+ *
+ * Revision 1.14  1999/11/30 13:47:12  adam
+ * Improved installation. Moved header files to include/yaz.
+ *
+ * Revision 1.13  1999/10/21 12:06:29  adam
+ * Retrieval module no longer uses ctype.h - functions.
+ *
+ * Revision 1.12  1999/08/27 09:40:32  adam
+ * Renamed logf function to yaz_log. Removed VC++ project files.
+ *
+ * Revision 1.11  1998/10/14 13:31:56  adam
+ * Bug fix. Bug introduced by previous commit.
+ *
+ * Revision 1.10  1998/10/13 16:09:48  adam
+ * Added support for arbitrary OID's for tagsets, schemas and attribute sets.
+ * Added support for multiple attribute set references and tagset references
+ * from an abstract syntax file.
+ * Fixed many bad logs-calls in routines that read the various
+ * specifications regarding data1 (*.abs,*.att,...) and made the messages
+ * consistent whenever possible.
+ * Added extra 'lineno' argument to function readconf_line.
+ *
+ * Revision 1.9  1998/05/18 13:07:03  adam
+ * Changed the way attribute sets are handled by the retriaval module.
+ * Extended Explain conversion / schema.
+ * Modified server and client to work with ASN.1 compiled protocol handlers.
+ *
+ * Revision 1.8  1998/02/11 11:53:35  adam
+ * Changed code so that it compiles as C++.
+ *
+ * Revision 1.7  1997/09/17 12:10:34  adam
+ * YAZ version 1.4.
+ *
+ * Revision 1.6  1997/09/05 09:50:56  adam
+ * Removed global data1_tabpath - uses data1_get_tabpath() instead.
+ *
+ * Revision 1.5  1996/05/09 07:27:43  quinn
+ * Multiple local attributes values supported.
+ *
+ * Revision 1.4  1996/02/21  15:23:36  quinn
+ * Reversed fclose and return;
+ *
+ * Revision 1.3  1995/12/13  17:14:26  quinn
+ * *** empty log message ***
+ *
+ * Revision 1.2  1995/11/01  16:34:55  quinn
+ * Making data1 look for tables in data1_tabpath
+ *
+ * Revision 1.1  1995/11/01  11:56:07  quinn
+ * Added Retrieval (data management) functions en masse.
+ *
+ *
+ */
+
+#include <stdio.h>
+#include <assert.h>
+#include <stdlib.h>
+
+#include <yaz/log.h>
+#include <yaz/d1_attset.h>
+#include <yaz/data1.h>
+
+data1_att *data1_getattbyname(data1_handle dh, data1_attset *s, char *name)
+{
+    data1_att *r;
+    data1_attset_child *c;
+    
+    /* scan local set */
+    for (r = s->atts; r; r = r->next)
+	if (!data1_matchstr(r->name, name))
+	    return r;
+    for (c = s->children; c; c = c->next)
+    {
+	assert (c->child);
+	/* scan included sets */
+	if ((r = data1_getattbyname (dh, c->child, name)))
+	    return r;
+    }
+    return 0;
+}
+
+data1_attset *data1_empty_attset(data1_handle dh)
+{
+    NMEM mem = data1_nmem_get (dh);
+    data1_attset *res = (data1_attset*) nmem_malloc(mem,sizeof(*res));
+
+    res->name = 0;
+    res->reference = VAL_NONE;
+    res->atts = 0;
+    res->children = 0;
+    res->next = 0;
+    return res;
+}
+
+data1_attset *data1_read_attset(data1_handle dh, const char *file)
+{
+    data1_attset *res = 0;
+    data1_attset_child **childp;
+    data1_att **attp;
+    FILE *f;
+    NMEM mem = data1_nmem_get (dh);
+    int lineno = 0;
+    int argc;
+    char *argv[50], line[512];
+
+    if (!(f = yaz_path_fopen(data1_get_tabpath(dh), file, "r")))
+	return NULL;
+    res = data1_empty_attset (dh);
+
+    childp = &res->children;
+    attp = &res->atts;
+
+    while ((argc = readconf_line(f, &lineno, line, 512, argv, 50)))
+    {
+	char *cmd = argv[0];
+	if (!strcmp(cmd, "att"))
+	{
+	    int num;
+	    char *name;
+	    data1_att *t;
+	    data1_local_attribute *locals;
+	    
+	    if (argc < 3)
+	    {
+		yaz_log(LOG_WARN, "%s:%d: Bad # of args to att", file, lineno);
+		continue;
+	    }
+	    num = atoi (argv[1]);
+	    name = argv[2];
+	    
+	    if (argc == 3) /* no local attributes given */
+	    {
+		locals = (data1_local_attribute *)
+		    nmem_malloc(mem, sizeof(*locals));
+		locals->local = num;
+		locals->next = 0;
+	    }
+	    else /* parse the string "local{,local}" */
+	    {
+		char *p = argv[3];
+		data1_local_attribute **ap = &locals;
+		do
+		{
+		    *ap = (data1_local_attribute *)
+			nmem_malloc(mem, sizeof(**ap));
+		    (*ap)->local = atoi(p);
+		    (*ap)->next = 0;
+		    ap = &(*ap)->next;
+		}
+		while ((p = strchr(p, ',')) && *(++p));
+	    }
+	    t = *attp = (data1_att *)nmem_malloc(mem, sizeof(*t));
+	    t->parent = res;
+	    t->name = nmem_strdup(mem, name);
+	    t->value = num;
+	    t->locals = locals;
+	    t->next = 0;
+	    attp = &t->next;
+	}
+	else if (!strcmp(cmd, "name"))
+	{
+	    if (argc != 2)
+	    {
+		yaz_log(LOG_WARN, "%s:%d: Bad # of args to name", file, lineno);
+		continue;
+	    }
+	}
+	else if (!strcmp(cmd, "reference"))
+	{
+	    char *name;
+
+	    if (argc != 2)
+	    {
+		yaz_log(LOG_WARN, "%s:%d: Bad # of args to reference",
+			file, lineno);
+		continue;
+	    }
+	    name = argv[1];
+	    if ((res->reference = oid_getvalbyname(name)) == VAL_NONE)
+	    {
+		yaz_log(LOG_WARN, "%s:%d: Unknown reference oid '%s'",
+			file, lineno, name);
+		fclose(f);
+		return 0;
+	    }
+	}
+	else if (!strcmp(cmd, "ordinal"))
+	{
+	    yaz_log (LOG_WARN, "%s:%d: Directive ordinal ignored",
+		     file, lineno);
+	}
+	else if (!strcmp(cmd, "include"))
+	{
+	    char *name;
+	    data1_attset *attset;
+
+	    if (argc != 2)
+	    {
+		yaz_log(LOG_WARN, "%s:%d: Bad # of args to include",
+			file, lineno);
+		continue;
+	    }
+	    name = argv[1];
+
+	    if (!(attset = data1_get_attset (dh, name)))
+	    {
+		yaz_log(LOG_WARN, "%s:%d: Include of attset %s failed",
+			file, lineno, name);
+		continue;
+		
+	    }
+	    *childp = (data1_attset_child *)
+		nmem_malloc (mem, sizeof(**childp));
+	    (*childp)->child = attset;
+	    (*childp)->next = 0;
+	    childp = &(*childp)->next;
+	}
+	else
+	{
+	    yaz_log(LOG_WARN, "%s:%d: Unknown directive '%s'",
+		    file, lineno, cmd);
+	}
+    }
+    fclose(f);
+    return res;
+}
Index: /main/tags/2.25/gsdl/packages/yaz/retrieval/d1_doespec.c
===================================================================
--- /main/tags/2.25/gsdl/packages/yaz/retrieval/d1_doespec.c	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/yaz/retrieval/d1_doespec.c	(revision 21064)
@@ -0,0 +1,334 @@
+/*
+ * Copyright (c) 1995-1999, Index Data.
+ * See the file LICENSE for details.
+ * Sebastian Hammer, Adam Dickmeiss
+ *
+ * $Log$
+ * Revision 1.1  2000/08/03 03:11:29  johnmcp
+ * Added the YAZ toolkit source to the packages directory (for z39.50 stuff)
+ *
+ * Revision 1.14  1999/11/30 13:47:12  adam
+ * Improved installation. Moved header files to include/yaz.
+ *
+ * Revision 1.13  1999/08/27 09:40:32  adam
+ * Renamed logf function to yaz_log. Removed VC++ project files.
+ *
+ * Revision 1.12  1999/04/23 13:34:33  adam
+ * Fixed bug in match_triple. Thanks to Franck Falcoz <franck@dtv.dk>.
+ *
+ * Revision 1.11  1997/11/06 11:36:44  adam
+ * Implemented variant match on simple elements -data1 tree and Espec-1.
+ *
+ * Revision 1.10  1997/10/02 12:10:24  quinn
+ * Attempt to fix bug in especs
+ *
+ * Revision 1.9  1997/09/17 12:10:35  adam
+ * YAZ version 1.4.
+ *
+ * Revision 1.8  1997/05/14 06:54:02  adam
+ * C++ support.
+ *
+ * Revision 1.7  1997/04/30 08:52:11  quinn
+ * Null
+ *
+ * Revision 1.6  1996/10/11  11:57:22  quinn
+ * Smallish
+ *
+ * Revision 1.5  1996/07/06  19:58:34  quinn
+ * System headerfiles gathered in yconfig
+ *
+ * Revision 1.4  1996/06/07  11:04:32  quinn
+ * Fixed tag->tagset dependency
+ *
+ * Revision 1.3  1995/11/13  09:27:33  quinn
+ * Fiddling with the variant stuff.
+ *
+ * Revision 1.2  1995/11/01  13:54:45  quinn
+ * Minor adjustments
+ *
+ * Revision 1.1  1995/11/01  11:56:07  quinn
+ * Added Retrieval (data management) functions en masse.
+ *
+ *
+ */
+
+
+#include <assert.h>
+
+#include <yaz/oid.h>
+#include <yaz/log.h>
+#include <yaz/proto.h>
+#include <yaz/data1.h>
+
+static int match_children(data1_handle dh, data1_node *n,
+			  Z_Espec1 *e, int i, Z_ETagUnit **t,
+    int num);
+
+static int match_children_wildpath(data1_handle dh, data1_node *n,
+				   Z_Espec1 *e, int i,
+				   Z_ETagUnit **t, int num)
+{
+    return 0;
+}
+
+/*
+ * Locate a specific triple within a variant.
+ * set is the set to look for, universal set is the set that applies to a
+ * triple with an unknown set.
+ */
+static Z_Triple *find_triple(Z_Variant *var, oid_value universalset,
+    oid_value set, int zclass, int type)
+{
+    int i;
+    oident *defaultsetent = oid_getentbyoid(var->globalVariantSetId);
+    oid_value defaultset = defaultsetent ? defaultsetent->value :
+    	universalset;
+
+    for (i = 0; i < var->num_triples; i++)
+    {
+	oident *cursetent =
+	    oid_getentbyoid(var->triples[i]->variantSetId);
+	oid_value curset = cursetent ? cursetent->value : defaultset;
+
+	if (set == curset &&
+	    *var->triples[i]->zclass == zclass &&
+	    *var->triples[i]->type == type)
+	    return var->triples[i];
+    }
+    return 0;
+}
+
+static void mark_subtree(data1_node *n, int make_variantlist, int no_data,
+    int get_bytes, Z_Variant *vreq)
+{
+    data1_node *c;
+
+#if 1
+    if (n->which == DATA1N_tag)
+#else
+    if (n->which == DATA1N_tag && (!n->child || n->child->which != DATA1N_tag))
+    /*
+     * This seems to cause multi-level elements to fall out when only a
+     * top-level elementRequest has been given... Problem is, I can't figure
+     * out what it was supposed to ACHIEVE.... delete when code has been
+     * verified.
+     */
+#endif
+    {
+	n->u.tag.node_selected = 1;
+	n->u.tag.make_variantlist = make_variantlist;
+	n->u.tag.no_data_requested = no_data;
+	n->u.tag.get_bytes = get_bytes;
+    }
+
+    for (c = n->child; c; c = c->next)
+    {
+	if (c->which == DATA1N_tag && (!n->child ||
+	    n->child->which != DATA1N_tag))
+	{
+	    c->u.tag.node_selected = 1;
+	    c->u.tag.make_variantlist = make_variantlist;
+	    c->u.tag.no_data_requested = no_data;
+	    c->u.tag.get_bytes = get_bytes;
+	}
+	mark_subtree(c, make_variantlist, no_data, get_bytes, vreq);
+    }
+}
+
+
+static void match_triple (data1_handle dh, Z_Variant *vreq,
+			  oid_value defsetval,
+			  oid_value var1, data1_node *n)
+{
+    data1_node **c;
+
+    if (!(n = n->child))
+        return;
+    if (n->which != DATA1N_variant)
+	return;
+    c = &n->child;
+    while (*c)
+    {
+	int remove_flag = 0;
+	Z_Triple *r;
+	
+	assert ((*c)->which == DATA1N_variant);
+	
+	if ((*c)->u.variant.type->zclass->zclass == 4 &&
+	    (*c)->u.variant.type->type == 1)
+	{
+	    if ((r = find_triple(vreq, defsetval, var1, 4, 1)) &&
+		(r->which == Z_Triple_internationalString))
+	    {
+		const char *string_value =
+		    r->value.internationalString;
+		if (strcmp ((*c)->u.variant.value, string_value))
+		    remove_flag = 1;
+	    }
+	}
+	if (remove_flag)
+	{
+	    data1_free_tree (dh, *c);
+	    *c = (*c)->next;
+	}
+	else
+	{
+	    match_triple (dh, vreq, defsetval, var1, *c);
+	    c = &(*c)->next;
+	}
+    }
+}
+				
+static int match_children_here (data1_handle dh, data1_node *n,
+				Z_Espec1 *e, int i,
+				Z_ETagUnit **t, int num)
+{
+    int counter = 0, hits = 0;
+    data1_node *c;
+    Z_ETagUnit *tp = *t;
+    Z_Occurrences *occur;
+
+    for (c = n->child; c ; c = c->next)
+    {
+	data1_tag *tag = 0;
+	if (c->which != DATA1N_tag)
+	    return 0;
+
+	if (tp->which == Z_ETagUnit_specificTag)
+	{
+	    Z_SpecificTag *want = tp->u.specificTag;
+	    occur = want->occurrences;
+	    if (c->u.tag.element)
+		tag = c->u.tag.element->tag;
+	    if (*want->tagType != ((tag && tag->tagset) ? tag->tagset->type :
+		3))
+		continue;
+	    if (want->tagValue->which == Z_StringOrNumeric_numeric)
+	    {
+		if (!tag || tag->which != DATA1T_numeric)
+		    continue;
+		if (*want->tagValue->u.numeric != tag->value.numeric)
+		    continue;
+	    }
+	    else
+	    {
+		assert(want->tagValue->which == Z_StringOrNumeric_string);
+		if (tag && tag->which != DATA1T_string)
+		    continue;
+		if (data1_matchstr(want->tagValue->u.string,
+		    tag ? tag->value.string : c->u.tag.tag))
+		    continue;
+	    }
+	}
+	else
+	    occur = tp->u.wildThing;
+
+	/*
+	 * Ok, so we have a matching tag. Are we within occurrences-range?
+	 */
+	counter++;
+	if (occur && occur->which == Z_Occurrences_last)
+	{
+	    yaz_log(LOG_WARN, "Can't do occurrences=last (yet)");
+	    return 0;
+	}
+	if (!occur || occur->which == Z_Occurrences_all ||
+	    (occur->which == Z_Occurrences_values && counter >=
+	    *occur->u.values->start))
+	{
+	    if (match_children(dh, c, e, i, t + 1, num - 1))
+	    {
+		c->u.tag.node_selected = 1;
+		/*
+		 * Consider the variant specification if this is a complete
+		 * match.
+		 */
+		if (num == 1)
+		{
+		    int show_variantlist = 0;
+		    int no_data = 0;
+		    int get_bytes = -1;
+
+		    Z_Variant *vreq =
+			e->elements[i]->u.simpleElement->variantRequest;
+		    oident *defset = oid_getentbyoid(e->defaultVariantSetId);
+		    oid_value defsetval = defset ? defset->value : VAL_NONE;
+		    oid_value var1 = oid_getvalbyname("Variant-1");
+
+		    if (!vreq)
+			vreq = e->defaultVariantRequest;
+
+		    if (vreq)
+		    {
+			Z_Triple *r;
+
+			/*
+			 * 6,5: meta-data requested, variant list.
+			 */
+			if (find_triple(vreq, defsetval, var1, 6, 5))
+			    show_variantlist = 1;
+			/*
+			 * 9,1: Miscellaneous, no data requested.
+			 */
+			if (find_triple(vreq, defsetval, var1, 9, 1))
+			    no_data = 1;
+
+			/* howmuch */
+			if ((r = find_triple(vreq, defsetval, var1, 5, 5)))
+			    if (r->which == Z_Triple_integer)
+				get_bytes = *r->value.integer;
+
+			if (!show_variantlist)
+			    match_triple (dh, vreq, defsetval, var1, c);
+		    }
+		    mark_subtree(c, show_variantlist, no_data, get_bytes, vreq);
+		}
+		hits++;
+		/*
+		 * have we looked at enough children?
+		 */
+		if (!occur || (occur->which == Z_Occurrences_values &&
+		    (!occur->u.values->howMany ||
+		    counter - *occur->u.values->start >=
+		    *occur->u.values->howMany - 1)))
+		    return hits;
+	    }
+	}
+    }
+    return hits;
+}
+
+static int match_children(data1_handle dh, data1_node *n, Z_Espec1 *e,
+			  int i, Z_ETagUnit **t, int num)
+{
+    int res;
+
+    if (!num)
+	return 1;
+    switch (t[0]->which)
+    {
+	case Z_ETagUnit_wildThing:
+	case Z_ETagUnit_specificTag:
+	    res = match_children_here(dh, n, e, i, t, num); break;
+	case Z_ETagUnit_wildPath:
+	    res = match_children_wildpath(dh, n, e, i, t, num); break;
+	default:
+	    abort();
+    }
+    return res;
+}
+
+int data1_doespec1 (data1_handle dh, data1_node *n, Z_Espec1 *e)
+{
+    int i;
+
+    for (i = 0; i < e->num_elements; i++)
+    {
+	if (e->elements[i]->which != Z_ERequest_simpleElement)
+	    return 100;
+    	match_children(dh, n, e, i,
+		       e->elements[i]->u.simpleElement->path->tags,
+		       e->elements[i]->u.simpleElement->path->num_tags);
+    }
+    return 0;
+}
Index: /main/tags/2.25/gsdl/packages/yaz/retrieval/d1_espec.c
===================================================================
--- /main/tags/2.25/gsdl/packages/yaz/retrieval/d1_espec.c	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/yaz/retrieval/d1_espec.c	(revision 21064)
@@ -0,0 +1,410 @@
+/*
+ * Copyright (c) 1995-1999, Index Data.
+ * See the file LICENSE for details.
+ * Sebastian Hammer, Adam Dickmeiss
+ *
+ * $Log$
+ * Revision 1.1  2000/08/03 03:11:29  johnmcp
+ * Added the YAZ toolkit source to the packages directory (for z39.50 stuff)
+ *
+ * Revision 1.18  1999/11/30 13:47:12  adam
+ * Improved installation. Moved header files to include/yaz.
+ *
+ * Revision 1.17  1999/10/21 12:06:29  adam
+ * Retrieval module no longer uses ctype.h - functions.
+ *
+ * Revision 1.16  1999/08/27 09:40:32  adam
+ * Renamed logf function to yaz_log. Removed VC++ project files.
+ *
+ * Revision 1.15  1998/10/13 16:09:49  adam
+ * Added support for arbitrary OID's for tagsets, schemas and attribute sets.
+ * Added support for multiple attribute set references and tagset references
+ * from an abstract syntax file.
+ * Fixed many bad logs-calls in routines that read the various
+ * specifications regarding data1 (*.abs,*.att,...) and made the messages
+ * consistent whenever possible.
+ * Added extra 'lineno' argument to function readconf_line.
+ *
+ * Revision 1.14  1998/02/11 11:53:35  adam
+ * Changed code so that it compiles as C++.
+ *
+ * Revision 1.13  1997/11/24 11:33:56  adam
+ * Using function odr_nullval() instead of global ODR_NULLVAL when
+ * appropriate.
+ *
+ * Revision 1.12  1997/10/31 12:20:09  adam
+ * Improved memory debugging for xmalloc/nmem.c. References to NMEM
+ * instead of ODR in n ESPEC-1 handling in source d1_espec.c.
+ * Bug fix: missing fclose in data1_read_espec1.
+ *
+ * Revision 1.11  1997/09/29 13:18:59  adam
+ * Added function, oid_ent_to_oid, to replace the function
+ * oid_getoidbyent, which is not thread safe.
+ *
+ * Revision 1.10  1997/09/29 07:21:10  adam
+ * Added typecast to avoid warnings on MSVC.
+ *
+ * Revision 1.9  1997/09/17 12:10:35  adam
+ * YAZ version 1.4.
+ *
+ * Revision 1.8  1997/09/05 09:50:56  adam
+ * Removed global data1_tabpath - uses data1_get_tabpath() instead.
+ *
+ * Revision 1.7  1997/05/14 06:54:02  adam
+ * C++ support.
+ *
+ * Revision 1.6  1996/07/06 19:58:34  quinn
+ * System headerfiles gathered in yconfig
+ *
+ * Revision 1.5  1996/01/02  08:57:44  quinn
+ * Changed enums in the ASN.1 .h files to #defines. Changed oident.class to oclass
+ *
+ * Revision 1.4  1995/12/05  11:16:10  quinn
+ * Fixed malloc of 0.
+ *
+ * Revision 1.3  1995/11/13  09:27:34  quinn
+ * Fiddling with the variant stuff.
+ *
+ * Revision 1.2  1995/11/01  16:34:56  quinn
+ * Making data1 look for tables in data1_tabpath
+ *
+ * Revision 1.1  1995/11/01  11:56:07  quinn
+ * Added Retrieval (data management) functions en masse.
+ *
+ *
+ */
+
+
+#include <stdlib.h>
+#include <assert.h>
+#include <string.h>
+
+#include <yaz/odr.h>
+#include <yaz/proto.h>
+#include <yaz/log.h>
+#include <yaz/data1.h>
+
+static Z_Variant *read_variant(int argc, char **argv, NMEM nmem,
+			       const char *file, int lineno)
+{
+    Z_Variant *r = (Z_Variant *)nmem_malloc(nmem, sizeof(*r));
+    oident var1;
+    int i;
+    int oid[OID_SIZE];
+
+    var1.proto = PROTO_Z3950;
+    var1.oclass = CLASS_VARSET;
+    var1.value = VAL_VAR1;
+    r->globalVariantSetId = odr_oiddup_nmem(nmem, oid_ent_to_oid(&var1, oid));
+
+    if (argc)
+	r->triples = (Z_Triple **)nmem_malloc(nmem, sizeof(Z_Triple*) * argc);
+    else
+	r->triples = 0;
+    r->num_triples = argc;
+    for (i = 0; i < argc; i++)
+    {
+	int zclass, type;
+	char value[512];
+	Z_Triple *t;
+
+	if (sscanf(argv[i], "(%d,%d,%[^)])", &zclass, &type, value) < 3)
+	{
+	    yaz_log(LOG_WARN, "%s:%d: Syntax error in variant component '%s'",
+		    file, lineno, argv[i]);
+	    return 0;
+	}
+	t = r->triples[i] = (Z_Triple *)nmem_malloc(nmem, sizeof(Z_Triple));
+	t->variantSetId = 0;
+	t->zclass = (int *)nmem_malloc(nmem, sizeof(int));
+	*t->zclass = zclass;
+	t->type = (int *)nmem_malloc(nmem, sizeof(int));
+	*t->type = type;
+	/*
+	 * This is wrong.. we gotta look up the correct type for the
+	 * variant, I guess... damn this stuff.
+	 */
+	if (*value == '@')
+	{
+	    t->which = Z_Triple_null;
+	    t->value.null = odr_nullval();
+	}
+	else if (d1_isdigit(*value))
+	{
+	    t->which = Z_Triple_integer;
+	    t->value.integer = (int *)
+		nmem_malloc(nmem, sizeof(*t->value.integer));
+	    *t->value.integer = atoi(value);
+	}
+	else
+	{
+	    t->which = Z_Triple_internationalString;
+	    t->value.internationalString = (char *)
+		nmem_malloc(nmem, strlen(value)+1);
+	    strcpy(t->value.internationalString, value);
+	}
+    }
+    return r;
+}
+
+static Z_Occurrences *read_occurrences(char *occ, NMEM nmem,
+				       const char *file, int lineno)
+{
+    Z_Occurrences *op = (Z_Occurrences *)nmem_malloc(nmem, sizeof(*op));
+    char *p;
+    
+    if (!occ)
+    {
+	op->which = Z_Occurrences_values;
+	op->u.values = (Z_OccurValues *)
+	    nmem_malloc(nmem, sizeof(Z_OccurValues));
+	op->u.values->start = (int *)nmem_malloc(nmem, sizeof(int));
+	*op->u.values->start = 1;
+	op->u.values->howMany = 0;
+    }
+    else if (!strcmp(occ, "all"))
+    {
+	op->which = Z_Occurrences_all;
+	op->u.all = odr_nullval();
+    }
+    else if (!strcmp(occ, "last"))
+    {
+	op->which = Z_Occurrences_last;
+	op->u.all = odr_nullval();
+    }
+    else
+    {
+	Z_OccurValues *ov = (Z_OccurValues *)nmem_malloc(nmem, sizeof(*ov));
+    
+	if (!d1_isdigit(*occ))
+	{
+	    yaz_log(LOG_WARN, "%s:%d: Bad occurrences-spec %s",
+		    file, lineno, occ);
+	    return 0;
+	}
+	op->which = Z_Occurrences_values;
+	op->u.values = ov;
+	ov->start = (int *)nmem_malloc(nmem, sizeof(*ov->start));
+	*ov->start = atoi(occ);
+	if ((p = strchr(occ, '+')))
+	{
+	    ov->howMany = (int *)nmem_malloc(nmem, sizeof(*ov->howMany));
+	    *ov->howMany = atoi(p + 1);
+	}
+	else
+	    ov->howMany = 0;
+    }
+    return op;
+}
+
+
+static Z_ETagUnit *read_tagunit(char *buf, NMEM nmem,
+				const char *file, int lineno)
+{
+    Z_ETagUnit *u = (Z_ETagUnit *)nmem_malloc(nmem, sizeof(*u));
+    int terms;
+    int type;
+    char value[512], occ[512];
+    
+    if (*buf == '*')
+    {
+	u->which = Z_ETagUnit_wildPath;
+	u->u.wildPath = odr_nullval();
+    }
+    else if (*buf == '?')
+    {
+	u->which = Z_ETagUnit_wildThing;
+	if (buf[1] == ':')
+	    u->u.wildThing = read_occurrences(buf+2, nmem, file, lineno);
+	else
+	    u->u.wildThing = read_occurrences(0, nmem, file, lineno);
+    }
+    else if ((terms = sscanf(buf, "(%d,%[^)]):%[a-z0-9+]", &type, value,
+			     occ)) >= 2)
+    {
+	int numval;
+	Z_SpecificTag *t;
+	char *valp = value;
+	int force_string = 0;
+	
+	if (*valp == '\'')
+	{
+	    valp++;
+	    force_string = 1;
+	}
+	u->which = Z_ETagUnit_specificTag;
+	u->u.specificTag = t = (Z_SpecificTag *)nmem_malloc(nmem, sizeof(*t));
+	t->tagType = (int *)nmem_malloc(nmem, sizeof(*t->tagType));
+	*t->tagType = type;
+	t->tagValue = (Z_StringOrNumeric *)
+	    nmem_malloc(nmem, sizeof(*t->tagValue));
+	if (!force_string && (numval = atoi(valp)))
+	{
+	    t->tagValue->which = Z_StringOrNumeric_numeric;
+	    t->tagValue->u.numeric = (int *)nmem_malloc(nmem, sizeof(int));
+	    *t->tagValue->u.numeric = numval;
+	}
+	else
+	{
+	    t->tagValue->which = Z_StringOrNumeric_string;
+	    t->tagValue->u.string = (char *)nmem_malloc(nmem, strlen(valp)+1);
+	    strcpy(t->tagValue->u.string, valp);
+	}
+	if (terms > 2) /* an occurrences-spec exists */
+	    t->occurrences = read_occurrences(occ, nmem, file, lineno);
+	else
+	    t->occurrences = 0;
+    }
+    return u;
+}
+
+/*
+ * Read an element-set specification from a file.
+ * NOTE: If !o, memory is allocated directly from the heap by nmem_malloc().
+ */
+Z_Espec1 *data1_read_espec1 (data1_handle dh, const char *file)
+{
+    FILE *f;
+    NMEM nmem = data1_nmem_get (dh);
+    int lineno = 0;
+    int argc, size_esn = 0;
+    char *argv[50], line[512];
+    Z_Espec1 *res = (Z_Espec1 *)nmem_malloc(nmem, sizeof(*res));
+    
+    if (!(f = yaz_path_fopen(data1_get_tabpath(dh), file, "r")))
+    {
+	yaz_log(LOG_WARN|LOG_ERRNO, "%s", file);
+	return 0;
+    }
+    
+    res->num_elementSetNames = 0;
+    res->elementSetNames = 0;
+    res->defaultVariantSetId = 0;
+    res->defaultVariantRequest = 0;
+    res->defaultTagType = 0;
+    res->num_elements = 0;
+    res->elements = 0;
+    
+    while ((argc = readconf_line(f, &lineno, line, 512, argv, 50)))
+	if (!strcmp(argv[0], "elementsetnames"))
+	{
+	    int nnames = argc-1, i;
+	    
+	    if (!nnames)
+	    {
+		yaz_log(LOG_WARN, "%s:%d: Empty elementsetnames directive",
+			file, lineno);
+		continue;
+	    }
+	    
+	    res->elementSetNames =
+		(char **)nmem_malloc(nmem, sizeof(char**)*nnames);
+	    for (i = 0; i < nnames; i++)
+	    {
+		res->elementSetNames[i] = (char *)
+		    nmem_malloc(nmem, strlen(argv[i+1])+1);
+		strcpy(res->elementSetNames[i], argv[i+1]);
+	    }
+	    res->num_elementSetNames = nnames;
+	}
+	else if (!strcmp(argv[0], "defaultvariantsetid"))
+	{
+	    if (argc != 2)
+	    {
+		yaz_log(LOG_WARN, "%s:%d: Bad # of args for %s",
+			file, lineno, argv[0]);
+		continue;
+	    }
+	    if (!(res->defaultVariantSetId =
+		  odr_getoidbystr_nmem(nmem, argv[1])))
+	    {
+		yaz_log(LOG_WARN, "%s:%d: Bad defaultvariantsetid",
+			file, lineno);
+		continue;
+	    }
+	}
+	else if (!strcmp(argv[0], "defaulttagtype"))
+	{
+	    if (argc != 2)
+	    {
+		yaz_log(LOG_WARN, "%s:%d: Bad # of args for %s",
+			file, lineno, argv[0]);
+		continue;
+	    }
+	    res->defaultTagType = (int *)nmem_malloc(nmem, sizeof(int));
+	    *res->defaultTagType = atoi(argv[1]);
+	}
+	else if (!strcmp(argv[0], "defaultvariantrequest"))
+	{
+	    if (!(res->defaultVariantRequest =
+		  read_variant(argc-1, argv+1, nmem, file, lineno)))
+	    {
+		yaz_log(LOG_WARN, "%s:%d: Bad defaultvariantrequest",
+			file, lineno);
+		continue;
+	    }
+	}
+	else if (!strcmp(argv[0], "simpleelement"))
+	{
+	    Z_ElementRequest *er;
+	    Z_SimpleElement *se;
+	    Z_ETagPath *tp;
+	    char *path = argv[1];
+	    char *ep;
+	    int num, i = 0;
+	    
+	    if (!res->elements)
+		res->elements = (Z_ElementRequest **)
+		    nmem_malloc(nmem, size_esn = 24*sizeof(er));
+	    else if (res->num_elements >= (int) (size_esn/sizeof(er)))
+	    {
+		Z_ElementRequest **oe = res->elements;
+		size_esn *= 2;
+		res->elements = (Z_ElementRequest **)
+		    nmem_malloc (nmem, size_esn*sizeof(er));
+		memcpy (res->elements, oe, size_esn/2);
+	    }
+	    if (argc < 2)
+	    {
+		yaz_log(LOG_WARN, "%s:%d: Bad # of args for %s",
+			file, lineno, argv[0]);
+		continue;
+	    }
+	    
+	    res->elements[res->num_elements++] = er =
+		(Z_ElementRequest *)nmem_malloc(nmem, sizeof(*er));
+	    er->which = Z_ERequest_simpleElement;
+	    er->u.simpleElement = se = (Z_SimpleElement *)
+		nmem_malloc(nmem, sizeof(*se));
+	    se->variantRequest = 0;
+	    se->path = tp = (Z_ETagPath *)nmem_malloc(nmem, sizeof(*tp));
+	    tp->num_tags = 0;
+	    /*
+	     * Parse the element selector.
+	     */
+	    for (num = 1, ep = path; (ep = strchr(ep, '/')); num++, ep++)
+		;
+	    tp->tags = (Z_ETagUnit **)
+		nmem_malloc(nmem, sizeof(Z_ETagUnit*)*num);
+	    
+	    for ((ep = strchr(path, '/')) ; path ;
+		 (void)((path = ep) && (ep = strchr(path, '/'))))
+	    {
+		if (ep)
+		    ep++;
+		
+		assert(i<num);
+		tp->tags[tp->num_tags++] =
+		    read_tagunit(path, nmem, file, lineno);
+	    }
+	    
+	    if (argc > 2 && !strcmp(argv[2], "variant"))
+		se->variantRequest=
+		    read_variant(argc-3, argv+3, nmem, file, lineno);
+	}
+	else
+	    yaz_log(LOG_WARN, "%s:%d: Unknown directive '%s'",
+		    file, lineno, argv[0]);
+    fclose (f);
+    return res;
+}
Index: /main/tags/2.25/gsdl/packages/yaz/retrieval/d1_expout.c
===================================================================
--- /main/tags/2.25/gsdl/packages/yaz/retrieval/d1_expout.c	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/yaz/retrieval/d1_expout.c	(revision 21064)
@@ -0,0 +1,1463 @@
+/*
+ * Copyright (c) 1995-1999, Index Data.
+ * See the file LICENSE for details.
+ * Sebastian Hammer, Adam Dickmeiss
+ *
+ * $Log$
+ * Revision 1.1  2000/08/03 03:11:30  johnmcp
+ * Added the YAZ toolkit source to the packages directory (for z39.50 stuff)
+ *
+ * Revision 1.17  1999/11/30 13:47:12  adam
+ * Improved installation. Moved header files to include/yaz.
+ *
+ * Revision 1.16  1999/08/27 09:40:32  adam
+ * Renamed logf function to yaz_log. Removed VC++ project files.
+ *
+ * Revision 1.15  1998/09/28 12:44:40  adam
+ * Fixed bug in f_integer.
+ *
+ * Revision 1.14  1998/06/08 14:26:41  adam
+ * Fixed bug in f_queryTypeDetails.
+ *
+ * Revision 1.13  1998/06/05 08:58:48  adam
+ * Fixed un-initialised var in f_rpnCapabilities.
+ *
+ * Revision 1.12  1998/05/18 13:07:04  adam
+ * Changed the way attribute sets are handled by the retriaval module.
+ * Extended Explain conversion / schema.
+ * Modified server and client to work with ASN.1 compiled protocol handlers.
+ *
+ * Revision 1.11  1998/04/02 08:27:37  adam
+ * Minor change in definition of Z_TargetInfo. Furhter work on Explain
+ * schema - added AttributeDetails.
+ *
+ * Revision 1.10  1998/03/31 15:13:20  adam
+ * Development towards compiled ASN.1.
+ *
+ * Revision 1.9  1998/03/05 08:07:58  adam
+ * Make data1 to EXPLAIN ignore local tags in root.
+ *
+ * Revision 1.8  1998/02/11 11:53:35  adam
+ * Changed code so that it compiles as C++.
+ *
+ * Revision 1.7  1997/12/09 16:18:16  adam
+ * Work on EXPLAIN schema. First implementation of sub-schema facility
+ * in the *.abs files.
+ *
+ * Revision 1.6  1997/11/24 11:33:56  adam
+ * Using function odr_nullval() instead of global ODR_NULLVAL when
+ * appropriate.
+ *
+ * Revision 1.5  1997/11/19 10:30:06  adam
+ * More explain work.
+ *
+ * Revision 1.4  1997/11/18 09:51:08  adam
+ * Removed element num_children from data1_node. Minor changes in
+ * data1 to Explain.
+ *
+ * Revision 1.3  1997/09/17 12:10:36  adam
+ * YAZ version 1.4.
+ *
+ * Revision 1.2  1995/12/14 16:28:30  quinn
+ * More explain stuff.
+ *
+ * Revision 1.1  1995/12/14  11:09:51  quinn
+ * Work on Explain
+ *
+ *
+ */
+
+#include <assert.h>
+#include <string.h>
+#include <stdlib.h>
+
+#include <yaz/log.h>
+#include <yaz/proto.h>
+#include <yaz/data1.h>
+
+typedef struct {
+    data1_handle dh;
+    ODR o;
+    int select;
+
+    bool_t *false_value;
+    bool_t *true_value;
+} ExpHandle;
+
+static int is_numeric_tag (ExpHandle *eh, data1_node *c)
+{
+    if (!c || c->which != DATA1N_tag)
+	return 0;
+    if (!c->u.tag.element)
+    {
+	yaz_log(LOG_WARN, "Tag %s is local", c->u.tag.tag);
+	return 0;
+    }
+    if (c->u.tag.element->tag->which != DATA1T_numeric)
+    {
+	yaz_log(LOG_WARN, "Tag %s is not numeric", c->u.tag.tag);
+	return 0;
+    }
+    if (eh->select && !c->u.tag.node_selected)
+	return 0;
+    return c->u.tag.element->tag->value.numeric;
+}
+
+static int is_data_tag (ExpHandle *eh, data1_node *c)
+{
+    if (!c || c->which != DATA1N_data)
+	return 0;
+    if (eh->select && !c->u.tag.node_selected)
+	return 0;
+    return 1;
+}
+
+static int *f_integer(ExpHandle *eh, data1_node *c)
+{
+    int *r;
+    char intbuf[64];
+
+    c = c->child;
+    if (!is_data_tag (eh, c) || c->u.data.len > 63)
+	return 0;
+    r = (int *)odr_malloc(eh->o, sizeof(*r));
+    sprintf(intbuf, "%.*s", c->u.data.len, c->u.data.data);
+    *r = atoi(intbuf);
+    return r;
+}
+
+static char *f_string(ExpHandle *eh, data1_node *c)
+{
+    char *r;
+
+    c = c->child;
+    if (!is_data_tag (eh, c))
+	return 0;
+    r = (char *)odr_malloc(eh->o, c->u.data.len+1);
+    memcpy(r, c->u.data.data, c->u.data.len);
+    r[c->u.data.len] = '\0';
+    return r;
+}
+
+static bool_t *f_bool(ExpHandle *eh, data1_node *c)
+{
+    bool_t *tf;
+    char intbuf[64];
+
+    c = c->child;
+    if (!is_data_tag (eh, c) || c->u.data.len > 63)
+	return 0;
+    tf = (int *)odr_malloc (eh->o, sizeof(*tf));
+    sprintf(intbuf, "%.*s", c->u.data.len, c->u.data.data);
+    *tf = atoi(intbuf);
+    return tf;
+}
+
+static Odr_oid *f_oid(ExpHandle *eh, data1_node *c, oid_class oclass)
+{
+    char oidstr[64];
+    int oid_this[20];
+    oid_value value_for_this;
+
+    c = c->child;
+    if (!is_data_tag (eh, c) || c->u.data.len > 63)
+	return 0;
+    sprintf(oidstr, "%.*s", c->u.data.len, c->u.data.data);
+    value_for_this = oid_getvalbyname(oidstr);
+    if (value_for_this == VAL_NONE)
+    {
+	Odr_oid *oid = odr_getoidbystr(eh->o, oidstr);
+	assert (oid);
+	return oid;
+    }
+    else
+    {
+	struct oident ident;
+
+	ident.oclass = oclass;
+	ident.proto = PROTO_Z3950;
+	ident.value = value_for_this;
+	
+	oid_ent_to_oid (&ident, oid_this);
+    }
+    return odr_oiddup (eh->o, oid_this);
+}
+
+static Z_IntUnit *f_intunit(ExpHandle *eh, data1_node *c)
+{
+    /* fix */
+    return 0;
+}
+
+static Z_HumanString *f_humstring(ExpHandle *eh, data1_node *c)
+{
+    Z_HumanString *r;
+    Z_HumanStringUnit *u;
+
+    c = c->child;
+    if (!is_data_tag (eh, c))
+	return 0;
+    r = (Z_HumanString *)odr_malloc(eh->o, sizeof(*r));
+    r->num_strings = 1;
+    r->strings = (Z_HumanStringUnit **)odr_malloc(eh->o, sizeof(Z_HumanStringUnit*));
+    r->strings[0] = u = (Z_HumanStringUnit *)odr_malloc(eh->o, sizeof(*u));
+    u->language = 0;
+    u->text = (char *)odr_malloc(eh->o, c->u.data.len+1);
+    memcpy(u->text, c->u.data.data, c->u.data.len);
+    u->text[c->u.data.len] = '\0';
+    return r;
+}
+
+static Z_CommonInfo *f_commonInfo(ExpHandle *eh, data1_node *n)
+{
+    Z_CommonInfo *res = (Z_CommonInfo *)odr_malloc(eh->o, sizeof(*res));
+    data1_node *c;
+
+    res->dateAdded = 0;
+    res->dateChanged = 0;
+    res->expiry = 0;
+    res->humanStringLanguage = 0;
+    res->otherInfo = 0;
+
+    for (c = n->child; c; c = c->next)
+    {
+	switch (is_numeric_tag (eh, c))
+	{
+	    case 601: res->dateAdded = f_string(eh, c); break;
+	    case 602: res->dateChanged = f_string(eh, c); break;
+	    case 603: res->expiry = f_string(eh, c); break;
+	    case 604: res->humanStringLanguage = f_string(eh, c); break;
+	}
+    }
+    return res;
+}
+
+Odr_oid **f_oid_seq (ExpHandle *eh, data1_node *n, int *num, oid_class oclass)
+{
+    Odr_oid **res;
+    data1_node *c;
+    int i;
+
+    *num = 0;
+    for (c = n->child ; c; c = c->next)
+	if (is_numeric_tag (eh, c) == 1000)
+	    ++(*num);
+    if (!*num)
+	return NULL;
+    res = (int **)odr_malloc (eh->o, sizeof(*res) * (*num));
+    for (c = n->child, i = 0 ; c; c = c->next)
+	if (is_numeric_tag (eh, c) == 1000)
+	    res[i++] = f_oid (eh, c, oclass);
+    return res;
+}
+    
+char **f_string_seq (ExpHandle *eh, data1_node *n, int *num)
+{
+    char **res;
+    data1_node *c;
+    int i;
+
+    *num = 0;
+    for (c = n->child ; c; c = c->next)
+    {
+	if (is_numeric_tag (eh, c) != 1001)
+	    continue;
+	++(*num);
+    }
+    if (!*num)
+	return NULL;
+    res = (char **)odr_malloc (eh->o, sizeof(*res) * (*num));
+    for (c = n->child, i = 0 ; c; c = c->next)
+    {
+	if (is_numeric_tag (eh, c) != 1001)
+	    continue;
+	res[i++] = f_string (eh, c);
+    }
+    return res;
+}
+
+Z_ProximitySupport *f_proximitySupport (ExpHandle *eh, data1_node *n)
+{
+    Z_ProximitySupport *res = (Z_ProximitySupport *)
+	odr_malloc (eh->o, sizeof(*res));
+    res->anySupport = eh->false_value;
+    res->num_unitsSupported = 0;
+    res->unitsSupported = 0;
+    return res;
+}
+
+Z_RpnCapabilities *f_rpnCapabilities (ExpHandle *eh, data1_node *n)
+{
+    Z_RpnCapabilities *res = (Z_RpnCapabilities *)
+	odr_malloc (eh->o, sizeof(*res));
+    data1_node *c;
+
+    res->num_operators = 0;
+    res->operators = NULL;
+    res->resultSetAsOperandSupported = eh->false_value;
+    res->restrictionOperandSupported = eh->false_value;
+    res->proximity = NULL;
+
+    for (c = n->child; c; c = c->next)
+    {
+	int i = 0;
+	switch (is_numeric_tag(eh, c))
+	{
+	case 550:
+	    for (n = c->child; n; n = n->next)
+	    {
+		if (is_numeric_tag(eh, n) != 551)
+		    continue;
+		(res->num_operators)++;
+	    }
+	    if (res->num_operators)
+		res->operators = (int **)
+		    odr_malloc (eh->o, res->num_operators
+				* sizeof(*res->operators));
+	    for (n = c->child; n; n = n->next)
+	    {
+		if (is_numeric_tag(eh, n) != 551)
+		    continue;
+		res->operators[i++] = f_integer (eh, n);
+	    }
+	    break;
+	case 552:
+	    res->resultSetAsOperandSupported = f_bool (eh, c);
+	    break;
+	case 553:
+	    res->restrictionOperandSupported = f_bool (eh, c);
+	    break;
+	case 554:
+	    res->proximity = f_proximitySupport (eh, c);
+	    break;
+	}
+    }
+    return res;
+}
+
+Z_QueryTypeDetails *f_queryTypeDetails (ExpHandle *eh, data1_node *n)
+{
+    Z_QueryTypeDetails *res = (Z_QueryTypeDetails *)
+	odr_malloc(eh->o, sizeof(*res));
+    data1_node *c;
+
+    res->which = Z_QueryTypeDetails_rpn;
+    res->u.rpn = 0;
+    for (c = n->child; c; c = c->next)
+    {
+	switch (is_numeric_tag(eh, c))
+	{
+	case 519:
+	    res->which = Z_QueryTypeDetails_rpn;
+	    res->u.rpn = f_rpnCapabilities (eh, c);
+	    break;
+	case 520:
+	    break;
+	case 521:
+	    break;
+	}
+    }
+    return res;
+}
+
+static Z_AccessInfo *f_accessInfo(ExpHandle *eh, data1_node *n)
+{
+    Z_AccessInfo *res = (Z_AccessInfo *)odr_malloc(eh->o, sizeof(*res));
+    data1_node *c;
+
+    res->num_queryTypesSupported = 0;
+    res->queryTypesSupported = 0;
+    res->num_diagnosticsSets = 0;
+    res->diagnosticsSets = 0;
+    res->num_attributeSetIds = 0;
+    res->attributeSetIds = 0;
+    res->num_schemas = 0;
+    res->schemas = 0;
+    res->num_recordSyntaxes = 0;
+    res->recordSyntaxes = 0;
+    res->num_resourceChallenges = 0;
+    res->resourceChallenges = 0;
+    res->restrictedAccess = 0;
+    res->costInfo = 0;
+    res->num_variantSets = 0;
+    res->variantSets = 0;
+    res->num_elementSetNames = 0;
+    res->elementSetNames = 0;
+    res->num_unitSystems = 0;
+    res->unitSystems = 0;
+
+    for (c = n->child; c; c = c->next)
+    {
+	int i = 0;
+	switch (is_numeric_tag (eh, c))
+	{
+	case 501:
+	    for (n = c->child; n; n = n->next)
+	    {
+		if (is_numeric_tag(eh, n) != 518)
+		    continue;
+		(res->num_queryTypesSupported)++;
+	    }
+	    if (res->num_queryTypesSupported)
+		res->queryTypesSupported =
+		    (Z_QueryTypeDetails **)
+		    odr_malloc (eh->o, res->num_queryTypesSupported
+				* sizeof(*res->queryTypesSupported));
+	    for (n = c->child; n; n = n->next)
+	    {
+		if (is_numeric_tag(eh, n) != 518)
+		    continue;
+		res->queryTypesSupported[i++] = f_queryTypeDetails (eh, n);
+	    }
+	    break;
+	case 503:
+	    res->diagnosticsSets =
+		f_oid_seq(eh, c, &res->num_diagnosticsSets, CLASS_DIAGSET);
+	    break;
+	case 505:
+	    res->attributeSetIds =
+		f_oid_seq(eh, c, &res->num_attributeSetIds, CLASS_ATTSET);
+	    break;
+	case 507:
+	    res->schemas =
+		f_oid_seq(eh, c, &res->num_schemas, CLASS_SCHEMA);
+	    break;
+	case 509:
+	    res->recordSyntaxes =
+		f_oid_seq (eh, c, &res->num_recordSyntaxes, CLASS_RECSYN);
+	    break;
+	case 511:
+	    res->resourceChallenges =
+		f_oid_seq (eh, c, &res->num_resourceChallenges, CLASS_RESFORM);
+	    break;
+	case 513: res->restrictedAccess = NULL; break; /* fix */
+	case 514: res->costInfo = NULL; break; /* fix */
+	case 515:
+	    res->variantSets =
+		f_oid_seq (eh, c, &res->num_variantSets, CLASS_VARSET);
+	    break;
+	case 516:
+	    res->elementSetNames =
+		f_string_seq (eh, c, &res->num_elementSetNames);
+	    break;
+	case 517:
+	    res->unitSystems = f_string_seq (eh, c, &res->num_unitSystems);
+	    break;
+	}
+    }
+    return res;
+}
+
+static int *f_recordCount(ExpHandle *eh, data1_node *c, int *which)
+{
+    int *r= (int *)odr_malloc(eh->o, sizeof(*r));
+    int *wp = which;
+    char intbuf[64];
+
+    c = c->child;
+    if (!is_numeric_tag (eh, c))
+	return 0;
+    if (c->u.tag.element->tag->value.numeric == 210)
+	*wp = Z_DatabaseInfo_actualNumber;
+    else if (c->u.tag.element->tag->value.numeric == 211)
+	*wp = Z_DatabaseInfo_approxNumber;
+    else
+	return 0;
+    if (!c->child || c->child->which != DATA1N_data)
+	return 0;
+    sprintf(intbuf, "%.*s", c->child->u.data.len, c->child->u.data.data);
+    *r = atoi(intbuf);
+    return r;
+}
+
+static Z_ContactInfo *f_contactInfo(ExpHandle *eh, data1_node *n)
+{
+    Z_ContactInfo *res = (Z_ContactInfo *)
+	odr_malloc (eh->o, sizeof(*res));
+    data1_node *c;
+    
+    res->name = 0;
+    res->description = 0;
+    res->address = 0;
+    res->email = 0;
+    res->phone = 0;
+    
+    for (c = n->child; c; c = c->next)
+    {
+	switch (is_numeric_tag (eh, c))
+	{
+	case 102: res->name = f_string (eh, c); break;
+	case 113: res->description = f_humstring (eh, c); break;
+	case 127: res->address = f_humstring (eh, c); break;
+	case 128: res->email = f_string (eh, c); break;
+	case 129: res->phone = f_string (eh, c); break;
+	}
+    }
+    return res;
+}
+
+static Z_DatabaseList *f_databaseList(ExpHandle *eh, data1_node *n)
+{
+    data1_node *c;
+    Z_DatabaseList *res;
+    int i = 0;
+    
+    for (c = n->child; c; c = c->next)
+    {
+	if (!is_numeric_tag (eh, c) != 102) 
+	    continue;
+	++i;
+    }
+    if (!i)
+	return NULL;
+
+    res = (Z_DatabaseList *)odr_malloc (eh->o, sizeof(*res));
+    
+    res->num_databases = i;
+    res->databases = (char **)odr_malloc (eh->o, sizeof(*res->databases) * i);
+    i = 0;
+    for (c = n->child; c; c = c->next)
+    {
+	if (!is_numeric_tag (eh, c) != 102)
+	    continue;
+	res->databases[i++] = f_string (eh, c);
+    }
+    return res;
+}
+
+static Z_NetworkAddressIA *f_networkAddressIA(ExpHandle *eh, data1_node *n)
+{
+    Z_NetworkAddressIA *res = (Z_NetworkAddressIA *)
+	odr_malloc (eh->o, sizeof(*res));
+    data1_node *c;
+    
+    res->hostAddress = 0;
+    res->port = 0;
+
+    for (c = n->child; c; c = c->next)
+    {
+	switch (is_numeric_tag (eh, c))
+	{
+	case 121: res->hostAddress = f_string (eh, c); break;
+	case 122: res->port = f_integer (eh, c); break;
+	}
+    }
+    return res;
+}
+
+static Z_NetworkAddressOther *f_networkAddressOther(ExpHandle *eh,
+						    data1_node *n)
+{
+    Z_NetworkAddressOther *res = (Z_NetworkAddressOther *)
+	odr_malloc (eh->o, sizeof(*res));
+    data1_node *c;
+
+    res->type = 0;
+    res->address = 0;
+
+    for (c = n->child; c; c = c->next)
+    {
+	switch (is_numeric_tag (eh, c))
+	{
+	case 124: res->type = f_string (eh, c); break;
+	case 121: res->address = f_string (eh, c); break;
+	}
+    }
+    return res;
+}
+
+static Z_NetworkAddress **f_networkAddresses(ExpHandle *eh, data1_node *n, 
+					     int *num)
+{
+    Z_NetworkAddress **res = NULL;
+    data1_node *c;
+    int i = 0;
+    
+    *num = 0;
+    for (c = n->child; c; c = c->next)
+    {
+	switch (is_numeric_tag (eh, c))
+	{
+	case 120:
+	case 123:
+	    (*num)++;
+	    break;
+	}
+    }
+
+    if (*num)
+	res = (Z_NetworkAddress **) odr_malloc (eh->o, sizeof(*res) * (*num));
+					       
+    for (c = n->child; c; c = c->next)
+    {
+	switch (is_numeric_tag (eh, c))
+	{
+	case 120:
+	    res[i] = (Z_NetworkAddress *) odr_malloc (eh->o, sizeof(**res));
+	    res[i]->which = Z_NetworkAddress_iA;
+	    res[i]->u.internetAddress = f_networkAddressIA(eh, c);
+	    i++;
+	    break;
+	case 123:
+	    res[i] = (Z_NetworkAddress *) odr_malloc (eh->o, sizeof(**res));
+	    res[i]->which = Z_NetworkAddress_other;
+	    res[i]->u.other = f_networkAddressOther(eh, c);
+	    i++;
+	    break;
+	}
+    }
+    return res;
+}
+
+static Z_CategoryInfo *f_categoryInfo(ExpHandle *eh, data1_node *n)
+{
+    Z_CategoryInfo *res = (Z_CategoryInfo *)odr_malloc(eh->o, sizeof(*res));
+    data1_node *c;
+
+    res->category = 0;
+    res->originalCategory = 0;
+    res->description = 0;
+    res->asn1Module = 0;
+    for (c = n->child; c; c = c->next)
+    {
+	switch (is_numeric_tag (eh, c))
+	{
+	case 102: res->category = f_string(eh, c); break;
+	case 302: res->originalCategory = f_string(eh, c); break;
+	case 113: res->description = f_humstring(eh, c); break;
+	case 303: res->asn1Module = f_string (eh, c); break;
+	}
+    }
+    return res;
+}
+
+static Z_CategoryList *f_categoryList(ExpHandle *eh, data1_node *n)
+{
+    Z_CategoryList *res = (Z_CategoryList *)odr_malloc(eh->o, sizeof(*res));
+    data1_node *c;
+
+    res->commonInfo = 0;
+    res->num_categories = 0;
+    res->categories = NULL;
+
+    for (c = n->child; c; c = c->next)
+    {
+	int i = 0;
+
+	switch (is_numeric_tag (eh, c))
+	{
+	case 600: res->commonInfo = f_commonInfo(eh, c); break;
+	case 300:
+	    for (n = c->child; n; n = n->next)
+	    {
+		if (is_numeric_tag(eh, n) != 301)
+		    continue;
+		(res->num_categories)++;
+	    }
+	    if (res->num_categories)
+		res->categories =
+		    (Z_CategoryInfo **)odr_malloc (eh->o, res->num_categories 
+						   * sizeof(*res->categories));
+	    for (n = c->child; n; n = n->next)
+	    {
+		if (is_numeric_tag(eh, n) != 301)
+		    continue;
+		res->categories[i++] = f_categoryInfo (eh, n);
+	    }
+	    break;
+	}
+    }
+    assert (res->num_categories && res->categories);
+    return res;
+}
+
+static Z_TargetInfo *f_targetInfo(ExpHandle *eh, data1_node *n)
+{
+    Z_TargetInfo *res = (Z_TargetInfo *)odr_malloc(eh->o, sizeof(*res));
+    data1_node *c;
+
+    res->commonInfo = 0;
+    res->name = 0;
+    res->recentNews = 0;
+    res->icon = 0;
+    res->namedResultSets = 0;
+    res->multipleDBsearch = 0;
+    res->maxResultSets = 0;
+    res->maxResultSize = 0;
+    res->maxTerms = 0;
+    res->timeoutInterval = 0;
+    res->welcomeMessage = 0;
+    res->contactInfo = 0;
+    res->description = 0;
+    res->num_nicknames = 0;
+    res->nicknames = 0;
+    res->usageRest = 0;
+    res->paymentAddr = 0;
+    res->hours = 0;
+    res->num_dbCombinations = 0;
+    res->dbCombinations = 0;
+    res->num_addresses = 0;
+    res->addresses = 0;
+    res->num_languages = 0;
+    res->languages = NULL;
+    res->commonAccessInfo = 0;
+    
+    for (c = n->child; c; c = c->next)
+    {
+	int i = 0;
+
+	switch (is_numeric_tag (eh, c))
+	{
+	case 600: res->commonInfo = f_commonInfo(eh, c); break;
+	case 102: res->name = f_string(eh, c); break;
+	case 103: res->recentNews = f_humstring(eh, c); break;
+	case 104: res->icon = NULL; break; /* fix */
+	case 105: res->namedResultSets = f_bool(eh, c); break;
+	case 106: res->multipleDBsearch = f_bool(eh, c); break;
+	case 107: res->maxResultSets = f_integer(eh, c); break;
+	case 108: res->maxResultSize = f_integer(eh, c); break;
+	case 109: res->maxTerms = f_integer(eh, c); break;
+	case 110: res->timeoutInterval = f_intunit(eh, c); break;
+	case 111: res->welcomeMessage = f_humstring(eh, c); break;
+	case 112: res->contactInfo = f_contactInfo(eh, c); break;
+	case 113: res->description = f_humstring(eh, c); break;
+	case 114: 
+	    res->num_nicknames = 0;
+	    for (n = c->child; n; n = n->next)
+	    {
+		if (is_numeric_tag(eh, n) != 102)
+		    continue;
+		(res->num_nicknames)++;
+	    }
+	    if (res->num_nicknames)
+		res->nicknames =
+		    (char **)odr_malloc (eh->o, res->num_nicknames 
+				* sizeof(*res->nicknames));
+	    for (n = c->child; n; n = n->next)
+	    {
+		if (is_numeric_tag(eh, n) != 102)
+		    continue;
+		res->nicknames[i++] = f_string (eh, n);
+	    }
+	    break;
+	case 115: res->usageRest = f_humstring(eh, c); break;
+	case 116: res->paymentAddr = f_humstring(eh, c); break;
+	case 117: res->hours = f_humstring(eh, c); break;
+	case 118:
+	    res->num_dbCombinations = 0;
+	    for (n = c->child; n; n = n->next)
+	    {
+		if (!is_numeric_tag(eh, n) != 605)
+		    continue;
+		(res->num_dbCombinations)++;
+	    }
+	    if (res->num_dbCombinations)
+		res->dbCombinations =
+		    (Z_DatabaseList **)odr_malloc (eh->o, res->num_dbCombinations
+				* sizeof(*res->dbCombinations));
+	    for (n = c->child; n; n = n->next)
+	    {
+		if (!is_numeric_tag(eh, n) != 605)
+		    continue;
+		res->dbCombinations[i++] = f_databaseList (eh, n);
+	    }
+	    break;
+	case 119: 
+	    res->addresses =
+		f_networkAddresses (eh, c, &res->num_addresses);
+	    break;
+	case 125:
+	    res->num_languages = 0;
+	    for (n = c->child; n; n = n->next)
+	    {
+		if (!is_numeric_tag(eh, n) != 126)
+		    continue;
+		(res->num_languages)++;
+	    }
+	    if (res->num_languages)
+		res->languages = (char **)
+		    odr_malloc (eh->o, res->num_languages *
+				sizeof(*res->languages));
+	    for (n = c->child; n; n = n->next)
+	    {
+		if (!is_numeric_tag(eh, n) != 126)
+		    continue;
+		res->languages[i++] = f_string (eh, n);
+	    }
+	    break;
+	case 500: res->commonAccessInfo = f_accessInfo(eh, c); break;
+	}
+    }
+    if (!res->namedResultSets)
+	res->namedResultSets = eh->false_value;
+    if (!res->multipleDBsearch)
+	res->multipleDBsearch = eh->false_value;
+    return res;
+}
+
+static Z_DatabaseInfo *f_databaseInfo(ExpHandle *eh, data1_node *n)
+{
+    Z_DatabaseInfo *res = (Z_DatabaseInfo *)odr_malloc(eh->o, sizeof(*res));
+    data1_node *c;
+
+    res->commonInfo = 0;
+    res->name = 0;
+    res->explainDatabase = 0;
+    res->num_nicknames = 0;
+    res->nicknames = 0;
+    res->icon = 0;
+    res->userFee = 0;
+    res->available = 0;
+    res->titleString = 0;
+    res->num_keywords = 0;
+    res->keywords = 0;
+    res->description = 0;
+    res->associatedDbs = 0;
+    res->subDbs = 0;
+    res->disclaimers = 0;
+    res->news = 0;
+    res->u.actualNumber = 0;
+    res->defaultOrder = 0;
+    res->avRecordSize = 0;
+    res->maxRecordSize = 0;
+    res->hours = 0;
+    res->bestTime = 0;
+    res->lastUpdate = 0;
+    res->updateInterval = 0;
+    res->coverage = 0;
+    res->proprietary = 0;
+    res->copyrightText = 0;
+    res->copyrightNotice = 0;
+    res->producerContactInfo = 0;
+    res->supplierContactInfo = 0;
+    res->submissionContactInfo = 0;
+    res->accessInfo = 0;
+    
+    for (c = n->child; c; c = c->next)
+    {
+	int i = 0;
+
+	switch (is_numeric_tag (eh, c))
+	{
+	case 600: res->commonInfo = f_commonInfo(eh, c); break;
+	case 102: res->name = f_string(eh, c); break;
+	case 226: res->explainDatabase = odr_nullval(); break;
+	case 114:
+	    res->num_nicknames = 0;
+	    for (n = c->child; n; n = n->next)
+	    {
+		if (!is_numeric_tag(eh, n) ||
+		    n->u.tag.element->tag->value.numeric != 102)
+		    continue;
+		(res->num_nicknames)++;
+	    }
+	    if (res->num_nicknames)
+		res->nicknames =
+		    (char **)odr_malloc (eh->o, res->num_nicknames 
+				* sizeof(*res->nicknames));
+	    for (n = c->child; n; n = n->next)
+	    {
+		if (!is_numeric_tag(eh, n) ||
+		    n->u.tag.element->tag->value.numeric != 102)
+		    continue;
+		res->nicknames[i++] = f_string (eh, n);
+	    }
+	    break;
+	case 104: res->icon = 0; break;      /* fix */
+	case 201: res->userFee = f_bool(eh, c); break;
+	case 202: res->available = f_bool(eh, c); break;
+	case 203: res->titleString = f_humstring(eh, c); break;
+	case 227:
+	    res->num_keywords = 0;
+	    for (n = c->child; n; n = n->next)
+	    {
+		if (!is_numeric_tag(eh, n) != 1000)
+		    continue;
+		(res->num_keywords)++;
+	    }
+	    if (res->num_keywords)
+		res->keywords =
+		    (Z_HumanString **)odr_malloc (eh->o, res->num_keywords 
+				* sizeof(*res->keywords));
+	    for (n = c->child; n; n = n->next)
+	    {
+		if (!is_numeric_tag(eh, n) != 1000)
+		    continue;
+		res->keywords[i++] = f_humstring (eh, n);
+	    }
+	    break;
+	case 113: res->description = f_humstring(eh, c); break;
+	case 205:
+	    res->associatedDbs = f_databaseList (eh, c);
+	    break;
+	case 206:
+	    res->subDbs = f_databaseList (eh, c);
+	    break;
+	case 207: res->disclaimers = f_humstring(eh, c); break;
+	case 103: res->news = f_humstring(eh, c); break;
+	case 209: res->u.actualNumber =
+		      f_recordCount(eh, c, &res->which); break;
+	case 212: res->defaultOrder = f_humstring(eh, c); break;
+	case 213: res->avRecordSize = f_integer(eh, c); break;
+	case 214: res->maxRecordSize = f_integer(eh, c); break;
+	case 215: res->hours = f_humstring(eh, c); break;
+	case 216: res->bestTime = f_humstring(eh, c); break;
+	case 217: res->lastUpdate = f_string(eh, c); break;
+	case 218: res->updateInterval = f_intunit(eh, c); break;
+	case 219: res->coverage = f_humstring(eh, c); break;
+	case 220: res->proprietary = f_bool(eh, c); break;
+	case 221: res->copyrightText = f_humstring(eh, c); break;
+	case 222: res->copyrightNotice = f_humstring(eh, c); break;
+	case 223: res->producerContactInfo = f_contactInfo(eh, c); break;
+	case 224: res->supplierContactInfo = f_contactInfo(eh, c); break;
+	case 225: res->submissionContactInfo = f_contactInfo(eh, c); break;
+	case 500: res->accessInfo = f_accessInfo(eh, c); break;
+	}
+    }
+    if (!res->userFee)
+	res->userFee = eh->false_value;
+    if (!res->available)
+	res->available = eh->true_value;
+    return res;
+}
+
+Z_StringOrNumeric *f_stringOrNumeric (ExpHandle *eh, data1_node *n)
+{
+    Z_StringOrNumeric *res = (Z_StringOrNumeric *)
+	odr_malloc (eh->o, sizeof(*res));
+    data1_node *c;
+    for (c = n->child; c; c = c->next)
+    {
+	switch (is_numeric_tag (eh, c))
+	{
+	case 1001:
+	    res->which = Z_StringOrNumeric_string;
+	    res->u.string = f_string (eh, c);
+	    break;
+	case 1002:
+	    res->which = Z_StringOrNumeric_numeric;
+	    res->u.numeric = f_integer (eh, c);
+	    break;
+	}
+    }
+    return res;
+}
+
+Z_AttributeDescription *f_attributeDescription (
+    ExpHandle *eh, data1_node *n)
+{
+    Z_AttributeDescription *res = (Z_AttributeDescription *)
+	odr_malloc(eh->o, sizeof(*res));
+    data1_node *c;
+    int i = 0;
+	
+    res->name = 0;
+    res->description = 0;
+    res->attributeValue = 0;
+    res->num_equivalentAttributes = 0;
+    res->equivalentAttributes = 0;
+
+    for (c = n->child; c; c = c->next)
+    {
+	switch (is_numeric_tag (eh, c))
+	{
+	case 102: res->name = f_string (eh, c); break;
+	case 113: res->description = f_humstring (eh, c); break;
+	case 710: res->attributeValue = f_stringOrNumeric (eh, c); break;
+	case 752: (res->num_equivalentAttributes++); break;
+	}
+    }
+    if (res->num_equivalentAttributes)
+	res->equivalentAttributes = (Z_StringOrNumeric **)
+	    odr_malloc (eh->o, sizeof(*res->equivalentAttributes) *
+			res->num_equivalentAttributes);
+    for (c = n->child; c; c = c->next)
+	if (is_numeric_tag (eh, c) == 752)
+	    res->equivalentAttributes[i++] = f_stringOrNumeric (eh, c);
+    return res;
+}
+
+Z_AttributeType *f_attributeType (ExpHandle *eh, data1_node *n)
+{
+    Z_AttributeType *res = (Z_AttributeType *)
+	odr_malloc(eh->o, sizeof(*res));
+    data1_node *c;
+
+    res->name = 0;
+    res->description = 0;
+    res->attributeType = 0;
+    res->num_attributeValues = 0;
+    res->attributeValues = 0;
+
+    for (c = n->child; c; c = c->next)
+    {
+	int i = 0;
+	switch (is_numeric_tag (eh, c))
+	{
+	case 102: res->name = f_string (eh, c); break;
+	case 113: res->description = f_humstring (eh, c); break;
+	case 704: res->attributeType = f_integer (eh, c); break;
+	case 708:
+	    for (n = c->child; n; n = n->next)
+	    {
+		if (is_numeric_tag(eh, n) != 709)
+		    continue;
+		(res->num_attributeValues)++;
+	    }
+	    if (res->num_attributeValues)
+		res->attributeValues = (Z_AttributeDescription **)
+		    odr_malloc (eh->o, res->num_attributeValues
+				* sizeof(*res->attributeValues));
+	    for (n = c->child; n; n = n->next)
+	    {
+		if (is_numeric_tag(eh, n) != 709)
+		    continue;
+		res->attributeValues[i++] = f_attributeDescription (eh, n);
+	    }
+	    break;
+	}
+    }
+    return res;
+}
+
+Z_AttributeSetInfo *f_attributeSetInfo (ExpHandle *eh, data1_node *n)
+{
+    Z_AttributeSetInfo *res = (Z_AttributeSetInfo *)
+	odr_malloc(eh->o, sizeof(*res));
+    data1_node *c;
+
+    res->commonInfo = 0;
+    res->attributeSet = 0;
+    res->name = 0;
+    res->num_attributes = 0;
+    res->attributes = 0;
+    res->description = 0;
+    for (c = n->child; c; c = c->next)
+    {
+	int i = 0;
+	switch (is_numeric_tag (eh, c))
+	{
+	case 600: res->commonInfo = f_commonInfo (eh, c); break;
+	case 1000: res->attributeSet = f_oid (eh, c, CLASS_ATTSET); break;
+	case 102: res->name = f_string (eh, c); break;
+	case 750:
+	    for (n = c->child; n; n = n->next)
+	    {
+		if (is_numeric_tag(eh, n) != 751)
+		    continue;
+		(res->num_attributes)++;
+	    }
+	    if (res->num_attributes)
+		res->attributes = (Z_AttributeType **)
+		    odr_malloc (eh->o, res->num_attributes
+				* sizeof(*res->attributes));
+	    for (n = c->child; n; n = n->next)
+	    {
+		if (is_numeric_tag(eh, n) != 751)
+		    continue;
+		res->attributes[i++] = f_attributeType (eh, n);
+	    }
+	    break;
+	case 113: res->description = f_humstring (eh, c); break;
+	}
+    }
+    return res;
+}
+
+Z_OmittedAttributeInterpretation *f_omittedAttributeInterpretation (
+    ExpHandle *eh, data1_node *n)
+{
+    Z_OmittedAttributeInterpretation *res = (Z_OmittedAttributeInterpretation*)
+	odr_malloc (eh->o, sizeof(*res));
+    data1_node *c;
+
+    res->defaultValue = 0;
+    res->defaultDescription = 0;
+    for (c = n->child; c; c = c->next)
+    {
+	switch (is_numeric_tag (eh, c))
+	{
+	case 706:
+	    res->defaultValue = f_stringOrNumeric (eh, c);
+	    break;
+	case 113:
+	    res->defaultDescription = f_humstring(eh, c);
+	    break;
+	}
+    }
+    return res;
+}
+
+Z_AttributeValue *f_attributeValue (ExpHandle *eh, data1_node *n)
+{
+    Z_AttributeValue *res = (Z_AttributeValue *)
+	odr_malloc (eh->o, sizeof(*res));
+    data1_node *c;
+
+    res->value = 0;
+    res->description = 0;
+    res->num_subAttributes = 0;
+    res->subAttributes = 0;
+    res->num_superAttributes = 0;
+    res->superAttributes = 0;
+    res->partialSupport = 0;
+    for (c = n->child; c; c = c->next)
+    {
+	int i = 0;
+	switch (is_numeric_tag (eh, c))
+	{
+	case 710:
+	    res->value = f_stringOrNumeric (eh, c);  break;
+	case 113:
+	    res->description = f_humstring (eh, c); break;
+	case 712:
+	    for (n = c->child; n; n = n->next)
+	    {
+		if (is_numeric_tag(eh, n) != 713)
+		    continue;
+		(res->num_subAttributes)++;
+	    }
+	    if (res->num_subAttributes)
+		res->subAttributes =
+		    (Z_StringOrNumeric **)
+		    odr_malloc (eh->o, res->num_subAttributes
+				* sizeof(*res->subAttributes));
+	    for (n = c->child; n; n = n->next)
+	    {
+		if (is_numeric_tag(eh, n) != 713)
+		    continue;
+		res->subAttributes[i++] = f_stringOrNumeric (eh, n);
+	    }
+	    break;
+	case 714:
+	    for (n = c->child; n; n = n->next)
+	    {
+		if (is_numeric_tag(eh, n) != 715)
+		    continue;
+		(res->num_superAttributes)++;
+	    }
+	    if (res->num_superAttributes)
+		res->superAttributes =
+		    (Z_StringOrNumeric **)
+		    odr_malloc (eh->o, res->num_superAttributes
+				* sizeof(*res->superAttributes));
+	    for (n = c->child; n; n = n->next)
+	    {
+		if (is_numeric_tag(eh, n) != 715)
+		    continue;
+		res->superAttributes[i++] = f_stringOrNumeric (eh, n);
+	    }
+	    break;
+	case 711:
+	    res->partialSupport = odr_nullval ();
+	    break;
+	}
+    }
+    return res;
+}
+
+Z_AttributeTypeDetails *f_attributeTypeDetails (ExpHandle *eh, data1_node *n)
+{
+    Z_AttributeTypeDetails *res = (Z_AttributeTypeDetails *)
+	odr_malloc(eh->o, sizeof(*res));
+    data1_node *c;
+    res->attributeType = 0;
+    res->defaultIfOmitted = 0;
+    res->num_attributeValues = 0;
+    res->attributeValues = 0;
+    for (c = n->child; c; c = c->next)
+    {
+	int i = 0;
+	switch (is_numeric_tag (eh, c))
+	{
+	case 704: res->attributeType = f_integer (eh, c); break;
+	case 705:
+	    res->defaultIfOmitted = f_omittedAttributeInterpretation (eh, c);
+	    break;
+	case 708:
+	    for (n = c->child; n; n = n->next)
+	    {
+		if (is_numeric_tag(eh, n) != 709)
+		    continue;
+		(res->num_attributeValues)++;
+	    }
+	    if (res->num_attributeValues)
+		res->attributeValues =
+		    (Z_AttributeValue **)
+		    odr_malloc (eh->o, res->num_attributeValues
+				* sizeof(*res->attributeValues));
+	    for (n = c->child; n; n = n->next)
+	    {
+		if (is_numeric_tag(eh, n) != 709)
+		    continue;
+		res->attributeValues[i++] = f_attributeValue (eh, n);
+	    }
+	    break;
+	}
+    }
+    return res;
+}
+
+Z_AttributeSetDetails *f_attributeSetDetails (ExpHandle *eh, data1_node *n)
+{
+    Z_AttributeSetDetails *res = (Z_AttributeSetDetails *)
+	odr_malloc(eh->o, sizeof(*res));
+    data1_node *c;
+    
+    res->attributeSet = 0;
+    res->num_attributesByType = 0;
+    res->attributesByType = 0;
+    for (c = n->child; c; c = c->next)
+    {
+	int i = 0;
+	switch (is_numeric_tag (eh, c))
+	{
+	case 1000: res->attributeSet = f_oid(eh, c, CLASS_ATTSET); break;
+	case 702:
+	    for (n = c->child; n; n = n->next)
+	    {
+		if (is_numeric_tag(eh, n) != 703)
+		    continue;
+		(res->num_attributesByType)++;
+	    }
+	    if (res->num_attributesByType)
+		res->attributesByType =
+		    (Z_AttributeTypeDetails **)
+		    odr_malloc (eh->o, res->num_attributesByType
+				* sizeof(*res->attributesByType));
+	    for (n = c->child; n; n = n->next)
+	    {
+		if (is_numeric_tag(eh, n) != 703)
+		    continue;
+		res->attributesByType[i++] = f_attributeTypeDetails (eh, n);
+	    }
+	    break;
+	}
+    }
+    return res;
+}
+
+Z_AttributeValueList *f_attributeValueList (ExpHandle *eh, data1_node *n)
+{
+    Z_AttributeValueList *res = (Z_AttributeValueList *)
+	odr_malloc (eh->o, sizeof(*res));
+    data1_node *c;
+    int i = 0;
+
+    res->num_attributes = 0;
+    res->attributes = 0;
+    for (c = n->child; c; c = c->next)
+	if (is_numeric_tag (eh, c) == 710)
+	    (res->num_attributes)++;
+    if (res->num_attributes)
+    {
+	res->attributes = (Z_StringOrNumeric **)
+	    odr_malloc (eh->o, res->num_attributes * sizeof(*res->attributes));
+    }
+    for (c = n->child; c; c = c->next)
+	if (is_numeric_tag(eh, c) == 710)
+	    res->attributes[i++] = f_stringOrNumeric (eh, c);
+    return res;
+}
+
+Z_AttributeOccurrence *f_attributeOccurrence (ExpHandle *eh, data1_node *n)
+{
+    Z_AttributeOccurrence *res = (Z_AttributeOccurrence *)
+	odr_malloc (eh->o, sizeof(*res));
+    data1_node *c;
+
+    res->attributeSet = 0;
+    res->attributeType = 0;
+    res->mustBeSupplied = 0;
+    res->which = Z_AttributeOcc_any_or_none;
+    res->attributeValues.any_or_none = odr_nullval ();
+
+    for (c = n->child; c; c = c->next)
+    {
+	switch (is_numeric_tag (eh, c))
+	{
+	case 1000:
+	    res->attributeSet = f_oid (eh, c, CLASS_ATTSET); break;
+	case 704:
+	    res->attributeType = f_integer (eh, c); break;
+	case 720:
+	    res->mustBeSupplied = odr_nullval (); break;
+	case 721:
+	    res->which = Z_AttributeOcc_any_or_none;
+	    res->attributeValues.any_or_none = odr_nullval ();
+	    break;
+	case 722:
+	    res->which = Z_AttributeOcc_specific;
+	    res->attributeValues.specific = f_attributeValueList (eh, c);
+	    break;
+	}
+    }
+    return res;
+}
+
+Z_AttributeCombination *f_attributeCombination (ExpHandle *eh, data1_node *n)
+{
+    Z_AttributeCombination *res = (Z_AttributeCombination *)
+	odr_malloc (eh->o, sizeof(*res));
+    data1_node *c;
+    int i = 0;
+
+    res->num_occurrences = 0;
+    res->occurrences = 0;
+    for (c = n->child; c; c = c->next)
+	if (is_numeric_tag (eh, c) == 719)
+	    (res->num_occurrences)++;
+    if (res->num_occurrences)
+    {
+	res->occurrences = (Z_AttributeOccurrence **)
+	    odr_malloc (eh->o, res->num_occurrences * sizeof(*res->occurrences));
+    }
+    for (c = n->child; c; c = c->next)
+	if (is_numeric_tag(eh, c) == 719)
+	    res->occurrences[i++] = f_attributeOccurrence (eh, c);
+    assert (res->num_occurrences);
+    return res;
+}
+
+Z_AttributeCombinations *f_attributeCombinations (ExpHandle *eh, data1_node *n)
+{
+    Z_AttributeCombinations *res = (Z_AttributeCombinations *)
+	odr_malloc (eh->o, sizeof(*res));
+    data1_node *c;
+    res->defaultAttributeSet = 0;
+    res->num_legalCombinations = 0;
+    res->legalCombinations = 0;
+
+    for (c = n->child; c; c = c->next)
+    {
+	int i = 0;
+	switch (is_numeric_tag (eh, c))
+	{
+	case 1000:
+	    res->defaultAttributeSet = f_oid (eh, c, CLASS_ATTSET);
+	    break;
+	case 717:
+	    for (n = c->child; n; n = n->next)
+	    {
+		if (is_numeric_tag(eh, n) != 718)
+		    continue;
+		(res->num_legalCombinations)++;
+	    }
+	    if (res->num_legalCombinations)
+		res->legalCombinations =
+		    (Z_AttributeCombination **)
+		    odr_malloc (eh->o, res->num_legalCombinations
+				* sizeof(*res->legalCombinations));
+	    for (n = c->child; n; n = n->next)
+	    {
+		if (is_numeric_tag(eh, n) != 718)
+		    continue;
+		res->legalCombinations[i++] = f_attributeCombination (eh, n);
+	    }
+	    break;
+	}
+    }
+    assert (res->num_legalCombinations);
+    return res;
+}
+
+Z_AttributeDetails *f_attributeDetails (ExpHandle *eh, data1_node *n)
+{
+    Z_AttributeDetails *res = (Z_AttributeDetails *)
+	odr_malloc(eh->o, sizeof(*res));
+    data1_node *c;
+
+    res->commonInfo = 0;
+    res->databaseName = 0;
+    res->num_attributesBySet = 0;
+    res->attributesBySet = NULL;
+    res->attributeCombinations = NULL;
+
+    for (c = n->child; c; c = c->next)
+    {
+	int i = 0;
+	switch (is_numeric_tag (eh, c))
+	{
+	case 600: res->commonInfo = f_commonInfo(eh, c); break;
+	case 102: res->databaseName = f_string (eh, c); break;
+	case 700:
+	    for (n = c->child; n; n = n->next)
+	    {
+		if (is_numeric_tag(eh, n) != 701)
+		    continue;
+		(res->num_attributesBySet)++;
+	    }
+	    if (res->num_attributesBySet)
+		res->attributesBySet =
+		    (Z_AttributeSetDetails **)
+		    odr_malloc (eh->o, res->num_attributesBySet
+				* sizeof(*res->attributesBySet));
+	    for (n = c->child; n; n = n->next)
+	    {
+		if (is_numeric_tag(eh, n) != 701)
+		    continue;
+		res->attributesBySet[i++] = f_attributeSetDetails (eh, n);
+	    }
+	    break;
+	case 716:
+	    res->attributeCombinations = f_attributeCombinations (eh, c);
+	    break;
+	}
+    }
+    return res;
+}
+
+Z_ExplainRecord *data1_nodetoexplain (data1_handle dh, data1_node *n,
+				      int select, ODR o)
+{
+    ExpHandle eh;
+    Z_ExplainRecord *res = (Z_ExplainRecord *)odr_malloc(o, sizeof(*res));
+
+    eh.dh = dh;
+    eh.select = select;
+    eh.o = o;
+    eh.false_value = (int *)odr_malloc(eh.o, sizeof(eh.false_value));
+    *eh.false_value = 0;
+    eh.true_value = (int *)odr_malloc(eh.o, sizeof(eh.true_value));
+    *eh.true_value = 1;
+
+    assert(n->which == DATA1N_root);
+    if (strcmp(n->u.root.type, "explain"))
+    {
+	yaz_log(LOG_WARN, "Attempt to convert a non-Explain record");
+	return 0;
+    }
+    for (n = n->child; n; n = n->next)
+    {
+	switch (is_numeric_tag (&eh, n))
+	{
+	case 1:
+	    res->which = Z_Explain_categoryList;
+	    if (!(res->u.categoryList = f_categoryList(&eh, n)))
+		return 0;
+	    return res;	    
+	case 2:
+	    res->which = Z_Explain_targetInfo;
+	    if (!(res->u.targetInfo = f_targetInfo(&eh, n)))
+		return 0;
+	    return res;
+	case 3:
+	    res->which = Z_Explain_databaseInfo;
+	    if (!(res->u.databaseInfo = f_databaseInfo(&eh, n)))
+		return 0;
+	    return res;
+	case 7:
+	    res->which = Z_Explain_attributeSetInfo;
+	    if (!(res->u.attributeSetInfo = f_attributeSetInfo(&eh, n)))
+		return 0;
+	    return res;	    
+	case 10:
+	    res->which = Z_Explain_attributeDetails;
+	    if (!(res->u.attributeDetails = f_attributeDetails(&eh, n)))
+		return 0;
+	    return res;
+	}
+    }
+    yaz_log(LOG_WARN, "No category in Explain record");
+    return 0;
+}
Index: /main/tags/2.25/gsdl/packages/yaz/retrieval/d1_grs.c
===================================================================
--- /main/tags/2.25/gsdl/packages/yaz/retrieval/d1_grs.c	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/yaz/retrieval/d1_grs.c	(revision 21064)
@@ -0,0 +1,346 @@
+/*
+ * Copyright (c) 1995-1999, Index Data.
+ * See the file LICENSE for details.
+ * Sebastian Hammer, Adam Dickmeiss
+ *
+ * $Log$
+ * Revision 1.1  2000/08/03 03:11:31  johnmcp
+ * Added the YAZ toolkit source to the packages directory (for z39.50 stuff)
+ *
+ * Revision 1.17  1999/11/30 13:47:12  adam
+ * Improved installation. Moved header files to include/yaz.
+ *
+ * Revision 1.16  1999/08/27 09:40:32  adam
+ * Renamed logf function to yaz_log. Removed VC++ project files.
+ *
+ * Revision 1.15  1999/03/31 11:18:25  adam
+ * Implemented odr_strdup. Added Reference ID to backend server API.
+ *
+ * Revision 1.14  1998/03/16 12:21:15  adam
+ * Fixed problem with tag names that weren't set to the right value
+ * when wildcards were used.
+ *
+ * Revision 1.13  1998/02/11 11:53:35  adam
+ * Changed code so that it compiles as C++.
+ *
+ * Revision 1.12  1997/11/24 11:33:56  adam
+ * Using function odr_nullval() instead of global ODR_NULLVAL when
+ * appropriate.
+ *
+ * Revision 1.11  1997/11/18 09:51:09  adam
+ * Removed element num_children from data1_node. Minor changes in
+ * data1 to Explain.
+ *
+ * Revision 1.10  1997/09/17 12:10:36  adam
+ * YAZ version 1.4.
+ *
+ * Revision 1.9  1997/05/14 06:54:03  adam
+ * C++ support.
+ *
+ * Revision 1.8  1996/12/05 13:17:49  quinn
+ * Fixed GRS-1 null-ref
+ *
+ * Revision 1.7  1996/10/11  11:57:23  quinn
+ * Smallish
+ *
+ * Revision 1.6  1996/07/06  19:58:34  quinn
+ * System headerfiles gathered in yconfig
+ *
+ * Revision 1.5  1996/06/03  09:46:42  quinn
+ * Added OID data type.
+ *
+ * Revision 1.4  1996/05/01  12:45:30  quinn
+ * Support use of local tag names in abs file.
+ *
+ * Revision 1.3  1995/11/13  09:27:35  quinn
+ * Fiddling with the variant stuff.
+ *
+ * Revision 1.2  1995/11/01  13:54:46  quinn
+ * Minor adjustments
+ *
+ * Revision 1.1  1995/11/01  11:56:07  quinn
+ * Added Retrieval (data management) functions en masse.
+ *
+ *
+ */
+
+#include <assert.h>
+#include <stdlib.h>
+
+#include <yaz/proto.h>
+#include <yaz/log.h>
+#include <yaz/data1.h>
+
+#define D1_VARIANTARRAY 20 /* fixed max length on sup'd variant-list. Lazy me */
+
+static Z_ElementMetaData *get_ElementMetaData(ODR o)
+{
+    Z_ElementMetaData *r = (Z_ElementMetaData *)odr_malloc(o, sizeof(*r));
+
+    r->seriesOrder = 0;
+    r->usageRight = 0;
+    r->num_hits = 0;
+    r->hits = 0;
+    r->displayName = 0;
+    r->num_supportedVariants = 0;
+    r->supportedVariants = 0;
+    r->message = 0;
+    r->elementDescriptor = 0;
+    r->surrogateFor = 0;
+    r->surrogateElement = 0;
+    r->other = 0;
+
+    return r;
+}
+
+/*
+ * N should point to the *last* (leaf) triple in a sequence. Construct a variant
+ * from each of the triples beginning (ending) with 'n', up to the
+ * nearest parent tag. num should equal the number of triples in the
+ * sequence.
+ */
+static Z_Variant *make_variant(data1_node *n, int num, ODR o)
+{
+    Z_Variant *v = (Z_Variant *)odr_malloc(o, sizeof(*v));
+    data1_node *p;
+
+    v->globalVariantSetId = 0;
+    v->num_triples = num;
+    v->triples = (Z_Triple **)odr_malloc(o, sizeof(Z_Triple*) * num);
+
+    /*
+     * cycle back up through the tree of variants
+     * (traversing exactly 'level' variants).
+     */
+    for (p = n, num--; p && num >= 0; p = p->parent, num--)
+    {
+	Z_Triple *t;
+
+	assert(p->which == DATA1N_variant);
+	t = v->triples[num] = (Z_Triple *)odr_malloc(o, sizeof(*t));
+	t->variantSetId = 0;
+	t->zclass = (int *)odr_malloc(o, sizeof(int));
+	*t->zclass = p->u.variant.type->zclass->zclass;
+	t->type = (int *)odr_malloc(o, sizeof(int));
+	*t->type = p->u.variant.type->type;
+
+	switch (p->u.variant.type->datatype)
+	{
+	    case DATA1K_string:
+		t->which = Z_Triple_internationalString;
+		t->value.internationalString =
+                    odr_strdup(o, p->u.variant.value);
+		break;
+	    default:
+		yaz_log(LOG_WARN, "Unable to handle value for variant %s",
+			p->u.variant.type->name);
+		return 0;
+	}
+    }
+    return v;
+}
+
+/*
+ * Traverse the variant children of n, constructing a supportedVariant list.
+ */
+static int traverse_triples(data1_node *n, int level, Z_ElementMetaData *m,
+    ODR o)
+{
+    data1_node *c;
+    
+    for (c = n->child; c; c = c->next)
+	if (c->which == DATA1N_data && level)
+	{
+	    if (!m->supportedVariants)
+		m->supportedVariants = (Z_Variant **)odr_malloc(o, sizeof(Z_Variant*) *
+		    D1_VARIANTARRAY);
+	    else if (m->num_supportedVariants >= D1_VARIANTARRAY)
+	    {
+		yaz_log(LOG_WARN, "Too many variants (D1_VARIANTARRAY==%d)",
+			D1_VARIANTARRAY);
+		return -1;
+	    }
+
+	    if (!(m->supportedVariants[m->num_supportedVariants++] =
+	    	make_variant(n, level, o)))
+		return -1;
+	}
+	else if (c->which == DATA1N_variant)
+	    if (traverse_triples(c, level+1, m, o) < 0)
+		return -1;
+    return 0;
+}
+
+static Z_ElementData *nodetoelementdata(data1_handle dh, data1_node *n,
+					int select, int leaf,
+					ODR o, int *len)
+{
+    Z_ElementData *res = (Z_ElementData *)odr_malloc(o, sizeof(*res));
+
+    if (!n)
+    {
+	res->which = Z_ElementData_elementNotThere;
+	res->u.elementNotThere = odr_nullval();
+    }
+    else if (n->which == DATA1N_data && (leaf || n->next == NULL))
+    {
+	char str[512];
+	int toget;
+	data1_node *p;
+
+	for (p = n->parent; p && p->which != DATA1N_tag; p = p->parent)
+	    ;
+
+	switch (n->u.data.what)
+	{
+	    case DATA1I_num:
+	    	res->which = Z_ElementData_numeric;
+		res->u.numeric = (int *)odr_malloc(o, sizeof(int));
+		*res->u.numeric = atoi(n->u.data.data);
+		*len += 4;
+		break;
+	    case DATA1I_text:
+	        toget = n->u.data.len;
+		if (p->u.tag.get_bytes > 0 && p->u.tag.get_bytes < toget)
+		    toget = p->u.tag.get_bytes;
+	    	res->which = Z_ElementData_string;
+		res->u.string = (char *)odr_malloc(o, toget+1);
+		memcpy(res->u.string, n->u.data.data, toget);
+		res->u.string[toget] = '\0';
+		*len += toget;
+		break;
+	    case DATA1I_oid:
+	        res->which = Z_ElementData_oid;
+		strncpy(str, n->u.data.data, n->u.data.len);
+		str[n->u.data.len] = '\0';
+		res->u.oid = odr_getoidbystr(o, str);
+		*len += n->u.data.len;
+		break;
+	    default:
+	    	yaz_log(LOG_WARN, "Can't handle datatype.");
+		return 0;
+	}
+    }
+    else
+    {
+	res->which = Z_ElementData_subtree;
+	if (!(res->u.subtree = data1_nodetogr (dh, n->parent, select, o, len)))
+	    return 0;
+    }
+    return res;
+}
+
+static Z_TaggedElement *nodetotaggedelement(data1_handle dh, data1_node *n,
+					    int select, ODR o,
+					    int *len)
+{
+    Z_TaggedElement *res = (Z_TaggedElement *)odr_malloc(o, sizeof(*res));
+    data1_tag *tag = 0;
+    data1_node *data;
+    int leaf;
+
+    if (n->which == DATA1N_tag)
+    {
+	if (n->u.tag.element)
+	    tag = n->u.tag.element->tag;
+	data = n->child;
+	leaf = 0;
+    }
+    /*
+     * If we're a data element at this point, we need to insert a
+     * wellKnown tag to wrap us up.
+     */
+    else if (n->which == DATA1N_data || n->which == DATA1N_variant)
+    {
+	if (!(tag = data1_gettagbyname (dh, n->root->u.root.absyn->tagset,
+					"wellKnown")))
+	{
+	    yaz_log(LOG_WARN, "Unable to locate tag for 'wellKnown'");
+	    return 0;
+	}
+	data = n;
+	leaf = 1;
+    }
+    else
+    {
+	yaz_log(LOG_WARN, "Bad data.");
+	return 0;
+    }
+
+    res->tagType = (int *)odr_malloc(o, sizeof(int));
+    *res->tagType = (tag && tag->tagset) ? tag->tagset->type : 3;
+    res->tagValue = (Z_StringOrNumeric *)odr_malloc(o, sizeof(Z_StringOrNumeric));
+    if (tag && tag->which == DATA1T_numeric)
+    {
+	res->tagValue->which = Z_StringOrNumeric_numeric;
+	res->tagValue->u.numeric = (int *)odr_malloc(o, sizeof(int));
+	*res->tagValue->u.numeric = tag->value.numeric;
+    }
+    else
+    {
+	char *tagstr;
+
+	if (n->which == DATA1N_tag)      
+	    tagstr = n->u.tag.tag;       /* tag at node */
+	else if (tag)                    
+	    tagstr = tag->value.string;  /* no take from well-known */
+	else
+	    tagstr = "?";                /* no tag at all! */
+	res->tagValue->which = Z_StringOrNumeric_string;
+	res->tagValue->u.string = odr_strdup(o, tagstr);
+    }
+    res->tagOccurrence = 0;
+    res->appliedVariant = 0;
+    res->metaData = 0;
+    if (n->which == DATA1N_variant || (data && data->which ==
+	DATA1N_variant && data->next == NULL))
+    {
+	int nvars = 0;
+
+	res->metaData = get_ElementMetaData(o);
+	if (n->which == DATA1N_tag && n->u.tag.make_variantlist)
+	    if (traverse_triples(data, 0, res->metaData, o) < 0)
+		return 0;
+	while (data && data->which == DATA1N_variant)
+	{
+	    nvars++;
+	    data = data->child;
+	}
+	if (n->which != DATA1N_tag || !n->u.tag.no_data_requested)
+	    res->appliedVariant = make_variant(data->parent, nvars-1, o);
+    }
+    if (n->which == DATA1N_tag && n->u.tag.no_data_requested)
+    {
+	res->content = (Z_ElementData *)odr_malloc(o, sizeof(*res->content));
+	res->content->which = Z_ElementData_noDataRequested;
+	res->content->u.noDataRequested = odr_nullval();
+    }
+    else if (!(res->content = nodetoelementdata (dh, data, select, leaf,
+						 o, len)))
+	return 0;
+    *len += 10;
+    return res;
+}
+
+Z_GenericRecord *data1_nodetogr(data1_handle dh, data1_node *n,
+				int select, ODR o, int *len)
+{
+    Z_GenericRecord *res = (Z_GenericRecord *)odr_malloc(o, sizeof(*res));
+    data1_node *c;
+    int num_children = 0;
+    
+    for (c = n->child; c; c = c->next)
+	num_children++;
+
+    res->elements = (Z_TaggedElement **)odr_malloc(o, sizeof(Z_TaggedElement *) * num_children);
+    res->num_elements = 0;
+    for (c = n->child; c; c = c->next)
+    {
+	if (c->which == DATA1N_tag && select && !c->u.tag.node_selected)
+	    continue;
+	if (!(res->elements[res->num_elements++] =
+	      nodetotaggedelement (dh, c, select, o, len)))
+	    return 0;
+    }
+    return res;
+}
Index: /main/tags/2.25/gsdl/packages/yaz/retrieval/d1_handle.c
===================================================================
--- /main/tags/2.25/gsdl/packages/yaz/retrieval/d1_handle.c	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/yaz/retrieval/d1_handle.c	(revision 21064)
@@ -0,0 +1,139 @@
+/*
+ * Copyright (c) 1995-1999, Index Data.
+ * See the file LICENSE for details.
+ * Sebastian Hammer, Adam Dickmeiss
+ *
+ * $Log$
+ * Revision 1.1  2000/08/03 03:11:32  johnmcp
+ * Added the YAZ toolkit source to the packages directory (for z39.50 stuff)
+ *
+ * Revision 1.6  1999/11/30 13:47:12  adam
+ * Improved installation. Moved header files to include/yaz.
+ *
+ * Revision 1.5  1999/08/27 09:40:32  adam
+ * Renamed logf function to yaz_log. Removed VC++ project files.
+ *
+ * Revision 1.4  1998/05/18 13:07:05  adam
+ * Changed the way attribute sets are handled by the retriaval module.
+ * Extended Explain conversion / schema.
+ * Modified server and client to work with ASN.1 compiled protocol handlers.
+ *
+ * Revision 1.3  1998/02/11 11:53:35  adam
+ * Changed code so that it compiles as C++.
+ *
+ * Revision 1.2  1997/09/30 11:50:04  adam
+ * Added handler data1_get_map_buf that is used by data1_nodetomarc.
+ *
+ * Revision 1.1  1997/09/17 12:28:24  adam
+ * Introduced new 'global' data1 handle.
+ *
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+
+#include <yaz/log.h>
+#include <yaz/data1.h>
+
+struct data1_handle_info {
+    WRBUF wrbuf;
+    char *tab_path;
+
+    char *read_buf;
+    int read_len;
+
+    data1_absyn_cache absyn_cache;
+    data1_attset_cache attset_cache;
+
+    char *map_buf;
+    int map_len;
+
+    NMEM mem;
+};
+
+data1_handle data1_create (void)
+{
+    data1_handle p = (data1_handle)xmalloc (sizeof(*p));
+    if (!p)
+	return NULL;
+    p->tab_path = NULL;
+    p->wrbuf = wrbuf_alloc();
+    p->read_buf = NULL;
+    p->read_len = 0;
+    p->map_buf = NULL;
+    p->map_len = 0;
+    p->absyn_cache = NULL;
+    p->attset_cache = NULL;
+    p->mem = nmem_create ();
+    return p;
+}
+
+NMEM data1_nmem_get (data1_handle dh)
+{
+    return dh->mem;
+}
+
+data1_absyn_cache *data1_absyn_cache_get (data1_handle dh)
+{
+    return &dh->absyn_cache;
+}
+
+data1_attset_cache *data1_attset_cache_get (data1_handle dh)
+{
+    return &dh->attset_cache;
+}
+
+void data1_destroy (data1_handle dh)
+{
+    if (!dh)
+	return;
+    wrbuf_free (dh->wrbuf, 1);
+    if (dh->tab_path)
+	xfree (dh->tab_path);
+    if (dh->read_buf)
+	xfree (dh->read_buf);
+    if (dh->map_buf)
+        xfree (dh->map_buf);
+    nmem_destroy (dh->mem);
+    
+    xfree (dh);
+}
+
+WRBUF data1_get_wrbuf (data1_handle dp)
+{
+    return dp->wrbuf;
+}
+
+char **data1_get_read_buf (data1_handle dp, int **lenp)
+{
+    *lenp = &dp->read_len;
+    yaz_log (LOG_DEBUG, "data1_get_read_buf lenp=%u", **lenp);
+    return &dp->read_buf;
+}
+
+char **data1_get_map_buf (data1_handle dp, int **lenp)
+{
+    *lenp = &dp->map_len;
+    yaz_log (LOG_DEBUG, "data1_get_map_buf lenp=%u", **lenp);
+    return &dp->map_buf;
+}
+
+void data1_set_tabpath (data1_handle dp, const char *p)
+{
+    if (dp->tab_path)
+    {
+        xfree (dp->tab_path);
+        dp->tab_path = NULL;
+    }
+    if (p)
+    {
+        dp->tab_path = (char *)xmalloc (strlen(p)+1);
+        strcpy (dp->tab_path, p);
+    }
+}
+
+const char *data1_get_tabpath (data1_handle dp)
+{
+    return dp->tab_path;
+}
+
Index: /main/tags/2.25/gsdl/packages/yaz/retrieval/d1_if.c
===================================================================
--- /main/tags/2.25/gsdl/packages/yaz/retrieval/d1_if.c	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/yaz/retrieval/d1_if.c	(revision 21064)
@@ -0,0 +1,308 @@
+/*
+ * Copyright (c) 1995-2000, Index Data.
+ * See the file LICENSE for details.
+ *
+ * d1_if.c : A simple interface for extracting strings from data1_node
+ *           tree structures
+ *
+ * $Log$
+ * Revision 1.1  2000/08/03 03:11:32  johnmcp
+ * Added the YAZ toolkit source to the packages directory (for z39.50 stuff)
+ *
+ * Revision 1.5  2000/02/10 13:42:43  adam
+ * Removed C++ comment.
+ *
+ * Revision 1.4  2000/01/06 14:30:56  adam
+ * Minor change - to prevent warnings.
+ *
+ * Revision 1.3  2000/01/06 11:27:02  adam
+ * Minor fix so that this source compiles using Visual C++.
+ *
+ * Revision 1.2  2000/01/04 17:46:17  ian
+ * Added function to count occurences of a tag spec in a data1 tree.
+ *
+ * Revision 1.1  1999/12/21 14:16:19  ian
+ * Changed retrieval module to allow data1 trees with no associated absyn.
+ * Also added a simple interface for extracting values from data1 trees using
+ * a string based tagpath.
+ *
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <yaz/data1.h>
+#include <yaz/log.h>
+
+#include <string.h>
+
+
+/*
+ * Search for a token in the supplied string up to the supplied list of stop characters or EOL
+ * At the end, return the character causing the break and fill pTokenBuffer with the token string so far
+ * After the scan, *pPosInBuffer will point to the next character after the one causing the break and
+ *                 pTokenBuffer will contain the actual token
+ */
+char data1_ScanNextToken(char* pBuffer,
+                         char** pPosInBuffer,
+                         char* pBreakChars,
+                         char* pWhitespaceChars,
+                         char* pTokenBuffer)
+{
+    char* pBuff = pTokenBuffer;
+    *pBuff = '\0';
+
+    while ( **pPosInBuffer )
+    {
+        if ( strchr(pBreakChars,**pPosInBuffer) != NULL )
+        {
+            /* Current character is a break character */
+            *pBuff++ = '\0';
+            return *((*pPosInBuffer)++);
+        }
+        else
+        {
+            if ( strchr(pWhitespaceChars, **pPosInBuffer) != NULL )
+                (*pPosInBuffer)++;
+            else
+                *pBuff++ = *((*pPosInBuffer)++);
+        }
+    }
+
+    *pBuff++ = *((*pPosInBuffer)++);
+    return(**pPosInBuffer);
+}
+
+/* 
+ * Attempt to find a string value given the specified tagpath
+ * 
+ * Need to make this safe by passing in a buffer..... 
+ *
+ */
+char *data1_getNodeValue(data1_node* node, char* pTagPath)
+{
+    data1_node* n = NULL;
+
+    n = data1_LookupNode(node, pTagPath );
+
+    if ( n )
+    {
+        /* n should be a tag node with some data under it.... */
+        if ( n->child )
+        {
+            if ( n->child->which == DATA1N_data )
+            {
+                return n->child->u.data.data;
+            }
+            else
+            {
+                yaz_log(LOG_WARN,"Attempting to lookup data for tagpath: Child node is not a data node");
+            }
+        }
+        else
+        {
+            yaz_log(LOG_WARN,"Found a node matching the tagpath, but it has no child data nodes");
+        }
+    }
+    else
+    {
+        yaz_log(LOG_WARN,"Unable to lookup a node on the specified tag path");
+    }
+
+    return "";
+}
+
+
+/* Max length of a tag */
+#define MAX_TAG_SIZE 50
+
+/* 
+ * data1_LookupNode : Try and find a node as specified by a tagpath
+ */
+data1_node *data1_LookupNode(data1_node* node, char* pTagPath)
+{
+    /* Node matching the pattern in the tagpath */
+    data1_node* matched_node = NULL;
+
+    /* Current Child node as we search for nodes matching the pattern in the tagpath */
+    data1_node* current_child = node->child;
+
+    /* Current position in string */
+    char* pCurrCharInPath = pTagPath;
+
+    /* Work buffer */
+    char Buffer[MAX_TAG_SIZE];
+
+    /* The tag type of this node */
+    int iTagType = 0;
+
+    /* for non string tags, the tag value */
+    int iTagValue = 0;
+
+    /* for string tags, the tag value */
+    char StringTagVal[MAX_TAG_SIZE];
+
+    /* Which occurence of that tag under this node */
+    int iOccurences=0;
+
+    /* Character causing a break */
+    char sepchr = '\0';
+    Buffer[0] = '\0';
+    StringTagVal[0] = '\0';
+
+    sepchr = data1_ScanNextToken(pTagPath, &pCurrCharInPath, ",[(."," ", Buffer);
+
+    if ( sepchr == '[' )
+    {
+        /* Next component in node value is [ TagType, TagVal, TagOccurence ] */
+        sepchr = data1_ScanNextToken(pTagPath, &pCurrCharInPath, ","," ", Buffer);
+        iTagType = atoi(Buffer);
+
+        /* Occurence is optional... */
+        sepchr = data1_ScanNextToken(pTagPath, &pCurrCharInPath, ",]."," ", Buffer);
+
+        if ( iTagType == 3 )
+            strcpy(StringTagVal,Buffer);
+        else
+            iTagValue = atoi(Buffer);
+
+        /* If sepchar was a ',' there should be an instance */
+        if ( sepchr == ',' )
+        {
+            sepchr = data1_ScanNextToken(pTagPath, &pCurrCharInPath, "]."," ", Buffer);
+            iOccurences = atoi(Buffer);
+        }
+
+        if ( sepchr == ']' )
+        {
+            /* See if we can scan the . for the next component or the end of the line... */
+            sepchr = data1_ScanNextToken(pTagPath, &pCurrCharInPath, "."," ", Buffer);
+        }
+        else
+        {
+            yaz_log(LOG_FATAL,"Node does not end with a ]");
+            /* Fatal Error */
+            return(NULL);
+        }
+    }
+    else
+    {
+        /* We have a TagName so Read up to ( or . or EOL */
+        iTagType = 3;
+        strcpy(StringTagVal,Buffer);
+
+        if ( sepchr == '(' )
+        {
+            /* Read the occurence */
+            sepchr = data1_ScanNextToken(pTagPath, &pCurrCharInPath, ")"," ", Buffer);
+            iOccurences = atoi(Buffer);
+
+            /* See if we can find the . at the end of this clause */
+            sepchr = data1_ScanNextToken(pTagPath, &pCurrCharInPath, "."," ", Buffer);
+        }
+        
+    }
+
+    yaz_log(LOG_DEBUG,"search node for child like [%d,%d,%s,%d]",iTagType,iTagValue,StringTagVal,iOccurences);
+    
+
+    /* OK.. We have extracted tagtype, Value and Occurence, see if we can find a node */
+    /* Under the current parent matching that description                             */
+
+    while ( ( current_child ) && ( matched_node == NULL ) )
+    {
+        if ( current_child->which == DATA1N_tag )
+        {
+            if ( iTagType == 3 )
+            {
+                if ( ( current_child->u.tag.element == NULL ) &&
+                     ( strcmp(current_child->u.tag.tag, StringTagVal) == 0 ) )
+                {
+                    if ( iOccurences )
+                    {
+                        /* Everything matched, but not yet found the
+                           right occurence of the given tag */
+                        iOccurences--;
+                    }
+                    else
+                    {
+                        /* We have matched a string tag... Is there more to
+                           process? */
+                        matched_node = current_child;
+                    }
+                }
+            }
+            else /* Attempt to match real element */
+            {
+                yaz_log(LOG_WARN,"Non string tag matching not yet implemented");
+            }
+        }
+        current_child = current_child->next;
+    }
+
+
+    /* If there is more... Continue */
+    if ( ( sepchr == '.' ) && ( matched_node ) )
+    {
+        return data1_LookupNode(matched_node, pCurrCharInPath);
+    }
+    else
+    {
+        return matched_node;
+    }
+}
+
+/**
+
+data1_CountOccurences
+
+Count the number of occurences of the last instance on a tagpath.
+
+@param data1_node* node : The root of the tree we wish to look for occurences in
+@param const char* pTagPath : The tagpath we want to count the occurences of... 
+
+*/
+int data1_CountOccurences(data1_node* node, char* pTagPath)
+{
+    int iRetVal = 0;
+    data1_node* n = NULL;
+    data1_node* pParent = NULL;
+
+    n = data1_LookupNode(node, pTagPath );
+
+
+    if ( ( n ) &&
+         ( n->which == DATA1N_tag ) &&
+         ( n->parent ) )
+    {
+        data1_node* current_child;
+        pParent = n->parent;
+
+        for ( current_child = pParent->child;
+              current_child;
+              current_child = current_child->next )
+        {
+            if ( current_child->which == DATA1N_tag )
+            {
+                if ( current_child->u.tag.element == NULL )
+                {
+                    if ( ( n->u.tag.tag ) &&
+                         ( current_child->u.tag.tag ) &&
+                         ( strcmp(current_child->u.tag.tag, n->u.tag.tag) == 0 ) )
+                    {
+                        iRetVal++;
+                    }
+                }
+                else if ( current_child->u.tag.element == n->u.tag.element )
+                {
+                    /* Hmmm... Is the above right for non string tags???? */
+                    iRetVal++;
+                }
+            }
+        }
+    }
+
+    return iRetVal;
+}
Index: /main/tags/2.25/gsdl/packages/yaz/retrieval/d1_map.c
===================================================================
--- /main/tags/2.25/gsdl/packages/yaz/retrieval/d1_map.c	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/yaz/retrieval/d1_map.c	(revision 21064)
@@ -0,0 +1,369 @@
+/*
+ * Copyright (c) 1995-1999, Index Data.
+ * See the file LICENSE for details.
+ * Sebastian Hammer, Adam Dickmeiss
+ *
+ * $Log$
+ * Revision 1.1  2000/08/03 03:11:33  johnmcp
+ * Added the YAZ toolkit source to the packages directory (for z39.50 stuff)
+ *
+ * Revision 1.17  1999/11/30 13:47:12  adam
+ * Improved installation. Moved header files to include/yaz.
+ *
+ * Revision 1.16  1999/10/21 12:06:29  adam
+ * Retrieval module no longer uses ctype.h - functions.
+ *
+ * Revision 1.15  1999/08/27 09:40:32  adam
+ * Renamed logf function to yaz_log. Removed VC++ project files.
+ *
+ * Revision 1.14  1998/10/13 16:09:50  adam
+ * Added support for arbitrary OID's for tagsets, schemas and attribute sets.
+ * Added support for multiple attribute set references and tagset references
+ * from an abstract syntax file.
+ * Fixed many bad logs-calls in routines that read the various
+ * specifications regarding data1 (*.abs,*.att,...) and made the messages
+ * consistent whenever possible.
+ * Added extra 'lineno' argument to function readconf_line.
+ *
+ * Revision 1.13  1998/02/11 11:53:35  adam
+ * Changed code so that it compiles as C++.
+ *
+ * Revision 1.12  1997/11/18 09:51:09  adam
+ * Removed element num_children from data1_node. Minor changes in
+ * data1 to Explain.
+ *
+ * Revision 1.11  1997/09/17 12:10:36  adam
+ * YAZ version 1.4.
+ *
+ * Revision 1.10  1997/09/05 09:50:56  adam
+ * Removed global data1_tabpath - uses data1_get_tabpath() instead.
+ *
+ * Revision 1.9  1996/06/10 08:56:02  quinn
+ * Work on Summary.
+ *
+ * Revision 1.8  1996/05/01  12:45:31  quinn
+ * Support use of local tag names in abs file.
+ *
+ * Revision 1.7  1995/12/13  13:44:31  quinn
+ * Modified Data1-system to use nmem
+ *
+ * Revision 1.6  1995/12/12  16:37:08  quinn
+ * Added destroy element to data1_node.
+ *
+ * Revision 1.5  1995/12/12  14:11:31  quinn
+ * More work on the large-record problem.
+ *
+ * Revision 1.4  1995/12/11  15:22:37  quinn
+ * Added last_child field to the node.
+ * Rewrote schema-mapping.
+ *
+ * Revision 1.3  1995/11/01  16:34:56  quinn
+ * Making data1 look for tables in data1_tabpath
+ *
+ * Revision 1.2  1995/11/01  13:54:46  quinn
+ * Minor adjustments
+ *
+ * Revision 1.1  1995/11/01  11:56:08  quinn
+ * Added Retrieval (data management) functions en masse.
+ *
+ *
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <yaz/oid.h>
+#include <yaz/log.h>
+#include <yaz/readconf.h>
+#include <yaz/tpath.h>
+#include <yaz/data1.h>
+#include <yaz/d1_map.h>
+
+data1_maptab *data1_read_maptab (data1_handle dh, const char *file)
+{
+    NMEM mem = data1_nmem_get (dh);
+    data1_maptab *res = (data1_maptab *)nmem_malloc(mem, sizeof(*res));
+    FILE *f;
+    int lineno = 0;
+    int argc;
+    char *argv[50], line[512];
+    data1_mapunit **mapp;
+    int local_numeric = 0;
+
+    if (!(f = yaz_path_fopen(data1_get_tabpath(dh), file, "r")))
+    {
+	yaz_log(LOG_WARN|LOG_ERRNO, "%s", file);
+	return 0;
+    }
+
+    res->name = 0;
+    res->target_absyn_ref = VAL_NONE;
+    res->map = 0;
+    mapp = &res->map;
+    res->next = 0;
+
+    while ((argc = readconf_line(f, &lineno, line, 512, argv, 50)))
+	if (!strcmp(argv[0], "targetref"))
+	{
+	    if (argc != 2)
+	    {
+		yaz_log(LOG_WARN, "%s:%d: Bad # args for targetref",
+			file, lineno);
+		continue;
+	    }
+	    if ((res->target_absyn_ref = oid_getvalbyname(argv[1]))
+		== VAL_NONE)
+	    {
+		yaz_log(LOG_WARN, "%s:%d: Unknown reference '%s'",
+			file, lineno, argv[1]);
+		continue;
+	    }
+	}
+	else if (!strcmp(argv[0], "targetname"))
+	{
+	    if (argc != 2)
+	    {
+		yaz_log(LOG_WARN, "%s:%d: Bad # args for targetname",
+			file, lineno);
+		continue;
+	    }
+	    res->target_absyn_name =
+		(char *)nmem_malloc(mem, strlen(argv[1])+1);
+	    strcpy(res->target_absyn_name, argv[1]);
+	}
+	else if (!yaz_matchstr(argv[0], "localnumeric"))
+	    local_numeric = 1;
+	else if (!strcmp(argv[0], "name"))
+	{
+	    if (argc != 2)
+	    {
+		yaz_log(LOG_WARN, "%s:%d: Bad # args for name", file, lineno);
+		continue;
+	    }
+	    res->name = (char *)nmem_malloc(mem, strlen(argv[1])+1);
+	    strcpy(res->name, argv[1]);
+	}
+	else if (!strcmp(argv[0], "map"))
+	{
+	    data1_maptag **mtp;
+	    char *ep, *path = argv[2];
+
+	    if (argc < 3)
+	    {
+		yaz_log(LOG_WARN, "%s:%d: Bad # of args for map",
+			file, lineno);
+		continue;
+	    }
+	    *mapp = (data1_mapunit *)nmem_malloc(mem, sizeof(**mapp));
+	    (*mapp)->next = 0;
+	    if (argc > 3 && !data1_matchstr(argv[3], "nodata"))
+		(*mapp)->no_data = 1;
+	    else
+		(*mapp)->no_data = 0;
+	    (*mapp)->source_element_name =
+		(char *)nmem_malloc(mem, strlen(argv[1])+1);
+	    strcpy((*mapp)->source_element_name, argv[1]);
+	    mtp = &(*mapp)->target_path;
+	    if (*path == '/')
+		path++;
+	    for (ep = strchr(path, '/'); path; (void)((path = ep) &&
+		(ep = strchr(path, '/'))))
+	    {
+		int type, np;
+		char valstr[512], parm[512];
+
+		if (ep)
+		    ep++;
+		if ((np = sscanf(path, "(%d,%[^)]):%[^/]", &type, valstr,
+		    parm)) < 2)
+		{
+		    yaz_log(LOG_WARN, "%s:%d: Syntax error in map "
+			    "directive: %s", file, lineno, argv[2]);
+		    fclose(f);
+		    return 0;
+		}
+		*mtp = (data1_maptag *)nmem_malloc(mem, sizeof(**mtp));
+		(*mtp)->next = 0;
+		(*mtp)->type = type;
+		if (np > 2 && !data1_matchstr(parm, "new"))
+		    (*mtp)->new_field = 1;
+		else
+		    (*mtp)->new_field = 0;
+		if ((type != 3 || local_numeric) && d1_isdigit(*valstr))
+                {
+		    (*mtp)->which = D1_MAPTAG_numeric;
+		    (*mtp)->value.numeric = atoi(valstr);
+		}
+		else
+		{
+		    (*mtp)->which = D1_MAPTAG_string;
+		    (*mtp)->value.string =
+			(char *)nmem_malloc(mem, strlen(valstr)+1);
+		    strcpy((*mtp)->value.string, valstr);
+		}
+		mtp = &(*mtp)->next;
+	    }
+	    mapp = &(*mapp)->next;
+	}
+	else 
+	    yaz_log(LOG_WARN, "%s:%d: Unknown directive '%s'",
+		    file, lineno, argv[0]);
+
+    fclose(f);
+    return res;
+}
+
+/*
+ * Locate node with given elementname.
+ * NOTE: This is stupid - we don't find repeats this way.
+ */
+static data1_node *find_node(data1_node *p, char *elementname)
+{
+    data1_node *c, *r;
+
+    for (c = p->child; c; c = c->next)
+	if (c->which == DATA1N_tag && c->u.tag.element &&
+	    !data1_matchstr(c->u.tag.element->name, elementname))
+	    return c;
+	else if ((r = find_node(c, elementname)))
+	    return r;
+    return 0;
+}
+
+/*
+ * See if the node n is equivalent to the tag t.
+ */
+static int tagmatch(data1_node *n, data1_maptag *t)
+{
+    if (n->which != DATA1N_tag)
+	return 0;
+    if (n->u.tag.element)
+    {
+	if (n->u.tag.element->tag->tagset)
+	{
+	    if (n->u.tag.element->tag->tagset->type != t->type)
+		return 0;
+	}
+	else if (t->type != 3)
+	    return 0;
+	if (n->u.tag.element->tag->which == DATA1T_numeric)
+	{
+	    if (t->which != D1_MAPTAG_numeric)
+		return 0;
+	    if (n->u.tag.element->tag->value.numeric != t->value.numeric)
+		return 0;
+	}
+	else
+	{
+	    if (t->which != D1_MAPTAG_string)
+		return 0;
+	    if (data1_matchstr(n->u.tag.element->tag->value.string,
+		t->value.string))
+		return 0;
+	}
+    }
+    else /* local tag */
+    {
+	char str[10];
+
+	if (t->type != 3)
+	    return 0;
+	if (t->which == D1_MAPTAG_numeric)
+	    sprintf(str, "%d", t->value.numeric);
+	else
+	    strcpy(str, t->value.string);
+	if (data1_matchstr(n->u.tag.tag, str))
+	    return 0;
+    }
+    return 1;
+}
+
+static int map_children(data1_handle dh, data1_node *n, data1_maptab *map,
+			data1_node *res, NMEM mem)
+{
+    data1_node *c;
+    data1_mapunit *m;
+    /*
+     * locate each source element in turn.
+     */
+    for (c = n->child; c; c = c->next)
+	if (c->which == DATA1N_tag && c->u.tag.element)
+	{
+	    for (m = map->map; m; m = m->next)
+	    {
+		if (!data1_matchstr(m->source_element_name,
+		    c->u.tag.element->name))
+		{
+		    data1_node *pn = res;
+		    data1_node *cur = pn->last_child;
+		    data1_maptag *mt;
+
+		    /*
+		     * process the target path specification.
+		     */
+		    for (mt = m->target_path; mt; mt = mt->next)
+		    {
+			if (!cur || mt->new_field || !tagmatch(cur, mt))
+			{
+			    cur = data1_mk_node (dh, mem);
+			    cur->which = DATA1N_tag;
+			    cur->u.tag.element = 0;
+			    cur->u.tag.tag = mt->value.string;
+			    cur->u.tag.node_selected = 0;
+			    cur->parent = pn;
+			    cur->root = pn->root;
+			    if (!pn->child)
+				pn->child = cur;
+			    if (pn->last_child)
+				pn->last_child->next = cur;
+			    pn->last_child = cur;
+			}
+			
+			if (mt->next)
+			    pn = cur;
+			else if (!m->no_data)
+			{
+			    cur->child = c->child;
+			    cur->last_child = c->last_child;
+			    c->child = 0;
+			    c->last_child = 0;
+			}
+		    }
+		    break;
+		}
+	    }
+	    if (map_children(dh, c, map, res, mem) < 0)
+		return -1;
+	}
+    return 0;
+}
+
+/*
+ * Create a (possibly lossy) copy of the given record based on the
+ * table. The new copy will refer back to the data of the original record,
+ * which should not be discarded during the lifetime of the copy.
+ */
+data1_node *data1_map_record (data1_handle dh, data1_node *n,
+			      data1_maptab *map, NMEM m)
+{
+    data1_node *res = data1_mk_node(dh, m);
+
+    res->which = DATA1N_root;
+    res->u.root.type = map->target_absyn_name;
+    if (!(res->u.root.absyn = data1_get_absyn(dh, map->target_absyn_name)))
+    {
+	yaz_log(LOG_WARN, "%s: Failed to load target absyn '%s'",
+		map->name, map->target_absyn_name);
+    }
+    res->parent = 0;
+    res->root = res;
+
+    if (map_children(dh, n, map, res, m) < 0)
+    {
+	data1_free_tree(dh, res);
+	return 0;
+    }
+    return res;
+}
+
Index: /main/tags/2.25/gsdl/packages/yaz/retrieval/d1_marc.c
===================================================================
--- /main/tags/2.25/gsdl/packages/yaz/retrieval/d1_marc.c	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/yaz/retrieval/d1_marc.c	(revision 21064)
@@ -0,0 +1,381 @@
+/*
+ * Copyright (c) 1995-1999, Index Data.
+ * See the file LICENSE for details.
+ * Sebastian Hammer, Adam Dickmeiss
+ *
+ * $Log$
+ * Revision 1.1  2000/08/03 03:11:34  johnmcp
+ * Added the YAZ toolkit source to the packages directory (for z39.50 stuff)
+ *
+ * Revision 1.16  1999/11/30 13:47:12  adam
+ * Improved installation. Moved header files to include/yaz.
+ *
+ * Revision 1.15  1999/10/21 12:06:29  adam
+ * Retrieval module no longer uses ctype.h - functions.
+ *
+ * Revision 1.14  1999/08/27 09:40:32  adam
+ * Renamed logf function to yaz_log. Removed VC++ project files.
+ *
+ * Revision 1.13  1998/10/13 16:09:52  adam
+ * Added support for arbitrary OID's for tagsets, schemas and attribute sets.
+ * Added support for multiple attribute set references and tagset references
+ * from an abstract syntax file.
+ * Fixed many bad logs-calls in routines that read the various
+ * specifications regarding data1 (*.abs,*.att,...) and made the messages
+ * consistent whenever possible.
+ * Added extra 'lineno' argument to function readconf_line.
+ *
+ * Revision 1.12  1998/02/23 10:57:09  adam
+ * Take care of integer data nodes as well in conversion.
+ *
+ * Revision 1.11  1998/02/11 11:53:35  adam
+ * Changed code so that it compiles as C++.
+ *
+ * Revision 1.10  1997/09/30 11:50:04  adam
+ * Added handler data1_get_map_buf that is used by data1_nodetomarc.
+ *
+ * Revision 1.9  1997/09/24 13:35:45  adam
+ * Added two members to data1_marctab to ease reading of weird MARC records.
+ *
+ * Revision 1.8  1997/09/17 12:10:37  adam
+ * YAZ version 1.4.
+ *
+ * Revision 1.7  1997/09/05 09:50:57  adam
+ * Removed global data1_tabpath - uses data1_get_tabpath() instead.
+ *
+ * Revision 1.6  1997/09/04 13:51:58  adam
+ * Added data1 to marc conversion with indicators.
+ *
+ * Revision 1.5  1997/09/04 13:48:04  adam
+ * Added data1 to marc conversion.
+ *
+ * Revision 1.4  1996/03/25 10:18:03  quinn
+ * Removed trailing whitespace from data elements
+ *
+ * Revision 1.3  1995/11/01  16:34:57  quinn
+ * Making data1 look for tables in data1_tabpath
+ *
+ * Revision 1.2  1995/11/01  13:54:48  quinn
+ * Minor adjustments
+ *
+ * Revision 1.1  1995/11/01  11:56:08  quinn
+ * Added Retrieval (data management) functions en masse.
+ *
+ *
+ */
+
+
+#include <assert.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <yaz/oid.h>
+#include <yaz/log.h>
+#include <yaz/marcdisp.h>
+#include <yaz/readconf.h>
+#include <yaz/xmalloc.h>
+#include <yaz/data1.h>
+#include <yaz/tpath.h>
+
+data1_marctab *data1_read_marctab (data1_handle dh, const char *file)
+{
+    FILE *f;
+    NMEM mem = data1_nmem_get (dh);
+    data1_marctab *res = (data1_marctab *)nmem_malloc(mem, sizeof(*res));
+    char line[512], *argv[50];
+    int lineno = 0;
+    int argc;
+    
+    if (!(f = yaz_path_fopen(data1_get_tabpath(dh), file, "r")))
+    {
+	yaz_log(LOG_WARN|LOG_ERRNO, "%s", file);
+	return 0;
+    }
+
+    res->name = 0;
+    res->reference = VAL_NONE;
+    res->next = 0;
+    res->length_data_entry = 4;
+    res->length_starting = 5;
+    res->length_implementation = 0;
+    strcpy(res->future_use, "4");
+
+    strcpy(res->record_status, "n");
+    strcpy(res->implementation_codes, "    ");
+    res->indicator_length = 2;
+    res->identifier_length = 2;
+    res->force_indicator_length = -1;
+    res->force_identifier_length = -1;
+    strcpy(res->user_systems, "z  ");
+    
+    while ((argc = readconf_line(f, &lineno, line, 512, argv, 50)))
+	if (!strcmp(*argv, "name"))
+	{
+	    if (argc != 2)
+	    {
+		yaz_log(LOG_WARN, "%s:%d:Missing arg for %s", file, lineno,
+			*argv);
+		continue;
+	    }
+	    res->name = nmem_strdup(mem, argv[1]);
+	}
+	else if (!strcmp(*argv, "reference"))
+	{
+	    if (argc != 2)
+	    {
+		yaz_log(LOG_WARN, "%s:%d: Missing arg for %s", file, lineno,
+			*argv);
+		continue;
+	    }
+	    if ((res->reference = oid_getvalbyname(argv[1])) == VAL_NONE)
+	    {
+		yaz_log(LOG_WARN, "%s:%d: Unknown tagset reference '%s'",
+			file, lineno, argv[1]);
+		continue;
+	    }
+	}
+	else if (!strcmp(*argv, "length-data-entry"))
+	{
+	    if (argc != 2)
+	    {
+		yaz_log(LOG_WARN, "%s:%d: Missing arg for %s", file, lineno,
+			*argv);
+		continue;
+	    }
+	    res->length_data_entry = atoi(argv[1]);
+	}
+	else if (!strcmp(*argv, "length-starting"))
+	{
+	    if (argc != 2)
+	    {
+		yaz_log(LOG_WARN, "%s:%d: Missing arg for %s", file, lineno,
+			*argv);
+		continue;
+	    }
+	    res->length_starting = atoi(argv[1]);
+	}
+	else if (!strcmp(*argv, "length-implementation"))
+	{
+	    if (argc != 2)
+	    {
+		yaz_log(LOG_WARN, "%s:%d: Missing arg for %s", file, lineno,
+			*argv);
+		continue;
+	    }
+	    res->length_implementation = atoi(argv[1]);
+	}
+	else if (!strcmp(*argv, "future-use"))
+	{
+	    if (argc != 2)
+	    {
+		yaz_log(LOG_WARN, "%s:%d: Missing arg for %s", file, lineno,
+			*argv);
+		continue;
+	    }
+	    strncpy(res->future_use, argv[1], 2);
+	}
+	else if (!strcmp(*argv, "force-indicator-length"))
+	{
+	    if (argc != 2)
+	    {
+		yaz_log(LOG_WARN, "%s:%d: Missing arg for %s", file, lineno,
+			*argv);
+		continue;
+	    }
+	    res->force_indicator_length = atoi(argv[1]);
+	}
+	else if (!strcmp(*argv, "force-identifier-length"))
+	{
+	    if (argc != 2)
+	    {
+		yaz_log(LOG_WARN, "%s:%d: Missing arg for %s", file, lineno,
+			*argv);
+		continue;
+	    }
+	    res->force_identifier_length = atoi(argv[1]);
+	}
+	else
+	    yaz_log(LOG_WARN, "%s:%d: Unknown directive '%s'", file, lineno,
+		    *argv);
+
+    fclose(f);
+    return res;
+}
+
+/*
+ * Locate some data under this node. This routine should handle variants
+ * prettily.
+ */
+static char *get_data(data1_node *n, int *len)
+{
+    char *r;
+
+    while (n->which != DATA1N_data && n->child)
+	n = n->child;
+    if (n->which != DATA1N_data || 
+	(n->u.data.what != DATA1I_text && n->u.data.what != DATA1I_num))
+    {
+	r = "[Structured/included data]";
+	*len = strlen(r);
+	return r;
+    }
+
+    *len = n->u.data.len;
+    while (*len && d1_isspace(n->u.data.data[*len - 1]))
+	(*len)--;
+    return n->u.data.data;
+}
+
+static void memint (char *p, int val, int len)
+{
+    char buf[10];
+
+    if (len == 1)
+        *p = val + '0';
+    else
+    {
+        sprintf (buf, "%08d", val);
+        memcpy (p, buf+8-len, len);
+    }
+}
+
+static int is_indicator (data1_marctab *p, data1_node *subf)
+{
+#if 1
+    if (p->indicator_length != 2 ||
+	(subf->which == DATA1N_tag && strlen(subf->u.tag.tag) == 2))
+	return 1;
+#else
+    if (subf->which == DATA1N_tag && subf->child->which == DATA1N_tag)
+	return 1;
+#endif
+    return 0;
+}
+
+static int nodetomarc(data1_marctab *p, data1_node *n, int selected,
+    char **buf, int *size)
+{
+    int len = 26;
+    int dlen;
+    int base_address = 25;
+    int entry_p, data_p;
+    char *op;
+    data1_node *field, *subf;
+
+    yaz_log (LOG_DEBUG, "nodetomarc");
+    for (field = n->child; field; field = field->next)
+    {
+	if (field->which != DATA1N_tag)
+	{
+	    yaz_log(LOG_WARN, "Malformed field composition for marc output.");
+	    return -1;
+	}
+	if (selected && !field->u.tag.node_selected)
+	    continue;
+        len += 4 + p->length_data_entry + p->length_starting
+            + p->length_implementation;
+        base_address += 3 + p->length_data_entry + p->length_starting
+            + p->length_implementation;
+	if (strncmp(field->u.tag.tag, "00", 2))
+            len += p->indicator_length;      /* this is fairly bogus */
+	subf = field->child;
+	
+	/*  we'll allow no indicator if length is not 2 */
+	if (is_indicator (p, subf))
+	    subf = subf->child;
+
+        for (; subf; subf = subf->next)
+        {
+	    if (subf->which != DATA1N_tag)
+	    {
+		yaz_log(LOG_WARN,
+		    "Malformed subfield composition for marc output.");
+		return -1;
+	    }
+            if (strncmp(field->u.tag.tag, "00", 2))
+                len += p->identifier_length;
+	    get_data(subf, &dlen);
+            len += dlen;
+        }
+    }
+
+    if (!*buf)
+	*buf = (char *)xmalloc(*size = len);
+    else if (*size <= len)
+	*buf = (char *)xrealloc(*buf, *size = len);
+	
+    op = *buf;
+    memint (op, len, 5);
+    memcpy (op+5, p->record_status, 1);
+    memcpy (op+6, p->implementation_codes, 4);
+    memint (op+10, p->indicator_length, 1);
+    memint (op+11, p->identifier_length, 1);
+    memint (op+12, base_address, 5);
+    memcpy (op+17, p->user_systems, 3);
+    memint (op+20, p->length_data_entry, 1);
+    memint (op+21, p->length_starting, 1);
+    memint (op+22, p->length_implementation, 1);
+    memcpy (op+23, p->future_use, 1);
+    
+    entry_p = 24;
+    data_p = base_address;
+
+    for (field = n->child; field; field = field->next)
+    {
+        int data_0 = data_p;
+	char *indicator_data = "    ";
+	if (selected && !field->u.tag.node_selected)
+	    continue;
+
+	subf = field->child;
+
+	if (is_indicator (p, subf))
+	{
+            indicator_data = subf->u.tag.tag;
+	    subf = subf->child;
+	}
+        if (strncmp(field->u.tag.tag, "00", 2))   /* bogus */
+        {
+            memcpy (op + data_p, indicator_data, p->indicator_length);
+            data_p += p->indicator_length;
+        }
+        for (; subf; subf = subf->next)
+        {
+	    char *data;
+
+            if (strncmp(field->u.tag.tag, "00", 2))
+            {
+                op[data_p] = ISO2709_IDFS;
+                memcpy (op + data_p+1, subf->u.tag.tag, p->identifier_length-1);
+                data_p += p->identifier_length;
+            }
+	    data = get_data(subf, &dlen);
+            memcpy (op + data_p, data, dlen);
+            data_p += dlen;
+        }
+        op[data_p++] = ISO2709_FS;
+
+        memcpy (op + entry_p, field->u.tag.tag, 3);
+        entry_p += 3;
+        memint (op + entry_p, data_p - data_0, p->length_data_entry);
+        entry_p += p->length_data_entry;
+        memint (op + entry_p, data_0 - base_address, p->length_starting);
+        entry_p += p->length_starting;
+        entry_p += p->length_implementation;
+    }
+    op[entry_p++] = ISO2709_FS;
+    assert (entry_p == base_address);
+    op[data_p++] = ISO2709_RS;
+    assert (data_p == len);
+    return len;
+}
+
+char *data1_nodetomarc(data1_handle dh, data1_marctab *p, data1_node *n,
+		       int selected, int *len)
+{
+    int *size;
+    char **buf = data1_get_map_buf (dh, &size);
+
+    *len = nodetomarc(p, n, selected, buf, size);
+    return *buf;
+}
Index: /main/tags/2.25/gsdl/packages/yaz/retrieval/d1_prtree.c
===================================================================
--- /main/tags/2.25/gsdl/packages/yaz/retrieval/d1_prtree.c	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/yaz/retrieval/d1_prtree.c	(revision 21064)
@@ -0,0 +1,111 @@
+/*
+ * Copyright (c) 1995-1999, Index Data.
+ * See the file LICENSE for details.
+ * Sebastian Hammer, Adam Dickmeiss
+ *
+ * $Log$
+ * Revision 1.1  2000/08/03 03:11:34  johnmcp
+ * Added the YAZ toolkit source to the packages directory (for z39.50 stuff)
+ *
+ * Revision 1.6  1999/11/30 13:47:12  adam
+ * Improved installation. Moved header files to include/yaz.
+ *
+ * Revision 1.5  1999/01/25 13:49:47  adam
+ * Made data1_pr_tree make better printing of data1 buffers.
+ *
+ * Revision 1.4  1998/05/18 13:07:06  adam
+ * Changed the way attribute sets are handled by the retriaval module.
+ * Extended Explain conversion / schema.
+ * Modified server and client to work with ASN.1 compiled protocol handlers.
+ *
+ * Revision 1.3  1998/02/27 14:05:34  adam
+ * Added printing of integer nodes.
+ *
+ * Revision 1.2  1997/11/06 11:36:44  adam
+ * Implemented variant match on simple elements -data1 tree and Espec-1.
+ *
+ * Revision 1.1  1997/10/27 14:04:07  adam
+ * New debug utility, data1_pr_tree, that dumps a data1 tree.
+ *
+ */
+
+#include <yaz/log.h>
+#include <yaz/data1.h>
+
+static void pr_string (FILE *out, const char *str, int len)
+{
+    int i;
+    for (i = 0; i<len; i++)
+    {
+	int c = str[i];
+	if (c < 32 || c >126)
+	    fprintf (out, "\\x%02x", c);
+	else
+	    fputc (c, out);
+    }
+}
+
+static void pr_tree (data1_handle dh, data1_node *n, FILE *out, int level)
+{
+    fprintf (out, "%*s", level, "");
+    switch (n->which)
+    {
+     case DATA1N_root:
+         fprintf (out, "root abstract syntax=%s\n", n->u.root.type);
+         break;
+    case DATA1N_tag:
+	fprintf (out, "tag type=%s\n", n->u.tag.tag);
+	break;
+    case DATA1N_data:
+	fprintf (out, "data type=");
+	switch (n->u.data.what)
+	{
+	case DATA1I_inctxt:
+	    fprintf (out, "inctxt\n");
+	    break;
+	case DATA1I_incbin:
+	    fprintf (out, "incbin\n");
+	    break;
+	case DATA1I_text:
+	    fprintf (out, "text '");
+	    pr_string (out, n->u.data.data, n->u.data.len);
+	    fprintf (out, "'\n");
+	    break;
+	case DATA1I_num:
+	    fprintf (out, "num '");
+	    pr_string (out, n->u.data.data, n->u.data.len);
+	    fprintf (out, "'\n");
+	    break;
+	case DATA1I_oid:
+	    fprintf (out, "oid '");
+	    pr_string (out, n->u.data.data, n->u.data.len);
+	    fprintf (out, "'\n");
+	    break;
+	default:
+	    fprintf (out, "unknown(%d)\n", n->u.data.what);
+	    break;
+	}
+	break;
+    case DATA1N_variant:
+	fprintf (out, "variant\n");
+#if 0
+	if (n->u.variant.type->name)
+	    fprintf (out, " class=%s type=%d value=%s\n",
+		     n->u.variant.type->name, n->u.variant.type->type,
+		     n->u.variant.value);
+#endif
+	break;
+    default:
+	fprintf (out, "unknown(%d)\n", n->which);
+    }
+    if (n->child)
+	pr_tree (dh, n->child, out, level+4);
+    if (n->next)
+	pr_tree (dh, n->next, out, level);
+}
+
+
+void data1_pr_tree (data1_handle dh, data1_node *n, FILE *out)
+{
+    pr_tree (dh, n, out, 0);
+}
Index: /main/tags/2.25/gsdl/packages/yaz/retrieval/d1_read.c
===================================================================
--- /main/tags/2.25/gsdl/packages/yaz/retrieval/d1_read.c	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/yaz/retrieval/d1_read.c	(revision 21064)
@@ -0,0 +1,596 @@
+/*
+ * Copyright (c) 1995-1999, Index Data.
+ * See the file LICENSE for details.
+ * Sebastian Hammer, Adam Dickmeiss
+ *
+ * $Log$
+ * Revision 1.1  2000/08/03 03:11:35  johnmcp
+ * Added the YAZ toolkit source to the packages directory (for z39.50 stuff)
+ *
+ * Revision 1.32  2000/01/06 11:25:59  adam
+ * Added case to prevent warning.
+ *
+ * Revision 1.31  1999/12/21 14:16:20  ian
+ * Changed retrieval module to allow data1 trees with no associated absyn.
+ * Also added a simple interface for extracting values from data1 trees using
+ * a string based tagpath.
+ *
+ * Revision 1.30  1999/11/30 13:47:12  adam
+ * Improved installation. Moved header files to include/yaz.
+ *
+ * Revision 1.29  1999/10/21 12:06:29  adam
+ * Retrieval module no longer uses ctype.h - functions.
+ *
+ * Revision 1.28  1999/10/21 09:50:33  adam
+ * SGML reader uses own isspace - it doesn't do 8-bit on WIN32!
+ *
+ * Revision 1.27  1999/08/27 09:40:32  adam
+ * Renamed logf function to yaz_log. Removed VC++ project files.
+ *
+ * Revision 1.26  1999/07/13 13:23:48  adam
+ * Non-recursive version of data1_read_node. data1_read_nodex reads
+ * stream of bytes (instead of buffer in memory).
+ *
+ * Revision 1.25  1999/04/20 09:56:48  adam
+ * Added 'name' paramter to encoder/decoder routines (typedef Odr_fun).
+ * Modified all encoders/decoders to reflect this change.
+ *
+ * Revision 1.24  1998/10/28 15:10:09  adam
+ * Added --with-yc option to configure. For the data1_node in data1.h:
+ * decreased size of localdata and removed member "line" which wasn't useful.
+ *
+ * Revision 1.23  1998/03/12 11:28:45  adam
+ * Fix: didn't set root member of tagged node in function.
+ * data1_add_insert_taggeddata.
+ *
+ * Revision 1.22  1998/03/05 08:15:32  adam
+ * Implemented data1_add_insert_taggeddata utility which is more flexible
+ * than data1_insert_taggeddata.
+ *
+ * Revision 1.21  1998/02/27 14:08:05  adam
+ * Added const to some char pointer arguments.
+ * Reworked data1_read_node so that it doesn't create a tree with
+ * pointers to original "SGML"-buffer.
+ *
+ * Revision 1.20  1998/02/11 11:53:35  adam
+ * Changed code so that it compiles as C++.
+ *
+ * Revision 1.19  1997/12/09 16:17:09  adam
+ * Fix bug regarding variants. Tags with prefix "var" was incorrectly
+ * interpreted as "start of variants". Now, only "var" indicates such
+ * start.
+ * Cleaned up data1_read_node so tag names and variant names are
+ * copied and not pointed to by the generated data1 tree. Data nodes
+ * still point to old buffer.
+ *
+ * Revision 1.18  1997/11/18 09:51:09  adam
+ * Removed element num_children from data1_node. Minor changes in
+ * data1 to Explain.
+ *
+ * Revision 1.17  1997/11/05 09:20:51  adam
+ * Minor change.
+ *
+ * Revision 1.16  1997/09/17 12:10:37  adam
+ * YAZ version 1.4.
+ *
+ * Revision 1.15  1997/09/05 09:50:57  adam
+ * Removed global data1_tabpath - uses data1_get_tabpath() instead.
+ *
+ * Revision 1.14  1997/05/14 06:54:04  adam
+ * C++ support.
+ *
+ * Revision 1.13  1996/10/29 13:35:38  adam
+ * Implemented data1_set_tabpath and data1_get_tabpath.
+ *
+ * Revision 1.12  1996/10/11 10:35:38  adam
+ * Fixed a bug that caused data1_read_node to core dump when no abstract
+ * syntax was defined in a "sgml"-record.
+ *
+ * Revision 1.11  1996/07/06 19:58:35  quinn
+ * System headerfiles gathered in yconfig
+ *
+ * Revision 1.10  1996/01/19  15:41:47  quinn
+ * Fixed uninitialized boolean.
+ *
+ * Revision 1.9  1996/01/17  14:52:47  adam
+ * Changed prototype for reader function parsed to data1_read_record.
+ *
+ * Revision 1.8  1995/12/15  16:20:41  quinn
+ * Added formatted text.
+ *
+ * Revision 1.7  1995/12/13  13:44:32  quinn
+ * Modified Data1-system to use nmem
+ *
+ * Revision 1.6  1995/12/12  16:37:08  quinn
+ * Added destroy element to data1_node.
+ *
+ * Revision 1.5  1995/12/11  15:22:37  quinn
+ * Added last_child field to the node.
+ * Rewrote schema-mapping.
+ *
+ * Revision 1.4  1995/11/13  09:27:36  quinn
+ * Fiddling with the variant stuff.
+ *
+ * Revision 1.3  1995/11/01  16:34:57  quinn
+ * Making data1 look for tables in data1_tabpath
+ *
+ * Revision 1.2  1995/11/01  13:54:48  quinn
+ * Minor adjustments
+ *
+ * Revision 1.1  1995/11/01  11:56:09  quinn
+ * Added Retrieval (data management) functions en masse.
+ *
+ * Revision 1.14  1995/10/30  12:40:55  quinn
+ * Fixed a couple of bugs.
+ *
+ * Revision 1.13  1995/10/25  16:00:47  quinn
+ * USMARC support is now almost operational
+ *
+ * Revision 1.12  1995/10/16  14:02:55  quinn
+ * Changes to support element set names and espec1
+ *
+ * Revision 1.11  1995/10/13  16:05:08  quinn
+ * Adding Espec1-processing
+ *
+ * Revision 1.10  1995/10/11  14:53:44  quinn
+ * Work on variants.
+ *
+ * Revision 1.9  1995/10/06  16:56:50  quinn
+ * Fixed ranked result.
+ *
+ * Revision 1.8  1995/10/06  16:44:13  quinn
+ * Work on attribute set mapping, etc.
+ *
+ * Revision 1.7  1995/10/06  12:58:35  quinn
+ * SUTRS support
+ *
+ * Revision 1.6  1995/10/04  09:29:49  quinn
+ * Adjustments to support USGS test data
+ *
+ * Revision 1.5  1995/10/03  17:56:43  quinn
+ * Fixing GRS code.
+ *
+ * Revision 1.4  1995/10/02  15:53:19  quinn
+ * Work
+ *
+ * Revision 1.3  1995/10/02  14:55:21  quinn
+ * *** empty log message ***
+ *
+ * Revision 1.2  1995/09/14  15:18:13  quinn
+ * Work
+ *
+ * Revision 1.1  1995/09/12  11:24:30  quinn
+ * Beginning to add code for structured records.
+ *
+ *
+ */
+
+#include <assert.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+#include <yaz/xmalloc.h>
+#include <yaz/log.h>
+#include <yaz/data1.h>
+
+/*
+ * get the tag which is the immediate parent of this node (this may mean
+ * traversing intermediate things like variants and stuff.
+ */
+data1_node *get_parent_tag (data1_handle dh, data1_node *n)
+{
+    for (; n && n->which != DATA1N_root; n = n->parent)
+	if (n->which == DATA1N_tag)
+	    return n;
+    return 0;
+}
+
+data1_node *data1_mk_node (data1_handle dh, NMEM m)
+{
+    data1_node *r;
+
+    r = (data1_node *)nmem_malloc(m, sizeof(*r));
+    r->next = r->child = r->last_child = r->parent = 0;
+    r->destroy = 0;
+    return r;
+}
+
+void data1_free_tree (data1_handle dh, data1_node *t)
+{
+    data1_node *p = t->child, *pn;
+
+    while (p)
+    {
+	pn = p->next;
+	data1_free_tree (dh, p);
+	p = pn;
+    }
+    if (t->destroy)
+	(*t->destroy)(t);
+}
+
+char *data1_insert_string (data1_handle dh, data1_node *res,
+                           NMEM m, const char *str)
+{
+    int len = strlen(str);
+
+    if (len >= DATA1_LOCALDATA)
+        return nmem_strdup (m, str);
+    else
+    {
+        strcpy (res->lbuf, str);
+	return res->lbuf;
+    }
+}
+
+data1_node *data1_add_insert_taggeddata(data1_handle dh, data1_node *root,
+					data1_node *at,
+					const char *tagname, NMEM m,
+					int first_flag, int local_allowed)
+{
+    data1_node *partag = get_parent_tag (dh, at);
+    data1_node *tagn = data1_mk_node (dh, m);
+    data1_element *e = NULL;
+    data1_node *datn;
+
+    tagn->which = DATA1N_tag;
+    tagn->u.tag.tag = data1_insert_string (dh, tagn, m, tagname);
+    tagn->u.tag.node_selected = 0;
+    tagn->u.tag.make_variantlist = 0;
+    tagn->u.tag.no_data_requested = 0;
+    tagn->u.tag.get_bytes = -1;
+
+    if (partag)
+	e = partag->u.tag.element;
+    tagn->u.tag.element =
+	data1_getelementbytagname (dh, root->u.root.absyn, e, tagname);
+    if (!local_allowed && !tagn->u.tag.element)
+	return NULL;
+    tagn->last_child = tagn->child = datn = data1_mk_node (dh, m);
+    tagn->root = root;
+    datn->parent = tagn;
+    datn->root = root;
+    datn->which = DATA1N_data;
+    datn->u.data.formatted_text = 0;
+    tagn->parent = at;
+
+    if (first_flag)
+    {
+	tagn->next = at->child;
+	if (!tagn->next)
+	    at->last_child = tagn;
+	at->child = tagn;
+    }
+    else
+    {
+	if (!at->child)
+	    at->child = tagn;
+	else
+	{
+	    assert (at->last_child);
+	    at->last_child->next = tagn;
+	}
+	at->last_child = tagn;
+    }
+    return datn;
+}
+
+data1_node *data1_add_taggeddata(data1_handle dh, data1_node *root,
+				 data1_node *at,
+				 const char *tagname, NMEM m)
+{
+    return data1_add_insert_taggeddata (dh, root, at, tagname, m, 0, 1);
+}
+
+
+/*
+ * Insert a tagged node into the record root as first child of the node at
+ * which should be root or tag itself). Returns pointer to the data node,
+ * which can then be modified.
+ */
+data1_node *data1_insert_taggeddata(data1_handle dh, data1_node *root,
+				    data1_node *at,
+				    const char *tagname, NMEM m)
+{
+    return data1_add_insert_taggeddata (dh, root, at, tagname, m, 1, 0);
+}
+
+/*
+ * Ugh. Sometimes functions just grow and grow on you. This one reads a
+ * 'node' and its children.
+ */
+data1_node *data1_read_nodex (data1_handle dh, NMEM m,
+			      int (*get_byte)(void *fh), void *fh, WRBUF wrbuf)
+{
+    data1_absyn *absyn = 0;
+    data1_node *d1_stack[256];
+    data1_node *res;
+    int c;
+    int level = 0;
+    int line = 1;
+
+    d1_stack[level] = 0;
+    c = (*get_byte)(fh);
+    while (1)
+    {
+	data1_node *parent = level ? d1_stack[level-1] : 0;
+	while (c != '\0' && d1_isspace(c))
+	{
+	    if (c == '\n')
+		line++;
+	    c = (*get_byte)(fh);
+	}
+	if (c == '\0')
+	    break;
+	
+	if (c == '<') /* beginning of tag */
+	{
+	    char tag[64];
+	    char args[256];
+	    size_t i;
+	    
+	    for (i = 0; (c=(*get_byte)(fh)) && c != '>' && !d1_isspace(c);)
+		if (i < (sizeof(tag)-1))
+		    tag[i++] = c;
+	    tag[i] = '\0';
+	    while (d1_isspace(c))
+		c = (*get_byte)(fh);
+	    for (i = 0; c && c != '>'; c = (*get_byte)(fh))
+		if (i < (sizeof(args)-1))
+		    args[i++] = c;
+	    args[i] = '\0';
+	    if (c != '>')
+	    {
+		yaz_log(LOG_WARN, "d1: %d: Malformed tag", line);
+		return 0;
+	    }
+	    else
+		c = (*get_byte)(fh);
+
+	    /* End tag? */
+	    if (*tag == '/')       
+	    {
+		if (tag[1] == '\0')
+		    --level;        /* </> */
+		else
+		{                   /* </tag> */
+		    int i = level;
+		    while (i > 0)
+		    {
+			parent = d1_stack[--i];
+			if ((parent->which == DATA1N_root &&
+			     !strcmp(tag+1, parent->u.root.type)) ||
+			    (parent->which == DATA1N_tag &&
+			     !strcmp(tag+1, parent->u.tag.tag)))
+			{
+			    level = i;
+			    break;
+			}
+		    }
+		    if (i != level)
+		    {
+			yaz_log (LOG_WARN, "%d: no begin tag for %s",
+				 line, tag);
+			break;
+		    }
+		}
+		if (level == 0)
+		    return d1_stack[0];
+		continue;
+	    }	
+	    if (level == 0) /* root ? */
+	    {
+		if (!(absyn = data1_get_absyn (dh, tag)))
+		{
+		    yaz_log(LOG_WARN, "Unable to acquire abstract syntax " "for '%s'", tag); 
+                    /* It's now OK for a record not to have an absyn */
+		}
+		res = data1_mk_node (dh, m);
+		res->which = DATA1N_root;
+		res->u.root.type = data1_insert_string (dh, res, m, tag);
+		res->u.root.absyn = absyn;
+		res->root = res;
+	    }
+	    else if (!strcmp(tag, "var"))
+	    {
+		char tclass[DATA1_MAX_SYMBOL], type[DATA1_MAX_SYMBOL];
+		data1_vartype *tp;
+		int val_offset;
+		
+		if (sscanf(args, "%s %s %n", tclass, type, &val_offset) != 2)
+		{
+		    yaz_log(LOG_WARN, "Malformed variant triple at '%s'", tag);
+		    continue;
+		}
+		if (!(tp =
+		      data1_getvartypebyct(dh,
+					   parent->root->u.root.absyn->varset,
+					   tclass, type)))
+		    continue;
+		/*
+		 * If we're the first variant in this group, create a parent 
+		 * variant, and insert it before the current variant.
+		 */
+		if (parent->which != DATA1N_variant)
+		{
+		    res = data1_mk_node (dh, m);
+		    res->which = DATA1N_variant;
+		    res->u.variant.type = 0;
+		    res->u.variant.value = 0;
+		}
+		else
+		{
+		    /*
+		     * now determine if one of our ancestor triples is of
+		     * same type. If so, we break here.
+		     */
+		    int i;
+		    for (i = level-1; d1_stack[i]->which==DATA1N_variant; --i)
+			if (d1_stack[i]->u.variant.type == tp)
+			{
+			    level = i;
+			    break;
+			}
+		    res = data1_mk_node (dh, m);
+		    res->which = DATA1N_variant;
+		    res->u.variant.type = tp;
+		    res->u.variant.value =
+			data1_insert_string (dh, res, m, args + val_offset);
+		}
+	    }
+	    else /* tag.. acquire our element in the abstract syntax */
+	    {
+		data1_node *partag = get_parent_tag (dh, parent);
+		data1_element *elem, *e = 0;
+		int localtag = 0;
+		
+		if (parent->which == DATA1N_variant)
+		    return 0;
+		if (partag)
+		    if (!(e = partag->u.tag.element))
+			localtag = 1; /* our parent is a local tag */
+		
+		elem = data1_getelementbytagname(dh, absyn, e, tag);
+		res = data1_mk_node (dh, m);
+		res->which = DATA1N_tag;
+		res->u.tag.tag = data1_insert_string (dh, res, m, tag);
+		res->u.tag.element = elem;
+		res->u.tag.node_selected = 0;
+		res->u.tag.make_variantlist = 0;
+		res->u.tag.no_data_requested = 0;
+		res->u.tag.get_bytes = -1;
+	    }
+	    if (parent)
+	    {
+		parent->last_child = res;
+		res->root = parent->root;
+	    }
+	    res->parent = parent;
+	    if (d1_stack[level])
+		d1_stack[level]->next = res;
+	    else if (parent)
+		parent->child = res;
+	    d1_stack[level] = res;
+	    d1_stack[++level] = 0;
+	}
+	else /* != '<'... this is a body of text */
+	{
+	    const char *src;
+	    char *dst;
+	    int len, prev_char = 0;
+	    
+	    if (level == 0)
+	    {
+		c = (*get_byte)(fh);
+		continue;
+	    }
+	    res = data1_mk_node(dh, m);
+	    res->parent = parent;
+	    res->which = DATA1N_data;
+	    res->u.data.what = DATA1I_text;
+	    res->u.data.formatted_text = 0;
+	    res->root = parent->root;
+	    parent->last_child = res;
+	    if (d1_stack[level])
+		d1_stack[level]->next = res;
+	    else
+		parent->child = res;
+	    d1_stack[level] = res;
+	    
+	    wrbuf_rewind(wrbuf);
+
+	    while (c != '<')
+	    {
+		wrbuf_putc (wrbuf, c);
+		c = (*get_byte)(fh);
+	    }
+	    len = wrbuf_len(wrbuf);
+
+	    /* use local buffer of nmem if too large */
+	    if (len >= DATA1_LOCALDATA)
+		res->u.data.data = (char*) nmem_malloc (m, len);
+	    else
+		res->u.data.data = res->lbuf;
+	    
+	    /* read "data" and transfer while removing white space */
+	    dst = res->u.data.data;
+	    for (src = wrbuf_buf(wrbuf); --len >= 0; src++)
+	    {
+		if (*src == '\n')
+		    line++;
+		if (d1_isspace (*src))
+		    prev_char = ' ';
+		else
+		{
+		    if (prev_char)
+		    {
+			*dst++ = prev_char;
+			prev_char = 0;
+		    }
+		    *dst++ = *src;
+		}
+	    }
+	    res->u.data.len = dst - res->u.data.data;
+	}
+    }
+    return 0;
+}
+
+int getc_mem (void *fh)
+{
+    const char **p = (const char **) fh;
+    if (**p)
+	return *(*p)++;
+    return 0;
+}
+
+data1_node *data1_read_node (data1_handle dh, const char **buf, NMEM m)
+{
+    WRBUF wrbuf = wrbuf_alloc();
+    data1_node *node;
+
+    node = data1_read_nodex(dh, m, getc_mem, (void *) (buf), wrbuf);
+    wrbuf_free (wrbuf, 1);
+    return node;
+}
+
+/*
+ * Read a record in the native syntax.
+ */
+data1_node *data1_read_record(data1_handle dh,
+			      int (*rf)(void *, char *, size_t), void *fh,
+                              NMEM m)
+{
+    int *size;
+    char **buf = data1_get_read_buf (dh, &size);
+    const char *bp;
+    int rd = 0, res;
+    
+    if (!*buf)
+	*buf = (char *)xmalloc(*size = 4096);
+    
+    for (;;)
+    {
+	if (rd + 2048 >= *size && !(*buf =(char *)xrealloc(*buf, *size *= 2)))
+	    abort();
+	if ((res = (*rf)(fh, *buf + rd, 2048)) <= 0)
+	{
+	    if (!res)
+	    {
+		bp = *buf;
+		(*buf)[rd] = '\0';
+		return data1_read_node(dh, &bp, m);
+	    }
+	    else
+		return 0;
+	}
+	rd += res;
+    }
+}
+
+data1_node *data1_read_sgml (data1_handle dh, NMEM m, const char *buf)
+{
+    const char *bp = buf;
+    return data1_read_node (dh, &bp, m);
+}
+
Index: /main/tags/2.25/gsdl/packages/yaz/retrieval/d1_soif.c
===================================================================
--- /main/tags/2.25/gsdl/packages/yaz/retrieval/d1_soif.c	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/yaz/retrieval/d1_soif.c	(revision 21064)
@@ -0,0 +1,92 @@
+/*
+ * Copyright (c) 1995-1999, Index Data.
+ * See the file LICENSE for details.
+ * Sebastian Hammer, Adam Dickmeiss
+ *
+ * $Log$
+ * Revision 1.1  2000/08/03 03:11:36  johnmcp
+ * Added the YAZ toolkit source to the packages directory (for z39.50 stuff)
+ *
+ * Revision 1.4  1999/11/30 13:47:12  adam
+ * Improved installation. Moved header files to include/yaz.
+ *
+ * Revision 1.3  1997/09/17 12:10:37  adam
+ * YAZ version 1.4.
+ *
+ * Revision 1.2  1997/04/30 08:52:11  quinn
+ * Null
+ *
+ * Revision 1.1  1996/10/08  10:43:20  quinn
+ * Added SOIF syntax.
+ *
+ *
+ */
+
+#include <yaz/wrbuf.h>
+#include <yaz/data1.h>
+
+/*
+ * This module generates SOIF (Simple Object Interchange Format) records
+ * from d1-nodes. nested elements are flattened out, depth first, by
+ * concatenating the tag names at each level.
+ */
+
+static int nodetoelement(data1_node *n, int select, char *prefix, WRBUF b)
+{
+    data1_node *c;
+    char tmp[1024];
+
+    for (c = n->child; c; c = c->next)
+    {
+	char *tag;
+
+	if (c->which == DATA1N_tag)
+	{
+	    if (select && !c->u.tag.node_selected)
+		continue;
+	    if (c->u.tag.element && c->u.tag.element->tag)
+		tag = c->u.tag.element->tag->names->name; /* first name */
+	    else
+	    tag = c->u.tag.tag; /* local string tag */
+
+	    if (*prefix)
+		sprintf(tmp, "%s-%s", prefix, tag);
+	    else
+		strcpy(tmp, tag);
+
+	    if (nodetoelement(c, select, tmp, b) < 0)
+		return 0;
+	}
+	else if (c->which == DATA1N_data)
+	{
+	    char *p = c->u.data.data;
+	    int l = c->u.data.len;
+
+	    wrbuf_write(b, prefix, strlen(prefix));
+
+	    sprintf(tmp, "{%d}:\t", l);
+	    wrbuf_write(b, tmp, strlen(tmp));
+	    wrbuf_write(b, p, l);
+	    wrbuf_putc(b, '\n');
+	}
+    }
+    return 0;
+}
+
+char *data1_nodetosoif (data1_handle dh, data1_node *n, int select, int *len)
+{
+    WRBUF b = data1_get_wrbuf (dh);
+    char buf[128];
+
+    wrbuf_rewind(b);
+    
+    if (n->which != DATA1N_root)
+	return 0;
+    sprintf(buf, "@%s{\n", n->u.root.type);
+    wrbuf_write(b, buf, strlen(buf));
+    if (nodetoelement(n, select, "", b))
+	return 0;
+    wrbuf_write(b, "}\n", 2);
+    *len = wrbuf_len(b);
+    return wrbuf_buf(b);
+}
Index: /main/tags/2.25/gsdl/packages/yaz/retrieval/d1_sumout.c
===================================================================
--- /main/tags/2.25/gsdl/packages/yaz/retrieval/d1_sumout.c	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/yaz/retrieval/d1_sumout.c	(revision 21064)
@@ -0,0 +1,121 @@
+/*
+ * Copyright (c) 1995-1999, Index Data.
+ * See the file LICENSE for details.
+ * Sebastian Hammer, Adam Dickmeiss
+ *
+ * $Log$
+ * Revision 1.1  2000/08/03 03:11:36  johnmcp
+ * Added the YAZ toolkit source to the packages directory (for z39.50 stuff)
+ *
+ * Revision 1.5  1999/11/30 13:47:12  adam
+ * Improved installation. Moved header files to include/yaz.
+ *
+ * Revision 1.4  1999/08/27 09:40:32  adam
+ * Renamed logf function to yaz_log. Removed VC++ project files.
+ *
+ * Revision 1.3  1998/02/11 11:53:35  adam
+ * Changed code so that it compiles as C++.
+ *
+ * Revision 1.2  1997/09/17 12:10:38  adam
+ * YAZ version 1.4.
+ *
+ * Revision 1.1  1996/06/10 08:56:03  quinn
+ * Work on Summary.
+ *
+ *
+ */
+
+#include <assert.h>
+#include <string.h>
+#include <stdlib.h>
+
+#include <yaz/log.h>
+#include <yaz/proto.h>
+#include <yaz/data1.h>
+
+static int *f_integer(data1_node *c, ODR o)
+{
+    int *r;
+    char intbuf[64];
+
+    if (!c->child || c->child->which != DATA1N_data ||
+	c->child->u.data.len > 63)
+	return 0;
+    r = (int *)odr_malloc(o, sizeof(*r));
+    sprintf(intbuf, "%.*s", 63, c->child->u.data.data);
+    *r = atoi(intbuf);
+    return r;
+}
+
+static char *f_string(data1_node *c, ODR o)
+{
+    char *r;
+
+    if (!c->child || c->child->which != DATA1N_data)
+	return 0;
+    r = (char *)odr_malloc(o, c->child->u.data.len+1);
+    memcpy(r, c->child->u.data.data, c->child->u.data.len);
+    r[c->child->u.data.len] = '\0';
+    return r;
+}
+
+Z_BriefBib *data1_nodetosummary (data1_handle dh, data1_node *n,
+				 int select, ODR o)
+{
+    Z_BriefBib *res = (Z_BriefBib *)odr_malloc(o, sizeof(*res));
+    data1_node *c;
+
+    assert(n->which == DATA1N_root);
+    if (strcmp(n->u.root.type, "summary"))
+    {
+	yaz_log(LOG_WARN, "Attempt to convert a non-summary record");
+	return 0;
+    }
+
+    res->title = "[UNKNOWN]";
+    res->author = 0;
+    res->callNumber = 0;
+    res->recordType = 0;
+    res->bibliographicLevel = 0;
+    res->num_format = 0;
+    res->format = 0;
+    res->publicationPlace = 0;
+    res->publicationDate = 0;
+    res->targetSystemKey = 0;
+    res->satisfyingElement = 0;
+    res->rank = 0;
+    res->documentId = 0;
+    res->abstract = 0;
+    res->otherInfo = 0;
+
+    for (c = n->child; c; c = c->next)
+    {
+	if (c->which != DATA1N_tag || !c->u.tag.element)
+	{
+	    yaz_log(LOG_WARN, "Malformed element in Summary record");
+	    return 0;
+	}
+	if (select && !c->u.tag.node_selected)
+	    continue;
+	switch (c->u.tag.element->tag->value.numeric)
+	{
+	    case 0: res->title = f_string(c, o); break;
+	    case 1: res->author = f_string(c, o); break;
+	    case 2: res->callNumber = f_string(c, o); break;
+	    case 3: res->recordType = f_string(c, o); break;
+	    case 4: res->bibliographicLevel = f_string(c, o); break;
+	    case 5: abort();   /* TODO */
+	    case 10: res->publicationPlace = f_string(c, o); break;
+	    case 11: res->publicationDate = f_string(c, o); break;
+	    case 12: res->targetSystemKey = f_string(c, o); break;
+	    case 13: res->satisfyingElement = f_string(c, o); break;
+	    case 14: res->rank = f_integer(c, o); break;
+	    case 15: res->documentId = f_string(c, o); break;
+	    case 16: res->abstract = f_string(c, o); break;
+	    case 17: abort(); /* TODO */
+	    default:
+	        yaz_log(LOG_WARN, "Unknown element in Summary record.");
+	}
+    }
+    return res;
+}
Index: /main/tags/2.25/gsdl/packages/yaz/retrieval/d1_sutrs.c
===================================================================
--- /main/tags/2.25/gsdl/packages/yaz/retrieval/d1_sutrs.c	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/yaz/retrieval/d1_sutrs.c	(revision 21064)
@@ -0,0 +1,155 @@
+/*
+ * Copyright (c) 1995-1997, Index Data.
+ * See the file LICENSE for details.
+ * Sebastian Hammer, Adam Dickmeiss
+ *
+ * $Log$
+ * Revision 1.1  2000/08/03 03:11:37  johnmcp
+ * Added the YAZ toolkit source to the packages directory (for z39.50 stuff)
+ *
+ * Revision 1.6  1999/11/30 13:47:12  adam
+ * Improved installation. Moved header files to include/yaz.
+ *
+ * Revision 1.5  1999/10/21 12:06:29  adam
+ * Retrieval module no longer uses ctype.h - functions.
+ *
+ * Revision 1.4  1997/09/17 12:10:38  adam
+ * YAZ version 1.4.
+ *
+ * Revision 1.3  1995/12/15 16:57:11  quinn
+ * Added formatted-text.
+ *
+ * Revision 1.2  1995/11/01  13:54:49  quinn
+ * Minor adjustments
+ *
+ * Revision 1.1  1995/11/01  11:56:09  quinn
+ * Added Retrieval (data management) functions en masse.
+ *
+ *
+ */
+
+#include <yaz/data1.h>
+
+#define NTOBUF_INDENT   2
+#define NTOBUF_MARGIN 75
+
+static int wordlen(char *b)
+{
+    int l = 0;
+
+    while (*b && !d1_isspace(*b))
+	l++, b++;
+    return l;
+}
+
+static int nodetobuf(data1_node *n, int select, WRBUF b, int indent, int col)
+{
+    data1_node *c;
+    char line[1024];
+
+    for (c = n->child; c; c = c->next)
+    {
+	char *tag;
+
+	if (c->which == DATA1N_tag)
+	{
+	    if (select && !c->u.tag.node_selected)
+		continue;
+	    if (c->u.tag.element && c->u.tag.element->tag)
+		tag = c->u.tag.element->tag->names->name; /* first name */
+	    else
+		tag = c->u.tag.tag; /* local string tag */
+	    if (data1_matchstr(tag, "wellknown")) /* skip wellknown */
+	    {
+		if (col)
+		    wrbuf_putc(b, '\n');
+		sprintf(line, "%*s%s:", indent * NTOBUF_INDENT, "", tag);
+		wrbuf_write(b, line, strlen(line));
+		col = strlen(line);
+	    }
+	    if (nodetobuf(c, select, b, indent+1, col) < 0)
+		return 0;
+	}
+	else if (c->which == DATA1N_data)
+	{
+	    char *p = c->u.data.data;
+	    int l = c->u.data.len;
+	    int first = 0;
+
+	    if (c->u.data.what == DATA1I_text && c->u.data.formatted_text)
+	    {
+		wrbuf_putc(b, '\n');
+		wrbuf_write(b, c->u.data.data, c->u.data.len);
+		sprintf(line, "%*s", indent * NTOBUF_INDENT, "");
+		wrbuf_write(b, line, strlen(line));
+		col = indent * NTOBUF_INDENT;
+	    }
+	    else if (c->u.data.what == DATA1I_text)
+	    {
+		while (l)
+		{
+		    int wlen;
+
+		    while (l && d1_isspace(*p))
+			p++, l--;
+		    if (!l)
+			break;
+		    /* break if we'll cross margin and word is not too long */
+		    if (col + (wlen = wordlen(p)) > NTOBUF_MARGIN && wlen <
+			NTOBUF_MARGIN - indent * NTOBUF_INDENT)
+		    {
+			sprintf(line, "\n%*s", indent * NTOBUF_INDENT, "");
+			wrbuf_write(b, line, strlen(line));
+			col = indent * NTOBUF_INDENT;
+			first = 1;
+		    }
+		    if (!first)
+		    {
+			wrbuf_putc(b, ' ');
+			col++;
+		    }
+		    while (l && !d1_isspace(*p))
+		    {
+			if (col > NTOBUF_MARGIN)
+			{
+			    wrbuf_putc(b, '=');
+			    wrbuf_putc(b, '\n');
+			    sprintf(line, "%*s", indent * NTOBUF_INDENT, "");
+			    wrbuf_write(b, line, strlen(line));
+			    col = indent * NTOBUF_INDENT;
+			}
+			wrbuf_putc(b, *p);
+			p++;
+			l--;
+			col++;
+		    }
+		    first = 0;
+		}
+	    }
+	    else if (c->u.data.what == DATA1I_num)
+	    {
+		wrbuf_putc(b, ' ');
+		wrbuf_write(b, c->u.data.data, c->u.data.len);
+	    }
+	}
+    }
+    return 0;
+}
+
+/*
+ * Return area containing SUTRS-formatted data. Ownership of this data
+ * remains in this module, and the buffer is reused on next call. This may
+ * need changing.
+ */
+
+char *data1_nodetobuf (data1_handle dh, data1_node *n, int select, int *len)
+{
+    WRBUF b = data1_get_wrbuf (dh);
+
+    wrbuf_rewind(b);
+    if (nodetobuf(n, select, b, 0, 0))
+	return 0;
+    wrbuf_putc(b, '\n');
+    *len = wrbuf_len(b);
+    return wrbuf_buf(b);
+}
Index: /main/tags/2.25/gsdl/packages/yaz/retrieval/d1_tagset.c
===================================================================
--- /main/tags/2.25/gsdl/packages/yaz/retrieval/d1_tagset.c	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/yaz/retrieval/d1_tagset.c	(revision 21064)
@@ -0,0 +1,303 @@
+/*
+ * Copyright (c) 1995-1999, Index Data.
+ * See the file LICENSE for details.
+ * Sebastian Hammer, Adam Dickmeiss
+ *
+ * $Log$
+ * Revision 1.1  2000/08/03 03:11:37  johnmcp
+ * Added the YAZ toolkit source to the packages directory (for z39.50 stuff)
+ *
+ * Revision 1.14  1999/11/30 13:47:12  adam
+ * Improved installation. Moved header files to include/yaz.
+ *
+ * Revision 1.13  1999/10/21 12:06:29  adam
+ * Retrieval module no longer uses ctype.h - functions.
+ *
+ * Revision 1.12  1999/08/27 09:40:32  adam
+ * Renamed logf function to yaz_log. Removed VC++ project files.
+ *
+ * Revision 1.11  1998/10/19 14:16:36  adam
+ * Fixed data1_gettagbyname. Bug introduced by previous revision.
+ *
+ * Revision 1.10  1998/10/15 08:29:17  adam
+ * Tag set type may be specified in reference to it using "tagset"
+ * directive in .abs-files and "include" directive in .tag-files.
+ *
+ * Revision 1.9  1998/10/13 16:09:53  adam
+ * Added support for arbitrary OID's for tagsets, schemas and attribute sets.
+ * Added support for multiple attribute set references and tagset references
+ * from an abstract syntax file.
+ * Fixed many bad logs-calls in routines that read the various
+ * specifications regarding data1 (*.abs,*.att,...) and made the messages
+ * consistent whenever possible.
+ * Added extra 'lineno' argument to function readconf_line.
+ *
+ * Revision 1.8  1998/05/18 13:07:07  adam
+ * Changed the way attribute sets are handled by the retriaval module.
+ * Extended Explain conversion / schema.
+ * Modified server and client to work with ASN.1 compiled protocol handlers.
+ *
+ * Revision 1.7  1998/02/11 11:53:35  adam
+ * Changed code so that it compiles as C++.
+ *
+ * Revision 1.6  1997/09/17 12:10:38  adam
+ * YAZ version 1.4.
+ *
+ * Revision 1.5  1997/09/05 09:50:57  adam
+ * Removed global data1_tabpath - uses data1_get_tabpath() instead.
+ *
+ * Revision 1.4  1995/11/13 09:27:38  quinn
+ * Fiddling with the variant stuff.
+ *
+ * Revision 1.3  1995/11/01  16:34:58  quinn
+ * Making data1 look for tables in data1_tabpath
+ *
+ * Revision 1.2  1995/11/01  13:54:49  quinn
+ * Minor adjustments
+ *
+ * Revision 1.1  1995/11/01  11:56:09  quinn
+ * Added Retrieval (data management) functions en masse.
+ *
+ *
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <yaz/log.h>
+#include <yaz/data1.h>
+
+/*
+ * We'll probably want to add some sort of hashed index to these lookup-
+ * functions eventually.
+ */
+
+data1_datatype data1_maptype (data1_handle dh, char *t)
+{
+    static struct
+    {
+	char *tname;
+	data1_datatype type;
+    } types[] =
+    {
+	{"structured", DATA1K_structured},
+	{"string", DATA1K_string},
+	{"numeric", DATA1K_numeric},
+	{"oid", DATA1K_oid},
+	{"bool", DATA1K_bool},
+	{"generalizedtime", DATA1K_generalizedtime},
+	{"intunit", DATA1K_intunit},
+	{"int", DATA1K_int},
+	{"octetstring", DATA1K_octetstring},
+	{"null", DATA1K_null},
+	{NULL, (data1_datatype) -1}
+    };
+    int i;
+
+    for (i = 0; types[i].tname; i++)
+	if (!data1_matchstr(types[i].tname, t))
+	    return types[i].type;
+    return DATA1K_unknown;
+}
+
+data1_tag *data1_gettagbynum (data1_handle dh, data1_tagset *s,
+			      int type, int value)
+{
+    data1_tag *r;
+    
+    for (; s; s = s->next)
+    {
+	/* scan local set */
+	if (type == s->type)
+	    for (r = s->tags; r; r = r->next)
+		if (r->which == DATA1T_numeric && r->value.numeric == value)
+		    return r;
+	/* scan included sets */
+	if (s->children &&
+	    (r = data1_gettagbynum (dh, s->children, type, value)))
+	    return r;
+    }
+    return 0;
+}
+
+data1_tag *data1_gettagbyname (data1_handle dh, data1_tagset *s,
+			       const char *name)
+{
+    data1_tag *r;
+
+    for (; s; s = s->next)
+    {
+	/* scan local set */
+	for (r = s->tags; r; r = r->next)
+	{
+	    data1_name *np;
+
+	    for (np = r->names; np; np = np->next)
+		if (!data1_matchstr(np->name, name))
+		    return r;
+	}
+	/* scan included sets */
+	if (s->children && (r = data1_gettagbyname (dh, s->children, name)))
+	    return r;
+    }
+    return 0;
+}
+
+data1_tagset *data1_empty_tagset (data1_handle dh)
+{
+    data1_tagset *res =
+	(data1_tagset *) nmem_malloc(data1_nmem_get (dh), sizeof(*res));
+    res->name = 0;
+    res->reference = VAL_NONE;
+    res->tags = 0;
+    res->type = 0;
+    res->children = 0;
+    res->next = 0;
+    return res;
+}
+
+data1_tagset *data1_read_tagset (data1_handle dh, const char *file, int type)
+{
+    NMEM mem = data1_nmem_get (dh);
+    data1_tagset *res = 0;
+    data1_tagset **childp;
+    data1_tag **tagp;
+    FILE *f;
+    int lineno = 0;
+    int argc;
+    char *argv[50], line[512];
+
+    if (!(f = yaz_path_fopen(data1_get_tabpath(dh), file, "r")))
+    {
+	yaz_log(LOG_WARN|LOG_ERRNO, "%s", file);
+	return 0;
+    }
+    res = data1_empty_tagset (dh);
+    res->type = type;
+    childp = &res->children;
+    tagp = &res->tags;
+
+    while ((argc = readconf_line(f, &lineno, line, 512, argv, 50)))
+    {
+	char *cmd = *argv;
+	if (!strcmp(cmd, "tag"))
+	{
+	    int value;
+	    char *names, *type, *nm;
+	    data1_tag *rr;
+	    data1_name **npp;
+
+	    if (argc != 4)
+	    {
+		yaz_log(LOG_WARN, "%s:%d: Bad # args to tag", file, lineno);
+		continue;
+	    }
+	    value = atoi(argv[1]);
+	    names = argv[2];
+	    type = argv[3];
+
+	    rr = *tagp = (data1_tag *)nmem_malloc(mem, sizeof(*rr));
+	    rr->tagset = res;
+	    rr->next = 0;
+	    rr->which = DATA1T_numeric;
+	    rr->value.numeric = value;
+	    /*
+	     * how to deal with local numeric tags?
+	     */
+
+	    if (!(rr->kind = data1_maptype(dh, type)))
+	    {
+		yaz_log(LOG_WARN, "%s:%d: Unknown datatype %s",
+		     file, lineno, type);
+		fclose(f);
+		return 0;
+	    }
+	    
+	    /* read namelist */
+	    nm = names;
+	    npp = &rr->names;
+	    do
+	    {
+		char *e;
+
+		*npp = (data1_name *)nmem_malloc(mem, sizeof(**npp));
+		if ((e = strchr(nm, '/')))
+		    *(e++) = '\0';
+		(*npp)->name = nmem_strdup(mem, nm);
+		(*npp)->next = 0;
+		npp = &(*npp)->next;
+		nm = e;
+	    }
+	    while (nm);
+	    tagp = &rr->next;
+	}
+	else if (!strcmp(cmd, "name"))
+	{
+	    if (argc != 2)
+	    {
+		yaz_log(LOG_WARN, "%s:%d: Bad # args to name", file, lineno);
+		continue;
+	    }
+	    res->name = nmem_strdup(mem, argv[1]);
+	}
+	else if (!strcmp(cmd, "reference"))
+	{
+	    char *name;
+	    
+	    if (argc != 2)
+	    {
+		yaz_log(LOG_WARN, "%s:%d: Bad # args to reference",
+			file, lineno);
+		continue;
+	    }
+	    name = argv[1];
+	    if ((res->reference = oid_getvalbyname(name)) == VAL_NONE)
+	    {
+		yaz_log(LOG_WARN, "%s:%d: Unknown tagset ref '%s'",
+			file, lineno, name);
+		continue;
+	    }
+	}
+	else if (!strcmp(cmd, "type"))
+	{
+	    if (argc != 2)
+	    {
+		yaz_log (LOG_WARN, "%s:%d: Bad # args to type", file, lineno);
+		continue;
+	    }
+	    if (!res->type)
+		res->type = atoi(argv[1]);
+	}
+	else if (!strcmp(cmd, "include"))
+	{
+	    char *name;
+	    int type = 0;
+
+	    if (argc < 2)
+	    {
+		yaz_log(LOG_WARN, "%s:%d: Bad # args to include",
+			file, lineno);
+		continue;
+	    }
+	    name = argv[1];
+	    if (argc == 3)
+		type = atoi(argv[2]);
+	    *childp = data1_read_tagset (dh, name, type);
+	    if (!(*childp))
+	    {
+		yaz_log(LOG_WARN, "%s:%d: Inclusion failed for tagset %s",
+			file, lineno, name);
+		continue;
+	    }
+	    childp = &(*childp)->next;
+	}
+	else
+	{
+	    yaz_log(LOG_WARN, "%s:%d: Unknown directive '%s'",
+		    file, lineno, cmd);
+	}
+    }
+    fclose(f);
+    return res;
+}
Index: /main/tags/2.25/gsdl/packages/yaz/retrieval/d1_varset.c
===================================================================
--- /main/tags/2.25/gsdl/packages/yaz/retrieval/d1_varset.c	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/yaz/retrieval/d1_varset.c	(revision 21064)
@@ -0,0 +1,178 @@
+/*
+ * Copyright (c) 1995-1999, Index Data.
+ * See the file LICENSE for details.
+ * Sebastian Hammer, Adam Dickmeiss
+ *
+ * $Log$
+ * Revision 1.1  2000/08/03 03:11:38  johnmcp
+ * Added the YAZ toolkit source to the packages directory (for z39.50 stuff)
+ *
+ * Revision 1.10  1999/11/30 13:47:12  adam
+ * Improved installation. Moved header files to include/yaz.
+ *
+ * Revision 1.9  1999/08/27 09:40:32  adam
+ * Renamed logf function to yaz_log. Removed VC++ project files.
+ *
+ * Revision 1.8  1998/10/13 16:09:54  adam
+ * Added support for arbitrary OID's for tagsets, schemas and attribute sets.
+ * Added support for multiple attribute set references and tagset references
+ * from an abstract syntax file.
+ * Fixed many bad logs-calls in routines that read the various
+ * specifications regarding data1 (*.abs,*.att,...) and made the messages
+ * consistent whenever possible.
+ * Added extra 'lineno' argument to function readconf_line.
+ *
+ * Revision 1.7  1998/02/11 11:53:35  adam
+ * Changed code so that it compiles as C++.
+ *
+ * Revision 1.6  1997/09/17 12:10:39  adam
+ * YAZ version 1.4.
+ *
+ * Revision 1.5  1997/09/05 09:50:58  adam
+ * Removed global data1_tabpath - uses data1_get_tabpath() instead.
+ *
+ * Revision 1.4  1997/05/14 06:54:04  adam
+ * C++ support.
+ *
+ * Revision 1.3  1995/11/01 16:34:58  quinn
+ * Making data1 look for tables in data1_tabpath
+ *
+ * Revision 1.2  1995/11/01  13:54:50  quinn
+ * Minor adjustments
+ *
+ * Revision 1.1  1995/11/01  11:56:09  quinn
+ * Added Retrieval (data management) functions en masse.
+ *
+ *
+ */
+
+#include <string.h>
+#include <stdlib.h>
+
+#include <yaz/oid.h>
+#include <yaz/log.h>
+#include <yaz/data1.h>
+
+data1_vartype *data1_getvartypebyct (data1_handle dh, data1_varset *set,
+				     char *zclass, char *type)
+{
+    data1_varclass *c;
+    data1_vartype *t;
+
+    for (c = set->classes; c; c = c->next)
+	if (!data1_matchstr(c->name, zclass))
+	{
+	    for (t = c->types; t; t = t->next)
+		if (!data1_matchstr(t->name, type))
+		    return t;
+	    yaz_log(LOG_WARN, "Unknown variant type %s in class %s",
+		    type, zclass);
+	    return 0;
+	}
+    yaz_log(LOG_WARN, "Unknown variant class %s", zclass);
+    return 0;
+}
+
+data1_varset *data1_read_varset (data1_handle dh, const char *file)
+{
+    NMEM mem = data1_nmem_get (dh);
+    data1_varset *res = (data1_varset *)nmem_malloc(mem, sizeof(*res));
+    data1_varclass **classp = &res->classes, *zclass = 0;
+    data1_vartype **typep = 0;
+    FILE *f;
+    int lineno = 0;
+    int argc;
+    char *argv[50],line[512];
+
+    res->name = 0;
+    res->reference = VAL_NONE;
+    res->classes = 0;
+
+    if (!(f = yaz_path_fopen(data1_get_tabpath(dh), file, "r")))
+    {
+	yaz_log(LOG_WARN|LOG_ERRNO, "%s", file);
+	return 0;
+    }
+    while ((argc = readconf_line(f, &lineno, line, 512, argv, 50)))
+	if (!strcmp(argv[0], "class"))
+	{
+	    data1_varclass *r;
+	    
+	    if (argc != 3)
+	    {
+		yaz_log(LOG_WARN, "%s:%d: Bad # or args to class",
+			file, lineno);
+		continue;
+	    }
+	    *classp = r = zclass = (data1_varclass *)
+		nmem_malloc(mem, sizeof(*r));
+	    r->set = res;
+	    r->zclass = atoi(argv[1]);
+	    r->name = nmem_strdup(mem, argv[2]);
+	    r->types = 0;
+	    typep = &r->types;
+	    r->next = 0;
+	    classp = &r->next;
+	}
+	else if (!strcmp(argv[0], "type"))
+	{
+	    data1_vartype *r;
+
+	    if (!typep)
+	    {
+		yaz_log(LOG_WARN, "%s:%d: Directive class must precede type",
+			file, lineno);
+		continue;
+	    }
+	    if (argc != 4)
+	    {
+		yaz_log(LOG_WARN, "%s:%d: Bad # or args to type",
+			file, lineno);
+		continue;
+	    }
+	    *typep = r = (data1_vartype *)nmem_malloc(mem, sizeof(*r));
+	    r->name = nmem_strdup(mem, argv[2]);
+	    r->zclass = zclass;
+	    r->type = atoi(argv[1]);
+	    if (!(r->datatype = data1_maptype (dh, argv[3])))
+	    {
+		yaz_log(LOG_WARN, "%s:%d: Unknown datatype '%s'",
+			file, lineno, argv[3]);
+		fclose(f);
+		return 0;
+	    }
+	    r->next = 0;
+	    typep = &r->next;
+	}
+	else if (!strcmp(argv[0], "name"))
+	{
+	    if (argc != 2)
+	    {
+		yaz_log(LOG_WARN, "%s:%d: Bad # args for name",
+			file, lineno);
+		continue;
+	    }
+	    res->name = nmem_strdup(mem, argv[1]);
+	}
+	else if (!strcmp(argv[0], "reference"))
+	{
+	    if (argc != 2)
+	    {
+		yaz_log(LOG_WARN, "%s:%d: Bad # args for reference",
+			file, lineno);
+		continue;
+	    }
+	    if ((res->reference = oid_getvalbyname(argv[1])) == VAL_NONE)
+	    {
+		yaz_log(LOG_WARN, "%s:%d: Unknown reference '%s'",
+			file, lineno, argv[1]);
+		continue;
+	    }
+	}
+	else 
+	    yaz_log(LOG_WARN, "%s:%d: Unknown directive '%s'",
+		    file, lineno, argv[0]);
+    
+    fclose(f);
+    return res;
+}
Index: /main/tags/2.25/gsdl/packages/yaz/retrieval/d1_write.c
===================================================================
--- /main/tags/2.25/gsdl/packages/yaz/retrieval/d1_write.c	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/yaz/retrieval/d1_write.c	(revision 21064)
@@ -0,0 +1,158 @@
+/*
+ * Copyright (c) 1995-1999, Index Data.
+ * See the file LICENSE for details.
+ * Sebastian Hammer, Adam Dickmeiss
+ *
+ * $Log$
+ * Revision 1.1  2000/08/03 03:11:38  johnmcp
+ * Added the YAZ toolkit source to the packages directory (for z39.50 stuff)
+ *
+ * Revision 1.8  1999/11/30 13:47:12  adam
+ * Improved installation. Moved header files to include/yaz.
+ *
+ * Revision 1.7  1999/10/21 12:06:29  adam
+ * Retrieval module no longer uses ctype.h - functions.
+ *
+ * Revision 1.6  1999/07/06 12:16:00  adam
+ * Improved layout generated record in SGML/XML format.
+ *
+ * Revision 1.5  1998/06/05 08:57:43  adam
+ * Fixed problem with function wordlen.
+ *
+ * Revision 1.4  1998/05/18 13:07:08  adam
+ * Changed the way attribute sets are handled by the retriaval module.
+ * Extended Explain conversion / schema.
+ * Modified server and client to work with ASN.1 compiled protocol handlers.
+ *
+ * Revision 1.3  1997/09/17 12:10:39  adam
+ * YAZ version 1.4.
+ *
+ * Revision 1.2  1995/12/13 17:14:27  quinn
+ * *** empty log message ***
+ *
+ * Revision 1.1  1995/12/13  15:38:43  quinn
+ * Added SGML-output filter.
+ *
+ *
+ */
+
+#include <string.h>
+
+#include <yaz/data1.h>
+#include <yaz/wrbuf.h>
+
+#define IDSGML_MARGIN 75
+
+static int wordlen(char *b, int max)
+{
+    int l = 0;
+
+    while (l < max && !d1_isspace(*b))
+	l++, b++;
+    return l;
+}
+
+static int nodetoidsgml(data1_node *n, int select, WRBUF b, int col)
+{
+    data1_node *c;
+    char line[1024];
+
+    for (c = n->child; c; c = c->next)
+    {
+	char *tag;
+
+	if (c->which == DATA1N_tag)
+	{
+	    if (select && c->u.tag.node_selected)
+		continue;
+	    if (c->u.tag.element && c->u.tag.element->tag)
+		tag = c->u.tag.element->tag->names->name; /* first name */
+	    else
+		tag = c->u.tag.tag; /* local string tag */
+	    if (!data1_matchstr(tag, "wellknown")) /* skip wellknown */
+	    {
+		if (nodetoidsgml(c, select, b, col) < 0)
+		    return -1;
+	    }
+	    else
+	    {
+		sprintf(line, "%*s<%s>\n", col, "", tag);
+		wrbuf_write(b, line, strlen(line));
+		if (nodetoidsgml(c, select, b, (col > 40) ? 40 : col+2) < 0)
+		    return -1;
+		sprintf (line, "%*s</%s>\n", col, "", tag);
+		wrbuf_write(b, line, strlen(line));
+	    }
+	}
+	else if (c->which == DATA1N_data)
+	{
+	    char *p = c->u.data.data;
+	    int l = c->u.data.len;
+	    int first = 1;
+	    int lcol = col;
+
+	    sprintf(line, "%*s", col, "");
+	    wrbuf_write(b, line, strlen(line));
+	    switch (c->u.data.what)
+	    {
+	    case DATA1I_text:
+		while (l)
+		{
+		    int wlen;
+		    
+		    while (l && d1_isspace(*p))
+			p++, l--;
+		    if (!l)
+			break;
+		    /* break if we'll cross margin and word is not too long */
+		    if (lcol + (wlen = wordlen(p, l)) > IDSGML_MARGIN && wlen <
+			IDSGML_MARGIN)
+		    {
+			sprintf(line, "\n%*s", col, "");
+			lcol = col;
+			wrbuf_write(b, line, strlen(line));
+			first = 1;
+		    }
+		    if (!first)
+		    {
+			wrbuf_putc(b, ' ');
+			lcol++;
+		    }
+		    while (l && !d1_isspace(*p))
+		    {
+			wrbuf_putc(b, *p);
+			p++;
+			l--;
+			lcol++;
+		    }
+		    first = 0;
+		}
+		wrbuf_write(b, "\n", 1);
+		break;
+	    case DATA1I_num:
+		wrbuf_write(b, c->u.data.data, c->u.data.len);
+		break;
+	    case DATA1I_oid:
+		wrbuf_write(b, c->u.data.data, c->u.data.len);
+	    }
+	}
+    }
+    return 0;
+}
+
+char *data1_nodetoidsgml (data1_handle dh, data1_node *n, int select, int *len)
+{
+    WRBUF b = data1_get_wrbuf (dh);
+    char line[1024];
+    
+    wrbuf_rewind(b);
+    
+    sprintf(line, "<%s>\n", n->u.root.type);
+    wrbuf_write(b, line, strlen(line));
+    if (nodetoidsgml(n, select, b, 0))
+	return 0;
+    sprintf(line, "</%s>\n", n->u.root.type);
+    wrbuf_write(b, line, strlen(line));
+    *len = wrbuf_len(b);
+    return wrbuf_buf(b);
+}
Index: /main/tags/2.25/gsdl/packages/yaz/server/Makefile.am
===================================================================
--- /main/tags/2.25/gsdl/packages/yaz/server/Makefile.am	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/yaz/server/Makefile.am	(revision 21064)
@@ -0,0 +1,12 @@
+## $Id$
+
+noinst_LIBRARIES=libserver.a
+
+libserver_a_SOURCES = eventl.c seshigh.c statserv.c requestq.c tcpdchk.c \
+ eventl.h service.h session.h
+
+EXTRA_DIST=service.c
+
+INCLUDES=-I../include
+
+LDADD = ../lib/libyaz.a
Index: /main/tags/2.25/gsdl/packages/yaz/server/Makefile.in
===================================================================
--- /main/tags/2.25/gsdl/packages/yaz/server/Makefile.in	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/yaz/server/Makefile.in	(revision 21064)
@@ -0,0 +1,272 @@
+# Makefile.in generated automatically by automake 1.4 from Makefile.am
+
+# Copyright (C) 1994, 1995-8, 1999 Free Software Foundation, Inc.
+# This Makefile.in is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
+# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE.
+
+
+SHELL = @SHELL@
+
+srcdir = @srcdir@
+top_srcdir = @top_srcdir@
+VPATH = @srcdir@
+prefix = @prefix@
+exec_prefix = @exec_prefix@
+
+bindir = @bindir@
+sbindir = @sbindir@
+libexecdir = @libexecdir@
+datadir = @datadir@
+sysconfdir = @sysconfdir@
+sharedstatedir = @sharedstatedir@
+localstatedir = @localstatedir@
+libdir = @libdir@
+infodir = @infodir@
+mandir = @mandir@
+includedir = @includedir@
+oldincludedir = /usr/include
+
+DESTDIR =
+
+pkgdatadir = $(datadir)/@PACKAGE@
+pkglibdir = $(libdir)/@PACKAGE@
+pkgincludedir = $(includedir)/@PACKAGE@
+
+top_builddir = ..
+
+ACLOCAL = @ACLOCAL@
+AUTOCONF = @AUTOCONF@
+AUTOMAKE = @AUTOMAKE@
+AUTOHEADER = @AUTOHEADER@
+
+INSTALL = @INSTALL@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@ $(AM_INSTALL_PROGRAM_FLAGS)
+INSTALL_DATA = @INSTALL_DATA@
+INSTALL_SCRIPT = @INSTALL_SCRIPT@
+transform = @program_transform_name@
+
+NORMAL_INSTALL = :
+PRE_INSTALL = :
+POST_INSTALL = :
+NORMAL_UNINSTALL = :
+PRE_UNINSTALL = :
+POST_UNINSTALL = :
+ASNMODULE = @ASNMODULE@
+CC = @CC@
+CPP = @CPP@
+ILLLIB = @ILLLIB@
+ILLMODULE = @ILLMODULE@
+MAKEINFO = @MAKEINFO@
+PACKAGE = @PACKAGE@
+RANLIB = @RANLIB@
+SUBDIRS_VAR = @SUBDIRS_VAR@
+VERSION = @VERSION@
+have_sgml2html = @have_sgml2html@
+have_sgml2latex = @have_sgml2latex@
+have_sgml2txt = @have_sgml2txt@
+
+noinst_LIBRARIES = libserver.a
+
+libserver_a_SOURCES = eventl.c seshigh.c statserv.c requestq.c tcpdchk.c  eventl.h service.h session.h
+
+
+EXTRA_DIST = service.c
+
+INCLUDES = -I../include
+
+LDADD = ../lib/libyaz.a
+mkinstalldirs = $(SHELL) $(top_srcdir)/mkinstalldirs
+CONFIG_CLEAN_FILES = 
+LIBRARIES =  $(noinst_LIBRARIES)
+
+
+DEFS = @DEFS@ -I. -I$(srcdir) 
+CPPFLAGS = @CPPFLAGS@
+LDFLAGS = @LDFLAGS@
+LIBS = @LIBS@
+libserver_a_LIBADD = 
+libserver_a_OBJECTS =  eventl.o seshigh.o statserv.o requestq.o \
+tcpdchk.o
+AR = ar
+CFLAGS = @CFLAGS@
+COMPILE = $(CC) $(DEFS) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
+CCLD = $(CC)
+LINK = $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(LDFLAGS) -o $@
+DIST_COMMON =  Makefile.am Makefile.in
+
+
+DISTFILES = $(DIST_COMMON) $(SOURCES) $(HEADERS) $(TEXINFOS) $(EXTRA_DIST)
+
+TAR = gtar
+GZIP_ENV = --best
+SOURCES = $(libserver_a_SOURCES)
+OBJECTS = $(libserver_a_OBJECTS)
+
+all: all-redirect
+.SUFFIXES:
+.SUFFIXES: .S .c .o .s
+$(srcdir)/Makefile.in: Makefile.am $(top_srcdir)/configure.in $(ACLOCAL_M4) 
+	cd $(top_srcdir) && $(AUTOMAKE) --gnu --include-deps server/Makefile
+
+Makefile: $(srcdir)/Makefile.in  $(top_builddir)/config.status
+	cd $(top_builddir) \
+	  && CONFIG_FILES=$(subdir)/$@ CONFIG_HEADERS= $(SHELL) ./config.status
+
+
+mostlyclean-noinstLIBRARIES:
+
+clean-noinstLIBRARIES:
+	-test -z "$(noinst_LIBRARIES)" || rm -f $(noinst_LIBRARIES)
+
+distclean-noinstLIBRARIES:
+
+maintainer-clean-noinstLIBRARIES:
+
+.c.o:
+	$(COMPILE) -c $<
+
+.s.o:
+	$(COMPILE) -c $<
+
+.S.o:
+	$(COMPILE) -c $<
+
+mostlyclean-compile:
+	-rm -f *.o core *.core
+
+clean-compile:
+
+distclean-compile:
+	-rm -f *.tab.c
+
+maintainer-clean-compile:
+
+libserver.a: $(libserver_a_OBJECTS) $(libserver_a_DEPENDENCIES)
+	-rm -f libserver.a
+	$(AR) cru libserver.a $(libserver_a_OBJECTS) $(libserver_a_LIBADD)
+	$(RANLIB) libserver.a
+
+tags: TAGS
+
+ID: $(HEADERS) $(SOURCES) $(LISP)
+	list='$(SOURCES) $(HEADERS)'; \
+	unique=`for i in $$list; do echo $$i; done | \
+	  awk '    { files[$$0] = 1; } \
+	       END { for (i in files) print i; }'`; \
+	here=`pwd` && cd $(srcdir) \
+	  && mkid -f$$here/ID $$unique $(LISP)
+
+TAGS:  $(HEADERS) $(SOURCES)  $(TAGS_DEPENDENCIES) $(LISP)
+	tags=; \
+	here=`pwd`; \
+	list='$(SOURCES) $(HEADERS)'; \
+	unique=`for i in $$list; do echo $$i; done | \
+	  awk '    { files[$$0] = 1; } \
+	       END { for (i in files) print i; }'`; \
+	test -z "$(ETAGS_ARGS)$$unique$(LISP)$$tags" \
+	  || (cd $(srcdir) && etags $(ETAGS_ARGS) $$tags  $$unique $(LISP) -o $$here/TAGS)
+
+mostlyclean-tags:
+
+clean-tags:
+
+distclean-tags:
+	-rm -f TAGS ID
+
+maintainer-clean-tags:
+
+distdir = $(top_builddir)/$(PACKAGE)-$(VERSION)/$(subdir)
+
+subdir = server
+
+distdir: $(DISTFILES)
+	@for file in $(DISTFILES); do \
+	  d=$(srcdir); \
+	  if test -d $$d/$$file; then \
+	    cp -pr $$/$$file $(distdir)/$$file; \
+	  else \
+	    test -f $(distdir)/$$file \
+	    || ln $$d/$$file $(distdir)/$$file 2> /dev/null \
+	    || cp -p $$d/$$file $(distdir)/$$file || :; \
+	  fi; \
+	done
+
+info-am:
+info: info-am
+dvi-am:
+dvi: dvi-am
+check-am: all-am
+check: check-am
+installcheck-am:
+installcheck: installcheck-am
+install-exec-am:
+install-exec: install-exec-am
+
+install-data-am:
+install-data: install-data-am
+
+install-am: all-am
+	@$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
+install: install-am
+uninstall-am:
+uninstall: uninstall-am
+all-am: Makefile $(LIBRARIES)
+all-redirect: all-am
+install-strip:
+	$(MAKE) $(AM_MAKEFLAGS) AM_INSTALL_PROGRAM_FLAGS=-s install
+installdirs:
+
+
+mostlyclean-generic:
+
+clean-generic:
+
+distclean-generic:
+	-rm -f Makefile $(CONFIG_CLEAN_FILES)
+	-rm -f config.cache config.log stamp-h stamp-h[0-9]*
+
+maintainer-clean-generic:
+mostlyclean-am:  mostlyclean-noinstLIBRARIES mostlyclean-compile \
+		mostlyclean-tags mostlyclean-generic
+
+mostlyclean: mostlyclean-am
+
+clean-am:  clean-noinstLIBRARIES clean-compile clean-tags clean-generic \
+		mostlyclean-am
+
+clean: clean-am
+
+distclean-am:  distclean-noinstLIBRARIES distclean-compile \
+		distclean-tags distclean-generic clean-am
+
+distclean: distclean-am
+
+maintainer-clean-am:  maintainer-clean-noinstLIBRARIES \
+		maintainer-clean-compile maintainer-clean-tags \
+		maintainer-clean-generic distclean-am
+	@echo "This command is intended for maintainers to use;"
+	@echo "it deletes files that may require special tools to rebuild."
+
+maintainer-clean: maintainer-clean-am
+
+.PHONY: mostlyclean-noinstLIBRARIES distclean-noinstLIBRARIES \
+clean-noinstLIBRARIES maintainer-clean-noinstLIBRARIES \
+mostlyclean-compile distclean-compile clean-compile \
+maintainer-clean-compile tags mostlyclean-tags distclean-tags \
+clean-tags maintainer-clean-tags distdir info-am info dvi-am dvi check \
+check-am installcheck-am installcheck install-exec-am install-exec \
+install-data-am install-data install-am install uninstall-am uninstall \
+all-redirect all-am all installdirs mostlyclean-generic \
+distclean-generic clean-generic maintainer-clean-generic clean \
+mostlyclean distclean maintainer-clean
+
+
+# Tell versions [3.59,3.63) of GNU make to not export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:
Index: /main/tags/2.25/gsdl/packages/yaz/server/eventl.c
===================================================================
--- /main/tags/2.25/gsdl/packages/yaz/server/eventl.c	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/yaz/server/eventl.c	(revision 21064)
@@ -0,0 +1,246 @@
+/*
+ * Copyright (c) 1995-1999, Index Data
+ * See the file LICENSE for details.
+ * Sebastian Hammer, Adam Dickmeiss
+ *
+ * $Log$
+ * Revision 1.1  2000/08/03 03:11:40  johnmcp
+ * Added the YAZ toolkit source to the packages directory (for z39.50 stuff)
+ *
+ * Revision 1.29  1999/11/30 13:47:12  adam
+ * Improved installation. Moved header files to include/yaz.
+ *
+ * Revision 1.28  1999/08/27 09:40:32  adam
+ * Renamed logf function to yaz_log. Removed VC++ project files.
+ *
+ * Revision 1.27  1999/02/02 13:57:34  adam
+ * Uses preprocessor define WIN32 instead of WINDOWS to build code
+ * for Microsoft WIN32.
+ *
+ * Revision 1.26  1998/02/11 11:53:35  adam
+ * Changed code so that it compiles as C++.
+ *
+ * Revision 1.25  1998/01/29 13:30:23  adam
+ * Better event handle system for NT/Unix.
+ *
+ * Revision 1.24  1997/09/04 14:19:13  adam
+ * Added credits.
+ *
+ * Revision 1.23  1997/09/01 08:52:59  adam
+ * New windows NT/95 port using MSV5.0. The test server 'ztest' was
+ * moved a separate directory. MSV5.0 project server.dsp created.
+ * As an option, the server can now operate as an NT service.
+ *
+ * Revision 1.22  1996/07/06 19:58:35  quinn
+ * System headerfiles gathered in yconfig
+ *
+ * Revision 1.21  1996/02/21  12:55:51  quinn
+ * small
+ *
+ * Revision 1.20  1996/02/21  12:52:55  quinn
+ * Test
+ *
+ * Revision 1.19  1995/12/05  11:17:30  quinn
+ * Moved some paranthesises around. Sigh.
+ *
+ * Revision 1.18  1995/11/13  09:27:41  quinn
+ * Fiddling with the variant stuff.
+ *
+ * Revision 1.17  1995/11/07  12:37:44  quinn
+ * Added support for forcing TIMEOUT event.
+ *
+ * Revision 1.16  1995/11/01  13:54:56  quinn
+ * Minor adjustments
+ *
+ * Revision 1.15  1995/09/15  14:44:15  quinn
+ * *** empty log message ***
+ *
+ * Revision 1.14  1995/08/29  14:44:50  quinn
+ * Reset timeouts.
+ *
+ * Revision 1.13  1995/08/29  11:17:56  quinn
+ * Added code to receive close
+ *
+ * Revision 1.12  1995/08/29  10:41:18  quinn
+ * Small.
+ *
+ * Revision 1.11  1995/06/19  12:39:09  quinn
+ * Fixed bug in timeout code. Added BER dumper.
+ *
+ * Revision 1.10  1995/06/16  10:31:33  quinn
+ * Added session timeout.
+ *
+ * Revision 1.9  1995/06/05  10:53:31  quinn
+ * Added a better SCAN.
+ *
+ * Revision 1.8  1995/05/16  08:51:01  quinn
+ * License, documentation, and memory fixes
+ *
+ * Revision 1.7  1995/03/27  15:02:01  quinn
+ * Added some includes for better portability
+ *
+ * Revision 1.6  1995/03/27  08:34:21  quinn
+ * Added dynamic server functionality.
+ * Released bindings to session.c (is now redundant)
+ *
+ * Revision 1.5  1995/03/15  08:37:41  quinn
+ * Now we're pretty much set for nonblocking I/O.
+ *
+ * Revision 1.4  1995/03/14  16:59:48  quinn
+ * Bug-fixes
+ *
+ * Revision 1.3  1995/03/14  11:30:14  quinn
+ * Works better now.
+ *
+ * Revision 1.2  1995/03/14  10:27:59  quinn
+ * More work on demo server.
+ *
+ * Revision 1.1  1995/03/10  18:22:44  quinn
+ * The rudiments of an asynchronous server.
+ *
+ */
+
+#include <stdio.h>
+#include <assert.h>
+#ifdef WIN32
+#include <winsock.h>
+#else
+#include <unistd.h>
+#endif
+#include <stdlib.h>
+#include <errno.h>
+#include <string.h>
+
+#include <yaz/yconfig.h>
+#include <yaz/log.h>
+#include <yaz/comstack.h>
+#include <yaz/xmalloc.h>
+#include "eventl.h"
+#include "session.h"
+#include <yaz/statserv.h>
+
+IOCHAN iochan_create(int fd, IOC_CALLBACK cb, int flags)
+{
+    IOCHAN new_iochan;
+
+    if (!(new_iochan = (IOCHAN)xmalloc(sizeof(*new_iochan))))
+    	return 0;
+    new_iochan->destroyed = 0;
+    new_iochan->fd = fd;
+    new_iochan->flags = flags;
+    new_iochan->fun = cb;
+    new_iochan->force_event = 0;
+    new_iochan->last_event = new_iochan->max_idle = 0;
+    new_iochan->next = NULL;
+    return new_iochan;
+}
+
+int event_loop(IOCHAN *iochans)
+{
+    do /* loop as long as there are active associations to process */
+    {
+    	IOCHAN p, nextp;
+	fd_set in, out, except;
+	int res, max;
+	static struct timeval nullto = {0, 0}, to;
+	struct timeval *timeout;
+
+	FD_ZERO(&in);
+	FD_ZERO(&out);
+	FD_ZERO(&except);
+	timeout = &to; /* hang on select */
+	to.tv_sec = 5*60;
+	to.tv_usec = 0;
+	max = 0;
+    	for (p = *iochans; p; p = p->next)
+    	{
+	    if (p->force_event)
+		timeout = &nullto;        /* polling select */
+	    if (p->flags & EVENT_INPUT)
+		FD_SET(p->fd, &in);
+	    if (p->flags & EVENT_OUTPUT)
+	        FD_SET(p->fd, &out);
+	    if (p->flags & EVENT_EXCEPT)
+	        FD_SET(p->fd, &except);
+	    if (p->fd > max)
+	        max = p->fd;
+	}
+	if ((res = select(max + 1, &in, &out, &except, timeout)) < 0)
+	{
+	    if (errno == EINTR)
+    		continue;
+            else
+            {
+                /* Destroy the first member in the chain, and try again */
+                association *assoc = (association *)iochan_getdata(*iochans);
+                COMSTACK conn = assoc->client_link;
+
+                cs_close(conn);
+	        destroy_association(assoc);
+	        iochan_destroy(*iochans);
+                yaz_log(LOG_DEBUG, "error select, destroying iochan %p",
+			*iochans);
+            }
+	}
+    	for (p = *iochans; p; p = p->next)
+    	{
+	    int force_event = p->force_event;
+	    time_t now = time(0);
+
+	    p->force_event = 0;
+	    if (!p->destroyed && (FD_ISSET(p->fd, &in) ||
+		force_event == EVENT_INPUT))
+	    {
+    		p->last_event = now;
+		(*p->fun)(p, EVENT_INPUT);
+	    }
+	    if (!p->destroyed && (FD_ISSET(p->fd, &out) ||
+	        force_event == EVENT_OUTPUT))
+	    {
+	  	p->last_event = now;
+	    	(*p->fun)(p, EVENT_OUTPUT);
+	    }
+	    if (!p->destroyed && (FD_ISSET(p->fd, &except) ||
+	        force_event == EVENT_EXCEPT))
+	    {
+		p->last_event = now;
+	    	(*p->fun)(p, EVENT_EXCEPT);
+	    }
+	    if (!p->destroyed && ((p->max_idle && now - p->last_event >
+	        p->max_idle) || force_event == EVENT_TIMEOUT))
+	    {
+	        p->last_event = now;
+	        (*p->fun)(p, EVENT_TIMEOUT);
+	    }
+	}
+	for (p = *iochans; p; p = nextp)
+	{
+	    nextp = p->next;
+
+	    if (p->destroyed)
+	    {
+		IOCHAN tmp = p, pr;
+
+                /* We need to inform the threadlist that this channel has been destroyed */
+                statserv_remove(p);
+
+	    	/* Now reset the pointers */
+                if (p == *iochans)
+		    *iochans = p->next;
+		else
+		{
+		    for (pr = *iochans; pr; pr = pr->next)
+		        if (pr->next == p)
+    		            break;
+		    assert(pr); /* grave error if it weren't there */
+		    pr->next = p->next;
+		}
+		if (nextp == p)
+		    nextp = p->next;
+		xfree(tmp);
+	    }
+	}
+    }
+    while (*iochans);
+    return 0;
+}
Index: /main/tags/2.25/gsdl/packages/yaz/server/eventl.h
===================================================================
--- /main/tags/2.25/gsdl/packages/yaz/server/eventl.h	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/yaz/server/eventl.h	(revision 21064)
@@ -0,0 +1,94 @@
+/*
+ * Copyright (c) 1995-1999, Index Data
+ * See the file LICENSE for details.
+ * Sebastian Hammer, Adam Dickmeiss
+ *
+ * $Log$
+ * Revision 1.1  2000/08/03 03:11:41  johnmcp
+ * Added the YAZ toolkit source to the packages directory (for z39.50 stuff)
+ *
+ * Revision 1.11  1999/04/20 09:56:48  adam
+ * Added 'name' paramter to encoder/decoder routines (typedef Odr_fun).
+ * Modified all encoders/decoders to reflect this change.
+ *
+ * Revision 1.10  1998/01/29 13:30:23  adam
+ * Better event handle system for NT/Unix.
+ *
+ * Revision 1.9  1997/09/01 09:31:48  adam
+ * Removed definition statserv_remove from statserv.h to eventl.h.
+ *
+ * Revision 1.8  1995/06/19 12:39:09  quinn
+ * Fixed bug in timeout code. Added BER dumper.
+ *
+ * Revision 1.7  1995/06/16  10:31:34  quinn
+ * Added session timeout.
+ *
+ * Revision 1.6  1995/05/16  08:51:02  quinn
+ * License, documentation, and memory fixes
+ *
+ * Revision 1.5  1995/05/15  11:56:37  quinn
+ * Asynchronous facilities. Restructuring of seshigh code.
+ *
+ * Revision 1.4  1995/03/27  08:34:23  quinn
+ * Added dynamic server functionality.
+ * Released bindings to session.c (is now redundant)
+ *
+ * Revision 1.3  1995/03/15  08:37:42  quinn
+ * Now we're pretty much set for nonblocking I/O.
+ *
+ * Revision 1.2  1995/03/14  10:28:00  quinn
+ * More work on demo server.
+ *
+ * Revision 1.1  1995/03/10  18:22:45  quinn
+ * The rudiments of an asynchronous server.
+ *
+ */
+
+#ifndef EVENTL_H
+#define EVENTL_H
+
+#include <time.h>
+
+struct iochan;
+
+typedef void (*IOC_CALLBACK)(struct iochan *i, int event);
+
+typedef struct iochan
+{
+    int fd;
+    int flags;
+#define EVENT_INPUT     0x01
+#define EVENT_OUTPUT    0x02
+#define EVENT_EXCEPT    0x04
+#define EVENT_TIMEOUT   0x08
+#define EVENT_WORK      0x10
+int force_event;
+    IOC_CALLBACK fun;
+    void *data;
+    int destroyed;
+    time_t last_event;
+    time_t max_idle;
+    
+    struct iochan *next;
+} *IOCHAN;
+
+#define iochan_destroy(i) (void)((i)->destroyed = 1)
+#define iochan_getfd(i) ((i)->fd)
+#define iochan_setfd(i, f) ((i)->fd = (f))
+#define iochan_getdata(i) ((i)->data)
+#define iochan_setdata(i, d) ((i)->data = d)
+#define iochan_getflags(i) ((i)->flags)
+#define iochan_setflags(i, d) ((i)->flags = d)
+#define iochan_setflag(i, d) ((i)->flags |= d)
+#define iochan_clearflag(i, d) ((i)->flags &= ~(d))
+#define iochan_getflag(i, d) ((i)->flags & d ? 1 : 0)
+#define iochan_getfun(i) ((i)->fun)
+#define iochan_setfun(i, d) ((i)->fun = d)
+#define iochan_setevent(i, e) ((i)->force_event = (e))
+#define iochan_getnext(i) ((i)->next)
+#define iochan_settimeout(i, t) ((i)->max_idle = (t), (i)->last_event = time(0))
+
+IOCHAN iochan_create(int fd, IOC_CALLBACK cb, int flags);
+int event_loop(IOCHAN *iochans);
+void statserv_remove (IOCHAN pIOChannel);
+#endif
Index: /main/tags/2.25/gsdl/packages/yaz/server/requestq.c
===================================================================
--- /main/tags/2.25/gsdl/packages/yaz/server/requestq.c	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/yaz/server/requestq.c	(revision 21064)
@@ -0,0 +1,126 @@
+/*
+ * Copyright (C) 1994-1998, Index Data.
+ * See the file LICENSE for details.
+ * Sebastian Hammer, Adam Dickmeiss
+ *
+ * $Log$
+ * Revision 1.1  2000/08/03 03:11:41  johnmcp
+ * Added the YAZ toolkit source to the packages directory (for z39.50 stuff)
+ *
+ * Revision 1.7  1999/11/30 13:47:12  adam
+ * Improved installation. Moved header files to include/yaz.
+ *
+ * Revision 1.6  1998/02/11 11:53:35  adam
+ * Changed code so that it compiles as C++.
+ *
+ * Revision 1.5  1998/02/10 11:03:56  adam
+ * Added support for extended handlers in backend server interface.
+ *
+ * Revision 1.4  1997/10/27 13:55:03  adam
+ * Fixed memory leak: member response wasn't freed when queue
+ * was destroyed.
+ *
+ * Revision 1.3  1997/09/01 08:53:00  adam
+ * New windows NT/95 port using MSV5.0. The test server 'ztest' was
+ * moved a separate directory. MSV5.0 project server.dsp created.
+ * As an option, the server can now operate as an NT service.
+ *
+ * Revision 1.2  1995/11/01 13:54:57  quinn
+ * Minor adjustments
+ *
+ * Revision 1.1  1995/05/15  12:12:22  quinn
+ * Request queue.
+ *
+ *
+ */
+
+/*
+ * Simple queue management.
+ *
+ * We also use the request-freelist to store encoding buffers, rather than
+ * freeing and xmalloc'ing them on each cycle.
+ */
+
+#include <stdlib.h>
+
+#include <yaz/xmalloc.h>
+#include "session.h"
+
+void request_enq(request_q *q, request *r)
+{
+    if (q->tail)
+    	q->tail->next = r;
+    else
+    	q->head = r;
+    q->tail = r;
+    q->num++;
+}
+
+request *request_head(request_q *q)
+{
+    return q->head;
+}
+
+request *request_deq(request_q *q)
+{
+    request *r = q->head;
+
+    if (!r)
+    	return 0;
+    q->head = q->head->next;
+    if (!q->head)
+    	q->tail = 0;
+    q->num--;
+    return r;
+}
+
+void request_initq(request_q *q)
+{
+    q->head = q->tail = q->list = 0;
+    q->num = 0;
+}
+
+void request_delq(request_q *q)
+{
+    request *r1, *r = q->list;
+    while (r)
+    {
+	xfree (r->response);
+        r1 = r;
+        r = r->next;
+        xfree (r1);
+    }
+}
+
+request *request_get(request_q *q)
+{
+    request *r = q->list;
+
+    if (r)
+    	q->list = r->next;
+    else
+    {
+    	if (!(r = (request *)xmalloc(sizeof(*r))))
+	    abort();
+	r->response = 0;
+	r->size_response = 0;
+    }
+    r->q = q;
+    r->len_refid = 0;
+    r->refid = 0;
+    r->request = 0;
+    r->request_mem = 0;
+    r->len_response = 0;
+    r->clientData = 0;
+    r->state = REQUEST_IDLE;
+    r->next = 0;
+    return r;
+}
+
+void request_release(request *r)
+{
+    request_q *q = r->q;
+    r->next = q->list;
+    q->list = r;
+}
+
Index: /main/tags/2.25/gsdl/packages/yaz/server/service.c
===================================================================
--- /main/tags/2.25/gsdl/packages/yaz/server/service.c	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/yaz/server/service.c	(revision 21064)
@@ -0,0 +1,487 @@
+/*
+ * NT Service interface Utility.
+ *  Based on code written by
+ *     Chas Woodfield, Fretwell Downing Datasystems.
+ * $Log$
+ * Revision 1.1  2000/08/03 03:11:42  johnmcp
+ * Added the YAZ toolkit source to the packages directory (for z39.50 stuff)
+ *
+ * Revision 1.3  1999/06/10 11:45:30  adam
+ * Added bend_start, bend_stop handlers and removed pre_init.
+ * Handlers bend_start/bend_stop are called when service/daemon is
+ * started/stopped.
+ *
+ * Revision 1.2  1999/02/02 13:57:36  adam
+ * Uses preprocessor define WIN32 instead of WINDOWS to build code
+ * for Microsoft WIN32.
+ *
+ * Revision 1.1  1997/11/07 13:31:52  adam
+ * Added NT Service name part of statserv_options_block. Moved NT
+ * service utility to server library.
+ *
+ * Revision 1.6  1997/09/18 08:49:14  adam
+ * Option -runnormal no needed to run server in standalone mode.
+ *
+ * Revision 1.5  1997/09/17 12:10:43  adam
+ * YAZ version 1.4.
+ *
+ * Revision 1.4  1997/09/09 10:10:20  adam
+ * Another MSV5.0 port. Changed projects to include proper
+ * library/include paths.
+ * Server starts server in test-mode when no options are given.
+ *
+ * Revision 1.3  1997/09/04 13:50:30  adam
+ * Bug fix in ztest.
+ *
+ */
+
+/************************************************************/
+/* Note this file is shared by all processes                */
+/* Should really put it somewhere other than here           */
+/* For some strange reason it won't work when part of a lib */
+/************************************************************/
+
+#ifdef WIN32
+
+#include <windows.h>
+#include <stdio.h>
+#include <tchar.h>
+
+#include "service.h"
+
+static AppService *pService = NULL;
+static BOOL bRunAsService = TRUE;
+static void *pAppHandle = NULL;
+
+/* Private functions to this module */
+void Service_Create(LPTSTR pAppName, LPTSTR pServiceName, LPTSTR pServiceDisplayName, LPTSTR pDependancies, int argc, char **argv);
+void Service_Delete();
+void Service_Initialize();
+BOOL NotifyServiceController();
+BOOL UpdateServiceStatus(DWORD Status);
+void FailServiceStart(DWORD Win32Code, DWORD PrivateCode);
+void CmdInstallService(int argc, char *argv[], BOOL bAutoStart);
+void CmdRemoveService();
+LPTSTR GetLastErrorText(LPTSTR lpszBuf, DWORD dwSize);
+BOOL CheckServiceArguments(int argc, char *argv[]);
+
+/* Callback functions for thee service manager */
+void WINAPI ServiceMain(DWORD argc, LPTSTR argv[]);
+void WINAPI ServiceControlHandler(DWORD fdwControl);
+
+/* Function to handle Ctrl + C etc... */
+BOOL EventHandlerRoutine(DWORD dwCtrlType);
+
+void Service_Create(LPTSTR pAppName, LPTSTR pServiceName, LPTSTR pServiceDisplayName, LPTSTR pDependancies, int argc, char **argv)
+{
+    pService = malloc(sizeof(AppService));
+    pService->pAppName = pAppName;
+    pService->pServiceName = pServiceName;
+    pService->pServiceDisplayName = pServiceDisplayName;
+    pService->pDependancies = pDependancies;
+    pService->hService = 0;
+    pService->ServiceTable[0].lpServiceName = pServiceName; 
+    pService->ServiceTable[0].lpServiceProc = ServiceMain; 
+    pService->ServiceTable[1].lpServiceName = NULL; 
+    pService->ServiceTable[1].lpServiceProc = NULL; 
+    pService->argc = argc;
+    pService->argv = argv;
+}
+
+void Service_Delete()
+{
+    if (pService != NULL)
+    {
+        /* Mark the service as stopping */
+        UpdateServiceStatus(SERVICE_STOP_PENDING);
+
+        /* Stop the service */
+        StopAppService(pAppHandle);
+
+        /* Service has now stopped */
+        UpdateServiceStatus(SERVICE_STOPPED);
+
+        /* Free the memory */
+        free(pService);
+        pService = NULL;
+    }
+}
+
+void Service_Initialize()
+{
+    if (pService != NULL)
+    {
+        /* Register ourselves with the control dispatcher */
+        StartServiceCtrlDispatcher(pService->ServiceTable);
+    }
+}
+
+void WINAPI ServiceMain(DWORD argc, LPTSTR argv[])
+{
+    if (pService != NULL)
+    {
+        if (NotifyServiceController())
+        {
+            /* Set the status to pending */
+            UpdateServiceStatus(SERVICE_START_PENDING);
+
+            /* Lets attempt to start the service */
+            if (StartAppService(pAppHandle, pService->argc, pService->argv))
+            {
+                /* Service is now up and running */
+                UpdateServiceStatus(SERVICE_RUNNING);
+
+                /* Lets wait for our clients */
+                RunAppService(pAppHandle);
+            }
+            else
+            {
+                FailServiceStart(GetLastError(), 0);
+                Service_Delete();
+            }
+        }
+    }
+}
+
+BOOL NotifyServiceController()
+{
+    if (pService == NULL)
+    {
+        return(FALSE);
+    }
+    else
+    {
+        if (bRunAsService)
+        {
+            pService->ServiceStatus.dwServiceType = SERVICE_WIN32_OWN_PROCESS;
+            pService->ServiceStatus.dwCurrentState = SERVICE_STOPPED;
+            pService->ServiceStatus.dwControlsAccepted = SERVICE_ACCEPT_STOP;
+            pService->ServiceStatus.dwWin32ExitCode = 0;
+            pService->ServiceStatus.dwServiceSpecificExitCode = 0;
+            pService->ServiceStatus.dwCheckPoint = 0;
+            pService->ServiceStatus.dwWaitHint = 0;
+            pService->hService = RegisterServiceCtrlHandler(pService->pServiceName, ServiceControlHandler);
+
+            if (pService->hService)
+                UpdateServiceStatus(SERVICE_START_PENDING);
+            else
+                return(FALSE);
+        }
+        return(TRUE);
+    }
+}
+
+void WINAPI ServiceControlHandler(DWORD fdwControl)
+{
+    if (pService != NULL)
+    {
+        switch (fdwControl)
+        {
+            case SERVICE_CONTROL_STOP:
+                /* Update the service status to be pending */
+                Service_Delete();
+                break;
+
+            case SERVICE_CONTROL_INTERROGATE:
+                UpdateServiceStatus(pService->ServiceStatus.dwCurrentState);
+                break;
+
+            default:
+                break;
+        }
+    }
+}
+
+BOOL UpdateServiceStatus(DWORD Status)
+{
+    if (pService != NULL)
+    {
+        if (pService->hService)
+        {
+            pService->ServiceStatus.dwCurrentState = Status;
+            if ((Status == SERVICE_START_PENDING) || (Status == SERVICE_STOP_PENDING))
+            {
+                pService->ServiceStatus.dwCheckPoint ++;
+                pService->ServiceStatus.dwWaitHint = 5000;    /* 5 sec.*/
+            }
+            else
+            {
+                pService->ServiceStatus.dwCheckPoint = 0;
+                pService->ServiceStatus.dwWaitHint = 0;
+            }
+
+            return(SetServiceStatus(pService->hService, &pService->ServiceStatus));
+        }
+    }
+
+    return(FALSE);
+}
+
+void FailServiceStart(DWORD Win32Code, DWORD PrivateCode)
+{
+    if (pService != NULL)
+    {
+        pService->ServiceStatus.dwWin32ExitCode = Win32Code;
+        pService->ServiceStatus.dwServiceSpecificExitCode = PrivateCode;
+        UpdateServiceStatus(SERVICE_STOPPED);
+    }
+}
+
+void CmdInstallService(int argc, char *argv[], BOOL bAutoStart)
+{
+    if (pService != NULL)
+    {
+        SC_HANDLE   schService;
+        SC_HANDLE   schSCManager;
+
+        TCHAR szPath[1024];
+
+        if (GetModuleFileName(NULL, szPath, 512) == 0)
+        {
+            _tprintf(TEXT("Unable to install %s - %s\n"), TEXT(pService->pServiceDisplayName), GetLastErrorText(pService->szErr, 256));
+        }
+        else
+        {
+            int i;
+
+            strcat (szPath, TEXT(" -runservice"));
+            for (i = 1; i < argc; i++)
+            {
+                /* We will add the given command line arguments to the command */
+                /* We are not interested in the install and remove options */
+                if ((stricmp("-install", argv[i]) != 0) &&
+                    (stricmp("-installa", argv[i]) != 0) &&
+                    (stricmp("-remove", argv[i]) != 0))
+                {
+                    strcat(szPath, TEXT(" "));
+                    strcat(szPath, argv[i]);
+                }
+            }
+
+            schSCManager = OpenSCManager(NULL,                   /* machine (NULL == local) */
+                                         NULL,                   /* database (NULL == default) */
+                                         SC_MANAGER_ALL_ACCESS); /* access required */
+            if (schSCManager)
+            {
+                schService = CreateService(schSCManager,               /* SCManager database */
+                                           TEXT(pService->pServiceName),        /* name of service */
+                                           TEXT(pService->pServiceDisplayName), /* name to display */
+                                           SERVICE_ALL_ACCESS,         /* desired access */
+                                           SERVICE_WIN32_OWN_PROCESS,  /* service type */
+                                           bAutoStart ? SERVICE_AUTO_START :
+                                                        SERVICE_DEMAND_START, /* start type */
+                                           SERVICE_ERROR_NORMAL,       /* error control type */
+                                           szPath,                     /* service's binary */
+                                           NULL,                       /* no load ordering group */
+                                           NULL,                       /* no tag identifier */
+                                           TEXT(pService->pDependancies),       /* dependencies */
+                                           NULL,                       /* LocalSystem account */
+                                           NULL);                      /* no password */
+
+                if (schService)
+                {
+                    _tprintf(TEXT("%s installed.\n"), TEXT(pService->pServiceDisplayName));
+                    CloseServiceHandle(schService);
+                }
+                else
+                {
+                    _tprintf(TEXT("CreateService failed - %s\n"), GetLastErrorText(pService->szErr, 256));
+                }
+
+                CloseServiceHandle(schSCManager);
+            }
+            else
+                _tprintf(TEXT("OpenSCManager failed - %s\n"), GetLastErrorText(pService->szErr,256));
+        }
+    }
+}
+
+void CmdRemoveService()
+{
+    if (pService != NULL)
+    {
+        SC_HANDLE   schService;
+        SC_HANDLE   schSCManager;
+
+        schSCManager = OpenSCManager(NULL,                   /* machine (NULL == local) */
+                                     NULL,                   /* database (NULL == default) */
+                                     SC_MANAGER_ALL_ACCESS); /* access required */
+        if (schSCManager)
+        {
+            schService = OpenService(schSCManager, TEXT(pService->pServiceName), SERVICE_ALL_ACCESS);
+
+            if (schService)
+            {
+                /* try to stop the service */
+                if (ControlService(schService, SERVICE_CONTROL_STOP, &pService->ServiceStatus))
+                {
+                    _tprintf(TEXT("Stopping %s."), TEXT(pService->pServiceDisplayName));
+                    Sleep(1000);
+
+                    while (QueryServiceStatus(schService, &pService->ServiceStatus))
+                    {
+                        if (pService->ServiceStatus.dwCurrentState == SERVICE_STOP_PENDING)
+                        {
+                            _tprintf(TEXT("."));
+                            Sleep( 1000 );
+                        }
+                        else
+                            break;
+                    }
+
+                    if (pService->ServiceStatus.dwCurrentState == SERVICE_STOPPED)
+                        _tprintf(TEXT("\n%s stopped.\n"), TEXT(pService->pServiceDisplayName));
+                    else
+                        _tprintf(TEXT("\n%s failed to stop.\n"), TEXT(pService->pServiceDisplayName));
+
+                }
+
+                /* now remove the service */
+                if(DeleteService(schService))
+                    _tprintf(TEXT("%s removed.\n"), TEXT(pService->pServiceDisplayName));
+                else
+                    _tprintf(TEXT("DeleteService failed - %s\n"), GetLastErrorText(pService->szErr,256));
+
+                CloseServiceHandle(schService);
+            }
+            else
+                _tprintf(TEXT("OpenService failed - %s\n"), GetLastErrorText(pService->szErr,256));
+
+            CloseServiceHandle(schSCManager);
+        }
+        else
+            _tprintf(TEXT("OpenSCManager failed - %s\n"), GetLastErrorText(pService->szErr,256));
+    }
+}
+
+LPTSTR GetLastErrorText(LPTSTR lpszBuf, DWORD dwSize)
+{
+    DWORD dwRet;
+    LPTSTR lpszTemp = NULL;
+
+    dwRet = FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM |FORMAT_MESSAGE_ARGUMENT_ARRAY,
+                          NULL,
+                          GetLastError(),
+                          LANG_NEUTRAL,
+                          (LPTSTR)&lpszTemp,
+                          0,
+                          NULL);
+
+    /* supplied buffer is not long enough */
+    if (!dwRet || ((long)dwSize < (long)dwRet + 14))
+        lpszBuf[0] = TEXT('\0');
+    else
+    {
+        lpszTemp[lstrlen(lpszTemp)-2] = TEXT('\0');  /* remove cr and newline character */
+        _stprintf(lpszBuf, TEXT("%s (0x%x)"), lpszTemp, GetLastError());
+    }
+
+    if (lpszTemp)
+        LocalFree((HLOCAL)lpszTemp);
+
+    return(lpszBuf);
+}
+
+BOOL CheckServiceArguments(int argc, char *argv[])
+{
+    int i;
+
+    /* Lets process the arguments */
+    for (i = 1; i < argc; i++)
+    {
+        if (stricmp("-install", argv[i]) == 0)
+        {
+            /* They want to install the service */
+            CmdInstallService(argc, argv, FALSE);
+
+            /* We don't carry on, after we have installed the service */
+            return(FALSE);
+        }
+        else if (stricmp("-installa", argv[i]) == 0)
+        {
+            /* They want to install the service */
+            CmdInstallService(argc, argv, TRUE);
+
+            /* We don't carry on, after we have installed the service */
+            return(FALSE);
+        }
+        else if (stricmp("-remove", argv[i]) == 0)
+        {
+            /* Here they want to remove it */
+            CmdRemoveService();
+
+            /* We don't carry on, after we have removed the service */
+            return(FALSE);
+        }
+        else if (stricmp ("-runservice", argv[i]) == 0)
+        {
+            /* We can carry on, if we reached here */
+            argv[i] = "";
+            return(TRUE);
+        }
+    }
+    bRunAsService = FALSE;
+    return(TRUE);
+}
+
+BOOL SetupService(int argc, char *argv[], void *pHandle, LPTSTR pAppName, LPTSTR pServiceName, LPTSTR pServiceDisplayName, LPTSTR pDependancies)
+{
+    BOOL bDeleteService = TRUE;
+    BOOL bResult = FALSE;
+
+    /* Save the handle for later use */
+    pAppHandle = pHandle;
+
+    /* Create our service class */
+    Service_Create(pAppName, pServiceName, pServiceDisplayName, pDependancies, argc, argv);
+
+    if (CheckServiceArguments(argc, argv))
+    {
+        if (bRunAsService)
+        {
+            /* No need to set the console control handler, as the service manager handles all this for us */
+            Service_Initialize();
+            bDeleteService = FALSE;
+        }
+        else
+        {
+            /* Set the console control handler for exiting the program */
+            SetConsoleCtrlHandler((PHANDLER_ROUTINE)EventHandlerRoutine, TRUE);
+
+            /* Now do the main work */
+            ServiceMain(argc, argv);
+        }
+
+        /* We have been successful initializing, so let the caller know */
+        bResult = TRUE;
+    }
+
+    if (bDeleteService)
+    {
+        /* Finished with the service now */
+        Service_Delete();
+    }
+    return(bResult);
+}
+
+BOOL EventHandlerRoutine(DWORD dwCtrlType)
+{
+    /* This routine dosn't seem to get called all the time, Why ??? */
+    switch (dwCtrlType)
+    {
+        case CTRL_C_EVENT:        /* A CTRL+C signal was received, either from keyboard input or from a signal generated by the GenerateConsoleCtrlEvent function.*/
+        case CTRL_BREAK_EVENT:    /* A CTRL+BREAK signal was received, either from keyboard input or from a signal generated by GenerateConsoleCtrlEvent.*/
+        case CTRL_CLOSE_EVENT:    /* A signal that the system sends to all processes attached to a console when the user closes the console (either by choosing the Close command from the console window's System menu, or by choosing the End Task command from the Task List).*/
+        case CTRL_LOGOFF_EVENT:   /* A signal that the system sends to all console processes when a user is logging off. This signal does not indicate which user is logging off, so no assumptions can be made.*/
+        case CTRL_SHUTDOWN_EVENT: /* A signal that the system sends to all console processes when the system */
+            /* We are basically shutting down, so call Service_Delete */
+            Service_Delete();
+            return(FALSE);
+            break;
+
+        default:
+            /* we are not handling this one, so return FALSE */
+            return(FALSE);
+    }
+}
+#endif
Index: /main/tags/2.25/gsdl/packages/yaz/server/service.h
===================================================================
--- /main/tags/2.25/gsdl/packages/yaz/server/service.h	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/yaz/server/service.h	(revision 21064)
@@ -0,0 +1,54 @@
+/*
+ * NT Service interface Utility.
+ *  Based on code written by
+ *     Chas Woodfield, Fretwell Downing Datasystems.
+ * $Log$
+ * Revision 1.1  2000/08/03 03:11:42  johnmcp
+ * Added the YAZ toolkit source to the packages directory (for z39.50 stuff)
+ *
+ * Revision 1.1  1997/11/07 13:31:52  adam
+ * Added NT Service name part of statserv_options_block. Moved NT
+ * service utility to server library.
+ *
+ * Revision 1.2  1997/09/04 13:50:30  adam
+ * Bug fix in ztest.
+ *
+ */
+
+#ifndef SERVICE_INCLUDED
+#define SERVICE_INCLUDED
+
+#ifdef WIN32
+
+#include <windows.h>
+
+typedef struct _Service
+{
+    LPTSTR pAppName;
+    LPTSTR pServiceName;
+    LPTSTR pServiceDisplayName;
+    LPTSTR pDependancies;
+    TCHAR szErr[256];
+    SERVICE_STATUS_HANDLE hService;
+    SERVICE_STATUS ServiceStatus;
+    SERVICE_TABLE_ENTRY ServiceTable[2];
+    int argc;
+    char **argv;
+} AppService;
+
+/* Called by the app to initialize the service */
+BOOL SetupService(int argc, char *argv[], void *pHandle, LPTSTR pAppName, LPTSTR pServiceName, LPTSTR pServiceDisplayName, LPTSTR pDependancies);
+
+#endif /* WIN32 */
+
+/* Functions that must be in the main application */
+/* Initializes the app */
+int StartAppService(void *pHandle, int argc, char **argv);
+
+/* Now we wait for any connections */
+void RunAppService(void *pHandle);
+
+/* Time to tidyup and stop the service */
+void StopAppService(void *pHandle);
+
+#endif
Index: /main/tags/2.25/gsdl/packages/yaz/server/seshigh.c
===================================================================
--- /main/tags/2.25/gsdl/packages/yaz/server/seshigh.c	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/yaz/server/seshigh.c	(revision 21064)
@@ -0,0 +1,1935 @@
+/*
+ * Copyright (c) 1995-2000, Index Data
+ * See the file LICENSE for details.
+ *
+ * $Log$
+ * Revision 1.1  2000/08/03 03:11:43  johnmcp
+ * Added the YAZ toolkit source to the packages directory (for z39.50 stuff)
+ *
+ * Revision 1.101  2000/01/12 14:36:07  adam
+ * Added printing stream (ODR) for backend functions.
+ *
+ * Revision 1.100  1999/12/16 23:36:19  adam
+ * Implemented ILL protocol. Minor updates ASN.1 compiler.
+ *
+ * Revision 1.99  1999/11/30 13:47:12  adam
+ * Improved installation. Moved header files to include/yaz.
+ *
+ * Revision 1.98  1999/11/29 15:12:27  adam
+ * Changed the way implementationName - and version is set.
+ *
+ * Revision 1.96  1999/11/04 14:58:44  adam
+ * Added status elements for backend delete result set handler.
+ * Updated delete result result set command for client.
+ *
+ * Revision 1.95  1999/10/11 10:01:24  adam
+ * Implemented bend_sort_rr handler for frontend server.
+ *
+ * Revision 1.94  1999/08/27 09:40:32  adam
+ * Renamed logf function to yaz_log. Removed VC++ project files.
+ *
+ * Revision 1.93  1999/07/06 12:17:15  adam
+ * Added option -1 that runs server once (for profiling purposes).
+ *
+ * Revision 1.92  1999/06/17 10:54:45  adam
+ * Added facility to specify implementation version - and name
+ * for server.
+ *
+ * Revision 1.91  1999/06/01 14:29:12  adam
+ * Work on Extended Services.
+ *
+ * Revision 1.90  1999/05/27 13:02:20  adam
+ * Assigned OID for old DB Update (VAL_DBUPDATE0).
+ *
+ * Revision 1.89  1999/05/26 15:24:26  adam
+ * Fixed minor bugs regarding DB Update (introduced by previous commit).
+ *
+ * Revision 1.88  1999/04/20 09:56:48  adam
+ * Added 'name' paramter to encoder/decoder routines (typedef Odr_fun).
+ * Modified all encoders/decoders to reflect this change.
+ *
+ * Revision 1.87  1999/03/31 11:18:25  adam
+ * Implemented odr_strdup. Added Reference ID to backend server API.
+ *
+ * Revision 1.86  1999/02/02 13:57:38  adam
+ * Uses preprocessor define WIN32 instead of WINDOWS to build code
+ * for Microsoft WIN32.
+ *
+ * Revision 1.85  1998/11/17 09:52:59  adam
+ * Fixed minor bug (introduced by previous commit).
+ *
+ * Revision 1.84  1998/11/16 16:02:32  adam
+ * Added loggin utilies, log_rpn_query and log_scan_term. These used
+ * to be part of Zebra.
+ *
+ * Revision 1.83  1998/11/03 10:09:36  adam
+ * Fixed bug regarding YC.
+ *
+ * Revision 1.82  1998/10/20 14:00:30  quinn
+ * Fixed Scan
+ *
+ * Revision 1.81  1998/10/13 16:12:24  adam
+ * Added support for Surrogate Diagnostics for Scan Term entries.
+ *
+ * Revision 1.80  1998/09/02 12:41:53  adam
+ * Added decode stream in bend search structures.
+ *
+ * Revision 1.79  1998/08/19 16:10:08  adam
+ * Changed som member names of DeleteResultSetRequest/Response.
+ *
+ * Revision 1.78  1998/08/03 10:23:55  adam
+ * Fixed bug regarding Options for Sort.
+ *
+ * Revision 1.77  1998/07/20 12:38:42  adam
+ * Implemented delete result set service to server API.
+ *
+ * Revision 1.76  1998/05/27 16:57:07  adam
+ * Support for surrogate diagnostic records added for bend_fetch.
+ *
+ * Revision 1.75  1998/05/18 10:13:07  adam
+ * Fixed call to es_request handler - extra argument was passed.
+ *
+ * Revision 1.74  1998/03/31 15:13:20  adam
+ * Development towards compiled ASN.1.
+ *
+ * Revision 1.73  1998/03/31 11:07:45  adam
+ * Furhter work on UNIverse resource report.
+ * Added Extended Services handling in frontend server.
+ *
+ * Revision 1.72  1998/02/11 11:53:35  adam
+ * Changed code so that it compiles as C++.
+ *
+ * Revision 1.71  1998/02/10 11:03:57  adam
+ * Added support for extended handlers in backend server interface.
+ *
+ * Revision 1.70  1998/01/29 13:15:35  adam
+ * Implemented sort for the backend interface.
+ *
+ * Revision 1.69  1997/09/30 11:48:12  adam
+ * Fixed bug introduced by previous commit.
+ *
+ * Revision 1.68  1997/09/29 13:18:59  adam
+ * Added function, oid_ent_to_oid, to replace the function
+ * oid_getoidbyent, which is not thread safe.
+ *
+ * Revision 1.67  1997/09/17 12:10:40  adam
+ * YAZ version 1.4.
+ *
+ * Revision 1.66  1997/09/05 15:26:44  adam
+ * Added ODR encode in search and scen bend request structures.
+ * Fixed a few enums that caused trouble with C++.
+ *
+ * Revision 1.65  1997/09/01 08:53:01  adam
+ * New windows NT/95 port using MSV5.0. The test server 'ztest' was
+ * moved a separate directory. MSV5.0 project server.dsp created.
+ * As an option, the server can now operate as an NT service.
+ *
+ * Revision 1.64  1997/04/30 08:52:11  quinn
+ * Null
+ *
+ * Revision 1.63  1996/10/11  11:57:26  quinn
+ * Smallish
+ *
+ * Revision 1.62  1996/07/06  19:58:35  quinn
+ * System headerfiles gathered in yconfig
+ *
+ * Revision 1.61  1996/06/10  08:56:16  quinn
+ * Work on Summary.
+ *
+ * Revision 1.60  1996/05/30  11:03:10  quinn
+ * Fixed NextresultSetPosition bug fixed.
+ *
+ * Revision 1.59  1996/05/14  09:26:46  quinn
+ * Added attribute set to scan backend
+ *
+ * Revision 1.58  1996/02/20  12:53:04  quinn
+ * Chanes to SCAN
+ *
+ * Revision 1.57  1996/01/02  08:57:47  quinn
+ * Changed enums in the ASN.1 .h files to #defines. Changed oident.class to oclass
+ *
+ * Revision 1.56  1995/12/14  11:09:57  quinn
+ * Work on Explain
+ *
+ * Revision 1.55  1995/11/08  17:41:37  quinn
+ * Smallish.
+ *
+ * Revision 1.54  1995/11/08  15:11:29  quinn
+ * Log of close transmit.
+ *
+ * Revision 1.53  1995/11/01  13:54:58  quinn
+ * Minor adjustments
+ *
+ * Revision 1.52  1995/11/01  12:19:13  quinn
+ * Second attempt to fix same bug.
+ *
+ * Revision 1.50  1995/10/25  16:58:32  quinn
+ * Simple.
+ *
+ * Revision 1.49  1995/10/16  13:51:53  quinn
+ * Changes to provide Especs to the backend.
+ *
+ * Revision 1.48  1995/10/06  08:51:20  quinn
+ * Added Write-buffer.
+ *
+ * Revision 1.47  1995/08/29  14:24:16  quinn
+ * Added second half of close-handshake
+ *
+ * Revision 1.46  1995/08/29  11:17:58  quinn
+ * Added code to receive close
+ *
+ * Revision 1.45  1995/08/21  09:11:00  quinn
+ * Smallish fixes to suppport new formats.
+ *
+ * Revision 1.44  1995/08/17  12:45:25  quinn
+ * Fixed minor problems with GRS-1. Added support in c&s.
+ *
+ * Revision 1.43  1995/08/15  12:00:31  quinn
+ * Updated External
+ *
+ * Revision 1.42  1995/08/15  11:16:50  quinn
+ *
+ * Revision 1.41  1995/08/02  10:23:06  quinn
+ * Smallish
+ *
+ * Revision 1.40  1995/07/31  14:34:26  quinn
+ * Fixed bug in process_searchResponse (numberOfRecordsReturned).
+ *
+ * Revision 1.39  1995/06/27  13:21:00  quinn
+ * SUTRS support
+ *
+ * Revision 1.38  1995/06/19  12:39:11  quinn
+ * Fixed bug in timeout code. Added BER dumper.
+ *
+ * Revision 1.37  1995/06/16  13:16:14  quinn
+ * Fixed Defaultdiagformat.
+ *
+ * Revision 1.36  1995/06/16  10:31:36  quinn
+ * Added session timeout.
+ *
+ * Revision 1.35  1995/06/15  07:45:14  quinn
+ * Moving to v3.
+ *
+ * Revision 1.34  1995/06/14  15:26:46  quinn
+ * *** empty log message ***
+ *
+ * Revision 1.33  1995/06/06  14:57:05  quinn
+ * Better diagnostics.
+ *
+ * Revision 1.32  1995/06/06  08:41:44  quinn
+ * Better diagnostics.
+ *
+ * Revision 1.31  1995/06/06  08:15:37  quinn
+ * Cosmetic.
+ *
+ * Revision 1.30  1995/06/05  10:53:32  quinn
+ * Added a better SCAN.
+ *
+ * Revision 1.29  1995/06/01  11:25:03  quinn
+ * Smallish.
+ *
+ * Revision 1.28  1995/06/01  11:21:01  quinn
+ * Attempting to fix a bug in pack-records. replaced break with continue
+ * for large records, according to standard.
+ *
+ * Revision 1.27  1995/05/29  08:12:06  quinn
+ * Moved oid to util
+ *
+ * Revision 1.26  1995/05/18  13:02:12  quinn
+ * Smallish.
+ *
+ * Revision 1.25  1995/05/17  08:42:26  quinn
+ * Transfer auth info to backend. Allow backend to reject init gracefully.
+ *
+ * Revision 1.24  1995/05/16  08:51:04  quinn
+ * License, documentation, and memory fixes
+ *
+ * Revision 1.23  1995/05/15  13:25:10  quinn
+ * Fixed memory bug.
+ *
+ * Revision 1.22  1995/05/15  11:56:39  quinn
+ * Asynchronous facilities. Restructuring of seshigh code.
+ *
+ * Revision 1.21  1995/05/02  08:53:19  quinn
+ * Trying in vain to fix comm with ISODE
+ *
+ * Revision 1.20  1995/04/20  15:13:00  quinn
+ * Cosmetic
+ *
+ * Revision 1.19  1995/04/18  08:15:34  quinn
+ * Added dynamic memory allocation on encoding (whew). Code is now somewhat
+ * neater. We'll make the same change for decoding one day.
+ *
+ * Revision 1.18  1995/04/17  11:28:25  quinn
+ * Smallish
+ *
+ * Revision 1.17  1995/04/10  10:23:36  quinn
+ * Some work to add scan and other things.
+ *
+ * Revision 1.16  1995/03/31  09:18:55  quinn
+ * Added logging.
+ *
+ * Revision 1.15  1995/03/30  14:03:23  quinn
+ * Added RFC1006 as separate library
+ *
+ * Revision 1.14  1995/03/30  12:18:17  quinn
+ * Fixed bug.
+ *
+ * Revision 1.13  1995/03/30  09:09:24  quinn
+ * Added state-handle and some support for asynchronous activities.
+ *
+ * Revision 1.12  1995/03/29  15:40:16  quinn
+ * Ongoing work. Statserv is now dynamic by default
+ *
+ * Revision 1.11  1995/03/28  09:16:21  quinn
+ * Added record packing to the search request
+ *
+ * Revision 1.10  1995/03/27  08:34:24  quinn
+ * Added dynamic server functionality.
+ * Released bindings to session.c (is now redundant)
+ *
+ * Revision 1.9  1995/03/22  15:01:26  quinn
+ * Adjusting record packing.
+ *
+ * Revision 1.8  1995/03/22  10:13:21  quinn
+ * Working on record packer
+ *
+ * Revision 1.7  1995/03/21  15:53:31  quinn
+ * Little changes.
+ *
+ * Revision 1.6  1995/03/21  12:30:09  quinn
+ * Beginning to add support for record packing.
+ *
+ * Revision 1.5  1995/03/17  10:44:13  quinn
+ * Added catch of null-string in makediagrec
+ *
+ * Revision 1.4  1995/03/17  10:18:08  quinn
+ * Added memory management.
+ *
+ * Revision 1.3  1995/03/16  17:42:39  quinn
+ * Little changes
+ *
+ * Revision 1.2  1995/03/16  13:29:01  quinn
+ * Partitioned server.
+ *
+ * Revision 1.1  1995/03/15  16:02:10  quinn
+ * Modded session.c to seshigh.c
+ *
+ */
+
+/*
+ * Frontend server logic.
+ *
+ * This code receives incoming APDUs, and handles client requests by means
+ * of the backend API.
+ *
+ * Some of the code is getting quite involved, compared to simpler servers -
+ * primarily because it is asynchronous both in the communication with
+ * the user and the backend. We think the complexity will pay off in
+ * the form of greater flexibility when more asynchronous facilities
+ * are implemented.
+ *
+ * Memory management has become somewhat involved. In the simple case, where
+ * only one PDU is pending at a time, it will simply reuse the same memory,
+ * once it has found its working size. When we enable multiple concurrent
+ * operations, perhaps even with multiple parallel calls to the backend, it
+ * will maintain a pool of buffers for encoding and decoding, trying to
+ * minimize memory allocation/deallocation during normal operation.
+ *
+ * TODOs include (and will be done in order of public interest):
+ * 
+ * Support for EXPLAIN - provide simple meta-database system.
+ * Support for access control.
+ * Support for resource control.
+ * Support for extended services - primarily Item Order.
+ * Rest of Z39.50-1994
+ *
+ */
+
+#include <stdlib.h>
+#include <stdio.h>
+#ifdef WIN32
+#include <process.h>
+#else
+#include <unistd.h>
+#endif
+#include <assert.h>
+
+#include <yaz/yconfig.h>
+#include <yaz/xmalloc.h>
+#include <yaz/comstack.h>
+#include "eventl.h"
+#include "session.h"
+#include <yaz/proto.h>
+#include <yaz/oid.h>
+#include <yaz/log.h>
+#include <yaz/logrpn.h>
+#include <yaz/statserv.h>
+
+#include <yaz/backend.h>
+
+static int process_request(association *assoc, request *req, char **msg);
+void backend_response(IOCHAN i, int event);
+static int process_response(association *assoc, request *req, Z_APDU *res);
+static Z_APDU *process_initRequest(association *assoc, request *reqb);
+static Z_APDU *process_searchRequest(association *assoc, request *reqb,
+    int *fd);
+static Z_APDU *response_searchRequest(association *assoc, request *reqb,
+    bend_search_rr *bsrr, int *fd);
+static Z_APDU *process_presentRequest(association *assoc, request *reqb,
+    int *fd);
+static Z_APDU *process_scanRequest(association *assoc, request *reqb, int *fd);
+static Z_APDU *process_sortRequest(association *assoc, request *reqb, int *fd);
+static void process_close(association *assoc, request *reqb);
+void save_referenceId (request *reqb, Z_ReferenceId *refid);
+static Z_APDU *process_deleteRequest(association *assoc, request *reqb,
+    int *fd);
+static int bend_default_scan (void *handle, bend_scan_rr *rr);
+
+static FILE *apduf = 0; /* for use in static mode */
+static statserv_options_block *control_block = 0;
+
+/* Chas: Added in from DALI */
+static Z_APDU *process_ESRequest(association *assoc, request *reqb, int *fd);
+/* Chas: End of addition from DALI */
+
+/*
+ * Create and initialize a new association-handle.
+ *  channel  : iochannel for the current line.
+ *  link     : communications channel.
+ * Returns: 0 or a new association handle.
+ */
+association *create_association(IOCHAN channel, COMSTACK link)
+{
+    association *anew;
+
+    if (!control_block)
+    	control_block = statserv_getcontrol();
+    if (!(anew = (association *)xmalloc(sizeof(*anew))))
+    	return 0;
+    anew->client_chan = channel;
+    anew->client_link = link;
+    if (!(anew->decode = odr_createmem(ODR_DECODE)) ||
+    	!(anew->encode = odr_createmem(ODR_ENCODE)))
+	return 0;
+    if (*control_block->apdufile)
+    {
+    	char filename[256];
+	FILE *f;
+
+	strcpy(filename, control_block->apdufile);
+	if (!(anew->print = odr_createmem(ODR_PRINT)))
+	    return 0;
+	if (*control_block->apdufile != '-')
+	{
+	    strcpy(filename, control_block->apdufile);
+	    if (!control_block->dynamic)
+	    {
+		if (!apduf)
+		{
+		    if (!(apduf = fopen(filename, "w")))
+		    {
+			yaz_log(LOG_WARN|LOG_ERRNO, "%s", filename);
+			return 0;
+		    }
+		    setvbuf(apduf, 0, _IONBF, 0);
+		}
+		f = apduf;
+	    }
+	    else 
+	    {
+		sprintf(filename + strlen(filename), ".%d", getpid());
+		if (!(f = fopen(filename, "w")))
+		{
+		    yaz_log(LOG_WARN|LOG_ERRNO, "%s", filename);
+		    return 0;
+		}
+		setvbuf(f, 0, _IONBF, 0);
+	    }
+	    odr_setprint(anew->print, f);
+    	}
+    }
+    else
+    	anew->print = 0;
+    anew->input_buffer = 0;
+    anew->input_buffer_len = 0;
+    anew->backend = 0;
+    anew->state = ASSOC_NEW;
+    request_initq(&anew->incoming);
+    request_initq(&anew->outgoing);
+    anew->proto = cs_getproto(link);
+    return anew;
+}
+
+/*
+ * Free association and release resources.
+ */
+void destroy_association(association *h)
+{
+    odr_destroy(h->decode);
+    odr_destroy(h->encode);
+    if (h->print)
+	odr_destroy(h->print);
+    if (h->input_buffer)
+    xfree(h->input_buffer);
+    if (h->backend)
+    	bend_close(h->backend);
+    while (request_deq(&h->incoming));
+    while (request_deq(&h->outgoing));
+    request_delq(&h->incoming);
+    request_delq(&h->outgoing);
+    xfree(h);
+    if (control_block && control_block->one_shot)
+	exit (0);
+}
+
+static void do_close_req(association *a, int reason, char *message,
+			 request *req)
+{
+    Z_APDU apdu;
+    Z_Close *cls = zget_Close(a->encode);
+    
+    /* Purge request queue */
+    while (request_deq(&a->incoming));
+    while (request_deq(&a->outgoing));
+    if (a->version >= 3)
+    {
+	yaz_log(LOG_LOG, "Sending Close PDU, reason=%d, message=%s",
+	    reason, message ? message : "none");
+	apdu.which = Z_APDU_close;
+	apdu.u.close = cls;
+	*cls->closeReason = reason;
+	cls->diagnosticInformation = message;
+	process_response(a, req, &apdu);
+	iochan_settimeout(a->client_chan, 60);
+    }
+    else
+    {
+	yaz_log(LOG_DEBUG, "v2 client. No Close PDU");
+	iochan_setevent(a->client_chan, EVENT_TIMEOUT); /* force imm close */
+    }
+    a->state = ASSOC_DEAD;
+}
+
+static void do_close(association *a, int reason, char *message)
+{
+    do_close_req (a, reason, message, request_get(&a->outgoing));
+}
+
+/*
+ * This is where PDUs from the client are read and the further
+ * processing is initiated. Flow of control moves down through the
+ * various process_* functions below, until the encoded result comes back up
+ * to the output handler in here.
+ * 
+ *  h     : the I/O channel that has an outstanding event.
+ *  event : the current outstanding event.
+ */
+void ir_session(IOCHAN h, int event)
+{
+    int res;
+    association *assoc = (association *)iochan_getdata(h);
+    COMSTACK conn = assoc->client_link;
+    request *req;
+
+    assert(h && conn && assoc);
+    if (event == EVENT_TIMEOUT)
+    {
+	if (assoc->state != ASSOC_UP)
+	{
+	    yaz_log(LOG_LOG, "Final timeout - closing connection.");
+	    cs_close(conn);
+	    destroy_association(assoc);
+	    iochan_destroy(h);
+	}
+	else
+	{
+	    yaz_log(LOG_LOG, "Session idle too long. Sending close.");
+	    do_close(assoc, Z_Close_lackOfActivity, 0);
+	}
+	return;
+    }
+    if (event & EVENT_INPUT || event & EVENT_WORK) /* input */
+    {
+    	if (event & EVENT_INPUT)
+	{
+	    yaz_log(LOG_DEBUG, "ir_session (input)");
+	    assert(assoc && conn);
+	    /* We aren't speaking to this fellow */
+	    if (assoc->state == ASSOC_DEAD)
+	    {
+		yaz_log(LOG_LOG, "Closed connection after reject");
+		cs_close(conn);
+		destroy_association(assoc);
+		iochan_destroy(h);
+		return;
+	    }
+	    if ((res = cs_get(conn, &assoc->input_buffer,
+		&assoc->input_buffer_len)) <= 0)
+	    {
+		yaz_log(LOG_LOG, "Connection closed by client");
+		cs_close(conn);
+		destroy_association(assoc);
+		iochan_destroy(h);
+		return;
+	    }
+	    else if (res == 1) /* incomplete read - wait for more  */
+		return;
+	    if (cs_more(conn)) /* more stuff - call us again later, please */
+		iochan_setevent(h, EVENT_INPUT);
+	    	
+	    /* we got a complete PDU. Let's decode it */
+	    yaz_log(LOG_DEBUG, "Got PDU, %d bytes", res);
+	    req = request_get(&assoc->incoming); /* get a new request structure */
+	    odr_reset(assoc->decode);
+	    odr_setbuf(assoc->decode, assoc->input_buffer, res, 0);
+	    if (!z_APDU(assoc->decode, &req->request, 0, 0))
+	    {
+		yaz_log(LOG_LOG, "ODR error on incoming PDU: %s [near byte %d] ",
+		    odr_errmsg(odr_geterror(assoc->decode)),
+		    odr_offset(assoc->decode));
+		yaz_log(LOG_LOG, "PDU dump:");
+		odr_dumpBER(log_file(), assoc->input_buffer, res);
+		do_close(assoc, Z_Close_protocolError, "Malformed package");
+		return;
+	    }
+	    req->request_mem = odr_extract_mem(assoc->decode);
+	    if (assoc->print && !z_APDU(assoc->print, &req->request, 0, 0))
+	    {
+		yaz_log(LOG_WARN, "ODR print error: %s", 
+		    odr_errmsg(odr_geterror(assoc->print)));
+		odr_reset(assoc->print);
+	    }
+	    request_enq(&assoc->incoming, req);
+	}
+
+	/* can we do something yet? */
+	req = request_head(&assoc->incoming);
+	if (req->state == REQUEST_IDLE)
+	{
+	    char *msg;
+	    request_deq(&assoc->incoming);
+	    if (process_request(assoc, req, &msg) < 0)
+		do_close_req(assoc, Z_Close_systemProblem, msg, req);
+	}
+    }
+    if (event & EVENT_OUTPUT)
+    {
+    	request *req = request_head(&assoc->outgoing);
+
+	yaz_log(LOG_DEBUG, "ir_session (output)");
+	req->state = REQUEST_PENDING;
+    	switch (res = cs_put(conn, req->response, req->len_response))
+	{
+	    case -1:
+	    	yaz_log(LOG_LOG, "Connection closed by client");
+		cs_close(conn);
+		destroy_association(assoc);
+		iochan_destroy(h);
+		break;
+	    case 0: /* all sent - release the request structure */
+	    	yaz_log(LOG_DEBUG, "Wrote PDU, %d bytes", req->len_response);
+		nmem_destroy(req->request_mem);
+		request_deq(&assoc->outgoing);
+		request_release(req);
+		if (!request_head(&assoc->outgoing))
+		    iochan_clearflag(h, EVENT_OUTPUT);
+		break;
+	    /* value of 1 -- partial send -- is simply ignored */
+	}
+    }
+    if (event & EVENT_EXCEPT)
+    {
+	yaz_log(LOG_DEBUG, "ir_session (exception)");
+	cs_close(conn);
+	destroy_association(assoc);
+	iochan_destroy(h);
+    }
+}
+
+/*
+ * Initiate request processing.
+ */
+static int process_request(association *assoc, request *req, char **msg)
+{
+    int fd = -1;
+    Z_APDU *res;
+    int retval;
+
+    *msg = "Unknown Error";
+    assert(req && req->state == REQUEST_IDLE);
+    switch (req->request->which)
+    {
+    	case Z_APDU_initRequest:
+	    res = process_initRequest(assoc, req); break;
+	case Z_APDU_searchRequest:
+	    res = process_searchRequest(assoc, req, &fd); break;
+	case Z_APDU_presentRequest:
+	    res = process_presentRequest(assoc, req, &fd); break;
+	case Z_APDU_scanRequest:
+	    if (assoc->bend_scan)
+		res = process_scanRequest(assoc, req, &fd);
+	    else
+	    {
+		*msg = "Cannot handle Scan APDU";
+		return -1;
+	    }
+	    break;
+        case Z_APDU_extendedServicesRequest:
+	    if (assoc->bend_esrequest)
+		res = process_ESRequest(assoc, req, &fd);
+	    else
+	    {
+		*msg = "Cannot handle Extended Services APDU";
+		return -1;
+	    }
+	    break;
+        case Z_APDU_sortRequest:
+	    if (assoc->bend_sort)
+		res = process_sortRequest(assoc, req, &fd);
+	    else
+	    {
+		*msg = "Cannot handle Sort APDU";
+		return -1;
+	    }
+	    break;
+	case Z_APDU_close:
+	    process_close(assoc, req);
+	    return 0;
+        case Z_APDU_deleteResultSetRequest:
+	    if (assoc->bend_delete)
+		res = process_deleteRequest(assoc, req, &fd);
+	    else
+	    {
+		*msg = "Cannot handle Delete APDU";
+		return -1;
+	    }
+	    break;
+	default:
+	    *msg = "Bad APDU received";
+	    return -1;
+    }
+    if (res)
+    {
+    	yaz_log(LOG_DEBUG, "  result immediately available");
+    	retval = process_response(assoc, req, res);
+    }
+    else if (fd < 0)
+    {
+    	yaz_log(LOG_DEBUG, "  result unavailble");
+	retval = 0;
+    }
+    else /* no result yet - one will be provided later */
+    {
+    	IOCHAN chan;
+
+	/* Set up an I/O handler for the fd supplied by the backend */
+
+	yaz_log(LOG_DEBUG, "   establishing handler for result");
+	req->state = REQUEST_PENDING;
+	if (!(chan = iochan_create(fd, backend_response, EVENT_INPUT)))
+	    abort();
+	iochan_setdata(chan, assoc);
+	retval = 0;
+    }
+    return retval;
+}
+
+/*
+ * Handle message from the backend.
+ */
+void backend_response(IOCHAN i, int event)
+{
+    association *assoc = (association *)iochan_getdata(i);
+    request *req = request_head(&assoc->incoming);
+    Z_APDU *res;
+    int fd;
+
+    yaz_log(LOG_DEBUG, "backend_response");
+    assert(assoc && req && req->state != REQUEST_IDLE);
+    /* determine what it is we're waiting for */
+    switch (req->request->which)
+    {
+	case Z_APDU_searchRequest:
+	    res = response_searchRequest(assoc, req, 0, &fd); break;
+#if 0
+	case Z_APDU_presentRequest:
+	    res = response_presentRequest(assoc, req, 0, &fd); break;
+	case Z_APDU_scanRequest:
+	    res = response_scanRequest(assoc, req, 0, &fd); break;
+#endif
+	default:
+	    yaz_log(LOG_WARN, "Serious programmer's lapse or bug");
+	    abort();
+    }
+    if ((res && process_response(assoc, req, res) < 0) || fd < 0)
+    {
+	yaz_log(LOG_LOG, "Fatal error when talking to backend");
+	do_close(assoc, Z_Close_systemProblem, 0);
+	iochan_destroy(i);
+	return;
+    }
+    else if (!res) /* no result yet - try again later */
+    {
+    	yaz_log(LOG_DEBUG, "   no result yet");
+    	iochan_setfd(i, fd); /* in case fd has changed */
+    }
+}
+
+/*
+ * Encode response, and transfer the request structure to the outgoing queue.
+ */
+static int process_response(association *assoc, request *req, Z_APDU *res)
+{
+    odr_setbuf(assoc->encode, req->response, req->size_response, 1);
+    if (!z_APDU(assoc->encode, &res, 0, 0))
+    {
+    	yaz_log(LOG_WARN, "ODR error when encoding response: %s",
+	    odr_errmsg(odr_geterror(assoc->decode)));
+	odr_reset(assoc->encode);
+	return -1;
+    }
+    req->response = odr_getbuf(assoc->encode, &req->len_response,
+	&req->size_response);
+    odr_setbuf(assoc->encode, 0, 0, 0); /* don'txfree if we abort later */
+    if (assoc->print && !z_APDU(assoc->print, &res, 0, 0))
+    {
+	yaz_log(LOG_WARN, "ODR print error: %s", 
+	    odr_errmsg(odr_geterror(assoc->print)));
+	odr_reset(assoc->print);
+    }
+    odr_reset(assoc->encode);
+    req->state = REQUEST_IDLE;
+    request_enq(&assoc->outgoing, req);
+    /* turn the work over to the ir_session handler */
+    iochan_setflag(assoc->client_chan, EVENT_OUTPUT);
+    /* Is there more work to be done? give that to the input handler too */
+#if 1
+    if (request_head(&assoc->incoming))
+    {
+	yaz_log (LOG_DEBUG, "more work to be done");
+    	iochan_setevent(assoc->client_chan, EVENT_WORK);
+    }
+#endif
+    return 0;
+}
+
+/*
+ * Handle init request.
+ * At the moment, we don't check the options
+ * anywhere else in the code - we just try not to do anything that would
+ * break a naive client. We'll toss 'em into the association block when
+ * we need them there.
+ */
+static Z_APDU *process_initRequest(association *assoc, request *reqb)
+{
+    Z_InitRequest *req = reqb->request->u.initRequest;
+    Z_APDU *apdu = zget_APDU(assoc->encode, Z_APDU_initResponse);
+    Z_InitResponse *resp = apdu->u.initResponse;
+    bend_initrequest binitreq;
+    bend_initresult *binitres;
+    char options[100];
+
+    yaz_log(LOG_LOG, "Got initRequest");
+    if (req->implementationId)
+    	yaz_log(LOG_LOG, "Id:        %s", req->implementationId);
+    if (req->implementationName)
+    	yaz_log(LOG_LOG, "Name:      %s", req->implementationName);
+    if (req->implementationVersion)
+    	yaz_log(LOG_LOG, "Version:   %s", req->implementationVersion);
+
+    binitreq.stream = assoc->encode;
+    binitreq.print = assoc->print;
+    binitreq.configname = "default-config";
+    binitreq.auth = req->idAuthentication;
+    binitreq.referenceId = req->referenceId;
+    binitreq.implementation_version = 0;
+    binitreq.implementation_name = 0;
+    binitreq.bend_sort = NULL;
+    binitreq.bend_search = NULL;
+    binitreq.bend_present = NULL;
+    binitreq.bend_esrequest = NULL;
+    binitreq.bend_delete = NULL;
+    binitreq.bend_scan = bend_default_scan;
+    if (!(binitres = bend_init(&binitreq)))
+    {
+    	yaz_log(LOG_WARN, "Bad response from backend.");
+    	return 0;
+    }
+
+    assoc->backend = binitres->handle;
+    if ((assoc->bend_sort = (int (*)())binitreq.bend_sort))
+	yaz_log (LOG_DEBUG, "Sort handler installed");
+    if ((assoc->bend_search = (int (*)())binitreq.bend_search))
+	yaz_log (LOG_DEBUG, "Search handler installed");
+    if ((assoc->bend_present = (int (*)())binitreq.bend_present))
+	yaz_log (LOG_DEBUG, "Present handler installed");   
+    if ((assoc->bend_esrequest = (int (*)())binitreq.bend_esrequest))
+	yaz_log (LOG_DEBUG, "ESRequest handler installed");   
+    if ((assoc->bend_delete = (int (*)())binitreq.bend_delete))
+	yaz_log (LOG_DEBUG, "Delete handler installed");   
+    if ((assoc->bend_scan = (int (*)())binitreq.bend_scan))
+	yaz_log (LOG_DEBUG, "Scan handler installed");   
+    
+    resp->referenceId = req->referenceId;
+    *options = '\0';
+    /* let's tell the client what we can do */
+    if (ODR_MASK_GET(req->options, Z_Options_search))
+    {
+    	ODR_MASK_SET(resp->options, Z_Options_search);
+	strcat(options, "srch");
+    }
+    if (ODR_MASK_GET(req->options, Z_Options_present))
+    {
+    	ODR_MASK_SET(resp->options, Z_Options_present);
+	strcat(options, " prst");
+    }
+    if (ODR_MASK_GET(req->options, Z_Options_delSet) && binitreq.bend_delete)
+    {
+    	ODR_MASK_SET(resp->options, Z_Options_delSet);
+	strcat(options, " del");
+    }
+    if (ODR_MASK_GET(req->options, Z_Options_extendedServices) &&
+	binitreq.bend_esrequest)
+    {
+	ODR_MASK_SET(resp->options, Z_Options_extendedServices);
+	strcat (options, " extendedServices");
+    }
+    if (ODR_MASK_GET(req->options, Z_Options_namedResultSets))
+    {
+    	ODR_MASK_SET(resp->options, Z_Options_namedResultSets);
+	strcat(options, " namedresults");
+    }
+    if (ODR_MASK_GET(req->options, Z_Options_scan) && binitreq.bend_scan)
+    {
+    	ODR_MASK_SET(resp->options, Z_Options_scan);
+	strcat(options, " scan");
+    }
+    if (ODR_MASK_GET(req->options, Z_Options_concurrentOperations))
+    {
+    	ODR_MASK_SET(resp->options, Z_Options_concurrentOperations);
+	strcat(options, " concurop");
+    }
+    if (ODR_MASK_GET(req->options, Z_Options_sort) && binitreq.bend_sort)
+    {
+	ODR_MASK_SET(resp->options, Z_Options_sort);
+	strcat(options, " sort");
+    }
+    if (ODR_MASK_GET(req->protocolVersion, Z_ProtocolVersion_1))
+    {
+    	ODR_MASK_SET(resp->protocolVersion, Z_ProtocolVersion_1);
+	assoc->version = 2; /* 1 & 2 are equivalent */
+    }
+    if (ODR_MASK_GET(req->protocolVersion, Z_ProtocolVersion_2))
+    {
+    	ODR_MASK_SET(resp->protocolVersion, Z_ProtocolVersion_2);
+	assoc->version = 2;
+    }
+    if (ODR_MASK_GET(req->protocolVersion, Z_ProtocolVersion_3))
+    {
+    	ODR_MASK_SET(resp->protocolVersion, Z_ProtocolVersion_3);
+	assoc->version = 3;
+    }
+    yaz_log(LOG_LOG, "Negotiated to v%d: %s", assoc->version, options);
+    assoc->maximumRecordSize = *req->maximumRecordSize;
+    if (assoc->maximumRecordSize > control_block->maxrecordsize)
+    	assoc->maximumRecordSize = control_block->maxrecordsize;
+    assoc->preferredMessageSize = *req->preferredMessageSize;
+    if (assoc->preferredMessageSize > assoc->maximumRecordSize)
+    	assoc->preferredMessageSize = assoc->maximumRecordSize;
+    resp->preferredMessageSize = &assoc->preferredMessageSize;
+    resp->maximumRecordSize = &assoc->maximumRecordSize;
+
+    resp->implementationName = "GFS";
+
+    if (binitreq.implementation_name)
+    {
+	char *nv = (char *)
+	    odr_malloc (assoc->encode,
+			strlen(binitreq.implementation_name) + 10 + 
+			       strlen(resp->implementationName));
+	sprintf (nv, "%s / %s",
+		 resp->implementationName, binitreq.implementation_name);
+        resp->implementationName = nv;
+    }
+    if (binitreq.implementation_version)
+    {
+	char *nv = (char *)
+	    odr_malloc (assoc->encode,
+			strlen(binitreq.implementation_version) + 10 + 
+			       strlen(resp->implementationVersion));
+	sprintf (nv, "YAZ %s / %s",
+		 resp->implementationVersion, binitreq.implementation_version);
+        resp->implementationVersion = nv;
+    }
+
+    if (binitres->errcode)
+    {
+    	yaz_log(LOG_LOG, "Connection rejected by backend.");
+    	*resp->result = 0;
+	assoc->state = ASSOC_DEAD;
+    }
+    else
+	assoc->state = ASSOC_UP;
+    return apdu;
+}
+
+/*
+ * These functions should be merged.
+ */
+
+static void set_addinfo (Z_DefaultDiagFormat *dr, char *addinfo)
+{
+#if ASN_COMPILED
+    dr->which = Z_DefaultDiagFormat_v2Addinfo;
+    dr->u.v2Addinfo = addinfo ? addinfo : "";
+#else
+    dr->which = Z_DiagForm_v2AddInfo;
+    dr->addinfo = addinfo ? addinfo : "";
+#endif
+}
+
+/*
+ * nonsurrogate diagnostic record.
+ */
+static Z_Records *diagrec(association *assoc, int error, char *addinfo)
+{
+    int oid[OID_SIZE];
+    Z_Records *rec = (Z_Records *)
+	odr_malloc (assoc->encode, sizeof(*rec));
+    oident bib1;
+    int *err = (int *)
+	odr_malloc (assoc->encode, sizeof(*err));
+    Z_DiagRec *drec = (Z_DiagRec *)
+	odr_malloc (assoc->encode, sizeof(*drec));
+    Z_DefaultDiagFormat *dr = (Z_DefaultDiagFormat *)
+	odr_malloc (assoc->encode, sizeof(*dr));
+
+    bib1.proto = assoc->proto;
+    bib1.oclass = CLASS_DIAGSET;
+    bib1.value = VAL_BIB1;
+
+    yaz_log(LOG_DEBUG, "Diagnostic: %d -- %s", error, addinfo ? addinfo :
+	"NULL");
+    *err = error;
+    rec->which = Z_Records_NSD;
+#if ASN_COMPILED
+    rec->u.nonSurrogateDiagnostic = dr;
+#else
+    rec->u.nonSurrogateDiagnostic = drec;
+    drec->which = Z_DiagRec_defaultFormat;
+    drec->u.defaultFormat = dr;
+#endif
+    dr->diagnosticSetId =
+	odr_oiddup (assoc->encode, oid_ent_to_oid(&bib1, oid));
+    dr->condition = err;
+    set_addinfo (dr, addinfo);
+    return rec;
+}
+
+/*
+ * surrogate diagnostic.
+ */
+static Z_NamePlusRecord *surrogatediagrec(association *assoc, char *dbname,
+					  int error, char *addinfo)
+{
+    int oid[OID_SIZE];
+    Z_NamePlusRecord *rec = (Z_NamePlusRecord *)
+	odr_malloc (assoc->encode, sizeof(*rec));
+    int *err = (int *)odr_malloc (assoc->encode, sizeof(*err));
+    oident bib1;
+    Z_DiagRec *drec = (Z_DiagRec *)odr_malloc (assoc->encode, sizeof(*drec));
+    Z_DefaultDiagFormat *dr = (Z_DefaultDiagFormat *)
+	odr_malloc (assoc->encode, sizeof(*dr));
+    
+    bib1.proto = assoc->proto;
+    bib1.oclass = CLASS_DIAGSET;
+    bib1.value = VAL_BIB1;
+
+    yaz_log(LOG_DEBUG, "SurrogateDiagnotic: %d -- %s", error, addinfo);
+    *err = error;
+    rec->databaseName = dbname;
+    rec->which = Z_NamePlusRecord_surrogateDiagnostic;
+    rec->u.surrogateDiagnostic = drec;
+    drec->which = Z_DiagRec_defaultFormat;
+    drec->u.defaultFormat = dr;
+    dr->diagnosticSetId = odr_oiddup (assoc->encode,
+                                      oid_ent_to_oid(&bib1, oid));
+    dr->condition = err;
+    set_addinfo (dr, addinfo);
+
+    return rec;
+}
+
+/*
+ * multiple nonsurrogate diagnostics.
+ */
+static Z_DiagRecs *diagrecs(association *assoc, int error, char *addinfo)
+{
+    int oid[OID_SIZE];
+    Z_DiagRecs *recs = (Z_DiagRecs *)odr_malloc (assoc->encode, sizeof(*recs));
+    int *err = (int *)odr_malloc (assoc->encode, sizeof(*err));
+    oident bib1;
+    Z_DiagRec **recp = (Z_DiagRec **)odr_malloc (assoc->encode, sizeof(*recp));
+    Z_DiagRec *drec = (Z_DiagRec *)odr_malloc (assoc->encode, sizeof(*drec));
+    Z_DefaultDiagFormat *rec = (Z_DefaultDiagFormat *)odr_malloc (assoc->encode, sizeof(*rec));
+
+    yaz_log(LOG_DEBUG, "DiagRecs: %d -- %s", error, addinfo ? addinfo : "");
+    bib1.proto = assoc->proto;
+    bib1.oclass = CLASS_DIAGSET;
+    bib1.value = VAL_BIB1;
+
+    *err = error;
+    recs->num_diagRecs = 1;
+    recs->diagRecs = recp;
+    recp[0] = drec;
+    drec->which = Z_DiagRec_defaultFormat;
+    drec->u.defaultFormat = rec;
+
+    rec->diagnosticSetId = odr_oiddup (assoc->encode,
+                                      oid_ent_to_oid(&bib1, oid));
+    rec->condition = err;
+
+#ifdef ASN_COMPILED
+    rec->which = Z_DefaultDiagFormat_v2Addinfo;
+    rec->u.v2Addinfo = addinfo ? addinfo : "";
+#else
+    rec->which = Z_DiagForm_v2AddInfo;
+    rec->addinfo = addinfo ? addinfo : "";
+#endif
+    return recs;
+}
+
+static Z_Records *pack_records(association *a, char *setname, int start,
+				int *num, Z_RecordComposition *comp,
+				int *next, int *pres, oid_value format,
+				Z_ReferenceId *referenceId)
+{
+    int recno, total_length = 0, toget = *num, dumped_records = 0;
+    Z_Records *records =
+	(Z_Records *) odr_malloc (a->encode, sizeof(*records));
+    Z_NamePlusRecordList *reclist =
+	(Z_NamePlusRecordList *) odr_malloc (a->encode, sizeof(*reclist));
+    Z_NamePlusRecord **list =
+	(Z_NamePlusRecord **) odr_malloc (a->encode, sizeof(*list) * toget);
+
+    records->which = Z_Records_DBOSD;
+    records->u.databaseOrSurDiagnostics = reclist;
+    reclist->num_records = 0;
+    reclist->records = list;
+    *pres = Z_PRES_SUCCESS;
+    *num = 0;
+    *next = 0;
+
+    yaz_log(LOG_LOG, "Request to pack %d+%d", start, toget);
+    yaz_log(LOG_DEBUG, "pms=%d, mrs=%d", a->preferredMessageSize,
+    	a->maximumRecordSize);
+    for (recno = start; reclist->num_records < toget; recno++)
+    {
+    	bend_fetchrequest freq;
+	bend_fetchresult *fres;
+	Z_NamePlusRecord *thisrec;
+	int this_length = 0;
+	/*
+	 * we get the number of bytes allocated on the stream before any
+	 * allocation done by the backend - this should give us a reasonable
+	 * idea of the total size of the data so far.
+	 */
+	total_length = odr_total(a->encode) - dumped_records;
+	freq.setname = setname;
+	freq.number = recno;
+	freq.comp = comp;
+	freq.format = format;
+	freq.stream = a->encode;
+	freq.print = a->print;
+	freq.surrogate_flag = 0;
+	freq.referenceId = referenceId;
+	if (!(fres = bend_fetch(a->backend, &freq, 0)))
+	{
+	    *pres = Z_PRES_FAILURE;
+	    return diagrec(a, 2, "Backend interface problem");
+	}
+	/* backend should be able to signal whether error is system-wide
+	   or only pertaining to current record */
+	if (fres->errcode)
+	{
+	    if (!freq.surrogate_flag)
+	    {
+		*pres = Z_PRES_FAILURE;
+		return diagrec(a, fres->errcode, fres->errstring);
+	    }
+	    reclist->records[reclist->num_records] =
+		surrogatediagrec(a, fres->basename, fres->errcode,
+				 fres->errstring);
+	    reclist->num_records++;
+	    *next = fres->last_in_set ? 0 : recno + 1;
+	    continue;
+	}
+	if (fres->len >= 0)
+	    this_length = fres->len;
+	else
+	    this_length = odr_total(a->encode) - total_length;
+	yaz_log(LOG_DEBUG, "  fetched record, len=%d, total=%d",
+	    this_length, total_length);
+	if (this_length + total_length > a->preferredMessageSize)
+	{
+	    /* record is small enough, really */
+	    if (this_length <= a->preferredMessageSize)
+	    {
+	    	yaz_log(LOG_DEBUG, "  Dropped last normal-sized record");
+		*pres = Z_PRES_PARTIAL_2;
+		break;
+	    }
+	    /* record can only be fetched by itself */
+	    if (this_length < a->maximumRecordSize)
+	    {
+	    	yaz_log(LOG_DEBUG, "  Record > prefmsgsz");
+	    	if (toget > 1)
+		{
+		    yaz_log(LOG_DEBUG, "  Dropped it");
+		    reclist->records[reclist->num_records] =
+		   	 surrogatediagrec(a, fres->basename, 16, 0);
+		    reclist->num_records++;
+		    *next = fres->last_in_set ? 0 : recno + 1;
+		    dumped_records += this_length;
+		    continue;
+		}
+	    }
+	    else /* too big entirely */
+	    {
+	    	yaz_log(LOG_DEBUG, "Record > maxrcdsz");
+		reclist->records[reclist->num_records] =
+		    surrogatediagrec(a, fres->basename, 17, 0);
+		reclist->num_records++;
+		*next = fres->last_in_set ? 0 : recno + 1;
+		dumped_records += this_length;
+		continue;
+	    }
+	}
+
+	if (!(thisrec = (Z_NamePlusRecord *)
+	      odr_malloc(a->encode, sizeof(*thisrec))))
+	    return 0;
+	if (!(thisrec->databaseName = (char *)odr_malloc(a->encode,
+	    strlen(fres->basename) + 1)))
+	    return 0;
+	strcpy(thisrec->databaseName, fres->basename);
+	thisrec->which = Z_NamePlusRecord_databaseRecord;
+	thisrec->u.databaseRecord = z_ext_record(a->encode, fres->format,
+						 fres->record, fres->len);
+	if (!thisrec->u.databaseRecord)
+	    return 0;
+	reclist->records[reclist->num_records] = thisrec;
+	reclist->num_records++;
+	*next = fres->last_in_set ? 0 : recno + 1;
+    }
+    *num = reclist->num_records;
+    return records;
+}
+
+static Z_APDU *process_searchRequest(association *assoc, request *reqb,
+    int *fd)
+{
+    Z_SearchRequest *req = reqb->request->u.searchRequest;
+    bend_search_rr *bsrr = 
+	(bend_search_rr *)nmem_malloc (reqb->request_mem, sizeof(*bsrr));
+    
+    yaz_log(LOG_LOG, "Got SearchRequest.");
+    bsrr->fd = fd;
+    bsrr->request = reqb;
+    bsrr->association = assoc;
+    bsrr->referenceId = req->referenceId;
+    save_referenceId (reqb, bsrr->referenceId);
+
+    yaz_log (LOG_LOG, "ResultSet '%s'", req->resultSetName);
+    if (req->databaseNames)
+    {
+	int i;
+	for (i = 0; i < req->num_databaseNames; i++)
+	    yaz_log (LOG_LOG, "Database '%s'", req->databaseNames[i]);
+    }
+    switch (req->query->which)
+    {
+    case Z_Query_type_1: case Z_Query_type_101:
+	log_rpn_query (req->query->u.type_1);
+    }
+    if (assoc->bend_search)
+    {
+	bsrr->setname = req->resultSetName;
+	bsrr->replace_set = *req->replaceIndicator;
+	bsrr->num_bases = req->num_databaseNames;
+	bsrr->basenames = req->databaseNames;
+	bsrr->query = req->query;
+	bsrr->stream = assoc->encode;
+	bsrr->decode = assoc->decode;
+	bsrr->print = assoc->print;
+	bsrr->errcode = 0;
+	bsrr->hits = 0;
+	bsrr->errstring = NULL;
+	((int (*)(void *, bend_search_rr *))(assoc->bend_search))
+	    (assoc->backend, bsrr);
+	if (!bsrr->request)
+	    return 0;
+    }
+    else
+    {
+	bend_searchrequest bsrq;
+	bend_searchresult *bsrt;
+
+	bsrq.setname = req->resultSetName;
+	bsrq.replace_set = *req->replaceIndicator;
+	bsrq.num_bases = req->num_databaseNames;
+	bsrq.basenames = req->databaseNames;
+	bsrq.query = req->query;
+        bsrq.referenceId = req->referenceId;
+	bsrq.stream = assoc->encode;
+	bsrq.decode = assoc->decode;
+	bsrq.print = assoc->print;
+	if (!(bsrt = bend_search (assoc->backend, &bsrq, fd)))
+	    return 0;
+	bsrr->hits = bsrt->hits;
+	bsrr->errcode = bsrt->errcode;
+	bsrr->errstring = bsrt->errstring;
+    }
+    return response_searchRequest(assoc, reqb, bsrr, fd);
+}
+
+int bend_searchresponse(void *handle, bend_search_rr *bsrr) {return 0;}
+
+/*
+ * Prepare a searchresponse based on the backend results. We probably want
+ * to look at making the fetching of records nonblocking as well, but
+ * so far, we'll keep things simple.
+ * If bsrt is null, that means we're called in response to a communications
+ * event, and we'll have to get the response for ourselves.
+ */
+static Z_APDU *response_searchRequest(association *assoc, request *reqb,
+    bend_search_rr *bsrt, int *fd)
+{
+    Z_SearchRequest *req = reqb->request->u.searchRequest;
+    Z_APDU *apdu = (Z_APDU *)odr_malloc (assoc->encode, sizeof(*apdu));
+    Z_SearchResponse *resp = (Z_SearchResponse *)
+	odr_malloc (assoc->encode, sizeof(*resp));
+    int *nulint = (int *)odr_malloc (assoc->encode, sizeof(*nulint));
+    bool_t *sr = (bool_t *)odr_malloc (assoc->encode, sizeof(*sr));
+    int *next = (int *)odr_malloc (assoc->encode, sizeof(*next));
+    int *none = (int *)odr_malloc (assoc->encode, sizeof(*none));
+
+    *nulint = 0;
+    *sr = 1;
+    *next = 0;
+    *none = Z_RES_NONE;
+
+    apdu->which = Z_APDU_searchResponse;
+    apdu->u.searchResponse = resp;
+    resp->referenceId = req->referenceId;
+    resp->additionalSearchInfo = 0;
+    resp->otherInfo = 0;
+    *fd = -1;
+    if (!bsrt && !bend_searchresponse(assoc->backend, bsrt))
+    {
+    	yaz_log(LOG_FATAL, "Bad result from backend");
+    	return 0;
+    }
+    else if (bsrt->errcode)
+    {
+	resp->records = diagrec(assoc, bsrt->errcode, bsrt->errstring);
+	resp->resultCount = nulint;
+	resp->numberOfRecordsReturned = nulint;
+	resp->nextResultSetPosition = nulint;
+	resp->searchStatus = nulint;
+	resp->resultSetStatus = none;
+	resp->presentStatus = 0;
+    }
+    else
+    {
+    	int *toget = (int *)odr_malloc (assoc->encode, sizeof(*toget));
+        int *presst = (int *)odr_malloc (assoc->encode, sizeof(*presst));
+	Z_RecordComposition comp, *compp = 0;
+
+        *toget = 0;
+        *presst = 0;
+	resp->records = 0;
+	resp->resultCount = &bsrt->hits;
+
+	comp.which = Z_RecordComp_simple;
+	/* how many records does the user agent want, then? */
+	if (bsrt->hits <= *req->smallSetUpperBound)
+	{
+	    *toget = bsrt->hits;
+	    if ((comp.u.simple = req->smallSetElementSetNames))
+	        compp = &comp;
+	}
+	else if (bsrt->hits < *req->largeSetLowerBound)
+	{
+	    *toget = *req->mediumSetPresentNumber;
+	    if (*toget > bsrt->hits)
+		*toget = bsrt->hits;
+	    if ((comp.u.simple = req->mediumSetElementSetNames))
+	        compp = &comp;
+	}
+	else
+	    *toget = 0;
+
+	if (*toget && !resp->records)
+	{
+	    oident *prefformat;
+	    oid_value form;
+
+	    if (!(prefformat = oid_getentbyoid(req->preferredRecordSyntax)) ||
+	    	prefformat->oclass != CLASS_RECSYN)
+		form = VAL_NONE;
+	    else
+	    	form = prefformat->value;
+	    resp->records = pack_records(assoc, req->resultSetName, 1,
+		toget, compp, next, presst, form, req->referenceId);
+	    if (!resp->records)
+		return 0;
+	    resp->numberOfRecordsReturned = toget;
+	    resp->nextResultSetPosition = next;
+	    resp->searchStatus = sr;
+	    resp->resultSetStatus = 0;
+	    resp->presentStatus = presst;
+	}
+	else
+	{
+	    if (*resp->resultCount)
+	    	*next = 1;
+	    resp->numberOfRecordsReturned = nulint;
+	    resp->nextResultSetPosition = next;
+	    resp->searchStatus = sr;
+	    resp->resultSetStatus = 0;
+	    resp->presentStatus = 0;
+	}
+    }
+    return apdu;
+}
+
+/*
+ * Maybe we got a little over-friendly when we designed bend_fetch to
+ * get only one record at a time. Some backends can optimise multiple-record
+ * fetches, and at any rate, there is some overhead involved in
+ * all that selecting and hopping around. Problem is, of course, that the
+ * frontend can't know ahead of time how many records it'll need to
+ * fill the negotiated PDU size. Annoying. Segmentation or not, Z/SR
+ * is downright lousy as a bulk data transfer protocol.
+ *
+ * To start with, we'll do the fetching of records from the backend
+ * in one operation: To save some trips in and out of the event-handler,
+ * and to simplify the interface to pack_records. At any rate, asynch
+ * operation is more fun in operations that have an unpredictable execution
+ * speed - which is normally more true for search than for present.
+ */
+static Z_APDU *process_presentRequest(association *assoc, request *reqb,
+    int *fd)
+{
+    Z_PresentRequest *req = reqb->request->u.presentRequest;
+    oident *prefformat;
+    oid_value form;
+    Z_APDU *apdu;
+    Z_PresentResponse *resp;
+    int *presst;
+    int *next;
+    int *num;
+
+    yaz_log(LOG_LOG, "Got PresentRequest.");
+
+    if (!(prefformat = oid_getentbyoid(req->preferredRecordSyntax)) ||
+	prefformat->oclass != CLASS_RECSYN)
+	form = VAL_NONE;
+    else
+	form = prefformat->value;
+    if (assoc->bend_present)
+    {
+	bend_present_rr *bprr = (bend_present_rr *)
+	    nmem_malloc (reqb->request_mem, sizeof(*bprr));
+	bprr->setname = req->resultSetId;
+	bprr->start = *req->resultSetStartPoint;
+	bprr->number = *req->numberOfRecordsRequested;
+	bprr->format = form;
+	bprr->comp = req->recordComposition;
+	bprr->referenceId = req->referenceId;
+	bprr->stream = assoc->encode;
+	bprr->print = assoc->print;
+	bprr->request = reqb;
+	bprr->association = assoc;
+	bprr->errcode = 0;
+	bprr->errstring = NULL;
+	((int (*)(void *, bend_present_rr *))(*assoc->bend_present))(
+	    assoc->backend, bprr);
+	
+	if (!bprr->request)
+	    return 0;
+    }
+    apdu = (Z_APDU *)odr_malloc (assoc->encode, sizeof(*apdu));
+    resp = (Z_PresentResponse *)odr_malloc (assoc->encode, sizeof(*resp));
+    presst = (int *)odr_malloc (assoc->encode, sizeof(*presst));
+    next = (int *)odr_malloc (assoc->encode, sizeof(*next));
+    num = (int *)odr_malloc (assoc->encode, sizeof(*num));
+    *presst = 0;
+    *next = 0;
+    *num = *req->numberOfRecordsRequested;
+    
+    apdu->which = Z_APDU_presentResponse;
+    apdu->u.presentResponse = resp;
+    resp->referenceId = req->referenceId;
+    resp->otherInfo = 0;
+    
+    resp->records =
+	pack_records(assoc, req->resultSetId, *req->resultSetStartPoint,
+		     num, req->recordComposition, next, presst, form,
+                     req->referenceId);
+    if (!resp->records)
+	return 0;
+    resp->numberOfRecordsReturned = num;
+    resp->presentStatus = presst;
+    resp->nextResultSetPosition = next;
+    
+    return apdu;
+}
+
+static int bend_default_scan (void *handle, bend_scan_rr *rr)
+{
+    bend_scanrequest srq;
+    bend_scanresult *srs;
+
+    srq.num_bases = rr->num_bases;
+    srq.basenames = rr->basenames;
+    srq.attributeset = rr->attributeset;
+    srq.referenceId = rr->referenceId;
+    srq.term = rr->term;
+    srq.term_position = rr->term_position;
+    srq.num_entries = rr->num_entries;
+    srq.stream = rr->stream;
+    srq.print = rr->print;
+    
+    srs = bend_scan(handle, &srq, 0);
+
+    rr->term_position = srs->term_position;
+    rr->num_entries = srs->num_entries;
+    rr->entries = srs->entries;
+    rr->status = srs->status;
+    rr->errcode = srs->errcode;
+    rr->errstring = srs->errstring;
+    return 0;
+}
+
+/*
+ * Scan was implemented rather in a hurry, and with support for only the basic
+ * elements of the service in the backend API. Suggestions are welcome.
+ */
+static Z_APDU *process_scanRequest(association *assoc, request *reqb, int *fd)
+{
+    Z_ScanRequest *req = reqb->request->u.scanRequest;
+    Z_APDU *apdu = (Z_APDU *)odr_malloc (assoc->encode, sizeof(*apdu));
+    Z_ScanResponse *res = (Z_ScanResponse *)
+	odr_malloc (assoc->encode, sizeof(*res));
+    int *scanStatus = (int *)
+	odr_malloc (assoc->encode, sizeof(*scanStatus));
+    int *numberOfEntriesReturned = (int *)
+	odr_malloc (assoc->encode, sizeof(*numberOfEntriesReturned));
+    Z_ListEntries *ents = (Z_ListEntries *)
+	odr_malloc (assoc->encode, sizeof(*ents));
+    Z_DiagRecs *diagrecs_p = NULL;
+    oident *attent;
+    oident *attset;
+
+    yaz_log(LOG_LOG, "Got ScanRequest");
+    *scanStatus = Z_Scan_failure;
+    *numberOfEntriesReturned = 0;
+
+    apdu->which = Z_APDU_scanResponse;
+    apdu->u.scanResponse = res;
+    res->referenceId = req->referenceId;
+    res->stepSize = 0;
+    res->scanStatus = scanStatus;
+    res->numberOfEntriesReturned = numberOfEntriesReturned;
+    res->positionOfTerm = 0;
+    res->entries = ents;
+    ents->num_entries = 0;
+    ents->entries = NULL;
+    ents->num_nonsurrogateDiagnostics = 0;
+    ents->nonsurrogateDiagnostics = NULL;
+    res->attributeSet = 0;
+    res->otherInfo = 0;
+
+    if (req->attributeSet && (!(attent = oid_getentbyoid(req->attributeSet)) ||
+			      attent->oclass != CLASS_ATTSET
+			      || attent->value != VAL_BIB1))
+	diagrecs_p = diagrecs(assoc, 121, 0);
+    else if (req->stepSize && *req->stepSize > 0)
+    	diagrecs_p = diagrecs(assoc, 205, 0);
+    else
+    {
+	bend_scan_rr *bsrr = (bend_scan_rr *)
+	    odr_malloc (assoc->encode, sizeof(*bsrr));
+	if (req->databaseNames)
+	{
+	    int i;
+	    for (i = 0; i < req->num_databaseNames; i++)
+		yaz_log (LOG_LOG, "Database '%s'", req->databaseNames[i]);
+	}
+	bsrr->num_bases = req->num_databaseNames;
+	bsrr->basenames = req->databaseNames;
+	bsrr->num_entries = *req->numberOfTermsRequested;
+	bsrr->term = req->termListAndStartPoint;
+	bsrr->referenceId = req->referenceId;
+	bsrr->stream = assoc->encode;
+	bsrr->print = assoc->print;
+	if (!(attset = oid_getentbyoid(req->attributeSet)) ||
+	    attset->oclass != CLASS_RECSYN)
+	    bsrr->attributeset = VAL_NONE;
+	else
+	    bsrr->attributeset = attset->value;
+	log_scan_term (req->termListAndStartPoint, attset->value);
+	bsrr->term_position = req->preferredPositionInResponse ?
+	    *req->preferredPositionInResponse : 1;
+	((int (*)(void *, bend_scan_rr *))(*assoc->bend_scan))(assoc->backend,
+							       bsrr);
+	if (bsrr->errcode)
+	    diagrecs_p = diagrecs(assoc, bsrr->errcode, bsrr->errstring);
+	else
+	{
+	    int i;
+            Z_Entry **tab = (Z_Entry **)
+		odr_malloc (assoc->encode, sizeof(*tab) * bsrr->num_entries);
+	    
+	    if (bsrr->status == BEND_SCAN_PARTIAL)
+	    	*scanStatus = Z_Scan_partial_5;
+	    else
+	    	*scanStatus = Z_Scan_success;
+	    ents->entries = tab;
+	    ents->num_entries = bsrr->num_entries;
+	    res->numberOfEntriesReturned = &ents->num_entries;	    
+	    res->positionOfTerm = &bsrr->term_position;
+	    for (i = 0; i < bsrr->num_entries; i++)
+	    {
+	    	Z_Entry *e;
+		Z_TermInfo *t;
+		Odr_oct *o;
+		
+		tab[i] = e = (Z_Entry *)odr_malloc(assoc->encode, sizeof(*e));
+		if (bsrr->entries[i].occurrences >= 0)
+		{
+		    e->which = Z_Entry_termInfo;
+		    e->u.termInfo = t = (Z_TermInfo *)
+			odr_malloc(assoc->encode, sizeof(*t));
+		    t->suggestedAttributes = 0;
+		    t->displayTerm = 0;
+		    t->alternativeTerm = 0;
+		    t->byAttributes = 0;
+		    t->otherTermInfo = 0;
+		    t->globalOccurrences = &bsrr->entries[i].occurrences;
+		    t->term = (Z_Term *)
+			odr_malloc(assoc->encode, sizeof(*t->term));
+		    t->term->which = Z_Term_general;
+		    t->term->u.general = o =
+			(Odr_oct *)odr_malloc(assoc->encode, sizeof(Odr_oct));
+		    o->buf = (unsigned char *)
+			odr_malloc(assoc->encode, o->len = o->size =
+				   strlen(bsrr->entries[i].term));
+		    memcpy(o->buf, bsrr->entries[i].term, o->len);
+		    yaz_log(LOG_DEBUG, "  term #%d: '%s' (%d)", i,
+			 bsrr->entries[i].term, bsrr->entries[i].occurrences);
+		}
+		else
+		{
+		    Z_DiagRecs *drecs = diagrecs (assoc,
+						  bsrr->entries[i].errcode,
+						  bsrr->entries[i].errstring);
+		    assert (drecs->num_diagRecs == 1);
+		    e->which = Z_Entry_surrogateDiagnostic;
+		    assert (drecs->diagRecs[0]);
+		    e->u.surrogateDiagnostic = drecs->diagRecs[0];
+		}
+	    }
+	}
+    }
+    if (diagrecs_p)
+    {
+	ents->num_nonsurrogateDiagnostics = diagrecs_p->num_diagRecs;
+	ents->nonsurrogateDiagnostics = diagrecs_p->diagRecs;
+    }
+    return apdu;
+}
+
+static Z_APDU *process_sortRequest(association *assoc, request *reqb,
+    int *fd)
+{
+    Z_SortRequest *req = reqb->request->u.sortRequest;
+    Z_SortResponse *res = (Z_SortResponse *)
+	odr_malloc (assoc->encode, sizeof(*res));
+    bend_sort_rr *bsrr = (bend_sort_rr *)
+	odr_malloc (assoc->encode, sizeof(*bsrr));
+
+    Z_APDU *apdu = (Z_APDU *)odr_malloc (assoc->encode, sizeof(*apdu));
+
+    yaz_log(LOG_LOG, "Got SortRequest.");
+
+#ifdef ASN_COMPILED
+    bsrr->num_input_setnames = req->num_inputResultSetNames;
+    bsrr->input_setnames = req->inputResultSetNames;
+#else
+    bsrr->num_input_setnames = req->inputResultSetNames->num_strings;
+    bsrr->input_setnames = req->inputResultSetNames->strings;
+#endif
+    bsrr->referenceId = req->referenceId;
+    bsrr->output_setname = req->sortedResultSetName;
+    bsrr->sort_sequence = req->sortSequence;
+    bsrr->stream = assoc->encode;
+    bsrr->print = assoc->print;
+
+    bsrr->sort_status = Z_SortStatus_failure;
+    bsrr->errcode = 0;
+    bsrr->errstring = 0;
+    
+    ((int (*)(void *, bend_sort_rr *))(*assoc->bend_sort))(assoc->backend,
+							   bsrr);
+    
+    res->referenceId = bsrr->referenceId;
+    res->sortStatus = (int *)
+	odr_malloc (assoc->encode, sizeof(*res->sortStatus));
+    *res->sortStatus = bsrr->sort_status;
+    res->resultSetStatus = 0;
+    if (bsrr->errcode)
+    {
+	Z_DiagRecs *dr = diagrecs (assoc, bsrr->errcode, bsrr->errstring);
+#ifdef ASN_COMPILED
+	res->diagnostics = dr->diagRecs;
+	res->num_diagnostics = dr->num_diagRecs;
+#else
+	res->diagnostics = dr;
+#endif
+    }
+    else
+    {
+#ifdef ASN_COMPILED
+	res->num_diagnostics = 0;
+#endif
+	res->diagnostics = 0;
+    }
+    res->otherInfo = 0;
+
+    apdu->which = Z_APDU_sortResponse;
+    apdu->u.sortResponse = res;
+    return apdu;
+}
+
+static Z_APDU *process_deleteRequest(association *assoc, request *reqb,
+    int *fd)
+{
+    Z_DeleteResultSetRequest *req = reqb->request->u.deleteResultSetRequest;
+    Z_DeleteResultSetResponse *res = (Z_DeleteResultSetResponse *)
+	odr_malloc (assoc->encode, sizeof(*res));
+    bend_delete_rr *bdrr = (bend_delete_rr *)
+	odr_malloc (assoc->encode, sizeof(*bdrr));
+    Z_APDU *apdu = (Z_APDU *)odr_malloc (assoc->encode, sizeof(*apdu));
+
+    yaz_log(LOG_LOG, "Got DeleteRequest.");
+
+    bdrr->num_setnames = req->num_resultSetList;
+    bdrr->setnames = req->resultSetList;
+    bdrr->stream = assoc->encode;
+    bdrr->print = assoc->print;
+    bdrr->function = *req->deleteFunction;
+    bdrr->referenceId = req->referenceId;
+    bdrr->statuses = 0;
+    if (bdrr->num_setnames > 0)
+    {
+	int i;
+	bdrr->statuses = odr_malloc(assoc->encode, sizeof(*bdrr->statuses) *
+				    bdrr->num_setnames);
+	for (i = 0; i < bdrr->num_setnames; i++)
+	    bdrr->statuses[i] = 0;
+    }
+    ((int (*)(void *, bend_delete_rr *))
+     (*assoc->bend_delete))(assoc->backend, bdrr);
+    
+    res->referenceId = req->referenceId;
+
+    res->deleteOperationStatus = (int *)
+	odr_malloc (assoc->encode, sizeof(*res->deleteOperationStatus));
+    *res->deleteOperationStatus = bdrr->delete_status;
+
+    res->deleteListStatuses = 0;
+    if (bdrr->num_setnames > 0)
+    {
+	int i;
+	res->deleteListStatuses = odr_malloc(assoc->encode,
+					     sizeof(*res->deleteListStatuses));
+	res->deleteListStatuses->num = bdrr->num_setnames;
+	res->deleteListStatuses->elements =
+	    odr_malloc (assoc->encode,
+			sizeof(*res->deleteListStatuses->elements) *
+			bdrr->num_setnames);
+	for (i = 0; i<bdrr->num_setnames; i++)
+	{
+	    res->deleteListStatuses->elements[i] =
+		odr_malloc (assoc->encode,
+			    sizeof(**res->deleteListStatuses->elements));
+	    res->deleteListStatuses->elements[i]->status = bdrr->statuses+i;
+	    res->deleteListStatuses->elements[i]->id =
+		odr_strdup (assoc->encode, bdrr->setnames[i]);
+	    
+	}
+    }
+    res->numberNotDeleted = 0;
+    res->bulkStatuses = 0;
+    res->deleteMessage = 0;
+    res->otherInfo = 0;
+
+    apdu->which = Z_APDU_deleteResultSetResponse;
+    apdu->u.deleteResultSetResponse = res;
+    return apdu;
+}
+
+static void process_close(association *assoc, request *reqb)
+{
+    Z_Close *req = reqb->request->u.close;
+    static char *reasons[] =
+    {
+	"finished",
+	"shutdown",
+	"systemProblem",
+	"costLimit",
+	"resources",
+	"securityViolation",
+	"protocolError",
+	"lackOfActivity",
+	"peerAbort",
+	"unspecified"
+    };
+
+    yaz_log(LOG_LOG, "Got Close, reason %s, message %s",
+	reasons[*req->closeReason], req->diagnosticInformation ?
+	req->diagnosticInformation : "NULL");
+    if (assoc->version < 3) /* to make do_force respond with close */
+    	assoc->version = 3;
+    do_close_req(assoc, Z_Close_finished,
+		 "Association terminated by client", reqb);
+}
+
+void save_referenceId (request *reqb, Z_ReferenceId *refid)
+{
+    if (refid)
+    {
+	reqb->len_refid = refid->len;
+	reqb->refid = (char *)nmem_malloc (reqb->request_mem, refid->len);
+	memcpy (reqb->refid, refid->buf, refid->len);
+    }
+    else
+    {
+	reqb->len_refid = 0;
+	reqb->refid = NULL;
+    }
+}
+
+void bend_request_send (bend_association a, bend_request req, Z_APDU *res)
+{
+    process_response (a, req, res);
+}
+
+bend_request bend_request_mk (bend_association a)
+{
+    request *nreq = request_get (&a->outgoing);
+    nreq->request_mem = nmem_create ();
+    return nreq;
+}
+
+Z_ReferenceId *bend_request_getid (ODR odr, bend_request req)
+{
+    Z_ReferenceId *id;
+    if (!req->refid)
+	return 0;
+    id = (Odr_oct *)odr_malloc (odr, sizeof(*odr));
+    id->buf = (unsigned char *)odr_malloc (odr, req->len_refid);
+    id->len = id->size = req->len_refid;
+    memcpy (id->buf, req->refid, req->len_refid);
+    return id;
+}
+
+void bend_request_destroy (bend_request *req)
+{
+    nmem_destroy((*req)->request_mem);
+    request_release(*req);
+    *req = NULL;
+}
+
+int bend_backend_respond (bend_association a, bend_request req)
+{
+    char *msg;
+    int r;
+    r = process_request (a, req, &msg);
+    if (r < 0)
+	logf (LOG_WARN, "%s", msg);
+    return r;
+}
+
+void bend_request_setdata(bend_request r, void *p)
+{
+    r->clientData = p;
+}
+
+void *bend_request_getdata(bend_request r)
+{
+    return r->clientData;
+}
+
+static Z_APDU *process_ESRequest(association *assoc, request *reqb, int *fd)
+{
+    bend_esrequest_rr esrequest;
+
+    Z_ExtendedServicesRequest *req = reqb->request->u.extendedServicesRequest;
+    Z_APDU *apdu = zget_APDU(assoc->encode, Z_APDU_extendedServicesResponse);
+
+    Z_ExtendedServicesResponse *resp = apdu->u.extendedServicesResponse;
+
+    yaz_log(LOG_DEBUG,"inside Process esRequest");
+
+    esrequest.esr = reqb->request->u.extendedServicesRequest;
+    esrequest.stream = assoc->encode;
+    esrequest.decode = assoc->decode;
+    esrequest.print = assoc->print;
+    esrequest.errcode = 0;
+    esrequest.errstring = NULL;
+    esrequest.request = reqb;
+    esrequest.association = assoc;
+    esrequest.referenceId = req->referenceId;
+    
+    ((int (*)(void *, bend_esrequest_rr *))(*assoc->bend_esrequest))
+	(assoc->backend, &esrequest);
+    
+    /* If the response is being delayed, return NULL */
+    if (esrequest.request == NULL)
+        return(NULL);
+
+    resp->referenceId = req->referenceId;
+
+    if (esrequest.errcode == -1)
+    {
+        /* Backend service indicates request will be processed */
+        yaz_log(LOG_DEBUG,"Request could be processed...Accepted !");
+        *resp->operationStatus = Z_ExtendedServicesResponse_accepted;
+    }
+    else if (esrequest.errcode == 0)
+    {
+        /* Backend service indicates request will be processed */
+        yaz_log(LOG_DEBUG,"Request could be processed...Done !");
+        *resp->operationStatus = Z_ExtendedServicesResponse_done;
+    }
+    else
+    {
+	Z_DiagRecs *diagRecs = diagrecs (assoc, esrequest.errcode,
+					 esrequest.errstring);
+
+        /* Backend indicates error, request will not be processed */
+        yaz_log(LOG_DEBUG,"Request could not be processed...failure !");
+        *resp->operationStatus = Z_ExtendedServicesResponse_failure;
+	resp->num_diagnostics = diagRecs->num_diagRecs;
+	resp->diagnostics = diagRecs->diagRecs;
+    }
+    /* Do something with the members of bend_extendedservice */
+
+    yaz_log(LOG_DEBUG,"Send the result apdu");
+    return apdu;
+}
Index: /main/tags/2.25/gsdl/packages/yaz/server/session.h
===================================================================
--- /main/tags/2.25/gsdl/packages/yaz/server/session.h	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/yaz/server/session.h	(revision 21064)
@@ -0,0 +1,177 @@
+/*
+ * Copyright (C) 1995-1999, Index Data
+ * See the file LICENSE for details.
+ * Sebastian Hammer, Adam Dickmeiss
+ *
+ * $Log$
+ * Revision 1.1  2000/08/03 03:11:44  johnmcp
+ * Added the YAZ toolkit source to the packages directory (for z39.50 stuff)
+ *
+ * Revision 1.21  1999/11/30 13:47:12  adam
+ * Improved installation. Moved header files to include/yaz.
+ *
+ * Revision 1.20  1999/10/11 10:01:24  adam
+ * Implemented bend_sort_rr handler for frontend server.
+ *
+ * Revision 1.19  1999/04/20 09:56:48  adam
+ * Added 'name' paramter to encoder/decoder routines (typedef Odr_fun).
+ * Modified all encoders/decoders to reflect this change.
+ *
+ * Revision 1.18  1998/08/03 10:23:57  adam
+ * Fixed bug regarding Options for Sort.
+ *
+ * Revision 1.17  1998/07/20 12:38:43  adam
+ * Implemented delete result set service to server API.
+ *
+ * Revision 1.16  1998/03/31 11:07:45  adam
+ * Furhter work on UNIverse resource report.
+ * Added Extended Services handling in frontend server.
+ *
+ * Revision 1.15  1998/02/11 11:53:36  adam
+ * Changed code so that it compiles as C++.
+ *
+ * Revision 1.14  1998/02/10 11:03:57  adam
+ * Added support for extended handlers in backend server interface.
+ *
+ * Revision 1.13  1998/01/29 13:30:23  adam
+ * Better event handle system for NT/Unix.
+ *
+ * Revision 1.12  1997/09/01 08:53:01  adam
+ * New windows NT/95 port using MSV5.0. The test server 'ztest' was
+ * moved a separate directory. MSV5.0 project server.dsp created.
+ * As an option, the server can now operate as an NT service.
+ *
+ * Revision 1.11  1995/11/08 17:41:40  quinn
+ * Smallish.
+ *
+ * Revision 1.10  1995/08/29  11:18:01  quinn
+ * Added code to receive close
+ *
+ * Revision 1.9  1995/06/16  10:31:38  quinn
+ * Added session timeout.
+ *
+ * Revision 1.8  1995/05/17  08:42:28  quinn
+ * Transfer auth info to backend. Allow backend to reject init gracefully.
+ *
+ * Revision 1.7  1995/05/16  08:51:08  quinn
+ * License, documentation, and memory fixes
+ *
+ * Revision 1.6  1995/05/15  11:56:41  quinn
+ * Asynchronous facilities. Restructuring of seshigh code.
+ *
+ * Revision 1.5  1995/04/20  15:13:01  quinn
+ * Cosmetic
+ *
+ * Revision 1.4  1995/04/10  10:23:39  quinn
+ * Some work to add scan and other things.
+ *
+ * Revision 1.3  1995/03/30  09:09:27  quinn
+ * Added state-handle and some support for asynchronous activities.
+ *
+ * Revision 1.2  1995/03/27  08:34:29  quinn
+ * Added dynamic server functionality.
+ * Released bindings to session.c (is now redundant)
+ *
+ * Revision 1.1  1995/03/14  10:28:02  quinn
+ * More work on demo server.
+ *
+ *
+ */
+
+#ifndef SESSION_H
+#define SESSION_H
+
+#include <sys/types.h>
+#include <yaz/comstack.h>
+#include <yaz/odr.h>
+#include <yaz/oid.h>
+#include <yaz/proto.h>
+#include "eventl.h"
+
+typedef enum {
+   	REQUEST_IDLE,    /* the request is just sitting in the queue */
+	REQUEST_PENDING  /* operation pending (b'end processing or network I/O*/
+	/* this list will have more elements when acc/res control is added */
+} request_state;
+
+typedef struct request
+{
+    int len_refid;          /* length of referenceid */
+    char *refid;            /* referenceid */
+    request_state state;
+
+    Z_APDU *request;        /* Current request */
+    NMEM request_mem;    /* memory handle for request */
+
+    int size_response;     /* size of buffer */
+    int len_response;      /* length of encoded data */
+    char *response;        /* encoded data waiting for transmission */
+
+    void *clientData;
+    struct request *next;
+    struct request_q *q; 
+} request;
+
+typedef struct request_q
+{
+    request *head;
+    request *tail;
+    request *list;
+    int num;
+} request_q;
+
+/*
+ * association state.
+ */
+typedef enum
+{
+    ASSOC_NEW,                /* not initialized yet */
+    ASSOC_UP,                 /* normal operation */
+    ASSOC_DEAD                /* dead. Close if input arrives */
+} association_state;
+
+typedef struct association
+{
+    IOCHAN client_chan;           /* event-loop control */
+    COMSTACK client_link;         /* communication handle */
+    ODR decode;                   /* decoding stream */
+    ODR encode;                   /* encoding stream */
+    ODR print;                    /* printing stream (for -a) */
+    char *encode_buffer;          /* temporary buffer for encoded data */
+    int encoded_len;              /* length of encoded data */
+    char *input_buffer;           /* input buffer (allocated by comstack) */
+    int input_buffer_len;         /* length (size) of buffer */
+    int input_apdu_len;           /* length of current incoming APDU */
+    oid_proto proto;              /* protocol (PROTO_Z3950/PROTO_SR) */
+    void *backend;                /* backend handle */
+    request_q incoming;           /* Q of incoming PDUs */
+    request_q outgoing;           /* Q of outgoing data buffers (enc. PDUs) */
+    association_state state;
+
+    /* session parameters */
+    int preferredMessageSize;
+    int maximumRecordSize;
+    int version;                  /* highest version-bit set (2 or 3) */
+
+    int (*bend_sort) ();
+    int (*bend_search) ();
+    int (*bend_present) ();
+    int (*bend_esrequest) ();
+    int (*bend_delete) ();
+    int (*bend_scan) ();
+} association;
+
+association *create_association(IOCHAN channel, COMSTACK link);
+void destroy_association(association *h);
+void ir_session(IOCHAN h, int event);
+
+void request_enq(request_q *q, request *r);
+request *request_head(request_q *q);
+request *request_deq(request_q *q);
+request *request_deq_x(request_q *q, request *r);
+void request_initq(request_q *q);
+void request_delq(request_q *q);
+request *request_get(request_q *q);
+void request_release(request *r);
+
+#endif
Index: /main/tags/2.25/gsdl/packages/yaz/server/statserv.c
===================================================================
--- /main/tags/2.25/gsdl/packages/yaz/server/statserv.c	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/yaz/server/statserv.c	(revision 21064)
@@ -0,0 +1,1008 @@
+/*
+ * Copyright (c) 1995-1999, Index Data
+ * See the file LICENSE for details.
+ * Sebastian Hammer, Adam Dickmeiss
+ *
+ * NT server based on threads by
+ *   Chas Woodfield, Fretwell Downing Datasystems.
+ *
+ * $Log$
+ * Revision 1.1  2000/08/03 03:11:45  johnmcp
+ * Added the YAZ toolkit source to the packages directory (for z39.50 stuff)
+ *
+ * Revision 1.59  1999/11/30 13:47:12  adam
+ * Improved installation. Moved header files to include/yaz.
+ *
+ * Revision 1.58  1999/08/27 09:40:32  adam
+ * Renamed logf function to yaz_log. Removed VC++ project files.
+ *
+ * Revision 1.57  1999/07/06 12:17:15  adam
+ * Added option -1 that runs server once (for profiling purposes).
+ *
+ * Revision 1.56  1999/06/10 11:45:30  adam
+ * Added bend_start, bend_stop handlers and removed pre_init.
+ * Handlers bend_start/bend_stop are called when service/daemon is
+ * started/stopped.
+ *
+ * Revision 1.55  1999/06/10 09:18:54  adam
+ * Modified so that pre_init is called when service/server is started.
+ *
+ * Revision 1.54  1999/04/16 14:45:55  adam
+ * Added interface for tcpd wrapper for access control.
+ *
+ * Revision 1.53  1999/02/02 13:57:39  adam
+ * Uses preprocessor define WIN32 instead of WINDOWS to build code
+ * for Microsoft WIN32.
+ *
+ * Revision 1.52  1998/08/21 14:13:34  adam
+ * Added GNU Configure script to build Makefiles.
+ *
+ * Revision 1.51  1998/07/07 15:51:03  adam
+ * Changed server so that it stops if bind fails - "address already in
+ * use" typically causes this.
+ *
+ * Revision 1.50  1998/06/22 11:32:39  adam
+ * Added 'conditional cs_listen' feature.
+ *
+ * Revision 1.49  1998/02/27 14:04:55  adam
+ * Fixed bug in statserv_remove.
+ *
+ * Revision 1.48  1998/02/11 11:53:36  adam
+ * Changed code so that it compiles as C++.
+ *
+ * Revision 1.47  1998/02/10 10:28:57  adam
+ * Added app_name, service_dependencies, service_display_name and
+ * options_func. options_func allows us to specify a different function
+ * to interogate the command line arguments. The other members allow us
+ * to pass the full service details accross to the service manager (CW).
+ *
+ *
+ * Revision 1.46  1998/01/30 15:24:57  adam
+ * Fixed bug in inetd code. The server listened on tcp:@:9999 even
+ * though it was started in inetd mode.
+ *
+ * Revision 1.45  1998/01/29 13:30:23  adam
+ * Better event handle system for NT/Unix.
+ *
+ * Revision 1.44  1997/11/07 13:31:52  adam
+ * Added NT Service name part of statserv_options_block. Moved NT
+ * service utility to server library.
+ *
+ * Revision 1.43  1997/10/31 12:20:09  adam
+ * Improved memory debugging for xmalloc/nmem.c. References to NMEM
+ * instead of ODR in n ESPEC-1 handling in source d1_espec.c.
+ * Bug fix: missing fclose in data1_read_espec1.
+ *
+ * Revision 1.42  1997/10/27 14:03:02  adam
+ * Added new member to statserver_options_block, pre_init, which
+ * specifies a callback to be invoked after command line parsing and
+ * before the server listens for the first time.
+ *
+ * Revision 1.41  1997/09/29 07:19:32  adam
+ * Server library uses nmem_init/nmem_exit. The log prefix no longer
+ * includes leading path on NT.
+ *
+ * Revision 1.40  1997/09/17 12:10:41  adam
+ * YAZ version 1.4.
+ *
+ * Revision 1.39  1997/09/09 10:10:19  adam
+ * Another MSV5.0 port. Changed projects to include proper
+ * library/include paths.
+ * Server starts server in test-mode when no options are given.
+ *
+ * Revision 1.38  1997/09/04 14:19:14  adam
+ * Added credits.
+ *
+ * Revision 1.37  1997/09/01 08:53:01  adam
+ * New windows NT/95 port using MSV5.0. The test server 'ztest' was
+ * moved a separate directory. MSV5.0 project server.dsp created.
+ * As an option, the server can now operate as an NT service.
+ *
+ * Revision 1.36  1996/07/06 19:58:36  quinn
+ * System headerfiles gathered in yconfig
+ *
+ * Revision 1.35  1996/05/29  10:03:28  quinn
+ * Options work
+ *
+ * Revision 1.34  1996/02/21  13:12:07  quinn
+ * *** empty log message ***
+ *
+ * Revision 1.33  1996/02/10  12:23:49  quinn
+ * Enable inetd operations fro TCP/IP stack
+ *
+ * Revision 1.32  1996/01/19  15:41:52  quinn
+ * *** empty log message ***
+ *
+ * Revision 1.31  1995/11/17  11:09:39  adam
+ * Added new option '-c' to specify configuration name in control block.
+ *
+ * Revision 1.30  1995/11/01  13:54:59  quinn
+ * Minor adjustments
+ *
+ * Revision 1.29  1995/10/30  12:41:29  quinn
+ * Added hostname lookup for server.
+ *
+ * Revision 1.28  1995/09/29  17:12:30  quinn
+ * Smallish
+ *
+ * Revision 1.27  1995/09/27  15:03:02  quinn
+ * Modified function heads & prototypes.
+ *
+ * Revision 1.26  1995/08/29  14:44:51  quinn
+ * Reset timeouts.
+ *
+ * Revision 1.25  1995/08/29  11:18:02  quinn
+ * Added code to receive close
+ *
+ * Revision 1.24  1995/06/16  10:31:39  quinn
+ * Added session timeout.
+ *
+ * Revision 1.23  1995/06/15  12:30:48  quinn
+ * Setuid-facility.
+ *
+ * Revision 1.22  1995/06/15  07:45:17  quinn
+ * Moving to v3.
+ *
+ * Revision 1.21  1995/06/06  08:15:40  quinn
+ * Cosmetic.
+ *
+ * Revision 1.20  1995/05/29  08:12:09  quinn
+ * Moved oid to util
+ *
+ * Revision 1.19  1995/05/16  09:37:27  quinn
+ * Fixed bug
+ *
+ * Revision 1.18  1995/05/16  08:51:09  quinn
+ * License, documentation, and memory fixes
+ *
+ * Revision 1.17  1995/05/15  11:56:42  quinn
+ * Asynchronous facilities. Restructuring of seshigh code.
+ *
+ * Revision 1.16  1995/04/10  10:23:40  quinn
+ * Some work to add scan and other things.
+ *
+ * Revision 1.15  1995/03/31  10:16:51  quinn
+ * Fixed logging.
+ *
+ * Revision 1.14  1995/03/31  09:18:58  quinn
+ * Added logging.
+ *
+ * Revision 1.13  1995/03/30  16:08:39  quinn
+ * Little mods.
+ *
+ * Revision 1.12  1995/03/30  13:29:02  quinn
+ * Smallish
+ *
+ * Revision 1.11  1995/03/30  12:18:17  quinn
+ * Fixed bug.
+ *
+ * Revision 1.10  1995/03/29  15:40:16  quinn
+ * Ongoing work. Statserv is now dynamic by default
+ *
+ * Revision 1.9  1995/03/27  08:34:30  quinn
+ * Added dynamic server functionality.
+ * Released bindings to session.c (is now redundant)
+ *
+ * Revision 1.8  1995/03/20  09:46:26  quinn
+ * Added osi support.
+ *
+ * Revision 1.7  1995/03/16  13:29:04  quinn
+ * Partitioned server.
+ *
+ * Revision 1.6  1995/03/15  15:18:52  quinn
+ * Little changes to better support nonblocking I/O
+ * Added backend.h
+ *
+ * Revision 1.5  1995/03/15  08:37:45  quinn
+ * Now we're pretty much set for nonblocking I/O.
+ *
+ * Revision 1.4  1995/03/14  16:59:48  quinn
+ * Bug-fixes
+ *
+ * Revision 1.3  1995/03/14  11:30:15  quinn
+ * Works better now.
+ *
+ * Revision 1.2  1995/03/14  10:28:03  quinn
+ * More work on demo server.
+ *
+ * Revision 1.1  1995/03/10  18:22:45  quinn
+ * The rudiments of an asynchronous server.
+ *
+ */
+
+#include <stdio.h>
+#include <string.h>
+#ifdef WIN32
+#include <process.h>
+#include <winsock.h>
+#include <direct.h>
+#include "service.h"
+#else
+#include <unistd.h>
+#include <pwd.h>
+#endif
+#include <fcntl.h>
+#include <signal.h>
+#include <errno.h>
+
+#include <yaz/comstack.h>
+#include <yaz/tcpip.h>
+#include <yaz/options.h>
+#ifdef USE_XTIMOSI
+#include <yaz/xmosi.h>
+#endif
+#include <yaz/log.h>
+#include "eventl.h"
+#include "session.h"
+#include <yaz/statserv.h>
+
+static IOCHAN pListener = NULL;
+
+static char *me = "statserver";
+/*
+ * default behavior.
+ */
+int check_options(int argc, char **argv);
+statserv_options_block control_block = {
+    1,                          /* dynamic mode */
+    0,                          /* one shot (single session) */
+    LOG_DEFAULT_LEVEL,          /* log level */
+    "",                         /* no PDUs */
+    "",                         /* diagnostic output to stderr */
+    "tcp:@:9999",               /* default listener port */
+    PROTO_Z3950,                /* default application protocol */
+    60,                         /* idle timeout (minutes) */
+    1024*1024,                  /* maximum PDU size (approx.) to allow */
+    "default-config",           /* configuration name to pass to backend */
+    "",                         /* set user id */
+    0,                          /* bend_start handler */
+    0,                          /* bend_stop handler */
+    check_options,              /* Default routine, for checking the run-time arguments */
+    check_ip_tcpd,
+    "",
+    0                           /* default value for inet deamon */
+
+#ifdef WIN32
+    ,"Z39.50 Server",           /* NT Service Name */
+    "Server",                   /* NT application Name */
+    "",                         /* NT Service Dependencies */
+    "Z39.50 Server"             /* NT Service Display Name */
+#endif /* WIN32 */
+};
+
+/*
+ * handle incoming connect requests.
+ * The dynamic mode is a bit tricky mostly because we want to avoid
+ * doing all of the listening and accepting in the parent - it's
+ * safer that way.
+ */
+#ifdef WIN32
+
+typedef struct _ThreadList ThreadList;
+
+struct _ThreadList
+{
+    HANDLE hThread;
+    IOCHAN pIOChannel;
+    ThreadList *pNext;
+};
+
+static ThreadList *pFirstThread;
+static CRITICAL_SECTION Thread_CritSect;
+static BOOL bInitialized = FALSE;
+
+static void ThreadList_Initialize()
+{
+    /* Initialize the critical Sections */
+    InitializeCriticalSection(&Thread_CritSect);
+
+     /* Set the first thraed */
+    pFirstThread = NULL;
+
+    /* we have been initialized */
+    bInitialized = TRUE;
+}
+
+static void statserv_add(HANDLE hThread, IOCHAN pIOChannel)
+{
+    /* Only one thread can go through this section at a time */
+    EnterCriticalSection(&Thread_CritSect);
+
+    {
+        /* Lets create our new object */
+        ThreadList *pNewThread = (ThreadList *)malloc(sizeof(ThreadList));
+        pNewThread->hThread = hThread;
+        pNewThread->pIOChannel = pIOChannel;
+        pNewThread->pNext = pFirstThread;
+        pFirstThread = pNewThread;
+
+        /* Lets let somebody else create a new object now */
+        LeaveCriticalSection(&Thread_CritSect);
+    }
+}
+
+void statserv_remove(IOCHAN pIOChannel)
+{
+    /* Only one thread can go through this section at a time */
+    EnterCriticalSection(&Thread_CritSect);
+
+    {
+        ThreadList *pCurrentThread = pFirstThread;
+        ThreadList *pNextThread;
+        ThreadList *pPrevThread =NULL;
+
+        /* Step through alll the threads */
+        for (; pCurrentThread != NULL; pCurrentThread = pNextThread)
+        {
+            /* We only need to compare on the IO Channel */
+            if (pCurrentThread->pIOChannel == pIOChannel)
+            {
+                /* We have found the thread we want to delete */
+                /* First of all reset the next pointers */
+                if (pPrevThread == NULL)
+                    pFirstThread = pCurrentThread->pNext;
+                else
+                    pPrevThread->pNext = pCurrentThread->pNext;
+
+                /* All we need todo now is delete the memory */
+                free(pCurrentThread);
+
+                /* No need to look at any more threads */
+                pNextThread = NULL;
+            }
+            else
+            {
+                /* We need to look at another thread */
+                pNextThread = pCurrentThread->pNext;
+                pPrevThread = pCurrentThread;
+            }
+        }
+
+        /* Lets let somebody else remove an object now */
+        LeaveCriticalSection(&Thread_CritSect);
+    }
+}
+
+void statserv_closedown()
+{
+    /* Shouldn't do anything if we are not initialized */
+    if (bInitialized)
+    {
+        int iHandles = 0;
+        HANDLE *pThreadHandles = NULL;
+
+        /* We need to stop threads adding and removing while we */
+	/* start the closedown process */
+        EnterCriticalSection(&Thread_CritSect);
+
+        {
+            /* We have exclusive access to the thread stuff now */
+            /* Y didn't i use a semaphore - Oh well never mind */
+            ThreadList *pCurrentThread = pFirstThread;
+
+            /* Before we do anything else, we need to shutdown the listener */
+            if (pListener != NULL)
+                iochan_destroy(pListener);
+
+            for (; pCurrentThread != NULL; pCurrentThread = pCurrentThread->pNext)
+            {
+                /* Just destroy the IOCHAN, that should do the trick */
+                iochan_destroy(pCurrentThread->pIOChannel);
+
+                /* Keep a running count of our handles */
+                iHandles++;
+            }
+
+            if (iHandles > 0)
+            {
+                HANDLE *pCurrentHandle ;
+
+                /* Allocate the thread handle array */
+                pThreadHandles = (HANDLE *)malloc(sizeof(HANDLE) * iHandles);
+                pCurrentHandle = pThreadHandles; 
+
+                for (pCurrentThread = pFirstThread;
+                     pCurrentThread != NULL;
+                     pCurrentThread = pCurrentThread->pNext, pCurrentHandle++)
+                {
+                    /* Just the handle */
+                    *pCurrentHandle = pCurrentThread->hThread;
+                }
+            }
+
+            /* We can now leave the critical section */
+            LeaveCriticalSection(&Thread_CritSect);
+        }
+
+        /* Now we can really do something */
+        if (iHandles > 0)
+        {
+            /* This will now wait, until all the threads close */
+            WaitForMultipleObjects(iHandles, pThreadHandles, TRUE, INFINITE);
+
+            /* Free the memory we allocated for the handle array */
+            free(pThreadHandles);
+        }
+
+	if (control_block.bend_stop)
+	    (*control_block.bend_stop)(&control_block);
+        /* No longer require the critical section, since all threads are dead */
+        DeleteCriticalSection(&Thread_CritSect);
+    }
+}
+
+int __stdcall event_loop_thread (IOCHAN iochan)
+{
+    return event_loop (&iochan);
+}
+
+static void listener(IOCHAN h, int event)
+{
+    COMSTACK line = (COMSTACK) iochan_getdata(h);
+    association *newas;
+    int res;
+    HANDLE NewHandle;
+
+    if (event == EVENT_INPUT)
+    {
+        if ((res = cs_listen(line, 0, 0)) < 0)
+        {
+	    yaz_log(LOG_FATAL, "cs_listen failed");
+    	    return;
+        }
+        else if (res == 1)
+            return;
+        yaz_log(LOG_DEBUG, "listen ok");
+        iochan_setevent(h, EVENT_OUTPUT);
+        iochan_setflags(h, EVENT_OUTPUT | EVENT_EXCEPT); /* set up for acpt */
+    }
+    else if (event == EVENT_OUTPUT)
+    {
+    	COMSTACK new_line;
+    	IOCHAN new_chan;
+	char *a = NULL;
+        DWORD ThreadId;
+
+	if (!(new_line = cs_accept(line)))
+	{
+	    yaz_log(LOG_FATAL, "Accept failed.");
+	    iochan_setflags(h, EVENT_INPUT | EVENT_EXCEPT); /* reset listener */
+	    return;
+	}
+	yaz_log(LOG_DEBUG, "Accept ok");
+
+	if (!(new_chan = iochan_create(cs_fileno(new_line), ir_session,
+				       EVENT_INPUT)))
+	{
+	    yaz_log(LOG_FATAL, "Failed to create iochan");
+            iochan_destroy(h);
+            return;
+	}
+
+	yaz_log(LOG_DEBUG, "Creating association");
+	if (!(newas = create_association(new_chan, new_line)))
+	{
+	    yaz_log(LOG_FATAL, "Failed to create new assoc.");
+            iochan_destroy(h);
+            return;
+	}
+	yaz_log(LOG_DEBUG, "Setting timeout %d", control_block.idle_timeout);
+	iochan_setdata(new_chan, newas);
+	iochan_settimeout(new_chan, control_block.idle_timeout * 60);
+#ifndef WIN32
+	yaz_log(LOG_DEBUG, "Determining client address");
+	a = cs_addrstr(new_line);
+	yaz_log(LOG_LOG, "Accepted connection from %s", a ? a : "[Unknown]");
+#endif
+	/* Now what we need todo is create a new thread with this iochan as
+	   the parameter */
+	/* if (CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)event_loop_thread,
+	   new_chan, 0, &ThreadId) == NULL) */
+	/* Somehow, somewhere we need to store this thread id, otherwise we
+	   won't be able to close cleanly */
+        NewHandle = (HANDLE)_beginthreadex(NULL, 0, event_loop_thread,
+					   new_chan, 0, &ThreadId);
+        if (NewHandle == (HANDLE)-1)
+	{
+	    
+	    yaz_log(LOG_FATAL|LOG_ERRNO, "Failed to create new thread.");
+            iochan_destroy(h);
+            return;
+	}
+        /* We successfully created the thread, so add it to the list */
+        statserv_add(NewHandle, new_chan);
+
+        yaz_log(LOG_DEBUG, "Created new thread, iochan %p", new_chan);
+        iochan_setflags(h, EVENT_INPUT | EVENT_EXCEPT); /* reset listener */
+    }
+    else
+    {
+    	yaz_log(LOG_FATAL, "Bad event on listener.");
+        iochan_destroy(h);
+        return;
+    }
+}
+
+#else /* WIN32 */
+
+/* To save having an #ifdef in event_loop we need to define this empty function */
+void statserv_remove(IOCHAN pIOChannel)
+{
+}
+
+void statserv_closedown()
+{
+    IOCHAN p;
+    for (p = pListener; p; p = p->next)
+        iochan_destroy(p);
+}
+
+static void listener(IOCHAN h, int event)
+{
+    COMSTACK line = (COMSTACK) iochan_getdata(h);
+    association *newas;
+    static int hand[2];
+    static int child = 0;
+    int res;
+
+    if (event == EVENT_INPUT)
+    {
+	if (control_block.dynamic && !child) 
+	{
+	    int res;
+
+	    if (pipe(hand) < 0)
+	    {
+		yaz_log(LOG_FATAL|LOG_ERRNO, "pipe");
+                iochan_destroy(h);
+                return;
+	    }
+	    if ((res = fork()) < 0)
+	    {
+		yaz_log(LOG_FATAL|LOG_ERRNO, "fork");
+                iochan_destroy(h);
+                return;
+	    }
+	    else if (res == 0) /* child */
+	    {
+	    	char nbuf[100];
+		IOCHAN pp;
+
+		close(hand[0]);
+		child = 1;
+		for (pp = pListener; pp; pp = iochan_getnext(pp))
+		{
+		    if (pp != h)
+		    {
+			COMSTACK l = (COMSTACK)iochan_getdata(pp);
+			cs_close(l);
+			iochan_destroy(pp);
+		    }
+		}
+		sprintf(nbuf, "%s(%d)", me, getpid());
+		log_init(control_block.loglevel, nbuf, 0);
+	    }
+	    else /* parent */
+	    {
+		close(hand[1]);
+		/* wait for child to take the call */
+		for (;;)
+		{
+		    char dummy[1];
+		    int res;
+		    
+		    if ((res = read(hand[0], dummy, 1)) < 0 && errno != EINTR)
+		    {
+			yaz_log(LOG_FATAL|LOG_ERRNO, "handshake read");
+                        return;
+		    }
+		    else if (res >= 0)
+		    	break;
+		}
+		yaz_log(LOG_DEBUG, "P: Child has taken the call");
+		close(hand[0]);
+		return;
+	    }
+	}
+	if ((res = cs_listen_check(line, 0, 0, control_block.check_ip,
+				   control_block.daemon_name)) < 0)
+	{
+	    yaz_log(LOG_WARN, "cs_listen failed");
+	    return;
+	}
+	else if (res == 1)
+	    return;
+	yaz_log(LOG_DEBUG, "listen ok");
+	iochan_setevent(h, EVENT_OUTPUT);
+	iochan_setflags(h, EVENT_OUTPUT | EVENT_EXCEPT); /* set up for acpt */
+    }
+    /* in dynamic mode, only the child ever comes down here */
+    else if (event == EVENT_OUTPUT)
+    {
+    	COMSTACK new_line;
+    	IOCHAN new_chan;
+	char *a;
+
+	if (!(new_line = cs_accept(line)))
+	{
+	    yaz_log(LOG_FATAL, "Accept failed.");
+	    iochan_setflags(h, EVENT_INPUT | EVENT_EXCEPT); /* reset listener */
+	    return;
+	}
+	yaz_log(LOG_DEBUG, "accept ok");
+	if (control_block.dynamic)
+	{
+	    IOCHAN pp;
+	    /* close our half of the listener socket */
+	    for (pp = pListener; pp; pp = iochan_getnext(pp))
+	    {
+		COMSTACK l = (COMSTACK)iochan_getdata(pp);
+		cs_close(l);
+		iochan_destroy(pp);
+	    }
+	    /* release dad */
+	    yaz_log(LOG_DEBUG, "Releasing parent");
+	    close(hand[1]);
+	}
+	else
+	    iochan_setflags(h, EVENT_INPUT | EVENT_EXCEPT); /* reset listener */
+	
+	if (!(new_chan = iochan_create(cs_fileno(new_line), ir_session,
+	    EVENT_INPUT)))
+	{
+	    yaz_log(LOG_FATAL, "Failed to create iochan");
+            iochan_destroy(h);
+            return;
+	}
+        new_chan->next = pListener;
+        pListener = new_chan;
+	if (!(newas = create_association(new_chan, new_line)))
+	{
+	    yaz_log(LOG_FATAL, "Failed to create new assoc.");
+            iochan_destroy(h);
+            return;
+	}
+	iochan_setdata(new_chan, newas);
+	iochan_settimeout(new_chan, control_block.idle_timeout * 60);
+	a = cs_addrstr(new_line);
+	yaz_log(LOG_LOG, "Accepted connection from %s", a ? a : "[Unknown]");
+    }
+    else
+    {
+    	yaz_log(LOG_FATAL, "Bad event on listener.");
+        iochan_destroy(h);
+        return;
+    }
+}
+
+#endif /* WIN32 */
+
+static void inetd_connection(int what)
+{
+    COMSTACK line;
+    IOCHAN chan;
+    association *assoc;
+    char *addr;
+
+    if ((line = cs_createbysocket(0, tcpip_type, 0, what)))
+    {
+        if ((chan = iochan_create(cs_fileno(line), ir_session, EVENT_INPUT)))
+        {
+            if ((assoc = create_association(chan, line)))
+            {
+                iochan_setdata(chan, assoc);
+                iochan_settimeout(chan, control_block.idle_timeout * 60);
+                addr = cs_addrstr(line);
+                yaz_log(LOG_LOG, "Inetd association from %s", addr ? addr : "[UNKNOWN]");
+            }
+            else
+            {
+	        yaz_log(LOG_FATAL, "Failed to create association structure");
+            }
+            chan->next = pListener;
+            pListener = chan;
+        }
+        else
+        {
+            yaz_log(LOG_FATAL, "Failed to create iochan");
+        }
+    }
+    else
+    {
+	yaz_log(LOG_ERRNO|LOG_FATAL, "Failed to create comstack on socket 0");
+    }
+}
+
+/*
+ * Set up a listening endpoint, and give it to the event-handler.
+ */
+static void add_listener(char *where, int what)
+{
+    COMSTACK l;
+    CS_TYPE type;
+    char mode[100], addr[100];
+    void *ap;
+    IOCHAN lst = NULL;
+
+    if (!where || sscanf(where, "%[^:]:%s", mode, addr) != 2)
+    {
+	yaz_log (LOG_WARN, "%s: Address format: ('tcp'|'osi')':'<address>", me);
+	return;
+    }
+    if (!strcmp(mode, "tcp"))
+	type = tcpip_type;
+    else if (!strcmp(mode, "osi"))
+    {
+#ifdef USE_XTIMOSI
+	type = mosi_type;
+#else
+	yaz_log (LOG_WARN, "OSI Transport not allowed by configuration.");
+	return;
+#endif
+    }
+    else
+    {
+    	yaz_log (LOG_WARN, "You must specify either 'osi:' or 'tcp:'");
+	return;
+    }
+    yaz_log(LOG_LOG, "Adding %s %s listener on %s",
+        control_block.dynamic ? "dynamic" : "static",
+    	what == PROTO_SR ? "SR" : "Z3950", where);
+    if (!(l = cs_create(type, 0, what)))
+    {
+    	yaz_log(LOG_FATAL|LOG_ERRNO, "Failed to create listener");
+	return;
+    }
+    ap = cs_straddr (l, addr);
+    if (!ap)
+    {
+	fprintf(stderr, "Address resolution failed.\n");
+	cs_close (l);
+	return;
+    }
+    if (cs_bind(l, ap, CS_SERVER) < 0)
+    {
+    	yaz_log(LOG_FATAL|LOG_ERRNO, "Failed to bind to %s", where);
+	cs_close (l);
+	return;
+    }
+    if (!(lst = iochan_create(cs_fileno(l), listener, EVENT_INPUT |
+   	 EVENT_EXCEPT)))
+    {
+    	yaz_log(LOG_FATAL|LOG_ERRNO, "Failed to create IOCHAN-type");
+	cs_close (l);
+	return;
+    }
+    iochan_setdata(lst, l);
+
+    /* Ensure our listener chain is setup properly */
+    lst->next = pListener;
+    pListener = lst;
+}
+
+#ifndef WIN32
+/* For windows we don't need to catch the signals */
+static void catchchld(int num)
+{
+    while (waitpid(-1, 0, WNOHANG) > 0)
+	;
+    signal(SIGCHLD, catchchld);
+}
+#endif /* WIN32 */
+
+statserv_options_block *statserv_getcontrol(void)
+{
+    static statserv_options_block cb;
+
+    memcpy(&cb, &control_block, sizeof(cb));
+    return &cb;
+}
+
+void statserv_setcontrol(statserv_options_block *block)
+{
+    memcpy(&control_block, block, sizeof(*block));
+}
+
+int statserv_start(int argc, char **argv)
+{
+    int ret;
+
+    nmem_init ();
+#ifdef WIN32
+    /* We need to initialize the thread list */
+    ThreadList_Initialize();
+#endif /* WIN32 */
+
+#ifdef WIN32
+    if ((me = strrchr (argv[0], '\\')))
+	me++;
+    else
+	me = argv[0];
+#else
+    me = argv[0];
+#endif
+    if (control_block.options_func(argc, argv))
+        return(1);
+
+    if (control_block.bend_start)
+        (*control_block.bend_start)(&control_block);
+#ifndef WIN32
+    if (control_block.inetd)
+	inetd_connection(control_block.default_proto);
+    else
+    {
+	if (control_block.dynamic)
+	    signal(SIGCHLD, catchchld);
+    }
+    if (*control_block.setuid)
+    {
+    	struct passwd *pw;
+	
+	if (!(pw = getpwnam(control_block.setuid)))
+	{
+	    yaz_log(LOG_FATAL, "%s: Unknown user", control_block.setuid);
+	    return(1);
+	}
+	if (setuid(pw->pw_uid) < 0)
+	{
+	    yaz_log(LOG_FATAL|LOG_ERRNO, "setuid");
+	    exit(1);
+	}
+    }
+#endif /* WIN32 */
+
+    if ((pListener == NULL) && *control_block.default_listen)
+	add_listener(control_block.default_listen,
+		     control_block.default_proto);
+	
+    if (pListener == NULL)
+	ret = 1;
+    else
+    {
+	yaz_log(LOG_LOG, "Entering event loop.");
+        ret = event_loop(&pListener);
+    }
+    nmem_exit ();
+    return ret;
+}
+
+int check_options(int argc, char **argv)
+{
+    int ret = 0, r;
+    char *arg;
+
+    while ((ret = options("1a:iszSl:v:u:c:w:t:k:d:", argv, argc, &arg)) != -2)
+    {
+    	switch (ret)
+    	{
+	case 0:
+	    add_listener(arg, control_block.default_proto);
+	    break;
+	case '1':	 
+	    control_block.one_shot = 1;
+	    control_block.dynamic = 0;
+	    break;
+	case 'z':
+	    control_block.default_proto = PROTO_Z3950;
+	    break;
+	case 's':
+	    control_block.default_proto = PROTO_SR;
+	    break;
+	case 'S':
+	    control_block.dynamic = 0;
+	    break;
+	case 'l':
+	    strcpy(control_block.logfile, arg ? arg : "");
+	    log_init(control_block.loglevel, me, control_block.logfile);
+	    break;
+	case 'v':
+	    control_block.loglevel = log_mask_str(arg);
+	    log_init(control_block.loglevel, me, control_block.logfile);
+	    break;
+	case 'a':
+	    strcpy(control_block.apdufile, arg ? arg : "");
+	    break;
+	case 'u':
+	    strcpy(control_block.setuid, arg ? arg : "");
+	    break;
+	case 'c':
+	    strcpy(control_block.configname, arg ? arg : "");
+	    break;
+	case 'd':
+	    strcpy(control_block.daemon_name, arg ? arg : "");
+	    break;
+	case 't':
+	    if (!arg || !(r = atoi(arg)))
+	    {
+		fprintf(stderr, "%s: Specify positive timeout for -t.\n", me);
+		return(1);
+	    }
+	    control_block.idle_timeout = r;
+	    break;
+	case  'k':
+	    if (!arg || !(r = atoi(arg)))
+	    {
+		fprintf(stderr, "%s: Specify positive size for -k.\n", me);
+		return(1);
+	    }
+	    control_block.maxrecordsize = r * 1024;
+	    break;
+	case 'i':
+	    control_block.inetd = 1;
+	    break;
+	case 'w':
+	    if (chdir(arg))
+	    {
+		perror(arg);		
+		return(1);
+	    }
+	    break;
+	default:
+	    fprintf(stderr, "Usage: %s [ -i -a <pdufile> -v <loglevel>"
+		    " -l <logfile> -u <user> -c <config> -t <minutes>"
+		    " -k <kilobytes> -d <daemon>"
+                        " -zsS <listener-addr> -w <directory> ... ]\n", me);
+	    return(1);
+        }
+    }
+    return 0;
+}
+
+#ifdef WIN32
+typedef struct _Args
+{
+    char **argv;
+    int argc;
+} Args; 
+
+static Args ArgDetails;
+
+/* name of the executable */
+#define SZAPPNAME            "server"
+
+/* list of service dependencies - "dep1\0dep2\0\0" */
+#define SZDEPENDENCIES       ""
+
+int statserv_main(int argc, char **argv)
+{
+    statserv_options_block *cb = statserv_getcontrol();
+    
+    /* Lets setup the Arg structure */
+    ArgDetails.argc = argc;
+    ArgDetails.argv = argv;
+    
+    /* Now setup the service with the service controller */
+    SetupService(argc, argv, &ArgDetails, SZAPPNAME,
+		 cb->service_name, /* internal service name */
+		 cb->service_name, /* displayed name of the service */
+		 SZDEPENDENCIES);
+    return 0;
+}
+
+int StartAppService(void *pHandle, int argc, char **argv)
+{
+    /* Initializes the App */
+    return 1;
+}
+
+void RunAppService(void *pHandle)
+{
+    Args *pArgs = (Args *)pHandle;
+    
+    /* Starts the app running */
+    statserv_start(pArgs->argc, pArgs->argv);
+}
+
+void StopAppService(void *pHandle)
+{
+    /* Stops the app */
+    statserv_closedown();
+}
+#else
+int statserv_main(int argc, char **argv)
+{
+    int ret = statserv_start (argc, argv);
+    statserv_closedown ();
+    return ret;
+}
+#endif
Index: /main/tags/2.25/gsdl/packages/yaz/server/tcpdchk.c
===================================================================
--- /main/tags/2.25/gsdl/packages/yaz/server/tcpdchk.c	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/yaz/server/tcpdchk.c	(revision 21064)
@@ -0,0 +1,100 @@
+/*
+ * Copyright (c) 1995-2000, Index Data
+ * See the file LICENSE for details.
+ * Sebastian Hammer, Adam Dickmeiss
+ *
+ * $Log$
+ * Revision 1.1  2000/08/03 03:11:46  johnmcp
+ * Added the YAZ toolkit source to the packages directory (for z39.50 stuff)
+ *
+ * Revision 1.5  2000/02/28 11:20:06  adam
+ * Using autoconf. New definitions: YAZ_BEGIN_CDECL/YAZ_END_CDECL.
+ *
+ * Revision 1.4  1999/11/30 13:47:12  adam
+ * Improved installation. Moved header files to include/yaz.
+ *
+ * Revision 1.3  1999/08/27 09:40:32  adam
+ * Renamed logf function to yaz_log. Removed VC++ project files.
+ *
+ * Revision 1.2  1999/04/20 09:56:48  adam
+ * Added 'name' paramter to encoder/decoder routines (typedef Odr_fun).
+ * Modified all encoders/decoders to reflect this change.
+ *
+ * Revision 1.1  1999/04/16 14:45:55  adam
+ * Added interface for tcpd wrapper for access control.
+ *
+ */
+
+#include <stdio.h>
+#include <string.h>
+
+#include <yaz/yconfig.h>
+#include <yaz/comstack.h>
+
+#if HAVE_TCPD_H
+#include <syslog.h>
+#include <tcpd.h>
+
+
+int allow_severity = LOG_INFO;
+int deny_severity = LOG_WARNING;
+
+#ifdef LOG_DEBUG
+#undef LOG_DEBUG
+#endif
+#ifdef LOG_WARN
+#undef LOG_WARN
+#endif
+
+#endif
+
+#include <yaz/statserv.h>
+#include <yaz/log.h>
+
+int check_ip_tcpd(void *cd, const char *addr, int len, int type)
+{
+    const char *daemon_name = (const char *) cd;
+
+    if (type == AF_INET)
+    {
+	if (daemon_name && *daemon_name)
+	{
+#if HAVE_TCPD_H
+	    struct request_info request_info;
+	    int i;
+#endif
+	    char *host_name = 0, *host_addr = 0;
+	    struct hostent *host;
+
+	    struct sockaddr_in *addr_in = (struct sockaddr_in *) addr;
+	    
+	    if ((host = gethostbyaddr((char*)&addr_in->sin_addr,
+				      sizeof(addr_in->sin_addr),
+				      AF_INET)))
+		host_name = (char*) host->h_name;
+	    host_addr = inet_ntoa(addr_in->sin_addr);
+#if HAVE_TCPD_H
+	    if (host_addr)
+		request_init(&request_info, RQ_DAEMON, daemon_name,
+			     RQ_CLIENT_NAME, host_name,
+			     RQ_CLIENT_SIN, addr_in,
+			     RQ_CLIENT_ADDR, host_addr, 0);
+	    else
+		request_init(&request_info, RQ_DAEMON, daemon_name,
+			     RQ_CLIENT_SIN, addr_in,
+			     RQ_CLIENT_ADDR, host_addr, 0);
+	    i = hosts_access(&request_info);
+	    if (!i)
+	    {
+		yaz_log (LOG_DEBUG, "access denied from %s",
+			 host_name ? host_name : host_addr);
+		return 1;
+	    }
+	    yaz_log (LOG_DEBUG, "access granted from %s",
+		     host_name ? host_name : host_addr);
+#endif
+	}
+    }
+    return 0;
+}
+
Index: /main/tags/2.25/gsdl/packages/yaz/tab/Makefile.am
===================================================================
--- /main/tags/2.25/gsdl/packages/yaz/tab/Makefile.am	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/yaz/tab/Makefile.am	(revision 21064)
@@ -0,0 +1,16 @@
+## $Id$
+
+tabdatadir = $(pkgdatadir)/tab
+tabdata_DATA = bib1.att dan1.att danmarc.abs explain.abs explain.att \
+ explain.tag generic.tag gils-a.est gils-b.est gils-f.est gils-g.est \
+ gils-summary.map gils-usmarc.map gils-variant.est gils.abs gils.att \
+ gils.tag meta-b.est meta-usmarc.map meta.abs meta.tag summary.abs \
+ summary.tag tagsetg.tag tagsetm.tag usmarc-b.est usmarc.abs usmarc.mar \
+ usmarc.tag var1.var wais-b.est wais-variant.est wais.abs 
+
+EXTRA_DIST = bib1.att dan1.att danmarc.abs explain.abs explain.att \
+ explain.tag generic.tag gils-a.est gils-b.est gils-f.est gils-g.est \
+ gils-summary.map gils-usmarc.map gils-variant.est gils.abs gils.att \
+ gils.tag meta-b.est meta-usmarc.map meta.abs meta.tag summary.abs \
+ summary.tag tagsetg.tag tagsetm.tag usmarc-b.est usmarc.abs usmarc.mar \
+ usmarc.tag var1.var wais-b.est wais-variant.est wais.abs 
Index: /main/tags/2.25/gsdl/packages/yaz/tab/Makefile.in
===================================================================
--- /main/tags/2.25/gsdl/packages/yaz/tab/Makefile.in	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/yaz/tab/Makefile.in	(revision 21064)
@@ -0,0 +1,202 @@
+# Makefile.in generated automatically by automake 1.4 from Makefile.am
+
+# Copyright (C) 1994, 1995-8, 1999 Free Software Foundation, Inc.
+# This Makefile.in is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
+# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE.
+
+
+SHELL = @SHELL@
+
+srcdir = @srcdir@
+top_srcdir = @top_srcdir@
+VPATH = @srcdir@
+prefix = @prefix@
+exec_prefix = @exec_prefix@
+
+bindir = @bindir@
+sbindir = @sbindir@
+libexecdir = @libexecdir@
+datadir = @datadir@
+sysconfdir = @sysconfdir@
+sharedstatedir = @sharedstatedir@
+localstatedir = @localstatedir@
+libdir = @libdir@
+infodir = @infodir@
+mandir = @mandir@
+includedir = @includedir@
+oldincludedir = /usr/include
+
+DESTDIR =
+
+pkgdatadir = $(datadir)/@PACKAGE@
+pkglibdir = $(libdir)/@PACKAGE@
+pkgincludedir = $(includedir)/@PACKAGE@
+
+top_builddir = ..
+
+ACLOCAL = @ACLOCAL@
+AUTOCONF = @AUTOCONF@
+AUTOMAKE = @AUTOMAKE@
+AUTOHEADER = @AUTOHEADER@
+
+INSTALL = @INSTALL@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@ $(AM_INSTALL_PROGRAM_FLAGS)
+INSTALL_DATA = @INSTALL_DATA@
+INSTALL_SCRIPT = @INSTALL_SCRIPT@
+transform = @program_transform_name@
+
+NORMAL_INSTALL = :
+PRE_INSTALL = :
+POST_INSTALL = :
+NORMAL_UNINSTALL = :
+PRE_UNINSTALL = :
+POST_UNINSTALL = :
+ASNMODULE = @ASNMODULE@
+CC = @CC@
+CPP = @CPP@
+ILLLIB = @ILLLIB@
+ILLMODULE = @ILLMODULE@
+MAKEINFO = @MAKEINFO@
+PACKAGE = @PACKAGE@
+RANLIB = @RANLIB@
+SUBDIRS_VAR = @SUBDIRS_VAR@
+VERSION = @VERSION@
+have_sgml2html = @have_sgml2html@
+have_sgml2latex = @have_sgml2latex@
+have_sgml2txt = @have_sgml2txt@
+
+tabdatadir = $(pkgdatadir)/tab
+tabdata_DATA = bib1.att dan1.att danmarc.abs explain.abs explain.att  explain.tag generic.tag gils-a.est gils-b.est gils-f.est gils-g.est  gils-summary.map gils-usmarc.map gils-variant.est gils.abs gils.att  gils.tag meta-b.est meta-usmarc.map meta.abs meta.tag summary.abs  summary.tag tagsetg.tag tagsetm.tag usmarc-b.est usmarc.abs usmarc.mar  usmarc.tag var1.var wais-b.est wais-variant.est wais.abs 
+
+
+EXTRA_DIST = bib1.att dan1.att danmarc.abs explain.abs explain.att  explain.tag generic.tag gils-a.est gils-b.est gils-f.est gils-g.est  gils-summary.map gils-usmarc.map gils-variant.est gils.abs gils.att  gils.tag meta-b.est meta-usmarc.map meta.abs meta.tag summary.abs  summary.tag tagsetg.tag tagsetm.tag usmarc-b.est usmarc.abs usmarc.mar  usmarc.tag var1.var wais-b.est wais-variant.est wais.abs 
+
+mkinstalldirs = $(SHELL) $(top_srcdir)/mkinstalldirs
+CONFIG_CLEAN_FILES = 
+DATA =  $(tabdata_DATA)
+
+DIST_COMMON =  Makefile.am Makefile.in
+
+
+DISTFILES = $(DIST_COMMON) $(SOURCES) $(HEADERS) $(TEXINFOS) $(EXTRA_DIST)
+
+TAR = gtar
+GZIP_ENV = --best
+all: all-redirect
+.SUFFIXES:
+$(srcdir)/Makefile.in: Makefile.am $(top_srcdir)/configure.in $(ACLOCAL_M4) 
+	cd $(top_srcdir) && $(AUTOMAKE) --gnu --include-deps tab/Makefile
+
+Makefile: $(srcdir)/Makefile.in  $(top_builddir)/config.status
+	cd $(top_builddir) \
+	  && CONFIG_FILES=$(subdir)/$@ CONFIG_HEADERS= $(SHELL) ./config.status
+
+
+install-tabdataDATA: $(tabdata_DATA)
+	@$(NORMAL_INSTALL)
+	$(mkinstalldirs) $(DESTDIR)$(tabdatadir)
+	@list='$(tabdata_DATA)'; for p in $$list; do \
+	  if test -f $(srcdir)/$$p; then \
+	    echo " $(INSTALL_DATA) $(srcdir)/$$p $(DESTDIR)$(tabdatadir)/$$p"; \
+	    $(INSTALL_DATA) $(srcdir)/$$p $(DESTDIR)$(tabdatadir)/$$p; \
+	  else if test -f $$p; then \
+	    echo " $(INSTALL_DATA) $$p $(DESTDIR)$(tabdatadir)/$$p"; \
+	    $(INSTALL_DATA) $$p $(DESTDIR)$(tabdatadir)/$$p; \
+	  fi; fi; \
+	done
+
+uninstall-tabdataDATA:
+	@$(NORMAL_UNINSTALL)
+	list='$(tabdata_DATA)'; for p in $$list; do \
+	  rm -f $(DESTDIR)$(tabdatadir)/$$p; \
+	done
+tags: TAGS
+TAGS:
+
+
+distdir = $(top_builddir)/$(PACKAGE)-$(VERSION)/$(subdir)
+
+subdir = tab
+
+distdir: $(DISTFILES)
+	@for file in $(DISTFILES); do \
+	  d=$(srcdir); \
+	  if test -d $$d/$$file; then \
+	    cp -pr $$/$$file $(distdir)/$$file; \
+	  else \
+	    test -f $(distdir)/$$file \
+	    || ln $$d/$$file $(distdir)/$$file 2> /dev/null \
+	    || cp -p $$d/$$file $(distdir)/$$file || :; \
+	  fi; \
+	done
+info-am:
+info: info-am
+dvi-am:
+dvi: dvi-am
+check-am: all-am
+check: check-am
+installcheck-am:
+installcheck: installcheck-am
+install-exec-am:
+install-exec: install-exec-am
+
+install-data-am: install-tabdataDATA
+install-data: install-data-am
+
+install-am: all-am
+	@$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
+install: install-am
+uninstall-am: uninstall-tabdataDATA
+uninstall: uninstall-am
+all-am: Makefile $(DATA)
+all-redirect: all-am
+install-strip:
+	$(MAKE) $(AM_MAKEFLAGS) AM_INSTALL_PROGRAM_FLAGS=-s install
+installdirs:
+	$(mkinstalldirs)  $(DESTDIR)$(tabdatadir)
+
+
+mostlyclean-generic:
+
+clean-generic:
+
+distclean-generic:
+	-rm -f Makefile $(CONFIG_CLEAN_FILES)
+	-rm -f config.cache config.log stamp-h stamp-h[0-9]*
+
+maintainer-clean-generic:
+mostlyclean-am:  mostlyclean-generic
+
+mostlyclean: mostlyclean-am
+
+clean-am:  clean-generic mostlyclean-am
+
+clean: clean-am
+
+distclean-am:  distclean-generic clean-am
+
+distclean: distclean-am
+
+maintainer-clean-am:  maintainer-clean-generic distclean-am
+	@echo "This command is intended for maintainers to use;"
+	@echo "it deletes files that may require special tools to rebuild."
+
+maintainer-clean: maintainer-clean-am
+
+.PHONY: uninstall-tabdataDATA install-tabdataDATA tags distdir info-am \
+info dvi-am dvi check check-am installcheck-am installcheck \
+install-exec-am install-exec install-data-am install-data install-am \
+install uninstall-am uninstall all-redirect all-am all installdirs \
+mostlyclean-generic distclean-generic clean-generic \
+maintainer-clean-generic clean mostlyclean distclean maintainer-clean
+
+
+# Tell versions [3.59,3.63) of GNU make to not export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:
Index: /main/tags/2.25/gsdl/packages/yaz/tab/bib1.att
===================================================================
--- /main/tags/2.25/gsdl/packages/yaz/tab/bib1.att	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/yaz/tab/bib1.att	(revision 21064)
@@ -0,0 +1,104 @@
+# $Id$
+# Bib-1 Attribute Set
+name bib1
+reference Bib-1
+
+att 1               Personal-name
+att 2               Corporate-name
+att 3               Conference-name
+att 4               Title
+att 5               Title-series
+att 6               Title-uniform
+att 7               ISBN
+att 8               ISSN
+att 9               LC-card-number
+att 10              BNB-card-number
+att 11              BGF-number
+att 12              Local-number
+att 13              Dewey-classification
+att 14              UDC-classification
+att 15              Bliss-classification
+att 16              LC-call-number
+att 17              NLM-call-number
+att 18              NAL-call-number
+att 19              MOS-call-number
+att 20              Local-classification
+att 21              Subject-heading
+att 22              Subject-Rameau
+att 23              BDI-index-subject
+att 24              INSPEC-subject
+att 25              MESH-subject
+att 26              PA-subject
+att 27              LC-subject-heading
+att 28              RVM-subject-heading
+att 29              Local-subject-index
+att 30              Date
+att 31              Date-of-publication
+att 32              Date-of-acquisition
+att 33              Title-key
+att 34              Title-collective
+att 35              Title-parallel
+att 36              Title-cover
+att 37              Title-added-title-page
+att 38              Title-caption
+att 39              Title-running
+att 40              Title-spine
+att 41              Title-other-variant
+att 42              Title-former
+att 43              Title-abbreviated
+att 44              Title-expanded
+att 45              Subject-precis
+att 46              Subject-rswk
+att 47              Subject-subdivision
+att 48              Number-natl-biblio
+att 49              Number-legal-deposit
+att 50              Number-govt-pub
+att 51              Number-music-publisher
+att 52              Number-db
+att 53              Number-local-call
+att 54              Code-language
+att 55              Code-geographic
+att 56              Code-institution
+att 57              Name-and-title
+att 58              Name-geographic
+att 59              Place-publication
+att 60              CODEN
+att 61              Microform-generation
+att 62              Abstract
+att 63              Note
+att 1000            Author-title
+att 1001            Record-type
+att 1002            Name
+att 1003            Author
+att 1004            Author-name-personal
+att 1005            Author-name-corporate
+att 1006            Author-name-conference
+att 1007            Identifier-standard
+att 1008            Subject-LC-childrens
+att 1009            Subject-name-personal
+att 1010            Body-of-text
+att 1011            Date/time-added-to-db
+att 1012            Date/time-last-modified
+att 1013            Authority/format-id
+att 1014            Concept-text
+att 1015            Concept-reference
+att 1016            Any 		1016,4,1005,62
+att 1017            Server-choice
+att 1018            Publisher
+att 1019            Record-source
+att 1020            Editor
+att 1021            Bib-level
+att 1022            Geographic-class
+att 1023            Indexed-by
+att 1024            Map-scale
+att 1025            Music-key
+att 1026            Related-periodical
+att 1027            Report-number
+att 1028            Stock-number
+att 1030            Thematic-number
+att 1031            Material-type
+att 1032            Doc-id
+att 1033            Host-item
+att 1034            Content-type
+att 1035            Anywhere
+att 1036            Author-Title-Subject
Index: /main/tags/2.25/gsdl/packages/yaz/tab/dan1.att
===================================================================
--- /main/tags/2.25/gsdl/packages/yaz/tab/dan1.att	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/yaz/tab/dan1.att	(revision 21064)
@@ -0,0 +1,22 @@
+name dan1
+reference 1.2.840.10003.3.15
+att 1         Classification-DK5-alfa-subdivision   # au Alfabetisk underdeling DK-5
+att 2         Subject-controlled                    # ke Kontrollerede emneord
+att 3         Subject-DBC                           # db DBC emneord
+att 4         Subject-DBC-non-fiction               # df DBC-faglitterære emneord
+att 5         Subject-DBC-fiction                   # ds DBC-skønlitterære emneord
+att 6         Subject-DBC-music                     # me DBC-Musikemneord
+att 7         Form-as-subject                       # fm Form betegnelse som emneord 
+att 8         Level-as-subject                      # nb Niveau-emneord
+att 9         Shelf-mark                            # po Opstillingselement
+att 10        Classification-DK5-number             # dk DK5
+att 11        Classification-as-shelf-mark          # ok Klassifikation som opstilling
+att 12        Obsolete-shelf-mark                   # gd Forældet dk-klassemærke
+att 13        Subject-FUI                           # fg FUI-Koder
+att 14        Catalogue-code                        # kk Katalogkode
+att 15        LIX-number                            # ix LIX
+att 16        Music-notation                        # nm Musikalsk notation
+att 17        Item-number                           # nr Numre
+att 18        Local-item-number                     # en Numre på ens materiale
+att 19        Previous-FAUST-code                   # tf Tidligere og lokale faustnumre 
+att 20        Title-host-publication                # lvx Værtspublikationstitel (uden nummer)
Index: /main/tags/2.25/gsdl/packages/yaz/tab/danmarc.abs
===================================================================
--- /main/tags/2.25/gsdl/packages/yaz/tab/danmarc.abs	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/yaz/tab/danmarc.abs	(revision 21064)
@@ -0,0 +1,740 @@
+name danmarc
+reference DANmarc
+attset bib1.att dan1.att
+
+elm 10          DanBib-ID-nummer                    -
+elm 10/?        DanBib-ID-nummer                    Item-number
+elm 10/?/a      DanBib-ID-nummer                    Item-number
+elm 10/?/b      Dataproducentens-biblioteksnummer   -
+
+elm 11          ID-nummer-på-hovedmaterialets-post  -
+elm 11/?        ID-nummer-på-hovedmaterialets-post  -
+elm 11/?/a      ID-nummer-på-hovedmaterialets-post  -
+
+elm 14          ID-nummer-på-post-på-højere-niveau  -
+elm 14/?        ID-nummer-på-post-på-højere-niveau  -
+elm 14/?/a      ID-nummer-på-post-på-højere-niveau  -
+elm 14/?/x      ID-nummer-på-post-på-højere-niveau  Item-number
+
+elm 15          ID-nummer-på-post-på-lavere-niveau  -
+elm 15/?        ID-nummer-på-post-på-lavere-niveau  Item-number
+elm 15/?/a      ID-nummer-på-post-på-lavere-niveau  Item-number
+
+elm 16          ID-nummer-på-værtspublikation       -
+elm 16/?        ID-nummer-på-værtspublikation       -
+elm 16/?/a      ID-nummer-på-værtspublikation       -
+
+elm 17          ID-nummer-på-første-udgave          -
+elm 17/?        ID-nummer-på-første-udgave          Item-number,Local-item-number
+elm 17/?/a      ID-nummer-på-første-udgave          Item-number,Local-item-number
+
+elm 18          ID-nummer-på-anden-post-for-samme-materiale          -
+elm 18/?        ID-nummer-på-anden-post-for-samme-materiale          Item-number,Local-item-number
+elm 18/?/a      ID-nummer-på-anden-post-for-samme-materiale          Item-number,Local-item-number
+
+elm 20          Nationalbibliografisk-nummer        -
+elm 20/?        Nationalbibliografisk-nummer        Item-number
+elm 20/?/a      Landekode-for-nationalbibliografi   -
+elm 20/?/b      Nationalbibliografisk-nummer        Item-number
+
+elm 21          ISBN                                -
+elm 21/?        ISBN                                ISBN,Identifier--standard,Item-number
+elm 21/?/a      ISBN                                ISBN,Identifier--standard,Item-number
+elm 21/?/b      Tilføjelse                          -
+elm 21/?/c      Bindtype                            -
+elm 21/?/d      Anskaffelsesvilkår/pris             -
+elm 21/?/n      Bestillingsnummer                   Item-number
+elm 21/?/x      Fejltryk-eller-fejlagtigt-anvendt-ISBN  ISBN,Identifier--standard,Item-number
+
+elm 22          ISSN                                -
+elm 22/?        ISSN                                ISBN,Identifier--standard,Item-number
+elm 22/?/a      ISSN                                ISBN,Identifier--standard,Item-number
+elm 22/?/b      Tilføjelse                          -
+elm 22/?/c      Bindtype                            -
+elm 22/?/d      Anskaffelsesvilkår/pris             -
+elm 22/?/z      Fejlagtigt-tildelt-ISSN             ISBN,Identifier--standard,Item-number
+
+elm 28          ISMN                                -
+elm 28/?        ISMN                                ISBN,Identifier--standard,Item-number
+elm 28/?/a      ISMN                                ISBN,Identifier--standard,Item-number
+elm 28/?/b      Tilføjelse                          -
+elm 28/?/c      Bindtype                            -
+elm 28/?/d      Anskaffelsesvilkår/pris             -
+elm 28/?/n      Bestillingsnummer                   Item-number
+
+elm 30          CODEN                               -
+elm 30/?        CODEN                               CODEN,Item-number
+elm 30/?/a      CODEN                               CODEN,Item-number
+
+elm 32          Kode-for-natio-eller-fagbibliografi -
+elm 32/?        Kode-for-natio-eller-fagbibliografi Catalogue-code
+elm 32/?/a      Kode-for-nationalbibliografi        Catalogue-code
+elm 32/?/x      Kode-for-fagbibliografi             Catalogue-code
+
+elm 34          Kodede-matematiske-oplysninger      -
+elm 34/?        Kodede-matematiske-oplysninger      Code-map-scale
+elm 34/?/a      Målestokstype                       Code-map-scale
+elm 34/?/b      Konstant-lineær-vandret-målestok    Code-map-scale
+elm 34/?/d      Koordinater                         Code-map-scale
+elm 34/?/e      Koordinater                         Code-map-scale
+elm 34/?/f      Koordinater                         Code-map-scale
+elm 34/?/g      Koordinater                         Code-map-scale
+
+elm 38          Opstillingskode-for-børnelitteratur -
+elm 38/?        Opstillingskode-for-børnelitteratur -
+elm 38/?/a      Opstillingskode-for-børnelitteratur -
+
+elm 39          Opstillingskode-for-musikoptagelser -
+elm 39/?        Opstillingskode-for-musikoptagelser -
+elm 39/?/a      Opstillingskode-for-musikoptagelser -
+
+elm 41          Sprogkode                           -
+elm 41/?        Sprogkode                           -
+elm 41/?/a      Materialets-sprog                   Code-language
+elm 41/?/b      Mellemoriginalens-sprog             Code-language-original
+elm 41/?/c      Originaludgavens-sprog              Code-language-original
+elm 41/?/d      Sprog-i-resuméer                    Code-language
+elm 41/?/e      Sprog-i-mindre-dele-af-materialet   Code-language
+elm 41/?/p      Sprog-i-parallel-tekst              Code-language
+elm 41/?/u      Sprog-i-undertekster-til-film/video Code-language
+
+elm 42          Lix-tal                             -
+elm 42/?        Lix-tal                             -
+elm 42/?/a      Samlet-lix-tal                      LIX-number
+elm 42/?/b      Specifikation-af-lix-tal            -
+
+elm 43          Kode-for-geografisk-område          -
+elm 43/?        Kode-for-geografisk-område          -
+elm 43/?/a      Kode-for-geografisk-område          -
+
+elm 44          Pædagogisk-fagkode                  -
+elm 44/?        Pædagogisk-fagkode                  Subject-FUI
+elm 44/?/a      Kode-for-skoleretning               Subject-FUI
+elm 44/?/b      Kode-for-fag-og-undervisningsmateriale  Subject-FUI
+
+elm 50          LC-klassifikation                   -
+elm 50/?        LC-klassifikation                   Classification-LC
+elm 50/?/a      LC-klassifikation                   -
+elm 50/?/b      Materialenummer                     -
+
+elm 60          NLM-klassifikation                  -
+elm 60/?        NLM-klassifikation                  Classification-NLM
+elm 60/?/a      NLM-klassifikation                  -
+elm 60/?/b      Materialenummer                     -
+
+elm 70          NAL-klassifikation                  -
+elm 70/?        NAL-klassifikation                  Classification-NAL
+elm 70/?/a      Materialenummer                     -
+
+elm 79          DB-klassifikation                   -
+elm 79/?        DB-klassifikation                   Classification-DB 
+elm 79/?/a      Systemkode                          -
+
+elm 80          UDK                                 -
+elm 80/?        UDK                                 Classification-UDC
+elm 80/?/a      UDK-notation                        -
+
+elm 82          DDC                                 -
+elm 82/?        DDC                                 Classification-Dewey
+elm 82/?/a      Basisnummer                         -
+elm 82/?/b      Udgivelse                           -
+elm 82/?/c      DDC-udgave                          -
+
+elm 83          Felt-083                            -
+elm 83/?        Felt-083                            -
+elm 83/?/a      Felt-083                            -
+elm 83/?/b      Felt-083                            -
+
+elm 85          BCM-klassifikation                  -
+elm 85/?        BCM-klassifikation                  Classification-BCM
+elm 85/?/a      BCM-klassifikation                  -
+elm 85/?/b      BCM-klassifikation                  -
+elm 85/?/c      BCM-klassifikation                  -
+
+elm 87          Lokal-klassifikationsnotation-1     -
+elm 87/?        Lokal-klassifikationsnotation-1     -
+elm 87/?/a      Lokal-klassifikationsnotation-1     Classification-local
+elm 87/?/b      Lokal-klassifikationsnotation-1     -
+
+elm 88          Lokal-klassifikationsnotation-2     -
+elm 88/?        Lokal-klassifikationsnotation-2     -
+elm 88/?/a      Lokal-klassifikationsnotation-2     Classification-local
+elm 88/?/b      Lokal-klassifikationsnotation-2     -
+elm 88/?/c      Lokal-klassifikationsnotation-2     -
+elm 88/?/d      Lokal-klassifikationsnotation-2     -
+elm 88/?/e      Lokal-klassifikationsnotation-2     -
+elm 88/?/f      Lokal-klassifikationsnotation-2     -
+elm 88/?/n      Lokal-klassifikationsnotation-2     -
+elm 88/?/p      Lokal-klassifikationsnotation-2     -
+elm 88/?/q      Lokal-klassifikationsnotation-2     -
+elm 88/?/t      Lokal-klassifikationsnotation-2     -
+elm 88/?/u      Lokal-klassifikationsnotation-2     -
+
+elm 89          Lokal-klassifikationsnotation-3     -
+elm 89/?        Lokal-klassifikationsnotation-3     -
+elm 89/?/a      Lokal-klassifikationsnotation-3     Classification-local
+elm 89/?/b      Lokal-klassifikationsnotation-3     -
+elm 89/?/c      Lokal-klassifikationsnotation-3     -
+
+elm 96          Lokal-opstillingssignatur           -
+elm 96/?        Lokal-opstillingssignatur           -
+elm 96/?/a      Opstilling           -
+elm 96/?/n      Lokal-opstillingssignatur           -
+elm 96/?/z      Lokaliseringskode                   -
+
+elm 100         Personnavn                  -
+elm 100/?       Personnavn                  Author-name:w,Author-name:p,Author-name-personal:w,Author-name-personal:p,Shelf-mark
+elm 100/?/a     Efternavn/fornavn-alene     Author-name:w,Author-name:p,Author-name-personal:w,Author-name-personal:p,Shelf-mark
+elm 100/?/c     Fødselsår                   Author-name:w,Author-name:p,Author-name-personal:w,Author-name-personal:p,Shelf-mark
+elm 100/?/f     Tilføjelse                  Author-name:w,Author-name:p,Author-name-personal:w,Author-name-personal:p,Shelf-mark
+elm 100/?/h     Fornavn                     Author-name:w,Author-name:p,Author-name-personal:w,Author-name-personal:p,Shelf-mark
+elm 100/?/k     Fuldt-udskrevet-fornavn     Author-name:w,Author-name:p,Author-name-personal:w,Author-name-personal:p,Shelf-mark
+
+elm 110         Korporationsnavn-opstillingselement     -
+elm 110/?       Korporationsnavn-opstillingselement     Author-name:w,Author-name:p,Author-name-corporate:w,Author-name-corporate:p,Shelf-mark
+elm 110/?/a     Korporationsnavn                        Author-name:w,Author-name:p,Author-name-corporate:w,Author-name-corporate:p,Shelf-mark
+elm 110/?/c     Underkorporation                        Author-name:w,Author-name:p,Author-name-corporate:w,Author-name-corporate:p,Shelf-mark
+elm 110/?/e     Tilføjelse                              Author-name:w,Author-name:p,Author-name-corporate:w,Author-name-corporate:p,Shelf-mark
+elm 110/?/i     Nummer-på-konference                    Author-name:w,Author-name:p,Author-name-corporate:w,Author-name-corporate:p,Shelf-mark
+elm 110/?/j     Sted-for-konference                     Author-name:w,Author-name:p,Author-name-corporate:w,Author-name-corporate:p,Shelf-mark
+elm 110/?/k     År-for-konference                       Author-name:w,Author-name:p,Author-name-corporate:w,Author-name-corporate:p,Shelf-mark
+
+elm 210         Forkortet-nøgletitel                    -
+elm 210/?       Forkortet-nøgletitel                    Title-key,Title,Title:p
+elm 210/?/a     Forkortet-nøgletitel                    Title-key,Title,Title:p
+elm 210/?/b     Forkortet-identificerende-tilføjelse    Title-key,Title,Title:p
+
+elm 222         Nøgletitel                  -
+elm 222/?       Nøgletitel                  Title-key,Title,Title:p
+elm 222/?/a     Nøgletitel                  Title-key,Title,Title:p
+elm 222/?/b     Identificerende-tilføjelse  Title-key,Title,Title:p
+
+elm 239         Uniform-titel/standardtitel-opstillingselement  -
+elm 239/?       Uniform-titel/standardtitel-opstillingselement  Title-uniform,Title,Title:p
+elm 239/?/t     Uniform-titel                                   Title-uniform,Title,Title:p
+elm 239/?/u     Almindeligt-kendt-tilnavn                       Title-uniform,Title,Title:p
+elm 239/?/v     Uddragstitel                                    Title-uniform,Title,Title:p
+elm 239/?/Ø     Uniform-titel/standardtitel-opstillingselement  -
+elm 239/?/ø     Identificerende-tilføjelser                     Title-uniform,Title
+
+elm 240         Uniform-titel-opstillingselement    -
+elm 240/?       Uniform-titel-opstillingselement    Title-uniform,Title,Title:p
+elm 240/?/a     Uniform-titel                       Title-uniform,Title,Title:p
+elm 240/?/j     Andet-identificerende-element       Title-uniform,Title,Title:p
+elm 240/?/r     Sprog-i-oversættelse/version        -
+elm 240/?/u     Udgivelsesår                        -
+elm 240/?/ø     Identificerende-tilføjelser         Title-uniform,Title
+
+elm 241         Originaltitel           -
+elm 241/?       Originaltitel           Title,Title:p
+elm 241/?/a     Originaltitel           Title,Title:p
+elm 241/?/r     Sprog                   -
+
+elm 245         Originaltitel-og-ophavsangivelse            -
+elm 245/?       Originaltitel-og-ophavsangivelse            Title,Title:p
+elm 245/?/A     Originaltitel-og-ophavsangivelse            -
+elm 245/?/G     Originaltitel-og-ophavsangivelse            -
+elm 245/?/a     Titel                                       Title,Title:p
+elm 245/?/b     Rest-af-titel-eller-alternativ-titel        Title,Title:p
+elm 245/?/c     Undertitel-og-anden-titelinformation        Title,Title:p
+elm 245/?/e     Ophavsangivelser-opslag                     -
+elm 245/?/f     Ophavsangivelser                            -
+elm 245/?/g     Numerisk-eller-alfabetisk-betegnelse-for-bind                       Title,Title:p
+elm 245/?/i     Anden-primær/sekundær-ophavsangivelse-kun-i-nationalbibliogafien    -
+elm 245/?/j     Anden-primær/sekundær-ophavsangivelse-ikke-i-nationalbibliogafien   -
+elm 245/?/o     Titel-på-supplement/sektion                  -
+elm 245/?/p     Paralleltitel                               Title-parallel,Title,Title:p
+elm 245/?/s     Parallel-undertitel                         Title-parallel,Title,Title:p
+elm 245/?/u     Markant-undertitel                          Title,Title:p
+elm 245/?/x     Hovedtitel-på-tilføjet-værk-af-andet-ophav  Title,Title:p
+elm 245/?/y     Titel-på-supplement                         Title,Title:p
+elm 245/?/Ø     Originaltitel-og-ophavsangivelse            -
+elm 245/?/æ     Identificerende-ophavsangivelse-til-titel   -
+elm 245/?/ø     Identificerende-tilføjelser-til-titel       -
+
+elm 248         Bindspecifikation                       -
+elm 248/?       Bindspecifikation                       Title
+elm 248/?/a     Bindtitel/supplementstitel              Title,Title:p
+elm 248/?/c     Undertitel-og-anden-titelinformation    Title,Title:p
+elm 248/?/e     Ophavsangivelse                         -
+elm 248/?/g     Bindnummer/supplementsbetegnelse        Title
+elm 248/?/j     Udgivelsesår                            -
+elm 248/?/l     Generel-note                            Note
+elm 248/?/w     Udgavebetegnelse                        -
+
+elm 250         Udgavebetegnelse                        -
+elm 250/?       Udgavebetegnelse                        -
+elm 250/?/a     Udgavebetegnelse                        -
+elm 250/?/b     Kort-udgavebetegnelse/sonderingselement -
+elm 250/?/c     Ophavsangivelse-opslag                  -
+elm 250/?/d     Ophavsangivelse                         -
+elm 250/?/x     Oplagsbetegnelse                        -
+
+elm 255         Nummereringer-og-dateringer   -
+elm 255/?       Nummereringer-og-dateringer   -
+elm 255/?/a     Nummereringer-og-dateringer   -
+
+elm 256         Matematiske-oplysninger-for-kartografiske-materialer    -
+elm 256/?       Matematiske-oplysninger-for-kartografiske-materialer    Code-map-scale
+elm 256/?/a     Målestok                                                Code-map-scale
+elm 256/?/c     Projektion                                              Code-map-scale
+
+elm 260         Publicering/distribution        -
+elm 260/?       Publicering/distribution        -
+elm 260/?/a     Hjemsted-for-forlag             Name-geographic-place-publication
+elm 260/?/b     Navn-på-forlag                  Name-publisher
+elm 260/?/c     Udgivelsesår                    Date-publication
+elm 260/?/d     Adresse-på-forlag               -
+elm 260/?/e     Funktionsangivelse-på-forlag    -
+elm 260/?/f     Hjemsted-for-distributør        Name-geographic-place-publication
+elm 260/?/g     Navn-på-distributør             -
+elm 260/?/k     Trykkerioplysninger             -
+elm 260/?/p     Navn-på-forlag/distributør-på-andet-sprog/alfabet   Name-publisher
+
+elm 300         Fysisk-beskrivelse                          -
+elm 300/?       Fysisk-beskrivelse                          -
+elm 300/?/D     Fysisk-beskrivelse                          -
+elm 300/?/a     Omfang-uden-specifik-materialebetegnelse    -
+elm 300/?/b     Yderligere-fysisk-beskrivelse               -
+elm 300/?/c     Størrelse                                   -
+elm 300/?/d     Bilag                                       -
+elm 300/?/e     Tekniske-oplysninger                        -
+elm 300/?/l     Spilletid                                   -
+elm 300/?/n     Specifik-materialebetegnelse                -
+
+elm 440         Seriebetegnelse-i-materialets-form                  -
+elm 440/?       Seriebetegnelse-i-materialets-form                  -
+elm 440/?/A     Seriebetegnelse-i-materialets-form                  -
+elm 440/?/V     Seriebetegnelse-i-materialets-form                  -
+elm 440/?/a     Seriens-hovedtitel                                  Title,Title-series,Title:p
+elm 440/?/c     Undertitel-eller-anden-titelinformation             Title,Title-series,Title:p
+elm 440/?/e     Ophavsangivelse                                     -
+elm 440/?/n     Numerisk/alfabetisk-betegnelse-for-sektion          Title,Title-series
+elm 440/?/o     Titel-på-sektion                                    Title,Title-series,Title:p
+elm 440/?/p     Seriens-paralleltitel                               Title,Title-series,Title:p
+elm 440/?/v     Nummerering-og-datering-i-serien                    Title,Title-series
+elm 440/?/y     Seriebetegnelse-i-materialets-form                  -
+elm 440/?/z     Seriens-ISSN                                        Identifier-ISSN
+elm 440/?/å     Seriebetegnelse-i-materialets-form                  -
+elm 440/?/æ     Identificerende-ophavsangivelse-til-seriens-titel   -
+elm 440/?/ø     Identificerende-tilføjelse-til-seriens-titel        Title,Title-series,Title:p
+
+elm 500         Periodicums-frekvens    -
+elm 500/?       Periodicums-frekvens    -
+elm 500/?/a     Periodicums-frekvens    -
+
+elm 501         Systemkrav/adgangsmåde  -
+elm 501/?       Systemkrav              Note
+elm 501/?/a     Adgangsmåde             Note
+
+elm 502         Originaltitel/oversættelse  -
+elm 502/?       Originaltitel/oversættelse  Note
+elm 502/?/a     Originaltitel/oversættelse  Note
+
+elm 504         Indholdsbeskrivelse     -
+elm 504/?       Indholdsbeskrivelse     Note
+elm 504/?/a     Indholdsbeskrivelse     Note
+
+elm 505         Art/form                -
+elm 505/?       Art/form                Note
+elm 505/?/a     Art/form                Note
+
+elm 506         Disputats/afhandling    -
+elm 506/?       Disputats/afhandling    Note
+elm 506/?/a     Disputats/afhandling    Note
+
+
+elm 507         Anledning-til-udgivelse -
+elm 507/?       Anledning-til-udgivelse Note
+elm 507/?/a     Anledning-til-udgivelse Note
+
+elm 508         Sprog-og-alfabet        -
+elm 508/?       Sprog-og-alfabet        Note
+elm 508/?/a     Sprog-og-alfabet        Note
+
+elm 509         Besætning               -
+elm 509/?       Besætning               Note
+elm 509/?/a     Besætning               Note
+
+elm 512         Beskrivelse                     -
+elm 512/?       Beskrivelse                     -
+elm 512/?/a     Generel-note-til-beskrivelse    Note
+elm 512/?/b     Supplerende-tekst               -
+elm 512/?/e     Ophavsangivelse                 -
+elm 512/?/i     Indledende-tekst                -
+elm 512/?/t     Titel                           Title,Title:p
+
+elm 513         Fælles-ophavsangivelse  -
+elm 513/?       Fælles-ophavsangivelse  -
+elm 513/?/e     Primær-ophavsangivelse  -
+
+elm 517         Målgruppe-og-anvendelighed  -
+elm 517/?       Målgruppe-og-anvendelighed  Note
+elm 517/?/a     Målgruppe-og-anvendelighed  Note
+
+elm 520         Værkets-bibliografiske-historie -
+elm 520/?       Værkets-bibliografiske-historie -
+elm 520/?/a     Værkets-bibliografiske-historie -
+elm 520/?/b     Supplerende-tekst               -
+elm 520/?/i     Indledende-tekst                -
+elm 520/?/t     Titel                           Title,Title:p
+
+elm 521         Udgavens-oplag          -
+elm 521/?       Udgavens-oplag          -
+elm 521/?/a     Oplagsbetegnelse        -
+elm 521/?/b     Seneste-oplag           -
+elm 521/?/c     Oplagets-udgivelsesår   Date-publication
+
+elm 526         Sammenhæng-med-andre-værker -
+elm 526/?       Sammenhæng-med-andre-værker -
+elm 526/?/a     Sammenhæng-med-andre-værker Note
+elm 526/?/b     Supplerende-tekst           -
+elm 526/?/d     Ophavsangivelse-foran-titel -
+elm 526/?/e     Ophavsangivelse             -
+elm 526/?/i     Indledende-tekst            -
+elm 526/?/t     Titel                       Title,Title:p
+
+elm 530         Indholdsnote            -
+elm 530/?       Indholdsnote            -
+elm 530/?/a     Indholdsnote            Note
+elm 530/?/e     Ophavsangivelse         -
+elm 530/?/t     Titel                   Title,Title:p
+
+elm 531         Indledende-tekst-til-maskingenereret-indholdsnote   -
+elm 531/?       Indledende-tekst-til-maskingenereret-indholdsnote   -
+elm 531/?/a     Indledende-tekst-til-maskingenereret-indholdsnote   -
+
+elm 532         Litteraturhenvisninger-og-registre    -
+elm 532/?       Litteraturhenvisninger-og-registre    -
+elm 532/?/a     Litteraturhenvisninger-og-registre    -
+
+elm 534         Partielt-indhold        -
+elm 534/?       Partielt-indhold        Note
+elm 534/?/a     Partielt-indhold        Note
+
+elm 538         Numre-der-indgår-i-materialet   -
+elm 538/?       Numre-der-indgår-i-materialet   Item-number
+elm 538/?/a     Nummer                          Item-number
+elm 538/?/b     Editionsnummer                  Item-number
+elm 538/?/c     Pladenummer                     Item-number
+elm 538/?/d     Editions-og-pladenummer         Item-number
+elm 538/?/f     Forlag                          Name-publisher
+elm 538/?/g     Forlagsnummer                   Item-number
+
+elm 539         Grundlaget-for-katalogiseringen -
+elm 539/?       Grundlaget-for-katalogiseringen -
+elm 539/?/a     Grundlaget-for-katalogiseringen -
+
+elm 557         Periodicum-som-værtspublikation-for-I-analyse   -
+elm 557/?       Periodicum-som-værtspublikation-for-I-analyse   -
+elm 557/?/V     Periodicum-som-værtspublikation-for-I-analyse   -
+elm 557/?/a     Titel                                           Title,Title-host-item,Title:p
+elm 557/?/j     Udgivelsesår                                    -
+elm 557/?/v     Nummerering/datering                            Title,Title-host-item,Title:p
+
+elm 559         Generel-note            -
+elm 559/?       Generel-note            -
+elm 559/?/a     Generel-note            Note
+
+elm 600         Personnavn-emneord      -
+elm 600/?       Personnavn-emneord      Subject,Subject-name-personal,Subject:p
+elm 600/?/a     Efternavn/fornavn-alene Subject,Subject-name-personal,Subject:p
+elm 600/?/c     Fødselsår               Subject,Subject-name-personal,Subject:p
+elm 600/?/e     Romertal                Subject,Subject-name-personal,Subject:p
+elm 600/?/f     Tilføjelse              Subject,Subject-name-personal,Subject:p
+elm 600/?/h     Fornavn                 Subject,Subject-name-personal,Subject:p
+elm 600/?/k     Fuldt-udskrevet-fornavn Subject,Subject-name-personal,Subject:p
+elm 600/?/x     Underdeling-emne/art    Subject,Subject-name-personal,Subject:p
+elm 600/?/å     Personnavn-emneord      Subject,Subject-name-personal,Subject:p
+
+elm 610         Korporationsnavn-emneord    -
+elm 610/?       Korporationsnavn-emneord    Subject,Subject-name-corporate,Subject:p
+elm 610/?/a     Korporationsnavn            Subject,Subject-name-corporate,Subject:p
+elm 610/?/c     Underkorporation            Subject,Subject-name-corporate,Subject:p
+elm 610/?/e     Tilføjelse                  Subject,Subject-name-corporate,Subject:p
+elm 610/?/t     Titel                       Subject,Subject-name-corporate,Subject:p
+elm 610/?/x     Underdeling-emne/art        Subject,Subject-name-corporate,Subject:p
+elm 610/?/y     Underdeling-periode         Subject,Subject-name-corporate,Subject:p
+
+elm 621         Emnedata-for-kartografisk-materiale -
+elm 621/?       Emnedata-for-kartografisk-materiale Subject
+elm 621/?/a     Stednavn Subject
+elm 621/?/b     Land/stat Subject
+
+elm 630         Kontrolleret-emneord    -
+elm 630/?       Kontrolleret-emneord    Subject,Subject-controlled,Subject:p,Subject-controlled:p
+elm 630/?/a     Kontrolleret-emneord    Subject,Subject-controlled,Subject:p,Subject-controlled:p
+elm 630/?/b     Andre-bibliotekers-kontrollerede-emneord    Subject,Subject-controlled,Subject:p,Subject-controlled:p
+
+elm 631         Ukontrolleret-emneord   -
+elm 631/?       Ukontrolleret-emneord   Subject,Subject-uncontrolled,Subject:p,Subject-uncontrolled:p
+elm 631/?/a     Ukontrolleret-emneord   Subject,Subject-uncontrolled,Subject:p,Subject-uncontrolled:p
+elm 631/?/b     Andre-bibliotekers-ukontrollerede-emneord   Subject,Subject-uncontrolled,Subject:p,Subject-uncontrolled:p
+elm 631/?/f     Ukontrolleret-faglitterært-emneord          Subject,Subject-uncontrolled,Subject:p,Subject-uncontrolled:p
+
+elm 633         Stednavn                -
+elm 633/?       Stednavn                Subject,Subject-controlled,Subject:p,Subject-controlled:p
+elm 633/?/a     Stednavn                Subject,Subject-controlled,Subject:p,Subject-controlled:p
+
+elm 645         Titel                   -
+elm 645/?       Titel                   Subject,Subject-controlled,Subject:p,Subject-controlled:p
+elm 645/?/c     Titel                   Subject,Subject-controlled,Subject:p,Subject-controlled:p
+
+elm 650         LC-emneord              -
+elm 650/?       LC-emneord              Subject
+elm 650/?/a     LC-emneord              Subject
+elm 650/?/v     LC-emneord              -
+elm 650/?/x     Underdeling-emne/art    Subject
+elm 650/?/y     Underdeling-periode     Subject
+elm 650/?/z     Underdeling-lokalitet   Subject
+
+elm 651         LC-geografisk-emneord   -
+elm 651/?       LC-geografisk-emneord   Subject
+elm 651/?/a     LC-geografisk-emneord   Subject
+elm 651/?/x     Underdeling-emne/art    Subject
+elm 651/?/z     Underdeling-lokalitet   Subject
+
+elm 652         DK5-klassemærke         -
+elm 652/?       DK5-klassemærke         -
+elm 652/?/a     Efternavn/navn/korporationsnavn-som-alfabetisk-underdeling  Classification-DK5-alfa-subdivision
+elm 652/?/b     Andet-som-alfabetisk-underdeling                    Classification-DK5-alfa-subdivision,Subject
+elm 652/?/c     Fødselsår                                           Classification-DK5-alfa-subdivision
+elm 652/?/h     Fornavn                                             Classification-DK5-alfa-subdivision,Subject
+elm 652/?/i     Analytisk-klassemærke                               Classification,Classification-DK5-number
+elm 652/?/m     Opstillings-og-hovedplacering                       Classification,Classification-DK5-number,Classification-as-shelf-mark
+elm 652/?/n     Nationalbibliografisk-hovedplacering                Classification,Classification-DK5-number
+elm 652/?/o     Opstillingsklassemærkeog-bibliotekshovedplacering   Classification,Classification-DK5-number
+elm 652/?/p     Biplacering                                         Classification,Classification-DK5-number
+elm 652/?/q     Nationalbibliografisk-biplacering                   Classification,Classification-DK5-number
+elm 652/?/r     Biblioteksbiplacering                               Classification,Classification-DK5-number
+elm 652/?/v     Tilføjede-cifre-efter-kolon                         -
+elm 652/?/z     Tilføjede-cifre-efter-bindestreg                    -
+elm 652/?/å     Feltnumerator                                       -
+
+elm 654         Forældet-DK5-klassemærke    -
+elm 654/?       Forældet-DK5-klassemærke    Classification
+elm 654/?/p     Biplacering                 Classification
+
+elm 660         MeSH-emneord            -
+elm 660/?       MeSH-emneord            Subject,Subject-controlled,Subject-MESH
+elm 660/?/a     MeSH-emneord            Subject,Subject-controlled,Subject-MESH
+elm 660/?/x     Generel-underdeling     Subject,Subject-controlled,Subject-MESH
+
+elm 661         Europæisk-pædagogisk-tesaurus   -
+elm 661/?       Europæisk-pædagogisk-tesaurus   Subject,Subject-controlled
+elm 661/?/a     Kontrolleret-dansk-emneord      Subject,Subject-controlled
+elm 661/?/b     Kontrolleret-engelsk-emneord    Subject,Subject-controlled
+elm 661/?/c     Ukontrolleret-dansk-emneord     Subject,Subject-controlled
+
+elm 666         Kontrolleret-DBC-emneord            -
+elm 666/?       Kontrolleret-DBC-emneord            -
+elm 666/?/e     Stednavn-som-emneord-faglitteratur  Subject-DBC,Subject,Subject-DBC-non-fiction,Subject-controlled
+elm 666/?/f     Kontrolleret-faglitterært-emneord   Subject-DBC,Subject,Subject-DBC-non-fiction,Subject-controlled
+elm 666/?/i     Tidsangivelse                       Subject-DBC,Subject,Subject-DBC-non-fiction,Subject-controlled
+elm 666/?/l     Stednavn                            Subject-DBC,Subject
+elm 666/?/m     Musikalsk-genre-som-emneord         Subject-DBC,Subject,Subject-DBC-music
+elm 666/?/n     Musikalsk-besætning-som-emneord     Subject-DBC,Subject,Subject-DBC-music
+elm 666/?/o     Formbetegnelse                      Subject-DBC,Subject,Form-as-subject
+elm 666/?/p     Periodebetegnelse                   Subject-DBC,Subject,Subject-DBC-music
+elm 666/?/q     Stednavn-som-emneord-skønlitteratur Subject-DBC,Subject,Subject-DBC-fiction,Subject-controlled
+elm 666/?/s     Kontrolleret-skønlitterært-emneord  Subject-DBC,Subject,Subject-DBC-fiction,Subject-controlled
+elm 666/?/u     Niveau/brugerkategori               Subject-DBC,Subject,Level-as-subject
+elm 666/?/å     Kontrolleret-DBC-emneord            Subject-DBC,Subject
+
+elm 668         Genrebetegnelse         -
+elm 668/?       Genrebetegnelse         Subject,Subject-controlled
+elm 668/?/a     Genrebetegnelse         Subject,Subject-controlled
+elm 668/?/b     Underdeling             Subject,Subject-controlled
+
+elm 670         NAL-emneord             -
+elm 670/?       NAL-emneord             Subject-NAL
+elm 670/?/a     NAL-emneord             Subject
+
+elm 690         COMPASS-emneord         -
+elm 690/?       COMPASS-emneord         Subject,Subject-COMPASS
+elm 690/?/a     Enkeltord         Subject,Subject-COMPASS
+elm 690/?/b     Flere-ord         Subject,Subject-COMPASS
+elm 690/?/c     Forbindende-tekst         -
+elm 690/?/d     Underdeling-periode         Subject,Subject-COMPASS
+elm 690/?/h     COMPASS-emneord         Subject,Subject-COMPASS
+elm 690/?/i     COMPASS-emneord         -
+elm 690/?/m     COMPASS-emneord         -
+elm 690/?/v     COMPASS-emneord         -
+elm 690/?/w     COMPASS-emneord         -
+elm 690/?/x     COMPASS-emneord         -
+elm 690/?/y     COMPASS-emneord         -
+elm 690/?/z     COMPASS-emneord         -
+
+elm 700         Personnavn              -
+elm 700/?       Personnavn              Author-name,Author-name-personal
+elm 700/?/A     Personnavn              Author-name,Author-name-personal
+elm 700/?/a     Efternavn/fornavn-alene Author-name,Author-name-personal
+elm 700/?/b     Funktionsbetegnelse -
+elm 700/?/c     Fødselsår               Author-name,Author-name-personal
+elm 700/?/f     Tilføjelse              Author-name,Author-name-personal
+elm 700/?/h     Fornavn                 Author-name,Author-name-personal
+elm 700/?/k     Fuldt-udskrevet-fornavn Author-name,Author-name-personal
+elm 700/?/å     Personnavn              -
+
+elm 710         Korporationsnavn        -
+elm 710/?       Korporationsnavn        Author-name,Author-name-corporate
+elm 710/?/A     Korporationsnavn        Author-name,Author-name-corporate
+elm 710/?/a     Korporationsnavn        Author-name,Author-name-corporate
+elm 710/?/c     Underkorporation        Author-name,Author-name-corporate
+elm 710/?/e     Tilføjelse              Author-name,Author-name-corporate
+elm 710/?/i     Nummer-på-konference    Author-name,Author-name-corporate
+elm 710/?/j     Sted-for-konference     Author-name,Author-name-corporate
+elm 710/?/k     År-for-konference       Author-name,Author-name-corporate
+elm 710/?/å     Korporationsnavn        -
+
+
+elm 739         Uniform-titel/standardtitel -
+elm 739/?       Uniform-titel/standardtitel Title-uniform
+elm 739/?/t     Uniform-titel/standardtitel Title-uniform
+
+elm 740         Uniform-titel                -
+elm 740/?       Uniform-titel                Title,Title-uniform
+elm 740/?/a     Uniform-titel                Title,Title-uniform
+elm 740/?/s     Titel-på-del-af-værket       Title,Title-uniform
+
+elm 745         Varianttitel            -
+elm 745/?       Varianttitel            -
+elm 745/?/A     Varianttitel            -
+elm 745/?/a     Titel                   Title
+elm 745/?/o     Titel-på-afhængig-publikation/supplement    -
+
+elm 770         Personnavn-analyse      -
+elm 770/?       Personnavn-analyse      Author-name,Author-name-personal
+elm 770/?/A     Personnavn-analyse      -
+elm 770/?/a     Efternavn/fornavn-alene Author-name,Author-name-personal
+elm 770/?/c     Fødselsår               Author-name,Author-name-personal
+elm 770/?/f     Tilføjelse              Author-name,Author-name-personal
+elm 770/?/h     Fornavn                 Author-name,Author-name-personal
+elm 770/?/å     Feltnumerator           -
+
+elm 780         Korporationsnavn-analyse    -
+elm 780/?       Korporationsnavn-analyse    Author-name,Author-name-corporate
+elm 780/?/a     Korporationsnavn            Author-name,Author-name-corporate
+elm 780/?/å     Feltnumerator               Author-name,Author-name-corporate
+
+elm 795         Analytisk-titel                             -
+elm 795/?       Analytisk-titel                             Title
+elm 795/?/A     Analytisk-titel                             -
+elm 795/?/a     Analytisk-titel                             Title
+elm 795/?/b     Rest-af-analytisk-titel/alternativ-titel    Title
+elm 795/?/c     Undertitel/anden-titelinformation           Title
+elm 795/?/e     Ophavsangivelse-opslag                      -
+elm 795/?/i     Anden-primær/sekundær-ophavsangivelse       -
+elm 795/?/p     Paralleltitel                               Title
+elm 795/?/u     Almindeligt-kendt-tilnavn                   Title
+elm 795/?/v     Uddragstitel                                Title
+elm 795/?/y     Kode                                        -
+elm 795/?/å     Feltnumerator                               -
+
+elm 840         Serietitel              -
+elm 840/?       Serietitel              -
+elm 840/?/V     Serietitel              -
+elm 840/?/a     Seriens-hovedtitel              Title,Title-series
+elm 840/?/v     Seriens-nummerering/datering    Title,Title-series
+elm 840/?/z     Seriens-ISSN                    Identifier--standard,ISSN,Item-number
+elm 840/?/ø     Identificerende-tilføjelser-til-seriens-titel   Title
+
+elm 860         Tidligere-titel         -
+elm 860/?       Tidligere-titel         -
+elm 860/?/c     Tilføjelse-til-titel    Related-periodical,Title-former
+elm 860/?/t     Hovedtitel              Title-former
+elm 860/?/z     ISSN                    Identifier--standard,ISSN,Item-number
+
+elm 861         Senere-titel            -
+elm 861/?       Senere-titel            -
+elm 861/?/c     Tilføjelse-til-titel    Related-periodical,Title-later
+elm 861/?/i     Indledende-tekst       -
+elm 861/?/t     Hovedtitel              Related-periodical,Title-later
+elm 861/?/z     ISSN                    Identifier--standard,ISSN,Item-number
+
+elm 863         Udgivet-sammen-med      -
+elm 863/?       Udgivet-sammen-med      -
+elm 863/?/t     Hovedtitel              Title-related-periodical
+elm 863/?/z     ISSN                    Identifier--standard,ISSN,Item-number
+
+elm 867         Hovedudgave-på-andet-sprog/andet-indhold    -
+elm 867/?       Hovedudgave-på-andet-sprog/andet-indhold    -
+elm 867/?/t     Hovedtitel                                  Title-related-periodical
+elm 867/?/z     ISSN                                        Identifier--standard,ISSN,Item-number
+
+elm 868         Udgave-på-andet-sprog/andet-indhold     -
+elm 868/?       Udgave-på-andet-sprog/andet-indhold     -
+elm 868/?/t     Hovedtitel                              Title-related-periodical
+elm 868/?/z     ISSN                                    Identifier--standard,ISSN,Item-number
+
+elm 870         Hovedpublikation-til-supplement     -
+elm 870/?       Hovedpublikation-til-supplement     -
+elm 870/?/t     Hovedtitel                          Title-related-periodical
+elm 870/?/z     ISSN                                Identifier--standard,ISSN,Item-number
+
+elm 871         Supplement-til-hovedpublikation     -
+elm 871/?       Supplement-til-hovedpublikation     -
+elm 871/?/c     Tilføjelse-til-titel                -
+elm 871/?/t     Hovedtitel                          Title-related-periodical
+
+elm 874         Underserie              -
+elm 874/?       Underserie              -
+elm 874/?/t     Hovedtitel              Title-related-periodical
+elm 874/?/z     ISSN                    Identifier--standard,ISSN,Item-number
+
+elm 900         Henvisning-fra-personnavn   -
+elm 900/?       Henvisning-fra-personnavn   Author-name,Author-name-personal
+elm 900/?/A     Henvisning-fra-personnavn   -
+elm 900/?/a     Efternavnet/fornavnet-alene Author-name,Author-name-personal
+elm 900/?/c     Fødselsår                   Author-name,Author-name-personal
+elm 900/?/f     Tilføjelse                  Author-name,Author-name-personal
+elm 900/?/h     Fornavn                     Author-name,Author-name-personal
+elm 900/?/k     Fuldt-udskrevet-fornavn     Author-name,Author-name-personal
+elm 900/?/w     Ord-hvortil-der-henvises    -
+elm 900/?/x     Forbindende-tekst           -
+elm 900/?/z     Felt/delfeltkode-hvortil-der-henvises   -
+elm 900/?/å     Feltnumerator               -
+
+elm 910         Henvisning-fra-korporationsnavn     -
+elm 910/?       Henvisning-fra-korporationsnavn     Author-name,Author-name-corporate
+elm 910/?/A     Henvisning-fra-korporationsnavn     -
+elm 910/?/a     Korporationsnavn                    Author-name,Author-name-corporate
+elm 910/?/c     Underkorporation                    Author-name,Author-name-corporate
+elm 910/?/e     Tilføjelse                          Author-name,Author-name-corporate
+elm 910/?/g     Resten-af-korporationsnavn          Author-name,Author-name-corporate
+elm 910/?/h     Forbogstaver/fornavnsforkortelser   Author-name,Author-name-corporate
+elm 910/?/w     Ord-hvortil-der-henvises            -
+elm 910/?/x     Forbindende-tekst                   -
+elm 910/?/z     Felt/delfeltkode-hvortil-der-henvises     -
+elm 910/?/å     Feltnumerator                       -
+
+elm 945         Henvisning-fra-titel        -
+elm 945/?       Henvisning-fra-titel        -
+elm 945/?/a     Title                       Title
+elm 945/?/w     Ord-hvortil-der-henvises    -
+elm 945/?/x     Forbindende-tekst           -
+elm 945/?/z     Felt/delfeltkode-hvortil-der-henvises        -
+
+elm 980         Bibliotekets-beholdning-af-et-periodicum    -
+elm 980/?       Bibliotekets-beholdning-af-et-periodicum    -
+elm 980/?/d     Første-år                                   -
+elm 980/?/g     Kode-for-fuldstændighed                     -
+
+elm s01         felt-s01                    -
+elm s01/?       felt-s01                    -
+elm s01/?/a     felt-s01                    -
+elm s01/?/b     felt-s01                    -
+
+
+elm s06         felt-s06                    -
+elm s06/?       felt-s06                    -
+elm s06/?/a     felt-s06                    -
+elm s06/?/b     felt-s06                    -
+
+elm s10         felt-s10                    -
+elm s10/?       felt-s10                    -
+elm s10/?/a     felt-s10                    -
+
+elm s45         felt-s45                    -
+elm s45/?       felt-s45                    -
+elm s45/?/a     felt-s45                    -
Index: /main/tags/2.25/gsdl/packages/yaz/tab/explain.abs
===================================================================
--- /main/tags/2.25/gsdl/packages/yaz/tab/explain.abs	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/yaz/tab/explain.abs	(revision 21064)
@@ -0,0 +1,229 @@
+# This Explain schema is used for our internal management and processing of
+# explain data. On request, records are mapped to the proper Explain ASN.1
+# before transmission.
+#
+# $Id$
+
+name explain
+reference Explain-schema
+attset explain
+tagset explain.tag
+
+esetname B @
+esetname F @
+
+
+section rpnCapabilities
+elm (4,550)				rpnOperators			-
+elm (4,550)/(4,551)			rpnOperator			-
+elm (4,552)				resultSetAsOperandSupported	-
+elm (4,553)				restrictionOperandSupported	-
+elm (4,554)				proximitySupport		-
+elm (4,554)/(4,555)			anySupport			-
+elm (4,554)/(4,556)			unitsSupported			-
+elm (4,554)/(4,556)/(4,557)		unitSupported			-
+elm (4,554)/(4,556)/(4,557)/(4,558)	known				-
+elm (4,554)/(4,556)/(4,557)/(4,559)	private				-
+elm (4,554)/(4,556)/(4,557)/(4,559)/(4,558) privateUnit			-
+elm (4,554)/(4,556)/(4,557)/(4,559)/(4,560) description			-
+
+section accessInfo
+elm (4,501)				queryTypesSupported		-
+elm (4,501)/(4,518)			queryTypeDetails		-
+elm (4,501)/(4,518)/(4,519):rpnCapabilities	rpnCapabilities		-
+elm (4,501)/(4,518)/(4,520)		iso8777Capabilities		-
+elm (4,501)/(4,518)/(4,521)		privateCapabilities		-
+elm (4,503)				diagnosticSets			-
+elm (4,503)/(4,1000)			diagnosticSet			-
+elm (4,505)				attributeSetIds			-
+elm (4,505)/(4,1000)			attributeSetId			-
+elm (4,507)				schemas				-
+elm (4,507)/(4,1000)			schema				-
+elm (4,509)				recordSyntaxes			-
+elm (4,509)/(4,1000)			recordSyntax			-
+elm (4,511)				resourceChallenges		-
+elm (4,511)/(4,1000)			resourceChallenge		-
+elm (4,513)				restrictedAccess		-
+elm (4,514)				costInfo			-
+elm (4,515)				variantSets			-
+elm (4,515)/(4,1000)			variantSets			-
+elm (4,516)				elementSetNames			-
+elm (4,516)/(4,1001)			elementSetName			-
+elm (4,517)				unitSystems			-
+elm (4,517)/(4,1001)			unitSystem			-
+
+section commonInfo
+elm (4,601)				dateAdded			!
+elm (4,602)				dateChanged			!
+elm (4,603)				expiry		DateExpired
+elm (4,604)				languageCode	HumanStringLanguage
+
+section contactInfo
+elm (4,102)				name				-
+elm (4,113)				description			-
+elm (4,127)				address				-
+elm (4,128)				email				-
+elm (4,129)				phone				-
+
+section stringOrNumeric
+elm (4,1001)				string				-
+elm (4,1002)				numeric				-
+
+section attributeSetDetailsValue
+elm (4,709)				attributeValue			-
+elm (4,709)/(4,710):stringOrNumeric	value	-
+elm (4,709)/(4,113)			description			-
+elm (4,709)/(4,712)			subAttributes			-
+elm (4,709)/(4,712)/(4,713):stringOrNumeric subAttribute		-
+elm (4,709)/(4,714)			superAttributes			-
+elm (4,709)/(4,714)/(4,715):stringOrNumeric superAttributes		-
+elm (4,709)/(4,711)			partialSupport			-
+
+section attributeSetDetails
+elm (4,1000)				attributeSet			-
+elm (4,702)				attributesByType		-
+elm (4,702)/(4,703)			attributeTypeDetails		-
+elm (4,702)/(4,703)/(4,704)		attributeType			-
+elm (4,702)/(4,703)/(4,705)		defaultIfOmitted		-
+elm (4,702)/(4,703)/(4,705)/(4,706):stringOrNumeric	defaultValue	-
+elm (4,702)/(4,703)/(4,705)/(4,113)	defaultDescription		-
+elm (4,702)/(4,703)/(4,708):attributeSetDetailsValue attributeValues	-
+
+section attributeCombinations
+elm (4,1000)				attributeSet			-
+elm (4,717)				legalCombinations		-
+elm (4,717)/(4,718)			legalCombination		-
+elm (4,717)/(4,718)/(4,719)		attributeOccurrence		-
+elm (4,717)/(4,718)/(4,719)/(4,1000)	attributeSetId			-
+elm (4,717)/(4,718)/(4,719)/(4,704)	attributeType			-
+elm (4,717)/(4,718)/(4,719)/(4,720)	mustBeSupplied			-
+elm (4,717)/(4,718)/(4,719)/(4,721)	anyOrNone			-
+elm (4,717)/(4,718)/(4,719)/(4,722)	specific			-
+elm (4,717)/(4,718)/(4,719)/(4,722)/(4,710):stringOrNumeric value	-
+
+section attributeType
+elm (4,751)				attributeType			-
+elm (4,751)/(4,102)			attributeName			-
+elm (4,751)/(4,113)			attributeDescription		-
+elm (4,751)/(4,704)			type				-
+elm (4,751)/(4,708)			attributeValues			-
+elm (4,751)/(4,708)/(4,709)		attributeValue			-
+elm (4,751)/(4,708)/(4,709)/(4,102)	name				-
+elm (4,751)/(4,708)/(4,709)/(4,113)	description			-
+elm (4,751)/(4,708)/(4,709)/(4,710):stringOrNumeric attributeValue	-
+elm (4,751)/(4,708)/(4,709)/(4,752):stringOrNumeric equivalentAttribute	-
+
+section main
+#
+# CategoryList
+#
+elm (4,1)				categoryList	ExplainCategory
+elm (4,1)/(4,600):commonInfo		categoryListCommonInfo		-
+elm (4,1)/(4,300)			categories			-
+elm (4,1)/(4,300)/(4,301)		category			-
+elm (4,1)/(4,300)/(4,301)/(4,102)	categoryName			-
+elm (4,1)/(4,300)/(4,301)/(4,302)	originalName			-
+elm (4,1)/(4,300)/(4,301)/(4,113)	description			-
+elm (4,1)/(4,300)/(4,301)/(4,303)	asn1Module			-
+elm (4,1)/?				other				-
+
+#
+# TargetInfo
+# 
+elm (4,2)				targetInfo		ExplainCategory
+elm (4,2)/(4,600):commonInfo		targetCommonInfo		-
+elm (4,2)/(4,102)			targetName		TargetName
+elm (4,2)/(4,103)			recentNews			-
+elm (4,2)/(4,104)			icon				-
+elm (4,2)/(4,105)			namedResultSets			-
+elm (4,2)/(4,106)			multipleDbSearch		-
+elm (4,2)/(4,107)			maxResultSets			-
+elm (4,2)/(4,108)			maxResultSize			-
+elm (4,2)/(4,109)			maxTerms			-
+elm (4,2)/(4,110)			timeoutInterval			-
+elm (4,2)/(4,111)			welcomeMessage			-
+elm (4,2)/(4,112):contactInfo		contactInfo			-
+elm (4,2)/(4,113)			description			-
+elm (4,2)/(4,114)			nicknames			-
+elm (4,2)/(4,114)/(4,102)		nickname			-
+elm (4,2)/(4,115)			usageRestrictions		-
+elm (4,2)/(4,116)			paymentAddr			-
+elm (4,2)/(4,117)			hours				-
+elm (4,2)/(4,118)			dbCombinations			-
+elm (4,2)/(4,118)/(4,605)		databaseList			-
+elm (4,2)/(4,118)/(4,605)/(4,102)	databaseName			-
+elm (4,2)/(4,119)			addresses			-
+elm (4,2)/(4,119)/(4,120)		internetAddress			-
+elm (4,2)/(4,119)/(4,120)/(4,121) 	host				-
+elm (4,2)/(4,119)/(4,120)/(4,122)	port				-
+elm (4,2)/(4,119)/(4,123)		otherAddress			-
+elm (4,2)/(4,119)/(4,123)/(4,124)	addressType			-
+elm (4,2)/(4,119)/(4,123)/(4,121)	address				-
+elm (4,2)/(4,125)			languages			-
+elm (4,2)/(4,125)/(4,126)		language			-
+elm (4,2)/(4,500):accessInfo		commonAccessInfo		-
+elm (4,2)/?				other				-
+#
+# DatabaseInfo
+#
+elm (4,3)				databaseInfo	ExplainCategory
+elm (4,3)/(4,600):commonInfo		databaseCommonInfo		-
+elm (4,3)/(4,102)			databaseName	DatabaseName
+elm (4,3)/(4,226)			explainDatabase			-
+elm (4,3)/(4,114)			nicknames			-
+elm (4,3)/(4,114)/(4,102)		nickname			-
+elm (4,3)/(4,104)			icon				-
+elm (4,3)/(4,201)			userFee				-
+elm (4,3)/(4,202)			available	Availability
+elm (4,3)/(4,203)			titleString			-
+elm (4,3)/(4,227)			keywords			-
+elm (4,3)/(4,227)/(4,1000)		keyword				-
+elm (4,3)/(4,113)			description			-
+elm (4,3)/(4,205)			associatedDbs			-
+elm (4,3)/(4,205)/(4,605)		databaseList			-
+elm (4,3)/(4,205)/(4,605)/(4,102)	databaseName			-
+elm (4,3)/(4,206)			subDbs				-
+elm (4,3)/(4,206)/(4,605)		databaseList			-
+elm (4,3)/(4,206)/(4,605)/(4,102)	databaseName			-
+elm (4,3)/(4,207)			disclaimers			-
+elm (4,3)/(4,103)			recentNews			-
+elm (4,3)/(4,209)			recordCount			-
+elm (4,3)/(4,209)/(4,210)		recordCountActual		-
+elm (4,3)/(4,209)/(4,211)		recordCountApprox		-
+elm (4,3)/(4,212)			defaultOrder			-
+elm (4,3)/(4,213)			avRecordSize			-
+elm (4,3)/(4,214)			maxRecordSize			-
+elm (4,3)/(4,215)			hours				-
+elm (4,3)/(4,216)			bestTime			-
+elm (4,3)/(4,217)			lastUpdate			-
+elm (4,3)/(4,218)			updateInterval			-
+elm (4,3)/(4,219)			coverage			-
+elm (4,3)/(4,220)			proprietary			-
+elm (4,3)/(4,221)			copyrightText			-
+elm (4,3)/(4,222)			copyrightNotice			-
+elm (4,3)/(4,223):contactInfo		producerContactInfo		-
+elm (4,3)/(4,224):contactInfo		supplierContactInfo		-
+elm (4,3)/(4,225):contactInfo		submissionContactInfo		-
+elm (4,3)/(4,500):accessInfo		databaseAccessInfo		-
+elm (4,3)/?				other				-
+#
+# AttributeSetInfo
+#
+elm (4,7)				attributeSetInfo	ExplainCategory
+elm (4,7)/(4,600):commonInfo		attributeSetInfoCommonInfo	-
+elm (4,7)/(4,1000)			attributeSet		AttributeSetOID
+elm (4,7)/(4,113)			description			-
+elm (4,7)/(4,102)			name				-
+elm (4,7)/(4,750):attributeType		attributes			-
+elm (4,7)/?				other				-
+#
+# AttributeDetails
+#
+elm (4,10)				attributeDetails	ExplainCategory
+elm (4,10)/(4,600):commonInfo		attributeDetailsCommonInfo	-
+elm (4,10)/(4,102)			databaseName		DatabaseName
+elm (4,10)/(4,700)			attributesBySet			-
+elm (4,10)/(4,700)/(4,701):attributeSetDetails attributeSetDetails	-
+elm (4,10)/(4,716):attributeCombinations attributeCombinations		-
+elm (4,10)/?				other				-
+
Index: /main/tags/2.25/gsdl/packages/yaz/tab/explain.att
===================================================================
--- /main/tags/2.25/gsdl/packages/yaz/tab/explain.att	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/yaz/tab/explain.att	(revision 21064)
@@ -0,0 +1,27 @@
+# The Explain Attribute Set
+#
+# $Id$
+name explain
+reference Exp-1
+
+att 1			ExplainCategory
+att 2			HumanStringLanguage
+att 3			DatabaseName
+att 4			Targetname
+att 5			AttributeSetOID
+att 6			RecordSyntaxOID
+att 7			TagSetOID
+att 8			ExtendedServicesOID
+att 9			DateAdded
+att 10			DateChanged
+att 11			DateExpired
+att 12			ElementSetName
+att 13			ProcessingContext
+att 14			ProcessingName
+att 15			TermListName
+att 16			SchemaOID
+att 17			Producer
+att 18			Supplier
+att 19			Availability
+att 20			Proprietary
+att 21			UserFee
Index: /main/tags/2.25/gsdl/packages/yaz/tab/explain.tag
===================================================================
--- /main/tags/2.25/gsdl/packages/yaz/tab/explain.tag	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/yaz/tab/explain.tag	(revision 21064)
@@ -0,0 +1,175 @@
+# Tag set for internal Explain-data management
+#
+# $Id$
+
+name explain
+reference Explain-tagset
+type 4
+include tagsetm.tag
+
+#
+# Explain categories
+#
+tag 1		categoryList					structured
+tag 2		targetInfo					structured
+tag 3		databaseInfo					structured
+tag 4		schemaInfo					structured
+tag 5		tagSetInfo					structured
+tag 6		recordSyntaxInfo				structured
+tag 7           attributeSetInfo				structured
+tag 8		termListInfo					structured
+tag 9		extendedServicesInfo				structured
+tag 10		attributeDetails				structured
+tag 11		termListDetails					structured
+tag 12		elementSetDetails				structured
+tag 13		retrievalRecordDetails				structured
+tag 14		sortDetails					structured
+tag 15		processing					structured
+tag 16		variants					structured
+tag 17		units						structured
+
+#
+# TargetInfo
+#
+tag 102		name						string
+tag 103		recentNews					string
+tag 104		icon						structured
+tag 105		namedResultSets					bool
+tag 106		multipleDbSearch				bool
+tag 107		maxResultSets					numeric
+tag 108		maxResultSize					numeric
+tag 109		maxTerms					numeric
+tag 110		timeoutInterval					intunit
+tag 111		welcomeMessage					string
+tag 112		contactInfo					structured
+tag 113		description					string
+tag 114		nicknames					structured
+tag 115		usageRest					string
+tag 116		paymentAddr					string
+tag 117		hours						string
+tag 118		dbCombinations					structured
+tag 119		addresses					structured
+tag 120		internetAddress					structured
+tag 121		host						string
+tag 122		port						numeric
+tag 123		otherAddress					structured
+tag 124		addressType					string
+tag 125		languages					structured
+tag 126		language					string
+tag 127		address						string
+tag 128		email						string
+tag 129		phone						string
+
+#
+# DatabaseInfo
+#
+tag 201		userFee						bool
+tag 202		available					bool
+tag 203		titleString					string
+tag 205		associatedDbs					structured
+tag 206		subDbs						structured
+tag 207		disclaimers					string
+tag 209		recordCount					structured
+tag 210		recordCountActual				numeric
+tag 211		recordCountApprox				numeric
+tag 212		defaultOrder					string
+tag 213		avRecordSize					numeric
+tag 214		maxRecordSize					numeric
+tag 215		hours						string
+tag 216		bestTime					string
+tag 217		lastUpdate					generalizedtime
+tag 218		updateInterval					intunit
+tag 219		coverage					string
+tag 220		proprietary					bool
+tag 221		copyrightText					string
+tag 222		copyrightNotice					string
+tag 223		producerContactInfo				structured
+tag 224		supplierContactInfo				structured
+tag 225		submissionContactInfo				structured
+tag 226		explainDatabase					null
+tag 227		keywords					string
+
+# CategoryList
+tag 300		categories					structured
+tag 301		category					structured
+tag 302		originalName					string
+tag 303		asn1Module					string
+#
+# AccessInfo
+#
+tag 500		accessinfo					structured
+tag 501		queryTypesSupported				structured
+tag 503		diagnosticSets					structured
+tag 505		attributeSetIds					structured
+tag 507		schemas						structured
+tag 509		recordSyntaxes					structured
+tag 511		resourceChallenges				structured
+tag 513		restrictedAccess				structured
+tag 514		costInfo					structured
+tag 515		variantSets					structured
+tag 516		elementSetNames					structured
+tag 517		unitSystems					structured
+tag 518         queryTypeDetails				structured
+tag 519		rpnCapabilities					structured
+tag 520		Iso8777Capabilities				structured
+tag 521         privateCapabilities				structured
+
+tag 550		rpnOperators					structured
+tag 551		rpnOperator					numeric
+tag 552		resultSetAsOperandSupported			bool
+tag 553		restrictionOperandSupported			bool
+tag 554		proximitySupport				structured
+tag 555		anySupport					bool
+tag 556 	proximityUnitsSupported				structured
+tag 557		proximityUnitSupported				structured
+tag 558		proximityUnitVal				numeric
+tag 559		proximityUnitPrivate				structured
+tag 560		proximityUnitDescription			string
+
+# CommonInfo
+
+tag 600		commonInfo					structured
+tag 601		dateAdded					generalizedtime
+tag 602		dateChanged					generalizedtime
+tag 603		expiry						generalizedtime
+tag 604		languageCode					string
+tag 605 	databaseList					structured
+
+# AttributeDetails, AttributeSetDetails
+
+tag 700		attributesBySet					structured
+tag 701		attributeSetDetails				structured
+tag 702		attributesByType				structured
+tag 703		attributeTypeDetails				structured
+tag 704		type						numeric
+tag 705		defaultIfOmitted				structured
+tag 706		defaultValue					structured
+tag 708		attributeValues					structured
+tag 709		attributeValue					structured
+tag 710		value						structured
+tag 711		partialSupport					string
+tag 712		subAttributes					structured
+tag 713		subAttribute					structured
+tag 714		superAttributes					structured
+tag 715		superAttribute					structured
+tag 716		attributeCombinations				structured
+tag 717		legalAttributeCombinations			structured
+tag 718		attributeCombination				structured
+tag 719		attributeOccurrence				structured
+tag 720		mustBeSupplied					bool
+tag 721		anyOrNone					string
+tag 722		specific					structured
+
+#
+# AttributeSetInfo
+#
+tag 750		attributes					structured
+tag 751		attributeType					structured
+tag 752		equivalentAttribute				structured
+#
+# General tags for list members, etc.
+#
+tag 1000	oid						oid
+tag 1001	string						string
+tag 1002	numeric						numeric
+
Index: /main/tags/2.25/gsdl/packages/yaz/tab/generic.tag
===================================================================
--- /main/tags/2.25/gsdl/packages/yaz/tab/generic.tag	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/yaz/tab/generic.tag	(revision 21064)
@@ -0,0 +1,7 @@
+# Generic tags - including tagsetM and tagsetG.
+#
+# $Id$
+name generic
+
+include tagsetm.tag
+include tagsetg.tag
Index: /main/tags/2.25/gsdl/packages/yaz/tab/gils-a.est
===================================================================
--- /main/tags/2.25/gsdl/packages/yaz/tab/gils-a.est	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/yaz/tab/gils-a.est	(revision 21064)
@@ -0,0 +1,7 @@
+simpleelement (1,10)
+simpleelement (1,12)
+simpleelement (2,1)
+simpleelement (1,14)
+simpleelement (4,1)
+simpleelement (4,52)
+simpleelement (2,6)
Index: /main/tags/2.25/gsdl/packages/yaz/tab/gils-b.est
===================================================================
--- /main/tags/2.25/gsdl/packages/yaz/tab/gils-b.est	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/yaz/tab/gils-b.est	(revision 21064)
@@ -0,0 +1,10 @@
+# $Id$
+simpleelement (1,1)
+simpleelement (1,10)
+simpleelement (1,12)
+simpleelement (2,1)
+simpleelement (1,14)
+simpleelement (1,16)
+simpleelement (4,1)
+simpleelement (4,52)
+simpleelement (4,70)/(4,17)
Index: /main/tags/2.25/gsdl/packages/yaz/tab/gils-f.est
===================================================================
--- /main/tags/2.25/gsdl/packages/yaz/tab/gils-f.est	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/yaz/tab/gils-f.est	(revision 21064)
@@ -0,0 +1,2 @@
+# $Id$
+simpleelement ?
Index: /main/tags/2.25/gsdl/packages/yaz/tab/gils-g.est
===================================================================
--- /main/tags/2.25/gsdl/packages/yaz/tab/gils-g.est	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/yaz/tab/gils-g.est	(revision 21064)
@@ -0,0 +1,17 @@
+# $Id$
+simpleelement (1,1)
+simpleelement (1,10)
+simpleelement (1,12)
+simpleelement (2,1)
+simpleelement (1,14)
+simpleelement (1,16)
+simpleelement (4,1)
+simpleelement (4,52)
+simpleelement (4,98)
+
+#
+# These are not formally required by GILS
+#
+simpleelement (4,59)
+simpleelement (4,70)
+simpleelement (4,97)
Index: /main/tags/2.25/gsdl/packages/yaz/tab/gils-summary.map
===================================================================
--- /main/tags/2.25/gsdl/packages/yaz/tab/gils-summary.map	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/yaz/tab/gils-summary.map	(revision 21064)
@@ -0,0 +1,12 @@
+#
+# This table maps GILS-records to the Summary (abstract) syntax
+#
+
+targetname summary
+targetref Summary
+
+map title 		/(4,0)
+map originator		/(4,1)
+map localControlNumber  /(4,12)
+map rank		/(4,14)
+map abstract		/(4,16)
Index: /main/tags/2.25/gsdl/packages/yaz/tab/gils-usmarc.map
===================================================================
--- /main/tags/2.25/gsdl/packages/yaz/tab/gils-usmarc.map	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/yaz/tab/gils-usmarc.map	(revision 21064)
@@ -0,0 +1,78 @@
+#
+# This table maps records in the GILS abstract syntax to the USMARC one
+#
+
+targetname usmarc
+targetref USmarc
+
+map rank			/(3,999)/(3,r)
+map localControlNumber		/(3,001)/(3,@)
+map dateLastModified		/(3,005)/(3,@)
+map ControlIdentifier		/(3,035)/(3,a)
+
+map title			/(3,245)/(3,a)
+map abstract			/(3,520)/(3,a)
+map purpose			/(3,500)/(3,a)
+map originator			/(3,710)/(3,a)
+map accessConstraints		/(3,506)/(3,a)
+map useConstraints		/(3,540)/(3,a)
+
+map distributor			/(3,270):new nodata
+map distributorName		/(3,270)/(3,p)
+map distributorOrganization	/(3,270)/(3,p)
+map distributorStreetAddress	/(3,270)/(3,a)
+map distributorCity		/(3,270)/(3,b)
+map distributorState		/(3,270)/(3,c)
+map distributorZipCode		/(3,270)/(3,e)
+map distributorCountry		/(3,270)/(3,d)
+map distributorNetworkAddress	/(3,270)/(3,m)
+map distributorHoursOfService	/(3,301)/(3,a)
+map distributorTelephone	/(3,270)/(3,k)
+map distributorFax		/(3,270)/(3,l)
+
+map resourceDescription		/(3,037)/(3,f)
+map orderProcess		/(3,037)/(3,c)
+map technicalPrerequisite	/(3,538)/(3,a)
+map availableTimePeriodStructured	/(3,045)/(3,c)
+map availableTimePeriodTextual		/(3,037)/(3,n) # Unhandled conditional
+
+map linkage			/(3,856)/(3,u)
+map linkageType			/(3,856)/(3,2)
+#map pointOfContact		/(3,856)/(3,m) # Look into this
+
+map pointOfContact		/(3,270):new nodata
+map contactName			/(3,270)/(3,p)
+map contactOrganization		/(3,270)/(3,p)
+map contactStreetAddress	/(3,270)/(3,a)
+map contactCity			/(3,270)/(3,b)
+map contactState		/(3,270)/(3,c)
+map contactZipCode		/(3,270)/(3,e)
+map contactCountry		/(3,270)/(3,d)
+map contactNetworkAddress	/(3,270)/(3,m)
+map contactHoursOfService	/(3,301)/(3,a)
+map contactTelephone		/(3,270)/(3,k)
+map contactFax			/(3,270)/(3,l)
+
+map recordSource		/(3,040)/(3,a)
+map agencyProgram		/(3,500)/(3,a)
+map sourcesOfData		/(3,537)/(3,a)
+map controlledTerm      	/(3,650)/(3,a)
+map thesaurus			/(3,650)/(3,2)
+map localSubjectTerm		/(3,653)/(3,a)
+map methodology			/(3,567)/(3,a)
+
+map boundingrectangle		/(3,034):new nodata
+map westernMost			/(3,034)/(3,d)
+map easternMost			/(3,034)/(3,e)
+map northernMost		/(3,034)/(3,f)
+map southernMost		/(3,034)/(3,g)
+
+map geographicKeywordName	/(3,651)/(3,a)
+map geographicKeywordType	/(3,655)/(3,z)  # Probably incorrect
+map timeperiodStructured	/(3,045)/(3,c)
+map timeperiodTextual		/(3,513)/(3,b)
+map crossReference              /(3,787):new     nodata
+map crossReferenceTitle		/(3,787)/(3,t)
+map crossReferenceLinkage	/(3,787)/(3,w)
+
+map supplementalInformation	/(3,500)/(3,a)
Index: /main/tags/2.25/gsdl/packages/yaz/tab/gils-variant.est
===================================================================
--- /main/tags/2.25/gsdl/packages/yaz/tab/gils-variant.est	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/yaz/tab/gils-variant.est	(revision 21064)
@@ -0,0 +1,15 @@
+#
+# This is the WAIS VARIANT element set description.
+# The empty variant parameters to the simpleelement statements simply
+# override the default.
+#
+
+defaultvariantrequest (9,1,@) (6,5,@)  # No data; variant list.
+
+simpleelement (1,10) variant
+simpleelement (1,12) variant
+simpleelement (2,1) variant
+simpleelement (2,6)
+simpleelement (1,14) variant
+simpleelement (4,1)
+simpleelement (4,52)
Index: /main/tags/2.25/gsdl/packages/yaz/tab/gils.abs
===================================================================
--- /main/tags/2.25/gsdl/packages/yaz/tab/gils.abs	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/yaz/tab/gils.abs	(revision 21064)
@@ -0,0 +1,146 @@
+# This is the abstract syntax (and most of the top-level profile info)
+# for GILS version 2.
+#
+# $Id$
+
+name gils
+reference GILS-schema
+attset gils.att
+tagset gils.tag
+varset var1.var
+
+maptab gils-usmarc.map
+maptab gils-summary.map
+
+# Element set names
+
+esetname VARIANT gils-variant.est  # for WAIS-compliance
+esetname B gils-b.est
+esetname G gils-g.est
+esetname W gils-b.est   # We don't really do bodyOfDisplay yet.
+esetname F @
+
+#all Any
+
+elm (1,1)                   schemaIdentifier		-
+elm (1,10)                  rank 			-
+elm (1,12)                  url				-
+elm (1,14)                  localControlNumber		-
+elm (2,1)                   title			!:w,!:p,!:s
+elm (4,52)                  originator			author-name-corporate
+#
+# Additional structuring of originator non-standard.
+#
+elm (4,52)/(2,7)            originatorName		author-name-corporate
+elm (4,52)/(2,10)           originatorOrganization	author-name-corporate
+elm (4,52)/(4,2)            originatorStreetAddress	author-name-corporate
+elm (4,52)/(4,3)            originatorCity		author-name-corporate
+elm (4,52)/(4,4)            originatorStateOrProvince	author-name-corporate
+elm (4,52)/(4,5)            originatorZipOrPostalCode	author-name-corporate
+elm (4,52)/(2,16)           originatorCountry		author-name-corporate
+elm (4,52)/(2,12)           originatorNetworkAddress	author-name-corporate
+elm (4,52)/(4,6)            originatorHoursofService	author-name-corporate
+elm (4,52)/(2,14)           originatorTelephone	        author-name-corporate
+elm (4,52)/(2,15)           originatorFax		author-name-corporate
+elm (2,2)                   author			!
+#
+# Additional structuring of author non-standard.
+#
+elm (2,2)/(2,7)             authorName		        author
+elm (2,2)/(2,10)            authorOrganization	        author
+elm (2,2)/(4,2)             authorStreetAddress	        author
+elm (2,2)/(4,3)             authorCity		 	author
+elm (2,2)/(4,4)             authorStateOrProvince	author
+elm (2,2)/(4,5)             authorZipOrPostalCode	author
+elm (2,2)/(2,16)            authorCountry		author
+elm (2,2)/(2,12)            authorNetworkAddress	author
+elm (2,2)/(4,6)             authorHoursofService	author
+elm (2,2)/(2,14)            authorTelephone	        author
+elm (2,2)/(2,15)            authorFax			author
+elm (2,4)                   dateOfPublication		!
+elm (2,3)                   placeOfPublication          place-publication
+elm (4,32)                  languageOfResource		code-language
+elm (2,6)                   abstract			!
+elm (4,95)                  controlledSubjectIndex	-
+elm (4,95)/(4,21)           subjectThesaurus		-
+elm (4,95)/(4,96)           subjectTermsControlled	controlled-subject-index
+elm (4,95)/(4,96)/(4,20)    controlledTerm		index-terms
+elm (4,97)                  subjectTermsUncontrolled    uncontrolled-term
+elm (4,97)/(4,22)           uncontrolledTerm		uncontrolled-term
+elm (4,71)                  spatialDomain		!
+elm (4,71)/(4,91)           boundingCoordinates		!
+elm (4,71)/(4,91)/(4,9)     westBoundingCoordinate      !:n
+elm (4,71)/(4,91)/(4,10)    eastBoundingCoordinate	!:n
+elm (4,71)/(4,91)/(4,11)    northBoundingCoordinate	!:n
+elm (4,71)/(4,91)/(4,12)    southBoundingCoordinate	!:n
+elm (4,71)/(4,92)           place			!
+elm (4,71)/(4,92)/(4,14)    placeKeywordThesaurus	-
+elm (4,71)/(4,92)/(4,13)    placeKeyword		place
+elm (4,93)                  timePeriod			!
+elm (4,93)/(4,16)           timePeriodTextual		!
+elm (4,93)/(4,101)          timePeriodStructured	!
+elm (4,93)/(4,101)/(4,15)   beginningDate		!
+elm (4,93)/(4,101)/(4,36)   endingDate			!
+elm (4,70)                  availability		!
+elm (4,70)/(4,33)           medium			material-type
+elm (4,70)/(4,90)           distributor			!
+elm (4,70)/(4,90)/(2,7)     distributorName		!
+elm (4,70)/(4,90)/(2,10)    distributorOrganization	!
+elm (4,70)/(4,90)/(4,2)     distributorStreetAddress	!
+elm (4,70)/(4,90)/(4,3)     distributorCity		!
+elm (4,70)/(4,90)/(4,4)     distributorStateOrProvince	!
+elm (4,70)/(4,90)/(4,5)     distributorZipOrPostalCode	!
+elm (4,70)/(4,90)/(2,16)    distributorCountry		!
+elm (4,70)/(4,90)/(2,12)    distributorNetworkAddress	!
+elm (4,70)/(4,90)/(4,6)     distributorHoursofService	!
+elm (4,70)/(4,90)/(2,14)    distributorTelephone	!
+elm (4,70)/(4,90)/(2,15)    distributorFax		!
+elm (4,70)/(4,7)            resourceDescription		!
+elm (4,70)/(4,55)           orderProcess		!
+elm (4,70)/(4,55)/(4,28)    orderInformation		!
+elm (4,70)/(4,55)/(4,29)    cost			!
+elm (4,70)/(4,55)/(4,30)    costInformation		!
+elm (4,70)/(4,8)            technicalPrerequisites	!
+elm (4,70)/(4,93)           availableTimePeriod		!
+elm (4,70)/(4,93)/(4,16)    availableTimeTextual	!
+elm (4,70)/(4,93)/(4,102)   availableTimeStructured	!
+elm (4,70)/(4,93)/(4,102)/(4,15)  beginningDate        available-time-structured
+elm (4,70)/(4,93)/(4,102)/(4,36)  endingDate           available-time-structured
+elm (4,70)/(4,99)           availableLinkage		!
+elm (4,70)/(4,99)/(4,18)    linkageType			!
+elm (4,70)/(4,99)/(4,17)    linkage		       available-linkage:u,linkage:u
+elm (4,57)                  sourcesOfData		!
+elm (4,58)                  methodology			!
+elm (4,53)                  accessConstraints		!
+elm (4,53)/(4,25)           generalAccessConstraints	!
+elm (4,53)/(4,26)           originatorDisseminationControl	!
+elm (4,53)/(4,27)           securityClassificationControl	!
+elm (4,54)                  useConstraints			!
+elm (4,94)                  pointOfContact		!
+elm (4,94)/(2,7)            contactName			!
+elm (4,94)/(2,10)           contactOrganization		!
+elm (4,94)/(4,2)            contactStreetAddress	!
+elm (4,94)/(4,3)            contactCity			!
+elm (4,94)/(4,4)            contactStateOrProvince	!
+elm (4,94)/(4,5)            contactZipOrPostalCode	!
+elm (4,94)/(2,16)           contactCountry		!
+elm (4,94)/(2,12)           contactNetworkAddress	!
+elm (4,94)/(4,6)            contactHoursOfService	!
+elm (4,94)/(2,14)           contactTelephone		!
+elm (4,94)/(2,15)           contactFax			!
+elm (4,59)                  supplementalInformation	-
+elm (4,51)                  purpose			!
+elm (4,56)                  agencyProgram		!
+elm (4,98)                  crossReference		!
+elm (4,98)/(2,1)            crossReferenceTitle		!
+elm (4,98)/(4,35)           crossReferenceRelationship	!
+elm (4,98)/(4,100)          crossReferenceLinkage	!
+elm (4,98)/(4,100)/(4,18)    linkageType		-
+elm (4,98)/(4,100)/(4,17)    linkage			cross-reference-linkage:u
+elm (4,31)                  scheduleNumber		!
+elm (4,1)                   controlIdentifier		identifier-standard
+elm (4,23)                  originalControlIdentifier	!
+elm (4,19)                  recordSource		!
+elm (4,34)                  languageOfRecord		!
+elm (1,16)                  dateOfLastModification	date/time-last-modified:w,date/time-last-modified:s
+elm (4,24)                  recordReviewDate		!
Index: /main/tags/2.25/gsdl/packages/yaz/tab/gils.att
===================================================================
--- /main/tags/2.25/gsdl/packages/yaz/tab/gils.att	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/yaz/tab/gils.att	(revision 21064)
@@ -0,0 +1,79 @@
+# $Id$
+name gils
+reference GILS-attset
+include bib1.att
+
+att 2000         Distributor
+att 2001	 Distributor-Name
+att 2002	 Index-Terms				# Subject-Terms-Contr.
+att 2003         Purpose
+att 2004         General-Access-Constraints
+att 2005         Use-Constraints
+att 2006         Distributor-Organization
+att 2007         Distributor-Street-Address
+att 2008         Distributor-City
+att 2009         Distributor-State-or-Province
+att 2010         Distributor-Zip-or-Postal-Code
+att 2011         Distributor-Country
+att 2012         Distributor-Network-Address
+att 2013         Distributor-Hours-of-Service
+att 2014         Distributor-Telephone
+att 2015         Distributor-Fax
+att 2016         Resource-Description
+att 2017         Order-Information
+att 2018         Technical-Prerequisites
+att 2019         Available-Time-Structured
+att 2020         Available-Time-Textual
+att 2021         Linkage
+att 2022         Linkage-Type
+att 2023         Contact-Name
+att 2024         Contact-Organization
+att 2025         Contact-Street-Address
+att 2026         Contact-City
+att 2027         Contact-State-or-Province
+att 2028         Contact-Zip-or-Postal-Code
+att 2029         Contact-Country
+att 2030         Contact-Network-Address
+att 2031         Contact-Hours-of-Service
+att 2032         Contact-Telephone
+att 2033         Contact-Fax
+att 2034         Agency-Program
+att 2035         Sources-of-Data
+att 2036         Subject-Thesaurus
+att 2037         Methodology
+att 2038         West-Bounding-Coordinate
+att 2039         East-Bounding-Coordinate
+att 2040         North-Bounding-Coordinate
+att 2041         South-Bounding-Coordinate
+att 2042         Place-Keyword
+att 2043         Place-Keyword-Thesaurus
+att 2044         Time-Period-Structured
+att 2045         Time-Period-Textual
+att 2046         Cross-Reference-Title
+att 2047         Cross-Reference-Linkage
+att 2049         Original-Control-Identifier
+att 2050         Supplemental-Information
+att 2051         Record-Review-Date
+att 2052         Originator-Dissemination-Control
+att 2053         Security-Classification-Control
+att 2054         Cost
+att 2055         Cost-Information
+att 2056         Schedule-Number
+att 2057         Controlled-Subject-Index
+att 2058         Uncontrolled-Term
+att 2059         Spatial-Domain
+att 2060         Bounding-Coordinates
+att 2061         Place
+att 2062         Time-Period
+att 2063         Availability
+att 2064         Order-Process
+att 2065         Available-Time-Period
+att 2066         Access-Constraints
+att 2067         Point-of-Contact
+att 2068         Cross-Reference
+att 2069         Available-Linkage
+att 2070         Cross-Reference-Relationship
+att 2071         Language-of-Record
+att 2072         Beginning-Date
+att 2073         Ending-Date
+att 2074         Controlled-Term
Index: /main/tags/2.25/gsdl/packages/yaz/tab/gils.tag
===================================================================
--- /main/tags/2.25/gsdl/packages/yaz/tab/gils.tag	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/yaz/tab/gils.tag	(revision 21064)
@@ -0,0 +1,68 @@
+# Tag set for GILS version 2.
+#
+# $Id$
+name gils
+type 4
+include tagsetm.tag
+include tagsetg.tag
+
+tag 1      controlIdentifier        string
+tag 2      streetAddress            string
+tag 3      city                     string
+tag 4      stateOrProvince          string
+tag 5      zipOrPostalCode          string
+tag 6      hoursOfService           string
+tag 7      resourceDescription      string
+tag 8      technicalPrerequisites   string
+tag 9      westBoundingCoordinate   intUnit
+tag 10     eastBoundingCoordinate   intUnit
+tag 11     northBoundingCoordinate  intUnit
+tag 12     southBoundingCoordinate  intUnit
+tag 13     placeKeyword             string
+tag 14     placeKeywordThesaurus    string
+tag 15     beginningDate            GeneralizedTime
+tag 16     timePeriodTextual        string
+tag 17     linkage                  string
+tag 18     linkageType              string
+tag 19     recordSource             string
+tag 20     controlledTerm           string
+tag 21     subjectThesaurus         string
+tag 22     uncontrolledTerm         string
+tag 23     originalControlIdentifier string
+tag 24     recordReviewDate         GeneralizedTime
+tag 25     generalAccessConstraints string
+tag 26     originatorDisseminationControl string
+tag 27     securityClassificationControl string
+tag 28     orderInformation         string
+tag 29     cost                     bool
+tag 30     costInformation          string
+tag 31     scheduleNumber           string
+tag 32     languageOfResource       string
+tag 33     medium                   string
+tag 34     languageOfRecord         string
+tag 35     relationship             string
+tag 36     endingDate               GeneralizedTime
+tag 51     purpose                  structured
+tag 52     originator               structured
+tag 53     accessConstraints        structured
+tag 54     useConstraints           structured
+tag 55     orderProcess             structured
+tag 56     agencyProgram            structured
+tag 57     sourcesOfData            structured
+tag 58     methodology              structured
+tag 59     supplementalInformation  structured
+tag 70     availability             structured
+tag 71     spatialDomain            structured
+tag 90     distributor              structured
+tag 91     boundingCoordinates      structured
+tag 92     place                    structured
+tag 93     timePeriod               structured
+tag 94     pointOfContact           structured
+tag 95     controlledSubjectIndex   structured
+tag 96     subjectTermsControlled   structured
+tag 97     subjectTermsUncontrolled structured
+tag 98     crossReference           structured
+tag 99     availableLinkage         structured
+tag 100    crossReferenceLinkage    structured
+tag 101    timePeriodStructured     structured
+tag 102    availableTimeStructured  structured
Index: /main/tags/2.25/gsdl/packages/yaz/tab/meta-b.est
===================================================================
--- /main/tags/2.25/gsdl/packages/yaz/tab/meta-b.est	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/yaz/tab/meta-b.est	(revision 21064)
@@ -0,0 +1,7 @@
+simpleelement (1,10)
+simpleelement (1,12)
+simpleelement (2,1)
+simpleelement (1,14)
+simpleelement (4,5)
+simpleelement (2,3)
+simpleelement (2,2):all
Index: /main/tags/2.25/gsdl/packages/yaz/tab/meta-usmarc.map
===================================================================
--- /main/tags/2.25/gsdl/packages/yaz/tab/meta-usmarc.map	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/yaz/tab/meta-usmarc.map	(revision 21064)
@@ -0,0 +1,21 @@
+targetname usmarc
+targetref USmarc
+
+map localControlNumber  /(3,001)/(3,@)
+map dateLastModified    /(3,005)/(3,@)
+
+map subject		/(3,653)/(3,a)
+map title		/(3,245)/(3,a)
+map author		/(3,700)/(3,a)
+map publisher		/(3,260)/(3,b)
+map otheragent 		/(3,710)/(3,a)
+map date		/(3,260)/(3,c)
+map identifier		/(3,024)/(3,a)
+# objectType skipped for now
+map form		/(3,538)/(3,a)
+map relation		/(3,787)/(3,a)    # complexity here
+map language		/(3,041)/(3,a)
+map source		/(3,786)/(3,a)
+# coverage skipped for now
+
+map abstract            /(3,520)/(3,a)
Index: /main/tags/2.25/gsdl/packages/yaz/tab/meta.abs
===================================================================
--- /main/tags/2.25/gsdl/packages/yaz/tab/meta.abs	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/yaz/tab/meta.abs	(revision 21064)
@@ -0,0 +1,33 @@
+# This is a simple profile based on the Dublin Core of metadata elements.
+#
+# $Id$
+
+name meta
+attset bib1.att
+tagset meta.tag
+varset var1.var
+
+esetname F @
+esetname B meta-b.est
+
+maptab meta-usmarc.map
+
+elm (2,1)		title			Title:w,Title:p
+elm (2,2)		creator			Author:w,Author:p
+elm (2,21)		subject			Subject-heading
+elm (2,17)		description		-
+elm (2,31)		publisher		Publisher
+elm (2,32)		contributor		-
+elm (2,4)		date			Date
+elm (2,22)		type			Content-type
+elm (2,27)		format			Material-type
+elm (2,28)		identifier		-
+elm (2,33)		source			-
+elm (2,20)		language		Code-language
+elm (2,30)		relation		-
+elm (2,34)		coverage		-
+elm (2,29)		rights			-
+
+# These tags are required by Zebra for GRS-1 generation
+elm (1,10)		rank			-
+elm (1,14)		localControlNumber	Local-number
Index: /main/tags/2.25/gsdl/packages/yaz/tab/meta.tag
===================================================================
--- /main/tags/2.25/gsdl/packages/yaz/tab/meta.tag	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/yaz/tab/meta.tag	(revision 21064)
@@ -0,0 +1,4 @@
+name meta
+type 4
+include tagsetg.tag
+include tagsetm.tag
Index: /main/tags/2.25/gsdl/packages/yaz/tab/summary.abs
===================================================================
--- /main/tags/2.25/gsdl/packages/yaz/tab/summary.abs	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/yaz/tab/summary.abs	(revision 21064)
@@ -0,0 +1,26 @@
+# Summary record abstract syntax
+#
+# $Id$
+
+name summary
+tagset summary.tag
+attset bib1.att
+reference Summary
+
+elm (4,0)		title			!
+elm (4,1)		author			!
+elm (4,2)		callNumber		-
+elm (4,3)		recordType		-
+elm (4,4)		bibliographicLevel	-
+elm (4,5)		formats			-
+elm (4,5)/(4,6)		format			-
+elm (4,5)/(4,6)/(4,7)   format-type		-
+elm (4,5)/(4,6)/(4,8)   format-size		-
+elm (4,5)/(4,6)/(4,9)   format-bestPosn		-
+elm (4,10)		publicationPlace	-
+elm (4,11)		publicationDate		-
+elm (4,12)		targetSystemKey		-
+elm (4,13)		satisfyingElement	-
+elm (4,14)		rank			-
+elm (4,15)		documentId		-
+elm (4,16)		otherInformation	-
Index: /main/tags/2.25/gsdl/packages/yaz/tab/summary.tag
===================================================================
--- /main/tags/2.25/gsdl/packages/yaz/tab/summary.tag	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/yaz/tab/summary.tag	(revision 21064)
@@ -0,0 +1,27 @@
+# Tagset for Summary profile
+#
+# $Id$
+
+name summary
+type 4
+
+tag	0	title			string
+tag	1	author			string
+tag	2	callNumber		string
+tag	3	recordType		string
+tag	4	bibliographicLevel	string
+
+tag	5	formats			structured
+tag	6	format			structured
+tag	7	type			string
+tag	8	size			numeric
+tag	9	bestPosn		numeric
+
+tag	10	publicationPlace	string
+tag	11	publicationDate		string
+tag	12	targetSystemKey		string
+tag	13	satisfyingElement	string
+tag	14	rank			numeric
+tag	15	documentId		string
+tag	16	abstract		string
+tag	17	otherInformation	structured
Index: /main/tags/2.25/gsdl/packages/yaz/tab/tagsetg.tag
===================================================================
--- /main/tags/2.25/gsdl/packages/yaz/tab/tagsetg.tag	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/yaz/tab/tagsetg.tag	(revision 21064)
@@ -0,0 +1,41 @@
+# TagSet-G Tags
+# $Id$
+name tagsetg
+reference TagsetG
+type 2
+
+tag	1	title					string
+tag	2	author					string
+tag	3	publicationPlace			string
+tag	4	publicationDate/date-of-publication	string
+tag	5	documentId				string
+tag	6	abstract				string
+tag	7	name					string
+tag	8	dateTime				generalizedtime
+tag	9	displayObject				octetstring
+tag	10	organization/organisation		string
+tag	11	postalAddress				string
+tag	12	networkAddress				string
+tag	13	eMailAddress				string
+tag	14	phoneNumber/telephone			string
+tag	15	faxNumber/fax				string
+tag	16	country					string
+tag	17	description				string
+tag	18	time					intunit
+tag	19	documentcontent				octetstring
+tag	20	language				string
+tag	21	subject					string
+tag	22	resourceType				string
+tag	23	city					string
+tag	24	stateOrProvince				string
+tag	25	zipOrPostalCode				string
+tag	26	cost					string
+tag 	27	format					string
+tag	28	identifier				string
+tag	29	rights					string
+tag	30	relation				string
+tag	31	publisher				string
+tag	32	contributor				string
+tag	33	source					string
+tag	34	coverage				string
+tag	35	private					string
Index: /main/tags/2.25/gsdl/packages/yaz/tab/tagsetm.tag
===================================================================
--- /main/tags/2.25/gsdl/packages/yaz/tab/tagsetm.tag	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/yaz/tab/tagsetm.tag	(revision 21064)
@@ -0,0 +1,33 @@
+# TagSet-M Tags
+#
+# $Id$
+name tagsetm
+reference TagsetM
+type 1
+
+tag	1	schemaIdentifier		oid
+tag	2	elementsOrdered			bool
+tag	3	elementOrdering			int
+tag	4	defaultTagType			int
+tag	5	defaultVariantSetId		oid
+tag	6	defaultVariantSpec		structured
+tag	7	processingInstructions		string
+tag	8	recordUsage			int
+tag	9	restriction			string
+tag	10	rank				int
+tag	11	userMessage			string
+tag	12	url				string
+tag	13	record				structured
+tag	14	local-control-number		string
+tag	15	creation-date			generalizedtime
+tag	16	dateOfLastModification/lastModified generalizedtime
+tag	17	dateOfLastReview		generalizedtime
+tag	18	score				int
+tag	19	wellKnown			string
+tag	20	recordWrapper			structured
+tag	21	defaultTagSetId			oid
+tag	22	languageOfRecord		string
+tag	23	type				string
+tag	24	scheme				string
+tag	25	costInfo			string
+tag	26	costFlag			bool
Index: /main/tags/2.25/gsdl/packages/yaz/tab/usmarc-b.est
===================================================================
--- /main/tags/2.25/gsdl/packages/yaz/tab/usmarc-b.est	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/yaz/tab/usmarc-b.est	(revision 21064)
@@ -0,0 +1,6 @@
+simpleelement (3,'001)
+simpleelement (3,'035)
+simpleelement (3,'245)
+simpleelement (3,'100)
+simpleelement (3,'710)
+simpleelement (3,'700)
Index: /main/tags/2.25/gsdl/packages/yaz/tab/usmarc.abs
===================================================================
--- /main/tags/2.25/gsdl/packages/yaz/tab/usmarc.abs	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/yaz/tab/usmarc.abs	(revision 21064)
@@ -0,0 +1,36 @@
+# $Id$
+name usmarc
+reference USmarc
+attset bib1.att
+tagset usmarc.tag
+
+marc usmarc.mar
+
+esetname B usmarc-b.est
+esetname F @
+
+# All 245 subfields mapped to title (word) and 
+# 245 subfield a mapped to tile (phrase).
+elm 245			title		-
+elm 245/?		title		!:w
+elm 245/?/a		title		!:w,!:p
+
+# 100 mapped to Author-name-personal and Author.
+elm 100			Author-name-personal	-
+elm 100/?		Author-name-personal	!:w,!:p,Author:w,Author:p
+
+# 110 mapped to Author-name-corporate and Author
+elm 110			Author-name-corporate	-
+elm 110/?		Author-name-corporate	!:w,!:p,Author:w,Author:p
+
+# 111 mapped to Author-name-conference and Author
+elm 111			Author-name-conference	-
+elm 111/?		Author-name-conference	!:w,!:p,Author:w,Author:p
+
+# Tag 260 subfield a mapped to Place-publication
+elm 260			Place-publication	-
+elm 260/?		Place-publication	-
+elm 260/?/a		Place-publication	!:w
+elm 260/?/b		Publisher		!:w
+elm 260/?/c		Date			!:w
+
Index: /main/tags/2.25/gsdl/packages/yaz/tab/usmarc.mar
===================================================================
--- /main/tags/2.25/gsdl/packages/yaz/tab/usmarc.mar	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/yaz/tab/usmarc.mar	(revision 21064)
@@ -0,0 +1,3 @@
+# $Id$
+name usmarc
+reference USmarc
Index: /main/tags/2.25/gsdl/packages/yaz/tab/usmarc.tag
===================================================================
--- /main/tags/2.25/gsdl/packages/yaz/tab/usmarc.tag	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/yaz/tab/usmarc.tag	(revision 21064)
@@ -0,0 +1,12 @@
+# Pseudo-tagset for USMARC
+#
+# $Id$
+
+name usmarc
+type 4
+include tagsetm.tag
+
+#tag 1		a		string
+#tag 2		b		string
+tag 245		245		string
+tag 100		100		string
Index: /main/tags/2.25/gsdl/packages/yaz/tab/var1.var
===================================================================
--- /main/tags/2.25/gsdl/packages/yaz/tab/var1.var	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/yaz/tab/var1.var	(revision 21064)
@@ -0,0 +1,64 @@
+# Definition of the variant set Variant-1.
+# Variant triple syntax is '<VAR class type value>'. Eg.
+# <var body iana "application/postscript"> or <var lang lang "eng">.
+#
+# $Id$
+
+name variant-1
+reference Variant-1
+
+class 1 variantId
+
+  type	1	variantId		octetstring
+
+class 2 body
+
+  type	1	iana			string
+  type	2	z39.50			string
+  type	3	other			string
+
+class 3 format
+
+  type	1	characters-per-line	int
+  type	2	line-length		int
+
+  # More types here......
+
+class 4 lang
+
+  type	1	lang			string
+  type	2	charset			int
+  type	3	charset-id		oid
+  type	4	encoding-id		oid
+  type	5	private-string		string
+
+class 5 piece
+
+  type	1	fragment-wanted		int
+  type	2	fragment-returned	int
+  type	3	start			intunit
+  type	4	end			intunit
+  type	5	howmuch			intunit
+  type	6	step			intunit
+  type	7	targettoken		octetstring
+
+class 6 metadata-requested
+
+  type	1	cost			intunit
+  type	2	size			intunit
+  type	3	hitsvar			null
+  type	4	hitsnonvar		null
+  type	5	variantlist		null
+  type	6	isvariantsupported	null
+  type	7	documentdescriptor	null
+  type	8	surrogateinformation	null
+  type	998	allmetadata		null
+  type	999	othermetadata		oid
+
+class 7	metadata-returned
+
+  type	1	cost			intunit
+
+  # More...
+
+# More classes, too...
Index: /main/tags/2.25/gsdl/packages/yaz/tab/wais-b.est
===================================================================
--- /main/tags/2.25/gsdl/packages/yaz/tab/wais-b.est	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/yaz/tab/wais-b.est	(revision 21064)
@@ -0,0 +1,9 @@
+#
+# WAIS eset.
+#
+
+simpleelement (2,1)
+simpleelement (2,7)
+simpleelement (1,16)
+simpleelement (1,18)
+simpleelement (1,14)
Index: /main/tags/2.25/gsdl/packages/yaz/tab/wais-variant.est
===================================================================
--- /main/tags/2.25/gsdl/packages/yaz/tab/wais-variant.est	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/yaz/tab/wais-variant.est	(revision 21064)
@@ -0,0 +1,19 @@
+#
+# WAIS variant eset.
+#
+
+#
+# Default is no data, variant-list, please.
+#
+
+simpleelement ?:all variant (9,1,@) (6,5,@)
+
+#
+# Empty variant-requests for the well-known elements to override default.
+#
+
+simpleelement (2,1) variant
+simpleelement (2,7) variant
+simpleelement (1,16) variant
+simpleelement (1,18) variant
+simpleelement (1,14) variant
Index: /main/tags/2.25/gsdl/packages/yaz/tab/wais.abs
===================================================================
--- /main/tags/2.25/gsdl/packages/yaz/tab/wais.abs	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/yaz/tab/wais.abs	(revision 21064)
@@ -0,0 +1,24 @@
+# WAIS profile
+#
+# $Id$
+
+name wais
+reference WAIS-schema
+attset bib1.att
+tagset generic.tag
+
+varset var1.var
+
+esetname B wais-b.est
+esetname F @
+esetname VARIANT wais-variant.est
+
+elm (2,1)		Title			!:p,!:w
+elm (2,7)		Name			!:p,!:w
+elm (2,8)		Date			!
+elm (1,18)		Score			-
+elm (1,14)		RecordId		Local-number
+
+# Tags below this point are unofficial.
+
+elm Body		BodyOfText		!
Index: /main/tags/2.25/gsdl/packages/yaz/util/Makefile.am
===================================================================
--- /main/tags/2.25/gsdl/packages/yaz/util/Makefile.am	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/yaz/util/Makefile.am	(revision 21064)
@@ -0,0 +1,14 @@
+## Copyright (C) 1994-2000, Index Data
+## All rights reserved.
+## $Id$
+
+noinst_LIBRARIES = libutil.a
+
+bin_SCRIPTS = yaz-comp
+
+EXTRA_DIST = yaz-comp
+
+INCLUDES =-I../include
+
+libutil_a_SOURCES=options.c log.c marcdisp.c oid.c wrbuf.c nmemsdup.c \
+   xmalloc.c readconf.c tpath.c nmem.c matchstr.c atoin.c 
Index: /main/tags/2.25/gsdl/packages/yaz/util/Makefile.in
===================================================================
--- /main/tags/2.25/gsdl/packages/yaz/util/Makefile.in	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/yaz/util/Makefile.in	(revision 21064)
@@ -0,0 +1,294 @@
+# Makefile.in generated automatically by automake 1.4 from Makefile.am
+
+# Copyright (C) 1994, 1995-8, 1999 Free Software Foundation, Inc.
+# This Makefile.in is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
+# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE.
+
+
+SHELL = @SHELL@
+
+srcdir = @srcdir@
+top_srcdir = @top_srcdir@
+VPATH = @srcdir@
+prefix = @prefix@
+exec_prefix = @exec_prefix@
+
+bindir = @bindir@
+sbindir = @sbindir@
+libexecdir = @libexecdir@
+datadir = @datadir@
+sysconfdir = @sysconfdir@
+sharedstatedir = @sharedstatedir@
+localstatedir = @localstatedir@
+libdir = @libdir@
+infodir = @infodir@
+mandir = @mandir@
+includedir = @includedir@
+oldincludedir = /usr/include
+
+DESTDIR =
+
+pkgdatadir = $(datadir)/@PACKAGE@
+pkglibdir = $(libdir)/@PACKAGE@
+pkgincludedir = $(includedir)/@PACKAGE@
+
+top_builddir = ..
+
+ACLOCAL = @ACLOCAL@
+AUTOCONF = @AUTOCONF@
+AUTOMAKE = @AUTOMAKE@
+AUTOHEADER = @AUTOHEADER@
+
+INSTALL = @INSTALL@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@ $(AM_INSTALL_PROGRAM_FLAGS)
+INSTALL_DATA = @INSTALL_DATA@
+INSTALL_SCRIPT = @INSTALL_SCRIPT@
+transform = @program_transform_name@
+
+NORMAL_INSTALL = :
+PRE_INSTALL = :
+POST_INSTALL = :
+NORMAL_UNINSTALL = :
+PRE_UNINSTALL = :
+POST_UNINSTALL = :
+ASNMODULE = @ASNMODULE@
+CC = @CC@
+CPP = @CPP@
+ILLLIB = @ILLLIB@
+ILLMODULE = @ILLMODULE@
+MAKEINFO = @MAKEINFO@
+PACKAGE = @PACKAGE@
+RANLIB = @RANLIB@
+SUBDIRS_VAR = @SUBDIRS_VAR@
+VERSION = @VERSION@
+have_sgml2html = @have_sgml2html@
+have_sgml2latex = @have_sgml2latex@
+have_sgml2txt = @have_sgml2txt@
+
+noinst_LIBRARIES = libutil.a
+
+bin_SCRIPTS = yaz-comp
+
+EXTRA_DIST = yaz-comp
+
+INCLUDES = -I../include
+
+libutil_a_SOURCES = options.c log.c marcdisp.c oid.c wrbuf.c nmemsdup.c    xmalloc.c readconf.c tpath.c nmem.c matchstr.c atoin.c 
+
+mkinstalldirs = $(SHELL) $(top_srcdir)/mkinstalldirs
+CONFIG_CLEAN_FILES = 
+LIBRARIES =  $(noinst_LIBRARIES)
+
+
+DEFS = @DEFS@ -I. -I$(srcdir) 
+CPPFLAGS = @CPPFLAGS@
+LDFLAGS = @LDFLAGS@
+LIBS = @LIBS@
+libutil_a_LIBADD = 
+libutil_a_OBJECTS =  options.o log.o marcdisp.o oid.o wrbuf.o nmemsdup.o \
+xmalloc.o readconf.o tpath.o nmem.o matchstr.o atoin.o
+AR = ar
+SCRIPTS =  $(bin_SCRIPTS)
+
+CFLAGS = @CFLAGS@
+COMPILE = $(CC) $(DEFS) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
+CCLD = $(CC)
+LINK = $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(LDFLAGS) -o $@
+DIST_COMMON =  Makefile.am Makefile.in
+
+
+DISTFILES = $(DIST_COMMON) $(SOURCES) $(HEADERS) $(TEXINFOS) $(EXTRA_DIST)
+
+TAR = gtar
+GZIP_ENV = --best
+SOURCES = $(libutil_a_SOURCES)
+OBJECTS = $(libutil_a_OBJECTS)
+
+all: all-redirect
+.SUFFIXES:
+.SUFFIXES: .S .c .o .s
+$(srcdir)/Makefile.in: Makefile.am $(top_srcdir)/configure.in $(ACLOCAL_M4) 
+	cd $(top_srcdir) && $(AUTOMAKE) --gnu --include-deps util/Makefile
+
+Makefile: $(srcdir)/Makefile.in  $(top_builddir)/config.status
+	cd $(top_builddir) \
+	  && CONFIG_FILES=$(subdir)/$@ CONFIG_HEADERS= $(SHELL) ./config.status
+
+
+mostlyclean-noinstLIBRARIES:
+
+clean-noinstLIBRARIES:
+	-test -z "$(noinst_LIBRARIES)" || rm -f $(noinst_LIBRARIES)
+
+distclean-noinstLIBRARIES:
+
+maintainer-clean-noinstLIBRARIES:
+
+.c.o:
+	$(COMPILE) -c $<
+
+.s.o:
+	$(COMPILE) -c $<
+
+.S.o:
+	$(COMPILE) -c $<
+
+mostlyclean-compile:
+	-rm -f *.o core *.core
+
+clean-compile:
+
+distclean-compile:
+	-rm -f *.tab.c
+
+maintainer-clean-compile:
+
+libutil.a: $(libutil_a_OBJECTS) $(libutil_a_DEPENDENCIES)
+	-rm -f libutil.a
+	$(AR) cru libutil.a $(libutil_a_OBJECTS) $(libutil_a_LIBADD)
+	$(RANLIB) libutil.a
+
+install-binSCRIPTS: $(bin_SCRIPTS)
+	@$(NORMAL_INSTALL)
+	$(mkinstalldirs) $(DESTDIR)$(bindir)
+	@list='$(bin_SCRIPTS)'; for p in $$list; do \
+	  if test -f $$p; then \
+	    echo " $(INSTALL_SCRIPT) $$p $(DESTDIR)$(bindir)/`echo $$p|sed '$(transform)'`"; \
+	    $(INSTALL_SCRIPT) $$p $(DESTDIR)$(bindir)/`echo $$p|sed '$(transform)'`; \
+	  else if test -f $(srcdir)/$$p; then \
+	    echo " $(INSTALL_SCRIPT) $(srcdir)/$$p $(DESTDIR)$(bindir)/`echo $$p|sed '$(transform)'`"; \
+	    $(INSTALL_SCRIPT) $(srcdir)/$$p $(DESTDIR)$(bindir)/`echo $$p|sed '$(transform)'`; \
+	  else :; fi; fi; \
+	done
+
+uninstall-binSCRIPTS:
+	@$(NORMAL_UNINSTALL)
+	list='$(bin_SCRIPTS)'; for p in $$list; do \
+	  rm -f $(DESTDIR)$(bindir)/`echo $$p|sed '$(transform)'`; \
+	done
+
+tags: TAGS
+
+ID: $(HEADERS) $(SOURCES) $(LISP)
+	list='$(SOURCES) $(HEADERS)'; \
+	unique=`for i in $$list; do echo $$i; done | \
+	  awk '    { files[$$0] = 1; } \
+	       END { for (i in files) print i; }'`; \
+	here=`pwd` && cd $(srcdir) \
+	  && mkid -f$$here/ID $$unique $(LISP)
+
+TAGS:  $(HEADERS) $(SOURCES)  $(TAGS_DEPENDENCIES) $(LISP)
+	tags=; \
+	here=`pwd`; \
+	list='$(SOURCES) $(HEADERS)'; \
+	unique=`for i in $$list; do echo $$i; done | \
+	  awk '    { files[$$0] = 1; } \
+	       END { for (i in files) print i; }'`; \
+	test -z "$(ETAGS_ARGS)$$unique$(LISP)$$tags" \
+	  || (cd $(srcdir) && etags $(ETAGS_ARGS) $$tags  $$unique $(LISP) -o $$here/TAGS)
+
+mostlyclean-tags:
+
+clean-tags:
+
+distclean-tags:
+	-rm -f TAGS ID
+
+maintainer-clean-tags:
+
+distdir = $(top_builddir)/$(PACKAGE)-$(VERSION)/$(subdir)
+
+subdir = util
+
+distdir: $(DISTFILES)
+	@for file in $(DISTFILES); do \
+	  d=$(srcdir); \
+	  if test -d $$d/$$file; then \
+	    cp -pr $$/$$file $(distdir)/$$file; \
+	  else \
+	    test -f $(distdir)/$$file \
+	    || ln $$d/$$file $(distdir)/$$file 2> /dev/null \
+	    || cp -p $$d/$$file $(distdir)/$$file || :; \
+	  fi; \
+	done
+
+info-am:
+info: info-am
+dvi-am:
+dvi: dvi-am
+check-am: all-am
+check: check-am
+installcheck-am:
+installcheck: installcheck-am
+install-exec-am: install-binSCRIPTS
+install-exec: install-exec-am
+
+install-data-am:
+install-data: install-data-am
+
+install-am: all-am
+	@$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
+install: install-am
+uninstall-am: uninstall-binSCRIPTS
+uninstall: uninstall-am
+all-am: Makefile $(LIBRARIES) $(SCRIPTS)
+all-redirect: all-am
+install-strip:
+	$(MAKE) $(AM_MAKEFLAGS) AM_INSTALL_PROGRAM_FLAGS=-s install
+installdirs:
+	$(mkinstalldirs)  $(DESTDIR)$(bindir)
+
+
+mostlyclean-generic:
+
+clean-generic:
+
+distclean-generic:
+	-rm -f Makefile $(CONFIG_CLEAN_FILES)
+	-rm -f config.cache config.log stamp-h stamp-h[0-9]*
+
+maintainer-clean-generic:
+mostlyclean-am:  mostlyclean-noinstLIBRARIES mostlyclean-compile \
+		mostlyclean-tags mostlyclean-generic
+
+mostlyclean: mostlyclean-am
+
+clean-am:  clean-noinstLIBRARIES clean-compile clean-tags clean-generic \
+		mostlyclean-am
+
+clean: clean-am
+
+distclean-am:  distclean-noinstLIBRARIES distclean-compile \
+		distclean-tags distclean-generic clean-am
+
+distclean: distclean-am
+
+maintainer-clean-am:  maintainer-clean-noinstLIBRARIES \
+		maintainer-clean-compile maintainer-clean-tags \
+		maintainer-clean-generic distclean-am
+	@echo "This command is intended for maintainers to use;"
+	@echo "it deletes files that may require special tools to rebuild."
+
+maintainer-clean: maintainer-clean-am
+
+.PHONY: mostlyclean-noinstLIBRARIES distclean-noinstLIBRARIES \
+clean-noinstLIBRARIES maintainer-clean-noinstLIBRARIES \
+mostlyclean-compile distclean-compile clean-compile \
+maintainer-clean-compile uninstall-binSCRIPTS install-binSCRIPTS tags \
+mostlyclean-tags distclean-tags clean-tags maintainer-clean-tags \
+distdir info-am info dvi-am dvi check check-am installcheck-am \
+installcheck install-exec-am install-exec install-data-am install-data \
+install-am install uninstall-am uninstall all-redirect all-am all \
+installdirs mostlyclean-generic distclean-generic clean-generic \
+maintainer-clean-generic clean mostlyclean distclean maintainer-clean
+
+
+# Tell versions [3.59,3.63) of GNU make to not export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:
Index: /main/tags/2.25/gsdl/packages/yaz/util/atoin.c
===================================================================
--- /main/tags/2.25/gsdl/packages/yaz/util/atoin.c	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/yaz/util/atoin.c	(revision 21064)
@@ -0,0 +1,40 @@
+/*
+ * Copyright (c) 1997, Index Data
+ * See the file LICENSE for details.
+ * Sebastian Hammer, Adam Dickmeiss
+ *
+ * $Log$
+ * Revision 1.1  2000/08/03 03:12:06  johnmcp
+ * Added the YAZ toolkit source to the packages directory (for z39.50 stuff)
+ *
+ * Revision 1.3  2000/02/29 13:44:55  adam
+ * Check for config.h (currently not generated).
+ *
+ * Revision 1.2  1999/11/30 13:47:12  adam
+ * Improved installation. Moved header files to include/yaz.
+ *
+ * Revision 1.1  1997/09/04 07:52:27  adam
+ * Moved atoi_n function to separate source file.
+ *
+ */
+
+#if HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <string.h>
+#include <ctype.h>
+#include <yaz/yaz-util.h>
+
+int atoi_n (const char *buf, int len)
+{
+    int val = 0;
+
+    while (--len >= 0)
+    {
+        if (isdigit (*buf))
+            val = val*10 + (*buf - '0');
+	buf++;
+    }
+    return val;
+}
Index: /main/tags/2.25/gsdl/packages/yaz/util/log.c
===================================================================
--- /main/tags/2.25/gsdl/packages/yaz/util/log.c	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/yaz/util/log.c	(revision 21064)
@@ -0,0 +1,280 @@
+/*
+ * Copyright (c) 1995-2000, Index Data
+ * See the file LICENSE for details.
+ * Sebastian Hammer, Adam Dickmeiss
+ *
+ * $Log$
+ * Revision 1.1  2000/08/03 03:12:06  johnmcp
+ * Added the YAZ toolkit source to the packages directory (for z39.50 stuff)
+ *
+ * Revision 1.22  2000/02/29 13:44:55  adam
+ * Check for config.h (currently not generated).
+ *
+ * Revision 1.21  2000/02/28 11:20:06  adam
+ * Using autoconf. New definitions: YAZ_BEGIN_CDECL/YAZ_END_CDECL.
+ *
+ * Revision 1.20  1999/11/30 13:47:12  adam
+ * Improved installation. Moved header files to include/yaz.
+ *
+ * Revision 1.19  1999/08/27 09:40:32  adam
+ * Renamed logf function to yaz_log. Removed VC++ project files.
+ *
+ * Revision 1.18  1998/10/28 10:27:00  adam
+ * New functions log_init_file, log_init_level, log_init_prefix.
+ *
+ * Revision 1.17  1997/12/09 16:11:02  adam
+ * Assume strerror is defined on Unixes as well. It's standard ANSI.
+ *
+ * Revision 1.16  1997/10/06 08:55:07  adam
+ * Changed log_init so that previous (if any) is closed.
+ *
+ * Revision 1.15  1997/09/29 07:13:13  adam
+ * Minor changes.
+ *
+ * Revision 1.14  1997/09/18 08:48:09  adam
+ * Fixed minor bug that caused log_init to ignore filename.
+ *
+ * Revision 1.13  1997/09/01 08:54:13  adam
+ * New windows NT/95 port using MSV5.0. Made prefix query handling
+ * thread safe. The function options ignores empty arguments when met.
+ *
+ * Revision 1.12  1997/05/01 15:08:14  adam
+ * Added log_mask_str_x routine.
+ *
+ * Revision 1.11  1996/02/05 12:24:32  adam
+ * Implemented log_event_{start,end}-functions.
+ *
+ * Revision 1.10  1995/12/06  09:51:27  quinn
+ * Fixed the log-prefix buffer - it was too small and the setup code lacked
+ * a bounds-check.
+ *
+ * Revision 1.9  1995/09/29  17:12:34  quinn
+ * Smallish
+ *
+ * Revision 1.8  1995/09/27  15:03:02  quinn
+ * Modified function heads & prototypes.
+ *
+ * Revision 1.7  1995/06/19  12:40:18  quinn
+ * Added log_file()
+ *
+ * Revision 1.6  1995/06/15  15:45:03  quinn
+ * Added date info.
+ *
+ * Revision 1.5  1995/05/16  08:51:11  quinn
+ * License, documentation, and memory fixes
+ *
+ * Revision 1.4  1995/05/15  11:56:55  quinn
+ * Debuggng & adjustments.
+ *
+ * Revision 1.3  1995/04/10  10:23:51  quinn
+ * Fixes.
+ *
+ * Revision 1.2  1995/03/31  10:16:55  quinn
+ * Fixed logging.
+ *
+ * Revision 1.1  1995/03/30  10:26:53  quinn
+ * Logging system
+ *
+ * Revision 1.9  1994/12/12  12:09:02  quinn
+ * Changes
+ *
+ * Revision 1.8  1994/11/22  13:15:38  quinn
+ * Simple
+ *
+ * Revision 1.7  1994/10/05  10:16:11  quinn
+ * Added xrealloc. Fixed bug in log.
+ *
+ * Revision 1.6  1994/10/04  14:02:19  quinn
+ * Fixed log_init
+ *
+ * Revision 1.5  1994/09/28  13:07:41  adam
+ * Implemented log_mask_str.
+ *
+ * Revision 1.4  1994/09/27  20:04:13  quinn
+ * Added fflush.
+ *
+ * Revision 1.3  1994/08/18  08:18:48  quinn
+ * Added prefix to log_init.
+ *
+ * Revision 1.2  1994/08/17  14:27:53  quinn
+ * added LOG_ERRNO
+ *
+ * Revision 1.1  1994/08/17  13:23:15  quinn
+ * First version
+ * Added log.c
+ *
+ */
+
+#if HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <ctype.h>
+#include <string.h>
+#include <stdarg.h>
+#include <errno.h>
+#include <time.h>
+#include <yaz/log.h>
+
+#define HAS_STRERROR 1
+
+#if HAS_STRERROR
+
+#else
+char *strerror(int n)
+{
+        extern char *sys_errlist[];
+        return sys_errlist[n];
+}
+
+#endif
+
+static int l_level = LOG_DEFAULT_LEVEL;
+static FILE *l_file = NULL;
+static char l_prefix[512] = "log";
+
+static struct {
+    int mask;
+    char *name;
+} mask_names[] =
+{
+    { LOG_FATAL, "fatal"},
+    { LOG_DEBUG, "debug"},
+    { LOG_WARN,  "warn" },
+    { LOG_LOG,   "log"  },
+    { LOG_ERRNO, ""},
+    { LOG_ALL,   "all"  },
+    { 0,         "none" },
+    { 0, NULL }
+};  
+
+FILE *log_file(void)
+{
+    if (!l_file)
+        l_file = stderr;
+    return l_file;
+}
+
+void log_init_file (const char *fname)
+{
+    FILE *new_file;
+    if (!l_file)
+        l_file = stderr;
+    if (!fname || !*fname)
+        return;
+    if (!(new_file = fopen(fname, "a")))
+        return;
+    if (l_file != stderr)
+    {
+        fclose (l_file);
+    }
+    setvbuf(new_file, 0, _IONBF, 0);
+    l_file = new_file;
+}
+
+void log_init_level (int level)
+{
+    l_level = level;
+}
+
+void log_init_prefix (const char *prefix)
+{
+    if (prefix && *prefix)
+    	sprintf(l_prefix, "%.512s", prefix);
+}
+
+void log_init(int level, const char *prefix, const char *fname)
+{
+    log_init_level (level);
+    log_init_prefix (prefix);
+    log_init_file (fname);
+}
+
+static void (*start_hook_func)(int, const char *, void *) = NULL;
+static void *start_hook_info;
+static void (*end_hook_func)(int, const char *, void *) = NULL;
+static void *end_hook_info;
+
+void log_event_start (void (*func)(int, const char *, void *), void *info)
+{
+    start_hook_func = func;
+    start_hook_info = info;
+}
+
+void log_event_end (void (*func)(int, const char *, void *), void *info)
+{
+    end_hook_func = func;
+    end_hook_info = info;
+}
+
+void yaz_log(int level, const char *fmt, ...)
+{
+    va_list ap;
+    char buf[4096], flags[1024];
+    int i;
+    time_t ti;
+    struct tm *tim;
+    char tbuf[50];
+    int o_level = level;
+
+    if (!(level & l_level))
+    	return;
+    if (!l_file)
+        l_file = stderr;
+    *flags = '\0';
+    for (i = 0; level && mask_names[i].name; i++)
+    	if (mask_names[i].mask & level)
+    	{
+	    if (*mask_names[i].name)
+		sprintf(flags + strlen(flags), "[%s]", mask_names[i].name);
+	    level -= mask_names[i].mask;
+	}
+    va_start(ap, fmt);
+    vsprintf(buf, fmt, ap);
+    if (o_level & LOG_ERRNO)
+    	sprintf(buf + strlen(buf), " [%s]", strerror(errno));
+    if (start_hook_func)
+        (*start_hook_func)(o_level, buf, start_hook_info);
+    ti = time(0);
+    tim = localtime(&ti);
+    strftime(tbuf, 50, "%H:%M:%S-%d/%m", tim);
+    fprintf(l_file, "%s: %s: %s %s\n", tbuf, l_prefix, flags, buf);
+    fflush(l_file);
+    if (end_hook_func)
+	(*end_hook_func)(o_level, buf, end_hook_info);
+}
+
+int log_mask_str (const char *str)
+{
+    return log_mask_str_x (str, LOG_DEFAULT_LEVEL);
+}
+
+int log_mask_str_x (const char *str, int level)
+{
+    const char *p;
+    int i;
+
+    while (*str)
+    {
+        for (p = str; *p && *p != ','; p++)
+            ;
+        if (*str == '-' || isdigit(*str))
+            level = atoi (str);
+        else
+            for (i = 0; mask_names[i].name; i++)
+                if (strlen (mask_names[i].name) == (size_t) (p-str) &&
+                    memcmp (mask_names[i].name, str, p-str) == 0)
+                {
+                    if (mask_names[i].mask)
+                        level |= mask_names[i].mask;
+                    else
+                        level = 0;
+                }
+        if (*p == ',')
+            p++;
+        str = p;
+    }
+    return level;
+}
Index: /main/tags/2.25/gsdl/packages/yaz/util/marcdisp.c
===================================================================
--- /main/tags/2.25/gsdl/packages/yaz/util/marcdisp.c	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/yaz/util/marcdisp.c	(revision 21064)
@@ -0,0 +1,160 @@
+/*
+ * Copyright (c) 1995-2000, Index Data
+ * See the file LICENSE for details.
+ *
+ * $Log$
+ * Revision 1.1  2000/08/03 03:12:07  johnmcp
+ * Added the YAZ toolkit source to the packages directory (for z39.50 stuff)
+ *
+ * Revision 1.11  2000/02/29 13:44:55  adam
+ * Check for config.h (currently not generated).
+ *
+ * Revision 1.10  2000/02/05 10:47:19  adam
+ * Identifier-length and indicator-lenght no longer set to 2 (forced).
+ *
+ * Revision 1.9  1999/12/21 16:24:48  adam
+ * More robust ISO2709 handling (in case of real bad formats).
+ *
+ * Revision 1.8  1999/11/30 13:47:12  adam
+ * Improved installation. Moved header files to include/yaz.
+ *
+ * Revision 1.7  1997/09/24 13:29:40  adam
+ * Added verbose option -v to marcdump utility.
+ *
+ * Revision 1.6  1997/09/04 07:52:27  adam
+ * Moved atoi_n function to separate source file.
+ *
+ * Revision 1.5  1997/05/01 15:08:15  adam
+ * Added log_mask_str_x routine.
+ *
+ * Revision 1.4  1995/09/29 17:12:34  quinn
+ * Smallish
+ *
+ * Revision 1.3  1995/09/27  15:03:03  quinn
+ * Modified function heads & prototypes.
+ *
+ * Revision 1.2  1995/05/16  08:51:12  quinn
+ * License, documentation, and memory fixes
+ *
+ * Revision 1.1  1995/04/10  10:28:46  quinn
+ * Added copy of CCL and MARC display
+ *
+ */
+
+#if HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <stdio.h>
+#include <string.h>
+#include <ctype.h>
+#include <yaz/marcdisp.h>
+#include <yaz/yaz-util.h>
+
+int marc_display_ex (const char *buf, FILE *outf, int debug)
+{
+    int entry_p;
+    int record_length;
+    int indicator_length;
+    int identifier_length;
+    int base_address;
+    int length_data_entry;
+    int length_starting;
+    int length_implementation;
+
+    if (!outf)
+        outf = stdout;
+    record_length = atoi_n (buf, 5);
+    if (record_length < 25)
+        return -1;
+    if (isdigit(buf[10]))
+        indicator_length = atoi_n (buf+10, 1);
+    else
+        indicator_length = 2;
+    if (isdigit(buf[11]))
+	identifier_length = atoi_n (buf+11, 1);
+    else
+        identifier_length = 2;
+    base_address = atoi_n (buf+12, 4);
+
+    length_data_entry = atoi_n (buf+20, 1);
+    length_starting = atoi_n (buf+21, 1);
+    length_implementation = atoi_n (buf+22, 1);
+
+    if (debug)
+    {
+	fprintf (outf, "Record length         %5d\n", record_length);
+	fprintf (outf, "Indicator length      %5d\n", indicator_length);
+	fprintf (outf, "Identifier length     %5d\n", identifier_length);
+	fprintf (outf, "Base address          %5d\n", base_address);
+	fprintf (outf, "Length data entry     %5d\n", length_data_entry);
+	fprintf (outf, "Length starting       %5d\n", length_starting);
+	fprintf (outf, "Length implementation %5d\n", length_implementation);
+    }
+    for (entry_p = 24; buf[entry_p] != ISO2709_FS; )
+    {
+        entry_p += 3+length_data_entry+length_starting;
+        if (entry_p >= record_length)
+            return -1;
+    }
+    base_address = entry_p+1;
+    for (entry_p = 24; buf[entry_p] != ISO2709_FS; )
+    {
+        int data_length;
+	int data_offset;
+	int end_offset;
+	int i, j;
+	char tag[4];
+
+        memcpy (tag, buf+entry_p, 3);
+	entry_p += 3;
+        tag[3] = '\0';
+	if (debug)
+	    fprintf (outf, "Tag: ");
+	fprintf (outf, "%s ", tag);
+	data_length = atoi_n (buf+entry_p, length_data_entry);
+	entry_p += length_data_entry;
+	data_offset = atoi_n (buf+entry_p, length_starting);
+	entry_p += length_starting;
+	i = data_offset + base_address;
+	end_offset = i+data_length-1;
+	if (debug)
+	    fprintf (outf, " Ind: ");
+        if (memcmp (tag, "00", 2) && indicator_length)
+	{
+            for (j = 0; j<indicator_length; j++)
+		fprintf (outf, "%c", buf[i++]);
+	}
+	if (debug)
+	    fprintf (outf, " Fields: ");
+	while (buf[i] != ISO2709_RS && buf[i] != ISO2709_FS && i < end_offset)
+	{
+            if (memcmp (tag, "00", 2) && identifier_length)
+	    {
+	        i++;
+	        fprintf (outf, " $"); 
+                for (j = 1; j<identifier_length; j++)
+                    fprintf (outf, "%c", buf[i++]);
+		fprintf (outf, " ");
+	        while (buf[i] != ISO2709_RS && buf[i] != ISO2709_IDFS &&
+	               buf[i] != ISO2709_FS && i < end_offset)
+	            fprintf (outf, "%c", buf[i++]);
+	    }
+	    else
+	        fprintf (outf, "%c", buf[i++]);
+	}
+	fprintf (outf, "\n");
+	if (i < end_offset)
+	    fprintf (outf, "-- separator but not at end of field\n");
+	if (buf[i] != ISO2709_RS && buf[i] != ISO2709_FS)
+	    fprintf (outf, "-- no separator at end of field\n");
+    }
+    return record_length;
+}
+
+int marc_display (const char *buf, FILE *outf)
+{
+    return marc_display_ex (buf, outf, 0);
+}
+
+
Index: /main/tags/2.25/gsdl/packages/yaz/util/matchstr.c
===================================================================
--- /main/tags/2.25/gsdl/packages/yaz/util/matchstr.c	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/yaz/util/matchstr.c	(revision 21064)
@@ -0,0 +1,107 @@
+/*
+ * Copyright (c) 1995-2000, Index Data.
+ * See the file LICENSE for details.
+ * Sebastian Hammer, Adam Dickmeiss
+ *
+ * $Log$
+ * Revision 1.1  2000/08/03 03:12:07  johnmcp
+ * Added the YAZ toolkit source to the packages directory (for z39.50 stuff)
+ *
+ * Revision 1.5  2000/02/29 13:44:55  adam
+ * Check for config.h (currently not generated).
+ *
+ * Revision 1.4  1999/11/30 13:47:12  adam
+ * Improved installation. Moved header files to include/yaz.
+ *
+ * Revision 1.3  1999/10/19 12:35:42  adam
+ * Minor bug fix (bug introduced by previous commit).
+ *
+ * Revision 1.2  1999/10/15 11:35:41  adam
+ * Character '.' matches any single character.
+ *
+ * Revision 1.1  1999/06/08 10:10:16  adam
+ * New sub directory zutil. Moved YAZ Compiler to be part of YAZ tree.
+ *
+ * Revision 1.7  1997/09/30 11:47:47  adam
+ * Added function 'cause checkergcc doesn't include assert handler.
+ *
+ * Revision 1.6  1997/09/04 07:54:34  adam
+ * Right hande side operand of yaz_matchstr may include a ? in
+ * which case it returns "match ok".
+ *
+ * Revision 1.5  1997/07/21 12:48:11  adam
+ * Removed windows DLL stubs.
+ *
+ * Revision 1.4  1997/05/01 15:07:55  adam
+ * Added DLL entry point routines.
+ *
+ * Revision 1.3  1996/10/29 13:36:28  adam
+ * Added header.
+ *
+ * Revision 1.2  1996/02/20 17:58:42  adam
+ * Added const to yaz_matchstr.
+ *
+ * Revision 1.1  1996/02/20  16:33:06  quinn
+ * Moved matchstr to global util
+ *
+ * Revision 1.1  1995/11/01  11:56:08  quinn
+ * Added Retrieval (data management) functions en masse.
+ *
+ *
+ */
+#if HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <stdio.h>
+#include <assert.h>
+#include <ctype.h>
+#include <yaz/yaz-util.h>
+
+/*
+ * Match strings, independently of case and occurences of '-'.
+ * fairly inefficient - will be replaced with an indexing scheme for
+ * the various subsystems if we get a bottleneck here.
+ */
+
+int yaz_matchstr(const char *s1, const char *s2)
+{
+    while (*s1 && *s2)
+    {
+	char c1 = *s1;
+	char c2 = *s2;
+
+        if (c2 == '?')
+            return 0;
+	if (c1 == '-')
+	    c1 = *++s1;
+	if (c2 == '-')
+	    c2 = *++s2;
+	if (!c1 || !c2)
+	    break;
+        if (c2 != '.')
+        {
+	    if (isupper(c1))
+	        c1 = tolower(c1);
+	    if (isupper(c2))
+	        c2 = tolower(c2);
+	    if (c1 != c2)
+	        break;
+        }
+	s1++;
+	s2++;
+    }
+    return *s1 || *s2;
+}
+
+#ifdef __GNUC__
+#ifdef __CHECKER__
+void __assert_fail (const char *assertion, const char *file, 
+                    unsigned int line, const char *function)
+{
+    fprintf (stderr, "%s in file %s line %d func %s\n",
+             assertion, file, line, function);
+    abort ();
+}
+#endif
+#endif
Index: /main/tags/2.25/gsdl/packages/yaz/util/nmem.c
===================================================================
--- /main/tags/2.25/gsdl/packages/yaz/util/nmem.c	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/yaz/util/nmem.c	(revision 21064)
@@ -0,0 +1,405 @@
+/*
+ * Copyright (c) 1995-2000, Index Data.
+ * See the file LICENSE for details.
+ * Sebastian Hammer, Adam Dickmeiss
+ *
+ * $Log$
+ * Revision 1.1  2000/08/03 03:12:08  johnmcp
+ * Added the YAZ toolkit source to the packages directory (for z39.50 stuff)
+ *
+ * Revision 1.21  2000/02/29 13:44:55  adam
+ * Check for config.h (currently not generated).
+ *
+ * Revision 1.20  2000/01/06 14:59:13  adam
+ * Added oid_init/oid_exit. Changed oid_exit.
+ *
+ * Revision 1.19  1999/11/30 13:47:12  adam
+ * Improved installation. Moved header files to include/yaz.
+ *
+ * Revision 1.18  1999/08/27 09:40:32  adam
+ * Renamed logf function to yaz_log. Removed VC++ project files.
+ *
+ * Revision 1.17  1999/07/13 13:28:25  adam
+ * Better debugging for NMEM routines.
+ *
+ * Revision 1.16  1999/03/31 11:18:25  adam
+ * Implemented odr_strdup. Added Reference ID to backend server API.
+ *
+ * Revision 1.15  1999/02/11 09:10:26  adam
+ * Function nmem_init only mandatory on Windows.
+ *
+ * Revision 1.14  1999/02/02 13:57:40  adam
+ * Uses preprocessor define WIN32 instead of WINDOWS to build code
+ * for Microsoft WIN32.
+ *
+ * Revision 1.13  1998/10/19 15:24:21  adam
+ * New nmem utility, nmem_transfer, that transfer blocks from one
+ * NMEM to another.
+ *
+ * Revision 1.12  1998/10/13 16:00:18  adam
+ * Implemented nmem_critical_{enter,leave}.
+ *
+ * Revision 1.11  1998/08/21 14:13:36  adam
+ * Added GNU Configure script to build Makefiles.
+ *
+ * Revision 1.10  1998/07/20 12:35:57  adam
+ * Added more memory diagnostics (when NMEM_DEBUG is 1).
+ *
+ * Revision 1.9  1998/07/07 15:49:01  adam
+ * Reduced chunk size.
+ *
+ * Revision 1.8  1998/07/03 14:21:27  adam
+ * Added critical sections for pthreads-library. Thanks to Ian Ibbotson,
+ * Fretwell Downing Informatics.
+ *
+ * Revision 1.7  1998/02/11 11:53:36  adam
+ * Changed code so that it compiles as C++.
+ *
+ * Revision 1.6  1997/10/31 12:20:09  adam
+ * Improved memory debugging for xmalloc/nmem.c. References to NMEM
+ * instead of ODR in n ESPEC-1 handling in source d1_espec.c.
+ * Bug fix: missing fclose in data1_read_espec1.
+ *
+ * Revision 1.5  1997/10/06 09:09:52  adam
+ * Function mmem_exit releases memory used by the freelists.
+ *
+ * Revision 1.4  1997/09/29 07:12:50  adam
+ * NMEM thread safe. NMEM must be initialized before use (sigh) -
+ * routine nmem_init/nmem_exit implemented.
+ *
+ * Revision 1.3  1997/07/21 12:47:38  adam
+ * Moved definition of nmem_control and nmem_block.
+ *
+ * Revision 1.2  1995/12/13 13:44:37  quinn
+ * Modified Data1-system to use nmem
+ *
+ * Revision 1.1  1995/11/13  09:27:52  quinn
+ * Fiddling with the variant stuff.
+ *
+ *
+ */
+
+/*
+ * This is a simple and fairly wasteful little module for nibble memory
+ * allocation. Evemtually we'll put in something better.
+ */
+#if HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <assert.h>
+#include <string.h>
+#include <yaz/xmalloc.h>
+#include <yaz/nmem.h>
+#include <yaz/log.h>
+#ifdef WIN32
+#include <windows.h>
+#elif _REENTRANT
+
+#if HAVE_PTHREAD_H
+#include <pthread.h>
+#elif HAVE_THREAD_H
+#include <thread.h>
+#endif
+
+#endif
+
+#define NMEM_CHUNK (4*1024)
+
+#ifdef WIN32
+static CRITICAL_SECTION critical_section;
+#define NMEM_ENTER EnterCriticalSection(&critical_section)
+#define NMEM_LEAVE LeaveCriticalSection(&critical_section)
+#elif _REENTRANT
+static pthread_mutex_t nmem_mutex = PTHREAD_MUTEX_INITIALIZER;
+#define NMEM_ENTER pthread_mutex_lock(&nmem_mutex);
+#define NMEM_LEAVE pthread_mutex_unlock(&nmem_mutex);
+#else
+#define NMEM_ENTER
+#define NMEM_LEAVE
+#endif
+
+static nmem_block *freelist = NULL;        /* "global" freelists */
+static nmem_control *cfreelist = NULL;
+static int nmem_active_no = 0;
+static int nmem_init_flag = 0;
+
+#if NMEM_DEBUG
+struct nmem_debug {
+    void *p;
+    char file[40];
+    int line;
+    struct nmem_debug *next;
+};
+  
+struct nmem_debug *nmem_debug_list = 0;  
+#endif
+
+static void free_block(nmem_block *p)
+{  
+    p->next = freelist;
+    freelist = p;
+#if NMEM_DEBUG
+    yaz_log (LOG_DEBUG, "nmem free_block p=%p", p);
+#endif
+}
+
+#if NMEM_DEBUG
+void nmem_print_list (void)
+{
+    struct nmem_debug *p;
+
+    yaz_log (LOG_DEBUG, "nmem print list");
+    NMEM_ENTER;
+    for (p = nmem_debug_list; p; p = p->next)
+	yaz_log (LOG_DEBUG, " %s:%d p=%p", p->file, p->line, p->p);
+    NMEM_LEAVE;
+}
+#endif
+/*
+ * acquire a block with a minimum of size free bytes.
+ */
+static nmem_block *get_block(int size)
+{
+    nmem_block *r, *l;
+
+#if NMEM_DEBUG
+    yaz_log (LOG_DEBUG, "nmem get_block size=%d", size);
+#endif
+    for (r = freelist, l = 0; r; l = r, r = r->next)
+    	if (r->size >= size)
+	    break;
+    if (r)
+    {
+#if NMEM_DEBUG
+	yaz_log (LOG_DEBUG, "nmem get_block found free block p=%p", r);
+#endif
+    	if (l)
+	    l->next = r->next;
+	else
+	    freelist = r->next;
+    }
+    else
+    {
+    	int get = NMEM_CHUNK;
+
+	if (get < size)
+	    get = size;
+#if NMEM_DEBUG
+	yaz_log (LOG_DEBUG, "nmem get_block alloc new block size=%d", get);
+#endif
+	r = (nmem_block *)xmalloc(sizeof(*r));
+	r->buf = (char *)xmalloc(r->size = get);
+    }
+    r->top = 0;
+    return r;
+}
+
+void nmem_reset(NMEM n)
+{
+    nmem_block *t;
+
+#if NMEM_DEBUG
+    yaz_log (LOG_DEBUG, "nmem_reset p=%p", n);
+#endif
+    if (!n)
+	return;
+    NMEM_ENTER;
+    while (n->blocks)
+    {
+    	t = n->blocks;
+	n->blocks = n->blocks->next;
+	free_block(t);
+    }
+    n->total = 0;
+    NMEM_LEAVE;
+}
+
+#if NMEM_DEBUG
+void *nmem_malloc_f (const char *file, int line, NMEM n, int size)
+#else
+void *nmem_malloc(NMEM n, int size)
+#endif
+{
+    struct nmem_block *p;
+    char *r;
+
+#if NMEM_DEBUG
+    yaz_log (LOG_DEBUG, "%s:%d: nmem_malloc p=%p size=%d", file, line,
+                     n, size);
+#endif
+    if (!n)
+    {
+        abort ();
+	return xmalloc(size);
+    }
+#ifdef WIN32
+    assert (nmem_init_flag);
+#endif
+    NMEM_ENTER;
+    p = n->blocks;
+    if (!p || p->size - p->top < size)
+    {
+    	p = get_block(size);
+	p->next = n->blocks;
+	n->blocks = p;
+    }
+    r = p->buf + p->top;
+    /* align size */
+    p->top += (size + (sizeof(long) - 1)) & ~(sizeof(long) - 1);
+    n->total += size;
+    NMEM_LEAVE;
+    return r;
+}
+
+int nmem_total(NMEM n)
+{
+    return n->total;
+}
+
+#if NMEM_DEBUG
+NMEM nmem_create_f(const char *file, int line)
+#else
+NMEM nmem_create(void)
+#endif
+{
+    NMEM r;
+#if NMEM_DEBUG
+    struct nmem_debug *debug_p;
+#endif
+    
+    NMEM_ENTER;
+    nmem_active_no++;
+    r = cfreelist;
+    if (r)
+	cfreelist = cfreelist->next;
+    else
+	r = (nmem_control *)xmalloc(sizeof(*r));
+    NMEM_LEAVE;
+
+#if NMEM_DEBUG
+    yaz_log (LOG_DEBUG, "%s:%d: nmem_create %d p=%p", file, line,
+                     nmem_active_no, r);
+#endif
+    r->blocks = 0;
+    r->total = 0;
+    r->next = 0;
+
+#if NMEM_DEBUG
+    for (debug_p = nmem_debug_list; debug_p; debug_p = debug_p->next)
+	if (debug_p->p == r)
+	{
+	    yaz_log (LOG_FATAL, "multi used block in nmem");
+	    abort ();
+	}
+    debug_p = xmalloc (sizeof(*debug_p));
+    strncpy (debug_p->file, file, sizeof(debug_p->file)-1);
+    debug_p->file[sizeof(debug_p->file)-1] = '\0';
+    debug_p->line = line;
+    debug_p->p = r;
+    debug_p->next = nmem_debug_list;
+    nmem_debug_list = debug_p;
+
+    nmem_print_list();
+#endif
+    return r;
+}
+
+#if NMEM_DEBUG
+void nmem_destroy_f(const char *file, int line, NMEM n)
+#else
+void nmem_destroy(NMEM n)
+#endif
+{
+#if NMEM_DEBUG
+    struct nmem_debug **debug_p;
+    int ok = 0;
+#endif
+    if (!n)
+	return;
+    
+#if NMEM_DEBUG
+    yaz_log (LOG_DEBUG, "%s:%d: nmem_destroy %d p=%p", file, line,
+                     nmem_active_no-1, n);
+    NMEM_ENTER;
+    for (debug_p = &nmem_debug_list; *debug_p; debug_p = &(*debug_p)->next)
+	if ((*debug_p)->p == n)
+	{
+	    struct nmem_debug *debug_save = *debug_p;
+	    *debug_p = (*debug_p)->next;
+	    xfree (debug_save);
+	    ok = 1;
+	    break;
+	}
+    NMEM_LEAVE;
+    nmem_print_list();
+    if (!ok)
+    {
+	yaz_log (LOG_WARN, "%s:%d destroying unallocated nmem block p=%p",
+		 file, line, n);
+	return;
+    }
+#endif
+    nmem_reset(n);
+    NMEM_ENTER;
+    nmem_active_no--;
+    n->next = cfreelist;
+    cfreelist = n;
+    NMEM_LEAVE;
+}
+
+void nmem_transfer (NMEM dst, NMEM src)
+{
+    nmem_block *t;
+    while ((t=src->blocks))
+    {
+	src->blocks = t->next;
+	t->next = dst->blocks;
+	dst->blocks = t;
+    }
+    dst->total += src->total;
+    src->total = 0;
+}
+
+void nmem_critical_enter (void)
+{
+    NMEM_ENTER;
+}
+
+void nmem_critical_leave (void)
+{
+    NMEM_LEAVE;
+}
+
+void nmem_init (void)
+{
+    nmem_init_flag = 1;
+#ifdef WIN32
+    InitializeCriticalSection(&critical_section);
+#endif
+    nmem_active_no = 0;
+    freelist = NULL;
+    cfreelist = NULL;
+}
+
+void nmem_exit (void)
+{
+    while (freelist)
+    {
+	struct nmem_block *fl = freelist;
+	freelist = freelist->next;
+	xfree (fl->buf);
+	xfree (fl);
+    }
+    while (cfreelist)
+    {
+	struct nmem_control *cfl = cfreelist;
+	cfreelist = cfreelist->next;
+	xfree (cfl);
+    }
+    nmem_init_flag = 0;
+#ifdef WIN32
+    DeleteCriticalSection(&critical_section);
+#endif
+}
+
Index: /main/tags/2.25/gsdl/packages/yaz/util/nmemsdup.c
===================================================================
--- /main/tags/2.25/gsdl/packages/yaz/util/nmemsdup.c	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/yaz/util/nmemsdup.c	(revision 21064)
@@ -0,0 +1,35 @@
+/*
+ * Copyright (c) 1997-2000, Index Data.
+ * See the file LICENSE for details.
+ * Sebastian Hammer, Adam Dickmeiss
+ *
+ * $Log$
+ * Revision 1.1  2000/08/03 03:12:08  johnmcp
+ * Added the YAZ toolkit source to the packages directory (for z39.50 stuff)
+ *
+ * Revision 1.4  2000/02/29 13:44:55  adam
+ * Check for config.h (currently not generated).
+ *
+ * Revision 1.3  1999/11/30 13:47:12  adam
+ * Improved installation. Moved header files to include/yaz.
+ *
+ * Revision 1.2  1998/02/11 11:53:36  adam
+ * Changed code so that it compiles as C++.
+ *
+ * Revision 1.1  1997/09/17 12:10:42  adam
+ * YAZ version 1.4.
+ *
+ */
+#if HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <string.h>
+#include <yaz/nmem.h>
+
+char *nmem_strdup (NMEM mem, const char *src)
+{
+    char *dst = (char *)nmem_malloc (mem, strlen(src)+1);
+    strcpy (dst, src);
+    return dst;
+}
Index: /main/tags/2.25/gsdl/packages/yaz/util/oid.c
===================================================================
--- /main/tags/2.25/gsdl/packages/yaz/util/oid.c	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/yaz/util/oid.c	(revision 21064)
@@ -0,0 +1,755 @@
+/*
+ * Copyright (c) 1995-2000, Index Data
+ * See the file LICENSE for details.
+ *
+ * $Log$
+ * Revision 1.1  2000/08/03 03:12:09  johnmcp
+ * Added the YAZ toolkit source to the packages directory (for z39.50 stuff)
+ *
+ * Revision 1.42  2000/02/29 13:44:55  adam
+ * Check for config.h (currently not generated).
+ *
+ * Revision 1.41  2000/01/10 15:16:53  adam
+ * Added several OID's.
+ *
+ * Revision 1.40  2000/01/06 14:59:13  adam
+ * Added oid_init/oid_exit. Changed oid_exit.
+ *
+ * Revision 1.39  1999/12/16 23:36:19  adam
+ * Implemented ILL protocol. Minor updates ASN.1 compiler.
+ *
+ * Revision 1.38  1999/11/30 13:47:12  adam
+ * Improved installation. Moved header files to include/yaz.
+ *
+ * Revision 1.37  1999/09/13 12:51:15  adam
+ * Added CLIENT IP OID.
+ *
+ * Revision 1.36  1999/05/27 13:02:20  adam
+ * Assigned OID for old DB Update (VAL_DBUPDATE0).
+ *
+ * Revision 1.35  1999/04/20 09:56:49  adam
+ * Added 'name' paramter to encoder/decoder routines (typedef Odr_fun).
+ * Modified all encoders/decoders to reflect this change.
+ *
+ * Revision 1.34  1999/04/15 09:19:43  adam
+ * Added COOKIE UserInfo OID.
+ *
+ * Revision 1.33  1999/04/09 12:16:11  adam
+ * Added OtherInfo private OID proxy.
+ *
+ * Revision 1.32  1999/02/18 10:30:46  quinn
+ * Changed ES: Update OID
+ *
+ * Revision 1.31  1998/12/03 11:33:05  adam
+ * Added OID's for XML.
+ *
+ * Revision 1.30  1998/10/18 07:48:56  adam
+ * Fixed oid_getentbyoid so that it returns NULL when parsed oid is NULL.
+ *
+ * Revision 1.29  1998/10/14 13:32:35  adam
+ * Added include of string.h.
+ *
+ * Revision 1.28  1998/10/13 16:01:53  adam
+ * Implemented support for dynamic object identifiers.
+ * Function oid_getvalbyname now accepts raw OID's as well as traditional
+ * names.
+ *
+ * Revision 1.27  1998/05/18 10:10:02  adam
+ * Added Explain-schema and Explain-tagset to OID database.
+ *
+ * Revision 1.26  1998/03/20 14:46:06  adam
+ * Added UNIverse Resource Reports.
+ *
+ * Revision 1.25  1998/02/10 15:32:03  adam
+ * Added new Object Identifiers.
+ *
+ * Revision 1.24  1997/09/29 13:19:00  adam
+ * Added function, oid_ent_to_oid, to replace the function
+ * oid_getoidbyent, which is not thread safe.
+ *
+ * Revision 1.23  1997/09/09 10:10:19  adam
+ * Another MSV5.0 port. Changed projects to include proper
+ * library/include paths.
+ * Server starts server in test-mode when no options are given.
+ *
+ * Revision 1.22  1997/08/29 13:34:58  quinn
+ * Added thesaurus oids
+ *
+ * Revision 1.21  1997/08/19 08:46:05  quinn
+ * Added Thesaurus OID
+ *
+ * Revision 1.20  1997/07/28 12:34:43  adam
+ * Added new OID entries (RVDM).
+ *
+ * Revision 1.19  1997/05/02 08:39:41  quinn
+ * Support for private OID table added. Thanks to Ronald van der Meer
+ *
+ * Revision 1.18  1997/04/30 08:52:12  quinn
+ * Null
+ *
+ * Revision 1.17  1996/10/10  12:35:23  quinn
+ * Added Update extended service.
+ *
+ * Revision 1.16  1996/10/09  15:55:02  quinn
+ * Added SearchInfoReport
+ *
+ * Revision 1.15  1996/10/07  15:29:43  quinn
+ * Added SOIF support
+ *
+ * Revision 1.14  1996/02/20  17:58:28  adam
+ * Added const to oid_getvalbyname.
+ *
+ * Revision 1.13  1996/02/20  16:37:33  quinn
+ * Using yaz_matchstr in oid_getvalbyname
+ *
+ * Revision 1.12  1996/01/02  08:57:53  quinn
+ * Changed enums in the ASN.1 .h files to #defines. Changed oident.class to oclass
+ *
+ * Revision 1.11  1995/12/13  16:03:35  quinn
+ * *** empty log message ***
+ *
+ * Revision 1.10  1995/11/28  09:30:44  quinn
+ * Work.
+ *
+ * Revision 1.9  1995/11/13  09:27:53  quinn
+ * Fiddling with the variant stuff.
+ *
+ * Revision 1.8  1995/10/12  10:34:56  quinn
+ * Added Espec-1.
+ *
+ * Revision 1.7  1995/10/10  16:27:12  quinn
+ * *** empty log message ***
+ *
+ * Revision 1.6  1995/09/29  17:12:35  quinn
+ * Smallish
+ *
+ * Revision 1.5  1995/09/29  17:01:51  quinn
+ * More Windows work
+ *
+ * Revision 1.4  1995/09/27  15:03:03  quinn
+ * Modified function heads & prototypes.
+ *
+ * Revision 1.3  1995/09/12  11:32:06  quinn
+ * Added a looker-upper by name.
+ *
+ * Revision 1.2  1995/08/21  09:11:16  quinn
+ * Smallish fixes to suppport new formats.
+ *
+ * Revision 1.1  1995/05/29  08:17:13  quinn
+ * iMoved oid to util to support comstack.
+ *
+ * Revision 1.5  1995/05/22  11:30:16  quinn
+ * Adding Z39.50-1992 stuff to proto.c. Adding zget.c
+ *
+ * Revision 1.4  1995/05/16  08:50:22  quinn
+ * License, documentation, and memory fixes
+ *
+ * Revision 1.3  1995/04/11  11:52:02  quinn
+ * Fixed possible buf in proto.c
+ *
+ * Revision 1.2  1995/03/29  15:39:38  quinn
+ * Adding some resource control elements, and a null-check to getentbyoid
+ *
+ * Revision 1.1  1995/03/27  08:32:12  quinn
+ * Added OID database
+ *
+ *
+ */
+
+/*
+ * More or less protocol-transparent OID database.
+ * We could (and should?) extend this so that the user app can add new
+ * entries to the list at initialization.
+ */
+#if HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <stdlib.h>
+#include <string.h>
+#include <ctype.h>
+
+#include <yaz/oid.h>
+#include <yaz/yaz-util.h>
+
+static int z3950_prefix[] = { 1, 2, 840, 10003, -1 };
+static int sr_prefix[]    = { 1, 0, 10163, -1 };
+
+struct oident_list {
+    struct oident oident;
+    struct oident_list *next;
+};
+
+static struct oident_list *oident_table = NULL;
+static int oid_value_dynamic = VAL_DYNAMIC;
+static int oid_init_flag = 0;
+
+/*
+ * OID database
+ */
+static oident oids[] =
+{
+    /* General definitions */
+    {PROTO_GENERAL, CLASS_TRANSYN, VAL_BER,          {2,1,1,-1},
+     "BER" },
+    {PROTO_GENERAL, CLASS_TRANSYN, VAL_ISO2709,      {1,0,2709,1,1,-1},
+     "ISO2709"},
+    {PROTO_GENERAL, CLASS_GENERAL, VAL_ISO_ILL_1,    {1,2,10161,2,1,-1},
+     "ISOILL-1"},
+    /* Z39.50v3 definitions */
+    {PROTO_Z3950,   CLASS_ABSYN,   VAL_APDU,         {2,1,-1},
+     "Z-APDU"},    
+    {PROTO_Z3950,   CLASS_APPCTX,  VAL_BASIC_CTX,    {1,1,-1},
+     "Z-BASIC"},
+    {PROTO_Z3950,   CLASS_ATTSET,  VAL_BIB1,         {3,1,-1},
+     "Bib-1"},
+    {PROTO_Z3950,   CLASS_ATTSET,  VAL_EXP1,         {3,2,-1},
+     "Exp-1"},
+    {PROTO_Z3950,   CLASS_ATTSET,  VAL_EXT1,         {3,3,-1},
+     "Ext-1"},
+    {PROTO_Z3950,   CLASS_ATTSET,  VAL_CCL1,         {3,4,-1},
+     "CCL-1"},
+    {PROTO_Z3950,   CLASS_ATTSET,  VAL_GILS,         {3,5,-1},
+     "GILS-attset"},
+    {PROTO_Z3950,   CLASS_ATTSET,  VAL_STAS,         {3,6,-1},
+     "STAS-attset"},
+    {PROTO_Z3950,   CLASS_ATTSET,  VAL_COLLECT1,     {3,7,-1},
+     "Collections-attset"},
+    {PROTO_Z3950,   CLASS_ATTSET,  VAL_CIMI1,        {3,8,-1},
+     "CIMI-attset"},
+    {PROTO_Z3950,   CLASS_ATTSET,  VAL_GEO,          {3,9,-1},
+     "Geo-attset"},
+
+    {PROTO_Z3950,   CLASS_ATTSET,  VAL_ZBIG,         {3,10,-1},
+     "ZBIG"},
+    {PROTO_Z3950,   CLASS_ATTSET,  VAL_UTIL,         {3,11,-1},
+     "Util"},
+    {PROTO_Z3950,   CLASS_ATTSET,  VAL_XD1,          {3,12,-1},
+     "XD-1"},
+    {PROTO_Z3950,   CLASS_ATTSET,  VAL_ZTHES,        {3,13,-1},
+     "Zthes"},
+    {PROTO_Z3950,   CLASS_ATTSET,  VAL_FIN1,         {3,14,-1},
+     "Fin-1"},
+    {PROTO_Z3950,   CLASS_ATTSET,  VAL_DAN1,         {3,15,-1},
+     "Dan-1"},
+
+    {PROTO_Z3950,   CLASS_ATTSET,  VAL_THESAURUS,    {3,1000,81,1,-1},
+     "Thesaurus-attset"},
+    {PROTO_Z3950,   CLASS_DIAGSET, VAL_BIB1,         {4,1,-1},
+     "Bib-1"},
+    {PROTO_Z3950,   CLASS_DIAGSET, VAL_DIAG1,        {4,2,-1},
+     "Diag-1"},
+    {PROTO_Z3950,   CLASS_DIAGSET, VAL_DIAG_ES,      {4,3,-1},
+     "Diag-ES"},
+    {PROTO_Z3950,   CLASS_DIAGSET, VAL_DIAG_GENERAL, {4,3,-1},
+     "Diag-General"},
+    {PROTO_Z3950,   CLASS_RECSYN,  VAL_UNIMARC,      {5,1,-1},
+     "Unimarc"},
+    {PROTO_Z3950,   CLASS_RECSYN,  VAL_INTERMARC,    {5,2,-1},
+     "Intermarc"},
+    {PROTO_Z3950,   CLASS_RECSYN,  VAL_CCF,          {5,3,-1},
+     "CCF"},
+    {PROTO_Z3950,   CLASS_RECSYN,  VAL_USMARC,       {5,10,-1},
+     "USmarc"},
+    {PROTO_Z3950,   CLASS_RECSYN,  VAL_UKMARC,       {5,11,-1},
+     "UKmarc"},
+    {PROTO_Z3950,   CLASS_RECSYN,  VAL_NORMARC,      {5,12,-1},
+     "Normarc"},
+    {PROTO_Z3950,   CLASS_RECSYN,  VAL_LIBRISMARC,   {5,13,-1},
+     "Librismarc"},
+    {PROTO_Z3950,   CLASS_RECSYN,  VAL_DANMARC,      {5,14,-1},
+     "Danmarc"},
+    {PROTO_Z3950,   CLASS_RECSYN,  VAL_FINMARC,      {5,15,-1},
+     "Finmarc"},
+    {PROTO_Z3950,   CLASS_RECSYN,  VAL_MAB,          {5,16,-1},
+     "MAB"},
+    {PROTO_Z3950,   CLASS_RECSYN,  VAL_CANMARC,      {5,17,-1},
+     "Canmarc"},
+    {PROTO_Z3950,   CLASS_RECSYN,  VAL_SBN,          {5,18,-1},
+     "SBN"},
+    {PROTO_Z3950,   CLASS_RECSYN,  VAL_PICAMARC,     {5,19,-1},
+     "Picamarc"},
+    {PROTO_Z3950,   CLASS_RECSYN,  VAL_AUSMARC,      {5,20,-1},
+     "Ausmarc"},
+    {PROTO_Z3950,   CLASS_RECSYN,  VAL_IBERMARC,     {5,21,-1},
+     "Ibermarc"},
+    {PROTO_Z3950,   CLASS_RECSYN,  VAL_CATMARC,      {5,22,-1},
+     "Carmarc"},
+    {PROTO_Z3950,   CLASS_RECSYN,  VAL_MALMARC,      {5,23,-1},
+     "Malmarc"},
+    {PROTO_Z3950,   CLASS_RECSYN,  VAL_JPMARC,       {5,24,-1},
+     "JPmarc"},
+    {PROTO_Z3950,   CLASS_RECSYN,  VAL_SWEMARC,      {5,25,-1},
+     "SWEmarc"},
+    {PROTO_Z3950,   CLASS_RECSYN,  VAL_SIGLEMARC,    {5,26,-1},
+     "SIGLEmarc"},
+    {PROTO_Z3950,   CLASS_RECSYN,  VAL_ISDSMARC,     {5,27,-1},
+     "ISDSmarc"},
+    {PROTO_Z3950,   CLASS_RECSYN,  VAL_RUSMARC,      {5,28,-1},
+     "RUSmarc"},
+    {PROTO_Z3950,   CLASS_RECSYN,  VAL_EXPLAIN,      {5,100,-1},
+     "Explain"},
+    {PROTO_Z3950,   CLASS_RECSYN,  VAL_SUTRS,        {5,101,-1},
+     "SUTRS"},
+    {PROTO_Z3950,   CLASS_RECSYN,  VAL_OPAC,         {5,102,-1},
+     "OPAC"},
+    {PROTO_Z3950,   CLASS_RECSYN,  VAL_SUMMARY,      {5,103,-1},
+     "Summary"},
+    {PROTO_Z3950,   CLASS_RECSYN,  VAL_GRS0,         {5,104,-1},
+     "GRS-0"},
+    {PROTO_Z3950,   CLASS_RECSYN,  VAL_GRS1,         {5,105,-1},
+     "GRS-1"},
+    {PROTO_Z3950,   CLASS_RECSYN,  VAL_EXTENDED,     {5,106,-1},
+     "Extended"},
+    {PROTO_Z3950,   CLASS_RECSYN,  VAL_FRAGMENT,     {5,107,-1},
+     "Fragment"},
+    {PROTO_Z3950,   CLASS_RECSYN,  VAL_PDF,          {5,109,1,-1},
+     "pdf"},
+    {PROTO_Z3950,   CLASS_RECSYN,  VAL_POSTSCRIPT,   {5,109,2,-1},
+     "postscript"},
+    {PROTO_Z3950,   CLASS_RECSYN,  VAL_HTML,         {5,109,3,-1},
+     "html"},
+    {PROTO_Z3950,   CLASS_RECSYN,  VAL_TIFF,         {5,109,4,-1},
+     "tiff"},
+    {PROTO_Z3950,   CLASS_RECSYN,  VAL_GIF,          {5,109,5,-1},
+     "gif"},
+    {PROTO_Z3950,   CLASS_RECSYN,  VAL_JPEG,         {5,109,6,-1},
+     "jpeg"},
+    {PROTO_Z3950,   CLASS_RECSYN,  VAL_PNG,          {5,109,7,-1},
+     "png"},
+    {PROTO_Z3950,   CLASS_RECSYN,  VAL_MPEG,         {5,109,8,-1},
+     "mpeg"},
+    {PROTO_Z3950,   CLASS_RECSYN,  VAL_SGML,         {5,109,9,-1},
+     "sgml"},
+
+    {PROTO_Z3950,   CLASS_RECSYN,  VAL_TIFFB,        {5,110,1,-1},
+     "tiff-b"},
+    {PROTO_Z3950,   CLASS_RECSYN,  VAL_WAV,          {5,110,2,-1},
+     "wav"},
+
+    {PROTO_Z3950,   CLASS_RECSYN,  VAL_SQLRS,        {5,111,-1},
+     "SQL-RS"},
+    {PROTO_Z3950,   CLASS_RECSYN,  VAL_SOIF,         {5,1000,81,2,-1},
+     "SOIF" },
+    {PROTO_Z3950,   CLASS_RECSYN,  VAL_TEXT_XML,     {5,109,10,-1},
+     "text-XML" },
+    {PROTO_Z3950,   CLASS_RECSYN,  VAL_TEXT_XML,     {5,109,10,-1},
+     "XML" },
+    {PROTO_Z3950,   CLASS_RECSYN,  VAL_APPLICATION_XML, {5,109,11,-1},
+     "application-XML" },
+    {PROTO_Z3950,   CLASS_RESFORM, VAL_RESOURCE1,    {7,1,-1},
+     "Resource-1"},
+    {PROTO_Z3950,   CLASS_RESFORM, VAL_RESOURCE2,    {7,2,-1},
+     "Resource-2"},
+    {PROTO_Z3950,   CLASS_RESFORM, VAL_UNIVERSE_REPORT, {7,1000,81,1,-1},
+     "UNIverse-Resource-Report"},
+
+    {PROTO_Z3950,   CLASS_ACCFORM, VAL_PROMPT1,      {8,1,-1},
+     "Prompt-1"},
+    {PROTO_Z3950,   CLASS_ACCFORM, VAL_DES1,         {8,2,-1},
+     "Des-1"},
+    {PROTO_Z3950,   CLASS_ACCFORM, VAL_KRB1,         {8,3,-1},
+     "Krb-1"},
+    {PROTO_Z3950,   CLASS_EXTSERV, VAL_PRESSET,      {9,1,-1},
+     "Pers. set"},
+    {PROTO_Z3950,   CLASS_EXTSERV, VAL_PQUERY,       {9,2,-1},
+     "Pers. query"},
+    {PROTO_Z3950,   CLASS_EXTSERV, VAL_PCQUERY,      {9,3,-1},
+     "Per'd query"},
+    {PROTO_Z3950,   CLASS_EXTSERV, VAL_ITEMORDER,    {9,4,-1},
+     "Item order"},
+    {PROTO_Z3950,   CLASS_EXTSERV, VAL_DBUPDATE0,    {9,5,1,-1},
+     "DB. Update (old version)"},
+    {PROTO_Z3950,   CLASS_EXTSERV, VAL_DBUPDATE,     {9,5,1,1,-1},
+     "DB. Update"},
+    {PROTO_Z3950,   CLASS_EXTSERV, VAL_EXPORTSPEC,   {9,6,-1},
+     "exp. spec."},
+    {PROTO_Z3950,   CLASS_EXTSERV, VAL_EXPORTINV,    {9,7,-1},
+     "exp. inv."},
+
+    {PROTO_Z3950,   CLASS_USERINFO,VAL_SEARCHRES1,   {10,1,-1},
+     "searchResult-1"},
+    {PROTO_Z3950,   CLASS_USERINFO,VAL_CHARLANG,     {10,2,-1},
+     "CharSetandLanguageNegotiation"},
+    {PROTO_Z3950,   CLASS_USERINFO,VAL_USERINFO1,    {10,3,-1},
+     "UserInfo-1"},
+    {PROTO_Z3950,   CLASS_USERINFO,VAL_MULTISRCH1,   {10,4,-1},
+     "MultipleSearchTerms-1"},
+    {PROTO_Z3950,   CLASS_USERINFO,VAL_MULTISRCH2,   {10,5,-1},
+     "MultipleSearchTerms-2"},
+    {PROTO_Z3950,   CLASS_USERINFO,VAL_DATETIME,     {10,6,-1},
+     "DateTime"},
+    {PROTO_Z3950,   CLASS_USERINFO,VAL_PROXY,        {10,1000,81,1,-1},
+     "Proxy" },
+    {PROTO_Z3950,   CLASS_USERINFO,VAL_COOKIE,       {10,1000,81,2,-1},
+     "Cookie" },
+    {PROTO_Z3950,   CLASS_USERINFO,VAL_CLIENT_IP,    {10,1000,81,3,-1},
+     "Client-IP" },
+    {PROTO_Z3950,   CLASS_ELEMSPEC,VAL_ESPEC1,       {11,1,-1},
+     "Espec-1"},
+    {PROTO_Z3950,   CLASS_VARSET,  VAL_VAR1,         {12,1,-1},
+     "Variant-1"},
+    {PROTO_Z3950,   CLASS_SCHEMA,  VAL_WAIS,         {13,1,-1},
+     "WAIS-schema"},
+    {PROTO_Z3950,   CLASS_SCHEMA,  VAL_GILS,         {13,2,-1},
+     "GILS-schema"},
+    {PROTO_Z3950,   CLASS_SCHEMA,  VAL_COLLECT1,     {13,3,-1},
+     "Collections-schema"},
+    {PROTO_Z3950,   CLASS_SCHEMA,  VAL_GEO,          {13,4,-1},
+     "Geo-schema"},
+    {PROTO_Z3950,   CLASS_SCHEMA,  VAL_CIMI1,        {13,5,-1},
+     "CIMI-schema"},
+    {PROTO_Z3950,   CLASS_SCHEMA,  VAL_UPDATEES,     {13,6,-1},
+     "Update ES"},
+    {PROTO_Z3950,   CLASS_SCHEMA,  VAL_THESAURUS,    {13,1000,81,1,-1},
+     "thesaurus-schema"},
+    {PROTO_Z3950,   CLASS_SCHEMA,  VAL_EXPLAIN,      {13,1000,81,2,-1},
+     "Explain-schema"},
+    {PROTO_Z3950,   CLASS_TAGSET,  VAL_SETM,         {14,1,-1},
+     "TagsetM"},
+    {PROTO_Z3950,   CLASS_TAGSET,  VAL_SETG,         {14,2,-1},
+     "TagsetG"},
+    {PROTO_Z3950,   CLASS_TAGSET,  VAL_STAS,         {14,3,-1},
+     "STAS-tagset"},
+    {PROTO_Z3950,   CLASS_TAGSET,  VAL_GILS,         {14,4,-1},
+     "GILS-tagset"},
+    {PROTO_Z3950,   CLASS_TAGSET,  VAL_COLLECT1,     {14,5,-1},
+     "Collections-tagset"},
+    {PROTO_Z3950,   CLASS_TAGSET,  VAL_CIMI1,        {14,6,-1},
+     "CIMI-tagset"},
+    {PROTO_Z3950,   CLASS_TAGSET,  VAL_THESAURUS,    {14,1000,81,1,-1},
+     "thesaurus-tagset"},
+    {PROTO_Z3950,   CLASS_TAGSET,  VAL_EXPLAIN,      {14,1000,81,2,-1},
+     "Explain-tagset"},
+    
+
+    /* SR definitions. Note that some of them aren't defined by the
+        standard (yet), but are borrowed from Z3950v3 */
+    {PROTO_SR,      CLASS_ABSYN,   VAL_APDU,      {2,1,-1},    "SR-APDU"     },
+
+    {PROTO_SR,      CLASS_APPCTX,  VAL_BASIC_CTX, {1,1,-1},    "SR-BASIC"    },
+
+    {PROTO_SR,      CLASS_ATTSET,  VAL_BIB1,      {3,1,-1},    "Bib-1"       },
+    {PROTO_SR,      CLASS_ATTSET,  VAL_EXP1,      {3,2,-1},    "Exp-1"       },
+    {PROTO_SR,      CLASS_ATTSET,  VAL_EXT1,      {3,3,-1},    "Ext-1"       },
+    {PROTO_SR,      CLASS_ATTSET,  VAL_CCL1,      {3,4,-1},    "CCL-1"       },
+    {PROTO_SR,      CLASS_ATTSET,  VAL_GILS,      {3,5,-1},    "GILS"        },
+    {PROTO_SR,      CLASS_ATTSET,  VAL_STAS,      {3,6,-1},    "STAS",       },
+    {PROTO_SR,      CLASS_ATTSET,  VAL_COLLECT1,  {3,7,-1},    "Collections-attset"},
+    {PROTO_SR,      CLASS_ATTSET,  VAL_CIMI1,     {3,8,-1},    "CIMI-attset"},
+    {PROTO_SR,      CLASS_ATTSET,  VAL_GEO,       {3,9,-1},    "Geo-attset"},
+
+    {PROTO_SR,      CLASS_DIAGSET, VAL_BIB1,      {4,1,-1},    "Bib-1"       },
+    {PROTO_SR,      CLASS_DIAGSET, VAL_DIAG1,     {4,2,-1},    "Diag-1"      },
+
+    {PROTO_SR,      CLASS_RECSYN,  VAL_UNIMARC,   {5,1,-1},    "Unimarc"     },
+    {PROTO_SR,      CLASS_RECSYN,  VAL_INTERMARC, {5,2,-1},    "Intermarc"   },
+    {PROTO_SR,      CLASS_RECSYN,  VAL_CCF,       {5,3,-1},    "CCF"        },
+    {PROTO_SR,      CLASS_RECSYN,  VAL_USMARC,    {5,10,-1},   "USmarc"      },
+    {PROTO_SR,      CLASS_RECSYN,  VAL_UKMARC,    {5,11,-1},   "UKmarc"      },
+    {PROTO_SR,      CLASS_RECSYN,  VAL_NORMARC,   {5,12,-1},   "Normarc"     },
+    {PROTO_SR,      CLASS_RECSYN,  VAL_LIBRISMARC,{5,13,-1},   "Librismarc"  },
+    {PROTO_SR,      CLASS_RECSYN,  VAL_DANMARC,   {5,14,-1},   "Danmarc"     },
+    {PROTO_SR,      CLASS_RECSYN,  VAL_FINMARC,   {5,15,-1},   "Finmarc"     },
+    {PROTO_SR,      CLASS_RECSYN,  VAL_MAB,       {5,16,-1},   "MAB"         },
+    {PROTO_SR,      CLASS_RECSYN,  VAL_CANMARC,   {5,17,-1},   "Canmarc"     },
+    {PROTO_SR,      CLASS_RECSYN,  VAL_MAB,       {5,16,-1},   "MAB"         },
+    {PROTO_SR,      CLASS_RECSYN,  VAL_CANMARC,   {5,17,-1},   "Canmarc"     },
+    {PROTO_SR,      CLASS_RECSYN,  VAL_SBN,       {5,18,-1},   "SBN"         },
+    {PROTO_SR,      CLASS_RECSYN,  VAL_PICAMARC,  {5,19,-1},   "Picamarc"    },
+    {PROTO_SR,      CLASS_RECSYN,  VAL_AUSMARC,   {5,20,-1},   "Ausmarc"     },
+    {PROTO_SR,      CLASS_RECSYN,  VAL_IBERMARC,  {5,21,-1},   "Ibermarc"    },
+    {PROTO_SR,      CLASS_RECSYN,  VAL_CATMARC,   {5,22,-1},   "Catmarc"     },
+    {PROTO_SR,      CLASS_RECSYN,  VAL_MALMARC,   {5,23,-1},   "Malmarc"     },
+    {PROTO_SR,      CLASS_RECSYN,  VAL_EXPLAIN,   {5,100,-1},  "Explain"     },
+    {PROTO_SR,      CLASS_RECSYN,  VAL_SUTRS,     {5,101,-1},  "SUTRS"       },
+    {PROTO_SR,      CLASS_RECSYN,  VAL_OPAC,      {5,102,-1},  "OPAC"        },
+    {PROTO_SR,      CLASS_RECSYN,  VAL_SUMMARY,   {5,103,-1},  "Summary"     },
+    {PROTO_SR,      CLASS_RECSYN,  VAL_GRS0,      {5,104,-1},  "GRS-0"       },
+    {PROTO_SR,      CLASS_RECSYN,  VAL_GRS1,      {5,105,-1},  "GRS-1"       },
+    {PROTO_SR,      CLASS_RECSYN,  VAL_EXTENDED,  {5,106,-1},  "Extended"    },
+    {PROTO_SR,      CLASS_RECSYN,  VAL_FRAGMENT,  {5,107,-1},  "Fragment"    },
+
+    {PROTO_SR,      CLASS_RESFORM, VAL_RESOURCE1, {7,1,-1},    "Resource-1"  },
+    {PROTO_SR,      CLASS_RESFORM, VAL_RESOURCE2, {7,2,-1},    "Resource-2"  },
+
+    {PROTO_SR,      CLASS_ACCFORM, VAL_PROMPT1,   {8,1,-1},    "Prompt-1"    },
+    {PROTO_SR,      CLASS_ACCFORM, VAL_DES1,      {8,2,-1},    "Des-1"       },
+    {PROTO_SR,      CLASS_ACCFORM, VAL_KRB1,      {8,3,-1},    "Krb-1"       },
+
+    {PROTO_SR,      CLASS_EXTSERV, VAL_PRESSET,   {9,1,-1},    "Pers. set"   },
+    {PROTO_SR,      CLASS_EXTSERV, VAL_PQUERY,    {9,2,-1},    "Pers. query" },
+    {PROTO_SR,      CLASS_EXTSERV, VAL_PCQUERY,   {9,3,-1},    "Per'd query" },
+    {PROTO_SR,      CLASS_EXTSERV, VAL_ITEMORDER, {9,4,-1},    "Item order"  },
+    {PROTO_SR,      CLASS_EXTSERV, VAL_DBUPDATE,  {9,5,-1},    "DB. Update"  },
+    {PROTO_SR,      CLASS_EXTSERV, VAL_EXPORTSPEC,{9,6,-1},    "exp. spec."  },
+    {PROTO_SR,      CLASS_EXTSERV, VAL_EXPORTINV, {9,7,-1},    "exp. inv."   },
+
+    {PROTO_SR,      CLASS_ELEMSPEC,VAL_ESPEC1,    {11,1,-1},   "Espec-1"     },
+
+    {PROTO_SR,      CLASS_VARSET,  VAL_VAR1,      {12,1,-1},   "Variant-1"   },
+
+    {PROTO_SR,      CLASS_SCHEMA,  VAL_WAIS,      {13,1,-1},   "WAIS-schema" },
+    {PROTO_SR,      CLASS_SCHEMA,  VAL_GILS,      {13,2,-1},   "GILS-schema" },
+    {PROTO_SR,      CLASS_SCHEMA,  VAL_COLLECT1,  {13,3,-1},   "Collections-schema" },
+    {PROTO_SR,      CLASS_SCHEMA,  VAL_GEO,       {13,4,-1},   "Geo-schema" },
+    {PROTO_SR,      CLASS_SCHEMA,  VAL_CIMI1,     {13,5,-1},   "CIMI-schema" },
+
+    {PROTO_SR,      CLASS_TAGSET,  VAL_SETM,      {14,1,-1},   "TagsetM"     },
+    {PROTO_SR,      CLASS_TAGSET,  VAL_SETG,      {14,2,-1},   "TagsetG"     },
+
+    {PROTO_SR,      CLASS_TAGSET,  VAL_STAS,      {14,3,-1},   "STAS-tagset" },
+    {PROTO_SR,      CLASS_TAGSET,  VAL_GILS,      {14,4,-1},   "GILS-tagset" },
+    {PROTO_SR,      CLASS_TAGSET,  VAL_COLLECT1,  {14,5,-1},   "Collections-tagset"},
+    {PROTO_SR,      CLASS_TAGSET,  VAL_CIMI1,     {14,6,-1},   "CIMI-tagset" },
+
+    {PROTO_NOP,     CLASS_NOP,     VAL_NOP,       {-1},        0          }
+};
+
+/* OID utilities */
+
+void oid_oidcpy(int *t, int *s)
+{
+    while ((*(t++) = *(s++)) > -1);
+}
+
+void oid_oidcat(int *t, int *s)
+{
+    while (*t > -1)
+        t++;
+    while ((*(t++) = *(s++)) > -1);
+}
+
+int oid_oidcmp(int *o1, int *o2)
+{
+    while (*o1 == *o2 && *o1 > -1)
+    {
+        o1++;
+        o2++;
+    }
+    if (*o1 == *o2)
+        return 0;
+    else if (*o1 > *o2)
+        return 1;
+    else
+        return -1;
+}
+
+int oid_oidlen(int *o)
+{
+    int len = 0;
+
+    while (*(o++) >= 0)
+        len++;
+    return len;
+}
+
+
+static int match_prefix(int *look, int *prefix)
+{
+    int len;
+
+    for (len = 0; *look == *prefix; look++, prefix++, len++);
+    if (*prefix < 0) /* did we reach the end of the prefix? */
+        return len;
+    return 0;
+}
+
+void oid_transfer (struct oident *oident)
+{
+    while (*oident->oidsuffix >= 0)
+    {
+	oid_addent (oident->oidsuffix, oident->proto,
+		    oident->oclass,
+		    oident->desc, oident->value);
+	oident++;
+    }
+}
+
+void oid_init (void)
+{
+    if (oid_init_flag)
+	return;
+    /* oid_transfer is thread safe, so there's nothing wrong in having
+       two threads calling it simultaniously. On the other hand
+       no thread may exit oid_init before all OID's bave been
+       transferred - which is why checked is set after oid_transfer... 
+    */
+    oid_transfer (oids);
+    oid_init_flag = 1;
+}
+
+void oid_exit (void)
+{
+    while (oident_table)
+    {
+	struct oident_list *this_p = oident_table;
+	oident_table = oident_table->next;
+
+	xfree (this_p->oident.desc);
+	xfree (this_p);
+    }
+    oid_init_flag = 0;
+}
+
+static struct oident *oid_getentbyoid_x(int *o)
+{
+    enum oid_proto proto;
+    int prelen;
+    struct oident_list *ol;
+    
+    /* determine protocol type */
+    if ((prelen = match_prefix(o, z3950_prefix)) != 0)
+        proto = PROTO_Z3950;
+    else if ((prelen = match_prefix(o, sr_prefix)) != 0)
+        proto = PROTO_SR;
+    else
+        proto = PROTO_GENERAL;
+    for (ol = oident_table; ol; ol = ol->next)
+    {
+	struct oident *p = &ol->oident;
+        if (p->proto == proto && !oid_oidcmp(o + prelen, p->oidsuffix))
+            return p;
+	if (p->proto == PROTO_GENERAL && !oid_oidcmp (o, p->oidsuffix))
+	    return p;
+    }
+    return 0;
+}
+
+/*
+ * To query, fill out proto, class, and value of the ent parameter.
+ */
+int *oid_ent_to_oid(struct oident *ent, int *ret)
+{
+    struct oident_list *ol;
+    
+    oid_init ();
+    for (ol = oident_table; ol; ol = ol->next)
+    {
+	struct oident *p = &ol->oident;
+	if ((ent->proto == p->proto || p->proto == PROTO_GENERAL) &&
+	    (ent->oclass == p->oclass || p->oclass == CLASS_GENERAL) &&
+	    ent->value == p->value)
+	{
+	    if (p->proto == PROTO_Z3950)
+		oid_oidcpy(ret, z3950_prefix);
+	    else if (p->proto == PROTO_SR)
+		oid_oidcpy(ret, sr_prefix);
+	    else
+		ret[0] = -1;
+	    oid_oidcat(ret, p->oidsuffix);
+	    ent->desc = p->desc;
+	    return ret;
+	}
+    }
+    ret[0] = -1;
+    return 0;
+}
+
+/*
+ * To query, fill out proto, class, and value of the ent parameter.
+ */
+int *oid_getoidbyent(struct oident *ent)
+{
+    static int ret[OID_SIZE];
+
+    return oid_ent_to_oid (ent, ret);
+}
+
+struct oident *oid_addent (int *oid, enum oid_proto proto,
+			   enum oid_class oclass,
+			   const char *desc, int value)
+{
+    struct oident *oident;
+
+    nmem_critical_enter ();
+    oident = oid_getentbyoid_x (oid);
+    if (!oident)
+    {
+	char desc_str[200];
+	struct oident_list *oident_list;
+	oident_list = (struct oident_list *) xmalloc (sizeof(*oident_list));
+	oident = &oident_list->oident;
+	oident->proto = proto;
+	oident->oclass = oclass;
+
+	if (!desc)
+	{
+	    int i;
+
+	    sprintf (desc_str, "%d", *oid);
+	    for (i = 1; oid[i] >= 0; i++)
+		sprintf (desc_str+strlen(desc_str), ".%d", oid[i]);
+	    desc = desc_str;
+	}
+	oident->desc = (char *) xmalloc (strlen(desc)+1);
+	strcpy (oident->desc, desc);
+	if (value == VAL_DYNAMIC)
+	    oident->value = (enum oid_value) (++oid_value_dynamic);
+	else
+	    oident->value = (enum oid_value) value;
+	oid_oidcpy (oident->oidsuffix, oid);
+	oident_list->next = oident_table;
+	oident_table = oident_list;
+    }
+    nmem_critical_leave ();
+    return oident;
+}
+
+struct oident *oid_getentbyoid(int *oid)
+{
+    struct oident *oident;
+
+    if (!oid)
+	return 0;
+    oid_init ();
+    oident = oid_getentbyoid_x (oid);
+    if (!oident)
+	oident = oid_addent (oid, PROTO_GENERAL, CLASS_GENERAL,
+			     NULL, VAL_DYNAMIC);
+    return oident;
+}
+
+static oid_value oid_getval_raw(const char *name)
+{
+    int val = 0, i = 0, oid[OID_SIZE];
+    struct oident *oident;
+    
+    while (isdigit (*name))
+    {
+        val = val*10 + (*name - '0');
+        name++;
+        if (*name == '.')
+        {
+            if (i < OID_SIZE-1)
+                oid[i++] = val;
+	    val = 0;
+            name++;
+        }
+    }
+    oid[i] = val;
+    oid[i+1] = -1;
+    oident = oid_addent (oid, PROTO_GENERAL, CLASS_GENERAL, NULL,
+			 VAL_DYNAMIC);
+    return oident->value;
+}
+
+oid_value oid_getvalbyname(const char *name)
+{
+    struct oident_list *ol;
+
+    oid_init ();
+    if (isdigit (*name))
+        return oid_getval_raw (name);
+    for (ol = oident_table; ol; ol = ol->next)
+	if (!yaz_matchstr(ol->oident.desc, name))
+	{
+	    return ol->oident.value;
+	}
+    return VAL_NONE;
+}
+
+void oid_setprivateoids(oident *list)
+{
+    oid_transfer (list);
+}
Index: /main/tags/2.25/gsdl/packages/yaz/util/options.c
===================================================================
--- /main/tags/2.25/gsdl/packages/yaz/util/options.c	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/yaz/util/options.c	(revision 21064)
@@ -0,0 +1,121 @@
+/*
+ * Copyright (c) 1995-2000, Index Data
+ * See the file LICENSE for details.
+ * Sebastian Hammer, Adam Dickmeiss
+ *
+ * $Log$
+ * Revision 1.1  2000/08/03 03:12:09  johnmcp
+ * Added the YAZ toolkit source to the packages directory (for z39.50 stuff)
+ *
+ * Revision 1.8  2000/02/29 13:44:55  adam
+ * Check for config.h (currently not generated).
+ *
+ * Revision 1.7  1999/11/30 13:47:12  adam
+ * Improved installation. Moved header files to include/yaz.
+ *
+ * Revision 1.6  1997/09/01 08:54:13  adam
+ * New windows NT/95 port using MSV5.0. Made prefix query handling
+ * thread safe. The function options ignores empty arguments when met.
+ *
+ * Revision 1.5  1995/12/06 13:00:19  adam
+ * Minus alone not treated as an option.
+ *
+ * Revision 1.4  1995/09/29  17:12:35  quinn
+ * Smallish
+ *
+ * Revision 1.3  1995/09/27  15:03:03  quinn
+ * Modified function heads & prototypes.
+ *
+ * Revision 1.2  1995/05/16  08:51:13  quinn
+ * License, documentation, and memory fixes
+ *
+ * Revision 1.1  1995/03/27  08:35:18  quinn
+ * Created util library
+ * Added memory debugging module. Imported options-manager
+ *
+ * Revision 1.2  1994/10/04  17:47:10  adam
+ * Function options now returns arg with error option.
+ *
+ * Revision 1.1  1994/08/16  15:57:22  adam
+ * The first utility modules.
+ *
+ */
+#if HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <stdlib.h>
+
+#include <yaz/options.h>
+
+static int arg_no = 1;
+static int arg_off = 0;
+
+int options (const char *desc, char **argv, int argc, char **arg)
+{
+    int ch, i = 0;
+    
+    if (arg_no >= argc)
+        return -2;
+    if (arg_off == 0)
+    {
+        while (argv[arg_no][0] == '\0')
+        {
+            arg_no++;
+            if (arg_no >= argc)
+                return -2;
+        }
+        if (argv[arg_no][0] != '-' || argv[arg_no][1] == '\0')
+        {
+            *arg = argv[arg_no++];
+            return 0;
+        }
+        arg_off++;
+    }
+    ch = argv[arg_no][arg_off++];
+    while (desc[i])
+    {
+        int desc_char = desc[i++];
+        int type = 0;
+        if (desc[i] == ':')
+	{	/* string argument */
+            type = desc[i++];
+	}
+        if (desc_char == ch)
+	{ /* option with argument */
+            if (type)
+	    {
+                if (argv[arg_no][arg_off])
+		{
+                    *arg = argv[arg_no]+arg_off;
+                    arg_no++;
+                    arg_off =  0;
+		}
+                else
+		{
+                    arg_no++;
+                    arg_off = 0;
+                    if (arg_no < argc)
+                        *arg = argv[arg_no++];
+                    else
+                        *arg = "";
+		}
+	    }
+            else /* option with no argument */
+	    {
+                if (argv[arg_no][arg_off])
+                    arg_off++;
+                else
+		{
+                    arg_off = 0;
+                    arg_no++;
+		}
+	    }
+            return ch;
+	}		
+    }
+    *arg = argv[arg_no]+arg_off-1;
+    arg_no = arg_no + 1;
+    arg_off = 0;
+    return -1;
+}
Index: /main/tags/2.25/gsdl/packages/yaz/util/readconf.c
===================================================================
--- /main/tags/2.25/gsdl/packages/yaz/util/readconf.c	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/yaz/util/readconf.c	(revision 21064)
@@ -0,0 +1,132 @@
+/*
+ * Copyright (C) 1994-2000, Index Data
+ * All rights reserved.
+ * Sebastian Hammer, Adam Dickmeiss
+ *
+ * $Log$
+ * Revision 1.1  2000/08/03 03:12:10  johnmcp
+ * Added the YAZ toolkit source to the packages directory (for z39.50 stuff)
+ *
+ * Revision 1.10  2000/02/29 13:44:55  adam
+ * Check for config.h (currently not generated).
+ *
+ * Revision 1.9  1999/11/30 13:47:12  adam
+ * Improved installation. Moved header files to include/yaz.
+ *
+ * Revision 1.8  1999/08/27 09:40:32  adam
+ * Renamed logf function to yaz_log. Removed VC++ project files.
+ *
+ * Revision 1.7  1999/06/30 09:10:32  adam
+ * Fixed reading of MS-DOS files.
+ *
+ * Revision 1.6  1998/10/13 16:09:55  adam
+ * Added support for arbitrary OID's for tagsets, schemas and attribute sets.
+ * Added support for multiple attribute set references and tagset references
+ * from an abstract syntax file.
+ * Fixed many bad logs-calls in routines that read the various
+ * specifications regarding data1 (*.abs,*.att,...) and made the messages
+ * consistent whenever possible.
+ * Added extra 'lineno' argument to function readconf_line.
+ *
+ * Revision 1.5  1997/09/04 07:53:02  adam
+ * Added include readconf.h.
+ *
+ * Revision 1.4  1997/05/14 06:54:07  adam
+ * C++ support.
+ *
+ * Revision 1.3  1996/05/29 15:48:48  quinn
+ * Added \n to the isspace rule.
+ *
+ * Revision 1.2  1996/05/29  10:05:01  quinn
+ * Changed space criteria to support 8-bit characters
+ *
+ * Revision 1.1  1995/11/01  13:55:06  quinn
+ * Minor adjustments
+ *
+ * Revision 1.2  1995/10/30  13:54:27  quinn
+ * iRemoved fclose().
+ *
+ * Revision 1.1  1995/10/10  16:28:18  quinn
+ * Initial revision
+ *
+ *
+ */
+#if HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <stdio.h>
+#include <ctype.h>
+
+#include <yaz/log.h>
+#include <yaz/readconf.h>
+
+#define l_isspace(c) ((c) == '\t' || (c) == ' ' || (c) == '\n' || (c) == '\r')
+
+int readconf_line(FILE *f, int *lineno, char *line, int len,
+		  char *argv[], int num)
+{
+    char *p;
+    int argc;
+    
+    while ((p = fgets(line, len, f)))
+    {
+	(*lineno)++;
+	while (*p && l_isspace(*p))
+	    p++;
+	if (*p && *p != '#')
+	    break;
+    }
+    if (!p)
+	return 0;
+    
+    for (argc = 0; *p ; argc++)
+    {
+	if (*p == '#')  /* trailing comment */
+	    break;
+	argv[argc] = p;
+	while (*p && !l_isspace(*p))
+	    p++;
+	if (*p)
+	{
+	    *(p++) = '\0';
+	    while (*p && l_isspace(*p))
+		p++;
+	}
+    }
+    return argc;
+}
+
+/*
+ * Read lines of a configuration file.
+ */
+int readconf(char *name, void *rprivate,
+	     int (*fun)(char *name, void *rprivate, int argc, char *argv[]))
+{
+    FILE *f;
+    char line[512], *m_argv[50];
+    int m_argc;
+    int lineno = 0;
+    
+    if (!(f = fopen(name, "r")))
+    {
+	yaz_log(LOG_WARN|LOG_ERRNO, "readconf: %s", name);
+	return -1;
+    }
+    for (;;)
+    {
+	int res;
+	
+	if (!(m_argc = readconf_line(f, &lineno, line, 512, m_argv, 50)))
+	{
+	    fclose(f);
+	    return 0;
+	}
+
+	if ((res = (*fun)(name, rprivate, m_argc, m_argv)))
+	{
+	    fclose(f);
+	    return res;
+	}
+    }
+}
Index: /main/tags/2.25/gsdl/packages/yaz/util/tpath.c
===================================================================
--- /main/tags/2.25/gsdl/packages/yaz/util/tpath.c	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/yaz/util/tpath.c	(revision 21064)
@@ -0,0 +1,53 @@
+/*
+ * Copyright (c) 1995-2000, Index Data.
+ * See the file LICENSE for details.
+ * Sebastian Hammer, Adam Dickmeiss
+ *
+ * $Log$
+ * Revision 1.1  2000/08/03 03:12:10  johnmcp
+ * Added the YAZ toolkit source to the packages directory (for z39.50 stuff)
+ *
+ * Revision 1.4  2000/02/29 13:44:55  adam
+ * Check for config.h (currently not generated).
+ *
+ * Revision 1.3  1999/11/30 13:47:12  adam
+ * Improved installation. Moved header files to include/yaz.
+ *
+ * Revision 1.2  1996/10/29 13:36:26  adam
+ * Added header.
+ *
+ * Revision 1.1  1995/11/01 16:35:00  quinn
+ * Making data1 look for tables in data1_tabpath
+ *
+ *
+ */
+#if HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <stdio.h>
+#include <string.h>
+#include <yaz/tpath.h>
+
+FILE *yaz_path_fopen(const char *path, const char *name, const char *mode)
+{
+    char spath[512] = "";
+
+    if (!path)
+	return fopen(name, mode);
+
+    do
+    {
+	FILE *f;
+
+	if (sscanf(path, "%511[^:]", spath) < 1)
+	    return 0;
+	sprintf(spath + strlen(spath), "/%s", name);
+	if ((f = fopen(spath, mode)))
+	    return f;
+	if ((path = strchr(path, ':')))
+	    path++;
+    }
+    while (path);
+    return 0;
+}
Index: /main/tags/2.25/gsdl/packages/yaz/util/wrbuf.c
===================================================================
--- /main/tags/2.25/gsdl/packages/yaz/util/wrbuf.c	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/yaz/util/wrbuf.c	(revision 21064)
@@ -0,0 +1,110 @@
+/*
+ * Copyright (c) 1995-2000, Index Data.
+ * See the file LICENSE for details.
+ * Sebastian Hammer, Adam Dickmeiss
+ *
+ * $Log$
+ * Revision 1.1  2000/08/03 03:12:11  johnmcp
+ * Added the YAZ toolkit source to the packages directory (for z39.50 stuff)
+ *
+ * Revision 1.9  2000/02/29 13:44:55  adam
+ * Check for config.h (currently not generated).
+ *
+ * Revision 1.8  1999/11/30 13:47:12  adam
+ * Improved installation. Moved header files to include/yaz.
+ *
+ * Revision 1.7  1999/11/03 09:05:56  adam
+ * Implemented wrbuf_puts.
+ *
+ * Revision 1.6  1999/10/28 11:36:40  adam
+ * wrbuf_write allows zero buffer length.
+ *
+ * Revision 1.5  1999/08/27 09:40:32  adam
+ * Renamed logf function to yaz_log. Removed VC++ project files.
+ *
+ * Revision 1.4  1998/02/11 11:53:36  adam
+ * Changed code so that it compiles as C++.
+ *
+ * Revision 1.3  1997/05/01 15:08:15  adam
+ * Added log_mask_str_x routine.
+ *
+ * Revision 1.2  1995/11/01 13:55:06  quinn
+ * Minor adjustments
+ *
+ * Revision 1.1  1995/10/06  08:51:25  quinn
+ * Added Write-buffer.
+ *
+ *
+ */
+
+/*
+ * Growing buffer for writing various stuff.
+ */
+
+#if HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <stdlib.h>
+#include <string.h>
+
+#include <yaz/wrbuf.h>
+
+WRBUF wrbuf_alloc(void)
+{
+    WRBUF n;
+
+    if (!(n = (WRBUF)xmalloc(sizeof(*n))))
+	abort();
+    n->buf = 0;
+    n->size = 0;
+    n->pos = 0;
+    return n;
+}
+
+void wrbuf_free(WRBUF b, int free_buf)
+{
+    if (free_buf && b->buf)
+	xfree(b->buf);
+    xfree(b);
+}
+
+void wrbuf_rewind(WRBUF b)
+{
+    b->pos = 0;
+}
+
+int wrbuf_grow(WRBUF b, int minsize)
+{
+    int togrow;
+
+    if (!b->size)
+    	togrow = 1024;
+    else
+    	togrow = b->size;
+    if (togrow < minsize)
+    	togrow = minsize;
+    if (b->size && !(b->buf =(char *)xrealloc(b->buf, b->size += togrow)))
+    	abort();
+    else if (!b->size && !(b->buf = (char *)xmalloc(b->size = togrow)))
+    	abort();
+    return 0;
+}
+
+int wrbuf_write(WRBUF b, const char *buf, int size)
+{
+    if (size <= 0)
+        return 0;
+    if (b->pos + size >= b->size)
+	wrbuf_grow(b, size);
+    memcpy(b->buf + b->pos, buf, size);
+    b->pos += size;
+    return 0;
+}
+
+int wrbuf_puts(WRBUF b, const char *buf)
+{
+    wrbuf_write(b, buf, strlen(buf)+1);  /* '\0'-terminate as well */
+    (b->pos)--;                          /* don't include '\0' in count */
+    return 0;
+}
Index: /main/tags/2.25/gsdl/packages/yaz/util/xmalloc.c
===================================================================
--- /main/tags/2.25/gsdl/packages/yaz/util/xmalloc.c	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/yaz/util/xmalloc.c	(revision 21064)
@@ -0,0 +1,331 @@
+/*
+ * Copyright (C) 1994-2000, Index Data
+ * All rights reserved.
+ * Sebastian Hammer, Adam Dickmeiss
+ *
+ * $Log$
+ * Revision 1.1  2000/08/03 03:12:11  johnmcp
+ * Added the YAZ toolkit source to the packages directory (for z39.50 stuff)
+ *
+ * Revision 1.11  2000/02/29 13:44:55  adam
+ * Check for config.h (currently not generated).
+ *
+ * Revision 1.10  1999/11/30 13:47:12  adam
+ * Improved installation. Moved header files to include/yaz.
+ *
+ * Revision 1.9  1999/09/10 08:58:32  adam
+ * Set TRACE_XMALLOC to 1.
+ *
+ * Revision 1.8  1999/08/27 09:40:32  adam
+ * Renamed logf function to yaz_log. Removed VC++ project files.
+ *
+ * Revision 1.7  1999/07/13 13:24:53  adam
+ * Updated memory debugging memory allocatation routines.
+ *
+ * Revision 1.6  1998/02/11 11:53:36  adam
+ * Changed code so that it compiles as C++.
+ *
+ * Revision 1.5  1997/10/31 12:20:09  adam
+ * Improved memory debugging for xmalloc/nmem.c. References to NMEM
+ * instead of ODR in n ESPEC-1 handling in source d1_espec.c.
+ * Bug fix: missing fclose in data1_read_espec1.
+ *
+ * Revision 1.4  1996/07/03 13:21:36  adam
+ * Function xfree_f checks for NULL pointer.
+ *
+ * Revision 1.3  1995/12/05  15:08:44  adam
+ * Fixed verbose of xrealloc.
+ *
+ * Revision 1.2  1995/12/05  11:08:37  adam
+ * More verbose malloc routines.
+ *
+ * Revision 1.1  1995/11/01  11:56:53  quinn
+ * Added Xmalloc.
+ *
+ * Revision 1.6  1995/10/16  14:03:11  quinn
+ * Changes to support element set names and espec1
+ *
+ * Revision 1.5  1995/09/04  12:34:06  adam
+ * Various cleanup. YAZ util used instead.
+ *
+ * Revision 1.4  1994/10/05  10:16:16  quinn
+ * Added xrealloc. Fixed bug in log.
+ *
+ * Revision 1.3  1994/09/26  16:31:37  adam
+ * Added xcalloc_f.
+ *
+ * Revision 1.2  1994/08/18  08:23:26  adam
+ * Res.c now use handles. xmalloc defines xstrdup.
+ *
+ * Revision 1.1  1994/08/17  13:37:54  adam
+ * xmalloc.c added to util.
+ *
+ */
+
+#if HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <yaz/log.h>
+#include <yaz/xmalloc.h>
+
+#define TRACE_XMALLOC 1
+
+#if TRACE_XMALLOC > 1
+
+static const unsigned char head[] = {44, 33, 22, 11};
+static const unsigned char tail[] = {11, 22, 33, 44};
+static const unsigned char freed[] = {11, 22, 33, 44};
+
+struct dmalloc_info {
+    int len;
+    char file[16];
+    int line;
+    struct dmalloc_info *next;
+    struct dmalloc_info *prev;
+};
+
+struct dmalloc_info *dmalloc_list = 0;
+
+void *xmalloc_d(size_t nbytes, const char *file, int line)
+{
+    char *res;
+    struct dmalloc_info *dinfo;
+    
+    if (!(res = (char*) malloc(nbytes + sizeof(*dinfo)+8*sizeof(char))))
+	return 0;
+    dinfo = (struct dmalloc_info *) res;
+    strncpy (dinfo->file, file, sizeof(dinfo->file)-1);
+    dinfo->file[sizeof(dinfo->file)-1] = '\0';
+    dinfo->line = line;
+    dinfo->len = nbytes;
+    
+    dinfo->prev = 0;
+    dinfo->next = dmalloc_list;
+    if (dinfo->next)
+	dinfo->next->prev = dinfo;
+    dmalloc_list = dinfo;
+    
+    memcpy(res + sizeof(*dinfo), head, 4*sizeof(char));
+    res += sizeof(*dinfo) + 4*sizeof(char);
+    memcpy(res + nbytes, tail, 4*sizeof(char));
+    return res;
+}
+
+void xfree_d(void *ptr, const char *file, int line)
+{
+    struct dmalloc_info *dinfo;
+
+    if (!ptr)
+	return;
+    dinfo = (struct dmalloc_info *)
+	((char*)ptr - 4*sizeof(char) - sizeof(*dinfo));
+    if (memcmp(head, (char*) ptr - 4*sizeof(char), 4*sizeof(char)))
+    {
+	yaz_log(LOG_FATAL, "xfree_d bad head, %s:%d, %p", file, line, ptr);
+        abort();
+    }
+    if (memcmp((char*) ptr + dinfo->len, tail, 4*sizeof(char)))
+    {
+	yaz_log(LOG_FATAL, "xfree_d bad tail, %s:%d, %p", file, line, ptr);
+        abort();
+    }
+    if (dinfo->prev)
+	dinfo->prev->next = dinfo->next;
+    else
+	dmalloc_list = dinfo->next;
+    if (dinfo->next)
+	dinfo->next->prev = dinfo->prev;
+    memcpy ((char*) ptr - 4*sizeof(char), freed, 4*sizeof(char));
+    free(dinfo);
+    return;
+}
+
+void *xrealloc_d(void *p, size_t nbytes, const char *file, int line)
+{
+    struct dmalloc_info *dinfo;
+    char *ptr = (char*) p;
+    char *res;
+    
+    if (!ptr)
+    {
+	if (!nbytes)
+	    return 0;
+	res = (char *) malloc(nbytes + sizeof(*dinfo) + 8*sizeof(char));
+    }
+    else
+    {
+	if (memcmp(head, ptr - 4*sizeof(char), 4*sizeof(char)))
+	{
+	    yaz_log(LOG_FATAL, "xrealloc_d bad head, %s:%d, %p",
+		    file, line, ptr);
+	    abort();
+	}
+	dinfo = (struct dmalloc_info *) (ptr-4*sizeof(char) - sizeof(*dinfo));
+	if (memcmp(ptr + dinfo->len, tail, 4*sizeof(char)))
+	{
+	    yaz_log(LOG_FATAL, "xrealloc_d bad tail, %s:%d, %p",
+		    file, line, ptr);
+	    abort();
+	}
+	if (dinfo->prev)
+	    dinfo->prev->next = dinfo->next;
+	else
+	    dmalloc_list = dinfo->next;
+	if (dinfo->next)
+	    dinfo->next->prev = dinfo->prev;
+	
+	if (!nbytes)
+	{
+	    free (dinfo);
+	    return 0;
+	}
+	res = (char *)
+	    realloc(dinfo, nbytes + sizeof(*dinfo) + 8*sizeof(char));
+    }
+    if (!res)
+	return 0;
+    dinfo = (struct dmalloc_info *) res;
+    strncpy (dinfo->file, file, sizeof(dinfo->file)-1);
+    dinfo->file[sizeof(dinfo->file)-1] = '\0';
+    dinfo->line = line;
+    dinfo->len = nbytes;
+
+    dinfo->prev = 0;
+    dinfo->next = dmalloc_list;
+    if (dmalloc_list)
+	dmalloc_list->prev = dinfo;
+    dmalloc_list = dinfo;
+    
+    memcpy(res + sizeof(*dinfo), head, 4*sizeof(char));
+    res += sizeof(*dinfo) + 4*sizeof(char);
+    memcpy(res + nbytes, tail, 4*sizeof(char));
+    return res;
+}
+
+void *xcalloc_d(size_t nmemb, size_t size, const char *file, int line)
+{
+    char *res;
+    struct dmalloc_info *dinfo;
+    size_t nbytes = nmemb * size;
+    
+    if (!(res = (char*) calloc(1, nbytes+sizeof(*dinfo)+8*sizeof(char))))
+	return 0;
+    dinfo = (struct dmalloc_info *) res;
+    strncpy (dinfo->file, file, sizeof(dinfo->file)-1);
+    dinfo->file[sizeof(dinfo->file)-1] = '\0';
+    dinfo->line = line;
+    dinfo->len = nbytes;
+    
+    dinfo->prev = 0;
+    dinfo->next = dmalloc_list;
+    if (dinfo->next)
+	dinfo->next->prev = dinfo;
+    dmalloc_list = dinfo;
+    
+    memcpy(res + sizeof(*dinfo), head, 4*sizeof(char));
+    res += sizeof(*dinfo) + 4*sizeof(char);
+    memcpy(res + nbytes, tail, 4*sizeof(char));
+    return res;
+}
+
+void xmalloc_trav_d(const char *file, int line)
+{
+    size_t size = 0;
+    struct dmalloc_info *dinfo = dmalloc_list;
+    
+    yaz_log (LOG_LOG, "malloc_trav %s:%d", file, line);
+    while (dinfo)
+    {
+	yaz_log (LOG_LOG, " %20s:%d p=%p size=%d", dinfo->file, dinfo->line,
+	      dinfo+sizeof(*dinfo)+4*sizeof(char), dinfo->len);
+	size += dinfo->len;
+	dinfo = dinfo->next;
+    }
+    yaz_log (LOG_LOG, "total bytes %ld", (long) size);
+}
+
+#else
+/* TRACE_XMALLOC <= 1 */
+#define xrealloc_d(o, x, f, l) realloc(o, x)
+#define xmalloc_d(x, f, l) malloc(x)
+#define xcalloc_d(x,y, f, l) calloc(x,y)
+#define xfree_d(x, f, l) free(x)
+#define xmalloc_trav_d(f, l) 
+#endif
+
+void xmalloc_trav_f(const char *s, const char *file, int line)
+{
+    xmalloc_trav_d(file, line);
+}
+
+void *xrealloc_f (void *o, size_t size, const char *file, int line)
+{
+    void *p = xrealloc_d (o, size, file, line);
+
+#if TRACE_XMALLOC
+    yaz_log (LOG_DEBUG,
+            "%s:%d: xrealloc(s=%d) %p -> %p", file, line, size, o, p);
+#endif
+    if (!p)
+    {
+    	yaz_log (LOG_FATAL|LOG_ERRNO, "Out of memory, realloc (%d bytes)",
+		 size);
+    	exit(1);
+    }
+    return p;
+}
+
+void *xmalloc_f (size_t size, const char *file, int line)
+{
+    void *p = xmalloc_d (size, file, line);
+    
+#if TRACE_XMALLOC
+    yaz_log (LOG_DEBUG, "%s:%d: xmalloc(s=%d) %p", file, line, size, p);
+#endif
+    if (!p)
+    {
+        yaz_log (LOG_FATAL, "Out of memory - malloc (%d bytes)", size);
+        exit (1);
+    }
+    return p;
+}
+
+void *xcalloc_f (size_t nmemb, size_t size, const char *file, int line)
+{
+    void *p = xcalloc_d (nmemb, size, file, line);
+#if TRACE_XMALLOC
+    yaz_log (LOG_DEBUG, "%s:%d: xcalloc(s=%d) %p", file, line, size, p);
+#endif
+    if (!p)
+    {
+        yaz_log (LOG_FATAL, "Out of memory - calloc (%d, %d)", nmemb, size);
+        exit (1);
+    }
+    return p;
+}
+
+char *xstrdup_f (const char *s, const char *file, int line)
+{
+    char *p = (char *)xmalloc_d (strlen(s)+1, file, line);
+#if TRACE_XMALLOC
+    yaz_log (LOG_DEBUG, "%s:%d: xstrdup(s=%d) %p", file, line, strlen(s)+1, p);
+#endif
+    strcpy (p, s);
+    return p;
+}
+
+void xfree_f(void *p, const char *file, int line)
+{
+    if (!p)
+        return ;
+#if TRACE_XMALLOC
+    if (p)
+        yaz_log (LOG_DEBUG, "%s:%d: xfree %p", file, line, p);
+#endif
+    xfree_d(p, file, line);
+}
Index: /main/tags/2.25/gsdl/packages/yaz/util/yaz-comp
===================================================================
--- /main/tags/2.25/gsdl/packages/yaz/util/yaz-comp	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/yaz/util/yaz-comp	(revision 21064)
@@ -0,0 +1,1437 @@
+#!/bin/sh
+# the next line restarts using tclsh \
+if /usr/bin/test -e "`which tclsh`" ;then exec tclsh "$0" "$@";else exec tclsh8.0 "$0" "$@";fi
+#
+# yaz-comp: ASN.1 Compiler for YAZ
+# (c) Index Data 1996-2000
+# See the file LICENSE for details.
+#
+# Revision 1.1  2000/03/02 08:48:20  adam
+# Renamed ASN.1 compiler to yaz-comp (used to be yc.tcl).
+#
+# Revision 1.6  2000/02/10 13:44:02  adam
+# Tcl command clock not used if unavailable (Tcl7.4 and earlier).
+#
+# Revision 1.5  2000/01/15 09:18:42  adam
+# Bug fix: some elements where treated as OPTIONAL when they shouldn't.
+#
+# Revision 1.4  1999/12/16 23:36:19  adam
+# Implemented ILL protocol. Minor updates ASN.1 compiler.
+#
+# Revision 1.3  1999/11/30 13:47:12  adam
+# Improved installation. Moved header files to include/yaz.
+#
+# Revision 1.2  1999/06/09 09:43:11  adam
+# Added option -I and variable h-path to specify path for header files.
+#
+# Revision 1.1  1999/06/08 10:10:16  adam
+# New sub directory zutil. Moved YAZ Compiler to be part of YAZ tree.
+#
+# Revision 1.8  1999/04/20 10:37:04  adam
+# Updated for ODR - added name parameter.
+#
+# Revision 1.7  1998/04/03 14:44:20  adam
+# Small fix.
+#
+# Revision 1.6  1998/04/03 13:21:17  adam
+# Yet another fix.
+#
+# Revision 1.5  1998/04/03 12:48:17  adam
+# Fixed bug: missed handling of constructed tags for CHOICE.
+#
+# Revision 1.4  1998/03/31 15:47:45  adam
+# First compiled ASN.1 code for YAZ.
+#
+# Revision 1.3  1998/03/23 17:13:20  adam
+# Implemented SET OF and ENUM. The Compiler now eats ILL (ISO10161) and
+# LDAP (RFC1777).
+#
+# Revision 1.2  1997/10/07 10:31:01  adam
+# Added facility to specify tag type (CONTEXT, APPLICATION, ...).
+#
+# Revision 1.1.1.1  1996/10/31 14:04:40  adam
+# First version of the compiler for YAZ.
+#
+#
+
+set yc_version 0.3
+
+# Syntax for the ASN.1 supported:
+# file   -> file module
+#         | module
+# module -> name skip DEFINITIONS ::= mbody END
+# mbody  -> EXPORTS { nlist }
+#         | IMPORTS { imlist }
+#         | name ::= tmt
+#         | skip
+# tmt    -> tag mod type
+# type   -> SEQUENCE { sqlist }
+#         | SEQUENCE OF type
+#         | CHOICE { chlist }
+#         | basic enlist
+#
+# basic  -> INTEGER
+#         | BOOLEAN
+#         | OCTET STRING
+#         | BIT STRING
+#         | EXTERNAL
+#         | name
+# sqlist -> sqlist , name tmt opt
+#         | name tmt opt
+# chlist -> chlist , name tmt 
+#         | name tmt 
+# enlist -> enlist , name (n)
+#         | name (n)
+# imlist -> nlist FROM name
+#           imlist nlist FROM name
+# nlist  -> name
+#         | nlist , name
+# mod   -> IMPLICIT | EXPLICIT | e
+# tag   -> [tagtype n] | [n] | e
+# opt   -> OPTIONAL | e
+#
+# name    identifier/token 
+# e       epsilon/empty 
+# skip    one token skipped
+# n       number
+# tagtype APPLICATION, CONTEXT, etc.
+
+# lex: moves input file pointer and returns type of token.
+# The globals $type and $val are set. $val holds name if token
+# is normal identifier name.
+# sets global var type to one of:
+#     {}     eof-of-file
+#     \{     left curly brace 
+#     \}     right curly brace
+#     ,      comma
+#     ;      semicolon
+#     (      (n)
+#     [      [n]
+#     :      ::=
+#     n      other token n
+proc lex {} {
+    global inf val type
+    while {![string length $inf(str)]} {
+        incr inf(lineno)
+        set inf(cnt) [gets $inf(inf) inf(str)]
+        if {$inf(cnt) < 0} {
+            set type {}
+            return {}
+        }
+	lappend inf(asn,$inf(asndef)) $inf(str)
+        set l [string first -- $inf(str)]
+        if {$l >= 0} {
+            incr l -1
+            set inf(str) [string range $inf(str) 0 $l]
+        }
+        set inf(str) [string trim $inf(str)]
+    }
+    set s [string index $inf(str) 0]
+    set type $s
+    set val {}
+    switch -- $s {
+        \{ { }
+        \} { }
+        ,  { }
+        ;  { }
+	\(  { }
+	\)  { }
+        \[ { regexp {^\[[ ]*(.+)[ ]*\]} $inf(str) s val }
+        :  { regexp {^::=} $inf(str) s }
+        default {
+             regexp "^\[^,\t :\{\}();\]+" $inf(str) s
+             set type n
+             set val $s
+           }
+    }
+    set off [string length $s]
+    set inf(str) [string trim [string range $inf(str) $off end]]
+    return $type
+}
+
+# lex-expect: move pointer and expect token $t
+proc lex-expect {t} {
+    global type val
+    lex
+    if {[string compare $t $type]} {
+        asnError "Got $type '$val', expected $t"
+    }
+}
+
+# lex-name-move: see if token is $name; moves pointer and returns
+# 1 if it is; returns 0 otherwise.
+proc lex-name-move {name} {
+    global type val
+    if {![string compare $type n] && ![string compare $val $name]} {
+        lex
+        return 1
+    }
+    return 0
+}
+
+# asnError: Report error and die
+proc asnError {msg} {
+    global inf
+   
+    puts "Error in line $inf(lineno) in module $inf(module)"
+    puts " $msg"
+    error
+    exit 1
+}
+
+# asnWarning: Report warning and return
+proc asnWarning {msg} {
+    global inf
+   
+    puts "Warning in line $inf(lineno) in module $inf(module)"
+    puts " $msg"
+}
+
+# asnEnum: parses enumerated list - { name1 (n), name2 (n), ... }
+# Uses $name as prefix. If there really is a list, $lx holds the C
+# preprocessor definitions on return; otherwise lx isn't set.
+proc asnEnum {name lx} {
+    global type val inf
+
+    if {[string compare $type \{]} return
+    upvar $lx l
+    while {1} {
+	set pq [asnName $name]
+        set id [lindex $pq 0]
+	set id ${name}_$id
+	lex-expect n
+        lappend l "#define $inf(dprefix)$id $val"
+	lex-expect ")"
+        lex
+        if {[string compare $type ,]} break
+    }
+    if {[string compare $type \}]} {
+        asnError "Missing \} in enum list got $type '$val'"
+    }
+    lex
+}
+
+# asnMod: parses tag and modifier.
+# $xtag and $ximplicit holds tag and implicit-indication on return.
+# $xtag is empty if no tag was specified. $ximplicit is 1 on implicit
+# tagging; 0 otherwise.
+proc asnMod {xtag ximplicit xtagtype} {
+    global type val inf
+
+    upvar $xtag tag
+    upvar $ximplicit implicit
+    upvar $xtagtype tagtype
+
+    set tag {} 
+    set tagtype {}
+    if {![string compare $type \[]} {
+        if {[regexp {^([a-zA-Z]+)[ ]+([0-9]+)$} $val x tagtype tag]} {
+            set tagtype ODR_$tagtype 
+        } elseif {[regexp {^([0-9]+)$} $val x tag]} {
+            set tagtype ODR_CONTEXT
+        } else {
+            asnError "bad tag specification: $val"
+        }
+	lex
+    }
+    set implicit $inf(implicit-tags)
+    if {![string compare $type n]} {
+        if {![string compare $val EXPLICIT]} {
+            lex
+            set implicit 0
+        } elseif {![string compare $val IMPLICIT]} {
+            lex
+            set implicit 1
+        }
+    }
+}
+
+# asnName: moves pointer and expects name. Returns C-validated name.
+proc asnName {name} {
+    global val inf
+    lex-expect n
+    if {[info exists inf(membermap,$inf(module),$name,$val)]} {
+	    set nval $inf(membermap,$inf(module),$name,$val)
+	if {$inf(verbose)} {
+	    puts " mapping member $name,$val to $nval"
+	}
+	lex
+    } else {
+	set nval $val
+	if {![string match {[A-Z]*} $val]} {
+	    lex
+	}
+    }
+    return [join [split $nval -] _]
+}
+
+# asnOptional: parses optional modifier. Returns 1 if OPTIONAL was 
+# specified; 0 otherwise.
+proc asnOptional {} {
+    global type val
+    if {[lex-name-move OPTIONAL]} {
+        return 1
+    } elseif {[lex-name-move DEFAULT]} {
+	lex
+	return 0
+    }
+    return 0
+}
+
+# asnSizeConstraint: parses the optional SizeConstraint.
+# Currently not used for anything.
+proc asnSizeConstraint {} {
+    global type val
+    if {[lex-name-move SIZE]} {
+	asnSubtypeSpec
+    }
+}
+
+# asnSubtypeSpec: parses the SubtypeSpec ...
+# Currently not used for anything. We now it's balanced however, i.e.
+# (... ( ... ) .. )
+proc asnSubtypeSpec {} {
+    global type val
+
+    if {[string compare $type "("]} {
+	return 
+    }
+    lex
+    set level 1
+    while {$level > 0} {
+	if {![string compare $type "("]} {
+	    incr level
+	} elseif {![string compare $type ")"]} {
+	    incr level -1
+	}
+	lex
+    }
+}
+
+# asnType: parses ASN.1 type.
+# On entry $name should hold the name we are currently defining.
+# Returns type indicator:
+#   SequenceOf     SEQUENCE OF
+#   Sequence       SEQUENCE 
+#   SetOf          SET OF
+#   Set            SET
+#   Choice         CHOICE
+#   Simple         Basic types.
+#   In this casecalling procedure's $tname variable is a list holding:
+#        {C-Function C-Type} if the type is IMPORTed or ODR defined.
+#      or
+#        {C-Function C-Type 1} if the type should be defined in this module
+proc asnType {name} {
+    global type val inf
+    upvar tname tname
+
+    set tname {}
+    if {[string compare $type n]} {
+        asnError "Expects type specifier, but got $type"
+    }
+    set v $val
+    lex
+    switch -- $v {
+        SEQUENCE {
+	    asnSizeConstraint
+	    if {[lex-name-move OF]} {
+		asnSubtypeSpec
+		return SequenceOf
+	    } else {
+		asnSubtypeSpec
+		return Sequence
+	    }
+	}
+	SET {
+	    asnSizeConstraint
+	    if {[lex-name-move OF]} {
+		asnSubtypeSpec
+		return SetOf
+	    } else {
+		asnSubtypeSpec
+		return Set
+	    }
+        }
+        CHOICE {
+	    asnSubtypeSpec
+            return Choice
+        }
+    }
+    if {[string length [info commands asnBasic$v]]} {
+        set tname [asnBasic$v]
+    } else {
+        if {[info exists inf(map,$inf(module),$v)]} {
+            set v $inf(map,$inf(module),$v)
+        }
+        if {[info exists inf(imports,$v)]} {
+            set tname $inf(imports,$v)
+        } else {
+            set w [join [split $v -] _]
+            set tname [list $inf(fprefix)$w $inf(vprefix)$w 1]
+        }
+    }
+    if {[lex-name-move DEFINED]} {
+	if {[lex-name-move BY]} {
+	    lex
+	}
+    }
+    asnSubtypeSpec
+    return Simple
+}
+
+proc mapName {name} {
+    global inf
+    if {[info exists inf(map,$inf(module),$name)]} {
+        set name $inf(map,$inf(module),$name)
+	if {$inf(verbose)} {
+	    puts -nonewline " $name ($inf(lineno))"
+	    puts " mapping to $name"
+	}
+    } else {
+	if {$inf(verbose)} {
+	    puts " $name ($inf(lineno))"
+	}
+    }
+    return $name
+}
+
+# asnDef: parses type definition (top-level) and generates C code
+# On entry $name holds the type we are defining.
+proc asnDef {name} {
+    global inf file
+
+    set name [mapName $name]
+    if {[info exist inf(defined,$inf(fprefix)$name)]} {
+        incr inf(definedl,$name)
+        if {$inf(verbose) > 1} {
+            puts "set map($inf(module),$name) $name$inf(definedl,$name)"
+        }
+    } else {
+        set inf(definedl,$name) 0
+    }
+    set mname [join [split $name -] _]
+    asnMod tag implicit tagtype
+    set t [asnType $mname]
+    asnSub $mname $t $tname $tag $implicit $tagtype
+}
+
+
+# asnSub: parses type and generates C-code
+# On entry,
+#   $name holds the type we are defining.
+#   $t is the type returned by the asnType procedure.
+#   $tname is the $tname set by the asnType procedure.
+#   $tag is the tag as returned by asnMod
+#   $implicit is the implicit indicator as returned by asnMod
+proc asnSub {name t tname tag implicit tagtype} {
+    global file inf
+   
+    set ignore 0
+    set defname defined,$inf(fprefix)$name
+    if {[info exist inf($defname)]} {
+        asnWarning "$name already defined in line $inf($defname)"
+        set ignore 1
+    }
+    set inf($defname) $inf(lineno)
+    switch -- $t {
+        Sequence   { set l [asnSequence $name $tag $implicit $tagtype] }
+        SequenceOf { set l [asnOf $name $tag $implicit $tagtype 0] }
+	SetOf      { set l [asnOf $name $tag $implicit $tagtype 1] }
+        Choice     { set l [asnChoice $name $tag $implicit $tagtype] }
+        Simple     { set l [asnSimple $name $tname $tag $implicit $tagtype] }
+        default    { asnError "switch asnType case not handled" }
+    }
+    if {$ignore} return
+
+    puts $file(outc) {}
+    puts $file(outc) "int $inf(fprefix)$name (ODR o, $inf(vprefix)$name **p, int opt, const char *name)"
+    puts $file(outc) \{
+    puts $file(outc) [lindex $l 0]
+    puts $file(outc) \}
+    set ok 1
+    set fdef "$inf(cprefix)int $inf(fprefix)$name (ODR o, $inf(vprefix)$name **p, int opt, const char *name);"
+    switch -- $t {
+        Simple {
+            set decl "typedef [lindex $l 1] $inf(vprefix)$name;"
+            if {![string compare [lindex $tname 2] 1]} {
+                if {![info exist inf(defined,[lindex $tname 0])]} {
+                    set ok 0
+                }
+            }
+	    set inf(var,$inf(nodef)) [join [lindex $l 2] \n]
+	    incr inf(nodef)
+        }
+        default {
+            set decl "typedef struct $inf(vprefix)$name $inf(vprefix)$name;"
+	    set inf(var,$inf(nodef)) "[lindex $l 1];"
+	    incr inf(nodef)
+        }
+    }
+    if {$ok} {
+        puts $file(outh) {}
+        puts $file(outh) $decl
+        puts $file(outh) $fdef
+	asnForwardTypes $name
+    } else {
+        lappend inf(forward,code,[lindex $tname 0]) {} $decl $fdef
+        lappend inf(forward,ref,[lindex $tname 0]) $name
+    }
+}
+
+proc asnForwardTypes {name} {
+    global inf file
+
+    if {![info exists inf(forward,code,$inf(fprefix)$name)]} {
+	return 0
+    }
+    foreach r $inf(forward,code,$inf(fprefix)$name) {
+	puts $file(outh) $r
+    }
+    unset inf(forward,code,$inf(fprefix)$name)
+
+    while {[info exists inf(forward,ref,$inf(fprefix)$name)]} {
+	set n $inf(forward,ref,$inf(fprefix)$name)
+	set m [lrange $n 1 end]
+	if {[llength $m]} {
+	    set inf(forward,ref,$inf(fprefix)$name) $m
+	} else {
+	    unset inf(forward,ref,$inf(fprefix)$name)
+	}
+	asnForwardTypes [lindex $n 0]
+    }
+}
+
+# asnSimple: parses simple type definition and generates C code
+# On entry,
+#   $name is the name we are defining
+#   $tname is the tname as returned by asnType
+#   $tag is the tag as returned by asnMod
+#   $implicit is the implicit indicator as returned by asnMod
+# Returns,
+#   {c-code, h-code}
+# Note: Doesn't take care of enum lists yet.
+proc asnSimple {name tname tag implicit tagtype} {
+    global inf
+
+    set j "[lindex $tname 1] "
+
+    if {[info exists inf(unionmap,$inf(module),$name)]} {
+	set uName $inf(unionmap,$inf(module),$name)
+    } else {
+	set uName $name
+    }
+
+    asnEnum $uName jj
+    if {![string length $tag]} {
+        set l "\treturn [lindex $tname 0] (o, p, opt, name);" 
+    } elseif {$implicit} {
+        set l \
+  "\treturn odr_implicit_tag (o, [lindex $tname 0], p, $tagtype, $tag, opt, name);" 
+    } else {
+        set l \
+  "\treturn odr_explicit_tag (o, [lindex $tname 0], p, $tagtype, $tag, opt, name);" \
+    }
+    if {[info exists jj]} {
+	return [list $l $j $jj]
+    } else {
+	return [list $l $j]
+    }
+}
+
+# asnSequence: parses "SEQUENCE { s-list }" and generates C code.
+# On entry,
+#   $name is the type we are defining
+#   $tag tag 
+#   $implicit
+# Returns,
+#   {c-code, h-code}
+proc asnSequence {name tag implicit tagtype} {
+    global val type inf
+
+    lappend j "struct $inf(vprefix)$name \{"
+    set level 0
+    set nchoice 0
+    if {![string length $tag]} {
+        lappend l "\tif (!odr_sequence_begin (o, p, sizeof(**p), name))"
+        lappend l "\t\treturn opt && odr_ok (o);"
+    } elseif {$implicit} {
+        lappend l "\tif (!odr_implicit_settag (o, $tagtype, $tag) ||"
+        lappend l "\t\t!odr_sequence_begin (o, p, sizeof(**p), name))"
+        lappend l "\t\treturn opt && odr_ok(o);"
+    } else {
+        lappend l "\tif (!odr_constructed_begin (o, p, $tagtype, $tag, name))"
+        lappend l "\t\treturn opt && odr_ok(o);"
+        lappend l "\tif (o->direction == ODR_DECODE)"
+        lappend l "\t\t*p = odr_malloc (o, sizeof(**p));"
+
+        lappend l "\tif (!odr_sequence_begin (o, p, sizeof(**p), 0))"
+        lappend l "\t\{"
+        lappend l "\t\t*p = 0;"
+        lappend l "\t\treturn 0;"
+        lappend l "\t\}"
+    }
+    lappend l "\treturn"
+    while {1} {
+        set p [lindex [asnName $name] 0]
+        asnMod ltag limplicit ltagtype
+        set t [asnType $p]
+
+	set uName { }
+	if {[info exists inf(unionmap,$inf(module),$name,$p)]} {
+	    set uName $inf(unionmap,$inf(module),$name,$p)
+	}
+
+        if {![string compare $t Simple]} {
+	    if {[string compare $uName { }]} {
+		set enumName $uName
+	    } else {
+		set enumName $name
+	    }
+            asnEnum $enumName j
+            set opt [asnOptional]
+            if {![string length $ltag]} {
+                lappend l "\t\t[lindex $tname 0](o, &(*p)->$p, $opt, \"$p\") &&"
+            } elseif {$limplicit} {
+                lappend l "\t\todr_implicit_tag (o, [lindex $tname 0],"
+                lappend l "\t\t\t&(*p)->$p, $ltagtype, $ltag, $opt, \"$p\") &&"
+            } else {
+                lappend l "\t\todr_explicit_tag (o, [lindex $tname 0],"
+                lappend l "\t\t\t&(*p)->$p, $ltagtype, $ltag, $opt, \"$p\") &&"
+            }
+            set dec "\t[lindex $tname 1] *$p;"
+        } elseif {![string compare $t SequenceOf] && [string length $uName] &&\
+		      (![string length $ltag] || $limplicit)} {
+            set u [asnType $p]
+           
+	    if {[llength $uName] < 2} {
+		set uName [list num_$p $p]
+	    }
+            if {[string length $ltag]} {
+                if {!$limplicit} {
+                    asnError explicittag
+                }
+                lappend l "\t\todr_implicit_settag (o, $ltagtype, $ltag) &&"
+            }
+            switch -- $u {
+                Simple {
+                    asnEnum $name j
+                    set tmpa "odr_sequence_of(o, (Odr_fun) [lindex $tname 0], &(*p)->$p,"
+                    set tmpb "&(*p)->[lindex $uName 0], \"$p\")"
+                    lappend j "\tint [lindex $uName 0];"
+                    set dec "\t[lindex $tname 1] **[lindex $uName 1];"
+                }
+                default {
+                    set subName [mapName ${name}_$level]
+                    asnSub $subName $u {} {} 0 {}
+                    
+                    set tmpa "odr_sequence_of(o, (Odr_fun) $inf(fprefix)$subName, &(*p)->$p,"
+                    set tmpb "&(*p)->[lindex $uName 0], \"$p\")"
+                    lappend j "\tint [lindex $uName 0];"
+                    set dec "\t$inf(vprefix)$subName **[lindex $uName 1];"
+                    incr level
+                }
+            }
+            set opt [asnOptional]
+            if {$opt} {
+                lappend l "\t\t($tmpa"
+                lappend l "\t\t  $tmpb || odr_ok(o)) &&"
+            } else {
+                lappend l "\t\t$tmpa"
+                lappend l "\t\t  $tmpb &&"
+            }
+        } elseif {!$nchoice && ![string compare $t Choice] && \
+		      [string length $uName]} {
+	    if {[llength $uName] < 3} {
+		set uName [list which u $name]
+		incr nchoice
+	    }
+            lappend j "\tint [lindex $uName 0];"
+            lappend j "\tunion \{"
+            lappend v "\tstatic Odr_arm arm\[\] = \{"
+            asnArm $name [lindex $uName 2] v j
+            lappend v "\t\};"
+            set dec "\t\} [lindex $uName 1];"
+            set opt [asnOptional]
+            set oa {}
+            set ob {}
+            if {[string length $ltag]} {
+                if {$limplicit} {
+                    lappend l "\t\todr_implicit_settag (o, $ltagtype, $ltag) &&"
+                    if {$opt} {
+                        asnWarning "optional handling missing in CHOICE in SEQUENCE"
+			asnWarning " set unionmap($inf(module),$name,$p) to {}"
+                    }
+                } else {
+                    if {$opt} {
+                        set la "(("
+                    } else {
+                        set la ""
+                    }
+                    lappend l "\t\t${la}odr_constructed_begin (o, &(*p)->[lindex $uName 1], $ltagtype, $ltag, \"$p\") &&"
+                }
+            } else {
+                if {$opt} {
+                    set oa "("
+                    set ob " || odr_ok(o))" 
+                }
+            }
+            lappend l "\t\t${oa}odr_choice (o, arm, &(*p)->[lindex $uName 1], &(*p)->[lindex $uName 0], 0)${ob} &&"
+            if {[string length $ltag]} {
+                if {!$limplicit} {
+                    if {$opt} {
+                        set lb ") || odr_ok(o))"
+                    } else {
+                        set lb ""
+                    }
+                    lappend l "\t\todr_constructed_end (o)${lb} &&"
+                } 
+            }
+        } else {
+	    set subName [mapName ${name}_$level]
+            asnSub $subName $t {} {} 0 {}
+            set opt [asnOptional]
+            if {![string length $ltag]} {
+                lappend l "\t\t$inf(fprefix)${subName} (o, &(*p)->$p, $opt, \"$p\") &&"
+            } elseif {$limplicit} {
+                lappend l "\t\todr_implicit_tag (o, $inf(fprefix)${subName},"
+                lappend l "\t\t\t&(*p)->$p, $ltagtype, $ltag, $opt, \"$p\") &&"
+            } else {
+                lappend l "\t\todr_explicit_tag (o, $inf(fprefix)${subName},"
+                lappend l "\t\t\t&(*p)->$p, $ltagtype, $ltag, $opt, \"$p\") &&"
+            }
+            set dec "\t$inf(vprefix)${subName} *$p;"
+            incr level
+        }
+        if {$opt} {
+            lappend j "$dec /* OPT */"
+        } else {
+            lappend j $dec
+        }
+        if {[string compare $type ,]} break
+    }
+    lappend j "\}"
+    if {[string length $tag] && !$implicit} {
+        lappend l "\t\todr_sequence_end (o) &&"
+        lappend l "\t\todr_constructed_end (o);"
+    } else {
+        lappend l "\t\todr_sequence_end (o);"
+    }
+    if {[string compare $type \}]} {
+        asnError "Missing \} got $type '$val'"
+    }
+    lex
+    if {[info exists v]} {
+        set l [concat $v $l]
+    }
+    return [list [join $l \n] [join $j \n]]
+}
+
+# asnOf: parses "SEQUENCE/SET OF type" and generates C code.
+# On entry,
+#   $name is the type we are defining
+#   $tag tag 
+#   $implicit
+# Returns,
+#   {c-code, h-code}
+proc asnOf {name tag implicit tagtype isset} { 
+    global inf
+
+    if {$isset} {
+	set func odr_set_of
+    } else {
+	set func odr_sequence_of
+    }
+
+    if {[info exists inf(unionmap,$inf(module),$name)]} {
+	set numName $inf(unionmap,$inf(module),$name)
+    } else {
+	set numName {num elements}
+    }
+
+    lappend j "struct $inf(vprefix)$name \{"
+    lappend j "\tint [lindex $numName 0];"
+
+    lappend l "\tif (!odr_initmember (o, p, sizeof(**p)))"
+    lappend l "\t\treturn opt && odr_ok(o);"
+    if {[string length $tag]} {
+        if {$implicit} {
+            lappend l "\todr_implicit_settag (o, $tagtype, $tag);"
+        } else {
+            asnWarning "Constructed SEQUENCE/SET OF not handled"
+        }
+    }
+    set t [asnType $name]
+    switch -- $t {
+        Simple {
+            asnEnum $name j
+            lappend l "\tif ($func (o, (Odr_fun) [lindex $tname 0], &(*p)->[lindex $numName 1],"
+            lappend l "\t\t&(*p)->[lindex $numName 0], name))"
+            lappend j "\t[lindex $tname 1] **[lindex $numName 1];"
+        }
+        default {
+            set subName [mapName ${name}_s]
+            lappend l "\tif ($func (o, (Odr_fun) $inf(fprefix)$subName, &(*p)->[lindex $numName 1],"
+            lappend l "\t\t&(*p)->[lindex $numName 0], name))"
+            lappend j "\t$inf(vprefix)$subName **[lindex $numName 1];"
+            asnSub $subName $t {} {} 0 {}
+        }
+    }
+    lappend j "\}"
+    lappend l "\t\treturn 1;"
+    lappend l "\t*p = 0;"
+    lappend l "\treturn opt && odr_ok(o);"
+    return [list [join $l \n] [join $j \n]]
+}
+
+# asnArm: parses c-list in choice
+proc asnArm {name defname lx jx} {
+    global type val inf
+
+    upvar $lx l
+    upvar $jx j
+    while {1} {
+        set pq [asnName $name]
+        set p [lindex $pq 0]
+        set q [lindex $pq 1]
+        if {![string length $q]} {
+            set q $p
+	    set p ${defname}_$p
+        }
+        asnMod ltag limplicit ltagtype
+        set t [asnType $q]
+
+        lappend enums "$inf(dprefix)$p"
+        if {![string compare $t Simple]} {
+            asnEnum $name j
+            if {![string length $ltag]} {
+                lappend l "\t\t\{-1, -1, -1, $inf(dprefix)$p,"
+		lappend l "\t\t (Odr_fun) [lindex $tname 0], \"$q\"\},"
+            } elseif {$limplicit} {
+                lappend l "\t\t\{ODR_IMPLICIT, $ltagtype, $ltag, $inf(dprefix)$p,"
+                lappend l "\t\t(Odr_fun) [lindex $tname 0], \"$q\"\},"
+            } else {
+                lappend l "\t\t\{ODR_EXPLICIT, $ltagtype, $ltag, $inf(dprefix)$p,"
+                lappend l "\t\t(Odr_fun) [lindex $tname 0], \"$q\"\},"
+            }
+            lappend j "\t\t[lindex $tname 1] *$q;"
+        } else {
+            set subName [mapName ${name}_$q]
+            if {![string compare $inf(dprefix)${name}_$q \
+                                 $inf(vprefix)$subName]} {
+                set po [string toupper [string index $q 0]][string \
+                                                            range $q 1 end]
+                set subName [mapName ${name}${po}]
+            }
+            asnSub $subName $t $tname {} 0 {}
+            if {![string length $ltag]} {
+                lappend l "\t\t\{-1, -1, -1, $inf(dprefix)$p,"
+		lappend l "\t\t (Odr_fun) $inf(fprefix)$subName, \"$q\"\},"
+            } elseif {$limplicit} {
+                lappend l "\t\t\{ODR_IMPLICIT, $ltagtype, $ltag, $inf(dprefix)$p,"
+                lappend l "\t\t(Odr_fun) $inf(fprefix)$subName, \"$q\"\},"
+            } else {
+                lappend l "\t\t\{ODR_EXPLICIT, $ltagtype, $ltag, $inf(dprefix)$p,"
+                lappend l "\t\t(Odr_fun) $inf(fprefix)$subName, \"$q\"\},"
+            }
+            lappend j "\t\t$inf(vprefix)$subName *$q;"
+        }
+        if {[string compare $type ,]} break
+    }
+    if {[string compare $type \}]} {
+        asnError "Missing \} got $type '$val'"
+    }
+    lex
+    set level 1
+    foreach e $enums {
+        lappend j "#define $e $level"
+        incr level
+    }
+    lappend l "\t\t\{-1, -1, -1, -1, (Odr_fun) 0, 0\}"
+}
+
+# asnChoice: parses "CHOICE {c-list}" and generates C code.
+# On entry,
+#   $name is the type we are defining
+#   $tag tag 
+#   $implicit
+# Returns,
+#   {c-code, h-code}
+proc asnChoice {name tag implicit tagtype} {
+    global type val inf
+
+    if {[info exists inf(unionmap,$inf(module),$name)]} {
+	set uName $inf(unionmap,$inf(module),$name)
+    } else {
+	set uName [list which u $name]
+    }
+
+    lappend j "struct $inf(vprefix)$name \{"
+    lappend j "\tint [lindex $uName 0];"
+    lappend j "\tunion \{"
+    lappend l "\tstatic Odr_arm arm\[\] = \{"
+    asnArm $name [lindex $uName 2] l j
+    lappend j "\t\} [lindex $uName 1];"
+    lappend j "\}"
+    lappend l "\t\};"
+    if {![string length $tag]} {
+	lappend l "\tif (!odr_initmember(o, p, sizeof(**p)))"
+	lappend l "\t\treturn opt && odr_ok(o);"
+	lappend l "\tif (odr_choice(o, arm, &(*p)->[lindex $uName 1], &(*p)->[lindex $uName 0], name))"
+    } elseif {$implicit} {
+	lappend l "\tif (!odr_initmember(o, p, sizeof(**p)))"
+	lappend l "\t\treturn opt && odr_ok(o);"
+	lappend l "\todr_implicit_settag(o, $tagtype, $tag);"
+	lappend l "\tif (odr_choice(o, arm, &(*p)->[lindex $uName 1], &(*p)->[lindex $uName 0], name))"
+    } else {
+	lappend l "\tif (!*p && o->direction != ODR_DECODE)"
+	lappend l "\t\treturn opt;"
+	lappend l "\tif (!odr_constructed_begin(o, p, $tagtype, $tag, 0))"
+	lappend l "\t\treturn opt && odr_ok(o);"
+	lappend l "\tif (!odr_initmember(o, p, sizeof(**p)))"
+	lappend l "\t\treturn opt && odr_ok(o);"
+	lappend l "\tif (odr_choice(o, arm, &(*p)->[lindex $uName 1], &(*p)->[lindex $uName 0], name) &&"
+	lappend l "\t\todr_constructed_end(o))"
+    }
+    lappend l "\t\treturn 1;"
+    lappend l "\t*p = 0;"
+    lappend l "\treturn opt && odr_ok(o);"
+    return [list [join $l \n] [join $j \n]]
+}
+
+# asnImports: parses i-list in "IMPORTS {i-list}" 
+# On return inf(import,..)-array is updated.
+# inf(import,"module") is a list of {C-handler, C-type} elements.
+# The {C-handler, C-type} is compatible with the $tname as is used by the
+# asnType procedure to solve external references.
+proc asnImports {} {
+    global type val inf file
+
+    while {1} {
+        if {[string compare $type n]} {
+            asnError "Missing name in IMPORTS list"
+        }
+        lappend nam $val
+        lex
+        if {![string compare $type n] && ![string compare $val FROM]} {
+            lex
+	    
+	    if {[info exists inf(filename,$val)]} {
+		set fname $inf(filename,$val)
+	    } else {
+		set fname $val
+	    }
+	    puts $file(outh) "\#include <$inf(h-dir)${fname}.h>"
+
+            if {[info exists inf(prefix,$val)]} {
+                set prefix $inf(prefix,$val)
+            } else {
+                set prefix $inf(prefix)
+            }
+            foreach n $nam {
+		if {[info exists inf(map,$val,$n)]} {
+		    set v $inf(map,$val,$n)
+		} else {
+		    set v $n
+		}
+                set w [join [split $v -] _]
+                set inf(imports,$n) [list [lindex $prefix 0]$w \
+                                          [lindex $prefix 1]$w]
+            }
+            unset nam
+            lex
+            if {[string compare $type n]} break
+        } elseif {![string compare $type ,]} {
+            lex
+        } else break
+    }
+    if {[string compare $type \;]} {
+        asnError "Missing ; after IMPORTS list - got $type '$val'"
+    }
+    lex
+}
+
+# asnExports: parses e-list in "EXPORTS {e-list}" 
+# This function does nothing with elements in the list.
+proc asnExports {} {
+    global type val inf
+
+    while {1} {
+        if {[string compare $type n]} {
+            asnError "Missing name in EXPORTS list"
+        }
+        set inf(exports,$val) 1
+        lex
+        if {[string compare $type ,]} break
+        lex
+    }
+    if {[string compare $type \;]} {
+        asnError "Missing ; after EXPORTS list - got $type ($val)"
+    }
+    lex
+}
+
+# asnModuleBody: parses a module specification and generates C code.
+# Exports lists, imports lists, and type definitions are handled;
+# other things are silently ignored.
+proc asnModuleBody {} {
+    global type val file inf
+
+    if {[info exists inf(prefix,$inf(module))]} {
+        set prefix $inf(prefix,$inf(module))
+    } else {
+        set prefix $inf(prefix)
+    }
+    set inf(fprefix) [lindex $prefix 0]
+    set inf(vprefix) [lindex $prefix 1]
+    set inf(dprefix) [lindex $prefix 2]
+    if {[llength $prefix] > 3} {
+	set inf(cprefix) [lindex $prefix 3]
+    } else {
+	set inf(cprefix) {YAZ_EXPORT }
+    }
+
+    if {$inf(verbose)} {
+        puts "Module $inf(module), $inf(lineno)"
+    }
+
+    set defblock 0
+    if {[info exists inf(init,$inf(module),c)]} {
+	puts $file(outc) $inf(init,$inf(module),c)
+    }
+    if {[info exists inf(init,$inf(module),h)]} {
+	puts $file(outh) "\#ifdef __cplusplus"
+	puts $file(outh) "extern \"C\" \{"
+	puts $file(outh) "\#endif"
+	set defblock 1
+	puts $file(outh) $inf(init,$inf(module),h)
+    }
+    if {[info exists inf(init,$inf(module),p)]} {
+	puts $file(outp) $inf(init,$inf(module),p)
+    }
+
+    while {[string length $type]} {
+	if {[string compare $type n]} {
+	    lex
+	    continue
+	}
+	if {![string compare $val END]} {
+	    break
+	} elseif {![string compare $val EXPORTS]} {
+	    lex
+	    asnExports
+	} elseif {![string compare $val IMPORTS]} {
+	    if {$defblock} {
+		puts $file(outh) "\#ifdef __cplusplus"
+		puts $file(outh) "\}"
+		puts $file(outh) "\#endif"
+		set defblock 0
+	    }
+	    lex
+	    asnImports
+	} else {
+	    if {!$defblock} {
+		puts $file(outh) "\#ifdef __cplusplus"
+		puts $file(outh) "extern \"C\" \{"
+		puts $file(outh) "\#endif"
+		set defblock 1
+	    }
+	    set inf(asndef) $inf(nodef)
+	    set oval $val
+	    lex
+	    if {![string compare $type :]} {
+		lex
+		asnDef $oval
+		set inf(asndef) 0
+	    } elseif {![string compare $type n]} {
+		lex
+		if {[string length $type]} {
+		    lex
+		}
+	    }
+	}
+    }
+    if {$defblock} {
+	puts $file(outh) "\#ifdef __cplusplus"
+	puts $file(outh) "\}"
+	puts $file(outh) "\#endif"
+	set defblock 0
+    }
+    foreach x [array names inf imports,*] {
+        unset inf($x)
+    }
+}
+
+# asnTagDefault: parses TagDefault section
+proc asnTagDefault {} {
+    global type val inf file
+    
+    set inf(implicit-tags) 0
+    while {[string length $type]} {
+	if {[lex-name-move EXPLICIT]} {
+	    lex
+	    set inf(implicit-tags) 0
+	} elseif {[lex-name-move  IMPLICIT]} {
+	    lex
+	    set inf(implicit-tags) 1
+	} else {
+	    break
+	}
+    }
+}
+
+# asnModules: parses a collection of module specifications.
+# Depending on the module pattern, $inf(moduleP), a module is either
+# skipped or processed.
+proc asnModules {} {
+    global type val inf file yc_version
+
+    set inf(nodef) 0
+    set inf(asndef) 0
+    lex
+    while {![string compare $type n]} {
+	set inf(module) $val
+        if {[info exists inf(moduleP)] && ![string match $inf(moduleP) $val]} {
+            if {$inf(verbose)} {
+                puts "Skipping $id"
+            }
+            while {![lex-name-move END]} {
+		lex
+	    }
+        } else {
+	    set inf(nodef) 1
+	    set inf(asndef) 1
+
+	    while {![lex-name-move DEFINITIONS]} {
+		lex
+		if {![string length $type]} return
+	    }
+	    if {[info exists inf(filename,$inf(module))]} {
+		set fname $inf(filename,$inf(module))
+	    } else {
+		set fname $inf(module)
+	    }
+            set ppname [join [split $fname -] _]
+
+	    if {![info exists inf(c-file)]} {
+		set inf(c-file) ${fname}.c
+	    }
+	    set file(outc) [open $inf(c-file) w]
+
+	    if {![info exists inf(h-file)]} {
+		set inf(h-file) ${fname}.h
+	    }
+	    set file(outh) [open $inf(h-path)/$inf(h-dir)$inf(h-file) w]
+
+	    if {0} {
+	        if {![info exists inf(p-file)]} {
+		    set inf(p-file) ${fname}-p.h
+	        }
+	        set file(outp) [open $inf(h-path)/$inf(h-dir)$inf(p-file) w]
+            }
+
+	    set greeting {Generated automatically by the YAZ ASN.1 Compiler}
+
+	    puts $file(outc) "/* ${greeting} ${yc_version} */"
+	    puts $file(outc) "/* Module-C: $inf(module) */"
+	    puts $file(outc) {}
+
+	    puts $file(outh) "/* ${greeting} ${yc_version} */"
+	    puts $file(outh) "/* Module-H $inf(module) */"
+	    puts $file(outh) {}
+
+	    if {[info exists file(outp)]} {
+	        puts $file(outp) "/* ${greeting} ${yc_version} */"
+	        puts $file(outp) "/* Module-P: $inf(module) */"
+	        puts $file(outp) {}
+            }
+
+            if {[info exists inf(p-file)]} {
+	        puts $file(outc) "\#include <$inf(h-dir)$inf(p-file)>"
+            } else {
+	        puts $file(outc) "\#include <$inf(h-dir)$inf(h-file)>"
+            }
+	    puts $file(outh) "\#ifndef ${ppname}_H"
+	    puts $file(outh) "\#define ${ppname}_H"
+	    puts $file(outh) {}
+	    puts $file(outh) "\#include <$inf(h-dir)odr.h>"
+	   
+            if {[info exists file(outp)]} { 
+	        puts $file(outp) "\#ifndef ${ppname}_P_H"
+	        puts $file(outp) "\#define ${ppname}_P_H"
+	        puts $file(outp) {}
+	        puts $file(outp) "\#include <$inf(h-dir)$inf(h-file)>"
+
+            }
+	    
+	    asnTagDefault
+	    if {[string compare $type :]} {
+		asnError "::= expected got $type '$val'"
+	    } 
+	    lex
+	    if {![lex-name-move BEGIN]} {
+		asnError "BEGIN expected"
+	    }
+	    asnModuleBody
+	    lex
+
+	    if {[info exists file(outp)]} {
+		set f $file(outp)
+	    } else {
+		set f $file(outh)
+	    }
+	    puts $f "\#ifdef __cplusplus"
+	    puts $f "extern \"C\" \{"
+	    puts $f "\#endif"
+	    for {set i 1} {$i < $inf(nodef)} {incr i} {
+		puts $f $inf(var,$i)
+		if {[info exists inf(asn,$i)]} {
+		    if {0} {
+			puts $f "/*"
+			foreach comment $inf(asn,$i) {
+			    puts $f $comment
+			}
+			puts $f " */"
+		    }
+		    unset inf(asn,$i)
+		}
+		unset inf(var,$i)
+		puts $f {}
+	    }
+	    puts $f "\#ifdef __cplusplus"
+	    puts $f "\}"
+	    puts $f "\#endif"
+
+	    if {[info exists inf(body,$inf(module),h)]} {
+		puts $file(outh) $inf(body,$inf(module),h)
+	    }
+	    if {[info exists inf(body,$inf(module),c)]} {
+		puts $file(outc) $inf(body,$inf(module),c)
+	    }
+	    if {[info exists inf(body,$inf(module),p)]} {
+                if {[info exists file(outp)]} {
+		    puts $file(outp) $inf(body,$inf(module),p)
+                }
+	    }
+	    puts $file(outh) "\#endif"
+            if {[info exists file(outp)]} {
+	        puts $file(outp) "\#endif"
+            }
+	    foreach f [array names file] {
+		close $file($f)
+	    }
+	    unset inf(c-file)
+	    unset inf(h-file)
+	    catch {unset inf(p-file)}
+	}
+    }
+}
+
+# asnFile: parses an ASN.1 specification file as specified in $inf(iname).
+proc asnFile {} {
+    global inf file
+
+    if {$inf(verbose) > 1} {
+        puts "Reading ASN.1 file $inf(iname)"
+    }
+    set inf(str) {}
+    set inf(lineno) 0
+    set inf(inf) [open $inf(iname) r]
+    
+    asnModules
+    
+}
+
+# The following procedures are invoked by the asnType function. 
+# Each procedure takes the form: asnBasic<TYPE> and they must return
+# two elements: the C function handler and the C type.
+# On entry upvar $name is the type we are defining and global, $inf(module), is
+# the current module name.
+
+proc asnBasicEXTERNAL {} {
+    return {odr_external {Odr_external}}
+}
+
+proc asnBasicINTEGER {} {
+    return {odr_integer {int}}
+}
+
+proc asnBasicENUMERATED {} {
+    return {odr_enum {int}}
+}
+
+proc asnBasicNULL {} {
+    return {odr_null {Odr_null}}
+}
+
+proc asnBasicBOOLEAN {} {
+    return {odr_bool {bool_t}}
+}
+
+proc asnBasicOCTET {} {
+    global type val
+    lex-name-move STRING
+    return {odr_octetstring {Odr_oct}}
+}
+
+proc asnBasicBIT {} {
+    global type val
+    lex-name-move STRING
+    return {odr_bitstring {Odr_bitmask}}
+}
+
+proc asnBasicOBJECT {} {
+    global type val
+    lex-name-move IDENTIFIER
+    return {odr_oid {Odr_oid}}
+}
+
+proc asnBasicGeneralString {} {
+    return {odr_generalstring char}
+}
+
+proc asnBasicVisibleString {} {
+    return {odr_visiblestring char}
+}
+
+proc asnBasicGeneralizedTime {} {
+    return {odr_generalizedtime char}
+}
+
+proc asnBasicANY {} {
+    upvar name name
+    global inf
+    return [list $inf(fprefix)ANY_$name void]
+}
+
+# userDef: reads user definitions file $name
+proc userDef {name} {
+    global inf
+
+    if {$inf(verbose) > 1} {
+        puts "Reading definitions file $name"
+    }
+    source $name
+
+    if {[info exists default-prefix]} {
+        set inf(prefix) ${default-prefix}
+    }
+    if {[info exists h-path]} {
+        set inf(h-path) ${h-path}
+    }
+    foreach m [array names prefix] {
+        set inf(prefix,$m) $prefix($m)
+    }
+    foreach m [array names body] {
+	set inf(body,$m) $body($m)
+    }
+    foreach m [array names init] {
+	set inf(init,$m) $init($m)
+    }
+    foreach m [array names filename] {
+	set inf(filename,$m) $filename($m)
+    }
+    foreach m [array names map] {
+        set inf(map,$m) $map($m)
+    }
+    foreach m [array names membermap] {
+        set inf(membermap,$m) $membermap($m)
+    }
+    foreach m [array names unionmap] {
+        set inf(unionmap,$m) $unionmap($m)
+    }
+}
+
+set inf(verbose) 0
+set inf(prefix) {yc_ Yc_ YC_}
+set inf(h-path) .
+set inf(h-dir) ""
+
+# Parse command line
+set l [llength $argv]
+set i 0
+while {$i < $l} {
+    set arg [lindex $argv $i]
+    switch -glob -- $arg {
+        -v {
+	    incr inf(verbose) 
+        }
+        -c {
+	    set p [string range $arg 2 end]
+	    if {![string length $p]} {
+                 set p [lindex $argv [incr i]]
+             }
+	    set inf(c-file) $p
+        }
+        -I* {
+	    set p [string range $arg 2 end]
+	    if {![string length $p]} {
+                 set p [lindex $argv [incr i]]
+             }
+	    set inf(h-path) $p
+        }
+	-i* {
+	    set p [string range $arg 2 end]
+	    if {![string length $p]} {
+                 set p [lindex $argv [incr i]]
+            }
+	    set inf(h-dir) [string trim $p \\/]/
+	}
+        -h* {
+	    set p [string range $arg 2 end]
+	    if {![string length $p]} {
+                 set p [lindex $argv [incr i]]
+             }
+	    set inf(h-file) $p
+        }
+        -p* {
+	    set p [string range $arg 2 end]
+	    if {![string length $p]} {
+		set p [lindex $argv [incr i]]
+	    }
+	    set inf(p-file) $p
+        }
+        -d* {
+	    set p [string range $arg 2 end]
+	    if {![string length $p]} {
+		set p [lindex $argv [incr i]]
+	    }
+	    userDef $p
+        }
+        -m* {
+	    set p [string range $arg 2 end]
+	    if {![string length $p]} {
+		set p [lindex $argv [incr i]]
+	    }
+	    set inf(moduleP) $p
+        }
+	-x* {
+	    set p [string range $arg 2 end]
+	    if {![string length $p]} {
+		set p [lindex $argv [incr i]]
+	    }
+	    if {[llength $p] == 1} {
+		set inf(prefix) [list [string tolower $p] \
+				     [string toupper $p] [string toupper $p]]
+	    } elseif {[llength $p] == 3} {
+		set inf(prefix) $p
+	    } else {
+		puts [llength $p]
+		exit 1
+	    }
+	}	    
+        default {
+	    set inf(iname) $arg
+        }
+    }
+    incr i
+}
+
+if {![info exists inf(iname)]} {
+    puts "YAZ ASN.1 Compiler ${yc_version}"
+    puts -nonewline "Usage: ${argv0}"
+    puts { [-v] [-c cfile] [-h hfile] [-p hfile] [-d dfile] [-I path]}
+    puts {    [-x prefix] [-m module] file}
+    exit 1
+}
+
+asnFile
Index: /main/tags/2.25/gsdl/packages/yaz/win/makefile
===================================================================
--- /main/tags/2.25/gsdl/packages/yaz/win/makefile	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/yaz/win/makefile	(revision 21064)
@@ -0,0 +1,720 @@
+# Makefile.mak - makefile for MS NMAKE 
+# $Id$
+#
+# Programmed by
+#  HL: Heikki Levanto, Index Data
+#
+# Log at the end of the file
+#
+# Missing
+# - Move MS-C's whatnots into win direcotry
+# - The TCL script produces C and H files in the same dir as the 
+#   ASN files. H's are copied to INCL, C's are left there.
+#   They should be produced into OBJ...
+#  
+# Envoronment problems
+# - You need to have the proper path and environment for VC set
+#   up. There is a bat file VCVARS32.BAT that sets most of it up
+#   for you. You can find this somewhere near DevStudio\VC\BIN
+# - RegSvr32 must also be along the path, often in WINDOWS\SYSTEM
+# - TCL has to be available too, if compiling for NEW_Z3950
+
+###########################################################
+############### Parameters 
+###########################################################
+
+DEBUG=0   # 0 for release, 1 for debug
+
+NEW_Z3950=1  # 0= use old asn files
+             # 1= generate files from *.asn (needs tcl)
+
+
+default: all
+
+all: dirs proto_h dll client server ztest 
+
+generate: generated_files
+
+###########################################################
+############### Directories
+###########################################################
+# The current directory is supposed to be something like
+# ..../Yaz/Win, everything is relative to that
+ROOTDIR=..   # The home of Yaz
+
+INCLDIR=$(ROOTDIR)\include  # our includes
+LIBDIR=$(ROOTDIR)\lib       # We produce .lib, .exp etc there
+BINDIR=$(ROOTDIR)\bin       # We produce exes and dlls there
+WINDIR=$(ROOTDIR)\win       # all these Win make things
+OBJDIR=$(WINDIR)\obj        # where we store intermediate files
+UNIXDIR=$(ROOTDIR)\unix     # corresponding unix things
+SRCDIR=$(ROOTDIR)           # for the case we move them under src
+
+ASNDIR=$(SRCDIR)\ASN
+COMSTACKDIR=$(SRCDIR)\COMSTACK
+ODRDIR=$(SRCDIR)\ODR
+UTILDIR=$(SRCDIR)\UTIL
+ZUTILDIR=$(SRCDIR)\ZUTIL
+RETDIR=$(SRCDIR)\RETRIEVAL
+Z3950DIR=$(SRCDIR)\Z39.50
+ILLDIR=$(SRCDIR)\ill
+
+CLIENTDIR=$(SRCDIR)\CLIENT
+SERVERDIR=$(SRCDIR)\SERVER
+ZTESTDIR=$(SRCDIR)\ZTEST
+
+TMPDIR=$(ROOTDIR)\win\tmp
+TMP=$(TMPDIR)
+
+###########################################################
+############### Targets - what to make
+###########################################################
+
+
+DLL=$(BINDIR)\Yaz.dll
+IMPLIB=$(LIBDIR)\Yaz.lib
+
+CLIENT=$(BINDIR)\yaz-client.exe
+SERVER=$(LIBDIR)\server.lib
+ZTEST=$(BINDIR)\yaz-ztest.exe
+PROTOH=$(INCLDIR)\yaz\proto.h
+
+# shortcut names defined here
+dll : $(DLL) 
+client: $(CLIENT)
+server: $(SERVER)
+ztest: $(ZTEST)
+proto_h: $(PROTOH)
+
+###########################################################
+############### Compiler and linker options 
+###########################################################
+
+
+### C and CPP compiler  (the same thing)
+# Note: $(CPP) has already been defined in the environment
+# (if you set things up right!)
+
+COMMON_C_OPTIONS=          \
+  /nologo /W3 /GX /FD /c   \
+  /D "WIN32" /D "_WINDOWS" \
+  /FR"$(OBJDIR)\\"         \
+  /Fo"$(OBJDIR)\\"         \
+  /Fd"$(OBJDIR)\\" 
+
+COMMON_C_INCLUDES= \
+  /I"$(SRCDIR)\include"
+
+DEBUG_C_OPTIONS=  \
+  /D "_DEBUG"      \
+  /MDd  /Od /YX /Zi /Gm
+
+RELEASE_C_OPTIONS=  \
+  /D "NDEBUG"        \
+  /MD /O2
+
+# /W3  = warning level
+# /GX  = Enable exception handling
+# /FD  = Generate file dependencies (what ever they are)
+# /c   = compile without linking
+# /FR  = Generate browse info (.sbr file that gets combined into .bsc)
+# /Fo  = object file name (or at least path)
+# /Fd  = debug database name (or path)
+# /MD  = Runtime library: Multithread DLL
+# /MDd = Runtime library: Multithread DLL (debug)
+# /Od  = Disable optimising (debug)
+# /O2  = Optimize for speed
+# /YX  = Automatic use of precomipled headers
+# /Gm  = Minimal rebuild (some cpp class stuff)
+# /Zi  = Program database for debuggers
+# /ZI  = Pgm database with special "edit&continue" stuff - not available in C5
+
+
+### Linker options
+LINK=link.exe
+
+LINK_LIBS= kernel32.lib user32.lib   gdi32.lib   winspool.lib \
+           comdlg32.lib advapi32.lib shell32.lib ole32.lib    \
+           oleaut32.lib uuid.lib     odbc32.lib  odbccp32.lib \
+           wsock32.lib  advapi32.lib
+
+COMMON_LNK_OPTIONS= /nologo \
+                    /subsystem:windows \
+                    /machine:i386 \
+			  /incremental:no
+
+DEBUG_LNK_OPTIONS= /debug 
+
+RELEASE_LNK_OPTIONS=  /pdb:none
+
+DLL_LINK_OPTIONS= /dll  
+CLIENT_LINK_OPTIONS = /subsystem:console  
+SERVER_LINK_OPTIONS = -lib 
+ZTEST_LINK_OPTIONS = /subsystem:console  
+
+# TCL
+TCL="C:\Program Files\Tcl\bin\tclsh82.exe"
+
+COMMON_TCL_OPTIONS= ..\util\yaz-comp -I$(INCLDIR) -i yaz
+
+# Final opt variables
+!if $(DEBUG)
+COPT=   $(COMMON_C_OPTIONS)   $(DEBUG_C_OPTIONS)     $(COMMON_C_INCLUDES)
+MTLOPT= $(COMMON_MTL_OPTIONS) $(DEBUG_MTL_OPTIONS)
+RCOPT=  $(COMMON_RC_OPTIONS)  $(DEBUG_RC_OPTIONS)
+LNKOPT= $(COMMON_LNK_OPTIONS) $(DEBUG_LNK_OPTIONS)   $(LNK_LIBS)
+TCLOPT= $(COMMON_TCL_OPTIONS)
+
+!else
+COPT=   $(COMMON_C_OPTIONS)   $(RELEASE_C_OPTIONS)   $(COMMON_C_INCLUDES) 
+MTLOPT= $(COMMON_MTL_OPTIONS) $(RELEASE_MTL_OPTIONS)
+RCOPT=  $(COMMON_RC_OPTIONS)  $(RELEASE_RC_OPTIONS)
+LNKOPT= $(COMMON_LNK_OPTIONS) $(RELEASE_LNK_OPTIONS) $(LNK_LIBS)
+TCLOPT= $(COMMON_TCL_OPTIONS)
+!endif
+
+
+
+###########################################################
+###############  Source and object modules
+###########################################################
+
+# Note: Ordinary source files are not specified here at 
+# all, make finds them in suitable dirs. The object modules
+# need to be specified, though
+
+YAZ_CLIENT_OBJS= \
+   $(OBJDIR)\client.obj
+
+YAZ_SERVER_OBJS= \
+	"$(OBJDIR)\eventl.obj" \
+	"$(OBJDIR)\requestq.obj" \
+	"$(OBJDIR)\service.obj" \
+	"$(OBJDIR)\seshigh.obj" \
+	"$(OBJDIR)\statserv.obj" \
+	"$(OBJDIR)\tcpdchk.obj" 
+
+ZTEST_OBJS= \
+	"$(OBJDIR)\read-grs.obj" \
+	"$(OBJDIR)\ztest.obj" 
+	
+
+YAZ_ASN_OBJS= \
+   $(OBJDIR)\proto.obj \
+   $(OBJDIR)\prt-acc.obj \
+   $(OBJDIR)\prt-add.obj \
+   $(OBJDIR)\prt-arc.obj \
+   $(OBJDIR)\prt-dat.obj \
+   $(OBJDIR)\prt-dia.obj \
+   $(OBJDIR)\prt-esp.obj \
+   $(OBJDIR)\prt-exd.obj \
+   $(OBJDIR)\prt-exp.obj \
+   $(OBJDIR)\prt-grs.obj \
+   $(OBJDIR)\prt-rsc.obj \
+   $(OBJDIR)\prt-univ.obj 
+
+YAZ_COMSTACK_OBJS= \
+   $(OBJDIR)\comstack.obj \
+   $(OBJDIR)\tcpip.obj \
+   $(OBJDIR)\waislen.obj 
+
+YAZ_ODR_OBJS= \
+   $(OBJDIR)\ber_any.obj \
+   $(OBJDIR)\ber_bit.obj \
+   $(OBJDIR)\ber_bool.obj \
+   $(OBJDIR)\ber_int.obj \
+   $(OBJDIR)\ber_len.obj \
+   $(OBJDIR)\ber_null.obj \
+   $(OBJDIR)\ber_oct.obj \
+   $(OBJDIR)\ber_oid.obj \
+   $(OBJDIR)\ber_tag.obj \
+   $(OBJDIR)\dumpber.obj \
+   $(OBJDIR)\odr.obj \
+   $(OBJDIR)\odr_any.obj \
+   $(OBJDIR)\odr_bit.obj \
+   $(OBJDIR)\odr_bool.obj \
+   $(OBJDIR)\odr_choice.obj \
+   $(OBJDIR)\odr_cons.obj \
+   $(OBJDIR)\odr_enum.obj \
+   $(OBJDIR)\odr_int.obj \
+   $(OBJDIR)\odr_mem.obj \
+   $(OBJDIR)\odr_null.obj \
+   $(OBJDIR)\odr_oct.obj \
+   $(OBJDIR)\odr_oid.obj \
+   $(OBJDIR)\odr_seq.obj \
+   $(OBJDIR)\odr_tag.obj \
+   $(OBJDIR)\odr_use.obj \
+   $(OBJDIR)\odr_util.obj 
+
+YAZ_UTIL_OBJS= \
+   $(OBJDIR)\atoin.obj \
+   $(OBJDIR)\log.obj \
+   $(OBJDIR)\marcdisp.obj \
+   $(OBJDIR)\nmem.obj \
+   $(OBJDIR)\nmemsdup.obj \
+   $(OBJDIR)\oid.obj \
+   $(OBJDIR)\options.obj \
+   $(OBJDIR)\readconf.obj \
+   $(OBJDIR)\tpath.obj \
+   $(OBJDIR)\wrbuf.obj \
+   $(OBJDIR)\xmalloc.obj \
+   $(OBJDIR)\matchstr.obj 
+
+YAZ_ZUTIL_OBJS= \
+   $(OBJDIR)\diagbib1.obj \
+   $(OBJDIR)\zget.obj \
+   $(OBJDIR)\prt-ext.obj \
+   $(OBJDIR)\logrpn.obj \
+   $(OBJDIR)\pquery.obj \
+   $(OBJDIR)\yaz-ccl.obj \
+   $(OBJDIR)\otherinfo.obj
+
+YAZ_RET_OBJS= \
+   $(OBJDIR)\d1_absyn.obj\
+   $(OBJDIR)\d1_attset.obj\
+   $(OBJDIR)\d1_doespec.obj\
+   $(OBJDIR)\d1_espec.obj\
+   $(OBJDIR)\d1_expout.obj\
+   $(OBJDIR)\d1_grs.obj\
+   $(OBJDIR)\d1_handle.obj\
+   $(OBJDIR)\d1_map.obj\
+   $(OBJDIR)\d1_marc.obj\
+   $(OBJDIR)\d1_prtree.obj\
+   $(OBJDIR)\d1_read.obj\
+   $(OBJDIR)\d1_soif.obj\
+   $(OBJDIR)\d1_sumout.obj\
+   $(OBJDIR)\d1_sutrs.obj\
+   $(OBJDIR)\d1_tagset.obj\
+   $(OBJDIR)\d1_varset.obj\
+   $(OBJDIR)\d1_write.obj\
+   $(OBJDIR)\d1_if.obj
+
+Z3950_OBJS= \
+   $(OBJDIR)\z-date.obj\
+   $(OBJDIR)\z-univ.obj\
+   $(OBJDIR)\zes-update.obj\
+   $(OBJDIR)\z-accdes1.obj \
+   $(OBJDIR)\z-accform1.obj \
+   $(OBJDIR)\z-acckrb1.obj \
+   $(OBJDIR)\z-core.obj \
+   $(OBJDIR)\z-diag1.obj \
+   $(OBJDIR)\z-espec1.obj \
+   $(OBJDIR)\z-estask.obj \
+   $(OBJDIR)\z-exp.obj \
+   $(OBJDIR)\z-grs.obj \
+   $(OBJDIR)\z-opac.obj \
+   $(OBJDIR)\z-uifr1.obj \
+   $(OBJDIR)\z-rrf1.obj \
+   $(OBJDIR)\z-rrf2.obj \
+   $(OBJDIR)\z-sum.obj \
+   $(OBJDIR)\z-sutrs.obj \
+   $(OBJDIR)\zes-expi.obj \
+   $(OBJDIR)\zes-exps.obj \
+   $(OBJDIR)\zes-order.obj \
+   $(OBJDIR)\zes-pquery.obj \
+   $(OBJDIR)\zes-psched.obj \
+   $(OBJDIR)\zes-pset.obj \
+   $(OBJDIR)\zes-update0.obj 
+
+ILL_OBJS= \
+   $(OBJDIR)\ill-get.obj\
+   $(OBJDIR)\ill-core.obj\
+   $(OBJDIR)\item-req.obj
+
+COMMON_YAZ_OBJS= \
+   $(YAZ_COMSTACK_OBJS) \
+   $(YAZ_ODR_OBJS) \
+   $(YAZ_UTIL_OBJS) \
+   $(YAZ_ZUTIL_OBJS) \
+   $(YAZ_RET_OBJS)
+
+!if $(NEW_Z3950)
+YAZ_OBJS= \
+	$(COMMON_YAZ_OBJS) \
+	$(ILL_OBJS) \
+	$(Z3950_OBJS)
+!else
+YAZ_OBJS= \
+	$(COMMON_YAZ_OBJS) \
+	$(YAZ_ASN_OBJS)
+!endif
+
+DLL_OBJS= $(YAZ_OBJS)
+
+ALL_OBJS= \
+	$(YAZ_OBJS) \
+	$(YAZ_CLIENT_OBJS) \
+	$(YAZ_SERVER_OBJS) \
+	$(ZTEST_OBJS)
+
+
+##########################################################
+############## proto.h
+##########################################################
+
+!if $(NEW_Z3950)
+$(PROTOH): makefile $(INCLDIR)\yaz\z-proto.h
+	type $(INCLDIR)\yaz\z-proto.h > $(PROTOH)
+!else
+$(PROTOH): makefile $(INCLDIR)\yaz\prt-proto.h 
+	type $(INCLDIR)\yaz\prt-proto.h > $(PROTOH)
+!endif
+
+
+###########################################################
+############### Generated C and H files
+###########################################################
+
+Z3950_C_DIR=$(Z3950DIR)   
+ILL_C_DIR=$(ILLDIR)
+#!!! Should be moved to OBJ, but that requires too much trickery
+
+# Files generated from datetime.asn
+DATETIME_H_FILES = $(INCLDIR)\yaz\z-date.h
+DATETIME_C_FILES = $(Z3950_C_DIR)\z-date.c
+
+# Files generated from univres.asn
+UNIVRES_H_FILES = $(INCLDIR)\yaz\z-univ.h
+UNIVRES_C_FILES = $(Z3950_C_DIR)\z-univ.c
+
+# Files generated from esupdate.asn
+ESUPDATE_H_FILES = $(INCLDIR)\yaz\zes-update.h
+ESUPDATE_C_FILES = $(Z3950_C_DIR)\zes-update.c
+
+# Files created from z3950v3.asn
+Z3950V3_H_FILES= \
+   $(INCLDIR)\yaz\z-accdes1.h \
+   $(INCLDIR)\yaz\z-core.h
+
+Z3950V3_C_FILES= \
+   $(Z3950_C_DIR)\z-accdes1.c \
+   $(Z3950_C_DIR)\z-accform1.c \
+   $(Z3950_C_DIR)\z-acckrb1.c \
+   $(Z3950_C_DIR)\z-core.c \
+   $(Z3950_C_DIR)\z-diag1.c \
+   $(Z3950_C_DIR)\z-espec1.c \
+   $(Z3950_C_DIR)\z-estask.c \
+   $(Z3950_C_DIR)\z-exp.c \
+   $(Z3950_C_DIR)\z-grs.c \
+   $(Z3950_C_DIR)\z-opac.c \
+   $(Z3950_C_DIR)\z-uifr1.c \
+   $(Z3950_C_DIR)\z-rrf1.c \
+   $(Z3950_C_DIR)\z-rrf2.c \
+   $(Z3950_C_DIR)\z-sum.c \
+   $(Z3950_C_DIR)\z-sutrs.c \
+   $(Z3950_C_DIR)\zes-expi.c \
+   $(Z3950_C_DIR)\zes-exps.c \
+   $(Z3950_C_DIR)\zes-order.c \
+   $(Z3950_C_DIR)\zes-pquery.c \
+   $(Z3950_C_DIR)\zes-psched.c \
+   $(Z3950_C_DIR)\zes-pset.c \
+   $(Z3950_C_DIR)\zes-update0.c 
+
+ILL_CORE_H_FILES= \
+   $(INCLDIR)\yaz\ill-core.h
+
+ILL_CORE_C_FILES= \
+   $(ILL_C_DIR)\ill-core.c
+
+ITEM_REQ_H_FILES= \
+   $(INCLDIR)\yaz\item-req.h
+
+ITEM_REQ_C_FILES= \
+   $(ILL_C_DIR)\item-req.c
+
+DATETIME_FILES = $(DATETIME_H_FILES) $(DATETIME_C_FILES)
+UNIVRES_FILES = $(UNIVRES_H_FILES) $(UNIVRES_C_FILES)
+ESUPDATE_FILES = $(ESUPDATE_H_FILES) $(ESUPDATE_C_FILES)
+Z3950V3_FILES= $(Z3950V3_C_FILES) $(Z3950V3_H_FILES)
+ILL_CORE_FILES= $(ILL_CORE_C_FILES) $(ILL_CORE_H_FILES)
+ITEM_REQ_FILES= $(ITEM_REQ_C_FILES) $(ITEM_REQ_H_FILES)
+
+GENERATED_C_FILES= \
+   $(Z3950V3_C_FILES)  \
+   $(ESUPDATE_C_FILES) \
+   $(UNIVRES_C_FILES)  \
+   $(DATETIME_C_FILES)
+
+GENERATED_H_FILES= \
+   $(Z3950V3_H_FILES)  \
+   $(ESUPDATE_H_FILES) \
+   $(UNIVRES_H_FILES)  \
+   $(DATETIME_H_FILES)
+
+generated_files: \
+	$(GENERATED_H_FILES) \
+	$(GENERATED_C_FILES) \
+	$(PROTOH)
+
+###########################################################
+############### Compiling 
+###########################################################
+
+# Note: This defines where to look for the necessary
+# source files. Funny way of doing it, but it works.
+
+# DLL sources
+{$(SRCDIR)}.cpp{$(OBJDIR)}.obj:
+	@$(CPP) $(COPT) $<
+
+# Yaz client
+{$(CLIENTDIR)}.c{$(OBJDIR)}.obj:
+	@$(CPP) $(COPT) $< /D"_CONSOLE"
+
+# Ztest
+{$(ZTESTDIR)}.c{$(OBJDIR)}.obj:
+	@$(CPP) $(COPT) $< /D"_CONSOLE"
+
+# Server
+{$(SERVERDIR)}.c{$(OBJDIR)}.obj:
+	@$(CPP) $(COPT) $< 
+
+# Various YAZ source directories
+{$(ASNDIR)}.c{$(OBJDIR)}.obj:
+	@$(CPP) $(COPT) $< 
+
+{$(COMSTACKDIR)}.c{$(OBJDIR)}.obj:
+	@$(CPP) $(COPT) $< 
+
+{$(ODRDIR)}.c{$(OBJDIR)}.obj:
+	@$(CPP) $(COPT) $< 
+
+{$(UTILDIR)}.c{$(OBJDIR)}.obj:
+	@$(CPP) $(COPT) $< 
+
+{$(ZUTILDIR)}.c{$(OBJDIR)}.obj:
+	@$(CPP)	$(COPT) $< 
+
+{$(RETDIR)}.c{$(OBJDIR)}.obj:
+	@$(CPP) $(COPT) $<
+
+{$(Z3950_C_DIR)}.c{$(OBJDIR)}.obj:
+	@$(CPP) $(COPT) $< 
+
+{$(ILL_C_DIR)}.c{$(OBJDIR)}.obj:
+	@$(CPP) $(COPT) $< 
+
+############### ASN-generated files
+
+$(Z3950V3_FILES): $(Z3950DIR)\z3950v3.asn
+	@cd $(Z3950DIR)
+	$(TCL) $(TCLOPT) -d z.tcl z3950v3.asn
+	@cd $(WINDIR)
+
+$(DATETIME_FILES): $(Z3950DIR)\datetime.asn
+	@cd $(Z3950DIR)
+	$(TCL) $(TCLOPT) -d z.tcl datetime.asn
+	@cd $(WINDIR)
+
+$(UNIVRES_FILES): $(Z3950DIR)\univres.asn
+	@cd $(Z3950DIR)
+	$(TCL) $(TCLOPT) -d z.tcl univres.asn
+	@cd $(WINDIR)
+
+$(ESUPDATE_FILES): $(Z3950DIR)\esupdate.asn
+	@cd $(Z3950DIR)
+	$(TCL) $(TCLOPT) -d z.tcl esupdate.asn
+	@cd $(WINDIR)
+
+$(ILL_CORE_FILES): $(ILLDIR)\ill9702.asn
+	@cd $(ILLDIR)
+	$(TCL) $(TCLOPT) -d ill.tcl ill9702.asn
+	@cd $(WINDIR)
+
+$(ITEM_REQ_FILES): $(ILLDIR)\item-req.asn
+	@cd $(ILLDIR)
+	$(TCL) $(TCLOPT) -d ill.tcl item-req.asn
+	@cd $(WINDIR)
+
+###########################################################
+############### Linking
+###########################################################
+
+$(DLL) $(IMPLIB): "$(BINDIR)" $(DLL_OBJS) 
+	@echo Linking the dll  $(DLL)
+	$(LINK) @<<
+		$(LNKOPT) 
+		$(LINK_LIBS) 
+		$(DLL_LINK_OPTIONS)
+		$(DLL_OBJS) 
+		/out:$(DLL) 
+		/implib:"$(LIBDIR)/yaz.lib"
+		/pdb:"$(LIBDIR)/yaz.pdb" 
+		/map:"$(LIBDIR)/yaz.map"  
+<<
+
+$(CLIENT) : "$(BINDIR)" $(YAZ_CLIENT_OBJS) 
+	@echo Linking the client  $(CLIENT)
+	$(LINK) @<<
+        $(LNKOPT) 
+		$(CLIENT_LINK_OPTIONS)
+		$(LINK_LIBS) 
+		$(IMPLIB)
+		$(YAZ_CLIENT_OBJS)
+
+		/pdb:"$(LIBDIR)/yaz-client.pdb"
+
+		/map:"$(LIBDIR)/yaz-client.map"
+		/out:$(CLIENT)
+<<
+
+$(ZTEST) : "$(BINDIR)" $(ZTEST_OBJS) $(SERVER) $(DLL)
+	@echo Linking the ztest  $(ZTEST)
+	$(LINK) @<<
+        $(LNKOPT) 
+		$(ZTEST_LINK_OPTIONS)
+		$(LINK_LIBS) 
+		shell32.lib
+		$(IMPLIB)
+		$(SERVER)
+		$(ZTEST_OBJS) 
+
+		/implib:"$(LIBDIR)/yaz-ztest.lib"
+
+		/pdb:"$(LIBDIR)/yaz-ztest.pdb"
+
+		/map:"$(LIBDIR)/yaz-ztest.map"
+		/out:$(ZTEST) 
+<<
+
+
+$(SERVER) : "$(BINDIR)" $(YAZ_SERVER_OBJS) 
+	@echo Linking the server  $(SERVER)
+	$(LINK) $(SERVER_LINK_OPTIONS) @<<
+		/nologo
+		$(IMPLIB)
+		$(YAZ_SERVER_OBJS) 
+		/out:$(SERVER) 
+<<
+
+# note that this links a lib, so it uses completely different options.
+
+
+
+###########################################################
+############### Special operations
+###########################################################
+
+
+############## clean
+clean:
+	del $(DLL) 
+	del $(CLIENT)
+	del $(SERVER)
+	del $(ZTEST)
+	del $(TMPDIR)\*.
+
+	del $(LIBDIR)\*.MAP
+
+	del $(LIBDIR)\*.LIB
+	del $(OBJDIR)\*.OBJ
+
+	del $(PROTOH)
+
+realclean: clean
+	del $(Z3950_C_DIR)\*.c
+	del $(Z3950_C_DIR)\*.h
+	del $(INCLDIR)\yaz\z-accdes1.h
+	del $(INCLDIR)\yaz\z-core.h
+	del $(DATETIME_H_FILES)
+	del $(UNIVRES_H_FILES)
+	del $(ESUPDATE_H_FILES)
+
+# Because DOS del will only accept one file name to delete,
+# the _H_ files work only on sets that have just one file.
+# Z3950_H_FILES had to be spelled out. One more point for MS!
+
+########### check directories and create if needed
+dirs: $(OBJDIR) $(WINDIR) $(LIBDIR) $(BINDIR) $(TMPDIR)
+
+$(OBJDIR) $(WINDIR) $(LIBDIR) $(BINDIR) $(TMPDIR):
+ 	if not exist "$@/$(NUL)" mkdir "$@"
+
+
+###########################################################
+############### Explicit dependencies
+###########################################################
+
+$(ALL_OBJS): makefile $(PROTOH)
+
+# force recompilation of everything, if makefile changed
+
+$(Z3950_OBJS): $(GENERATED_C_FILES) $(GENERATED_H_FILES)
+
+$(ILL_OBJS): $(ILL_CORE_FILES) $(ITEM_REQ_FILES)
+
+!if $(NEW_Z3950)
+$(PROTOH): $(GENERATED_C_FILES) $(GENERATED_H_FILES)
+!endif
+# makes sure we generate before compiling anything, as the
+# new proto.h refers to the generated files, and is included
+# in various places
+
+###########################################################
+############### Log
+###########################################################
+#
+# $Log$
+# Revision 1.1  2000/08/03 03:12:13  johnmcp
+# Added the YAZ toolkit source to the packages directory (for z39.50 stuff)
+#
+# Revision 1.14  2000/03/02 08:48:21  adam
+# Renamed ASN.1 compiler to yaz-comp (used to be yc.tcl).
+#
+# Revision 1.13  2000/02/28 11:13:03  adam
+# Removed odr_priv.obj.
+#
+# Revision 1.12  2000/01/06 11:27:16  adam
+# Updated for ILL.
+#
+# Revision 1.11  1999/12/21 14:16:20  ian
+# Changed retrieval module to allow data1 trees with no associated absyn.
+# Also added a simple interface for extracting values from data1 trees using
+# a string based tagpath.
+#
+# Revision 1.10  1999/12/08 13:10:48  adam
+# New version.
+#
+# Revision 1.9  1999/11/30 13:47:12  adam
+# Improved installation. Moved header files to include/yaz.
+#
+# Revision 1.8  1999/07/21 08:48:02  adam
+# Removed dmalloc.obj.
+#
+# Revision 1.7  1999/06/09 15:10:08  heikki
+# Cleaning up. Seems to work all right
+#
+# Revision 1.6  1999/06/09 13:33:32  heikki
+# Compiles and links both old and new type stuff all right
+#
+# Revision 1.5  1999/06/09 11:05:30  heikki
+# At least it can compile
+#
+# Revision 1.4  1999/06/09 09:41:09  heikki
+# More work on the ASN-generated files.
+#
+# Revision 1.3  1999/06/08 14:32:30  heikki
+# Proto.h works all right, removed linker warnings from server.lib
+#
+# Revision 1.2  1999/06/08 14:07:24  heikki
+# Renamed a pile of files
+# Tmpdir (to get around Ms leaving temp files around, and crashing
+# when too many with same number...)
+#
+# Revision 1.1  1999/06/08 12:15:41  heikki
+# Renamed to makefile (.nothing) (from .mak)
+# Working on the proto.h problems and alternative confiigurations
+#
+# Revision 1.5  1999/06/04 10:04:28  heikki
+# Cleaning up
+#
+# Revision 1.4  1999/06/02 13:23:29  heikki
+# Debug options for C compiler
+#
+# Revision 1.3  1999/05/19 08:26:22  heikki
+# Added comments
+#
+#
+
+
+
Index: /main/tags/2.25/gsdl/packages/yaz/windows.txt
===================================================================
--- /main/tags/2.25/gsdl/packages/yaz/windows.txt	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/yaz/windows.txt	(revision 21064)
@@ -0,0 +1,56 @@
+YAZ Compilation guidelines for winNT/95.
+
+This distribution of YAZ includes makefiles that works with Visual
+C++ version 5 and 6. The makefile is located in sub directory 'win'.
+
+If you wish to make modifications to the make process you should
+edit makefile before proceeding. For example, a DEBUG version of YAZ
+can be build by modifying the line 'DEBUG=0' to 'DEBUG=1' in the
+makefile.
+
+Run nmake in that directory (in a Command prompt for example). Eg:
+    >CD \YAZ\WIN
+    >NMAKE
+
+Make sure that the environment variables PATH, LIB and INCLUDE are
+set properly. They *should* be set by the Visual C++ installation.
+Programs cl.exe, link.exe and others must be found in the PATH. The
+standard includes files, standard libraries must be found in INCLUDE
+and LIB respectively.
+
+The following components are build by the nmake process:
+
+yaz.dll - This DLL is made of the source in all sub directories except
+         for 'server', 'client' and 'ztest'. To export public functions
+         the header files contain the modifier YAZ_EXPORT which is
+         defined in yconfig.h. The value of this modifier,
+         __declspec(dllexport), is probably specific to Visual C++. 
+
+server.lib - The server library, which includes the source from
+         'server'.  Unlike the UNIX version, the server library is
+         multi-threaded.
+
+yaz-client.exe - A Z39.50 client console application. It is linked with
+         the import library yaz.lib. This application searches for yaz.dll
+         during runtime.
+
+yaz-ztest.exe - The Z39.50 test server as a console application. It is
+         linked with the import library yaz.lib and the regular library
+         server.lib. When running yaz-ztest make sure it is able to find
+         the record test files dummy-records, dummy-grs, and dummy-words
+         in the current directory. 
+
+         As an option ztest may be installed as an NT service
+         (not Windows 95). Use 'ztest -install <otherargs>' to install
+         it and 'ztest -remove <otherargs>' to remove it again. Since
+         NT runs the service program in some weird directory, such as
+         \winnt\system32, it's probably a good idea to use the option
+         '-w' to change to some other directory. For example
+
+            yaz-ztest -install -w d:\proj\yaz\ztest -l ztest.out tcp:@:210
+
+         which specifies both working directory (d:\proj\yaz\ztest) 
+         and a log file (ztest.out). The server is started on port 210.
+
+After successful compilation all executables and DLL's are located
+in sub YAZ\BIN. Libraries are located in YAZ\LIB.
Index: /main/tags/2.25/gsdl/packages/yaz/yaz.spec
===================================================================
--- /main/tags/2.25/gsdl/packages/yaz/yaz.spec	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/yaz/yaz.spec	(revision 21064)
@@ -0,0 +1,41 @@
+Summary: YAZ - A Z39.50 Library
+Name: yaz
+Version: 1.6
+Release: 1
+Copyright: BSD
+Group: Development/Libraries
+Vendor: Index Data ApS <info@indexdata.dk>
+Url: http://www.indexdata.dk/yaz/
+Source: yaz-1.6.tar.gz
+BuildRoot: /var/tmp/%{name}-%{version}-root
+Packager: Adam Dickmeiss <adam@indexdata.dk>
+
+%description
+The YAZ package is a developers' library for developing client - and
+server application using the ANSI/NISO Z39.50 protocol for Information
+Retrieval.
+
+%prep
+%setup
+
+%build
+
+CFLAGS="$RPM_OPT_FLAGS" \
+ ./configure --prefix=/usr --enable-yc --enable-tcpd
+make CFLAGS="$RPM_OPT_FLAGS"
+
+%install
+rm -fr $RPM_BUILD_ROOT
+make prefix=$RPM_BUILD_ROOT/usr install
+
+%files
+%defattr(-,root,root)
+%doc README LICENSE CHANGELOG TODO
+%config /usr/share/yaz/tab
+/usr/bin/yaz-client
+/usr/bin/yaz-ztest
+/usr/bin/yaz-config
+/usr/bin/yaz-comp
+/usr/lib/libyaz.a
+/usr/include/yaz
+/usr/share/yaz/doc
Index: /main/tags/2.25/gsdl/packages/yaz/z39.50/Makefile.am
===================================================================
--- /main/tags/2.25/gsdl/packages/yaz/z39.50/Makefile.am	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/yaz/z39.50/Makefile.am	(revision 21064)
@@ -0,0 +1,30 @@
+## $Id$
+
+INCLUDES=-I../include
+
+noinst_LIBRARIES = libasn.a
+
+EXTRA_DIST=datetime.asn esupdate.asn univres.asn z3950v3.asn z.tcl
+
+libasn_a_SOURCES = z-accdes1.c z-accform1.c z-acckrb1.c z-core.c \
+ z-diag1.c z-espec1.c z-estask.c z-exp.c z-grs.c z-opac.c z-uifr1.c \
+ z-rrf1.c z-rrf2.c z-sum.c z-sutrs.c \
+ zes-expi.c zes-exps.c zes-order.c zes-pquery.c zes-psched.c \
+ zes-pset.c zes-update0.c z-date.c z-univ.c zes-update.c
+
+z-accdes1.c z-accform1.c z-acckrb1.c z-core.c \
+ z-diag1.c z-espec1.c z-estask.c z-exp.c z-grs.c z-opac.c z-uifr1.c \
+ z-rrf1.c z-rrf2.c z-sum.c z-sutrs.c \
+ zes-expi.c zes-exps.c zes-order.c zes-pquery.c zes-psched.c \
+ zes-pset.c zes-update0.c \
+ ../include/yaz/z-accdes1.h: z.tcl z3950v3.asn ../util/yaz-comp
+	../util/yaz-comp -d z.tcl -i yaz -I ../include $(YCFLAGS) z3950v3.asn
+
+z-date.c ../include/yaz/z-date.h: z.tcl datetime.asn ../util/yaz-comp
+	../util/yaz-comp -d z.tcl -i yaz -I ../include $(YCFLAGS) datetime.asn
+
+z-univ.c ../include/yaz/z-univ.h: z.tcl univres.asn ../util/yaz-comp
+	../util/yaz-comp -d z.tcl -i yaz -I ../include $(YCFLAGS) univres.asn
+
+zes-update.c ../include/yaz/zes-update.h: z.tcl esupdate.asn ../util/yaz-comp
+	../util/yaz-comp -d z.tcl -i yaz -I ../include $(YCFLAGS) esupdate.asn
Index: /main/tags/2.25/gsdl/packages/yaz/z39.50/Makefile.in
===================================================================
--- /main/tags/2.25/gsdl/packages/yaz/z39.50/Makefile.in	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/yaz/z39.50/Makefile.in	(revision 21064)
@@ -0,0 +1,290 @@
+# Makefile.in generated automatically by automake 1.4 from Makefile.am
+
+# Copyright (C) 1994, 1995-8, 1999 Free Software Foundation, Inc.
+# This Makefile.in is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
+# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE.
+
+
+SHELL = @SHELL@
+
+srcdir = @srcdir@
+top_srcdir = @top_srcdir@
+VPATH = @srcdir@
+prefix = @prefix@
+exec_prefix = @exec_prefix@
+
+bindir = @bindir@
+sbindir = @sbindir@
+libexecdir = @libexecdir@
+datadir = @datadir@
+sysconfdir = @sysconfdir@
+sharedstatedir = @sharedstatedir@
+localstatedir = @localstatedir@
+libdir = @libdir@
+infodir = @infodir@
+mandir = @mandir@
+includedir = @includedir@
+oldincludedir = /usr/include
+
+DESTDIR =
+
+pkgdatadir = $(datadir)/@PACKAGE@
+pkglibdir = $(libdir)/@PACKAGE@
+pkgincludedir = $(includedir)/@PACKAGE@
+
+top_builddir = ..
+
+ACLOCAL = @ACLOCAL@
+AUTOCONF = @AUTOCONF@
+AUTOMAKE = @AUTOMAKE@
+AUTOHEADER = @AUTOHEADER@
+
+INSTALL = @INSTALL@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@ $(AM_INSTALL_PROGRAM_FLAGS)
+INSTALL_DATA = @INSTALL_DATA@
+INSTALL_SCRIPT = @INSTALL_SCRIPT@
+transform = @program_transform_name@
+
+NORMAL_INSTALL = :
+PRE_INSTALL = :
+POST_INSTALL = :
+NORMAL_UNINSTALL = :
+PRE_UNINSTALL = :
+POST_UNINSTALL = :
+ASNMODULE = @ASNMODULE@
+CC = @CC@
+CPP = @CPP@
+ILLLIB = @ILLLIB@
+ILLMODULE = @ILLMODULE@
+MAKEINFO = @MAKEINFO@
+PACKAGE = @PACKAGE@
+RANLIB = @RANLIB@
+SUBDIRS_VAR = @SUBDIRS_VAR@
+VERSION = @VERSION@
+have_sgml2html = @have_sgml2html@
+have_sgml2latex = @have_sgml2latex@
+have_sgml2txt = @have_sgml2txt@
+
+INCLUDES = -I../include
+
+noinst_LIBRARIES = libasn.a
+
+EXTRA_DIST = datetime.asn esupdate.asn univres.asn z3950v3.asn z.tcl
+
+libasn_a_SOURCES = z-accdes1.c z-accform1.c z-acckrb1.c z-core.c  z-diag1.c z-espec1.c z-estask.c z-exp.c z-grs.c z-opac.c z-uifr1.c  z-rrf1.c z-rrf2.c z-sum.c z-sutrs.c  zes-expi.c zes-exps.c zes-order.c zes-pquery.c zes-psched.c  zes-pset.c zes-update0.c z-date.c z-univ.c zes-update.c
+
+mkinstalldirs = $(SHELL) $(top_srcdir)/mkinstalldirs
+CONFIG_CLEAN_FILES = 
+LIBRARIES =  $(noinst_LIBRARIES)
+
+
+DEFS = @DEFS@ -I. -I$(srcdir) 
+CPPFLAGS = @CPPFLAGS@
+LDFLAGS = @LDFLAGS@
+LIBS = @LIBS@
+libasn_a_LIBADD = 
+libasn_a_OBJECTS =  z-accdes1.o z-accform1.o z-acckrb1.o z-core.o \
+z-diag1.o z-espec1.o z-estask.o z-exp.o z-grs.o z-opac.o z-uifr1.o \
+z-rrf1.o z-rrf2.o z-sum.o z-sutrs.o zes-expi.o zes-exps.o zes-order.o \
+zes-pquery.o zes-psched.o zes-pset.o zes-update0.o z-date.o z-univ.o \
+zes-update.o
+AR = ar
+CFLAGS = @CFLAGS@
+COMPILE = $(CC) $(DEFS) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
+CCLD = $(CC)
+LINK = $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(LDFLAGS) -o $@
+DIST_COMMON =  Makefile.am Makefile.in
+
+
+DISTFILES = $(DIST_COMMON) $(SOURCES) $(HEADERS) $(TEXINFOS) $(EXTRA_DIST)
+
+TAR = gtar
+GZIP_ENV = --best
+SOURCES = $(libasn_a_SOURCES)
+OBJECTS = $(libasn_a_OBJECTS)
+
+all: all-redirect
+.SUFFIXES:
+.SUFFIXES: .S .c .o .s
+$(srcdir)/Makefile.in: Makefile.am $(top_srcdir)/configure.in $(ACLOCAL_M4) 
+	cd $(top_srcdir) && $(AUTOMAKE) --gnu --include-deps z39.50/Makefile
+
+Makefile: $(srcdir)/Makefile.in  $(top_builddir)/config.status
+	cd $(top_builddir) \
+	  && CONFIG_FILES=$(subdir)/$@ CONFIG_HEADERS= $(SHELL) ./config.status
+
+
+mostlyclean-noinstLIBRARIES:
+
+clean-noinstLIBRARIES:
+	-test -z "$(noinst_LIBRARIES)" || rm -f $(noinst_LIBRARIES)
+
+distclean-noinstLIBRARIES:
+
+maintainer-clean-noinstLIBRARIES:
+
+.c.o:
+	$(COMPILE) -c $<
+
+.s.o:
+	$(COMPILE) -c $<
+
+.S.o:
+	$(COMPILE) -c $<
+
+mostlyclean-compile:
+	-rm -f *.o core *.core
+
+clean-compile:
+
+distclean-compile:
+	-rm -f *.tab.c
+
+maintainer-clean-compile:
+
+libasn.a: $(libasn_a_OBJECTS) $(libasn_a_DEPENDENCIES)
+	-rm -f libasn.a
+	$(AR) cru libasn.a $(libasn_a_OBJECTS) $(libasn_a_LIBADD)
+	$(RANLIB) libasn.a
+
+tags: TAGS
+
+ID: $(HEADERS) $(SOURCES) $(LISP)
+	list='$(SOURCES) $(HEADERS)'; \
+	unique=`for i in $$list; do echo $$i; done | \
+	  awk '    { files[$$0] = 1; } \
+	       END { for (i in files) print i; }'`; \
+	here=`pwd` && cd $(srcdir) \
+	  && mkid -f$$here/ID $$unique $(LISP)
+
+TAGS:  $(HEADERS) $(SOURCES)  $(TAGS_DEPENDENCIES) $(LISP)
+	tags=; \
+	here=`pwd`; \
+	list='$(SOURCES) $(HEADERS)'; \
+	unique=`for i in $$list; do echo $$i; done | \
+	  awk '    { files[$$0] = 1; } \
+	       END { for (i in files) print i; }'`; \
+	test -z "$(ETAGS_ARGS)$$unique$(LISP)$$tags" \
+	  || (cd $(srcdir) && etags $(ETAGS_ARGS) $$tags  $$unique $(LISP) -o $$here/TAGS)
+
+mostlyclean-tags:
+
+clean-tags:
+
+distclean-tags:
+	-rm -f TAGS ID
+
+maintainer-clean-tags:
+
+distdir = $(top_builddir)/$(PACKAGE)-$(VERSION)/$(subdir)
+
+subdir = z39.50
+
+distdir: $(DISTFILES)
+	@for file in $(DISTFILES); do \
+	  d=$(srcdir); \
+	  if test -d $$d/$$file; then \
+	    cp -pr $$/$$file $(distdir)/$$file; \
+	  else \
+	    test -f $(distdir)/$$file \
+	    || ln $$d/$$file $(distdir)/$$file 2> /dev/null \
+	    || cp -p $$d/$$file $(distdir)/$$file || :; \
+	  fi; \
+	done
+
+info-am:
+info: info-am
+dvi-am:
+dvi: dvi-am
+check-am: all-am
+check: check-am
+installcheck-am:
+installcheck: installcheck-am
+install-exec-am:
+install-exec: install-exec-am
+
+install-data-am:
+install-data: install-data-am
+
+install-am: all-am
+	@$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
+install: install-am
+uninstall-am:
+uninstall: uninstall-am
+all-am: Makefile $(LIBRARIES)
+all-redirect: all-am
+install-strip:
+	$(MAKE) $(AM_MAKEFLAGS) AM_INSTALL_PROGRAM_FLAGS=-s install
+installdirs:
+
+
+mostlyclean-generic:
+
+clean-generic:
+
+distclean-generic:
+	-rm -f Makefile $(CONFIG_CLEAN_FILES)
+	-rm -f config.cache config.log stamp-h stamp-h[0-9]*
+
+maintainer-clean-generic:
+mostlyclean-am:  mostlyclean-noinstLIBRARIES mostlyclean-compile \
+		mostlyclean-tags mostlyclean-generic
+
+mostlyclean: mostlyclean-am
+
+clean-am:  clean-noinstLIBRARIES clean-compile clean-tags clean-generic \
+		mostlyclean-am
+
+clean: clean-am
+
+distclean-am:  distclean-noinstLIBRARIES distclean-compile \
+		distclean-tags distclean-generic clean-am
+
+distclean: distclean-am
+
+maintainer-clean-am:  maintainer-clean-noinstLIBRARIES \
+		maintainer-clean-compile maintainer-clean-tags \
+		maintainer-clean-generic distclean-am
+	@echo "This command is intended for maintainers to use;"
+	@echo "it deletes files that may require special tools to rebuild."
+
+maintainer-clean: maintainer-clean-am
+
+.PHONY: mostlyclean-noinstLIBRARIES distclean-noinstLIBRARIES \
+clean-noinstLIBRARIES maintainer-clean-noinstLIBRARIES \
+mostlyclean-compile distclean-compile clean-compile \
+maintainer-clean-compile tags mostlyclean-tags distclean-tags \
+clean-tags maintainer-clean-tags distdir info-am info dvi-am dvi check \
+check-am installcheck-am installcheck install-exec-am install-exec \
+install-data-am install-data install-am install uninstall-am uninstall \
+all-redirect all-am all installdirs mostlyclean-generic \
+distclean-generic clean-generic maintainer-clean-generic clean \
+mostlyclean distclean maintainer-clean
+
+
+z-accdes1.c z-accform1.c z-acckrb1.c z-core.c \
+ z-diag1.c z-espec1.c z-estask.c z-exp.c z-grs.c z-opac.c z-uifr1.c \
+ z-rrf1.c z-rrf2.c z-sum.c z-sutrs.c \
+ zes-expi.c zes-exps.c zes-order.c zes-pquery.c zes-psched.c \
+ zes-pset.c zes-update0.c \
+ ../include/yaz/z-accdes1.h: z.tcl z3950v3.asn ../util/yaz-comp
+	../util/yaz-comp -d z.tcl -i yaz -I ../include $(YCFLAGS) z3950v3.asn
+
+z-date.c ../include/yaz/z-date.h: z.tcl datetime.asn ../util/yaz-comp
+	../util/yaz-comp -d z.tcl -i yaz -I ../include $(YCFLAGS) datetime.asn
+
+z-univ.c ../include/yaz/z-univ.h: z.tcl univres.asn ../util/yaz-comp
+	../util/yaz-comp -d z.tcl -i yaz -I ../include $(YCFLAGS) univres.asn
+
+zes-update.c ../include/yaz/zes-update.h: z.tcl esupdate.asn ../util/yaz-comp
+	../util/yaz-comp -d z.tcl -i yaz -I ../include $(YCFLAGS) esupdate.asn
+
+# Tell versions [3.59,3.63) of GNU make to not export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:
Index: /main/tags/2.25/gsdl/packages/yaz/z39.50/datetime.asn
===================================================================
--- /main/tags/2.25/gsdl/packages/yaz/z39.50/datetime.asn	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/yaz/z39.50/datetime.asn	(revision 21064)
@@ -0,0 +1,82 @@
+UserInfoFormat-dateTime
+{Z39-50-userInfoFormat dateTime (6)} DEFINITIONS ::=
+BEGIN
+IMPORTS IntUnit FROM Z39-50-APDU-1995;
+
+DateTime ::= SEQUENCE{
+     date [1]  Z3950Date OPTIONAL,
+     time [2]  Z3950Time OPTIONAL
+                    -- one or the other, or both
+          }
+
+Z3950Date ::= SEQUENCE{
+ year         [1] IMPLICIT INTEGER,
+                    -- For "positive" years, i.e. 1 AD or later, supply
+                    -- the absolute year, e.g. If the year is 1995, supply
+                    -- the integer 1995; the value 95 would indicate the
+                    -- year 0095.
+                    -- For "negative" years, e.g. 1 BC or earlier, -1
+                    -- represents 1 BC, -2 represents 2 BC, etc. Zero is
+                    -- invalid, because there was no year zero.
+ partOfYear   [2] CHOICE{ -- may be omitted if only year is significant
+        monthAndDay [1]   IMPLICIT SEQUENCE{
+                       month [2]  IMPLICIT INTEGER, 
+                                   -- value 1-12
+                       day   [3]  IMPLICIT INTEGER OPTIONAL
+                                   -- may be omitted if only year and month
+                                   -- are significant. Value 1-31.
+                                           },
+        julianDay   [2]   IMPLICIT INTEGER, -- Value 1 - 366.
+        weekNumber  [3]   IMPLICIT INTEGER, -- Value 1 - 53. 
+        quarter     [4] CHOICE{
+                       first    [1] IMPLICIT NULL,
+                       second   [2] IMPLICIT NULL,
+                       third    [3] IMPLICIT NULL,
+                       fourth   [4] IMPLICIT NULL},
+        season      [5] CHOICE{
+                       winter   [1] IMPLICIT NULL,
+                       spring   [2] IMPLICIT NULL,
+                       summer   [3] IMPLICIT NULL,
+                       autumn   [4] IMPLICIT NULL}
+                                              } OPTIONAL, 
+ flags        [3] IMPLICIT SEQUENCE{
+     circa          [1]   IMPLICIT NULL OPTIONAL,
+                          -- if this flag is set then the date is "approximate".
+     era            [2]   IMPLICIT CHOICE{
+                          -- If era occurs, partOfYear should not occur.
+                          decade         [1] IMPLICIT NULL,
+                                              -- year must be multiple of 10.
+                                              -- For example, 1900 refers to
+                                              -- the decade covering the years
+                                              -- 1900 through 1909.
+                          century        [2] IMPLICIT NULL,
+                                              -- year must be multiple of 100.
+                          millennium     [3] IMPLICIT NULL
+                                              -- year must be multiple of 1000.
+                                                    } OPTIONAL
+                                              } OPTIONAL
+                                }
+
+
+Z3950Time ::= SEQUENCE{
+     hour           [1] IMPLICIT INTEGER,
+                             -- Value 0-23. 
+     minute         [2]  IMPLICIT INTEGER OPTIONAL,
+                             -- value 0-59. May be omitted when hour only is
+                             -- significant (in which case second and
+                             -- partOfSecond must also be omitted). 
+     second         [3]  IMPLICIT INTEGER OPTIONAL,
+                             -- value 0-59. May be omitted when only hour, or
+                             -- hour and minute, is significant (in which case
+                             -- partOfSecond must also be omitted).
+     partOfSecond   [4]  IMPLICIT IntUnit OPTIONAL,
+                             -- Use Unit System = 'si', Unit type = 'time'; 
+                             -- Unit = 'second', with appropriate value and
+                             -- scale factor.
+     zone           [5]  CHOICE{
+                              local      [1]  IMPLICIT NULL,
+                              utc        [2]  IMPLICIT NULL,
+
+                              utcOffset  [3]  IMPLICIT INTEGER  -- in minutes
+                                                    }}             
+END                              
Index: /main/tags/2.25/gsdl/packages/yaz/z39.50/esupdate.asn
===================================================================
--- /main/tags/2.25/gsdl/packages/yaz/z39.50/esupdate.asn	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/yaz/z39.50/esupdate.asn	(revision 21064)
@@ -0,0 +1,103 @@
+ESFormat-Update
+{Z39-50-extendedService Update (5) revisions (1)  revision-1 (1)} DEFINITIONS ::=
+  -- oid is 1.2.840.10003.9.5.1.1
+BEGIN
+IMPORTS DiagRec, InternationalString
+FROM Z39-50-APDU-1995;
+Update ::= CHOICE{
+    esRequest      [1] IMPLICIT SEQUENCE{
+       toKeep         [1] OriginPartToKeep,
+       notToKeep      [2] OriginPartNotToKeep},
+    taskPackage    [2] IMPLICIT SEQUENCE{
+                       originPart     [1]
+                                   OriginPartToKeep,
+                       targetPart     [2] TargetPart}}
+
+OriginPartToKeep ::= SEQUENCE{
+action                  [1] IMPLICIT INTEGER{
+                                recordInsert    (1),
+                                recordReplace   (2),
+                                recordDelete    (3),
+                                elementUpdate   (4),
+                                specialUpdate   (5)},
+ databaseName           [2] IMPLICIT InternationalString,
+ schema                 [3] IMPLICIT OBJECT IDENTIFIER OPTIONAL,
+ elementSetName         [4] IMPLICIT InternationalString OPTIONAL,
+ actionQualifier        [5] IMPLICIT EXTERNAL OPTIONAL}
+
+OriginPartNotToKeep ::= SuppliedRecords
+
+TargetPart ::= SEQUENCE{
+  updateStatus        [1] IMPLICIT INTEGER{
+                          success (1),
+                          partial (2),
+                          failure (3)},
+  globalDiagnostics   [2] IMPLICIT SEQUENCE OF
+                              DiagRec OPTIONAL,
+                    -- These are non-surrogate
+                    -- diagnosticsrelating to the task,
+                    -- not to individual records.
+  taskPackageRecords  [3] IMPLICIT SEQUENCE OF
+TaskPackageRecordStructure
+                    -- There should be a
+                    -- TaskPackageRecordStructure
+                    -- for every record supplied.
+                    -- The target should create
+                    -- such a structure for every
+                    -- record immediately upon
+                    -- creating the task package
+                    -- to include correlation
+                    -- information and status.
+                    -- The record itself would not
+                    -- be included until processing
+                    -- for that record is complete.
+               }
+
+-- Auxiliary definitions for Update
+SuppliedRecords ::= SEQUENCE OF SEQUENCE{
+  recordId     [1] CHOICE{
+                number  [1] IMPLICIT INTEGER,
+                string  [2] IMPLICIT  InternationalString,
+                opaque  [3] IMPLICIT OCTET STRING} OPTIONAL,
+  supplementalId [2] CHOICE{
+                 timeStamp       [1] IMPLICIT  GeneralizedTime,
+                 versionNumber   [2] IMPLICIT InternationalString,
+                 previousVersion [3] IMPLICIT EXTERNAL} OPTIONAL,
+  correlationInfo   [3] IMPLICIT CorrelationInfo OPTIONAL,
+  record            [4] IMPLICIT EXTERNAL}
+
+CorrelationInfo ::= SEQUENCE{
+            -- origin may supply one or both for any record:
+  note [1] IMPLICIT InternationalString OPTIONAL,
+  id   [2] IMPLICIT INTEGER OPTIONAL}
+
+TaskPackageRecordStructure ::= SEQUENCE{
+     recordOrSurDiag  [1] CHOICE {
+                    record     [1] IMPLICIT EXTERNAL,
+                      -- Choose 'record' if
+                      -- recordStatus is 'success', and
+                      -- elementSetName was supplied.
+
+                  surrogateDiagnostics   [2] IMPLICIT
+                              SEQUENCE OF DiagRec
+                         -- Choose 'SurrogateDiagnostics', if
+                         -- RecordStatus is failure.
+                                } OPTIONAL,
+                -- The parameter recordOrSurDiag
+                    -- will thus be omitted only if
+                    -- 'elementSetName' was omitted and
+                    -- recordStatus is 'success'; or
+                    --if record status is 'queued'
+                    -- or in 'process'.
+     correlationInfo [2] IMPLICIT
+                         CorrelationInfo OPTIONAL,
+                    -- This should be included
+                    -- if it was supplied by the origin.
+     recordStatus    [3] IMPLICIT INTEGER{
+                                        success   (1),
+                                        queued    (2),
+                                        inProcess (3),
+                                        failure   (4)},
+      supplementalDiagnostics   [4] IMPLICIT
+                SEQUENCE OF DiagRec OPTIONAL}
+END
Index: /main/tags/2.25/gsdl/packages/yaz/z39.50/univres.asn
===================================================================
--- /main/tags/2.25/gsdl/packages/yaz/z39.50/univres.asn	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/yaz/z39.50/univres.asn	(revision 21064)
@@ -0,0 +1,23 @@
+ResourceReport-Format-Universe-1
+{Z39-50-resourceReport universe-1 (1000)} DEFINITIONS ::=
+BEGIN
+IMPORTS StringOrNumeric FROM Z39-50-APDU-1995;
+--
+
+UniverseReportHits ::= SEQUENCE {
+	database	StringOrNumeric,
+	hits	StringOrNumeric
+}
+
+UniverseReportDuplicate ::= SEQUENCE {
+	hitno StringOrNumeric
+}
+
+UniverseReport ::= SEQUENCE {
+	totalHits INTEGER,
+	report CHOICE {
+		databaseHits 	[0] IMPLICIT UniverseReportHits,
+		duplicate 		[1] IMPLICIT UniverseReportDuplicate
+	}
+}
+END
Index: /main/tags/2.25/gsdl/packages/yaz/z39.50/z-accdes1.c
===================================================================
--- /main/tags/2.25/gsdl/packages/yaz/z39.50/z-accdes1.c	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/yaz/z39.50/z-accdes1.c	(revision 21064)
@@ -0,0 +1,35 @@
+/* Generated automatically by the YAZ ASN.1 Compiler 0.3 */
+/* Module-C: AccessControlFormat-des-1 */
+
+#include <yaz/z-accdes1.h>
+
+int z_DES_RN_Object (ODR o, Z_DES_RN_Object **p, int opt, const char *name)
+{
+	static Odr_arm arm[] = {
+		{ODR_IMPLICIT, ODR_CONTEXT, 1, Z_DES_RN_Object_challenge,
+		(Odr_fun) z_DRNType, "challenge"},
+		{ODR_IMPLICIT, ODR_CONTEXT, 2, Z_DES_RN_Object_response,
+		(Odr_fun) z_DRNType, "response"},
+		{-1, -1, -1, -1, (Odr_fun) 0, 0}
+	};
+	if (!odr_initmember(o, p, sizeof(**p)))
+		return opt && odr_ok(o);
+	if (odr_choice(o, arm, &(*p)->u, &(*p)->which, name))
+		return 1;
+	*p = 0;
+	return opt && odr_ok(o);
+}
+
+int z_DRNType (ODR o, Z_DRNType **p, int opt, const char *name)
+{
+	if (!odr_sequence_begin (o, p, sizeof(**p), name))
+		return opt && odr_ok (o);
+	return
+		odr_implicit_tag (o, odr_octetstring,
+			&(*p)->userId, ODR_CONTEXT, 1, 1, "userId") &&
+		odr_implicit_tag (o, odr_octetstring,
+			&(*p)->salt, ODR_CONTEXT, 2, 1, "salt") &&
+		odr_implicit_tag (o, odr_octetstring,
+			&(*p)->randomNumber, ODR_CONTEXT, 3, 0, "randomNumber") &&
+		odr_sequence_end (o);
+}
Index: /main/tags/2.25/gsdl/packages/yaz/z39.50/z-accform1.c
===================================================================
--- /main/tags/2.25/gsdl/packages/yaz/z39.50/z-accform1.c	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/yaz/z39.50/z-accform1.c	(revision 21064)
@@ -0,0 +1,147 @@
+/* Generated automatically by the YAZ ASN.1 Compiler 0.3 */
+/* Module-C: AccessControlFormat-prompt-1 */
+
+#include <yaz/z-accform1.h>
+
+int z_PromptObject1 (ODR o, Z_PromptObject1 **p, int opt, const char *name)
+{
+	static Odr_arm arm[] = {
+		{ODR_IMPLICIT, ODR_CONTEXT, 1, Z_PromptObject1_challenge,
+		(Odr_fun) z_Challenge1, "challenge"},
+		{ODR_IMPLICIT, ODR_CONTEXT, 2, Z_PromptObject1_response,
+		(Odr_fun) z_Response1, "response"},
+		{-1, -1, -1, -1, (Odr_fun) 0, 0}
+	};
+	if (!odr_initmember(o, p, sizeof(**p)))
+		return opt && odr_ok(o);
+	if (odr_choice(o, arm, &(*p)->u, &(*p)->which, name))
+		return 1;
+	*p = 0;
+	return opt && odr_ok(o);
+}
+
+int z_ChallengeUnit1 (ODR o, Z_ChallengeUnit1 **p, int opt, const char *name)
+{
+	static Odr_arm arm[] = {
+		{ODR_IMPLICIT, ODR_CONTEXT, 1, Z_ChallengeUnit1_character,
+		(Odr_fun) z_InternationalString, "character"},
+		{ODR_IMPLICIT, ODR_CONTEXT, 2, Z_ChallengeUnit1_encrypted,
+		(Odr_fun) z_Encryption, "encrypted"},
+		{-1, -1, -1, -1, (Odr_fun) 0, 0}
+	};
+	if (!odr_sequence_begin (o, p, sizeof(**p), name))
+		return opt && odr_ok (o);
+	return
+		odr_explicit_tag (o, z_PromptId,
+			&(*p)->promptId, ODR_CONTEXT, 1, 0, "promptId") &&
+		odr_implicit_tag (o, z_InternationalString,
+			&(*p)->defaultResponse, ODR_CONTEXT, 2, 1, "defaultResponse") &&
+		((odr_constructed_begin (o, &(*p)->u, ODR_CONTEXT, 3, "promptInfo") &&
+		odr_choice (o, arm, &(*p)->u, &(*p)->which, 0) &&
+		odr_constructed_end (o)) || odr_ok(o)) &&
+		odr_implicit_tag (o, z_InternationalString,
+			&(*p)->regExpr, ODR_CONTEXT, 4, 1, "regExpr") &&
+		odr_implicit_tag (o, odr_null,
+			&(*p)->responseRequired, ODR_CONTEXT, 5, 1, "responseRequired") &&
+		odr_implicit_settag (o, ODR_CONTEXT, 6) &&
+		(odr_sequence_of(o, (Odr_fun) z_InternationalString, &(*p)->allowedValues,
+		  &(*p)->num_allowedValues, "allowedValues") || odr_ok(o)) &&
+		odr_implicit_tag (o, odr_null,
+			&(*p)->shouldSave, ODR_CONTEXT, 7, 1, "shouldSave") &&
+		odr_implicit_tag (o, odr_integer,
+			&(*p)->dataType, ODR_CONTEXT, 8, 1, "dataType") &&
+		odr_implicit_tag (o, z_External,
+			&(*p)->diagnostic, ODR_CONTEXT, 9, 1, "diagnostic") &&
+		odr_sequence_end (o);
+}
+
+int z_Challenge1 (ODR o, Z_Challenge1 **p, int opt, const char *name)
+{
+	if (!odr_initmember (o, p, sizeof(**p)))
+		return opt && odr_ok(o);
+	if (odr_sequence_of (o, (Odr_fun) z_ChallengeUnit1, &(*p)->elements,
+		&(*p)->num, name))
+		return 1;
+	*p = 0;
+	return opt && odr_ok(o);
+}
+
+int z_ResponseUnit1 (ODR o, Z_ResponseUnit1 **p, int opt, const char *name)
+{
+	static Odr_arm arm[] = {
+		{ODR_IMPLICIT, ODR_CONTEXT, 1, Z_ResponseUnit1_string,
+		(Odr_fun) z_InternationalString, "string"},
+		{ODR_IMPLICIT, ODR_CONTEXT, 2, Z_ResponseUnit1_accept,
+		(Odr_fun) odr_bool, "accept"},
+		{ODR_IMPLICIT, ODR_CONTEXT, 3, Z_ResponseUnit1_acknowledge,
+		(Odr_fun) odr_null, "acknowledge"},
+		{ODR_EXPLICIT, ODR_CONTEXT, 4, Z_ResponseUnit1_diagnostic,
+		(Odr_fun) z_DiagRec, "diagnostic"},
+		{ODR_IMPLICIT, ODR_CONTEXT, 5, Z_ResponseUnit1_encrypted,
+		(Odr_fun) z_Encryption, "encrypted"},
+		{-1, -1, -1, -1, (Odr_fun) 0, 0}
+	};
+	if (!odr_sequence_begin (o, p, sizeof(**p), name))
+		return opt && odr_ok (o);
+	return
+		odr_explicit_tag (o, z_PromptId,
+			&(*p)->promptId, ODR_CONTEXT, 1, 0, "promptId") &&
+		odr_constructed_begin (o, &(*p)->u, ODR_CONTEXT, 2, "promptResponse") &&
+		odr_choice (o, arm, &(*p)->u, &(*p)->which, 0) &&
+		odr_constructed_end (o) &&
+		odr_sequence_end (o);
+}
+
+int z_Response1 (ODR o, Z_Response1 **p, int opt, const char *name)
+{
+	if (!odr_initmember (o, p, sizeof(**p)))
+		return opt && odr_ok(o);
+	if (odr_sequence_of (o, (Odr_fun) z_ResponseUnit1, &(*p)->elements,
+		&(*p)->num, name))
+		return 1;
+	*p = 0;
+	return opt && odr_ok(o);
+}
+
+int z_PromptIdEnumeratedPrompt (ODR o, Z_PromptIdEnumeratedPrompt **p, int opt, const char *name)
+{
+	if (!odr_sequence_begin (o, p, sizeof(**p), name))
+		return opt && odr_ok (o);
+	return
+		odr_implicit_tag (o, odr_integer,
+			&(*p)->type, ODR_CONTEXT, 1, 0, "type") &&
+		odr_implicit_tag (o, z_InternationalString,
+			&(*p)->suggestedString, ODR_CONTEXT, 2, 1, "suggestedString") &&
+		odr_sequence_end (o);
+}
+
+int z_PromptId (ODR o, Z_PromptId **p, int opt, const char *name)
+{
+	static Odr_arm arm[] = {
+		{ODR_IMPLICIT, ODR_CONTEXT, 1, Z_PromptId_enumeratedPrompt,
+		(Odr_fun) z_PromptIdEnumeratedPrompt, "enumeratedPrompt"},
+		{ODR_IMPLICIT, ODR_CONTEXT, 2, Z_PromptId_nonEnumeratedPrompt,
+		(Odr_fun) z_InternationalString, "nonEnumeratedPrompt"},
+		{-1, -1, -1, -1, (Odr_fun) 0, 0}
+	};
+	if (!odr_initmember(o, p, sizeof(**p)))
+		return opt && odr_ok(o);
+	if (odr_choice(o, arm, &(*p)->u, &(*p)->which, name))
+		return 1;
+	*p = 0;
+	return opt && odr_ok(o);
+}
+
+int z_Encryption (ODR o, Z_Encryption **p, int opt, const char *name)
+{
+	if (!odr_sequence_begin (o, p, sizeof(**p), name))
+		return opt && odr_ok (o);
+	return
+		odr_implicit_tag (o, odr_octetstring,
+			&(*p)->cryptType, ODR_CONTEXT, 1, 1, "cryptType") &&
+		odr_implicit_tag (o, odr_octetstring,
+			&(*p)->credential, ODR_CONTEXT, 2, 1, "credential") &&
+		odr_implicit_tag (o, odr_octetstring,
+			&(*p)->data, ODR_CONTEXT, 3, 0, "data") &&
+		odr_sequence_end (o);
+}
Index: /main/tags/2.25/gsdl/packages/yaz/z39.50/z-acckrb1.c
===================================================================
--- /main/tags/2.25/gsdl/packages/yaz/z39.50/z-acckrb1.c	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/yaz/z39.50/z-acckrb1.c	(revision 21064)
@@ -0,0 +1,47 @@
+/* Generated automatically by the YAZ ASN.1 Compiler 0.3 */
+/* Module-C: AccessControlFormat-krb-1 */
+
+#include <yaz/z-acckrb1.h>
+
+int z_KRBObject (ODR o, Z_KRBObject **p, int opt, const char *name)
+{
+	static Odr_arm arm[] = {
+		{ODR_IMPLICIT, ODR_CONTEXT, 1, Z_KRBObject_challenge,
+		(Odr_fun) z_KRBRequest, "challenge"},
+		{ODR_IMPLICIT, ODR_CONTEXT, 2, Z_KRBObject_response,
+		(Odr_fun) z_KRBResponse, "response"},
+		{-1, -1, -1, -1, (Odr_fun) 0, 0}
+	};
+	if (!odr_initmember(o, p, sizeof(**p)))
+		return opt && odr_ok(o);
+	if (odr_choice(o, arm, &(*p)->u, &(*p)->which, name))
+		return 1;
+	*p = 0;
+	return opt && odr_ok(o);
+}
+
+int z_KRBRequest (ODR o, Z_KRBRequest **p, int opt, const char *name)
+{
+	if (!odr_sequence_begin (o, p, sizeof(**p), name))
+		return opt && odr_ok (o);
+	return
+		odr_implicit_tag (o, z_InternationalString,
+			&(*p)->service, ODR_CONTEXT, 1, 0, "service") &&
+		odr_implicit_tag (o, z_InternationalString,
+			&(*p)->instance, ODR_CONTEXT, 2, 1, "instance") &&
+		odr_implicit_tag (o, z_InternationalString,
+			&(*p)->realm, ODR_CONTEXT, 3, 1, "realm") &&
+		odr_sequence_end (o);
+}
+
+int z_KRBResponse (ODR o, Z_KRBResponse **p, int opt, const char *name)
+{
+	if (!odr_sequence_begin (o, p, sizeof(**p), name))
+		return opt && odr_ok (o);
+	return
+		odr_implicit_tag (o, z_InternationalString,
+			&(*p)->userid, ODR_CONTEXT, 1, 1, "userid") &&
+		odr_implicit_tag (o, odr_octetstring,
+			&(*p)->ticket, ODR_CONTEXT, 2, 0, "ticket") &&
+		odr_sequence_end (o);
+}
Index: /main/tags/2.25/gsdl/packages/yaz/z39.50/z-core.c
===================================================================
--- /main/tags/2.25/gsdl/packages/yaz/z39.50/z-core.c	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/yaz/z39.50/z-core.c	(revision 21064)
@@ -0,0 +1,1453 @@
+/* Generated automatically by the YAZ ASN.1 Compiler 0.3 */
+/* Module-C: Z39-50-APDU-1995 */
+
+#include <yaz/z-core.h>
+
+int z_APDU (ODR o, Z_APDU **p, int opt, const char *name)
+{
+	static Odr_arm arm[] = {
+		{ODR_IMPLICIT, ODR_CONTEXT, 20, Z_APDU_initRequest,
+		(Odr_fun) z_InitRequest, "initRequest"},
+		{ODR_IMPLICIT, ODR_CONTEXT, 21, Z_APDU_initResponse,
+		(Odr_fun) z_InitResponse, "initResponse"},
+		{ODR_IMPLICIT, ODR_CONTEXT, 22, Z_APDU_searchRequest,
+		(Odr_fun) z_SearchRequest, "searchRequest"},
+		{ODR_IMPLICIT, ODR_CONTEXT, 23, Z_APDU_searchResponse,
+		(Odr_fun) z_SearchResponse, "searchResponse"},
+		{ODR_IMPLICIT, ODR_CONTEXT, 24, Z_APDU_presentRequest,
+		(Odr_fun) z_PresentRequest, "presentRequest"},
+		{ODR_IMPLICIT, ODR_CONTEXT, 25, Z_APDU_presentResponse,
+		(Odr_fun) z_PresentResponse, "presentResponse"},
+		{ODR_IMPLICIT, ODR_CONTEXT, 26, Z_APDU_deleteResultSetRequest,
+		(Odr_fun) z_DeleteResultSetRequest, "deleteResultSetRequest"},
+		{ODR_IMPLICIT, ODR_CONTEXT, 27, Z_APDU_deleteResultSetResponse,
+		(Odr_fun) z_DeleteResultSetResponse, "deleteResultSetResponse"},
+		{ODR_IMPLICIT, ODR_CONTEXT, 28, Z_APDU_accessControlRequest,
+		(Odr_fun) z_AccessControlRequest, "accessControlRequest"},
+		{ODR_IMPLICIT, ODR_CONTEXT, 29, Z_APDU_accessControlResponse,
+		(Odr_fun) z_AccessControlResponse, "accessControlResponse"},
+		{ODR_IMPLICIT, ODR_CONTEXT, 30, Z_APDU_resourceControlRequest,
+		(Odr_fun) z_ResourceControlRequest, "resourceControlRequest"},
+		{ODR_IMPLICIT, ODR_CONTEXT, 31, Z_APDU_resourceControlResponse,
+		(Odr_fun) z_ResourceControlResponse, "resourceControlResponse"},
+		{ODR_IMPLICIT, ODR_CONTEXT, 32, Z_APDU_triggerResourceControlRequest,
+		(Odr_fun) z_TriggerResourceControlRequest, "triggerResourceControlRequest"},
+		{ODR_IMPLICIT, ODR_CONTEXT, 33, Z_APDU_resourceReportRequest,
+		(Odr_fun) z_ResourceReportRequest, "resourceReportRequest"},
+		{ODR_IMPLICIT, ODR_CONTEXT, 34, Z_APDU_resourceReportResponse,
+		(Odr_fun) z_ResourceReportResponse, "resourceReportResponse"},
+		{ODR_IMPLICIT, ODR_CONTEXT, 35, Z_APDU_scanRequest,
+		(Odr_fun) z_ScanRequest, "scanRequest"},
+		{ODR_IMPLICIT, ODR_CONTEXT, 36, Z_APDU_scanResponse,
+		(Odr_fun) z_ScanResponse, "scanResponse"},
+		{ODR_IMPLICIT, ODR_CONTEXT, 43, Z_APDU_sortRequest,
+		(Odr_fun) z_SortRequest, "sortRequest"},
+		{ODR_IMPLICIT, ODR_CONTEXT, 44, Z_APDU_sortResponse,
+		(Odr_fun) z_SortResponse, "sortResponse"},
+		{ODR_IMPLICIT, ODR_CONTEXT, 45, Z_APDU_segmentRequest,
+		(Odr_fun) z_Segment, "segmentRequest"},
+		{ODR_IMPLICIT, ODR_CONTEXT, 46, Z_APDU_extendedServicesRequest,
+		(Odr_fun) z_ExtendedServicesRequest, "extendedServicesRequest"},
+		{ODR_IMPLICIT, ODR_CONTEXT, 47, Z_APDU_extendedServicesResponse,
+		(Odr_fun) z_ExtendedServicesResponse, "extendedServicesResponse"},
+		{ODR_IMPLICIT, ODR_CONTEXT, 48, Z_APDU_close,
+		(Odr_fun) z_Close, "close"},
+		{-1, -1, -1, -1, (Odr_fun) 0, 0}
+	};
+	if (!odr_initmember(o, p, sizeof(**p)))
+		return opt && odr_ok(o);
+	if (odr_choice(o, arm, &(*p)->u, &(*p)->which, name))
+		return 1;
+	*p = 0;
+	return opt && odr_ok(o);
+}
+
+int z_InitRequest (ODR o, Z_InitRequest **p, int opt, const char *name)
+{
+	if (!odr_sequence_begin (o, p, sizeof(**p), name))
+		return opt && odr_ok (o);
+	return
+		z_ReferenceId(o, &(*p)->referenceId, 1, "referenceId") &&
+		z_ProtocolVersion(o, &(*p)->protocolVersion, 0, "protocolVersion") &&
+		z_Options(o, &(*p)->options, 0, "options") &&
+		odr_implicit_tag (o, odr_integer,
+			&(*p)->preferredMessageSize, ODR_CONTEXT, 5, 0, "preferredMessageSize") &&
+		odr_implicit_tag (o, odr_integer,
+			&(*p)->maximumRecordSize, ODR_CONTEXT, 6, 0, "maximumRecordSize") &&
+		odr_explicit_tag (o, z_IdAuthentication,
+			&(*p)->idAuthentication, ODR_CONTEXT, 7, 1, "idAuthentication") &&
+		odr_implicit_tag (o, z_InternationalString,
+			&(*p)->implementationId, ODR_CONTEXT, 110, 1, "implementationId") &&
+		odr_implicit_tag (o, z_InternationalString,
+			&(*p)->implementationName, ODR_CONTEXT, 111, 1, "implementationName") &&
+		odr_implicit_tag (o, z_InternationalString,
+			&(*p)->implementationVersion, ODR_CONTEXT, 112, 1, "implementationVersion") &&
+		odr_explicit_tag (o, z_External,
+			&(*p)->userInformationField, ODR_CONTEXT, 11, 1, "userInformationField") &&
+		z_OtherInformation(o, &(*p)->otherInfo, 1, "otherInfo") &&
+		odr_sequence_end (o);
+}
+
+int z_IdPass (ODR o, Z_IdPass **p, int opt, const char *name)
+{
+	if (!odr_sequence_begin (o, p, sizeof(**p), name))
+		return opt && odr_ok (o);
+	return
+		odr_implicit_tag (o, z_InternationalString,
+			&(*p)->groupId, ODR_CONTEXT, 0, 1, "groupId") &&
+		odr_implicit_tag (o, z_InternationalString,
+			&(*p)->userId, ODR_CONTEXT, 1, 1, "userId") &&
+		odr_implicit_tag (o, z_InternationalString,
+			&(*p)->password, ODR_CONTEXT, 2, 1, "password") &&
+		odr_sequence_end (o);
+}
+
+int z_IdAuthentication (ODR o, Z_IdAuthentication **p, int opt, const char *name)
+{
+	static Odr_arm arm[] = {
+		{-1, -1, -1, Z_IdAuthentication_open,
+		 (Odr_fun) odr_visiblestring, "open"},
+		{-1, -1, -1, Z_IdAuthentication_idPass,
+		 (Odr_fun) z_IdPass, "idPass"},
+		{-1, -1, -1, Z_IdAuthentication_anonymous,
+		 (Odr_fun) odr_null, "anonymous"},
+		{-1, -1, -1, Z_IdAuthentication_other,
+		 (Odr_fun) z_External, "other"},
+		{-1, -1, -1, -1, (Odr_fun) 0, 0}
+	};
+	if (!odr_initmember(o, p, sizeof(**p)))
+		return opt && odr_ok(o);
+	if (odr_choice(o, arm, &(*p)->u, &(*p)->which, name))
+		return 1;
+	*p = 0;
+	return opt && odr_ok(o);
+}
+
+int z_InitResponse (ODR o, Z_InitResponse **p, int opt, const char *name)
+{
+	if (!odr_sequence_begin (o, p, sizeof(**p), name))
+		return opt && odr_ok (o);
+	return
+		z_ReferenceId(o, &(*p)->referenceId, 1, "referenceId") &&
+		z_ProtocolVersion(o, &(*p)->protocolVersion, 0, "protocolVersion") &&
+		z_Options(o, &(*p)->options, 0, "options") &&
+		odr_implicit_tag (o, odr_integer,
+			&(*p)->preferredMessageSize, ODR_CONTEXT, 5, 0, "preferredMessageSize") &&
+		odr_implicit_tag (o, odr_integer,
+			&(*p)->maximumRecordSize, ODR_CONTEXT, 6, 0, "maximumRecordSize") &&
+		odr_implicit_tag (o, odr_bool,
+			&(*p)->result, ODR_CONTEXT, 12, 0, "result") &&
+		odr_implicit_tag (o, z_InternationalString,
+			&(*p)->implementationId, ODR_CONTEXT, 110, 1, "implementationId") &&
+		odr_implicit_tag (o, z_InternationalString,
+			&(*p)->implementationName, ODR_CONTEXT, 111, 1, "implementationName") &&
+		odr_implicit_tag (o, z_InternationalString,
+			&(*p)->implementationVersion, ODR_CONTEXT, 112, 1, "implementationVersion") &&
+		odr_explicit_tag (o, z_External,
+			&(*p)->userInformationField, ODR_CONTEXT, 11, 1, "userInformationField") &&
+		z_OtherInformation(o, &(*p)->otherInfo, 1, "otherInfo") &&
+		odr_sequence_end (o);
+}
+
+int z_ProtocolVersion (ODR o, Z_ProtocolVersion **p, int opt, const char *name)
+{
+	return odr_implicit_tag (o, odr_bitstring, p, ODR_CONTEXT, 3, opt, name);
+}
+
+int z_Options (ODR o, Z_Options **p, int opt, const char *name)
+{
+	return odr_implicit_tag (o, odr_bitstring, p, ODR_CONTEXT, 4, opt, name);
+}
+
+int z_SearchRequest (ODR o, Z_SearchRequest **p, int opt, const char *name)
+{
+	if (!odr_sequence_begin (o, p, sizeof(**p), name))
+		return opt && odr_ok (o);
+	return
+		z_ReferenceId(o, &(*p)->referenceId, 1, "referenceId") &&
+		odr_implicit_tag (o, odr_integer,
+			&(*p)->smallSetUpperBound, ODR_CONTEXT, 13, 0, "smallSetUpperBound") &&
+		odr_implicit_tag (o, odr_integer,
+			&(*p)->largeSetLowerBound, ODR_CONTEXT, 14, 0, "largeSetLowerBound") &&
+		odr_implicit_tag (o, odr_integer,
+			&(*p)->mediumSetPresentNumber, ODR_CONTEXT, 15, 0, "mediumSetPresentNumber") &&
+		odr_implicit_tag (o, odr_bool,
+			&(*p)->replaceIndicator, ODR_CONTEXT, 16, 0, "replaceIndicator") &&
+		odr_implicit_tag (o, z_InternationalString,
+			&(*p)->resultSetName, ODR_CONTEXT, 17, 0, "resultSetName") &&
+		odr_implicit_settag (o, ODR_CONTEXT, 18) &&
+		odr_sequence_of(o, (Odr_fun) z_DatabaseName, &(*p)->databaseNames,
+		  &(*p)->num_databaseNames, "databaseNames") &&
+		odr_explicit_tag (o, z_ElementSetNames,
+			&(*p)->smallSetElementSetNames, ODR_CONTEXT, 100, 1, "smallSetElementSetNames") &&
+		odr_explicit_tag (o, z_ElementSetNames,
+			&(*p)->mediumSetElementSetNames, ODR_CONTEXT, 101, 1, "mediumSetElementSetNames") &&
+		odr_implicit_tag (o, odr_oid,
+			&(*p)->preferredRecordSyntax, ODR_CONTEXT, 104, 1, "preferredRecordSyntax") &&
+		odr_explicit_tag (o, z_Query,
+			&(*p)->query, ODR_CONTEXT, 21, 0, "query") &&
+		odr_implicit_tag (o, z_OtherInformation,
+			&(*p)->additionalSearchInfo, ODR_CONTEXT, 203, 1, "additionalSearchInfo") &&
+		z_OtherInformation(o, &(*p)->otherInfo, 1, "otherInfo") &&
+		odr_sequence_end (o);
+}
+
+int z_Query (ODR o, Z_Query **p, int opt, const char *name)
+{
+	static Odr_arm arm[] = {
+		{ODR_EXPLICIT, ODR_CONTEXT, 0, Z_Query_type_0,
+		(Odr_fun) z_ANY_type_0, "type_0"},
+		{ODR_IMPLICIT, ODR_CONTEXT, 1, Z_Query_type_1,
+		(Odr_fun) z_RPNQuery, "type_1"},
+		{ODR_EXPLICIT, ODR_CONTEXT, 2, Z_Query_type_2,
+		(Odr_fun) odr_octetstring, "type_2"},
+		{ODR_EXPLICIT, ODR_CONTEXT, 100, Z_Query_type_100,
+		(Odr_fun) odr_octetstring, "type_100"},
+		{ODR_IMPLICIT, ODR_CONTEXT, 101, Z_Query_type_101,
+		(Odr_fun) z_RPNQuery, "type_101"},
+		{ODR_EXPLICIT, ODR_CONTEXT, 102, Z_Query_type_102,
+		(Odr_fun) odr_octetstring, "type_102"},
+		{-1, -1, -1, -1, (Odr_fun) 0, 0}
+	};
+	if (!odr_initmember(o, p, sizeof(**p)))
+		return opt && odr_ok(o);
+	if (odr_choice(o, arm, &(*p)->u, &(*p)->which, name))
+		return 1;
+	*p = 0;
+	return opt && odr_ok(o);
+}
+
+int z_RPNQuery (ODR o, Z_RPNQuery **p, int opt, const char *name)
+{
+	if (!odr_sequence_begin (o, p, sizeof(**p), name))
+		return opt && odr_ok (o);
+	return
+		z_AttributeSetId(o, &(*p)->attributeSetId, 0, "attributeSetId") &&
+		z_RPNStructure(o, &(*p)->RPNStructure, 0, "RPNStructure") &&
+		odr_sequence_end (o);
+}
+
+int z_Complex (ODR o, Z_Complex **p, int opt, const char *name)
+{
+	if (!odr_sequence_begin (o, p, sizeof(**p), name))
+		return opt && odr_ok (o);
+	return
+		z_RPNStructure(o, &(*p)->s1, 0, "s1") &&
+		z_RPNStructure(o, &(*p)->s2, 0, "s2") &&
+		z_Operator(o, &(*p)->roperator, 0, "roperator") &&
+		odr_sequence_end (o);
+}
+
+int z_RPNStructure (ODR o, Z_RPNStructure **p, int opt, const char *name)
+{
+	static Odr_arm arm[] = {
+		{ODR_EXPLICIT, ODR_CONTEXT, 0, Z_RPNStructure_simple,
+		(Odr_fun) z_Operand, "simple"},
+		{ODR_IMPLICIT, ODR_CONTEXT, 1, Z_RPNStructure_complex,
+		(Odr_fun) z_Complex, "complex"},
+		{-1, -1, -1, -1, (Odr_fun) 0, 0}
+	};
+	if (!odr_initmember(o, p, sizeof(**p)))
+		return opt && odr_ok(o);
+	if (odr_choice(o, arm, &(*p)->u, &(*p)->which, name))
+		return 1;
+	*p = 0;
+	return opt && odr_ok(o);
+}
+
+int z_Operand (ODR o, Z_Operand **p, int opt, const char *name)
+{
+	static Odr_arm arm[] = {
+		{-1, -1, -1, Z_Operand_APT,
+		 (Odr_fun) z_AttributesPlusTerm, "attributesPlusTerm"},
+		{-1, -1, -1, Z_Operand_resultSetId,
+		 (Odr_fun) z_ResultSetId, "resultSetId"},
+		{-1, -1, -1, Z_Operand_resultAttr,
+		 (Odr_fun) z_ResultSetPlusAttributes, "resultAttr"},
+		{-1, -1, -1, -1, (Odr_fun) 0, 0}
+	};
+	if (!odr_initmember(o, p, sizeof(**p)))
+		return opt && odr_ok(o);
+	if (odr_choice(o, arm, &(*p)->u, &(*p)->which, name))
+		return 1;
+	*p = 0;
+	return opt && odr_ok(o);
+}
+
+int z_AttributesPlusTerm (ODR o, Z_AttributesPlusTerm **p, int opt, const char *name)
+{
+	if (!odr_implicit_settag (o, ODR_CONTEXT, 102) ||
+		!odr_sequence_begin (o, p, sizeof(**p), name))
+		return opt && odr_ok(o);
+	return
+		z_AttributeList(o, &(*p)->attributes, 0, "attributes") &&
+		z_Term(o, &(*p)->term, 0, "term") &&
+		odr_sequence_end (o);
+}
+
+int z_ResultSetPlusAttributes (ODR o, Z_ResultSetPlusAttributes **p, int opt, const char *name)
+{
+	if (!odr_implicit_settag (o, ODR_CONTEXT, 214) ||
+		!odr_sequence_begin (o, p, sizeof(**p), name))
+		return opt && odr_ok(o);
+	return
+		z_ResultSetId(o, &(*p)->resultSet, 0, "resultSet") &&
+		z_AttributeList(o, &(*p)->attributes, 0, "attributes") &&
+		odr_sequence_end (o);
+}
+
+int z_AttributeList (ODR o, Z_AttributeList **p, int opt, const char *name)
+{
+	if (!odr_initmember (o, p, sizeof(**p)))
+		return opt && odr_ok(o);
+	odr_implicit_settag (o, ODR_CONTEXT, 44);
+	if (odr_sequence_of (o, (Odr_fun) z_AttributeElement, &(*p)->attributes,
+		&(*p)->num_attributes, name))
+		return 1;
+	*p = 0;
+	return opt && odr_ok(o);
+}
+
+int z_Term (ODR o, Z_Term **p, int opt, const char *name)
+{
+	static Odr_arm arm[] = {
+		{ODR_IMPLICIT, ODR_CONTEXT, 45, Z_Term_general,
+		(Odr_fun) odr_octetstring, "general"},
+		{ODR_IMPLICIT, ODR_CONTEXT, 215, Z_Term_numeric,
+		(Odr_fun) odr_integer, "numeric"},
+		{ODR_IMPLICIT, ODR_CONTEXT, 216, Z_Term_characterString,
+		(Odr_fun) z_InternationalString, "characterString"},
+		{ODR_IMPLICIT, ODR_CONTEXT, 217, Z_Term_oid,
+		(Odr_fun) odr_oid, "oid"},
+		{ODR_IMPLICIT, ODR_CONTEXT, 218, Z_Term_dateTime,
+		(Odr_fun) odr_generalizedtime, "dateTime"},
+		{ODR_IMPLICIT, ODR_CONTEXT, 219, Z_Term_external,
+		(Odr_fun) z_External, "external"},
+		{ODR_IMPLICIT, ODR_CONTEXT, 220, Z_Term_integerAndUnit,
+		(Odr_fun) z_IntUnit, "integerAndUnit"},
+		{ODR_IMPLICIT, ODR_CONTEXT, 221, Z_Term_null,
+		(Odr_fun) odr_null, "null"},
+		{-1, -1, -1, -1, (Odr_fun) 0, 0}
+	};
+	if (!odr_initmember(o, p, sizeof(**p)))
+		return opt && odr_ok(o);
+	if (odr_choice(o, arm, &(*p)->u, &(*p)->which, name))
+		return 1;
+	*p = 0;
+	return opt && odr_ok(o);
+}
+
+int z_Operator (ODR o, Z_Operator **p, int opt, const char *name)
+{
+	static Odr_arm arm[] = {
+		{ODR_IMPLICIT, ODR_CONTEXT, 0, Z_Operator_and,
+		(Odr_fun) odr_null, "and"},
+		{ODR_IMPLICIT, ODR_CONTEXT, 1, Z_Operator_or,
+		(Odr_fun) odr_null, "or"},
+		{ODR_IMPLICIT, ODR_CONTEXT, 2, Z_Operator_and_not,
+		(Odr_fun) odr_null, "and_not"},
+		{ODR_IMPLICIT, ODR_CONTEXT, 3, Z_Operator_prox,
+		(Odr_fun) z_ProximityOperator, "prox"},
+		{-1, -1, -1, -1, (Odr_fun) 0, 0}
+	};
+	if (!*p && o->direction != ODR_DECODE)
+		return opt;
+	if (!odr_constructed_begin(o, p, ODR_CONTEXT, 46, 0))
+		return opt && odr_ok(o);
+	if (!odr_initmember(o, p, sizeof(**p)))
+		return opt && odr_ok(o);
+	if (odr_choice(o, arm, &(*p)->u, &(*p)->which, name) &&
+		odr_constructed_end(o))
+		return 1;
+	*p = 0;
+	return opt && odr_ok(o);
+}
+
+int z_ComplexAttribute (ODR o, Z_ComplexAttribute **p, int opt, const char *name)
+{
+	if (!odr_sequence_begin (o, p, sizeof(**p), name))
+		return opt && odr_ok (o);
+	return
+		odr_implicit_settag (o, ODR_CONTEXT, 1) &&
+		odr_sequence_of(o, (Odr_fun) z_StringOrNumeric, &(*p)->list,
+		  &(*p)->num_list, "list") &&
+		odr_implicit_settag (o, ODR_CONTEXT, 2) &&
+		(odr_sequence_of(o, (Odr_fun) odr_integer, &(*p)->semanticAction,
+		  &(*p)->num_semanticAction, "semanticAction") || odr_ok(o)) &&
+		odr_sequence_end (o);
+}
+
+int z_AttributeElement (ODR o, Z_AttributeElement **p, int opt, const char *name)
+{
+	static Odr_arm arm[] = {
+		{ODR_IMPLICIT, ODR_CONTEXT, 121, Z_AttributeValue_numeric,
+		(Odr_fun) odr_integer, "numeric"},
+		{ODR_IMPLICIT, ODR_CONTEXT, 224, Z_AttributeValue_complex,
+		(Odr_fun) z_ComplexAttribute, "complex"},
+		{-1, -1, -1, -1, (Odr_fun) 0, 0}
+	};
+	if (!odr_sequence_begin (o, p, sizeof(**p), name))
+		return opt && odr_ok (o);
+	return
+		odr_implicit_tag (o, z_AttributeSetId,
+			&(*p)->attributeSet, ODR_CONTEXT, 1, 1, "attributeSet") &&
+		odr_implicit_tag (o, odr_integer,
+			&(*p)->attributeType, ODR_CONTEXT, 120, 0, "attributeType") &&
+		odr_choice (o, arm, &(*p)->value, &(*p)->which, 0) &&
+		odr_sequence_end (o);
+}
+
+int z_ProximityOperator (ODR o, Z_ProximityOperator **p, int opt, const char *name)
+{
+	static Odr_arm arm[] = {
+		{ODR_IMPLICIT, ODR_CONTEXT, 1, Z_ProximityOperator_known,
+		(Odr_fun) z_ProxUnit, "known"},
+		{ODR_IMPLICIT, ODR_CONTEXT, 2, Z_ProximityOperator_private,
+		(Odr_fun) odr_integer, "zprivate"},
+		{-1, -1, -1, -1, (Odr_fun) 0, 0}
+	};
+	if (!odr_sequence_begin (o, p, sizeof(**p), name))
+		return opt && odr_ok (o);
+	return
+		odr_implicit_tag (o, odr_bool,
+			&(*p)->exclusion, ODR_CONTEXT, 1, 1, "exclusion") &&
+		odr_implicit_tag (o, odr_integer,
+			&(*p)->distance, ODR_CONTEXT, 2, 0, "distance") &&
+		odr_implicit_tag (o, odr_bool,
+			&(*p)->ordered, ODR_CONTEXT, 3, 0, "ordered") &&
+		odr_implicit_tag (o, odr_integer,
+			&(*p)->relationType, ODR_CONTEXT, 4, 0, "relationType") &&
+		odr_constructed_begin (o, &(*p)->u, ODR_CONTEXT, 5, "proximityUnitCode") &&
+		odr_choice (o, arm, &(*p)->u, &(*p)->which, 0) &&
+		odr_constructed_end (o) &&
+		odr_sequence_end (o);
+}
+
+int z_ProxUnit (ODR o, Z_ProxUnit **p, int opt, const char *name)
+{
+	return odr_integer (o, p, opt, name);
+}
+
+int z_SearchResponse (ODR o, Z_SearchResponse **p, int opt, const char *name)
+{
+	if (!odr_sequence_begin (o, p, sizeof(**p), name))
+		return opt && odr_ok (o);
+	return
+		z_ReferenceId(o, &(*p)->referenceId, 1, "referenceId") &&
+		odr_implicit_tag (o, odr_integer,
+			&(*p)->resultCount, ODR_CONTEXT, 23, 0, "resultCount") &&
+		odr_implicit_tag (o, odr_integer,
+			&(*p)->numberOfRecordsReturned, ODR_CONTEXT, 24, 0, "numberOfRecordsReturned") &&
+		odr_implicit_tag (o, odr_integer,
+			&(*p)->nextResultSetPosition, ODR_CONTEXT, 25, 0, "nextResultSetPosition") &&
+		odr_implicit_tag (o, odr_bool,
+			&(*p)->searchStatus, ODR_CONTEXT, 22, 0, "searchStatus") &&
+		odr_implicit_tag (o, odr_integer,
+			&(*p)->resultSetStatus, ODR_CONTEXT, 26, 1, "resultSetStatus") &&
+		z_PresentStatus(o, &(*p)->presentStatus, 1, "presentStatus") &&
+		z_Records(o, &(*p)->records, 1, "records") &&
+		odr_implicit_tag (o, z_OtherInformation,
+			&(*p)->additionalSearchInfo, ODR_CONTEXT, 203, 1, "additionalSearchInfo") &&
+		z_OtherInformation(o, &(*p)->otherInfo, 1, "otherInfo") &&
+		odr_sequence_end (o);
+}
+
+int z_RecordComposition (ODR o, Z_RecordComposition **p, int opt, const char *name)
+{
+	static Odr_arm arm[] = {
+		{ODR_EXPLICIT, ODR_CONTEXT, 19, Z_RecordComp_simple,
+		(Odr_fun) z_ElementSetNames, "simple"},
+		{ODR_IMPLICIT, ODR_CONTEXT, 209, Z_RecordComp_complex,
+		(Odr_fun) z_CompSpec, "complex"},
+		{-1, -1, -1, -1, (Odr_fun) 0, 0}
+	};
+	if (!odr_initmember(o, p, sizeof(**p)))
+		return opt && odr_ok(o);
+	if (odr_choice(o, arm, &(*p)->u, &(*p)->which, name))
+		return 1;
+	*p = 0;
+	return opt && odr_ok(o);
+}
+
+int z_PresentRequest (ODR o, Z_PresentRequest **p, int opt, const char *name)
+{
+	if (!odr_sequence_begin (o, p, sizeof(**p), name))
+		return opt && odr_ok (o);
+	return
+		z_ReferenceId(o, &(*p)->referenceId, 1, "referenceId") &&
+		z_ResultSetId(o, &(*p)->resultSetId, 0, "resultSetId") &&
+		odr_implicit_tag (o, odr_integer,
+			&(*p)->resultSetStartPoint, ODR_CONTEXT, 30, 0, "resultSetStartPoint") &&
+		odr_implicit_tag (o, odr_integer,
+			&(*p)->numberOfRecordsRequested, ODR_CONTEXT, 29, 0, "numberOfRecordsRequested") &&
+		odr_implicit_settag (o, ODR_CONTEXT, 212) &&
+		(odr_sequence_of(o, (Odr_fun) z_Range, &(*p)->additionalRanges,
+		  &(*p)->num_ranges, "additionalRanges") || odr_ok(o)) &&
+		z_RecordComposition (o, &(*p)->recordComposition, 1, "recordComposition") &&
+		odr_implicit_tag (o, odr_oid,
+			&(*p)->preferredRecordSyntax, ODR_CONTEXT, 104, 1, "preferredRecordSyntax") &&
+		odr_implicit_tag (o, odr_integer,
+			&(*p)->maxSegmentCount, ODR_CONTEXT, 204, 1, "maxSegmentCount") &&
+		odr_implicit_tag (o, odr_integer,
+			&(*p)->maxRecordSize, ODR_CONTEXT, 206, 1, "maxRecordSize") &&
+		odr_implicit_tag (o, odr_integer,
+			&(*p)->maxSegmentSize, ODR_CONTEXT, 207, 1, "maxSegmentSize") &&
+		z_OtherInformation(o, &(*p)->otherInfo, 1, "otherInfo") &&
+		odr_sequence_end (o);
+}
+
+int z_Segment (ODR o, Z_Segment **p, int opt, const char *name)
+{
+	if (!odr_sequence_begin (o, p, sizeof(**p), name))
+		return opt && odr_ok (o);
+	return
+		z_ReferenceId(o, &(*p)->referenceId, 1, "referenceId") &&
+		odr_implicit_tag (o, odr_integer,
+			&(*p)->numberOfRecordsReturned, ODR_CONTEXT, 24, 0, "numberOfRecordsReturned") &&
+		odr_implicit_settag (o, ODR_CONTEXT, 0) &&
+		odr_sequence_of(o, (Odr_fun) z_NamePlusRecord, &(*p)->segmentRecords,
+		  &(*p)->num_segmentRecords, "segmentRecords") &&
+		z_OtherInformation(o, &(*p)->otherInfo, 1, "otherInfo") &&
+		odr_sequence_end (o);
+}
+
+int z_PresentResponse (ODR o, Z_PresentResponse **p, int opt, const char *name)
+{
+	if (!odr_sequence_begin (o, p, sizeof(**p), name))
+		return opt && odr_ok (o);
+	return
+		z_ReferenceId(o, &(*p)->referenceId, 1, "referenceId") &&
+		odr_implicit_tag (o, odr_integer,
+			&(*p)->numberOfRecordsReturned, ODR_CONTEXT, 24, 0, "numberOfRecordsReturned") &&
+		odr_implicit_tag (o, odr_integer,
+			&(*p)->nextResultSetPosition, ODR_CONTEXT, 25, 0, "nextResultSetPosition") &&
+		z_PresentStatus(o, &(*p)->presentStatus, 0, "presentStatus") &&
+		z_Records(o, &(*p)->records, 1, "records") &&
+		z_OtherInformation(o, &(*p)->otherInfo, 1, "otherInfo") &&
+		odr_sequence_end (o);
+}
+
+int z_NamePlusRecordList (ODR o, Z_NamePlusRecordList **p, int opt, const char *name)
+{
+	if (!odr_initmember (o, p, sizeof(**p)))
+		return opt && odr_ok(o);
+	if (odr_sequence_of (o, (Odr_fun) z_NamePlusRecord, &(*p)->records,
+		&(*p)->num_records, name))
+		return 1;
+	*p = 0;
+	return opt && odr_ok(o);
+}
+
+int z_DiagRecs (ODR o, Z_DiagRecs **p, int opt, const char *name)
+{
+	if (!odr_initmember (o, p, sizeof(**p)))
+		return opt && odr_ok(o);
+	if (odr_sequence_of (o, (Odr_fun) z_DiagRec, &(*p)->diagRecs,
+		&(*p)->num_diagRecs, name))
+		return 1;
+	*p = 0;
+	return opt && odr_ok(o);
+}
+
+int z_Records (ODR o, Z_Records **p, int opt, const char *name)
+{
+	static Odr_arm arm[] = {
+		{ODR_IMPLICIT, ODR_CONTEXT, 28, Z_Records_DBOSD,
+		(Odr_fun) z_NamePlusRecordList, "databaseOrSurDiagnostics"},
+		{ODR_IMPLICIT, ODR_CONTEXT, 130, Z_Records_NSD,
+		(Odr_fun) z_DefaultDiagFormat, "nonSurrogateDiagnostic"},
+		{ODR_IMPLICIT, ODR_CONTEXT, 205, Z_Records_multipleNSD,
+		(Odr_fun) z_DiagRecs, "multipleNonSurDiagnostics"},
+		{-1, -1, -1, -1, (Odr_fun) 0, 0}
+	};
+	if (!odr_initmember(o, p, sizeof(**p)))
+		return opt && odr_ok(o);
+	if (odr_choice(o, arm, &(*p)->u, &(*p)->which, name))
+		return 1;
+	*p = 0;
+	return opt && odr_ok(o);
+}
+
+int z_NamePlusRecord (ODR o, Z_NamePlusRecord **p, int opt, const char *name)
+{
+	static Odr_arm arm[] = {
+		{ODR_EXPLICIT, ODR_CONTEXT, 1, Z_NamePlusRecord_databaseRecord,
+		(Odr_fun) z_External, "databaseRecord"},
+		{ODR_EXPLICIT, ODR_CONTEXT, 2, Z_NamePlusRecord_surrogateDiagnostic,
+		(Odr_fun) z_DiagRec, "surrogateDiagnostic"},
+		{ODR_EXPLICIT, ODR_CONTEXT, 3, Z_NamePlusRecord_startingFragment,
+		(Odr_fun) z_FragmentSyntax, "startingFragment"},
+		{ODR_EXPLICIT, ODR_CONTEXT, 4, Z_NamePlusRecord_intermediateFragment,
+		(Odr_fun) z_FragmentSyntax, "intermediateFragment"},
+		{ODR_EXPLICIT, ODR_CONTEXT, 5, Z_NamePlusRecord_finalFragment,
+		(Odr_fun) z_FragmentSyntax, "finalFragment"},
+		{-1, -1, -1, -1, (Odr_fun) 0, 0}
+	};
+	if (!odr_sequence_begin (o, p, sizeof(**p), name))
+		return opt && odr_ok (o);
+	return
+		odr_implicit_tag (o, z_DatabaseName,
+			&(*p)->databaseName, ODR_CONTEXT, 0, 1, "databaseName") &&
+		odr_constructed_begin (o, &(*p)->u, ODR_CONTEXT, 1, "record") &&
+		odr_choice (o, arm, &(*p)->u, &(*p)->which, 0) &&
+		odr_constructed_end (o) &&
+		odr_sequence_end (o);
+}
+
+int z_FragmentSyntax (ODR o, Z_FragmentSyntax **p, int opt, const char *name)
+{
+	static Odr_arm arm[] = {
+		{-1, -1, -1, Z_FragmentSyntax_externallyTagged,
+		 (Odr_fun) z_External, "externallyTagged"},
+		{-1, -1, -1, Z_FragmentSyntax_notExternallyTagged,
+		 (Odr_fun) odr_octetstring, "notExternallyTagged"},
+		{-1, -1, -1, -1, (Odr_fun) 0, 0}
+	};
+	if (!odr_initmember(o, p, sizeof(**p)))
+		return opt && odr_ok(o);
+	if (odr_choice(o, arm, &(*p)->u, &(*p)->which, name))
+		return 1;
+	*p = 0;
+	return opt && odr_ok(o);
+}
+
+int z_DiagRec (ODR o, Z_DiagRec **p, int opt, const char *name)
+{
+	static Odr_arm arm[] = {
+		{-1, -1, -1, Z_DiagRec_defaultFormat,
+		 (Odr_fun) z_DefaultDiagFormat, "defaultFormat"},
+		{-1, -1, -1, Z_DiagRec_externallyDefined,
+		 (Odr_fun) z_External, "externallyDefined"},
+		{-1, -1, -1, -1, (Odr_fun) 0, 0}
+	};
+	if (!odr_initmember(o, p, sizeof(**p)))
+		return opt && odr_ok(o);
+	if (odr_choice(o, arm, &(*p)->u, &(*p)->which, name))
+		return 1;
+	*p = 0;
+	return opt && odr_ok(o);
+}
+
+int z_DefaultDiagFormat (ODR o, Z_DefaultDiagFormat **p, int opt, const char *name)
+{
+	static Odr_arm arm[] = {
+		{-1, -1, -1, Z_DefaultDiagFormat_v2Addinfo,
+		 (Odr_fun) odr_visiblestring, "v2Addinfo"},
+		{-1, -1, -1, Z_DefaultDiagFormat_v3Addinfo,
+		 (Odr_fun) z_InternationalString, "v3Addinfo"},
+		{-1, -1, -1, -1, (Odr_fun) 0, 0}
+	};
+	if (!odr_sequence_begin (o, p, sizeof(**p), name))
+		return opt && odr_ok (o);
+	return
+		odr_oid(o, &(*p)->diagnosticSetId, 0, "diagnosticSetId") &&
+		odr_integer(o, &(*p)->condition, 0, "condition") &&
+		odr_choice (o, arm, &(*p)->u, &(*p)->which, 0) &&
+		odr_sequence_end (o);
+}
+
+int z_Range (ODR o, Z_Range **p, int opt, const char *name)
+{
+	if (!odr_sequence_begin (o, p, sizeof(**p), name))
+		return opt && odr_ok (o);
+	return
+		odr_implicit_tag (o, odr_integer,
+			&(*p)->startingPosition, ODR_CONTEXT, 1, 0, "startingPosition") &&
+		odr_implicit_tag (o, odr_integer,
+			&(*p)->numberOfRecords, ODR_CONTEXT, 2, 0, "numberOfRecords") &&
+		odr_sequence_end (o);
+}
+
+int z_DatabaseSpecificUnit (ODR o, Z_DatabaseSpecificUnit **p, int opt, const char *name)
+{
+	if (!odr_sequence_begin (o, p, sizeof(**p), name))
+		return opt && odr_ok (o);
+	return
+		z_DatabaseName(o, &(*p)->dbName, 0, "dbName") &&
+		z_ElementSetName(o, &(*p)->esn, 0, "esn") &&
+		odr_sequence_end (o);
+}
+
+int z_DatabaseSpecific (ODR o, Z_DatabaseSpecific **p, int opt, const char *name)
+{
+	if (!odr_initmember (o, p, sizeof(**p)))
+		return opt && odr_ok(o);
+	if (odr_sequence_of (o, (Odr_fun) z_DatabaseSpecificUnit, &(*p)->elements,
+		&(*p)->num, name))
+		return 1;
+	*p = 0;
+	return opt && odr_ok(o);
+}
+
+int z_ElementSetNames (ODR o, Z_ElementSetNames **p, int opt, const char *name)
+{
+	static Odr_arm arm[] = {
+		{ODR_IMPLICIT, ODR_CONTEXT, 0, Z_ElementSetNames_generic,
+		(Odr_fun) z_InternationalString, "generic"},
+		{ODR_IMPLICIT, ODR_CONTEXT, 1, Z_ElementSetNames_databaseSpecific,
+		(Odr_fun) z_DatabaseSpecific, "databaseSpecific"},
+		{-1, -1, -1, -1, (Odr_fun) 0, 0}
+	};
+	if (!odr_initmember(o, p, sizeof(**p)))
+		return opt && odr_ok(o);
+	if (odr_choice(o, arm, &(*p)->u, &(*p)->which, name))
+		return 1;
+	*p = 0;
+	return opt && odr_ok(o);
+}
+
+int z_PresentStatus (ODR o, Z_PresentStatus **p, int opt, const char *name)
+{
+	return odr_implicit_tag (o, odr_integer, p, ODR_CONTEXT, 27, opt, name);
+}
+
+int z_DbSpecific (ODR o, Z_DbSpecific **p, int opt, const char *name)
+{
+	if (!odr_sequence_begin (o, p, sizeof(**p), name))
+		return opt && odr_ok (o);
+	return
+		odr_explicit_tag (o, z_DatabaseName,
+			&(*p)->db, ODR_CONTEXT, 1, 0, "db") &&
+		odr_implicit_tag (o, z_Specification,
+			&(*p)->spec, ODR_CONTEXT, 2, 0, "spec") &&
+		odr_sequence_end (o);
+}
+
+int z_CompSpec (ODR o, Z_CompSpec **p, int opt, const char *name)
+{
+	if (!odr_sequence_begin (o, p, sizeof(**p), name))
+		return opt && odr_ok (o);
+	return
+		odr_implicit_tag (o, odr_bool,
+			&(*p)->selectAlternativeSyntax, ODR_CONTEXT, 1, 0, "selectAlternativeSyntax") &&
+		odr_implicit_tag (o, z_Specification,
+			&(*p)->generic, ODR_CONTEXT, 2, 1, "generic") &&
+		odr_implicit_settag (o, ODR_CONTEXT, 3) &&
+		(odr_sequence_of(o, (Odr_fun) z_DbSpecific, &(*p)->dbSpecific,
+		  &(*p)->num_dbSpecific, "dbSpecific") || odr_ok(o)) &&
+		odr_implicit_settag (o, ODR_CONTEXT, 4) &&
+		(odr_sequence_of(o, (Odr_fun) odr_oid, &(*p)->recordSyntax,
+		  &(*p)->num_recordSyntax, "recordSyntax") || odr_ok(o)) &&
+		odr_sequence_end (o);
+}
+
+int z_ElementSpec (ODR o, Z_ElementSpec **p, int opt, const char *name)
+{
+	static Odr_arm arm[] = {
+		{ODR_IMPLICIT, ODR_CONTEXT, 1, Z_ElementSpec_elementSetName,
+		(Odr_fun) z_InternationalString, "elementSetName"},
+		{ODR_IMPLICIT, ODR_CONTEXT, 2, Z_ElementSpec_externalSpec,
+		(Odr_fun) z_External, "externalSpec"},
+		{-1, -1, -1, -1, (Odr_fun) 0, 0}
+	};
+	if (!odr_initmember(o, p, sizeof(**p)))
+		return opt && odr_ok(o);
+	if (odr_choice(o, arm, &(*p)->u, &(*p)->which, name))
+		return 1;
+	*p = 0;
+	return opt && odr_ok(o);
+}
+
+int z_Specification (ODR o, Z_Specification **p, int opt, const char *name)
+{
+	if (!odr_sequence_begin (o, p, sizeof(**p), name))
+		return opt && odr_ok (o);
+	return
+		odr_implicit_tag (o, odr_oid,
+			&(*p)->schema, ODR_CONTEXT, 1, 1, "schema") &&
+		odr_explicit_tag (o, z_ElementSpec,
+			&(*p)->elementSpec, ODR_CONTEXT, 2, 1, "elementSpec") &&
+		odr_sequence_end (o);
+}
+
+int z_DeleteResultSetRequest (ODR o, Z_DeleteResultSetRequest **p, int opt, const char *name)
+{
+	if (!odr_sequence_begin (o, p, sizeof(**p), name))
+		return opt && odr_ok (o);
+	return
+		z_ReferenceId(o, &(*p)->referenceId, 1, "referenceId") &&
+		odr_implicit_tag (o, odr_integer,
+			&(*p)->deleteFunction, ODR_CONTEXT, 32, 0, "deleteFunction") &&
+		(odr_sequence_of(o, (Odr_fun) z_ResultSetId, &(*p)->resultSetList,
+		  &(*p)->num_resultSetList, "resultSetList") || odr_ok(o)) &&
+		z_OtherInformation(o, &(*p)->otherInfo, 1, "otherInfo") &&
+		odr_sequence_end (o);
+}
+
+int z_DeleteResultSetResponse (ODR o, Z_DeleteResultSetResponse **p, int opt, const char *name)
+{
+	if (!odr_sequence_begin (o, p, sizeof(**p), name))
+		return opt && odr_ok (o);
+	return
+		z_ReferenceId(o, &(*p)->referenceId, 1, "referenceId") &&
+		odr_implicit_tag (o, z_DeleteStatus,
+			&(*p)->deleteOperationStatus, ODR_CONTEXT, 0, 0, "deleteOperationStatus") &&
+		odr_implicit_tag (o, z_ListStatuses,
+			&(*p)->deleteListStatuses, ODR_CONTEXT, 1, 1, "deleteListStatuses") &&
+		odr_implicit_tag (o, odr_integer,
+			&(*p)->numberNotDeleted, ODR_CONTEXT, 34, 1, "numberNotDeleted") &&
+		odr_implicit_tag (o, z_ListStatuses,
+			&(*p)->bulkStatuses, ODR_CONTEXT, 35, 1, "bulkStatuses") &&
+		odr_implicit_tag (o, z_InternationalString,
+			&(*p)->deleteMessage, ODR_CONTEXT, 36, 1, "deleteMessage") &&
+		z_OtherInformation(o, &(*p)->otherInfo, 1, "otherInfo") &&
+		odr_sequence_end (o);
+}
+
+int z_ListStatus (ODR o, Z_ListStatus **p, int opt, const char *name)
+{
+	if (!odr_sequence_begin (o, p, sizeof(**p), name))
+		return opt && odr_ok (o);
+	return
+		z_ResultSetId(o, &(*p)->id, 0, "id") &&
+		z_DeleteStatus(o, &(*p)->status, 0, "status") &&
+		odr_sequence_end (o);
+}
+
+int z_ListStatuses (ODR o, Z_ListStatuses **p, int opt, const char *name)
+{
+	if (!odr_initmember (o, p, sizeof(**p)))
+		return opt && odr_ok(o);
+	if (odr_sequence_of (o, (Odr_fun) z_ListStatus, &(*p)->elements,
+		&(*p)->num, name))
+		return 1;
+	*p = 0;
+	return opt && odr_ok(o);
+}
+
+int z_DeleteStatus (ODR o, Z_DeleteStatus **p, int opt, const char *name)
+{
+	return odr_implicit_tag (o, odr_integer, p, ODR_CONTEXT, 33, opt, name);
+}
+
+int z_AccessControlRequest (ODR o, Z_AccessControlRequest **p, int opt, const char *name)
+{
+	static Odr_arm arm[] = {
+		{ODR_IMPLICIT, ODR_CONTEXT, 37, Z_AccessControlRequest_simpleForm,
+		(Odr_fun) odr_octetstring, "simpleForm"},
+		{ODR_EXPLICIT, ODR_CONTEXT, 0, Z_AccessControlRequest_externallyDefined,
+		(Odr_fun) z_External, "externallyDefined"},
+		{-1, -1, -1, -1, (Odr_fun) 0, 0}
+	};
+	if (!odr_sequence_begin (o, p, sizeof(**p), name))
+		return opt && odr_ok (o);
+	return
+		z_ReferenceId(o, &(*p)->referenceId, 1, "referenceId") &&
+		odr_choice (o, arm, &(*p)->u, &(*p)->which, 0) &&
+		z_OtherInformation(o, &(*p)->otherInfo, 1, "otherInfo") &&
+		odr_sequence_end (o);
+}
+
+int z_AccessControlResponse (ODR o, Z_AccessControlResponse **p, int opt, const char *name)
+{
+	static Odr_arm arm[] = {
+		{ODR_IMPLICIT, ODR_CONTEXT, 38, Z_AccessControlResponse_simpleForm,
+		(Odr_fun) odr_octetstring, "simpleForm"},
+		{ODR_EXPLICIT, ODR_CONTEXT, 0, Z_AccessControlResponse_externallyDefined,
+		(Odr_fun) z_External, "externallyDefined"},
+		{-1, -1, -1, -1, (Odr_fun) 0, 0}
+	};
+	if (!odr_sequence_begin (o, p, sizeof(**p), name))
+		return opt && odr_ok (o);
+	return
+		z_ReferenceId(o, &(*p)->referenceId, 1, "referenceId") &&
+		(odr_choice (o, arm, &(*p)->u, &(*p)->which, 0) || odr_ok(o)) &&
+		odr_explicit_tag (o, z_DiagRec,
+			&(*p)->diagnostic, ODR_CONTEXT, 223, 1, "diagnostic") &&
+		z_OtherInformation(o, &(*p)->otherInfo, 1, "otherInfo") &&
+		odr_sequence_end (o);
+}
+
+int z_ResourceControlRequest (ODR o, Z_ResourceControlRequest **p, int opt, const char *name)
+{
+	if (!odr_sequence_begin (o, p, sizeof(**p), name))
+		return opt && odr_ok (o);
+	return
+		z_ReferenceId(o, &(*p)->referenceId, 1, "referenceId") &&
+		odr_implicit_tag (o, odr_bool,
+			&(*p)->suspendedFlag, ODR_CONTEXT, 39, 1, "suspendedFlag") &&
+		odr_explicit_tag (o, z_ResourceReport,
+			&(*p)->resourceReport, ODR_CONTEXT, 40, 1, "resourceReport") &&
+		odr_implicit_tag (o, odr_integer,
+			&(*p)->partialResultsAvailable, ODR_CONTEXT, 41, 1, "partialResultsAvailable") &&
+		odr_implicit_tag (o, odr_bool,
+			&(*p)->responseRequired, ODR_CONTEXT, 42, 0, "responseRequired") &&
+		odr_implicit_tag (o, odr_bool,
+			&(*p)->triggeredRequestFlag, ODR_CONTEXT, 43, 1, "triggeredRequestFlag") &&
+		z_OtherInformation(o, &(*p)->otherInfo, 1, "otherInfo") &&
+		odr_sequence_end (o);
+}
+
+int z_ResourceControlResponse (ODR o, Z_ResourceControlResponse **p, int opt, const char *name)
+{
+	if (!odr_sequence_begin (o, p, sizeof(**p), name))
+		return opt && odr_ok (o);
+	return
+		z_ReferenceId(o, &(*p)->referenceId, 1, "referenceId") &&
+		odr_implicit_tag (o, odr_bool,
+			&(*p)->continueFlag, ODR_CONTEXT, 44, 0, "continueFlag") &&
+		odr_implicit_tag (o, odr_bool,
+			&(*p)->resultSetWanted, ODR_CONTEXT, 45, 1, "resultSetWanted") &&
+		z_OtherInformation(o, &(*p)->otherInfo, 1, "otherInfo") &&
+		odr_sequence_end (o);
+}
+
+int z_TriggerResourceControlRequest (ODR o, Z_TriggerResourceControlRequest **p, int opt, const char *name)
+{
+	if (!odr_sequence_begin (o, p, sizeof(**p), name))
+		return opt && odr_ok (o);
+	return
+		z_ReferenceId(o, &(*p)->referenceId, 1, "referenceId") &&
+		odr_implicit_tag (o, odr_integer,
+			&(*p)->requestedAction, ODR_CONTEXT, 46, 0, "requestedAction") &&
+		odr_implicit_tag (o, z_ResourceReportId,
+			&(*p)->prefResourceReportFormat, ODR_CONTEXT, 47, 1, "prefResourceReportFormat") &&
+		odr_implicit_tag (o, odr_bool,
+			&(*p)->resultSetWanted, ODR_CONTEXT, 48, 1, "resultSetWanted") &&
+		z_OtherInformation(o, &(*p)->otherInfo, 1, "otherInfo") &&
+		odr_sequence_end (o);
+}
+
+int z_ResourceReportRequest (ODR o, Z_ResourceReportRequest **p, int opt, const char *name)
+{
+	if (!odr_sequence_begin (o, p, sizeof(**p), name))
+		return opt && odr_ok (o);
+	return
+		z_ReferenceId(o, &(*p)->referenceId, 1, "referenceId") &&
+		odr_implicit_tag (o, z_ReferenceId,
+			&(*p)->opId, ODR_CONTEXT, 210, 1, "opId") &&
+		odr_implicit_tag (o, z_ResourceReportId,
+			&(*p)->prefResourceReportFormat, ODR_CONTEXT, 49, 1, "prefResourceReportFormat") &&
+		z_OtherInformation(o, &(*p)->otherInfo, 1, "otherInfo") &&
+		odr_sequence_end (o);
+}
+
+int z_ResourceReportResponse (ODR o, Z_ResourceReportResponse **p, int opt, const char *name)
+{
+	if (!odr_sequence_begin (o, p, sizeof(**p), name))
+		return opt && odr_ok (o);
+	return
+		z_ReferenceId(o, &(*p)->referenceId, 1, "referenceId") &&
+		odr_implicit_tag (o, odr_integer,
+			&(*p)->resourceReportStatus, ODR_CONTEXT, 50, 0, "resourceReportStatus") &&
+		odr_explicit_tag (o, z_ResourceReport,
+			&(*p)->resourceReport, ODR_CONTEXT, 51, 1, "resourceReport") &&
+		z_OtherInformation(o, &(*p)->otherInfo, 1, "otherInfo") &&
+		odr_sequence_end (o);
+}
+
+int z_ResourceReport (ODR o, Z_ResourceReport **p, int opt, const char *name)
+{
+	return z_External (o, p, opt, name);
+}
+
+int z_ResourceReportId (ODR o, Z_ResourceReportId **p, int opt, const char *name)
+{
+	return odr_oid (o, p, opt, name);
+}
+
+int z_ScanRequest (ODR o, Z_ScanRequest **p, int opt, const char *name)
+{
+	if (!odr_sequence_begin (o, p, sizeof(**p), name))
+		return opt && odr_ok (o);
+	return
+		z_ReferenceId(o, &(*p)->referenceId, 1, "referenceId") &&
+		odr_implicit_settag (o, ODR_CONTEXT, 3) &&
+		odr_sequence_of(o, (Odr_fun) z_DatabaseName, &(*p)->databaseNames,
+		  &(*p)->num_databaseNames, "databaseNames") &&
+		z_AttributeSetId(o, &(*p)->attributeSet, 1, "attributeSet") &&
+		z_AttributesPlusTerm(o, &(*p)->termListAndStartPoint, 0, "termListAndStartPoint") &&
+		odr_implicit_tag (o, odr_integer,
+			&(*p)->stepSize, ODR_CONTEXT, 5, 1, "stepSize") &&
+		odr_implicit_tag (o, odr_integer,
+			&(*p)->numberOfTermsRequested, ODR_CONTEXT, 6, 0, "numberOfTermsRequested") &&
+		odr_implicit_tag (o, odr_integer,
+			&(*p)->preferredPositionInResponse, ODR_CONTEXT, 7, 1, "preferredPositionInResponse") &&
+		z_OtherInformation(o, &(*p)->otherInfo, 1, "otherInfo") &&
+		odr_sequence_end (o);
+}
+
+int z_ScanResponse (ODR o, Z_ScanResponse **p, int opt, const char *name)
+{
+	if (!odr_sequence_begin (o, p, sizeof(**p), name))
+		return opt && odr_ok (o);
+	return
+		z_ReferenceId(o, &(*p)->referenceId, 1, "referenceId") &&
+		odr_implicit_tag (o, odr_integer,
+			&(*p)->stepSize, ODR_CONTEXT, 3, 1, "stepSize") &&
+		odr_implicit_tag (o, odr_integer,
+			&(*p)->scanStatus, ODR_CONTEXT, 4, 0, "scanStatus") &&
+		odr_implicit_tag (o, odr_integer,
+			&(*p)->numberOfEntriesReturned, ODR_CONTEXT, 5, 0, "numberOfEntriesReturned") &&
+		odr_implicit_tag (o, odr_integer,
+			&(*p)->positionOfTerm, ODR_CONTEXT, 6, 1, "positionOfTerm") &&
+		odr_implicit_tag (o, z_ListEntries,
+			&(*p)->entries, ODR_CONTEXT, 7, 1, "entries") &&
+		odr_implicit_tag (o, z_AttributeSetId,
+			&(*p)->attributeSet, ODR_CONTEXT, 8, 1, "attributeSet") &&
+		z_OtherInformation(o, &(*p)->otherInfo, 1, "otherInfo") &&
+		odr_sequence_end (o);
+}
+
+int z_ListEntries (ODR o, Z_ListEntries **p, int opt, const char *name)
+{
+	if (!odr_sequence_begin (o, p, sizeof(**p), name))
+		return opt && odr_ok (o);
+	return
+		odr_implicit_settag (o, ODR_CONTEXT, 1) &&
+		(odr_sequence_of(o, (Odr_fun) z_Entry, &(*p)->entries,
+		  &(*p)->num_entries, "entries") || odr_ok(o)) &&
+		odr_implicit_settag (o, ODR_CONTEXT, 2) &&
+		(odr_sequence_of(o, (Odr_fun) z_DiagRec, &(*p)->nonsurrogateDiagnostics,
+		  &(*p)->num_nonsurrogateDiagnostics, "nonsurrogateDiagnostics") || odr_ok(o)) &&
+		odr_sequence_end (o);
+}
+
+int z_Entry (ODR o, Z_Entry **p, int opt, const char *name)
+{
+	static Odr_arm arm[] = {
+		{ODR_IMPLICIT, ODR_CONTEXT, 1, Z_Entry_termInfo,
+		(Odr_fun) z_TermInfo, "termInfo"},
+		{ODR_EXPLICIT, ODR_CONTEXT, 2, Z_Entry_surrogateDiagnostic,
+		(Odr_fun) z_DiagRec, "surrogateDiagnostic"},
+		{-1, -1, -1, -1, (Odr_fun) 0, 0}
+	};
+	if (!odr_initmember(o, p, sizeof(**p)))
+		return opt && odr_ok(o);
+	if (odr_choice(o, arm, &(*p)->u, &(*p)->which, name))
+		return 1;
+	*p = 0;
+	return opt && odr_ok(o);
+}
+
+int z_TermInfo (ODR o, Z_TermInfo **p, int opt, const char *name)
+{
+	if (!odr_sequence_begin (o, p, sizeof(**p), name))
+		return opt && odr_ok (o);
+	return
+		z_Term(o, &(*p)->term, 0, "term") &&
+		odr_implicit_tag (o, z_InternationalString,
+			&(*p)->displayTerm, ODR_CONTEXT, 0, 1, "displayTerm") &&
+		z_AttributeList(o, &(*p)->suggestedAttributes, 1, "suggestedAttributes") &&
+		odr_implicit_settag (o, ODR_CONTEXT, 4) &&
+		(odr_sequence_of(o, (Odr_fun) z_AttributesPlusTerm, &(*p)->alternativeTerm,
+		  &(*p)->num_alternativeTerm, "alternativeTerm") || odr_ok(o)) &&
+		odr_implicit_tag (o, odr_integer,
+			&(*p)->globalOccurrences, ODR_CONTEXT, 2, 1, "globalOccurrences") &&
+		odr_implicit_tag (o, z_OccurrenceByAttributes,
+			&(*p)->byAttributes, ODR_CONTEXT, 3, 1, "byAttributes") &&
+		z_OtherInformation(o, &(*p)->otherTermInfo, 1, "otherTermInfo") &&
+		odr_sequence_end (o);
+}
+
+int z_byDatabaseList_s (ODR o, Z_byDatabaseList_s **p, int opt, const char *name)
+{
+	if (!odr_sequence_begin (o, p, sizeof(**p), name))
+		return opt && odr_ok (o);
+	return
+		z_DatabaseName(o, &(*p)->db, 0, "db") &&
+		odr_implicit_tag (o, odr_integer,
+			&(*p)->num, ODR_CONTEXT, 1, 1, "num") &&
+		z_OtherInformation(o, &(*p)->otherDbInfo, 1, "otherDbInfo") &&
+		odr_sequence_end (o);
+}
+
+int z_byDatabaseList (ODR o, Z_byDatabaseList **p, int opt, const char *name)
+{
+	if (!odr_initmember (o, p, sizeof(**p)))
+		return opt && odr_ok(o);
+	if (odr_sequence_of (o, (Odr_fun) z_byDatabaseList_s, &(*p)->elements,
+		&(*p)->num, name))
+		return 1;
+	*p = 0;
+	return opt && odr_ok(o);
+}
+
+int z_OccurrenceByAttributesElem (ODR o, Z_OccurrenceByAttributesElem **p, int opt, const char *name)
+{
+	static Odr_arm arm[] = {
+		{ODR_EXPLICIT, ODR_CONTEXT, 2, Z_OccurrenceByAttributesElem_global,
+		(Odr_fun) odr_integer, "global"},
+		{ODR_IMPLICIT, ODR_CONTEXT, 3, Z_OccurrenceByAttributesElem_byDatabase,
+		(Odr_fun) z_byDatabaseList, "byDatabase"},
+		{-1, -1, -1, -1, (Odr_fun) 0, 0}
+	};
+	if (!odr_sequence_begin (o, p, sizeof(**p), name))
+		return opt && odr_ok (o);
+	return
+		odr_explicit_tag (o, z_AttributeList,
+			&(*p)->attributes, ODR_CONTEXT, 1, 0, "attributes") &&
+		(odr_choice (o, arm, &(*p)->u, &(*p)->which, 0) || odr_ok(o)) &&
+		z_OtherInformation(o, &(*p)->otherOccurInfo, 1, "otherOccurInfo") &&
+		odr_sequence_end (o);
+}
+
+int z_OccurrenceByAttributes (ODR o, Z_OccurrenceByAttributes **p, int opt, const char *name)
+{
+	if (!odr_initmember (o, p, sizeof(**p)))
+		return opt && odr_ok(o);
+	if (odr_sequence_of (o, (Odr_fun) z_OccurrenceByAttributesElem, &(*p)->elements,
+		&(*p)->num, name))
+		return 1;
+	*p = 0;
+	return opt && odr_ok(o);
+}
+
+int z_SortKeySpecList (ODR o, Z_SortKeySpecList **p, int opt, const char *name)
+{
+	if (!odr_initmember (o, p, sizeof(**p)))
+		return opt && odr_ok(o);
+	if (odr_sequence_of (o, (Odr_fun) z_SortKeySpec, &(*p)->specs,
+		&(*p)->num_specs, name))
+		return 1;
+	*p = 0;
+	return opt && odr_ok(o);
+}
+
+int z_SortRequest (ODR o, Z_SortRequest **p, int opt, const char *name)
+{
+	if (!odr_sequence_begin (o, p, sizeof(**p), name))
+		return opt && odr_ok (o);
+	return
+		z_ReferenceId(o, &(*p)->referenceId, 1, "referenceId") &&
+		odr_implicit_settag (o, ODR_CONTEXT, 3) &&
+		odr_sequence_of(o, (Odr_fun) z_InternationalString, &(*p)->inputResultSetNames,
+		  &(*p)->num_inputResultSetNames, "inputResultSetNames") &&
+		odr_implicit_tag (o, z_InternationalString,
+			&(*p)->sortedResultSetName, ODR_CONTEXT, 4, 0, "sortedResultSetName") &&
+		odr_implicit_tag (o, z_SortKeySpecList,
+			&(*p)->sortSequence, ODR_CONTEXT, 5, 0, "sortSequence") &&
+		z_OtherInformation(o, &(*p)->otherInfo, 1, "otherInfo") &&
+		odr_sequence_end (o);
+}
+
+int z_SortResponse (ODR o, Z_SortResponse **p, int opt, const char *name)
+{
+	if (!odr_sequence_begin (o, p, sizeof(**p), name))
+		return opt && odr_ok (o);
+	return
+		z_ReferenceId(o, &(*p)->referenceId, 1, "referenceId") &&
+		odr_implicit_tag (o, odr_integer,
+			&(*p)->sortStatus, ODR_CONTEXT, 3, 0, "sortStatus") &&
+		odr_implicit_tag (o, odr_integer,
+			&(*p)->resultSetStatus, ODR_CONTEXT, 4, 1, "resultSetStatus") &&
+		odr_implicit_settag (o, ODR_CONTEXT, 5) &&
+		(odr_sequence_of(o, (Odr_fun) z_DiagRec, &(*p)->diagnostics,
+		  &(*p)->num_diagnostics, "diagnostics") || odr_ok(o)) &&
+		z_OtherInformation(o, &(*p)->otherInfo, 1, "otherInfo") &&
+		odr_sequence_end (o);
+}
+
+int z_SortKeySpec (ODR o, Z_SortKeySpec **p, int opt, const char *name)
+{
+	static Odr_arm arm[] = {
+		{ODR_IMPLICIT, ODR_CONTEXT, 1, Z_SortKeySpec_abort,
+		(Odr_fun) odr_null, "abort"},
+		{ODR_IMPLICIT, ODR_CONTEXT, 2, Z_SortKeySpec_null,
+		(Odr_fun) odr_null, "null"},
+		{ODR_IMPLICIT, ODR_CONTEXT, 3, Z_SortKeySpec_missingValueData,
+		(Odr_fun) odr_octetstring, "missingValueData"},
+		{-1, -1, -1, -1, (Odr_fun) 0, 0}
+	};
+	if (!odr_sequence_begin (o, p, sizeof(**p), name))
+		return opt && odr_ok (o);
+	return
+		z_SortElement(o, &(*p)->sortElement, 0, "sortElement") &&
+		odr_implicit_tag (o, odr_integer,
+			&(*p)->sortRelation, ODR_CONTEXT, 1, 0, "sortRelation") &&
+		odr_implicit_tag (o, odr_integer,
+			&(*p)->caseSensitivity, ODR_CONTEXT, 2, 0, "caseSensitivity") &&
+		((odr_constructed_begin (o, &(*p)->u, ODR_CONTEXT, 3, "missingValueAction") &&
+		odr_choice (o, arm, &(*p)->u, &(*p)->which, 0) &&
+		odr_constructed_end (o)) || odr_ok(o)) &&
+		odr_sequence_end (o);
+}
+
+int z_SortDbSpecificList_s (ODR o, Z_SortDbSpecificList_s **p, int opt, const char *name)
+{
+	if (!odr_sequence_begin (o, p, sizeof(**p), name))
+		return opt && odr_ok (o);
+	return
+		z_DatabaseName(o, &(*p)->databaseName, 0, "databaseName") &&
+		z_SortKey(o, &(*p)->dbSort, 0, "dbSort") &&
+		odr_sequence_end (o);
+}
+
+int z_SortDbSpecificList (ODR o, Z_SortDbSpecificList **p, int opt, const char *name)
+{
+	if (!odr_initmember (o, p, sizeof(**p)))
+		return opt && odr_ok(o);
+	if (odr_sequence_of (o, (Odr_fun) z_SortDbSpecificList_s, &(*p)->elements,
+		&(*p)->num, name))
+		return 1;
+	*p = 0;
+	return opt && odr_ok(o);
+}
+
+int z_SortElement (ODR o, Z_SortElement **p, int opt, const char *name)
+{
+	static Odr_arm arm[] = {
+		{ODR_EXPLICIT, ODR_CONTEXT, 1, Z_SortElement_generic,
+		(Odr_fun) z_SortKey, "generic"},
+		{ODR_IMPLICIT, ODR_CONTEXT, 2, Z_SortElement_databaseSpecific,
+		(Odr_fun) z_SortDbSpecificList, "databaseSpecific"},
+		{-1, -1, -1, -1, (Odr_fun) 0, 0}
+	};
+	if (!odr_initmember(o, p, sizeof(**p)))
+		return opt && odr_ok(o);
+	if (odr_choice(o, arm, &(*p)->u, &(*p)->which, name))
+		return 1;
+	*p = 0;
+	return opt && odr_ok(o);
+}
+
+int z_SortAttributes (ODR o, Z_SortAttributes **p, int opt, const char *name)
+{
+	if (!odr_sequence_begin (o, p, sizeof(**p), name))
+		return opt && odr_ok (o);
+	return
+		z_AttributeSetId(o, &(*p)->id, 0, "id") &&
+		z_AttributeList(o, &(*p)->list, 0, "list") &&
+		odr_sequence_end (o);
+}
+
+int z_SortKey (ODR o, Z_SortKey **p, int opt, const char *name)
+{
+	static Odr_arm arm[] = {
+		{ODR_IMPLICIT, ODR_CONTEXT, 0, Z_SortKey_sortField,
+		(Odr_fun) z_InternationalString, "sortField"},
+		{ODR_IMPLICIT, ODR_CONTEXT, 1, Z_SortKey_elementSpec,
+		(Odr_fun) z_Specification, "elementSpec"},
+		{ODR_IMPLICIT, ODR_CONTEXT, 2, Z_SortKey_sortAttributes,
+		(Odr_fun) z_SortAttributes, "sortAttributes"},
+		{-1, -1, -1, -1, (Odr_fun) 0, 0}
+	};
+	if (!odr_initmember(o, p, sizeof(**p)))
+		return opt && odr_ok(o);
+	if (odr_choice(o, arm, &(*p)->u, &(*p)->which, name))
+		return 1;
+	*p = 0;
+	return opt && odr_ok(o);
+}
+
+int z_ExtendedServicesRequest (ODR o, Z_ExtendedServicesRequest **p, int opt, const char *name)
+{
+	if (!odr_sequence_begin (o, p, sizeof(**p), name))
+		return opt && odr_ok (o);
+	return
+		z_ReferenceId(o, &(*p)->referenceId, 1, "referenceId") &&
+		odr_implicit_tag (o, odr_integer,
+			&(*p)->function, ODR_CONTEXT, 3, 0, "function") &&
+		odr_implicit_tag (o, odr_oid,
+			&(*p)->packageType, ODR_CONTEXT, 4, 0, "packageType") &&
+		odr_implicit_tag (o, z_InternationalString,
+			&(*p)->packageName, ODR_CONTEXT, 5, 1, "packageName") &&
+		odr_implicit_tag (o, z_InternationalString,
+			&(*p)->userId, ODR_CONTEXT, 6, 1, "userId") &&
+		odr_implicit_tag (o, z_IntUnit,
+			&(*p)->retentionTime, ODR_CONTEXT, 7, 1, "retentionTime") &&
+		odr_implicit_tag (o, z_Permissions,
+			&(*p)->permissions, ODR_CONTEXT, 8, 1, "permissions") &&
+		odr_implicit_tag (o, z_InternationalString,
+			&(*p)->description, ODR_CONTEXT, 9, 1, "description") &&
+		odr_implicit_tag (o, z_External,
+			&(*p)->taskSpecificParameters, ODR_CONTEXT, 10, 1, "taskSpecificParameters") &&
+		odr_implicit_tag (o, odr_integer,
+			&(*p)->waitAction, ODR_CONTEXT, 11, 0, "waitAction") &&
+		z_ElementSetName(o, &(*p)->elements, 1, "elements") &&
+		z_OtherInformation(o, &(*p)->otherInfo, 1, "otherInfo") &&
+		odr_sequence_end (o);
+}
+
+int z_ExtendedServicesResponse (ODR o, Z_ExtendedServicesResponse **p, int opt, const char *name)
+{
+	if (!odr_sequence_begin (o, p, sizeof(**p), name))
+		return opt && odr_ok (o);
+	return
+		z_ReferenceId(o, &(*p)->referenceId, 1, "referenceId") &&
+		odr_implicit_tag (o, odr_integer,
+			&(*p)->operationStatus, ODR_CONTEXT, 3, 0, "operationStatus") &&
+		odr_implicit_settag (o, ODR_CONTEXT, 4) &&
+		(odr_sequence_of(o, (Odr_fun) z_DiagRec, &(*p)->diagnostics,
+		  &(*p)->num_diagnostics, "diagnostics") || odr_ok(o)) &&
+		odr_implicit_tag (o, z_External,
+			&(*p)->taskPackage, ODR_CONTEXT, 5, 1, "taskPackage") &&
+		z_OtherInformation(o, &(*p)->otherInfo, 1, "otherInfo") &&
+		odr_sequence_end (o);
+}
+
+int z_Permissions_s (ODR o, Z_Permissions_s **p, int opt, const char *name)
+{
+	if (!odr_sequence_begin (o, p, sizeof(**p), name))
+		return opt && odr_ok (o);
+	return
+		odr_implicit_tag (o, z_InternationalString,
+			&(*p)->userId, ODR_CONTEXT, 1, 0, "userId") &&
+		odr_implicit_settag (o, ODR_CONTEXT, 2) &&
+		odr_sequence_of(o, (Odr_fun) odr_integer, &(*p)->allowableFunctions,
+		  &(*p)->num_allowableFunctions, "allowableFunctions") &&
+		odr_sequence_end (o);
+}
+
+int z_Permissions (ODR o, Z_Permissions **p, int opt, const char *name)
+{
+	if (!odr_initmember (o, p, sizeof(**p)))
+		return opt && odr_ok(o);
+	if (odr_sequence_of (o, (Odr_fun) z_Permissions_s, &(*p)->elements,
+		&(*p)->num, name))
+		return 1;
+	*p = 0;
+	return opt && odr_ok(o);
+}
+
+int z_Close (ODR o, Z_Close **p, int opt, const char *name)
+{
+	if (!odr_sequence_begin (o, p, sizeof(**p), name))
+		return opt && odr_ok (o);
+	return
+		z_ReferenceId(o, &(*p)->referenceId, 1, "referenceId") &&
+		z_CloseReason(o, &(*p)->closeReason, 0, "closeReason") &&
+		odr_implicit_tag (o, z_InternationalString,
+			&(*p)->diagnosticInformation, ODR_CONTEXT, 3, 1, "diagnosticInformation") &&
+		odr_implicit_tag (o, z_ResourceReportId,
+			&(*p)->resourceReportFormat, ODR_CONTEXT, 4, 1, "resourceReportFormat") &&
+		odr_explicit_tag (o, z_ResourceReport,
+			&(*p)->resourceReport, ODR_CONTEXT, 5, 1, "resourceReport") &&
+		z_OtherInformation(o, &(*p)->otherInfo, 1, "otherInfo") &&
+		odr_sequence_end (o);
+}
+
+int z_CloseReason (ODR o, Z_CloseReason **p, int opt, const char *name)
+{
+	return odr_implicit_tag (o, odr_integer, p, ODR_CONTEXT, 211, opt, name);
+}
+
+int z_ReferenceId (ODR o, Z_ReferenceId **p, int opt, const char *name)
+{
+	return odr_implicit_tag (o, odr_octetstring, p, ODR_CONTEXT, 2, opt, name);
+}
+
+int z_ResultSetId (ODR o, Z_ResultSetId **p, int opt, const char *name)
+{
+	return odr_implicit_tag (o, z_InternationalString, p, ODR_CONTEXT, 31, opt, name);
+}
+
+int z_ElementSetName (ODR o, Z_ElementSetName **p, int opt, const char *name)
+{
+	return odr_implicit_tag (o, z_InternationalString, p, ODR_CONTEXT, 103, opt, name);
+}
+
+int z_DatabaseName (ODR o, Z_DatabaseName **p, int opt, const char *name)
+{
+	return odr_implicit_tag (o, z_InternationalString, p, ODR_CONTEXT, 105, opt, name);
+}
+
+int z_AttributeSetId (ODR o, Z_AttributeSetId **p, int opt, const char *name)
+{
+	return odr_oid (o, p, opt, name);
+}
+
+int z_OtherInformationUnit (ODR o, Z_OtherInformationUnit **p, int opt, const char *name)
+{
+	static Odr_arm arm[] = {
+		{ODR_IMPLICIT, ODR_CONTEXT, 2, Z_OtherInfo_characterInfo,
+		(Odr_fun) z_InternationalString, "characterInfo"},
+		{ODR_IMPLICIT, ODR_CONTEXT, 3, Z_OtherInfo_binaryInfo,
+		(Odr_fun) odr_octetstring, "binaryInfo"},
+		{ODR_IMPLICIT, ODR_CONTEXT, 4, Z_OtherInfo_externallyDefinedInfo,
+		(Odr_fun) z_External, "externallyDefinedInfo"},
+		{ODR_IMPLICIT, ODR_CONTEXT, 5, Z_OtherInfo_oid,
+		(Odr_fun) odr_oid, "oid"},
+		{-1, -1, -1, -1, (Odr_fun) 0, 0}
+	};
+	if (!odr_sequence_begin (o, p, sizeof(**p), name))
+		return opt && odr_ok (o);
+	return
+		odr_implicit_tag (o, z_InfoCategory,
+			&(*p)->category, ODR_CONTEXT, 1, 1, "category") &&
+		odr_choice (o, arm, &(*p)->information, &(*p)->which, 0) &&
+		odr_sequence_end (o);
+}
+
+int z_OtherInformation (ODR o, Z_OtherInformation **p, int opt, const char *name)
+{
+	if (!odr_initmember (o, p, sizeof(**p)))
+		return opt && odr_ok(o);
+	odr_implicit_settag (o, ODR_CONTEXT, 201);
+	if (odr_sequence_of (o, (Odr_fun) z_OtherInformationUnit, &(*p)->list,
+		&(*p)->num_elements, name))
+		return 1;
+	*p = 0;
+	return opt && odr_ok(o);
+}
+
+int z_InfoCategory (ODR o, Z_InfoCategory **p, int opt, const char *name)
+{
+	if (!odr_sequence_begin (o, p, sizeof(**p), name))
+		return opt && odr_ok (o);
+	return
+		odr_implicit_tag (o, odr_oid,
+			&(*p)->categoryTypeId, ODR_CONTEXT, 1, 1, "categoryTypeId") &&
+		odr_implicit_tag (o, odr_integer,
+			&(*p)->categoryValue, ODR_CONTEXT, 2, 0, "categoryValue") &&
+		odr_sequence_end (o);
+}
+
+int z_IntUnit (ODR o, Z_IntUnit **p, int opt, const char *name)
+{
+	if (!odr_sequence_begin (o, p, sizeof(**p), name))
+		return opt && odr_ok (o);
+	return
+		odr_implicit_tag (o, odr_integer,
+			&(*p)->value, ODR_CONTEXT, 1, 0, "value") &&
+		odr_implicit_tag (o, z_Unit,
+			&(*p)->unitUsed, ODR_CONTEXT, 2, 0, "unitUsed") &&
+		odr_sequence_end (o);
+}
+
+int z_Unit (ODR o, Z_Unit **p, int opt, const char *name)
+{
+	if (!odr_sequence_begin (o, p, sizeof(**p), name))
+		return opt && odr_ok (o);
+	return
+		odr_explicit_tag (o, z_InternationalString,
+			&(*p)->unitSystem, ODR_CONTEXT, 1, 1, "unitSystem") &&
+		odr_explicit_tag (o, z_StringOrNumeric,
+			&(*p)->unitType, ODR_CONTEXT, 2, 1, "unitType") &&
+		odr_explicit_tag (o, z_StringOrNumeric,
+			&(*p)->unit, ODR_CONTEXT, 3, 1, "unit") &&
+		odr_implicit_tag (o, odr_integer,
+			&(*p)->scaleFactor, ODR_CONTEXT, 4, 1, "scaleFactor") &&
+		odr_sequence_end (o);
+}
+
+int z_InternationalString (ODR o, Z_InternationalString **p, int opt, const char *name)
+{
+	return odr_generalstring (o, p, opt, name);
+}
+
+int z_StringOrNumeric (ODR o, Z_StringOrNumeric **p, int opt, const char *name)
+{
+	static Odr_arm arm[] = {
+		{ODR_IMPLICIT, ODR_CONTEXT, 1, Z_StringOrNumeric_string,
+		(Odr_fun) z_InternationalString, "string"},
+		{ODR_IMPLICIT, ODR_CONTEXT, 2, Z_StringOrNumeric_numeric,
+		(Odr_fun) odr_integer, "numeric"},
+		{-1, -1, -1, -1, (Odr_fun) 0, 0}
+	};
+	if (!odr_initmember(o, p, sizeof(**p)))
+		return opt && odr_ok(o);
+	if (odr_choice(o, arm, &(*p)->u, &(*p)->which, name))
+		return 1;
+	*p = 0;
+	return opt && odr_ok(o);
+}
+
+
+/* the type-0 query ... */
+int z_ANY_type_0 (ODR o, void **p, int opt)
+{
+    return 0;
+}
+
+
Index: /main/tags/2.25/gsdl/packages/yaz/z39.50/z-date.c
===================================================================
--- /main/tags/2.25/gsdl/packages/yaz/z39.50/z-date.c	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/yaz/z39.50/z-date.c	(revision 21064)
@@ -0,0 +1,157 @@
+/* Generated automatically by the YAZ ASN.1 Compiler 0.3 */
+/* Module-C: UserInfoFormat-dateTime */
+
+#include <yaz/z-date.h>
+
+int z_DateTime (ODR o, Z_DateTime **p, int opt, const char *name)
+{
+	if (!odr_sequence_begin (o, p, sizeof(**p), name))
+		return opt && odr_ok (o);
+	return
+		odr_explicit_tag (o, z_Date,
+			&(*p)->date, ODR_CONTEXT, 1, 1, "date") &&
+		odr_explicit_tag (o, z_Time,
+			&(*p)->time, ODR_CONTEXT, 2, 1, "time") &&
+		odr_sequence_end (o);
+}
+
+int z_DateMonthAndDay (ODR o, Z_DateMonthAndDay **p, int opt, const char *name)
+{
+	if (!odr_sequence_begin (o, p, sizeof(**p), name))
+		return opt && odr_ok (o);
+	return
+		odr_implicit_tag (o, odr_integer,
+			&(*p)->month, ODR_CONTEXT, 2, 0, "month") &&
+		odr_implicit_tag (o, odr_integer,
+			&(*p)->day, ODR_CONTEXT, 3, 1, "day") &&
+		odr_sequence_end (o);
+}
+
+int z_DateQuarter (ODR o, Z_DateQuarter **p, int opt, const char *name)
+{
+	static Odr_arm arm[] = {
+		{ODR_IMPLICIT, ODR_CONTEXT, 1, Z_DateQuarter_first,
+		(Odr_fun) odr_null, "first"},
+		{ODR_IMPLICIT, ODR_CONTEXT, 2, Z_DateQuarter_second,
+		(Odr_fun) odr_null, "second"},
+		{ODR_IMPLICIT, ODR_CONTEXT, 3, Z_DateQuarter_third,
+		(Odr_fun) odr_null, "third"},
+		{ODR_IMPLICIT, ODR_CONTEXT, 4, Z_DateQuarter_fourth,
+		(Odr_fun) odr_null, "fourth"},
+		{-1, -1, -1, -1, (Odr_fun) 0, 0}
+	};
+	if (!odr_initmember(o, p, sizeof(**p)))
+		return opt && odr_ok(o);
+	if (odr_choice(o, arm, &(*p)->u, &(*p)->which, name))
+		return 1;
+	*p = 0;
+	return opt && odr_ok(o);
+}
+
+int z_DateSeason (ODR o, Z_DateSeason **p, int opt, const char *name)
+{
+	static Odr_arm arm[] = {
+		{ODR_IMPLICIT, ODR_CONTEXT, 1, Z_DateSeason_winter,
+		(Odr_fun) odr_null, "winter"},
+		{ODR_IMPLICIT, ODR_CONTEXT, 2, Z_DateSeason_spring,
+		(Odr_fun) odr_null, "spring"},
+		{ODR_IMPLICIT, ODR_CONTEXT, 3, Z_DateSeason_summer,
+		(Odr_fun) odr_null, "summer"},
+		{ODR_IMPLICIT, ODR_CONTEXT, 4, Z_DateSeason_autumn,
+		(Odr_fun) odr_null, "autumn"},
+		{-1, -1, -1, -1, (Odr_fun) 0, 0}
+	};
+	if (!odr_initmember(o, p, sizeof(**p)))
+		return opt && odr_ok(o);
+	if (odr_choice(o, arm, &(*p)->u, &(*p)->which, name))
+		return 1;
+	*p = 0;
+	return opt && odr_ok(o);
+}
+
+int z_Era (ODR o, Z_Era **p, int opt, const char *name)
+{
+	static Odr_arm arm[] = {
+		{ODR_IMPLICIT, ODR_CONTEXT, 1, Z_Era_decade,
+		(Odr_fun) odr_null, "decade"},
+		{ODR_IMPLICIT, ODR_CONTEXT, 2, Z_Era_century,
+		(Odr_fun) odr_null, "century"},
+		{ODR_IMPLICIT, ODR_CONTEXT, 3, Z_Era_millennium,
+		(Odr_fun) odr_null, "millennium"},
+		{-1, -1, -1, -1, (Odr_fun) 0, 0}
+	};
+	if (!odr_initmember(o, p, sizeof(**p)))
+		return opt && odr_ok(o);
+	if (odr_choice(o, arm, &(*p)->u, &(*p)->which, name))
+		return 1;
+	*p = 0;
+	return opt && odr_ok(o);
+}
+
+int z_DateFlags (ODR o, Z_DateFlags **p, int opt, const char *name)
+{
+	if (!odr_sequence_begin (o, p, sizeof(**p), name))
+		return opt && odr_ok (o);
+	return
+		odr_implicit_tag (o, odr_null,
+			&(*p)->circa, ODR_CONTEXT, 1, 1, "circa") &&
+		odr_implicit_tag (o, z_Era,
+			&(*p)->era, ODR_CONTEXT, 2, 1, "era") &&
+		odr_sequence_end (o);
+}
+
+int z_Date (ODR o, Z_Date **p, int opt, const char *name)
+{
+	static Odr_arm arm[] = {
+		{ODR_IMPLICIT, ODR_CONTEXT, 1, Z_Date_monthAndDay,
+		(Odr_fun) z_DateMonthAndDay, "monthAndDay"},
+		{ODR_IMPLICIT, ODR_CONTEXT, 2, Z_Date_julianDay,
+		(Odr_fun) odr_integer, "julianDay"},
+		{ODR_IMPLICIT, ODR_CONTEXT, 3, Z_Date_weekNumber,
+		(Odr_fun) odr_integer, "weekNumber"},
+		{ODR_EXPLICIT, ODR_CONTEXT, 4, Z_Date_quarter,
+		(Odr_fun) z_DateQuarter, "quarter"},
+		{ODR_EXPLICIT, ODR_CONTEXT, 5, Z_Date_season,
+		(Odr_fun) z_DateSeason, "season"},
+		{-1, -1, -1, -1, (Odr_fun) 0, 0}
+	};
+	if (!odr_sequence_begin (o, p, sizeof(**p), name))
+		return opt && odr_ok (o);
+	return
+		odr_implicit_tag (o, odr_integer,
+			&(*p)->year, ODR_CONTEXT, 1, 0, "year") &&
+		((odr_constructed_begin (o, &(*p)->u, ODR_CONTEXT, 2, "partOfYear") &&
+		odr_choice (o, arm, &(*p)->u, &(*p)->which, 0) &&
+		odr_constructed_end (o)) || odr_ok(o)) &&
+		odr_implicit_tag (o, z_DateFlags,
+			&(*p)->flags, ODR_CONTEXT, 3, 1, "flags") &&
+		odr_sequence_end (o);
+}
+
+int z_Time (ODR o, Z_Time **p, int opt, const char *name)
+{
+	static Odr_arm arm[] = {
+		{ODR_IMPLICIT, ODR_CONTEXT, 1, Z_Time_local,
+		(Odr_fun) odr_null, "local"},
+		{ODR_IMPLICIT, ODR_CONTEXT, 2, Z_Time_utc,
+		(Odr_fun) odr_null, "utc"},
+		{ODR_IMPLICIT, ODR_CONTEXT, 3, Z_Time_utcOffset,
+		(Odr_fun) odr_integer, "utcOffset"},
+		{-1, -1, -1, -1, (Odr_fun) 0, 0}
+	};
+	if (!odr_sequence_begin (o, p, sizeof(**p), name))
+		return opt && odr_ok (o);
+	return
+		odr_implicit_tag (o, odr_integer,
+			&(*p)->hour, ODR_CONTEXT, 1, 0, "hour") &&
+		odr_implicit_tag (o, odr_integer,
+			&(*p)->minute, ODR_CONTEXT, 2, 1, "minute") &&
+		odr_implicit_tag (o, odr_integer,
+			&(*p)->second, ODR_CONTEXT, 3, 1, "second") &&
+		odr_implicit_tag (o, z_IntUnit,
+			&(*p)->partOfSecond, ODR_CONTEXT, 4, 1, "partOfSecond") &&
+		odr_constructed_begin (o, &(*p)->u, ODR_CONTEXT, 5, "zone") &&
+		odr_choice (o, arm, &(*p)->u, &(*p)->which, 0) &&
+		odr_constructed_end (o) &&
+		odr_sequence_end (o);
+}
Index: /main/tags/2.25/gsdl/packages/yaz/z39.50/z-diag1.c
===================================================================
--- /main/tags/2.25/gsdl/packages/yaz/z39.50/z-diag1.c	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/yaz/z39.50/z-diag1.c	(revision 21064)
@@ -0,0 +1,381 @@
+/* Generated automatically by the YAZ ASN.1 Compiler 0.3 */
+/* Module-C: DiagnosticFormatDiag1 */
+
+#include <yaz/z-diag1.h>
+
+int z_DiagnosticFormat_s (ODR o, Z_DiagnosticFormat_s **p, int opt, const char *name)
+{
+	static Odr_arm arm[] = {
+		{ODR_IMPLICIT, ODR_CONTEXT, 1, Z_DiagnosticFormat_s_defaultDiagRec,
+		(Odr_fun) z_DefaultDiagFormat, "defaultDiagRec"},
+		{ODR_EXPLICIT, ODR_CONTEXT, 2, Z_DiagnosticFormat_s_explicitDiagnostic,
+		(Odr_fun) z_DiagFormat, "explicitDiagnostic"},
+		{-1, -1, -1, -1, (Odr_fun) 0, 0}
+	};
+	if (!odr_sequence_begin (o, p, sizeof(**p), name))
+		return opt && odr_ok (o);
+	return
+		((odr_constructed_begin (o, &(*p)->u, ODR_CONTEXT, 1, "diagnostic") &&
+		odr_choice (o, arm, &(*p)->u, &(*p)->which, 0) &&
+		odr_constructed_end (o)) || odr_ok(o)) &&
+		odr_implicit_tag (o, z_InternationalString,
+			&(*p)->message, ODR_CONTEXT, 2, 1, "message") &&
+		odr_sequence_end (o);
+}
+
+int z_DiagnosticFormat (ODR o, Z_DiagnosticFormat **p, int opt, const char *name)
+{
+	if (!odr_initmember (o, p, sizeof(**p)))
+		return opt && odr_ok(o);
+	if (odr_sequence_of (o, (Odr_fun) z_DiagnosticFormat_s, &(*p)->elements,
+		&(*p)->num, name))
+		return 1;
+	*p = 0;
+	return opt && odr_ok(o);
+}
+
+int z_TooMany (ODR o, Z_TooMany **p, int opt, const char *name)
+{
+	if (!odr_sequence_begin (o, p, sizeof(**p), name))
+		return opt && odr_ok (o);
+	return
+		odr_implicit_tag (o, odr_integer,
+			&(*p)->tooManyWhat, ODR_CONTEXT, 1, 0, "tooManyWhat") &&
+		odr_implicit_tag (o, odr_integer,
+			&(*p)->max, ODR_CONTEXT, 2, 1, "max") &&
+		odr_sequence_end (o);
+}
+
+int z_BadSpec (ODR o, Z_BadSpec **p, int opt, const char *name)
+{
+	if (!odr_sequence_begin (o, p, sizeof(**p), name))
+		return opt && odr_ok (o);
+	return
+		odr_implicit_tag (o, z_Specification,
+			&(*p)->spec, ODR_CONTEXT, 1, 0, "spec") &&
+		odr_implicit_tag (o, z_DatabaseName,
+			&(*p)->db, ODR_CONTEXT, 2, 1, "db") &&
+		odr_implicit_settag (o, ODR_CONTEXT, 3) &&
+		(odr_sequence_of(o, (Odr_fun) z_Specification, &(*p)->goodOnes,
+		  &(*p)->num_goodOnes, "goodOnes") || odr_ok(o)) &&
+		odr_sequence_end (o);
+}
+
+int z_DbUnavail_0 (ODR o, Z_DbUnavail_0 **p, int opt, const char *name)
+{
+	if (!odr_sequence_begin (o, p, sizeof(**p), name))
+		return opt && odr_ok (o);
+	return
+		odr_implicit_tag (o, odr_integer,
+			&(*p)->reasonCode, ODR_CONTEXT, 1, 1, "reasonCode") &&
+		odr_implicit_tag (o, z_InternationalString,
+			&(*p)->message, ODR_CONTEXT, 2, 1, "message") &&
+		odr_sequence_end (o);
+}
+
+int z_DbUnavail (ODR o, Z_DbUnavail **p, int opt, const char *name)
+{
+	if (!odr_sequence_begin (o, p, sizeof(**p), name))
+		return opt && odr_ok (o);
+	return
+		odr_implicit_tag (o, z_DatabaseName,
+			&(*p)->db, ODR_CONTEXT, 1, 0, "db") &&
+		odr_implicit_tag (o, z_DbUnavail_0,
+			&(*p)->why, ODR_CONTEXT, 2, 0, "why") &&
+		odr_sequence_end (o);
+}
+
+int z_Attribute (ODR o, Z_Attribute **p, int opt, const char *name)
+{
+	if (!odr_sequence_begin (o, p, sizeof(**p), name))
+		return opt && odr_ok (o);
+	return
+		odr_implicit_tag (o, odr_oid,
+			&(*p)->id, ODR_CONTEXT, 1, 0, "id") &&
+		odr_implicit_tag (o, odr_integer,
+			&(*p)->type, ODR_CONTEXT, 2, 1, "type") &&
+		odr_implicit_tag (o, odr_integer,
+			&(*p)->value, ODR_CONTEXT, 3, 1, "value") &&
+		odr_explicit_tag (o, z_Term,
+			&(*p)->term, ODR_CONTEXT, 4, 1, "term") &&
+		odr_sequence_end (o);
+}
+
+int z_AttCombo (ODR o, Z_AttCombo **p, int opt, const char *name)
+{
+	if (!odr_sequence_begin (o, p, sizeof(**p), name))
+		return opt && odr_ok (o);
+	return
+		odr_implicit_tag (o, z_AttributeList,
+			&(*p)->unsupportedCombination, ODR_CONTEXT, 1, 0, "unsupportedCombination") &&
+		odr_implicit_settag (o, ODR_CONTEXT, 2) &&
+		(odr_sequence_of(o, (Odr_fun) z_AttributeList, &(*p)->recommendedAlternatives,
+		  &(*p)->num_recommendedAlternatives, "recommendedAlternatives") || odr_ok(o)) &&
+		odr_sequence_end (o);
+}
+
+int z_DiagTerm (ODR o, Z_DiagTerm **p, int opt, const char *name)
+{
+	if (!odr_sequence_begin (o, p, sizeof(**p), name))
+		return opt && odr_ok (o);
+	return
+		odr_implicit_tag (o, odr_integer,
+			&(*p)->problem, ODR_CONTEXT, 1, 1, "problem") &&
+		odr_explicit_tag (o, z_Term,
+			&(*p)->term, ODR_CONTEXT, 2, 0, "term") &&
+		odr_sequence_end (o);
+}
+
+int z_Proximity (ODR o, Z_Proximity **p, int opt, const char *name)
+{
+	static Odr_arm arm[] = {
+		{ODR_IMPLICIT, ODR_CONTEXT, 1, Z_Proximity_resultSets,
+		(Odr_fun) odr_null, "resultSets"},
+		{ODR_IMPLICIT, ODR_CONTEXT, 2, Z_Proximity_badSet,
+		(Odr_fun) z_InternationalString, "badSet"},
+		{ODR_IMPLICIT, ODR_CONTEXT, 3, Z_Proximity_relation,
+		(Odr_fun) odr_integer, "relation"},
+		{ODR_IMPLICIT, ODR_CONTEXT, 4, Z_Proximity_unit,
+		(Odr_fun) odr_integer, "unit"},
+		{ODR_IMPLICIT, ODR_CONTEXT, 5, Z_Proximity_distance,
+		(Odr_fun) odr_integer, "distance"},
+		{ODR_EXPLICIT, ODR_CONTEXT, 6, Z_Proximity_attributes,
+		(Odr_fun) z_AttributeList, "attributes"},
+		{ODR_IMPLICIT, ODR_CONTEXT, 7, Z_Proximity_ordered,
+		(Odr_fun) odr_null, "ordered"},
+		{ODR_IMPLICIT, ODR_CONTEXT, 8, Z_Proximity_exclusion,
+		(Odr_fun) odr_null, "exclusion"},
+		{-1, -1, -1, -1, (Odr_fun) 0, 0}
+	};
+	if (!odr_initmember(o, p, sizeof(**p)))
+		return opt && odr_ok(o);
+	if (odr_choice(o, arm, &(*p)->u, &(*p)->which, name))
+		return 1;
+	*p = 0;
+	return opt && odr_ok(o);
+}
+
+int z_AttrListList (ODR o, Z_AttrListList **p, int opt, const char *name)
+{
+	if (!odr_initmember (o, p, sizeof(**p)))
+		return opt && odr_ok(o);
+	if (odr_sequence_of (o, (Odr_fun) z_AttributeList, &(*p)->elements,
+		&(*p)->num, name))
+		return 1;
+	*p = 0;
+	return opt && odr_ok(o);
+}
+
+int z_Scan (ODR o, Z_Scan **p, int opt, const char *name)
+{
+	static Odr_arm arm[] = {
+		{ODR_IMPLICIT, ODR_CONTEXT, 0, Z_Scan_nonZeroStepSize,
+		(Odr_fun) odr_null, "nonZeroStepSize"},
+		{ODR_IMPLICIT, ODR_CONTEXT, 1, Z_Scan_specifiedStepSize,
+		(Odr_fun) odr_null, "specifiedStepSize"},
+		{ODR_IMPLICIT, ODR_CONTEXT, 3, Z_Scan_termList1,
+		(Odr_fun) odr_null, "termList1"},
+		{ODR_IMPLICIT, ODR_CONTEXT, 4, Z_Scan_termList2,
+		(Odr_fun) z_AttrListList, "termList2"},
+		{ODR_IMPLICIT, ODR_CONTEXT, 5, Z_Scan_posInResponse,
+		(Odr_fun) odr_integer, "posInResponse"},
+		{ODR_IMPLICIT, ODR_CONTEXT, 6, Z_Scan_resources,
+		(Odr_fun) odr_null, "resources"},
+		{ODR_IMPLICIT, ODR_CONTEXT, 7, Z_Scan_endOfList,
+		(Odr_fun) odr_null, "endOfList"},
+		{-1, -1, -1, -1, (Odr_fun) 0, 0}
+	};
+	if (!odr_initmember(o, p, sizeof(**p)))
+		return opt && odr_ok(o);
+	if (odr_choice(o, arm, &(*p)->u, &(*p)->which, name))
+		return 1;
+	*p = 0;
+	return opt && odr_ok(o);
+}
+
+int z_StringList (ODR o, Z_StringList **p, int opt, const char *name)
+{
+	if (!odr_initmember (o, p, sizeof(**p)))
+		return opt && odr_ok(o);
+	if (odr_sequence_of (o, (Odr_fun) z_InternationalString, &(*p)->elements,
+		&(*p)->num, name))
+		return 1;
+	*p = 0;
+	return opt && odr_ok(o);
+}
+
+int z_Sort (ODR o, Z_Sort **p, int opt, const char *name)
+{
+	static Odr_arm arm[] = {
+		{ODR_IMPLICIT, ODR_CONTEXT, 0, Z_SortD_sequence,
+		(Odr_fun) odr_null, "sequence"},
+		{ODR_IMPLICIT, ODR_CONTEXT, 1, Z_SortD_noRsName,
+		(Odr_fun) odr_null, "noRsName"},
+		{ODR_IMPLICIT, ODR_CONTEXT, 2, Z_SortD_tooMany,
+		(Odr_fun) odr_integer, "tooMany"},
+		{ODR_IMPLICIT, ODR_CONTEXT, 3, Z_SortD_incompatible,
+		(Odr_fun) odr_null, "incompatible"},
+		{ODR_IMPLICIT, ODR_CONTEXT, 4, Z_SortD_generic,
+		(Odr_fun) odr_null, "generic"},
+		{ODR_IMPLICIT, ODR_CONTEXT, 5, Z_SortD_dbSpecific,
+		(Odr_fun) odr_null, "dbSpecific"},
+		{ODR_EXPLICIT, ODR_CONTEXT, 6, Z_SortD_sortElement,
+		(Odr_fun) z_SortElement, "sortElement"},
+		{ODR_IMPLICIT, ODR_CONTEXT, 7, Z_SortD_key,
+		(Odr_fun) odr_integer, "key"},
+		{ODR_IMPLICIT, ODR_CONTEXT, 8, Z_SortD_action,
+		(Odr_fun) odr_null, "action"},
+		{ODR_IMPLICIT, ODR_CONTEXT, 9, Z_SortD_illegal,
+		(Odr_fun) odr_integer, "illegal"},
+		{ODR_IMPLICIT, ODR_CONTEXT, 10, Z_SortD_inputTooLarge,
+		(Odr_fun) z_StringList, "inputTooLarge"},
+		{ODR_IMPLICIT, ODR_CONTEXT, 11, Z_SortD_aggregateTooLarge,
+		(Odr_fun) odr_null, "aggregateTooLarge"},
+		{-1, -1, -1, -1, (Odr_fun) 0, 0}
+	};
+	if (!odr_initmember(o, p, sizeof(**p)))
+		return opt && odr_ok(o);
+	if (odr_choice(o, arm, &(*p)->u, &(*p)->which, name))
+		return 1;
+	*p = 0;
+	return opt && odr_ok(o);
+}
+
+int z_Segmentation (ODR o, Z_Segmentation **p, int opt, const char *name)
+{
+	static Odr_arm arm[] = {
+		{ODR_IMPLICIT, ODR_CONTEXT, 0, Z_Segmentation_segmentCount,
+		(Odr_fun) odr_null, "segmentCount"},
+		{ODR_IMPLICIT, ODR_CONTEXT, 1, Z_Segmentation_segmentSize,
+		(Odr_fun) odr_integer, "segmentSize"},
+		{-1, -1, -1, -1, (Odr_fun) 0, 0}
+	};
+	if (!odr_initmember(o, p, sizeof(**p)))
+		return opt && odr_ok(o);
+	if (odr_choice(o, arm, &(*p)->u, &(*p)->which, name))
+		return 1;
+	*p = 0;
+	return opt && odr_ok(o);
+}
+
+int z_ExtServices (ODR o, Z_ExtServices **p, int opt, const char *name)
+{
+	static Odr_arm arm[] = {
+		{ODR_IMPLICIT, ODR_CONTEXT, 1, Z_ExtServices_req,
+		(Odr_fun) odr_integer, "req"},
+		{ODR_IMPLICIT, ODR_CONTEXT, 2, Z_ExtServices_permission,
+		(Odr_fun) odr_integer, "permission"},
+		{ODR_IMPLICIT, ODR_CONTEXT, 3, Z_ExtServices_immediate,
+		(Odr_fun) odr_integer, "immediate"},
+		{-1, -1, -1, -1, (Odr_fun) 0, 0}
+	};
+	if (!odr_initmember(o, p, sizeof(**p)))
+		return opt && odr_ok(o);
+	if (odr_choice(o, arm, &(*p)->u, &(*p)->which, name))
+		return 1;
+	*p = 0;
+	return opt && odr_ok(o);
+}
+
+int z_OidList (ODR o, Z_OidList **p, int opt, const char *name)
+{
+	if (!odr_initmember (o, p, sizeof(**p)))
+		return opt && odr_ok(o);
+	if (odr_sequence_of (o, (Odr_fun) odr_oid, &(*p)->elements,
+		&(*p)->num, name))
+		return 1;
+	*p = 0;
+	return opt && odr_ok(o);
+}
+
+int z_AltOidList (ODR o, Z_AltOidList **p, int opt, const char *name)
+{
+	if (!odr_initmember (o, p, sizeof(**p)))
+		return opt && odr_ok(o);
+	if (odr_sequence_of (o, (Odr_fun) odr_oid, &(*p)->elements,
+		&(*p)->num, name))
+		return 1;
+	*p = 0;
+	return opt && odr_ok(o);
+}
+
+int z_AccessCtrl (ODR o, Z_AccessCtrl **p, int opt, const char *name)
+{
+	static Odr_arm arm[] = {
+		{ODR_IMPLICIT, ODR_CONTEXT, 1, Z_AccessCtrl_noUser,
+		(Odr_fun) odr_null, "noUser"},
+		{ODR_IMPLICIT, ODR_CONTEXT, 2, Z_AccessCtrl_refused,
+		(Odr_fun) odr_null, "refused"},
+		{ODR_IMPLICIT, ODR_CONTEXT, 3, Z_AccessCtrl_simple,
+		(Odr_fun) odr_null, "simple"},
+		{ODR_IMPLICIT, ODR_CONTEXT, 4, Z_AccessCtrl_oid,
+		(Odr_fun) z_OidList, "oid"},
+		{ODR_IMPLICIT, ODR_CONTEXT, 5, Z_AccessCtrl_alternative,
+		(Odr_fun) z_AltOidList, "alternative"},
+		{ODR_IMPLICIT, ODR_CONTEXT, 6, Z_AccessCtrl_pwdInv,
+		(Odr_fun) odr_null, "pwdInv"},
+		{ODR_IMPLICIT, ODR_CONTEXT, 7, Z_AccessCtrl_pwdExp,
+		(Odr_fun) odr_null, "pwdExp"},
+		{-1, -1, -1, -1, (Odr_fun) 0, 0}
+	};
+	if (!odr_initmember(o, p, sizeof(**p)))
+		return opt && odr_ok(o);
+	if (odr_choice(o, arm, &(*p)->u, &(*p)->which, name))
+		return 1;
+	*p = 0;
+	return opt && odr_ok(o);
+}
+
+int z_RecordSyntax (ODR o, Z_RecordSyntax **p, int opt, const char *name)
+{
+	if (!odr_sequence_begin (o, p, sizeof(**p), name))
+		return opt && odr_ok (o);
+	return
+		odr_implicit_tag (o, odr_oid,
+			&(*p)->unsupportedSyntax, ODR_CONTEXT, 1, 0, "unsupportedSyntax") &&
+		odr_implicit_settag (o, ODR_CONTEXT, 2) &&
+		(odr_sequence_of(o, (Odr_fun) odr_oid, &(*p)->suggestedAlternatives,
+		  &(*p)->num_suggestedAlternatives, "suggestedAlternatives") || odr_ok(o)) &&
+		odr_sequence_end (o);
+}
+
+int z_DiagFormat (ODR o, Z_DiagFormat **p, int opt, const char *name)
+{
+	static Odr_arm arm[] = {
+		{ODR_IMPLICIT, ODR_CONTEXT, 1000, Z_DiagFormat_tooMany,
+		(Odr_fun) z_TooMany, "tooMany"},
+		{ODR_IMPLICIT, ODR_CONTEXT, 1001, Z_DiagFormat_badSpec,
+		(Odr_fun) z_BadSpec, "badSpec"},
+		{ODR_IMPLICIT, ODR_CONTEXT, 1002, Z_DiagFormat_dbUnavail,
+		(Odr_fun) z_DbUnavail, "dbUnavail"},
+		{ODR_IMPLICIT, ODR_CONTEXT, 1003, Z_DiagFormat_unSupOp,
+		(Odr_fun) odr_integer, "unSupOp"},
+		{ODR_IMPLICIT, ODR_CONTEXT, 1004, Z_DiagFormat_attribute,
+		(Odr_fun) z_Attribute, "attribute"},
+		{ODR_IMPLICIT, ODR_CONTEXT, 1005, Z_DiagFormat_attCombo,
+		(Odr_fun) z_AttCombo, "attCombo"},
+		{ODR_IMPLICIT, ODR_CONTEXT, 1006, Z_DiagFormat_term,
+		(Odr_fun) z_DiagTerm, "term"},
+		{ODR_EXPLICIT, ODR_CONTEXT, 1007, Z_DiagFormat_proximity,
+		(Odr_fun) z_Proximity, "proximity"},
+		{ODR_EXPLICIT, ODR_CONTEXT, 1008, Z_DiagFormat_scan,
+		(Odr_fun) z_Scan, "scan"},
+		{ODR_EXPLICIT, ODR_CONTEXT, 1009, Z_DiagFormat_sort,
+		(Odr_fun) z_Sort, "sort"},
+		{ODR_EXPLICIT, ODR_CONTEXT, 1010, Z_DiagFormat_segmentation,
+		(Odr_fun) z_Segmentation, "segmentation"},
+		{ODR_EXPLICIT, ODR_CONTEXT, 1011, Z_DiagFormat_extServices,
+		(Odr_fun) z_ExtServices, "extServices"},
+		{ODR_EXPLICIT, ODR_CONTEXT, 1012, Z_DiagFormat_accessCtrl,
+		(Odr_fun) z_AccessCtrl, "accessCtrl"},
+		{ODR_IMPLICIT, ODR_CONTEXT, 1013, Z_DiagFormat_recordSyntax,
+		(Odr_fun) z_RecordSyntax, "recordSyntax"},
+		{-1, -1, -1, -1, (Odr_fun) 0, 0}
+	};
+	if (!odr_initmember(o, p, sizeof(**p)))
+		return opt && odr_ok(o);
+	if (odr_choice(o, arm, &(*p)->u, &(*p)->which, name))
+		return 1;
+	*p = 0;
+	return opt && odr_ok(o);
+}
Index: /main/tags/2.25/gsdl/packages/yaz/z39.50/z-espec1.c
===================================================================
--- /main/tags/2.25/gsdl/packages/yaz/z39.50/z-espec1.c	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/yaz/z39.50/z-espec1.c	(revision 21064)
@@ -0,0 +1,172 @@
+/* Generated automatically by the YAZ ASN.1 Compiler 0.3 */
+/* Module-C: ElementSpecificationFormat-eSpec-1 */
+
+#include <yaz/z-espec1.h>
+
+int z_Espec1 (ODR o, Z_Espec1 **p, int opt, const char *name)
+{
+	if (!odr_sequence_begin (o, p, sizeof(**p), name))
+		return opt && odr_ok (o);
+	return
+		odr_implicit_settag (o, ODR_CONTEXT, 1) &&
+		(odr_sequence_of(o, (Odr_fun) z_InternationalString, &(*p)->elementSetNames,
+		  &(*p)->num_elementSetNames, "elementSetNames") || odr_ok(o)) &&
+		odr_implicit_tag (o, odr_oid,
+			&(*p)->defaultVariantSetId, ODR_CONTEXT, 2, 1, "defaultVariantSetId") &&
+		odr_implicit_tag (o, z_Variant,
+			&(*p)->defaultVariantRequest, ODR_CONTEXT, 3, 1, "defaultVariantRequest") &&
+		odr_implicit_tag (o, odr_integer,
+			&(*p)->defaultTagType, ODR_CONTEXT, 4, 1, "defaultTagType") &&
+		odr_implicit_settag (o, ODR_CONTEXT, 5) &&
+		(odr_sequence_of(o, (Odr_fun) z_ElementRequest, &(*p)->elements,
+		  &(*p)->num_elements, "elements") || odr_ok(o)) &&
+		odr_sequence_end (o);
+}
+
+int z_ElementRequestCompositeElementPrimitives (ODR o, Z_ElementRequestCompositeElementPrimitives **p, int opt, const char *name)
+{
+	if (!odr_initmember (o, p, sizeof(**p)))
+		return opt && odr_ok(o);
+	if (odr_sequence_of (o, (Odr_fun) z_InternationalString, &(*p)->elements,
+		&(*p)->num, name))
+		return 1;
+	*p = 0;
+	return opt && odr_ok(o);
+}
+
+int z_ElementRequestCompositeElementSpecs (ODR o, Z_ElementRequestCompositeElementSpecs **p, int opt, const char *name)
+{
+	if (!odr_initmember (o, p, sizeof(**p)))
+		return opt && odr_ok(o);
+	if (odr_sequence_of (o, (Odr_fun) z_SimpleElement, &(*p)->elements,
+		&(*p)->num, name))
+		return 1;
+	*p = 0;
+	return opt && odr_ok(o);
+}
+
+int z_ElementRequestCompositeElement (ODR o, Z_ElementRequestCompositeElement **p, int opt, const char *name)
+{
+	static Odr_arm arm[] = {
+		{ODR_IMPLICIT, ODR_CONTEXT, 1, Z_ElementRequestCompositeElement_primitives,
+		(Odr_fun) z_ElementRequestCompositeElementPrimitives, "primitives"},
+		{ODR_IMPLICIT, ODR_CONTEXT, 2, Z_ElementRequestCompositeElement_specs,
+		(Odr_fun) z_ElementRequestCompositeElementSpecs, "specs"},
+		{-1, -1, -1, -1, (Odr_fun) 0, 0}
+	};
+	if (!odr_sequence_begin (o, p, sizeof(**p), name))
+		return opt && odr_ok (o);
+	return
+		odr_constructed_begin (o, &(*p)->u, ODR_CONTEXT, 1, "elementList") &&
+		odr_choice (o, arm, &(*p)->u, &(*p)->which, 0) &&
+		odr_constructed_end (o) &&
+		odr_implicit_tag (o, z_ETagPath,
+			&(*p)->deliveryTag, ODR_CONTEXT, 2, 0, "deliveryTag") &&
+		odr_implicit_tag (o, z_Variant,
+			&(*p)->variantRequest, ODR_CONTEXT, 3, 1, "variantRequest") &&
+		odr_sequence_end (o);
+}
+
+int z_ElementRequest (ODR o, Z_ElementRequest **p, int opt, const char *name)
+{
+	static Odr_arm arm[] = {
+		{ODR_IMPLICIT, ODR_CONTEXT, 1, Z_ERequest_simpleElement,
+		(Odr_fun) z_SimpleElement, "simpleElement"},
+		{ODR_IMPLICIT, ODR_CONTEXT, 2, Z_ERequest_compositeElement,
+		(Odr_fun) z_ElementRequestCompositeElement, "compositeElement"},
+		{-1, -1, -1, -1, (Odr_fun) 0, 0}
+	};
+	if (!odr_initmember(o, p, sizeof(**p)))
+		return opt && odr_ok(o);
+	if (odr_choice(o, arm, &(*p)->u, &(*p)->which, name))
+		return 1;
+	*p = 0;
+	return opt && odr_ok(o);
+}
+
+int z_SimpleElement (ODR o, Z_SimpleElement **p, int opt, const char *name)
+{
+	if (!odr_sequence_begin (o, p, sizeof(**p), name))
+		return opt && odr_ok (o);
+	return
+		odr_implicit_tag (o, z_ETagPath,
+			&(*p)->path, ODR_CONTEXT, 1, 0, "path") &&
+		odr_implicit_tag (o, z_Variant,
+			&(*p)->variantRequest, ODR_CONTEXT, 2, 1, "variantRequest") &&
+		odr_sequence_end (o);
+}
+
+int z_SpecificTag (ODR o, Z_SpecificTag **p, int opt, const char *name)
+{
+	if (!odr_sequence_begin (o, p, sizeof(**p), name))
+		return opt && odr_ok (o);
+	return
+		odr_implicit_tag (o, odr_integer,
+			&(*p)->tagType, ODR_CONTEXT, 1, 1, "tagType") &&
+		odr_explicit_tag (o, z_StringOrNumeric,
+			&(*p)->tagValue, ODR_CONTEXT, 2, 0, "tagValue") &&
+		odr_explicit_tag (o, z_Occurrences,
+			&(*p)->occurrences, ODR_CONTEXT, 3, 1, "occurrences") &&
+		odr_sequence_end (o);
+}
+
+int z_ETagUnit (ODR o, Z_ETagUnit **p, int opt, const char *name)
+{
+	static Odr_arm arm[] = {
+		{ODR_IMPLICIT, ODR_CONTEXT, 1, Z_ETagUnit_specificTag,
+		(Odr_fun) z_SpecificTag, "specificTag"},
+		{ODR_EXPLICIT, ODR_CONTEXT, 2, Z_ETagUnit_wildThing,
+		(Odr_fun) z_Occurrences, "wildThing"},
+		{ODR_IMPLICIT, ODR_CONTEXT, 3, Z_ETagUnit_wildPath,
+		(Odr_fun) odr_null, "wildPath"},
+		{-1, -1, -1, -1, (Odr_fun) 0, 0}
+	};
+	if (!odr_initmember(o, p, sizeof(**p)))
+		return opt && odr_ok(o);
+	if (odr_choice(o, arm, &(*p)->u, &(*p)->which, name))
+		return 1;
+	*p = 0;
+	return opt && odr_ok(o);
+}
+
+int z_ETagPath (ODR o, Z_ETagPath **p, int opt, const char *name)
+{
+	if (!odr_initmember (o, p, sizeof(**p)))
+		return opt && odr_ok(o);
+	if (odr_sequence_of (o, (Odr_fun) z_ETagUnit, &(*p)->tags,
+		&(*p)->num_tags, name))
+		return 1;
+	*p = 0;
+	return opt && odr_ok(o);
+}
+
+int z_OccurValues (ODR o, Z_OccurValues **p, int opt, const char *name)
+{
+	if (!odr_sequence_begin (o, p, sizeof(**p), name))
+		return opt && odr_ok (o);
+	return
+		odr_implicit_tag (o, odr_integer,
+			&(*p)->start, ODR_CONTEXT, 1, 0, "start") &&
+		odr_implicit_tag (o, odr_integer,
+			&(*p)->howMany, ODR_CONTEXT, 2, 1, "howMany") &&
+		odr_sequence_end (o);
+}
+
+int z_Occurrences (ODR o, Z_Occurrences **p, int opt, const char *name)
+{
+	static Odr_arm arm[] = {
+		{ODR_IMPLICIT, ODR_CONTEXT, 1, Z_Occurrences_all,
+		(Odr_fun) odr_null, "all"},
+		{ODR_IMPLICIT, ODR_CONTEXT, 2, Z_Occurrences_last,
+		(Odr_fun) odr_null, "last"},
+		{ODR_IMPLICIT, ODR_CONTEXT, 3, Z_Occurrences_values,
+		(Odr_fun) z_OccurValues, "values"},
+		{-1, -1, -1, -1, (Odr_fun) 0, 0}
+	};
+	if (!odr_initmember(o, p, sizeof(**p)))
+		return opt && odr_ok(o);
+	if (odr_choice(o, arm, &(*p)->u, &(*p)->which, name))
+		return 1;
+	*p = 0;
+	return opt && odr_ok(o);
+}
Index: /main/tags/2.25/gsdl/packages/yaz/z39.50/z-estask.c
===================================================================
--- /main/tags/2.25/gsdl/packages/yaz/z39.50/z-estask.c	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/yaz/z39.50/z-estask.c	(revision 21064)
@@ -0,0 +1,35 @@
+/* Generated automatically by the YAZ ASN.1 Compiler 0.3 */
+/* Module-C: RecordSyntax-ESTaskPackage */
+
+#include <yaz/z-estask.h>
+
+int z_TaskPackage (ODR o, Z_TaskPackage **p, int opt, const char *name)
+{
+	if (!odr_sequence_begin (o, p, sizeof(**p), name))
+		return opt && odr_ok (o);
+	return
+		odr_implicit_tag (o, odr_oid,
+			&(*p)->packageType, ODR_CONTEXT, 1, 0, "packageType") &&
+		odr_implicit_tag (o, z_InternationalString,
+			&(*p)->packageName, ODR_CONTEXT, 2, 1, "packageName") &&
+		odr_implicit_tag (o, z_InternationalString,
+			&(*p)->userId, ODR_CONTEXT, 3, 1, "userId") &&
+		odr_implicit_tag (o, z_IntUnit,
+			&(*p)->retentionTime, ODR_CONTEXT, 4, 1, "retentionTime") &&
+		odr_implicit_tag (o, z_Permissions,
+			&(*p)->permissions, ODR_CONTEXT, 5, 1, "permissions") &&
+		odr_implicit_tag (o, z_InternationalString,
+			&(*p)->description, ODR_CONTEXT, 6, 1, "description") &&
+		odr_implicit_tag (o, odr_octetstring,
+			&(*p)->targetReference, ODR_CONTEXT, 7, 1, "targetReference") &&
+		odr_implicit_tag (o, odr_generalizedtime,
+			&(*p)->creationDateTime, ODR_CONTEXT, 8, 1, "creationDateTime") &&
+		odr_implicit_tag (o, odr_integer,
+			&(*p)->taskStatus, ODR_CONTEXT, 9, 0, "taskStatus") &&
+		odr_implicit_settag (o, ODR_CONTEXT, 10) &&
+		(odr_sequence_of(o, (Odr_fun) z_DiagRec, &(*p)->packageDiagnostics,
+		  &(*p)->num_packageDiagnostics, "packageDiagnostics") || odr_ok(o)) &&
+		odr_implicit_tag (o, z_External,
+			&(*p)->taskSpecificParameters, ODR_CONTEXT, 11, 0, "taskSpecificParameters") &&
+		odr_sequence_end (o);
+}
Index: /main/tags/2.25/gsdl/packages/yaz/z39.50/z-exp.c
===================================================================
--- /main/tags/2.25/gsdl/packages/yaz/z39.50/z-exp.c	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/yaz/z39.50/z-exp.c	(revision 21064)
@@ -0,0 +1,1436 @@
+/* Generated automatically by the YAZ ASN.1 Compiler 0.3 */
+/* Module-C: RecordSyntax-explain */
+
+#include <yaz/z-exp.h>
+
+int z_ExplainRecord (ODR o, Z_ExplainRecord **p, int opt, const char *name)
+{
+	static Odr_arm arm[] = {
+		{ODR_IMPLICIT, ODR_CONTEXT, 0, Z_Explain_targetInfo,
+		(Odr_fun) z_TargetInfo, "targetInfo"},
+		{ODR_IMPLICIT, ODR_CONTEXT, 1, Z_Explain_databaseInfo,
+		(Odr_fun) z_DatabaseInfo, "databaseInfo"},
+		{ODR_IMPLICIT, ODR_CONTEXT, 2, Z_Explain_schemaInfo,
+		(Odr_fun) z_SchemaInfo, "schemaInfo"},
+		{ODR_IMPLICIT, ODR_CONTEXT, 3, Z_Explain_tagSetInfo,
+		(Odr_fun) z_TagSetInfo, "tagSetInfo"},
+		{ODR_IMPLICIT, ODR_CONTEXT, 4, Z_Explain_recordSyntaxInfo,
+		(Odr_fun) z_RecordSyntaxInfo, "recordSyntaxInfo"},
+		{ODR_IMPLICIT, ODR_CONTEXT, 5, Z_Explain_attributeSetInfo,
+		(Odr_fun) z_AttributeSetInfo, "attributeSetInfo"},
+		{ODR_IMPLICIT, ODR_CONTEXT, 6, Z_Explain_termListInfo,
+		(Odr_fun) z_TermListInfo, "termListInfo"},
+		{ODR_IMPLICIT, ODR_CONTEXT, 7, Z_Explain_extendedServicesInfo,
+		(Odr_fun) z_ExtendedServicesInfo, "extendedServicesInfo"},
+		{ODR_IMPLICIT, ODR_CONTEXT, 8, Z_Explain_attributeDetails,
+		(Odr_fun) z_AttributeDetails, "attributeDetails"},
+		{ODR_IMPLICIT, ODR_CONTEXT, 9, Z_Explain_termListDetails,
+		(Odr_fun) z_TermListDetails, "termListDetails"},
+		{ODR_IMPLICIT, ODR_CONTEXT, 10, Z_Explain_elementSetDetails,
+		(Odr_fun) z_ElementSetDetails, "elementSetDetails"},
+		{ODR_IMPLICIT, ODR_CONTEXT, 11, Z_Explain_retrievalRecordDetails,
+		(Odr_fun) z_RetrievalRecordDetails, "retrievalRecordDetails"},
+		{ODR_IMPLICIT, ODR_CONTEXT, 12, Z_Explain_sortDetails,
+		(Odr_fun) z_SortDetails, "sortDetails"},
+		{ODR_IMPLICIT, ODR_CONTEXT, 13, Z_Explain_processing,
+		(Odr_fun) z_ProcessingInformation, "processing"},
+		{ODR_IMPLICIT, ODR_CONTEXT, 14, Z_Explain_variants,
+		(Odr_fun) z_VariantSetInfo, "variants"},
+		{ODR_IMPLICIT, ODR_CONTEXT, 15, Z_Explain_units,
+		(Odr_fun) z_UnitInfo, "units"},
+		{ODR_IMPLICIT, ODR_CONTEXT, 100, Z_Explain_categoryList,
+		(Odr_fun) z_CategoryList, "categoryList"},
+		{-1, -1, -1, -1, (Odr_fun) 0, 0}
+	};
+	if (!odr_initmember(o, p, sizeof(**p)))
+		return opt && odr_ok(o);
+	if (odr_choice(o, arm, &(*p)->u, &(*p)->which, name))
+		return 1;
+	*p = 0;
+	return opt && odr_ok(o);
+}
+
+int z_TargetInfo (ODR o, Z_TargetInfo **p, int opt, const char *name)
+{
+	if (!odr_sequence_begin (o, p, sizeof(**p), name))
+		return opt && odr_ok (o);
+	return
+		odr_implicit_tag (o, z_CommonInfo,
+			&(*p)->commonInfo, ODR_CONTEXT, 0, 1, "commonInfo") &&
+		odr_implicit_tag (o, z_InternationalString,
+			&(*p)->name, ODR_CONTEXT, 1, 0, "name") &&
+		odr_implicit_tag (o, z_HumanString,
+			&(*p)->recentNews, ODR_CONTEXT, 2, 1, "recentNews") &&
+		odr_implicit_tag (o, z_IconObject,
+			&(*p)->icon, ODR_CONTEXT, 3, 1, "icon") &&
+		odr_implicit_tag (o, odr_bool,
+			&(*p)->namedResultSets, ODR_CONTEXT, 4, 0, "namedResultSets") &&
+		odr_implicit_tag (o, odr_bool,
+			&(*p)->multipleDBsearch, ODR_CONTEXT, 5, 0, "multipleDBsearch") &&
+		odr_implicit_tag (o, odr_integer,
+			&(*p)->maxResultSets, ODR_CONTEXT, 6, 1, "maxResultSets") &&
+		odr_implicit_tag (o, odr_integer,
+			&(*p)->maxResultSize, ODR_CONTEXT, 7, 1, "maxResultSize") &&
+		odr_implicit_tag (o, odr_integer,
+			&(*p)->maxTerms, ODR_CONTEXT, 8, 1, "maxTerms") &&
+		odr_implicit_tag (o, z_IntUnit,
+			&(*p)->timeoutInterval, ODR_CONTEXT, 9, 1, "timeoutInterval") &&
+		odr_implicit_tag (o, z_HumanString,
+			&(*p)->welcomeMessage, ODR_CONTEXT, 10, 1, "welcomeMessage") &&
+		odr_implicit_tag (o, z_ContactInfo,
+			&(*p)->contactInfo, ODR_CONTEXT, 11, 1, "contactInfo") &&
+		odr_implicit_tag (o, z_HumanString,
+			&(*p)->description, ODR_CONTEXT, 12, 1, "description") &&
+		odr_implicit_settag (o, ODR_CONTEXT, 13) &&
+		(odr_sequence_of(o, (Odr_fun) z_InternationalString, &(*p)->nicknames,
+		  &(*p)->num_nicknames, "nicknames") || odr_ok(o)) &&
+		odr_implicit_tag (o, z_HumanString,
+			&(*p)->usageRest, ODR_CONTEXT, 14, 1, "usageRest") &&
+		odr_implicit_tag (o, z_HumanString,
+			&(*p)->paymentAddr, ODR_CONTEXT, 15, 1, "paymentAddr") &&
+		odr_implicit_tag (o, z_HumanString,
+			&(*p)->hours, ODR_CONTEXT, 16, 1, "hours") &&
+		odr_implicit_settag (o, ODR_CONTEXT, 17) &&
+		(odr_sequence_of(o, (Odr_fun) z_DatabaseList, &(*p)->dbCombinations,
+		  &(*p)->num_dbCombinations, "dbCombinations") || odr_ok(o)) &&
+		odr_implicit_settag (o, ODR_CONTEXT, 18) &&
+		(odr_sequence_of(o, (Odr_fun) z_NetworkAddress, &(*p)->addresses,
+		  &(*p)->num_addresses, "addresses") || odr_ok(o)) &&
+		odr_implicit_settag (o, ODR_CONTEXT, 101) &&
+		(odr_sequence_of(o, (Odr_fun) z_InternationalString, &(*p)->languages,
+		  &(*p)->num_languages, "languages") || odr_ok(o)) &&
+		odr_implicit_tag (o, z_AccessInfo,
+			&(*p)->commonAccessInfo, ODR_CONTEXT, 19, 1, "commonAccessInfo") &&
+		odr_sequence_end (o);
+}
+
+int z_DatabaseInfo (ODR o, Z_DatabaseInfo **p, int opt, const char *name)
+{
+	static Odr_arm arm[] = {
+		{ODR_IMPLICIT, ODR_CONTEXT, 0, Z_DatabaseInfo_actualNumber,
+		(Odr_fun) odr_integer, "actualNumber"},
+		{ODR_IMPLICIT, ODR_CONTEXT, 1, Z_DatabaseInfo_approxNumber,
+		(Odr_fun) odr_integer, "approxNumber"},
+		{-1, -1, -1, -1, (Odr_fun) 0, 0}
+	};
+	if (!odr_sequence_begin (o, p, sizeof(**p), name))
+		return opt && odr_ok (o);
+	return
+		odr_implicit_tag (o, z_CommonInfo,
+			&(*p)->commonInfo, ODR_CONTEXT, 0, 1, "commonInfo") &&
+		odr_implicit_tag (o, z_DatabaseName,
+			&(*p)->name, ODR_CONTEXT, 1, 0, "name") &&
+		odr_implicit_tag (o, odr_null,
+			&(*p)->explainDatabase, ODR_CONTEXT, 2, 1, "explainDatabase") &&
+		odr_implicit_settag (o, ODR_CONTEXT, 3) &&
+		(odr_sequence_of(o, (Odr_fun) z_DatabaseName, &(*p)->nicknames,
+		  &(*p)->num_nicknames, "nicknames") || odr_ok(o)) &&
+		odr_implicit_tag (o, z_IconObject,
+			&(*p)->icon, ODR_CONTEXT, 4, 1, "icon") &&
+		odr_implicit_tag (o, odr_bool,
+			&(*p)->userFee, ODR_CONTEXT, 5, 0, "userFee") &&
+		odr_implicit_tag (o, odr_bool,
+			&(*p)->available, ODR_CONTEXT, 6, 0, "available") &&
+		odr_implicit_tag (o, z_HumanString,
+			&(*p)->titleString, ODR_CONTEXT, 7, 1, "titleString") &&
+		odr_implicit_settag (o, ODR_CONTEXT, 8) &&
+		(odr_sequence_of(o, (Odr_fun) z_HumanString, &(*p)->keywords,
+		  &(*p)->num_keywords, "keywords") || odr_ok(o)) &&
+		odr_implicit_tag (o, z_HumanString,
+			&(*p)->description, ODR_CONTEXT, 9, 1, "description") &&
+		odr_implicit_tag (o, z_DatabaseList,
+			&(*p)->associatedDbs, ODR_CONTEXT, 10, 1, "associatedDbs") &&
+		odr_implicit_tag (o, z_DatabaseList,
+			&(*p)->subDbs, ODR_CONTEXT, 11, 1, "subDbs") &&
+		odr_implicit_tag (o, z_HumanString,
+			&(*p)->disclaimers, ODR_CONTEXT, 12, 1, "disclaimers") &&
+		odr_implicit_tag (o, z_HumanString,
+			&(*p)->news, ODR_CONTEXT, 13, 1, "news") &&
+		((odr_constructed_begin (o, &(*p)->u, ODR_CONTEXT, 14, "recordCount") &&
+		odr_choice (o, arm, &(*p)->u, &(*p)->which, 0) &&
+		odr_constructed_end (o)) || odr_ok(o)) &&
+		odr_implicit_tag (o, z_HumanString,
+			&(*p)->defaultOrder, ODR_CONTEXT, 15, 1, "defaultOrder") &&
+		odr_implicit_tag (o, odr_integer,
+			&(*p)->avRecordSize, ODR_CONTEXT, 16, 1, "avRecordSize") &&
+		odr_implicit_tag (o, odr_integer,
+			&(*p)->maxRecordSize, ODR_CONTEXT, 17, 1, "maxRecordSize") &&
+		odr_implicit_tag (o, z_HumanString,
+			&(*p)->hours, ODR_CONTEXT, 18, 1, "hours") &&
+		odr_implicit_tag (o, z_HumanString,
+			&(*p)->bestTime, ODR_CONTEXT, 19, 1, "bestTime") &&
+		odr_implicit_tag (o, odr_generalizedtime,
+			&(*p)->lastUpdate, ODR_CONTEXT, 20, 1, "lastUpdate") &&
+		odr_implicit_tag (o, z_IntUnit,
+			&(*p)->updateInterval, ODR_CONTEXT, 21, 1, "updateInterval") &&
+		odr_implicit_tag (o, z_HumanString,
+			&(*p)->coverage, ODR_CONTEXT, 22, 1, "coverage") &&
+		odr_implicit_tag (o, odr_bool,
+			&(*p)->proprietary, ODR_CONTEXT, 23, 1, "proprietary") &&
+		odr_implicit_tag (o, z_HumanString,
+			&(*p)->copyrightText, ODR_CONTEXT, 24, 1, "copyrightText") &&
+		odr_implicit_tag (o, z_HumanString,
+			&(*p)->copyrightNotice, ODR_CONTEXT, 25, 1, "copyrightNotice") &&
+		odr_implicit_tag (o, z_ContactInfo,
+			&(*p)->producerContactInfo, ODR_CONTEXT, 26, 1, "producerContactInfo") &&
+		odr_implicit_tag (o, z_ContactInfo,
+			&(*p)->supplierContactInfo, ODR_CONTEXT, 27, 1, "supplierContactInfo") &&
+		odr_implicit_tag (o, z_ContactInfo,
+			&(*p)->submissionContactInfo, ODR_CONTEXT, 28, 1, "submissionContactInfo") &&
+		odr_implicit_tag (o, z_AccessInfo,
+			&(*p)->accessInfo, ODR_CONTEXT, 29, 1, "accessInfo") &&
+		odr_sequence_end (o);
+}
+
+int z_TagTypeMapping (ODR o, Z_TagTypeMapping **p, int opt, const char *name)
+{
+	if (!odr_sequence_begin (o, p, sizeof(**p), name))
+		return opt && odr_ok (o);
+	return
+		odr_implicit_tag (o, odr_integer,
+			&(*p)->tagType, ODR_CONTEXT, 0, 0, "tagType") &&
+		odr_implicit_tag (o, odr_oid,
+			&(*p)->tagSet, ODR_CONTEXT, 1, 1, "tagSet") &&
+		odr_implicit_tag (o, odr_null,
+			&(*p)->defaultTagType, ODR_CONTEXT, 2, 1, "defaultTagType") &&
+		odr_sequence_end (o);
+}
+
+int z_SchemaInfo (ODR o, Z_SchemaInfo **p, int opt, const char *name)
+{
+	if (!odr_sequence_begin (o, p, sizeof(**p), name))
+		return opt && odr_ok (o);
+	return
+		odr_implicit_tag (o, z_CommonInfo,
+			&(*p)->commonInfo, ODR_CONTEXT, 0, 1, "commonInfo") &&
+		odr_implicit_tag (o, odr_oid,
+			&(*p)->schema, ODR_CONTEXT, 1, 0, "schema") &&
+		odr_implicit_tag (o, z_InternationalString,
+			&(*p)->name, ODR_CONTEXT, 2, 0, "name") &&
+		odr_implicit_tag (o, z_HumanString,
+			&(*p)->description, ODR_CONTEXT, 3, 1, "description") &&
+		odr_implicit_settag (o, ODR_CONTEXT, 4) &&
+		(odr_sequence_of(o, (Odr_fun) z_TagTypeMapping, &(*p)->tagTypeMapping,
+		  &(*p)->num_tagTypeMapping, "tagTypeMapping") || odr_ok(o)) &&
+		odr_implicit_settag (o, ODR_CONTEXT, 5) &&
+		(odr_sequence_of(o, (Odr_fun) z_ElementInfo, &(*p)->recordStructure,
+		  &(*p)->num_recordStructure, "recordStructure") || odr_ok(o)) &&
+		odr_sequence_end (o);
+}
+
+int z_ElementInfo (ODR o, Z_ElementInfo **p, int opt, const char *name)
+{
+	if (!odr_sequence_begin (o, p, sizeof(**p), name))
+		return opt && odr_ok (o);
+	return
+		odr_implicit_tag (o, z_InternationalString,
+			&(*p)->elementName, ODR_CONTEXT, 1, 0, "elementName") &&
+		odr_implicit_tag (o, z_Path,
+			&(*p)->elementTagPath, ODR_CONTEXT, 2, 0, "elementTagPath") &&
+		odr_explicit_tag (o, z_ElementDataType,
+			&(*p)->dataType, ODR_CONTEXT, 3, 1, "dataType") &&
+		odr_implicit_tag (o, odr_bool,
+			&(*p)->required, ODR_CONTEXT, 4, 0, "required") &&
+		odr_implicit_tag (o, odr_bool,
+			&(*p)->repeatable, ODR_CONTEXT, 5, 0, "repeatable") &&
+		odr_implicit_tag (o, z_HumanString,
+			&(*p)->description, ODR_CONTEXT, 6, 1, "description") &&
+		odr_sequence_end (o);
+}
+
+int z_PathUnit (ODR o, Z_PathUnit **p, int opt, const char *name)
+{
+	if (!odr_sequence_begin (o, p, sizeof(**p), name))
+		return opt && odr_ok (o);
+	return
+		odr_implicit_tag (o, odr_integer,
+			&(*p)->tagType, ODR_CONTEXT, 1, 0, "tagType") &&
+		odr_explicit_tag (o, z_StringOrNumeric,
+			&(*p)->tagValue, ODR_CONTEXT, 2, 0, "tagValue") &&
+		odr_sequence_end (o);
+}
+
+int z_Path (ODR o, Z_Path **p, int opt, const char *name)
+{
+	if (!odr_initmember (o, p, sizeof(**p)))
+		return opt && odr_ok(o);
+	if (odr_sequence_of (o, (Odr_fun) z_PathUnit, &(*p)->elements,
+		&(*p)->num, name))
+		return 1;
+	*p = 0;
+	return opt && odr_ok(o);
+}
+
+int z_ElementInfoList (ODR o, Z_ElementInfoList **p, int opt, const char *name)
+{
+	if (!odr_initmember (o, p, sizeof(**p)))
+		return opt && odr_ok(o);
+	if (odr_sequence_of (o, (Odr_fun) z_ElementInfo, &(*p)->elements,
+		&(*p)->num, name))
+		return 1;
+	*p = 0;
+	return opt && odr_ok(o);
+}
+
+int z_ElementDataType (ODR o, Z_ElementDataType **p, int opt, const char *name)
+{
+	static Odr_arm arm[] = {
+		{ODR_IMPLICIT, ODR_CONTEXT, 0, Z_ElementDataType_primitive,
+		(Odr_fun) z_PrimitiveDataType, "primitive"},
+		{ODR_IMPLICIT, ODR_CONTEXT, 1, Z_ElementDataType_structured,
+		(Odr_fun) z_ElementInfoList, "structured"},
+		{-1, -1, -1, -1, (Odr_fun) 0, 0}
+	};
+	if (!odr_initmember(o, p, sizeof(**p)))
+		return opt && odr_ok(o);
+	if (odr_choice(o, arm, &(*p)->u, &(*p)->which, name))
+		return 1;
+	*p = 0;
+	return opt && odr_ok(o);
+}
+
+int z_PrimitiveDataType (ODR o, Z_PrimitiveDataType **p, int opt, const char *name)
+{
+	return odr_integer (o, p, opt, name);
+}
+
+int z_TagSetElements (ODR o, Z_TagSetElements **p, int opt, const char *name)
+{
+	if (!odr_sequence_begin (o, p, sizeof(**p), name))
+		return opt && odr_ok (o);
+	return
+		odr_implicit_tag (o, z_InternationalString,
+			&(*p)->elementname, ODR_CONTEXT, 1, 0, "elementname") &&
+		odr_implicit_settag (o, ODR_CONTEXT, 2) &&
+		(odr_sequence_of(o, (Odr_fun) z_InternationalString, &(*p)->nicknames,
+		  &(*p)->num_nicknames, "nicknames") || odr_ok(o)) &&
+		odr_explicit_tag (o, z_StringOrNumeric,
+			&(*p)->elementTag, ODR_CONTEXT, 3, 0, "elementTag") &&
+		odr_implicit_tag (o, z_HumanString,
+			&(*p)->description, ODR_CONTEXT, 4, 1, "description") &&
+		odr_explicit_tag (o, z_PrimitiveDataType,
+			&(*p)->dataType, ODR_CONTEXT, 5, 1, "dataType") &&
+		z_OtherInformation(o, &(*p)->otherTagInfo, 1, "otherTagInfo") &&
+		odr_sequence_end (o);
+}
+
+int z_TagSetInfo (ODR o, Z_TagSetInfo **p, int opt, const char *name)
+{
+	if (!odr_sequence_begin (o, p, sizeof(**p), name))
+		return opt && odr_ok (o);
+	return
+		odr_implicit_tag (o, z_CommonInfo,
+			&(*p)->commonInfo, ODR_CONTEXT, 0, 1, "commonInfo") &&
+		odr_implicit_tag (o, odr_oid,
+			&(*p)->tagSet, ODR_CONTEXT, 1, 0, "tagSet") &&
+		odr_implicit_tag (o, z_InternationalString,
+			&(*p)->name, ODR_CONTEXT, 2, 0, "name") &&
+		odr_implicit_tag (o, z_HumanString,
+			&(*p)->description, ODR_CONTEXT, 3, 1, "description") &&
+		odr_implicit_settag (o, ODR_CONTEXT, 4) &&
+		(odr_sequence_of(o, (Odr_fun) z_TagSetElements, &(*p)->elements,
+		  &(*p)->num_elements, "elements") || odr_ok(o)) &&
+		odr_sequence_end (o);
+}
+
+int z_RecordSyntaxInfo (ODR o, Z_RecordSyntaxInfo **p, int opt, const char *name)
+{
+	if (!odr_sequence_begin (o, p, sizeof(**p), name))
+		return opt && odr_ok (o);
+	return
+		odr_implicit_tag (o, z_CommonInfo,
+			&(*p)->commonInfo, ODR_CONTEXT, 0, 1, "commonInfo") &&
+		odr_implicit_tag (o, odr_oid,
+			&(*p)->recordSyntax, ODR_CONTEXT, 1, 0, "recordSyntax") &&
+		odr_implicit_tag (o, z_InternationalString,
+			&(*p)->name, ODR_CONTEXT, 2, 0, "name") &&
+		odr_implicit_settag (o, ODR_CONTEXT, 3) &&
+		(odr_sequence_of(o, (Odr_fun) odr_oid, &(*p)->transferSyntaxes,
+		  &(*p)->num_transferSyntaxes, "transferSyntaxes") || odr_ok(o)) &&
+		odr_implicit_tag (o, z_HumanString,
+			&(*p)->description, ODR_CONTEXT, 4, 1, "description") &&
+		odr_implicit_tag (o, z_InternationalString,
+			&(*p)->asn1Module, ODR_CONTEXT, 5, 1, "asn1Module") &&
+		odr_implicit_settag (o, ODR_CONTEXT, 6) &&
+		(odr_sequence_of(o, (Odr_fun) z_ElementInfo, &(*p)->abstractStructure,
+		  &(*p)->num_abstractStructure, "abstractStructure") || odr_ok(o)) &&
+		odr_sequence_end (o);
+}
+
+int z_AttributeSetInfo (ODR o, Z_AttributeSetInfo **p, int opt, const char *name)
+{
+	if (!odr_sequence_begin (o, p, sizeof(**p), name))
+		return opt && odr_ok (o);
+	return
+		odr_implicit_tag (o, z_CommonInfo,
+			&(*p)->commonInfo, ODR_CONTEXT, 0, 1, "commonInfo") &&
+		odr_implicit_tag (o, z_AttributeSetId,
+			&(*p)->attributeSet, ODR_CONTEXT, 1, 0, "attributeSet") &&
+		odr_implicit_tag (o, z_InternationalString,
+			&(*p)->name, ODR_CONTEXT, 2, 0, "name") &&
+		odr_implicit_settag (o, ODR_CONTEXT, 3) &&
+		(odr_sequence_of(o, (Odr_fun) z_AttributeType, &(*p)->attributes,
+		  &(*p)->num_attributes, "attributes") || odr_ok(o)) &&
+		odr_implicit_tag (o, z_HumanString,
+			&(*p)->description, ODR_CONTEXT, 4, 1, "description") &&
+		odr_sequence_end (o);
+}
+
+int z_AttributeType (ODR o, Z_AttributeType **p, int opt, const char *name)
+{
+	if (!odr_sequence_begin (o, p, sizeof(**p), name))
+		return opt && odr_ok (o);
+	return
+		odr_implicit_tag (o, z_InternationalString,
+			&(*p)->name, ODR_CONTEXT, 0, 1, "name") &&
+		odr_implicit_tag (o, z_HumanString,
+			&(*p)->description, ODR_CONTEXT, 1, 1, "description") &&
+		odr_implicit_tag (o, odr_integer,
+			&(*p)->attributeType, ODR_CONTEXT, 2, 0, "attributeType") &&
+		odr_implicit_settag (o, ODR_CONTEXT, 3) &&
+		odr_sequence_of(o, (Odr_fun) z_AttributeDescription, &(*p)->attributeValues,
+		  &(*p)->num_attributeValues, "attributeValues") &&
+		odr_sequence_end (o);
+}
+
+int z_AttributeDescription (ODR o, Z_AttributeDescription **p, int opt, const char *name)
+{
+	if (!odr_sequence_begin (o, p, sizeof(**p), name))
+		return opt && odr_ok (o);
+	return
+		odr_implicit_tag (o, z_InternationalString,
+			&(*p)->name, ODR_CONTEXT, 0, 1, "name") &&
+		odr_implicit_tag (o, z_HumanString,
+			&(*p)->description, ODR_CONTEXT, 1, 1, "description") &&
+		odr_explicit_tag (o, z_StringOrNumeric,
+			&(*p)->attributeValue, ODR_CONTEXT, 2, 0, "attributeValue") &&
+		odr_implicit_settag (o, ODR_CONTEXT, 3) &&
+		(odr_sequence_of(o, (Odr_fun) z_StringOrNumeric, &(*p)->equivalentAttributes,
+		  &(*p)->num_equivalentAttributes, "equivalentAttributes") || odr_ok(o)) &&
+		odr_sequence_end (o);
+}
+
+int z_TermListElement (ODR o, Z_TermListElement **p, int opt, const char *name)
+{
+	if (!odr_sequence_begin (o, p, sizeof(**p), name))
+		return opt && odr_ok (o);
+	return
+		odr_implicit_tag (o, z_InternationalString,
+			&(*p)->name, ODR_CONTEXT, 1, 0, "name") &&
+		odr_implicit_tag (o, z_HumanString,
+			&(*p)->title, ODR_CONTEXT, 2, 1, "title") &&
+		odr_implicit_tag (o, odr_integer,
+			&(*p)->searchCost, ODR_CONTEXT, 3, 1, "searchCost") &&
+		odr_implicit_tag (o, odr_bool,
+			&(*p)->scanable, ODR_CONTEXT, 4, 0, "scanable") &&
+		odr_implicit_settag (o, ODR_CONTEXT, 5) &&
+		(odr_sequence_of(o, (Odr_fun) z_InternationalString, &(*p)->broader,
+		  &(*p)->num_broader, "broader") || odr_ok(o)) &&
+		odr_implicit_settag (o, ODR_CONTEXT, 6) &&
+		(odr_sequence_of(o, (Odr_fun) z_InternationalString, &(*p)->narrower,
+		  &(*p)->num_narrower, "narrower") || odr_ok(o)) &&
+		odr_sequence_end (o);
+}
+
+int z_TermListInfo (ODR o, Z_TermListInfo **p, int opt, const char *name)
+{
+	if (!odr_sequence_begin (o, p, sizeof(**p), name))
+		return opt && odr_ok (o);
+	return
+		odr_implicit_tag (o, z_CommonInfo,
+			&(*p)->commonInfo, ODR_CONTEXT, 0, 1, "commonInfo") &&
+		odr_implicit_tag (o, z_DatabaseName,
+			&(*p)->databaseName, ODR_CONTEXT, 1, 0, "databaseName") &&
+		odr_implicit_settag (o, ODR_CONTEXT, 2) &&
+		odr_sequence_of(o, (Odr_fun) z_TermListElement, &(*p)->termLists,
+		  &(*p)->num_termLists, "termLists") &&
+		odr_sequence_end (o);
+}
+
+int z_ExtendedServicesInfo (ODR o, Z_ExtendedServicesInfo **p, int opt, const char *name)
+{
+	if (!odr_sequence_begin (o, p, sizeof(**p), name))
+		return opt && odr_ok (o);
+	return
+		odr_implicit_tag (o, z_CommonInfo,
+			&(*p)->commonInfo, ODR_CONTEXT, 0, 1, "commonInfo") &&
+		odr_implicit_tag (o, odr_oid,
+			&(*p)->type, ODR_CONTEXT, 1, 0, "type") &&
+		odr_implicit_tag (o, z_InternationalString,
+			&(*p)->name, ODR_CONTEXT, 2, 1, "name") &&
+		odr_implicit_tag (o, odr_bool,
+			&(*p)->privateType, ODR_CONTEXT, 3, 0, "privateType") &&
+		odr_implicit_tag (o, odr_bool,
+			&(*p)->restrictionsApply, ODR_CONTEXT, 5, 0, "restrictionsApply") &&
+		odr_implicit_tag (o, odr_bool,
+			&(*p)->feeApply, ODR_CONTEXT, 6, 0, "feeApply") &&
+		odr_implicit_tag (o, odr_bool,
+			&(*p)->available, ODR_CONTEXT, 7, 0, "available") &&
+		odr_implicit_tag (o, odr_bool,
+			&(*p)->retentionSupported, ODR_CONTEXT, 8, 0, "retentionSupported") &&
+		odr_implicit_tag (o, odr_integer,
+			&(*p)->waitAction, ODR_CONTEXT, 9, 0, "waitAction") &&
+		odr_implicit_tag (o, z_HumanString,
+			&(*p)->description, ODR_CONTEXT, 10, 1, "description") &&
+		odr_implicit_tag (o, z_External,
+			&(*p)->specificExplain, ODR_CONTEXT, 11, 1, "specificExplain") &&
+		odr_implicit_tag (o, z_InternationalString,
+			&(*p)->esASN, ODR_CONTEXT, 12, 1, "esASN") &&
+		odr_sequence_end (o);
+}
+
+int z_AttributeDetails (ODR o, Z_AttributeDetails **p, int opt, const char *name)
+{
+	if (!odr_sequence_begin (o, p, sizeof(**p), name))
+		return opt && odr_ok (o);
+	return
+		odr_implicit_tag (o, z_CommonInfo,
+			&(*p)->commonInfo, ODR_CONTEXT, 0, 1, "commonInfo") &&
+		odr_implicit_tag (o, z_DatabaseName,
+			&(*p)->databaseName, ODR_CONTEXT, 1, 0, "databaseName") &&
+		odr_implicit_settag (o, ODR_CONTEXT, 2) &&
+		(odr_sequence_of(o, (Odr_fun) z_AttributeSetDetails, &(*p)->attributesBySet,
+		  &(*p)->num_attributesBySet, "attributesBySet") || odr_ok(o)) &&
+		odr_implicit_tag (o, z_AttributeCombinations,
+			&(*p)->attributeCombinations, ODR_CONTEXT, 3, 1, "attributeCombinations") &&
+		odr_sequence_end (o);
+}
+
+int z_AttributeSetDetails (ODR o, Z_AttributeSetDetails **p, int opt, const char *name)
+{
+	if (!odr_sequence_begin (o, p, sizeof(**p), name))
+		return opt && odr_ok (o);
+	return
+		odr_implicit_tag (o, z_AttributeSetId,
+			&(*p)->attributeSet, ODR_CONTEXT, 0, 0, "attributeSet") &&
+		odr_implicit_settag (o, ODR_CONTEXT, 1) &&
+		odr_sequence_of(o, (Odr_fun) z_AttributeTypeDetails, &(*p)->attributesByType,
+		  &(*p)->num_attributesByType, "attributesByType") &&
+		odr_sequence_end (o);
+}
+
+int z_AttributeTypeDetails (ODR o, Z_AttributeTypeDetails **p, int opt, const char *name)
+{
+	if (!odr_sequence_begin (o, p, sizeof(**p), name))
+		return opt && odr_ok (o);
+	return
+		odr_implicit_tag (o, odr_integer,
+			&(*p)->attributeType, ODR_CONTEXT, 0, 0, "attributeType") &&
+		odr_implicit_tag (o, z_OmittedAttributeInterpretation,
+			&(*p)->defaultIfOmitted, ODR_CONTEXT, 1, 1, "defaultIfOmitted") &&
+		odr_implicit_settag (o, ODR_CONTEXT, 2) &&
+		(odr_sequence_of(o, (Odr_fun) z_AttributeValue, &(*p)->attributeValues,
+		  &(*p)->num_attributeValues, "attributeValues") || odr_ok(o)) &&
+		odr_sequence_end (o);
+}
+
+int z_OmittedAttributeInterpretation (ODR o, Z_OmittedAttributeInterpretation **p, int opt, const char *name)
+{
+	if (!odr_sequence_begin (o, p, sizeof(**p), name))
+		return opt && odr_ok (o);
+	return
+		odr_explicit_tag (o, z_StringOrNumeric,
+			&(*p)->defaultValue, ODR_CONTEXT, 0, 1, "defaultValue") &&
+		odr_implicit_tag (o, z_HumanString,
+			&(*p)->defaultDescription, ODR_CONTEXT, 1, 1, "defaultDescription") &&
+		odr_sequence_end (o);
+}
+
+int z_AttributeValue (ODR o, Z_AttributeValue **p, int opt, const char *name)
+{
+	if (!odr_sequence_begin (o, p, sizeof(**p), name))
+		return opt && odr_ok (o);
+	return
+		odr_explicit_tag (o, z_StringOrNumeric,
+			&(*p)->value, ODR_CONTEXT, 0, 0, "value") &&
+		odr_implicit_tag (o, z_HumanString,
+			&(*p)->description, ODR_CONTEXT, 1, 1, "description") &&
+		odr_implicit_settag (o, ODR_CONTEXT, 2) &&
+		(odr_sequence_of(o, (Odr_fun) z_StringOrNumeric, &(*p)->subAttributes,
+		  &(*p)->num_subAttributes, "subAttributes") || odr_ok(o)) &&
+		odr_implicit_settag (o, ODR_CONTEXT, 3) &&
+		(odr_sequence_of(o, (Odr_fun) z_StringOrNumeric, &(*p)->superAttributes,
+		  &(*p)->num_superAttributes, "superAttributes") || odr_ok(o)) &&
+		odr_implicit_tag (o, odr_null,
+			&(*p)->partialSupport, ODR_CONTEXT, 4, 1, "partialSupport") &&
+		odr_sequence_end (o);
+}
+
+int z_EScanInfo (ODR o, Z_EScanInfo **p, int opt, const char *name)
+{
+	if (!odr_sequence_begin (o, p, sizeof(**p), name))
+		return opt && odr_ok (o);
+	return
+		odr_implicit_tag (o, odr_integer,
+			&(*p)->maxStepSize, ODR_CONTEXT, 0, 1, "maxStepSize") &&
+		odr_implicit_tag (o, z_HumanString,
+			&(*p)->collatingSequence, ODR_CONTEXT, 1, 1, "collatingSequence") &&
+		odr_implicit_tag (o, odr_bool,
+			&(*p)->increasing, ODR_CONTEXT, 2, 1, "increasing") &&
+		odr_sequence_end (o);
+}
+
+int z_TermListDetails (ODR o, Z_TermListDetails **p, int opt, const char *name)
+{
+	if (!odr_sequence_begin (o, p, sizeof(**p), name))
+		return opt && odr_ok (o);
+	return
+		odr_implicit_tag (o, z_CommonInfo,
+			&(*p)->commonInfo, ODR_CONTEXT, 0, 1, "commonInfo") &&
+		odr_implicit_tag (o, z_InternationalString,
+			&(*p)->termListName, ODR_CONTEXT, 1, 0, "termListName") &&
+		odr_implicit_tag (o, z_HumanString,
+			&(*p)->description, ODR_CONTEXT, 2, 1, "description") &&
+		odr_implicit_tag (o, z_AttributeCombinations,
+			&(*p)->attributes, ODR_CONTEXT, 3, 1, "attributes") &&
+		odr_implicit_tag (o, z_EScanInfo,
+			&(*p)->scanInfo, ODR_CONTEXT, 4, 1, "scanInfo") &&
+		odr_implicit_tag (o, odr_integer,
+			&(*p)->estNumberTerms, ODR_CONTEXT, 5, 1, "estNumberTerms") &&
+		odr_implicit_settag (o, ODR_CONTEXT, 6) &&
+		(odr_sequence_of(o, (Odr_fun) z_Term, &(*p)->sampleTerms,
+		  &(*p)->num_sampleTerms, "sampleTerms") || odr_ok(o)) &&
+		odr_sequence_end (o);
+}
+
+int z_ElementSetDetails (ODR o, Z_ElementSetDetails **p, int opt, const char *name)
+{
+	if (!odr_sequence_begin (o, p, sizeof(**p), name))
+		return opt && odr_ok (o);
+	return
+		odr_implicit_tag (o, z_CommonInfo,
+			&(*p)->commonInfo, ODR_CONTEXT, 0, 1, "commonInfo") &&
+		odr_implicit_tag (o, z_DatabaseName,
+			&(*p)->databaseName, ODR_CONTEXT, 1, 0, "databaseName") &&
+		odr_implicit_tag (o, z_ElementSetName,
+			&(*p)->elementSetName, ODR_CONTEXT, 2, 0, "elementSetName") &&
+		odr_implicit_tag (o, odr_oid,
+			&(*p)->recordSyntax, ODR_CONTEXT, 3, 0, "recordSyntax") &&
+		odr_implicit_tag (o, odr_oid,
+			&(*p)->schema, ODR_CONTEXT, 4, 0, "schema") &&
+		odr_implicit_tag (o, z_HumanString,
+			&(*p)->description, ODR_CONTEXT, 5, 1, "description") &&
+		odr_implicit_settag (o, ODR_CONTEXT, 6) &&
+		(odr_sequence_of(o, (Odr_fun) z_PerElementDetails, &(*p)->detailsPerElement,
+		  &(*p)->num_detailsPerElement, "detailsPerElement") || odr_ok(o)) &&
+		odr_sequence_end (o);
+}
+
+int z_RetrievalRecordDetails (ODR o, Z_RetrievalRecordDetails **p, int opt, const char *name)
+{
+	if (!odr_sequence_begin (o, p, sizeof(**p), name))
+		return opt && odr_ok (o);
+	return
+		odr_implicit_tag (o, z_CommonInfo,
+			&(*p)->commonInfo, ODR_CONTEXT, 0, 1, "commonInfo") &&
+		odr_implicit_tag (o, z_DatabaseName,
+			&(*p)->databaseName, ODR_CONTEXT, 1, 0, "databaseName") &&
+		odr_implicit_tag (o, odr_oid,
+			&(*p)->schema, ODR_CONTEXT, 2, 0, "schema") &&
+		odr_implicit_tag (o, odr_oid,
+			&(*p)->recordSyntax, ODR_CONTEXT, 3, 0, "recordSyntax") &&
+		odr_implicit_tag (o, z_HumanString,
+			&(*p)->description, ODR_CONTEXT, 4, 1, "description") &&
+		odr_implicit_settag (o, ODR_CONTEXT, 5) &&
+		(odr_sequence_of(o, (Odr_fun) z_PerElementDetails, &(*p)->detailsPerElement,
+		  &(*p)->num_detailsPerElement, "detailsPerElement") || odr_ok(o)) &&
+		odr_sequence_end (o);
+}
+
+int z_PerElementDetails (ODR o, Z_PerElementDetails **p, int opt, const char *name)
+{
+	if (!odr_sequence_begin (o, p, sizeof(**p), name))
+		return opt && odr_ok (o);
+	return
+		odr_implicit_tag (o, z_InternationalString,
+			&(*p)->name, ODR_CONTEXT, 0, 1, "name") &&
+		odr_implicit_tag (o, z_RecordTag,
+			&(*p)->recordTag, ODR_CONTEXT, 1, 1, "recordTag") &&
+		odr_implicit_settag (o, ODR_CONTEXT, 2) &&
+		(odr_sequence_of(o, (Odr_fun) z_Path, &(*p)->schemaTags,
+		  &(*p)->num_schemaTags, "schemaTags") || odr_ok(o)) &&
+		odr_implicit_tag (o, odr_integer,
+			&(*p)->maxSize, ODR_CONTEXT, 3, 1, "maxSize") &&
+		odr_implicit_tag (o, odr_integer,
+			&(*p)->minSize, ODR_CONTEXT, 4, 1, "minSize") &&
+		odr_implicit_tag (o, odr_integer,
+			&(*p)->avgSize, ODR_CONTEXT, 5, 1, "avgSize") &&
+		odr_implicit_tag (o, odr_integer,
+			&(*p)->fixedSize, ODR_CONTEXT, 6, 1, "fixedSize") &&
+		odr_implicit_tag (o, odr_bool,
+			&(*p)->repeatable, ODR_CONTEXT, 8, 0, "repeatable") &&
+		odr_implicit_tag (o, odr_bool,
+			&(*p)->required, ODR_CONTEXT, 9, 0, "required") &&
+		odr_implicit_tag (o, z_HumanString,
+			&(*p)->description, ODR_CONTEXT, 12, 1, "description") &&
+		odr_implicit_tag (o, z_HumanString,
+			&(*p)->contents, ODR_CONTEXT, 13, 1, "contents") &&
+		odr_implicit_tag (o, z_HumanString,
+			&(*p)->billingInfo, ODR_CONTEXT, 14, 1, "billingInfo") &&
+		odr_implicit_tag (o, z_HumanString,
+			&(*p)->restrictions, ODR_CONTEXT, 15, 1, "restrictions") &&
+		odr_implicit_settag (o, ODR_CONTEXT, 16) &&
+		(odr_sequence_of(o, (Odr_fun) z_InternationalString, &(*p)->alternateNames,
+		  &(*p)->num_alternateNames, "alternateNames") || odr_ok(o)) &&
+		odr_implicit_settag (o, ODR_CONTEXT, 17) &&
+		(odr_sequence_of(o, (Odr_fun) z_InternationalString, &(*p)->genericNames,
+		  &(*p)->num_genericNames, "genericNames") || odr_ok(o)) &&
+		odr_implicit_tag (o, z_AttributeCombinations,
+			&(*p)->searchAccess, ODR_CONTEXT, 18, 1, "searchAccess") &&
+		odr_sequence_end (o);
+}
+
+int z_RecordTag (ODR o, Z_RecordTag **p, int opt, const char *name)
+{
+	if (!odr_sequence_begin (o, p, sizeof(**p), name))
+		return opt && odr_ok (o);
+	return
+		odr_explicit_tag (o, z_StringOrNumeric,
+			&(*p)->qualifier, ODR_CONTEXT, 0, 1, "qualifier") &&
+		odr_explicit_tag (o, z_StringOrNumeric,
+			&(*p)->tagValue, ODR_CONTEXT, 1, 0, "tagValue") &&
+		odr_sequence_end (o);
+}
+
+int z_SortDetails (ODR o, Z_SortDetails **p, int opt, const char *name)
+{
+	if (!odr_sequence_begin (o, p, sizeof(**p), name))
+		return opt && odr_ok (o);
+	return
+		odr_implicit_tag (o, z_CommonInfo,
+			&(*p)->commonInfo, ODR_CONTEXT, 0, 1, "commonInfo") &&
+		odr_implicit_tag (o, z_DatabaseName,
+			&(*p)->databaseName, ODR_CONTEXT, 1, 0, "databaseName") &&
+		odr_implicit_settag (o, ODR_CONTEXT, 2) &&
+		(odr_sequence_of(o, (Odr_fun) z_SortKeyDetails, &(*p)->sortKeys,
+		  &(*p)->num_sortKeys, "sortKeys") || odr_ok(o)) &&
+		odr_sequence_end (o);
+}
+
+int z_SortKeyDetails (ODR o, Z_SortKeyDetails **p, int opt, const char *name)
+{
+	static Odr_arm arm[] = {
+		{ODR_IMPLICIT, ODR_CONTEXT, 0, Z_SortKeyDetails_character,
+		(Odr_fun) odr_null, "character"},
+		{ODR_IMPLICIT, ODR_CONTEXT, 1, Z_SortKeyDetails_numeric,
+		(Odr_fun) odr_null, "numeric"},
+		{ODR_IMPLICIT, ODR_CONTEXT, 2, Z_SortKeyDetails_structured,
+		(Odr_fun) z_HumanString, "structured"},
+		{-1, -1, -1, -1, (Odr_fun) 0, 0}
+	};
+	if (!odr_sequence_begin (o, p, sizeof(**p), name))
+		return opt && odr_ok (o);
+	return
+		odr_implicit_tag (o, z_HumanString,
+			&(*p)->description, ODR_CONTEXT, 0, 1, "description") &&
+		odr_implicit_settag (o, ODR_CONTEXT, 1) &&
+		(odr_sequence_of(o, (Odr_fun) z_Specification, &(*p)->elementSpecifications,
+		  &(*p)->num_elementSpecifications, "elementSpecifications") || odr_ok(o)) &&
+		odr_implicit_tag (o, z_AttributeCombinations,
+			&(*p)->attributeSpecifications, ODR_CONTEXT, 2, 1, "attributeSpecifications") &&
+		((odr_constructed_begin (o, &(*p)->u, ODR_CONTEXT, 3, "sortType") &&
+		odr_choice (o, arm, &(*p)->u, &(*p)->which, 0) &&
+		odr_constructed_end (o)) || odr_ok(o)) &&
+		odr_implicit_tag (o, odr_integer,
+			&(*p)->caseSensitivity, ODR_CONTEXT, 4, 1, "caseSensitivity") &&
+		odr_sequence_end (o);
+}
+
+int z_ProcessingInformation (ODR o, Z_ProcessingInformation **p, int opt, const char *name)
+{
+	if (!odr_sequence_begin (o, p, sizeof(**p), name))
+		return opt && odr_ok (o);
+	return
+		odr_implicit_tag (o, z_CommonInfo,
+			&(*p)->commonInfo, ODR_CONTEXT, 0, 1, "commonInfo") &&
+		odr_implicit_tag (o, z_DatabaseName,
+			&(*p)->databaseName, ODR_CONTEXT, 1, 0, "databaseName") &&
+		odr_implicit_tag (o, odr_integer,
+			&(*p)->processingContext, ODR_CONTEXT, 2, 0, "processingContext") &&
+		odr_implicit_tag (o, z_InternationalString,
+			&(*p)->name, ODR_CONTEXT, 3, 0, "name") &&
+		odr_implicit_tag (o, odr_oid,
+			&(*p)->oid, ODR_CONTEXT, 4, 0, "oid") &&
+		odr_implicit_tag (o, z_HumanString,
+			&(*p)->description, ODR_CONTEXT, 5, 1, "description") &&
+		odr_implicit_tag (o, z_External,
+			&(*p)->instructions, ODR_CONTEXT, 6, 1, "instructions") &&
+		odr_sequence_end (o);
+}
+
+int z_VariantSetInfo (ODR o, Z_VariantSetInfo **p, int opt, const char *name)
+{
+	if (!odr_sequence_begin (o, p, sizeof(**p), name))
+		return opt && odr_ok (o);
+	return
+		odr_implicit_tag (o, z_CommonInfo,
+			&(*p)->commonInfo, ODR_CONTEXT, 0, 1, "commonInfo") &&
+		odr_implicit_tag (o, odr_oid,
+			&(*p)->variantSet, ODR_CONTEXT, 1, 0, "variantSet") &&
+		odr_implicit_tag (o, z_InternationalString,
+			&(*p)->name, ODR_CONTEXT, 2, 0, "name") &&
+		odr_implicit_settag (o, ODR_CONTEXT, 3) &&
+		(odr_sequence_of(o, (Odr_fun) z_VariantClass, &(*p)->variants,
+		  &(*p)->num_variants, "variants") || odr_ok(o)) &&
+		odr_sequence_end (o);
+}
+
+int z_VariantClass (ODR o, Z_VariantClass **p, int opt, const char *name)
+{
+	if (!odr_sequence_begin (o, p, sizeof(**p), name))
+		return opt && odr_ok (o);
+	return
+		odr_implicit_tag (o, z_InternationalString,
+			&(*p)->name, ODR_CONTEXT, 0, 1, "name") &&
+		odr_implicit_tag (o, z_HumanString,
+			&(*p)->description, ODR_CONTEXT, 1, 1, "description") &&
+		odr_implicit_tag (o, odr_integer,
+			&(*p)->variantClass, ODR_CONTEXT, 2, 0, "variantClass") &&
+		odr_implicit_settag (o, ODR_CONTEXT, 3) &&
+		odr_sequence_of(o, (Odr_fun) z_VariantType, &(*p)->variantTypes,
+		  &(*p)->num_variantTypes, "variantTypes") &&
+		odr_sequence_end (o);
+}
+
+int z_VariantType (ODR o, Z_VariantType **p, int opt, const char *name)
+{
+	if (!odr_sequence_begin (o, p, sizeof(**p), name))
+		return opt && odr_ok (o);
+	return
+		odr_implicit_tag (o, z_InternationalString,
+			&(*p)->name, ODR_CONTEXT, 0, 1, "name") &&
+		odr_implicit_tag (o, z_HumanString,
+			&(*p)->description, ODR_CONTEXT, 1, 1, "description") &&
+		odr_implicit_tag (o, odr_integer,
+			&(*p)->variantType, ODR_CONTEXT, 2, 0, "variantType") &&
+		odr_implicit_tag (o, z_VariantValue,
+			&(*p)->variantValue, ODR_CONTEXT, 3, 1, "variantValue") &&
+		odr_sequence_end (o);
+}
+
+int z_VariantValue (ODR o, Z_VariantValue **p, int opt, const char *name)
+{
+	if (!odr_sequence_begin (o, p, sizeof(**p), name))
+		return opt && odr_ok (o);
+	return
+		odr_explicit_tag (o, z_PrimitiveDataType,
+			&(*p)->dataType, ODR_CONTEXT, 0, 0, "dataType") &&
+		odr_explicit_tag (o, z_ValueSet,
+			&(*p)->values, ODR_CONTEXT, 1, 1, "values") &&
+		odr_sequence_end (o);
+}
+
+int z_ValueSetEnumerated (ODR o, Z_ValueSetEnumerated **p, int opt, const char *name)
+{
+	if (!odr_initmember (o, p, sizeof(**p)))
+		return opt && odr_ok(o);
+	if (odr_sequence_of (o, (Odr_fun) z_ValueDescription, &(*p)->elements,
+		&(*p)->num, name))
+		return 1;
+	*p = 0;
+	return opt && odr_ok(o);
+}
+
+int z_ValueSet (ODR o, Z_ValueSet **p, int opt, const char *name)
+{
+	static Odr_arm arm[] = {
+		{ODR_IMPLICIT, ODR_CONTEXT, 0, Z_ValueSet_range,
+		(Odr_fun) z_ValueRange, "range"},
+		{ODR_IMPLICIT, ODR_CONTEXT, 1, Z_ValueSet_enumerated,
+		(Odr_fun) z_ValueSetEnumerated, "enumerated"},
+		{-1, -1, -1, -1, (Odr_fun) 0, 0}
+	};
+	if (!odr_initmember(o, p, sizeof(**p)))
+		return opt && odr_ok(o);
+	if (odr_choice(o, arm, &(*p)->u, &(*p)->which, name))
+		return 1;
+	*p = 0;
+	return opt && odr_ok(o);
+}
+
+int z_ValueRange (ODR o, Z_ValueRange **p, int opt, const char *name)
+{
+	if (!odr_sequence_begin (o, p, sizeof(**p), name))
+		return opt && odr_ok (o);
+	return
+		odr_explicit_tag (o, z_ValueDescription,
+			&(*p)->lower, ODR_CONTEXT, 0, 1, "lower") &&
+		odr_explicit_tag (o, z_ValueDescription,
+			&(*p)->upper, ODR_CONTEXT, 1, 1, "upper") &&
+		odr_sequence_end (o);
+}
+
+int z_ValueDescription (ODR o, Z_ValueDescription **p, int opt, const char *name)
+{
+	static Odr_arm arm[] = {
+		{-1, -1, -1, Z_ValueDescription_integer,
+		 (Odr_fun) odr_integer, "integer"},
+		{-1, -1, -1, Z_ValueDescription_string,
+		 (Odr_fun) z_InternationalString, "string"},
+		{-1, -1, -1, Z_ValueDescription_octets,
+		 (Odr_fun) odr_octetstring, "octets"},
+		{-1, -1, -1, Z_ValueDescription_oid,
+		 (Odr_fun) odr_oid, "oid"},
+		{ODR_IMPLICIT, ODR_CONTEXT, 1, Z_ValueDescription_unit,
+		(Odr_fun) z_Unit, "unit"},
+		{ODR_IMPLICIT, ODR_CONTEXT, 2, Z_ValueDescription_valueAndUnit,
+		(Odr_fun) z_IntUnit, "valueAndUnit"},
+		{-1, -1, -1, -1, (Odr_fun) 0, 0}
+	};
+	if (!odr_initmember(o, p, sizeof(**p)))
+		return opt && odr_ok(o);
+	if (odr_choice(o, arm, &(*p)->u, &(*p)->which, name))
+		return 1;
+	*p = 0;
+	return opt && odr_ok(o);
+}
+
+int z_UnitInfo (ODR o, Z_UnitInfo **p, int opt, const char *name)
+{
+	if (!odr_sequence_begin (o, p, sizeof(**p), name))
+		return opt && odr_ok (o);
+	return
+		odr_implicit_tag (o, z_CommonInfo,
+			&(*p)->commonInfo, ODR_CONTEXT, 0, 1, "commonInfo") &&
+		odr_implicit_tag (o, z_InternationalString,
+			&(*p)->unitSystem, ODR_CONTEXT, 1, 0, "unitSystem") &&
+		odr_implicit_tag (o, z_HumanString,
+			&(*p)->description, ODR_CONTEXT, 2, 1, "description") &&
+		odr_implicit_settag (o, ODR_CONTEXT, 3) &&
+		(odr_sequence_of(o, (Odr_fun) z_UnitType, &(*p)->units,
+		  &(*p)->num_units, "units") || odr_ok(o)) &&
+		odr_sequence_end (o);
+}
+
+int z_UnitType (ODR o, Z_UnitType **p, int opt, const char *name)
+{
+	if (!odr_sequence_begin (o, p, sizeof(**p), name))
+		return opt && odr_ok (o);
+	return
+		odr_implicit_tag (o, z_InternationalString,
+			&(*p)->name, ODR_CONTEXT, 0, 1, "name") &&
+		odr_implicit_tag (o, z_HumanString,
+			&(*p)->description, ODR_CONTEXT, 1, 1, "description") &&
+		odr_explicit_tag (o, z_StringOrNumeric,
+			&(*p)->unitType, ODR_CONTEXT, 2, 0, "unitType") &&
+		odr_implicit_settag (o, ODR_CONTEXT, 3) &&
+		odr_sequence_of(o, (Odr_fun) z_Units, &(*p)->units,
+		  &(*p)->num_units, "units") &&
+		odr_sequence_end (o);
+}
+
+int z_Units (ODR o, Z_Units **p, int opt, const char *name)
+{
+	if (!odr_sequence_begin (o, p, sizeof(**p), name))
+		return opt && odr_ok (o);
+	return
+		odr_implicit_tag (o, z_InternationalString,
+			&(*p)->name, ODR_CONTEXT, 0, 1, "name") &&
+		odr_implicit_tag (o, z_HumanString,
+			&(*p)->description, ODR_CONTEXT, 1, 1, "description") &&
+		odr_explicit_tag (o, z_StringOrNumeric,
+			&(*p)->unit, ODR_CONTEXT, 2, 0, "unit") &&
+		odr_sequence_end (o);
+}
+
+int z_CategoryList (ODR o, Z_CategoryList **p, int opt, const char *name)
+{
+	if (!odr_sequence_begin (o, p, sizeof(**p), name))
+		return opt && odr_ok (o);
+	return
+		odr_implicit_tag (o, z_CommonInfo,
+			&(*p)->commonInfo, ODR_CONTEXT, 0, 1, "commonInfo") &&
+		odr_implicit_settag (o, ODR_CONTEXT, 1) &&
+		odr_sequence_of(o, (Odr_fun) z_CategoryInfo, &(*p)->categories,
+		  &(*p)->num_categories, "categories") &&
+		odr_sequence_end (o);
+}
+
+int z_CategoryInfo (ODR o, Z_CategoryInfo **p, int opt, const char *name)
+{
+	if (!odr_sequence_begin (o, p, sizeof(**p), name))
+		return opt && odr_ok (o);
+	return
+		odr_implicit_tag (o, z_InternationalString,
+			&(*p)->category, ODR_CONTEXT, 1, 0, "category") &&
+		odr_implicit_tag (o, z_InternationalString,
+			&(*p)->originalCategory, ODR_CONTEXT, 2, 1, "originalCategory") &&
+		odr_implicit_tag (o, z_HumanString,
+			&(*p)->description, ODR_CONTEXT, 3, 1, "description") &&
+		odr_implicit_tag (o, z_InternationalString,
+			&(*p)->asn1Module, ODR_CONTEXT, 4, 1, "asn1Module") &&
+		odr_sequence_end (o);
+}
+
+int z_CommonInfo (ODR o, Z_CommonInfo **p, int opt, const char *name)
+{
+	if (!odr_sequence_begin (o, p, sizeof(**p), name))
+		return opt && odr_ok (o);
+	return
+		odr_implicit_tag (o, odr_generalizedtime,
+			&(*p)->dateAdded, ODR_CONTEXT, 0, 1, "dateAdded") &&
+		odr_implicit_tag (o, odr_generalizedtime,
+			&(*p)->dateChanged, ODR_CONTEXT, 1, 1, "dateChanged") &&
+		odr_implicit_tag (o, odr_generalizedtime,
+			&(*p)->expiry, ODR_CONTEXT, 2, 1, "expiry") &&
+		odr_implicit_tag (o, z_LanguageCode,
+			&(*p)->humanStringLanguage, ODR_CONTEXT, 3, 1, "humanStringLanguage") &&
+		z_OtherInformation(o, &(*p)->otherInfo, 1, "otherInfo") &&
+		odr_sequence_end (o);
+}
+
+int z_HumanStringUnit (ODR o, Z_HumanStringUnit **p, int opt, const char *name)
+{
+	if (!odr_sequence_begin (o, p, sizeof(**p), name))
+		return opt && odr_ok (o);
+	return
+		odr_implicit_tag (o, z_LanguageCode,
+			&(*p)->language, ODR_CONTEXT, 0, 1, "language") &&
+		odr_implicit_tag (o, z_InternationalString,
+			&(*p)->text, ODR_CONTEXT, 1, 0, "text") &&
+		odr_sequence_end (o);
+}
+
+int z_HumanString (ODR o, Z_HumanString **p, int opt, const char *name)
+{
+	if (!odr_initmember (o, p, sizeof(**p)))
+		return opt && odr_ok(o);
+	if (odr_sequence_of (o, (Odr_fun) z_HumanStringUnit, &(*p)->strings,
+		&(*p)->num_strings, name))
+		return 1;
+	*p = 0;
+	return opt && odr_ok(o);
+}
+
+int z_IconObjectUnit (ODR o, Z_IconObjectUnit **p, int opt, const char *name)
+{
+	static Odr_arm arm[] = {
+		{ODR_IMPLICIT, ODR_CONTEXT, 1, Z_IconObjectUnit_ianaType,
+		(Odr_fun) z_InternationalString, "ianaType"},
+		{ODR_IMPLICIT, ODR_CONTEXT, 2, Z_IconObjectUnit_z3950type,
+		(Odr_fun) z_InternationalString, "z3950type"},
+		{ODR_IMPLICIT, ODR_CONTEXT, 3, Z_IconObjectUnit_otherType,
+		(Odr_fun) z_InternationalString, "otherType"},
+		{-1, -1, -1, -1, (Odr_fun) 0, 0}
+	};
+	if (!odr_sequence_begin (o, p, sizeof(**p), name))
+		return opt && odr_ok (o);
+	return
+		odr_constructed_begin (o, &(*p)->u, ODR_CONTEXT, 1, "bodyType") &&
+		odr_choice (o, arm, &(*p)->u, &(*p)->which, 0) &&
+		odr_constructed_end (o) &&
+		odr_implicit_tag (o, odr_octetstring,
+			&(*p)->content, ODR_CONTEXT, 2, 0, "content") &&
+		odr_sequence_end (o);
+}
+
+int z_IconObject (ODR o, Z_IconObject **p, int opt, const char *name)
+{
+	if (!odr_initmember (o, p, sizeof(**p)))
+		return opt && odr_ok(o);
+	if (odr_sequence_of (o, (Odr_fun) z_IconObjectUnit, &(*p)->elements,
+		&(*p)->num, name))
+		return 1;
+	*p = 0;
+	return opt && odr_ok(o);
+}
+
+int z_LanguageCode (ODR o, Z_LanguageCode **p, int opt, const char *name)
+{
+	return z_InternationalString (o, p, opt, name);
+}
+
+int z_ContactInfo (ODR o, Z_ContactInfo **p, int opt, const char *name)
+{
+	if (!odr_sequence_begin (o, p, sizeof(**p), name))
+		return opt && odr_ok (o);
+	return
+		odr_implicit_tag (o, z_InternationalString,
+			&(*p)->name, ODR_CONTEXT, 0, 1, "name") &&
+		odr_implicit_tag (o, z_HumanString,
+			&(*p)->description, ODR_CONTEXT, 1, 1, "description") &&
+		odr_implicit_tag (o, z_HumanString,
+			&(*p)->address, ODR_CONTEXT, 2, 1, "address") &&
+		odr_implicit_tag (o, z_InternationalString,
+			&(*p)->email, ODR_CONTEXT, 3, 1, "email") &&
+		odr_implicit_tag (o, z_InternationalString,
+			&(*p)->phone, ODR_CONTEXT, 4, 1, "phone") &&
+		odr_sequence_end (o);
+}
+
+int z_NetworkAddressIA (ODR o, Z_NetworkAddressIA **p, int opt, const char *name)
+{
+	if (!odr_sequence_begin (o, p, sizeof(**p), name))
+		return opt && odr_ok (o);
+	return
+		odr_implicit_tag (o, z_InternationalString,
+			&(*p)->hostAddress, ODR_CONTEXT, 0, 0, "hostAddress") &&
+		odr_implicit_tag (o, odr_integer,
+			&(*p)->port, ODR_CONTEXT, 1, 0, "port") &&
+		odr_sequence_end (o);
+}
+
+int z_NetworkAddressOPA (ODR o, Z_NetworkAddressOPA **p, int opt, const char *name)
+{
+	if (!odr_sequence_begin (o, p, sizeof(**p), name))
+		return opt && odr_ok (o);
+	return
+		odr_implicit_tag (o, z_InternationalString,
+			&(*p)->pSel, ODR_CONTEXT, 0, 0, "pSel") &&
+		odr_implicit_tag (o, z_InternationalString,
+			&(*p)->sSel, ODR_CONTEXT, 1, 1, "sSel") &&
+		odr_implicit_tag (o, z_InternationalString,
+			&(*p)->tSel, ODR_CONTEXT, 2, 1, "tSel") &&
+		odr_implicit_tag (o, z_InternationalString,
+			&(*p)->nSap, ODR_CONTEXT, 3, 0, "nSap") &&
+		odr_sequence_end (o);
+}
+
+int z_NetworkAddressOther (ODR o, Z_NetworkAddressOther **p, int opt, const char *name)
+{
+	if (!odr_sequence_begin (o, p, sizeof(**p), name))
+		return opt && odr_ok (o);
+	return
+		odr_implicit_tag (o, z_InternationalString,
+			&(*p)->type, ODR_CONTEXT, 0, 0, "type") &&
+		odr_implicit_tag (o, z_InternationalString,
+			&(*p)->address, ODR_CONTEXT, 1, 0, "address") &&
+		odr_sequence_end (o);
+}
+
+int z_NetworkAddress (ODR o, Z_NetworkAddress **p, int opt, const char *name)
+{
+	static Odr_arm arm[] = {
+		{ODR_IMPLICIT, ODR_CONTEXT, 0, Z_NetworkAddress_iA,
+		(Odr_fun) z_NetworkAddressIA, "internetAddress"},
+		{ODR_IMPLICIT, ODR_CONTEXT, 1, Z_NetworkAddress_oPA,
+		(Odr_fun) z_NetworkAddressOPA, "osiPresentationAddress"},
+		{ODR_IMPLICIT, ODR_CONTEXT, 2, Z_NetworkAddress_other,
+		(Odr_fun) z_NetworkAddressOther, "other"},
+		{-1, -1, -1, -1, (Odr_fun) 0, 0}
+	};
+	if (!odr_initmember(o, p, sizeof(**p)))
+		return opt && odr_ok(o);
+	if (odr_choice(o, arm, &(*p)->u, &(*p)->which, name))
+		return 1;
+	*p = 0;
+	return opt && odr_ok(o);
+}
+
+int z_AccessInfo (ODR o, Z_AccessInfo **p, int opt, const char *name)
+{
+	if (!odr_sequence_begin (o, p, sizeof(**p), name))
+		return opt && odr_ok (o);
+	return
+		odr_implicit_settag (o, ODR_CONTEXT, 0) &&
+		(odr_sequence_of(o, (Odr_fun) z_QueryTypeDetails, &(*p)->queryTypesSupported,
+		  &(*p)->num_queryTypesSupported, "queryTypesSupported") || odr_ok(o)) &&
+		odr_implicit_settag (o, ODR_CONTEXT, 1) &&
+		(odr_sequence_of(o, (Odr_fun) odr_oid, &(*p)->diagnosticsSets,
+		  &(*p)->num_diagnosticsSets, "diagnosticsSets") || odr_ok(o)) &&
+		odr_implicit_settag (o, ODR_CONTEXT, 2) &&
+		(odr_sequence_of(o, (Odr_fun) z_AttributeSetId, &(*p)->attributeSetIds,
+		  &(*p)->num_attributeSetIds, "attributeSetIds") || odr_ok(o)) &&
+		odr_implicit_settag (o, ODR_CONTEXT, 3) &&
+		(odr_sequence_of(o, (Odr_fun) odr_oid, &(*p)->schemas,
+		  &(*p)->num_schemas, "schemas") || odr_ok(o)) &&
+		odr_implicit_settag (o, ODR_CONTEXT, 4) &&
+		(odr_sequence_of(o, (Odr_fun) odr_oid, &(*p)->recordSyntaxes,
+		  &(*p)->num_recordSyntaxes, "recordSyntaxes") || odr_ok(o)) &&
+		odr_implicit_settag (o, ODR_CONTEXT, 5) &&
+		(odr_sequence_of(o, (Odr_fun) odr_oid, &(*p)->resourceChallenges,
+		  &(*p)->num_resourceChallenges, "resourceChallenges") || odr_ok(o)) &&
+		odr_implicit_tag (o, z_AccessRestrictions,
+			&(*p)->restrictedAccess, ODR_CONTEXT, 6, 1, "restrictedAccess") &&
+		odr_implicit_tag (o, z_Costs,
+			&(*p)->costInfo, ODR_CONTEXT, 8, 1, "costInfo") &&
+		odr_implicit_settag (o, ODR_CONTEXT, 9) &&
+		(odr_sequence_of(o, (Odr_fun) odr_oid, &(*p)->variantSets,
+		  &(*p)->num_variantSets, "variantSets") || odr_ok(o)) &&
+		odr_implicit_settag (o, ODR_CONTEXT, 10) &&
+		(odr_sequence_of(o, (Odr_fun) z_ElementSetName, &(*p)->elementSetNames,
+		  &(*p)->num_elementSetNames, "elementSetNames") || odr_ok(o)) &&
+		odr_implicit_settag (o, ODR_CONTEXT, 11) &&
+		odr_sequence_of(o, (Odr_fun) z_InternationalString, &(*p)->unitSystems,
+		  &(*p)->num_unitSystems, "unitSystems") &&
+		odr_sequence_end (o);
+}
+
+int z_QueryTypeDetails (ODR o, Z_QueryTypeDetails **p, int opt, const char *name)
+{
+	static Odr_arm arm[] = {
+		{ODR_IMPLICIT, ODR_CONTEXT, 0, Z_QueryTypeDetails_private,
+		(Odr_fun) z_PrivateCapabilities, "zprivate"},
+		{ODR_IMPLICIT, ODR_CONTEXT, 1, Z_QueryTypeDetails_rpn,
+		(Odr_fun) z_RpnCapabilities, "rpn"},
+		{ODR_IMPLICIT, ODR_CONTEXT, 2, Z_QueryTypeDetails_iso8777,
+		(Odr_fun) z_Iso8777Capabilities, "iso8777"},
+		{ODR_IMPLICIT, ODR_CONTEXT, 100, Z_QueryTypeDetails_z39_58,
+		(Odr_fun) z_HumanString, "z39_58"},
+		{ODR_IMPLICIT, ODR_CONTEXT, 101, Z_QueryTypeDetails_erpn,
+		(Odr_fun) z_RpnCapabilities, "erpn"},
+		{ODR_IMPLICIT, ODR_CONTEXT, 102, Z_QueryTypeDetails_rankedList,
+		(Odr_fun) z_HumanString, "rankedList"},
+		{-1, -1, -1, -1, (Odr_fun) 0, 0}
+	};
+	if (!odr_initmember(o, p, sizeof(**p)))
+		return opt && odr_ok(o);
+	if (odr_choice(o, arm, &(*p)->u, &(*p)->which, name))
+		return 1;
+	*p = 0;
+	return opt && odr_ok(o);
+}
+
+int z_PrivateCapOperator (ODR o, Z_PrivateCapOperator **p, int opt, const char *name)
+{
+	if (!odr_sequence_begin (o, p, sizeof(**p), name))
+		return opt && odr_ok (o);
+	return
+		odr_implicit_tag (o, z_InternationalString,
+			&(*p)->roperator, ODR_CONTEXT, 0, 0, "roperator") &&
+		odr_implicit_tag (o, z_HumanString,
+			&(*p)->description, ODR_CONTEXT, 1, 1, "description") &&
+		odr_sequence_end (o);
+}
+
+int z_PrivateCapabilities (ODR o, Z_PrivateCapabilities **p, int opt, const char *name)
+{
+	if (!odr_sequence_begin (o, p, sizeof(**p), name))
+		return opt && odr_ok (o);
+	return
+		odr_implicit_settag (o, ODR_CONTEXT, 0) &&
+		(odr_sequence_of(o, (Odr_fun) z_PrivateCapOperator, &(*p)->operators,
+		  &(*p)->num_operators, "operators") || odr_ok(o)) &&
+		odr_implicit_settag (o, ODR_CONTEXT, 1) &&
+		(odr_sequence_of(o, (Odr_fun) z_SearchKey, &(*p)->searchKeys,
+		  &(*p)->num_searchKeys, "searchKeys") || odr_ok(o)) &&
+		odr_implicit_settag (o, ODR_CONTEXT, 2) &&
+		(odr_sequence_of(o, (Odr_fun) z_HumanString, &(*p)->description,
+		  &(*p)->num_description, "description") || odr_ok(o)) &&
+		odr_sequence_end (o);
+}
+
+int z_RpnCapabilities (ODR o, Z_RpnCapabilities **p, int opt, const char *name)
+{
+	if (!odr_sequence_begin (o, p, sizeof(**p), name))
+		return opt && odr_ok (o);
+	return
+		odr_implicit_settag (o, ODR_CONTEXT, 0) &&
+		(odr_sequence_of(o, (Odr_fun) odr_integer, &(*p)->operators,
+		  &(*p)->num_operators, "operators") || odr_ok(o)) &&
+		odr_implicit_tag (o, odr_bool,
+			&(*p)->resultSetAsOperandSupported, ODR_CONTEXT, 1, 0, "resultSetAsOperandSupported") &&
+		odr_implicit_tag (o, odr_bool,
+			&(*p)->restrictionOperandSupported, ODR_CONTEXT, 2, 0, "restrictionOperandSupported") &&
+		odr_implicit_tag (o, z_ProximitySupport,
+			&(*p)->proximity, ODR_CONTEXT, 3, 1, "proximity") &&
+		odr_sequence_end (o);
+}
+
+int z_Iso8777Capabilities (ODR o, Z_Iso8777Capabilities **p, int opt, const char *name)
+{
+	if (!odr_sequence_begin (o, p, sizeof(**p), name))
+		return opt && odr_ok (o);
+	return
+		odr_implicit_settag (o, ODR_CONTEXT, 0) &&
+		odr_sequence_of(o, (Odr_fun) z_SearchKey, &(*p)->searchKeys,
+		  &(*p)->num_searchKeys, "searchKeys") &&
+		odr_implicit_tag (o, z_HumanString,
+			&(*p)->restrictions, ODR_CONTEXT, 1, 1, "restrictions") &&
+		odr_sequence_end (o);
+}
+
+int z_ProxSupportPrivate (ODR o, Z_ProxSupportPrivate **p, int opt, const char *name)
+{
+	if (!odr_sequence_begin (o, p, sizeof(**p), name))
+		return opt && odr_ok (o);
+	return
+		odr_implicit_tag (o, odr_integer,
+			&(*p)->unit, ODR_CONTEXT, 0, 0, "unit") &&
+		odr_explicit_tag (o, z_HumanString,
+			&(*p)->description, ODR_CONTEXT, 1, 1, "description") &&
+		odr_sequence_end (o);
+}
+
+int z_ProxSupportUnit (ODR o, Z_ProxSupportUnit **p, int opt, const char *name)
+{
+	static Odr_arm arm[] = {
+		{ODR_IMPLICIT, ODR_CONTEXT, 1, Z_ProxSupportUnit_known,
+		(Odr_fun) odr_integer, "known"},
+		{ODR_IMPLICIT, ODR_CONTEXT, 2, Z_ProxSupportUnit_private,
+		(Odr_fun) z_ProxSupportPrivate, "zprivate"},
+		{-1, -1, -1, -1, (Odr_fun) 0, 0}
+	};
+	if (!odr_initmember(o, p, sizeof(**p)))
+		return opt && odr_ok(o);
+	if (odr_choice(o, arm, &(*p)->u, &(*p)->which, name))
+		return 1;
+	*p = 0;
+	return opt && odr_ok(o);
+}
+
+int z_ProximitySupport (ODR o, Z_ProximitySupport **p, int opt, const char *name)
+{
+	if (!odr_sequence_begin (o, p, sizeof(**p), name))
+		return opt && odr_ok (o);
+	return
+		odr_implicit_tag (o, odr_bool,
+			&(*p)->anySupport, ODR_CONTEXT, 0, 0, "anySupport") &&
+		odr_implicit_settag (o, ODR_CONTEXT, 1) &&
+		(odr_sequence_of(o, (Odr_fun) z_ProxSupportUnit, &(*p)->unitsSupported,
+		  &(*p)->num_unitsSupported, "unitsSupported") || odr_ok(o)) &&
+		odr_sequence_end (o);
+}
+
+int z_SearchKey (ODR o, Z_SearchKey **p, int opt, const char *name)
+{
+	if (!odr_sequence_begin (o, p, sizeof(**p), name))
+		return opt && odr_ok (o);
+	return
+		odr_implicit_tag (o, z_InternationalString,
+			&(*p)->searchKey, ODR_CONTEXT, 0, 0, "searchKey") &&
+		odr_implicit_tag (o, z_HumanString,
+			&(*p)->description, ODR_CONTEXT, 1, 1, "description") &&
+		odr_sequence_end (o);
+}
+
+int z_AccessRestrictionsUnit (ODR o, Z_AccessRestrictionsUnit **p, int opt, const char *name)
+{
+	if (!odr_sequence_begin (o, p, sizeof(**p), name))
+		return opt && odr_ok (o);
+	return
+		odr_explicit_tag (o, odr_integer,
+			&(*p)->accessType, ODR_CONTEXT, 0, 0, "accessType") &&
+		odr_implicit_tag (o, z_HumanString,
+			&(*p)->accessText, ODR_CONTEXT, 1, 1, "accessText") &&
+		odr_implicit_settag (o, ODR_CONTEXT, 2) &&
+		(odr_sequence_of(o, (Odr_fun) odr_oid, &(*p)->accessChallenges,
+		  &(*p)->num_accessChallenges, "accessChallenges") || odr_ok(o)) &&
+		odr_sequence_end (o);
+}
+
+int z_AccessRestrictions (ODR o, Z_AccessRestrictions **p, int opt, const char *name)
+{
+	if (!odr_initmember (o, p, sizeof(**p)))
+		return opt && odr_ok(o);
+	if (odr_sequence_of (o, (Odr_fun) z_AccessRestrictionsUnit, &(*p)->elements,
+		&(*p)->num, name))
+		return 1;
+	*p = 0;
+	return opt && odr_ok(o);
+}
+
+int z_CostsOtherCharge (ODR o, Z_CostsOtherCharge **p, int opt, const char *name)
+{
+	if (!odr_sequence_begin (o, p, sizeof(**p), name))
+		return opt && odr_ok (o);
+	return
+		odr_implicit_tag (o, z_HumanString,
+			&(*p)->forWhat, ODR_CONTEXT, 1, 0, "forWhat") &&
+		odr_implicit_tag (o, z_Charge,
+			&(*p)->charge, ODR_CONTEXT, 2, 0, "charge") &&
+		odr_sequence_end (o);
+}
+
+int z_Costs (ODR o, Z_Costs **p, int opt, const char *name)
+{
+	if (!odr_sequence_begin (o, p, sizeof(**p), name))
+		return opt && odr_ok (o);
+	return
+		odr_implicit_tag (o, z_Charge,
+			&(*p)->connectCharge, ODR_CONTEXT, 0, 1, "connectCharge") &&
+		odr_implicit_tag (o, z_Charge,
+			&(*p)->connectTime, ODR_CONTEXT, 1, 1, "connectTime") &&
+		odr_implicit_tag (o, z_Charge,
+			&(*p)->displayCharge, ODR_CONTEXT, 2, 1, "displayCharge") &&
+		odr_implicit_tag (o, z_Charge,
+			&(*p)->searchCharge, ODR_CONTEXT, 3, 1, "searchCharge") &&
+		odr_implicit_tag (o, z_Charge,
+			&(*p)->subscriptCharge, ODR_CONTEXT, 4, 1, "subscriptCharge") &&
+		odr_implicit_settag (o, ODR_CONTEXT, 5) &&
+		(odr_sequence_of(o, (Odr_fun) z_CostsOtherCharge, &(*p)->otherCharges,
+		  &(*p)->num_otherCharges, "otherCharges") || odr_ok(o)) &&
+		odr_sequence_end (o);
+}
+
+int z_Charge (ODR o, Z_Charge **p, int opt, const char *name)
+{
+	if (!odr_sequence_begin (o, p, sizeof(**p), name))
+		return opt && odr_ok (o);
+	return
+		odr_implicit_tag (o, z_IntUnit,
+			&(*p)->cost, ODR_CONTEXT, 1, 0, "cost") &&
+		odr_implicit_tag (o, z_Unit,
+			&(*p)->perWhat, ODR_CONTEXT, 2, 1, "perWhat") &&
+		odr_implicit_tag (o, z_HumanString,
+			&(*p)->text, ODR_CONTEXT, 3, 1, "text") &&
+		odr_sequence_end (o);
+}
+
+int z_DatabaseList (ODR o, Z_DatabaseList **p, int opt, const char *name)
+{
+	if (!odr_initmember (o, p, sizeof(**p)))
+		return opt && odr_ok(o);
+	if (odr_sequence_of (o, (Odr_fun) z_DatabaseName, &(*p)->databases,
+		&(*p)->num_databases, name))
+		return 1;
+	*p = 0;
+	return opt && odr_ok(o);
+}
+
+int z_AttributeCombinations (ODR o, Z_AttributeCombinations **p, int opt, const char *name)
+{
+	if (!odr_sequence_begin (o, p, sizeof(**p), name))
+		return opt && odr_ok (o);
+	return
+		odr_implicit_tag (o, z_AttributeSetId,
+			&(*p)->defaultAttributeSet, ODR_CONTEXT, 0, 0, "defaultAttributeSet") &&
+		odr_implicit_settag (o, ODR_CONTEXT, 1) &&
+		odr_sequence_of(o, (Odr_fun) z_AttributeCombination, &(*p)->legalCombinations,
+		  &(*p)->num_legalCombinations, "legalCombinations") &&
+		odr_sequence_end (o);
+}
+
+int z_AttributeCombination (ODR o, Z_AttributeCombination **p, int opt, const char *name)
+{
+	if (!odr_initmember (o, p, sizeof(**p)))
+		return opt && odr_ok(o);
+	if (odr_sequence_of (o, (Odr_fun) z_AttributeOccurrence, &(*p)->occurrences,
+		&(*p)->num_occurrences, name))
+		return 1;
+	*p = 0;
+	return opt && odr_ok(o);
+}
+
+int z_AttributeValueList (ODR o, Z_AttributeValueList **p, int opt, const char *name)
+{
+	if (!odr_initmember (o, p, sizeof(**p)))
+		return opt && odr_ok(o);
+	if (odr_sequence_of (o, (Odr_fun) z_StringOrNumeric, &(*p)->attributes,
+		&(*p)->num_attributes, name))
+		return 1;
+	*p = 0;
+	return opt && odr_ok(o);
+}
+
+int z_AttributeOccurrence (ODR o, Z_AttributeOccurrence **p, int opt, const char *name)
+{
+	static Odr_arm arm[] = {
+		{ODR_IMPLICIT, ODR_CONTEXT, 3, Z_AttributeOcc_any_or_none,
+		(Odr_fun) odr_null, "any_or_none"},
+		{ODR_IMPLICIT, ODR_CONTEXT, 4, Z_AttributeOcc_specific,
+		(Odr_fun) z_AttributeValueList, "specific"},
+		{-1, -1, -1, -1, (Odr_fun) 0, 0}
+	};
+	if (!odr_sequence_begin (o, p, sizeof(**p), name))
+		return opt && odr_ok (o);
+	return
+		odr_implicit_tag (o, z_AttributeSetId,
+			&(*p)->attributeSet, ODR_CONTEXT, 0, 1, "attributeSet") &&
+		odr_implicit_tag (o, odr_integer,
+			&(*p)->attributeType, ODR_CONTEXT, 1, 0, "attributeType") &&
+		odr_implicit_tag (o, odr_null,
+			&(*p)->mustBeSupplied, ODR_CONTEXT, 2, 1, "mustBeSupplied") &&
+		odr_choice (o, arm, &(*p)->attributeValues, &(*p)->which, 0) &&
+		odr_sequence_end (o);
+}
Index: /main/tags/2.25/gsdl/packages/yaz/z39.50/z-grs.c
===================================================================
--- /main/tags/2.25/gsdl/packages/yaz/z39.50/z-grs.c	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/yaz/z39.50/z-grs.c	(revision 21064)
@@ -0,0 +1,219 @@
+/* Generated automatically by the YAZ ASN.1 Compiler 0.3 */
+/* Module-C: RecordSyntax-generic */
+
+#include <yaz/z-grs.h>
+
+int z_GenericRecord (ODR o, Z_GenericRecord **p, int opt, const char *name)
+{
+	if (!odr_initmember (o, p, sizeof(**p)))
+		return opt && odr_ok(o);
+	if (odr_sequence_of (o, (Odr_fun) z_TaggedElement, &(*p)->elements,
+		&(*p)->num_elements, name))
+		return 1;
+	*p = 0;
+	return opt && odr_ok(o);
+}
+
+int z_TaggedElement (ODR o, Z_TaggedElement **p, int opt, const char *name)
+{
+	if (!odr_sequence_begin (o, p, sizeof(**p), name))
+		return opt && odr_ok (o);
+	return
+		odr_implicit_tag (o, odr_integer,
+			&(*p)->tagType, ODR_CONTEXT, 1, 1, "tagType") &&
+		odr_explicit_tag (o, z_StringOrNumeric,
+			&(*p)->tagValue, ODR_CONTEXT, 2, 0, "tagValue") &&
+		odr_implicit_tag (o, odr_integer,
+			&(*p)->tagOccurrence, ODR_CONTEXT, 3, 1, "tagOccurrence") &&
+		odr_explicit_tag (o, z_ElementData,
+			&(*p)->content, ODR_CONTEXT, 4, 0, "content") &&
+		odr_implicit_tag (o, z_ElementMetaData,
+			&(*p)->metaData, ODR_CONTEXT, 5, 1, "metaData") &&
+		odr_implicit_tag (o, z_Variant,
+			&(*p)->appliedVariant, ODR_CONTEXT, 6, 1, "appliedVariant") &&
+		odr_sequence_end (o);
+}
+
+int z_ElementData (ODR o, Z_ElementData **p, int opt, const char *name)
+{
+	static Odr_arm arm[] = {
+		{-1, -1, -1, Z_ElementData_octets,
+		 (Odr_fun) odr_octetstring, "octets"},
+		{-1, -1, -1, Z_ElementData_numeric,
+		 (Odr_fun) odr_integer, "numeric"},
+		{-1, -1, -1, Z_ElementData_date,
+		 (Odr_fun) odr_generalizedtime, "date"},
+		{-1, -1, -1, Z_ElementData_ext,
+		 (Odr_fun) z_External, "ext"},
+		{-1, -1, -1, Z_ElementData_string,
+		 (Odr_fun) z_InternationalString, "string"},
+		{-1, -1, -1, Z_ElementData_trueOrFalse,
+		 (Odr_fun) odr_bool, "trueOrFalse"},
+		{-1, -1, -1, Z_ElementData_oid,
+		 (Odr_fun) odr_oid, "oid"},
+		{ODR_IMPLICIT, ODR_CONTEXT, 1, Z_ElementData_intUnit,
+		(Odr_fun) z_IntUnit, "intUnit"},
+		{ODR_IMPLICIT, ODR_CONTEXT, 2, Z_ElementData_elementNotThere,
+		(Odr_fun) odr_null, "elementNotThere"},
+		{ODR_IMPLICIT, ODR_CONTEXT, 3, Z_ElementData_elementEmpty,
+		(Odr_fun) odr_null, "elementEmpty"},
+		{ODR_IMPLICIT, ODR_CONTEXT, 4, Z_ElementData_noDataRequested,
+		(Odr_fun) odr_null, "noDataRequested"},
+		{ODR_IMPLICIT, ODR_CONTEXT, 5, Z_ElementData_diagnostic,
+		(Odr_fun) z_External, "diagnostic"},
+		{ODR_EXPLICIT, ODR_CONTEXT, 6, Z_ElementData_subtree,
+		(Odr_fun) z_GenericRecord, "subtree"},
+		{-1, -1, -1, -1, (Odr_fun) 0, 0}
+	};
+	if (!odr_initmember(o, p, sizeof(**p)))
+		return opt && odr_ok(o);
+	if (odr_choice(o, arm, &(*p)->u, &(*p)->which, name))
+		return 1;
+	*p = 0;
+	return opt && odr_ok(o);
+}
+
+int z_ElementMetaData (ODR o, Z_ElementMetaData **p, int opt, const char *name)
+{
+	if (!odr_sequence_begin (o, p, sizeof(**p), name))
+		return opt && odr_ok (o);
+	return
+		odr_implicit_tag (o, z_Order,
+			&(*p)->seriesOrder, ODR_CONTEXT, 1, 1, "seriesOrder") &&
+		odr_implicit_tag (o, z_Usage,
+			&(*p)->usageRight, ODR_CONTEXT, 2, 1, "usageRight") &&
+		odr_implicit_settag (o, ODR_CONTEXT, 3) &&
+		(odr_sequence_of(o, (Odr_fun) z_HitVector, &(*p)->hits,
+		  &(*p)->num_hits, "hits") || odr_ok(o)) &&
+		odr_implicit_tag (o, z_InternationalString,
+			&(*p)->displayName, ODR_CONTEXT, 4, 1, "displayName") &&
+		odr_implicit_settag (o, ODR_CONTEXT, 5) &&
+		(odr_sequence_of(o, (Odr_fun) z_Variant, &(*p)->supportedVariants,
+		  &(*p)->num_supportedVariants, "supportedVariants") || odr_ok(o)) &&
+		odr_implicit_tag (o, z_InternationalString,
+			&(*p)->message, ODR_CONTEXT, 6, 1, "message") &&
+		odr_implicit_tag (o, odr_octetstring,
+			&(*p)->elementDescriptor, ODR_CONTEXT, 7, 1, "elementDescriptor") &&
+		odr_implicit_tag (o, z_TagPath,
+			&(*p)->surrogateFor, ODR_CONTEXT, 8, 1, "surrogateFor") &&
+		odr_implicit_tag (o, z_TagPath,
+			&(*p)->surrogateElement, ODR_CONTEXT, 9, 1, "surrogateElement") &&
+		odr_implicit_tag (o, z_External,
+			&(*p)->other, ODR_CONTEXT, 99, 1, "other") &&
+		odr_sequence_end (o);
+}
+
+int z_TagPath_s (ODR o, Z_TagPath_s **p, int opt, const char *name)
+{
+	if (!odr_sequence_begin (o, p, sizeof(**p), name))
+		return opt && odr_ok (o);
+	return
+		odr_implicit_tag (o, odr_integer,
+			&(*p)->tagType, ODR_CONTEXT, 1, 1, "tagType") &&
+		odr_explicit_tag (o, z_StringOrNumeric,
+			&(*p)->tagValue, ODR_CONTEXT, 2, 0, "tagValue") &&
+		odr_implicit_tag (o, odr_integer,
+			&(*p)->tagOccurrence, ODR_CONTEXT, 3, 1, "tagOccurrence") &&
+		odr_sequence_end (o);
+}
+
+int z_TagPath (ODR o, Z_TagPath **p, int opt, const char *name)
+{
+	if (!odr_initmember (o, p, sizeof(**p)))
+		return opt && odr_ok(o);
+	if (odr_sequence_of (o, (Odr_fun) z_TagPath_s, &(*p)->elements,
+		&(*p)->num, name))
+		return 1;
+	*p = 0;
+	return opt && odr_ok(o);
+}
+
+int z_Order (ODR o, Z_Order **p, int opt, const char *name)
+{
+	if (!odr_sequence_begin (o, p, sizeof(**p), name))
+		return opt && odr_ok (o);
+	return
+		odr_implicit_tag (o, odr_bool,
+			&(*p)->ascending, ODR_CONTEXT, 1, 0, "ascending") &&
+		odr_implicit_tag (o, odr_integer,
+			&(*p)->order, ODR_CONTEXT, 2, 0, "order") &&
+		odr_sequence_end (o);
+}
+
+int z_Usage (ODR o, Z_Usage **p, int opt, const char *name)
+{
+	if (!odr_sequence_begin (o, p, sizeof(**p), name))
+		return opt && odr_ok (o);
+	return
+		odr_implicit_tag (o, odr_integer,
+			&(*p)->type, ODR_CONTEXT, 1, 0, "type") &&
+		odr_implicit_tag (o, z_InternationalString,
+			&(*p)->restriction, ODR_CONTEXT, 2, 1, "restriction") &&
+		odr_sequence_end (o);
+}
+
+int z_HitVector (ODR o, Z_HitVector **p, int opt, const char *name)
+{
+	if (!odr_sequence_begin (o, p, sizeof(**p), name))
+		return opt && odr_ok (o);
+	return
+		z_Term(o, &(*p)->satisfier, 1, "satisfier") &&
+		odr_implicit_tag (o, z_IntUnit,
+			&(*p)->offsetIntoElement, ODR_CONTEXT, 1, 1, "offsetIntoElement") &&
+		odr_implicit_tag (o, z_IntUnit,
+			&(*p)->length, ODR_CONTEXT, 2, 1, "length") &&
+		odr_implicit_tag (o, odr_integer,
+			&(*p)->hitRank, ODR_CONTEXT, 3, 1, "hitRank") &&
+		odr_implicit_tag (o, odr_octetstring,
+			&(*p)->targetToken, ODR_CONTEXT, 4, 1, "targetToken") &&
+		odr_sequence_end (o);
+}
+
+int z_Triple (ODR o, Z_Triple **p, int opt, const char *name)
+{
+	static Odr_arm arm[] = {
+		{-1, -1, -1, Z_Triple_integer,
+		 (Odr_fun) odr_integer, "integer"},
+		{-1, -1, -1, Z_Triple_internationalString,
+		 (Odr_fun) z_InternationalString, "internationalString"},
+		{-1, -1, -1, Z_Triple_octetString,
+		 (Odr_fun) odr_octetstring, "octetString"},
+		{-1, -1, -1, Z_Triple_objectIdentifier,
+		 (Odr_fun) odr_oid, "objectIdentifier"},
+		{-1, -1, -1, Z_Triple_boolean,
+		 (Odr_fun) odr_bool, "boolean"},
+		{-1, -1, -1, Z_Triple_null,
+		 (Odr_fun) odr_null, "null"},
+		{ODR_IMPLICIT, ODR_CONTEXT, 1, Z_Triple_unit,
+		(Odr_fun) z_Unit, "unit"},
+		{ODR_IMPLICIT, ODR_CONTEXT, 2, Z_Triple_valueAndUnit,
+		(Odr_fun) z_IntUnit, "valueAndUnit"},
+		{-1, -1, -1, -1, (Odr_fun) 0, 0}
+	};
+	if (!odr_sequence_begin (o, p, sizeof(**p), name))
+		return opt && odr_ok (o);
+	return
+		odr_implicit_tag (o, odr_oid,
+			&(*p)->variantSetId, ODR_CONTEXT, 0, 1, "variantSetId") &&
+		odr_implicit_tag (o, odr_integer,
+			&(*p)->zclass, ODR_CONTEXT, 1, 0, "zclass") &&
+		odr_implicit_tag (o, odr_integer,
+			&(*p)->type, ODR_CONTEXT, 2, 0, "type") &&
+		odr_constructed_begin (o, &(*p)->value, ODR_CONTEXT, 3, "value") &&
+		odr_choice (o, arm, &(*p)->value, &(*p)->which, 0) &&
+		odr_constructed_end (o) &&
+		odr_sequence_end (o);
+}
+
+int z_Variant (ODR o, Z_Variant **p, int opt, const char *name)
+{
+	if (!odr_sequence_begin (o, p, sizeof(**p), name))
+		return opt && odr_ok (o);
+	return
+		odr_implicit_tag (o, odr_oid,
+			&(*p)->globalVariantSetId, ODR_CONTEXT, 1, 1, "globalVariantSetId") &&
+		odr_implicit_settag (o, ODR_CONTEXT, 2) &&
+		odr_sequence_of(o, (Odr_fun) z_Triple, &(*p)->triples,
+		  &(*p)->num_triples, "triples") &&
+		odr_sequence_end (o);
+}
Index: /main/tags/2.25/gsdl/packages/yaz/z39.50/z-opac.c
===================================================================
--- /main/tags/2.25/gsdl/packages/yaz/z39.50/z-opac.c	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/yaz/z39.50/z-opac.c	(revision 21064)
@@ -0,0 +1,124 @@
+/* Generated automatically by the YAZ ASN.1 Compiler 0.3 */
+/* Module-C: RecordSyntax-opac */
+
+#include <yaz/z-opac.h>
+
+int z_OPACRecord (ODR o, Z_OPACRecord **p, int opt, const char *name)
+{
+	if (!odr_sequence_begin (o, p, sizeof(**p), name))
+		return opt && odr_ok (o);
+	return
+		odr_implicit_tag (o, z_External,
+			&(*p)->bibliographicRecord, ODR_CONTEXT, 1, 1, "bibliographicRecord") &&
+		odr_implicit_settag (o, ODR_CONTEXT, 2) &&
+		(odr_sequence_of(o, (Odr_fun) z_HoldingsRecord, &(*p)->holdingsData,
+		  &(*p)->num_holdingsData, "holdingsData") || odr_ok(o)) &&
+		odr_sequence_end (o);
+}
+
+int z_HoldingsRecord (ODR o, Z_HoldingsRecord **p, int opt, const char *name)
+{
+	static Odr_arm arm[] = {
+		{ODR_IMPLICIT, ODR_CONTEXT, 1, Z_HoldingsRecord_marcHoldingsRecord,
+		(Odr_fun) z_External, "marcHoldingsRecord"},
+		{ODR_IMPLICIT, ODR_CONTEXT, 2, Z_HoldingsRecord_holdingsAndCirc,
+		(Odr_fun) z_HoldingsAndCircData, "holdingsAndCirc"},
+		{-1, -1, -1, -1, (Odr_fun) 0, 0}
+	};
+	if (!odr_initmember(o, p, sizeof(**p)))
+		return opt && odr_ok(o);
+	if (odr_choice(o, arm, &(*p)->u, &(*p)->which, name))
+		return 1;
+	*p = 0;
+	return opt && odr_ok(o);
+}
+
+int z_HoldingsAndCircData (ODR o, Z_HoldingsAndCircData **p, int opt, const char *name)
+{
+	if (!odr_sequence_begin (o, p, sizeof(**p), name))
+		return opt && odr_ok (o);
+	return
+		odr_implicit_tag (o, z_InternationalString,
+			&(*p)->typeOfRecord, ODR_CONTEXT, 1, 1, "typeOfRecord") &&
+		odr_implicit_tag (o, z_InternationalString,
+			&(*p)->encodingLevel, ODR_CONTEXT, 2, 1, "encodingLevel") &&
+		odr_implicit_tag (o, z_InternationalString,
+			&(*p)->format, ODR_CONTEXT, 3, 1, "format") &&
+		odr_implicit_tag (o, z_InternationalString,
+			&(*p)->receiptAcqStatus, ODR_CONTEXT, 4, 1, "receiptAcqStatus") &&
+		odr_implicit_tag (o, z_InternationalString,
+			&(*p)->generalRetention, ODR_CONTEXT, 5, 1, "generalRetention") &&
+		odr_implicit_tag (o, z_InternationalString,
+			&(*p)->completeness, ODR_CONTEXT, 6, 1, "completeness") &&
+		odr_implicit_tag (o, z_InternationalString,
+			&(*p)->dateOfReport, ODR_CONTEXT, 7, 1, "dateOfReport") &&
+		odr_implicit_tag (o, z_InternationalString,
+			&(*p)->nucCode, ODR_CONTEXT, 8, 1, "nucCode") &&
+		odr_implicit_tag (o, z_InternationalString,
+			&(*p)->localLocation, ODR_CONTEXT, 9, 1, "localLocation") &&
+		odr_implicit_tag (o, z_InternationalString,
+			&(*p)->shelvingLocation, ODR_CONTEXT, 10, 1, "shelvingLocation") &&
+		odr_implicit_tag (o, z_InternationalString,
+			&(*p)->callNumber, ODR_CONTEXT, 11, 1, "callNumber") &&
+		odr_implicit_tag (o, z_InternationalString,
+			&(*p)->shelvingData, ODR_CONTEXT, 12, 1, "shelvingData") &&
+		odr_implicit_tag (o, z_InternationalString,
+			&(*p)->copyNumber, ODR_CONTEXT, 13, 1, "copyNumber") &&
+		odr_implicit_tag (o, z_InternationalString,
+			&(*p)->publicNote, ODR_CONTEXT, 14, 1, "publicNote") &&
+		odr_implicit_tag (o, z_InternationalString,
+			&(*p)->reproductionNote, ODR_CONTEXT, 15, 1, "reproductionNote") &&
+		odr_implicit_tag (o, z_InternationalString,
+			&(*p)->termsUseRepro, ODR_CONTEXT, 16, 1, "termsUseRepro") &&
+		odr_implicit_tag (o, z_InternationalString,
+			&(*p)->enumAndChron, ODR_CONTEXT, 17, 1, "enumAndChron") &&
+		odr_implicit_settag (o, ODR_CONTEXT, 18) &&
+		(odr_sequence_of(o, (Odr_fun) z_Volume, &(*p)->volumes,
+		  &(*p)->num_volumes, "volumes") || odr_ok(o)) &&
+		odr_implicit_settag (o, ODR_CONTEXT, 19) &&
+		(odr_sequence_of(o, (Odr_fun) z_CircRecord, &(*p)->circulationData,
+		  &(*p)->num_circulationData, "circulationData") || odr_ok(o)) &&
+		odr_sequence_end (o);
+}
+
+int z_Volume (ODR o, Z_Volume **p, int opt, const char *name)
+{
+	if (!odr_sequence_begin (o, p, sizeof(**p), name))
+		return opt && odr_ok (o);
+	return
+		odr_implicit_tag (o, z_InternationalString,
+			&(*p)->enumeration, ODR_CONTEXT, 1, 1, "enumeration") &&
+		odr_implicit_tag (o, z_InternationalString,
+			&(*p)->chronology, ODR_CONTEXT, 2, 1, "chronology") &&
+		odr_implicit_tag (o, z_InternationalString,
+			&(*p)->enumAndChron, ODR_CONTEXT, 3, 1, "enumAndChron") &&
+		odr_sequence_end (o);
+}
+
+int z_CircRecord (ODR o, Z_CircRecord **p, int opt, const char *name)
+{
+	if (!odr_sequence_begin (o, p, sizeof(**p), name))
+		return opt && odr_ok (o);
+	return
+		odr_implicit_tag (o, odr_bool,
+			&(*p)->availableNow, ODR_CONTEXT, 1, 0, "availableNow") &&
+		odr_implicit_tag (o, z_InternationalString,
+			&(*p)->availablityDate, ODR_CONTEXT, 2, 1, "availablityDate") &&
+		odr_implicit_tag (o, z_InternationalString,
+			&(*p)->availableThru, ODR_CONTEXT, 3, 1, "availableThru") &&
+		odr_implicit_tag (o, z_InternationalString,
+			&(*p)->restrictions, ODR_CONTEXT, 4, 1, "restrictions") &&
+		odr_implicit_tag (o, z_InternationalString,
+			&(*p)->itemId, ODR_CONTEXT, 5, 1, "itemId") &&
+		odr_implicit_tag (o, odr_bool,
+			&(*p)->renewable, ODR_CONTEXT, 6, 0, "renewable") &&
+		odr_implicit_tag (o, odr_bool,
+			&(*p)->onHold, ODR_CONTEXT, 7, 0, "onHold") &&
+		odr_implicit_tag (o, z_InternationalString,
+			&(*p)->enumAndChron, ODR_CONTEXT, 8, 1, "enumAndChron") &&
+		odr_implicit_tag (o, z_InternationalString,
+			&(*p)->midspine, ODR_CONTEXT, 9, 1, "midspine") &&
+		odr_implicit_tag (o, z_InternationalString,
+			&(*p)->temporaryLocation, ODR_CONTEXT, 10, 1, "temporaryLocation") &&
+		odr_sequence_end (o);
+}
Index: /main/tags/2.25/gsdl/packages/yaz/z39.50/z-rrf1.c
===================================================================
--- /main/tags/2.25/gsdl/packages/yaz/z39.50/z-rrf1.c	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/yaz/z39.50/z-rrf1.c	(revision 21064)
@@ -0,0 +1,36 @@
+/* Generated automatically by the YAZ ASN.1 Compiler 0.3 */
+/* Module-C: ResourceReport-Format-Resource-1 */
+
+#include <yaz/z-rrf1.h>
+
+int z_ResourceReport1 (ODR o, Z_ResourceReport1 **p, int opt, const char *name)
+{
+	if (!odr_sequence_begin (o, p, sizeof(**p), name))
+		return opt && odr_ok (o);
+	return
+		odr_implicit_settag (o, ODR_CONTEXT, 1) &&
+		odr_sequence_of(o, (Odr_fun) z_Estimate1, &(*p)->estimates,
+		  &(*p)->num_estimates, "estimates") &&
+		odr_implicit_tag (o, z_InternationalString,
+			&(*p)->message, ODR_CONTEXT, 2, 0, "message") &&
+		odr_sequence_end (o);
+}
+
+int z_Estimate1 (ODR o, Z_Estimate1 **p, int opt, const char *name)
+{
+	if (!odr_sequence_begin (o, p, sizeof(**p), name))
+		return opt && odr_ok (o);
+	return
+		odr_implicit_tag (o, z_EstimateType,
+			&(*p)->type, ODR_CONTEXT, 1, 0, "type") &&
+		odr_implicit_tag (o, odr_integer,
+			&(*p)->value, ODR_CONTEXT, 2, 0, "value") &&
+		odr_implicit_tag (o, odr_integer,
+			&(*p)->currency_code, ODR_CONTEXT, 3, 1, "currency_code") &&
+		odr_sequence_end (o);
+}
+
+int z_EstimateType (ODR o, Z_EstimateType **p, int opt, const char *name)
+{
+	return odr_integer (o, p, opt, name);
+}
Index: /main/tags/2.25/gsdl/packages/yaz/z39.50/z-rrf2.c
===================================================================
--- /main/tags/2.25/gsdl/packages/yaz/z39.50/z-rrf2.c	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/yaz/z39.50/z-rrf2.c	(revision 21064)
@@ -0,0 +1,29 @@
+/* Generated automatically by the YAZ ASN.1 Compiler 0.3 */
+/* Module-C: ResourceReport-Format-Resource-2 */
+
+#include <yaz/z-rrf2.h>
+
+int z_ResourceReport2 (ODR o, Z_ResourceReport2 **p, int opt, const char *name)
+{
+	if (!odr_sequence_begin (o, p, sizeof(**p), name))
+		return opt && odr_ok (o);
+	return
+		odr_implicit_settag (o, ODR_CONTEXT, 1) &&
+		(odr_sequence_of(o, (Odr_fun) z_Estimate2, &(*p)->estimates,
+		  &(*p)->num_estimates, "estimates") || odr_ok(o)) &&
+		odr_implicit_tag (o, z_InternationalString,
+			&(*p)->message, ODR_CONTEXT, 2, 1, "message") &&
+		odr_sequence_end (o);
+}
+
+int z_Estimate2 (ODR o, Z_Estimate2 **p, int opt, const char *name)
+{
+	if (!odr_sequence_begin (o, p, sizeof(**p), name))
+		return opt && odr_ok (o);
+	return
+		odr_explicit_tag (o, z_StringOrNumeric,
+			&(*p)->type, ODR_CONTEXT, 1, 0, "type") &&
+		odr_implicit_tag (o, z_IntUnit,
+			&(*p)->value, ODR_CONTEXT, 2, 0, "value") &&
+		odr_sequence_end (o);
+}
Index: /main/tags/2.25/gsdl/packages/yaz/z39.50/z-sum.c
===================================================================
--- /main/tags/2.25/gsdl/packages/yaz/z39.50/z-sum.c	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/yaz/z39.50/z-sum.c	(revision 21064)
@@ -0,0 +1,54 @@
+/* Generated automatically by the YAZ ASN.1 Compiler 0.3 */
+/* Module-C: RecordSyntax-summary */
+
+#include <yaz/z-sum.h>
+
+int z_BriefBib (ODR o, Z_BriefBib **p, int opt, const char *name)
+{
+	if (!odr_sequence_begin (o, p, sizeof(**p), name))
+		return opt && odr_ok (o);
+	return
+		odr_implicit_tag (o, z_InternationalString,
+			&(*p)->title, ODR_CONTEXT, 1, 0, "title") &&
+		odr_implicit_tag (o, z_InternationalString,
+			&(*p)->author, ODR_CONTEXT, 2, 1, "author") &&
+		odr_implicit_tag (o, z_InternationalString,
+			&(*p)->callNumber, ODR_CONTEXT, 3, 1, "callNumber") &&
+		odr_implicit_tag (o, z_InternationalString,
+			&(*p)->recordType, ODR_CONTEXT, 4, 1, "recordType") &&
+		odr_implicit_tag (o, z_InternationalString,
+			&(*p)->bibliographicLevel, ODR_CONTEXT, 5, 1, "bibliographicLevel") &&
+		odr_implicit_settag (o, ODR_CONTEXT, 6) &&
+		(odr_sequence_of(o, (Odr_fun) z_FormatSpec, &(*p)->format,
+		  &(*p)->num_format, "format") || odr_ok(o)) &&
+		odr_implicit_tag (o, z_InternationalString,
+			&(*p)->publicationPlace, ODR_CONTEXT, 7, 1, "publicationPlace") &&
+		odr_implicit_tag (o, z_InternationalString,
+			&(*p)->publicationDate, ODR_CONTEXT, 8, 1, "publicationDate") &&
+		odr_implicit_tag (o, z_InternationalString,
+			&(*p)->targetSystemKey, ODR_CONTEXT, 9, 1, "targetSystemKey") &&
+		odr_implicit_tag (o, z_InternationalString,
+			&(*p)->satisfyingElement, ODR_CONTEXT, 10, 1, "satisfyingElement") &&
+		odr_implicit_tag (o, odr_integer,
+			&(*p)->rank, ODR_CONTEXT, 11, 1, "rank") &&
+		odr_implicit_tag (o, z_InternationalString,
+			&(*p)->documentId, ODR_CONTEXT, 12, 1, "documentId") &&
+		odr_implicit_tag (o, z_InternationalString,
+			&(*p)->abstract, ODR_CONTEXT, 13, 1, "abstract") &&
+		z_OtherInformation(o, &(*p)->otherInfo, 1, "otherInfo") &&
+		odr_sequence_end (o);
+}
+
+int z_FormatSpec (ODR o, Z_FormatSpec **p, int opt, const char *name)
+{
+	if (!odr_sequence_begin (o, p, sizeof(**p), name))
+		return opt && odr_ok (o);
+	return
+		odr_implicit_tag (o, z_InternationalString,
+			&(*p)->type, ODR_CONTEXT, 1, 0, "type") &&
+		odr_implicit_tag (o, odr_integer,
+			&(*p)->size, ODR_CONTEXT, 2, 1, "size") &&
+		odr_implicit_tag (o, odr_integer,
+			&(*p)->bestPosn, ODR_CONTEXT, 3, 1, "bestPosn") &&
+		odr_sequence_end (o);
+}
Index: /main/tags/2.25/gsdl/packages/yaz/z39.50/z-sutrs.c
===================================================================
--- /main/tags/2.25/gsdl/packages/yaz/z39.50/z-sutrs.c	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/yaz/z39.50/z-sutrs.c	(revision 21064)
@@ -0,0 +1,16 @@
+/* Generated automatically by the YAZ ASN.1 Compiler 0.3 */
+/* Module-C: RecordSyntax-SUTRS */
+
+#include <yaz/z-sutrs.h>
+
+int z_SutrsRecord (ODR o, Z_SutrsRecord **p, int opt, const char *name)
+{
+	return z_InternationalString (o, p, opt, name);
+}
+
+int z_SUTRS (ODR o, Odr_oct **p, int opt)
+{
+    return odr_implicit(o, odr_octetstring, p, ODR_UNIVERSAL,
+        ODR_GENERALSTRING, opt);
+}
+
Index: /main/tags/2.25/gsdl/packages/yaz/z39.50/z-uifr1.c
===================================================================
--- /main/tags/2.25/gsdl/packages/yaz/z39.50/z-uifr1.c	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/yaz/z39.50/z-uifr1.c	(revision 21064)
@@ -0,0 +1,112 @@
+/* Generated automatically by the YAZ ASN.1 Compiler 0.3 */
+/* Module-C: UserInfoFormat-searchResult-1 */
+
+#include <yaz/z-uifr1.h>
+
+int z_SearchInfoReport_s (ODR o, Z_SearchInfoReport_s **p, int opt, const char *name)
+{
+	if (!odr_sequence_begin (o, p, sizeof(**p), name))
+		return opt && odr_ok (o);
+	return
+		odr_implicit_tag (o, z_InternationalString,
+			&(*p)->subqueryId, ODR_CONTEXT, 1, 1, "subqueryId") &&
+		odr_implicit_tag (o, odr_bool,
+			&(*p)->fullQuery, ODR_CONTEXT, 2, 0, "fullQuery") &&
+		odr_explicit_tag (o, z_QueryExpression,
+			&(*p)->subqueryExpression, ODR_CONTEXT, 3, 1, "subqueryExpression") &&
+		odr_explicit_tag (o, z_QueryExpression,
+			&(*p)->subqueryInterpretation, ODR_CONTEXT, 4, 1, "subqueryInterpretation") &&
+		odr_explicit_tag (o, z_QueryExpression,
+			&(*p)->subqueryRecommendation, ODR_CONTEXT, 5, 1, "subqueryRecommendation") &&
+		odr_implicit_tag (o, odr_integer,
+			&(*p)->subqueryCount, ODR_CONTEXT, 6, 1, "subqueryCount") &&
+		odr_implicit_tag (o, z_IntUnit,
+			&(*p)->subqueryWeight, ODR_CONTEXT, 7, 1, "subqueryWeight") &&
+		odr_implicit_tag (o, z_ResultsByDB,
+			&(*p)->resultsByDB, ODR_CONTEXT, 8, 1, "resultsByDB") &&
+		odr_sequence_end (o);
+}
+
+int z_SearchInfoReport (ODR o, Z_SearchInfoReport **p, int opt, const char *name)
+{
+	if (!odr_initmember (o, p, sizeof(**p)))
+		return opt && odr_ok(o);
+	if (odr_sequence_of (o, (Odr_fun) z_SearchInfoReport_s, &(*p)->elements,
+		&(*p)->num, name))
+		return 1;
+	*p = 0;
+	return opt && odr_ok(o);
+}
+
+int z_ResultsByDB_sList (ODR o, Z_ResultsByDB_sList **p, int opt, const char *name)
+{
+	if (!odr_initmember (o, p, sizeof(**p)))
+		return opt && odr_ok(o);
+	if (odr_sequence_of (o, (Odr_fun) z_DatabaseName, &(*p)->elements,
+		&(*p)->num, name))
+		return 1;
+	*p = 0;
+	return opt && odr_ok(o);
+}
+
+int z_ResultsByDB_s (ODR o, Z_ResultsByDB_s **p, int opt, const char *name)
+{
+	static Odr_arm arm[] = {
+		{ODR_IMPLICIT, ODR_CONTEXT, 1, Z_ResultsByDB_s_all,
+		(Odr_fun) odr_null, "all"},
+		{ODR_IMPLICIT, ODR_CONTEXT, 2, Z_ResultsByDB_s_list,
+		(Odr_fun) z_ResultsByDB_sList, "list"},
+		{-1, -1, -1, -1, (Odr_fun) 0, 0}
+	};
+	if (!odr_sequence_begin (o, p, sizeof(**p), name))
+		return opt && odr_ok (o);
+	return
+		odr_constructed_begin (o, &(*p)->u, ODR_CONTEXT, 1, "databases") &&
+		odr_choice (o, arm, &(*p)->u, &(*p)->which, 0) &&
+		odr_constructed_end (o) &&
+		odr_implicit_tag (o, odr_integer,
+			&(*p)->count, ODR_CONTEXT, 2, 1, "count") &&
+		odr_implicit_tag (o, z_InternationalString,
+			&(*p)->resultSetName, ODR_CONTEXT, 3, 1, "resultSetName") &&
+		odr_sequence_end (o);
+}
+
+int z_ResultsByDB (ODR o, Z_ResultsByDB **p, int opt, const char *name)
+{
+	if (!odr_initmember (o, p, sizeof(**p)))
+		return opt && odr_ok(o);
+	if (odr_sequence_of (o, (Odr_fun) z_ResultsByDB_s, &(*p)->elements,
+		&(*p)->num, name))
+		return 1;
+	*p = 0;
+	return opt && odr_ok(o);
+}
+
+int z_QueryExpressionTerm (ODR o, Z_QueryExpressionTerm **p, int opt, const char *name)
+{
+	if (!odr_sequence_begin (o, p, sizeof(**p), name))
+		return opt && odr_ok (o);
+	return
+		odr_explicit_tag (o, z_Term,
+			&(*p)->queryTerm, ODR_CONTEXT, 1, 0, "queryTerm") &&
+		odr_implicit_tag (o, z_InternationalString,
+			&(*p)->termComment, ODR_CONTEXT, 2, 1, "termComment") &&
+		odr_sequence_end (o);
+}
+
+int z_QueryExpression (ODR o, Z_QueryExpression **p, int opt, const char *name)
+{
+	static Odr_arm arm[] = {
+		{ODR_IMPLICIT, ODR_CONTEXT, 1, Z_QueryExpression_term,
+		(Odr_fun) z_QueryExpressionTerm, "term"},
+		{ODR_EXPLICIT, ODR_CONTEXT, 2, Z_QueryExpression_query,
+		(Odr_fun) z_Query, "query"},
+		{-1, -1, -1, -1, (Odr_fun) 0, 0}
+	};
+	if (!odr_initmember(o, p, sizeof(**p)))
+		return opt && odr_ok(o);
+	if (odr_choice(o, arm, &(*p)->u, &(*p)->which, name))
+		return 1;
+	*p = 0;
+	return opt && odr_ok(o);
+}
Index: /main/tags/2.25/gsdl/packages/yaz/z39.50/z-univ.c
===================================================================
--- /main/tags/2.25/gsdl/packages/yaz/z39.50/z-univ.c	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/yaz/z39.50/z-univ.c	(revision 21064)
@@ -0,0 +1,40 @@
+/* Generated automatically by the YAZ ASN.1 Compiler 0.3 */
+/* Module-C: ResourceReport-Format-Universe-1 */
+
+#include <yaz/z-univ.h>
+
+int z_UniverseReportHits (ODR o, Z_UniverseReportHits **p, int opt, const char *name)
+{
+	if (!odr_sequence_begin (o, p, sizeof(**p), name))
+		return opt && odr_ok (o);
+	return
+		z_StringOrNumeric(o, &(*p)->database, 0, "database") &&
+		z_StringOrNumeric(o, &(*p)->hits, 0, "hits") &&
+		odr_sequence_end (o);
+}
+
+int z_UniverseReportDuplicate (ODR o, Z_UniverseReportDuplicate **p, int opt, const char *name)
+{
+	if (!odr_sequence_begin (o, p, sizeof(**p), name))
+		return opt && odr_ok (o);
+	return
+		z_StringOrNumeric(o, &(*p)->hitno, 0, "hitno") &&
+		odr_sequence_end (o);
+}
+
+int z_UniverseReport (ODR o, Z_UniverseReport **p, int opt, const char *name)
+{
+	static Odr_arm arm[] = {
+		{ODR_IMPLICIT, ODR_CONTEXT, 0, Z_UniverseReport_databaseHits,
+		(Odr_fun) z_UniverseReportHits, "databaseHits"},
+		{ODR_IMPLICIT, ODR_CONTEXT, 1, Z_UniverseReport_duplicate,
+		(Odr_fun) z_UniverseReportDuplicate, "duplicate"},
+		{-1, -1, -1, -1, (Odr_fun) 0, 0}
+	};
+	if (!odr_sequence_begin (o, p, sizeof(**p), name))
+		return opt && odr_ok (o);
+	return
+		odr_integer(o, &(*p)->totalHits, 0, "totalHits") &&
+		odr_choice (o, arm, &(*p)->u, &(*p)->which, 0) &&
+		odr_sequence_end (o);
+}
Index: /main/tags/2.25/gsdl/packages/yaz/z39.50/z.tcl
===================================================================
--- /main/tags/2.25/gsdl/packages/yaz/z39.50/z.tcl	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/yaz/z39.50/z.tcl	(revision 21064)
@@ -0,0 +1,329 @@
+# YC Sample Config File for Z39.50
+# $Id$
+# ----------------------------------------------------------
+# Prefix Specifications
+#  
+#    1: C function prefix
+#    2: C type prefix
+#    3: C preprocessor prefix
+
+# Default prefix
+set default-prefix {z_ Z_ Z_}
+
+# Name clash in extended services (TargetPart, OriginPartToKeep, etc)
+# You can possibly think of better names :)
+set prefix(ESFormat-PersistentResultSet) {z_PR Z_PR Z_PR}
+set prefix(ESFormat-PersistentQuery) {z_PQuery Z_PQuery Z_PQuery}
+set prefix(ESFormat-PeriodicQuerySchedule) {z_PQS Z_PQS Z_PQS}
+set prefix(ESFormat-ItemOrder) {z_IO Z_IO Z_IO}
+set prefix(ESFormat-Update0) {z_IU0 Z_IU0 Z_IU0}
+set prefix(ESFormat-Update) {z_IU Z_IU Z_IU}
+set prefix(ESFormat-ExportSpecification) {z_ES Z_ES Z_ES}
+set prefix(ESFormat-ExportInvocation) {z_EI Z_EI Z_EI}
+
+# ----------------------------------------------------------
+# Settings for core of the protocol
+set m Z39-50-APDU-1995
+
+# Filename
+set filename($m) z-core
+
+# Public header initialization code
+set init($m,h) {
+typedef struct Z_External Z_External;
+YAZ_EXPORT int z_External(ODR o, Z_External **p, int opt, const char *name);
+}
+
+set body($m,h) "
+#ifdef __cplusplus
+extern \"C\" \{
+#endif
+
+int z_ANY_type_0 (ODR o, void **p, int opt);
+
+#ifdef __cplusplus
+\}
+#endif
+"
+set body($m,c) {
+
+/* the type-0 query ... */
+int z_ANY_type_0 (ODR o, void **p, int opt)
+{
+    return 0;
+}
+
+}
+
+# Type Name overrides
+set map($m,PDU) APDU
+set map($m,AttributeElement_complex) ComplexAttribute
+set map($m,DeleteSetStatus) DeleteStatus
+set membermap($m,ProximityOperator,private) {ProximityOperator_private zprivate}
+set unionmap($m,AttributeElement,attributeValue) {which value AttributeValue}
+set membermap($m,ElementSpec,externalEspec) externalSpec
+set membermap($m,RPNStructure,op) simple
+set membermap($m,RPNStructure,rpnRpnOp) complex
+set map($m,RPNStructure_complex) Complex
+set membermap($m,Operand,attrTerm) {Operand_APT attributesPlusTerm}
+set membermap($m,Operand,resultSet) {Operand_resultSetId resultSetId}
+set membermap($m,Operand,resultAttr) {Operand_resultAttr resultAttr}
+set membermap($m,Complex,rpn1) s1
+set membermap($m,Complex,rpn2) s2
+set membermap($m,Complex,op) roperator
+set membermap($m,RPNQuery,attributeSet) attributeSetId
+set membermap($m,RPNQuery,rpn) RPNStructure
+set map($m,KnownProximityUnit) ProxUnit
+set membermap($m,ProximityOperator,lessThan) {Prox_lessThan 1}
+set membermap($m,ProximityOperator,lessThanOrEqual) {Prox_lessThanOrEqual 1}
+set membermap($m,ProximityOperator,equal) {Prox_equal 1}
+set membermap($m,ProximityOperator,greaterThanOrEqual) {Prox_greaterThanOrEqual 1}
+set membermap($m,ProximityOperator,greaterThan) {Prox_greaterThan 1}
+set membermap($m,ProximityOperator,notEqual) {Prox_notEqual 1}
+#
+set membermap($m,Records,responseRecords) {Records_DBOSD databaseOrSurDiagnostics}
+set membermap($m,Records,nonSurrogateDiagnostic) {Records_NSD nonSurrogateDiagnostic}
+set membermap($m,Records,multipleNonSurDiagnostics) {Records_multipleNSD multipleNonSurDiagnostics}
+set map($m,Records_DBOSD) NamePlusRecordList
+set map($m,Records_NSD) DiagRec
+set map($m,Records_multipleNSD) DiagRecs
+set membermap($m,NamePlusRecord,name) databaseName
+set unionmap($m,DiagRecs) {num_diagRecs diagRecs}
+set unionmap($m,NamePlusRecordList) {num_records records}
+#
+set membermap($m,ElementSetNames,genericElementSetName) generic
+set map($m,ElementSetNames_databaseSpecific) DatabaseSpecific
+#
+set map($m,OccurrenceByAttributes_s) OccurrenceByAttributesElem
+set map($m,OccurrenceByAttributesElem_byDatabase) byDatabaseList
+#
+set membermap($m,SortElement,datbaseSpecific) databaseSpecific
+set map($m,SortElement_databaseSpecific) SortDbSpecificList
+#
+set map($m,SortKey_sortAttributes) SortAttributes
+set unionmap($m,PresentRequest,recordComposition) {}
+set map($m,PresentRequest_0) RecordComposition
+set unionmap($m,PresentRequest,additionalRanges) {num_ranges additionalRanges}
+set unionmap($m,SortRequest,sortSequence) {}
+set map($m,SortRequest_0) SortKeySpecList
+set unionmap($m,SortKeySpecList) {num_specs specs}
+set map($m,InitializeRequest) InitRequest
+set map($m,InitializeResponse) InitResponse
+set unionmap($m,CloseReason) Close
+set membermap($m,ProtocolVersion,version-1) 1
+set membermap($m,ProtocolVersion,version-2) 2
+set membermap($m,ProtocolVersion,version-3) 3
+set membermap($m,InitRequest,exceptionalRecordSize) maximumRecordSize
+set membermap($m,InitResponse,exceptionalRecordSize) maximumRecordSize
+set map($m,RecordsMultipleNonSurDiagnostics) DiagRecs
+set map($m,RecordsDatabaseOrSurDiagnostics) NamePlusRecordList
+set membermap($m,NamePlusRecord,retrievalRecord) databaseRecord
+set unionmap($m,RecordComposition) {which u RecordComp}
+set unionmap($m,ScanResponse,scanStatus) Scan
+set unionmap($m,AttributeList) {num_attributes attributes}
+set membermap($m,SortKey,sortfield) sortField
+set map($m,CompSpec_0) DbSpecific
+set map($m,DatabaseSpecific_s) DatabaseSpecificUnit
+set map($m,ListStatuses_s) ListStatus
+set map($m,IdAuthenticationIdPass) IdPass
+set map($m,OtherInformation_s) OtherInformationUnit
+set unionmap($m,OtherInformationUnit,information) {which information OtherInfo}
+set unionmap($m,OtherInformation) {num_elements list}
+set unionmap($m,Specification,elementSpec) {}
+set map($m,Specification_0) ElementSpec
+
+# ----
+set m DiagnosticFormatDiag1
+set filename($m) z-diag1
+set map($m,DiagFormat_tooMany) TooMany
+set map($m,DiagFormat_badSpec) BadSpec
+set map($m,DiagFormat_dbUnavail) DbUnavail
+set map($m,DiagFormat_attribute) Attribute
+set map($m,DiagFormat_attCombo) AttCombo
+set map($m,DiagFormat_term) DiagTerm
+set map($m,DiagFormat_proximity) Proximity
+set map($m,DiagFormat_scan) Scan
+set map($m,DiagFormat_sort) Sort
+set unionmap($m,Sort) {which u SortD}
+set map($m,DiagFormat_segmentation) Segmentation
+set map($m,DiagFormat_extServices) ExtServices
+set map($m,DiagFormat_accessCtrl) AccessCtrl
+set map($m,DiagFormat_recordSyntax) RecordSyntax
+#
+set map($m,Scan_termList2) AttrListList
+set map($m,Sort_inputTooLarge) StringList
+#
+set map($m,AccessCtrl_oid) OidList
+set map($m,AccessCtrl_alternative) AltOidList
+# ----
+set m RecordSyntax-explain
+set filename($m) z-exp
+set map($m,Explain-Record) ExplainRecord
+set map($m,ElementDataType_structured) ElementInfoList
+set map($m,HumanString_s) HumanStringUnit
+set unionmap($m,HumanString) {num_strings strings}
+set membermap($m,CommonInfo,humanString-Language) humanStringLanguage
+set unionmap($m,AttributeOccurrence,attributeValues) {which attributeValues AttributeOcc}
+set unionmap($m,AttributeCombination) {num_occurrences occurrences}
+#
+set membermap($m,NetworkAddress,internetAddress) {NetworkAddress_iA internetAddress}
+set map($m,NetworkAddress_iA) NetworkAddressIA
+set membermap($m,NetworkAddress,osiPresentationAddress) {NetworkAddress_oPA osiPresentationAddress}
+set map($m,NetworkAddress_oPA) NetworkAddressOPA
+set map($m,NetworkAddress_other) NetworkAddressOther
+set unionmap($m,DatabaseList) {num_databases databases}
+set membermap($m,TargetInfo,recent-news) recentNews
+set membermap($m,TargetInfo,usage-restrictions) usageRest
+set membermap($m,DatabaseInfo,user-fee) userFee
+#
+set map($m,ProximitySupport_0) ProxSupportUnit
+set map($m,ProxSupportUnitZprivate) ProxSupportPrivate
+set membermap($m,ProxSupportUnit,private) {ProxSupportUnit_private zprivate}
+#
+set map($m,AttributeOccurrence_specific) AttributeValueList
+set unionmap($m,AttributeValueList) {num_attributes attributes}
+
+set unionmap($m,ExplainRecord) {which u Explain}
+set map($m,SchemaInfo_0) TagTypeMapping
+set map($m,TagSetInfo_0) TagSetElements
+set map($m,TermListInfo_0) TermListElement
+set map($m,TermListDetails_0) EScanInfo
+set map($m,PrivateCapabilities_0) PrivateCapOperator
+set map($m,Costs_0) CostsOtherCharge
+set map($m,Path_s) PathUnit
+set map($m,IconObject_s) IconObjectUnit
+set map($m,NetworkAddressInternetAddress) NetworkAddressIA
+set map($m,NetworkAddressOsiPresentationAddress) NetworkAddressOPA
+set membermap($m,QueryTypeDetails,private) {QueryTypeDetails_private zprivate}
+set membermap($m,PrivateCapOperator,operator) roperator
+set map($m,AccessRestrictions_s) AccessRestrictionsUnit
+# ----
+set m RecordSyntax-SUTRS
+set filename($m) z-sutrs
+#set map($m,SutrsRecord) SUTRS
+set body($m,c) {
+int z_SUTRS (ODR o, Odr_oct **p, int opt)
+{
+    return odr_implicit(o, odr_octetstring, p, ODR_UNIVERSAL,
+        ODR_GENERALSTRING, opt);
+}
+}
+
+set init($m,h) {
+typedef Odr_oct Z_SUTRS;
+YAZ_EXPORT int z_SUTRS (ODR o, Odr_oct **p, int opt);
+}
+# ----
+set m RecordSyntax-opac
+set filename($m) z-opac
+# ----
+set m RecordSyntax-summary
+set filename($m) z-sum
+# ----
+set m RecordSyntax-generic
+set filename($m) z-grs
+set map($m,ElementData_subtree) GenericRecord
+set map($m,Variant_0) Triple
+set membermap($m,Triple,class) zclass
+set unionmap($m,Triple,value) {which value Triple}
+set unionmap($m,GenericRecord) {num_elements elements}
+# ----
+set m RecordSyntax-ESTaskPackage
+set filename($m) z-estask
+# ----
+set m ResourceReport-Format-Resource-1
+set filename($m) z-rrf1
+set map($m,ResourceReport) ResourceReport1
+set map($m,Estimate) Estimate1
+# ----
+set m ResourceReport-Format-Resource-2
+set filename($m) z-rrf2
+set map($m,ResourceReport) ResourceReport2
+set map($m,Estimate) Estimate2
+# ----
+set m AccessControlFormat-prompt-1
+set filename($m) z-accform1
+set membermap($m,PromptId,enummeratedPrompt) enumeratedPrompt 
+set map($m,PromptObject) PromptObject1
+set map($m,Challenge) Challenge1
+set map($m,Challenge1_s) ChallengeUnit1
+set map($m,Response) Response1
+set map($m,Response1_s) ResponseUnit1
+set map($m,PromptObject) PromptObject1
+# ----
+set m AccessControlFormat-des-1
+set filename($m) z-accdes1
+# ----
+set m AccessControlFormat-krb-1
+set filename($m) z-acckrb1
+# ----
+set m ESFormat-PersistentResultSet
+set filename($m) zes-pset
+# ----
+set m ESFormat-PersistentQuery
+set filename($m) zes-pquery
+# ----
+set m ESFormat-PeriodicQuerySchedule 
+set filename($m) zes-psched
+# ----
+set m ESFormat-ItemOrder
+set filename($m) zes-order
+set map($m,ItemOrderEsRequest) Request
+set map($m,ItemOrderTaskPackage) TaskPackage
+set map($m,OriginPartToKeep_0) Contact
+set map($m,OriginPartToKeep_1) Billing
+set map($m,OriginPartNotToKeep_0) ResultSetItem
+#
+# ---- (old version)
+set m ESFormat-Update0
+set filename($m) zes-update0
+set map($m,SuppliedRecords_s) SuppliedRecords_elem
+set map($m,SuppliedRecords_elem_0) SuppliedRecordsId
+#
+# ---- (new, current version)
+set m ESFormat-Update
+set filename($m) zes-update
+set map($m,SuppliedRecords_s) SuppliedRecords_elem
+set map($m,SuppliedRecords_elem_0) SuppliedRecordsId
+# ----
+set m ESFormat-ExportSpecification
+set filename($m) zes-exps
+# ----
+set m ESFormat-ExportInvocation
+set filename($m) zes-expi
+# ----
+set m UserInfoFormat-searchResult-1
+set filename($m) z-uifr1
+# ----
+set m ElementSpecificationFormat-eSpec-1
+set filename($m) z-espec1
+set map($m,Espec-1) Espec1
+set map($m,TagPath) ETagPath
+set map($m,ETagPath_s) ETagUnit
+set map($m,ETagUnitSpecificTag) SpecificTag
+set membermap($m,SpecificTag,occurrence) occurrences
+set unionmap($m,ElementRequest) {which u ERequest}
+set unionmap($m,ETagPath) {num_tags tags}
+set map($m,OccurrencesValues) OccurValues
+# ----
+set m UserInfoFormat-dateTime
+set filename($m) z-date
+set map($m,Z3950Date) Date
+set map($m,Z3950Time) Time
+set unionmap($m,Z3950Date,era) {}
+set map($m,DateFlags_0) Era
+set map($m,Z3950DateMonthAndDay) MonthAndDay
+set map($m,Z3950DateQuarter) DateQuater
+set map($m,Z3950DateSeason) DateSeason
+set map($m,Date_0) DateFlags
+set unionmap($m,DateFlags,era) {}
+# ----
+set m ResourceReport-Format-Universe-1 
+set filename($m) z-univ
+
+# ----------------------------------------------------------
+# "Constructed" types defined by means of C-types are declared here.
+# Each function returns the C-handler and the C-type.
+proc asnBasicEXTERNAL {} {
+    return {z_External Z_External}
+}
Index: /main/tags/2.25/gsdl/packages/yaz/z39.50/z3950v3.asn
===================================================================
--- /main/tags/2.25/gsdl/packages/yaz/z39.50/z3950v3.asn	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/yaz/z39.50/z3950v3.asn	(revision 21064)
@@ -0,0 +1,2590 @@
+Z39-50-APDU-1995 -- OID for this definition, assigned in OID.3.1, is {Z39-50 2 1} 
+DEFINITIONS ::=  
+BEGIN   -- Z39.50 Maintenance Agency Official Text for ANSI/NISO Z39.50-1995 - July 1995
+--
+EXPORTS OtherInformation, Term, AttributeSetId, AttributeList, AttributeElement, ElementSetName, SortElement, DatabaseName,
+CompSpec, Specification, Permissions, InternationalString, IntUnit, Unit, StringOrNumeric, Query, Records, ResultSetId,
+DefaultDiagFormat, DiagRec;
+--
+
+PDU ::= CHOICE{
+ initRequest        [20] IMPLICIT InitializeRequest,
+ initResponse      [21] IMPLICIT InitializeResponse,
+ searchRequest      [22] IMPLICIT SearchRequest,
+ searchResponse      [23] IMPLICIT SearchResponse,
+ presentRequest      [24] IMPLICIT PresentRequest,
+ presentResponse      [25] IMPLICIT PresentResponse,
+ deleteResultSetRequest    [26] IMPLICIT DeleteResultSetRequest,
+ deleteResultSetResponse    [27] IMPLICIT DeleteResultSetResponse,
+ accessControlRequest    [28] IMPLICIT AccessControlRequest,
+ accessControlResponse    [29] IMPLICIT AccessControlResponse,
+ resourceControlRequest         [30] IMPLICIT ResourceControlRequest,
+ resourceControlResponse    [31] IMPLICIT ResourceControlResponse,
+ triggerResourceControlRequest  [32] IMPLICIT TriggerResourceControlRequest,
+ resourceReportRequest          [33] IMPLICIT ResourceReportRequest,
+ resourceReportResponse    [34] IMPLICIT ResourceReportResponse,
+ scanRequest         [35] IMPLICIT ScanRequest,
+ scanResponse      [36] IMPLICIT ScanResponse,
+              -- [37] through [42] reserved
+ sortRequest        [43] IMPLICIT SortRequest,
+ sortResponse      [44] IMPLICIT SortResponse,
+ segmentRequest      [45] IMPLICIT Segment,
+ extendedServicesRequest    [46] IMPLICIT ExtendedServicesRequest,
+ extendedServicesResponse    [47] IMPLICIT ExtendedServicesResponse,
+ close          [48] IMPLICIT Close}
+
+
+-- Initialize APDUs
+--
+  InitializeRequest ::= SEQUENCE{
+  referenceId        ReferenceId OPTIONAL,
+  protocolVersion      ProtocolVersion,
+  options        Options,
+  preferredMessageSize  [5]  IMPLICIT INTEGER,
+   exceptionalRecordSize  [6]  IMPLICIT INTEGER,
+   idAuthentication    [7]    IdAuthentication OPTIONAL, -- see note below
+  implementationId    [110]  IMPLICIT InternationalString OPTIONAL,
+  implementationName  [111]  IMPLICIT InternationalString OPTIONAL,
+   implementationVersion  [112]  IMPLICIT InternationalString OPTIONAL,   
+  userInformationField  [11]  EXTERNAL OPTIONAL,
+  otherInfo        OtherInformation OPTIONAL}
+--Note:
+-- For idAuthentication, the type ANY is retained for compatibility with earlier versions. 
+-- For interoperability, the following is recommended:
+IdAuthentication ::=
+   CHOICE{
+      open   VisibleString,
+      idPass  SEQUENCE {
+      groupId  [0]  IMPLICIT InternationalString OPTIONAL,
+      userId   [1]  IMPLICIT InternationalString OPTIONAL,
+      password  [2]  IMPLICIT InternationalString OPTIONAL },
+      anonymous  NULL,
+      other    EXTERNAL
+   }
+-- May use access control formats for 'other'.  See Appendix 7 ACC.
+--
+  InitializeResponse ::= SEQUENCE{
+  referenceId        ReferenceId OPTIONAL,
+   protocolVersion                ProtocolVersion,
+  options              Options,
+  preferredMessageSize  [5]  IMPLICIT INTEGER,
+   exceptionalRecordSize  [6]  IMPLICIT INTEGER,
+  result        [12]  IMPLICIT BOOLEAN,    -- reject = FALSE; Accept = TRUE
+  implementationId    [110]  IMPLICIT InternationalString OPTIONAL,
+  implementationName  [111]  IMPLICIT InternationalString OPTIONAL,
+   implementationVersion  [112]  IMPLICIT InternationalString OPTIONAL,   
+  userInformationField  [11]  EXTERNAL OPTIONAL,
+  otherInfo        OtherInformation OPTIONAL}
+-- Begin auxiliary definitions for Init PDUs
+  ProtocolVersion  ::=  [3]   IMPLICIT BIT STRING{
+    version-1      (0),       -- This bit should always be set, but does not
+              -- correspond to any Z39.50 version.
+    version-2      (1),              -- "Version 2 supported."
+              -- This bit should always be set.
+    version-3      (2)        -- "Version 3 supported."
+-- Values higher than 'version-3' should be ignored. Both the Initialize request and Initialize Response APDUs
+-- include a value string corresponding to the supported versions. The highest common version is selected
+-- for use. If there are no versions in common, "Result" in the Init Response should indicate "reject."
+-- Note: Versions 1 and 2 are identical. Systems supporting version 2 should indicate support for version
+-- 1 as well, for interoperability with systems that indicate support for version 1 only (e.g. ISO 10163-1991
+-- implementations).  
+  }
+  Options  ::= [4] IMPLICIT BIT STRING{ 
+      search        (0), 
+      present       (1), 
+      delSet        (2),
+       resourceReport    (3),
+      triggerResourceCtrl    (4),
+      resourceCtrl       (5), 
+      accessCtrl       (6),
+      scan         (7),
+      sort        (8), 
+      --        (9) (reserved)
+      extendedServices    (10),
+      level-1Segmentation    (11),
+      level-2Segmentation    (12),
+      concurrentOperations  (13),
+      namedResultSets    (14)}
+-- end auxiliary definitions for Init PDUs
+
+
+--Search APDUs
+  SearchRequest ::= SEQUENCE{
+  referenceId          ReferenceId OPTIONAL,
+      smallSetUpperBound    [13]  IMPLICIT INTEGER,
+  largeSetLowerBound    [14]  IMPLICIT INTEGER,
+  mediumSetPresentNumber    [15]  IMPLICIT INTEGER,
+  replaceIndicator      [16]  IMPLICIT BOOLEAN,
+  resultSetName      [17]  IMPLICIT InternationalString,
+   databaseNames      [18]   IMPLICIT SEQUENCE OF DatabaseName,
+   smallSetElementSetNames    [100]  ElementSetNames OPTIONAL,
+    mediumSetElementSetNames  [101]  ElementSetNames OPTIONAL,
+  preferredRecordSyntax    [104]  IMPLICIT OBJECT IDENTIFIER OPTIONAL,
+  query          [21]  Query,
+    -- Following two parameters may be used only if version 3 is in force.
+   additionalSearchInfo    [203]  IMPLICIT OtherInformation OPTIONAL,
+  otherInfo          OtherInformation OPTIONAL}
+
+
+-- Query Definitions
+  Query  ::=  CHOICE{
+      type-0  [0]  ANY,  
+        type-1    [1]  IMPLICIT RPNQuery,
+        type-2      [2]  OCTET STRING,
+        type-100  [100]  OCTET STRING,
+        type-101  [101]  IMPLICIT RPNQuery,
+       type-102  [102]  OCTET STRING}
+--
+-- Definitions for RPN query
+     RPNQuery ::= SEQUENCE{
+      attributeSet    AttributeSetId,
+      rpn      RPNStructure}
+--
+  RPNStructure ::= CHOICE{
+    op    [0] Operand, 
+     rpnRpnOp  [1] IMPLICIT SEQUENCE{
+          rpn1    RPNStructure,
+                rpn2    RPNStructure,
+                op    Operator }} 
+  Operand ::= CHOICE{
+    attrTerm  AttributesPlusTerm, 
+    resultSet  ResultSetId, 
+          -- If version 2 is in force: 
+          --   - If query type is 1, one of the above two must be chosen; 
+          --   - resultAttr (below) may be used only if query type is 101. 
+    resultAttr  ResultSetPlusAttributes}
+
+  AttributesPlusTerm ::= [102] IMPLICIT SEQUENCE{
+         attributes  AttributeList, 
+        term    Term}
+  ResultSetPlusAttributes ::= [214] IMPLICIT SEQUENCE{
+        resultSet  ResultSetId,
+        attributes  AttributeList}
+  AttributeList ::=    [44]  IMPLICIT SEQUENCE OF AttributeElement
+--
+  Term ::= CHOICE{
+    general      [45]  IMPLICIT OCTET STRING,
+              -- values below may be used only if version 3 is in force
+    numeric      [215]  IMPLICIT INTEGER,
+    characterString    [216]  IMPLICIT InternationalString,
+    oid        [217]  IMPLICIT OBJECT IDENTIFIER,
+    dateTime      [218]  IMPLICIT GeneralizedTime,
+    external      [219]  IMPLICIT EXTERNAL,
+    integerAndUnit    [220] IMPLICIT IntUnit,
+    null        [221] IMPLICIT NULL}   
+
+  Operator ::= [46] CHOICE{
+         and    [0] IMPLICIT NULL,
+            or    [1] IMPLICIT NULL,
+                and-not  [2] IMPLICIT NULL,
+              -- If version 2 is in force: 
+              --  - For query type 1, one of the above three must be chosen;
+              --  - prox (below) may be used only if query type is 101. 
+        prox    [3] IMPLICIT ProximityOperator}
+  AttributeElement  ::=  SEQUENCE{
+    attributeSet    [1]    IMPLICIT AttributeSetId OPTIONAL,
+                -- Must be omitted if version 2 is in force.
+                -- If included, overrides value of attributeSet
+                -- in RPNQuery above, but only for this attribute.
+    attributeType  [120]  IMPLICIT INTEGER,
+    attributeValue    CHOICE{
+              numeric  [121]   IMPLICIT INTEGER,
+                  -- If version 2 is in force, 
+                  -- Must select 'numeric' for attributeValue.
+
+      complex  [224] IMPLICIT SEQUENCE{ 
+               list      [1] IMPLICIT SEQUENCE OF StringOrNumeric,
+                    semanticAction  [2] IMPLICIT SEQUENCE OF INTEGER OPTIONAL}}}
+                       
+
+  ProximityOperator ::= SEQUENCE{
+    exclusion      [1] IMPLICIT BOOLEAN OPTIONAL,
+    distance      [2] IMPLICIT INTEGER,
+    ordered      [3] IMPLICIT BOOLEAN,
+    relationType      [4] IMPLICIT INTEGER{
+              lessThan      (1),
+              lessThanOrEqual    (2),
+              equal        (3),
+              greaterThanOrEqual    (4),
+              greaterThan      (5),
+              notEqual      (6)},
+    proximityUnitCode    [5] CHOICE{
+              known  [1] IMPLICIT KnownProximityUnit,
+              private  [2] IMPLICIT INTEGER}}
+--
+    KnownProximityUnit ::= INTEGER{
+          character  (1),
+          word     (2),
+          sentence   (3),
+          paragraph   (4),
+          section   (5),
+          chapter   (6),
+          document   (7),
+          element  (8),
+          subelement  (9),
+          elementType  (10),
+           byte    (11) -- Version 3 only
+          }
+-- End definitions for RPN Query
+
+
+SearchResponse ::= SEQUENCE{
+  referenceId        ReferenceId OPTIONAL,
+  resultCount       [23]  IMPLICIT INTEGER,
+  numberOfRecordsReturned  [24]  IMPLICIT INTEGER,
+  nextResultSetPosition  [25]  IMPLICIT INTEGER,
+  searchStatus      [22]  IMPLICIT BOOLEAN,
+  resultSetStatus    [26]  IMPLICIT INTEGER{
+              subset    (1),
+                 interim  (2), 
+               none    (3)} OPTIONAL,
+  presentStatus        PresentStatus  OPTIONAL,
+    records        Records OPTIONAL,
+    -- Following two parameters may be used only if version 3 is in force.
+  additionalSearchInfo  [203]  IMPLICIT OtherInformation OPTIONAL,
+  otherInfo        OtherInformation OPTIONAL}
+--Retrieval APDUs 
+  PresentRequest ::= SEQUENCE{
+  referenceId          ReferenceId OPTIONAL,
+      resultSetId          ResultSetId,
+  resultSetStartPoint      [30]  IMPLICIT INTEGER,
+  numberOfRecordsRequested  [29]  IMPLICIT INTEGER,
+  additionalRanges      [212]  IMPLICIT SEQUENCE OF Range OPTIONAL,
+      -- additionalRanges may be included only if version 3 is in force.
+  recordComposition      CHOICE{
+                simple  [19]         ElementSetNames,
+                -- must choose 'simple' if version 2 is in force
+                complex  [209]               IMPLICIT CompSpec} OPTIONAL,
+  preferredRecordSyntax    [104]  IMPLICIT OBJECT IDENTIFIER OPTIONAL,
+  maxSegmentCount      [204]  IMPLICIT INTEGER OPTIONAL, -- level 1 or 2
+  maxRecordSize      [206]  IMPLICIT INTEGER OPTIONAL, -- level 2 only
+  maxSegmentSize      [207]  IMPLICIT INTEGER OPTIONAL, -- level 2 only
+  otherInfo          OtherInformation OPTIONAL}
+--
+  Segment ::= SEQUENCE{
+      -- Segment PDU may only be used when version 3 is in force, 
+      -- and only when segmentation is in effect.
+   referenceId          ReferenceId OPTIONAL,
+     numberOfRecordsReturned    [24]  IMPLICIT INTEGER,
+  segmentRecords      [0]  IMPLICIT SEQUENCE OF NamePlusRecord,
+  otherInfo          OtherInformation OPTIONAL}
+--
+  PresentResponse ::= SEQUENCE{
+  referenceId          ReferenceId OPTIONAL,
+  numberOfRecordsReturned    [24]  IMPLICIT INTEGER,
+   nextResultSetPosition    [25]  IMPLICIT INTEGER,
+    presentStatus          PresentStatus,
+  records          Records OPTIONAL,
+  otherInfo          OtherInformation OPTIONAL} 
+-- begin auxiliary definitions for Search and Present APDUs
+
+-- begin definition of records
+  Records ::= CHOICE{
+  responseRecords      [28]  IMPLICIT SEQUENCE OF NamePlusRecord,
+  nonSurrogateDiagnostic     [130]  IMPLICIT DefaultDiagFormat,
+  multipleNonSurDiagnostics   [205]  IMPLICIT SEQUENCE OF DiagRec} 
+--
+  NamePlusRecord  ::=  SEQUENCE{
+  name    [0] IMPLICIT DatabaseName OPTIONAL,
+  record  [1] CHOICE{
+        retrievalRecord        [1] EXTERNAL,
+        surrogateDiagnostic    [2] DiagRec, 
+          -- Must select one of the above two, retrievalRecord or
+          -- surrogateDiagnostic, unless 'level 2 segmentation' is in effect.
+        startingFragment    [3] FragmentSyntax,
+        intermediateFragment  [4] FragmentSyntax,
+        finalFragment    [5] FragmentSyntax}}
+  FragmentSyntax ::= CHOICE{
+    externallyTagged    EXTERNAL,
+    notExternallyTagged  OCTET STRING}
+
+  DiagRec ::= CHOICE{
+      defaultFormat    DefaultDiagFormat,
+                -- Must choose defaultFormat if version 2 is in effect.
+      externallyDefined    EXTERNAL}
+
+  DefaultDiagFormat::= SEQUENCE{ 
+  diagnosticSetId  OBJECT IDENTIFIER,
+  condition    INTEGER,
+  addinfo      CHOICE{
+           v2Addinfo  VisibleString,  -- version 2
+           v3Addinfo  InternationalString  -- version 3
+            }}
+  -- end definition of records
+  Range  ::= SEQUENCE{
+    startingPosition    [1] IMPLICIT INTEGER,
+    numberOfRecords    [2] IMPLICIT INTEGER} 
+--
+  ElementSetNames ::= CHOICE {
+    genericElementSetName  [0] IMPLICIT InternationalString,
+    databaseSpecific    [1] IMPLICIT SEQUENCE OF SEQUENCE{
+              dbName  DatabaseName,
+              esn    ElementSetName}}
+
+  PresentStatus   ::=    [27]  IMPLICIT INTEGER{
+                            success  (0),
+                             partial-1   (1),
+                              partial-2   (2),
+              partial-3   (3),
+                                      partial-4   (4),
+                               failure    (5)}
+
+-- begin definition of composition specification
+  CompSpec ::= SEQUENCE{
+  selectAlternativeSyntax  [1] IMPLICIT BOOLEAN,
+            -- See comment for recordSyntax, below.
+  generic             [2] IMPLICIT Specification OPTIONAL,
+  dbSpecific      [3] IMPLICIT SEQUENCE OF SEQUENCE{
+                db  [1] DatabaseName,
+                spec  [2] IMPLICIT Specification} OPTIONAL,
+    -- At least one of generic and dbSpecific must occur, and both may occur. If both, then for
+     -- any record not in the list of databases within dbSpecific, generic applies.
+   recordSyntax               [4] IMPLICIT SEQUENCE OF OBJECT IDENTIFIER OPTIONAL
+               -- For each record, the target selects the first record syntax
+               -- in this list that it can support.  If the list is exhausted, the
+               -- target may select an alternative syntax if
+               -- selectAlternativeSyntax is 'true'.
+        }
+  Specification ::= SEQUENCE{
+  schema    [1] IMPLICIT OBJECT IDENTIFIER OPTIONAL,
+  elementSpec    [2] CHOICE{
+              elementSetName   [1] IMPLICIT InternationalString,
+          externalEspec  [2] IMPLICIT EXTERNAL} OPTIONAL}
+-- end definition of composition specification
+-- end auxiliary definitions for search and response APDUs
+
+-- Delete APDUs
+  DeleteResultSetRequest ::= SEQUENCE{
+  referenceId          ReferenceId OPTIONAL,
+      deleteFunction      [32]  IMPLICIT INTEGER{
+                    list   (0),
+                    all   (1)},
+   resultSetList          SEQUENCE OF ResultSetId OPTIONAL,
+  otherInfo          OtherInformation OPTIONAL} 
+--
+  DeleteResultSetResponse ::= SEQUENCE{
+  referenceId          ReferenceId OPTIONAL,
+    deleteOperationStatus    [0]  IMPLICIT DeleteSetStatus,
+  deleteListStatuses      [1]  IMPLICIT ListStatuses OPTIONAL,
+  numberNotDeleted       [34]  IMPLICIT INTEGER OPTIONAL,
+     bulkStatuses        [35]   IMPLICIT ListStatuses OPTIONAL,
+   deleteMessage      [36]  IMPLICIT InternationalString OPTIONAL,
+  otherInfo          OtherInformation OPTIONAL}
+  ListStatuses ::= SEQUENCE OF SEQUENCE{ 
+        id  ResultSetId, 
+        status  DeleteSetStatus}
+
+  DeleteSetStatus ::= [33] IMPLICIT INTEGER{
+                  success          (0),
+                   resultSetDidNotExist      (1),
+                    previouslyDeletedByTarget      (2),
+                     systemProblemAtTarget      (3),
+                   accessNotAllowed        (4),
+      resourceControlAtOrigin      (5),
+                   resourceControlAtTarget      (6),
+                    bulkDeleteNotSupported      (7),
+                   notAllRsltSetsDeletedOnBulkDlte    (8),
+      notAllRequestedResultSetsDeleted    (9),
+      resultSetInUse        (10)}
+--
+
+--Access- and Resource-control APDUs
+--
+  AccessControlRequest ::= SEQUENCE{
+  referenceId        ReferenceId OPTIONAL,
+  securityChallenge      CHOICE{
+              simpleForm      [37] IMPLICIT OCTET STRING,
+               externallyDefined    [0]  EXTERNAL},
+  otherInfo        OtherInformation OPTIONAL}
+
+  AccessControlResponse ::= SEQUENCE{
+  referenceId        ReferenceId OPTIONAL,
+  securityChallengeResponse  CHOICE{
+              simpleForm      [38]   IMPLICIT OCTET STRING,
+               externallyDefined    [0]  EXTERNAL} OPTIONAL,
+              -- Optional only in version 3; mandatory in version 2. If
+              -- omitted (in version 3) then diagnostic must occur.
+  diagnostic    [223]    DiagRec OPTIONAL, -- Version 3 only.
+  otherInfo        OtherInformation OPTIONAL}
+
+
+
+  ResourceControlRequest ::= SEQUENCE{
+  referenceId          ReferenceId OPTIONAL,
+  suspendedFlag      [39]  IMPLICIT BOOLEAN OPTIONAL,
+  resourceReport      [40]  ResourceReport OPTIONAL,
+  partialResultsAvailable    [41]  IMPLICIT INTEGER{
+                subset    (1),
+                interim  (2),
+                none    (3)} OPTIONAL,
+  responseRequired      [42]   IMPLICIT BOOLEAN, 
+  triggeredRequestFlag    [43]   IMPLICIT BOOLEAN OPTIONAL,
+  otherInfo          OtherInformation OPTIONAL}
+
+
+  ResourceControlResponse ::= SEQUENCE{
+     referenceId          ReferenceId OPTIONAL,
+    continueFlag       [44]   IMPLICIT BOOLEAN, 
+  resultSetWanted      [45]  IMPLICIT BOOLEAN OPTIONAL,
+  otherInfo          OtherInformation OPTIONAL}
+
+
+
+  TriggerResourceControlRequest ::= SEQUENCE{
+     referenceId          ReferenceId OPTIONAL,
+  requestedAction      [46]  IMPLICIT INTEGER{
+                resourceReport  (1),
+                resourceControl  (2),
+                cancel      (3)}, 
+  prefResourceReportFormat    [47]   IMPLICIT ResourceReportId OPTIONAL,
+  resultSetWanted      [48]   IMPLICIT BOOLEAN OPTIONAL,
+  otherInfo          OtherInformation OPTIONAL}
+
+
+
+  ResourceReportRequest ::= SEQUENCE{
+     referenceId          ReferenceId OPTIONAL,
+  opId          [210]  IMPLICIT ReferenceId OPTIONAL,
+  prefResourceReportFormat    [49]   IMPLICIT ResourceReportId OPTIONAL,
+  otherInfo          OtherInformation OPTIONAL}
+--
+  ResourceReportResponse ::= SEQUENCE{
+     referenceId          ReferenceId OPTIONAL,
+  resourceReportStatus    [50]   IMPLICIT INTEGER{
+                success    (0),
+                partial    (1),
+                failure-1    (2),
+                failure-2    (3),
+                failure-3    (4),
+                failure-4    (5),
+                failure-5    (6),
+                failure-6    (7)},
+  resourceReport               [51]   ResourceReport OPTIONAL,
+  otherInfo          OtherInformation OPTIONAL}
+--
+   ResourceReport     ::=   EXTERNAL
+  ResourceReportId    ::=    OBJECT IDENTIFIER
+
+--Scan APDUs
+  ScanRequest ::= SEQUENCE{
+  referenceId              ReferenceId OPTIONAL,
+    databaseNames        [3]  IMPLICIT SEQUENCE OF DatabaseName,
+    attributeSet            AttributeSetId OPTIONAL,
+    termListAndStartPoint        AttributesPlusTerm,
+    stepSize           [5]   IMPLICIT INTEGER OPTIONAL,
+    numberOfTermsRequested         [6]   IMPLICIT INTEGER,
+    preferredPositionInResponse      [7]   IMPLICIT INTEGER OPTIONAL,
+    otherInfo            OtherInformation OPTIONAL}
+
+  ScanResponse ::= SEQUENCE{
+   referenceId              ReferenceId OPTIONAL,
+   stepSize           [3]  IMPLICIT INTEGER OPTIONAL,
+   scanStatus           [4]  IMPLICIT INTEGER {
+                                success   (0),
+                                partial-1   (1),
+                                partial-2   (2),
+                                partial-3   (3),
+                                partial-4   (4),
+                                partial-5   (5),
+                                failure  (6) },
+   numberOfEntriesReturned       [5]  IMPLICIT INTEGER,
+   positionOfTerm         [6]  IMPLICIT INTEGER OPTIONAL,
+   entries           [7]  IMPLICIT ListEntries  OPTIONAL,  
+   attributeSet          [8]  IMPLICIT AttributeSetId OPTIONAL,
+   otherInfo            OtherInformation OPTIONAL}
+
+-- begin auxiliary definitions for Scan
+  ListEntries ::= SEQUENCE{
+  entries        [1]   IMPLICIT SEQUENCE OF Entry OPTIONAL,
+    nonsurrogateDiagnostics    [2]  IMPLICIT SEQUENCE OF DiagRec OPTIONAL
+    -- At least one of entries and nonsurrogateDiagnostics must occur
+          }
+
+  Entry  ::= CHOICE {
+     termInfo               [1]   IMPLICIT TermInfo,
+     surrogateDiagnostic    [2]   DiagRec}
+--
+  TermInfo ::= SEQUENCE {
+   term                    Term,
+     displayTerm      [0]   IMPLICIT InternationalString OPTIONAL,
+                                     -- Presence of displayTerm means that term is not considered by
+              -- the target to be suitable for display, and displayTerm should
+              -- instead be displayed. 'term' is the actual term in the term list;
+               -- 'displayTerm' is for display purposes only, and is not an actual
+              -- term in the term list.
+  suggestedAttributes            AttributeList OPTIONAL,
+     alternativeTerm    [4]  IMPLICIT SEQUENCE OF AttributesPlusTerm OPTIONAL, 
+     globalOccurrences    [2]  IMPLICIT INTEGER OPTIONAL,
+     byAttributes      [3]  IMPLICIT OccurrenceByAttributes OPTIONAL,
+     otherTermInfo      OtherInformation OPTIONAL} 
+
+  OccurrenceByAttributes ::= SEQUENCE OF SEQUENCE{
+     attributes    [1]  AttributeList, 
+     occurrences       CHOICE{
+               global    [2] INTEGER,
+            byDatabase  [3] IMPLICIT SEQUENCE OF SEQUENCE{ 
+              db      DatabaseName,
+              num     [1]  IMPLICIT INTEGER OPTIONAL,
+              otherDbInfo    OtherInformation OPTIONAL}} OPTIONAL,
+     otherOccurInfo    OtherInformation OPTIONAL} 
+-- end auxiliary definitions for Scan
+
+-- Sort APDUs
+SortRequest  ::= SEQUENCE{
+  referenceId              ReferenceId OPTIONAL,
+  inputResultSetNames  [3]  IMPLICIT SEQUENCE OF InternationalString,
+  sortedResultSetName  [4]    IMPLICIT InternationalString,
+  sortSequence     [5]  IMPLICIT SEQUENCE OF SortKeySpec,
+              -- order of occurrence is from major to minor
+  otherInfo        OtherInformation OPTIONAL}
+
+SortResponse  ::= SEQUENCE{
+  referenceId          ReferenceId OPTIONAL,
+  sortStatus         [3]  IMPLICIT INTEGER{
+                            success  (0), 
+              partial-1  (1),
+              failure  (2)},
+  resultSetStatus    [4]  IMPLICIT INTEGER{
+              empty    (1), 
+                  interim  (2), 
+                  unchanged  (3),
+              none    (4)} OPTIONAL,
+  diagnostics        [5]             IMPLICIT SEQUENCE OF DiagRec OPTIONAL,
+  otherInfo        OtherInformation OPTIONAL}
+
+-- begin auxiliary definitions for Sort
+  SortKeySpec ::= SEQUENCE{
+    sortElement      SortElement, 
+       sortRelation    [1]  IMPLICIT INTEGER{
+                                ascending      (0),
+              descending      (1),
+              ascendingByFrequency    (3),
+              descendingByfrequency  (4)},
+      caseSensitivity    [2]   IMPLICIT INTEGER{
+                                 caseSensitive      (0), 
+              caseInsensitive    (1)},
+      missingValueAction    [3]   CHOICE{
+                                     abort    [1] IMPLICIT NULL,
+                                     null      [2] IMPLICIT NULL,
+                    --supply a null value for missing value
+          missingValueData  [3] IMPLICIT OCTET STRING} OPTIONAL}
+
+  SortElement ::=   CHOICE{
+    generic        [1] SortKey,
+       datbaseSpecific    [2] IMPLICIT SEQUENCE OF SEQUENCE{
+                       databaseName  DatabaseName,
+                       dbSort    SortKey}} 
+
+  SortKey ::= CHOICE{
+    sortfield       [0]  IMPLICIT InternationalString,
+                  -- An element, element-group-tag, or alias supported by the target
+               -- and denoting a set of elements associated with each record.
+     elementSpec    [1]  IMPLICIT Specification,
+        sortAttributes    [2]  IMPLICIT SEQUENCE{
+              id  AttributeSetId,
+              list  AttributeList}}
+-- end auxiliary definitions for sort
+
+
+
+-- Extended Service APDUs
+  ExtendedServicesRequest  ::= SEQUENCE{
+  referenceId              ReferenceId OPTIONAL,
+  function      [3]  IMPLICIT INTEGER {
+              create    (1),
+              delete    (2),
+              modify  (3)},
+  packageType      [4]  IMPLICIT OBJECT IDENTIFIER,
+  packageName    [5]  IMPLICIT InternationalString OPTIONAL,
+              -- PackageName mandatory for 'modify' or 'delete'; optional for
+              -- 'create'. Following four parameters mandatory for 'create'; should
+              -- be included on 'modify' if being modified; not needed on 'delete'.
+  userId        [6]   IMPLICIT InternationalString OPTIONAL,
+  retentionTime    [7]   IMPLICIT IntUnit OPTIONAL,
+  permissions      [8]   IMPLICIT Permissions OPTIONAL,
+  description      [9]   IMPLICIT InternationalString OPTIONAL,
+
+-- (ExtendedServiceRequest APDU continued)
+  taskSpecificParameters  [10]  IMPLICIT EXTERNAL OPTIONAL, 
+              -- Mandatory for 'create'; included on 'modify' if specific
+              -- parameters being modified; not necessary on 'delete'. For the
+              -- 'EXTERNAL,' use OID of specific ES definition and select
+              --  CHOICE [1]: 'esRequest'.
+  waitAction      [11]  IMPLICIT INTEGER{
+              wait      (1),
+              waitIfPossible  (2),
+              dontWait    (3),
+              dontReturnPackage  (4)},
+  elements          ElementSetName OPTIONAL,
+  otherInfo          OtherInformation OPTIONAL}
+--
+
+ExtendedServicesResponse ::= SEQUENCE{
+  referenceId                ReferenceId OPTIONAL,
+  operationStatus    [3]    IMPLICIT INTEGER{
+                done      (1),
+                accepted    (2),  
+                failure    (3)},
+  diagnostics      [4]    IMPLICIT SEQUENCE OF DiagRec OPTIONAL,
+  taskPackage      [5]    IMPLICIT EXTERNAL OPTIONAL,
+                -- Use OID: {Z39-50-recordSyntax (106)} and corresponding
+                -- syntax. For the EXTERNAL, 'taskSpecific,' within that
+                -- definition, use OID of the specific es, and choose [2],
+                -- 'taskPackage'.
+  otherInfo          OtherInformation OPTIONAL}
+
+ Permissions ::= SEQUENCE OF SEQUENCE{
+  userId      [1] IMPLICIT InternationalString,
+  allowableFunctions  [2] IMPLICIT SEQUENCE OF INTEGER{
+              delete      (1),
+              modifyContents  (2),
+              modifyPermissions  (3),
+              present    (4),
+                 invoke    (5)}} 
+
+Close ::= SEQUENCE{
+  referenceId          ReferenceId OPTIONAL,  -- See 3.2.11.1.5.
+  closeReason          CloseReason,
+  diagnosticInformation    [3]  IMPLICIT InternationalString OPTIONAL,
+  resourceReportFormat    [4]  IMPLICIT ResourceReportId OPTIONAL, 
+                -- For use by origin only, and only on Close request;
+                -- origin requests target to include report in response.
+   resourceReport      [5]  ResourceReport OPTIONAL,
+                -- For use by target only, unilaterally on Close request;
+                -- on Close response may be unilateral or in response
+                -- to origin request.
+  otherInfo          OtherInformation OPTIONAL}
+
+  CloseReason ::=  [211]  IMPLICIT INTEGER{
+            finished      (0),
+            shutdown      (1),
+            systemProblem    (2),
+            costLimit      (3),
+            resources      (4),
+            securityViolation    (5),
+            protocolError    (6),
+            lackOfActivity    (7),
+            peerAbort      (8),
+            unspecified      (9)}
+
+
+-- Global auxiliary definitions
+  ReferenceId       ::=      [2]  IMPLICIT OCTET STRING
+  ResultSetId        ::=      [31]    IMPLICIT InternationalString
+  ElementSetName     ::=     [103]   IMPLICIT InternationalString
+  DatabaseName     ::=    [105]   IMPLICIT InternationalString
+  AttributeSetId     ::=       OBJECT IDENTIFIER
+
+
+-- OtherInformation
+  OtherInformation   ::= [201] IMPLICIT SEQUENCE OF SEQUENCE{
+    category            [1]   IMPLICIT InfoCategory OPTIONAL, 
+    information        CHOICE{
+      characterInfo        [2]  IMPLICIT InternationalString,
+      binaryInfo        [3]  IMPLICIT OCTET STRING,
+      externallyDefinedInfo    [4]  IMPLICIT EXTERNAL,
+      oid          [5]  IMPLICIT OBJECT IDENTIFIER}}
+--
+  InfoCategory ::= SEQUENCE{
+      categoryTypeId  [1]   IMPLICIT OBJECT IDENTIFIER OPTIONAL,
+      categoryValue  [2]   IMPLICIT INTEGER}
+
+
+-- Units
+  -- IntUnit is used when value and unit are supplied together. Unit, alone, is used when just
+  -- specifying a unit (without a value).  For example, IntUnit is used in Term, in an RPNQuery, or
+  -- it can be the datatype of an element within a retrieval record. Unit (alone) would be used in an
+  -- element request, when requesting data be returned according to a particular unit.
+
+  IntUnit ::= SEQUENCE{
+    value    [1] IMPLICIT INTEGER,
+    unitUsed  [2] IMPLICIT Unit}
+--
+  Unit ::= SEQUENCE{
+    unitSystem    [1] InternationalString OPTIONAL,    -- e.g. 'SI'
+    unitType    [2] StringOrNumeric OPTIONAL,    -- e.g. 'mass'
+    unit      [3] StringOrNumeric OPTIONAL,    -- e.g. 'kilograms'
+    scaleFactor    [4] IMPLICIT INTEGER OPTIONAL    -- e.g. 9 means 10**9
+        }
+
+--CharacterString
+  InternationalString ::= GeneralString
+    -- When version 2 is in force, this collapses to VisibleString. That is, only characters in the
+    -- visibleString repertoire may be used. (Datatype compatibility with version 2 is not affected,
+     -- because references are IMPLICIT.)  When version 3 is in force, the semantics of the
+    -- GeneralString content may be altered by negotiation during initialization. If no such
+    -- negotiation is in effect, then GeneralString semantics are in force.
+
+StringOrNumeric ::= CHOICE{
+  string    [1] IMPLICIT InternationalString,
+  numeric  [2] IMPLICIT INTEGER}
+
+END -- IR DEFINITIONS
+
+
+
+DiagnosticFormatDiag1 
+{Z39-50-diagnosticFormat diag-1 (2)} DEFINITIONS ::=
+BEGIN
+IMPORTS Term, Specification, AttributeList, SortElement, DatabaseName, 
+DefaultDiagFormat, InternationalString FROM Z39-50-APDU-1995;
+
+
+DiagnosticFormat ::=  SEQUENCE OF SEQUENCE{ 
+  diagnostic  [1] CHOICE{
+              defaultDiagRec    [1]  IMPLICIT DefaultDiagFormat,
+              explicitDiagnostic    [2]  DiagFormat} OPTIONAL, 
+  message  [2] IMPLICIT InternationalString OPTIONAL} 
+
+
+DiagFormat ::= CHOICE{
+
+tooMany  [1000]   IMPLICIT SEQUENCE{
+                tooManyWhat   [1]  IMPLICIT INTEGER{
+                                  argumentWords        (1), 
+                                  truncatedWords        (2), 
+                                  booleanOperators      (3),
+                                  incompleteSubfields    (4), 
+                                  characters          (5),
+                                  recordsRetrieved      (6), 
+                                  dataBasesSpecified      (7),
+                                  resultSetsCreated      (8), 
+                                  indexTermsProcessed    (9)},
+                max        [2]  IMPLICIT INTEGER OPTIONAL},
+
+
+
+
+
+
+
+badSpec    [1001]  IMPLICIT SEQUENCE{  -- element set name or specification
+                spec        [1] IMPLICIT Specification, -- esn or element spec not supported
+                db        [2] IMPLICIT DatabaseName OPTIONAL,
+                            -- if db specified, above spec not supported for db; otherwise,
+                            -- spec not supported period.
+                goodOnes    [3] IMPLICIT SEQUENCE OF Specification OPTIONAL  
+                            -- target supplies ones that are supported
+                            },
+
+
+dbUnavail  [1002]  IMPLICIT SEQUENCE{ -- database unavailable
+                db  [1] IMPLICIT DatabaseName,
+                why  [2] IMPLICIT SEQUENCE{
+                        reasonCode  [1] IMPLICIT INTEGER{
+                                      doesNotExist    (0),
+                                      existsButUnavail  (1),
+                                      locked      (2),
+                                      accessDenied    (3)} OPTIONAL,
+                        message    [2] IMPLICIT InternationalString OPTIONAL}},
+
+
+unSupOp  [1003]  IMPLICIT INTEGER{  -- unsupported operator
+                and     (0),
+                or      (1),
+                and-not  (2),
+                prox    (3)},
+
+
+attribute    [1004]  IMPLICIT SEQUENCE{
+                    -- Applies for unsupported attribute set, attribute type, 
+                    -- attribute value, or term (for a given attribute type or value).
+
+                id      [1]  IMPLICIT OBJECT IDENTIFIER,
+                   -- if only "id" occurs, then attribute set is not supported
+                type    [2]  IMPLICIT INTEGER OPTIONAL,
+                   -- must occur if value occurs.
+                value    [3]   IMPLICIT INTEGER OPTIONAL,
+                    -- if omitted, and Type occurs, then Type is what is unsupported
+                term    [4]  Term OPTIONAL
+                    -- If occurs, term is illegal or not supported, for attribute value,
+                    -- if value occurs; otherwise, for type.
+                                },
+
+
+attCombo  [1005]  IMPLICIT SEQUENCE{ -- attribute combination not supported
+              unsupportedCombination  [1] IMPLICIT AttributeList, 
+              recommendedAlternatives  [2] IMPLICIT SEQUENCE OF AttributeList OPTIONAL}, 
+
+
+
+
+term      [1006]  IMPLICIT SEQUENCE{
+                problem    [1] IMPLICIT INTEGER{
+                            codedValue  (1),
+                            unparsable  (2),
+                            tooShort    (3),
+                            type      (4)} OPTIONAL,
+                term      [2] Term},
+
+
+proximity  [1007] CHOICE{        -- proximity diagnostics:
+               resultSets  [1]    IMPLICIT NULL,         -- proximity between sets not supported
+              badSet    [2]    IMPLICIT InternationalString,  -- bad result set specified
+                 relation    [3]   IMPLICIT INTEGER,      -- 1 to 6 ; relation not supported
+              unit      [4]  IMPLICIT INTEGER,      -- unsupported unit code
+              distance    [5]  IMPLICIT INTEGER,      -- unsupported distance
+              attributes  [6]  AttributeList,             --  proximity not supported with specified
+                                                   -- attribute combination
+              ordered    [7]  IMPLICIT NULL,        -- ordered flag not supported
+              exclusion  [8]  IMPLICIT NULL          -- exclusion flag not supported
+                    },
+
+
+
+
+
+scan     [1008] CHOICE{      -- scan diagnostics:
+              nonZeroStepSize  [0] IMPLICIT NULL,  -- only zero step size supported
+              specifiedStepSize  [1] IMPLICIT NULL,  -- specified step size not supported
+              termList1      [3] IMPLICIT NULL,  -- term list not supported (no alternative supplied)
+              termList2      [4] IMPLICIT SEQUENCE OF AttributeList,
+                                          -- term list not supported (alternatives supplied)
+              posInResponse    [5] IMPLICIT INTEGER{  --value of positionInResponse not supported
+                              mustBeOne        (1),
+                              mustBePositive    (2),
+                              mustBeNonNegative  (3),
+                              other            (4)},
+              resources      [6] IMPLICIT NULL,   -- resources exhausted looking for satisfying terms
+              endOfList      [7] IMPLICIT NULL  -- beginning or end of term list
+                },
+
+
+sort       [1009] CHOICE{
+              sequence    [0]  IMPLICIT NULL,        -- cannot sort according to sequence
+              noRsName    [1]  IMPLICIT NULL,        -- no result set name supplied
+              tooMany    [2]  IMPLICIT INTEGER,      --  Too many input result sets,
+                                                --  maximum supplied.
+              incompatible  [3]  IMPLICIT NULL,        -- records with different formats
+                                                 -- not compatible for sorting
+              generic      [4]  IMPLICIT NULL,        -- generic sort not supported 
+                                                -- (db specific only)
+              dbSpecific    [5]  IMPLICIT NULL,        -- db specific sort not supported
+              sortElement    [6]  SortElement,
+              key        [7]  IMPLICIT INTEGER{
+                              tooMany  (1),    -- too many sort keys
+                              duplicate  (2)},    -- duplicate sort keys
+              action      [8]  IMPLICIT NULL,  -- unsupported missing data action
+              illegal      [9]  IMPLICIT INTEGER{
+                              relation  (1),  -- illegal sort relation
+                              case    (2),  -- illegal case value
+                              action  (3),   -- illegal missing data action
+                              sort    (4)},  -- illegal sort
+            inputTooLarge    [10]  IMPLICIT SEQUENCE OF InternationalString,
+                                      --   one or more of the input result sets too large to sort
+          aggregateTooLarge  [11]  IMPLICIT NULL  --  aggregate result set too large
+                          },
+
+segmentation  [1010]  CHOICE{
+                segmentCount  [0]    IMPLICIT NULL,
+                                  -- Cannot guarantee record will fit within max segments. Target
+                                  -- suggests that origin try again to retrieve record, without
+                                  -- including max-segment-count.
+                segmentSize  [1]    IMPLICIT INTEGER
+                                -- record cannot be segmented into fragments such that the largest
+                                -- will fit within max segment size specified. Target supplies (in
+                                -- bytes) the smallest acceptable value of Max-segment-size to
+                                -- retrieve the record.
+                          },
+
+
+extServices  [1011] CHOICE{
+                req        [1] IMPLICIT INTEGER{   -- bad request
+                            nameInUse    (1),  -- package name already in use
+                            noSuchName  (2),  -- no such package, on modify/delete
+                            quota        (3),  -- quota exceeded
+                            type        (4)},  -- extended service type not supported
+                permission  [2] IMPLICIT INTEGER{ -- permission denied on ES, because: 
+                            id         (1),    --   id not authorized, or
+                            modifyDelete  (2)},    -- cannot modify or delete
+                immediate  [3] IMPLICIT INTEGER{ -- immediate execution:
+                            failed      (1),    -- failed, 
+                            service      (2),    -- not supported for this service, or
+                            parameters    (3)    -- for these parameters.
+                                }},
+
+
+accessCtrl    [1012] CHOICE{
+                noUser    [1] IMPLICIT NULL,    -- no user to display challenge to
+                refused    [2] IMPLICIT NULL,    -- access control information refused by user
+                simple    [3] IMPLICIT NULL,    -- only simple form supported (target used
+                                          -- externally defined)
+                oid      [4] IMPLICIT SEQUENCE OF OBJECT IDENTIFIER,
+                                          -- oid not supported (origin supplies alternative
+                                          -- suggested oids)
+                alternative  [5] IMPLICIT SEQUENCE OF OBJECT IDENTIFIER,
+                                          -- origin insists that target use an alternative
+                                          -- challenge for this data (e.g. stronger                                     
+   
+                                          -- authentication or stronger Access control). The                            
+              -- origin supplies suggested alternative oids.
+                pwdInv    [6] IMPLICIT NULL,    -- password invalid
+                pwdExp    [7] IMPLICIT NULL      -- password expired
+                    },
+
+
+recordSyntax  [1013] IMPLICIT SEQUENCE{ -- record cannot be transferred in requested syntax
+              unsupportedSyntax    [1] IMPLICIT OBJECT IDENTIFIER, 
+              suggestedAlternatives  [2] IMPLICIT SEQUENCE OF OBJECT IDENTIFIER OPTIONAL}
+}
+
+END
+
+
+
+
+
+RecordSyntax-explain 
+{Z39-50-recordSyntax explain (100)} DEFINITIONS ::=
+
+BEGIN 
+IMPORTS AttributeSetId, Term, OtherInformation, DatabaseName, ElementSetName, IntUnit, Unit,
+ StringOrNumeric, Specification, InternationalString, AttributeList, AttributeElement FROM Z39-50-APDU-1995;
+
+Explain-Record ::= CHOICE{
+  -- Each of these may be used as search term  when Use attribute is 'explain-category'.
+  targetInfo         [0]    IMPLICIT TargetInfo,
+  databaseInfo      [1]    IMPLICIT DatabaseInfo,
+  schemaInfo        [2]    IMPLICIT SchemaInfo,
+  tagSetInfo         [3]    IMPLICIT TagSetInfo,
+  recordSyntaxInfo    [4]    IMPLICIT RecordSyntaxInfo,
+  attributeSetInfo    [5]    IMPLICIT AttributeSetInfo,
+  termListInfo      [6]    IMPLICIT TermListInfo,
+  extendedServicesInfo  [7]    IMPLICIT ExtendedServicesInfo,
+  attributeDetails      [8]    IMPLICIT AttributeDetails,
+  termListDetails    [9]    IMPLICIT TermListDetails,
+  elementSetDetails    [10]  IMPLICIT ElementSetDetails,
+  retrievalRecordDetails  [11]   IMPLICIT RetrievalRecordDetails,
+  sortDetails             [12]   IMPLICIT SortDetails,
+  processing           [13]  IMPLICIT ProcessingInformation,
+  variants          [14]  IMPLICIT VariantSetInfo,
+  units          [15]    IMPLICIT UnitInfo,
+  categoryList            [100]  IMPLICIT CategoryList}
+
+-- Element set name 'B' (brief)  retrieves:
+--  -  'commonInfo' (except for otherInfo within commonInfo)
+--  -  key elements
+--  -  other elements designated as 'non-key brief elements'
+-- Esn 'description' retrieves brief elements as well as 'description', and specific additional descriptive
+-- elements if designated.  
+-- Element set name 'F' (full) retrieves all of the above, as well as those designated as "non-brief elements". Some
+-- elements designated as OPTIONAL may be mandatory in full records, and are so identified. (Note that all elements
+-- that are not part of the brief element set must be designated as OPTIONAL in the ASN.1, otherwise it would be
+-- illegal to omit them.)
+-- Other esns are defined (below) as needed.
+
+-- - - - - - - - - - - - -   Info Records
+  -- Info records are mainly for software consumption
+  -- They describe individual entities within the target system:
+  --   The target itself
+  --   Individual databases
+  --   Schemas
+  --   Tag sets
+  --   Record syntaxes
+  --   Attribute sets
+  --   Term lists
+  --   Extended services
+ --     The information about each Schema, Tag Set, Record Syntax and Attribute Set should
+  -- match the universal definitions of these items. The only exception is that a target may omit any
+  -- items it doesn't support, for example the description of the bib-1 attribute set may omit attributes
+  -- that the target does not support under any circumstances.
+  --      Databases that may be searched together can be listed in the dbCominations element of the TargetInfo record.  
+TargetInfo ::= SEQUENCE {
+  commonInfo      [0]    IMPLICIT CommonInfo OPTIONAL,
+    -- Key elements follow:
+  name          [1]    IMPLICIT InternationalString,
+    -- Non-key brief elements follow:
+  recent-news      [2]    IMPLICIT HumanString OPTIONAL,
+  icon          [3]    IMPLICIT IconObject OPTIONAL,
+  namedResultSets    [4]    IMPLICIT BOOLEAN,
+  multipleDBsearch    [5]    IMPLICIT BOOLEAN,
+  maxResultSets      [6]    IMPLICIT INTEGER OPTIONAL,
+  maxResultSize      [7]    IMPLICIT INTEGER OPTIONAL,
+  maxTerms        [8]    IMPLICIT INTEGER OPTIONAL,
+  timeoutInterval      [9]    IMPLICIT IntUnit OPTIONAL,
+  welcomeMessage    [10]  IMPLICIT HumanString OPTIONAL,
+    -- non-brief elements follow:
+  -- 'description' esn retrieves the following two (as well as brief):
+  contactInfo      [11]  IMPLICIT ContactInfo OPTIONAL,
+  description      [12]  IMPLICIT HumanString OPTIONAL,
+  nicknames        [13]  IMPLICIT SEQUENCE OF InternationalString OPTIONAL,
+  usage-restrictions    [14]  IMPLICIT HumanString OPTIONAL,
+  paymentAddr      [15]  IMPLICIT HumanString OPTIONAL,
+  hours          [16]  IMPLICIT HumanString OPTIONAL,
+  dbCombinations    [17]  IMPLICIT SEQUENCE OF DatabaseList OPTIONAL,
+  addresses        [18]  IMPLICIT SEQUENCE OF NetworkAddress OPTIONAL,
+  languages        [101]  IMPLICIT SEQUENCE OF InternationalString OPTIONAL,
+                  -- Languages supported for message strings.  Each is a three-character
+                  -- language code from Z39.53-1994.
+-- characterSets      [102]  this tag reserved for "character sets supported for name and message strings".
+  -- commonAccessInfo elements list objects the target supports. All objects listed in
+  -- AccessInfo for any individual database should also be listed here.
+  commonAccessInfo  [19]  IMPLICIT AccessInfo OPTIONAL}
+
+
+DatabaseInfo ::= SEQUENCE {
+      -- A target may provide "virtual databases" that are combinations of individual database. These
+      -- databases are indicated by the presence of subDbs in the combination database's DatabaseDescription.
+  commonInfo        [0]    IMPLICIT CommonInfo OPTIONAL,
+    -- Key elements follow:
+  name            [1]    IMPLICIT DatabaseName,
+    -- Non-key brief elements follow:
+  explainDatabase      [2]             IMPLICIT NULL OPTIONAL,
+                       -- If present, this database is the Explain database, or an Explain database
+                    -- for a different server, possibly on a different host. The means by which
+                    -- that server may be accessed is not addressed by this standard. One
+                    -- suggested possibility is an implementor agreement whereby the
+                    -- database name is a url which may be used to connect to the server.
+  nicknames          [3]    IMPLICIT SEQUENCE OF DatabaseName OPTIONAL,
+  icon            [4]    IMPLICIT IconObject OPTIONAL,
+  user-fee          [5]    IMPLICIT BOOLEAN,
+  available          [6]    IMPLICIT BOOLEAN,
+  titleString          [7]    IMPLICIT HumanString OPTIONAL,
+    -- Non-brief elements follow:
+  keywords          [8]    IMPLICIT SEQUENCE OF HumanString OPTIONAL,
+  description        [9]    IMPLICIT HumanString OPTIONAL,
+  associatedDbs        [10]  IMPLICIT DatabaseList OPTIONAL,
+                    -- databases that may be searched in combination with this one 
+
+  subDbs          [11]  IMPLICIT DatabaseList OPTIONAL,
+                        -- When present, this database is a composite representing the combined
+                     -- databases 'subDbs'. The individual subDbs are also available.
+  disclaimers        [12]  IMPLICIT HumanString OPTIONAL,
+  news            [13]  IMPLICIT HumanString OPTIONAL,
+  recordCount           [14]    CHOICE {
+                                   actualNumber  [0] IMPLICIT INTEGER,
+                                    approxNumber  [1] IMPLICIT INTEGER} OPTIONAL,
+  defaultOrder        [15]  IMPLICIT HumanString OPTIONAL,
+  avRecordSize        [16]  IMPLICIT INTEGER OPTIONAL,
+  maxRecordSize      [17]  IMPLICIT INTEGER OPTIONAL,
+  hours            [18]  IMPLICIT HumanString OPTIONAL,
+  bestTime          [19]  IMPLICIT HumanString OPTIONAL,
+  lastUpdate          [20]  IMPLICIT GeneralizedTime OPTIONAL,
+  updateInterval        [21]  IMPLICIT IntUnit OPTIONAL,
+  coverage          [22]  IMPLICIT HumanString OPTIONAL,
+  proprietary        [23]  IMPLICIT BOOLEAN OPTIONAL, -- mandatory in full record
+  copyrightText        [24]  IMPLICIT HumanString OPTIONAL,
+  copyrightNotice      [25]  IMPLICIT HumanString OPTIONAL,
+  producerContactInfo    [26]  IMPLICIT ContactInfo OPTIONAL,
+  supplierContactInfo      [27]  IMPLICIT ContactInfo OPTIONAL,
+  submissionContactInfo    [28]  IMPLICIT ContactInfo OPTIONAL,
+    -- accessInfo lists items connected with the database. All listed items should be in the target's AccessInfo.
+  accessInfo                [29]  IMPLICIT AccessInfo OPTIONAL}
+
+
+SchemaInfo ::= SEQUENCE {
+  commonInfo    [0]  IMPLICIT CommonInfo OPTIONAL,
+    -- Key elements follow:
+  schema      [1]  IMPLICIT OBJECT IDENTIFIER,
+    -- Non-key brief elements follow:
+  name        [2]  IMPLICIT InternationalString,
+    -- Non-brief elements follow:
+  description    [3]  IMPLICIT HumanString OPTIONAL,
+  tagTypeMapping  [4]  IMPLICIT SEQUENCE OF SEQUENCE {
+              tagType    [0] IMPLICIT INTEGER,
+              tagSet       [1] IMPLICIT OBJECT IDENTIFIER OPTIONAL,
+                -- If tagSet is omitted, then this tagType is for a tagSet locally defined
+                -- within the schema that cannot be referenced by another schema.
+              defaultTagType  [2] IMPLICIT NULL OPTIONAL
+                        } OPTIONAL,
+  recordStructure  [5]  IMPLICIT SEQUENCE OF ElementInfo OPTIONAL}
+
+
+  --  ElementInfo referenced in SchemaInfo and RecordSyntaxInfo
+    ElementInfo ::= SEQUENCE {
+      elementName  [1] IMPLICIT InternationalString,
+      elementTagPath  [2] IMPLICIT Path,
+      dataType      [3] ElementDataType OPTIONAL, -- If omitted, not specified. 
+       required         [4] IMPLICIT BOOLEAN,
+      repeatable     [5] IMPLICIT BOOLEAN,
+       description    [6] IMPLICIT HumanString OPTIONAL}
+
+
+  -- Path is referenced by ElementInfo as well as PerElementDetails
+             Path ::= SEQUENCE OF SEQUENCE{
+              tagType  [1] IMPLICIT INTEGER,
+              tagValue     [2] StringOrNumeric}
+      ElementDataType ::= CHOICE{
+            primitive  [0] IMPLICIT PrimitiveDataType,
+           structured  [1] IMPLICIT SEQUENCE OF ElementInfo}
+      PrimitiveDataType ::= INTEGER{
+            octetString        (0),
+            numeric           (1),
+            date            (2),
+            external        (3),
+            string          (4),
+            trueOrFalse       (5),
+            oid         (6),
+            intUnit        (7),
+        empty        (8),
+            noneOfTheAbove  (100) -- see 'description'
+            }
+
+
+TagSetInfo ::= SEQUENCE {
+  commonInfo  [0]  IMPLICIT CommonInfo OPTIONAL,
+    -- Key elements follow:
+  tagSet      [1]  IMPLICIT OBJECT IDENTIFIER,
+    -- non-key brief elements follow:
+  name      [2]  IMPLICIT InternationalString,
+    -- non-brief elements follow:
+  description  [3]  IMPLICIT HumanString OPTIONAL,
+  elements    [4]  IMPLICIT SEQUENCE OF SEQUENCE {
+              elementname  [1]  IMPLICIT InternationalString,
+               nicknames    [2]  IMPLICIT SEQUENCE OF InternationalString OPTIONAL,
+              elementTag     [3]  StringOrNumeric, 
+              description    [4]  IMPLICIT HumanString OPTIONAL, 
+            dataType       [5]  PrimitiveDataType OPTIONAL,
+              -- If the data type is expected to be structured, that is described in the schema info,
+              -- and datatype is omitted here.
+             otherTagInfo       OtherInformation OPTIONAL} OPTIONAL}
+
+RecordSyntaxInfo ::= SEQUENCE {
+  commonInfo    [0]  IMPLICIT CommonInfo OPTIONAL,
+    -- Key elements follow:
+  recordSyntax    [1]  IMPLICIT OBJECT IDENTIFIER,
+    -- Non-key brief elements follow:
+  name        [2]  IMPLICIT InternationalString,
+    -- non-brief elements follow:
+  transferSyntaxes  [3]  IMPLICIT SEQUENCE OF OBJECT IDENTIFIER OPTIONAL,
+  description    [4]  IMPLICIT HumanString OPTIONAL,
+  asn1Module    [5]  IMPLICIT InternationalString OPTIONAL,
+  abstractStructure  [6]  IMPLICIT SEQUENCE OF ElementInfo OPTIONAL
+               -- Omitting abstractStructure only means target isn't using
+                 -- Explain to describe the structure, not that there is no structure.
+              }
+
+AttributeSetInfo ::= SEQUENCE {
+  commonInfo  [0]  IMPLICIT CommonInfo OPTIONAL,
+    -- Key elements follow:
+  attributeSet  [1]  IMPLICIT AttributeSetId,
+    -- non-key brief elements follow:
+  name      [2]  IMPLICIT InternationalString,
+    -- non-brief elements follow:
+  attributes    [3]  IMPLICIT SEQUENCE OF AttributeType OPTIONAL,
+            -- mandatory in full record
+  description   [4] IMPLICIT HumanString OPTIONAL}
+-- AttributeType referenced in AttributeSetInfo
+  AttributeType ::= SEQUENCE {
+      name             [0] IMPLICIT InternationalString OPTIONAL,
+      description      [1] IMPLICIT HumanString OPTIONAL,
+       attributeType    [2] IMPLICIT INTEGER,
+      attributeValues  [3] IMPLICIT SEQUENCE OF AttributeDescription}
+    AttributeDescription ::= SEQUENCE {
+        name                 [0] IMPLICIT InternationalString OPTIONAL,
+        description          [1] IMPLICIT HumanString OPTIONAL,
+        attributeValue       [2] StringOrNumeric,
+        equivalentAttributes  [3]  IMPLICIT SEQUENCE OF StringOrNumeric OPTIONAL
+                  -- each is an occurrence of 'attributeValue' from AttributeDescription for a
+                  -- different attribute. Equivalences listed here should be derived from the 
+                  -- attribute set definition, not from a particular server's behavior.  
+                    }
+
+
+TermListInfo ::= SEQUENCE{
+  commonInfo    [0]  IMPLICIT CommonInfo OPTIONAL,
+    -- Key elements follow:
+  databaseName  [1]  IMPLICIT DatabaseName,
+    -- Non-key brief elements follow:
+  termLists      [2] IMPLICIT SEQUENCE OF SEQUENCE{
+            name    [1] IMPLICIT InternationalString,
+            title    [2] IMPLICIT HumanString OPTIONAL,
+                                            -- Title is for users to see and can differ by language. Name, on the
+                      -- other hand is typically a short string not necessarily meant to be
+                       -- human-readable, and not variable by language.
+            searchCost   [3]   IMPLICIT INTEGER {
+                  optimized  (0),    -- The attribute (or combination) associated
+                            -- with this   list will do fast searches. 
+                      normal      (1),    -- The attribute (combination) will work as
+                            -- expected. So there's probably an index for the
+                            -- attribute (combination) or some similar
+                             -- mechanism.
+                      expensive   (2),    -- Can use the attribute (combination), but it
+                            -- might not provide satisfactory results.
+                            -- Probably there is no index, or post-
+                            -- processing of records is required.
+                      filter      (3)    -- can't search with this attribute (combination) alone.
+                         } OPTIONAL,
+              scanable  [4]  IMPLICIT BOOLEAN, -- 'true' means this list can be scanned.
+               broader    [5] IMPLICIT SEQUENCE OF InternationalString OPTIONAL,
+               narrower  [6] IMPLICIT SEQUENCE OF InternationalString OPTIONAL
+                       -- broader and narrower list alternative term lists related to this one.
+                       -- The term lists so listed should also be in this termLists structure.
+                          }
+  -- no non-brief elements
+            }
+
+
+ExtendedServicesInfo ::= SEQUENCE {
+  commonInfo          [0]  IMPLICIT CommonInfo OPTIONAL,
+    -- Key elements follow:
+  type          [1]  IMPLICIT OBJECT IDENTIFIER,
+    -- Non-key brief elements follow:
+  name                [2]  IMPLICIT InternationalString OPTIONAL,
+                -- should be supplied if privateType is 'true'
+  privateType      [3]  IMPLICIT BOOLEAN,
+  restrictionsApply    [5]  IMPLICIT BOOLEAN,  -- if 'true' see 'description'
+  feeApply              [6]  IMPLICIT BOOLEAN,  -- if 'true' see 'description'
+  available             [7]  IMPLICIT BOOLEAN,
+  retentionSupported    [8]  IMPLICIT BOOLEAN,
+  waitAction      [9]  IMPLICIT INTEGER{
+                waitSupported    (1),
+                waitAlways      (2),
+                waitNotSupported  (3),
+                depends      (4),
+                notSaying      (5)},
+  -- non-brief elements follow:
+    -- To get brief plus 'description' use esn 'description'
+  description           [10]  IMPLICIT HumanString OPTIONAL,
+      -- to get above elements and 'specificExplain' use esn 'specificExplain'
+  specificExplain    [11]  IMPLICIT EXTERNAL OPTIONAL,
+                  -- Use oid of specific ES, and select choice [3] 'explain'. Format
+                  -- to be developed in conjunction with the specific ES definition.
+    -- to get all elements except 'specificExplain', use esn 'asn'
+  esASN          [12]  IMPLICIT InternationalString OPTIONAL -- the ASN.1 for this ES
+                }
+
+-- - - - - - - - - - - - - Detail records
+ -- The detail records describe relationships among entities supported by the target. RetrievalRecordDetails describes
+ -- the way that schema elements are mapped into record elements. This mapping may be different for each
+ -- combination of database, schema, record syntax. The per-element details describe the default mapping.
+ -- Origin-request re-tagging can change that mapping. When multiple databases are listed in a databaseNames
+ -- element, the record applies equally to all of the listed databases.  This is unrelated to searching the databases
+ -- together. AttributeDetails describes how databases can be searched. Each supported attribute is listed, and the
+ -- allowable combinations can be described.
+
+
+AttributeDetails ::= SEQUENCE {
+  commonInfo        [0]  IMPLICIT CommonInfo OPTIONAL,
+    -- Key elements follow:
+  databaseName        [1]  IMPLICIT DatabaseName,
+    -- Non-brief elements follow:
+  attributesBySet        [2]  IMPLICIT SEQUENCE OF AttributeSetDetails OPTIONAL, 
+                  -- mandatory in full record
+  attributeCombinations    [3]  IMPLICIT AttributeCombinations OPTIONAL}
+
+
+
+
+-- AttributeSetDetails referenced by AttributeDetails
+  AttributeSetDetails ::= SEQUENCE {
+        attributeSet      [0] IMPLICIT AttributeSetId,
+          attributesByType  [1] IMPLICIT SEQUENCE OF AttributeTypeDetails }
+    AttributeTypeDetails ::= SEQUENCE {
+         attributeType     [0] IMPLICIT INTEGER,
+          defaultIfOmitted    [1] IMPLICIT OmittedAttributeInterpretation OPTIONAL,
+          attributeValues    [2] IMPLICIT SEQUENCE OF AttributeValue OPTIONAL }
+                          -- If no attributeValues are supplied, all values of this type are fully
+                    -- supported, and the descriptions in AttributeSetInfo are adequate.
+
+    OmittedAttributeInterpretation ::= SEQUENCE {
+        defaultValue           [0] StringOrNumeric OPTIONAL,
+                                -- A default value is listed if that's how the server works
+        defaultDescription  [1] IMPLICIT HumanString OPTIONAL }
+                          -- The human-readable description should generally be provided.
+                    -- It is legal for both default elements to be missing, which
+                    -- means that the target will allow the attribute type to be
+                    -- omitted, but isn't saying what it will do.
+
+    AttributeValue ::= SEQUENCE {
+        value              [0]  StringOrNumeric,
+        description        [1]  IMPLICIT HumanString OPTIONAL,
+        subAttributes     [2]  IMPLICIT SEQUENCE OF StringOrNumeric OPTIONAL,
+        superAttributes    [3]  IMPLICIT SEQUENCE OF StringOrNumeric OPTIONAL,
+        partialSupport    [4]  IMPLICIT NULL OPTIONAL }
+        -- partialSupport indicates that an attributeValue is accepted, but may not be processed in the
+        -- "expected" way. One important reason for this is composite databases: in this case partialSupport
+        -- may indicate that only some of the subDbs support the attribute, and others ignore it.
+
+
+
+TermListDetails ::= SEQUENCE{  -- one for each termList in TermListInfo
+  commonInfo    [0]  IMPLICIT CommonInfo OPTIONAL,
+    -- Key elements follow:
+  termListName    [1]  IMPLICIT InternationalString,
+    -- Non-key elements (all non-brief) follow:
+  description    [2]  IMPLICIT HumanString OPTIONAL,
+  attributes      [3]  IMPLICIT AttributeCombinations OPTIONAL,
+                          -- Pattern for attributes that hit this list. Mandatory in full record
+  scanInfo      [4]  IMPLICIT SEQUENCE {
+                maxStepSize         [0] IMPLICIT INTEGER OPTIONAL,
+                collatingSequence  [1] IMPLICIT HumanString OPTIONAL,
+                increasing            [2] IMPLICIT BOOLEAN OPTIONAL} OPTIONAL,
+            -- Occurs only if list is scanable. If list is scanable and if scanInfo is omitted, 
+            -- target doesn't consider these important.
+  estNumberTerms  [5]  IMPLICIT INTEGER OPTIONAL,
+  sampleTerms    [6]  IMPLICIT SEQUENCE OF Term OPTIONAL}
+
+
+
+ElementSetDetails ::= SEQUENCE {
+  -- ElementSetDetails describes the way that database records are mapped to record elements. This
+  -- mapping may be different for each combination of database name and element set. The database record
+   -- description is a schema, which may be private to the target. The schema's abstract record structure
+  -- and tag sets provide the vocabulary for discussing record content; their presence in the Explain
+  -- database does not imply support for complex retrieval specification.
+  commonInfo      [0]  IMPLICIT CommonInfo OPTIONAL,
+    -- Key elements follow:
+  databaseName      [1]  IMPLICIT DatabaseName,
+  elementSetName    [2]  IMPLICIT ElementSetName,
+  recordSyntax      [3]  IMPLICIT OBJECT IDENTIFIER,
+    -- Non-key Brief elements follow:
+  schema        [4]  IMPLICIT OBJECT IDENTIFIER,
+    -- Non-brief elements follow:
+  description      [5]  IMPLICIT HumanString OPTIONAL,
+  detailsPerElement    [6]  IMPLICIT SEQUENCE OF PerElementDetails OPTIONAL -- mandatory in full record
+              }
+
+
+RetrievalRecordDetails ::= SEQUENCE {
+  commonInfo      [0]  IMPLICIT CommonInfo OPTIONAL,
+    -- Key elements follow:
+  databaseName      [1]  IMPLICIT DatabaseName,
+  schema        [2]  IMPLICIT OBJECT IDENTIFIER,
+  recordSyntax      [3]  IMPLICIT OBJECT IDENTIFIER,
+    -- Non-brief elements follow:
+  description      [4]  IMPLICIT HumanString OPTIONAL,
+  detailsPerElement    [5]  IMPLICIT SEQUENCE OF PerElementDetails OPTIONAL
+                -- mandatory in full record
+            }
+
+-- PerElementDetails is referenced in RetrievalRecordDetails and ElementSetDetails.
+  PerElementDetails ::= SEQUENCE {
+      name      [0]    IMPLICIT InternationalString OPTIONAL,
+                   -- If the name is omitted, the record syntax's name for this element
+                  -- is appropriate.
+      recordTag    [1]    IMPLICIT RecordTag OPTIONAL,
+                   -- The record tag may be omitted if tags are inappropriate for the record
+                  -- syntax, or if the origin can be expected to know it for some other reason.
+      schemaTags    [2]    IMPLICIT SEQUENCE OF Path OPTIONAL,
+                      -- The information from the listed schema elements is combined
+                  -- in some way to produce the data sent in the listed record tag. The
+                  -- 'contents' element below may describe the logic used.
+      maxSize    [3]    IMPLICIT INTEGER OPTIONAL,
+      minSize    [4]    IMPLICIT INTEGER OPTIONAL,
+      avgSize      [5]    IMPLICIT INTEGER OPTIONAL,
+      fixedSize    [6]    IMPLICIT INTEGER OPTIONAL,
+      repeatable    [8]    IMPLICIT BOOLEAN,
+      required    [9]    IMPLICIT BOOLEAN, 
+                  -- 'required' really means that target will always supply the element.
+      description    [12]  IMPLICIT HumanString OPTIONAL,
+      contents    [13]  IMPLICIT HumanString OPTIONAL,
+      billingInfo    [14]  IMPLICIT HumanString OPTIONAL,
+      restrictions    [15]  IMPLICIT HumanString OPTIONAL,
+      alternateNames  [16]  IMPLICIT SEQUENCE OF InternationalString OPTIONAL,
+      genericNames  [17]  IMPLICIT SEQUENCE OF InternationalString OPTIONAL,
+      searchAccess  [18]  IMPLICIT AttributeCombinations OPTIONAL }
+      -- RecordTag referenced in PerElementDetails above
+        RecordTag ::= SEQUENCE {
+              qualifier  [0] StringOrNumeric OPTIONAL,
+                    -- E.g. tag set for GRS-1
+              tagValue  [1] StringOrNumeric}
+
+SortDetails ::= SEQUENCE {
+  commonInfo    [0]  IMPLICIT CommonInfo OPTIONAL,
+  -- Key elements follow:
+  databaseName    [1]  IMPLICIT DatabaseName,
+    -- No non-key brief elements
+    -- Non-brief elements follow:
+  sortKeys      [2]  IMPLICIT SEQUENCE OF SortKeyDetails OPTIONAL
+              -- mandatory in full record
+          }
+  SortKeyDetails ::= SEQUENCE {
+      description        [0]  IMPLICIT HumanString OPTIONAL,
+      elementSpecifications  [1]  IMPLICIT SEQUENCE OF Specification OPTIONAL,
+                      -- each specification is a way of specifying this same sort key
+      attributeSpecifications  [2]  IMPLICIT AttributeCombinations OPTIONAL,
+                      -- each combination is a way of specifying this same sort key
+      sortType                   [3]  CHOICE {
+                    character    [0]  IMPLICIT NULL,
+                    numeric    [1]  IMPLICIT NULL,
+                    structured    [2]  IMPLICIT HumanString} OPTIONAL,
+      caseSensitivity      [4]  IMPLICIT INTEGER {
+                      always    (0),  -- always case-sensitive
+                    never    (1),            -- never case-sensitive
+                    default-yes  (2),               -- case-sensitivity is as specified on request, and if not
+                            -- specified, case-sensitive.
+                    default-no  (3)} -- case-sensitivity is as specified on request, and if not
+                            -- specified, not case-sensitive.
+                          OPTIONAL}
+
+ProcessingInformation ::= SEQUENCE{
+  commonInfo      [0]  IMPLICIT CommonInfo OPTIONAL,
+    -- Key elements follow:
+  databaseName      [1]  IMPLICIT DatabaseName,
+  processingContext    [2]  IMPLICIT INTEGER {
+                  access        (0),   -- e.g. choosing databases
+                  search        (1),   -- e.g. "search strategies" or search forms 
+                  retrieval      (2),   -- e.g. recommended element combinations 
+                  record-presentation  (3),    -- display of retrieved records
+                  record-handling    (4)    -- handling (e.g. saving) of retrieved records
+        },
+  name          [3]  IMPLICIT InternationalString,
+  oid          [4]  IMPLICIT OBJECT IDENTIFIER,
+    -- No non-key brief elements
+    -- Non-brief elements follow:
+  description      [5]  IMPLICIT HumanString OPTIONAL,
+                -- use element set name 'description' to retrieve all except instructions.
+  instructions      [6]  IMPLICIT EXTERNAL OPTIONAL -- mandatory in full record
+              }
+
+
+VariantSetInfo ::= SEQUENCE {
+    -- A record in this category describes a variant set definition, i.e., classes, types, and values, for a specific
+    -- variant set definition supported by the target. Support by the target of a particular variant set definition
+    -- does not imply that the definition is supported for any specific database or element. 
+  commonInfo    [0] IMPLICIT CommonInfo OPTIONAL,
+  -- Key elements follow:
+  variantSet    [1] IMPLICIT OBJECT IDENTIFIER,
+  -- Non-key brief elements follow:
+  name      [2] IMPLICIT InternationalString,
+  -- Non-brief elements follow:
+  variants    [3] IMPLICIT SEQUENCE OF VariantClass OPTIONAL
+                   -- mandatory in full record
+           }
+
+  -- Subsidiary structures for VariantSetInfo
+    VariantClass ::= SEQUENCE {
+          name        [0] IMPLICIT InternationalString OPTIONAL,
+          description    [1] IMPLICIT HumanString OPTIONAL,
+          variantClass    [2] IMPLICIT INTEGER,
+          variantTypes  [3] IMPLICIT SEQUENCE OF VariantType}
+    VariantType ::= SEQUENCE {
+          name            [0] IMPLICIT InternationalString OPTIONAL,
+          description     [1] IMPLICIT HumanString OPTIONAL,
+          variantType    [2] IMPLICIT INTEGER,
+          variantValue  [3] IMPLICIT VariantValue OPTIONAL}
+    VariantValue ::= SEQUENCE {
+          dataType     [0] PrimitiveDataType,
+          values        [1] ValueSet OPTIONAL }
+    ValueSet ::= CHOICE {
+          range       [0] IMPLICIT ValueRange,
+          enumerated  [1] IMPLICIT SEQUENCE OF ValueDescription }
+    ValueRange ::= SEQUENCE {
+            -- At last one the following must be supplied, both may be supplied.
+          lower      [0] ValueDescription OPTIONAL,
+          upper     [1] ValueDescription OPTIONAL }
+    ValueDescription ::= CHOICE{
+      integer             INTEGER,
+          string              InternationalString,
+          octets              OCTET STRING,
+          oid                 OBJECT IDENTIFIER,
+          unit               [1]  IMPLICIT Unit,
+          valueAndUnit   [2]  IMPLICIT IntUnit 
+            -- oid and unit can't be used in a ValueRange
+            }
+
+
+
+UnitInfo ::= SEQUENCE {
+  commonInfo  [0] IMPLICIT CommonInfo OPTIONAL,
+  -- Key elements follow:
+  unitSystem   [1] IMPLICIT InternationalString,
+   -- No non-key brief elements
+   -- Non-brief elements follow:
+  description   [2] IMPLICIT HumanString OPTIONAL,
+  units      [3] IMPLICIT SEQUENCE OF UnitType OPTIONAL
+                         -- mandatory in full record
+           }
+
+  -- Subsidiary structures for UnitInfo
+    UnitType ::= SEQUENCE {
+      name    [0] IMPLICIT InternationalString OPTIONAL,
+      description  [1] IMPLICIT HumanString OPTIONAL,
+      unitType  [2] StringOrNumeric,
+      units     [3] IMPLICIT SEQUENCE OF Units}
+
+    Units ::= SEQUENCE {
+      name     [0] IMPLICIT InternationalString OPTIONAL,
+      description  [1] IMPLICIT HumanString OPTIONAL,
+      unit      [2] StringOrNumeric}
+
+CategoryList ::= SEQUENCE {
+  commonInfo      [0] IMPLICIT CommonInfo OPTIONAL,
+    -- Only one record expected per Explain database. All elements appear in brief presentation.
+  categories      [1] IMPLICIT SEQUENCE OF CategoryInfo }
+    CategoryInfo ::= SEQUENCE {
+           category          [1] IMPLICIT InternationalString,
+            originalCategory    [2] IMPLICIT InternationalString OPTIONAL,
+          description         [3] IMPLICIT HumanString OPTIONAL,
+         asn1Module      [4] IMPLICIT InternationalString OPTIONAL}
+
+
+-- - - - - - - - - - - - - - Subsidiary definitions
+
+CommonInfo ::= SEQUENCE {
+  dateAdded         [0] IMPLICIT GeneralizedTime OPTIONAL,
+  dateChanged       [1] IMPLICIT GeneralizedTime OPTIONAL,
+  expiry                [2] IMPLICIT GeneralizedTime OPTIONAL,
+  humanString-Language  [3] IMPLICIT LanguageCode OPTIONAL,
+  -- following not to occur for brief:
+  otherInfo          OtherInformation OPTIONAL}
+
+
+HumanString ::= SEQUENCE OF SEQUENCE {
+          language  [0] IMPLICIT LanguageCode OPTIONAL,
+        text        [1] IMPLICIT InternationalString}
+
+IconObject ::= SEQUENCE OF SEQUENCE{
+      -- Note that the "SEQUENCE OF" is to allow alternative representations of the same Icon; it is not
+      -- intended to allow multiple icons.
+  bodyType [1] CHOICE{
+           ianaType  [1] IMPLICIT InternationalString,
+          z3950type  [2] IMPLICIT InternationalString,
+           otherType  [3] IMPLICIT InternationalString},
+  content  [2] IMPLICIT OCTET STRING}
+
+
+LanguageCode ::= InternationalString  -- from ANSI/NISO Z39.53-1994 
+
+ContactInfo ::= SEQUENCE {
+  name           [0] IMPLICIT InternationalString OPTIONAL,
+  description  [1] IMPLICIT HumanString OPTIONAL,
+  address        [2] IMPLICIT HumanString OPTIONAL,
+  email         [3] IMPLICIT InternationalString OPTIONAL,
+  phone         [4] IMPLICIT InternationalString OPTIONAL}
+
+NetworkAddress ::= CHOICE {
+  internetAddress      [0] IMPLICIT SEQUENCE {
+                  hostAddress    [0]  IMPLICIT InternationalString,
+                  port       [1]  IMPLICIT INTEGER},
+  osiPresentationAddress    [1] IMPLICIT SEQUENCE { 
+                    pSel         [0] IMPLICIT InternationalString,  
+                    sSel         [1] IMPLICIT InternationalString OPTIONAL,  
+                    tSel        [2] IMPLICIT InternationalString OPTIONAL,  
+                    nSap      [3] IMPLICIT InternationalString},
+  other            [2] IMPLICIT SEQUENCE {  
+                      type        [0] IMPLICIT InternationalString,
+                address    [1] IMPLICIT InternationalString}}
+
+AccessInfo ::= SEQUENCE {
+    -- AccessInfo contains the fundamental information about what facilities are required to use this target
+    -- or server. For example, if an origin can handle none of the record syntaxes a database can provide, 
+    -- it might choose not to access the database.
+  queryTypesSupported  [0]    IMPLICIT SEQUENCE OF QueryTypeDetails OPTIONAL,
+  diagnosticsSets        [1]    IMPLICIT SEQUENCE OF OBJECT IDENTIFIER OPTIONAL,
+  attributeSetIds          [2]    IMPLICIT SEQUENCE OF AttributeSetId OPTIONAL,
+  schemas                [3]    IMPLICIT SEQUENCE OF OBJECT IDENTIFIER OPTIONAL,
+  recordSyntaxes         [4]    IMPLICIT SEQUENCE OF OBJECT IDENTIFIER OPTIONAL,
+  resourceChallenges    [5]    IMPLICIT SEQUENCE OF OBJECT IDENTIFIER OPTIONAL,
+  restrictedAccess       [6]    IMPLICIT AccessRestrictions OPTIONAL,
+  costInfo                 [8]    IMPLICIT Costs OPTIONAL,
+  variantSets       [9]    IMPLICIT SEQUENCE OF OBJECT IDENTIFIER OPTIONAL,
+  elementSetNames    [10]  IMPLICIT SEQUENCE OF ElementSetName OPTIONAL,
+  unitSystems      [11]  IMPLICIT SEQUENCE OF InternationalString}
+
+-- begin auxiliary definitions for AccessInfo
+-- Begin Query Details
+QueryTypeDetails ::= CHOICE {
+  private       [0]    IMPLICIT PrivateCapabilities,
+  rpn            [1]    IMPLICIT RpnCapabilities,
+  iso8777          [2]    IMPLICIT Iso8777Capabilities,
+  z39-58      [100]  IMPLICIT HumanString,
+  erpn        [101]  IMPLICIT RpnCapabilities,
+  rankedList      [102]  IMPLICIT HumanString}
+
+PrivateCapabilities ::= SEQUENCE {
+  operators       [0]  IMPLICIT SEQUENCE OF SEQUENCE {
+              operator  [0] IMPLICIT InternationalString,
+              description  [1] IMPLICIT HumanString OPTIONAL } OPTIONAL,
+  searchKeys    [1]  IMPLICIT SEQUENCE OF SearchKey OPTIONAL,  -- field names that can be searched
+  description    [2]  IMPLICIT SEQUENCE OF HumanString OPTIONAL }
+
+RpnCapabilities ::= SEQUENCE {
+  operators                    [0] IMPLICIT SEQUENCE OF INTEGER OPTIONAL,
+                                        -- Omitted means all operators are supported.
+  resultSetAsOperandSupported  [1] IMPLICIT BOOLEAN,
+  restrictionOperandSupported    [2] IMPLICIT BOOLEAN,
+  proximity                    [3] IMPLICIT ProximitySupport OPTIONAL}
+
+Iso8777Capabilities ::= SEQUENCE {
+  searchKeys  [0]  IMPLICIT SEQUENCE OF SearchKey,  -- field names that may be searched
+  restrictions   [1]  IMPLICIT HumanString OPTIONAL 
+            -- Omitted means supported, not specifying units.
+              }
+
+ProximitySupport ::= SEQUENCE {
+  anySupport      [0]   IMPLICIT BOOLEAN,
+          -- 'false' means no proximity support, in which case unitsSupported not supplied.
+  unitsSupported  [1]   IMPLICIT SEQUENCE OF CHOICE{  
+             known  [1] IMPLICIT INTEGER, -- values from KnownProximityUnit
+          private  [2] IMPLICIT SEQUENCE{  
+                      unit    [0] IMPLICIT INTEGER,  
+                description  [1] HumanString OPTIONAL}} OPTIONAL}
+
+SearchKey ::= SEQUENCE {
+  searchKey     [0]  IMPLICIT InternationalString,
+  description     [1]  IMPLICIT HumanString OPTIONAL }
+-- End Query details
+AccessRestrictions ::= SEQUENCE OF SEQUENCE {
+  accessType      [0] INTEGER {
+                  any         (0),
+                  search         (1),
+                  present         (2),
+                  specific-elements  (3),
+                  extended-services  (4),
+            by-database      (5)},
+  accessText         [1]  IMPLICIT HumanString OPTIONAL,
+  accessChallenges  [2]  IMPLICIT SEQUENCE OF OBJECT IDENTIFIER OPTIONAL}
+
+Costs ::= SEQUENCE {
+  connectCharge    [0] IMPLICIT Charge OPTIONAL,    -- Per-connection charge
+  connectTime    [1] IMPLICIT Charge OPTIONAL,    -- Time-based charge
+  displayCharge     [2] IMPLICIT Charge OPTIONAL,    -- Per-record charge
+  searchCharge     [3] IMPLICIT Charge OPTIONAL,    -- Per-search charge
+  subscriptCharge  [4]  IMPLICIT Charge OPTIONAL,  -- Subscription charges
+  otherCharges    [5] IMPLICIT SEQUENCE OF SEQUENCE{   -- Other charges
+            forWhat  [1]  IMPLICIT HumanString,
+            charge    [2]  IMPLICIT Charge} OPTIONAL} 
+    Charge ::= SEQUENCE{
+        cost          [1] IMPLICIT IntUnit,
+        perWhat  [2] IMPLICIT Unit OPTIONAL,
+                      -- e.g. "second," "minute," "line," "record"...
+        text          [3] IMPLICIT HumanString OPTIONAL} 
+-- End Auxiliary definitions for AccessInfo
+
+DatabaseList ::= SEQUENCE OF DatabaseName
+
+AttributeCombinations ::= SEQUENCE {
+  defaultAttributeSet  [0] IMPLICIT AttributeSetId,
+                 -- Default for the combinations. Also probably a good choice for the default
+              -- in searches, but that isn't required.
+  legalCombinations  [1] IMPLICIT SEQUENCE OF AttributeCombination }
+
+
+AttributeCombination ::= SEQUENCE OF AttributeOccurrence
+            -- An AttributeCombination is a pattern for legal combination of attributes
+
+
+AttributeOccurrence ::= SEQUENCE {   
+      -- An AttributeOccurrence lists the legal values for a specific attribute type in a combination.
+       attributeSet       [0]  IMPLICIT AttributeSetId OPTIONAL,
+       attributeType      [1]  IMPLICIT INTEGER,
+       mustBeSupplied  [2]  IMPLICIT NULL OPTIONAL,
+       attributeValues    CHOICE {
+                      any-or-none  [3] IMPLICIT NULL, -- All supported values are OK 
+                      specific    [4] IMPLICIT SEQUENCE OF StringOrNumeric}}
+                                                  -- Only these values allowed
+END
+
+
+
+
+
+
+
+
+
+RecordSyntax-SUTRS
+{Z39-50-recordSyntax SUTRS (101)} DEFINITIONS ::=
+BEGIN 
+IMPORTS InternationalString  FROM Z39-50-APDU-1995;
+        SutrsRecord ::=  InternationalString
+-- Line terminator is ASCII LF (X'0A').
+-- Recommended maximum line length is 72 characters.
+END
+
+
+
+
+
+RecordSyntax-opac
+{Z39-50-recordSyntax opac (102)} DEFINITIONS ::=
+BEGIN 
+IMPORTS InternationalString  FROM Z39-50-APDU-1995;
+OPACRecord ::= SEQUENCE {
+  bibliographicRecord   [1]   IMPLICIT EXTERNAL OPTIONAL,
+  holdingsData     [2]   IMPLICIT SEQUENCE OF HoldingsRecord OPTIONAL}
+HoldingsRecord ::=  CHOICE {
+  marcHoldingsRecord  [1]   IMPLICIT EXTERNAL,
+  holdingsAndCirc  [2]  IMPLICIT HoldingsAndCircData}
+HoldingsAndCircData ::=  SEQUENCE {
+-- the following elements are required to display holdings in conformance with NISO standards.
+  typeOfRecord    [1]   IMPLICIT InternationalString OPTIONAL, -- LDR 06
+  encodingLevel    [2]   IMPLICIT InternationalString OPTIONAL, -- LDR 017
+  format      [3]   IMPLICIT InternationalString OPTIONAL, -- 007 00-01
+  receiptAcqStatus    [4]   IMPLICIT InternationalString OPTIONAL, -- 008 06
+  generalRetention    [5]   IMPLICIT InternationalString OPTIONAL, -- 008 12
+  completeness    [6]   IMPLICIT InternationalString OPTIONAL, -- 008 16
+       dateOfReport     [7]   IMPLICIT InternationalString OPTIONAL, -- 008 26-31
+  nucCode    [8]   IMPLICIT InternationalString OPTIONAL, -- 852 $a
+  localLocation    [9]   IMPLICIT InternationalString OPTIONAL, -- 852 $b
+  shelvingLocation  [10]   IMPLICIT InternationalString OPTIONAL, -- 852 $c
+  callNumber    [11]   IMPLICIT InternationalString OPTIONAL, -- 852 $h and $i
+  shelvingData     [12]   IMPLICIT InternationalString OPTIONAL, -- 852 $j thru $m
+  copyNumber    [13]   IMPLICIT InternationalString OPTIONAL, -- 852 $t
+  publicNote    [14]   IMPLICIT InternationalString OPTIONAL, -- 852 $z
+  reproductionNote  [15]   IMPLICIT InternationalString OPTIONAL, -- 843
+  termsUseRepro     [16]   IMPLICIT InternationalString OPTIONAL, -- 845
+  enumAndChron    [17]   IMPLICIT InternationalString OPTIONAL, -- all 85x, 86x
+  volumes     [18]   IMPLICIT SEQUENCE OF Volume OPTIONAL, 
+            -- repeats for each volume held
+  circulationData    [19]   IMPLICIT SEQUENCE OF CircRecord OPTIONAL 
+            -- repeats for each circulating item.
+            }
+Volume ::=  SEQUENCE {
+  enumeration    [1]   IMPLICIT InternationalString OPTIONAL,
+  chronology     [2]   IMPLICIT InternationalString OPTIONAL,
+  enumAndChron    [3]   IMPLICIT InternationalString OPTIONAL }
+CircRecord ::=  SEQUENCE {
+  availableNow    [1]   IMPLICIT BOOLEAN,
+  availablityDate    [2]   IMPLICIT InternationalString OPTIONAL,
+  availableThru      [3]   IMPLICIT InternationalString OPTIONAL,
+  restrictions     [4]   IMPLICIT InternationalString OPTIONAL,
+  itemId        [5]   IMPLICIT InternationalString OPTIONAL,
+  renewable        [6]   IMPLICIT BOOLEAN,
+  onHold        [7]   IMPLICIT BOOLEAN,
+  enumAndChron     [8]   IMPLICIT InternationalString OPTIONAL,
+  midspine    [9]   IMPLICIT InternationalString OPTIONAL,
+  temporaryLocation  [10]   IMPLICIT InternationalString OPTIONAL}
+END
+
+
+
+RecordSyntax-summary
+
+{Z39-50-recordSyntax summary (103)} DEFINITIONS ::=
+BEGIN 
+IMPORTS OtherInformation, InternationalString  FROM Z39-50-APDU-1995;
+BriefBib ::= SEQUENCE {
+  title           [1]   IMPLICIT InternationalString,
+  author            [2]   IMPLICIT InternationalString OPTIONAL,
+  callNumber         [3]   IMPLICIT InternationalString OPTIONAL,
+  recordType      [4]   IMPLICIT InternationalString OPTIONAL,
+  bibliographicLevel  [5]   IMPLICIT InternationalString OPTIONAL,
+  format        [6]   IMPLICIT SEQUENCE OF FormatSpec OPTIONAL,
+  publicationPlace    [7]   IMPLICIT InternationalString OPTIONAL,
+  publicationDate     [8]   IMPLICIT InternationalString OPTIONAL,
+  targetSystemKey   [9]   IMPLICIT InternationalString OPTIONAL,
+  satisfyingElement  [10]   IMPLICIT InternationalString OPTIONAL,
+  rank         [11]   IMPLICIT INTEGER OPTIONAL,
+  documentId     [12]   IMPLICIT InternationalString OPTIONAL,
+  abstract       [13]   IMPLICIT InternationalString OPTIONAL,
+  otherInfo        OtherInformation OPTIONAL}
+
+FormatSpec     ::=  SEQUENCE {
+  type         [1]   IMPLICIT InternationalString,
+  size      [2]   IMPLICIT INTEGER OPTIONAL,
+  bestPosn     [3]   IMPLICIT INTEGER OPTIONAL}
+END
+
+
+
+
+
+
+
+
+
+
+RecordSyntax-generic  -- For detailed semantics, see Appendix RET.
+{Z39-50-recordSyntax GRS-1 (105)} DEFINITIONS ::=
+BEGIN 
+EXPORTS Variant;
+IMPORTS IntUnit, Unit, InternationalString, StringOrNumeric, Term FROM Z39-50-APDU-1995;
+
+GenericRecord ::= SEQUENCE OF TaggedElement  
+TaggedElement ::= SEQUENCE {
+  tagType    [1] IMPLICIT INTEGER OPTIONAL,
+              -- If omitted, default should be supplied dynamically by tagSet-M; 
+              -- otherwise it should be statically specified by the schema.
+  tagValue    [2] StringOrNumeric,
+  tagOccurrence  [3] IMPLICIT INTEGER OPTIONAL,
+                             -- Occurrence within the database record, and relative to the parent. No
+              -- default; if omitted, target not telling or it is irrelevant.
+  content      [4] ElementData,
+  metaData    [5] IMPLICIT ElementMetaData OPTIONAL,
+  appliedVariant  [6] IMPLICIT Variant OPTIONAL}
+
+ElementData ::= CHOICE{
+  octets      OCTET STRING,
+  numeric    INTEGER,
+  date      GeneralizedTime,
+  ext        EXTERNAL,
+  string      InternationalString,
+  trueOrFalse    BOOLEAN,
+  oid        OBJECT IDENTIFIER,
+  intUnit          [1]  IMPLICIT IntUnit,
+   elementNotThere    [2] IMPLICIT NULL,  -- element requested but not there
+  elementEmpty      [3] IMPLICIT NULL,  -- element there, but empty
+  noDataRequested    [4] IMPLICIT NULL,  -- variant request said 'no data'
+  diagnostic        [5] IMPLICIT EXTERNAL,
+  subtree          [6] SEQUENCE OF TaggedElement -- recursive, for nested tags
+              }
+
+
+ElementMetaData ::= SEQUENCE{
+  seriesOrder        [1]   IMPLICIT Order OPTIONAL, -- only for a non-leaf node
+  usageRight        [2]   IMPLICIT Usage OPTIONAL,
+  hits            [3]    IMPLICIT SEQUENCE OF HitVector OPTIONAL,
+  displayName      [4]    IMPLICIT InternationalString OPTIONAL, 
+                    -- name for element that origin can use for display
+  supportedVariants    [5]   IMPLICIT SEQUENCE OF Variant OPTIONAL,
+  message        [6]    IMPLICIT InternationalString OPTIONAL,
+  elementDescriptor    [7]   IMPLICIT OCTET STRING OPTIONAL,
+  surrogateFor      [8]   IMPLICIT TagPath OPTIONAL,  
+                    -- the retrieved element is a surrogate for the element given by this path  
+  surrogateElement    [9]   IMPLICIT TagPath OPTIONAL,
+                    -- the element given by this path is a surrogate for the retrieved element
+    other          [99]  IMPLICIT EXTERNAL OPTIONAL}
+
+        TagPath ::= SEQUENCE  OF SEQUENCE{
+          tagType      [1]  IMPLICIT INTEGER OPTIONAL,
+            tagValue      [2]  StringOrNumeric,
+            tagOccurrence    [3]  IMPLICIT INTEGER OPTIONAL}
+
+
+
+Order ::= SEQUENCE{
+  ascending    [1] IMPLICIT BOOLEAN,
+              -- "true" means monotonically increasing (i.e. non-decreasing); 
+              -- "false" means monotonically decreasing (i.e. non-increasing).
+  order      [2] IMPLICIT INTEGER
+              -- Same as defined by 'elementOrdering' in tagSet-M, though this may be
+              -- overridden by schema.
+          }
+
+
+
+Usage ::= SEQUENCE  {
+  type        [1] IMPLICIT INTEGER{
+              redistributable    (1),   -- Element is freely redistributable.
+              restricted      (2),   -- Restriction contains statement.
+              licensePointer    (3)   -- Restriction contains license pointer.
+              },
+  restriction    [2] IMPLICIT InternationalString OPTIONAL}
+
+
+
+HitVector ::= SEQUENCE{ 
+    -- Each hit vector points to a fragment within the element, via location and/or token.
+  satisfier            Term OPTIONAL, -- sourceword, etc.
+  offsetIntoElement    [1] IMPLICIT IntUnit OPTIONAL,
+  length          [2] IMPLICIT IntUnit OPTIONAL,
+  hitRank          [3] IMPLICIT INTEGER OPTIONAL,
+  targetToken        [4] IMPLICIT OCTET STRING OPTIONAL
+                  -- Origin may use token subsequently within a variantRequest (in
+                  --  an elementRequest) to retrieve (or to refer to) the fragment.  
+              }
+
+
+
+
+Variant ::= SEQUENCE{
+    globalVariantSetId    [1] IMPLICIT OBJECT IDENTIFIER OPTIONAL,
+                  -- Applies to the triples below, when variantSetId omitted. If
+                  -- globalVariantSetId omitted, default applies. Default may be provided by
+                  -- the tagSet-M element defaultVariantSetId.
+
+
+
+
+  triples          [2]  IMPLICIT SEQUENCE OF SEQUENCE{
+                  variantSetId  [0]  IMPLICIT OBJECT IDENTIFIER OPTIONAL,
+                              -- If omitted, globalVariantSetId (above)
+                              -- applies, unless that too is omitted, in
+                               -- which case, default used.
+                  class      [1]  IMPLICIT INTEGER,
+                  type      [2]  IMPLICIT INTEGER,
+                  value      [3]  CHOICE{
+                               integer INTEGER,
+                               internationalString InternationalString,
+                               octetString OCTET STRING,
+                               objectIdentifier OBJECT IDENTIFIER,
+                               boolean BOOLEAN,
+                              null NULL,
+                          -- Following need context tags:
+                            unit      [1] IMPLICIT Unit, 
+                            valueAndUnit  [2] IMPLICIT IntUnit}}}
+END
+
+
+
+RecordSyntax-ESTaskPackage
+{Z39-50-recordSyntax ESTaskPackage (106)} DEFINITIONS ::=
+BEGIN 
+IMPORTS Permissions, InternationalString, IntUnit, DiagRec FROM Z39-50-APDU-1995;
+
+TaskPackage ::= SEQUENCE{
+  packageType      [1]   IMPLICIT OBJECT IDENTIFIER,
+                    -- oid of specific ES definition
+  packageName      [2]   IMPLICIT InternationalString OPTIONAL,
+  userId          [3]   IMPLICIT InternationalString OPTIONAL,
+  retentionTime      [4]   IMPLICIT IntUnit OPTIONAL,
+  permissions        [5]   IMPLICIT Permissions OPTIONAL,
+  description        [6]   IMPLICIT InternationalString OPTIONAL,
+  targetReference      [7]   IMPLICIT OCTET STRING OPTIONAL,
+  creationDateTime    [8]   IMPLICIT GeneralizedTime OPTIONAL,
+  taskStatus        [9]   IMPLICIT INTEGER{
+                      pending    (0),
+                      active    (1),
+                      complete  (2),
+                      aborted    (3)},
+  packageDiagnostics    [10]  IMPLICIT SEQUENCE OF DiagRec OPTIONAL,
+  taskSpecificParameters  [11]  IMPLICIT EXTERNAL
+                    -- Use oid for specific ES definition
+                    -- (same oid as packageType above)
+                    -- and select [2] "taskPackage."
+    } 
+END
+
+
+
+
+ResourceReport-Format-Resource-1
+{Z39-50-resourceReport resource-1 (1)} DEFINITIONS ::=
+BEGIN 
+IMPORTS InternationalString FROM Z39-50-APDU-1995;  
+--
+ResourceReport ::= SEQUENCE{
+estimates    [1]   IMPLICIT SEQUENCE OF Estimate,
+message      [2]   IMPLICIT InternationalString}
+--
+Estimate ::= SEQUENCE{
+type        [1]   IMPLICIT EstimateType,
+value        [2]   IMPLICIT INTEGER,  -- the actual estimate
+currency-code  [3]   IMPLICIT INTEGER OPTIONAL
+                -- code for representation of currencies defined in ISO 4217-1990.  
+                -- Applicable only to monetary estimates.
+                              }
+EstimateType ::= INTEGER{
+currentSearchRecords    (1),         -- estimated no. records in current (incomplete) result set for search
+finalSearchRecords       (2),        -- estimated no. records that will be in result set if search completes
+currentPresentRecords    (3),        -- estimated number of records in current (incomplete) set of
+                      -- records to be returned on Present
+finalPresentRecords      (4),  -- estimated number of records that will be in the set of records
+                      -- to be returned by Present if Present completes
+currentOpTimeProcessing  (5),  -- processing time (in .001 CPU seconds) used by operation so far
+finalOpTimeProcessing    (6),                -- estimated total processing time (in .001 CPU seconds) that will
+                              -- be used by this operation if it completes
+currentAssocTime      (7),  -- estimated processing time used by association (in .001 CPU sec.)
+currentOperationCost      (8),  -- estimated cost for this operation so far
+finalOperationCost      (9),  -- estimated cost for this operation if it completes
+currentAssocCost        (10),  -- estimated cost for this association so far
+finalOpTimeElapsed            (11),  -- estimated elapsed time for operation if it completes (in .001 sec.) 
+percentComplete         (12), -- estimated percent complete
+currentSearchAssocCost    (13),  -- estimated search cost for association so far
+currentPresentAssocCost  (14),  -- estimated present cost for this association so far
+currentConnectAssocCost    (15),  -- estimated connect time cost for association so far
+currentOtherAssocCost    (16)  -- estimated other cost (not included in 13-15) for association so far
+                  }
+END
+
+
+
+
+
+
+
+
+
+
+
+
+
+ResourceReport-Format-Resource-2
+{Z39-50-resourceReport resource-2 (2)} DEFINITIONS ::=
+BEGIN 
+IMPORTS InternationalString, StringOrNumeric, IntUnit FROM Z39-50-APDU-1995;  
+--
+ResourceReport ::= SEQUENCE{
+estimates    [1]   IMPLICIT SEQUENCE OF Estimate OPTIONAL,
+message      [2]   IMPLICIT InternationalString OPTIONAL}
+--
+Estimate ::= SEQUENCE{
+type      [1]   StringOrNumeric,
+              -- Numeric values of 1-16 are the same as used in Resource-1.
+value      [2]   IMPLICIT IntUnit
+              -- When expressing currency:
+              --    unitSystem (of Unit) is 'z3950'  (case insensitive)
+              --    unitType is 'iso4217-1990'       (case insensitive)
+              --    unit is currency code from ISO 4217-1990.
+}
+END
+
+
+
+
+
+AccessControlFormat-prompt-1
+{Z39-50-accessControl prompt-1 (1)} DEFINITIONS ::=
+BEGIN
+IMPORTS InternationalString, DiagRec FROM Z39-50-APDU-1995;
+--
+PromptObject ::= CHOICE{
+  challenge      [1] IMPLICIT Challenge,
+   response        [2] IMPLICIT Response}
+
+  Challenge ::= SEQUENCE OF SEQUENCE {
+    promptId      [1] PromptId,
+                    -- Target supplies a number (for an enumerated prompt) or string (for a non
+                    -- -enumerated prompt), for each prompt, and the origin returns it in response, for
+                    -- this prompt, so target may correlate the prompt response with the prompt.
+    defaultResponse  [2] IMPLICIT InternationalString OPTIONAL,
+     promptInfo      [3] CHOICE{ 
+                    character  [1] IMPLICIT InternationalString,
+                    encrypted  [2] IMPLICIT Encryption} OPTIONAL,
+                    -- Information corresponding to an enumerated prompt. For example if 'type', within
+                    -- PromptId, is 'copyright', then promptInfo may contain a copyright statement.  
+    regExpr        [4] IMPLICIT InternationalString OPTIONAL,
+                              -- A regular expression that promptResponse should match. See IEEE 1003.2
+                    -- Volume 1, Section 2.8 "Regular Expression Notation." For example if promptId
+                    -- is "Year of publication," regExpr might be "19[89][0-9]|20[0-9][0-9]".
+    responseRequired  [5] IMPLICIT NULL OPTIONAL,
+     allowedValues    [6] IMPLICIT SEQUENCE OF InternationalString OPTIONAL,
+                        -- e.g. promptId="Desired color"; allowed = 'red', 'blue','Green'.
+    shouldSave      [7] IMPLICIT NULL OPTIONAL,
+                        -- Target recommends that origin save the data that it prompts from the
+                     -- user corresponding to this prompt, because it is likely to be requested again (so
+                    -- origin might not have to prompt the user next time).
+        dataType        [8] IMPLICIT INTEGER{
+                             integer        (1),
+                          date            (2),
+                        float           (3),
+                        alphaNumeric  (4),
+                        url-urn       (5),
+                        boolean       (6)} OPTIONAL,
+                        -- Target telling origin type of data it wants. E.g., if "date" is specified,
+                        -- presumably the origin will try to prompt something "date-like" from the user.
+        diagnostic       [9] IMPLICIT EXTERNAL OPTIONAL
+                          -- Intended for repeat requests when there is an error the origin 
+                        -- should report to the user from previous attempt.
+                }
+
+
+  Response ::= SEQUENCE OF SEQUENCE {
+      promptId    [1] PromptId,
+                  -- Corresponds to a prompt in the challenge, or may be unprompted, for
+                  -- example "newPassword." If unprompted, should be "enumerated." 
+                  -- If this responds to a non-enumerated prompt, then nonEnumeratedPrompt
+                   -- should contain the prompt string from the challenge.
+    promptResponse  [2] CHOICE{
+                    string      [1] IMPLICIT InternationalString,
+                    accept      [2] IMPLICIT BOOLEAN,
+                    acknowledge  [3] IMPLICIT NULL,
+                    diagnostic    [4] DiagRec,
+                     encrypted    [5] IMPLICIT Encryption}}
+
+
+ PromptId ::= CHOICE{
+  enummeratedPrompt    [1] IMPLICIT SEQUENCE{
+                      type            [1] IMPLICIT INTEGER{
+                                      groupId    (0),
+                                      userId     (1),
+                                      password   (2),
+                                      newPassword  (3),
+                                      copyright    (4),
+                            -- When type on Challenge is 'copyright', promptInfo has text of
+                            -- copyright message to be displayed verbatim to the user. If
+                            -- promptResponse indicates 'acceptance', this indicates the user has been
+                            -- shown, and accepted, the terms of the copyright. This is not intended
+                            -- to be legally binding, but provides a good-faith attempt on
+                            -- the part of the target to inform the user of the copyright.
+                                      sessionId      (5)},
+                      suggestedString    [2] IMPLICIT InternationalString OPTIONAL},
+   nonEnumeratedPrompt  [2] IMPLICIT InternationalString}
+
+
+ Encryption ::= SEQUENCE{
+  cryptType    [1] IMPLICIT OCTET STRING OPTIONAL, 
+  credential    [2] IMPLICIT OCTET STRING OPTIONAL,
+                    --random number, SALT, or other factor
+  data        [3] IMPLICIT OCTET STRING}
+
+END
+
+
+
+
+AccessControlFormat-des-1
+{Z39-50-accessControlFormat  des-1 (2)} DEFINITIONS ::=
+BEGIN
+    DES-RN-Object ::= CHOICE {
+      challenge    [1]    IMPLICIT DRNType,
+      response      [2]    IMPLICIT DRNType}
+    DRNType ::= SEQUENCE{
+          userId        [1]    IMPLICIT OCTET STRING OPTIONAL,
+          salt          [2]    IMPLICIT OCTET STRING OPTIONAL,
+          randomNumber  [3]    IMPLICIT OCTET STRING}
+END
+
+
+AccessControlFormat-krb-1
+{Z39-50-accessControlFormat  krb-1 (3)} DEFINITIONS ::=
+BEGIN
+IMPORTS InternationalString FROM Z39-50-APDU-1995;
+
+     KRBObject ::= CHOICE {
+       challenge   [1]    IMPLICIT KRBRequest,
+       response    [2]    IMPLICIT KRBResponse}
+     KRBRequest ::= SEQUENCE{
+           service         [1]   IMPLICIT InternationalString,
+           instance        [2]   IMPLICIT InternationalString OPTIONAL,
+           realm          [3]   IMPLICIT InternationalString OPTIONAL}
+        -- target requests a ticket for the given service, instance, and realm
+     KRBResponse ::= SEQUENCE{
+           userid            [1]   IMPLICIT InternationalString OPTIONAL,
+           ticket           [2]  IMPLICIT OCTET STRING}
+        -- origin responds with a ticket for the requested service
+END
+
+
+
+
+
+
+
+
+
+ESFormat-PersistentResultSet
+{Z39-50-extendedService PersistentResultSet (1)} DEFINITIONS ::=
+BEGIN
+IMPORTS InternationalString FROM Z39-50-APDU-1995;
+PersistentResultSet ::= CHOICE{
+    esRequest    [1] IMPLICIT SEQUENCE{
+        toKeep    [1] IMPLICIT NULL,
+        notToKeep  [2] OriginPartNotToKeep OPTIONAL},
+    taskPackage  [2] IMPLICIT SEQUENCE{
+        originPart  [1] IMPLICIT NULL,
+        targetPart  [2] TargetPart OPTIONAL}}
+OriginPartNotToKeep ::= SEQUENCE{
+  originSuppliedResultSet  [1] IMPLICIT InternationalString OPTIONAL,
+          -- name of transient result set, supplied on request, mandatory unless function is 'delete'
+  replaceOrAppend    [2] IMPLICIT INTEGER{  -- only if function is "modify"
+          replace    (1),
+          append    (2)} OPTIONAL}
+TargetPart ::= SEQUENCE{
+  targetSuppliedResultSet  [1] IMPLICIT InternationalString OPTIONAL, 
+          -- Name of transient result set, supplied by target, representing the persistent result set to which
+          -- package pertains. Meaningful only when package  is presented. (i.e. not on ES response).
+  numberOfRecords  [2] IMPLICIT INTEGER OPTIONAL}
+END
+
+
+ESFormat-PersistentQuery
+{Z39-50-extendedService PersistentQuery (2)} DEFINITIONS ::=
+BEGIN
+IMPORTS Query, InternationalString, OtherInformation FROM Z39-50-APDU-1995;
+PersistentQuery ::= CHOICE{
+    esRequest      [1] IMPLICIT SEQUENCE{
+        toKeep    [1] OriginPartToKeep OPTIONAL,
+        notToKeep  [2] OriginPartNotToKeep},
+    taskPackage    [2] IMPLICIT SEQUENCE{
+        originPart  [1] OriginPartToKeep OPTIONAL,
+        targetPart  [2] TargetPart}}
+OriginPartToKeep ::= SEQUENCE{
+  dbNames        [2] IMPLICIT SEQUENCE OF InternationalString OPTIONAL,
+  additionalSearchInfo  [3] OtherInformation OPTIONAL}
+OriginPartNotToKeep ::= CHOICE{
+  package    [1] IMPLICIT InternationalString,
+  query    [2] Query}
+TargetPart ::= Query          
+END
+
+ESFormat-PeriodicQuerySchedule
+{Z39-50-extendedService PeriodicQuerySchedule (3)} DEFINITIONS ::=
+BEGIN
+IMPORTS Query, InternationalString, IntUnit FROM Z39-50-APDU-1995 
+ExportSpecification, Destination FROM ESFormat-ExportSpecification;
+
+PeriodicQuerySchedule ::= CHOICE{
+    esRequest    [1] IMPLICIT SEQUENCE{
+              toKeep    [1] OriginPartToKeep,
+              notToKeep  [2] OriginPartNotToKeep},
+    taskPackage    [2] IMPLICIT SEQUENCE{
+              originPart  [1] OriginPartToKeep,
+              targetPart  [2] TargetPart}}
+
+OriginPartToKeep ::=SEQUENCE{
+  activeFlag          [1] IMPLICIT BOOLEAN,
+  databaseNames        [2] IMPLICIT SEQUENCE OF InternationalString OPTIONAL,
+  resultSetDisposition      [3] IMPLICIT INTEGER{
+                    replace    (1),
+                    append    (2),
+                    createNew  (3)  -- Only if origin and target have agreement about
+                            -- naming convention for the resulting package,
+                             -- and only if no result set is specified.
+                } OPTIONAL,   -- Mandatory on 'create' if result set is specified, in
+                        -- which case it must be 'replace' or 'append.
+  alertDestination        [4] Destination OPTIONAL,
+  exportParameters      [5] CHOICE{
+                    packageName  [1]   IMPLICIT InternationalString,
+                    exportPackage  [2] ExportSpecification} OPTIONAL}
+
+OriginPartNotToKeep ::= SEQUENCE{
+  querySpec           [1] CHOICE{
+                    actualQuery    [1] Query,
+                    packageName  [2] IMPLICIT InternationalString} OPTIONAL,
+                  -- mandatory for 'create'
+  originSuggestedPeriod    [2] Period OPTIONAL,  -- mandatory for 'create'
+  expiration          [3] IMPLICIT GeneralizedTime OPTIONAL,
+  resultSetPackage        [4] IMPLICIT InternationalString OPTIONAL}
+
+TargetPart ::= SEQUENCE{
+  actualQuery        [1] Query,
+  targetStatedPeriod    [2] Period,
+                  -- Target supplies the period, which may be same as origin proposed.
+  expiration        [3] IMPLICIT GeneralizedTime OPTIONAL,
+                  -- Target supplies value for task package. It may be the same as origin
+                  -- proposed or different from (and overrides) origin proposal, but if
+                  -- omitted, there is no expiration.
+  resultSetPackage      [4] IMPLICIT InternationalString OPTIONAL,
+                  -- May be omitted only if exportParameters was supplied. Target
+                  -- supplies same name as origin supplied, if origin did supply a name.
+  lastQueryTime      [5] IMPLICIT GeneralizedTime,
+  lastResultNumber    [6] IMPLICIT INTEGER,
+  numberSinceModify    [7] IMPLICIT INTEGER OPTIONAL}
+
+
+
+
+  Period ::= CHOICE{
+                unit             [1] IMPLICIT IntUnit,
+                 businessDaily     [2] IMPLICIT NULL,
+              continuous       [3] IMPLICIT NULL,
+              other         [4] IMPLICIT InternationalString}
+END
+
+
+ESFormat-ItemOrder
+{Z39-50-extendedService ItemOrder (4)} DEFINITIONS ::=
+BEGIN
+IMPORTS InternationalString FROM Z39-50-APDU-1995;
+ItemOrder ::= CHOICE{
+    esRequest  [1] IMPLICIT SEQUENCE{
+              toKeep    [1] OriginPartToKeep OPTIONAL,
+              notToKeep  [2] OriginPartNotToKeep},
+    taskPackage  [2] IMPLICIT SEQUENCE{
+              originPart  [1] OriginPartToKeep OPTIONAL,
+              targetPart  [2] TargetPart}}
+OriginPartToKeep ::= SEQUENCE{
+  supplDescription    [1] IMPLICIT EXTERNAL OPTIONAL,
+  contact        [2] IMPLICIT SEQUENCE{
+                       name  [1]   IMPLICIT InternationalString OPTIONAL,
+                         phone  [2]   IMPLICIT InternationalString OPTIONAL,
+                       email  [3]   IMPLICIT InternationalString OPTIONAL} OPTIONAL,
+  addlBilling      [3] IMPLICIT SEQUENCE{
+                paymentMethod    [1]   CHOICE{
+                                  billInvoice              [0] IMPLICIT NULL,
+                                    prepay                [1] IMPLICIT NULL,
+                                    depositAccount        [2] IMPLICIT NULL,
+                                    creditCard          [3] IMPLICIT CreditCardInfo,
+                    cardInfoPreviouslySupplied  [4] IMPLICIT NULL,
+                    privateKnown        [5] IMPLICIT NULL,
+                    privateNotKnown      [6] IMPLICIT EXTERNAL},
+                customerReference  [2] IMPLICIT InternationalString OPTIONAL,
+                     customerPONumber  [3] IMPLICIT InternationalString OPTIONAL}
+                                 OPTIONAL}
+CreditCardInfo   ::= SEQUENCE{
+       nameOnCard    [1] IMPLICIT InternationalString,
+      expirationDate    [2] IMPLICIT InternationalString,
+    cardNumber      [3] IMPLICIT InternationalString} 
+
+OriginPartNotToKeep ::= SEQUENCE{ -- Corresponds to 'requestedItem' in service definition.
+      --  Must supply at least one, and may supply both.
+  resultSetItem    [1]   IMPLICIT SEQUENCE{  
+                resultSetId    [1]   IMPLICIT InternationalString,
+                    item      [2]   IMPLICIT INTEGER} OPTIONAL,
+  itemRequest      [2] IMPLICIT EXTERNAL OPTIONAL
+                -- When itemRequest is an ILL-Request APDU, 
+                -- use OID {iso standard 10161 abstract-syntax (2) ill-apdus (1)}
+              }
+
+TargetPart ::= SEQUENCE{
+  itemRequest      [1]  IMPLICIT EXTERNAL OPTIONAL,
+    -- When itemRequest is an ILL-Request APDU, use OID 1.0.10161.2.1 (as above)
+  statusOrErrorReport  [2] IMPLICIT EXTERNAL OPTIONAL,
+    -- When statusOrErrorReport is an ILL Status-Or-Error-Report APDU, use OID  1.0.10161.2.1 (as above)
+  auxiliaryStatus    [3]  IMPLICIT INTEGER{
+                notReceived      (1),
+                loanQueue      (2),
+                forwarded      (3),
+                unfilledCopyright  (4),
+                filledCopyright    (5)} OPTIONAL}
+END
+
+
+
+
+ESFormat-Update0
+{Z39-50-extendedService Update (5)} DEFINITIONS ::=
+BEGIN
+IMPORTS DiagRec, InternationalString FROM Z39-50-APDU-1995; 
+Update ::= CHOICE{
+    esRequest  [1] IMPLICIT SEQUENCE{
+              toKeep    [1] OriginPartToKeep,
+              notToKeep  [2] OriginPartNotToKeep},
+    taskPackage  [2] IMPLICIT SEQUENCE{
+              originPart  [1] OriginPartToKeep,
+              targetPart  [2] TargetPart}}
+
+
+OriginPartToKeep ::= SEQUENCE{
+  action          [1] IMPLICIT INTEGER{
+                   recordInsert    (1),
+                   recordReplace  (2),
+                  recordDelete  (3),
+                  elementUpdate  (4)},
+  databaseName      [2] IMPLICIT InternationalString,
+  schema          [3] IMPLICIT OBJECT IDENTIFIER OPTIONAL,
+  elementSetName      [4] IMPLICIT InternationalString OPTIONAL}
+
+
+OriginPartNotToKeep ::= SuppliedRecords
+
+
+TargetPart ::= SEQUENCE{
+  updateStatus    [1] IMPLICIT INTEGER{
+                  success  (1),
+                  partial  (2),
+                  failure  (3)},
+  globalDiagnostics  [2] IMPLICIT SEQUENCE OF DiagRec OPTIONAL,
+                -- These are non-surrogate diagnostics relating to the task, 
+                -- not to individual records.
+  taskPackageRecords  [3] IMPLICIT SEQUENCE OF TaskPackageRecordStructure
+                -- There should be a TaskPackageRecordStructure for every record
+                -- supplied. The target should create such a structure for every
+                      -- record immediately upon creating the task package to include
+                -- correlation information and status. The record itself would not
+                -- be included until processing for that record is complete.
+            }
+
+-- Auxiliary definitions for Update
+SuppliedRecords ::= SEQUENCE OF SEQUENCE{
+  recordId    [1] CHOICE{
+              number  [1] IMPLICIT INTEGER,
+              string  [2] IMPLICIT InternationalString,
+              opaque  [3]  IMPLICIT OCTET STRING} OPTIONAL,
+  supplementalId  [2] CHOICE{
+              timeStamp    [1] IMPLICIT GeneralizedTime,
+              versionNumber  [2] IMPLICIT InternationalString,
+              previousVersion  [3] IMPLICIT EXTERNAL} OPTIONAL,
+  correlationInfo  [3] IMPLICIT CorrelationInfo OPTIONAL,
+  record      [4] IMPLICIT EXTERNAL}
+
+CorrelationInfo ::= SEQUENCE{
+          -- origin may supply one or both for any record:
+  note  [1] IMPLICIT InternationalString OPTIONAL,
+  id    [2] IMPLICIT INTEGER OPTIONAL}
+
+TaskPackageRecordStructure ::= SEQUENCE{
+    recordOrSurDiag  [1] CHOICE {
+                record    [1] IMPLICIT EXTERNAL,
+                        -- Choose 'record' if recordStatus is 'success', and
+                        -- elementSetName was supplied.
+                diagnostic  [2] DiagRec
+                        -- Choose 'diagnostic', if RecordStatus is failure.
+                                } OPTIONAL,
+                -- The parameter recordOrSurDiag will thus be omitted only if
+                -- 'elementSetName' was omitted and recordStatus is
+                -- 'success'; or if record status is 'queued' or in 'process'.
+    correlationInfo    [2] IMPLICIT CorrelationInfo OPTIONAL,
+                -- This should be included if it was supplied by the origin.
+    recordStatus      [3] IMPLICIT INTEGER{
+                  success    (1),
+                  queued    (2),
+                  inProcess  (3),
+                  failure    (4)}}
+END
+
+
+ESFormat-ExportSpecification
+{Z39-50-extendedService ExportSpecification (6)} DEFINITIONS ::=
+BEGIN
+EXPORTS ExportSpecification, Destination; IMPORTS CompSpec, InternationalString FROM Z39-50-APDU-1995;
+ExportSpecification ::= CHOICE{
+    esRequest    [1] IMPLICIT SEQUENCE{
+        toKeep    [1] OriginPartToKeep,
+        notToKeep  [2] IMPLICIT NULL},
+    taskPackage    [2] IMPLICIT SEQUENCE{
+        originPart  [1] OriginPartToKeep,
+        targetPart  [2] IMPLICIT NULL}}
+OriginPartToKeep ::= SEQUENCE{
+  composition        [1] IMPLICIT CompSpec,
+  exportDestination    [2] Destination}
+
+  Destination ::= CHOICE{
+  phoneNumber    [1]    IMPLICIT InternationalString,
+  faxNumber      [2]   IMPLICIT InternationalString,
+  x400address      [3]   IMPLICIT InternationalString,
+  emailAddress    [4]   IMPLICIT InternationalString,
+  pagerNumber    [5]   IMPLICIT InternationalString,
+  ftpAddress      [6]   IMPLICIT InternationalString,
+  ftamAddress    [7]   IMPLICIT InternationalString,
+  printerAddress    [8]   IMPLICIT InternationalString,
+  other        [100]  IMPLICIT SEQUENCE{
+                  vehicle      [1]  IMPLICIT InternationalString  OPTIONAL,
+                  destination    [2] IMPLICIT InternationalString}}
+END
+
+
+
+
+ESFormat-ExportInvocation
+{Z39-50-extendedService ExportInvocation (7)} DEFINITIONS ::=
+BEGIN
+IMPORTS InternationalString, IntUnit FROM Z39-50-APDU-1995 
+ExportSpecification FROM ESFormat-ExportSpecification;
+ExportInvocation ::= CHOICE{
+    esRequest    [1] IMPLICIT SEQUENCE{
+        toKeep    [1] OriginPartToKeep,
+        notToKeep  [2] OriginPartNotToKeep},
+    taskPackage    [2] IMPLICIT SEQUENCE{
+        originPart  [1] OriginPartToKeep,
+        targetPart  [2] TargetPart OPTIONAL}}
+
+OriginPartToKeep ::= SEQUENCE{
+  exportSpec    [1] CHOICE{
+              packageName    [1] IMPLICIT InternationalString,
+              packageSpec    [2] ExportSpecification},
+  numberOfCopies  [2] IMPLICIT INTEGER}
+
+
+
+
+
+OriginPartNotToKeep  ::= SEQUENCE{
+  resultSetId      [1] IMPLICIT InternationalString,
+  records        [2] CHOICE{
+                all    [1] IMPLICIT NULL,
+                ranges  [2]   IMPLICIT SEQUENCE OF SEQUENCE{
+                        start  [1] IMPLICIT INTEGER,
+                        count  [2] IMPLICIT INTEGER OPTIONAL
+                          -- Count may be omitted only on last range, to indicate
+                          -- "all remaining records beginning with 'start'."
+                    }}}
+
+TargetPart   ::= SEQUENCE{
+    estimatedQuantity    [1] IMPLICIT IntUnit OPTIONAL,
+    quantitySoFar      [2] IMPLICIT IntUnit OPTIONAL,
+    estimatedCost      [3] IMPLICIT IntUnit OPTIONAL,
+    costSoFar        [4] IMPLICIT IntUnit OPTIONAL}
+END
+
+
+
+UserInfoFormat-searchResult-1
+{Z39-50-userInfoFormat searchResult-1 (1)} DEFINITIONS ::=
+BEGIN
+IMPORTS DatabaseName, Term, Query, IntUnit, InternationalString FROM Z39-50-APDU-1995;
+SearchInfoReport ::= SEQUENCE OF SEQUENCE{
+  subqueryId      [1] IMPLICIT InternationalString OPTIONAL, 
+                           -- shorthand identifier of subquery
+  fullQuery        [2] IMPLICIT BOOLEAN,     -- 'true' means this is the full query; 'false',
+                          -- a sub-query 
+  subqueryExpression    [3] QueryExpression OPTIONAL,  -- A subquery of the query as
+                          -- submitted. May be whole query;
+                          -- if so, "fullQuery" should be 'true'.
+  subqueryInterpretation  [4] QueryExpression OPTIONAL,  -- how target interpreted subquery
+  subqueryRecommendation  [5] QueryExpression OPTIONAL,  -- target-recommended alternative
+  subqueryCount      [6] IMPLICIT INTEGER OPTIONAL,  -- Number of records for this
+                          -- subQuery, across all of the specified
+                          -- databases. (If during search, via resource
+                           -- control, number of records so far).
+  subqueryWeight     [7] IMPLICIT IntUnit OPTIONAL,  -- relative weight of this subquery
+  resultsByDB          [8] IMPLICIT ResultsByDB OPTIONAL}
+
+ResultsByDB ::= SEQUENCE OF SEQUENCE{
+  databases      [1] CHOICE{
+            all     [1] IMPLICIT NULL,
+                  -- applies across all of the databases in Search PDU
+            list    [2]  IMPLICIT SEQUENCE OF DatabaseName
+                  -- applies across all databases in this list
+              },
+  count        [2] IMPLICIT INTEGER OPTIONAL,
+            -- Number of records for query component (and, as above, if during search,
+             -- via resource control, number of records so far).
+  resultSetName    [3] IMPLICIT InternationalString OPTIONAL
+                        -- Target-assigned result set by which subQuery is available. Should not
+             -- be provided unless processing for this query component is concluded (i.e.,
+            -- when this report comes during search, via resource control, as opposed
+            -- to after search, via additionalSearchInfo).
+              }
+
+QueryExpression ::=  CHOICE {
+                term   [1] IMPLICIT SEQUENCE{
+              queryTerm  [1]  Term,
+              termComment            [2] IMPLICIT InternationalString OPTIONAL},
+           query  [2] Query}
+END
+
+
+
+ElementSpecificationFormat-eSpec-1
+{Z39-50-elementSpec eSpec-1 (1)} DEFINITIONS ::=
+BEGIN
+IMPORTS Variant FROM RecordSyntax-generic
+StringOrNumeric, InternationalString FROM Z39-50-APDU-1995;
+--
+Espec-1 ::= SEQUENCE{
+  elementSetNames    [1] IMPLICIT SEQUENCE OF InternationalString OPTIONAL,
+                  -- Origin may include one or more element set names, each
+                  -- specifying a set of elements. Each of the elements is to be
+                  -- treated as an elementRequest in the form of simpleElement,
+                  -- where occurrence is 1. 
+  defaultVariantSetId    [2] IMPLICIT OBJECT IDENTIFIER OPTIONAL,
+                  -- If supplied, applies whenever variantRequest 
+                  -- does not include variantSetId. 
+  defaultVariantRequest  [3] IMPLICIT Variant OPTIONAL,
+                  -- If supplied, then for each simple elementRequest that does not
+                   -- include a variantRequest, the defaultVariantRequest applies.
+                  -- (defaultVariantRequest does not apply to a compositeRequest.)
+  defaultTagType      [4] IMPLICIT INTEGER OPTIONAL,
+                  -- If supplied, applies whenever 'tagType' (within 'tag' within TagPath) 
+                  -- is omitted.
+  elements        [5] IMPLICIT SEQUENCE OF ElementRequest OPTIONAL}
+--
+
+ElementRequest::= CHOICE{
+  simpleElement    [1]   IMPLICIT SimpleElement,
+  compositeElement  [2] IMPLICIT SEQUENCE{
+            elementList    [1] CHOICE{
+                  primitives    [1]   IMPLICIT SEQUENCE OF InternationalString,
+                              -- Origin may specify one or more element
+                              -- set names, each identifying a set of elements,
+                              -- and the composite element is the union.
+                  specs      [2] IMPLICIT SEQUENCE OF SimpleElement},
+
+            deliveryTag    [2] IMPLICIT TagPath,
+                          -- DeliveryTag tagPath for compositeElement may not
+                          -- include wildThing or wildPath.
+            variantRequest  [3] IMPLICIT Variant OPTIONAL}}
+
+SimpleElement ::= SEQUENCE{
+      path        [1] IMPLICIT TagPath,
+      variantRequest  [2] IMPLICIT Variant OPTIONAL}
+  
+
+TagPath ::= SEQUENCE OF CHOICE{  
+  specificTag  [1] IMPLICIT SEQUENCE{
+            tagType  [1] IMPLICIT INTEGER OPTIONAL,
+                      -- If omitted, then 'defaultTagType' (above) applies, if supplied, and
+                      -- if not supplied, then default listed in schema applies.
+            tagValue  [2] StringOrNumeric,
+             occurrence  [3] Occurrences OPTIONAL 
+                      -- default is "first occurrence"
+                  },
+  wildThing  [2] Occurrences,
+              -- Get Nth "thing" at this level, regardless of tag, for each N specified by
+            -- "Occurrences" (which may be 'all' meaning match every element at this level).
+            -- E.g., if "Occurrences" is 3, get third element regardless of its tag or the tag of
+            -- the first two elements.
+  wildPath  [3] IMPLICIT NULL
+              -- Match any tag, at this level or below, that is on a path for which next tag in this 
+              -- TagPath sequence occurs. WildPath may not be last member of the TagPath
+            -- sequence.
+                      }
+--
+
+Occurrences ::= CHOICE{
+  all    [1] IMPLICIT NULL,
+  last    [2] IMPLICIT NULL,
+  values  [3] IMPLICIT SEQUENCE{
+          start    [1] IMPLICIT INTEGER,
+                  -- if 'start' alone is included, then single occurrence is requested
+          howMany  [2] IMPLICIT INTEGER OPTIONAL
+                  -- For example, if 'start' is 5 and 'howMany' is 6, then request is for
+                  -- "occurrences 5 through 10."
+                  }}
+END
+
Index: /main/tags/2.25/gsdl/packages/yaz/z39.50/zes-expi.c
===================================================================
--- /main/tags/2.25/gsdl/packages/yaz/z39.50/zes-expi.c	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/yaz/z39.50/zes-expi.c	(revision 21064)
@@ -0,0 +1,124 @@
+/* Generated automatically by the YAZ ASN.1 Compiler 0.3 */
+/* Module-C: ESFormat-ExportInvocation */
+
+#include <yaz/zes-expi.h>
+
+int z_EIExportInvocationEsRequest (ODR o, Z_EIExportInvocationEsRequest **p, int opt, const char *name)
+{
+	if (!odr_sequence_begin (o, p, sizeof(**p), name))
+		return opt && odr_ok (o);
+	return
+		odr_explicit_tag (o, z_EIOriginPartToKeep,
+			&(*p)->toKeep, ODR_CONTEXT, 1, 0, "toKeep") &&
+		odr_explicit_tag (o, z_EIOriginPartNotToKeep,
+			&(*p)->notToKeep, ODR_CONTEXT, 2, 0, "notToKeep") &&
+		odr_sequence_end (o);
+}
+
+int z_EIExportInvocationTaskPackage (ODR o, Z_EIExportInvocationTaskPackage **p, int opt, const char *name)
+{
+	if (!odr_sequence_begin (o, p, sizeof(**p), name))
+		return opt && odr_ok (o);
+	return
+		odr_explicit_tag (o, z_EIOriginPartToKeep,
+			&(*p)->originPart, ODR_CONTEXT, 1, 0, "originPart") &&
+		odr_explicit_tag (o, z_EITargetPart,
+			&(*p)->targetPart, ODR_CONTEXT, 2, 1, "targetPart") &&
+		odr_sequence_end (o);
+}
+
+int z_EIExportInvocation (ODR o, Z_EIExportInvocation **p, int opt, const char *name)
+{
+	static Odr_arm arm[] = {
+		{ODR_IMPLICIT, ODR_CONTEXT, 1, Z_EIExportInvocation_esRequest,
+		(Odr_fun) z_EIExportInvocationEsRequest, "esRequest"},
+		{ODR_IMPLICIT, ODR_CONTEXT, 2, Z_EIExportInvocation_taskPackage,
+		(Odr_fun) z_EIExportInvocationTaskPackage, "taskPackage"},
+		{-1, -1, -1, -1, (Odr_fun) 0, 0}
+	};
+	if (!odr_initmember(o, p, sizeof(**p)))
+		return opt && odr_ok(o);
+	if (odr_choice(o, arm, &(*p)->u, &(*p)->which, name))
+		return 1;
+	*p = 0;
+	return opt && odr_ok(o);
+}
+
+int z_EIOriginPartToKeep (ODR o, Z_EIOriginPartToKeep **p, int opt, const char *name)
+{
+	static Odr_arm arm[] = {
+		{ODR_IMPLICIT, ODR_CONTEXT, 1, Z_EIOriginPartToKeep_packageName,
+		(Odr_fun) z_InternationalString, "packageName"},
+		{ODR_EXPLICIT, ODR_CONTEXT, 2, Z_EIOriginPartToKeep_packageSpec,
+		(Odr_fun) z_ESExportSpecification, "packageSpec"},
+		{-1, -1, -1, -1, (Odr_fun) 0, 0}
+	};
+	if (!odr_sequence_begin (o, p, sizeof(**p), name))
+		return opt && odr_ok (o);
+	return
+		odr_constructed_begin (o, &(*p)->u, ODR_CONTEXT, 1, "exportSpec") &&
+		odr_choice (o, arm, &(*p)->u, &(*p)->which, 0) &&
+		odr_constructed_end (o) &&
+		odr_implicit_tag (o, odr_integer,
+			&(*p)->numberOfCopies, ODR_CONTEXT, 2, 0, "numberOfCopies") &&
+		odr_sequence_end (o);
+}
+
+int z_EIOriginPartNotToKeepRanges_s (ODR o, Z_EIOriginPartNotToKeepRanges_s **p, int opt, const char *name)
+{
+	if (!odr_sequence_begin (o, p, sizeof(**p), name))
+		return opt && odr_ok (o);
+	return
+		odr_implicit_tag (o, odr_integer,
+			&(*p)->start, ODR_CONTEXT, 1, 0, "start") &&
+		odr_implicit_tag (o, odr_integer,
+			&(*p)->count, ODR_CONTEXT, 2, 1, "count") &&
+		odr_sequence_end (o);
+}
+
+int z_EIOriginPartNotToKeepRanges (ODR o, Z_EIOriginPartNotToKeepRanges **p, int opt, const char *name)
+{
+	if (!odr_initmember (o, p, sizeof(**p)))
+		return opt && odr_ok(o);
+	if (odr_sequence_of (o, (Odr_fun) z_EIOriginPartNotToKeepRanges_s, &(*p)->elements,
+		&(*p)->num, name))
+		return 1;
+	*p = 0;
+	return opt && odr_ok(o);
+}
+
+int z_EIOriginPartNotToKeep (ODR o, Z_EIOriginPartNotToKeep **p, int opt, const char *name)
+{
+	static Odr_arm arm[] = {
+		{ODR_IMPLICIT, ODR_CONTEXT, 1, Z_EIOriginPartNotToKeep_all,
+		(Odr_fun) odr_null, "all"},
+		{ODR_IMPLICIT, ODR_CONTEXT, 2, Z_EIOriginPartNotToKeep_ranges,
+		(Odr_fun) z_EIOriginPartNotToKeepRanges, "ranges"},
+		{-1, -1, -1, -1, (Odr_fun) 0, 0}
+	};
+	if (!odr_sequence_begin (o, p, sizeof(**p), name))
+		return opt && odr_ok (o);
+	return
+		odr_implicit_tag (o, z_InternationalString,
+			&(*p)->resultSetId, ODR_CONTEXT, 1, 0, "resultSetId") &&
+		odr_constructed_begin (o, &(*p)->u, ODR_CONTEXT, 2, "records") &&
+		odr_choice (o, arm, &(*p)->u, &(*p)->which, 0) &&
+		odr_constructed_end (o) &&
+		odr_sequence_end (o);
+}
+
+int z_EITargetPart (ODR o, Z_EITargetPart **p, int opt, const char *name)
+{
+	if (!odr_sequence_begin (o, p, sizeof(**p), name))
+		return opt && odr_ok (o);
+	return
+		odr_implicit_tag (o, z_IntUnit,
+			&(*p)->estimatedQuantity, ODR_CONTEXT, 1, 1, "estimatedQuantity") &&
+		odr_implicit_tag (o, z_IntUnit,
+			&(*p)->quantitySoFar, ODR_CONTEXT, 2, 1, "quantitySoFar") &&
+		odr_implicit_tag (o, z_IntUnit,
+			&(*p)->estimatedCost, ODR_CONTEXT, 3, 1, "estimatedCost") &&
+		odr_implicit_tag (o, z_IntUnit,
+			&(*p)->costSoFar, ODR_CONTEXT, 4, 1, "costSoFar") &&
+		odr_sequence_end (o);
+}
Index: /main/tags/2.25/gsdl/packages/yaz/z39.50/zes-exps.c
===================================================================
--- /main/tags/2.25/gsdl/packages/yaz/z39.50/zes-exps.c	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/yaz/z39.50/zes-exps.c	(revision 21064)
@@ -0,0 +1,100 @@
+/* Generated automatically by the YAZ ASN.1 Compiler 0.3 */
+/* Module-C: ESFormat-ExportSpecification */
+
+#include <yaz/zes-exps.h>
+
+int z_ESExportSpecificationEsRequest (ODR o, Z_ESExportSpecificationEsRequest **p, int opt, const char *name)
+{
+	if (!odr_sequence_begin (o, p, sizeof(**p), name))
+		return opt && odr_ok (o);
+	return
+		odr_explicit_tag (o, z_ESOriginPartToKeep,
+			&(*p)->toKeep, ODR_CONTEXT, 1, 0, "toKeep") &&
+		odr_implicit_tag (o, odr_null,
+			&(*p)->notToKeep, ODR_CONTEXT, 2, 0, "notToKeep") &&
+		odr_sequence_end (o);
+}
+
+int z_ESExportSpecificationTaskPackage (ODR o, Z_ESExportSpecificationTaskPackage **p, int opt, const char *name)
+{
+	if (!odr_sequence_begin (o, p, sizeof(**p), name))
+		return opt && odr_ok (o);
+	return
+		odr_explicit_tag (o, z_ESOriginPartToKeep,
+			&(*p)->originPart, ODR_CONTEXT, 1, 0, "originPart") &&
+		odr_implicit_tag (o, odr_null,
+			&(*p)->targetPart, ODR_CONTEXT, 2, 0, "targetPart") &&
+		odr_sequence_end (o);
+}
+
+int z_ESExportSpecification (ODR o, Z_ESExportSpecification **p, int opt, const char *name)
+{
+	static Odr_arm arm[] = {
+		{ODR_IMPLICIT, ODR_CONTEXT, 1, Z_ESExportSpecification_esRequest,
+		(Odr_fun) z_ESExportSpecificationEsRequest, "esRequest"},
+		{ODR_IMPLICIT, ODR_CONTEXT, 2, Z_ESExportSpecification_taskPackage,
+		(Odr_fun) z_ESExportSpecificationTaskPackage, "taskPackage"},
+		{-1, -1, -1, -1, (Odr_fun) 0, 0}
+	};
+	if (!odr_initmember(o, p, sizeof(**p)))
+		return opt && odr_ok(o);
+	if (odr_choice(o, arm, &(*p)->u, &(*p)->which, name))
+		return 1;
+	*p = 0;
+	return opt && odr_ok(o);
+}
+
+int z_ESOriginPartToKeep (ODR o, Z_ESOriginPartToKeep **p, int opt, const char *name)
+{
+	if (!odr_sequence_begin (o, p, sizeof(**p), name))
+		return opt && odr_ok (o);
+	return
+		odr_implicit_tag (o, z_CompSpec,
+			&(*p)->composition, ODR_CONTEXT, 1, 0, "composition") &&
+		odr_explicit_tag (o, z_ESDestination,
+			&(*p)->exportDestination, ODR_CONTEXT, 2, 0, "exportDestination") &&
+		odr_sequence_end (o);
+}
+
+int z_ESDestinationOther (ODR o, Z_ESDestinationOther **p, int opt, const char *name)
+{
+	if (!odr_sequence_begin (o, p, sizeof(**p), name))
+		return opt && odr_ok (o);
+	return
+		odr_implicit_tag (o, z_InternationalString,
+			&(*p)->vehicle, ODR_CONTEXT, 1, 1, "vehicle") &&
+		odr_implicit_tag (o, z_InternationalString,
+			&(*p)->destination, ODR_CONTEXT, 2, 0, "destination") &&
+		odr_sequence_end (o);
+}
+
+int z_ESDestination (ODR o, Z_ESDestination **p, int opt, const char *name)
+{
+	static Odr_arm arm[] = {
+		{ODR_IMPLICIT, ODR_CONTEXT, 1, Z_ESDestination_phoneNumber,
+		(Odr_fun) z_InternationalString, "phoneNumber"},
+		{ODR_IMPLICIT, ODR_CONTEXT, 2, Z_ESDestination_faxNumber,
+		(Odr_fun) z_InternationalString, "faxNumber"},
+		{ODR_IMPLICIT, ODR_CONTEXT, 3, Z_ESDestination_x400address,
+		(Odr_fun) z_InternationalString, "x400address"},
+		{ODR_IMPLICIT, ODR_CONTEXT, 4, Z_ESDestination_emailAddress,
+		(Odr_fun) z_InternationalString, "emailAddress"},
+		{ODR_IMPLICIT, ODR_CONTEXT, 5, Z_ESDestination_pagerNumber,
+		(Odr_fun) z_InternationalString, "pagerNumber"},
+		{ODR_IMPLICIT, ODR_CONTEXT, 6, Z_ESDestination_ftpAddress,
+		(Odr_fun) z_InternationalString, "ftpAddress"},
+		{ODR_IMPLICIT, ODR_CONTEXT, 7, Z_ESDestination_ftamAddress,
+		(Odr_fun) z_InternationalString, "ftamAddress"},
+		{ODR_IMPLICIT, ODR_CONTEXT, 8, Z_ESDestination_printerAddress,
+		(Odr_fun) z_InternationalString, "printerAddress"},
+		{ODR_IMPLICIT, ODR_CONTEXT, 100, Z_ESDestination_other,
+		(Odr_fun) z_ESDestinationOther, "other"},
+		{-1, -1, -1, -1, (Odr_fun) 0, 0}
+	};
+	if (!odr_initmember(o, p, sizeof(**p)))
+		return opt && odr_ok(o);
+	if (odr_choice(o, arm, &(*p)->u, &(*p)->which, name))
+		return 1;
+	*p = 0;
+	return opt && odr_ok(o);
+}
Index: /main/tags/2.25/gsdl/packages/yaz/z39.50/zes-order.c
===================================================================
--- /main/tags/2.25/gsdl/packages/yaz/z39.50/zes-order.c	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/yaz/z39.50/zes-order.c	(revision 21064)
@@ -0,0 +1,157 @@
+/* Generated automatically by the YAZ ASN.1 Compiler 0.3 */
+/* Module-C: ESFormat-ItemOrder */
+
+#include <yaz/zes-order.h>
+
+int z_IORequest (ODR o, Z_IORequest **p, int opt, const char *name)
+{
+	if (!odr_sequence_begin (o, p, sizeof(**p), name))
+		return opt && odr_ok (o);
+	return
+		odr_explicit_tag (o, z_IOOriginPartToKeep,
+			&(*p)->toKeep, ODR_CONTEXT, 1, 1, "toKeep") &&
+		odr_explicit_tag (o, z_IOOriginPartNotToKeep,
+			&(*p)->notToKeep, ODR_CONTEXT, 2, 0, "notToKeep") &&
+		odr_sequence_end (o);
+}
+
+int z_IOTaskPackage (ODR o, Z_IOTaskPackage **p, int opt, const char *name)
+{
+	if (!odr_sequence_begin (o, p, sizeof(**p), name))
+		return opt && odr_ok (o);
+	return
+		odr_explicit_tag (o, z_IOOriginPartToKeep,
+			&(*p)->originPart, ODR_CONTEXT, 1, 1, "originPart") &&
+		odr_explicit_tag (o, z_IOTargetPart,
+			&(*p)->targetPart, ODR_CONTEXT, 2, 0, "targetPart") &&
+		odr_sequence_end (o);
+}
+
+int z_IOItemOrder (ODR o, Z_IOItemOrder **p, int opt, const char *name)
+{
+	static Odr_arm arm[] = {
+		{ODR_IMPLICIT, ODR_CONTEXT, 1, Z_IOItemOrder_esRequest,
+		(Odr_fun) z_IORequest, "esRequest"},
+		{ODR_IMPLICIT, ODR_CONTEXT, 2, Z_IOItemOrder_taskPackage,
+		(Odr_fun) z_IOTaskPackage, "taskPackage"},
+		{-1, -1, -1, -1, (Odr_fun) 0, 0}
+	};
+	if (!odr_initmember(o, p, sizeof(**p)))
+		return opt && odr_ok(o);
+	if (odr_choice(o, arm, &(*p)->u, &(*p)->which, name))
+		return 1;
+	*p = 0;
+	return opt && odr_ok(o);
+}
+
+int z_IOContact (ODR o, Z_IOContact **p, int opt, const char *name)
+{
+	if (!odr_sequence_begin (o, p, sizeof(**p), name))
+		return opt && odr_ok (o);
+	return
+		odr_implicit_tag (o, z_InternationalString,
+			&(*p)->name, ODR_CONTEXT, 1, 1, "name") &&
+		odr_implicit_tag (o, z_InternationalString,
+			&(*p)->phone, ODR_CONTEXT, 2, 1, "phone") &&
+		odr_implicit_tag (o, z_InternationalString,
+			&(*p)->email, ODR_CONTEXT, 3, 1, "email") &&
+		odr_sequence_end (o);
+}
+
+int z_IOBilling (ODR o, Z_IOBilling **p, int opt, const char *name)
+{
+	static Odr_arm arm[] = {
+		{ODR_IMPLICIT, ODR_CONTEXT, 0, Z_IOBilling_billInvoice,
+		(Odr_fun) odr_null, "billInvoice"},
+		{ODR_IMPLICIT, ODR_CONTEXT, 1, Z_IOBilling_prepay,
+		(Odr_fun) odr_null, "prepay"},
+		{ODR_IMPLICIT, ODR_CONTEXT, 2, Z_IOBilling_depositAccount,
+		(Odr_fun) odr_null, "depositAccount"},
+		{ODR_IMPLICIT, ODR_CONTEXT, 3, Z_IOBilling_creditCard,
+		(Odr_fun) z_IOCreditCardInfo, "creditCard"},
+		{ODR_IMPLICIT, ODR_CONTEXT, 4, Z_IOBilling_cardInfoPreviouslySupplied,
+		(Odr_fun) odr_null, "cardInfoPreviouslySupplied"},
+		{ODR_IMPLICIT, ODR_CONTEXT, 5, Z_IOBilling_privateKnown,
+		(Odr_fun) odr_null, "privateKnown"},
+		{ODR_IMPLICIT, ODR_CONTEXT, 6, Z_IOBilling_privateNotKnown,
+		(Odr_fun) z_External, "privateNotKnown"},
+		{-1, -1, -1, -1, (Odr_fun) 0, 0}
+	};
+	if (!odr_sequence_begin (o, p, sizeof(**p), name))
+		return opt && odr_ok (o);
+	return
+		odr_constructed_begin (o, &(*p)->u, ODR_CONTEXT, 1, "paymentMethod") &&
+		odr_choice (o, arm, &(*p)->u, &(*p)->which, 0) &&
+		odr_constructed_end (o) &&
+		odr_implicit_tag (o, z_InternationalString,
+			&(*p)->customerReference, ODR_CONTEXT, 2, 1, "customerReference") &&
+		odr_implicit_tag (o, z_InternationalString,
+			&(*p)->customerPONumber, ODR_CONTEXT, 3, 1, "customerPONumber") &&
+		odr_sequence_end (o);
+}
+
+int z_IOOriginPartToKeep (ODR o, Z_IOOriginPartToKeep **p, int opt, const char *name)
+{
+	if (!odr_sequence_begin (o, p, sizeof(**p), name))
+		return opt && odr_ok (o);
+	return
+		odr_implicit_tag (o, z_External,
+			&(*p)->supplDescription, ODR_CONTEXT, 1, 1, "supplDescription") &&
+		odr_implicit_tag (o, z_IOContact,
+			&(*p)->contact, ODR_CONTEXT, 2, 1, "contact") &&
+		odr_implicit_tag (o, z_IOBilling,
+			&(*p)->addlBilling, ODR_CONTEXT, 3, 1, "addlBilling") &&
+		odr_sequence_end (o);
+}
+
+int z_IOCreditCardInfo (ODR o, Z_IOCreditCardInfo **p, int opt, const char *name)
+{
+	if (!odr_sequence_begin (o, p, sizeof(**p), name))
+		return opt && odr_ok (o);
+	return
+		odr_implicit_tag (o, z_InternationalString,
+			&(*p)->nameOnCard, ODR_CONTEXT, 1, 0, "nameOnCard") &&
+		odr_implicit_tag (o, z_InternationalString,
+			&(*p)->expirationDate, ODR_CONTEXT, 2, 0, "expirationDate") &&
+		odr_implicit_tag (o, z_InternationalString,
+			&(*p)->cardNumber, ODR_CONTEXT, 3, 0, "cardNumber") &&
+		odr_sequence_end (o);
+}
+
+int z_IOResultSetItem (ODR o, Z_IOResultSetItem **p, int opt, const char *name)
+{
+	if (!odr_sequence_begin (o, p, sizeof(**p), name))
+		return opt && odr_ok (o);
+	return
+		odr_implicit_tag (o, z_InternationalString,
+			&(*p)->resultSetId, ODR_CONTEXT, 1, 0, "resultSetId") &&
+		odr_implicit_tag (o, odr_integer,
+			&(*p)->item, ODR_CONTEXT, 2, 0, "item") &&
+		odr_sequence_end (o);
+}
+
+int z_IOOriginPartNotToKeep (ODR o, Z_IOOriginPartNotToKeep **p, int opt, const char *name)
+{
+	if (!odr_sequence_begin (o, p, sizeof(**p), name))
+		return opt && odr_ok (o);
+	return
+		odr_implicit_tag (o, z_IOResultSetItem,
+			&(*p)->resultSetItem, ODR_CONTEXT, 1, 1, "resultSetItem") &&
+		odr_implicit_tag (o, z_External,
+			&(*p)->itemRequest, ODR_CONTEXT, 2, 1, "itemRequest") &&
+		odr_sequence_end (o);
+}
+
+int z_IOTargetPart (ODR o, Z_IOTargetPart **p, int opt, const char *name)
+{
+	if (!odr_sequence_begin (o, p, sizeof(**p), name))
+		return opt && odr_ok (o);
+	return
+		odr_implicit_tag (o, z_External,
+			&(*p)->itemRequest, ODR_CONTEXT, 1, 1, "itemRequest") &&
+		odr_implicit_tag (o, z_External,
+			&(*p)->statusOrErrorReport, ODR_CONTEXT, 2, 1, "statusOrErrorReport") &&
+		odr_implicit_tag (o, odr_integer,
+			&(*p)->auxiliaryStatus, ODR_CONTEXT, 3, 1, "auxiliaryStatus") &&
+		odr_sequence_end (o);
+}
Index: /main/tags/2.25/gsdl/packages/yaz/z39.50/zes-pquery.c
===================================================================
--- /main/tags/2.25/gsdl/packages/yaz/z39.50/zes-pquery.c	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/yaz/z39.50/zes-pquery.c	(revision 21064)
@@ -0,0 +1,80 @@
+/* Generated automatically by the YAZ ASN.1 Compiler 0.3 */
+/* Module-C: ESFormat-PersistentQuery */
+
+#include <yaz/zes-pquery.h>
+
+int z_PQueryPersistentQueryEsRequest (ODR o, Z_PQueryPersistentQueryEsRequest **p, int opt, const char *name)
+{
+	if (!odr_sequence_begin (o, p, sizeof(**p), name))
+		return opt && odr_ok (o);
+	return
+		odr_explicit_tag (o, z_PQueryOriginPartToKeep,
+			&(*p)->toKeep, ODR_CONTEXT, 1, 1, "toKeep") &&
+		odr_explicit_tag (o, z_PQueryOriginPartNotToKeep,
+			&(*p)->notToKeep, ODR_CONTEXT, 2, 0, "notToKeep") &&
+		odr_sequence_end (o);
+}
+
+int z_PQueryPersistentQueryTaskPackage (ODR o, Z_PQueryPersistentQueryTaskPackage **p, int opt, const char *name)
+{
+	if (!odr_sequence_begin (o, p, sizeof(**p), name))
+		return opt && odr_ok (o);
+	return
+		odr_explicit_tag (o, z_PQueryOriginPartToKeep,
+			&(*p)->originPart, ODR_CONTEXT, 1, 1, "originPart") &&
+		odr_explicit_tag (o, z_PQueryTargetPart,
+			&(*p)->targetPart, ODR_CONTEXT, 2, 0, "targetPart") &&
+		odr_sequence_end (o);
+}
+
+int z_PQueryPersistentQuery (ODR o, Z_PQueryPersistentQuery **p, int opt, const char *name)
+{
+	static Odr_arm arm[] = {
+		{ODR_IMPLICIT, ODR_CONTEXT, 1, Z_PQueryPersistentQuery_esRequest,
+		(Odr_fun) z_PQueryPersistentQueryEsRequest, "esRequest"},
+		{ODR_IMPLICIT, ODR_CONTEXT, 2, Z_PQueryPersistentQuery_taskPackage,
+		(Odr_fun) z_PQueryPersistentQueryTaskPackage, "taskPackage"},
+		{-1, -1, -1, -1, (Odr_fun) 0, 0}
+	};
+	if (!odr_initmember(o, p, sizeof(**p)))
+		return opt && odr_ok(o);
+	if (odr_choice(o, arm, &(*p)->u, &(*p)->which, name))
+		return 1;
+	*p = 0;
+	return opt && odr_ok(o);
+}
+
+int z_PQueryOriginPartToKeep (ODR o, Z_PQueryOriginPartToKeep **p, int opt, const char *name)
+{
+	if (!odr_sequence_begin (o, p, sizeof(**p), name))
+		return opt && odr_ok (o);
+	return
+		odr_implicit_settag (o, ODR_CONTEXT, 2) &&
+		(odr_sequence_of(o, (Odr_fun) z_InternationalString, &(*p)->dbNames,
+		  &(*p)->num_dbNames, "dbNames") || odr_ok(o)) &&
+		odr_explicit_tag (o, z_OtherInformation,
+			&(*p)->additionalSearchInfo, ODR_CONTEXT, 3, 1, "additionalSearchInfo") &&
+		odr_sequence_end (o);
+}
+
+int z_PQueryOriginPartNotToKeep (ODR o, Z_PQueryOriginPartNotToKeep **p, int opt, const char *name)
+{
+	static Odr_arm arm[] = {
+		{ODR_IMPLICIT, ODR_CONTEXT, 1, Z_PQueryOriginPartNotToKeep_package,
+		(Odr_fun) z_InternationalString, "package"},
+		{ODR_EXPLICIT, ODR_CONTEXT, 2, Z_PQueryOriginPartNotToKeep_query,
+		(Odr_fun) z_Query, "query"},
+		{-1, -1, -1, -1, (Odr_fun) 0, 0}
+	};
+	if (!odr_initmember(o, p, sizeof(**p)))
+		return opt && odr_ok(o);
+	if (odr_choice(o, arm, &(*p)->u, &(*p)->which, name))
+		return 1;
+	*p = 0;
+	return opt && odr_ok(o);
+}
+
+int z_PQueryTargetPart (ODR o, Z_PQueryTargetPart **p, int opt, const char *name)
+{
+	return z_Query (o, p, opt, name);
+}
Index: /main/tags/2.25/gsdl/packages/yaz/z39.50/zes-psched.c
===================================================================
--- /main/tags/2.25/gsdl/packages/yaz/z39.50/zes-psched.c	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/yaz/z39.50/zes-psched.c	(revision 21064)
@@ -0,0 +1,139 @@
+/* Generated automatically by the YAZ ASN.1 Compiler 0.3 */
+/* Module-C: ESFormat-PeriodicQuerySchedule */
+
+#include <yaz/zes-psched.h>
+
+int z_PQSPeriodicQueryScheduleEsRequest (ODR o, Z_PQSPeriodicQueryScheduleEsRequest **p, int opt, const char *name)
+{
+	if (!odr_sequence_begin (o, p, sizeof(**p), name))
+		return opt && odr_ok (o);
+	return
+		odr_explicit_tag (o, z_PQSOriginPartToKeep,
+			&(*p)->toKeep, ODR_CONTEXT, 1, 0, "toKeep") &&
+		odr_explicit_tag (o, z_PQSOriginPartNotToKeep,
+			&(*p)->notToKeep, ODR_CONTEXT, 2, 0, "notToKeep") &&
+		odr_sequence_end (o);
+}
+
+int z_PQSPeriodicQueryScheduleTaskPackage (ODR o, Z_PQSPeriodicQueryScheduleTaskPackage **p, int opt, const char *name)
+{
+	if (!odr_sequence_begin (o, p, sizeof(**p), name))
+		return opt && odr_ok (o);
+	return
+		odr_explicit_tag (o, z_PQSOriginPartToKeep,
+			&(*p)->originPart, ODR_CONTEXT, 1, 0, "originPart") &&
+		odr_explicit_tag (o, z_PQSTargetPart,
+			&(*p)->targetPart, ODR_CONTEXT, 2, 0, "targetPart") &&
+		odr_sequence_end (o);
+}
+
+int z_PQSPeriodicQuerySchedule (ODR o, Z_PQSPeriodicQuerySchedule **p, int opt, const char *name)
+{
+	static Odr_arm arm[] = {
+		{ODR_IMPLICIT, ODR_CONTEXT, 1, Z_PQSPeriodicQuerySchedule_esRequest,
+		(Odr_fun) z_PQSPeriodicQueryScheduleEsRequest, "esRequest"},
+		{ODR_IMPLICIT, ODR_CONTEXT, 2, Z_PQSPeriodicQuerySchedule_taskPackage,
+		(Odr_fun) z_PQSPeriodicQueryScheduleTaskPackage, "taskPackage"},
+		{-1, -1, -1, -1, (Odr_fun) 0, 0}
+	};
+	if (!odr_initmember(o, p, sizeof(**p)))
+		return opt && odr_ok(o);
+	if (odr_choice(o, arm, &(*p)->u, &(*p)->which, name))
+		return 1;
+	*p = 0;
+	return opt && odr_ok(o);
+}
+
+int z_PQSOriginPartToKeep (ODR o, Z_PQSOriginPartToKeep **p, int opt, const char *name)
+{
+	static Odr_arm arm[] = {
+		{ODR_IMPLICIT, ODR_CONTEXT, 1, Z_PQSOriginPartToKeep_packageName,
+		(Odr_fun) z_InternationalString, "packageName"},
+		{ODR_EXPLICIT, ODR_CONTEXT, 2, Z_PQSOriginPartToKeep_exportPackage,
+		(Odr_fun) z_ESExportSpecification, "exportPackage"},
+		{-1, -1, -1, -1, (Odr_fun) 0, 0}
+	};
+	if (!odr_sequence_begin (o, p, sizeof(**p), name))
+		return opt && odr_ok (o);
+	return
+		odr_implicit_tag (o, odr_bool,
+			&(*p)->activeFlag, ODR_CONTEXT, 1, 0, "activeFlag") &&
+		odr_implicit_settag (o, ODR_CONTEXT, 2) &&
+		(odr_sequence_of(o, (Odr_fun) z_InternationalString, &(*p)->databaseNames,
+		  &(*p)->num_databaseNames, "databaseNames") || odr_ok(o)) &&
+		odr_implicit_tag (o, odr_integer,
+			&(*p)->resultSetDisposition, ODR_CONTEXT, 3, 1, "resultSetDisposition") &&
+		odr_explicit_tag (o, z_ESDestination,
+			&(*p)->alertDestination, ODR_CONTEXT, 4, 1, "alertDestination") &&
+		((odr_constructed_begin (o, &(*p)->u, ODR_CONTEXT, 5, "exportParameters") &&
+		odr_choice (o, arm, &(*p)->u, &(*p)->which, 0) &&
+		odr_constructed_end (o)) || odr_ok(o)) &&
+		odr_sequence_end (o);
+}
+
+int z_PQSOriginPartNotToKeep (ODR o, Z_PQSOriginPartNotToKeep **p, int opt, const char *name)
+{
+	static Odr_arm arm[] = {
+		{ODR_EXPLICIT, ODR_CONTEXT, 1, Z_PQSOriginPartNotToKeep_actualQuery,
+		(Odr_fun) z_Query, "actualQuery"},
+		{ODR_IMPLICIT, ODR_CONTEXT, 2, Z_PQSOriginPartNotToKeep_packageName,
+		(Odr_fun) z_InternationalString, "packageName"},
+		{-1, -1, -1, -1, (Odr_fun) 0, 0}
+	};
+	if (!odr_sequence_begin (o, p, sizeof(**p), name))
+		return opt && odr_ok (o);
+	return
+		((odr_constructed_begin (o, &(*p)->u, ODR_CONTEXT, 1, "querySpec") &&
+		odr_choice (o, arm, &(*p)->u, &(*p)->which, 0) &&
+		odr_constructed_end (o)) || odr_ok(o)) &&
+		odr_explicit_tag (o, z_PQSPeriod,
+			&(*p)->originSuggestedPeriod, ODR_CONTEXT, 2, 1, "originSuggestedPeriod") &&
+		odr_implicit_tag (o, odr_generalizedtime,
+			&(*p)->expiration, ODR_CONTEXT, 3, 1, "expiration") &&
+		odr_implicit_tag (o, z_InternationalString,
+			&(*p)->resultSetPackage, ODR_CONTEXT, 4, 1, "resultSetPackage") &&
+		odr_sequence_end (o);
+}
+
+int z_PQSTargetPart (ODR o, Z_PQSTargetPart **p, int opt, const char *name)
+{
+	if (!odr_sequence_begin (o, p, sizeof(**p), name))
+		return opt && odr_ok (o);
+	return
+		odr_explicit_tag (o, z_Query,
+			&(*p)->actualQuery, ODR_CONTEXT, 1, 0, "actualQuery") &&
+		odr_explicit_tag (o, z_PQSPeriod,
+			&(*p)->targetStatedPeriod, ODR_CONTEXT, 2, 0, "targetStatedPeriod") &&
+		odr_implicit_tag (o, odr_generalizedtime,
+			&(*p)->expiration, ODR_CONTEXT, 3, 1, "expiration") &&
+		odr_implicit_tag (o, z_InternationalString,
+			&(*p)->resultSetPackage, ODR_CONTEXT, 4, 1, "resultSetPackage") &&
+		odr_implicit_tag (o, odr_generalizedtime,
+			&(*p)->lastQueryTime, ODR_CONTEXT, 5, 0, "lastQueryTime") &&
+		odr_implicit_tag (o, odr_integer,
+			&(*p)->lastResultNumber, ODR_CONTEXT, 6, 0, "lastResultNumber") &&
+		odr_implicit_tag (o, odr_integer,
+			&(*p)->numberSinceModify, ODR_CONTEXT, 7, 1, "numberSinceModify") &&
+		odr_sequence_end (o);
+}
+
+int z_PQSPeriod (ODR o, Z_PQSPeriod **p, int opt, const char *name)
+{
+	static Odr_arm arm[] = {
+		{ODR_IMPLICIT, ODR_CONTEXT, 1, Z_PQSPeriod_unit,
+		(Odr_fun) z_IntUnit, "unit"},
+		{ODR_IMPLICIT, ODR_CONTEXT, 2, Z_PQSPeriod_businessDaily,
+		(Odr_fun) odr_null, "businessDaily"},
+		{ODR_IMPLICIT, ODR_CONTEXT, 3, Z_PQSPeriod_continuous,
+		(Odr_fun) odr_null, "continuous"},
+		{ODR_IMPLICIT, ODR_CONTEXT, 4, Z_PQSPeriod_other,
+		(Odr_fun) z_InternationalString, "other"},
+		{-1, -1, -1, -1, (Odr_fun) 0, 0}
+	};
+	if (!odr_initmember(o, p, sizeof(**p)))
+		return opt && odr_ok(o);
+	if (odr_choice(o, arm, &(*p)->u, &(*p)->which, name))
+		return 1;
+	*p = 0;
+	return opt && odr_ok(o);
+}
Index: /main/tags/2.25/gsdl/packages/yaz/z39.50/zes-pset.c
===================================================================
--- /main/tags/2.25/gsdl/packages/yaz/z39.50/zes-pset.c	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/yaz/z39.50/zes-pset.c	(revision 21064)
@@ -0,0 +1,69 @@
+/* Generated automatically by the YAZ ASN.1 Compiler 0.3 */
+/* Module-C: ESFormat-PersistentResultSet */
+
+#include <yaz/zes-pset.h>
+
+int z_PRPersistentResultSetEsRequest (ODR o, Z_PRPersistentResultSetEsRequest **p, int opt, const char *name)
+{
+	if (!odr_sequence_begin (o, p, sizeof(**p), name))
+		return opt && odr_ok (o);
+	return
+		odr_implicit_tag (o, odr_null,
+			&(*p)->toKeep, ODR_CONTEXT, 1, 0, "toKeep") &&
+		odr_explicit_tag (o, z_PROriginPartNotToKeep,
+			&(*p)->notToKeep, ODR_CONTEXT, 2, 1, "notToKeep") &&
+		odr_sequence_end (o);
+}
+
+int z_PRPersistentResultSetTaskPackage (ODR o, Z_PRPersistentResultSetTaskPackage **p, int opt, const char *name)
+{
+	if (!odr_sequence_begin (o, p, sizeof(**p), name))
+		return opt && odr_ok (o);
+	return
+		odr_implicit_tag (o, odr_null,
+			&(*p)->originPart, ODR_CONTEXT, 1, 0, "originPart") &&
+		odr_explicit_tag (o, z_PRTargetPart,
+			&(*p)->targetPart, ODR_CONTEXT, 2, 1, "targetPart") &&
+		odr_sequence_end (o);
+}
+
+int z_PRPersistentResultSet (ODR o, Z_PRPersistentResultSet **p, int opt, const char *name)
+{
+	static Odr_arm arm[] = {
+		{ODR_IMPLICIT, ODR_CONTEXT, 1, Z_PRPersistentResultSet_esRequest,
+		(Odr_fun) z_PRPersistentResultSetEsRequest, "esRequest"},
+		{ODR_IMPLICIT, ODR_CONTEXT, 2, Z_PRPersistentResultSet_taskPackage,
+		(Odr_fun) z_PRPersistentResultSetTaskPackage, "taskPackage"},
+		{-1, -1, -1, -1, (Odr_fun) 0, 0}
+	};
+	if (!odr_initmember(o, p, sizeof(**p)))
+		return opt && odr_ok(o);
+	if (odr_choice(o, arm, &(*p)->u, &(*p)->which, name))
+		return 1;
+	*p = 0;
+	return opt && odr_ok(o);
+}
+
+int z_PROriginPartNotToKeep (ODR o, Z_PROriginPartNotToKeep **p, int opt, const char *name)
+{
+	if (!odr_sequence_begin (o, p, sizeof(**p), name))
+		return opt && odr_ok (o);
+	return
+		odr_implicit_tag (o, z_InternationalString,
+			&(*p)->originSuppliedResultSet, ODR_CONTEXT, 1, 1, "originSuppliedResultSet") &&
+		odr_implicit_tag (o, odr_integer,
+			&(*p)->replaceOrAppend, ODR_CONTEXT, 2, 1, "replaceOrAppend") &&
+		odr_sequence_end (o);
+}
+
+int z_PRTargetPart (ODR o, Z_PRTargetPart **p, int opt, const char *name)
+{
+	if (!odr_sequence_begin (o, p, sizeof(**p), name))
+		return opt && odr_ok (o);
+	return
+		odr_implicit_tag (o, z_InternationalString,
+			&(*p)->targetSuppliedResultSet, ODR_CONTEXT, 1, 1, "targetSuppliedResultSet") &&
+		odr_implicit_tag (o, odr_integer,
+			&(*p)->numberOfRecords, ODR_CONTEXT, 2, 1, "numberOfRecords") &&
+		odr_sequence_end (o);
+}
Index: /main/tags/2.25/gsdl/packages/yaz/z39.50/zes-update.c
===================================================================
--- /main/tags/2.25/gsdl/packages/yaz/z39.50/zes-update.c	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/yaz/z39.50/zes-update.c	(revision 21064)
@@ -0,0 +1,188 @@
+/* Generated automatically by the YAZ ASN.1 Compiler 0.3 */
+/* Module-C: ESFormat-Update */
+
+#include <yaz/zes-update.h>
+
+int z_IUUpdateEsRequest (ODR o, Z_IUUpdateEsRequest **p, int opt, const char *name)
+{
+	if (!odr_sequence_begin (o, p, sizeof(**p), name))
+		return opt && odr_ok (o);
+	return
+		odr_explicit_tag (o, z_IUOriginPartToKeep,
+			&(*p)->toKeep, ODR_CONTEXT, 1, 0, "toKeep") &&
+		odr_explicit_tag (o, z_IUOriginPartNotToKeep,
+			&(*p)->notToKeep, ODR_CONTEXT, 2, 0, "notToKeep") &&
+		odr_sequence_end (o);
+}
+
+int z_IUUpdateTaskPackage (ODR o, Z_IUUpdateTaskPackage **p, int opt, const char *name)
+{
+	if (!odr_sequence_begin (o, p, sizeof(**p), name))
+		return opt && odr_ok (o);
+	return
+		odr_explicit_tag (o, z_IUOriginPartToKeep,
+			&(*p)->originPart, ODR_CONTEXT, 1, 0, "originPart") &&
+		odr_explicit_tag (o, z_IUTargetPart,
+			&(*p)->targetPart, ODR_CONTEXT, 2, 0, "targetPart") &&
+		odr_sequence_end (o);
+}
+
+int z_IUUpdate (ODR o, Z_IUUpdate **p, int opt, const char *name)
+{
+	static Odr_arm arm[] = {
+		{ODR_IMPLICIT, ODR_CONTEXT, 1, Z_IUUpdate_esRequest,
+		(Odr_fun) z_IUUpdateEsRequest, "esRequest"},
+		{ODR_IMPLICIT, ODR_CONTEXT, 2, Z_IUUpdate_taskPackage,
+		(Odr_fun) z_IUUpdateTaskPackage, "taskPackage"},
+		{-1, -1, -1, -1, (Odr_fun) 0, 0}
+	};
+	if (!odr_initmember(o, p, sizeof(**p)))
+		return opt && odr_ok(o);
+	if (odr_choice(o, arm, &(*p)->u, &(*p)->which, name))
+		return 1;
+	*p = 0;
+	return opt && odr_ok(o);
+}
+
+int z_IUOriginPartToKeep (ODR o, Z_IUOriginPartToKeep **p, int opt, const char *name)
+{
+	if (!odr_sequence_begin (o, p, sizeof(**p), name))
+		return opt && odr_ok (o);
+	return
+		odr_implicit_tag (o, odr_integer,
+			&(*p)->action, ODR_CONTEXT, 1, 0, "action") &&
+		odr_implicit_tag (o, z_InternationalString,
+			&(*p)->databaseName, ODR_CONTEXT, 2, 0, "databaseName") &&
+		odr_implicit_tag (o, odr_oid,
+			&(*p)->schema, ODR_CONTEXT, 3, 1, "schema") &&
+		odr_implicit_tag (o, z_InternationalString,
+			&(*p)->elementSetName, ODR_CONTEXT, 4, 1, "elementSetName") &&
+		odr_implicit_tag (o, z_External,
+			&(*p)->actionQualifier, ODR_CONTEXT, 5, 1, "actionQualifier") &&
+		odr_sequence_end (o);
+}
+
+int z_IUOriginPartNotToKeep (ODR o, Z_IUOriginPartNotToKeep **p, int opt, const char *name)
+{
+	return z_IUSuppliedRecords (o, p, opt, name);
+}
+
+int z_IUTargetPart (ODR o, Z_IUTargetPart **p, int opt, const char *name)
+{
+	if (!odr_sequence_begin (o, p, sizeof(**p), name))
+		return opt && odr_ok (o);
+	return
+		odr_implicit_tag (o, odr_integer,
+			&(*p)->updateStatus, ODR_CONTEXT, 1, 0, "updateStatus") &&
+		odr_implicit_settag (o, ODR_CONTEXT, 2) &&
+		(odr_sequence_of(o, (Odr_fun) z_DiagRec, &(*p)->globalDiagnostics,
+		  &(*p)->num_globalDiagnostics, "globalDiagnostics") || odr_ok(o)) &&
+		odr_implicit_settag (o, ODR_CONTEXT, 3) &&
+		odr_sequence_of(o, (Odr_fun) z_IUTaskPackageRecordStructure, &(*p)->taskPackageRecords,
+		  &(*p)->num_taskPackageRecords, "taskPackageRecords") &&
+		odr_sequence_end (o);
+}
+
+int z_IUSuppliedRecordsId (ODR o, Z_IUSuppliedRecordsId **p, int opt, const char *name)
+{
+	static Odr_arm arm[] = {
+		{ODR_IMPLICIT, ODR_CONTEXT, 1, Z_IUSuppliedRecordsId_timeStamp,
+		(Odr_fun) odr_generalizedtime, "timeStamp"},
+		{ODR_IMPLICIT, ODR_CONTEXT, 2, Z_IUSuppliedRecordsId_versionNumber,
+		(Odr_fun) z_InternationalString, "versionNumber"},
+		{ODR_IMPLICIT, ODR_CONTEXT, 3, Z_IUSuppliedRecordsId_previousVersion,
+		(Odr_fun) z_External, "previousVersion"},
+		{-1, -1, -1, -1, (Odr_fun) 0, 0}
+	};
+	if (!odr_initmember(o, p, sizeof(**p)))
+		return opt && odr_ok(o);
+	if (odr_choice(o, arm, &(*p)->u, &(*p)->which, name))
+		return 1;
+	*p = 0;
+	return opt && odr_ok(o);
+}
+
+int z_IUSuppliedRecords_elem (ODR o, Z_IUSuppliedRecords_elem **p, int opt, const char *name)
+{
+	static Odr_arm arm[] = {
+		{ODR_IMPLICIT, ODR_CONTEXT, 1, Z_IUSuppliedRecords_elem_number,
+		(Odr_fun) odr_integer, "number"},
+		{ODR_IMPLICIT, ODR_CONTEXT, 2, Z_IUSuppliedRecords_elem_string,
+		(Odr_fun) z_InternationalString, "string"},
+		{ODR_IMPLICIT, ODR_CONTEXT, 3, Z_IUSuppliedRecords_elem_opaque,
+		(Odr_fun) odr_octetstring, "opaque"},
+		{-1, -1, -1, -1, (Odr_fun) 0, 0}
+	};
+	if (!odr_sequence_begin (o, p, sizeof(**p), name))
+		return opt && odr_ok (o);
+	return
+		((odr_constructed_begin (o, &(*p)->u, ODR_CONTEXT, 1, "recordId") &&
+		odr_choice (o, arm, &(*p)->u, &(*p)->which, 0) &&
+		odr_constructed_end (o)) || odr_ok(o)) &&
+		odr_explicit_tag (o, z_IUSuppliedRecordsId,
+			&(*p)->supplementalId, ODR_CONTEXT, 2, 1, "supplementalId") &&
+		odr_implicit_tag (o, z_IUCorrelationInfo,
+			&(*p)->correlationInfo, ODR_CONTEXT, 3, 1, "correlationInfo") &&
+		odr_implicit_tag (o, z_External,
+			&(*p)->record, ODR_CONTEXT, 4, 0, "record") &&
+		odr_sequence_end (o);
+}
+
+int z_IUSuppliedRecords (ODR o, Z_IUSuppliedRecords **p, int opt, const char *name)
+{
+	if (!odr_initmember (o, p, sizeof(**p)))
+		return opt && odr_ok(o);
+	if (odr_sequence_of (o, (Odr_fun) z_IUSuppliedRecords_elem, &(*p)->elements,
+		&(*p)->num, name))
+		return 1;
+	*p = 0;
+	return opt && odr_ok(o);
+}
+
+int z_IUCorrelationInfo (ODR o, Z_IUCorrelationInfo **p, int opt, const char *name)
+{
+	if (!odr_sequence_begin (o, p, sizeof(**p), name))
+		return opt && odr_ok (o);
+	return
+		odr_implicit_tag (o, z_InternationalString,
+			&(*p)->note, ODR_CONTEXT, 1, 1, "note") &&
+		odr_implicit_tag (o, odr_integer,
+			&(*p)->id, ODR_CONTEXT, 2, 1, "id") &&
+		odr_sequence_end (o);
+}
+
+int z_IUTaskPackageRecordStructureSurrogateDiagnostics (ODR o, Z_IUTaskPackageRecordStructureSurrogateDiagnostics **p, int opt, const char *name)
+{
+	if (!odr_initmember (o, p, sizeof(**p)))
+		return opt && odr_ok(o);
+	if (odr_sequence_of (o, (Odr_fun) z_DiagRec, &(*p)->elements,
+		&(*p)->num, name))
+		return 1;
+	*p = 0;
+	return opt && odr_ok(o);
+}
+
+int z_IUTaskPackageRecordStructure (ODR o, Z_IUTaskPackageRecordStructure **p, int opt, const char *name)
+{
+	static Odr_arm arm[] = {
+		{ODR_IMPLICIT, ODR_CONTEXT, 1, Z_IUTaskPackageRecordStructure_record,
+		(Odr_fun) z_External, "record"},
+		{ODR_IMPLICIT, ODR_CONTEXT, 2, Z_IUTaskPackageRecordStructure_surrogateDiagnostics,
+		(Odr_fun) z_IUTaskPackageRecordStructureSurrogateDiagnostics, "surrogateDiagnostics"},
+		{-1, -1, -1, -1, (Odr_fun) 0, 0}
+	};
+	if (!odr_sequence_begin (o, p, sizeof(**p), name))
+		return opt && odr_ok (o);
+	return
+		((odr_constructed_begin (o, &(*p)->u, ODR_CONTEXT, 1, "recordOrSurDiag") &&
+		odr_choice (o, arm, &(*p)->u, &(*p)->which, 0) &&
+		odr_constructed_end (o)) || odr_ok(o)) &&
+		odr_implicit_tag (o, z_IUCorrelationInfo,
+			&(*p)->correlationInfo, ODR_CONTEXT, 2, 1, "correlationInfo") &&
+		odr_implicit_tag (o, odr_integer,
+			&(*p)->recordStatus, ODR_CONTEXT, 3, 0, "recordStatus") &&
+		odr_implicit_settag (o, ODR_CONTEXT, 4) &&
+		(odr_sequence_of(o, (Odr_fun) z_DiagRec, &(*p)->supplementalDiagnostics,
+		  &(*p)->num_supplementalDiagnostics, "supplementalDiagnostics") || odr_ok(o)) &&
+		odr_sequence_end (o);
+}
Index: /main/tags/2.25/gsdl/packages/yaz/z39.50/zes-update0.c
===================================================================
--- /main/tags/2.25/gsdl/packages/yaz/z39.50/zes-update0.c	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/yaz/z39.50/zes-update0.c	(revision 21064)
@@ -0,0 +1,172 @@
+/* Generated automatically by the YAZ ASN.1 Compiler 0.3 */
+/* Module-C: ESFormat-Update0 */
+
+#include <yaz/zes-update0.h>
+
+int z_IU0UpdateEsRequest (ODR o, Z_IU0UpdateEsRequest **p, int opt, const char *name)
+{
+	if (!odr_sequence_begin (o, p, sizeof(**p), name))
+		return opt && odr_ok (o);
+	return
+		odr_explicit_tag (o, z_IU0OriginPartToKeep,
+			&(*p)->toKeep, ODR_CONTEXT, 1, 0, "toKeep") &&
+		odr_explicit_tag (o, z_IU0OriginPartNotToKeep,
+			&(*p)->notToKeep, ODR_CONTEXT, 2, 0, "notToKeep") &&
+		odr_sequence_end (o);
+}
+
+int z_IU0UpdateTaskPackage (ODR o, Z_IU0UpdateTaskPackage **p, int opt, const char *name)
+{
+	if (!odr_sequence_begin (o, p, sizeof(**p), name))
+		return opt && odr_ok (o);
+	return
+		odr_explicit_tag (o, z_IU0OriginPartToKeep,
+			&(*p)->originPart, ODR_CONTEXT, 1, 0, "originPart") &&
+		odr_explicit_tag (o, z_IU0TargetPart,
+			&(*p)->targetPart, ODR_CONTEXT, 2, 0, "targetPart") &&
+		odr_sequence_end (o);
+}
+
+int z_IU0Update (ODR o, Z_IU0Update **p, int opt, const char *name)
+{
+	static Odr_arm arm[] = {
+		{ODR_IMPLICIT, ODR_CONTEXT, 1, Z_IU0Update_esRequest,
+		(Odr_fun) z_IU0UpdateEsRequest, "esRequest"},
+		{ODR_IMPLICIT, ODR_CONTEXT, 2, Z_IU0Update_taskPackage,
+		(Odr_fun) z_IU0UpdateTaskPackage, "taskPackage"},
+		{-1, -1, -1, -1, (Odr_fun) 0, 0}
+	};
+	if (!odr_initmember(o, p, sizeof(**p)))
+		return opt && odr_ok(o);
+	if (odr_choice(o, arm, &(*p)->u, &(*p)->which, name))
+		return 1;
+	*p = 0;
+	return opt && odr_ok(o);
+}
+
+int z_IU0OriginPartToKeep (ODR o, Z_IU0OriginPartToKeep **p, int opt, const char *name)
+{
+	if (!odr_sequence_begin (o, p, sizeof(**p), name))
+		return opt && odr_ok (o);
+	return
+		odr_implicit_tag (o, odr_integer,
+			&(*p)->action, ODR_CONTEXT, 1, 0, "action") &&
+		odr_implicit_tag (o, z_InternationalString,
+			&(*p)->databaseName, ODR_CONTEXT, 2, 0, "databaseName") &&
+		odr_implicit_tag (o, odr_oid,
+			&(*p)->schema, ODR_CONTEXT, 3, 1, "schema") &&
+		odr_implicit_tag (o, z_InternationalString,
+			&(*p)->elementSetName, ODR_CONTEXT, 4, 1, "elementSetName") &&
+		odr_sequence_end (o);
+}
+
+int z_IU0OriginPartNotToKeep (ODR o, Z_IU0OriginPartNotToKeep **p, int opt, const char *name)
+{
+	return z_IU0SuppliedRecords (o, p, opt, name);
+}
+
+int z_IU0TargetPart (ODR o, Z_IU0TargetPart **p, int opt, const char *name)
+{
+	if (!odr_sequence_begin (o, p, sizeof(**p), name))
+		return opt && odr_ok (o);
+	return
+		odr_implicit_tag (o, odr_integer,
+			&(*p)->updateStatus, ODR_CONTEXT, 1, 0, "updateStatus") &&
+		odr_implicit_settag (o, ODR_CONTEXT, 2) &&
+		(odr_sequence_of(o, (Odr_fun) z_DiagRec, &(*p)->globalDiagnostics,
+		  &(*p)->num_globalDiagnostics, "globalDiagnostics") || odr_ok(o)) &&
+		odr_implicit_settag (o, ODR_CONTEXT, 3) &&
+		odr_sequence_of(o, (Odr_fun) z_IU0TaskPackageRecordStructure, &(*p)->taskPackageRecords,
+		  &(*p)->num_taskPackageRecords, "taskPackageRecords") &&
+		odr_sequence_end (o);
+}
+
+int z_IU0SuppliedRecordsId (ODR o, Z_IU0SuppliedRecordsId **p, int opt, const char *name)
+{
+	static Odr_arm arm[] = {
+		{ODR_IMPLICIT, ODR_CONTEXT, 1, Z_IU0SuppliedRecordsId_timeStamp,
+		(Odr_fun) odr_generalizedtime, "timeStamp"},
+		{ODR_IMPLICIT, ODR_CONTEXT, 2, Z_IU0SuppliedRecordsId_versionNumber,
+		(Odr_fun) z_InternationalString, "versionNumber"},
+		{ODR_IMPLICIT, ODR_CONTEXT, 3, Z_IU0SuppliedRecordsId_previousVersion,
+		(Odr_fun) z_External, "previousVersion"},
+		{-1, -1, -1, -1, (Odr_fun) 0, 0}
+	};
+	if (!odr_initmember(o, p, sizeof(**p)))
+		return opt && odr_ok(o);
+	if (odr_choice(o, arm, &(*p)->u, &(*p)->which, name))
+		return 1;
+	*p = 0;
+	return opt && odr_ok(o);
+}
+
+int z_IU0SuppliedRecords_elem (ODR o, Z_IU0SuppliedRecords_elem **p, int opt, const char *name)
+{
+	static Odr_arm arm[] = {
+		{ODR_IMPLICIT, ODR_CONTEXT, 1, Z_IU0SuppliedRecords_elem_number,
+		(Odr_fun) odr_integer, "number"},
+		{ODR_IMPLICIT, ODR_CONTEXT, 2, Z_IU0SuppliedRecords_elem_string,
+		(Odr_fun) z_InternationalString, "string"},
+		{ODR_IMPLICIT, ODR_CONTEXT, 3, Z_IU0SuppliedRecords_elem_opaque,
+		(Odr_fun) odr_octetstring, "opaque"},
+		{-1, -1, -1, -1, (Odr_fun) 0, 0}
+	};
+	if (!odr_sequence_begin (o, p, sizeof(**p), name))
+		return opt && odr_ok (o);
+	return
+		((odr_constructed_begin (o, &(*p)->u, ODR_CONTEXT, 1, "recordId") &&
+		odr_choice (o, arm, &(*p)->u, &(*p)->which, 0) &&
+		odr_constructed_end (o)) || odr_ok(o)) &&
+		odr_explicit_tag (o, z_IU0SuppliedRecordsId,
+			&(*p)->supplementalId, ODR_CONTEXT, 2, 1, "supplementalId") &&
+		odr_implicit_tag (o, z_IU0CorrelationInfo,
+			&(*p)->correlationInfo, ODR_CONTEXT, 3, 1, "correlationInfo") &&
+		odr_implicit_tag (o, z_External,
+			&(*p)->record, ODR_CONTEXT, 4, 0, "record") &&
+		odr_sequence_end (o);
+}
+
+int z_IU0SuppliedRecords (ODR o, Z_IU0SuppliedRecords **p, int opt, const char *name)
+{
+	if (!odr_initmember (o, p, sizeof(**p)))
+		return opt && odr_ok(o);
+	if (odr_sequence_of (o, (Odr_fun) z_IU0SuppliedRecords_elem, &(*p)->elements,
+		&(*p)->num, name))
+		return 1;
+	*p = 0;
+	return opt && odr_ok(o);
+}
+
+int z_IU0CorrelationInfo (ODR o, Z_IU0CorrelationInfo **p, int opt, const char *name)
+{
+	if (!odr_sequence_begin (o, p, sizeof(**p), name))
+		return opt && odr_ok (o);
+	return
+		odr_implicit_tag (o, z_InternationalString,
+			&(*p)->note, ODR_CONTEXT, 1, 1, "note") &&
+		odr_implicit_tag (o, odr_integer,
+			&(*p)->id, ODR_CONTEXT, 2, 1, "id") &&
+		odr_sequence_end (o);
+}
+
+int z_IU0TaskPackageRecordStructure (ODR o, Z_IU0TaskPackageRecordStructure **p, int opt, const char *name)
+{
+	static Odr_arm arm[] = {
+		{ODR_IMPLICIT, ODR_CONTEXT, 1, Z_IU0TaskPackageRecordStructure_record,
+		(Odr_fun) z_External, "record"},
+		{ODR_EXPLICIT, ODR_CONTEXT, 2, Z_IU0TaskPackageRecordStructure_diagnostic,
+		(Odr_fun) z_DiagRec, "diagnostic"},
+		{-1, -1, -1, -1, (Odr_fun) 0, 0}
+	};
+	if (!odr_sequence_begin (o, p, sizeof(**p), name))
+		return opt && odr_ok (o);
+	return
+		((odr_constructed_begin (o, &(*p)->u, ODR_CONTEXT, 1, "recordOrSurDiag") &&
+		odr_choice (o, arm, &(*p)->u, &(*p)->which, 0) &&
+		odr_constructed_end (o)) || odr_ok(o)) &&
+		odr_implicit_tag (o, z_IU0CorrelationInfo,
+			&(*p)->correlationInfo, ODR_CONTEXT, 2, 1, "correlationInfo") &&
+		odr_implicit_tag (o, odr_integer,
+			&(*p)->recordStatus, ODR_CONTEXT, 3, 0, "recordStatus") &&
+		odr_sequence_end (o);
+}
Index: /main/tags/2.25/gsdl/packages/yaz/ztest/Makefile.am
===================================================================
--- /main/tags/2.25/gsdl/packages/yaz/ztest/Makefile.am	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/yaz/ztest/Makefile.am	(revision 21064)
@@ -0,0 +1,12 @@
+## $Id$
+
+bin_PROGRAMS=yaz-ztest
+
+yaz_ztest_SOURCES=ztest.c read-grs.c
+
+EXTRA_DIST=dummy-records dummy-words dummy-grs
+
+INCLUDES=-I../include
+
+LDADD=../lib/libyaz.a
+
Index: /main/tags/2.25/gsdl/packages/yaz/ztest/Makefile.in
===================================================================
--- /main/tags/2.25/gsdl/packages/yaz/ztest/Makefile.in	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/yaz/ztest/Makefile.in	(revision 21064)
@@ -0,0 +1,287 @@
+# Makefile.in generated automatically by automake 1.4 from Makefile.am
+
+# Copyright (C) 1994, 1995-8, 1999 Free Software Foundation, Inc.
+# This Makefile.in is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
+# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE.
+
+
+SHELL = @SHELL@
+
+srcdir = @srcdir@
+top_srcdir = @top_srcdir@
+VPATH = @srcdir@
+prefix = @prefix@
+exec_prefix = @exec_prefix@
+
+bindir = @bindir@
+sbindir = @sbindir@
+libexecdir = @libexecdir@
+datadir = @datadir@
+sysconfdir = @sysconfdir@
+sharedstatedir = @sharedstatedir@
+localstatedir = @localstatedir@
+libdir = @libdir@
+infodir = @infodir@
+mandir = @mandir@
+includedir = @includedir@
+oldincludedir = /usr/include
+
+DESTDIR =
+
+pkgdatadir = $(datadir)/@PACKAGE@
+pkglibdir = $(libdir)/@PACKAGE@
+pkgincludedir = $(includedir)/@PACKAGE@
+
+top_builddir = ..
+
+ACLOCAL = @ACLOCAL@
+AUTOCONF = @AUTOCONF@
+AUTOMAKE = @AUTOMAKE@
+AUTOHEADER = @AUTOHEADER@
+
+INSTALL = @INSTALL@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@ $(AM_INSTALL_PROGRAM_FLAGS)
+INSTALL_DATA = @INSTALL_DATA@
+INSTALL_SCRIPT = @INSTALL_SCRIPT@
+transform = @program_transform_name@
+
+NORMAL_INSTALL = :
+PRE_INSTALL = :
+POST_INSTALL = :
+NORMAL_UNINSTALL = :
+PRE_UNINSTALL = :
+POST_UNINSTALL = :
+ASNMODULE = @ASNMODULE@
+CC = @CC@
+CPP = @CPP@
+ILLLIB = @ILLLIB@
+ILLMODULE = @ILLMODULE@
+MAKEINFO = @MAKEINFO@
+PACKAGE = @PACKAGE@
+RANLIB = @RANLIB@
+SUBDIRS_VAR = @SUBDIRS_VAR@
+VERSION = @VERSION@
+have_sgml2html = @have_sgml2html@
+have_sgml2latex = @have_sgml2latex@
+have_sgml2txt = @have_sgml2txt@
+
+bin_PROGRAMS = yaz-ztest
+
+yaz_ztest_SOURCES = ztest.c read-grs.c
+
+EXTRA_DIST = dummy-records dummy-words dummy-grs
+
+INCLUDES = -I../include
+
+LDADD = ../lib/libyaz.a
+mkinstalldirs = $(SHELL) $(top_srcdir)/mkinstalldirs
+CONFIG_CLEAN_FILES = 
+PROGRAMS =  $(bin_PROGRAMS)
+
+
+DEFS = @DEFS@ -I. -I$(srcdir) 
+CPPFLAGS = @CPPFLAGS@
+LDFLAGS = @LDFLAGS@
+LIBS = @LIBS@
+yaz_ztest_OBJECTS =  ztest.o read-grs.o
+yaz_ztest_LDADD = $(LDADD)
+yaz_ztest_DEPENDENCIES =  ../lib/libyaz.a
+yaz_ztest_LDFLAGS = 
+CFLAGS = @CFLAGS@
+COMPILE = $(CC) $(DEFS) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
+CCLD = $(CC)
+LINK = $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(LDFLAGS) -o $@
+DIST_COMMON =  Makefile.am Makefile.in
+
+
+DISTFILES = $(DIST_COMMON) $(SOURCES) $(HEADERS) $(TEXINFOS) $(EXTRA_DIST)
+
+TAR = gtar
+GZIP_ENV = --best
+SOURCES = $(yaz_ztest_SOURCES)
+OBJECTS = $(yaz_ztest_OBJECTS)
+
+all: all-redirect
+.SUFFIXES:
+.SUFFIXES: .S .c .o .s
+$(srcdir)/Makefile.in: Makefile.am $(top_srcdir)/configure.in $(ACLOCAL_M4) 
+	cd $(top_srcdir) && $(AUTOMAKE) --gnu --include-deps ztest/Makefile
+
+Makefile: $(srcdir)/Makefile.in  $(top_builddir)/config.status
+	cd $(top_builddir) \
+	  && CONFIG_FILES=$(subdir)/$@ CONFIG_HEADERS= $(SHELL) ./config.status
+
+
+mostlyclean-binPROGRAMS:
+
+clean-binPROGRAMS:
+	-test -z "$(bin_PROGRAMS)" || rm -f $(bin_PROGRAMS)
+
+distclean-binPROGRAMS:
+
+maintainer-clean-binPROGRAMS:
+
+install-binPROGRAMS: $(bin_PROGRAMS)
+	@$(NORMAL_INSTALL)
+	$(mkinstalldirs) $(DESTDIR)$(bindir)
+	@list='$(bin_PROGRAMS)'; for p in $$list; do \
+	  if test -f $$p; then \
+	    echo "  $(INSTALL_PROGRAM) $$p $(DESTDIR)$(bindir)/`echo $$p|sed 's/$(EXEEXT)$$//'|sed '$(transform)'|sed 's/$$/$(EXEEXT)/'`"; \
+	     $(INSTALL_PROGRAM) $$p $(DESTDIR)$(bindir)/`echo $$p|sed 's/$(EXEEXT)$$//'|sed '$(transform)'|sed 's/$$/$(EXEEXT)/'`; \
+	  else :; fi; \
+	done
+
+uninstall-binPROGRAMS:
+	@$(NORMAL_UNINSTALL)
+	list='$(bin_PROGRAMS)'; for p in $$list; do \
+	  rm -f $(DESTDIR)$(bindir)/`echo $$p|sed 's/$(EXEEXT)$$//'|sed '$(transform)'|sed 's/$$/$(EXEEXT)/'`; \
+	done
+
+.c.o:
+	$(COMPILE) -c $<
+
+.s.o:
+	$(COMPILE) -c $<
+
+.S.o:
+	$(COMPILE) -c $<
+
+mostlyclean-compile:
+	-rm -f *.o core *.core
+
+clean-compile:
+
+distclean-compile:
+	-rm -f *.tab.c
+
+maintainer-clean-compile:
+
+yaz-ztest: $(yaz_ztest_OBJECTS) $(yaz_ztest_DEPENDENCIES)
+	@rm -f yaz-ztest
+	$(LINK) $(yaz_ztest_LDFLAGS) $(yaz_ztest_OBJECTS) $(yaz_ztest_LDADD) $(LIBS)
+
+tags: TAGS
+
+ID: $(HEADERS) $(SOURCES) $(LISP)
+	list='$(SOURCES) $(HEADERS)'; \
+	unique=`for i in $$list; do echo $$i; done | \
+	  awk '    { files[$$0] = 1; } \
+	       END { for (i in files) print i; }'`; \
+	here=`pwd` && cd $(srcdir) \
+	  && mkid -f$$here/ID $$unique $(LISP)
+
+TAGS:  $(HEADERS) $(SOURCES)  $(TAGS_DEPENDENCIES) $(LISP)
+	tags=; \
+	here=`pwd`; \
+	list='$(SOURCES) $(HEADERS)'; \
+	unique=`for i in $$list; do echo $$i; done | \
+	  awk '    { files[$$0] = 1; } \
+	       END { for (i in files) print i; }'`; \
+	test -z "$(ETAGS_ARGS)$$unique$(LISP)$$tags" \
+	  || (cd $(srcdir) && etags $(ETAGS_ARGS) $$tags  $$unique $(LISP) -o $$here/TAGS)
+
+mostlyclean-tags:
+
+clean-tags:
+
+distclean-tags:
+	-rm -f TAGS ID
+
+maintainer-clean-tags:
+
+distdir = $(top_builddir)/$(PACKAGE)-$(VERSION)/$(subdir)
+
+subdir = ztest
+
+distdir: $(DISTFILES)
+	@for file in $(DISTFILES); do \
+	  d=$(srcdir); \
+	  if test -d $$d/$$file; then \
+	    cp -pr $$/$$file $(distdir)/$$file; \
+	  else \
+	    test -f $(distdir)/$$file \
+	    || ln $$d/$$file $(distdir)/$$file 2> /dev/null \
+	    || cp -p $$d/$$file $(distdir)/$$file || :; \
+	  fi; \
+	done
+
+info-am:
+info: info-am
+dvi-am:
+dvi: dvi-am
+check-am: all-am
+check: check-am
+installcheck-am:
+installcheck: installcheck-am
+install-exec-am: install-binPROGRAMS
+install-exec: install-exec-am
+
+install-data-am:
+install-data: install-data-am
+
+install-am: all-am
+	@$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
+install: install-am
+uninstall-am: uninstall-binPROGRAMS
+uninstall: uninstall-am
+all-am: Makefile $(PROGRAMS)
+all-redirect: all-am
+install-strip:
+	$(MAKE) $(AM_MAKEFLAGS) AM_INSTALL_PROGRAM_FLAGS=-s install
+installdirs:
+	$(mkinstalldirs)  $(DESTDIR)$(bindir)
+
+
+mostlyclean-generic:
+
+clean-generic:
+
+distclean-generic:
+	-rm -f Makefile $(CONFIG_CLEAN_FILES)
+	-rm -f config.cache config.log stamp-h stamp-h[0-9]*
+
+maintainer-clean-generic:
+mostlyclean-am:  mostlyclean-binPROGRAMS mostlyclean-compile \
+		mostlyclean-tags mostlyclean-generic
+
+mostlyclean: mostlyclean-am
+
+clean-am:  clean-binPROGRAMS clean-compile clean-tags clean-generic \
+		mostlyclean-am
+
+clean: clean-am
+
+distclean-am:  distclean-binPROGRAMS distclean-compile distclean-tags \
+		distclean-generic clean-am
+
+distclean: distclean-am
+
+maintainer-clean-am:  maintainer-clean-binPROGRAMS \
+		maintainer-clean-compile maintainer-clean-tags \
+		maintainer-clean-generic distclean-am
+	@echo "This command is intended for maintainers to use;"
+	@echo "it deletes files that may require special tools to rebuild."
+
+maintainer-clean: maintainer-clean-am
+
+.PHONY: mostlyclean-binPROGRAMS distclean-binPROGRAMS clean-binPROGRAMS \
+maintainer-clean-binPROGRAMS uninstall-binPROGRAMS install-binPROGRAMS \
+mostlyclean-compile distclean-compile clean-compile \
+maintainer-clean-compile tags mostlyclean-tags distclean-tags \
+clean-tags maintainer-clean-tags distdir info-am info dvi-am dvi check \
+check-am installcheck-am installcheck install-exec-am install-exec \
+install-data-am install-data install-am install uninstall-am uninstall \
+all-redirect all-am all installdirs mostlyclean-generic \
+distclean-generic clean-generic maintainer-clean-generic clean \
+mostlyclean distclean maintainer-clean
+
+
+# Tell versions [3.59,3.63) of GNU make to not export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:
Index: /main/tags/2.25/gsdl/packages/yaz/ztest/dummy-grs
===================================================================
--- /main/tags/2.25/gsdl/packages/yaz/ztest/dummy-grs	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/yaz/ztest/dummy-grs	(revision 21064)
@@ -0,0 +1,98 @@
+#1
+(1,1) This is a test record
+(0,0)
+
+#2
+(1,2) title
+(1,8) {
+    (1,9) Author thing
+    (1,10) Other thing
+    (1,11) {
+	(1,12) test
+	(1,14) Deeper
+    }
+}
+(0,0)
+
+#3
+(3,title) The Ugly Duckling
+(3,author) {
+    (3,nationality) Danish
+    (3,name) Andersen, H.C.
+}
+(3,subject) Fairy tale about duck who would be swan and does so in end.
+(0,0)
+
+#4
+(3,title) This is a fairly deeply nested GRS-1 Record
+(3,level1) {
+    (3,level2) {
+	(3,level3) {
+	    (3,level4) {
+		(3,level5) {
+		    (3,level6) {
+			(3,level7) Whew!! This is silly
+			(3,hmm) Let's hope it never comes to this.
+		    }
+		    (3,level6) Uhm.
+		}
+		(3,level5) Down again.
+	    }
+	    (3,level4) Down further.
+	}
+	(3,level3) Down...
+    }
+    (3,level2) Down...
+}
+(3,level1) Down...
+(0,0)
+
+#5
+(1,1) Data
+(1,2) Stuff
+(0,0)
+
+#6
+(1,1) GGGGGGGGGGGGGGGGGGG
+(1,1) GGGGGGGGGGGGGGGGGGG
+(1,1) GGGGGGGGGGGGGGGGGGG
+(1,1) GGGGGGGGGGGGGGGGGGG
+(1,1) GGGGGGGGGGGGGGGGGGG
+(1,1) GGGGGGGGGGGGGGGGGGG
+(1,1) GGGGGGGGGGGGGGGGGGG
+(1,1) GGGGGGGGGGGGGGGGGGG
+(1,1) GGGGGGGGGGGGGGGGGGG
+(1,1) GGGGGGGGGGGGGGGGGGG
+(1,1) GGGGGGGGGGGGGGGGGGG
+(1,1) GGGGGGGGGGGGGGGGGGG
+(0,0)
+
+#7
+(2,1) Zen and the Art of Motorcycle Maintenance
+(2,6) An inquiry into values
+(4,52) Robert M. Pirsig
+(4,70) {
+    (4,90) {
+	(2,7) Transworld Publishers, ltd.
+	(2,11) Century House, 61-63 Uxbridge Road, London
+    }
+}
+(4,27) Just a silly test record, really.
+(0,0)
+
+#8
+(3,someField) Ok.. this is the last of the test records.
+(3,someFIeld) It's time to get back to work.
+(0,0)
+
+#9
+(1,1) This is a test record
+(0,0)
+
+#10
+(1,1) This is a test record
+(0,0)
+
+#11
+(1,1) This is a test record
+(0,0)
Index: /main/tags/2.25/gsdl/packages/yaz/ztest/dummy-records
===================================================================
--- /main/tags/2.25/gsdl/packages/yaz/ztest/dummy-records	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/yaz/ztest/dummy-records	(revision 21064)
@@ -0,0 +1,530 @@
+00366nam  22001698a 4500001001300000003000400013005001700017008004100034010001700179040001300075050001200088100001700100245003000117260001200147263000900159300001100168
+   11224466 
+DLC
+00000000000000.0
+910710c19910701nju           00010 eng  
+  aDLCcDLC
+00a123-xyz
+10aJack Collins
+10aHow to program a computer
+1 aPenguin
+  a8710
+  ap. cm.
+  a   11224466 
+
+00366nam  22001698a 4500001001300000003000400013005001700017008004100034010001700179040001300075050001200088100001700100245003000117260001200147263000900159300001100168
+   11224467 
+DLC
+00000000000000.0
+910710c19910701nju           00010 eng  
+  aDLCcDLC
+00a123-xyz
+10aJack Collins
+10aHow to program a computer
+1 aPenguin
+  a8710
+  ap. cm.
+  a   11224467 
+
+01369cam  2200265 i 4500001001800000003000400018005001700022008004100039010002201081040001800080050002200098082002100120111012100141245034700262260005400609300003000663504005100693650005600744650003900800650006200839700002300901700002000924710007100944710006601015
+   73090924 //r82
+DLC
+19820524000000.0
+760609s1974    nyua     b    10110 eng  
+  aDLCcDLCdDLC
+00aRC71.3b.W67 1971
+00a616.07/575/02854
+20aWorkshop on Computer Processing of Dynamic Images from an Anger Scintillation Camera,cWashington University,d1971.
+10aComputer processing of dynamic images from an Anger scintillation camera :bthe proceedings of a workshop /ccosponsored by the Biomedical Computer Laboratory and the Nuclear Medicine Division, Department of Radiology, School of Medicine, Washington University, St. Louis, January 18-22, 1971 ; edited by Kenneth B. Larson, Jerome R. Cox, Jr.
+0 aNew York :bSociety of Nuclear Medicine,c[c1974]
+  axiv, p. :bill. ;c24 cm.
+  aIncludes bibliographical references and index.
+ 0aRadioisotope scanningxData processingxCongresses.
+ 0aScintillation camerasxCongresses.
+ 0aImaging systems in medicinexData processingxCongresses.
+10aLarson, Kenneth B.
+10aCox, Jerome R. 
+20aWashington University, St. Louis.bBiomedical Computer Laboratory.
+20aWashington University, St. Louis.bNuclear Medicine Division.
+  a   73090924 //r82
+
+00942cam  22002531a 4500001001900000003000400019005001700023008004100040010002300665040001800081041001400099050001600113082001600129245007300145260007000218300005000288500004800338500009600386630003900482630003900521700003800560700003300598710003400631
+   73209622 //r823
+DLC
+19820325000000.0
+780306m19009999ohu           00000 grc  
+  aDLCcDLCdDLC
+0 agrchebeng
+00aBS421b.C64
+00a220.4/4219
+04aThe Computer Bible /cJ. Arthur Baird, David Noel Freedman, editors.
+0 a[Wooster, Ohio] :bBiblical Research Associates,c<1973-c1980   >
+  av. <2-4, 7-10, 13, 15-18, 20-24   > ;c28 cm.
+  aHebrew and Greek; introductions in English.
+  aVols. 2, 8: Missoula, Mont. : Published by Scholars Press for Biblical Research Associates.
+ 0aBible. O.T.xConcordances, Hebrew.
+00aBible.pN.T.xConcordances, Greek.
+10aBaird, J. Arthurq(Joseph Arthur)
+10aFreedman, David Noel,d1922-
+20aBiblical Research Associates.
+  a   73209622 //r823
+
+01033cam  2200253 i 4500001002100000003000400021005001700025008004100042010002500754040001800083043001200101050002200113100001900135245010500154260007300259300003800332490006800370500003500438504002400473650003400497651004600531700003900577810013800616
+   76357895 /MAP/r82
+DLC
+19820806000000.0
+760407s1974    waua     b    00010 eng  
+  aDLCcDLCdDLC
+  an-us-wa
+00aG1467.P8bM3 1974
+10aMairs, John W.
+14aThe Puget Sound Region :ba portfolio of thematic computer maps /cJohn W. Mairs, Eugene A. Hoerauf.
+0 a[Bellingham, Wash.] :bCenter for Pacific Northwest Studies,cc1974.
+  aiii, 41 p. :bill. ;c25 x 36 cm.
+1 aOccasional paper - Center for Pacific Northwest Studies ; no. 3
+  aScale of maps ca. 1:1,000,000.
+  aBibliography: p. 4.
+ 0aCartographyxData processing.
+ 0aPuget Sound region (Wash.)xCensusxMaps.
+10aHoerauf, Eugene A.,ejoint author.
+1 aWashington (State).bWestern Washington State College, Bellingham.bCenter for Pacific Northwest Studies.tOccasional paper ;vno. 3.
+  a   76357895 /MAP/r82
+
+01000pam  2200229 i 4500001001300000003000400013005001700017008004100034010001700753020001500075040001800090050001800108082001500126245030400141260004800445300003300493504005100526650002800577700002900605710004800634710007100682
+   77000348 
+DLC
+19770707000000.0
+770112s1977    mdua     b    10110 eng  
+  a0839108826
+  aDLCcDLCdDLC
+00aRC78.7.T6bR4
+00a616.07/572
+00aReconstruction tomography in diagnostic radiology and nuclear medicine :bproceedings of the workshop ... /cedited by Michel M. Ter-Pogossian ... [et al.] ; co-sponsors, the Edward Mallinckrodt Institute of Radiology and Biomedical Computer Laboratory, Washington University School of Medicine ....
+0 aBaltimore :bUniversity Park Press,cc1977.
+  axv, 573 p. :bill. ;c24 cm.
+  aIncludes bibliographical references and index.
+ 0aTomographyxCongresses.
+20aTer-Pogossian, Michel M.
+20aEdward Mallinckrodt Institute of Radiology.
+20aWashington University, St. Louis.bBiomedical Computer Laboratory.
+  a   77000348 
+
+01493pam  2200277 i 4500001001300000003000400013005001700017008004100034010001701198040001800075043001200093050003400105082002800139086001800167111009500185245044800280260013800728300003400866490003600900650005900936700003100995700002101026700002001047710005001067810008101117
+   77004773 
+DLC
+19770822000000.0
+770321s1977    dcua          10000 eng  
+  aDLCcDLCdDLC
+  an-us---
+00aQC100b.U57 no. 500-8aTA1650
+00a602/.1 sa621.381.9/598
+  aC13.10:500-8.
+20aWorkshop on Standards for Image Pattern Recognition,cNational Bureau of Standards,d1976.
+10aComputer science & technology :bproceedings of a workshop held at the National Bureau of Standards, Gaithersburg, MD, June 3-4, 1976 /cWorkshop on Standards for Image Pattern Recognition ; John M. Evans, Jr., Russell Kirsch, and Roger N. Nagel, editor[s] ; sponsored by National Bureau of Standards, Electronic Industries Association, Institute of Electrical and Electronic Engineers, in cooperation with Association for Computing Machinery.
+0 a[Washington] :bU.S. Dept. of Commerce, National Bureau of Standards : for sale by the Supt. of Docs., U.S. Govt. Print. Off.,c1977.
+  avii, 112 p. :bill. ;c26 cm.
+1 aNBS special publication ; 500-8
+ 0aOptical pattern recognitionxStandardszUnited States.
+10aEvans, John Martin,d1942-
+10aKirsch, Russell.
+10aNagel, Roger N.
+10aUnited States.bNational Bureau of Standards.
+1 aUnited States.bNational Bureau of Standards.tSpecial publication ;v500-8.
+  a   77004773 
+
+00878cam  2200229 i 4500001001300000003000400013005001700017008004100034010001700631040001800075050003800093082002200131086001700153100001900170245008700189260013800276300002400414440003400438490003600472650004200508810008100550
+   77005558 
+DLC
+19770713000000.0
+770401s1977    dcu           00010 eng  
+  aDLCcDLCdDLC
+00aQC100b.U57 no. 500-9aQA76.9.A25
+00a602/.1 sa001.6/4
+0 aC13.10:500-9
+10aWood, Helen M.
+14aThe use of passwords for controlled access to computer resources /cHelen M. Wood.
+0 a[Washington] :bU.S. Dept. of Commerce, National Bureau of Standards : for sale by the Supt. of Docs., U.S. Govt. Print. Off.,c1977.
+  aiv, 53 p. ;c26 cm.
+ 0aComputer science & technology
+1 aNBS special publication ; 500-9
+ 0aComputersxAccess controlxPasswords.
+1 aUnited States.bNational Bureau of Standards.tSpecial publication ;v500-9.
+  a   77005558 
+
+00791cam  2200217   4500001001800000003000400018005001700022008004100039010002200551040001800080043003000098050001800128082001800146100002100164245016200185260002300347300002600370500002900396650006400425710006200489
+   77616367 //r84
+DLC
+19841213000000.0
+720329s1971    dcua          00010 eng  
+  aDLCcDLCdDLC
+  an-us-dcan-us-mdan-us-va
+00aHE2781.W3bE5
+00a385/.22/09753
+10aEnglund, Carl R.
+10aWashington metropolitan area rail computer feasibility study;bfinal reportc[by] Carl R. Englund, Jr. Prepared for Urban Mass Transportation Administration.
+0 aWashington,c1971.
+  a92 l.billus.c28 cm.
+  a"Contract DOT-UT-10003."
+ 0aRailroadszWashington Metropolitan AreaxCommuting traffic.
+10aUnited States.bUrban Mass Transportation Administration.
+  a   77616367 //r84
+
+00686cam  2200229   4500001001800000003000400018005001700022008004100039010002200434040001800080043001200098050002400110082001900134110007000153245005500223250000900278260002100287300001800308500001700326650004800343650004300391
+   77637075 //r82
+DLC
+19820817000000.0
+720320s1971    wau      s    00000 eng  
+  aDLCcDLCdDLC
+  an-us-wa
+00aLB1028.5b.W37 1971
+00a378/.052/09797
+10aWashington (State).bState Board for Community College Education.
+12aA plan for community college computer development.
+  aRev.
+1 a[Olympia]c1971.
+  a47 l.c28 cm.
+  aCover title.
+ 0aUniversities and collegesxData processing.
+ 0aCommunity collegeszWashington (State)
+  a   77637075 //r82
+
+00668nam  22002171  4500001001300000003000400013005001700017008004100034010001700433040001800075050001800093082001600111100001900127245007600146260004000222300004000262350000900302490003200311504003000343630006000373
+   70001070 
+DLC
+19700427000000.0
+700302s1968    mouab    b    00000 eng  
+  aDLCcDLCdDLC
+00aBS1275.5b.O2
+00a222/.15/007
+10aOberst, Bruce.
+00aDeuteronomy.cThought questions, by Don DeWelt. Summary by Adam Clarke.
+0 aJoplin, Mo.,bCollege Pressc[1968]
+  aviii, 452 p.billus., maps.c22 cm.
+  a5.95
+0 aBible study textbook series
+  aBibliography: p. 449-452.
+ 0aBible. O.T. DeuteronomyxStudyxOutlines, syllabi, etc.
+  a   70001070 
+
+00888pam  2200265   4500001001300000003000400013005001700017008004100034010001700605020001500075040001800090043001200108050002000120082001200140100002900152245009300181260005500274300002800329500008100357504004100438650004500479650002500524651002200549830003400571
+   72002565 
+DLC
+19730409000000.0
+720418r19721909nyu      b    00000 eng  
+  a0836968433
+  aDLCcDLCdDLC
+  ae-gr---
+00aBL785b.A3 1972
+00a292/.08
+10aAdam, James,d1860-1907.
+14aThe religious teachers of Greece.cEdited with a memoir, by his wife, Adela Marion Adam.
+0 aFreeport, N.Y.,bBooks for Libraries Pressc[1972]
+  axix, lv, 467 p.c22 cm.
+  aReprint of the 1909 ed., which was issued as the 1904-1906 Gifford lectures.
+  aIncludes bibliographical references.
+ 0aGreek literaturexHistory and criticism.
+ 0aPhilosophy, Ancient.
+ 0aGreecexReligion.
+ 0aGifford lectures,v1904-1906.
+  a   72002565 
+
+01126nam  2200265 a 4500001001300000003000400013005001700017008004100034010001700843020003100075040001800106050002100124082001800145100004200163245015800205250003700363260004500400300005000445440003500495630006400530630006400594630006200658630006300720730006000783
+   80082329 
+DLC
+19810528000000.0
+810526s1980    ctuaf         00010 eng  
+  a0879832355 (pbk.) :c$4.95
+  aDLCcDLCdDLC
+00aBS1433b.S5 1980
+00a223/.2077219
+10aSmith, George Adam,cSir,d1856-1942.
+10aFour psalms :bXXIII, XXXVI, LII, CXXI /cinterpreted for practical use by George Adam Smith ; introduction by F.F. Bruce ; illustrations by Ron McCarty.
+  aShepherd illustrated classic ed.
+0 aNew Canaan, Conn. :bKeats Pub.,cc1980.
+  a81 p., [5] leaves of plates :bill. ;c21 cm.
+ 2aA Shepherd illustrated classic
+00aBible.pO.T.pPsalms XXIIIxCriticism, interpretation, etc.
+00aBible.pO.T.pPsalms XXXVIxCriticism, interpretation, etc.
+00aBible.pO.T.pPsalms LIIxCriticism, interpretation, etc.
+00aBible.pO.T.pPsalms CXXIxCriticism, interpretation, etc.
+01aBible.pO.T.pPsalms XXIII, XXXVI, LII, CXXI.lEnglish.
+  a   80082329 
+
+01433nas  2200421 a 4500001000900000003000400009005001700013008004100030010003100071022001400102030001100116032001700127035002000144035002700164040009600191042001300287050002000300070001800320072000900338082001400347210001900361222001900380245002000399260004300419265005800462300001700520310006200537350001100599362003200610500002400642650004600666650003600712650003900748650003500787650003300822780008200855850007400937
+ACD-3837
+DLC
+19940614065614.0
+920728c19929999ctumn1p       0   a0eng d
+  a   92646062 zsn 92004430 
+0 a1064-3923
+  aIERNE8
+  a008187bUSPS
+  a(OCoLC)26273275
+00ilcmarc/AQP-6285/JEANNE
+  aNSDPcNSDPdWaUdNICdDNALdOUCAdNSTdDLCdNSTdNSDPdNSTdDLCdInUdMHdNSDPdNdDLCdMiU
+  ansdpalc
+00aTK5105.5b.R448
+0 aTK5105.5.R448
+ 0aX200
+00a384.3220
+0 aInternet world
+ 0aInternet world
+00aInternet world.
+  aWestport, CT :bMeckler Corp.,cc1992-
+  aMeckler Corp., 11 Ferry Lane West, Westport, CT 06880
+  av. ;c28 cm.
+  aMonthly (except Jan./Feb., July/Aug., Nov./Dec. combined)
+  a$97.00
+0 aVol. 3, no. 7 (Sept. 1992)-
+  aTitle from caption.
+ 0aInternet (Computer network)xPeriodicals.
+ 0aComputer networksxPeriodicals.
+ 0aInformation networksxPeriodicals.
+ 2aComputer Systemsxperiodicals.
+ 2aOnline Systemsxperiodicals.
+00tResearch & education networkingx1051-4791w(DLC)   90646613w(OCoLC)21974448
+  aDLCaDNALaDNGAaInUaMBCoaMH-EdaMdBJaMiUaMoKLaNaNICaTxHRaWaU
+
+01330nas  22003735a 4500001000900000003000400009005001700013008004100030010001700071022002500088035002000113035002700133040002900160042001600189043001200205055001200217082001200229130003500241210002700276222002900303245001700332260005400349265006900403300002500472310001200497350002100509362003300530500002400563580005800587780008300645780005100728785008300779787009400862
+ACD-3799
+DLC
+19940614090514.0
+920723c19919999oncmr4p       0   a0eng d
+  acn 92031641 
+0 a1187-7081y0025-9535
+  a(OCoLC)26244844
+00ilcmarc/AQF-2896/JEANNE
+  aCaOOCMbengcCaOONLdInU
+  anlcaisds/c
+  an-cn---
+ 2aHD9696*
+1 a004212
+0 aInfo Canada (Downsview, Ont.).
+0 aInfo Can.b(Downsview)
+ 0aInfo Canadab(Downsview)
+00aInfo Canada.
+  aDownsview, Ont. :bLaurentian Technomedia,c1991-
+  aLaurentian Technomedia, 501 Oakdale Rd., Downsview, Ont. M3N 1W7
+  av. :bill. ;c40 cm.
+  aMonthly
+  a$50.00 per year.
+0 aVol. 16, no. 9 (Sept. 1991)-
+  aTitle from caption.
+  aIncludes: Network world Canada, Sept. 1991-Jan. 1992.
+00tComputer datax0383-7319w(CaOONL)770308317w(OCoLC)11416479w(DLC)cn 77030831
+05tI.T. magazine (Toronto, Ont.)w(OCoLC)27699066
+01tNetwork world CanadagFeb. 1992x1187-2985w(OCoLC)25314012w(CaOONL)920305725
+1 tNetwork world CanadagSept. 1991-Jan. 1992x1187-2985w(OCoLC)25314012w(CaOONL)920305725
+
+00803nam  22002898a 4500001000900000003000400009005001700013008004100030010001700071020001500088035002700103040001300130043001200143050002800155082001800183100002500201245009500226250001200321260003400333263000900367300001100376500002000387630003800407600002200445600001500467650003100482
+ACD-3792
+DLC
+19931215084605.7
+931206s1993    nyu           001 0 eng  
+  a   93047992 
+  a1562827545
+00ilcmarc/ARU-2364/STEVES
+  aDLCcDLC
+  an-us---
+00aPN1992.77.T63bC37 1993
+00a791.45/72220
+1 aCarter, Bill,d1949-
+14aThe late shift :bLetterman, Leno, and the network battle for the night /cby Bill Carter.
+  a1st ed.
+  aNew York :bHyperion,cc1993.
+  a9402
+  ap. cm.
+  aIncludes index.
+00aTonight show (Television program)
+10aLetterman, David.
+10aLeno, Jay.
+ 0aTalk showszUnited States.
+
+00766nam  22002658a 4500001000900000005001700009008004100026010001700067020001500084035002900099040001300128050002900141082001600170245007600186250001600262260005600278263000900334300001100343440003200354500002000386650003200406650001900438700002500457700001800482
+ACD-3665
+19930730092004.1
+930721s1993    nju           001 0 eng  
+  a   93030775 
+  a0132896613
+00ilcmarc/ARI-3804/JULIANNE
+  aDLCcDLC
+00aTK5105.875.I57bI56 1993
+00a384.3/4220
+00aInternet :bmailing lists /cedited by Edward T.L. Hardie, Vivian Neou.
+  aUpdated ed.
+  aEnglewood Cliffs, N.J. :bPTR Prentice Hall,c1993.
+  a9308
+  ap. cm.
+ 0aInternet information series
+  aIncludes index.
+ 0aInternet (Computer network)
+ 0aMailing lists.
+10aHardie, Edward T. L.
+10aNeou, Vivian.
+
+01324nam  2200289Ia 4500001000900000008004100009005001700050010001300067037002300080043001200103074001900115086002200134049000900156245006200165260014500227300002500372500008000397500022100477500005500698500002100753500002200774610006100796650004300857650004500900700002100945710006800966
+ACD-2728
+910514s1984    nyu      r   f00100 eng d
+19910519144551.0
+  o23740002
+  aED ED 289459bERIC
+  an-us---
+  a0466-A-03 (MF)
+0 aED 1.310/2:289459
+  aDRUG
+00aTechnology programs that work /cMichael B. Webb, editor.
+0 aNew York, N.Y. :bTechnology for the NDN Project, Institute for Urban and Minority Education, Teachers College, Columbia University,c[1984]
+  a72, [1] p. ;c28 cm.
+  a"Spons agency Office of Educational Research and Improvement"--Doc. resume.
+  a"This directory was developed by the Technology for the National Diffusion Network Project, Teachers College, Columbia University pursuant to contract number OE-300-83-0253, U.S. Department of Education"--T.p. verso.
+  aDistributed to depository libraries in microfiche.
+  a"December 1984."
+  aIncludes indexes.
+10aUnited States.bNational Diffusion NetworkxDirectories.
+ 0aEducational technologyzUnited States.
+ 0aFederal aid to educationzUnited States.
+10aWebb, Michael B.
+10aUnited States.bOffice of Educational Research and Improvement.
+
+01559nam  2200373Ia 4500001000900000008004100009005001700050010001300067037002000080043001200100074001900112086002200131088001600153049000900169100002200178245025900200260010500459300003300564500005500597500001700652504004100669500001800710650004400728650004400772650003700816650005200853650003700905700004400942700002500986710004801011710003001059710006801089740002801157
+ACD-2476
+910425s1987    dcua     b   f00010 eng d
+19910519144551.0
+  o23602389
+  aED 288529bERIC
+  an-us---
+  a0466-A-03 (MF)
+0 aED 1.310/2:288529
+  aLP 87-403 c
+  aDRUG
+10aSeager, Andrew J.
+10aCheck this out :blibrary program models /cprepared by Andrew J. Seager, Sarah J. Roberts, Carol Z. Lincoln ; prepared for National Diffusion Network under contract to RMC Corporation, contract 300-84-0251 with the United States Department of Education.
+0 aWashington, D.C. :bOffice of Educational Research and Improvement, U.S. Dept. of Education,c[1987]
+  aix, 319 p. :bill. ;c28 cm.
+  aDistributed to depository libraries in microfiche.
+  a"July 1987."
+  aIncludes bibliographical references.
+  a"LP 87-403c."
+ 0aLibraries and communityzUnited States.
+ 0aLibraries and educationzUnited States.
+ 0aSchool librarieszUnited States.
+ 0aInstructional materials centerszUnited States.
+ 0aPublic librarieszUnited States.
+10aRoberts, Sarah J.q(Sarah Jane),d1946-
+10aLincoln, Carol Zall.
+10aUnited States.bNational Diffusion Network.
+20aRMC Research Corporation.
+10aUnited States.bOffice of Educational Research and Improvement.
+01aLibrary program models.
+
+01155nas  22003135a 4500001000900000008004100009005001700050010002700067040000800094012001200102042000700114050001500121074001100136086002000147049000900167212008300176245006900259260011500328265007100443300001700514310001100531500003200542610003600574650006200610650006400672710002200736710007000758936001300828
+ACD-2376
+910225c19uu9999dcuar        f0uuu 0eng  
+19910519144551.0
+  a   91656060 o23150847
+  dGPO
+  a2i9103
+  alc
+00aIN PROCESS
+  a0785-H
+0 aLC 1.40/2:F 31/
+  aDRUG
+0 aFederal Library and Information Network services directory for fiscal year ...
+00aFEDLINK services directory for fiscal year ... /cFLICC/FEDLINK.
+00aWashington, D.C. :bFederal Library and Information Network, Federal Library and Information Center Committee,
+  aFEDLINK, Room LA 1026C, Library of Congress, Washington D.C. 20540
+  av. ;c28 cm.
+  aAnnual
+  aDescription based on: 1990.
+20aFEDLINK (Network)xDirectories.
+ 0aLibrary information networkszUnited StatesxDirectories.
+ 0aLibraries, Governmental, administrative, etc.xPeriodicals.
+20aFEDLINK (Network)
+20aUnited States.bFederal Library and Information Center Committee.
+  a1991 LIC
+
+00915nam  2200229Ka 4500001000900000008004100009005001700050010001300067040001300080037002000093074001900113086002200132049000900154100001800163245015700181260012400338300000900462533009300471500005500564650001400619710005200633
+ACD-1949
+910415r19901087dcu     b    f00010 eng d
+19910421122541.0
+  o23469261
+  aGPOcGPO
+  aED 286992bERIC
+  a0466-A-03 (MF)
+0 aED 1.310/2:286992
+  aDRUG
+10aPaulu, Nancy.
+10aDealing with dropoutshmicroform :bthe urban superintendents' call to action /cby the OERI Urban Superintendents Network ; Nancy Paulu, writer-editor.
+0 a[Washington, D.C]. :bOffice of Educational Research and Improvement, Educational Resources Information Center,c[1987]
+  a1 v.
+  aMicrofiche.b[Washington, D.C.?] :cSupt. of Docs., U.S. G.P.O.,d[1990].e1 microfiche.
+  aDistributed to depository libraries in microfiche.
+ 0aDropouts.
+20aEducational Resources Information Center (U.S.)
+
+01053nam  2200217Ka 4500001000900000008004100009005001700050010001300067037002000080074001900100086002200119049000900141245016300150260025100313300000900564533009400573500005500667650002400722650003700746710005200783
+ACD-1947
+910415r19901986dcu     b    f00010 eng d
+19910421122541.0
+  o23469098
+  aED 286333bERIC
+  a0466-A-03 (MF)
+0 aED 1.310/2:286333
+  aDRUG
+00aNational dissemination model for the I'M SPECIAL Program of Physical Education for the Handicapped, 1983-1986hmicroform :bfinal report, I'M SPECIAL network.
+0 aTampa, Fla. :bDepartment of Physical Education, College of Education, University of South Florida ;a[Washington, D.C.] :bU.S. Dept. of Education, Office of Educational Research and Improvement, Educational Resources Information Center,c[1986]
+  a1 v.
+  aMicrofiche.b[Washington, D.C.?] :cSupt. of Docs., U.S. G.P.O.,d[1990].e2 microfiches.
+  aDistributed to depository libraries in microfiche.
+ 0aPhysical education.
+ 0aHandicapped childrenxEducation.
+20aEducational Resources Information Center (U.S.)
+
+01036nam  2200289Ia 4500001000900000008004100009005001700050010001300067040001300080043001200093074001400105086001800119088001500137049000900152245004500161260010500206300004100311500005500352500003300407500002800440500002600468610004800494650005500542650004400597710006800641740003700709
+ACD-1938
+910415s1991    dcu          f00000 eng d
+19910421122541.0
+  o23468272
+  aGPOcGPO
+  an-us---
+  a0461-D-05
+0 aED 1.302:Sh 2
+  aPIP 91-836
+  aDRUG
+00aNDN, sharing success to improve schools.
+0 a[Washington, DC] :bU.S. Dept. of Education, Office of Educational Research and Improvement,c[1991]
+  a1 folded sheet (6 p.) ;c22 x 10 cm.
+  aAt head of title: National Diffusion Network, NDN.
+  aShipping list no.: 91-198-P.
+  a"January 1991"--P. [5].
+  a"PIP 91-836"--P. [5].
+10aUnited States.bNational Diffusion Network.
+ 0aDemonstration centers in educationzUnited States.
+ 0aEducational innovationszUnited States.
+10aUnited States.bOffice of Educational Research and Improvement.
+01aNational Diffusion Network, NDN.
+
+00725nam0 2200253   45  001001500000004001500015008002300030021003400053041001300087100001800100241001500118245012300133250002400256260003200280300002700312520003100339652001100370010002100381096001100402251002400413261000900437970001300446970001200459
+00aD000015937
+00satmrnu0
+00ar19881981bdkldan
+00a87-11-04010-6chf.dkr. 92,00
+00adanceng
+00aAndersonhBob
+00aStretching
+00aStrækøvelserdBob Andersonfillustreret af Jean Andersonfdansk udgave ved Lis Engelf[oversættelse ved Jesper Langer]
+00a1. udgave, 4. oplag
+00a[Kbh.]bClausen bøgerc1988
+00a192 siderbill.c26 cm
+00aTidligere: 1. udgave. 1981
+00a79.601
+00a870970b05675030
+00z870970
+00a1. udgave, 4. oplag
+00c1988
+00b05675030
+00cDBF8842
+
+
+
+
Index: /main/tags/2.25/gsdl/packages/yaz/ztest/dummy-words
===================================================================
--- /main/tags/2.25/gsdl/packages/yaz/ztest/dummy-words	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/yaz/ztest/dummy-words	(revision 21064)
@@ -0,0 +1,990 @@
+0:44
+0OK:2
+0SUCCESS:2
+1:41
+10:5
+2:2
+210:4
+3:2
+301024:4
+3536:2
+45:2
+7:2
+8:2
+99:2
+A:249
+ABLE:4
+ABOUT:13
+ABOVE:2
+ABSENT:4
+ACCESS:10
+ACCORDING:2
+ACTUAL:3
+ACTUALLY:2
+ADAPT:2
+ADD:4
+ADDED:4
+ADDINFO:2
+ADDING:3
+ADDITION:3
+ADDRESS:19
+ADDRESSES:6
+AFTER:10
+AGAIN:8
+AGAINST:2
+ALL:21
+ALLOCATE:9
+ALLOCATED:14
+ALLOCATES:2
+ALLOCATING:2
+ALLOCATION:2
+ALLOW:5
+ALLOWED:3
+ALONG:2
+ALREADY:7
+ALSO:9
+ALTERNATIVE:2
+ALTHOUGH:6
+ALWAYS:7
+AN:69
+AND:161
+ANY:22
+APDUS:2
+API:12
+APIS:2
+APPEAR:2
+APPLICATION:10
+APPLICATIONS:7
+APPROACH:4
+ARCHIVE:2
+ARE:63
+ARGUMENT:6
+ARISES:3
+ARM:5
+AROUND:2
+ARRAY:11
+AS:75
+ASN:12
+ASN1:23
+ASSOCIATION:9
+ASSUME:8
+ASYNCHRONOUS:5
+AT:40
+ATTRIBUTESET:2
+AUTHORS:2
+AVAILABLE:5
+AWARE:3
+B:4
+BACKEND:18
+BACKENDH:4
+BADN:2
+BASE:2
+BASED:5
+BASENAME:2
+BASIC:3
+BE:123
+BECAUSE:6
+BEEN:21
+BEFORE:12
+BEGINNING:5
+BEHAVIOR:2
+BEING:2
+BELONGING:2
+BELOW:5
+BEND:3
+BENDDELETEREQUEST:4
+BENDDELETERESPONSEVOID:2
+BENDDELETERESULT:6
+BENDDELETEVOID:2
+BENDFETCHREQUEST:4
+BENDFETCHRESPONSEVOID:2
+BENDFETCHRESULT:6
+BENDFETCHVOID:2
+BENDINITBENDINITREQUEST:2
+BENDINITREQUEST:3
+BENDINITRESULT:4
+BENDSCANRESULT:2
+BENDSEARCHREQUEST:6
+BENDSEARCHRESPONSEVOID:2
+BENDSEARCHRESULT:8
+BENDSEARCHVOID:2
+BER:4
+BERENCODED:3
+BETTER:2
+BETWEEN:9
+BEYOND:3
+BIT:6
+BITMASK:5
+BITNO:3
+BITS:5
+BLOCK:4
+BLOCKING:6
+BOOLEAN:7
+BOOLT:4
+BOOLTNULL:3
+BOOLTTRUE:3
+BOOLVAL:4
+BOTH:3
+BRIEF:2
+BUF:11
+BUFFER:20
+BUFFERP:3
+BUT:15
+BY:58
+BYTES:4
+C:21
+CALL:41
+CALLED:8
+CALLING:8
+CALLS:6
+CAN:61
+CANGROW:4
+CANNOT:3
+CANT:3
+CAPABILITIES:3
+CARE:4
+CASE:9
+CASES:4
+CERTAIN:2
+CHANGE:3
+CHANGES:3
+CHAR:39
+CHARACTER:6
+CHARINDEX:2
+CHARYAZ:2
+CHECK:2
+CHOICE:11
+CHUNKS:2
+CLASS:10
+CLEAN:2
+CLEAR:2
+CLIENT:11
+CLOSE:3
+CODE:3
+COMES:3
+COMMAND:2
+COMMANDLINE:2
+COMMON:3
+COMMUNICATION:10
+COMMUNICATIONS:2
+COMPACT:3
+COMPILE:2
+COMPILER:6
+COMPLETE:4
+COMPLETED:3
+COMPLEX:9
+COMPLEXITY:2
+COMSTACK:14
+COMSTACKH:2
+CONDITION:7
+CONFIGNAME:2
+CONNECT:4
+CONNECTION:14
+CONNECTIONS:3
+CONSISTS:4
+CONST:4
+CONSTANT:3
+CONSTANTS:3
+CONSTRUCT:2
+CONSTRUCTED:6
+CONSTRUCTION:3
+CONSTRUCTIONS:2
+CONTAIN:3
+CONTAINED:2
+CONTAINS:4
+CONTENTS:4
+CONTEXT:3
+CONTROL:4
+COPY:2
+COPYRIGHT:3
+CORRECT:3
+CORRESPONDING:9
+CORRESPONDS:2
+COULD:7
+COURSE:2
+CRASH:2
+CREATE:8
+CREATED:3
+CSACCEPTCOMSTACK:2
+CSBINDCOMSTACK:2
+CSCLOSECOMSTACK:2
+CSCONNECT:2
+CSCONNECTCOMSTACK:2
+CSCREATECSTYPE:2
+CSERRLIST:2
+CSERRNO:2
+CSGET:8
+CSGETCOMSTACK:2
+CSLISTEN:3
+CSLISTENCOMSTACK:2
+CSLOOKCOMSTACK:2
+CSMORE:6
+CSMORECOMSTACK:2
+CSPERRORCOMSTACK:2
+CSPUTCOMSTACK:2
+CSRCVCONNECT:2
+CSRCVCONNECTCOMSTACK:2
+CSSTACKERRCOMSTACK:2
+CURRENT:9
+CURRENTLY:4
+DAMAGES:2
+DATA:54
+DATABASE:24
+DATABASENAMESCHARNULL:2
+DATABASES:2
+DATAYAZ:2
+DEBUGGING:2
+DECODE:11
+DECODED:2
+DECODES:2
+DECODING:18
+DEFAULT:9
+DEFAULTS:2
+DEFINE:3
+DEFINED:14
+DEFINITION:11
+DEFINITIONS:10
+DELETE:3
+DEMO:2
+DEPENDING:5
+DERIVED:3
+DESC:2
+DESCRIBED:4
+DESCRIPTOR:2
+DESIGNED:2
+DESIRED:2
+DETERMINE:4
+DETERMINES:2
+DEVELOPMENT:2
+DIAGNOSTIC:8
+DIFFERENT:14
+DIFFERENTLY:2
+DIGITS:2
+DIRECT:2
+DIRECTION:2
+DIRECTORY:13
+DISCONNECT:2
+DISCRIMINATOR:5
+DISTRIBUTION:3
+DN:2
+DO:7
+DOCUMENT:2
+DOCUMENTATION:5
+DOES:4
+DOESNT:6
+DONE:7
+DONT:9
+DURING:4
+EACH:18
+EASILY:3
+EFFECT:2
+EFFICIENT:2
+EG:6
+EITHER:17
+ELEMENT:4
+ELEMENTS:10
+EMPTY:4
+ENCODE:6
+ENCODED:8
+ENCODERS:2
+ENCODING:21
+ENCODINGDECODING:2
+END:3
+ENDPOINT:7
+ENSURE:3
+ENSURES:2
+ENTRIES:2
+ENUM:7
+EQUIVALENT:2
+ERRCODE:7
+ERROR:31
+ERRSTRING:7
+ESTABLISH:2
+ESTABLISHMENT:2
+ETC:4
+EVEN:4
+EVENT:9
+EVENTHANDLING:2
+EVERYTHING:5
+EXACTLY:2
+EXAMINED:2
+EXAMPLE:3
+EXAMPLES:2
+EXCEPT:2
+EXCHANGE:5
+EXISTING:5
+EXPECTED:4
+EXPLAIN:2
+EXPLICIT:4
+EXPLICITLY:3
+EXTERN:4
+EXTERNAL:2
+EXTRA:6
+FACILITIES:2
+FACILITY:4
+FAILED:2
+FAIRLY:8
+FAR:5
+FD:11
+FEW:2
+FIDDLE:2
+FIELD:10
+FIELDS:6
+FIELDTYPEDEFAULT:15
+FILE:18
+FILES:4
+FIND:3
+FIRST:11
+FIT:2
+FLAG:5
+FOLLOW:3
+FOLLOWED:2
+FOLLOWING:5
+FOR:115
+FORK:4
+FORM:9
+FORMAT:8
+FOUND:10
+FREE:3
+FREE2:2
+FREED:2
+FREELIST:2
+FROM:26
+FRONTEND:11
+FULL:10
+FULLY:2
+FUN:5
+FUNCTION:93
+FUNCTIONS:43
+FURNISS:3
+FURTHER:3
+FUTURE:6
+GCC:2
+GENERAL:7
+GENERALITY:2
+GENERALLY:14
+GET:6
+GIVE:2
+GIVEN:9
+GIVES:3
+GLOBAL:5
+GO:4
+GOOD:5
+GUIDE:2
+HAD:6
+HANDED:2
+HANDLE:54
+HAPPENS:2
+HAPPY:5
+HAS:34
+HAVE:43
+HAVENT:2
+HEADER:2
+HELP:2
+HERE:4
+HEX:2
+HIGHERLEVEL:2
+HITS:3
+HOLDS:4
+HOST:2
+HOSTNAME:3
+HOW:5
+HUMANREADABLE:2
+IDENTIFIERS:7
+IF:87
+IGNORED:3
+IMMEDIATELY:7
+IMPLEMENT:8
+IMPLEMENTATION:11
+IMPLEMENTATIONID:2
+IMPLEMENTATIONNAME:2
+IMPLEMENTATIONS:7
+IMPLEMENTATIONVERSIONCHARYAZVERSION:2
+IMPLEMENTED:3
+IMPLEMENTING:4
+IMPLEMENTS:3
+IMPLICIT:8
+IMPORTANT:6
+IN:156
+INCLUDE:15
+INCLUDING:3
+INCOMING:5
+INDEPENDENT:4
+INDEX:8
+INDICATE:2
+INDICATES:2
+INDIRECT:3
+INDIVIDUAL:9
+INDIVIDUALLY:2
+INFOINDEXPINGDK:2
+INFORMATION:6
+INITIALIZATION:2
+INITIALIZE:2
+INITIALIZED:4
+INITREQUEST:3
+INPUT:3
+INSTALLATION:2
+INSTANCE:5
+INSTEAD:3
+INT:172
+INTEGER:16
+INTEGRATION:2
+INTERESTED:2
+INTERFACE:33
+INTERFACES:5
+INTERNAL:4
+INTERNALLY:2
+INTERPRETED:2
+INTO:8
+INTVAL:4
+INVOCATION:2
+IO:2
+IPNUMBER:2
+IS:205
+ISNT:3
+ISODE:5
+IT:92
+ITS:25
+ITSELF:6
+JUST:5
+KEEP:3
+KEYWORD:2
+KIND:3
+L:2
+LANGUAGE:2
+LARGE:3
+LAST:5
+LASTINSET:2
+LATER:5
+LATEST:2
+LAYER:2
+LAYERS:4
+LEAST:5
+LEAVE:2
+LEN:17
+LENGTH:8
+LESS:3
+LEVEL:8
+LIBMOSIA:2
+LIBRARY:13
+LICENSE:2
+LIKE:22
+LIKELY:3
+LIKES:2
+LIMITED:3
+LINE:5
+LINK:4
+LIST:3
+LISTEN:2
+LISTENER:5
+LISTENING:2
+LITTLE:5
+LIVE:2
+LOCAL:3
+LOG:2
+LOGFILE:2
+LOGLEVEL:2
+LONG:2
+LONGER:3
+LOOK:16
+LOOKS:3
+LOWER:6
+LOWLEVEL:2
+MACRO:2
+MACROS:4
+MAIL:2
+MAIN:4
+MAINTAIN:2
+MAKE:14
+MAKEFILE:3
+MAKES:2
+MALLOC2:2
+MANAGEMENT:6
+MANAGING:4
+MANIFEST:2
+MANY:5
+MAP:2
+MAPPING:3
+MARK:2
+MATCH:3
+MATTER:2
+MAXIMUM:4
+MAXIMUMRECORDSIZE:2
+MAY:16
+MAYBE:2
+MEANS:2
+MECHANISM:8
+MEMBER:7
+MEMBERS:10
+MEMORY:28
+MESSAGE:11
+METHOD:2
+METHODS:2
+MIGHT:15
+MINIMUM:2
+MODE:20
+MODEL:3
+MODIFY:2
+MODULE:19
+MODULES:2
+MORE:15
+MOSI:2
+MOSISTRTOADDR:2
+MOSISTRTOADDRCHAR:2
+MOSITYPE:2
+MOST:12
+MOVE:2
+MUST:2
+MYARRAY:4
+MYCHOICE:3
+MYCHOICEOTHER:2
+MYCHOICETAGGED:2
+MYCHOICEUNTAGGED:2
+MYINT:2
+MYSEQUENCE:10
+MYSEQUENCEODR:3
+NAME:16
+NAMED:2
+NAMES:2
+NECESSARY:5
+NEED:25
+NEEDED:3
+NEEDS:2
+NEGOTIATION:3
+NETBUF:2
+NETWORK:6
+NEW:21
+NEXT:6
+NIBBLE:3
+NO:19
+NONBLOCKING:6
+NONZERO:3
+NORMAL:2
+NOT:32
+NOTE:21
+NOTICE:3
+NOW:2
+NULL:34
+NUM:2
+NUMBER:18
+NUMBEROFRECORDSRETURNED:2
+NUMDATABASENAMES:2
+O:65
+OBJECT:7
+OCCURS:4
+OCTET:3
+OCTETSTRING:2
+ODIRECTION:3
+ODR:62
+ODRARM:5
+ODRBITMASK:7
+ODRBOOLO:3
+ODRCONSTRUCTED:2
+ODRCONTEXT:5
+ODRCREATEMEMINT:2
+ODRDECODE:4
+ODRDESTROYODR:2
+ODRERRLIST:2
+ODREXPLICIT:5
+ODREXTRACTMEMODR:2
+ODRFUN:3
+ODRGETBUFODR:2
+ODRGETERRORODR:2
+ODRH:2
+ODRIMPLICIT:6
+ODRIMPLICITSETTAGODR:2
+ODRINTEGER:5
+ODRINTEGERO:3
+ODRINTEGERODR:2
+ODRMALLOC:6
+ODRMALLOCO:3
+ODRMALLOCODR:2
+ODRMEM:3
+ODROCT:3
+ODROID:3
+ODROIDNULL:3
+ODROKO:5
+ODRRELEASEMEMODRMEM:2
+ODRRESET:13
+ODRRESETODR:2
+ODRSEQUENCEBEGINO:3
+ODRSEQUENCEENDO:3
+ODRSETBUF:3
+ODRSETBUFODR:2
+OF:290
+OFF:2
+OFFERS:2
+OFTEN:3
+OID:8
+OIDENT:5
+OIDPROTO:3
+OIDS:2
+OK:2
+ON:59
+ONCE:7
+ONE:27
+ONLY:16
+OPAQUE:2
+OPEN:3
+OPERATE:2
+OPERATION:9
+OPERATIONS:4
+OPTION:4
+OPTIONAL:41
+OPTIONS:10
+OR:86
+OSF1:2
+OSI:16
+OTHER:23
+OTHERS:2
+OTHERWISE:3
+OUR:5
+OUT:7
+OUTPUT:4
+OVER:5
+OWN:8
+P:46
+PACKAGE:11
+PACKAGES:7
+PACKET:2
+PARAMETER:17
+PARAMETERS:8
+PART:7
+PARTIAL:2
+PASSED:2
+PBOOLVAL:3
+PDU:11
+PDUS:16
+PEER:3
+PENDING:3
+PERFORM:3
+PERMISSION:3
+PETER:3
+PINTVAL:3
+PLACE:6
+PLACED:2
+PLATFORMS:5
+POINT:8
+POINTED:5
+POINTER:22
+POINTERS:8
+POINTS:2
+PORT:6
+PORTABLE:2
+PORTNUMBER:2
+POSSIBILITY:2
+POSSIBLE:9
+PRACTICAL:2
+PREFERREDMESSAGESIZE:2
+PREFERREDRECORDSYNTAXODROIDNULL:2
+PREFIX:2
+PREPARE:2
+PRESENT:4
+PRESENTATION:5
+PRESENTSTATUSINT:2
+PRIMARY:3
+PRIMITIVE:18
+PRIMITIVES:2
+PRINTING:2
+PRINTS:2
+PRIVATE:2
+PROBABLY:3
+PROBLEM:5
+PROBLEMS:5
+PROCESS:9
+PROCESSING:5
+PROGRAM:3
+PROGRAMMER:2
+PROGRAMMING:4
+PROTO:3
+PROTOCOL:39
+PROTOCOLS:5
+PROTOCOLVERSION:2
+PROTOH:2
+PROTOSR:3
+PROTOTYPES:2
+PROTOZ3950:3
+PROVIDE:15
+PROVIDED:29
+PROVIDES:13
+PURPOSE:6
+PURPOSES:3
+QUALITY:2
+QUERY:8
+QUESTIONS:2
+QUITE:5
+R:12
+RATHER:5
+READ:9
+REAL:2
+REALISE:2
+REALLY:2
+REASON:5
+RECEIVED:6
+RECOMMEND:2
+RECORD:16
+RECORDS:6
+RECYCLED:2
+REFER:6
+REFERENCE:8
+REFERENCEID:15
+RELEASE:8
+RELEASED:2
+RELEASES:6
+REPEATEDLY:3
+REPLACESET:2
+REPORTS:2
+REPRESENT:2
+REPRESENTATION:8
+REPRESENTATIONS:2
+REPRESENTING:3
+REPRESENTS:2
+REQUEST:12
+REQUESTS:3
+REQUIRE:2
+REQUIRED:11
+REQUIREMENTS:2
+REQUIRING:2
+RESOURCES:2
+RESPOND:2
+RESPONSE:3
+REST:3
+RESULT:8
+RESULTING:2
+RESULTSETWANTED:2
+RESVALP:3
+RETAIN:4
+RETURN:40
+RETURNED:7
+RETURNS:11
+RFC1006:3
+ROLE:5
+ROUTINE:5
+ROUTINES:3
+RPN:2
+RULES:2
+RUN:4
+RUNTIME:2
+S:2
+SAME:11
+SAY:7
+SCHEME:2
+SEARCH:3
+SEARCHREQUEST:3
+SECTION:11
+SEE:12
+SEEN:2
+SELECT2:5
+SELECTOR:2
+SEND:2
+SENDS:2
+SENT:2
+SEPARATE:3
+SEQUENCE:13
+SEQUENCES:2
+SERVER:27
+SERVICE:6
+SESSION:4
+SET:37
+SETNAME:5
+SETS:3
+SETTINGS:3
+SEVERAL:4
+SHORT:2
+SHOULD:46
+SHOULDNT:2
+SIDE:4
+SIMILAR:2
+SIMPLE:14
+SIMPLIFY:3
+SIMPLY:7
+SINCE:6
+SINGLE:4
+SIZE:24
+SIZEOFP:6
+SMALL:4
+SO:9
+SOCKADDRIN:2
+SOCKETS:3
+SOFTWARE:17
+SOME:14
+SOMETHING:3
+SOMETIMES:4
+SOMEWHAT:2
+SOURCE:3
+SPACE:7
+SPECIAL:4
+SPECIFIC:3
+SPECIFICALLY:4
+SPECIFICATION:6
+SPECIFY:2
+SR:5
+STACK:2
+STACKS:2
+STANDARD:6
+STATE:5
+STATIC:4
+STATSERVMAIN:3
+STATSERVOPTIONSBLOCK:2
+STDERR:5
+STEPSIZE:2
+STILL:7
+STR:4
+STRAIGHTFORWARD:2
+STREAM:38
+STREAMS:5
+STRING:11
+STRINGS:5
+STRUCT:21
+STRUCTURE:33
+STRUCTURES:6
+SUBSYSTEM:8
+SUCCESS:5
+SUCH:7
+SUFFICIENT:3
+SUGGEST:2
+SUN:2
+SUPPLIED:3
+SUPPORT:11
+SYNOPSIS:3
+SYSTEM:22
+SYSTEMS:2
+TABLES:2
+TAG:10
+TAGGED:4
+TAGGING:10
+TAGMODE:2
+TAKE:6
+TAKEN:2
+TAKES:2
+TALK:3
+TARGET:2
+TASK:2
+TCP:2
+TCPIP:5
+TCPIPSTRTOADDRCHAR:2
+TELL:4
+TELLS:3
+TERMINATED:2
+THAN:10
+THAT:125
+THE:916
+THEIR:3
+THEM:2
+THEN:8
+THERE:7
+THERES:4
+THESE:5
+THEY:12
+THING:4
+THINGS:5
+THINK:2
+THINOSI:3
+THIS:95
+THREE:5
+THROUGH:3
+TIME:7
+TIMEOUT:3
+TIMES:2
+TO:369
+TOO:5
+TOOLKIT:3
+TOP:3
+TOPLEVEL:8
+TRANSPARENT:2
+TRANSPORT:15
+TRIED:2
+TRY:3
+TSELECTOR:2
+TWO:10
+TYPE:67
+TYPEDEF:14
+TYPES:41
+TYPICAL:2
+TYPICALLY:9
+U:3
+UNDER:4
+UNDERLYING:2
+UNION:7
+UNIONNULL:2
+UNLESS:4
+UNPACKED:2
+UNTAGGED:2
+UNTIL:6
+UP:6
+UPDATE:2
+US:3
+USE:67
+USED:26
+USEFUL:9
+USER:4
+USERINFORMATIONFIELD:2
+USERS:4
+USING:18
+V:2
+VALP:3
+VALUE:39
+VALUES:7
+VARIABLE:2
+VARIABLES:3
+VERIFY:2
+VERSION:5
+VERY:3
+VISIBLESTRING:2
+VOID:29
+WANT:12
+WARRANTY:2
+WAS:10
+WAY:12
+WE:52
+WED:5
+WELL:22
+WENT:3
+WERE:2
+WHAT:2
+WHEN:49
+WHENEVER:2
+WHERE:9
+WHETHER:3
+WHICH:44
+WHICHP:2
+WHILE:8
+WHOLE:2
+WILL:91
+WISH:9
+WITH:58
+WITHIN:2
+WITHOUT:9
+WONT:2
+WORK:8
+WORKING:2
+WORKS:6
+WORRY:4
+WOULD:16
+WRITE:5
+WRITING:2
+WRITTEN:5
+X500:4
+XDR:4
+XMOSIH:3
+XTI:2
+XTIMOSI:11
+YAZ:25
+YET:6
+YOU:198
+YOULL:5
+YOUR:53
+YOURE:6
+YOURSELF:6
+Z:3
+Z3950:8
+Z39501994:2
+Z3950SR:4
+ZAPDU:5
+ZELEMENTSETNAMES:3
+ZERO:6
+ZGET:2
+ZINITREQUEST:3
+ZLISTSTATUSNULL:2
+ZRECORDS:2
+ZREFERENCEIDNULL:15
Index: /main/tags/2.25/gsdl/packages/yaz/ztest/read-grs.c
===================================================================
--- /main/tags/2.25/gsdl/packages/yaz/ztest/read-grs.c	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/yaz/ztest/read-grs.c	(revision 21064)
@@ -0,0 +1,125 @@
+/*
+ * Copyright (c) 1995-1999, Index Data.
+ * See the file LICENSE for details.
+ * Sebastian Hammer, Adam Dickmeiss
+ *
+ * $Log$
+ * Revision 1.1  2000/08/03 03:12:33  johnmcp
+ * Added the YAZ toolkit source to the packages directory (for z39.50 stuff)
+ *
+ * Revision 1.5  1999/11/30 13:47:12  adam
+ * Improved installation. Moved header files to include/yaz.
+ *
+ * Revision 1.4  1999/08/27 09:40:32  adam
+ * Renamed logf function to yaz_log. Removed VC++ project files.
+ *
+ * Revision 1.3  1999/03/31 11:18:25  adam
+ * Implemented odr_strdup. Added Reference ID to backend server API.
+ *
+ * Revision 1.2  1998/02/11 11:53:36  adam
+ * Changed code so that it compiles as C++.
+ *
+ * Revision 1.1  1997/09/01 08:55:53  adam
+ * New windows NT/95 port using MSV5.0. Test server ztest now in
+ * separate directory. When using NT, this test server may operate
+ * as an NT service. Note that the service.[ch] should be part of
+ * generic, but it isn't yet.
+ *
+ * Revision 1.1  1995/08/17 12:45:23  quinn
+ * Fixed minor problems with GRS-1. Added support in c&s.
+ *
+ *
+ */
+
+/*
+ * Little toy-thing to read a GRS-1 record from a file.
+ */
+
+#include <stdio.h>
+#include <ctype.h>
+#include <stdlib.h>
+
+#include <yaz/proto.h>
+#include <yaz/log.h>
+
+#define GRS_MAX_FIELDS 50
+
+Z_GenericRecord *read_grs1(FILE *f, ODR o)
+{
+    char line[512], *buf;
+    int type, ivalue;
+    char value[512];
+    Z_GenericRecord *r = 0;
+
+    for (;;)
+    {
+	Z_TaggedElement *t;
+	Z_ElementData *c;
+
+	while (fgets(buf = line, 512, f))
+	{
+	    while (*buf && isspace(*buf))
+		buf++;
+	    if (!*buf || *buf == '#')
+		continue;
+	    break;
+	}
+	if (*buf == '}')
+	    return r;
+	if (sscanf(buf, "(%d,%[^)])", &type, value) != 2)
+	{
+	    yaz_log(LOG_WARN, "Bad data in '%s'", buf);
+	    return 0;
+	}
+	if (!type && *value == '0')
+	    return r;
+	if (!(buf = strchr(buf, ')')))
+	    return 0;
+	buf++;
+	while (*buf && isspace(*buf))
+	    buf++;
+	if (!*buf)
+	    return 0;
+	if (!r)
+	{
+	    r = (Z_GenericRecord *)odr_malloc(o, sizeof(*r));
+	    r->elements = (Z_TaggedElement **)
+                odr_malloc(o, sizeof(Z_TaggedElement*) * GRS_MAX_FIELDS);
+	    r->num_elements = 0;
+	}
+	r->elements[r->num_elements] = t = (Z_TaggedElement *)
+            odr_malloc(o, sizeof(Z_TaggedElement));
+	t->tagType = (int *)odr_malloc(o, sizeof(int));
+	*t->tagType = type;
+	t->tagValue = (Z_StringOrNumeric *)
+            odr_malloc(o, sizeof(Z_StringOrNumeric));
+	if ((ivalue = atoi(value)))
+	{
+	    t->tagValue->which = Z_StringOrNumeric_numeric;
+	    t->tagValue->u.numeric = (int *)odr_malloc(o, sizeof(int));
+	    *t->tagValue->u.numeric = ivalue;
+	}
+	else
+	{
+	    t->tagValue->which = Z_StringOrNumeric_string;
+	    t->tagValue->u.string = (char *)odr_malloc(o, strlen(value)+1);
+	    strcpy(t->tagValue->u.string, value);
+	}
+	t->tagOccurrence = 0;
+	t->metaData = 0;
+	t->appliedVariant = 0;
+	t->content = c = (Z_ElementData *)odr_malloc(o, sizeof(Z_ElementData));
+	if (*buf == '{')
+	{
+	    c->which = Z_ElementData_subtree;
+	    c->u.subtree = read_grs1(f, o);
+	}
+	else
+	{
+	    c->which = Z_ElementData_string;
+	    buf[strlen(buf)-1] = '\0';
+	    c->u.string = odr_strdup(o, buf);
+	}
+	r->num_elements++;
+    }
+}
Index: /main/tags/2.25/gsdl/packages/yaz/ztest/ztest.c
===================================================================
--- /main/tags/2.25/gsdl/packages/yaz/ztest/ztest.c	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/yaz/ztest/ztest.c	(revision 21064)
@@ -0,0 +1,625 @@
+/*
+ * Copyright (c) 1995-2000, Index Data.
+ * See the file LICENSE for details.
+ *
+ * NT Service interface by
+ *    Chas Woodfield, Fretwell Downing Datasystems.
+ *
+ * $Log$
+ * Revision 1.1  2000/08/03 03:12:33  johnmcp
+ * Added the YAZ toolkit source to the packages directory (for z39.50 stuff)
+ *
+ * Revision 1.31  2000/01/31 13:15:21  adam
+ * Removed uses of assert(3). Cleanup of ODR. CCL parser update so
+ * that some characters are not surrounded by spaces in resulting term.
+ * ILL-code updates.
+ *
+ * Revision 1.30  2000/01/13 23:05:50  adam
+ * Fixed tagging for member requester-CHECKED-IN in ILL ASN.1 spec.
+ *
+ * Revision 1.29  2000/01/12 14:36:07  adam
+ * Added printing stream (ODR) for backend functions.
+ *
+ * Revision 1.28  1999/12/16 23:36:19  adam
+ * Implemented ILL protocol. Minor updates ASN.1 compiler.
+ *
+ * Revision 1.27  1999/11/30 13:47:12  adam
+ * Improved installation. Moved header files to include/yaz.
+ *
+ * Revision 1.26  1999/08/27 09:40:32  adam
+ * Renamed logf function to yaz_log. Removed VC++ project files.
+ *
+ * Revision 1.25  1999/06/01 14:29:12  adam
+ * Work on Extended Services.
+ *
+ * Revision 1.24  1999/05/27 13:07:54  adam
+ * Fix.
+ *
+ * Revision 1.23  1999/05/27 13:02:20  adam
+ * Assigned OID for old DB Update (VAL_DBUPDATE0).
+ *
+ * Revision 1.22  1999/05/26 13:49:12  adam
+ * DB Update implemented in client (very basic).
+ *
+ * Revision 1.21  1998/12/15 12:45:42  adam
+ * Minor change.
+ *
+ * Revision 1.20  1998/12/14 14:48:05  adam
+ * Fixed memory leak - happened when fetching MARC records.
+ *
+ * Revision 1.19  1998/10/20 15:16:22  adam
+ * Minor change to prevent warning.
+ *
+ * Revision 1.18  1998/10/20 15:13:45  adam
+ * Minor fix regarding output for Item Order.
+ *
+ * Revision 1.17  1998/10/18 22:33:35  quinn
+ * Added diagnostic dump of Item Order Eservice.
+ *
+ * Revision 1.16  1998/10/15 08:26:23  adam
+ * Added type cast to make C++ happy.
+ *
+ * Revision 1.15  1998/10/13 20:05:57  adam
+ * Minor change.
+ *
+ * Revision 1.14  1998/10/13 16:12:25  adam
+ * Added support for Surrogate Diagnostics for Scan Term entries.
+ *
+ * Revision 1.13  1998/08/19 16:10:09  adam
+ * Changed som member names of DeleteResultSetRequest/Response.
+ *
+ * Revision 1.12  1998/07/20 12:38:44  adam
+ * Implemented delete result set service to server API.
+ *
+ * Revision 1.11  1998/06/09 13:55:08  adam
+ * Minor changes.
+ *
+ * Revision 1.10  1998/05/27 16:55:54  adam
+ * Minor changes.
+ *
+ * Revision 1.9  1998/03/31 11:07:45  adam
+ * Furhter work on UNIverse resource report.
+ * Added Extended Services handling in frontend server.
+ *
+ * Revision 1.8  1998/02/11 11:53:36  adam
+ * Changed code so that it compiles as C++.
+ *
+ * Revision 1.7  1998/02/10 11:03:57  adam
+ * Added support for extended handlers in backend server interface.
+ *
+ * Revision 1.6  1998/01/29 13:16:02  adam
+ * Added dummy sort in test server.
+ *
+ * Revision 1.5  1997/11/07 13:31:58  adam
+ * Added NT Service name part of statserv_options_block. Moved NT
+ * service utility to server library.
+ *
+ * Revision 1.4  1997/09/17 12:10:43  adam
+ * YAZ version 1.4.
+ *
+ * Revision 1.3  1997/09/09 10:10:20  adam
+ * Another MSV5.0 port. Changed projects to include proper
+ * library/include paths.
+ * Server starts server in test-mode when no options are given.
+ *
+ * Revision 1.2  1997/09/04 13:50:31  adam
+ * Bug fix in ztest.
+ *
+ */
+
+/*
+ * Demonstration of simple server
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <ctype.h>
+
+#include <yaz/backend.h>
+#include <yaz/log.h>
+
+#ifdef ASN_COMPILED
+#include <yaz/ill.h>
+#endif
+
+Z_GenericRecord *read_grs1(FILE *f, ODR o);
+
+int ztest_search (void *handle, bend_search_rr *rr);
+int ztest_sort (void *handle, bend_sort_rr *rr);
+int ztest_present (void *handle, bend_present_rr *rr);
+int ztest_esrequest (void *handle, bend_esrequest_rr *rr);
+int ztest_delete (void *handle, bend_delete_rr *rr);
+
+bend_initresult *bend_init(bend_initrequest *q)
+{
+    bend_initresult *r = (bend_initresult *) odr_malloc (q->stream, sizeof(*r));
+    static char *dummy = "Hej fister";
+
+    r->errcode = 0;
+    r->errstring = 0;
+    r->handle = dummy;
+    q->bend_sort = ztest_sort;       /* register sort handler */
+    q->bend_search = ztest_search;   /* register search handler */
+    q->bend_present = ztest_present; /* register present handle */
+    q->bend_esrequest = ztest_esrequest;
+    q->bend_delete = ztest_delete;
+    return r;
+}
+
+int ztest_search (void *handle, bend_search_rr *rr)
+{
+    rr->hits = rand() % 22;
+    return 0;
+}
+
+int ztest_present (void *handle, bend_present_rr *rr)
+{
+    return 0;
+}
+
+int ztest_esrequest (void *handle, bend_esrequest_rr *rr)
+{
+    yaz_log(LOG_LOG, "function: %d", *rr->esr->function);
+    if (rr->esr->packageName)
+    	yaz_log(LOG_LOG, "packagename: %s", rr->esr->packageName);
+    yaz_log(LOG_LOG, "Waitaction: %d", *rr->esr->waitAction);
+
+    if (!rr->esr->taskSpecificParameters)
+    {
+        yaz_log (LOG_WARN, "No task specific parameters");
+    }
+    else if (rr->esr->taskSpecificParameters->which == Z_External_itemOrder)
+    {
+    	Z_ItemOrder *it = rr->esr->taskSpecificParameters->u.itemOrder;
+	yaz_log (LOG_LOG, "Received ItemOrder");
+	switch (it->which)
+	{
+#ifdef ASN_COMPILED
+	case Z_IOItemOrder_esRequest:
+#else
+	case Z_ItemOrder_esRequest:
+#endif
+	{
+	    Z_IORequest *ir = it->u.esRequest;
+	    Z_IOOriginPartToKeep *k = ir->toKeep;
+	    Z_IOOriginPartNotToKeep *n = ir->notToKeep;
+	    
+	    if (k && k->contact)
+	    {
+	        if (k->contact->name)
+		    yaz_log(LOG_LOG, "contact name %s", k->contact->name);
+		if (k->contact->phone)
+		    yaz_log(LOG_LOG, "contact phone %s", k->contact->phone);
+		if (k->contact->email)
+		    yaz_log(LOG_LOG, "contact email %s", k->contact->email);
+	    }
+	    if (k->addlBilling)
+	    {
+	        yaz_log(LOG_LOG, "Billing info (not shown)");
+	    }
+	    
+	    if (n->resultSetItem)
+	    {
+	        yaz_log(LOG_LOG, "resultsetItem");
+		yaz_log(LOG_LOG, "setId: %s", n->resultSetItem->resultSetId);
+		yaz_log(LOG_LOG, "item: %d", *n->resultSetItem->item);
+	    }
+#ifdef ASN_COMPILED
+	    if (n->itemRequest)
+	    {
+		Z_External *r = (Z_External*) n->itemRequest;
+		ILL_ItemRequest *item_req = 0;
+		ILL_Request *ill_req = 0;
+		if (r->direct_reference)
+		{
+		    oident *ent = oid_getentbyoid(r->direct_reference);
+		    if (ent)
+			yaz_log(LOG_LOG, "OID %s", ent->desc);
+		    if (ent && ent->value == VAL_ISO_ILL_1)
+		    {
+			yaz_log (LOG_LOG, "ItemRequest");
+			if (r->which == ODR_EXTERNAL_single)
+			{
+			    odr_setbuf(rr->decode,
+				       r->u.single_ASN1_type->buf,
+				       r->u.single_ASN1_type->len, 0);
+			    
+			    if (!ill_ItemRequest (rr->decode, &item_req, 0, 0))
+			    {
+				yaz_log (LOG_LOG,
+                                    "Couldn't decode ItemRequest %s near %d",
+                                       odr_errmsg(odr_geterror(rr->decode)),
+                                       odr_offset(rr->decode));
+                                yaz_log(LOG_LOG, "PDU dump:");
+                                odr_dumpBER(log_file(),
+                                     r->u.single_ASN1_type->buf,
+                                     r->u.single_ASN1_type->len);
+                            }
+			    if (rr->print)
+			    {
+				ill_ItemRequest (rr->print, &item_req, 0,
+                                    "ItemRequest");
+				odr_reset (rr->print);
+ 			    }
+			}
+			if (!item_req && r->which == ODR_EXTERNAL_single)
+			{
+			    yaz_log (LOG_LOG, "ILLRequest");
+			    odr_setbuf(rr->decode,
+				       r->u.single_ASN1_type->buf,
+				       r->u.single_ASN1_type->len, 0);
+			    
+			    if (!ill_Request (rr->decode, &ill_req, 0, 0))
+			    {
+				yaz_log (LOG_LOG,
+                                    "Couldn't decode ILLRequest %s near %d",
+                                       odr_errmsg(odr_geterror(rr->decode)),
+                                       odr_offset(rr->decode));
+                                yaz_log(LOG_LOG, "PDU dump:");
+                                odr_dumpBER(log_file(),
+                                     r->u.single_ASN1_type->buf,
+                                     r->u.single_ASN1_type->len);
+                            }
+			    if (rr->print)
+                            {
+				ill_Request (rr->print, &ill_req, 0,
+                                    "ILLRequest");
+				odr_reset (rr->print);
+			    }
+			}
+		    }
+		}
+		if (item_req)
+		{
+		    yaz_log (LOG_LOG, "ILL protocol version = %d",
+			     *item_req->protocol_version_num);
+		}
+	    }
+#endif
+	}
+	break;
+	}
+    }
+    else if (rr->esr->taskSpecificParameters->which == Z_External_update)
+    {
+    	Z_IUUpdate *up = rr->esr->taskSpecificParameters->u.update;
+	yaz_log (LOG_LOG, "Received DB Update");
+	if (up->which == Z_IUUpdate_esRequest)
+	{
+	    Z_IUUpdateEsRequest *esRequest = up->u.esRequest;
+	    Z_IUOriginPartToKeep *toKeep = esRequest->toKeep;
+	    Z_IUSuppliedRecords *notToKeep = esRequest->notToKeep;
+	    
+	    yaz_log (LOG_LOG, "action");
+	    if (toKeep->action)
+	    {
+		switch (*toKeep->action)
+		{
+		case Z_IUOriginPartToKeep_recordInsert:
+		    yaz_log (LOG_LOG, " recordInsert");
+		    break;
+		case Z_IUOriginPartToKeep_recordReplace:
+		    yaz_log (LOG_LOG, " recordUpdate");
+		    break;
+		case Z_IUOriginPartToKeep_recordDelete:
+		    yaz_log (LOG_LOG, " recordDelete");
+		    break;
+		case Z_IUOriginPartToKeep_elementUpdate:
+		    yaz_log (LOG_LOG, " elementUpdate");
+		    break;
+		case Z_IUOriginPartToKeep_specialUpdate:
+		    yaz_log (LOG_LOG, " specialUpdate");
+		    break;
+		default:
+		    yaz_log (LOG_LOG, " unknown (%d)", *toKeep->action);
+		}
+	    }
+	    if (toKeep->databaseName)
+	    {
+		yaz_log (LOG_LOG, "database: %s", toKeep->databaseName);
+		if (!strcmp(toKeep->databaseName, "fault"))
+		{
+		    rr->errcode = 109;
+		    rr->errstring = toKeep->databaseName;
+		}
+		if (!strcmp(toKeep->databaseName, "accept"))
+		    rr->errcode = -1;
+	    }
+	    if (notToKeep)
+	    {
+		int i;
+		for (i = 0; i < notToKeep->num; i++)
+		{
+		    Z_External *rec = notToKeep->elements[i]->record;
+
+		    if (rec->direct_reference)
+		    {
+			struct oident *oident;
+			oident = oid_getentbyoid(rec->direct_reference);
+			if (oident)
+			    yaz_log (LOG_LOG, "record %d type %s", i,
+				     oident->desc);
+		    }
+		    switch (rec->which)
+		    {
+		    case Z_External_sutrs:
+			if (rec->u.octet_aligned->len > 170)
+			    yaz_log (LOG_LOG, "%d bytes:\n%.168s ...",
+				     rec->u.sutrs->len,
+				     rec->u.sutrs->buf);
+			else
+			    yaz_log (LOG_LOG, "%d bytes:\n%s",
+				     rec->u.sutrs->len,
+				     rec->u.sutrs->buf);
+                        break;
+		    case Z_External_octet        :
+			if (rec->u.octet_aligned->len > 170)
+			    yaz_log (LOG_LOG, "%d bytes:\n%.168s ...",
+				     rec->u.octet_aligned->len,
+				     rec->u.octet_aligned->buf);
+			else
+			    yaz_log (LOG_LOG, "%d bytes\n%s",
+				     rec->u.octet_aligned->len,
+				     rec->u.octet_aligned->buf);
+		    }
+		}
+	    }
+	}
+    }
+    else
+    {
+        yaz_log (LOG_WARN, "Unknown Extended Service(%d)",
+		 rr->esr->taskSpecificParameters->which);
+	
+    }
+    return 0;
+}
+
+int ztest_delete (void *handle, bend_delete_rr *rr)
+{
+    if (rr->num_setnames == 1 && !strcmp (rr->setnames[0], "1"))
+	rr->delete_status = Z_DeleteStatus_success;
+    else
+        rr->delete_status = Z_DeleteStatus_resultSetDidNotExist;
+    return 0;
+}
+
+/* Obsolete bend_search, never called because handler is registered */
+bend_searchresult *bend_search(void *handle, bend_searchrequest *q, int *fd)
+{
+    return 0;
+}
+
+/* Our sort handler really doesn't sort... */
+int ztest_sort (void *handle, bend_sort_rr *rr)
+{
+    rr->errcode = 0;
+    rr->sort_status = Z_SortStatus_success;
+    return 0;
+}
+
+static int atoin (const char *buf, int n)
+{
+    int val = 0;
+    while (--n >= 0)
+    {
+        if (isdigit(*buf))
+            val = val*10 + (*buf - '0');
+        buf++;
+    }
+    return val;
+}
+
+char *marc_read(FILE *inf, ODR odr)
+{
+    char length_str[5];
+    size_t size;
+    char *buf;
+
+    if (fread (length_str, 1, 5, inf) != 5)
+        return NULL;
+    size = atoin (length_str, 5);
+    if (size <= 6)
+        return NULL;
+    if (!(buf = (char*) odr_malloc (odr, size+1)))
+        return NULL;
+    if (fread (buf+5, 1, size-5, inf) != (size-5))
+    {
+        xfree (buf);
+        return NULL;
+    }
+    memcpy (buf, length_str, 5);
+    buf[size] = '\0';
+    return buf;
+}
+
+static char *dummy_database_record (int num, ODR odr)
+{
+    FILE *inf = fopen ("dummy-records", "r");
+    char *buf = 0;
+
+    if (!inf)
+	return NULL;
+    while (--num >= 0)
+    {
+	if (num == 98)
+	{
+	    buf = (char*) odr_malloc(odr, 2101);
+	    memset(buf, 'A', 2100);
+	    buf[2100] = '\0';
+	    break;
+	}
+	else
+	    buf = marc_read (inf, odr);
+	if (!num || !buf)
+	    break;
+    }
+    fclose(inf);
+    if (num < 0)
+    	return 0;
+    return buf;
+}
+
+static Z_GenericRecord *dummy_grs_record (int num, ODR o)
+{
+    FILE *f = fopen("dummy-grs", "r");
+    char line[512];
+    Z_GenericRecord *r = 0;
+    int n;
+
+    if (!f)
+	return 0;
+    while (fgets(line, 512, f))
+	if (*line == '#' && sscanf(line, "#%d", &n) == 1 && n == num)
+	{
+	    r = read_grs1(f, o);
+	    break;
+	}
+    fclose(f);
+    return r;
+}
+
+bend_fetchresult *bend_fetch(void *handle, bend_fetchrequest *q, int *fd)
+{
+    bend_fetchresult *r = (bend_fetchresult *)
+			odr_malloc (q->stream, sizeof(*r));
+    char *cp;
+    r->errstring = 0;
+    r->last_in_set = 0;
+    r->basename = "DUMMY";
+    r->format = q->format;  
+    if (q->format == VAL_SUTRS)
+    {
+    	char buf[100];
+
+	sprintf(buf, "This is dummy SUTRS record number %d\n", q->number);
+	r->len = strlen(buf);
+	r->record = (char *) odr_malloc (q->stream, r->len+1);
+	strcpy(r->record, buf);
+    }
+    else if (q->format == VAL_GRS1)
+    {
+	r->len = -1;
+	r->record = (char*) dummy_grs_record(q->number, q->stream);
+	if (!r->record)
+	{
+	    r->errcode = 13;
+	    return r;
+	}
+    }
+    else if ((cp = dummy_database_record(q->number, q->stream)))
+    {
+	r->len = strlen(cp);
+	r->record = cp;
+	r->format = VAL_USMARC;
+    }
+    else
+    {
+    	r->errcode = 13;
+	return r;
+    }
+    r->errcode = 0;
+    return r;
+}
+
+/*
+ * silly dummy-scan what reads words from a file.
+ */
+bend_scanresult *bend_scan(void *handle, bend_scanrequest *q, int *fd)
+{
+    bend_scanresult *r = (bend_scanresult *)
+	odr_malloc (q->stream, sizeof(*r));
+    static FILE *f = 0;
+    static struct scan_entry list[200];
+    static char entries[200][80];
+    int hits[200];
+    char term[80], *p;
+    int i, pos;
+
+    r->errcode = 0;
+    r->errstring = 0;
+    r->entries = list;
+    r->status = BEND_SCAN_SUCCESS;
+    if (!f && !(f = fopen("dummy-words", "r")))
+    {
+	perror("dummy-words");
+	exit(1);
+    }
+    if (q->term->term->which != Z_Term_general)
+    {
+    	r->errcode = 229; /* unsupported term type */
+	return r;
+    }
+    if (q->term->term->u.general->len >= 80)
+    {
+    	r->errcode = 11; /* term too long */
+	return r;
+    }
+    if (q->num_entries > 200)
+    {
+    	r->errcode = 31;
+	return r;
+    }
+    memcpy(term, q->term->term->u.general->buf, q->term->term->u.general->len);
+    term[q->term->term->u.general->len] = '\0';
+    for (p = term; *p; p++)
+    	if (islower(*p))
+	    *p = toupper(*p);
+
+    fseek(f, 0, SEEK_SET);
+    r->num_entries = 0;
+    for (i = 0, pos = 0; fscanf(f, " %79[^:]:%d", entries[pos], &hits[pos]) == 2;
+	i++, pos < 199 ? pos++ : (pos = 0))
+    {
+    	if (!r->num_entries && strcmp(entries[pos], term) >= 0) /* s-point fnd */
+	{
+	    if ((r->term_position = q->term_position) > i + 1)
+	    {
+	    	r->term_position = i + 1;
+		r->status = BEND_SCAN_PARTIAL;
+	    }
+	    for (; r->num_entries < r->term_position; r->num_entries++)
+	    {
+	    	int po;
+
+		po = pos - r->term_position + r->num_entries + 1; /* find pos */
+		if (po < 0)
+		    po += 200;
+
+		if (!strcmp (term, "SD") && r->num_entries == 2)
+		{
+		    list[r->num_entries].term = entries[pos];
+		    list[r->num_entries].occurrences = -1;
+		    list[r->num_entries].errcode = 233;
+		    list[r->num_entries].errstring = "SD for Scan Term";
+		}
+		else
+		{
+		    list[r->num_entries].term = entries[po];
+		    list[r->num_entries].occurrences = hits[po];
+		}
+	    }
+	}
+	else if (r->num_entries)
+	{
+	    list[r->num_entries].term = entries[pos];
+	    list[r->num_entries].occurrences = hits[pos];
+	    r->num_entries++;
+	}
+	if (r->num_entries >= q->num_entries)
+	    break;
+    }
+    if (feof(f))
+    	r->status = BEND_SCAN_PARTIAL;
+    return r;
+}
+
+void bend_close(void *handle)
+{
+    return;
+}
+
+int main(int argc, char **argv)
+{
+    return statserv_main(argc, argv);
+}
Index: /main/tags/2.25/gsdl/packages/yaz/zutil/Makefile.am
===================================================================
--- /main/tags/2.25/gsdl/packages/yaz/zutil/Makefile.am	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/yaz/zutil/Makefile.am	(revision 21064)
@@ -0,0 +1,7 @@
+## $Id$
+noinst_LIBRARIES = libzutil.a
+
+INCLUDES=-I../include 
+
+libzutil_a_SOURCES = zget.c prt-ext.c yaz-ccl.c diagbib1.c logrpn.c \
+  otherinfo.c pquery.c
Index: /main/tags/2.25/gsdl/packages/yaz/zutil/Makefile.in
===================================================================
--- /main/tags/2.25/gsdl/packages/yaz/zutil/Makefile.in	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/yaz/zutil/Makefile.in	(revision 21064)
@@ -0,0 +1,268 @@
+# Makefile.in generated automatically by automake 1.4 from Makefile.am
+
+# Copyright (C) 1994, 1995-8, 1999 Free Software Foundation, Inc.
+# This Makefile.in is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
+# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE.
+
+
+SHELL = @SHELL@
+
+srcdir = @srcdir@
+top_srcdir = @top_srcdir@
+VPATH = @srcdir@
+prefix = @prefix@
+exec_prefix = @exec_prefix@
+
+bindir = @bindir@
+sbindir = @sbindir@
+libexecdir = @libexecdir@
+datadir = @datadir@
+sysconfdir = @sysconfdir@
+sharedstatedir = @sharedstatedir@
+localstatedir = @localstatedir@
+libdir = @libdir@
+infodir = @infodir@
+mandir = @mandir@
+includedir = @includedir@
+oldincludedir = /usr/include
+
+DESTDIR =
+
+pkgdatadir = $(datadir)/@PACKAGE@
+pkglibdir = $(libdir)/@PACKAGE@
+pkgincludedir = $(includedir)/@PACKAGE@
+
+top_builddir = ..
+
+ACLOCAL = @ACLOCAL@
+AUTOCONF = @AUTOCONF@
+AUTOMAKE = @AUTOMAKE@
+AUTOHEADER = @AUTOHEADER@
+
+INSTALL = @INSTALL@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@ $(AM_INSTALL_PROGRAM_FLAGS)
+INSTALL_DATA = @INSTALL_DATA@
+INSTALL_SCRIPT = @INSTALL_SCRIPT@
+transform = @program_transform_name@
+
+NORMAL_INSTALL = :
+PRE_INSTALL = :
+POST_INSTALL = :
+NORMAL_UNINSTALL = :
+PRE_UNINSTALL = :
+POST_UNINSTALL = :
+ASNMODULE = @ASNMODULE@
+CC = @CC@
+CPP = @CPP@
+ILLLIB = @ILLLIB@
+ILLMODULE = @ILLMODULE@
+MAKEINFO = @MAKEINFO@
+PACKAGE = @PACKAGE@
+RANLIB = @RANLIB@
+SUBDIRS_VAR = @SUBDIRS_VAR@
+VERSION = @VERSION@
+have_sgml2html = @have_sgml2html@
+have_sgml2latex = @have_sgml2latex@
+have_sgml2txt = @have_sgml2txt@
+
+noinst_LIBRARIES = libzutil.a
+
+INCLUDES = -I../include 
+
+libzutil_a_SOURCES = zget.c prt-ext.c yaz-ccl.c diagbib1.c logrpn.c   otherinfo.c pquery.c
+
+mkinstalldirs = $(SHELL) $(top_srcdir)/mkinstalldirs
+CONFIG_CLEAN_FILES = 
+LIBRARIES =  $(noinst_LIBRARIES)
+
+
+DEFS = @DEFS@ -I. -I$(srcdir) 
+CPPFLAGS = @CPPFLAGS@
+LDFLAGS = @LDFLAGS@
+LIBS = @LIBS@
+libzutil_a_LIBADD = 
+libzutil_a_OBJECTS =  zget.o prt-ext.o yaz-ccl.o diagbib1.o logrpn.o \
+otherinfo.o pquery.o
+AR = ar
+CFLAGS = @CFLAGS@
+COMPILE = $(CC) $(DEFS) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
+CCLD = $(CC)
+LINK = $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(LDFLAGS) -o $@
+DIST_COMMON =  Makefile.am Makefile.in
+
+
+DISTFILES = $(DIST_COMMON) $(SOURCES) $(HEADERS) $(TEXINFOS) $(EXTRA_DIST)
+
+TAR = gtar
+GZIP_ENV = --best
+SOURCES = $(libzutil_a_SOURCES)
+OBJECTS = $(libzutil_a_OBJECTS)
+
+all: all-redirect
+.SUFFIXES:
+.SUFFIXES: .S .c .o .s
+$(srcdir)/Makefile.in: Makefile.am $(top_srcdir)/configure.in $(ACLOCAL_M4) 
+	cd $(top_srcdir) && $(AUTOMAKE) --gnu --include-deps zutil/Makefile
+
+Makefile: $(srcdir)/Makefile.in  $(top_builddir)/config.status
+	cd $(top_builddir) \
+	  && CONFIG_FILES=$(subdir)/$@ CONFIG_HEADERS= $(SHELL) ./config.status
+
+
+mostlyclean-noinstLIBRARIES:
+
+clean-noinstLIBRARIES:
+	-test -z "$(noinst_LIBRARIES)" || rm -f $(noinst_LIBRARIES)
+
+distclean-noinstLIBRARIES:
+
+maintainer-clean-noinstLIBRARIES:
+
+.c.o:
+	$(COMPILE) -c $<
+
+.s.o:
+	$(COMPILE) -c $<
+
+.S.o:
+	$(COMPILE) -c $<
+
+mostlyclean-compile:
+	-rm -f *.o core *.core
+
+clean-compile:
+
+distclean-compile:
+	-rm -f *.tab.c
+
+maintainer-clean-compile:
+
+libzutil.a: $(libzutil_a_OBJECTS) $(libzutil_a_DEPENDENCIES)
+	-rm -f libzutil.a
+	$(AR) cru libzutil.a $(libzutil_a_OBJECTS) $(libzutil_a_LIBADD)
+	$(RANLIB) libzutil.a
+
+tags: TAGS
+
+ID: $(HEADERS) $(SOURCES) $(LISP)
+	list='$(SOURCES) $(HEADERS)'; \
+	unique=`for i in $$list; do echo $$i; done | \
+	  awk '    { files[$$0] = 1; } \
+	       END { for (i in files) print i; }'`; \
+	here=`pwd` && cd $(srcdir) \
+	  && mkid -f$$here/ID $$unique $(LISP)
+
+TAGS:  $(HEADERS) $(SOURCES)  $(TAGS_DEPENDENCIES) $(LISP)
+	tags=; \
+	here=`pwd`; \
+	list='$(SOURCES) $(HEADERS)'; \
+	unique=`for i in $$list; do echo $$i; done | \
+	  awk '    { files[$$0] = 1; } \
+	       END { for (i in files) print i; }'`; \
+	test -z "$(ETAGS_ARGS)$$unique$(LISP)$$tags" \
+	  || (cd $(srcdir) && etags $(ETAGS_ARGS) $$tags  $$unique $(LISP) -o $$here/TAGS)
+
+mostlyclean-tags:
+
+clean-tags:
+
+distclean-tags:
+	-rm -f TAGS ID
+
+maintainer-clean-tags:
+
+distdir = $(top_builddir)/$(PACKAGE)-$(VERSION)/$(subdir)
+
+subdir = zutil
+
+distdir: $(DISTFILES)
+	@for file in $(DISTFILES); do \
+	  d=$(srcdir); \
+	  if test -d $$d/$$file; then \
+	    cp -pr $$/$$file $(distdir)/$$file; \
+	  else \
+	    test -f $(distdir)/$$file \
+	    || ln $$d/$$file $(distdir)/$$file 2> /dev/null \
+	    || cp -p $$d/$$file $(distdir)/$$file || :; \
+	  fi; \
+	done
+
+info-am:
+info: info-am
+dvi-am:
+dvi: dvi-am
+check-am: all-am
+check: check-am
+installcheck-am:
+installcheck: installcheck-am
+install-exec-am:
+install-exec: install-exec-am
+
+install-data-am:
+install-data: install-data-am
+
+install-am: all-am
+	@$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
+install: install-am
+uninstall-am:
+uninstall: uninstall-am
+all-am: Makefile $(LIBRARIES)
+all-redirect: all-am
+install-strip:
+	$(MAKE) $(AM_MAKEFLAGS) AM_INSTALL_PROGRAM_FLAGS=-s install
+installdirs:
+
+
+mostlyclean-generic:
+
+clean-generic:
+
+distclean-generic:
+	-rm -f Makefile $(CONFIG_CLEAN_FILES)
+	-rm -f config.cache config.log stamp-h stamp-h[0-9]*
+
+maintainer-clean-generic:
+mostlyclean-am:  mostlyclean-noinstLIBRARIES mostlyclean-compile \
+		mostlyclean-tags mostlyclean-generic
+
+mostlyclean: mostlyclean-am
+
+clean-am:  clean-noinstLIBRARIES clean-compile clean-tags clean-generic \
+		mostlyclean-am
+
+clean: clean-am
+
+distclean-am:  distclean-noinstLIBRARIES distclean-compile \
+		distclean-tags distclean-generic clean-am
+
+distclean: distclean-am
+
+maintainer-clean-am:  maintainer-clean-noinstLIBRARIES \
+		maintainer-clean-compile maintainer-clean-tags \
+		maintainer-clean-generic distclean-am
+	@echo "This command is intended for maintainers to use;"
+	@echo "it deletes files that may require special tools to rebuild."
+
+maintainer-clean: maintainer-clean-am
+
+.PHONY: mostlyclean-noinstLIBRARIES distclean-noinstLIBRARIES \
+clean-noinstLIBRARIES maintainer-clean-noinstLIBRARIES \
+mostlyclean-compile distclean-compile clean-compile \
+maintainer-clean-compile tags mostlyclean-tags distclean-tags \
+clean-tags maintainer-clean-tags distdir info-am info dvi-am dvi check \
+check-am installcheck-am installcheck install-exec-am install-exec \
+install-data-am install-data install-am install uninstall-am uninstall \
+all-redirect all-am all installdirs mostlyclean-generic \
+distclean-generic clean-generic maintainer-clean-generic clean \
+mostlyclean distclean maintainer-clean
+
+
+# Tell versions [3.59,3.63) of GNU make to not export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:
Index: /main/tags/2.25/gsdl/packages/yaz/zutil/diagbib1.c
===================================================================
--- /main/tags/2.25/gsdl/packages/yaz/zutil/diagbib1.c	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/yaz/zutil/diagbib1.c	(revision 21064)
@@ -0,0 +1,195 @@
+/*
+ * Copyright (c) 1995-1997, Index Data
+ * See the file LICENSE for details.
+ * Sebastian Hammer, Adam Dickmeiss
+ *
+ * $Log$
+ * Revision 1.1  2000/08/03 03:12:35  johnmcp
+ * Added the YAZ toolkit source to the packages directory (for z39.50 stuff)
+ *
+ * Revision 1.2  1999/11/30 13:47:12  adam
+ * Improved installation. Moved header files to include/yaz.
+ *
+ * Revision 1.1  1999/06/08 10:10:16  adam
+ * New sub directory zutil. Moved YAZ Compiler to be part of YAZ tree.
+ *
+ * Revision 1.7  1997/09/29 07:22:26  adam
+ * Added static modifier to msg_tab.
+ *
+ * Revision 1.6  1997/07/01 14:15:10  adam
+ * Added new BIB-1 diagnostic messages.
+ *
+ * Revision 1.5  1996/01/02 13:57:30  adam
+ * Added error messages.
+ *
+ * Revision 1.4  1995/09/29  17:11:52  quinn
+ * Smallish
+ *
+ * Revision 1.3  1995/09/27  15:02:39  quinn
+ * Modified function heads & prototypes.
+ *
+ * Revision 1.2  1995/05/16  08:50:21  quinn
+ * License, documentation, and memory fixes
+ *
+ * Revision 1.1  1995/03/15  13:46:09  adam
+ * New function diagbib1_str.
+ *
+ */
+
+#include <stdio.h>
+
+#include <yaz/diagbib1.h>
+
+static struct {
+    int code;
+    char *msg;
+} msg_tab[] = {
+{ 1, "Permanent system error" },
+{ 2, "Temporary system error" },
+{ 3, "Unsupported search" },
+{ 4, "Terms only exclusion (stop) words" },
+{ 5, "Too many argument words" },
+{ 6, "Too many boolean operators" },
+{ 7, "Too many truncated words" },
+{ 8, "Too many incomplete subfields" },
+{ 9, "Truncated words too short" },
+{ 10, "Invalid format for record number (search term)" },
+{ 11, "Too many characters in search statement" },
+{ 12, "Too many records retrieved" },
+{ 13, "Present request out of range" },
+{ 14, "System error in presenting records" },
+{ 15, "Record no authorized to be sent intersystem" },
+{ 16, "Record exceeds Preferred-message-size" },
+{ 17, "Record exceeds Maximum-record-size" },
+{ 18, "Result set not supported as a search term" },
+{ 19, "Only single result set as search term supported" },
+{ 20, "Only ANDing of a single result set as search term supported" },
+{ 21, "Result set exists and replace indicator off" },
+{ 22, "Result set naming not supported" },
+{ 23, "Combination of specified databases not supported" },
+{ 24, "Element set names not supported" },
+{ 25, "Specified element set name not valid for specified database" },
+{ 26, "Only a single element set name supported" },
+{ 27, "Result set no longer exists - unilaterally deleted by target" },
+{ 28, "Result set is in use" },
+{ 29, "One of the specified databases is locked" },
+{ 30, "Specified result set does not exist" },
+{ 31, "Resources exhausted - no results available" },
+{ 32, "Resources exhausted - unpredictable partial results available" },
+{ 33, "Resources exhausted - valid subset of results available" },
+{ 100, "Unspecified error" },
+{ 101, "Access-control failure" },
+{ 102, "Security challenge required but could not be issued -"
+" request terminated" },
+{ 103, "Security challenge required but could not be issued -"
+" record not included" },
+{ 104, "Security challenge failed - record not included" },
+{ 105, "Terminated by negative continue response" },
+{ 106, "No abstract syntaxes agreed to for this record" },
+{ 107, "Query type not supported" },
+{ 108, "Malformed query" },
+{ 109, "Database unavailable" },
+{ 110, "Operator unsupported" },
+{ 111, "Too many databases specified" },
+{ 112, "Too many result sets created" },
+{ 113, "Unsupported attribute type" },
+{ 114, "Unsupported Use attribute" },
+{ 115, "Unsupported value for Use attribute" },
+{ 116, "Use attribute required but not supplied" },
+{ 117, "Unsupported Relation attribute" },
+{ 118, "Unsupported Structure attribute" },
+{ 119, "Unsupported Position attribute" },
+{ 120, "Unsupported Truncation attribute" },
+{ 121, "Unsupported Attribute Set" },
+{ 122, "Unsupported Completeness attribute" },
+{ 123, "Unsupported attribute combination" },
+{ 124, "Unsupported coded value for term" },
+{ 125, "Malformed search term" },
+{ 126, "Illegal term value for attribute" },
+{ 127, "Unparsable format for un-normalized value" },
+{ 128, "Illegal result set name" },
+{ 129, "Proximity search of sets not supported" },
+{ 130, "Illegal result set in proximity search" },
+{ 131, "Unsupported proximity relation" },
+{ 132, "Unsupported proximity unit code" },
+{ 201, "Proximity not supported with this attribute combination" },
+{ 202, "Unsupported distance for proximity" },
+{ 203, "Ordered flag not supported for proximity" },
+{ 205, "Only zero step size supported for Scan" },
+{ 206, "Specified step size not supported for Scan" },
+{ 207, "Cannot sort according to sequence" },
+{ 208, "No result set name supplied on Sort" },
+{ 209, "Generic sort not supported (database-specific sort only supported)" },
+{ 210, "Database specific sort not supported" },
+{ 211, "Too many sort keys" },
+{ 212, "Duplicate sort keys" },
+{ 213, "Unsupported missing data action" },
+{ 214, "Illegal sort relation" },
+{ 215, "Illegal case value" },
+{ 216, "Illegal missing data action" },
+{ 217, "Segmentation: Cannot guarantee records will fit in specified segments"
+},
+{ 218, "ES: Package name already in use" },
+{ 219, "ES: no such package, on modify/delete" },
+{ 220, "ES: quota exceeded" },
+{ 221, "ES: extended service type not supported" },
+{ 222, "ES: permission denied on ES - id not authorized" },
+{ 223, "ES: permission denied on ES - cannot modify or delete" },
+{ 224, "ES: immediate execution failed" },
+{ 225, "ES: immediate execution not supported for this service" },
+{ 226, "ES: immediate execution not supported for these parameters" },
+{ 227, "No data available in requested record syntax" },
+{ 228, "Scan: malformed scan" },
+{ 229, "Term type not supported" },
+{ 230, "Sort: too many input results" },
+{ 231, "Sort: incompatible record formats" },
+{ 232, "Scan: term list not supported" },
+{ 233, "Scan: unsupported value of position-in-response" },
+{ 234, "Too many index terms processed" },
+{ 235, "Database does not exist" },
+{ 236, "Access to specified database denied" },
+{ 237, "Sort: illegal sort" },
+{ 238, "Record not available in requested syntax" },
+{ 239, "Record syntax not supported" },
+{ 240, "Scan: Resources exhausted looking for satisfying terms" },
+{ 241, "Scan: Beginning or end of term list" },
+{ 242, "Segmentation: max-segment-size too small to segment record" },
+{ 243, "Present:  additional-ranges parameter not supported" },
+{ 244, "Present:  comp-spec parameter not supported" },
+{ 245, "Type-1 query: restriction ('resultAttr') operand not supported" },
+{ 246, "Type-1 query: 'complex' attributeValue not supported" },
+{ 247, "Type-1 query: 'attributeSet' as part of AttributeElement not supported" },
+{ 1001, "Malformed APDU"}, 
+{ 1002, "ES: EXTERNAL form of Item Order request not supported" },
+{ 1003, "ES: Result set item form of Item Order request not supported" },
+{ 1004, "ES: Extended services not supported unless access control is in effect" },
+{ 1005, "Response records in Search response not supported" },
+{ 1006, "Response records in Search response not possible for specified database (or database combination)" },
+{ 1007, "No Explain server. Addinfo: pointers to servers that have a surrogate Explain database for this server" },
+{ 1008, "ES: missing mandatory parameter for specified function. Addinfo: parameter" },
+{ 1009, "ES: Item Order, unsupported OID in itemRequest. Addinfo: OID" },
+{ 1010, "Init/AC: Bad Userid" },
+{ 1011, "Init/AC: Bad Userid and/or Password" },
+{ 1012, "Init/AC: No searches remaining (pre-purchased searches exhausted)" },
+{ 1013, "Init/AC: Incorrect interface type (specified id valid only when used with a particular access method or client)" },
+{ 1014, "Init/AC: Authentication System error" },
+{ 1015, "Init/AC: Maximum number of simultaneous sessions for Userid" },
+{ 1016, "Init/AC: Blocked network address"},
+{ 1017, "Init/AC: No databases available for specified userId"},
+{ 1018, "Init/AC: System temporarily out of resources"},
+{ 1019, "Init/AC: System not available due to maintenance (Addinfo: when it's expected back up)" },
+{ 1020, "Init/AC: System temporarily unavailable (Addinfo: when it's expected back up)"},
+{ 1021, "Init/AC: Account has expired"},
+{ 1022, "Init/AC: Password has expired so a new one must be supplied"},
+{ 1023, "Init/AC: Password has been changed by an administrator so a new one must be supplied"},
+{ 0, NULL} 
+};
+
+const char *diagbib1_str (int code)
+{
+    int i;
+    for (i=0; msg_tab[i].msg; i++)
+        if (msg_tab[i].code == code)
+            return msg_tab[i].msg;
+    return "Unknown error";
+}
Index: /main/tags/2.25/gsdl/packages/yaz/zutil/logrpn.c
===================================================================
--- /main/tags/2.25/gsdl/packages/yaz/zutil/logrpn.c	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/yaz/zutil/logrpn.c	(revision 21064)
@@ -0,0 +1,383 @@
+/*
+ * Copyright (C) 1995-2000, Index Data
+ * All rights reserved.
+ * Sebastian Hammer, Adam Dickmeiss
+ *
+ * $Log$
+ * Revision 1.1  2000/08/03 03:12:36  johnmcp
+ * Added the YAZ toolkit source to the packages directory (for z39.50 stuff)
+ *
+ * Revision 1.4  2000/01/31 13:15:22  adam
+ * Removed uses of assert(3). Cleanup of ODR. CCL parser update so
+ * that some characters are not surrounded by spaces in resulting term.
+ * ILL-code updates.
+ *
+ * Revision 1.3  1999/11/30 13:47:12  adam
+ * Improved installation. Moved header files to include/yaz.
+ *
+ * Revision 1.2  1999/08/27 09:40:33  adam
+ * Renamed logf function to yaz_log. Removed VC++ project files.
+ *
+ * Revision 1.1  1999/06/08 10:10:16  adam
+ * New sub directory zutil. Moved YAZ Compiler to be part of YAZ tree.
+ *
+ * Revision 1.1  1998/11/16 16:02:35  adam
+ * Added loggin utilies, log_rpn_query and log_scan_term. These used
+ * to be part of Zebra.
+ *
+ *
+ *
+ * Old logs from zlogs.c:
+ *
+ * Revision 1.9  1998/10/13 20:36:02  adam
+ * Changed "indent" format string in log messages.
+ *
+ * Revision 1.8  1998/04/02 14:35:29  adam
+ * First version of Zebra that works with compiled ASN.1.
+ *
+ * Revision 1.7  1998/01/29 13:40:11  adam
+ * Better logging for scan service.
+ *
+ * Revision 1.6  1997/09/29 09:06:41  adam
+ * Removed static var to make this module thread safe.
+ *
+ * Revision 1.5  1997/04/30 08:56:07  quinn
+ * null
+ *
+ * Revision 1.4  1996/10/08  09:41:25  quinn
+ * Fixed diagnostic.
+ *
+ * Revision 1.3  1996/03/20  09:36:40  adam
+ * Function dict_lookup_grep got extra parameter, init_pos, which marks
+ * from which position in pattern approximate pattern matching should occur.
+ * Approximate pattern matching is used in relevance=re-2.
+ *
+ * Revision 1.2  1996/01/03  16:22:11  quinn
+ * operator->roperator
+ *
+ * Revision 1.1  1995/11/16  17:00:55  adam
+ * Better logging of rpn query.
+ *
+ */
+#include <stdio.h>
+
+#include <yaz/log.h>
+#include <yaz/logrpn.h>
+
+static void attrStr (int type, int value, enum oid_value ast, char *str)
+{
+    *str = '\0';
+    switch (ast)
+    {
+    case VAL_BIB1:
+    case VAL_EXP1:
+    case VAL_GILS:
+        switch (type)
+        {
+        case 1:
+            sprintf (str, "use");
+            break;
+        case 2:
+            switch (value)
+            {
+            case 1:
+                sprintf (str, "relation=Less than");
+                break;
+            case 2:
+                sprintf (str, "relation=Less than or equal");
+                break;
+            case 3:
+                sprintf (str, "relation=Equal");
+                break;
+            case 4:
+                sprintf (str, "relation=Greater or equal");
+                break;
+            case 5:
+                sprintf (str, "relation=Greater than");
+                break;
+            case 6:
+                sprintf (str, "relation=Not equal");
+                break;
+            case 100:
+                sprintf (str, "relation=Phonetic");
+                break;
+            case 101:
+                sprintf (str, "relation=Stem");
+                break;
+            case 102:
+                sprintf (str, "relation=Relevance");
+                break;
+            case 103:
+                sprintf (str, "relation=AlwaysMatches");
+                break;
+            default:
+                sprintf (str, "relation");
+            }
+            break;
+        case 3:
+            switch (value)
+            {
+            case 1:
+                sprintf (str, "position=First in field");
+                break;
+            case 2:
+                sprintf (str, "position=First in any subfield");
+                break;
+            case 3:
+                sprintf (str, "position=Any position in field");
+                break;
+            default:
+                sprintf (str, "position");
+            }
+            break;
+        case 4:
+            switch (value)
+            {
+            case 1:
+                sprintf (str, "structure=Phrase");
+                break;
+            case 2:
+                sprintf (str, "structure=Word");
+                break;
+            case 3:
+                sprintf (str, "structure=Key");
+                break;
+            case 4:
+                sprintf (str, "structure=Year");
+                break;
+            case 5:
+                sprintf (str, "structure=Date");
+                break;
+            case 6:
+                sprintf (str, "structure=Word list");
+                break;
+            case 100:
+                sprintf (str, "structure=Date (un)");
+                break;
+            case 101:
+                sprintf (str, "structure=Name (norm)");
+                break;
+            case 102:
+                sprintf (str, "structure=Name (un)");
+                break;
+            case 103:
+                sprintf (str, "structure=Structure");
+                break;
+            case 104:
+                sprintf (str, "structure=urx");
+                break;
+            case 105:
+                sprintf (str, "structure=free-form-text");
+                break;
+            case 106:
+                sprintf (str, "structure=document-text");
+                break;
+            case 107:
+                sprintf (str, "structure=local-number");
+                break;
+            case 108:
+                sprintf (str, "structure=string");
+                break;
+            case 109:
+                sprintf (str, "structure=numeric string");
+                break;
+            default:
+                sprintf (str, "structure");
+            }
+            break;
+        case 5:
+            switch (value)
+            {
+            case 1:
+                sprintf (str, "truncation=Right");
+                break;
+            case 2:
+                sprintf (str, "truncation=Left");
+                break;
+            case 3:
+                sprintf (str, "truncation=Left&right");
+                break;
+            case 100:
+                sprintf (str, "truncation=Do not truncate");
+                break;
+            case 101:
+                sprintf (str, "truncation=Process #");
+                break;
+            case 102:
+                sprintf (str, "truncation=re-1");
+                break;
+            case 103:
+                sprintf (str, "truncation=re-2");
+                break;
+            default:
+                sprintf (str, "truncation");
+            }
+            break;
+        case 6:
+            switch (value)
+            {
+            case 1:
+                sprintf (str, "completeness=Incomplete subfield");
+                break;
+            case 2:
+                sprintf (str, "completeness=Complete subfield");
+                break;
+            case 3:
+                sprintf (str, "completeness=Complete field");
+                break;
+            default:
+                sprintf (str, "completeness");
+            }
+            break;
+        }
+        break;
+    default:
+        break;
+    }
+    if (*str)
+        sprintf (str + strlen(str), " (%d=%d)", type, value);
+    else
+        sprintf (str, "%d=%d", type, value);
+}
+
+/*
+ * zlog_attributes: print attributes of term
+ */
+static void zlog_attributes (Z_AttributesPlusTerm *t, int level,
+                             enum oid_value ast)
+{
+    int of, i;
+    char str[80];
+#ifdef ASN_COMPILED
+    int num_attributes = t->attributes->num_attributes;
+#else
+    int num_attributes = t->num_attributes;
+#endif
+    
+    for (of = 0; of < num_attributes; of++)
+    {
+	const char *attset_name = "";
+        Z_AttributeElement *element;
+#ifdef ASN_COMPILED
+	element = t->attributes->attributes[of];
+#else
+        element = t->attributeList[of];
+#endif
+	if (element->attributeSet)
+	{
+	    oident *attrset;
+	    attrset = oid_getentbyoid (element->attributeSet);
+	    attset_name = attrset->desc;
+	}
+        switch (element->which) 
+        {
+        case Z_AttributeValue_numeric:
+	    attrStr (*element->attributeType,
+		     *element->value.numeric, ast, str);
+            yaz_log (LOG_LOG, "%*.0s%s %s", level, "", attset_name, str);
+            break;
+        case Z_AttributeValue_complex:
+            yaz_log (LOG_LOG, "%*.0s%s attributeType=%d complex",
+		  level, "", attset_name, *element->attributeType);
+            for (i = 0; i<element->value.complex->num_list; i++)
+            {
+                if (element->value.complex->list[i]->which ==
+                    Z_StringOrNumeric_string)
+                    yaz_log (LOG_LOG, "%*.0s  string: '%s'", level, "",
+			     element->value.complex->list[i]->u.string);
+                else if (element->value.complex->list[i]->which ==
+                         Z_StringOrNumeric_numeric)
+                    yaz_log (LOG_LOG, "%*.0s  numeric: '%d'", level, "",
+			     *element->value.complex->list[i]->u.numeric);
+            }
+            break;
+        default:
+            yaz_log (LOG_LOG, "%.*s%s attribute unknown",
+		     level, "", attset_name);
+        }
+    }
+}
+
+static void zlog_structure (Z_RPNStructure *zs, int level, enum oid_value ast)
+{
+    if (zs->which == Z_RPNStructure_complex)
+    {
+        switch (zs->u.complex->roperator->which)
+        {
+        case Z_Operator_and:
+            yaz_log (LOG_LOG, "%*.0s and", level, "");
+            break;
+        case Z_Operator_or:
+            yaz_log (LOG_LOG, "%*.0s or", level, "");
+            break;
+        case Z_Operator_and_not:
+            yaz_log (LOG_LOG, "%*.0s and-not", level, "");
+            break;
+        default:
+            yaz_log (LOG_LOG, "%*.0s unknown complex", level, "");
+            return;
+        }
+        zlog_structure (zs->u.complex->s1, level+2, ast);
+        zlog_structure (zs->u.complex->s2, level+2, ast);
+    }
+    else if (zs->which == Z_RPNStructure_simple)
+    {
+        if (zs->u.simple->which == Z_Operand_APT)
+        {
+            Z_AttributesPlusTerm *zapt = zs->u.simple->u.attributesPlusTerm;
+
+            if (zapt->term->which == Z_Term_general) 
+            {
+                yaz_log (LOG_LOG, "%*.0s term '%.*s' (general)", level, "",
+			 zapt->term->u.general->len,
+			 zapt->term->u.general->buf);
+            }
+            else
+            {
+                yaz_log (LOG_LOG, "%*.0s term (not general)", level, "");
+            }
+            zlog_attributes (zapt, level+2, ast);
+        }
+        else if (zs->u.simple->which == Z_Operand_resultSetId)
+        {
+            yaz_log (LOG_LOG, "%*.0s set '%s'", level, "",
+		     zs->u.simple->u.resultSetId);
+        }
+        else
+            yaz_log (LOG_LOG, "%*.0s unknown simple structure", level, "");
+    }
+    else
+        yaz_log (LOG_LOG, "%*.0s unknown structure", level, "");
+}
+
+void log_rpn_query (Z_RPNQuery *rpn)
+{
+    oident *attrset;
+    enum oid_value ast;
+    
+    attrset = oid_getentbyoid (rpn->attributeSetId);
+    if (attrset)
+    {
+        ast = attrset->value;
+	yaz_log (LOG_LOG, "RPN query. Type: %s", attrset->desc);
+    } 
+    else
+    {
+	ast = VAL_NONE;
+	yaz_log (LOG_LOG, "RPN query. Unknown type");
+    }
+    zlog_structure (rpn->RPNStructure, 0, ast);
+}
+
+void log_scan_term (Z_AttributesPlusTerm *zapt, oid_value ast)
+{
+    int level = 0;
+    if (zapt->term->which == Z_Term_general) 
+    {
+	yaz_log (LOG_LOG, "%*.0s term '%.*s' (general)", level, "",
+		 zapt->term->u.general->len, zapt->term->u.general->buf);
+    }
+    else
+	yaz_log (LOG_LOG, "%*.0s term (not general)", level, "");
+    zlog_attributes (zapt, level+2, ast);
+}
Index: /main/tags/2.25/gsdl/packages/yaz/zutil/otherinfo.c
===================================================================
--- /main/tags/2.25/gsdl/packages/yaz/zutil/otherinfo.c	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/yaz/zutil/otherinfo.c	(revision 21064)
@@ -0,0 +1,223 @@
+/*
+ * Copyright (c) 1999, Index Data
+ * See the file LICENSE for details.
+ * Sebastian Hammer, Adam Dickmeiss
+ *
+ * $Log$
+ * Revision 1.1  2000/08/03 03:12:36  johnmcp
+ * Added the YAZ toolkit source to the packages directory (for z39.50 stuff)
+ *
+ * Revision 1.4  1999/11/30 13:47:12  adam
+ * Improved installation. Moved header files to include/yaz.
+ *
+ * Revision 1.3  1999/11/10 09:06:40  adam
+ * Fixed yaz_oi_update so that it ignores NULL pointer.
+ *
+ * Revision 1.2  1999/09/13 12:51:35  adam
+ * Fixed bug in yaz_oi_update and added delete option.
+ *
+ * Revision 1.1  1999/06/08 10:10:16  adam
+ * New sub directory zutil. Moved YAZ Compiler to be part of YAZ tree.
+ *
+ * Revision 1.1  1999/04/26 07:25:25  adam
+ * Implemented OtherInfo utility.
+ *
+ */
+
+#include <stdio.h>
+#include <string.h>
+
+#include <yaz/otherinfo.h>
+
+void yaz_oi_APDU(Z_APDU *apdu, Z_OtherInformation ***oip)
+{
+    switch (apdu->which)
+    {
+    case Z_APDU_initRequest:
+	*oip = &apdu->u.initRequest->otherInfo;
+	break;
+    case Z_APDU_searchRequest:
+	*oip = &apdu->u.searchRequest->otherInfo;
+	break;
+    case Z_APDU_presentRequest:
+	*oip = &apdu->u.presentRequest->otherInfo;
+	break;
+    case Z_APDU_sortRequest:
+	*oip = &apdu->u.sortRequest->otherInfo;
+	break;
+    case Z_APDU_scanRequest:
+	*oip = &apdu->u.scanRequest->otherInfo;
+	break;
+    case Z_APDU_extendedServicesRequest:
+	*oip = &apdu->u.extendedServicesRequest->otherInfo;
+	break;
+    case Z_APDU_deleteResultSetRequest:
+	*oip = &apdu->u.deleteResultSetRequest->otherInfo;
+	break;
+    case Z_APDU_initResponse:
+	*oip = &apdu->u.initResponse->otherInfo;
+	break;
+    case Z_APDU_searchResponse:
+	*oip = &apdu->u.searchResponse->otherInfo;
+	break;
+    case Z_APDU_presentResponse:
+	*oip = &apdu->u.presentResponse->otherInfo;
+	break;
+    case Z_APDU_sortResponse:
+	*oip = &apdu->u.sortResponse->otherInfo;
+	break;
+    case Z_APDU_scanResponse:
+	*oip = &apdu->u.scanResponse->otherInfo;
+	break;
+    case Z_APDU_extendedServicesResponse:
+	*oip = &apdu->u.extendedServicesResponse->otherInfo;
+	break;
+    case Z_APDU_deleteResultSetResponse:
+	*oip = &apdu->u.deleteResultSetResponse->otherInfo;
+	break;
+    default:
+	*oip = 0;
+	break;
+    }
+}
+
+Z_OtherInformationUnit *yaz_oi_update (
+    Z_OtherInformation **otherInformationP, ODR odr,
+    int *oid, int categoryValue, int delete_flag)
+{
+    int i;
+    Z_OtherInformation *otherInformation;
+
+    if (!otherInformationP)
+        return 0;
+    otherInformation = *otherInformationP;
+    if (!otherInformation)
+    {
+	if (!odr)
+	    return 0;
+	otherInformation = *otherInformationP = (Z_OtherInformation *)
+	    odr_malloc (odr, sizeof(*otherInformation));
+	otherInformation->num_elements = 0;
+	otherInformation->list = 0;
+    }
+    for (i = 0; i<otherInformation->num_elements; i++)
+    {
+	if (!oid)
+	{
+	    if (!otherInformation->list[i]->category)
+		return otherInformation->list[i];
+	}
+	else
+	{
+	    if (otherInformation->list[i]->category &&
+		categoryValue ==
+		*otherInformation->list[i]->category->categoryValue &&
+		!oid_oidcmp (oid, otherInformation->list[i]->category->
+			     categoryTypeId))
+	    {
+		Z_OtherInformationUnit *this_list = otherInformation->list[i];
+
+		if (delete_flag)
+		{
+		    (otherInformation->num_elements)--;
+		    while (i < otherInformation->num_elements)
+		    {
+			otherInformation->list[i] =
+			    otherInformation->list[i+1];
+			i++;
+		    }
+		}
+		return this_list;
+	    }
+	}
+    }
+    if (!odr)
+	return 0;
+    else
+    {
+	Z_OtherInformationUnit **newlist = (Z_OtherInformationUnit**)
+	    odr_malloc(odr, (otherInformation->num_elements+1) *
+		       sizeof(*newlist));
+	for (i = 0; i<otherInformation->num_elements; i++)
+	    newlist[i] = otherInformation->list[i];
+	otherInformation->list = newlist;
+	
+	otherInformation->list[i] = (Z_OtherInformationUnit*)
+	    odr_malloc (odr, sizeof(Z_OtherInformationUnit));
+	if (oid)
+	{
+	    otherInformation->list[i]->category = (Z_InfoCategory*)
+		odr_malloc (odr, sizeof(Z_InfoCategory));
+	    otherInformation->list[i]->category->categoryTypeId = (int*)
+		odr_oiddup (odr, oid);
+	    otherInformation->list[i]->category->categoryValue = (int*)
+		odr_malloc (odr, sizeof(int));
+	    *otherInformation->list[i]->category->categoryValue =
+		categoryValue;
+	}
+	else
+	    otherInformation->list[i]->category = 0;
+	otherInformation->list[i]->which = Z_OtherInfo_characterInfo;
+	otherInformation->list[i]->information.characterInfo = 0;
+	
+	otherInformation->num_elements = i+1;
+	return otherInformation->list[i];
+    }
+}
+
+void yaz_oi_set_string_oid (
+    Z_OtherInformation **otherInformation, ODR odr,
+    int *oid, int categoryValue,
+    const char *str)
+{
+    Z_OtherInformationUnit *oi =
+	yaz_oi_update(otherInformation, odr, oid, categoryValue, 0);
+    if (!oi)
+	return;
+    oi->which = Z_OtherInfo_characterInfo;
+    oi->information.characterInfo = odr_strdup (odr, str);
+}
+
+void yaz_oi_set_string_oidval (
+    Z_OtherInformation **otherInformation, ODR odr,
+    int oidval, int categoryValue,
+    const char *str)
+{
+    int oid[OID_SIZE];
+    struct oident ent;
+    ent.proto = PROTO_Z3950;
+    ent.oclass = CLASS_USERINFO;
+    ent.value = (oid_value) oidval;
+    if (!oid_ent_to_oid (&ent, oid))
+	return ;
+    yaz_oi_set_string_oid(otherInformation,
+			  odr, oid, categoryValue, str);
+}
+
+char *yaz_oi_get_string_oid (
+    Z_OtherInformation **otherInformation,
+    int *oid, int categoryValue, int delete_flag)
+{
+    Z_OtherInformationUnit *oi;
+    
+    if ((oi = yaz_oi_update(otherInformation, 0, oid, 1, delete_flag)) &&
+	oi->which == Z_OtherInfo_characterInfo)
+	return oi->information.characterInfo;
+    return 0;
+}
+
+char *yaz_oi_get_string_oidval(Z_OtherInformation **otherInformation,
+			       int oidval, int categoryValue, int delete_flag)
+{
+    int oid[OID_SIZE];
+    struct oident ent;
+    ent.proto = PROTO_Z3950;
+    ent.oclass = CLASS_USERINFO;
+    ent.value = (oid_value) oidval;
+
+    if (!oid_ent_to_oid (&ent, oid))
+	return 0;
+    return yaz_oi_get_string_oid (otherInformation, oid, categoryValue,
+				  delete_flag);
+}
+
Index: /main/tags/2.25/gsdl/packages/yaz/zutil/pquery.c
===================================================================
--- /main/tags/2.25/gsdl/packages/yaz/zutil/pquery.c	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/yaz/zutil/pquery.c	(revision 21064)
@@ -0,0 +1,636 @@
+/*
+ * Copyright (c) 1995-1998, Index Data.
+ * See the file LICENSE for details.
+ * Sebastian Hammer, Adam Dickmeiss
+ *
+ * $Log$
+ * Revision 1.1  2000/08/03 03:12:37  johnmcp
+ * Added the YAZ toolkit source to the packages directory (for z39.50 stuff)
+ *
+ * Revision 1.4  1999/12/21 16:25:20  adam
+ * Fixed handling of default/inherited attributes.
+ *
+ * Revision 1.3  1999/12/20 15:20:13  adam
+ * Implemented ccl_pquery to convert from CCL tree to prefix query.
+ *
+ * Revision 1.2  1999/11/30 13:47:12  adam
+ * Improved installation. Moved header files to include/yaz.
+ *
+ * Revision 1.1  1999/06/08 10:10:16  adam
+ * New sub directory zutil. Moved YAZ Compiler to be part of YAZ tree.
+ *
+ * Revision 1.22  1999/04/20 09:56:49  adam
+ * Added 'name' paramter to encoder/decoder routines (typedef Odr_fun).
+ * Modified all encoders/decoders to reflect this change.
+ *
+ * Revision 1.21  1998/10/13 16:03:37  adam
+ * Better checking for invalid OID's in p_query_rpn.
+ *
+ * Revision 1.20  1998/03/31 15:13:20  adam
+ * Development towards compiled ASN.1.
+ *
+ * Revision 1.19  1998/03/05 08:09:03  adam
+ * Minor change to make C++ happy.
+ *
+ * Revision 1.18  1998/02/11 11:53:36  adam
+ * Changed code so that it compiles as C++.
+ *
+ * Revision 1.17  1997/11/24 11:33:57  adam
+ * Using function odr_nullval() instead of global ODR_NULLVAL when
+ * appropriate.
+ *
+ * Revision 1.16  1997/09/29 13:19:00  adam
+ * Added function, oid_ent_to_oid, to replace the function
+ * oid_getoidbyent, which is not thread safe.
+ *
+ * Revision 1.15  1997/09/29 07:13:43  adam
+ * Changed type of a few variables to avoid warnings.
+ *
+ * Revision 1.14  1997/09/22 12:33:41  adam
+ * Fixed bug introduced by previous commit.
+ *
+ * Revision 1.13  1997/09/17 12:10:42  adam
+ * YAZ version 1.4.
+ *
+ * Revision 1.12  1997/09/01 08:54:13  adam
+ * New windows NT/95 port using MSV5.0. Made prefix query handling
+ * thread safe. The function options ignores empty arguments when met.
+ *
+ * Revision 1.11  1996/11/11 13:15:29  adam
+ * Added proximity operator.
+ *
+ * Revision 1.10  1996/08/12 14:10:35  adam
+ * New function p_query_attset to define default attribute set.
+ *
+ * Revision 1.9  1996/03/15  11:03:46  adam
+ * Attribute set can be set globally for a query with the @attrset
+ * operator. The @attr operator has an optional attribute-set specifier
+ * that sets the attribute set locally.
+ *
+ * Revision 1.8  1996/01/02  11:46:56  quinn
+ * Changed 'operator' to 'roperator' to avoid C++ conflict.
+ *
+ * Revision 1.7  1995/09/29  17:12:36  quinn
+ * Smallish
+ *
+ * Revision 1.6  1995/09/27  15:03:03  quinn
+ * Modified function heads & prototypes.
+ *
+ * Revision 1.5  1995/06/15  12:31:02  quinn
+ * *** empty log message ***
+ *
+ * Revision 1.4  1995/06/15  07:45:19  quinn
+ * Moving to v3.
+ *
+ * Revision 1.3  1995/06/14  11:06:35  adam
+ * Bug fix: Attributes wasn't interpreted correctly!
+ *
+ * Revision 1.2  1995/05/26  08:56:11  adam
+ * New function: p_query_scan.
+ *
+ * Revision 1.1  1995/05/22  15:31:49  adam
+ * New function, p_query_rpn, to convert from prefix (ascii) to rpn (asn).
+ *
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+
+#include <yaz/proto.h>
+#include <yaz/oid.h>
+#include <yaz/pquery.h>
+
+static oid_value p_query_dfset = VAL_NONE;
+
+struct lex_info {
+    const char *query_buf;
+    const char *lex_buf;
+    size_t lex_len;
+    int query_look;
+    char *left_sep;
+    char *right_sep;
+    int escape_char;
+    int term_type;
+};
+
+static Z_RPNStructure *rpn_structure (struct lex_info *li, ODR o, oid_proto, 
+                                      int num_attr, int max_attr, 
+                                      int *attr_list, oid_value *attr_set);
+
+static enum oid_value query_oid_getvalbyname (struct lex_info *li)
+{
+    enum oid_value value;
+    char buf[32];
+
+    if (li->lex_len > 31)
+        return VAL_NONE;
+    memcpy (buf, li->lex_buf, li->lex_len);
+    buf[li->lex_len] = '\0';
+    value = oid_getvalbyname (buf);
+    return value;
+}
+
+static int compare_term (struct lex_info *li, const char *src, size_t off)
+{
+    size_t len=strlen(src);
+
+    if (li->lex_len == len+off && !memcmp (li->lex_buf+off, src, len-off))
+	return 1;
+    return 0;
+}
+
+static int query_token (struct lex_info *li)
+{
+    const char *sep_match;
+    const char **qptr = &li->query_buf;
+
+    while (**qptr == ' ')
+        (*qptr)++;
+    if (**qptr == '\0')
+        return 0;
+    li->lex_len = 0;
+    if ((sep_match = strchr (li->left_sep, **qptr)))
+    {
+        int sep_index = sep_match - li->left_sep;
+        
+        ++(*qptr);
+        li->lex_buf = *qptr;
+        while (**qptr && **qptr != li->right_sep[sep_index])
+        {
+            ++(li->lex_len);
+            ++(*qptr);
+        }
+        if (**qptr)
+            ++(*qptr);
+    }
+    else
+    {
+        li->lex_buf = *qptr;
+        while (**qptr && **qptr != ' ')
+        {
+            ++(li->lex_len);
+            ++(*qptr);
+        }
+    }
+    if (li->lex_len >= 1 && li->lex_buf[0] == li->escape_char)
+    {
+	if (compare_term (li, "and", 1))
+	    return 'a';
+        if (compare_term (li, "or", 1))
+            return 'o';
+        if (compare_term (li, "not", 1))
+            return 'n';
+        if (compare_term (li, "attr", 1))
+            return 'l';
+        if (compare_term (li, "set", 1))
+            return 's';
+        if (compare_term (li, "attrset", 1))
+            return 'r';
+        if (compare_term (li, "prox", 1))
+            return 'p';
+        if (compare_term (li, "term", 1))
+            return 'y';
+    }
+    return 't';
+}
+
+static int lex (struct lex_info *li)
+{
+    return li->query_look = query_token (li);
+}
+
+static Z_AttributesPlusTerm *rpn_term (struct lex_info *li, ODR o,
+                                       oid_proto proto, 
+                                       int num_attr, int *attr_list,
+                                       oid_value *attr_set)
+{
+    Z_AttributesPlusTerm *zapt;
+    Odr_oct *term_octet;
+    Z_Term *term;
+    Z_AttributeElement **elements;
+
+    zapt = (Z_AttributesPlusTerm *)odr_malloc (o, sizeof(*zapt));
+    term_octet = (Odr_oct *)odr_malloc (o, sizeof(*term_octet));
+    term = (Z_Term *)odr_malloc (o, sizeof(*term));
+
+    if (!num_attr)
+        elements = (Z_AttributeElement**)odr_nullval();
+    else
+    {
+        int i, k = 0;
+        int *attr_tmp;
+
+        elements = (Z_AttributeElement**)
+	    odr_malloc (o, num_attr * sizeof(*elements));
+
+        attr_tmp = (int *)odr_malloc (o, num_attr * 2 * sizeof(int));
+        memcpy (attr_tmp, attr_list, num_attr * 2 * sizeof(int));
+        for (i = num_attr; --i >= 0; )
+        {
+            int j;
+            for (j = i+1; j<num_attr; j++)
+                if (attr_tmp[2*j] == attr_tmp[2*i])
+                    break;
+            if (j < num_attr)
+                continue;
+            elements[k] =
+                (Z_AttributeElement*)odr_malloc (o,sizeof(**elements));
+            elements[k]->attributeType = &attr_tmp[2*i];
+            if (attr_set[i] == VAL_NONE)
+                elements[k]->attributeSet = 0;
+            else
+            {
+                oident attrid;
+                int oid[OID_SIZE];
+		
+                attrid.proto = PROTO_Z3950;
+                attrid.oclass = CLASS_ATTSET;
+                attrid.value = attr_set[i];
+                   
+                elements[k]->attributeSet =
+		    odr_oiddup (o, oid_ent_to_oid (&attrid, oid));
+            }
+	    elements[k]->which = Z_AttributeValue_numeric;
+	    elements[k]->value.numeric = &attr_tmp[2*i+1];
+            k++;
+        }
+        num_attr = k;
+    }
+#ifdef ASN_COMPILED
+    zapt->attributes = (Z_AttributeList *)
+	odr_malloc (o, sizeof(*zapt->attributes));
+    zapt->attributes->num_attributes = num_attr;
+    zapt->attributes->attributes = elements;
+#else
+    zapt->num_attributes = num_attr;
+    zapt->attributeList = elements;
+#endif    
+
+    zapt->term = term;
+    term->which = Z_Term_general;
+    term->u.general = term_octet;
+    term_octet->buf = (unsigned char *)odr_malloc (o, li->lex_len);
+    term_octet->size = term_octet->len = li->lex_len;
+    memcpy (term_octet->buf, li->lex_buf, li->lex_len);
+    return zapt;
+}
+
+static Z_Operand *rpn_simple (struct lex_info *li, ODR o, oid_proto proto,
+                              int num_attr, int *attr_list,
+                              oid_value *attr_set)
+{
+    Z_Operand *zo;
+
+    zo = (Z_Operand *)odr_malloc (o, sizeof(*zo));
+    switch (li->query_look)
+    {
+    case 't':
+        zo->which = Z_Operand_APT;
+        if (!(zo->u.attributesPlusTerm =
+              rpn_term (li, o, proto, num_attr, attr_list, attr_set)))
+            return NULL;
+        lex (li);
+        break;
+    case 's':
+        lex (li);
+        if (!li->query_look)
+            return NULL;
+        zo->which = Z_Operand_resultSetId;
+        zo->u.resultSetId = (char *)odr_malloc (o, li->lex_len+1);
+        memcpy (zo->u.resultSetId, li->lex_buf, li->lex_len);
+        zo->u.resultSetId[li->lex_len] = '\0';
+        lex (li);
+        break;
+    default:
+        return NULL;
+    }
+    return zo;
+}
+
+static Z_ProximityOperator *rpn_proximity (struct lex_info *li, ODR o)
+{
+    Z_ProximityOperator *p = (Z_ProximityOperator *)odr_malloc (o, sizeof(*p));
+
+    if (!lex (li))
+        return NULL;
+    if (*li->lex_buf == '1')
+    {
+        p->exclusion = (int *)odr_malloc (o, sizeof(*p->exclusion));
+        *p->exclusion = 1;
+    } 
+    else if (*li->lex_buf == '0')
+    {
+        p->exclusion = (int *)odr_malloc (o, sizeof(*p->exclusion));
+        *p->exclusion = 0;
+    }
+    else
+        p->exclusion = NULL;
+
+    if (!lex (li))
+        return NULL;
+    p->distance = (int *)odr_malloc (o, sizeof(*p->distance));
+    *p->distance = atoi (li->lex_buf);
+
+    if (!lex (li))
+        return NULL;
+    p->ordered = (int *)odr_malloc (o, sizeof(*p->ordered));
+    *p->ordered = atoi (li->lex_buf);
+    
+    if (!lex (li))
+        return NULL;
+    p->relationType = (int *)odr_malloc (o, sizeof(*p->relationType));
+    *p->relationType = atoi (li->lex_buf);
+
+    if (!lex (li))
+        return NULL;
+    if (*li->lex_buf == 'k')
+        p->which = 0;
+    else if (*li->lex_buf == 'p')
+        p->which = 1;
+    else
+        p->which = atoi (li->lex_buf);
+
+    if (!lex (li))
+        return NULL;
+#ifdef ASN_COMPILED
+    p->which = Z_ProximityOperator_known;
+    p->u.known = (int *)odr_malloc (o, sizeof(*p->u.known));
+    *p->u.known = atoi (li->lex_buf);
+#else
+    p->proximityUnitCode = (int *)odr_malloc (o, sizeof(*p->proximityUnitCode));
+    *p->proximityUnitCode = atoi (li->lex_buf);
+#endif
+    return p;
+}
+
+static Z_Complex *rpn_complex (struct lex_info *li, ODR o, oid_proto proto,
+                               int num_attr, int max_attr, 
+                               int *attr_list, oid_value *attr_set)
+{
+    Z_Complex *zc;
+    Z_Operator *zo;
+
+    zc = (Z_Complex *)odr_malloc (o, sizeof(*zc));
+    zo = (Z_Operator *)odr_malloc (o, sizeof(*zo));
+    zc->roperator = zo;
+    switch (li->query_look)
+    {
+    case 'a':
+        zo->which = Z_Operator_and;
+        zo->u.and = odr_nullval();
+        break;
+    case 'o':
+        zo->which = Z_Operator_or;
+        zo->u.and = odr_nullval();
+        break;
+    case 'n':
+        zo->which = Z_Operator_and_not;
+        zo->u.and = odr_nullval();
+        break;
+    case 'p':
+        zo->which = Z_Operator_prox;
+        zo->u.prox = rpn_proximity (li, o);
+        if (!zo->u.prox)
+            return NULL;
+        break;
+    default:
+        return NULL;
+    }
+    lex (li);
+    if (!(zc->s1 =
+          rpn_structure (li, o, proto, num_attr, max_attr, attr_list,
+                         attr_set)))
+        return NULL;
+    if (!(zc->s2 =
+          rpn_structure (li, o, proto, num_attr, max_attr, attr_list,
+                         attr_set)))
+        return NULL;
+    return zc;
+}
+
+static Z_RPNStructure *rpn_structure (struct lex_info *li, ODR o,
+                                      oid_proto proto, 
+                                      int num_attr, int max_attr, 
+                                      int *attr_list, oid_value *attr_set)
+{
+    Z_RPNStructure *sz;
+    const char *cp;
+
+    sz = (Z_RPNStructure *)odr_malloc (o, sizeof(*sz));
+    switch (li->query_look)
+    {
+    case 'a':
+    case 'o':
+    case 'n':
+    case 'p':
+        sz->which = Z_RPNStructure_complex;
+        if (!(sz->u.complex =
+              rpn_complex (li, o, proto, num_attr, max_attr, attr_list,
+                           attr_set)))
+            return NULL;
+        break;
+    case 't':
+    case 's':
+        sz->which = Z_RPNStructure_simple;
+        if (!(sz->u.simple =
+              rpn_simple (li, o, proto, num_attr, attr_list,
+                          attr_set)))
+            return NULL;
+        break;
+    case 'l':
+        lex (li);
+        if (!li->query_look)
+            return NULL;
+        if (num_attr >= max_attr)
+            return NULL;
+        if (!(cp = strchr (li->lex_buf, '=')) ||
+            (size_t) (cp-li->lex_buf) > li->lex_len)
+        {
+            attr_set[num_attr] = query_oid_getvalbyname (li);
+	    if (attr_set[num_attr] == VAL_NONE)
+		return NULL;
+            lex (li);
+
+            if (!(cp = strchr (li->lex_buf, '=')))
+                return NULL;
+        }
+        else 
+        {
+            if (num_attr > 0)
+                attr_set[num_attr] = attr_set[num_attr-1];
+            else
+                attr_set[num_attr] = VAL_NONE;
+        }
+	attr_list[2*num_attr] = atoi(li->lex_buf); 
+	attr_list[2*num_attr+1] = atoi (cp+1);
+	num_attr++;
+        lex (li);
+        return
+            rpn_structure (li, o, proto, num_attr, max_attr, attr_list,
+                           attr_set);
+    case 'y':
+	lex (li);
+	if (!li->query_look)
+	    return NULL;
+	if (compare_term (li, "general", 0))
+	    li->term_type = Z_Term_general;
+	else if (compare_term (li, "numeric", 0))
+	    li->term_type = Z_Term_numeric;
+	else if (compare_term (li, "string", 0))
+	    li->term_type = Z_Term_characterString;
+	else if (compare_term (li, "oid", 0))
+	    li->term_type = Z_Term_oid;
+	else if (compare_term (li, "datetime", 0))
+	    li->term_type = Z_Term_dateTime;
+	else if (compare_term (li, "null", 0))
+	    li->term_type = Z_Term_null;
+	lex (li);
+        return
+            rpn_structure (li, o, proto, num_attr, max_attr, attr_list,
+                           attr_set);
+    case 0:                /* operator/operand expected! */
+        return NULL;
+    }
+    return sz;
+}
+
+Z_RPNQuery *p_query_rpn_mk (ODR o, struct lex_info *li, oid_proto proto,
+                            const char *qbuf)
+{
+    Z_RPNQuery *zq;
+    int attr_array[1024];
+    oid_value attr_set[512];
+    oid_value topSet = VAL_NONE;
+    oident oset;
+    int oid[OID_SIZE];
+
+    zq = (Z_RPNQuery *)odr_malloc (o, sizeof(*zq));
+    lex (li);
+    if (li->query_look == 'r')
+    {
+        lex (li);
+        topSet = query_oid_getvalbyname (li);
+        if (topSet == VAL_NONE)
+            return NULL;
+
+        lex (li);
+    }
+    if (topSet == VAL_NONE)
+        topSet = p_query_dfset;
+    if (topSet == VAL_NONE)
+        topSet = VAL_BIB1;
+    oset.proto = proto;
+    oset.oclass = CLASS_ATTSET;
+    oset.value = topSet;
+
+    if (!oid_ent_to_oid (&oset, oid))
+	return NULL;
+    zq->attributeSetId = odr_oiddup (o, oid);
+
+    if (!(zq->RPNStructure = rpn_structure (li, o, proto, 0, 512,
+                                            attr_array, attr_set)))
+        return NULL;
+    return zq;
+}
+
+Z_RPNQuery *p_query_rpn (ODR o, oid_proto proto,
+                         const char *qbuf)
+{
+    struct lex_info li;
+    
+    li.left_sep = "{\"";
+    li.right_sep = "}\"";
+    li.escape_char = '@';
+    li.term_type = Z_Term_general;
+    li.query_buf = qbuf;
+    return p_query_rpn_mk (o, &li, proto, qbuf);
+}
+
+Z_AttributesPlusTerm *p_query_scan_mk (struct lex_info *li,
+                                       ODR o, oid_proto proto,
+                                       Odr_oid **attributeSetP,
+                                       const char *qbuf)
+{
+    int attr_list[1024];
+    oid_value attr_set[512];
+    int num_attr = 0;
+    int max_attr = 512;
+    const char *cp;
+    oid_value topSet = VAL_NONE;
+    oident oset;
+    int oid[OID_SIZE];
+
+    lex (li);
+    if (li->query_look == 'r')
+    {
+        lex (li);
+        topSet = query_oid_getvalbyname (li);
+
+        lex (li);
+    }
+    if (topSet == VAL_NONE)
+        topSet = p_query_dfset;
+    if (topSet == VAL_NONE)
+        topSet = VAL_BIB1;
+    oset.proto = proto;
+    oset.oclass = CLASS_ATTSET;
+    oset.value = topSet;
+
+    *attributeSetP = odr_oiddup (o, oid_ent_to_oid (&oset, oid));
+
+    while (li->query_look == 'l')
+    {
+        lex (li);
+        if (!li->query_look)
+            return NULL;
+        if (num_attr >= max_attr)
+            return NULL;
+
+        if (!(cp = strchr (li->lex_buf, '=')) ||
+            (size_t) (cp-li->lex_buf) > li->lex_len)
+        {
+            attr_set[num_attr] = query_oid_getvalbyname (li);
+            lex (li);
+
+            if (!(cp = strchr (li->lex_buf, '=')))
+                return NULL;
+        }
+        else
+        {
+            if (num_attr > 0)
+                attr_set[num_attr] = attr_set[num_attr-1];
+            else
+                attr_set[num_attr] = VAL_NONE;
+        }
+        attr_list[2*num_attr] = atoi (li->lex_buf);
+        attr_list[2*num_attr+1] = atoi (cp+1);
+        num_attr++;
+        lex (li);
+    }
+    if (!li->query_look)
+        return NULL;
+    return rpn_term (li, o, proto, num_attr, attr_list, attr_set);
+}
+
+Z_AttributesPlusTerm *p_query_scan (ODR o, oid_proto proto,
+                                    Odr_oid **attributeSetP,
+                                    const char *qbuf)
+{
+    struct lex_info li;
+
+    li.left_sep = "{\"";
+    li.right_sep = "}\"";
+    li.escape_char = '@';
+    li.term_type = Z_Term_general;
+    li.query_buf = qbuf;
+
+    return p_query_scan_mk (&li, o, proto, attributeSetP, qbuf);
+}
+
+int p_query_attset (const char *arg)
+{
+    p_query_dfset = oid_getvalbyname (arg);
+    return (p_query_dfset == VAL_NONE) ? -1 : 0;
+}
+
Index: /main/tags/2.25/gsdl/packages/yaz/zutil/prt-ext.c
===================================================================
--- /main/tags/2.25/gsdl/packages/yaz/zutil/prt-ext.c	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/yaz/zutil/prt-ext.c	(revision 21064)
@@ -0,0 +1,284 @@
+/*
+ * Copyright (c) 1995-1999, Index Data.
+ * See the file LICENSE for details.
+ * Sebastian Hammer, Adam Dickmeiss
+ *
+ * $Log$
+ * Revision 1.1  2000/08/03 03:12:38  johnmcp
+ * Added the YAZ toolkit source to the packages directory (for z39.50 stuff)
+ *
+ * Revision 1.2  1999/11/30 13:47:12  adam
+ * Improved installation. Moved header files to include/yaz.
+ *
+ * Revision 1.1  1999/06/08 10:10:16  adam
+ * New sub directory zutil. Moved YAZ Compiler to be part of YAZ tree.
+ *
+ * Revision 1.22  1999/05/26 15:24:26  adam
+ * Fixed minor bugs regarding DB Update (introduced by previous commit).
+ *
+ * Revision 1.21  1999/05/26 14:47:12  adam
+ * Implemented z_ext_record.
+ *
+ * Revision 1.20  1999/04/20 09:56:48  adam
+ * Added 'name' paramter to encoder/decoder routines (typedef Odr_fun).
+ * Modified all encoders/decoders to reflect this change.
+ *
+ * Revision 1.19  1998/03/31 15:13:19  adam
+ * Development towards compiled ASN.1.
+ *
+ * Revision 1.18  1998/03/31 11:07:44  adam
+ * Furhter work on UNIverse resource report.
+ * Added Extended Services handling in frontend server.
+ *
+ * Revision 1.17  1998/03/20 14:46:06  adam
+ * Added UNIverse Resource Reports.
+ *
+ * Revision 1.16  1998/02/11 11:53:32  adam
+ * Changed code so that it compiles as C++.
+ *
+ * Revision 1.15  1998/02/10 15:31:46  adam
+ * Implemented date and time structure. Changed the Update Extended
+ * Service.
+ *
+ * Revision 1.14  1998/01/05 09:04:57  adam
+ * Fixed bugs in encoders/decoders - Not operator (!) missing.
+ *
+ * Revision 1.13  1997/05/14 06:53:22  adam
+ * C++ support.
+ *
+ * Revision 1.12  1997/04/30 08:52:02  quinn
+ * Null
+ *
+ * Revision 1.11  1996/10/10  12:35:13  quinn
+ * Added Update extended service.
+ *
+ * Revision 1.10  1996/10/09  15:54:55  quinn
+ * Added SearchInfoReport
+ *
+ * Revision 1.9  1996/06/10  08:53:36  quinn
+ * Added Summary,OPAC,ResourceReport
+ *
+ * Revision 1.8  1996/02/20  12:51:44  quinn
+ * Completed SCAN. Fixed problems with EXTERNAL.
+ *
+ * Revision 1.7  1995/10/12  10:34:38  quinn
+ * Added Espec-1.
+ *
+ * Revision 1.6  1995/09/29  17:11:55  quinn
+ * Smallish
+ *
+ * Revision 1.5  1995/09/27  15:02:42  quinn
+ * Modified function heads & prototypes.
+ *
+ * Revision 1.4  1995/08/29  11:17:16  quinn
+ * *** empty log message ***
+ *
+ * Revision 1.3  1995/08/21  09:10:18  quinn
+ * Smallish fixes to suppport new formats.
+ *
+ * Revision 1.2  1995/08/17  12:45:00  quinn
+ * Fixed minor problems with GRS-1. Added support in c&s.
+ *
+ * Revision 1.1  1995/08/15  13:37:41  quinn
+ * Improved EXTERNAL
+ *
+ *
+ */
+
+#include <yaz/proto.h>
+
+/*
+ * The table below should be moved to the ODR structure itself and
+ * be an image of the association context: To help
+ * map indirect references when they show up. 
+ */
+static Z_ext_typeent type_table[] =
+{
+    {VAL_SUTRS, Z_External_sutrs, (Odr_fun) z_SUTRS},
+    {VAL_EXPLAIN, Z_External_explainRecord, (Odr_fun)z_ExplainRecord},
+    {VAL_RESOURCE1, Z_External_resourceReport1, (Odr_fun)z_ResourceReport1},
+    {VAL_RESOURCE2, Z_External_resourceReport2, (Odr_fun)z_ResourceReport2},
+    {VAL_PROMPT1, Z_External_promptObject1, (Odr_fun)z_PromptObject1 },
+    {VAL_GRS1, Z_External_grs1, (Odr_fun)z_GenericRecord},
+    {VAL_EXTENDED, Z_External_extendedService, (Odr_fun)z_TaskPackage},
+#ifdef ASN_COMPILED
+    {VAL_ITEMORDER, Z_External_itemOrder, (Odr_fun)z_IOItemOrder},
+#else
+    {VAL_ITEMORDER, Z_External_itemOrder, (Odr_fun)z_ItemOrder},
+#endif
+    {VAL_DIAG1, Z_External_diag1, (Odr_fun)z_DiagnosticFormat},
+    {VAL_ESPEC1, Z_External_espec1, (Odr_fun)z_Espec1},
+    {VAL_SUMMARY, Z_External_summary, (Odr_fun)z_BriefBib},
+    {VAL_OPAC, Z_External_OPAC, (Odr_fun)z_OPACRecord},
+    {VAL_SEARCHRES1, Z_External_searchResult1, (Odr_fun)z_SearchInfoReport},
+    {VAL_DBUPDATE, Z_External_update, (Odr_fun)z_IUUpdate},
+    {VAL_DATETIME, Z_External_dateTime, (Odr_fun)z_DateTime},
+    {VAL_UNIVERSE_REPORT, Z_External_universeReport, (Odr_fun)z_UniverseReport},
+    {VAL_NONE, 0, 0}
+};
+
+Z_ext_typeent *z_ext_getentbyref(oid_value val)
+{
+    Z_ext_typeent *i;
+
+    for (i = type_table; i->dref != VAL_NONE; i++)
+	if (i->dref == val)
+	    return i;
+    return 0;
+}
+
+int z_External(ODR o, Z_External **p, int opt, const char *name)
+{
+    oident *oid;
+    Z_ext_typeent *type;
+
+    static Odr_arm arm[] =
+    {
+	{ODR_EXPLICIT, ODR_CONTEXT, 0, Z_External_single,
+	 (Odr_fun)odr_any, 0},
+	{ODR_IMPLICIT, ODR_CONTEXT, 1, Z_External_octet,
+	 (Odr_fun)odr_octetstring, 0},
+	{ODR_IMPLICIT, ODR_CONTEXT, 2, Z_External_arbitrary,
+	 (Odr_fun)odr_bitstring, 0},
+	{ODR_EXPLICIT, ODR_CONTEXT, 0, Z_External_sutrs,
+	 (Odr_fun)z_SUTRS, 0},
+	{ODR_EXPLICIT, ODR_CONTEXT, 0, Z_External_explainRecord,
+	 (Odr_fun)z_ExplainRecord, 0},
+	{ODR_EXPLICIT, ODR_CONTEXT, 0, Z_External_resourceReport1,
+	 (Odr_fun)z_ResourceReport1, 0},
+	{ODR_EXPLICIT, ODR_CONTEXT, 0, Z_External_resourceReport2,
+	 (Odr_fun)z_ResourceReport2, 0},
+	{ODR_EXPLICIT, ODR_CONTEXT, 0, Z_External_promptObject1,
+	 (Odr_fun)z_PromptObject1, 0},
+	{ODR_EXPLICIT, ODR_CONTEXT, 0, Z_External_grs1,
+	 (Odr_fun)z_GenericRecord, 0},
+	{ODR_EXPLICIT, ODR_CONTEXT, 0, Z_External_extendedService,
+	 (Odr_fun)z_TaskPackage, 0},
+#ifdef ASN_COMPILED
+	{ODR_EXPLICIT, ODR_CONTEXT, 0, Z_External_itemOrder,
+	 (Odr_fun)z_IOItemOrder, 0},
+#else
+	{ODR_EXPLICIT, ODR_CONTEXT, 0, Z_External_itemOrder,
+	 (Odr_fun)z_ItemOrder, 0},
+#endif
+	{ODR_EXPLICIT, ODR_CONTEXT, 0, Z_External_diag1,
+	 (Odr_fun)z_DiagnosticFormat, 0},
+	{ODR_EXPLICIT, ODR_CONTEXT, 0, Z_External_espec1,
+	 (Odr_fun)z_Espec1, 0},
+	{ODR_EXPLICIT, ODR_CONTEXT, 0, Z_External_summary,
+	 (Odr_fun)z_BriefBib, 0},
+	{ODR_EXPLICIT, ODR_CONTEXT, 0, Z_External_OPAC,
+	 (Odr_fun)z_OPACRecord, 0},
+	{ODR_EXPLICIT, ODR_CONTEXT, 0, Z_External_searchResult1,
+	 (Odr_fun)z_SearchInfoReport, 0},
+	{ODR_EXPLICIT, ODR_CONTEXT, 0, Z_External_update,
+	 (Odr_fun)z_IUUpdate, 0},
+	{ODR_EXPLICIT, ODR_CONTEXT, 0, Z_External_dateTime,
+	 (Odr_fun)z_DateTime, 0},
+	{ODR_EXPLICIT, ODR_CONTEXT, 0, Z_External_universeReport,
+	 (Odr_fun)z_UniverseReport, 0},
+	{-1, -1, -1, -1, 0, 0}
+    };
+    
+    odr_implicit_settag(o, ODR_UNIVERSAL, ODR_EXTERNAL);
+    if (!odr_sequence_begin(o, p, sizeof(**p), name))
+	return opt && odr_ok(o);
+    if (!(odr_oid(o, &(*p)->direct_reference, 1, 0) &&
+	  odr_integer(o, &(*p)->indirect_reference, 1, 0) &&
+	  odr_graphicstring(o, &(*p)->descriptor, 1, 0)))
+	return 0;
+    /*
+     * Do we know this beast?
+     */
+    if (o->direction == ODR_DECODE && (*p)->direct_reference &&
+	(oid = oid_getentbyoid((*p)->direct_reference)) &&
+	(type = z_ext_getentbyref(oid->value)))
+    {
+	int zclass, tag, cons;
+	
+	/*
+	 * We know it. If it's represented as an ASN.1 type, bias the CHOICE.
+	 */
+	if (!odr_peektag(o, &zclass, &tag, &cons))
+	    return opt && odr_ok(o);
+	if (zclass == ODR_CONTEXT && tag == 0 && cons == 1)
+	    odr_choice_bias(o, type->what);
+    }
+    return
+	odr_choice(o, arm, &(*p)->u, &(*p)->which, name) &&
+	odr_sequence_end(o);
+}
+
+Z_External *z_ext_record(ODR o, int format, const char *buf, int len)
+{
+    Z_External *thisext;
+    oident recform;
+    int oid[OID_SIZE];
+
+    thisext = (Z_External *) odr_malloc(o, sizeof(*thisext));
+    thisext->descriptor = 0;
+    thisext->indirect_reference = 0;
+
+    recform.proto = PROTO_Z3950;
+    recform.oclass = CLASS_RECSYN;
+    recform.value = (enum oid_value) format;
+    if (!oid_ent_to_oid(&recform, oid))
+	return 0;
+    thisext->direct_reference = odr_oiddup(o, oid);
+    
+    if (len < 0) /* Structured data */
+    {
+	switch (format)
+	{
+	case VAL_SUTRS:
+	    thisext->which = Z_External_sutrs;
+	    break;
+	case VAL_GRS1:
+	    thisext->which = Z_External_grs1;
+	    break;
+	case VAL_EXPLAIN:
+	    thisext->which = Z_External_explainRecord;
+	    break;
+	case VAL_SUMMARY:
+	    thisext->which = Z_External_summary;
+	    break;
+	case VAL_OPAC:
+	    thisext->which = Z_External_OPAC;
+	    break;
+	default:
+	    return 0;
+	}
+	
+	/*
+	 * We cheat on the pointers here. Obviously, the record field
+	 * of the backend-fetch structure should have been a union for
+	 * correctness, but we're stuck with this for backwards
+	 * compatibility.
+	 */
+	thisext->u.grs1 = (Z_GenericRecord*) buf;
+    }
+    else if (format == VAL_SUTRS) /* SUTRS is a single-ASN.1-type */
+    {
+	Odr_oct *sutrs = (Odr_oct *)odr_malloc(o, sizeof(*sutrs));
+	
+	thisext->which = Z_External_sutrs;
+	thisext->u.sutrs = sutrs;
+	sutrs->buf = (unsigned char *)odr_malloc(o, len);
+	sutrs->len = sutrs->size = len;
+	memcpy(sutrs->buf, buf, len);
+    }
+    else
+    {
+	thisext->which = Z_External_octet;
+	if (!(thisext->u.octet_aligned = (Odr_oct *)
+	      odr_malloc(o, sizeof(Odr_oct))))
+	    return 0;
+	if (!(thisext->u.octet_aligned->buf = (unsigned char *)
+	      odr_malloc(o, len)))
+	    return 0;
+	memcpy(thisext->u.octet_aligned->buf, buf, len);
+	thisext->u.octet_aligned->len = thisext->u.octet_aligned->size = len;
+    }
+    return thisext;
+}
+
Index: /main/tags/2.25/gsdl/packages/yaz/zutil/yaz-ccl.c
===================================================================
--- /main/tags/2.25/gsdl/packages/yaz/zutil/yaz-ccl.c	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/yaz/zutil/yaz-ccl.c	(revision 21064)
@@ -0,0 +1,292 @@
+/*
+ * Copyright (c) 1996-2000, Index Data.
+ * See the file LICENSE for details.
+ * Sebastian Hammer, Adam Dickmeiss
+ *
+ * $Log$
+ * Revision 1.1  2000/08/03 03:12:39  johnmcp
+ * Added the YAZ toolkit source to the packages directory (for z39.50 stuff)
+ *
+ * Revision 1.6  2000/02/02 15:13:23  adam
+ * Minor change.
+ *
+ * Revision 1.5  2000/01/31 13:15:22  adam
+ * Removed uses of assert(3). Cleanup of ODR. CCL parser update so
+ * that some characters are not surrounded by spaces in resulting term.
+ * ILL-code updates.
+ *
+ * Revision 1.4  1999/12/20 15:20:13  adam
+ * Implemented ccl_pquery to convert from CCL tree to prefix query.
+ *
+ * Revision 1.3  1999/11/30 13:47:12  adam
+ * Improved installation. Moved header files to include/yaz.
+ *
+ * Revision 1.2  1999/06/16 12:00:08  adam
+ * Added proximity.
+ *
+ * Revision 1.1  1999/06/08 10:12:43  adam
+ * Moved file to be part of zutil (instead of util).
+ *
+ * Revision 1.13  1998/03/31 15:13:20  adam
+ * Development towards compiled ASN.1.
+ *
+ * Revision 1.12  1998/02/11 11:53:36  adam
+ * Changed code so that it compiles as C++.
+ *
+ * Revision 1.11  1997/11/24 11:33:57  adam
+ * Using function odr_nullval() instead of global ODR_NULLVAL when
+ * appropriate.
+ *
+ * Revision 1.10  1997/09/29 08:58:25  adam
+ * Fixed conversion of trees so that true copy is made.
+ *
+ * Revision 1.9  1997/06/23 10:31:25  adam
+ * Added ODR argument to ccl_rpn_query and ccl_scan_query.
+ *
+ * Revision 1.8  1996/10/29 13:36:27  adam
+ * Added header.
+ *
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <yaz/yaz-ccl.h>
+
+static Z_RPNStructure *ccl_rpn_structure (ODR o, struct ccl_rpn_node *p);
+
+static Z_AttributesPlusTerm *ccl_rpn_term (ODR o, struct ccl_rpn_node *p)
+{
+    struct ccl_rpn_attr *attr;
+    int num = 0;
+    Z_AttributesPlusTerm *zapt;
+    Odr_oct *term_octet;
+    Z_Term *term;
+    Z_AttributeElement **elements;
+
+    zapt = (Z_AttributesPlusTerm *)odr_malloc (o, sizeof(*zapt));
+
+    term_octet = (Odr_oct *)odr_malloc (o, sizeof(*term_octet));
+
+    term = (Z_Term *)odr_malloc (o, sizeof(*term));
+
+    for (attr = p->u.t.attr_list; attr; attr = attr->next)
+        num++;
+    if (!num)
+        elements = (Z_AttributeElement**)odr_nullval();
+    else
+    {
+        int i = 0;
+	elements = (Z_AttributeElement **)
+	    odr_malloc (o, num*sizeof(*elements));
+        for (attr = p->u.t.attr_list; attr; attr = attr->next, i++)
+        {
+            elements[i] = (Z_AttributeElement *)
+		odr_malloc (o, sizeof(**elements));
+            elements[i]->attributeType =
+		(int *)odr_malloc(o, sizeof(int));
+            *elements[i]->attributeType = attr->type;
+	    elements[i]->attributeSet = 0;
+	    elements[i]->which = Z_AttributeValue_numeric;
+	    elements[i]->value.numeric =
+		(int *)odr_malloc (o, sizeof(int));
+	    *elements[i]->value.numeric = attr->value;
+        }
+    }
+#ifdef ASN_COMPILED
+    zapt->attributes = (Z_AttributeList *)
+	odr_malloc (o, sizeof(*zapt->attributes));
+    zapt->attributes->num_attributes = num;
+    zapt->attributes->attributes = elements;
+#else
+    zapt->num_attributes = num;
+    zapt->attributeList = elements;
+#endif    
+    zapt->term = term;
+    term->which = Z_Term_general;
+    term->u.general = term_octet;
+    term_octet->len = term_octet->size = strlen (p->u.t.term);
+    term_octet->buf = (unsigned char *)odr_malloc (o, term_octet->len+1);
+    strcpy ((char*) term_octet->buf, p->u.t.term);
+    return zapt;
+}
+
+static Z_Operand *ccl_rpn_simple (ODR o, struct ccl_rpn_node *p)
+{
+    Z_Operand *zo;
+
+    zo = (Z_Operand *)odr_malloc (o, sizeof(*zo));
+
+    switch (p->kind)
+    {
+    case CCL_RPN_TERM:
+        zo->which = Z_Operand_APT;
+        zo->u.attributesPlusTerm = ccl_rpn_term (o, p);
+        break;
+    case CCL_RPN_SET:
+        zo->which = Z_Operand_resultSetId;
+        zo->u.resultSetId = p->u.setname;
+        break;
+    default:
+	return 0;
+    }
+    return zo;
+}
+
+static Z_Complex *ccl_rpn_complex (ODR o, struct ccl_rpn_node *p)
+{
+    Z_Complex *zc;
+    Z_Operator *zo;
+
+    zc = (Z_Complex *)odr_malloc (o, sizeof(*zc));
+    zo = (Z_Operator *)odr_malloc (o, sizeof(*zo));
+
+    zc->roperator = zo;
+    switch (p->kind)
+    {
+    case CCL_RPN_AND:
+        zo->which = Z_Operator_and;
+        zo->u.and = odr_nullval();
+        break;
+    case CCL_RPN_OR:
+        zo->which = Z_Operator_or;
+        zo->u.and = odr_nullval();
+        break;
+    case CCL_RPN_NOT:
+        zo->which = Z_Operator_and_not;
+        zo->u.and = odr_nullval();
+        break;
+    case CCL_RPN_PROX:
+	zo->which = Z_Operator_prox;
+	zo->u.prox = (Z_ProximityOperator *)
+	    odr_malloc (o, sizeof(*zo->u.prox));
+	zo->u.prox->exclusion = 0;
+
+	zo->u.prox->distance = (int *)
+	    odr_malloc (o, sizeof(*zo->u.prox->distance));
+	*zo->u.prox->distance = 2;
+
+	zo->u.prox->ordered = (bool_t *)
+	    odr_malloc (o, sizeof(*zo->u.prox->ordered));
+	*zo->u.prox->ordered = 0;
+
+	zo->u.prox->relationType = (int *)
+	    odr_malloc (o, sizeof(*zo->u.prox->relationType));
+#ifdef ASN_COMPILED
+	*zo->u.prox->relationType = Z_ProximityOperator_Prox_lessThan;
+	zo->u.prox->which = Z_ProximityOperator_known;
+	zo->u.prox->u.known = 
+	    odr_malloc (o, sizeof(*zo->u.prox->u.known));
+	*zo->u.prox->u.known = Z_ProxUnit_word;
+#else
+	*zo->u.prox->relationType = Z_Prox_lessThan;
+	zo->u.prox->which = Z_ProxCode_known;
+	zo->u.prox->proximityUnitCode = (int*)
+	    odr_malloc (o, sizeof(*zo->u.prox->proximityUnitCode));
+	*zo->u.prox->proximityUnitCode = Z_ProxUnit_word;
+#endif
+	break;
+    default:
+	return 0;
+    }
+    zc->s1 = ccl_rpn_structure (o, p->u.p[0]);
+    zc->s2 = ccl_rpn_structure (o, p->u.p[1]);
+    return zc;
+}
+
+static Z_RPNStructure *ccl_rpn_structure (ODR o, struct ccl_rpn_node *p)
+{
+    Z_RPNStructure *zs;
+
+    zs = (Z_RPNStructure *)odr_malloc (o, sizeof(*zs));
+    switch (p->kind)
+    {
+    case CCL_RPN_AND:
+    case CCL_RPN_OR:
+    case CCL_RPN_NOT:
+    case CCL_RPN_PROX:
+        zs->which = Z_RPNStructure_complex;
+        zs->u.complex = ccl_rpn_complex (o, p);
+        break;
+    case CCL_RPN_TERM:
+    case CCL_RPN_SET:
+        zs->which = Z_RPNStructure_simple;
+        zs->u.simple = ccl_rpn_simple (o, p);
+        break;
+    default:
+	return 0;
+    }
+    return zs;
+}
+
+Z_RPNQuery *ccl_rpn_query (ODR o, struct ccl_rpn_node *p)
+{
+    Z_RPNQuery *zq;
+
+    zq = (Z_RPNQuery *)odr_malloc (o, sizeof(*zq));
+    zq->attributeSetId = NULL;
+    zq->RPNStructure = ccl_rpn_structure (o, p);
+    return zq;
+}
+
+Z_AttributesPlusTerm *ccl_scan_query (ODR o, struct ccl_rpn_node *p)
+{
+    if (p->kind != CCL_RPN_TERM)
+        return NULL;
+    return ccl_rpn_term (o, p);
+}
+
+static void ccl_pquery_complex (WRBUF w, struct ccl_rpn_node *p)
+{
+    switch (p->kind)
+    {
+    case CCL_RPN_AND:
+    	wrbuf_puts (w, "@and ");
+	break;
+    case CCL_RPN_OR:
+    	wrbuf_puts(w, "@or ");
+	break;
+    case CCL_RPN_NOT:
+    	wrbuf_puts(w, "@not ");
+	break;
+    case CCL_RPN_PROX:
+    	wrbuf_puts(w, "@prox 0 2 0 1 known 2 ");
+	break;
+    default:
+	wrbuf_puts(w, "@ bad op (unknown) ");
+    };
+    ccl_pquery(w, p->u.p[0]);
+    ccl_pquery(w, p->u.p[1]);
+}
+    	
+void ccl_pquery (WRBUF w, struct ccl_rpn_node *p)
+{
+    struct ccl_rpn_attr *att;
+
+    switch (p->kind)
+    {
+    case CCL_RPN_AND:
+    case CCL_RPN_OR:
+    case CCL_RPN_NOT:
+    case CCL_RPN_PROX:
+    	ccl_pquery_complex (w, p);
+	break;
+    case CCL_RPN_SET:
+	wrbuf_puts (w, "@set ");
+	wrbuf_puts (w, p->u.setname);
+	wrbuf_puts (w, " ");
+	break;
+    case CCL_RPN_TERM:
+    	for (att = p->u.t.attr_list; att; att = att->next)
+	{
+	    char tmpattr[128];
+	    sprintf(tmpattr, "@attr %d=%d ", att->type, att->value);
+	    wrbuf_puts (w, tmpattr);
+	}
+	wrbuf_puts (w, "{");
+	wrbuf_puts (w, p->u.t.term);
+	wrbuf_puts (w, "} ");
+	break;
+    }
+}
Index: /main/tags/2.25/gsdl/packages/yaz/zutil/zget.c
===================================================================
--- /main/tags/2.25/gsdl/packages/yaz/zutil/zget.c	(revision 21064)
+++ /main/tags/2.25/gsdl/packages/yaz/zutil/zget.c	(revision 21064)
@@ -0,0 +1,531 @@
+/*
+ * Copyright (c) 1995-1999, Index Data.
+ * See the file LICENSE for details.
+ * Sebastian Hammer, Adam Dickmeiss
+ *
+ * $Log$
+ * Revision 1.1  2000/08/03 03:12:39  johnmcp
+ * Added the YAZ toolkit source to the packages directory (for z39.50 stuff)
+ *
+ * Revision 1.2  1999/11/30 13:47:12  adam
+ * Improved installation. Moved header files to include/yaz.
+ *
+ * Revision 1.1  1999/06/08 10:10:16  adam
+ * New sub directory zutil. Moved YAZ Compiler to be part of YAZ tree.
+ *
+ * Revision 1.17  1999/04/20 09:56:48  adam
+ * Added 'name' paramter to encoder/decoder routines (typedef Odr_fun).
+ * Modified all encoders/decoders to reflect this change.
+ *
+ * Revision 1.16  1998/08/19 16:10:05  adam
+ * Changed som member names of DeleteResultSetRequest/Response.
+ *
+ * Revision 1.15  1998/03/31 15:13:19  adam
+ * Development towards compiled ASN.1.
+ *
+ * Revision 1.14  1998/02/11 11:53:32  adam
+ * Changed code so that it compiles as C++.
+ *
+ * Revision 1.13  1998/01/29 13:13:39  adam
+ * Function zget_presentRequest fills resultSetId with "default" instead
+ * of "Default".
+ *
+ * Revision 1.12  1997/10/29 12:00:37  adam
+ * Routine zget_SearchRequest fills resultSetName member with "default"
+ * instead of "Default".
+ *
+ * Revision 1.11  1997/05/02 08:39:10  quinn
+ * New PDUs added, thanks to Ronald van der Meer
+ *
+ * Revision 1.10  1996/01/02 08:57:23  quinn
+ * Changed enums in the ASN.1 .h files to #defines. Changed oident.class to oclass
+ *
+ * Revision 1.9  1995/09/29  17:11:55  quinn
+ * Smallish
+ *
+ * Revision 1.8  1995/09/27  15:02:43  quinn
+ * Modified function heads & prototypes.
+ *
+ * Revision 1.7  1995/06/15  07:44:52  quinn
+ * Moving to v3.
+ *
+ * Revision 1.6  1995/06/14  15:26:37  quinn
+ * *** empty log message ***
+ *
+ * Revision 1.5  1995/06/07  14:42:30  quinn
+ * Fixed CLOSE
+ *
+ * Revision 1.4  1995/06/07  14:36:25  quinn
+ * Added CLOSE
+ *
+ * Revision 1.3  1995/06/05  10:52:06  quinn
+ * Fixed some negligences.
+ *
+ * Revision 1.2  1995/05/30  10:15:49  quinn
+ * Added our implementor's ID
+ *
+ * Revision 1.1  1995/05/22  11:30:20  quinn
+ * Adding Z39.50-1992 stuff to proto.c. Adding zget.c
+ *
+ *
+ */
+
+#include <yaz/proto.h>
+
+Z_InitRequest *zget_InitRequest(ODR o)
+{
+    Z_InitRequest *r = (Z_InitRequest *)odr_malloc(o, sizeof(*r));
+
+    r->referenceId = 0;
+    r->options = (Odr_bitmask *)odr_malloc(o, sizeof(*r->options));
+    ODR_MASK_ZERO(r->options);
+    r->protocolVersion = (Odr_bitmask *)odr_malloc(o, sizeof(*r->protocolVersion));
+    ODR_MASK_ZERO(r->protocolVersion);
+    r->preferredMessageSize = (int *)odr_malloc(o, sizeof(int));
+    *r->preferredMessageSize = 30*1024;
+    r->maximumRecordSize = (int *)odr_malloc(o, sizeof(int));
+    *r->maximumRecordSize = 30*1024;
+    r->idAuthentication = 0;
+    r->implementationId = "YAZ (id=81)";
+    r->implementationName = "Index Data/YAZ";
+    r->implementationVersion = YAZ_VERSION;
+    r->userInformationField = 0;
+    r->otherInfo = 0;
+    return r;
+}
+
+Z_InitResponse *zget_InitResponse(ODR o)
+{
+    Z_InitResponse *r = (Z_InitResponse *)odr_malloc(o, sizeof(*r));
+
+    r->referenceId = 0;
+    r->options = (Odr_bitmask *)odr_malloc(o, sizeof(*r->options));
+    ODR_MASK_ZERO(r->options);
+    r->protocolVersion = (Odr_bitmask *)odr_malloc(o, sizeof(*r->protocolVersion));
+    ODR_MASK_ZERO(r->protocolVersion);
+    r->preferredMessageSize = (int *)odr_malloc(o, sizeof(int));
+    *r->preferredMessageSize = 30*1024;
+    r->maximumRecordSize = (int *)odr_malloc(o, sizeof(int));
+    *r->maximumRecordSize = 30*1024;
+    r->result = (int *)odr_malloc(o, sizeof(bool_t));
+    *r->result = 1;
+    r->implementationId = "YAZ (id=81)";
+    r->implementationName = "Index Data/YAZ";
+    r->implementationVersion = YAZ_VERSION;
+    r->userInformationField = 0;
+    r->otherInfo = 0;
+    return r;
+}
+
+Z_SearchRequest *zget_SearchRequest(ODR o)
+{
+    Z_SearchRequest *r = (Z_SearchRequest *)odr_malloc(o, sizeof(*r));
+
+    r->referenceId = 0;
+    r->smallSetUpperBound = (int *)odr_malloc(o, sizeof(int));
+    *r->smallSetUpperBound = 0;
+    r->largeSetLowerBound = (int *)odr_malloc(o, sizeof(int));
+    *r->largeSetLowerBound = 1;
+    r->mediumSetPresentNumber = (int *)odr_malloc(o, sizeof(int));
+    *r->mediumSetPresentNumber = 0;
+    r->replaceIndicator = (int *)odr_malloc(o, sizeof(bool_t));
+    *r->replaceIndicator = 1;
+    r->resultSetName = "default";
+    r->num_databaseNames = 0;
+    r->databaseNames = 0;
+    r->smallSetElementSetNames = 0;
+    r->mediumSetElementSetNames = 0;
+    r->preferredRecordSyntax = 0;
+    r->query = 0;
+    r->additionalSearchInfo = 0;
+    r->otherInfo = 0;
+    return r;
+}
+
+Z_SearchResponse *zget_SearchResponse(ODR o)
+{
+    Z_SearchResponse *r = (Z_SearchResponse *)odr_malloc(o, sizeof(*r));
+
+    r->referenceId = 0;
+    r->resultCount = (int *)odr_malloc(o, sizeof(int));
+    *r->resultCount = 0;
+    r->numberOfRecordsReturned = (int *)odr_malloc(o, sizeof(int));
+    *r->numberOfRecordsReturned = 0;
+    r->nextResultSetPosition = (int *)odr_malloc(o, sizeof(int));
+    *r->nextResultSetPosition = 0;
+    r->searchStatus = (int *)odr_malloc(o, sizeof(bool_t));
+    *r->searchStatus = 1;
+    r->resultSetStatus = 0;
+    r->presentStatus = 0;
+    r->records = 0;
+    r->additionalSearchInfo = 0;
+    r->otherInfo = 0;
+    return r;
+}
+
+Z_PresentRequest *zget_PresentRequest(ODR o)
+{
+    Z_PresentRequest *r = (Z_PresentRequest *)odr_malloc(o, sizeof(*r));
+
+    r->referenceId = 0;
+    r->resultSetId = "default";
+    r->resultSetStartPoint = (int *)odr_malloc(o, sizeof(int));
+    *r->resultSetStartPoint = 1;
+    r->numberOfRecordsRequested = (int *)odr_malloc(o, sizeof(int));
+    *r->numberOfRecordsRequested = 10;
+    r->num_ranges = 0;
+    r->additionalRanges = 0;
+    r->recordComposition = 0;
+    r->preferredRecordSyntax = 0;
+    r->maxSegmentCount = 0;
+    r->maxRecordSize = 0;
+    r->maxSegmentSize = 0;
+    r->otherInfo = 0;
+    return r;
+}
+
+Z_PresentResponse *zget_PresentResponse(ODR o)
+{
+    Z_PresentResponse *r = (Z_PresentResponse *)odr_malloc(o, sizeof(*r));
+
+    r->referenceId = 0;
+    r->numberOfRecordsReturned = (int *)odr_malloc(o, sizeof(int));
+    *r->numberOfRecordsReturned = 0;
+    r->nextResultSetPosition = (int *)odr_malloc(o, sizeof(int));
+    *r->nextResultSetPosition = 0;
+    r->presentStatus = (int *)odr_malloc(o, sizeof(int));
+    *r->presentStatus = Z_PRES_SUCCESS;
+    r->records = 0;
+    r->otherInfo = 0;
+    return r;
+}
+
+Z_DeleteResultSetRequest *zget_DeleteResultSetRequest(ODR o)
+{
+    Z_DeleteResultSetRequest *r = (Z_DeleteResultSetRequest *)
+	odr_malloc(o, sizeof(*r));
+
+    r->referenceId = 0;
+    r->deleteFunction = (int *)odr_malloc(o, sizeof(int));
+    *r->deleteFunction = Z_DeleteRequest_list;
+    r->num_resultSetList = 0;
+    r->resultSetList = 0;
+    r->otherInfo = 0;
+    return r;
+}
+
+Z_DeleteResultSetResponse *zget_DeleteResultSetResponse(ODR o)
+{
+    Z_DeleteResultSetResponse *r = (Z_DeleteResultSetResponse *)
+	odr_malloc(o, sizeof(*r));
+    
+    r->referenceId = 0;
+    r->deleteOperationStatus = (int *)odr_malloc(o, sizeof(int));
+    *r->deleteOperationStatus = Z_DeleteStatus_success;
+    r->deleteListStatuses = 0;
+    r->numberNotDeleted = 0;
+    r->bulkStatuses = 0;
+    r->deleteMessage = 0;
+    r->otherInfo = 0;
+    return r;
+}
+
+Z_ScanRequest *zget_ScanRequest(ODR o)
+{
+    Z_ScanRequest *r = (Z_ScanRequest *)odr_malloc(o, sizeof(*r));
+    
+    r->referenceId = 0;
+    r->num_databaseNames = 0;
+    r->databaseNames = 0;
+    r->attributeSet = 0;
+    r->termListAndStartPoint = 0;
+    r->stepSize = 0;
+    r->numberOfTermsRequested = (int *)odr_malloc(o, sizeof(int));
+    *r->numberOfTermsRequested = 20;
+    r->preferredPositionInResponse = 0;
+    r->otherInfo = 0;
+    return r;
+}
+
+Z_ScanResponse *zget_ScanResponse(ODR o)
+{
+    Z_ScanResponse *r = (Z_ScanResponse *)odr_malloc(o, sizeof(*r));
+    
+    r->referenceId = 0;
+    r->stepSize = 0;
+    r->scanStatus = (int *)odr_malloc(o, sizeof(int));
+    *r->scanStatus = Z_Scan_success;
+    r->numberOfEntriesReturned = (int *)odr_malloc(o, sizeof(int));
+    *r->numberOfEntriesReturned = 0;
+    r->positionOfTerm =0;
+    r->entries = 0;
+    r->attributeSet = 0;
+    r->otherInfo = 0;
+    return r;
+}
+
+Z_TriggerResourceControlRequest *zget_TriggerResourceControlRequest(ODR o)
+{
+    Z_TriggerResourceControlRequest *r = (Z_TriggerResourceControlRequest *)
+	odr_malloc(o, sizeof(*r));
+    
+    r->referenceId = 0;
+    r->requestedAction = (int *)odr_malloc(o, sizeof(int));
+    *r->requestedAction = Z_TriggerResourceCtrl_resourceReport;
+    r->prefResourceReportFormat = 0;
+    r->resultSetWanted = 0;
+    r->otherInfo = 0;
+    return r;
+}
+
+Z_ResourceControlRequest *zget_ResourceControlRequest(ODR o)
+{
+    Z_ResourceControlRequest *r = (Z_ResourceControlRequest *)
+	odr_malloc(o, sizeof(*r));
+
+    r->referenceId = 0;
+    r->suspendedFlag = 0;
+    r->resourceReport = 0;
+    r->partialResultsAvailable = 0;
+    r->responseRequired = (int *)odr_malloc(o, sizeof(bool_t));
+    *r->responseRequired = 0;
+    r->triggeredRequestFlag = 0;
+    r->otherInfo = 0;
+    return r;
+}
+
+Z_ResourceControlResponse *zget_ResourceControlResponse(ODR o)
+{
+    Z_ResourceControlResponse *r = (Z_ResourceControlResponse *)
+	odr_malloc(o, sizeof(*r));
+
+    r->referenceId = 0;
+    r->continueFlag = (int *)odr_malloc(o, sizeof(bool_t));
+    *r->continueFlag = 1;
+    r->resultSetWanted = 0;
+    r->otherInfo = 0;
+    return r;
+}
+
+Z_AccessControlRequest *zget_AccessControlRequest(ODR o)
+{
+    Z_AccessControlRequest *r = (Z_AccessControlRequest *)
+	odr_malloc(o, sizeof(*r));
+
+    r->referenceId = 0;
+    r->which = Z_AccessRequest_simpleForm;
+    r->u.simpleForm = 0;
+    r->otherInfo = 0;
+    return r;
+}
+
+Z_AccessControlResponse *zget_AccessControlResponse(ODR o)
+{
+    Z_AccessControlResponse *r = (Z_AccessControlResponse *)
+	odr_malloc(o, sizeof(*r));
+
+    r->referenceId = 0;
+    r->which = Z_AccessResponse_simpleForm;
+    r->u.simpleForm = 0;
+    r->diagnostic = 0;
+    r->otherInfo = 0;
+    return r;
+}
+
+Z_Segment *zget_Segment(ODR o)
+{
+    Z_Segment *r = (Z_Segment *)odr_malloc(o, sizeof(*r));
+
+    r->referenceId = 0;
+    r->numberOfRecordsReturned = (int *)odr_malloc(o, sizeof(int));
+    *r->numberOfRecordsReturned = 0;
+    r->num_segmentRecords = 0;
+    r->segmentRecords = 0;
+    r->otherInfo = 0;
+    return r;
+}
+
+Z_Close *zget_Close(ODR o)
+{
+    Z_Close *r = (Z_Close *)odr_malloc(o, sizeof(*r));
+
+    r->referenceId = 0;
+    r->closeReason = (int *)odr_malloc(o, sizeof(int));
+    *r->closeReason = Z_Close_finished;
+    r->diagnosticInformation = 0;
+    r->resourceReportFormat = 0;
+    r->resourceReport = 0;
+    r->otherInfo = 0;
+    return r;
+}
+
+Z_ResourceReportRequest *zget_ResourceReportRequest(ODR o)
+{
+    Z_ResourceReportRequest *r = (Z_ResourceReportRequest *)
+	odr_malloc(o, sizeof(*r));
+
+    r->referenceId = 0;
+    r->opId = 0;
+    r->prefResourceReportFormat = 0;
+    r->otherInfo = 0;
+    return r;
+}
+
+Z_ResourceReportResponse *zget_ResourceReportResponse(ODR o)
+{
+    Z_ResourceReportResponse *r = (Z_ResourceReportResponse *)
+	odr_malloc(o, sizeof(*r));
+
+    r->referenceId = 0;
+    r->resourceReportStatus = (int *)odr_malloc(o, sizeof(int));
+    *r->resourceReportStatus = Z_ResourceReportStatus_success;
+    r->resourceReport = 0;
+    r->otherInfo = 0;
+    return r;
+}
+
+Z_SortRequest *zget_SortRequest(ODR o)
+{
+    Z_SortRequest *r = (Z_SortRequest *)odr_malloc(o, sizeof(*r));
+
+    r->referenceId = 0;
+    r->inputResultSetNames = 0;
+    r->sortedResultSetName = 0;
+    r->sortSequence = 0;
+    r->otherInfo = 0;
+    return r;
+}
+
+Z_SortResponse *zget_SortResponse(ODR o)
+{
+    Z_SortResponse *r = (Z_SortResponse *)odr_malloc(o, sizeof(*r));
+
+    r->referenceId = 0;
+    r->sortStatus = (int *)odr_malloc(o, sizeof(int));
+    *r->sortStatus = Z_SortStatus_success;
+    r->resultSetStatus = (int *)odr_malloc(o, sizeof(int));
+    *r->resultSetStatus = Z_SortResultSetStatus_empty;
+    r->diagnostics = 0;
+    r->otherInfo = 0;
+    return r;
+}
+
+Z_ExtendedServicesRequest *zget_ExtendedServicesRequest(ODR o)
+{
+    Z_ExtendedServicesRequest *r = (Z_ExtendedServicesRequest *)
+	odr_malloc(o, sizeof(*r));
+
+    r->referenceId = 0;
+    r->function = (int *)odr_malloc(o, sizeof(int));
+    *r->function = Z_ExtendedServicesRequest_create;
+    r->packageType = 0;
+    r->packageName = 0;
+    r->userId = 0;
+    r->retentionTime = 0;
+    r->permissions = 0;
+    r->description = 0;
+    r->taskSpecificParameters = 0;
+    r->waitAction = (int *)odr_malloc(o, sizeof(int));
+    *r->waitAction = Z_ExtendedServicesRequest_wait;
+    r->elements = 0;
+    r->otherInfo = 0;
+    return r;
+}
+
+Z_ExtendedServicesResponse *zget_ExtendedServicesResponse(ODR o)
+{
+    Z_ExtendedServicesResponse *r = (Z_ExtendedServicesResponse *)
+	odr_malloc(o, sizeof(*r));
+
+    r->referenceId = 0;
+    r->operationStatus = (int *)odr_malloc(o, sizeof(int));
+    *r->operationStatus = Z_ExtendedServicesResponse_done;
+    r->num_diagnostics = 0;
+    r->diagnostics = 0;
+    r->taskPackage = 0;
+    r->otherInfo = 0;
+    return r;
+}
+
+Z_APDU *zget_APDU(ODR o, int which)
+{
+    Z_APDU *r = (Z_APDU *)odr_malloc(o, sizeof(*r));
+
+    switch (r->which = which)
+    {
+    	case Z_APDU_initRequest:
+	    r->u.initRequest = zget_InitRequest(o);
+            break;
+	case Z_APDU_initResponse:
+	    r->u.initResponse = zget_InitResponse(o);
+            break;
+	case Z_APDU_searchRequest:
+	    r->u.searchRequest = zget_SearchRequest(o);
+            break;
+	case Z_APDU_searchResponse:
+	    r->u.searchResponse = zget_SearchResponse(o);
+            break;
+	case Z_APDU_presentRequest:
+	    r->u.presentRequest = zget_PresentRequest(o);
+            break;
+	case Z_APDU_presentResponse:
+	    r->u.presentResponse = zget_PresentResponse(o);
+            break;
+	case Z_APDU_deleteResultSetRequest:
+	    r->u.deleteResultSetRequest = zget_DeleteResultSetRequest(o);
+            break;
+	case Z_APDU_deleteResultSetResponse:
+	    r->u.deleteResultSetResponse = zget_DeleteResultSetResponse(o);
+	    break;
+	case Z_APDU_scanRequest:
+	    r->u.scanRequest = zget_ScanRequest(o);
+            break;
+	case Z_APDU_scanResponse:
+	    r->u.scanResponse = zget_ScanResponse(o);
+            break;
+	case Z_APDU_triggerResourceControlRequest:
+	    r->u.triggerResourceControlRequest =
+                zget_TriggerResourceControlRequest(o);
+            break;
+	case Z_APDU_resourceControlRequest:
+	    r->u.resourceControlRequest = zget_ResourceControlRequest(o);
+	    break;
+	case Z_APDU_resourceControlResponse:
+	    r->u.resourceControlResponse = zget_ResourceControlResponse(o);
+	    break;
+	case Z_APDU_segmentRequest:
+	    r->u.segmentRequest = zget_Segment(o);
+	    break;
+	case Z_APDU_close:
+	    r->u.close = zget_Close(o);
+	    break;
+	case Z_APDU_accessControlRequest:
+	    r->u.accessControlRequest = zget_AccessControlRequest(o);
+	    break;
+	case Z_APDU_accessControlResponse:
+	    r->u.accessControlResponse = zget_AccessControlResponse(o);
+	    break;
+	case Z_APDU_resourceReportRequest:
+	    r->u.resourceReportRequest = zget_ResourceReportRequest(o);
+	    break;
+	case Z_APDU_resourceReportResponse:
+	    r->u.resourceReportResponse = zget_ResourceReportResponse(o);
+	    break;
+	case Z_APDU_sortRequest:
+	    r->u.sortRequest = zget_SortRequest(o);
+	    break;
+	case Z_APDU_sortResponse:
+	    r->u.sortResponse = zget_SortResponse(o);
+	    break;
+	case Z_APDU_extendedServicesRequest:
+	    r->u.extendedServicesRequest = zget_ExtendedServicesRequest(o);
+	    break;
+	case Z_APDU_extendedServicesResponse:
+	    r->u.extendedServicesResponse = zget_ExtendedServicesResponse(o);
+	    break;
+	default:
+	    fprintf(stderr, "Bad APDU-type to zget_APDU");
+	    exit(1);
+    }
+    return r;
+}
Index: /main/tags/2.25/gsdl/perllib/acronym.pm
===================================================================
--- /main/tags/2.25/gsdl/perllib/acronym.pm	(revision 21064)
+++ /main/tags/2.25/gsdl/perllib/acronym.pm	(revision 21064)
@@ -0,0 +1,450 @@
+##########################################################################
+#
+# acronym.pm --
+# A component of the Greenstone digital library software
+# from the New Zealand Digital Library Project at the 
+# University of Waikato, New Zealand.
+#
+# Copyright (C) 1999 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.
+#
+###########################################################################
+#    class to handle acronyms
+###########################################################################
+
+use strict;
+use diagnostics;
+
+package acronym;
+
+###########################################################################
+#    global variables
+###########################################################################
+# valiables to control the recall/precision tradeoff
+
+#the maximum range to look for acronyms
+my $max_offset = 30;
+#acronyms must be upper case
+my $upper_case = 1;
+#acronym case must match
+my $case_match = 1;
+#minimum acronym length
+my $min_def_length = 3;
+#minimum acronym length
+my $min_acro_length = 3;
+#minimum acronym length saving
+my $min_length_saving = 3;
+#allow recusive acronyms
+my $allow_recursive = "";
+
+my @stop_words = split / /, "A OF AT THE IN TO AND VON BEI DER DIE DAS DEM DEN DES UND";
+#my @stop_words = split / /, "OF AT THE IN TO AND";
+
+#the text split into an array, one word per element
+my @split_text = ();
+my @acronym_list = ();
+
+
+###########################################################################
+#    member functions 
+###########################################################################
+
+
+sub new {
+    my $self = [
+	"", # 0 acronym
+	[], # 1 definition
+    ];
+    bless $self;
+}
+
+
+
+sub clone  {
+    my $self = shift (@_);
+
+    my $copy = new acronym;
+
+    $copy->[0] = $self->[0];
+    push @{$copy->[1]}, @{$self->[1]};
+    bless $copy;
+
+    return $copy;
+}
+
+#return the acronym
+sub to_acronym {
+    my $self = shift (@_);
+    my @array = @{$self->[1]};
+
+    return $self->[0];
+}
+
+#return the number of words in the acronym definition
+sub words_in_acronym_definition {
+    my $self = shift (@_);
+    my @array = @{$self->[1]};
+
+    return $#array + 1;
+}
+
+#return the number of letters in the acronym definition
+sub letters_in_acronym_definition {
+    my $self = shift (@_);
+
+    return length($self->to_def_string());
+}
+
+#return the number of letters in the acronym definition
+sub letters_in_acronym {
+    my $self = shift (@_);
+
+    return length($self->to_acronym());
+}
+
+#return the acronym definition
+sub to_def_string {
+    my $self = shift (@_);
+
+    my $result = "";
+
+    # do the definition
+    my @array = @{$self->[1]};
+    my $i = 0;
+    while ($i <= $#array)
+    {
+	$result = $result . $array[$i];
+
+	if ($i+1 <= $#array)
+	{
+	    $result = $result . " ";
+	}
+	$i++;
+    }
+    return $result;
+}
+
+
+#print out the kwic for the acronym
+sub to_string_kwic {
+    my $self = shift (@_);
+
+    # the list of all possible combinations
+    my @list = ();
+
+    my $result = "";
+
+    my $j = 0;
+    my @array = @{$self->[1]};
+    while ($j <= $#array)
+    {
+
+	# do the definition
+	my $i = 0;
+
+	#add the key word
+	$result = "<td halign=left>"  . $array[$j] . "</td><td halign=right>";
+
+	#add the proceeding words
+	while ($i < $j)
+	{
+	    $result = $result .  $array[$i] . " ";
+	    $i++;
+	}
+	#add the key word
+	$result = $result . "</td><td halign=left>"  . $array[$j] . 
+	    "</td><td halign=left>";
+
+	#add the trailing words
+	$i++;
+	while ($i <= $#array )
+	{
+	    $result = $result .  $array[$i] . " ";
+	    $i++;
+	}
+
+	#add the actual acronym
+
+	$result = $result . "</td><td halign=left>" . $self->[0] . "</td>";
+
+	push @list, $result;
+	$j++;
+    }
+    return @list;
+}
+
+#this is the one used when building the collection ...
+sub to_string {
+    my $self = shift (@_);
+
+    my $result = $self->[0] . " ";
+
+    # do the definition
+    my @array = @{$self->[1]};
+    my $i = 0;
+    while ($i <= $#array)
+    {
+	$result = $result . $array[$i];
+	if ($i+1 <= $#array)
+	{
+	    $result = $result . " ";
+	}
+	$i++;
+    }
+    return $result;
+}
+
+sub check {
+    my $self = shift (@_);
+
+    if (length($self->to_acronym()) < $min_acro_length) 
+    {
+#	print "acronym " . $self->to_string() . " rejected (too short I)\n";
+	return 0;
+    }
+    if ($self->words_in_acronym_definition() < $min_def_length) 
+    {
+#	print "acronym " . $self->to_string() . " rejected (too short II)\n";
+	return 0;
+    }
+    if ($min_length_saving * $self->letters_in_acronym() > 
+	$self->letters_in_acronym_definition()) 
+    {
+#	print "acronym " . $self->to_string() . " rejected (too short III)\n";
+#	print "" . $min_length_saving .
+	    "|" . $self->letters_in_acronym() .
+	    "|" . $self->letters_in_acronym_definition() . "\n";
+	return 0;
+    }
+#    print "acronym " . $self->to_string() . " not rejected\n";
+    return 1;
+}
+
+###########################################################################
+#    static functions 
+###########################################################################
+
+sub recurse {
+    my ($acro_offset,       #offset of word we're finding acronyms for
+	$text_offset,       
+	$letter_offset, 
+	@def_so_far) = @_;
+
+    my $word = $split_text[$text_offset];
+    my $acro = $split_text[$acro_offset];
+    $word = "" if !defined $word;
+    $acro = "" if !defined $acro;
+    
+#    print "recurse(" . $acro_offset . ", " . $text_offset . ", " . 
+#	$letter_offset  . ", " . @def_so_far . ")\n";
+
+    #check for termination ...
+    if ($letter_offset >= length($acro))
+    {	
+	my $acronym = new acronym();
+	$acronym->[0] = $acro;
+	push @{$acronym->[1]}, @def_so_far;
+	if ($acronym->check())
+	{
+	    push @acronym_list, ( $acronym );
+	}
+#	print "acronym created\n";
+	return;
+    }
+    #check for recursion
+    if (!$allow_recursive)
+    {
+	if ($word eq $acro)
+	{
+#	    print "recursion detected\n";
+	    return;
+	}
+    }
+    
+    #skip a stop-word
+    my $i = 0;
+    if ($letter_offset != 0)
+    {
+	while ($i <= $#stop_words)
+	{
+	    if ($stop_words[$i] eq uc($word))
+	    {
+#	    print "::found stop word::" . $stop_words[$i] . "\n";
+		&recurse($acro_offset,
+			 $text_offset+1,
+			 $letter_offset,
+			 @def_so_far, $word);
+	    }
+	    $i++;
+	}
+    }
+    $i = 1;
+    #using the first $i letters ...
+    while ($letter_offset+$i <= length($acro) )
+    {
+#	print "". ((substr $word, 0, $i) . " " . 
+#	    (substr $acro, $letter_offset, $i) . "\n");
+	if (((!$case_match) &&
+	     (uc(substr $word, 0, $i) eq
+	      uc(substr $acro, $letter_offset, $i)))
+	    ||
+	    (($case_match) &&
+	     ((substr $word, 0, $i) eq
+	      (substr $acro, $letter_offset, $i))))
+	{
+#	    print "::match::\n";
+#	    print "" . ((substr $word, 0, $i) . " " . 
+#		   (substr $acro, $letter_offset, $i) . "\n");
+	    &recurse($acro_offset,
+		     $text_offset+1,
+		     $letter_offset+$i,
+		     @def_so_far, $word);
+	} else {
+	    return;
+	}	    
+	$i++;
+    }
+    return;
+}
+
+
+sub acronyms {
+    #clean up the text
+    my $processed_text =  shift @_;
+    $$processed_text =~ s/[^A-Za-z]/ /g;
+    $$processed_text =~ s/\s+/ /g;
+
+    #clear some global variables
+    @split_text = ();
+    @acronym_list = ();
+
+    return &acronyms_from_clean_text($processed_text);
+}
+
+sub acronyms_from_clean_text {
+    my ($processed_text) = @_;
+
+    @split_text = split / /, $$processed_text;
+
+#    my $i = 0;
+#    while ($i <= $#split_text)
+#    {
+#	print $split_text[$i] . "\n";
+#	$i++;
+#    }
+
+    my $first = 0;
+    my $last = $#split_text +1;
+    my $acro_counter = $first;
+    
+    while ($acro_counter < $last)
+    {
+	my $word = $split_text[$acro_counter];
+
+	if ((!$upper_case) ||
+	    (uc($word) eq $word))
+	{
+	    
+	    if (length $word >= $min_acro_length)
+	    {
+		my $def_counter = 0;
+		if ($acro_counter - $max_offset > 0)
+		{
+		    $def_counter = $acro_counter - $max_offset;
+		}
+		my $local_last = $acro_counter  + $max_offset;
+		if ($local_last > $last)
+		{
+		    $local_last = $last;
+		}
+		while ($def_counter <= $local_last)
+		{
+		    &recurse($acro_counter,$def_counter,0,());
+		    $def_counter++;
+		}
+	    }
+	}
+	$acro_counter++;
+    }
+
+    return \@acronym_list;
+}
+
+
+
+sub test {
+
+#    my $blarg = new acronym();
+#    my $simple;
+#    $simple = 10;
+#    $blarg->initialise($simple, $simple, $simple);
+#    my $blarg2 = $blarg->clone();
+#    print $blarg->to_string();
+#    print $blarg2;
+#    print "\n";
+#    
+    my $tla = new acronym();
+    $tla->[0] = "TLA";
+
+    my @array = ("Three", "Letter", "Acronym");
+#    my $i = 0;
+#    while ($i <= $#array)
+#    {
+#	print @array[$i] . "\n";
+#	$i++;
+#    }
+
+    print "\n";
+    push @{$tla->[1]}, ("Three" );
+    push @{$tla->[1]}, ("Letter" );
+    push @{$tla->[1]}, ("Acronym" );
+    print $tla->to_string(). "\n";
+    print "\n";
+    print "\n";
+    my $tla2 = $tla->clone();
+    push @{$tla2->[1]}, ("One");
+    push @{$tla2->[1]}, ("Two");
+    $tla2->[0] = "ALT";
+    print $tla->to_string(). "\n";
+    print $tla2->to_string(). "\n";
+
+    print "\n";
+    print "\n";
+
+    print "Testing recursion ...\n";
+    my $acros = &acronyms("TLA Three Letter Acronym in tla TlA");
+    
+    foreach my $acro (@$acros)
+    {
+	if ($acro->check)
+        {
+           print "accepted: " .$acro->to_string() . "\n";
+#           print "|" .  $acro->to_acronym() . "|" .  $acro->to_def_string() .
+#              "|" .  $acro->words_in_acronym_definition() .
+#              "|" .  $acro->letters_in_acronym_definition() . 
+#              "|" .  $acro->letters_in_acronym() . "|\n";
+        } else {
+#          print "found but rejected: " .$acro->to_string() . "\n";
+        }
+    }
+}
+
+#uncomment this line to test this package
+#&test();
+
+1;
+
+
Index: /main/tags/2.25/gsdl/perllib/arcinfo.pm
===================================================================
--- /main/tags/2.25/gsdl/perllib/arcinfo.pm	(revision 21064)
+++ /main/tags/2.25/gsdl/perllib/arcinfo.pm	(revision 21064)
@@ -0,0 +1,164 @@
+###########################################################################
+#
+# arcinfo.pm --
+# A component of the Greenstone digital library software
+# from the New Zealand Digital Library Project at the 
+# University of Waikato, New Zealand.
+#
+# Copyright (C) 1999 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.
+#
+###########################################################################
+
+
+# This module stores information about the archives. At the moment
+# this information just consists of the file name (relative to the
+# directory the archives information file is in) and its OID.
+
+# This module assumes there is a one to one correspondance between
+# a file in the archives directory and an OID.
+
+
+package arcinfo;
+
+sub new {
+    my ($class) = @_;
+    my $self = {'info'=>{},
+		'order'=>[]};
+
+    return bless $self, $class;
+}
+
+sub load_info {
+    my $self = shift (@_);
+    my ($filename) = @_;
+
+    $self->{'info'} = {};
+
+    if (-e $filename) {
+	open (INFILE, $filename) || 
+	    die "arcinfo::load_info couldn't read $filename\n";
+
+	my ($line, @line);
+	while (defined ($line = <INFILE>)) {
+	    $line =~ s/\cM|\cJ//g; # remove end-of-line characters
+	    @line = split ("\t", $line); # filename, 
+	    if (scalar(@line) >= 2) {
+		$self->add_info (@line);
+	    }
+	}
+
+	close (INFILE);
+    }
+}
+
+sub save_info {
+    my $self = shift (@_);
+    my ($filename) = @_;
+
+    my ($OID, $info);
+
+    open (OUTFILE, ">$filename") || 
+	die "arcinfo::save_info couldn't write $filename\n";
+
+    foreach $info (@{$self->get_OID_list()}) {
+	if (defined $info) {
+	    print OUTFILE join("\t", @$info), "\n";
+	}
+    }
+    
+    close (OUTFILE);
+}
+
+sub delete_info {
+    my $self = shift (@_);
+    my ($OID) = @_;
+
+    if (defined $self->{'info'}->{$OID}) {
+	delete $self->{'info'}->{$OID};
+	
+	my $i = 0;
+	while ($i < scalar (@{$self->{'order'}})) {
+	    if ($self->{'order'}->[$i]->[0] eq $OID) {
+		splice (@{$self->{'order'}}, $i, 1);
+		last;
+	    }
+	    
+	    $i ++;
+	}
+    }
+}
+
+sub add_info {
+    my $self = shift (@_);
+    my ($OID, $doc_file, $sortmeta) = @_;
+    $sortmeta = "" unless defined $sortmeta;
+
+    $self->delete_info ($OID);
+    $self->{'info'}->{$OID} = [$doc_file];
+    push (@{$self->{'order'}}, [$OID, $sortmeta]);
+}
+
+# returns a list of the form [[OID, doc_file], ...]
+sub get_OID_list {
+    my $self = shift (@_);
+
+    my ($OID);
+    my @list = ();
+
+    foreach $OID (sort {$a->[1] cmp $b->[1]} @{$self->{'order'}}) {
+	push (@list, [$OID->[0], $self->{'info'}->{$OID->[0]}->[0]]);
+    }
+
+    return \@list;
+}
+
+# returns a list of the form [[doc_file, OID], ...]
+sub get_file_list {
+    my $self = shift (@_);
+
+    my ($OID);
+    my @list = ();
+
+    foreach $OID (sort {$a->[1] cmp $b->[1]} @{$self->{'order'}}) {
+	push (@list, [$self->{'info'}->{$OID->[0]}->[0], $OID->[0]]);
+    }
+
+    return \@list;
+}
+
+
+# returns a list of the form [doc_file]
+sub get_info {
+    my $self = shift (@_);
+    my ($OID) = @_;
+
+    if (defined $self->{'info'}->{$OID}) {
+	return $self->{'info'}->{$OID};
+    }
+
+    return undef;
+}
+
+
+# returns the number of documents so far
+sub size {
+    my $self = shift (@_);
+    return (scalar(@{$self->{'order'}}));
+}
+
+1;
+
Index: /main/tags/2.25/gsdl/perllib/cfgread.pm
===================================================================
--- /main/tags/2.25/gsdl/perllib/cfgread.pm	(revision 21064)
+++ /main/tags/2.25/gsdl/perllib/cfgread.pm	(revision 21064)
@@ -0,0 +1,139 @@
+###########################################################################
+#
+# cfgread.pm --
+# A component of the Greenstone digital library software
+# from the New Zealand Digital Library Project at the 
+# University of Waikato, New Zealand.
+#
+# Copyright (C) 1999 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.
+#
+###########################################################################
+
+# reads in configuration files
+
+package cfgread;
+
+
+sub read_cfg_line {
+    my ($handle) = @_;
+    my $line = "";
+    my @line = ();
+    my $linecontinues = 0;
+
+    while (defined($line = <$handle>)) {
+	$line =~ s/^\#.*$//;   # remove comments
+	$line =~ s/\cM|\cJ//g; # remove end-of-line characters
+	$line =~ s/^\s+//;     # remove initial white space
+	$linecontinues = $line =~ s/\\$//;
+	while ($line =~ s/\s*(\"[^\"]*\"|\'[^\']*\'|\S+)\s*//) {
+	    if (defined $1) {
+		# remove any enclosing quotes
+		my $entry = $1;
+		$entry =~ s/^([\"\'])(.*)\1$/$2/;
+
+		# substitute an environment variables
+		$entry =~ s/\$(\w+)/$ENV{$1}/g;
+		$entry =~ s/\$\{(\w+)\}/$ENV{$1}/g;
+
+		push (@line, $entry);
+	    } else {
+		push (@line, "");
+	    }
+	}
+
+	if (scalar(@line) > 0 && !$linecontinues) {
+#	    print STDERR "line: \"" . join ("\" \"", @line) . "\"\n";
+	    return \@line;
+	}
+    }
+
+    return undef;
+}
+
+sub write_cfg_line {
+    my ($handle, $line) = @_;
+    print $handle join ("\t", @$line), "\n";
+}
+
+
+# stringexp, arrayexp, hashexp and arrayarrayexp 
+# should be something like '^(this|that)$'
+sub read_cfg_file {
+    my ($filename, $stringexp, $arrayexp, $hashexp, $arrayarrayexp) = @_;
+    my ($line);
+    my $data = {};
+
+    if (open (COLCFG, $filename)) {
+	while (defined ($line = &read_cfg_line('COLCFG'))) {
+	    if (scalar(@$line) >= 2) {
+		my $key = shift (@$line);
+		if (defined $stringexp && $key =~ /$stringexp/) {
+		    $data->{$key} = shift (@$line);
+
+		} elsif (defined $arrayexp && $key =~ /$arrayexp/) {
+		    push (@{$data->{$key}}, @$line);
+
+		} elsif (defined $hashexp && $key =~ /$hashexp/) {
+		    my $k = shift @$line;
+		    my $v = shift @$line;
+		    $data->{$key}->{$k} = $v;
+		} elsif (defined $arrayarrayexp && $key =~ /$arrayarrayexp/) {
+		    if (!defined $data->{$key}) {
+			$data->{$key} = [];
+		    }
+		    push (@{$data->{$key}}, $line);
+		}
+	    }
+	}
+	close (COLCFG);
+    } else {
+	print STDERR "cfgread::read_cfg_file couldn't read the cfg file $filename\n";
+    }
+
+    return $data;
+}
+
+
+# stringexp, arrayexp, hashexp and arrayarrayexp 
+# should be something like '^(this|that)$'
+sub write_cfg_file {
+    my ($filename, $data, $stringexp, $arrayexp, $hashexp, $arrayarrayexp) = @_;
+    
+    if (open (COLCFG, ">$filename")) {
+	foreach $key (sort(keys(%$data))) {
+	    if ($key =~ /$stringexp/) {
+		&write_cfg_line ('COLCFG', [$key, $data->{$key}]);
+	    } elsif ($key =~ /$arrayexp/) {
+		&write_cfg_line ('COLCFG', [$key, @{$data->{$key}}]);
+	    } elsif ($key =~ /$hashexp/) {
+		foreach $k (keys (%{$data->{$key}})) {
+		    &write_cfg_line ('COLCFG', [$key, $k, $data->{$key}->{$k}]);
+		}
+	    } elsif ($key =~ /$arrayarrayexp/) {
+		foreach $k (@{$data->{$key}}) {
+		    &write_cfg_line ('COLCFG', [$key, @$k]);
+		}
+	    }
+	}
+	close (COLCFG);
+    } else {
+	print STDERR "cfgread::write_cfg_file couldn't write the cfg file $filename\n";
+    }
+}
+
+
+1;
Index: /main/tags/2.25/gsdl/perllib/classify.pm
===================================================================
--- /main/tags/2.25/gsdl/perllib/classify.pm	(revision 21064)
+++ /main/tags/2.25/gsdl/perllib/classify.pm	(revision 21064)
@@ -0,0 +1,202 @@
+###########################################################################
+#
+# classify.pm --
+# A component of the Greenstone digital library software
+# from the New Zealand Digital Library Project at the 
+# University of Waikato, New Zealand.
+#
+# Copyright (C) 1999 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.
+#
+###########################################################################
+
+# functions to handle classifiers
+
+package classify;
+
+require util;
+
+
+$next_classify_num = 1;
+
+sub load_classifiers {
+    my ($classify_list) = @_;
+    my @classify_objects = ();
+    
+    foreach $classifyoption (@$classify_list) {
+
+	# get the classifier name
+	my $classname = shift @$classifyoption;
+	next unless defined $classname;
+    
+	# find the classifier
+	my $colclassname = &util::filename_cat($ENV{'GSDLCOLLECTDIR'},"perllib/classify", 
+					       "${classname}.pm");
+	my $mainclassname = &util::filename_cat($ENV{'GSDLHOME'},"perllib/classify", 
+						"${classname}.pm");
+
+	if (-e $colclassname) { require $colclassname; }
+	elsif (-e $mainclassname) { require $mainclassname; }
+	else { die "ERROR - couldn't find classifier \"$classname\"\n"; }
+
+	# create the classify object
+	my ($classobj);
+	map { $_ = "\"$_\""; } @$classifyoption;
+	my $options = join (",", @$classifyoption);
+	eval ("\$classobj = new \$classname($options)");
+	die "$@" if $@;
+	
+	# add this object to the list
+	push (@classify_objects, $classobj);
+    }
+
+    return \@classify_objects;
+}
+
+# init_classifiers resets all the classifiers and readys them to process
+# the documents.
+sub init_classifiers {
+    my ($classifiers) = @_;
+    
+    foreach $classobj (@$classifiers) {
+	$classobj->init();
+    }
+}
+
+# classify_doc lets each of the classifiers classify a document
+sub classify_doc {
+    my ($classifiers, $doc_obj) = @_;
+    
+    foreach $classobj (@$classifiers) {
+	$classobj->classify($doc_obj);
+    }
+}
+
+# output_classify_info outputs all the info needed for the classification
+# to the gdbm
+sub output_classify_info {
+    my ($classifiers, $handle, $allclassifications) = @_;
+#    $handle = "main::STDOUT";
+
+    # create a classification containing all the info
+    my $classifyinfo = {'classifyOID'=>'browse',
+			'contains'=>[]};
+
+    # get each of the classifications
+    foreach $classobj (@$classifiers) {
+	my $tempinfo = $classobj->get_classify_info();
+	$tempinfo->{'classifyOID'} = "CL$next_classify_num";
+	$next_classify_num++;
+	push (@{$classifyinfo->{'contains'}}, $tempinfo);
+    }
+
+    &print_classify_info ($handle, $classifyinfo, "", $allclassifications);
+}
+
+sub print_classify_info {
+    my ($handle, $classifyinfo, $OID, $allclassifications) = @_;
+
+    $OID =~ s/^\.+//; # just for good luck
+
+    # book information is printed elsewhere
+    return if (defined ($classifyinfo->{'OID'}));
+ 
+    # don't want empty classifications
+    if ($allclassifications || &check_contents ($classifyinfo) > 0) {
+   
+	$OID = $classifyinfo->{'classifyOID'} if defined ($classifyinfo->{'classifyOID'});
+	
+	my $outputtext = "[$OID]\n";
+	$outputtext .= "<doctype>classify\n";
+	$outputtext .= "<hastxt>0\n";
+	$outputtext .= "<childtype>$classifyinfo->{'childtype'}\n" 
+	    if defined $classifyinfo->{'childtype'};
+	$outputtext .= "<Title>$classifyinfo->{'Title'}\n" 
+	    if defined $classifyinfo->{'Title'};
+	$outputtext .= "<numleafdocs>$classifyinfo->{'numleafdocs'}\n" 
+	    if defined $classifyinfo->{'numleafdocs'};
+	$outputtext .= "<thistype>$classifyinfo->{'thistype'}\n" 
+	    if defined $classifyinfo->{'thistype'};
+
+	
+	my $contains_text = "<contains>";
+	my $mdoffset_text = "<mdoffset>";
+	
+	my $next_subOID = 1;
+	my $first = 1;
+	foreach $tempinfo (@{$classifyinfo->{'contains'}}) {
+	    # empty contents were made undefined by clean_contents()
+	    next unless defined $tempinfo;
+	    
+	    $contains_text .= ";" unless $first;
+	    $mdoffset_text .= ";" unless $first;
+	    $first = 0;
+	    
+	    if (defined ($tempinfo->{'classifyOID'})) {
+		$contains_text .= $tempinfo->{'classifyOID'};
+		&print_classify_info ($handle, $tempinfo, $tempinfo->{'classifyOID'},
+				      $allclassifications);
+	    } elsif (defined ($tempinfo->{'OID'})) {
+		$contains_text .= $tempinfo->{'OID'};
+		$mdoffset_text .= $tempinfo->{'offset'}
+		  if (defined ($tempinfo->{'offset'}))
+		# note: we don't want to print the contents of the books
+	    } else {
+		$contains_text .= "\".$next_subOID";
+		&print_classify_info ($handle, $tempinfo, "$OID.$next_subOID",
+				      $allclassifications);
+		$next_subOID++;
+	    }
+	}
+	
+	$outputtext .= "$contains_text\n";
+	$outputtext .= "<mdtype>$classifyinfo->{'mdtype'}\n" 
+	    if defined $classifyinfo->{'mdtype'};
+	$outputtext .= "$mdoffset_text\n"
+	    if ($mdoffset_text !~ m/^<mdoffset>;+$/);
+	
+	$outputtext .= '-' x 70 . "\n";
+	
+	print $handle $outputtext;
+    }
+}
+
+sub check_contents {
+    my ($classifyinfo) = @_;
+    my $num_leaf_docs = 0;
+    my $sub_num_leaf_docs = 0;
+
+    return $classifyinfo->{'numleafdocs'} if (defined $classifyinfo->{'numleafdocs'});
+
+    foreach $content (@{$classifyinfo->{'contains'}}) {
+	if (defined $content->{'OID'}) {
+	    # found a book
+	    $num_leaf_docs ++;
+	} elsif (($sub_num_leaf_docs = &check_contents ($content)) > 0) {
+	    # there's a book somewhere below
+	    $num_leaf_docs += $sub_num_leaf_docs;
+	} else {
+	    # section contains no books so we want to remove 
+	    # it from its parents contents
+	    $content = undef;
+	}
+    }
+
+    $classifyinfo->{'numleafdocs'} = $num_leaf_docs;
+    return $num_leaf_docs;
+}
+
+1;
Index: /main/tags/2.25/gsdl/perllib/classify/AZCompactList.pm
===================================================================
--- /main/tags/2.25/gsdl/perllib/classify/AZCompactList.pm	(revision 21064)
+++ /main/tags/2.25/gsdl/perllib/classify/AZCompactList.pm	(revision 21064)
@@ -0,0 +1,617 @@
+###########################################################################
+#
+# AZCompactList.pm --
+# A component of the Greenstone digital library software
+# from the New Zealand Digital Library Project at the 
+# University of Waikato, New Zealand.
+#
+# Copyright (C) 1999 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.
+#
+###########################################################################
+
+# classifier plugin for sorting alphabetically
+# options are:
+#
+# metadata=Metaname -- all documents with Metaname metadata
+#                      will be included in list, list will be sorted
+#                      by this element.
+# title=Title       -- (optional) the title field for this classification.
+#                      if not included title field will be Metaname. 
+# mingroup=Num      -- (optional) the smallest value that will cause
+#                      a group in the hierarchy to form.
+# minnesting=Num    -- (optional) the smallest value that will cause a 
+#		       list to converted into nested list
+# mincompact=Num    -- (optional) used in compact list
+# maxcompact=Num    -- (optional) used in compact list
+# doclevel=top|section -- (optional) level to process document at.
+# onlyfirst         -- (optional) control whether all or only first
+#                      metadata value used from array of metadata
+package AZCompactList;
+
+use sorttools;
+
+sub new {
+    my ($class, @options) = @_;
+
+    my ($metaname, $title);
+    my $mingroup = 2;
+    my $minnesting = 20;
+    my $mincompact = 10;
+    my $maxcompact = 30;
+    my $doclevel = "top";
+    my $onlyfirst = 0;
+    my $recopt   = undef;
+
+    foreach $option (@options) {
+	if ($option =~ /^metadata=(.*)$/i) {
+	    $metaname = $1;
+	} elsif ($option =~ /^title=(.*)$/i) {
+	    $title = $1;
+	} elsif ($option =~ /^mingroup(size)?=(.*)$/i) {
+	    $mingroup = $2;
+	} elsif ($option =~ /^minnesting=(.*)$/i) {
+	    $minnesting = $1;
+	} elsif ($option =~ /^mincompact=(.*)$/i) {
+	    $mincompact = $1;
+	} elsif ($option =~ /^maxcompact=(.*)$/i) {
+	    $maxcompact = $1;
+	} elsif ($option =~ /^doclevel=(.*)$/i) {
+	    $doclevel = $1;
+	} elsif ($option =~ /^onlyfirst$/i) {
+	    $onlyfirst = 1;
+	} elsif ($option =~ /^recopt$/i) {
+	    $recopt = "on";
+	}
+    }
+
+    die "AZCompactList used with no metadata name to classify by\n"
+	unless defined $metaname;
+    $title = $metaname unless defined $title;
+
+    return bless {
+	'list'=>{}, 
+	'listmetavalue'=>{}, 
+	'reclassify'=>{},
+	'reclassifylist'=>{},
+	'metaname' => $metaname,
+	'title' => $title,
+	'mingroup' => $mingroup,
+	'minnesting' => $minnesting,
+	'mincompact' => $mincompact,
+	'maxcompact' => $maxcompact,
+	'doclevel' => $doclevel,
+	'onlyfirst' => $onlyfirst,
+	'recopt' => $recopt
+	}, $class;
+
+
+}
+
+sub init 
+{
+    my $self = shift (@_);
+    
+    $self->{'list'} = {};
+    $self->{'listmetavalue'} = {};
+    $self->{'reclassify'} = {};
+    $self->{'reclassifylist'} = {};
+}
+
+$tmp = 0;
+
+sub classify 
+{
+    my $self = shift (@_);
+    my ($doc_obj) = @_;
+
+    my $doc_OID = $doc_obj->get_OID();
+
+    my @sectionlist = ();
+    my $topsection = $doc_obj->get_top_section();
+
+    my $metaname = $self->{'metaname'};
+
+    $metaname =~ s/(\/.*)//; # grab first name in n1/n2/n3 list
+##    print STDERR "AZCompactList: processing $doc_OID for $metaname\n";
+
+    if ($self->{'doclevel'} =~ /^top(level)?/i)
+    {
+	push(@sectionlist,$topsection);
+    }
+    else
+    {
+	my $thissection = $doc_obj->get_next_section($topsection);
+	while (defined $thissection) 
+	{
+	    push(@sectionlist,$thissection);
+	    $thissection = $doc_obj->get_next_section ($thissection);
+	}
+    }
+
+    my $thissection;
+    foreach $thissection (@sectionlist)
+    {
+	my $full_doc_OID 
+	    = ($thissection ne "") ? "$doc_OID.$thissection" : $doc_OID;
+
+	if (defined $self->{'list'}->{$full_doc_OID}) 
+	{
+	    print STDERR "WARNING: AZCompactList::classify called multiple times for $full_doc_OID\n";
+	} 
+	$self->{'list'}->{$full_doc_OID} = [];	
+	$self->{'listmetavalue'}->{$full_doc_OID} = [];
+
+	my $metavalues = $doc_obj->get_metadata($thissection,$metaname);
+	my $metavalue;
+	foreach $metavalue (@$metavalues) 
+	{
+###	    print STDERR "$metaname :\tmetavalue = $metavalue\n";
+	    # if this document doesn't contain the metadata element we're
+	    # sorting by we won't include it in this classification
+	    if (defined $metavalue && $metavalue =~ /\w/) 
+	    {
+		my $formatted_metavalue = $metavalue;
+		if ($self->{'metaname'} =~ m/^Creator(:.*)?$/)
+		{
+		    &sorttools::format_string_name_english (\$formatted_metavalue);
+		} 
+		else 
+		{
+		    &sorttools::format_string_english (\$formatted_metavalue);
+		}
+		
+		push(@{$self->{'list'}->{$full_doc_OID}},$formatted_metavalue);
+		push(@{$self->{'listmetavalue'}->{$full_doc_OID}} ,$metavalue);
+
+		last if ($self->{'onlyfirst'});
+	    }
+	}
+	my $date = $doc_obj->get_metadata_element($thissection,"Date");
+	$self->{'reclassify'}->{$full_doc_OID} = [$doc_obj,$date];
+    }
+}
+
+sub reinit 
+{
+    my ($self,$classlist_ref) = @_;
+    
+    my %mtfreq = ();
+    my @single_classlist = ();
+    my @multiple_classlist = ();
+
+    # find out how often each metavalue occurs
+    map 
+    { 
+	my $mv;
+	foreach $mv (@{$self->{'listmetavalue'}->{$_}} )
+	{
+	    $mtfreq{$mv}++; 
+	}
+    } @$classlist_ref;
+
+    # use this information to split the list: single metavalue/repeated value
+    map
+    { 
+	my $i = 1;
+	my $metavalue;
+	foreach $metavalue (@{$self->{'listmetavalue'}->{$_}})
+	{
+	    if ($mtfreq{$metavalue} >= $self->{'mingroup'})
+	    {
+		push(@multiple_classlist,[$_,$i,$metavalue]); 
+	    } 
+	    else
+	    {
+		push(@single_classlist,[$_,$metavalue]); 
+		$metavalue =~ tr/[A-Z]/[a-z]/;
+		$self->{'reclassifylist'}->{"Metavalue_$i.$_"} = $metavalue;
+	    }
+	    $i++;
+	}
+    } @$classlist_ref;
+    
+    
+    # Setup sub-classifiers for multiple list
+
+    $self->{'classifiers'} = {};
+
+    my $pm;
+    foreach $pm ("List", "SectionList")
+    {
+	my $listname 
+	    = &util::filename_cat($ENV{'GSDLHOME'},"perllib/classify/$pm.pm");
+	if (-e $listname) { require $listname; }
+	else 
+	{ 
+	    die "AZCompactList ERROR - couldn't find classifier \"$listname\"\n"; 
+	}
+    }
+
+    # Create classifiers objects for each entry >= mingroup
+    my $metavalue;
+    foreach $metavalue (keys %mtfreq)
+    {
+	if ($mtfreq{$metavalue} >= $self->{'mingroup'})
+	{
+	    my $listclassobj;
+	    my $doclevel = $self->{'doclevel'};
+	    my $metaname  = $self->{'metaname'};
+	    my @metaname_list = split('/',$metaname);
+	    $metaname = shift(@metaname_list);
+	    if (@metaname_list==0)
+	    {
+		if ($doclevel =~ m/^top(level)?/i)
+		{
+		    my $args = "\"metadata=$metaname\"";
+		    $args .= ", \"title=\$metavalue\"";
+		    $args .= ", \"sort=Date\"";
+		    eval ("\$listclassobj = new List($args)");
+		}
+		else
+		{
+		    my $args = "\"metadata=$metaname\"";
+		    $args .= ", \"title=\$metavalue\"";
+		    $args .= ", \"sort=Date\"";
+		    eval ("\$listclassobj = new SectionList($args)");
+		}
+	    }
+	    else
+	    {
+		$metaname = join('/',@metaname_list);
+
+		my $args = "\"metadata=$metaname\"";
+		$args .= ", \"title=\$metavalue\"";
+		$args .= ", \"doclevel=\$doclevel\"";
+		$args .= ", \"recopt\"";
+
+		eval ("\$listclassobj = new AZCompactList($args)");
+	    }
+	    die "$@" if $@;
+	    
+	    $listclassobj->init();
+
+	    if (defined $metavalue && $metavalue =~ /\w/) 
+	    {
+		my $formatted_node = $metavalue;
+		if ($self->{'metaname'} =~ m/^Creator(:.*)?$/)
+		{
+		    &sorttools::format_string_name_english(\$formatted_node);
+		} 
+		else 
+		{
+		    &sorttools::format_string_english(\$formatted_node);
+		}
+		
+		$self->{'classifiers'}->{$metavalue} 
+		= { 'classifyobj'   => $listclassobj,
+		    'formattednode' => $formatted_node };
+	    }
+	}
+    }
+
+
+    return (\@single_classlist,\@multiple_classlist);
+}
+
+
+sub reclassify 
+{
+    my ($self,$multiple_cl_ref) = @_;
+
+    # Entries in the current classify list that are "book nodes"
+    # should be recursively classified.
+    #--
+    foreach $dm_pair (@$multiple_cl_ref) 
+    {
+	my ($doc_OID,$mdoffset,$metavalue) = @$dm_pair;
+        my $listclassobj;
+
+	# find metavalue in list of sub-classifiers
+	my $found = 0;
+	my $node_name;
+	foreach $node_name (keys %{$self->{'classifiers'}}) 
+	{
+	    $resafe_node_name = $node_name;
+	    $resafe_node_name =~ s/(\(|\)|\[|\]|\{|\}|\^|\$|\.|\+|\*|\?|\|)/\\$1/g;
+	    if ($metavalue =~ m/^$resafe_node_name$/i) 
+	    {
+		my ($doc_obj,$date) = @{$self->{'reclassify'}->{$doc_OID}};
+
+		## date appears to not be used in classifier call ####
+
+		if ($doc_OID =~ m/^.*\.(\d+)$/)
+		{
+		    $self->{'classifiers'}->{$node_name}->{'classifyobj'}
+		    ->classify($doc_obj, "Section=$1"); 
+		}
+		else
+		{
+		    $self->{'classifiers'}->{$node_name}->{'classifyobj'}
+		    ->classify($doc_obj); 
+		}
+		
+		$found = 1;
+		last;
+	    }
+	}
+	
+	if (!$found)
+	{
+	    print STDERR "Warning: AZCompactList::reclassify ";
+	    print STDERR "could not find sub-node for $metavalue with doc_OID $doc_OID\n";
+	}
+    }
+}
+
+
+
+sub get_reclassify_info 
+{
+    my $self = shift (@_);
+    
+    my $node_name;
+    foreach $node_name (keys %{$self->{'classifiers'}}) 
+    {
+        my $classifyinfo 
+	    = $self->{'classifiers'}->{$node_name}->{'classifyobj'}
+	        ->get_classify_info();
+        $self->{'classifiers'}->{$node_name}->{'classifyinfo'} 
+	    = $classifyinfo;
+        $self->{'reclassifylist'}->{"CLASSIFY.$node_name"} 
+	    = $self->{'classifiers'}->{$node_name}->{'formattednode'};
+    }
+}
+
+
+sub alpha_numeric_cmp
+{
+    my ($self,$a,$b) = @_;
+
+    my $title_a = $self->{'reclassifylist'}->{$a};
+    my $title_b = $self->{'reclassifylist'}->{$b};
+
+    if ($title_a =~ m/^(\d+(\.\d+)?)/)
+    {
+	my $val_a = $1;
+	if ($title_b =~ m/^(\d+(\.\d+)?)/)
+	{
+	    my $val_b = $1;
+	    if ($val_a != $val_b)
+	    {
+		return ($val_a <=> $val_b);
+	    }
+	}
+    }
+    
+    return ($title_a cmp $title_b);
+}
+
+sub get_classify_info {
+    my $self = shift (@_);
+
+    my @classlist =keys %{$self->{'list'}}; # list all doc oids
+
+    my ($single_cl_ref,$multiple_cl_ref) = $self->reinit(\@classlist);
+    $self->reclassify($multiple_cl_ref);
+    $self->get_reclassify_info();
+
+
+#    my @reclassified_classlist 
+#	= sort {$self->{'reclassifylist'}->{$a} cmp $self->{'reclassifylist'}->{$b};} keys %{$self->{'reclassifylist'}};
+
+    # alpha_numeric_cmp is slower but handles numbers better ...
+    my @reclassified_classlist 
+	= sort { $self->alpha_numeric_cmp($a,$b) } keys %{$self->{'reclassifylist'}};
+
+
+    return $self->splitlist (\@reclassified_classlist);
+}
+
+sub get_entry {
+    my $self = shift (@_);
+    my ($title, $childtype, $metaname, $thistype) = @_;
+
+    # organise into classification structure
+    my %classifyinfo = ('childtype'=>$childtype,
+                        'Title'=>$title,
+                        'contains'=>[],
+			'mdtype'=>$metaname);
+
+    $classifyinfo{'thistype'} = $thistype
+        if defined $thistype && $thistype =~ /\w/;
+
+    return \%classifyinfo;
+}
+
+
+
+# splitlist takes an ordered list of classifications (@$classlistref) and 
+# splits it up into alphabetical sub-sections.
+sub splitlist {
+    my $self = shift (@_);
+    my ($classlistref) = @_;
+    my $classhash = {};
+
+    # top level
+    my @metanames = split("/",$self->{'metaname'});
+    my $metaname = shift(@metanames);
+
+    my $childtype = "HList";
+    $childtype = "VList" if (scalar (@$classlistref) <= $self->{'minnesting'});
+
+    my $classifyinfo;
+    if (!defined($self->{'recopt'}))
+    {
+	my $title = $metaname;
+	$classifyinfo 
+	    = $self->get_entry ($metaname, $childtype, $metaname, "Invisible");
+    }
+    else
+    {
+	my $title = $self->{'title'};
+	$classifyinfo 
+	    = $self->get_entry ($title, $childtype, $metaname, "VList");
+    }
+
+    # don't need to do any splitting if there are less than 'minnesting' classifications
+    if ((scalar @$classlistref) <= $self->{'minnesting'}) {
+	foreach $subOID (@$classlistref) {
+            if ($subOID =~ /^CLASSIFY\.(.*)$/ 
+		&& defined $self->{'classifiers'}->{$1}) 
+	    {
+###		print STDERR "*** subOID = $subOID\n";
+
+                push (@{$classifyinfo->{'contains'}}, 
+		      $self->{'classifiers'}->{$1}->{'classifyinfo'});
+            } 
+	    else 
+	    {
+		$subOID =~ s/^Metavalue_(\d+)\.//;
+		my $metaname_offset = $1 -1;
+		my $oid_rec = {'OID'=>$subOID, 'offset'=>$metaname_offset};
+		push (@{$classifyinfo->{'contains'}}, $oid_rec);
+	    }
+	}
+	return $classifyinfo;
+    }
+	
+    # first split up the list into separate A-Z and 0-9 classifications
+    foreach $classification (@$classlistref) {
+	my $title = $self->{'reclassifylist'}->{$classification};
+	$title =~ s/&(.){2,4};//g; # remove any HTML special chars
+###	$title =~ s/^\s+//g; # remove a leading spaces
+###	$title =~ s/^_+//g; # remove a leading underscores
+	$title =~ s/^\W+//g;
+###	$title =~ s/^(\'|\`|\"|\:|\()//g; # remove any opening punctutation
+	$title =~ s/^(.).*$/$1/;
+	$title =~ tr/[a-z]/[A-Z]/;
+
+	if ($title =~ /^[0-9]$/) {$title = '0-9';}
+	elsif ($title !~ /^[A-Z]$/) {
+	    print STDERR "AZCompactList: WARNING $classification has badly formatted title ($title)\n";
+	}
+	$classhash->{$title} = [] unless defined $classhash->{$title};
+	push (@{$classhash->{$title}}, $classification);
+    }
+    $classhash = $self->compactlist ($classhash);
+
+    my @tmparr = ();
+    foreach $subsection (sort keys (%$classhash)) {
+	push (@tmparr, $subsection);
+    }
+    
+    # if there's a 0-9 section it will have been sorted to the beginning
+    # but we want it at the end
+    if ($tmparr[0] eq '0-9') {
+	shift @tmparr;
+	push (@tmparr, '0-9');
+    }
+
+    foreach $subclass (@tmparr) 
+    {
+	my $tempclassify = $self->get_entry($subclass, "VList", $metaname);
+	foreach $subsubOID (@{$classhash->{$subclass}}) 
+	{
+            if ($subsubOID =~ /^CLASSIFY\.(.*)$/ 
+		&& defined $self->{'classifiers'}->{$1}) 
+	    {
+                push (@{$tempclassify->{'contains'}}, 
+		      $self->{'classifiers'}->{$1}->{'classifyinfo'});
+	    }
+	    else
+	    {
+		$subsubOID =~ s/^Metavalue_(\d+)\.//;
+		my $metaname_offset = $1 -1;
+		my $oid_rec = {'OID'=>$subsubOID, 'offset'=>$metaname_offset};
+		push (@{$tempclassify->{'contains'}}, $oid_rec);
+	    }
+	}
+	push (@{$classifyinfo->{'contains'}}, $tempclassify);
+    }
+
+    return $classifyinfo;
+}
+
+sub compactlist {
+    my $self = shift (@_);
+    my ($classhashref) = @_;
+    my $compactedhash = {};
+    my @currentOIDs = ();
+    my $currentfirstletter = "";
+    my $currentlastletter = "";
+    my $lastkey = "";
+
+    # minimum and maximum documents to be displayed per page.
+    # the actual maximum will be max + (min-1).
+    # the smallest sub-section is a single letter at present
+    # so in this case there may be many times max documents
+    # displayed on a page.
+    my $min = $self->{'mincompact'}; 
+    my $max = $self->{'maxcompact'};
+
+    foreach $subsection (sort keys %$classhashref) {
+	if ($subsection eq '0-9') {
+	    @{$compactedhash->{$subsection}} = @{$classhashref->{$subsection}};
+	    next;
+	}
+	$currentfirstletter = $subsection if $currentfirstletter eq "";
+	if ((scalar (@currentOIDs) < $min) ||
+	    ((scalar (@currentOIDs) + scalar (@{$classhashref->{$subsection}})) <= $max)) {
+	    push (@currentOIDs, @{$classhashref->{$subsection}});
+	    $currentlastletter = $subsection;
+	} else {
+
+	    if ($currentfirstletter eq $currentlastletter) {
+		@{$compactedhash->{$currentfirstletter}} = @currentOIDs;
+		$lastkey = $currentfirstletter;
+	    } else {
+		@{$compactedhash->{"$currentfirstletter-$currentlastletter"}} = @currentOIDs;
+		$lastkey = "$currentfirstletter-$currentlastletter";
+	    } 
+	    if (scalar (@{$classhashref->{$subsection}}) >= $max) {
+		$compactedhash->{$subsection} = $classhashref->{$subsection};
+		@currentOIDs = ();
+		$currentfirstletter = "";
+	    } else {
+		@currentOIDs = @{$classhashref->{$subsection}};
+		$currentfirstletter = $subsection;
+		$currentlastletter = $subsection;
+	    }
+	}
+    }
+
+    # add final OIDs to last sub-classification if there aren't many otherwise
+    # add final sub-classification
+    if (scalar (@currentOIDs) < $min) {
+	my ($newkey) = $lastkey =~ /^(.)/;
+	@currentOIDs = (@{$compactedhash->{$lastkey}}, @currentOIDs);
+	delete $compactedhash->{$lastkey};
+	@{$compactedhash->{"$newkey-$currentlastletter"}} = @currentOIDs;
+    } else {
+	if ($currentfirstletter eq $currentlastletter) {
+	    @{$compactedhash->{$currentfirstletter}} = @currentOIDs;
+	} else {
+	    @{$compactedhash->{"$currentfirstletter-$currentlastletter"}} = @currentOIDs;
+	} 
+    }
+
+    return $compactedhash;
+}
+
+1;
+
+
Index: /main/tags/2.25/gsdl/perllib/classify/AZList.pm
===================================================================
--- /main/tags/2.25/gsdl/perllib/classify/AZList.pm	(revision 21064)
+++ /main/tags/2.25/gsdl/perllib/classify/AZList.pm	(revision 21064)
@@ -0,0 +1,263 @@
+###########################################################################
+#
+# AZList.pm --
+# A component of the Greenstone digital library software
+# from the New Zealand Digital Library Project at the 
+# University of Waikato, New Zealand.
+#
+# Copyright (C) 1999 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.
+#
+###########################################################################
+
+# classifier plugin for sorting alphabetically
+# options are:
+# metadata=Metaname -- all documents with Metaname metadata
+#                      will be included in list, list will be sorted
+#                      by this element.
+# title=Title       -- (optional) the title field for this classification.
+#                      if not included title field will be Metaname. 
+
+package AZList;
+
+use sorttools;
+
+sub new {
+    my ($class, @options) = @_;
+
+    my ($metaname, $title);
+
+    foreach $option (@options) {
+	if ($option =~ /^metadata=(.*)$/i) {
+	    $metaname = $1;
+	} elsif ($option =~ /^title=(.*)$/i) {
+	    $title = $1;
+	}
+    }
+
+    die "AZList used with no metadata name to classify by\n"
+	unless defined $metaname;
+    $title = $metaname unless defined $title;
+
+    return bless {
+	'list'=>{},
+	'metaname' => $metaname,
+	'title' => $title
+	}, $class;
+}
+
+sub init {
+    my $self = shift (@_);
+
+    $self->{'list'} = {};
+}
+
+sub classify {
+    my $self = shift (@_);
+    my ($doc_obj) = @_;
+
+    my $doc_OID = $doc_obj->get_OID();
+    my $metavalue = $doc_obj->get_metadata_element ($doc_obj->get_top_section(),
+						    $self->{'metaname'});
+
+    # if this document doesn't contain the metadata element we're
+    # sorting by we won't include it in this classification
+    if (defined $metavalue && $metavalue ne "") {
+	if ($self->{'metaname'} eq 'Creator') {
+	    &sorttools::format_string_name_english (\$metavalue);
+	} else {
+	    &sorttools::format_string_english (\$metavalue);
+	}
+	if (defined $self->{'list'}->{$doc_OID}) {
+	    print STDERR "WARNING: AZList::classify called multiple times for $doc_OID\n";
+	} 
+	$self->{'list'}->{$doc_OID} = $metavalue;
+    }
+}
+
+sub alpha_numeric_cmp
+{
+    my ($self,$a,$b) = @_;
+
+    my $title_a = $self->{'list'}->{$a};
+    my $title_b = $self->{'list'}->{$b};
+
+    if ($title_a =~ m/^(\d+(\.\d+)?)/)
+    {
+	my $val_a = $1;
+	if ($title_b =~ m/^(\d+(\.\d+)?)/)
+	{
+	    my $val_b = $1;
+	    if ($val_a != $val_b)
+	    {
+		return ($val_a <=> $val_b);
+	    }
+	}
+    }
+    
+    return ($title_a cmp $title_b);
+}
+
+sub get_classify_info {
+    my $self = shift (@_);
+
+    my @classlist 
+	= sort { $self->alpha_numeric_cmp($a,$b) } keys %{$self->{'list'}};
+
+    return $self->splitlist (\@classlist);
+}
+
+sub get_entry {
+    my $self = shift (@_);
+    my ($title, $childtype, $thistype) = @_;
+    
+    # organise into classification structure
+    my %classifyinfo = ('childtype'=>$childtype,
+			'Title'=>$title,
+			'contains'=>[]);
+    $classifyinfo{'thistype'} = $thistype 
+	if defined $thistype && $thistype =~ /\w/;
+
+    return \%classifyinfo;
+}
+
+# splitlist takes an ordered list of classifications (@$classlistref) and splits it
+# up into alphabetical sub-sections.
+sub splitlist {
+    my $self = shift (@_);
+    my ($classlistref) = @_;
+    my $classhash = {};
+
+    # top level
+    my $childtype = "HList";
+    if (scalar (@$classlistref) <= 39) {$childtype = "VList";}
+    my $classifyinfo = $self->get_entry ($self->{'title'}, $childtype, "Invisible");
+
+    # don't need to do any splitting if there are less than 39 (max + min -1) classifications
+    if ((scalar @$classlistref) <= 39) {
+	foreach $subOID (@$classlistref) {
+	    push (@{$classifyinfo->{'contains'}}, {'OID'=>$subOID});
+	}
+	return $classifyinfo;
+    }
+	
+    # first split up the list into separate A-Z and 0-9 classifications
+    foreach $classification (@$classlistref) {
+	my $title = $self->{'list'}->{$classification};
+
+	$title =~ s/^(&.{1,6};|<[^>]>|[^a-zA-Z0-9])//g; # remove any unwanted stuff
+	$title =~ s/^(.).*$/$1/;
+	$title =~ tr/[a-z]/[A-Z]/;
+	if ($title =~ /^[0-9]$/) {$title = '0-9';}
+	elsif ($title !~ /^[A-Z]$/) {
+	    print STDERR "AZList: WARNING $classification has badly formatted title ($title)\n";
+	}
+	$classhash->{$title} = [] unless defined $classhash->{$title};
+	push (@{$classhash->{$title}}, $classification);
+    }
+    $classhash = $self->compactlist ($classhash);
+
+    my @tmparr = ();
+    foreach $subsection (sort keys (%$classhash)) {
+	push (@tmparr, $subsection);
+    }
+    
+    # if there's a 0-9 section it will have been sorted to the beginning
+    # but we want it at the end
+    if ($tmparr[0] eq '0-9') {
+	shift @tmparr;
+	push (@tmparr, '0-9');
+    }
+
+    foreach $subclass (@tmparr) {
+	my $tempclassify = $self->get_entry($subclass, "VList");
+	foreach $subsubOID (@{$classhash->{$subclass}}) {
+	    push (@{$tempclassify->{'contains'}}, {'OID'=>$subsubOID});
+	}
+	push (@{$classifyinfo->{'contains'}}, $tempclassify);
+    }
+
+    return $classifyinfo;
+}
+
+sub compactlist {
+    my $self = shift (@_);
+    my ($classhashref) = @_;
+    my $compactedhash = {};
+    my @currentOIDs = ();
+    my $currentfirstletter = "";
+    my $currentlastletter = "";
+    my $lastkey = "";
+
+    # minimum and maximum documents to be displayed per page.
+    # the actual maximum will be max + (min-1).
+    # the smallest sub-section is a single letter at present
+    # so in this case there may be many times max documents
+    # displayed on a page.
+    my $min = 10; 
+    my $max = 30;
+
+    foreach $subsection (sort keys %$classhashref) {
+	if ($subsection eq '0-9') {
+	    @{$compactedhash->{$subsection}} = @{$classhashref->{$subsection}};
+	    next;
+	}
+	$currentfirstletter = $subsection if $currentfirstletter eq "";
+	if ((scalar (@currentOIDs) < $min) ||
+	    ((scalar (@currentOIDs) + scalar (@{$classhashref->{$subsection}})) <= $max)) {
+	    push (@currentOIDs, @{$classhashref->{$subsection}});
+	    $currentlastletter = $subsection;
+	} else {
+
+	    if ($currentfirstletter eq $currentlastletter) {
+		@{$compactedhash->{$currentfirstletter}} = @currentOIDs;
+		$lastkey = $currentfirstletter;
+	    } else {
+		@{$compactedhash->{"$currentfirstletter-$currentlastletter"}} = @currentOIDs;
+		$lastkey = "$currentfirstletter-$currentlastletter";
+	    } 
+	    if (scalar (@{$classhashref->{$subsection}}) >= $max) {
+		$compactedhash->{$subsection} = $classhashref->{$subsection};
+		@currentOIDs = ();
+		$currentfirstletter = "";
+		$lastkey = $subsection;
+	    } else {
+		@currentOIDs = @{$classhashref->{$subsection}};
+		$currentfirstletter = $subsection;
+		$currentlastletter = $subsection;
+	    }
+	}
+    }
+
+    # add final OIDs to last sub-classification if there aren't many otherwise
+    # add final sub-classification
+    if (scalar (@currentOIDs) < $min) {
+	my ($newkey) = $lastkey =~ /^(.)/;
+	@currentOIDs = (@{$compactedhash->{$lastkey}}, @currentOIDs);
+	delete $compactedhash->{$lastkey};
+	@{$compactedhash->{"$newkey-$currentlastletter"}} = @currentOIDs;	
+    } else {
+	if ($currentfirstletter eq $currentlastletter) {
+	    @{$compactedhash->{$currentfirstletter}} = @currentOIDs;
+	} else {
+	    @{$compactedhash->{"$currentfirstletter-$currentlastletter"}} = @currentOIDs;
+	} 
+    }
+
+    return $compactedhash;
+}
+
+1;
Index: /main/tags/2.25/gsdl/perllib/classify/AZSectionList.pm
===================================================================
--- /main/tags/2.25/gsdl/perllib/classify/AZSectionList.pm	(revision 21064)
+++ /main/tags/2.25/gsdl/perllib/classify/AZSectionList.pm	(revision 21064)
@@ -0,0 +1,82 @@
+###########################################################################
+#
+# AZSectionList.pm --
+# A component of the Greenstone digital library software
+# from the New Zealand Digital Library Project at the 
+# University of Waikato, New Zealand.
+#
+# Copyright (C) 1999 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.
+#
+###########################################################################
+
+# classifier plugin for sorting sections alphabetically
+
+# this is very similar to AZList except it sorts by
+# section level metadata (excluding the top level)
+# instead of just top level metadata
+
+# the only change is to the classify() subroutine which 
+# must now iterate through each section, adding each
+# to the classification
+
+package AZSectionList;
+
+use AZList;
+use sorttools;
+
+sub BEGIN {
+    @ISA = ('AZList');
+}
+
+sub classify {
+    my $self = shift (@_);
+    my ($doc_obj) = @_;
+
+    my $doc_OID = $doc_obj->get_OID();
+    my $thissection = $doc_obj->get_next_section ($doc_obj->get_top_section());
+
+    while (defined $thissection) {
+	$self->classify_section ($thissection, $doc_obj);
+	$thissection = $doc_obj->get_next_section ($thissection);
+    }
+}
+
+sub classify_section {
+    my $self = shift (@_);
+    my ($section, $doc_obj) = @_;
+
+    my $doc_OID = $doc_obj->get_OID();
+    my $metavalue = $doc_obj->get_metadata_element ($section, $self->{'metaname'});
+
+    # if this section doesn't contain the metadata element we're
+    # sorting by we won't include it in this classification
+    if (defined $metavalue && $metavalue ne "") {
+	if ($self->{'metaname'} eq 'Creator') {
+	    &sorttools::format_string_name_english (\$metavalue);
+	} else {
+	    &sorttools::format_string_english (\$metavalue);
+	}
+	if (defined $self->{'list'}->{"$doc_OID.$section"}) {
+	    print STDERR "WARNING: AZSectionList::classify called multiple times " .
+		"for $doc_OID.$section\n";
+	} 
+	$self->{'list'}->{"$doc_OID.$section"} = $metavalue;
+    }
+}
+
+
+1;
Index: /main/tags/2.25/gsdl/perllib/classify/DateList.pm
===================================================================
--- /main/tags/2.25/gsdl/perllib/classify/DateList.pm	(revision 21064)
+++ /main/tags/2.25/gsdl/perllib/classify/DateList.pm	(revision 21064)
@@ -0,0 +1,197 @@
+###########################################################################
+#
+# DateList.pm --
+# A component of the Greenstone digital library software
+# from the New Zealand Digital Library Project at the 
+# University of Waikato, New Zealand.
+#
+# Copyright (C) 1999 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.
+#
+###########################################################################
+
+# classifier plugin for sorting by date
+
+# no options - always sorts by 'Date' metadata
+
+# date is assumed to be in the form yyyymmdd
+
+# at present dates are split by year - this should change
+
+package DateList;
+
+use sorttools;
+
+sub new {
+    my ($class, @options) = @_;
+
+    return bless {
+	'list'=>{},
+	}, $class;
+}
+
+sub init {
+    my $self = shift (@_);
+
+    $self->{'list'} = {};
+}
+
+sub classify {
+    my $self = shift (@_);
+    my ($doc_obj) = @_;
+
+    my $doc_OID = $doc_obj->get_OID();
+    my $date = $doc_obj->get_metadata_element ($doc_obj->get_top_section(), 'Date');
+
+    # if this document doesn't contain Date element we won't 
+    # include it in this classification
+    if (defined $date && $date =~ /\d/) {
+	if (defined $self->{'list'}->{$doc_OID}) {
+	    print STDERR "WARNING: DateList::classify called multiple times for $doc_OID\n";
+	} 
+	$self->{'list'}->{$doc_OID} = $date;
+    }
+}
+
+
+sub get_classify_info {
+    my $self = shift (@_);
+
+    my @classlist = sort {$self->{'list'}->{$a} cmp $self->{'list'}->{$b};} keys %{$self->{'list'}};
+
+    return $self->splitlist (\@classlist);
+}
+
+
+sub get_entry {
+    my $self = shift (@_);
+    my ($title, $childtype, $thistype) = @_;
+    
+    # organise into classification structure
+    my %classifyinfo = ('childtype'=>$childtype,
+			'Title'=>$title,
+			'contains'=>[]);
+    $classifyinfo{'thistype'} = $thistype 
+	if defined $thistype && $thistype =~ /\w/;
+
+    return \%classifyinfo;
+}
+
+# splitlist takes an ordered list of classifications (@$classlistref) and splits it
+# up into sub-sections by date
+sub splitlist {
+    my $self = shift (@_);
+    my ($classlistref) = @_;
+    my $classhash = {};
+
+    # top level
+    my $childtype = "HList";
+    if (scalar (@$classlistref) <= 20) {$childtype = "DateList";}
+    my $classifyinfo = $self->get_entry ("Date", $childtype, "Invisible");
+
+    # don't need to do any splitting if there are less than 20 classifications
+    if ((scalar @$classlistref) <= 20) {
+	foreach $subOID (@$classlistref) {
+	    push (@{$classifyinfo->{'contains'}}, {'OID'=>$subOID});
+	}
+	return $classifyinfo;
+    }
+
+    # first split up the list into separate year classifications
+    foreach $classification (@$classlistref) {
+	my $date = $self->{'list'}->{$classification};
+	$date =~ s/^(\d\d\d\d).*$/$1/;
+	$classhash->{$date} = [] unless defined $classhash->{$date};
+	push (@{$classhash->{$date}}, $classification);
+    }
+
+    $classhash = $self->compactlist ($classhash);
+
+    foreach $subclass (sort keys %$classhash) {
+	my $tempclassify = $self->get_entry($subclass, "DateList");
+	foreach $subsubOID (@{$classhash->{$subclass}}) {
+	    push (@{$tempclassify->{'contains'}}, {'OID'=>$subsubOID});
+	}
+	push (@{$classifyinfo->{'contains'}}, $tempclassify);
+    }
+
+    return $classifyinfo;
+}
+
+sub compactlist {
+    my $self = shift (@_);
+    my ($classhashref) = @_;
+    my $compactedhash = {};
+    my @currentOIDs = ();
+    my $currentfirstletter = "";
+    my $currentlastletter = "";
+    my $lastkey = "";
+
+    # minimum and maximum documents to be displayed per page.
+    # the actual maximum will be max + (min-1).
+    # the smallest sub-section is a single letter at present
+    # so in this case there may be many times max documents
+    # displayed on a page.
+    my $min = 10; 
+    my $max = 30;
+
+    foreach $subsection (sort keys %$classhashref) {
+	$currentfirstletter = $subsection if $currentfirstletter eq "";
+	if ((scalar (@currentOIDs) < $min) ||
+	    ((scalar (@currentOIDs) + scalar (@{$classhashref->{$subsection}})) <= $max)) {
+	    push (@currentOIDs, @{$classhashref->{$subsection}});
+	    $currentlastletter = $subsection;
+	} else {
+
+	    if ($currentfirstletter eq $currentlastletter) {
+		@{$compactedhash->{$currentfirstletter}} = @currentOIDs;
+		$lastkey = $currentfirstletter;
+	    } else {
+		@{$compactedhash->{"$currentfirstletter-$currentlastletter"}} = @currentOIDs;
+		$lastkey = "$currentfirstletter-$currentlastletter";
+	    } 
+	    if (scalar (@{$classhashref->{$subsection}}) >= $max) {
+		$compactedhash->{$subsection} = $classhashref->{$subsection};
+		@currentOIDs = ();
+		$currentfirstletter = "";
+		$lastkey = $subsection;
+	    } else {
+		@currentOIDs = @{$classhashref->{$subsection}};
+		$currentfirstletter = $subsection;
+		$currentlastletter = $subsection;
+	    }
+	}
+    }
+
+    # add final OIDs to last sub-classification if there aren't many otherwise
+    # add final sub-classification
+    if (scalar (@currentOIDs) < $min) {
+	my ($newkey) = $lastkey =~ /^(\d\d\d\d)/;
+	@currentOIDs = (@{$compactedhash->{$lastkey}}, @currentOIDs);
+	delete $compactedhash->{$lastkey};
+	@{$compactedhash->{"$newkey-$currentlastletter"}} = @currentOIDs;	
+    } else {
+	if ($currentfirstletter eq $currentlastletter) {
+	    @{$compactedhash->{$currentfirstletter}} = @currentOIDs;
+	} else {
+	    @{$compactedhash->{"$currentfirstletter-$currentlastletter"}} = @currentOIDs;
+	} 
+    }
+
+    return $compactedhash;
+}
+
+1;
Index: /main/tags/2.25/gsdl/perllib/classify/HTML.pm
===================================================================
--- /main/tags/2.25/gsdl/perllib/classify/HTML.pm	(revision 21064)
+++ /main/tags/2.25/gsdl/perllib/classify/HTML.pm	(revision 21064)
@@ -0,0 +1,84 @@
+###########################################################################
+#
+# HTML.pm --
+# A component of the Greenstone digital library software
+# from the New Zealand Digital Library Project at the 
+# University of Waikato, New Zealand.
+#
+# Copyright (C) 1999 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.
+#
+###########################################################################
+
+# html classifier plugin - creates an empty classification
+# that's simply a link to a web page
+# options are:
+# title=Title       -- (optional) the title field for this classification.
+#                      if not included title field 'Browse'
+# url=url           -- the url of the web page to link to
+
+package HTML;
+
+sub new {
+    my ($class, @options) = @_;
+
+    my ($title, $url);
+
+    foreach $option (@options) {
+	if ($option =~ /^url=(.*)$/i) {
+	    $url = $1;
+	} elsif ($option =~ /^title=(.*)$/i) {
+	    $title = $1;
+	}
+    }
+
+    die "Error: HTML classifier contains no 'url' option\n" 
+	unless defined $url;
+
+    $title = 'Browse' unless defined $title;
+
+    return bless {
+	'url' => $url,
+	'title' => $title
+	}, $class;
+}
+
+sub init {
+    my $self = shift (@_);
+}
+
+sub classify {
+    my $self = shift (@_);
+    my ($doc_obj) = @_;
+
+    # we don't do anything for individual documents
+}
+
+sub get_classify_info {
+    my $self = shift (@_);
+
+    my %classifyinfo = ('thistype'=>'Invisible',
+			'childtype'=>'HTML',
+			'Title'=>$self->{'title'},
+			'contains'=>[]);
+
+    push (@{$classifyinfo{'contains'}}, {'OID'=>$self->{'url'}});
+
+    return \%classifyinfo;
+}
+
+
+1;
Index: /main/tags/2.25/gsdl/perllib/classify/Hierarchy.pm
===================================================================
--- /main/tags/2.25/gsdl/perllib/classify/Hierarchy.pm	(revision 21064)
+++ /main/tags/2.25/gsdl/perllib/classify/Hierarchy.pm	(revision 21064)
@@ -0,0 +1,218 @@
+###########################################################################
+#
+# Hierarchy.pm --
+# A component of the Greenstone digital library software
+# from the New Zealand Digital Library Project at the 
+# University of Waikato, New Zealand.
+#
+# Copyright (C) 1999 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.
+#
+###########################################################################
+
+# classifier plugin for generating hierarchical classifications
+
+# options for this classifier are:
+# hfile=file.txt    - classification file
+# metadata=Metaname - metadata field to test against file.txt
+# sort=Meta         - this option is optional (genious;-). by default this 
+#                     classifier will sort documents within each section 
+#                     alphabetically by Title. sort=nosort prevents sorting 
+#                     (i.e. documents will end up in build order), sort=Meta 
+#                     will sort each field alphabetically by Meta (Meta may 
+#                     also be 'Filename' to sort by the original filename).
+# title=Title       - another optional field. this is what will end up in the
+#                     Title field for this classification. if not present it
+#                     defaults to Metaname
+
+package Hierarchy;
+
+use util;
+use cfgread;
+use sorttools;
+
+sub new {
+    my ($class, @options) = @_;
+
+    my $sortname = "Title";
+    my ($hfile, $metadata, $title);
+
+    foreach $option (@options) {
+	if ($option =~ /^sort=(.*)$/i) {
+	    $sortname = $1;
+	    $sortname = undef if $sortname =~ /^nosort$/i;
+	} elsif ($option =~ /^hfile=(.*)$/i) {
+	    $hfile = $1;
+	} elsif ($option =~ /^metadata=(.*)$/i) {
+	    $metadata = $1;
+	} elsif ($option =~ /^title=(.*)$/i) {
+	    $title = $1;
+	}
+    }
+
+    if (!defined ($hfile) || !defined ($metadata)) {
+	die "Error in options passed to Hierarchy classification\n" .
+	    "hfile and metadata options aren't optional\n\n" .
+		"Options:\n" .
+		    "hfile -- the classification structure file\n" .
+			"metadata -- metadata field to test against hfile\n" .
+			    "sort -- metadata field to sort by\n" .
+				"title -- title of classification\n\n";
+    }
+
+    $title = $metadata unless defined $title;
+    
+    my $subjectfile = &util::filename_cat($ENV{'GSDLCOLLECTDIR'},"etc", $hfile);
+    if (!-e $subjectfile) {
+	my $collfile = $subjectfile;
+	$subjectfile = &util::filename_cat($ENV{'GSDLHOME'},"etc", $hfile);
+	if (!-e $subjectfile) {
+	    die "Hierarchy Error: Can't locate subject file $hfile\n" .
+		"This file should be in $collfile or $subjectfile\n";
+	}
+    }
+
+    return bless {
+	'descriptorlist'=>{}, # first field in subject file
+	'locatorlist'=>{},    # second field in subject file
+	'subjectfile' => $subjectfile,
+	'metaname' => $metadata,
+	'sortname' => $sortname,
+	'title' => $title
+	}, $class;
+}
+
+sub init {
+    my $self = shift (@_);
+
+    # read in the subject file
+    my $list = &cfgread::read_cfg_file ($self->{'subjectfile'}, undef, '^[^#]?\w');
+    
+    # $list is a hash that is indexed by the descriptor. The contents of this
+    # hash is a list of two items. The first item is the OID and the second item
+    # is the title
+    foreach $descriptor (keys (%$list)) {
+	$self->{'descriptorlist'}->{$descriptor} = $list->{$descriptor}->[0];
+	unless (defined $self->{'locatorlist'}->{$list->{$descriptor}->[0]}) {
+	    $self->{'locatorlist'}->{$list->{$descriptor}->[0]}->{'title'} = $list->{$descriptor}->[1];
+	    $self->{'locatorlist'}->{$list->{$descriptor}->[0]}->{'contents'} = [];
+	}
+    }
+}
+
+sub classify {
+    my $self = shift (@_);
+    my ($doc_obj) = @_;
+
+    my $doc_OID = $doc_obj->get_OID();
+
+    my $metadata = $doc_obj->get_metadata ($doc_obj->get_top_section(),
+					   $self->{'metaname'});
+
+    my $sortmeta = "";
+    if (defined $self->{'sortname'}) {
+	if ($self->{'sortname'} =~ /^filename$/i) {
+	    $sortmeta = $doc_obj->get_source_filename();
+	} else {
+	    $sortmeta = $doc_obj->get_metadata_element($doc_obj->get_top_section(),
+						       $self->{'sortname'});
+	    if (defined $sortmeta) {
+		if ($self->{'sortname'} eq "Creator") {
+		    &sorttools::format_string_name_english (\$sortmeta);
+		} else {
+		    &sorttools::format_string_english (\$sortmeta);
+		}
+	    }
+	}
+	$sortmeta = "" unless defined $sortmeta;
+    }
+
+    foreach $metaelement (@$metadata) {
+	if ((defined $self->{'descriptorlist'}->{$metaelement}) &&
+	    (defined $self->{'locatorlist'}->{$self->{'descriptorlist'}->{$metaelement}})) {
+
+	    push (@{$self->{'locatorlist'}->{$self->{'descriptorlist'}->{$metaelement}}->{'contents'}}, 
+		  [$doc_OID, $sortmeta]);
+	}
+    }
+}
+
+sub get_classify_info {
+    my $self = shift (@_);
+    
+    my $list = $self->{'locatorlist'};
+
+    my $classifyinfo = $self->get_entry ($self->{'title'}, "VList", "Invisible");
+    foreach $OID (keys (%$list)) {
+	my $tempinfo = $self->get_OID_entry ($OID, $classifyinfo, $list->{$OID}->{'title'}, "VList");
+
+	if (defined $self->{'sortname'}) {
+	    foreach $subOID (sort {$a->[1] cmp $b->[1];} @{$list->{$OID}->{'contents'}}) {
+		push (@{$tempinfo->{'contains'}}, {'OID'=>$subOID->[0]});
+	    }
+	} else {
+	    foreach $subOID (@{$list->{$OID}->{'contents'}}) {
+		push (@{$tempinfo->{'contains'}}, {'OID'=>$subOID->[0]});
+	    }
+	}
+    }
+    
+    return $classifyinfo;
+}
+
+sub get_OID_entry {
+    my $self = shift (@_);
+    my ($OID, $classifyinfo, $title, $classifytype) = @_;
+
+    $OID = "" unless defined $OID;
+    $OID =~ s/^\.+//;
+    
+    my ($headOID, $tailOID) = $OID =~ /^(\d+)(.*)$/;
+    $tailOID = "" unless defined $tailOID;
+
+
+    if (!defined $headOID) {
+	$classifyinfo->{'Title'} = $title;
+	$classifyinfo->{'classifytype'} = $classifytype;
+	return $classifyinfo;
+    }
+
+    $classifyinfo->{'contains'} = [] unless defined $classifyinfo->{'contains'};
+    
+    # add entries to the contains list until we have one for headOID
+    while (scalar(@{$classifyinfo->{'contains'}}) < $headOID) {
+	push (@{$classifyinfo->{'contains'}}, $self->get_entry("", $classifytype));
+    }
+
+    return $self->get_OID_entry ($tailOID, $classifyinfo->{'contains'}->[($headOID-1)], $title, $classifytype);
+}
+
+sub get_entry {
+    my $self = shift (@_);
+    my ($title, $childtype, $thistype) = @_;
+    
+    # organise into classification structure
+    my %classifyinfo = ('childtype'=>$childtype,
+			'Title'=>$title,
+			'contains'=>[]);
+    $classifyinfo{'thistype'} = $thistype 
+	if defined $thistype && $thistype =~ /\w/;
+
+    return \%classifyinfo;
+}
+
+
+1;
Index: /main/tags/2.25/gsdl/perllib/classify/List.pm
===================================================================
--- /main/tags/2.25/gsdl/perllib/classify/List.pm	(revision 21064)
+++ /main/tags/2.25/gsdl/perllib/classify/List.pm	(revision 21064)
@@ -0,0 +1,173 @@
+###########################################################################
+#
+# List.pm --
+# A component of the Greenstone digital library software
+# from the New Zealand Digital Library Project at the 
+# University of Waikato, New Zealand.
+#
+# Copyright (C) 1999 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.
+#
+###########################################################################
+
+# simple list classifier plugin 
+# options are:
+# metadata=Metaname -- (optional) all documents with Metaname metadata
+#                      will be included in list. if not included all documents
+#                      will be included in list.
+# sort=Meta         -- (optional) sort documents in list alphabetically by
+#                      Meta. by default it will sort by Metaname, if neither
+#                      are set documents will be in build (random) order.
+#                      Meta may be Filename to sort by original filename or
+#                      nosort to force not to sort
+# title=Title       -- (optional) the title field for this classification.
+#                      if not included title field will be Metaname. 
+#                      if metadata is also not included title will be 'List'
+
+package List;
+
+use sorttools;
+
+sub new {
+    my ($class, @options) = @_;
+
+    my $list = [];
+    my ($metaname, $title, $sortname);
+
+    foreach $option (@options) {
+	if ($option =~ /^metadata=(.*)$/i) {
+	    $metaname = $1;
+	    $list = {};
+	} elsif ($option =~ /^title=(.*)$/i) {
+	    $title = $1;
+	} elsif ($option =~ /^sort=(.*)$/i) {
+	    $sortname = $1;
+	}
+    }
+
+    if (!defined $title) {
+	if (defined $metaname) {
+	    $title = $metaname;
+	} else {
+	    $title = 'List';
+	}
+    }
+
+    if (defined $sortname && $sortname =~ /^nosort$/i) {
+	$sortname = undef;
+    } elsif (!defined $sortname && defined $metaname) {
+	$sortname = $metaname;
+    }
+
+    return bless {
+	'list'=>$list,
+	'metaname' => $metaname,
+	'title' => $title,
+	'sortname' => $sortname
+	}, $class;
+}
+
+sub init {
+    my $self = shift (@_);
+
+    if (defined $self->{'sortname'}) {
+	$self->{'list'} = {};
+    } else {
+	$self->{'list'} = [];
+    }
+}
+
+sub classify {
+    my $self = shift (@_);
+    my ($doc_obj) = @_;
+
+    my $doc_OID = $doc_obj->get_OID();
+
+    my $sortmeta = "";
+    if (defined $self->{'sortname'}) {
+	if ($self->{'sortname'} =~ /^filename$/i) {
+	    $sortmeta = $doc_obj->get_source_filename();
+	} else {
+	    $sortmeta = $doc_obj->get_metadata_element($doc_obj->get_top_section(),
+						       $self->{'sortname'});
+	    if (defined $sortmeta) {
+		if ($self->{'sortname'} eq "Creator") {
+		    &sorttools::format_string_name_english (\$sortmeta);
+		} else {
+		    &sorttools::format_string_english (\$sortmeta);
+		}
+	    }
+	}
+	$sortmeta = "" unless defined $sortmeta;
+
+	if (defined $self->{'metaname'}) {
+	    my $metavalue = $doc_obj->get_metadata_element ($doc_obj->get_top_section(),
+							    $self->{'metaname'});
+	    if (defined $metavalue) {
+		if (defined $self->{'list'}->{$doc_OID}) {
+		    print STDERR "WARNING: List::classify called multiple times for $doc_OID\n";
+		} 
+		$self->{'list'}->{$doc_OID} = $sortmeta;
+	    }
+	} else {
+	    if (defined $self->{'list'}->{$doc_OID}) {
+		print STDERR "WARNING: List::classify called multiple times for $doc_OID\n";
+	    } 
+	    $self->{'list'}->{$doc_OID} = $sortmeta;
+	}
+    } else {
+	if (defined $self->{'metaname'}) {
+	    my $metavalue = $doc_obj->get_metadata_element ($doc_obj->get_top_section(),
+							    $self->{'metaname'});
+	    if (defined $metavalue) {
+		push (@{$self->{'list'}}, $doc_OID);
+	    }
+	} else {
+	    push (@{$self->{'list'}}, $doc_OID);
+	}	    	    
+    }
+}
+
+sub get_classify_info {
+    my $self = shift (@_);
+    my ($no_thistype) = @_;
+    $no_thistype = 0 unless defined $no_thistype;
+
+    my @list = ();
+    if (defined $self->{'sortname'}) {
+	if (keys %{$self->{'list'}}) {
+	    @list = sort {$self->{'list'}->{$a} 
+			  cmp $self->{'list'}->{$b};} keys %{$self->{'list'}};
+	}
+    } else {
+	@list = @{$self->{'list'}};
+    }
+
+    # organise into classification structure
+    my %classifyinfo = ('childtype'=>'VList',
+			'Title'=>$self->{'title'},
+			'contains'=>[]);
+    $classifyinfo{'thistype'} = 'Invisible' unless $no_thistype;
+
+    foreach $OID (@list) {
+	push (@{$classifyinfo{'contains'}}, {'OID'=>$OID});
+    }
+
+    return \%classifyinfo;
+}
+
+
+1;
Index: /main/tags/2.25/gsdl/perllib/classify/SectionList.pm
===================================================================
--- /main/tags/2.25/gsdl/perllib/classify/SectionList.pm	(revision 21064)
+++ /main/tags/2.25/gsdl/perllib/classify/SectionList.pm	(revision 21064)
@@ -0,0 +1,120 @@
+###########################################################################
+#
+# SectionList.pm --
+# A component of the Greenstone digital library software
+# from the New Zealand Digital Library Project at the 
+# University of Waikato, New Zealand.
+#
+# Copyright (C) 1999 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.
+#
+###########################################################################
+
+# Same as List classifier but includes all sections of document
+# (excluding top level) rather than just top level document 
+# itself
+
+package SectionList;
+
+use sorttools;
+
+sub BEGIN {
+    @ISA = ('List');
+}
+
+sub classify {
+    my $self = shift (@_);
+    my ($doc_obj, @options) = @_;
+    
+    my $thissection = undef;
+
+    my $option;
+    foreach $option (@options)
+    {
+	if ($option =~ m/^section=(\d+)$/i) 
+	{
+	    $thissection = $1;
+	}
+    }
+
+    my $sortmeta = "";
+    if (defined $self->{'sortname'}) {
+	if ($self->{'sortname'} =~ /^filename$/i) {
+	    $sortmeta = $doc_obj->get_source_filename();
+	} else {
+	    $sortmeta = $doc_obj->get_metadata_element($doc_obj->get_top_section(),
+						       $self->{'sortname'});
+	    if ($self->{'sortname'} eq "Creator") {
+		&sorttools::format_string_name_english (\$sortmeta);
+	    } else {
+		&sorttools::format_string_english (\$sortmeta);
+	    }
+	}
+	$sortmeta = "" unless defined $sortmeta;
+    }
+
+    if (!defined $thissection)
+    {
+	$thissection = $doc_obj->get_next_section ($doc_obj->get_top_section());
+	while (defined $thissection) {
+	    $self->classify_section($thissection, $doc_obj, $sortmeta);
+	    $thissection = $doc_obj->get_next_section ($thissection);
+	}
+    }
+    else
+    {
+	$self->classify_section($thissection, $doc_obj, $sortmeta);
+    }
+}
+
+sub classify_section {
+    my $self = shift (@_);
+    my ($section, $doc_obj, $sortmeta) = @_;
+
+    my $doc_OID = $doc_obj->get_OID();
+    $sortmeta = "" unless defined $sortmeta;
+
+    if (defined $self->{'sortname'}) {
+	if (defined $self->{'metaname'}) {
+
+	    my $metavalue = $doc_obj->get_metadata_element ($section, $self->{'metaname'});
+	    if (defined $metavalue) {
+		if (defined $self->{'list'}->{"$doc_OID.$section"}) {
+		    print STDERR "WARNING: SectionList::classify called multiple times for $doc_OID.$section\n";
+		} 
+		$self->{'list'}->{"$doc_OID.$section"} = $sortmeta;
+	    }
+	} else {
+	    if (defined $self->{'list'}->{"$doc_OID.$section"}) {
+		print STDERR "WARNING: SectionList::classify called multiple times for $doc_OID.$section\n";
+	    } 
+	    $self->{'list'}->{"$doc_OID.$section"} = $sortmeta;
+	}
+
+    } else {
+	if (defined $self->{'metaname'}) {
+
+	    my $metavalue = $doc_obj->get_metadata_element ($section, $self->{'metaname'});
+	    if (defined $metavalue) {
+		push (@{$self->{'list'}}, "$doc_OID.$section");
+	    }
+	} else {
+	    push (@{$self->{'list'}}, "$doc_OID.$section");
+	}
+    }
+}
+
+1;
Index: /main/tags/2.25/gsdl/perllib/cnseg.pm
===================================================================
--- /main/tags/2.25/gsdl/perllib/cnseg.pm	(revision 21064)
+++ /main/tags/2.25/gsdl/perllib/cnseg.pm	(revision 21064)
@@ -0,0 +1,74 @@
+###########################################################################
+#
+# cnseg.pm --
+# A component of the Greenstone digital library software
+# from the New Zealand Digital Library Project at the 
+# University of Waikato, New Zealand.
+#
+# Copyright (C) 1999 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.
+#
+###########################################################################
+
+
+# this package segments a chinese UTF-8 encoded Unicode
+# string into words.
+
+package cnseg;
+
+use unicode;
+
+
+# 'segment' takes a UTF-8 encoded Unicode Chinese-language
+# string and places U-200B between words -- the ZERO
+# WIDTH SPACE. Each line is treated as a separate 
+# paragraph, so lines in one paragraph should
+# be joined before using this method (normally a single
+# word might span more than one line within a paragraph).
+#
+# 'segment' is currently written in Perl, however, I (Rodger)
+# plan to use C++ (via pipes) once a more complex (and useful!)
+# algorithm is being used. Currently, each Chinese character
+# is treated as a seperate word.
+
+sub segment {
+    my ($in) = @_;
+    my ($c);
+
+    my $uniin = &unicode::utf82unicode($in);
+    my $out = [];
+
+    my $space = 1; # start doesn't need a space
+    foreach $c (@$uniin) {
+	if (($c >= 0x4e00 && $c <= 0x9fa5) ||
+	    ($c >= 0xf900 && $c <= 0xfa2d)) {
+	    # Chinese character
+	    push (@$out, 0x200b) unless $space;
+	    push (@$out, $c);
+	    push (@$out, 0x200b);
+	    $space = 1;
+
+	} else {
+	    # non-Chinese character
+	    push (@$out, $c);
+	    $space = 0;
+	}
+    }
+
+    return &unicode::unicode2utf8($out);
+}
+
+1;
Index: /main/tags/2.25/gsdl/perllib/colcfg.pm
===================================================================
--- /main/tags/2.25/gsdl/perllib/colcfg.pm	(revision 21064)
+++ /main/tags/2.25/gsdl/perllib/colcfg.pm	(revision 21064)
@@ -0,0 +1,113 @@
+###########################################################################
+#
+# colcfg.pm --
+# A component of the Greenstone digital library software
+# from the New Zealand Digital Library Project at the 
+# University of Waikato, New Zealand.
+#
+# Copyright (C) 1999 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.
+#
+###########################################################################
+
+# reads in a collection configuration file
+
+package colcfg;
+
+use cfgread;
+
+
+# the collection configuration file data is stored in the form
+#
+# {'creator'}->string
+# {'public'}->string
+# {'beta'}->string
+# {'defaultindex'}->string
+# {'importdir'}->string
+# {'archivedir'}->string
+# {'cachedir'}->string
+# {'builddir'}->string
+# {'removeold'}->string
+# {'textcompress'}->string
+
+# {'maintainer'}->array of strings
+# {'languages'}->array of strings
+# {'indexsubcollections'}->array of strings
+# {'indexes'}->array of strings
+# {'dontbuild'}->array of strings
+# {'dontgdbm'}->array of strings
+# {'mirror'}->array of strings
+
+# {'subcollection'}->hash of key-value pairs
+# {'collectionmeta'}->hash of key-value pairs
+
+# {'plugin'}->array of arrays of strings
+# {'classify'}->array of arrays of strings
+
+sub read_collect_cfg {
+    my ($filename) = @_;
+
+    return &cfgread::read_cfg_file ($filename, 
+				    q/^(creator|public|beta|defaultindex|importdir|/ .
+					q/archivedir|cachedir|builddir|removeold|textcompress)$/,
+				    q/(maintainer|languages|indexsubcollections|/ .
+				       q/indexes|dontbuild|dontgdbm|mirror)$/,
+				    q/^(subcollection|collectionmeta)$/,
+				    q/^(plugin|classify)$/);
+}
+
+sub write_collect_cfg {
+    my ($filename, $data) = @_;
+
+    &cfgread::write_cfg_file($filename, $data,
+			     q/^(creator|public|beta|defaultindex|importdir|/ .
+				 q/archivedir|cachedir|builddir|removeold|textcompress)$/,
+			     q/^(maintainer|languages|indexsubcollections|/ .
+				 q/indexes|dontbuild|dontgdbm)$/,
+			     q/^(subcollection|collectionmeta)$/,
+			     q/^(plugin|classify)$/);
+}
+
+
+# the build configuration file data is stored in the form
+#
+# {'builddate'}->string
+# {'buildtype'}->string
+# {'metadata'}->array of strings
+# {'languages'}->array of strings
+# {'numdocs'}->string
+# {'numwords'}->string
+# {'numbytes'}->string
+# {'indexfields'}->array of strings
+
+sub read_build_cfg {
+    my ($filename) = @_;
+
+    return &cfgread::read_cfg_file ($filename, 
+				    q/^(builddate|buildtype|numdocs|numwords|numbytes)$/, 
+				    q/^(metadata|languages|indexfields)$/);
+}
+
+sub write_build_cfg {
+    my ($filename, $data) = @_;
+
+    &cfgread::write_cfg_file($filename, $data,
+			     q/^(builddate|numdocs|numwords|numbytes)$/, 
+			     q/^(metadata|languages)$/);
+}
+
+
+1;
Index: /main/tags/2.25/gsdl/perllib/doc.pm
===================================================================
--- /main/tags/2.25/gsdl/perllib/doc.pm	(revision 21064)
+++ /main/tags/2.25/gsdl/perllib/doc.pm	(revision 21064)
@@ -0,0 +1,875 @@
+###########################################################################
+#
+# doc.pm --
+# A component of the Greenstone digital library software
+# from the New Zealand Digital Library Project at the 
+# University of Waikato, New Zealand.
+#
+# Copyright (C) 1999 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.
+#
+###########################################################################
+
+# base class to hold documents
+
+package doc;
+
+BEGIN {
+    die "GSDLHOME not set\n" unless defined $ENV{'GSDLHOME'};
+    unshift (@INC, "$ENV{'GSDLHOME'}/perllib/dynamic/lib/site_perl/5.005/i686-linux");
+}
+
+use unicode;
+use util;
+use ghtml;
+##use hashdoc;
+
+# the document type may be indexed_doc, nonindexed_doc, or
+# classification
+
+sub new {
+    my $class = shift (@_);
+    my ($source_filename, $doc_type) = @_;
+
+    my $self = bless {'associated_files'=>[],
+		      'subsection_order'=>[],
+		      'next_subsection'=>1,
+		      'subsections'=>{},
+		      'metadata'=>[],
+		      'text'=>""}, $class;
+
+    $self->set_source_filename ($source_filename) if defined $source_filename;
+    $self->set_doc_type ($doc_type) if defined $doc_type;
+
+    return $self;
+}
+
+# clone the $self object
+sub duplicate {
+    my $self = shift (@_);
+
+    my $newobj = {};
+    
+    foreach $k (keys %$self) {
+	$newobj->{$k} = &clone ($self->{$k});
+    }
+
+    bless $newobj, ref($self);
+    return $newobj;
+}
+
+sub clone {
+    my ($from) = @_;
+    my $type = ref ($from);
+
+    if ($type eq "HASH") {
+	my $to = {};
+	foreach $key (keys %$from) {
+	    $to->{$key} = &clone ($from->{$key});
+	}
+	return $to;
+    } elsif ($type eq "ARRAY") {
+	my $to = [];
+	foreach $v (@$from) {
+	    push (@$to, &clone ($v));
+	}
+	return $to;
+    } else {
+	return $from;
+    }
+}
+
+
+sub set_source_filename {
+    my $self = shift (@_);
+    my ($source_filename) = @_;
+
+    $self->set_metadata_element ($self->get_top_section(), 
+				 "gsdlsourcefilename", 
+				 $source_filename);
+}
+
+# returns the source_filename as it was provided
+sub get_source_filename {
+    my $self = shift (@_);
+
+    return $self->get_metadata_element ($self->get_top_section(), "gsdlsourcefilename");
+}
+
+sub set_doc_type {
+    my $self = shift (@_);
+    my ($doc_type) = @_;
+
+    $self->set_metadata_element ($self->get_top_section(), 
+				 "gsdldoctype", 
+				 $doc_type);
+}
+
+# returns the source_filename as it was provided
+# the default of "indexed_doc" is used if no document
+# type was provided
+sub get_doc_type {
+    my $self = shift (@_);
+
+    my $doc_type = $self->get_metadata_element ($self->get_top_section(), "gsdldoctype");
+    return $doc_type if (defined $doc_type);
+    return "indexed_doc";
+}
+
+sub _escape_text {
+    my ($text) = @_;
+
+    # special characters in the gml encoding
+    $text =~ s/&/&amp;/g; # this has to be first...
+    $text =~ s/</&lt;/g;
+    $text =~ s/>/&gt;/g;
+    $text =~ s/\"/&quot;/g;
+
+    return $text;
+}
+
+
+sub buffer_section {
+    my $self = shift (@_);
+    my ($section, $suppress_subject_info) = @_;
+
+    $suppress_subject_info = 0 unless defined $suppress_subject_info;
+    my ($all_text,$data, $subsection);
+    
+    my $section_ptr = $self->_lookup_section ($section);
+    my ($section_num) = $section =~ /(\d+)$/;
+    
+    return "" unless defined $section_ptr;
+
+    # output the section header (including the section number
+    # and metadata)
+
+    $all_text = "<gsdlsection";
+    $all_text .= " gsdlnum=\"$section_num\"" if defined $section_num;
+    foreach $data (@{$section_ptr->{'metadata'}}) {
+	$all_text .= " $data->[0]=\"" . &_escape_text($data->[1]) . "\"" 
+	    unless $suppress_subject_info && $data->[0] eq "Subject";
+    }
+    $all_text .= ">";
+
+    # output the text
+    $all_text .= &_escape_text($section_ptr->{'text'});
+
+    # output all the subsections
+    foreach $subsection (@{$section_ptr->{'subsection_order'}}) {
+	$all_text .= $self->buffer_section("$section.$subsection", $suppress_subject_info);
+    }
+    
+    # output the closing tag
+    $all_text .=  "</gsdlsection>\n";
+
+    return $all_text;
+}
+
+sub output_section {
+    my $self = shift (@_);
+    my ($handle, $section, $suppress_subject_info) = @_;
+
+    my $all_text = $self->buffer_section($section, $suppress_subject_info);
+    print $handle $all_text;
+}
+
+# look up the reference to the a particular section
+sub _lookup_section {
+    my $self = shift (@_);
+    my ($section) = @_;
+
+    my ($num);
+    my $sectionref = $self;
+
+    while (defined $section && $section ne "") {
+	($num, $section) = $section =~ /^\.?(\d+)(.*)$/;
+	$num =~ s/^0+(\d)/$1/; # remove leading 0s
+	$section = "" unless defined $section;
+	
+	if (defined $num && defined $sectionref->{'subsections'}->{$num}) {
+	    $sectionref = $sectionref->{'subsections'}->{$num};
+	} else {
+	    return undef;
+	}
+    }
+    
+    return $sectionref;
+}
+
+sub _calc_OID {
+    my $self = shift (@_);
+    my ($filename) = @_;
+
+    my $osexe = &util::get_os_exe();
+
+    my $hashfile_exe = &util::filename_cat($ENV{'GSDLHOME'},"bin",
+					   $ENV{'GSDLOS'},"hashfile$osexe");
+    my $result = "NULL";
+
+    if (-e "$hashfile_exe") {
+	$result = `$hashfile_exe \"$filename\"`;
+	($result) = $result =~ /:\s*([0-9a-f]+)/i;
+
+    } else {
+	print STDERR "doc::_calc_OID $hashfile_exe could not be found\n";
+    }
+
+    return "HASH$result";
+}
+
+# methods dealing with OID, not groups of them.
+
+# if $OID is not provided one is calculated from hashing the
+# current contents of the document
+# An OID are actually stored as metadata of the document
+sub set_OID {
+    my $self = shift (@_);
+    my ($OID) = @_;
+
+    # if an OID wasn't provided then feed this document to 
+    # hashfile.exe
+    if (!defined $OID) {
+	$OID = "NULL";
+
+	my $filename = $self->get_source_filename();
+	if (defined($filename) && -e $filename) {
+
+	    $OID = $self->_calc_OID ($filename);
+
+	} else {
+	    
+	    print STDERR "doc::set_OID source filename undefined/non-existant (continuing)\n";
+	    
+	    $filename = &util::get_tmp_filename();
+	    if (!open (OUTFILE, ">$filename")) {
+		print STDERR "doc::set_OID could not write to $filename\n";
+	    } else {
+		$self->output_section('OUTFILE', $self->get_top_section(), 1);
+		close (OUTFILE);
+	    }
+	    
+	    $OID = $self->_calc_OID ($filename);
+	    &util::rm ($filename);
+	}
+    }
+
+    $self->set_metadata_element ($self->get_top_section(), "Identifier", $OID);
+}
+
+# this uses hashdoc (embedded c thingy) which is faster but still 
+# needs a little work to be suffiently stable
+sub ___set_OID {
+    my $self = shift (@_);
+    my ($OID) = @_;
+
+    # if an OID wasn't provided then calculate hash value based on document
+    if (!defined $OID) 
+    {
+	my $hash_text = $self->buffer_section($self->get_top_section(), 1);
+	my $hash_len = length($hash_text);
+
+        $OID = &hashdoc::buffer($hash_text,$hash_len);
+    }
+
+    $self->set_metadata_element ($self->get_top_section(), "Identifier", $OID);
+}
+
+# returns the OID for this document
+sub get_OID {
+    my $self = shift (@_);
+    my $OID = $self->get_metadata_element ($self->get_top_section(), "Identifier");
+    return $OID if (defined $OID);
+    return "NULL";
+}
+
+sub delete_OID {
+    my $self = shift (@_);
+    
+    $self->set_metadata_element ($self->get_top_section(), "Identifier", "NULL");
+}
+
+
+# methods for manipulating section names
+
+# returns the name of the top-most section (the top
+# level of the document
+sub get_top_section {
+    my $self = shift (@_);
+    
+    return "";
+}
+
+# returns a section
+sub get_parent_section {
+    my $self = shift (@_);
+    my ($section) = @_;
+
+    $section =~ s/(^|\.)\d+$//;
+
+    return $section;
+}
+
+# returns the first child section (or the end child 
+# if there isn't any)
+sub get_begin_child {
+    my $self = shift (@_);
+    my ($section) = @_;
+
+    my $section_ptr = $self->_lookup_section($section);
+    return "" unless defined $section_ptr;
+
+    if (defined $section_ptr->{'subsection_order'}->[0]) {
+	return "$section.$section_ptr->{'subsection_order'}->[0]";
+    }
+
+    return $self->get_end_child ($section);
+}
+
+# returns the next child of a parent section
+sub get_next_child {
+    my $self = shift (@_);
+    my ($section) = @_;
+    
+    my $parent_section = $self->get_parent_section($section);
+    my $parent_section_ptr = $self->_lookup_section($parent_section);
+    return undef unless defined $parent_section_ptr;
+
+    my ($section_num) = $section =~ /(\d+)$/;
+    return undef unless defined $section_num;
+
+    my $i = 0;
+    my $section_order = $parent_section_ptr->{'subsection_order'};
+    while ($i < scalar(@$section_order)) {
+	last if $section_order->[$i] eq $section_num;
+	$i++;
+    }
+
+    $i++; # the next child
+    if ($i < scalar(@$section_order)) {
+	return $section_order->[$i] if $parent_section eq "";
+	return "$parent_section.$section_order->[$i]";
+    }
+
+    # no more sections in this level
+    return undef;
+}
+
+# returns a reference to a list of children
+sub get_children {
+    my $self = shift (@_);
+    my ($section) = @_;
+
+    my $section_ptr = $self->_lookup_section($section);
+    return [] unless defined $section_ptr;
+
+    my @children = @{$section_ptr->{'subsection_order'}};
+
+    map {$_ = "$section.$_"; $_ =~ s/^\.+//;} @children;
+    return \@children;
+}
+
+# returns the child section one past the last one (which
+# is coded as "0")
+sub get_end_child {
+    my $self = shift (@_);
+    my ($section) = @_;
+
+    return $section . ".0" unless $section eq "";
+    return "0";
+}
+
+# returns the next section in book order
+sub get_next_section {
+    my $self = shift (@_);
+    my ($section) = @_;
+
+    return undef unless defined $section;
+
+    my $section_ptr = $self->_lookup_section($section);
+    return undef unless defined $section_ptr;
+
+    # first try to find first child
+    if (defined $section_ptr->{'subsection_order'}->[0]) {
+	return $section_ptr->{'subsection_order'}->[0] if ($section eq "");
+	return "$section.$section_ptr->{'subsection_order'}->[0]";
+    }
+
+    do {
+	# try to find sibling
+	my $next_child = $self->get_next_child ($section);
+	return $next_child if (defined $next_child);
+
+	# move up one level
+	$section = $self->get_parent_section ($section);
+    } while $section =~ /\d/;
+
+    return undef;
+}
+
+sub is_leaf_section {
+    my $self = shift (@_);
+    my ($section) = @_;
+
+    my $section_ptr = $self->_lookup_section($section);
+    return 1 unless defined $section_ptr;
+
+    return (scalar (@{$section_ptr->{'subsection_order'}}) == 0);
+}
+
+# methods for dealing with sections
+
+# returns the name of the inserted section
+sub insert_section {
+    my $self = shift (@_);
+    my ($before_section) = @_;
+
+    # get the child to insert before and its parent section
+    my $parent_section = "";
+    my $before_child = "0";
+    my @before_section = split (/\./, $before_section);
+    if (scalar(@before_section) > 0) {
+	$before_child = pop (@before_section);
+	$parent_section = join (".", @before_section);
+    }
+
+    my $parent_section_ptr = $self->_lookup_section($parent_section);
+    if (!defined $parent_section_ptr) {
+	print STDERR "doc::insert_section couldn't find parent section " .
+	    "$parent_section\n";
+	return;
+    }
+
+    # get the next section number
+    my $section_num = $parent_section_ptr->{'next_subsection'}++;
+
+    my $i = 0;
+    while ($i < scalar(@{$parent_section_ptr->{'subsection_order'}}) &&
+	   $parent_section_ptr->{'subsection_order'}->[$i] ne $before_child) {
+	$i++;
+    }
+    
+    # insert the section number into the order list
+    splice (@{$parent_section_ptr->{'subsection_order'}}, $i, 0, $section_num);
+
+    # add this section to the parent section
+    my $section_ptr = {'subsection_order'=>[],
+		       'next_subsection'=>1,
+		       'subsections'=>{},
+		       'metadata'=>[],
+		       'text'=>""};
+    $parent_section_ptr->{'subsections'}->{$section_num} = $section_ptr;
+
+    # work out the full section number
+    my $section = $parent_section;
+    $section .= "." unless $section eq "";
+    $section .= $section_num;
+    
+    return $section;
+}
+
+# creates a pre-named section
+sub create_named_section {
+    my $self = shift (@_);
+    my ($mastersection) = @_;
+
+    my ($num);
+    my $section = $mastersection;
+    my $sectionref = $self;
+
+####    print STDERR "*** mastersection = $mastersection\n";
+
+    while ($section ne "") {
+	($num, $section) = $section =~ /^\.?(\d+)(.*)$/;
+	$num =~ s/^0+(\d)/$1/; # remove leading 0s
+	$section = "" unless defined $section;
+	
+	if (defined $num) {
+	    if (!defined $sectionref->{'subsections'}->{$num}) {
+		push (@{$sectionref->{'subsection_order'}}, $num);
+		$sectionref->{'subsections'}->{$num} = {'subsection_order'=>[],
+							'next_subsection'=>1,
+							'subsections'=>{},
+							'metadata'=>[],
+							'text'=>""};
+		if ($num >= $sectionref->{'next_subsection'}) {
+		    $sectionref->{'next_subsection'} = $num + 1;
+		}
+	    }
+	    $sectionref = $sectionref->{'subsections'}->{$num};
+
+	} else {
+	    print STDERR "doc::create_named_section couldn't create section ";
+	    print STDERR "$mastersection\n";
+	    last;
+	}
+    }
+}
+
+# returns a reference to a list of subsections
+sub list_subsections {
+    my $self = shift (@_);
+    my ($section) = @_;
+
+    my $section_ptr = $self->_lookup_section ($section);
+    if (!defined $section_ptr) {
+	print STDERR "doc::list_subsections couldn't find section $section\n";
+	return [];
+    }
+
+    return [@{$section_ptr->{'subsection_order'}}];
+}
+
+sub delete_section {
+    my $self = shift (@_);
+    my ($section) = @_;
+
+#    my $section_ptr = {'subsection_order'=>[],
+#		       'next_subsection'=>1,
+#		       'subsections'=>{},
+#		       'metadata'=>[],
+#		       'text'=>""};
+
+    # if this is the top section reset everything
+    if ($section eq "") {
+	$self->{'subsection_order'} = [];
+	$self->{'subsections'} = {};
+	$self->{'metadata'} = [];
+	$self->{'text'} = "";
+	return;
+    }
+
+    # find the parent of the section to delete
+    my $parent_section = "";
+    my $child = "0";
+    my @section = split (/\./, $section);
+    if (scalar(@section) > 0) {
+	$child = pop (@section);
+	$parent_section = join (".", @section);
+    }
+
+    my $parent_section_ptr = $self->_lookup_section($parent_section);
+    if (!defined $parent_section_ptr) {
+	print STDERR "doc::delete_section couldn't find parent section " .
+	    "$parent_section\n";
+	return;
+    }
+
+    # remove this section from the subsection_order list
+    my $i = 0;
+    while ($i < scalar (@{$parent_section_ptr->{'subsection_order'}})) {
+	if ($parent_section_ptr->{'subsection_order'}->[$i] eq $child) {
+	    splice (@{$parent_section_ptr->{'subsection_order'}}, $i, 1);
+	    last;
+	}
+	$i++;
+    }
+
+    # remove this section from the subsection hash
+    if (defined ($parent_section_ptr->{'subsections'}->{$child})) {
+	undef $parent_section_ptr->{'subsections'}->{$child};
+    }
+}
+
+#--
+# methods for dealing with metadata
+
+# set_metadata_element and get_metadata_element are for metadata
+# which should only have one value. add_meta_data and get_metadata
+# are for metadata which can have more than one value.
+
+# returns the first metadata value which matches field
+sub get_metadata_element {
+    my $self = shift (@_);
+    my ($section, $field) = @_;
+    my ($data);
+
+    my $section_ptr = $self->_lookup_section($section);
+    if (!defined $section_ptr) {
+	print STDERR "doc::get_metadata_element couldn't find section " .
+	    "$section\n";
+	return;
+    }
+
+    foreach $data (@{$section_ptr->{'metadata'}}) {
+	return $data->[1] if (scalar(@$data) >= 2 && $data->[0] eq $field);
+    }
+	
+    return undef; # was not found
+}
+
+
+# returns a list of the form [value1, value2, ...]
+sub get_metadata {
+    my $self = shift (@_);
+    my ($section, $field) = @_;
+    my ($data);
+
+    my $section_ptr = $self->_lookup_section($section);
+    if (!defined $section_ptr) {
+        print STDERR "doc::get_metadata couldn't find section " .
+            "$section\n";
+        return;
+    }
+
+    my @metadata = ();
+    foreach $data (@{$section_ptr->{'metadata'}}) {
+        push (@metadata, $data->[1]) if ($data->[0] eq $field);
+    }
+        
+    return \@metadata;
+}
+
+# returns a list of the form [[field,value],[field,value],...]
+sub get_all_metadata {
+    my $self = shift (@_);
+    my ($section) = @_;
+
+    my $section_ptr = $self->_lookup_section($section);
+    if (!defined $section_ptr) {
+	print STDERR "doc::get_all_metadata couldn't find section " .
+	    "$section\n";
+	return;
+    }
+    
+    return $section_ptr->{'metadata'};
+}
+
+# $value is optional
+sub delete_metadata {
+    my $self = shift (@_);
+    my ($section, $field, $value) = @_;
+
+    my $section_ptr = $self->_lookup_section($section);
+    if (!defined $section_ptr) {
+	print STDERR "doc::delete_metadata couldn't find section " .
+	    "$section\n";
+	return;
+    }
+
+    my $i = 0;
+    while ($i < scalar (@{$section_ptr->{'metadata'}})) {
+	if (($section_ptr->{'metadata'}->[$i]->[0] eq $field) &&
+	    (!defined $value || $section_ptr->{'metadata'}->[$i]->[1] eq $value)) {
+	    splice (@{$section_ptr->{'metadata'}}, $i, 1);
+	} else {
+	    $i++;
+	}
+    }
+}
+
+sub delete_all_metadata {
+    my $self = shift (@_);
+    my ($section) = @_;
+
+    my $section_ptr = $self->_lookup_section($section);
+    if (!defined $section_ptr) {
+	print STDERR "doc::delete_all_metadata couldn't find section " .
+	    "$section\n";
+	return;
+    }
+    
+    $section_ptr->{'metadata'} = [];
+}
+
+sub set_metadata_element {
+    my $self = shift (@_);
+    my ($section, $field, $value) = @_;
+
+    $self->set_utf8_metadata_element ($section, $field, 
+				      &unicode::ascii2utf8($value));
+}
+
+# set_utf8_metadata_element assumes the text has already been
+# converted to the UTF-8 encoding.
+sub set_utf8_metadata_element {
+    my $self = shift (@_);
+    my ($section, $field, $value) = @_;
+
+    $self->delete_metadata ($section, $field);
+    $self->add_utf8_metadata ($section, $field, $value);
+}
+
+
+# add_metadata assumes the text is in (extended) ascii form. For
+# text which hash been already converted to the UTF-8 format use
+# add_utf8_metadata.
+sub add_metadata {
+    my $self = shift (@_);
+    my ($section, $field, $value) = @_;
+
+    $self->add_utf8_metadata ($section, $field,
+			      &unicode::ascii2utf8($value));
+}
+
+# add_utf8_metadata assumes the text has already been converted
+# to the UTF-8 encoding.
+sub add_utf8_metadata {
+    my $self = shift (@_);
+    my ($section, $field, $value) = @_;
+
+    my $section_ptr = $self->_lookup_section($section);
+    if (!defined $section_ptr) {
+	print STDERR "doc::add_utf8_metadata couldn't find section " .
+	    "$section\n";
+	return;
+    }
+    
+    push (@{$section_ptr->{'metadata'}}, [$field, $value]);
+}
+
+
+# methods for dealing with text
+
+# returns the text for a section
+sub get_text {
+    my $self = shift (@_);
+    my ($section) = @_;
+
+    my $section_ptr = $self->_lookup_section($section);
+    if (!defined $section_ptr) {
+	print STDERR "doc::get_text couldn't find section " .
+	    "$section\n";
+	return "";
+    }
+
+    return $section_ptr->{'text'};
+}
+
+# returns the (utf-8 encoded) length of the text for a section
+sub get_text_length {
+    my $self = shift (@_);
+    my ($section) = @_;
+
+    my $section_ptr = $self->_lookup_section($section);
+    if (!defined $section_ptr) {
+	print STDERR "doc::get_text_length couldn't find section " .
+	    "$section\n";
+	return 0;
+    }
+
+    return length ($section_ptr->{'text'});
+}
+
+sub delete_text {
+    my $self = shift (@_);
+    my ($section) = @_;
+
+    my $section_ptr = $self->_lookup_section($section);
+    if (!defined $section_ptr) {
+	print STDERR "doc::delete_text couldn't find section " .
+	    "$section\n";
+	return;
+    }
+
+    $section_ptr->{'text'} = "";
+}
+
+# add_text assumes the text is in (extended) ascii form. For
+# text which has been already converted to the UTF-8 format
+# use add_utf8_text.
+sub add_text {
+    my $self = shift (@_);
+    my ($section, $text) = @_;
+
+    # convert the text to UTF-8 encoded unicode characters
+    # and add the text
+    $self->add_utf8_text($section, &unicode::ascii2utf8($text));
+}
+
+
+# add_utf8_text assumes the text to be added has already
+# been converted to the UTF-8 encoding. For ascii text use
+# add_text
+sub add_utf8_text {
+    my $self = shift (@_);
+    my ($section, $text) = @_;
+
+    my $section_ptr = $self->_lookup_section($section);
+    if (!defined $section_ptr) {
+	print STDERR "doc::add_utf8_text couldn't find section " .
+	    "$section\n";
+	return;
+    }
+
+    $section_ptr->{'text'} .= $text;
+}
+
+
+# methods for dealing with associated files
+
+# a file is associated with a document, NOT a section.
+# if section is defined it is noted in the data structure
+# only so that files associated from a particular section
+# may be removed later (using delete_section_assoc_files)
+sub associate_file {
+    my $self = shift (@_);
+    my ($real_filename, $assoc_filename, $mime_type, $section) = @_;
+    $mime_type = &ghtml::guess_mime_type ($real_filename) unless defined $mime_type;
+
+    # remove all associated files with the same name
+    $self->delete_assoc_file ($assoc_filename);
+
+    push (@{$self->{'associated_files'}}, 
+	  [$real_filename, $assoc_filename, $mime_type, $section]);
+}
+
+# returns a list of associated files in the form
+#   [[real_filename, assoc_filename, mimetype], ...]
+sub get_assoc_files {
+    my $self = shift (@_);
+
+    return $self->{'associated_files'};
+}
+
+sub delete_section_assoc_files {
+    my $self = shift (@_);
+    my ($section) = @_;
+
+    my $i=0;
+    while ($i < scalar (@{$self->{'associated_files'}})) {
+	if (defined $self->{'associated_files'}->[$i]->[3] &&
+	    $self->{'associated_files'}->[$i]->[3] eq $section) {
+	    splice (@{$self->{'associated_files'}}, $i, 1);
+	} else {
+	    $i++;
+	}
+    }
+}
+
+sub delete_assoc_file {
+    my $self = shift (@_);
+    my ($assoc_filename) = @_;
+
+    my $i=0;
+    while ($i < scalar (@{$self->{'associated_files'}})) {
+	if ($self->{'associated_files'}->[$i]->[1] eq $assoc_filename) {
+	    splice (@{$self->{'associated_files'}}, $i, 1);
+	} else {
+	    $i++;
+	}
+    }
+}
+
+sub reset_nextsection_ptr {
+    my $self = shift (@_);
+    my ($section) = @_;
+    
+    my $section_ptr = $self->_lookup_section($section);
+    $section_ptr->{'next_subsection'} = 1;
+}
+
+1;
Index: /main/tags/2.25/gsdl/perllib/docprint.pm
===================================================================
--- /main/tags/2.25/gsdl/perllib/docprint.pm	(revision 21064)
+++ /main/tags/2.25/gsdl/perllib/docprint.pm	(revision 21064)
@@ -0,0 +1,66 @@
+###########################################################################
+#
+# docprint.pm
+# A component of the Greenstone digital library software
+# from the New Zealand Digital Library Project at the 
+# University of Waikato, New Zealand.
+#
+# Copyright (C) 1999 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.
+#
+###########################################################################
+
+# This document processor prints a document out to STDOUT
+
+
+package docprint;
+
+use arcinfo;
+use docproc;
+use util;
+
+
+sub BEGIN {
+    @ISA = ('docproc');
+}
+
+sub new {
+    my ($class) = @_;
+    my $self = new docproc ();
+
+    return bless $self, $class;
+}
+
+sub process {
+    my $self = shift (@_);
+    my ($doc_obj) = @_;
+
+    # add associated files as metadata to the document
+    my @assoc_files = ();
+    foreach $assoc_file (@{$doc_obj->get_assoc_files()}) {
+	if (-e $assoc_file->[0]) {
+	    $doc_obj->add_metadata ($doc_obj->get_top_section(), 
+				    "gsdlassocfile", 
+				    "$assoc_file->[1]:$assoc_file->[2]");
+	}
+    }
+    
+    # output document
+    $doc_obj->output_section(STDOUT, $doc_obj->get_top_section());
+}
+
+
+1;
Index: /main/tags/2.25/gsdl/perllib/docproc.pm
===================================================================
--- /main/tags/2.25/gsdl/perllib/docproc.pm	(revision 21064)
+++ /main/tags/2.25/gsdl/perllib/docproc.pm	(revision 21064)
@@ -0,0 +1,46 @@
+###########################################################################
+#
+# docproc.pm --
+# A component of the Greenstone digital library software
+# from the New Zealand Digital Library Project at the 
+# University of Waikato, New Zealand.
+#
+# Copyright (C) 1999 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.
+#
+###########################################################################
+
+# document processors are used by the document reader plugins
+# to do some processing on some documents
+
+package docproc;
+
+sub new {
+    my ($class) = @_;
+    my $self = {};
+
+    return bless $self, $class;
+}
+
+sub process {
+    my $self = shift (@_);
+    my ($doc_obj) = @_;
+
+    die "docproc::process function must be implemented in sub classes\n";
+}
+
+1;
+
Index: /main/tags/2.25/gsdl/perllib/docsave.pm
===================================================================
--- /main/tags/2.25/gsdl/perllib/docsave.pm	(revision 21064)
+++ /main/tags/2.25/gsdl/perllib/docsave.pm	(revision 21064)
@@ -0,0 +1,265 @@
+###########################################################################
+#
+# docsave.pm
+# A component of the Greenstone digital library software
+# from the New Zealand Digital Library Project at the 
+# University of Waikato, New Zealand.
+#
+# Copyright (C) 1999 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.
+#
+###########################################################################
+
+# This document processor saves a document in the 
+# archives directory of a collection
+
+
+package docsave;
+
+use arcinfo;
+use docproc;
+use util;
+
+
+sub BEGIN {
+    @ISA = ('docproc');
+}
+
+sub new {
+    my ($class, $collection,$archive_info,$verbosity,$gzip,$groupsize) = @_;
+    my $self = new docproc ();
+
+
+    $groupsize=1 unless defined $groupsize;
+    $self->{'collection'} = $collection;
+    $self->{'archive_info'} = $archive_info;
+    $self->{'verbosity'} = $verbosity;
+    $self->{'gzip'} = $gzip;
+    
+    $self->{'groupsize'} = $groupsize;
+    $self->{'gs_count'} = 0;
+
+    # set a default for the archive directory
+    $self->{'archive_dir'} = "$ENV{'GSDLHOME'}/collect/$self->{'collection'}/archives";
+
+    $self->{'sortmeta'} = undef;
+
+    return bless $self, $class;
+}
+
+sub setarchivedir {
+    my $self = shift (@_);
+    my ($archive_dir) = @_;
+
+    $self->{'archive_dir'} = $archive_dir;
+}
+
+sub set_sortmeta {
+    my $self = shift (@_);
+    my ($sortmeta) = @_;
+
+    $self->{'sortmeta'} = $sortmeta;
+}
+
+sub process {
+    my $self = shift (@_);
+    my ($doc_obj) = @_;
+
+    if ($self->{'groupsize'} > 1) {
+	$self->group_process ($doc_obj);
+
+    } else {
+	# groupsize is 1 (i.e. one document per GML file) so sortmeta 
+	# may be used
+
+	my $OID = $doc_obj->get_OID();
+	$OID = "NULL" unless defined $OID;
+	
+	# get document's directory
+	my $doc_dir = $self->get_doc_dir ($OID);
+    
+	# copy all the associated files, add this information as metadata
+	# to the document
+	$self->process_assoc_files ($doc_obj, $doc_dir);
+
+	my $doc_file 
+	    = &util::filename_cat ($self->{'archive_dir'}, $doc_dir, "doc.gml");
+	my $short_doc_file = &util::filename_cat ($doc_dir, "doc.gml");
+	    
+	if (!open (OUTDOC, ">$doc_file")) {
+	    print STDERR "docsave::process could not write to file $doc_file\n";
+	    return;
+	}
+
+	# save this document
+	$doc_obj->output_section('docsave::OUTDOC', $doc_obj->get_top_section());
+	close OUTDOC;
+
+	if ($self->{'gzip'}) {
+	    my $doc_file = $self->{'gs_filename'};
+	    `gzip $doc_file`;
+	    $doc_file .= ".gz";
+	    $short_doc_file .= ".gz";
+	    if (!-e $doc_file) {
+		print STDERR "error while gzipping: $doc_file doesn't exist\n";
+		return 0;
+	    }
+	}
+
+	# do the sortmeta thing
+	my ($metadata);
+	if (defined ($self->{'sortmeta'})) {
+	    $metadata = $doc_obj->get_metadata_element ($doc_obj->get_top_section(), $self->{'sortmeta'});
+	}
+
+	# store reference in the archive_info
+	$self->{'archive_info'}->add_info($OID, $short_doc_file, $metadata);
+    }
+}
+
+sub group_process {
+    my $self = shift (@_);
+    my ($doc_obj) = @_;
+
+    my $OID = $doc_obj->get_OID();
+    $OID = "NULL" unless defined $OID;
+
+    my $groupsize = $self->{'groupsize'};
+    my $gs_count = $self->{'gs_count'};
+    my $open_new_file = (($gs_count % $groupsize)==0);
+
+    # opening a new file, or document has assoicated files => directory needed
+    if (($open_new_file) || (scalar(@{$doc_obj->get_assoc_files()})>0)) {
+
+	# get document's directory
+	my $doc_dir = $self->get_doc_dir ($OID);
+
+	# copy all the associated files, add this information as metadata
+	# to the document
+	$self->process_assoc_files ($doc_obj, $doc_dir);
+
+
+	if ($open_new_file) {
+	    # only if opening new file
+	    my $doc_file 
+		= &util::filename_cat ($self->{'archive_dir'}, $doc_dir, "doc.gml");
+	    my $short_doc_file = &util::filename_cat ($doc_dir, "doc.gml");
+	    
+	    if ($gs_count>0)
+	    {
+		return if (!$self->close_file_output());
+	    }
+	    
+	    if (!open (OUTDOC, ">$doc_file")) {
+		print STDERR "docsave::group_process could not write to file $doc_file\n";
+		return;
+	    }
+	    $self->{'gs_filename'} = $doc_file;
+	    $self->{'gs_short_filename'} = $short_doc_file;
+	    $self->{'gs_OID'} = $OID;
+	}
+    }
+
+    # save this document
+    $doc_obj->output_section('docsave::OUTDOC', $doc_obj->get_top_section());
+
+    $self->{'gs_count'}++;
+}
+
+
+sub get_doc_dir {
+    my $self = shift (@_);
+    my ($OID) = @_;
+
+    my $doc_info = $self->{'archive_info'}->get_info($OID);
+    my $doc_dir = "";
+    if (defined $doc_info && scalar(@$doc_info) >= 1) {
+	# this OID already has an assigned directory, use the
+	# same one.
+	$doc_dir = $doc_info->[0];
+	$doc_dir =~ s/\/?doc\.gml(\.gz)?$//;
+    } else {
+	# have to get a new document directory
+	my $doc_dir_rest = $OID;
+	my $doc_dir_num = 0;
+	do {
+	    $doc_dir .= "/" if $doc_dir_num > 0;
+	    if ($doc_dir_rest =~ s/^(.{1,8})//) {
+		$doc_dir .= $1;
+		$doc_dir_num++;
+	    }
+	} while ($doc_dir_rest ne "" && 
+		 ((-d &util::filename_cat ($self->{'archive_dir'}, "$doc_dir.dir")) || 
+		  ($self->{'archive_info'}->size() >= 1024 && $doc_dir_num < 2)));
+	$doc_dir .= ".dir";
+	
+    }
+	
+    &util::mk_all_dir (&util::filename_cat ($self->{'archive_dir'}, $doc_dir));
+
+    return $doc_dir;
+}
+
+
+sub process_assoc_files {
+    my $self = shift (@_);
+    my ($doc_obj, $doc_dir) = @_;
+
+    my @assoc_files = ();
+    foreach $assoc_file (@{$doc_obj->get_assoc_files()}) {
+	my ($dir, $afile) = $assoc_file->[1] =~ /^(.*?)([^\/\\]+)$/;
+	$dir = "" unless defined $dir;
+	if (-e $assoc_file->[0]) {
+	    my $filepath = &util::filename_cat($self->{'archive_dir'}, $doc_dir, $afile);
+	    &util::hard_link ($assoc_file->[0], $filepath);
+	    $doc_obj->add_utf8_metadata ($doc_obj->get_top_section(),
+					 "gsdlassocfile",
+					 "$afile:$assoc_file->[2]:$dir");
+	} else {
+	    print STDERR "docsave::process couldn't copy the associated file " .
+		"$assoc_file->[0] to $afile\n";
+	}
+    }
+}
+    
+
+sub close_file_output
+{
+    my ($self) = @_;
+
+    close OUTDOC;
+
+    my $OID = $self->{'gs_OID'};
+    my $short_doc_file = $self->{'gs_short_filename'};
+
+    if ($self->{'gzip'}) {
+	my $doc_file = $self->{'gs_filename'};
+	`gzip $doc_file`;
+	$doc_file .= ".gz";
+	$short_doc_file .= ".gz";
+	if (!-e $doc_file) {
+	    print STDERR "error while gzipping: $doc_file doesn't exist\n";
+	    return 0;
+	}
+    }
+
+    # store reference in the archive_info
+    $self->{'archive_info'}->add_info($OID, $short_doc_file);
+
+    return 1;
+}
+
+1;
Index: /main/tags/2.25/gsdl/perllib/gb.pm
===================================================================
--- /main/tags/2.25/gsdl/perllib/gb.pm	(revision 21064)
+++ /main/tags/2.25/gsdl/perllib/gb.pm	(revision 21064)
@@ -0,0 +1,282 @@
+###########################################################################
+#
+# gb.pm --
+# A component of the Greenstone digital library software
+# from the New Zealand Digital Library Project at the 
+# University of Waikato, New Zealand.
+#
+# Copyright (C) 1999 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.
+#
+###########################################################################
+
+#! /usr/local/bin/perl5 -w
+
+# useful methods for dealing with the GuoBiao (GB) encoding
+
+package gb;
+
+use util;
+
+# %encodings is of the form:
+#
+# encodings{encodingname-encodingname}->blocktranslation
+# blocktranslation->[[0-255],[256-511], ..., [65280-65535]]
+#
+# Any of the top translation blocks can point to an undefined
+# value. This data structure aims to allow fast translation and 
+# efficient storage.
+
+# @array256 is used for initialisation, there must be
+# a better way...
+@array256 = (0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+	     0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+	     0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+	     0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+	     0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+	     0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+	     0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+	     0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+	     0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+	     0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+	     0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+	     0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+	     0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+	     0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+	     0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+	     0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0);
+
+
+%translations = ();
+
+
+# gb2unicode uses the GBK translation table
+sub gb2unicode {
+    generalgb2unicode ("GBK", @_);
+}
+
+# returns a pointer to unicode array
+sub generalgb2unicode {
+    my ($encoding, $intext) = @_;
+
+    if (!&loadmapencoding ("$encoding-unicode")) {
+	print STDERR "gb: ERROR - could not load encoding $encoding\n";
+	return [];
+    }
+    
+    my @outtext = ();
+    my $encodename = "$encoding-unicode";
+    my $len = length($intext);
+    my ($c1, $c2);
+    my $i = 0;
+
+    while ($i < $len) {
+	if (($c1 = ord(substr($intext, $i, 1))) >= 0x81) {
+	    if ($i+1 < $len) {
+		# found a GB character, put black square if cannot translate
+		$c2 = ord(substr($intext, $i+1, 1));
+		my $c = &transchar ($encodename, ($c1 << 8) | $c2);
+		$c = 0x25a1 if $c == 0;
+		push (@outtext, $c);
+		$i += 2;
+		
+	    } else {
+		# error
+		print STDERR "gb: ERROR missing second half of GB character\n";
+		$i++;
+	    }
+	    
+	} else {
+	    # normal ascii character
+	    push (@outtext, $c1) if ($c1 < 0x80);
+	    $i++;
+	}
+    }
+    
+    return \@outtext;
+}
+
+
+# unicode2gb uses the GBK translation table
+sub unicode2gb {
+    generalunicode2gb ("GBK", @_);
+}
+
+# returns a gb string. Note that this will not translate
+# traditional forms of characters to their simplified forms
+# Any traditional characters in the unicode will not be translated
+sub generalunicode2gb {
+    my ($encoding, $intext) = @_;
+
+    # load the encoding (if it is not already loaded)
+    if (!&loadmapencoding ("unicode-$encoding")) {
+	print STDERR "gb: ERROR - could not load encoding $encoding\n";
+	return "";
+    }
+    
+    # translate the string
+    my ($num, $gbc);
+    my $outtext = "";
+    my $encodename = "unicode-$encoding";
+    foreach $num (@$intext) {
+	if ($num < 0x80) {
+	    # normal ascii character
+	    $outtext .= chr ($num);
+	} else {
+	    # gb character
+	    my $gbc = &transchar ($encodename, $num);
+	    $gbc = 0xa1f5 if $gbc == 0;
+	    $outtext .= chr ($gbc >> 8);
+	    $outtext .= chr ($gbc & 0xff);
+	}
+    }
+
+    return $outtext;
+}
+
+
+# It returns 1 if successful, 0 if unsuccessful
+sub loadmapencoding {
+    my ($encoding) = @_;
+    
+    # check to see if the encoding has already been loaded
+    return 1 if (defined $translations{$encoding});
+
+    my $filename = $encoding;
+    $filename =~ s/\-//;
+    $filename =~ s/unicode/u/i;
+    $filename =~ tr/A-Z/a-z/;
+    $filename .= ".ump"; # unicode map file
+
+    return 0 unless open (MAPFILE, "$ENV{'GSDLHOME'}/unicode/$filename");
+    binmode (MAPFILE); # f$#@!!! windows
+
+    $translations{$encoding} = [@array256];
+    my $block = $translations{$encoding};
+
+    my ($in,$i,$j);
+    while (read(MAPFILE, $in, 1) == 1) {
+	$i = unpack ("C", $in);
+	$block->[$i] = [@array256];
+	for ($j=0; $j<256 && read(MAPFILE, $in, 2)==2; $j++) {
+	    my ($n1, $n2) = unpack ("CC", $in);
+	    $block->[$i]->[$j] = ($n1*256) + $n2;
+	}
+    }
+
+    close (MAPFILE);
+}
+
+
+
+# loadencoding expects the mapfile to contain (at least) two
+# tab-seperated fields. The first field is the mapped value
+# and the second field is the unicode value.
+#
+# It returns 1 if successful, 0 if unsuccessful
+sub loadencoding {
+    my ($encoding, $mapfile) = @_;
+    
+    my $to = "$encoding-unicode";
+    my $from = "unicode-$encoding";
+
+    # check to see if the encoding has already been loaded
+    if (defined $translations{$to} && defined $translations{$from}) {
+	return 1;
+    }
+
+    return 0 unless open (MAPFILE, $mapfile);
+
+    my ($line, @line);
+    $translations{$to} = [@array256];
+    $translations{$from} = [@array256];
+    while (defined ($line = <MAPFILE>)) {
+	# remove comments
+	$line =~ s/\#.*$//;
+	next unless $line =~ /\S/;
+
+	# split the line into fields and do a few
+	# simple sanity checks
+	@line = split (/\t/, $line);
+	next unless (scalar(@line) >= 2 &&
+		     $line[0] =~ /^0x/ &&
+		     $line[1] =~ /^0x/);
+
+	my $gbc = hex($line[0]);
+	my $unic = hex($line[1]);
+
+	# gbk has already had the necessary most significant
+	# bits set (it is used in the encoding
+	$gbc = $gbc | 0x8080 unless ($encoding =~ /gbk/i);
+
+	&addchartrans ($translations{$to}, $gbc, $unic);
+	&addchartrans ($translations{$from}, $unic, $gbc);
+    }
+
+    close (MAPFILE);
+
+    return 1;
+}
+
+sub showfilled {
+    my ($block) = @_;
+    my $count = 0;
+    foreach $el (@$block) {
+	if (ref ($el) eq "ARRAY") {
+	    print "1";
+	    $count++;
+	} else {
+	    print "0";
+	}
+    }
+    print "\n";
+    print "total: $count\n";
+}
+
+
+# addchartrans adds one character translation to a translation block.
+# It also simplifies the translation block if possible.
+sub addchartrans {
+    my ($block, $from, $to) = @_;
+    my $i = 0;
+
+    my $high = ($from / 256) % 256;
+    my $low = $from % 256;
+
+    if (ref ($block->[$high]) ne "ARRAY") {
+	$block->[$high] = [@array256];
+    }
+    $block->[$high]->[$low] = $to;
+}
+
+
+sub transchar {
+    my ($encoding, $from) = @_;
+    my $high = ($from / 256) % 256;
+    my $low = $from % 256;
+
+    return 0 unless defined $translations{$encoding};
+
+    my $block = $translations{$encoding};
+
+    if (ref ($block->[$high]) ne "ARRAY") {
+	return 0;
+    }
+    return $block->[$high]->[$low];
+}
+
+
+1;
Index: /main/tags/2.25/gsdl/perllib/gflock.pm
===================================================================
--- /main/tags/2.25/gsdl/perllib/gflock.pm	(revision 21064)
+++ /main/tags/2.25/gsdl/perllib/gflock.pm	(revision 21064)
@@ -0,0 +1,54 @@
+###########################################################################
+#
+# gflock.pm - an attempt to use flock only on those platforms
+# on which it's supported (i.e. everything but Windows 95/98)
+#
+# A component of the Greenstone digital library software
+# from the New Zealand Digital Library Project at the 
+# University of Waikato, New Zealand.
+#
+# Copyright (C) 1999 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 gflock;
+
+use Fcntl ':flock';
+
+# returns true if successful (or if OS is a form of windows other than NT)
+sub lock {
+    my ($handle) = @_;
+
+    if ($ENV{'GSDLOS'} eq "windows" && !Win32::IsWinNT()) {
+	return 1;
+    } else {
+	return flock($handle, LOCK_EX);
+    }
+}
+
+# returns true if successful (or if OS is a form of windows other than NT)
+sub unlock {
+    my ($handle) = @_;
+
+    if ($ENV{'GSDLOS'} eq "windows" && !Win32::IsWinNT()) {
+	return 1;
+    } else {
+	return flock($handle, LOCK_UN);
+    }
+}
+
+1;
Index: /main/tags/2.25/gsdl/perllib/ghtml.pm
===================================================================
--- /main/tags/2.25/gsdl/perllib/ghtml.pm	(revision 21064)
+++ /main/tags/2.25/gsdl/perllib/ghtml.pm	(revision 21064)
@@ -0,0 +1,277 @@
+###########################################################################
+#
+# ghtml.pm -- this used to be called html.pm but it clashed
+# with the existing html module under windows
+#
+# A component of the Greenstone digital library software
+# from the New Zealand Digital Library Project at the 
+# University of Waikato, New Zealand.
+#
+# Copyright (C) 1999 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 ghtml;
+
+# htmlsafe(TEXT)
+# 
+# Converts SGML meta characters in TEXT to entity references.
+# 
+sub htmlsafe
+{
+    $_[0] =~ s/&/&amp;/osg;
+    $_[0] =~ s/</&lt;/osg;
+    $_[0] =~ s/>/&gt;/osg;
+    $_[0] =~ s/\"/&quot;/osg;
+}
+
+# urlsafe(TEXT)
+# 
+# Converts characters not allowed in a URL to their hex representation.
+# 
+sub urlsafe
+{
+    $_[0] =~ s/[\x09\x20\x22\x3c\x3e\x5b\x5c\x5d\x5e\x60\x7b\x7c\x7d\x7e\?\=\&\+_\/]/sprintf("%%%2x", ord($&))/gse;
+}
+
+# dmsafe
+#
+# Converts characters which could make display.pl or html crack to their entity references.
+# Don't use this on dm macros as they will no longer be recognisable by dm (which
+# by the way, is the whole idea).
+# -- Rodger 12/1/98
+sub dmsafe {
+    my ($s) = $_[0];
+    $s =~ s/&/&amp;/osg; # for html
+    $s =~ s/</&lt;/osg;  # for html
+    $s =~ s/>/&gt;/osg;  # for html
+    $s =~ s/\_/&#095;/osg; # for dm (we have a convention of starting macros with _
+    $s =~ s/\"/&quot;/osg; # for html (don't want to be interpreted as a quote)
+    $s =~ s/\{/&#123;/osg; # for dm blocks
+    $s =~ s/\}/&#125;/osg; # for dm blocks
+    $s =~ s/\\/&#092;/osg; # for dm (dm removes naturally occurring backquotes)
+    return $s;
+}
+
+
+# named entry to the standard html font
+%charnetosf = ("Agrave"=> "192",  "Aacute"=> "193",  "Acirc" => "194",  "Atilde"=> "195",
+	       "Auml"  => "196",  "Aring" => "197",  "AElig" => "198",  "Ccedil"=> "199",
+	       "Egrave"=> "200",  "Eacute"=> "201",  "Ecirc" => "202",  "Euml"  => "203",
+	       "Igrave"=> "204",  "Iacute"=> "205",  "Icirc" => "206",  "Iuml"  => "207",
+	       "ETH"   => "208",  "Ntilde"=> "209",  "Ograve"=> "210",  "Oacute"=> "211",
+	       "Ocirc" => "212",  "Otilde"=> "213",  "Ouml"  => "214",  
+	       "Oslash"=> "216",  "Ugrave"=> "217",  "Uacute"=> "218",  "Ucirc" => "219",
+	       "Uuml"  => "220",  "Yacute"=> "221",  "THORN" => "222",  "szlig" => "223",
+	       "agrave"=> "224",  "aacute"=> "225",  "acirc" => "226",  "atilde"=> "227",
+	       "auml"  => "228",  "aring" => "229",  "aelig" => "230",  "ccedil"=> "231",
+	       "egrave"=> "232",  "eacute"=> "233",  "ecirc" => "234",  "euml"  => "235",
+	       "igrave"=> "236",  "iacute"=> "237",  "icirc" => "238",  "iuml"  => "239",
+	       "eth"   => "240",  "ntidle"=> "241",  "ograve"=> "242",  "oacute"=> "243",
+	       "ocirc" => "244",  "otilde"=> "245",  "ouml"  => "246",  
+	       "oslash"=> "248",  "ugrave"=> "249",  "uacute"=> "250",  "ucirc" => "251",
+	       "uuml"  => "252",  "yacute"=> "253",  "thorn" => "254",  "yuml"  => "255");
+
+%symnetosf = ("quot"  => "34",   "amp"   => "38",   "lt"    => "60",   "gt"    => "62",
+	      "nbsp"  => "160",  "iexcl" => "161",  "cent"  => "162",  "pound" => "163",
+	      "curren"=> "164",  "yen"   => "165",  "brvbar"=> "166",  "sect"  => "167",
+	      "uml"   => "168",  "copy"  => "169",  "ordf"  => "170",  "laquo" => "171",
+	      "not"   => "172",  "shy"   => "173",  "reg"   => "174",  "macr"  => "175",
+	      "deg"   => "176",  "plusmn"=> "177",  "sup2"  => "178",  "sup3"  => "179",
+	      "acute" => "180",  "micro" => "181",  "para"  => "182",  "middot"=> "183",
+	      "cedil" => "184",  "sup1"  => "185",  "ordm"  => "186",  "raquo" => "187",
+	      "frac14"=> "188",  "frac12"=> "189",  "frac34"=> "190",  "iquest"=> "191",
+	      "times" => "215",  "divide"=> "247");
+
+
+
+# standard font to plain text
+%sftotxt = ("32"  => " ",  "33"  => "!",  "34"  => "\"",  "35"  => "\#",  "36"  => "\$",
+	    "37"  => "\%", "38"  => "&",  "39"  => "'",   "40"  => "(",   "41"  => ")",
+	    "42"  => "*",  "43"  => "+",  "44"  => ",",   "45"  => "-",   "46"  => ".",
+	    "47"  => "/",  "48"  => "0",  "49"  => "1",   "50"  => "2",   "51"  => "3",
+	    "52"  => "4",  "53"  => "5",  "54"  => "6",   "55"  => "7",   "56"  => "8",
+	    "57"  => "9",  "58"  => ":",  "59"  => ";",   "60"  => "<",   "61"  => "=",
+	    "62"  => ">",  "63"  => "?",  "64"  => "\@",  "65"  => "A",   "66"  => "B",
+	    "57"  => "9",  "58"  => ":",  "59"  => ";",   "61"  => "=",
+	    "63"  => "?",  "64"  => "\@", "65"  => "A",  "66"  => "B",
+	    "67"  => "C",  "68"  => "D",  "69"  => "E",   "70"  => "F",   "71"  => "G",
+	    "72"  => "H",  "73"  => "I",  "74"  => "J",   "75"  => "K",   "76"  => "L",
+	    "77"  => "M",  "78"  => "N",  "79"  => "O",   "80"  => "P",   "81"  => "Q",
+	    "82"  => "R",  "83"  => "S",  "84"  => "T",   "85"  => "U",   "86"  => "V",
+	    "87"  => "W",  "88"  => "X",  "89"  => "Y",   "90"  => "Z",   "91"  => "[",
+	    "92"  => "\\", "93"  => "]",  "94"  => "^",   "95"  => "_",   "96"  => "`",
+	    "97"  => "a",  "98"  => "b",  "99"  => "c",   "100" => "d",   "101" => "e",
+	    "102" => "f",  "103" => "g",  "104" => "h",   "105" => "i",   "106" => "j",
+	    "107" => "k",  "108" => "l",  "109" => "m",   "110" => "n",   "111" => "o",
+	    "112" => "p",  "113" => "q",  "114" => "r",   "115" => "s",   "116" => "t",
+	    "117" => "u",  "118" => "v",  "119" => "w",   "120" => "x",   "121" => "y",
+	    "122" => "z",  "123" => "{",  "124" => "|",   "125" => "}",   "126" => "~",
+	    "130" => ",",  "131" => "f",  "132" => "\"",   "133" => "...", "139" => "<",
+	    "140" => "OE", "145" => "'",  "146" => "'",   "147" => "\"",   "148" => "\"",
+	    "149" => "o",  "150" => "--", "151" => "-",   "152" => "~",   "153" => "TM",
+	    "155" => ">",  "156" => "oe", "159" => "Y",   "160" => " ",   "178" => "2",
+	    "179" => "3",  "185" => "1",  "188" => "1/4", "189" => "1/2", "190" => "3/4",
+	    "192" => "A",  "193" => "A",  "194" => "A",   "195" => "A",   "196" => "A",
+	    "197" => "A",  "198" => "AE", "199" => "C",   "200" => "E",   "201" => "E",
+	    "202" => "E",  "203" => "E",  "204" => "I",   "205" => "I",   "206" => "I",
+	    "207" => "I",  "208" => "D",  "209" => "N",   "210" => "O",   "211" => "O",
+	    "212" => "O",  "213" => "O",  "214" => "O",   "215" => "*",   "216" => "O",
+	    "217" => "U",  "218" => "U",  "219" => "U",   "220" => "U",   "221" => "Y",
+	    "223" => "ss", "224" => "a",  "225" => "a",   "226" => "a",   "227" => "a",
+	    "228" => "a",  "229" => "a",  "230" => "ae",  "231" => "c",   "232" => "e",
+	    "233" => "e",  "234" => "e",  "235" => "e",   "236" => "i",   "237" => "i",
+	    "238" => "i",  "239" => "i",  "241" => "n",   "242" => "o",   "243" => "o",
+	    "244" => "o",  "245" => "o",  "246" => "o",   "247" => "/",   "248" => "o",
+	    "249" => "u",  "250" => "u",  "251" => "u",   "252" => "u",   "253" => "y",
+	    "255" => "y",  "8218" => ",");
+
+
+# returns the character in the standard html font. It assumes that the
+# & and ; have been stripped off the string.
+sub getcharequiv {
+    my ($entity, $convertsymbols) = @_;
+
+    # replace &#8218 with comma (",")
+    $entity =~ s/8218/044/;
+
+    # a numeric entity
+    if ($entity =~ /^\#0*(\d+)/) {
+	return pack("c", $1);
+    }
+    
+    # a named character entity
+    if (defined $charnetosf{$entity}) {
+	return pack("c", $charnetosf{$entity});
+    }
+
+    # a named symbol entity
+    if ($convertsymbols && defined $symnetosf{$entity}) {
+	return pack("c", $symnetosf{$entity});
+    }
+
+    return "&$entity;"; # unknown character
+}
+
+# convert character entities from named equivalents to html font
+sub convertcharentities {
+    # args: the text that you want to convert
+
+    $_[0] =~ s/&([^;]+);/&getcharequiv($1,0)/gse;
+}
+
+# convert any entities from named equivalents to html font
+sub convertallentities {
+    # args: the text that you want to convert
+
+    $_[0] =~ s/&([^;]+);/&getcharequiv($1,1)/gse;
+}
+
+sub html2txt {
+    # args: the text that you want converted to ascii, 
+    # and whether to strip out sgml tags
+
+    # strip out sgml tags if needed
+    $_[0] =~ s/<[^>]>//g if $_[1];
+
+    # convert the char entities to the standard html font
+    &convertcharentities($_[0]); 
+    
+    # convert the html character set to a plain ascii character set
+    my $pos = 0;
+    while ($pos < length($_[0])) {
+	my $charnum = ord(substr($_[0], $pos, 1));
+	if ($charnum >= 32) { # only convert characters above #32
+	    my $replacechars = " ";
+	    $replacechars = $sftotxt{$charnum} if defined $sftotxt{$charnum};
+	    substr($_[0], $pos, 1) = $replacechars;
+	    $pos += length ($replacechars);
+
+	} else {
+	    $pos ++;
+	}
+    }
+}  
+
+
+sub guess_mime_type {
+    my ($filename) = @_;
+
+    my ($fileext) = $filename =~ /\.(\w+)$/;
+    return "unknown" unless defined $fileext;
+
+    my %mime_type = ("ai"=>"application/postscript", "aif"=>"audio/x-aiff", 
+		     "aifc"=>"audio/x-aiff", "aiff"=>"audio/x-aiff", 
+		     "au"=>"audio/basic", "avi"=>"video/x-msvideo",
+		     "bcpio"=>"application/x-bcpio", "bin"=>"application/octet-stream", 
+		     "cdf"=>"application/x-netcdf", "class"=>"application/octet-stream", 
+		     "cpio"=>"application/x-cpio", "cpt"=>"application/mac-compactpro",
+		     "csh"=>"application/x-csh", "dcr"=>"application/x-director", 
+		     "dir"=>"application/x-director", "dms"=>"application/octet-stream", 
+		     "doc"=>"application/msword", "dvi"=>"application/x-dvi",
+		     "dxr"=>"application/x-director", "eps"=>"application/postscript", 
+		     "etx"=>"text/x-setext",
+		     "exe"=>"application/octet-stream", "gif"=>"image/gif",
+		     "gtar"=>"application/x-gtar", "hdf"=>"application/x-hdf",
+		     "hqx"=>"application/mac-binhex40", "htm"=>"text/html",
+		     "html"=>"text/html", "ice"=>"x-conference/x-cooltalk",
+		     "ief"=>"image/ief", "jpe"=>"image/jpeg",
+		     "jpeg"=>"image/jpeg", "jpg"=>"image/jpeg",
+		     "kar"=>"audio/midi", "latex"=>"application/x-latex",
+		     "lha"=>"application/octet-stream", "lzh"=>"application/octet-stream",
+		     "man"=>"application/x-troff-man", "mcf"=>"image/vasa",
+		     "me"=>"application/x-troff-me", "mid"=>"audio/midi",
+		     "midi"=>"audio/midi", "mif"=>"application/x-mif",
+		     "mov"=>"video/quicktime", "movie"=>"video/x-sgi-movie",
+		     "mp2"=>"audio/mpeg", "mpe"=>"video/mpeg",
+		     "mpeg"=>"video/mpeg", "mpg"=>"video/mpeg",
+		     "mpga"=>"audio/mpeg", "ms"=>"application/x-troff-ms",
+		     "nc"=>"application/x-netcdf", "oda"=>"application/oda",
+		     "pbm"=>"image/x-portable-bitmap", "pdb"=>"chemical/x-pdb",
+		     "pdf"=>"application/pdf", "pgm"=>"image/x-portable-graymap",
+		     "png"=>"image/png", "pnm"=>"image/x-portable-anymap",
+		     "ppm"=>"image/x-portable-pixmap", "ppt"=>"application/powerpoint",
+		     "ps"=>"application/postscript", "qt"=>"video/quicktime",
+		     "ra"=>"audio/x-realaudio", "ram"=>"audio/x-pn-realaudio",
+		     "ras"=>"image/x-cmu-raster", "rgb"=>"image/x-rgb",
+		     "roff"=>"application/x-troff", "rpm"=>"audio/x-pn-realaudio-plugin",
+		     "rtf"=>"application/rtf", "rtx"=>"text/richtext",
+		     "sgm"=>"text/x-sgml", "sgml"=>"text/x-sgml",
+		     "sh"=>"application/x-sh", "shar"=>"application/x-shar",
+		     "sit"=>"application/x-stuffit", "skd"=>"application/x-koan",
+		     "skm"=>"application/x-koan", "skp"=>"application/x-koan",
+		     "skt"=>"application/x-koan", "snd"=>"audio/basic",
+		     "src"=>"application/x-wais-source", "sv4cpio"=>"application/x-sv4cpio",
+		     "sv4crc"=>"application/x-sv4crc", "t"=>"application/x-troff",
+		     "tar"=>"application/x-tar", "tcl"=>"application/x-tcl",
+		     "tex"=>"application/x-tex", "texi"=>"application/x-texinfo",
+		     "texinfo"=>"application/x-texinfo", "tif"=>"image/tiff",
+		     "tiff"=>"image/tiff", "tr"=>"application/x-troff",
+		     "tsv"=>"text/tab-separated-values", "txt"=>"text/plain",
+		     "ustar"=>"application/x-ustar", "vcd"=>"application/x-cdlink",
+		     "vrml"=>"x-world/x-vrml", "wav"=>"audio/x-wav",
+		     "wrl"=>"x-world/x-vrml", "xbm"=>"image/x-xbitmap",
+		     "xpm"=>"image/x-xpixmap", "xwd"=>"image/x-xwindowdump",
+		     "xyz"=>"chemical/x-pdb", "zip"=>"application/zip");
+
+    return $mime_type{$fileext} if (defined $mime_type{$fileext});
+
+    return "unknown";
+}
+
+
+1;
Index: /main/tags/2.25/gsdl/perllib/lang.pm
===================================================================
--- /main/tags/2.25/gsdl/perllib/lang.pm	(revision 21064)
+++ /main/tags/2.25/gsdl/perllib/lang.pm	(revision 21064)
@@ -0,0 +1,201 @@
+###########################################################################
+#
+# lang.pm --
+# A component of the Greenstone digital library software
+# from the New Zealand Digital Library Project at the 
+# University of Waikato, New Zealand.
+#
+# Copyright (C) 1999 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.
+#
+###########################################################################
+
+# this module translates language descriptions to and from
+# the ISO 639 standard
+
+package lang;
+
+@trans = (["ab", "Abkhazian"],      ["om", "Afan Oromo"],
+	  ["om", "Oromo"],          ["aa", "Afar"],
+	  ["af", "Afrikaans"],      ["sq", "Albanian"],
+	  ["am", "Amharic"],        ["ar", "Arabic"],
+	  ["hy", "Armenian"],       ["as", "Assamese"],
+	  ["ay", "Aymara"],         ["az", "Azerbaijani"],
+
+	  ["ba", "Bashkir"],        ["eu", "Basque"],
+	  ["bn", "Bengali"],        ["bn", "Bangla"],
+	  ["dz", "Bhutani"],        ["bh", "Bihari"],
+	  ["bi", "Bislama"],        ["br", "Breton"],
+	  ["bg", "Bulgarian"],      ["my", "Burmese"],
+	  ["be", "Byelorussian"],
+
+	  ["km", "Cambodian"],      ["ca", "Catalan"],
+	  ["zh", "Chinese"],        ["co", "Corsican"],
+	  ["hr", "Croatian"],       ["cs", "Czech"],
+
+	  ["da", "Danish"],         ["nl", "Dutch"],
+
+	  ["en", "English"],        ["eo", "Esperanto"],
+	  ["et", "Estonian"],       ["fo", "Faroese"],
+	  ["fj", "Fijian"],         ["fi", "Finnish"],
+	  ["fr", "French"],         ["fy", "Frisian"],
+
+	  ["gl", "Galician"],       ["ka", "Georgian"],
+	  ["de", "German"],         ["el", "Greek"],
+	  ["kl", "Greenlandic"],    ["gn", "Guarani"],
+	  ["gu", "Gujarati"],
+
+	  ["ha", "Hausa"],          ["iw", "Hebrew"],
+	  ["hi", "Hindi"],          ["hu", "Hungarian"],
+
+	  ["is", "Icelandic"],      ["in", "Indonesian"],
+	  ["ia", "Interlingua"],    ["ie", "Interlingue"],
+	  ["ik", "Inupiak"],        ["ga", "Irish"],
+	  ["it", "Italian"],
+
+	  ["ja", "Japanese"],       ["jv", "Javanese"],
+
+	  ["kn", "Kannada"],        ["ks", "Kashmiri"],
+	  ["kk", "Kazakh"],         ["rw", "Kinyarwanda"],
+	  ["ky", "Kirghiz"],        ["rn", "Kirundi"],
+	  ["ko", "Korean"],         ["ku", "Kurdish"],
+
+	  ["lo", "Laothian"],       ["la", "Latin"],
+	  ["lv", "Latvian"],        ["lv", "Lettish"],
+	  ["ln", "Lingala"],        ["lt", "Lithuanian"],
+
+	  ["mk", "Macedonian"],     ["mg", "Malagasy"],
+	  ["ms", "Malay"],          ["ml", "Malayalam"],
+	  ["mt", "Maltese"],        ["mi", "Maori"],
+	  ["mr", "Marathi"],        ["mo", "Moldavian"],
+	  ["mn", "Mongolian"],
+
+	  ["na", "Nauru"],          ["ne", "Nepali"],
+	  ["no", "Norwegian"],
+
+	  ["oc", "Occitan"],        ["or", "Oriya"],
+
+	  ["ps", "Pashto"],         ["ps", "Pushto"],
+	  ["fa", "Persian"],        ["pl", "Polish"],
+	  ["pt", "Portuguese"],     ["pa", "Punjabi"],
+
+	  ["qu", "Quechua"],
+
+	  ["rm", "Rhaeto-Romance"], ["ro", "Romanian"],
+	  ["ru", "Russian"],
+
+	  ["sm", "Samoan"],         ["sg", "Sangho"],
+	  ["sa", "Sanskrit"],       ["gd", "Scots Gaelic"],
+	  ["sr", "Serbian"],        ["sh", "Serbo-Croatian"],
+	  ["st", "Sesotho"],        ["tn", "Setswana"],
+	  ["sn", "Shona"],          ["sd", "Sindhi"],
+	  ["si", "Singhalese"],     ["ss", "Siswati"],
+	  ["sk", "Slovak"],         ["sl", "Slovenian"],
+	  ["so", "Somali"],         ["es", "Spanish"],
+	  ["su", "Sundanese"],      ["sw", "Swahili"],
+	  ["sv", "Swedish"],
+
+	  ["tl", "Tagalog"],        ["tg", "Tajik"],
+	  ["ta", "Tamil"],          ["tt", "Tatar"],
+	  ["te", "Telugu"],         ["th", "Thai"],
+	  ["bo", "Tibetan"],        ["ti", "Tigrinya"],
+	  ["to", "Tonga"],          ["ts", "Tsonga"],
+	  ["tr", "Turkish"],        ["tk", "Turkmen"],
+	  ["tw", "Twi"],
+
+	  ["uk", "Ukrainian"],      ["ur", "Urdu"],
+	  ["uz", "Uzbek"],
+
+	  ["vi", "Vietnamese"],     ["vo", "Volapuk"],
+
+	  ["cy", "Welsh"],          ["wo", "Wolof"],
+
+	  ["xh", "Xhosa"],
+
+	  ["ji", "Yiddish"],        ["yo", "Yoruba"],
+
+	  ["zu", "Zulu"]);
+
+
+sub one_english_to_iso639 {
+    my ($english) = @_;
+    my $iso639 = "";
+
+    foreach $lang (@trans) {
+	my $code = $lang->[0];
+	my $enname = $lang->[1];
+	if ($english =~ /\s*($code|$enname)\s*$/i) {
+	    # found the language
+	    $iso639 = $code;
+	    last;
+
+	}
+    }
+
+    return $iso639;
+}
+
+
+sub english_to_iso639 {
+    my ($englishlist) = @_;
+    my ($english);
+
+    my @englishlist = split (",", $englishlist);
+    my @iso639list = ();
+
+    foreach $english (@englishlist) {
+	push (@iso639list, &one_english_to_iso639($english));
+    }
+
+    return join (",", @iso639list);
+}
+
+
+sub one_iso639_to_english {
+    my ($iso639) = @_;
+    my $english = "";
+
+    foreach $lang (@trans) {
+	my $code = $lang->[0];
+	my $enname = $lang->[1];
+	if ($iso639 =~ /\s*($code|$enname)\s*$/i) {
+	    # found the language
+	    $english = $enname;
+	    last;
+
+	}
+    }
+
+    return $enname;
+}
+
+
+sub iso639_to_english {
+    my ($iso639list) = @_;
+    my ($iso639);
+
+    my @iso639list = split (",", $iso639list);
+    my @englishlist = ();
+
+    foreach $iso639 (@iso639list) {
+	push (@englishlist, &one_iso639_to_english($iso639));
+    }
+
+    return join (",", @englishlist);
+}
+
+
+1;
Index: /main/tags/2.25/gsdl/perllib/mgbuilder.pm
===================================================================
--- /main/tags/2.25/gsdl/perllib/mgbuilder.pm	(revision 21064)
+++ /main/tags/2.25/gsdl/perllib/mgbuilder.pm	(revision 21064)
@@ -0,0 +1,750 @@
+###########################################################################
+#
+# mgbuilder.pm -- MGBuilder object
+# A component of the Greenstone digital library software
+# from the New Zealand Digital Library Project at the 
+# University of Waikato, New Zealand.
+#
+# Copyright (C) 1999 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 mgbuilder;
+
+use classify;
+use cfgread;
+use colcfg;
+use plugin;
+use util;
+use FileHandle;
+
+BEGIN {
+    # set autoflush on for STDERR and STDOUT so that mg
+    # doesn't get out of sync with plugins
+    STDOUT->autoflush(1);
+    STDERR->autoflush(1);
+}
+
+END {
+    STDOUT->autoflush(0);
+    STDERR->autoflush(0);
+}
+
+$maxdocsize = 12000;
+
+%wanted_index_files = ('td'=>1,
+		       't'=>1,
+		       'idb'=>1,
+		       'ib1'=>1,
+		       'ib2'=>1,
+		       'ib3'=>1,
+		       'i'=>1,
+		       'ip'=>1,
+		       'tiw'=>1,
+		       'wa'=>1);
+
+
+sub new {
+    my ($class, $collection, $source_dir, $build_dir, $verbosity, 
+	$maxdocs, $debug, $keepold, $allclassifications) = @_;
+
+    # create an mgbuilder object
+    my $self = bless {'collection'=>$collection,
+		      'source_dir'=>$source_dir,
+		      'build_dir'=>$build_dir,
+		      'verbosity'=>$verbosity,
+		      'maxdocs'=>$maxdocs,
+		      'debug'=>$debug,
+		      'keepold'=>$keepold,
+		      'allclassifications'=>$allclassifications,
+		      'notbuilt'=>[]    # indexes not built
+		      }, $class;
+
+
+    # read in the collection configuration file
+    my $colcfgname = "$ENV{'GSDLCOLLECTDIR'}/etc/collect.cfg";
+    if (!-e $colcfgname) {
+	die "mgbuilder::new - couldn't find collect.cfg for collection $collection\n";
+    }
+    $self->{'collect_cfg'} = &colcfg::read_collect_cfg ($colcfgname);
+
+    # sort out subcollection indexes
+    if (defined $self->{'collect_cfg'}->{'indexsubcollections'}) {
+	my $indexes = $self->{'collect_cfg'}->{'indexes'};
+	$self->{'collect_cfg'}->{'indexes'} = [];
+	foreach $subcollection (@{$self->{'collect_cfg'}->{'indexsubcollections'}}) {
+	    foreach $index (@$indexes) {
+		push (@{$self->{'collect_cfg'}->{'indexes'}}, "$index:$subcollection");
+	    }
+	}
+    }
+
+    # sort out language subindexes
+    if (defined $self->{'collect_cfg'}->{'languages'}) {
+	my $indexes = $self->{'collect_cfg'}->{'indexes'};
+	$self->{'collect_cfg'}->{'indexes'} = [];
+	foreach $language (@{$self->{'collect_cfg'}->{'languages'}}) {
+	    foreach $index (@$indexes) {
+		push (@{$self->{'collect_cfg'}->{'indexes'}}, "$index:$language");
+	    }
+	}
+    }
+
+    # get the list of plugins for this collection
+    my $plugins = [];
+    if (defined $self->{'collect_cfg'}->{'plugin'}) {
+	$plugins = $self->{'collect_cfg'}->{'plugin'};
+    }
+    
+    # load all the plugins
+    $self->{'pluginfo'} = &plugin::load_plugins ($plugins, $verbosity);
+    if (scalar(@{$self->{'pluginfo'}}) == 0) {
+	print STDERR "No plugins were loaded.\n";
+	die "\n";
+    }
+
+    # get the list of classifiers for this collection
+    my $classifiers = [];
+    if (defined $self->{'collect_cfg'}->{'classify'}) {
+	$classifiers = $self->{'collect_cfg'}->{'classify'};
+    }
+    
+    # load all the classifiers
+    $self->{'classifiers'} = &classify::load_classifiers ($classifiers);
+
+    # load up any dontgdbm fields
+    $self->{'dontgdbm'} = {};
+    if (defined ($self->{'collect_cfg'}->{'dontgdbm'})) {
+	foreach $dg (@{$self->{'collect_cfg'}->{'dontgdbm'}}) {
+	    $self->{'dontgdbm'}->{$dg} = 1;
+	}
+    }
+
+    # load up the document processor for building
+    # if a buildproc class has been created for this collection, use it
+    # otherwise, use the mg buildproc
+    my ($buildprocdir, $buildproctype);
+    if (-e "$ENV{'GSDLCOLLECTDIR'}/perllib/${collection}buildproc.pm") {
+	$buildprocdir = "$ENV{'GSDLCOLLECTDIR'}/perllib";
+	$buildproctype = "${collection}buildproc";
+    } else {
+	$buildprocdir = "$ENV{'GSDLHOME'}/perllib";
+	$buildproctype = "mgbuildproc";
+    }
+    require "$buildprocdir/$buildproctype.pm";
+
+    eval("\$self->{'buildproc'} = new $buildproctype(\$collection, " .
+	 "\$source_dir, \$build_dir, \$verbosity)");
+    die "$@" if $@;
+
+    return $self;
+}
+
+sub init {
+    my $self = shift (@_);
+
+    if (!$self->{'debug'} && !$self->{'keepold'}) {
+	# remove any old builds
+	&util::rm_r($self->{'build_dir'});
+	&util::mk_all_dir($self->{'build_dir'});
+        
+	# make the text directory
+	my $textdir = "$self->{'build_dir'}/text";
+	&util::mk_all_dir($textdir);
+    }
+}
+
+sub compress_text {
+    my $self = shift (@_);
+    my ($textindex) = @_;
+    my $exedir = "$ENV{'GSDLHOME'}/bin/$ENV{'GSDLOS'}";
+    my $exe = &util::get_os_exe ();
+    my $mg_passes_exe = &util::filename_cat($exedir, "mg_passes$exe");
+    my $mg_compression_dict_exe = &util::filename_cat($exedir, "mg_compression_dict$exe");
+
+    &util::mk_all_dir (&util::filename_cat($self->{'build_dir'}, "text"));
+    my $basefilename = "text/$self->{'collection'}";
+    my $fulltextprefix = &util::filename_cat ($self->{'build_dir'}, $basefilename);
+
+    my $osextra = "";
+    if ($ENV{'GSDLOS'} =~ /^windows$/i) {
+	$fulltextprefix =~ s/\//\\/g;
+    } else {
+	$osextra = " -d /";
+    }
+
+    print STDERR "\n*** creating the compressed text\n" if ($self->{'verbosity'} >= 1);
+
+    # collect the statistics for the text
+    # -b $maxdocsize sets the maximum document size to be 12 meg
+    print STDERR "\n    collecting text statistics\n"  if ($self->{'verbosity'} >= 1);
+
+    my ($handle);
+    if ($self->{'debug'}) {
+	$handle = STDOUT;
+    } else {
+	if (!-e "$mg_passes_exe" || 
+	    !open (PIPEOUT, "| $mg_passes_exe -f $fulltextprefix -b $maxdocsize -T1 $osextra")) {
+	    die "mgbuilder::compress_text - couldn't run $mg_passes_exe\n";
+	}
+	$handle = mgbuilder::PIPEOUT;
+    }
+
+    $self->{'buildproc'}->set_output_handle ($handle);
+    $self->{'buildproc'}->set_mode ('text');
+    $self->{'buildproc'}->set_index ($textindex);
+    $self->{'buildproc'}->set_indexing_text (0);
+    $self->{'buildproc'}->reset();
+    &plugin::begin($self->{'pluginfo'}, $self->{'source_dir'}, 
+		   $self->{'buildproc'}, $self->{'maxdocs'});
+    &plugin::read ($self->{'pluginfo'}, $self->{'source_dir'}, 
+		   "", {}, $self->{'buildproc'}, $self->{'maxdocs'});
+    &plugin::end($self->{'pluginfo'});
+
+    close ($handle) unless $self->{'debug'};
+
+    $self->print_stats();
+
+    # create the compression dictionary
+    # the compression dictionary is built by assuming the stats are from a seed
+    # dictionary (-S), if a novel word is encountered it is spelled out (-H),
+    # and the resulting dictionary must be less than 5 meg with the most frequent
+    # words being put into the dictionary first (-2 -k 5120)
+    if (!$self->{'debug'}) {
+	print STDERR "\n    creating the compression dictionary\n"  if ($self->{'verbosity'} >= 1);
+	if (!-e "$mg_compression_dict_exe") {
+	    die "mgbuilder::compress_text - couldn't run $mg_compression_dict_exe\n";
+	}
+	system ("$mg_compression_dict_exe -f $fulltextprefix -S -H -2 -k 5120 $osextra");
+
+	# -b $maxdocsize sets the maximum document size to be 12 meg
+	if (!-e "$mg_passes_exe" || 
+	    !open ($handle, "| $mg_passes_exe -f $fulltextprefix -b $maxdocsize -T2 $osextra")) {
+	    die "mgbuilder::compress_text - couldn't run $mg_passes_exe\n";
+	}
+    }
+
+    $self->{'buildproc'}->reset();
+    # compress the text
+    print STDERR "\n    compressing the text\n"  if ($self->{'verbosity'} >= 1);
+    &plugin::read ($self->{'pluginfo'}, $self->{'source_dir'}, 
+		   "", {}, $self->{'buildproc'}, $self->{'maxdocs'});
+    close ($handle) unless $self->{'debug'};
+
+    $self->print_stats();
+}
+
+sub want_built {
+    my $self = shift (@_);
+    my ($index) = @_;
+
+    if (defined ($self->{'collect_cfg'}->{'dontbuild'})) {
+	foreach $checkstr (@{$self->{'collect_cfg'}->{'dontbuild'}}) {
+	    if ($index =~ /^$checkstr$/) {
+		push (@{$self->{'notbuilt'}}, $self->{'index_mapping'}->{$index});
+		return 0;
+	    }
+	}
+    }
+
+    return 1;
+}
+
+sub build_indexes {
+    my $self = shift (@_);
+    my ($indexname) = @_;
+
+    my $indexes = [];
+    if (defined $indexname && $indexname =~ /\w/) {
+	push @$indexes, $indexname;
+    } else {
+	$indexes = $self->{'collect_cfg'}->{'indexes'};
+    }
+
+    # create the mapping between the index descriptions 
+    # and their directory names
+    $self->{'index_mapping'} = $self->create_index_mapping ($indexes);
+
+    # build each of the indexes
+    foreach $index (@$indexes) {
+	if ($self->want_built($index)) {
+	    print STDERR "\n*** building index $index in subdirectory " . 
+		"$self->{'index_mapping'}->{$index}\n" if ($self->{'verbosity'} >= 1);
+	    $self->build_index($index);
+	} else {
+	    print STDERR "\n*** ignoring index $index\n" if ($self->{'verbosity'} >= 1);
+	}
+    }
+}
+
+# creates directory names for each of the index descriptions
+sub create_index_mapping {
+    my $self = shift (@_);
+    my ($indexes) = @_;
+
+    my %mapping = ();
+    $mapping{'indexmaporder'} = [];
+    $mapping{'subcollectionmaporder'} = [];
+    $mapping{'languagemaporder'} = [];
+    
+    # dirnames is used to check for collisions. Start this off
+    # with the manditory directory names
+    my %dirnames = ('text'=>'text',
+		    'extra'=>'extra');
+    my %pnames = ('index' => '', 'subcollection' => '', 'languages' => '');
+
+    foreach $index (@$indexes) {
+	my ($level, $gran, $subcollection, $languages) = split (":", $index);
+
+	# the directory name starts with the first character of the index level
+	my ($pindex) = $level =~ /^(.)/;
+
+	# next comes a processed version of the index
+	$pindex .= $self->process_field ($gran); 
+	$pindex = lc ($pindex);
+
+	# next comes a processed version of the subcollection if there is one.
+	my $psub = $self->process_field ($subcollection);
+	$psub = lc ($psub);
+
+	# next comes a processed version of the language if there is one.
+	my $plang = $self->process_field ($languages);
+	$plang = lc ($plang);
+
+	my $dirname = $pindex . $psub . $plang;
+
+	# check to be sure all index names are unique
+	while (defined ($dirnames{$dirname})) {
+	    $dirname = $self->make_unique (\%pnames, $index, \$pindex, \$psub, \$plang);
+	}
+
+	# store the mapping orders as well as the maps
+	if (!defined $mapping{'indexmap'}{"$level:$gran"}) {
+	    $mapping{'indexmap'}{"$level:$gran"} = $pindex;
+	    push (@{$mapping{'indexmaporder'}}, "$level:$gran");
+	}
+	if ($psub =~ /\w/ && !defined ($mapping{'subcollectionmap'}{$subcollection})) {
+	    $mapping{'subcollectionmap'}{$subcollection} = $psub;
+	    push (@{$mapping{'subcollectionmaporder'}}, $subcollection);
+	}
+	if ($plang =~ /\w/ && !defined ($mapping{'languagemap'}{$languages})) {
+	    $mapping{'languagemap'}{$languages} = $plang;
+	    push (@{$mapping{'languagemaporder'}}, $language);
+	}
+	$mapping{$index} = $dirname;
+	$dirnames{$dirname} = $index;
+	$pnames{'index'}{$pindex} = "$level:$gran";
+	$pnames{'subcollection'}{$psub} = $subcollection;
+	$pnames{'languages'}{$plang} = $languages;
+    }
+
+    return \%mapping;
+}
+
+# returns a processed version of a field.
+# if the field has only one component the processed
+# version will contain the first character and next consonant
+# of that componant - otherwise it will contain the first 
+# character of the first two components 
+sub process_field {
+    my $self = shift (@_);
+    my ($field) = @_;
+ 
+    return "" unless (defined ($field) && $field =~ /\w/);
+
+    my @components = split /,/, $field;
+    if (scalar @components >= 2) {
+	splice (@components, 2);
+	map {s/^(.).*$/$1/;} @components;
+	return join("", @components);
+    } else {
+	my ($a, $b) = $field =~ /^(.).*?([bcdfghjklmnpqrstvwxyz])/i;
+	($a, $b) = $field =~ /^(.)(.)/ unless defined $a && defined $b;
+	return "$a$b";
+    }
+}
+
+sub make_unique {
+    my $self = shift (@_);
+    my ($namehash, $index, $indexref, $subref, $langref) = @_;
+    my ($level, $gran, $subcollection, $languages) = split (":", $index);
+
+    if ($namehash->{'index'}->{$$indexref} ne "$level:$gran") {
+	$self->get_next_version ($indexref);
+    } elsif ($namehash->{'subcollection'}->{$$subref} ne $subcollection) {
+	$self->get_next_version ($subref);
+    } elsif ($namehash->{'languages'}->{$$langref} ne $languages) {
+	$self->get_next_version ($langref);
+    }
+    return "$$indexref$$subref$$langref";
+}	
+
+sub get_next_version {
+    my $self = shift (@_);
+    my ($nameref) = @_;
+
+    if ($$nameref =~ /(\d\d)$/) {
+	my $num = $1; $num ++;
+	$$nameref =~ s/\d\d$/$num/;
+    } elsif ($$nameref =~ /(\d)$/) {
+	my $num = $1;
+	if ($num == 9) {$$nameref =~ s/\d\d$/10/;}
+	else {$num ++; $$nameref =~ s/\d$/$num/;}
+    } else {
+	$$nameref =~ s/.$/0/;
+    }
+}
+
+sub build_index {
+    my $self = shift (@_);
+    my ($index) = @_;
+
+    # get the full index directory path and make sure it exists
+    my $indexdir = $self->{'index_mapping'}->{$index};
+    &util::mk_all_dir (&util::filename_cat($self->{'build_dir'}, $indexdir));
+    my $fullindexprefix = &util::filename_cat ($self->{'build_dir'}, $indexdir, 
+					       $self->{'collection'});
+    my $fulltextprefix = &util::filename_cat ($self->{'build_dir'}, "text", 
+					       $self->{'collection'});
+
+    # get any os specific stuff
+    my $exedir = "$ENV{'GSDLHOME'}/bin/$ENV{'GSDLOS'}";
+    my $exe = &util::get_os_exe ();
+    my $mg_passes_exe = &util::filename_cat($exedir, "mg_passes$exe");
+    my $mg_perf_hash_build_exe = 
+	&util::filename_cat($exedir, "mg_perf_hash_build$exe");
+    my $mg_weights_build_exe = 
+	&util::filename_cat ($exedir, "mg_weights_build$exe");
+    my $mg_invf_dict_exe = 
+	&util::filename_cat ($exedir, "mg_invf_dict$exe");
+    my $mg_stem_idx_exe =
+	&util::filename_cat ($exedir, "mg_stem_idx$exe");
+
+    my $osextra = "";
+    if ($ENV{'GSDLOS'} =~ /^windows$/i) {
+	$fullindexprefix =~ s/\//\\/g;
+    } else {
+	$osextra = " -d /";
+    }
+
+    # get the index level from the index description
+    # the index will be level 2 unless we are building a
+    # paragraph level index
+    my $index_level = 2;
+    $index_level = 3 if $index =~ /^paragraph/i;
+
+    # get the index expression if this index belongs
+    # to a subcollection
+    my $indexexparr = [];
+    my ($level, $fields, $subcollection) = split (":", $index);
+    my @subcollections = ();
+    @subcollections = split /,/, $subcollection if (defined $subcollection);
+
+    foreach $subcollection (@subcollections) {
+	if (defined ($self->{'collect_cfg'}->{'subcollection'}->{$subcollection})) {
+	    push (@$indexexparr, $self->{'collect_cfg'}->{'subcollection'}->{$subcollection});
+	} 
+    }
+    
+    # add expressions for languages if this index belongs to
+    # a language subcollection
+    foreach $language (@{$self->{'collect_cfg'}->{'languages'}}) {
+	if ($language =~ s/^\!//) {
+	    push (@$indexexparr, "!Language/$language/");
+	} else {
+	    push (@$indexexparr, "Language/$language/");
+	}
+    }
+
+    # Build index dictionary. Uses verbatim stem method
+    print STDERR "\n    creating index dictionary\n"  if ($self->{'verbosity'} >= 1);
+    my ($handle);
+    if ($self->{'debug'}) {
+	$handle = STDOUT;
+    } else {
+	if (!-e "$mg_passes_exe" || 
+	    !open (PIPEOUT, "| $mg_passes_exe -f $fullindexprefix -b $maxdocsize " .
+		   "-$index_level -m 32 -s 0 -G -t 10 -N1 $osextra")) {
+	    die "mgbuilder::build_index - couldn't run $mg_passes_exe\n";
+	}
+	$handle = mgbuilder::PIPEOUT;
+    }
+	
+    # set up the document processor
+    $self->{'buildproc'}->set_output_handle ($handle);
+    $self->{'buildproc'}->set_mode ('text');
+    $self->{'buildproc'}->set_index ($index, $indexexparr);
+    $self->{'buildproc'}->set_indexing_text (1);
+
+    $self->{'buildproc'}->reset();
+    &plugin::read ($self->{'pluginfo'}, $self->{'source_dir'}, 
+		   "", {}, $self->{'buildproc'}, $self->{'maxdocs'});
+    close ($handle) unless $self->{'debug'};
+
+    $self->print_stats();
+
+    if (!$self->{'debug'}) {
+	# create the perfect hash function
+	if (!-e "$mg_perf_hash_build_exe") {
+	    die "mgbuilder::build_index - couldn't run $mg_perf_hash_build_exe\n";
+	}
+	system ("$mg_perf_hash_build_exe -f $fullindexprefix $osextra");
+
+	if (!-e "$mg_passes_exe" || 
+	    !open ($handle, "| $mg_passes_exe -f $fullindexprefix -b $maxdocsize " .
+		   "-$index_level -c 3 -G -t 10 -N2 $osextra")) {
+	    die "mgbuilder::build_index - couldn't run $mg_passes_exe\n";
+	}
+    }
+    
+    # invert the text
+    print STDERR "\n    inverting the text\n"  if ($self->{'verbosity'} >= 1);
+
+    $self->{'buildproc'}->reset();
+    &plugin::read ($self->{'pluginfo'}, $self->{'source_dir'}, 
+		   "", {}, $self->{'buildproc'}, $self->{'maxdocs'});
+
+    $self->print_stats ();
+
+    if (!$self->{'debug'}) {
+
+	close ($handle);
+	
+	# create the weights file
+	print STDERR "\n    create the weights file\n"  if ($self->{'verbosity'} >= 1);
+	if (!-e "$mg_weights_build_exe") {
+	    die "mgbuilder::build_index - couldn't run $mg_weights_build_exe\n";
+	}
+	system ("$mg_weights_build_exe -f $fullindexprefix -t $fulltextprefix $osextra");
+
+	# create 'on-disk' stemmed dictionary
+	print STDERR "\n    creating 'on-disk' stemmed dictionary\n"  if ($self->{'verbosity'} >= 1);
+	if (!-e "$mg_invf_dict_exe") {
+	    die "mgbuilder::build_index - couldn't run $mg_invf_dict_exe\n";
+	}
+	system ("$mg_invf_dict_exe -f $fullindexprefix $osextra");
+
+
+	# creates stem index files for the various stemming methods
+	print STDERR "\n    creating stem indexes\n"  if ($self->{'verbosity'} >= 1);
+	if (!-e "$mg_stem_idx_exe") {
+	    die "mgbuilder::build_index - couldn't run $mg_stem_idx_exe\n";
+	}
+	system ("$mg_stem_idx_exe -b 4096 -s1 -f $fullindexprefix $osextra");
+	system ("$mg_stem_idx_exe -b 4096 -s2 -f $fullindexprefix $osextra");
+	system ("$mg_stem_idx_exe -b 4096 -s3 -f $fullindexprefix $osextra");
+
+    
+	# remove unwanted files
+	my $tmpdir = &util::filename_cat ($self->{'build_dir'}, $indexdir);
+	opendir (DIR, $tmpdir) || die
+	    "mgbuilder::build_index - couldn't read directory $tmpdir\n";
+	foreach $file (readdir(DIR)) {
+	    next if $file =~ /^\./;
+	    my ($suffix) = $file =~ /\.([^\.]+)$/;
+	    if (defined $suffix && !defined $wanted_index_files{$suffix}) {
+		# delete it!
+		print STDERR "deleting $file\n" if $self->{'verbosity'} > 2;
+		&util::rm (&util::filename_cat ($tmpdir, $file));
+	    }
+	}
+	closedir (DIR);
+    }
+}
+
+sub make_infodatabase {
+    my $self = shift (@_);
+    my $textdir = &util::filename_cat($self->{'build_dir'}, "text");
+    my $assocdir = &util::filename_cat($self->{'build_dir'}, "assoc");
+    &util::mk_all_dir ($textdir);
+    &util::mk_all_dir ($assocdir);
+
+    # get db name
+    my $dbext = ".bdb";
+    $dbext = ".ldb" if &util::is_little_endian();
+    my $fulldbname = &util::filename_cat ($textdir, "$self->{'collection'}$dbext");
+    $fulldbname =~ s/\//\\/g if ($ENV{'GSDLOS'} =~ /^windows$/i);
+
+    my $exedir = "$ENV{'GSDLHOME'}/bin/$ENV{'GSDLOS'}";
+    my $exe = &util::get_os_exe ();
+    my $txt2db_exe = &util::filename_cat($exedir, "txt2db$exe");
+
+    print STDERR "\n*** creating the info database and processing associated files\n" 
+	if ($self->{'verbosity'} >= 1);
+
+    # init all the classifiers
+    &classify::init_classifiers ($self->{'classifiers'});
+
+    # set up the document processor
+    my ($handle);
+    if ($self->{'debug'}) {
+	$handle = STDOUT;
+    } else {
+	if (!-e "$txt2db_exe" || !open (PIPEOUT, "| $txt2db_exe $fulldbname")) {
+	    die "mgbuilder::make_infodatabase - couldn't run $txt2db_exe\n";
+	}
+	$handle = mgbuilder::PIPEOUT;
+    }
+
+    $self->{'buildproc'}->set_output_handle ($handle);
+    $self->{'buildproc'}->set_mode ('infodb');
+    $self->{'buildproc'}->set_assocdir ($assocdir);
+    $self->{'buildproc'}->set_dontgdbm ($self->{'dontgdbm'});
+    $self->{'buildproc'}->set_classifiers ($self->{'classifiers'});
+    $self->{'buildproc'}->set_indexing_text (0);
+    $self->{'buildproc'}->reset();
+
+    if (defined $self->{'collect_cfg'}->{'collectionmeta'}) {
+	
+	if (!defined $self->{'index_mapping'}) {
+	    $self->{'index_mapping'} = 
+		$self->create_index_mapping ($self->{'collect_cfg'}->{'indexes'});
+	}
+
+	print $handle "[collection]\n";
+	
+	foreach $cmeta (keys (%{$self->{'collect_cfg'}->{'collectionmeta'}})) {
+	    if ($cmeta =~ s/^\.//) {
+		if (defined $self->{'index_mapping'}->{$cmeta}) {
+		    print $handle "<$self->{'index_mapping'}->{$cmeta}>" .
+			$self->{'collect_cfg'}->{'collectionmeta'}->{".$cmeta"} . "\n";
+		} else {
+		    print STDERR "mgbuilder: warning bad collectionmeta option '$cmeta' - ignored\n";
+		}
+	    } else {
+		print $handle "<$cmeta>$self->{'collect_cfg'}->{'collectionmeta'}->{$cmeta}\n";
+	    }
+	}
+	print $handle "\n" . ('-' x 70) . "\n";
+
+    }
+
+    &plugin::read ($self->{'pluginfo'}, $self->{'source_dir'}, 
+		   "", {}, $self->{'buildproc'}, $self->{'maxdocs'});
+
+    # output classification information
+    &classify::output_classify_info ($self->{'classifiers'}, $handle,
+				     $self->{'allclassifications'});
+
+    close ($handle) if !$self->{'debug'};
+}
+
+sub collect_specific {
+    my $self = shift (@_);
+}
+
+sub make_auxiliary_files {
+    my $self = shift (@_);
+    my ($index);
+    my %build_cfg = ();
+
+    print STDERR "\n*** creating auxiliary files \n" if ($self->{'verbosity'} >= 1);
+
+    # get the text directory
+    &util::mk_all_dir ($self->{'build_dir'});
+
+    # store the build date
+    $build_cfg->{'builddate'} = time;
+
+    # store the number of documents and number of bytes
+    $build_cfg->{'numdocs'} = $self->{'buildproc'}->get_num_docs();
+    $build_cfg->{'numbytes'} = $self->{'buildproc'}->get_num_bytes();
+
+    # get additional stats from mg
+    my $exedir = "$ENV{'GSDLHOME'}/bin/$ENV{'GSDLOS'}";
+    my $exe = &util::get_os_exe ();
+    my $mgstat_exe = &util::filename_cat($exedir, "mgstat$exe");
+    my $input_file = &util::filename_cat ("text", $self->{'collection'});
+    if (!-e "$mgstat_exe" || !open (PIPEIN, "$mgstat_exe -d $self->{'build_dir'} -f $input_file |")) {
+	print STDERR "Warning: Couldn't open pipe to $mgstat_exe to get additional stats\n";
+    } else {
+	my $line = "";
+	while (defined ($line = <PIPEIN>)) {
+	    if ($line =~ /^Words in collection \[dict\]\s+:\s+(\d+)/) {
+		($build_cfg->{'numwords'}) = $1;
+	    } elsif ($line =~ /^Documents\s+:\s+(\d+)/) {
+		($build_cfg->{'numsections'}) = $1;
+	    }
+	}
+	close PIPEIN;
+    }
+
+    # store the mapping between the index names and the directory names
+    my @indexmap = ();
+    foreach $index (@{$self->{'index_mapping'}->{'indexmaporder'}}) {
+	push (@indexmap, "$index\-\>$self->{'index_mapping'}->{'indexmap'}->{$index}");
+    }
+    $build_cfg->{'indexmap'} = \@indexmap;
+
+    my @subcollectionmap = ();
+    foreach $subcollection (@{$self->{'index_mapping'}->{'subcollectionmaporder'}}) {
+	push (@subcollectionmap, "$subcollection\-\>" .
+	      $self->{'index_mapping'}->{'subcollectionmap'}->{$subcollection});
+    }
+    $build_cfg->{'subcollectionmap'} = \@subcollectionmap if scalar (@subcollectionmap);
+
+    my @languagemap = ();
+    foreach $language (@{$self->{'index_mapping'}->{'languagemaporder'}}) {
+	push (@languagemap, "$language\-\>" .
+	      $self->{'index_mapping'}->{'languagemap'}->{$language});
+    }
+    $build_cfg->{'languagemap'} = \@languagemap if scalar (@languagemap);
+
+    $build_cfg->{'notbuilt'} = $self->{'notbuilt'} if scalar @{$self->{'notbuilt'}};
+
+    # write out the build information
+    &cfgread::write_cfg_file("$self->{'build_dir'}/build.cfg", $build_cfg,
+			     '^(builddate|numdocs|numbytes|numwords|numsections)$', 
+                             '^(indexmap|subcollectionmap|languagemap|notbuilt)$');
+
+}
+
+sub deinit {
+    my $self = shift (@_);
+}
+
+sub print_stats {
+    my $self = shift (@_);
+
+    my $indexing_text = $self->{'buildproc'}->get_indexing_text();
+    my $index = $self->{'buildproc'}->get_index();
+    my $num_bytes = $self->{'buildproc'}->get_num_bytes();
+    my $num_processed_bytes = $self->{'buildproc'}->get_num_processed_bytes();
+
+    if ($indexing_text) {
+	print STDERR "Stats (Creating index $index)\n";
+    } else {
+	print STDERR "Stats (Compressing text from $index)\n";
+    }
+    print STDERR "Total bytes in collection: $num_bytes\n";
+    print STDERR "Total bytes in $index: $num_processed_bytes\n";
+
+    if ($num_processed_bytes < 50) {
+	print STDERR "***************\n";
+	print STDERR "WARNING: There is very little or no text to process for $index\n";
+	if ($indexing_text) {
+	    print STDERR "This may cause an error while attempting to build the index\n";
+	} else {
+	    print STDERR "This may cause an error while attempting to compress the text\n";
+	}
+	print STDERR "***************\n";
+    }
+}
+
+1;
+
+
Index: /main/tags/2.25/gsdl/perllib/mgbuildproc.pm
===================================================================
--- /main/tags/2.25/gsdl/perllib/mgbuildproc.pm	(revision 21064)
+++ /main/tags/2.25/gsdl/perllib/mgbuildproc.pm	(revision 21064)
@@ -0,0 +1,475 @@
+###########################################################################
+#
+# mgbuildproc.pm -- 
+# A component of the Greenstone digital library software
+# from the New Zealand Digital Library Project at the 
+# University of Waikato, New Zealand.
+#
+# Copyright (C) 1999 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.
+#
+###########################################################################
+
+# This document processor outputs a document
+# for mg to process
+
+
+package mgbuildproc;
+
+use classify;
+use doc;
+use docproc;
+use util;
+
+BEGIN {
+    @ISA = ('docproc');
+}
+
+
+sub new {
+    my ($class, $collection, $source_dir, $build_dir, $verbosity) = @_;
+    my $self = new docproc ();
+
+    $self->{'collection'} = $collection;
+    $self->{'source_dir'} = $source_dir;
+    $self->{'build_dir'} = $build_dir;
+    $self->{'verbosity'} = $verbosity;
+    $self->{'classifiers'} = [];
+    $self->{'mode'} = "text";
+    $self->{'assocdir'} = $build_dir;
+    $self->{'dontgdbm'} = {};
+    $self->{'index'} = "section:text";
+    $self->{'indexexparr'} = [];
+    $self->{'output_handle'} = "STDOUT";
+    $self->{'num_docs'} = 0;
+    $self->{'num_sections'} = 0;
+    $self->{'num_bytes'} = 0;
+    $self->{'num_processed_bytes'} = 0;
+
+    $self->{'indexing_text'} = 0;
+
+    return bless $self, $class;
+}
+
+sub reset {
+    my $self = shift (@_);
+    
+    $self->{'num_docs'} = 0;
+    $self->{'num_sections'} = 0;
+    $self->{'num_processed_bytes'} = 0;
+    $self->{'num_bytes'} = 0;
+}
+
+sub get_num_docs {
+    my $self = shift (@_);
+
+    return $self->{'num_docs'};
+}
+
+sub get_num_sections {
+    my $self = shift (@_);
+
+    return $self->{'num_sections'};
+}
+
+# num_bytes is the actual number of bytes in the collection
+# this is normally the same as what's processed during text compression
+sub get_num_bytes {
+    my $self = shift (@_);
+
+    return $self->{'num_bytes'};
+}
+
+# num_processed_bytes is the number of bytes actually passed
+# to mg for the current index
+sub get_num_processed_bytes {
+    my $self = shift (@_);
+
+    return $self->{'num_processed_bytes'};
+}
+
+sub set_output_handle {
+    my $self = shift (@_);
+    my ($handle) = @_;
+
+    $self->{'output_handle'} = $handle;
+}
+
+sub set_mode {
+    my $self = shift (@_);
+    my ($mode) = @_;
+
+    $self->{'mode'} = $mode;
+}
+
+sub set_assocdir {
+    my $self = shift (@_);
+    my ($assocdir) = @_;
+
+    $self->{'assocdir'} = $assocdir;
+}
+
+sub set_dontgdbm {
+    my $self = shift (@_);
+    my ($dontgdbm) = @_;
+
+    $self->{'dontgdbm'} = $dontgdbm;
+}
+
+sub set_index {
+    my $self = shift (@_);
+    my ($index, $indexexparr) = @_;
+
+    $self->{'index'} = $index;
+    $self->{'indexexparr'} = $indexexparr if defined $indexexparr;
+}
+
+sub get_index {
+    my $self = shift (@_);
+
+    return $self->{'index'};
+}
+
+sub set_classifiers {
+    my $self = shift (@_);
+    my ($classifiers) = @_;
+
+    $self->{'classifiers'} = $classifiers;
+}
+
+sub set_indexing_text {
+    my $self = shift (@_);
+    my ($indexing_text) = @_;
+
+    $self->{'indexing_text'} = $indexing_text;
+}
+
+sub get_indexing_text {
+    my $self = shift (@_);
+
+    return $self->{'indexing_text'};
+}
+
+sub process {
+    my $self = shift (@_);
+    my $method = $self->{'mode'};
+
+    $self->$method(@_);
+}
+
+# use 'Paged' if document has no more than 2 levels
+# and each section at second level has a number for
+# Title metadata
+sub get_document_type {
+    my $self = shift (@_);
+    my ($doc_obj) = @_;
+
+    my $thistype = "VList";
+    my $childtype = "VList";
+    my $title;
+    my @tmp = ();
+    
+    my $section = $doc_obj->get_top_section ();
+    my $first = 1;
+    while (defined $section) {
+	@tmp = split /\./, $section;
+	if (scalar(@tmp) > 1) {
+	    return ($thistype, $childtype);
+	}
+	if (!$first) {
+	    $title = $doc_obj->get_metadata_element ($section, "Title");
+	    if (!defined $title || $title !~ /^\d+$/) {
+		return ($thistype, $childtype);
+	    }
+	}
+	$first = 0;
+	$section = $doc_obj->get_next_section($section);
+    }
+    if ($doc_obj->get_text_length ($doc_obj->get_top_section())) {
+	$thistype = "Paged";
+    } else {
+	$thistype = "Invisible";
+    }
+    $childtype = "Paged";
+    return ($thistype, $childtype);
+}
+
+sub assoc_files {
+    my $self = shift (@_);
+    my ($doc_obj, $archivedir) = @_;
+    my ($afile);
+    
+    foreach my $assoc_file (@{$doc_obj->get_assoc_files()}) {
+	# if assoc file contains directory structure of
+	# its own use it, otherwise use HASH... directory
+	if ($assoc_file->[1] =~ /[\/\\]/) {
+	    $afile = &util::filename_cat($self->{'assocdir'}, $assoc_file->[1]);
+	} else {
+	    $afile = &util::filename_cat($self->{'assocdir'}, $archivedir, $assoc_file->[1]);
+	}
+	&util::hard_link ($assoc_file->[0], $afile);
+    }
+}
+
+sub infodb {
+    my $self = shift (@_);
+    my ($doc_obj, $filename) = @_;
+    my $handle = $self->{'output_handle'};
+#    $handle = "main::STDOUT";
+
+    my $doctype = $doc_obj->get_doc_type();
+
+    # only output this document if it is one to be indexed
+    return if ($doctype ne "indexed_doc");
+
+    my ($archivedir) = $filename =~ /^(.*?)(?:\/|\\)[^\/\\]*$/;
+    $archivedir = "" unless defined $archivedir;
+    $archivedir =~ s/\\/\//g;
+    $archivedir =~ s/^\/+//;
+    $archivedir =~ s/\/+$//;
+
+    $self->assoc_files ($doc_obj, $archivedir);
+
+    # this is another document
+    $self->{'num_docs'} += 1 unless ($doctype eq "classification");
+
+    # is this a paged or a hierarchical document
+    my ($thistype, $childtype) = $self->get_document_type ($doc_obj);
+
+    my $section = $doc_obj->get_top_section ();
+    my $doc_OID = $doc_obj->get_OID();
+    my $first = 1;
+    my $url = "";
+    while (defined $section) {
+	# update a few statistics
+	$self->{'num_bytes'} += $doc_obj->get_text_length ($section);
+	$self->{'num_sections'} += 1 unless ($doctype eq "classification");
+
+	# output the section name
+	if ($section eq "") { print $handle "[$doc_OID]\n"; }
+	else { print $handle "[$doc_OID.$section]\n"; }
+
+	# output the fact that this document is a document (unless doctype
+	# has been set to something else from within a plugin
+	my $dtype = $doc_obj->get_metadata_element ($section, "doctype");
+	if (!defined $dtype || $dtype !~ /\w/) {
+	    print $handle "<doctype>doc\n";
+	}
+
+	# output whether this node contains text
+	if ($doc_obj->get_text_length($section) > 0) {
+	    print $handle "<hastxt>1\n";
+	} else {
+	    print $handle "<hastxt>0\n";
+	}
+
+	# output all the section metadata
+	my $metadata = $doc_obj->get_all_metadata ($section);
+	foreach my $pair (@$metadata) {
+	    my ($field, $value) = (@$pair);
+
+	    if ($field ne "Identifier" && $field !~ /^gsdl/ && 
+		defined $value && $value ne "") {
+
+		# escape problematic stuff
+		$value =~ s/\\/\\\\/g;
+		$value =~ s/\n/\\n/g;
+		$value =~ s/\r/\\r/g;
+
+		# special case for URL metadata
+		if ($field =~ /^URL$/i) {
+                    $url .= "[$value]\n";
+                    if ($section eq "") {$url .= "<section>$doc_OID\n";}
+                    else {$url .= "<section>$doc_OID.$section\n";}
+                    $url .= '-' x 70 . "\n";
+		}
+
+		if (!defined $self->{'dontgdbm'}->{$field}) {
+		    print $handle "<$field>$value\n";
+		}
+	    }
+	}
+	
+	# output archivedir if at top level
+	if ($section eq $doc_obj->get_top_section()) {
+	    print $handle "<archivedir>$archivedir\n";
+	}
+	
+	# output document display type
+	if ($first) {
+	    print $handle "<thistype>$thistype\n";
+	}
+
+	# output a list of children
+	my $children = $doc_obj->get_children ($section);
+	if (scalar(@$children) > 0) {
+	    print $handle "<childtype>$childtype\n";
+	    print $handle "<contains>";
+	    my $firstchild = 1;
+	    foreach my $child (@$children) {
+		print $handle ";" unless $firstchild;
+		$firstchild = 0;
+		if ($child =~ /^.*?\.(\d+)$/) {
+		    print $handle "\".$1";
+		} else {
+		    print $handle "\".$child";
+		}
+#		if ($child eq "") { print $handle "$doc_OID"; }
+#		elsif ($section eq "") { print $handle "$doc_OID.$child"; }
+#		else { print $handle "$doc_OID.$section.$child"; }
+	    }
+	    print $handle "\n";
+	}
+
+	# output the matching document number
+	print $handle "<docnum>$self->{'num_sections'}\n";
+
+	print $handle '-' x 70, "\n";
+
+	
+	# output a database entry for the document number
+	print $handle "[$self->{'num_sections'}]\n";
+	if ($section eq "") { print $handle "<section>$doc_OID\n"; }
+	else { print $handle "<section>$doc_OID.$section\n"; }
+	print $handle '-' x 70, "\n";
+	
+        # output entry for url
+        if ($url ne "") {
+            print $handle $url;
+        }
+
+	$first = 0;
+	$section = $doc_obj->get_next_section($section);
+    }
+
+    # classify this document
+    &classify::classify_doc ($self->{'classifiers'}, $doc_obj);
+
+}
+
+sub find_paragraphs {
+    $_[1] =~ s/(<p\b)/\cC$1/gi;
+}
+
+sub filter_text {
+    # $self->filter_text ($field, $new_text);
+    # don't want to do anything for this version, however,
+    # in a particular collection you might want to override
+    # this method to post-process certain fields depending on
+    # the field, or whether we are outputting it for indexing
+}
+
+sub text {
+    my $self = shift (@_);
+    my ($doc_obj) = @_;
+    my $handle = $self->{'output_handle'};
+    my $indexed_doc = 1;
+
+    # only output this document if it is one to be indexed
+    return if ($doc_obj->get_doc_type() ne "indexed_doc");
+
+    # see if this document belongs to this subcollection
+    foreach my $indexexp (@{$self->{'indexexparr'}}) {
+	$indexed_doc = 0;
+	my ($field, $exp, $options) = split /\//, $indexexp;
+	if (defined ($field) && defined ($exp)) {
+	    my ($bool) = $field =~ /^(.)/;
+	    $field =~ s/^.// if $bool eq '!';
+	    if ($field =~ /^filename$/i) {
+		$field = $doc_obj->get_source_filename();
+	    } else {
+		$field = $doc_obj->get_metadata_element($doc_obj->get_top_section(), $field);
+	    }
+	    next unless defined $field;
+	    if ($bool eq '!') {
+		if ($options =~ /^i$/i) {
+		    if ($field !~ /$exp/i) {$indexed_doc = 1; last;}
+		} else {
+		    if ($field !~ /$exp/) {$indexed_doc = 1; last;}
+		}
+	    } else {
+		if ($options =~ /^i$/i) {
+		    if ($field =~ /$exp/i) {$indexed_doc = 1; last;}
+		} else {
+		    if ($field =~ /$exp/) {$indexed_doc = 1; last;}
+		}
+	    }
+	}
+    }
+
+    # this is another document
+    $self->{'num_docs'} += 1;
+
+    # get the parameters for the output
+    my ($level, $fields) = split (/:/, $self->{'index'});
+    $fields =~ s/\ball\b/Title,Creator,text/;
+    $fields =~ s/\btopall\b/topTitle,topCreator,toptext/;
+
+    my $doc_section = 0; # just for this document
+    my $text = "";
+    my $text_extra = "";
+
+    # get the text for this document
+    my $section = $doc_obj->get_top_section();
+    while (defined $section) {
+	# update a few statistics
+	$doc_section++;
+	$self->{'num_sections'} += 1;
+
+	if ($indexed_doc) {
+	    $self->{'num_bytes'} += $doc_obj->get_text_length ($section);
+	    foreach my $field (split (/,/, $fields)) {
+		# only deal with this field if it doesn't start with top or
+		# this is the first section
+		my $real_field = $field;
+		if (!($real_field =~ s/^top//) || ($doc_section == 1)) {
+		    my $new_text = "";
+		    if ($real_field eq "text") {
+			$new_text = $doc_obj->get_text ($section);
+			$self->{'num_processed_bytes'} += length ($new_text);
+			$new_text =~ s/[\cB\cC]//g;
+			$self->find_paragraphs($new_text);
+			
+		    } else {
+			my $first = 1;
+			foreach $meta (@{$doc_obj->get_metadata ($section, $real_field)}) {
+			    $meta =~ s/[\cB\cC]//g;
+			    $self->{'num_processed_bytes'} += length ($meta);
+			    $new_text .= "\cC" unless $first;
+			    $new_text .= $meta;
+			    $first = 0;
+			}
+		    }
+		    
+		    # filter the text
+		    $self->filter_text ($field, $new_text);
+
+		    $text .= "$new_text\cC";
+		}
+	    }
+	}
+	
+	if ($level eq "document") { $text_extra .= "\cB"; }
+	else { $text .= "\cB"; }
+	
+	$section = $doc_obj->get_next_section($section);
+    }
+
+    print $handle "$text$text_extra";
+}
+
+1;
+
Index: /main/tags/2.25/gsdl/perllib/mgppbuilder.pm
===================================================================
--- /main/tags/2.25/gsdl/perllib/mgppbuilder.pm	(revision 21064)
+++ /main/tags/2.25/gsdl/perllib/mgppbuilder.pm	(revision 21064)
@@ -0,0 +1,831 @@
+###########################################################################
+#
+# mgbuilder.pm -- MGBuilder object
+# A component of the Greenstone digital library software
+# from the New Zealand Digital Library Project at the 
+# University of Waikato, New Zealand.
+#
+# Copyright (C) 1999 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 mgppbuilder;
+
+use classify;
+use cfgread;
+use colcfg;
+use plugin;
+use util;
+
+#update this !!!!!!!!!!!!!!!!
+%wanted_index_files = ('td'=>1,
+		       't'=>1,
+		       'idb'=>1,
+		       'ib1'=>1,
+		       'ib2'=>1,
+		       'ib3'=>1,
+		       'i'=>1,
+		       'ip'=>1,
+		       'tiw'=>1,
+		       'wa'=>1);
+
+
+sub new {
+    my ($class, $collection, $source_dir, $build_dir, $verbosity, 
+	$maxdocs, $debug, $keepold, $allclassifications) = @_;
+
+    # create an mgppbuilder object
+    my $self = bless {'collection'=>$collection,
+		      'source_dir'=>$source_dir,
+		      'build_dir'=>$build_dir,
+		      'verbosity'=>$verbosity,
+		      'maxdocs'=>$maxdocs,
+		      'debug'=>$debug,
+		      'keepold'=>$keepold,
+		      'allclassifications'=>$allclassifications,
+		      'notbuilt'=>[]    # indexes not built
+		      }, $class;
+
+
+    # read in the collection configuration file
+    my $colcfgname = "$ENV{'GSDLCOLLECTDIR'}/etc/collect.cfg";
+    if (!-e $colcfgname) {
+	die "mgppbuilder::new - couldn't find collect.cfg for collection $collection\n";
+    }
+    $self->{'collect_cfg'} = &colcfg::read_collect_cfg ($colcfgname);
+
+    # sort out subcollection indexes
+    if (defined $self->{'collect_cfg'}->{'indexsubcollections'}) {
+	my $indexes = $self->{'collect_cfg'}->{'indexes'};
+	$self->{'collect_cfg'}->{'indexes'} = [];
+	foreach $subcollection (@{$self->{'collect_cfg'}->{'indexsubcollections'}}) {
+	    foreach $index (@$indexes) {
+		push (@{$self->{'collect_cfg'}->{'indexes'}}, "$index:$subcollection");
+	    }
+	}
+    }
+
+    # sort out language subindexes
+    if (defined $self->{'collect_cfg'}->{'languages'}) {
+	my $indexes = $self->{'collect_cfg'}->{'indexes'};
+	$self->{'collect_cfg'}->{'indexes'} = [];
+	foreach $language (@{$self->{'collect_cfg'}->{'languages'}}) {
+	    foreach $index (@$indexes) {
+		push (@{$self->{'collect_cfg'}->{'indexes'}}, "$index:$language");
+	    }
+	}
+    }
+
+    # get the list of plugins for this collection
+    my $plugins = [];
+    if (defined $self->{'collect_cfg'}->{'plugin'}) {
+	$plugins = $self->{'collect_cfg'}->{'plugin'};
+    }
+    
+    # load all the plugins
+    $self->{'pluginfo'} = &plugin::load_plugins ($plugins);
+    if (scalar(@{$self->{'pluginfo'}}) == 0) {
+	print STDERR "No plugins were loaded.\n";
+	die "\n";
+    }
+
+    # get the list of classifiers for this collection
+    my $classifiers = [];
+    if (defined $self->{'collect_cfg'}->{'classify'}) {
+	$classifiers = $self->{'collect_cfg'}->{'classify'};
+    }
+    
+    # load all the classifiers
+    $self->{'classifiers'} = &classify::load_classifiers ($classifiers);
+
+    # load up any dontgdbm fields
+    $self->{'dontgdbm'} = {};
+    if (defined ($self->{'collect_cfg'}->{'dontgdbm'})) {
+	foreach $dg (@{$self->{'collect_cfg'}->{'dontgdbm'}}) {
+	    $self->{'dontgdbm'}->{$dg} = 1;
+	}
+    }
+
+    # load up the document processor for building
+    # if a buildproc class has been created for this collection, use it
+    # otherwise, use the mg buildproc
+    my ($buildprocdir, $buildproctype);
+    if (-e "$ENV{'GSDLCOLLECTDIR'}/perllib/${collection}buildproc.pm") {
+	$buildprocdir = "$ENV{'GSDLCOLLECTDIR'}/perllib";
+	$buildproctype = "${collection}buildproc";
+    } else {
+	$buildprocdir = "$ENV{'GSDLHOME'}/perllib";
+	$buildproctype = "mgppbuildproc";
+    }
+    require "$buildprocdir/$buildproctype.pm";
+
+    eval("\$self->{'buildproc'} = new $buildproctype(\$collection, " .
+	 "\$source_dir, \$build_dir, \$verbosity)");
+    die "$@" if $@;
+
+
+    return $self;
+}
+
+sub init {
+    my $self = shift (@_);
+
+    if (!$self->{'debug'} && !$self->{'keepold'}) {
+	# remove any old builds
+	&util::rm_r($self->{'build_dir'});
+	&util::mk_all_dir($self->{'build_dir'});
+        
+	# make the text directory
+	my $textdir = "$self->{'build_dir'}/text";
+	&util::mk_all_dir($textdir);
+    }
+}
+
+sub build_collection {
+    my $self = shift (@_);
+    my ($textindex, $indexname) = @_;
+
+    print STDERR "build_col, textindex=$textindex, indexname=$indexname\n";
+    my $exedir = "$ENV{'GSDLHOME'}/src/mgpp/text";
+    my $exe = &util::get_os_exe ();
+
+    my $mg_passes_exe = &util::filename_cat($exedir, "mg_passes$exe");
+    my $mg_compression_dict_exe = &util::filename_cat($exedir, "mg_compression_dict$exe");
+    my $mg_perf_hash_build_exe = 
+	&util::filename_cat($exedir, "mg_perf_hash_build$exe");
+    my $mg_weights_build_exe = 
+	&util::filename_cat ($exedir, "mg_weights_build$exe");
+    my $mg_invf_dict_exe = 
+	&util::filename_cat ($exedir, "mg_invf_dict$exe");
+    my $mg_stem_idx_exe =
+	&util::filename_cat ($exedir, "mg_stem_idx$exe");
+
+    &util::mk_all_dir (&util::filename_cat($self->{'build_dir'}, "text"));
+    my $basefilename = "$self->{'collection'}";
+#    my $fulltextprefix = &util::filename_cat ($self->{'build_dir'}, $basefilename);
+ #   my $fullindexprefix = &util::filename_cat ($self->{'build_dir'}, 
+	#				       $self->{'collection'});
+
+    my $fulltextprefix=$self->{'build_dir'}; # note if this works, change all to $directory, change in mg calls!!!!!!!!!!!!!!
+    my $fullindexprefix=$self->{'build_dir'};
+
+    my $directory = $self->{'build_dir'};
+    my $osextra = "";
+    if ($ENV{'GSDLOS'} =~ /^windows$/i) {
+	$fulltextprefix =~ s/\//\\/g;
+	#$directory = ~s/\//\\/g;
+    } else {
+	$osextra = " -d /";
+    }
+
+    #indexname got from command line arg. if not specified, its "", so use
+    # ones stated in cfg file
+    my $indexes = [];
+    if (!(defined $indexname && $indexname =~ /\w/)) {
+	$indexes = $self->{'collect_cfg'}->{'indexes'};
+	$indexname="Title,Organization,Magazine,text";
+    } 
+    else {
+	push @$indexes, $indexname;
+    }
+    print STDERR "indexes are: @$indexes\n";
+    
+
+   print STDERR "\n*** mg_passes: first pass\n" if ($self->{'verbosity'} >= 1);
+    print STDERR "fulltextprefix=$fulltextprefix\n";
+    # carry out the first pass of mg_passes
+    # -b $maxdocsize sets the maximum document size to be 12 meg - not available any longer
+    print STDERR "\n    collecting text statistics\n"  if ($self->{'verbosity'} >= 1);
+
+    my ($handle);
+    if ($self->{'debug'}) {
+	$handle = STDOUT;
+    } else {
+	if (!-e "$mg_passes_exe" || 
+	    !open (PIPEOUT, "| $mg_passes_exe -K Section -K Paragraph -T1 -I1 -d $fulltextprefix -f $basefilename")) {
+	    die "mgppbuilder::compress_text - couldn't run $mg_passes_exe\n";
+	}
+	$handle = mgppbuilder::PIPEOUT;
+    }
+
+    
+    #Assume that only going to build one index for now. so index will be
+    # anything specified in cfg file
+    $self->{'buildproc'}->set_output_handle ($handle);
+    $self->{'buildproc'}->set_mode ('text');
+    $self->{'buildproc'}->set_index ($indexname);
+    $self->{'buildproc'}->set_indexing_text (1); # not used at the moment I think
+    $self->{'buildproc'}->reset();
+    &plugin::begin($self->{'pluginfo'}, $self->{'source_dir'}, 
+		   $self->{'buildproc'}, $self->{'maxdocs'});
+    &plugin::read ($self->{'pluginfo'}, $self->{'source_dir'}, 
+		   "", {}, $self->{'buildproc'}, $self->{'maxdocs'});
+    &plugin::end($self->{'pluginfo'});
+    close (PIPEOUT);
+
+    close ($handle) unless $self->{'debug'};
+
+
+    # create the compression dictionary
+    # the compression dictionary is built by assuming the stats are from a seed
+    # dictionary (-S), if a novel word is encountered it is spelled out (-H),
+    # and the resulting dictionary must be less than 5 meg with the most frequent
+    # words being put into the dictionary first (-2 -k 5120)
+    if (!$self->{'debug'}) {
+	print STDERR "\n    creating the compression dictionary\n"  if ($self->{'verbosity'} >= 1);
+	if (!-e "$mg_compression_dict_exe") {
+	    die "mgppbuilder::compress_text - couldn't run $mg_compression_dict_exe\n";
+	}
+	system ("$mg_compression_dict_exe -d $fulltextprefix -f $basefilename");
+
+	# create the perfect hash function
+	if (!-e "$mg_perf_hash_build_exe") {
+	    die "mgppbuilder::build_index - couldn't run $mg_perf_hash_build_exe\n";
+	}
+	system ("$mg_perf_hash_build_exe -d $fullindexprefix -f $basefilename");
+
+    # compress the text
+    # -b $maxdocsize sets the maximum document size to be 12 meg
+    if (!$self->{'debug'}) {
+	if (!-e "$mg_passes_exe" || 
+	    !open ($handle, "| $mg_passes_exe -K Section -K Paragraph -d $fulltextprefix -f $basefilename -T2 -I2")) {
+	    die "mgppbuilder::compress_text - couldn't run $mg_passes_exe\n";
+	}
+    }
+    }
+    
+    $self->{'buildproc'}->reset();
+    
+    print STDERR "\n    compressing the text\n"  if ($self->{'verbosity'} >= 1);
+    &plugin::read ($self->{'pluginfo'}, $self->{'source_dir'}, 
+		   "", {}, $self->{'buildproc'}, $self->{'maxdocs'});
+    close ($handle) unless $self->{'debug'};
+    
+    
+    
+    # create the weights file
+    print STDERR "\n    create the weights file\n"  if ($self->{'verbosity'} >= 1);
+    if (!-e "$mg_weights_build_exe") {
+	die "mgppbuilder::build_index - couldn't run $mg_weights_build_exe\n";
+    }
+    system ("$mg_weights_build_exe -d $fullindexprefix -f $basefilename ");
+    
+    # create 'on-disk' stemmed dictionary
+    print STDERR "\n    creating 'on-disk' stemmed dictionary\n"  if ($self->{'verbosity'} >= 1);
+    if (!-e "$mg_invf_dict_exe") {
+	die "mgppbuilder::build_index - couldn't run $mg_invf_dict_exe\n";
+	}
+    system ("$mg_invf_dict_exe -d $fullindexprefix -f $basefilename");
+    
+    
+    # creates stem index files for the various stemming methods
+    print STDERR "\n    creating stem indexes\n"  if ($self->{'verbosity'} >= 1);
+    if (!-e "$mg_stem_idx_exe") {
+	die "mgppbuilder::build_index - couldn't run $mg_stem_idx_exe\n";
+    }
+    system ("$mg_stem_idx_exe -b 4096 -s1 -d $fullindexprefix -f $basefilename");
+    system ("$mg_stem_idx_exe -b 4096 -s2 -d $fullindexprefix -f $basefilename");
+    system ("$mg_stem_idx_exe -b 4096 -s3 -d $fullindexprefix -f $basefilename");
+}
+
+
+#for mgpp with more than one index
+sub compress_text {
+
+    my $self = shift (@_);
+    my ($textindex) = @_;
+
+#    $textindex = "Title,Organization,Subject,Magazine,text";
+    my $exedir = "$ENV{'GSDLHOME'}/src/mgpp/text";
+    my $exe = &util::get_os_exe ();
+    my $mg_passes_exe = &util::filename_cat($exedir, "mg_passes$exe");
+    my $mg_compression_dict_exe = &util::filename_cat($exedir, "mg_compression_dict$exe");
+
+    &util::mk_all_dir (&util::filename_cat($self->{'build_dir'}, "text"));
+
+    my $builddir = $self->{'build_dir'};
+    my $basefilename = "text/$self->{'collection'}";
+    
+     if ($ENV{'GSDLOS'} =~ /^windows$/i) {
+	 $basefilename =~ s/\//\\/g;
+	 $builddir =~ s/\//\\/g;
+	
+    } 
+
+    print STDERR "\n*** creating the compressed text\n" if ($self->{'verbosity'} >= 1);
+
+    # collect the statistics for the text
+       print STDERR "\n    collecting text statistics\n"  if ($self->{'verbosity'} >= 1);
+
+    my ($handle);
+    if ($self->{'debug'}) {
+	$handle = STDOUT;
+    } else {
+	if (!-e "$mg_passes_exe" || 
+	    !open (PIPEOUT, "| $mg_passes_exe -K Section -K Paragraph -d $builddir -f $basefilename -T1")) {
+	    die "mgppbuilder::compress_text - couldn't run $mg_passes_exe\n";
+	}
+	$handle = mgppbuilder::PIPEOUT;
+    }
+
+    $self->{'buildproc'}->set_output_handle ($handle);
+    $self->{'buildproc'}->set_mode ('text');
+    $self->{'buildproc'}->set_index ($textindex);
+    $self->{'buildproc'}->set_indexing_text (0);
+    $self->{'buildproc'}->reset();
+    &plugin::begin($self->{'pluginfo'}, $self->{'source_dir'}, 
+		   $self->{'buildproc'}, $self->{'maxdocs'});
+    &plugin::read ($self->{'pluginfo'}, $self->{'source_dir'}, 
+		   "", {}, $self->{'buildproc'}, $self->{'maxdocs'});
+    &plugin::end($self->{'pluginfo'});
+    close (PIPEOUT);
+
+    close ($handle) unless $self->{'debug'};
+
+    # create the compression dictionary
+    # the compression dictionary is built by assuming the stats are from a seed
+    # dictionary (-S), if a novel word is encountered it is spelled out (-H),
+    # and the resulting dictionary must be less than 5 meg with the most 
+    # frequent words being put into the dictionary first (-2 -k 5120)
+    # note: this options are left over from mg version
+    if (!$self->{'debug'}) {
+	print STDERR "\n    creating the compression dictionary\n"  if ($self->{'verbosity'} >= 1);
+	if (!-e "$mg_compression_dict_exe") {
+	    die "mgppbuilder::compress_text - couldn't run $mg_compression_dict_exe\n";
+	}
+	system ("$mg_compression_dict_exe -d $builddir -f $basefilename -S -H -2 -k 5120");
+
+
+	if (!$self->{'debug'}) {
+	    if (!-e "$mg_passes_exe" || 
+		!open ($handle, "| $mg_passes_exe -K Section -K Paragraph -f $basefilename -d $builddir -T2")) {
+		die "mgppbuilder::compress_text - couldn't run $mg_passes_exe\n";
+	    }
+	}
+    }
+
+    $self->{'buildproc'}->reset();
+    # compress the text
+    print STDERR "\n    compressing the text\n"  if ($self->{'verbosity'} >= 1);
+    &plugin::read ($self->{'pluginfo'}, $self->{'source_dir'}, 
+		   "", {}, $self->{'buildproc'}, $self->{'maxdocs'});
+    close ($handle) unless $self->{'debug'};
+}
+
+sub want_built {
+    my $self = shift (@_);
+    my ($index) = @_;
+
+    if (defined ($self->{'collect_cfg'}->{'dontbuild'})) {
+	foreach $checkstr (@{$self->{'collect_cfg'}->{'dontbuild'}}) {
+	    if ($index =~ /^$checkstr$/) {
+		push (@{$self->{'notbuilt'}}, $self->{'index_mapping'}->{$index});
+		return 0;
+	    }
+	}
+    }
+
+    return 1;
+}
+
+sub build_indexes {
+    my $self = shift (@_);
+    my ($indexname) = @_;
+
+    my $indexes = [];
+    if (defined $indexname && $indexname =~ /\w/) {
+	push @$indexes, $indexname;
+    } else {
+	$indexes = $self->{'collect_cfg'}->{'indexes'};
+    }
+
+#    push @$indexes, "text,Title,Organization,Magazine,Subject";
+#    push @$indexes, "Title,Organization,Magazine,Subject";
+    # create the mapping between the index descriptions 
+    # and their directory names
+    $self->{'index_mapping'} = $self->create_index_mapping ($indexes);
+
+    # build each of the indexes
+    foreach $index (@$indexes) {
+	if ($self->want_built($index)) {
+	    print STDERR "\n*** building index $index in subdirectory " . 
+		"$self->{'index_mapping'}->{$index}\n" if ($self->{'verbosity'} >= 1);
+	    $self->build_index($index);
+	} else {
+	    print STDERR "\n*** ignoring index $index\n" if ($self->{'verbosity'} >= 1);
+	}
+    }
+}
+
+# creates directory names for each of the index descriptions
+sub create_index_mapping {
+    my $self = shift (@_);
+    my ($indexes) = @_;
+
+    my %mapping = ();
+    $mapping{'indexmaporder'} = [];
+    $mapping{'subcollectionmaporder'} = [];
+    $mapping{'languagemaporder'} = [];
+    
+    # dirnames is used to check for collisions. Start this off
+    # with the manditory directory names
+    my %dirnames = ('text'=>'text',
+		    'extra'=>'extra');
+    my %pnames = ('index' => '', 'subcollection' => '', 'languages' => '');
+
+    foreach $index (@$indexes) {
+	my ($fields, $subcollection, $languages) = split (":", $index);
+
+	# the directory name starts with a processed version of index fields
+	my ($pindex) = $self->process_field($fields);
+	# next comes a processed version of the index
+	$pindex = lc ($pindex);
+
+	# next comes a processed version of the subcollection if there is one.
+	my $psub = $self->process_field ($subcollection);
+	$psub = lc ($psub);
+
+	# next comes a processed version of the language if there is one.
+	my $plang = $self->process_field ($languages);
+	$plang = lc ($plang);
+
+	my $dirname = $pindex . $psub . $plang;
+
+	# check to be sure all index names are unique
+	while (defined ($dirnames{$dirname})) {
+	    $dirname = $self->make_unique (\%pnames, $index, \$pindex, \$psub, \$plang);
+	}
+
+	# store the mapping orders as well as the maps
+	if (!defined $mapping{'indexmap'}{"$fields"}) {
+	    $mapping{'indexmap'}{"$fields"} = $pindex;
+	    push (@{$mapping{'indexmaporder'}}, "$fields");
+	}
+	if ($psub =~ /\w/ && !defined ($mapping{'subcollectionmap'}{$subcollection})) {
+	    $mapping{'subcollectionmap'}{$subcollection} = $psub;
+	    push (@{$mapping{'subcollectionmaporder'}}, $subcollection);
+	}
+	if ($plang =~ /\w/ && !defined ($mapping{'languagemap'}{$languages})) {
+	    $mapping{'languagemap'}{$languages} = $plang;
+	    push (@{$mapping{'languagemaporder'}}, $language);
+	}
+	$mapping{$index} = $dirname;
+	$dirnames{$dirname} = $index;
+	$pnames{'index'}{$pindex} = "$fields";
+	$pnames{'subcollection'}{$psub} = $subcollection;
+	$pnames{'languages'}{$plang} = $languages;
+    }
+
+    return \%mapping;
+}
+
+# returns a processed version of a field.
+# if the field has only one component the processed
+# version will contain the first character and next consonant
+# of that componant - otherwise it will contain the first 
+# character of the first two components 
+sub process_field {
+    my $self = shift (@_);
+    my ($field) = @_;
+ 
+    return "" unless (defined ($field) && $field =~ /\w/);
+
+    my @components = split /,/, $field;
+    if (scalar @components >= 2) {
+	splice (@components, 2);
+	map {s/^(.).*$/$1/;} @components;
+	return join("", @components);
+    } else {
+	my ($a, $b) = $field =~ /^(.).*?([bcdfghjklmnpqrstvwxyz])/i;
+	($a, $b) = $field =~ /^(.)(.)/ unless defined $a && defined $b;
+	return "$a$b";
+    }
+}
+
+sub make_unique {
+    my $self = shift (@_);
+    my ($namehash, $index, $indexref, $subref, $langref) = @_;
+    my ($fields, $subcollection, $languages) = split (":", $index);
+
+    if ($namehash->{'index'}->{$$indexref} ne "$fields") {
+	$self->get_next_version ($indexref);
+    } elsif ($namehash->{'subcollection'}->{$$subref} ne $subcollection) {
+	$self->get_next_version ($subref);
+    } elsif ($namehash->{'languages'}->{$$langref} ne $languages) {
+	$self->get_next_version ($langref);
+    }
+    return "$$indexref$$subref$$langref";
+}	
+
+sub get_next_version {
+    my $self = shift (@_);
+    my ($nameref) = @_;
+
+    if ($$nameref =~ /(\d\d)$/) {
+	my $num = $1; $num ++;
+	$$nameref =~ s/\d\d$/$num/;
+    } elsif ($$nameref =~ /(\d)$/) {
+	my $num = $1;
+	if ($num == 9) {$$nameref =~ s/\d\d$/10/;}
+	else {$num ++; $$nameref =~ s/\d$/$num/;}
+    } else {
+	$$nameref =~ s/.$/0/;
+    }
+}
+
+sub build_index {
+    my $self = shift (@_);
+    my ($index) = @_;
+
+    # get the full index directory path and make sure it exists
+    my $indexdir = $self->{'index_mapping'}->{$index};
+    &util::mk_all_dir (&util::filename_cat($self->{'build_dir'}, $indexdir));
+    my $builddir = $self->{'build_dir'};
+
+    my $basefilename = &util::filename_cat ($indexdir, 
+					       $self->{'collection'});
+
+    # get any os specific stuff
+    my $exedir = "$ENV{'GSDLHOME'}/src/mgpp/text";
+
+    my $exe = &util::get_os_exe ();
+    my $mg_passes_exe = &util::filename_cat($exedir, "mg_passes$exe");
+    my $mg_perf_hash_build_exe = 
+	&util::filename_cat($exedir, "mg_perf_hash_build$exe");
+    my $mg_weights_build_exe = 
+	&util::filename_cat ($exedir, "mg_weights_build$exe");
+    my $mg_invf_dict_exe = 
+	&util::filename_cat ($exedir, "mg_invf_dict$exe");
+    my $mg_stem_idx_exe =
+	&util::filename_cat ($exedir, "mg_stem_idx$exe");
+
+    if ($ENV{'GSDLOS'} =~ /^windows$/i) {
+	$builddir=~ s/\//\\/g;
+	$basefilename =~ s/\//\\/g; 
+    }
+
+    # get the index expression if this index belongs
+    # to a subcollection
+    my $indexexparr = [];
+    my ($fields, $subcollection) = split (":", $index);
+    my @subcollections = ();
+    @subcollections = split /,/, $subcollection if (defined $subcollection);
+
+    foreach $subcollection (@subcollections) {
+	if (defined ($self->{'collect_cfg'}->{'subcollection'}->{$subcollection})) {
+	    push (@$indexexparr, $self->{'collect_cfg'}->{'subcollection'}->{$subcollection});
+	} 
+    }
+    
+    # add expressions for languages if this index belongs to
+    # a language subcollection
+    foreach $language (@{$self->{'collect_cfg'}->{'languages'}}) {
+	if ($language =~ s/^\!//) {
+	    push (@$indexexparr, "!Language/$language/");
+	} else {
+	    push (@$indexexparr, "Language/$language/");
+	}
+    }
+
+    # Build index dictionary. Uses verbatim stem method
+    print STDERR "\n    creating index dictionary\n"  if ($self->{'verbosity'} >= 1);
+    my ($handle);
+    if ($self->{'debug'}) {
+	$handle = STDOUT;
+    } else {
+	if (!-e "$mg_passes_exe" || 
+	    !open (PIPEOUT, "| $mg_passes_exe -K Section -K Paragraph -d $builddir -f $basefilename -I1")) {
+	    die "mgppbuilder::build_index - couldn't run $mg_passes_exe\n";
+	}
+	$handle = mgppbuilder::PIPEOUT;
+    }
+	
+    # set up the document processor
+    $self->{'buildproc'}->set_output_handle ($handle);
+    $self->{'buildproc'}->set_mode ('text');
+    $self->{'buildproc'}->set_index ($index, $indexexparr);
+    $self->{'buildproc'}->set_indexing_text (1);
+
+    $self->{'buildproc'}->reset();
+    &plugin::read ($self->{'pluginfo'}, $self->{'source_dir'}, 
+		   "", {}, $self->{'buildproc'}, $self->{'maxdocs'});
+    close ($handle) unless $self->{'debug'};
+
+    if (!$self->{'debug'}) {
+	# create the perfect hash function
+	if (!-e "$mg_perf_hash_build_exe") {
+	    die "mgppbuilder::build_index - couldn't run $mg_perf_hash_build_exe\n";
+	}
+	system ("$mg_perf_hash_build_exe -d $builddir -f $basefilename");
+
+	if (!-e "$mg_passes_exe" || 
+	    !open ($handle, "| $mg_passes_exe -K Section -K Paragraph -d $builddir -f $basefilename -I2")) {
+	    die "mgppbuilder::build_index - couldn't run $mg_passes_exe\n";
+	}
+    }
+    
+    # invert the text
+    print STDERR "\n    inverting the text\n"  if ($self->{'verbosity'} >= 1);
+
+    $self->{'buildproc'}->reset();
+    &plugin::read ($self->{'pluginfo'}, $self->{'source_dir'}, 
+		   "", {}, $self->{'buildproc'}, $self->{'maxdocs'});
+    
+    if (!$self->{'debug'}) {
+
+	close ($handle);
+	
+	# create the weights file
+	print STDERR "\n    create the weights file\n"  if ($self->{'verbosity'} >= 1);
+	if (!-e "$mg_weights_build_exe") {
+	    die "mgppbuilder::build_index - couldn't run $mg_weights_build_exe\n";
+	}
+	system ("$mg_weights_build_exe -d $builddir -f $basefilename");
+
+	# create 'on-disk' stemmed dictionary
+	print STDERR "\n    creating 'on-disk' stemmed dictionary\n"  if ($self->{'verbosity'} >= 1);
+	if (!-e "$mg_invf_dict_exe") {
+	    die "mgppbuilder::build_index - couldn't run $mg_invf_dict_exe\n";
+	}
+	system ("$mg_invf_dict_exe -d $builddir -f $basefilename");
+
+
+	# creates stem index files for the various stemming methods
+	print STDERR "\n    creating stem indexes\n"  if ($self->{'verbosity'} >= 1);
+	if (!-e "$mg_stem_idx_exe") {
+	    die "mgppbuilder::build_index - couldn't run $mg_stem_idx_exe\n";
+	}
+	system ("$mg_stem_idx_exe -b 4096 -s1 -d $builddir -f $basefilename");
+	system ("$mg_stem_idx_exe -b 4096 -s2 -d $builddir -f $basefilename");
+	system ("$mg_stem_idx_exe -b 4096 -s3 -d $builddir -f $basefilename");
+
+    
+	# remove unwanted files
+#	my $tmpdir = &util::filename_cat ($self->{'build_dir'}, $indexdir);
+#	opendir (DIR, $tmpdir) || die
+#	    "mgppbuilder::build_index - couldn't read directory $tmpdir\n";
+#	foreach $file (readdir(DIR)) {
+#	    next if $file =~ /^\./;
+#	    my ($suffix) = $file =~ /\.([^\.]+)$/;
+#	    if (defined $suffix && !defined $wanted_index_files{$suffix}) {
+		# delete it!
+#		print STDERR "deleting $file\n" if $self->{'verbosity'} > 2;
+#		&util::rm (&util::filename_cat ($tmpdir, $file));
+#	    }
+#	}
+#	closedir (DIR);
+  }
+}   
+
+sub make_infodatabase {
+    my $self = shift (@_);
+    my $textdir = &util::filename_cat($self->{'build_dir'}, "text");
+    my $assocdir = &util::filename_cat($self->{'build_dir'}, "assoc");
+    &util::mk_all_dir ($textdir);
+    &util::mk_all_dir ($assocdir);
+
+    # get db name
+    my $dbext = ".bdb";
+    $dbext = ".ldb" if &util::is_little_endian();
+    my $fulldbname = &util::filename_cat ($textdir, "$self->{'collection'}$dbext");
+    $fulldbname =~ s/\//\\/g if ($ENV{'GSDLOS'} =~ /^windows$/i);
+
+    my $exedir = "$ENV{'GSDLHOME'}/bin/$ENV{'GSDLOS'}";
+    my $exe = &util::get_os_exe ();
+    my $txt2db_exe = &util::filename_cat($exedir, "txt2db$exe");
+
+    print STDERR "\n*** creating the info database and processing associated files\n" 
+	if ($self->{'verbosity'} >= 1);
+
+    # init all the classifiers
+    &classify::init_classifiers ($self->{'classifiers'});
+
+    # set up the document processor
+    my ($handle);
+    if ($self->{'debug'}) {
+	$handle = STDOUT;
+    } else {
+	if (!-e "$txt2db_exe" || !open (PIPEOUT, "| $txt2db_exe $fulldbname")) {
+	    die "mgppbuilder::make_infodatabase - couldn't run $txt2db_exe\n";
+	}
+	$handle = mgppbuilder::PIPEOUT;
+    }
+
+    $self->{'buildproc'}->set_output_handle ($handle);
+    $self->{'buildproc'}->set_mode ('infodb');
+    $self->{'buildproc'}->set_assocdir ($assocdir);
+    $self->{'buildproc'}->set_dontgdbm ($self->{'dontgdbm'});
+    $self->{'buildproc'}->set_classifiers ($self->{'classifiers'});
+    $self->{'buildproc'}->set_indexing_text (0);
+    $self->{'buildproc'}->reset();
+
+    if (defined $self->{'collect_cfg'}->{'collectionmeta'}) {
+	
+	if (!defined $self->{'index_mapping'}) {
+	    $self->{'index_mapping'} = 
+		$self->create_index_mapping ($self->{'collect_cfg'}->{'indexes'});
+	}
+
+	print $handle "[collection]\n";
+	
+	foreach $cmeta (keys (%{$self->{'collect_cfg'}->{'collectionmeta'}})) {
+	    if ($cmeta =~ s/^\.//) {
+		if (defined $self->{'index_mapping'}->{$cmeta}) {
+		    print $handle "<$self->{'index_mapping'}->{$cmeta}>" .
+			$self->{'collect_cfg'}->{'collectionmeta'}->{".$cmeta"} . "\n";
+		print STDERR "have .section entry in collect file\n";
+		} else {
+		    print STDERR "mgppbuilder: warning bad collectionmeta option '$cmeta' - ignored\n";
+		}
+	    } else {
+		print $handle "<$cmeta>$self->{'collect_cfg'}->{'collectionmeta'}->{$cmeta}\n";
+	    }
+	}
+	print $handle "\n" . ('-' x 70) . "\n";
+
+    }
+
+    &plugin::read ($self->{'pluginfo'}, $self->{'source_dir'}, 
+		   "", {}, $self->{'buildproc'}, $self->{'maxdocs'});
+
+    # output classification information
+    &classify::output_classify_info ($self->{'classifiers'}, $handle,
+				     $self->{'allclassifications'});
+
+    close ($handle) if !$self->{'debug'};
+}
+
+sub collect_specific {
+    my $self = shift (@_);
+}
+
+sub make_auxiliary_files {
+    my $self = shift (@_);
+    my ($index);
+    my %build_cfg = ();
+
+    print STDERR "\n*** creating auxiliary files \n" if ($self->{'verbosity'} >= 1);
+
+    # get the text directory
+    &util::mk_all_dir ($self->{'build_dir'});
+
+    # store the build date
+    $build_cfg->{'builddate'} = time;
+    $build_cfg->{'buildtype'} = "mgpp";
+
+    # store the number of documents and number of bytes
+    $build_cfg->{'numdocs'} = $self->{'buildproc'}->get_num_docs();
+    $build_cfg->{'numbytes'} = $self->{'buildproc'}->get_num_bytes();
+
+    # store the mapping between the index names and the directory names
+    my @indexmap = ();
+    foreach $index (@{$self->{'index_mapping'}->{'indexmaporder'}}) {
+	push (@indexmap, "$index\-\>$self->{'index_mapping'}->{'indexmap'}->{$index}");
+    }
+    $build_cfg->{'indexmap'} = \@indexmap;
+
+    my @subcollectionmap = ();
+    foreach $subcollection (@{$self->{'index_mapping'}->{'subcollectionmaporder'}}) {
+	push (@subcollectionmap, "$subcollection\-\>" .
+	      $self->{'index_mapping'}->{'subcollectionmap'}->{$subcollection});
+    }
+    $build_cfg->{'subcollectionmap'} = \@subcollectionmap if scalar (@subcollectionmap);
+
+    my @languagemap = ();
+    foreach $language (@{$self->{'index_mapping'}->{'languagemaporder'}}) {
+	push (@languagemap, "$language\-\>" .
+	      $self->{'index_mapping'}->{'languagemap'}->{$language});
+    }
+    $build_cfg->{'languagemap'} = \@languagemap if scalar (@languagemap);
+
+    $build_cfg->{'notbuilt'} = $self->{'notbuilt'};
+
+    # write out the build information
+    &cfgread::write_cfg_file("$self->{'build_dir'}/build.cfg", $build_cfg,
+			     '^(builddate|buildtype|numdocs|numbytes)$', 
+                             '^(indexmap|subcollectionmap|languagemap|notbuilt)$');
+
+}
+
+sub deinit {
+    my $self = shift (@_);
+}
+
+
+1;
+
+
Index: /main/tags/2.25/gsdl/perllib/mgppbuildproc.pm
===================================================================
--- /main/tags/2.25/gsdl/perllib/mgppbuildproc.pm	(revision 21064)
+++ /main/tags/2.25/gsdl/perllib/mgppbuildproc.pm	(revision 21064)
@@ -0,0 +1,475 @@
+###########################################################################
+#
+# mgbuildproc.pm -- 
+# A component of the Greenstone digital library software
+# from the New Zealand Digital Library Project at the 
+# University of Waikato, New Zealand.
+#
+# Copyright (C) 1999 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.
+#
+###########################################################################
+
+# This document processor outputs a document
+# for mg to process
+
+
+package mgppbuildproc;
+
+use classify;
+use doc;
+use docproc;
+use util;
+
+
+BEGIN {
+    @ISA = ('docproc');
+}
+
+
+sub new {
+    my ($class, $collection, $source_dir, $build_dir, $verbosity) = @_;
+    my $self = new docproc ();
+
+    $self->{'collection'} = $collection;
+    $self->{'source_dir'} = $source_dir;
+    $self->{'build_dir'} = $build_dir;
+    $self->{'verbosity'} = $verbosity;
+    $self->{'classifiers'} = [];
+    $self->{'mode'} = "text";
+    $self->{'assocdir'} = $build_dir;
+    $self->{'dontgdbm'} = {};
+    $self->{'index'} = "text";
+    $self->{'indexexparr'} = [];
+    $self->{'output_handle'} = "STDOUT";
+    $self->{'num_docs'} = 0;
+    $self->{'num_sections'} = 0;
+    $self->{'num_bytes'} = 0;
+
+    $self->{'indexing_text'} = 0;
+
+    return bless $self, $class;
+}
+
+sub reset {
+    my $self = shift (@_);
+    
+    $self->{'num_docs'} = 0;
+    $self->{'num_sections'} = 0;
+    $self->{'num_bytes'} = 0;
+}
+
+sub get_num_docs {
+    my $self = shift (@_);
+
+    return $self->{'num_docs'};
+}
+
+sub get_num_sections {
+    my $self = shift (@_);
+
+    return $self->{'num_sections'};
+}
+
+sub get_num_bytes {
+    my $self = shift (@_);
+
+    return $self->{'num_bytes'};
+}
+
+sub set_output_handle {
+    my $self = shift (@_);
+    my ($handle) = @_;
+
+    $self->{'output_handle'} = $handle;
+}
+
+sub set_mode {
+    my $self = shift (@_);
+    my ($mode) = @_;
+
+    $self->{'mode'} = $mode;
+}
+
+sub set_assocdir {
+    my $self = shift (@_);
+    my ($assocdir) = @_;
+
+    $self->{'assocdir'} = $assocdir;
+}
+
+sub set_dontgdbm {
+    my $self = shift (@_);
+    my ($dontgdbm) = @_;
+
+    $self->{'dontgdbm'} = $dontgdbm;
+}
+
+sub set_index {
+    my $self = shift (@_);
+    my ($index, $indexexparr) = @_;
+
+    $self->{'index'} = $index;
+    $self->{'indexexparr'} = $indexexparr if defined $indexexparr;
+}
+
+sub set_classifiers {
+    my $self = shift (@_);
+    my ($classifiers) = @_;
+
+    $self->{'classifiers'} = $classifiers;
+}
+
+sub set_indexing_text {
+    my $self = shift (@_);
+    my ($indexing_text) = @_;
+
+    $self->{'indexing_text'} = $indexing_text;
+}
+
+sub process {
+    my $self = shift (@_);
+    my $method = $self->{'mode'};
+
+    $self->$method(@_);
+}
+
+# use 'Paged' if document has no more than 2 levels
+# and each section at second level has a number for
+# Title metadata
+sub get_document_type {
+    my $self = shift (@_);
+    my ($doc_obj) = @_;
+
+    my $thistype = "VList";
+    my $childtype = "VList";
+    my $title;
+    my @tmp = ();
+    
+    my $section = $doc_obj->get_top_section ();
+    my $first = 1;
+    while (defined $section) {
+	@tmp = split /\./, $section;
+	if (scalar(@tmp) > 1) {
+	    return ($thistype, $childtype);
+	}
+	if (!$first) {
+	    $title = $doc_obj->get_metadata_element ($section, "Title");
+	    if (!defined $title || $title !~ /^\d+$/) {
+		return ($thistype, $childtype);
+	    }
+	}
+	$first = 0;
+	$section = $doc_obj->get_next_section($section);
+    }
+    if ($doc_obj->get_text_length ($doc_obj->get_top_section())) {
+	$thistype = "Paged";
+    } else {
+	$thistype = "Invisible";
+    }
+    $childtype = "Paged";
+    return ($thistype, $childtype);
+}
+
+sub assoc_files {
+   my $self = shift (@_);
+    my ($doc_obj, $archivedir) = @_;
+    my ($afile);
+    
+    foreach my $assoc_file (@{$doc_obj->get_assoc_files()}) {
+	# if assoc file contains directory structure of
+	# its own use it, otherwise use HASH... directory
+	if ($assoc_file->[1] =~ /[\/\\]/) {
+	    $afile = &util::filename_cat($self->{'assocdir'}, $assoc_file->[1]);
+	} else {
+	    $afile = &util::filename_cat($self->{'assocdir'}, $archivedir, $assoc_file->[1]);
+	}
+	&util::hard_link ($assoc_file->[0], $afile);
+    }
+}
+
+sub infodb {
+    my $self = shift (@_);
+    my ($doc_obj, $filename) = @_;
+    my $handle = $self->{'output_handle'};
+#    $handle = "main::STDOUT";
+
+    my $doctype = $doc_obj->get_doc_type();
+
+    # only output this document if it is one to be indexed
+    return if ($doctype ne "indexed_doc");
+
+    my ($archivedir) = $filename =~ /^(.*?)(?:\/|\\)[^\/\\]*$/;
+    $archivedir = "" unless defined $archivedir;
+    $archivedir =~ s/\\/\//g;
+    $archivedir =~ s/^\/+//;
+    $archivedir =~ s/\/+$//;
+
+    $self->assoc_files ($doc_obj, $archivedir);
+
+    # this is another document
+    $self->{'num_docs'} += 1 unless ($doctype eq "classification");
+
+    # is this a paged or a hierarchical document
+    my ($thistype, $childtype) = $self->get_document_type ($doc_obj);
+
+    my $section = $doc_obj->get_top_section ();
+    my $doc_OID = $doc_obj->get_OID();
+    my $first = 1;
+    my $url = "";
+    while (defined $section) {
+	# update a few statistics
+	$self->{'num_bytes'} += $doc_obj->get_text_length ($section);
+	$self->{'num_sections'} += 1 unless ($doctype eq "classification");
+
+	# output the section name
+	if ($section eq "") { print $handle "[$doc_OID]\n"; }
+	else { print $handle "[$doc_OID.$section]\n"; }
+
+	# output the fact that this document is a document
+	#print $handle "<doctype>doc\n";
+
+	# output whether this node contains text
+	if ($doc_obj->get_text_length($section) > 0) {
+	    print $handle "<hastxt>1\n";
+	} else {
+	    print $handle "<hastxt>0\n";
+	}
+
+	# output all the section metadata
+	my $found_doctype = 0;
+	my $metadata = $doc_obj->get_all_metadata ($section);
+	foreach $pair (@$metadata) {
+	    my ($field, $value) = (@$pair);
+
+	    $found_doctype = 1 if $field eq "doctype";
+	    if ($field ne "Identifier" && $field !~ /^gsdl/ && 
+		defined $value && $value ne "") {
+
+		# escape problematic stuff
+		$value =~ s/\\/\\\\/g;
+		$value =~ s/\n/\\n/g;
+		$value =~ s/\r/\\r/g;
+
+		# special case for URL metadata
+		if ($field =~ /^URL$/i) {
+                    $url .= "[$value]\n";
+                    if ($section eq "") {$url .= "<section>$doc_OID\n";}
+                    else {$url .= "<section>$doc_OID.$section\n";}
+                    $url .= '-' x 70 . "\n";
+		}
+
+		if (!defined $self->{'dontgdbm'}->{$field}) {
+		    print $handle "<$field>$value\n";
+		}
+	    }
+	}
+
+	# output the fact that this document is a document
+	# (unless doctype was already output as part of 
+	# metadata)
+	if (!$found_doctype && !defined $self->{'dontgdbm'}->{'doctype'}) {
+	    print $handle "<doctype>doc\n";
+	}
+	
+	
+
+	# output archivedir if at top level
+	if ($section eq $doc_obj->get_top_section()) {
+	    print $handle "<archivedir>$archivedir\n";
+	}
+
+	# output document display type
+	if ($first) {
+	    print $handle "<thistype>$thistype\n";
+	}
+
+	# output a list of children
+	my $children = $doc_obj->get_children ($section);
+	if (scalar(@$children) > 0) {
+	    print $handle "<childtype>$childtype\n";
+	    print $handle "<contains>";
+	    my $firstchild = 1;
+	    foreach $child (@$children) {
+		print $handle ";" unless $firstchild;
+		$firstchild = 0;
+		if ($child =~ /^.*?\.(\d+)$/) {
+		    print $handle "\".$1";
+		} else {
+		    print $handle "\".$child";
+		}
+#		if ($child eq "") { print $handle "$doc_OID"; }
+#		elsif ($section eq "") { print $handle "$doc_OID.$child"; }
+#		else { print $handle "$doc_OID.$section.$child"; }
+	    }
+	    print $handle "\n";
+	}
+
+	# output the matching document number
+	print $handle "<docnum>$self->{'num_sections'}\n";
+
+	print $handle '-' x 70, "\n";
+
+	
+	# output a database entry for the document number
+	print $handle "[$self->{'num_sections'}]\n";
+	if ($section eq "") { print $handle "<section>$doc_OID\n"; }
+	else { print $handle "<section>$doc_OID.$section\n"; }
+	print $handle '-' x 70, "\n";
+	
+        # output entry for url
+        if ($url ne "") {
+            print $handle $url;
+        }
+
+	$first = 0;
+	$section = $doc_obj->get_next_section($section);
+    }
+
+    # classify this document
+    &classify::classify_doc ($self->{'classifiers'}, $doc_obj);
+
+}
+
+sub find_paragraphs {
+    $_[1] =~ s/(<p\b)/<Paragraph>$1/gi;
+}
+
+sub filter_text {
+    # $self->filter_text ($field, $new_text);
+    # don't want to do anything for this version, however,
+    # in a particular collection you might want to override
+    # this method to post-process certain fields depending on
+    # the field, or whether we are outputting it for indexing
+}
+
+sub text {
+    my $self = shift (@_);
+    my ($doc_obj) = @_;
+    my $handle = $self->{'output_handle'};
+    my $indexed_doc = 1;
+
+    # only output this document if it is one to be indexed
+    return if ($doc_obj->get_doc_type() ne "indexed_doc");
+
+    # see if this document belongs to this subcollection
+    foreach $indexexp (@{$self->{'indexexparr'}}) {
+	$indexed_doc = 0;
+	my ($field, $exp, $options) = split /\//, $indexexp;
+	if (defined ($field) && defined ($exp)) {
+	    my ($bool) = $field =~ /^(.)/;
+	    $field =~ s/^.// if $bool eq '!';
+	    if ($field =~ /^filename$/i) {
+		$field = $doc_obj->get_source_filename();
+	    } else {
+		$field = $doc_obj->get_metadata_element($doc_obj->get_top_section(), $field);
+	    }
+	    next unless defined $field;
+	    if ($bool eq '!') {
+		if ($options =~ /^i$/i) {
+		    if ($field !~ /$exp/i) {$indexed_doc = 1; last;}
+		} else {
+		    if ($field !~ /$exp/) {$indexed_doc = 1; last;}
+		}
+	    } else {
+		if ($options =~ /^i$/i) {
+		    if ($field =~ /$exp/i) {$indexed_doc = 1; last;}
+		} else {
+		    if ($field =~ /$exp/) {$indexed_doc = 1; last;}
+		}
+	    }
+	}
+    }
+
+    # this is another document
+    $self->{'num_docs'} += 1;
+
+    # get the parameters for the output
+    my ($fields) = $self->{'index'};
+    #print STDERR "fields are $fields\n";
+    $fields =~ s/\ball\b/Title,Creator,text/; # add in others here
+
+    my $doc_section = 0; # just for this document
+    my $text = "<Document>\n";
+    my $text_extra = "";
+
+    # get the text for this document
+    my $section = $doc_obj->get_top_section();
+    while (defined $section) {
+	# update a few statistics
+	$doc_section++;
+	$self->{'num_sections'} += 1;
+	$text .= "<Section>\n";
+	if ($indexed_doc) {
+	    $self->{'num_bytes'} += $doc_obj->get_text_length ($section);
+	    foreach $field (split (/,/, $fields)) {
+		# only deal with this field if it doesn't start with top or
+		# this is the first section
+		my $real_field = $field;
+		if (!($real_field =~ s/^top//) || ($doc_section == 1)) {
+		    my $new_text = ""; 
+		    if ($real_field eq "text") {
+			#print STDERR "in text bit";
+			$new_text = "<Paragraph>";
+			$new_text .= $doc_obj->get_text ($section);
+			$self->find_paragraphs($new_text);
+		    } else { # metadata field
+			if ($real_field eq "metadata") { # insert all metadata 
+			                                 #except gsdl stuff
+			    #print STDERR "in metadata bit\n";
+			    my $metadata = $doc_obj->get_all_metadata ($section);
+			    foreach $pair (@$metadata) {
+				my ($mfield, $mvalue) = (@$pair);
+				#print STDERR "$mfield, $mvalue\n";
+				# check fields here, maybe others dont want
+				if ($mfield ne "Identifier" && $mfield ne "classifytype" && 
+				    $mfield !~ /^gsdl/ && defined $mvalue && $mvalue ne "") {
+				   
+					$new_text .= "<Paragraph><$mfield>$mvalue</$mfield>\n";
+					#print STDERR "metadata=$mfield:$mvalue";
+				    
+				}
+			    }
+
+			}
+			else { #individual metadata specified
+			    foreach $item (@{$doc_obj->get_metadata ($section, $real_field)}) {
+				$new_text .= "<Paragraph><$real_field>$item</$real_field>\n";
+			    }
+			}
+
+		    }
+		    
+		    # filter the text
+		    $self->filter_text ($field, $new_text);
+
+		    #????????????????????
+		    if ($self->{'indexing_text'} && 
+			$new_text =~ /[\(\)\{\}]/) {
+		    }
+
+		    $text .= "$new_text";
+		}
+	    }
+	} # if (indexed_doc)
+	
+	$section = $doc_obj->get_next_section($section);
+    } #while defined section
+    print $handle "$text"; 
+}
+
+1;
+
Index: /main/tags/2.25/gsdl/perllib/multiread.pm
===================================================================
--- /main/tags/2.25/gsdl/perllib/multiread.pm	(revision 21064)
+++ /main/tags/2.25/gsdl/perllib/multiread.pm	(revision 21064)
@@ -0,0 +1,350 @@
+###########################################################################
+#
+# multiread.pm --
+#
+# Copyright (C) 1999 DigiLib Systems Limited, NZ
+#
+# 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.
+#
+###########################################################################
+
+# the multiread object will read in a number of encodings,
+# the results are always returned in the utf-8 format
+
+# encodings currently supported are
+#
+# utf8         - either utf8 or unicode (automatically detected)
+# unicode      - just unicode (doesn't currently do endian detection)
+# gb           - GB
+# iso_8859_1   - extended ascii (iso-8859-1)
+# iso_8859_6   - 8 bit arabic (iso-8859-6)
+# windows_1256 - Windows codepage 1256 (Arabic)
+
+package multiread;
+
+use unicode;
+use gb;
+
+sub new {
+    my ($class) = @_;
+
+    my $self = {'handle'    => "",
+		'first'     => 1,
+		'encoding'  => "utf8",
+		'bigendian' => 1};
+
+    return bless $self, $class;
+}
+
+# set_handle expects the file to be already open but
+# not read yet
+sub set_handle {
+    my $self = shift (@_);
+    ($self->{'handle'}) = @_;
+    $self->{'first'} = 1;
+    $self->{'encoding'} = "utf8";
+    $self->{'bigendian'} = 1;
+}
+
+# set_encoding should be called after set_handle
+sub set_encoding {
+    my $self = shift (@_);
+    ($self->{'encoding'}) = @_;
+}
+
+sub get_encoding {
+    my $self = shift (@_);
+    return $self->{'encoding'};
+}
+
+# undef will be returned if the eof has been reached
+# the result will always be returned in utf-8
+# if automatic detection between utf8 and unicode is desired
+# then the encoding should be initially set to utf8
+sub read_char {
+    my $self = shift (@_);
+
+    # make sure we have a file handle
+    return undef if ($self->{'handle'} eq "");
+    my $handle = $self->{'handle'};
+
+    if ($self->{'encoding'} eq "utf8") {
+	# utf-8 text, how many characters we get depends 
+	# on what we find
+	my $c1 = "";
+	my $c2 = "";
+	my $c3 = "";
+
+	while (!eof ($handle)) {
+	    $c1 = ord (getc ($handle));
+	    if ($self->{'first'}) {
+		$self->{'first'} = 0;
+
+		if ($c1 == 0xfe || $c1 == 0xff) {
+		    $c2 = ord (getc ($handle)) if (!eof ($handle));
+		    
+		    # if unicode fall through to the unicode reading code
+		    if ($c1 == 0xff && $c2 == 0xfe) {
+			$self->{'encoding'} = "unicode";
+			$self->{'bigendian'} = 0;
+			if ($ENV{'GSDLOS'} =~ /windows/i) {
+			    binmode ($handle); # silly windows
+			}
+			last;
+
+		    } elsif ($c1 == 0xfe && $c2 == 0xff) {
+			$self->{'encoding'} = "unicode";
+			$self->{'bigendian'} = 1;
+			if ($ENV{'GSDLOS'} =~ /windows/i) {
+			    binmode ($handle); # silly windows
+			}
+			last;
+		    }
+
+		    # an error, but we might be able to recover
+		    # from it
+		    $c1 = $c2;
+		}
+	    }
+
+	    if ($c1 <= 0x7f) {
+		# one byte character
+		return chr ($c1);
+
+	    } elsif ($c1 >= 0xc0 && $c1 <= 0xdf) {
+		# two byte character
+		$c2 = getc ($handle) if (!eof ($handle));
+		return chr ($c1) . $c2;
+
+	    } elsif ($c1 >= 0xe0 && $c1 <= 0xef) {
+		# three byte character
+		$c2 = getc ($handle) if (!eof ($handle));
+		$c3 = getc ($handle) if (!eof ($handle));
+		return chr ($c1) . $c2 . $c3;
+	    }
+
+	    # if we get here there was an error in the file, we should
+	    # be able to recover from it however, maybe the file is in
+	    # another encoding
+	}
+
+	return undef if (eof ($handle));
+    }
+
+    if ($self->{'encoding'} eq "unicode") {
+	# unicode text, get the next two characters
+	return undef if (eof ($handle));
+	my $c1 = ord (getc ($handle));
+	return undef if (eof ($handle));
+	my $c2 = ord (getc ($handle));
+
+	return &unicode::unicode2utf8 ([(($self->{'bigendian'}) ? ($c1*256+$c2) : ($c2*256+$c1))]);
+    }
+
+    if ($self->{'encoding'} eq "gb") {
+	# GB or GBK
+	return undef if (eof ($handle));
+	my $c1 = getc ($handle);
+	if (ord ($c1) >= 0x81) {
+	    # double byte character
+	    return undef if (eof ($handle));
+	    my $c2 = getc ($handle);
+	    return &unicode::unicode2utf8 (&gb::gb2unicode ($c1.$c2));
+	    
+	} else {
+	    # single byte character
+	    return &unicode::ascii2utf8 ($c1);
+	}
+    }
+
+    if ($self->{'encoding'} eq "iso_8859_1") {
+	# Latin 1 extended ascii (ISO-8859-1)
+	return undef if (eof ($handle));
+	return &unicode::ascii2utf8 (getc ($handle));
+    }
+
+    if ($self->{'encoding'} eq "iso_8859_6") {
+	# 8 bit Arabic (IOS-8859-6)
+	return undef if (eof ($handle));
+	return &unicode::unicode2utf8(&unicode::arabic2unicode (getc ($handle)));
+    }
+
+    if ($self->{'encoding'} eq "windows_1256") {
+	# Windows 1256 (Arabic)
+	return undef if (eof ($handle));
+	return &unicode::unicode2utf8(&unicode::windows2unicode ("1256", getc ($handle)));
+    }
+
+    # unknown encoding
+    return undef;
+}
+
+
+# undef will be returned if the eof has been reached
+# the result will always be returned in utf-8
+sub read_line {
+    my $self = shift (@_);
+
+    # make sure we have a file handle
+    return undef if ($self->{'handle'} eq "");
+
+    my $handle = $self->{'handle'};
+
+    if ($self->{'first'} && $self->{'encoding'} eq "utf8") {
+	# special case for the first line of utf8 text to detect whether
+	# the file is in utf8 or unicode
+	my $out = "";
+	my $thisc = "";
+	while (defined ($thisc = $self->read_char())) {
+	    $out .= $thisc;
+	    last if ($thisc eq "\n");
+	}
+	
+	return $out if (length ($out) > 0);
+	return undef;
+    }
+
+
+    if ($self->{'encoding'} eq "utf8") {
+	# utf-8 line
+	return <$handle>;
+    }
+
+    if ($self->{'encoding'} eq "unicode") {
+	# unicode line
+	my $c = "";
+	my ($c1, $c2) = ("", "");
+	my $out = "";
+	while (read ($handle, $c, 2) == 2) {
+	    $c1 = ord (substr ($c, 0, 1));
+	    $c2 = ord (substr ($c, 1, 1));
+	    $c = &unicode::unicode2utf8([(($self->{'bigendian'}) ? ($c1*256+$c2) : ($c2*256+$c1))]);
+	    $out .= $c;
+	    last if ($c eq "\n");
+	}
+
+	return $out if (length ($out) > 0);
+	return undef;
+    }
+
+    if ($self->{'encoding'} eq "gb") {
+	# GB or GBK
+	my $line = "";
+	if (defined ($line = <$handle>)) {
+	    return &unicode::unicode2utf8 (&gb::gb2unicode ($line));
+	}
+	return undef;
+    }
+    
+    if ($self->{'encoding'} eq "iso_8859_1") {
+	# extended ascii (ISO-8859-1)
+	my $line = "";
+	if (defined ($line = <$handle>)) {
+	    return &unicode::ascii2utf8 ($line);
+	}
+	return undef;
+    }
+    
+    if ($self->{'encoding'} eq "iso_8859_6") {
+	# 8 bit arabic (ISO-8859-6)
+	my $line = "";
+	if (defined ($line = <$handle>)) {
+	    return &unicode::unicode2utf8(&unicode::arabic2unicode ($line));
+	}
+	return undef;
+    }
+    
+    if ($self->{'encoding'} eq "windows_1256") {
+	# Windows 1256 (Arabic)
+	my $line = "";
+	if (defined ($line = <$handle>)) {
+	    return &unicode::unicode2utf8(&unicode::windows2unicode ("1256", $line));
+	}
+	return undef;
+    }
+
+    # unknown encoding
+    return undef;
+}
+
+
+# will convert entire contents of file to utf8 and append result to $outputref
+# this may be a slightly faster way to get the contents of a file than by 
+# recursively calling read_line()
+sub read_file {
+    my $self = shift (@_);
+    my ($outputref) = @_;
+
+    # make sure we have a file handle
+    return if ($self->{'handle'} eq "");
+
+    my $handle = $self->{'handle'};
+
+    if ($self->{'first'} && $self->{'encoding'} eq "utf8") {
+	# special case for the first line of utf8 text to detect whether
+	# the file is in utf8 or unicode
+	$$text .= $self->read_line ();
+    }
+
+    if ($self->{'encoding'} eq "utf8") {
+	undef $/;
+	$$outputref .=  <$handle>;
+	$/ = "\n";
+	return;
+    }
+
+    if ($self->{'encoding'} eq "unicode") {
+	my $line = "";
+	while (defined ($line = $self->read_line())) {
+	    $$outputref .= $line;
+	}
+	return;
+    }
+
+    if ($self->{'encoding'} eq "gb") {
+	undef $/;
+	my $text = <$handle>;
+	$/ = "\n";
+	$$outputref .= &unicode::unicode2utf8 (&gb::gb2unicode ($text));
+	return;
+    }
+    
+    if ($self->{'encoding'} eq "iso_8859_1") {
+	undef $/;
+	my $text = <$handle>;
+	$/ = "\n";
+	$$outputref .= &unicode::ascii2utf8 ($text);
+	return;
+    }
+    
+    if ($self->{'encoding'} eq "iso_8859_6") {
+	my $text = <$handle>;
+	undef $/;
+	$/ = "\n";
+	$$outputref .= &unicode::unicode2utf8(&unicode::arabic2unicode ($text));
+	return;
+    }
+
+    if ($self->{'encoding'} eq "windows_1256") {
+	undef $/;
+	my $text = <$handle>;
+	$/ = "\n";
+	$$outputref .= &unicode::unicode2utf8(&unicode::windows2unicode ("1256", $text));
+	return;
+    }
+}
+
+
+1;
Index: /main/tags/2.25/gsdl/perllib/muread.pm
===================================================================
--- /main/tags/2.25/gsdl/perllib/muread.pm	(revision 21064)
+++ /main/tags/2.25/gsdl/perllib/muread.pm	(revision 21064)
@@ -0,0 +1,151 @@
+###########################################################################
+#
+# muread.pm -- read a marked-up file
+#
+# Copyright (C) 1999 DigiLib Systems Limited, NZ
+#
+# 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 muread;
+
+use unicode;
+use multiread;
+
+sub new {
+    my ($class) = @_;
+
+    my $self = {'filename'=>"",
+		'encoding'=>"",
+		'handle'=>"",
+		'reader'=>"",
+		'buffer'=>""};
+
+    return bless $self, $class;
+}
+
+# returns a new tag with a tag name and any options
+sub parse_tag {
+    my $self = shift (@_);
+    my ($orgtagtext) = @_;
+    my $tagtext = $orgtagtext;
+    my $newtag = {};
+    my $misformed = 0;
+
+#    print STDERR "parsing \"$tagtext\"\n";
+
+    # get tag name (if there is one)
+    if ($tagtext =~ /^(\w+)/) {
+	$newtag->{'_tagname'} = $1;
+	$tagtext =~ s/^(\w+)//;
+    } else {
+	print STDERR "muread::parse_tag error - no tag name found\n";
+    }
+
+    # get the tag arguments
+    while ($tagtext =~ /\S/) {
+	$tagtext =~ s/^\s+//s;
+	if ($tagtext =~ /^(\w+)\s*=\s*\"([^\"]*)\"/s) {
+	    $newtag->{$1} = (defined $2) ? $2 : "";
+	    $tagtext =~ s/^\w+\s*=\s*\"[^\"]*\"//s;
+
+	} else {
+	    if (!$misformed) {
+		print STDERR "muread::parse_tag error - miss-formed tag <$orgtagtext>\n";
+		$misformed = 1;
+	    }
+	    $tagtext =~ s/^\S+//s;
+	}
+    }
+
+    return $newtag;
+}
+
+sub read_tag_content {
+    my $self = shift (@_);
+    my ($tag) = @_;
+
+    # all tags contain a _tagname except the tag for the document
+
+    my $line = "";
+    while (1) {
+	# deal with preceeding text
+	if ($self->{'buffer'} =~ /^([^<]+)</s) {
+	    # add preceeding text
+	    $tag->{'_contains'} = [] unless defined $tag->{'_contains'};
+	    push (@{$tag->{'_contains'}}, {'_text'=>$1});
+
+	    $self->{'buffer'} =~ s/^[^<]+</</s;
+	}
+
+	if ($self->{'buffer'} =~ /^<([^>\/]+)>/s) {
+	    # add info from this tag
+	    my $tagtext = $1;
+	    my $newtag = $self->parse_tag ($tagtext);
+	    push (@{$tag->{'_contains'}}, $newtag);
+	    $self->{'buffer'} =~ s/^<[^>\/]+>//s;
+	    
+	    # deal with the contents of this tag
+	    $self->read_tag_content ($newtag);
+
+	} elsif ($self->{'buffer'} =~ /^<\/([^>\/]+)>/s) {
+	    my $tagname = $1;
+	    $self->{'buffer'} =~ s/^<\/[^>\/]+>//s;
+
+	    # check that this tag is the right tag
+	    if (!defined $tag->{'_tagname'} || $tag->{'_tagname'} ne $tagname) {
+		print STDERR "muread::read_tag_content error - mismatched tag </$tagname>, " .
+		    "expected </$tag->{'_tagname'}>\n";
+	    } else {
+		return;
+	    }
+	} elsif (defined ($line = $self->{'reader'}->read_line())) {
+	    $self->{'buffer'} .= $line;
+	} else {
+	    if ($self->{'buffer'} =~ /\S/) {
+		print STDERR "muread::read_tag_content error - can't parse text \"$self->{'buffer'}\"\n";
+	    }
+	    last;
+	}
+    }
+    
+    if (defined $tag->{'_tagname'}) {
+	print STDERR "muread::read_tag_content error - eof reached before closing " .
+	    "tag \"$tag->{'_tagname'}\" found\n";
+    }
+}
+
+sub read_file {
+    my $self = shift (@_);
+    ($self->{'handle'}, $self->{'filename'}, $self->{'encoding'}) = @_;
+    $self->{'encoding'} = "utf8" unless defined $self->{'encoding'};
+
+    my $doc = {};
+
+    # get reader set up
+    $self->{'reader'} = new multiread ();
+    $self->{'reader'}->set_handle ($self->{'handle'});
+    $self->{'reader'}->set_encoding ($self->{'encoding'});
+
+    # read in the file
+    $self->read_tag_content ($doc);
+
+    $self->{'handle'} = "";
+    return $doc;
+}
+
+1;
Index: /main/tags/2.25/gsdl/perllib/parsargv.pm
===================================================================
--- /main/tags/2.25/gsdl/perllib/parsargv.pm	(revision 21064)
+++ /main/tags/2.25/gsdl/perllib/parsargv.pm	(revision 21064)
@@ -0,0 +1,226 @@
+###########################################################################
+#
+# parseargv.pm --
+# A component of the Greenstone digital library software
+# from the New Zealand Digital Library Project at the 
+# University of Waikato, New Zealand.
+#
+# Copyright (C) 1999 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 parsargv;
+# 
+# parse(ARGVREF, [SPEC, VARREF] ...)
+# 
+# Parse command line arguments.
+# 
+# ARGVREF is an array reference, usually to @ARGV.  The remaining
+# arguments are paired (SPEC, VARREF).  SPEC is a specification string
+# for a particular argument; VARREF is a variable reference that will
+# receive the argument.
+# 
+# SPEC is in one of the following forms:
+# 
+# ARG/REGEX/DEFAULT ARG is the name of command line argument.  REGEX is
+#     a regular expression that gives legal values for the argument.
+#     DEFAULT is the default value assigned to VARREF if the option does
+#     not appear on the command line.  Example
+# 
+# 
+# ARG/REGEX ARG and REGEX are as above.  Since no default is given, ARG
+#     must appear on the command line; if it doesn't, parse() returns 0.
+# 
+# ARG ARG is as above.  ARG is a boolean option.  VARREF is assigned 0 if ARG
+#     is not on the command line; 1 otherwise.
+# 
+# SPEC may start with a punctuation character, in which case this
+# character will be used instead of '/' as a delimiter.  Useful when '/'
+# is needed in the REGEX part.
+# 
+# VARREF is a reference to a scalar or an array.  If VARREF is an array
+# reference, then multiple command line options are allowed an append.  Example:
+# 
+# 	Command line: -day mon -day fri
+# 
+# 	parse(\@ARGV, "day/(mon|tue|wed|thu|fri)", \@days)
+# 
+# 	days => ('mon', 'fri')
+# 
+# Returns 0 if there was an error, nonzero otherwise.
+# 
+
+ 
+ sub parse
+{
+    my $arglist = shift;
+    my ($spec, $var);
+    my %option;
+
+    my @rest = @_;
+
+    # if the last argument is the string "allow_extra_options" then options
+    # in \@rest without a corresponding SPEC will be ignored (i.e. the "$arg is
+    # not a valid option" error won't occur)\n";
+    my $allow_extra_options = pop @rest;
+    if (defined ($allow_extra_options)) {
+	if ($allow_extra_options eq "allow_extra_options") {
+	    $allow_extra_options = 1;
+	} else {
+	    # put it back where we got it
+	    push (@rest, $allow_extra_options);
+	    $allow_extra_options = 0;
+	}
+    } else {
+	$allow_extra_options = 0;
+    }
+
+    while (($spec, $var) = splice(@rest, 0, 2))
+        {
+	die "Variable for $spec is not a valid type."
+	    unless ref($var) eq 'SCALAR' || ref($var) eq 'ARRAY';
+
+	my $delimiter;
+	if ($spec !~ /^\w/)
+	{
+	    $delimiter = substr($spec, 0, 1);
+	    $spec = substr($spec, 1);
+	}
+	else
+	{
+	    $delimiter = '/';
+	}
+	my ($name, $regex, $default) = split(/$delimiter/, $spec, 3);
+	
+	if ($name)
+	{
+	    if ($default && $default !~ /$regex/)
+	    {
+		die "Default value for $name doesn't match regex ($spec).";
+	    }
+	    $option{$name} = {'name' => $name,
+			      'regex' => $regex,
+			      'default' => $default,
+			      'varref' => $var,
+			      'set' => 0};
+	}
+	else
+	{
+	    die "Invalid argument ($spec) for parsargv.";
+	}
+    }
+
+    my @argv;
+    my $arg;
+    my $parse_options = 1;
+    my $errors = 0;
+
+    while ($arg = shift(@$arglist))
+    {
+	if ($parse_options && $arg eq '--')
+	{
+	    $parse_options = 0;
+	    next;
+	}
+
+	if ($parse_options && $arg =~ /^-+\w/)
+	{
+	    $arg =~ s/^-+//;
+
+	    if (defined $option{$arg})
+	    {
+		&process_arg($option{$arg}, $arglist, \$errors);
+	    }
+	    elsif (!$allow_extra_options)
+	    {
+		print STDERR "$arg is not a valid option.\n";
+		$errors++;
+	    }
+	}
+	else
+	{
+	    push(@argv, $arg);
+	}
+    }
+    @$arglist = @argv;
+
+    foreach $arg (keys %option)
+    {
+	if ($option{$arg}->{'set'} == 0)
+	{
+	    if (defined $option{$arg}->{'default'})
+	    {
+		&set_var($option{$arg}, $option{$arg}->{'default'});
+	    }
+	    elsif (!$option{$arg}->{'regex'})
+	    {
+		&set_var($option{$arg}, 0)
+	    }
+	    elsif (ref($option{$arg}->{'varref'}) ne 'ARRAY')
+	    {
+		print STDERR "Missing command line argument -$arg.\n";
+		$errors++;
+	    }
+	}
+    }
+    return $errors == 0;
+}
+
+sub process_arg
+{
+    my ($option, $arglist, $errors) = @_;
+
+    if ($option->{'regex'} && @$arglist > 0 && $arglist->[0] !~ /^-+\w/)
+    {
+	if ($arglist->[0] =~ /$option->{'regex'}/)
+	{
+	    &set_var($option, shift(@$arglist));
+	}
+	else
+	{
+	    print STDERR "Bad value for -$option->{'name'} argument.\n";
+	    $$errors++;
+	}
+    }
+    elsif (!$option->{'regex'})
+    {
+	&set_var($option, 1);
+    }
+    else
+    {
+	print STDERR "No value given for -$option->{'name'}.\n";
+	$$errors++;
+    }
+}
+
+sub set_var
+{
+    my ($option, $value) = @_;
+    my $type = ref($option->{'varref'});
+
+    if ($type eq 'SCALAR')
+    {
+	${$option->{'varref'}} = $value;
+    }
+    elsif ($type eq 'ARRAY')
+    {
+	push(@{$option->{'varref'}}, $value);
+    }
+    $option->{'set'} = 1;
+}
+
+1;
Index: /main/tags/2.25/gsdl/perllib/plugin.pm
===================================================================
--- /main/tags/2.25/gsdl/perllib/plugin.pm	(revision 21064)
+++ /main/tags/2.25/gsdl/perllib/plugin.pm	(revision 21064)
@@ -0,0 +1,100 @@
+###########################################################################
+#
+# plugin.pm -- functions to handle using plugins
+# A component of the Greenstone digital library software
+# from the New Zealand Digital Library Project at the 
+# University of Waikato, New Zealand.
+#
+# Copyright (C) 1999 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 plugin;
+
+require util;
+
+sub load_plugins {
+    my ($plugin_list, $verbosity) = @_;
+    my @plugin_objects = ();
+
+    $verbosity = 2 unless defined $verbosity;
+
+    foreach $pluginoptions (@$plugin_list) {
+	my $pluginname = shift @$pluginoptions;
+	next unless defined $pluginname;
+
+	# find the plugin
+	my $colplugname = &util::filename_cat($ENV{'GSDLCOLLECTDIR'},"perllib/plugins", 
+					      "${pluginname}.pm");
+	my $mainplugname = &util::filename_cat($ENV{'GSDLHOME'},"perllib/plugins", 
+					       "${pluginname}.pm");
+	if (-e $colplugname) { require $colplugname; }
+	elsif (-e $mainplugname) { require $mainplugname; }
+	else { die "ERROR - couldn't find plugin \"$pluginname\"\n"; }
+
+	# create a plugin object
+	my ($plugobj);
+	map { $_ = "\"$_\""; } @$pluginoptions;
+	my $options = join (",", @$pluginoptions);
+	$options =~ s/\$/\\\$/g;
+	eval ("\$plugobj = new \$pluginname($options)");
+	die "$@" if $@;
+	
+	# initialize plugin
+	$plugobj->init($verbosity);
+
+	# add this object to the list
+	push (@plugin_objects, $plugobj);
+    }
+
+    return \@plugin_objects;
+}
+
+
+sub begin {
+    my ($pluginfo, $base_dir, $processor, $maxdocs) = @_;
+
+    map { $_->begin($pluginfo, $base_dir, $processor, $maxdocs); } @$pluginfo;
+}
+
+sub read {
+    my ($pluginfo, $base_dir, $file, $metadata, $processor, $maxdocs, $aux) = @_;
+
+    $maxdocs = -1 unless defined $maxdocs && $maxdocs =~ /\d/;
+    my $rv = 0;
+
+    # pass this file by each of the plugins in turn until one
+    # is found which will process it
+    foreach $plugobj (@$pluginfo) {
+	$rv = $plugobj->read($pluginfo, $base_dir, $file, 
+			     $metadata, $processor, $maxdocs, $aux);
+	return $rv if defined $rv;
+    }
+    
+    if (defined $processor->{'verbosity'} && $processor->{'verbosity'} >= 2) {
+	print STDERR "WARNING - no plugin could process " . 
+	    &util::filename_cat($base_dir,$file) . "\n";
+    }
+    return 0;
+}
+
+sub end {
+    my	($pluginfo) = @_;
+    map { $_->end(); } @$pluginfo;
+}
+
+1;
Index: /main/tags/2.25/gsdl/perllib/plugins/ArcPlug.pm
===================================================================
--- /main/tags/2.25/gsdl/perllib/plugins/ArcPlug.pm	(revision 21064)
+++ /main/tags/2.25/gsdl/perllib/plugins/ArcPlug.pm	(revision 21064)
@@ -0,0 +1,97 @@
+###########################################################################
+#
+# ArcPlug.pm --
+# A component of the Greenstone digital library software
+# from the New Zealand Digital Library Project at the 
+# University of Waikato, New Zealand.
+#
+# Copyright (C) 1999 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.
+#
+###########################################################################
+
+# plugin which recurses through an archives.inf file
+# (i.e. the file generated in the archives directory
+# when an import is done), processing each file it finds 
+
+package ArcPlug;
+
+use util;
+use BasPlug;
+use plugin;
+use arcinfo;
+
+BEGIN {
+    @ISA = ('BasPlug');
+}
+
+use strict;
+
+sub new {
+    my ($class) = @_;
+    my $self = new BasPlug ("ArcPlug", @_);
+
+    return bless $self, $class;
+}
+
+# return 1 if this class might recurse using $pluginfo
+sub is_recursive {
+    my $self = shift (@_);
+
+    return 1;
+}
+
+# return number of files processed, undef if can't process
+# Note that $base_dir might be "" and that $file might 
+# include directories
+sub read {
+    my $self = shift (@_);
+    my ($pluginfo, $base_dir, $file, $metadata, $processor, $maxdocs) = @_;
+
+    my $count = 0;
+
+    # see if this has a archives information file within it
+    my $archive_info_filename = &util::filename_cat($base_dir,$file,"archives.inf");
+
+    if (-e $archive_info_filename) {
+
+	# found an archives.inf file
+	print STDERR "ArcPlug: processing $archive_info_filename\n";
+
+	# read in the archives information file
+	my $archive_info = new arcinfo ();
+	$archive_info->load_info ($archive_info_filename);
+	
+	my $file_list = $archive_info->get_file_list();
+
+	# process each file
+	foreach my $subfile (@$file_list) {
+	    last if ($maxdocs != -1 && $count >= $maxdocs);
+
+	    my $tmp = &util::filename_cat ($file, $subfile->[0]);
+	    next if $tmp eq $file;
+	    # note: metadata is not carried on to the next level
+	    $count += &plugin::read ($pluginfo, $base_dir, $tmp, {}, $processor, $maxdocs);
+	}
+
+	return $count;
+    }
+
+    # wasn't an archives directory, someone else will have to process it
+    return undef;
+}
+
+1;
Index: /main/tags/2.25/gsdl/perllib/plugins/BasPlug.pm
===================================================================
--- /main/tags/2.25/gsdl/perllib/plugins/BasPlug.pm	(revision 21064)
+++ /main/tags/2.25/gsdl/perllib/plugins/BasPlug.pm	(revision 21064)
@@ -0,0 +1,382 @@
+###########################################################################
+#
+# BasPlug.pm -- base class for all the import plugins
+# A component of the Greenstone digital library software
+# from the New Zealand Digital Library Project at the 
+# University of Waikato, New Zealand.
+#
+# Copyright (C) 1999 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 BasPlug;
+
+use parsargv;
+use multiread;
+use cnseg;
+use acronym;
+use textcat;
+use strict;
+use doc;
+use diagnostics;
+
+sub print_general_usage {
+    my ($plugin_name) = @_;
+
+    print STDERR "\n  usage: plugin $plugin_name [options]\n\n";
+    print STDERR "   -input_encoding   The encoding of the source documents. Documents will be\n";
+    print STDERR "                     converted from these encodings and stored internally as\n";
+    print STDERR "                     utf8. The default input_encoding is ascii. Accepted values\n";
+    print STDERR "                     are:\n";
+    print STDERR "                        iso_8859_1 (extended ascii)\n";
+    print STDERR "                        Latin1 (the same as iso-8859-1)\n";
+    print STDERR "                        ascii (7 bit ascii -- may be faster than Latin1 as no\n";
+    print STDERR "                               conversion is neccessary)\n";
+    print STDERR "                        gb (GB or GBK simplified Chinese)\n";
+    print STDERR "                        iso_8859_6 (8 bit Arabic)\n";
+    print STDERR "                        windows_1256 (Windows codepage 1256 (Arabic))\n";
+    print STDERR "                        Arabic (the same as windows_1256)\n";
+    print STDERR "                        utf8 (either utf8 or unicode -- automatically detected)\n";
+    print STDERR "                        unicode (just unicode -- doesn't currently do endian\n";
+    print STDERR "                                 detection)\n";
+    print STDERR "   -process_exp      A perl regular expression to match against filenames.\n";
+    print STDERR "                     Matching filenames will be processed by this plugin.\n";
+    print STDERR "                     Each plugin has its own default process_exp. e.g HTMLPlug\n";
+    print STDERR "                     defaults to '(?i)\.html?\$' i.e. all documents ending in\n";
+    print STDERR "                     .htm or .html (case-insensitive).\n";
+    print STDERR "   -block_exp        Files matching this regular expression will be blocked from\n";
+    print STDERR "                     being passed to any further plugins in the list. This has no\n";
+    print STDERR "                     real effect other than to prevent lots of warning messages\n";
+    print STDERR "                     about input files you don't care about. Each plugin may or may\n";
+    print STDERR "                     not have a default block_exp. e.g. by default HTMLPlug blocks\n";
+    print STDERR "                     any files with .gif, .jpg, .jpeg, .png, .pdf, .rtf or .css\n";
+    print STDERR "                     file extensions.\n";
+    print STDERR "   -extract_acronyms Extract acronyms from within text and set as metadata\n\n";
+    print STDERR "   -extract_langauge Identify the language of the text and set as metadata\n\n";
+}
+
+# print_usage should be overridden for any sub-classes having 
+# their own plugin specific options
+sub print_usage {
+    print STDERR "\nThis plugin has no plugin specific options\n\n";
+
+}
+
+sub new {
+    my $class = shift (@_);
+    my $plugin_name = shift (@_);
+
+    my $self = {};
+    my $encodings = "^(iso_8859_1|Latin1|ascii|gb|iso_8859_6|windows_1256|Arabic|utf8|unicode)\$";
+
+    # general options available to all plugins
+    if (!parsargv::parse(\@_,
+			 qq^input_encoding/$encodings/ascii^, \$self->{'input_encoding'},
+			 q^process_exp/.*/^, \$self->{'process_exp'},
+			 q^block_exp/.*/^, \$self->{'block_exp'},
+			 q^extract_acronyms^, \$self->{'extract_acronyms'},
+			 q^extract_language^, \$self->{'extract_language'},
+			 "allow_extra_options")) {
+
+	print STDERR "\nThe $plugin_name plugin uses an incorrect general option (general options are those\n";
+	print STDERR "available to all plugins). Check your collect.cfg configuration file.\n";
+    	&print_general_usage($plugin_name);
+	die "\n";
+    }
+
+    return bless $self, $class;
+}
+
+# initialize BasPlug options
+# if init() is overridden in a sub-class, remember to call BasPlug::init()
+sub init {
+    my $self = shift (@_);
+    my ($verbosity) = @_;
+
+    # verbosity is passed through from the processor
+    $self->{'verbosity'} = $verbosity;
+
+    # set process_exp and block_exp to defaults unless they were
+    # explicitly set
+
+    if ((!$self->is_recursive()) and 
+	(!defined $self->{'process_exp'}) || ($self->{'process_exp'} eq "")) {
+
+	$self->{'process_exp'} = $self->get_default_process_exp ();
+	if ($self->{'process_exp'} eq "") {
+	    warn ref($self) . " Warning: Non-recursive plugin has no process_exp\n";
+	}
+    }
+
+    if ((!defined $self->{'block_exp'}) || ($self->{'block_exp'} eq "")) {
+	$self->{'block_exp'} = $self->get_default_block_exp ();
+    }
+    
+    # handle input_encoding aliases
+    $self->{'input_encoding'} = "iso_8859_1" if $self->{'input_encoding'} eq "Latin1";
+    $self->{'input_encoding'} = "windows_1256" if $self->{'input_encoding'} eq "Arabic";
+}
+
+sub begin {
+    my $self = shift (@_);
+    my ($pluginfo, $base_dir, $processor, $maxdocs) = @_;
+}
+
+sub end {
+    my ($self) = @_;
+}
+
+# this function should be overridden to return 1
+# in recursive plugins
+sub is_recursive {
+    my $self = shift (@_);
+
+    return 0; 
+}
+
+sub get_default_block_exp {
+    my $self = shift (@_);
+
+    return "";
+}
+
+sub get_default_process_exp {
+    my $self = shift (@_);
+
+    return "";
+}
+
+# The BasPlug read() function. This function does all the right things
+# to make general options work for a given plugin. It calls the process()
+# function which does all the work specific to a plugin (like the old
+# read functions used to do). Most plugins should define their own 
+# process() function and let this read() function keep control.
+#
+# recursive plugins (e.g. RecPlug) and specialized plugins like those
+# capable of processing many documents within a single file (e.g.
+# GMLPlug) should normally implement their own version of read()
+#
+# Return number of files processed, undef if can't process
+# Note that $base_dir might be "" and that $file might 
+# include directories
+
+sub read {
+    my $self = shift (@_);
+    my ($pluginfo, $base_dir, $file, $metadata, $processor, $maxdocs) = @_;
+
+    if ($self->is_recursive()) {
+	die "BasPlug::read function must be implemented in sub-class for recursive plugins\n";
+    }
+
+    my $filename = &util::filename_cat($base_dir, $file);
+    return 0 if $self->{'block_exp'} ne "" && $filename =~ /$self->{'block_exp'}/;
+    if ($filename !~ /$self->{'process_exp'}/ || !-f $filename) {
+	return undef;
+    }
+    my $plugin_name = ref ($self);
+    $file =~ s/^[\/\\]+//; # $file often begins with / so we'll tidy it up
+    
+    # create a new document
+    my $doc_obj = new doc ($filename, "indexed_doc");
+    
+    # read in file ($text will be in utf8)
+    my $text = "";
+    $self->read_file ($filename, \$text);
+
+    if ($text !~ /\w/) {
+	print STDERR "$plugin_name: ERROR: $file contains no text\n" if $self->{'verbosity'};
+	return 0;
+    }
+
+    # include any metadata passed in from previous plugins 
+    # note that this metadata is associated with the top level section
+    $self->extra_metadata ($doc_obj, $doc_obj->get_top_section(), $metadata);
+
+    # do plugin specific processing of doc_obj
+    return undef unless defined ($self->process (\$text, $pluginfo, $base_dir, $file, $metadata, $doc_obj));
+
+    # do any automatic metadata extraction
+    $self->auto_extract_metadata ($doc_obj);
+
+    # add an OID
+    $doc_obj->set_OID();
+
+    # process the document
+    $processor->process($doc_obj);
+
+    return 1; # processed the file
+}
+
+# returns undef if file is rejected by the plugin
+sub process {
+    my $self = shift (@_);
+    my ($textref, $pluginfo, $base_dir, $file, $metadata, $doc_obj) = @_;
+
+    die "Basplug::process function must be implemented in sub-class\n";
+
+    return undef; # never gets here
+}
+
+# uses the multiread package to read in the entire file pointed to
+# by filename and loads the resulting text into $$textref. Input text
+# may be in any of the encodings handled by multiread, output text
+# will be in utf8
+sub read_file {
+    my $self = shift (@_);
+    my ($filename, $textref) = @_;
+
+    $$textref = "";
+
+    open (FILE, $filename) || die "BasPlug::read_file could not open $filename for reading ($!)\n";
+
+    if ($self->{'input_encoding'} eq "ascii") {
+	undef $/;
+	$$textref = <FILE>;
+	$/ = "\n";
+    } else {
+	my $reader = new multiread();
+	$reader->set_handle ('BasPlug::FILE');
+	$reader->set_encoding ($self->{'input_encoding'});
+	$reader->read_file ($textref);
+
+	if ($self->{'input_encoding'} eq "gb") {
+	    # segment the Chinese words
+	    $$textref = &cnseg::segment($$textref);
+	}
+    }
+
+    close FILE;
+}
+
+# add any extra metadata that's been passed around from one
+# plugin to another.
+# extra_metadata uses add_utf8_metadata so it expects metadata values
+# to already be in utf8
+sub extra_metadata {
+    my $self = shift (@_);
+    my ($doc_obj, $cursection, $metadata) = @_;
+
+    foreach my $field (keys(%$metadata)) {
+	# $metadata->{$field} may be an array reference
+	if (ref ($metadata->{$field}) eq "ARRAY") {
+	    map { 
+		$doc_obj->add_utf8_metadata ($cursection, $field, $_); 
+	    } @{$metadata->{$field}};
+	} else {
+	    $doc_obj->add_utf8_metadata ($cursection, $field, $metadata->{$field}); 
+	}
+    }
+}
+
+# extract acronyms (and hopefully other stuff soon too).
+sub auto_extract_metadata {
+    my $self = shift (@_);
+    my ($doc_obj) = @_;
+
+    if ($self->{'extract_acronyms'}) {
+	my $thissection = $doc_obj->get_top_section();
+	while (defined $thissection) {
+	    my $text = $doc_obj->get_text($thissection);
+	    $self->extract_acronyms (\$text, $doc_obj, $thissection) if $text =~ /./;
+	    $thissection = $doc_obj->get_next_section ($thissection);
+	}
+    }
+
+    if ($self->{'extract_language'}) {
+	my $thissection = $doc_obj->get_top_section();
+	while (defined $thissection) {
+	    my $text = $doc_obj->get_text($thissection);
+	    $self->extract_language (\$text, $doc_obj, $thissection) if $text =~ /./;
+	    $thissection = $doc_obj->get_next_section ($thissection);
+	}
+    }
+
+}
+
+
+# Identify the language of a section and add it to the metadata
+sub extract_language {
+    my $self = shift (@_);
+    my ($textref, $doc_obj, $thissection) = @_;
+
+    # remove all HTML tags
+    my $text = $$textref;
+    $text =~ s/<P[^>]*>/\n/sgi;
+    $text =~ s/<H[^>]*>/\n/sgi;
+    $text =~ s/<[^>]*>//sgi;
+    $text =~ tr/\n/\n/s;
+
+    # get the language
+    my @results = textcat::classify($text);
+    @results = ("unknown") if ($#results > 2);
+
+    # create language string and remove encoding information
+    my $language = join(" or ", @results);
+    $language =~ s/\-\w+//g;
+    $doc_obj->add_utf8_metadata($thissection, "Language",  $language);
+    # print "Language: ", time, "-> $language\n";
+
+}
+
+# extract acronyms from a section in a document. progress is 
+# reported to STDERR based on the verbosity. both the Acronym
+# and the AcronymKWIC metadata items are created. 
+
+sub extract_acronyms {
+    my $self = shift (@_);
+    my ($textref, $doc_obj, $thissection) = @_;
+
+    print STDERR " checking for acronyms ...\n" 
+	if ($self->{'verbosity'} >= 2);
+
+    my $acro_array =  &acronym::acronyms($textref);
+    
+    foreach my $acro (@$acro_array) {
+
+	#check that this is the first time ...
+	my $seen_before = "false";
+	my $previous_data = $doc_obj->get_metadata($thissection, "Acronym");
+	foreach my $thisAcro (@$previous_data) {
+	    if ($thisAcro eq $acro->to_string())
+	    {
+		$seen_before = "true";
+		print STDERR "  already seen ". $acro->to_string() . "\n" 
+		    if ($self->{'verbosity'} >= 2);
+	    } 	    
+	}
+
+	if ($seen_before eq "false")
+	{
+	    #do the normal acronym
+	    $doc_obj->add_utf8_metadata($thissection, "Acronym",  $acro->to_string());
+		print STDERR "  adding ". $acro->to_string() . "\n" 
+		    if ($self->{'verbosity'} >= 1);
+	    
+	    # do the KWIC (Key Word In Context) acronym
+	    my @kwic = $acro->to_string_kwic();
+	    foreach my $kwic (@kwic) {
+		$doc_obj->add_utf8_metadata($thissection, "AcronymKWIC",  $kwic);
+		print STDERR "   adding ".  $kwic . "\n" 
+		    if ($self->{'verbosity'} >= 2);
+	    }
+	}
+    }
+    print STDERR " done with acronyms. \n" 
+	if ($self->{'verbosity'} >= 2);
+}
+
+1;
Index: /main/tags/2.25/gsdl/perllib/plugins/EMAILPlug.pm
===================================================================
--- /main/tags/2.25/gsdl/perllib/plugins/EMAILPlug.pm	(revision 21064)
+++ /main/tags/2.25/gsdl/perllib/plugins/EMAILPlug.pm	(revision 21064)
@@ -0,0 +1,206 @@
+###########################################################################
+#
+# EMAILPlug.pm - a plugin for parsing email files
+#
+# A component of the Greenstone digital library software
+# from the New Zealand Digital Library Project at the 
+# University of Waikato, New Zealand.
+#
+# Copyright (C) 1999 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.
+#
+###########################################################################
+
+
+
+# EMAILPlug
+#
+# by Gordon Paynter (gwp@cs.waikato.ac.nz)
+#
+# Email plug reads email files.  These are named with a simple
+# number (i.e. as they appear in mh_mail folders) or with the 
+# extension .email
+#
+# Document text:
+#   The document text consists of all the text 
+#   after the first blank line in the document.
+#
+# Metadata:
+#   $Headers      All the header content
+#   $Subject      Subject: header
+#   $To           To: header
+#   $From         From: header - this will be stored as Creator
+#   $DateText     Date: header
+#   $Date         Date: header in GSDL format (eg: 19990924)
+#
+# Version history
+#
+# 1.2   (2000 Jun 12) Major rewrite.
+#       (The new version of Greenstone breaks some of the metadata.)
+# 1.1.1 Compensated for two-digit years like "95"
+# 1.1   (1999 Sep 20) Introduced the various metadata fileds
+# 1.0   Based on the original HTMLPlug code
+#
+
+
+package EMAILPlug;
+
+use BasPlug;
+use sorttools;
+use util;
+
+
+# EMAILPlug is a sub-class of BasPlug.
+
+sub BEGIN { 
+    @ISA = ('BasPlug');
+}
+
+use strict;
+
+# Create a new EMAILPlug object with which to parse a file.
+# Accomplished by creating a new BasPlug and using bless to 
+# turn it into an EMAILPlug.
+
+sub new {
+    my ($class) = @_;
+    my $self = new BasPlug ("EMAILPlug", @_);
+
+    return bless $self, $class;
+}
+
+sub get_default_process_exp {
+    my $self = shift (@_);
+
+    return q^\d+(\.email)?$^;
+}
+
+# do plugin specific processing of doc_obj
+sub process {
+    my $self = shift (@_);
+    my ($textref, $pluginfo, $base_dir, $file, $metadata, $doc_obj) = @_;
+    
+    # Check that we're dealing with a valid mail file
+    return undef unless (($$textref =~ /From:/) || ($$textref =~ /To:/));
+
+    print STDERR "EMAILPlug: processing $file\n" 
+	if $self->{'verbosity'} > 1;
+
+    my $cursection = $doc_obj->get_top_section();
+
+    #
+    # Parse the document's text and extract metadata
+    #
+
+    # Separate header from body of message
+    my $Headers = $$textref;
+    $Headers =~ s/\n\n.*//s;
+    $$textref = substr $$textref, (length $Headers);
+
+    # Extract basic metadata from header
+    my @headers = ("From", "To", "Subject", "Date");
+    my $value = ""; 
+    my %raw;
+
+    foreach my $name (@headers) {
+	$value = $Headers; 
+	$value =~ s/.*$name://s;
+	$value =~ s/\S*:.*//s;
+	$value =~ s/\s*$//;
+	$value =~ s/\s+/ /g;
+	$raw{$name} = $value;
+    }
+
+    # Process Date information
+    if ($raw{"Date"}) {
+	$raw{"DateText"} = $raw{"Date"};
+	
+	# Convert the date text to internal date format
+	$value = $raw{"Date"};
+	my ($day, $month, $year) = $value =~ /(\d?\d)\s([A-Z][a-z][a-z])\s(\d\d\d?\d?)/;
+	if ($year < 100) { $year += 1900; }
+	$raw{"Date"} = &sorttools::format_date($day, $month, $year);
+	
+    } else {
+	# We have not extracted a date
+	$raw{"DateText"} = "Unknown.";
+	$raw{"Date"} = "19000000";
+    }
+
+
+    # Add extracted metadata to document object
+    foreach my $name (keys %raw) {
+	$value = $raw{$name};
+	if ($value) {
+	    $value = &text_into_html($value);
+	} else {
+	    $value = "No $name field";
+	}
+	$doc_obj->add_utf8_metadata ($cursection, $name, $value);
+    }
+
+    # Add "All headers" metadata
+    $Headers = &text_into_html($Headers);
+    $Headers = "No headers" unless ($Headers =~ /\w/);
+    $doc_obj->add_utf8_metadata ($cursection, "Headers", $Headers);
+
+    # Add text to document object
+    $$textref = &text_into_html($$textref);
+    $$textref = "No message" unless ($$textref =~ /\w/);
+    $doc_obj->add_utf8_text($cursection, $$textref);
+
+    return 1;
+}
+
+
+# Convert a text string into HTML.
+#
+# The HTML is going to be inserted into a GML file, so 
+# we have to be careful not to use symbols like ">",
+# which ocurs frequently in email messages (and use
+# &gt instead.
+#
+# This function also turns links and email addresses into hyperlinks,
+# and replaces carriage returns with <BR> tags (and multiple carriage
+# returns with <P> tags).
+
+
+sub text_into_html {
+    my ($text) = @_;
+
+    # Convert problem characters into HTML symbols
+    $text =~ s/&/&amp;/go;
+    $text =~ s/</&lt;/go;
+    $text =~ s/>/&gt;/go;
+    $text =~ s/\"/&quot;/go;
+
+    # convert email addresses and URLs into links
+    $text =~ s/([\w\d\.\-]+@[\w\d\.\-]+)/<a href=\"mailto:$1\">$1<\/a>/g;
+    $text =~ s/(http:\/\/[\w\d\.\-]+[\/\w\d\.\-~]*)/<a href=\"$1\">$1<\/a>/g;
+
+    # Clean up whitespace and convert \n charaters to <BR> or <P>
+    $text =~ s/ +/ /go;
+    $text =~ s/\s*$//o; 
+    $text =~ s/^\s*//o; 
+    $text =~ s/\n/\n<BR>/go;
+    $text =~ s/<BR>\s*<BR>/<P>/go;
+
+    return $text;
+}
+
+
+# Perl packages have to return true if they are run.
+1;
Index: /main/tags/2.25/gsdl/perllib/plugins/FOXPlug.pm
===================================================================
--- /main/tags/2.25/gsdl/perllib/plugins/FOXPlug.pm	(revision 21064)
+++ /main/tags/2.25/gsdl/perllib/plugins/FOXPlug.pm	(revision 21064)
@@ -0,0 +1,257 @@
+###########################################################################
+#
+# FOXPlug.pm
+# A component of the Greenstone digital library software
+# from the New Zealand Digital Library Project at the 
+# University of Waikato, New Zealand.
+#
+# Copyright (C) 1999 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.
+#
+###########################################################################
+
+# plugin to process a Foxbase dbt file. This plugin provides the basic
+# functionality to read in the dbt and dbf files and process each record.
+# This general plugin should be overridden for a particular database to process
+# the appropriate fields in the file.
+
+package FOXPlug;
+
+use BasPlug;
+use util;
+use doc;
+use unicode;
+use cnseg;
+use gb;
+
+
+sub BEGIN {
+    @ISA = ('BasPlug');
+}
+
+sub new {
+    my ($class) = @_;
+    $self = new BasPlug ();
+
+    return bless $self, $class;
+}
+
+sub is_recursive {
+    my $self = shift (@_);
+
+    return 0; # this is not a recursive plugin
+}
+
+
+# return number of files processed, undef if can't process
+# Note that $base_dir might be "" and that $file might 
+# include directories
+sub read {
+    my $self = shift (@_);
+    my ($pluginfo, $base_dir, $file, $metadata, $processor) = @_;
+    my $fullname = &util::filename_cat ($base_dir, $file);
+
+    # dbt files are processed at the same time as dbf files
+    return 0 if ($fullname =~ /\.dbt$/i);
+
+    # see if this is a foxbase database
+    return undef unless (-f $fullname && $fullname =~ /\.dbf$/i);
+
+    my ($parent_dir) = $fullname =~ /^(.*)\/[^\/]+\.dbf$/i;
+
+    # open the file
+    if (!open (FOXBASEIN, $fullname)) {
+	print STDERR "FOXPlug::read - couldn't read $fullname\n";
+	return undef;
+    }
+    
+    print STDERR "FOXPlug: processing $file\n";
+
+    # read in the database header
+    my ($temp, %dbf);
+    
+    # read in information about dbt file
+    if (read (FOXBASEIN, $temp, 32) < 32) {
+	print STDERR "FOXPlug::read - eof while reading database header";
+	close (FOXBASEIN);
+	return undef;
+    }
+    
+    # unpack the header
+    ($dbf{'hasdbt'},
+     $dbf{'modyear'}, $dbf{'modmonth'}, $dbf{'modday'},
+     $dbf{'numrecords'}, $dbf{'headerlen'}, 
+     $dbf{'recordlen'}) = unpack ("CCCCVvv", $temp);
+    
+    # process hasdbt
+    if ($dbf{'hasdbt'} == 131) {
+	$dbf{'hasdbt'} = 1;
+    } elsif ($dbf{'hasdbt'} == 3) {
+	$dbf{'hasdbt'} = 0;
+    } else {
+	print STDERR "FOXPlug:read $fullname doesn't seem to be a Foxbase file\n";
+	return undef;
+    }
+
+    # read in the field description
+    $dbf{'numfields'} = 0;
+    $dbf{'fieldinfo'} = [];
+    while (read (FOXBASEIN, $temp, 1) > 0) {
+	last if ($temp eq "\x0d");
+	last if (read (FOXBASEIN, $temp, 31, 1) < 31);
+
+	my %field = ();
+	$field{'name'} = $self->extracttext($temp, 11);
+	($field{'type'}, $field{'pos'}, $field{'len'}, $field{'dp'}) 
+	    = unpack ("x11a1VCC", $temp);
+
+	push (@{$dbf{'fieldinfo'}}, \%field);
+
+	$dbf{'numfields'} ++;
+    }
+
+    # open the dbt file if we need to
+    $dbtfullname = $fullname;
+    if ($fullname =~ /f$/) {
+	$dbtfullname =~ s/f$/t/;
+    } else {
+	$dbtfullname =~ s/F$/T/;
+    }
+    if ($dbf{'hasdbt'} && !open (DBTIN, $dbtfullname)) {
+	print STDERR "FOXPlug::read - couldn't read $dbtfullname\n";
+	close (FOXBASEIN);
+	return undef;
+    }
+
+    # read in and process each record in the database
+    my $numrecords = 0;
+    while (($numrecords < $dbf{'numrecords'}) && 
+	   (read (FOXBASEIN, $temp, $dbf{'recordlen'}) == $dbf{'recordlen'})) {
+
+	# create a new record
+	my $record = [];
+	
+	foreach $field (@{$dbf{'fieldinfo'}}) {
+	    my $fieldvalue = "";
+	    
+	    if ($field->{'type'} eq "M" && $dbf{'hasdbt'}) {
+		# a memo field, look up this field in the dbt file
+		my $seekpos = substr ($temp, $field->{'pos'}, $field->{'len'});
+
+		$seekpos =~ s/^\s*//;
+		$seekpos = 0 unless $seekpos =~ /^\d+$/;
+		
+		$seekpos = $seekpos * 512;
+
+		if ($seekpos == 0) {
+		    # there is no memo field
+
+		} elsif (seek (DBTIN, $seekpos, 0)) {
+		    while (read (DBTIN, $fieldvalue, 512, length($fieldvalue)) > 0) {
+			last if ($fieldvalue =~ /\cZ/);
+		    }
+
+		    # remove everything after the control-Z
+		    substr($fieldvalue, index($fieldvalue, "\cZ")) = "";
+
+		} else {
+		    print STDERR "\nERROR - seek (to $seekpos) failed\n";
+		}
+
+	    } else {
+		# a normal field
+		$fieldvalue = substr ($temp, $field->{'pos'}, $field->{'len'});
+	    }
+
+	    push (@$record, {%$field, 'value'=>$fieldvalue});
+	}
+
+	# process this record
+	$self->process_record ($pluginfo, $base_dir, $file, $metadata, $processor, 
+			       $numrecords, $record);
+	
+	# finished another record...
+	$numrecords++;
+    }
+
+    # close the dbt file if we need to
+    if ($dbf{'hasdbt'}) {
+	close (DBTIN);
+    }
+
+    # close the dbf file
+    close (FOXBASEIN);
+
+    # finished processing
+    return 1;
+}
+
+
+# will extract a string from some larger string, making it
+# conform to a number of constraints
+sub extracttext {
+    my $self = shift (@_);
+    my ($text, $maxlen, $offset, $stopstr) = @_;
+    $offset = 0 unless defined $offset;
+    $stopstr = "\x00" unless defined $stopstr;
+    
+    # decide where the string finishes
+    my $end = index ($text, $stopstr, $offset);
+    $end = length ($text) if $end < 0;
+    $end = $offset+$maxlen if (defined $maxlen) && ($end-$offset > $maxlen);
+    
+    return "" if ($end <= $offset);
+    return substr ($text, $offset, $end-$offset);
+}
+
+
+# process_record should be overriden for a particular type
+# of database. This default version outputs an html document
+# containing all the fields in the record as a table.
+# It also assumes that the text is in utf-8.
+sub process_record {
+    my $self = shift (@_);
+    my ($pluginfo, $base_dir, $file, $metadata, $processor, $numrecords, $record) = @_;
+
+    # create a new document
+    my $doc_obj = new doc ($file, "indexed_doc");
+    my $section = $doc_obj->get_top_section();
+
+    # start of document
+    $doc_obj->add_utf8_text($section, "<table>\n");
+
+    # add each field
+    foreach $field (@$record) {
+	if (defined ($field->{'name'}) && defined ($field->{'value'})) {
+	    $doc_obj->add_utf8_text($section, "  <tr>\n");
+	    $doc_obj->add_utf8_text($section, "    <td>$field->{'name'}</td>\n");
+	    $doc_obj->add_utf8_text($section, "    <td>$field->{'value'}</td>\n");
+	    $doc_obj->add_utf8_text($section, "  </tr>\n");
+	}
+    }
+
+    # end of document
+    $doc_obj->add_utf8_text($section, "</table>\n");
+
+    # add an object id
+    $doc_obj->set_OID();
+
+    # process the document
+    $processor->process($doc_obj);
+}
+
+
+1;
Index: /main/tags/2.25/gsdl/perllib/plugins/GMLPlug.pm
===================================================================
--- /main/tags/2.25/gsdl/perllib/plugins/GMLPlug.pm	(revision 21064)
+++ /main/tags/2.25/gsdl/perllib/plugins/GMLPlug.pm	(revision 21064)
@@ -0,0 +1,195 @@
+###########################################################################
+#
+# GMLPlug.pm --
+# A component of the Greenstone digital library software
+# from the New Zealand Digital Library Project at the 
+# University of Waikato, New Zealand.
+#
+# Copyright (C) 1999 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.
+#
+###########################################################################
+
+# plugin which processes a GML format document
+# assumes that gml tags are all in lower-case.
+
+package GMLPlug;
+
+use BasPlug;
+use util;
+use doc;
+
+sub BEGIN {
+    @ISA = ('BasPlug');
+}
+
+use strict;
+
+sub new {
+    my ($class) = @_;
+    my $self = new BasPlug ("GMLPlug", @_);
+
+    return bless $self, $class;
+}
+
+sub get_default_process_exp {
+    my $self = shift (@_);
+
+    return q^(?i)\.gml?$^;
+}
+
+# return number of files processed, undef if can't process
+# Note that $base_dir might be "" and that $file might 
+# include directories
+sub read {
+    my $self = shift (@_);
+    my ($pluginfo, $base_dir, $file, $metadata, $processor, $maxdocs) = @_;
+
+    my $filename = &util::filename_cat($base_dir, $file);
+    return 0 if $self->{'block_exp'} ne "" && $filename =~ /$self->{'block_exp'}/;
+    if ($filename !~ /$self->{'process_exp'}/ || !-f $filename) {
+	return undef;
+    }
+    $file =~ s/^[\/\\]+//; # $file often begins with / so we'll tidy it up
+
+    print STDERR "GMLPlug: processing $file\n";
+
+    my $parent_dir = $file;
+    $parent_dir =~ s/[^\\\/]*$//;
+    $parent_dir = &util::filename_cat ($base_dir, $parent_dir);
+
+    if (!open (INFILE, $filename)) {
+	print STDERR "GMLPlug::read - couldn't read $filename\n";
+	return 0;
+    }
+
+    undef $/;
+    my $gml = <INFILE>;
+    $/ = "\n";
+    close (INFILE);
+    
+    my @gml_sections = split("</gsdlsection>",$gml);
+    $gml = shift(@gml_sections);
+
+    my $no_docs = 0;
+
+    while (1) {
+	# create a new document
+	my $doc_obj = new doc ();
+	my $section = $doc_obj->get_top_section();
+
+	# process the document
+	my $firstsection = 1;
+	while (1) {
+	    my ($tags, $text) = ("", "");
+
+	    my @indenting_sections = split("<gsdlsection", $gml);
+	    shift(@indenting_sections); # first entry is trivially empty
+
+	    foreach $gml (@indenting_sections) {
+
+		if ($gml =~ /^\s*([^>]*)>(.*)$/so) {
+		    $tags = $1 if defined $1;
+		    $text = &GMLPlug::_unescape_text($2);
+
+		} else {
+		    print STDERR "GMLPlug::read - error in file $filename\n";
+		    print STDERR "text: \"$gml\"\n";
+		    last;
+		}
+
+		# create the section (unless this is the first section)
+		if ($firstsection) {
+ 		    $firstsection = 0;
+#		    $tags =~ /gsdlsourcefilename\s*=\s*(?:\"([^\"]*)\")/o;
+#		    $src_filename = $2 || $3;
+
+		} else {
+
+		    $tags =~ s/gsdlnum\s*=\s*\"?(\d+)\"?//o;
+		    if (defined $1) {
+			$section .= ".$1";
+			$doc_obj->create_named_section($section);
+		    } else {
+			$section = $doc_obj->insert_section($doc_obj->get_end_child($section));
+		    }
+		}
+	    
+		# add the tags
+		while ((defined $tags) && ($tags =~ s/^\s*(\S+)=\"([^\"]*)\"//o)) {
+		    $doc_obj->add_utf8_metadata($section, $1, &GMLPlug::_unescape_text($2)) 
+			if (defined $1 and defined $2);
+
+		}
+		
+		# add the text
+		$doc_obj->add_utf8_text($section, $text) 
+		    if ((defined $text) && ($text ne ""));		
+	    }
+
+	    $gml = shift(@gml_sections); # get next bit of data
+	    last unless defined $gml;
+ 	    last if $section eq ""; # back to top level again (more than one document in gml file)
+	    $section = $doc_obj->get_parent_section ($section);
+	} # while (1) section level
+
+	# add the associated files
+	my $assoc_files = $doc_obj->get_metadata($doc_obj->get_top_section(), "gsdlassocfile");
+	my ($assoc_file_info, $afile);
+	foreach $assoc_file_info (@$assoc_files) {
+	    my ($assoc_file, $mime_type, $dir) = split (":", $assoc_file_info);
+	    if (defined $dir && $dir =~ /\w/) {
+		$afile = &util::filename_cat($dir, $assoc_file);
+	    } else {
+		$afile = $assoc_file;
+	    }
+	    $doc_obj->associate_file(&util::filename_cat($parent_dir, $assoc_file),
+				     $afile, $mime_type);
+	}
+	$doc_obj->delete_metadata($doc_obj->get_top_section(), "gsdlassocfile");
+	
+	# add metadata passed in from elsewhere
+	$self->extra_metadata ($doc_obj, $doc_obj->get_top_section(), $metadata);
+	
+	# do any automatic metadata extraction
+	$self->auto_extract_metadata ($doc_obj);
+
+	# assume the document has an OID already
+	
+	# process the document
+	$processor->process($doc_obj, $file);
+	
+	$no_docs++;
+	last if ($maxdocs > -1 && $no_docs >= $maxdocs);
+	last unless defined $gml && $gml =~ /\w/;
+    } # while(1) document level
+
+    return $no_docs; # no of docs processed
+}
+
+sub _unescape_text {
+    my ($text) = @_;
+
+    # special characters in the gml encoding
+    $text =~ s/&lt;/</g;
+    $text =~ s/&gt;/>/g;
+    $text =~ s/&quot;/\"/g;
+    $text =~ s/&amp;/&/g; # this has to be last...
+
+    return $text;
+}
+
+1;
Index: /main/tags/2.25/gsdl/perllib/plugins/HBPlug.pm
===================================================================
--- /main/tags/2.25/gsdl/perllib/plugins/HBPlug.pm	(revision 21064)
+++ /main/tags/2.25/gsdl/perllib/plugins/HBPlug.pm	(revision 21064)
@@ -0,0 +1,316 @@
+###########################################################################
+#
+# HBPlug.pm --
+# A component of the Greenstone digital library software
+# from the New Zealand Digital Library Project at the 
+# University of Waikato, New Zealand.
+#
+# Copyright (C) 1999 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.
+#
+###########################################################################
+
+# plugin which processes an HTML book directory
+
+# This plugin is used by the Humanity Library collections and does not handle
+# input encodings other than ascii or extended ascii
+
+# this code is kind of ugly and could no doubt be made to run faster, by leaving
+# it in this state I hope to encourage people to make their collections use
+# HBSPlug instead ;-)
+
+# Use HBSPlug if creating a new collection and marking up files like the
+# Humanity Library collections. HBSPlug accepts all input encodings but
+# expects the marked up files to be cleaner than those used by the
+# Humanity Library collections
+
+package HBPlug;
+
+use ghtml;
+use BasPlug;
+use util;
+use doc;
+
+
+sub BEGIN {
+    @ISA = ('BasPlug');
+}
+
+sub new {
+    my ($class) = @_;
+    my $self = new BasPlug ("HBPlug", @_);
+
+    return bless $self, $class;
+}
+
+sub init {
+    my $self = shift (@_);
+    my ($verbosity) = @_;
+
+    $self->BasPlug::init();
+
+    # this plugin only handles ascii encodings
+    if ($self->{'input_encoding'} !~ /^(iso_8859_1|ascii)$/) {
+	die "ERROR: HBPlug can handle only iso_8859_1 or ascii encodings.\n" .
+	    $self->{'input_encoding'} . " is not an acceptable input_encoding value\n";
+    }
+}
+
+# this is included only to prevent warnings being printed out 
+# from BasPlug::init. The process_exp is not used by this plugin
+sub get_default_process_exp {
+    my $self = shift (@_);
+
+    return "This plugin does not use a process_exp\n";
+}
+
+
+sub HB_read_html_file {
+    my $self = shift (@_);
+    my ($htmlfile, $text) = @_;
+
+    # load in the file
+    if (!open (FILE, $htmlfile)) {
+	print STDERR "ERROR - could not open $htmlfile\n";
+	return;
+    }
+
+    my $foundbody = 0;
+    $self->HB_gettext (\$foundbody, $text, "FILE");
+    close FILE;
+
+    # just in case there was no <body> tag
+    if (!$foundbody) {
+	$foundbody = 1;
+	open (FILE, $htmlfile) || return;
+	$self->HB_gettext (\$foundbody, $text, "FILE");	
+	close FILE;
+    }
+}
+
+sub HB_gettext {
+    my $self = shift (@_);
+    my ($foundbody, $text, $handle) = @_;
+
+    my $line = "";
+    while (defined ($line = <$handle>)) {
+	# look for body tag
+	if (!$$foundbody) {
+	    if ($line =~ s/^.*<body[^>]*>//i) {
+		$$foundbody = 1;
+	    } else {
+		next;
+	    }
+	}
+	
+	# check for symbol fonts
+	if ($line =~ /<font [^>]*?face\s*=\s*\"?(\w+)\"?/i) {
+	    my $font = $1;
+	    print STDERR "HBPlug::HB_gettext - warning removed font $font\n" 
+		if ($font !~ /^arial$/i);
+	}
+
+	$line =~ s/<\/p>//ig;   # remove </p> tags
+	$line =~ s/<\/?(body|html|font)\b[^>]*>//ig; # remove any unwanted tags
+
+	# convert any alphanumeric character entities to their extended
+	# ascii equivalent for indexing purposes
+	&ghtml::convertcharentities ($line);
+
+	$$text .= $line;
+    }
+    $$text =~ s/\s+/ /g; # remove \n's
+}
+
+sub HB_clean_section {
+    my $self = shift (@_);
+    my ($section) = @_;
+
+    # remove tags without a starting tag from the section
+    my ($tag, $tagstart);
+    while ($section =~ /<\/([^>]{1,10})>/) {
+	$tag = $1;
+	$tagstart = index($section, "<$tag");
+	last if (($tagstart >= 0) && ($tagstart < index($section, "<\/$tag")));
+	$section =~ s/<\/$tag>//;
+    }
+    
+    # remove extra paragraph tags
+    while ($section =~ s/<p\b[^>]*>\s*<p\b/<p/ig) {}
+    
+    # remove extra stuff at the end of the section
+    while ($section =~ s/(<u>|<i>|<b>|<p\b[^>]*>|&nbsp;|\s)$//i) {}
+    
+    # add a newline at the beginning of each paragraph
+    $section =~ s/(.)\s*<p\b/$1\n\n<p/gi;
+    
+    # add a newline every 80 characters at a word boundary
+    # Note: this regular expression puts a line feed before
+    # the last word in each section, even when it is not
+    # needed.
+    $section =~ s/(.{1,80})\s/$1\n/g;
+    
+    # fix up the image links
+    $section =~ s/<img[^>]*?src=\"?([^\">]+)\"?[^>]*>/
+	<center><img src=\"_httpdocimg_\/$1\"><\/center><br>/ig;
+    $section =~ s/&lt;&lt;I&gt;&gt;\s*([^\.]+\.(png|jpg|gif))/
+	<center><img src=\"_httpdocimg_\/$1\"><\/center><br>/ig;
+
+    return $section;
+}
+
+
+sub shorten {
+    my $self = shift (@_);
+    my ($text) = @_;
+
+    return "\"$text\"" if (length($text) < 100);
+
+    return "\"" . substr ($text, 0, 50) . "\" ... \"" . 
+	substr ($text, length($text)-50) . "\"";
+}
+
+# if input_encoding is ascii we can call add_utf8_metadata
+# directly but if it's iso_8859_1 (the default) we need to call
+# add_metadata so that the ascii2utf8 conversion is done first
+# this should speed things up a little if processing an ascii only
+# document with input_encoding set to ascii
+sub HB_add_metadata {
+    my $self = shift (@_);
+    my ($doc_obj, $cursection, $field, $value) = @_;
+
+    if ($self->{'input_encoding'} eq "ascii") {
+	$doc_obj->add_utf8_metadata ($cursection, $field, $value);
+    } else {
+	$doc_obj->add_metadata ($cursection, $field, $value);
+    }
+}
+
+# return number of files processed, undef if can't process
+# Note that $base_dir might be "" and that $file might 
+# include directories
+sub read {
+    my $self = shift (@_);
+    my ($pluginfo, $base_dir, $file, $metadata, $processor) = @_;
+
+    # get the html filename and see if this is an HTML Book...
+    my $jobnumber = $file;
+    if ($file =~ /[\\\/]/) {
+	($jobnumber) = $file =~ /[\\\/]([^\\\/]+)$/;
+    }
+    return undef unless defined $jobnumber;
+    my $htmlfile = &util::filename_cat($base_dir, $file, "$jobnumber.htm");
+    return undef unless -e $htmlfile;
+
+    print STDERR "HBPlug: processing $file\n";
+
+    # read in the file and do basic html cleaning (removing header etc)
+    my $html = "";
+    $self->HB_read_html_file ($htmlfile, \$html);
+
+    # create a new document
+    my $doc_obj = new doc ($file, "indexed_doc");
+
+    # copy the book cover if it exists
+    my $bookcover = &util::filename_cat($base_dir, $file, "$jobnumber.jpg");
+    $doc_obj->associate_file($bookcover, "cover.jpg", "image/jpeg");
+
+    my $cursection = $doc_obj->get_top_section();
+
+    # add metadata for top level of document
+    foreach my $field (keys(%$metadata)) {
+	# $metadata->{$field} may be an array reference
+	if (ref ($metadata->{$field}) eq "ARRAY") {
+	    map { 
+		$self->HB_add_metadata ($doc_obj, $cursection, $field, $_); 
+	    } @{$metadata->{$field}};
+	} else {
+	    $self->HB_add_metadata ($doc_obj, $cursection, $field, $metadata->{$field}); 
+	}
+    }
+
+    # process the file one section at a time
+    my $curtoclevel = 1;
+    my $firstsection = 1;
+    while (length ($html) > 0) {
+	if ($html =~ s/^.*?(?:<p\b[^>]*>)?((<b>|<i>|<u>|\s)*)&lt;&lt;TOC(\d+)&gt;&gt;\s*(.*?)<p\b/<p/i) {
+	    my $toclevel = $3;
+	    my $title = $4;
+	    my $sectiontext = "";
+	    if ($html =~ s/^(.*?)((?:<p\b[^>]*>)?((<b>|<i>|<u>|\s)*)&lt;&lt;TOC\d+&gt;&gt;)/$2/i) {
+		$sectiontext = $1;
+	    } else {
+		$sectiontext = $html;
+		$html = "";
+	    }
+
+	    # remove tags and extra spaces from the title
+	    $title =~ s/<\/?[^>]+>//g;
+	    $title =~ s/^\s+|\s+$//g;
+
+	    # close any sections below the current level and
+	    # create a new section (special case for the firstsection)
+	    while (($curtoclevel > $toclevel) ||
+		   (!$firstsection && $curtoclevel == $toclevel)) {
+		$cursection = $doc_obj->get_parent_section ($cursection);
+		$curtoclevel--;
+	    }
+	    if ($curtoclevel+1 < $toclevel) {
+		print STDERR "WARNING - jump in toc levels in $htmlfile " . 
+		    "from $curtoclevel to $toclevel\n";
+	    }
+	    while ($curtoclevel < $toclevel) {
+		$curtoclevel++;
+		$cursection = 
+		    $doc_obj->insert_section($doc_obj->get_end_child($cursection));
+	    }
+
+	    # add the metadata to this section
+	    $self->HB_add_metadata ($doc_obj, $cursection, "Title", $title);
+
+	    # clean up the section html
+	    $sectiontext = $self->HB_clean_section($sectiontext);
+
+	    # associate any files
+	    map { $doc_obj->associate_file(&util::filename_cat ($base_dir, $file, $1), $1)
+		      if /_httpdocimg_\/([^\"]+)\"/; 0; }
+	         split (/(_httpdocimg_\/[^\"]+\")/, $sectiontext);
+
+	    # add the text for this section
+	    if ($self->{'input_encoding'} eq "ascii") {
+		$doc_obj->add_utf8_text ($cursection, $sectiontext);
+	    } else {
+		$doc_obj->add_text ($cursection, $sectiontext);
+	    }
+	} else {
+	    print STDERR "WARNING - leftover text\n" , $self->shorten($html), 
+	    "\nin $htmlfile\n";
+	    last;
+	}
+	$firstsection = 0;
+    }
+
+    # add a OID
+    $doc_obj->set_OID ();
+
+    # process the document
+    $processor->process($doc_obj, &util::filename_cat($file, "$jobnumber.htm"));
+        
+    return 1; # processed the file
+}
+
+
+1;
Index: /main/tags/2.25/gsdl/perllib/plugins/HBSPlug.pm
===================================================================
--- /main/tags/2.25/gsdl/perllib/plugins/HBSPlug.pm	(revision 21064)
+++ /main/tags/2.25/gsdl/perllib/plugins/HBSPlug.pm	(revision 21064)
@@ -0,0 +1,214 @@
+###########################################################################
+#
+# HBSPlug.pm -- plugin for processing simple html (or text) books
+# A component of the Greenstone digital library software
+# from the New Zealand Digital Library Project at the 
+# University of Waikato, New Zealand.
+#
+# Copyright (C) 1999 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.
+#
+###########################################################################
+
+# creates multi-level document from document containing 
+# <<TOC>> level tags. Metadata for each section is taken from any
+# other tags on the same line as the <<TOC>>. e.g. <<Title>>xxxx<</Title>>
+# sets Title metadata.
+
+# Everything else between TOC tags is treated as simple html (i.e. no 
+# processing of html links or any other HTMLPlug type stuff is done).
+
+# expects input files to have a .hb file extension by default (this can be 
+# changed by adding a -process_exp option
+
+# a file with the same name as the hb file but a .jpg extension is
+# taken as the cover image (jpg files are blocked by this plugin)
+
+# HBSPlug is a simplification (and extension of) the HBPlug used
+# by the Humanity Library collections. HBSPlug is faster as it expects
+# the input files to be cleaner (The input to the HDL collections
+# contains lots of excess html tags around <<TOC>> tags, uses <<I>>
+# tags to specify images, and simply takes all text between <<TOC>>
+# tags and start of text to be Title metadata). If you're marking up
+# documents to be displayed in the same way as the HDL collections,
+# use this plugin instead of HBPlug.
+
+package HBSPlug;
+
+use BasPlug;
+use util;
+
+sub BEGIN {
+    @ISA = ('BasPlug');
+}
+
+use strict;
+
+sub new {
+    my ($class) = @_;
+    my $self = new BasPlug ("HBSPlug", @_);
+
+    return bless $self, $class;
+}
+
+sub get_default_block_exp {
+    my $self = shift (@_);
+
+    return q^\.jpg$^;
+}
+
+sub get_default_process_exp {
+    my $self = shift (@_);
+
+    return q^(?i)\.hb$^;
+}
+
+# do plugin specific processing of doc_obj
+sub process {
+    my $self = shift (@_);
+    my ($textref, $pluginfo, $base_dir, $file, $metadata, $doc_obj) = @_;
+    
+    print STDERR "HBSPlug: processing $file\n" 
+	if $self->{'verbosity'} > 1;
+    
+    my $cursection = $doc_obj->get_top_section();
+
+    my $filename = &util::filename_cat($base_dir, $file);
+    my $absdir = $filename;
+    $absdir =~ s/[^\/\\]*$//;
+
+    # add the cover image
+    my $coverimage = $filename;
+    $coverimage =~ s/\.[^\.]*$/\.jpg/i;
+    $doc_obj->associate_file($coverimage, "cover.jpg", "image/jpeg");
+
+    my $title = "";
+
+    # remove any leading rubbish
+    $$textref =~ s/^.*?(<<TOC)/$1/ios;
+    
+    my $curtoclevel = 1;
+    my $firstsection = 1;
+    my $toccount = 0;
+    while ($$textref =~ /\w/) {
+	$$textref =~ s/^<<TOC(\d+)>>([^\n]*)\n(.*?)(<<TOC|\Z)/$4/ios;
+	my $toclevel = $1;
+	my $metadata = $2;
+	my $sectiontext = $3;
+
+	if ($toclevel == 2) {
+	    $toccount ++;
+	}
+	
+	# close any sections below the current level and
+	# create a new section (special case for the firstsection)
+	while (($curtoclevel > $toclevel) ||
+	       (!$firstsection && $curtoclevel == $toclevel)) {
+	    $cursection = $doc_obj->get_parent_section ($cursection);
+	    $curtoclevel--;
+	}
+	if ($curtoclevel+1 < $toclevel) {
+	    print STDERR "WARNING - jump in toc levels in $filename " . 
+		"from $curtoclevel to $toclevel\n";
+	}
+	while ($curtoclevel < $toclevel) {
+	    $curtoclevel++;
+	    $cursection = 
+		$doc_obj->insert_section($doc_obj->get_end_child($cursection));
+	}
+
+	# sort out metadata
+	while ($metadata =~ s/^.*?<<([^>]*)>>(.*?)<<[^>]*>>//) {
+	    my $metakey = $1;
+	    my $metavalue = $2;
+
+	    if ($metavalue ne "" && $metakey ne "") {
+		# make sure key fits in with gsdl naming scheme 
+		$metakey =~ tr/[A-Z]/[a-z]/;
+		$metakey = ucfirst ($metakey);
+		$doc_obj->add_utf8_metadata ($cursection, $metakey, $metavalue);
+	    }
+	}
+
+	# remove header rubbish
+	$sectiontext =~ s/^.*?<body[^>]*>//ios;
+
+	# and any other unwanted tags
+	$sectiontext =~ s/<(\/p|\/html|\/body)>//isg;
+
+	# fix up the image links
+	$sectiontext =~ s/(<img[^>]*?src\s*=\s*\"?)([^\">]+)(\"?[^>]*>)/
+	    &replace_image_links($absdir, $doc_obj, $1, $2, $3)/isge;
+
+	# add the text
+	$doc_obj->add_utf8_text($cursection, $sectiontext);
+
+	$firstsection = 0;
+
+	$$textref =~ s/^\s+//s;
+    }
+
+    return 1;
+}
+
+sub replace_image_links {
+
+    my ($dir, $doc_obj, $front, $link, $back) = @_;
+
+    my ($filename, $error);
+    my $foundimage = 0;
+    
+    $link =~ s/\/\///;
+    my ($imagetype) = $link =~ /([^\.]*)$/;
+    $imagetype =~ tr/[A-Z]/[a-z]/;
+    if ($imagetype eq "jpg") {$imagetype = "jpeg";}
+    if ($imagetype !~ /^(jpeg|gif|png)$/) {
+	print STDERR "HBSPlug: Warning - unknown image type ($imagetype)\n";
+    }
+    my ($imagefile) = $link =~ /([^\/]*)$/;
+    my ($imagepath) = $link =~ /^[^\/]*(.*)$/;
+
+    if (defined $imagepath && $imagepath =~ /\w/) {
+	# relative link
+	$filename = &util::filename_cat ($dir, $imagepath);
+	if (-e $filename) {
+	    $doc_obj->associate_file ($filename, $imagefile, "image/$imagetype");
+	    $foundimage = 1;
+	} else {
+	    $error = "HBSPlug: Warning - couldn't find image file $imagefile in either $filename or";
+	}
+    }
+
+    if (!$foundimage) {
+	$filename = &util::filename_cat ($dir, $imagefile);
+	if (-e $filename) {
+	    $doc_obj->associate_file ($filename, $imagefile, "image/$imagetype");    
+	    $foundimage = 1;
+	} elsif (defined $error) {
+	    print STDERR "$error $filename\n";
+	} else {
+	    print STDERR "HBSPlug: Warning - couldn't find image file $imagefile in $filename\n";
+	}
+    }
+
+    if ($foundimage) {
+	return "${front}_httpdocimg_/${imagefile}${back}";
+    } else {
+	return "";
+    }
+}
+
+1;
Index: /main/tags/2.25/gsdl/perllib/plugins/HTMLPlug.pm
===================================================================
--- /main/tags/2.25/gsdl/perllib/plugins/HTMLPlug.pm	(revision 21064)
+++ /main/tags/2.25/gsdl/perllib/plugins/HTMLPlug.pm	(revision 21064)
@@ -0,0 +1,448 @@
+###########################################################################
+#
+# HTMLPlug.pm -- basic html plugin
+#
+# A component of the Greenstone digital library software
+# from the New Zealand Digital Library Project at the 
+# University of Waikato, New Zealand.
+#
+# Copyright (C) 1999 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.
+#
+###########################################################################
+
+# 
+# Note that this plugin handles frames only in a very simple way
+# i.e. each frame is treated as a separate document. This means
+# search results will contain links to individual frames rather
+# than linking to the top level frameset.
+# There may also be some problems caused by the _parent target
+# (it's removed by this plugin)
+# To use frames properly you'll need to use the WebPlug plugin.
+#
+
+
+package HTMLPlug;
+
+use BasPlug;
+use ghtml;
+use util;
+use parsargv;
+
+sub BEGIN {
+    @ISA = ('BasPlug');
+}
+
+use strict;
+
+sub print_usage {
+    print STDERR "\n  usage: plugin HTMLPlug [options]\n\n";
+    print STDERR "  options:\n";
+    print STDERR "   -nolinks               Don't make any attempt to trap links (setting this flag may\n";
+    print STDERR "                          improve speed of building/importing but any relative links within\n";
+    print STDERR "                          documents will be broken).\n";
+    print STDERR "   -keep_head             Don't remove headers from html files.\n";
+    print STDERR "   -no_metadata           Don't attempt to extract any metadata from files.\n";
+    print STDERR "   -metadata_fields       Comma separated list of metadata fields to attempt to extract.\n";
+    print STDERR "                          Defaults to 'Title'.\n";
+    print STDERR "                          Use `first200` to get the first 200 characters of the body.\n";
+    print STDERR "                          Use `H1` to get the text inside the first <H1> and </H1> tags in the text.\n";
+    print STDERR "   -w3mir                 Set if w3mir was used to generate input file structure.\n";
+    print STDERR "   -assoc_files           Perl regular expression of file extensions to associate with\n";
+    print STDERR "                          html documents. Defaults to '(?i)\.(jpe?g|gif|png|css|pdf)\$'\n";
+    print STDERR "   -rename_assoc_files    Renames files associated with documents (e.g. images). Also\n";
+    print STDERR "                          creates much shallower directory structure (useful when creating\n";
+    print STDERR "                          collections to go on cd-rom).\n\n";
+}
+
+sub new {
+    my $class = shift (@_);
+    my $self = new BasPlug ("HTMLPlug", @_);
+
+    if (!parsargv::parse(\@_, 
+			 q^nolinks^, \$self->{'nolinks'},
+			 q^keep_head^, \$self->{'keep_head'},
+			 q^no_metadata^, \$self->{'no_metadata'},
+			 q^metadata_fields/.*/Title^, \$self->{'metadata_fields'},
+			 q^w3mir^, \$self->{'w3mir'},
+			 q^assoc_files/.*/(?i)\.(jpe?g|gif|png|css|pdf)$^, \$self->{'assoc_files'},
+			 q^rename_assoc_files^, \$self->{'rename_assoc_files'},
+			 "allow_extra_options")) {
+
+	print STDERR "\nIncorrect options passed to HTMLPlug, check your collect.cfg configuration file\n";
+	&print_usage();
+	die "\n";
+    }
+    
+    $self->{'aux_files'} = {};
+    $self->{'dir_num'} = 0;
+    $self->{'file_num'} = 0;
+    
+    return bless $self, $class;
+}
+
+
+sub get_default_block_exp {
+    my $self = shift (@_);
+
+    return q^(?i)\.(gif|jpe?g|png|pdf|rtf|css)$^;
+}
+
+sub get_default_process_exp {
+    my $self = shift (@_);
+
+    return q^(?i)\.html?$^;
+}
+
+
+# do plugin specific processing of doc_obj
+sub process {
+    my $self = shift (@_);
+    my ($textref, $pluginfo, $base_dir, $file, $metadata, $doc_obj) = @_;
+
+    print STDERR "HTMLPlug: processing $file\n" 
+	if $self->{'verbosity'} > 1;
+
+    my $cursection = $doc_obj->get_top_section();
+
+    $self->extract_metadata ($textref, $metadata, $doc_obj, $cursection) 
+	unless $self->{'no_metadata'};
+
+    # Store URL for page as metadata - this can be used for an
+    # altavista style search interface. The URL won't be valid
+    # unless the file structure contains the domain name (i.e.
+    # like when w3mir is used to download a website).
+    my $web_url = "http://$file";
+    $web_url =~ s/\\/\//g; # for windows
+    $doc_obj->add_utf8_metadata($cursection, "URL", $web_url);
+
+    # remove header and footer
+    if (!$self->{'keep_head'}) {
+	$$textref =~ s/^.*?<body[^>]*>//is;
+	$$textref =~ s/(<\/body[^>]*>|<\/html[^>]*>)//isg;
+    }
+
+    # trap links
+    if (!$self->{'nolinks'}) {
+
+	# usemap="./#index" not handled correctly => change to "#index"
+	$$textref =~ s/(<img[^>]*?usemap\s*=\s*\"?)([^\">\s]+)(\"?[^>]*>)/
+	    $self->replace_usemap_links($1, $2, $3)/isge;
+
+	$$textref =~ s/(<(?:a|area|frame|link)\s+[^>]*?\s*(?:href|src)\s*=\s*\"?)([^\">\s]+)(\"?[^>]*>)/
+	    $self->replace_href_links ($1, $2, $3, $base_dir, $file, $doc_obj, $cursection)/isge;
+    }
+
+    # trap images
+    $$textref =~ s/(<img[^>]*? src\s*=\s*\"?)([^\">\s]+)(\"?[^>]*>)/
+	$self->replace_images ($1, $2, $3, $base_dir, $file, $doc_obj, $cursection)/isge;
+
+    # add text to document object
+    $doc_obj->add_utf8_text($cursection, $$textref);
+
+    return 1;
+}
+
+sub replace_images {
+    my $self = shift (@_);
+    my ($front, $link, $back, $base_dir, 
+	$file, $doc_obj, $section) = @_;
+    
+    $link =~ s/\n/ /g;
+    
+    my ($href, $hash_part, $rl) = $self->format_link ($link, $base_dir, $file);
+    return $front . $self->add_file ($href, $rl, $hash_part, $base_dir, $doc_obj, $section) . $back;
+}
+
+sub replace_href_links {
+    my $self = shift (@_);
+    my ($front, $link, $back, $base_dir, $file, $doc_obj, $section) = @_;
+
+    # attempt to sort out targets - frames are not handled 
+    # well in this plugin and some cases will screw things
+    # up - e.g. the _parent target (so we'll just remove 
+    # them all ;-)
+    $front =~ s/(target=\"?)_top(\"?)/$1_gsdltop_$2/is;
+    $back =~ s/(target=\"?)_top(\"?)/$1_gsdltop_$2/is;
+    $front =~ s/target=\"?_parent\"?//is;
+    $back =~ s/target=\"?_parent\"?//is;
+
+    return $front . $link . $back if $link =~ /^\#/s;
+    $link =~ s/\n/ /g;
+
+    my ($href, $hash_part, $rl) = $self->format_link ($link, $base_dir, $file);
+    # href may use '\'s where '/'s should be on Windows
+    $href =~ s/\\/\//g;
+
+    my ($filename) = $href =~ /^(?:.*?):(?:\/\/)?(.*)/;
+
+    ##### leave all these links alone (they won't be picked up by intermediate 
+    ##### pages). I think that's safest when dealing with frames, targets etc.
+    ##### (at least until I think of a better way to do it). Problems occur with
+    ##### mailto links from within small frames, the intermediate page is displayed
+    ##### within that frame and can't be seen. There is still potential for this to
+    ##### happen even with html pages - the solution seems to be to somehow tell
+    ##### the browser from the server side to display the page being sent (i.e. 
+    ##### the intermediate page) in the top level window - I'm not sure if that's 
+    ##### possible - the following line should probably be deleted if that can be done
+    return $front . $link . $back if $href =~ /^(mailto|news|gopher|nntp|telnet|javascript):/is;
+
+
+    if (($rl == 0) || ($filename =~ /$self->{'process_exp'}/) || 
+	($href =~ /\/$/) || ($href =~ /^(mailto|news|gopher|nntp|telnet|javascript):/i)) {
+	&ghtml::urlsafe ($href);
+	return $front . "_httpextlink_&rl=" . $rl . "&href=" . $href . $hash_part . $back;
+	
+    } else {
+	# link is to some other type of file (image, pdf etc.) so we'll
+	# need to associate that file
+	return $front . $self->add_file ($href, $rl, $hash_part, $base_dir, $doc_obj, $section) . $back;
+    }
+}
+
+sub add_file {
+    my $self = shift (@_);
+    my ($href, $rl, $hash_part, $base_dir, $doc_obj, $section) = @_;
+    my ($newname);
+
+    my $filename = $href;
+    $filename =~ s/^[^:]*:\/\///;
+    $filename = &util::filename_cat ($base_dir, $filename);
+    my ($ext) = $filename =~ /(\.[^\.]*)$/;
+
+    if ((!defined $ext) || ($ext !~ /$self->{'assoc_files'}/)) {
+	return "_httpextlink_&rl=" . $rl . "&href=" . $href . $hash_part;
+    }
+
+    if ($self->{'rename_assoc_files'}) {
+	if (defined $self->{'aux_files'}->{$href}) {
+	    $newname = $self->{'aux_files'}->{$href}->{'dir_num'} . "/" .
+		$self->{'aux_files'}->{$href}->{'file_num'} . $ext;
+	} else {
+	    $newname = $self->{'dir_num'} . "/" . $self->{'file_num'} . $ext;
+	    $self->{'aux_files'}->{$href} = {'dir_num' => $self->{'dir_num'}, 'file_num' => $self->{'file_num'}};
+	    $self->inc_filecount ();
+	}
+	$doc_obj->associate_file($filename, $newname, undef, $section);
+	return "_httpcollimg_/$newname";
+
+    } else {
+	($newname) = $filename =~ /([^\/\\]*)$/;
+	$doc_obj->associate_file($filename, $newname, undef, $section);
+	return "_httpdocimg_/$newname";
+    }
+}
+
+
+sub format_link {
+    my $self = shift (@_);
+    my ($link, $base_dir, $file) = @_;
+
+    my ($before_hash, $hash_part) = $link =~ /^([^\#]*)(\#?.*)$/;
+    $hash_part = "" if !defined $hash_part;
+    if (!defined $before_hash || $before_hash !~ /[\w\.\/]/) {
+	print STDERR "HTMLPlug: ERROR - badly formatted tag ignored ($link)\n"
+	    if $self->{'verbosity'};
+	return ($link, "", 0);
+    }
+    
+    if ($before_hash =~ s/^((?:http|ftp|file):\/\/)//i) {
+	my $type = $1;
+	       
+	if ($link =~ /^(http|ftp):/i) {
+	    # Turn url (using /) into file name (possibly using \ on windows)
+	    my @http_dir_split = split('/', $before_hash);
+	    $before_hash = &util::filename_cat(@http_dir_split);
+	}
+
+	$before_hash = $self->eval_dir_dots($before_hash);
+					 
+	my $linkfilename = &util::filename_cat ($base_dir, $before_hash);
+
+	my $rl = 0;
+	$rl = 1 if (-e $linkfilename);
+
+	# make sure there's a slash on the end if it's a directory
+	if ($before_hash !~ /\/$/) {
+	    $before_hash .= "/" if (-d $linkfilename);
+	}
+
+	return ($type . $before_hash, $hash_part, $rl);
+    
+    } elsif ($link !~ /^(mailto|news|gopher|nntp|telnet|javascript):/i) {
+
+	if ($before_hash =~ s/^\///) {
+	    # the first directory will be the domain name if w3mir was used
+	    # to generate archives, otherwise we'll assume all files are
+	    # from the same site and base_dir is the root
+	    if ($self->{'w3mir'}) {
+		my @dirs = split /[\/\\]/, $file;
+		my $domname = shift (@dirs);
+		$before_hash = &util::filename_cat($domname, $before_hash);
+		$before_hash =~ s/\\/\//g; # for windows
+	    }
+
+	} else {
+	    # Turn relative file path into full path
+	    my $dirname = &File::Basename::dirname($file);
+	    $before_hash = &util::filename_cat($dirname, $before_hash);
+	    $before_hash = $self->eval_dir_dots($before_hash);
+	}
+
+	# make sure there's a slash on the end if it's a directory
+	my $linkfilename = &util::filename_cat ($base_dir, $before_hash);
+	if ($before_hash !~ /\/$/) {
+	    $before_hash .= "/" if (-d $linkfilename);
+	}
+
+	return ("http://" . $before_hash, $hash_part, 1);
+
+    } else {
+	# mailto, news, nntp, telnet, javascript or gopher link
+	return ($before_hash, "", 0);
+    }
+}
+
+sub extract_metadata {
+    my $self = shift (@_);
+    my ($textref, $metadata, $doc_obj, $section) = @_;
+
+    foreach my $field (split /,/, $self->{'metadata_fields'}) {
+
+	# don't need to extract field if it was passed in from a previous 
+	# (recursive) plugin
+	next if defined $metadata->{$field};
+
+	# see if there's a <meta> tag for this field
+	if ($$textref =~ /<meta(.*?)(?:name|http-equiv)\s*=\s*\"?$field\"?([^>]*)/is) {
+	    my $content = $1 . $2;
+	    if ($content =~ /content\s*=\s*\"?(.*?)\"?/is) {
+		if (defined $1) {
+		    my $value = $1;
+		    $value =~ s/\s+/ /gs;
+		    $doc_obj->add_utf8_metadata($section, $field, $value);
+		    next;
+		}
+	    }
+	}
+	
+	# TITLE: extract the document title
+	
+	if ($field =~ /^title$/i) {
+
+	    # see if there's a <title> tag
+	    if ($$textref =~ /<title[^>]*>([^<]*)<\/title[^>]*>/is) {
+		if (defined $1) {
+		    my $title = $1;
+		    if ($title =~ /\w/) {
+			$title =~ s/\s+/ /gs;
+			$title =~ s/^\s+//;
+			$title =~ s/\s+$//;
+			$doc_obj->add_utf8_metadata ($section, $field, $title);
+			next;
+		    }
+		}
+	    }
+	    
+	    # if no title use first 100 characters
+	    my $tmptext = $$textref;
+	    $tmptext =~ s/\s+/ /gs;
+	    $tmptext =~ s/<[^>]*>//g;
+	    $tmptext = substr ($tmptext, 0, 100);
+	    $tmptext =~ s/^\s+//;
+	    $tmptext =~ s/\s+$//;
+	    $tmptext =~ s/\s\S*$/.../;
+	    $doc_obj->add_utf8_metadata ($section, $field, $tmptext);
+	    next;
+	}
+
+	# FIRST200: extract the first 200 characters as metadata
+
+	if ($field =~ /^first200$/i) {
+	    my $tmptext = $$textref;
+	    $tmptext =~ s/\s+/ /gs;
+	    $tmptext =~ s/.*<body[^>]*>//i;
+	    $tmptext =~ s/<[^>]*>//g;
+	    $tmptext = substr ($tmptext, 0, 200);
+	    $tmptext =~ s/^\s+//;
+	    $tmptext =~ s/\s+$//;
+	    $tmptext =~ s/\s\S*$/.../;
+	    $doc_obj->add_utf8_metadata ($section, $field, $tmptext);
+	    next;
+	}
+
+	# H1: extract the text between the first <H1> and </H1> tags
+	if ($field =~ /^H1$/i) {
+	    my $tmptext = $$textref;
+	    $tmptext =~ s/\s+/ /gs;
+	    if ($tmptext =~ /<H1[^>]*>/i) {
+		$tmptext =~ s/.*<H1[^>]*>//i;
+		$tmptext =~ s/<\/H1[^>]*>.*//i;
+		$tmptext =~ s/^\s+//;
+		$tmptext =~ s/\s+$//;
+		$doc_obj->add_utf8_metadata ($section, $field, $tmptext);
+	    }
+	    next;
+	}
+    }
+}
+
+
+# evaluate any "../" to next directory up
+# evaluate any "./" as here
+sub eval_dir_dots {
+    my $self = shift (@_);
+    my ($filename) = @_;
+
+    my $dirsep_os = &util::get_os_dirsep();
+    my @dirsep = split(/$dirsep_os/,$filename);
+
+    my @eval_dirs = ();
+    foreach my $d (@dirsep) {
+	if ($d eq "..") {
+	    pop(@eval_dirs);
+
+	} elsif ($d eq ".") {
+	    # do nothing!
+
+	} else {
+	    push(@eval_dirs,$d);
+	}
+    }
+
+    return &util::filename_cat(@eval_dirs);
+}
+
+sub replace_usemap_links {
+    my $self = shift (@_);
+    my ($front, $link, $back) = @_;
+
+    $link =~ s/^\.\///;
+    return $front . $link . $back;
+}
+
+sub inc_filecount {
+    my $self = shift (@_);
+
+    if ($self->{'file_num'} == 1000) {
+	$self->{'dir_num'} ++;
+	$self->{'file_num'} = 0;
+    } else {
+	$self->{'file_num'} ++;
+    }
+}
+
+1;
Index: /main/tags/2.25/gsdl/perllib/plugins/IndexPlug.pm
===================================================================
--- /main/tags/2.25/gsdl/perllib/plugins/IndexPlug.pm	(revision 21064)
+++ /main/tags/2.25/gsdl/perllib/plugins/IndexPlug.pm	(revision 21064)
@@ -0,0 +1,139 @@
+###########################################################################
+#
+# IndexPlug.pm --
+# A component of the Greenstone digital library software
+# from the New Zealand Digital Library Project at the 
+# University of Waikato, New Zealand.
+#
+# Copyright (C) 1999 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.
+#
+###########################################################################
+
+# This recursive plugin processes an index.txt file. 
+# The index.txt file should contain the list of files to be
+# included in the collection followed by any extra metadata to
+# be associated with each file.
+
+# The index.txt file should be formatted as follows:
+# The first line may be a key (beginning with key:)
+# to name the metadata fields
+# (e.g. key: Subject Organization Date) 
+# The following lines will contain a filename followed 
+# by the value that metadata entry is to be set to.
+# (e.g. 'irma/iw097e 3.2 unesco 1993' will associate the
+# metadata Subject=3.2, Organization=unesco, and Date=1993
+# with the file irma/iw097e if the above key line was used)
+
+# Note that if any of the metadata fields use the Hierarchy
+# classifier plugin then the value they're set to should
+# correspond to the first field (the descriptor) in the
+# appropriate classification file.
+
+# Metadata values may be named separately using a tag 
+# (e.g. <Subject>3.2) and this will override any name 
+# given to them by the key line.
+# If there's no key line any unnamed metadata value will be
+# named 'Subject'.
+
+package IndexPlug;
+
+use plugin;
+use BasPlug;
+use doc;
+use util;
+use cfgread;
+
+sub BEGIN {
+    @ISA = ('BasPlug');
+}
+
+use strict;
+
+sub new {
+    my ($class) = @_;
+    my $self = new BasPlug ("IndexPlug", @_);
+
+    return bless $self, $class;
+}
+
+# return 1 if this class might recurse using $pluginfo
+sub is_recursive {
+    my $self = shift (@_);
+    
+    return 1;
+}
+
+# return number of files processed, undef if can't process
+# Note that $base_dir might be "" and that $file might 
+# include directories
+sub read {
+    my $self = shift (@_);
+    my ($pluginfo, $base_dir, $file, $metadata, $processor, $maxdocs) = @_;
+
+    my $indexfile = &util::filename_cat($base_dir, $file, "index.txt");
+    if (!-f $indexfile) {
+	# not a directory containing an index file
+	return undef;
+    }
+
+    # found an index.txt file
+    print STDERR "IndexPlug: processing $indexfile\n";
+
+    # read in the index.txt
+    my $list = &cfgread::read_cfg_file ($indexfile, undef, '^[^#]\w');
+    my @fields = ();
+    # see if there's a 'key:' line
+    if (defined $list->{'key:'}) {
+	@fields = @{$list->{'key:'}};
+    }
+
+    # process each document
+    my $count = 0;
+    foreach my $docfile (keys (%$list)) {
+	last if ($maxdocs != -1 && $count >= $maxdocs);
+	$metadata = {}; # at present we can do this as metadata
+	                # will always be empty when it arrives
+	                # at this plugin - this might cause 
+	                # problems if things change though
+
+	# note that $list->{$docfile} is an array reference
+	if ($docfile !~ /key:/i) {
+	    my $i = 0;
+	    for ($i = 0; $i < scalar (@{$list->{$docfile}}); $i ++) {
+		if ($list->{$docfile}->[$i] =~ /^<([^>]+)>(.+)$/) {
+		    unless (defined ($metadata->{$1})) {
+			$metadata->{$1} = [];
+		    } 
+		    push (@{$metadata->{$1}}, $2);
+		} elsif (scalar @fields >= $i) {
+		    unless (defined ($metadata->{$fields[$i]})) {
+			$metadata->{$fields[$i]} = [];
+		    } 
+		    push (@{$metadata->{$fields[$i]}}, $list->{$docfile}->[$i]);
+		} else {
+		    $metadata->{'Subject'} = $list->{$docfile};
+		}
+	    }
+	    $count += &plugin::read ($pluginfo, $base_dir, $docfile, $metadata, $processor, $maxdocs);
+	}
+    }
+
+    return $count; # was processed
+}
+
+
+1;
Index: /main/tags/2.25/gsdl/perllib/plugins/RecPlug.pm
===================================================================
--- /main/tags/2.25/gsdl/perllib/plugins/RecPlug.pm	(revision 21064)
+++ /main/tags/2.25/gsdl/perllib/plugins/RecPlug.pm	(revision 21064)
@@ -0,0 +1,109 @@
+###########################################################################
+#
+# RecPlug.pm --
+# A component of the Greenstone digital library software
+# from the New Zealand Digital Library Project at the 
+# University of Waikato, New Zealand.
+#
+# Copyright (C) 1999 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.
+#
+###########################################################################
+
+# plugin which recurses through directories processing
+# each file it finds
+
+package RecPlug;
+
+use BasPlug;
+use plugin;
+use util;
+
+
+BEGIN {
+    @ISA = ('BasPlug');
+}
+
+use strict;
+
+sub new {
+    my ($class) = @_;
+    my $self = new BasPlug ("RecPlug", @_);
+
+    $self->{'exclude_tail_dirs'} = []; # empty by default
+
+    return bless $self, $class;
+}
+
+# return 1 if this class might recurse using $pluginfo
+sub is_recursive {
+    my $self = shift (@_);
+
+    return 1;
+}
+
+
+# return number of files processed, undef if can't process
+# Note that $base_dir might be "" and that $file might 
+# include directories
+sub read {
+    my $self = shift (@_);
+    my ($pluginfo, $base_dir, $file, $metadata, $processor, $maxdocs) = @_;
+
+    foreach my $etd ( @{$self->{'exclude_tail_dirs'}} )
+    {
+	return 0 if ($file =~ m/$etd/);
+    }	
+
+    my (@dir, $subfile);
+
+    my $count = 0;
+
+    # see if this is a directory
+    my $dirname = &util::filename_cat ($base_dir, $file);
+    if (-d $dirname) {
+
+	# read all the files in the directory
+        if (!opendir (DIR, $dirname))
+        {
+            print STDERR "RecPlug: WARNING - couldn't read directory $dirname\n";
+            return;
+        }
+
+	@dir = readdir (DIR);
+	closedir (DIR);
+
+	print STDERR "RecPlug: getting directory $dirname\n";
+
+	# process each file
+	foreach $subfile (@dir) {
+	    last if ($maxdocs != -1 && $count >= $maxdocs);
+
+	    if ($subfile !~ /^\.\.?$/) {
+		# note: metadata is not carried on to the next level
+		$count += &plugin::read ($pluginfo, $base_dir, &util::filename_cat($file, $subfile),
+					 {}, $processor, $maxdocs);
+	    }
+	}
+	return $count;
+    }
+
+    # wasn't a directory, someone else will have to process it
+    return undef;
+}
+
+
+1;
Index: /main/tags/2.25/gsdl/perllib/plugins/TEXTPlug.pm
===================================================================
--- /main/tags/2.25/gsdl/perllib/plugins/TEXTPlug.pm	(revision 21064)
+++ /main/tags/2.25/gsdl/perllib/plugins/TEXTPlug.pm	(revision 21064)
@@ -0,0 +1,90 @@
+###########################################################################
+#
+# TEXTPlug.pm -- simple text plugin
+# A component of the Greenstone digital library software
+# from the New Zealand Digital Library Project at the 
+# University of Waikato, New Zealand.
+#
+# Copyright (C) 1999 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.
+#
+###########################################################################
+
+# creates simple single-level document. Adds Title metadata 
+# of first line of text (up to 100 characters long).
+
+package TEXTPlug;
+
+use BasPlug;
+
+sub BEGIN {
+    @ISA = ('BasPlug');
+}
+
+use strict;
+
+sub new {
+    my ($class) = @_;
+    my $self = new BasPlug ("TEXTPlug", @_);
+
+    return bless $self, $class;
+}
+
+sub get_default_process_exp {
+    my $self = shift (@_);
+
+    return q^(?i)\.te?xt$^;
+}
+
+# do plugin specific processing of doc_obj
+sub process {
+    my $self = shift (@_);
+    my ($textref, $pluginfo, $base_dir, $file, $metadata, $doc_obj) = @_;
+    
+    print STDERR "TEXTPlug: processing $file\n" 
+	if $self->{'verbosity'} > 1;
+    
+    my $cursection = $doc_obj->get_top_section();
+    
+    # get title metadata
+    # (don't need to get title if it has been passed
+    # in from another plugin)
+    if (!defined $metadata->{'Title'}) {
+	my ($title) = $$textref =~ /^([^\n]*)/;
+	if (length($title) > 100) {
+	    $title = substr ($title, 0, 100);
+	}
+	$doc_obj->add_utf8_metadata ($cursection, "Title", $title);
+    }
+    
+    # insert preformat tags and add text to document object
+    $doc_obj->add_utf8_text($cursection, "<pre>\n$$textref\n</pre>");
+
+    return 1;
+}
+
+1;
+
+
+
+
+
+
+
+
+
+
+
Index: /main/tags/2.25/gsdl/perllib/plugins/ZIPPlug.pm
===================================================================
--- /main/tags/2.25/gsdl/perllib/plugins/ZIPPlug.pm	(revision 21064)
+++ /main/tags/2.25/gsdl/perllib/plugins/ZIPPlug.pm	(revision 21064)
@@ -0,0 +1,144 @@
+###########################################################################
+#
+# ZIPPlug.pm --
+# A component of the Greenstone digital library software
+# from the New Zealand Digital Library Project at the 
+# University of Waikato, New Zealand.
+#
+# Copyright (C) 1999 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.
+#
+###########################################################################
+
+# plugin which handles compressed and/or archived input formats
+#
+# currently handled formats and file extensions are:
+# 
+# gzip (.gz, .z, .tgz, .taz)
+# bzip (.bz)
+# zip (.zip)
+# tar (.tar)
+#
+# this plugin relies on the following utilities being present 
+# (if trying to process the corresponding formats)
+#
+# gunzip (for gzip)
+# bunzip (for bzip)
+# unzip (for zip)
+# tar (for tar) 
+
+package ZIPPlug;
+
+use BasPlug;
+use plugin;
+use util;
+use Cwd;
+
+
+BEGIN {
+    @ISA = ('BasPlug');
+}
+
+use strict;
+
+sub new {
+    my ($class) = @_;
+    my $self = new BasPlug ("ZIPPlug", @_);
+
+    return bless $self, $class;
+}
+
+# this is a recursive plugin
+sub is_recursive {
+    my $self = shift (@_);
+
+    return 1;
+}
+
+# return number of files processed, undef if can't process
+# Note that $base_dir might be "" and that $file might 
+# include directories
+sub read {
+    my $self = shift (@_);
+    my ($pluginfo, $base_dir, $file, $metadata, $processor, $maxdocs) = @_;
+
+    if ($file =~ /\.(gz|tgz|z|taz|bz|zip|tar)$/i) {
+
+	my $filename = &util::filename_cat ($base_dir, $file);
+	if (!-e $filename) {
+	    print STDERR "ZIPPLug: WARNING: $filename does not exist\n";
+	    return undef;
+	}
+	
+	my ($file_only) = $file =~ /([^\\\/]*)$/;
+	my $tmpdir = &util::get_tmp_filename ();
+	&util::mk_all_dir ($tmpdir);
+
+	print STDERR "ZIPPlug: extracting $file_only to $tmpdir\n";
+
+	# save current working directory
+	my $cwd = cwd();
+	chdir ($tmpdir) || die;
+	&util::cp ($filename, $tmpdir);
+	
+	if ($file =~ /\.bz$/i) {
+	    $self->bunzip ($file_only);
+	} elsif ($file =~ /\.zip$/i) {
+	    $self->unzip ($file_only);
+	} elsif ($file =~ /\.tar$/i) {
+	    $self->untar ($file_only);
+	} else {
+	    $self->gunzip ($file_only);
+	}
+
+	chdir ($cwd) || die;
+
+	my $numdocs = &plugin::read ($pluginfo, "", $tmpdir, $metadata, $processor, $maxdocs);
+	&util::rm_r ($tmpdir);
+	return $numdocs;
+
+    } else {
+	return undef;
+    }
+}
+
+sub bunzip {
+    my $self = shift (@_);
+    my ($file) = @_;
+    system ("bunzip $file");
+}
+
+sub unzip {
+    my $self = shift (@_);
+    my ($file) = @_;
+    system ("unzip $file");
+    &util::rm ($file) if -e $file;
+}
+
+sub untar {
+    my $self = shift (@_);
+    my ($file) = @_;
+    system ("tar xf $file");
+    &util::rm ($file) if -e $file;
+}
+
+sub gunzip {
+    my $self = shift (@_);
+    my ($file) = @_;
+    system ("gunzip $file");
+}
+
+1;
Index: /main/tags/2.25/gsdl/perllib/remproc.pm
===================================================================
--- /main/tags/2.25/gsdl/perllib/remproc.pm	(revision 21064)
+++ /main/tags/2.25/gsdl/perllib/remproc.pm	(revision 21064)
@@ -0,0 +1,59 @@
+###########################################################################
+#
+# remproc.pm -- document processor used to cache all documents in memory
+# A component of the Greenstone digital library software
+# from the New Zealand Digital Library Project at the 
+# University of Waikato, New Zealand.
+#
+# Copyright (C) 1999 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 remproc;
+
+use classify;
+use doc;
+use docproc;
+
+BEGIN {
+    @ISA = ('docproc');
+}
+
+
+sub new {
+    my ($class) = @_;
+    my $self = {'docs'=>[]};
+
+    return bless $self, $class;
+}
+
+sub process {
+    my $self = shift (@_);
+    my ($doc_obj, $filename) = @_;
+
+    push (@{$self->{'docs'}}, {'doc_obj'=>$doc_obj,
+			       'filename'=>$filename});
+}
+
+sub get_doc_list {
+    my $self = shift (@_);
+
+    return $self->{'docs'};
+}
+
+1;
+
Index: /main/tags/2.25/gsdl/perllib/sorttools.pm
===================================================================
--- /main/tags/2.25/gsdl/perllib/sorttools.pm	(revision 21064)
+++ /main/tags/2.25/gsdl/perllib/sorttools.pm	(revision 21064)
@@ -0,0 +1,120 @@
+###########################################################################
+#
+# sorttools.pm --
+# A component of the Greenstone digital library software
+# from the New Zealand Digital Library Project at the 
+# University of Waikato, New Zealand.
+#
+# Copyright (C) 1999 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.
+#
+###########################################################################
+
+# various subroutines to format strings
+# for sorting
+
+package sorttools;
+
+
+# format an english string for sorting
+# i.e. convert to lowercase, remove the, a or an
+# from beginning of string etc.
+sub format_string_english {
+    my ($stringref) = @_;
+
+    $$stringref =~ tr/A-Z/a-z/;
+    $$stringref =~ s/[^a-z0-9 ]//g;
+    $$stringref =~ s/^\s*(the|a|an)\b//;
+    $$stringref =~ s/^\s+//;
+}
+
+# format an english name for sorting
+# i.e. convert to lowercase, put surname before
+# first names etc.    
+sub format_string_name_english {
+    my ($stringref) = @_;
+
+    $$stringref =~ tr/A-Z/a-z/;
+    $$stringref =~ s/[^a-z0-9 ]//g;
+    $$stringref =~ s/\s+/ /g;
+    $$stringref =~ s/^\s+//;
+    my @names = split / /, $$stringref;
+    my $surname = pop @names;
+    while (scalar @names && $surname =~ /^(jnr|snr)$/i) {
+	$surname = pop @names;
+    }
+    $$stringref = $surname . " " . $$stringref;
+}
+
+# takes arguments of day, month, year and converts to
+# date of form yyyymmdd. month may be full (e.g. "January"),
+# abbreviated (e.g. "Jan"), or a number (1-12). Years like "86" 
+# will be assumed to be "1986".
+sub format_date {
+    my ($day, $month, $year) = @_;
+
+    my %months = ('january' => '01', 'jan' => '01', 'february' => '02', 'feb' => '02',
+		  'march' => '03', 'mar' => '03', 'april' => '04', 'apr' => '04',
+		  'may' => '05', 'june' => '06', 'jun' => '06', 'july' => '07', 
+		  'jul' => '07', 'august' => '08', 'aug' => '08', 'september' => '09', 
+		  'sep' => '09', 'october' => '10', 'oct' => '10', 'november' => '11', 
+		  'nov' => '11', 'december' => '12', 'dec' => '12');
+
+    $month =~ tr/A-Z/a-z/;
+    
+    if ($day < 1) { 
+	print STDERR "sorttools::format_date WARNING day $day out of range\n";
+	$day = "01";
+    } elsif ($day > 31) {
+	print STDERR "sorttools::format_date WARNING day $day out of range\n";
+	$day = "31";
+    }
+
+    $day = "0$day" if (length($day) == 1);
+
+    if ($month =~ /^\d\d?$/) {
+	if ($month < 1) {
+	    print STDERR "sorttools::format_date WARNING month $month out of range\n";
+	    $month = "01";
+	} elsif ($month > 12) {
+	    print STDERR "sorttools::format_date WARNING month $month out of range\n";
+	    $month = "12";
+	}
+	if ($month =~ /^\d$/) {
+	    $month = "0" . $month;
+	}
+    } elsif (!defined $months{$month}) {
+	print STDERR "sorttools::format_date WARNING month $month out of range\n";
+	$month = "01";
+    } else {
+	$month = $months{$month};
+    }
+    
+    if ($year !~ /^\d\d\d\d$/) {
+	if ($year !~ /^\d\d$/) {
+	    print STDERR "sorttools::format_date WARNING year $year assumed to be 19$year\n";
+	    $year = "19" . $year;
+	} else {
+	    print STDERR "sorttools::format_date WARNING year $year out of range - reset to 1900\n";
+	    $year = "1900";
+	}
+    }
+
+    return "$year$month$day";
+}
+
+
+1;
Index: /main/tags/2.25/gsdl/perllib/textcat.pm
===================================================================
--- /main/tags/2.25/gsdl/perllib/textcat.pm	(revision 21064)
+++ /main/tags/2.25/gsdl/perllib/textcat.pm	(revision 21064)
@@ -0,0 +1,162 @@
+###########################################################################
+#
+# textcat.pm -- Identify the language of a piece of text
+#
+#
+# This file is based on TextCat version 1.08 by Gertjan van Noord
+# Copyright (C) 1997 Gertjan van Noord (vannoord@let.rug.nl)
+# TextCat is available from: http://odur.let.rug.nl/~vannoord/TextCat 
+#
+# It was modified by Gordon Paynter (gwp@cs.waikato.ac.nz) and turned
+# into a package for use in Greenstone digital library system.  Most of
+# the modifications consist of commenting out or deleting functionality
+# I don't need.  
+#
+#
+# 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 textcat;
+
+use strict;
+#use Benchmark;
+
+# OPTIONS
+my $model_dir = $ENV{'GSDLHOME'} . "/perllib/textcat";
+
+my $opt_f = 1;                # Ngrams which occur <= this number of times are removed
+my $opt_t = 400;              # topmost number of ngrams that should be used
+my $opt_u = 1.05;             # how much worse result must be before it is ignored
+
+my $non_word_characters = '0-9\s';
+
+
+# CLASSIFICATION
+#
+# What language is a text string?
+#   Input:  text string
+#   Output: array of language names
+
+sub classify {
+  my ($input)=@_;
+  my %results=();
+  my $maxp = $opt_t;
+
+  # open directory to find which languages are supported
+  opendir DIR, "$model_dir" or die "directory $model_dir: $!\n";
+  my @languages = sort(grep { s/\.lm// && -r "$model_dir/$_.lm" } readdir(DIR));
+  closedir DIR;
+  @languages or die "sorry, can't read any language models from $model_dir\n" .
+    "language models must reside in files with .lm ending\n";
+
+  # create ngrams for input. Note that hash %unknown is not used;
+  # it contains the actual counts which are only used under -n: creating
+  # new language model (and even then they are not really required).
+  my @unknown=create_lm($input);
+  # load model and count for each language.
+  my $language;
+  # my $t1 = new Benchmark;
+  foreach $language (@languages) {
+    # loads the language model into hash %$language.
+    my %ngram=();
+    my $rang=1;
+    open(LM,"$model_dir/$language.lm") || die "cannot open $language.lm: $!\n";
+    while (<LM>) {
+      chomp;
+      # only use lines starting with appropriate character. Others are
+      # ignored.
+      if (/^[^$non_word_characters]+/o) {
+	$ngram{$&} = $rang++;
+      } 
+    }
+    close(LM);
+    #print STDERR "loaded language model $language\n" if $opt_v;
+    
+    # compares the language model with input ngrams list
+    my ($i,$p)=(0,0);
+    while ($i < @unknown) {
+      if ($ngram{$unknown[$i]}) {
+	$p=$p+abs($ngram{$unknown[$i]}-$i);
+      } else { 
+	$p=$p+$maxp; 
+      }
+      ++$i;
+    }
+    #print STDERR "$language: $p\n" if $opt_v;
+    
+    $results{$language} = $p;
+  }
+  # print STDERR "read language models done (" . 
+  #   timestr(timediff(new Benchmark, $t1)) . 
+  #   ".\n" if $opt_v;
+  my @results = sort { $results{$a} <=> $results{$b} } keys %results;
+  
+  # print join("\n",map { "$_\t $results{$_}"; } @results),"\n" if $opt_v;
+  my $a = $results{$results[0]};
+  
+  my @answers=(shift(@results));
+  while (@results && $results{$results[0]} < ($opt_u *$a)) {
+    @answers=(@answers,shift(@results));
+  }
+
+  return @answers;
+}
+
+
+
+sub create_lm {
+  # my $t1 = new Benchmark;
+  my $ngram;
+  ($_,$ngram) = @_;  #$ngram contains reference to the hash we build
+                     # then add the ngrams found in each word in the hash
+  my $word;
+  foreach $word (split("[$non_word_characters]+")) {
+    $word = "_" . $word . "_";
+    my $len = length($word);
+    my $flen=$len;
+    my $i;
+    for ($i=0;$i<$flen;$i++) {
+      $$ngram{substr($word,$i,5)}++ if $len > 4;
+      $$ngram{substr($word,$i,4)}++ if $len > 3;
+      $$ngram{substr($word,$i,3)}++ if $len > 2;
+      $$ngram{substr($word,$i,2)}++ if $len > 1;
+      $$ngram{substr($word,$i,1)}++;
+      $len--;
+    }
+  }
+  ###print "@{[%$ngram]}";
+  # my $t2 = new Benchmark;
+  # print STDERR "count_ngrams done (". 
+  #   timestr(timediff($t2, $t1)) .").\n" if $opt_v;
+
+  # as suggested by Karel P. de Vos, k.vos@elsevier.nl, we speed up
+  # sorting by removing singletons
+  map { my $key=$_; if ($$ngram{$key} <= $opt_f) 
+             { delete $$ngram{$key}; }; } keys %$ngram;
+
+  
+  # sort the ngrams, and spit out the $opt_t frequent ones.
+  # adding  `or $a cmp $b' in the sort block makes sorting five
+  # times slower..., although it would be somewhat nicer (unique result)
+  my @sorted = sort { $$ngram{$b} <=> $$ngram{$a} } keys %$ngram;
+  splice(@sorted,$opt_t) if (@sorted > $opt_t); 
+  # print STDERR "sorting done (" . 
+  #  timestr(timediff(new Benchmark, $t2)) . 
+  #    ").\n" if $opt_v;
+  return @sorted;
+}
+
+1;
Index: /main/tags/2.25/gsdl/perllib/textcat/Other/afrikaans.lm
===================================================================
--- /main/tags/2.25/gsdl/perllib/textcat/Other/afrikaans.lm	(revision 21064)
+++ /main/tags/2.25/gsdl/perllib/textcat/Other/afrikaans.lm	(revision 21064)
@@ -0,0 +1,400 @@
+_	 23602
+e	 8036
+a	 4087
+n	 3782
+i	 3726
+o	 3314
+r	 2951
+s	 2885
+t	 2749
+d	 2479
+e_	 2118
+l	 1854
+k	 1741
+ie	 1670
+g	 1601
+n_	 1447
+m	 1440
+_d	 1219
+t_	 1143
+er	 1124
+h	 1124
+u	 1110
+ie_	 1079
+y	 1048
+w	 986
+s_	 982
+_s	 969
+_h	 956
+di	 924
+an	 922
+r_	 912
+aa	 882
+v	 876
+en	 807
+_di	 807
+.	 790
+y_	 747
+_v	 709
+et	 706
+._	 694
+die	 691
+die_	 667
+_n	 666
+_die	 651
+p	 639
+_m	 634
+_die_	 633
+_w	 632
+ee	 607
+ge	 606
+_o	 598
+b	 586
+te	 568
+,	 560
+in	 555
+k_	 550
+_e	 550
+,_	 548
+oo	 516
+et_	 511
+de	 509
+el	 489
+_g	 486
+f	 461
+ar	 451
+ni	 450
+nd	 442
+an_	 440
+en_	 437
+_i	 426
+he	 423
+g_	 418
+_t	 412
+oe	 410
+at	 406
+er_	 400
+om	 381
+wa	 378
+_a	 378
+_b	 377
+_k	 371
+nie	 371
+_he	 370
+aar	 355
+_ge	 351
+es	 351
+_ni	 348
+da	 346
+m_	 342
+ou	 338
+it	 335
+_nie	 335
+d_	 332
+l_	 330
+_wa	 329
+or	 327
+le	 326
+we	 326
+ek	 324
+het	 321
+me	 319
+_het	 319
+is	 318
+j	 315
+at_	 311
+on	 309
+se	 308
+_en	 298
+ma	 294
+st	 291
+as	 280
+va	 277
+_en_	 270
+re	 270
+"	 269
+'	 265
+het_	 261
+_het_	 260
+om_	 254
+al	 252
+ar_	 250
+li	 248
+te_	 247
+aar_	 247
+_da	 245
+u_	 242
+nde	 241
+ou_	 237
+_l	 231
+be	 229
+_'	 226
+rd	 224
+_va	 224
+ig	 223
+ng	 222
+ns	 221
+ve	 220
+it_	 218
+_j	 216
+_me	 216
+sy	 215
+ke	 213
+_sy	 212
+aan	 212
+van	 212
+_in	 210
+is_	 210
+in_	 208
+sy_	 206
+_sy_	 206
+'n	 205
+ro	 205
+ko	 204
+_'n	 203
+ra	 203
+'n_	 203
+_'n_	 202
+so	 202
+D	 202
+ho	 201
+rs	 200
+eer	 200
+ik	 199
+la	 198
+_te	 196
+_van	 196
+_ma	 195
+as_	 194
+ui	 194
+ver	 192
+e.	 192
+der	 191
+to	 188
+op	 187
+van_	 184
+ag	 184
+_ve	 182
+and	 180
+_van_	 178
+ha	 178
+f_	 176
+ka	 176
+ne	 175
+_is	 175
+sk	 174
+e._	 174
+oor	 174
+_ver	 170
+ek_	 170
+_hy	 170
+hy	 170
+p_	 168
+_be	 168
+ri	 168
+ur	 167
+nie_	 165
+_so	 165
+_D	 164
+si	 164
+ll	 164
+no	 164
+_in_	 163
+_hy_	 162
+hy_	 162
+ed	 161
+ers	 160
+_r	 156
+ak	 156
+_ho	 155
+_nie_	 153
+eg	 153
+nt	 152
+de_	 152
+_p	 151
+_we	 148
+_is_	 148
+ei	 147
+es_	 142
+maa	 142
+wee	 142
+na	 141
+nder	 139
+a_	 138
+ing	 138
+ew	 138
+S	 135
+lle	 135
+_om	 135
+_te_	 134
+eu	 134
+ie.	 134
+wo	 132
+em	 132
+wat	 131
+_no	 130
+_"	 130
+vo	 130
+E	 129
+H	 128
+_wat	 127
+ti	 126
+mo	 126
+A	 126
+e,	 126
+_ha	 125
+vi	 125
+el_	 125
+ter	 125
+e,_	 124
+dat	 124
+eer_	 124
+wat_	 124
+le_	 124
+ta	 124
+Di	 123
+dat_	 123
+_wat_	 122
+ie._	 122
+was	 121
+ste	 121
+_H	 121
+_se	 121
+se_	 120
+ul	 120
+al_	 120
+_was	 120
+_om_	 119
+_st	 119
+lik	 118
+"_	 118
+_ko	 118
+_maa	 118
+lo	 117
+_to	 117
+ns_	 115
+aan_	 115
+nie.	 114
+_vi	 114
+met	 114
+_nie.	 111
+nk	 110
+_Di	 110
+-	 110
+_op	 109
+_oo	 109
+_on	 108
+ir	 108
+ord	 108
+uit	 106
+ens	 105
+_was_	 105
+was_	 105
+een	 105
+_met	 105
+os	 105
+_S	 104
+nie._	 104
+ig_	 103
+_sk	 102
+op_	 101
+_ek	 101
+_wee	 101
+ir_	 101
+met_	 100
+_met_	 100
+rt	 100
+ik_	 99
+end	 99
+nd_	 99
+gt	 99
+ond	 98
+ot	 98
+_aa	 97
+og	 97
+vir_	 95
+vir	 95
+_ka	 94
+hu	 94
+_mo	 94
+_vir_	 94
+_vir	 94
+_dit	 93
+kr	 93
+am	 93
+ol	 93
+dit	 93
+_ek_	 93
+ki	 93
+sa	 93
+_aan	 92
+man	 92
+jy	 92
+ng_	 92
+aak	 92
+lle_	 91
+_hu	 91
+_na	 91
+_vo	 90
+ewe	 90
+of	 90
+jy_	 90
+_dit_	 90
+dit_	 90
+_jy	 89
+der_	 89
+jo	 89
+_f	 88
+_u	 88
+sie	 87
+_dat	 87
+_jy_	 87
+daa	 87
+do	 87
+vr	 87
+wi	 86
+ry	 86
+_dat_	 86
+eur	 86
+rs_	 85
+_jo	 85
+_wo	 84
+_ne	 84
+jie	 84
+ji	 84
+pe	 83
+moe	 83
+my	 82
+ull	 82
+Die	 81
+maar	 81
+_hom	 81
+ulle	 81
+_maar	 81
+hom	 81
+_uit	 80
+_ui	 80
+ges	 80
+raa	 80
+or_	 80
+ies	 80
+jou	 79
+_la	 79
+maar_	 79
+ulle_	 79
+_daa	 79
+Die_	 79
+daar	 78
+_daar	 78
+ien	 78
+_my	 78
+_jou	 78
+ok	 78
+il	 78
+lik_	 77
+sta	 77
+_Die	 77
+ur_	 77
+ga	 77
+ag_	 77
+kan	 77
Index: /main/tags/2.25/gsdl/perllib/textcat/Other/albanian.lm
===================================================================
--- /main/tags/2.25/gsdl/perllib/textcat/Other/albanian.lm	(revision 21064)
+++ /main/tags/2.25/gsdl/perllib/textcat/Other/albanian.lm	(revision 21064)
@@ -0,0 +1,400 @@
+_	 19480
+ë	 4099
+e	 4082
+t	 3635
+i	 3134
+a	 2893
+r	 2820
+n	 2610
+s	 2380
+h	 2060
+ë_	 2055
+e_	 1825
+j	 1677
+u	 1489
+d	 1381
+o	 1370
+m	 1318
+k	 1264
+të	 1091
+p	 1072
+_t	 1068
+sh	 998
+l	 936
+_n	 876
+a_	 822
+,	 816
+,_	 808
+të_	 795
+i_	 770
+_p	 739
+_m	 702
+_s	 700
+te	 653
+ër	 620
+_d	 613
+_e	 607
+g	 602
+_k	 601
+_të	 593
+.	 575
+_të_	 574
+v	 567
+_e_	 554
+r_	 525
+._	 523
+ht	 503
+n_	 480
+he	 473
+në	 462
+sht	 461
+te_	 457
+q	 454
+nd	 436
+ri	 432
+is	 414
+et	 403
+b	 402
+je	 401
+me	 395
+in	 391
+it	 381
+rë	 374
+_a	 374
+t_	 359
+ur	 353
+_i	 346
+ar	 342
+ës	 339
+er	 338
+në_	 338
+ën	 338
+dh	 337
+en	 336
+pë	 334
+f	 328
+_v	 323
+jë	 318
+nj	 313
+ish	 312
+për	 294
+y	 285
+z	 282
+es	 281
+at	 274
+_me	 273
+_q	 273
+gj	 269
+ra	 261
+as	 258
+_në	 256
+ku	 256
+j_	 250
+ta	 249
+re	 246
+një	 245
+o_	 243
+ni	 243
+_pë	 240
+hte	 240
+_nj	 239
+on	 239
+isht	 236
+pa	 234
+th	 233
+shte	 233
+_për	 232
+se	 228
+_g	 223
+ve	 221
+in_	 220
+s_	 219
+_në_	 219
+do	 218
+hte_	 218
+më	 216
+ti	 215
+aj	 212
+shte_	 212
+ej	 212
+u_	 211
+që	 211
+_sh	 210
+nt	 207
+jë_	 206
+_b	 205
+_një	 203
+di	 202
+_pa	 201
+_i_	 201
+ll	 199
+_f	 199
+kë	 198
+me_	 197
+dhe	 195
+ishte	 195
+si	 194
+hi	 191
+he_	 188
+-	 187
+ja	 187
+_që	 187
+ua	 186
+il	 184
+_dh	 184
+ur_	 183
+ër_	 182
+or	 180
+se_	 179
+që_	 178
+S	 176
+ç	 175
+_h	 173
+an	 172
+një_	 172
+ng	 170
+nte	 170
+_që_	 169
+_S	 169
+rë_	 166
+dhe_	 165
+_me_	 164
+ka	 162
+im	 159
+hë	 158
+mi	 157
+to	 156
+tu	 156
+ën_	 155
+_një_	 154
+ha	 153
+nte_	 150
+tr	 148
+sa	 148
+ët	 148
+_gj	 148
+un	 147
+rr	 147
+ë,	 147
+_dhe	 147
+ej_	 147
+ki	 146
+ë,_	 146
+_ku	 145
+_-	 144
+_ng	 142
+ik	 141
+_nd	 140
+end	 138
+uk	 137
+etë	 135
+ko	 135
+_dhe_	 135
+_ve	 132
+va	 131
+_l	 131
+për_	 131
+shi	 131
+erë	 129
+ke	 127
+kis	 127
+së	 126
+jo	 125
+li	 124
+ga	 124
+kish	 123
+_ki	 122
+po	 122
+_se	 122
+'	 121
+du	 120
+mb	 120
+_më	 119
+Si	 115
+më_	 115
+esh	 115
+_si	 114
+qe	 114
+lë	 114
+_kis	 113
+oh	 113
+_kish	 113
+_Si	 113
+pr	 112
+_u	 112
+uar	 111
+de	 111
+hu	 111
+_th	 111
+al	 111
+ta_	 109
+ilv	 108
+Sil	 108
+Silv	 108
+lv	 108
+k_	 108
+e,	 108
+ji	 107
+e,_	 106
+_Sil	 106
+_Silv	 106
+_r	 105
+os	 104
+_se_	 104
+kisht	 102
+_di	 102
+st	 101
+_për_	 101
+bë	 101
+tj	 100
+_nga	 99
+nga	 99
+_du	 98
+ra_	 98
+vë	 98
+gji	 98
+_ish	 96
+rt	 96
+_is	 96
+ro	 95
+ir	 94
+ga_	 94
+ësh	 94
+ont	 93
+c	 93
+t,	 93
+t,_	 93
+hin	 92
+a,	 92
+_at	 92
+und	 92
+jt	 91
+_mb	 91
+a,_	 91
+tje	 90
+_nga_	 90
+_do	 90
+_pr	 90
+rit	 90
+men	 90
+nga_	 90
+ri_	 89
+N	 89
+ma	 89
+it_	 88
+_kë	 88
+-_	 88
+m_	 87
+jo_	 87
+onte	 87
+atë	 87
+la	 87
+ëri	 87
+ilva	 86
+shin	 86
+ë.	 86
+Silva	 86
+lva	 86
+së_	 85
+jer	 85
+et_	 85
+_po	 85
+ës_	 84
+kur	 84
+ru	 84
+nin	 83
+ot	 83
+hin_	 83
+_N	 83
+her	 83
+htë	 82
+ap	 82
+shin_	 82
+mo	 81
+ash	 81
+tha	 81
+_ç	 81
+ë._	 81
+ëm	 81
+jit	 80
+_ta	 80
+ul	 80
+le	 80
+ho	 80
+_z	 79
+dr	 78
+jet	 78
+nin_	 78
+_më_	 78
+gjit	 78
+A	 78
+hk	 78
+onte_	 78
+oni	 77
+lo	 77
+ba	 77
+herë	 77
+ndo	 76
+shk	 76
+mend	 75
+_vë	 75
+ha_	 75
+dë	 75
+tur	 74
+_A	 74
+el	 74
+bi	 74
+_ko	 74
+uk_	 73
+erë_	 73
+si_	 73
+_sa	 73
+ar_	 72
+P	 72
+rs	 72
+pas	 72
+ith	 72
+uar_	 71
+_isht	 71
+ai	 70
+e.	 70
+_vet	 70
+vet	 70
+_bë	 70
+zi	 70
+d_	 70
+jith	 70
+da	 70
+gjith	 69
+duk	 69
+na	 69
+hej	 69
+tër	 68
+_men	 68
+_ka	 68
+am	 68
+nd_	 68
+_c	 67
+_pas	 67
+_duk	 67
+jes	 67
+ak	 67
+s,	 67
+e._	 67
+s,_	 67
+K	 67
+ësht	 67
+mu	 66
+kur_	 66
+yr	 66
+em	 65
+_së	 65
+tha_	 65
+imi	 65
+ie	 65
+hej_	 64
+_së_	 64
+_u_	 64
+?	 64
+fu	 64
+_P	 64
Index: /main/tags/2.25/gsdl/perllib/textcat/Other/amharic-utf.lm
===================================================================
--- /main/tags/2.25/gsdl/perllib/textcat/Other/amharic-utf.lm	(revision 21064)
+++ /main/tags/2.25/gsdl/perllib/textcat/Other/amharic-utf.lm	(revision 21064)
@@ -0,0 +1,406 @@
+á	 21403
+_	 10092
+	 7734
+á	 6558
+_á	 5003
+	 4717
+	 4401
+á	 4274
+á	 4176
+	 4054
+á	 3868
+	 2728
+	 1656
+á	 1591
+µ	 1579
+ 	 1425
+ á	 1402
+_á	 1261
+_á	 1231
+š	 1217
+á	 1187
+šá	 1183
+_á	 1160
+	 1145
+á	 1123
+­	 1097
+á	 1043
+	 1043
+°	 1041
+°á	 1004
+_á	 991
+á	 936
+«	 880
+	 855
+á	 855
+¥	 849
+µá	 805
+µ	 783
+áµ	 783
+µ_	 763
+«á	 709
+¥á	 704
+ 	 682
+á 	 682
+­á	 679
+	 670
+á	 667
+á á	 666
+ á	 666
+á	 658
+	 643
+áš	 637
+š	 637
+šá	 627
+ášá	 627
+á	 614
+	 614
+­	 611
+á­	 611
+_	 588
+µ_	 583
+áµ_	 583
+_áš	 577
+_ášá	 574
+áá	 573
+á	 573
+áá	 570
+á	 570
+á	 563
+	 563
+á	 557
+áá	 557
+ 	 554
+á 	 554
+á á	 553
+á°	 553
+ á	 553
+°	 553
+á°á	 547
+°á	 547
+á	 534
+	 534
+ á	 532
+-	 531
+áµ	 525
+µ	 525
+--	 521
+á	 515
+	 515
+---	 512
+----	 503
+_á 	 499
+-----	 494
+_á á	 487
+á	 479
+šá	 477
+_	 473
+á	 469
+áá	 469
+á_	 468
+_	 468
+¢	 465
+³	 464
+á«	 457
+«	 457
+°á	 444
+_á 	 424
+_á á	 424
+áµá	 423
+µá	 423
+­_	 415
+³á	 402
+œ	 401
+	 390
+á	 389
+	 382
+_	 378
+á_	 378
+á	 365
+«á	 364
+á«á	 364
+	 363
+áá	 357
+á	 357
+£	 356
+¢_	 351
+œ	 347
+áœ	 347
+	 341
+á	 341
+á­	 337
+¢	 337
+á¢	 337
+­	 337
+¢_	 337
+á¢_	 337
+á	 336
+
+	 334
+¥	 320
+á¥	 320
+£á	 320
+á	 320
+¥á	 318
+á¥á	 318
+­_	 314
+á­_	 314
+á	 312
+á	 311
+šá	 301
+á	 300
+á	 300
+	 300
+	 300
+ á	 299
+á	 297
+á­á	 294
+	 294
+á	 294
+­á	 294
+	 293
+á	 291
+áš	 291
+á	 291
+á	 291
+š	 291
+áá	 291
+áá	 291
+áá	 291
+á°	 288
+°	 288
+_á¥	 285
+_á¥á	 283
+®	 279
+šá	 279
+ášá	 279
+ á	 279
+á á	 279
+áá	 276
+á	 276
+á	 276
+_á	 272
+¥	 270
+á¥	 270
+_	 269
+áá	 264
+á	 264
+á	 262
+¥á	 262
+áá	 262
+¥á	 262
+á­á	 261
+­á	 261
+	 260
+á	 260
+á°á	 259
+°á	 259
+á«	 254
+£	 254
+á£	 254
+«	 254
+	 253
+®á	 249
+á	 247
+á	 245
+µá	 244
+á	 242
+	 242
+ášá	 242
+šá	 242
+áá	 238
+á	 238
+ á	 237
+áš	 237
+š	 237
+°á	 236
+á°á	 236
+á_	 235
+_	 235
+á	 234
+­á	 233
+«á	 233
+£á	 230
+	 230
+á£á	 230
+á	 230
+áµ	 228
+µ	 228
+_á	 227
+á	 227
+_áá	 226
+šá	 225
+ášá	 225
+²	 225
+á¢	 222
+á¢_	 222
+ á	 216
+á¥á	 214
+áá	 214
+¥á	 214
+á	 214
+
+á	 213
+²á	 212
+«á	 210
+á	 209
+áá	 209
+©	 208
+á	 207
+á	 206
+œ_	 206
+¥á	 205
+á¥á	 205
+á	 202
+°	 200
+á³	 200
+³	 200
+á°	 200
+«á	 199
+á«á	 199
+á°á	 198
+°á	 198
+áµá	 195
+á	 195
+µá	 195
+	 195
+á	 194
+áá	 194
+œá	 191
+	 191
+œ_	 189
+áœ_	 189
+á	 188
+žá	 186
+ž	 186
+_á	 184
+_áá	 183
+áá	 183
+á	 183
+¥á	 180
+šá	 179
+ášá	 179
+á	 178
+±	 177
+¥áá	 177
+_áš	 175
+¥	 174
+á¥	 174
+ á	 172
+á á	 172
+_ášá	 170
+	 170
+«_	 169
+¥á	 169
+á	 166
+°á	 166
+áá	 165
+_	 165
+á	 165
+á_	 163
+_	 163
+ž	 160
+áž	 160
+ážá	 160
+žá	 160
+á	 160
+šá	 159
+žá	 159
+	 158
+á	 158
+­á	 158
+£á	 156
+áá	 155
+á	 155
+áœá	 154
+žá	 154
+á_	 154
+œá	 154
+žá	 154
+ážá	 154
+_	 154
+µá	 152
+³á	 151
+žá	 151
+á	 150
+_á	 150
+¶	 150
+_áá	 150
+	 150
+_á­á	 150
+_á­	 150
+³á	 149
+á³á	 149
+á¢	 148
+ á	 147
+á°á	 147
+°á	 147
+á á	 147
+	 146
+_á°	 146
+_á°á	 146
+áá	 145
+á	 145
+áµá	 144
+µá	 144
+á	 144
+µá	 144
+á
+	 143
+
+	 143
+¥_	 143
+áá	 142
+á	 142
+³	 141
+á³	 141
+á	 139
+á
+	 138
+
+	 138
+á	 137
+áá	 137
+«á	 137
+á	 136
+á	 136
+á á	 135
+ á	 135
+á	 135
+áµá	 134
+µá	 134
+á 	 133
+á³á	 133
+ 	 133
+áá	 133
+á	 133
+á	 133
+³á	 133
+	 133
+áá	 132
+á	 132
+šá°	 131
+á«á	 131
+šá°á	 131
+«á	 131
+á	 129
+µá	 128
+­	 128
+á­	 128
+á	 128
+	 128
+°á	 127
+ á	 127
+á á	 127
+«	 126
+á«	 126
+á	 124
+á á	 123
+°á	 123
+á«á	 123
+«á	 123
+ á	 123
+šá	 122
+ášá	 122
+á	 121
+áá	 121
Index: /main/tags/2.25/gsdl/perllib/textcat/Other/arabic-iso8859_6.lm
===================================================================
--- /main/tags/2.25/gsdl/perllib/textcat/Other/arabic-iso8859_6.lm	(revision 21064)
+++ /main/tags/2.25/gsdl/perllib/textcat/Other/arabic-iso8859_6.lm	(revision 21064)
@@ -0,0 +1,434 @@
+_	 9692
+Ø	 7361
+Ù	 6120
+Ø§	 2417
+§	 2417
+_Ø	 1691
+Ù	 1587
+	 1587
+Ø§Ù	 1415
+§Ù	 1415
+Ç	 1241
+_Ù	 1129
+_Ø§	 987
+§Ù	 978
+Ø§Ù	 978
+ä	 952
+_Ø§Ù	 894
+Ù
+	 869
+
+	 869
+ÙØ	 801
+Ø	 801
+	 798
+Ù	 798
+_Ø§Ù	 771
+ª	 757
+Øª	 757
+Ø§Ø	 738
+§Ø	 738
+Ù	 680
+	 680
+Ù	 659
+	 659
+è	 622
+ÙÙ	 619
+Ù	 619
+§ÙØ	 574
+Ø§ÙØ	 574
+¹	 547
+Ø¹	 547
+Ø±	 541
+±	 541
+ê	 527
+©	 512
+Ø©	 512
+
+Ø	 504
+Ù
+Ø	 504
+æ	 496
+Çä	 492
+Øš	 490
+š	 490
+Ø©_	 482
+©_	 482
+å	 477
+_Ç	 470
+Ø	 461
+ÙØ	 461
+.	 430
+_Çä	 405
+§ÙÙ	 352
+Ø§ÙÙ	 352
+Ù	 350
+	 350
+È	 340
+Ø¯	 339
+¯	 339
+ØªØ	 334
+ªØ	 334
+Ñ	 324
+	 314
+Ù	 314
+ç	 302
+_Ù	 289
+
+Ù	 278
+Ù
+Ù	 278
+ÙØ	 276
+Ø	 276
+Ø¹Ù	 270
+¹Ù	 270
+Ê	 267
+ÙÙ	 263
+Ù	 263
+Ù_	 262
+_	 262
+_Ù
+	 259
+	 258
+Ù	 258
+³	 258
+Ø³	 258
+ÙØ§	 258
+Ø§	 258
+æ_	 257
+ØšØ	 252
+šØ	 252
+Ø	 252
+ÙØ	 252
+¬	 252
+§_	 250
+Ø§_	 250
+Ï	 242
+_è	 235
+Øª_	 226
+ª_	 226
+._	 223
+±Ù	 213
+Ø±Ù	 213
+§Øª	 206
+Ø§Øª	 206
+­	 202
+Ø­	 202
+Ç_	 200
+±Ø	 199
+Ø±Ø	 199
+á	 199
+¹Ø	 198
+Ø¹Ø	 198
+šÙ	 196
+ØšÙ	 196
+ÙØ	 193
+Ø	 193
+ØªÙ	 191
+ÙÙ
+	 191
+ªÙ	 191
+Ù
+	 191
+..	 188
+Ù	 184
+	 184
+Ø¬	 183
+Ø§Ù	 180
+§Ù	 180
+§ÙØ§	 178
+_	 176
+ÙØ©	 176
+Ø©	 176
+Ù_	 176
+ã	 175
+ÙÙ	 175
+Ù	 175
+_Øš	 171
+Ì	 171
+§ÙÙ
+	 170
+Ã	 166
+_	 165
+Ù_	 165
+ÙØ	 163
+_Ù	 163
+Ø	 163
+Ž	 162
+ØŽ	 162
+Ù_	 162
+_	 162
+Ù	 161
+ÙÙ	 161
+É	 160
+â	 159
+ÙØ©_	 158
+Ø©_	 158
+	 155
+Ù	 155
+Ø³Ø	 153
+³Ø	 153
+Ù_	 150
+_	 150
+Í	 150
+Ó	 148
+§Øª_	 147
+Ø§Øª_	 147
+µ	 144
+_å	 144
+Øµ	 144
+ç_	 142
+Ù
+Ø	 139
+ÙÙ
+Ø	 139
+_ÙÙ	 136
+_Ù
+Ù	 133
+Ù
+Ø§	 130
+_ØšØ	 130
+
+Ø§	 130
+ØŽØ	 129
+ŽØ	 129
+_Ù_	 129
+¯Ø	 128
+Ø¯Ø	 128
+É_	 127
+äÇ	 127
+_Ù
+Ø	 126
+Ø±_	 124
+±_	 124
+Ø¹Ù	 123
+¹Ù	 123
+ÙÙ	 122
+Ù	 122
+ÙØ	 121
+_È	 121
+Ø	 121
+­Ø	 119
+Ø­Ø	 119
+ÙØ§Ù	 118
+Ø§Ù	 118
+ò	 117
+ê_	 117
+_Ø¹	 117
+î	 116
+Ù	 115
+_Øª	 115
+ÙÙ	 115
+äå	 113
+¯Ù	 113
+Ø¯Ù	 113
+
+Ù	 111
+Ù
+Ø¹	 111
+
+Ø¹	 111
+Ù
+Ù	 111
+Ø¹ÙÙ	 110
+¹ÙÙ	 110
+_Ã	 109
+_Ù	 108
+ÙÙ	 108
+Ù	 108
+Ù_	 102
+ÙØ§	 102
+ÙØ§Ø	 102
+Ø§Ø	 102
+ÙÙ_	 102
+Ø§	 102
+®	 101
+¬Ø	 101
+Ø®	 101
+_ÙØ	 100
+Ø¬Ø	 100
+_ÙÙ	 99
+ÙØ	 99
+Ø	 99
+Ð	 98
+¯_	 97
+Ø§Ù
+	 97
+§Ù
+	 97
+Ø¯_	 97
+...	 94
+_Ù
+Ù	 94
+šØ§	 93
+·	 93
+ØšØ§	 93
+_Ø§Ø	 93
+Ø·	 93
+Ø§	 92
+ï	 92
+ÙØ§	 92
+ÙØª	 91
+Øª	 91
+ä_	 90
+Çæ	 89
+_á	 89
+Ï_	 88
+èÇ	 87
+_Ø¹Ù	 87
+ÙÙ	 85
+Ù	 85
+èä	 84
+Ø°	 84
+
+Ù_	 84
+Ø³Ù	 84
+³Ù	 84
+Ù_	 84
+°	 84
+ÙÙ_	 84
+Ù
+Ù_	 84
+Çäå	 84
+-	 83
+®Ø	 83
+Ø®Ø	 83
+_ä	 82
+
+_	 82
+§Ø³	 82
+Ø§Ø³	 82
+Ù
+_	 82
+_Çäå	 81
+Ù
+	 80
+é	 80
+ÙÙ
+	 80
+é_	 79
+Ø§ÙØ	 79
+§ÙØ	 79
+¹_	 78
+±Ø§	 78
+¹Ø§	 78
+Ø¹Ø§	 78
+§Ø±	 78
+ÙØ§_	 78
+Ø¹_	 78
+¬_	 78
+Ø§_	 78
+Ø±Ø§	 78
+Ø§Ø±	 78
+µØ	 78
+ØµØ	 78
+.._	 77
+Ø£	 77
+..._	 77
+£	 77
+Ô	 77
+Ù	 76
+ÙÙ	 76
+ªØ±	 75
+ØªØ±	 75
+«	 74
+ÙÙ	 73
+Ø§Ù_	 73
+Ø¶	 73
+Ø«	 73
+¬Ù	 73
+Ø¬Ù	 73
+¶	 73
+§Ù_	 73
+Ù	 73
+Ù
+Ø¹Ù	 72
+
+Ø¹Ù	 72
+åæ	 71
+èÌ	 70
+Ø§	 70
+ÙØ§	 70
+­Ù	 69
+î_	 69
+Ø­Ù	 69
+êæ	 69
+Øª	 68
+ÙØª	 68
+Ø§	 68
+Ùä	 68
+_ØªØ	 68
+ÙØ§	 68
+_ê	 67
+Ë	 66
+ò.	 66
+èÏ	 66
+_¬_	 65
+³Øª	 65
+äè	 65
+Ø³Øª	 65
+_¬	 65
+Ìè	 65
+ð	 64
+ÙÙ
+Ø	 64
+áê	 64
+Ù
+Ø	 64
+èæ	 63
+Ø§Ø³Ø	 63
+Õ	 63
+§Ø³Ø	 63
+Ñ_	 62
+-_	 62
+ÇÊ	 61
+_-	 61
+Ù	 61
+ÙÙ	 61
+_Ø§Ù	 61
+åÇ	 61
+å_	 61
+äé_	 60
+§Ø¯	 60
+_ÙÙ	 60
+èÌè	 60
+Ö	 60
+Ø§Ø¯	 60
+äé	 60
+ØªØ	 59
+ÌèÏ	 59
+_-_	 59
+_Ø¹Ù	 59
+ÙØªØ	 59
+èÌèÏ	 58
+ÙÙ	 58
+²	 58
+Ø¬Ø§	 58
+Ù	 58
+Øš	 58
+ÙØš	 58
+_Ù	 58
+_åæ	 58
+Ø²	 58
+_ÙØ	 58
+¬Ø§	 58
+Ø§	 57
+§ÙØª	 57
+Ù	 57
+ÙØ§	 57
+ÙÙ	 57
+ò..	 56
+ØŽØš	 56
+ò..._	 56
+ŽØš	 56
+Çæ_	 56
+ò...	 56
+šÙ	 56
+ØšÙ	 56
+ØªØ¹	 55
+Ø¹Ù
+	 55
+¹ÙÙ	 55
+_Ù	 55
+ªØ¹	 55
+_._	 55
Index: /main/tags/2.25/gsdl/perllib/textcat/Other/armenian.lm
===================================================================
--- /main/tags/2.25/gsdl/perllib/textcat/Other/armenian.lm	(revision 21064)
+++ /main/tags/2.25/gsdl/perllib/textcat/Other/armenian.lm	(revision 21064)
@@ -0,0 +1,402 @@
+_	 49002
+³	 12626
+	 9480
+Ý	 8485
+ñ	 7623
+ï	 7071
+á	 7010
+»	 6370
+«	 6320
+¯	 5012
+ó	 4656
+	 4607
+õ	 4506
+Ç	 4210
+í	 3775
+áõ	 3655
+Ù	 3369
+ë	 3320
+	 3208
+Ï	 3016
+¯ó	 2832
+³Ý	 2755
+Û	 2552
+§	 2519
+,	 2502
+,_	 2492
+Ý_	 2177
+«	 2099
+	 2034
+é	 2007
+©	 1918
+»ñ	 1748
+³ñ	 1703
+Ñ	 1605
+«_	 1587
+É	 1558
+ã	 1528
+Ï³	 1502
+:	 1483
+:_	 1482
+ù	 1420
+_³	 1403
+ñ_	 1382
+Ç_	 1335
+Ã	 1307
+Á	 1294
+Ý»	 1281
+	 1274
+¹	 1264
+ï	 1229
+å	 1218
+ï	 1184
+÷	 1170
+³Ï	 1154
+_á	 1139
+³Û	 1130
+_Ñ	 1121
+	 1085
+	 1065
+_	 1046
+_»	 1036
+áñ	 1019
+	 1017
+õÙ	 1001
+áõÙ	 993
+ÇÝ	 987
+ï_	 964
+	 962
+_Ù	 961
+ñ³	 952
+Ù³	 951
+_	 945
+	 941
+	 938
+Ñ³	 934
+Õ	 929
+Ý»ñ	 919
+¯ï	 918
+·	 915
+ó_	 911
+»Ý	 910
+Ý³	 910
+³Ý_	 882
+«	 863
+«	 846
+ç	 834
+	 827
+©	 824
+¿	 818
+ÃÛ	 817
+õÃ	 804
+áõÃ	 804
+_	 791
+õÃÛ	 787
+áõÃÛ	 787
+£	 781
+õÝ	 753
+_¯	 750
+Ù_	 748
+_	 747
+ï	 747
+áõÝ	 744
+_¿	 732
+ñá	 730
+«	 723
+ó§	 710
+õ_	 710
+¯ó§	 709
+_Ñ³	 708
+_Ï	 705
+ï³	 703
+µ	 702
+	 697
+	 695
+§_	 684
+_§	 683
+ñÇ	 682
+
+	 672
+³Ï³	 671
+Ûá	 669
+»É	 666
+ó	 659
+ß	 659
+Í	 658
+¯ó	 658
+Ë	 653
+©	 649
+ó©	 641
+¯ó©	 641
+ó«	 640
+Ûáõ	 636
+»õ	 635
+¯ó«	 631
+_ã	 626
+	 623
+Û³	 620
+ë_	 616
+_	 615
+õÙ_	 614
+áõÙ_	 613
+Ýá	 601
+Ï³Ý	 597
+«	 596
+«_	 590
+³Ù	 590
+§	 582
+Á_	 581
+«ï	 576
+³ï	 574
+í³	 574
+	 566
+í	 564
+	 555
+_í	 532
+©¯	 527
+Ýù	 527
+©	 526
+_	 524
+©¯ó	 517
+_Ç	 511
+ï	 510
+_	 507
+§	 500
+í	 500
+ÛáõÝ	 497
+ï¯	 496
+œ	 488
+	 485
+³í	 480
+_	 480
+ó§_	 478
+¯ó§_	 477
+«¯	 476
+ÃÛá	 475
+ÃÛáõ	 475
+³Ï³Ý	 473
+_Ý	 469
+É_	 466
+­	 465
+»ñÇ	 465
+ÃÛáõÝ	 464
+_ë	 463
+õÃÛá	 459
+õÃÛáõ	 459
+áõÃÛá	 459
+Ýáõ	 454
+	 449
+_áñ	 449
+ñ»	 444
+_³Û	 442
+_	 431
+Ù»	 428
+í_	 427
+_Ï³	 422
+	 422
+©¯ó«	 421
+»õ_	 416
+ó	 416
+_¯ï	 415
+³ë	 414
+_	 413
+å³	 408
+©¯	 405
+©¯ó	 405
+ÇÝ_	 404
+©¯ó«	 400
+ó©¯	 399
+¯ó©¯	 399
+ó©¯ó	 399
+ñÇ_	 398
+¿_	 395
+Û³Ý	 394
+áñ_	 387
+-	 385
+ñáõ	 383
+«	 382
+é	 380
+ù_	 379
+ã	 377
+«¯ó	 377
+é_	 377
+áí	 376
+Ý»ñÇ	 374
+ëï	 371
+©«	 371
+»Ý_	 371
+_¹	 371
+ï	 370
+ë	 368
+³	 367
+_¿_	 366
+íá	 363
+í»	 361
+ï»	 358
+.	 357
+ÙÇ	 356
+_å	 351
+¡	 347
+_»õ	 345
+ÃÛ³	 342
+³é	 341
+_µ	 341
+_«	 340
+Ï³Ý_	 339
+ñÁ	 338
+_ï	 337
+_	 331
+¯ï_	 330
+õÃÛ³	 328
+áõÃÛ³	 328
+ÝÇ	 328
+ï	 327
+«_	 324
+_»Ý	 324
+¯£	 324
+_»õ_	 322
+Éá	 321
+»ñÇ_	 321
+_Ù»	 318
+µ³	 317
+áÕ	 317
+Ù³Ý	 316
+_·	 314
+ÝÝ	 314
+å»	 309
+_©	 309
+³Ï³Ý_	 307
+ë	 306
+»ï	 306
+_÷	 303
+ÛÝ	 302
+«÷	 302
+¹³	 302
+Çñ	 300
+¯	 299
+ÃÛ³Ý	 299
+³Ýá	 299
+_	 299
+__	 299
+Ïá	 298
+«	 298
+ñ¹	 297
+_	 294
+_áõ	 293
+_	 292
+ïá	 291
+³ó	 291
+õÃÛ³Ý	 288
+»Õ	 288
+»ë	 287
+áõ_	 286
+_
+	 286
+²	 284
+ë	 284
+¯ë	 284
+Ë³	 283
+Å	 283
+ó_	 281
+«_	 281
+Û³Ý_	 281
+`	 280
+ñ	 279
+`_	 279
+«	 279
+³Ù³	 278
+»É_	 274
+³Í	 271
+Ó	 268
+_Ù³	 266
+ç	 266
+§	 266
+ÉÇ	 266
+Ý»ñÇ_	 266
+í	 264
+Ý,	 263
+§	 263
+³_	 262
+ë¯	 262
+Ý,_	 262
+««	 259
+ÝÁ	 258
+_	 258
+Ï»	 257
+»ñÁ	 257
+Ï_	 255
+ï¯ó	 255
+_ù	 255
+_áñ_	 255
+ï	 255
+ñÏ	 253
+ÝÝ»	 252
+»ñ_	 252
+	 250
+ù³	 248
+ÝÝ»ñ	 248
+_¯ï_	 247
+Ý¹	 246
+Ýù_	 246
+	 245
+ï	 244
+³Ñ	 244
+«ï	 244
+©	 244
+»ó	 243
+ÃÛ³Ý_	 243
+ó©	 242
+¯ó©	 242
+	 241
+¯	 239
+³ñ³	 238
+ï_	 238
+³Ý³	 237
+«	 237
+í	 237
+·á	 237
+_é	 236
+ÝáõÙ	 234
+³É	 234
+«_	 233
+÷_	 233
+Ù³ñ	 233
+ë³	 232
+³Ýáõ	 232
+«	 231
+×	 230
+é	 230
+«¯	 230
+_ó	 228
+³ÛÝ	 228
+©«	 228
+Ã»	 227
+»Ýù	 227
+_ÙÇ	 226
+Ý³Ï	 223
+«_	 223
+_-	 222
+»Ï	 222
+¯ó_	 222
+éí	 220
+_Ã	 220
+_³Ý	 218
+Ï³ñ	 217
+©«	 216
+_ã	 216
+§	 216
+	 215
+	 215
+ó©«	 214
+í¯	 214
+_¯ó	 213
+û	 213
+	 213
+÷	 212
+Ñ³Ù	 211
+ï	 210
+³œ	 210
+_ó_	 210
+_«	 209
+ïí	 209
+_»Ý_	 208
Index: /main/tags/2.25/gsdl/perllib/textcat/Other/basque.lm
===================================================================
--- /main/tags/2.25/gsdl/perllib/textcat/Other/basque.lm	(revision 21064)
+++ /main/tags/2.25/gsdl/perllib/textcat/Other/basque.lm	(revision 21064)
@@ -0,0 +1,400 @@
+_	 12114
+a	 5537
+e	 4040
+i	 3103
+t	 2567
+n	 2474
+r	 2406
+o	 1937
+k	 1761
+z	 1627
+u	 1561
+d	 1367
+l	 1075
+s	 1048
+b	 995
+n_	 958
+a_	 957
+en	 802
+g	 772
+_e	 736
+er	 680
+ra	 669
+.	 625
+at	 610
+_b	 594
+ar	 589
+an	 585
+_d	 580
+,	 569
+,_	 569
+h	 563
+ta	 563
+te	 555
+._	 520
+ko	 513
+m	 503
+o_	 486
+al	 481
+en_	 471
+tz	 458
+re	 435
+_a	 423
+ik	 416
+in	 409
+it	 392
+za	 391
+ak	 388
+ba	 358
+et	 357
+da	 352
+di	 351
+ka	 350
+ze	 349
+ai	 347
+p	 340
+ri	 335
+la	 329
+an_	 327
+de	 322
+ez	 318
+na	 314
+ti	 307
+be	 305
+i_	 302
+iz	 294
+k_	 293
+tu	 289
+eta	 287
+(	 280
+)	 280
+_i	 279
+or	 276
+_(	 270
+ko_	 269
+ek	 265
+rr	 264
+_h	 263
+e_	 260
+es	 260
+_ba	 258
+nt	 258
+ha	 255
+_g	 247
+era	 246
+ia	 240
+_be	 234
+oa	 229
+un	 229
+ta_	 218
+ma	 212
+on	 211
+z_	 209
+du	 207
+(_	 205
+_(_	 205
+:	 204
+tze	 204
+:_	 204
+us	 191
+u_	 191
+_da	 188
+ren	 183
+az	 183
+_)	 183
+ur	 182
+st	 182
+ea	 181
+_et	 181
+eta_	 179
+zi	 178
+si	 177
+zen	 177
+as	 176
+_n	 175
+go	 175
+_eta	 172
+il	 169
+tik	 169
+_z	 167
+_eta_	 167
+ne	 167
+bi	 166
+zk	 166
+sk	 165
+ag	 163
+t_	 162
+le	 160
+rt	 160
+ke	 158
+-	 150
+gu	 148
+au	 148
+tza	 147
+_de	 147
+ati	 146
+ut	 146
+A	 145
+li	 145
+hi	 145
+E	 144
+bat	 144
+_o	 143
+a,	 142
+a,_	 142
+_m	 141
+ntz	 141
+ad	 140
+ren_	 139
+_er	 138
+io	 138
+)_	 138
+_ez	 138
+ir	 137
+eh	 137
+ab	 135
+ate	 135
+ak_	 134
+sa	 134
+ra_	 134
+_bat	 133
+nd	 133
+_l	 133
+ki	 132
+ere	 131
+ika	 125
+ku	 125
+f	 124
+ga	 123
+ld	 122
+_di	 121
+arr	 120
+el	 120
+eg	 119
+uz	 119
+are	 116
+ng	 116
+os	 116
+_E	 115
+gi	 113
+_p	 113
+_du	 113
+mo	 113
+zen_	 112
+ib	 111
+_k	 110
+ber	 109
+ako	 108
+_iz	 107
+iza	 107
+ala	 107
+itz	 107
+har	 106
+eko	 106
+adi	 105
+l_	 105
+ie	 105
+ste	 105
+atu	 104
+am	 104
+ska	 104
+ah	 104
+_.	 104
+r_	 104
+zt	 103
+rri	 103
+ait	 103
+ua	 103
+tzen	 103
+ald	 103
+usk	 102
+aren	 102
+_._	 102
+ro	 102
+id	 100
+la_	 99
+_s	 98
+ue	 98
+tek	 97
+uska	 97
+atz	 96
+aren_	 96
+_ha	 95
+rre	 95
+"	 94
+atik	 94
+tzen_	 94
+ara	 94
+in_	 93
+ni	 93
+j	 92
+ge	 91
+ez_	 91
+ain	 91
+od	 91
+no	 91
+na_	 91
+ri_	 90
+tan	 90
+mat	 90
+do	 89
+_mo	 88
+ho	 88
+iko	 88
+beh	 88
+_ad	 88
+al_	 87
+_iza	 87
+I	 87
+zan	 87
+_ze	 87
+_adi	 87
+_A	 86
+uk	 86
+eha	 85
+dit	 85
+ru	 85
+pe	 85
+eko_	 84
+ela	 84
+ed	 84
+kar	 84
+n,_	 83
+ari	 83
+bil	 83
+_beh	 83
+bai	 83
+tu_	 83
+n,	 83
+ehar	 83
+_izan	 82
+itu	 82
+_ho	 82
+is	 82
+ean	 82
+ama	 82
+izan	 82
+_)_	 81
+ik_	 81
+B	 80
+koa	 80
+ot	 80
+_na	 79
+zu	 79
+beha	 78
+behar	 78
+_t	 78
+H	 78
+_ko	 78
+dir	 77
+mati	 76
+_j	 75
+at_	 75
+em	 74
+tika	 74
+K	 74
+_B	 74
+zte	 74
+ten	 74
+_beha	 74
+ter	 74
+matik	 73
+egi	 73
+_dir	 73
+a.	 72
+ago	 72
+kal	 72
+ram	 72
+ena	 72
+unt	 71
+lt	 71
+_H	 71
+su	 71
+mod	 71
+bo	 71
+G	 70
+_ber	 70
+lde	 70
+c	 69
+te_	 69
+ar_	 69
+me	 69
+ina	 69
+dal	 69
+ako_	 68
+L	 68
+rik	 68
+a._	 68
+ori	 68
+ite	 68
+raz	 67
+alde	 67
+)._	 67
+).	 67
+zio	 66
+_ez_	 66
+tan_	 66
+amat	 66
+atika	 66
+est	 66
+ntza	 65
+dut	 65
+izk	 65
+_ga	 65
+ia_	 65
+s_	 65
+ita	 65
+tea	 64
+ei	 64
+hal	 64
+_mod	 64
+pa	 64
+bu	 64
+re_	 63
+eu	 63
+ert	 63
+oa_	 63
+_era	 63
+ten_	 63
+_G	 63
+_eg	 63
+rama	 63
+odal	 63
+ramat	 63
+oda	 63
+amati	 62
+atze	 62
+gr	 62
+untz	 62
+eza	 62
+gra	 62
+_ge	 61
+gram	 61
+kat	 61
+abi	 61
+_gr	 60
+_gram	 60
+_gra	 60
+int	 60
+rd	 60
+_in	 60
+k,	 59
+_hi	 59
+zko	 59
+k,_	 59
+pr	 59
+rab	 59
+da_	 59
+ide	 58
+_)._	 57
+tat	 57
+ing	 57
+ira	 57
+tak	 57
+x	 57
+_).	 57
+_ed	 57
+_es	 57
+_bi	 57
+rak	 56
+_-	 56
Index: /main/tags/2.25/gsdl/perllib/textcat/Other/belarus-windows1251.lm
===================================================================
--- /main/tags/2.25/gsdl/perllib/textcat/Other/belarus-windows1251.lm	(revision 21064)
+++ /main/tags/2.25/gsdl/perllib/textcat/Other/belarus-windows1251.lm	(revision 21064)
@@ -0,0 +1,400 @@
+_	 9440
+à	 4377
+í	 1855
+i	 1544
+ð	 1436
+ó	 1345
+ê	 1246
+û	 1233
+å	 1215
+ñ	 1093
+ë	 1090
+ò	 1050
+ÿ	 934
+ä	 860
+î	 811
+â	 792
+à_	 740
+ì	 724
+ç	 699
+ö	 643
+íà	 589
+ï	 580
+ã	 531
+.	 480
+êà	 467
+ðà	 458
+ó_	 432
+i_	 430
+._	 418
+,	 402
+,_	 402
+á	 391
+àð	 373
+òà	 361
+÷	 350
+âà	 340
+ü	 335
+àë	 330
+ý	 329
+_ï	 328
+àí	 315
+ëà	 307
+ÿ_	 306
+_ñ	 305
+û_	 296
+àä	 279
+é	 279
+_ó	 274
+ðû	 271
+ø	 269
+ãà	 250
+å_	 247
+õ	 244
+_í	 240
+_ç	 236
+_à	 221
+ñò	 221
+íû	 220
+ëi	 218
+äà	 210
+àâ	 203
+_ê	 199
+ñê	 197
+ïà	 195
+_ó_	 194
+äç	 193
+íi	 193
+àì	 192
+_ã	 190
+êi	 190
+_i	 189
+àñ	 187
+çå	 185
+_ä	 179
+é_	 178
+àó	 176
+àã	 174
+þ	 171
+_íà	 169
+ëü	 167
+_â	 166
+íà_	 166
+ëå	 162
+_ì	 161
+àé	 160
+ií	 158
+ì_	 154
+æ	 154
+òû	 154
+ðó	 151
+ïð	 151
+_á	 149
+iê	 148
+ûÿ	 147
+çà	 146
+åð	 145
+ðî	 142
+àê	 141
+óñ	 140
+_i_	 140
+ü_	 140
+"	 137
+åí	 135
+àö	 135
+êó	 131
+ìà	 129
+_ïà	 129
+õ_	 126
+äçå	 126
+àç	 125
+íå	 125
+íí	 123
+_ò	 122
+àò	 122
+ãà_	 121
+àãà	 120
+_ïð	 120
+åë	 120
+àâà	 119
+À	 119
+ûì	 116
+-	 113
+âå	 112
+âû	 112
+ñà	 112
+àé_	 111
+öû	 109
+öü	 109
+_À	 107
+ìi	 106
+àãà_	 105
+îð	 103
+öü_	 102
+Ì	 101
+_êà	 100
+_Ì	 100
+_ÿ	 99
+ëÿ	 99
+íÿ	 98
+íñ	 96
+Â	 95
+ñÿ	 94
+òð	 94
+âi	 92
+ãî	 92
+ç_	 91
+ñêà	 91
+öà	 91
+òó	 91
+àá	 91
+àëà	 90
+÷à	 88
+òî	 88
+íû_	 87
+ñòà	 87
+î_	 87
+_ð	 86
+ÿê	 84
+öö	 84
+iêà	 83
+îó	 83
+ñâ	 83
+àÿ	 83
+÷û	 82
+ïðà	 81
+_çà	 79
+ûí	 79
+åò	 79
+ìå	 79
+ÿí	 79
+âÿ	 79
+_ç_	 78
+ëi_	 78
+ûÿ_	 78
+ðóñ	 77
+êi_	 75
+îä	 74
+_ãà	 74
+i÷	 74
+åö	 73
+íñê	 73
+åëà	 72
+àíà	 72
+âàí	 72
+äð	 72
+ô	 71
+óí	 71
+ðí	 71
+àðó	 71
+àó_	 70
+àå	 70
+àëå	 70
+_íà_	 70
+àëi	 69
+iì	 68
+Ï	 68
+à.	 68
+îë	 68
+òâ	 68
+_àä	 68
+ûì_	 67
+àÿ_	 67
+ëàð	 67
+ööà	 67
+ñï	 67
+_"	 67
+îí	 67
+i,	 67
+à._	 67
+àðóñ	 67
+i,_	 67
+åëàðó	 66
+öi	 66
+óä	 66
+àðà	 66
+ëàðóñ	 66
+ëàðó	 66
+ïå	 66
+åëàð	 66
+_ø	 65
+àäç	 65
+êò	 65
+Í	 65
+_äà	 65
+òà_	 65
+Á	 64
+_Â	 64
+ðàä	 64
+íàã	 64
+_ñò	 64
+øû	 63
+íê	 63
+üí	 63
+óð	 62
+ëüí	 62
+_Ï	 62
+çi	 62
+óë	 62
+ëà_	 62
+ðý	 62
+iö	 62
+òàð	 62
+óê	 61
+û,	 61
+ñö	 61
+_Í	 61
+û,_	 61
+àõ	 61
+êàë	 60
+iñ	 60
+ð_	 60
+öà_	 60
+I	 59
+îâ	 59
+íàãà	 59
+_I	 59
+_Á	 59
+ûõ	 59
+Ê	 59
+_ïðà	 59
+äí	 59
+óñê	 59
+ië	 59
+íå_	 59
+ó.	 59
+_ñâ	 58
+ó._	 58
+ä_	 57
+êî	 57
+áå	 57
+ñi	 57
+çå_	 57
+êð	 57
+ýí	 56
+àâàí	 56
+àðû	 56
+ïi	 56
+åä	 56
+äçå_	 55
+_âû	 55
+íàãà_	 54
+áà	 54
+ööà_	 54
+öå	 53
+áî	 53
+Ìi	 53
+÷í	 53
+à÷	 53
+åê	 53
+iÿ	 53
+Ñ	 53
+íî	 53
+_Ìi	 52
+_ÿê	 52
+ÿð	 52
+òâà	 51
+íûÿ	 51
+ûñ	 51
+àï	 50
+à,_	 50
+ó,_	 50
+àëü	 50
+ïðû	 50
+_÷	 50
+à,	 50
+ó,	 50
+àíí	 50
+ûõ_	 50
+_Ñ	 50
+áû	 49
+êñ	 49
+iõ	 49
+åðà	 49
+ê_	 49
+þ_	 48
+ðóñê	 48
+_Ê	 48
+_ý	 47
+äû	 47
+êë	 47
+ãi	 47
+_.	 47
+àø	 47
+óò	 47
+íiê	 46
+âàð	 46
+àäà	 46
+_._	 46
+øò	 46
+ðû_	 46
+òý	 46
+_íå	 46
+çí	 45
+òû_	 45
+ûë	 45
+_-	 45
+_ñà	 45
+àì_	 45
+Ä	 45
+_ìà	 45
+iò	 44
+_ë	 44
+_ïðû	 44
+óñêà	 44
+ëiê	 44
+âà_	 44
+àçå	 43
+ýò	 43
+êàì	 43
+ÿë	 43
+_ãî	 43
+äî	 43
+í_	 43
+ÿò	 43
+iõ_	 42
+íûÿ_	 42
+ðò	 42
+ñòâ	 42
+íàé	 42
+êàâ	 42
+ãàçå	 42
+..	 42
+_ãàç	 42
+_ãàçå	 42
+ãàç	 42
+ïåð	 42
+íò	 41
+_áå	 41
+ñå	 41
+ðàâ	 41
+áð	 41
+àðî	 41
+ûö	 41
+íä	 41
+Áåë	 40
+åööà	 40
+äà_	 40
+û.	 40
+iíñê	 40
+ûi	 40
+_ðà	 40
+îëü	 40
+è	 40
+"_	 40
+(	 40
+_Ä	 40
+øà	 40
+òàê	 40
+Ó	 40
+ñÿ_	 40
+iíñ	 40
+_âà	 40
+_(	 40
+àíû	 40
+Áå	 40
+)	 40
+åöö	 40
+íÿ_	 39
+äçi	 39
+_Ó	 39
Index: /main/tags/2.25/gsdl/perllib/textcat/Other/bosnian.lm
===================================================================
--- /main/tags/2.25/gsdl/perllib/textcat/Other/bosnian.lm	(revision 21064)
+++ /main/tags/2.25/gsdl/perllib/textcat/Other/bosnian.lm	(revision 21064)
@@ -0,0 +1,400 @@
+_	 9464
+a	 2787
+i	 2108
+e	 2077
+o	 2018
+j	 1396
+n	 1328
+s	 1170
+u	 1010
+r	 988
+d	 957
+a_	 889
+e_	 833
+t	 774
+je	 771
+k	 756
+l	 743
+m	 702
+v	 685
+p	 604
+c	 538
+i_	 538
+_s	 522
+u_	 476
+z	 463
+_p	 450
+o_	 433
+,_	 381
+,	 381
+_i	 369
+_n	 358
+b	 349
+_d	 349
+.	 346
+na	 341
+je_	 337
+._	 321
+_j	 307
+g	 299
+ra	 292
+st	 283
+ko	 278
+_je	 274
+ij	 254
+_o	 245
+ni	 240
+_k	 236
+an	 228
+oj	 227
+da	 226
+_u	 222
+pr	 221
+no	 219
+ma	 219
+la	 211
+ri	 206
+_je_	 203
+po	 203
+ci	 196
+_pr	 191
+os	 190
+od	 187
+ka	 186
+im	 185
+ti	 184
+li	 182
+vo	 178
+_po	 174
+ja	 171
+_i_	 169
+ov	 169
+al	 168
+re	 167
+ne	 167
+m_	 164
+ta	 160
+na_	 158
+ed	 157
+_m	 157
+_na	 157
+se	 156
+_u_	 154
+en	 153
+ic	 151
+sa	 151
+_b	 149
+ak	 141
+va	 140
+ad	 137
+h	 136
+ju	 135
+su	 134
+dj	 133
+ije	 133
+ar	 127
+ca	 127
+_z	 126
+nj	 125
+ji	 124
+da_	 124
+_ko	 123
+_da	 122
+il	 121
+"	 120
+av	 120
+_t	 118
+aj	 116
+ob	 115
+ro	 114
+am	 114
+vi	 114
+_su	 113
+om	 112
+dje	 112
+za	 112
+at	 111
+le	 111
+di	 110
+su_	 107
+iz	 107
+ve	 107
+lj	 106
+_se	 105
+ev	 105
+is	 105
+es	 103
+se_	 103
+do	 101
+ih	 100
+a,	 99
+_su_	 99
+a,_	 99
+on	 98
+bi	 98
+in	 97
+voj	 97
+az	 96
+ac	 95
+_da_	 95
+la_	 95
+_r	 93
+_g	 93
+jev	 92
+ma_	 92
+er	 92
+or	 91
+h_	 90
+_sa	 90
+e,	 90
+e,_	 90
+ba	 90
+ima	 89
+a.	 88
+ol	 88
+_do	 87
+dn	 87
+it	 87
+ko_	 86
+ne_	 86
+ost	 85
+ek	 85
+to	 85
+d_	 84
+as	 84
+ju_	 84
+ao	 84
+ih_	 84
+a._	 84
+te	 83
+evo	 83
+koj	 83
+pri	 82
+jevo	 82
+ce	 81
+_se_	 81
+og	 80
+go	 80
+jevoj	 79
+de	 79
+uc	 79
+evoj	 79
+_od	 78
+_za	 78
+tr	 78
+S	 77
+_koj	 76
+ke	 75
+_v	 75
+ao_	 75
+_dje	 74
+_bi	 74
+sta	 74
+_dj	 74
+cij	 74
+ik	 74
+djev	 73
+sl	 73
+_djev	 72
+ga	 72
+djevo	 72
+_ka	 71
+rij	 71
+_iz	 71
+P	 71
+_pri	 70
+_a	 69
+us	 68
+_S	 68
+mo	 67
+el	 67
+sk	 66
+me	 66
+zi	 66
+ija	 65
+n_	 65
+ku	 64
+im_	 63
+_st	 63
+ica	 63
+_na_	 62
+_ne	 62
+em	 61
+edn	 61
+jk	 61
+io	 61
+li_	 60
+ojk	 60
+evojk	 60
+_"	 60
+zn	 60
+vojk	 60
+pro	 59
+lo	 59
+ije_	 59
+jed	 58
+ke_	 58
+om_	 58
+jen	 58
+sti	 57
+_im	 57
+le_	 57
+_ra	 56
+e.	 56
+ze	 55
+_pro	 55
+nu	 55
+nje	 55
+ti_	 55
+ec	 55
+pre	 55
+oc	 54
+aci	 54
+no_	 54
+et	 54
+oji	 53
+si	 53
+ara	 53
+ama	 53
+z_	 53
+pos	 52
+rad	 52
+ran	 52
+ima_	 52
+ru	 52
+_P	 52
+tu	 52
+mu	 51
+e._	 51
+ja_	 50
+_pre	 50
+sa_	 49
+io_	 49
+od_	 48
+ni_	 48
+_nj	 48
+j_	 48
+_pos	 47
+_c	 47
+ila	 47
+K	 46
+_sa_	 46
+uz	 46
+N	 46
+_ni	 45
+zna	 45
+U	 45
+za_	 45
+_no	 45
+ako	 45
+u,	 44
+lu	 44
+ali	 44
+u,_	 44
+sto	 44
+ste	 44
+ve_	 44
+ani	 44
+oli	 44
+aka	 44
+_jed	 43
+i,_	 43
+ji_	 43
+uci	 43
+i,	 43
+ci_	 43
+osti	 43
+_N	 42
+dr	 42
+so	 42
+ust	 41
+ila_	 41
+B	 41
+-	 41
+red	 41
+jke	 41
+sv	 41
+_go	 41
+bar	 41
+g_	 41
+est	 40
+D	 40
+iv	 40
+vojke	 40
+aju	 40
+ta_	 40
+A	 40
+lje	 40
+jedn	 40
+bil	 40
+ojke	 40
+ova	 40
+ati	 39
+_mu	 39
+pa	 39
+M	 39
+_ba	 39
+ca_	 39
+O	 39
+ka_	 39
+_a_	 38
+_B	 38
+_ima	 38
+sn	 38
+nu_	 38
+T	 38
+to_	 38
+eg	 38
+ava	 38
+ros	 37
+ir	 37
+ala	 37
+og_	 37
+osl	 37
+ovi	 37
+koji	 37
+_sv	 37
+dv	 36
+ric	 36
+_za_	 36
+br	 36
+_on	 36
+odi	 36
+_koji	 36
+_jedn	 35
+nik	 35
+dno	 35
+_D	 35
+jo	 35
+tra	 35
+_M	 35
+sp	 35
+iz_	 35
+oz	 35
+vr	 35
+u.	 35
+eri	 35
+I	 35
+eko	 35
+ale	 35
+_ma	 34
+lik	 34
+_bil	 34
+c_	 34
+ut	 34
+je,_	 34
+u._	 34
+str	 34
+je,	 34
+adi	 34
+tit	 34
+_iz_	 34
+iti	 34
+i.	 33
+_rad	 33
+ici	 33
+rost	 33
+aju_	 33
+va_	 33
+_ob	 33
+nog	 33
Index: /main/tags/2.25/gsdl/perllib/textcat/Other/breton.lm
===================================================================
--- /main/tags/2.25/gsdl/perllib/textcat/Other/breton.lm	(revision 21064)
+++ /main/tags/2.25/gsdl/perllib/textcat/Other/breton.lm	(revision 21064)
@@ -0,0 +1,400 @@
+_	 21447
+e	 6375
+a	 5414
+n	 3228
+r	 3039
+o	 2968
+t	 2392
+i	 1812
+h	 1751
+u	 1650
+l	 1630
+d	 1506
+a_	 1352
+z	 1319
+t_	 1310
+_e	 1168
+_a	 1168
+e_	 1133
+m	 1105
+s	 1100
+g	 1090
+r_	 998
+k	 997
+n_	 958
+et	 941
+v	 888
+_d	 868
+an	 859
+.	 846
+'	 841
+en	 836
+b	 757
+,	 749
+,_	 743
+._	 716
+ar	 703
+ou	 700
+et_	 689
+c	 686
+ez	 572
+'h	 572
+_g	 565
+er	 555
+p	 553
+_k	 535
+c'h	 530
+c'	 530
+nt	 513
+_h	 505
+re	 505
+ra	 478
+ha	 466
+ñ	 458
+ne	 456
+oa	 454
+_o	 442
+_b	 434
+-	 432
+zh	 422
+ar_	 415
+_m	 414
+_e_	 414
+nn	 384
+el	 376
+_a_	 356
+ur	 350
+o_	 346
+h_	 345
+ve	 340
+nt_	 340
+w	 339
+ke	 338
+de	 333
+añ	 332
+_p	 332
+s_	 327
+he	 325
+on	 318
+le	 318
+ga	 316
+ma	 315
+_ar	 312
+eu	 312
+_n	 310
+an_	 298
+ant	 296
+enn	 285
+z_	 282
+_ar_	 281
+be	 280
+_v	 276
+_r	 272
+al	 270
+en_	 268
+_ke	 267
+l_	 264
+em	 264
+_c	 263
+ñ_	 262
+da	 262
+_s	 261
+ho	 260
+di	 259
+_ha	 252
+ll	 250
+tr	 248
+oa_	 247
+me	 246
+us	 242
+_ga	 234
+la	 231
+ket	 227
+ant_	 219
+_da	 219
+_l	 216
+ur_	 216
+_oa	 215
+in	 214
+ket_	 211
+gan	 211
+_c'	 207
+_u	 207
+_c'h	 207
+ad	 207
+añ_	 207
+ao	 204
+_ma	 204
+_t	 204
+_ket	 201
+_an	 199
+_di	 197
+ezh	 196
+ù	 196
+où	 196
+_de	 195
+ev	 193
+?	 192
+st	 192
+ro	 192
+P	 192
+_ket_	 188
+er_	 188
+f	 186
+na	 186
+ue	 185
+da_	 184
+?_	 184
+_gan	 184
+_da_	 184
+_ne	 183
+ed	 182
+_P	 180
+g_	 180
+pe	 179
+m_	 178
+A	 177
+ri	 176
+us_	 175
+ta	 174
+ze	 174
+gant	 174
+ka	 174
+i_	 172
+d_	 171
+G	 167
+te	 167
+ae	 166
+zh_	 164
+ha_	 163
+_ha_	 163
+_he	 161
+_gant	 159
+do	 159
+oue	 159
+_G	 158
+eus	 158
+eo	 158
+'h_	 157
+_en	 157
+go	 157
+am	 157
+c'h_	 157
+_be	 156
+we	 156
+iz	 154
+_an_	 151
+_A	 150
+eus_	 147
+sk	 147
+li	 146
+as	 146
+_pe	 146
+j	 146
+_oa_	 146
+av	 144
+gant_	 143
+ut	 142
+no	 141
+vez	 140
+va	 140
+_ra	 140
+ge	 138
+ez_	 138
+bo	 137
+ 	 137
+_ur	 136
+lo	 134
+he_	 134
+où_	 133
+ù_	 133
+_ur_	 132
+es	 130
+'ho	 129
+ni	 129
+uz	 129
+tra	 127
+se	 126
+it	 125
+ra_	 125
+out	 125
+is	 125
+at	 125
+hi	 125
+eg	 125
+ig	 124
+ko	 124
+io	 123
+k_	 123
+ch	 123
+_w	 121
+or	 121
+Pe	 121
+_ma_	 119
+ma_	 119
+gw	 118
+_em	 118
+_Pe	 118
+un	 118
+eme	 117
+ne_	 117
+nn_	 117
+c'ho	 117
+ol	 116
+ag	 116
+M	 115
+'ha	 115
+_en_	 115
+iv	 115
+vi	 113
+_ka	 113
+K	 113
+ud	 112
+_he_	 111
+ont	 110
+oc	 110
+vo	 110
+ec	 109
+wa	 109
+..	 107
+_M	 107
+_z	 107
+br	 107
+om	 106
+to	 105
+_f	 105
+N	 105
+_c'ho	 104
+ti	 104
+ut_	 104
+D	 104
+_o_	 103
+_la	 103
+_go	 101
+az	 101
+out_	 101
+ba	 101
+enn_	 101
+c'ha	 101
+our	 100
+oc'h	 100
+ell	 100
+oc'	 100
+etr	 99
+el_	 99
+_K	 99
+_D	 99
+:	 99
+:_	 99
+eve	 98
+_d'	 97
+all	 97
+d'	 97
+E	 97
+_ne_	 97
+_me	 95
+eo_	 95
+ak	 95
+bet	 95
+_eu	 95
+rc	 94
+_do	 94
+_gw	 94
+zi	 93
+oz	 93
+aou	 93
+etra	 92
+pa	 91
+ab	 90
+on_	 90
+ei	 90
+tra_	 90
+n,	 89
+zo	 89
+ag_	 89
+_ev	 88
+ul	 88
+'e	 88
+n'	 88
+n,_	 88
+ouz	 87
+v_	 86
+_n'	 86
+_eus	 84
+H	 83
+za	 83
+S	 83
+etra_	 83
+_eo	 82
+t,_	 82
+t,	 82
+il	 81
+ent	 81
+fe	 81
+rc'h	 81
+rc'	 81
+_eus_	 80
+ie	 80
+_bo	 79
+ele	 79
+_ve	 79
+mp	 79
+_bet	 78
+B	 78
+it_	 77
+_vo	 77
+'a	 77
+n.	 76
+_S	 76
+hag	 76
+hoa	 75
+_hag	 75
+len	 75
+_N	 75
+'hoa	 74
+_E	 74
+ir	 74
+hag_	 74
+_hag_	 74
+mañ	 74
+as_	 73
+eze	 73
+ont_	 73
+_.	 73
+iñ	 73
+r,	 72
+pr	 72
+ed_	 72
+n._	 72
+re_	 72
+in_	 72
+r,_	 72
+_H	 71
+'he	 70
+t.	 70
+gou	 70
+em_	 70
+_br	 70
+rae	 70
+rez	 69
+t._	 69
+bet_	 69
+net	 69
+dr	 68
+_eo_	 68
+ll_	 68
+mo	 67
+po	 67
+oul	 67
+rou	 67
+c'hoa	 67
+a-	 67
+vel	 67
+oc'h_	 67
+nna	 66
+_B	 66
+met	 65
+ec'	 65
+ec'h	 65
+R	 64
+den	 64
Index: /main/tags/2.25/gsdl/perllib/textcat/Other/bulgarian-iso8859_5.lm
===================================================================
--- /main/tags/2.25/gsdl/perllib/textcat/Other/bulgarian-iso8859_5.lm	(revision 21064)
+++ /main/tags/2.25/gsdl/perllib/textcat/Other/bulgarian-iso8859_5.lm	(revision 21064)
@@ -0,0 +1,400 @@
+_	 11056
+Ð	 3428
+Ø	 3007
+Õ	 2501
+Þ	 2490
+Ý	 2179
+â	 2166
+à	 1596
+á	 1492
+Ò	 1159
+Ð_	 1144
+Ú	 1093
+Û	 918
+Ô	 803
+Ø_	 803
+ÝÐ	 724
+ß	 720
+×	 702
+Õ_	 642
+Ü	 613
+_Ý	 577
+_á	 569
+Þ_	 556
+.	 537
+ÝØ	 534
+âÕ	 473
+._	 467
+ï	 462
+áâ	 455
+_ß	 452
+_ÝÐ	 446
+,_	 440
+,	 440
+Ó	 439
+Ñ	 432
+ÝÐ_	 422
+ê	 405
+ã	 382
+âÞ	 376
+ÕÝ	 360
+àÐ	 360
+ç	 355
+_Ø	 353
+Ðâ	 334
+âÐ	 330
+â_	 324
+Øâ	 322
+_ÝÐ_	 316
+ÐÝ	 310
+àÕ	 308
+àØ	 305
+ÒÐ	 303
+ÝÞ	 301
+Þâ	 281
+_Ò	 278
+_Þ	 275
+ØâÕ	 262
+ÚÞ	 262
+ßà	 262
+_Ú	 250
+âÞ_	 248
+ÚÐ	 242
+àÞ	 236
+ßÞ	 235
+Ðà	 230
+_Ô	 226
+ÝÕ	 222
+Þá	 216
+æ	 214
+Øï	 210
+âÕ_	 203
+âØ	 198
+_Ø_	 196
+Õâ	 196
+_ßà	 195
+áÚ	 189
+ÕÔ	 189
+ØâÕ_	 189
+Ò_	 186
+ÐÒ	 185
+ÔÐ	 185
+_Õ	 184
+×Ø	 178
+ÞÒ	 177
+ä	 175
+ÛØ	 175
+âÐ_	 172
+ØÚ	 171
+ÐÚ	 170
+_à	 169
+_ßÞ	 169
+_Ñ	 165
+ï_	 163
+×Ð	 162
+Ö	 161
+Õà	 160
+ÝØ_	 159
+ÛÕ	 156
+áÕ	 156
+ÒÕ	 155
+ÕÛ	 154
+_Ò_	 152
+_×	 152
+Ø×	 151
+ÚØ	 151
+_Ü	 150
+ÛÐ	 149
+é	 148
+_Þâ	 146
+ØÝ	 145
+æØ	 143
+ÜØ	 141
+_â	 138
+Ð×	 137
+ÓÐ	 135
+Þà	 134
+Õ×	 133
+_×Ð	 133
+ÞÔ	 131
+ÞÑ	 129
+Ù	 128
+ÐÛ	 127
+_Ó	 126
+ÐâÐ	 124
+Þáâ	 123
+ÔØ	 123
+Øï_	 123
+Øá	 122
+Õá	 121
+_áÕ	 120
+ÕÝØ	 119
+ÞÛ	 118
+ÒØ	 116
+ÒÐ_	 115
+âÝ	 113
+ÝÞ_	 112
+¿	 112
+-	 111
+Þâ_	 111
+ÜÕ	 110
+ÐâÐ_	 109
+Ýâ	 108
+_Þâ_	 108
+Úâ	 108
+ÐÝØ	 107
+ÔÕ	 107
+ÒÞ	 107
+_ÚÞ	 106
+áÕ_	 105
+çÕ	 103
+_¿	 103
+_áÕ_	 101
+Øà	 101
+âÒ	 100
+_ÔÐ	 99
+"	 99
+ØÕ	 99
+ØÜ	 99
+ÜÐ	 98
+áÚØ	 97
+ÕâÞ	 97
+ÐÝÕ	 97
+_Õ_	 97
+ßàÞ	 96
+ÐÚâ	 96
+è	 93
+ÔÐ_	 93
+ÓÞ	 92
+áØ	 92
+ÐàØ	 92
+ÔÞ	 92
+áÛ	 91
+Øæ	 90
+ÛÝ	 90
+Øç	 89
+Õ×Ø	 89
+×Ð_	 89
+ÞÓ	 88
+ÕâÞ_	 88
+_ã	 88
+ÐÜ	 88
+Ø,	 87
+âÕà	 87
+Ðá	 87
+Ø,_	 87
+_ÔÐ_	 85
+_×Ð_	 83
+êÛ	 83
+áâÒ	 83
+Ðâ_	 83
+å	 82
+ØÛ	 81
+Ú_	 81
+_Ø×	 81
+_Ð	 80
+ßàÕ	 80
+ÝØâ	 79
+ÞÝ	 78
+ïâ	 78
+ÝØâÕ	 78
+âà	 78
+Á	 77
+ÕàØ	 77
+ÝÕ_	 77
+ÑØ	 77
+ÚØ_	 76
+_ÝÕ	 76
+ÓÐà	 75
+Øáâ	 75
+ÛÓ	 75
+ØÒ	 75
+ÝÞá	 74
+ÛÞ	 73
+_àÕ	 73
+ÜÞ	 73
+á_	 73
+àÕÔ	 73
+_ßàÞ	 72
+ÑÐ	 72
+ãç	 72
+ÛÓÐà	 72
+ÛÓÐ	 72
+êÛÓ	 71
+Ðä	 71
+Ð,_	 71
+êÛÓÐà	 71
+ÝØâÕ_	 71
+ÒÐÝ	 71
+êÛÓÐ	 71
+Ý_	 71
+Ð,	 71
+êà	 70
+áê	 70
+àÕ×	 70
+ÐÔ	 70
+àÐÝ	 70
+ÕÚ	 70
+_àÐ	 70
+Û_	 69
+çÝ	 68
+ØàÐ	 68
+Óà	 67
+Ýá	 67
+ØæØ	 66
+ÝØï	 66
+ÝÞáâ	 66
+Ü_	 66
+áÐ	 66
+ÕÜ	 65
+àÐ×	 65
+ÚÐâ	 64
+ÞâÞ	 64
+Ñê	 64
+ÝØÕ	 64
+_ç	 64
+âÕàØ	 63
+ÐÒÐ	 63
+_ÚÐ	 63
+_Á	 62
+_±	 62
+ÚÐ_	 62
+±	 62
+ØÚ_	 62
+_.	 62
+çÐ	 61
+ÞÙ	 61
+Òê	 61
+çØ	 61
+ÞÜ	 61
+_áê	 61
+Õáâ	 60
+ÕÝâ	 60
+(	 60
+)	 60
+áâÕ	 59
+ßÕ	 59
+Þß	 59
+âÝÞ	 59
+äÐ	 59
+Ø.	 58
+À	 58
+áâÐ	 58
+_(	 58
+_ßàÕ	 58
+ÔÝ	 58
+àá	 58
+_Û	 57
+ÞâÞ_	 57
+ÓàÐ	 57
+ßàØ	 57
+ØÝÐ	 56
+Ø._	 56
+Úê	 56
+ÝÐâ	 56
+âÕÝ	 56
+_àÐ×	 55
+×Ò	 55
+áâØ	 55
+ÚâÕ	 55
+_á_	 55
+áà	 55
+_,_	 55
+_ÔÞ	 55
+ÑêÛÓÐ	 55
+ÑêÛ	 55
+ÑêÛÓ	 55
+_,	 55
+ØÕ_	 54
+ÐÚâÕà	 54
+È	 54
+ÐÚâÕ	 54
+_-	 54
+ÚâÕà	 54
+-_	 53
+áÚÐ	 53
+ãá	 53
+áâ_	 53
+ÚâÕàØ	 53
+áâÞ	 53
+_áà	 53
+ÕÒ	 53
+_Ñê	 52
+âÕÛ	 52
+ÛÝØ	 52
+_-_	 52
+ØÞ	 51
+_È	 51
+Ðß	 51
+Þ×	 51
+Ô_	 50
+_À	 50
+äÐà	 50
+ÒÐâ	 50
+ØØ	 50
+ž	 50
+_ßàØ	 50
+_áÛ	 50
+_"	 50
+ÞÚ	 49
+_ÑÐ	 49
+áß	 49
+áâÕÝ	 49
+ØÐ	 48
+ÛÕÔ	 48
+áÚØ_	 48
+àØÚ	 48
+ÑÐÚâÕ	 48
+_áÐ	 48
+ÈÐ	 48
+_._	 48
+ÑÐÚ	 48
+àã	 48
+ÑÐÚâ	 48
+Òï	 48
+ØáâÕ	 48
+ÛÐÒ	 47
+Úà	 47
+œ	 47
+äÐàØÚ	 47
+_ÈÐ	 47
+äÐàØ	 47
+ÐäÐ	 47
+ÐäÐàØ	 47
+Ðàá	 47
+ÐäÐà	 47
+ÐàØÚ	 47
+ÈÐä	 47
+àáÚ	 47
+âÝØ	 46
+ÈÐäÐ	 46
+_ÈÐä	 46
+ÐÝÕ_	 46
+ÞÒÕ	 46
+ÈÐäÐà	 46
+_ÈÐäÐ	 45
+ÐâÞ	 45
+Øïâ	 45
+ÞØ	 45
+ïÝ	 45
+ÕÝØÕ	 45
+_áâ	 45
+éÐ	 45
+ÕÝ_	 45
+ÑÞ	 45
+×Øá	 45
+×ØÚ	 45
+âÕÝâ	 44
+ØáâÕÝ	 44
+_ÑêÛ	 44
+áâÕÝâ	 44
+_ÑêÛÓ	 44
+ÚÞ_	 44
+ÝØï_	 44
+ÝáÚ	 44
+àØ_	 44
+ÝÐâÐ	 44
+Â	 43
+×Øáâ	 43
+Ðáâ	 43
+×ØáâÕ	 43
Index: /main/tags/2.25/gsdl/perllib/textcat/Other/catalan.lm
===================================================================
--- /main/tags/2.25/gsdl/perllib/textcat/Other/catalan.lm	(revision 21064)
+++ /main/tags/2.25/gsdl/perllib/textcat/Other/catalan.lm	(revision 21064)
@@ -0,0 +1,400 @@
+_	 16604
+e	 5091
+a	 4937
+s	 3120
+r	 3037
+i	 2987
+l	 2747
+n	 2641
+t	 2466
+o	 2274
+d	 1775
+c	 1740
+u	 1515
+a_	 1460
+s_	 1416
+_d	 1116
+e_	 1067
+p	 1014
+m	 995
+es	 985
+de	 972
+_de	 842
+en	 700
+_l	 691
+re	 652
+_e	 637
+de_	 611
+el	 602
+_de_	 601
+_a	 600
+,	 599
+,_	 599
+er	 598
+la	 584
+ar	 583
+_p	 550
+l_	 547
+ci	 522
+n_	 518
+es_	 515
+an	 515
+ra	 499
+nt	 495
+ta	 495
+b	 476
+_c	 452
+al	 450
+v	 440
+g	 428
+.	 420
+on	 420
+or	 404
+t_	 402
+at	 396
+._	 377
+r_	 372
+i_	 371
+la_	 368
+_i	 364
+_la	 351
+_la_	 325
+f	 325
+le	 322
+te	 312
+'	 311
+_s	 308
+st	 308
+se	 305
+ó	 302
+ue	 302
+na	 301
+os	 301
+qu	 300
+q	 300
+el_	 299
+it	 292
+co	 290
+ri	 277
+ca	 277
+ti	 273
+ac	 272
+in	 268
+ll	 264
+ic	 264
+me	 259
+un	 257
+que	 248
+C	 248
+tr	 244
+ns	 242
+ió	 238
+_i_	 236
+ad	 233
+ent	 232
+_el	 227
+ne	 226
+_t	 223
+_co	 221
+_m	 221
+_C	 217
+en_	 217
+li	 217
+ia	 212
+à	 212
+pe	 207
+_a_	 207
+pr	 206
+ció	 203
+ó_	 203
+pa	 203
+ro	 202
+o_	 198
+E	 198
+di	 197
+io	 197
+ls	 196
+h	 192
+_q	 192
+_qu	 192
+_en	 187
+aci	 186
+am	 186
+ec	 183
+to	 183
+as	 180
+om	 180
+ni	 180
+da	 179
+ió_	 179
+si	 178
+ls_	 176
+L	 175
+ma	 172
+res	 172
+ur	 171
+_el_	 162
+rt	 162
+ue_	 160
+A	 160
+os_	 159
+_que	 159
+que_	 158
+_r	 158
+po	 157
+_es	 155
+er_	 155
+_que_	 155
+M	 155
+_se	 153
+va	 153
+del	 153
+ció_	 151
+_pr	 151
+is	 150
+_en_	 149
+P	 147
+_pe	 146
+_del	 145
+ts	 145
+lo	 145
+_M	 144
+ct	 144
+_u	 144
+ol	 143
+ve	 141
+_L	 140
+x	 140
+y	 140
+a,_	 139
+a,	 139
+nc	 138
+men	 137
+al_	 137
+_f	 137
+_re	 137
+_P	 136
+ació	 136
+les	 136
+rs	 134
+est	 133
+tu	 131
+_E	 130
+et	 130
+s,_	 129
+_un	 129
+na_	 129
+_v	 129
+s,	 129
+ion	 127
+per	 126
+so	 125
+em	 125
+at_	 124
+no	 124
+j	 124
+br	 123
+nt_	 122
+ar_	 122
+sa	 121
+_n	 119
+les_	 118
+é	 118
+ce	 117
+il	 117
+ell	 116
+_per	 114
+í	 114
+ob	 113
+re_	 113
+ir	 113
+_A	 112
+ons	 112
+do	 112
+ua	 112
+con	 112
+ment	 111
+gu	 111
+ts_	 110
+ss	 110
+ns_	 109
+ant	 109
+ra_	 109
+Co	 109
+par	 108
+l'	 107
+d'	 107
+_l'	 107
+els	 107
+tat	 107
+sc	 106
+_d'	 106
+an_	 105
+_Co	 105
+vi	 104
+els_	 104
+ica	 104
+ran	 103
+ul	 102
+iv	 102
+S	 102
+_del_	 102
+del_	 102
+mb	 101
+mi	 101
+ita	 101
+nta	 100
+_pa	 99
+_o	 99
+_con	 98
+ació_	 97
+rn	 96
+_in	 96
+ia_	 96
+z	 96
+im	 95
+rr	 95
+art	 94
+ta_	 93
+com	 93
+tre	 92
+_h	 92
+s.	 91
+mp	 90
+ie	 90
+J	 90
+s._	 89
+cio	 89
+_le	 89
+bre	 88
+_ca	 88
+_al	 88
+sta	 88
+_com	 88
+cu	 88
+à_	 87
+pre	 87
+fe	 86
+ba	 86
+tra	 86
+ge	 85
+pro	 85
+_les	 84
+des	 84
+ter	 84
+_po	 84
+_les_	 84
+T	 84
+_J	 84
+nd	 84
+cion	 84
+_S	 84
+ura	 83
+nci	 82
+va_	 81
+ha	 81
+ona	 81
+ent_	 80
+ues	 80
+oc	 80
+ea	 80
+nte	 80
+és	 80
+_di	 79
+ui	 79
+as_	 78
+ut	 78
+ici	 78
+res_	 78
+us	 77
+ot	 77
+ara	 77
+ip	 75
+rm	 75
+ab	 75
+eg	 75
+_per_	 75
+ng	 75
+'a	 75
+I	 75
+per_	 75
+rec	 74
+du	 74
+_tr	 74
+è	 73
+cia	 73
+_no	 73
+b_	 73
+_par	 72
+ep	 72
+id	 72
+lle	 71
+rc	 71
+_pro	 70
+D	 69
+G	 69
+ga	 69
+fo	 69
+una	 68
+El	 68
+lit	 68
+un_	 68
+ques	 68
+amb	 67
+ix	 67
+és_	 67
+_G	 67
+era	 67
+cr	 67
+)	 66
+da_	 66
+-	 66
+sp	 66
+y_	 66
+ada	 66
+tor	 66
+(	 66
+_(	 66
+_T	 65
+ment_	 65
+B	 65
+_es_	 65
+Ma	 65
+V	 65
+uc	 65
+ect	 65
+ame	 64
+iu	 64
+_Ma	 64
+orn	 64
+_B	 64
+_D	 64
+Ca	 64
+sti	 64
+_g	 63
+esc	 63
+rd	 63
+una_	 63
+là	 62
+"	 62
+ed	 62
+amen	 61
+mo	 61
+ions	 61
+_El	 61
+_Ca	 61
+Jo	 61
+eu	 61
+ari	 61
+lt	 61
+F	 61
+u_	 61
+ament	 60
+_V	 60
+m_	 60
+fi	 60
+au	 60
+ev	 60
+La	 60
+itat	 59
+_ha	 59
Index: /main/tags/2.25/gsdl/perllib/textcat/Other/croatian-ascii.lm
===================================================================
--- /main/tags/2.25/gsdl/perllib/textcat/Other/croatian-ascii.lm	(revision 21064)
+++ /main/tags/2.25/gsdl/perllib/textcat/Other/croatian-ascii.lm	(revision 21064)
@@ -0,0 +1,400 @@
+_	 36598
+a	 9456
+o	 9050
+i	 8526
+e	 7955
+n	 5513
+j	 5379
+s	 4971
+t	 4125
+r	 3889
+u	 3423
+je	 3281
+l	 3231
+e_	 3177
+d	 3128
+k	 2992
+v	 2891
+a_	 2835
+o_	 2679
+m	 2645
+p	 2316
+_s	 2212
+i_	 2205
+y	 2174
+c	 1894
+z	 1867
+je_	 1613
+_n	 1593
+g	 1581
+_p	 1490
+b	 1386
+u_	 1382
+,	 1208
+,_	 1208
+st	 1203
+_j	 1202
+na	 1159
+_je	 1118
+_d	 1105
+_i	 1104
+.	 1069
+._	 1058
+ra	 1017
+ko	 981
+ni	 980
+_je_	 918
+ij	 914
+ti	 911
+no	 891
+da	 884
+to	 879
+_k	 863
+_o	 856
+cy	 839
+li	 838
+ne	 790
+sy	 786
+-	 785
+pr	 760
+_u	 748
+po	 734
+ta	 711
+_b	 705
+_t	 704
+la	 699
+ja	 699
+an	 691
+m_	 680
+ov	 674
+ije	 673
+_z	 669
+ka	 662
+ri	 652
+lo	 651
+vo	 643
+re	 641
+is	 626
+in	 623
+se	 623
+va	 622
+_m	 617
+oj	 614
+_po	 594
+_pr	 592
+bi	 588
+en	 582
+il	 578
+os	 576
+vi	 572
+nj	 569
+ak	 564
+_na	 558
+im	 558
+da_	 553
+od	 550
+ao	 550
+al	 549
+om	 545
+na_	 533
+_se	 524
+_i_	 523
+h	 517
+_g	 511
+ma	 508
+at	 502
+cj	 501
+og	 497
+--	 493
+ro	 493
+on	 485
+av	 480
+_da	 474
+_ne	 474
+ed	 472
+zy	 471
+se_	 466
+_se_	 458
+_bi	 457
+ao_	 452
+ad	 452
+lj	 445
+es	 444
+ji	 441
+_v	 433
+_c	 430
+za	 421
+go	 418
+_r	 413
+_u_	 411
+yi	 410
+ek	 406
+di	 403
+sa	 396
+et	 393
+ic	 391
+io	 390
+_da_	 389
+to_	 389
+as	 386
+_ko	 383
+ye	 378
+ar	 378
+mo	 373
+le	 367
+or	 364
+ju	 363
+el	 354
+tr	 354
+io_	 352
+ve	 345
+lo_	 344
+su	 344
+ol	 344
+am	 344
+iz	 343
+li_	 338
+ti_	 336
+sto	 323
+n_	 321
+it	 319
+_za	 319
+sta	 317
+_ni	 316
+te	 312
+nu	 312
+a,	 309
+a,_	 309
+ya	 309
+do	 304
+om_	 303
+la_	 300
+no_	 299
+_na_	 299
+d_	 297
+ko_	 296
+aj	 294
+ik	 292
+ru	 291
+ga	 291
+em	 288
+nje	 283
+dj	 281
+ne_	 281
+k_	 277
+_st	 276
+koj	 276
+ec	 274
+_ka	 272
+_su	 270
+ob	 265
+-_	 263
+az	 261
+sv	 260
+_koj	 260
+im_	 260
+ije_	 259
+pa	 258
+ot	 257
+yt	 256
+ok	 255
+su_	 255
+ih	 254
+me	 253
+dn	 253
+_cy	 253
+iv	 251
+syt	 248
+g_	 247
+--_	 246
+_-	 246
+kr	 246
+---	 246
+a.	 245
+e,_	 245
+---_	 245
+e,	 245
+er	 245
+a._	 244
+_iz	 244
+mi	 243
+_---_	 242
+cyi	 242
+_--	 242
+_---	 242
+jed	 240
+h_	 239
+_a	 239
+_sa	 237
+j_	 236
+_l	 231
+_sv	 229
+_to	 229
+sk	 228
+ih_	 224
+ja_	 223
+pro	 223
+yn	 222
+t_	 222
+ost	 221
+_do	 221
+oc	 219
+gl	 218
+_su_	 216
+og_	 216
+uc	 214
+s_	 214
+bil	 213
+oz	 213
+ki	 212
+ni_	 212
+nij	 209
+ako	 208
+eg	 208
+ut	 205
+pre	 205
+ci	 204
+ji_	 203
+_od	 203
+ilo	 202
+ati	 202
+ac	 201
+ns	 200
+_mo	 197
+rij	 196
+bo	 195
+ovo	 195
+ku	 195
+dje	 194
+ma_	 192
+_bil	 191
+cje	 186
+sti	 186
+_go	 186
+de	 185
+sl	 183
+_pro	 182
+ju_	 182
+nije	 181
+tv	 180
+lje	 179
+isy	 179
+pri	 178
+_pre	 177
+dr	 177
+e._	 177
+e.	 177
+op	 176
+ima	 176
+anj	 175
+jen	 175
+us	 172
+ilo_	 172
+_ra	 170
+S	 167
+ecj	 166
+iti	 166
+sp	 163
+_S	 161
+vr	 161
+i.	 161
+i._	 161
+zn	 161
+ali	 161
+i,_	 160
+i,	 160
+ap	 157
+nije_	 157
+nst	 156
+pi	 156
+ga_	 156
+_sy	 155
+_nj	 155
+jes	 155
+ran	 155
+vo_	 155
+yto	 154
+ev	 153
+_to_	 152
+_pri	 151
+est	 150
+N	 150
+ins	 150
+ist	 149
+ir	 149
+o,	 148
+vj	 148
+vje	 148
+o,_	 148
+B	 148
+zi	 147
+jec	 147
+gov	 147
+yto_	 147
+syto	 146
+ton	 146
+od_	 145
+O	 144
+rije	 144
+lik	 143
+on_	 142
+ocy	 142
+W	 142
+ba	 142
+_W	 141
+kao	 141
+Wi	 141
+_N	 141
+inst	 141
+_nij	 141
+_nije	 140
+_Wi	 140
+syto_	 140
+lic	 139
+P	 139
+ovi	 138
+_tr	 138
+rs	 137
+ez	 137
+edn	 136
+_P	 136
+si	 136
+ili	 136
+du	 136
+Winst	 135
+cye	 135
+nston	 135
+ston	 135
+ud	 135
+kao_	 135
+Wins	 135
+insto	 135
+oji	 135
+nsto	 135
+Win	 135
+raz	 135
+zye	 135
+_Win	 134
+ova	 134
+_Wins	 134
+_on	 133
+ako_	 133
+odi	 133
+cya	 133
+ila	 133
+icy	 133
+oj_	 133
+ke	 133
+va_	 132
+ija	 132
+_is	 132
+jel	 132
+oje	 130
+pu	 130
+cje_	 130
+bi_	 129
+rat	 128
+ce	 128
+tu	 128
+mu	 128
+ve_	 127
Index: /main/tags/2.25/gsdl/perllib/textcat/Other/czech-iso8859_2.lm
===================================================================
--- /main/tags/2.25/gsdl/perllib/textcat/Other/czech-iso8859_2.lm	(revision 21064)
+++ /main/tags/2.25/gsdl/perllib/textcat/Other/czech-iso8859_2.lm	(revision 21064)
@@ -0,0 +1,400 @@
+_	 26378
+o	 5870
+e	 5354
+a	 4740
+n	 4462
+t	 3745
+s	 3438
+i	 3187
+v	 3118
+l	 2891
+r	 2754
+k	 2566
+d	 2508
+m	 2198
+u	 2197
+p	 2032
+í	 1924
+c	 1678
+h	 1572
+z	 1544
+á	 1522
+_p	 1299
+e_	 1266
+y	 1231
+a_	 1219
+j	 1219
+_s	 1156
+b	 1079
+o_	 1065
+ì	 1043
+_v	 1038
+,	 952
+,_	 946
+st	 945
+_n	 911
+é	 878
+.	 870
+í_	 848
+ø	 822
+._	 803
+ní	 782
+ov	 757
+_z	 723
+i_	 716
+u_	 684
+ro	 674
+en	 656
+ý	 647
+Ÿ	 639
+po	 630
+ch	 629
+è	 625
+na	 599
+_a	 598
+sk	 592
+¹	 563
+ho	 552
+_d	 551
+ra	 545
+m_	 539
+y_	 530
+_t	 512
+ko	 504
+_k	 503
+le	 502
+_j	 501
+_o	 486
+to	 479
+pr	 471
+ne	 468
+ní_	 462
+je	 458
+é_	 456
+ti	 455
+od	 433
+li	 432
+va	 432
+_po	 429
+_m	 428
+al	 424
+te	 424
+ou	 423
+ed	 418
+se	 415
+la	 410
+no	 397
+os	 382
+lo	 377
+an	 376
+_pr	 375
+ù	 375
+v_	 372
+øe	 370
+_a_	 364
+em	 363
+at	 360
+ta	 359
+do	 357
+t_	 357
+_b	 355
+or	 349
+h_	 345
+_v_	 338
+ch_	 327
+S	 325
+ce	 323
+av	 323
+pø	 322
+ni	 319
+ké	 316
+er	 315
+nì	 315
+_na	 313
+na_	 312
+_ne	 311
+de	 308
+ic	 307
+in	 306
+_se	 306
+l_	 304
+dn	 302
+za	 298
+_pø	 293
+ì_	 291
+ol	 290
+_je	 281
+ob	 280
+is	 277
+ve	 274
+ho_	 272
+es	 270
+ot	 268
+ak	 265
+vo	 263
+ná	 260
+il	 257
+se_	 257
+it	 256
+et	 253
+ad	 250
+by	 249
+P	 242
+_r	 242
+k_	 242
+ost	 241
+_se_	 241
+tr	 238
+me	 237
+pro	 234
+Ÿe	 234
+ka	 230
+_za	 227
+om	 224
+el	 223
+_P	 223
+on	 218
+_pro	 216
+ou_	 216
+tu	 215
+O	 212
+mi	 212
+ku	 211
+_u	 210
+_do	 208
+_l	 207
+_na_	 206
+N	 205
+ské	 205
+ím	 205
+íc	 205
+ý_	 203
+mì	 203
+_S	 200
+oz	 200
+V	 200
+ze	 198
+da	 194
+sl	 192
+á_	 191
+ova	 190
+mo	 190
+re	 189
+so	 187
+vy	 186
+ej	 185
+rá	 184
+ar	 184
+s_	 183
+vì	 183
+A	 181
+ru	 180
+_st	 178
+f	 178
+éh	 177
+ého	 176
+kt	 176
+tn	 175
+g	 174
+bo	 174
+ez	 173
+ci	 172
+ký	 172
+né	 170
+M	 170
+án	 169
+as	 168
+vi	 167
+øi	 167
+ac	 166
+Ÿe_	 165
+ýc	 165
+Ÿ_	 165
+ck	 164
+K	 164
+B	 164
+ých	 164
+vá	 162
+_c	 162
+ého_	 162
+ení	 161
+lá	 160
+_Ÿ	 160
+øí	 160
+pøe	 159
+ec	 158
+ù_	 157
+J	 156
+vn	 156
+_h	 155
+ké_	 155
+ok	 154
+sta	 154
+to_	 152
+vý	 152
+nt	 151
+ých_	 149
+lo_	 149
+_by	 149
+dy	 149
+_pøe	 148
+ce_	 147
+R	 146
+n_	 146
+ád	 146
+pa	 145
+vé	 145
+am	 145
+mu	 145
+ný	 145
+ud	 144
+_è	 144
+_B	 142
+ter	 141
+nì_	 141
+èe	 140
+¹e	 140
+_V	 140
+_ko	 140
+li_	 139
+dì	 137
+hl	 137
+je_	 137
+ji	 137
+ist	 135
+jí	 135
+-	 134
+ik	 133
+si	 133
+ál	 132
+em_	 132
+_to	 132
+_vy	 131
+sp	 130
+ut	 130
+_J	 130
+_Ÿe	 130
+_M	 129
+di	 129
+kon	 128
+la_	 128
+tí	 128
+_ro	 127
+ns	 127
+ek	 126
+ick	 126
+T	 126
+yl	 125
+èn	 125
+rn	 125
+_Ÿe_	 124
+op	 124
+sti	 124
+kte	 124
+øed	 124
+edn	 123
+us	 121
+ím_	 120
+"	 119
+z_	 119
+str	 118
+ti_	 118
+ém	 118
+vat	 118
+d_	 118
+_ve	 118
+áv	 118
+ení_	 117
+iv	 117
+oj	 117
+_kt	 117
+ìl	 117
+val	 116
+eb	 116
+_K	 115
+tø	 115
+_kte	 115
+át	 115
+_i	 114
+_N	 114
+D	 114
+kl	 114
+ny	 114
+byl	 113
+ev	 113
+ri	 113
+ú	 113
+ky	 111
+sm	 111
+oh	 111
+E	 110
+ma	 110
+ìt	 110
+ský	 110
+kter	 109
+nu	 109
+le_	 108
+ja	 107
+zá	 107
+tì	 106
+tá	 106
+zn	 106
+let	 105
+aj	 105
+sto	 105
+¹í	 105
+me_	 105
+-_	 105
+u,	 105
+sv	 104
+_le	 104
+pol	 104
+L	 104
+_-	 104
+ln	 104
+pod	 104
+H	 103
+zi	 103
+kéh	 103
+kého	 103
+_ná	 103
+ent	 102
+u,_	 102
+_od	 102
+né_	 101
+_-_	 101
+al_	 101
+_kter	 101
+do_	 100
+nos	 100
+cí	 100
+rav	 99
+ran	 99
+_sv	 99
+ká	 98
+eè	 98
+ním	 98
+bu	 97
+_z_	 97
+ích	 97
+_byl	 97
+ání	 96
+rov	 96
+kr	 96
+dá	 95
+ové	 95
+dl	 95
+uj	 95
+nost	 95
+ém_	 95
+ech	 94
+ly	 94
+oc	 94
+vé_	 93
+_o_	 93
+dy_	 93
+ak_	 93
+nsk	 93
+_so	 93
+_ob	 92
+nc	 92
Index: /main/tags/2.25/gsdl/perllib/textcat/Other/estonian.lm
===================================================================
--- /main/tags/2.25/gsdl/perllib/textcat/Other/estonian.lm	(revision 21064)
+++ /main/tags/2.25/gsdl/perllib/textcat/Other/estonian.lm	(revision 21064)
@@ -0,0 +1,400 @@
+_	 20738
+a	 7004
+e	 5699
+i	 5321
+s	 4731
+t	 3769
+l	 3448
+u	 3446
+n	 2902
+k	 2584
+d	 2202
+m	 2043
+a_	 1758
+o	 1684
+r	 1429
+g	 1174
+v	 1151
+e_	 1139
+i_	 1136
+_k	 1136
+s_	 1077
+h	 1009
+,	 995
+,_	 995
+_t	 953
+p	 953
+j	 940
+ä	 900
+is	 896
+st	 851
+se	 841
+_s	 822
+.	 821
+as	 801
+d_	 801
+le	 800
+ta	 794
+in	 793
+_m	 790
+ô	 754
+._	 753
+t_	 746
+ma	 710
+_p	 680
+si	 677
+_v	 660
+es	 636
+al	 626
+us	 619
+el	 602
+_o	 596
+_e	 586
+ja	 580
+_j	 563
+te	 562
+ü	 549
+li	 532
+va	 515
+id	 501
+ol	 498
+tu	 497
+da	 490
+_n	 480
+ku	 478
+ud	 459
+nu	 455
+na	 438
+ei	 432
+ks	 418
+mi	 411
+ee	 411
+u_	 407
+ka	 400
+n_	 394
+b	 394
+ga	 386
+_l	 384
+_a	 380
+an	 366
+ja_	 365
+et	 358
+me	 358
+l_	 350
+at	 348
+la	 341
+ad	 340
+st_	 339
+ne	 336
+ll	 333
+_ta	 332
+ra	 330
+_ja	 328
+ik	 323
+en	 318
+ni	 308
+ul	 305
+sa	 302
+_ol	 302
+nd	 299
+_ja_	 299
+nud	 296
+ii	 291
+ko	 286
+_se	 285
+le_	 283
+aa	 281
+is_	 281
+gi	 270
+_te	 269
+ag	 269
+_va	 268
+_ku	 267
+ed	 262
+em	 255
+_mi	 255
+ma_	 247
+ti	 246
+ri	 245
+_h	 242
+gu	 239
+id_	 238
+ast	 237
+it	 236
+ga_	 236
+un	 232
+de	 230
+ud_	 230
+ha	 230
+ak	 228
+ah	 228
+uu	 228
+il	 227
+ôi	 226
+as_	 223
+ke	 222
+ar	 220
+a,	 220
+am	 220
+_ko	 220
+a,_	 220
+_ka	 220
+ai	 220
+eg	 216
+sin	 214
+est	 214
+ui	 214
+he	 214
+ks_	 213
+ö	 213
+oo	 213
+ju	 207
+är	 205
+ut	 203
+in_	 203
+oli	 201
+ki	 199
+su	 199
+es_	 199
+lt	 198
+ist	 188
+li_	 186
+ea	 186
+vi	 184
+im	 181
+mu	 181
+se_	 180
+ts	 180
+on	 178
+ise	 178
+ta_	 177
+ek	 176
+_oli	 176
+sel	 173
+nud_	 173
+_ü	 172
+a.	 171
+nn	 170
+ema	 169
+ng	 168
+lu	 168
+ge	 167
+_si	 166
+_ei	 165
+_i	 165
+_ei_	 164
+ei_	 164
+_r	 163
+ole	 161
+pa	 160
+lle	 160
+a._	 160
+ust	 159
+du	 156
+er	 156
+vô	 153
+da_	 153
+min	 152
+et_	 151
+d,_	 149
+_M	 149
+ht	 149
+d,	 149
+M	 149
+kui	 148
+_et	 147
+K	 147
+_K	 146
+pe	 145
+gi_	 145
+_vô	 145
+or	 144
+_tu	 142
+lt_	 141
+_ma	 141
+asi	 140
+ve	 139
+us_	 138
+ig	 136
+sin_	 136
+ur	 135
+_ta_	 134
+di	 134
+_et_	 134
+s,_	 132
+tas	 132
+s,	 132
+_kui	 131
+sk	 131
+re	 130
+po	 129
+oli_	 129
+om	 129
+äi	 128
+inu	 128
+_na	 128
+_oli_	 128
+_sa	 128
+aj	 128
+mis	 127
+ui_	 127
+_me	 127
+_pa	 126
+tus	 125
+pi	 125
+te_	 124
+ül	 123
+-	 123
+est_	 122
+_on	 121
+kk	 121
+tt	 120
+aga	 119
+na_	 119
+_T	 119
+T	 119
+b_	 118
+al_	 118
+sta	 118
+_mu	 116
+_ju	 116
+ida	 116
+aks	 116
+gu_	 116
+_ni	 116
+s.	 116
+ad_	 116
+_pe	 114
+eks	 114
+ev	 114
+end	 113
+s._	 113
+use	 111
+ära	 111
+_po	 111
+_min	 110
+S	 110
+aja	 110
+_la	 110
+ele	 109
+el_	 108
+on_	 108
+ab	 108
+_S	 108
+av	 107
+ing	 107
+kui_	 106
+_on_	 106
+au	 104
+ne_	 104
+ti_	 104
+ell	 103
+ae	 101
+kô	 101
+ed_	 100
+_ke	 99
+ata	 99
+iis	 99
+!	 98
+!_	 98
+sid	 98
+nda	 98
+eh	 98
+lle_	 97
+pu	 97
+ää	 97
+vôi	 97
+ine	 96
+t,	 96
+e,_	 96
+ale	 96
+_vôi	 96
+t,_	 96
+e,	 96
+eda	 96
+uk	 95
+ast_	 95
+ld	 95
+?	 94
+_kui_	 94
+_sel	 93
+_kô	 93
+tul	 93
+ega	 93
+lg	 92
+sii	 92
+val	 92
+e.	 92
+_su	 92
+ug	 92
+oh	 92
+kü	 92
+d.	 91
+ee_	 91
+see	 91
+e._	 91
+öö	 91
+oma	 91
+_ole	 90
+ses	 90
+stu	 90
+ôt	 90
+üü	 90
+_om	 89
+me_	 89
+ot	 89
+d._	 89
+_sii	 88
+to	 88
+_en	 87
+atu	 87
+?_	 87
+A	 86
+J	 86
+pea	 86
+jä	 85
+_A	 85
+_see	 85
+ime	 84
+_pi	 84
+_ha	 84
+mô	 84
+nä	 84
+_J	 84
+les	 84
+ste	 84
+kas	 84
+_ä	 84
+vä	 83
+E	 83
+pä	 83
+_ve	 83
+_E	 83
+eis	 82
+_jä	 81
+_pea	 81
+_mô	 80
+um	 80
+_kü	 80
+iku	 80
+üd	 80
+all	 79
+eid	 79
+ba	 79
+_vä	 79
+ina	 78
+lj	 78
+sid_	 78
+hu	 78
+tun	 78
+lä	 78
+_oma	 77
+i,_	 77
+i,	 77
+agu	 77
+uh	 77
+lm	 76
+ras	 76
+ss	 76
+kä	 76
+ees	 76
Index: /main/tags/2.25/gsdl/perllib/textcat/Other/frisian.lm
===================================================================
--- /main/tags/2.25/gsdl/perllib/textcat/Other/frisian.lm	(revision 21064)
+++ /main/tags/2.25/gsdl/perllib/textcat/Other/frisian.lm	(revision 21064)
@@ -0,0 +1,400 @@
+_	 46446
+e	 15767
+n	 9616
+i	 7837
+a	 7830
+t	 7562
+r	 7297
+s	 6307
+o	 4784
+n_	 4595
+d	 4564
+e_	 4213
+l	 4032
+k	 3951
+t_	 3079
+en	 2863
+m	 2605
+er	 2492
+y	 2462
+f	 2371
+_d	 2253
+de	 2124
+h	 1943
+in	 1899
+w	 1898
+en_	 1857
+_i	 1815
+u	 1769
+g	 1738
+an	 1690
+j	 1678
+p	 1651
+r_	 1619
+_f	 1602
+.	 1601
+ar	 1561
+te	 1545
+b	 1488
+s_	 1476
+._	 1435
+_s	 1370
+de_	 1235
+_de	 1224
+_w	 1181
+it	 1172
+ie	 1140
+,	 1078
+_o	 1056
+,_	 1056
+oa	 1045
+_e	 1040
+st	 1038
+an_	 1010
+_b	 972
+_de_	 965
+ke	 949
+_m	 947
+_t	 933
+ne	 920
+er_	 895
+at	 863
+sk	 856
+c	 850
+it_	 848
+_h	 838
+ei	 832
+k_	 817
+yn	 790
+ch	 784
+le	 772
+is	 769
+je	 765
+el	 761
+me	 758
+ea	 754
+_k	 740
+fa	 736
+in_	 735
+'	 733
+_it	 733
+_it_	 727
+ge	 727
+re	 725
+al	 724
+_fa	 684
+yn_	 640
+aa	 628
+fan	 626
+_y	 618
+ar_	 617
+et	 616
+ri	 615
+_fan	 613
+_n	 612
+li	 611
+_yn	 610
+_en	 598
+fan_	 594
+oe	 589
+_fan_	 584
+_en_	 583
+at_	 581
+_in	 570
+oar	 565
+_in_	 560
+y_	 555
+F	 549
+es	 540
+_a	 536
+ng	 523
+be	 514
+sj	 512
+nt	 510
+l_	 510
+_F	 506
+ns	 506
+D	 499
+te_	 499
+der	 497
+_yn_	 497
+ti	 493
+ek	 490
+ro	 476
+rs	 474
+rd	 473
+se	 470
+fo	 470
+ys	 462
+op	 461
+û	 461
+we	 456
+ry	 451
+da	 445
+d_	 443
+is_	 442
+_D	 440
+ur	 433
+i_	 432
+ha	 426
+_me	 425
+ear	 422
+_l	 417
+ed	 410
+as	 409
+om	 407
+ei_	 406
+Fr	 405
+nd	 404
+_fo	 394
+_p	 393
+oc	 390
+rys	 389
+ol	 386
+_Fr	 386
+och	 383
+fe	 381
+ik	 379
+ma	 379
+ra	 377
+nn	 374
+_g	 368
+_da	 367
+di	 363
+ts	 362
+ta	 361
+a_	 360
+ko	 359
+et_	 358
+ysk	 356
+Fry	 354
+Frys	 354
+z	 354
+ll	 350
+_be	 349
+ke_	 348
+I	 347
+ing	 346
+_'	 345
+m_	 343
+h_	 340
+ske	 339
+_ha	 338
+sje	 336
+_Fry	 336
+_Frys	 336
+wi	 335
+_op	 334
+p_	 334
+_is	 333
+ch_	 333
+tr	 330
+ten	 328
+ers	 327
+wa	 325
+ter	 322
+ji	 322
+rysk	 319
+_ne	 319
+je_	 312
+foa	 311
+ê	 309
+jo	 307
+_is_	 307
+ste	 307
+_te	 306
+â	 301
+n.	 301
+nne	 300
+rt	 300
+foar	 299
+S	 299
+mei	 299
+_r	 298
+_oa	 297
+wu	 293
+ak	 291
+si	 290
+wur	 290
+ni	 290
+pe	 288
+Frysk	 287
+oan	 286
+n._	 285
+_mei	 284
+der_	 281
+_foar	 281
+_foa	 281
+ht	 278
+cht	 277
+-	 275
+ú	 275
+_j	 274
+ne_	 273
+ken	 273
+fer	 271
+ûn	 270
+am	 270
+on	 268
+nde	 264
+_S	 264
+B	 262
+ki	 261
+id	 261
+le_	 261
+dat	 260
+v	 259
+_I	 256
+oar_	 255
+op_	 254
+lle	 252
+la	 244
+tt	 243
+dat_	 242
+_fe	 242
+mm	 240
+inn	 239
+_wi	 239
+_dat	 237
+g_	 236
+mei_	 236
+al_	 235
+_B	 234
+e.	 234
+ld	 231
+_al	 230
+_wur	 230
+urd	 230
+_wu	 230
+_op_	 230
+De	 229
+inne	 228
+ng_	 227
+_mei_	 227
+'t	 226
+ks	 226
+'t_	 224
+_dat_	 224
+_ko	 223
+_st	 220
+ân	 219
+rk	 219
+sa	 219
+e._	 219
+tte	 218
+en.	 218
+n,	 217
+ier	 216
+ten_	 216
+_fer	 215
+mi	 215
+hi	 215
+ien	 214
+_wa	 213
+n,_	 213
+no	 213
+_te_	 212
+ig	 212
+_De	 212
+ske_	 212
+_der	 212
+W	 211
+H	 211
+_oan	 210
+ee	 209
+dy	 208
+ek_	 207
+en._	 207
+ic	 207
+mme	 206
+yk	 204
+pr	 204
+net	 203
+foar_	 203
+he	 203
+wurd	 201
+_der_	 199
+jen	 199
+_dy	 199
+kr	 198
+ka	 197
+im	 196
+_H	 196
+il	 196
+ze	 196
+_ma	 195
+by	 194
+oer	 194
+kt	 193
+us	 193
+M	 193
+sk_	 192
+wo	 192
+_hi	 191
+or	 190
+ing_	 190
+_W	 190
+ich	 189
+De_	 187
+rr	 186
+int	 185
+_ú	 184
+:	 184
+ij	 184
+_ek	 183
+eg	 182
+:_	 180
+gen	 180
+as_	 180
+_se	 179
+e,	 178
+_net	 177
+e,_	 177
+ins	 177
+N	 177
+ls	 176
+st_	 176
+_wurd	 176
+ie_	 175
+E	 175
+nne_	 175
+_De_	 175
+sy	 175
+wer	 174
+gr	 174
+f_	 173
+nk	 172
+och_	 172
+net_	 169
+ad	 169
+_we	 169
+rde	 168
+sl	 168
+bi	 168
+of	 168
+so	 168
+_no	 167
+_ta	 167
+re_	 167
+to	 167
+den	 167
+J	 167
+t.	 166
+It	 165
+út	 165
+inne_	 165
+ysk_	 165
+lik	 164
+sp	 163
+_ek_	 162
+ou	 162
+tsj	 162
+It_	 161
+_sa	 160
+A	 160
+wol	 160
+lâ	 159
+_wo	 159
+ge_	 159
+lân	 159
+ige	 158
Index: /main/tags/2.25/gsdl/perllib/textcat/Other/georgian.lm
===================================================================
--- /main/tags/2.25/gsdl/perllib/textcat/Other/georgian.lm	(revision 21064)
+++ /main/tags/2.25/gsdl/perllib/textcat/Other/georgian.lm	(revision 21064)
@@ -0,0 +1,400 @@
+_	 14926
+À	 7221
+È	 5780
+Ä	 4137
+Ð	 2966
+Ñ	 2908
+Ë	 2607
+Ê	 2372
+Í	 2260
+Å	 2080
+Ã	 2078
+Ì	 2005
+Ç	 1598
+Á	 1383
+Ó	 1363
+È_	 1248
+À_	 1149
+Â	 1145
+ÊÈ	 1009
+Þ	 974
+_Ë	 965
+Ñ_	 964
+ÃÀ	 912
+ÈÑ	 901
+ÀÐ	 897
+Ø	 820
+.	 813
+ÄÁ	 767
+"	 762
+._	 735
+,	 720
+,_	 718
+ÑÀ	 684
+_À	 669
+Ú	 653
+ËÀ	 631
+ÀÌ	 622
+ÄÊ	 575
+ÐÈ	 570
+ÅÄ	 567
+Õ	 551
+_Ã	 550
+Ò	 542
+_Ñ	 526
+É	 518
+ÀË	 517
+ÅÀ	 485
+ÅÈ	 479
+ÂÀ	 478
+_Â	 474
+ÓÊ	 468
+_È	 436
+ÐÀ	 435
+ÀÅ	 420
+ËÈ	 419
+ÌÈ	 418
+ÄÐ	 416
+ÄÌ	 412
+ÈÑ_	 407
+_ÃÀ	 404
+ÃÀ_	 393
+ÀÊ	 384
+ËÍ	 382
+Ü	 376
+_"	 374
+ÊÈ_	 371
+×	 369
+ÐÍ	 364
+ÀÑ	 360
+ÈÇ	 358
+ÀÃ	 353
+ÌÀ	 349
+Ô	 349
+ÁÀ	 342
+Æ	 341
+ËÄ	 335
+ÈÀ	 334
+ÈÊ	 332
+ÐÇ	 326
+_Ð	 322
+ÁÈ	 321
+ØÈ	 319
+_Ä	 319
+_Ø	 319
+ÃÄ	 317
+_ÂÀ	 316
+ÇÀ	 316
+ÄÑ	 306
+Ä_	 299
+_Ç	 288
+ÐÄ	 279
+ÓÊÈ	 273
+ÊÍ	 271
+Ö	 270
+Ì_	 267
+ÌÄ	 267
+_ÑÀ	 266
+ÍÁ	 263
+ÓÐ	 260
+Ç_	 256
+ÄÊÈ	 255
+ÃÈ	 238
+ÊÄ	 238
+ÑÈ	 234
+ÊÀ	 233
+ÍÐ	 230
+ÈÌ	 229
+_Þ	 227
+"_	 225
+ÄÁÈ	 224
+:	 224
+:_	 223
+È.	 221
+_ÃÀ_	 217
+Û	 215
+ÞÄ	 213
+È,	 213
+È,_	 212
+_Ó	 211
+Í_	 209
+_ËÀ	 208
+ÈÑÀ	 208
+ÍË	 206
+_ÀÐ	 204
+ÇÅ	 203
+ÀÐÇ	 203
+ØÄ	 203
+È._	 201
+À.	 200
+-	 193
+ÀÞ	 192
+ÅÄÊ	 192
+Ú_	 189
+ÈÃ	 188
+Ù	 188
+ÕÀ	 187
+Ã_	 185
+ÈÊÈ	 183
+ÄÃ	 179
+À._	 177
+Ð_	 177
+ÍÃ	 174
+ÞÀ	 174
+ÈÐ	 173
+ÌÃ	 172
+_ÐÍ	 172
+ÍÑ	 172
+ÄÁÀ	 171
+_ËÍ	 170
+ÐÈ_	 170
+_ËÈ	 170
+_Ü	 169
+ÇÈ	 166
+ÁÄ	 166
+_Õ	 165
+ØÈ_	 165
+ÄÑ_	 163
+ÀÈ	 162
+_ØÄ	 160
+ÄÅ	 158
+_É	 155
+ÀÚ	 154
+ÊÈÑ	 153
+Î	 151
+Ë_	 149
+ÕÀÐ	 148
+À,_	 147
+À,	 147
+ÀÇ	 147
+ÀÂ	 145
+ÕÀÐÇ	 145
+ÈÂ	 143
+ËÀÐ	 143
+ÍÊ	 143
+ÀÊÈ	 142
+ÂÈ	 142
+ÌÄÁ	 141
+ÄË	 140
+ÀØ	 139
+ÓÊÈ_	 139
+ÄÇ	 139
+ÇÓ	 138
+_Ì	 136
+ÈÇ_	 135
+ÀÐÈ	 133
+ÀÌ_	 132
+ÊÄÁ	 131
+×Í	 130
+ÑÄ	 130
+ÈË	 130
+ÐÄÁ	 128
+ÀÕ	 125
+ÆÄ	 125
+ÔÄ	 125
+Ê_	 124
+ÀÅÈ	 124
+ÀÃ_	 124
+ÅÈÑ	 123
+_ËÄ	 123
+ÀËÈ	 122
+_ÕÀ	 121
+ÉÈ	 121
+_Å	 120
+×Å	 120
+ÍÅ	 116
+_Á	 114
+ÀÌÈ	 113
+ÀËÍ	 113
+ÂÀÌ	 113
+ÍÌ	 112
+ÉÀ	 112
+ÈÚ	 112
+ØÀ	 112
+ÀÐÀ	 111
+ÁÓ	 111
+ÞÅ	 109
+ÀÖ	 109
+ÂÍ	 107
+ÁÀ_	 107
+ÌÈ_	 107
+ÅÀÐ	 107
+ÄÊÈ_	 106
+ÐÃ	 106
+ÀÐ_	 106
+_ÀË	 105
+ß	 104
+ÄÐÇ	 104
+_ÄÐ	 104
+ÅÄÌ	 103
+_ÄÑ	 103
+ÐÍË	 103
+ÄÌÈ	 103
+_Ú	 103
+ÁÍ	 102
+_Ù	 102
+ËÈÑ	 102
+ÐÈÑ	 102
+ÞÍ	 102
+_ÐÍË	 101
+_ÕÀÐ	 101
+ÈÅ	 100
+_ÕÀÐÇ	 100
+ÓÐÈ	 99
+ÒÈ	 99
+ÂÄ	 99
+ÈÒ	 99
+ÀÀ	 97
+ÀÒ	 97
+ÁÓÊ	 96
+ÕÅ	 94
+ÈÄ	 94
+_ÇÀ	 94
+Ñ,_	 93
+ÐÑ	 93
+ÅÊ	 93
+_ØÀ	 93
+Ñ,	 93
+_ÑÈ	 93
+ÀÉ	 93
+ÀÆ	 92
+ÍÁÀ	 92
+ÀÑ_	 92
+ÌÍ	 91
+ÄÁÓ	 91
+ÇÕ	 91
+ËÓ	 90
+ÄÌ_	 90
+ÇÀÅ	 89
+ÄÁÓÊ	 89
+ÊÑ	 89
+ÀØÈ	 89
+ÃÄÁ	 89
+ÀÁ	 89
+È"	 89
+Ñ.	 88
+ÚÞ	 88
+ÂÀË	 88
+ÍÑ_	 87
+_ÄÐÇ	 87
+È×	 87
+ÁÈÑ	 87
+ÌÃÀ	 87
+ØÅ	 87
+ÞÄÊ	 87
+ÁÈÇ	 85
+ÑÀ_	 85
+ÇÅÄ	 85
+ÓÌ	 85
+ÒÀ	 85
+_Î	 84
+ÊÈ.	 84
+_ÐÀ	 83
+Ñ._	 83
+_Ô	 83
+_ÂÀË	 83
+ÊÈÀ	 83
+ÊÈ._	 82
+ÄÐÈ	 82
+ÈÀ_	 82
+ÈÀÌ	 82
+ÜÈ	 81
+ÀÚ_	 81
+"Ë	 81
+ÈÓ	 80
+_"Ë	 80
+ÐÇÅ	 80
+_ÄÑ_	 79
+_ÈÂ	 79
+ÀÓ	 79
+ÈÕ	 79
+ÀÐÇÅ	 79
+ÇÈ_	 79
+ÑÀÞ	 79
+ÐÇÓ	 78
+ÊÈ,	 78
+ÚÈ	 78
+ÞÈ	 78
+ÐÇÓÊ	 78
+ÇÓÊ	 78
+ÊÈ,_	 78
+ÀÃÀ	 78
+ÁÑ	 78
+_ÀÐ_	 77
+ÞÊ	 77
+ÐÓ	 77
+ÀÐÇÓÊ	 77
+_ÌÀ	 77
+ÅÈÇ	 77
+ÈÂÈ	 77
+ÀÐÇÓ	 77
+ÜÀ	 76
+ÅÀ_	 75
+_ÞÀ	 75
+ÉÅ	 75
+ÒÄ	 75
+ÐÀ_	 75
+ÅÀÊ	 75
+ÇÅÄÊ	 74
+ÐÇÅÄ	 74
+ÀÐÇÅÄ	 74
+ÄÁÀ_	 74
+ÐË	 73
+ÑÞ	 73
+ÑÒ	 73
+ÅÑ	 73
+ÑÓ	 73
+ÐÇÅÄÊ	 73
+ËÞ	 73
+ÍÊÍ	 72
+ÐÚ	 72
+_×	 72
+ÂÐ	 71
+ÅÄ_	 71
+ÒÍ	 71
+ÇÄ	 71
+ÍÂ	 71
+ÅÄÁ	 71
+ÕÀÐÇÓ	 71
+ÐÀÃ	 70
+ÀË_	 70
+ÅÃ	 69
+ËÀ_	 69
+ÍÄ	 69
+_ÀÐÀ	 67
+à	 67
+ÄÃÀ	 67
+ÇÀÌ	 67
+È×Í	 67
+ÕÀÐÇÅ	 67
+Ò×	 67
+ÂÀËÍ	 66
+_ÂÀËÍ	 66
+ÄÒ	 66
+ÍÃÀ	 66
+ÅÄÊÈ	 66
+ÀÌÀ	 66
+ÄÁÈÇ	 66
+_ÈÂÈ	 66
+ÄÊÍ	 65
+ÄÂ	 65
+ËÈÊ	 65
+ÊË	 65
+ÈÊÈ_	 65
+ÍÁÈ	 65
+ÅÐ	 65
+_ÈÑ	 64
+Ó_	 63
+ËÃ	 63
+",	 63
+ÃÍ	 63
+ÊÍÁ	 63
+ÂÅ	 63
+ÃÂ	 63
+ÄÍ	 62
+À"	 62
+ÀÅÀ	 62
+?	 62
+",_	 62
+!	 62
+_È×	 62
Index: /main/tags/2.25/gsdl/perllib/textcat/Other/greek-iso8859-7.lm
===================================================================
--- /main/tags/2.25/gsdl/perllib/textcat/Other/greek-iso8859-7.lm	(revision 21064)
+++ /main/tags/2.25/gsdl/perllib/textcat/Other/greek-iso8859-7.lm	(revision 21064)
@@ -0,0 +1,400 @@
+_	 89284
+á	 19666
+ô	 16086
+ï	 15826
+å	 14848
+é	 12766
+í	 12189
+ð	 8776
+ó	 8653
+ñ	 8399
+ê	 7761
+ì	 7529
+õ	 6850
+Ü	 6284
+_ô	 5918
+ë	 5802
+ò	 5371
+á_	 5272
+ç	 5236
+Ý	 4739
+ß	 4609
+ü	 4489
+ôï	 4461
+ò_	 4111
+ïõ	 4075
+é_	 4033
+å_	 4019
+.	 3916
+_ê	 3897
+ï_	 3836
+._	 3810
+í_	 3661
+_ð	 3414
+_ó	 3333
+"	 3247
+_ì	 3242
+_ôï	 3118
+,	 3106
+,_	 3068
+ã	 3058
+_á	 2912
+ù	 2689
+íá	 2593
+ä	 2455
+ôá	 2420
+÷	 2411
+êá	 2406
+óô	 2406
+_å	 2353
+-	 2335
+-_	 2192
+ý	 2171
+áí	 2162
+ôç	 2151
+Þ	 2141
+õ_	 2133
+áé	 2100
+è	 2053
+ö	 1989
+ïõ_	 1974
+åé	 1889
+_êá	 1882
+åß	 1864
+ôï_	 1802
+ðï	 1771
+áé_	 1727
+óå	 1709
+_í	 1647
+_"	 1619
+ç_	 1609
+éá	 1602
+íá_	 1518
+ôé	 1501
+ïí	 1501
+ôïõ	 1495
+ìå	 1460
+_ôïõ	 1407
+_Ý	 1405
+_óô	 1396
+þ	 1364
+ðå	 1359
+ôå	 1300
+ìá	 1298
+â	 1274
+ñé	 1252
+ü_	 1241
+_ä	 1231
+î	 1223
+íô	 1220
+_ôï_	 1196
+áð	 1187
+ñï	 1184
+_ã	 1183
+_ôç	 1177
+æ	 1158
+_åß	 1150
+Ü_	 1150
+_íá	 1124
+Ýí	 1115
+êáé	 1110
+_êáé	 1093
+áí_	 1082
+ñá	 1078
+êáé_	 1061
+_íá_	 1060
+_êáé_	 1053
+ìð	 1049
+íï	 1048
+áô	 1036
+éï	 1024
+éá_	 1018
+åñ	 1003
+ïý	 993
+_áð	 984
+óå_	 974
+éê	 973
+_ï	 967
+åí	 947
+ïò	 936
+åé_	 935
+ðü	 901
+ëï	 892
+_ìå	 890
+íå	 884
+ôïõ_	 871
+ïí_	 869
+áò	 865
+_ôïõ_	 854
+áó	 841
+ìå_	 840
+óá	 834
+êï	 833
+áñ	 832
+ðñ	 824
+ßí	 820
+êÜ	 808
+_ðï	 804
+ðé	 796
+Ê	 796
+ìÝ	 783
+ìï	 777
+Ýñ	 772
+áë	 766
+çí	 762
+Ì	 759
+éó	 745
+êå	 742
+ôá_	 740
+óôï	 738
+ù_	 730
+çí_	 728
+Ï	 717
+Ô	 714
+_ö	 711
+åô	 705
+äå	 704
+ðá	 697
+áò_	 688
+ôÜ	 684
+ïò_	 683
+_ü	 680
+_Ê	 675
+ïé	 671
+_÷	 670
+ôçí	 663
+ôçí_	 658
+_óôï	 647
+Þ_	 645
+ðü_	 638
+_è	 633
+_ï_	 631
+",	 630
+_ðñ	 626
+_Ì	 624
+ßð	 624
+Üí	 623
+",_	 623
+áðü	 620
+ðïõ	 619
+üô	 618
+ëá	 617
+ôïí	 617
+_áðü	 616
+ìé	 612
+Ï_	 611
+ñå	 607
+õô	 604
+ëå	 595
+_ë	 594
+ñü	 590
+_ìå_	 586
+éÜ	 580
+ôïí_	 577
+ãé	 577
+_Ï	 575
+áðü_	 572
+Üñ	 570
+ðÜ	 570
+_áðü_	 569
+ñÜ	 562
+ôáí	 554
+Ýíá	 553
+õí	 552
+ðïõ_	 551
+äé	 547
+ôñ	 547
+ôü	 544
+_â	 540
+÷å	 536
+åí_	 534
+çó	 528
+_Ï_	 525
+çò	 520
+".	 519
+_ðïõ	 516
+_Ô	 515
+"._	 513
+ôç_	 512
+ò.	 510
+åßð	 508
+ôáí_	 504
+_åßð	 503
+ò._	 501
+_ôá	 500
+îå	 497
+óôï_	 496
+ëë	 493
+áê	 492
+Á	 491
+_ðïõ_	 490
+Üë	 489
+ßðå	 489
+åßðå	 485
+_åßðå	 483
+_ôçí	 483
+ôé_	 482
+_ôçí_	 481
+Üô	 480
+ëé	 480
+_äå	 479
+Üì	 477
+_óôï_	 475
+óï	 473
+_Ü	 468
+"_	 463
+ìÝí	 463
+éí	 461
+éò	 452
+_áí	 452
+êü	 451
+áõ	 451
+_ôïí	 450
+_ãé	 449
+èá	 447
+åò	 446
+óç	 446
+_ìé	 445
+_ôïí_	 443
+å.	 441
+å._	 441
+ïõò	 439
+ëÜ	 439
+õò	 439
+ïë	 438
+ðéï	 437
+ïñ	 432
+_ðá	 428
+_êÜ	 427
+ôå_	 427
+áì	 423
+;	 423
+_ìï	 422
+óê	 421
+ôçò	 421
+_î	 418
+óôç	 415
+ÊÜ	 411
+íç	 408
+ãéá	 405
+á.	 403
+êñ	 402
+êé	 402
+ò,	 402
+ò,_	 401
+á._	 398
+çê	 397
+_ÊÜ	 397
+åë	 396
+_Ýí	 395
+_Þ	 393
+_ìá	 392
+ßá	 391
+ùò	 391
+ëç	 390
+ßíá	 389
+ðß	 389
+ìïõ	 388
+ìÜ	 388
+_áõ	 387
+çò_	 386
+óõ	 384
+íáé	 384
+Ð	 383
+áõô	 382
+ß_	 376
+ìðé	 375
+ßó	 372
+_ôçò	 370
+_ôá_	 367
+_ãéá	 365
+_Ýíá	 362
+_ìð	 361
+èå	 361
+éïí	 359
+éò_	 358
+ôÞ	 358
+_èá	 354
+_áõô	 354
+Üìð	 352
+ê.	 352
+ê._	 351
+åßí	 351
+ïì	 350
+ßíáé	 348
+íôá	 348
+íáé_	 348
+ùò_	 347
+÷á	 346
+Å	 346
+õ.	 346
+ãéá_	 346
+õ._	 345
+äåí	 345
+Ýíá_	 345
+á,	 344
+á,_	 344
+äåí_	 344
+ýñ	 343
+üí	 343
+á-	 342
+ýó	 341
+_ê.	 340
+óôå	 339
+ÊÜì	 339
+_ê._	 339
+ôÝ	 339
+á-_	 338
+åõ	 338
+éë	 338
+ñß	 338
+ÊÜìð	 338
+_ìïõ	 338
+_ÊÜì	 338
+_ÊÜìð	 337
+õì	 336
+óåé	 336
+ðéïí	 336
+ìðéïí	 336
+ìðéï	 336
+_êï	 334
+ÊÜìðé	 334
+_ç	 334
+Üìðé	 334
+èá_	 333
+íé	 332
+ôçò_	 331
+ø	 331
+üì	 330
+çóå	 330
+_óá	 329
+ìá_	 328
+üò	 328
+Ó	 326
+_äåí	 325
+_äåí_	 325
+óì	 324
+åò_	 324
+ðåñ	 324
+ß÷	 323
+ßíáé_	 323
+ôéê	 322
+_ñ	 321
+Üìðéï	 321
+õò_	 321
+ïõò_	 321
+_ðå	 321
+óù	 320
+_ãéá_	 320
+ðñï	 320
+ãå	 318
+;"	 316
+;"_	 316
+Ä	 315
+ôõ	 314
+ñá_	 313
+_óõ	 312
+ñù	 312
+_èá_	 310
+üó	 309
+ïõ.	 309
Index: /main/tags/2.25/gsdl/perllib/textcat/Other/hawaian.lm
===================================================================
--- /main/tags/2.25/gsdl/perllib/textcat/Other/hawaian.lm	(revision 21064)
+++ /main/tags/2.25/gsdl/perllib/textcat/Other/hawaian.lm	(revision 21064)
@@ -0,0 +1,400 @@
+_	 35416
+a	 12973
+i	 6074
+o	 5151
+a_	 5093
+k	 5083
+e	 4551
+l	 3544
+u	 3442
+n	 3100
+_k	 2908
+e_	 2600
+i_	 2556
+h	 2489
+o_	 2245
+m	 2060
+ka	 1994
+'	 1943
+_i	 1899
+_a	 1620
+,	 1539
+,_	 1516
+_m	 1372
+_ka	 1339
+ma	 1338
+na	 1325
+p	 1235
+ä	 1233
+Ô	 1192
+ÿ	 1189
+ka_	 1085
+la	 1070
+ua	 1065
+ak	 997
+_i_	 995
+ai	 989
+ke	 977
+_h	 968
+K	 941
+_'	 938
+_l	 933
+u_	 920
+_K	 912
+_n	 894
+_ka_	 891
+.	 890
+an	 847
+_ma	 836
+ia	 812
+le	 804
+ke_	 753
+._	 749
+na_	 748
+au	 736
+ho	 700
+a,	 674
+ah	 670
+a,_	 666
+_ÿ	 662
+ku	 660
+lo	 654
+hi	 619
+_ke	 617
+_o	 616
+_p	 613
+ia_	 605
+'o	 589
+Ka	 586
+_Ka	 581
+el	 570
+ana	 569
+_a_	 566
+ä_	 564
+la_	 561
+w	 555
+al	 549
+_Ô	 539
+ko	 528
+_ke_	 518
+ik	 515
+_o_	 502
+'a	 495
+a'	 484
+ol	 465
+ha	 462
+ua_	 462
+	 459
+pu	 454
+no	 454
+_'o	 445
+ne	 438
+aku	 432
+le_	 427
+_ia	 422
+am	 420
+ÿo	 419
+wa	 415
+he	 414
+ahi	 412
+li	 410
+_ak	 394
+ai_	 393
+ele	 388
+Ôo	 388
+ki	 382
+H	 382
+on	 381
+'o_	 369
+_ho	 367
+au_	 366
+_aku	 364
+_e	 358
+pua	 357
+_H	 355
+me	 355
+_'o_	 352
+il	 352
+ama	 351
+pa	 348
+in	 346
+mai	 345
+_e_	 345
+O	 342
+_mai	 336
+A	 333
+_ia_	 332
+a.	 331
+oh	 319
+Kam	 317
+_Kam	 316
+P	 310
+aka	 308
+ul	 307
+_me	 307
+ap	 306
+"	 304
+aÔ	 302
+Kama	 299
+_Kama	 298
+ana_	 296
+_P	 294
+a._	 292
+_ko	 291
+i,	 289
+a'a	 288
+i,_	 288
+'i	 285
+Ôa	 278
+_w	 273
+_ÿo	 270
+ei	 269
+ele_	 261
+M	 260
+oa	 259
+ÿo_	 259
+_la	 257
+un	 255
+_Ôo	 253
+lu	 250
+nä	 249
+lä	 248
+apu	 245
+_M	 243
+ea	 243
+Ôi	 243
+ö	 242
+ua'	 241
+ÿa	 240
+Ôo_	 239
+ih	 239
+iki	 238
+_he	 235
+apua	 233
+ua'a	 229
+hi_	 228
+mapu	 226
+Kamap	 226
+amapu	 226
+mapua	 226
+amap	 226
+pua'	 226
+map	 226
+pua'a	 226
+ma_	 222
+_ÿo_	 221
+_wa	 218
+_no	 214
+e,	 214
+ila	 214
+ona	 213
+no_	 213
+he_	 210
+I	 209
+e,_	 209
+ok	 208
+ail	 206
+ula	 206
+lo_	 205
+nä_	 205
+ë	 204
+mak	 204
+me_	 204
+oe	 202
+aila	 201
+nu	 201
+_Ôo_	 200
+_me_	 200
+_lä	 200
+O_	 199
+ÿi	 197
+_iä	 195
+_iä_	 195
+iä_	 195
+_	 195
+iä	 195
+una	 191
+ake	 191
+kä	 189
+_u	 187
+ou	 185
+_nä	 185
+ni	 185
+apua'	 184
+nei	 183
+_ma_	 182
+i.	 181
+kau	 180
+Ma	 180
+iho	 179
+_pa	 176
+ahi_	 176
+mo	 176
+_Ma	 174
+ona_	 174
+oÔ	 173
+"_	 171
+ki_	 171
+_lo	 170
+kah	 168
+ho_	 167
+hu	 167
+'a_	 166
+kua	 165
+_I	 165
+_nä_	 164
+kul	 162
+ne_	 162
+ü	 162
+mai_	 162
+N	 161
+än	 160
+alo	 159
+iki_	 159
+kai	 159
+ila_	 158
+_mai_	 158
+i._	 155
+a'a_	 155
+_mak	 153
+_kä	 153
+aila_	 152
+He	 151
+li_	 151
+akul	 150
+kula	 149
+_pu	 149
+ao	 149
+_akul	 149
+akula	 149
+kon	 148
+na,	 147
+kona	 147
+na,_	 147
+ole	 147
+L	 147
+_ne	 146
+i'	 146
+E	 145
+hik	 144
+_kona	 144
+aÔa	 144
+_kon	 144
+ula_	 144
+loa	 142
+o'	 141
+_nei	 141
+_'a	 141
+_an	 139
+_He	 139
+_ha	 139
+kona_	 138
+_kau	 137
+_N	 137
+oe_	 137
+nak	 137
+_ih	 137
+_A	 136
+hiki	 136
+_ana	 135
+aÿ	 133
+_"	 133
+aka_	 133
+ku_	 132
+ala	 132
+mail	 132
+	 132
+aua	 132
+'i_	 132
+maila	 131
+_mail	 131
+aw	 131
+ha_	 130
+kahi	 129
+Ôi_	 129
+hel	 128
+ea_	 128
+ui	 127
+_L	 127
+_iho	 126
+op	 126
+_al	 126
+I_	 125
+Pe	 125
+wah	 125
+aha	 125
+uk	 124
+lel	 124
+oÿ	 124
+hin	 123
+_Pe	 123
+ali	 123
+hol	 123
+_ai	 123
+po	 122
+akua	 122
+hele	 122
+kula_	 121
+_ÿa	 121
+ola	 121
+ua'a_	 120
+aik	 120
+ou_	 120
+'O	 119
+_wah	 119
+eh	 119
+una_	 119
+u,	 118
+ake_	 118
+kou	 117
+_I_	 117
+Pel	 116
+_he_	 116
+Pele	 116
+'e	 116
+_Pele	 116
+_Pel	 116
+hine	 115
+la,	 115
+ani	 115
+kan	 115
+ine	 115
+aku_	 114
+naka	 114
+A_	 114
+la,_	 114
+ÿe	 113
+_'O	 113
+u,_	 112
+ahin	 112
+_ku	 111
+'O_	 111
+wahi	 111
+ole_	 110
+ahine	 110
+hoÔ	 110
+."	 110
+ono	 110
+_pua	 109
+wai	 109
+i'i	 109
+'u	 109
+_hoÔ	 108
+make	 108
+_O	 108
+_hi	 108
+_'O_	 108
+ek	 107
+oa_	 107
+."_	 107
+_wahi	 107
+	 107
+ola_	 106
+ö_	 106
+ko_	 106
+kë	 106
+ika	 105
+olo	 104
+_no_	 104
+_ua	 104
+_aku_	 104
Index: /main/tags/2.25/gsdl/perllib/textcat/Other/hebrew-iso8859_8.lm
===================================================================
--- /main/tags/2.25/gsdl/perllib/textcat/Other/hebrew-iso8859_8.lm	(revision 21064)
+++ /main/tags/2.25/gsdl/perllib/textcat/Other/hebrew-iso8859_8.lm	(revision 21064)
@@ -0,0 +1,400 @@
+_	 81560
+é	 23072
+å	 19215
+ä	 15606
+ì	 12612
+ø	 11293
+ú	 11070
+î	 10090
+á	 9648
+à	 9601
+ù	 9081
+ä_	 7811
+ð	 6685
+ò	 6326
+_ú	 5878
+í	 5542
+ã	 5019
+ç	 4669
+_í	 4570
+á_	 4267
+ë	 3984
+_ä	 3812
+÷	 3769
+ô	 3699
+ì_	 3693
+íé	 3535
+î_	 3489
+ñ	 3374
+à_	 3362
+úå	 3130
+,	 3067
+_ì	 3037
+_,	 3035
+_é	 2936
+ù_	 2886
+_íé	 2840
+â	 2768
+è	 2626
+ï	 2424
+_ø	 2395
+_úå	 2291
+.	 2256
+ö	 2215
+_.	 2205
+éð	 2144
+ò_	 2003
+_ï	 1959
+_å	 1913
+"	 1815
+éá	 1797
+ìù	 1742
+éì	 1687
+éø	 1665
+é_	 1647
+åé	 1620
+å_	 1578
+åø	 1525
+úà	 1475
+ë_	 1469
+øå	 1411
+æ	 1383
+åð	 1353
+îä	 1351
+úé	 1343
+éé	 1343
+ìå	 1315
+éã	 1285
+øé	 1236
+îä_	 1211
+äì	 1206
+åî	 1192
+ðé	 1163
+øù	 1155
+éà	 1146
+àø	 1138
+_úà	 1137
+ùé	 1134
+éù	 1087
+ð_	 1080
+ìà	 1074
+åç	 1067
+_à	 1062
+ùî	 1059
+éî	 1052
+äé	 1047
+-	 1024
+ìù_	 1008
+åä	 973
+øá	 967
+åà	 954
+úà_	 951
+åì	 948
+_ã	 941
+éä	 896
+ðå	 888
+åò	 883
+éë	 873
+åù	 871
+ìò	 867
+àì	 850
+òå	 843
+_-	 830
+ç_	 830
+ãå	 824
+ïå	 820
+ø_	 806
+åá	 805
+_ìù	 799
+éè	 784
+àä	 773
+_ìù_	 748
+éò	 746
+ãé	 743
+_ù	 726
+_úà_	 723
+ê	 720
+_úé	 719
+-_	 716
+_-_	 713
+áé	 709
+áå	 706
+åú	 699
+àä_	 690
+øî	 686
+ùä	 683
+åã	 678
+éç	 675
+ô_	 672
+äð	 669
+_á	 668
+_ò	 659
+_ê	 655
+éñ	 652
+ïé	 649
+_ìò	 640
+éå	 635
+àî	 635
+éá_	 632
+ú_	 631
+îà	 628
+ùå	 627
+_ïå	 624
+ìé	 624
+ìò_	 621
+úä	 619
+éú	 600
+äì_	 599
+åë	 599
+éô	 596
+ôä	 595
+å÷	 586
+äù	 578
+òé	 575
+_ïé	 569
+îå	 564
+_ìò_	 561
+÷é	 560
+éâ	 557
+éä_	 557
+øùé	 554
+íå	 548
+àì_	 548
+úåé	 548
+ìàø	 546
+øà	 542
+äø	 540
+"_	 540
+îá	 539
+ùä_	 538
+åô	 538
+àøù	 535
+øò	 534
+çä	 533
+åâ	 532
+àøùé	 530
+ìàøùé	 530
+ìàøù	 530
+àå	 527
+îé	 525
+_éë	 518
+äî	 518
+ôä_	 511
+éë_	 510
+_éð	 509
+ìë	 506
+úî	 502
+îá_	 500
+ñå	 498
+çà	 497
+é÷	 497
+åå	 494
+_÷	 485
+â_	 481
+íéì	 477
+_äé	 477
+ãî	 472
+áä	 470
+,ä	 470
+_,ä	 470
+÷_	 469
+òá	 468
+_íå	 467
+äá	 467
+çä_	 466
+_éë_	 463
+àá	 462
+øç	 462
+_àì	 461
+õ	 455
+îì	 454
+éðé	 454
+ùà	 453
+øä	 453
+éö	 452
+íéø	 451
+_äð	 447
+èé	 443
+ã_	 441
+îò	 440
+íéé	 439
+åä_	 439
+'	 435
+àî_	 430
+.í	 429
+úð	 429
+_.í	 428
+ø÷	 427
+úø	 423
+åñ	 417
+ðù	 417
+_äì	 414
+ñì	 413
+ðú	 408
+ñ_	 405
+ñä	 400
+ìô	 400
+áù	 399
+,í	 399
+_,í	 399
+îî	 397
+ùé_	 396
+ðá	 396
+òä	 394
+úä_	 393
+úåð	 393
+íéð	 389
+_øå	 385
+øîà	 384
+éà_	 384
+ìá	 384
+úá	 381
+áø	 378
+áä_	 377
+èñ	 374
+_õ	 374
+òî	 374
+çé	 373
+øô	 373
+äå	 371
+çå	 370
+áì	 370
+_ìà	 370
+÷å	 367
+_äø	 366
+_íéø	 364
+çî	 363
+æ_	 362
+_ç	 360
+ðë	 360
+_ìå	 360
+ëå	 359
+,ú	 358
+_,ú	 357
+îú	 356
+éðå	 353
+åøé	 353
+åà_	 349
+øã	 348
+úåø	 348
+àé	 345
+ó	 345
+ìùî	 344
+ëé	 340
+_íéì	 340
+åö	 338
+úì	 338
+_íéé	 336
+øçà	 335
+_úåé	 335
+îà_	 332
+ìç	 331
+_úø	 329
+_úåð	 325
+âé	 325
+òä_	 325
+:	 324
+ôì	 324
+àá_	 324
+ùø	 322
+øè	 321
+úù	 320
+ö_	 320
+îò_	 319
+åé_	 319
+_:	 319
+öî	 316
+ùîî	 315
+_ñ	 315
+úéð	 315
+ñî	 315
+äã	 313
+øä_	 312
+åè	 312
+_ó	 310
+ùàø	 309
+øùé_	 305
+àøùé_	 305
+.íé	 305
+_.íé	 304
+äú	 303
+éèñ	 303
+_'	 303
+âä	 302
+ùî_	 302
+_íéð	 301
+ìä	 298
+øâ	 294
+çè	 293
+ãò	 293
+íéã	 292
+àù	 292
+ìùîî	 292
+íò	 292
+éãé	 290
+ùì	 289
+ôå	 289
+ãá	 289
+öå	 287
+_íò	 286
+,íé	 285
+_,íé	 285
+ðî	 284
+ñé	 282
+ùá	 282
+_øù	 281
+ãø	 281
+_úåø	 281
+÷ä	 280
+úåù	 278
+äù_	 276
+îì_	 276
+_àì_	 275
+åäé	 274
+_ìàø	 274
+ôé	 274
+òá_	 271
+ìà_	 271
+áà	 270
+çà_	 269
+çì	 268
+òô	 267
+áò	 267
+.ä	 266
+_øé	 266
+_ìàøù	 266
+åðé	 266
+_.ä	 265
+éèñì	 265
+èñì	 265
+éìà	 265
+úò	 264
+ðä	 263
+÷ì	 262
+ðéè	 260
+_.ú	 260
+.ú	 260
+ôì_	 260
+äå_	 259
+ñìô	 258
+èñìô	 258
+éèñìô	 258
+ðéèñì	 257
+ðéèñ	 257
+åî_	 256
+ñä_	 256
+îù	 255
+éøå	 255
+ðù_	 254
+åîú	 254
+ää	 252
+á÷	 251
+éù_	 251
+_åð	 251
+éøá	 251
+_øá	 249
+_éã	 249
+_íéã	 249
+ëä	 248
+âð	 247
+_ãå	 247
Index: /main/tags/2.25/gsdl/perllib/textcat/Other/hungarian.lm
===================================================================
--- /main/tags/2.25/gsdl/perllib/textcat/Other/hungarian.lm	(revision 21064)
+++ /main/tags/2.25/gsdl/perllib/textcat/Other/hungarian.lm	(revision 21064)
@@ -0,0 +1,400 @@
+_	 19186
+e	 5753
+a	 4627
+t	 4522
+s	 3480
+l	 3437
+n	 3137
+k	 3036
+i	 2527
+r	 2437
+z	 2399
+o	 2303
+á	 2039
+é	 1995
+g	 1978
+m	 1695
+y	 1338
+_a	 1256
+b	 1186
+d	 1148
+a_	 1108
+v	 1057
+t_	 901
+sz	 889
+el	 832
+,	 819
+,_	 818
+h	 792
+k_	 769
+.	 767
+et	 743
+gy	 711
+s_	 705
+_m	 702
+_a_	 695
+en	 671
+ö	 662
+n_	 646
+_k	 645
+j	 623
+._	 613
+i_	 606
+eg	 601
+p	 586
+_e	 580
+u	 579
+le	 576
+ó	 542
+er	 495
+f	 485
+ek	 477
+te	 477
+és	 473
+_s	 471
+al	 464
+ta	 458
+í	 453
+_h	 444
+_t	 442
+an	 426
+ze	 425
+me	 406
+at	 405
+l_	 401
+es	 395
+õ	 387
+y_	 381
+z_	 375
+tt	 374
+ke	 372
+_v	 369
+ás	 368
+ak	 367
+_é	 365
+ny	 363
+tá	 359
+c	 358
+re	 350
+to	 347
+A	 343
+e_	 340
+ü	 332
+ne	 330
+os	 326
+ál	 320
+_f	 320
+az	 317
+zt	 317
+ár	 317
+_n	 315
+ko	 312
+_A	 303
+_sz	 302
+is	 301
+ve	 299
+gy_	 297
+ít	 293
+_b	 293
+ra	 291
+or	 289
+ol	 284
+_i	 281
+em	 279
+_l	 274
+la	 264
+ez	 262
+be	 260
+lt	 260
+ok	 260
+ye	 256
+_me	 252
+on	 251
+en_	 247
+ar	 245
+_az	 245
+in	 243
+án	 242
+se	 242
+ég	 238
+egy	 237
+ha	 237
+r_	 237
+té	 237
+ér	 235
+sze	 233
+én	 226
+ly	 224
+g_	 221
+"	 221
+ll	 219
+iz	 214
+de	 214
+ek_	 213
+mi	 212
+rt	 211
+ba	 209
+ho	 209
+A_	 209
+és_	 209
+az_	 205
+va	 204
+ag	 203
+ka	 202
+na	 202
+og	 201
+ik	 201
+nt	 200
+_A_	 199
+ô	 199
+-	 198
+tt_	 198
+_az_	 197
+ni	 195
+cs	 194
+ki	 190
+kö	 187
+át	 187
+_eg	 187
+nd	 186
+fe	 185
+_és	 185
+lá	 182
+bi	 181
+nk	 180
+_le	 179
+an_	 179
+_és_	 177
+tás	 175
+ké	 174
+meg	 173
+_egy	 172
+ma	 171
+as	 170
+sa	 170
+sí	 169
+ge	 167
+ot	 167
+za	 167
+E	 166
+m_	 165
+_meg	 165
+_el	 165
+bb	 164
+ro	 164
+zá	 163
+he	 162
+má	 161
+sé	 160
+_r	 160
+sít	 160
+tos	 159
+ti	 159
+st	 158
+_j	 158
+él	 157
+it	 156
+_ho	 156
+ül	 156
+_ha	 155
+vé	 154
+am	 152
+oz	 152
+ele	 151
+ya	 151
+zto	 150
+ú	 149
+biz	 147
+so	 147
+et_	 145
+izto	 144
+izt	 144
+ap	 141
+"_	 141
+ed	 141
+ss	 140
+bizt	 140
+ék	 140
+bizto	 140
+iztos	 139
+ét	 139
+ztos	 139
+osít	 138
+zet	 138
+osí	 138
+mé	 137
+_is	 137
+t,	 136
+tosít	 136
+tosí	 136
+t,_	 136
+ó_	 135
+agy	 135
+ztosí	 135
+li	 134
+om	 134
+_fe	 134
+ere	 133
+ág	 133
+t.	 132
+nek	 131
+vi	 129
+_d	 129
+zo	 128
+k,_	 128
+k,	 128
+_kö	 127
+_p	 127
+M	 126
+let	 126
+ak_	 125
+já	 125
+ett	 125
+û	 124
+si	 124
+ész	 123
+_E	 123
+ép	 123
+vá	 123
+rá	 123
+t._	 123
+is_	 123
+S	 123
+ítás	 122
+ítá	 122
+kor	 121
+ai	 121
+fel	 120
+da	 120
+_mi	 120
+pe	 119
+ogy	 118
+ban	 118
+ad	 117
+ga	 116
+_va	 116
+ott	 114
+_ne	 114
+_ki	 113
+ör	 113
+zé	 112
+ben	 112
+_te	 111
+zi	 111
+sá	 110
+ség	 109
+do	 109
+tó	 108
+em_	 108
+_"	 108
+_ta	 108
+_M	 107
+ogy_	 107
+_á	 107
+k.	 106
+ól	 105
+_ke	 105
+_g	 104
+:	 103
+gye	 102
+ák	 102
+hog	 102
+ri	 102
+mo	 101
+ok_	 101
+:_	 101
+hogy	 101
+il	 101
+el_	 100
+zer	 100
+ete	 99
+nn	 99
+nak	 98
+je	 98
+sítá	 98
+szá	 98
+yo	 98
+osítá	 98
+sítás	 98
+_ké	 98
+_hog	 98
+lé	 97
+_S	 97
+_hogy	 97
+ig	 97
+_-	 96
+hogy_	 96
+ban_	 96
+ese	 95
+_bi	 94
+fo	 94
+ja	 94
+ul	 94
+õ_	 94
+k._	 94
+_c	 93
+ká	 91
+es_	 91
+ná	 91
+ény	 91
+gé	 91
+ás_	 91
+egy_	 90
+áb	 90
+rd	 89
+I	 89
+ány	 89
+_biz	 89
+_fel	 88
+öv	 88
+ala	 88
+szer	 88
+po	 88
+_ma	 88
+leg	 88
+tö	 88
+ket	 87
+un	 87
+di	 87
+ai_	 87
+nek_	 87
+rm	 86
+tal	 86
+év	 85
+_is_	 85
+nem	 85
+ti_	 84
+öz	 84
+szt	 84
+ut	 83
+ter	 83
+dé	 83
+kk	 83
+or_	 83
+b_	 82
+né	 82
+os_	 82
+re_	 82
+rs	 82
+_bizt	 82
+min	 82
+ben_	 81
+ra_	 81
+ik_	 81
+go	 80
+len	 80
+lm	 80
+öt	 80
+ely	 80
+aj	 80
+öl	 80
+_sze	 80
+_be	 79
+ev	 79
+ré	 79
+ssz	 79
+nt_	 79
+gya	 79
+K	 79
+si_	 79
+sza	 78
Index: /main/tags/2.25/gsdl/perllib/textcat/Other/icelandic.lm
===================================================================
--- /main/tags/2.25/gsdl/perllib/textcat/Other/icelandic.lm	(revision 21064)
+++ /main/tags/2.25/gsdl/perllib/textcat/Other/icelandic.lm	(revision 21064)
@@ -0,0 +1,400 @@
+_	 26104
+a	 6496
+r	 6044
+n	 5160
+i	 5123
+s	 3987
+e	 3891
+u	 3582
+t	 3300
+ð	 3126
+l	 3071
+g	 2726
+m	 2459
+k	 2256
+f	 2230
+r_	 1967
+v	 1641
+ar	 1472
+ð_	 1420
+_s	 1332
+á	 1248
+o	 1221
+í	 1197
+a_	 1155
+in	 1150
+i_	 1114
+h	 1023
+j	 975
+d	 974
+st	 929
+að	 925
+.	 922
+n_	 875
+._	 875
+_v	 874
+m_	 854
+nn	 842
+_f	 840
+ur	 824
+_a	 806
+ó	 785
+_h	 782
+æ	 779
+ið	 771
+er	 765
+um	 727
+g_	 716
+y	 711
+_e	 709
+þ	 672
+b	 672
+ir	 671
+ri	 670
+an	 667
+ö	 650
+_á	 648
+að_	 645
+u_	 633
+na	 631
+í_	 625
+ar_	 622
+_þ	 608
+á_	 606
+_í	 595
+ta	 567
+ei	 566
+la	 558
+_m	 549
+_í_	 549
+um_	 547
+t_	 535
+ti	 529
+_o	 524
+ur_	 523
+_að	 519
+ið_	 512
+ði	 496
+ve	 494
+og	 494
+ú	 482
+og_	 479
+_og	 478
+_og_	 478
+nd	 469
+p	 464
+ra	 455
+un	 454
+ir_	 452
+_að_	 451
+ni	 439
+en	 439
+ðu	 439
+_á_	 436
+ng	 434
+il	 404
+ga	 395
+_t	 395
+nu	 393
+ki	 392
+ja	 383
+inn	 379
+_b	 375
+sk	 352
+s_	 350
+vi	 349
+rð	 347
+ða	 345
+ef	 339
+ag	 336
+_u	 330
+se	 324
+lu	 324
+af	 321
+_ve	 320
+tu	 318
+em	 307
+eg	 304
+nn_	 303
+_l	 303
+va	 301
+_k	 296
+,	 295
+ns	 292
+re	 292
+tt	 291
+,_	 291
+l_	 286
+am	 286
+es	 285
+yr	 285
+al	 281
+da	 277
+S	 275
+gu	 273
+_se	 271
+ver	 268
+_g	 266
+ing	 266
+_n	 262
+is	 258
+_er	 257
+sa	 256
+ður	 255
+le	 255
+_st	 255
+_S	 254
+sem	 254
+ll	 254
+me	 253
+ha	 251
+li	 249
+kk	 249
+rs	 247
+_vi	 247
+rn	 246
+sl	 244
+gi	 243
+ss	 242
+rf	 241
+fy	 240
+ði_	 240
+mi	 238
+ka	 237
+ma	 231
+ld	 230
+é	 229
+rir	 227
+sta	 227
+fyr	 227
+ví	 227
+di	 226
+ru	 224
+var	 224
+_fy	 222
+ku	 221
+em_	 221
+nar	 220
+_sem_	 220
+_sem	 220
+sem_	 220
+he	 219
+yri	 217
+_fyr	 216
+si	 216
+yrir	 215
+au	 212
+er_	 212
+ek	 211
+_ha	 210
+þe	 209
+fyri	 207
+fyrir	 207
+_þe	 205
+fi	 204
+fr	 203
+ge	 201
+or	 200
+ne	 200
+ann	 198
+jó	 198
+_va	 196
+_fyri	 196
+_ver	 194
+fl	 192
+_er_	 191
+_um	 189
+ík	 188
+til	 187
+_he	 186
+fa	 186
+il_	 182
+_ti	 178
+_til	 177
+gar	 176
+_var	 176
+na_	 176
+ý	 175
+eð	 171
+fu	 170
+nni	 169
+_me	 168
+ki_	 167
+við	 166
+ey	 165
+fn	 165
+arf	 164
+til_	 163
+st_	 162
+_til_	 162
+þa	 161
+num	 161
+_þa	 161
+as	 160
+_við	 160
+rt	 159
+el	 158
+uð	 156
+inn_	 155
+_um_	 154
+ra_	 153
+bæ	 153
+tar	 151
+ta_	 151
+erð	 151
+ór	 148
+and	 148
+_sa	 146
+ig	 146
+_en	 146
+nga	 145
+rir_	 145
+us	 144
+jar	 143
+et	 143
+ár	 142
+_sk	 140
+ndi	 140
+æð	 139
+var_	 139
+_r	 138
+av	 138
+æk	 137
+nna	 137
+ður_	 136
+ál	 136
+ko	 135
+nin	 135
+við_	 135
+ól	 135
+ins	 134
+ik	 133
+E	 133
+K	 133
+yrir_	 133
+ns_	 133
+on	 133
+ein	 132
+_við_	 132
+ög	 132
+já	 132
+Þ	 132
+öl	 132
+ðs	 132
+_mi	 131
+f_	 131
+sí	 131
+sj	 131
+stu	 131
+nda	 130
+_var_	 130
+gr	 129
+ús	 128
+tæ	 127
+ri_	 126
+haf	 126
+_sí	 125
+vík	 124
+rin	 124
+te	 124
+r.	 124
+r._	 123
+H	 123
+nes	 123
+ót	 123
+ru_	 123
+kr	 122
+F	 122
+ær	 121
+num_	 121
+k_	 121
+a.	 121
+_H	 121
+_fr	 120
+_ge	 120
+rá	 120
+_E	 120
+_Þ	 120
+ug	 120
+ngu	 119
+an_	 119
+inga	 118
+_K	 118
+_haf	 118
+enn	 117
+ars	 117
+rið	 117
+en_	 117
+sin	 116
+kur	 116
+it	 116
+ða_	 116
+ti_	 115
+rði	 114
+tj	 114
+ni_	 114
+at	 114
+tarf	 114
+br	 113
+slu	 113
+kki	 113
+rg	 113
+má	 113
+kv	 113
+_en_	 113
+a._	 112
+gar_	 112
+du	 112
+ju	 110
+eið	 110
+und	 110
+lag	 110
+tur	 110
+ega	 109
+hú	 109
+íð	 109
+gn	 109
+hef	 109
+kj	 109
+_hef	 109
+_sta	 108
+B	 108
+V	 108
+sam	 107
+_ei	 106
+_B	 106
+ft	 106
+ga_	 106
+G	 106
+_G	 105
+lö	 105
+kki_	 105
+star	 104
+in_	 104
+R	 104
+með	 104
+_ár	 103
+_með	 103
+ekk	 103
+inu	 103
+tö	 103
+_V	 103
+m.	 103
+aði	 103
+jö	 102
+æj	 102
+_bæ	 102
+ess	 102
+hús	 101
+ut	 101
+gs	 101
+aví	 101
+mu	 101
+_R	 101
+_ú	 101
+rst	 100
+æjar	 100
+leg	 100
+æja	 100
+ja_	 99
+avík	 99
Index: /main/tags/2.25/gsdl/perllib/textcat/Other/indonesian.lm
===================================================================
--- /main/tags/2.25/gsdl/perllib/textcat/Other/indonesian.lm	(revision 21064)
+++ /main/tags/2.25/gsdl/perllib/textcat/Other/indonesian.lm	(revision 21064)
@@ -0,0 +1,400 @@
+_	 19406
+a	 10666
+n	 5455
+e	 4535
+i	 4387
+r	 2936
+t	 2902
+an	 2853
+u	 2841
+k	 2761
+s	 2311
+m	 2178
+d	 2134
+g	 2105
+l	 1780
+a_	 1506
+n_	 1476
+ng	 1449
+p	 1397
+b	 1275
+an_	 1270
+o	 1246
+h	 1130
+i_	 1108
+er	 1038
+ka	 1032
+_d	 1006
+y	 997
+,	 951
+en	 941
+ar	 914
+,_	 900
+_m	 880
+ya	 842
+ta	 838
+ang	 797
+di	 787
+da	 773
+.	 754
+la	 742
+._	 738
+me	 732
+ak	 728
+_s	 718
+at	 690
+ra	 688
+ga	 683
+_k	 671
+_me	 650
+in	 628
+ah	 601
+_t	 583
+_p	 570
+g_	 551
+_b	 551
+_di	 548
+ng_	 544
+ma	 536
+se	 526
+tu	 511
+na	 506
+al	 500
+ri	 490
+as	 483
+k_	 482
+j	 480
+si	 470
+ny	 467
+h_	 457
+sa	 452
+ang_	 439
+it	 424
+kan	 423
+ti	 418
+_se	 417
+pe	 412
+S	 409
+ba	 407
+ke	 407
+em	 405
+men	 405
+be	 403
+un	 401
+te	 401
+am	 396
+pa	 395
+nya	 390
+_men	 374
+el	 374
+t_	 371
+_a	 360
+_i	 356
+u_	 355
+kan_	 345
+_ke	 339
+is	 335
+ah_	 324
+_S	 324
+eng	 321
+nga	 320
+ia	 318
+_pe	 316
+ha	 313
+ap	 311
+r_	 308
+w	 305
+li	 301
+_da	 300
+s_	 299
+P	 296
+nd	 290
+_be	 287
+ik	 283
+ja	 281
+yan	 281
+ad	 275
+ek	 273
+uk	 272
+di_	 270
+bu	 269
+ya_	 268
+yang	 268
+ak_	 266
+ber	 265
+_y	 265
+_ya	 264
+_P	 263
+ru	 260
+K	 259
+yang_	 256
+_yang	 256
+_yan	 256
+nt	 255
+de	 253
+_te	 250
+wa	 249
+et	 247
+at_	 246
+ara	 245
+gan	 243
+A	 237
+ari	 235
+ala	 230
+itu	 229
+c	 225
+ol	 225
+ni	 225
+us	 225
+dan	 224
+_K	 224
+M	 224
+B	 223
+ata	 222
+ai	 221
+ur	 219
+nya_	 217
+ua	 215
+_ka	 214
+_ber	 210
+eb	 209
+ran	 206
+D	 206
+ela	 206
+_di_	 205
+_l	 204
+ngan	 204
+ter	 203
+re	 201
+-	 199
+aka	 198
+l_	 194
+_A	 191
+era	 191
+a,	 191
+e_	 190
+ir	 187
+I	 186
+tan	 185
+_B	 184
+ut	 184
+ku	 183
+a,_	 183
+il	 182
+J	 181
+um	 180
+_it	 180
+_itu	 180
+_ta	 179
+su	 179
+dan_	 177
+es	 177
+on	 177
+or	 177
+_dan	 176
+lu	 174
+_M	 172
+tu_	 172
+_dan_	 172
+enga	 171
+mb	 169
+R	 169
+si_	 168
+per	 168
+gan_	 168
+ngan_	 165
+"	 162
+_ter	 162
+a.	 161
+man	 161
+gk	 160
+a._	 160
+asi	 160
+ngk	 160
+ep	 160
+ag	 159
+ul	 158
+da_	 157
+m_	 155
+du	 155
+ada	 153
+ki	 153
+rt	 150
+mp	 150
+T	 150
+ama	 148
+ing	 148
+na_	 147
+_J	 147
+_D	 145
+ung	 145
+ana	 145
+n,	 144
+ju	 144
+ud	 144
+rin	 143
+gi	 143
+aw	 141
+lah	 138
+lan	 138
+_sa	 136
+ri_	 136
+meng	 136
+_meng	 135
+_ma	 134
+n,_	 134
+awa	 134
+st	 134
+eka	 133
+mi	 133
+mu	 132
+_T	 132
+po	 131
+ge	 131
+ar_	 130
+id	 129
+ko	 129
+le	 128
+_h	 128
+ena	 127
+_j	 126
+emb	 126
+ina	 125
+_r	 124
+itu_	 124
+ay	 123
+ngg	 123
+gg	 123
+rang	 123
+pi	 120
+nan	 120
+_ba	 119
+_la	 119
+apa	 119
+_I	 118
+p_	 118
+bi	 117
+ai_	 117
+ta_	 116
+san	 116
+Ke	 116
+ro	 115
+eri	 114
+kar	 113
+lah_	 113
+_itu_	 112
+aya	 111
+i,	 110
+an,	 110
+ra_	 110
+_per	 110
+im	 110
+ika	 109
+isi	 109
+mem	 109
+tah	 108
+_Ke	 108
+ian	 108
+_mem	 108
+akan	 108
+Se	 108
+to	 107
+ab	 107
+ngka	 106
+rs	 106
+gka	 106
+uk_	 105
+seb	 104
+_de	 104
+pu	 104
+i,_	 104
+ita	 104
+nda	 103
+_ti	 103
+ni_	 103
+ca	 103
+_Se	 103
+ers	 103
+pen	 103
+ini	 102
+an,_	 102
+angk	 101
+uh	 101
+han	 101
+nta	 100
+_in	 99
+f	 99
+nj	 99
+ok	 99
+aga	 99
+_R	 98
+as_	 98
+tr	 98
+mer	 97
+lam	 97
+and	 97
+end	 96
+anga	 96
+ne	 96
+Sa	 96
+ka_	 96
+arin	 95
+gu	 95
+_ha	 94
+Z	 94
+al_	 94
+ga_	 94
+_Z	 93
+_pen	 93
+dar	 93
+Ad	 93
+i._	 93
+ada_	 93
+atan	 93
+tak	 93
+i.	 93
+ia_	 92
+asa	 92
+ap_	 92
+ari_	 92
+kat	 92
+_seb	 92
+_Za	 91
+Za	 91
+den	 91
+n.	 90
+_u	 90
+_Ad	 90
+engan	 89
+ib	 89
+any	 89
+n._	 89
+o_	 89
+Zar	 88
+Zari	 88
+rina	 88
+_Zar	 88
+_Zari	 88
+Zarin	 88
+arina	 88
+ks	 88
+angka	 87
+oli	 87
+eg	 87
+kt	 86
+_Sa	 86
+hu	 85
+ih	 85
+us_	 85
+adi	 85
+om	 85
+eba	 85
+anya	 85
+_bu	 84
+denga	 83
+L	 83
+ed	 83
+dak	 83
+deng	 83
+ma_	 82
+asi_	 82
Index: /main/tags/2.25/gsdl/perllib/textcat/Other/irish.lm
===================================================================
--- /main/tags/2.25/gsdl/perllib/textcat/Other/irish.lm	(revision 21064)
+++ /main/tags/2.25/gsdl/perllib/textcat/Other/irish.lm	(revision 21064)
@@ -0,0 +1,400 @@
+_	 8010
+a	 2622
+i	 1573
+h	 1334
+n	 1247
+r	 968
+_a	 847
+e	 830
+s	 817
+t	 747
+l	 639
+c	 636
+g	 598
+o	 590
+d	 554
+n_	 501
+a_	 487
+m	 432
+an	 415
+u	 413
+b	 379
+h_	 352
+ai	 350
+ch	 350
+ea	 346
+r_	 346
+í	 334
+é	 321
+_s	 309
+á	 306
+in	 281
+ar	 277
+.	 269
+_d	 266
+s_	 254
+ir	 253
+_b	 250
+f	 250
+an_	 246
+,	 241
+,_	 226
+ag	 225
+_an	 221
+bh	 218
+_c	 216
+._	 212
+ac	 210
+ha	 208
+_a_	 201
+"	 199
+_m	 199
+th	 198
+_t	 190
+ach	 182
+_ag	 180
+_an_	 179
+í_	 176
+_l	 168
+na	 168
+nn	 160
+e_	 159
+ar_	 158
+_g	 157
+ú	 156
+_i	 152
+il	 150
+le	 150
+is	 143
+ó	 142
+_bh	 138
+ei	 138
+g_	 135
+_f	 135
+dh	 135
+l_	 126
+t_	 125
+ig	 123
+é_	 122
+_n	 120
+gu	 120
+á_	 120
+mh	 118
+id	 117
+ch_	 117
+ad	 116
+he	 114
+ir_	 114
+ra	 109
+o_	 109
+ach_	 107
+ia	 105
+_ar	 105
+us	 104
+ui	 104
+_"	 101
+us_	 100
+T	 99
+am	 99
+ta	 98
+gus	 98
+gus_	 98
+_le	 97
+gh	 97
+_ch	 97
+agus	 94
+agus_	 94
+agu	 94
+éa	 93
+_agus	 93
+_agu	 93
+ean	 93
+na_	 92
+d_	 92
+ái	 91
+p	 89
+it	 89
+A	 89
+_ar_	 88
+rt	 86
+al	 85
+oi	 84
+sa	 84
+"_	 82
+hai	 81
+_r	 79
+nn_	 79
+hu	 79
+as	 79
+éi	 78
+_T	 78
+ma	 77
+air	 77
+at	 77
+ann	 76
+B	 76
+sé	 76
+hí	 75
+igh	 74
+st	 74
+ga	 73
+go	 71
+ua	 71
+ne	 71
+la	 71
+-	 71
+de	 71
+te	 71
+re	 70
+inn	 70
+ith	 69
+eac	 69
+_sé	 69
+in_	 68
+_go	 68
+hi	 68
+each	 68
+dh_	 68
+si	 67
+ag_	 67
+_go_	 66
+hea	 66
+go_	 66
+tha	 64
+om	 64
+_sé_	 63
+sé_	 63
+hí_	 63
+on	 62
+se	 61
+úi	 60
+nt	 60
+C	 60
+D	 59
+i_	 58
+_ag_	 58
+is_	 58
+ío	 58
+_de	 57
+_B	 56
+il_	 56
+or	 56
+_th	 54
+ca	 53
+fa	 53
+amh	 53
+_A	 53
+le_	 52
+?	 52
+S	 51
+io	 51
+_in	 51
+sí	 51
+li	 51
+rai	 50
+hf	 50
+ht	 50
+eo	 50
+sc	 50
+ri	 49
+:	 49
+igh_	 49
+gh_	 49
+_sí	 49
+:_	 49
+há	 49
+_D	 49
+be	 49
+aig	 49
+hé	 48
+oc	 48
+idh	 48
+rt_	 48
+ho	 47
+os	 47
+ann_	 47
+_C	 46
+!	 46
+Bh	 46
+bhf	 45
+_si	 45
+lt	 45
+_bhf	 45
+irt	 45
+ear	 44
+_na	 44
+ta_	 44
+air_	 44
+_p	 44
+im	 44
+aga	 44
+_ma	 44
+_S	 44
+aigh	 43
+án	 43
+_dh	 43
+uai	 43
+ao	 43
+cht	 43
+ain	 42
+bhe	 42
+ait	 42
+fh	 42
+sa_	 41
+m_	 41
+adh	 41
+ile	 41
+_é	 41
+ail	 41
+eir	 41
+ói	 41
+_Bh	 40
+as_	 40
+cha	 40
+idh_	 40
+hái	 39
+_i_	 39
+bh_	 39
+th_	 39
+ad_	 39
+och	 39
+mh_	 39
+tr	 39
+rea	 38
+_se	 38
+ro	 38
+rí	 38
+hair	 38
+_is	 38
+uil	 37
+iú	 37
+áin	 37
+I	 37
+ll	 37
+mé	 37
+_be	 36
+ba	 36
+eann	 36
+tá	 36
+_o	 36
+M	 36
+aid	 36
+aith	 36
+ib	 36
+'	 36
+tea	 36
+_mé	 35
+chu	 35
+ibh	 35
+each_	 35
+ean_	 34
+irt_	 34
+_na_	 34
+N	 34
+ist	 34
+fu	 34
+mha	 34
+bea	 34
+h.	 34
+_bhe	 34
+lá	 34
+ic	 34
+_sí_	 33
+eis	 33
+bhí	 33
+ni	 33
+héa	 33
+_sa	 33
+ith_	 33
+sí_	 33
+har	 33
+_bhí	 33
+ig_	 32
+ur	 32
+aí	 32
+hr	 32
+_am	 32
+_bhí_	 31
+da	 31
+úir	 31
+hfu	 31
+_chu	 31
+ol	 31
+ne_	 31
+_fa	 31
+An	 31
+Bhí_	 31
+Bhí	 31
+n,	 31
+_ac	 31
+bhí_	 31
+_bhfu	 30
+_ó	 30
+ana	 30
+_M	 30
+mé_	 30
+_fh	 30
+aigh_	 30
+bhfu	 30
+_mé_	 30
+tú	 29
+_le_	 29
+tá_	 29
+hean	 29
+háin	 29
+sin	 29
+eir_	 29
+nne	 29
+cé	 29
+_aga	 29
+h._	 29
+Tá	 29
+ibh_	 29
+iste	 28
+An_	 28
+do	 28
+hui	 28
+fui	 28
+ní	 28
+ste	 28
+acht	 28
+n,_	 28
+co	 28
+dea	 28
+ng	 28
+nach	 28
+id_	 28
+hfui	 28
+..	 28
+lei	 28
+nac	 28
+ce	 27
+a.	 27
+c_	 27
+lea	 27
+hfuil	 27
+_Bhí_	 27
+_bea	 27
+adh_	 27
+di	 27
+fuil	 27
+."	 27
+Tá_	 27
+ha_	 27
+ú_	 27
+uil_	 27
+."_	 27
+bhfui	 27
+_Bhí	 27
+éan	 27
+_do	 27
+lta	 27
+aoi	 27
+_lei	 27
+_mh	 26
+dú	 26
+fuil_	 26
+eat	 26
+-_	 26
+teac	 26
+ath	 26
Index: /main/tags/2.25/gsdl/perllib/textcat/Other/japanese-shift_jis.lm
===================================================================
--- /main/tags/2.25/gsdl/perllib/textcat/Other/japanese-shift_jis.lm	(revision 21064)
+++ /main/tags/2.25/gsdl/perllib/textcat/Other/japanese-shift_jis.lm	(revision 21064)
@@ -0,0 +1,400 @@
+	 9970
+	 2204
+_	 1555
+	 1214
+	 891
+A	 885
+	 846
+Ì	 836
+A	 831
+	 818
+	 815
+Ì	 790
+	 739
+	 729
+	 618
+	 607
+	 589
+	 568
+ð	 566
+	 555
+É	 552
+	 528
+É	 527
+ð	 500
+	 489
+	 481
+µ	 461
+¢	 460
+œ	 453
+	 449
+µ	 449
+Æ	 445
+Í	 440
+B	 419
+Å	 411
+B	 405
+ª	 404
+œ	 404
+¢	 401
+Ä	 396
+È	 389
+Æ	 387
+é	 368
+·	 366
+µ	 363
+Å	 361
+µ	 357
+é	 352
+Í	 352
+Ä	 349
+È	 345
+è	 330
+ª	 321
+	 320
+¢	 320
+¢	 306
+·	 305
+Ü	 292
+©	 284
+@	 282
+_	 281
+Ü	 275
+Ü	 268
+v	 263
+Ü	 258
+È	 256
+ê	 251
+È	 240
+è	 239
+­	 238
+Ä	 234
+à	 232
+Æ	 231
+Å	 226
+@	 220
+œ	 217
+Æ	 214
+Å	 211
+_	 210
+Ä	 205
+©	 204
+©	 203
+œ	 199
+³	 198
+Ì	 195
+ç	 194
+¯	 194
+©	 182
+Á	 182
+è	 181
+ß	 180
+É	 180
+A	 176
+€	 176
+±	 173
+É	 172
+Ì	 172
+v	 169
+»	 169
+·	 167
+ñ	 167
+B_	 166
+N	 166
+B_	 166
+O	 165
+«	 165
+A	 165
+·	 164
+P	 163
+ê	 163
+Á	 159
+æ	 159
+_@	 157
+ê	 156
+·	 155
+[	 153
+ç	 153
+X	 153
+é	 148
+i	 148
+é	 148
+Á	 147
+·B	 146
+±	 146
+·B	 145
+j	 142
+Á	 142
+P	 141
+µÄ	 141
+µÄ	 141
+Í	 141
+à	 141
+·	 137
+V	 137
+ß	 135
+ê	 135
+ú	 134
+u	 133
+[	 132
+€	 131
+l	 129
+å	 129
+s	 128
+Ÿ	 128
+ 	 125
+±	 125
+S	 125
+g	 124
+ª	 123
+³	 123
+ü	 123
+±	 122
+	 122
+Ç	 120
+³	 120
+è	 120
+Š	 120
+\	 119
+Í	 119
+u	 119
+v	 119
+œ	 119
+ß	 118
+W	 118
+Í	 117
+Ü·	 117
+R	 117
+œ	 117
+Ü·	 117
+æ	 114
+â	 114
+ã	 113
+	 113
+{	 113
+N	 112
+ 	 111
+í	 111
+³	 111
+o	 108
+Ü·	 107
+Ü·	 107
+Q	 106
+	 106
+«	 105
+Ü·B	 104
+à	 103
+«	 103
+ç	 103
+	 103
+ì	 102
+»	 102
+ 	 100
+ú	 100
+ 	 100
+ß	 99
+µœ	 98
+µœ	 98
+Ê	 97
+¯	 96
+¶	 96
+ð	 96
+I	 95
+[	 95
+[	 95
+ÍA	 94
+å	 94
+ÍA	 94
+€	 93
+Ä¢	 92
+Â	 92
+Ä¢	 92
+­	 92
+E	 92
+Q	 91
+š	 90
+w	 90
+Ä¢	 89
+Ä¢	 89
+Î	 89
+Œ	 88
+ç	 87
+x	 87
+­	 86
+P	 86
+§	 86
+ª	 86
+n	 86
+	 85
+·é	 85
+·é	 85
+€	 84
+ñ	 84
+¿	 84
+Í	 84
+À	 84
+Ÿ	 83
+œB	 83
+œB	 83
+	 83
+¯	 83
+ï	 82
+²	 82
+v	 80
+Ÿ	 80
+P	 80
+©ç	 79
+¡	 79
+A	 77
+Ý	 77
+¬	 77
+Ç	 77
+µÄ	 77
+µÄ	 77
+ñ	 76
+B	 75
+X	 75
+©ç	 75
+«	 74
+c	 74
+Ù	 74
+O	 73
+Š	 73
+š	 72
+i	 72
+ð	 71
+Š	 71
+B	 71
+æ	 70
+ï	 70
+Û	 70
+y	 70
+Ç	 69
+T	 69
+p	 69
+è	 68
+	 68
+	 68
+·B_	 67
+l	 67
+Z	 67
+æ	 67
+	 67
+ü	 67
+®	 67
+·B_	 67
+Ï	 67
+X	 66
+Ð	 66
+à	 66
+¹	 66
+Í	 66
+A	 66
+â	 65
+¯	 65
+A	 65
+U	 65
+š	 64
+í	 64
+í	 63
+èÜ	 62
+C	 62
+Áœ	 62
+èÜ	 62
+R	 62
+µ	 62
+ÁÄ	 62
+ÁÄ	 62
+Áœ	 62
+_	 61
+èÜ	 61
+µ	 61
+ü	 61
+^	 61
+	 61
+èÜ	 61
+é	 61
+l	 61
+é	 61
+»	 60
+üv	 60
+è	 60
+ü	 60
+v	 60
+üv	 60
+Ô	 60
+í	 60
+±Æ	 60
+	 60
+A	 60
+û	 59
+	 59
+ÈÇ	 59
+ÈÇ	 59
+Â	 59
+¯	 59
+W	 59
+ð	 58
+i	 58
+±Æ	 58
+Q	 58
+j	 58
+­	 58
+N	 58
+{	 57
+»	 57
+ª	 57
+	 57
+ð	 57
+Ì	 56
+É	 56
+µA	 56
+e	 56
+g	 56
+µA	 56
+Ê	 56
+@	 56
+Â	 55
+z	 55
+I	 55
+Y	 55
+Å·	 55
+¿	 55
+èA	 55
+A	 55
+š	 54
+¹	 54
+X	 54
+Ÿ	 54
+t	 54
+Å·	 54
+j	 54
+Š	 53
+É	 53
+±Æ	 53
+ã	 53
+±Æ	 53
+º	 53
+I	 53
+	 53
+ª	 53
+A	 53
+U	 53
+~	 53
+¹	 52
+A	 52
+x	 52
+èA	 52
+Ì	 52
+n	 52
+S	 51
+A	 51
+b	 51
+j	 51
+Ç	 51
+Q	 51
+¢œ	 51
+E	 51
+î	 51
+A	 51
+	 51
Index: /main/tags/2.25/gsdl/perllib/textcat/Other/latin.lm
===================================================================
--- /main/tags/2.25/gsdl/perllib/textcat/Other/latin.lm	(revision 21064)
+++ /main/tags/2.25/gsdl/perllib/textcat/Other/latin.lm	(revision 21064)
@@ -0,0 +1,400 @@
+_	 20136
+e	 6892
+i	 5604
+a	 5443
+u	 4581
+t	 4552
+s	 4354
+r	 3923
+n	 3375
+m	 3063
+o	 2921
+c	 2224
+l	 1805
+e_	 1625
+s_	 1503
+p	 1424
+d	 1397
+,	 1285
+,_	 1276
+er	 1077
+qu	 1028
+q	 1028
+a_	 1019
+t_	 1018
+is	 942
+_a	 921
+re	 902
+m_	 891
+v	 858
+b	 821
+um	 808
+_s	 773
+us	 772
+en	 766
+nt	 733
+in	 729
+ue	 727
+te	 720
+g	 718
+_i	 710
+_p	 679
+it	 676
+_c	 669
+et	 653
+que	 652
+_e	 643
+at	 643
+ue_	 616
+ra	 614
+que_	 611
+f	 601
+or	 598
+ri	 576
+ti	 572
+ta	 559
+tu	 552
+an	 551
+ae	 527
+_m	 513
+am	 501
+_t	 493
+us_	 488
+is_	 487
+es	 479
+em	 479
+_f	 451
+um_	 443
+_v	 442
+ia	 442
+li	 438
+_d	 436
+.	 432
+i_	 430
+et_	 429
+ni	 412
+ne	 409
+h	 406
+de	 404
+ur	 396
+._	 392
+ar	 388
+os	 388
+mi	 382
+pe	 382
+la	 376
+st	 371
+s,	 368
+di	 367
+_et	 366
+s,_	 365
+_in	 363
+on	 360
+o_	 359
+_n	 351
+_et_	 351
+as	 346
+im	 336
+na	 327
+se	 320
+ma	 315
+cu	 307
+vi	 306
+si	 303
+ro	 303
+r_	 302
+su	 299
+un	 295
+_l	 291
+to	 291
+ec	 290
+ci	 288
+co	 287
+_r	 287
+ere	 286
+ce	 284
+tr	 280
+re_	 278
+ent	 275
+x	 275
+ct	 274
+ve	 271
+ru	 259
+ul	 256
+me	 255
+ui	 255
+c_	 252
+_o	 250
+ic	 249
+ns	 247
+_qu	 242
+_q	 242
+no	 241
+ant	 235
+am_	 235
+_co	 233
+sa	 231
+ca	 230
+t,	 226
+mu	 225
+t,_	 225
+_re	 223
+el	 222
+ib	 222
+id	 218
+om	 212
+_te	 211
+al	 209
+le	 209
+it_	 208
+mo	 208
+ol	 206
+_u	 203
+;	 199
+_h	 199
+ac	 198
+;_	 198
+bu	 197
+nu	 196
+ua	 195
+n_	 195
+ll	 194
+tis	 191
+A	 189
+rt	 188
+ge	 188
+nd	 187
+au	 187
+lu	 186
+iu	 185
+squ	 185
+per	 185
+sq	 185
+ter	 185
+pa	 183
+_A	 183
+em_	 183
+ia_	 180
+ed	 179
+_pe	 178
+m,	 176
+sque	 175
+_su	 175
+ae_	 175
+m,_	 175
+pr	 175
+bi	 175
+bus	 174
+_vi	 174
+os_	 173
+ta_	 172
+mqu	 171
+mq	 171
+ss	 170
+sque_	 169
+ibu	 167
+ad	 166
+ibus	 165
+I	 164
+nte	 163
+ra_	 163
+mque	 162
+_de	 162
+po	 161
+_se	 160
+ere_	 160
+nc	 160
+qua	 159
+T	 159
+lo	 157
+oc	 156
+mque_	 156
+_T	 155
+_pa	 155
+_pr	 155
+tem	 154
+bus_	 152
+nti	 149
+rum	 149
+er_	 149
+ab	 148
+ir	 148
+da	 147
+_ve	 146
+ibus_	 146
+ex	 146
+ut	 145
+pi	 145
+tur	 145
+_ca	 143
+_me	 142
+es_	 142
+gi	 142
+te_	 141
+_I	 141
+vo	 141
+do	 141
+_si	 140
+tus	 139
+il	 137
+_ar	 136
+du	 133
+nt_	 133
+uc	 133
+fa	 132
+as_	 132
+rr	 131
+ba	 130
+_ad	 128
+ne_	 127
+_ma	 127
+ens	 127
+gn	 126
+s.	 126
+y	 126
+min	 125
+ris	 124
+in_	 123
+tum	 123
+P	 123
+_g	 123
+mp	 123
+e,	 122
+io	 122
+_P	 122
+ea	 122
+hi	 122
+e,_	 121
+era	 120
+sc	 120
+_la	 120
+qui	 120
+unt	 120
+fe	 119
+_in_	 118
+_no	 118
+ore	 118
+iam	 118
+va	 117
+tis_	 117
+s._	 117
+at_	 117
+eri	 116
+d_	 116
+con	 115
+fu	 115
+pu	 114
+cum	 114
+ub	 114
+ng	 114
+ine	 113
+_au	 113
+:	 113
+_di	 112
+ag	 111
+_con	 111
+ect	 111
+i,	 111
+equ	 111
+i,_	 111
+be	 111
+eq	 111
+_po	 110
+so	 110
+:_	 110
+nis	 109
+ha	 109
+uo	 109
+_fa	 108
+na_	 107
+ip	 107
+is,	 107
+_cu	 106
+cr	 106
+ate	 105
+is,_	 105
+ig	 105
+tor	 105
+rat	 104
+_qua	 103
+eg	 103
+a,	 103
+a,_	 102
+tra	 102
+_mo	 101
+sp	 101
+mis	 100
+itu	 100
+D	 99
+ali	 99
+eb	 99
+eni	 99
+_sa	 98
+ie	 98
+imu	 98
+_ex	 97
+_D	 96
+res	 95
+est	 94
+tri	 94
+ene	 94
+_mi	 94
+str	 94
+enti	 93
+t.	 92
+av	 92
+_per	 91
+ur_	 91
+ora	 91
+lt	 91
+umqu	 90
+_vo	 90
+umq	 90
+up	 89
+t._	 88
+quo	 88
+_ne	 88
+gen	 88
+rum_	 87
+tqu	 87
+tq	 87
+_fu	 86
+ep	 86
+ma_	 86
+umque	 86
+it,_	 85
+ine_	 85
+it,	 85
+men	 85
+mus	 84
+ort	 83
+ven	 83
+ina	 83
+us,_	 83
+us,	 83
+tque	 82
+_ge	 82
+per_	 82
+mor	 82
+inc	 82
+are	 81
+tus_	 81
+_an	 81
+rim	 81
+tque_	 81
+ot	 81
+ani	 80
+H	 80
+_tu	 80
+ho	 80
+tem_	 80
+u_	 80
+ser	 79
+um,_	 79
+um,	 79
+S	 79
+ten	 79
+ver	 79
+sti	 79
+ntu	 78
+fer	 78
Index: /main/tags/2.25/gsdl/perllib/textcat/Other/latvian.lm
===================================================================
--- /main/tags/2.25/gsdl/perllib/textcat/Other/latvian.lm	(revision 21064)
+++ /main/tags/2.25/gsdl/perllib/textcat/Other/latvian.lm	(revision 21064)
@@ -0,0 +1,400 @@
+_	 24504
+a	 8735
+i	 7353
+s	 6064
+t	 5176
+e	 4390
+r	 4339
+u	 4200
+n	 3422
+â	 3055
+m	 2817
+p	 2755
+k	 2703
+o	 2643
+s_	 2595
+d	 2131
+l	 2035
+j	 1972
+î	 1958
+ie	 1887
+v	 1822
+as	 1530
+u_	 1396
+_p	 1380
+b	 1357
+z	 1311
+ç	 1267
+a_	 1261
+as_	 1217
+.	 1065
+,	 1048
+,_	 1033
+g	 1010
+ar	 970
+ð	 965
+ti	 962
+c	 922
+_a	 876
+ja	 838
+st	 828
+_i	 822
+_v	 805
+pa	 792
+_t	 775
+._	 774
+um	 760
+_k	 749
+â_	 734
+_n	 728
+es	 712
+i_	 706
+at	 703
+is	 695
+_s	 680
+ai	 649
+ta	 635
+an	 631
+ka	 621
+r_	 615
+îb	 586
+ij	 585
+_u	 568
+_pa	 548
+un	 541
+no	 539
+va	 537
+ma	 525
+ra	 522
+ri	 515
+iz	 512
+in	 509
+vi	 508
+pr	 506
+sa	 487
+ju	 486
+tâ	 483
+ik	 473
+n_	 472
+am	 454
+en	 452
+tie	 440
+na	 432
+ða	 430
+tu	 420
+ija	 420
+ir	 419
+o_	 415
+m_	 414
+li	 411
+ci	 409
+ku	 404
+mi	 401
+_no	 398
+ek	 398
+_un	 397
+t_	 395
+_l	 394
+un_	 393
+_d	 393
+ot	 392
+_un_	 392
+ies	 391
+ar_	 388
+nâ	 387
+da	 387
+ei	 385
+em	 382
+_ti	 382
+pi	 380
+al	 368
+ba	 356
+ts	 355
+_iz	 353
+ap	 350
+jas	 349
+ko	 346
+au	 345
+ðan	 339
+re	 339
+ni	 337
+kâ	 328
+ro	 327
+et	 326
+rî	 325
+ga	 323
+mu	 322
+jas_	 321
+tr	 317
+_va	 312
+te	 310
+_pr	 307
+sp	 298
+sk	 297
+ne	 295
+îba	 293
+âs	 289
+ijas	 287
+_ar	 283
+la	 283
+to	 282
+ad	 280
+dz	 278
+îg	 277
+tî	 277
+çj	 277
+_sa	 277
+jâ	 274
+_m	 273
+ties	 273
+lî	 272
+ijas_	 269
+_at	 269
+ed	 267
+_pi	 267
+ò	 267
+s,	 265
+s,_	 265
+çr	 261
+gu	 258
+f	 258
+si	 257
+mâ	 256
+nt	 254
+tu_	 254
+_r	 253
+ru	 252
+âj	 251
+jum	 251
+âs_	 250
+ât	 249
+iem	 248
+_b	 248
+_vi	 245
+par	 244
+pie	 244
+rt	 243
+vç	 242
+_ne	 240
+âr	 240
+ai_	 239
+_.	 239
+_j	 237
+us	 237
+_ka	 236
+er	 232
+bas	 232
+_tie	 232
+_par	 230
+di	 229
+û	 228
+ms	 228
+âd	 226
+îbas	 224
+om	 220
+bu	 219
+umu	 217
+iek	 216
+kt	 216
+it	 216
+râ	 215
+_ko	 214
+ana	 211
+âk	 211
+or	 210
+de	 210
+inâ	 207
+dî	 204
+ur	 203
+pri	 203
+_c	 202
+ta_	 202
+bas_	 201
+es_	 201
+_pie	 200
+il	 200
+os	 199
+ðana	 199
+id	 198
+L	 198
+_ie	 197
+bi	 194
+ak	 194
+ja_	 194
+îbas_	 193
+çt	 192
+îbu	 192
+_g	 191
+ï	 189
+ma_	 189
+ien	 188
+kum	 187
+	 187
+_ir	 186
+on	 186
+_ties	 185
+zî	 185
+ce	 185
+ied	 184
+ist	 183
+ts_	 183
+_	 183
+_	 182
+âm	 181
+vie	 180
+__	 180
+cij	 180
+ka_	 179
+_ap	 175
+sî	 174
+ir_	 174
+zi	 174
+uma	 173
+âl	 172
+_ir_	 172
+oð	 171
+_da	 169
+î_	 168
+arî	 168
+)	 167
+do	 166
+ve	 166
+(	 165
+ls	 165
+bu_	 164
+val	 164
+mu_	 164
+isk	 163
+uz	 161
+av	 160
+par_	 160
+_vç	 159
+_par_	 158
+vçr	 158
+_ar_	 157
+rie	 157
+_uz	 157
+aj	 156
+îbu_	 156
+oj	 155
+kâ_	 155
+ld	 154
+iet	 154
+iku	 154
+ks	 153
+du	 153
+ep	 153
+ms_	 152
+ec	 152
+V	 151
+ais	 150
+str	 150
+nie	 149
+am_	 149
+ums	 148
+_(	 147
+ju_	 146
+z_	 142
+ru_	 142
+îj	 142
+gum	 142
+u,_	 141
+u,	 141
+iò	 141
+uma_	 141
+çrt	 141
+îgu	 141
+me	 140
+dâ	 140
+ît	 140
+ent	 139
+ikum	 138
+pâ	 138
+em_	 138
+_L	 138
+lie	 136
+sta	 136
+rî_	 136
+lst	 136
+eik	 135
+se	 135
+s.	 134
+pro	 134
+rs	 134
+s._	 134
+tik	 134
+lç	 134
+ska	 133
+pap	 133
+kas	 133
+rm	 133
+âju	 133
+pî	 132
+nu	 132
+T	 132
+pç	 131
+tei	 131
+nas	 131
+_V	 131
+jo	 131
+lîg	 131
+ut	 131
+iem_	 130
+ras	 129
+pu	 129
+_li	 129
+_ga	 128
+dar	 128
+_kâ	 128
+umu_	 127
+îv	 126
+îgum	 126
+kas_	 126
+tîb	 125
+vai	 125
+lîgu	 125
+P	 125
+arî_	 125
+ev	 124
+lai	 124
+îr	 124
+lîgum	 124
+tv	 123
+að	 123
+_arî_	 122
+_arî	 122
+_vie	 121
+S	 121
+_T	 120
+îju	 120
+teik	 120
+cija	 119
+rb	 119
+_ð	 119
+jâ_	 119
+nas_	 118
+tâj	 118
+vçrt	 118
+iec	 118
+_la	 117
+îd	 116
+_vai	 116
+îjum	 116
+vien	 116
+als	 116
+_lî	 116
+apîr	 115
+rts	 115
+isi	 115
+pîr	 115
+papî	 115
+papîr	 115
+apî	 115
+tsp	 115
+mç	 114
+im	 114
+be	 114
+is_	 114
+alst	 114
+_ja	 114
+rtspa	 113
Index: /main/tags/2.25/gsdl/perllib/textcat/Other/lithuanian.lm
===================================================================
--- /main/tags/2.25/gsdl/perllib/textcat/Other/lithuanian.lm	(revision 21064)
+++ /main/tags/2.25/gsdl/perllib/textcat/Other/lithuanian.lm	(revision 21064)
@@ -0,0 +1,400 @@
+_	 23070
+i	 8196
+a	 7763
+s	 5179
+e	 3458
+o	 3425
+u	 3371
+t	 3344
+r	 3240
+n	 3070
+k	 3019
+l	 2060
+p	 1889
+s_	 1756
+m	 1680
+d	 1640
+v	 1590
+,	 1501
+,_	 1497
+ó	 1400
+g	 1302
+j	 1200
+o_	 1138
+.	 1128
+ai	 1113
+÷	 1075
+_p	 1047
+_k	 1035
+i_	 990
+._	 984
+as	 975
+b	 937
+au	 903
+is	 863
+_n	 815
+ka	 811
+si	 804
+_s	 799
+ia	 796
+ý	 759
+ta	 735
+ie	 731
+ti	 728
+y	 721
+_t	 711
+in	 697
+_i	 686
+us	 675
+pa	 658
+ir	 640
+ar	 633
+ù	 620
+_a	 617
+r_	 609
+ne	 583
+a_	 578
+ri	 569
+_v	 558
+_pa	 541
+al	 540
+ra	 531
+li	 522
+Ý	 509
+u_	 493
+vi	 490
+_ka	 489
+da	 487
+_ne	 482
+_j	 481
+en	 478
+ù_	 445
+os	 444
+ki	 442
+õ	 441
+an	 440
+ik	 434
+ma	 433
+as_	 430
+st	 420
+_d	 420
+ai_	 417
+s,_	 396
+am	 396
+is_	 396
+s,	 396
+_ir	 390
+jo	 387
+ir_	 385
+at	 384
+_ir_	 383
+i÷	 381
+ni	 377
+ga	 376
+_b	 367
+na	 366
+e_	 365
+to	 352
+pr	 337
+_g	 332
+_m	 332
+û	 328
+ß	 326
+io	 323
+ei	 323
+Ý_	 321
+su	 320
+ßi	 320
+uo	 319
+la	 317
+er	 303
+va	 299
+vo	 298
+ýi	 293
+es	 291
+-	 290
+ó_	 286
+-_	 285
+_vi	 284
+_-	 283
+ko	 283
+_-_	 283
+iau	 281
+sa	 278
+s.	 278
+iu	 276
+et	 274
+nu	 265
+ja	 262
+õ_	 262
+_ta	 262
+s._	 259
+el	 258
+ój	 258
+os_	 256
+im	 255
+it	 254
+_pr	 253
+no	 252
+av	 251
+ur	 251
+_÷	 248
+mi	 246
+ve	 245
+ak	 245
+ku	 243
+ek	 241
+tu	 241
+_ý	 241
+ad	 241
+ñ	 238
+_l	 238
+_i÷	 236
+us_	 236
+_su	 232
+oj	 231
+au_	 231
+ba	 224
+nt	 218
+me	 214
+te	 210
+jo_	 208
+ro	 205
+ós	 204
+iù	 203
+tai	 203
+_õ	 201
+ló	 201
+pas	 200
+ip	 198
+iai	 197
+di	 195
+usi	 194
+vo_	 193
+kai	 190
+i,	 189
+i,_	 189
+sk	 187
+_r	 186
+aus	 184
+ap	 183
+gi	 182
+mo	 182
+uk	 181
+t_	 180
+_da	 177
+be	 176
+ien	 176
+o,	 174
+il	 174
+o,_	 173
+ti_	 173
+re	 172
+_nu	 171
+ßia	 171
+_pas	 169
+pri	 169
+÷_	 169
+ok	 168
+dó	 166
+ól	 162
+bu	 161
+÷i	 160
+on	 160
+asi	 159
+id	 158
+ul	 157
+ji	 157
+aip	 156
+ia_	 155
+_sa	 154
+ot	 154
+gal	 153
+nk	 153
+om	 152
+p_	 151
+_pri	 151
+od	 151
+vis	 150
+_at	 150
+vie	 150
+uv	 150
+ab	 150
+iù_	 149
+ama	 149
+nó	 149
+A	 149
+sta	 148
+kr	 148
+_A	 145
+ais	 144
+rt	 143
+J	 142
+_J	 142
+ójo	 142
+_õ_	 141
+K	 140
+_K	 139
+pi	 139
+avo	 139
+ng	 139
+mas	 138
+du	 138
+ug	 137
+_ga	 137
+ol	 136
+tik	 135
+ali	 135
+..	 135
+_vis	 135
+iek	 134
+ini	 133
+kad	 133
+a,	 133
+le	 133
+kó	 133
+T	 133
+tó	 132
+i.	 132
+_T	 131
+dý	 131
+a,_	 131
+go	 131
+ip_	 131
+aip_	 131
+ró	 129
+a÷	 129
+dýi	 129
+ke	 128
+k_	 128
+d_	 127
+ad_	 127
+_ti	 127
+_ma	 126
+_va	 125
+i._	 124
+z	 123
+÷k	 123
+iau_	 121
+m_	 120
+kar	 119
+um	 119
+tù	 119
+_kad	 118
+uý	 117
+tr	 117
+_kai	 117
+as,	 116
+og	 116
+kad_	 116
+as,_	 116
+_ji	 116
+rie	 115
+yt	 114
+_ja	 114
+_ko	 114
+vó	 114
+ys	 114
+jau	 113
+ar_	 113
+pra	 112
+aý	 112
+ant	 112
+kl	 111
+tas	 111
+gu	 111
+_ku	 110
+si_	 110
+pe	 109
+eb	 109
+N	 109
+ójo_	 108
+_kad_	 108
+se	 108
+_ki	 108
+or	 107
+ly	 107
+lo	 107
+iai_	 107
+_la	 106
+ts	 106
+ñs	 106
+ig	 105
+_N	 105
+ut	 105
+_u	 105
+ós_	 105
+avo_	 104
+ie_	 104
+a.	 104
+kt	 104
+em	 103
+do	 103
+je	 102
+ks	 102
+ats	 101
+_be	 101
+ris	 101
+l_	 101
+_vie	 101
+tin	 101
+ag	 100
+dam	 100
+_st	 100
+a._	 99
+_bu	 99
+?	 99
+V	 98
+io_	 98
+kas	 98
+_jo	 98
+vien	 97
+_gal	 97
+ót	 97
+kia	 97
+lia	 96
+c	 96
+uri	 96
+_V	 96
+?_	 96
+uvo	 95
+ru	 95
+ty	 95
+ep	 94
+nd	 94
+lai	 94
+_tai	 94
+ju	 93
+man	 92
+o.	 92
+buv	 92
+tÝ	 92
+_÷i	 91
+i÷_	 91
+_i÷_	 91
+i÷k	 90
+o._	 90
+_to	 90
+bi	 90
+up	 89
+po	 89
+rs	 89
+_prie	 88
+ù,_	 88
+aik	 88
+ui	 88
+_tik	 88
+ij	 88
+ù,	 88
+pat	 88
+prie	 88
+I	 87
+ies	 87
+tai_	 87
+n_	 87
+pasi	 87
+ius	 87
+÷t	 87
+eik	 86
+_me	 86
+ina	 86
Index: /main/tags/2.25/gsdl/perllib/textcat/Other/malay.lm
===================================================================
--- /main/tags/2.25/gsdl/perllib/textcat/Other/malay.lm	(revision 21064)
+++ /main/tags/2.25/gsdl/perllib/textcat/Other/malay.lm	(revision 21064)
@@ -0,0 +1,400 @@
+_	 87128
+a	 50232
+n	 25424
+e	 18746
+i	 18605
+an	 14419
+u	 12470
+k	 11955
+t	 11875
+r	 11007
+d	 9856
+g	 9545
+m	 9390
+s	 8926
+l	 8631
+n_	 8004
+an_	 7095
+p	 6890
+a_	 6739
+b	 6645
+ng	 6630
+h	 5964
+da	 5153
+_d	 5107
+er	 4625
+ka	 4448
+la	 4339
+y	 4323
+i_	 4295
+en	 4159
+ya	 3800
+ang	 3778
+_m	 3750
+o	 3593
+.	 3539
+._	 3310
+at	 3288
+ah	 3216
+_b	 3199
+_s	 3177
+ta	 3076
+ra	 3036
+_k	 2949
+g_	 2939
+ng_	 2933
+ar	 2915
+_p	 2906
+me	 2884
+ga	 2781
+di	 2778
+ak	 2727
+al	 2705
+_me	 2671
+ang_	 2524
+h_	 2509
+ba	 2508
+pa	 2454
+kan	 2449
+in	 2437
+tu	 2411
+_t	 2376
+sa	 2338
+_da	 2276
+j	 2276
+pe	 2225
+,	 2150
+k_	 2147
+ma	 2143
+se	 2138
+am	 2131
+kan_	 2117
+_di	 2082
+,_	 2079
+ke	 2048
+un	 2004
+be	 1947
+_a	 1925
+na	 1871
+ti	 1868
+ri	 1861
+u_	 1857
+as	 1854
+ny	 1827
+ha	 1789
+te	 1788
+_pe	 1768
+em	 1750
+it	 1737
+_i	 1732
+_ke	 1711
+yan	 1706
+ad	 1698
+ia	 1673
+yang	 1673
+_y	 1668
+_ya	 1655
+yang_	 1653
+_se	 1648
+ah_	 1646
+_yan	 1639
+_yang	 1639
+ala	 1612
+nya	 1587
+el	 1576
+ik	 1571
+t_	 1568
+ai	 1549
+men	 1531
+eng	 1522
+_men	 1464
+nga	 1441
+dan	 1366
+_be	 1365
+si	 1343
+uk	 1328
+ada	 1299
+nt	 1291
+__	 1287
+ap	 1276
+ua	 1265
+___	 1238
+-	 1213
+ja	 1211
+ber	 1204
+gan	 1203
+_ba	 1193
+____	 1189
+ni	 1181
+_te	 1169
+c	 1143
+ran	 1141
+_____	 1140
+m_	 1127
+ara	 1118
+per	 1099
+le	 1084
+_dan	 1083
+dan_	 1079
+ngan	 1060
+_dan_	 1050
+ya_	 1046
+at_	 1044
+da_	 1021
+li	 1016
+aka	 1013
+A	 999
+r_	 999
+w	 997
+eb	 995
+lah	 980
+ata	 980
+ak_	 978
+nd	 974
+_ber	 955
+gi	 936
+is	 933
+il	 931
+tu_	 923
+s_	 920
+gan_	 915
+mb	 913
+wa	 904
+ag	 903
+ngan_	 898
+ter	 887
+nya_	 877
+S	 873
+ek	 853
+ru	 852
+_l	 838
+ela	 828
+itu	 824
+ol	 822
+aha	 822
+ada_	 820
+pu	 812
+di_	 807
+bu	 807
+am_	 804
+ur	 801
+tan	 790
+mp	 790
+_per	 786
+_sa	 784
+M	 782
+ut	 781
+us	 779
+era	 779
+lam	 778
+lah_	 775
+asa	 767
+ki	 761
+ir	 759
+de	 756
+enga	 750
+su	 748
+du	 741
+id	 739
+"	 733
+akan	 732
+apa	 728
+_S	 724
+ul	 721
+lu	 717
+ari	 717
+dal	 704
+et	 698
+es	 698
+pad	 688
+_ma	 688
+_M	 685
+ana	 684
+bi	 679
+pada	 673
+dala	 673
+l_	 671
+ep	 664
+f	 662
+_di_	 658
+B	 655
+ing	 655
+_j	 654
+ika	 653
+ku	 650
+_.	 644
+akan_	 642
+ama	 637
+pen	 636
+alam	 634
+eh	 634
+pada_	 633
+ai_	 632
+_ter	 632
+K	 631
+mu	 628
+ju	 628
+P	 626
+mem	 625
+au	 622
+_mem	 614
+lan	 612
+_._	 611
+ntu	 608
+lam_	 605
+um	 601
+on	 600
+gk	 597
+_in	 597
+ngk	 597
+a.	 584
+meng	 582
+_meng	 578
+alam_	 577
+_A	 576
+aa	 575
+uk_	 572
+_pen	 569
+ban	 569
+or	 569
+st	 566
+ay	 566
+dar	 565
+_pa	 564
+a._	 564
+_h	 562
+bah	 562
+_P	 560
+D	 559
+ri_	 558
+ini	 552
+_de	 551
+rt	 550
+aan	 545
+_it	 542
+_itu	 542
+nda	 540
+eri	 540
+dalam	 537
+_B	 533
+_dal	 532
+ip	 532
+_dala	 532
+ta_	 528
+_u	 527
+ung	 525
+ih	 524
+aw	 520
+_n	 519
+atu	 517
+ila	 513
+mi	 513
+leh	 513
+ian	 512
+tuk	 509
+awa	 508
+gu	 506
+ert	 506
+engan	 505
+ole	 504
+_K	 501
+seb	 497
+ca	 496
+gg	 493
+_ta	 489
+ra_	 488
+ngg	 488
+itu_	 487
+emb	 482
+ni_	 482
+ida	 482
+nj	 482
+_ti	 479
+man	 478
+den	 477
+_D	 474
+_ka	 473
+aj	 470
+oleh	 468
+n.	 468
+n._	 464
+ngka	 464
+gka	 464
+dak	 464
+anga	 461
+ena	 459
+san	 458
+pat	 458
+rk	 458
+(	 455
+ent	 454
+agi	 453
+)	 451
+ia_	 450
+ge	 450
+ab	 449
+im	 447
+_ini	 446
+ntuk	 445
+I	 445
+ar_	 440
+N	 439
+aan_	 436
+_la	 433
+pi	 432
+baha	 431
+deng	 430
+han	 430
+bag	 429
+eh_	 429
+hu	 429
+denga	 428
+_o	 427
+na_	 427
+T	 425
+leh_	 422
+_den	 422
+ka_	 419
+any	 415
+ud	 415
+rang	 414
+anya	 413
+gi_	 412
+angan	 412
+a,	 411
+_deng	 410
+ita	 409
+kat	 408
+re	 408
+_(	 406
+tuk_	 403
+aga	 401
+ne	 400
+and	 399
+aya	 398
+_dar	 397
+a,_	 396
+ro	 396
+ntuk_	 393
+eba	 392
+aran	 390
+_"	 387
+ed	 385
+end	 384
+ko	 383
+sa_	 381
+p_	 381
+ara_	 380
+_seb	 379
+alah	 379
+oleh_	 379
+an.	 378
+dak_	 378
+eg	 378
+hi	 376
+dari	 375
+an._	 375
+au_	 373
+bo	 373
+ti_	 371
+ula	 371
Index: /main/tags/2.25/gsdl/perllib/textcat/Other/manx.lm
===================================================================
--- /main/tags/2.25/gsdl/perllib/textcat/Other/manx.lm	(revision 21064)
+++ /main/tags/2.25/gsdl/perllib/textcat/Other/manx.lm	(revision 21064)
@@ -0,0 +1,400 @@
+_	 36004
+e	 9455
+a	 8302
+y	 6395
+n	 6395
+h	 5736
+r	 4939
+s	 4799
+o	 4429
+i	 4129
+l	 3462
+y_	 2896
+g	 2731
+n_	 2549
+d	 2232
+t	 2160
+_a	 1836
+m	 1823
+sh	 1774
+e_	 1746
+h_	 1645
+yn	 1550
+c	 1531
+ee	 1515
+gh	 1461
+s_	 1460
+_s	 1388
+ey	 1345
+_e	 1316
+ag	 1312
+a_	 1201
+r_	 1173
+agh	 1165
+in	 1148
+as	 1136
+_d	 1136
+u	 1124
+he	 1060
+yn_	 1025
+oo	 1012
+ey_	 1005
+_m	 1002
+er	 965
+v	 949
+_y	 941
+_v	 895
+_c	 891
+_as	 880
+'	 869
+,	 866
+_n	 832
+ll	 828
+,_	 827
+_sh	 818
+.	 802
+hi	 797
+as_	 770
+ee_	 768
+ne	 767
+_as_	 764
+b	 762
+re	 735
+ay	 730
+._	 730
+an	 726
+ar	 725
+gh_	 722
+ny	 709
+en	 703
+_r	 697
+ch	 688
+agh_	 687
+dy	 686
+t_	 677
+le	 667
+k	 658
+er_	 616
+oi	 612
+ea	 607
+_t	 601
+yr	 596
+_er	 585
+ra	 574
+_dy	 572
+in_	 570
+l_	 564
+f	 557
+_l	 556
+ha	 551
+_g	 548
+_ny	 534
+nn	 530
+"	 528
+_ch	 527
+_y_	 524
+ie	 514
+dy_	 514
+_dy_	 513
+aa	 510
+_f	 509
+j	 504
+sh_	 487
+oa	 480
+is	 478
+_h	 470
+rr	 468
+ny_	 467
+_ny_	 463
+_er_	 454
+ish	 445
+ho	 442
+ai	 441
+d_	 435
+ro	 423
+ht	 418
+ei	 417
+shi	 416
+il	 409
+me	 408
+_ay	 403
+_b	 403
+la	 400
+_j	 400
+my	 394
+va	 391
+ns	 386
+on	 385
+_o	 381
+ys	 380
+_shi	 379
+ia	 377
+ayn	 373
+_va	 371
+hen	 362
+she	 356
+ri	 345
+lle	 342
+ooi	 342
+mee	 340
+ley	 335
+_me	 331
+el	 330
+rt	 328
+ie_	 327
+eh	 324
+w	 316
+_ayn	 313
+al	 311
+g_	 309
+ish_	 308
+lley	 307
+mee_	 305
+_mee	 304
+ill	 301
+es	 299
+na	 299
+je	 298
+yns	 296
+C	 294
+_my	 291
+_she	 290
+ley_	 282
+V	 280
+_yn	 278
+_"	 278
+_mee_	 277
+ta	 272
+_V	 271
+ys_	 268
+-	 268
+lley_	 265
+hin	 264
+_ro	 259
+shin	 256
+_yn_	 255
+_je	 255
+do	 253
+va_	 253
+ne_	 253
+_va_	 252
+ns_	 252
+_shin	 251
+yns_	 250
+ayns	 248
+en_	 247
+che	 246
+_ayns	 246
+eh_	 246
+_do	 242
+ad	 241
+ney	 240
+o_	 240
+ym	 240
+ed	 239
+yr_	 239
+ayns_	 237
+ur	 237
+st	 234
+_C	 234
+rt_	 234
+'n	 232
+m_	 232
+p	 231
+li	 231
+or	 230
+ow	 228
+hin_	 225
+da	 225
+shen	 223
+"_	 223
+'n_	 223
+Va	 221
+ght	 220
+shin_	 219
+tr	 217
+_Va	 217
+ry	 216
+ve	 216
+_shen	 215
+ty	 214
+mo	 206
+_'	 205
+_ve	 205
+ma	 203
+be	 203
+te	 203
+hie	 203
+hey	 203
+nag	 202
+ll_	 201
+yl	 200
+w_	 200
+ss	 200
+aa_	 198
+nagh	 198
+an_	 197
+io	 195
+ow_	 194
+it	 194
+sy	 193
+ayr	 193
+ney_	 192
+E	 192
+sht	 192
+ni	 191
+_k	 190
+ha_	 190
+ain	 189
+u_	 189
+hy	 189
+aght	 188
+oo_	 188
+ree	 188
+lh	 187
+_tr	 186
+esh	 186
+_che	 183
+yrt	 182
+_da	 182
+oar	 182
+doo	 181
+k_	 181
+se	 180
+au	 180
+ille	 179
+ar_	 179
+_lh	 179
+ki	 177
+arr	 176
+ec	 176
+ol	 175
+_doo	 175
+T	 175
+row	 175
+_row	 174
+ge	 173
+so	 172
+oy	 171
+oil	 170
+_re	 170
+_ag	 170
+'e	 169
+rey	 169
+illey	 169
+ck	 168
+ad_	 168
+ann	 168
+n,	 166
+eea	 166
+_ta	 166
+ht_	 165
+ae	 162
+_row_	 162
+!	 162
+row_	 162
+ane	 161
+fe	 161
+dd	 160
+go	 159
+tyn	 159
+oin	 158
+ooa	 158
+n.	 158
+eg	 156
+_ec	 156
+_ma	 156
+_agh	 155
+n,_	 154
+_fe	 154
+Ch	 154
+nyn	 153
+fo	 152
+eay	 152
+nagh_	 152
+n._	 152
+_go	 151
+S	 150
+ke	 150
+hey_	 150
+enn	 150
+cha	 149
+rre	 149
+_fo	 149
+ghe	 149
+raa	 149
+G	 148
+lan	 148
+mm	 147
+ym_	 147
+A	 146
+c_	 146
+oill	 145
+hee	 144
+ooar	 144
+_E	 144
+nne	 143
+tey	 142
+ir	 141
+de	 141
+hyn	 140
+_he	 140
+nyn_	 140
+'s	 139
+_gh	 139
+_cha	 138
+L	 138
+yrt_	 138
+_Ch	 137
+e,	 137
+lla	 136
+Va_	 136
+ooin	 136
+ell	 135
+a'	 135
+os	 135
+_oo	 134
+am	 134
+rish	 133
+th	 133
+_mo	 133
+ris	 133
+iag	 133
+gg	 133
+_Va_	 132
+iagh	 132
+_G	 132
+e,_	 132
+ass	 132
+!_	 132
+my_	 132
+hoo	 131
+_T	 131
+nee	 130
+a'n_	 129
+rag	 129
+a'n	 129
+_'s	 129
+_so	 128
+co	 128
+rey_	 128
+_eh	 126
+_my_	 126
+nni	 126
+ou	 126
+_'sy	 125
+'sy	 125
+_p	 125
+vo	 125
+_S	 125
+H	 125
+_agh_	 125
+tra	 124
+moo	 124
+hu	 123
+ooy	 123
+ragh	 123
+al_	 123
+it_	 123
+hia	 122
+id	 122
Index: /main/tags/2.25/gsdl/perllib/textcat/Other/marathi.lm
===================================================================
--- /main/tags/2.25/gsdl/perllib/textcat/Other/marathi.lm	(revision 21064)
+++ /main/tags/2.25/gsdl/perllib/textcat/Other/marathi.lm	(revision 21064)
@@ -0,0 +1,400 @@
+þ	 17815
+_	 14534
+þþ	 4035
+þ_	 3087
+·	 2180
+ø	 1762
+·þ	 1669
+ú	 1654
+¡	 1534
+¥	 1480
+¡þ	 1433
+Å	 1342
+£	 1289
+	 1237
+	 1163
+­	 1158
+¬	 1153
+þþ_	 1133
+¿	 1099
+š	 1084
+	 1062
+	 1059
+ú_	 1054
+¥þ	 1054
+Å	 1050
+¡þþ	 1039
+þú	 989
+	 983
+þ	 968
+	 965
+¹	 949
+_	 936
+.	 936
+šþ	 915
+þ¿	 859
+þ£	 842
+¬þ	 838
+þ	 836
+þ·	 769
+þ	 764
+µ	 710
+þ¥	 710
+þ	 684
+þ·þ	 681
+._	 670
+þú_	 637
+œ	 609
+þ	 578
+_	 578
+_þ	 569
+_	 543
+þ	 530
+_·	 530
+µþ	 524
+_	 523
+	 511
+	 504
+ø_	 495
+·þ_	 477
+þ¥þ	 476
+þ­	 474
+_¹	 474
+_¬	 457
+_Å	 447
+_þ	 447
+¡þþ_	 446
+þø	 444
+ž	 438
+þ	 423
+¥þþ	 422
+þ	 409
+þš	 388
+Åþ	 387
+þþ	 381
+£_	 366
+Åþ	 359
+é	 339
+þšþ	 334
+_¬þ	 332
+þµ	 331
+þ	 324
+þþ	 320
+_þ	 320
+þþ	 318
+ª	 315
+_­	 315
+þ_	 314
+Û	 313
+þ¹	 306
+þ£_	 303
+þ¬	 301
+þ	 297
+	 297
+þþ	 295
+ªþ	 284
+þ¡	 280
+§	 274
+¿_	 272
+þþ·	 270
+þ¡þ	 268
+¥þþ_	 268
+£þ	 264
+þ	 264
+­ú	 263
+,	 258
+þþ·þ	 256
+þ¥þþ	 256
+þ·þ_	 256
+,_	 255
+þÅ	 255
+Ù	 249
+¬þþ	 247
+þþ¿	 243
+þþ£	 241
+_	 234
+_·þ	 233
+·þþ	 232
+þ	 232
+·¡	 231
+þ¿_	 231
+þþ	 230
+þ¬þ	 228
+Ä	 227
+	 226
+þµþ	 225
+œ_	 223
+·¡þ	 221
+­œ	 220
+_	 220
+¥ø	 219
+µþ_	 218
+šþþ	 217
+þ.	 216
+þ	 215
+_þ	 213
+..	 209
+_þþ	 209
+þþþ	 205
+þþ	 205
+·¡þþ	 204
+	 204
+·þú	 203
+þ¥þþ_	 202
+Å_	 202
+þþ¥	 201
+ê	 198
+_š	 198
+þ	 193
+_¡	 191
+þþ	 190
+þ._	 189
+¡þ	 188
+¡	 188
+¡þþ	 187
+Ï	 186
+ø·	 186
+	 185
+­ú_	 180
+þ_	 180
+_þ	 180
+þ	 179
+Ú	 178
+_Åþ	 176
+_·¡þ	 175
+_·¡þþ	 175
+­þ	 175
+_·¡	 175
+þþ	 174
+þ­ú	 171
+¥¡	 170
+_	 170
+...	 168
+¥¡þ	 167
+þú	 166
+_¥	 164
+þþ	 164
+þ­	 163
+¥¡þþ	 163
+þ	 162
+ø·þ	 162
+_þ­	 162
+¡þþ_	 161
+­ø	 160
+Å_	 159
+þþ¥þ	 159
+þ­œ	 157
+þþ	 154
+þ	 154
+_þ	 154
+_ž	 154
+ø¥	 153
+þþ	 153
+þ	 151
+þ£þ	 151
+_	 151
+þ­œ	 150
+þ§	 150
+·ø	 150
+ø.	 149
+_þ­œ	 149
+¬	 148
+¥þú	 148
+£ú	 147
+Ï	 147
+Å£	 146
+þú_	 146
+_¬	 145
+ø._	 145
+þþš	 144
+þÄ	 143
+	 142
+	 140
+¡þþ	 140
+¹šþ	 139
+¹š	 139
+þþ­	 137
+þþ	 136
+_­ø	 136
+­	 136
+_¡þ	 135
+ú.	 135
+·þø	 135
+'	 135
+Å£	 134
+_¥þ	 132
+þþšþ	 131
+þþ·þ_	 131
+µþþ	 129
+'_	 129
+_þþ	 129
+ú._	 128
+þÛ	 127
+....	 127
+	 127
+¿	 126
+þþ¬	 125
+_šþ	 124
+¡þ_	 123
+þ·þþ	 123
+«	 122
+;	 122
+_Ï	 121
+_¡þþ	 119
+»	 118
+¬þ¿	 115
+¥þ¿	 114
+¥þ_	 114
+þþ	 113
+þ¥¡þ	 113
+þ¥¡	 113
+b	 113
+þ£ú	 112
+_'	 112
+s	 111
+&	 111
+þþ	 111
+¬þ	 111
+þþú	 111
+p	 111
+ê	 111
+_£	 110
+þ¥¡þþ	 110
+bs	 109
+êþ	 109
+n	 109
+º	 109
+_¬þ	 108
+&n	 107
+bsp;	 107
+nbsp;	 107
+sp;	 107
+nb	 107
+bsp	 107
+nbs	 107
+sp	 107
+nbsp	 107
+&nb	 107
+&nbsp	 107
+p;	 107
+&nbs	 107
+þþþ	 106
+_'_	 106
+þ¥ø	 106
+·þ£	 106
+ø¥þ	 106
+þþ_	 105
+šþ£	 104
+þ¿	 104
+þ	 104
+þž	 104
+_þ	 103
+þ¬þþ	 103
+ø	 103
+­ø·	 102
+þþþ	 101
+þþ­ú	 100
+þþþ	 99
+þ,	 99
+_	 98
+þ,_	 98
+_Å£	 98
+þ	 98
+þþú_	 98
+_þþ	 97
+;&	 97
+_þ	 97
+þþ	 97
+_þþ	 96
+þ	 96
+¡þþþ	 96
+¬þ·	 96
+	 96
+;&nb	 95
+p;&nb	 95
+;&n	 95
+p;&	 95
+;&nbs	 95
+bsp;&	 95
+.....	 95
+êþ_	 95
+sp;&n	 95
+sp;&	 95
+p;&n	 95
+°	 94
+_	 94
+	 94
+¥¡þþ_	 94
+þþ¬þ	 93
+þú	 93
+þµþ_	 93
+£ú_	 93
+þµ	 93
+_	 92
+µ¡	 92
+_­ø·	 92
+þ­ú_	 92
+µ¡þ	 92
+·þú_	 91
+¹­	 91
+­œ_	 90
+_¬þþ	 90
+_þþ	 90
+þþ¥þþ	 90
+	 90
+µ¡þþ	 90
+þ	 89
+¹·	 89
+þ¡þ	 89
+þ£ú_	 89
+þÚ	 89
+þ¡	 89
+þÅþ	 89
+¿	 89
+þþ	 89
+_­	 88
+œÅ	 88
+þ¡þþ	 88
+_¹š	 88
+_¹šþ	 88
+­ø·þ	 87
+ø	 87
+œ	 87
+þþ­ú	 87
+_	 87
+­µ	 87
+þþ­	 87
+þµþ	 86
+¥þú_	 86
+_þ¹	 85
+þ¹	 85
+£·	 85
+_	 85
+¹·þ	 85
+_þþ­	 84
+¡ø	 84
+þ¹µþ	 83
+þþµ	 83
+¹µþ	 83
+¹µ	 83
+þ¹µ	 83
+þþ_	 83
+_ª	 82
+_þ¹µ	 82
+þ¹µþ_	 82
+þþ_	 82
+þ¹µþ	 82
+þ¹µ	 82
+þú_	 82
+_þ	 82
+¹µþ_	 82
+þþ£_	 81
+ø	 81
+œ._	 80
+¿þ	 80
+_·þ£	 80
+œ.	 80
+ú	 79
+_þ	 79
+þµþ_	 79
+²	 79
Index: /main/tags/2.25/gsdl/perllib/textcat/Other/middle_frisian.lm
===================================================================
--- /main/tags/2.25/gsdl/perllib/textcat/Other/middle_frisian.lm	(revision 21064)
+++ /main/tags/2.25/gsdl/perllib/textcat/Other/middle_frisian.lm	(revision 21064)
@@ -0,0 +1,400 @@
+_	 60524
+e	 20138
+n	 10664
+t	 8674
+i	 7833
+a	 7549
+o	 7278
+r	 6963
+n_	 5391
+s	 5087
+d	 4731
+t_	 4327
+l	 4306
+e_	 4271
+en	 4068
+k	 3483
+m	 3346
+g	 2990
+er	 2965
+en_	 2835
+y	 2597
+w	 2481
+h	 2475
+j	 2441
+_d	 2375
+r_	 2250
+u	 2059
+s_	 1921
+ie	 1780
+_h	 1725
+z	 1710
+de	 1666
+_m	 1652
+_w	 1629
+_i	 1611
+et	 1550
+te	 1540
+b	 1538
+.	 1517
+er_	 1481
+in	 1420
+an	 1408
+p	 1392
+f	 1311
+,	 1280
+,_	 1273
+k_	 1266
+._	 1258
+y_	 1238
+_z	 1230
+oe	 1162
+v	 1144
+et_	 1138
+ne	 1131
+ee	 1125
+st	 1120
+_o	 1107
+_s	 1107
+_e	 1076
+_n	 1068
+_b	 989
+_t	 988
+l_	 983
+oo	 981
+ge	 975
+je	 963
+_g	 952
+at	 949
+me	 946
+ij	 943
+is	 913
+he	 899
+'	 892
+aa	 882
+el	 870
+_v	 864
+re	 843
+ar	 837
+_de	 805
+on	 800
+ke	 796
+de_	 788
+ei	 782
+_a	 776
+_'	 770
+le	 744
+at_	 742
+it	 741
+_k	 738
+or	 734
+an_	 729
+in_	 723
+da	 715
+te_	 703
+_he	 680
+_l	 664
+H	 661
+al	 652
+_H	 652
+a_	 650
+_da	 648
+D	 648
+d_	 646
+_D	 643
+es	 617
+g_	 608
+is_	 606
+æ	 596
+_f	 594
+'t	 591
+_'t	 584
+'t_	 583
+_me	 580
+c	 576
+_'t_	 576
+ri	 571
+_en	 564
+yn	 563
+_en_	 559
+ze	 538
+m_	 535
+om	 535
+ik	 522
+_de_	 522
+ed	 521
+be	 517
+wi	 509
+ch	 509
+ol	 498
+ar_	 498
+ha	 496
+_ne	 495
+we	 494
+ou	 486
+nd	 474
+ma	 474
+ik_	 470
+J	 459
+_ik	 456
+_ik_	 451
+_J	 451
+ll	 450
+M	 446
+li	 443
+wa	 442
+_M	 442
+ien	 435
+ro	 432
+di	 421
+nn	 418
+ste	 415
+wo	 415
+yn_	 415
+_r	 413
+_ha	 411
+it_	 409
+tt	 408
+ve	 407
+S	 404
+_j	 399
+_S	 398
+_in	 395
+as	 395
+der	 395
+hi	 389
+_al	 388
+uw	 384
+tte	 384
+ng	 381
+_wi	 381
+nne	 381
+het	 380
+_het	 378
+lle	 376
+nt	 374
+ns	 373
+op	 373
+je_	 367
+E	 366
+ek	 363
+B	 363
+dat	 362
+_B	 362
+_ma	 362
+_in_	 361
+_dat	 359
+_wo	 359
+ier	 358
+og	 357
+_E	 354
+_ge	 352
+dat_	 349
+ne_	 349
+eer	 349
+het_	 348
+_het_	 348
+_is	 348
+_dat_	 348
+ey	 347
+W	 346
+_W	 343
+_te	 339
+eg	 337
+ra	 335
+rs	 335
+!	 332
+zi	 332
+gt	 329
+_He	 327
+He	 327
+_be	 324
+j_	 320
+ij_	 320
+u_	 319
+f_	 317
+_di	 316
+;	 315
+_we	 315
+_is_	 314
+rt	 313
+!_	 313
+;_	 312
+n.	 311
+p_	 310
+la	 310
+_wa	 310
+ea	 308
+_u	 308
+pe	 304
+ta	 304
+il	 301
+my	 300
+ig	 300
+n,	 300
+n,_	 298
+iet	 297
+sc	 297
+ter	 296
+sch	 296
+oor	 295
+no	 294
+_my	 293
+n._	 291
+ti	 290
+_zi	 289
+st_	 288
+el_	 283
+gen	 282
+se	 280
+K	 279
+_oo	 278
+ui	 278
+e,	 275
+ten	 274
+net	 274
+oon	 274
+ho	 274
+jn	 273
+e,_	 273
+ijn	 272
+ien_	 272
+ko	 272
+N	 271
+ni	 271
+_N	 269
+den	 269
+za	 268
+_net	 267
+i_	 266
+wol	 266
+een	 264
+va	 264
+am	 264
+do	 263
+ol_	 262
+le_	 261
+_te_	 260
+rd	 260
+ke_	 259
+ey_	 259
+ers	 258
+_K	 255
+_ie	 255
+ver	 254
+to	 254
+_hi	 253
+nde	 253
+:	 253
+der_	 252
+jo	 251
+net_	 251
+al_	 250
+_wol	 250
+_p	 250
+_no	 250
+aar	 248
+_za	 245
+_net_	 245
+nk	 242
+est	 241
+om_	 241
+_va	 241
+ak	 241
+tj	 239
+ae	 238
+_op	 237
+mo	 236
+tr	 236
+_st	 233
+ier_	 233
+_ve	 233
+mm	 232
+T	 231
+eu	 229
+_ze	 228
+:_	 228
+mi	 228
+ag	 227
+zo	 227
+_ko	 226
+vo	 225
+_T	 225
+nne_	 225
+F	 224
+..	 224
+fo	 224
+_F	 223
+en,	 223
+oe_	 222
+wie	 222
+en,_	 221
+kk	 221
+_ien	 220
+on_	 218
+wol_	 218
+_fo	 218
+I	 217
+_do	 216
+eit	 214
+ei_	 214
+mme	 214
+G	 213
+_I	 213
+as_	 213
+or_	 211
+A	 211
+_G	 210
+_A	 210
+lle_	 209
+Da	 208
+_Da	 207
+_wol_	 207
+ren	 206
+_ee	 206
+e.	 205
+van	 205
+jen	 205
+een_	 205
+_van	 204
+kke	 204
+en.	 204
+O	 204
+_vo	 204
+V	 203
+_O	 203
+_V	 203
+ken	 203
+_mo	 203
+ot	 202
+ie_	 201
+ou_	 201
+ur	 201
+tte_	 200
+em	 200
+_van_	 199
+L	 199
+van_	 199
+_zo	 199
+op_	 199
+_L	 197
+iet_	 196
+of	 194
+ten_	 194
+oer	 193
+_ien_	 193
+e._	 193
+oed	 192
+hie	 192
+zy	 191
+en._	 191
+De	 191
+_ver	 191
+_ho	 189
+_De	 189
+oa	 189
+den_	 188
+_zy	 188
+lo	 187
+dan	 187
+nt_	 186
Index: /main/tags/2.25/gsdl/perllib/textcat/Other/mingo.lm
===================================================================
--- /main/tags/2.25/gsdl/perllib/textcat/Other/mingo.lm	(revision 21064)
+++ /main/tags/2.25/gsdl/perllib/textcat/Other/mingo.lm	(revision 21064)
@@ -0,0 +1,400 @@
+_	 3156
+'	 991
+a	 829
+t	 788
+k	 788
+n	 752
+e	 640
+h	 602
+ë	 551
+s	 495
+w	 466
+ö	 422
+y	 403
+u	 397
+'_	 368
+_n	 330
+i	 269
+.	 269
+._	 240
+e'	 238
+ô	 219
+a'	 209
+ne	 209
+e_	 194
+_ne	 184
+wa	 172
+_k	 164
+kw	 162
+á	 154
+e'_	 146
+_t	 145
+'t	 141
+"	 141
+ë'	 134
+ê	 132
+_h	 131
+é	 129
+ak	 129
+ne_	 126
+ta	 123
+_ne_	 123
+at	 121
+u'	 121
+hu	 118
+_u	 108
+ka	 107
+í	 106
+nö	 105
+N	 103
+ö'	 100
+hs	 95
+ha	 95
+te	 94
+ya	 93
+_ë	 92
+kh	 90
+'k	 86
+ú	 85
+æ	 84
+ni	 84
+'.	 84
+wë	 83
+ny	 83
+sh	 80
+_N	 80
+'._	 76
+ö_	 76
+kë	 72
+_"	 71
+ën	 70
+th	 69
+yu	 66
+_w	 66
+ëh	 66
+t_	 66
+ô_	 66
+Ne	 65
+Ne'	 65
+'s	 64
+ne'	 64
+"_	 64
+_.	 63
+_._	 61
+Ne'_	 61
+,	 60
+ne'_	 58
+në	 58
+kwa	 57
+_ne'	 57
+öt	 57
+a't	 57
+ek	 56
+s_	 56
+ët	 55
+i'	 55
+_hu	 54
+T	 54
+ë_	 54
+_s	 54
+_Ne	 53
+të	 53
+tö	 53
+_Ne'	 53
+_ne'_	 53
+ht	 53
+-	 53
+ts	 52
+ya'	 52
+ë'_	 51
+_wa	 51
+_Ne'_	 51
+'ö	 50
+íy	 50
+_ka	 50
+as	 50
+ní	 49
+un	 49
+ê_	 49
+ty	 48
+hu_	 48
+ke	 48
+u_	 48
+,_	 47
+yô	 46
+he	 46
+ye	 46
+kê	 45
+si	 45
+nô	 44
+khu	 44
+a'k	 44
+_a	 43
+ák	 43
+wat	 42
+'ë	 42
+nö'	 42
+wá	 42
+aw	 41
+an	 41
+we	 41
+ôt	 41
+i_	 41
+_kh	 41
+tak	 41
+_te	 41
+ik	 41
+_khu	 40
+ës	 40
+yö	 40
+k_	 39
+khu_	 39
+yu'	 38
+hö	 38
+wën	 38
+n-	 38
+ëhs	 38
+_ha	 38
+wa'	 38
+_n-	 37
+sa	 37
+?	 37
+_T	 37
+æ'	 37
+_un	 36
+hô	 36
+wé	 36
+ah	 36
+_khu_	 35
+iy	 35
+ëk	 35
+ut	 35
+ök	 35
+öh	 35
+te'	 35
+u'_	 35
+_kë	 34
+yô_	 34
+ha'	 34
+st	 34
+ti	 34
+ta'	 34
+u't	 33
+ya't	 33
+'t_	 33
+'ö_	 33
+akw	 33
+ôk	 33
+níy	 32
+'ta	 32
+ku	 32
+ui	 32
+_sh	 32
+aa	 31
+én	 31
+ay	 31
+ënö	 31
+â	 30
+se	 30
+tw	 30
+yë	 30
+(_	 29
+_(_	 29
+_)_	 29
+us	 29
+_ëhs	 29
+(	 29
+kö	 29
+_ëh	 29
+ae	 29
+hë	 29
+_)	 29
+)_	 29
+_(	 29
+sy	 29
+)	 29
+ëë	 28
+ôn	 28
+sk	 28
+tá	 28
+té	 28
+tk	 28
+ên	 28
+kê_	 28
+a_	 28
+án	 27
+_huik	 27
+ön	 27
+_hui	 27
+kwé	 27
+huik	 27
+ék	 27
+hui	 27
+uik	 27
+_na	 27
+na	 27
+a'_	 26
+uikê	 26
+_ni	 26
+."	 26
+ææ	 26
+wi	 26
+huikê	 26
+ikê	 26
+nya	 25
+."_	 25
+?"	 25
+të'	 25
+íyu	 25
+awë	 25
+sn	 25
+në_	 24
+ö'_	 24
+ikê_	 24
+ekh	 24
+'ke	 24
+uikê_	 24
+?"_	 24
+tek	 24
+êt	 24
+',	 24
+"N	 23
+_ta	 23
+'a	 23
+hk	 23
+tê	 23
+tsi	 23
+wö	 23
+yu'_	 23
+_"N	 23
+íyu'	 23
+níyu	 23
+a'ta	 23
+é'	 23
+níyu'	 23
+shô	 22
+wëní	 22
+kwa'	 22
+ëní	 22
+kwë	 22
+_u'	 22
+ey	 22
+ëníyu	 22
+K	 22
+ai	 22
+_shô	 22
+úw	 22
+aö	 22
+ëht	 22
+ëníy	 22
+kwe	 22
+wëníy	 22
+_he	 22
+_te'	 21
+ún	 21
+s.	 21
+nöh	 21
+ëö	 21
+_ëk	 21
+'sh	 21
+kë'	 21
+htö	 21
+H	 21
+ata	 21
+U	 20
+'h	 20
+_ha'	 20
+ææ'	 20
+ae_	 20
+a'ke	 20
+ény	 20
+unö	 20
+we'	 20
+wë'	 20
+i'_	 20
+kës	 20
+ya'ta	 19
+es	 19
+awëní	 19
+hô_	 19
+uk	 19
+awën	 19
+hw	 19
+ë'.	 19
+ô'	 19
+tö'	 19
+sé	 19
+ë'ë	 19
+ë'._	 19
+'ëë	 19
+hkw	 19
+-a	 19
+twa	 19
+'kw	 18
+he_	 18
+_K	 18
+nöt	 18
+hsa	 18
+hsi	 18
+ôni	 18
+aya	 18
+is	 18
+ëë'	 18
+kæ	 18
+skw	 18
+uw	 18
+',_	 18
+e't	 18
+kææ	 18
+ka'	 18
+nae	 17
+shô_	 17
+sat	 17
+niy	 17
+ëts	 17
+ath	 17
+ye'	 17
+í_	 17
+'ëë'	 17
+'u	 17
+_ët	 17
+ës_	 17
+_kës	 17
+_y	 17
+kak	 17
+ö'ö	 17
+kat	 17
+_th	 17
+'ë_	 17
+út	 17
+u'k	 17
+_H	 17
+tekh	 17
+s._	 17
+wê	 17
+_nae	 17
+kwá	 17
+_shô_	 17
+yê	 17
+öte	 16
+sha	 16
+ke_	 16
+k.	 16
+si'	 16
+hö'	 16
+yá	 16
+hta	 16
+kn	 16
+_nae_	 16
+hse	 16
+ké	 16
+ë'ë_	 16
+unë	 16
+nya'	 16
+nae_	 16
+nê	 16
+á'	 16
+ás	 16
+tô	 16
+a's	 16
+a'u	 16
Index: /main/tags/2.25/gsdl/perllib/textcat/Other/nepali.lm
===================================================================
--- /main/tags/2.25/gsdl/perllib/textcat/Other/nepali.lm	(revision 21064)
+++ /main/tags/2.25/gsdl/perllib/textcat/Other/nepali.lm	(revision 21064)
@@ -0,0 +1,400 @@
+_	 7044
+f	 2698
+]	 1196
+g	 933
+s	 815
+l	 781
+/	 698
+;	 662
+k	 645
+d	 635
+]_	 630
+f_	 611
+sf	 549
+f]	 541
+n	 526
+t	 460
+o	 412
+j	 399
+f]_	 374
+L	 365
+_;	 364
+x	 356
+_k	 353
+{	 337
+b	 323
+u	 321
+'	 303
+df	 299
+sf]	 290
+_l	 283
+sf]_	 265
+g]	 245
+G	 232
+e	 231
+|	 227
+a	 222
+/_	 222
+L_	 211
+_g	 210
+c	 207
+df_	 207
+{_	 207
+_c	 201
+g_	 201
+kf	 184
+f/	 177
+_u	 171
+/f	 168
+P	 163
+_/	 162
+k|	 161
+_s	 161
+}	 159
++	 158
+h	 151
+fn	 150
+n]	 145
+of	 141
+tf	 140
+:	 136
+p	 136
+t_	 134
+.	 133
+_k|	 133
+._	 133
+_e	 131
+_d	 131
+_f	 129
+_._	 127
+_.	 127
+n]_	 123
+;f	 119
+lj	 118
+O	 118
+?	 118
+q	 118
+nf	 118
+y	 116
+_a	 113
+m	 111
+Ps	 110
+r	 110
+fg	 106
+w	 105
+sf_	 103
+lg	 102
+g]_	 100
+gf	 94
+_g]	 91
+Psf	 90
+x?	 89
+fd	 88
+fO	 88
+_lj	 85
+]s	 85
+z	 85
+s_	 84
+_p	 82
+_sf	 80
+D	 79
+kl	 78
+_;f	 78
+f/_	 77
+cf	 77
+}_	 76
+Psf]	 76
+jf	 76
+,	 75
+fl	 75
+\	 75
+_x	 74
+kfn	 74
+f{	 74
+_/f	 74
+]k	 73
+of]	 73
+,_	 72
+v	 72
+lt	 72
+_cf	 72
+_b	 71
+O{	 70
+i	 69
+xf	 68
+]kf	 68
+_/_	 68
+Psf]_	 68
+_h	 67
+g]kfn	 67
+g]k	 67
+d_	 67
+g]kf	 67
+O{_	 67
+]kfn	 67
+_g]k	 66
+g'	 66
+_g]kf	 66
+o_	 64
+"	 64
+;b	 63
+Gq	 63
+f+	 63
+n_	 63
+fk	 62
+sf/	 62
+/L	 62
+_kl	 62
+I	 61
+T	 61
+/s	 61
+If	 61
+dG	 60
+_j	 60
+]sf	 60
+;_	 59
+u_	 59
+yf	 59
+dGq	 58
+fO{	 58
+af	 57
+eP	 57
+fs	 57
+fO{_	 57
+fj	 56
+f;	 56
+qL	 56
+l/	 55
+\_	 55
+;D	 54
+dGqL	 54
+GqL	 54
+;+	 53
+g\	 53
+/sf	 52
+nfO	 51
+_kf	 51
+ug	 51
+pg	 51
+:t	 51
+fp	 50
+_ug	 50
+u/	 50
+lg_	 49
+ePs	 49
+fdf	 48
+cl	 48
+nfO{_	 48
+nfO{	 48
+;/	 48
+_cl	 47
+F	 47
+'/	 47
+g\_	 47
+_r	 47
+fo	 47
+_eP	 47
+]{	 46
+Z	 46
+/L_	 46
+_f_	 45
+ePsf	 45
+gd	 45
+_;D	 45
+if	 45
+Gb	 44
+lb	 44
+Q	 44
+_n	 44
+fsf	 44
+]sf]	 43
++;	 43
+nL	 43
+lx	 43
+_t	 43
+_:	 42
++;b	 42
+_o	 42
+fdf_	 42
+bf	 42
+hf	 42
+_lg	 42
+ePsf]	 41
+j_	 41
+ln	 41
+ef	 41
+/]	 41
+_df	 41
+To	 40
+klg_	 40
+_klg_	 40
+]sf]_	 40
+klg	 40
+_klg	 40
+_u/	 40
+f{_	 40
+_ePs	 40
+'g	 40
+Gg	 39
+:y	 39
+_g\	 39
+f}	 39
+kf_	 39
+:tf	 38
+]{_	 38
+fpg	 38
+b'	 38
+hg	 38
+g]{	 38
+jZ	 38
+_;+	 37
+gs	 37
+wf	 37
+o{	 37
+GqL_	 37
+l_	 37
+qL_	 37
+dGqL_	 37
+gf_	 37
+];	 37
+_ePsf	 36
+x'	 36
+?_	 36
+!	 36
+fx	 35
+u|	 34
+;d	 34
+_lb	 34
+fn_	 34
+_P	 34
+fg_	 34
+=	 34
+bn	 34
+Zj	 34
+o;	 34
+g]{_	 34
+_g\_	 34
+kIf	 33
+dl	 33
+kI	 33
+ljZj	 33
+jZj	 33
+rf	 33
++u	 33
+]d	 33
+ljZ	 33
+nL_	 32
+f+;	 32
+fnL	 32
+gL	 32
+;/sf	 32
+tf_	 32
+wfg	 32
+_;/	 32
+Qm	 32
+fb	 32
+f;_	 32
+ld	 32
+;/sf/	 32
+/sf/	 32
+_x'	 32
+;/s	 32
+;f+	 32
+_;f+	 32
+fu	 32
+x?_	 32
+;f+;	 31
+_k|:t	 31
+s'	 31
+_kI	 31
+_k|:	 31
+of]_	 31
+_kIf	 31
+_;f+;	 31
+]l	 31
+k|:	 31
+bg	 31
+_;/s	 31
+|:	 31
+f+;b	 31
+_;/sf	 31
+|:t	 31
+|]	 31
+k|:t	 31
+m_	 31
+;f+;b	 31
+Jo	 30
+k|wf	 30
+|w	 30
+|wf	 30
+k|w	 30
+km	 30
+J	 30
+k|wfg	 30
+|wfg	 30
+]t	 30
+@	 30
+;f]	 30
+b_	 29
+>	 29
+kfn_	 29
+fn]	 29
+gsf	 29
+sf+	 29
+Zjf	 29
+]kfn_	 29
+jif	 29
+ji	 29
+jf;	 29
+_k|w	 29
+fgd	 29
+_k|wf	 29
+Zjf;	 29
+ljZjf	 28
+jZjf;	 28
+]n	 28
+_z	 28
+_s'	 28
+_dG	 28
+|];	 28
+_;d	 28
+jZjf	 28
+u|]	 27
+gdGq	 27
+gdG	 27
+?n	 27
+x'g	 27
+|wfgd	 27
+wfgd	 27
+gdGqL	 27
++u|]	 27
+f+u	 27
+fgdG	 27
+u|];	 27
++u|];	 27
+wfgdG	 27
+dfg	 27
+a}	 27
+_dGq	 27
+f+u|	 27
+fgdGq	 27
+sf+u|	 27
+_sf+u	 27
+f+u|]	 27
++u|	 27
+sf+u	 27
+_sf+	 27
+x?n	 27
+S	 26
+_To	 26
+]kfnL	 26
+_!	 26
+_T	 26
+ul	 26
+/f]	 26
+fsf]	 26
+af_	 26
+;s	 26
+kfnL	 26
+|:tf	 26
+k|:tf	 26
Index: /main/tags/2.25/gsdl/perllib/textcat/Other/persian.lm
===================================================================
--- /main/tags/2.25/gsdl/perllib/textcat/Other/persian.lm	(revision 21064)
+++ /main/tags/2.25/gsdl/perllib/textcat/Other/persian.lm	(revision 21064)
@@ -0,0 +1,400 @@
+_	 12318
+?	 5938
+€	 2613
+?_	 1815
+¢	 1745
+þ	 1569
+ø	 1546
+õ	 1422
+-	 1333
+÷	 1155
+ù	 991
+š	 841
+_ù	 778
+ö	 761
+î	 693
+ü	 664
+_ö	 663
+ª	 660
+€?	 631
+õ_	 624
+_?	 601
+?€	 598
+¥	 589
+_€	 565
+??	 564
+ý	 513
+¢_	 486
+_ü	 473
+_ý	 469
+þ?	 459
+û	 428
+ø_	 427
+_¢	 398
+î_	 392
+ó	 390
+ê	 384
+ö?	 379
+÷?	 361
+_ø	 337
+_-	 334
+>	 327
+ú	 324
+_ö?	 319
+ù?	 313
+_ø_	 308
+ð	 305
+€¢	 303
+€_	 297
+?õ	 290
+š?	 285
+¢÷	 272
+-_	 271
+S	 266
+_ù?	 265
+ô	 259
+-š	 255
+¡	 255
+??_	 255
+ý?	 254
+¥?	 250
+Y	 246
+€¢_	 245
+ì	 243
+_ý?	 238
+?¢	 234
+_¥	 229
+ò	 229
+_S	 228
+€ø	 216
+ø€	 215
+?þ	 215
+?š	 214
+_€¢	 214
+ñ	 208
+þ?_	 207
+¢€	 203
+?-	 202
+_ô	 199
+ù?_	 199
+öþ	 195
+š_	 190
+š?_	 190
+_??	 189
+õ?	 188
+.	 188
+_€¢_	 185
+_ñ	 183
+?ø	 181
+_öþ	 180
+¢?	 177
+*	 176
+÷_	 176
+_ù?_	 174
+?û	 173
+€þ	 172
+ª_	 170
+þõ	 164
+ä	 161
+¯	 158
+-š?	 156
+û_	 155
+€?_	 155
+_¥?	 152
+üõ	 151
+ý€	 150
+_€?	 146
+¥?_	 144
+þ€	 143
+¢ø	 141
+?€_	 140
+*_	 138
+ü÷	 137
+?÷	 136
+¬	 133
+ùî	 132
+_ý€	 131
+-ª	 131
+ø?	 130
+?ú	 129
+_.	 129
+þó	 129
+¡_	 128
+ù¢	 124
+€õ	 121
+€-	 120
+ùî_	 120
+_ùî	 120
+_??_	 119
+ª?	 119
+-š?_	 119
+ã	 118
+-?	 118
+>_	 116
+öþ?	 114
+ê_	 111
+¢þ	 109
+_¥?_	 109
+_ü÷	 109
+_ùî_	 108
+_öþ?	 107
+ö?€	 107
+©	 106
+_¢÷	 106
+.¢	 104
+?¥	 103
+_?€	 103
+€ê	 103
+ó?	 103
+þ¢	 103
+ñ?	 102
+ªî	 100
+?î	 100
+?€?	 98
+ð_	 98
+ý?û	 96
+€ú	 95
+öþ?_	 95
+_©	 94
+§	 94
+Y_	 94
+_ö?€	 93
+_ý?û	 93
+¥ø	 92
+øª	 91
+_ñ?	 91
+_öþ?_	 91
+?š_	 90
+÷?_	 90
+óþ	 90
+õ?_	 90
+ü-	 90
+øõ	 89
+:	 89
+ªî_	 88
+ü÷?	 88
+öø	 88
+_ù¢	 87
+-ê	 86
+þ÷	 85
+_öø	 83
+,	 82
+þõ_	 82
+þš	 82
+?¢_	 80
+®	 80
+?€þ	 79
+_ü÷?	 79
+¢ª	 77
+???	 77
+øþ	 76
+_-?	 75
+÷î	 75
+?ª	 75
+?ì	 75
+€î	 74
+_€ø	 73
+ä_	 73
+þóþ	 73
+û?	 73
+óþõ	 72
+þóþõ	 71
+ù€	 71
+?>	 71
+ê?	 70
+_?€_	 70
+_.¢	 70
+ø¡	 69
+à	 69
+_§	 68
+¥ø€	 68
+þóþõ_	 67
+_ü-	 67
+€øª	 67
+óþõ_	 67
+õû	 67
+€ê_	 67
+šõ	 67
+€õ_	 66
+?-_	 65
+ù÷	 65
+ý?€	 65
+öøþ	 64
+€þ?	 64
+¬_	 64
+?ð	 63
+?-š	 63
+ø-	 63
+_ý?€	 62
+ø?_	 62
+ø€_	 62
+_-š	 61
+õþ	 61
+øþóþõ	 60
+øþóþ	 60
+øþó	 60
+?ù	 60
+øªî	 60
+_¢ø	 60
+€øªî	 60
+_öøþ	 60
+-ª?	 60
+ì_	 60
+š€	 60
+ý€?	 60
+÷þ	 59
+öøþóþ	 59
+¯?	 59
+_¢?	 59
+öøþó	 59
+¢ª_	 59
+€??	 58
+€?¥	 58
+_üõ	 58
+.-	 58
+?¡	 58
+ø÷	 57
+í	 57
+¢€î	 57
+?€?_	 57
+þ?€	 57
+ù-	 57
+üõ_	 56
+ñ?š	 56
+øõ_	 56
+?€þ?	 56
+ú?	 56
+î€	 56
+€?¢	 56
+õû_	 55
+ô?	 55
+ª?¢	 55
+_öøþó	 55
+-ª?¢	 55
+þ_	 55
+ö?€þ	 55
+€î_	 55
+S€	 55
+üþ	 54
+_S€	 53
+øªî_	 53
+_ù€	 53
+ò¢	 53
+€ò	 53
+€øªî_	 53
+ø¡_	 52
+¢÷?	 52
+û€	 52
+üþ?	 52
+õ>	 52
+-õ	 52
+¢€?	 52
+üð	 52
+ì?	 52
+_í	 52
+î?	 52
+üó	 52
+??€	 52
+ð÷	 51
+€ò¢	 51
+-þ	 51
+_ý€?	 51
+¡?	 50
+_¢€	 50
+¢€î_	 50
+.-š	 50
+ö?õ	 50
+ë	 50
+_ô?	 50
+ø¢	 50
+_ñ?š	 49
+.¢÷	 49
+÷€	 49
+ý?€?	 49
+ú-	 48
+_üð	 48
+_ö?€þ	 48
+€þ?_	 48
+ò¢_	 48
+ûù	 48
+ú?_	 48
+€ò¢_	 47
+ê€	 47
+â	 47
+.-š?	 47
+_¢þ	 47
+>÷	 47
+úª	 47
+÷?õ	 47
+£	 47
+?€þ?_	 47
+?ûù	 47
+€¯	 46
+_.-	 46
+_ý?€?	 46
+õ€	 46
+õó	 46
+-€	 46
+_üþ	 46
+¥þ	 46
+€ð	 45
+ôþ	 45
+_üó	 45
+ö?-	 45
+§þ	 45
+_ë	 45
+f	 45
+õ-	 44
+_ù-	 44
+úõ	 44
+_üþ?	 44
+ü-ª	 44
+-î	 44
+ð¢	 44
+ö?€þ?	 44
+õª	 44
+.-š?_	 44
+šõ_	 44
+€ª	 44
+_-š?	 44
+€?î	 43
+ä?	 43
+é	 43
+?õ_	 43
+_€øªî	 43
+þª	 43
+?ê	 43
+?î_	 43
+_€øª	 43
+¯_	 43
+€š	 43
+þ??	 42
+Y?	 42
+¥_	 42
+÷÷	 42
+÷õ	 42
+_¥ø	 42
+þš?	 42
+¢õ	 42
+/	 42
+_â	 42
+???_	 42
+_¥ø€	 42
+_ù÷	 42
+s	 42
+¢÷÷	 42
+ö?-š	 41
+÷ø	 41
+ù÷?	 41
+?*	 41
+S€ò¢	 41
+_ö?õ	 41
+ñþ	 41
+_.-š	 41
+îþ	 41
+÷¢	 41
+ùõ	 41
+S€ò	 41
+ªø	 41
+ý?€?_	 40
+€úª	 40
Index: /main/tags/2.25/gsdl/perllib/textcat/Other/quechua.lm
===================================================================
--- /main/tags/2.25/gsdl/perllib/textcat/Other/quechua.lm	(revision 21064)
+++ /main/tags/2.25/gsdl/perllib/textcat/Other/quechua.lm	(revision 21064)
@@ -0,0 +1,400 @@
+_	 5766
+a	 4900
+n	 1941
+i	 1666
+u	 1384
+s	 1032
+t	 995
+y	 939
+h	 929
+k	 915
+q	 909
+p	 882
+a_	 847
+an	 821
+r	 783
+m	 740
+c	 705
+l	 695
+ta	 637
+ch	 613
+ay	 587
+qa	 557
+pa	 490
+ha	 486
+e	 474
+ma	 457
+o	 441
+na	 434
+ku	 411
+j	 409
+un	 367
+w	 358
+in	 353
+,	 345
+,_	 344
+cha	 318
+ar	 317
+n_	 315
+as	 291
+wa	 289
+ta_	 269
+ll	 259
+man	 255
+_k	 248
+._	 243
+.	 243
+nt	 227
+am	 224
+pi	 222
+la	 222
+ka	 217
+ac	 214
+ni	 214
+at	 213
+aq	 213
+i_	 208
+ri	 207
+qa_	 204
+una	 204
+y_	 192
+aj	 192
+_p	 192
+is	 188
+_m	 181
+lla	 175
+ach	 174
+rq	 173
+us	 172
+an_	 171
+_ka	 171
+ata	 169
+rqa	 165
+sq	 163
+hu	 162
+sp	 161
+_w	 157
+nk	 157
+hay	 157
+_s	 156
+sqa	 155
+ki	 153
+kun	 152
+_c	 152
+al	 150
+nta	 149
+ap	 147
+ant	 146
+yk	 146
+ay_	 144
+spa	 141
+hi	 137
+_ch	 136
+_n	 136
+ya	 135
+'	 134
+j_	 133
+uy	 132
+ra	 132
+a,_	 132
+a,	 132
+ti	 130
+_a	 125
+nc	 125
+kuna	 122
+s_	 121
+su	 121
+ak	 121
+_ma	 118
+ana	 118
+ari	 115
+_t	 114
+ama	 114
+chi	 114
+ñ	 113
+a._	 111
+a.	 111
+nch	 111
+iy	 111
+all	 110
+aw	 110
+_r	 110
+anta	 109
+ayk	 109
+na_	 109
+chay	 108
+sa	 104
+_wa	 104
+si	 103
+chu	 102
+pa_	 101
+acha	 101
+_cha	 101
+pi_	 101
+qan	 100
+_pa	 99
+_q	 97
+aj_	 97
+awa	 97
+ank	 95
+nku	 95
+im	 94
+q_	 92
+uk	 92
+C	 92
+mu	 90
+tu	 89
+J	 89
+_ni	 88
+taj	 87
+_J	 87
+nin	 86
+_chay	 86
+u_	 86
+_C	 84
+wan	 83
+nta_	 81
+_j	 81
+mant	 80
+ut	 79
+in_	 79
+ik	 79
+manta	 79
+asq	 79
+yt	 78
+n,	 78
+asqa	 78
+n,_	 78
+pay	 78
+li	 77
+yn	 77
+nq	 76
+yta	 76
+ic	 76
+up	 76
+_Ch	 75
+yku	 75
+Ch	 75
+he	 75
+hay_	 74
+nan	 74
+ina	 74
+ur	 73
+er	 72
+S	 72
+arq	 72
+or	 72
+_l	 71
+_u	 71
+aq_	 70
+os	 70
+yp	 70
+anc	 69
+man_	 69
+mi	 69
+ich	 68
+_i	 68
+st	 67
+_S	 67
+arqa	 66
+it	 66
+anch	 66
+ru	 66
+aku	 65
+pu	 65
+ña	 65
+alla	 64
+mp	 64
+sqa_	 64
+'a	 64
+ayku	 63
+es	 63
+A	 63
+ia	 63
+_man	 63
+_Cha	 61
+Cha	 61
+taj_	 60
+api	 60
+_ll	 60
+wi	 60
+ayp	 60
+aman	 59
+g	 58
+anku	 58
+yki	 57
+ima	 57
+yni	 57
+oj	 57
+mana	 57
+anta_	 57
+_su	 57
+uc	 56
+isp	 56
+ispa	 56
+uch	 56
+M	 56
+ir	 56
+_h	 55
+nqa	 55
+kuy	 55
+ayt	 54
+_M	 54
+b	 54
+_y	 53
+_mana	 53
+:	 53
+uku	 53
+:_	 53
+nm	 53
+au	 52
+ayta	 52
+io	 52
+qo	 51
+an,_	 51
+apa	 51
+spa_	 51
+erq	 51
+_wi	 51
+erqa	 51
+_sa	 51
+an,	 51
+el	 50
+um	 50
+ana_	 50
+han	 50
+il	 50
+on	 49
+chay_	 49
+sta	 49
+_D	 49
+D	 49
+iku	 49
+aqa	 49
+che	 48
+en	 48
+yta_	 48
+Ma	 47
+P	 47
+_lla	 47
+_Je	 47
+yq	 47
+Je	 47
+ita	 47
+rqan	 47
+ypi	 46
+har	 46
+Jes	 46
+_Jes	 46
+ios	 46
+ayq	 46
+Dio	 46
+un_	 46
+kus	 46
+_Dio	 46
+taq	 46
+_Dios	 46
+_Ma	 46
+_Di	 46
+Dios	 46
+Di	 46
+d	 46
+kan	 45
+Chay	 45
+oq	 45
+_Chay	 45
+_pay	 45
+upa	 45
+mun	 45
+ata_	 44
+_tu	 44
+nis	 44
+re	 44
+paq	 44
+yo	 44
+ej	 44
+qay	 43
+ncha	 43
+ha_	 43
+_A	 43
+I	 43
+_kan	 43
+_nis	 43
+_P	 43
+nman	 43
+nma	 43
+ataj	 42
+ara	 42
+ku_	 42
+nata	 42
+nat	 42
+i,	 41
+tin	 41
+qh	 41
+t'	 41
+orq	 41
+nki	 41
+_ru	 41
+_ku	 41
+i,_	 41
+ip	 40
+ham	 40
+usq	 40
+_ya	 40
+qank	 39
+orqa	 39
+ayn	 39
+mana_	 39
+ray	 39
+ym	 39
+uma	 39
+_pu	 39
+par	 39
+kay	 39
+n.	 38
+qa,_	 38
+n._	 38
+sus	 38
+aypi	 38
+usqa	 38
+qanku	 38
+ill	 38
+qa,	 38
+was	 38
+pa,	 38
+pa,_	 38
+asp	 38
+qa._	 37
+_mu	 37
+paj	 37
+amp	 37
+hin	 37
+uti	 37
+rin	 37
+_im	 37
+_ima	 37
+ja	 37
+_ri	 37
+rqa_	 37
+taq_	 37
+qa.	 37
+sh	 36
+spa,_	 36
+cha_	 36
+spa,	 36
+achi	 36
+una_	 36
+rqank	 36
+jt	 36
+K	 36
+amu	 36
+aspa	 35
+_Jesu	 35
+Jesus	 35
+nispa	 35
+ki_	 35
+waw	 35
+ko	 35
+ne	 35
+esus	 35
+int	 35
Index: /main/tags/2.25/gsdl/perllib/textcat/Other/romanian.lm
===================================================================
--- /main/tags/2.25/gsdl/perllib/textcat/Other/romanian.lm	(revision 21064)
+++ /main/tags/2.25/gsdl/perllib/textcat/Other/romanian.lm	(revision 21064)
@@ -0,0 +1,400 @@
+_	 20674
+a	 6376
+e	 5815
+i	 5746
+t	 3396
+r	 3280
+n	 3103
+u	 2835
+s	 2611
+c	 2582
+e_	 2235
+l	 2224
+o	 2149
+a_	 1974
+d	 1629
+m	 1528
+p	 1410
+i_	 1358
+in	 1308
+_c	 1167
+_s	 1118
+_d	 999
+re	 905
+ar	 898
+,	 791
+,_	 786
+_p	 785
+de	 771
+_a	 754
+te	 687
+_i	 667
+at	 654
+ti	 645
+ca	 639
+n_	 630
+ta	 617
+si	 614
+_de	 609
+f	 606
+st	 583
+ri	 581
+u_	 567
+nt	 553
+.	 542
+ra	 540
+_m	 534
+g	 528
+v	 516
+ul	 516
+de_	 513
+_in	 503
+b	 492
+_de_	 474
+._	 472
+le	 459
+l_	 444
+un	 443
+_si	 440
+es	 437
+tr	 426
+ea	 420
+t_	 412
+ce	 412
+ma	 407
+cu	 402
+er	 398
+_ca	 397
+si_	 388
+_f	 387
+_l	 383
+z	 382
+la	 381
+ne	 370
+sa	 364
+as	 360
+_e	 357
+in_	 356
+an	 352
+it	 351
+te_	 346
+or	 345
+el	 345
+ci	 339
+_si_	 333
+_n	 330
+are	 324
+pe	 319
+re_	 317
+al	 310
+_t	 309
+se	 304
+ic	 295
+ie	 290
+_u	 290
+ul_	 290
+ni	 289
+int	 285
+_o	 280
+en	 279
+ta_	 279
+ur	 261
+pa	 256
+co	 255
+_pe	 254
+ia	 252
+mi	 251
+pr	 249
+_ma	 249
+oa	 249
+me	 246
+lu	 246
+li	 241
+im	 238
+_in_	 237
+da	 237
+na	 237
+_sa	 235
+ac	 234
+-	 234
+ii	 232
+est	 231
+r_	 231
+h	 230
+_cu	 230
+le_	 229
+ai	 229
+ca_	 227
+il	 226
+ru	 223
+sc	 223
+_v	 221
+nu	 220
+tu	 220
+_un	 220
+nd	 220
+di	 219
+are_	 216
+to	 215
+am	 214
+on	 213
+o_	 208
+is	 208
+sa_	 203
+la_	 200
+_b	 200
+ste	 195
+et	 194
+ec	 191
+_r	 186
+car	 185
+ui	 180
+un_	 179
+lo	 178
+cu_	 177
+ei	 176
+e,	 175
+e,_	 175
+pe_	 171
+m_	 167
+_la	 166
+a,	 165
+a,_	 164
+_ce	 164
+rt	 163
+_co	 163
+ent	 162
+ro	 162
+ele	 162
+_pe_	 160
+po	 160
+ea_	 159
+"	 158
+ntr	 158
+_cu_	 158
+_pr	 157
+ut	 157
+nc	 156
+ata	 155
+care	 154
+um	 153
+au	 151
+va	 151
+_o_	 150
+_car	 150
+ii_	 145
+ind	 145
+_un_	 144
+os	 144
+ad	 141
+_la_	 140
+I	 140
+este	 138
+ste_	 138
+care_	 138
+ir	 137
+ga	 136
+ap	 136
+ol	 136
+ra_	 136
+_di	 134
+D	 134
+_care	 133
+se_	 133
+om	 133
+ara	 133
+ati	 133
+fi	 133
+_sa_	 131
+zi	 130
+vi	 130
+_ca_	 129
+_se	 128
+_nu	 128
+ai_	 127
+ch	 127
+pi	 124
+ve	 123
+fa	 122
+ot	 121
+_a_	 120
+este_	 120
+du	 119
+ine	 119
+s_	 118
+fo	 118
+_ci	 118
+ui_	 118
+ba	 118
+i,	 117
+i,_	 116
+ne_	 115
+us	 115
+_g	 115
+a.	 115
+fe	 114
+A	 114
+pu	 114
+ce_	 113
+ar_	 113
+_pa	 113
+oc	 112
+sta	 112
+lui	 112
+ns	 112
+em	 112
+'	 112
+oar	 112
+din	 111
+iu	 111
+_int	 111
+ate	 111
+mu	 111
+hi	 110
+ele_	 110
+mp	 109
+_D	 109
+S	 109
+sti	 108
+bi	 108
+ata_	 107
+ti_	 107
+tra	 107
+C	 107
+c_	 106
+tre	 106
+_al	 105
+rea	 105
+mai	 105
+j	 104
+a._	 104
+gi	 104
+e.	 103
+d_	 103
+_fa	 103
+E	 102
+mo	 102
+at_	 101
+_e_	 101
+nte	 101
+lt	 101
+sp	 101
+za	 100
+mai_	 100
+su	 99
+na_	 98
+tat	 97
+sin	 97
+ez	 96
+tru	 96
+e._	 96
+ie_	 96
+ia_	 96
+_re	 96
+tul	 96
+_fo	 96
+ina	 95
+art	 95
+_C	 95
+no	 95
+nu_	 94
+_es	 94
+_po	 94
+cr	 94
+inc	 93
+_da	 92
+_mai	 92
+lui_	 92
+_din	 92
+_est	 92
+pre	 91
+_mai_	 91
+io	 91
+chi	 91
+ge	 90
+pri	 90
+eu	 90
+uri	 90
+az	 90
+_nu_	 89
+_me	 89
+ct	 89
+au_	 88
+esc	 88
+ev	 88
+ei_	 88
+min	 87
+ace	 87
+op	 86
+ng	 86
+ici	 86
+_lu	 85
+ari	 85
+_mi	 84
+ita	 84
+_S	 84
+_tr	 84
+ere	 83
+or_	 83
+ast	 83
+ist	 83
+nt_	 83
+_se_	 82
+ou	 82
+tin	 82
+intr	 82
+con	 82
+do	 81
+_fi	 81
+str	 81
+am_	 80
+rat	 80
+ru_	 80
+ri_	 80
+par	 80
+oi	 80
+uc	 79
+ze	 79
+pl	 79
+res	 78
+_ac	 77
+ulu	 77
+din_	 76
+va_	 76
+ada	 76
+ului	 75
+_con	 75
+id	 75
+inte	 74
+ile	 73
+cit	 73
+_din_	 73
+lor	 73
+_"	 72
+ig	 72
+rin	 72
+da_	 72
+_st	 72
+-_	 71
+_-	 71
+it_	 71
+ani	 71
+nd_	 71
+ci_	 70
+ag	 70
+eri	 70
+i.	 70
+tru_	 70
+_ne	 70
+rm	 70
+P	 69
+_este	 69
+nta	 69
+bu	 69
+une	 69
+ma_	 69
+nti	 69
+imp	 68
+_-_	 68
+iv	 68
+ind_	 68
Index: /main/tags/2.25/gsdl/perllib/textcat/Other/rumantsch.lm
===================================================================
--- /main/tags/2.25/gsdl/perllib/textcat/Other/rumantsch.lm	(revision 21064)
+++ /main/tags/2.25/gsdl/perllib/textcat/Other/rumantsch.lm	(revision 21064)
@@ -0,0 +1,400 @@
+_	 10888
+a	 3490
+e	 2268
+i	 2196
+s	 2169
+n	 1961
+t	 1555
+r	 1510
+l	 1281
+u	 1249
+a_	 1155
+c	 1060
+d	 954
+o	 815
+s_	 744
+g	 726
+m	 686
+h	 620
+p	 617
+n_	 559
+v	 493
+_s	 480
+er	 476
+ch	 469
+_d	 457
+in	 455
+da	 418
+_c	 404
+r_	 388
+_e	 377
+.	 358
+_p	 340
+as	 333
+l_	 328
+,	 327
+._	 320
+_i	 320
+,_	 315
+la	 313
+en	 312
+sc	 310
+an	 301
+ta	 300
+_da	 285
+f	 282
+_t	 268
+_a	 262
+nt	 259
+_m	 252
+un	 248
+ra	 247
+i_	 247
+na	 245
+ma	 245
+ia	 241
+ar	 234
+sch	 228
+b	 228
+da_	 217
+es	 214
+ai	 213
+st	 212
+'	 209
+e_	 208
+as_	 208
+er_	 200
+t_	 199
+re	 199
+_l	 195
+al	 193
+_n	 193
+el	 192
+tg	 192
+te	 188
+z	 187
+ha	 180
+_f	 180
+sa	 174
+_da_	 172
+ve	 169
+ei	 168
+_v	 165
+at	 165
+ss	 161
+is	 161
+_ch	 161
+on	 160
+la_	 158
+cu	 158
+ad	 158
+he	 156
+in_	 147
+va	 147
+_in	 146
+gl	 145
+ns	 141
+ur	 140
+ü	 140
+u_	 138
+ts	 138
+pe	 136
+li	 134
+gi	 133
+et	 133
+de	 132
+ig	 132
+or	 130
+ti	 129
+il	 127
+d_	 126
+che	 123
+ut	 122
+us	 122
+cha	 121
+di	 120
+ia_	 120
+_b	 118
+_la	 117
+na_	 116
+ain	 115
+per	 115
+to	 115
+_cu	 113
+_sc	 112
+se	 111
+ls	 109
+-	 108
+iu	 108
+ca	 107
+si	 104
+ir	 102
+rt	 102
+ie	 102
+_g	 102
+un_	 102
+nd	 101
+av	 101
+ni	 100
+q	 99
+au	 97
+ls_	 97
+ll	 96
+qu	 96
+_pe	 96
+le	 96
+rs	 95
+pa	 95
+ri	 95
+_ma	 94
+_per	 93
+am	 93
+eg	 92
+_r	 92
+gn	 92
+me	 92
+pi	 91
+an_	 91
+en_	 91
+ga	 91
+ent	 90
+hi	 90
+_e_	 90
+it	 89
+ta_	 88
+ter	 87
+ns_	 86
+iv	 86
+igl	 86
+a.	 85
+em	 85
+I	 85
+chi	 84
+_en	 84
+int	 84
+ue	 83
+su	 82
+tt	 82
+a,	 82
+a,_	 82
+o_	 82
+_ve	 82
+a._	 82
+_q	 81
+_qu	 80
+ge	 80
+"	 80
+_la_	 80
+ar_	 80
+vi	 79
+gl_	 79
+tu	 78
+ng	 78
+ro	 76
+mi	 76
+sta	 75
+ed	 75
+lla	 74
+ei_	 73
+_o	 73
+ic	 73
+el_	 73
+_il	 73
+_in_	 72
+g_	 72
+pr	 71
+nu	 70
+ina	 70
+_h	 69
+scha	 68
+mai	 68
+pl	 68
+il_	 68
+os	 68
+ha_	 68
+be	 67
+uo	 67
+cun	 67
+ra_	 67
+_pa	 65
+ts_	 64
+s.	 64
+co	 64
+_u	 64
+fi	 64
+_I	 63
+sa_	 63
+s._	 63
+_re	 62
+ün	 62
+_nu	 62
+?	 62
+S	 62
+_se	 61
+no	 61
+nt_	 61
+E	 61
+tr	 61
+mp	 60
+igl_	 60
+_su	 60
+_st	 60
+ess	 60
+im	 60
+zi	 59
+?_	 59
+nc	 59
+_E	 58
+_-	 58
+_cun	 58
+_te	 58
+_sa	 58
+ant	 58
+main	 58
+eu	 57
+ssa	 57
+-_	 57
+iun	 57
+_-_	 57
+aint	 56
+op	 56
+al_	 56
+dal	 56
+j	 56
+ama	 55
+_tg	 55
+ua	 55
+M	 55
+per_	 55
+tsc	 54
+nta	 54
+tsch	 54
+um	 54
+fa	 54
+za	 54
+_di	 54
+pia	 54
+_per_	 54
+T	 54
+_M	 53
+ne	 53
+era	 53
+A	 53
+que	 53
+_dal	 53
+cr	 53
+_de	 53
+lla_	 53
+_che	 52
+h'	 52
+_me	 51
+ot	 51
+_pr	 51
+_pl	 51
+_sch	 51
+ch'	 50
+_S	 50
+opi	 50
+ou	 50
+tta	 50
+mo	 50
+ada	 50
+ba	 50
+_an	 49
+top	 49
+id	 49
+è	 49
+he_	 49
+C	 49
+va_	 49
+uto	 49
+ins	 48
+topi	 48
+L	 48
+ir_	 48
+ist	 48
+c_	 48
+_il_	 48
+P	 48
+ss_	 48
+ag	 47
+_no	 47
+res	 47
+las	 47
+_vi	 46
+s,	 46
+schi	 46
+_en_	 46
+tg_	 46
+s,_	 46
+_si	 46
+_que	 45
+_T	 45
+az	 45
+'i	 45
+cun_	 44
+_fa	 44
+_mi	 44
+utop	 44
+utopi	 44
+sche	 44
+_C	 44
+ur_	 44
+tge	 44
+po	 44
+es_	 44
+x	 44
+nz	 44
+_L	 44
+_cun_	 44
+man	 44
+_ch'	 43
+_fi	 43
+pu	 43
+ell	 43
+opia	 43
+_igl	 43
+_ig	 43
+sp	 43
+topia	 43
+ava	 42
+egn	 42
+che_	 42
+on_	 42
+ci	 42
+_P	 42
+ev	 42
+ond	 41
+_"	 41
+à	 41
+us_	 41
+_ha	 41
+D	 40
+_co	 40
+etg	 40
+'e	 40
+las_	 40
+est	 40
+ura	 40
+uel	 39
+ed_	 39
+vo	 39
+gia	 39
+bu	 39
+mu	 39
+nn	 39
+gli	 39
+_A	 39
+lu	 39
+cha_	 39
+ul	 38
+mal	 38
+_ün	 38
+ina_	 38
+_bu	 38
+_ca	 38
+_ü	 38
+uc	 38
+nts	 38
+tra	 38
+_tu	 37
Index: /main/tags/2.25/gsdl/perllib/textcat/Other/russian-iso8859_5.lm
===================================================================
--- /main/tags/2.25/gsdl/perllib/textcat/Other/russian-iso8859_5.lm	(revision 21064)
+++ /main/tags/2.25/gsdl/perllib/textcat/Other/russian-iso8859_5.lm	(revision 21064)
@@ -0,0 +1,400 @@
+_	 76249
+Þ	 19732
+Õ	 16714
+Ð	 14389
+Ø	 13942
+â	 13160
+Ý	 12444
+á	 9867
+à	 8461
+Ò	 7895
+Û	 7330
+Ú	 6498
+Ü	 5935
+.	 5725
+ã	 5287
+Ô	 5019
+ß	 4877
+ï	 4083
+,	 3899
+,_	 3878
+ë	 3656
+ì	 3376
+Ø_	 3167
+_ß	 3144
+Õ_	 3135
+Þ_	 3098
+-	 3019
+×	 2983
+_Ò	 2952
+._	 2930
+_á	 2919
+ç	 2887
+Ó	 2876
+Ñ	 2797
+áâ	 2672
+_Ý	 2631
+âÞ	 2585
+..	 2407
+_Ø	 2316
+ÝÞ	 2300
+-_	 2294
+Ù	 2281
+Ð_	 2249
+ÝÐ	 2057
+ï_	 2029
+ÞÒ	 1981
+ÝØ	 1950
+_â	 1944
+å	 1874
+ÕÝ	 1856
+_Þ	 1774
+...	 1744
+àÐ	 1709
+ÝÕ	 1685
+ßÞ	 1636
+_-	 1625
+ÚÞ	 1616
+âÕ	 1595
+àÞ	 1584
+_Ú	 1558
+_-_	 1531
+Ù_	 1521
+Õâ	 1518
+Ö	 1509
+_Ø_	 1454
+âÐ	 1433
+ÐÝ	 1419
+Õà	 1396
+Þâ	 1389
+ì_	 1381
+ÓÞ	 1375
+ÐÛ	 1370
+_ßÞ	 1364
+àÕ	 1345
+ÚÐ	 1338
+ßà	 1337
+ÒÐ	 1329
+âØ	 1306
+ÛØ	 1300
+_Ô	 1297
+_Ü	 1290
+Õá	 1284
+ÒÞ	 1271
+çÕ	 1256
+Þà	 1245
+....	 1232
+âì	 1219
+Þá	 1212
+è	 1192
+î	 1187
+Ò_	 1168
+.....	 1167
+ÞÝ	 1147
+ÐÚ	 1144
+æ	 1109
+ÞÓ	 1101
+ÛÞ	 1099
+â_	 1093
+àØ	 1076
+Ü_	 1074
+_ßà	 1063
+ÞÛ	 1062
+Ûì	 1045
+_ÝÕ	 1034
+ÕÛ	 1029
+_Ñ	 1026
+ØÝ	 1000
+ÞÔ	 998
+ÞÜ	 996
+ÜÕ	 993
+ë_	 975
+ÒÕ	 968
+áÚ	 968
+_ÝÐ	 966
+ÔÕ	 946
+Ýë	 943
+_à	 931
+_ç	 923
+Ðâ	 913
+ÕÜ	 910
+ã_	 907
+×Ð	 898
+å_	 898
+ÛÕ	 889
+âÞ_	 881
+Øâ	 878
+ÞÙ	 875
+áÕ	 862
+_Ò_	 833
+_×	 816
+ÚØ	 816
+âà	 807
+"	 786
+âì_	 769
+ÕÔ	 767
+ÝÕ_	 762
+áï	 754
+ÛÐ	 748
+ÞÑ	 747
+ÜÞ	 741
+ÔÐ	 730
+ÓÞ_	 715
+Ú_	 713
+Øá	 711
+_ã	 702
+ÞÙ_	 697
+ØÛ	 694
+ÜÐ	 692
+ÝÝ	 687
+ÔÞ	 662
+Ðá	 660
+ÐÜ	 656
+Øï	 649
+ÖÕ	 646
+Ð×	 638
+áÞ	 629
+ÝÐ_	 619
+_Ó	 615
+ÜØ	 612
+_Ð	 610
+í	 609
+Òá	 608
+.._	 605
+Òë	 604
+ÞÓÞ	 604
+ØÜ	 604
+_ÚÞ	 600
+ÐÒ	 597
+áÛ	 594
+ØÕ	 593
+_ÝÕ_	 589
+_Õ	 587
+_âÕ	 583
+âã	 583
+Øç	 583
+àã	 575
+Þáâ	 571
+é	 571
+Û_	 570
+_í	 569
+_ï	 559
+°	 556
+ÕÝØ	 544
+Ø×	 540
+ÕÚ	 536
+ÞÒÐ	 533
+ä	 525
+:	 519
+²	 513
+ÐÝØ	 511
+_Òá	 510
+ØÙ	 510
+œ	 508
+_ÚÐ	 508
+!	 503
+?	 501
+ÔØ	 498
+ÛØ_	 489
+¿	 488
+ßàÞ	 486
+_àÐ	 485
+áØ	 484
+Øà	 484
+_áâ	 484
+ìÝ	 484
+ÛìÝ	 484
+:_	 484
+áï_	 480
+_×Ð	 477
+ÑÞ	 470
+_Û	 469
+..._	 465
+Ñë	 464
+Øå	 464
+ž	 462
+ÕÓ	 461
+âÒ	 459
+ÝØï	 458
+ïâ	 454
+çâ	 454
+íâ	 445
+çÕá	 442
+_âÞ	 442
+Øï_	 441
+ØÚ	 440
+ÒØ	 437
+ÐÚ_	 436
+áâÐ	 436
+ÞÓÞ_	 435
+_²	 434
+ØçÕ	 433
+æØ	 431
+çâÞ	 431
+ëå	 429
+_íâ	 429
+Á	 425
+_çâ	 424
+_°	 424
+î_	 423
+ßÕ	 422
+Ýï	 422
+_çâÞ	 422
+Ûï	 419
+ÒáÕ	 418
+Ôã	 418
+ÕáÚ	 415
+Ýâ	 413
+ÚÐÚ	 411
+áâÞ	 411
+_Òë	 409
+Ýã	 408
+âá	 406
+Ý_	 406
+_¿	 401
+Œ	 401
+ÝÞ_	 399
+_ßàÞ	 398
+_.	 397
+àÞÒ	 396
+æÕ	 396
+Úâ	 394
+Õáâ	 394
+_"	 393
+èÕ	 393
+á_	 392
+_Þâ	 392
+Ÿ	 391
+_ÝÐ_	 391
+àÕÔ	 391
+çÕáÚ	 390
+Þ-	 390
+ÒÐÝ	 388
+Ð,	 385
+ÐÔ	 384
+Ðï	 384
+_ï_	 383
+Ð,_	 383
+âë	 383
+?_	 383
+_ÞÑ	 380
+_ÒáÕ	 380
+_âÐ	 378
+_ÚÐÚ	 376
+åÞ	 375
+âÐÚ	 375
+ÐÛì	 374
+ÞÖ	 373
+ëå_	 372
+ÞÒÞ	 372
+ØÒ	 371
+_ÒÞ	 369
+Üã	 369
+_œ	 369
+ÕÙ	 368
+ßàÕ	 368
+×Ý	 366
+ØçÕá	 365
+ßØ	 365
+ÕÓÞ	 362
+_áÞ	 360
+ÞÕ	 360
+!_	 360
+Ðâì	 360
+áâØ	 358
+Øå_	 358
+âÝ	 358
+ÜÕÝ	 358
+âáï	 356
+ØÕ_	 356
+ØçÕáÚ	 354
+ÑÕ	 352
+_Ñë	 352
+áâà	 349
+Úã	 349
+_ÜÞ	 348
+Õâ_	 348
+Â	 346
+_ÜÕ	 344
+ÕÒ	 344
+ßàØ	 343
+çØ	 342
+ÜÝ	 341
+ÝØï_	 339
+Ðà	 338
+ÝÝÞ	 337
+ÞÒÐÝ	 334
+Úá	 334
+ãà	 328
+_çÕ	 328
+ÞÛì	 328
+ãâ	 327
+çâÞ_	 324
+ÞÜ_	 323
+Þß	 323
+àÜ	 322
+°_	 322
+_çâÞ_	 322
+íâÞ	 322
+Þç	 321
+Þ,_	 320
+Þ,	 320
+áÚÞ	 319
+ÚÞÝ	 319
+ÛÞÒ	 318
+ëÙ	 318
+ãá	 317
+Þâ_	 316
+ØàÞ	 315
+áâÒ	 314
+Ø,	 314
+ØÙ_	 313
+áá	 313
+Ø,_	 313
+âÞÜ	 312
+ÐÕ	 312
+ÕÝÝ	 311
+Õ×	 311
+ÝÞÙ	 311
+_íâÞ	 310
+º	 309
+áÐ	 309
+àÐ×	 309
+Õß	 309
+_ÔÞ	 308
+ÞÛÞ	 308
+áâì	 308
+ãÔ	 307
+ÔÕÛ	 307
+_ž	 305
+ÐÑ	 305
+áì	 303
+ÐÛìÝ	 302
+ÞÚ	 300
+áÚØ	 300
+Ýëå	 300
+_ßàØ	 298
+çÐ	 297
+_Ö	 297
+Õ,	 297
+Õ,_	 297
+_°_	 296
+_ÝØ	 296
+_._	 295
+âáï_	 295
+ØØ	 294
+×ÝÐ	 293
+ï,	 292
+ï,_	 292
+_ßàÕ	 291
+_Á	 290
+ÝÞÙ_	 290
+Ðï_	 288
+_Ÿ	 288
+ÐÛØ	 286
+ÖÕ_	 285
+áß	 285
+Øáâ	 285
+Ýëå_	 285
+×_	 283
+_Œ	 283
Index: /main/tags/2.25/gsdl/perllib/textcat/Other/russian-koi8_r.lm
===================================================================
--- /main/tags/2.25/gsdl/perllib/textcat/Other/russian-koi8_r.lm	(revision 21064)
+++ /main/tags/2.25/gsdl/perllib/textcat/Other/russian-koi8_r.lm	(revision 21064)
@@ -0,0 +1,400 @@
+_	 28256
+Ï	 8957
+Å	 7206
+Á	 6230
+É	 5966
+Ô	 5385
+Î	 5338
+Ó	 4464
+Ò	 3984
+×	 3504
+Ì	 3335
+Ë	 2700
+Í	 2441
+Ð	 2324
+Ä	 2230
+Õ	 1840
+Ñ	 1562
+Ù	 1540
+_Ð	 1505
+,	 1492
+,_	 1492
+Ø	 1437
+Ï_	 1423
+Å_	 1335
+ÓÔ	 1286
+Ú	 1283
+Ç	 1233
+Â	 1232
+É_	 1193
+ÔÏ	 1175
+_Ó	 1146
+Þ	 1143
+_×	 1118
+_Î	 1062
+Á_	 1032
+.	 999
+ÎÏ	 996
+ÅÎ	 920
+Ï×	 911
+._	 908
+Ê	 907
+ÎÁ	 893
+ÒÏ	 869
+ÒÁ	 851
+ÎÉ	 844
+Ñ_	 808
+ÐÒ	 786
+ÐÏ	 775
+ËÏ	 768
+Ö	 763
+_Ï	 735
+ÎÅ	 730
+ÏÓ	 723
+_É	 721
+È	 696
+ÒÅ	 667
+_ÐÒ	 629
+_Ë	 626
+×_	 621
+ÔÅ	 620
+Ø_	 616
+×Ï	 599
+Ê_	 597
+_ÐÏ	 592
+ÇÏ	 589
+ÅÒ	 584
+ÌÉ	 579
+ÔÁ	 576
+ÅÔ	 566
+Í_	 562
+ÅÓ	 548
+ÏÒ	 545
+ÅÌ	 545
+ÁÌ	 544
+×Á	 535
+ÔØ	 533
+ÌÅ	 528
+_Ä	 522
+ÏÍ	 520
+ËÁ	 520
+À	 518
+Û	 510
+_Ô	 507
+ÏÔ	 502
+ÏÌ	 500
+ÁÎ	 498
+ÌØ	 486
+ÏÄ	 476
+ÁÔ	 475
+ÔÉ	 471
+ÉÔ	 458
+ÏÎ	 457
+ÏÇ	 450
+Ã	 450
+ÌÏ	 449
+Ô_	 448
+_ÎÁ	 447
+ÎÙ	 443
+ÄÅ	 442
+_Í	 438
+ÌÁ	 431
+_×_	 430
+ÓË	 428
+_ÎÅ	 424
+ÒÉ	 400
+ÅÍ	 396
+_Â	 392
+_Þ	 388
+ÞÅ	 388
+ÁË	 388
+_É_	 385
+_Ò	 382
+ÔÏ_	 381
+ÉÎ	 380
+ÍÅ	 374
+ÄÁ	 362
+Ù_	 361
+×Å	 350
+ÔØ_	 348
+ÐÒÏ	 347
+ÏÊ	 346
+ÚÁ	 338
+È_	 336
+ÁÓ	 335
+ÏÂ	 328
+ÓÑ	 326
+ÉÍ	 323
+ÔÒ	 321
+ÎÁ_	 321
+ÓÏ	 320
+ÅÄ	 320
+ÏÓÔ	 318
+ÉÅ	 318
+ÍÏ	 317
+ÎÎ	 316
+ÓÅ	 314
+-	 314
+Á×	 309
+ÖÅ	 308
+Õ_	 307
+ËÉ	 306
+ÎÅ_	 305
+ÇÏ_	 302
+_Ú	 300
+ÉÌ	 295
+_ÐÒÏ	 291
+Ý	 289
+Ô×	 288
+ÉÓ	 285
+_Õ	 275
+_ËÏ	 274
+ÅÎÉ	 274
+Ü	 273
+ÎÏ_	 272
+ÉÒ	 271
+_Ç	 271
+ÁÚ	 267
+ÁÒ	 266
+ÄÉ	 265
+ÏÊ_	 264
+ÏÇÏ	 263
+ÁÍ	 260
+ÐÅ	 258
+×Ù	 255
+ÍÉ	 254
+ÄÏ	 254
+ÓÔ×	 247
+ÉÚ	 246
+ÃÉ	 246
+î	 244
+Æ	 240
+_Ü	 239
+_Á	 239
+Ë_	 238
+ó	 237
+ÅÓÔ	 237
+_ÎÅ_	 236
+ÂÙ	 234
+ÉÑ	 234
+ÒÕ	 229
+ÅË	 228
+ÓÉ	 226
+ÔÅÌ	 224
+ÉË	 224
+ÌÉ_	 222
+ÅÊ	 222
+ÓÑ_	 222
+ÎÔ	 220
+ØÎ	 218
+ÞÔ	 216
+ÌØÎ	 216
+ÏÅ	 214
+ÍÁ	 213
+_ÚÁ	 211
+Ï×Á	 211
+ÂÏ	 210
+_Ì	 210
+ÞÁ	 209
+_î	 208
+ÓÌ	 205
+ÞÔÏ	 204
+_ÞÔ	 204
+ÅÔ_	 203
+_ÞÔÏ	 203
+ÜÔ	 202
+Ó_	 202
+×É	 201
+ÁÑ	 199
+ÅÎÎ	 199
+ÔÏÒ	 199
+_ÎÁ_	 199
+ÓÔÁ	 198
+ÏÖ	 198
+ÉÅ_	 197
+_ó	 197
+_ÓÏ	 195
+ÐÒÉ	 194
+ËÔ	 193
+Ì_	 193
+×Ó	 191
+ÏÍ_	 190
+ÏÇÏ_	 187
+_Ö	 187
+ÅÇ	 186
+_ÔÏ	 186
+ÁÄ	 186
+_ÒÁ	 185
+_ÜÔ	 184
+_ËÁ	 184
+ÓÔÉ	 183
+_Å	 182
+Å×	 182
+ÔÓ	 181
+_ÓÔ	 180
+ÌÑ	 180
+ÔÎ	 180
+ÓÐ	 173
+ÉÉ	 172
+ÏÞ	 172
+À_	 172
+ÐÒÅ	 172
+ÏË	 172
+ÁÔØ	 171
+ÂÉ	 171
+ÛÅ	 170
+ÁÅ	 169
+á	 169
+ÏÒÏ	 168
+ÙÈ	 167
+Ï×Ï	 166
+ÏÌØ	 166
+ÁÎÉ	 165
+ÞÔÏ_	 164
+_ÞÔÏ_	 163
+÷	 163
+ÁÑ_	 163
+ÉÈ	 162
+Ï,_	 160
+Ï,	 160
+ÓÓ	 160
+ÅÚ	 159
+ÎÉÅ	 158
+ÚÎ	 157
+ÜÔÏ	 157
+ÄÎ	 156
+ÒÏ×	 156
+ð	 155
+Á,	 155
+ÓËÏ	 155
+_×Ï	 155
+Á,_	 155
+_ÂÙ	 154
+ÙÅ	 154
+ÝÅ	 154
+_ÏÂ	 154
+É,_	 153
+É,	 153
+ÎÎÏ	 152
+_ÐÒÉ	 151
+ÔÙ	 150
+ÓÔÏ	 150
+ÉÑ_	 150
+ÍÕ	 150
+É×	 150
+_-	 149
+ÒÅÄ	 148
+ÉÔÅ	 147
+_ÜÔÏ	 146
+ÍÅÎ	 146
+ÏÐ	 146
+_ÐÒÅ	 145
+	 145
+ÉÊ	 145
+ÅÌØ	 145
+_÷	 144
+_Ó_	 144
+ÉÞ	 144
+__	 144
+_	 144
+_	 144
+ÈÏ	 143
+ÅÇÏ	 143
+ÑÔ	 142
+ÔÓÑ	 142
+ÐÅÒ	 142
+ÙÊ	 142
+ÐÁ	 141
+ÏÔÏ	 140
+-_	 140
+ÁÐ	 139
+ÏÚ	 139
+ÓËÉ	 138
+ÙÈ_	 138
+ï	 137
+ÓÁ	 137
+ÙÅ_	 137
+_ð	 136
+Å,	 136
+Å,_	 136
+ÒÙ	 136
+Î_	 135
+_á	 135
+ÇÉ	 134
+_×Ù	 134
+ÓÔØ	 134
+ÁÓÔ	 133
+ÖÅ_	 133
+ÞÉ	 133
+ÎÉÑ	 133
+ÕÔ	 133
+ÁÌÉ	 132
+_-_	 131
+ËÕ	 131
+ÓØ	 131
+_ÄÏ	 129
+ÄÕ	 129
+ÒÁÚ	 129
+ÖÎ	 129
+ÁÅÔ	 129
+_ÍÏ	 127
+ÖÉ	 127
+_ÄÅ	 127
+ÓÔÒ	 127
+ØÎÏ	 126
+ÔÕ	 126
+_×Ó	 126
+ÌØÎÏ	 126
+ÌÅÎ	 125
+ÁÌØ	 125
+Ï×_	 124
+×Ì	 123
+ÉÂ	 123
+ÁË_	 123
+_ÐÅ	 123
+ÔÅÌØ	 123
+Ú_	 122
+×Î	 122
+ÁÀ	 122
+ÅÎÔ	 121
+ÐÏÌ	 121
+ÉÈ_	 121
+ÙÊ_	 121
+ÓÎ	 121
+ÎÏÇ	 121
+ÃÅ	 120
+_ÏÔ	 120
+ÅÍ_	 119
+ÉÏ	 119
+_ÔÅ	 118
+ËÁË	 118
+_ÎÏ	 117
+ÉÉ_	 117
+ÉÔØ	 117
+ë	 116
+_ÉÚ	 116
+ÕÓ	 116
+ÎÏÓ	 115
+ÂÅ	 115
+ÕÄ	 115
+ÅÒÅ	 114
+ÂÌ	 114
+ÉÔÅÌ	 113
+ÅÇÏ_	 113
+ÙÍ	 113
+ÁÂ	 113
+ÎØ	 113
+ÎÏÊ	 112
+ÎÉÅ_	 112
+_Æ	 112
+ÒÏÓ	 111
+ËÒ	 111
+_ËÁË	 111
+ÛÉ	 111
+Í,	 111
+ÎÏ×	 111
+Í,_	 111
+ÔÏÍ	 110
+ÅÅ	 110
+ÔÏ×	 109
+Ó×	 109
Index: /main/tags/2.25/gsdl/perllib/textcat/Other/sanskrit.lm
===================================================================
--- /main/tags/2.25/gsdl/perllib/textcat/Other/sanskrit.lm	(revision 21064)
+++ /main/tags/2.25/gsdl/perllib/textcat/Other/sanskrit.lm	(revision 21064)
@@ -0,0 +1,400 @@
+a	 15017
+_	 14975
+h	 5028
+i	 3820
+t	 2976
+s	 2788
+r	 2599
+|	 2437
+n	 2432
+aa	 2276
+ha	 2007
+m	 1982
+a_	 1802
+v	 1799
+d	 1768
+u	 1629
+y	 1599
+_|	 1470
+|_	 1470
+e	 1403
+k	 1371
+sh	 1330
+ra	 1243
+p	 1213
+va	 1152
+A	 1134
+ya	 1120
+ma	 1097
+na	 1091
+ar	 1080
+ta	 1054
+M	 1050
+.	 1047
+am	 1037
+an	 1006
+||	 967
+||_	 965
+_||	 965
+_||_	 963
+at	 962
+M_	 946
+as	 910
+_s	 882
+o	 848
+b	 844
+i_	 827
+aM	 764
+aM_	 685
+c	 630
+ch	 629
+sa	 623
+N	 616
+ad	 612
+H	 601
+pa	 595
+H_	 584
+g	 580
+_n	 579
+l	 554
+bh	 552
+hi	 547
+ka	 542
+it	 536
+ii	 535
+ama	 519
+_|_	 505
+e_	 477
+_p	 475
+dh	 475
+av	 469
+ak	 445
+aH	 444
+da	 440
+aH_	 439
+ay	 437
+j	 437
+_na	 432
+ana	 430
+hh	 428
+ti	 426
+ara	 425
+aa_	 410
+_k	 394
+shh	 389
+_v	 388
+_sa	 381
+.h	 379
+ah	 369
+_b	 368
+h_	 363
+.h_	 363
+cha	 362
+haa	 361
+_t	 358
+ri	 352
+sha	 345
+ap	 333
+vi	 330
+is	 329
+^	 321
+o_	 321
+_m	 320
+ai	 311
+_d	 311
+la	 302
+na_	 301
+.n	 298
+ava	 295
+al	 294
+_sh	 291
+ja	 288
+a.	 280
+aan	 277
+ish	 274
+aN	 273
+aya	 273
+ash	 266
+ha_	 265
+ga	 264
+st	 255
+ni	 255
+ii_	 254
+hu	 253
+Na	 253
+R	 248
+R^	 248
+^i	 247
+R^i	 247
+a.n	 243
+th	 241
+_c	 240
+_ch	 239
+maa	 238
+bha	 237
+vaa	 233
+ab	 228
+ir	 226
+\	 226
+ita	 223
+uu	 222
+dha	 220
+har	 218
+_a	 216
+_bh	 216
+nam	 212
+u_	 212
+he	 212
+m.h_	 211
+m.	 211
+m.h	 211
+ur	 210
+es	 209
+ata	 208
+te	 206
+yaa	 205
+_ma	 204
+esh	 202
+aka	 200
+id	 199
+pr	 199
+aha	 198
+hy	 198
+T	 197
+aat	 197
+_OM_	 196
+OM	 196
+_O	 196
+_OM	 196
+OM_	 196
+O	 196
+ti_	 195
+ari	 194
+raa	 193
+ag	 192
+_y	 192
+aas	 190
+_ta	 190
+_j	 189
+I	 189
+_na_	 187
+am.h_	 185
+am.h	 185
+am.	 185
+_pa	 183
+iv	 182
+de	 182
+ada	 178
+nd	 178
+_cha	 177
+_h	 176
+ati	 175
+taa	 173
+ev	 172
+nt	 171
+rii	 171
+ishh	 170
+ya_	 168
+_vi	 166
+ast	 165
+tr	 164
+abh	 164
+kh	 162
+ala	 160
+tha	 160
+apa	 160
+asa	 158
+naa	 158
+_nam	 156
+ru	 156
+A_	 155
+_ka	 154
+aar	 153
+_pr	 152
+_g	 151
+pra	 150
+ham	 150
+hha	 149
+aana	 149
+di	 149
+ra_	 147
+ik	 146
+.a	 144
+yat	 143
+ks	 143
+hA	 143
+hya	 143
+ksh	 143
+ut	 142
+sy	 141
+nama	 140
+_va	 140
+.\	 140
+paa	 140
+han	 139
+eva	 138
+U	 138
+mi	 138
+_r	 136
+_ja	 136
+asy	 135
+hr	 135
+sya	 134
+cha_	 132
+rv	 132
+tv	 130
+asya	 130
+kar	 130
+ho	 129
+yo	 129
+in	 128
+adh	 127
+yA	 127
+va_	 126
+su	 125
+_ya	 125
+shha	 124
+pu	 124
+R^it	 123
+sta	 123
+mu	 123
+^it	 123
+ty	 123
+_nama	 121
+ac	 120
+rii_	 120
+ach	 120
+aNa	 119
+tas	 119
+shi	 119
+iva	 119
+hav	 119
+tra	 118
+var	 118
+par	 118
+haM	 117
+aad	 117
+kaa	 117
+hch	 117
+mas	 117
+ai_	 117
+hc	 117
+sar	 116
+aam	 116
+_bha	 115
+_pra	 114
+et	 114
+haM_	 113
+aay	 113
+aj	 113
+ye	 113
+o.	 113
+An	 111
+arii	 111
+t.h	 110
+t.	 110
+ath	 110
+t.h_	 109
+man	 109
+te_	 108
+o.a	 108
+hara	 108
+rA	 108
+rva	 108
+tva	 108
+asta	 108
+up	 108
+shr	 107
+daa	 104
+me	 104
+dr	 104
+ram	 104
+arii_	 102
+_ni	 102
+arv	 102
+iH	 102
+hit	 101
+ras	 101
+aga	 101
+Am	 101
+mA	 101
+ba	 101
+amas	 100
+tu	 100
+yaM	 100
+ant	 99
+ud	 99
+uk	 98
+iH_	 98
+yaM_	 98
+kha	 98
+au	 98
+ira	 97
+shhT	 97
+rah	 97
+hT	 97
+hhT	 97
+D	 96
+_sar	 96
+re	 96
+eshh	 95
+sarv	 94
+amaa	 94
+and	 94
+arva	 94
+_ra	 93
+_dh	 93
+tt	 92
+tad	 92
+hm	 92
+raM_	 91
+dev	 91
+raM	 91
+C	 91
+ani	 91
+_sarv	 90
+atha	 89
+Ad	 89
+chi	 89
+tA	 88
+sarva	 88
+avi	 88
+taM	 87
+hava	 87
+anaa	 86
+vA	 86
+dd	 86
+nA	 85
+Ar	 85
+hv	 85
+taM_	 85
+dhi	 84
+ksha	 84
+ip	 84
+ma_	 84
+_sha	 84
+ati_	 83
+yai	 83
+vat	 83
+At	 83
+kR	 82
+kR^	 82
+bhi	 82
+_shr	 82
+to	 82
+ta_	 82
+br	 82
+ek	 82
+kR^i	 82
+tat	 81
+nta	 81
+hma	 81
+aaya	 80
+tam	 80
+en	 80
+us	 79
+bra	 79
+ke	 79
+kt	 79
+ddh	 79
+mo	 79
Index: /main/tags/2.25/gsdl/perllib/textcat/Other/scots.lm
===================================================================
--- /main/tags/2.25/gsdl/perllib/textcat/Other/scots.lm	(revision 21064)
+++ /main/tags/2.25/gsdl/perllib/textcat/Other/scots.lm	(revision 21064)
@@ -0,0 +1,400 @@
+_	 11688
+e	 3223
+a	 2469
+t	 2269
+i	 1928
+n	 1903
+r	 1414
+o	 1406
+h	 1369
+s	 1249
+l	 929
+n_	 890
+_t	 862
+_a	 843
+d	 818
+e_	 798
+th	 704
+w	 661
+he	 625
+an	 612
+t_	 606
+u	 592
+_th	 575
+c	 508
+s_	 471
+the	 470
+,	 469
+-	 458
+in	 455
+m	 445
+,_	 440
+b	 434
+g	 429
+er	 409
+ee	 408
+_the	 407
+k	 402
+an_	 402
+f	 385
+_w	 378
+he_	 376
+the_	 364
+_an	 362
+_o	 360
+y	 358
+_the_	 354
+_s	 353
+_an_	 342
+a_	 335
+r_	 327
+_b	 316
+d_	 303
+i_	 278
+en	 277
+p	 270
+ei	 245
+A	 236
+wa	 232
+_A	 231
+re	 229
+in_	 229
+ui	 218
+oo	 217
+le	 217
+ai	 216
+et	 212
+ti	 209
+it	 209
+_f	 206
+te	 204
+_a_	 203
+_m	 202
+ha	 200
+as	 193
+on	 188
+at	 184
+_i	 183
+_wa	 183
+_c	 182
+o_	 180
+or	 178
+_h	 176
+_g	 169
+ch	 165
+A_	 159
+_l	 158
+_A_	 157
+st	 156
+_d	 155
+_ti	 148
+.	 148
+._	 146
+ke	 144
+ti_	 143
+--	 143
+_o_	 142
+ow	 142
+---	 140
+ed	 138
+----	 138
+_r	 137
+as_	 137
+y_	 136
+er_	 136
+-----	 136
+ir	 135
+aa	 135
+la	 131
+een	 130
+ae	 129
+_ti_	 128
+ra	 126
+es	 125
+nd	 124
+de	 120
+h_	 120
+ie	 120
+ar	 119
+ll	 119
+nt	 118
+ot	 118
+en_	 115
+ma	 115
+eet	 113
+her	 112
+el	 112
+is	 112
+'	 112
+at_	 111
+ic	 109
+se	 108
+or_	 106
+wu	 104
+me	 104
+ne	 103
+fo	 102
+on_	 101
+was	 99
+_was	 98
+et_	 98
+ri	 98
+_e	 97
+_ma	 97
+v	 97
+_n	 97
+!	 97
+li	 97
+ht	 93
+hi	 92
+_wu	 92
+ng	 91
+ro	 91
+it_	 90
+ck	 90
+_fo	 90
+tha	 90
+k_	 89
+il	 89
+cht	 86
+eet_	 86
+_p	 86
+we	 86
+_was_	 85
+was_	 85
+rt	 84
+ed_	 83
+ter	 83
+id	 83
+ga	 82
+;	 82
+;_	 81
+ther	 79
+tt	 76
+air	 76
+e,	 75
+un	 75
+ho	 75
+for	 74
+ge	 74
+_st	 73
+_y	 72
+_he	 72
+wh	 71
+_on	 71
+sh	 70
+z	 70
+e,_	 69
+bi	 68
+_tha	 68
+wui	 67
+!_	 67
+ad	 67
+een_	 66
+l_	 66
+ts	 66
+_for	 66
+n,	 66
+_wh	 65
+re_	 65
+be	 65
+eh	 64
+hat	 64
+ns	 64
+br	 64
+g_	 64
+ui_	 64
+rr	 64
+wui_	 63
+ni	 63
+_wui	 62
+ay	 62
+s,	 62
+pe	 61
+n,_	 61
+bo	 61
+al	 61
+ye	 61
+_bi	 60
+oot	 60
+na	 60
+ang	 60
+s,_	 59
+es_	 59
+ill	 58
+that	 58
+_wui_	 58
+nn	 58
+eh_	 58
+oa	 57
+han	 57
+_that	 56
+_br	 56
+ca	 56
+_ga	 56
+ng_	 56
+um	 55
+hat_	 55
+oon	 55
+od	 55
+for_	 55
+no	 55
+ree	 55
+_for_	 54
+_le	 54
+ht_	 54
+ot_	 54
+_k	 53
+rd	 53
+ki	 53
+aw	 53
+nd_	 53
+_on_	 53
+_it	 53
+ik	 53
+t,	 53
+_be	 52
+that_	 52
+ve	 52
+rn	 52
+'s	 51
+au	 51
+co	 51
+ich	 51
+to	 51
+lo	 51
+t,_	 51
+ea	 51
+tee	 51
+lan	 50
+fi	 50
+_at	 50
+am	 50
+_in	 50
+ere	 50
+ur	 50
+le_	 50
+nt_	 49
+'s_	 49
+hin	 49
+yi	 49
+hr	 49
+ts_	 49
+_ca	 48
+"	 48
+ta	 48
+cht_	 48
+-_	 48
+_as	 47
+T	 47
+ang_	 47
+lei	 46
+_ma_	 46
+tr	 46
+_ro	 46
+fe	 46
+ma_	 46
+icht	 46
+_as_	 46
+der	 46
+cl	 46
+e-	 45
+n-	 45
+thr	 45
+ba	 45
+m_	 45
+st_	 45
+rt_	 45
+_u	 45
+do	 45
+_T	 45
+im	 44
+_se	 44
+sk	 44
+_la	 44
+eik	 44
+bit	 43
+ike	 43
+B	 43
+kee	 43
+tte	 43
+di	 43
+eed	 43
+_B	 42
+_aa	 42
+her_	 42
+da	 42
+ff	 42
+tu	 42
+ie_	 42
+_cl	 42
+_ba	 42
+oot_	 42
+bu	 41
+eike	 41
+oc	 41
+hu	 41
+_thr	 41
+ther_	 41
+_co	 41
+aa_	 41
+so	 41
+_me	 41
+H	 41
+_H	 40
+ke_	 40
+ert	 40
+lu	 40
+ist	 40
+si	 40
+iz	 40
+ar_	 39
+uc	 39
+thi	 39
+ad_	 39
+ru	 39
+owe	 39
+gi	 38
+_bit	 38
+_do	 38
+int	 38
+bl	 38
+ld	 38
+_at_	 38
+lt	 38
+ac	 38
+_ha	 38
+ae_	 38
+rs	 37
+here	 37
+ei_	 37
+han_	 37
+p_	 37
+is_	 37
+eth	 37
+fa	 37
+_sk	 37
+ll_	 37
+ss	 36
+bra	 36
+wha	 36
+gl	 36
+ck_	 36
+pl	 36
+lin	 36
+ir_	 36
+ab	 36
+_ther	 36
+_da	 35
+ce	 35
+rin	 35
+_oo	 35
+rl	 35
+wee	 35
+and	 35
+sa	 35
+_yi	 35
+_bra	 35
+'d	 35
+ds	 35
+_bo	 35
Index: /main/tags/2.25/gsdl/perllib/textcat/Other/scots_gaelic.lm
===================================================================
--- /main/tags/2.25/gsdl/perllib/textcat/Other/scots_gaelic.lm	(revision 21064)
+++ /main/tags/2.25/gsdl/perllib/textcat/Other/scots_gaelic.lm	(revision 21064)
@@ -0,0 +1,400 @@
+_	 12634
+a	 5353
+h	 3268
+i	 2898
+n	 2792
+e	 1651
+r	 1563
+d	 1455
+_a	 1425
+c	 1245
+n_	 1236
+s	 1165
+l	 1152
+an	 1121
+t	 980
+ai	 979
+g	 962
+u	 905
+ch	 902
+ha	 836
+h_	 833
+a_	 829
+ea	 821
+o	 794
+dh	 726
+an_	 711
+b	 639
+m	 585
+na	 514
+nn	 506
+ac	 498
+r_	 495
+s_	 482
+ir	 480
+ach	 466
+id	 458
+_an	 450
+_c	 427
+th	 403
+à	 388
+he	 383
+in	 379
+bh	 367
+idh	 358
+ad	 342
+_n	 341
+il	 332
+nn_	 323
+_t	 322
+_d	 319
+ar	 317
+e_	 311
+dh_	 307
+_an_	 303
+_b	 302
+_na	 294
+air	 289
+ig	 279
+.	 275
+ir_	 272
+ag	 272
+_ai	 272
+,	 270
+gu	 269
+,_	 269
+._	 265
+ean	 264
+ch_	 261
+f	 259
+?	 258
+_s	 255
+ann	 250
+ra	 241
+ei	 241
+_a_	 241
+ha_	 241
+d_	 238
+-	 235
+_m	 231
+gh	 230
+hea	 228
+le	 226
+_f	 224
+ui	 223
+is	 223
+as	 218
+adh	 218
+l_	 216
+g_	 208
+ài	 207
+ò	 207
+hai	 205
+cha	 205
+air_	 204
+na_	 201
+inn	 198
+tha	 190
+C	 189
+G	 188
+ann_	 187
+_ag	 186
+_air	 186
+eac	 185
+_g	 185
+_na_	 184
+ach_	 184
+_C	 183
+us	 183
+_ch	 183
+la	 182
+_G	 182
+each	 181
+us_	 178
+al	 178
+gus	 176
+gus_	 176
+_th	 169
+_air_	 168
+_agus	 167
+agus_	 167
+_agu	 167
+agus	 167
+agu	 167
+ta	 164
+aid	 163
+hi	 163
+hd	 163
+chd	 160
+T	 157
+A	 156
+ic	 152
+_T	 152
+adh_	 150
+idh_	 148
+mh	 147
+?_	 146
+ar_	 145
+oi	 144
+da	 143
+aidh	 143
+_bh	 139
+ean_	 138
+sa	 138
+ig_	 138
+_r	 136
+_A	 134
+ì	 134
+te	 134
+achd	 131
+hu	 131
+_e	 130
+aig	 130
+_l	 130
+_ann	 129
+ain	 127
+ne	 127
+dhe	 125
+_dh	 125
+àid	 123
+o_	 121
+hl	 119
+acha	 119
+ga	 118
+àidh	 118
+on	 118
+it	 117
+aidh_	 116
+de	 115
+nan	 115
+ua	 115
+_ann_	 115
+ich	 115
+il_	 114
+m_	 114
+eil	 114
+ri	 112
+at	 112
+ma	 111
+li	 109
+ao	 109
+re	 109
+inn_	 108
+_tha	 107
+fh	 106
+as_	 106
+bh_	 106
+nan_	 103
+lea	 103
+lt	 103
+S	 103
+a?	 103
+a?_	 102
+io	 102
+E	 101
+am	 101
+'	 100
+_a?	 100
+igh	 100
+_a?_	 99
+_gu	 99
+idhe	 99
+t_	 99
+se	 99
+si	 98
+ba	 97
+ù	 97
+tha_	 96
+bha	 95
+B	 94
+is_	 94
+u_	 94
+_B	 94
+_i	 93
+ile	 92
+aic	 91
+hei	 91
+ia	 90
+ho	 89
+Th	 88
+ath	 88
+_Th	 88
+rt	 87
+ib	 87
+Gàid	 86
+_Gài	 86
+_Gà	 86
+Gài	 86
+òr	 86
+Gà	 86
+Gàidh	 86
+_Gàid	 86
+had	 85
+ibh	 85
+_fh	 85
+p	 84
+ad_	 83
+_?	 83
+_E	 83
+hd_	 82
+dhea	 82
+chd_	 82
+ear	 81
+ith	 81
+_tha_	 80
+h-	 79
+eal	 78
+hean	 78
+sg	 77
+rea	 77
+_S	 76
+ais	 75
+ll	 75
+han	 74
+hà	 74
+achd_	 74
+ead	 74
+idhea	 73
+am_	 72
+dha	 72
+_nan	 71
+_nan_	 71
+hadh	 71
+gh_	 71
+ail	 70
+hui	 70
+Ch	 69
+eachd	 69
+h.	 69
+aich	 69
+hli	 69
+chai	 69
+om	 68
+fa	 68
+chad	 68
+I	 67
+h._	 67
+_Ch	 67
+tea	 67
+nea	 66
+chadh	 66
+achad	 66
+rai	 66
+lig	 66
+haid	 66
+dea	 66
+rt_	 65
+àr	 65
+dhl	 65
+ana	 64
+eann	 64
+Ei	 64
+le_	 64
+hn	 64
+ilt	 64
+uid	 64
+_fa	 63
+_Tha	 63
+Tha	 63
+ob	 63
+_si	 62
+ro	 62
+cu	 62
+ainn	 62
+un	 62
+dhli	 61
+idhli	 61
+lean	 61
+idhl	 61
+àidhl	 61
+hlig	 61
+dhlig	 61
+in_	 60
+_à	 60
+st	 60
+rr	 60
+_cu	 60
+hr	 60
+_aig	 60
+bhe	 59
+i_	 59
+aigh	 59
+Tha_	 59
+è	 59
+_ri	 59
+_Tha_	 59
+lb	 58
+che	 58
+ran	 58
+nac	 58
+haidh	 58
+hadh_	 58
+aig_	 58
+Gh	 58
+ilea	 58
+_Gh	 58
+lte	 58
+_le	 58
+ru	 58
+àidhe	 57
+_I	 57
+ilte	 57
+eadh	 57
+M	 56
+hlig_	 56
+L	 56
+chu	 56
+nach	 56
+_ma	 56
+lig_	 56
+h,_	 55
+th_	 55
+ibh_	 55
+_aig_	 55
+D	 55
+atha	 55
+_Ei	 55
+h,	 55
+gu_	 54
+_gu_	 54
+im	 54
+eil_	 54
+eu	 53
+_M	 53
+Al	 53
+irt	 53
+_L	 53
+iad	 53
+sea	 52
+lba	 52
+Alba	 52
+F	 52
+Alb	 52
+uai	 52
+ich_	 52
+_F	 51
+ilean	 51
+has	 51
+tai	 51
+each_	 50
+eacha	 50
+har	 50
+ni	 50
+_de	 50
+irt_	 50
+n,_	 50
+mha	 50
+n,	 50
+_e_	 50
+ide	 49
+neach	 49
+neac	 49
+ur	 49
+rd	 49
+_h	 49
+hean_	 49
+oc	 49
+eò	 49
+te_	 49
+han_	 49
+on_	 49
Index: /main/tags/2.25/gsdl/perllib/textcat/Other/serbian-ascii.lm
===================================================================
--- /main/tags/2.25/gsdl/perllib/textcat/Other/serbian-ascii.lm	(revision 21064)
+++ /main/tags/2.25/gsdl/perllib/textcat/Other/serbian-ascii.lm	(revision 21064)
@@ -0,0 +1,400 @@
+_	 34122
+a	 9113
+o	 8135
+i	 7736
+e	 7535
+n	 5207
+s	 4860
+j	 3995
+t	 3797
+r	 3660
+u	 3224
+l	 3065
+d	 3061
+e_	 2941
+v	 2786
+a_	 2746
+k	 2701
+m	 2492
+o_	 2328
+y	 2238
+p	 2151
+_s	 2148
+i_	 2094
+je	 1887
+c	 1854
+z	 1731
+_n	 1437
+_p	 1432
+g	 1418
+b	 1368
+u_	 1333
+je_	 1237
+,	 1226
+,_	 1214
+_i	 1130
+st	 1105
+na	 1076
+.	 1056
+_d	 1033
+._	 1030
+_j	 967
+ra	 934
+ko	 908
+ni	 900
+cy	 893
+sy	 875
+_je	 871
+_o	 824
+ta	 799
+no	 780
+_u	 777
+re	 766
+_b	 764
+_k	 763
+da	 760
+ne	 754
+li	 750
+ti	 745
+se	 722
+po	 713
+to	 713
+_je_	 696
+an	 688
+ja	 683
+pr	 665
+va	 651
+lo	 634
+_z	 626
+m_	 625
+is	 625
+il	 622
+ov	 621
+la	 621
+_m	 615
+bi	 604
+_t	 603
+_po	 594
+en	 586
+_se	 578
+os	 578
+in	 576
+od	 576
+ka	 552
+ve	 548
+ij	 538
+_pr	 536
+al	 536
+vo	 535
+om	 530
+_i_	 525
+nj	 515
+ed	 509
+_na	 507
+na_	 503
+og	 499
+oj	 498
+ma	 493
+_bi	 492
+on	 489
+ak	 482
+im	 481
+ye	 481
+ro	 480
+vi	 473
+sa	 469
+ri	 464
+da_	 451
+av	 450
+at	 449
+se_	 447
+es	 446
+h	 443
+ao	 441
+ji	 437
+yi	 436
+_da	 433
+ad	 432
+_se_	 430
+lj	 428
+zy	 426
+za	 426
+_ne	 425
+de	 422
+tr	 417
+cj	 415
+_u_	 414
+_c	 412
+le	 402
+_v	 397
+ar	 390
+_g	 390
+ic	 384
+n_	 382
+ju	 379
+lo_	 377
+aj	 376
+_ko	 369
+ao_	 366
+ek	 361
+_da_	 359
+et	 356
+go	 354
+iz	 346
+_za	 345
+_r	 344
+or	 342
+mo	 341
+el	 340
+as	 339
+ik	 336
+te	 332
+_sa	 329
+d_	 323
+am	 320
+me	 318
+sto	 317
+di	 315
+ec	 311
+ol	 310
+a,_	 307
+a,	 307
+_ni	 302
+ya	 296
+do	 295
+yt	 294
+su	 292
+syt	 289
+li_	 288
+sta	 286
+ije	 284
+ko_	 277
+ti_	 277
+la_	 277
+ga	 276
+bil	 275
+no_	 274
+a.	 273
+nu	 272
+a._	 271
+ne_	 271
+om_	 268
+_cy	 266
+_na_	 263
+_bil	 263
+sv	 263
+ru	 259
+to_	 256
+_od	 253
+cyi	 253
+nje	 251
+it	 251
+pa	 250
+az	 248
+e,_	 245
+e,	 245
+ob	 244
+dn	 243
+ac	 242
+ost	 242
+k_	 240
+iv	 239
+io	 238
+_su	 238
+_iz	 237
+ilo	 235
+_sv	 234
+_ka	 233
+koj	 231
+mi	 229
+im_	 229
+ije_	 227
+g_	 226
+em	 223
+su_	 223
+ih	 223
+ji_	 221
+kr	 220
+ut	 220
+_koj	 220
+V	 218
+_st	 218
+ye_	 217
+_l	 214
+_V	 213
+ovo	 211
+j_	 210
+uc	 208
+ja_	 208
+h_	 207
+nij	 206
+sk	 206
+ot	 203
+io_	 203
+gl	 203
+_do	 201
+ok	 200
+ns	 199
+ilo_	 199
+er	 197
+ih_	 195
+pre	 193
+ci	 193
+og_	 193
+ki	 192
+sl	 191
+t_	 189
+ni_	 189
+_a	 189
+vr	 188
+ati	 187
+_su_	 186
+nije	 181
+pro	 181
+be	 180
+yn	 179
+cye	 178
+ju_	 178
+ku	 177
+isy	 177
+ta_	 174
+sye	 172
+_tr	 172
+O	 172
+jen	 172
+_to	 171
+pi	 168
+_pre	 168
+S	 168
+ima	 167
+nije_	 167
+_mo	 166
+eg	 166
+e._	 164
+za_	 164
+e.	 164
+_pro	 164
+gov	 163
+N	 162
+dr	 162
+ako	 162
+tv	 162
+_S	 160
+P	 159
+ma_	 159
+_on	 159
+sp	 158
+nst	 158
+anj	 158
+dj	 157
+oc	 157
+_sy	 156
+ev	 155
+ce	 155
+lik	 154
+_nij	 153
+_N	 152
+ist	 151
+_P	 151
+_nije	 151
+-	 151
+ba	 150
+jed	 150
+sti	 150
+ova	 149
+_is	 148
+id	 148
+ton	 148
+ke	 147
+pos	 147
+od_	 147
+osy	 146
+Vi	 146
+ila	 145
+ins	 145
+bo	 145
+_Vi	 145
+ir	 144
+_za_	 144
+oz	 144
+ecj	 144
+cje	 143
+on_	 143
+zn	 142
+_O	 141
+us	 141
+i,	 141
+i,_	 141
+mu	 140
+inst	 140
+cya	 140
+oji	 139
+esy	 139
+icy	 139
+lja	 138
+_go	 138
+i.	 138
+_re	 137
+_bilo	 137
+edn	 137
+acy	 137
+rat	 137
+bilo	 137
+ali	 136
+ecy	 136
+ija	 135
+pri	 135
+ad_	 135
+lic	 135
+i._	 135
+Vins	 134
+Vin	 134
+ston	 134
+Vinst	 134
+ga_	 134
+nston	 134
+insto	 134
+nsto	 134
+_Vins	 133
+_Vin	 133
+zi	 132
+ran	 131
+le_	 130
+ili	 130
+bilo_	 130
+_pos	 129
+ila_	 129
+est	 128
+_ve	 128
+tre	 128
+zye	 127
+_nj	 127
+si	 126
+f	 126
+alo	 125
+ako_	 125
+tra	 125
+sa_	 125
+pu	 124
+ud	 124
+z_	 124
+_ra	 124
+iti	 124
+_de	 124
+odi	 123
+T	 123
+-_	 122
+o,_	 121
+o,	 121
+du	 121
+rs	 121
+B	 120
+ka_	 119
+red	 119
+_od_	 118
+an_	 118
+nu_	 118
+iko	 117
+dno	 117
+_pa	 117
+s_	 116
Index: /main/tags/2.25/gsdl/perllib/textcat/Other/slovak-ascii.lm
===================================================================
--- /main/tags/2.25/gsdl/perllib/textcat/Other/slovak-ascii.lm	(revision 21064)
+++ /main/tags/2.25/gsdl/perllib/textcat/Other/slovak-ascii.lm	(revision 21064)
@@ -0,0 +1,400 @@
+_	 20064
+a	 4991
+o	 4983
+e	 3838
+n	 3342
+i	 3317
+r	 2583
+s	 2501
+v	 2383
+t	 2325
+c	 1918
+k	 1912
+l	 1888
+d	 1736
+u	 1725
+p	 1543
+a_	 1527
+y	 1371
+m	 1339
+z	 1227
+h	 1194
+e_	 956
+_p	 881
+_s	 828
+o_	 814
+na	 809
+b	 808
+_v	 798
+j	 797
+.	 796
+ov	 795
+._	 785
+st	 687
+i_	 665
+,	 657
+,_	 657
+_n	 625
+ch	 623
+u_	 618
+ro	 617
+po	 598
+_o	 546
+ne	 529
+en	 520
+v_	 519
+_a	 516
+ra	 506
+pr	 488
+y_	 481
+od	 476
+_z	 467
+ie	 462
+ni	 448
+an	 447
+vy	 434
+to	 433
+h_	 431
+_na	 429
+re	 416
+ch_	 404
+ho	 401
+al	 399
+ci	 394
+va	 387
+na_	 386
+_pr	 385
+_d	 384
+_k	 378
+la	 377
+ko	 375
+do	 374
+_po	 373
+si	 353
+_t	 346
+_r	 337
+os	 336
+no	 334
+in	 328
+tr	 324
+om	 321
+_v_	 320
+ny	 319
+m_	 319
+ri	 317
+S	 306
+ac	 302
+sa	 300
+ti	 300
+_m	 298
+za	 298
+er	 291
+ia	 290
+ce	 290
+li	 289
+yc	 286
+ych	 285
+ed	 284
+at	 281
+ob	 281
+ak	 280
+_na_	 280
+il	 279
+_,	 279
+_,_	 279
+ok	 277
+sk	 268
+ych_	 265
+_c	 262
+mi	 261
+ol	 260
+me	 260
+l_	 259
+t_	 259
+ku	 258
+ta	 256
+le	 256
+_b	 254
+or	 252
+_a_	 250
+lo	 247
+oc	 246
+vo	 246
+es	 244
+ve	 242
+_vy	 240
+on	 238
+_sa	 231
+as	 231
+da	 230
+aj	 228
+av	 218
+el	 216
+ova	 216
+ic	 215
+ne_	 209
+_do	 208
+sa_	 207
+ka	 205
+_sa_	 204
+te	 203
+j_	 201
+_ro	 199
+P	 198
+_za	 196
+ky	 196
+_S	 195
+je	 194
+ar	 193
+_.	 193
+it	 192
+s_	 192
+em	 191
+ej	 191
+ur	 190
+ad	 189
+_o_	 187
+_._	 187
+ov_	 185
+de	 180
+_%	 179
+om_	 179
+%	 179
+_u	 174
+pre	 173
+dn	 173
+D	 172
+rok	 170
+ie_	 170
+sp	 169
+pri	 167
+_pre	 167
+am	 165
+-	 164
+ke	 164
+eh	 162
+oz	 161
+k_	 160
+ost	 160
+_j	 156
+f	 155
+zn	 153
+g	 152
+kt	 152
+ho_	 151
+eho	 151
+hod	 150
+ku_	 148
+is	 148
+zi	 147
+cn	 147
+eho_	 146
+ej_	 145
+az	 145
+tu	 145
+_pri	 144
+cen	 144
+_st	 143
+ma	 142
+ast	 141
+_ce	 140
+rov	 140
+la_	 138
+ot	 138
+nych	 135
+nyc	 135
+_ob	 133
+z_	 133
+nych_	 131
+N	 130
+li_	 129
+ani	 129
+co	 128
+nt	 128
+ny_	 127
+E	 125
+_ne	 124
+)	 123
+_(	 123
+sti	 123
+A	 123
+(	 123
+cho	 122
+vi	 122
+_sp	 122
+di	 120
+pa	 120
+n_	 119
+ju	 118
+ys	 117
+bo	 117
+_P	 116
+_tr	 115
+V	 114
+je_	 114
+ln	 114
+_i	 113
+ze	 113
+spo	 112
+_N	 112
+nd	 111
+nu	 111
+so	 111
+red	 110
+vn	 110
+kl	 110
+kov	 110
+_cen	 110
+_rok	 109
+tn	 109
+du	 109
+nc	 109
+ap	 109
+d_	 108
+van	 108
+ca	 108
+M	 108
+chod	 107
+ti_	 107
+U	 106
+_ak	 106
+ru	 105
+sta	 105
+ym	 105
+_-	 104
+et	 103
+_h	 102
+est	 102
+_je	 102
+nos	 101
+aci	 101
+us	 100
+dov	 100
+pod	 100
+_to	 100
+tor	 99
+uc	 99
+ras	 98
+ky_	 98
+_s_	 98
+_mi	 97
+*	 97
+uj	 97
+nost	 97
+vys	 97
+ovy	 97
+ez	 97
+oku	 96
+_V	 96
+op	 96
+bc	 96
+rast	 96
+se	 95
+B	 95
+roku	 95
+kto	 94
+ove	 94
+by	 94
+-_	 94
+_ko	 93
+obc	 92
+nie	 91
+ia_	 91
+ka_	 91
+*_	 90
+ali	 90
+lo_	 89
+ovan	 89
+to_	 88
+iz	 88
+_bo	 88
+_l	 88
+odo	 87
+bch	 87
+bchod	 87
+bcho	 87
+sl	 86
+st_	 86
+pred	 86
+C	 86
+pol	 85
+_pred	 85
+R	 85
+ik	 84
+uro	 84
+pi	 84
+ek	 84
+zo	 83
+eni	 83
+obch	 83
+cie	 83
+oku_	 83
+obcho	 83
+ns	 83
+roku_	 82
+ii	 82
+tv	 82
+ba	 82
+ent	 82
+_spo	 81
+tov	 81
+pe	 81
+kon	 80
+kc	 80
+ec	 80
+kci	 80
+ck	 80
+x	 79
+osti	 79
+_Sk	 79
+mi_	 79
+_in	 79
+Sk	 79
+sia	 79
+br	 78
+rh	 78
+val	 78
+olo	 77
+_pod	 77
+%_	 77
+_%_	 77
+bu	 77
+_f	 77
+iv	 77
+_obc	 77
+_obch	 77
+eb	 76
+str	 76
+nej	 76
+_D	 76
+ni_	 75
+ou	 75
+im	 75
+ena	 74
+tre	 74
+_A	 74
+mo	 74
+su	 74
+rz	 73
+_trh	 73
+trh	 73
+_U	 73
+al_	 73
+_ra	 73
+_e	 72
+_C	 72
+sti_	 72
+zv	 72
+te_	 72
+cno	 72
+oj	 72
+ktor	 71
+_roku	 71
+ocn	 71
+ina	 71
+sil	 71
+nov	 71
+alo	 71
+odn	 70
+nan	 70
+oh	 70
Index: /main/tags/2.25/gsdl/perllib/textcat/Other/slovak-windows1250.lm
===================================================================
--- /main/tags/2.25/gsdl/perllib/textcat/Other/slovak-windows1250.lm	(revision 21064)
+++ /main/tags/2.25/gsdl/perllib/textcat/Other/slovak-windows1250.lm	(revision 21064)
@@ -0,0 +1,400 @@
+_	 8202
+o	 2145
+a	 1912
+e	 1763
+i	 1491
+n	 1415
+r	 1256
+t	 1127
+v	 1080
+s	 1004
+k	 824
+d	 739
+p	 739
+l	 735
+m	 685
+c	 620
+u	 597
+h	 531
+a_	 467
+j	 449
+_p	 445
+z	 439
+e_	 412
+á	 402
+_v	 369
+.	 361
+_s	 359
+ov	 330
+b	 327
+st	 312
+y	 309
+pr	 307
+._	 300
+o_	 297
+í	 278
+,	 268
+,_	 260
+to	 258
+è	 256
+_a	 254
+ý	 253
+i_	 252
+_pr	 246
+ch	 242
+re	 233
+_z	 223
+ra	 220
+_n	 217
+ne	 214
+ie	 214
+po	 214
+en	 208
+ro	 205
+or	 204
+é	 199
+u_	 197
+an	 197
+ko	 194
+na	 189
+ni	 187
+va	 183
+	 182
+ú	 180
+os	 179
+v_	 176
+	 173
+_o	 171
+ho	 170
+ia	 168
+no	 166
+li	 166
+h_	 166
+ed	 164
+j_	 161
+om	 160
+_k	 160
+	 158
+ch_	 158
+ti	 155
+y_	 148
+m_	 147
+ej	 147
+_po	 145
+ci	 145
+_d	 140
+_	 139
+do	 138
+_t	 137
+_m	 134
+ri	 129
+mi	 129
+od	 128
+te	 124
+_a_	 124
+la	 122
+al	 121
+aj	 120
+ej_	 120
+vo	 119
+ol	 119
+in	 118
+ve	 117
+me	 117
+tr	 116
+sk	 116
+ova	 116
+S	 111
+er	 110
+ob	 110
+_na	 109
+ad	 107
+je	 106
+at	 104
+_v_	 103
+_r	 102
+ic	 101
+ých	 100
+pre	 100
+ýc	 100
+av	 98
+es	 96
+ta	 95
+dn	 94
+ho_	 94
+lo	 94
+é_	 93
+_pre	 93
+it	 93
+V	 92
+de	 92
+kt	 89
+ný	 89
+za	 88
+A	 87
+le	 86
+ých_	 86
+ok	 86
+ost	 85
+vi	 84
+ie_	 83
+ak	 82
+P	 82
+né	 81
+R	 80
+sa	 80
+as	 79
+èi	 78
+na_	 77
+a	 77
+í_	 77
+Ÿ	 76
+ar	 75
+di	 75
+_S	 74
+om_	 74
+_V	 73
+_do	 73
+_za	 72
+-	 72
+ck	 71
+vy	 71
+ka	 71
+f	 70
+tor	 70
+am	 70
+on	 70
+_-	 69
+_P	 69
+M	 68
+_i	 68
+_sa	 68
+nos	 68
+ní	 68
+ác	 67
+a_	 67
+sl	 66
+il	 66
+rá	 66
+_c	 66
+_b	 66
+_-_	 64
+sa_	 64
+-_	 64
+kto	 64
+_j	 64
+ani	 64
+kr	 64
+sti	 63
+ou	 63
+ot	 63
+ne_	 63
+_sa_	 62
+vý	 62
+_na_	 62
+red	 62
+ku	 61
+is	 61
+ná	 60
+ý_	 60
+so	 60
+sp	 60
+_st	 59
+g	 59
+tn	 59
+str	 58
+e	 58
+nt	 58
+et	 57
+pra	 57
+ke	 57
+ov_	 57
+_vy	 57
+_M	 57
+nej	 56
+tu	 56
+l_	 56
+_je	 56
+nie	 56
+èn	 56
+k_	 56
+pe	 56
+_h	 55
+oz	 55
+ú_	 55
+est	 55
+_è	 55
+va	 55
+ma	 54
+né_	 53
+tá	 53
+..	 53
+rí	 52
+ran	 52
+bo	 51
+nej_	 51
+ick	 51
+ti_	 51
+ia_	 51
+ktor	 51
+K	 51
+O	 51
+T	 51
+_ne	 51
+ou_	 50
+I	 50
+oc	 50
+to_	 50
+vn	 50
+sta	 50
+_.	 50
+da	 50
+éh	 49
+ého	 49
+N	 49
+_ro	 49
+_ko	 49
+ac	 49
+ek	 49
+li_	 49
+èa	 49
+rov	 49
+oj	 48
+s_	 48
+s	 48
+ého_	 48
+va_	 48
+je_	 48
+zá	 47
+ik	 47
+mo	 47
+mi_	 47
+si	 47
+_kto	 46
+_sp	 46
+_kt	 46
+E	 46
+_ktor	 46
+eb	 46
+nýc	 45
+_u	 45
+el	 45
+B	 45
+ných	 45
+pro	 45
+eni	 44
+_	 44
+em	 44
+kon	 44
+pa	 44
+ky	 44
+uj	 44
+e_	 44
+ova	 44
+cie	 44
+hr	 44
+ký	 44
+ných_	 43
+pred	 43
+zo	 43
+ln	 43
+oè	 43
+tov	 43
+nu	 43
+eè	 43
+íc	 42
+ál	 42
+ým	 42
+pri	 42
+_to	 42
+lá	 41
+ce	 41
+áv	 41
+eh	 41
+_pro	 41
+rav	 41
+kej	 41
+ns	 41
+ali	 41
+oli	 40
+á_	 40
+_pri	 40
+oh	 40
+ud	 40
+_ak	 40
+ent	 40
+eŸ	 40
+prav	 39
+_pred	 39
+i	 39
+zn	 39
+ny	 39
+ove	 39
+pol	 39
+ru	 39
+a,	 39
+ah	 39
+kej_	 39
+a,_	 38
+z_	 38
+aj_	 38
+r_	 38
+i	 38
+ova_	 38
+tre	 38
+pod	 37
+_zá	 37
+_ob	 37
+nost	 37
+sti_	 37
+van	 37
+up	 37
+osti	 36
+áci	 36
+_e	 36
+jú	 36
+co	 36
+_str	 36
+i	 36
+_ma	 36
+ut	 36
+nsk	 36
+by	 36
+_ve	 35
+ko_	 35
+de_	 35
+èia	 35
+_aj	 35
+_aj_	 35
+op	 35
+_pod	 34
+prí	 34
+_in	 34
+ez	 34
+odn	 34
+dne	 34
+Z	 34
+tra	 34
+bn	 34
+ád	 34
+_e_	 34
+_vo	 34
+èas	 34
+át	 34
+d_	 34
+ô	 34
+sto	 34
+ky_	 34
+ir	 33
+_z_	 33
+nie_	 33
+t	 33
+ven	 33
+i_	 33
+_s_	 33
+_B	 33
+e	 33
+ens	 33
+spo	 32
+eho	 32
+lad	 32
Index: /main/tags/2.25/gsdl/perllib/textcat/Other/slovenian-ascii.lm
===================================================================
--- /main/tags/2.25/gsdl/perllib/textcat/Other/slovenian-ascii.lm	(revision 21064)
+++ /main/tags/2.25/gsdl/perllib/textcat/Other/slovenian-ascii.lm	(revision 21064)
@@ -0,0 +1,400 @@
+_	 25262
+e	 6217
+a	 5964
+i	 5611
+o	 5538
+n	 4132
+s	 3349
+l	 3268
+r	 2913
+t	 2777
+j	 2672
+v	 2282
+k	 2175
+e_	 1958
+d	 1953
+p	 1786
+a_	 1700
+y	 1623
+m	 1559
+o_	 1542
+z	 1521
+i_	 1462
+_s	 1433
+je	 1383
+,	 1278
+,_	 1278
+b	 1230
+c	 1137
+_p	 1130
+_n	 1032
+je_	 997
+u	 986
+_j	 972
+g	 933
+_je	 877
+cy	 848
+_je_	 842
+_v	 793
+il	 786
+ni	 782
+st	 779
+na	 743
+ra	 726
+.	 723
+._	 716
+_z	 713
+in	 691
+_k	 685
+_b	 667
+al	 640
+h	 627
+po	 607
+ti	 584
+pr	 584
+ko	 584
+_d	 582
+el	 579
+n_	 579
+la	 577
+lo	 573
+l_	 571
+_t	 567
+se	 567
+ne	 562
+_i	 556
+no	 549
+en	 546
+_o	 534
+re	 524
+bi	 514
+li	 512
+ov	 496
+sy	 458
+_na	 457
+te	 453
+da	 451
+_po	 440
+_bi	 437
+ye	 436
+to	 424
+ri	 420
+an	 420
+_pr	 417
+ve	 410
+nj	 404
+ka	 403
+_m	 394
+le	 385
+ja	 377
+va	 374
+de	 374
+is	 371
+ed	 364
+v_	 362
+za	 361
+in_	 354
+bil	 353
+_se	 351
+aj	 347
+ga	 344
+ar	 343
+od	 339
+_in	 338
+_in_	 333
+tr	 332
+os	 332
+_bil	 332
+ta	 328
+vo	 327
+ki	 324
+ro	 324
+et	 320
+so	 315
+em	 313
+lo_	 311
+na_	 306
+av	 305
+ih	 305
+yi	 304
+h_	 295
+at	 294
+m_	 293
+ek	 292
+ol	 289
+se_	 289
+as	 284
+lj	 281
+_za	 277
+ob	 275
+om	 273
+me	 273
+zy	 272
+mi	 268
+eg	 265
+_v_	 263
+_g	 260
+or	 260
+es	 259
+_se_	 258
+do	 255
+ni_	 255
+ga_	 253
+oc	 251
+il_	 250
+vi	 249
+ak	 248
+no_	 243
+da_	 241
+pa	 240
+_ne	 238
+ot	 238
+_so	 238
+ocy	 237
+ya	 237
+la_	 234
+li_	 234
+ih_	 231
+_c	 229
+az	 229
+ik	 228
+on	 225
+ki_	 224
+go	 223
+im	 223
+sk	 223
+mo	 221
+cye	 219
+ti_	 217
+ji	 216
+_da	 216
+iz	 215
+ko_	 214
+ic	 213
+_l	 209
+u_	 209
+pre	 208
+_r	 208
+_ko	 208
+t_	 207
+z_	 206
+er	 206
+so_	 206
+ilo	 203
+r_	 201
+j_	 199
+ad	 195
+cyi	 193
+_na_	 193
+sa	 191
+ev	 191
+i,	 188
+i,_	 188
+it	 187
+sto	 186
+_da_	 184
+_ni	 183
+_so_	 182
+_ve	 182
+nje	 181
+a,	 181
+kr	 181
+a,_	 181
+dn	 177
+_st	 177
+di	 176
+ega	 176
+og	 174
+o,_	 174
+o,	 174
+ilo_	 172
+_ki	 171
+ma	 170
+-	 170
+ij	 169
+_cy	 169
+ost	 169
+e,	 168
+e,_	 168
+ne_	 168
+ok	 166
+ke	 165
+_pre	 165
+del	 165
+yn	 165
+al_	 165
+bo	 164
+_pa	 163
+_ki_	 163
+am	 159
+ns	 158
+ye_	 156
+sp	 155
+em_	 154
+_ka	 154
+_te	 153
+_iz	 152
+ega_	 151
+_ob	 150
+br	 149
+ec	 149
+pri	 148
+ap	 147
+ez	 147
+ali	 147
+raz	 144
+jo	 142
+to_	 141
+d_	 138
+a._	 137
+a.	 137
+cya	 137
+ova	 136
+anj	 136
+el_	 135
+V	 135
+si	 134
+sta	 134
+_pri	 132
+_to	 131
+_a	 130
+_bilo	 130
+bilo	 130
+oj	 129
+ecy	 128
+_od	 128
+gl	 128
+op	 127
+ju	 127
+rav	 126
+_u	 125
+s_	 125
+_V	 125
+ila	 125
+ce	 124
+_mo	 124
+ali_	 124
+ah	 122
+str	 122
+_sp	 121
+vr	 121
+aj_	 121
+_do	 121
+bilo_	 121
+N	 119
+iv	 117
+ru	 116
+vs	 116
+jal	 116
+pi	 115
+O	 115
+_z_	 113
+icy	 112
+k_	 112
+be	 112
+elo	 111
+dr	 110
+pra	 110
+sye	 110
+ved	 109
+rs	 108
+_tr	 108
+tv	 108
+oz	 108
+tn	 107
+_nj	 107
+le_	 107
+_N	 107
+_ni_	 106
+pa_	 106
+l,_	 105
+l,	 105
+ins	 105
+ako	 104
+ac	 104
+ist	 104
+ir	 104
+sl	 104
+ila_	 103
+nik	 103
+bi_	 103
+i.	 102
+i._	 102
+_vs	 102
+iti	 102
+_sy	 101
+P	 101
+val	 100
+ku	 100
+_P	 99
+pe	 99
+ala	 99
+bil_	 98
+eli	 98
+jen	 98
+ede	 98
+_zy	 98
+T	 96
+ja_	 96
+ran	 95
+_bo	 95
+S	 95
+ln	 95
+zn	 94
+nst	 93
+_pa_	 93
+_ra	 93
+_bil_	 93
+nil	 93
+ati	 92
+ej	 92
+ocyi	 92
+e.	 91
+_le	 91
+ud	 91
+nov	 91
+nja	 91
+sn	 91
+ar_	 91
+e._	 91
+kl	 91
+isy	 90
+zye	 90
+en_	 90
+sti	 90
+_ga	 90
+prav	 90
+_bi_	 90
+za_	 89
+lik	 89
+ton	 89
+kra	 88
+rt	 88
+W	 88
+_de	 88
+_ga_	 88
+M	 88
+ep	 87
+cyn	 87
+Wi	 87
+_S	 87
+ut	 87
+_W	 87
+inst	 87
+insto	 86
+ste	 86
+Wins	 86
+gov	 86
+nu	 86
+Win	 86
+_Wi	 86
+Winst	 86
+nsto	 86
+eti	 86
+ston	 86
+nston	 86
+_Win	 85
+_Wins	 85
+ili	 84
+bra	 83
+rat	 83
Index: /main/tags/2.25/gsdl/perllib/textcat/Other/slovenian-iso8859_2.lm
===================================================================
--- /main/tags/2.25/gsdl/perllib/textcat/Other/slovenian-iso8859_2.lm	(revision 21064)
+++ /main/tags/2.25/gsdl/perllib/textcat/Other/slovenian-iso8859_2.lm	(revision 21064)
@@ -0,0 +1,400 @@
+_	 10406
+a	 2828
+e	 2676
+i	 2458
+o	 2418
+n	 1814
+r	 1484
+v	 1253
+l	 1248
+s	 1228
+t	 1172
+j	 1107
+d	 1085
+k	 911
+p	 880
+a_	 823
+m	 763
+i_	 681
+e_	 678
+_p	 603
+o_	 566
+u	 521
+z	 516
+b	 456
+_s	 435
+je	 434
+,	 416
+,_	 411
+ni	 399
+è	 383
+_v	 372
+_d	 356
+pr	 355
+g	 345
+ra	 336
+_n	 332
+st	 323
+an	 313
+po	 303
+re	 301
+na	 295
+h	 287
+ov	 276
+_pr	 276
+li	 275
+al	 274
+_z	 270
+je_	 259
+la	 255
+¹	 253
+ne	 248
+en	 246
+ko	 244
+in	 237
+c	 234
+ti	 234
+v_	 234
+_po	 232
+no	 230
+ve	 230
+_k	 227
+_i	 224
+da	 224
+.	 221
+_j	 221
+ri	 220
+ja	 216
+_t	 214
+se	 213
+ed	 212
+._	 211
+em	 206
+te	 205
+za	 201
+od	 201
+av	 200
+lo	 196
+nj	 194
+_o	 194
+_je	 193
+il	 190
+or	 183
+ka	 181
+sk	 179
+_b	 178
+_je_	 178
+ih	 178
+n_	 177
+_za	 173
+h_	 171
+er	 171
+os	 171
+_na	 168
+va	 168
+ta	 164
+le	 163
+m_	 161
+ev	 157
+ij	 157
+ar	 157
+do	 155
+to	 155
+Ÿ	 154
+A	 153
+el	 150
+_m	 148
+ro	 147
+ol	 146
+_v_	 145
+aj	 145
+di	 143
+N	 142
+S	 142
+at	 140
+ih_	 139
+ki	 138
+de	 137
+_in	 135
+vo	 135
+ga	 134
+me	 131
+in_	 129
+vi	 129
+om	 127
+_in_	 125
+et	 124
+pre	 124
+O	 123
+bi	 120
+I	 119
+da_	 117
+ik	 117
+ma	 115
+E	 114
+so	 113
+bo	 112
+it	 112
+anj	 112
+eg	 110
+ni_	 109
+mi	 108
+ke	 108
+na_	 108
+u_	 108
+lj	 106
+iz	 105
+ob	 105
+_da	 103
+li_	 103
+is	 103
+im	 102
+red	 102
+_pre	 102
+dr	 100
+mo	 99
+P	 99
+_se	 99
+ji	 98
+r_	 97
+ad	 97
+pri	 97
+K	 97
+_l	 97
+tr	 95
+pa	 94
+no_	 94
+j_	 92
+ki_	 91
+ti_	 91
+_pri	 91
+dn	 89
+_P	 88
+ej	 88
+_da_	 87
+ne_	 86
+ega	 86
+_r	 86
+_bi	 86
+l_	 86
+em_	 86
+go	 86
+"	 85
+sl	 85
+ek	 84
+ali	 84
+ove	 84
+aè	 84
+ak	 84
+ci	 83
+ga_	 83
+ko_	 83
+se_	 82
+_S	 82
+jo	 81
+ot	 81
+ja_	 81
+_so	 80
+lov	 80
+L	 80
+D	 79
+V	 79
+as	 78
+_do	 78
+am	 78
+nje	 77
+es	 77
+za_	 77
+_pa	 76
+T	 75
+tu	 75
+_za_	 74
+sti	 74
+_dr	 74
+la_	 74
+_N	 74
+_de	 74
+ega_	 73
+_ko	 73
+og	 73
+ns	 72
+èe	 72
+ds	 72
+_bo	 71
+ora	 71
+vn	 71
+ost	 71
+_ne	 71
+iè	 70
+ven	 69
+z_	 69
+èi	 69
+_te	 68
+ce	 68
+_se_	 67
+èa	 67
+oè	 67
+M	 66
+_u	 66
+un	 65
+ln	 65
+pos	 64
+ju	 64
+sta	 64
+op	 64
+di_	 63
+ud	 63
+vs	 63
+t_	 62
+nsk	 62
+tv	 62
+on	 62
+ski	 62
+R	 62
+pa_	 62
+_ka	 62
+i,	 61
+so_	 61
+_iz	 60
+_pa_	 60
+s_	 60
+i,_	 60
+pro	 59
+del	 59
+rav	 59
+eni	 59
+oli	 58
+rj	 58
+e,	 57
+¹e	 57
+ili	 57
+vr	 57
+d_	 57
+_le	 57
+pred	 57
+jo_	 56
+e,_	 56
+nik	 56
+love	 56
+_pred	 56
+ske	 56
+er_	 55
+str	 55
+èn	 54
+pra	 54
+J	 54
+_¹	 54
+oven	 53
+_ra	 53
+tn	 53
+_na_	 53
+_so_	 53
+nih	 53
+loven	 53
+si	 52
+ke_	 52
+_g	 52
+ic	 52
+udi	 51
+bi_	 51
+eds	 51
+oj	 51
+ru	 51
+a,	 51
+_pro	 50
+_pos	 50
+nc	 50
+nih_	 50
+èu	 50
+a,_	 50
+_a	 50
+az	 50
+ok	 50
+B	 50
+let	 49
+udi_	 49
+_od	 49
+_K	 49
+aj_	 48
+_bi_	 48
+_ve	 48
+raè	 48
+o,	 47
+_tu	 47
+ija	 47
+ter	 47
+ist	 47
+Z	 47
+reds	 46
+nd	 46
+ali_	 46
+A_	 46
+iti	 46
+bil	 46
+_ob	 46
+o,_	 46
+ati	 46
+tud	 45
+tudi	 45
+_ki	 45
+k_	 45
+be	 45
+a¹	 45
+ir	 45
+Ÿa	 45
+do_	 45
+sp	 45
+_ki_	 45
+_st	 45
+ep	 44
+_del	 44
+tudi_	 44
+rŸ	 44
+aèu	 44
+_ni	 44
+ah	 43
+raèu	 43
+raèun	 43
+i¹	 43
+_mo	 43
+avn	 43
+_tud	 43
+èun	 43
+aèun	 43
+_tudi	 43
+_to	 42
+raz	 42
+kr	 42
+ova	 42
+_e	 42
+ogo	 42
+ani	 42
+_"	 42
+ev_	 42
+br	 42
+eb	 42
+sa	 42
+mi_	 42
+tem	 42
+ta_	 41
+prav	 41
+i.	 41
+slov	 41
+ens	 41
+bo_	 41
+Ÿe	 41
+_T	 41
+_let	 41
+odo	 41
+slo	 41
+ensk	 40
+ka_	 40
+neg	 40
+ez	 40
+nos	 40
+eè	 40
+_sl	 40
+_V	 40
+rŸa	 40
+nega	 40
+ili_	 39
Index: /main/tags/2.25/gsdl/perllib/textcat/Other/swahili.lm
===================================================================
--- /main/tags/2.25/gsdl/perllib/textcat/Other/swahili.lm	(revision 21064)
+++ /main/tags/2.25/gsdl/perllib/textcat/Other/swahili.lm	(revision 21064)
@@ -0,0 +1,400 @@
+_	 16483
+a	 9342
+i	 5293
+a_	 4071
+u	 2730
+k	 2609
+n	 2351
+w	 2076
+m	 1928
+e	 1866
+h	 1800
+o	 1775
+wa	 1743
+l	 1486
+s	 1419
+i_	 1401
+t	 1399
+_k	 1306
+y	 1100
+_w	 969
+li	 945
+wa_	 911
+z	 891
+_wa	 890
+ka	 834
+ku	 799
+r	 770
+b	 733
+an	 727
+ma	 723
+o_	 711
+_m	 707
+na	 698
+ya	 675
+ha	 672
+g	 602
+al	 580
+d	 570
+at	 560
+am	 554
+_n	 549
+_ku	 549
+ik	 543
+_h	 515
+ya_	 514
+A	 494
+is	 487
+_y	 485
+hi	 474
+na_	 471
+_ya	 471
+ta	 468
+sh	 456
+ali	 449
+j	 426
+u_	 423
+ki	 418
+e_	 402
+p	 401
+ti	 401
+_wa_	 399
+f	 392
+_ya_	 390
+ba	 390
+ri	 385
+ng	 385
+il	 380
+c	 358
+hu	 356
+_na	 356
+ni	 355
+za	 354
+zi	 351
+ia	 344
+_na_	 343
+_a	 336
+in	 327
+_ma	 326
+ch	 322
+mb	 317
+ika	 314
+.	 311
+._	 309
+_ka	 307
+as	 306
+ak	 306
+ati	 301
+,	 300
+ka_	 296
+,_	 294
+_u	 292
+kw	 286
+ili	 278
+K	 274
+en	 271
+si	 266
+_kw	 262
+la	 261
+ni_	 261
+ma_	 261
+_s	 258
+kwa	 258
+ar	 256
+ut	 245
+za_	 245
+nd	 242
+mba	 241
+_kwa	 239
+_z	 234
+li_	 233
+un	 233
+ny	 230
+it	 229
+se	 229
+yo	 227
+ia_	 222
+M	 221
+sa	 221
+kat	 217
+_K	 214
+_i	 213
+ika_	 213
+ana	 212
+ish	 212
+kati	 206
+_ha	 204
+on	 201
+ai	 200
+I	 198
+aa	 196
+um	 195
+im	 190
+v	 188
+mu	 187
+amb	 187
+sha	 185
+em	 183
+fa	 181
+zi_	 180
+di	 179
+mi	 178
+_M	 178
+us	 176
+_ki	 176
+ha_	 175
+iw	 172
+ama	 172
+_kat	 168
+_kati	 168
+_hi	 166
+_l	 166
+ra	 166
+kwa_	 165
+la_	 164
+W	 164
+ja	 163
+U	 163
+N	 163
+amba	 161
+ao	 161
+_za	 160
+ji	 160
+B	 157
+iwa	 155
+tik	 155
+wal	 155
+le	 155
+tika	 154
+ge	 153
+lis	 153
+tu	 152
+atika	 152
+to	 152
+atik	 152
+uw	 152
+_kwa_	 151
+A_	 151
+ke	 150
+S	 147
+tika_	 145
+aj	 145
+we	 144
+cha	 144
+bi	 141
+az	 140
+er	 139
+ek	 138
+katik	 138
+ez	 138
+uwa	 137
+kut	 135
+_al	 134
+_B	 134
+ad	 134
+mu_	 133
+_ali	 133
+rik	 132
+_W	 131
+ba_	 131
+kuw	 131
+me	 130
+ali_	 128
+kuwa	 128
+ema	 127
+wan	 127
+bu	 126
+sem	 126
+_A	 125
+ir	 125
+ata	 125
+iz	 124
+_hu	 124
+ay	 124
+ul	 124
+af	 123
+iki	 122
+ema_	 121
+da	 120
+ti_	 120
+sema	 119
+aka	 118
+sema_	 118
+te	 118
+uz	 117
+yo_	 117
+_v	 117
+io	 116
+iy	 115
+uta	 115
+ani	 115
+_wal	 115
+he	 115
+if	 114
+_la	 114
+ab	 114
+go	 112
+_za_	 111
+ama_	 111
+sa_	 111
+pa	 110
+_t	 110
+zo	 110
+nge	 110
+wam	 109
+wali	 108
+ua	 107
+ur	 106
+_c	 106
+ise	 105
+_ch	 105
+isem	 105
+ho	 105
+ye	 104
+iyo	 104
+E	 104
+el	 104
+mo	 103
+ung	 103
+eri	 103
+_wali	 103
+_b	 102
+mba_	 102
+ari	 101
+ita	 101
+isema	 100
+ot	 99
+_la_	 99
+uk	 99
+ao_	 99
+di_	 99
+sha_	 99
+ini	 99
+kuwa_	 98
+uwa_	 98
+ana_	 98
+lise	 98
+lisem	 98
+uli	 97
+shi	 97
+ga	 96
+iwa_	 96
+fu	 96
+T	 96
+R	 95
+_il	 95
+wak	 94
+aw	 94
+isha	 94
+ri_	 93
+_am	 93
+ara	 92
+_cha	 92
+aji	 92
+_ili	 91
+ifa	 91
+O	 90
+_p	 90
+uh	 90
+iri	 90
+chi	 90
+asi	 89
+po	 89
+a.	 89
+ong	 89
+azi	 88
+_j	 88
+_kut	 88
+eny	 88
+nc	 88
+a._	 88
+ko	 87
+uu	 87
+id	 87
+w_	 87
+no	 87
+P	 86
+ah	 86
+ina	 86
+rika	 86
+_Bw	 85
+H	 85
+gu	 85
+uo	 85
+Bw_	 85
+_Bw_	 85
+_se	 85
+Bw	 85
+ib	 84
+_S	 84
+kam	 84
+hi_	 84
+nya	 84
+si_	 83
+a,	 82
+no_	 81
+pi	 81
+ok	 81
+i.	 81
+ip	 81
+kwam	 81
+i._	 81
+amba_	 80
+dh	 80
+end	 80
+ani_	 80
+a,_	 79
+wamb	 79
+kwamb	 79
+_sh	 79
+eza	 79
+nz	 79
+wi	 79
+_kwam	 79
+wamba	 79
+alis	 78
+_kuw	 78
+ngo	 78
+ap	 77
+_N	 77
+any	 77
+ili_	 77
+C	 77
+WA	 76
+vy	 76
+wana	 76
+_hiy	 75
+Wa	 75
+hiyo	 75
+nch	 75
+_hiyo	 75
+de	 75
+_kuwa	 75
+ing	 75
+hiy	 75
+vi	 75
+isha_	 74
+es	 74
+atu	 74
+_Wa	 74
+nchi	 74
+aki	 74
+lim	 73
+da_	 73
+ini_	 73
+ash	 73
+ala	 73
+i,	 73
+ano	 73
+i,_	 72
+_kam	 71
+_wan	 71
+ano_	 71
+mw	 71
+nde	 71
+ji_	 71
+ion	 70
+_amb	 70
+ndi	 70
+_Ka	 70
+eza_	 70
Index: /main/tags/2.25/gsdl/perllib/textcat/Other/tagalog.lm
===================================================================
--- /main/tags/2.25/gsdl/perllib/textcat/Other/tagalog.lm	(revision 21064)
+++ /main/tags/2.25/gsdl/perllib/textcat/Other/tagalog.lm	(revision 21064)
@@ -0,0 +1,400 @@
+_	 10664
+a	 6092
+n	 3421
+i	 2332
+g	 2149
+ng	 1488
+an	 1332
+g_	 1308
+ng_	 1243
+t	 1155
+a_	 1138
+o	 1137
+l	 1105
+s	 1067
+k	 1035
+_n	 957
+m	 909
+y	 801
+ang	 787
+u	 767
+ang_	 683
+p	 682
+na	 670
+_a	 634
+la	 596
+.	 572
+in	 561
+r	 559
+sa	 545
+_s	 502
+._	 487
+ma	 476
+ka	 473
+_na	 464
+b	 462
+_m	 458
+al	 448
+d	 445
+pa	 414
+n_	 412
+at	 394
+ak	 393
+h	 378
+ya	 358
+_k	 356
+ag	 350
+ni	 344
+_p	 339
+_sa	 335
+o_	 328
+ta	 308
+_an	 307
+iy	 300
+sa_	 296
+_ang	 294
+_ang_	 293
+t_	 290
+ay	 286
+ga	 283
+on	 280
+it	 275
+_sa_	 265
+ala	 258
+_ng	 256
+am	 252
+_i	 248
+_pa	 248
+i_	 243
+na_	 243
+an_	 240
+e	 239
+_ma	 237
+_ka	 235
+iya	 231
+y_	 229
+il	 228
+li	 228
+w	 226
+_ni	 225
+_na_	 224
+_ng_	 220
+as	 214
+ba	 207
+si	 206
+"	 195
+ti	 195
+ha	 186
+,	 179
+ar	 178
+ing	 173
+ra	 173
+A	 172
+ki	 168
+ong	 167
+_b	 167
+ap	 166
+,_	 162
+ong_	 161
+ko	 159
+ay_	 159
+un	 157
+ul	 155
+yo	 154
+to	 152
+_l	 150
+ah	 148
+is	 147
+hi	 147
+_t	 146
+lan	 145
+ama	 142
+niy	 139
+at_	 138
+_niy	 138
+aka	 136
+wa	 136
+niya	 135
+_niya	 135
+ab	 134
+-	 134
+di	 133
+_si	 132
+"_	 131
+aw	 129
+_d	 126
+_A	 126
+yan	 123
+ya_	 122
+ata	 120
+a.	 120
+gi	 120
+P	 120
+ing_	 118
+um	 115
+o.	 113
+aki	 113
+ri	 113
+ik	 112
+nd	 112
+ila	 111
+mo	 110
+da	 110
+a._	 110
+in_	 109
+la_	 107
+ali	 106
+S	 106
+man	 105
+ig	 105
+iya_	 105
+s_	 104
+_ak	 104
+_at	 103
+_h	 102
+yon	 102
+asa	 101
+ina	 101
+_P	 101
+n.	 99
+N	 98
+aa	 98
+ga_	 97
+_mo	 97
+_ba	 97
+_"	 95
+ito	 94
+bi	 94
+yang	 94
+n._	 93
+pag	 92
+lang	 92
+yang_	 92
+_la	 92
+o._	 90
+K	 90
+_at_	 90
+tu	 88
+_S	 88
+ara	 87
+nga	 87
+ro	 85
+apa	 83
+rr	 82
+lam	 82
+lo	 81
+nan	 81
+_N	 80
+aman	 79
+aha	 78
+mg	 78
+mga	 78
+mga_	 78
+_mga_	 78
+_mg	 78
+_mga	 78
+_K	 78
+siy	 77
+kan	 76
+it_	 76
+san	 76
+d_	 75
+ad	 75
+di_	 74
+tin	 74
+'	 74
+ati	 73
+siya	 73
+kin	 72
+M	 72
+lang_	 71
+mo_	 70
+_mo_	 70
+ako	 70
+uma	 70
+_pag	 69
+pi	 69
+l_	 68
+_siy	 68
+rrr	 68
+_siya	 67
+ula	 67
+_M	 66
+Pa	 66
+iyo	 66
+mi	 66
+bu	 66
+mu	 65
+no	 65
+pu	 65
+nag	 65
+ung	 65
+Na	 65
+ot	 64
+_Na	 64
+niya_	 64
+iyan	 64
+ku	 64
+k_	 63
+go	 62
+awa	 62
+ip	 61
+_Pa	 61
+lu	 61
+_di	 60
+pan	 60
+_ta	 60
+ini	 60
+isa	 60
+nt	 60
+iyang	 60
+_iyo	 59
+_iy	 59
+on_	 59
+tan	 59
+mang	 59
+aba	 59
+gan	 59
+ut	 58
+I	 58
+hin	 58
+nak	 58
+an.	 57
+akin	 57
+_r	 57
+han	 57
+Ka	 57
+_ay	 57
+_ako	 56
+may	 56
+iyon	 56
+rrrr	 55
+Sa	 55
+aga	 55
+to_	 55
+nit	 55
+_ko	 54
+er	 54
+ib	 54
+ari	 54
+ana	 54
+ili	 54
+an._	 54
+ahi	 54
+au	 54
+ala_	 54
+gk	 53
+pa_	 53
+_is	 53
+rin	 53
+ilan	 52
+_kan	 52
+_Ka	 52
+_it	 52
+_Sa	 51
+king	 51
+ko_	 51
+_nak	 51
+gin	 51
+_ay_	 50
+bo	 50
+_iyon	 50
+amang	 50
+'y	 49
+os	 49
+mang_	 49
+_pa_	 49
+kat	 49
+a,	 49
+An	 48
+Ma	 48
+ny	 48
+mag	 48
+_ku	 48
+_ito	 48
+_ha	 47
+yong	 47
+?	 47
+aking	 47
+T	 47
+ni_	 47
+yong_	 47
+_An	 47
+king_	 47
+_akin	 46
+sang	 46
+_nag	 46
+kas	 46
+_aki	 46
+_ni_	 46
+ayo	 45
+kit	 45
+'y_	 45
+mat	 45
+_Ma	 45
+lal	 45
+ot_	 45
+nya	 44
+ban	 44
+ndi	 44
+oo	 44
+_u	 44
+ngi	 44
+_hi	 44
+sang_	 44
+B	 43
+su	 43
+may_	 43
+rrrrr	 43
+p_	 43
+ita	 43
+wal	 43
+ika	 43
+abi	 43
+aan	 43
+_may	 43
+lama	 42
+naka	 42
+mal	 42
+_I	 42
+_ri	 42
+alan	 42
+any	 42
+im	 42
+_pu	 42
+ai	 42
+wala	 41
+anya	 41
+a,_	 41
+_B	 41
+ndi_	 41
+as_	 41
+pat	 41
+po	 41
+nang	 41
+_mag	 41
+laman	 40
+lala	 40
+kal	 40
+g-	 40
+..	 40
+ir	 40
+!	 40
+uk	 40
+gu	 39
+ito_	 39
+ro_	 39
+_g	 39
+_da	 39
+_isa	 39
+_lam	 39
+ilang	 39
+kanya	 39
+w_	 39
+kany	 39
+agk	 38
+pal	 38
+ka_	 38
+_naka	 38
+siya_	 38
+isan	 38
Index: /main/tags/2.25/gsdl/perllib/textcat/Other/tamil.lm
===================================================================
--- /main/tags/2.25/gsdl/perllib/textcat/Other/tamil.lm	(revision 21064)
+++ /main/tags/2.25/gsdl/perllib/textcat/Other/tamil.lm	(revision 21064)
@@ -0,0 +1,400 @@
+_	 11468
+Õ	 2697
+Ô	 2533
+Ž	 1960
+»	 1786
+œ	 1249
+Â	 1103
+Ù	 990
+£	 976
+Ø	 849
+¡	 847
+š	 831
+¿	 821
+À	 794
+Ÿ	 758
+§	 750
+Á	 721
+¹	 715
+¶	 713
+.	 702
+£_	 671
+×	 655
+â	 648
+Æ	 625
+._	 611
+ç	 601
+Å	 571
+¯	 557
+»Õ	 556
+É	 524
+_É	 520
+¢	 518
+_œ	 492
+Ç	 489
+_×	 488
+Þ	 484
+_Ç	 482
+€	 461
+Ä	 442
+Œ	 418
+ÿ	 416
+¥	 403
+§_	 398
+œÔ	 373
+_Ø	 368
+ª	 360
+Í	 359
+_Í	 349
+»Ô	 348
+ŽÕ	 342
+à	 337
+_Â	 331
+õ	 331
+š_	 323
+_Œ	 321
+¡Ž	 320
+_Ž	 310
+Õ¿	 308
+Ü	 299
+¢»	 294
+Ó	 292
+ŽÔ	 292
+ÿ»	 290
+Õ§	 288
+¡Þ	 284
+â_	 279
+ý	 271
+õŽ	 266
+ÂÕ	 265
+_»	 265
+ŸÔ	 241
+_Ÿ	 234
+Žª	 232
+=	 231
+±	 229
+€œ	 227
+==	 221
+¶Õ	 218
+»_	 218
+Õ§_	 213
+===	 211
+Õ_	 210
+====	 201
+ª_	 199
+Ž_	 198
+ÀÕ	 197
+=====	 191
+,	 188
+Øœ	 188
+¿Õ	 187
+º	 186
+_¶	 184
+,_	 184
+Ã	 183
+Ô¯	 181
+¿_	 179
+Ôš	 178
+å	 172
+Žª_	 171
+ì	 169
+ÙÁ	 168
+¢»Õ	 165
+¿Ô	 165
+Ô_	 165
+ç¡	 164
+È	 161
+Þ_	 160
+Íš	 160
+_Íš	 157
+«	 156
+_È	 156
+§Á	 152
+ÔŽ	 152
+Ù»	 151
+Ð	 150
+_Ð	 149
+ä	 149
+ö	 146
+ÕÅ	 146
+ØœÔ	 145
+¯Ž	 143
+Ö	 142
+×¶	 142
+ÁÔ	 142
+œÕ	 140
+Á_	 139
+Ô§	 138
+_Éç	 138
+Éç	 138
+¶Ô	 137
+Õš	 137
+Æ_	 136
+¢â	 133
+_×¶	 132
+ÔÆ	 128
+¡ŽÕ	 128
+ÀÔ	 127
+¥¹	 127
+_Ë	 127
+Ë	 127
+_Øœ	 127
+ÕÀ	 125
+öÓ	 125
+ÄÕ	 124
+ÆÔ	 122
+ÅÕ	 121
+Þ£	 120
+Õç	 119
+ŒÔ	 119
+×œ	 119
+ŽÙ	 119
+_å	 118
+¯_	 118
+£.	 117
+ŽÕÅ	 116
+»Õ¿	 115
+ÂÔ	 115
+_ÂÕ	 113
+â.	 113
+×»	 113
+£._	 112
+¡Þ_	 112
+ÕÙ	 111
+Õ¡	 111
+ÙÄ	 109
+×Ž	 109
+é	 109
+â._	 108
+_œÔ	 107
+ÕŽ	 106
+€_	 105
+ÆÕ	 104
+'	 104
+œ¹	 103
+ç_	 102
+¹Ô	 102
+ØŽ	 101
+ŒÕ	 100
+Éÿ	 100
+_Éÿ	 99
+_×»	 99
+ÔÀ	 98
+Éÿ»	 98
+æ	 98
+_×œ	 97
+Å_	 97
+Ô»	 97
+_Éÿ»	 97
+Ôš_	 97
+¹_	 97
+ß	 96
+±Å	 96
+×ŽÔ	 96
+»Ôš	 95
+¡Þ£	 94
+Õ¿_	 94
+Ø»	 94
+ø	 94
+ØÂ	 93
+í	 93
+_ØœÔ	 93
+ŸÕ	 93
+Õš_	 92
+ÿ»_	 91
+ÁÕ	 91
+_Éç¡	 90
+Éç¡	 90
+Ðç	 90
+ÕÆ	 90
+_Ðç	 90
+ÿ»Õ	 90
+Ù¹	 89
+_ŽÔ	 89
+_Ðç_	 88
+_ŒÔ	 88
+Ðç_	 88
+ì_	 86
+ç¡Ž	 86
+ÅÔ	 86
+ÿâ	 85
+¥à	 85
+¯Žª	 84
+šÆ	 84
+šì	 83
+Ô¥	 83
+÷	 83
+_Þ	 83
+ŽÄ	 82
+à_	 81
+ÔŽ_	 81
+š.	 80
+_ŸÔ	 80
+¿Õ§	 80
+²	 80
+ÕÁ	 80
+Ä_	 79
+ŽÙÄ	 79
+_œ¹	 79
+šÅ	 79
+Ô£	 79
+«¶	 78
+¡_	 78
+š._	 77
+_¶Õ	 77
+§ÁÔ	 77
+_ŒÕ	 77
+ë	 77
+Åâ	 76
+Þ£_	 75
+ÔÆ_	 75
+ÙŸ	 75
+Â¯	 75
+ÙÂ	 74
+çÿ	 73
+ýà	 72
+è	 72
+šì_	 71
+Ô§_	 71
+Žë	 71
+¥Ü	 71
+§Ù	 70
+»Õ§	 70
+§ÙÁ	 70
+£œ	 69
+Ù»_	 69
+ªÄ	 69
+ç¡Þ	 69
+Ó_	 68
+Ôõ	 68
+ØŸ	 67
+_ØŽ	 67
+Õ¢	 66
+ÄÔ	 66
+»Ôš_	 66
+à£	 66
+_Ç»	 66
+Ç»	 66
+Ô¹	 66
+Î	 66
+¿Õ§_	 65
+Ôâ	 65
+_»Õ	 64
+¯.	 64
+¹¢	 63
+Õ¥	 63
+Ô¡	 63
+_×Ž	 63
+_Î	 63
+ÙŽ	 62
+ŽÄÕ	 62
+Õ¿Ô	 62
+¯._	 61
+Éÿ»Õ	 61
+_œÕ	 61
+_×»Ô	 61
+×»Ô	 61
+ÔõŽ	 61
+œ¥	 60
+ÿ»Õ¿	 60
+_ä	 60
+_Éÿ»Õ	 60
+ÔŸ	 60
+Ôç	 59
+×¶Ô	 59
+¡Þ£_	 59
+€ä	 59
+_ÇÙ	 58
+ÿâ_	 58
+ÙÅ	 58
+ÇÂ	 58
+ÇÙ	 58
+Éÿ»Õ¿	 58
+ºÕ	 58
+»À	 57
+œÔ¯	 57
+¹£	 57
+ýº	 57
+_ÇÂ	 57
+æ£	 56
+ÔÁ	 56
+_×¶Ô	 55
+?	 55
+ý¹	 54
+ÃÕ	 54
+ÙÆ	 54
+»Õç	 54
+_×ŽÔ	 54
+ŽÕÅâ	 53
+»Õ¿_	 53
+_À	 53
+ÕÅâ	 53
+¡ŽÕÅ	 53
+ç¡ŽÕ	 52
+ÇÀ	 52
+ÙÄ_	 52
+×Â	 51
+Ü_	 51
+'_	 51
+_ÇÀ	 51
+ÔÂ	 51
+Íšì	 51
+Âç	 51
+î	 51
+â¡	 51
+_Íšì	 51
+À_	 51
+Õ¿Õ	 51
+ÙÀ	 51
+_É§	 50
+É§	 50
+œý	 50
+»Õ§_	 50
+×œÔ	 50
+±ÅÕ	 50
+»Ÿ	 49
+à£_	 49
+Ôà	 49
+õŽª	 49
+Ž¥	 49
+»Õ_	 49
+»ÕÀ	 48
+¶Ô§	 48
+ç£	 48
+Õ¡Ž	 48
+Õ€	 48
+ÕØ	 48
+À£	 48
+ÀÕ¿	 48
+_Éç¡Ž	 47
+æ£_	 47
+ê	 47
+Íšì_	 47
+×¶Ô§	 47
+Éç¡Ž	 47
+Â_	 47
+_Íšì_	 47
+?_	 46
+Ø¿	 46
+Ô¿	 46
+_Ø»	 46
+¹õ	 46
+_Ù	 46
+õŽª_	 46
+è£	 45
+ŽÙÄ_	 45
+¢Ù»	 45
+¢Ù	 45
+»Ù	 45
+_×œÔ	 44
+œÜ	 44
+Ô£_	 44
+ÕÆÕ	 44
+ŽØ	 44
+á	 44
+Ž£	 44
+œÔâ	 44
+ÁÔ£	 44
+Á.	 44
+_×¶Ô§	 43
+Žë¡	 43
Index: /main/tags/2.25/gsdl/perllib/textcat/Other/thai.lm
===================================================================
--- /main/tags/2.25/gsdl/perllib/textcat/Other/thai.lm	(revision 21064)
+++ /main/tags/2.25/gsdl/perllib/textcat/Other/thai.lm	(revision 21064)
@@ -0,0 +1,400 @@
+_	 6290
+Ò	 5252
+Ã	 4377
+¹	 3920
+¡	 3050
+è	 2984
+Í	 2657
+§	 2522
+Ñ	 2454
+Á	 2369
+é	 2304
+à	 2158
+Â	 1981
+Ç	 1908
+Õ	 1693
+Å	 1543
+Ô	 1443
+Ž	 1422
+·	 1398
+µ	 1398
+»	 1301
+Ë	 1245
+Ð	 1239
+€	 1210
+º	 1181
+Ê	 1081
+š	 1045
+ä	 978
+ÒÃ	 951
+Ÿ	 907
+ª	 892
+èÒ	 829
+á	 795
+¡Ò	 735
+ã	 722
+¡ÒÃ	 710
+¢	 691
+ÒÂ	 688
+×	 668
+Í§	 595
+.	 588
+ç	 553
+Ø	 543
+ÃÑ	 532
+Õè	 528
+ÃÐ	 522
+»Ã	 522
+·Õ	 477
+Ù	 452
+·Õè	 451
+èÍ	 443
+¹Ò	 441
+Ó	 422
+Ò§	 419
+éÒ	 414
+ì	 388
+¹_	 378
+ÃÃ	 367
+ÒÁ	 360
+°	 354
+Ñº	 349
+Ò_	 347
+éÍ	 345
+»ÃÐ	 340
+Çè	 337
+ÃÒ	 337
+Áè	 336
+ÇèÒ	 336
+à»	 334
+Ò¹	 333
+Ñé	 332
+¡Ã	 328
+Žé	 325
+Ö	 322
+_à	 320
+ç¹	 314
+À	 313
+ÁÒ	 299
+Ñ§	 297
+Ò¡	 297
+×Í	 296
+äÁ	 295
+Ñ°	 293
+ÃÑ°	 293
+×è	 290
+â	 289
+äÁè	 288
+ž	 285
+ã¹	 280
+Œ	 273
+è§	 268
+¹ÒÂ	 268
+é¹	 266
+ŸÃ	 263
+Ñ¹	 263
+³	 263
+áÅ	 256
+¹¡	 254
+ËÒ	 253
+§¡	 252
+×èÍ	 251
+ÁÕ	 251
+äŽ	 248
+­	 248
+äŽé	 248
+šÐ	 248
+»ç¹	 247
+à»ç¹	 247
+»ç	 247
+à»ç	 247
+Í¡	 245
+ÇÒ	 245
+ãË	 244
+¶	 244
+ªÒ	 243
+µÔ	 241
+_á	 240
+¡Ñ	 238
+È	 237
+_¡	 236
+µè	 234
+«	 227
+éÇ	 225
+é§	 221
+É	 216
+Â¡	 214
+Ã€	 213
+ÕÂ	 211
+Ñé§	 211
+ÃÁ	 211
+¢Í	 210
+Ô¹	 209
+èÇ	 206
+Õé	 202
+ÅÐ	 202
+Ë¹	 201
+¹Ñ	 201
+_¹	 200
+µÃ	 197
+Ëé	 196
+§_	 193
+Á¹	 191
+Ðà	 191
+ÀÒ	 188
+ÍÂ	 188
+ÒÇ	 186
+¢Í§	 184
+¹Õ	 184
+ãËé	 183
+€Ç	 183
+ÃÕ	 181
+§à	 180
+¡Å	 179
+áÅÐ	 178
+èÒ§	 177
+èÒ_	 176
+ÃÃ€	 176
+_Ÿ	 176
+€ÇÒÁ	 174
+¹µ	 174
+ÇÒÁ	 174
+€ÇÒ	 174
+ÑŽ	 172
+ÔŽ	 172
+ÇèÒ_	 171
+ŸÃÃ	 167
+šÒ	 167
+Í¹	 167
+Òµ	 167
+¹Õé	 167
+ŸÃÃ€	 166
+¡ç	 166
+€Ã	 165
+¹à	 165
+è¹	 163
+ºÒ	 162
+¢é	 161
+§ã	 161
+Õ_	 161
+ì_	 154
+ËÅ	 154
+Á×	 154
+éÍ§	 151
+¹¡ÒÃ	 151
+¹¡Ò	 151
+ä»	 150
+Ñ¡	 150
+é_	 148
+ÃÒÂ	 147
+µÑ	 146
+¹·	 146
+ÅÑ	 146
+Â_	 146
+àŸ	 145
+Åé	 140
+à¡	 139
+šÒ¡	 139
+àÁ	 138
+ÃÔ	 138
+ŸÅ	 137
+Ã×	 136
+·Ñ	 135
+¡Ñº	 134
+ÒÂ¡	 133
+_Ã	 132
+ºÃ	 132
+§ä	 132
+Ãà	 131
+à·	 130
+Åè	 129
+ÒµÔ	 129
+_·	 128
+¡Ô	 128
+µÃÕ	 128
+ÃÑº	 128
+Õ¡	 128
+àË	 127
+¹Í	 127
+µé	 126
+_¹Ò	 126
+ªÒµÔ	 126
+ÅÒ	 126
+ªÒµ	 126
+¹Ç	 126
+Òà	 126
+_áÅ	 125
+§¹	 124
+§€	 124
+¡ÒÃà	 124
+ÒÃà	 124
+ÍÁ	 123
+Ò€	 122
+ 	 122
+áµ	 122
+àÊ	 121
+ÇÑ	 121
+Ñé¹	 120
+ÃÃÁ	 120
+Ò·	 119
+¹µÃ	 119
+èÒÇ	 118
+áµè	 118
+§·	 117
+Ç¹	 117
+ÂÑ	 117
+Á¹µÃ	 117
+¹µÃÕ	 117
+Á¹µ	 117
+Á¹µÃÕ	 117
+ÃÍ	 116
+Ùé	 116
+_¹ÒÂ	 116
+àÁ×	 116
+°Á¹	 115
+àÃ	 115
+ÃÑ°Á¹	 115
+ËÁ	 115
+à¢	 115
+Ñ°Á	 115
+Í.	 115
+Ñ°Á¹µ	 115
+ÃÑ°Á	 115
+°Á¹µ	 115
+Ñ°Á¹	 115
+°Á¹µÃ	 115
+°Á	 115
+_áÅÐ	 113
+éà	 113
+Ãè	 113
+èÁ	 112
+ãš	 112
+_Ê	 112
+¹Ñé	 111
+Ô»	 111
+¹Ñé¹	 111
+èà	 111
+èä	 110
+_Í	 110
+Âà	 110
+_š	 110
+Òš	 109
+»ÃÒ	 108
+¹ÒÂ¡	 108
+_Ë	 107
+Ñ­	 107
+éÒ¹	 107
+šÑ	 106
+§¡Ò	 106
+_€	 106
+§¡ÒÃ	 105
+ÇÂ	 105
+Ôµ	 105
+¹é	 105
+ÒÅ	 103
+ŽÂ	 102
+è_	 102
+ÃÐà	 102
+àÍ	 102
+¹¹	 102
+ÍÒ	 101
+âŽ	 100
+µéÍ	 100
+ªè	 100
+_ä	 99
+ÇÅ	 99
+µéÍ§	 99
+âŽÂ	 99
+Ã_	 98
+Ðª	 98
+ŸÑ	 98
+»ÃÐà	 98
+Â¡Ã	 97
+Öè§	 97
+¡_	 97
+Öè	 97
+Òª	 97
+é¹_	 96
+ÅÔ	 96
+Ñ°º	 94
+ÒŸ	 94
+ÃÑ°º	 94
+ŒÙ	 94
+°º	 94
+Âè	 93
+¹ä	 93
+·Ò	 93
+°ºÒ	 92
+ÅèÒ	 92
+Å.	 92
+Ñ°ºÒ	 92
+¡Ñ¹	 92
+Ñ°ºÒÅ	 92
+§Ã	 92
+ÃÑ°ºÒ	 92
+ºÒÅ	 92
+°ºÒÅ	 92
+Ö§	 92
+.Í	 91
+¢éÒ	 91
+Ã¡	 91
+_ŸÅ	 90
+ÍÂè	 90
+ŸÅ.	 90
+Íà	 90
+ÍÂèÒ	 90
+ÂèÒ	 90
+¡ÃÐ	 89
+.Í.	 89
+ÂèÒ§	 89
+Õé_	 89
+ÍÂèÒ§	 89
+ÂÑ§	 89
+ÊØ	 89
+µèÍ	 88
+Íº	 88
+_â	 88
+Å.Í	 87
+èÍ§	 87
+ÃÐª	 87
+Áà	 87
+ÂÇ	 87
+ÅÑ§	 87
+ŸÅ.Í.	 87
+Å.Í.	 87
+¹Õé_	 87
+àŽ	 87
+Á¡	 87
+ŒÙé	 87
+ÇÔ	 87
+ŸÅ.Í	 87
+»ÃÐª	 87
+»Ñ	 87
+'	 86
+ÊÔ	 86
+Êè	 86
+Áèä	 86
+_ŸÅ.	 86
+·Ò§	 86
+ÇÁ	 85
+¡à	 85
+Â§	 85
+._	 85
+¡ÃÑ	 85
+ÍÀ	 85
+ªÇ	 84
+ÒÐ	 84
+¹éÒ	 84
+¡ÃÑ°	 84
+ÀÔ	 84
+·Ó	 84
+ËÒÃ	 84
+_ŸÅ.Í	 84
+ÍÍ	 83
+§Ê	 83
+ÍÀÔ	 83
+äÁèä	 83
+Ñµ	 82
+»ÃÒÂ	 82
+€¹	 82
+Í_	 82
Index: /main/tags/2.25/gsdl/perllib/textcat/Other/turkish.lm
===================================================================
--- /main/tags/2.25/gsdl/perllib/textcat/Other/turkish.lm	(revision 21064)
+++ /main/tags/2.25/gsdl/perllib/textcat/Other/turkish.lm	(revision 21064)
@@ -0,0 +1,400 @@
+_	 23226
+i	 8957
+a	 7675
+e	 6219
+n	 5169
+&	 4950
+;	 4950
+l	 4674
+r	 4464
+&i	 3206
+&i;	 3206
+i;	 3206
+s	 3206
+k	 3009
+d	 2977
+t	 2442
+m	 2010
+y	 2001
+u	 1885
+n_	 1725
+g	 1584
+o	 1567
+b	 1470
+e_	 1426
+ü	 1353
+ar	 1273
+la	 1236
+a_	 1209
+i_	 1169
+in	 1124
+_b	 1101
+an	 1097
+er	 1073
+le	 1058
+s;	 1036
+&s;	 1036
+&s	 1036
+;_	 1018
+de	 936
+;n	 918
+&i;n	 917
+i;n	 917
+,_	 872
+_,	 872
+_,_	 872
+,	 872
+i;_	 863
+&i;_	 863
+_k	 816
+en	 769
+r_	 762
+_y	 759
+da	 759
+il	 759
+k_	 750
+z	 739
+nd	 725
+&g;	 708
+g;	 708
+&g	 708
+ra	 697
+_a	 692
+_d	 692
+_s	 676
+'	 673
+_i	 644
+._	 641
+.	 641
+_.	 637
+_._	 637
+c	 637
+ka	 635
+v	 632
+;&	 624
+h	 615
+_g	 597
+ri	 596
+ç	 596
+lar	 583
+li	 580
+ma	 559
+ya	 555
+ler	 553
+p	 547
+re	 529
+al	 529
+ö	 527
+_t	 520
+ir	 508
+ak	 502
+bi	 500
+;l	 480
+in_	 478
+di	 477
+r&	 468
+el	 453
+et	 449
+ek	 445
+n&	 439
+_o	 439
+ol	 437
+da_	 434
+n&i	 433
+n&i;	 433
+ni	 429
+ti	 428
+de_	 425
+an_	 422
+eri	 421
+r&i	 417
+r&i;	 417
+s&	 413
+s&i	 413
+s&i;	 413
+ar&	 412
+me	 407
+te	 405
+a&	 404
+i&	 390
+ay	 387
+ne	 380
+_bi	 373
+_ka	 368
+ar&i;	 367
+ar&i	 367
+u_	 363
+as	 363
+_e	 362
+ta	 359
+&i;l	 352
+i;l	 352
+nda	 350
+ki	 347
+na	 346
+si	 343
+_v	 337
+;&i;	 334
+;&i	 334
+ve	 334
+ara	 333
+en_	 332
+;i	 331
+on	 328
+un	 326
+l&i;	 322
+l&	 322
+l&i	 322
+leri	 322
+ba	 318
+_m	 318
+ik	 315
+mi	 315
+f	 306
+lar&	 302
+lar&i	 302
+sa	 298
+_h	 297
+ld	 296
+&i;&	 290
+i;&	 290
+_ve	 288
+l_	 287
+ge	 286
+is	 285
+ed	 285
+i&s;	 284
+i&s	 284
+;r	 282
+_ya	 279
+_ol	 279
+d&i;	 278
+d&	 278
+d&i	 278
+nl	 277
+kl	 275
+;k	 274
+&i;n_	 271
+;n_	 271
+i;n_	 271
+ile	 270
+or	 269
+iy	 267
+a&s	 264
+a&s;	 264
+y&i;	 262
+ad	 262
+y&	 262
+y&i	 262
+ye	 259
+ha	 258
+es	 258
+t&	 257
+t&i	 257
+t&i;	 257
+ini	 253
+;nd	 253
+i;nd	 253
+ür	 253
+&i;nd	 253
+se	 248
+_ge	 248
+i;nda	 248
+;nda	 248
+;n&i;	 247
+i;n&	 247
+;n&	 247
+&i;n&	 247
+i;n&i	 247
+;n&i	 247
+bu	 245
+_'	 245
+_ba	 244
+as&i	 242
+as&i;	 242
+_de	 242
+as&	 242
+at	 240
+am	 240
+nda_	 239
+ar_	 231
+ve_	 230
+rin	 230
+_ve_	 228
+_bu	 227
+im	 227
+&i;r	 226
+i;r	 226
+ur	 221
+g;&i	 220
+g;&	 220
+&g;&	 220
+yo	 220
+&g;&i	 220
+g;&i;	 220
+ul	 215
+ak_	 215
+ke	 213
+nu	 213
+erin	 211
+g;i	 208
+&g;i	 208
+lan	 207
+bir	 205
+r&i;n	 205
+nde	 202
+rl	 202
+n&i;_	 201
+ko	 201
+ca	 200
+m_	 197
+rd	 196
+t_	 194
+er_	 194
+st	 193
+em	 193
+_sa	 190
+lm	 189
+rt	 188
+_ü	 187
+i;k	 187
+ün	 187
+ola	 187
+&i;k	 187
+lerin	 185
+ce	 185
+'_	 185
+;m	 183
+az	 183
+rk	 182
+yü	 182
+;la	 181
+_bir	 181
+ir_	 180
+n&i;n	 180
+ru	 180
+lu	 180
+;nda_	 178
+e&	 177
+_ç	 176
+_ha	 175
+_ko	 173
+esi	 171
+_ö	 170
+ap	 170
+ni_	 168
+tü	 167
+den	 164
+ind	 161
+di_	 161
+be	 161
+s&i;n	 160
+nin	 159
+üz	 158
+ri_	 155
+y&i;l	 155
+_p	 154
+nin_	 153
+&s;_	 152
+_y&	 152
+edi	 152
+s;_	 152
+_y&i;	 152
+_y&i	 152
+yl	 151
+le_	 151
+inde	 150
+eti	 150
+ala	 150
+&i;&s	 149
+ele	 149
+i;&s;	 149
+;&s;	 149
+;&s	 149
+i;&s	 149
+ek_	 148
+ere	 148
+çi	 147
+du	 145
+ön	 145
+z_	 144
+na_	 144
+eri_	 143
+ec	 142
+gö	 142
+i;&g;	 141
+s&i;_	 141
+bir_	 141
+&i;&g	 141
+i;&g	 141
+ah	 141
+;&g;	 141
+;&g	 141
+_gö	 140
+lar_	 140
+eli	 140
+a&g;	 140
+a&g	 140
+dan	 140
+ac	 140
+iç	 140
+an&	 140
+u&	 139
+;&g;&	 138
+_yü	 138
+an&i	 138
+an&i;	 138
+pa	 138
+it	 137
+_ola	 137
+_bir_	 136
+;t	 135
+ör	 135
+ne_	 135
+ini_	 134
+lma	 134
+kan	 133
+ab	 132
+to	 131
+ba&	 131
+kar	 130
+r&i;_	 130
+_ar	 129
+ili	 129
+li_	 129
+ki_	 128
+bu_	 127
+anl	 127
+dü	 127
+ler_	 126
+_ba&	 126
+kon	 126
+ll	 125
+tl	 125
+ine	 125
+e&g;	 124
+e&g	 124
+_il	 124
+_bu_	 124
+re_	 124
+bil	 123
+&s;i	 123
+;&i;n	 123
+s;i	 123
+ede	 123
+zd	 123
+''	 122
+_da	 122
+_''	 122
+_tü	 122
+ret	 122
+_-_	 121
+_''_	 121
+mas	 121
+''_	 121
+-	 121
+dan_	 121
+leri_	 121
+;u	 121
+_-	 121
+ev	 121
Index: /main/tags/2.25/gsdl/perllib/textcat/Other/ukrainian-koi8_r.lm
===================================================================
--- /main/tags/2.25/gsdl/perllib/textcat/Other/ukrainian-koi8_r.lm	(revision 21064)
+++ /main/tags/2.25/gsdl/perllib/textcat/Other/ukrainian-koi8_r.lm	(revision 21064)
@@ -0,0 +1,400 @@
+_	 21726
+Ï	 4832
+Á	 4080
+É	 3253
+Š	 2775
+Î	 2747
+×	 2642
+Ô	 2481
+Å	 2373
+Ò	 2066
+Ë	 1929
+Ä	 1806
+Ó	 1797
+Ì	 1760
+Õ	 1605
+Ð	 1347
+Í	 1345
+Ñ	 1061
+Ú	 1060
+Á_	 971
+Ï_	 965
+É_	 916
+_×	 902
+Â	 881
+_Ð	 869
+Å_	 847
+Ø	 843
+Š_	 810
+Ç	 760
+_Î	 696
+.	 676
+Þ	 654
+Ê	 647
+_Ó	 623
+"	 621
+_Ú	 606
+ÎÁ	 582
+_Ä	 565
+Ö	 543
+_Ô	 514
+ËÁ	 480
+._	 476
+ÔÉ	 464
+Ï×	 459
+×Š	 457
+Õ_	 457
+×_	 451
+À	 450
+Ñ_	 449
+_Ë	 443
+È	 438
+ÒÏ	 431
+Û	 428
+_Í	 419
+ÎÅ	 418
+ÐÏ	 414
+ÓÔ	 413
+€	 410
+ÔÏ	 400
+ÇÏ	 396
+Ø_	 394
+ÔØ	 377
+ÌÉ	 375
+ËÏ	 373
+ÒÁ	 358
+ÎÏ	 356
+Ê_	 354
+á	 354
+_Â	 350
+ÔÁ	 346
+,	 343
+ÏÄ	 341
+ÉÔ	 340
+ÏÌ	 336
+ÏÇ	 333
+×Á	 331
+Ã	 328
+Á×	 326
+,_	 323
+ÒÉ	 322
+ÄÏ	 321
+ÌÏ	 319
+ŠÄ	 318
+ÎÉ	 317
+÷	 314
+_ÐÏ	 314
+î	 312
+×É	 310
+ÏÒ	 310
+ÅÒ	 305
+ï	 295
+ÏÍ	 295
+ÎŠ	 294
+_ÎÁ	 289
+_ÎÅ	 288
+×Ï	 288
+Ý	 287
+ÅÎ	 282
+ÁÌ	 282
+ÎÁ_	 280
+ÚÁ	 274
+ô	 273
+ËÉ	 268
+_Š	 268
+§	 267
+ÐÒ	 266
+"_	 264
+ÏÇÏ	 254
+ÓÑ	 252
+ÁÔ	 252
+_"	 251
+ÔØ_	 251
+ÎÅ_	 249
+Í_	 248
+ð	 246
+ÔÉ_	 245
+I	 245
+ÉÊ	 244
+_Ò	 241
+€_	 239
+_ÄÏ	 239
+ÄÁ	 235
+ÏÂ	 235
+é	 233
+_Ñ	 232
+_Š_	 228
+ÖÅ	 228
+ÁÎ	 228
+Ë_	 226
+ÉÎ	 224
+_ÐÒ	 221
+ÍÏ	 219
+_ÚÁ	 218
+ŠÎ	 216
+Á€	 215
+ÍÁ	 214
+ÌÁ	 213
+_×Š	 210
+ÄÉ	 209
+_Ç	 207
+À_	 206
+ÒÅ	 206
+ÇÏ_	 204
+É×	 203
+_Ý	 203
+Ú_	 202
+ÝÏ	 201
+ÌŠ	 200
+ò	 199
+ÏÇÏ_	 199
+ó	 197
+ÓÑ_	 196
+ÉÓ	 193
+ÏÎ	 193
+_ÎÅ_	 190
+_ð	 190
+ŠÌ	 188
+ÏÓ	 187
+_Ï	 186
+ÔÅ	 186
+ÞÉ	 185
+ÁÒ	 184
+ÉÊ_	 184
+_÷	 176
+_×_	 174
+_Þ	 174
+ÑË	 173
+ÌØ	 173
+ë	 173
+ÁÓ	 170
+_ÝÏ	 169
+ÍÕ	 168
+ÂÕ	 167
+ñ	 166
+ÉÌ	 166
+ÉË	 163
+å	 163
+ÒŠ	 163
+ä	 163
+ú	 162
+ÝÏ_	 161
+ÔÒ	 160
+ÎŠ_	 160
+Š×	 160
+ÖÅ_	 159
+×ŠÄ	 159
+_Ì	 158
+ÔŠ	 155
+_×É	 155
+*	 154
+ÄÎ	 153
+ÁÍ	 153
+_*	 152
+Á€_	 152
+ÌÉ_	 152
+ØË	 152
+_ËÏ	 151
+È_	 151
+ËÕ	 151
+*_	 151
+ÄÅ	 151
+_*_	 150
+í	 149
+_Ú_	 149
+_ÑË	 148
+_Á	 147
+ÄŠ	 147
+ÄÕ	 146
+ÁÖ	 145
+_ÎÁ_	 144
+ÁÔÉ	 144
+ËÁ_	 143
+ÐÉ	 142
+_ÓÔ	 141
+ÓØ	 141
+ÌÑ	 140
+Î_	 139
+ÌÅ	 138
+ÐŠ	 137
+ÏÌÏ	 137
+ÒÕ	 136
+ÁÄ	 136
+_ÝÏ_	 136
+ÍÉ	 135
+ÃŠ	 135
+_î	 134
+_ÍÏ	 133
+ÁË	 133
+ËÉ_	 133
+ÏÀ	 132
+ÎÕ	 131
+ÉÍ	 130
+ŠÔ	 129
+_ËÁ	 129
+ÂÁ	 129
+_ÔÏ	 129
+§_	 128
+ÍÅ	 128
+ÐÅ	 128
+ÍŠ	 128
+_ÂÕ	 127
+×Ó	 126
+á_	 126
+Ï×Š	 123
+ÏË	 123
+×Å	 122
+ËŠ	 121
+:	 119
+_Ã	 118
+Õ×	 118
+ÂÉ	 116
+ÓŠ	 116
+ÇÁ	 115
+Ï§	 115
+ÐÁ	 115
+ÎÏ_	 115
+ÏÍÕ	 114
+ÍÕ_	 113
+_Ö	 113
+ÏÒÏ	 113
+ÏÔ	 113
+ÉÔØ	 112
+ÏÚ	 112
+?	 111
+ÔÕ	 110
+ÓÔÏ	 109
+_ú	 109
+ÏÞ	 109
+ÉÈ	 109
+ÕÔ	 109
+ÏÀ_	 108
+ŠË	 108
+_È	 106
+â	 106
+ÄÏ_	 106
+ŠÊ	 106
+_×ŠÄ	 106
+Ó×	 106
+ÚÎ	 105
+ÂŠ	 105
+ÐÒÉ	 105
+ÓÔÁ	 104
+ÁÚ	 104
+ËÒ	 104
+ËÁÖ	 104
+ÎÑ	 103
+ÕÄ	 103
+_ô	 102
+_ÇÏ	 102
+Ä_	 102
+ÔÏ_	 102
+ÉÔÉ	 102
+_ó	 101
+_ÔÁ	 101
+ÌÏ×	 101
+ì	 100
+_ÒÏ	 100
+ÞÁ	 99
+ÏÍÕ_	 99
+ÐÅÒ	 99
+_ÄÏ_	 98
+ÏÄÉ	 98
+ŠÓ	 98
+ÁÖÅ	 97
+ÌÁ_	 97
+ÁÊ	 96
+ÓÏ	 94
+ÁÔÉ_	 94
+_Õ	 94
+ÌÀ	 93
+!	 93
+_Ó×	 93
+..	 93
+ÅÒÅ	 92
+ÓË	 92
+ŠÌØ	 92
+ÓÉ	 92
+_ÐÒÉ	 91
+ÅÌ	 91
+ÐÒÏ	 91
+_ËÁÖ	 91
+ÈÏ	 91
+ÏÖ	 89
+þ	 89
+Ô_	 88
+ÉÔØ_	 88
+ÅÓ	 88
+ÞÏ	 86
+ÂÏ	 86
+ÓÌ	 86
+ËÁÖÅ	 86
+ÑÔ	 85
+ñ_	 85
+ÓÐ	 84
+ÔÏÒ	 84
+ÏÌÉ	 84
+_ËÁÖÅ	 83
+_ÐŠ	 83
+_ÍÁ	 82
+ÕÌ	 82
+ÕË	 82
+ç	 81
+õ	 81
+_ë	 81
+Á×_	 81
+ÎÎ	 81
+ÞÅ	 81
+ÍÅÎ	 81
+ÍÉ_	 80
+_Ê	 79
+_í	 79
+ØÓ	 78
+ÎË	 78
+ÁÀ	 78
+ÂÅ	 78
+ÃÅ	 78
+_ÐÒÏ	 77
+ŠÎ_	 77
+ÏÍ_	 77
+ÕÓ	 77
+ÅÍ	 77
+_ñ	 77
+_ä	 77
+_×Ï	 76
+_ÍÅ	 76
+ÉÈ_	 76
+ÅÔ	 76
+ØÏ	 75
+ÉÞ	 75
+ØËÉ	 75
+ÕÒ	 74
+ØÓÑ	 74
+ÔØÓ	 74
+ÔØÓÑ	 74
+Ï§_	 73
+_ÓÔÏ	 73
+ËÏÌ	 72
+".	 72
+."	 72
+ÏÌÏ×	 72
+ÊÏ	 72
+Ä×	 71
+Š×_	 71
+ÏÐ	 71
+Æ	 71
+_ÐÅ	 71
+Õ×Á	 71
+ÎÉÊ	 71
+ÓØ_	 70
+_â	 70
+ÌØË	 70
+_ÏÄ	 69
+ÅÎŠ	 69
+ÁÞ	 68
+ÁÌÉ	 68
+ŠÌØË	 68
+ÈÁ	 68
+ÑË_	 68
+ÔØÓÑ_	 68
+ÔÁË	 68
Index: /main/tags/2.25/gsdl/perllib/textcat/Other/vietnamese.lm
===================================================================
--- /main/tags/2.25/gsdl/perllib/textcat/Other/vietnamese.lm	(revision 21064)
+++ /main/tags/2.25/gsdl/perllib/textcat/Other/vietnamese.lm	(revision 21064)
@@ -0,0 +1,400 @@
+_	 88044
+n	 17000
+h	 12823
+t	 9071
+i	 8490
+c	 8394
+g	 8035
+ng	 6718
+_t	 6352
+_c	 5234
+a	 5083
+g_	 4883
+ng_	 4882
+_n	 4379
+n_	 4365
+i_	 4365
+u	 4149
+m	 3648
+à	 3635
+nh	 3480
+o	 3451
+Ç	 3193
+_Ç	 3168
+r	 3011
+l	 2692
+Ü	 2659
+,	 2328
+,_	 2295
+c_	 2279
+_l	 2263
+ch	 2226
+v	 2161
+th	 2158
+a_	 2132
+_th	 2113
+y	 2111
+.	 2107
+t_	 2106
+h_	 2074
+_v	 2057
+_h	 1888
+_m	 1834
+_ch	 1813
+s	 1749
+nh_	 1715
+u_	 1679
+á	 1668
+à_	 1649
+tr	 1611
+b	 1589
+_tr	 1581
+_nh	 1541
+_b	 1530
+m_	 1505
+p	 1483
+._	 1455
+k	 1429
+_s	 1415
+o_	 1380
+y_	 1371
+_k	 1367
+_ng	 1348
+©	 1343
+e	 1296
+ó	 1208
+	 1199
+ô	 1181
+¶	 1139
+å	 1132
+T	 1126
+hi	 1121
+â	 1081
+ì	 1058
+ê	 1055
+d	 1040
+_g	 1039
+kh	 1034
+_kh	 1027
+_T	 994
+©i	 967
+là	 943
+_là	 941
+"	 926
+ä	 916
+Ü©	 901
+an	 893
+_d	 888
+Ó	 877
+©i_	 859
+on	 853
+Ã	 848
+N	 846
+	 820
+ó_	 813
+	 801
+ôn	 795
+ph	 776
+_p	 772
+_ph	 752
+û	 752
+§	 734
+hÜ	 728
+ho	 715
+và	 709
+_và	 703
+gÜ	 702
+®	 700
+_r	 696
+H	 693
+_là_	 691
+là_	 691
+Ü©i	 684
+àn	 679
+ên	 677
+ông	 676
+ha	 672
+gi	 663
+C	 656
+_gi	 655
+Ö	 654
+gÜ©i	 646
+gÜ©	 646
+Ü©i_	 624
+ông_	 610
+ngÜ	 610
+_ngÜ	 608
+ác	 606
+ú	 601
+ngÜ©	 600
+ngÜ©i	 600
+_ngÜ©	 598
+gÜ©i_	 594
+ûa	 587
+cû	 586
+_cû	 585
+¶t	 585
+cûa	 585
+ên_	 585
+_cûa	 584
+có	 583
+ûa_	 582
+_có	 581
+cûa_	 581
+ã	 581
+_cûa_	 580
+¶t_	 578
+_N	 574
+có_	 574
+»	 573
+_có_	 572
+i	 568
+À	 562
+	 562
+m¶	 557
+_C	 553
+_m¶	 551
+p_	 540
+Æ	 540
+m¶t	 538
+m¶t_	 534
+_m¶t	 532
+ìn	 528
+_m¶t_	 528
+ti	 526
+i	 525
+Ù	 517
+Î	 512
+ình	 500
+..	 500
+	 497
+và_	 497
+_và_	 496
+æ	 491
+q	 490
+qu	 490
+_H	 487
+_q	 484
+_qu	 484
+ong	 481
+ong_	 471
+há	 471
+x	 470
+hô	 468
+¿	 466
+_"	 460
+Ü®	 456
+ro	 453
+ình_	 445
+ì_	 434
+_x	 434
+ã_	 427
+í	 423
+_ti	 423
+in	 422
+ân	 421
+"_	 418
+i	 415
+Ön	 413
+ron	 412
+V	 411
+rong	 410
+§i	 410
+rong_	 409
+ác_	 405
+ª	 400
+n	 399
+hôn	 398
+åi	 395
+ay	 390
+_V	 387
+h»	 382
+hà	 380
+ày	 377
+Ãt	 376
+uy	 374
+ÇÜ	 374
+_ÇÜ	 373
+§i_	 372
+cá	 371
+_cá	 367
+nà	 366
+_	 366
+hú	 366
+_nà	 365
+ra	 363
+hông	 362
+ho_	 359
+ân_	 356
+án	 356
+°	 355
+åi_	 354
+ai	 352
+hu	 352
+cho	 352
+Ü®c	 351
+®c	 351
+Ón	 351
+_cho	 349
+tro	 347
+t	 347
+ào	 347
+_tro	 346
+_tron	 346
+ñ	 346
+tron	 346
+trong	 346
+M	 345
+khô	 340
+âu	 338
+_khô	 338
+cho_	 337
+_cho_	 336
+hông_	 336
+ay_	 333
+ch_	 332
+Çã	 331
+Ãt_	 331
+(	 331
+_(	 330
+Ò	 329
+_Çã	 329
+ÇÜ®	 328
+_ÇÜ®c	 328
+)	 328
+ÇÜ®c	 328
+_ÇÜ®	 328
+khôn	 324
+_ñ	 324
+_khôn	 322
+Çã_	 322
+_Çã_	 320
+ò	 318
+ån	 318
+không	 316
+ào_	 316
+Ü®c_	 316
+®c_	 316
+nhÜ	 315
+Ü_	 315
+»ng	 313
+»ng_	 313
+»n	 313
+_nhÜ	 313
+Th	 312
+hì	 311
+Û	 310
+h»n	 310
+h»ng_	 310
+h»ng	 310
+iê	 309
+gh	 309
+u	 307
+ta	 307
+anh	 307
+¡	 307
+ai_	 306
+àng	 306
+ày_	 304
+ÇÜ®c_	 298
+ÜÖ	 295
+S	 295
+:	 294
+t_	 294
+e_	 294
+:_	 290
+Î_	 289
+ua	 288
+æn	 288
+ài	 286
+u_	 285
+_nh»	 285
+nh»	 285
+nh»ng	 285
+nh»n	 285
+_nh»n	 285
+_Th	 285
+n_	 284
+n	 283
+Ø	 281
+_M	 281
+A	 281
+úc	 278
+L	 277
+ø	 277
+ÜÖn	 276
+_ha	 276
+n,	 275
+Öng	 275
+ÜÖng	 275
+an_	 272
+ài_	 271
+iu	 269
+sÓ	 269
+n,_	 268
+¿_	 268
+on_	 267
+_sÓ	 267
+các	 265
+àng_	 265
+_các	 264
+anh_	 264
+ngh	 264
+_ta	 263
+hi_	 262
+hàn	 261
+_	 261
+âu_	 261
+Àn	 260
+ù	 260
+_ngh	 257
+ia	 255
+¢	 252
+...	 252
+êu	 251
+Ùc	 251
+i,	 249
+iu_	 248
+nhi	 247
+B	 246
+i,_	 245
+Óng	 244
+ª_	 244
+co	 244
+_nhi	 244
+¥	 244
+Ü§	 244
+iên	 243
+D	 243
+Tr	 241
+_S	 240
+hÜ_	 239
+òn	 237
+hÃ	 236
+hÆ	 233
+K	 233
+Öng_	 232
+ôi	 232
+ÜÖng_	 232
+Àn_	 231
+_co	 231
+n_	 229
+hå	 229
+äi	 229
+yê	 229
+Ûn	 229
+¢n	 228
+Ûng	 228
+_L	 227
+Ûng_	 226
+inh	 226
+Çi	 225
+mà	 225
+_Çi	 225
+ng,	 224
+ang	 224
+P	 224
+n	 224
+g,	 224
+g,_	 223
+_v§	 223
Index: /main/tags/2.25/gsdl/perllib/textcat/Other/welsh.lm
===================================================================
--- /main/tags/2.25/gsdl/perllib/textcat/Other/welsh.lm	(revision 21064)
+++ /main/tags/2.25/gsdl/perllib/textcat/Other/welsh.lm	(revision 21064)
@@ -0,0 +1,400 @@
+_	 78614
+a	 18113
+d	 17890
+y	 16837
+e	 14108
+n	 13902
+r	 13869
+i	 12928
+o	 9972
+l	 9188
+h	 7454
+g	 7165
+w	 7010
+t	 6296
+f	 6080
+u	 5400
+n_	 5159
+_y	 5051
+dd	 4946
+s	 4884
+r_	 4547
+m	 4364
+d_	 4223
+yn	 4082
+_a	 4020
+c	 3707
+th	 3301
+u_	 2900
+yd	 2900
+ae	 2649
+l_	 2588
+_g	 2547
+.	 2460
+'	 2458
+._	 2408
+wy	 2334
+yn_	 2331
+_d	 2307
+b	 2267
+ym	 2262
+ra	 2261
+an	 2235
+ar	 2228
+ol	 2218
+ia	 2212
+i_	 2199
+ed	 2191
+_yn	 2038
+_i	 2020
+y_	 1983
+_c	 1934
+_yn_	 1861
+ei	 1815
+it	 1796
+g_	 1787
+ith	 1779
+dd_	 1745
+h_	 1741
+ydd	 1731
+ai	 1709
+au	 1708
+'r_	 1655
+'r	 1655
+_y_	 1621
+di	 1615
+,	 1613
+,_	 1608
+da	 1585
+od	 1546
+_o	 1535
+ad	 1532
+th_	 1510
+ll	 1494
+au_	 1492
+_s	 1415
+er	 1359
+o_	 1350
+io	 1311
+a_	 1299
+ol_	 1294
+_e	 1273
+_h	 1249
+cy	 1246
+yr	 1243
+en	 1228
+p	 1217
+_f	 1212
+_cy	 1203
+mr	 1200
+gy	 1193
+ymr	 1185
+ha	 1172
+hy	 1164
+eg	 1159
+do	 1151
+edd	 1147
+G	 1134
+we	 1107
+C	 1089
+_ar	 1078
+_m	 1075
+yf	 1057
+de	 1048
+fe	 1047
+_G	 1045
+ch	 1043
+rae	 1023
+el	 1016
+no	 1010
+ni	 1010
+_b	 1009
+ne	 1001
+ef	 992
+ri	 983
+et	 978
+_C	 957
+_gy	 952
+_a_	 943
+eth	 943
+_.	 940
+_._	 939
+eit	 930
+eith	 927
+ys	 921
+wyd	 912
+ga	 901
+_i_	 893
+s_	 887
+mrae	 878
+mraeg	 878
+raeg	 878
+ymrae	 878
+aeg	 878
+ymra	 878
+mra	 878
+_p	 856
+aet	 850
+aeth	 850
+_n	 844
+un	 838
+on	 836
+ait	 833
+aith	 833
+nn	 830
+at	 827
+oe	 823
+li	 805
+_r	 801
+ddi	 795
+gw	 789
+ma	 783
+le	 777
+nt	 772
+ho	 769
+ff	 766
+yr_	 764
+na	 753
+la	 748
+rh	 747
+eg_	 734
+si	 733
+ng	 732
+dol	 732
+ro	 718
+al	 712
+_dd	 706
+wn	 705
+oed	 705
+Gy	 704
+dy	 701
+Cy	 696
+o'	 692
+ar_	 691
+ny	 690
+Gym	 678
+wr	 677
+id	 676
+_Gy	 672
+_o_	 668
+Gymr	 667
+if	 662
+ith_	 662
+_ar_	 660
+iad	 657
+_w	 657
+fo	 656
+eu	 655
+aeg_	 650
+raeg_	 650
+aith_	 648
+or	 648
+_Gym	 646
+fa	 642
+re	 638
+_Cy	 638
+_Gymr	 635
+_gw	 633
+fy	 633
+oedd	 633
+edd_	 629
+rd	 627
+od_	 622
+ac	 619
+ddo	 612
+an_	 607
+Gymra	 606
+er_	 605
+A	 604
+eth_	 601
+hw	 596
+ydd_	 591
+o'r	 586
+o'r_	 586
+es	 583
+ir	 579
+dw	 573
+go	 559
+yl	 548
+rw	 545
+aeth_	 545
+wydd	 543
+aw	 539
+_rh	 539
+dr	 537
+ly	 537
+fn	 534
+dau	 533
+_hy	 531
+t_	 531
+sg	 529
+'n	 529
+*	 528
+'n_	 523
+_*	 522
+nyd	 521
+nydd	 521
+M	 519
+st	 518
+Y	 516
+sy	 515
+yd_	 513
+lw	 512
+_ga	 508
+iai	 503
+il	 502
+_l	 499
+rt	 494
+ad_	 493
+_yr	 493
+_yr_	 492
+as	 492
+dol_	 492
+f_	 491
+dda	 491
+ig	 490
+og	 484
+wa	 479
+he	 478
+iaith	 477
+iait	 477
+oedd_	 475
+_ma	 473
+c_	 472
+Cym	 470
+te	 469
+_ym	 467
+am	 467
+_M	 465
+_ia	 462
+efn	 462
+i'	 460
+ie	 458
+_Cym	 458
+_ac	 457
+dau_	 456
+yw	 455
+ew	 453
+fr	 441
+fod	 441
+_A	 441
+du	 437
+_sy	 434
+e_	 432
+wi	 426
+Cymr	 426
+se	 425
+B	 424
+D	 424
+_Cymr	 423
+bl	 423
+lu	 420
+in	 417
+_t	 417
+tr	 414
+ac_	 413
+wed	 410
+os	 410
+_iai	 407
+_iait	 407
+el_	 405
+_ac_	 405
+rha	 404
+m_	 404
+is	 403
+on_	 401
+eu_	 393
+hi	 393
+rdd	 393
+id_	 389
+_Y	 388
+ry	 387
+odd	 387
+rwy	 387
+rf	 386
+io_	 380
+ynn	 380
+cyf	 380
+hr	 380
+_cyf	 379
+yddi	 379
+cyn	 372
+_de	 372
+rth	 371
+ru	 368
+S	 363
+wei	 363
+ysg	 362
+_B	 362
+u'	 361
+yddo	 360
+wn_	 360
+so	 359
+dio	 359
+_ei	 358
+N	 356
+dwy	 355
+_da	 353
+me	 353
+gan	 353
+gyf	 353
+w_	 352
+_o'	 351
+fer	 349
+nol	 347
+hyn	 346
+ddy	 346
+af	 346
+ta	 343
+ddol	 343
+_fe	 340
+nd	 340
+mae	 338
+_cyn	 338
+efnyd	 337
+fnydd	 337
+fny	 337
+efny	 337
+fnyd	 337
+iad_	 335
+_mae	 333
+ion	 333
+_ll	 330
+def	 330
+_gyf	 327
+nt_	 326
+i'r_	 326
+-	 326
+i'r	 326
+weith	 325
+weit	 325
+defn	 325
+defny	 325
+bo	 324
+hyd	 323
+by	 322
+_si	 321
+ir_	 321
+hau	 318
+nod	 318
+edi	 315
+I	 314
+fyd	 313
+wyr	 313
+ada	 311
+ddio	 310
+rif	 309
+sia	 307
+sa	 306
+fel	 305
+tha	 305
+_S	 302
+_ne	 302
+_u	 301
+fod_	 300
+_o'r	 300
+yg	 300
+_o'r_	 300
+_i'	 299
+ge	 299
+dia	 299
Index: /main/tags/2.25/gsdl/perllib/textcat/Other/yiddish-utf.lm
===================================================================
--- /main/tags/2.25/gsdl/perllib/textcat/Other/yiddish-utf.lm	(revision 21064)
+++ /main/tags/2.25/gsdl/perllib/textcat/Other/yiddish-utf.lm	(revision 21064)
@@ -0,0 +1,400 @@
+×	 29767
+_	 13552
+_×	 6516
+Ö	 4273
+	 3670
+×	 3670
+×¢	 3261
+¢	 3261
+¢×	 2826
+×¢×	 2826
+×Ö	 2785
+Ö	 2785
+×	 2565
+	 2565
+š	 2082
+×š	 2082
+×	 2062
+××	 2062
+	 1857
+×	 1857
+·	 1828
+Ö·	 1828
+	 1793
+×	 1793
+_×	 1537
+_	 1532
+×_	 1532
+·×	 1527
+Ö·×	 1527
+×Ö·	 1517
+Ö·	 1517
+×š×	 1355
+š×	 1355
+	 1270
+×	 1270
+ž	 1268
+×Öž	 1268
+Öž	 1268
+Öž	 1268
+Ö·×	 1240
+×Ö·×	 1240
+× 	 1232
+ 	 1232
+×Öž×	 1229
+Öž×	 1229
+ž×	 1229
+Öž×	 1229
+× ×	 1181
+ ×	 1181
+×	 1116
+	 1116
+	 1031
+×	 1031
+××	 1012
+×	 1012
+××	 1007
+×	 1007
+××	 975
+×	 975
+××	 965
+×	 965
+×€Ö	 929
+€	 929
+×€	 929
+€Ö	 929
+¢×š	 873
+×¢×š	 873
+××	 870
+×	 870
+×	 868
+	 868
+¡	 832
+×¡	 832
+§	 797
+×§	 797
+_××	 784
+×	 766
+	 766
+_×Ö	 752
+×	 747
+××	 747
+	 742
+×	 742
+©	 725
+×©	 725
+×_	 699
+_	 699
+×°	 691
+°	 691
+×°×	 674
+°×	 674
+²	 667
+×²	 667
+×	 664
+××	 664
+¿	 661
+Ö¿	 661
+×§×	 654
+§×	 654
+¿×	 652
+Ö¿×	 652
+×©×	 651
+©×	 651
+×	 643
+××	 643
+×€Ö¿	 641
+€Ö¿	 641
+×€Ö¿×	 638
+€Ö¿×	 638
+_×Ö·	 638
+×š_	 592
+š_	 592
+_×	 560
+_××	 554
+,	 551
+,_	 534
+×	 517
+	 517
+_×€Ö	 502
+_×€	 502
+××	 472
+×	 472
+×¡×	 436
+¡×	 436
+×Š	 436
+Š	 436
+×Š×	 433
+Š×	 433
+_×°	 430
+_×°×	 429
+	 410
+×	 410
+¢×š_	 404
+_×€Ö¿	 404
+×¢×š_	 404
+_×	 400
+_××	 396
+××¢	 390
+×¢	 390
+_×	 390
+_××	 386
+×¢×	 384
+×¢×	 384
+××¢×	 384
+¢×	 384
+×¢×š×	 382
+¢×š×	 382
+.	 374
+××	 372
+×	 372
+ÖŒ	 366
+Œ	 366
+×	 363
+××	 363
+××	 362
+×××	 362
+_×	 359
+×±	 357
+±	 357
+_××	 356
+××	 349
+×	 349
+×_	 346
+_	 346
+×¢_	 343
+¢_	 343
+×_	 337
+××_	 337
+×¢	 334
+××¢	 334
+_××	 331
+×	 330
+	 330
+×¢×	 323
+Œ×	 323
+××¢×	 323
+ÖŒ×	 323
+²×	 322
+×²×	 322
+×¢×_	 321
+¢×_	 321
+±×	 320
+×±×	 320
+×	 317
+××	 317
+²Ö·	 311
+Ö·×š	 311
+×²Ö	 311
+·×š	 311
+Ö·×š	 311
+×²Ö·	 311
+²Ö	 311
+××¢	 310
+×¢	 310
+._	 307
+-	 305
+·_	 297
+Ö·_	 297
+	 294
+×	 294
+ ×¢	 290
+× ×¢	 290
+×¡_	 289
+¡_	 289
+×€ÖŒ	 288
+€ÖŒ	 288
+×²Ö·×	 287
+²Ö·×	 287
+×_	 283
+_	 283
+Ö·_	 274
+×Ö·_	 274
+Ö·×š×	 272
+·×š×	 272
+××¢×	 261
+×¢×	 261
+_××	 260
+_×	 260
+_×Š	 259
+×©	 257
+××©	 257
+_×Š×	 256
+××	 254
+×	 254
+×€ÖŒ×	 252
+€ÖŒ×	 252
+××¢	 248
+×¢	 248
+_×§	 247
+× ×¢×	 247
+ ×¢×	 247
+××¢	 245
+×¢	 245
+_×§×	 245
+××	 244
+××	 244
+×	 244
+×××	 244
+¢×	 238
+×¢×	 238
+×	 235
+××	 235
+××Ö	 235
+×©×	 235
+©×	 235
+×Ö	 235
+××	 234
+×	 234
+_××	 231
+×¢×š	 231
+_×	 231
+Ö·× 	 229
+·× 	 229
+·× ×	 228
+Ö·× ×	 228
+_××	 227
+_××¢	 226
+	 219
+×	 219
+"	 218
+×¢×	 217
+××¢×	 217
+°×¢	 217
+×°×¢	 217
+·×	 216
+Ö·×	 216
+_××	 215
+_× 	 215
+×¢××	 212
+¢××	 212
+š×	 211
+×š×	 211
+_× ×	 211
+××¢×	 211
+×¢×	 211
+×°×	 210
+°×	 210
+_××¢	 210
+°×Ö	 209
+×°×¢×	 209
+×°×Ö	 209
+°×¢×	 209
+×©×	 208
+××©×	 208
+×§	 207
+××§	 207
+×š×Ö	 206
+š×Ö	 206
+_	 205
+×_	 205
+×	 196
+××	 196
+_×©	 195
+×××	 195
+××	 195
+Ö·×	 193
+_×©×	 191
+Ö¿×	 189
+¿×	 189
+€Ö¿×	 189
+Ö¿×Ö	 188
+¿×	 188
+Ö¿××	 188
+Ö¿×	 188
+¿××	 188
+¿×Ö	 188
+××	 187
+×Öž	 186
+_××	 185
+€Ö¿×	 184
+_×¢	 179
+_××	 178
+×	 176
+××	 176
+××Ö	 175
+×Ö	 175
+Öž×¡	 174
+Öž×¡	 174
+××	 174
+×	 174
+ž×¡	 174
+×_	 173
+_	 173
+×_	 173
+××_	 173
+×_	 171
+·××	 171
+_	 171
+Ö·××	 171
+_×¢×	 171
+Öž×	 169
+ž×	 169
+Öž×	 169
+××	 168
+×	 168
+Öž×š	 166
+××	 166
+Öž×š	 166
+ž×š	 166
+×××	 166
+× ×	 164
+×¢× 	 164
+ ×	 164
+¢× 	 164
+š×	 163
+×š×	 163
+××_	 163
+×_	 163
+°×Öž	 162
+×¢× ×	 162
+¢× ×	 162
+¿×Ö·	 160
+¢×	 160
+×¢×	 160
+_×	 158
+š××	 157
+×š	 157
+×š××	 157
+××š	 157
+-×	 156
+Öž×¡_	 155
+ž×¡_	 155
+×	 154
+_××	 154
+××	 154
+×§×¢	 153
+×× 	 153
+§×¢	 153
+× 	 153
+_×°×	 152
+ ××	 152
+× ××	 152
+×	 151
+××	 151
+××±	 151
+×±	 151
+×Ö	 150
+·×	 150
+Ž	 150
+Ö	 150
+×ÖŽ	 150
+ÖŽ	 150
+ÖŽ	 150
+Ö·×	 150
+ÖŽ×	 149
+ÖŽ×	 149
+Ž×	 149
+×ÖŽ×	 149
+××	 148
+_××	 148
+×××	 148
+×±×	 146
+××±×	 146
+Ö·× 	 146
+_××±	 145
+¿××	 145
+××	 143
+×	 143
+××	 142
+×××	 142
Index: /main/tags/2.25/gsdl/perllib/textcat/README
===================================================================
--- /main/tags/2.25/gsdl/perllib/textcat/README	(revision 21064)
+++ /main/tags/2.25/gsdl/perllib/textcat/README	(revision 21064)
@@ -0,0 +1,24 @@
+This driectory contains language models for TextCat version 1.08
+Copyright (C) 1997 Gertjan van Noord (vannoord@let.rug.nl)
+
+Only the files in the textcat directory are used; there are some
+other languages in the Other directory.  If you want to recognise
+these languages, move them from Other into the textcat directory.
+
+
+TextCat is available from: http://odur.let.rug.nl/~vannoord/TextCat 
+under the terms of the GNU General Public License version 2.
+
+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.
Index: /main/tags/2.25/gsdl/perllib/textcat/arabic-windows1256.lm
===================================================================
--- /main/tags/2.25/gsdl/perllib/textcat/arabic-windows1256.lm	(revision 21064)
+++ /main/tags/2.25/gsdl/perllib/textcat/arabic-windows1256.lm	(revision 21064)
@@ -0,0 +1,400 @@
+_	 3974
+Ç	 1252
+á	 958
+æ	 626
+í	 534
+ä	 498
+Çá	 496
+ã	 482
+_Ç	 473
+_Çá	 408
+È	 345
+.	 335
+Ñ	 326
+å	 303
+Ê	 269
+Ú	 260
+ä_	 258
+Ï	 244
+_æ	 235
+Ý	 202
+Ç_	 200
+..	 188
+ß	 175
+Ì	 173
+Ã	 166
+É	 162
+Þ	 157
+Í	 150
+Ó	 150
+_ã	 145
+å_	 143
+._	 130
+áÇ	 129
+É_	 129
+_È	 124
+í_	 120
+ú	 117
+ó	 116
+áã	 115
+_Ã	 109
+Ð	 98
+...	 94
+õ	 92
+_Ý	 92
+_Ú	 90
+Çä	 90
+á_	 90
+Ï_	 88
+æÇ	 87
+Çáã	 86
+æá	 84
+_Çáã	 83
+_á	 82
+ì	 80
+ì_	 79
+Ô	 77
+.._	 77
+..._	 77
+æÌ	 72
+ãä	 71
+¡_	 69
+Úá	 69
+¡	 69
+íä	 69
+ó_	 68
+æÏ	 68
+_í	 67
+Ìæ	 67
+Ýí	 67
+Ë	 66
+ú.	 66
+áæ	 65
+ö	 64
+æä	 63
+ÇÊ	 63
+Õ	 63
+ã_	 62
+ãÇ	 62
+æÌæ	 62
+Ñ_	 62
+ÌæÏ	 61
+áì	 60
+æÌæÏ	 60
+Ö	 60
+áì_	 60
+_¡_	 58
+_ãä	 58
+_¡	 58
+Çä_	 57
+ú..._	 56
+ú..	 56
+ú...	 56
+-_	 53
+-	 53
+_-	 52
+_-_	 52
+_Ýí	 51
+ãä_	 50
+áí	 50
+Çáæ	 50
+_æÇ	 50
+ÐÇ	 49
+áÇ_	 48
+Á	 48
+áÚ	 47
+_ß	 47
+È_	 47
+ö_	 46
+_Çáæ	 45
+æä_	 45
+íÇ	 44
+Ò	 44
+Ýí_	 44
+_Úá	 43
+_Ñ	 43
+õ_	 43
+æÏ_	 43
+_ãä_	 43
+ÌæÏ_	 42
+æÌæÏ_	 42
+Î	 42
+ÇáÚ	 41
+Ø	 41
+ÍÇ	 41
+Úáì_	 40
+_Ê	 40
+Úáì	 40
+_Çä	 40
+ãÑ	 40
+íä_	 39
+Èí	 39
+åÇ	 39
+_ÇáÚ	 38
+ÑÇ	 38
+áå	 37
+äí	 37
+_Þ	 37
+_Ýí_	 36
+Ê_	 36
+ÊÈ	 35
+_æá	 35
+áæÌ	 35
+áá	 35
+_Çä_	 35
+áæÌæ	 35
+Êå	 34
+ãÇ_	 34
+Á_	 34
+Æ	 34
+ÐÇÊ	 34
+áæÌæÏ	 34
+ÇáæÌ	 33
+ÇáæÌæ	 33
+ÇáÇ	 33
+ßæ	 33
+_å	 32
+Çæ	 32
+äÇ	 31
+ßæä	 31
+ÇÈ	 31
+ÈÉ	 31
+åÇ_	 31
+_Ì	 30
+áä	 30
+Çæá	 30
+íÑ	 30
+_ÇáæÌ	 30
+Êõ	 30
+Çã	 30
+Ãä	 30
+Û	 30
+_Í	 30
+ø	 29
+Èá	 29
+ÇÁ	 29
+Êå_	 29
+ÃÍ	 29
+æÑ	 29
+ÇÏ	 29
+íå	 29
+_ÃÍ	 29
+Å	 29
+ÈÇ	 29
+_Úáì_	 28
+ÇÊå	 28
+_ÇáÇ	 28
+_Úáì	 28
+ÈÉ_	 28
+ãæ	 27
+ßæä_	 27
+_Ô	 27
+ÑÊ	 27
+íÉ	 27
+áß	 27
+æÇá	 27
+æã	 27
+ÐÇÊå	 27
+Ó_	 26
+_.	 26
+Çá_	 26
+ÞÇ	 26
+_æÇá	 26
+ßÇ	 26
+íÉ_	 26
+äå	 26
+ÇÊå_	 26
+_._	 26
+æá_	 25
+Ïí	 25
+ÚÑ	 25
+ÐÇÊå_	 25
+áå_	 25
+ãÓ	 24
+ÇÆ	 24
+ÏÇ	 24
+íß	 24
+_áÇ	 24
+æÈ	 23
+ÊÈÉ_	 23
+ãÑÊÈ	 23
+_ÃÍÇæ	 23
+äæ	 23
+Ãí	 23
+Çáá	 23
+äú	 23
+ÑÊÈ	 23
+ÚÇ	 23
+íßæ	 23
+íßæä	 23
+ÍÇæá	 23
+ÊÈÉ	 23
+ÃÍÇæá	 23
+íßæä_	 23
+_ÃÍÇ	 23
+ÇÑ	 23
+ÃÍÇ	 23
+Èú	 23
+_Çáá	 23
+ÍÇæ	 23
+ãÑÊ	 23
+ÃÍÇæ	 23
+_íß	 23
+_íßæä	 22
+ãÑÊÈÉ	 22
+ò	 22
+ÇÌ	 22
+ÌÈ	 22
+äí_	 22
+_íßæ	 22
+ÑÊÈÉ	 22
+Çæá_	 22
+ÑÊÈÉ_	 22
+ß_	 22
+_Å	 21
+_Èá	 21
+áãÑ	 21
+Þí	 21
+ÑÈ	 21
+ßá	 21
+æáÇ	 21
+Êõ_	 21
+ÇáãÑ	 21
+Çáä	 21
+_ÇáãÑ	 20
+Ïå	 20
+ÌÈ_	 20
+ááå	 20
+ÇáË	 20
+ÇÊ_	 20
+áË	 20
+ÑÓ	 20
+_Ð	 20
+ÇÓ	 20
+åæ	 20
+Úí	 19
+Çå	 19
+Èä	 19
+æ_	 19
+åÐ	 19
+Ðå	 19
+Èíä	 19
+áã_	 19
+_Ãä	 19
+íÑ_	 19
+áÊ	 19
+ÍÇæá_	 18
+áÔ	 18
+Çááå	 18
+ÇÌÈ_	 18
+æÇÌÈ_	 18
+ËÇ	 18
+Úä	 18
+ááå_	 18
+Ãä_	 18
+íÏ	 18
+ÇÌÈ	 18
+Ôí	 18
+_Çáä	 18
+áãÑÊÈ	 18
+_æÃ	 18
+_Çááå	 18
+áãÑÊ	 18
+æÇÌ	 18
+Ñí	 18
+æÃ	 18
+ÇáãÑÊ	 18
+æÇÌÈ	 18
+ÞÏ	 18
+_ÞÇ	 17
+ÇáÔ	 17
+Úíä	 17
+ÝÇ	 17
+åã	 17
+Ú_	 17
+íÇ_	 17
+ãæÌ	 17
+ò_	 17
+Çááå_	 17
+ãÊ	 17
+äú.	 17
+ãæÌæ	 17
+íÓ	 17
+ÚÏ	 17
+ÍÏ	 17
+ÌÇ	 17
+Óí	 17
+_áÇ_	 17
+ãæÌæÏ	 17
+æÑ_	 17
+Èå	 16
+Õæ	 16
+_æã	 16
+ÇÁ_	 16
+äå_	 16
+Ù	 16
+_æáÇ	 16
+Çäí	 16
+_åÐ	 16
+_ÐÇ	 16
+ÓÇ	 16
+ÓÊ	 16
+ßä	 16
+áÐ	 16
+Óã	 16
+_ÐÇÊ	 16
+ÇÚ	 16
+ñ	 16
+áæÇ	 16
+íÊ	 16
+ãÍ	 16
+_ÈÐ	 15
+íÞ	 15
+æáÇ_	 15
+ÇáÚÑ	 15
+áíå	 15
+_Çáãæ	 15
+áãæ	 15
+äÇ_	 15
+ÚÑÈ	 15
+_æÌ	 15
+_ÇáÔ	 15
+Çáãæ	 15
+Þ_	 15
+Ëá	 15
+_ÇáÚÑ	 15
+áó	 15
+áÚÑ	 15
+æÝ	 15
+_ä	 15
+ÈÐ	 15
+íá	 14
+Óá	 14
+ÐÇ_	 14
+!	 14
+Èíä_	 14
+ÇáæÇ	 14
+_ÑÓ	 14
+ÇáÚÑÈ	 14
+ÈÊ	 14
+áó_	 14
+Úáí	 14
+æÚ	 14
+áÚÑÈ	 14
+_ÇáÐ	 14
+åä	 14
+ÇáÊ	 14
+ÇáÐ	 14
+_Ãä_	 14
+Ý_	 14
+áÝ	 14
+Èú.	 14
+ãí	 14
+áÛ	 13
+åÐå_	 13
+åÐå	 13
+_åÐå	 13
+ÖÇ	 13
+_ßá	 13
+áØ	 13
+ÈáÇ	 13
Index: /main/tags/2.25/gsdl/perllib/textcat/chinese-big5.lm
===================================================================
--- /main/tags/2.25/gsdl/perllib/textcat/chinese-big5.lm	(revision 21064)
+++ /main/tags/2.25/gsdl/perllib/textcat/chinese-big5.lm	(revision 21064)
@@ -0,0 +1,400 @@
+_	 30653
+€	 2524
+_€	 2123
+¡	 1457
+¥	 1406
+_¥	 1245
+Š	 1244
+_¡	 1196
+_Š	 1100
+ª	 833
+M	 783
+M_	 764
+_ª	 727
+¡M_	 688
+¡M	 688
+_¡M_	 684
+_¡M	 684
+³	 680
+­	 675
+š	 659
+°	 629
+º	 593
+¬	 566
+_š	 560
+«	 533
+_­	 516
+®	 497
+_¬	 495
+_°	 485
+ž	 483
+§	 473
+©	 459
+·	 458
+µ	 448
+_«	 442
+¹	 436
+_®	 425
+±	 422
+_©	 422
+_³	 404
+²	 401
+»	 393
+º_	 385
+_·	 382
+_§	 374
+_ž	 373
+Ž	 350
+C	 333
+Ÿ	 324
+ªº	 318
+œ	 315
+_¹	 314
+_±	 312
+¶	 310
+ªº_	 303
+C_	 303
+_ªº	 303
+_ªº_	 302
+_²	 302
+@	 288
+_¶	 279
+@_	 275
+Ä	 275
+À	 272
+_Ž	 269
+_µ	 269
+|	 268
+Q	 265
+q	 260
+~	 260
+|_	 255
+~_	 250
+Á	 241
+A	 235
+Œ	 234
+_Ÿ	 233
+Ó	 233
+¡C_	 226
+¡C	 226
+Ó_	 225
+£	 224
+_¡C	 224
+_¡C_	 224
+³_	 222
+A_	 218
+Q_	 217
+O	 210
+q_	 210
+D	 209
+_Ä	 206
+ø	 202
+H	 200
+€@	 198
+Ã	 197
+¯	 196
+O_	 196
+_»	 195
+£_	 192
+H_	 191
+€@_	 190
+_€@	 189
+_€@_	 189
+ø_	 180
+ê	 177
+P	 176
+D_	 175
+¿	 173
+Î	 172
+ê_	 172
+Î_	 170
+_º	 168
+É	 165
+u	 164
+_Á	 162
+_Œ	 162
+_·|	 161
+·|	 161
+_·|_	 161
+Ü	 161
+L	 161
+·|_	 161
+û	 157
+p	 156
+o	 156
+Ç	 155
+_¯	 155
+µ_	 153
+Ü_	 151
+¡A	 151
+Ç_	 151
+W	 151
+€Q	 151
+L_	 150
+û_	 150
+Æ	 149
+u_	 149
+ó	 147
+Å	 147
+¡A_	 146
+_À	 145
+p_	 145
+ó_	 143
+_œ	 142
+_¡A_	 142
+_¡A	 142
+{	 141
+ä	 140
+Â	 140
+œ_	 140
+P_	 139
+É_	 137
+W_	 136
+{_	 136
+ä_	 135
+T	 134
+Ñ	 134
+j	 134
+×	 132
+_Ã	 131
+Ñ_	 131
+d	 130
+G	 130
+X	 130
+o_	 129
+j_	 127
+F	 126
+×_	 126
+F_	 125
+é	 124
+b	 123
+v	 122
+÷	 122
+_Â	 122
+Æ_	 121
+»_	 120
+Ð	 120
+d_	 120
+€_	 119
+b_	 118
+T_	 118
+æ	 117
+X_	 116
+n	 116
+_¿	 116
+e	 115
+Ò	 115
+÷_	 115
+v_	 114
+w	 114
+a	 114
+€H	 114
+æ_	 114
+i	 114
+­_	 113
+Ò_	 113
+ï	 112
+â	 111
+€H_	 111
+_€H_	 110
+_€H	 110
+è	 109
+°ê	 109
+À_	 107
+w_	 107
+_°ê	 107
+°ê_	 106
+_°ê_	 106
+è_	 106
+Š³	 105
+ï_	 105
+Õ	 105
+€Q_	 105
+a_	 104
+]	 104
+_Šb_	 103
+_Šb	 103
+h	 103
+_€Q	 103
+Šb	 103
+Šb_	 103
+_€Q_	 103
+¡_	 102
+Ê	 102
+­û_	 101
+­û	 101
+k	 100
+_­û_	 100
+e_	 100
+_­û	 100
+k_	 100
+_Š³	 100
+Š³_	 100
+_Š³_	 100
+B	 99
+ü	 99
+€é	 98
+°_	 98
+s	 98
+_Å	 98
+â_	 98
+€j	 98
+i_	 97
+]_	 97
+n_	 96
+á	 95
+h_	 95
+ü_	 95
+U	 95
+á_	 94
+€£	 94
+€j_	 94
+Ê_	 94
+_€j	 93
+_€j_	 93
+¹q	 92
+õ	 92
+È	 92
+Õ_	 92
+§_	 92
+È_	 91
+S	 90
+_€£_	 90
+€£_	 90
+_€£	 90
+ì	 90
+®É	 89
+ú	 89
+€€	 88
+B_	 88
+Ø	 88
+_®É_	 87
+_®É	 87
+U_	 87
+í	 87
+®É_	 87
+N	 87
+Š~	 86
+_Š~_	 86
+ì_	 86
+í_	 86
+ô	 86
+_Š~	 86
+Š~_	 86
+Ï	 85
+^	 85
+€Î	 84
+€Î_	 84
+ù	 84
+Ø_	 84
+G_	 84
+N_	 83
+_€Î	 83
+_€Î_	 83
+_€€	 83
+E	 83
+õ_	 82
+Žä	 81
+€€_	 81
+±_	 81
+ŸÇ	 81
+_€€_	 81
+ß	 80
+ô_	 80
+²_	 79
+ŸÇ_	 79
+_ŸÇ	 79
+_ŸÇ_	 79
+Ì	 78
+_ªø	 78
+_ªø_	 78
+ß_	 78
+ªø	 78
+ªø_	 78
+š_	 77
+S_	 77
+¬O_	 77
+_¬O_	 77
+_¬O	 77
+_Žä_	 77
+Žä_	 77
+Ï_	 77
+_Žä	 77
+¬O	 77
+é_	 77
+Ì_	 76
+ž_	 76
+ù_	 76
+ú_	 75
+ë	 74
+©ó	 72
+t	 72
+©ó_	 72
+_©ó	 72
+_©ó_	 72
+s_	 71
+K	 71
+€T	 71
+I	 71
+Ð_	 71
+€À	 70
+€è	 70
+¬°	 70
+Á_	 70
+¬°_	 69
+€W	 69
+«_	 69
+_¬°_	 68
+¬F_	 68
+_¬F	 68
+_€è_	 68
+¹_	 68
+_¬F_	 68
+_€è	 68
+€è_	 68
+€­	 68
+¬F	 68
+_¬°	 68
+¥X	 67
+ý	 67
+ö	 66
+ŠÊ_	 66
+ŠÊ	 66
+J	 66
+_ŠÊ_	 66
+¥D	 66
+_¹q	 66
+_ŠÊ	 66
+_¥D	 66
+l	 65
+Í	 65
+z	 65
+_€W	 65
+¥D_	 65
+_¥D_	 65
+ò	 65
+Ú	 65
+_€W_	 64
+€W_	 64
+¹q_	 64
+J_	 64
+ý_	 64
+_¹q_	 64
+_€T	 63
+_¥X_	 63
+¥X_	 63
+_€À	 63
+_¥X	 63
+€À_	 63
+¥»	 63
+_€À_	 63
+«á	 62
+Y	 62
+«á_	 61
+ò_	 61
+_«á	 61
+_«á_	 61
+Äµ	 61
+ö_	 61
+Äµ_	 60
+_€T_	 60
Index: /main/tags/2.25/gsdl/perllib/textcat/chinese-gb2312.lm
===================================================================
--- /main/tags/2.25/gsdl/perllib/textcat/chinese-gb2312.lm	(revision 21064)
+++ /main/tags/2.25/gsdl/perllib/textcat/chinese-gb2312.lm	(revision 21064)
@@ -0,0 +1,400 @@
+_	 77350
+£	 7152
+_£	 5428
+µ	 3924
+Ä	 3063
+¡	 3020
+¹	 2565
+Ö	 2491
+Ê	 2490
+_¡	 2490
+¬	 2438
+Ð	 2424
+»	 2394
+_µ	 2391
+œ	 2384
+Ò	 2349
+¬_	 2233
+_£¬_	 2102
+£¬_	 2102
+£¬	 2102
+_£¬	 2102
+Œ	 2057
+±	 2043
+Ë	 2000
+Ô	 1999
+È	 1936
+Í	 1856
+²	 1824
+Ó	 1824
+°	 1796
+·	 1780
+¶	 1752
+Î	 1728
+Ï	 1726
+Ž	 1696
+Ä_	 1637
+³	 1631
+Ã	 1630
+ž	 1630
+É	 1596
+Õ	 1571
+£_	 1545
+×	 1535
+Á	 1520
+µÄ	 1505
+µÄ_	 1500
+_µÄ	 1470
+_µÄ_	 1466
+º	 1450
+€	 1429
+ú	 1425
+Ç	 1367
+Ÿ	 1364
+À	 1356
+¿	 1335
+Æ	 1306
+_Ê	 1286
+¢	 1215
+¡£_	 1173
+_¡£_	 1173
+_¡£	 1173
+¡£	 1173
+_Ò	 1141
+Ú	 1131
+_œ	 1124
+€_	 1105
+Â	 1083
+_Ö	 1076
+_¹	 1048
+_È	 1038
+_Ô	 1026
+ª	 1015
+±_	 1008
+Ì	 973
+Å	 952
+°_	 947
+¢_	 946
+Ú_	 932
+_Î	 908
+_Á	 904
+Ñ	 876
+_×	 831
+_ž	 823
+Ë_	 817
+_º	 808
+_²	 805
+_Ž	 803
+_·	 790
+_Ó	 785
+Ð_	 783
+_»	 768
+_Í	 766
+÷	 759
+_¶	 759
+µ_	 751
+_Œ	 749
+š	 744
+£€_	 740
+_£€	 740
+_£€_	 740
+£€	 740
+_Ÿ	 738
+ö	 733
+ú_	 720
+Ø	 708
+«	 694
+_Ë	 690
+ø	 688
+_Ä	 686
+_É	 685
+¡¢_	 674
+¡¢	 674
+_¡¢_	 674
+_¡¢	 674
+ª_	 663
+»_	 656
+_Õ	 651
+ê	 643
+¹_	 643
+_Ï	 632
+_³	 628
+â	 626
+ñ	 605
+Í_	 593
+®	 586
+_Ã	 585
+¯	 584
+û	 578
+_Ð	 574
+á	 563
+ó	 562
+_°	 549
+œ_	 534
+_±	 521
+Äê	 515
+¹ú	 510
+ö_	 507
+Ö_	 503
+Ç_	 493
+Ò»	 493
+_¿	 482
+®_	 481
+ý	 476
+ÔÚ	 474
+ê_	 470
+£°	 468
+_£°	 465
+£°_	 465
+_£°_	 465
+ÔÚ_	 464
+ò	 455
+ø_	 450
+©	 449
+_Æ	 449
+þ	 448
+_À	 448
+à	 445
+ÁË	 445
+ì	 441
+·_	 434
+_Ç	 432
+Â_	 430
+ü	 428
+ÁË_	 427
+_£±	 426
+_£±_	 426
+£±_	 426
+£±	 426
+ºÍ	 425
+÷_	 424
+_ÔÚ	 423
+_Ò»	 419
+­	 419
+í	 417
+Äê_	 417
+_ÔÚ_	 415
+ï	 413
+Ã_	 412
+Ž_	 411
+ç	 411
+â_	 410
+é	 409
+Ï_	 402
+²_	 400
+§	 398
+_ÁË	 397
+_ºÍ	 397
+Ó_	 395
+_Ì	 393
+š_	 392
+ß	 390
+¯_	 387
+î	 386
+Ü	 385
+Ø_	 383
+_ÁË_	 380
+ºÍ_	 379
+ò_	 378
+_Å	 372
+Ù	 368
+_ºÍ_	 368
+û_	 364
+ž_	 359
+«_	 358
+¿_	 356
+Œ_	 355
+ë	 355
+¡_	 349
+³_	 346
+Ò_	 343
+Ô_	 343
+Å_	 340
+ã	 340
+ÈË	 338
+ÖÐ	 338
+¶_	 336
+ý_	 331
+ù	 329
+ñ_	 324
+Ò»_	 309
+¹ú_	 306
+å	 304
+¹€	 300
+ï_	 298
+ó_	 297
+ÓÐ	 296
+È_	 294
+ä	 293
+_Ñ	 290
+Š	 289
+ë_	 281
+_Äê	 276
+ì_	 274
+Òµ	 274
+ß_	 273
+»á	 272
+á_	 270
+ð	 270
+æ	 270
+©_	 269
+_Ò»_	 269
+Õ_	 268
+õ	 268
+_ÖÐ	 267
+ÐÐ	 267
+ÉÏ	 266
+à_	 265
+ü_	 264
+é_	 264
+_Â	 262
+¥	 258
+í_	 257
+§_	 256
+Æ_	 248
+Òµ_	 246
+²ú	 242
+É_	 242
+Û	 242
+ã_	 237
+Ãñ	 233
+·¢	 230
+²»	 229
+µØ	 228
+Îª	 228
+ÊÇ	 226
+_ÓÐ	 225
+ç_	 225
+Ê_	 224
+Žó	 224
+º_	 224
+ÊÇ_	 223
+ŒÒ	 223
+Î_	 222
+î_	 222
+þ_	 221
+³ö	 221
+_Õâ	 220
+Õâ	 220
+Ù_	 220
+å_	 219
+£¹	 218
+£¹_	 217
+_£¹_	 217
+_£¹	 217
+ÓÐ_	 217
+_ÈË	 214
+žö	 210
+_ÉÏ	 210
+è	 209
+·Ö	 209
+Éú	 208
+²¿	 208
+õ_	 208
+_¹ú	 207
+À_	 207
+_¡°	 205
+¡±_	 205
+¡°_	 205
+¡±	 205
+_¡°_	 205
+_¡±_	 205
+_¡±	 205
+¡°	 205
+£ž	 204
+Š_	 203
+×÷	 202
+Ÿ_	 202
+_Äê_	 201
+£²	 201
+_£²_	 200
+_£²	 200
+£²_	 200
+žö_	 199
+Ñ_	 197
+_£ž	 197
+£ž_	 197
+_£ž_	 197
+_¹€	 196
+Ý	 193
+_²»	 191
+£µ	 189
+ð_	 188
+_£µ	 186
+_£µ_	 186
+Ü_	 186
+£µ_	 186
+£³	 183
+œø	 183
+¶à	 182
+Îª_	 182
+ŒÒ_	 180
+ÊÐ	 179
+ÈÕ	 179
+³É	 178
+_ÊÇ	 178
+æ_	 177
+_ÊÇ_	 177
+ÈË_	 177
+ù_	 176
+Õþ	 175
+µœ	 174
+_Îª	 173
+È«	 171
+­_	 171
+Ÿü	 171
+œš	 171
+££	 169
+_£³_	 169
+_££	 169
+_££_	 169
+£³_	 169
+££_	 169
+_£³	 169
+_·¢	 168
+_žö	 168
+Û_	 168
+µœ_	 167
+_¶à	 166
+×_	 166
+¶à_	 166
+Òª	 165
+ÓÃ	 164
+Ê±	 164
+_Žó	 164
+ÖÐ_	 163
+Ý_	 160
+»á_	 160
+ÉÏ_	 159
+ô	 158
+_žö_	 157
+ÐÐ_	 157
+¶¯	 156
+_ÓÐ_	 156
+_¶à_	 155
+ÒÔ	 155
+³€	 154
+ÐÂ	 154
+_œš	 154
+_µØ	 154
+ŒÓ	 152
+_ÈÕ	 151
+_ÊÐ	 151
+ÀŽ	 151
+Ê¡	 149
+¿ª	 148
+ä_	 148
+_Ê¡	 148
+Àí	 147
+_³ö	 146
+µØ_	 145
+_È«	 143
+Í¬	 143
+Íò	 142
+_·Ö	 141
+Íò_	 140
+Ö÷	 140
+Ñ§	 140
+Å©	 139
+Òª_	 139
+_œø	 137
Index: /main/tags/2.25/gsdl/perllib/textcat/danish.lm
===================================================================
--- /main/tags/2.25/gsdl/perllib/textcat/danish.lm	(revision 21064)
+++ /main/tags/2.25/gsdl/perllib/textcat/danish.lm	(revision 21064)
@@ -0,0 +1,400 @@
+_	 21274
+e	 9291
+r	 5307
+n	 4733
+i	 3976
+t	 3948
+s	 3751
+a	 3296
+l	 3063
+d	 3025
+o	 2868
+g	 2471
+er	 2164
+k	 2002
+m	 1680
+e_	 1655
+en	 1613
+f	 1507
+de	 1484
+r_	 1379
+v	 1245
+u	 1176
+t_	 1081
+n_	 1032
+er_	 992
+b	 942
+.	 870
+ge	 868
+._	 831
+re	 816
+h	 816
+et	 813
+te	 813
+p	 806
+in	 788
+or	 775
+_s	 753
+_a	 749
+en_	 712
+_e	 691
+ti	 689
+an	 687
+,	 681
+,_	 677
+_f	 655
+_d	 645
+el	 642
+ng	 635
+nd	 634
+g_	 634
+se	 615
+le	 615
+st	 607
+s_	 601
+_o	 572
+ne	 560
+li	 537
+et_	 524
+es	 521
+_i	 512
+ri	 511
+sk	 510
+_de	 498
+å	 497
+ar	 475
+ed	 473
+ig	 463
+at	 452
+_m	 446
+is	 443
+fo	 441
+æ	 441
+ve	 438
+_k	 434
+ø	 432
+der	 429
+ke	 428
+ing	 427
+og	 426
+_b	 412
+me	 408
+il	 407
+for	 405
+ns	 394
+y	 389
+_h	 380
+_t	 374
+on	 371
+d_	 370
+al	 362
+be	 359
+_fo	 351
+af	 336
+de_	 335
+_og	 333
+_p	 332
+og_	 325
+om	 325
+_for	 324
+_og_	 313
+l_	 308
+nge	 302
+i_	 295
+_v	 294
+c	 289
+ter	 283
+ll	 280
+ni	 278
+nde	 278
+rs	 277
+_af	 277
+un	 275
+ra	 271
+ko	 271
+den	 270
+_i_	 268
+id	 265
+til	 265
+j	 265
+vi	 264
+D	 260
+ere	 256
+ma	 255
+si	 253
+f_	 252
+af_	 238
+_af_	 235
+ik	 235
+m_	 234
+å_	 232
+_ti	 227
+_D	 226
+_u	 226
+_er	 225
+nt	 224
+_en	 224
+ls	 221
+es_	 216
+lig	 216
+ger	 216
+re_	 210
+ag	 210
+_me	 207
+at_	 204
+lle	 200
+ge_	 200
+_til	 200
+ige	 199
+_er_	 199
+der_	 199
+em	 199
+ds	 197
+r.	 195
+io	 195
+r._	 195
+ud	 193
+_at	 192
+_at_	 191
+ta	 190
+els	 190
+_l	 190
+ha	 190
+il_	 189
+or_	 189
+ke_	 186
+rt	 185
+gen	 184
+ka	 183
+-	 180
+rk	 180
+ning	 178
+ol	 178
+nin	 178
+la	 177
+ld	 175
+De	 175
+it	 173
+ede	 172
+ed_	 171
+_ko	 171
+lse	 171
+ek	 168
+else	 167
+inge	 167
+på	 167
+ng_	 167
+_på	 167
+iv	 166
+ør	 166
+so	 165
+he	 165
+ens	 165
+ske	 165
+ind	 164
+til_	 163
+rn	 163
+ide	 162
+ev	 162
+den_	 162
+to	 162
+sen	 160
+_be	 160
+sa	 160
+bl	 158
+_g	 158
+an_	 157
+det	 156
+om_	 156
+ru	 156
+va	 155
+_til_	 155
+ste	 154
+rd	 153
+_på_	 152
+k_	 152
+på_	 152
+di	 152
+kr	 152
+K	 151
+_De	 149
+for_	 148
+te_	 148
+kon	 148
+ver	 147
+mm	 146
+am	 146
+_en_	 145
+_r	 145
+ne_	 144
+ing_	 144
+tr	 143
+le_	 142
+del	 142
+_in	 142
+gt	 140
+_st	 138
+S	 138
+eg	 138
+gs	 138
+tt	 138
+r,	 137
+ser	 137
+r,_	 137
+er.	 137
+ro	 137
+er._	 137
+_for_	 136
+ent	 136
+kt	 136
+eri	 135
+ur	 134
+lin	 134
+B	 133
+A	 133
+sti	 133
+ner	 133
+da	 133
+ris	 132
+ion	 132
+_K	 131
+ern	 131
+ers	 130
+ist	 130
+ær	 130
+ige_	 130
+_si	 130
+tte	 129
+E	 128
+_n	 128
+nn	 127
+_B	 126
+_ha	 126
+_.	 126
+rne	 125
+H	 125
+_ud	 125
+rin	 124
+na	 124
+und	 124
+ft	 124
+_der	 124
+ku	 123
+_A	 122
+ler	 120
+and	 120
+end	 120
+ns_	 120
+rg	 119
+op	 119
+er,_	 119
+er,	 119
+ar_	 118
+P	 118
+_S	 117
+_H	 117
+_._	 116
+ov	 116
+erne	 115
+tio	 115
+med	 115
+tion	 115
+_E	 115
+_P	 115
+det_	 114
+pr	 114
+e.	 113
+ter_	 113
+:	 113
+kk	 113
+e._	 113
+e,_	 113
+e,	 113
+od	 113
+kke	 113
+ten	 113
+ling	 113
+:_	 112
+mi	 112
+eli	 112
+lo	 111
+som	 111
+_den	 111
+rb	 110
+se_	 110
+ell	 110
+sid	 110
+nne	 109
+fi	 108
+lt	 107
+v_	 107
+_de_	 107
+ark	 106
+lige	 106
+ngen	 106
+ie	 105
+_med	 105
+_der_	 105
+ring	 105
+a_	 105
+_vi	 104
+-_	 104
+ys	 103
+gel	 103
+_so	 103
+ia	 103
+ive	 102
+ej	 101
+ati	 101
+ren	 101
+_det	 101
+side	 101
+ske_	 101
+br	 100
+gi	 100
+F	 100
+M	 100
+ul	 99
+isk	 99
+men	 99
+n,_	 99
+age	 99
+fr	 99
+n,	 99
+tu	 98
+ts	 98
+_ma	 98
+nder	 98
+ot	 97
+dt	 97
+R	 97
+med_	 96
+ho	 96
+ans	 95
+_kon	 95
+pe	 95
+ce	 94
+gr	 93
+mme	 92
+ret	 92
+lige_	 92
+mu	 91
+_med_	 91
+hv	 91
+væ	 91
+Det	 91
+ens_	 91
+kl	 91
+_M	 90
+T	 90
+ingen	 90
+rm	 90
+ill	 89
+elle	 89
+ef	 89
+ene	 89
+nds	 89
+ove	 89
+som_	 89
+C	 88
+_den_	 88
Index: /main/tags/2.25/gsdl/perllib/textcat/dutch.lm
===================================================================
--- /main/tags/2.25/gsdl/perllib/textcat/dutch.lm	(revision 21064)
+++ /main/tags/2.25/gsdl/perllib/textcat/dutch.lm	(revision 21064)
@@ -0,0 +1,400 @@
+_	 20104
+e	 9848
+n	 5323
+a	 3733
+t	 3683
+i	 3490
+r	 3195
+d	 2876
+o	 2845
+n_	 2443
+en	 2439
+s	 2195
+e_	 1842
+l	 1837
+g	 1522
+en_	 1500
+de	 1489
+er	 1388
+t_	 1377
+v	 1253
+u	 1217
+k	 1204
+_d	 1136
+h	 1102
+m	 1084
+an	 939
+te	 875
+j	 857
+in	 810
+_v	 793
+r_	 751
+de_	 742
+ee	 737
+p	 732
+et	 718
+ge	 716
+aa	 708
+b	 703
+_e	 686
+st	 669
+z	 668
+ie	 662
+_de	 655
+w	 631
+c	 611
+.	 604
+s_	 582
+_de_	 576
+_h	 572
+el	 570
+ij	 564
+._	 554
+et_	 531
+an_	 522
+he	 505
+_o	 497
+nd	 478
+_i	 475
+ar	 459
+_m	 451
+re	 442
+ve	 441
+'	 428
+or	 424
+ng	 421
+at	 418
+_s	 415
+oo	 403
+_z	 401
+le	 395
+_b	 394
+_a	 391
+_he	 386
+va	 385
+er_	 381
+me	 372
+_w	 368
+f	 361
+on	 351
+_t	 351
+_va	 345
+_g	 342
+di	 342
+nt	 340
+,	 335
+g_	 335
+,_	 334
+van	 327
+ch	 326
+is	 326
+ing	 325
+be	 325
+ni	 320
+it	 317
+een	 316
+_van	 315
+al	 310
+den	 309
+ti	 309
+van_	 307
+oe	 302
+ke	 302
+_van_	 299
+aar	 299
+d_	 295
+we	 293
+da	 292
+tu	 290
+_ee	 290
+ud	 287
+een_	 286
+li	 284
+es	 282
+_st	 281
+ver	 281
+ten	 281
+ri	 275
+nde	 275
+der	 274
+_in	 270
+k_	 268
+vo	 267
+het	 266
+oor	 264
+_het	 262
+het_	 262
+_het_	 259
+_een	 258
+l_	 258
+ze	 257
+_n	 254
+ro	 248
+gen	 243
+_een_	 241
+at_	 240
+op	 238
+n.	 238
+_en	 237
+rs	 237
+_da	 235
+stu	 232
+in_	 230
+_be	 229
+_ge	 228
+_k	 226
+rd	 226
+tud	 220
+_en_	 220
+n._	 217
+te_	 209
+ei	 208
+ent	 206
+_me	 203
+la	 202
+ek	 202
+ed	 201
+ra	 200
+stud	 200
+en.	 200
+ie_	 197
+ste	 196
+_vo	 195
+_in_	 193
+_stu	 191
+zi	 191
+om	 189
+ui	 189
+en._	 186
+ten_	 185
+_stud	 185
+ude	 184
+die	 183
+ns	 183
+_j	 181
+D	 179
+aan	 179
+se	 179
+ma	 178
+_ve	 176
+ne	 174
+_p	 174
+eg	 173
+p_	 172
+ar_	 172
+aar_	 171
+_te	 170
+ng_	 169
+_we	 169
+''	 167
+_D	 165
+ers	 164
+_op	 163
+dat	 161
+dat_	 160
+ig	 160
+ere	 159
+eer	 158
+_zi	 158
+voor	 156
+voo	 156
+nge	 155
+nder	 151
+nte	 151
+or_	 150
+ta	 150
+je	 149
+ing_	 148
+ll	 148
+_ver	 147
+jk	 146
+oor_	 146
+_dat	 145
+ijk	 145
+ren	 145
+is_	 145
+_dat_	 144
+_l	 144
+and	 144
+lij	 143
+ter	 143
+na	 142
+uden	 139
+tude	 138
+_voor	 136
+_voo	 136
+ond	 136
+ken	 135
+cht	 135
+_al	 135
+ht	 135
+wa	 134
+ho	 133
+em	 133
+den_	 133
+pe	 132
+sc	 132
+un	 131
+ur	 131
+_di	 130
+gen_	 130
+zo	 129
+rt	 129
+ev	 128
+mo	 128
+lijk	 127
+_is	 126
+stude	 124
+ha	 123
+to	 122
+el_	 121
+og	 121
+op_	 121
+sch	 120
+ol	 120
+ente	 119
+_u	 118
+pr	 118
+end	 118
+mi	 117
+iet	 116
+_aa	 116
+eli	 115
+dent	 115
+ijn	 115
+jn	 115
+ou	 115
+men	 114
+_'	 114
+tie	 113
+_is_	 113
+nie	 113
+tr	 112
+ak	 112
+id	 112
+udent	 111
+tuden	 111
+uit	 110
+_te_	 109
+aan_	 109
+ld	 109
+S	 108
+_aan	 108
+ede	 108
+ja	 107
+nten	 107
+it_	 107
+je_	 107
+ts	 107
+erd	 106
+est	 106
+E	 105
+_op_	 105
+ad	 104
+al_	 104
+_ze	 104
+_on	 104
+rk	 104
+lle	 103
+ens	 103
+gel	 103
+m_	 103
+len	 103
+_r	 102
+ec	 102
+inge	 102
+met	 102
+_met	 101
+si	 100
+die_	 100
+us	 100
+onde	 99
+_ni	 99
+De	 99
+eu	 99
+dente	 99
+enten	 99
+ic	 99
+_met_	 98
+f_	 98
+met_	 98
+no	 97
+ko	 96
+voor_	 96
+rde	 96
+H	 96
+ngen	 95
+lo	 95
+ot	 95
+as	 94
+zij	 93
+_nie	 92
+vi	 92
+eb	 92
+_De	 92
+_zij	 91
+ep	 91
+wi	 91
+_zo	 91
+kt	 91
+ege	 91
+G	 91
+bi	 90
+j_	 90
+ij_	 90
+ze_	 90
+do	 90
+lan	 89
+ov	 89
+udi	 89
+ord	 89
+onder	 89
+V	 88
+elij	 88
+_wa	 88
+elijk	 88
+ef	 88
+_die	 87
+ag	 86
+erk	 86
+eren	 86
+R	 85
+ik	 85
+_ma	 85
+gr	 85
+am	 85
+_mo	 84
+ul	 84
+nn	 83
+eve	 83
+De_	 83
+maa	 83
+ingen	 83
+wo	 83
+_''	 83
+O	 83
+tudi	 82
+I	 82
+nt_	 82
+tudie	 81
+ven	 81
+udie	 81
+nten_	 81
+_die_	 81
+jaa	 80
+ka	 80
+eke	 80
+ite	 80
+a_	 80
+_je	 80
+ac	 80
+jaar	 80
+_je_	 79
+_H	 79
+_zijn	 79
+zijn	 79
+n,	 78
+nen	 78
+N	 78
+n,_	 78
+ijn_	 77
Index: /main/tags/2.25/gsdl/perllib/textcat/english.lm
===================================================================
--- /main/tags/2.25/gsdl/perllib/textcat/english.lm	(revision 21064)
+++ /main/tags/2.25/gsdl/perllib/textcat/english.lm	(revision 21064)
@@ -0,0 +1,400 @@
+_	 20326
+e	 6617
+t	 4843
+o	 3834
+n	 3653
+i	 3602
+a	 3433
+s	 2945
+r	 2921
+h	 2507
+e_	 2000
+d	 1816
+_t	 1785
+c	 1639
+l	 1635
+th	 1535
+he	 1351
+_th	 1333
+u	 1309
+f	 1253
+m	 1175
+p	 1151
+_a	 1145
+the	 1142
+_the	 1060
+s_	 978
+er	 968
+_o	 967
+he_	 928
+d_	 888
+t_	 885
+the_	 844
+_the_	 843
+on	 842
+in	 817
+y	 783
+n_	 773
+b	 761
+re	 754
+,	 734
+,_	 732
+an	 732
+g	 728
+w	 718
+_i	 707
+en	 676
+f_	 599
+y_	 595
+of	 594
+_of	 592
+es	 589
+ti	 587
+v	 580
+_of_	 575
+of_	 575
+nd	 568
+at	 549
+r_	 540
+_w	 534
+it	 522
+ed	 496
+_p	 494
+nt	 485
+_c	 462
+o_	 457
+io	 450
+_an	 439
+te	 432
+or	 425
+_b	 418
+nd_	 407
+to	 406
+st	 402
+is	 401
+_s	 396
+_in	 389
+ion	 385
+and	 385
+de	 384
+ve	 382
+ha	 375
+ar	 366
+_m	 361
+and_	 360
+_and	 360
+_and_	 358
+se	 353
+_to	 347
+me	 346
+to_	 344
+ed_	 339
+.	 330
+be	 329
+_f	 329
+._	 329
+_to_	 320
+co	 317
+ic	 316
+ns	 308
+al	 307
+le	 304
+ou	 304
+ce	 293
+ent	 279
+l_	 278
+_co	 277
+tio	 275
+on_	 274
+_d	 274
+tion	 268
+ri	 266
+_e	 264
+ng	 253
+hi	 251
+er_	 249
+ea	 246
+as	 245
+_be	 242
+pe	 242
+h_	 234
+_r	 232
+ec	 227
+ch	 223
+ro	 222
+ct	 220
+_h	 219
+pr	 217
+in_	 217
+ne	 214
+ll	 214
+rt	 213
+s,_	 210
+s,	 210
+li	 209
+ra	 208
+T	 207
+wh	 204
+a_	 203
+ac	 201
+_wh	 199
+_n	 196
+ts	 196
+di	 196
+es_	 195
+si	 194
+re_	 193
+at_	 192
+nc	 192
+ie	 190
+_a_	 188
+_in_	 185
+ing	 184
+us	 182
+_re	 182
+g_	 179
+ng_	 178
+op	 178
+con	 177
+tha	 175
+_l	 174
+_tha	 174
+ver	 173
+ma	 173
+ion_	 171
+_con	 171
+ci	 170
+ons	 170
+_it	 170
+po	 169
+ere	 168
+is_	 167
+ta	 167
+la	 166
+_pr	 165
+fo	 164
+ho	 164
+ir	 162
+ss	 161
+men	 160
+be_	 160
+un	 159
+ty	 159
+_be_	 158
+ing_	 157
+om	 156
+ot	 156
+hat	 155
+ly	 155
+_g	 155
+em	 153
+_T	 151
+rs	 150
+mo	 148
+ch_	 148
+wi	 147
+we	 147
+ad	 147
+ts_	 145
+res	 143
+_wi	 143
+I	 143
+hat_	 142
+ei	 141
+ly_	 141
+ni	 140
+os	 140
+ca	 139
+ur	 139
+A	 138
+ut	 138
+that	 138
+_that	 137
+ati	 137
+_fo	 137
+st_	 137
+il	 136
+or_	 136
+for	 136
+pa	 136
+ul	 135
+ate	 135
+ter	 134
+it_	 134
+nt_	 133
+that_	 132
+_ha	 129
+al_	 128
+el	 128
+as_	 127
+ll_	 127
+_ma	 125
+no	 124
+ment	 124
+an_	 124
+tion_	 122
+su	 122
+bl	 122
+_de	 122
+nce	 120
+pl	 120
+fe	 119
+tr	 118
+so	 118
+int	 115
+ov	 114
+e,	 114
+e,_	 114
+_u	 113
+ent_	 113
+Th	 113
+her	 113
+j	 112
+atio	 112
+ation	 112
+_Th	 111
+le_	 110
+ai	 110
+_it_	 110
+_on	 110
+_for	 109
+ect	 109
+k	 109
+hic	 108
+est	 108
+der	 107
+tu	 107
+na	 106
+_by_	 106
+by_	 106
+E	 106
+by	 106
+_by	 106
+ve_	 106
+_di	 106
+en_	 104
+vi	 104
+m_	 103
+_whi	 102
+iv	 102
+whi	 102
+ns_	 102
+_A	 101
+ich	 100
+ge	 100
+pro	 99
+ess	 99
+_whic	 99
+ers	 99
+hich	 99
+ce_	 99
+which	 99
+whic	 99
+all	 98
+ove	 98
+_is	 98
+ich_	 97
+ee	 97
+hich_	 97
+n,_	 96
+n,	 96
+im	 95
+ir_	 94
+hei	 94
+ions	 94
+sti	 94
+se_	 94
+per	 93
+The	 93
+_pa	 93
+heir	 93
+id	 93
+eir	 93
+eir_	 93
+ig	 93
+heir_	 93
+_no	 93
+ev	 93
+era	 92
+_int	 92
+ted	 91
+_The	 91
+ies	 91
+art	 91
+thei	 90
+_ar	 90
+_thei	 90
+their	 90
+_pro	 90
+et	 89
+_pe	 88
+_mo	 88
+ther	 88
+x	 87
+gh	 87
+S	 87
+_is_	 87
+ol	 87
+ty_	 87
+_I	 86
+nde	 86
+am	 86
+rn	 86
+nte	 86
+mp	 85
+_su	 84
+_we	 84
+par	 84
+_v	 84
+pu	 82
+his	 82
+ow	 82
+mi	 82
+go	 81
+N	 81
+ue	 81
+ple	 81
+ep	 80
+ab	 80
+;_	 80
+;	 80
+ex	 80
+ain	 80
+over	 80
+_un	 79
+q	 79
+qu	 79
+pp	 79
+ith	 79
+ry	 79
+_as	 79
+ber	 79
+ub	 78
+av	 78
+uc	 78
+s._	 77
+s.	 77
+enc	 77
+are	 77
+iti	 77
+gr	 76
+his_	 76
+ua	 76
+part	 76
+ff	 75
+eve	 75
+O	 75
+rea	 74
+ous	 74
+ia	 74
+The_	 73
+ag	 73
+mb	 73
+_go	 73
+fa	 72
+on,_	 72
+ern	 72
+t,_	 72
+on,	 72
+t,	 72
+_me	 71
Index: /main/tags/2.25/gsdl/perllib/textcat/esperanto.lm
===================================================================
--- /main/tags/2.25/gsdl/perllib/textcat/esperanto.lm	(revision 21064)
+++ /main/tags/2.25/gsdl/perllib/textcat/esperanto.lm	(revision 21064)
@@ -0,0 +1,400 @@
+_	 57050
+a	 16035
+i	 12706
+e	 12227
+o	 12102
+n	 10393
+s	 8344
+l	 7707
+r	 7492
+t	 7134
+k	 5376
+u	 4558
+j	 3946
+a_	 3875
+m	 3783
+d	 3710
+p	 3693
+la	 2840
+s_	 2769
+e_	 2751
+.	 2706
+_l	 2635
+_k	 2619
+v	 2531
+n_	 2504
+o_	 2444
+i_	 2333
+._	 2278
+on	 2238
+,	 2193
+,_	 2182
+_la	 2100
+en	 2080
+j_	 2050
+as	 2028
+la_	 2012
+ta	 1956
+_la_	 1907
+an	 1882
+_p	 1850
+g	 1831
+_e	 1791
+_d	 1778
+is	 1737
+aj	 1658
+st	 1635
+_s	 1575
+c	 1526
+de	 1517
+oj	 1498
+er	 1476
+ti	 1456
+f	 1443
+_a	 1442
+b	 1427
+ro	 1379
+_m	 1351
+ra	 1341
+nt	 1293
+ka	 1270
+ri	 1258
+al	 1249
+as_	 1248
+aj_	 1213
+to	 1209
+_de	 1203
+_t	 1200
+te	 1179
+_n	 1176
+is_	 1171
+in	 1151
+ko	 1145
+or	 1114
+es	 1083
+re	 1034
+ia	 1029
+li	 1022
+de_	 1016
+_de_	 979
+ar	 974
+_v	 966
+vi	 942
+lo	 932
+x	 928
+io	 917
+ne	 855
+no	 848
+ni	 843
+mi	 835
+ma	 819
+_ka	 816
+el	 815
+pr	 771
+z	 744
+un	 734
+l_	 732
+po	 730
+_f	 725
+ø	 724
+est	 691
+na	 687
+ki	 679
+kaj	 676
+si	 665
+u_	 663
+kaj_	 660
+"	 654
+tas	 651
+le	 650
+oj_	 648
+_i	 643
+tr	 642
+_pr	 630
+_es	 628
+jn	 626
+pe	 618
+_kaj	 616
+ig	 616
+_kaj_	 611
+do	 608
+sta	 606
+on_	 602
+ek	 602
+ci	 597
+r_	 595
+ý	 594
+_r	 593
+il	 592
+_est	 587
+di	 586
+am	 586
+_mi	 582
+aý	 578
+_vi	 577
+mo	 575
+ant	 565
+_ne	 562
+en_	 561
+o.	 559
+æ	 543
+iu	 538
+o,	 529
+ur	 527
+o._	 527
+om	 525
+o,_	 524
+at	 521
+va	 521
+-	 519
+_en	 518
+:	 513
+:_	 512
+_ti	 500
+M	 496
+h	 488
+nd	 484
+me	 484
+_al	 481
+_ko	 479
+ve	 478
+ie	 478
+_ki	 473
+it	 473
+L	 466
+_b	 465
+se	 462
+em	 452
+ol	 450
+nta	 449
+tu	 448
+ik	 444
+ov	 443
+da	 443
+_M	 440
+_po	 439
+tas_	 438
+ne_	 437
+et	 437
+_ma	 436
+_en_	 435
+su	 429
+pl	 426
+_L	 425
+pa	 420
+_o	 417
+vo	 408
+an_	 407
+ro_	 406
+sti	 406
+nu	 399
+kon	 396
+stas	 391
+m_	 391
+ir	 388
+n.	 386
+fa	 386
+jn_	 382
+ku	 382
+os	 376
+ke	 375
+n,	 375
+esta	 374
+n,_	 372
+_su	 362
+ta_	 362
+stas_	 359
+xi	 359
+Mi	 358
+_ne_	 356
+al_	 355
+nk	 353
+so	 353
+n._	 352
+id	 349
+_g	 348
+estas	 347
+ga	 346
+_h	 345
+per	 345
+_Mi	 340
+ok	 339
+K	 339
+mp	 337
+_esta	 337
+s,_	 335
+s,	 335
+_se	 333
+anta	 332
+ul	 326
+ran	 325
+_"	 323
+ý_	 322
+te_	 320
+ak	 320
+aý_	 320
+ed	 320
+rt	 319
+ojn	 318
+gi	 318
+_æ	 317
+tis	 316
+gx	 316
+mal	 316
+ia_	 315
+ks	 310
+_al_	 310
+mi_	 309
+S	 309
+lu	 309
+ns	 308
+kt	 305
+io_	 302
+ent	 300
+?	 300
+_K	 300
+ec	 300
+el_	 299
+_-	 299
+li_	 299
+E	 298
+þ	 298
+_li	 297
+fo	 296
+ter	 296
+_re	 296
+A	 295
+nto	 294
+vi_	 292
+La	 292
+_mal	 290
+nte	 288
+sp	 287
+sa	 287
+_mi_	 279
+ut	 278
+op	 278
+_ke	 277
+bo	 277
+ajn	 276
+un_	 276
+T	 274
+to_	 272
+-_	 272
+bl	 272
+_an	 271
+_La	 271
+øi	 269
+_S	 268
+_pl	 267
+_fa	 266
+ni_	 266
+La_	 265
+_E	 264
+N	 263
+tis_	 263
+_tr	 263
+'	 262
+!	 262
+_-_	 262
+pro	 261
+iu_	 261
+iø	 261
+nc	 260
+_si	 259
+du	 257
+_kon	 256
+ru	 255
+_vi_	 254
+_j	 253
+ce	 251
+ke_	 249
+ap	 248
+us	 247
+be	 247
+im	 247
+B	 246
+_ku	 246
+_La_	 246
+tra	 245
+ad	 245
+uj	 245
+ac	 245
+ita	 243
+pre	 242
+_pro	 242
+co	 241
+rm	 241
+_ni	 238
+_pe	 236
+?_	 234
+on.	 234
+toj	 234
+"_	 234
+j.	 234
+_ke_	 233
+s.	 232
+_A	 231
+av	 230
+ri_	 230
+_el	 229
+por	 229
+`	 224
+ev	 224
+las	 223
+P	 223
+j._	 221
+eni	 220
+_T	 220
+_B	 219
+j,_	 218
+j,	 218
+era	 217
+_in	 216
+on._	 216
+cx	 216
+_N	 215
+ion	 215
+ab	 215
+..	 214
+)	 213
+fi	 213
+or_	 212
+pri	 212
+s._	 212
+_por	 210
+ez	 210
+in_	 210
+am_	 209
+on,_	 209
+ll	 209
+æi	 209
+on,	 209
+_ve	 208
+ris	 208
+esti	 208
+!_	 207
+men	 206
+vas	 205
+iel	 204
+taj	 203
+_c	 201
+aro	 201
+ank	 200
+_pri	 200
+jo	 200
+ja	 200
+ont	 200
+lt	 199
+_P	 199
+igi	 199
+_pa	 197
+oj.	 197
+(	 196
+au	 195
+oro	 195
+ng	 195
+_(	 194
+sto	 194
+ast	 194
+ag	 193
Index: /main/tags/2.25/gsdl/perllib/textcat/finnish.lm
===================================================================
--- /main/tags/2.25/gsdl/perllib/textcat/finnish.lm	(revision 21064)
+++ /main/tags/2.25/gsdl/perllib/textcat/finnish.lm	(revision 21064)
@@ -0,0 +1,400 @@
+_	 19984
+a	 9133
+i	 8384
+t	 7797
+e	 6481
+n	 6431
+s	 5897
+l	 4504
+o	 4163
+u	 4106
+k	 4013
+ä	 3354
+n_	 2868
+m	 2569
+a_	 1987
+v	 1905
+r	 1827
+ta	 1580
+en	 1553
+is	 1515
+h	 1508
+y	 1462
+st	 1390
+in	 1375
+p	 1342
+j	 1333
+an	 1139
+si	 1073
+tt	 1030
+te	 1008
+en_	 982
+_k	 980
+it	 974
+ll	 947
+aa	 942
+ä_	 902
+va	 878
+el	 855
+_t	 851
+ka	 846
+i_	 835
+.	 832
+se	 818
+li	 806
+tä	 804
+oi	 767
+ai	 744
+._	 739
+tu	 734
+_o	 719
+mi	 715
+al	 703
+on	 684
+d	 681
+_v	 662
+et	 654
+_j	 641
+t_	 635
+ti	 632
+_m	 628
+_s	 620
+ja	 616
+ma	 596
+sa	 595
+la	 582
+ist	 575
+_e	 565
+to	 565
+ks	 557
+in_	 554
+es	 551
+il	 538
+an_	 536
+ki	 527
+,	 525
+ku	 525
+,_	 524
+us	 520
+as	 514
+nt	 512
+ri	 495
+ke	 494
+at	 491
+_p	 485
+le	 484
+ik	 483
+ss	 477
+ut	 469
+ö	 469
+sta	 460
+ee	 459
+uu	 458
+ol	 457
+ta_	 451
+ne	 445
+ää	 445
+ei	 443
+uo	 436
+ko	 433
+un	 430
+lu	 421
+ii	 420
+e_	 418
+nn	 413
+_h	 412
+ar	 408
+er	 402
+än	 396
+ja_	 386
+im	 381
+on_	 365
+_va	 363
+aan	 354
+_a	 352
+me	 350
+ak	 345
+ssa	 331
+na	 330
+ie	 329
+pa	 327
+_ja	 326
+ia	 325
+tä_	 322
+_l	 319
+vi	 317
+ise	 316
+tta	 315
+de	 314
+os	 312
+lli	 309
+_ja_	 304
+jo	 295
+vä	 290
+su	 289
+au	 287
+lis	 286
+_on	 285
+sä	 284
+uk	 280
+am	 280
+ot	 280
+ty	 275
+ett	 271
+ttä	 270
+ni	 269
+lä	 267
+ksi	 264
+nk	 264
+ht	 263
+ul	 261
+ell	 261
+sa_	 259
+ha	 257
+sen	 257
+a.	 254
+isi	 253
+ste	 253
+aan_	 252
+_on_	 252
+_ka	 252
+sk	 251
+kk	 246
+itt	 245
+ok	 242
+a._	 239
+all	 239
+yt	 239
+mä	 237
+mu	 237
+av	 237
+_y	 236
+lla	 233
+taa	 231
+ais	 231
+een	 230
+K	 230
+lt	 228
+s_	 227
+ast	 227
+iv	 226
+ssa_	 225
+ra	 225
+-	 223
+kse	 223
+oit	 220
+om	 220
+T	 219
+_ku	 218
+än_	 216
+aa_	 214
+at_	 214
+tel	 211
+ui	 210
+si_	 208
+rk	 207
+sta_	 207
+_jo	 203
+kä	 202
+_K	 201
+est	 200
+em	 200
+he	 199
+_n	 199
+vo	 198
+_ta	 196
+eh	 196
+_ol	 196
+S	 196
+nta	 196
+_ko	 194
+je	 194
+stä	 194
+är	 193
+ust	 191
+mis	 191
+ns	 190
+pu	 189
+nen	 188
+ät	 188
+toi	 188
+iin	 187
+ten	 187
+min	 186
+ista	 185
+hd	 184
+a,	 184
+a,_	 184
+sen_	 183
+E	 182
+lle	 181
+vat	 179
+ill	 177
+no	 176
+pä	 176
+lm	 176
+llis	 175
+n.	 175
+io	 172
+ine	 171
+n._	 170
+pi	 169
+uks	 168
+ava	 168
+ään	 166
+nen_	 165
+ah	 165
+_mu	 164
+tus	 163
+mm	 162
+_to	 162
+ek	 160
+int	 159
+_r	 159
+lin	 158
+oim	 158
+_T	 158
+A	 158
+imi	 157
+tö	 157
+la_	 157
+jä	 157
+aj	 156
+yh	 155
+o_	 154
+lo	 154
+oli	 153
+een_	 153
+le_	 153
+_si	 153
+g	 152
+aik	 151
+vat_	 150
+L	 149
+ur	 149
+ti_	 149
+sia	 148
+ite	 147
+inen	 147
+ain	 146
+sti	 146
+lla_	 146
+ys	 145
+_mi	 145
+val	 144
+stu	 144
+äm	 144
+alli	 143
+pe	 143
+utt	 142
+et_	 141
+_tu	 141
+eri	 140
+_E	 140
+:	 140
+nki	 139
+ir	 139
+llä	 138
+up	 138
+äi	 137
+ama	 137
+_ha	 135
+id	 135
+_se	 135
+po	 134
+inen_	 134
+tte	 133
+nna	 133
+ten_	 132
+or	 132
+ts	 131
+nä	 131
+yk	 131
+äs	 131
+_S	 130
+ses	 130
+ve	 130
+ess	 129
+äl	 129
+ita	 129
+lai	 129
+H	 129
+van	 127
+äk	 127
+kin	 127
+N	 127
+_te	 126
+den	 126
+tee	 126
+P	 126
+kaa	 126
+iin_	 125
+kun	 125
+ois	 125
+sit	 125
+oh	 124
+V	 124
+yö	 124
+äv	 124
+tav	 124
+voi	 124
+ia_	 123
+I	 123
+oll	 123
+maa	 122
+ih	 122
+oj	 122
+rj	 121
+ro	 121
+ikk	 120
+so	 120
+oo	 120
+oimi	 120
+do	 120
+pp	 119
+M	 119
+_ei	 118
+toim	 118
+op	 118
+uut	 118
+tet	 118
+_i	 118
+_ma	 117
+vai	 117
+lä_	 116
+u_	 116
+sy	 116
+kau	 116
+utta	 116
+un_	 115
+eu	 115
+ssä	 115
+tti	 115
+_sa	 115
+mp	 114
+eis	 114
+ka_	 112
+että	 112
+taa_	 111
+_et	 111
+hu	 111
+itu	 111
+suu	 111
+den_	 111
+ksen	 110
+ap	 110
+_ke	 110
+uv	 110
+tam	 110
+yv	 109
+aup	 109
+stä_	 109
+asta	 109
+äy	 109
+kan	 108
+nu	 108
+ukse	 108
+_toi	 107
+ien	 107
+hi	 107
+iss	 107
Index: /main/tags/2.25/gsdl/perllib/textcat/french.lm
===================================================================
--- /main/tags/2.25/gsdl/perllib/textcat/french.lm	(revision 21064)
+++ /main/tags/2.25/gsdl/perllib/textcat/french.lm	(revision 21064)
@@ -0,0 +1,400 @@
+_	 20800
+e	 7258
+i	 4051
+s	 4003
+a	 3972
+n	 3903
+r	 3650
+t	 3590
+u	 2968
+o	 2823
+l	 2723
+e_	 2632
+d	 2241
+s_	 1721
+_d	 1693
+c	 1663
+p	 1528
+é	 1320
+m	 1297
+es	 1164
+t_	 1106
+_l	 1079
+de	 1048
+on	 959
+_de	 940
+en	 939
+_p	 852
+nt	 825
+le	 808
+es_	 791
+re	 777
+,	 721
+,_	 720
+n_	 703
+de_	 685
+'	 670
+an	 667
+_de_	 645
+v	 641
+_s	 610
+r_	 596
+_c	 594
+er	 585
+ai	 575
+_a	 558
+_e	 554
+ou	 554
+q	 549
+qu	 538
+is	 530
+te	 528
+ti	 525
+ur	 519
+it	 514
+g	 498
+a_	 490
+f	 480
+la	 476
+in	 475
+_le	 441
+me	 436
+nt_	 432
+.	 427
+b	 427
+ra	 423
+io	 416
+ent	 415
+._	 404
+ne	 395
+ns	 392
+ion	 383
+h	 381
+ue	 376
+se	 371
+le_	 370
+ar	 370
+ie	 362
+co	 361
+at	 359
+tr	 359
+et	 349
+pr	 342
+ce	 336
+au	 328
+u_	 321
+il	 314
+_r	 313
+_la	 304
+un	 303
+eu	 303
+st	 300
+re_	 296
+ro	 290
+la_	 288
+on_	 287
+_m	 286
+_la_	 283
+que	 281
+_qu	 280
+_q	 280
+po	 275
+tio	 273
+tion	 273
+pa	 273
+li	 271
+_t	 269
+nc	 268
+si	 266
+_pr	 265
+ri	 264
+al	 263
+ui	 262
+_co	 259
+i_	 255
+ta	 255
+é_	 251
+x	 247
+em	 244
+l_	 243
+et_	 238
+_l'	 236
+l'	 236
+les	 233
+ns_	 233
+ir	 232
+_le_	 228
+ent_	 227
+or	 226
+ré	 224
+_f	 224
+ne_	 222
+à	 221
+ve	 220
+ch	 220
+it_	 219
+di	 219
+oi	 217
+-	 216
+ni	 215
+à_	 215
+les_	 215
+d'	 214
+el	 212
+ss	 212
+_n	 212
+ut	 211
+our	 210
+des	 210
+"	 208
+ur_	 207
+nd	 207
+er_	 206
+ait	 206
+ion_	 204
+rs	 202
+_en	 201
+_et	 200
+j	 200
+_d'	 200
+ll	 199
+_des	 198
+des_	 197
+_pa	 197
+té	 196
+_et_	 195
+_à	 195
+_à_	 195
+om	 193
+ma	 192
+ati	 190
+_des_	 189
+L	 188
+so	 187
+_u	 185
+è	 184
+_"	 183
+sa	 182
+_po	 181
+tre	 181
+dé	 181
+ue_	 180
+pe	 179
+en_	 179
+ont	 178
+_un	 178
+_L	 178
+us	 176
+_les	 176
+_les_	 176
+rt	 176
+is_	 173
+_i	 173
+du	 172
+e,_	 171
+e,	 171
+na	 171
+s,	 170
+s,_	 170
+as	 169
+men	 169
+M	 167
+ait_	 167
+'a	 166
+vi	 162
+ci	 159
+ant	 158
+_au	 158
+da	 157
+_M	 157
+ation	 155
+atio	 155
+con	 154
+que_	 153
+ons	 153
+eur	 151
+est	 149
+me_	 149
+mi	 149
+par	 148
+tion_	 148
+_so	 147
+te_	 147
+res	 144
+lo	 144
+ment	 144
+és	 144
+ans	 143
+_du	 142
+du_	 141
+ux	 141
+un_	 140
+y	 138
+pro	 138
+_du_	 136
+_dé	 136
+ce_	 135
+_se	 134
+_re	 134
+pl	 133
+A	 132
+ge	 131
+ic	 131
+su	 130
+x_	 129
+ien	 129
+nce	 129
+"_	 129
+ac	 128
+il_	 128
+qui	 128
+_pro	 127
+no	 127
+av	 126
+_v	 125
+_o	 125
+rs_	 125
+ans_	 124
+eme	 124
+bl	 123
+emen	 122
+_en_	 122
+iqu	 122
+ct	 122
+iq	 122
+lle	 122
+nn	 121
+ts	 121
+ement	 121
+ét	 120
+_"_	 120
+ér	 119
+té_	 119
+_ce	 119
+mp	 119
+ire	 119
+ui_	 119
+to	 118
+he	 117
+_é	 117
+ca	 117
+_j	 116
+ec	 116
+va	 116
+_par	 116
+ée	 115
+_con	 115
+se_	 114
+tre_	 113
+ique	 112
+dan	 111
+éc	 111
+ha	 110
+une	 110
+P	 110
+lu	 110
+ux_	 109
+_b	 108
+s.	 108
+pou	 108
+_pou	 108
+ier	 107
+C	 107
+ais	 106
+s._	 105
+ain	 104
+_un_	 104
+nte	 103
+'e	 103
+mo	 103
+mm	 103
+ment_	 102
+une_	 102
+com	 101
+_P	 101
+'i	 101
+_ma	 100
+do	 99
+ant_	 98
+anc	 98
+che	 97
+ap	 97
+ont_	 97
+_que	 97
+os	 97
+urs	 96
+_di	 96
+fi	 96
+im	 96
+pour	 96
+_pour	 96
+ê	 95
+ts_	 95
+_g	 95
+our_	 94
+_sa	 94
+ntr	 94
+_da	 94
+_ré	 93
+rai	 93
+rm	 93
+_qui	 93
+e.	 92
+am	 92
+_com	 91
+uv	 91
+_C	 91
+D	 91
+qui_	 90
+e._	 90
+pu	 89
+_qui_	 88
+ia	 87
+_dan	 87
+_dans	 87
+dans	 87
+ter	 87
+fo	 87
+son	 87
+dans_	 87
+id	 86
+ag	 86
+ine	 86
+tu	 85
+ran	 85
+au_	 85
+ol	 85
+oc	 84
+est_	 84
+st_	 84
+enc	 84
+F	 82
+_tr	 81
+'u	 81
+tai	 81
+ell	 80
+R	 79
+_su	 79
+S	 79
+ions	 79
+pré	 79
+sé	 78
+ab	 78
+né	 77
+_que_	 77
+_in	 77
+_av	 76
+pour_	 76
+fa	 76
+rr	 76
+air	 75
+_ch	 75
+_a_	 75
+ba	 74
+_pl	 74
+gr	 74
+tt	 74
+ssi	 74
+rd	 73
+pas	 73
+bi	 73
Index: /main/tags/2.25/gsdl/perllib/textcat/german.lm
===================================================================
--- /main/tags/2.25/gsdl/perllib/textcat/german.lm	(revision 21064)
+++ /main/tags/2.25/gsdl/perllib/textcat/german.lm	(revision 21064)
@@ -0,0 +1,400 @@
+_	 31586
+e	 15008
+n	 9058
+i	 7299
+r	 6830
+t	 5662
+s	 5348
+a	 4618
+h	 4176
+d	 4011
+er	 3415
+en	 3412
+u	 3341
+l	 3266
+n_	 2848
+c	 2636
+ch	 2460
+g	 2407
+o	 2376
+e_	 2208
+r_	 2128
+m	 2077
+_d	 1948
+de	 1831
+en_	 1786
+ei	 1718
+er_	 1570
+in	 1568
+te	 1505
+ie	 1505
+b	 1458
+t_	 1425
+f	 1306
+k	 1176
+ge	 1144
+s_	 1137
+un	 1113
+,	 1104
+,_	 1099
+w	 1099
+z	 1060
+nd	 1039
+he	 1004
+st	 989
+_s	 952
+_de	 949
+.	 909
+_e	 906
+ne	 906
+der	 880
+._	 847
+be	 841
+es	 829
+ic	 796
+_a	 791
+ie_	 779
+is	 769
+ich	 763
+an	 755
+re	 749
+di	 732
+ein	 730
+se	 730
+"	 720
+ng	 709
+_i	 706
+sc	 683
+sch	 681
+it	 673
+der_	 652
+h_	 651
+ch_	 642
+S	 630
+le	 609
+p	 609
+ä	 607
+ü	 603
+au	 603
+v	 602
+che	 599
+_w	 596
+d_	 585
+die	 576
+_di	 572
+m_	 562
+_die	 559
+el	 548
+_S	 540
+_der	 529
+li	 527
+_der_	 523
+si	 515
+al	 514
+ns	 507
+on	 501
+or	 495
+ti	 490
+ten	 487
+ht	 486
+die_	 485
+_die_	 483
+D	 479
+rt	 478
+nd_	 476
+_u	 470
+nt	 468
+A	 466
+in_	 464
+den	 461
+cht	 447
+und	 443
+me	 440
+_z	 429
+ung	 426
+ll	 423
+_un	 421
+_ei	 419
+_n	 415
+hr	 412
+ine	 412
+_A	 408
+_ein	 405
+ar	 404
+ra	 403
+_v	 400
+_g	 400
+as	 395
+zu	 392
+et	 389
+em	 385
+_D	 380
+eine	 376
+gen	 376
+g_	 376
+da	 368
+we	 366
+K	 365
+lt	 360
+B	 354
+_"	 353
+nde	 349
+ni	 347
+und_	 345
+E	 345
+ur	 345
+_m	 342
+ri	 341
+ha	 340
+eh	 339
+ten_	 338
+es_	 336
+_K	 336
+_und	 335
+ig	 335
+_b	 335
+hen	 334
+_und_	 332
+_au	 329
+_B	 327
+_da	 325
+_zu	 324
+_in	 322
+at	 321
+us	 318
+wi	 307
+n,	 305
+n,_	 304
+nn	 304
+te_	 301
+eit	 301
+_h	 300
+ter	 299
+M	 298
+n.	 295
+ß	 294
+ng_	 289
+sche	 289
+-	 283
+rs	 282
+den_	 282
+_si	 280
+G	 280
+im	 278
+_ge	 277
+chen	 276
+rd	 273
+_E	 273
+n._	 270
+icht	 270
+rn	 268
+uf	 267
+isch	 264
+isc	 264
+nen	 263
+_in_	 262
+_M	 260
+_er	 257
+ich_	 255
+ac	 253
+lic	 252
+_G	 252
+ber	 252
+la	 251
+vo	 251
+eb	 250
+ke	 249
+F	 248
+as_	 248
+hen_	 248
+ach	 245
+en,	 244
+ung_	 243
+lich	 243
+ste	 243
+en,_	 243
+_k	 241
+ben	 241
+_f	 241
+en.	 241
+_be	 239
+it_	 239
+L	 238
+_se	 237
+mi	 236
+ve	 236
+na	 236
+on_	 236
+P	 235
+ss	 234
+ist	 234
+ö	 234
+ht_	 233
+ru	 233
+st_	 229
+_F	 229
+ts	 227
+ab	 226
+W	 226
+ol	 225
+_eine	 225
+hi	 225
+so	 224
+em_	 223
+"_	 223
+ren	 222
+en._	 221
+chen_	 221
+R	 221
+ta	 221
+ere	 220
+ische	 219
+ers	 218
+ert	 217
+_P	 217
+tr	 217
+ed	 215
+ze	 215
+eg	 215
+ens	 215
+ür	 213
+ah	 212
+_vo	 212
+ne_	 211
+cht_	 210
+uc	 209
+_wi	 209
+nge	 208
+lle	 208
+fe	 207
+_L	 207
+ver	 206
+hl	 205
+V	 204
+ma	 203
+wa	 203
+auf	 201
+H	 198
+_W	 195
+T	 195
+nte	 193
+uch	 193
+l_	 192
+sei	 192
+nen_	 190
+u_	 189
+_den	 189
+_al	 189
+_V	 188
+t.	 188
+lte	 187
+ut	 186
+ent	 184
+sich	 183
+sic	 183
+il	 183
+ier	 182
+am	 181
+gen_	 180
+sen	 179
+fü	 178
+um	 178
+t._	 177
+f_	 174
+he_	 174
+ner	 174
+nst	 174
+ls	 174
+_sei	 173
+ro	 173
+ir	 173
+ebe	 173
+mm	 173
+ag	 172
+ern	 169
+t,_	 169
+t,	 169
+eu	 169
+ft	 168
+icht_	 167
+hre	 167
+Be	 166
+nz	 165
+nder	 165
+_T	 164
+_den_	 164
+iche	 163
+tt	 163
+zu_	 162
+and	 162
+J	 161
+rde	 160
+rei	 160
+_we	 159
+_H	 159
+ige	 159
+_Be	 158
+rte	 157
+hei	 156
+das	 155
+aus	 155
+che_	 154
+_das	 154
+_zu_	 154
+tz	 154
+_ni	 153
+das_	 153
+_R	 153
+N	 153
+des	 153
+_ve	 153
+_J	 152
+I	 152
+_das_	 152
+men	 151
+_so	 151
+_ver	 151
+_auf	 150
+ine_	 150
+_ha	 150
+rg	 149
+ind	 148
+eben	 148
+kt	 147
+mit	 147
+_an	 147
+her	 146
+Ge	 146
+Sc	 145
+_sich	 145
+U	 145
+Sch	 145
+_sic	 145
+end	 145
+Di	 144
+abe	 143
+ck	 143
+sse	 142
+ür_	 142
+ell	 142
+ik	 141
+o_	 141
+nic	 141
+nich	 141
+sa	 141
+_fü	 140
+hn	 140
+zi	 140
+no	 140
+nicht	 140
+im_	 139
+von_	 139
+von	 139
+_nic	 139
+_nich	 139
+eine_	 139
+oc	 138
+wei	 138
+io	 138
+schen	 138
+gt	 138
Index: /main/tags/2.25/gsdl/perllib/textcat/hindi.lm
===================================================================
--- /main/tags/2.25/gsdl/perllib/textcat/hindi.lm	(revision 21064)
+++ /main/tags/2.25/gsdl/perllib/textcat/hindi.lm	(revision 21064)
@@ -0,0 +1,400 @@
+_	 75620
+æ	 19109
+U	 16333
+ð	 11131
+€	 11107
+·	 10241
+·€	 7855
+Ú	 6993
+ÚU	 6598
+ç	 6322
+è	 6151
+Ù	 5887
+_·	 5800
+ã	 5370
+â	 5168
+U_	 5118
+æ_	 4935
+Ì	 4508
+×	 4467
+Ø	 4292
+ð_	 3962
+_·€	 3937
+è_	 3904
+Â	 3718
+€_	 3609
+Ü	 3563
+ãU	 3514
+_ç	 3394
+Ž	 3363
+ß	 2962
+¥	 2907
+ÚU_	 2851
+_¥	 2668
+_ã	 2632
+_â	 2575
+ô	 2527
+Î	 2513
+Ž_	 2512
+Á	 2451
+Uæ	 2336
+Õ	 2314
+_Â	 2280
+_×	 2260
+ñ	 2187
+¢	 2082
+»	 2078
+€æ	 1988
+ðŽ	 1913
+·€æ	 1886
+·ð	 1881
+ð€	 1877
+·ð€	 1860
+Ð	 1842
+Ð_	 1830
+·€_	 1746
+é	 1714
+æð	 1703
+ð€_	 1695
+·ð€_	 1694
+æÚ	 1631
+ü	 1610
+_·ð	 1579
+_·ð€	 1567
+ðŽ_	 1556
+æÚU	 1536
+Øæ	 1528
+Ùð	 1525
+Uè	 1515
+_·ð€_	 1488
+Ù_	 1411
+Ùð_	 1407
+à	 1390
+_ãñ	 1357
+ãñ	 1357
+Å	 1337
+Ì_	 1319
+_Õ	 1315
+×ð	 1300
+ç·	 1279
+Ö	 1270
+_Á	 1258
+_·€æ	 1209
+ç·€	 1203
+€è	 1195
+_Ù	 1187
+°	 1181
+§	 1166
+×ðŽ	 1163
+àæ	 1162
+ý	 1157
+¿	 1155
+_×ð	 1150
+×ðŽ_	 1140
+·€è	 1127
+€è_	 1092
+_×ðŽ	 1086
+_×ðŽ_	 1077
+ñU	 1075
+_ãU	 1071
+·€è_	 1065
+ãñU	 1062
+_ãñU	 1062
+æÙ	 1053
+¥æ	 1052
+Ìæ	 1038
+€Ú	 1035
+_ç·	 1009
+€ÚU	 972
+âð	 970
+_ç·€	 967
+_·€è	 959
+ÚUæ	 936
+ãUæ	 930
+_·€è_	 929
+·€Ú	 928
+Í	 926
+_¥æ	 904
+ÅU	 904
+Ç	 904
+©	 890
+ê	 887
+©U	 885
+·€ÚU	 866
+_©	 865
+_©U	 862
+_Ö	 854
+âð_	 850
+_Ú	 847
+_Ì	 837
+S	 834
+UÐ	 831
+_Î	 830
+UÐ_	 823
+_ß	 798
+Ùæ	 788
+â_	 783
+_ÚU	 773
+Uè_	 770
+ôŽ	 753
+æØ	 752
+Ï	 749
+Øæ_	 732
+×æ	 732
+ô_	 704
+_§	 704
+Áæ	 704
+_âð	 697
+Âý	 695
+ãUè	 693
+€æ_	 690
+ü_	 688
+æÚU_	 685
+,	 684
+_»	 682
+·€æ_	 679
+,_	 674
+_·€Ú	 670
+¹	 665
+ðU	 664
+ßæ	 648
+_Âý	 647
+UÌ	 644
+Ü_	 643
+_Ü	 641
+ç·€_	 639
+Ø_	 639
+Üæ	 633
+_âð_	 633
+æç	 623
+Uô	 621
+ôŽ_	 615
+_·€ÚU	 611
+Uæ_	 599
+ãU_	 595
+Üð	 594
+UÙ	 589
+ñUÐ	 580
+_ãñUÐ	 580
+ãñUÐ	 580
+_°	 576
+_Áæ	 573
+ñUÐ_	 572
+ãñUÐ_	 572
+æÜ	 569
+_Ø	 569
+_Ùð	 569
+ÂÚ	 561
+_ç·€_	 557
+	 556
+€ô	 552
+ææ	 550
+ÂÚU	 549
+çß	 544
+Õæ	 538
+_·€æ_	 535
+×_	 532
+çÜ	 525
+âæ	 523
+·€ô	 519
+æð_	 502
+æ¢	 501
+ž	 498
+_Ùð_	 495
+	 494
+_ÂÚ	 493
+Âæ	 493
+Ìæ_	 490
+_ÂÚU	 485
+çÙ	 484
+õ	 481
+È	 478
+æ	 469
+.	 459
+ÂÚU_	 458
+Öæ	 449
+Øð	 449
+_çß	 445
+§â	 444
+€ÚU_	 443
+Öè	 442
+_§â	 440
+_ÂÚU_	 439
+æðŽ	 437
+Ùæ_	 435
+	 434
+_¿	 433
+ÚUè	 431
+â¢	 431
+_·€ô	 430
+Îð	 427
+æÌ	 425
+Î_	 420
+Öè_	 419
+žU	 415
+	 412
+æ	 412
+§ü	 410
+ŽU	 405
+ÇU	 399
+»æ	 399
+·€ÚU_	 394
+Uã	 394
+æÙ_	 393
+çÌ	 393
+€ô_	 392
+·€ô_	 392
+çÎ	 389
+ÚUÌ	 385
+æÁ	 385
+Çž	 383
+æðŽ_	 382
+Ìè	 381
+Íæ	 379
+çÚ	 375
+°_	 374
+ãUô	 374
+ÚUã	 374
+æÐ	 373
+æÐ_	 372
+_·€ô_	 371
+_Õæ	 369
+æè	 364
+çÚU	 364
+ðU_	 362
+€æð	 358
+È€	 357
+Uæð	 354
+èŽ	 353
+â·	 352
+ß_	 350
+U·	 349
+€æÚ	 346
+Ìð	 346
+·€æð	 346
+æü	 345
+õÚ	 344
+õÚU	 342
+·€æÚ	 342
+_×æ	 341
+_Öè	 341
+_çÜ	 340
+ñU_	 337
+_ãñU_	 337
+ÿ	 337
+ãñU_	 337
+Ùè	 336
+ãUè_	 334
+¿æ	 334
+ñŽ	 334
+_Öè_	 332
+æ×	 327
+€æÚU	 327
+ÿæ	 326
+_Í	 325
+U·€	 323
+·€æÚU	 323
+UèŽ	 322
+ãUèŽ	 321
+_âæ	 320
+ÇžU	 319
+_¥õ	 319
+¥õ	 319
+õÚU_	 319
+_ÚUã	 318
+Úð	 317
+èŽ_	 316
+_â¢	 316
+æ·	 313
+Øô	 310
+_ãUæ	 309
+Øã	 309
+À	 308
+ØãU	 308
+_Øã	 308
+_ØãU	 307
+_·€æð	 304
+_¥õÚ	 304
+¥õÚ	 304
+_¥õÚU	 304
+_Öæ	 304
+¥õÚU	 304
+¥õÚU_	 303
+_çÙ	 303
+ãUèŽ_	 300
+UèŽ_	 300
+_S	 300
+Îæ	 300
+UÜ	 298
+ÚUè_	 296
+æÎ	 296
+æß	 294
+ÅU_	 294
+Øð_	 293
+Ùã	 292
+âè	 291
+_Ùã	 290
+æè_	 290
+ðà	 290
+Üð_	 289
+UãU	 288
+ÙãU	 288
+Uâ	 288
+_ÙãU	 286
+_à	 286
+_ÙãUè	 285
+_Âæ	 285
+ÙãUè	 285
+æ·€	 284
+_àæ	 284
+ÙãUèŽ	 283
+UÌ_	 282
+ãñŽ	 280
+_ãñŽ	 280
+ñŽU	 280
+â×	 279
+_çÎ	 278
+_ãñŽU	 278
+ãñŽU	 278
+»_	 277
+_Îð	 275
+ðàæ	 274
+àæ_	 273
+æñ	 272
+·€ã	 272
+€ã	 272
+Ìð_	 272
+_ãUô	 272
+æ_	 272
+-	 271
+€ãU	 271
+·€ãU	 271
+¢_	 271
+_·€ã	 270
+ãUæ_	 270
+_·€ãU	 269
+ÚUãU	 268
+ãé	 267
+æâ	 265
+°·	 263
+€Ø	 263
+€æð_	 262
+·€æð_	 262
+°·€	 262
+ÚðU	 258
+_°·	 258
+Ùè_	 258
+_°·€	 257
+ÀU	 256
+v	 253
+ÂÙ	 252
+_ÚUæ	 252
+Üè	 249
+ç×	 247
+çâ	 246
+_Å	 246
+ÚUÙ	 246
+×é	 245
+._	 245
+UÚ	 244
+éU	 243
Index: /main/tags/2.25/gsdl/perllib/textcat/italian.lm
===================================================================
--- /main/tags/2.25/gsdl/perllib/textcat/italian.lm	(revision 21064)
+++ /main/tags/2.25/gsdl/perllib/textcat/italian.lm	(revision 21064)
@@ -0,0 +1,400 @@
+_	 25028
+a	 7570
+e	 6477
+i	 5481
+o	 5104
+l	 3905
+n	 3866
+r	 3502
+t	 2934
+c	 2862
+s	 2862
+a_	 2504
+e_	 2404
+d	 2004
+i_	 1749
+o_	 1679
+u	 1650
+v	 1611
+p	 1561
+m	 1414
+_c	 1325
+,	 1192
+,_	 1192
+_s	 1190
+_d	 1094
+g	 1067
+an	 925
+er	 915
+_a	 914
+_p	 895
+la	 858
+_l	 830
+re	 799
+ar	 769
+h	 762
+no	 753
+co	 726
+va	 698
+_e	 657
+n_	 656
+on	 656
+ra	 653
+to	 651
+f	 638
+di	 638
+_i	 634
+ch	 634
+ll	 633
+l_	 624
+la_	 598
+ta	 593
+el	 576
+in	 567
+_m	 558
+en	 529
+b	 528
+ri	 525
+_co	 523
+_n	 523
+_di	 522
+li	 513
+av	 507
+al	 501
+le	 494
+ia	 492
+se	 484
+ol	 479
+_f	 477
+or	 477
+te	 469
+_e_	 467
+ve	 454
+at	 449
+de	 447
+.	 443
+ne	 429
+va_	 428
+ca	 426
+._	 422
+tt	 422
+re_	 415
+nt	 415
+io	 411
+_v	 407
+pe	 405
+z	 392
+to_	 391
+_ch	 389
+na	 384
+si	 384
+'	 383
+he	 382
+no_	 379
+ci	 374
+_la	 373
+ro	 371
+_g	 370
+st	 368
+cc	 366
+he_	 362
+di_	 362
+ma	 358
+ev	 354
+che	 354
+es	 352
+me	 352
+pa	 351
+_t	 349
+ti	 348
+_di_	 347
+ss	 345
+che_	 344
+a,_	 337
+a,	 337
+nd	 335
+o,	 333
+o,_	 333
+ell	 330
+gl	 323
+sa	 322
+il	 322
+gli	 321
+da	 318
+as	 318
+do	 314
+_che	 308
+_che_	 306
+eva	 306
+_la_	 300
+lla	 298
+le_	 293
+un	 291
+_pe	 290
+_de	 288
+q	 283
+qu	 283
+ava	 280
+po	 277
+on_	 275
+r_	 273
+li_	 273
+_b	 269
+_il	 268
+_il_	 268
+il_	 268
+lo	 267
+om	 263
+e,	 263
+e,_	 263
+ni	 258
+tr	 258
+so	 255
+ra_	 253
+os	 251
+_in	 249
+_u	 248
+per	 244
+are	 243
+et	 243
+_se	 240
+ano	 239
+si_	 238
+_ca	 238
+_qu	 238
+lla_	 238
+_q	 238
+_a_	 236
+ac	 236
+_r	 234
+ic	 233
+_no	 232
+ie	 227
+fa	 227
+hi	 226
+del	 225
+ua	 222
+_per	 218
+ce	 218
+_ma	 216
+sc	 216
+_del	 215
+mi	 212
+_un	 208
+chi	 206
+era	 205
+i,	 205
+i,_	 205
+su	 203
+and	 202
+vo	 202
+_fa	 201
+eva_	 200
+ano_	 199
+gli_	 197
+non	 196
+pi	 196
+vi	 195
+er_	 195
+_al	 194
+se_	 193
+_ne	 192
+_non	 191
+am	 190
+is	 187
+ava_	 187
+_non_	 186
+non_	 186
+in_	 185
+ent	 185
+_si	 184
+_pa	 184
+com	 183
+!	 182
+_le	 182
+_su	 181
+uo	 181
+el_	 180
+!_	 180
+l'	 178
+ue	 177
+te_	 177
+_com	 177
+are_	 176
+pr	 176
+_in_	 176
+van	 172
+mo	 172
+ta_	 171
+gn	 167
+ere	 166
+na_	 166
+tto	 163
+it	 161
+_per_	 161
+per_	 161
+é	 161
+all	 160
+ess	 159
+ut	 159
+col	 158
+acc	 157
+gi	 155
+lo_	 154
+oc	 154
+vano	 153
+io_	 153
+_av	 151
+ndo	 151
+é_	 151
+ato	 149
+ave	 148
+_st	 147
+me_	 147
+'a	 146
+ia_	 144
+con	 143
+mp	 143
+fi	 142
+ett	 142
+_si_	 141
+_pi	 140
+era_	 140
+ti_	 140
+ó	 140
+vano_	 140
+_gl	 139
+qua	 139
+ella	 139
+sta	 138
+ome	 137
+S	 137
+_gli	 137
+_S	 137
+ad	 136
+_ve	 134
+ant	 134
+ne_	 134
+ó_	 133
+sp	 133
+do_	 133
+_po	 132
+ro_	 132
+ov	 132
+_le_	 131
+ella_	 130
+sse	 129
+_con	 128
+ir	 128
+_vi	 128
+ig	 127
+_gli_	 127
+_ave	 127
+vev	 127
+un_	 126
+ot	 126
+veva	 125
+dell	 125
+que	 125
+a.	 125
+_o	 125
+a._	 124
+tu	 124
+cia	 123
+za	 123
+_que	 123
+_da	 121
+par	 121
+_pr	 120
+cch	 120
+_dell	 120
+eg	 119
+_sa	 119
+o._	 119
+o.	 119
+_col	 118
+lt	 118
+_un_	 118
+rt	 118
+ur	 117
+_vo	 117
+_me	 117
+ome_	 117
+L	 116
+ap	 116
+_L	 116
+zi	 116
+nto	 116
+og	 115
+_an	 115
+_so	 115
+em	 114
+ag	 114
+be	 111
+ni_	 111
+im	 110
+cchi	 110
+ver	 110
+lle	 109
+nz	 109
+cci	 109
+_ri	 109
+nc	 108
+_er	 108
+come_	 107
+come	 107
+aveva	 107
+ui	 107
+avev	 107
+tto_	 107
+_come	 106
+ed	 106
+P	 105
+man	 105
+_P	 105
+rs	 105
+occ	 104
+ndo_	 103
+ato_	 103
+_qua	 103
+_era	 103
+ari	 102
+ba	 100
+_mo	 100
+nel	 100
+id	 99
+men	 98
+_fi	 98
+_all	 98
+rr	 97
+_do	 97
+_avev	 97
+att	 97
+l'a	 96
+ei	 96
+zz	 96
+;	 96
+vol	 95
+pp	 95
+tra	 95
+;_	 95
+ere_	 94
+lle_	 94
+nda	 94
+utt	 94
+est	 93
+_nel	 93
+ul	 92
+ola	 92
+iv	 92
+ando	 90
+ale	 90
+lu	 90
+rn	 90
+e.	 89
+e._	 89
+ll'	 89
+tta	 88
+nte	 87
+_l'	 87
+uel	 87
Index: /main/tags/2.25/gsdl/perllib/textcat/japanese-euc_jp.lm
===================================================================
--- /main/tags/2.25/gsdl/perllib/textcat/japanese-euc_jp.lm	(revision 21064)
+++ /main/tags/2.25/gsdl/perllib/textcat/japanese-euc_jp.lm	(revision 21064)
@@ -0,0 +1,400 @@
+€	 78988
+¥	 57258
+_	 34456
+¡	 22280
+£	 18223
+Œ	 11290
+¹	 11237
+Î	 10621
+¬	 9502
+ë	 8859
+¿	 8812
+€Î	 8266
+È	 8180
+Í	 7520
+Ë	 7325
+Ã	 6982
+Ê	 6930
+Ç	 6929
+µ	 6896
+Æ	 6865
+€ë	 6858
+ì	 6261
+¡Œ	 6067
+Œ¥	 5926
+¡Œ¥	 5888
+Ï	 5878
+ž	 5806
+Ä	 5562
+Á	 5426
+œ	 5314
+€Ë	 5228
+»	 5011
+·	 4836
+€€	 4775
+É	 4385
+£_	 4323
+€Ï	 4310
+¡£	 4305
+¡£_	 4294
+Â	 4253
+¥¹	 4090
+¹€	 4075
+ê	 4032
+§	 4029
+Ì	 3975
+ó	 3947
+Ÿ	 3923
+°	 3853
+Ž	 3845
+ò	 3759
+³	 3583
+¡€	 3485
+€ì	 3475
+®	 3367
+À	 3366
+ì€	 3366
+€ò	 3314
+ë¡	 3313
+Å	 3282
+¯	 3273
+€ì€	 3255
+Ó	 3207
+Ã¥	 3188
+¥Ã	 3182
+¬¥	 3175
+¥Ã¥	 3170
+¬§	 3131
+á	 3058
+€ë¡	 3035
+¥¬	 3024
+¬¥¬	 3000
+ë¡£	 2952
+ë¡£_	 2948
+€ë¡£	 2947
+€ë¡£_	 2943
+¢	 2905
+Ô	 2893
+€¹	 2865
+€È	 2848
+²	 2819
+È€	 2791
+¿®	 2776
+¥¬¥	 2749
+¬¥¬¥	 2730
+¥¬¥¬	 2729
+¬¥¬¥¬	 2729
+ª	 2697
+è	 2689
+Ð	 2545
+€Æ	 2543
+¥È	 2525
+€¹€	 2473
+¥¬¥¬¥	 2459
+€Ç	 2399
+.	 2395
+Ñ	 2381
+,	 2380
+µ€	 2357
+¥ó	 2346
+Ö	 2340
+±	 2328
+¥£	 2326
+¡¥	 2316
+×	 2314
+Õ	 2293
+€¹€ë	 2283
+¹€ë	 2283
+€µ	 2253
+._	 2251
+€Ê	 2227
+€µ€	 2222
+¥ž	 2200
+_€	 2189
+Ç€	 2172
+¥»	 2145
+Ó¥	 2137
+€¿	 2112
+€µ€ì	 2110
+µ€ì	 2110
+«	 2100
+µ¡	 2061
+¥¯	 2027
+ë€	 2017
+€·	 2011
+¥Ó	 2007
+¥Ó¥	 2002
+Ë€	 1995
+µ€ì€	 1983
+€µ€ì€	 1983
+é	 1947
+ó¥	 1913
+è€	 1861
+€¥	 1847
+¥ó¥	 1834
+€¬	 1834
+¥ì	 1826
+­	 1795
+€€€	 1791
+ç	 1782
+Þ	 1782
+€Ë€	 1763
+€È€	 1760
+¥á	 1716
+¥ë	 1713
+š	 1709
+á¥	 1696
+Ê€	 1691
+·€	 1688
+_¥	 1686
+¯¥	 1679
+¥¯¥	 1669
+¥á¥	 1668
+Ý	 1666
+€ë€	 1659
+€Ç€	 1655
+¢€	 1638
+â	 1637
+¿€	 1612
+€·€	 1598
+Œ¥ž	 1584
+¡Œ¥ž	 1584
+€Ê€	 1570
+¥µ	 1568
+€è	 1565
+€è€	 1562
+ÍÑ	 1554
+Ø	 1544
+Æ€	 1541
+Æ¥	 1538
+¥¿	 1526
+³€	 1525
+ì€ë	 1523
+€ì€ë	 1523
+ð	 1517
+€¢	 1510
+€¢€	 1509
+-	 1490
+»¡	 1476
+¥ê	 1465
+¥€	 1465
+¶	 1464
+¥á¥Ã	 1454
+á¥Ã	 1454
+¥á¥Ã¥	 1453
+¥Ã¥»¡	 1453
+¥»¡Œ¥	 1453
+á¥Ã¥»	 1453
+Ã¥»¡	 1453
+¥»¡Œ	 1453
+¥Ã¥»	 1453
+»¡Œ¥	 1453
+¥»¡	 1453
+á¥Ã¥	 1453
+Ã¥»	 1453
+Ã¥»¡Œ	 1453
+»¡Œ	 1453
+»¡Œ¥ž	 1452
+º	 1450
+ì¥	 1445
+õ	 1441
+¥·	 1420
+à	 1419
+ý	 1418
+¥µ¡	 1415
+µ¡Œ¥	 1413
+¥µ¡Œ	 1413
+¥µ¡Œ¥	 1413
+µ¡Œ	 1413
+·¥	 1413
+¥Æ	 1411
+Ó¥¹	 1406
+Œ¥Ó¥	 1406
+¡Œ¥Ó¥	 1406
+¥Ó¥¹	 1406
+¡Œ¥Ó	 1406
+Œ¥Ó	 1406
+¥ì¥	 1403
+µ¡Œ¥Ó	 1403
+Œ¥Ó¥¹	 1403
+¥Æ¥	 1396
+¥·¥	 1392
+¥€¥	 1383
+æ	 1378
+œ€	 1372
+_£	 1368
+Î¥	 1358
+T	 1354
+Ï¡	 1341
+ª€	 1338
+€é	 1337
+€³	 1325
+Š	 1323
+Î€	 1314
+€Î¥	 1312
+¢€ë	 1311
+€¢€ë	 1311
+Ô€	 1308
+)	 1302
+_.	 1297
+Ü	 1294
+£Í	 1294
+€³€	 1292
+ŒÔ	 1289
+¥¹€	 1284
+€Æ€	 1284
+¿¥	 1273
+¹¥	 1260
+_._	 1244
+÷	 1244
+þ	 1238
+¥¹¥	 1211
+¥Õ	 1190
+ë¥	 1182
+_¡	 1182
+€¿€	 1152
+È¥	 1151
+Í×	 1145
+µ€ì€ë	 1130
+Çœ	 1129
+Õ¥	 1126
+Û	 1120
+¥Õ¥	 1113
+€Ï¡	 1105
+¥Ç	 1103
+ß	 1101
+é€	 1084
+¥¢	 1080
+ž€	 1062
+ï	 1060
+Á÷	 1051
+£Á	 1050
+¡¥£	 1043
+ÄÌ	 1033
+§¬	 1033
+§¬§	 1033
+¬§¬	 1032
+¬§¬§	 1032
+Ï¡€	 1030
+€Ï¡€	 1030
+Ç€¢	 1022
+€Ç€¢	 1021
+Ç€¢€	 1021
+€Ç€¢€	 1020
+Ç¥	 1012
+í	 1006
+Äê	 997
+¢¥	 995
+€é€	 991
+Í£	 988
+¥¢¥	 985
+£¥	 984
+£Í£	 983
+¡Ê	 981
+€ª	 976
+¥£¥	 974
+€Î€	 971
+€ª€	 971
+š€	 962
+¥¿¥	 955
+ê¥	 955
+ê€	 954
+¥È¥	 953
+¥Ç¥	 951
+¥É	 942
+®€	 929
+Íý	 920
+á€	 918
+ä	 909
+€«	 904
+ø	 904
+ŒÔ€	 903
+€¢€ë¡	 900
+¢€ë¡	 900
+¥_	 894
+«€	 893
+-_	 892
+Ï,	 887
+¥È€	 886
+€Ï,	 886
+¡¥_	 884
+¥×	 881
+€ê	 881
+(	 878
+C	 877
+Ç€¢€ë	 877
+I	 877
+€â	 875
+¢€ë¡£	 875
+i	 872
+¥ê¥	 865
+¡Ë	 860
+Ö€	 857
+â€	 856
+¥à	 855
+§£	 855
+­€	 846
+ÇÛ	 841
+Þ€	 834
+¬§£	 834
+e	 825
+€«€	 825
+£Ð	 819
+€·€Æ	 818
+·€Æ	 818
+£Ô	 808
+Œš	 802
+¥Ç¥£	 796
+Ç¥£	 796
+_¬	 792
+a	 776
+¥Ã¥È	 771
+Ã¥È	 771
+€¹€ë€	 770
+¹€ë€	 770
+ž¥	 767
+Ñ€	 748
+€ì€ë¡	 743
+ì€ë¡	 743
+¥Ç¥£¥	 741
+Ç¥£¥	 741
+§_	 738
+¥ž¥	 732
+N	 729
+¹ð	 728
+¥ë¥	 728
+Á€	 727
+Œõ	 724
+ì€ë¡£	 722
+¥ž€	 718
+Ë€è	 716
+Ë€è€	 716
+€Ë€è€	 715
+¡Œ¥ž€	 715
+Œ¥ž€	 715
+€Ë€è	 715
+×¥	 715
+¥×¥	 711
+§¬§¬§	 710
+§¬§¬	 710
+¬§¬§¬	 710
+Ä€	 705
+Ò	 702
+©	 701
+_¬§	 699
+³€È	 696
+¬§_	 694
+»¥	 694
+¹€ë¡	 692
+€¹€ë¡	 692
+€³€È	 692
+¥»¥	 686
+ÍÑ€	 685
+€Ê€€	 685
+Ê€€	 685
+«¹	 684
+Æ€€	 684
+n	 682
+ó€	 682
+£Ä	 681
+Ž«	 681
Index: /main/tags/2.25/gsdl/perllib/textcat/korean.lm
===================================================================
--- /main/tags/2.25/gsdl/perllib/textcat/korean.lm	(revision 21064)
+++ /main/tags/2.25/gsdl/perllib/textcat/korean.lm	(revision 21064)
@@ -0,0 +1,400 @@
+_	 11636
+À	 2659
+°	 1629
+Ç	 1578
+ž	 1458
+¿	 1397
+Ž	 1299
+µ	 1118
+Á	 1005
+±	 928
+»	 849
+Œ	 840
+_À	 809
+¹	 808
+º	 780
+¡	 773
+Ã	 764
+³	 674
+Ÿ	 640
+Ì	 591
+Î	 580
+ÀÌ	 538
+œ	 526
+Ï	 519
+Â	 518
+_°	 518
+Ù	 506
+·	 483
+È	 464
+ö	 463
+­	 454
+ŽÙ	 451
+ø	 404
+Æ	 395
+ë	 384
+_¿	 382
+í	 377
+.	 374
+Å	 373
+ç	 358
+._	 347
+_Ç	 344
+ŽÂ	 338
+¡_	 333
+Â_	 329
+¿¡	 327
+_Á	 319
+ŽÂ_	 317
+ŽÙ.	 313
+Ù.	 313
+â	 308
+¶	 308
+ŽÙ._	 301
+Ù._	 301
+»_	 299
+_¹	 291
+î	 288
+®	 282
+À»	 279
+Ö	 278
+Š	 274
+À»_	 271
+Î_	 269
+,	 266
+Ñ	 266
+°í	 261
+Áö	 258
+,_	 258
+°¡	 250
+ß	 248
+_Œ	 246
+Ä	 245
+ÀÇ	 244
+Ì_	 243
+_ž	 243
+_µ	 242
+ü	 238
+é	 235
+Œ­	 234
+ÀÌ_	 234
+ÇÏ	 234
+_±	 233
+Žë	 228
+·Î	 227
+ÇÑ	 222
+œÃ	 222
+_³	 215
+±â	 212
+_Ã	 210
+í_	 208
+_Ž	 206
+Š_	 206
+Ç_	 205
+_Ÿ	 205
+º_	 204
+÷	 198
+Àº	 198
+°í_	 194
+·Î_	 193
+ó	 193
+¿¡_	 193
+žŠ_	 192
+žŠ	 192
+_ÀÌ	 190
+­_	 189
+Àº_	 189
+_œ	 189
+µµ	 188
+ÀÏ	 188
+ÀÇ_	 188
+_º	 186
+Í	 177
+Ú	 175
+ú	 171
+»ç	 161
+Ô	 154
+_ÀÏ	 153
+Ø	 152
+¿ø	 151
+±ž	 150
+µ¿	 147
+Ò	 147
+žž	 145
+Œö	 143
+€	 142
+ºÎ	 142
+_»	 141
+ÀÖ	 140
+æ	 139
+Ð	 138
+ù	 138
+ª	 137
+µé	 136
+è	 134
+Àž	 134
+_ÀÖ	 133
+²	 132
+Ñ_	 127
+ÀÎ	 125
+°¡_	 123
+ÀÚ	 122
+ÇÑ_	 121
+Àü	 121
+ŸÆ	 118
+ý	 117
+å	 116
+Ï_	 115
+Ÿî	 115
+µ_	 115
+¢	 114
+ÖŽ	 113
+°ú	 112
+ž·	 111
+¯	 109
+ÇØ	 109
+§	 108
+à	 108
+_È	 108
+±¹	 107
+Œ­_	 107
+×	 107
+£	 106
+ÀÖŽ	 105
+Èž	 103
+ž®	 101
+ö_	 101
+û	 100
+_ÀÖŽ	 100
+Ãµ	 100
+ž·Î	 100
+"	 98
+Àž·Î	 97
+ÁÖ	 97
+Àž·	 97
+Àå	 95
+_Žë	 94
+¡Œ	 94
+³ª	 94
+_œÃ	 94
+¥	 94
+µî	 94
+Á€	 92
+°ø	 92
+_Å	 91
+á	 91
+Ï°	 90
+ÇÐ	 90
+ž·Î_	 90
+Ê	 89
+©	 89
+Í_	 89
+ž_	 89
+Àž·Î_	 89
+éÀ	 89
+Þ	 88
+¡Œ­	 88
+¿¡Œ	 88
+¿¡Œ­	 88
+ê	 87
+µµ_	 87
+±³	 85
+_Æ	 85
+î_	 84
+°æ	 84
+µéÀ	 84
+ží	 84
+ëÇ	 83
+¿ù	 83
+_Áö	 82
+ÇÏ°	 82
+¿À	 81
+¶ó	 80
+¿¡Œ­_	 79
+¡Œ­_	 79
+ÀÏ_	 78
+Ý	 78
+ÁŠ	 78
+ç_	 78
+øÀ	 78
+'	 77
+Çß	 77
+ì	 77
+Ü	 77
+Áß	 77
+ú_	 76
+Áö_	 76
+Ó	 76
+â_	 75
+(	 74
+)	 74
+»ó	 74
+°ü	 74
+»ý	 73
+_¿ù	 72
+_°¡	 72
+_Œö	 72
+-	 72
+¿©	 72
+ÖŽÙ	 72
+ºž	 71
+ÀÖŽÙ	 71
+»ê	 70
+°³	 70
+œº	 70
+Œ±	 69
+¿ë	 69
+°ú_	 69
+_ÀÖŽÙ	 69
+_µî	 69
+ø_	 69
+ßŽ	 69
+°Í	 68
+³»	 68
+_¡	 68
+_ÇÑ	 68
+ù_	 67
+ÃŒ	 67
+ž¿	 66
+_ÀÏ_	 66
+ÇßŽ	 66
+°Ô	 65
+ñ	 65
+_¶	 65
+_°Í	 65
+ÇßŽÙ	 64
+ßŽÙ	 64
+_ÇÏ	 63
+¹Î	 62
+«	 62
+ÏŽ	 62
+ŒÒ	 62
+¿ù_	 62
+Á¶	 61
+³â	 61
+Ï°í	 61
+ÌŽ	 60
+ŸÈ	 60
+ÇÏ°í	 60
+õ	 59
+_¿ù_	 59
+_Œ­	 59
+Åë	 59
+ÆÄ	 58
+®_	 58
+_žž	 58
+Ø_	 58
+Žç	 57
+ßŽÙ.	 57
+¬	 57
+Õ	 57
+ÇßŽÙ.	 57
+¹°	 57
+Ÿ÷	 57
+ÖŽÙ.	 56
+ß_	 56
+ÀÖŽÙ.	 56
+¿Í	 56
+ßŽÙ._	 56
+Áø	 56
+Àç	 55
+ž°	 55
+ÍÀ	 55
+Æ®	 55
+¹é	 55
+ÀÌŽ	 55
+ÖŽÙ._	 54
+_¹é	 54
+¿Í_	 53
+Àû	 53
+ð	 53
+¹®	 53
+_ÁÖ	 53
+ŽÜ	 53
+Œº	 53
+ÇØ_	 53
+°Ç	 53
+íÀ	 52
+_Àü	 52
+Ô_	 52
+¿¬	 52
+_°æ	 51
+°ÍÀ	 51
+°£	 51
+¿ì	 51
+È­	 51
+ä	 50
+_ŸÆ	 50
+ŽëÇ	 50
+Ä¡	 50
+Ï°í_	 49
+ÇÏ°í_	 49
+_ÀÎ	 49
+Û	 49
+É	 49
+_"	 48
+öµ	 48
+À§	 48
+ÀÌŽÙ	 48
+ÀÔ	 48
+_°ÍÀ	 48
+ÌŽÙ	 48
+¡­	 47
+ÌŽÙ.	 47
+_°ø	 47
+ÀÌŽÙ.	 47
+°Ô_	 47
+_»ç	 47
+žç	 47
+œÅ	 47
+Ã_	 46
+ÅÍ	 46
+é_	 46
+Ò_	 46
+ï	 46
+ÇÏŽ	 46
+_°³	 45
+_ŽÙ	 45
+_ÀÚ	 45
+ž¶	 45
+°è	 45
+Çà	 45
+ÌŽÙ._	 45
+÷À	 44
+îÁ	 44
+ÈÄ	 44
+±â_	 43
+(_	 43
+žé	 43
+­¿	 43
+ü_	 43
+ºñ	 42
+­Ž	 42
+ë_	 42
+ÀÎ_	 42
+_ÀÌ_	 42
+µî_	 42
+°­	 42
+ÎÃ	 41
+µÇ	 41
+¿øÀ	 41
+¿µ	 41
+Àœ	 40
+ÎÃµ	 40
+±×	 40
+Ë	 40
+¿¹	 40
+_¿À	 40
+øÇ	 40
+ž»	 40
+_ÇÐ	 40
+¡­_	 39
+_³â	 39
+³²	 39
+ÇÒ	 39
+¿_	 39
+_³ª	 39
+³­	 38
+žíÀ	 38
+âÀ	 38
+ª_	 38
Index: /main/tags/2.25/gsdl/perllib/textcat/norwegian.lm
===================================================================
--- /main/tags/2.25/gsdl/perllib/textcat/norwegian.lm	(revision 21064)
+++ /main/tags/2.25/gsdl/perllib/textcat/norwegian.lm	(revision 21064)
@@ -0,0 +1,400 @@
+_	 22970
+e	 6833
+n	 4206
+r	 3516
+t	 3112
+a	 2587
+s	 2440
+i	 2112
+l	 1901
+o	 1900
+n_	 1875
+r_	 1761
+k	 1713
+g	 1630
+en	 1615
+m	 1508
+e_	 1450
+d	 1444
+er	 1436
+h	 1306
+t_	 1300
+_h	 1180
+_s	 1148
+er_	 1105
+v	 982
+en_	 976
+an	 919
+.	 901
+._	 791
+_.	 781
+et	 770
+g_	 762
+_._	 726
+å	 725
+u	 719
+f	 709
+p	 702
+ha	 682
+_ha	 672
+de	 657
+te	 651
+_e	 621
+et_	 614
+re	 581
+ne	 565
+_o	 554
+an_	 544
+ke	 534
+_,	 522
+,_	 522
+,	 522
+_,_	 522
+_f	 519
+_m	 515
+or	 503
+_d	 483
+_i	 480
+å_	 479
+se	 476
+m_	 469
+nn	 454
+b	 449
+me	 441
+ø	 434
+_a	 413
+st	 404
+_t	 398
+og	 380
+_v	 377
+_og	 366
+ar	 364
+el	 364
+le	 361
+i_	 356
+om	 353
+og_	 351
+_og_	 351
+li	 350
+_k	 346
+_de	 339
+ge	 339
+han	 337
+y	 333
+_han	 332
+ve	 330
+kk	 323
+in	 311
+_b	 307
+fo	 301
+j	 301
+il	 298
+_H	 291
+H	 291
+han_	 288
+_han_	 288
+for	 287
+ik	 281
+l_	 278
+kke	 277
+tt	 276
+ti	 270
+ne_	 270
+d_	 269
+ed	 269
+om_	 268
+nne	 266
+_me	 264
+ng	 257
+_er	 257
+_fo	 256
+eg	 256
+_se	 256
+_g	 256
+un	 255
+ig	 255
+sk	 253
+_er_	 252
+_p	 252
+_for	 250
+ke_	 249
+_n	 238
+_l	 233
+al	 232
+ør	 222
+s_	 221
+ar_	 215
+at	 214
+_en	 211
+he	 211
+pe	 209
+_i_	 208
+am	 200
+es	 200
+si	 200
+enn	 197
+det	 195
+or_	 193
+vi	 190
+ns	 189
+ikk	 188
+det_	 185
+so	 185
+un_	 183
+il_	 181
+nd	 181
+te_	 181
+"_	 180
+"	 180
+_"_	 180
+_"	 180
+em	 179
+_ti	 176
+kke_	 176
+lig	 174
+ten	 174
+Ha	 173
+_Ha	 173
+re_	 172
+ikke	 168
+je	 165
+Han	 165
+ter	 165
+_Han	 165
+eg_	 164
+på	 164
+_på	 163
+_si	 163
+_å	 163
+_Han_	 162
+Han_	 162
+på_	 162
+_på_	 161
+til	 160
+som	 160
+_so	 159
+den	 159
+_det	 157
+ed_	 155
+ll	 155
+_ik	 155
+rt	 155
+som_	 153
+ra	 152
+a_	 152
+har	 152
+nt	 152
+de_	 152
+tr	 151
+v_	 151
+_har	 151
+ka	 151
+ig_	 150
+_som	 150
+for_	 150
+_som_	 150
+_en_	 149
+hu	 149
+_ikk	 148
+_ham	 148
+ham	 148
+ste	 148
+_det_	 148
+_ikke	 148
+enne	 148
+ikke_	 148
+har_	 147
+nge	 147
+D	 147
+_har_	 147
+_D	 147
+am_	 147
+ere	 147
+ham_	 146
+_ham_	 146
+it	 145
+_he	 144
+_til	 144
+av	 143
+va	 140
+men	 140
+år	 140
+_ve	 140
+_hu	 139
+ta	 139
+pen	 137
+sp	 137
+_st	 135
+tte	 135
+la	 135
+_E	 133
+E	 133
+den_	 130
+is	 130
+til_	 128
+_r	 128
+tt_	 128
+år_	 127
+k_	 124
+_å_	 124
+ri	 124
+_til_	 124
+at_	 123
+ene	 123
+seg	 123
+_av	 123
+med	 122
+_vi	 122
+_seg	 122
+seg_	 121
+_seg_	 121
+_for_	 120
+nne_	 120
+ut	 120
+_u	 119
+mm	 119
+mme	 119
+De	 118
+_De	 118
+_at	 118
+_hun	 117
+hun	 117
+ko	 117
+be	 116
+_at_	 115
+ter_	 115
+pen_	 114
+ker	 113
+hun_	 113
+_hun_	 113
+on	 111
+lig_	 111
+..	 110
+hen	 107
+_med	 107
+rs	 106
+ser	 106
+med_	 105
+_men	 104
+_hen	 104
+_sk	 104
+_med_	 104
+ak	 103
+ans	 103
+ker_	 102
+av_	 101
+_ka	 101
+no	 100
+ver	 100
+ler	 99
+J	 99
+spe	 99
+ten_	 99
+_J	 99
+ene_	 98
+ld	 98
+hv	 98
+_av_	 98
+ger	 97
+ni	 96
+gen	 96
+ie	 95
+ser_	 94
+_et	 94
+spen	 94
+_hv	 94
+men_	 93
+Espe	 92
+Es	 92
+_Esp	 92
+_Es	 92
+_Espe	 92
+Esp	 92
+_al	 92
+Espen	 92
+lle	 89
+rem	 89
+id	 89
+fø	 89
+ei	 88
+inn	 88
+rd	 88
+enne_	 88
+_henn	 87
+henne	 87
+henn	 87
+kt	 86
+spen_	 86
+_om	 86
+ler_	 86
+da	 86
+ett	 86
+itt	 86
+bl	 85
+to	 85
+_Je	 84
+ger_	 84
+Je	 84
+æ	 84
+ma	 83
+ing	 83
+ær	 83
+ns_	 83
+eli	 82
+ang	 82
+_be	 82
+så	 82
+_den	 82
+pp	 81
+rk	 81
+dr	 81
+oe	 81
+ss	 81
+_fø	 80
+ek	 80
+le_	 79
+_no	 79
+kj	 78
+elig	 78
+nes	 78
+nn_	 77
+nk	 77
+fr	 77
+sl	 77
+my	 77
+kan	 77
+så_	 76
+as	 76
+_om_	 76
+_kan	 75
+_ko	 75
+_bl	 73
+Hu	 73
+nen	 73
+_Hu	 73
+eng	 73
+gj	 73
+rt_	 72
+ge_	 72
+ba	 72
+lv	 71
+rer	 71
+nde	 71
+ls	 70
+lo	 70
+ga	 70
+_noe	 70
+ro	 70
+_den_	 70
+_ut	 70
+noe	 70
+Hun	 69
+Hun_	 69
+_in	 69
+_Hun	 69
+_Hun_	 69
+ren	 68
+øre	 68
+ør_	 68
+sen	 68
+sa	 67
Index: /main/tags/2.25/gsdl/perllib/textcat/polish.lm
===================================================================
--- /main/tags/2.25/gsdl/perllib/textcat/polish.lm	(revision 21064)
+++ /main/tags/2.25/gsdl/perllib/textcat/polish.lm	(revision 21064)
@@ -0,0 +1,400 @@
+_	 31480
+a	 7945
+i	 7766
+e	 7462
+o	 6838
+z	 5104
+n	 5077
+r	 4178
+w	 4139
+s	 3596
+c	 3580
+y	 3569
+t	 3381
+d	 3027
+k	 2819
+p	 2639
+m	 2494
+ie	 2484
+u	 2016
+l	 1947
+j	 1932
+ni	 1930
+e_	 1746
+_p	 1712
+³	 1649
+a_	 1496
+o_	 1431
+,	 1368
+,_	 1366
+b	 1296
+_w	 1257
+g	 1249
+i_	 1140
+.	 1118
+_s	 1045
+ze	 1041
+._	 1035
+_n	 997
+nie	 958
+cz	 956
+rz	 952
+h	 950
+_z	 933
+ê	 918
+ow	 911
+ie_	 902
+y_	 899
+na	 885
+ch	 871
+po	 864
+pr	 863
+wi	 851
+st	 847
+¿	 835
+±	 832
+an	 814
+ó	 800
+ra	 778
+zy	 766
+ia	 726
+za	 718
+_t	 699
+wa	 692
+ro	 692
+_d	 683
+_pr	 675
+¶	 661
+w_	 658
+sz	 652
+_po	 649
+_o	 628
+m_	 613
+li	 613
+dz	 611
+ki	 611
+en	 609
+mi	 593
+ta	 571
+ci	 564
+ej	 562
+nie_	 558
+_m	 553
+_k	 549
+ar	 543
+go	 541
+_i	 540
+em	 532
+od	 525
+yc	 520
+a³	 511
+rze	 508
+do	 504
+eg	 503
+ko	 502
+ac	 482
+to	 478
+_na	 467
+_ni	 467
+h_	 466
+ch_	 466
+æ	 465
+iê	 461
+_b	 458
+on	 458
+u_	 458
+zi	 454
+ka	 450
+er	 448
+sk	 447
+si	 447
+wy	 444
+te	 437
+ak	 434
+ê_	 431
+_j	 429
+je	 429
+z_	 427
+ny	 422
+aw	 422
+ne	 420
+ów	 418
+_w_	 415
+_c	 414
+ego	 412
+prz	 412
+_r	 410
+al	 407
+³a	 405
+"	 405
+re	 405
+es	 401
+_nie	 396
+dzi	 394
+ty	 389
+j_	 380
+ic	 380
+_prz	 379
+ad	 367
+ej_	 364
+le	 359
+æ_	 358
+ed	 354
+ych	 346
+_za	 346
+_do	 344
+zn	 344
+go_	 344
+ani	 343
+_i_	 342
+no	 339
+or	 337
+³o	 336
+tr	 334
+P	 330
+os	 329
+am	 329
+da	 328
+ec	 327
+ol	 325
+±_	 325
+by	 322
+ego_	 321
+at	 321
+¿e	 319
+ym	 317
+wie	 314
+³_	 312
+-	 310
+na_	 309
+_si	 303
+W	 301
+as	 301
+wo	 300
+pa	 299
+siê	 295
+nia	 293
+owa	 292
+o¶	 286
+_P	 283
+el	 282
+_siê	 279
+ja	 278
+rzy	 276
+prze	 276
+_wy	 275
+iê_	 269
+in	 267
+_-	 267
+de	 267
+kie	 267
+dn	 264
+ob	 262
+_u	 261
+ych_	 260
+-_	 258
+ez	 257
+_-_	 256
+¶c	 255
+ws	 255
+¶ci	 254
+em_	 253
+_siê_	 253
+siê_	 253
+_nie_	 253
+kt	 252
+ski	 252
+we	 251
+_g	 251
+_W	 250
+t_	 249
+_prze	 249
+_je	 248
+aj	 247
+_a	 247
+¿e_	 246
+_¿	 244
+ia_	 243
+eni	 241
+om	 240
+la	 240
+k_	 235
+mo	 235
+f	 234
+pi	 232
+is	 231
+cze	 231
+_z_	 230
+ñ	 228
+nt	 227
+ce	 224
+sta	 221
+ry	 220
+ma	 219
+cj	 219
+zie	 218
+ek	 216
+oc	 213
+dy	 212
+owi	 208
+sp	 208
+K	 208
+tó	 205
+_"	 204
+ud	 203
+S	 202
+ier	 202
+pra	 202
+czn	 201
+ys	 200
+nia_	 199
+j±	 198
+_¿e	 196
+oz	 194
+N	 192
+zo	 191
+dzie	 190
+ku	 190
+ów_	 189
+czy	 189
+_mi	 188
+_¿e_	 187
+mie	 186
+do_	 186
+iej	 185
+ym_	 185
+_do_	 184
+cy	 184
+_pa	 183
+y³	 182
+_na_	 181
+zy_	 181
+ew	 180
+_l	 180
+_cz	 178
+_by	 178
+ru	 177
+to_	 175
+±c	 175
+_wi	 175
+ln	 174
+_K	 171
+ok	 170
+ot	 170
+raw	 169
+nych	 168
+nyc	 168
+az	 168
+ik	 167
+bi	 167
+i,_	 166
+i,	 166
+_te	 165
+tu	 163
+wan	 163
+et	 162
+J	 162
+ór	 161
+cie	 160
+_od	 160
+ba	 160
+oj	 159
+o¶c	 158
+i³	 158
+_ro	 158
+og	 158
+mu	 158
+A	 158
+o¶ci	 158
+d_	 157
+tw	 156
+io	 155
+gr	 155
+_J	 155
+_N	 155
+_to	 155
+us	 155
+¿_	 154
+aæ	 154
+ach	 154
+yd	 153
+_kt	 153
+_ko	 152
+_st	 152
+pow	 151
+yt	 150
+kr	 149
+_S	 149
+a³_	 149
+ak_	 149
+li_	 148
+T	 148
+ur	 148
+sa	 148
+op	 147
+yw	 147
+ent	 147
+bo	 146
+_sp	 145
+O	 145
+a,_	 144
+a,	 144
+iem	 144
+któ	 143
+praw	 143
+wn	 142
+tór	 142
+i±	 141
+³y	 141
+zu	 141
+dni	 140
+im	 139
+icz	 139
+ró	 139
+³e	 138
+któr	 137
+my	 137
+est	 136
+awi	 135
+przy	 134
+nych_	 134
+e,_	 132
+e,	 132
+ki_	 132
+pro	 131
+_któ	 131
+_któr	 131
+_przy	 130
+_ja	 129
+szy	 127
+ia³	 127
+Po	 127
+ania	 127
+M	 126
+ze_	 125
+ne_	 125
+ñs	 124
+_ty	 124
+sze	 124
+a¿	 124
+nn	 124
+pod	 124
+aæ_	 122
+B	 122
+za_	 122
+cza	 122
+³o_	 122
+Z	 122
+_to_	 121
+iu	 120
+zc	 119
+esz	 119
+skie	 118
+i.	 118
+_ka	 117
+so	 117
+trz	 117
+o¿	 116
+ieg	 116
+nik	 116
+ga	 116
Index: /main/tags/2.25/gsdl/perllib/textcat/portuguese.lm
===================================================================
--- /main/tags/2.25/gsdl/perllib/textcat/portuguese.lm	(revision 21064)
+++ /main/tags/2.25/gsdl/perllib/textcat/portuguese.lm	(revision 21064)
@@ -0,0 +1,400 @@
+_	 35328
+a	 10423
+e	 10132
+o	 8919
+s	 6795
+r	 6033
+i	 5443
+n	 4588
+d	 4531
+t	 4217
+m	 3476
+u	 3404
+o_	 3240
+a_	 3029
+e_	 2879
+c	 2756
+s_	 2461
+_d	 2379
+l	 2307
+p	 2242
+_a	 1753
+de	 1751
+,	 1660
+,_	 1658
+_e	 1454
+es	 1447
+os	 1412
+ra	 1343
+_p	 1328
+nt	 1302
+_de	 1248
+do	 1215
+en	 1176
+re	 1150
+as	 1123
+v	 1115
+m_	 1113
+de_	 1096
+er	 1082
+g	 1053
+_c	 1047
+da	 1008
+co	 986
+os_	 975
+te	 974
+ar	 950
+or	 943
+q	 938
+qu	 938
+_s	 908
+ta	 902
+_de_	 901
+_o	 858
+se	 841
+ue	 831
+to	 799
+ad	 777
+.	 761
+que	 752
+em	 751
+an	 748
+f	 746
+r_	 745
+b	 732
+st	 718
+is	 716
+al	 712
+_qu	 706
+_q	 706
+in	 701
+as_	 696
+ã	 695
+do_	 685
+ent	 678
+ão	 677
+_n	 671
+_co	 660
+_a_	 654
+_m	 646
+on	 645
+ç	 624
+ri	 623
+_que	 619
+ma	 602
+po	 581
+ia	 580
+ão_	 575
+._	 573
+na	 572
+me	 564
+ro	 554
+_t	 544
+pa	 533
+da_	 528
+h	 523
+ue_	 515
+ca	 511
+que_	 509
+nte	 503
+no	 499
+tr	 498
+am	 496
+em_	 491
+_que_	 487
+_se	 485
+om	 471
+io	 460
+_do	 459
+ti	 448
+ci	 445
+_da	 444
+nd	 442
+ei	 435
+ra_	 435
+pr	 427
+_r	 423
+_e_	 420
+_f	 420
+ss	 412
+es_	 412
+el	 407
+id	 406
+_o_	 399
+_pa	 390
+um	 379
+pe	 378
+_po	 376
+la	 374
+ir	 371
+á	 371
+ic	 362
+di	 362
+li	 359
+é	 359
+_re	 353
+ve	 353
+mo	 350
+s,	 349
+s,_	 349
+ou	 347
+com	 340
+sa	 338
+si	 338
+men	 337
+rt	 331
+_i	 330
+con	 330
+o,	 327
+_da_	 326
+o,_	 326
+se_	 325
+_com	 325
+ado	 323
+to_	 322
+ai	 322
+it	 320
+A	 319
+ec	 316
+dos	 316
+_em	 312
+ção	 310
+aç	 310
+çã	 310
+ara	 305
+so	 299
+tu	 299
+res	 297
+im	 296
+_pr	 295
+mi	 293
+ua	 292
+nto	 291
+ment	 290
+í	 290
+par	 288
+_do_	 287
+ce	 286
+est	 286
+u_	 284
+ente	 284
+S	 278
+l_	 278
+_u	 278
+"	 276
+ni	 276
+z	 274
+sta	 273
+nc	 272
+_em_	 270
+P	 269
+ção_	 267
+_v	 267
+at	 267
+dos_	 266
+_es	 262
+«	 259
+_«	 259
+te_	 258
+»	 257
+va	 255
+le	 252
+ur	 252
+_um	 252
+vi	 251
+_par	 250
+a,	 247
+a,_	 247
+_con	 247
+ant	 242
+lo	 240
+ia_	 240
+gu	 237
+ar_	 235
+ac	 235
+e,_	 234
+e,	 234
+no_	 232
+eg	 232
+il	 232
+ns	 232
+er_	 231
+_ma	 230
+por	 230
+_in	 228
+_l	 226
+ó	 225
+ont	 224
+_no	 223
+_P	 222
+tra	 220
+E	 219
+ida	 218
+is_	 217
+ol	 216
+açã	 215
+ter	 215
+ação	 215
+_A	 211
+un	 211
+-	 210
+_te	 210
+or_	 209
+ma_	 208
+_pe	 208
+ara_	 208
+C	 206
+ist	 202
+para	 202
+nta	 201
+ais	 201
+ut	 198
+nte_	 198
+j	 197
+dad	 196
+_na	 195
+am_	 195
+ade	 193
+ica	 191
+x	 190
+al_	 189
+O	 188
+des	 187
+_para	 187
+ada	 187
+nh	 186
+_se_	 186
+mp	 185
+ndo	 184
+R	 183
+_por	 181
+ação_	 181
+para_	 179
+eir	 177
+ui	 177
+vo	 177
+ou_	 177
+ta_	 177
+M	 176
+ria	 175
+tos	 175
+rr	 174
+D	 174
+io_	 174
+br	 174
+_di	 173
+õ	 173
+õe	 173
+fo	 173
+I	 172
+ões	 172
+_C	 171
+mo_	 171
+ov	 170
+pro	 169
+_os_	 169
+_os	 169
+das	 167
+iv	 166
+uma	 165
+gr	 165
+su	 164
+fi	 164
+um_	 162
+na_	 162
+ga	 162
+ais_	 161
+_S	 161
+lh	 159
+ort	 159
+cia	 158
+..	 157
+_est	 156
+cont	 156
+ig	 155
+á_	 154
+ran	 154
+ça	 154
+om_	 153
+_en	 152
+dade	 152
+_as	 152
+ho	 152
+ntr	 151
+nto_	 151
+fe	 150
+N	 149
+das_	 149
+uma_	 149
+ess	 149
+é_	 148
+ndo_	 147
+ob	 147
+»_	 147
+ul	 146
+ente_	 146
+go	 146
+ento	 144
+ver	 144
+_des	 144
+gi	 144
+ha	 142
+cu	 142
+idad	 142
+av	 141
+ões_	 141
+_pro	 141
+ura	 141
+ap	 139
+_com_	 139
+_ca	 139
+com_	 139
+ao	 139
+ne	 138
+od	 138
+_"	 137
+_M	 137
+pre	 137
+ras	 136
+_me	 136
+_ao	 136
+_no_	 134
+oc	 134
+str	 133
+tes	 133
+_b	 133
+and	 133
+_g	 133
+ro_	 133
+omo	 133
+_dos	 132
+_fo	 132
+_dos_	 132
+rn	 132
+mento	 131
+ito	 131
+ev	 131
+rio	 130
+ass	 130
+eu	 130
+be	 128
+os,	 128
+os,_	 128
+sp	 127
+_uma	 127
+ep	 126
+tad	 125
+s.	 125
+_uma_	 125
+_E	 125
+idade	 124
+_um_	 124
+nã	 124
+não	 124
+ct	 123
+ram	 123
+ado_	 123
+ela	 123
+omo_	 121
+iz	 121
+_an	 121
Index: /main/tags/2.25/gsdl/perllib/textcat/russian-windows1251.lm
===================================================================
--- /main/tags/2.25/gsdl/perllib/textcat/russian-windows1251.lm	(revision 21064)
+++ /main/tags/2.25/gsdl/perllib/textcat/russian-windows1251.lm	(revision 21064)
@@ -0,0 +1,400 @@
+_	 21836
+î	 5818
+à	 4506
+å	 4258
+è	 3769
+ò	 3394
+í	 3254
+ñ	 2594
+ë	 2470
+ð	 2346
+â	 2227
+ê	 1798
+ì	 1709
+ó	 1673
+ä	 1638
+ï	 1377
+,	 1187
+,_	 1172
+î_	 1160
+ÿ	 1059
+ü	 1024
+û	 1006
+å_	 966
+á	 945
+_ï	 937
+ç	 910
+_í	 907
+è_	 896
+òî	 878
+ã	 856
+_ñ	 828
+_â	 818
+à_	 801
+÷	 795
+.	 789
+._	 761
+ñò	 655
+íå	 617
+_è	 616
+íà	 575
+ø	 568
+é	 565
+ïî	 549
+ðà	 526
+íî	 524
+ÿ_	 522
+_ò	 521
+_î	 497
+_ä	 496
+æ	 484
+_ïî	 477
+_ê	 477
+ãî	 472
+àë	 470
+ü_	 461
+íè	 456
+îâ	 454
+êî	 452
+ðî	 432
+êà	 431
+ëè	 425
+õ	 413
+òà	 403
+åí	 402
+_ì	 396
+_á	 396
+âî	 395
+îë	 388
+òî_	 384
+é_	 383
+_íå	 378
+_è_	 375
+îð	 369
+âà	 367
+_íà	 365
+ì_	 364
+îì	 363
+ïð	 357
+ó_	 357
+åë	 353
+åð	 352
+ëà	 350
+èò	 344
+îñ	 344
+ë_	 343
+òü	 338
+äå	 337
+ëî	 334
+ðè	 330
+ðå	 328
+èë	 326
+àê	 326
+îò	 323
+-	 322
+îí	 320
+åò	 317
+þ	 312
+àí	 308
+âå	 308
+â_	 302
+_÷	 299
+ò_	 296
+çà	 292
+íå_	 292
+òå	 291
+äà	 291
+_ç	 291
+îä	 286
+àð	 283
+àò	 283
+_ïð	 274
+åñ	 264
+ìî	 263
+û_	 260
+îã	 253
+_-	 245
+_ó	 245
+ê_	 244
+îá	 240
+ãî_	 238
+ñÿ	 235
+_íå_	 235
+ìå	 233
+ëü	 229
+-_	 225
+ñê	 219
+_â_	 217
+åì	 217
+íû	 215
+îé	 215
+ñå	 211
+áû	 211
+êè	 211
+÷ò	 209
+òü_	 209
+÷å	 208
+_ã	 206
+Í	 206
+äî	 205
+ö	 205
+÷òî	 203
+èí	 203
+àñ	 202
+_-_	 202
+_÷ò	 199
+_÷òî	 199
+òè	 197
+àâ	 197
+íà_	 197
+_å	 195
+åä	 192
+_ð	 191
+æå	 190
+àì	 190
+åã	 188
+àç	 188
+òð	 185
+_òî	 184
+_Í	 183
+èì	 182
+_çà	 181
+äè	 175
+Â	 174
+_êî	 172
+ëå	 170
+_Â	 169
+îé_	 168
+!	 168
+÷òî_	 165
+ìó	 165
+íî_	 164
+èñ	 164
+í_	 164
+ìè	 163
+ñòà	 163
+ù	 162
+_÷òî_	 162
+_áû	 159
+ìà	 158
+ðó	 157
+âû	 156
+âè	 154
+âñ	 154
+åãî	 153
+èê	 153
+èç	 153
+ñü	 153
+àø	 152
+ûë	 150
+_íà_	 149
+ñ_	 148
+òâ	 148
+_ñò	 146
+ñÿ_	 146
+ëè_	 146
+_ÿ	 144
+îãî	 143
+øå	 141
+õ_	 141
+àê_	 141
+!_	 139
+ñî	 139
+êó	 139
+áî	 137
+ïðî	 136
+àòü	 136
+åãî_	 135
+_êà	 134
+_ìî	 131
+èå	 131
+îñò	 130
+îì_	 129
+î,	 128
+_ãî	 128
+î,_	 127
+èâ	 127
+ñë	 126
+óò	 126
+_òà	 126
+íí	 125
+àä	 125
+Ñ	 124
+íó	 123
+î÷	 122
+_âû	 122
+_âñ	 121
+_îí	 120
+áûë	 120
+ïà	 120
+óä	 120
+_Ñ	 119
+ïðè	 119
+îâî	 119
+õî	 118
+ý	 117
+_áûë	 117
+è,	 115
+åé	 115
+_äî	 115
+àë_	 114
+_æ	 114
+è,_	 114
+_à	 113
+_ý	 113
+îå	 112
+åñò	 112
+îðî	 110
+çí	 110
+_äå	 110
+øè	 109
+èä	 109
+ñòî	 109
+_ïðî	 109
+_âî	 108
+àëè	 108
+íÿ	 107
+øà	 107
+ýò	 107
+îæ	 106
+à,	 106
+Ï	 106
+ûé	 105
+îëü	 105
+óñ	 105
+_ýò	 105
+_ïðè	 104
+èõ	 104
+ñü_	 104
+ñè	 104
+îï	 104
+Ì	 103
+à,_	 103
+àÿ	 103
+åç	 102
+äåë	 102
+_ðà	 102
+_Ï	 101
+îâà	 101
+óæ	 101
+âàë	 101
+þ_	 101
+êàê	 100
+_ÿ_	 100
+ó,	 100
+æå_	 100
+ñòâ	 100
+äí	 100
+÷è	 100
+òó	 100
+_õ	 100
+_Ì	 99
+ò,	 99
+îê	 99
+èòü	 99
+åò_	 99
+_ñî	 99
+ëÿ	 98
+àå	 98
+_îò	 98
+îãî_	 98
+Ê	 97
+âîð	 97
+òí	 97
+_ë	 97
+ó,_	 97
+äó	 96
+_äà	 96
+ò,_	 96
+áà	 96
+ïå	 96
+ëà_	 95
+áó	 95
+áå	 94
+ìó_	 94
+_ìå	 94
+÷à	 94
+âñå	 93
+òû	 93
+êà_	 92
+_êàê	 91
+ìí	 91
+òñ	 90
+íü	 90
+_îá	 90
+?	 90
+ðàç	 89
+òàê	 89
+_ñ_	 89
+ñà	 89
+å,	 89
+æè	 88
+ô	 88
+_òàê	 88
+èÿ	 88
+è÷	 88
+îí_	 87
+ìåí	 87
+å,_	 87
+ûé_	 86
+ë,	 86
+ë,_	 86
+òîì	 86
+ðàí	 86
+ýòî	 86
+Íó	 86
+È	 86
+öè	 85
+èå_	 85
+âåð	 85
+ñâ	 84
+_îí_	 84
+_âñå	 84
+ðû	 84
+_ýòî	 84
+_È	 84
+ç_	 83
+ïè	 83
+ëó	 83
+À	 83
+åíè	 82
+èë_	 82
+"	 82
+ïîë	 82
+àòü_	 81
+òîð	 81
+èëè	 81
+êð	 81
+ëñ	 81
+òåë	 81
+åíí	 81
+îòî	 80
+äà_	 79
+èòå	 79
+ñòð	 79
+îâîð	 79
+ãîâ	 79
+îðè	 79
+àíè	 79
+_Íó	 78
+ëñÿ	 78
+_íè	 78
+è.	 77
+_ñâ	 77
+è._	 76
+à.	 76
+_èç	 76
+èø	 76
+ùå	 76
+ÿò	 76
+îëî	 76
+ü,	 75
+Î	 75
+êè_	 75
+ü,_	 75
+ëî_	 75
+îç	 74
+_åã	 74
+ëüí	 74
+üí	 74
+ûå	 74
Index: /main/tags/2.25/gsdl/perllib/textcat/spanish.lm
===================================================================
--- /main/tags/2.25/gsdl/perllib/textcat/spanish.lm	(revision 21064)
+++ /main/tags/2.25/gsdl/perllib/textcat/spanish.lm	(revision 21064)
@@ -0,0 +1,400 @@
+_	 25044
+e	 7830
+a	 7437
+o	 5102
+s	 4394
+n	 4358
+i	 4065
+r	 3998
+l	 3634
+d	 3118
+c	 2931
+t	 2834
+u	 2316
+a_	 2269
+e_	 2211
+s_	 1862
+de	 1679
+p	 1673
+_d	 1644
+m	 1447
+_de	 1443
+n_	 1332
+o_	 1301
+en	 1295
+_e	 1216
+es	 1177
+_l	 1132
+de_	 1080
+la	 1060
+os	 1028
+_de_	 1027
+_p	 963
+l_	 910
+ci	 890
+_c	 866
+_a	 866
+os_	 801
+ar	 777
+er	 775
+as	 768
+ra	 746
+nt	 736
+_la	 727
+re	 726
+,_	 724
+,	 724
+el	 722
+ta	 708
+ue	 701
+g	 678
+on	 674
+al	 670
+_s	 666
+co	 653
+b	 637
+an	 622
+v	 616
+la_	 616
+or	 612
+te	 599
+st	 596
+el_	 580
+_la_	 573
+y	 545
+to	 543
+r_	 517
+ad	 512
+ó	 511
+do	 504
+ro	 504
+se	 488
+as_	 488
+q	 487
+qu	 487
+.	 479
+._	 478
+en_	 475
+ca	 460
+in	 459
+un	 456
+_co	 450
+es_	 449
+ic	 449
+_en	 440
+ac	 440
+que	 439
+na	 439
+lo	 430
+_m	 430
+f	 429
+ent	 428
+da	 412
+ue_	 411
+po	 405
+le	 399
+_q	 399
+_qu	 399
+que_	 393
+_que	 388
+ie	 386
+h	 385
+pa	 382
+y_	 371
+ti	 367
+_que_	 365
+_en_	 365
+_y	 361
+tr	 358
+_el	 353
+ri	 349
+ia	 342
+_el_	 333
+_se	 330
+ió	 330
+_y_	 330
+io	 329
+pr	 320
+ón	 317
+ec	 317
+no	 314
+id	 301
+í	 300
+mi	 299
+_t	 299
+ión	 292
+nte	 292
+me	 286
+aci	 283
+do_	 279
+li	 276
+con	 276
+nd	 273
+est	 272
+ni	 272
+á	 271
+di	 270
+_es	 268
+_lo	 267
+ció	 265
+ma	 265
+ón_	 264
+_pr	 263
+_r	 261
+ción	 255
+z	 254
+ra_	 251
+si	 247
+ión_	 246
+oc	 245
+nc	 244
+_u	 244
+_po	 243
+los	 243
+or_	 242
+_con	 241
+is	 239
+del	 238
+_del	 237
+ado	 236
+se_	 233
+_i	 233
+los_	 231
+_re	 231
+por	 229
+_del_	 228
+sta	 228
+del_	 228
+al_	 228
+ne	 226
+_h	 226
+cu	 225
+_n	 225
+_a_	 224
+_v	 224
+_un	 223
+ce	 222
+so	 220
+ción_	 218
+res	 218
+vi	 217
+om	 216
+te_	 212
+_pa	 211
+ien	 210
+j	 209
+E	 208
+_los	 207
+_los_	 207
+to_	 206
+ol	 204
+it	 203
+am	 202
+ació	 201
+rt	 201
+ación	 201
+pe	 197
+ha	 190
+_se_	 189
+nto	 188
+_o	 184
+_E	 184
+on_	 184
+sa	 183
+na_	 182
+ta_	 181
+su	 180
+cia	 180
+mo	 180
+ct	 178
+par	 178
+_f	 177
+_por	 176
+eg	 172
+_in	 172
+ur	 170
+L	 168
+ve	 166
+im	 164
+ga	 163
+_est	 161
+ar_	 161
+ab	 160
+_L	 159
+tu	 158
+at	 158
+no_	 157
+s,	 157
+s,_	 157
+_por_	 156
+por_	 156
+las	 156
+ba	 154
+o,_	 154
+o,	 154
+ento	 151
+et	 150
+C	 150
+_ha	 149
+A	 149
+tra	 148
+ient	 148
+_al	 147
+a,_	 146
+ica	 146
+a,	 146
+pro	 146
+ado_	 145
+ici	 144
+_ca	 144
+an_	 144
+las_	 143
+ara	 143
+nci	 143
+ente	 142
+ú	 142
+rr	 142
+ir	 142
+da_	 141
+em	 141
+ll	 140
+il	 139
+ía	 138
+iv	 138
+_su	 138
+_par	 136
+ul	 136
+ant	 136
+_A	 135
+mp	 135
+_las_	 134
+_las	 134
+_C	 134
+_pro	 133
+men	 132
+P	 132
+des	 131
+com	 130
+ion	 130
+era	 130
+ed	 129
+ida	 129
+sp	 128
+gu	 127
+nte_	 127
+ns	 127
+za	 126
+dos	 125
+M	 125
+cio	 125
+les	 125
+_P	 124
+bl	 124
+_com	 122
+s._	 122
+s.	 122
+_M	 121
+ua	 120
+nta	 120
+mu	 119
+_no	 118
+dad	 118
+ñ	 117
+é	 116
+un_	 116
+va	 116
+ist	 116
+nes	 116
+iento	 115
+one	 114
+ara_	 113
+S	 113
+ada	 113
+_un_	 113
+fi	 111
+pre	 110
+tos	 110
+ter	 109
+ot	 109
+esta	 108
+_me	 107
+ido	 107
+ob	 107
+_g	 105
+br	 105
+go	 105
+ea	 104
+nto_	 104
+ona	 103
+pu	 103
+dos_	 103
+tro	 103
+ier	 103
+para	 102
+ment	 101
+ag	 101
+ero	 101
+gr	 101
+rec	 101
+bi	 101
+ia_	 100
+una	 100
+nic	 99
+ncia	 99
+ía_	 98
+a._	 98
+tos_	 98
+a.	 98
+ran	 98
+lo_	 97
+ones	 97
+rm	 96
+lu	 96
+ron	 95
+con_	 95
+ó_	 95
+nes_	 95
+_ci	 95
+ante	 94
+ch	 94
+_con_	 94
+_para	 94
+ntr	 93
+una_	 93
+para_	 93
+mie	 92
+ico	 92
+fe	 92
+les_	 92
+uc	 92
+ip	 91
+sto	 91
+_ma	 91
+ui	 91
+sta_	 91
+_ve	 90
+cion	 90
+"	 90
+op	 90
+cal	 89
+_mu	 89
+_S	 89
+ro_	 89
+_pe	 88
+ste	 88
+ras	 88
+pl	 88
+_una	 88
+_di	 87
+ento_	 86
+ita	 86
+ione	 85
+ect	 85
+_una_	 85
+mien	 85
+tan	 85
+du	 84
+den	 84
+ndo	 84
+per	 84
+eri	 84
Index: /main/tags/2.25/gsdl/perllib/textcat/swedish.lm
===================================================================
--- /main/tags/2.25/gsdl/perllib/textcat/swedish.lm	(revision 21064)
+++ /main/tags/2.25/gsdl/perllib/textcat/swedish.lm	(revision 21064)
@@ -0,0 +1,400 @@
+_	 33494
+e	 8992
+n	 7900
+t	 7859
+a	 7781
+r	 7251
+s	 6435
+i	 5649
+l	 4541
+d	 4079
+o	 3724
+m	 3203
+k	 3058
+g	 2478
+en	 2403
+n_	 2389
+t_	 2073
+de	 1939
+r_	 1910
+v	 1890
+h	 1789
+u	 1782
+_s	 1768
+ä	 1724
+er	 1709
+f	 1597
+en_	 1537
+a_	 1526
+an	 1357
+p	 1320
+et	 1317
+ö	 1278
+å	 1261
+st	 1236
+ar	 1226
+c	 1191
+_d	 1158
+e_	 1116
+in	 1045
+_f	 1027
+te	 1000
+b	 997
+_a	 978
+s_	 974
+ra	 958
+.	 956
+tt	 935
+_i	 898
+_m	 890
+._	 886
+ll	 870
+ta	 844
+_o	 842
+_e	 839
+nd	 820
+ti	 804
+sk	 798
+re	 779
+at	 769
+_de	 754
+om	 743
+m_	 739
+ör	 720
+,	 697
+,_	 695
+ng	 686
+li	 673
+ka	 666
+oc	 662
+_h	 654
+on	 652
+et_	 647
+ch	 645
+ns	 643
+is	 642
+er_	 630
+är	 625
+_v	 614
+_t	 614
+ni	 611
+i_	 609
+_oc	 592
+tt_	 587
+na	 586
+y	 586
+la	 579
+_b	 579
+h_	 577
+kt	 575
+ch_	 568
+ig	 564
+fö	 563
+och	 555
+or	 555
+_och	 554
+och_	 554
+_och_	 553
+me	 548
+den	 548
+om_	 535
+_i_	 531
+d_	 530
+j	 529
+ik	 520
+de_	 520
+för	 518
+ge	 498
+ad	 497
+_k	 491
+_fö	 487
+ri	 484
+el	 482
+il	 481
+so	 480
+al	 474
+g_	 469
+le	 464
+an_	 461
+_för	 447
+si	 437
+ar_	 437
+att	 435
+_p	 434
+es	 420
+ing	 413
+se	 407
+to	 404
+_u	 403
+_en	 403
+and	 398
+den_	 395
+nde	 393
+nn	 393
+_l	 391
+å_	 391
+D	 385
+än	 383
+nt	 382
+l_	 381
+tr	 378
+_D	 372
+va	 370
+am	 369
+sa	 367
+_so	 365
+ga	 364
+_en_	 361
+är_	 358
+ck	 357
+av	 354
+v_	 351
+ed	 347
+ma	 346
+da	 346
+som	 346
+rs	 344
+som_	 344
+ve	 342
+ter	 341
+att_	 341
+ha	 338
+ne	 337
+ut	 335
+as	 332
+ska	 329
+_at	 327
+_att	 326
+_som	 324
+_att_	 324
+_som_	 323
+vi	 322
+ikt	 317
+_av	 316
+det	 316
+_den	 315
+he	 315
+ss	 314
+un	 307
+ke	 304
+_g	 303
+us	 302
+di	 302
+_st	 300
+rn	 297
+_me	 296
+_ä	 295
+ade	 294
+"	 290
+_ha	 290
+av_	 289
+ill	 288
+_n	 286
+_in	 279
+io	 275
+_r	 275
+der	 275
+it	 274
+_av_	 274
+sta	 274
+gen	 272
+isk	 270
+_ti	 269
+id	 265
+na_	 265
+ns_	 264
+ko	 262
+_den_	 261
+ag	 258
+det_	 257
+lig	 257
+era	 256
+ll_	 255
+_det	 252
+_är	 251
+be	 249
+_är_	 248
+ra_	 247
+ion	 244
+-	 241
+pr	 240
+oni	 233
+til	 231
+ten	 228
+_si	 225
+k_	 222
+på	 222
+fr	 221
+ro	 219
+till	 219
+iv	 216
+ls	 216
+ande	 215
+ör_	 214
+_det_	 213
+äl	 212
+_på	 211
+ts	 210
+ens	 209
+med	 209
+mm	 208
+rt	 208
+_till	 208
+_til	 208
+_va	 207
+_fr	 205
+_sk	 205
+var	 205
+nin	 204
+ning	 203
+ol	 201
+ka_	 200
+lle	 198
+ett	 198
+rd	 197
+em	 196
+på_	 195
+x	 195
+rk	 194
+_ut	 194
+ste	 194
+ds	 193
+_vi	 192
+år	 192
+S	 192
+nde_	 191
+are	 191
+ver	 190
+_på_	 190
+nis	 189
+kr	 189
+_med	 188
+all	 188
+ån	 187
+nge	 185
+mo	 184
+os	 183
+ld	 182
+ade_	 181
+_S	 181
+ed_	 180
+rä	 176
+De	 175
+_-	 175
+kan	 174
+ta_	 173
+ng_	 172
+vä	 171
+för_	 170
+ill_	 170
+han	 170
+_De	 170
+pp	 169
+lt	 169
+sam	 168
+nte	 167
+ans	 167
+ton	 166
+ur	 165
+mi	 165
+ess	 165
+kl	 164
+ig_	 164
+ks	 164
+as_	 163
+und	 163
+men	 162
+med_	 161
+_med_	 161
+ak	 161
+Di	 160
+ot	 159
+rna	 159
+ul	 159
+_var	 159
+te_	 158
+gen_	 158
+het	 157
+kto	 157
+str	 156
+_Di	 155
+tad	 155
+lan	 154
+ga_	 154
+iska	 154
+fa	 154
+fi	 154
+så	 154
+Dikt	 153
+Dik	 153
+pe	 153
+ska_	 152
+ja	 152
+H	 151
+res	 151
+ku	 151
+iu	 150
+ande_	 150
+till_	 150
+t.	 150
+ern	 150
+rm	 149
+_Dikt	 149
+_Dik	 149
+ie	 149
+bl	 148
+-_	 147
+od	 147
+_H	 147
+n.	 147
+ist	 147
+_di	 146
+ius	 146
+_"	 145
+la_	 145
+sl	 145
+man	 145
+ren	 145
+_för_	 145
+toni	 144
+kton	 144
+n._	 144
+ktoni	 144
+ikton	 144
+I	 144
+ikto	 144
+nius	 143
+ten_	 143
+onius	 143
+oniu	 143
+toniu	 143
+ing_	 143
+Dikto	 143
+niu	 143
+_ko	 143
+ic	 142
+_sa	 142
+_han	 142
+ett_	 142
+sm	 141
+ba	 141
+M	 141
+gr	 140
+lä	 140
+ex	 138
+t._	 138
+sp	 137
+lla	 137
+_et	 137
+_M	 137
+dr	 137
+rö	 136
+rad	 136
+ek	 136
+_be	 135
+tar	 135
+_-_	 135
+_om	 134
+rl	 134
+E	 134
+mä	 133
Index: /main/tags/2.25/gsdl/perllib/unicode.pm
===================================================================
--- /main/tags/2.25/gsdl/perllib/unicode.pm	(revision 21064)
+++ /main/tags/2.25/gsdl/perllib/unicode.pm	(revision 21064)
@@ -0,0 +1,287 @@
+###########################################################################
+#
+# unicode.pm --
+# A component of the Greenstone digital library software
+# from the New Zealand Digital Library Project at the 
+# University of Waikato, New Zealand.
+#
+# Copyright (C) 1999 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.
+#
+###########################################################################
+
+# useful functions for dealing with Unicode
+
+# Unicode strings are stored as arrays of scalars as perl 
+# lacks characters are 8-bit (currently)
+
+package unicode;
+
+%translations = ();
+
+# ascii2unicode takes an (extended) ascii string (ISO-8859-1)
+# and returns a unicode array.
+sub ascii2unicode {
+    my ($in) = @_;
+    my $out = [];
+
+    my $i = 0;
+    my $len = length($in);
+    while ($i < $len) {
+	push (@$out, ord(substr ($in, $i, 1)));	
+	$i++;
+    }
+
+    return $out;
+}
+
+# arabic2unicode takes an 8 bit Arabic string (ISO-8859-6)
+# and returns a unicode array
+sub arabic2unicode {
+    my ($in) = @_;
+    my $out = [];
+
+    my $i = 0;
+    my $len = length($in);
+    while ($i < $len) {
+	my $c = ord(substr ($in, $i, 1));
+	$c += (1567-191) if ($c >= 0x80);
+	push (@$out, $c);
+	$i++;
+    }
+
+    return $out;
+}
+
+# windows2unicode takes a windows encoding (e.g. Windows 1256 (Arabic))
+# and returns a unicode array. These encodings are similar to but not
+# identical to the corresponding ISO-8859 encodings.
+#
+# The map files for these encodings should be in unicode/MAPPINGS/WINDOWS
+sub windows2unicode {
+    my ($encoding, $in) = @_;
+    my $out = [];
+
+    my $mapfile = &util::filename_cat($ENV{'GSDLHOME'}, "unicode", "MAPPINGS", 
+				      "WINDOWS", "$encoding.TXT"); 
+    return $out unless &loadmapping ($encoding, $mapfile);
+
+    my $i = 0;
+    my $len = length($in);
+    while ($i < $len) {
+	my $c = ord(substr ($in, $i, 1));
+	$c = $translations{"$encoding-unicode"}->{$c} if ($c >= 0x80);
+	push (@$out, $c);
+	$i++;
+    }
+
+    return $out;
+}
+
+
+# ascii2utf8 takes a (extended) ascii string and
+# returns a UTF-8 encoded string. This is just
+# a faster version of "&unicode2utf8(&ascii2unicode($str));"
+sub ascii2utf8 {
+    my ($in) = @_;
+    my $out = "";
+
+    my ($c);
+    my $i = 0;
+    my $len = length($in);
+    while ($i < $len) {
+	$c = ord (substr ($in, $i, 1));
+	if ($c < 0x80) {
+	    # ascii character
+	    $out .= chr ($c);
+
+	} else {
+	    # extended ascii character
+	    $out .= chr (0xc0 + (($c >> 6) & 0x1f));
+	    $out .= chr (0x80 + ($c & 0x3f));
+	}
+	$i++;
+    }
+
+    return $out;
+}
+
+
+# unicode2utf8 takes a unicode array as input and encodes it
+# using utf-8
+sub unicode2utf8 {
+    my ($in) = @_;
+    my $out = "";
+    
+    foreach $num (@$in) {
+	if ($num < 0x80) {
+	    $out .= chr ($num);
+
+	} elsif ($num < 0x800) {
+	    $out .= chr (0xc0 + (($num >> 6) & 0x1f));
+	    $out .= chr (0x80 + ($num & 0x3f));
+
+	} elsif ($num < 0xFFFF) {
+	    $out .= chr (0xe0 + (($num >> 12) & 0xf));
+	    $out .= chr (0x80 + (($num >> 6) & 0x3f));
+	    $out .= chr (0x80 + ($num & 0x3f));
+
+	} else {
+	    # error, don't encode anything
+	    die;
+	}
+    }
+
+    return $out;
+}
+
+
+# utf82unicode takes a utf-8 string and produces a unicode
+# array
+sub utf82unicode {
+    my ($in) = @_;
+    my $out = [];
+
+    my $i = 0;
+    my ($c1, $c2, $c3);
+    $len = length($in);
+    while ($i < $len) {
+	if (($c1 = ord(substr ($in, $i, 1))) < 0x80) {
+	    # normal ascii character
+	    push (@$out, $c1);
+
+	} elsif ($c1 < 0xc0) {
+	    # error, was expecting the first byte of an
+	    # encoded character. Do nothing.
+
+	} elsif ($c1 < 0xe0 && $i+1 < $len) {
+	    # an encoded character with two bytes
+	    $c2 = ord (substr ($in, $i+1, 1));
+	    if ($c2 >= 0x80 && $c2 < 0xc0) {
+		# everything looks ok
+		push (@$out, ((($c1 & 0x1f) << 6) +
+		      ($c2 & 0x3f)));
+		$i++; # gobbled an extra byte
+	    }
+
+	} elsif ($c1 < 0xf0 && $i+2 < $len) {
+	    # an encoded character with three bytes
+	    $c2 = ord (substr ($in, $i+1, 1));
+	    $c3 = ord (substr ($in, $i+2, 1));
+	    if ($c2 >= 0x80 && $c2 < 0xc0 &&
+		$c3 >= 0x80 && $c3 < 0xc0) {
+		# everything looks ok
+		push (@$out, ((($c1 & 0xf) << 12) +
+		      (($c2 & 0x3f) << 6) +
+		      ($c3 & 0x3f)));
+
+		$i += 2; # gobbled an extra two bytes
+	    }
+
+	} else {
+	    # error, only decode Unicode characters not full UCS.
+	    # Do nothing.
+	}
+
+	$i++;
+    }
+
+    return $out;
+}
+
+
+# unicode2ucs2 takes a unicode array and produces a UCS-2
+# unicode string (every two bytes forms a unicode character)
+sub unicode2ucs2 {
+    my ($in) = @_;
+    my $out = "";
+
+    foreach $num (@$in) {
+	$out .= chr (($num & 0xff00) >> 8);
+	$out .= chr ($num & 0xff);
+    }
+
+    return $out;
+}
+
+
+# ucs22unicode takes a UCS-2 string and produces a unicode array
+sub ucs22unicode {
+    my ($in) = @_;
+    my $out = [];
+
+    my $i = 0;
+    my $len = length ($in);
+    while ($i+1 < $len) {
+	push (@$out, ord (substr($in, $i, 1)) << 8 +
+	      ord (substr($in, $i+1, 1)));
+
+	$i ++;
+    }
+
+    return $out;
+}
+
+# loadmapping expects the mapfile to contain (at least) two
+# tab-separated fields. The first field is the mapped value
+# and the second field is the unicode value.
+#
+# It returns 1 if successful, 0 if unsuccessful
+sub loadmapping {
+    my ($encoding, $mapfile) = @_;
+    
+    my $to = "$encoding-unicode";
+    my $from = "unicode-$encoding";
+
+    # check to see if the encoding has already been loaded
+    if (defined $translations{$to} && defined $translations{$from}) {
+	return 1;
+    }
+
+    if (!open (MAPFILE, $mapfile)) {
+	print STDERR "ERROR: unable to load mapfile $mapfile\n";
+	return 0;
+    }
+
+    my ($line, @line);
+    $translations{$to} = {};
+    $translations{$from} = {};
+    while (defined ($line = <MAPFILE>)) {
+	# remove comments
+	$line =~ s/\#.*$//;
+	next unless $line =~ /\S/;
+
+	# split the line into fields and do a few
+	# simple sanity checks
+	@line = split (/\t/, $line);
+	next unless (scalar(@line) >= 2 &&
+		     $line[0] =~ /^0x/ &&
+		     $line[1] =~ /^0x/);
+
+	my $a = hex($line[0]);
+	my $b = hex($line[1]);
+
+	$translations{$to}->{$a} = $b;
+	$translations{$from}->{$b} = $a;
+    }
+
+    close (MAPFILE);
+
+    return 1;
+}
+
+
+1;
Index: /main/tags/2.25/gsdl/perllib/util.pm
===================================================================
--- /main/tags/2.25/gsdl/perllib/util.pm	(revision 21064)
+++ /main/tags/2.25/gsdl/perllib/util.pm	(revision 21064)
@@ -0,0 +1,569 @@
+###########################################################################
+#
+# util.pm -- various useful utilities
+# A component of the Greenstone digital library software
+# from the New Zealand Digital Library Project at the 
+# University of Waikato, New Zealand.
+#
+# Copyright (C) 1999 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 util;
+
+use File::Copy;
+use File::Basename;
+
+
+# removes files (but not directories)
+sub rm {
+    my (@files) = @_;
+    my @filefiles = ();
+
+    # make sure the files we want to delete exist 
+    # and are regular files
+    foreach $file (@files) {
+	if (!-e $file) {
+	    print STDERR "util::rm $file does not exist\n";
+	} elsif ((!-f $file) && (!-l $file)) {
+	    print STDERR "util::rm $file is not a regular (or symbolic) file\n";
+	} else {
+	    push (@filefiles, $file);
+	}
+    }
+    
+    # remove the files
+    my $numremoved = unlink @filefiles;
+
+    # check to make sure all of them were removed
+    if ($numremoved != scalar(@filefiles)) {
+	print STDERR "util::rm Not all files were removed\n";
+    }
+}
+
+
+# recursive removal
+sub rm_r {
+    my (@files) = @_;
+
+    # recursively remove the files
+    foreach $file (@files) {
+	$file =~ s/[\/\\]+$//; # remove trailing slashes
+	
+	if (!-e $file) {
+	    print STDERR "util::rm_r $file does not exist\n";
+
+	} elsif ((-d $file) && (!-l $file)) { # don't recurse down symbolic link
+	    # get the contents of this directory
+	    if (!opendir (INDIR, $file)) {
+		print STDERR "util::rm_r could not open directory $file\n";
+	    } else {
+		my @filedir = grep (!/^\.\.?$/, readdir (INDIR));
+		closedir (INDIR);
+
+		# remove all the files in this directory
+		&rm_r (map {$_="$file/$_";} @filedir);
+
+		# remove this directory
+		if (!rmdir $file) {
+		    print STDERR "util::rm_r couldn't remove directory $file\n";
+		}
+	    }
+
+	} else {
+	    # remove this file
+	    &rm ($file);
+	}
+    }
+}
+
+# moves a file or a group of files
+sub mv {
+    my $dest = pop (@_);
+    my (@srcfiles) = @_;
+
+    # remove trailing slashes from source and destination files
+    $dest =~ s/[\\\/]+$//;
+    map {$_ =~ s/[\\\/]+$//;} @srcfiles;
+
+    # a few sanity checks
+    if (scalar (@srcfiles) == 0) {
+	print STDERR "util::mv no destination directory given\n";
+	return;
+    } elsif ((scalar (@srcfiles) > 1) && (!-d $dest)) {
+	print STDERR "util::mv if multiple source files are given the ".
+	    "destination must be a directory\n";
+	return;
+    }
+
+    # move the files
+    foreach $file (@srcfiles) {
+	my $tempdest = $dest;
+	if (-d $tempdest) {
+	    my ($filename) = $file =~ /([^\\\/]+)$/;
+	    $tempdest .= "/$filename";
+	}
+	if (!-e $file) {
+	    print STDERR "util::mv $file does not exist\n";
+	} else {
+	    rename ($file, $tempdest);
+	}
+    }
+}
+
+
+# copies a file or a group of files
+sub cp {
+    my $dest = pop (@_);
+    my (@srcfiles) = @_;
+
+    # remove trailing slashes from source and destination files
+    $dest =~ s/[\\\/]+$//;
+    map {$_ =~ s/[\\\/]+$//;} @srcfiles;
+
+    # a few sanity checks
+    if (scalar (@srcfiles) == 0) {
+	print STDERR "util::cp no destination directory given\n";
+	return;
+    } elsif ((scalar (@srcfiles) > 1) && (!-d $dest)) {
+	print STDERR "util::cp if multiple source files are given the ".
+	    "destination must be a directory\n";
+	return;
+    }
+
+    # copy the files
+    foreach $file (@srcfiles) {
+	my $tempdest = $dest;
+	if (-d $tempdest) {
+	    my ($filename) = $file =~ /([^\\\/]+)$/;
+	    $tempdest .= "/$filename";
+	}
+	if (!-e $file) {
+	    print STDERR "util::cp $file does not exist\n";
+	} elsif (!-f $file) {
+	    print STDERR "util::cp $file is not a plain file\n";
+	} else {
+	    &File::Copy::copy ($file, $tempdest);
+	}
+    }
+}
+
+
+
+# recursively copies a file or group of files
+# syntax: cp_r (sourcefiles, destination file or directory)
+sub cp_r {
+    my $dest = pop (@_);
+    my (@srcfiles) = @_;
+
+    # remove trailing slashes from source and destination files
+    $dest =~ s/[\\\/]+$//;
+    map {$_ =~ s/[\\\/]+$//;} @srcfiles;
+
+    # a few sanity checks
+    if (scalar (@srcfiles) == 0) {
+	print STDERR "util::cp no destination directory given\n";
+	return;
+    } elsif ((scalar (@srcfiles) > 1) && (!-d $dest)) {
+	print STDERR "util::cp if multiple source files are given the ".
+	    "destination must be a directory\n";
+	return;
+    }
+    
+    # copy the files
+    foreach $file (@srcfiles) {
+	# copy the file to within dest if dest is a directory
+	# exception: if there is only one source file and that
+	# source file is a directory
+	my $tempdest = $dest;
+	if (-d $tempdest && !(scalar(@srcfiles) == 1 && -d $file)) {
+	    my ($filename) = $file =~ /([^\\\/]+)$/;
+	    $tempdest .= "/$filename";
+	}
+
+	if (!-e $file) {
+	    print STDERR "util::cp $file does not exist\n";
+
+	} elsif (-d $file) {
+	    # make a new directory (if needed)
+	    unless (-e $tempdest)
+	    {
+		my $store_umask = umask(0002);
+		mkdir ($tempdest, 0777);
+		umask($store_umask);
+	    }
+
+	    # get the contents of this directory
+	    if (!opendir (INDIR, $file)) {
+		print STDERR "util::cp_r could not open directory $file\n";
+	    } else {
+		my @filedir = grep (!/^\.\.?$/, readdir (INDIR));
+		closedir (INDIR);
+
+		# copy all the files in this directory
+		&cp_r (map {$_="$file/$_";} @filedir, $tempdest);
+	    }
+
+	} else {
+	    &cp($file, $tempdest);
+	}
+    }
+}
+
+
+sub mk_dir {
+    my ($dir) = @_;
+
+    my $store_umask = umask(0002);
+    my $mkdir_ok = mkdir ($dir, 0777);
+    umask($store_umask);
+    
+    if (!$mkdir_ok) 
+    {
+	print STDERR "util::mk_dir could not create directory $dir\n";
+	return;
+    }
+}
+
+# in case anyone cares - I did some testing (using perls Benchmark module)
+# on this subroutine against File::Path::mkpath (). mk_all_dir() is apparently
+# slightly faster (surprisingly) - Stefan.
+sub mk_all_dir {
+    my ($dir) = @_;
+
+    # use / for the directory separator, remove duplicate and
+    # trailing slashes
+    $dir=~s/[\\\/]+/\//g; 
+    $dir=~s/[\\\/]+$//;
+
+    # make sure the cache directory exists
+    my $dirsofar = "";
+    my $first = 1;
+    foreach $dirname (split ("/", $dir)) {
+	$dirsofar .= "/" unless $first;
+	$first = 0;
+
+	$dirsofar .= $dirname;
+
+	next if $dirname =~ /^(|[a-z]:)$/i;
+	if (!-e $dirsofar)
+	    {
+		my $store_umask = umask(0002);
+		my $mkdir_ok = mkdir ($dirsofar, 0777);
+		umask($store_umask);
+		if (!$mkdir_ok)
+		{
+		    print STDERR "util::mk_all_dir could not create directory $dirsofar\n";
+		    return;
+		}
+	    }
+    }
+}
+
+# make hard link to file if supported by OS, otherwise copy the file
+sub hard_link {
+    my ($src, $dest) = @_;
+
+    # remove trailing slashes from source and destination files
+    $src =~ s/[\\\/]+$//;
+    $dest =~ s/[\\\/]+$//;
+
+    # a few sanity checks
+    if (-e $dest) {
+	# destination file already exists
+	return;
+    }
+    elsif (!-e $src) {
+	print STDERR "util::hard_link source file $src does not exist\n";
+	return;
+    }
+    elsif (-d $src) {
+	print STDERR "util::hard_link source $src is a directory\n";
+	return;
+    }
+
+    my $dest_dir = &File::Basename::dirname($dest);
+    mk_all_dir($dest_dir) if (!-e $dest_dir);
+
+    # link not supported on wondows
+    if ($ENV{'GSDLOS'} =~ /^windows$/i) {
+	&File::Copy::copy ($src, $dest);
+
+    } elsif (!link($src, $dest)) {
+	print STDERR "util::hard_link: unable to create hard link. ";
+	print STDERR " Attempting to copy file: $src -> $dest\n";
+	&File::Copy::copy ($src, $dest);
+    }
+}
+
+# make soft link to file if supported by OS, otherwise return error
+sub soft_link {
+    my ($src, $dest) = @_;
+
+    # remove trailing slashes from source and destination files
+    $src =~ s/[\\\/]+$//;
+    $dest =~ s/[\\\/]+$//;
+
+    # a few sanity checks
+    if (!-e $src) {
+	print STDERR "util::soft_link source file $src does not exist\n";
+	return 0;
+    }
+
+    my $dest_dir = &File::Basename::dirname($dest);
+    mk_all_dir($dest_dir) if (!-e $dest_dir);
+
+    if (!symlink($src, $dest))
+    {
+	print STDERR "util::soft_link: unable to create soft link.";
+	return 0;
+    }
+
+    return 1;
+}
+
+
+
+
+# updates a copy of a directory in some other part of the filesystem
+# verbosity settings are: 0=low, 1=normal, 2=high
+# both $fromdir and $todir should be absolute paths
+sub cachedir {
+    my ($fromdir, $todir, $verbosity) = @_;
+    $verbosity = 1 unless defined $verbosity;
+
+    # use / for the directory separator, remove duplicate and
+    # trailing slashes
+    $fromdir=~s/[\\\/]+/\//g; 
+    $fromdir=~s/[\\\/]+$//;
+    $todir=~s/[\\\/]+/\//g; 
+    $todir=~s/[\\\/]+$//;
+
+    &mk_all_dir ($todir);
+
+    # get the directories in ascending order
+    if (!opendir (FROMDIR, $fromdir)) {
+	print STDERR "util::cachedir could not read directory $fromdir\n";
+	return;
+    }
+    my @fromdir = grep (!/^\.\.?$/, sort(readdir (FROMDIR)));
+    closedir (FROMDIR);
+
+    if (!opendir (TODIR, $todir)) {
+	print STDERR "util::cacedir could not read directory $todir\n";
+	return;
+    }
+    my @todir = grep (!/^\.\.?$/, sort(readdir (TODIR)));
+    closedir (TODIR);
+
+    my $fromi = 0;
+    my $toi = 0;
+		    
+    while ($fromi < scalar(@fromdir) || $toi < scalar(@todir)) {
+#	print "fromi: $fromi toi: $toi\n";
+
+	# see if we should delete a file/directory
+	# this should happen if the file/directory
+	# is not in the from list or if its a different
+	# size, or has an older timestamp
+	if ($toi < scalar(@todir)) {
+	    if (($fromi >= scalar(@fromdir)) ||
+		($todir[$toi] lt $fromdir[$fromi] || 
+		 ($todir[$toi] eq $fromdir[$fromi] && 
+		  &differentfiles("$fromdir/$fromdir[$fromi]","$todir/$todir[$toi]",
+				  $verbosity)))) {
+
+		# the files are different
+		&rm_r("$todir/$todir[$toi]");
+		splice(@todir, $toi, 1); # $toi stays the same
+
+	    } elsif ($todir[$toi] eq $fromdir[$fromi]) {
+		# the files are the same
+		# if it is a directory, check its contents
+		if (-d "$todir/$todir[$toi]") {
+		    &cachedir ("$fromdir/$fromdir[$fromi]",
+			       "$todir/$todir[$toi]", $verbosity);
+		}
+
+		$toi++;
+		$fromi++;
+		next;
+	    }
+	}
+  
+	# see if we should insert a file/directory
+	# we should insert a file/directory if there
+	# is no tofiles left or if the tofile does not exist
+	if ($fromi < scalar(@fromdir) && ($toi >= scalar(@todir) || 
+					  $todir[$toi] gt $fromdir[$fromi])) {
+	    &cp_r ("$fromdir/$fromdir[$fromi]", "$todir/$fromdir[$fromi]");
+	    splice (@todir, $toi, 0, $fromdir[$fromi]);
+
+	    $toi++;
+	    $fromi++;
+	}
+    }
+}
+
+# this function returns -1 if either file is not found
+# assumes that $file1 and $file2 are absolute file names or
+# in the current directory
+# $file2 is allowed to be newer than $file1
+sub differentfiles {
+    my ($file1, $file2, $verbosity) = @_;
+    $verbosity = 1 unless defined $verbosity;
+
+    $file1 =~ s/\/+$//;
+    $file2 =~ s/\/+$//;
+    
+    my ($file1name) = $file1 =~ /\/([^\/]*)$/;
+    my ($file2name) = $file2 =~ /\/([^\/]*)$/;
+
+    return -1 unless (-e $file1 && -e $file2);
+    if ($file1name ne $file2name) {
+	print STDERR "filenames are not the same\n" if ($verbosity >= 2);
+	return 1;
+    }
+
+    @file1stat = stat ($file1);
+    @file2stat = stat ($file2);
+
+    if (-d $file1) {
+	if (! -d $file2) {
+	    print STDERR "one file is a directory\n" if ($verbosity >= 2);
+	    return 1;
+	}
+	return 0;
+    }
+
+    # both must be regular files
+    unless (-f $file1 && -f $file2) {
+	print STDERR "one file is not a regular file\n" if ($verbosity >= 2);
+	return 1;
+    }
+
+    # the size of the files must be the same
+    if ($file1stat[7] != $file2stat[7]) {
+	print STDERR "different sized files\n" if ($verbosity >= 2);
+	return 1;
+    }
+
+    # the second file cannot be older than the first
+    if ($file1stat[9] > $file2stat[9]) {
+	print STDERR "file is older\n" if ($verbosity >= 2);
+	return 1;
+    }
+
+    return 0;
+}
+
+
+sub get_tmp_filename {
+    my $tmpdir = "$ENV{'GSDLHOME'}/tmp";
+    &mk_all_dir ($tmpdir) unless -e $tmpdir;
+
+    my $count = 1000;
+    my $rand = int(rand $count);
+    while (-e "$tmpdir/F$rand") {
+	$rand = int(rand $count);
+	$count++;
+    }
+
+    return "$tmpdir/F$rand";
+}
+
+
+sub filename_cat {
+    my (@filenames) = @_;
+    my $filename = join("/", @filenames);
+
+    # remove duplicate slashes and remove the last slash
+    if ($ENV{'GSDLOS'} =~ /^windows$/i) {
+	$filename =~ s/[\\\/]+/\\/g;
+    } else {
+	$filename =~ s/[\/]+/\//g; 
+	# DB: want a filename abc\de.html to remain like this
+    }
+    $filename =~ s/[\\\/]$//;
+
+    return $filename;
+}
+
+sub get_os_dirsep {
+
+    if ($ENV{'GSDLOS'} =~ /^windows$/i) {
+	return "\\\\";
+    } else {
+	return "\\\/";
+    }
+}
+
+sub get_re_dirsep {
+
+    return "\\\\|\\\/";
+}
+
+
+# if this is running on windows we want binaries to end in
+# .exe, otherwise they don't have to end in any extension
+sub get_os_exe {
+    return ".exe" if $ENV{'GSDLOS'} =~ /^windows$/i;
+    return "";
+}
+
+
+# test to see whether this is a big or little endian machine
+sub is_little_endian {
+    return (ord(substr(pack("s",1), 0, 1)) == 1);
+}
+
+
+# will return the collection name if successful, "" otherwise
+sub use_collection {
+    my ($collection) = @_;
+
+    # get and check the collection
+    if (!defined($collection) || $collection eq "") {
+	if (defined $ENV{'GSDLCOLLECTION'}) {
+	    $collection = $ENV{'GSDLCOLLECTION'};
+	} else {
+	    print STDERR "No collection specified\n";
+	    return "";
+	}
+    }
+    
+    if ($collection eq "modelcol") {
+	print STDERR "You can't use modelcol.\n";
+	return "";
+    }
+
+    # make sure the environment variables GSDLCOLLECTION and GSDLCOLLECTDIR
+    # are defined
+    $ENV{'GSDLCOLLECTION'} = $collection unless defined $ENV{'GSDLCOLLECTION'};
+    $ENV{'GSDLCOLLECTDIR'} = "$ENV{'GSDLHOME'}/collect/$collection";
+
+    # make sure this collection exists
+    if (!-e $ENV{'GSDLCOLLECTDIR'}) {
+	print STDERR "Invalid collection ($collection).\n";
+	return "";
+    }
+
+    # everything is ready to go
+    return $collection;
+}
+
+1;
Index: /main/tags/2.25/gsdl/perllib/webpageutil.pm
===================================================================
--- /main/tags/2.25/gsdl/perllib/webpageutil.pm	(revision 21064)
+++ /main/tags/2.25/gsdl/perllib/webpageutil.pm	(revision 21064)
@@ -0,0 +1,24 @@
+package webpageutil;
+
+use ghtml;
+
+sub error_location
+{
+    my ($args,$text) = @_;
+
+    &ghtml::urlsafe($text);
+    my $mess_url = "$args->{'httpbuild'}&bca=mess&head=_headerror_";
+    print "Location: $mess_url&mess=$text\n\n";
+}
+
+sub status_location
+{
+    my ($args,$text,$tmpname,$bc1finished) = @_;
+
+    &ghtml::urlsafe($text);    
+    my $mess_url = "$args->{'httpbuild'}&bca=buildstatus";
+    $mess_url .= "&bc1tmpfilename=$tmpname&bc1finished=$bc1finished";
+    print "Location: $mess_url&mess=$text\n\n";
+}
+
+1;
Index: /main/tags/2.25/gsdl/setup.bash
===================================================================
--- /main/tags/2.25/gsdl/setup.bash	(revision 21064)
+++ /main/tags/2.25/gsdl/setup.bash	(revision 21064)
@@ -0,0 +1,4 @@
+export GSDLHOME=`pwd`
+export GSDLOS=`uname -s | tr A-Z a-z`
+export PATH=$PATH:$GSDLHOME/bin/script:$GSDLHOME/bin/$GSDLOS
+export MANPATH=$MANPATH:$GSDLHOME/packages/mg/man
Index: /main/tags/2.25/gsdl/setup.csh
===================================================================
--- /main/tags/2.25/gsdl/setup.csh	(revision 21064)
+++ /main/tags/2.25/gsdl/setup.csh	(revision 21064)
@@ -0,0 +1,4 @@
+setenv GSDLHOME `pwd`
+setenv GSDLOS `uname -s | tr A-Z a-z`
+setenv PATH $PATH\:$GSDLHOME/bin/script\:$GSDLHOME/bin/$GSDLOS
+setenv MANPATH $MANPATH\:$GSDLHOME/packages/mg/man
Index: /main/tags/2.25/gsdl/src/checkis/checkis.cpp
===================================================================
--- /main/tags/2.25/gsdl/src/checkis/checkis.cpp	(revision 21064)
+++ /main/tags/2.25/gsdl/src/checkis/checkis.cpp	(revision 21064)
@@ -0,0 +1,67 @@
+#include <windows.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <memory.h>
+#pragma hdrstop
+
+int __stdcall WinMain(HANDLE Instance, HANDLE /*PrevInstance*/, LPSTR CmdLineStr, int /*CmdShow*/) {
+  HKEY hk1, hk2, hk3, hk4, hk5, lk;
+  char command[2048];
+  command[0] = '\0';
+  
+  // try to find the command to start the library
+  if (RegOpenKey(HKEY_LOCAL_MACHINE, "SOFTWARE", &hk1) == ERROR_SUCCESS) {
+    if (RegOpenKey(hk1, "Waikato University", &hk2) == ERROR_SUCCESS) {
+      if (RegOpenKey(hk2, "FAO", &hk3) == ERROR_SUCCESS) {
+	if (RegOpenKey(hk3, "1", &hk4) == ERROR_SUCCESS) {
+	  if (RegOpenKey(hk4, "1.00.000", &hk5) == ERROR_SUCCESS) {
+
+	    if (RegOpenKey(hk3, "1.00.000", &lk) == ERROR_SUCCESS) {
+	    
+	      // look for the command to start the browser
+	      DWORD dwIndex = 0;
+	      char key[256];
+	      key[0] = '\0';
+	      DWORD keysize = 256;
+	      DWORD type;
+	      DWORD comsize = 2048;
+	      while (RegEnumValue(lk, dwIndex, key, &keysize, NULL, &type, 
+				  (unsigned char *)command, &comsize) == ERROR_SUCCESS) {
+		// see if this is the right key
+		if (strcmp (key, "library") == 0) break;
+		else command[0] = '\0';
+	      
+		// prepare for next iteration
+		dwIndex++;
+		keysize = 256;
+		comsize = 2048;
+	      }
+	      RegCloseKey(lk);
+	    }
+	    RegCloseKey(hk5);
+	  }	   
+ 	  RegCloseKey(hk4);
+	}
+	RegCloseKey(hk3);
+      }
+      RegCloseKey(hk2);
+    }
+    RegCloseKey(hk1);
+  }
+  
+  if (strlen (command) == 0) { 
+    // not installed, try to run the setup program
+    WinExec ("setup.exe", SW_SHOW);
+  } else { 
+    // installed ask the user whether they want to run the library now
+    if (MessageBox (NULL, 
+		    "Would you like to run the FAO Library?",
+		    "Greenstone Digital Library",
+		    MB_YESNO) == IDYES) {
+      WinExec (command, SW_SHOW);
+    }
+  }
+  
+  return 0;
+}
Index: /main/tags/2.25/gsdl/src/colservr/GCC.mak
===================================================================
--- /main/tags/2.25/gsdl/src/colservr/GCC.mak	(revision 21064)
+++ /main/tags/2.25/gsdl/src/colservr/GCC.mak	(revision 21064)
@@ -0,0 +1,73 @@
+###########################################################################
+#
+# gcc win32 makefile -- src/colservr
+# A component of the Greenstone digital library software
+# from the New Zealand Digital Library Project at the
+# University of Waikato, New Zealand.
+#
+# Copyright (C) 2000  The 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.
+#
+###########################################################################
+
+
+AR = ar
+RANLIB = ranlib
+CC = g++
+DELETE = del
+
+o = .o
+/ = \\
+
+CPPFLAGS = -g -Wall
+DEFS = -D__WIN32__ -DGSDL_USE_IOS_H -DHAVE_CONFIG_H
+
+INCLUDES = -I"..$/..$/lib" -I"..$/recpt" -I"..$/..$/packages$/mg" \
+	   -I"..$/..$/packages$/mg$/lib" -I"..$/..$/packages$/mg$/src$/text" \
+           -I"..$/..$/packages$/wingdbm"
+
+COMPILE = $(CC) -c $(DEFS) $(INCLUDES) $(CPPFLAGS)
+LINK = $(CC) $(LDFLAGS) -o $@
+ 
+.SUFFIXES:
+.SUFFIXES: .c $o
+.c$o:
+	$(COMPILE) $<
+
+.SUFFIXES: .cpp $o
+.cpp$o:
+	$(COMPILE) $< 
+
+HEADERS = mgq.h mgsearch.h querycache.h queryinfo.h collectserver.h \
+          colservrconfig.h maptools.h filter.h source.h browsefilter.h \
+          queryfilter.h mggdbmsource.h phrasesearch.h phrasequeryfilter.h
+
+SOURCES = mgq.c mgsearch.cpp querycache.cpp queryinfo.cpp collectserver.cpp \
+          colservrconfig.cpp maptools.cpp filter.cpp source.cpp \
+          browsefilter.cpp queryfilter.cpp mggdbmsource.cpp phrasesearch.cpp \
+          phrasequeryfilter.cpp
+
+OBJECTS = mgq$o mgsearch$o querycache$o queryinfo$o collectserver$o \
+          colservrconfig$o maptools$o filter$o source$o browsefilter$o \
+          queryfilter$o mggdbmsource$o phrasesearch$o phrasequeryfilter$o
+
+all : $(OBJECTS)
+
+clean:
+	$(DELETE) *$o
+
+install:
Index: /main/tags/2.25/gsdl/src/colservr/Makefile.in
===================================================================
--- /main/tags/2.25/gsdl/src/colservr/Makefile.in	(revision 21064)
+++ /main/tags/2.25/gsdl/src/colservr/Makefile.in	(revision 21064)
@@ -0,0 +1,119 @@
+###########################################################################
+#
+# Makefile -- src/colservr
+# A component of the Greenstone digital library software
+# from the New Zealand Digital Library Project at the
+# University of Waikato, New Zealand.
+#
+# Copyright (C) 1999  The 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.
+#
+###########################################################################
+
+
+AR = ar
+CC = @CC@
+#CCFLAGS = @CFLAGS@ -Wall -Wunused -pedantic -W -Woverloaded-virtual
+CCFLAGS = @CFLAGS@
+
+USE_FASTCGI = @USE_FASTCGI@
+USE_MGPP = @USE_MGPP@
+ifneq ($(USE_FASTCGI), 1)
+DEFS = -DNZDL -DQUIET -DSHORT_SUFFIX -DPARADOCNUM -DGSDLSERVER @DEFS@
+
+CGI_INCLUDES = 
+
+else
+DEFS = -DNZDL -DQUIET -DSHORT_SUFFIX -DPARADOCNUM -DGSDLSERVER -DUSE_FASTCGI @DEFS@
+
+CGI_INCLUDES = -I../../packages/fcgi/include 
+endif
+
+ifneq ($(USE_MGPP), 1)
+MG_INCLUDES = -I../../packages/mg  -I../../packages/mg/lib \
+		-I../../packages/mg/src/text
+MG_HEADERS = mgq.h mgsearch.h mgqueryfilter.h 
+
+MG_SOURCES = mgq.c mgsearch.cpp mgqueryfilter.cpp 
+
+MG_OBJECTS = mgq.o mgsearch.o mgqueryfilter.o 
+
+else
+MG_INCLUDES = -I../mgpp/text -I../mgpp/lib 
+
+MG_HEADERS = mgppsearch.h mgppqueryfilter.h
+
+MG_SOURCES = mgppsearch.cpp mgppqueryfilter.cpp
+
+MG_OBJECTS = mgppsearch.o mgppqueryfilter.o
+
+endif
+
+INCLUDES = -I../.. -I../../lib -I ../recpt \
+		$(CGI_INCLUDES) $(MG_INCLUDES)
+
+RANLIB = @RANLIB@
+LDFLAGS = @LDFLAGS@
+LIBS = @LIBS@
+
+GSDLOS = @gsdlos@
+
+
+COMPILE = $(CC) -c $(CCFLAGS) $(DEFS) $(INCLUDES)
+LINK = $(CC) $(LDFLAGS) -o $@
+
+.SUFFIXES:
+.SUFFIXES: .c .o
+.c.o:
+	$(COMPILE) $<
+
+.SUFFIXES: .cpp .o
+.cpp.o:
+	$(COMPILE) $< 
+
+HEADERS = search.h  querycache.h queryinfo.h collectserver.h \
+          colservrconfig.h maptools.h filter.h source.h browsefilter.h \
+          queryfilter.h mggdbmsource.h phrasesearch.h phrasequeryfilter.h \
+	  $(MG_HEADERS)
+
+SOURCES = search.cpp querycache.cpp queryinfo.cpp collectserver.cpp \
+          colservrconfig.cpp maptools.cpp filter.cpp source.cpp \
+          browsefilter.cpp queryfilter.cpp mggdbmsource.cpp phrasesearch.cpp \
+          phrasequeryfilter.cpp \
+	  $(MG_SOURCES)
+
+OBJECTS = search.o querycache.o queryinfo.o collectserver.o \
+          colservrconfig.o maptools.o filter.o source.o browsefilter.o \
+          queryfilter.o mggdbmsource.o phrasesearch.o phrasequeryfilter.o \
+	  $(MG_OBJECTS)
+
+all : $(OBJECTS)
+
+distclean:
+	rm -f $(OBJECTS) Makefile mgppsearch.o mgppqueryfilter.o
+
+clean:
+	rm -f $(OBJECTS) mgppsearch.o mgppqueryfilter.o
+
+install:
+
+depend:
+	makedepend -Y -- $(DEFS) $(INCLUDES) $(CCFLAGS) -- $(SOURCES)
+
+
+
+
Index: /main/tags/2.25/gsdl/src/colservr/browsefilter.cpp
===================================================================
--- /main/tags/2.25/gsdl/src/colservr/browsefilter.cpp	(revision 21064)
+++ /main/tags/2.25/gsdl/src/colservr/browsefilter.cpp	(revision 21064)
@@ -0,0 +1,283 @@
+/**********************************************************************
+ *
+ * browsefilter.cpp -- 
+ * Copyright (C) 1999  The New Zealand Digital Library Project
+ *
+ * A component of the Greenstone digital library software
+ * from the New Zealand Digital Library Project at the
+ * University of Waikato, New Zealand.
+ *
+ * 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.
+ *
+ *********************************************************************/
+
+#include "browsefilter.h"
+#include "fileutil.h"
+#include "gsdltools.h"
+
+
+browsefilterclass::browsefilterclass () {
+  gdbmptr = NULL;
+
+  // -- onePerQuery StartResults   integer
+  FilterOption_t filtopt;
+  filtopt.name = "StartResults";
+  filtopt.type = FilterOption_t::integert;
+  filtopt.repeatable = FilterOption_t::onePerQuery;
+  filtopt.defaultValue = "1";
+  filtopt.validValues.push_back("1");
+  filtopt.validValues.push_back("10000");
+  filterOptions["StartResults"] = filtopt;
+
+  // -- onePerQuery EndResults     integer
+  filtopt.clear();
+  filtopt.name = "EndResults";
+  filtopt.type = FilterOption_t::integert;
+  filtopt.repeatable = FilterOption_t::onePerQuery;
+  filtopt.defaultValue = "-1";
+  filtopt.validValues.push_back("-1");
+  filtopt.validValues.push_back("10000");
+  filterOptions["EndResults"] = filtopt;
+
+  // -- onePerQuery ParentNode     string ("" will return the browsing available)
+  filtopt.clear();
+  filtopt.name = "ParentNode";
+  filtopt.type = FilterOption_t::stringt;
+  filtopt.repeatable = FilterOption_t::onePerQuery;
+  filtopt.defaultValue = "";
+  filterOptions["ParentNode"] = filtopt;
+}
+
+browsefilterclass::~browsefilterclass () {
+}
+
+bool browsefilterclass::init (ostream &logout) {
+  outconvertclass text_t2ascii;
+
+  if (!filterclass::init(logout)) return false;
+
+  // get the filename for the database and make sure it exists
+  gdbm_filename = filename_cat(collectdir,"index","text",collection);
+
+  if (littleEndian()) gdbm_filename += ".ldb";
+  else gdbm_filename += ".bdb";
+
+  if (!file_exists(gdbm_filename)) {
+    logout << text_t2ascii
+	   << "warning: gdbm database \"" //****
+	   << gdbm_filename << "\" does not exist\n\n";
+    //    return false; //****
+  }
+
+  return true;
+}
+
+void browsefilterclass::filter (const FilterRequest_t &request,
+				FilterResponse_t &response,
+				comerror_t &err, ostream &logout) {
+  int numDocs = 0;
+  outconvertclass text_t2ascii;
+
+  response.clear ();
+  err = noError;
+  if (gdbmptr == NULL) {
+    // most likely a configuration problem
+    logout << text_t2ascii 
+	   << "configuration error: browsefilter contains a null gdbmclass\n\n";
+    err = configurationError;
+    return;
+  }
+
+  // open the database
+  gdbmptr->setlogout(&logout);
+  if (!gdbmptr->opendatabase (gdbm_filename, GDBM_READER, 100, false)) {
+    // most likely a system problem (we have already checked that the
+    // gdbm database exists)
+    logout << text_t2ascii
+	   << "system problem: open on gdbm database \""
+	   << gdbm_filename << "\" failed\n\n";
+    err = systemProblem;
+    return;
+  }
+
+  // get the browse parameters
+  int startresults = filterOptions["StartResults"].defaultValue.getint();
+  int endresults = filterOptions["EndResults"].defaultValue.getint();
+  text_t parentnode = filterOptions["ParentNode"].defaultValue;
+  OptionValue_tarray::const_iterator options_here = request.filterOptions.begin();
+  OptionValue_tarray::const_iterator options_end = request.filterOptions.end();
+  while (options_here != options_end) {
+    if ((*options_here).name == "StartResults") 
+      startresults = (*options_here).value.getint();
+    else if ((*options_here).name == "EndResults")
+      endresults = (*options_here).value.getint();
+    else if ((*options_here).name == "ParentNode")
+      parentnode = (*options_here).value;
+    else {
+      logout << text_t2ascii
+	     << "warning: unknown browsefilter option \""
+	     << (*options_here).name
+	     << "\" ignored.\n\n";
+    }
+
+    options_here++;
+  }
+
+  infodbclass info;
+
+  // translate any ".fc", ".pr" etc. stuff in the parentnode
+  parentnode = gdbmptr->translate_OID (parentnode, info);
+
+  // adjust topmost browsing node
+  if (parentnode.empty()) parentnode = "browse";
+
+  // get the node
+  if ((request.filterResultOptions & FROID) ||
+      (request.filterResultOptions & FRmetadata)) {
+    if (!gdbmptr->getinfo(parentnode, info)) {
+      // didn't find the node
+      logout << text_t2ascii
+	     << "warning: lookup for node \"" << parentnode 
+	     << "\" failed for browsefilter.\n\n";
+    } else {
+      // found the node
+
+      // replace " with the parent node name and split the contains string
+      // into the result set
+      text_tarray resultset;
+      text_t tmptext;
+      text_t &contains = info["contains"];
+      text_t::iterator contains_here = contains.begin();
+      text_t::iterator contains_end = contains.end();
+      while (contains_here != contains_end) {
+	if (*contains_here == '"') tmptext += parentnode;
+	else if (*contains_here == ';') {
+	  if (!tmptext.empty()) resultset.push_back (tmptext);
+	  tmptext.clear();
+	} else tmptext.push_back(*contains_here);
+	
+	contains_here++;
+      }
+      // insert the last result in the set
+      if (!tmptext.empty()) resultset.push_back (tmptext);
+
+      text_tarray offset_resultset;
+      text_t &md_type = info["mdtype"];
+      if (!md_type.empty())
+	{
+	  text_t &md_offset = info["mdoffset"];
+	  if (!md_offset.empty())
+	    {
+	      text_t offsettext;
+
+	      text_t::iterator offset_here = md_offset.begin();
+	      text_t::iterator offset_end = md_offset.end();
+	      while (offset_here != offset_end) 
+		{
+		  if (*offset_here == ';')
+		    {
+		      if (offsettext.empty())
+			{
+			  offset_resultset.push_back ("0");
+			}
+		      else
+			{
+			  offset_resultset.push_back (offsettext);
+			}
+		      offsettext.clear();
+		    } 
+		  else 
+		    {
+		      offsettext.push_back(*offset_here);
+		    }
+		  
+		  offset_here++;
+		}
+	      // insert the last result in the set
+	      if (!offsettext.empty()) offset_resultset.push_back (offsettext);
+	    }
+	  else
+	    {
+	      // add 0 offset for each 'contains' entry
+	      text_tarray::iterator result_here = resultset.begin();
+	      text_tarray::iterator result_end = resultset.end();
+	      while (result_here != result_end) {
+		offset_resultset.push_back("0");
+		result_here++;
+	      }
+	    }
+
+	  // do an intersection with the input set
+	  if (!request.docSet.empty()) {
+
+	    text_tarray intersect_resultset;
+	    text_tarray intersect_offset_resultset;
+	    
+	    text_tarray::const_iterator resultset_here = resultset.begin();
+	    text_tarray::const_iterator resultset_end = resultset.end();
+	    text_tarray::const_iterator offset_resultset_here = offset_resultset.begin();
+	    
+	    while (resultset_here != resultset_end) {
+	      if (in_set (request.docSet, *resultset_here))
+		{
+		  intersect_resultset.push_back (*resultset_here);
+		  intersect_offset_resultset.push_back (*offset_resultset_here);
+		}
+	      resultset_here ++;
+	      offset_resultset_here ++;
+	    }
+	    resultset = intersect_resultset;
+	    offset_resultset = intersect_offset_resultset;
+	  }
+	}
+      else
+	{
+	  // do an intersection with the input set
+	  if (!request.docSet.empty()) {
+	    intersect (resultset, request.docSet);
+	  }
+	}
+
+      // create the response
+      numDocs = resultset.size();
+      int resultnum = 1;
+      ResultDocInfo_t resultdoc;
+      text_tarray::iterator result_here = resultset.begin();
+      text_tarray::iterator result_end = resultset.end();
+      text_tarray::iterator offset_result_here = offset_resultset.begin();
+
+      while (result_here != result_end) {
+	// if endresults is -1 get all results
+	if ((endresults != -1) && (resultnum > endresults)) break;
+	if (resultnum >= startresults) {
+	  resultdoc.OID = (*result_here);
+	  if (!md_type.empty())
+	    {
+	      resultdoc.classifier_metadata_type = md_type;
+	      resultdoc.classifier_metadata_offset = offset_result_here->getint();
+	    }
+	  response.docInfo.push_back(resultdoc);
+	}
+
+	resultnum++;
+	result_here++;
+	if (!md_type.empty()) offset_result_here++;
+      }
+    }
+  }
+
+  response.numDocs = numDocs;
+  response.isApprox = Exact;
+}
Index: /main/tags/2.25/gsdl/src/colservr/browsefilter.h
===================================================================
--- /main/tags/2.25/gsdl/src/colservr/browsefilter.h	(revision 21064)
+++ /main/tags/2.25/gsdl/src/colservr/browsefilter.h	(revision 21064)
@@ -0,0 +1,59 @@
+/**********************************************************************
+ *
+ * browsefilter.h -- 
+ * Copyright (C) 1999  The New Zealand Digital Library Project
+ *
+ * A component of the Greenstone digital library software
+ * from the New Zealand Digital Library Project at the
+ * University of Waikato, New Zealand.
+ *
+ * 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.
+ *
+ *********************************************************************/
+
+
+#ifndef BROWSEFILTER_H
+#define BROWSEFILTER_H
+
+
+#include "gsdlconf.h"
+#include "text_t.h"
+#include "comtypes.h"
+#include "filter.h"
+#include "infodbclass.h"
+
+
+class browsefilterclass : public filterclass {
+protected:
+  text_t gdbm_filename;
+  gdbmclass *gdbmptr;
+
+public:
+  browsefilterclass ();
+  virtual ~browsefilterclass ();
+
+  // the gdbmptr remains the responsability of the calling code and
+  // should be destroyed after this browsefilter is destroyed
+  void set_gdbmptr (gdbmclass *thegdbmptr) {gdbmptr = thegdbmptr;}
+
+  bool init (ostream &logout);
+  text_t get_filter_name () {return "BrowseFilter";}
+  void filter (const FilterRequest_t &request,
+	       FilterResponse_t &response,
+	       comerror_t &err, ostream &logout);
+};
+
+
+#endif
Index: /main/tags/2.25/gsdl/src/colservr/collectserver.cpp
===================================================================
--- /main/tags/2.25/gsdl/src/colservr/collectserver.cpp	(revision 21064)
+++ /main/tags/2.25/gsdl/src/colservr/collectserver.cpp	(revision 21064)
@@ -0,0 +1,301 @@
+
+/**********************************************************************
+ *
+ * collectserver.cpp -- 
+ * Copyright (C) 1999  The New Zealand Digital Library Project
+ *
+ * A component of the Greenstone digital library software
+ * from the New Zealand Digital Library Project at the
+ * University of Waikato, New Zealand.
+ *
+ * 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.
+ *
+ *********************************************************************/
+
+#include "collectserver.h"
+#include "infodbclass.h"
+#include "OIDtools.h"
+#include <assert.h>
+
+
+collectserver::collectserver () {
+  configinfo.collection = "null";
+}
+
+collectserver::~collectserver () {
+}
+
+// configure should be called for each line in the
+// configuration files to configure the collection server and everything
+// it contains. The configuration should take place just before initialisation.
+void collectserver::configure (const text_t &key, const text_tarray &cfgline) {
+  if (cfgline.size() >= 1) {
+    const text_t &value = cfgline[0];
+    if (key == "gsdlhome") configinfo.gsdlhome = value;
+    else if (key == "gdbmhome") configinfo.gdbmhome = value;
+    else if (key == "collection") {
+      configinfo.collection = value;
+      collectinfo.shortInfo.name = value;
+    } else if (key == "collectdir") configinfo.collectdir = value;
+    else if (key == "host") collectinfo.shortInfo.host = value;
+    else if (key == "port") collectinfo.shortInfo.port = value.getint();
+    else if (key == "public") {
+      if (value == "true") collectinfo.isPublic = true;
+      else collectinfo.isPublic = false;
+    } else if (key == "beta") {
+      if (value == "true") collectinfo.isBeta = true;
+      else collectinfo.isBeta = false;
+    } else if (key == "ccscols") collectinfo.ccsCols = cfgline;
+    else if (key == "builddate") collectinfo.buildDate = value.getint();
+    else if (key == "languages") collectinfo.languages = cfgline;
+    else if (key == "numdocs") collectinfo.numDocs = value.getint();
+    else if (key == "numsections") collectinfo.numSections = value.getint();
+    else if (key == "numwords") collectinfo.numWords = value.getint();
+    else if (key == "numbytes") collectinfo.numBytes = value.getint();
+    else if (key == "collectionmeta" && cfgline.size() == 2)
+      collectinfo.collectionmeta[cfgline[0]] = cfgline[1];
+    else if (key == "format" && cfgline.size() == 2)
+      collectinfo.format[cfgline[0]] = cfgline[1];
+    else if (key == "building" && cfgline.size() == 2)
+      collectinfo.building[cfgline[0]] = cfgline[1];
+    else if (key == "receptionist") collectinfo.receptionist = value;
+    else if (key == "buildtype") collectinfo.buildType = value;
+  }
+
+  // configure the filters
+  filtermapclass::iterator filter_here = filters.begin();
+  filtermapclass::iterator filter_end = filters.end();
+  while (filter_here != filter_end) {
+    assert ((*filter_here).second.f != NULL);
+    if ((*filter_here).second.f != NULL) 
+      (*filter_here).second.f->configure(key, cfgline);
+
+    filter_here++;
+  }
+
+  // configure the sources
+  sourcelistclass::iterator source_here = sources.begin();
+  sourcelistclass::iterator source_end = sources.end();
+  while (source_here != source_end) {
+    assert ((*source_here).s != NULL);
+    if ((*source_here).s != NULL)
+      (*source_here).s->configure(key, cfgline);
+    
+    source_here++;
+  }
+}
+
+void collectserver::configure (const text_t &key, const text_t &value) {
+  text_tarray cfgline;
+  cfgline.push_back (value);
+  configure(key, cfgline);
+}
+
+
+bool collectserver::init (ostream &logout) {
+  // init the filters
+  filtermapclass::iterator filter_here = filters.begin();
+  filtermapclass::iterator filter_end = filters.end();
+  while (filter_here != filter_end) {
+    assert ((*filter_here).second.f != NULL);
+    if (((*filter_here).second.f != NULL) &&
+	!(*filter_here).second.f->init(logout)) return false;
+    
+    filter_here++;
+  }
+
+  // init the sources
+  sourcelistclass::iterator source_here = sources.begin();
+  sourcelistclass::iterator source_end = sources.end();
+  while (source_here != source_end) {
+    assert ((*source_here).s != NULL);
+    if (((*source_here).s != NULL) &&
+	!(*source_here).s->init(logout)) return false;
+    
+    source_here++;
+  }
+
+  return true;
+}
+
+
+void collectserver::get_collectinfo (ColInfoResponse_t &reponse,
+		      comerror_t &err, ostream &/*logout*/) {
+  reponse = collectinfo; 
+  err = noError;
+}
+
+void collectserver::get_filterinfo (InfoFiltersResponse_t &response,
+				    comerror_t &err, ostream &/*logout*/) {
+  response.clear ();
+
+  // get a list of filter names
+  filtermapclass::iterator filter_here = filters.begin();
+  filtermapclass::iterator filter_end = filters.end();
+  while (filter_here != filter_end) {
+    response.filterNames.insert ((*filter_here).first);
+    filter_here++;
+  }
+
+  err = noError;
+}
+
+void collectserver::get_filteroptions (const InfoFilterOptionsRequest_t &request,
+				       InfoFilterOptionsResponse_t &response, 
+				       comerror_t &err, ostream &logout) {
+  outconvertclass text_t2ascii;
+
+  filterclass *thisfilter = filters.getfilter(request.filterName);
+  if (thisfilter != NULL) {
+    thisfilter->get_filteroptions (response, err, logout);
+  } else {
+    response.clear ();
+    err = protocolError;
+    logout << text_t2ascii << "Protocol Error: filter options requested for non-existent\n"
+	   << "filter \"" << request.filterName << "\".\n\n";
+  }
+}
+
+void collectserver::filter (FilterRequest_t &request,
+			    FilterResponse_t &response,
+			    comerror_t &err, ostream &logout) {
+  outconvertclass text_t2ascii;
+
+  // translate any ".fc", ".pr" etc. stuff in the docSet
+  text_t translatedOID;
+  text_tarray translatedOIDs;
+  text_tarray::iterator doc_here = request.docSet.begin();
+  text_tarray::iterator doc_end = request.docSet.end();
+  while (doc_here != doc_end) {
+    if (needs_translating (*doc_here)) {
+      sourcelistclass::iterator source_here = sources.begin();
+      sourcelistclass::iterator source_end = sources.end();
+      while (source_here != source_end) {
+	assert ((*source_here).s != NULL);
+	if (((*source_here).s != NULL) &&
+	    ((*source_here).s->translate_OID (*doc_here, translatedOID, err, logout))) {
+	  if (err != noError) return;
+	  break;
+	}
+	source_here++;
+      }
+      translatedOIDs.push_back (translatedOID);
+    } else {
+      translatedOIDs.push_back (*doc_here);
+    }
+    doc_here ++;
+  }
+  request.docSet = translatedOIDs;
+
+  response.clear();
+
+  filterclass *thisfilter = filters.getfilter(request.filterName);
+  if (thisfilter != NULL) {
+    // filter the data
+    thisfilter->filter (request, response, err, logout);
+
+    // fill in the metadata for each of the OIDs (if it is requested)
+    if (request.filterResultOptions & FRmetadata) {
+      bool processed = false;
+      ResultDocInfo_tarray::iterator resultdoc_here = response.docInfo.begin();
+      ResultDocInfo_tarray::iterator resultdoc_end = response.docInfo.end();
+      while (resultdoc_here != resultdoc_end) {
+	// try each of the sources in turn
+	sourcelistclass::iterator source_here = sources.begin();
+	sourcelistclass::iterator source_end = sources.end();
+	while (source_here != source_end) {
+	  assert ((*source_here).s != NULL);
+	  if (((*source_here).s != NULL) &&
+	      ((*source_here).s->get_metadata(request.requestParams, request.refParams,
+					      request.getParents, request.fields, 
+					      (*resultdoc_here).OID, (*resultdoc_here).metadata, 
+					      err, logout))) {
+	    if (err != noError) return;
+	    processed = true;
+	    break;
+	  }
+	  source_here++;
+	}
+	if (!processed) {
+	  err = protocolError;
+	  return;
+	}
+	resultdoc_here++;
+      }
+    }
+    
+  } else {
+    response.clear ();
+    err = protocolError;
+    logout << text_t2ascii << "Protocol Error: filter options requested for non-existent\n"
+	   << "filter \"" << request.filterName << "\".\n\n";
+  }
+  
+  err = noError;
+}
+
+void collectserver::get_document (const DocumentRequest_t &request,
+				  DocumentResponse_t &response,
+				  comerror_t &err, ostream &logout) {
+
+  sourcelistclass::iterator source_here = sources.begin();
+  sourcelistclass::iterator source_end = sources.end();
+  while (source_here != source_end) {
+    assert ((*source_here).s != NULL);
+    if (((*source_here).s != NULL) &&
+	((*source_here).s->get_document (request.OID, response.doc, err, logout))) {
+      if (err != noError) return;
+      break;
+    }
+    source_here++;
+  }
+}
+
+
+bool operator==(const collectserverptr &x, const collectserverptr &y) {
+  return (x.c == y.c);
+}
+
+bool operator<(const collectserverptr &x, const collectserverptr &y) {
+  return (x.c < y.c);
+}
+
+
+// thecollectserver remains the property of the calling code but
+// should not be deleted until it is removed from this list.
+void collectservermapclass::addcollectserver (collectserver *thecollectserver) {
+  // can't add a null collection server
+  assert (thecollectserver != NULL);
+  if (thecollectserver == NULL) return;
+  
+  // can't add an collection server with no collection name
+  assert (!(thecollectserver->get_collection_name()).empty());
+  if ((thecollectserver->get_collection_name()).empty()) return;
+
+  collectserverptr cptr;
+  cptr.c = thecollectserver;
+  collectserverptrs[thecollectserver->get_collection_name()] = cptr;
+}
+
+// getcollectserver will return NULL if the collectserver could not be found
+collectserver *collectservermapclass::getcollectserver (const text_t &collection) {
+  // can't find a collection with no name
+  if (collection.empty()) return NULL;
+
+  iterator here = collectserverptrs.find (collection);
+  if (here == collectserverptrs.end()) return NULL;
+  
+  return (*here).second.c;
+}
Index: /main/tags/2.25/gsdl/src/colservr/collectserver.h
===================================================================
--- /main/tags/2.25/gsdl/src/colservr/collectserver.h	(revision 21064)
+++ /main/tags/2.25/gsdl/src/colservr/collectserver.h	(revision 21064)
@@ -0,0 +1,183 @@
+/**********************************************************************
+ *
+ * collectserver.h -- 
+ * Copyright (C) 1999  The New Zealand Digital Library Project
+ *
+ * A component of the Greenstone digital library software
+ * from the New Zealand Digital Library Project at the
+ * University of Waikato, New Zealand.
+ *
+ * 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.
+ *
+ *********************************************************************/
+
+
+#ifndef COLLECTSERVER_H
+#define COLLECTSERVER_H
+
+#include "gsdlconf.h"
+#include "text_t.h"
+#include "comtypes.h"
+#include "filter.h"
+#include "source.h"
+#include "cfgread.h"
+
+#if defined(GSDL_USE_OBJECTSPACE)
+#  include <ospace\std\iostream>
+#elif defined(GSDL_USE_IOS_H)
+#  include <iostream.h>
+#else
+#  include <iostream>
+#endif
+
+#if defined(GSDL_USE_OBJECTSPACE)
+#  include <ospace\std\map>
+#elif defined(GSDL_USE_STL_H)
+#  include <map.h>
+#else
+#  include <map>
+#endif
+
+
+struct colservrconf {
+  text_t gsdlhome;
+  text_t gdbmhome;
+  text_t collection;
+  text_t collectdir;
+};
+
+
+class collectserver {
+protected:
+  colservrconf configinfo;
+  ColInfoResponse_t collectinfo;
+
+  filtermapclass filters;
+  sourcelistclass sources;
+
+public:
+  collectserver ();
+  virtual ~collectserver ();
+
+  // add_filter makes another filter available to the collection server
+  // the filter remains the property of the calling code and that
+  // code should destroy the filter after the collection server has been
+  // destroyed.
+  void add_filter (filterclass *thefilter) {filters.addfilter(thefilter);}
+  filtermapclass *get_filtermap_ptr () {return &filters;}
+
+  // add_source makes another source available to the collection server
+  // the source remains the property of the calling code and that
+  // code should destroy the source after the collection server has been
+  // destroyed.
+  void add_source (sourceclass *thesource) {sources.addsource(thesource);}
+  sourcelistclass *get_sourcelist_ptr () {return &sources;}
+
+  // configure should be called for each line in the
+  // configuration files to configure the collection server and everything
+  // it contains. The configuration should take place just before initialisation.
+  virtual void configure (const text_t &key, const text_tarray &cfgline);
+  void configure (const text_t &key, const text_t &value);
+  const colservrconf &get_configinfo () {return configinfo;}
+  text_t get_collection_name () {return configinfo.collection;}
+
+  // init should be called after the collection name has been set and
+  // all initialisation is done. init returns true if the initialisation
+  // was successful, if false is returned then no other functions
+  // should be called (without producing meaningless output).
+  virtual bool init (ostream &logout);
+
+  void get_collectinfo (ColInfoResponse_t &reponse,
+			comerror_t &err, ostream &logout);
+
+  virtual void get_filterinfo (InfoFiltersResponse_t &response,
+			       comerror_t &err, ostream &logout);
+
+  virtual void get_filteroptions (const InfoFilterOptionsRequest_t &request,
+				  InfoFilterOptionsResponse_t &response, 
+				  comerror_t &err, ostream &logout);
+
+  virtual void filter (FilterRequest_t &request,
+		       FilterResponse_t &response,
+		       comerror_t &err, ostream &logout);
+
+
+  virtual void get_document (const DocumentRequest_t &request,
+			     DocumentResponse_t &response,
+			     comerror_t &err, ostream &logout);
+
+};
+
+
+// The collectserverptr function does not 'own' the collectserver. The
+// collectserver should be deleted by the code which created it.
+class collectserverptr {
+public:
+  collectserver *c;
+
+  collectserverptr () {c=NULL;}
+  ~collectserverptr () {}
+};
+
+bool operator==(const collectserverptr &x, const collectserverptr &y);
+bool operator<(const collectserverptr &x, const collectserverptr &y);
+
+typedef map<text_t, collectserverptr, lttext_t> collectserverptrmap;
+
+// contains a list of collectservers indexed by their name
+class collectservermapclass {
+protected:
+  collectserverptrmap collectserverptrs;
+
+public:
+  // type support for collectserverptrmap
+  typedef collectserverptrmap::iterator iterator;
+  typedef collectserverptrmap::const_iterator const_iterator;
+  typedef collectserverptrmap::reference reference;
+  typedef collectserverptrmap::const_reference const_reference;
+  typedef collectserverptrmap::size_type size_type;
+
+  typedef collectserverptrmap::difference_type difference_type;
+  typedef collectserverptrmap::const_reverse_iterator const_reverse_iterator;
+  typedef collectserverptrmap::reverse_iterator reverse_iterator;
+  
+  // basic container support
+  iterator begin () {return collectserverptrs.begin();}
+  const_iterator begin () const {return collectserverptrs.begin();}
+  iterator end () {return collectserverptrs.end();}
+  const_iterator end () const {return collectserverptrs.end();}
+
+  void erase(iterator pos) {collectserverptrs.erase(pos);}
+  void erase(iterator first, iterator last) {collectserverptrs.erase(first, last);}
+  collectservermapclass &operator=(const collectservermapclass &x) 
+    {collectserverptrs=x.collectserverptrs;return *this;}
+
+  bool empty () const {return collectserverptrs.empty();}
+  size_type size() const {return collectserverptrs.size();}
+
+
+  // added functionality
+  void clear () {collectserverptrs.erase(collectserverptrs.begin(),collectserverptrs.end());}
+
+  // thecollectserver remains the property of the calling code but
+  // should not be deleted until it is removed from this list.
+  void addcollectserver (collectserver *thecollectserver);
+
+  // getcollectserver will return NULL if the collectserver could not be found
+  collectserver *getcollectserver (const text_t &collection);
+};
+
+
+#endif
Index: /main/tags/2.25/gsdl/src/colservr/colservrconfig.cpp
===================================================================
--- /main/tags/2.25/gsdl/src/colservr/colservrconfig.cpp	(revision 21064)
+++ /main/tags/2.25/gsdl/src/colservr/colservrconfig.cpp	(revision 21064)
@@ -0,0 +1,114 @@
+/**********************************************************************
+ *
+ * colservrconfig.cpp -- 
+ * Copyright (C) 1999  The New Zealand Digital Library Project
+ *
+ * A component of the Greenstone digital library software
+ * from the New Zealand Digital Library Project at the
+ * University of Waikato, New Zealand.
+ *
+ * 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.
+ *
+ *********************************************************************/
+
+#include "colservrconfig.h"
+#include "fileutil.h"
+#include "cfgread.h"
+
+
+#if defined(GSDL_USE_OBJECTSPACE)
+#  include <ospace/std/iostream>
+#  include <ospace/std/fstream>
+#elif defined(GSDL_USE_IOS_H)
+#  include <iostream.h>
+#  include <fstream.h>
+#else
+#  include <iostream>
+#  include <fstream>
+#endif
+
+// collect_cfg_read reads collect.cfg returning true on success.
+bool collect_cfg_read (collectserver &cserver, const text_t &gsdlhome,
+		       const text_t &collection) {
+  text_t filename = filename_cat (gsdlhome, "collect");
+  filename = filename_cat (filename, collection);
+  filename = filename_cat (filename, "etc");
+  filename = filename_cat (filename, "collect.cfg");
+  if (!file_exists (filename)) {
+    filename = filename_cat (gsdlhome, "etc");
+    filename = filename_cat (filename, "collect.cfg");
+    if (!file_exists (filename)) return false;
+  }
+
+  // read in the collection configuration file
+  text_t key;
+  text_tarray cfgline;
+  char *cstr = filename.getcstr();
+  ifstream confin (cstr);
+  delete cstr;
+
+  if (confin) {
+    while (read_cfg_line(confin, cfgline) >= 0) {
+      if (cfgline.size () >= 2) {
+	key = cfgline[0];
+	cfgline.erase(cfgline.begin());
+
+	// configure the collection server
+	cserver.configure (key, cfgline);
+      }
+    }
+    confin.close ();
+    return true;
+  }
+  return false;
+}
+
+
+// build_cfg_read reads build.cfg and returns true on success.
+bool build_cfg_read (collectserver &cserver, const text_t &gsdlhome,
+		     const text_t &collection) {
+  text_t filename = filename_cat (gsdlhome, "collect");
+  filename = filename_cat (filename, collection);
+  filename = filename_cat (filename, "index");
+
+  filename = filename_cat (filename, "build.cfg");
+  if (!file_exists (filename)) {
+    filename = filename_cat (gsdlhome, "index");
+    filename = filename_cat (filename, "build.cfg");
+    if (!file_exists (filename)) return false;
+  }
+
+  // read in the build configuration file
+  text_t key;
+  text_tarray cfgline;
+  char *cstr = filename.getcstr();
+  ifstream confin (cstr);
+  delete cstr;
+
+  if (confin) {
+    while (read_cfg_line(confin, cfgline) >= 0) {
+      if (cfgline.size () >= 2) {
+	key = cfgline[0];
+	cfgline.erase(cfgline.begin());
+
+	// configure the collection server
+	cserver.configure (key, cfgline);
+      }
+    }
+    confin.close ();
+    return true;
+  }
+  return false;
+}
Index: /main/tags/2.25/gsdl/src/colservr/colservrconfig.h
===================================================================
--- /main/tags/2.25/gsdl/src/colservr/colservrconfig.h	(revision 21064)
+++ /main/tags/2.25/gsdl/src/colservr/colservrconfig.h	(revision 21064)
@@ -0,0 +1,45 @@
+/**********************************************************************
+ *
+ * colservrconfig.h -- 
+ * Copyright (C) 1999  The New Zealand Digital Library Project
+ *
+ * A component of the Greenstone digital library software
+ * from the New Zealand Digital Library Project at the
+ * University of Waikato, New Zealand.
+ *
+ * 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.
+ *
+ *********************************************************************/
+
+
+#ifndef COLSERVRCONFIG_H
+#define COLSERVRCONFIG_H
+
+
+#include "gsdlconf.h"
+#include "text_t.h"
+#include "collectserver.h"
+
+
+// collect_cfg_read reads collect.cfg returning true on success.
+bool collect_cfg_read (collectserver &cserver, const text_t &gsdlhome,
+		       const text_t &collection);
+
+// build_cfg_read reads build.cfg and returns true on success.
+bool build_cfg_read (collectserver &cserver, const text_t &gsdlhome,
+		     const text_t &collection);
+
+
+#endif
Index: /main/tags/2.25/gsdl/src/colservr/filter.cpp
===================================================================
--- /main/tags/2.25/gsdl/src/colservr/filter.cpp	(revision 21064)
+++ /main/tags/2.25/gsdl/src/colservr/filter.cpp	(revision 21064)
@@ -0,0 +1,308 @@
+/**********************************************************************
+ *
+ * filter.cpp -- 
+ * Copyright (C) 1999  The New Zealand Digital Library Project
+ *
+ * A component of the Greenstone digital library software
+ * from the New Zealand Digital Library Project at the
+ * University of Waikato, New Zealand.
+ *
+ * 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.
+ *
+ *********************************************************************/
+
+#include "filter.h"
+#include "fileutil.h"
+#include <assert.h>
+
+
+// default constructor does nothing
+filterclass::filterclass () {
+}
+
+// default destructor does nothing
+filterclass::~filterclass () {
+}
+
+// configure should be called once for each configuration line
+// default configures the default filter options
+void filterclass::configure (const text_t &key, const text_tarray &cfgline) {
+  if (cfgline.size() >= 1) {
+    const text_t &value = cfgline[0];
+
+    if (key == "collection") collection = value;
+    else if (key == "collectdir") collectdir = value;
+    else if (key == "gsdlhome") gsdlhome = value;
+    else if ((key == "filteroptdefault") && (cfgline.size() == 2)) {
+      // see if this filter has an option with this name
+      FilterOption_tmap::iterator thisfilteroption = 
+	filterOptions.find(cfgline[0]);
+      if (thisfilteroption != filterOptions.end())
+	(*thisfilteroption).second.defaultValue = cfgline[1];
+    }
+  }
+}
+
+// init should be called after all the configuration is done but
+// before any other methods are called
+// default checks all the filter option defaults
+bool filterclass::init (ostream &/*logout*/) {
+  // check all the filter defaults
+  FilterOption_tmap::iterator filteroption_here = filterOptions.begin();
+  FilterOption_tmap::iterator filteroption_end = filterOptions.end();
+  while (filteroption_here != filteroption_end) {
+    (*filteroption_here).second.check_defaultValue ();
+    
+    filteroption_here++;
+  }
+
+  // get the collection directory name
+  if (collectdir.empty()) {
+    collectdir = filename_cat (gsdlhome, "collect", collection);
+  }
+  
+  return true;
+}
+
+// returns the name of this filter
+// default returns "NullFilter"
+text_t filterclass::get_filter_name () {
+  return "NullFilter";
+}
+
+// returns the current filter options
+void filterclass::get_filteroptions (InfoFilterOptionsResponse_t &response,
+				     comerror_t &err, ostream &/*logout*/) {
+  response.clear();
+  response.filterOptions = filterOptions;
+  err = noError;
+}
+
+// default returns nothing
+void filterclass::filter (const FilterRequest_t &request,
+			  FilterResponse_t &response,
+			  comerror_t &err, ostream &/*logout*/) {
+  ResultDocInfo_t resultdoc;
+
+  response.clear();
+
+  if ((request.filterResultOptions & FROID) ||
+      (request.filterResultOptions & FRmetadata)) {
+    // copy the OIDs from the request to the response
+    text_tarray::const_iterator here = request.docSet.begin();
+    text_tarray::const_iterator end = request.docSet.end();
+    while (here != end) {
+      resultdoc.OID = (*here);
+      response.docInfo.push_back(resultdoc);
+
+      here++;
+    }
+  }
+
+  response.numDocs = response.docInfo.size();
+  response.isApprox = Exact;
+  err = noError;
+}
+
+
+bool operator==(const filterptr &x, const filterptr &y) {
+  return (x.f == y.f);
+}
+
+bool operator<(const filterptr &x, const filterptr &y) {
+  return (x.f < y.f);
+}
+
+
+// thefilter remains the property of the calling code but
+// should not be deleted until it is removed from this list.
+void filtermapclass::addfilter (filterclass *thefilter) {
+  // can't add a null filter
+  assert (thefilter != NULL);
+  if (thefilter == NULL) return;
+  
+  // can't add an filter with no name
+  assert (!(thefilter->get_filter_name()).empty());
+  if ((thefilter->get_filter_name()).empty()) return;
+
+  filterptr fptr;
+  fptr.f = thefilter;
+  filterptrs[thefilter->get_filter_name()] = fptr;
+}
+
+// getfilter will return NULL if the filter could not be found
+filterclass *filtermapclass::getfilter (const text_t &key) {
+  // can't find an filter with no name
+  assert (!key.empty());
+  if (key.empty()) return NULL;
+
+  iterator here = filterptrs.find (key);
+  if (here == filterptrs.end()) return NULL;
+  
+  return (*here).second.f;
+}
+
+
+
+
+// some useful functions for dealing with document sets
+
+// returns -1 if t1 is a child of t2
+// returns 0  if t1 and t2 are not parent-child related
+// returns 1  if t1 is a parent of t2
+int child_compare (const text_t &t1, const text_t &t2) {
+  text_t::const_iterator t1_here = t1.begin();
+  text_t::const_iterator t1_end = t1.end();
+  text_t::const_iterator t2_here = t2.begin();
+  text_t::const_iterator t2_end = t2.end();
+
+  while ((t1_here != t1_end) && (t2_here != t2_end)) {
+    if (*t1_here != *t2_here) return 0; // unrelated
+    t1_here++;
+    t2_here++;
+  }
+
+  if ((t1_here == t1_end) && (t2_here == t2_end)) return 0; // equal
+  if (t1_here != t1_end) {
+    if (*t1_here == '.') return -1; // t1 is child
+    else return 0; // unrelated
+  }
+
+  if (t2_here != t2_end) {
+    if (*t2_here == '.') return 1; // t2 is child
+    else return 0; // unrelated
+  }
+
+  return 0; // shouldn't get here...
+}
+
+// intersect places the result in set1
+void intersect (text_tset &set1, const text_tset &set2) {
+  text_tset resultset;
+  int childcomp = 0;
+
+  text_tset::const_iterator set1_here = set1.begin();
+  text_tset::const_iterator set1_end = set1.end();
+  text_tset::const_iterator set2_here = set2.begin();
+  text_tset::const_iterator set2_end = set2.end();
+  while ((set1_here != set1_end) && (set2_here != set2_end)) {
+    if (*set1_here == *set2_here) {
+      // equal
+      resultset.insert (*set1_here);
+      set1_here++;
+      set2_here++;
+
+    } else if ((childcomp=child_compare(*set1_here, *set2_here)) != 0) {
+      if (childcomp < 0) {
+	// set1_here is child
+	resultset.insert (*set1_here);
+	set1_here++;
+      } else {
+	// set2_here is child
+	resultset.insert (*set2_here);
+	set2_here++;
+      }
+
+    } else if (*set1_here < *set2_here) {
+      // set1 is less
+      set1_here++;
+
+    } else {
+      // set2 is less
+      set2_here++;
+    }
+  }
+
+  set1 = resultset;
+}
+
+void intersect (text_tarray &set1, const text_tset &set2) {
+  text_tarray resultset;
+
+  text_tarray::const_iterator set1_here = set1.begin();
+  text_tarray::const_iterator set1_end = set1.end();
+
+  while (set1_here != set1_end) {
+    if (in_set (set2, *set1_here))
+      resultset.push_back (*set1_here);
+    set1_here ++;
+  }
+  set1 = resultset;
+}
+
+void intersect (text_tarray &set1, const text_tarray &set2) {
+  text_tarray resultset;
+
+  text_tarray::const_iterator set1_here = set1.begin();
+  text_tarray::const_iterator set1_end = set1.end();
+
+  while (set1_here != set1_end) {
+    if (in_set (set2, *set1_here))
+      resultset.push_back (*set1_here);
+    set1_here ++;
+  }
+  set1 = resultset;
+}
+
+// tests to see if el is in set
+bool in_set (const text_tset &set1, const text_t &el) {
+  text_t::const_iterator here = el.begin();
+  text_t::const_iterator end = el.begin();
+  text_t tryel, tryel_add;
+  bool first = true;
+
+  // the element is in the set if any of its parents are
+  // in the set
+  do {
+    // get next possible element to try
+    here = getdelimitstr (here, end, '.', tryel_add);
+    if (!first) tryel += ".";
+    first = false;
+    tryel += tryel_add;
+
+    // see if this element is in the set
+    if (set1.find(tryel) != set1.end()) return true;
+  } while (here != end);
+
+  return false;
+}
+
+bool in_set (const text_tarray &set1, const text_t &el) {
+  text_t::const_iterator here = el.begin();
+  text_t::const_iterator end = el.begin();
+  text_t tryel, tryel_add;
+  bool first = true;
+
+  // the element is in the set if any of its parents are
+  // in the set
+  do {
+    // get next possible element to try
+    here = getdelimitstr (here, end, '.', tryel_add);
+    if (!first) tryel += ".";
+    first = false;
+    tryel += tryel_add;
+
+    // see if this element is in the set
+    text_tarray::const_iterator here = set1.begin();
+    text_tarray::const_iterator end = set1.end();
+    while (here != end) {
+      if (*here == tryel) break;
+      here ++;
+    }
+    if (here != end) return true;
+  } while (here != end);
+
+  return false;
+}
Index: /main/tags/2.25/gsdl/src/colservr/filter.h
===================================================================
--- /main/tags/2.25/gsdl/src/colservr/filter.h	(revision 21064)
+++ /main/tags/2.25/gsdl/src/colservr/filter.h	(revision 21064)
@@ -0,0 +1,140 @@
+/**********************************************************************
+ *
+ * filter.h -- 
+ * Copyright (C) 1999  The New Zealand Digital Library Project
+ *
+ * A component of the Greenstone digital library software
+ * from the New Zealand Digital Library Project at the
+ * University of Waikato, New Zealand.
+ *
+ * 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.
+ *
+ *********************************************************************/
+
+
+#ifndef FILTER_H
+#define FILTER_H
+
+#include "gsdlconf.h"
+#include "text_t.h"
+#include "comtypes.h"
+
+
+class filterclass {
+protected:
+  text_t gsdlhome;
+  text_t collection;
+  text_t collectdir;
+
+  FilterOption_tmap filterOptions;
+
+public:
+  filterclass ();
+  virtual ~filterclass ();
+
+  // configure should be called once for each configuration line
+  // default configures the default filter options
+  virtual void configure (const text_t &key, const text_tarray &cfgline);
+
+  // init should be called after all the configuration is done but
+  // before any other methods are called
+  // default checks all the filter option defaults
+  virtual bool init (ostream &logout);
+
+  // returns the name of this filter
+  virtual text_t get_filter_name ();
+
+  // returns the current filter options
+  virtual void get_filteroptions (InfoFilterOptionsResponse_t &response,
+				  comerror_t &err, ostream &logout);
+
+  virtual void filter (const FilterRequest_t &request,
+		       FilterResponse_t &response,
+		       comerror_t &err, ostream &logout);
+};
+
+
+// The filterptr class does not 'own' the filter. The 
+// filter should be deleted by the code which created it.
+class filterptr {
+public:
+  filterclass *f;
+
+  filterptr () {f=NULL;}
+  ~filterptr () {}
+};
+
+bool operator==(const filterptr &x, const filterptr &y);
+bool operator<(const filterptr &x, const filterptr &y);
+
+
+typedef map<text_t, filterptr, lttext_t> filterptrmap;
+
+// contains a list of filters indexed by their name
+class filtermapclass {
+protected:
+  filterptrmap filterptrs;
+
+public:
+  // type support for filterptrmap
+  typedef filterptrmap::iterator iterator;
+  typedef filterptrmap::const_iterator const_iterator;
+  typedef filterptrmap::reference reference;
+  typedef filterptrmap::const_reference const_reference;
+  typedef filterptrmap::size_type size_type;
+
+  typedef filterptrmap::difference_type difference_type;
+  typedef filterptrmap::const_reverse_iterator const_reverse_iterator;
+  typedef filterptrmap::reverse_iterator reverse_iterator;
+  
+  // basic container support
+  iterator begin () {return filterptrs.begin();}
+  const_iterator begin () const {return filterptrs.begin();}
+  iterator end () {return filterptrs.end();}
+  const_iterator end () const {return filterptrs.end();}
+
+  void erase(iterator pos) {filterptrs.erase(pos);}
+  void erase(iterator first, iterator last) {filterptrs.erase(first, last);}
+  filtermapclass &operator=(const filtermapclass &x) {filterptrs=x.filterptrs;return *this;}
+
+  bool empty () const {return filterptrs.empty();}
+  size_type size() const {return filterptrs.size();}
+
+
+  // added functionality
+  void clear () {filterptrs.erase(filterptrs.begin(),filterptrs.end());}
+
+  // thefilter remains the property of the calling code but
+  // should not be deleted until it is removed from this list.
+  void addfilter (filterclass *thefilter);
+
+  // getfilter will return NULL if the filter could not be found
+  filterclass *getfilter (const text_t &key);
+};
+
+
+
+// some useful functions for dealing with document sets
+
+// intersect places the result in set1
+void intersect (text_tset &set1, const text_tset &set2);
+void intersect (text_tarray &set1, const text_tset &set2);
+void intersect (text_tarray &set1, const text_tarray &set2);
+
+// tests to see if el is in set
+bool in_set (const text_tset &set1, const text_t &el);
+bool in_set (const text_tarray &set1, const text_t &el);
+
+#endif
Index: /main/tags/2.25/gsdl/src/colservr/maptools.cpp
===================================================================
--- /main/tags/2.25/gsdl/src/colservr/maptools.cpp	(revision 21064)
+++ /main/tags/2.25/gsdl/src/colservr/maptools.cpp	(revision 21064)
@@ -0,0 +1,177 @@
+/**********************************************************************
+ *
+ * maptools.cpp -- 
+ * Copyright (C) 1999  The New Zealand Digital Library Project
+ *
+ * A component of the Greenstone digital library software
+ * from the New Zealand Digital Library Project at the
+ * University of Waikato, New Zealand.
+ *
+ * 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.
+ *
+ *********************************************************************/
+
+#include "maptools.h"
+
+
+
+void stringmap::clear () {
+  fromorder.erase (fromorder.begin(), fromorder.end());
+  mapfrom.erase (mapfrom.begin(), mapfrom.end());
+}
+
+void stringmap::importmap (const text_tarray &maparray) {
+  clear ();
+  
+  text_tarray::const_iterator here = maparray.begin();
+  text_tarray::const_iterator end = maparray.end();
+  text_t from;
+  text_t to;
+
+  while (here != end) {
+    splitmapentry (*here, from, to);
+    fromorder.push_back (from);
+    mapfrom[from] = to;
+    here++;
+  }
+}
+
+void stringmap::exportmap (text_tarray &maparray) const {
+  maparray.erase (maparray.begin(), maparray.end());
+
+  text_tarray::const_iterator here = fromorder.begin();
+  text_tarray::const_iterator end = fromorder.end();
+  text_tmap::const_iterator toptr;
+  text_t tempmap;
+
+  while (here != end) {
+    toptr = mapfrom.find (*here);
+    if (toptr != mapfrom.end()) {
+      joinmapentry ((*toptr).first, (*toptr).second, tempmap);
+      maparray.push_back (tempmap);
+    }
+
+    here++;
+  }
+}
+
+void stringmap::getfromarray (text_tarray &fromarray) const {
+  fromarray = fromorder;
+}
+
+void stringmap::gettoarray (text_tarray &toarray) const {
+  toarray.erase(toarray.begin(), toarray.end());
+
+  text_tarray::const_iterator here = fromorder.begin();
+  text_tarray::const_iterator end = fromorder.end();
+  text_tmap::const_iterator toptr;
+
+  while (here != end) {
+    toptr = mapfrom.find (*here);
+    if (toptr != mapfrom.end()) {
+      toarray.push_back((*toptr).second);
+    }
+    here++;
+  }
+}
+
+bool stringmap::fromexists (const text_t &from) const {
+  return (mapfrom.find (from) != mapfrom.end ());
+}
+
+bool stringmap::toexists (const text_t &to) const {
+  text_tarray::const_iterator here = fromorder.begin();
+  text_tarray::const_iterator end = fromorder.end();
+  text_tmap::const_iterator toptr;
+
+  while (here != end) {
+    toptr = mapfrom.find (*here);
+    if (toptr != mapfrom.end() && (*toptr).second == to) return true;
+    here++;
+  }
+  
+  // it was not found
+  return false;
+}
+
+bool stringmap::from2to (const text_t &from, text_t &to) const {
+  text_tmap::const_iterator toptr = mapfrom.find (from);
+  if (toptr == mapfrom.end()) {
+    to.clear();
+    return false;
+  }
+
+  to = (*toptr).second;
+  return true;
+}
+
+bool stringmap::to2from (const text_t &to, text_t &from) const {
+  text_tarray::const_iterator here = fromorder.begin();
+  text_tarray::const_iterator end = fromorder.end();
+  text_tmap::const_iterator toptr;
+
+  while (here != end) {
+    toptr = mapfrom.find (*here);
+    if (toptr != mapfrom.end() && (*toptr).second == to) {
+      from = (*toptr).first;
+      return true;
+    }
+    here++;
+  }
+  
+  // it was not found
+  from.clear();
+  return false;
+}
+
+
+
+void splitmapentry (const text_t &mapentry, text_t &from, text_t &to) {
+  from.clear ();
+  to.clear();
+
+  text_t::const_iterator here = mapentry.begin();
+  text_t::const_iterator end = mapentry.end();
+
+  // get the "from" part of the map
+  while (here != end) {
+    if (*here == '-') {
+      here++;
+      if (here != end && *here == '>') {
+	here++;
+	break; // found "->"
+      }
+
+      // didn't find "->"
+      from.push_back('-');
+
+    } else {
+      from.push_back(*here);
+      here++;
+    }
+  }
+
+  // get the "to" part of the map
+  while (here != end) {
+    to.push_back(*here);
+    here++;
+  }
+}
+
+void joinmapentry (const text_t &from, const text_t &to, text_t &mapentry) {
+  mapentry = from;
+  mapentry += "->";
+  mapentry += to;
+}
Index: /main/tags/2.25/gsdl/src/colservr/maptools.h
===================================================================
--- /main/tags/2.25/gsdl/src/colservr/maptools.h	(revision 21064)
+++ /main/tags/2.25/gsdl/src/colservr/maptools.h	(revision 21064)
@@ -0,0 +1,65 @@
+/**********************************************************************
+ *
+ * maptools.h -- 
+ * Copyright (C) 1999  The New Zealand Digital Library Project
+ *
+ * A component of the Greenstone digital library software
+ * from the New Zealand Digital Library Project at the
+ * University of Waikato, New Zealand.
+ *
+ * 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.
+ *
+ *********************************************************************/
+
+
+#ifndef MAPTOOLS_H
+#define MAPTOOLS_H
+
+
+#include "gsdlconf.h"
+#include "text_t.h"
+
+// stringmap is a mapping which remembers the original order 
+// of the map, but is very fast to look up.
+class stringmap {
+protected:
+  text_tarray fromorder;
+  text_tmap mapfrom;
+
+public:
+  void clear ();
+
+  void importmap (const text_tarray &maparray);
+  void exportmap (text_tarray &maparray) const;
+
+  void getfromarray (text_tarray &fromarray) const;
+  void gettoarray (text_tarray &toarray) const;
+  
+  bool fromexists (const text_t &from) const;
+  bool toexists (const text_t &to) const;
+
+  // from2to and to2from return false if the key (the "from"
+  // field or the "to" field) cannot be found
+  bool from2to (const text_t &from, text_t &to) const;
+  bool to2from (const text_t &to, text_t &from) const;
+};
+
+
+// a few useful functions used by stringmap
+void splitmapentry (const text_t &mapentry, text_t &from, text_t &to);
+void joinmapentry (const text_t &from, const text_t &to, text_t &mapentry);
+
+
+#endif
Index: /main/tags/2.25/gsdl/src/colservr/mggdbmsource.cpp
===================================================================
--- /main/tags/2.25/gsdl/src/colservr/mggdbmsource.cpp	(revision 21064)
+++ /main/tags/2.25/gsdl/src/colservr/mggdbmsource.cpp	(revision 21064)
@@ -0,0 +1,326 @@
+/**********************************************************************
+ *
+ * mggdbmsource.cpp -- 
+ * Copyright (C) 1999  The New Zealand Digital Library Project
+ *
+ * A component of the Greenstone digital library software
+ * from the New Zealand Digital Library Project at the
+ * University of Waikato, New Zealand.
+ *
+ * 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.
+ *
+ *********************************************************************/
+
+#include "mggdbmsource.h"
+#include "fileutil.h"
+#include "OIDtools.h"
+#include "gsdltools.h"
+
+
+mggdbmsourceclass::mggdbmsourceclass () {
+  gdbmptr = NULL;
+  mgsearchptr = NULL;
+}
+
+mggdbmsourceclass::~mggdbmsourceclass () {
+}
+
+void mggdbmsourceclass::configure (const text_t &key, const text_tarray &cfgline) {
+  if (cfgline.size() >= 1) {
+    const text_t &value = cfgline[0];
+
+    if (key == "collection") collection = value;
+    else if (key == "collectdir") collectdir = value;
+    else if (key == "gsdlhome") gsdlhome = value;
+    else if (key == "gdbmhome") gdbmhome = value;
+  }
+
+  if (key == "indexmap") {
+    indexmap.importmap (cfgline);
+
+  } else if (key == "defaultindex") {
+    indexmap.from2to (cfgline[0], defaultindex);
+
+  } else if (key == "subcollectionmap") {
+    subcollectionmap.importmap (cfgline);
+
+  } else if (key == "defaultsubcollection") {
+    subcollectionmap.from2to (cfgline[0], defaultsubcollection);
+
+  } else if (key == "languagemap") {
+    languagemap.importmap (cfgline);
+
+  } else if (key == "defaultlanguage") 
+    languagemap.from2to (cfgline[0], defaultlanguage);
+}
+
+bool mggdbmsourceclass::init (ostream &logout) {
+  outconvertclass text_t2ascii;
+  
+  if (gdbmhome.empty()) gdbmhome = gsdlhome;
+
+  if (!sourceclass::init (logout)) return false;
+  
+  // get the collection directory name
+  if (collectdir.empty()) {
+    collectdir = filename_cat (gdbmhome, "collect", collection);
+  }
+  
+  // get the filename for the database and make sure it exists
+  gdbm_filename = filename_cat(collectdir,"index","text",collection);
+
+  if (littleEndian()) gdbm_filename += ".ldb";
+  else gdbm_filename += ".bdb";
+
+  if (!file_exists(gdbm_filename)) {
+    logout << text_t2ascii
+	   << "warning: gdbm database \"" //****
+	   << gdbm_filename << "\" does not exist\n\n";
+    // return false; //****
+  }
+  
+  return true;
+}
+
+bool mggdbmsourceclass::translate_OID (const text_t &OIDin, text_t &OIDout, 
+				       comerror_t &err, ostream &logout) {
+
+  outconvertclass text_t2ascii;
+
+  err = noError;
+  if (gdbmptr == NULL) {
+    // most likely a configuration problem
+    logout << text_t2ascii 
+	   << "configuration error: mggdbmsource contains a null gdbmclass\n\n";
+    err = configurationError;
+    return true;
+  }
+
+  // open the database
+  gdbmptr->setlogout(&logout);
+  if (!gdbmptr->opendatabase (gdbm_filename, GDBM_READER, 100, false)) {
+    // most likely a system problem (we have already checked that the
+    // gdbm database exists)
+    logout << text_t2ascii
+	   << "system problem: open on gdbm database \""
+	   << gdbm_filename << "\" failed\n\n";
+    err = systemProblem;
+    return true;
+  }
+
+  infodbclass info;
+  OIDout = gdbmptr->translate_OID (OIDin, info);
+  return true;
+}
+
+bool mggdbmsourceclass::get_metadata (const text_t &/*requestParams*/, const text_t &/*refParams*/, 
+				      bool getParents, const text_tset &fields, 
+				      const text_t &OID, MetadataInfo_tmap &metadata, 
+				      comerror_t &err, ostream &logout) {
+  outconvertclass text_t2ascii;
+
+  metadata.erase(metadata.begin(), metadata.end());
+
+  err = noError;
+  if (gdbmptr == NULL) {
+    // most likely a configuration problem
+    logout << text_t2ascii 
+	   << "configuration error: mggdbmsource contains a null gdbmclass\n\n";
+    err = configurationError;
+    return true;
+  }
+
+  // open the database
+  gdbmptr->setlogout(&logout);
+  if (!gdbmptr->opendatabase (gdbm_filename, GDBM_READER, 100, false)) {
+    // most likely a system problem (we have already checked that the
+    // gdbm database exists)
+    logout << text_t2ascii
+	   << "system problem: open on gdbm database \""
+	   << gdbm_filename << "\" failed\n\n";
+    err = systemProblem;
+    return true;
+  }
+
+  // get the metadata - if getParents is set we need to get 
+  // info for all parents of OID as well as OID
+  vector<infodbclass> info_array;
+  text_tarray OIDs;
+  if (getParents) get_parents_array (OID, OIDs);
+  OIDs.push_back (OID);
+
+  text_tarray::const_iterator this_OID = OIDs.begin();
+  text_tarray::const_iterator end_OID = OIDs.end();
+
+  while (this_OID != end_OID) {
+    infodbclass info;
+    if (!gdbmptr->getinfo(*this_OID, info)) return false;
+
+    // adjust the metadata
+    text_t &contains = info["contains"];
+    if (contains.empty()) info["haschildren"] = 0;
+    else info["haschildren"] = 1;
+    contains.clear();
+
+    info_array.push_back(info);
+    this_OID ++;
+  }
+
+  // if fields set is empty we want to get all available metadata
+  text_tset tfields = fields;
+  if (tfields.empty() && !info_array.empty()) {
+    infodbclass::iterator t_info = info_array[0].begin(); 
+    infodbclass::iterator e_info = info_array[0].end(); 
+    while (t_info != e_info) {
+      if ((*t_info).first != "contains")
+	tfields.insert ((*t_info).first);
+      t_info ++;
+    }
+    tfields.insert ("hasnext");
+    tfields.insert ("hasprevious");
+  }
+    
+  // collect together the metadata
+  bool donenextprevtest = false;
+  bool hasnext=false, hasprevious=false;
+  MetadataInfo_t this_metadata;
+  text_tarray *pos_metadata;
+  text_tset::const_iterator fields_here = tfields.begin();
+  text_tset::const_iterator fields_end = tfields.end();
+
+  while (fields_here != fields_end) {
+    this_metadata.clear();
+    this_metadata.isRef = false;
+
+    vector<infodbclass>::reverse_iterator this_info = info_array.rbegin(); 
+    vector<infodbclass>::reverse_iterator end_info = info_array.rend(); 
+    MetadataInfo_t *tmetaptr = &this_metadata;
+    while (this_info != end_info) {
+
+      pos_metadata = (*this_info).getmultinfo(*fields_here);
+      if ((*fields_here == "hasnext" || *fields_here == "hasprevious")) {
+	
+	// collect metadata
+	if (!donenextprevtest) {
+	  donenextprevtest = true;
+	  
+	  // cache parent contents array
+	  text_t thisparent = get_parent (OID);
+	  if (!thisparent.empty()) {
+	    if (thisparent != parentOID) {
+	      parentOID = thisparent;
+	      parentcontents.erase(parentcontents.begin(), parentcontents.end());
+	      if (gdbmptr->getinfo(parentOID, parentinfo)) {
+		text_t &parentinfocontains = parentinfo["contains"];
+		if (!parentinfocontains.empty())
+		  splitchar (parentinfocontains.begin(), parentinfocontains.end(), 
+			     ';', parentcontents);
+	      }
+	    }
+	    
+	    // do tests
+	    text_tarray::const_iterator parentcontents_here = parentcontents.begin();
+	    text_tarray::const_iterator parentcontents_end = parentcontents.end();
+	    text_t shrunk_OID = OID;
+	    shrink_parent (shrunk_OID);
+	    while (parentcontents_here != parentcontents_end) {
+	      if (*parentcontents_here == shrunk_OID) {
+		if (parentcontents_here == parentcontents.begin()) hasprevious = false;
+		else hasprevious = true;
+		
+		parentcontents_here++;
+		
+		if (parentcontents_here == parentcontents.end()) hasnext = false;
+		else hasnext = true;
+		
+		break;
+	      }  
+	      
+	      parentcontents_here ++;
+	    }
+	 
+	    // fill in metadata
+	    if ((*fields_here == "hasnext" && hasnext) ||
+		(*fields_here == "hasprevious" && hasprevious))
+	      tmetaptr->values.push_back("1");
+	    else
+	      tmetaptr->values.push_back("0");
+	  } else
+	    tmetaptr->values.push_back("0");
+	}
+      }
+      else if (pos_metadata != NULL && *fields_here != "contains") {
+	tmetaptr->values = *pos_metadata;
+      }
+      else
+	tmetaptr->values.push_back("");
+
+      this_info ++;
+      if (this_info != end_info) {
+	tmetaptr->parent = new MetadataInfo_t();
+	tmetaptr = tmetaptr->parent;
+      }
+    }
+    metadata[*fields_here] = this_metadata;
+    fields_here++;
+  }
+  return true;
+}
+
+
+bool mggdbmsourceclass::get_document (const text_t &OID, text_t &doc, 
+				      comerror_t &err, ostream &logout) {
+
+  outconvertclass text_t2ascii;
+
+  err = noError;
+  if (gdbmptr == NULL) {
+    // most likely a configuration problem
+    logout << text_t2ascii 
+	   << "configuration error: mggdbmsource contains a null gdbmclass\n\n";
+    err = configurationError;
+    return true;
+  }
+
+  // open the database
+  gdbmptr->setlogout(&logout);
+  if (!gdbmptr->opendatabase (gdbm_filename, GDBM_READER, 100, false)) {
+    // most likely a system problem (we have already checked that the
+    // gdbm database exists)
+    logout << text_t2ascii
+	   << "system problem: open on gdbm database \""
+	   << gdbm_filename << "\" failed\n\n";
+    err = systemProblem;
+    return true;
+  }
+
+  text_t tOID = OID;
+  if (needs_translating (OID)) 
+    translate_OID (OID, tOID, err, logout);
+  infodbclass info;
+  if (!gdbmptr->getinfo(tOID, info)) return false;
+  
+  if (info["hastxt"].getint() == 1) {
+    int docnum = info["docnum"].getint();
+    
+    // set the collection directory
+    mgsearchptr->setcollectdir (collectdir);
+    
+    // get the text
+    mgsearchptr->docTargetDocument(defaultindex, defaultsubcollection,
+				   defaultlanguage, collection, docnum, doc);
+  }
+  return true;
+}
Index: /main/tags/2.25/gsdl/src/colservr/mggdbmsource.h
===================================================================
--- /main/tags/2.25/gsdl/src/colservr/mggdbmsource.h	(revision 21064)
+++ /main/tags/2.25/gsdl/src/colservr/mggdbmsource.h	(revision 21064)
@@ -0,0 +1,88 @@
+/**********************************************************************
+ *
+ * mggdbmsource.h -- 
+ * Copyright (C) 1999  The New Zealand Digital Library Project
+ *
+ * A component of the Greenstone digital library software
+ * from the New Zealand Digital Library Project at the
+ * University of Waikato, New Zealand.
+ *
+ * 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.
+ *
+ *********************************************************************/
+
+
+#ifndef MGGDBMSOURCE_H
+#define MGGDBMSOURCE_H
+
+#include "gsdlconf.h"
+#include "text_t.h"
+#include "comtypes.h"
+#include "infodbclass.h"
+#include "maptools.h"
+#include "search.h"
+#include "source.h"
+
+
+class mggdbmsourceclass : public sourceclass {
+protected:
+  text_t gsdlhome;
+  text_t gdbmhome;
+  text_t collection;
+  text_t collectdir;
+
+  // these maps are only needed to convert the default indexes
+  stringmap indexmap;
+  stringmap subcollectionmap;
+  stringmap languagemap;
+
+  text_t defaultindex;
+  text_t defaultsubcollection;
+  text_t defaultlanguage;
+
+  text_t parentOID;
+  infodbclass parentinfo;
+  text_tarray parentcontents;
+
+  text_t gdbm_filename;
+  gdbmclass *gdbmptr;
+  
+  searchclass *mgsearchptr;
+
+public:
+  mggdbmsourceclass ();
+  virtual ~mggdbmsourceclass ();
+
+  // the gdbmptr remains the responsability of the calling code
+  void set_gdbmptr (gdbmclass *thegdbmptr) {gdbmptr=thegdbmptr;}
+
+  // the mgsearchptr remains the responsability of the calling code
+  void set_mgsearchptr (searchclass *themgsearchptr) {mgsearchptr=themgsearchptr;}
+
+  void configure (const text_t &key, const text_tarray &cfgline);
+  bool init (ostream &logout);
+  bool translate_OID (const text_t &OIDin, text_t &OIDout, 
+		      comerror_t &err, ostream &logout);
+  bool get_metadata (const text_t &requestParams, const text_t &refParams, 
+		     bool getParents, const text_tset &fields, 
+		     const text_t &OID, MetadataInfo_tmap &metadata, 
+		     comerror_t &err, ostream &logout);
+  bool get_document (const text_t &OID, text_t &doc, 
+		     comerror_t &err, ostream &logout);
+};
+
+
+
+#endif
Index: /main/tags/2.25/gsdl/src/colservr/mgppqueryfilter.cpp
===================================================================
--- /main/tags/2.25/gsdl/src/colservr/mgppqueryfilter.cpp	(revision 21064)
+++ /main/tags/2.25/gsdl/src/colservr/mgppqueryfilter.cpp	(revision 21064)
@@ -0,0 +1,346 @@
+/**********************************************************************
+ *
+ * queryfilter.cpp -- 
+ * Copyright (C) 1999  The New Zealand Digital Library Project
+ *
+ * A component of the Greenstone digital library software
+ * from the New Zealand Digital Library Project at the
+ * University of Waikato, New Zealand.
+ *
+ * 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.
+ *
+ * $Id$
+ *
+ *********************************************************************/
+
+
+
+#include "mgppqueryfilter.h"
+#include "fileutil.h"
+#include <assert.h>
+#include "mgppsearch.h"
+
+/////////////////////////////////
+// functions for queryfilterclass
+/////////////////////////////////
+
+
+mgppqueryfilterclass::mgppqueryfilterclass () 
+  : queryfilterclass() {
+  
+ FilterOption_t filtopt;
+  // -- onePerTerm  Level          enumerated
+  filtopt.clear();
+  filtopt.name = "Level";
+  filtopt.type = FilterOption_t::enumeratedt;
+  filtopt.repeatable = FilterOption_t::onePerTerm;
+  filtopt.validValues.push_back("Document");
+  filtopt.validValues.push_back("Section");
+  filtopt.validValues.push_back("Paragraph");
+  filtopt.defaultValue = "Document";
+  filterOptions["Level"] = filtopt;
+
+  // --  BrowseFields, enumerated, used to list available fields
+  filtopt.clear();
+  filtopt.name = "BrowseFields";
+  filtopt.type = FilterOption_t::enumeratedt;
+  filtopt.repeatable = FilterOption_t::onePerTerm;
+  filtopt.validValues.push_back("AllFields");
+  filtopt.defaultValue = "AllFields";
+  filterOptions["BrowseFields"] = filtopt;
+
+}
+
+mgppqueryfilterclass::~mgppqueryfilterclass () {
+}
+
+
+//whether a query is a full text browse
+bool mgppqueryfilterclass::full_text_browse (int filterRequestOptions) {
+  return (filterRequestOptions & FRfullTextBrowse);
+}
+
+void mgppqueryfilterclass::configure (const text_t &key, const text_tarray &cfgline) {
+  queryfilterclass::configure(key, cfgline);
+
+  if (key == "indexfields") {
+    text_tarray::iterator here = cfgline.begin();
+    text_tarray::iterator end = cfgline.end();
+    
+    while (here !=end) {
+      
+      filterOptions["BrowseFields"].validValues.push_back(*here);
+      here++;
+    }
+  }
+}
+
+
+void mgppqueryfilterclass::filter(const FilterRequest_t &request,
+				  FilterResponse_t &response,
+				  comerror_t &err, ostream &logout) {  
+
+
+  outconvertclass text_t2ascii;
+
+  response.clear ();
+  err = noError;
+  if (gdbmptr == NULL) {
+    // most likely a configuration problem
+    logout << text_t2ascii 
+	   << "configuration error: queryfilter contains a null gdbmclass\n\n";
+    err = configurationError;
+    return;
+  }
+  if (mgsearchptr == NULL) {
+    // most likely a configuration problem
+    logout << text_t2ascii 
+	   << "configuration error: queryfilter contains a null mgppsearchclass\n\n";
+    err = configurationError;
+    return;
+  }
+  if (full_text_browse(request.filterResultOptions)) {
+    browsefilter(request, response, err, logout);
+    return;
+  }
+  // open the database
+  gdbmptr->setlogout(&logout);
+  if (!gdbmptr->opendatabase (gdbm_filename, GDBM_READER, 100, false)) {
+    // most likely a system problem (we have already checked that the
+    // gdbm database exists)
+    logout << text_t2ascii
+	   << "system problem: open on gdbm database \""
+	   << gdbm_filename << "\" failed\n\n";
+    err = systemProblem;
+    return;
+  }
+
+
+  // get the query parameters
+  int startresults, endresults;
+  text_t phrasematch; // not used here any more
+  vector<queryparamclass> queryfilterparams;
+  parse_query_params (request, queryfilterparams, startresults, 
+		      endresults, phrasematch, logout);  
+ 
+   
+  // do query
+  queryresultsclass queryresults;
+  do_multi_query (request, queryfilterparams, queryresults, err, logout);
+  if (err != noError) return;
+  
+  // assemble document results
+  if (need_matching_docs (request.filterResultOptions)) {
+    
+    int resultnum = 1;
+    ResultDocInfo_t resultdoc;
+    text_t trans_OID;
+    vector<int>::iterator docorder_here = queryresults.docs.docorder.begin();
+    vector<int>::iterator docorder_end = queryresults.docs.docorder.end();
+
+    if (endresults == -1) endresults = MAXNUMDOCS;
+    while (docorder_here != docorder_end) {
+      if (resultnum > endresults) break;
+      
+      // translate the document number
+      if (!translate(gdbmptr, *docorder_here, trans_OID)) {
+	logout << text_t2ascii
+	       << "warning: could not translate mgpp document number \""
+	       << *docorder_here << "\"to OID.\n\n";
+	
+      } else {
+	docresultmap::iterator docset_here = queryresults.docs.docset.find (*docorder_here);
+
+	// see if there is a result for this number,
+	// if it is in the request set (or the request set is empty)
+	if (docset_here != queryresults.docs.docset.end() &&
+	    (request.docSet.empty() || in_set(request.docSet, trans_OID))) {
+	  if (resultnum >= startresults) {
+	    // add this document
+	    resultdoc.OID = trans_OID;
+	    resultdoc.result_num = resultnum;
+	    resultdoc.ranking = (int)((*docset_here).second.docweight * 10000.0 + 0.5);
+
+	    response.docInfo.push_back (resultdoc);
+	  }
+	  
+	  resultnum++;
+	}
+      } // else
+      
+      docorder_here++;
+    }
+  } // if need matching docs
+
+  // assemble the term results
+  if (need_term_info(request.filterResultOptions)) {
+    // note: the terms have already been sorted and uniqued
+
+    TermInfo_t terminfo;
+    bool terms_first = true;
+
+    termfreqclassarray::iterator terms_here = queryresults.terms.begin();
+    termfreqclassarray::iterator terms_end = queryresults.terms.end();
+
+    while (terms_here != terms_end) {
+      terminfo.clear();
+      terminfo.term = (*terms_here).termstr;
+      terminfo.freq = (*terms_here).termfreq;
+      if (terms_first) {
+	text_tset::iterator termvariants_here = queryresults.termvariants.begin();
+	text_tset::iterator termvariants_end = queryresults.termvariants.end();
+	while (termvariants_here != termvariants_end) {
+	  terminfo.matchTerms.push_back (*termvariants_here);
+	  termvariants_here++;
+	}
+      }
+      terms_first = false;
+
+      response.termInfo.push_back (terminfo);
+
+      terms_here++;
+    }
+  }
+
+  response.numDocs = queryresults.docs_matched;
+  response.isApprox = queryresults.is_approx;
+}
+
+void mgppqueryfilterclass::browsefilter(const FilterRequest_t &request,
+					FilterResponse_t &response,
+					comerror_t &err, ostream &logout) {  
+
+  outconvertclass text_t2ascii;
+
+  // get the query parameters
+  int startresults, endresults;
+  text_t phrasematch; // not used here any more, just have it so can use
+                      // parse_query_params function
+  
+  vector<queryparamclass> queryfilterparams;
+  parse_query_params (request, queryfilterparams, startresults, 
+		      endresults, phrasematch, logout);  
+ 
+  vector<queryparamclass>::const_iterator query_here = queryfilterparams.begin();
+   
+  // do query
+  queryresultsclass queryresults;
+  queryresults.clear();
+  
+  int numDocs = endresults-startresults;
+  mgsearchptr->setcollectdir (collectdir);
+
+  if (!((mgppsearchclass*)mgsearchptr)->browse_search((*query_here), startresults, numDocs, queryresults)) {
+    // most likely a system problem
+    logout << text_t2ascii
+	   << "system problem: could not do full text browse with mgpp for index \""
+	   << (*query_here).index << (*query_here).subcollection
+	   << (*query_here).language << "\".\n\n";
+    err = systemProblem;
+    return;
+  }
+
+  // assemble the term results
+  TermInfo_t terminfo;
+  
+  termfreqclassarray::iterator terms_here = queryresults.terms.begin();
+  termfreqclassarray::iterator terms_end = queryresults.terms.end();
+
+  while (terms_here != terms_end) {
+    terminfo.clear();
+    terminfo.term = (*terms_here).termstr;
+    terminfo.freq = (*terms_here).termfreq;
+    
+    response.termInfo.push_back (terminfo);
+
+    terms_here++;
+  }
+  
+
+}
+
+// mgppsearchptr and gdbmptr are assumed to be valid
+void mgppqueryfilterclass::do_multi_query (const FilterRequest_t &request,
+					   const vector<queryparamclass> &query_params,
+					   queryresultsclass &multiresults,
+					   comerror_t &err, ostream &logout) {
+  outconvertclass text_t2ascii;
+
+  err = noError;
+  mgsearchptr->setcollectdir (collectdir);
+  multiresults.clear();
+  
+  vector<queryparamclass>::const_iterator query_here = query_params.begin();
+  vector<queryparamclass>::const_iterator query_end = query_params.end();
+  while (query_here != query_end) {
+    queryresultsclass thisqueryresults;
+    text_t indx((*query_here).index);
+     if (!mgsearchptr->search((*query_here), thisqueryresults)) {
+      // most likely a system problem
+      logout << text_t2ascii
+	     << "system problem: could not do search with mgpp for index \""
+	     << (*query_here).index << (*query_here).subcollection
+	     << (*query_here).language << "\".\n\n";
+      err = systemProblem;
+      return;
+    }
+
+    // combine the results
+    if (need_matching_docs (request.filterResultOptions)) {
+            
+      if (query_params.size() == 1) {
+	multiresults.docs = thisqueryresults.docs; // just one set of results
+	multiresults.docs_matched = thisqueryresults.docs_matched;
+	multiresults.is_approx = thisqueryresults.is_approx;
+	
+      } else {
+	if ((*query_here).combinequery == "and") {
+	  multiresults.docs.combine_and (thisqueryresults.docs);
+	} else if ((*query_here).combinequery == "or") {
+	  multiresults.docs.combine_or (thisqueryresults.docs);
+	} else if ((*query_here).combinequery == "not") {
+	  multiresults.docs.combine_not (thisqueryresults.docs);
+	}
+	multiresults.docs_matched = multiresults.docs.docset.size();
+	multiresults.is_approx = Exact;
+      }
+    }
+
+    // combine the term information 
+    if (need_term_info (request.filterResultOptions)) {
+      // append the terms
+      multiresults.orgterms.insert(multiresults.orgterms.end(),
+				   thisqueryresults.orgterms.begin(),
+				   thisqueryresults.orgterms.end());
+
+      
+      // add the term variants - 
+      text_tset::iterator termvar_here = thisqueryresults.termvariants.begin();
+      text_tset::iterator termvar_end = thisqueryresults.termvariants.end();
+      while (termvar_here != termvar_end) {
+	multiresults.termvariants.insert(*termvar_here);
+	termvar_here++;
+      }
+    }
+   
+    query_here++;
+  }
+
+  // sort and unique the query terms
+  multiresults.sortuniqqueryterms ();
+}
+
+
+
Index: /main/tags/2.25/gsdl/src/colservr/mgppqueryfilter.h
===================================================================
--- /main/tags/2.25/gsdl/src/colservr/mgppqueryfilter.h	(revision 21064)
+++ /main/tags/2.25/gsdl/src/colservr/mgppqueryfilter.h	(revision 21064)
@@ -0,0 +1,66 @@
+/**********************************************************************
+ *
+ * mgppqueryfilter.h -- new queryfilter to use mgpp 
+ * Copyright (C) 1999  The New Zealand Digital Library Project
+ *
+ * A component of the Greenstone digital library software
+ * from the New Zealand Digital Library Project at the
+ * University of Waikato, New Zealand.
+ *
+ * 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.
+ *
+ * $Id$
+ *
+ *********************************************************************/
+
+
+#ifndef MGPPQUERYFILTER_H
+#define MGPPQUERYFILTER_H
+
+#include "queryfilter.h"
+
+class mgppqueryfilterclass : public queryfilterclass {
+protected:
+
+  bool full_text_browse (int filterRequestOptions);
+
+  // mgsearchptr and gdbmptr are assumed to be valid
+  void do_multi_query (const FilterRequest_t &request,
+		       const vector<queryparamclass> &query_params,
+		       queryresultsclass &multiresults,
+		       comerror_t &err, ostream &logout);
+
+
+public:
+  mgppqueryfilterclass ();
+  virtual ~mgppqueryfilterclass ();
+
+  void configure (const text_t &key, const text_tarray &cfgline);
+
+  void filter (const FilterRequest_t &request,
+		       FilterResponse_t &response,
+		       comerror_t &err, ostream &logout);
+  
+  void browsefilter(const FilterRequest_t &request,
+		    FilterResponse_t &response,
+		    comerror_t &err, ostream &logout);  
+
+
+};
+
+#endif
+
+
+
Index: /main/tags/2.25/gsdl/src/colservr/mgppsearch.cpp
===================================================================
--- /main/tags/2.25/gsdl/src/colservr/mgppsearch.cpp	(revision 21064)
+++ /main/tags/2.25/gsdl/src/colservr/mgppsearch.cpp	(revision 21064)
@@ -0,0 +1,251 @@
+/**********************************************************************
+ *
+ * mgppsearch.cpp -- 
+ * Copyright (C) 1999  The New Zealand Digital Library Project
+ *
+ * A component of the Greenstone digital library software
+ * from the New Zealand Digital Library Project at the
+ * University of Waikato, New Zealand.
+ *
+ * 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.
+ *
+ * $Id$
+ *
+ *********************************************************************/
+
+
+#include "gsdlconf.h"
+#include "mgppsearch.h"
+#include "fileutil.h"
+#include "GSDLQueryParser.h"
+#include "MGQuery.h"
+#include "TextGet.h"
+#include "queryinfo.h"
+
+
+
+static text_t getindexsuffix(const queryparamclass &qp) {
+  text_t indexsuffix = "index";
+  text_t ind = qp.index;
+  text_t sub = qp.subcollection;
+  text_t lang = qp.language;
+   
+  indexsuffix = filename_cat(indexsuffix, ind + sub + lang, qp.collection);
+  return indexsuffix;
+
+}
+
+////////////////////
+// mgppsearch class //
+////////////////////
+
+mgppsearchclass::mgppsearchclass ()
+  : searchclass() {
+ 
+}
+
+mgppsearchclass::~mgppsearchclass () 
+{
+  if (cache != NULL) 
+    {
+      delete cache;
+      cache = NULL;
+    }
+}
+
+bool mgppsearchclass::search(const queryparamclass &queryparams, 
+			     queryresultsclass &queryresult) {
+  
+  char *basepath = collectdir.getcstr(); //like ...gsdl/collect/demo
+  char *indexname = (getindexsuffix(queryparams)).getcstr(); // like ...demo/mt/demo
+
+  // load index data
+  IndexData indexData;
+  if (!indexData.LoadData (basepath, indexname)) {
+    cerr<<"couldn't load index data\n"<<endl;
+    return false;
+  }
+
+  // set default stem method from values originally set on prefs page
+  int defaultStemMethod = 0;
+  if (queryparams.casefolding) {
+    defaultStemMethod |= 1;
+  }
+  if (queryparams.stemming) {
+    defaultStemMethod |= 2;
+  }
+  
+  // use default query info settings - change to reflect user preferences??
+  QueryInfo queryInfo;
+  SetCStr (queryInfo.docLevel, (queryparams.level.getcstr())); 
+  queryInfo.maxDocs = (unsigned long)queryparams.maxdocs;
+  queryInfo.sortByRank = true;
+  queryInfo.exactWeights = false;
+  queryInfo.needRankInfo = true;
+  queryInfo.needTermFreqs = true;
+  
+  ExtQueryResult queryResult;
+  
+  UCArray queryArray;
+  SetCStr(queryArray, (queryparams.querystring.getcstr()));
+  
+  // create the mgpp query tree
+  QueryNode *queryTree = NULL;
+  queryTree = ParseQuery(queryArray, defaultStemMethod);
+    
+  UCArray level;
+  UCArrayClear(level);
+  
+  //always return sections - default for GSDL
+  SetCStr(level, "Section");
+  
+  // do the query
+  MGQuery(indexData, queryInfo, queryTree, queryResult, level);
+  
+ 
+  // convert ExtQueryResult to queryresultclass
+  
+  queryresult.docs_matched = (int)queryResult.docs.size();
+  queryresult.is_approx = Exact; //for now - change to reflect actual results
+  
+  docresultclass doc;
+  for (int i=0; i<(int)queryResult.docs.size(); i++) {
+    doc.clear();
+    doc.docnum = (int)queryResult.levels[i];
+    doc.docweight = queryResult.ranks[i];
+    queryresult.docs.docset[doc.docnum] = doc;
+    queryresult.docs.docorder.push_back(doc.docnum);
+
+  }
+
+  // term info
+  termfreqclass term;
+  for (int i=0; i<(int)queryResult.termFreqs.size(); i++) {
+    term.clear();
+    term.termstr = GetCStr(queryResult.termFreqs[i].term);
+    term.termstemstr = term.termstr;
+    term.termfreq = queryResult.termFreqs[i].termFreq;
+    queryresult.terms.push_back(term);
+    queryresult.orgterms.push_back(term);
+
+  }
+  // clean up
+  indexData.UnloadData();
+  delete indexname;
+  return true;
+
+}
+
+
+bool mgppsearchclass::browse_search(const queryparamclass &queryparams, int start, int numDocs,
+				    queryresultsclass &queryresult) {
+
+  char *basepath = collectdir.getcstr(); //like ...gsdl/collect/demo
+  char *indexname = (getindexsuffix(queryparams)).getcstr();
+ 
+  IndexData indexData;
+  if (!indexData.LoadData (basepath, indexname)) {
+    cerr<<"couldn't load index data\n"<<endl;
+    return false;
+  }
+
+  UCArray level;
+  UCArrayClear(level);
+  
+  //browse always at top level
+  SetCStr(level, "Document");
+  
+
+  BrowseQueryNode browseNode;
+  browseNode.startPosition = start;
+  browseNode.numTerms = numDocs;
+
+  BrowseQueryResult browseResult;
+
+  UCArrayClear(browseNode.term);
+  SetCStr(browseNode.term, (queryparams.querystring.getcstr()));
+
+  // do the actual query
+  MGBrowseQuery(indexData, level, browseNode, browseResult);
+
+  // load results into term info
+  termfreqclass term;
+  for (int i=0; i<(int)browseResult.termFreqs.size(); i++) {
+    term.clear();
+    term.termstr = GetCStr(browseResult.termFreqs[i].term);
+    term.termstemstr = term.termstr;
+    term.termfreq = browseResult.termFreqs[i].termFreq;
+    queryresult.terms.push_back(term);
+    queryresult.orgterms.push_back(term);
+
+  }
+  // clean up
+  indexData.UnloadData();
+  delete indexname;
+
+  return true;
+}
+
+// the document text for 'docnum' is placed in 'output'
+// docTargetDocument returns 'true' if it was able to
+// try to get a document
+// collection is needed to see if an index from the 
+// collection is loaded. THe default index bits are just there cos
+// the mg version needs them
+
+bool mgppsearchclass::docTargetDocument(const text_t &/*defaultindex*/,
+					const text_t &/*defaultsubcollection*/,
+					const text_t &/*defaultlanguage*/,
+					const text_t &collection,
+					int docnum,
+					text_t &output) {
+  
+  char *basepath = collectdir.getcstr(); //like ...gsdl/collect/demo
+
+  text_t textfilename = "/index/text/"+collection;
+  TextData textdata;
+  if(!textdata.LoadData(basepath, textfilename.getcstr())) {
+    //error
+    return false;
+  }
+  UCArray doctext;
+  UCArray level;
+  SetCStr(level, "Section");
+  if (!GetDocText(textdata, level, (unsigned long)docnum, doctext)) {
+    //error
+    return false;
+  }
+
+  // convert UCArray to text_t
+  output.clear();
+  output = GetCStr(doctext);
+
+  // here need to remove the <Document>, <Section>, <Paragraph> tags
+
+  // mg converts to unicode, this may need to be added here???
+
+  //clean up
+  textdata.UnloadData ();
+  delete basepath;
+
+  return true;
+
+}
+
+
+
+
+
+
Index: /main/tags/2.25/gsdl/src/colservr/mgppsearch.h
===================================================================
--- /main/tags/2.25/gsdl/src/colservr/mgppsearch.h	(revision 21064)
+++ /main/tags/2.25/gsdl/src/colservr/mgppsearch.h	(revision 21064)
@@ -0,0 +1,78 @@
+/**********************************************************************
+ *
+ * mgppsearch.h -- implementation of search class for mgpp
+ * Copyright (C) 1999  The New Zealand Digital Library Project
+ *
+ * A component of the Greenstone digital library software
+ * from the New Zealand Digital Library Project at the
+ * University of Waikato, New Zealand.
+ *
+ * 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.
+ *
+ * 
+ *
+ *********************************************************************/
+
+
+#ifndef MGPPSEARCH_H
+#define MGPPSEARCH_H
+
+#include "search.h"
+
+class mgppsearchclass : public searchclass {
+public:
+  mgppsearchclass ();
+  virtual ~mgppsearchclass ();
+
+  // the search results are returned in queryresults
+  // search returns 'true' if it was able to do a search
+  virtual bool search(const queryparamclass &queryparams, 
+	      queryresultsclass &queryresults);
+  
+  // this returns a list of terms in queryresults - no document info is returned
+  // returns a list of numTerms terms, starting from the query string term (in queryparams)
+  // + start. used for full text browsing
+  virtual bool browse_search(const queryparamclass &queryparams, int start, int numTerms,
+			     queryresultsclass &queryresults);
+
+  // the document text for 'docnum' is placed in 'output'
+  // docTargetDocument returns 'true' if it was able to
+  // try to get a document
+  // collection is needed to see if an index from the 
+  // collection is loaded. If no index has been loaded
+  // defaultindex is needed to load one
+  virtual bool docTargetDocument(const text_t &defaultindex,
+			 const text_t &defaultsubcollection,
+			 const text_t &defaultlanguage,
+			 const text_t &collection,
+			 int docnum,
+			 text_t &output);
+
+  /*  // same as docTargetDocument except the document is returned
+  // in its raw form. UDoc remains the property of mg and may
+  // be destroyed on the next call to mg.
+  // not implemented for mgpp
+  virtual bool mgdocument (const text_t &defaultindex,
+		   const text_t &defaultsubcollection,
+		   const text_t &defaultlanguage,
+		   const text_t &collection,
+		   int docnum,
+		   char *&UDoc, int &ULen);
+  */
+};
+
+
+#endif
+
Index: /main/tags/2.25/gsdl/src/colservr/mgq.c
===================================================================
--- /main/tags/2.25/gsdl/src/colservr/mgq.c	(revision 21064)
+++ /main/tags/2.25/gsdl/src/colservr/mgq.c	(revision 21064)
@@ -0,0 +1,731 @@
+/**********************************************************************
+ *
+ * mgq.c -- cut-dowm version of mgquery
+ * Copyright (C) 1999  The New Zealand Digital Library Project
+ *
+ * A component of the Greenstone digital library software
+ * from the New Zealand Digital Library Project at the
+ * University of Waikato, New Zealand.
+ *
+ * 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.
+ *
+ *********************************************************************/
+
+#include "mgq.h"
+
+
+#include <stdio.h>
+#include <string.h>
+/* #include <io.h> */
+#include <fcntl.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+  
+#include "sysfuncs.h"
+  
+#include "messages.h"
+#include "memlib.h"
+  
+#include "invf.h"
+#include "text.h"
+#include "lists.h"
+#include "backend.h"
+#include "environment.h"
+#include "globals.h"
+#include "mg_errors.h"
+#include "commands.h"
+#include "text_get.h"
+#include "term_lists.h"
+#include "local_strings.h"
+
+#include "words.h"
+#include "stemmer.h"
+#include "stem_search.h"
+  
+#ifdef __cplusplus
+}
+#endif
+
+
+#include "mgq.h"
+
+/* get a reasonable database cache size */
+#ifndef MAXNUMDATABASEINFO
+#  ifdef GSDLSERVER
+#    define MAXNUMDATABASEINFO 10
+#  else
+#    define MAXNUMDATABASEINFO 2
+#  endif
+#endif
+
+#define MAXCOLLECTIONLEN  16
+#define MAXMGDIRLEN       256
+#define MAXGENSUFFIXLEN   256
+#define MAXTEXTSUFFIXLEN  256
+
+typedef struct DatabaseInfo {
+  int accessnum; /* -1 = invalid record */
+  char collection[MAXCOLLECTIONLEN];
+  char mgdir[MAXMGDIRLEN];
+  char gensuffix[MAXGENSUFFIXLEN];
+  char textsuffix[MAXTEXTSUFFIXLEN];
+  query_data *qd;
+} DatabaseInfo;
+
+
+/* globals needed by some vague part of mg... */
+FILE *OutFile = NULL, *InFile = NULL;
+int OutPipe = 0, InPipe = 0;
+int Quitting = 0;
+
+/* globals needed to handle loading of databases */
+static int cur_cachenum = -1;
+
+/* globals needed by the database cache */
+static DatabaseInfo dbcache[MAXNUMDATABASEINFO];
+static int cache_nextaccessnum = 0;
+static int cache_numloaded = 0;
+
+
+
+#if defined(PARADOCNUM) ||  defined(NZDL)
+static int GetDocNumFromParaNum(query_data *qd, int paranum) {
+  int Documents = qd->td->cth.num_of_docs;
+  int *Paragraph = qd->paragraph;
+  int low = 1, high = Documents;
+  int mid = (low+high)/2;
+
+  while ((mid = (low+high)/2) >=1 && mid <= Documents)
+    {
+      if (paranum > Paragraph[mid])
+        low = mid+1;
+      else if (paranum <= Paragraph[mid-1])
+        high = mid-1;
+      else
+        return mid;
+    }
+  FatalError(1, "Bad paragraph number.\n");
+  return 0;
+}
+
+static int GetParaNumFromDocNum(query_data *qd, int docnum) {
+  int Documents = qd->td->cth.num_of_docs;
+  int *Paragraph = qd->paragraph;
+
+  if (docnum > 0 && docnum <= Documents)
+    return Paragraph[docnum-1]+1;
+  return 0;
+}
+#endif
+
+
+/*****************************************************************************/
+
+static void MGQError(char *emsg)
+{
+  fprintf(stderr,"Fatal error: %s\n", emsg);
+  exit(1);
+}
+
+static int ProcessDocs (query_data * qd, int skip, int howmany, 
+			enum result_kinds kind, 
+			int (*sender)(char *,int,int,float,void *), void *ptr) {
+  int max_buf = 0, output_failure = 0;
+  int DocCount = 0;
+  int need_text = (kind == result_docs);
+
+  /* skip the requested number of documents */
+  while (skip > 0) {
+    if (!NextDoc(qd)) return 0;
+    skip--;
+  }
+
+  /* find out the maximum size for the text buffer */
+  if (need_text) max_buf = atoi (GetDefEnv ("buffer", "1048576"));
+
+  /* process each document */
+  do {
+    u_char *UDoc = NULL;
+    unsigned long ULen=0;
+
+#if defined(PARADOCNUM) ||  defined(NZDL)
+    /* adjust the document number for paragraph level result_docs */
+    /* this is a bit of a hack ... */
+    if (kind==result_docs && qd->id->ifh.InvfLevel == 3 &&
+	qd->DL != NULL && (int)qd->doc_pos < (int)qd->DL->num)
+      qd->DL->DE[qd->doc_pos].DocNum = GetParaNumFromDocNum(qd, qd->DL->DE[qd->doc_pos].DocNum);
+#endif
+    
+    if (need_text) {
+      /* load the compressed text */
+      if (LoadCompressedText (qd, max_buf))
+	MGQError("Unable to load compressed text(memory?).");
+
+      /* uncompress the loaded text */
+      UDoc = GetDocText (qd, &ULen);
+      if (UDoc == NULL) MGQError("UDoc is unexpectedly NULL");
+    }
+      
+    if (UDoc != NULL  ||  kind == result_docnums) {
+      int docnum = GetDocNum(qd);
+#if defined(PARADOCNUM) ||  defined(NZDL)
+      if (qd->id->ifh.InvfLevel == 3) docnum = GetDocNumFromParaNum(qd, docnum);
+#endif
+      switch (kind) {
+      case result_docnums:
+	if (sender != NULL)
+	  output_failure = (*sender)("",0,docnum,GetDocWeight(qd),ptr);
+	break;
+      case result_docs:
+	if (sender != NULL)
+	  output_failure = (*sender)((char *)UDoc,ULen,docnum,GetDocWeight(qd),ptr);
+	break;
+      default:
+	break;
+      }
+    }
+    DocCount++;
+      
+  } while (NextDoc (qd) && output_failure == 0 && --howmany > 0);
+  
+  /*  if (need_text) FreeTextBuffer (qd);*/
+  
+  return (DocCount);
+}
+
+
+static void send_query_term_freqs(QueryTermList *qtl,
+				  int (*sender)(char *,int,int,float,void *), void *ptr)
+{
+  int i = 0;
+  for (i = 0; i < qtl->num; i++)
+    if (sender != NULL) {
+      /*      word = word2str(qtl->QTE[i].Term); 
+	      (* sender)(word, strlen(word), qtl->QTE[i].Count, (float)0.0, ptr); */
+      (* sender)((char *)(qtl->QTE[i].Term+1), qtl->QTE[i].Term[0], 
+		 qtl->QTE[i].Count, (float)0.0, ptr);
+    }
+}
+
+
+static void send_terms (TermList * qtl, 
+			int (*sender)(char *,int,int,float,void *), void *ptr)
+{
+  int i = 0;
+  if (sender == NULL) return;
+  for (i = 0; i < qtl->num; i++)
+    {
+      /*      word = word2str(qtl->TE[i].Word);
+	      (* sender)(word, strlen(word), qtl->TE[i].Count, (float)0.0, ptr);*/
+      (* sender)((char *)(qtl->TE[i].Word+1), qtl->TE[i].Word[0], 
+		 qtl->TE[i].Count, (float)0.0, ptr);
+    }
+}
+
+
+/* MoreDocs () */
+/* Displays all documents in list  DocList. */
+/* Documents are fetched, then decompressed and displayed according to the */
+/* format implied in  FormString(). */
+
+static void
+MoreDocs (query_data * qd, enum result_kinds kind, 
+	  int skip, int howmany,
+	  int (*sender)(char *,int,int,float,void *), void *ptr)
+{
+  qd->num_of_ans = qd->DL->num;
+  switch (kind) {
+  case result_docs:
+  case result_docnums:
+    if (qd->num_of_ans > 0)
+      ProcessDocs (qd, skip, howmany, kind, sender, ptr);
+    break;
+  case result_termfreqs:
+    send_query_term_freqs(qd->QTL, sender, ptr);
+    break;
+  case result_terms:
+    send_terms(qd->TL, sender, ptr);
+    break;
+  }
+}
+
+
+
+
+
+
+/******************************************
+ * functions to handle the database cache *
+ ******************************************/
+
+/* init_dbcache should be called at the start of each */
+/* function which deals with the database cache */
+static void init_dbcache (void) {
+  static int dbcacheinited = 0;
+  int i = 0;
+
+  if (dbcacheinited) return;
+
+  cache_numloaded = 0;
+
+  for (i=0; i<MAXNUMDATABASEINFO; i++) {
+    dbcache[i].accessnum = -1;
+    dbcache[i].collection[0] = '\0';
+    dbcache[i].mgdir[0] = '\0';
+    dbcache[i].gensuffix[0] = '\0';
+    dbcache[i].textsuffix[0] = '\0';
+    dbcache[i].qd = NULL;
+  }
+
+  dbcacheinited = 1;
+}
+
+/* returns the next cache access number and increments it */
+static int get_next_accessnum (void) {
+  return cache_nextaccessnum++;
+}
+
+/* get_free_dbcache returns the cache number which */
+/* was used the longest time ago */
+/* init_dbcache should be called before this function */
+static int get_free_dbcache (void) {
+  int i = 0;
+  int minaccessnum = cache_nextaccessnum; /* the current max */
+  int minpos = 0;
+
+  for (i=0; i<MAXNUMDATABASEINFO; i++) {
+    if (dbcache[i].accessnum < minaccessnum) {
+      minaccessnum = dbcache[i].accessnum;
+      minpos = i;
+    }
+  }
+  
+  return minpos;
+}
+
+/* search_collect will search for an index which */
+/* belongs to a certain collection It returns -1 if none could be found. */
+/* init_dbcache should be called before this function */
+static int search_collect (char *collection) {
+  int i = 0;
+
+  for (i=0; i<MAXNUMDATABASEINFO; i++) {
+    if ((dbcache[i].accessnum >= 0) &&
+	(dbcache[i].qd != NULL) &&
+	(strcmp (collection, dbcache[i].collection) == 0)
+	/* && (dbcache[i].qd->id->ifh.InvfLevel == 2)*/
+	) {
+      dbcache[i].accessnum = get_next_accessnum ();
+      return i;
+    }
+  }
+
+  return -1;
+}
+
+/* search_gensuffix will search for an index which */
+/* has a certain gensuffix. It returns -1 if none could be found. */
+/* init_dbcache should be called before this function */
+static int search_gensuffix (char *gensuffix) {
+  int i = 0;
+
+  for (i=0; i<MAXNUMDATABASEINFO; i++) {
+    if ((dbcache[i].accessnum >= 0) &&
+	(dbcache[i].qd != NULL) &&
+	(strcmp (gensuffix, dbcache[i].gensuffix) == 0)) {
+      dbcache[i].accessnum = get_next_accessnum ();
+      return i;
+    }
+  }
+
+  return -1;
+}
+
+/* unload_database will unload a certain entry within */
+/* the database cache, clearing it for furture use. */
+static void unload_database (int i) {
+  /* check to see if it contains anything */
+  if (dbcache[i].accessnum < 0 || dbcache[i].qd == NULL) 
+    return;
+
+  /* unload all the query information  */
+  FinishQuerySystem(dbcache[i].qd);
+  
+  /* reset all the db info */
+  dbcache[i].accessnum = -1;
+  dbcache[i].collection[0] = '\0';
+  dbcache[i].mgdir[0] = '\0';
+  dbcache[i].gensuffix[0] = '\0';
+  dbcache[i].textsuffix[0] = '\0';
+  dbcache[i].qd = NULL;
+
+  cache_numloaded--;
+  if (cache_numloaded < 0) cache_numloaded = 0;
+}
+
+/* cache_database will store the information about */
+/* a database in the database cache. */
+static void cache_database (int i, char *collection, char *mgdir, char *gensuffix,
+			    char *textsuffix, query_data *qd) {
+  /* make sure this entry has been unloaded first */
+  if (dbcache[i].accessnum >= 0 && dbcache[i].qd != NULL) 
+    unload_database (i);
+
+  /* store the db info */
+  dbcache[i].accessnum = get_next_accessnum ();
+  strcpy (dbcache[i].collection, collection);
+  strcpy (dbcache[i].mgdir, mgdir);
+  strcpy (dbcache[i].gensuffix, gensuffix);
+  strcpy (dbcache[i].textsuffix, textsuffix);
+  dbcache[i].qd = qd;
+
+  cache_numloaded++;
+}
+
+static void make_current (int i) {
+  /* see if it is the current index */
+  if (i == cur_cachenum) return;
+ 
+  /* unload the old index */
+  if (cur_cachenum >= 0) UninitEnv ();
+  cur_cachenum = -1;
+
+  /* make sure the new one is ok */
+  if (i < 0 || dbcache[i].accessnum < 0 || dbcache[i].qd == NULL)
+    return;
+
+  /* load the new one */
+
+  /* Initialise the environment with default values */
+  InitEnv ();
+  
+  SetEnv("mgdir",dbcache[i].mgdir,NULL);
+  SetEnv("mgname",dbcache[i].gensuffix,NULL);
+  SetEnv("textname",dbcache[i].textsuffix,NULL);
+  
+  PushEnv ();
+  
+  cur_cachenum = i;
+}
+
+
+
+/********************
+ * public functions *
+ ********************/
+
+int mgq_ask(char *line)
+{
+  query_data *qd = (query_data *)NULL;
+  char QueryType = QUERY_BOOLEAN;
+  char OutputType = QUERY_DOCNUMS;
+  char *LinePtr = (char *)NULL;
+
+  if (cur_cachenum == -1) return 0;
+  qd = dbcache[cur_cachenum].qd;
+  if (qd == NULL) return 0;
+  
+  ResetFileStats (qd);
+  qd->max_mem_in_use = qd->mem_in_use = 0;
+  qd->tot_hops_taken += qd->hops_taken;
+  qd->tot_num_of_ptrs += qd->num_of_ptrs;
+  qd->tot_num_of_accum += qd->num_of_accum;
+  qd->tot_num_of_terms += qd->num_of_terms;
+  qd->tot_num_of_ans += qd->num_of_ans;
+  qd->tot_text_idx_lookups += qd->text_idx_lookups;
+  qd->hops_taken = qd->num_of_ptrs = 0;
+  qd->num_of_accum = qd->num_of_ans = qd->num_of_terms = 0;
+  qd->text_idx_lookups = 0;
+  
+  LinePtr = ProcessCommands (line, qd);
+  if (CommandsErrorStr) {
+    fprintf (stderr, "%s\n", CommandsErrorStr);
+    return 0;
+  }
+  if (*LinePtr == '\0') return 1;
+  
+  FreeQueryDocs (qd);
+  
+  QueryType = get_query_type ();
+  OutputType = get_output_type ();
+  /* No point in hiliting words on a docnum query */
+  if (OutputType == OUTPUT_HILITE && QueryType == QUERY_DOCNUMS)
+    OutputType = OUTPUT_TEXT;
+  
+  switch (QueryType)
+    {
+    case QUERY_BOOLEAN:
+      {
+	char *maxdocs = (char *)NULL;
+	BooleanQueryInfo bqi;
+	maxdocs = GetDefEnv ("maxdocs", "all");
+	bqi.MaxDocsToRetrieve = strcmp (maxdocs, "all") ? atoi (maxdocs) : -1;
+        if (qd->sd->sdh.indexed)
+	  BooleanQuery (qd, line, &bqi, (BooleanEnv (GetEnv ("casefold"), 0) |
+					 (BooleanEnv (GetEnv ("stem"), 0) << 1)));
+	else
+	  BooleanQuery (qd, line, &bqi, qd->sd->sdh.stem_method);
+	/*	if (qd->sd->sdh.indexed) BooleanQuery (qd, line, &bqi, 3);
+	else BooleanQuery (qd, line, &bqi, qd->sd->sdh.stem_method); */
+	break;
+      }
+    case QUERY_APPROX:
+    case QUERY_RANKED:
+      {
+	char *maxdocs = (char *)NULL;
+	char *maxterms = (char *)NULL;
+	char *maxaccum = (char *)NULL;
+	RankedQueryInfo rqi;
+	maxdocs = GetDefEnv ("maxdocs", "all");
+	maxterms = GetDefEnv ("max_terms", "all");
+	maxaccum = GetDefEnv ("max_accumulators", "all");
+	rqi.Sort = BooleanEnv (GetEnv ("sorted_terms"), 0);
+	rqi.QueryFreqs = BooleanEnv (GetEnv ("qfreq"), 1);
+	rqi.Exact = QueryType == QUERY_RANKED;
+	rqi.MaxDocsToRetrieve = strcmp (maxdocs, "all") ? atoi (maxdocs) : -1;
+	rqi.MaxTerms = strcmp (maxterms, "all") ? atoi (maxterms) : -1;
+	rqi.MaxParasToRetrieve = rqi.MaxDocsToRetrieve;
+	if (qd->id->ifh.InvfLevel == 3 && GetEnv ("maxparas"))
+	  rqi.MaxParasToRetrieve = atoi (GetEnv ("maxparas"));
+	rqi.AccumMethod = toupper (*GetDefEnv ("accumulator_method", "A"));
+	rqi.MaxAccums = strcmp (maxaccum, "all") ? atoi (maxaccum) : -1;
+	rqi.HashTblSize = IntEnv (GetEnv ("hash_tbl_size"), 1000);
+	rqi.StopAtMaxAccum = BooleanEnv (GetEnv ("stop_at_max_accum"), 0);
+	rqi.skip_dump = GetEnv ("skip_dump");
+	RankedQuery (qd, line, &rqi);
+	break;
+      }
+    case QUERY_DOCNUMS:
+      {
+	DocnumsQuery (qd, line);
+	break;
+      }
+    }
+
+  return 1;
+}
+
+int mgq_numdocs(void)
+{
+  query_data *qd = NULL;
+  if (cur_cachenum == -1) return 0;
+  qd = dbcache[cur_cachenum].qd;
+  if (qd == NULL) return 0;
+
+  if (qd->DL) return qd->DL->num;
+  else return 0;
+}
+
+int mgq_numterms(void)
+{
+  query_data *qd = NULL;
+  if (cur_cachenum == -1) return 0;
+  qd = dbcache[cur_cachenum].qd;
+  if (qd == NULL) return 0;
+
+  if (qd->QTL) return qd->QTL->num;
+  else return 0;
+}
+
+int mgq_results(enum result_kinds kind,int skip,int howmany, int (*sender)(char *, int, int, float, void *), void *ptr)
+{
+  query_data *qd = NULL;
+  if (cur_cachenum == -1) return 0;
+  qd = dbcache[cur_cachenum].qd;
+  if (qd == NULL) return 0;
+
+  if (qd->DL) {
+    qd->doc_pos = 0;
+    MoreDocs(qd, kind, skip, howmany, sender, ptr);
+  }
+  return 0;
+}
+
+/* get all the terms that match wordstem using the current stemmer and */
+/* stemming method. The callback is the same style used by mgq_results */
+int mgq_equivterms (unsigned char *wordstem, int (*sender)(char *, int, int, float, void *),
+		    void *ptr) {
+  int stem_method = 0;
+  query_data *qd = NULL;
+  TermList *equivterms = NULL;  /* used for equivalent terms */
+
+  if (cur_cachenum == -1) return 0;
+  qd = dbcache[cur_cachenum].qd;
+  if (qd == NULL || wordstem == NULL || sender == NULL) return 0;
+
+  if (qd->sd->sdh.indexed) {
+    stem_method = BooleanEnv(GetEnv("casefold"),0) | (BooleanEnv(GetEnv("stem"),0) << 1);
+  } else {
+    stem_method = qd->sd->sdh.stem_method;
+  }
+
+  /* make the term list */
+  equivterms = MakeTermList (0);
+  
+  /* expand out this word */
+  if (FindWords (qd->sd, wordstem, stem_method, &equivterms) > 0) {
+    int i;
+    for (i=0; i < equivterms->num; i++) {
+      (* sender)((char *)(equivterms->TE[i].Word+1), equivterms->TE[i].Word[0], 
+		 equivterms->TE[i].Count, (float)0.0, ptr);
+    }
+  }
+
+  /* free the term list */
+  if (equivterms != NULL) FreeTermList (&equivterms);
+
+  return 0;
+}
+
+/* gets the total number of documents retrieved. If this is not available */
+/* it will set total_retrieved to 0 (even when it obviously isn't) */
+int mgq_docsretrieved (int *total_retrieved, int *is_approx) {
+  query_data *qd = NULL;
+
+  if (cur_cachenum == -1) return 0;
+  qd = dbcache[cur_cachenum].qd;
+  if (qd == NULL || total_retrieved == NULL || is_approx == NULL) return 0;
+
+  /* set default values */
+  *total_retrieved = 0;
+  *is_approx = 0;
+
+  if (qd->DL == NULL) return 0;
+
+  *total_retrieved = qd->DL->total_retrieved;
+  *is_approx = qd->DL->is_approx;
+
+  return 0;
+}
+
+
+/* use mgq_getmaxstemlen to determine the length of the word stems to pass */
+/* to mgq_stemword */
+int mgq_getmaxstemlen () {
+  return MAXSTEMLEN;
+}
+
+/* note: the stemming method and the stemmer come from the last query */
+/* "word" should be at least maxstemlen+1 long and it is a string that */
+/* starts with the string length */
+void mgq_stemword (unsigned char *word) {
+  int stem_method = 0;
+  query_data *qd = NULL;
+
+  if (cur_cachenum == -1) return;
+  qd = dbcache[cur_cachenum].qd;
+  if (qd == NULL || word == NULL) return;
+
+  if (qd->sd->sdh.indexed) {
+    stem_method = BooleanEnv(GetEnv("casefold"),0) | (BooleanEnv(GetEnv("stem"),0) << 1);
+  } else {
+    stem_method = qd->sd->sdh.stem_method;
+  }
+
+  stemmer (stem_method, qd->sd->sdh.stemmer_num, word);
+}
+
+
+
+int is_dbcache_full (void) {
+  init_dbcache ();
+  if (cache_numloaded >= MAXNUMDATABASEINFO) return 1;
+  return 0;
+}
+
+int load_database (char *collection, char *mgdir, 
+		   char *gensuffix, char *textsuffix) {
+  int i = 0;
+  query_data *qd = NULL;
+  /*  FILE *deb = NULL; */
+  init_dbcache ();
+
+  /* print out some debug information */
+/*  deb = fopen ("/home/rjmcnab/gsdl/etc/deb.txt", "a");
+  fprintf (deb, "\ncache_nextaccessnum: %i\n", cache_nextaccessnum);
+  fprintf (deb, "cache_numloaded: %i\n", cache_numloaded);
+  fprintf (deb, "cur_cachenum: %i\n", cur_cachenum);
+  fprintf (deb, "MAXNUMDATABASEINFO: %i\n\n", MAXNUMDATABASEINFO);
+  for (i=0; i<MAXNUMDATABASEINFO; i++) {
+    fprintf (deb, "Entry %i\n", i);
+    fprintf (deb, "  accessnum: %i\n", dbcache[i].accessnum);
+    fprintf (deb, "  collection: %s\n", dbcache[i].collection);
+    fprintf (deb, "  mgdir: %s\n", dbcache[i].mgdir);
+    fprintf (deb, "  gensuffix: %s\n", dbcache[i].gensuffix);
+    fprintf (deb, "  textsuffix: %s\n", dbcache[i].textsuffix);
+    fprintf (deb, "  qd: %x\n", (int)(dbcache[i].qd));
+  }
+  fclose (deb); */
+
+  /* search for the index */
+  i = search_gensuffix (gensuffix);
+  if (i >= 0) {
+    make_current (i);
+    return 1;
+  }
+
+  /* if there was a current database then the */
+  /* environment needs uninitialising */
+  make_current (-1);
+
+  /* get a free cache number */
+  i = get_free_dbcache ();
+  unload_database (i);
+
+  /* load the index */
+  qd = InitQuerySystem (mgdir, gensuffix, textsuffix, NULL);
+  if (qd == NULL) return 0;
+
+  /* cache this index */
+  cache_database (i, collection, mgdir, gensuffix, textsuffix, qd);
+
+  /* make this index current */
+  make_current (i);
+
+  return 1;
+}
+
+/* load_text_database tries to make an index of the */
+/* specified collection current */
+int load_text_database (char *collection) {
+  int i = 0;
+  init_dbcache ();
+
+  /* search for the index */
+  i = search_collect (collection);
+
+  /* return if none were found */
+  if (i < 0) return 0;
+  
+  /* make this index current */
+  make_current (i);
+  return 1;
+}
+
+void close_all_databases (void) {
+  int i = 0;
+  init_dbcache ();
+  
+  /* unload all active databases */
+  for (i=0; i<MAXNUMDATABASEINFO; i++) {
+    unload_database (i);
+  }
+
+  /* if there was a current database then the */
+  /* environment needs uninitialising */
+  make_current (-1);
+}
Index: /main/tags/2.25/gsdl/src/colservr/mgq.h
===================================================================
--- /main/tags/2.25/gsdl/src/colservr/mgq.h	(revision 21064)
+++ /main/tags/2.25/gsdl/src/colservr/mgq.h	(revision 21064)
@@ -0,0 +1,78 @@
+/**********************************************************************
+ *
+ * mgq.h -- 
+ * Copyright (C) 1999  The New Zealand Digital Library Project
+ *
+ * A component of the Greenstone digital library software
+ * from the New Zealand Digital Library Project at the
+ * University of Waikato, New Zealand.
+ *
+ * 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.
+ *
+ *********************************************************************/
+
+
+#ifndef MGQ_H
+#define MGQ_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+  
+enum result_kinds {
+  result_docs,      /* Return the documents found in last search */
+  result_docnums,   /* Return document id numbers and weights */
+  result_termfreqs, /* Return terms and frequencies */
+  result_terms      /* Return matching query terms */
+};
+
+int mgq_ask(char *line);
+int mgq_results(enum result_kinds kind, int skip, int howmany,
+		int (*sender)(char *, int, int, float, void *), void *ptr);
+int mgq_numdocs(void);
+int mgq_numterms(void);
+
+/* get all the terms that match wordstem using the current stemmer and */
+/* stemming method. The callback is the same style used by mgq_results */
+int mgq_equivterms (unsigned char *wordstem, int (*sender)(char *, int, int, float, void *),
+		    void *ptr);
+
+/* gets the total number of documents retrieved. If this is not available */
+/* it will set total_retrieved to 0 (even when it obviously isn't) */
+int mgq_docsretrieved (int *total_retrieved, int *is_approx);
+  
+/* use mgq_getmaxstemlen to determine the length of the word stems to pass */
+/* to mgq_stemword */
+int mgq_getmaxstemlen ();
+
+/* note: the stemming method and the stemmer come from the last query */
+/* "word" should be at least maxstemlen+1 long and it is a string that */
+/* starts with the string length */
+void mgq_stemword (unsigned char *word);
+
+  
+int is_dbcache_full (void);
+int load_database (char *collection, char *mgdir, char *gensuffix, char *textsuffix);
+int load_text_database (char *collection);
+void close_all_databases (void);
+
+
+#ifdef __cplusplus
+}
+#endif
+
+
+#endif
Index: /main/tags/2.25/gsdl/src/colservr/mgqueryfilter.cpp
===================================================================
--- /main/tags/2.25/gsdl/src/colservr/mgqueryfilter.cpp	(revision 21064)
+++ /main/tags/2.25/gsdl/src/colservr/mgqueryfilter.cpp	(revision 21064)
@@ -0,0 +1,509 @@
+/**********************************************************************
+ *
+ * mgqueryfilter.cpp -- implementation of queryfilter for old mg 
+ * Copyright (C) 1999  The New Zealand Digital Library Project
+ *
+ * A component of the Greenstone digital library software
+ * from the New Zealand Digital Library Project at the
+ * University of Waikato, New Zealand.
+ *
+ * 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.
+ *
+ * $Id$
+ *
+ *********************************************************************/
+
+/*
+   $Log$
+   Revision 1.1  2000/08/02 00:58:27  kjm18
+   mgpp incorporated. the old mgsearchclass and queryfilterclass are changed.
+   Have a base searchclass, from which mgsearchclass and mgppsearchclass inherit.
+   Have a base queryfilterclass, from which mgqueryfilterclass and
+   mgppqueryfilterclass inherit. librarymain in recpt should choose the appropriate
+   type (mg vs mgpp) for each collection.
+
+   Revision 1.21  1999/11/25 02:21:13  sjboddie
+   fixed bug in phrasematch stuff
+
+   Revision 1.20  1999/11/01 22:06:06  sjboddie
+   Added filter option to remove documents not matching a phrase match.
+   This used to be done in the receptionist.
+
+   Revision 1.19  1999/10/19 03:23:40  davidb
+   Collection building support through web pages
+   and internal and external link handling for collection documents
+
+   Revision 1.18  1999/09/22 03:43:18  sjboddie
+   Endresults queryfilter option may now take '-1' for 'all'
+
+   Revision 1.17  1999/09/21 12:01:07  sjboddie
+   added Maxdocs queryfilter option (which may be -1 for 'all')
+
+   Revision 1.16  1999/09/07 04:57:24  sjboddie
+   added gpl notice
+
+   Revision 1.15  1999/08/31 22:47:09  rjmcnab
+   Added matchmode option for some and all.
+
+   Revision 1.14  1999/07/16 03:42:21  sjboddie
+   changed isApprox
+
+   Revision 1.13  1999/07/16 00:17:06  sjboddie
+   got using phrasesearch for post-processing
+
+   Revision 1.12  1999/07/09 02:19:43  rjmcnab
+   Fixed a couple of compiler conflicts
+
+   Revision 1.11  1999/07/08 20:49:44  rjmcnab
+   Added result_num to the ResultDocInto_t structure.
+
+   Revision 1.10  1999/07/07 06:19:46  rjmcnab
+   Added ability to combine two or more independant queries.
+
+   Revision 1.9  1999/07/01 09:29:20  rjmcnab
+   Changes for better reporting of number documents which match a query. Changes
+   should still work as before with older versions of mg.
+
+   Revision 1.8  1999/07/01 03:59:54  rjmcnab
+   reduced MAXDOCS to 200 (more reasonable ???). I also added a virtual
+   method for post-processing the query.
+
+   Revision 1.7  1999/06/30 04:04:13  rjmcnab
+   made stemming functions available from mgsearch and made the stems
+   for the query terms available in queryinfo
+
+   Revision 1.6  1999/06/29 22:06:23  rjmcnab
+   Added a couple of fields to queryinfo to handle a special version
+   of mg.
+
+   Revision 1.5  1999/06/27 22:08:48  sjboddie
+   now check for defaultindex, defaultsubcollection, and defaultlanguage
+   entries in config files
+
+   Revision 1.4  1999/06/16 02:03:25  sjboddie
+   fixed bug in isApprox and set MAXDOCS to always be 500
+
+   Revision 1.3  1999/04/19 23:56:09  rjmcnab
+   Finished the gdbm metadata stuff
+
+   Revision 1.2  1999/04/12 03:45:03  rjmcnab
+   Finished the query filter.
+
+   Revision 1.1  1999/04/06 22:22:09  rjmcnab
+   Initial revision.
+
+ */
+
+
+#include "mgqueryfilter.h"
+#include "fileutil.h"
+#include "phrasesearch.h"
+#include <assert.h>
+#include "mgsearch.h"
+
+///////////////////////////////
+// methods for resultsorderer_t
+///////////////////////////////
+
+resultsorderer_t::resultsorderer_t() {
+  clear ();
+}
+
+void resultsorderer_t::clear() {
+  compare_phrase_match = false;
+  compare_terms_match = false;
+  compare_doc_weight = true;
+
+  docset = NULL;
+}
+
+bool resultsorderer_t::operator()(const int &t1, const int &t2) const {
+  if (docset == NULL) return t1>t2;
+
+  docresultmap::iterator t1_here = docset->find(t1);
+  docresultmap::iterator t2_here = docset->find(t2);
+  docresultmap::iterator end = docset->end();
+
+  // sort all the document numbers not in the document set to
+  // the end of the list
+  if (t1_here == end) {
+    if (t2_here == end) return t1>t2;
+    else return true;
+  } else if (t2_here == end) return false;
+  
+  if (compare_phrase_match) {
+    if ((*t1_here).second.num_phrase_match > (*t2_here).second.num_phrase_match) return true;
+    if ((*t1_here).second.num_phrase_match < (*t2_here).second.num_phrase_match) return false;
+  }
+
+  if (compare_terms_match) {
+    if ((*t1_here).second.num_query_terms_matched > (*t2_here).second.num_query_terms_matched) return true;
+    if ((*t1_here).second.num_query_terms_matched < (*t2_here).second.num_query_terms_matched) return false;
+  }
+
+  if (compare_doc_weight) {
+    if ((*t1_here).second.docweight > (*t2_here).second.docweight) return true;
+    if ((*t1_here).second.docweight < (*t2_here).second.docweight) return false;
+  }
+
+  return t1>t2;
+}
+
+
+
+
+/////////////////////////////////
+// functions for mgqueryfilterclass
+/////////////////////////////////
+
+// loads up phrases data structure with any phrases (that's the quoted bits)
+// occuring in the querystring
+void mgqueryfilterclass::get_phrase_terms (const text_t &querystring, 
+					 const termfreqclassarray &orgterms,
+					 vector<termfreqclassarray> &phrases) {
+
+  text_t::const_iterator here = querystring.begin();
+  text_t::const_iterator end = querystring.end();
+
+  termfreqclassarray tmpterms;
+
+  int termcount = 0;
+  bool foundquote = false;
+  bool foundbreak = false;
+  bool start = true;
+  while (here != end) {
+    if (*here == '\"') {
+      if (foundquote) {
+	if (!foundbreak && !start) {
+	  tmpterms.push_back (orgterms[termcount]);
+	  termcount ++;
+	}
+	if (tmpterms.size() > 1) {
+	  phrases.push_back (tmpterms);
+	  tmpterms.erase (tmpterms.begin(), tmpterms.end());
+	}
+	foundquote = false;
+	foundbreak = true;
+      } else foundquote = true;
+    } else if (!is_unicode_letdig(*here)) {
+      // found a break between terms
+      if (!foundbreak && !start) {
+	if (foundquote)
+	  tmpterms.push_back (orgterms[termcount]);
+	termcount ++;
+      }
+      foundbreak = true;
+    } else {
+      start = false;
+      foundbreak = false;
+    }      
+    here++;
+  }
+}
+
+// do aditional query processing
+void mgqueryfilterclass::post_process (const queryparamclass &queryparams, 
+				     queryresultsclass &queryresults) {
+
+  // post-process the results if needed
+  if (queryresults.orgterms.size() > 1 && !queryresults.docs.docset.empty()) {
+
+    // get the terms between quotes (if any)
+    vector<termfreqclassarray> phrases;
+    get_phrase_terms (queryparams.querystring, queryresults.orgterms, phrases);
+
+    num_phrases = phrases.size();
+    if (num_phrases > 0) {
+
+      // get the long version of the index
+      text_t longindex;
+      indexmap.to2from (queryparams.index, longindex);
+      
+      vector<termfreqclassarray>::const_iterator this_phrase = phrases.begin();
+      vector<termfreqclassarray>::const_iterator end_phrase = phrases.end();
+
+      while (this_phrase != end_phrase) {
+
+	// process each of the matched documents
+	docresultmap::iterator docs_here = queryresults.docs.docset.begin();
+	docresultmap::iterator docs_end = queryresults.docs.docset.end();
+	while (docs_here != docs_end) {
+	  if (OID_phrase_search (*((mgsearchclass*)mgsearchptr), *gdbmptr, queryparams.index,
+				 queryparams.subcollection, queryparams.language, 
+				 longindex, queryparams.collection, *this_phrase,
+				 (*docs_here).second.docnum)) {
+	    (*docs_here).second.num_phrase_match++;
+	  }
+	
+	  docs_here++;
+	}
+	this_phrase++;
+      }
+    }
+  }
+}
+
+
+// do query that might involve multiple sub queries
+// mgsearchptr and gdbmptr are assumed to be valid
+void mgqueryfilterclass::do_multi_query (const FilterRequest_t &request,
+				       const vector<queryparamclass> &query_params,
+				       queryresultsclass &multiresults,
+				       comerror_t &err, ostream &logout) {
+  outconvertclass text_t2ascii;
+
+  err = noError;
+  mgsearchptr->setcollectdir (collectdir);
+  multiresults.clear();
+  
+  vector<queryparamclass>::const_iterator query_here = query_params.begin();
+  vector<queryparamclass>::const_iterator query_end = query_params.end();
+  while (query_here != query_end) {
+    queryresultsclass thisqueryresults;
+    
+    if (!mgsearchptr->search(*query_here, thisqueryresults)) {
+      // most likely a system problem
+      logout << text_t2ascii
+	     << "system problem: could not do search with mg for index \""
+	     << (*query_here).index << (*query_here).subcollection
+	     << (*query_here).language << "\".\n\n";
+      err = systemProblem;
+      return;
+    }
+
+    // combine the results
+    if (need_matching_docs (request.filterResultOptions)) {
+      // post-process the results if needed
+      if (!thisqueryresults.postprocessed && thisqueryresults.orgterms.size() > 1 &&
+	  !thisqueryresults.docs.docset.empty()) {
+	post_process (*query_here, thisqueryresults);
+	thisqueryresults.postprocessed = true;
+	multiresults.postprocessed = true;
+      }
+      
+      if (query_params.size() == 1) {
+	multiresults.docs = thisqueryresults.docs; // just one set of results
+	multiresults.docs_matched = thisqueryresults.docs_matched;
+	multiresults.is_approx = thisqueryresults.is_approx;
+	
+      } else {
+	if ((*query_here).combinequery == "and") {
+	  multiresults.docs.combine_and (thisqueryresults.docs);
+	} else if ((*query_here).combinequery == "or") {
+	  multiresults.docs.combine_or (thisqueryresults.docs);
+	} else if ((*query_here).combinequery == "not") {
+	  multiresults.docs.combine_not (thisqueryresults.docs);
+	}
+	multiresults.docs_matched = multiresults.docs.docset.size();
+	multiresults.is_approx = Exact;
+      }
+    }
+
+    // combine the term information 
+    if (need_term_info (request.filterResultOptions)) {
+      // append the terms
+      multiresults.orgterms.insert(multiresults.orgterms.end(),
+				   thisqueryresults.orgterms.begin(),
+				   thisqueryresults.orgterms.end());
+
+      // add the term variants
+      text_tset::iterator termvar_here = thisqueryresults.termvariants.begin();
+      text_tset::iterator termvar_end = thisqueryresults.termvariants.end();
+      while (termvar_here != termvar_end) {
+	multiresults.termvariants.insert(*termvar_here);
+	termvar_here++;
+      }
+    }
+   
+    query_here++;
+  }
+
+  // sort and unique the query terms
+  multiresults.sortuniqqueryterms ();
+}
+
+
+void mgqueryfilterclass::sort_doc_results (const FilterRequest_t &/*request*/,
+					 docresultsclass &docs) {
+  resultsorderer_t resultsorderer;
+  resultsorderer.compare_phrase_match = true;
+  resultsorderer.docset = &(docs.docset);
+
+  // first get a list of document numbers
+  docs.docnum_order();
+
+  sort (docs.docorder.begin(), docs.docorder.end(), resultsorderer);
+}
+
+
+
+mgqueryfilterclass::mgqueryfilterclass () 
+  :queryfilterclass() {
+
+  num_phrases = 0;
+
+}
+
+mgqueryfilterclass::~mgqueryfilterclass () {
+}
+
+void mgqueryfilterclass::filter (const FilterRequest_t &request,
+			       FilterResponse_t &response,
+			       comerror_t &err, ostream &logout) {
+  outconvertclass text_t2ascii;
+
+  response.clear ();
+  err = noError;
+  if (gdbmptr == NULL) {
+    // most likely a configuration problem
+    logout << text_t2ascii 
+	   << "configuration error: mgqueryfilter contains a null gdbmclass\n\n";
+    err = configurationError;
+    return;
+  }
+  if (mgsearchptr == NULL) {
+    // most likely a configuration problem
+    logout << text_t2ascii 
+	   << "configuration error: mgqueryfilter contains a null mgsearchclass\n\n";
+    err = configurationError;
+    return;
+  }
+
+  // open the database
+  gdbmptr->setlogout(&logout);
+  if (!gdbmptr->opendatabase (gdbm_filename, GDBM_READER, 100, false)) {
+    // most likely a system problem (we have already checked that the
+    // gdbm database exists)
+    logout << text_t2ascii
+	   << "system problem: open on gdbm database \""
+	   << gdbm_filename << "\" failed\n\n";
+    err = systemProblem;
+    return;
+  }
+
+  // get the query parameters
+  int startresults = filterOptions["StartResults"].defaultValue.getint();
+  int endresults = filterOptions["EndResults"].defaultValue.getint();
+  text_t phrasematch = filterOptions["PhraseMatch"].defaultValue;
+
+  vector<queryparamclass> queryfilterparams;
+  parse_query_params (request, queryfilterparams, startresults, 
+		      endresults, phrasematch, logout);  
+  
+  // do query
+  queryresultsclass queryresults;
+  do_multi_query (request, queryfilterparams, queryresults, err, logout);
+  if (err != noError) return;
+  
+  // assemble document results
+  if (need_matching_docs (request.filterResultOptions)) {
+    // sort the query results
+    sort_doc_results (request, queryresults.docs);
+    
+    int resultnum = 1;
+    ResultDocInfo_t resultdoc;
+    text_t trans_OID;
+    vector<int>::iterator docorder_here = queryresults.docs.docorder.begin();
+    vector<int>::iterator docorder_end = queryresults.docs.docorder.end();
+
+    if (endresults == -1) endresults = MAXNUMDOCS;
+    while (docorder_here != docorder_end) {
+      if (resultnum > endresults) break;
+      
+      // translate the document number
+      if (!translate(gdbmptr, *docorder_here, trans_OID)) {
+	logout << text_t2ascii
+	       << "warning: could not translate mg document number \""
+	       << *docorder_here << "\"to OID.\n\n";
+	
+      } else {
+	docresultmap::iterator docset_here = queryresults.docs.docset.find (*docorder_here);
+	
+	// documents containing matching phrases will be sorted to the top so
+	// we can break out once we're past those that match the PhraseMatch
+	// option -- "all_phrases" = return only those documents containing all
+	//	                     phrases in query string
+	//           "some_phrases" = return only those documents containing 
+	//                            at least 1 of the phrases in the document
+	//           "all_docs" = return all documents regardless
+	if (num_phrases > 0) {
+	  if ((phrasematch == "all_phrases") && ((*docset_here).second.num_phrase_match < num_phrases)) {
+	    queryresults.docs_matched = response.docInfo.size();
+	    break;
+	  }
+	  if ((phrasematch == "some_phrases") && ((*docset_here).second.num_phrase_match < 1)) {
+	    queryresults.docs_matched = response.docInfo.size();
+	    break;
+	  }
+	}
+
+	// see if there is a result for this number,
+	// if it is in the request set (or the request set is empty)
+	if (docset_here != queryresults.docs.docset.end() &&
+	    (request.docSet.empty() || in_set(request.docSet, trans_OID))) {
+	  if (resultnum >= startresults) {
+	    // add this document
+	    resultdoc.OID = trans_OID;
+	    resultdoc.result_num = resultnum;
+	    resultdoc.ranking = (int)((*docset_here).second.docweight * 10000.0 + 0.5);
+
+	    // these next two are not available on all versions of mg
+	    resultdoc.num_terms_matched = (*docset_here).second.num_query_terms_matched; 
+	    resultdoc.num_phrase_match = (*docset_here).second.num_phrase_match;
+	    
+	    response.docInfo.push_back (resultdoc);
+	  }
+	  
+	  resultnum++;
+	}
+      }
+      
+      docorder_here++;
+    }
+  }
+
+  // assemble the term results
+  if (need_term_info(request.filterResultOptions)) {
+    // note: the terms have already been sorted and uniqued
+
+    TermInfo_t terminfo;
+    bool terms_first = true;
+    termfreqclassarray::iterator terms_here = queryresults.terms.begin();
+    termfreqclassarray::iterator terms_end = queryresults.terms.end();
+
+    while (terms_here != terms_end) {
+      terminfo.clear();
+      terminfo.term = (*terms_here).termstr;
+      terminfo.freq = (*terms_here).termfreq;
+      if (terms_first) {
+	text_tset::iterator termvariants_here = queryresults.termvariants.begin();
+	text_tset::iterator termvariants_end = queryresults.termvariants.end();
+	while (termvariants_here != termvariants_end) {
+	  terminfo.matchTerms.push_back (*termvariants_here);
+	  termvariants_here++;
+	}
+      }
+      terms_first = false;
+
+      response.termInfo.push_back (terminfo);
+
+      terms_here++;
+    }
+  }
+
+  response.numDocs = queryresults.docs_matched;
+  response.isApprox = queryresults.is_approx;
+}
+
Index: /main/tags/2.25/gsdl/src/colservr/mgqueryfilter.h
===================================================================
--- /main/tags/2.25/gsdl/src/colservr/mgqueryfilter.h	(revision 21064)
+++ /main/tags/2.25/gsdl/src/colservr/mgqueryfilter.h	(revision 21064)
@@ -0,0 +1,83 @@
+/**********************************************************************
+ *
+ * mgqueryfilter.h -- queryfilter for old mg
+ * Copyright (C) 1999  The New Zealand Digital Library Project
+ *
+ * A component of the Greenstone digital library software
+ * from the New Zealand Digital Library Project at the
+ * University of Waikato, New Zealand.
+ *
+ * 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.
+ *
+ * $Id$
+ *
+ *********************************************************************/
+
+
+#ifndef MGQUERYFILTER_H
+#define MGQUERYFILTER_H
+
+#include "queryfilter.h"
+
+// resultsorderer_t is used to sort the query results
+struct resultsorderer_t {
+  bool compare_phrase_match;
+  bool compare_terms_match;
+  bool compare_doc_weight;
+  docresultmap *docset;
+
+  resultsorderer_t();
+  void clear();
+  bool operator()(const int &t1, const int &t2) const;
+};
+
+
+
+class mgqueryfilterclass : public queryfilterclass {
+protected:
+  
+  int num_phrases;
+
+  void get_phrase_terms (const text_t &querystring, 
+			 const termfreqclassarray &orgterms,
+			 vector<termfreqclassarray> &phrases);
+
+  // do aditional query processing
+  virtual void post_process (const queryparamclass &queryparams,
+			     queryresultsclass &queryresults);
+
+  // do query that might involve multiple sub queries
+  // mgsearchptr and gdbmptr are assumed to be valid
+  void do_multi_query (const FilterRequest_t &request,
+		       const vector<queryparamclass> &query_params,
+		       queryresultsclass &multiresults,
+		       comerror_t &err, ostream &logout);
+
+  virtual void sort_doc_results (const FilterRequest_t &request,
+				 docresultsclass &docs);
+
+  
+public:
+  mgqueryfilterclass ();
+  virtual ~mgqueryfilterclass ();
+
+  void filter (const FilterRequest_t &request,
+	       FilterResponse_t &response,
+	       comerror_t &err, ostream &logout);
+};
+
+
+#endif
+
Index: /main/tags/2.25/gsdl/src/colservr/mgsearch.cpp
===================================================================
--- /main/tags/2.25/gsdl/src/colservr/mgsearch.cpp	(revision 21064)
+++ /main/tags/2.25/gsdl/src/colservr/mgsearch.cpp	(revision 21064)
@@ -0,0 +1,511 @@
+/**********************************************************************
+ *
+ * mgsearch.cpp -- 
+ * Copyright (C) 1999  The New Zealand Digital Library Project
+ *
+ * A component of the Greenstone digital library software
+ * from the New Zealand Digital Library Project at the
+ * University of Waikato, New Zealand.
+ *
+ * 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.
+ *
+ *********************************************************************/
+
+#include "gsdlconf.h"
+#include "mgsearch.h"
+#include "fileutil.h"
+
+#include <string.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <ctype.h>
+
+#if defined(GSDL_USE_OBJECTSPACE)
+#  include <ospace\std\iostream>
+#elif defined(GSDL_USE_IOS_H)
+#  include <iostream.h>
+#else
+#  include <iostream>
+#endif
+
+#if defined(__WIN32__)
+// gdbm stuff
+#  include "autoconf.h"
+#  include "systems.h"
+#  include "gdbmconst.h"
+#  include "gdbm.h"
+#else
+#  include <gdbm.h>
+#endif
+
+  
+#include <assert.h>
+
+#include "mgq.h"
+// #include "locateinfo.h"
+#include "gsdlunicode.h"
+#include "unitool.h"
+
+
+/////////////
+// globals //
+/////////////
+
+static char *tempdoc = NULL;
+static int templen = 0;
+
+
+//////////////////////
+// useful functions //
+//////////////////////
+
+
+// input and output are in utf8
+text_t mgsearch_stemword (const text_t &word) {
+  // allocate working stem space
+  int maxstemlen = mgq_getmaxstemlen ();
+  unsigned char *word_stem = new unsigned char [maxstemlen + 2];
+  if (word_stem == NULL) return "";
+
+  // copy word to word_stem
+  int len = 0;
+  text_t::const_iterator here = word.begin();
+  text_t::const_iterator end = word.end();
+  while (len < maxstemlen && here != end) {
+    word_stem[len+1] = (unsigned char)(*here);
+    len++; here++;
+  }
+  word_stem[len+1] = '\0';
+  word_stem[0] = len;
+
+  mgq_stemword (word_stem);
+
+  // copy word_stem back to tempstr
+  text_t tempstr;
+  tempstr.setcarr((char *)(&word_stem[1]), word_stem[0]);
+
+  delete [] word_stem;
+  
+  return tempstr;
+}
+
+
+
+////////////////////////
+// callback functions //
+////////////////////////
+
+// This routine is called for each document found in a search
+// it assumes that cache_num is set up correctly to point to
+// a suitable result cache
+int ourquerycallback(char * /*UDoc*/, int /*ULen*/, int DocNum, 
+		     float Weight, void *info) {
+
+  
+  queryresultsclass *queryresults = (queryresultsclass * )info;
+
+  // append this entry to the document results
+  docresultclass docresult;
+  docresult.docnum = DocNum;
+  docresult.num_query_terms_matched = (int)(Weight/100.0); // will always be 0 on some versions of mg...
+  docresult.docweight = Weight - docresult.num_query_terms_matched*100;
+  
+  queryresults->docs.docset[DocNum] = docresult;
+  queryresults->docs.docorder.push_back(DocNum);
+  
+  return 0;
+}
+
+int termequivcallback(char *Word, int ULen,  int /*Freq*/, 
+		      float /*Weight*/,  void *info) {
+  text_tset *equivterms = (text_tset *)info;
+  if (equivterms == NULL) return 0;
+
+  text_t thisterm;
+  thisterm.setcarr(Word, ULen);
+
+  equivterms->insert(thisterm);
+  
+  return 0;
+}
+
+
+void mgsearch_equivterms (const text_t &word, text_tset &equivterms) {
+  // allocate working stem space
+  int maxstemlen = mgq_getmaxstemlen ();
+  unsigned char *word_stem = new unsigned char [maxstemlen + 2];
+  if (word_stem == NULL) return;
+
+  // copy word to word_stem
+  int len = 0;
+  text_t::const_iterator here = word.begin();
+  text_t::const_iterator end = word.end();
+  while (len < maxstemlen && here != end) {
+    word_stem[len+1] = (unsigned char)(*here);
+    len++; here++;
+  }
+  word_stem[len+1] = '\0';
+  word_stem[0] = len;
+
+  // get the equivalent terms
+  mgq_equivterms (word_stem, termequivcallback, (void *)(&equivterms));
+  
+  delete [] word_stem;
+
+  return;
+}
+
+  text_tset utf8equivterms; // kept as utf8 string for fast matching
+
+
+// This callback is called once for each term in the query
+int termfreqcallback(char *Word, int ULen,  int Freq, 
+		     float /*Weight*/,  void *info) {
+  queryresultsclass *queryresults = (queryresultsclass *)info;
+  if (queryresults == NULL) return 0;
+
+  text_t term;
+  term.setcarr(Word, ULen);
+  termfreqclass termfreq;
+
+  termfreq.termstr = to_uni(term);
+  text_t utf8termstem = mgsearch_stemword (term);
+  termfreq.termstemstr = to_uni (utf8termstem);
+
+  mgsearch_equivterms (utf8termstem, termfreq.utf8equivterms);
+  
+  termfreq.termfreq = Freq;
+  queryresults->orgterms.push_back(termfreq);
+  
+  return 0;
+}
+
+// this callback is called once for each variation of each term
+int termvariantscallback(char *Word, int ULen, int /*Freq*/,
+			 float /*Weight*/, void *info) {
+
+  text_t term;
+  term.setcarr(Word, ULen);
+  queryresultsclass *queryresults = (queryresultsclass *)info;
+  queryresults->termvariants.insert(to_uni(term));
+
+  return 0;
+}
+
+// This callback is for getting document text
+int doctextcallback(char *Doc, int ULen,  int /*Freq*/, 
+		    float /*Weight*/,  void * /*info*/) {
+  tempdoc = Doc;
+  templen = ULen;
+  
+  return 0;
+}
+
+
+static text_t getindexsuffix (const text_t &collection, 
+			      const text_t &index) {
+
+  text_t indexsuffix = "index";  
+  indexsuffix = filename_cat (indexsuffix, index);
+  indexsuffix = filename_cat (indexsuffix, collection);
+  return indexsuffix;
+}
+
+
+
+
+////////////////////
+// mgsearch class //
+////////////////////
+
+mgsearchclass::mgsearchclass ()
+  : searchclass() {
+ 
+}
+
+mgsearchclass::~mgsearchclass () 
+{
+  if (cache != NULL) 
+    {
+      delete cache;
+      cache = NULL;
+    }
+}
+
+// you only need to use this function before doing any stemming
+// casefolding and stemming will be set if values for them are
+// provided (0 or 1).
+// makeindexcurrent returns true if it was able to load the database
+bool mgsearchclass::makeindexcurrent (const text_t &index,
+				      const text_t &subcollection,
+				      const text_t &language,
+				      const text_t &collection,
+				      int casefolding,
+				      int stemming) {
+  bool databaseloaded = true;
+
+  // get the names of the collection, index and text suffixes
+  char *ccollection = collection.getcstr();
+  assert (ccollection != NULL);
+  char *idxsuffix = (getindexsuffix (collection, (index+subcollection+language))).getcstr();
+  assert (idxsuffix != NULL);
+  char *txtsuffix = (getindexsuffix (collection, "text")).getcstr();
+  assert (txtsuffix != NULL);
+
+#ifdef __WIN32__
+  char *ccollectdir = (collectdir+"\\").getcstr(); assert (ccollectdir != NULL);
+#else
+  char *ccollectdir = collectdir.getcstr(); assert (ccollectdir != NULL);
+#endif
+
+  if (load_database(ccollection, ccollectdir, idxsuffix, txtsuffix)) {
+    if (casefolding == 0) mgq_ask(".set casefold off");
+    else if (casefolding > 0) mgq_ask(".set casefold on");
+    if (stemming == 0) mgq_ask(".set stem off");
+    else if (stemming > 0) mgq_ask(".set stem on");
+    
+  } else databaseloaded = false;
+
+  // free up the c strings
+  delete ccollection;
+  delete idxsuffix;
+  delete txtsuffix;
+  delete ccollectdir;
+
+  return databaseloaded;
+}
+
+
+// stem word uses the values set in the last call to makeindexcurrent
+// to stem the word. It is assumed that word is in unicode
+text_t mgsearchclass::stemword (const text_t &word) {
+  return to_uni (mgsearch_stemword (to_utf8 (word)));
+}
+
+text_t mgsearchclass::stemword (text_t::const_iterator here, text_t::const_iterator end) {
+  return to_uni (mgsearch_stemword (to_utf8 (here, end)));
+}
+
+
+bool mgsearchclass::search(const queryparamclass &queryparams, 
+			   queryresultsclass &queryresults) {
+  //  assert (cache != NULL);
+
+  queryresults.clear();
+  cerr << "mgsearch start of search"<<endl;
+  // first check the cache
+  if (cache != NULL) {
+    if (cache->find(queryparams, queryresults)) return true;
+  }
+  // make sure there is a query to be processed
+  if (!has_unicode_letdig(queryparams.querystring)) return true;
+
+  if (makeindexcurrent (queryparams.index, queryparams.subcollection,
+			queryparams.language, queryparams.collection)) {
+    cerr << "made index current "<<endl;
+    setsearchmode (queryparams);
+    submitquery (queryparams);
+    getresults (queryparams, queryresults);
+    cerr << "got results"<<endl;
+    return true;
+  }
+
+  return false;
+}
+
+
+void mgsearchclass::setsearchmode (const queryparamclass &queryparams)
+{
+  mgq_ask(".set expert true");
+  mgq_ask(".set sorted_terms true");
+  mgq_ask(".set accumulator_method list");
+  mgq_ask(".set max_accumulators 500000");
+  mgq_ask(".set maxparas 500000");
+  mgq_ask(".set verbatim true");
+  mgq_ask(".unset skip_dump");
+  mgq_ask(".set mode docnums");
+
+  switch (queryparams.search_type) 
+    {
+    case 0: mgq_ask(".set query boolean");  break;
+    case 1:  mgq_ask(".set query ranked"); break;
+    }
+  switch (queryparams.casefolding) 
+    {
+    case 1: mgq_ask(".set casefold on");  break;
+    case 0: mgq_ask(".set casefold off"); break;
+    }
+  switch (queryparams.stemming) 
+    {
+    case 1: mgq_ask(".set stem on");  break;
+    case 0: mgq_ask(".set stem off"); break;
+    }
+  mgq_ask(".set heads_length 150");
+  
+  if (queryparams.maxdocs == -1) {
+    mgq_ask(".set maxdocs all");
+  } else {
+    char maxdocstr[32];
+    sprintf(maxdocstr, ".set maxdocs %i", queryparams.maxdocs);
+    mgq_ask(maxdocstr);
+  }
+}
+
+
+void mgsearchclass::submitquery (const queryparamclass &queryparams)
+{
+  // sort out the query string
+  text_t ttquerystring = queryparams.querystring;
+  filterquery (ttquerystring);
+  char *querystring = to_utf8(ttquerystring).getcstr();
+  
+  // submit the query
+  mgq_ask(querystring);
+
+  delete querystring;
+}
+
+
+void mgsearchclass::getresults (const queryparamclass &queryparams,
+				queryresultsclass &queryresults) {
+
+  int howmany = queryparams.maxdocs;
+  if (howmany == -1) howmany = MAXNUMDOCS;
+  mgq_results(result_docnums, 0, howmany, 
+	      ourquerycallback, (void *)(&queryresults));
+  
+  // get the term frequencies
+  mgq_results(result_termfreqs, 0, MAXNUMTERMS, 
+	      termfreqcallback, (void *)(&queryresults));
+  queryresults.sortuniqqueryterms();
+
+  // get term variants 
+  mgq_results(result_terms, 0, MAXNUMTERMS,
+              termvariantscallback, (void *)(&queryresults));
+
+  // get the number of documents retrieved
+  int total_retrieved = 0, is_approx = 0;
+  mgq_docsretrieved (&total_retrieved, &is_approx);
+
+  if (total_retrieved == 0) {
+    // not available (or really was zero)
+    queryresults.docs_matched = queryresults.docs.docset.size();
+    if ((queryparams.maxdocs == -1) ||
+	(queryresults.docs_matched < queryparams.maxdocs))
+      queryresults.is_approx = Exact;
+    else
+      queryresults.is_approx = MoreThan;
+  } else {
+    queryresults.docs_matched = total_retrieved;
+    if (is_approx) queryresults.is_approx = Approximate;
+    else queryresults.is_approx = Exact;
+  }
+}
+
+void mgsearchclass::filterquery (text_t &ttquerystring) {
+  text_t::iterator ithere = ttquerystring.begin ();
+  text_t::iterator itend = ttquerystring.end ();
+  
+  // remove all non alphanumeric characters (except
+  // boolean operators
+  while (ithere != itend) {
+    if ((!is_unicode_letdig(*ithere)) && (*ithere != '!') &&
+	(*ithere != '&') && (*ithere != '|') && (*ithere != '(') &&
+	(*ithere != ')')) (*ithere) = ' ';
+    ithere++;
+  }
+}
+
+
+// the document text for 'docnum' is placed in 'output'
+// docTargetDocument returns 'true' if it was able to
+// try to get a document
+// collection is needed to see if an index from the 
+// collection is loaded. If no index has been loaded
+// defaultindex is needed to load one
+bool mgsearchclass::docTargetDocument(const text_t &defaultindex,
+				      const text_t &defaultsubcollection,
+				      const text_t &defaultlanguage,
+				      const text_t &collection,
+				      int docnum,
+				      text_t &output) {
+  output.clear();
+
+  // get the mg version of the document
+  char *mgdoc = NULL;
+  int doclen = 0;
+  if (!mgdocument (defaultindex, defaultsubcollection, defaultlanguage,
+		   collection, docnum, mgdoc, doclen)) return false;
+  if (mgdoc == NULL) return false;
+
+  // replace all control-Cs with spaces
+  char *mgdoc_here = mgdoc;
+  char *mgdoc_end = mgdoc + doclen;
+  while (mgdoc_here < mgdoc_end) {
+    if (*mgdoc_here == '\x3') *mgdoc_here = ' ';
+    mgdoc_here++;
+  }
+
+  // convert this document to unicode
+  utf8inconvertclass inconvert;
+  convertclass::status_t status;
+  inconvert.reset ();
+  inconvert.setinput (mgdoc, doclen);
+  inconvert.convert (output, status);
+
+  return true;
+}
+
+
+bool mgsearchclass::mgdocument (const text_t &defaultindex, 
+				const text_t &defaultsubcollection,
+				const text_t &defaultlanguage,
+				const text_t &collection,
+				int docnum,
+				char *&UDoc, int &ULen) {
+  int databaseloaded = 0;
+
+  UDoc = NULL; ULen = 0;
+  
+  // see if we can make an appropriate database current
+//    char *ccollection = collection.getcstr();
+//    assert (ccollection != NULL);
+//    databaseloaded = load_text_database (ccollection);
+//    delete ccollection;
+  
+  // try and load the database
+//    if (!databaseloaded)
+  databaseloaded = makeindexcurrent (defaultindex, defaultsubcollection,
+				     defaultlanguage, collection);
+  
+  if (databaseloaded) {
+    // retrieve the document from mg
+    char docstr[32];
+    sprintf(docstr, "%i", docnum);
+    
+    mgq_ask(".set mode text");
+    mgq_ask(".set query docnums");
+    mgq_ask(docstr);
+
+    tempdoc = NULL;
+    templen = 0;
+    mgq_results (result_docs, 0, 1, doctextcallback, (void *)NULL);
+    UDoc = tempdoc;
+    ULen = templen;
+  }
+
+  return (bool)databaseloaded;
+}
+
Index: /main/tags/2.25/gsdl/src/colservr/mgsearch.h
===================================================================
--- /main/tags/2.25/gsdl/src/colservr/mgsearch.h	(revision 21064)
+++ /main/tags/2.25/gsdl/src/colservr/mgsearch.h	(revision 21064)
@@ -0,0 +1,89 @@
+/**********************************************************************
+ *
+ * mgsearch.h --  implementation of search for old versions of mg
+ * Copyright (C) 1999  The New Zealand Digital Library Project
+ *
+ * A component of the Greenstone digital library software
+ * from the New Zealand Digital Library Project at the
+ * University of Waikato, New Zealand.
+ *
+ * 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.
+ *
+ *********************************************************************/
+
+
+#ifndef MGSEARCH_H
+#define MGSEARCH_H
+
+
+#include "search.h"
+
+class mgsearchclass : public searchclass {
+public:
+  mgsearchclass ();
+  virtual ~mgsearchclass ();
+
+  // you only need to use this function before doing any stemming
+  // casefolding and stemming will be set if values for them are
+  // provided (0 or 1).
+  // makeindexcurrent returns true if it was able to load the database
+  bool makeindexcurrent (const text_t &index, const text_t &subcollection,
+			 const text_t &language, const text_t &collection,
+			 int casefolding = -1, int stemming = -1);
+
+  // stem word uses the values set in the last call to makeindexcurrent
+  // to stem the word. It is assumed that word is in unicode
+  text_t stemword (const text_t &word);
+  text_t stemword (text_t::const_iterator here, text_t::const_iterator end);
+  
+  // the search results are returned in queryresults
+  // search returns 'true' if it was able to do a search
+   bool search(const queryparamclass &queryparams, 
+	      queryresultsclass &queryresults);
+  
+  // the document text for 'docnum' is placed in 'output'
+  // docTargetDocument returns 'true' if it was able to
+  // try to get a document
+  // collection is needed to see if an index from the 
+  // collection is loaded. If no index has been loaded
+  // defaultindex is needed to load one
+  bool docTargetDocument(const text_t &defaultindex,
+			 const text_t &defaultsubcollection,
+			 const text_t &defaultlanguage,
+			 const text_t &collection,
+			 int docnum,
+			 text_t &output);
+
+  // same as docTargetDocument except the document is returned
+  // in its raw form. UDoc remains the property of mg and may
+  // be destroyed on the next call to mg.
+  bool mgdocument (const text_t &defaultindex,
+		   const text_t &defaultsubcollection,
+		   const text_t &defaultlanguage,
+		   const text_t &collection,
+		   int docnum,
+		   char *&UDoc, int &ULen);
+
+protected:
+
+  void setsearchmode (const queryparamclass &queryparams);
+  void submitquery (const queryparamclass &queryparams);
+  void getresults (const queryparamclass &queryparams, queryresultsclass &queryresults);
+
+  virtual void filterquery (text_t &ttquerystring);
+};
+
+
+#endif
Index: /main/tags/2.25/gsdl/src/colservr/phrasequeryfilter.cpp
===================================================================
--- /main/tags/2.25/gsdl/src/colservr/phrasequeryfilter.cpp	(revision 21064)
+++ /main/tags/2.25/gsdl/src/colservr/phrasequeryfilter.cpp	(revision 21064)
@@ -0,0 +1,84 @@
+/**********************************************************************
+ *
+ * phrasequeryfilter.cpp -- 
+ * Copyright (C) 1999  DigiLib Systems Limited, New Zealand
+ *
+ * A component of the Greenstone digital library software
+ * from the New Zealand Digital Library Project at the
+ * University of Waikato, New Zealand.
+ *
+ * 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.
+ *
+ *********************************************************************/
+
+#include "phrasequeryfilter.h"
+#include "queryinfo.h"
+
+#include "phrasesearch.h"
+
+
+
+// do aditional query processing
+void phrasequeryfilterclass::post_process (const queryparamclass &queryparams,
+					   queryresultsclass &queryresults) {
+  bool results_shrunk = false;
+
+  // post-process the results if needed
+  if (queryresults.orgterms.size() > 1 && !queryresults.docs.docset.empty()) {
+    // get the long version of the index
+    text_t longindex;
+    indexmap.to2from (queryparams.index, longindex);
+      
+    // process each of the matched documents
+    docresultmap::iterator docs_here = queryresults.docs.docset.begin();
+    docresultmap::iterator docs_end = queryresults.docs.docset.end();
+    while (docs_here != docs_end) {
+      if ((*docs_here).second.num_query_terms_matched == queryresults.orgterms.size() &&
+	  OID_phrase_search (*(mgsearchclass *)mgsearchptr, *gdbmptr, queryparams.index,
+			     queryparams.subcollection, queryparams.language, 
+			     longindex, queryparams.collection, queryresults.orgterms,
+			     (*docs_here).second.docnum)) {
+	(*docs_here).second.num_phrase_match++;
+	docs_here++;
+
+      } else {
+	docresultmap::iterator this_doc_here = docs_here;
+	docs_here++;
+	if (queryparams.match_mode == 1) {
+	  // need to delete this element, there was no exact match
+	  queryresults.docs.docset.erase(this_doc_here);
+	  results_shrunk = true;
+	}
+      }
+    }
+  }
+
+  if (results_shrunk) queryresults.docs_matched = queryresults.docs.docset.size();
+}
+
+
+void phrasequeryfilterclass::sort_doc_results (const FilterRequest_t &/*request*/,
+					 docresultsclass &docs) {
+  resultsorderer_t resultsorderer;
+  resultsorderer.compare_phrase_match = true;
+  resultsorderer.compare_terms_match = true;
+  resultsorderer.compare_doc_weight = true;
+  resultsorderer.docset = &(docs.docset);
+
+  // first get a list of document numbers
+  docs.docnum_order();
+
+  sort (docs.docorder.begin(), docs.docorder.end(), resultsorderer);
+}
Index: /main/tags/2.25/gsdl/src/colservr/phrasequeryfilter.h
===================================================================
--- /main/tags/2.25/gsdl/src/colservr/phrasequeryfilter.h	(revision 21064)
+++ /main/tags/2.25/gsdl/src/colservr/phrasequeryfilter.h	(revision 21064)
@@ -0,0 +1,43 @@
+/**********************************************************************
+ *
+ * phrasequeryfilter.h -- 
+ * Copyright (C) 1999  DigiLib Systems Limited, New Zealand
+ *
+ * A component of the Greenstone digital library software
+ * from the New Zealand Digital Library Project at the
+ * University of Waikato, New Zealand.
+ *
+ * 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.
+ *
+ *********************************************************************/
+
+
+#ifndef PHRASEQUERYFILTER_H
+#define PHRASEQUERYFILTER_H
+
+#include "mgqueryfilter.h"
+
+
+class phrasequeryfilterclass : public mgqueryfilterclass {
+protected:
+  void post_process (const queryparamclass &queryparams,
+		     queryresultsclass &queryresults);
+  void sort_doc_results (const FilterRequest_t &request,
+			 docresultsclass &docs);
+public:
+};
+
+
+#endif
Index: /main/tags/2.25/gsdl/src/colservr/phrasesearch.cpp
===================================================================
--- /main/tags/2.25/gsdl/src/colservr/phrasesearch.cpp	(revision 21064)
+++ /main/tags/2.25/gsdl/src/colservr/phrasesearch.cpp	(revision 21064)
@@ -0,0 +1,192 @@
+/**********************************************************************
+ *
+ * phrasesearch.cpp -- tools to search for a phrase in a larger text
+ * Copyright (C) 1999  DigiLib Systems Limited
+ *
+ * A component of the Greenstone digital library software
+ * from the New Zealand Digital Library Project at the
+ * University of Waikato, New Zealand.
+ *
+ * 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.
+ *
+ *********************************************************************/
+
+#include "phrasesearch.h"
+#include "gsdlunicode.h"
+
+inline unsigned char *parse_nonword_word (unsigned char *here, unsigned char *end,
+					  text_t &word) {
+  int c_len = 0;
+  unsigned short c = 0;
+
+  word.clear();
+
+  // parse non word
+  while (here <= end) {
+    c_len = parse_utf8_char (here, end, &c);
+    if (c == '(') {
+      // found a note, look for '}'
+      while (here <= end && c != ')') {
+	c_len = parse_utf8_char (here, end, &c);
+	here += c_len;
+      }
+    }
+    if (c == '{') {
+      // found a composite character, look for '}'
+      while (here <= end && c != '}') {
+	c_len = parse_utf8_char (here, end, &c);
+	here += c_len;
+      }
+    }
+    if (is_unicode_letdig(c)) {
+      while (c_len > 0) {
+	// this is in a word
+	word.push_back(*here);
+	here++; c_len--;
+      }
+      break;
+    }
+    here += c_len;
+  }
+
+  // parse word
+  while (here <= end) {
+    c_len = parse_utf8_char (here, end, &c);
+    if (!is_unicode_letdig(c)) {
+      here += c_len;  // it is ok to skip a nonword character
+      break;
+    }
+    while (c_len > 0) {
+      word.push_back(*here);
+      here++; c_len--;
+    }
+  }
+
+  return here;
+}
+
+
+bool doc_phrase_search (unsigned char *doc, int doclen,
+			const termfreqclassarray &phrase) {
+  // note: this uses the most braindead search routine :-)
+  // however its not so bad as there shouldn't be many partial
+  // matches
+
+  // a null phrase matches anything
+  if (phrase.empty()) return true;
+
+  // if there is nothing then there can't be a match
+  if (doc == NULL || doclen == 0) return false;
+  
+  text_t doc_word;
+  doc_word.reserve (16);
+
+  bool first = true;
+
+  unsigned char *doc_here = doc;
+  unsigned char *doc_herefirstword = doc;
+  unsigned char *doc_end = doc+doclen-1; // unitool conventions :-/
+
+  while (doc_here <= doc_end) {
+    first = true;
+    
+    // there will be at least one member of phrase (see above)
+    termfreqclassarray::const_iterator phrase_here = phrase.begin();
+    termfreqclassarray::const_iterator phrase_end = phrase.end();
+    do {
+      // get the next non-word ... and ignore it, then get the next word
+      doc_here = parse_nonword_word (doc_here, doc_end, doc_word);
+      if (first) {doc_herefirstword = doc_here; first = false;}
+
+      // break if this word is not the next in the phrase
+      if ((*phrase_here).utf8equivterms.find (doc_word) ==
+	  (*phrase_here).utf8equivterms.end()) break;
+
+      phrase_here++;
+    } while (doc_here <= doc_end && phrase_here != phrase_end);
+
+    // see if we found a phrase
+    if (phrase_here == phrase_end) return true;
+    
+    doc_here = doc_herefirstword; // set the counter back
+  }
+
+  return false;
+}
+
+
+// looks for the stemmed phrase in the metadata or text associated with
+// an OID. This function has not been coded with all situations in mind
+bool OID_phrase_search (mgsearchclass &mgsearch,
+			gdbmclass &gdbm,
+			const text_t &index,
+			const text_t &subcollection,
+			const text_t &language,
+			const text_t &longindex,
+			const text_t &collection,
+			const termfreqclassarray &phrase,
+			int docnum) {
+  // disect the long index to find out where the text should come from
+  text_t level, gran;
+  text_t::const_iterator longindex_here = longindex.begin();
+  text_t::const_iterator longindex_end = longindex.end();
+  longindex_here = getdelimitstr (longindex_here, longindex_end, ':', level);
+  longindex_here = getdelimitstr (longindex_here, longindex_end, ':', gran);
+
+  if (gran.empty()) return false;
+  
+  if (gran == "text") {
+    char *doc = NULL;
+    int doclen = 0;
+  
+    // get text from mg.
+    if (!mgsearch.mgdocument (index, subcollection, language, collection,
+			      docnum, doc, doclen)) return false;
+    return doc_phrase_search ((unsigned char *)doc, doclen, phrase);
+  } 
+
+  // get OID
+  char *metadata = NULL;
+  text_t::size_type metadata_len = 0;
+  infodbclass docnum_info;
+  infodbclass OID_info;
+  
+  if (!gdbm.getinfo (docnum, docnum_info)) return false;
+  text_t &OID = docnum_info["section"];
+  if (OID.empty()) return false;
+  
+  // get field
+  if (!gdbm.getinfo (OID, OID_info)) return false;
+
+  bool result = false;
+  text_tarray *tarr_ptr = OID_info.getmultinfo (gran);
+  if (tarr_ptr != NULL ) {
+    text_tarray::const_iterator subvalue_here = (*tarr_ptr).begin();
+    text_tarray::const_iterator subvalue_end = (*tarr_ptr).end();
+    while (subvalue_here != subvalue_end) {
+      if (subvalue_here != NULL) {
+	metadata = (to_utf8(*subvalue_here)).getcarr(metadata_len);
+	result = doc_phrase_search ((unsigned char *)metadata, metadata_len, phrase);
+	delete [] metadata;
+
+	if (result) return true;
+      }
+      
+      subvalue_here++;
+    }
+  }
+
+  return result;
+}
Index: /main/tags/2.25/gsdl/src/colservr/phrasesearch.h
===================================================================
--- /main/tags/2.25/gsdl/src/colservr/phrasesearch.h	(revision 21064)
+++ /main/tags/2.25/gsdl/src/colservr/phrasesearch.h	(revision 21064)
@@ -0,0 +1,50 @@
+/**********************************************************************
+ *
+ * phrasesearch.h -- tools to search for a phrase in a larger text
+ * Copyright (C) 1999  DigiLib Systems Limited
+ *
+ * A component of the Greenstone digital library software
+ * from the New Zealand Digital Library Project at the
+ * University of Waikato, New Zealand.
+ *
+ * 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.
+ *
+ *********************************************************************/
+
+
+#ifndef PHRASESEARCH_H
+#define PHRASESEARCH_H
+
+
+#include "text_t.h"
+#include "unitool.h"
+#include "mgsearch.h"
+#include "infodbclass.h"
+
+
+// looks for the phrase in the metadata or text associated with
+// a document number. This function has not been coded with all
+// situations in mind and expects mgsearch and gdbm set up ready to go
+bool OID_phrase_search (mgsearchclass &mgsearch,
+			gdbmclass &gdbm,
+			const text_t &index,
+			const text_t &subcollection,
+			const text_t &language,
+			const text_t &longindex,
+			const text_t &collection,
+			const termfreqclassarray &phrase,
+			int docnum);
+
+#endif
Index: /main/tags/2.25/gsdl/src/colservr/querycache.cpp
===================================================================
--- /main/tags/2.25/gsdl/src/colservr/querycache.cpp	(revision 21064)
+++ /main/tags/2.25/gsdl/src/colservr/querycache.cpp	(revision 21064)
@@ -0,0 +1,104 @@
+/**********************************************************************
+ *
+ * querycache.cpp -- 
+ * Copyright (C) 1999  The New Zealand Digital Library Project
+ *
+ * A component of the Greenstone digital library software
+ * from the New Zealand Digital Library Project at the
+ * University of Waikato, New Zealand.
+ *
+ * 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.
+ *
+ *********************************************************************/
+
+#include "querycache.h"
+
+
+
+
+resultcacheel::resultcacheel () 
+{
+  accessnum = -1;
+}
+
+
+
+querycache::querycache (int themaxcachesize)
+{
+  if (themaxcachesize < 1) themaxcachesize = 1;
+  
+  resultcache = new resultcacheel[themaxcachesize];
+
+  maxcachesize = themaxcachesize;
+  nextaccessnum = 1;
+}
+
+querycache::~querycache ()
+{
+  delete [] resultcache;
+}
+
+// returns true if the query was found in the cache
+// if the query was found then queryresults contains
+// the results
+bool querycache::find (const queryparamclass &queryparams, 
+		       queryresultsclass &queryresults)
+{
+  int i;
+
+  for (i=0; i < maxcachesize; i++)
+    {
+      if (resultcache[i].queryparameters == queryparams)
+	{
+	  queryresults = resultcache[i].queryresults;
+	  resultcache[i].accessnum = getnextaccessnum ();
+	  return true;
+	}
+    }
+
+  return false;
+}
+
+
+void querycache::cache (const queryparamclass &queryparams,
+	  const queryresultsclass &queryresults)
+{
+  int i = getfreecachenum();
+  resultcache[i].queryparameters = queryparams;
+  resultcache[i].queryresults = queryresults;
+  resultcache[i].accessnum = getnextaccessnum ();
+}
+
+int querycache::getnextaccessnum ()
+{
+  return nextaccessnum++;
+}
+
+int querycache::getfreecachenum ()
+{
+  int i;
+  int minaccessnum = 0;
+  int minaccessi = 0;
+  
+  for (i=0; i < maxcachesize; i++)
+    {
+      if (resultcache[i].accessnum < minaccessnum) {
+	minaccessnum = resultcache[i].accessnum;
+	minaccessi = i;
+      }
+    }
+
+  return minaccessi;
+}
Index: /main/tags/2.25/gsdl/src/colservr/querycache.h
===================================================================
--- /main/tags/2.25/gsdl/src/colservr/querycache.h	(revision 21064)
+++ /main/tags/2.25/gsdl/src/colservr/querycache.h	(revision 21064)
@@ -0,0 +1,70 @@
+/**********************************************************************
+ *
+ * querycache.h -- 
+ * Copyright (C) 1999  The New Zealand Digital Library Project
+ *
+ * A component of the Greenstone digital library software
+ * from the New Zealand Digital Library Project at the
+ * University of Waikato, New Zealand.
+ *
+ * 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.
+ *
+ *********************************************************************/
+
+
+#ifndef QUERYCACHE_H
+#define QUERYCACHE_H
+
+
+#include "text_t.h"
+#include "queryinfo.h"
+
+class resultcacheel
+{
+public:
+  resultcacheel ();
+
+  int accessnum;
+  queryparamclass queryparameters;
+  queryresultsclass queryresults;
+};
+
+
+class querycache {
+public:
+  querycache (int themaxcachesize);
+  ~querycache ();
+
+  // returns true if the query was found in the cache
+  // if the query was found then queryresults contains
+  // the results
+  bool find (const queryparamclass &queryparams, 
+	     queryresultsclass &queryresults);
+
+  void cache (const queryparamclass &queryparams,
+	    const queryresultsclass &queryresults);
+
+protected:
+  resultcacheel *resultcache;
+
+  int maxcachesize;
+  int nextaccessnum;
+  
+  int getnextaccessnum ();
+  int getfreecachenum ();
+};
+
+
+#endif
Index: /main/tags/2.25/gsdl/src/colservr/queryfilter.cpp
===================================================================
--- /main/tags/2.25/gsdl/src/colservr/queryfilter.cpp	(revision 21064)
+++ /main/tags/2.25/gsdl/src/colservr/queryfilter.cpp	(revision 21064)
@@ -0,0 +1,356 @@
+/**********************************************************************
+ *
+ * queryfilter.cpp -- base class for queryfilters
+ * Copyright (C) 1999  The New Zealand Digital Library Project
+ *
+ * A component of the Greenstone digital library software
+ * from the New Zealand Digital Library Project at the
+ * University of Waikato, New Zealand.
+ *
+ * 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.
+ *
+ *********************************************************************/
+
+#include "queryfilter.h"
+#include "fileutil.h"
+#include "gsdltools.h"
+#include <assert.h>
+
+
+// translate will return true if successful
+bool queryfilterclass::translate (gdbmclass *gdbmptr, int docnum, text_t &trans_OID) {
+  infodbclass info;
+
+  trans_OID.clear();
+
+  // get the info
+  if (gdbmptr == NULL) return false;
+  if (!gdbmptr->getinfo(docnum, info)) return false;
+
+  // translate
+  if (info["section"].empty()) return false;
+
+  trans_OID = info["section"];
+  return true;
+}
+
+
+// whether document results are needed
+bool queryfilterclass::need_matching_docs (int filterResultOptions) {
+  return ((filterResultOptions & FROID) || (filterResultOptions & FRranking) ||
+	  (filterResultOptions & FRmetadata));
+}
+
+// whether term information is needed
+bool queryfilterclass::need_term_info (int filterResultOptions) {
+  return ((filterResultOptions & FRtermFreq) || (filterResultOptions & FRmatchTerms));
+}
+
+/////////////////////////////////
+// functions for queryfilterclass
+/////////////////////////////////
+
+// get the query parameters
+void queryfilterclass::parse_query_params (const FilterRequest_t &request,
+					   vector<queryparamclass> &query_params,
+					   int &startresults, int &endresults,
+					   text_t &phrasematch, ostream &logout) {
+  outconvertclass text_t2ascii;
+
+  // set defaults for the return parameters
+  query_params.erase(query_params.begin(), query_params.end());
+  startresults = filterOptions["StartResults"].defaultValue.getint();
+  endresults = filterOptions["EndResults"].defaultValue.getint();
+  phrasematch = filterOptions["PhraseMatch"].defaultValue;
+
+  // set defaults for query parameters
+  queryparamclass query;
+  query.combinequery = "or"; // first one must be "or"
+  query.collection = collection;
+  query.index = filterOptions["Index"].defaultValue;
+  query.subcollection = filterOptions["Subcollection"].defaultValue;
+  query.language = filterOptions["Language"].defaultValue;
+  query.querystring.clear();
+  query.search_type = (filterOptions["QueryType"].defaultValue == "ranked");
+  query.match_mode = (filterOptions["MatchMode"].defaultValue == "all");
+  query.casefolding = (filterOptions["Casefold"].defaultValue == "true");
+  query.stemming = (filterOptions["Stem"].defaultValue == "true");
+  query.maxdocs = filterOptions["Maxdocs"].defaultValue.getint();
+  query.level = "";
+  OptionValue_tarray::const_iterator options_here = request.filterOptions.begin();
+  OptionValue_tarray::const_iterator options_end = request.filterOptions.end();
+  while (options_here != options_end) {
+    if ((*options_here).name == "CombineQuery") {
+      // add this query
+      
+      // "all", needed when combining queries where the document results are needed
+      if (need_matching_docs (request.filterResultOptions)) query.maxdocs = -1; 
+      query_params.push_back (query);
+
+      // start on next query
+      query.clear();
+      query.combinequery = (*options_here).value;
+
+      // set defaults for query parameters
+      query.collection = collection;
+      query.index = filterOptions["Index"].defaultValue;
+      query.subcollection = filterOptions["Subcollection"].defaultValue;
+      query.language = filterOptions["Language"].defaultValue;
+      query.querystring.clear();
+      query.search_type = (filterOptions["QueryType"].defaultValue == "ranked");
+      query.match_mode = (filterOptions["MatchMode"].defaultValue == "all");
+      query.casefolding = (filterOptions["Casefold"].defaultValue == "true");
+      query.stemming = (filterOptions["Stem"].defaultValue == "true");
+      query.level = "";
+      // "all", needed when combining queries where the document results are needed
+      if (need_matching_docs (request.filterResultOptions)) query.maxdocs = -1; 
+      else query.maxdocs = filterOptions["Maxdocs"].defaultValue.getint();
+      
+    } else if ((*options_here).name == "StartResults") {
+      startresults = (*options_here).value.getint();
+    } else if ((*options_here).name == "EndResults") {
+      endresults = (*options_here).value.getint();
+    } else if ((*options_here).name == "QueryType") {
+      query.search_type = ((*options_here).value == "ranked");
+    } else if ((*options_here).name == "MatchMode") {
+      query.match_mode = ((*options_here).value == "all");
+      if (query.match_mode == 1) query.maxdocs = -1;
+    } else if ((*options_here).name == "Term") {
+      query.querystring = (*options_here).value;
+    } else if ((*options_here).name == "Casefold") {
+      query.casefolding = ((*options_here).value == "true");
+    } else if ((*options_here).name == "Stem") {
+      query.stemming = ((*options_here).value == "true");
+    } else if ((*options_here).name == "Index") {
+      query.index = (*options_here).value;
+    } else if ((*options_here).name == "Subcollection") {
+      query.subcollection = (*options_here).value;
+    } else if ((*options_here).name == "Language") {
+      query.language = (*options_here).value;
+    } else if ((*options_here).name == "Maxdocs") {
+      query.maxdocs = (*options_here).value.getint();
+    } else if ((*options_here).name == "PhraseMatch") {
+      phrasematch = (*options_here).value;
+    } else if ((*options_here).name == "Level") {
+      query.level = (*options_here).value;
+    } else {
+      logout << text_t2ascii
+	     << "warning: unknown queryfilter option \""
+	     << (*options_here).name
+	     << "\" ignored.\n\n";
+    }
+
+    options_here++;
+  }
+
+  // add the last query
+  query_params.push_back (query);
+}
+
+
+
+
+queryfilterclass::queryfilterclass () {
+  gdbmptr = NULL;
+  mgsearchptr = NULL;
+
+  FilterOption_t filtopt;
+  filtopt.name = "CombineQuery";
+  filtopt.type = FilterOption_t::enumeratedt;
+  filtopt.repeatable = FilterOption_t::onePerQuery;
+  filtopt.defaultValue = "and";
+  filtopt.validValues.push_back("and");
+  filtopt.validValues.push_back("or");
+  filtopt.validValues.push_back("not");
+  filterOptions["CombineQuery"] = filtopt;
+
+  // -- onePerQuery StartResults   integer
+  filtopt.clear();
+  filtopt.name = "StartResults";
+  filtopt.type = FilterOption_t::integert;
+  filtopt.repeatable = FilterOption_t::onePerQuery;
+  filtopt.defaultValue = "1";
+  filtopt.validValues.push_back("1");
+  filtopt.validValues.push_back("1000");
+  filterOptions["StartResults"] = filtopt;
+
+  // -- onePerQuery EndResults     integer
+  filtopt.clear();
+  filtopt.name = "EndResults";
+  filtopt.type = FilterOption_t::integert;
+  filtopt.repeatable = FilterOption_t::onePerQuery;
+  filtopt.defaultValue = "10";
+  filtopt.validValues.push_back("-1");
+  filtopt.validValues.push_back("1000");
+  filterOptions["EndResults"] = filtopt;
+
+  // -- onePerQuery QueryType      enumerated (boolean, ranked)
+  filtopt.clear();
+  filtopt.name = "QueryType";
+  filtopt.type = FilterOption_t::enumeratedt;
+  filtopt.repeatable = FilterOption_t::onePerQuery;
+  filtopt.defaultValue = "ranked";
+  filtopt.validValues.push_back("boolean");
+  filtopt.validValues.push_back("ranked");
+  filterOptions["QueryType"] = filtopt;
+
+  // -- onePerQuery MatchMode      enumerated (some, all)
+  filtopt.clear();
+  filtopt.name = "MatchMode";
+  filtopt.type = FilterOption_t::enumeratedt;
+  filtopt.repeatable = FilterOption_t::onePerQuery;
+  filtopt.defaultValue = "some";
+  filtopt.validValues.push_back("some");
+  filtopt.validValues.push_back("all");
+  filterOptions["MatchMode"] = filtopt;
+
+  // -- onePerTerm  Term           string ???
+  filtopt.clear();
+  filtopt.name = "Term";
+  filtopt.type = FilterOption_t::stringt;
+  filtopt.repeatable = FilterOption_t::onePerTerm;
+  filtopt.defaultValue = "";
+  filterOptions["Term"] = filtopt;
+
+  // -- onePerTerm  Casefold       boolean
+  filtopt.clear();
+  filtopt.name = "Casefold";
+  filtopt.type = FilterOption_t::booleant;
+  filtopt.repeatable = FilterOption_t::onePerTerm;
+  filtopt.defaultValue = "true";
+  filtopt.validValues.push_back("false");
+  filtopt.validValues.push_back("true");
+  filterOptions["Casefold"] = filtopt;
+
+  // -- onePerTerm  Stem           boolean
+  filtopt.clear();
+  filtopt.name = "Stem";
+  filtopt.type = FilterOption_t::booleant;
+  filtopt.repeatable = FilterOption_t::onePerTerm;
+  filtopt.defaultValue = "false";
+  filtopt.validValues.push_back("false");
+  filtopt.validValues.push_back("true");
+  filterOptions["Stem"] = filtopt;
+
+  // -- onePerTerm  Index          enumerated
+  filtopt.clear();
+  filtopt.name = "Index";
+  filtopt.type = FilterOption_t::enumeratedt;
+  filtopt.repeatable = FilterOption_t::onePerTerm;
+  filtopt.defaultValue = "";
+  filterOptions["Index"] = filtopt;
+
+  // -- onePerTerm  Subcollection  enumerated
+  filtopt.clear();
+  filtopt.name = "Subcollection";
+  filtopt.type = FilterOption_t::enumeratedt;
+  filtopt.repeatable = FilterOption_t::onePerTerm;
+  filtopt.defaultValue = "";
+  filterOptions["Subcollection"] = filtopt;
+
+  // -- onePerTerm  Language  enumerated
+  filtopt.clear();
+  filtopt.name = "Language";
+  filtopt.type = FilterOption_t::enumeratedt;
+  filtopt.repeatable = FilterOption_t::onePerTerm;
+  filtopt.defaultValue = "";
+  filterOptions["Language"] = filtopt;
+
+  // -- onePerQuery  Maxdocs  integer
+  filtopt.clear();
+  filtopt.name = "Maxdocs";
+  filtopt.type = FilterOption_t::integert;
+  filtopt.repeatable = FilterOption_t::onePerQuery;
+  filtopt.defaultValue = "200";
+  filtopt.validValues.push_back("-1");
+  filtopt.validValues.push_back("1000");
+  filterOptions["Maxdocs"] = filtopt;
+
+  // -- onePerQuery  PhraseMatch  enumerated
+  filtopt.clear();
+  filtopt.name = "PhraseMatch";
+  filtopt.type = FilterOption_t::enumeratedt;
+  filtopt.repeatable = FilterOption_t::onePerQuery;
+  filtopt.defaultValue = "some_phrases";
+  filtopt.validValues.push_back ("all_phrases");
+  filtopt.validValues.push_back ("some_phrases");
+  filtopt.validValues.push_back ("all_docs");
+  filterOptions["PhraseMatch"] = filtopt;
+}
+
+queryfilterclass::~queryfilterclass () {
+}
+
+void queryfilterclass::configure (const text_t &key, const text_tarray &cfgline) {
+  filterclass::configure (key, cfgline);
+
+  if (key == "indexmap") {
+    indexmap.importmap (cfgline);
+    
+    // update the list of indexes in the filter information
+    text_tarray options;
+    indexmap.gettoarray (options);
+    filterOptions["Index"].validValues = options;
+
+  } else if (key == "defaultindex") {
+    indexmap.from2to (cfgline[0], filterOptions["Index"].defaultValue);
+
+  } else if (key == "subcollectionmap") {
+    subcollectionmap.importmap (cfgline);
+
+    // update the list of subcollections in the filter information
+    text_tarray options;
+    subcollectionmap.gettoarray (options);
+    filterOptions["Subcollection"].validValues = options;
+
+  } else if (key == "defaultsubcollection") {
+    subcollectionmap.from2to (cfgline[0], filterOptions["Subcollection"].defaultValue);
+
+  } else if (key == "languagemap") {
+    languagemap.importmap (cfgline);
+
+    // update the list of languages in the filter information
+    text_tarray options;
+    languagemap.gettoarray (options);
+    filterOptions["Language"].validValues = options;
+
+  } else if (key == "defaultlanguage") 
+    languagemap.from2to (cfgline[0], filterOptions["Language"].defaultValue);
+}
+
+bool queryfilterclass::init (ostream &logout) {
+  outconvertclass text_t2ascii;
+
+  if (!filterclass::init(logout)) return false;
+
+  // get the filename for the database and make sure it exists
+  gdbm_filename = filename_cat(collectdir,"index","text",collection);
+
+  if (littleEndian()) gdbm_filename += ".ldb";
+  else gdbm_filename += ".bdb";
+
+  if (!file_exists(gdbm_filename)) {
+    logout << text_t2ascii
+	   << "warning: gdbm database \"" //****
+	   << gdbm_filename << "\" does not exist\n\n";
+    //return false; //****
+  }
+
+  return true;
+}
+
+
+
+
Index: /main/tags/2.25/gsdl/src/colservr/queryfilter.h
===================================================================
--- /main/tags/2.25/gsdl/src/colservr/queryfilter.h	(revision 21064)
+++ /main/tags/2.25/gsdl/src/colservr/queryfilter.h	(revision 21064)
@@ -0,0 +1,96 @@
+/**********************************************************************
+ *
+ * queryfilter.h -- abstract base class for queryfilters
+ *          mgqueryfilter and mgppqueryfilter implement this
+ * Copyright (C) 1999  The New Zealand Digital Library Project
+ *
+ * A component of the Greenstone digital library software
+ * from the New Zealand Digital Library Project at the
+ * University of Waikato, New Zealand.
+ *
+ * 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.
+ *
+ *********************************************************************/
+
+
+#ifndef QUERYFILTER_H
+#define QUERYFILTER_H
+
+
+#include "gsdlconf.h"
+#include "text_t.h"
+#include "comtypes.h"
+#include "filter.h"
+#include "infodbclass.h"
+#include "maptools.h"
+#include "search.h"
+#include "queryinfo.h"
+
+
+class queryfilterclass : public filterclass {
+protected:
+
+  stringmap indexmap;
+  stringmap subcollectionmap;
+  stringmap languagemap;
+
+  text_t gdbm_filename;
+  gdbmclass *gdbmptr;
+  
+  searchclass *mgsearchptr;
+  
+   // get the query parameters
+  void parse_query_params (const FilterRequest_t &request,
+			   vector<queryparamclass> &query_params,
+			   int &startresults, int &endresults,
+			   text_t &phrasematch, ostream &logout);
+
+  // do query that might involve multiple sub queries
+  // mgsearchptr and gdbmptr are assumed to be valid
+  virtual void do_multi_query (const FilterRequest_t &request,
+		       const vector<queryparamclass> &query_params,
+		       queryresultsclass &multiresults,
+		       comerror_t &err, ostream &logout)=0;
+
+public:
+  queryfilterclass ();
+  virtual ~queryfilterclass ();
+
+  // the gdbmptr remains the responsability of the calling code
+  void set_gdbmptr (gdbmclass *thegdbmptr) {gdbmptr=thegdbmptr;}
+
+  // the mgsearchptr remains the responsability of the calling code
+  void set_mgsearchptr (searchclass *themgsearchptr) {mgsearchptr=themgsearchptr;}
+
+  virtual void configure (const text_t &key, const text_tarray &cfgline);
+  bool init (ostream &logout);
+
+  text_t get_filter_name () {return "QueryFilter";}
+  bool translate(gdbmclass *gdbmptr, int docnum, text_t &trans_OID);
+  bool need_matching_docs (int filterResultOptions);
+  bool need_term_info (int filterResultOptions);
+
+
+  virtual void filter (const FilterRequest_t &request,
+	       FilterResponse_t &response,
+	       comerror_t &err, ostream &logout)=0;
+
+
+
+};
+
+
+#endif
+
Index: /main/tags/2.25/gsdl/src/colservr/queryinfo.cpp
===================================================================
--- /main/tags/2.25/gsdl/src/colservr/queryinfo.cpp	(revision 21064)
+++ /main/tags/2.25/gsdl/src/colservr/queryinfo.cpp	(revision 21064)
@@ -0,0 +1,398 @@
+/**********************************************************************
+ *
+ * queryinfo.cpp -- 
+ * Copyright (C) 1999  The New Zealand Digital Library Project
+ *
+ * A component of the Greenstone digital library software
+ * from the New Zealand Digital Library Project at the
+ * University of Waikato, New Zealand.
+ *
+ * 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.
+ *
+ *********************************************************************/
+
+#include "queryinfo.h"
+
+
+// query parameters
+
+queryparamclass::queryparamclass () {
+  clear ();
+}
+
+void queryparamclass::clear () {
+  combinequery.clear();
+  collection.clear();
+  index.clear();
+  subcollection.clear();
+  language.clear();
+  level.clear();
+  querystring.clear();
+  search_type = 0; // 0 = boolean, 1 = ranked
+  match_mode = 0; // 0 = some, 1 = all
+  casefolding = 0;
+  stemming = 0;
+  maxdocs = -1;    // all
+}
+
+
+queryparamclass &queryparamclass::operator=(const queryparamclass &q) {
+  combinequery = q.combinequery;
+  collection = q.collection;
+  index = q.index;
+  subcollection = q.subcollection;
+  language = q.language;
+  level = q.level;
+  querystring = q.querystring;
+  search_type = q.search_type;
+  match_mode = q.match_mode;
+  casefolding = q.casefolding;
+  stemming = q.stemming;
+  maxdocs = q.maxdocs;
+
+  return *this;
+}
+
+
+bool operator==(const queryparamclass &x, const queryparamclass &y) {
+  return ((x.combinequery == y.combinequery) &&
+	  (x.collection == y.collection) &&
+	  (x.index == y.index) &&
+	  (x.subcollection == y.subcollection) &&
+	  (x.language == y.language) &&
+	  (x.level == y.level) &&
+	  (x.querystring == y.querystring) &&
+	  (x.search_type == y.search_type) &&
+	  (x.match_mode == y.match_mode) &&
+	  (x.casefolding == y.casefolding) &&
+	  (x.stemming == y.stemming) &&
+	  (x.maxdocs == y.maxdocs));
+}
+
+bool operator!=(const queryparamclass &x, const queryparamclass &y) {
+  return !(x == y);
+}
+
+
+ostream &operator<< (ostream &outs, queryparamclass &q) {
+  outconvertclass text_t2ascii;
+
+  outs << "*** queryparamclass\n";
+  outs << text_t2ascii << " combinequery = \"" << q.combinequery << "\"\n";
+  outs << text_t2ascii << " collection = \"" << q.collection << "\"\n";
+  outs << text_t2ascii << " index = \"" << q.index << "\"\n";
+  outs << text_t2ascii << " level = \"" << q.level << "\"\n";
+  outs << text_t2ascii << " subcollection = \"" << q.subcollection << "\"\n";
+  outs << text_t2ascii << " language = \"" << q.language << "\"\n";
+  outs << text_t2ascii << " querystring = \"" << q.querystring << "\"\n";
+  outs << " search_type = \"" << q.search_type << "\"\n";
+  outs << " match_mode = \"" << q.match_mode << "\"\n";
+  outs << " casefolding = \"" << q.casefolding << "\"\n";
+  outs << " stemming = \"" << q.stemming << "\"\n";
+  outs << " maxdocs = \"" << q.maxdocs << "\"\n";
+  outs << "\n";
+
+  return outs;
+}
+
+
+
+
+// term frequencies
+
+termfreqclass::termfreqclass () {
+  clear();
+}
+
+void termfreqclass::clear() {
+  termstr.clear();
+  termstemstr.clear();
+  utf8equivterms.erase(utf8equivterms.begin(), utf8equivterms.end());
+  termfreq = 0;
+}
+
+termfreqclass &termfreqclass::operator=(const termfreqclass &t)  {
+  termstr = t.termstr;
+  termstemstr = t.termstemstr;
+  utf8equivterms = t.utf8equivterms;
+  termfreq = t.termfreq;
+
+  return *this;
+}
+	
+bool operator==(const termfreqclass &x, const termfreqclass &y) {
+  return ((x.termstr == y.termstr) &&
+	  (x.termstemstr == y.termstemstr) &&
+	  (x.termfreq == y.termfreq));
+}
+
+bool operator!=(const termfreqclass &x, const termfreqclass &y) {
+  return !(x == y);
+}
+
+// ordered by termfreq and then by termstr
+bool operator<(const termfreqclass &x, const termfreqclass &y) {
+  return ((x.termfreq < y.termfreq) ||
+	  ((x.termfreq == y.termfreq) && (x.termstemstr < y.termstemstr)) ||
+	  ((x.termfreq == y.termfreq) && (x.termstemstr == y.termstemstr) && (x.termstr < y.termstr)));
+}
+
+bool operator>(const termfreqclass &x, const termfreqclass &y) {
+  return ((x.termfreq > y.termfreq) ||
+	  ((x.termfreq == y.termfreq) && (x.termstemstr > y.termstemstr)) ||
+	  ((x.termfreq == y.termfreq) && (x.termstemstr == y.termstemstr) && (x.termstr > y.termstr)));
+}
+
+// stream output for debugging purposes
+ostream &operator<< (ostream &outs, termfreqclass &t) {
+  outconvertclass text_t2ascii;
+
+  outs << text_t2ascii << " t:\"" << t.termstr << "\"";
+  outs << text_t2ascii << " s:\"" << t.termstemstr << "\"";
+  outs << " f:" << t.termfreq << "\n";
+
+  return outs;
+}
+
+
+
+// one query result
+
+docresultclass::docresultclass() {
+  clear ();
+}
+
+void docresultclass::clear () {
+  docnum=-1;
+  docweight=0.0;
+  num_query_terms_matched=0;
+  num_phrase_match=0;
+}
+
+// merges two result classes relating to a single docnum
+docresultclass &docresultclass::combine(const docresultclass &d) {
+  docweight += d.docweight; // budget!
+  num_query_terms_matched += d.num_query_terms_matched;
+  num_phrase_match += d.num_phrase_match;
+
+  return *this;
+}
+
+docresultclass &docresultclass::operator=(const docresultclass &d) {
+  docnum = d.docnum;
+  docweight = d.docweight;
+  num_query_terms_matched = d.num_query_terms_matched;
+  num_phrase_match = d.num_phrase_match;
+
+  return *this;
+}
+
+
+bool operator==(const docresultclass &x, const docresultclass &y) {
+  return ((x.docnum == y.docnum) && (x.docweight == y.docweight) &&
+	  (x.num_query_terms_matched == y.num_query_terms_matched) &&
+	  (x.num_phrase_match == y.num_phrase_match));
+}
+
+bool operator<(const docresultclass &x, const docresultclass &y) {
+  return ((x.docnum < y.docnum) ||
+	  ((x.docnum == y.docnum) &&
+	   ((x.docweight < y.docweight) ||
+	    ((x.docweight == y.docweight) &&
+	     ((x.num_query_terms_matched < y.num_query_terms_matched) ||
+	      ((x.num_query_terms_matched == y.num_query_terms_matched) &&
+	       ((x.num_phrase_match < y.num_phrase_match))))))));
+}
+
+
+// stream output for debugging purposes
+ostream &operator<< (ostream &outs, docresultclass &a) {
+  outs << " d:" << a.docnum << " w:" << a.docweight << "\n";
+  return outs;
+}
+
+
+
+// many document results
+
+docresultsclass::docresultsclass () {
+  clear ();
+}
+
+void docresultsclass::clear () {
+  docset.erase(docset.begin(), docset.end());
+  docorder.erase(docorder.begin(), docorder.end());
+}
+
+void docresultsclass::docnum_order() {
+  docorder.erase(docorder.begin(), docorder.end());
+  
+  docresultmap::iterator here = docset.begin();
+  docresultmap::iterator end = docset.end();
+  while (here != end) {
+    docorder.push_back ((*here).first);
+    here++;
+  }
+}
+
+void docresultsclass::combine_and (const docresultsclass &d) {
+  docorder.erase(docorder.begin(), docorder.end());
+
+  // put the resulting set in tempresults
+  docresultmap tempresults;
+  
+  docresultmap::const_iterator d_here = d.docset.begin();
+  docresultmap::const_iterator d_end = d.docset.end();
+  docresultmap::iterator found = docset.end();
+  while (d_here != d_end) {
+    found = docset.find((*d_here).first);
+    if (found != docset.end()) {
+      (*found).second.combine ((*d_here).second);
+      tempresults[(*found).first] = (*found).second;
+    }
+    d_here++;
+  }
+
+  // then copy it back to docset
+  docset = tempresults;
+}
+
+void docresultsclass::combine_or (const docresultsclass &d) {
+  docorder.erase(docorder.begin(), docorder.end());
+    
+  docresultmap::const_iterator d_here = d.docset.begin();
+  docresultmap::const_iterator d_end = d.docset.end();
+  docresultmap::iterator found = docset.end();
+  while (d_here != d_end) {
+    found = docset.find((*d_here).first);
+    if (found != docset.end()) {
+      (*found).second.combine ((*d_here).second);
+    } else {
+      docset[(*d_here).first] = (*d_here).second;
+    }
+    d_here++;
+  }
+}
+
+void docresultsclass::combine_not (const docresultsclass &d) {
+  docorder.erase(docorder.begin(), docorder.end());
+
+ docresultmap::const_iterator d_here = d.docset.begin();
+ docresultmap::const_iterator d_end = d.docset.end();
+ docresultmap::iterator found = docset.end();
+ while (d_here != d_end) {
+   found = docset.find((*d_here).first);
+   if (found != docset.end()) docset.erase (found);
+   d_here++;
+ }
+}
+
+docresultsclass &docresultsclass::operator=(const docresultsclass &d) {
+  docset = d.docset;
+  docorder = d.docorder;
+
+  return *this;
+}
+
+
+
+
+// query results
+
+void queryresultsclass::clear () {
+  docs_matched = 0;
+  is_approx = Exact;
+
+  postprocessed = false;
+
+  docs.clear();
+  orgterms.erase(orgterms.begin(),orgterms.end());
+  terms.erase(terms.begin(),terms.end());
+}
+
+queryresultsclass &queryresultsclass::operator=(const queryresultsclass &q) {
+  docs_matched = q.docs_matched;
+  is_approx = q.is_approx;
+
+  postprocessed = q.postprocessed;
+  
+  docs = q.docs;
+  terms = q.terms;
+  termvariants = q.termvariants;
+
+  return *this;
+}
+
+void queryresultsclass::sortuniqqueryterms() {
+  termfreqclassarray tempterms = orgterms;
+  text_tset seenterms;
+  terms.erase(terms.begin(), terms.end());
+
+  // sort the terms to get the frequencies in ascending order
+  sort (tempterms.begin(), tempterms.end());
+
+  // insert first occurance of each term (maximum)
+  termfreqclassarray::reverse_iterator here = tempterms.rbegin();
+  termfreqclassarray::reverse_iterator end = tempterms.rend();
+  while (here != end) {
+    if (seenterms.find((*here).termstr) == seenterms.end()) {
+      // the termstemstr and utf8equivterms might be different for
+      // different occurances of the term
+      (*here).termstemstr.clear();
+      (*here).utf8equivterms.erase((*here).utf8equivterms.begin(),
+				   (*here).utf8equivterms.end());
+      terms.push_back(*here);
+      seenterms.insert((*here).termstr);
+    }
+    here++;
+  }
+
+  // now re-sort in ascending order
+  sort (terms.begin(), terms.end());
+}
+
+
+// stream output for debugging purposes
+ostream &operator<< (ostream &outs, queryresultsclass &q) {
+  outs << "*** queryresultsclass\n";
+  outs << "docs\n";
+
+  docresultmap::iterator docshere = q.docs.docset.begin();
+  docresultmap::iterator docsend = q.docs.docset.end();
+  while (docshere != docsend) {
+    outs << (*docshere).second;
+    docshere++;
+  }
+
+  outs << "orgterms\n";
+  termfreqclassarray::iterator orgtermshere = q.orgterms.begin();
+  termfreqclassarray::iterator orgtermsend = q.orgterms.end();
+  while (orgtermshere != orgtermsend) {
+    outs << (*orgtermshere);
+    orgtermshere++;
+  }
+
+  outs << "terms\n";
+  termfreqclassarray::iterator termshere = q.terms.begin();
+  termfreqclassarray::iterator termsend = q.terms.end();
+  while (termshere != termsend) {
+    outs << (*termshere);
+    termshere++;
+  }
+
+  outs << "\n";
+
+  return outs;
+}
Index: /main/tags/2.25/gsdl/src/colservr/queryinfo.h
===================================================================
--- /main/tags/2.25/gsdl/src/colservr/queryinfo.h	(revision 21064)
+++ /main/tags/2.25/gsdl/src/colservr/queryinfo.h	(revision 21064)
@@ -0,0 +1,187 @@
+/**********************************************************************
+ *
+ * queryinfo.h -- 
+ * Copyright (C) 1999  The New Zealand Digital Library Project
+ *
+ * A component of the Greenstone digital library software
+ * from the New Zealand Digital Library Project at the
+ * University of Waikato, New Zealand.
+ *
+ * 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.
+ *
+ *********************************************************************/
+
+
+#ifndef QUERYINFO_H
+#define QUERYINFO_H
+
+
+#include "gsdlconf.h"
+#include "text_t.h"
+#include "comtypes.h"
+
+#if defined(GSDL_USE_OBJECTSPACE)
+#  include <ospace\std\vector>
+#  include <ospace\std\algorithm>
+#elif defined(GSDL_USE_STL_H)
+#  include <vector.h>
+#  if defined(GSDL_USE_ALGO_H)
+#    include <algo.h>
+#  else
+#    include <algorithm.h>
+#  endif
+#else
+#  include <vector>
+#  include <algorithm>
+#endif
+
+// query parameters
+
+struct queryparamclass {
+  text_t combinequery;
+  text_t collection;
+
+  // search_index = index+subcollection+language
+  text_t index;
+  text_t subcollection;
+  text_t language;
+  text_t level; // for new mg stuff
+  text_t querystring;
+  int search_type; // 0 = boolean, 1 = ranked
+  int match_mode; // 0 = some, 1 = all
+  int casefolding;
+  int stemming;
+  int maxdocs;
+
+  queryparamclass ();
+  void clear ();
+  queryparamclass &operator=(const queryparamclass &q);
+};
+
+bool operator==(const queryparamclass &x, const queryparamclass &y);
+bool operator!=(const queryparamclass &x, const queryparamclass &y);
+
+// stream output for debugging purposes
+ostream &operator<< (ostream &outs, queryparamclass &q);
+
+
+
+// term frequencies
+
+struct termfreqclass {
+  text_t termstr;
+  text_t termstemstr;
+  text_tset utf8equivterms; // kept as utf8 string for fast matching
+  unsigned int termfreq;
+
+  termfreqclass ();
+  void clear();
+  termfreqclass &operator=(const termfreqclass &t);
+};
+
+typedef vector<termfreqclass> termfreqclassarray;
+
+bool operator==(const termfreqclass &x, const termfreqclass &y);
+bool operator!=(const termfreqclass &x, const termfreqclass &y);
+bool operator<(const termfreqclass &x, const termfreqclass &y);
+bool operator>(const termfreqclass &x, const termfreqclass &y);
+
+// stream output for debugging purposes
+ostream &operator<< (ostream &outs, termfreqclass &q);
+
+
+
+// one query result
+
+struct docresultclass {
+  int docnum;
+  float docweight;
+  unsigned int num_query_terms_matched;  // not available on all versions of mg
+  int num_phrase_match;                  // not available on all versions of mg
+
+  docresultclass();
+  ~docresultclass() {}
+  void clear ();
+  
+  // merges two result classes relating to a single docnum
+  docresultclass &combine(const docresultclass &d);
+
+  docresultclass &operator=(const docresultclass &d);
+};
+
+bool operator==(const docresultclass &x, const docresultclass &y);
+bool operator<(const docresultclass &x, const docresultclass &y);
+
+
+// stream output for debugging purposes
+ostream &operator<< (ostream &outs, docresultclass &a);
+
+
+struct ltint {
+  bool operator()(const int &t1, const int &t2) const
+  { return t1 < t2; }
+};
+
+typedef map<int, docresultclass, ltint> docresultmap;
+
+
+
+// many document results
+
+struct docresultsclass {
+  docresultmap docset;
+  vector<int> docorder;
+
+  docresultsclass ();
+  void clear ();
+  void docnum_order();
+
+  void combine_and (const docresultsclass &d);
+  void combine_or (const docresultsclass &d);
+  void combine_not (const docresultsclass &d);
+  
+  docresultsclass &operator=(const docresultsclass &d);
+};
+
+
+
+
+// query results
+
+struct queryresultsclass {
+  queryresultsclass () {clear();}
+
+  int docs_matched; // not available on all versions of mg
+  isapprox is_approx;
+  //  bool is_approx;   // not available on all versions of mg
+
+  bool postprocessed; // whether this record has been post-processed
+  
+  docresultsclass docs;
+  termfreqclassarray orgterms; // terms before they are sorted and uniqued
+  termfreqclassarray terms;
+  text_tset termvariants;
+  
+  void clear ();
+  queryresultsclass &operator=(const queryresultsclass &q);
+  
+  void sortuniqqueryterms();
+};
+
+// stream output for debugging purposes
+ostream &operator<< (ostream &outs, queryresultsclass &q);
+
+
+#endif
Index: /main/tags/2.25/gsdl/src/colservr/search.cpp
===================================================================
--- /main/tags/2.25/gsdl/src/colservr/search.cpp	(revision 21064)
+++ /main/tags/2.25/gsdl/src/colservr/search.cpp	(revision 21064)
@@ -0,0 +1,145 @@
+/**********************************************************************
+ *
+ * search.cpp -- abstract search class for mg
+ * Copyright (C) 1999  The New Zealand Digital Library Project
+ *
+ * A component of the Greenstone digital library software
+ * from the New Zealand Digital Library Project at the
+ * University of Waikato, New Zealand.
+ *
+ * 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.
+ *
+ * $Id$
+ *
+ *********************************************************************/
+
+/*
+   $Log$
+   Revision 1.1  2000/08/02 00:58:29  kjm18
+   mgpp incorporated. the old mgsearchclass and queryfilterclass are changed.
+   Have a base searchclass, from which mgsearchclass and mgppsearchclass inherit.
+   Have a base queryfilterclass, from which mgqueryfilterclass and
+   mgppqueryfilterclass inherit. librarymain in recpt should choose the appropriate
+   type (mg vs mgpp) for each collection.
+
+   Revision 1.22  1999/09/24 02:41:21  rjmcnab
+   change to use has_unicode_letdig in text_t
+
+   Revision 1.21  1999/09/21 21:41:41  sjboddie
+   fixed an error in what I committed last
+
+   Revision 1.20  1999/09/21 11:59:26  sjboddie
+   added Maxdocs queryfilter option (which may be -1 for 'all)
+
+   Revision 1.19  1999/09/07 22:52:52  rjmcnab
+   Seems to be an error in mg for retrieving documents using a paragraph
+   based index for some cases. Just added a work around (loads the default
+   index every time).
+
+   Revision 1.18  1999/09/07 04:57:22  sjboddie
+   added gpl notice
+
+   Revision 1.17  1999/08/31 22:42:41  rjmcnab
+   A couple of minor things.
+
+   Revision 1.16  1999/08/25 04:51:06  sjboddie
+   small change to allow for searching using boolean operators
+
+   Revision 1.15  1999/07/16 08:35:03  rjmcnab
+   Fixed a weird bug to do with a faulty case statement.
+
+   Revision 1.14  1999/07/16 03:42:22  sjboddie
+   changed isApprox
+
+   Revision 1.13  1999/07/16 00:12:46  sjboddie
+   removed all the old post-processing stuff
+
+   Revision 1.12  1999/07/07 06:17:47  rjmcnab
+   broke search_index into index+subcollection+language
+   within mgsearch
+
+   Revision 1.11  1999/07/05 21:06:43  rjmcnab
+   Disabled quoted strings.
+
+   Revision 1.10  1999/07/01 09:29:19  rjmcnab
+   Changes for better reporting of number documents which match a query. Changes
+   should still work as before with older versions of mg.
+
+   Revision 1.9  1999/07/01 03:54:48  rjmcnab
+   Added code to plug in the equivalent terms of each of the query terms.
+   Also added a function to get a raw utf8 encoded mg document (for speeding
+   up a phrase matching function)
+
+   Revision 1.8  1999/06/30 04:04:12  rjmcnab
+   made stemming functions available from mgsearch and made the stems
+   for the query terms available in queryinfo
+
+   Revision 1.7  1999/06/27 22:07:27  sjboddie
+   got rid of all the old functions for dealing with dir indexes
+
+   Revision 1.6  1999/06/09 00:41:32  sjboddie
+   phrase searching now uses case-folding if it's turned on
+
+   Revision 1.5  1999/02/21 22:31:35  rjmcnab
+
+   Removed locateinfo.
+
+   Revision 1.4  1999/02/03 01:13:27  sjboddie
+
+   Got interface to handle subcollections and language subcollections -
+   committed changes made to some of the collections
+
+   Revision 1.3  1999/01/19 01:38:17  rjmcnab
+
+   Made the source more portable.
+
+   Revision 1.2  1999/01/12 01:51:02  rjmcnab
+
+   Standard header.
+
+   Revision 1.1  1999/01/08 09:02:16  rjmcnab
+
+   Moved from src/library.
+
+ */
+
+#include "search.h"
+
+////////////////////
+// search class //
+////////////////////
+
+searchclass::searchclass ()
+{
+  cache = new querycache (RESULTCACHESIZE);
+ 
+}
+
+searchclass::~searchclass () 
+{
+  if (cache != NULL) 
+    {
+      delete cache;
+      cache = NULL;
+    }
+}
+
+
+void searchclass::setcollectdir (const text_t &thecollectdir)
+{
+  collectdir = thecollectdir;
+}
+
+
Index: /main/tags/2.25/gsdl/src/colservr/search.h
===================================================================
--- /main/tags/2.25/gsdl/src/colservr/search.h	(revision 21064)
+++ /main/tags/2.25/gsdl/src/colservr/search.h	(revision 21064)
@@ -0,0 +1,73 @@
+/**********************************************************************
+ *
+ * search.h -- abstract search class for mg systems
+ * Copyright (C) 1999  The New Zealand Digital Library Project
+ *
+ * A component of the Greenstone digital library software
+ * from the New Zealand Digital Library Project at the
+ * University of Waikato, New Zealand.
+ *
+ * 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.
+ *
+ * $Id$
+ *
+ *********************************************************************/
+
+
+#ifndef SEARCH_H
+#define SEARCH_H
+
+#include "text_t.h"
+#include "querycache.h"
+
+#define RESULTCACHESIZE 10
+#define MAXNUMDOCS      1000000
+#define MAXNUMTERMS     100
+
+class searchclass {
+public:
+  searchclass ();
+  virtual ~searchclass ();
+
+  // the index directory must be set before any searching
+  // is done
+  virtual void setcollectdir (const text_t &thecollectdir);
+  
+  // the search results are returned in queryresults
+  // search returns 'true' if it was able to do a search
+   virtual bool search(const queryparamclass &queryparams, 
+	      queryresultsclass &queryresults)=0;
+  
+  // the document text for 'docnum' is placed in 'output'
+  // docTargetDocument returns 'true' if it was able to
+  // try to get a document
+  // collection is needed to see if an index from the 
+  // collection is loaded. If no index has been loaded
+  // defaultindex is needed to load one
+  virtual bool docTargetDocument(const text_t &defaultindex,
+			 const text_t &defaultsubcollection,
+			 const text_t &defaultlanguage,
+			 const text_t &collection,
+			 int docnum,
+			 text_t &output)=0;
+
+protected:
+  querycache *cache;
+  text_t collectdir; // the collection directory
+
+};
+
+
+#endif
Index: /main/tags/2.25/gsdl/src/colservr/source.cpp
===================================================================
--- /main/tags/2.25/gsdl/src/colservr/source.cpp	(revision 21064)
+++ /main/tags/2.25/gsdl/src/colservr/source.cpp	(revision 21064)
@@ -0,0 +1,100 @@
+/**********************************************************************
+ *
+ * source.cpp -- 
+ * Copyright (C) 1999  The New Zealand Digital Library Project
+ *
+ * A component of the Greenstone digital library software
+ * from the New Zealand Digital Library Project at the
+ * University of Waikato, New Zealand.
+ *
+ * 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.
+ *
+ *********************************************************************/
+
+#include "source.h"
+#include <assert.h>
+
+
+// default constructor does nothing
+sourceclass::sourceclass () {
+}
+
+// default destructor does nothing
+sourceclass::~sourceclass () {
+}
+
+// configure should be called once for each configuration line
+// default does nothing
+void sourceclass::configure (const text_t &/*key*/, const text_tarray &/*cfgline*/) {
+}
+
+// init should be called after all the configuration is done but
+// before any other methods are called
+// default does nothing
+bool sourceclass::init (ostream &/*logout*/) {
+  return true;
+}
+
+
+// translate_OID translates OIDs using ".pr", ."fc" etc.
+bool sourceclass::translate_OID (const text_t &/*OIDin*/, text_t &/*OIDout*/, 
+				 comerror_t &err, ostream &/*logout*/) {
+  err = noError;
+
+  return false;
+}
+
+
+// get_metadata fills out the metadata if possible, if it is not responsable
+// for the given OID then it will return false.
+bool sourceclass::get_metadata (const text_t &/*requestParams*/, const text_t &/*refParams*/, 
+				bool /*getParents*/, const text_tset &/*fields*/, 
+				const text_t &/*OID*/, MetadataInfo_tmap &metadata, 
+				comerror_t &err, ostream &/*logout*/) {
+  metadata.erase(metadata.begin(), metadata.end());
+  err = noError;
+
+  return false;
+}
+
+bool sourceclass::get_document (const text_t &/*OID*/, text_t &/*doc*/, 
+				comerror_t &err, ostream &/*logout*/) {
+  err = noError;
+
+  return false;
+}
+
+
+bool operator==(const sourceptr &x, const sourceptr &y) {
+  return (x.s == y.s);
+}
+
+bool operator<(const sourceptr &x, const sourceptr &y) {
+  return (x.s < y.s);
+}
+
+
+// thesource remains the property of the calling code but
+// should not be deleted until it is removed from this list.
+void sourcelistclass::addsource (sourceclass *thesource) {
+  // can't add a source that doesn't exist
+  assert (thesource != NULL);
+  if (thesource == NULL) return;
+
+  sourceptr sp;
+  sp.s = thesource;
+
+  sourceptrs.push_back(sp);
+}
Index: /main/tags/2.25/gsdl/src/colservr/source.h
===================================================================
--- /main/tags/2.25/gsdl/src/colservr/source.h	(revision 21064)
+++ /main/tags/2.25/gsdl/src/colservr/source.h	(revision 21064)
@@ -0,0 +1,120 @@
+/**********************************************************************
+ *
+ * source.h -- 
+ * Copyright (C) 1999  The New Zealand Digital Library Project
+ *
+ * A component of the Greenstone digital library software
+ * from the New Zealand Digital Library Project at the
+ * University of Waikato, New Zealand.
+ *
+ * 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.
+ *
+ *********************************************************************/
+
+
+#ifndef SOURCE_H
+#define SOURCE_H
+
+#include "gsdlconf.h"
+#include "text_t.h"
+#include "comtypes.h"
+
+
+class sourceclass {
+public:
+  sourceclass ();
+  virtual ~sourceclass ();
+
+  // configure should be called once for each configuration line
+  virtual void configure (const text_t &key, const text_tarray &cfgline);
+
+  // init should be called after all the configuration is done but
+  // before any other methods are called
+  virtual bool init (ostream &logout);
+
+  // translate_OID translates OIDs using ".pr", ."fc" etc.
+  virtual bool translate_OID (const text_t &OIDin, text_t &OIDout, 
+			      comerror_t &err, ostream &logout);
+
+  // get_metadata fills out the metadata if possible, if it is not responsable
+  // for the given OID then it will return false.
+  virtual bool get_metadata (const text_t &requestParams, const text_t &refParams, 
+			     bool getParents, const text_tset &fields,
+			     const text_t &OID, MetadataInfo_tmap &metadata, 
+			     comerror_t &err, ostream &logout);
+
+  virtual bool get_document (const text_t &OID, text_t &doc, 
+			     comerror_t &err, ostream &logout);
+};
+
+
+// The sourceptr class does not 'own' the source. The 
+// source should be deleted by the code which created it.
+class sourceptr {
+public:
+  sourceclass *s;
+
+  sourceptr () {s=NULL;}
+  ~sourceptr () {}
+};
+
+bool operator==(const sourceptr &x, const sourceptr &y);
+bool operator<(const sourceptr &x, const sourceptr &y);
+
+typedef vector<sourceptr> sourceptrlist;
+
+// contains a list of sources
+class sourcelistclass {
+protected:
+  sourceptrlist sourceptrs;
+
+public:
+  // type support for sourcelistclass
+  typedef sourceptrlist::iterator iterator;
+  typedef sourceptrlist::const_iterator const_iterator;
+  typedef sourceptrlist::reference reference;
+  typedef sourceptrlist::const_reference const_reference;
+  typedef sourceptrlist::size_type size_type;
+
+  typedef sourceptrlist::difference_type difference_type;
+  typedef sourceptrlist::const_reverse_iterator const_reverse_iterator;
+  typedef sourceptrlist::reverse_iterator reverse_iterator;
+  
+  // basic container support
+  iterator begin () {return sourceptrs.begin();}
+  const_iterator begin () const {return sourceptrs.begin();}
+  iterator end () {return sourceptrs.end();}
+  const_iterator end () const {return sourceptrs.end();}
+
+  void erase(iterator pos) {sourceptrs.erase(pos);}
+  void erase(iterator first, iterator last) {sourceptrs.erase(first, last);}
+  sourcelistclass &operator=(const sourcelistclass &x) 
+    {sourceptrs=x.sourceptrs;return *this;}
+
+  bool empty () const {return sourceptrs.empty();}
+  size_type size() const {return sourceptrs.size();}
+
+
+  // added functionality
+  void clear () {sourceptrs.erase(sourceptrs.begin(),sourceptrs.end());}
+
+  // thesource remains the property of the calling code but
+  // should not be deleted until it is removed from this list.
+  void addsource (sourceclass *thesource);
+};
+
+
+
+#endif
Index: /main/tags/2.25/gsdl/src/colservr/win32.mak
===================================================================
--- /main/tags/2.25/gsdl/src/colservr/win32.mak	(revision 21064)
+++ /main/tags/2.25/gsdl/src/colservr/win32.mak	(revision 21064)
@@ -0,0 +1,74 @@
+###########################################################################
+#
+# win32 makefile -- src/colservr
+# A component of the Greenstone digital library software
+# from the New Zealand Digital Library Project at the
+# University of Waikato, New Zealand.
+#
+# Copyright (C) 1999  The 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.
+#
+###########################################################################
+
+GSDLHOME = c:\gsdl
+STLPATH = c:\stlport
+
+AR = lib
+CC = cl
+CPPFLAGS =
+LDFLAGS =
+DEFS = -DNZDL -DQUIET -D__WIN32__ -DGSDL_NAMESPACE_BROKEN -DGSDL_USE_IOS_H \
+       -DSHORT_SUFFIX -DPARADOCNUM -DHAVE_CONFIG_H -D__STL_NO_NEW_IOSTREAMS \
+       -DGSDLSERVER	
+INCLUDES = -I$(GSDLHOME)\src\colservr -I$(GSDLHOME)\lib -I$(GSDLHOME)\src\recpt \
+	   -I$(GSDLHOME)\packages\mg -I$(GSDLHOME)\packages\mg\lib \
+	   -I$(GSDLHOME)\packages\mg\src\text -I$(GSDLHOME)\packages\wingdbm \
+	   -I$(STLPATH)
+
+LIBS = $(GSDLHOME)\packages\wingdbm\gdbm.lib
+
+COMPILE = $(CC) -c $(CPPFLAGS) $(DEFS) $(INCLUDES)
+LINK = $(CC) $(LDFLAGS) -o $@
+
+.SUFFIXES:
+.SUFFIXES: .c .obj
+.c.obj:
+	$(COMPILE) $<
+
+.SUFFIXES: .cpp .obj
+.cpp.obj:
+	$(COMPILE) $< 
+
+HEADERS = mgq.h mgsearch.h querycache.h queryinfo.h collectserver.h \
+          colservrconfig.h maptools.h filter.h source.h browsefilter.h \
+          queryfilter.h mggdbmsource.h phrasesearch.h phrasequeryfilter.h
+
+SOURCES = mgq.c mgsearch.cpp querycache.cpp queryinfo.cpp collectserver.cpp \
+          colservrconfig.cpp maptools.cpp filter.cpp source.cpp \
+          browsefilter.cpp queryfilter.cpp mggdbmsource.cpp phrasesearch.cpp \
+          phrasequeryfilter.cpp
+
+OBJECTS = mgq.obj mgsearch.obj querycache.obj queryinfo.obj collectserver.obj \
+          colservrconfig.obj maptools.obj filter.obj source.obj browsefilter.obj \
+          queryfilter.obj mggdbmsource.obj phrasesearch.obj phrasequeryfilter.obj
+
+all : $(OBJECTS)
+
+clean:
+	del *.obj
+
+install:
Index: /main/tags/2.25/gsdl/src/db2txt/Makefile.in
===================================================================
--- /main/tags/2.25/gsdl/src/db2txt/Makefile.in	(revision 21064)
+++ /main/tags/2.25/gsdl/src/db2txt/Makefile.in	(revision 21064)
@@ -0,0 +1,85 @@
+###########################################################################
+#
+# Makefile -- Makefile for db2txt
+# A component of the Greenstone digital library software
+# from the New Zealand Digital Library Project at the
+# University of Waikato, New Zealand.
+#
+# Copyright (C) 1999 Rodger McNab, Stefan Boddie
+#
+#
+# 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.
+#
+#       @(#)Makefile.in	1.3 16 Mar 1994
+#
+###########################################################################
+
+ 
+AR = ar
+CC = @CC@
+CCFLAGS = -Wall @CFLAGS@ 
+DEFS = @DEFS@
+RANLIB = @RANLIB@
+INCLUDES = -I../../lib
+LDFLAGS =
+DPLIBS = 
+#LIBS = -lstdc++ -lgdbm
+LIBS = @LIBS@
+GSDLOS = @gsdlos@
+
+ 
+COMPILE = $(CC) -c $(DEFS) $(INCLUDES) $(CCFLAGS)
+LINK = $(CC) $(LDFLAGS) -o $@
+ 
+.SUFFIXES:
+.SUFFIXES: .c .o
+.c.o:
+	$(COMPILE) $<
+
+.SUFFIXES: .cpp .o
+.cpp.o:
+	$(COMPILE) $< 
+ 
+
+HEADERS = 
+
+SOURCES = db2txt.cpp
+
+OBJECTS = db2txt.o
+
+EXEC    = db2txt
+ 
+all : $(EXEC)
+
+install: $(EXEC)
+	install -d ../../bin/$(GSDLOS)
+	install -m 755 -s $(EXEC) ../../bin/$(GSDLOS)
+
+distclean:
+	rm -f $(OBJECTS) $(EXEC) Makefile
+
+clean:
+	rm -f $(OBJECTS) $(EXEC)
+
+depend:
+	makedepend -Y -- $(DEFS) $(INCLUDES) $(CCFLAGS) -- $(SOURCES)
+
+
+# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
+
+DB2TXT_OBJS = db2txt.o
+
+db2txt: $(DB2TXT_OBJS) $(DPLIBS)
+	$(LINK) $(DB2TXT_OBJS) $(LIBS) 
Index: /main/tags/2.25/gsdl/src/db2txt/db2txt.cpp
===================================================================
--- /main/tags/2.25/gsdl/src/db2txt/db2txt.cpp	(revision 21064)
+++ /main/tags/2.25/gsdl/src/db2txt/db2txt.cpp	(revision 21064)
@@ -0,0 +1,91 @@
+/**********************************************************************
+ *
+ * db2txt.cpp -- 
+ * Copyright (C) 1999  The New Zealand Digital Library Project
+ *
+ * A component of the Greenstone digital library software
+ * from the New Zealand Digital Library Project at the
+ * University of Waikato, New Zealand.
+ *
+ * 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.
+ *
+ *********************************************************************/
+
+
+#ifdef __WIN32__
+#include "autoconf.h"
+#include "systems.h"
+#include "gdbmconst.h"
+#include "gdbm.h"
+
+#else
+#include <gdbm.h>
+#endif
+
+#include "gsdlconf.h"
+#include <stdlib.h>
+
+#if defined(GSDL_USE_OBJECTSPACE)
+#include <ospace\std\iostream>
+#elif defined(GSDL_USE_IOS_H)
+#include <iostream.h>
+#else
+#include <iostream>
+#endif
+
+void print_usage (char *program_name) {
+  cerr << "usage: " << program_name << " database-name\n\n";
+}
+
+
+int main (int argc, char *argv[]) {
+  int block_size = 0, i;
+  GDBM_FILE dbf;
+  datum key, value;
+      
+  // sanity check
+  if (argc != 2) {
+    print_usage (argv[0]);
+    exit (0);
+  }
+  
+  // open the database
+#ifdef __WIN32__
+  dbf = gdbm_open (argv[1], block_size, GDBM_READER, 00664, NULL, 0);
+#else
+  dbf = gdbm_open  (argv[1], block_size, GDBM_READER, 00664, NULL);
+#endif
+  if (dbf == NULL) {
+    cerr << "couldn't create " << argv[1] << "\n";
+    exit (0);
+  }
+
+  key = gdbm_firstkey (dbf);
+  while (key.dptr != NULL) {
+    cout << "[";
+    for (i = 0; i < key.dsize; i++)
+      cout << key.dptr[i];
+    cout << "]\n";
+    value = gdbm_fetch (dbf, key);
+    for (i = 0; i < value.dsize; i++)
+      cout << value.dptr[i];
+    cout << "\n----------------------------------------------------------------------\n";
+    key = gdbm_nextkey (dbf, key);
+    delete value.dptr;
+  }
+  
+  gdbm_close (dbf);
+  return 0;
+}
Index: /main/tags/2.25/gsdl/src/db2txt/win32.mak
===================================================================
--- /main/tags/2.25/gsdl/src/db2txt/win32.mak	(revision 21064)
+++ /main/tags/2.25/gsdl/src/db2txt/win32.mak	(revision 21064)
@@ -0,0 +1,72 @@
+###########################################################################
+#
+# win32 makefile -- db2txt
+# A component of the Greenstone digital library software
+# from the New Zealand Digital Library Project at the
+# University of Waikato, New Zealand.
+#
+# Copyright (C) 1999  The 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.
+#
+###########################################################################
+
+GSDLHOME = d:\home\dl\gsdl
+STLPATH = d:\home\dl\stl\stlport
+
+AR = lib
+CC = cl
+CPPFLAGS = 
+LDFLAGS =
+DEFS = -DQUIET -DHAVE_CONFIG_H -D__WIN32__ -D__STL_NO_NEW_IOSTREAMS \
+       -DGSDL_NAMESPACE_BROKEN -DSHORT_SUFFIX -DGSDL_USE_IOS_H
+INCLUDES = -I$(GSDLHOME)\src\db2txt -I$(GSDLHOME)\lib -I$(GSDLHOME)\packages\mg\lib \
+	   -I$(STLPATH) -I$(GSDLHOME)\packages\wingdbm
+LIBS = $(GSDLHOME)\packages\mg\lib\unitool.obj $(GSDLHOME)\lib\gsdllib.lib \
+       $(GSDLHOME)\packages\wingdbm\gdbm.lib
+
+COMPILE = $(CC) -c -GX $(DEFS) $(INCLUDES)
+LINK = $(CC) $(LDFLAGS)
+
+.SUFFIXES:
+.SUFFIXES: .cpp .obj
+.cpp.obj:
+	$(COMPILE) $<
+
+ANSI2KNR = 
+o = .obj
+e = .exe
+
+HEADERS = 
+
+SOURCES = db2txt.cpp
+
+OBJECTS = db2txt$o
+
+EXEC = db2txt$e
+
+all : $(EXEC)
+
+install: $(EXEC)
+	if NOT EXIST $(GSDLHOME)\bin\windows mkdir $(GSDLHOME)\bin\windows
+	copy $(EXEC) $(GSDLHOME)\bin\windows\$(EXEC)
+
+clean:
+	del *.$o
+	del $(EXEC)
+
+db2txt$e: $(OBJECTS) $(LIBS)
+	  $(LINK) $(OBJECTS) $(LIBS)
Index: /main/tags/2.25/gsdl/src/hashfile/Makefile.in
===================================================================
--- /main/tags/2.25/gsdl/src/hashfile/Makefile.in	(revision 21064)
+++ /main/tags/2.25/gsdl/src/hashfile/Makefile.in	(revision 21064)
@@ -0,0 +1,83 @@
+###########################################################################
+#
+# Makefile -- Makefile for hashfile
+# A component of the Greenstone digital library software
+# from the New Zealand Digital Library Project at the
+# University of Waikato, New Zealand.
+#
+# Copyright (C) 1999 Rodger McNab, Stefan Boddie
+#
+#
+# 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.
+#
+#       @(#)Makefile.in	1.3 16 Mar 1994
+#
+###########################################################################
+
+ 
+AR = ar
+CC = @CC@
+CCFLAGS = -Wall @CFLAGS@
+DEFS = @DEFS@
+RANLIB = @RANLIB@
+INCLUDES = -I../../lib
+LDFLAGS = 
+LIBS = ../../lib/gsdllib.a
+GSDLOS = @gsdlos@
+
+ 
+COMPILE = $(CC) -c $(DEFS) $(INCLUDES) $(CCFLAGS)
+LINK = $(CC) $(LDFLAGS) -o $@
+ 
+.SUFFIXES:
+.SUFFIXES: .c .o
+.c.o:
+	$(COMPILE) $<
+
+.SUFFIXES: .cpp .o
+.cpp.o:
+	$(COMPILE) $< 
+ 
+
+HEADERS = 
+
+SOURCES = hashfile.cpp
+
+OBJECTS = hashfile.o
+
+EXEC    = hashfile
+ 
+all : $(EXEC)
+
+install: $(EXEC)
+	install -d ../../bin/$(GSDLOS)
+	install -m 755 -s $(EXEC) ../../bin/$(GSDLOS)
+
+distclean:
+	rm -f $(OBJECTS) $(EXEC) Makefile
+
+clean:
+	rm -f $(OBJECTS) $(EXEC)
+
+depend:
+	makedepend -Y -- $(DEFS) $(INCLUDES) $(CCFLAGS) -- $(SOURCES)
+
+
+# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
+
+HASHFILE_OBJS = hashfile.o
+
+hashfile: $(HASHFILE_OBJS) $(LIBS)
+	$(LINK) $(HASHFILE_OBJS) $(LIBS) 
Index: /main/tags/2.25/gsdl/src/hashfile/hashfile.cpp
===================================================================
--- /main/tags/2.25/gsdl/src/hashfile/hashfile.cpp	(revision 21064)
+++ /main/tags/2.25/gsdl/src/hashfile/hashfile.cpp	(revision 21064)
@@ -0,0 +1,263 @@
+/**********************************************************************
+ *
+ * hashfile.cpp -- 
+ * Copyright (C) 1999  The New Zealand Digital Library Project
+ *
+ * A component of the Greenstone digital library software
+ * from the New Zealand Digital Library Project at the
+ * University of Waikato, New Zealand.
+ *
+ * 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.
+ *
+ *********************************************************************/
+
+#include <stdio.h>
+
+#define MAXNUMLEN  100   // bytes
+
+
+// The number class is used to store very long unsigned integers.
+// The least significant of each number is stored first. Numbers can 
+// be no longer than MAXNUMLEN bytes long. A number with length=0
+// is considered to be equal to 0. There should be no extra zeros
+// at the front of the number.
+
+struct number {
+  unsigned int len;
+  unsigned char num[MAXNUMLEN];
+
+  number () {len = 0;}
+};
+
+
+// evaluates a = a + b
+// a and b can be the same number
+void my_inc (number &a, number &b) {
+  unsigned int carry = 0;
+  unsigned int num = 0;
+  unsigned int i = 0;
+
+  while ((carry || (i < a.len) || (i < b.len)) && (i < MAXNUMLEN)) {
+    num = carry;
+    if (i < a.len) num += a.num[i];
+    if (i < b.len) num += b.num[i];
+
+    if (num >= 256) {
+      num -= 256; // assumes that each number in the list < 256
+      carry = 1;
+    } else {
+      carry = 0;
+    }
+    a.num[i] = (unsigned char)num;
+
+    i++;
+  }
+
+  a.len = i;
+}
+
+
+// evaluates a = a - b if a >= b
+// returns true if the subtraction was possible
+int my_ifpos_dec (number &a, number &b) {
+  int carry = 0;
+  int num = 0;
+  int i = 0;
+  unsigned int len = 0; // the last non-zero digit
+
+  // make sure a >= b
+  if (b.len > a.len) return 0;
+  if (b.len == a.len) {
+    i = a.len - 1;
+    while (i >= 0) {
+      if (a.num[i] > b.num[i]) break;
+      if (a.num[i] < b.num[i]) return 0;
+      i--;
+    }
+  }
+
+  unsigned int j = 0;
+  len = 0;
+  while ((j < a.len) || (j < b.len)) {
+    num = -carry;
+    if (j < a.len) num += a.num[j];
+    if (j < b.len) num -= b.num[j];
+
+    if (num < 0) {
+      num += 256; // assumes each number in the list < 256
+      carry = 1;
+    } else {
+      carry = 0;
+    }
+
+    a.num[j] = (unsigned char) num;
+    
+    j++;
+    if (num != 0) len = j;
+  }
+
+  a.len = len;
+
+  if (carry) {
+    // panic, this should NOT happen
+    fprintf (stderr, "panic: error in my_ifpos_dec\n");
+  }
+
+  return 1;
+}
+
+
+char *my_convert_num (number &a) {
+  char *result = new char[(a.len*2)+1];
+  int i,len;
+  char convert[16] = {'0','1','2','3','4','5','6','7',
+		      '8','9','a','b','c','d','e','f'};
+
+  // zero might be a special case
+  if (a.len == 0) {
+    result[0] = '0';
+    result[1] = '\0';
+    return result;
+  }
+
+  for (i=a.len-1, len=0; i >= 0; i--) {
+    result[len++] = convert[a.num[i]/16];
+    result[len++] = convert[a.num[i]%16];
+  }
+  result[len] = '\0';
+
+  return result;
+}
+
+
+
+// create a hash string from the contents of a file.
+//
+// The file is treated as a large base 256 number (each char is a digit),
+// and the hash value is the remainder when this number is divided by a
+// very large prime.
+//
+// PROBLEM: This is a flawed hash function because the rightmost (highest)
+// value in remainder is more likely to be a "1" than it is to be any other
+// number.  
+//
+// EVIDENCE: About 50% of the files in any GSDL directory have a hash code
+// that starts with 01* which implies (based on the my_convert_num function)
+// that the rightmost "digit" of the remainder = z such that (z % 16 = 0)
+// and (z / 16 = 1) which means (z = 1).
+//
+// MAJOR REASON: suppose our prime number was 19.  Then, if we have a 
+// reasonably random distribution of numbers for which we are going to 
+// calculate (N % 19), we expect to get a roughly uniform distribution
+// of remainders where the possible values are 0, 1, 2, 3... 18.  The
+// problem is that 9 out of the 19 possible values (10,11... 18) start
+// with the digit 1.  Thus our hascode will start with "01".
+//
+// ANOTHER PROBLEM: Characters in the file are read one at a time; after each 
+// one is read it is prepended to the remainder, then the remainder is
+// recalculated on the string thus far seen.  I am sure the math here 
+// is wrong - if I try calculating (111 mod 7) by the same algorithm, it
+// simply does nor work.
+//
+// ANOTHER POSSIBLE PROLEM: Each character from the file is read into 
+// remainder at the most significant end, and when that character
+// is a zero you get a number like "01" which would be considered 
+// larger than a number like "8" because it is longer (two  digits
+// instead of 1).  
+//
+// These comments added by Gordon Paynter (gwp@cs.waikato.ac.nz) in
+// June 2000.  I didn't write any code, however.
+
+char *hashfile (char *filename) {
+  FILE *infile = (FILE *)NULL;
+  int i;
+
+  number primepow[8];
+  number pow;
+  number remainder;
+  unsigned char c;
+
+  // our prime number (618970019642690137449562111)
+  pow.num[0] = 255;  pow.num[1] = 255;
+  pow.num[2] = 255;  pow.num[3] = 255;
+  pow.num[4] = 255;  pow.num[5] = 255;
+  pow.num[6] = 255;  pow.num[7] = 255;
+  pow.num[8] = 255;  pow.num[9] = 255;
+  pow.num[10] = 255; pow.num[11] = 1;
+  pow.len = 12;
+
+  // calculate 8 multiples of the prime number.
+  // These are used to find the remainder using only subtraction operations
+  for (i=0; i<8; i++) {
+    primepow[i] = pow;
+    my_inc (pow, pow);
+  }
+
+  // The "remainder" after division by the prime.  Our result.
+  remainder.len = 0;
+
+  // open the file
+  infile = fopen (filename, "rb");
+  if (infile == NULL) {
+    return (char *)NULL;
+  }
+  c = (unsigned char)fgetc(infile);
+  
+  while (!feof (infile)) {
+
+    // make sure the remainder has not grown too large
+    if (remainder.len == MAXNUMLEN-1) {
+      fprintf (stderr, "ERROR - number overflow\n");
+      return (char *)NULL;
+    }
+
+    // remainder = remainder * 256 + c
+    for (i=remainder.len; i>0; i--) {
+      remainder.num[i] = remainder.num[i-1];
+    }
+    remainder.num[0] = c;
+    if (remainder.len > 0 || c != 0) remainder.len = remainder.len+1;
+    
+    // remainder = (remainder % large-prime-number)
+    for (i=7; i>=0; i--) {
+      my_ifpos_dec (remainder, primepow[i]);
+    }
+
+    // read a new character from the file
+    c = (unsigned char)fgetc(infile);
+  }
+
+  fclose (infile);
+
+  return my_convert_num (remainder);
+}
+
+
+int main (int argc, char *argv[]) {
+  int i;
+  char *result;
+
+  for (i = 1; i < argc; i++) {
+    result = hashfile (argv[i]);
+    if (result == NULL) {
+      printf ("ERROR - could not process %s\n", argv[i]);
+    } else {
+      printf ("%s: %s\n", argv[i], result);
+      delete [] result;
+    }
+  }
+
+  return 0;
+}
Index: /main/tags/2.25/gsdl/src/hashfile/win32.mak
===================================================================
--- /main/tags/2.25/gsdl/src/hashfile/win32.mak	(revision 21064)
+++ /main/tags/2.25/gsdl/src/hashfile/win32.mak	(revision 21064)
@@ -0,0 +1,71 @@
+###########################################################################
+#
+# win32 makefile -- hashfile
+# A component of the Greenstone digital library software
+# from the New Zealand Digital Library Project at the
+# University of Waikato, New Zealand.
+#
+# Copyright (C) 1999  The 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.
+#
+###########################################################################
+ 
+GSDLHOME = d:\home\dl\gsdl
+STLPATH = d:\home\dl\stl\stlport
+
+AR = lib
+CC = cl
+CPPFLAGS = 
+DEFS = -DQUIET -DHAVE_CONFIG_H -D__WIN32__ -D__STL_NO_NEW_IOSTREAMS \
+       -DGSDL_NAMESPACE_BROKEN -DSHORT_SUFFIX -DGSDL_USE_IOS_H
+INCLUDES = -I$(GSDLHOME)\src\hashfile -I$(GSDLHOME)\lib -I$(STLPATH)
+LIBS = $(GSDLHOME)\lib\gsdllib.lib
+
+COMPILE = $(CC) -c -GX $(DEFS) $(INCLUDES)
+LINK = $(CC) $(LDFLAGS)
+
+.SUFFIXES:
+.SUFFIXES: .cpp .obj
+.cpp.obj:
+	$(COMPILE) $<
+
+ANSI2KNR = 
+o = .obj
+e = .exe
+ 
+HEADERS = 
+
+SOURCES = hashfile.cpp
+
+OBJECTS = hashfile$o
+
+EXEC = hashfile$e
+ 
+all : $(EXEC)
+
+install: $(EXEC)
+	if NOT EXIST $(GSDLHOME)\bin\windows mkdir $(GSDLHOME)\bin\windows
+	copy $(EXEC) $(GSDLHOME)\bin\windows\$(EXEC)
+
+clean:
+	del *.$o
+	del $(EXEC)
+
+HASHFILE_OBJS = hashfile$o
+
+hashfile$e: $(HASHFILE_OBJS) $(LIBS)
+	    $(LINK) $(HASHFILE_OBJS) $(LIBS)
Index: /main/tags/2.25/gsdl/src/mgpp/COPYING
===================================================================
--- /main/tags/2.25/gsdl/src/mgpp/COPYING	(revision 21064)
+++ /main/tags/2.25/gsdl/src/mgpp/COPYING	(revision 21064)
@@ -0,0 +1,344 @@
+		    GNU GENERAL PUBLIC LICENSE
+		       Version 2, June 1991
+
+ Copyright (C) 1989, 1991 Free Software Foundation, Inc.
+                          675 Mass Ave, Cambridge, MA 02139, USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+			    Preamble
+
+  The licenses for most software are designed to take away your
+freedom to share and change it.  By contrast, the GNU General Public
+License is intended to guarantee your freedom to share and change free
+software--to make sure the software is free for all its users.  This
+General Public License applies to most of the Free Software
+Foundation's software and to any other program whose authors commit to
+using it.  (Some other Free Software Foundation software is covered by
+the GNU Library General Public License instead.)  You can apply it to
+your programs, too.
+
+  When we speak of free software, we are referring to freedom, not
+price.  Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+this service if you wish), that you receive source code or can get it
+if you want it, that you can change the software or use pieces of it
+in new free programs; and that you know you can do these things.
+
+  To protect your rights, we need to make restrictions that forbid
+anyone to deny you these rights or to ask you to surrender the rights.
+These restrictions translate to certain responsibilities for you if you
+distribute copies of the software, or if you modify it.
+
+  For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must give the recipients all the rights that
+you have.  You must make sure that they, too, receive or can get the
+source code.  And you must show them these terms so they know their
+rights.
+
+  We protect your rights with two steps: (1) copyright the software, and
+(2) offer you this license which gives you legal permission to copy,
+distribute and/or modify the software.
+
+  Also, for each author's protection and ours, we want to make certain
+that everyone understands that there is no warranty for this free
+software.  If the software is modified by someone else and passed on, we
+want its recipients to know that what they have is not the original, so
+that any problems introduced by others will not reflect on the original
+authors' reputations.
+
+  Finally, any free program is threatened constantly by software
+patents.  We wish to avoid the danger that redistributors of a free
+program will individually obtain patent licenses, in effect making the
+program proprietary.  To prevent this, we have made it clear that any
+patent must be licensed for everyone's free use or not licensed at all.
+
+  The precise terms and conditions for copying, distribution and
+modification follow.
+
+
+		    GNU GENERAL PUBLIC LICENSE
+   TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+  0. This License applies to any program or other work which contains
+a notice placed by the copyright holder saying it may be distributed
+under the terms of this General Public License.  The "Program", below,
+refers to any such program or work, and a "work based on the Program"
+means either the Program or any derivative work under copyright law:
+that is to say, a work containing the Program or a portion of it,
+either verbatim or with modifications and/or translated into another
+language.  (Hereinafter, translation is included without limitation in
+the term "modification".)  Each licensee is addressed as "you".
+
+Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope.  The act of
+running the Program is not restricted, and the output from the Program
+is covered only if its contents constitute a work based on the
+Program (independent of having been made by running the Program).
+Whether that is true depends on what the Program does.
+
+  1. You may copy and distribute verbatim copies of the Program's
+source code as you receive it, in any medium, provided that you
+conspicuously and appropriately publish on each copy an appropriate
+copyright notice and disclaimer of warranty; keep intact all the
+notices that refer to this License and to the absence of any warranty;
+and give any other recipients of the Program a copy of this License
+along with the Program.
+
+You may charge a fee for the physical act of transferring a copy, and
+you may at your option offer warranty protection in exchange for a fee.
+
+  2. You may modify your copy or copies of the Program or any portion
+of it, thus forming a work based on the Program, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+    a) You must cause the modified files to carry prominent notices
+    stating that you changed the files and the date of any change.
+
+    b) You must cause any work that you distribute or publish, that in
+    whole or in part contains or is derived from the Program or any
+    part thereof, to be licensed as a whole at no charge to all third
+    parties under the terms of this License.
+
+    c) If the modified program normally reads commands interactively
+    when run, you must cause it, when started running for such
+    interactive use in the most ordinary way, to print or display an
+    announcement including an appropriate copyright notice and a
+    notice that there is no warranty (or else, saying that you provide
+    a warranty) and that users may redistribute the program under
+    these conditions, and telling the user how to view a copy of this
+    License.  (Exception: if the Program itself is interactive but
+    does not normally print such an announcement, your work based on
+    the Program is not required to print an announcement.)
+
+
+These requirements apply to the modified work as a whole.  If
+identifiable sections of that work are not derived from the Program,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works.  But when you
+distribute the same sections as part of a whole which is a work based
+on the Program, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Program.
+
+In addition, mere aggregation of another work not based on the Program
+with the Program (or with a work based on the Program) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+  3. You may copy and distribute the Program (or a work based on it,
+under Section 2) in object code or executable form under the terms of
+Sections 1 and 2 above provided that you also do one of the following:
+
+    a) Accompany it with the complete corresponding machine-readable
+    source code, which must be distributed under the terms of Sections
+    1 and 2 above on a medium customarily used for software interchange; or,
+
+    b) Accompany it with a written offer, valid for at least three
+    years, to give any third party, for a charge no more than your
+    cost of physically performing source distribution, a complete
+    machine-readable copy of the corresponding source code, to be
+    distributed under the terms of Sections 1 and 2 above on a medium
+    customarily used for software interchange; or,
+
+    c) Accompany it with the information you received as to the offer
+    to distribute corresponding source code.  (This alternative is
+    allowed only for noncommercial distribution and only if you
+    received the program in object code or executable form with such
+    an offer, in accord with Subsection b above.)
+
+The source code for a work means the preferred form of the work for
+making modifications to it.  For an executable work, complete source
+code means all the source code for all modules it contains, plus any
+associated interface definition files, plus the scripts used to
+control compilation and installation of the executable.  However, as a
+special exception, the source code distributed need not include
+anything that is normally distributed (in either source or binary
+form) with the major components (compiler, kernel, and so on) of the
+operating system on which the executable runs, unless that component
+itself accompanies the executable.
+
+If distribution of executable or object code is made by offering
+access to copy from a designated place, then offering equivalent
+access to copy the source code from the same place counts as
+distribution of the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+
+  4. You may not copy, modify, sublicense, or distribute the Program
+except as expressly provided under this License.  Any attempt
+otherwise to copy, modify, sublicense or distribute the Program is
+void, and will automatically terminate your rights under this License.
+However, parties who have received copies, or rights, from you under
+this License will not have their licenses terminated so long as such
+parties remain in full compliance.
+
+  5. You are not required to accept this License, since you have not
+signed it.  However, nothing else grants you permission to modify or
+distribute the Program or its derivative works.  These actions are
+prohibited by law if you do not accept this License.  Therefore, by
+modifying or distributing the Program (or any work based on the
+Program), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Program or works based on it.
+
+  6. Each time you redistribute the Program (or any work based on the
+Program), the recipient automatically receives a license from the
+original licensor to copy, distribute or modify the Program subject to
+these terms and conditions.  You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties to
+this License.
+
+  7. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License.  If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Program at all.  For example, if a patent
+license would not permit royalty-free redistribution of the Program by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Program.
+
+If any portion of this section is held invalid or unenforceable under
+any particular circumstance, the balance of the section is intended to
+apply and the section as a whole is intended to apply in other
+circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system, which is
+implemented by public license practices.  Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+
+  8. If the distribution and/or use of the Program is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Program under this License
+may add an explicit geographical distribution limitation excluding
+those countries, so that distribution is permitted only in or among
+countries not thus excluded.  In such case, this License incorporates
+the limitation as if written in the body of this License.
+
+  9. The Free Software Foundation may publish revised and/or new versions
+of the General Public License from time to time.  Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+Each version is given a distinguishing version number.  If the Program
+specifies a version number of this License which applies to it and "any
+later version", you have the option of following the terms and conditions
+either of that version or of any later version published by the Free
+Software Foundation.  If the Program does not specify a version number of
+this License, you may choose any version ever published by the Free Software
+Foundation.
+
+  10. If you wish to incorporate parts of the Program into other free
+programs whose distribution conditions are different, write to the author
+to ask for permission.  For software which is copyrighted by the Free
+Software Foundation, write to the Free Software Foundation; we sometimes
+make exceptions for this.  Our decision will be guided by the two goals
+of preserving the free status of all derivatives of our free software and
+of promoting the sharing and reuse of software generally.
+
+			    NO WARRANTY
+
+  11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
+FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW.  EXCEPT WHEN
+OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
+PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
+OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.  THE ENTIRE RISK AS
+TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU.  SHOULD THE
+PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
+REPAIR OR CORRECTION.
+
+  12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
+REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
+INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
+OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
+TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
+YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
+PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGES.
+
+		     END OF TERMS AND CONDITIONS
+
+
+	    How to Apply These Terms to Your New Programs
+
+  If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+  To do so, attach the following notices to the program.  It is safest
+to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least
+the "copyright" line and a pointer to where the full notice is found.
+
+    <one line to give the program's name and a brief idea of what it does.>
+    Copyright (C) 19yy  <name of author>
+
+    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.
+
+Also add information on how to contact you by electronic and paper mail.
+
+If the program is interactive, make it output a short notice like this
+when it starts in an interactive mode:
+
+    Gnomovision version 69, Copyright (C) 19yy name of author
+    Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
+    This is free software, and you are welcome to redistribute it
+    under certain conditions; type `show c' for details.
+
+The hypothetical commands `show w' and `show c' should show the appropriate
+parts of the General Public License.  Of course, the commands you use may
+be called something other than `show w' and `show c'; they could even be
+mouse-clicks or menu items--whatever suits your program.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the program, if
+necessary.  Here is a sample; alter the names:
+
+  Yoyodyne, Inc., hereby disclaims all copyright interest in the program
+  `Gnomovision' (which makes passes at compilers) written by James Hacker.
+
+  <signature of Ty Coon>, 1 April 1989
+  Ty Coon, President of Vice
+
+This General Public License does not permit incorporating your program into
+proprietary programs.  If your program is a subroutine library, you may
+consider it more useful to permit linking proprietary applications with the
+library.  If this is what you want to do, use the GNU Library General
+Public License instead of this License.
Index: /main/tags/2.25/gsdl/src/mgpp/Makefile.in
===================================================================
--- /main/tags/2.25/gsdl/src/mgpp/Makefile.in	(revision 21064)
+++ /main/tags/2.25/gsdl/src/mgpp/Makefile.in	(revision 21064)
@@ -0,0 +1,110 @@
+# Main Makefile for GNU tar.
+# Copyright (C) 1994, 1995 Free Software Foundation, Inc.
+ 
+# 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, 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 = @PACKAGE@
+VERSION = @VERSION@
+ 
+@SET_MAKE@
+SHELL = /bin/sh
+VPATH = @srcdir@
+exec_prefix = @exec_prefix@
+prefix = @prefix@
+srcdir = @srcdir@
+ 
+
+CC = @CC@
+CPP = @CXX@
+CFLAGS = @CFLAGS@ -ansi
+INSTALL = @INSTALL@
+INSTALL_DATA = @INSTALL_DATA@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@
+LDFLAGS = @LDFLAGS@
+LIBS = @LIBS@  
+TOUCH = echo timestamp >
+ 
+bindir = $(exec_prefix)/bin
+infodir = $(prefix)/info
+libexecdir = $(exec_prefix)/libexec
+ 
+MDEFINES = 
+#CC='$(CC)' CFLAGS='$(CFLAGS)' LDFLAGS='$(LDFLAGS)' LIBS='$(LIBS)' \
+#prefix='$(prefix)' exec_prefix='$(exec_prefix)' \
+#bindir='$(bindir)' libexecdir='$(libexecdir)' \
+#infodir='$(infodir)' infodir='$(infodir)' libexecdir='$(libexecdir)'
+
+SUBDIRS = lib text
+
+
+.SUFFIXES:
+
+all install uninstall execinstall execuninstall maninstall manuninstall: config.h
+	for subdir in $(SUBDIRS); do \
+	  echo making $@ in $$subdir; \
+	  (cd $$subdir && $(MAKE) $(MDEFINES) $@) || exit 1; \
+	done
+
+# Have not written any texinfo files for the documentation yet
+#info dvi:
+#	cd doc && $(MAKE) $@
+
+mostlyclean: mostlyclean-recursive mostlyclean-local
+
+clean: clean-recursive clean-local
+
+distclean: distclean-recursive distclean-local
+	rm config.status
+
+maintainer-clean: maintainer-clean-recursive maintainer-clean-local
+	rm config.status
+
+mostlyclean-recursive clean-recursive distclean-recursive \
+maintainer-clean-recursive:
+	for subdir in $(SUBDIRS); do \
+	  target=`echo $@ | sed 's/-recursive//'`; \
+	  echo making $$target in $$subdir; \
+	  (cd $$subdir && $(MAKE) $$target) || exit 1; \
+	done
+
+mostlyclean-local:
+
+clean-local: mostlyclean-local
+
+distclean-local: clean-local
+	rm -f Makefile config.cache config.h config.log stamp-h
+
+maintainer-clean-local: distclean-local
+	@echo "This command is intended only for maintainers to use;"
+	@echo "rebuilding the deleted files may require special tools."
+
+# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
+
+distdir = $(PACKAGE)-$(VERSION)
+
+distname = $(distdir)
+
+DISTFILES = \
+INSTALL.mg INSTALL README README.port COPYING MODIFICATIONS about_mg.html \
+Makefile.in acconfig.h aclocal.m4 configure.in install-sh mkinstalldirs \
+config.guess config.sub \
+config.h.in configure stamp-h.in
+
+#-----------------------------------------------------------------
+
+# Tell versions [3.59,3.63) of GNU make not to export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:
+
Index: /main/tags/2.25/gsdl/src/mgpp/acconfig.h
===================================================================
--- /main/tags/2.25/gsdl/src/mgpp/acconfig.h	(revision 21064)
+++ /main/tags/2.25/gsdl/src/mgpp/acconfig.h	(revision 21064)
@@ -0,0 +1,41 @@
+/* Special definitions for mg, processed by autoheader.
+   Created by [TS:Aug/95] 
+   by grepping for AC_DEFINE on configure.in and using the appropriate defs 
+   of acconfig.h used by GNU tar.
+*/
+
+/* Define to the name of the distribution.  */
+#undef PACKAGE
+
+/* Define to the version of the distribution.  */
+#undef VERSION
+
+/* Define if `union wait' is the type of the first arg to wait functions.  */
+#undef HAVE_UNION_WAIT
+
+/* Define to 1 if you have the valloc function.  */
+#undef HAVE_VALLOC
+
+/* Define to 1 if ANSI function prototypes are usable.  */
+#undef PROTOTYPES
+ 
+/* Define to 1 for better use of the debugging malloc library.  See
+   site ftp.antaire.com in antaire/src, file dmalloc/dmalloc.tar.gz.  */
+#undef WITH_DMALLOC
+ 
+/* Define to 1 if GNU regex should be used instead of GNU rx.  */
+#undef WITH_REGEX
+
+/* Define to 1 if GNU readline should be used. */
+#undef WITH_GNU_READLINE
+
+/* Some braindead header files do not have the requ'd function declarations */
+#undef HAVE_FGETC_DECL
+#undef HAVE_FREAD_DECL
+
+/* See if have this field in the prstatus_t structure */
+/* It stores the size of the process heap */
+#undef HAVE_PR_BRKSIZE
+
+/* Define to 1 to override the automatic selection of "long long" */
+#undef DISABLE_LONG_LONG
Index: /main/tags/2.25/gsdl/src/mgpp/aclocal.m4
===================================================================
--- /main/tags/2.25/gsdl/src/mgpp/aclocal.m4	(revision 21064)
+++ /main/tags/2.25/gsdl/src/mgpp/aclocal.m4	(revision 21064)
@@ -0,0 +1,225 @@
+# Local additions to Autoconf macros.
+# Copyright (C) 1992, 1994, 1995 Free Software Foundation, Inc.
+# François Pinard <pinard@iro.umontreal.ca>, 1992.
+
+# [TS:Aug/95] - chopped out the NLS stuff which I don't support
+
+## ------------------------------- ##
+## Check for function prototypes.  ##
+## ------------------------------- ##
+
+AC_DEFUN(fp_C_PROTOTYPES,
+[AC_REQUIRE([fp_PROG_CC_STDC])
+AC_MSG_CHECKING([for function prototypes])
+if test "$ac_cv_prog_cc_stdc" != no; then
+  AC_MSG_RESULT(yes)
+  AC_DEFINE(PROTOTYPES)
+  U= ANSI2KNR=
+else
+  AC_MSG_RESULT(no)
+  U=_ ANSI2KNR=ansi2knr
+fi
+AC_SUBST(U)dnl
+AC_SUBST(ANSI2KNR)dnl
+])
+
+## ----------------------------------------- ##
+## ANSIfy the C compiler whenever possible.  ##
+## ----------------------------------------- ##
+
+# @defmac AC_PROG_CC_STDC
+# @maindex PROG_CC_STDC
+# @ovindex CC
+# If the C compiler in not in ANSI C mode by default, try to add an option
+# to output variable @code{CC} to make it so.  This macro tries various
+# options that select ANSI C on some system or another.  It considers the
+# compiler to be in ANSI C mode if it defines @code{__STDC__} to 1 and
+# handles function prototypes correctly.
+#
+# If you use this macro, you should check after calling it whether the C
+# compiler has been set to accept ANSI C; if not, the shell variable
+# @code{ac_cv_prog_cc_stdc} is set to @samp{no}.  If you wrote your source
+# code in ANSI C, you can make an un-ANSIfied copy of it by using the
+# program @code{ansi2knr}, which comes with Ghostscript.
+# @end defmac
+
+AC_DEFUN(fp_PROG_CC_STDC,
+[AC_MSG_CHECKING(for ${CC-cc} option to accept ANSI C)
+AC_CACHE_VAL(ac_cv_prog_cc_stdc,
+[ac_cv_prog_cc_stdc=no
+ac_save_CFLAGS="$CFLAGS"
+# Don't try gcc -ansi; that turns off useful extensions and
+# breaks some systems' header files.
+# AIX			-qlanglvl=ansi
+# Ultrix and OSF/1	-std1
+# HP-UX			-Aa -D_HPUX_SOURCE
+# SVR4			-Xc
+for ac_arg in "" -qlanglvl=ansi -std1 "-Aa -D_HPUX_SOURCE" -Xc
+do
+  CFLAGS="$ac_save_CFLAGS $ac_arg"
+  AC_TRY_COMPILE(
+[#if !defined(__STDC__) || __STDC__ != 1
+choke me
+#endif	
+], [int test (int i, double x);
+struct s1 {int (*f) (int a);};
+struct s2 {int (*f) (double a);};],
+[ac_cv_prog_cc_stdc="$ac_arg"; break])
+done
+CFLAGS="$ac_save_CFLAGS"
+])
+AC_MSG_RESULT($ac_cv_prog_cc_stdc)
+case "x$ac_cv_prog_cc_stdc" in
+  x|xno) ;;
+  *) CC="$CC $ac_cv_prog_cc_stdc" ;;
+esac
+])
+
+## --------------------------------------------------------- ##
+## Use AC_PROG_INSTALL, supplementing it with INSTALL_SCRIPT ##
+## substitution.					     ##
+## --------------------------------------------------------- ##
+
+AC_DEFUN(fp_PROG_INSTALL,
+[AC_PROG_INSTALL
+test -z "$INSTALL_SCRIPT" && INSTALL_SCRIPT='${INSTALL} -m 755'
+AC_SUBST(INSTALL_SCRIPT)dnl
+])
+
+## ----------------------------------- ##
+## Check if --with-dmalloc was given.  ##
+## ----------------------------------- ##
+
+# I just checked, and GNU rx seems to work fine with a slightly
+# modified GNU m4.  So, I put out the test below in my aclocal.m4,
+# and will try to use it in my things.  The idea is to distribute
+# rx.[hc] and regex.[hc] together, for a while.  The WITH_REGEX symbol
+# (which should also be documented in acconfig.h) is used to decide
+# which of regex.h or rx.h should be included in the application.
+#
+# If `./configure --with-regex' is given, the package will use
+# the older regex.  Else, a check is made to see if rx is already
+# installed, as with newer Linux'es.  If not found, the package will
+# use the rx from the distribution.  If found, the package will use
+# the system's rx which, on Linux at least, will result in a smaller
+# executable file.
+
+AC_DEFUN(fp_WITH_DMALLOC,
+[AC_MSG_CHECKING(if malloc debugging is wanted)
+AC_ARG_WITH(dmalloc,
+[  --with-dmalloc          use dmalloc, as in
+                          ftp://ftp.letters.com/src/dmalloc/dmalloc.tar.gz],
+[if test "$withval" = yes; then
+  AC_MSG_RESULT(yes)
+  AC_DEFINE(WITH_DMALLOC)
+  LIBS="$LIBS -ldmalloc"
+  LDFLAGS="$LDFLAGS -g"
+else
+  AC_MSG_RESULT(no)
+fi], [AC_MSG_RESULT(no)])
+])
+
+## --------------------------------- ##
+## Check if --with-regex was given.  ##
+## --------------------------------- ##
+
+AC_DEFUN(fp_WITH_REGEX,
+[AC_MSG_CHECKING(which of rx or regex is wanted)
+AC_ARG_WITH(regex,
+[  --with-regex            use older regex in lieu of GNU rx for matching],
+[if test "$withval" = yes; then
+  ac_with_regex=1
+  AC_MSG_RESULT(regex)
+  AC_DEFINE(WITH_REGEX)
+  LIBOBJS="$LIBOBJS regex.o"
+fi])
+if test -z "$ac_with_regex"; then
+  AC_MSG_RESULT(rx)
+  AC_CHECK_FUNC(re_rx_search, , 
+   [AC_CHECK_SIZEOF(unsigned char *, unsigned char *)  
+    if test "$ac_cv_sizeof_unsigned_char_p" = 8
+    then
+      AC_MSG_WARN(I'm forcing you to use regex because I can't 
+        find a local rx library and the one included with this 
+        distribution doesn't work on 64-bit machines like yours)
+      [LIBOBJS="$LIBOBJS regex.o"]
+    else
+      [LIBOBJS="$LIBOBJS rx.o"]
+    fi]
+  )
+fi
+AC_SUBST(LIBOBJS)dnl
+])
+
+
+## --------------------------------------- ##
+## Check if --with-gnu-readline was given. ##
+## --------------------------------------- ##
+
+AC_DEFUN(fp_WITH_GNU_READLINE,
+[AC_MSG_CHECKING(whether GNU readline requested)
+  AC_ARG_WITH(gnu_readline,
+    [  --with-gnu-readline     compile with GNU readline support],
+    [if test "$withval" = yes; then
+      AC_MSG_RESULT(yes)
+      ac_with_gnu_readline=1
+    else
+      AC_MSG_RESULT(no)
+    fi],
+    AC_MSG_RESULT(no))
+
+  if test -n "$ac_with_gnu_readline"; then
+    AC_CHECK_HEADER(readline/readline.h, ac_mg_readline_header_found=1,
+	AC_MSG_WARN(Can't find GNU readline headers; configuring without \
+GNU readline support))
+    if test -n "$ac_mg_readline_header_found"; then
+      # first check whether we can find the readline library itself
+      AC_CHECK_LIB(readline, main, 
+        [ac_mg_readline_lib_found=1
+         AC_DEFINE(WITH_GNU_READLINE)
+         LIBS="$LIBS -lreadline"],
+        AC_MSG_WARN(Can't find GNU readline library; configuring without \
+GNU readline support))
+      if test -n "$ac_mg_readline_lib_found"; then
+        # on some systems, readline needs curses.  It is difficult to 
+        #  determine whether this is necessary on the current system,
+        #  since other undefined symbols can be turned up by an
+        #  AC_CHECK_LIB(readline, readline) test that are actually defined
+	#  by mg itself (e.g. xmalloc, xrealloc).  So, if we find libcurses,
+	#  we just bung it on and hope for the best.
+	AC_CHECK_LIB(curses, main,
+	  LIBS="$LIBS -lcurses")
+      fi
+    fi
+  fi
+])	
+
+
+
+#AC_DEFUN(fp_WITH_GNU_READLINE,
+#[AC_MSG_CHECKING(whether GNU readline requested)
+#  AC_ARG_WITH(gnu-readline,
+#    [  --with-gnu-readline   compile with GNU readline support],
+#    [if test "$withval" = yes; then
+#      AC_MSG_RESULT(yes)
+#      ac_with_gnu_readline=1
+#    else
+#      AC_MSG_RESULT(no)
+#    fi],
+#    AC_MSG_RESULT(no))
+#  if test -n "$ac_with_gnu_readline"; then
+#    AC_CHECK_LIB(readline, main, 
+#      AC_CHECK_HEADER(readline/readline.h,
+#	[AC_DEFINE(WITH_GNU_READLINE)
+## curses required on some systems (DEC OSF/1), but not on others (GNU/Linux,
+##  Solaris 2.6).  Forcing its inclusion is unsophisticated; if it causes 
+##  any actual problems on any UNIX platforms, let the maintainer know.
+#	LIBS="$LIBS -lreadline -lcurses"],
+#        AC_MSG_WARN(Can't find GNU readline headers: configuring \
+#without GNU readline support)
+#      ),
+#      AC_MSG_WARN(Can't find GNU readline library: configuring \
+#without GNU readline support)
+#    )
+#  fi 
+#])
Index: /main/tags/2.25/gsdl/src/mgpp/config.guess
===================================================================
--- /main/tags/2.25/gsdl/src/mgpp/config.guess	(revision 21064)
+++ /main/tags/2.25/gsdl/src/mgpp/config.guess	(revision 21064)
@@ -0,0 +1,470 @@
+#!/bin/sh
+# Attempt to guess a canonical system name.
+#   Copyright (C) 1992, 1993, 1994 Free Software Foundation, Inc.
+#
+# This file 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.
+#
+# As a special exception to the GNU General Public License, if you
+# distribute this file as part of a program that contains a
+# configuration script generated by Autoconf, you may include it under
+# the same distribution terms that you use for the rest of that program.
+
+# Written by Per Bothner <bothner@cygnus.com>.
+# The master version of this file is at the FSF in /home/gd/gnu/lib.
+#
+# This script attempts to guess a canonical system name similar to
+# config.sub.  If it succeeds, it prints the system name on stdout, and
+# exits with 0.  Otherwise, it exits with 1.
+#
+# The plan is that this can be called by configure scripts if you
+# don't specify an explicit system type (host/target name).
+#
+# Only a few systems have been added to this list; please add others
+# (but try to keep the structure clean).
+#
+
+# This is needed to find uname on a Pyramid OSx when run in the BSD universe.
+# (ghazi@noc.rutgers.edu 8/24/94.)
+if (test -f /.attbin/uname) >/dev/null 2>&1 ; then
+	PATH=$PATH:/.attbin ; export PATH
+fi
+
+UNAME_MACHINE=`(uname -m) 2>/dev/null` || UNAME_MACHINE=unknown
+UNAME_RELEASE=`(uname -r) 2>/dev/null` || UNAME_RELEASE=unknown
+UNAME_SYSTEM=`(uname -s) 2>/dev/null` || UNAME_SYSTEM=unknown
+UNAME_VERSION=`(uname -v) 2>/dev/null` || UNAME_VERSION=unknown
+
+trap 'rm -f dummy.c dummy.o dummy; exit 1' 1 2 15
+
+# Note: order is significant - the case branches are not exclusive.
+
+case "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" in
+    alpha:OSF1:V*:*)
+	# After 1.2, OSF1 uses "V1.3" for uname -r.
+	echo alpha-dec-osf`echo ${UNAME_RELEASE} | sed -e 's/^V//'`
+	exit 0 ;;
+    alpha:OSF1:*:*)
+	# 1.2 uses "1.2" for uname -r.
+	echo alpha-dec-osf${UNAME_RELEASE}
+        exit 0 ;;
+    arm:RISC*:1.[012]*:*|arm:riscix:1.[012]*:*)
+	echo arm-acorn-riscix${UNAME_RELEASE}
+	exit 0;;
+    Pyramid*:OSx*:*:*)
+	if test "`(/bin/universe) 2>/dev/null`" = att ; then
+		echo pyramid-pyramid-sysv3
+	else
+		echo pyramid-pyramid-bsd
+	fi
+	exit 0 ;;
+    sun4*:SunOS:5.*:*)
+	echo sparc-sun-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'`
+	exit 0 ;;
+    sun4*:SunOS:6*:*)
+	# According to config.sub, this is the proper way to canonicalize
+	# SunOS6.  Hard to guess exactly what SunOS6 will be like, but
+	# it's likely to be more like Solaris than SunOS4.
+	echo sparc-sun-solaris3`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'`
+	exit 0 ;;
+    sun4*:SunOS:*:*)
+	# Japanese Language versions have a version number like `4.1.3-JL'.
+	echo sparc-sun-sunos`echo ${UNAME_RELEASE}|sed -e 's/-/_/'`
+	exit 0 ;;
+    sun3*:SunOS:*:*)
+	echo m68k-sun-sunos${UNAME_RELEASE}
+	exit 0 ;;
+    RISC*:ULTRIX:*:*)
+	echo mips-dec-ultrix${UNAME_RELEASE}
+	exit 0 ;;
+    VAX*:ULTRIX*:*:*)
+	echo vax-dec-ultrix${UNAME_RELEASE}
+	exit 0 ;;
+    mips:*:5*:RISCos)
+	echo mips-mips-riscos${UNAME_RELEASE}
+	exit 0 ;;
+    m88k:CX/UX:7*:*)
+	echo m88k-harris-cxux7
+	exit 0 ;;
+    m88k:*:4*:R4*)
+	echo m88k-motorola-sysv4
+	exit 0 ;;
+    m88k:*:3*:R3*)
+	echo m88k-motorola-sysv3
+	exit 0 ;;
+    AViiON:dgux:*:*)
+	if [ ${TARGET_BINARY_INTERFACE}x = m88kdguxelfx \
+	     -o ${TARGET_BINARY_INTERFACE}x = x ] ; then
+		echo m88k-dg-dgux${UNAME_RELEASE}
+	else
+		echo m88k-dg-dguxbcs${UNAME_RELEASE}
+	fi
+ 	exit 0 ;;
+    M88*:DolphinOS:*:*)	# DolphinOS (SVR3)
+	echo m88k-dolphin-sysv3
+	exit 0 ;;
+    M88*:*:R3*:*)
+	# Delta 88k system running SVR3
+	echo m88k-motorola-sysv3
+	exit 0 ;;
+    XD88*:*:*:*) # Tektronix XD88 system running UTekV (SVR3)
+	echo m88k-tektronix-sysv3
+	exit 0 ;;
+    Tek43[0-9][0-9]:UTek:*:*) # Tektronix 4300 system running UTek (BSD)
+	echo m68k-tektronix-bsd
+	exit 0 ;;
+    *:IRIX:*:*)
+	echo mips-sgi-irix${UNAME_RELEASE}
+	exit 0 ;;
+    i[34]86:AIX:*:*)
+	echo i386-ibm-aix
+	exit 0 ;;
+    *:AIX:2:3)
+	if grep bos325 /usr/include/stdio.h >/dev/null 2>&1; then
+		sed 's/^		//' << EOF >dummy.c
+		#include <sys/systemcfg.h>
+
+		main()
+			{
+			if (!__power_pc())
+				exit(1);
+			puts("powerpc-ibm-aix3.2.5");
+			exit(0);
+			}
+EOF
+		${CC-cc} dummy.c -o dummy && ./dummy && rm dummy.c dummy && exit 0
+		rm -f dummy.c dummy
+		echo rs6000-ibm-aix3.2.5
+	elif grep bos324 /usr/include/stdio.h >/dev/null 2>&1; then
+		echo rs6000-ibm-aix3.2.4
+	else
+		echo rs6000-ibm-aix3.2
+	fi
+	exit 0 ;;
+    *:AIX:*:4)
+	if /usr/sbin/lsattr -EHl proc0 | grep POWER >/dev/null 2>&1; then
+		IBM_ARCH=rs6000
+	else
+		IBM_ARCH=powerpc
+	fi
+	if grep bos410 /usr/include/stdio.h >/dev/null 2>&1; then
+		IBM_REV=4.1
+	elif grep bos411 /usr/include/stdio.h >/dev/null 2>&1; then
+		IBM_REV=4.1.1
+	else
+		IBM_REV=4.${UNAME_RELEASE}
+	fi
+	echo ${IBM_ARCH}-ibm-aix${IBM_REV}
+	exit 0 ;;
+    *:AIX:*:*)
+	echo rs6000-ibm-aix
+	exit 0 ;;
+    *:BOSX:*:*)
+	echo rs6000-bull-bosx
+	exit 0 ;;
+    DPX/2?00:B.O.S.:*:*)
+	echo m68k-bull-sysv3
+	exit 0 ;;
+    9000/[34]??:4.3bsd:1.*:*)
+	echo m68k-hp-bsd
+	exit 0 ;;
+    hp300:4.4BSD:*:* | 9000/[34]??:4.3bsd:2.*:*)
+	echo m68k-hp-bsd4.4
+	exit 0 ;;
+    9000/[3478]??:HP-UX:*:*)
+	case "${UNAME_MACHINE}" in
+	    9000/31? )            HP_ARCH=m68000 ;;
+	    9000/[34]?? )         HP_ARCH=m68k ;;
+	    9000/7?? | 9000/8?7 ) HP_ARCH=hppa1.1 ;;
+	    9000/8?? )            HP_ARCH=hppa1.0 ;;
+	esac
+	HPUX_REV=`echo ${UNAME_RELEASE}|sed -e 's/[^.]*.[0B]*//'`
+	echo ${HP_ARCH}-hp-hpux${HPUX_REV}
+	exit 0 ;;
+    3050*:HI-UX:*:*)
+	sed 's/^	//' << EOF >dummy.c
+	#include <unistd.h>
+	int
+	main ()
+	{
+	  long cpu = sysconf (_SC_CPU_VERSION);
+	  /* The order matters, because CPU_IS_HP_MC68K erroneously returns
+	     true for CPU_PA_RISC1_0.  CPU_IS_PA_RISC returns correct
+	     results, however.  */
+	  if (CPU_IS_PA_RISC (cpu))
+	    {
+	      switch (cpu)
+		{
+		  case CPU_PA_RISC1_0: puts ("hppa1.0-hitachi-hiuxwe2"); break;
+		  case CPU_PA_RISC1_1: puts ("hppa1.1-hitachi-hiuxwe2"); break;
+		  case CPU_PA_RISC2_0: puts ("hppa2.0-hitachi-hiuxwe2"); break;
+		  default: puts ("hppa-hitachi-hiuxwe2"); break;
+		}
+	    }
+	  else if (CPU_IS_HP_MC68K (cpu))
+	    puts ("m68k-hitachi-hiuxwe2");
+	  else puts ("unknown-hitachi-hiuxwe2");
+	  exit (0);
+	}
+EOF
+	${CC-cc} dummy.c -o dummy && ./dummy && rm dummy.c dummy && exit 0
+	rm -f dummy.c dummy
+	echo unknown-hitachi-hiuxwe2
+	exit 0 ;;
+    9000/7??:4.3bsd:*:* | 9000/8?7:4.3bsd:*:* )
+	echo hppa1.1-hp-bsd
+	exit 0 ;;
+    9000/8??:4.3bsd:*:*)
+	echo hppa1.0-hp-bsd
+	exit 0 ;;
+    hp7??:OSF1:*:* | hp8?7:OSF1:*:* )
+	echo hppa1.1-hp-osf
+	exit 0 ;;
+    hp8??:OSF1:*:*)
+	echo hppa1.0-hp-osf
+	exit 0 ;;
+    C1*:ConvexOS:*:* | convex:ConvexOS:C1*:*)
+	echo c1-convex-bsd
+        exit 0 ;;
+    C2*:ConvexOS:*:* | convex:ConvexOS:C2*:*)
+	if getsysinfo -f scalar_acc
+	then echo c32-convex-bsd
+	else echo c2-convex-bsd
+	fi
+        exit 0 ;;
+    C34*:ConvexOS:*:* | convex:ConvexOS:C34*:*)
+	echo c34-convex-bsd
+        exit 0 ;;
+    C38*:ConvexOS:*:* | convex:ConvexOS:C38*:*)
+	echo c38-convex-bsd
+        exit 0 ;;
+    C4*:ConvexOS:*:* | convex:ConvexOS:C4*:*)
+	echo c4-convex-bsd
+        exit 0 ;;
+    CRAY*X-MP:UNICOS:*:*)
+	echo xmp-cray-unicos
+        exit 0 ;;
+    CRAY*Y-MP:UNICOS:*:*)
+	echo ymp-cray-unicos
+        exit 0 ;;
+    CRAY-2:UNICOS:*:*)
+	echo cray2-cray-unicos
+        exit 0 ;;
+    hp3[0-9][05]:NetBSD:*:*)
+	echo m68k-hp-netbsd${UNAME_RELEASE}
+	exit 0 ;;
+    i[34]86:BSD/386:*:*)
+	echo ${UNAME_MACHINE}-unknown-bsdi${UNAME_RELEASE}
+	exit 0 ;;
+    *:FreeBSD:*:*)
+	echo ${UNAME_MACHINE}-unknown-freebsd`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'`
+	exit 0 ;;
+    *:NetBSD:*:*)
+	echo ${UNAME_MACHINE}-unknown-netbsd`echo ${UNAME_RELEASE}|sed -e 's/[-_].*/\./'`
+	exit 0 ;;
+    *:GNU:*:*)
+	echo `echo ${UNAME_MACHINE}|sed -e 's,/.*$,,'`-unknown-gnu`echo ${UNAME_RELEASE}|sed -e 's,/.*$,,'`
+	exit 0 ;;
+    *:Linux:*:*)
+	echo ${UNAME_MACHINE}-unknown-linux
+	exit 0 ;;
+# ptx 4.0 does uname -s correctly, with DYNIX/ptx in there.  earlier versions
+# are messed up and put the nodename in both sysname and nodename.
+    i[34]86:DYNIX/ptx:4*:*)
+	echo i386-sequent-sysv4
+	exit 0 ;;
+    i[34]86:*:4.*:* | i[34]86:SYSTEM_V:4.*:*)
+	if grep Novell /usr/include/link.h >/dev/null 2>/dev/null; then
+		echo ${UNAME_MACHINE}-univel-sysv${UNAME_RELEASE}
+	else
+		echo ${UNAME_MACHINE}-unknown-sysv${UNAME_RELEASE}
+	fi
+	exit 0 ;;
+    i[34]86:*:3.2:*)
+	if /bin/uname -X 2>/dev/null >/dev/null ; then
+		UNAME_REL=`(/bin/uname -X|egrep Release|sed -e 's/.*= //')`
+		(/bin/uname -X|egrep i80486 >/dev/null) && UNAME_MACHINE=i486
+		echo ${UNAME_MACHINE}-unknown-sco$UNAME_REL
+	elif test -f /usr/options/cb.name; then
+		UNAME_REL=`sed -n 's/.*Version //p' </usr/options/cb.name`
+		echo ${UNAME_MACHINE}-unknown-isc$UNAME_REL
+	else
+		echo ${UNAME_MACHINE}-unknown-sysv32
+	fi
+	exit 0 ;;
+    Intel:Mach:3*:*)
+	echo i386-unknown-mach3
+	exit 0 ;;
+    i860:*:4.*:*) # i860-SVR4
+	if grep Stardent /usr/include/sys/uadmin.h >/dev/null 2>&1 ; then
+	  echo i860-stardent-sysv${UNAME_RELEASE} # Stardent Vistra i860-SVR4
+	else # Add other i860-SVR4 vendors below as they are discovered.
+	  echo i860-unknown-sysv${UNAME_RELEASE}  # Unknown i860-SVR4
+	fi
+	exit 0 ;;
+    mini*:CTIX:SYS*5:*)
+	# "miniframe"
+	echo m68010-convergent-sysv
+	exit 0 ;;
+    M680[234]0:*:R3V[567]*:*)
+	test -r /sysV68 && echo 'm68k-motorola-sysv' && exit 0 ;;
+    3[34]??:*:4.0:3.0 | 3[34]??,*:*:4.0:3.0)
+        uname -p 2>/dev/null | grep 86 >/dev/null \
+          && echo i486-ncr-sysv4.3 && exit 0 ;;
+    3[34]??:*:4.0:* | 3[34]??,*:*:4.0:*)
+        uname -p 2>/dev/null | grep 86 >/dev/null \
+          && echo i486-ncr-sysv4 && exit 0 ;;
+    m680[234]0:LynxOS:2.2*:*)
+	echo m68k-lynx-lynxos${UNAME_RELEASE}
+	exit 0 ;;
+    mc68030:UNIX_System_V:4.*:*)
+	echo m68k-atari-sysv4
+	exit 0 ;;
+    i[34]86:LynxOS:2.2*:*)
+	echo i386-lynx-lynxos${UNAME_RELEASE}
+	exit 0 ;;
+    TSUNAMI:LynxOS:2.2*:*)
+	echo sparc-lynx-lynxos${UNAME_RELEASE}
+	exit 0 ;;
+    rs6000:LynxOS:2.2*:*)
+	echo rs6000-lynx-lynxos${UNAME_RELEASE}
+	exit 0 ;;
+    RM*:SINIX-*:*:*)
+	echo mips-sni-sysv4
+	exit 0 ;;
+    *:SINIX-*:*:*)
+	if uname -p 2>/dev/null >/dev/null ; then
+		UNAME_MACHINE=`(uname -p) 2>/dev/null`
+		echo ${UNAME_MACHINE}-sni-sysv4
+	else
+		echo ns32k-sni-sysv
+	fi
+	exit 0 ;;
+esac
+
+#echo '(No uname command or uname output not recognized.)' 1>&2
+#echo "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" 1>&2
+
+cat >dummy.c <<EOF
+main ()
+{
+#if defined (sony)
+#if defined (MIPSEB)
+  /* BFD wants "bsd" instead of "newsos".  Perhaps BFD should be changed,
+     I don't know....  */
+  printf ("mips-sony-bsd\n"); exit (0);
+#else
+  printf ("m68k-sony-newsos\n"); exit (0);
+#endif
+#endif
+
+#if defined (__arm) && defined (__acorn) && defined (__unix)
+  printf ("arm-acorn-riscix"); exit (0);
+#endif
+
+#if defined (hp300) && !defined (hpux)
+  printf ("m68k-hp-bsd\n"); exit (0);
+#endif
+
+#if defined (NeXT)
+#if !defined (__ARCHITECTURE__)
+#define __ARCHITECTURE__ "m68k"
+#endif
+  int version;
+  version=`(hostinfo | sed -n 's/.*NeXT Mach \([0-9]*\).*/\1/p') 2>/dev/null`;
+  printf ("%s-next-nextstep%s\n", __ARCHITECTURE__,  version==2 ? "2" : "3");
+  exit (0);
+#endif
+
+#if defined (MULTIMAX) || defined (n16)
+#if defined (UMAXV)
+  printf ("ns32k-encore-sysv\n"); exit (0);
+#else
+#if defined (CMU)
+  printf ("ns32k-encore-mach\n"); exit (0);
+#else
+  printf ("ns32k-encore-bsd\n"); exit (0);
+#endif
+#endif
+#endif
+
+#if defined (__386BSD__)
+  printf ("i386-unknown-bsd\n"); exit (0);
+#endif
+
+#if defined (sequent)
+#if defined (i386)
+  printf ("i386-sequent-dynix\n"); exit (0);
+#endif
+#if defined (ns32000)
+  printf ("ns32k-sequent-dynix\n"); exit (0);
+#endif
+#endif
+
+#if defined (_SEQUENT_)
+  printf ("i386-sequent-ptx\n"); exit (0);
+#endif
+
+#if defined (vax)
+#if !defined (ultrix)
+  printf ("vax-dec-bsd\n"); exit (0);
+#else
+  printf ("vax-dec-ultrix\n"); exit (0);
+#endif
+#endif
+
+#if defined (alliant) && defined (i860)
+  printf ("i860-alliant-bsd\n"); exit (0);
+#endif
+
+  exit (1);
+}
+EOF
+
+${CC-cc} dummy.c -o dummy 2>/dev/null && ./dummy && rm dummy.c dummy && exit 0
+rm -f dummy.c dummy
+
+# Apollos put the system type in the environment.
+
+test -d /usr/apollo && { echo ${ISP}-apollo-${SYSTYPE}; exit 0; }
+
+# Convex versions that predate uname can use getsysinfo(1)
+
+if [ -x /usr/convex/getsysinfo ]
+then
+    case `getsysinfo -f cpu_type` in
+    c1*)
+	echo c1-convex-bsd
+	exit 0 ;;
+    c2*)
+	if getsysinfo -f scalar_acc
+	then echo c32-convex-bsd
+	else echo c2-convex-bsd
+	fi
+	exit 0 ;;
+    c34*)
+	echo c34-convex-bsd
+	exit 0 ;;
+    c38*)
+	echo c38-convex-bsd
+	exit 0 ;;
+    c4*)
+	echo c4-convex-bsd
+	exit 0 ;;
+    esac
+fi
+
+#echo '(Unable to guess system type)' 1>&2
+
+exit 1
Index: /main/tags/2.25/gsdl/src/mgpp/config.h
===================================================================
--- /main/tags/2.25/gsdl/src/mgpp/config.h	(revision 21064)
+++ /main/tags/2.25/gsdl/src/mgpp/config.h	(revision 21064)
@@ -0,0 +1,184 @@
+/* config.h.  Generated automatically by configure.  */
+/* config.h.in.  Generated automatically from configure.in by autoheader.  */
+
+/* Define if on AIX 3.
+   System headers sometimes define this.
+   We just want to avoid a redefinition error message.  */
+#ifndef _ALL_SOURCE
+/* #undef _ALL_SOURCE */
+#endif
+
+/* Define if using alloca.c.  */
+/* #undef C_ALLOCA */
+
+/* Define to empty if the keyword does not work.  */
+/* #undef const */
+
+/* Define to one of _getb67, GETB67, getb67 for Cray-2 and Cray-YMP systems.
+   This function is required for alloca.c support on those systems.  */
+/* #undef CRAY_STACKSEG_END */
+
+/* Define if you have alloca, as a function or macro.  */
+#define HAVE_ALLOCA 1
+
+/* Define if you have <alloca.h> and it should be used (not on Ultrix).  */
+#define HAVE_ALLOCA_H 1
+
+/* Define if you don't have vprintf but do have _doprnt.  */
+/* #undef HAVE_DOPRNT */
+
+/* Define if you have the vprintf function.  */
+#define HAVE_VPRINTF 1
+
+/* Define if on MINIX.  */
+/* #undef _MINIX */
+
+/* Define to `long' if <sys/types.h> doesn't define.  */
+/* #undef off_t */
+
+/* Define if the system does not provide POSIX.1 features except
+   with this defined.  */
+/* #undef _POSIX_1_SOURCE */
+
+/* Define if you need to in order for stat and other things to work.  */
+/* #undef _POSIX_SOURCE */
+
+/* Define as the return type of signal handlers (int or void).  */
+#define RETSIGTYPE void
+
+/* Define to `unsigned' if <sys/types.h> doesn't define.  */
+/* #undef size_t */
+
+/* If using the C implementation of alloca, define if you know the
+   direction of stack growth for your system; otherwise it will be
+   automatically deduced at run-time.
+ STACK_DIRECTION > 0 => grows toward higher addresses
+ STACK_DIRECTION < 0 => grows toward lower addresses
+ STACK_DIRECTION = 0 => direction of growth unknown
+ */
+/* #undef STACK_DIRECTION */
+
+/* Define if you have the ANSI C header files.  */
+#define STDC_HEADERS 1
+
+/* Define if you can safely include both <sys/time.h> and <time.h>.  */
+#define TIME_WITH_SYS_TIME 1
+
+/* Define if your <sys/time.h> declares struct tm.  */
+/* #undef TM_IN_SYS_TIME */
+
+/* Define to the name of the distribution.  */
+#define PACKAGE "mgpp"
+
+/* Define to the version of the distribution.  */
+#define VERSION "1.3"
+
+/* Define to 1 if you have the valloc function.  */
+#define HAVE_VALLOC 1
+
+/* Define to 1 if ANSI function prototypes are usable.  */
+#define PROTOTYPES 1
+
+ 
+/* Define to 1 for better use of the debugging malloc library.  See
+   site ftp.antaire.com in antaire/src, file dmalloc/dmalloc.tar.gz.  */
+/* #undef WITH_DMALLOC */
+
+ 
+/* Define to 1 if GNU regex should be used instead of GNU rx.  */
+/* #undef WITH_REGEX */
+
+/* Define to 1 if GNU readline should be used. */
+/* #undef WITH_GNU_READLINE */
+
+/* Some braindead header files do not have the requ'd function declarations */
+#define HAVE_FGETC_DECL 1
+#define HAVE_FREAD_DECL 1
+
+/* See if have this field in the prstatus_t structure */
+/* It stores the size of the process heap */
+/* #undef HAVE_PR_BRKSIZE */
+
+/* Define to 1 to override the automatic selection of "long long" */
+/* #undef DISABLE_LONG_LONG */
+
+/* The number of bytes in a unsigned char *.  */
+#define SIZEOF_UNSIGNED_CHAR_P 4
+
+/* Define if you have the ftime function.  */
+#define HAVE_FTIME 1
+
+/* Define if you have the ftruncate function.  */
+#define HAVE_FTRUNCATE 1
+
+/* Define if you have the getpagesize function.  */
+#define HAVE_GETPAGESIZE 1
+
+/* Define if you have the getrusage function.  */
+#define HAVE_GETRUSAGE 1
+
+/* Define if you have the mallinfo function.  */
+#define HAVE_MALLINFO 1
+
+/* Define if you have the select function.  */
+#define HAVE_SELECT 1
+
+/* Define if you have the setbuffer function.  */
+#define HAVE_SETBUFFER 1
+
+/* Define if you have the strcasecmp function.  */
+#define HAVE_STRCASECMP 1
+
+/* Define if you have the strerror function.  */
+#define HAVE_STRERROR 1
+
+/* Define if you have the strftime function.  */
+#define HAVE_STRFTIME 1
+
+/* Define if you have the strstr function.  */
+#define HAVE_STRSTR 1
+
+/* Define if you have the strtol function.  */
+#define HAVE_STRTOL 1
+
+/* Define if you have the times function.  */
+#define HAVE_TIMES 1
+
+/* Define if you have the valloc function.  */
+#define HAVE_VALLOC 1
+
+/* Define if you have the <dirent.h> header file.  */
+#define HAVE_DIRENT_H 1
+
+/* Define if you have the <fcntl.h> header file.  */
+#define HAVE_FCNTL_H 1
+
+/* Define if you have the <limits.h> header file.  */
+#define HAVE_LIMITS_H 1
+
+/* Define if you have the <memory.h> header file.  */
+#define HAVE_MEMORY_H 1
+
+/* Define if you have the <ndir.h> header file.  */
+/* #undef HAVE_NDIR_H */
+
+/* Define if you have the <string.h> header file.  */
+#define HAVE_STRING_H 1
+
+/* Define if you have the <sys/dir.h> header file.  */
+/* #undef HAVE_SYS_DIR_H */
+
+/* Define if you have the <sys/ndir.h> header file.  */
+/* #undef HAVE_SYS_NDIR_H */
+
+/* Define if you have the <sys/procfs.h> header file.  */
+#define HAVE_SYS_PROCFS_H 1
+
+/* Define if you have the <sys/time.h> header file.  */
+#define HAVE_SYS_TIME_H 1
+
+/* Define if you have the <unistd.h> header file.  */
+#define HAVE_UNISTD_H 1
+
+/* Define if you have the m library (-lm).  */
+#define HAVE_LIBM 1
Index: /main/tags/2.25/gsdl/src/mgpp/config.h.in
===================================================================
--- /main/tags/2.25/gsdl/src/mgpp/config.h.in	(revision 21064)
+++ /main/tags/2.25/gsdl/src/mgpp/config.h.in	(revision 21064)
@@ -0,0 +1,183 @@
+/* config.h.in.  Generated automatically from configure.in by autoheader.  */
+
+/* Define if on AIX 3.
+   System headers sometimes define this.
+   We just want to avoid a redefinition error message.  */
+#ifndef _ALL_SOURCE
+#undef _ALL_SOURCE
+#endif
+
+/* Define if using alloca.c.  */
+#undef C_ALLOCA
+
+/* Define to empty if the keyword does not work.  */
+#undef const
+
+/* Define to one of _getb67, GETB67, getb67 for Cray-2 and Cray-YMP systems.
+   This function is required for alloca.c support on those systems.  */
+#undef CRAY_STACKSEG_END
+
+/* Define if you have alloca, as a function or macro.  */
+#undef HAVE_ALLOCA
+
+/* Define if you have <alloca.h> and it should be used (not on Ultrix).  */
+#undef HAVE_ALLOCA_H
+
+/* Define if you don't have vprintf but do have _doprnt.  */
+#undef HAVE_DOPRNT
+
+/* Define if you have the vprintf function.  */
+#undef HAVE_VPRINTF
+
+/* Define if on MINIX.  */
+#undef _MINIX
+
+/* Define to `long' if <sys/types.h> doesn't define.  */
+#undef off_t
+
+/* Define if the system does not provide POSIX.1 features except
+   with this defined.  */
+#undef _POSIX_1_SOURCE
+
+/* Define if you need to in order for stat and other things to work.  */
+#undef _POSIX_SOURCE
+
+/* Define as the return type of signal handlers (int or void).  */
+#undef RETSIGTYPE
+
+/* Define to `unsigned' if <sys/types.h> doesn't define.  */
+#undef size_t
+
+/* If using the C implementation of alloca, define if you know the
+   direction of stack growth for your system; otherwise it will be
+   automatically deduced at run-time.
+ STACK_DIRECTION > 0 => grows toward higher addresses
+ STACK_DIRECTION < 0 => grows toward lower addresses
+ STACK_DIRECTION = 0 => direction of growth unknown
+ */
+#undef STACK_DIRECTION
+
+/* Define if you have the ANSI C header files.  */
+#undef STDC_HEADERS
+
+/* Define if you can safely include both <sys/time.h> and <time.h>.  */
+#undef TIME_WITH_SYS_TIME
+
+/* Define if your <sys/time.h> declares struct tm.  */
+#undef TM_IN_SYS_TIME
+
+/* Define to the name of the distribution.  */
+#undef PACKAGE
+
+/* Define to the version of the distribution.  */
+#undef VERSION
+
+/* Define to 1 if you have the valloc function.  */
+#undef HAVE_VALLOC
+
+/* Define to 1 if ANSI function prototypes are usable.  */
+#undef PROTOTYPES
+
+ 
+/* Define to 1 for better use of the debugging malloc library.  See
+   site ftp.antaire.com in antaire/src, file dmalloc/dmalloc.tar.gz.  */
+#undef WITH_DMALLOC
+
+ 
+/* Define to 1 if GNU regex should be used instead of GNU rx.  */
+#undef WITH_REGEX
+
+/* Define to 1 if GNU readline should be used. */
+#undef WITH_GNU_READLINE
+
+/* Some braindead header files do not have the requ'd function declarations */
+#undef HAVE_FGETC_DECL
+#undef HAVE_FREAD_DECL
+
+/* See if have this field in the prstatus_t structure */
+/* It stores the size of the process heap */
+#undef HAVE_PR_BRKSIZE
+
+/* Define to 1 to override the automatic selection of "long long" */
+#undef DISABLE_LONG_LONG
+
+/* The number of bytes in a unsigned char *.  */
+#undef SIZEOF_UNSIGNED_CHAR_P
+
+/* Define if you have the ftime function.  */
+#undef HAVE_FTIME
+
+/* Define if you have the ftruncate function.  */
+#undef HAVE_FTRUNCATE
+
+/* Define if you have the getpagesize function.  */
+#undef HAVE_GETPAGESIZE
+
+/* Define if you have the getrusage function.  */
+#undef HAVE_GETRUSAGE
+
+/* Define if you have the mallinfo function.  */
+#undef HAVE_MALLINFO
+
+/* Define if you have the select function.  */
+#undef HAVE_SELECT
+
+/* Define if you have the setbuffer function.  */
+#undef HAVE_SETBUFFER
+
+/* Define if you have the strcasecmp function.  */
+#undef HAVE_STRCASECMP
+
+/* Define if you have the strerror function.  */
+#undef HAVE_STRERROR
+
+/* Define if you have the strftime function.  */
+#undef HAVE_STRFTIME
+
+/* Define if you have the strstr function.  */
+#undef HAVE_STRSTR
+
+/* Define if you have the strtol function.  */
+#undef HAVE_STRTOL
+
+/* Define if you have the times function.  */
+#undef HAVE_TIMES
+
+/* Define if you have the valloc function.  */
+#undef HAVE_VALLOC
+
+/* Define if you have the <dirent.h> header file.  */
+#undef HAVE_DIRENT_H
+
+/* Define if you have the <fcntl.h> header file.  */
+#undef HAVE_FCNTL_H
+
+/* Define if you have the <limits.h> header file.  */
+#undef HAVE_LIMITS_H
+
+/* Define if you have the <memory.h> header file.  */
+#undef HAVE_MEMORY_H
+
+/* Define if you have the <ndir.h> header file.  */
+#undef HAVE_NDIR_H
+
+/* Define if you have the <string.h> header file.  */
+#undef HAVE_STRING_H
+
+/* Define if you have the <sys/dir.h> header file.  */
+#undef HAVE_SYS_DIR_H
+
+/* Define if you have the <sys/ndir.h> header file.  */
+#undef HAVE_SYS_NDIR_H
+
+/* Define if you have the <sys/procfs.h> header file.  */
+#undef HAVE_SYS_PROCFS_H
+
+/* Define if you have the <sys/time.h> header file.  */
+#undef HAVE_SYS_TIME_H
+
+/* Define if you have the <unistd.h> header file.  */
+#undef HAVE_UNISTD_H
+
+/* Define if you have the m library (-lm).  */
+#undef HAVE_LIBM
Index: /main/tags/2.25/gsdl/src/mgpp/config.sub
===================================================================
--- /main/tags/2.25/gsdl/src/mgpp/config.sub	(revision 21064)
+++ /main/tags/2.25/gsdl/src/mgpp/config.sub	(revision 21064)
@@ -0,0 +1,793 @@
+#!/bin/sh
+# Configuration validation subroutine script, version 1.1.
+#   Copyright (C) 1991, 1992, 1993, 1994 Free Software Foundation, Inc.
+# This file is (in principle) common to ALL GNU software.
+# The presence of a machine in this file suggests that SOME GNU software
+# can handle that machine.  It does not imply ALL GNU software can. 
+#
+# This file 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.
+
+# As a special exception to the GNU General Public License, if you
+# distribute this file as part of a program that contains a
+# configuration script generated by Autoconf, you may include it under
+# the same distribution terms that you use for the rest of that program.
+
+# Configuration subroutine to validate and canonicalize a configuration type.
+# Supply the specified configuration type as an argument.
+# If it is invalid, we print an error message on stderr and exit with code 1.
+# Otherwise, we print the canonical config type on stdout and succeed.
+
+# This file is supposed to be the same for all GNU packages
+# and recognize all the CPU types, system types and aliases
+# that are meaningful with *any* GNU software.
+# Each package is responsible for reporting which valid configurations
+# it does not support.  The user should be able to distinguish
+# a failure to support a valid configuration from a meaningless
+# configuration.
+
+# The goal of this file is to map all the various variations of a given
+# machine specification into a single specification in the form:
+#	CPU_TYPE-MANUFACTURER-OPERATING_SYSTEM
+# It is wrong to echo any other type of specification.
+
+# First pass through any local machine types.
+case $1 in
+	*local*)
+		echo $1
+		exit 0
+		;;
+	*)
+	;;
+esac
+
+# Separate what the user gave into CPU-COMPANY and OS (if any).
+basic_machine=`echo $1 | sed 's/-[^-]*$//'`
+if [ $basic_machine != $1 ]
+then os=`echo $1 | sed 's/.*-/-/'`
+else os=; fi
+
+### Let's recognize common machines as not being operating systems so
+### that things like config.sub decstation-3100 work.  We also
+### recognize some manufacturers as not being operating systems, so we
+### can provide default operating systems below.
+case $os in
+	-sun*os*)
+		# Prevent following clause from handling this invalid input.
+		;;
+	-dec* | -mips* | -sequent* | -encore* | -pc532* | -sgi* | -sony* | \
+	-att* | -7300* | -3300* | -delta* | -motorola* | -sun[234]* | \
+	-unicom* | -ibm* | -next | -hp | -isi* | -apollo | -altos* | \
+	-convergent* | -ncr* | -news | -32* | -3600* | -3100* | -hitachi* |\
+	-c[123]* | -convex* | -sun | -crds | -omron* | -dg | -ultra | -tti* | \
+	-harris | -dolphin | -highlevel | -gould | -cbm | -ns | -masscomp )
+		os=
+		basic_machine=$1
+		;;
+	-hiux*)
+		os=-hiuxwe2
+		;;
+	-sco4)
+		os=-sco3.2v4
+		basic_machine=`echo $1 | sed -e 's/86-.*/86-unknown/'`
+		;;
+	-sco3.2.[4-9]*)
+		os=`echo $os | sed -e 's/sco3.2./sco3.2v/'`
+		basic_machine=`echo $1 | sed -e 's/86-.*/86-unknown/'`
+		;;
+	-sco3.2v[4-9]*)
+		# Don't forget version if it is 3.2v4 or newer.
+		basic_machine=`echo $1 | sed -e 's/86-.*/86-unknown/'`
+		;;
+	-sco*)
+		os=-sco3.2v2
+		basic_machine=`echo $1 | sed -e 's/86-.*/86-unknown/'`
+		;;
+	-isc)
+		os=-isc2.2
+		basic_machine=`echo $1 | sed -e 's/86-.*/86-unknown/'`
+		;;
+	-clix*)
+		basic_machine=clipper-intergraph
+		;;
+	-isc*)
+		basic_machine=`echo $1 | sed -e 's/86-.*/86-unknown/'`
+		;;
+	-lynx)
+		os=-lynxos
+		;;
+	-ptx*)
+		basic_machine=`echo $1 | sed -e 's/86-.*/86-sequent/'`
+		;;
+	-windowsnt*)
+		os=`echo $os | sed -e 's/windowsnt/winnt/'`
+		;;
+esac
+
+# Decode aliases for certain CPU-COMPANY combinations.
+case $basic_machine in
+	# Recognize the basic CPU types without company name.
+	# Some are omitted here because they have special meanings below.
+	tahoe | i[345]86 | i860 | m68k | m68000 | m88k | ns32k | arm | pyramid \
+		| tron | a29k | 580 | i960 | h8300 | hppa1.0 | hppa1.1 \
+		| alpha | we32k | ns16k | clipper | sparclite | i370 | sh \
+		| powerpc | sparc64 | 1750a | dsp16xx | mips64 | mipsel \
+		| pdp11 | mips64el | mips64orion | mips64orionel )
+		basic_machine=$basic_machine-unknown
+		;;
+	# Object if more than one company name word.
+	*-*-*)
+		echo Invalid configuration \`$1\': machine \`$basic_machine\' not recognized 1>&2
+		exit 1
+		;;
+	# Recognize the basic CPU types with company name.
+	vax-* | tahoe-* | i[345]86-* | i860-* | m68k-* | m68000-* | m88k-* \
+	      | sparc-* | ns32k-* | fx80-* | arm-* | c[123]* \
+	      | mips-* | pyramid-* | tron-* | a29k-* | romp-* | rs6000-* \
+	      | none-* | 580-* | cray2-* | h8300-* | i960-* | xmp-* | ymp-* \
+	      | hppa1.0-* | hppa1.1-* | alpha-* | we32k-* | cydra-* | ns16k-* \
+	      | pn-* | np1-* | xps100-* | clipper-* | orion-* | sparclite-* \
+	      | pdp11-* | sh-* | powerpc-* | sparc64-* | mips64-* | mipsel-* \
+	      | mips64el-* | mips64orion-* | mips64orionel-* )
+		;;
+	# Recognize the various machine names and aliases which stand
+	# for a CPU type and a company and sometimes even an OS.
+	3b1 | 7300 | 7300-att | att-7300 | pc7300 | safari | unixpc)
+		basic_machine=m68000-att
+		;;
+	3b*)
+		basic_machine=we32k-att
+		;;
+	alliant | fx80)
+		basic_machine=fx80-alliant
+		;;
+	altos | altos3068)
+		basic_machine=m68k-altos
+		;;
+	am29k)
+		basic_machine=a29k-none
+		os=-bsd
+		;;
+	amdahl)
+		basic_machine=580-amdahl
+		os=-sysv
+		;;
+	amiga | amiga-*)
+		basic_machine=m68k-cbm
+		;;
+	amigados)
+		basic_machine=m68k-cbm
+		os=-amigados
+		;;
+	amigaunix | amix)
+		basic_machine=m68k-cbm
+		os=-sysv4
+		;;
+	apollo68)
+		basic_machine=m68k-apollo
+		os=-sysv
+		;;
+	balance)
+		basic_machine=ns32k-sequent
+		os=-dynix
+		;;
+	convex-c1)
+		basic_machine=c1-convex
+		os=-bsd
+		;;
+	convex-c2)
+		basic_machine=c2-convex
+		os=-bsd
+		;;
+	convex-c32)
+		basic_machine=c32-convex
+		os=-bsd
+		;;
+	convex-c34)
+		basic_machine=c34-convex
+		os=-bsd
+		;;
+	convex-c38)
+		basic_machine=c38-convex
+		os=-bsd
+		;;
+	cray | ymp)
+		basic_machine=ymp-cray
+		os=-unicos
+		;;
+	cray2)
+		basic_machine=cray2-cray
+		os=-unicos
+		;;
+	crds | unos)
+		basic_machine=m68k-crds
+		;;
+	da30 | da30-*)
+		basic_machine=m68k-da30
+		;;
+	decstation | decstation-3100 | pmax | pmax-* | pmin | dec3100 | decstatn)
+		basic_machine=mips-dec
+		;;
+	delta | 3300 | motorola-3300 | motorola-delta \
+	      | 3300-motorola | delta-motorola)
+		basic_machine=m68k-motorola
+		;;
+	delta88)
+		basic_machine=m88k-motorola
+		os=-sysv3
+		;;
+	dpx20 | dpx20-*)
+		basic_machine=rs6000-bull
+		os=-bosx
+		;;
+	dpx2* | dpx2*-bull)
+		basic_machine=m68k-bull
+		os=-sysv3
+		;;
+	ebmon29k)
+		basic_machine=a29k-amd
+		os=-ebmon
+		;;
+	elxsi)
+		basic_machine=elxsi-elxsi
+		os=-bsd
+		;;
+	encore | umax | mmax)
+		basic_machine=ns32k-encore
+		;;
+	fx2800)
+		basic_machine=i860-alliant
+		;;
+	genix)
+		basic_machine=ns32k-ns
+		;;
+	gmicro)
+		basic_machine=tron-gmicro
+		os=-sysv
+		;;
+	h3050r* | hiux*)
+		basic_machine=hppa1.1-hitachi
+		os=-hiuxwe2
+		;;
+	h8300hms)
+		basic_machine=h8300-hitachi
+		os=-hms
+		;;
+	harris)
+		basic_machine=m88k-harris
+		os=-sysv3
+		;;
+	hp300-*)
+		basic_machine=m68k-hp
+		;;
+	hp300bsd)
+		basic_machine=m68k-hp
+		os=-bsd
+		;;
+	hp300hpux)
+		basic_machine=m68k-hp
+		os=-hpux
+		;;
+	hp9k2[0-9][0-9] | hp9k31[0-9])
+		basic_machine=m68000-hp
+		;;
+	hp9k3[2-9][0-9])
+		basic_machine=m68k-hp
+		;;
+	hp9k7[0-9][0-9] | hp7[0-9][0-9] | hp9k8[0-9]7 | hp8[0-9]7)
+		basic_machine=hppa1.1-hp
+		;;
+	hp9k8[0-9][0-9] | hp8[0-9][0-9])
+		basic_machine=hppa1.0-hp
+		;;
+	i370-ibm* | ibm*)
+		basic_machine=i370-ibm
+		os=-mvs
+		;;
+# I'm not sure what "Sysv32" means.  Should this be sysv3.2?
+	i[345]86v32)
+		basic_machine=`echo $1 | sed -e 's/86.*/86-unknown/'`
+		os=-sysv32
+		;;
+	i[345]86v4*)
+		basic_machine=`echo $1 | sed -e 's/86.*/86-unknown/'`
+		os=-sysv4
+		;;
+	i[345]86v)
+		basic_machine=`echo $1 | sed -e 's/86.*/86-unknown/'`
+		os=-sysv
+		;;
+	i[345]86sol2)
+		basic_machine=`echo $1 | sed -e 's/86.*/86-unknown/'`
+		os=-solaris2
+		;;
+	iris | iris4d)
+		basic_machine=mips-sgi
+		case $os in
+		    -irix*)
+			;;
+		    *)
+			os=-irix4
+			;;
+		esac
+		;;
+	isi68 | isi)
+		basic_machine=m68k-isi
+		os=-sysv
+		;;
+	m88k-omron*)
+		basic_machine=m88k-omron
+		;;
+	magnum | m3230)
+		basic_machine=mips-mips
+		os=-sysv
+		;;
+	merlin)
+		basic_machine=ns32k-utek
+		os=-sysv
+		;;
+	miniframe)
+		basic_machine=m68000-convergent
+		;;
+	mips3*-*)
+		basic_machine=`echo $basic_machine | sed -e 's/mips3/mips64/'`
+		;;
+	mips3*)
+		basic_machine=`echo $basic_machine | sed -e 's/mips3/mips64/'`-unknown
+		;;
+	ncr3000)
+		basic_machine=i486-ncr
+		os=-sysv4
+		;;
+	news | news700 | news800 | news900)
+		basic_machine=m68k-sony
+		os=-newsos
+		;;
+	news1000)
+		basic_machine=m68030-sony
+		os=-newsos
+		;;
+	news-3600 | risc-news)
+		basic_machine=mips-sony
+		os=-newsos
+		;;
+	next | m*-next )
+		basic_machine=m68k-next
+		case $os in
+		    -nextstep* )
+			;;
+		    -ns2*)
+		      os=-nextstep2
+			;;
+		    *)
+		      os=-nextstep3
+			;;
+		esac
+		;;
+	nh3000)
+		basic_machine=m68k-harris
+		os=-cxux
+		;;
+	nh[45]000)
+		basic_machine=m88k-harris
+		os=-cxux
+		;;
+	nindy960)
+		basic_machine=i960-intel
+		os=-nindy
+		;;
+	np1)
+		basic_machine=np1-gould
+		;;
+	pa-hitachi)
+		basic_machine=hppa1.1-hitachi
+		os=-hiuxwe2
+		;;
+	paragon)
+		basic_machine=i860-intel
+		os=-osf
+		;;
+	pbd)
+		basic_machine=sparc-tti
+		;;
+	pbb)
+		basic_machine=m68k-tti
+		;;
+        pc532 | pc532-*)
+		basic_machine=ns32k-pc532
+		;;
+	pentium-*)
+		# We will change tis to say i586 once there has been
+		# time for various packages to start to recognize that.
+		basic_machine=i486-`echo $basic_machine | sed 's/^[^-]*-//'`
+		;;
+	pn)
+		basic_machine=pn-gould
+		;;
+	ps2)
+		basic_machine=i386-ibm
+		;;
+	rtpc | rtpc-*)
+		basic_machine=romp-ibm
+		;;
+	sequent)
+		basic_machine=i386-sequent
+		;;
+	sh)
+		basic_machine=sh-hitachi
+		os=-hms
+		;;
+	sps7)
+		basic_machine=m68k-bull
+		os=-sysv2
+		;;
+	spur)
+		basic_machine=spur-unknown
+		;;
+	sun2)
+		basic_machine=m68000-sun
+		;;
+	sun2os3)
+		basic_machine=m68000-sun
+		os=-sunos3
+		;;
+	sun2os4)
+		basic_machine=m68000-sun
+		os=-sunos4
+		;;
+	sun3os3)
+		basic_machine=m68k-sun
+		os=-sunos3
+		;;
+	sun3os4)
+		basic_machine=m68k-sun
+		os=-sunos4
+		;;
+	sun4os3)
+		basic_machine=sparc-sun
+		os=-sunos3
+		;;
+	sun4os4)
+		basic_machine=sparc-sun
+		os=-sunos4
+		;;
+	sun3 | sun3-*)
+		basic_machine=m68k-sun
+		;;
+	sun4)
+		basic_machine=sparc-sun
+		;;
+	sun386 | sun386i | roadrunner)
+		basic_machine=i386-sun
+		;;
+	symmetry)
+		basic_machine=i386-sequent
+		os=-dynix
+		;;
+	tower | tower-32)
+		basic_machine=m68k-ncr
+		;;
+	ultra3)
+		basic_machine=a29k-nyu
+		os=-sym1
+		;;
+	vaxv)
+		basic_machine=vax-dec
+		os=-sysv
+		;;
+	vms)
+		basic_machine=vax-dec
+		os=-vms
+		;;
+	vxworks960)
+		basic_machine=i960-wrs
+		os=-vxworks
+		;;
+	vxworks68)
+		basic_machine=m68k-wrs
+		os=-vxworks
+		;;
+	xmp)
+		basic_machine=xmp-cray
+		os=-unicos
+		;;
+        xps | xps100)
+		basic_machine=xps100-honeywell
+		;;
+	none)
+		basic_machine=none-none
+		os=-none
+		;;
+
+# Here we handle the default manufacturer of certain CPU types.  It is in
+# some cases the only manufacturer, in others, it is the most popular.
+	mips)
+		basic_machine=mips-mips
+		;;
+	romp)
+		basic_machine=romp-ibm
+		;;
+	rs6000)
+		basic_machine=rs6000-ibm
+		;;
+	vax)
+		basic_machine=vax-dec
+		;;
+	pdp11)
+		basic_machine=pdp11-dec
+		;;
+	we32k)
+		basic_machine=we32k-att
+		;;
+	sparc)
+		basic_machine=sparc-sun
+		;;
+        cydra)
+		basic_machine=cydra-cydrome
+		;;
+	orion)
+		basic_machine=orion-highlevel
+		;;
+	orion105)
+		basic_machine=clipper-highlevel
+		;;
+	*)
+		echo Invalid configuration \`$1\': machine \`$basic_machine\' not recognized 1>&2
+		exit 1
+		;;
+esac
+
+# Here we canonicalize certain aliases for manufacturers.
+case $basic_machine in
+	*-digital*)
+		basic_machine=`echo $basic_machine | sed 's/digital.*/dec/'`
+		;;
+	*-commodore*)
+		basic_machine=`echo $basic_machine | sed 's/commodore.*/cbm/'`
+		;;
+	*)
+		;;
+esac
+
+# Decode manufacturer-specific aliases for certain operating systems.
+
+if [ x"$os" != x"" ]
+then
+case $os in
+	# -solaris* is a basic system type, with this one exception.
+	-solaris1 | -solaris1.*)
+		os=`echo $os | sed -e 's|solaris1|sunos4|'`
+		;;
+	-solaris)
+		os=-solaris2
+		;;
+	-gnu/linux*)
+		os=`echo $os | sed -e 's|gnu/linux|linux|'`
+		;;
+	# First accept the basic system types.
+	# The portable systems comes first.
+	# Each alternative must end in a *, to match a version number.
+	# -sysv* is not here because it comes later, after sysvr4.
+	-gnu* | -bsd* | -mach* | -minix* | -genix* | -ultrix* | -irix* \
+	      | -vms* | -sco* | -esix* | -isc* | -aix* | -sunos | -sunos[345]* \
+	      | -hpux* | -unos* | -osf* | -luna* | -dgux* | -solaris* | -sym* \
+	      | -amigados* | -msdos* | -newsos* | -unicos* | -aos* \
+	      | -nindy* | -vxworks* | -ebmon* | -hms* | -mvs* | -clix* \
+	      | -riscos* | -linux* | -uniplus* | -iris* | -rtu* | -xenix* \
+	      | -hiux* | -386bsd* | -netbsd* | -freebsd* | -riscix* \
+	      | -lynxos* | -bosx* | -nextstep* | -cxux* | -aout* | -elf* \
+	      | -ptx* | -coff* | -winnt*)
+		;;
+	-sunos5*)
+		os=`echo $os | sed -e 's|sunos5|solaris2|'`
+		;;
+	-sunos6*)
+		os=`echo $os | sed -e 's|sunos6|solaris3|'`
+		;;
+	-osfrose*)
+		os=-osfrose
+		;;
+	-osf*)
+		os=-osf
+		;;
+	-utek*)
+		os=-bsd
+		;;
+	-dynix*)
+		os=-bsd
+		;;
+	-acis*)
+		os=-aos
+		;;
+	-ctix* | -uts*)
+		os=-sysv
+		;;
+	-triton*)
+		os=-sysv3
+		;;
+	-oss*)
+		os=-sysv3
+		;;
+	-svr4)
+		os=-sysv4
+		;;
+	-svr3)
+		os=-sysv3
+		;;
+	-sysvr4)
+		os=-sysv4
+		;;
+	# This must come after -sysvr4.
+	-sysv*)
+		;;
+	-xenix)
+		os=-xenix
+		;;
+	-none)
+		;;
+	*)
+		# Get rid of the `-' at the beginning of $os.
+		os=`echo $os | sed 's/[^-]*-//'`
+		echo Invalid configuration \`$1\': system \`$os\' not recognized 1>&2
+		exit 1
+		;;
+esac
+else
+
+# Here we handle the default operating systems that come with various machines.
+# The value should be what the vendor currently ships out the door with their
+# machine or put another way, the most popular os provided with the machine.
+
+# Note that if you're going to try to match "-MANUFACTURER" here (say,
+# "-sun"), then you have to tell the case statement up towards the top
+# that MANUFACTURER isn't an operating system.  Otherwise, code above
+# will signal an error saying that MANUFACTURER isn't an operating
+# system, and we'll never get to this point.
+
+case $basic_machine in
+	*-acorn)
+		os=-riscix1.2
+		;;
+        pdp11-*)
+		os=-none
+		;;
+	*-dec | vax-*)
+		os=-ultrix4.2
+		;;
+	i386-sun)
+		os=-sunos4.0.2
+		;;
+	m68000-sun)
+		os=-sunos3
+		# This also exists in the configure program, but was not the
+		# default.
+		# os=-sunos4
+		;;
+	*-tti)	# must be before sparc entry or we get the wrong os.
+		os=-sysv3
+		;;
+	sparc-* | *-sun)
+		os=-sunos4.1.1
+		;;
+	*-ibm)
+		os=-aix
+		;;
+	*-hp)
+		os=-hpux
+		;;
+	*-hitachi)
+		os=-hiux
+		;;
+	i860-* | *-att | *-ncr | *-altos | *-motorola | *-convergent)
+		os=-sysv
+		;;
+	*-cbm)
+		os=-amigados
+		;;
+	*-dg)
+		os=-dgux
+		;;
+	*-dolphin)
+		os=-sysv3
+		;;
+	m68k-ccur)
+		os=-rtu
+		;;
+	m88k-omron*)
+		os=-luna
+		;;
+	*-sequent)
+		os=-ptx
+		;;
+	*-crds)
+		os=-unos
+		;;
+	*-ns)
+		os=-genix
+		;;
+	i370-*)
+		os=-mvs
+		;;
+	*-next)
+		os=-nextstep3
+		;;
+        *-gould)
+		os=-sysv
+		;;
+        *-highlevel)
+		os=-bsd
+		;;
+	*-encore)
+		os=-bsd
+		;;
+        *-sgi)
+		os=-irix
+		;;
+	*-masscomp)
+		os=-rtu
+		;;
+	*)
+		os=-none
+		;;
+esac
+fi
+
+# Here we handle the case where we know the os, and the CPU type, but not the
+# manufacturer.  We pick the logical manufacturer.
+vendor=unknown
+case $basic_machine in
+	*-unknown)
+		case $os in
+			-riscix*)
+				vendor=acorn
+				;;
+			-sunos*)
+				vendor=sun
+				;;
+			-lynxos*)
+				vendor=lynx
+				;;
+			-aix*)
+				vendor=ibm
+				;;
+			-hpux*)
+				vendor=hp
+				;;
+			-hiux*)
+				vendor=hitachi
+				;;
+			-unos*)
+				vendor=crds
+				;;
+			-dgux*)
+				vendor=dg
+				;;
+			-luna*)
+				vendor=omron
+				;;
+			-genix*)
+				vendor=ns
+				;;
+			-mvs*)
+				vendor=ibm
+				;;
+			-ptx*)
+				vendor=sequent
+				;;
+		esac
+		basic_machine=`echo $basic_machine | sed "s/unknown/$vendor/"`
+		;;
+esac
+
+echo $basic_machine$os
Index: /main/tags/2.25/gsdl/src/mgpp/configure
===================================================================
--- /main/tags/2.25/gsdl/src/mgpp/configure	(revision 21064)
+++ /main/tags/2.25/gsdl/src/mgpp/configure	(revision 21064)
@@ -0,0 +1,3380 @@
+#! /bin/sh
+
+# Guess values for system-dependent variables and create Makefiles.
+# Generated automatically using autoconf version 2.13 
+# Copyright (C) 1992, 93, 94, 95, 96 Free Software Foundation, Inc.
+#
+# This configure script is free software; the Free Software Foundation
+# gives unlimited permission to copy, distribute and modify it.
+
+# Defaults:
+ac_help=
+ac_default_prefix=/usr/local
+# Any additions from configure.in:
+ac_help="$ac_help
+  --with-dmalloc          use dmalloc, as in
+                          ftp://ftp.letters.com/src/dmalloc/dmalloc.tar.gz"
+ac_help="$ac_help
+  --with-regex            use older regex in lieu of GNU rx for matching"
+ac_help="$ac_help
+  --with-gnu-readline     compile with GNU readline support"
+ac_help="$ac_help
+  --enable-override-longlong
+                          overide use of long long with GCC"
+
+# Initialize some variables set by options.
+# The variables have the same names as the options, with
+# dashes changed to underlines.
+build=NONE
+cache_file=./config.cache
+exec_prefix=NONE
+host=NONE
+no_create=
+nonopt=NONE
+no_recursion=
+prefix=NONE
+program_prefix=NONE
+program_suffix=NONE
+program_transform_name=s,x,x,
+silent=
+site=
+srcdir=
+target=NONE
+verbose=
+x_includes=NONE
+x_libraries=NONE
+bindir='${exec_prefix}/bin'
+sbindir='${exec_prefix}/sbin'
+libexecdir='${exec_prefix}/libexec'
+datadir='${prefix}/share'
+sysconfdir='${prefix}/etc'
+sharedstatedir='${prefix}/com'
+localstatedir='${prefix}/var'
+libdir='${exec_prefix}/lib'
+includedir='${prefix}/include'
+oldincludedir='/usr/include'
+infodir='${prefix}/info'
+mandir='${prefix}/man'
+
+# Initialize some other variables.
+subdirs=
+MFLAGS= MAKEFLAGS=
+SHELL=${CONFIG_SHELL-/bin/sh}
+# Maximum number of lines to put in a shell here document.
+ac_max_here_lines=12
+
+ac_prev=
+for ac_option
+do
+
+  # If the previous option needs an argument, assign it.
+  if test -n "$ac_prev"; then
+    eval "$ac_prev=\$ac_option"
+    ac_prev=
+    continue
+  fi
+
+  case "$ac_option" in
+  -*=*) ac_optarg=`echo "$ac_option" | sed 's/[-_a-zA-Z0-9]*=//'` ;;
+  *) ac_optarg= ;;
+  esac
+
+  # Accept the important Cygnus configure options, so we can diagnose typos.
+
+  case "$ac_option" in
+
+  -bindir | --bindir | --bindi | --bind | --bin | --bi)
+    ac_prev=bindir ;;
+  -bindir=* | --bindir=* | --bindi=* | --bind=* | --bin=* | --bi=*)
+    bindir="$ac_optarg" ;;
+
+  -build | --build | --buil | --bui | --bu)
+    ac_prev=build ;;
+  -build=* | --build=* | --buil=* | --bui=* | --bu=*)
+    build="$ac_optarg" ;;
+
+  -cache-file | --cache-file | --cache-fil | --cache-fi \
+  | --cache-f | --cache- | --cache | --cach | --cac | --ca | --c)
+    ac_prev=cache_file ;;
+  -cache-file=* | --cache-file=* | --cache-fil=* | --cache-fi=* \
+  | --cache-f=* | --cache-=* | --cache=* | --cach=* | --cac=* | --ca=* | --c=*)
+    cache_file="$ac_optarg" ;;
+
+  -datadir | --datadir | --datadi | --datad | --data | --dat | --da)
+    ac_prev=datadir ;;
+  -datadir=* | --datadir=* | --datadi=* | --datad=* | --data=* | --dat=* \
+  | --da=*)
+    datadir="$ac_optarg" ;;
+
+  -disable-* | --disable-*)
+    ac_feature=`echo $ac_option|sed -e 's/-*disable-//'`
+    # Reject names that are not valid shell variable names.
+    if test -n "`echo $ac_feature| sed 's/[-a-zA-Z0-9_]//g'`"; then
+      { echo "configure: error: $ac_feature: invalid feature name" 1>&2; exit 1; }
+    fi
+    ac_feature=`echo $ac_feature| sed 's/-/_/g'`
+    eval "enable_${ac_feature}=no" ;;
+
+  -enable-* | --enable-*)
+    ac_feature=`echo $ac_option|sed -e 's/-*enable-//' -e 's/=.*//'`
+    # Reject names that are not valid shell variable names.
+    if test -n "`echo $ac_feature| sed 's/[-_a-zA-Z0-9]//g'`"; then
+      { echo "configure: error: $ac_feature: invalid feature name" 1>&2; exit 1; }
+    fi
+    ac_feature=`echo $ac_feature| sed 's/-/_/g'`
+    case "$ac_option" in
+      *=*) ;;
+      *) ac_optarg=yes ;;
+    esac
+    eval "enable_${ac_feature}='$ac_optarg'" ;;
+
+  -exec-prefix | --exec_prefix | --exec-prefix | --exec-prefi \
+  | --exec-pref | --exec-pre | --exec-pr | --exec-p | --exec- \
+  | --exec | --exe | --ex)
+    ac_prev=exec_prefix ;;
+  -exec-prefix=* | --exec_prefix=* | --exec-prefix=* | --exec-prefi=* \
+  | --exec-pref=* | --exec-pre=* | --exec-pr=* | --exec-p=* | --exec-=* \
+  | --exec=* | --exe=* | --ex=*)
+    exec_prefix="$ac_optarg" ;;
+
+  -gas | --gas | --ga | --g)
+    # Obsolete; use --with-gas.
+    with_gas=yes ;;
+
+  -help | --help | --hel | --he)
+    # Omit some internal or obsolete options to make the list less imposing.
+    # This message is too long to be a string in the A/UX 3.1 sh.
+    cat << EOF
+Usage: configure [options] [host]
+Options: [defaults in brackets after descriptions]
+Configuration:
+  --cache-file=FILE       cache test results in FILE
+  --help                  print this message
+  --no-create             do not create output files
+  --quiet, --silent       do not print \`checking...' messages
+  --version               print the version of autoconf that created configure
+Directory and file names:
+  --prefix=PREFIX         install architecture-independent files in PREFIX
+                          [$ac_default_prefix]
+  --exec-prefix=EPREFIX   install architecture-dependent files in EPREFIX
+                          [same as prefix]
+  --bindir=DIR            user executables in DIR [EPREFIX/bin]
+  --sbindir=DIR           system admin executables in DIR [EPREFIX/sbin]
+  --libexecdir=DIR        program executables in DIR [EPREFIX/libexec]
+  --datadir=DIR           read-only architecture-independent data in DIR
+                          [PREFIX/share]
+  --sysconfdir=DIR        read-only single-machine data in DIR [PREFIX/etc]
+  --sharedstatedir=DIR    modifiable architecture-independent data in DIR
+                          [PREFIX/com]
+  --localstatedir=DIR     modifiable single-machine data in DIR [PREFIX/var]
+  --libdir=DIR            object code libraries in DIR [EPREFIX/lib]
+  --includedir=DIR        C header files in DIR [PREFIX/include]
+  --oldincludedir=DIR     C header files for non-gcc in DIR [/usr/include]
+  --infodir=DIR           info documentation in DIR [PREFIX/info]
+  --mandir=DIR            man documentation in DIR [PREFIX/man]
+  --srcdir=DIR            find the sources in DIR [configure dir or ..]
+  --program-prefix=PREFIX prepend PREFIX to installed program names
+  --program-suffix=SUFFIX append SUFFIX to installed program names
+  --program-transform-name=PROGRAM
+                          run sed PROGRAM on installed program names
+EOF
+    cat << EOF
+Host type:
+  --build=BUILD           configure for building on BUILD [BUILD=HOST]
+  --host=HOST             configure for HOST [guessed]
+  --target=TARGET         configure for TARGET [TARGET=HOST]
+Features and packages:
+  --disable-FEATURE       do not include FEATURE (same as --enable-FEATURE=no)
+  --enable-FEATURE[=ARG]  include FEATURE [ARG=yes]
+  --with-PACKAGE[=ARG]    use PACKAGE [ARG=yes]
+  --without-PACKAGE       do not use PACKAGE (same as --with-PACKAGE=no)
+  --x-includes=DIR        X include files are in DIR
+  --x-libraries=DIR       X library files are in DIR
+EOF
+    if test -n "$ac_help"; then
+      echo "--enable and --with options recognized:$ac_help"
+    fi
+    exit 0 ;;
+
+  -host | --host | --hos | --ho)
+    ac_prev=host ;;
+  -host=* | --host=* | --hos=* | --ho=*)
+    host="$ac_optarg" ;;
+
+  -includedir | --includedir | --includedi | --included | --include \
+  | --includ | --inclu | --incl | --inc)
+    ac_prev=includedir ;;
+  -includedir=* | --includedir=* | --includedi=* | --included=* | --include=* \
+  | --includ=* | --inclu=* | --incl=* | --inc=*)
+    includedir="$ac_optarg" ;;
+
+  -infodir | --infodir | --infodi | --infod | --info | --inf)
+    ac_prev=infodir ;;
+  -infodir=* | --infodir=* | --infodi=* | --infod=* | --info=* | --inf=*)
+    infodir="$ac_optarg" ;;
+
+  -libdir | --libdir | --libdi | --libd)
+    ac_prev=libdir ;;
+  -libdir=* | --libdir=* | --libdi=* | --libd=*)
+    libdir="$ac_optarg" ;;
+
+  -libexecdir | --libexecdir | --libexecdi | --libexecd | --libexec \
+  | --libexe | --libex | --libe)
+    ac_prev=libexecdir ;;
+  -libexecdir=* | --libexecdir=* | --libexecdi=* | --libexecd=* | --libexec=* \
+  | --libexe=* | --libex=* | --libe=*)
+    libexecdir="$ac_optarg" ;;
+
+  -localstatedir | --localstatedir | --localstatedi | --localstated \
+  | --localstate | --localstat | --localsta | --localst \
+  | --locals | --local | --loca | --loc | --lo)
+    ac_prev=localstatedir ;;
+  -localstatedir=* | --localstatedir=* | --localstatedi=* | --localstated=* \
+  | --localstate=* | --localstat=* | --localsta=* | --localst=* \
+  | --locals=* | --local=* | --loca=* | --loc=* | --lo=*)
+    localstatedir="$ac_optarg" ;;
+
+  -mandir | --mandir | --mandi | --mand | --man | --ma | --m)
+    ac_prev=mandir ;;
+  -mandir=* | --mandir=* | --mandi=* | --mand=* | --man=* | --ma=* | --m=*)
+    mandir="$ac_optarg" ;;
+
+  -nfp | --nfp | --nf)
+    # Obsolete; use --without-fp.
+    with_fp=no ;;
+
+  -no-create | --no-create | --no-creat | --no-crea | --no-cre \
+  | --no-cr | --no-c)
+    no_create=yes ;;
+
+  -no-recursion | --no-recursion | --no-recursio | --no-recursi \
+  | --no-recurs | --no-recur | --no-recu | --no-rec | --no-re | --no-r)
+    no_recursion=yes ;;
+
+  -oldincludedir | --oldincludedir | --oldincludedi | --oldincluded \
+  | --oldinclude | --oldinclud | --oldinclu | --oldincl | --oldinc \
+  | --oldin | --oldi | --old | --ol | --o)
+    ac_prev=oldincludedir ;;
+  -oldincludedir=* | --oldincludedir=* | --oldincludedi=* | --oldincluded=* \
+  | --oldinclude=* | --oldinclud=* | --oldinclu=* | --oldincl=* | --oldinc=* \
+  | --oldin=* | --oldi=* | --old=* | --ol=* | --o=*)
+    oldincludedir="$ac_optarg" ;;
+
+  -prefix | --prefix | --prefi | --pref | --pre | --pr | --p)
+    ac_prev=prefix ;;
+  -prefix=* | --prefix=* | --prefi=* | --pref=* | --pre=* | --pr=* | --p=*)
+    prefix="$ac_optarg" ;;
+
+  -program-prefix | --program-prefix | --program-prefi | --program-pref \
+  | --program-pre | --program-pr | --program-p)
+    ac_prev=program_prefix ;;
+  -program-prefix=* | --program-prefix=* | --program-prefi=* \
+  | --program-pref=* | --program-pre=* | --program-pr=* | --program-p=*)
+    program_prefix="$ac_optarg" ;;
+
+  -program-suffix | --program-suffix | --program-suffi | --program-suff \
+  | --program-suf | --program-su | --program-s)
+    ac_prev=program_suffix ;;
+  -program-suffix=* | --program-suffix=* | --program-suffi=* \
+  | --program-suff=* | --program-suf=* | --program-su=* | --program-s=*)
+    program_suffix="$ac_optarg" ;;
+
+  -program-transform-name | --program-transform-name \
+  | --program-transform-nam | --program-transform-na \
+  | --program-transform-n | --program-transform- \
+  | --program-transform | --program-transfor \
+  | --program-transfo | --program-transf \
+  | --program-trans | --program-tran \
+  | --progr-tra | --program-tr | --program-t)
+    ac_prev=program_transform_name ;;
+  -program-transform-name=* | --program-transform-name=* \
+  | --program-transform-nam=* | --program-transform-na=* \
+  | --program-transform-n=* | --program-transform-=* \
+  | --program-transform=* | --program-transfor=* \
+  | --program-transfo=* | --program-transf=* \
+  | --program-trans=* | --program-tran=* \
+  | --progr-tra=* | --program-tr=* | --program-t=*)
+    program_transform_name="$ac_optarg" ;;
+
+  -q | -quiet | --quiet | --quie | --qui | --qu | --q \
+  | -silent | --silent | --silen | --sile | --sil)
+    silent=yes ;;
+
+  -sbindir | --sbindir | --sbindi | --sbind | --sbin | --sbi | --sb)
+    ac_prev=sbindir ;;
+  -sbindir=* | --sbindir=* | --sbindi=* | --sbind=* | --sbin=* \
+  | --sbi=* | --sb=*)
+    sbindir="$ac_optarg" ;;
+
+  -sharedstatedir | --sharedstatedir | --sharedstatedi \
+  | --sharedstated | --sharedstate | --sharedstat | --sharedsta \
+  | --sharedst | --shareds | --shared | --share | --shar \
+  | --sha | --sh)
+    ac_prev=sharedstatedir ;;
+  -sharedstatedir=* | --sharedstatedir=* | --sharedstatedi=* \
+  | --sharedstated=* | --sharedstate=* | --sharedstat=* | --sharedsta=* \
+  | --sharedst=* | --shareds=* | --shared=* | --share=* | --shar=* \
+  | --sha=* | --sh=*)
+    sharedstatedir="$ac_optarg" ;;
+
+  -site | --site | --sit)
+    ac_prev=site ;;
+  -site=* | --site=* | --sit=*)
+    site="$ac_optarg" ;;
+
+  -srcdir | --srcdir | --srcdi | --srcd | --src | --sr)
+    ac_prev=srcdir ;;
+  -srcdir=* | --srcdir=* | --srcdi=* | --srcd=* | --src=* | --sr=*)
+    srcdir="$ac_optarg" ;;
+
+  -sysconfdir | --sysconfdir | --sysconfdi | --sysconfd | --sysconf \
+  | --syscon | --sysco | --sysc | --sys | --sy)
+    ac_prev=sysconfdir ;;
+  -sysconfdir=* | --sysconfdir=* | --sysconfdi=* | --sysconfd=* | --sysconf=* \
+  | --syscon=* | --sysco=* | --sysc=* | --sys=* | --sy=*)
+    sysconfdir="$ac_optarg" ;;
+
+  -target | --target | --targe | --targ | --tar | --ta | --t)
+    ac_prev=target ;;
+  -target=* | --target=* | --targe=* | --targ=* | --tar=* | --ta=* | --t=*)
+    target="$ac_optarg" ;;
+
+  -v | -verbose | --verbose | --verbos | --verbo | --verb)
+    verbose=yes ;;
+
+  -version | --version | --versio | --versi | --vers)
+    echo "configure generated by autoconf version 2.13"
+    exit 0 ;;
+
+  -with-* | --with-*)
+    ac_package=`echo $ac_option|sed -e 's/-*with-//' -e 's/=.*//'`
+    # Reject names that are not valid shell variable names.
+    if test -n "`echo $ac_package| sed 's/[-_a-zA-Z0-9]//g'`"; then
+      { echo "configure: error: $ac_package: invalid package name" 1>&2; exit 1; }
+    fi
+    ac_package=`echo $ac_package| sed 's/-/_/g'`
+    case "$ac_option" in
+      *=*) ;;
+      *) ac_optarg=yes ;;
+    esac
+    eval "with_${ac_package}='$ac_optarg'" ;;
+
+  -without-* | --without-*)
+    ac_package=`echo $ac_option|sed -e 's/-*without-//'`
+    # Reject names that are not valid shell variable names.
+    if test -n "`echo $ac_package| sed 's/[-a-zA-Z0-9_]//g'`"; then
+      { echo "configure: error: $ac_package: invalid package name" 1>&2; exit 1; }
+    fi
+    ac_package=`echo $ac_package| sed 's/-/_/g'`
+    eval "with_${ac_package}=no" ;;
+
+  --x)
+    # Obsolete; use --with-x.
+    with_x=yes ;;
+
+  -x-includes | --x-includes | --x-include | --x-includ | --x-inclu \
+  | --x-incl | --x-inc | --x-in | --x-i)
+    ac_prev=x_includes ;;
+  -x-includes=* | --x-includes=* | --x-include=* | --x-includ=* | --x-inclu=* \
+  | --x-incl=* | --x-inc=* | --x-in=* | --x-i=*)
+    x_includes="$ac_optarg" ;;
+
+  -x-libraries | --x-libraries | --x-librarie | --x-librari \
+  | --x-librar | --x-libra | --x-libr | --x-lib | --x-li | --x-l)
+    ac_prev=x_libraries ;;
+  -x-libraries=* | --x-libraries=* | --x-librarie=* | --x-librari=* \
+  | --x-librar=* | --x-libra=* | --x-libr=* | --x-lib=* | --x-li=* | --x-l=*)
+    x_libraries="$ac_optarg" ;;
+
+  -*) { echo "configure: error: $ac_option: invalid option; use --help to show usage" 1>&2; exit 1; }
+    ;;
+
+  *)
+    if test -n "`echo $ac_option| sed 's/[-a-z0-9.]//g'`"; then
+      echo "configure: warning: $ac_option: invalid host type" 1>&2
+    fi
+    if test "x$nonopt" != xNONE; then
+      { echo "configure: error: can only configure for one host and one target at a time" 1>&2; exit 1; }
+    fi
+    nonopt="$ac_option"
+    ;;
+
+  esac
+done
+
+if test -n "$ac_prev"; then
+  { echo "configure: error: missing argument to --`echo $ac_prev | sed 's/_/-/g'`" 1>&2; exit 1; }
+fi
+
+trap 'rm -fr conftest* confdefs* core core.* *.core $ac_clean_files; exit 1' 1 2 15
+
+# File descriptor usage:
+# 0 standard input
+# 1 file creation
+# 2 errors and warnings
+# 3 some systems may open it to /dev/tty
+# 4 used on the Kubota Titan
+# 6 checking for... messages and results
+# 5 compiler messages saved in config.log
+if test "$silent" = yes; then
+  exec 6>/dev/null
+else
+  exec 6>&1
+fi
+exec 5>./config.log
+
+echo "\
+This file contains any messages produced by compilers while
+running configure, to aid debugging if configure makes a mistake.
+" 1>&5
+
+# Strip out --no-create and --no-recursion so they do not pile up.
+# Also quote any args containing shell metacharacters.
+ac_configure_args=
+for ac_arg
+do
+  case "$ac_arg" in
+  -no-create | --no-create | --no-creat | --no-crea | --no-cre \
+  | --no-cr | --no-c) ;;
+  -no-recursion | --no-recursion | --no-recursio | --no-recursi \
+  | --no-recurs | --no-recur | --no-recu | --no-rec | --no-re | --no-r) ;;
+  *" "*|*"	"*|*[\[\]\~\#\$\^\&\*\(\)\{\}\\\|\;\<\>\?]*)
+  ac_configure_args="$ac_configure_args '$ac_arg'" ;;
+  *) ac_configure_args="$ac_configure_args $ac_arg" ;;
+  esac
+done
+
+# NLS nuisances.
+# Only set these to C if already set.  These must not be set unconditionally
+# because not all systems understand e.g. LANG=C (notably SCO).
+# Fixing LC_MESSAGES prevents Solaris sh from translating var values in `set'!
+# Non-C LC_CTYPE values break the ctype check.
+if test "${LANG+set}"   = set; then LANG=C;   export LANG;   fi
+if test "${LC_ALL+set}" = set; then LC_ALL=C; export LC_ALL; fi
+if test "${LC_MESSAGES+set}" = set; then LC_MESSAGES=C; export LC_MESSAGES; fi
+if test "${LC_CTYPE+set}"    = set; then LC_CTYPE=C;    export LC_CTYPE;    fi
+
+# confdefs.h avoids OS command line length limits that DEFS can exceed.
+rm -rf conftest* confdefs.h
+# AIX cpp loses on an empty file, so make sure it contains at least a newline.
+echo > confdefs.h
+
+# A filename unique to this package, relative to the directory that
+# configure is in, which we can look for to find out if srcdir is correct.
+ac_unique_file=text/MGQuery.cpp
+
+# Find the source files, if location was not specified.
+if test -z "$srcdir"; then
+  ac_srcdir_defaulted=yes
+  # Try the directory containing this script, then its parent.
+  ac_prog=$0
+  ac_confdir=`echo $ac_prog|sed 's%/[^/][^/]*$%%'`
+  test "x$ac_confdir" = "x$ac_prog" && ac_confdir=.
+  srcdir=$ac_confdir
+  if test ! -r $srcdir/$ac_unique_file; then
+    srcdir=..
+  fi
+else
+  ac_srcdir_defaulted=no
+fi
+if test ! -r $srcdir/$ac_unique_file; then
+  if test "$ac_srcdir_defaulted" = yes; then
+    { echo "configure: error: can not find sources in $ac_confdir or .." 1>&2; exit 1; }
+  else
+    { echo "configure: error: can not find sources in $srcdir" 1>&2; exit 1; }
+  fi
+fi
+srcdir=`echo "${srcdir}" | sed 's%\([^/]\)/*$%\1%'`
+
+# Prefer explicitly selected file to automatically selected ones.
+if test -z "$CONFIG_SITE"; then
+  if test "x$prefix" != xNONE; then
+    CONFIG_SITE="$prefix/share/config.site $prefix/etc/config.site"
+  else
+    CONFIG_SITE="$ac_default_prefix/share/config.site $ac_default_prefix/etc/config.site"
+  fi
+fi
+for ac_site_file in $CONFIG_SITE; do
+  if test -r "$ac_site_file"; then
+    echo "loading site script $ac_site_file"
+    . "$ac_site_file"
+  fi
+done
+
+if test -r "$cache_file"; then
+  echo "loading cache $cache_file"
+  . $cache_file
+else
+  echo "creating cache $cache_file"
+  > $cache_file
+fi
+
+ac_ext=c
+# CFLAGS is not in ac_cpp because -g, -O, etc. are not valid cpp options.
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='${CC-cc} -c $CFLAGS $CPPFLAGS conftest.$ac_ext 1>&5'
+ac_link='${CC-cc} -o conftest${ac_exeext} $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS 1>&5'
+cross_compiling=$ac_cv_prog_cc_cross
+
+ac_exeext=
+ac_objext=o
+if (echo "testing\c"; echo 1,2,3) | grep c >/dev/null; then
+  # Stardent Vistra SVR4 grep lacks -e, says ghazi@caip.rutgers.edu.
+  if (echo -n testing; echo 1,2,3) | sed s/-n/xn/ | grep xn >/dev/null; then
+    ac_n= ac_c='
+' ac_t='	'
+  else
+    ac_n=-n ac_c= ac_t=
+  fi
+else
+  ac_n= ac_c='\c' ac_t=
+fi
+
+
+
+if test "$program_transform_name" = s,x,x,; then
+  program_transform_name=
+else
+  # Double any \ or $.  echo might interpret backslashes.
+  cat <<\EOF_SED > conftestsed
+s,\\,\\\\,g; s,\$,$$,g
+EOF_SED
+  program_transform_name="`echo $program_transform_name|sed -f conftestsed`"
+  rm -f conftestsed
+fi
+test "$program_prefix" != NONE &&
+  program_transform_name="s,^,${program_prefix},; $program_transform_name"
+# Use a double $ so make ignores it.
+test "$program_suffix" != NONE &&
+  program_transform_name="s,\$\$,${program_suffix},; $program_transform_name"
+
+# sed with no file args requires a program.
+test "$program_transform_name" = "" && program_transform_name="s,x,x,"
+
+
+PACKAGE=mgpp
+VERSION=1.3
+
+cat >> confdefs.h <<EOF
+#define PACKAGE "$PACKAGE"
+EOF
+
+cat >> confdefs.h <<EOF
+#define VERSION "$VERSION"
+EOF
+
+
+
+
+for ac_prog in $CCC c++ g++ gcc CC cxx cc++ cl
+do
+# Extract the first word of "$ac_prog", so it can be a program name with args.
+set dummy $ac_prog; ac_word=$2
+echo $ac_n "checking for $ac_word""... $ac_c" 1>&6
+echo "configure:575: checking for $ac_word" >&5
+if eval "test \"`echo '$''{'ac_cv_prog_CXX'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  if test -n "$CXX"; then
+  ac_cv_prog_CXX="$CXX" # Let the user override the test.
+else
+  IFS="${IFS= 	}"; ac_save_ifs="$IFS"; IFS=":"
+  ac_dummy="$PATH"
+  for ac_dir in $ac_dummy; do
+    test -z "$ac_dir" && ac_dir=.
+    if test -f $ac_dir/$ac_word; then
+      ac_cv_prog_CXX="$ac_prog"
+      break
+    fi
+  done
+  IFS="$ac_save_ifs"
+fi
+fi
+CXX="$ac_cv_prog_CXX"
+if test -n "$CXX"; then
+  echo "$ac_t""$CXX" 1>&6
+else
+  echo "$ac_t""no" 1>&6
+fi
+
+test -n "$CXX" && break
+done
+test -n "$CXX" || CXX="gcc"
+
+
+echo $ac_n "checking whether the C++ compiler ($CXX $CXXFLAGS $LDFLAGS) works""... $ac_c" 1>&6
+echo "configure:607: checking whether the C++ compiler ($CXX $CXXFLAGS $LDFLAGS) works" >&5
+
+ac_ext=C
+# CXXFLAGS is not in ac_cpp because -g, -O, etc. are not valid cpp options.
+ac_cpp='$CXXCPP $CPPFLAGS'
+ac_compile='${CXX-g++} -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext 1>&5'
+ac_link='${CXX-g++} -o conftest${ac_exeext} $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS 1>&5'
+cross_compiling=$ac_cv_prog_cxx_cross
+
+cat > conftest.$ac_ext << EOF
+
+#line 618 "configure"
+#include "confdefs.h"
+
+int main(){return(0);}
+EOF
+if { (eval echo configure:623: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+  ac_cv_prog_cxx_works=yes
+  # If we can't run a trivial program, we are probably using a cross compiler.
+  if (./conftest; exit) 2>/dev/null; then
+    ac_cv_prog_cxx_cross=no
+  else
+    ac_cv_prog_cxx_cross=yes
+  fi
+else
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  ac_cv_prog_cxx_works=no
+fi
+rm -fr conftest*
+ac_ext=c
+# CFLAGS is not in ac_cpp because -g, -O, etc. are not valid cpp options.
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='${CC-cc} -c $CFLAGS $CPPFLAGS conftest.$ac_ext 1>&5'
+ac_link='${CC-cc} -o conftest${ac_exeext} $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS 1>&5'
+cross_compiling=$ac_cv_prog_cc_cross
+
+echo "$ac_t""$ac_cv_prog_cxx_works" 1>&6
+if test $ac_cv_prog_cxx_works = no; then
+  { echo "configure: error: installation or configuration problem: C++ compiler cannot create executables." 1>&2; exit 1; }
+fi
+echo $ac_n "checking whether the C++ compiler ($CXX $CXXFLAGS $LDFLAGS) is a cross-compiler""... $ac_c" 1>&6
+echo "configure:649: checking whether the C++ compiler ($CXX $CXXFLAGS $LDFLAGS) is a cross-compiler" >&5
+echo "$ac_t""$ac_cv_prog_cxx_cross" 1>&6
+cross_compiling=$ac_cv_prog_cxx_cross
+
+echo $ac_n "checking whether we are using GNU C++""... $ac_c" 1>&6
+echo "configure:654: checking whether we are using GNU C++" >&5
+if eval "test \"`echo '$''{'ac_cv_prog_gxx'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  cat > conftest.C <<EOF
+#ifdef __GNUC__
+  yes;
+#endif
+EOF
+if { ac_try='${CXX-g++} -E conftest.C'; { (eval echo configure:663: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }; } | egrep yes >/dev/null 2>&1; then
+  ac_cv_prog_gxx=yes
+else
+  ac_cv_prog_gxx=no
+fi
+fi
+
+echo "$ac_t""$ac_cv_prog_gxx" 1>&6
+
+if test $ac_cv_prog_gxx = yes; then
+  GXX=yes
+else
+  GXX=
+fi
+
+ac_test_CXXFLAGS="${CXXFLAGS+set}"
+ac_save_CXXFLAGS="$CXXFLAGS"
+CXXFLAGS=
+echo $ac_n "checking whether ${CXX-g++} accepts -g""... $ac_c" 1>&6
+echo "configure:682: checking whether ${CXX-g++} accepts -g" >&5
+if eval "test \"`echo '$''{'ac_cv_prog_cxx_g'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  echo 'void f(){}' > conftest.cc
+if test -z "`${CXX-g++} -g -c conftest.cc 2>&1`"; then
+  ac_cv_prog_cxx_g=yes
+else
+  ac_cv_prog_cxx_g=no
+fi
+rm -f conftest*
+
+fi
+
+echo "$ac_t""$ac_cv_prog_cxx_g" 1>&6
+if test "$ac_test_CXXFLAGS" = set; then
+  CXXFLAGS="$ac_save_CXXFLAGS"
+elif test $ac_cv_prog_cxx_g = yes; then
+  if test "$GXX" = yes; then
+    CXXFLAGS="-g -O2"
+  else
+    CXXFLAGS="-g"
+  fi
+else
+  if test "$GXX" = yes; then
+    CXXFLAGS="-O2"
+  else
+    CXXFLAGS=
+  fi
+fi
+
+for ac_prog in mawk gawk nawk awk
+do
+# Extract the first word of "$ac_prog", so it can be a program name with args.
+set dummy $ac_prog; ac_word=$2
+echo $ac_n "checking for $ac_word""... $ac_c" 1>&6
+echo "configure:718: checking for $ac_word" >&5
+if eval "test \"`echo '$''{'ac_cv_prog_AWK'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  if test -n "$AWK"; then
+  ac_cv_prog_AWK="$AWK" # Let the user override the test.
+else
+  IFS="${IFS= 	}"; ac_save_ifs="$IFS"; IFS=":"
+  ac_dummy="$PATH"
+  for ac_dir in $ac_dummy; do
+    test -z "$ac_dir" && ac_dir=.
+    if test -f $ac_dir/$ac_word; then
+      ac_cv_prog_AWK="$ac_prog"
+      break
+    fi
+  done
+  IFS="$ac_save_ifs"
+fi
+fi
+AWK="$ac_cv_prog_AWK"
+if test -n "$AWK"; then
+  echo "$ac_t""$AWK" 1>&6
+else
+  echo "$ac_t""no" 1>&6
+fi
+
+test -n "$AWK" && break
+done
+
+for ac_prog in 'bison -y' byacc
+do
+# Extract the first word of "$ac_prog", so it can be a program name with args.
+set dummy $ac_prog; ac_word=$2
+echo $ac_n "checking for $ac_word""... $ac_c" 1>&6
+echo "configure:752: checking for $ac_word" >&5
+if eval "test \"`echo '$''{'ac_cv_prog_YACC'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  if test -n "$YACC"; then
+  ac_cv_prog_YACC="$YACC" # Let the user override the test.
+else
+  IFS="${IFS= 	}"; ac_save_ifs="$IFS"; IFS=":"
+  ac_dummy="$PATH"
+  for ac_dir in $ac_dummy; do
+    test -z "$ac_dir" && ac_dir=.
+    if test -f $ac_dir/$ac_word; then
+      ac_cv_prog_YACC="$ac_prog"
+      break
+    fi
+  done
+  IFS="$ac_save_ifs"
+fi
+fi
+YACC="$ac_cv_prog_YACC"
+if test -n "$YACC"; then
+  echo "$ac_t""$YACC" 1>&6
+else
+  echo "$ac_t""no" 1>&6
+fi
+
+test -n "$YACC" && break
+done
+test -n "$YACC" || YACC="yacc"
+
+# Extract the first word of "gcc", so it can be a program name with args.
+set dummy gcc; ac_word=$2
+echo $ac_n "checking for $ac_word""... $ac_c" 1>&6
+echo "configure:785: checking for $ac_word" >&5
+if eval "test \"`echo '$''{'ac_cv_prog_CC'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  if test -n "$CC"; then
+  ac_cv_prog_CC="$CC" # Let the user override the test.
+else
+  IFS="${IFS= 	}"; ac_save_ifs="$IFS"; IFS=":"
+  ac_dummy="$PATH"
+  for ac_dir in $ac_dummy; do
+    test -z "$ac_dir" && ac_dir=.
+    if test -f $ac_dir/$ac_word; then
+      ac_cv_prog_CC="gcc"
+      break
+    fi
+  done
+  IFS="$ac_save_ifs"
+fi
+fi
+CC="$ac_cv_prog_CC"
+if test -n "$CC"; then
+  echo "$ac_t""$CC" 1>&6
+else
+  echo "$ac_t""no" 1>&6
+fi
+
+if test -z "$CC"; then
+  # Extract the first word of "cc", so it can be a program name with args.
+set dummy cc; ac_word=$2
+echo $ac_n "checking for $ac_word""... $ac_c" 1>&6
+echo "configure:815: checking for $ac_word" >&5
+if eval "test \"`echo '$''{'ac_cv_prog_CC'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  if test -n "$CC"; then
+  ac_cv_prog_CC="$CC" # Let the user override the test.
+else
+  IFS="${IFS= 	}"; ac_save_ifs="$IFS"; IFS=":"
+  ac_prog_rejected=no
+  ac_dummy="$PATH"
+  for ac_dir in $ac_dummy; do
+    test -z "$ac_dir" && ac_dir=.
+    if test -f $ac_dir/$ac_word; then
+      if test "$ac_dir/$ac_word" = "/usr/ucb/cc"; then
+        ac_prog_rejected=yes
+	continue
+      fi
+      ac_cv_prog_CC="cc"
+      break
+    fi
+  done
+  IFS="$ac_save_ifs"
+if test $ac_prog_rejected = yes; then
+  # We found a bogon in the path, so make sure we never use it.
+  set dummy $ac_cv_prog_CC
+  shift
+  if test $# -gt 0; then
+    # We chose a different compiler from the bogus one.
+    # However, it has the same basename, so the bogon will be chosen
+    # first if we set CC to just the basename; use the full file name.
+    shift
+    set dummy "$ac_dir/$ac_word" "$@"
+    shift
+    ac_cv_prog_CC="$@"
+  fi
+fi
+fi
+fi
+CC="$ac_cv_prog_CC"
+if test -n "$CC"; then
+  echo "$ac_t""$CC" 1>&6
+else
+  echo "$ac_t""no" 1>&6
+fi
+
+  if test -z "$CC"; then
+    case "`uname -s`" in
+    *win32* | *WIN32*)
+      # Extract the first word of "cl", so it can be a program name with args.
+set dummy cl; ac_word=$2
+echo $ac_n "checking for $ac_word""... $ac_c" 1>&6
+echo "configure:866: checking for $ac_word" >&5
+if eval "test \"`echo '$''{'ac_cv_prog_CC'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  if test -n "$CC"; then
+  ac_cv_prog_CC="$CC" # Let the user override the test.
+else
+  IFS="${IFS= 	}"; ac_save_ifs="$IFS"; IFS=":"
+  ac_dummy="$PATH"
+  for ac_dir in $ac_dummy; do
+    test -z "$ac_dir" && ac_dir=.
+    if test -f $ac_dir/$ac_word; then
+      ac_cv_prog_CC="cl"
+      break
+    fi
+  done
+  IFS="$ac_save_ifs"
+fi
+fi
+CC="$ac_cv_prog_CC"
+if test -n "$CC"; then
+  echo "$ac_t""$CC" 1>&6
+else
+  echo "$ac_t""no" 1>&6
+fi
+ ;;
+    esac
+  fi
+  test -z "$CC" && { echo "configure: error: no acceptable cc found in \$PATH" 1>&2; exit 1; }
+fi
+
+echo $ac_n "checking whether the C compiler ($CC $CFLAGS $LDFLAGS) works""... $ac_c" 1>&6
+echo "configure:898: checking whether the C compiler ($CC $CFLAGS $LDFLAGS) works" >&5
+
+ac_ext=c
+# CFLAGS is not in ac_cpp because -g, -O, etc. are not valid cpp options.
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='${CC-cc} -c $CFLAGS $CPPFLAGS conftest.$ac_ext 1>&5'
+ac_link='${CC-cc} -o conftest${ac_exeext} $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS 1>&5'
+cross_compiling=$ac_cv_prog_cc_cross
+
+cat > conftest.$ac_ext << EOF
+
+#line 909 "configure"
+#include "confdefs.h"
+
+main(){return(0);}
+EOF
+if { (eval echo configure:914: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+  ac_cv_prog_cc_works=yes
+  # If we can't run a trivial program, we are probably using a cross compiler.
+  if (./conftest; exit) 2>/dev/null; then
+    ac_cv_prog_cc_cross=no
+  else
+    ac_cv_prog_cc_cross=yes
+  fi
+else
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  ac_cv_prog_cc_works=no
+fi
+rm -fr conftest*
+ac_ext=c
+# CFLAGS is not in ac_cpp because -g, -O, etc. are not valid cpp options.
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='${CC-cc} -c $CFLAGS $CPPFLAGS conftest.$ac_ext 1>&5'
+ac_link='${CC-cc} -o conftest${ac_exeext} $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS 1>&5'
+cross_compiling=$ac_cv_prog_cc_cross
+
+echo "$ac_t""$ac_cv_prog_cc_works" 1>&6
+if test $ac_cv_prog_cc_works = no; then
+  { echo "configure: error: installation or configuration problem: C compiler cannot create executables." 1>&2; exit 1; }
+fi
+echo $ac_n "checking whether the C compiler ($CC $CFLAGS $LDFLAGS) is a cross-compiler""... $ac_c" 1>&6
+echo "configure:940: checking whether the C compiler ($CC $CFLAGS $LDFLAGS) is a cross-compiler" >&5
+echo "$ac_t""$ac_cv_prog_cc_cross" 1>&6
+cross_compiling=$ac_cv_prog_cc_cross
+
+echo $ac_n "checking whether we are using GNU C""... $ac_c" 1>&6
+echo "configure:945: checking whether we are using GNU C" >&5
+if eval "test \"`echo '$''{'ac_cv_prog_gcc'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  cat > conftest.c <<EOF
+#ifdef __GNUC__
+  yes;
+#endif
+EOF
+if { ac_try='${CC-cc} -E conftest.c'; { (eval echo configure:954: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }; } | egrep yes >/dev/null 2>&1; then
+  ac_cv_prog_gcc=yes
+else
+  ac_cv_prog_gcc=no
+fi
+fi
+
+echo "$ac_t""$ac_cv_prog_gcc" 1>&6
+
+if test $ac_cv_prog_gcc = yes; then
+  GCC=yes
+else
+  GCC=
+fi
+
+ac_test_CFLAGS="${CFLAGS+set}"
+ac_save_CFLAGS="$CFLAGS"
+CFLAGS=
+echo $ac_n "checking whether ${CC-cc} accepts -g""... $ac_c" 1>&6
+echo "configure:973: checking whether ${CC-cc} accepts -g" >&5
+if eval "test \"`echo '$''{'ac_cv_prog_cc_g'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  echo 'void f(){}' > conftest.c
+if test -z "`${CC-cc} -g -c conftest.c 2>&1`"; then
+  ac_cv_prog_cc_g=yes
+else
+  ac_cv_prog_cc_g=no
+fi
+rm -f conftest*
+
+fi
+
+echo "$ac_t""$ac_cv_prog_cc_g" 1>&6
+if test "$ac_test_CFLAGS" = set; then
+  CFLAGS="$ac_save_CFLAGS"
+elif test $ac_cv_prog_cc_g = yes; then
+  if test "$GCC" = yes; then
+    CFLAGS="-g -O2"
+  else
+    CFLAGS="-g"
+  fi
+else
+  if test "$GCC" = yes; then
+    CFLAGS="-O2"
+  else
+    CFLAGS=
+  fi
+fi
+
+ac_aux_dir=
+for ac_dir in $srcdir $srcdir/.. $srcdir/../..; do
+  if test -f $ac_dir/install-sh; then
+    ac_aux_dir=$ac_dir
+    ac_install_sh="$ac_aux_dir/install-sh -c"
+    break
+  elif test -f $ac_dir/install.sh; then
+    ac_aux_dir=$ac_dir
+    ac_install_sh="$ac_aux_dir/install.sh -c"
+    break
+  fi
+done
+if test -z "$ac_aux_dir"; then
+  { echo "configure: error: can not find install-sh or install.sh in $srcdir $srcdir/.. $srcdir/../.." 1>&2; exit 1; }
+fi
+ac_config_guess=$ac_aux_dir/config.guess
+ac_config_sub=$ac_aux_dir/config.sub
+ac_configure=$ac_aux_dir/configure # This should be Cygnus configure.
+
+# Find a good install program.  We prefer a C program (faster),
+# so one script is as good as another.  But avoid the broken or
+# incompatible versions:
+# SysV /etc/install, /usr/sbin/install
+# SunOS /usr/etc/install
+# IRIX /sbin/install
+# AIX /bin/install
+# AIX 4 /usr/bin/installbsd, which doesn't work without a -g flag
+# AFS /usr/afsws/bin/install, which mishandles nonexistent args
+# SVR4 /usr/ucb/install, which tries to use the nonexistent group "staff"
+# ./install, which can be erroneously created by make from ./install.sh.
+echo $ac_n "checking for a BSD compatible install""... $ac_c" 1>&6
+echo "configure:1035: checking for a BSD compatible install" >&5
+if test -z "$INSTALL"; then
+if eval "test \"`echo '$''{'ac_cv_path_install'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+    IFS="${IFS= 	}"; ac_save_IFS="$IFS"; IFS=":"
+  for ac_dir in $PATH; do
+    # Account for people who put trailing slashes in PATH elements.
+    case "$ac_dir/" in
+    /|./|.//|/etc/*|/usr/sbin/*|/usr/etc/*|/sbin/*|/usr/afsws/bin/*|/usr/ucb/*) ;;
+    *)
+      # OSF1 and SCO ODT 3.0 have their own names for install.
+      # Don't use installbsd from OSF since it installs stuff as root
+      # by default.
+      for ac_prog in ginstall scoinst install; do
+        if test -f $ac_dir/$ac_prog; then
+	  if test $ac_prog = install &&
+            grep dspmsg $ac_dir/$ac_prog >/dev/null 2>&1; then
+	    # AIX install.  It has an incompatible calling convention.
+	    :
+	  else
+	    ac_cv_path_install="$ac_dir/$ac_prog -c"
+	    break 2
+	  fi
+	fi
+      done
+      ;;
+    esac
+  done
+  IFS="$ac_save_IFS"
+
+fi
+  if test "${ac_cv_path_install+set}" = set; then
+    INSTALL="$ac_cv_path_install"
+  else
+    # As a last resort, use the slow shell script.  We don't cache a
+    # path for INSTALL within a source directory, because that will
+    # break other packages using the cache if that directory is
+    # removed, or if the path is relative.
+    INSTALL="$ac_install_sh"
+  fi
+fi
+echo "$ac_t""$INSTALL" 1>&6
+
+# Use test -z because SunOS4 sh mishandles braces in ${var-val}.
+# It thinks the first close brace ends the variable substitution.
+test -z "$INSTALL_PROGRAM" && INSTALL_PROGRAM='${INSTALL}'
+
+test -z "$INSTALL_SCRIPT" && INSTALL_SCRIPT='${INSTALL_PROGRAM}'
+
+test -z "$INSTALL_DATA" && INSTALL_DATA='${INSTALL} -m 644'
+
+echo $ac_n "checking whether ln -s works""... $ac_c" 1>&6
+echo "configure:1088: checking whether ln -s works" >&5
+if eval "test \"`echo '$''{'ac_cv_prog_LN_S'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  rm -f conftestdata
+if ln -s X conftestdata 2>/dev/null
+then
+  rm -f conftestdata
+  ac_cv_prog_LN_S="ln -s"
+else
+  ac_cv_prog_LN_S=ln
+fi
+fi
+LN_S="$ac_cv_prog_LN_S"
+if test "$ac_cv_prog_LN_S" = "ln -s"; then
+  echo "$ac_t""yes" 1>&6
+else
+  echo "$ac_t""no" 1>&6
+fi
+
+echo $ac_n "checking whether ${MAKE-make} sets \${MAKE}""... $ac_c" 1>&6
+echo "configure:1109: checking whether ${MAKE-make} sets \${MAKE}" >&5
+set dummy ${MAKE-make}; ac_make=`echo "$2" | sed 'y%./+-%__p_%'`
+if eval "test \"`echo '$''{'ac_cv_prog_make_${ac_make}_set'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  cat > conftestmake <<\EOF
+all:
+	@echo 'ac_maketemp="${MAKE}"'
+EOF
+# GNU make sometimes prints "make[1]: Entering...", which would confuse us.
+eval `${MAKE-make} -f conftestmake 2>/dev/null | grep temp=`
+if test -n "$ac_maketemp"; then
+  eval ac_cv_prog_make_${ac_make}_set=yes
+else
+  eval ac_cv_prog_make_${ac_make}_set=no
+fi
+rm -f conftestmake
+fi
+if eval "test \"`echo '$ac_cv_prog_make_'${ac_make}_set`\" = yes"; then
+  echo "$ac_t""yes" 1>&6
+  SET_MAKE=
+else
+  echo "$ac_t""no" 1>&6
+  SET_MAKE="MAKE=${MAKE-make}"
+fi
+
+# Extract the first word of "ranlib", so it can be a program name with args.
+set dummy ranlib; ac_word=$2
+echo $ac_n "checking for $ac_word""... $ac_c" 1>&6
+echo "configure:1138: checking for $ac_word" >&5
+if eval "test \"`echo '$''{'ac_cv_prog_RANLIB'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  if test -n "$RANLIB"; then
+  ac_cv_prog_RANLIB="$RANLIB" # Let the user override the test.
+else
+  IFS="${IFS= 	}"; ac_save_ifs="$IFS"; IFS=":"
+  ac_dummy="$PATH"
+  for ac_dir in $ac_dummy; do
+    test -z "$ac_dir" && ac_dir=.
+    if test -f $ac_dir/$ac_word; then
+      ac_cv_prog_RANLIB="ranlib"
+      break
+    fi
+  done
+  IFS="$ac_save_ifs"
+  test -z "$ac_cv_prog_RANLIB" && ac_cv_prog_RANLIB=":"
+fi
+fi
+RANLIB="$ac_cv_prog_RANLIB"
+if test -n "$RANLIB"; then
+  echo "$ac_t""$RANLIB" 1>&6
+else
+  echo "$ac_t""no" 1>&6
+fi
+
+
+echo $ac_n "checking how to run the C preprocessor""... $ac_c" 1>&6
+echo "configure:1167: checking how to run the C preprocessor" >&5
+# On Suns, sometimes $CPP names a directory.
+if test -n "$CPP" && test -d "$CPP"; then
+  CPP=
+fi
+if test -z "$CPP"; then
+if eval "test \"`echo '$''{'ac_cv_prog_CPP'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+    # This must be in double quotes, not single quotes, because CPP may get
+  # substituted into the Makefile and "${CC-cc}" will confuse make.
+  CPP="${CC-cc} -E"
+  # On the NeXT, cc -E runs the code through the compiler's parser,
+  # not just through cpp.
+  cat > conftest.$ac_ext <<EOF
+#line 1182 "configure"
+#include "confdefs.h"
+#include <assert.h>
+Syntax Error
+EOF
+ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out"
+{ (eval echo configure:1188: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }
+ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"`
+if test -z "$ac_err"; then
+  :
+else
+  echo "$ac_err" >&5
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -rf conftest*
+  CPP="${CC-cc} -E -traditional-cpp"
+  cat > conftest.$ac_ext <<EOF
+#line 1199 "configure"
+#include "confdefs.h"
+#include <assert.h>
+Syntax Error
+EOF
+ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out"
+{ (eval echo configure:1205: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }
+ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"`
+if test -z "$ac_err"; then
+  :
+else
+  echo "$ac_err" >&5
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -rf conftest*
+  CPP="${CC-cc} -nologo -E"
+  cat > conftest.$ac_ext <<EOF
+#line 1216 "configure"
+#include "confdefs.h"
+#include <assert.h>
+Syntax Error
+EOF
+ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out"
+{ (eval echo configure:1222: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }
+ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"`
+if test -z "$ac_err"; then
+  :
+else
+  echo "$ac_err" >&5
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -rf conftest*
+  CPP=/lib/cpp
+fi
+rm -f conftest*
+fi
+rm -f conftest*
+fi
+rm -f conftest*
+  ac_cv_prog_CPP="$CPP"
+fi
+  CPP="$ac_cv_prog_CPP"
+else
+  ac_cv_prog_CPP="$CPP"
+fi
+echo "$ac_t""$CPP" 1>&6
+
+echo $ac_n "checking for AIX""... $ac_c" 1>&6
+echo "configure:1247: checking for AIX" >&5
+cat > conftest.$ac_ext <<EOF
+#line 1249 "configure"
+#include "confdefs.h"
+#ifdef _AIX
+  yes
+#endif
+
+EOF
+if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
+  egrep "yes" >/dev/null 2>&1; then
+  rm -rf conftest*
+  echo "$ac_t""yes" 1>&6; cat >> confdefs.h <<\EOF
+#define _ALL_SOURCE 1
+EOF
+
+else
+  rm -rf conftest*
+  echo "$ac_t""no" 1>&6
+fi
+rm -f conftest*
+
+
+echo $ac_n "checking for POSIXized ISC""... $ac_c" 1>&6
+echo "configure:1271: checking for POSIXized ISC" >&5
+if test -d /etc/conf/kconfig.d &&
+  grep _POSIX_VERSION /usr/include/sys/unistd.h >/dev/null 2>&1
+then
+  echo "$ac_t""yes" 1>&6
+  ISC=yes # If later tests want to check for ISC.
+  cat >> confdefs.h <<\EOF
+#define _POSIX_SOURCE 1
+EOF
+
+  if test "$GCC" = yes; then
+    CC="$CC -posix"
+  else
+    CC="$CC -Xp"
+  fi
+else
+  echo "$ac_t""no" 1>&6
+  ISC=
+fi
+
+ac_safe=`echo "minix/config.h" | sed 'y%./+-%__p_%'`
+echo $ac_n "checking for minix/config.h""... $ac_c" 1>&6
+echo "configure:1293: checking for minix/config.h" >&5
+if eval "test \"`echo '$''{'ac_cv_header_$ac_safe'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  cat > conftest.$ac_ext <<EOF
+#line 1298 "configure"
+#include "confdefs.h"
+#include <minix/config.h>
+EOF
+ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out"
+{ (eval echo configure:1303: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }
+ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"`
+if test -z "$ac_err"; then
+  rm -rf conftest*
+  eval "ac_cv_header_$ac_safe=yes"
+else
+  echo "$ac_err" >&5
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -rf conftest*
+  eval "ac_cv_header_$ac_safe=no"
+fi
+rm -f conftest*
+fi
+if eval "test \"`echo '$ac_cv_header_'$ac_safe`\" = yes"; then
+  echo "$ac_t""yes" 1>&6
+  MINIX=yes
+else
+  echo "$ac_t""no" 1>&6
+MINIX=
+fi
+
+if test "$MINIX" = yes; then
+  cat >> confdefs.h <<\EOF
+#define _POSIX_SOURCE 1
+EOF
+
+  cat >> confdefs.h <<\EOF
+#define _POSIX_1_SOURCE 2
+EOF
+
+  cat >> confdefs.h <<\EOF
+#define _MINIX 1
+EOF
+
+fi
+
+echo $ac_n "checking for ${CC-cc} option to accept ANSI C""... $ac_c" 1>&6
+echo "configure:1341: checking for ${CC-cc} option to accept ANSI C" >&5
+if eval "test \"`echo '$''{'ac_cv_prog_cc_stdc'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  ac_cv_prog_cc_stdc=no
+ac_save_CFLAGS="$CFLAGS"
+# Don't try gcc -ansi; that turns off useful extensions and
+# breaks some systems' header files.
+# AIX			-qlanglvl=ansi
+# Ultrix and OSF/1	-std1
+# HP-UX			-Aa -D_HPUX_SOURCE
+# SVR4			-Xc
+for ac_arg in "" -qlanglvl=ansi -std1 "-Aa -D_HPUX_SOURCE" -Xc
+do
+  CFLAGS="$ac_save_CFLAGS $ac_arg"
+  cat > conftest.$ac_ext <<EOF
+#line 1357 "configure"
+#include "confdefs.h"
+#if !defined(__STDC__) || __STDC__ != 1
+choke me
+#endif	
+
+int main() {
+int test (int i, double x);
+struct s1 {int (*f) (int a);};
+struct s2 {int (*f) (double a);};
+; return 0; }
+EOF
+if { (eval echo configure:1369: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
+  rm -rf conftest*
+  ac_cv_prog_cc_stdc="$ac_arg"; break
+else
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+fi
+rm -f conftest*
+done
+CFLAGS="$ac_save_CFLAGS"
+
+fi
+
+echo "$ac_t""$ac_cv_prog_cc_stdc" 1>&6
+case "x$ac_cv_prog_cc_stdc" in
+  x|xno) ;;
+  *) CC="$CC $ac_cv_prog_cc_stdc" ;;
+esac
+
+
+echo $ac_n "checking for function prototypes""... $ac_c" 1>&6
+echo "configure:1390: checking for function prototypes" >&5
+if test "$ac_cv_prog_cc_stdc" != no; then
+  echo "$ac_t""yes" 1>&6
+  cat >> confdefs.h <<\EOF
+#define PROTOTYPES 1
+EOF
+
+  U= ANSI2KNR=
+else
+  echo "$ac_t""no" 1>&6
+  U=_ ANSI2KNR=ansi2knr
+fi
+
+echo $ac_n "checking for working const""... $ac_c" 1>&6
+echo "configure:1404: checking for working const" >&5
+if eval "test \"`echo '$''{'ac_cv_c_const'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  cat > conftest.$ac_ext <<EOF
+#line 1409 "configure"
+#include "confdefs.h"
+
+int main() {
+
+/* Ultrix mips cc rejects this.  */
+typedef int charset[2]; const charset x;
+/* SunOS 4.1.1 cc rejects this.  */
+char const *const *ccp;
+char **p;
+/* NEC SVR4.0.2 mips cc rejects this.  */
+struct point {int x, y;};
+static struct point const zero = {0,0};
+/* AIX XL C 1.02.0.0 rejects this.
+   It does not let you subtract one const X* pointer from another in an arm
+   of an if-expression whose if-part is not a constant expression */
+const char *g = "string";
+ccp = &g + (g ? g-g : 0);
+/* HPUX 7.0 cc rejects these. */
+++ccp;
+p = (char**) ccp;
+ccp = (char const *const *) p;
+{ /* SCO 3.2v4 cc rejects this.  */
+  char *t;
+  char const *s = 0 ? (char *) 0 : (char const *) 0;
+
+  *t++ = 0;
+}
+{ /* Someone thinks the Sun supposedly-ANSI compiler will reject this.  */
+  int x[] = {25, 17};
+  const int *foo = &x[0];
+  ++foo;
+}
+{ /* Sun SC1.0 ANSI compiler rejects this -- but not the above. */
+  typedef const int *iptr;
+  iptr p = 0;
+  ++p;
+}
+{ /* AIX XL C 1.02.0.0 rejects this saying
+     "k.c", line 2.27: 1506-025 (S) Operand must be a modifiable lvalue. */
+  struct s { int j; const int *ap[3]; };
+  struct s *b; b->j = 5;
+}
+{ /* ULTRIX-32 V3.1 (Rev 9) vcc rejects this */
+  const int foo = 10;
+}
+
+; return 0; }
+EOF
+if { (eval echo configure:1458: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
+  rm -rf conftest*
+  ac_cv_c_const=yes
+else
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -rf conftest*
+  ac_cv_c_const=no
+fi
+rm -f conftest*
+fi
+
+echo "$ac_t""$ac_cv_c_const" 1>&6
+if test $ac_cv_c_const = no; then
+  cat >> confdefs.h <<\EOF
+#define const 
+EOF
+
+fi
+
+echo $ac_n "checking for ANSI C header files""... $ac_c" 1>&6
+echo "configure:1479: checking for ANSI C header files" >&5
+if eval "test \"`echo '$''{'ac_cv_header_stdc'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  cat > conftest.$ac_ext <<EOF
+#line 1484 "configure"
+#include "confdefs.h"
+#include <stdlib.h>
+#include <stdarg.h>
+#include <string.h>
+#include <float.h>
+EOF
+ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out"
+{ (eval echo configure:1492: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }
+ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"`
+if test -z "$ac_err"; then
+  rm -rf conftest*
+  ac_cv_header_stdc=yes
+else
+  echo "$ac_err" >&5
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -rf conftest*
+  ac_cv_header_stdc=no
+fi
+rm -f conftest*
+
+if test $ac_cv_header_stdc = yes; then
+  # SunOS 4.x string.h does not declare mem*, contrary to ANSI.
+cat > conftest.$ac_ext <<EOF
+#line 1509 "configure"
+#include "confdefs.h"
+#include <string.h>
+EOF
+if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
+  egrep "memchr" >/dev/null 2>&1; then
+  :
+else
+  rm -rf conftest*
+  ac_cv_header_stdc=no
+fi
+rm -f conftest*
+
+fi
+
+if test $ac_cv_header_stdc = yes; then
+  # ISC 2.0.2 stdlib.h does not declare free, contrary to ANSI.
+cat > conftest.$ac_ext <<EOF
+#line 1527 "configure"
+#include "confdefs.h"
+#include <stdlib.h>
+EOF
+if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
+  egrep "free" >/dev/null 2>&1; then
+  :
+else
+  rm -rf conftest*
+  ac_cv_header_stdc=no
+fi
+rm -f conftest*
+
+fi
+
+if test $ac_cv_header_stdc = yes; then
+  # /bin/cc in Irix-4.0.5 gets non-ANSI ctype macros unless using -ansi.
+if test "$cross_compiling" = yes; then
+  :
+else
+  cat > conftest.$ac_ext <<EOF
+#line 1548 "configure"
+#include "confdefs.h"
+#include <ctype.h>
+#define ISLOWER(c) ('a' <= (c) && (c) <= 'z')
+#define TOUPPER(c) (ISLOWER(c) ? 'A' + ((c) - 'a') : (c))
+#define XOR(e, f) (((e) && !(f)) || (!(e) && (f)))
+int main () { int i; for (i = 0; i < 256; i++)
+if (XOR (islower (i), ISLOWER (i)) || toupper (i) != TOUPPER (i)) exit(2);
+exit (0); }
+
+EOF
+if { (eval echo configure:1559: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext} && (./conftest; exit) 2>/dev/null
+then
+  :
+else
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -fr conftest*
+  ac_cv_header_stdc=no
+fi
+rm -fr conftest*
+fi
+
+fi
+fi
+
+echo "$ac_t""$ac_cv_header_stdc" 1>&6
+if test $ac_cv_header_stdc = yes; then
+  cat >> confdefs.h <<\EOF
+#define STDC_HEADERS 1
+EOF
+
+fi
+
+echo $ac_n "checking for off_t""... $ac_c" 1>&6
+echo "configure:1583: checking for off_t" >&5
+if eval "test \"`echo '$''{'ac_cv_type_off_t'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  cat > conftest.$ac_ext <<EOF
+#line 1588 "configure"
+#include "confdefs.h"
+#include <sys/types.h>
+#if STDC_HEADERS
+#include <stdlib.h>
+#include <stddef.h>
+#endif
+EOF
+if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
+  egrep "(^|[^a-zA-Z_0-9])off_t[^a-zA-Z_0-9]" >/dev/null 2>&1; then
+  rm -rf conftest*
+  ac_cv_type_off_t=yes
+else
+  rm -rf conftest*
+  ac_cv_type_off_t=no
+fi
+rm -f conftest*
+
+fi
+echo "$ac_t""$ac_cv_type_off_t" 1>&6
+if test $ac_cv_type_off_t = no; then
+  cat >> confdefs.h <<\EOF
+#define off_t long
+EOF
+
+fi
+
+echo $ac_n "checking for size_t""... $ac_c" 1>&6
+echo "configure:1616: checking for size_t" >&5
+if eval "test \"`echo '$''{'ac_cv_type_size_t'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  cat > conftest.$ac_ext <<EOF
+#line 1621 "configure"
+#include "confdefs.h"
+#include <sys/types.h>
+#if STDC_HEADERS
+#include <stdlib.h>
+#include <stddef.h>
+#endif
+EOF
+if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
+  egrep "(^|[^a-zA-Z_0-9])size_t[^a-zA-Z_0-9]" >/dev/null 2>&1; then
+  rm -rf conftest*
+  ac_cv_type_size_t=yes
+else
+  rm -rf conftest*
+  ac_cv_type_size_t=no
+fi
+rm -f conftest*
+
+fi
+echo "$ac_t""$ac_cv_type_size_t" 1>&6
+if test $ac_cv_type_size_t = no; then
+  cat >> confdefs.h <<\EOF
+#define size_t unsigned
+EOF
+
+fi
+
+echo $ac_n "checking whether time.h and sys/time.h may both be included""... $ac_c" 1>&6
+echo "configure:1649: checking whether time.h and sys/time.h may both be included" >&5
+if eval "test \"`echo '$''{'ac_cv_header_time'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  cat > conftest.$ac_ext <<EOF
+#line 1654 "configure"
+#include "confdefs.h"
+#include <sys/types.h>
+#include <sys/time.h>
+#include <time.h>
+int main() {
+struct tm *tp;
+; return 0; }
+EOF
+if { (eval echo configure:1663: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
+  rm -rf conftest*
+  ac_cv_header_time=yes
+else
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -rf conftest*
+  ac_cv_header_time=no
+fi
+rm -f conftest*
+fi
+
+echo "$ac_t""$ac_cv_header_time" 1>&6
+if test $ac_cv_header_time = yes; then
+  cat >> confdefs.h <<\EOF
+#define TIME_WITH_SYS_TIME 1
+EOF
+
+fi
+
+echo $ac_n "checking whether struct tm is in sys/time.h or time.h""... $ac_c" 1>&6
+echo "configure:1684: checking whether struct tm is in sys/time.h or time.h" >&5
+if eval "test \"`echo '$''{'ac_cv_struct_tm'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  cat > conftest.$ac_ext <<EOF
+#line 1689 "configure"
+#include "confdefs.h"
+#include <sys/types.h>
+#include <time.h>
+int main() {
+struct tm *tp; tp->tm_sec;
+; return 0; }
+EOF
+if { (eval echo configure:1697: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
+  rm -rf conftest*
+  ac_cv_struct_tm=time.h
+else
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -rf conftest*
+  ac_cv_struct_tm=sys/time.h
+fi
+rm -f conftest*
+fi
+
+echo "$ac_t""$ac_cv_struct_tm" 1>&6
+if test $ac_cv_struct_tm = sys/time.h; then
+  cat >> confdefs.h <<\EOF
+#define TM_IN_SYS_TIME 1
+EOF
+
+fi
+
+
+if test "$ac_cv_prog_cc_stdc" = '-Xc'; then
+cat > conftest.$ac_ext <<EOF
+#line 1720 "configure"
+#include "confdefs.h"
+#include <stdio.h>
+
+int main() {
+ FILE *rubbish = popen("yes", "r"); 
+; return 0; }
+EOF
+if { (eval echo configure:1728: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
+  :
+else
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -rf conftest*
+  CC="`echo $CC | sed 's/-Xc/-Xa/'`"    ac_cv_prog_cc_stdc='-Xa'
+fi
+rm -f conftest*
+fi
+
+
+echo $ac_n "checking for main in -lm""... $ac_c" 1>&6
+echo "configure:1741: checking for main in -lm" >&5
+ac_lib_var=`echo m'_'main | sed 'y%./+-%__p_%'`
+if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  ac_save_LIBS="$LIBS"
+LIBS="-lm  $LIBS"
+cat > conftest.$ac_ext <<EOF
+#line 1749 "configure"
+#include "confdefs.h"
+
+int main() {
+main()
+; return 0; }
+EOF
+if { (eval echo configure:1756: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+  rm -rf conftest*
+  eval "ac_cv_lib_$ac_lib_var=yes"
+else
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -rf conftest*
+  eval "ac_cv_lib_$ac_lib_var=no"
+fi
+rm -f conftest*
+LIBS="$ac_save_LIBS"
+
+fi
+if eval "test \"`echo '$ac_cv_lib_'$ac_lib_var`\" = yes"; then
+  echo "$ac_t""yes" 1>&6
+    ac_tr_lib=HAVE_LIB`echo m | sed -e 's/[^a-zA-Z0-9_]/_/g' \
+    -e 'y/abcdefghijklmnopqrstuvwxyz/ABCDEFGHIJKLMNOPQRSTUVWXYZ/'`
+  cat >> confdefs.h <<EOF
+#define $ac_tr_lib 1
+EOF
+
+  LIBS="-lm $LIBS"
+
+else
+  echo "$ac_t""no" 1>&6
+fi
+
+
+ac_header_dirent=no
+for ac_hdr in dirent.h sys/ndir.h sys/dir.h ndir.h
+do
+ac_safe=`echo "$ac_hdr" | sed 'y%./+-%__p_%'`
+echo $ac_n "checking for $ac_hdr that defines DIR""... $ac_c" 1>&6
+echo "configure:1789: checking for $ac_hdr that defines DIR" >&5
+if eval "test \"`echo '$''{'ac_cv_header_dirent_$ac_safe'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  cat > conftest.$ac_ext <<EOF
+#line 1794 "configure"
+#include "confdefs.h"
+#include <sys/types.h>
+#include <$ac_hdr>
+int main() {
+DIR *dirp = 0;
+; return 0; }
+EOF
+if { (eval echo configure:1802: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
+  rm -rf conftest*
+  eval "ac_cv_header_dirent_$ac_safe=yes"
+else
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -rf conftest*
+  eval "ac_cv_header_dirent_$ac_safe=no"
+fi
+rm -f conftest*
+fi
+if eval "test \"`echo '$ac_cv_header_dirent_'$ac_safe`\" = yes"; then
+  echo "$ac_t""yes" 1>&6
+    ac_tr_hdr=HAVE_`echo $ac_hdr | sed 'y%abcdefghijklmnopqrstuvwxyz./-%ABCDEFGHIJKLMNOPQRSTUVWXYZ___%'`
+  cat >> confdefs.h <<EOF
+#define $ac_tr_hdr 1
+EOF
+ ac_header_dirent=$ac_hdr; break
+else
+  echo "$ac_t""no" 1>&6
+fi
+done
+# Two versions of opendir et al. are in -ldir and -lx on SCO Xenix.
+if test $ac_header_dirent = dirent.h; then
+echo $ac_n "checking for opendir in -ldir""... $ac_c" 1>&6
+echo "configure:1827: checking for opendir in -ldir" >&5
+ac_lib_var=`echo dir'_'opendir | sed 'y%./+-%__p_%'`
+if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  ac_save_LIBS="$LIBS"
+LIBS="-ldir  $LIBS"
+cat > conftest.$ac_ext <<EOF
+#line 1835 "configure"
+#include "confdefs.h"
+/* Override any gcc2 internal prototype to avoid an error.  */
+/* We use char because int might match the return type of a gcc2
+    builtin and then its argument prototype would still apply.  */
+char opendir();
+
+int main() {
+opendir()
+; return 0; }
+EOF
+if { (eval echo configure:1846: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+  rm -rf conftest*
+  eval "ac_cv_lib_$ac_lib_var=yes"
+else
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -rf conftest*
+  eval "ac_cv_lib_$ac_lib_var=no"
+fi
+rm -f conftest*
+LIBS="$ac_save_LIBS"
+
+fi
+if eval "test \"`echo '$ac_cv_lib_'$ac_lib_var`\" = yes"; then
+  echo "$ac_t""yes" 1>&6
+  LIBS="$LIBS -ldir"
+else
+  echo "$ac_t""no" 1>&6
+fi
+
+else
+echo $ac_n "checking for opendir in -lx""... $ac_c" 1>&6
+echo "configure:1868: checking for opendir in -lx" >&5
+ac_lib_var=`echo x'_'opendir | sed 'y%./+-%__p_%'`
+if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  ac_save_LIBS="$LIBS"
+LIBS="-lx  $LIBS"
+cat > conftest.$ac_ext <<EOF
+#line 1876 "configure"
+#include "confdefs.h"
+/* Override any gcc2 internal prototype to avoid an error.  */
+/* We use char because int might match the return type of a gcc2
+    builtin and then its argument prototype would still apply.  */
+char opendir();
+
+int main() {
+opendir()
+; return 0; }
+EOF
+if { (eval echo configure:1887: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+  rm -rf conftest*
+  eval "ac_cv_lib_$ac_lib_var=yes"
+else
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -rf conftest*
+  eval "ac_cv_lib_$ac_lib_var=no"
+fi
+rm -f conftest*
+LIBS="$ac_save_LIBS"
+
+fi
+if eval "test \"`echo '$ac_cv_lib_'$ac_lib_var`\" = yes"; then
+  echo "$ac_t""yes" 1>&6
+  LIBS="$LIBS -lx"
+else
+  echo "$ac_t""no" 1>&6
+fi
+
+fi
+
+echo $ac_n "checking for ANSI C header files""... $ac_c" 1>&6
+echo "configure:1910: checking for ANSI C header files" >&5
+if eval "test \"`echo '$''{'ac_cv_header_stdc'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  cat > conftest.$ac_ext <<EOF
+#line 1915 "configure"
+#include "confdefs.h"
+#include <stdlib.h>
+#include <stdarg.h>
+#include <string.h>
+#include <float.h>
+EOF
+ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out"
+{ (eval echo configure:1923: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }
+ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"`
+if test -z "$ac_err"; then
+  rm -rf conftest*
+  ac_cv_header_stdc=yes
+else
+  echo "$ac_err" >&5
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -rf conftest*
+  ac_cv_header_stdc=no
+fi
+rm -f conftest*
+
+if test $ac_cv_header_stdc = yes; then
+  # SunOS 4.x string.h does not declare mem*, contrary to ANSI.
+cat > conftest.$ac_ext <<EOF
+#line 1940 "configure"
+#include "confdefs.h"
+#include <string.h>
+EOF
+if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
+  egrep "memchr" >/dev/null 2>&1; then
+  :
+else
+  rm -rf conftest*
+  ac_cv_header_stdc=no
+fi
+rm -f conftest*
+
+fi
+
+if test $ac_cv_header_stdc = yes; then
+  # ISC 2.0.2 stdlib.h does not declare free, contrary to ANSI.
+cat > conftest.$ac_ext <<EOF
+#line 1958 "configure"
+#include "confdefs.h"
+#include <stdlib.h>
+EOF
+if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
+  egrep "free" >/dev/null 2>&1; then
+  :
+else
+  rm -rf conftest*
+  ac_cv_header_stdc=no
+fi
+rm -f conftest*
+
+fi
+
+if test $ac_cv_header_stdc = yes; then
+  # /bin/cc in Irix-4.0.5 gets non-ANSI ctype macros unless using -ansi.
+if test "$cross_compiling" = yes; then
+  :
+else
+  cat > conftest.$ac_ext <<EOF
+#line 1979 "configure"
+#include "confdefs.h"
+#include <ctype.h>
+#define ISLOWER(c) ('a' <= (c) && (c) <= 'z')
+#define TOUPPER(c) (ISLOWER(c) ? 'A' + ((c) - 'a') : (c))
+#define XOR(e, f) (((e) && !(f)) || (!(e) && (f)))
+int main () { int i; for (i = 0; i < 256; i++)
+if (XOR (islower (i), ISLOWER (i)) || toupper (i) != TOUPPER (i)) exit(2);
+exit (0); }
+
+EOF
+if { (eval echo configure:1990: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext} && (./conftest; exit) 2>/dev/null
+then
+  :
+else
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -fr conftest*
+  ac_cv_header_stdc=no
+fi
+rm -fr conftest*
+fi
+
+fi
+fi
+
+echo "$ac_t""$ac_cv_header_stdc" 1>&6
+if test $ac_cv_header_stdc = yes; then
+  cat >> confdefs.h <<\EOF
+#define STDC_HEADERS 1
+EOF
+
+fi
+
+for ac_hdr in fcntl.h limits.h sys/time.h unistd.h string.h memory.h sys/procfs.h
+do
+ac_safe=`echo "$ac_hdr" | sed 'y%./+-%__p_%'`
+echo $ac_n "checking for $ac_hdr""... $ac_c" 1>&6
+echo "configure:2017: checking for $ac_hdr" >&5
+if eval "test \"`echo '$''{'ac_cv_header_$ac_safe'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  cat > conftest.$ac_ext <<EOF
+#line 2022 "configure"
+#include "confdefs.h"
+#include <$ac_hdr>
+EOF
+ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out"
+{ (eval echo configure:2027: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }
+ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"`
+if test -z "$ac_err"; then
+  rm -rf conftest*
+  eval "ac_cv_header_$ac_safe=yes"
+else
+  echo "$ac_err" >&5
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -rf conftest*
+  eval "ac_cv_header_$ac_safe=no"
+fi
+rm -f conftest*
+fi
+if eval "test \"`echo '$ac_cv_header_'$ac_safe`\" = yes"; then
+  echo "$ac_t""yes" 1>&6
+    ac_tr_hdr=HAVE_`echo $ac_hdr | sed 'y%abcdefghijklmnopqrstuvwxyz./-%ABCDEFGHIJKLMNOPQRSTUVWXYZ___%'`
+  cat >> confdefs.h <<EOF
+#define $ac_tr_hdr 1
+EOF
+ 
+else
+  echo "$ac_t""no" 1>&6
+fi
+done
+
+cat > conftest.$ac_ext <<EOF
+#line 2054 "configure"
+#include "confdefs.h"
+#include <stdio.h>
+EOF
+if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
+  egrep "fread" >/dev/null 2>&1; then
+  rm -rf conftest*
+  cat >> confdefs.h <<\EOF
+#define HAVE_FREAD_DECL 1
+EOF
+
+fi
+rm -f conftest*
+
+cat > conftest.$ac_ext <<EOF
+#line 2069 "configure"
+#include "confdefs.h"
+#include <stdio.h>
+EOF
+if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
+  egrep "fgetc" >/dev/null 2>&1; then
+  rm -rf conftest*
+  cat >> confdefs.h <<\EOF
+#define HAVE_FGETC_DECL 1
+EOF
+
+fi
+rm -f conftest*
+
+cat > conftest.$ac_ext <<EOF
+#line 2084 "configure"
+#include "confdefs.h"
+#include <sys/procfs.h>
+EOF
+if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
+  egrep "pr_brksize" >/dev/null 2>&1; then
+  rm -rf conftest*
+  cat >> confdefs.h <<\EOF
+#define HAVE_PR_BRKSIZE 1
+EOF
+
+fi
+rm -f conftest*
+
+
+# The Ultrix 4.2 mips builtin alloca declared by alloca.h only works
+# for constant arguments.  Useless!
+echo $ac_n "checking for working alloca.h""... $ac_c" 1>&6
+echo "configure:2102: checking for working alloca.h" >&5
+if eval "test \"`echo '$''{'ac_cv_header_alloca_h'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  cat > conftest.$ac_ext <<EOF
+#line 2107 "configure"
+#include "confdefs.h"
+#include <alloca.h>
+int main() {
+char *p = alloca(2 * sizeof(int));
+; return 0; }
+EOF
+if { (eval echo configure:2114: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+  rm -rf conftest*
+  ac_cv_header_alloca_h=yes
+else
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -rf conftest*
+  ac_cv_header_alloca_h=no
+fi
+rm -f conftest*
+fi
+
+echo "$ac_t""$ac_cv_header_alloca_h" 1>&6
+if test $ac_cv_header_alloca_h = yes; then
+  cat >> confdefs.h <<\EOF
+#define HAVE_ALLOCA_H 1
+EOF
+
+fi
+
+echo $ac_n "checking for alloca""... $ac_c" 1>&6
+echo "configure:2135: checking for alloca" >&5
+if eval "test \"`echo '$''{'ac_cv_func_alloca_works'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  cat > conftest.$ac_ext <<EOF
+#line 2140 "configure"
+#include "confdefs.h"
+
+#ifdef __GNUC__
+# define alloca __builtin_alloca
+#else
+# ifdef _MSC_VER
+#  include <malloc.h>
+#  define alloca _alloca
+# else
+#  if HAVE_ALLOCA_H
+#   include <alloca.h>
+#  else
+#   ifdef _AIX
+ #pragma alloca
+#   else
+#    ifndef alloca /* predefined by HP cc +Olibcalls */
+char *alloca ();
+#    endif
+#   endif
+#  endif
+# endif
+#endif
+
+int main() {
+char *p = (char *) alloca(1);
+; return 0; }
+EOF
+if { (eval echo configure:2168: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+  rm -rf conftest*
+  ac_cv_func_alloca_works=yes
+else
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -rf conftest*
+  ac_cv_func_alloca_works=no
+fi
+rm -f conftest*
+fi
+
+echo "$ac_t""$ac_cv_func_alloca_works" 1>&6
+if test $ac_cv_func_alloca_works = yes; then
+  cat >> confdefs.h <<\EOF
+#define HAVE_ALLOCA 1
+EOF
+
+fi
+
+if test $ac_cv_func_alloca_works = no; then
+  # The SVR3 libPW and SVR4 libucb both contain incompatible functions
+  # that cause trouble.  Some versions do not even contain alloca or
+  # contain a buggy version.  If you still want to use their alloca,
+  # use ar to extract alloca.o from them instead of compiling alloca.c.
+  ALLOCA=alloca.${ac_objext}
+  cat >> confdefs.h <<\EOF
+#define C_ALLOCA 1
+EOF
+
+
+echo $ac_n "checking whether alloca needs Cray hooks""... $ac_c" 1>&6
+echo "configure:2200: checking whether alloca needs Cray hooks" >&5
+if eval "test \"`echo '$''{'ac_cv_os_cray'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  cat > conftest.$ac_ext <<EOF
+#line 2205 "configure"
+#include "confdefs.h"
+#if defined(CRAY) && ! defined(CRAY2)
+webecray
+#else
+wenotbecray
+#endif
+
+EOF
+if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
+  egrep "webecray" >/dev/null 2>&1; then
+  rm -rf conftest*
+  ac_cv_os_cray=yes
+else
+  rm -rf conftest*
+  ac_cv_os_cray=no
+fi
+rm -f conftest*
+
+fi
+
+echo "$ac_t""$ac_cv_os_cray" 1>&6
+if test $ac_cv_os_cray = yes; then
+for ac_func in _getb67 GETB67 getb67; do
+  echo $ac_n "checking for $ac_func""... $ac_c" 1>&6
+echo "configure:2230: checking for $ac_func" >&5
+if eval "test \"`echo '$''{'ac_cv_func_$ac_func'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  cat > conftest.$ac_ext <<EOF
+#line 2235 "configure"
+#include "confdefs.h"
+/* System header to define __stub macros and hopefully few prototypes,
+    which can conflict with char $ac_func(); below.  */
+#include <assert.h>
+/* Override any gcc2 internal prototype to avoid an error.  */
+/* We use char because int might match the return type of a gcc2
+    builtin and then its argument prototype would still apply.  */
+char $ac_func();
+
+int main() {
+
+/* The GNU C library defines this for functions which it implements
+    to always fail with ENOSYS.  Some functions are actually named
+    something starting with __ and the normal name is an alias.  */
+#if defined (__stub_$ac_func) || defined (__stub___$ac_func)
+choke me
+#else
+$ac_func();
+#endif
+
+; return 0; }
+EOF
+if { (eval echo configure:2258: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+  rm -rf conftest*
+  eval "ac_cv_func_$ac_func=yes"
+else
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -rf conftest*
+  eval "ac_cv_func_$ac_func=no"
+fi
+rm -f conftest*
+fi
+
+if eval "test \"`echo '$ac_cv_func_'$ac_func`\" = yes"; then
+  echo "$ac_t""yes" 1>&6
+  cat >> confdefs.h <<EOF
+#define CRAY_STACKSEG_END $ac_func
+EOF
+
+  break
+else
+  echo "$ac_t""no" 1>&6
+fi
+
+done
+fi
+
+echo $ac_n "checking stack direction for C alloca""... $ac_c" 1>&6
+echo "configure:2285: checking stack direction for C alloca" >&5
+if eval "test \"`echo '$''{'ac_cv_c_stack_direction'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  if test "$cross_compiling" = yes; then
+  ac_cv_c_stack_direction=0
+else
+  cat > conftest.$ac_ext <<EOF
+#line 2293 "configure"
+#include "confdefs.h"
+find_stack_direction ()
+{
+  static char *addr = 0;
+  auto char dummy;
+  if (addr == 0)
+    {
+      addr = &dummy;
+      return find_stack_direction ();
+    }
+  else
+    return (&dummy > addr) ? 1 : -1;
+}
+main ()
+{
+  exit (find_stack_direction() < 0);
+}
+EOF
+if { (eval echo configure:2312: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext} && (./conftest; exit) 2>/dev/null
+then
+  ac_cv_c_stack_direction=1
+else
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -fr conftest*
+  ac_cv_c_stack_direction=-1
+fi
+rm -fr conftest*
+fi
+
+fi
+
+echo "$ac_t""$ac_cv_c_stack_direction" 1>&6
+cat >> confdefs.h <<EOF
+#define STACK_DIRECTION $ac_cv_c_stack_direction
+EOF
+
+fi
+
+if test $ac_cv_prog_gcc = yes; then
+    echo $ac_n "checking whether ${CC-cc} needs -traditional""... $ac_c" 1>&6
+echo "configure:2335: checking whether ${CC-cc} needs -traditional" >&5
+if eval "test \"`echo '$''{'ac_cv_prog_gcc_traditional'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+    ac_pattern="Autoconf.*'x'"
+  cat > conftest.$ac_ext <<EOF
+#line 2341 "configure"
+#include "confdefs.h"
+#include <sgtty.h>
+Autoconf TIOCGETP
+EOF
+if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
+  egrep "$ac_pattern" >/dev/null 2>&1; then
+  rm -rf conftest*
+  ac_cv_prog_gcc_traditional=yes
+else
+  rm -rf conftest*
+  ac_cv_prog_gcc_traditional=no
+fi
+rm -f conftest*
+
+
+  if test $ac_cv_prog_gcc_traditional = no; then
+    cat > conftest.$ac_ext <<EOF
+#line 2359 "configure"
+#include "confdefs.h"
+#include <termio.h>
+Autoconf TCGETA
+EOF
+if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
+  egrep "$ac_pattern" >/dev/null 2>&1; then
+  rm -rf conftest*
+  ac_cv_prog_gcc_traditional=yes
+fi
+rm -f conftest*
+
+  fi
+fi
+
+echo "$ac_t""$ac_cv_prog_gcc_traditional" 1>&6
+  if test $ac_cv_prog_gcc_traditional = yes; then
+    CC="$CC -traditional"
+  fi
+fi
+
+echo $ac_n "checking return type of signal handlers""... $ac_c" 1>&6
+echo "configure:2381: checking return type of signal handlers" >&5
+if eval "test \"`echo '$''{'ac_cv_type_signal'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  cat > conftest.$ac_ext <<EOF
+#line 2386 "configure"
+#include "confdefs.h"
+#include <sys/types.h>
+#include <signal.h>
+#ifdef signal
+#undef signal
+#endif
+#ifdef __cplusplus
+extern "C" void (*signal (int, void (*)(int)))(int);
+#else
+void (*signal ()) ();
+#endif
+
+int main() {
+int i;
+; return 0; }
+EOF
+if { (eval echo configure:2403: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
+  rm -rf conftest*
+  ac_cv_type_signal=void
+else
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -rf conftest*
+  ac_cv_type_signal=int
+fi
+rm -f conftest*
+fi
+
+echo "$ac_t""$ac_cv_type_signal" 1>&6
+cat >> confdefs.h <<EOF
+#define RETSIGTYPE $ac_cv_type_signal
+EOF
+
+
+echo $ac_n "checking for vprintf""... $ac_c" 1>&6
+echo "configure:2422: checking for vprintf" >&5
+if eval "test \"`echo '$''{'ac_cv_func_vprintf'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  cat > conftest.$ac_ext <<EOF
+#line 2427 "configure"
+#include "confdefs.h"
+/* System header to define __stub macros and hopefully few prototypes,
+    which can conflict with char vprintf(); below.  */
+#include <assert.h>
+/* Override any gcc2 internal prototype to avoid an error.  */
+/* We use char because int might match the return type of a gcc2
+    builtin and then its argument prototype would still apply.  */
+char vprintf();
+
+int main() {
+
+/* The GNU C library defines this for functions which it implements
+    to always fail with ENOSYS.  Some functions are actually named
+    something starting with __ and the normal name is an alias.  */
+#if defined (__stub_vprintf) || defined (__stub___vprintf)
+choke me
+#else
+vprintf();
+#endif
+
+; return 0; }
+EOF
+if { (eval echo configure:2450: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+  rm -rf conftest*
+  eval "ac_cv_func_vprintf=yes"
+else
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -rf conftest*
+  eval "ac_cv_func_vprintf=no"
+fi
+rm -f conftest*
+fi
+
+if eval "test \"`echo '$ac_cv_func_'vprintf`\" = yes"; then
+  echo "$ac_t""yes" 1>&6
+  cat >> confdefs.h <<\EOF
+#define HAVE_VPRINTF 1
+EOF
+
+else
+  echo "$ac_t""no" 1>&6
+fi
+
+if test "$ac_cv_func_vprintf" != yes; then
+echo $ac_n "checking for _doprnt""... $ac_c" 1>&6
+echo "configure:2474: checking for _doprnt" >&5
+if eval "test \"`echo '$''{'ac_cv_func__doprnt'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  cat > conftest.$ac_ext <<EOF
+#line 2479 "configure"
+#include "confdefs.h"
+/* System header to define __stub macros and hopefully few prototypes,
+    which can conflict with char _doprnt(); below.  */
+#include <assert.h>
+/* Override any gcc2 internal prototype to avoid an error.  */
+/* We use char because int might match the return type of a gcc2
+    builtin and then its argument prototype would still apply.  */
+char _doprnt();
+
+int main() {
+
+/* The GNU C library defines this for functions which it implements
+    to always fail with ENOSYS.  Some functions are actually named
+    something starting with __ and the normal name is an alias.  */
+#if defined (__stub__doprnt) || defined (__stub____doprnt)
+choke me
+#else
+_doprnt();
+#endif
+
+; return 0; }
+EOF
+if { (eval echo configure:2502: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+  rm -rf conftest*
+  eval "ac_cv_func__doprnt=yes"
+else
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -rf conftest*
+  eval "ac_cv_func__doprnt=no"
+fi
+rm -f conftest*
+fi
+
+if eval "test \"`echo '$ac_cv_func_'_doprnt`\" = yes"; then
+  echo "$ac_t""yes" 1>&6
+  cat >> confdefs.h <<\EOF
+#define HAVE_DOPRNT 1
+EOF
+
+else
+  echo "$ac_t""no" 1>&6
+fi
+
+fi
+
+for ac_func in ftime select strftime strtol getrusage times mallinfo setbuffer getpagesize strerror
+do
+echo $ac_n "checking for $ac_func""... $ac_c" 1>&6
+echo "configure:2529: checking for $ac_func" >&5
+if eval "test \"`echo '$''{'ac_cv_func_$ac_func'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  cat > conftest.$ac_ext <<EOF
+#line 2534 "configure"
+#include "confdefs.h"
+/* System header to define __stub macros and hopefully few prototypes,
+    which can conflict with char $ac_func(); below.  */
+#include <assert.h>
+/* Override any gcc2 internal prototype to avoid an error.  */
+/* We use char because int might match the return type of a gcc2
+    builtin and then its argument prototype would still apply.  */
+char $ac_func();
+
+int main() {
+
+/* The GNU C library defines this for functions which it implements
+    to always fail with ENOSYS.  Some functions are actually named
+    something starting with __ and the normal name is an alias.  */
+#if defined (__stub_$ac_func) || defined (__stub___$ac_func)
+choke me
+#else
+$ac_func();
+#endif
+
+; return 0; }
+EOF
+if { (eval echo configure:2557: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+  rm -rf conftest*
+  eval "ac_cv_func_$ac_func=yes"
+else
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -rf conftest*
+  eval "ac_cv_func_$ac_func=no"
+fi
+rm -f conftest*
+fi
+
+if eval "test \"`echo '$ac_cv_func_'$ac_func`\" = yes"; then
+  echo "$ac_t""yes" 1>&6
+    ac_tr_func=HAVE_`echo $ac_func | tr 'abcdefghijklmnopqrstuvwxyz' 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'`
+  cat >> confdefs.h <<EOF
+#define $ac_tr_func 1
+EOF
+ 
+else
+  echo "$ac_t""no" 1>&6
+fi
+done
+
+for ac_func in ftruncate strstr strcasecmp
+do
+echo $ac_n "checking for $ac_func""... $ac_c" 1>&6
+echo "configure:2584: checking for $ac_func" >&5
+if eval "test \"`echo '$''{'ac_cv_func_$ac_func'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  cat > conftest.$ac_ext <<EOF
+#line 2589 "configure"
+#include "confdefs.h"
+/* System header to define __stub macros and hopefully few prototypes,
+    which can conflict with char $ac_func(); below.  */
+#include <assert.h>
+/* Override any gcc2 internal prototype to avoid an error.  */
+/* We use char because int might match the return type of a gcc2
+    builtin and then its argument prototype would still apply.  */
+char $ac_func();
+
+int main() {
+
+/* The GNU C library defines this for functions which it implements
+    to always fail with ENOSYS.  Some functions are actually named
+    something starting with __ and the normal name is an alias.  */
+#if defined (__stub_$ac_func) || defined (__stub___$ac_func)
+choke me
+#else
+$ac_func();
+#endif
+
+; return 0; }
+EOF
+if { (eval echo configure:2612: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+  rm -rf conftest*
+  eval "ac_cv_func_$ac_func=yes"
+else
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -rf conftest*
+  eval "ac_cv_func_$ac_func=no"
+fi
+rm -f conftest*
+fi
+
+if eval "test \"`echo '$ac_cv_func_'$ac_func`\" = yes"; then
+  echo "$ac_t""yes" 1>&6
+    ac_tr_func=HAVE_`echo $ac_func | tr 'abcdefghijklmnopqrstuvwxyz' 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'`
+  cat >> confdefs.h <<EOF
+#define $ac_tr_func 1
+EOF
+ 
+else
+  echo "$ac_t""no" 1>&6
+LIBOBJS="$LIBOBJS ${ac_func}.${ac_objext}"
+fi
+done
+
+
+
+
+# *** Custom checking (based on GNU tar configure.in) ***
+# ---------------------------------------------------------------------------
+echo $ac_n "checking for HP-UX needing gmalloc""... $ac_c" 1>&6
+echo "configure:2643: checking for HP-UX needing gmalloc" >&5
+if test "`(uname -s) 2> /dev/null`" = 'HP-UX'; then
+  echo "$ac_t""yes" 1>&6
+  LIBOBJS="$LIBOBJS gmalloc.o"
+  cat >> confdefs.h <<\EOF
+#define HAVE_VALLOC 1
+EOF
+
+else
+  echo "$ac_t""no" 1>&6
+  for ac_func in valloc
+do
+echo $ac_n "checking for $ac_func""... $ac_c" 1>&6
+echo "configure:2656: checking for $ac_func" >&5
+if eval "test \"`echo '$''{'ac_cv_func_$ac_func'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  cat > conftest.$ac_ext <<EOF
+#line 2661 "configure"
+#include "confdefs.h"
+/* System header to define __stub macros and hopefully few prototypes,
+    which can conflict with char $ac_func(); below.  */
+#include <assert.h>
+/* Override any gcc2 internal prototype to avoid an error.  */
+/* We use char because int might match the return type of a gcc2
+    builtin and then its argument prototype would still apply.  */
+char $ac_func();
+
+int main() {
+
+/* The GNU C library defines this for functions which it implements
+    to always fail with ENOSYS.  Some functions are actually named
+    something starting with __ and the normal name is an alias.  */
+#if defined (__stub_$ac_func) || defined (__stub___$ac_func)
+choke me
+#else
+$ac_func();
+#endif
+
+; return 0; }
+EOF
+if { (eval echo configure:2684: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+  rm -rf conftest*
+  eval "ac_cv_func_$ac_func=yes"
+else
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -rf conftest*
+  eval "ac_cv_func_$ac_func=no"
+fi
+rm -f conftest*
+fi
+
+if eval "test \"`echo '$ac_cv_func_'$ac_func`\" = yes"; then
+  echo "$ac_t""yes" 1>&6
+    ac_tr_func=HAVE_`echo $ac_func | tr 'abcdefghijklmnopqrstuvwxyz' 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'`
+  cat >> confdefs.h <<EOF
+#define $ac_tr_func 1
+EOF
+ 
+else
+  echo "$ac_t""no" 1>&6
+fi
+done
+
+fi
+
+echo $ac_n "checking if malloc debugging is wanted""... $ac_c" 1>&6
+echo "configure:2711: checking if malloc debugging is wanted" >&5
+# Check whether --with-dmalloc or --without-dmalloc was given.
+if test "${with_dmalloc+set}" = set; then
+  withval="$with_dmalloc"
+  if test "$withval" = yes; then
+  echo "$ac_t""yes" 1>&6
+  cat >> confdefs.h <<\EOF
+#define WITH_DMALLOC 1
+EOF
+
+  LIBS="$LIBS -ldmalloc"
+  LDFLAGS="$LDFLAGS -g"
+else
+  echo "$ac_t""no" 1>&6
+fi
+else
+  echo "$ac_t""no" 1>&6
+fi
+
+
+echo $ac_n "checking which of rx or regex is wanted""... $ac_c" 1>&6
+echo "configure:2732: checking which of rx or regex is wanted" >&5
+# Check whether --with-regex or --without-regex was given.
+if test "${with_regex+set}" = set; then
+  withval="$with_regex"
+  if test "$withval" = yes; then
+  ac_with_regex=1
+  echo "$ac_t""regex" 1>&6
+  cat >> confdefs.h <<\EOF
+#define WITH_REGEX 1
+EOF
+
+  LIBOBJS="$LIBOBJS regex.o"
+fi
+fi
+
+if test -z "$ac_with_regex"; then
+  echo "$ac_t""rx" 1>&6
+  echo $ac_n "checking for re_rx_search""... $ac_c" 1>&6
+echo "configure:2750: checking for re_rx_search" >&5
+if eval "test \"`echo '$''{'ac_cv_func_re_rx_search'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  cat > conftest.$ac_ext <<EOF
+#line 2755 "configure"
+#include "confdefs.h"
+/* System header to define __stub macros and hopefully few prototypes,
+    which can conflict with char re_rx_search(); below.  */
+#include <assert.h>
+/* Override any gcc2 internal prototype to avoid an error.  */
+/* We use char because int might match the return type of a gcc2
+    builtin and then its argument prototype would still apply.  */
+char re_rx_search();
+
+int main() {
+
+/* The GNU C library defines this for functions which it implements
+    to always fail with ENOSYS.  Some functions are actually named
+    something starting with __ and the normal name is an alias.  */
+#if defined (__stub_re_rx_search) || defined (__stub___re_rx_search)
+choke me
+#else
+re_rx_search();
+#endif
+
+; return 0; }
+EOF
+if { (eval echo configure:2778: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+  rm -rf conftest*
+  eval "ac_cv_func_re_rx_search=yes"
+else
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -rf conftest*
+  eval "ac_cv_func_re_rx_search=no"
+fi
+rm -f conftest*
+fi
+
+if eval "test \"`echo '$ac_cv_func_'re_rx_search`\" = yes"; then
+  echo "$ac_t""yes" 1>&6
+  :
+else
+  echo "$ac_t""no" 1>&6
+echo $ac_n "checking size of unsigned char *""... $ac_c" 1>&6
+echo "configure:2796: checking size of unsigned char *" >&5
+if eval "test \"`echo '$''{'ac_cv_sizeof_unsigned_char_p'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  if test "$cross_compiling" = yes; then
+  ac_cv_sizeof_unsigned_char_p=unsigned char *
+else
+  cat > conftest.$ac_ext <<EOF
+#line 2804 "configure"
+#include "confdefs.h"
+#include <stdio.h>
+main()
+{
+  FILE *f=fopen("conftestval", "w");
+  if (!f) exit(1);
+  fprintf(f, "%d\n", sizeof(unsigned char *));
+  exit(0);
+}
+EOF
+if { (eval echo configure:2815: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext} && (./conftest; exit) 2>/dev/null
+then
+  ac_cv_sizeof_unsigned_char_p=`cat conftestval`
+else
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -fr conftest*
+  ac_cv_sizeof_unsigned_char_p=0
+fi
+rm -fr conftest*
+fi
+
+fi
+echo "$ac_t""$ac_cv_sizeof_unsigned_char_p" 1>&6
+cat >> confdefs.h <<EOF
+#define SIZEOF_UNSIGNED_CHAR_P $ac_cv_sizeof_unsigned_char_p
+EOF
+
+  
+    if test "$ac_cv_sizeof_unsigned_char_p" = 8
+    then
+      echo "configure: warning: I'm forcing you to use regex because I can't 
+        find a local rx library and the one included with this 
+        distribution doesn't work on 64-bit machines like yours" 1>&2
+      LIBOBJS="$LIBOBJS regex.o"
+    else
+      LIBOBJS="$LIBOBJS rx.o"
+    fi
+  
+fi
+
+fi
+
+echo $ac_n "checking whether GNU readline requested""... $ac_c" 1>&6
+echo "configure:2849: checking whether GNU readline requested" >&5
+  # Check whether --with-gnu_readline or --without-gnu_readline was given.
+if test "${with_gnu_readline+set}" = set; then
+  withval="$with_gnu_readline"
+  if test "$withval" = yes; then
+      echo "$ac_t""yes" 1>&6
+      ac_with_gnu_readline=1
+    else
+      echo "$ac_t""no" 1>&6
+    fi
+else
+  echo "$ac_t""no" 1>&6
+fi
+
+
+  if test -n "$ac_with_gnu_readline"; then
+    ac_safe=`echo "readline/readline.h" | sed 'y%./+-%__p_%'`
+echo $ac_n "checking for readline/readline.h""... $ac_c" 1>&6
+echo "configure:2867: checking for readline/readline.h" >&5
+if eval "test \"`echo '$''{'ac_cv_header_$ac_safe'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  cat > conftest.$ac_ext <<EOF
+#line 2872 "configure"
+#include "confdefs.h"
+#include <readline/readline.h>
+EOF
+ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out"
+{ (eval echo configure:2877: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }
+ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"`
+if test -z "$ac_err"; then
+  rm -rf conftest*
+  eval "ac_cv_header_$ac_safe=yes"
+else
+  echo "$ac_err" >&5
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -rf conftest*
+  eval "ac_cv_header_$ac_safe=no"
+fi
+rm -f conftest*
+fi
+if eval "test \"`echo '$ac_cv_header_'$ac_safe`\" = yes"; then
+  echo "$ac_t""yes" 1>&6
+  ac_mg_readline_header_found=1
+else
+  echo "$ac_t""no" 1>&6
+echo "configure: warning: Can't find GNU readline headers; configuring without \
+GNU readline support" 1>&2
+fi
+
+    if test -n "$ac_mg_readline_header_found"; then
+      # first check whether we can find the readline library itself
+      echo $ac_n "checking for main in -lreadline""... $ac_c" 1>&6
+echo "configure:2903: checking for main in -lreadline" >&5
+ac_lib_var=`echo readline'_'main | sed 'y%./+-%__p_%'`
+if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  ac_save_LIBS="$LIBS"
+LIBS="-lreadline  $LIBS"
+cat > conftest.$ac_ext <<EOF
+#line 2911 "configure"
+#include "confdefs.h"
+
+int main() {
+main()
+; return 0; }
+EOF
+if { (eval echo configure:2918: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+  rm -rf conftest*
+  eval "ac_cv_lib_$ac_lib_var=yes"
+else
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -rf conftest*
+  eval "ac_cv_lib_$ac_lib_var=no"
+fi
+rm -f conftest*
+LIBS="$ac_save_LIBS"
+
+fi
+if eval "test \"`echo '$ac_cv_lib_'$ac_lib_var`\" = yes"; then
+  echo "$ac_t""yes" 1>&6
+  ac_mg_readline_lib_found=1
+         cat >> confdefs.h <<\EOF
+#define WITH_GNU_READLINE 1
+EOF
+
+         LIBS="$LIBS -lreadline"
+else
+  echo "$ac_t""no" 1>&6
+echo "configure: warning: Can't find GNU readline library; configuring without \
+GNU readline support" 1>&2
+fi
+
+      if test -n "$ac_mg_readline_lib_found"; then
+        # on some systems, readline needs curses.  It is difficult to 
+        #  determine whether this is necessary on the current system,
+        #  since other undefined symbols can be turned up by an
+        #  AC_CHECK_LIB(readline, readline) test that are actually defined
+	#  by mg itself (e.g. xmalloc, xrealloc).  So, if we find libcurses,
+	#  we just bung it on and hope for the best.
+	echo $ac_n "checking for main in -lcurses""... $ac_c" 1>&6
+echo "configure:2953: checking for main in -lcurses" >&5
+ac_lib_var=`echo curses'_'main | sed 'y%./+-%__p_%'`
+if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  ac_save_LIBS="$LIBS"
+LIBS="-lcurses  $LIBS"
+cat > conftest.$ac_ext <<EOF
+#line 2961 "configure"
+#include "confdefs.h"
+
+int main() {
+main()
+; return 0; }
+EOF
+if { (eval echo configure:2968: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+  rm -rf conftest*
+  eval "ac_cv_lib_$ac_lib_var=yes"
+else
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -rf conftest*
+  eval "ac_cv_lib_$ac_lib_var=no"
+fi
+rm -f conftest*
+LIBS="$ac_save_LIBS"
+
+fi
+if eval "test \"`echo '$ac_cv_lib_'$ac_lib_var`\" = yes"; then
+  echo "$ac_t""yes" 1>&6
+  LIBS="$LIBS -lcurses"
+else
+  echo "$ac_t""no" 1>&6
+fi
+
+      fi
+    fi
+  fi
+
+
+# ---------------------------------------------------------------------------
+if test "$ac_cv_func_alloca" = 'no'; then
+  LIBOBJS="$LIBOBJS xmalloc.o error.o"
+fi
+
+
+# ---------------------------------------------------------------------------
+# see if the user wants to override use of long long
+# Check whether --enable-override-longlong or --disable-override-longlong was given.
+if test "${enable_override_longlong+set}" = set; then
+  enableval="$enable_override_longlong"
+  cat >> confdefs.h <<\EOF
+#define DISABLE_LONG_LONG 1
+EOF
+
+fi
+
+
+# ---------------------------------------------------------------------------
+
+trap '' 1 2 15
+cat > confcache <<\EOF
+# This file is a shell script that caches the results of configure
+# tests run on this system so they can be shared between configure
+# scripts and configure runs.  It is not useful on other systems.
+# If it contains results you don't want to keep, you may remove or edit it.
+#
+# By default, configure uses ./config.cache as the cache file,
+# creating it if it does not exist already.  You can give configure
+# the --cache-file=FILE option to use a different cache file; that is
+# what configure does when it calls configure scripts in
+# subdirectories, so they share the cache.
+# Giving --cache-file=/dev/null disables caching, for debugging configure.
+# config.status only pays attention to the cache file if you give it the
+# --recheck option to rerun configure.
+#
+EOF
+# The following way of writing the cache mishandles newlines in values,
+# but we know of no workaround that is simple, portable, and efficient.
+# So, don't put newlines in cache variables' values.
+# Ultrix sh set writes to stderr and can't be redirected directly,
+# and sets the high bit in the cache file unless we assign to the vars.
+(set) 2>&1 |
+  case `(ac_space=' '; set | grep ac_space) 2>&1` in
+  *ac_space=\ *)
+    # `set' does not quote correctly, so add quotes (double-quote substitution
+    # turns \\\\ into \\, and sed turns \\ into \).
+    sed -n \
+      -e "s/'/'\\\\''/g" \
+      -e "s/^\\([a-zA-Z0-9_]*_cv_[a-zA-Z0-9_]*\\)=\\(.*\\)/\\1=\${\\1='\\2'}/p"
+    ;;
+  *)
+    # `set' quotes correctly as required by POSIX, so do not add quotes.
+    sed -n -e 's/^\([a-zA-Z0-9_]*_cv_[a-zA-Z0-9_]*\)=\(.*\)/\1=${\1=\2}/p'
+    ;;
+  esac >> confcache
+if cmp -s $cache_file confcache; then
+  :
+else
+  if test -w $cache_file; then
+    echo "updating cache $cache_file"
+    cat confcache > $cache_file
+  else
+    echo "not updating unwritable cache $cache_file"
+  fi
+fi
+rm -f confcache
+
+trap 'rm -fr conftest* confdefs* core core.* *.core $ac_clean_files; exit 1' 1 2 15
+
+test "x$prefix" = xNONE && prefix=$ac_default_prefix
+# Let make expand exec_prefix.
+test "x$exec_prefix" = xNONE && exec_prefix='${prefix}'
+
+# Any assignment to VPATH causes Sun make to only execute
+# the first set of double-colon rules, so remove it if not needed.
+# If there is a colon in the path, we need to keep it.
+if test "x$srcdir" = x.; then
+  ac_vpsub='/^[ 	]*VPATH[ 	]*=[^:]*$/d'
+fi
+
+trap 'rm -f $CONFIG_STATUS conftest*; exit 1' 1 2 15
+
+DEFS=-DHAVE_CONFIG_H
+
+# Without the "./", some shells look in PATH for config.status.
+: ${CONFIG_STATUS=./config.status}
+
+echo creating $CONFIG_STATUS
+rm -f $CONFIG_STATUS
+cat > $CONFIG_STATUS <<EOF
+#! /bin/sh
+# Generated automatically by configure.
+# Run this file to recreate the current configuration.
+# This directory was configured as follows,
+# on host `(hostname || uname -n) 2>/dev/null | sed 1q`:
+#
+# $0 $ac_configure_args
+#
+# Compiler output produced by configure, useful for debugging
+# configure, is in ./config.log if it exists.
+
+ac_cs_usage="Usage: $CONFIG_STATUS [--recheck] [--version] [--help]"
+for ac_option
+do
+  case "\$ac_option" in
+  -recheck | --recheck | --rechec | --reche | --rech | --rec | --re | --r)
+    echo "running \${CONFIG_SHELL-/bin/sh} $0 $ac_configure_args --no-create --no-recursion"
+    exec \${CONFIG_SHELL-/bin/sh} $0 $ac_configure_args --no-create --no-recursion ;;
+  -version | --version | --versio | --versi | --vers | --ver | --ve | --v)
+    echo "$CONFIG_STATUS generated by autoconf version 2.13"
+    exit 0 ;;
+  -help | --help | --hel | --he | --h)
+    echo "\$ac_cs_usage"; exit 0 ;;
+  *) echo "\$ac_cs_usage"; exit 1 ;;
+  esac
+done
+
+ac_given_srcdir=$srcdir
+ac_given_INSTALL="$INSTALL"
+
+trap 'rm -fr `echo "Makefile text/Makefile lib/Makefile  config.h" | sed "s/:[^ ]*//g"` conftest*; exit 1' 1 2 15
+EOF
+cat >> $CONFIG_STATUS <<EOF
+
+# Protect against being on the right side of a sed subst in config.status.
+sed 's/%@/@@/; s/@%/@@/; s/%g\$/@g/; /@g\$/s/[\\\\&%]/\\\\&/g;
+ s/@@/%@/; s/@@/@%/; s/@g\$/%g/' > conftest.subs <<\\CEOF
+$ac_vpsub
+$extrasub
+s%@SHELL@%$SHELL%g
+s%@CFLAGS@%$CFLAGS%g
+s%@CPPFLAGS@%$CPPFLAGS%g
+s%@CXXFLAGS@%$CXXFLAGS%g
+s%@FFLAGS@%$FFLAGS%g
+s%@DEFS@%$DEFS%g
+s%@LDFLAGS@%$LDFLAGS%g
+s%@LIBS@%$LIBS%g
+s%@exec_prefix@%$exec_prefix%g
+s%@prefix@%$prefix%g
+s%@program_transform_name@%$program_transform_name%g
+s%@bindir@%$bindir%g
+s%@sbindir@%$sbindir%g
+s%@libexecdir@%$libexecdir%g
+s%@datadir@%$datadir%g
+s%@sysconfdir@%$sysconfdir%g
+s%@sharedstatedir@%$sharedstatedir%g
+s%@localstatedir@%$localstatedir%g
+s%@libdir@%$libdir%g
+s%@includedir@%$includedir%g
+s%@oldincludedir@%$oldincludedir%g
+s%@infodir@%$infodir%g
+s%@mandir@%$mandir%g
+s%@PACKAGE@%$PACKAGE%g
+s%@VERSION@%$VERSION%g
+s%@CXX@%$CXX%g
+s%@AWK@%$AWK%g
+s%@YACC@%$YACC%g
+s%@CC@%$CC%g
+s%@INSTALL_PROGRAM@%$INSTALL_PROGRAM%g
+s%@INSTALL_SCRIPT@%$INSTALL_SCRIPT%g
+s%@INSTALL_DATA@%$INSTALL_DATA%g
+s%@LN_S@%$LN_S%g
+s%@SET_MAKE@%$SET_MAKE%g
+s%@RANLIB@%$RANLIB%g
+s%@CPP@%$CPP%g
+s%@U@%$U%g
+s%@ANSI2KNR@%$ANSI2KNR%g
+s%@ALLOCA@%$ALLOCA%g
+s%@LIBOBJS@%$LIBOBJS%g
+
+CEOF
+EOF
+
+cat >> $CONFIG_STATUS <<\EOF
+
+# Split the substitutions into bite-sized pieces for seds with
+# small command number limits, like on Digital OSF/1 and HP-UX.
+ac_max_sed_cmds=90 # Maximum number of lines to put in a sed script.
+ac_file=1 # Number of current file.
+ac_beg=1 # First line for current file.
+ac_end=$ac_max_sed_cmds # Line after last line for current file.
+ac_more_lines=:
+ac_sed_cmds=""
+while $ac_more_lines; do
+  if test $ac_beg -gt 1; then
+    sed "1,${ac_beg}d; ${ac_end}q" conftest.subs > conftest.s$ac_file
+  else
+    sed "${ac_end}q" conftest.subs > conftest.s$ac_file
+  fi
+  if test ! -s conftest.s$ac_file; then
+    ac_more_lines=false
+    rm -f conftest.s$ac_file
+  else
+    if test -z "$ac_sed_cmds"; then
+      ac_sed_cmds="sed -f conftest.s$ac_file"
+    else
+      ac_sed_cmds="$ac_sed_cmds | sed -f conftest.s$ac_file"
+    fi
+    ac_file=`expr $ac_file + 1`
+    ac_beg=$ac_end
+    ac_end=`expr $ac_end + $ac_max_sed_cmds`
+  fi
+done
+if test -z "$ac_sed_cmds"; then
+  ac_sed_cmds=cat
+fi
+EOF
+
+cat >> $CONFIG_STATUS <<EOF
+
+CONFIG_FILES=\${CONFIG_FILES-"Makefile text/Makefile lib/Makefile "}
+EOF
+cat >> $CONFIG_STATUS <<\EOF
+for ac_file in .. $CONFIG_FILES; do if test "x$ac_file" != x..; then
+  # Support "outfile[:infile[:infile...]]", defaulting infile="outfile.in".
+  case "$ac_file" in
+  *:*) ac_file_in=`echo "$ac_file"|sed 's%[^:]*:%%'`
+       ac_file=`echo "$ac_file"|sed 's%:.*%%'` ;;
+  *) ac_file_in="${ac_file}.in" ;;
+  esac
+
+  # Adjust a relative srcdir, top_srcdir, and INSTALL for subdirectories.
+
+  # Remove last slash and all that follows it.  Not all systems have dirname.
+  ac_dir=`echo $ac_file|sed 's%/[^/][^/]*$%%'`
+  if test "$ac_dir" != "$ac_file" && test "$ac_dir" != .; then
+    # The file is in a subdirectory.
+    test ! -d "$ac_dir" && mkdir "$ac_dir"
+    ac_dir_suffix="/`echo $ac_dir|sed 's%^\./%%'`"
+    # A "../" for each directory in $ac_dir_suffix.
+    ac_dots=`echo $ac_dir_suffix|sed 's%/[^/]*%../%g'`
+  else
+    ac_dir_suffix= ac_dots=
+  fi
+
+  case "$ac_given_srcdir" in
+  .)  srcdir=.
+      if test -z "$ac_dots"; then top_srcdir=.
+      else top_srcdir=`echo $ac_dots|sed 's%/$%%'`; fi ;;
+  /*) srcdir="$ac_given_srcdir$ac_dir_suffix"; top_srcdir="$ac_given_srcdir" ;;
+  *) # Relative path.
+    srcdir="$ac_dots$ac_given_srcdir$ac_dir_suffix"
+    top_srcdir="$ac_dots$ac_given_srcdir" ;;
+  esac
+
+  case "$ac_given_INSTALL" in
+  [/$]*) INSTALL="$ac_given_INSTALL" ;;
+  *) INSTALL="$ac_dots$ac_given_INSTALL" ;;
+  esac
+
+  echo creating "$ac_file"
+  rm -f "$ac_file"
+  configure_input="Generated automatically from `echo $ac_file_in|sed 's%.*/%%'` by configure."
+  case "$ac_file" in
+  *Makefile*) ac_comsub="1i\\
+# $configure_input" ;;
+  *) ac_comsub= ;;
+  esac
+
+  ac_file_inputs=`echo $ac_file_in|sed -e "s%^%$ac_given_srcdir/%" -e "s%:% $ac_given_srcdir/%g"`
+  sed -e "$ac_comsub
+s%@configure_input@%$configure_input%g
+s%@srcdir@%$srcdir%g
+s%@top_srcdir@%$top_srcdir%g
+s%@INSTALL@%$INSTALL%g
+" $ac_file_inputs | (eval "$ac_sed_cmds") > $ac_file
+fi; done
+rm -f conftest.s*
+
+# These sed commands are passed to sed as "A NAME B NAME C VALUE D", where
+# NAME is the cpp macro being defined and VALUE is the value it is being given.
+#
+# ac_d sets the value in "#define NAME VALUE" lines.
+ac_dA='s%^\([ 	]*\)#\([ 	]*define[ 	][ 	]*\)'
+ac_dB='\([ 	][ 	]*\)[^ 	]*%\1#\2'
+ac_dC='\3'
+ac_dD='%g'
+# ac_u turns "#undef NAME" with trailing blanks into "#define NAME VALUE".
+ac_uA='s%^\([ 	]*\)#\([ 	]*\)undef\([ 	][ 	]*\)'
+ac_uB='\([ 	]\)%\1#\2define\3'
+ac_uC=' '
+ac_uD='\4%g'
+# ac_e turns "#undef NAME" without trailing blanks into "#define NAME VALUE".
+ac_eA='s%^\([ 	]*\)#\([ 	]*\)undef\([ 	][ 	]*\)'
+ac_eB='$%\1#\2define\3'
+ac_eC=' '
+ac_eD='%g'
+
+if test "${CONFIG_HEADERS+set}" != set; then
+EOF
+cat >> $CONFIG_STATUS <<EOF
+  CONFIG_HEADERS="config.h"
+EOF
+cat >> $CONFIG_STATUS <<\EOF
+fi
+for ac_file in .. $CONFIG_HEADERS; do if test "x$ac_file" != x..; then
+  # Support "outfile[:infile[:infile...]]", defaulting infile="outfile.in".
+  case "$ac_file" in
+  *:*) ac_file_in=`echo "$ac_file"|sed 's%[^:]*:%%'`
+       ac_file=`echo "$ac_file"|sed 's%:.*%%'` ;;
+  *) ac_file_in="${ac_file}.in" ;;
+  esac
+
+  echo creating $ac_file
+
+  rm -f conftest.frag conftest.in conftest.out
+  ac_file_inputs=`echo $ac_file_in|sed -e "s%^%$ac_given_srcdir/%" -e "s%:% $ac_given_srcdir/%g"`
+  cat $ac_file_inputs > conftest.in
+
+EOF
+
+# Transform confdefs.h into a sed script conftest.vals that substitutes
+# the proper values into config.h.in to produce config.h.  And first:
+# Protect against being on the right side of a sed subst in config.status.
+# Protect against being in an unquoted here document in config.status.
+rm -f conftest.vals
+cat > conftest.hdr <<\EOF
+s/[\\&%]/\\&/g
+s%[\\$`]%\\&%g
+s%#define \([A-Za-z_][A-Za-z0-9_]*\) *\(.*\)%${ac_dA}\1${ac_dB}\1${ac_dC}\2${ac_dD}%gp
+s%ac_d%ac_u%gp
+s%ac_u%ac_e%gp
+EOF
+sed -n -f conftest.hdr confdefs.h > conftest.vals
+rm -f conftest.hdr
+
+# This sed command replaces #undef with comments.  This is necessary, for
+# example, in the case of _POSIX_SOURCE, which is predefined and required
+# on some systems where configure will not decide to define it.
+cat >> conftest.vals <<\EOF
+s%^[ 	]*#[ 	]*undef[ 	][ 	]*[a-zA-Z_][a-zA-Z_0-9]*%/* & */%
+EOF
+
+# Break up conftest.vals because some shells have a limit on
+# the size of here documents, and old seds have small limits too.
+
+rm -f conftest.tail
+while :
+do
+  ac_lines=`grep -c . conftest.vals`
+  # grep -c gives empty output for an empty file on some AIX systems.
+  if test -z "$ac_lines" || test "$ac_lines" -eq 0; then break; fi
+  # Write a limited-size here document to conftest.frag.
+  echo '  cat > conftest.frag <<CEOF' >> $CONFIG_STATUS
+  sed ${ac_max_here_lines}q conftest.vals >> $CONFIG_STATUS
+  echo 'CEOF
+  sed -f conftest.frag conftest.in > conftest.out
+  rm -f conftest.in
+  mv conftest.out conftest.in
+' >> $CONFIG_STATUS
+  sed 1,${ac_max_here_lines}d conftest.vals > conftest.tail
+  rm -f conftest.vals
+  mv conftest.tail conftest.vals
+done
+rm -f conftest.vals
+
+cat >> $CONFIG_STATUS <<\EOF
+  rm -f conftest.frag conftest.h
+  echo "/* $ac_file.  Generated automatically by configure.  */" > conftest.h
+  cat conftest.in >> conftest.h
+  rm -f conftest.in
+  if cmp -s $ac_file conftest.h 2>/dev/null; then
+    echo "$ac_file is unchanged"
+    rm -f conftest.h
+  else
+    # Remove last slash and all that follows it.  Not all systems have dirname.
+      ac_dir=`echo $ac_file|sed 's%/[^/][^/]*$%%'`
+      if test "$ac_dir" != "$ac_file" && test "$ac_dir" != .; then
+      # The file is in a subdirectory.
+      test ! -d "$ac_dir" && mkdir "$ac_dir"
+    fi
+    rm -f $ac_file
+    mv conftest.h $ac_file
+  fi
+fi; done
+
+EOF
+cat >> $CONFIG_STATUS <<EOF
+
+EOF
+cat >> $CONFIG_STATUS <<\EOF
+test -z "$CONFIG_HEADERS" || echo timestamp > stamp-h
+exit 0
+EOF
+chmod +x $CONFIG_STATUS
+rm -fr confdefs* $ac_clean_files
+test "$no_create" = yes || ${CONFIG_SHELL-/bin/sh} $CONFIG_STATUS || exit 1
+
Index: /main/tags/2.25/gsdl/src/mgpp/configure.in
===================================================================
--- /main/tags/2.25/gsdl/src/mgpp/configure.in	(revision 21064)
+++ /main/tags/2.25/gsdl/src/mgpp/configure.in	(revision 21064)
@@ -0,0 +1,105 @@
+dnl Process this file with autoconf to produce a configure script.
+AC_INIT(text/MGQuery.cpp)
+AC_CONFIG_HEADER(config.h)
+AC_ARG_PROGRAM
+
+dnl
+PACKAGE=mgpp
+VERSION=1.3
+
+AC_DEFINE_UNQUOTED(PACKAGE, "$PACKAGE")
+AC_DEFINE_UNQUOTED(VERSION, "$VERSION")
+AC_SUBST(PACKAGE)
+AC_SUBST(VERSION)
+
+dnl Checks for programs.
+AC_PROG_CXX
+AC_PROG_AWK
+AC_PROG_YACC
+AC_PROG_CC
+AC_PROG_INSTALL
+AC_PROG_LN_S
+AC_PROG_MAKE_SET
+AC_PROG_RANLIB
+
+dnl Checks for typedefs, structures, and compiler characteristics.
+AC_AIX
+AC_ISC_POSIX
+AC_MINIX
+fp_C_PROTOTYPES
+AC_C_CONST
+AC_TYPE_OFF_T
+AC_TYPE_SIZE_T
+AC_HEADER_TIME
+AC_STRUCT_TM
+
+dnl --- This should be in the stdc checking -----------------
+if test "$ac_cv_prog_cc_stdc" = '-Xc'; then
+dnl The Pyramids running SMP_DC.OSx on MIPS r3000 chips with
+dnl /usr/opt/cc3.11/bin/cc treat -Xc as full ANSI mode - no POSIX or
+dnl XOPEN extensions (like popen).
+dnl Unfortunately -D_{XOPEN,POSIX}_SOURCE can't provide all that mg
+dnl needs. So drop back to -Xa
+AC_TRY_COMPILE(
+[#include <stdio.h>
+], [ FILE *rubbish = popen("yes", "r"); ],,
+[CC="`echo $CC | sed 's/-Xc/-Xa/'`"    ac_cv_prog_cc_stdc='-Xa'])
+fi
+dnl ----------------------
+
+
+dnl Checks for libraries.
+dnl Replace `main' with a function in -lm:
+AC_CHECK_LIB(m, main)
+
+dnl Checks for header files.
+AC_HEADER_DIRENT
+AC_HEADER_STDC
+AC_CHECK_HEADERS(fcntl.h limits.h sys/time.h unistd.h string.h memory.h sys/procfs.h)
+AC_EGREP_HEADER(fread, stdio.h, AC_DEFINE(HAVE_FREAD_DECL))
+AC_EGREP_HEADER(fgetc, stdio.h, AC_DEFINE(HAVE_FGETC_DECL))
+AC_EGREP_HEADER(pr_brksize, sys/procfs.h, AC_DEFINE(HAVE_PR_BRKSIZE))
+
+dnl Checks for library functions.
+AC_FUNC_ALLOCA
+AC_PROG_GCC_TRADITIONAL
+AC_TYPE_SIGNAL
+AC_FUNC_VPRINTF
+AC_CHECK_FUNCS(ftime select strftime strtol getrusage times mallinfo setbuffer getpagesize strerror)
+AC_REPLACE_FUNCS(ftruncate strstr strcasecmp)
+
+
+# *** Custom checking (based on GNU tar configure.in) ***
+# ---------------------------------------------------------------------------
+AC_MSG_CHECKING(for HP-UX needing gmalloc)
+if test "`(uname -s) 2> /dev/null`" = 'HP-UX'; then
+  AC_MSG_RESULT(yes)
+  LIBOBJS="$LIBOBJS gmalloc.o"
+  AC_DEFINE(HAVE_VALLOC)
+else
+  AC_MSG_RESULT(no)
+  AC_CHECK_FUNCS(valloc)
+fi
+
+fp_WITH_DMALLOC
+fp_WITH_REGEX
+fp_WITH_GNU_READLINE
+
+# ---------------------------------------------------------------------------
+if test "$ac_cv_func_alloca" = 'no'; then
+dnl    support functions for alloca.c
+  LIBOBJS="$LIBOBJS xmalloc.o error.o"
+fi
+
+
+# ---------------------------------------------------------------------------
+# see if the user wants to override use of long long
+AC_ARG_ENABLE(override-longlong,
+[  --enable-override-longlong
+                          overide use of long long with GCC],
+  AC_DEFINE(DISABLE_LONG_LONG))
+
+# ---------------------------------------------------------------------------
+
+AC_OUTPUT([Makefile text/Makefile lib/Makefile ], 
+[test -z "$CONFIG_HEADERS" || echo timestamp > stamp-h])
Index: /main/tags/2.25/gsdl/src/mgpp/install-sh
===================================================================
--- /main/tags/2.25/gsdl/src/mgpp/install-sh	(revision 21064)
+++ /main/tags/2.25/gsdl/src/mgpp/install-sh	(revision 21064)
@@ -0,0 +1,238 @@
+#! /bin/sh
+#
+# install - install a program, script, or datafile
+# This comes from X11R5.
+#
+# Calling this script install-sh is preferred over install.sh, to prevent
+# `make' implicit rules from creating a file called install from it
+# when there is no Makefile.
+#
+# This script is compatible with the BSD install script, but was written
+# from scratch.
+#
+
+
+# set DOITPROG to echo to test this script
+
+# Don't use :- since 4.3BSD and earlier shells don't like it.
+doit="${DOITPROG-}"
+
+
+# put in absolute paths if you don't have them in your path; or use env. vars.
+
+mvprog="${MVPROG-mv}"
+cpprog="${CPPROG-cp}"
+chmodprog="${CHMODPROG-chmod}"
+chownprog="${CHOWNPROG-chown}"
+chgrpprog="${CHGRPPROG-chgrp}"
+stripprog="${STRIPPROG-strip}"
+rmprog="${RMPROG-rm}"
+mkdirprog="${MKDIRPROG-mkdir}"
+
+tranformbasename=""
+transform_arg=""
+instcmd="$mvprog"
+chmodcmd="$chmodprog 0755"
+chowncmd=""
+chgrpcmd=""
+stripcmd=""
+rmcmd="$rmprog -f"
+mvcmd="$mvprog"
+src=""
+dst=""
+dir_arg=""
+
+while [ x"$1" != x ]; do
+    case $1 in
+	-c) instcmd="$cpprog"
+	    shift
+	    continue;;
+
+	-d) dir_arg=true
+	    shift
+	    continue;;
+
+	-m) chmodcmd="$chmodprog $2"
+	    shift
+	    shift
+	    continue;;
+
+	-o) chowncmd="$chownprog $2"
+	    shift
+	    shift
+	    continue;;
+
+	-g) chgrpcmd="$chgrpprog $2"
+	    shift
+	    shift
+	    continue;;
+
+	-s) stripcmd="$stripprog"
+	    shift
+	    continue;;
+
+	-t=*) transformarg=`echo $1 | sed 's/-t=//'`
+	    shift
+	    continue;;
+
+	-b=*) transformbasename=`echo $1 | sed 's/-b=//'`
+	    shift
+	    continue;;
+
+	*)  if [ x"$src" = x ]
+	    then
+		src=$1
+	    else
+		# this colon is to work around a 386BSD /bin/sh bug
+		:
+		dst=$1
+	    fi
+	    shift
+	    continue;;
+    esac
+done
+
+if [ x"$src" = x ]
+then
+	echo "install:	no input file specified"
+	exit 1
+else
+	true
+fi
+
+if [ x"$dir_arg" != x ]; then
+	dst=$src
+	src=""
+	
+	if [ -d $dst ]; then
+		instcmd=:
+	else
+		instcmd=mkdir
+	fi
+else
+
+# Waiting for this to be detected by the "$instcmd $src $dsttmp" command
+# might cause directories to be created, which would be especially bad 
+# if $src (and thus $dsttmp) contains '*'.
+
+	if [ -f $src -o -d $src ]
+	then
+		true
+	else
+		echo "install:  $src does not exist"
+		exit 1
+	fi
+	
+	if [ x"$dst" = x ]
+	then
+		echo "install:	no destination specified"
+		exit 1
+	else
+		true
+	fi
+
+# If destination is a directory, append the input filename; if your system
+# does not like double slashes in filenames, you may need to add some logic
+
+	if [ -d $dst ]
+	then
+		dst="$dst"/`basename $src`
+	else
+		true
+	fi
+fi
+
+## this sed command emulates the dirname command
+dstdir=`echo $dst | sed -e 's,[^/]*$,,;s,/$,,;s,^$,.,'`
+
+# Make sure that the destination directory exists.
+#  this part is taken from Noah Friedman's mkinstalldirs script
+
+# Skip lots of stat calls in the usual case.
+if [ ! -d "$dstdir" ]; then
+defaultIFS='	
+'
+IFS="${IFS-${defaultIFS}}"
+
+oIFS="${IFS}"
+# Some sh's can't handle IFS=/ for some reason.
+IFS='%'
+set - `echo ${dstdir} | sed -e 's@/@%@g' -e 's@^%@/@'`
+IFS="${oIFS}"
+
+pathcomp=''
+
+while [ $# -ne 0 ] ; do
+	pathcomp="${pathcomp}${1}"
+	shift
+
+	if [ ! -d "${pathcomp}" ] ;
+        then
+		$mkdirprog "${pathcomp}"
+	else
+		true
+	fi
+
+	pathcomp="${pathcomp}/"
+done
+fi
+
+if [ x"$dir_arg" != x ]
+then
+	$doit $instcmd $dst &&
+
+	if [ x"$chowncmd" != x ]; then $doit $chowncmd $dst; else true ; fi &&
+	if [ x"$chgrpcmd" != x ]; then $doit $chgrpcmd $dst; else true ; fi &&
+	if [ x"$stripcmd" != x ]; then $doit $stripcmd $dst; else true ; fi &&
+	if [ x"$chmodcmd" != x ]; then $doit $chmodcmd $dst; else true ; fi
+else
+
+# If we're going to rename the final executable, determine the name now.
+
+	if [ x"$transformarg" = x ] 
+	then
+		dstfile=`basename $dst`
+	else
+		dstfile=`basename $dst $transformbasename | 
+			sed $transformarg`$transformbasename
+	fi
+
+# don't allow the sed command to completely eliminate the filename
+
+	if [ x"$dstfile" = x ] 
+	then
+		dstfile=`basename $dst`
+	else
+		true
+	fi
+
+# Make a temp file name in the proper directory.
+
+	dsttmp=$dstdir/#inst.$$#
+
+# Move or copy the file name to the temp name
+
+	$doit $instcmd $src $dsttmp &&
+
+	trap "rm -f ${dsttmp}" 0 &&
+
+# and set any options; do chmod last to preserve setuid bits
+
+# If any of these fail, we abort the whole thing.  If we want to
+# ignore errors from any of these, just make sure not to ignore
+# errors from the above "$doit $instcmd $src $dsttmp" command.
+
+	if [ x"$chowncmd" != x ]; then $doit $chowncmd $dsttmp; else true;fi &&
+	if [ x"$chgrpcmd" != x ]; then $doit $chgrpcmd $dsttmp; else true;fi &&
+	if [ x"$stripcmd" != x ]; then $doit $stripcmd $dsttmp; else true;fi &&
+	if [ x"$chmodcmd" != x ]; then $doit $chmodcmd $dsttmp; else true;fi &&
+
+# Now rename the file to the real destination.
+
+	$doit $rmcmd -f $dstdir/$dstfile &&
+	$doit $mvcmd $dsttmp $dstdir/$dstfile 
+
+fi &&
+
+
+exit 0
Index: /main/tags/2.25/gsdl/src/mgpp/lib/Makefile.in
===================================================================
--- /main/tags/2.25/gsdl/src/mgpp/lib/Makefile.in	(revision 21064)
+++ /main/tags/2.25/gsdl/src/mgpp/lib/Makefile.in	(revision 21064)
@@ -0,0 +1,157 @@
+###########################################################################
+#
+# Makefile.in -- Makefile for the general purpose library
+# Copyright (C) 1994  Neil Sharman; (C) 1995 Tim Shimmin
+#
+# 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.
+#
+#       @(#)Makefile.in	1.3 16 Mar 1994
+#
+###########################################################################
+
+
+PACKAGE = @PACKAGE@
+VERSION = @VERSION@
+ 
+SHELL = /bin/sh
+srcdir = @srcdir@
+subdir = lib
+VPATH = @srcdir@
+ 
+AR = ar
+CC = @CC@
+CPP = @CXX@
+ifneq ($(NZDL), 1)
+CFLAGS = @CFLAGS@ -ansi
+else 
+CFLAGS = @CFLAGS@ -ansi -DSILENT
+endif
+CPPFLAGS = @CPPFLAGS@
+DEFS = @DEFS@
+RANLIB = @RANLIB@
+
+prefix = @prefix@
+datadir = $(prefix)/share
+localedir = $(datadir)/locale
+ 
+COMPILE = $(CC) -c $(DEFS) $(INCLUDES) $(CPPFLAGS) $(CFLAGS)
+CPPCOMPILE = $(CPP) -c $(DEFS) $(INCLUDES) $(CPPFLAGS) $(CFLAGS)
+ 
+.SUFFIXES:
+.SUFFIXES: .c .o
+.c.o:
+	$(COMPILE) $<
+
+.SUFFIXES: .cpp .o
+.cpp.o:
+	$(COMPILE) -D__cplusplus $<
+
+ANSI2KNR = @ANSI2KNR@
+o = .@U@o
+ 
+.SUFFIXES: ._c ._o
+.c._c:
+	./ansi2knr $< > $*.tmp && mv $*.tmp $@
+._c._o:
+	@echo $(COMPILE) $<
+	@rm -f _$*.c
+	@ln $< _$*.c && $(COMPILE) _$*.c && mv _$*.o $@ && rm _$*.c
+.c._o:
+	./ansi2knr $< > $*.tmp && mv $*.tmp $*._c
+	@echo $(COMPILE) $*._c
+	@rm -f _$*.c
+	@ln $*._c _$*.c && $(COMPILE) _$*.c && mv _$*.o $@ && rm _$*.c
+
+ 
+INCLUDES = -I.. -I$(srcdir)
+ 
+HEADERS = \
+    bitio_m_random.h   local_strings.h    lovinstem.h \
+    bitio_m_stdio.h    getopt.h           memlib.h           netorder.h \
+    bitio_gen.h        mgheap.h           messages.h \
+    bitio_m.h          huffman.h  \
+    bitio_m_mem.h      perf_hash.h \
+    bitio_m_mems.h      \
+    pathmax.h          getpagesize.h      sysfuncs.h         bitio_m_abstract.h  \
+    random.h           simplefrenchstem.h unitool.h	     longlong.h \
+    non_ansi.h
+
+
+SOURCES = \
+    mgheap.cpp        memlib.cpp \
+    huffman.cpp       messages.cpp \
+    bitio_gen.cpp     perf_hash.cpp \
+    getopt.cpp         \
+    getopt1.cpp       local_strings.cpp lovinstem.cpp \
+    bitio_m_mem.cpp   bitio_m_stdio.cpp bitio_m_mems.cpp \
+    alloca.c                     xmalloc.c         strstr.cpp \
+    gmalloc.c         ftruncate.cpp     strcasecmp.cpp    random.cpp \
+    simplefrenchstem.cpp                unitool.cpp       bitio_m_random.cpp \
+    bitio_m_abstract.cpp
+
+OBJECTS =  mgheap$o          memlib$o \
+    huffman$o         messages$o \
+    bitio_gen$o       perf_hash$o \
+    getopt$o           \
+    getopt1$o         local_strings$o   lovinstem$o \
+    bitio_m_mem$o     bitio_m_stdio$o   bitio_m_mems$o \
+    xmalloc$o         bitio_m_random$o  bitio_m_abstract$o \
+    gmalloc$o         random$o          simplefrenchstem$o \
+    unitool$o
+
+DISTFILES = Makefile.in $(HEADERS) $(SOURCES)
+ 
+all : libmg.a
+
+libmg.a : $(OBJECTS)
+	rm -f libmg.a
+	$(AR) cru libmg.a $(OBJECTS)
+	$(RANLIB) libmg.a
+
+$(OBJECTS): ../config.h
+
+install: 
+installdirs:
+uninstall:
+execinstall:
+execuninstall:
+maninstall:
+manuninstall:
+ 
+dist: $(DISTFILES)
+	for file in $(DISTFILES); do \
+	  ln $$file $(distdir) 2> /dev/null \
+	  || cp -p $$file $(distdir); \
+	done
+
+mostlyclean:
+	rm -f *.o *_.o
+ 
+clean: mostlyclean
+	rm -f libmg.a
+ 
+distclean: clean
+	rm -f Makefile
+ 
+maintainer-clean: distclean
+	@echo "This command is intended only for maintainers to use;"
+	@echo "rebuilding the deleted files may require special tools."
+
+Makefile: Makefile.in ../../../config.status
+	cd ../../.. && CONFIG_FILES=$(subdir)/$@ CONFIG_HEADERS= ./config.status
+ 
+# Tell versions [3.59,3.63) of GNU make not to export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:
Index: /main/tags/2.25/gsdl/src/mgpp/lib/WIN32.MAK
===================================================================
--- /main/tags/2.25/gsdl/src/mgpp/lib/WIN32.MAK	(revision 21064)
+++ /main/tags/2.25/gsdl/src/mgpp/lib/WIN32.MAK	(revision 21064)
@@ -0,0 +1,125 @@
+# Generated automatically from Makefile.in by configure.
+###########################################################################
+#
+# Makefile.in -- Makefile for the general purpose library
+# Copyright (C) 1994  Neil Sharman; (C) 1995 Tim Shimmin
+#
+# 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.
+#
+#       @(#)Makefile.in 1.3 16 Mar 1994
+#
+###########################################################################
+
+
+PACKAGE = mg
+VERSION = 1.3
+ 
+AR = lib
+CC = cl
+#CFLAGS = -g -O 
+CPPFLAGS = 
+DEFS = -DQUIET -DHAVE_CONFIG_H -D__WIN32__ -D_LITTLE_ENDIAN
+ 
+COMPILE = $(CC) -c $(DEFS) -I. -I..
+ 
+.SUFFIXES:
+.SUFFIXES: .c .obj
+.c.obj:
+	$(COMPILE) $<
+
+ANSI2KNR = 
+o = .obj
+ 
+ 
+INCLUDES = -I.. 
+ 
+HEADERS = \
+    bitio_m_random.h   local_strings.h    lovinstem.h \
+    bitio_m_stdio.h    getopt.h           memlib.h           netorder.h \
+    bitio_gen.h        mgheap.h           messages.h \
+    bitio_m.h          huffman.h  \
+    bitio_m_mem.h      perf_hash.h \
+    bitio_m_mems.h      \
+    pathmax.h          getpagesize.h      sysfuncs.h         bitio_m_abstract.h  \
+    random.h           simplefrenchstem.h unitool.h	     longlong.h \
+    non_ansi.h         win32in.h
+
+
+SOURCES = \
+    mgheap.cpp        memlib.cpp \
+    huffman.cpp       messages.cpp \
+    bitio_gen.cpp     perf_hash.cpp \
+    getopt.cpp         \
+    getopt1.cpp       local_strings.cpp lovinstem.cpp \
+    bitio_m_mem.cpp   bitio_m_stdio.cpp bitio_m_mems.cpp \
+    alloca.c                     xmalloc.c         strstr.cpp \
+    gmalloc.c         ftruncate.cpp     strcasecmp.cpp    random.cpp \
+    simplefrenchstem.cpp                unitool.cpp       bitio_m_random.cpp \
+    bitio_m_abstract.cpp         win32in.c
+
+OBJECTS =  mgheap$o          memlib$o \
+    huffman$o         messages$o \
+    bitio_gen$o       perf_hash$o \
+    getopt$o           \
+    getopt1$o         local_strings$o   lovinstem$o \
+    bitio_m_mem$o     bitio_m_stdio$o   bitio_m_mems$o \
+    xmalloc$o         bitio_m_random$o  bitio_m_abstract$o \
+    gmalloc$o         random$o          simplefrenchstem$o \
+    unitool$o         win32in$o
+
+ 
+DISTFILES = Makefile.in $(HEADERS) $(SOURCES)
+ 
+all : libmg.lib
+
+libmg.lib : $(OBJECTS)
+	del libmg.lib
+	$(AR) /out:libmg.lib $(OBJECTS)
+
+$(OBJECTS): ..\win32cfg.h
+
+install: 
+installdirs:
+uninstall:
+execinstall:
+execuninstall:
+maninstall:
+manuninstall:
+ 
+#dist: $(DISTFILES)
+#        for file in $(DISTFILES); do \
+#          ln $$file $(distdir) 2> /dev/null \
+#         || cp -p $$file $(distdir); \
+#       done
+
+mostlyclean:
+	del *.obj
+ 
+clean: mostlyclean
+	del libmg.lib
+ 
+distclean: clean
+	rm -f Makefile
+ 
+maintainer-clean: distclean
+	@echo "This command is intended only for maintainers to use;"
+	@echo "rebuilding the deleted files may require special tools."
+
+#Makefile: Makefile.in ../config.status
+#        cd .. && CONFIG_FILES=$(subdir)/$@ CONFIG_HEADERS= ./config.status
+ 
+# Tell versions [3.59,3.63) of GNU make not to export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+#.NOEXPORT:
Index: /main/tags/2.25/gsdl/src/mgpp/lib/alloca.c
===================================================================
--- /main/tags/2.25/gsdl/src/mgpp/lib/alloca.c	(revision 21064)
+++ /main/tags/2.25/gsdl/src/mgpp/lib/alloca.c	(revision 21064)
@@ -0,0 +1,496 @@
+/* alloca.c -- allocate automatically reclaimed memory
+   (Mostly) portable public-domain implementation -- D A Gwyn
+
+   This implementation of the PWB library alloca function,
+   which is used to allocate space off the run-time stack so
+   that it is automatically reclaimed upon procedure exit,
+   was inspired by discussions with J. Q. Johnson of Cornell.
+   J.Otto Tennant <jot@cray.com> contributed the Cray support.
+
+   There are some preprocessor constants that can
+   be defined when compiling for your specific system, for
+   improved efficiency; however, the defaults should be okay.
+
+   The general concept of this implementation is to keep
+   track of all alloca-allocated blocks, and reclaim any
+   that are found to be deeper in the stack than the current
+   invocation.  This heuristic does not reclaim storage as
+   soon as it becomes invalid, but it will do so eventually.
+
+   As a special case, alloca(0) reclaims storage without
+   allocating any.  It is a good idea to use alloca(0) in
+   your main control loop, etc. to force garbage collection.  */
+
+#ifdef HAVE_CONFIG_H
+# ifdef __WIN32__  /* [RPAP - Feb 97: WIN32 Port] */
+#  include <win32cfg.h>
+# else
+#  include <sysfuncs.h>
+# endif
+#endif
+
+#ifdef emacs
+#include "blockinput.h"
+#endif
+
+/* If compiling with GCC 2, this file's not needed.  */
+#if !defined (__GNUC__) || __GNUC__ < 2
+
+/* If someone has defined alloca as a macro,
+   there must be some other way alloca is supposed to work.  */
+#ifndef alloca
+
+#ifdef emacs
+#ifdef static
+/* actually, only want this if static is defined as ""
+   -- this is for usg, in which emacs must undefine static
+   in order to make unexec workable
+   */
+#ifndef STACK_DIRECTION
+you
+lose
+-- must know STACK_DIRECTION at compile-time
+#endif /* STACK_DIRECTION undefined */
+#endif /* static */
+#endif /* emacs */
+
+/* If your stack is a linked list of frames, you have to
+   provide an "address metric" ADDRESS_FUNCTION macro.  */
+
+#if defined (CRAY) && defined (CRAY_STACKSEG_END)
+long i00afunc ();
+#define ADDRESS_FUNCTION(arg) (char *) i00afunc (&(arg))
+#else
+#define ADDRESS_FUNCTION(arg) &(arg)
+#endif
+
+#if __STDC__
+typedef void *pointer;
+#else
+typedef char *pointer;
+#endif
+
+#define	NULL	0
+
+/* Different portions of Emacs need to call different versions of
+   malloc.  The Emacs executable needs alloca to call xmalloc, because
+   ordinary malloc isn't protected from input signals.  On the other
+   hand, the utilities in lib-src need alloca to call malloc; some of
+   them are very simple, and don't have an xmalloc routine.
+
+   Non-Emacs programs expect this to call use xmalloc.
+
+   Callers below should use malloc.  */
+
+#ifndef emacs
+#define malloc xmalloc
+#endif
+extern pointer malloc ();
+
+/* Define STACK_DIRECTION if you know the direction of stack
+   growth for your system; otherwise it will be automatically
+   deduced at run-time.
+
+   STACK_DIRECTION > 0 => grows toward higher addresses
+   STACK_DIRECTION < 0 => grows toward lower addresses
+   STACK_DIRECTION = 0 => direction of growth unknown  */
+
+#ifndef STACK_DIRECTION
+#define	STACK_DIRECTION	0	/* Direction unknown.  */
+#endif
+
+#if STACK_DIRECTION != 0
+
+#define	STACK_DIR	STACK_DIRECTION	/* Known at compile-time.  */
+
+#else /* STACK_DIRECTION == 0; need run-time code.  */
+
+static int stack_dir;		/* 1 or -1 once known.  */
+#define	STACK_DIR	stack_dir
+
+static void
+find_stack_direction ()
+{
+  static char *addr = NULL;	/* Address of first `dummy', once known.  */
+  auto char dummy;		/* To get stack address.  */
+
+  if (addr == NULL)
+    {				/* Initial entry.  */
+      addr = ADDRESS_FUNCTION (dummy);
+
+      find_stack_direction ();	/* Recurse once.  */
+    }
+  else
+    {
+      /* Second entry.  */
+      if (ADDRESS_FUNCTION (dummy) > addr)
+	stack_dir = 1;		/* Stack grew upward.  */
+      else
+	stack_dir = -1;		/* Stack grew downward.  */
+    }
+}
+
+#endif /* STACK_DIRECTION == 0 */
+
+/* An "alloca header" is used to:
+   (a) chain together all alloca'ed blocks;
+   (b) keep track of stack depth.
+
+   It is very important that sizeof(header) agree with malloc
+   alignment chunk size.  The following default should work okay.  */
+
+#ifndef	ALIGN_SIZE
+#define	ALIGN_SIZE	sizeof(double)
+#endif
+
+typedef union hdr
+{
+  char align[ALIGN_SIZE];	/* To force sizeof(header).  */
+  struct
+    {
+      union hdr *next;		/* For chaining headers.  */
+      char *deep;		/* For stack depth measure.  */
+    } h;
+} header;
+
+static header *last_alloca_header = NULL;	/* -> last alloca header.  */
+
+/* Return a pointer to at least SIZE bytes of storage,
+   which will be automatically reclaimed upon exit from
+   the procedure that called alloca.  Originally, this space
+   was supposed to be taken from the current stack frame of the
+   caller, but that method cannot be made to work for some
+   implementations of C, for example under Gould's UTX/32.  */
+
+pointer
+alloca (size)
+     unsigned size;
+{
+  auto char probe;		/* Probes stack depth: */
+  register char *depth = ADDRESS_FUNCTION (probe);
+
+#if STACK_DIRECTION == 0
+  if (STACK_DIR == 0)		/* Unknown growth direction.  */
+    find_stack_direction ();
+#endif
+
+  /* Reclaim garbage, defined as all alloca'd storage that
+     was allocated from deeper in the stack than currently. */
+
+  {
+    register header *hp;	/* Traverses linked list.  */
+
+#ifdef emacs
+    BLOCK_INPUT;
+#endif
+
+    for (hp = last_alloca_header; hp != NULL;)
+      if ((STACK_DIR > 0 && hp->h.deep > depth)
+	  || (STACK_DIR < 0 && hp->h.deep < depth))
+	{
+	  register header *np = hp->h.next;
+
+	  free ((pointer) hp);	/* Collect garbage.  */
+
+	  hp = np;		/* -> next header.  */
+	}
+      else
+	break;			/* Rest are not deeper.  */
+
+    last_alloca_header = hp;	/* -> last valid storage.  */
+
+#ifdef emacs
+    UNBLOCK_INPUT;
+#endif
+  }
+
+  if (size == 0)
+    return NULL;		/* No allocation required.  */
+
+  /* Allocate combined header + user data storage.  */
+
+  {
+    register pointer new = malloc (sizeof (header) + size);
+    /* Address of header.  */
+
+    ((header *) new)->h.next = last_alloca_header;
+    ((header *) new)->h.deep = depth;
+
+    last_alloca_header = (header *) new;
+
+    /* User storage begins just after header.  */
+
+    return (pointer) ((char *) new + sizeof (header));
+  }
+}
+
+#if defined (CRAY) && defined (CRAY_STACKSEG_END)
+
+#ifdef DEBUG_I00AFUNC
+#include <stdio.h>
+#endif
+
+#ifndef CRAY_STACK
+#define CRAY_STACK
+#ifndef CRAY2
+/* Stack structures for CRAY-1, CRAY X-MP, and CRAY Y-MP */
+struct stack_control_header
+  {
+    long shgrow:32;		/* Number of times stack has grown.  */
+    long shaseg:32;		/* Size of increments to stack.  */
+    long shhwm:32;		/* High water mark of stack.  */
+    long shsize:32;		/* Current size of stack (all segments).  */
+  };
+
+/* The stack segment linkage control information occurs at
+   the high-address end of a stack segment.  (The stack
+   grows from low addresses to high addresses.)  The initial
+   part of the stack segment linkage control information is
+   0200 (octal) words.  This provides for register storage
+   for the routine which overflows the stack.  */
+
+struct stack_segment_linkage
+  {
+    long ss[0200];		/* 0200 overflow words.  */
+    long sssize:32;		/* Number of words in this segment.  */
+    long ssbase:32;		/* Offset to stack base.  */
+    long:32;
+    long sspseg:32;		/* Offset to linkage control of previous
+				   segment of stack.  */
+    long:32;
+    long sstcpt:32;		/* Pointer to task common address block.  */
+    long sscsnm;		/* Private control structure number for
+				   microtasking.  */
+    long ssusr1;		/* Reserved for user.  */
+    long ssusr2;		/* Reserved for user.  */
+    long sstpid;		/* Process ID for pid based multi-tasking.  */
+    long ssgvup;		/* Pointer to multitasking thread giveup.  */
+    long sscray[7];		/* Reserved for Cray Research.  */
+    long ssa0;
+    long ssa1;
+    long ssa2;
+    long ssa3;
+    long ssa4;
+    long ssa5;
+    long ssa6;
+    long ssa7;
+    long sss0;
+    long sss1;
+    long sss2;
+    long sss3;
+    long sss4;
+    long sss5;
+    long sss6;
+    long sss7;
+  };
+
+#else /* CRAY2 */
+/* The following structure defines the vector of words
+   returned by the STKSTAT library routine.  */
+struct stk_stat
+  {
+    long now;			/* Current total stack size.  */
+    long maxc;			/* Amount of contiguous space which would
+				   be required to satisfy the maximum
+				   stack demand to date.  */
+    long high_water;		/* Stack high-water mark.  */
+    long overflows;		/* Number of stack overflow ($STKOFEN) calls.  */
+    long hits;			/* Number of internal buffer hits.  */
+    long extends;		/* Number of block extensions.  */
+    long stko_mallocs;		/* Block allocations by $STKOFEN.  */
+    long underflows;		/* Number of stack underflow calls ($STKRETN).  */
+    long stko_free;		/* Number of deallocations by $STKRETN.  */
+    long stkm_free;		/* Number of deallocations by $STKMRET.  */
+    long segments;		/* Current number of stack segments.  */
+    long maxs;			/* Maximum number of stack segments so far.  */
+    long pad_size;		/* Stack pad size.  */
+    long current_address;	/* Current stack segment address.  */
+    long current_size;		/* Current stack segment size.  This
+				   number is actually corrupted by STKSTAT to
+				   include the fifteen word trailer area.  */
+    long initial_address;	/* Address of initial segment.  */
+    long initial_size;		/* Size of initial segment.  */
+  };
+
+/* The following structure describes the data structure which trails
+   any stack segment.  I think that the description in 'asdef' is
+   out of date.  I only describe the parts that I am sure about.  */
+
+struct stk_trailer
+  {
+    long this_address;		/* Address of this block.  */
+    long this_size;		/* Size of this block (does not include
+				   this trailer).  */
+    long unknown2;
+    long unknown3;
+    long link;			/* Address of trailer block of previous
+				   segment.  */
+    long unknown5;
+    long unknown6;
+    long unknown7;
+    long unknown8;
+    long unknown9;
+    long unknown10;
+    long unknown11;
+    long unknown12;
+    long unknown13;
+    long unknown14;
+  };
+
+#endif /* CRAY2 */
+#endif /* not CRAY_STACK */
+
+#ifdef CRAY2
+/* Determine a "stack measure" for an arbitrary ADDRESS.
+   I doubt that "lint" will like this much. */
+
+static long
+i00afunc (long *address)
+{
+  struct stk_stat status;
+  struct stk_trailer *trailer;
+  long *block, size;
+  long result = 0;
+
+  /* We want to iterate through all of the segments.  The first
+     step is to get the stack status structure.  We could do this
+     more quickly and more directly, perhaps, by referencing the
+     $LM00 common block, but I know that this works.  */
+
+  STKSTAT (&status);
+
+  /* Set up the iteration.  */
+
+  trailer = (struct stk_trailer *) (status.current_address
+				    + status.current_size
+				    - 15);
+
+  /* There must be at least one stack segment.  Therefore it is
+     a fatal error if "trailer" is null.  */
+
+  if (trailer == 0)
+    abort ();
+
+  /* Discard segments that do not contain our argument address.  */
+
+  while (trailer != 0)
+    {
+      block = (long *) trailer->this_address;
+      size = trailer->this_size;
+      if (block == 0 || size == 0)
+	abort ();
+      trailer = (struct stk_trailer *) trailer->link;
+      if ((block <= address) && (address < (block + size)))
+	break;
+    }
+
+  /* Set the result to the offset in this segment and add the sizes
+     of all predecessor segments.  */
+
+  result = address - block;
+
+  if (trailer == 0)
+    {
+      return result;
+    }
+
+  do
+    {
+      if (trailer->this_size <= 0)
+	abort ();
+      result += trailer->this_size;
+      trailer = (struct stk_trailer *) trailer->link;
+    }
+  while (trailer != 0);
+
+  /* We are done.  Note that if you present a bogus address (one
+     not in any segment), you will get a different number back, formed
+     from subtracting the address of the first block.  This is probably
+     not what you want.  */
+
+  return (result);
+}
+
+#else /* not CRAY2 */
+/* Stack address function for a CRAY-1, CRAY X-MP, or CRAY Y-MP.
+   Determine the number of the cell within the stack,
+   given the address of the cell.  The purpose of this
+   routine is to linearize, in some sense, stack addresses
+   for alloca.  */
+
+static long
+i00afunc (long address)
+{
+  long stkl = 0;
+
+  long size, pseg, this_segment, stack;
+  long result = 0;
+
+  struct stack_segment_linkage *ssptr;
+
+  /* Register B67 contains the address of the end of the
+     current stack segment.  If you (as a subprogram) store
+     your registers on the stack and find that you are past
+     the contents of B67, you have overflowed the segment.
+
+     B67 also points to the stack segment linkage control
+     area, which is what we are really interested in.  */
+
+  stkl = CRAY_STACKSEG_END ();
+  ssptr = (struct stack_segment_linkage *) stkl;
+
+  /* If one subtracts 'size' from the end of the segment,
+     one has the address of the first word of the segment.
+
+     If this is not the first segment, 'pseg' will be
+     nonzero.  */
+
+  pseg = ssptr->sspseg;
+  size = ssptr->sssize;
+
+  this_segment = stkl - size;
+
+  /* It is possible that calling this routine itself caused
+     a stack overflow.  Discard stack segments which do not
+     contain the target address.  */
+
+  while (!(this_segment <= address && address <= stkl))
+    {
+#ifdef DEBUG_I00AFUNC
+      fprintf (stderr, "%011o %011o %011o\n", this_segment, address, stkl);
+#endif
+      if (pseg == 0)
+	break;
+      stkl = stkl - pseg;
+      ssptr = (struct stack_segment_linkage *) stkl;
+      size = ssptr->sssize;
+      pseg = ssptr->sspseg;
+      this_segment = stkl - size;
+    }
+
+  result = address - this_segment;
+
+  /* If you subtract pseg from the current end of the stack,
+     you get the address of the previous stack segment's end.
+     This seems a little convoluted to me, but I'll bet you save
+     a cycle somewhere.  */
+
+  while (pseg != 0)
+    {
+#ifdef DEBUG_I00AFUNC
+      fprintf (stderr, "%011o %011o\n", pseg, size);
+#endif
+      stkl = stkl - pseg;
+      ssptr = (struct stack_segment_linkage *) stkl;
+      size = ssptr->sssize;
+      pseg = ssptr->sspseg;
+      result += size;
+    }
+  return (result);
+}
+
+#endif /* not CRAY2 */
+#endif /* CRAY */
+
+#endif /* no alloca */
+#endif /* not GCC version 2 */
Index: /main/tags/2.25/gsdl/src/mgpp/lib/bitio_gen.cpp
===================================================================
--- /main/tags/2.25/gsdl/src/mgpp/lib/bitio_gen.cpp	(revision 21064)
+++ /main/tags/2.25/gsdl/src/mgpp/lib/bitio_gen.cpp	(revision 21064)
@@ -0,0 +1,160 @@
+/**************************************************************************
+ *
+ * bitio_gen.c -- General supoport routines for bitio
+ * Copyright (C) 1994  Neil Sharman and Alistair Moffat
+ *
+ * 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.
+ *
+ * $Id$
+ *
+ **************************************************************************/
+
+/*
+   $Log$
+   Revision 1.1  2000/01/14 02:16:58  sjboddie
+   Rodgers new C++ mg
+
+   Revision 1.1  1999/10/11 02:54:54  cs025
+   Base install of MG-PP
+
+   Revision 1.1  1999/08/10 21:16:42  sjboddie
+   renamed mg-1.3d directory mg
+
+   Revision 1.1  1998/11/17 09:31:40  rjmcnab
+   *** empty log message ***
+
+   * Revision 1.1  1994/08/22  00:24:38  tes
+   * Initial placement under CVS.
+   *
+ */
+
+static char *RCSID = "$Id$";
+
+#include "sysfuncs.h"
+#include "bitio_m_abstract.h"
+
+
+
+
+int fprintf (FILE *, const char *,...);
+
+unsigned long 
+BIO_Unary_Length (unsigned long val)
+{
+  register unsigned long num;
+  num = bitio_buffer::unary_length(val);
+  //  UNARY_LENGTH (val, num);
+  return (num);
+}
+
+
+unsigned long 
+BIO_Binary_Length (unsigned long val, unsigned long b)
+{
+  register unsigned long num;
+  num = bitio_buffer::binary_length (val, b);
+  return (num);
+}
+
+
+unsigned long BIO_Gamma_Length (unsigned long val) {
+  register unsigned long num;
+  num = bitio_buffer::gamma_length(val);
+  return (num);
+}
+
+
+unsigned long 
+BIO_Delta_Length (unsigned long val)
+{
+  register unsigned long num;
+  num = bitio_buffer::delta_length(val);
+  return (num);
+}
+
+
+unsigned long 
+BIO_Elias_Length (unsigned long val, unsigned long b, double s)
+{
+  register unsigned long num;
+  num = bitio_buffer::elias_length(val, b, s);
+  return (num);
+}
+
+unsigned long 
+BIO_Bblock_Length (unsigned long val, unsigned long b)
+{
+  register unsigned long num;
+  num = bitio_buffer::bblock_length (val, b);
+  return (num);
+}
+
+
+int 
+BIO_Bblock_Init (int N, int p)
+{
+  int b;
+  b = (int) (0.5 + 0.6931471 * N / p);
+  return (b ? b : 1);
+}
+
+
+int 
+BIO_Bblock_Init_W (int N, int p)
+{
+  int logb;
+  logb = bitio_buffer::floor_log2 ((N - p) / p);
+  return (logb < 0 ? 1 : (1 << logb));
+}
+
+int 
+BIO_Bblock_Bound_b (int N, int p, int b)
+{
+  int clogb;
+  clogb = bitio_buffer::ceil_log2 (b);
+  return (p * (1 + clogb) + (N - p * ((1 << clogb) - b + 1)) / b);
+}
+
+int 
+BIO_Bblock_Bound (int N, int p)
+{
+  int b;
+  b = BIO_Bblock_Init_W (N, p);
+  return (BIO_Bblock_Bound_b (N, p, b));
+}
+
+/* adjustment is a hack to overcome inaccuracies in floating point,
+   where (int)(ln4/ln2) can equal 1, not 2. */
+int 
+BIO_Gamma_Bound (int N, int p)
+{
+  return ((int) (p * (2 * log2 (((double) N * 1.0001) / p) + 1)));
+}
+
+int 
+floorlog_2 (int b)
+{
+  int logb;
+  logb = bitio_buffer::floor_log2 (b);
+  return logb;
+}
+
+int 
+ceillog_2 (int b)
+{
+  int logb;
+  logb = bitio_buffer::ceil_log2 (b);
+  return logb;
+}
Index: /main/tags/2.25/gsdl/src/mgpp/lib/bitio_gen.h
===================================================================
--- /main/tags/2.25/gsdl/src/mgpp/lib/bitio_gen.h	(revision 21064)
+++ /main/tags/2.25/gsdl/src/mgpp/lib/bitio_gen.h	(revision 21064)
@@ -0,0 +1,63 @@
+/**************************************************************************
+ *
+ * bitio_gen.h -- General supoport routines for bitio
+ * Copyright (C) 1994  Neil Sharman and Alistair Moffat
+ *
+ * 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.
+ *
+ * $Id$
+ *
+ **************************************************************************
+ *
+ *  This file contains function definitions for doing general bitio operations.
+ *
+ *  This file defines functions for calculation the length in bits of a number
+ *  coded unary, binary, delta, gamma, elias, and  bblock coding. It defines 
+ *  routines for calculating the parameter and bounds for bblock coding. 
+ *  Routines for calculating ceil and floor lg are also defined.
+ *
+ *
+ **************************************************************************/
+
+#ifndef H_BITIO_GEN
+#define H_BITIO_GEN
+
+unsigned long BIO_Unary_Length (unsigned long val);
+
+unsigned long BIO_Binary_Length (unsigned long val, unsigned long b);
+
+unsigned long BIO_Gamma_Length (unsigned long val);
+
+unsigned long BIO_Delta_Length (unsigned long val);
+
+unsigned long BIO_Elias_Length (unsigned long val, unsigned long b, double s);
+
+unsigned long BIO_Bblock_Length (unsigned long val, unsigned long b);
+
+int BIO_Bblock_Init (int N, int p);
+
+int BIO_Bblock_Init_W (int N, int p);
+
+int BIO_Bblock_Bound_b (int N, int p, int b);
+
+int BIO_Bblock_Bound (int N, int p);
+
+int BIO_Gamma_Bound (int N, int p);
+
+int floorlog_2 (int b);
+
+int ceillog_2 (int b);
+
+#endif
Index: /main/tags/2.25/gsdl/src/mgpp/lib/bitio_m_abstract.cpp
===================================================================
--- /main/tags/2.25/gsdl/src/mgpp/lib/bitio_m_abstract.cpp	(revision 21064)
+++ /main/tags/2.25/gsdl/src/mgpp/lib/bitio_m_abstract.cpp	(revision 21064)
@@ -0,0 +1,9 @@
+#include <stdlib.h>
+#include <stdio.h>
+
+#include "bitio_m_abstract.h"
+
+
+
+
+
Index: /main/tags/2.25/gsdl/src/mgpp/lib/bitio_m_abstract.h
===================================================================
--- /main/tags/2.25/gsdl/src/mgpp/lib/bitio_m_abstract.h	(revision 21064)
+++ /main/tags/2.25/gsdl/src/mgpp/lib/bitio_m_abstract.h	(revision 21064)
@@ -0,0 +1,340 @@
+#ifndef H_BITIO_ABSTRACT
+#define H_BITIO_ABSTRACT
+
+class bitio_buffer {
+public:
+  virtual int bit() = 0;
+  virtual void encodeBit(int bit) = 0;
+  virtual void seek(unsigned long topos) = 0;
+  
+  static inline void check_positive(char *type, unsigned long x) {
+    if (x <= 0) {
+      fprintf(stderr, "Error: Cannot %s encode %lu\n", type, x);
+      exit(1);
+    }
+  }
+
+  static inline int floor_log2(unsigned long x) {
+    unsigned long  _B_x = x;
+    int reply;
+    
+    reply = -1;
+    while (_B_x != 0) {
+      _B_x >>= 1;
+      reply ++;
+    }
+    return reply;
+  }
+  
+  static inline int ceil_log2(unsigned long x) {
+    register int _B_x;
+    unsigned long reply;
+    
+    _B_x = x - 1;
+    reply = 0;
+    while (_B_x != 0) {
+      _B_x >>= 1;
+      reply ++;
+    }
+    return reply;
+  }
+
+  inline unsigned long unary_decode(unsigned long *count) {
+    unsigned long x;
+    
+    x = 1;
+    while (!this->bit()) x++;
+    if (count != NULL) {
+      *count += x;
+    }
+    return x;
+  }
+
+  inline void unary_encode(unsigned long x, unsigned long *count) {
+    register unsigned long _B_x = x;
+    check_positive("unary", _B_x);
+    if (count != NULL) {
+      *count += _B_x;
+    }
+    while(--_B_x) 
+      encodeBit(0);
+    encodeBit(1);
+  }
+
+
+  inline unsigned long binary_decode(unsigned long b, unsigned long *count) {
+    register unsigned long _B_x = 0;
+    register unsigned long _B_b = b;
+    register int _B_i, _B_logofb, _B_thresh;
+    register unsigned long reply;
+    
+    if (_B_b != 1) {					
+      _B_logofb = ceil_log2(_B_b);
+      _B_thresh = (1<<_B_logofb) - _B_b;
+      _B_logofb--;
+      
+      if (count != NULL) {
+	*count += _B_logofb;
+      }
+      
+      for (_B_i=0; _B_i < _B_logofb; _B_i++) {
+	_B_x += _B_x + this->bit();
+      }
+
+      if ((int)_B_x >= _B_thresh) {
+	_B_x += _B_x + this->bit();
+	_B_x -= _B_thresh;
+	if (count != NULL) {
+	  *count = *count + 1;
+	}
+      }
+      reply = _B_x+1;
+      
+    } else reply = 1;
+    
+    return reply;
+  }
+
+  inline void binary_encode(unsigned long x, unsigned long b, unsigned long *count) {
+    register unsigned long _B_x = (x);
+    register unsigned long _B_b = (b);
+    register int _B_nbits, _B_logofb, _B_thresh;
+    
+    check_positive("binary", _B_x);
+    _B_logofb = ceil_log2(_B_b);
+    
+    _B_thresh = (1<<_B_logofb) - _B_b;
+    if ((int)(--_B_x) < _B_thresh) _B_nbits = _B_logofb-1;
+    else {
+      _B_nbits = _B_logofb;
+      _B_x += _B_thresh;
+    }
+    if (count != NULL) {
+      *count += _B_nbits;
+    }
+    while (--_B_nbits>=0)
+      encodeBit((_B_x>>_B_nbits) & 0x1);
+  }
+
+  inline unsigned long bblock_decode(unsigned long b, unsigned long *count) {
+    register unsigned long _B_x1, _B_xx = 0;
+    register unsigned long _B_bb = (b);
+    register int _B_xdivb;
+    
+    _B_xdivb = this->unary_decode(count);
+    _B_xdivb--;				       
+    while (_B_xdivb--) {
+      _B_xx += _B_bb;
+    }
+    _B_x1 = this->binary_decode(_B_bb, count);
+    return (_B_xx + _B_x1);
+  }
+  
+  inline void bblock_encode(unsigned long x, unsigned long b, unsigned long *count) {
+    register unsigned long _B_xx = (x);
+    register unsigned long _B_bb = (b);
+    register int _B_xdivb = 0;
+    check_positive("bblock", _B_xx);
+    _B_xx--;
+    while (_B_xx >= _B_bb) {
+      _B_xdivb++;
+      _B_xx -= _B_bb;
+    }
+    unary_encode(_B_xdivb+1, count);
+    binary_encode(_B_xx+1, _B_bb, count);
+  }
+
+  inline unsigned long elias_decode(unsigned long b, double s, unsigned long *count) {
+    register unsigned long _B_xx;
+    register unsigned long _B_b = b;
+    register double _B_s = s;
+    register int _B_lower=1, _B_upper=1;
+    register int _B_k;
+    register double _B_pow=1.0;
+    
+    _B_k = this->unary_decode(count);
+    _B_k--;
+    while (_B_k--) {
+      _B_lower = _B_upper+1;
+      _B_pow *= _B_s;
+      _B_upper += (int) (_B_b*_B_pow);
+    }
+    _B_xx = this->binary_decode(_B_upper-_B_lower+1, count);
+    _B_xx--;
+    check_positive("gamma", _B_xx+_B_lower);
+    return _B_xx+_B_lower;
+  }
+  
+  inline void elias_encode(unsigned long x, unsigned long b, double s, unsigned long *count) {
+    register unsigned long _B_xx = x;
+    register unsigned long _B_b = b;
+    register double _B_s = s;
+    register int _B_lower=1, _B_upper=1;
+    register int _B_k=0;
+    register double _B_pow=1.0;
+    
+    check_positive("elias", _B_xx);
+    
+    while ((int)_B_xx>_B_upper) {
+      _B_k++;
+      _B_lower = _B_upper+1;
+      _B_pow *= _B_s;
+      _B_upper += (int) (_B_b*_B_pow);
+    }
+    unary_encode(_B_k+1, count);
+    binary_encode(_B_xx-_B_lower+1, _B_upper-_B_lower+1, count);
+  }
+  
+  inline unsigned long gamma_decode(unsigned long *count) {
+    register unsigned long _B_xx = 1;
+    register int _B_nbits = 0;
+    
+    while(!this->bit()) _B_nbits++;
+    if (count != NULL) {
+      *count += _B_nbits*2+1;
+    }
+    while (_B_nbits-- > 0)
+      _B_xx += _B_xx + this->bit();
+    return _B_xx;
+  }
+
+  inline void gamma_encode(unsigned long x, unsigned long *count) {
+    register unsigned long _B_xx = x;
+    register int _B_logofb;
+    register int _B_nbits;
+    
+    check_positive("gamma", _B_xx);
+    _B_logofb = floor_log2(_B_xx);
+    _B_nbits = _B_logofb+1;
+    
+    if (count != NULL) { 
+      *count += _B_logofb*2+1;
+    }
+    while(_B_logofb--) encodeBit(0);
+    while (--_B_nbits>=0) encodeBit((_B_xx>>_B_nbits) & 0x1);
+  }
+  
+  inline unsigned long delta_decode(unsigned long *count) {
+    register unsigned long _B_xxx;
+    register int _B_logx;
+    _B_logx = gamma_decode(count);
+    _B_logx--;
+    _B_xxx = binary_decode(1<<_B_logx, count); 
+    _B_xxx--;
+    return (_B_xxx + (1<<_B_logx));
+  }
+
+  inline void delta_encode(unsigned long x, unsigned long *count) {
+    register unsigned long _B_xxx = x;
+    register int _B_logx;
+    _B_logx = floor_log2(_B_xxx);
+    gamma_encode(_B_logx+1, count);
+    binary_encode(_B_xxx+1, 1<<_B_logx, count);
+  }
+
+  inline unsigned long huff_decode(unsigned long *mcodes, unsigned long **values,
+				   unsigned long *count = NULL) {
+    register unsigned long *__min_code = mcodes;
+    register unsigned long *__mclen    = mcodes;
+    register unsigned long **__values  = values;
+    register unsigned long __code = 0;
+    do {
+      __code += __code + bit();
+      if (count != NULL) (*count) ++;
+    } while (__code < *++__mclen);
+    
+    return __values[__mclen - __min_code][__code - *__mclen];
+  }
+
+  inline void huff_encode(unsigned long x, unsigned long *codes, char *lens,
+			  unsigned long *count = NULL) {
+    register int __i;
+    register int __clen = lens[x];
+    register unsigned long __code = codes[x];
+    for (__i=__clen-1; __i>=0; __i--) {
+      encodeBit((__code >> __i) & 1);
+    }
+    if (count != NULL) {
+      *count += lens[x];
+    }
+  }
+
+  static inline unsigned long unary_length(unsigned long x) {
+    check_positive("unary", x);
+    return x;
+  }
+
+  static inline int binary_length(unsigned long x, unsigned long b) {
+    register unsigned long _B_x = (x);
+    register unsigned long _B_b = (b);
+    register int _B_nbits, _B_logofb, _B_thresh;
+    
+    check_positive("binary", _B_x);
+    _B_logofb = ceil_log2(_B_b);
+    _B_thresh = (1<<_B_logofb) - _B_b;
+    if ((int)(--_B_x) < _B_thresh) _B_nbits = _B_logofb-1;
+    else _B_nbits = _B_logofb;
+    return _B_nbits;
+  }
+
+  static inline unsigned long bblock_length(unsigned long x, unsigned long b) {
+    register unsigned long _B_bcount, count, _B_xx = (x);
+    register unsigned long _B_bb = (b);
+    register int _B_xdivb = 0;
+    
+    check_positive("bblock", _B_xx);
+    _B_xx--;
+    while (_B_xx >= _B_bb) {
+      _B_xdivb++;
+      _B_xx -= _B_bb;
+    }
+    count = unary_length(_B_xdivb+1);
+    _B_bcount = binary_length(_B_xx+1, _B_bb);
+    count += _B_bcount;
+    return count;
+  }
+  
+  static inline unsigned long elias_length(unsigned long x, unsigned long b, 
+					   double s) {
+    register unsigned long _B_xx = x;
+    register unsigned long _B_b = b;
+    register double _B_s = s;
+    register int _B_lower=1, _B_upper=1;
+    register int _B_k=0, _B_ecount;
+    register double _B_pow=1.0;
+    register unsigned long count;
+    check_positive("gamma", _B_xx);
+    
+    while ((int)(_B_xx)>_B_upper) {
+      _B_k++;
+      _B_lower = _B_upper+1;
+      _B_pow *= _B_s;
+      _B_upper += (int) (_B_b*_B_pow);
+    }
+    count = unary_length(_B_k+1);
+    _B_ecount = binary_length(_B_xx-_B_lower+1, _B_upper-_B_lower+1);
+    count += _B_ecount;
+    return count;
+  }
+  
+  static inline unsigned long gamma_length(unsigned long x) {
+    register unsigned long _B_xx = x;
+    register int _B_logofb;
+    check_positive("gamma", _B_xx);
+    _B_logofb = floor_log2(_B_xx);
+    return _B_logofb*2+1;
+  }
+
+  static inline unsigned long delta_length(unsigned long x) {
+    register unsigned long _B_xxx = x;
+    register int _B_logx, _B_dcount;
+    register unsigned long count;
+    _B_logx = floor_log2 (_B_xxx);
+    count = gamma_length(_B_logx+1);
+    _B_dcount = binary_length (_B_xxx+1, 1<<_B_logx);
+    count += _B_dcount;
+    return count;
+  }
+};
+
+#endif
Index: /main/tags/2.25/gsdl/src/mgpp/lib/bitio_m_mem.cpp
===================================================================
--- /main/tags/2.25/gsdl/src/mgpp/lib/bitio_m_mem.cpp	(revision 21064)
+++ /main/tags/2.25/gsdl/src/mgpp/lib/bitio_m_mem.cpp	(revision 21064)
@@ -0,0 +1,128 @@
+#include <stdlib.h>
+#include <stdio.h>
+
+#include "bitio_m_abstract.h"
+#include "bitio_m_mem.h"
+
+mem_bitio_buffer::mem_bitio_buffer() {
+}
+
+mem_bitio_buffer::mem_bitio_buffer(unsigned char *readbuffer, int size) { 
+  pos       = readbuffer;
+  base      = readbuffer;
+  remaining = size;
+  buffer    = 0;
+  btg       = 0;
+}
+
+
+void mem_bitio_buffer::error() {
+  fprintf (stderr, "Unexpected EOF in \"%s\" on line %d\n", __FILE__, __LINE__);
+  exit(1);
+}
+
+void mem_bitio_buffer::encodeStart() {
+  btg = sizeof(buffer) * 8;
+}
+
+
+void mem_bitio_buffer::seek(unsigned long toPos) { 
+  register long _newPos;
+  do {
+    _newPos = toPos;
+    
+    pos    = base + (_newPos >> 3);
+    buffer = *pos++;
+    btg    = 8 - (_newPos & 0x07);
+  } while (0);
+}
+
+long mem_bitio_buffer::addff(long b) {
+  do {
+    if (btg == 0) {
+      if (remaining != 0) {
+	buffer = *pos++;
+	remaining --;
+      } else {
+	buffer = 0xff;
+      }
+      btg = sizeof(buffer) * 8;
+    }
+    b = b + b + ((buffer >> --btg) & 1);
+  } while(0);
+
+  return b;
+}
+
+long mem_bitio_buffer::add00(long b) {
+  do {
+    if (btg == 0) {
+      if (remaining != 0) {
+	buffer = *pos++;
+	remaining --;
+      } else {
+	buffer = 0x00;
+      }
+      btg = sizeof(buffer) * 8;
+    }
+    b = b + b + ((buffer >> --btg) & 1);
+  } while(0);
+  
+  return b;
+}
+
+int mem_bitio_buffer::bit() {
+  if (btg == 0) {
+
+    if (remaining == 0) { 
+      this->error();
+      return 0;
+
+    } else {
+      buffer = *pos++;
+      remaining--;
+      btg = sizeof(buffer) * 8;
+    }
+    
+  }
+  return ((buffer >> --btg) & 0x01);
+}
+
+void mem_bitio_buffer::encodeBit(int b) {
+  btg--;
+  if (b) buffer |= (1 << btg);
+  
+  if (btg == 0) {
+    if (remaining) {
+      *pos++ = buffer;
+      remaining--;
+    }
+    buffer = 0;
+    btg = sizeof(buffer)*8;
+  }
+}
+
+void mem_bitio_buffer::flush() {
+  if (btg != sizeof(buffer)*8) {
+    if (remaining) {
+      *pos++ = buffer;
+      remaining--;
+    }
+  }
+  btg = sizeof(buffer)*8;
+}
+
+void mem_bitio_buffer::done() {
+  // do nothing
+}
+
+int mem_bitio_buffer::encodeLength() {
+  return pos - base;
+}
+
+int mem_bitio_buffer::encodeVerify() {
+  return (remaining != 0);
+}
+
+
+
Index: /main/tags/2.25/gsdl/src/mgpp/lib/bitio_m_mem.h
===================================================================
--- /main/tags/2.25/gsdl/src/mgpp/lib/bitio_m_mem.h	(revision 21064)
+++ /main/tags/2.25/gsdl/src/mgpp/lib/bitio_m_mem.h	(revision 21064)
@@ -0,0 +1,106 @@
+/**************************************************************************
+ *
+ * bitio_m_mem.h -- Macros for bitio to memory
+ * Copyright (C) 1994  Neil Sharman
+ *
+ * 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.
+ *
+ * $Id$
+ *
+ **************************************************************************
+ *
+ *  This file contains macros for doing bitwise input and output on an array 
+ *  of chars. These routines are faster than the ones in "mems" files. But 
+ *  with these routines you cannot mix reads and writes on the array of chars,
+ *  or multiple write, at the same time and guarantee them to work, also you 
+ *  cannot seek to a point and do a write. The decode routine can detect when
+ *  you run off the end of the array and will produce an approate error 
+ *  message, and the encode routine will stop when it gets to the end of the 
+ *  character array. 
+ *
+ **************************************************************************/
+
+#ifndef H_BITIO_M_MEM
+#define H_BITIO_M_MEM
+
+#include "bitio_m_abstract.h"
+
+
+class mem_bitio_buffer : public bitio_buffer {
+protected:
+  unsigned char *pos;
+  unsigned char *base;
+  int            remaining;
+  unsigned char  buffer;
+  unsigned char  btg;
+  
+public:
+  mem_bitio_buffer ();
+  mem_bitio_buffer (unsigned char *buffer, int size);
+  void seek (unsigned long topos);
+  void error ();
+  long add00 (long b);
+  long addff (long b);
+  int  bit ();
+  void done ();
+
+  void encodeStart ();
+  void encodeBit (int bit);
+  void encodeDone () { flush(); }
+  int  encodeVerify ();
+  int  encodeLength ();
+  void flush ();
+};
+
+
+/*
+#define ENCODE_START(p,r)						\
+  {									\
+    mem_bitio_buffer buffer(p, r);                                     \
+    buffer.encodeStart();
+
+#define ENCODE_CONTINUE(b)						\
+  {									\
+    mem_bitio_buffer buffer;                                           \
+    buffer.unpause(b);
+
+#define ENCODE_PAUSE(b)	buffer.pause(&b);}
+
+#define ENCODE_FLUSH buffer.flush()
+
+#define ENCODE_DONE buffer.flush();}
+
+
+#define DECODE_START(p,r)						\
+  {	                                                                \
+    mem_bitio_buffer buffer(p,r);
+
+#define DECODE_CONTINUE(b)						\
+  {	                                                                \
+    mem_bitio_buffer buffer;                                           \
+    buffer.unpause(b);
+
+#define DECODE_ADD_FF(b) b = buffer.addff(b)
+
+#define DECODE_ADD_00(b) b = buffer.add00(b)
+
+#define DECODE_BIT buffer.bit()
+
+#define DECODE_DONE buffer.done();}
+
+#define DECODE_PAUSE(b) buffer.pause(&b);}
+*/
+
+#endif
Index: /main/tags/2.25/gsdl/src/mgpp/lib/bitio_m_mems.cpp
===================================================================
--- /main/tags/2.25/gsdl/src/mgpp/lib/bitio_m_mems.cpp	(revision 21064)
+++ /main/tags/2.25/gsdl/src/mgpp/lib/bitio_m_mems.cpp	(revision 21064)
@@ -0,0 +1,89 @@
+#include <stdlib.h>
+#include <stdio.h>
+
+#include "bitio_m_abstract.h"
+#include "bitio_m_mems.h"
+
+/**
+ * Create decoding "stream"/"file"
+ */
+mems_bitio_buffer::mems_bitio_buffer()
+{
+}
+
+mems_bitio_buffer::mems_bitio_buffer(unsigned char *readbuffer, long _pos)
+{ 
+  base = readbuffer;
+  pos  = _pos;
+}
+
+void mems_bitio_buffer::encodeStart()
+{
+  // Do nothing
+}
+
+
+void mems_bitio_buffer::error()
+{
+  fprintf(stderr, "Unexpected EOF in \"%s\" on line %d\n", __FILE__, __LINE__);
+  exit(1);
+}
+
+
+void mems_bitio_buffer::seek(unsigned long toPos)
+{ 
+  pos = toPos;
+}
+
+unsigned long mems_bitio_buffer::position()
+{
+  return pos;
+}
+
+long mems_bitio_buffer::addff(long b)
+{
+  do
+    {
+      b = b + b + (base[pos>>3] & (0x80 >> (pos & 0x07)) != 0);
+      pos ++;
+    }
+  while(0);
+
+  return b;
+}
+
+long mems_bitio_buffer::add00(long b)
+{
+  return addff(b);
+}
+
+int mems_bitio_buffer::bit()
+{
+  pos ++;
+  return ((base[(pos-1)>>3] & (0x80 >> ((pos-1) & 0x07))) != 0);
+}
+
+void mems_bitio_buffer::encodeBit(int bit)
+{
+  if (bit)
+    base[pos>>3] |= 0x80 >> (pos & 0x07);
+  else
+    base[pos>>3] &= 0xff7f >> (pos & 0x07);
+  pos++;
+}
+
+void mems_bitio_buffer::flush()
+{
+  // do nothing
+}
+
+void mems_bitio_buffer::done()
+{
+  // do nothing
+}
+
+void mems_bitio_buffer::encodeDone()
+{
+  flush();
+}
+
Index: /main/tags/2.25/gsdl/src/mgpp/lib/bitio_m_mems.h
===================================================================
--- /main/tags/2.25/gsdl/src/mgpp/lib/bitio_m_mems.h	(revision 21064)
+++ /main/tags/2.25/gsdl/src/mgpp/lib/bitio_m_mems.h	(revision 21064)
@@ -0,0 +1,102 @@
+/**************************************************************************
+ *
+ * bitio_m_mems.h -- Macros for bitio to memory (random access)
+ * Copyright (C) 1994  Neil Sharman
+ *
+ * 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.
+ *
+ * $Id$
+ *
+ **************************************************************************
+ *
+ *  This file contains macros for doing bitwise input and output on an array 
+ *  of chars. These routines are slower than the ones in "mem" files. but 
+ *  with these routines you can mix reads and writes, or multiple writes,  on
+ *  the array of chars at the same time and guarantee them to work, also you 
+ *  can seek to a point and do a write. The decode and encode macros cannot 
+ *  detect when the end off the character is reached and just continue 
+ *  processing.
+ *
+ **************************************************************************/
+
+#ifndef H_BITIO_M_MEMS
+#define H_BITIO_M_MEMS
+
+#include "bitio_m_abstract.h"
+
+
+class mems_bitio_buffer : public bitio_buffer {
+protected:
+  unsigned char *base;
+  unsigned long  pos;
+  
+public:
+  mems_bitio_buffer();
+  mems_bitio_buffer(unsigned char *readbuffer, long _pos);
+  void seek(unsigned long topos);
+  void error();
+  long add00(long b);
+  long addff(long b);
+  int  bit();
+  //  int  bitOffset();
+  void done();
+
+  unsigned long position();
+
+  void encodeStart();
+  void encodeBit(int b);
+  void encodeDone();
+  void flush();
+};
+
+
+/*#define ENCODE_START(b,p)						\
+  {									\
+    mems_bitio_buffer buffer(b, p);
+
+#define ENCODE_CONTINUE(b)						\
+  {									\
+    mems_bitio_buffer buffer;                                          \
+    buffer.unpause(b);
+
+#define ENCODE_PAUSE(b)	buffer.pause(&b);}
+
+#define ENCODE_FLUSH buffer.flush();
+
+
+#define ENCODE_DONE buffer.encodeDone();}
+
+
+#define DECODE_START(b,p)						\
+  {		                                                        \
+    mems_bitio_buffer buffer(b, p);
+
+#define DECODE_CONTINUE(b)						\
+  {									\
+    mems_bitio_buffer buffer;                                          \
+    buffer.unpause(b);
+
+#define DECODE_ADD_FF(b) b = buffer.addff(b);
+
+#define DECODE_ADD_00(b) b = buffer.add00(b);
+
+#define DECODE_BIT buffer.bit()
+
+#define DECODE_DONE buffer.done();}
+
+#define DECODE_PAUSE(b) buffer.pause(&b);}
+*/
+
+#endif
Index: /main/tags/2.25/gsdl/src/mgpp/lib/bitio_m_random.cpp
===================================================================
--- /main/tags/2.25/gsdl/src/mgpp/lib/bitio_m_random.cpp	(revision 21064)
+++ /main/tags/2.25/gsdl/src/mgpp/lib/bitio_m_random.cpp	(revision 21064)
@@ -0,0 +1,217 @@
+#include <stdlib.h>
+#include <stdio.h>
+
+#include "longlong.h"
+#include "sysfuncs.h"
+#include "memlib.h"
+
+#include "bitio_m_abstract.h"
+#include "bitio_m_random.h"
+
+random_bitio_buffer::random_bitio_buffer(FILE *f, unsigned long length)
+{
+  buffer = NULL;
+  attachFile (f, length);
+}
+
+random_bitio_buffer::~random_bitio_buffer() {
+  if (buffer != NULL) delete buffer;
+}
+
+void random_bitio_buffer::attachFile (FILE *f, unsigned long length) {
+  // delete the old buffer
+  if (buffer != NULL) {
+    delete buffer;
+    buffer = NULL;
+  }
+
+  // reset all the values
+  file   = f;
+  pos    = 0;
+  base   = 0;
+  used   = 0;
+  len    = length - 1;
+  shift  = 0;
+
+  // make sure the length is a power of 2
+  while (len != 0) {
+    shift ++;
+    len = len >> 1;
+  }
+  len = 1 << shift;
+
+  // allocate a new buffer
+  buffer = new u_char[len];
+
+  // fill up the buffer
+  if (file != NULL) {
+    fseek(file, 0, 0);
+    fread(buffer, 1, len, file);
+  }
+}
+
+random_bitio_buffer &random_bitio_buffer::operator= (const random_bitio_buffer &_rbb) {
+  // delete the old buffer
+  if (buffer != NULL) {
+    delete buffer;
+    buffer = NULL;
+  }
+
+  file = _rbb.file;
+
+  base = _rbb.base;
+  used = _rbb.used;
+  pos = _rbb.pos;
+  len = _rbb.len;
+  shift = _rbb.shift;
+
+  // copy the buffer
+  buffer = new u_char [len];
+  bcopy ((char *)_rbb.buffer, (char *)buffer, len);
+  
+  return (*this);
+}
+
+void random_bitio_buffer::error() {
+}
+
+void random_bitio_buffer::writeRead()
+{
+  if (used)
+    {
+      fseek(file, base, 0);
+      fwrite(buffer, 1, len, file);
+    }
+  //  else
+  //    {
+      base += len;
+      fseek(file, base, 0);
+      fread(buffer, 1, len, file);
+      pos = 0;
+      used = 0;
+  //    }
+}
+
+void random_bitio_buffer::encodeBit(int bit)
+{
+  do
+    {
+      if (bit != 0)
+	{
+	  buffer[pos >> 3] |= 0x80 >> (pos & 0x07);
+	}
+      else
+	{
+	  buffer[pos >> 3] &= 0xff7f >> (pos & 0x07);
+	}
+      used = 1;
+      pos ++;
+
+      if ((pos >> 3) >= len)
+	{
+	  writeRead();
+	}
+    }
+  while (0);
+}
+
+void random_bitio_buffer::flush()
+{
+  if (used != 0)
+    {
+      fseek(file, base, 0);
+      fwrite(buffer, 1, len, file);
+      used = 0;
+    }
+}
+
+void random_bitio_buffer::encodeDone()
+{
+  flush();
+  if (buffer != NULL) {
+    delete buffer;
+    buffer = NULL;
+  }
+}
+
+unsigned long random_bitio_buffer::tell()
+{
+  return ((base << 3) + pos);
+}
+
+void random_bitio_buffer::seek(unsigned long toPos)
+{
+  if (((toPos >> 3) >= base) && (((toPos+7) >> 3) < (base + len)))
+    {
+      pos = toPos - (base << 3);
+    }
+  else
+    {
+      flush();
+      base = toPos >> 3;
+      base = (toPos >> (shift + 3)) << shift;
+      fseek(file, base, 0);
+      fread(buffer, 1, len, file);
+      pos = toPos & 0x07;
+      pos = toPos & ((8 << shift) - 1);
+    }
+}
+
+int random_bitio_buffer::bit()
+{
+  //  fprintf(stderr, "Bit in");
+  pos ++;
+  if (((pos - 1) >> 3) >= len)
+    {
+      writeRead();
+      pos = 1;
+    }
+  return (buffer[(pos - 1) >> 3] & (0x80 >> ((pos - 1) & 0x07))) != 0;
+}
+
+long random_bitio_buffer::addff(long b)
+{
+  return b + b + bit();
+}
+
+long random_bitio_buffer::add00(long b)
+{
+  return addff(b);
+}
+
+int random_bitio_buffer::bitOffset()
+{
+  return 0;
+}
+
+void random_bitio_buffer::done()
+{
+  encodeDone();
+}
+
+
+#ifdef USE_LONG_LONG
+void random_bitio_buffer::seek_LL(mg_ullong toPos)
+{
+  if (((toPos >> 3) >= (mg_ullong) base) &&
+      (((toPos + 7) >> 3) < (mg_ullong) (base + len)))
+    {
+      pos = (long) (toPos - (mg_ullong) (base << 3));
+    }
+  else
+    {
+      flush();
+      base = (long) ((toPos >> (shift + 3)) << shift);
+
+      fseek(file, base, 0);
+      fread(buffer, 1, len, file);
+      pos = (long) (toPos & ((8 << shift) - 1));
+    }
+}
+
+mg_ullong random_bitio_buffer::tell_LL()
+{
+  return (((mg_ullong) base) << 3ull) + pos;
+}
+#endif
+
Index: /main/tags/2.25/gsdl/src/mgpp/lib/bitio_m_random.h
===================================================================
--- /main/tags/2.25/gsdl/src/mgpp/lib/bitio_m_random.h	(revision 21064)
+++ /main/tags/2.25/gsdl/src/mgpp/lib/bitio_m_random.h	(revision 21064)
@@ -0,0 +1,129 @@
+/**************************************************************************
+ *
+ * bitio_m_random.h -- Macros for bitio to a file (random access)
+ * Copyright (C) 1994  Neil Sharman
+ *
+ * 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.
+ *
+ * $Id$
+ *
+ **************************************************************************
+ *
+ *  This file contains macros for doing bitwise input and output on an array 
+ *  of chars. These routines are slower than the ones in "mem" files. but 
+ *  with these routines you can mix reads and writes, or multiple writes,  on
+ *  the array of chars at the same time and guarantee them to work, also you 
+ *  can seek to a point and do a write. The decode and encode macros cannot 
+ *  detect when the end off the character is reached and just continue 
+ *  processing.
+ *
+ *
+ **************************************************************************/
+
+#ifndef H_BITIO_M_RANDOM
+#define H_BITIO_M_RANDOM
+
+#include "longlong.h"
+#include "bitio_m_abstract.h"
+
+
+class random_bitio_buffer : public bitio_buffer { 
+public:
+  FILE *file;
+  unsigned char *buffer;
+  unsigned long  base;
+  unsigned long  used;
+  unsigned long  pos;
+  unsigned long  len;
+  unsigned long  shift;
+  void writeRead();
+
+  random_bitio_buffer(FILE *f = 0,
+		      unsigned long length = 8*1024);
+  virtual ~random_bitio_buffer();
+  
+  void attachFile (FILE *f, unsigned long length);
+
+  random_bitio_buffer &operator= (const random_bitio_buffer &_rbb);
+  
+  void encodeDone();
+  void encodeBit(int b);
+  void flush();
+  unsigned long tell();
+
+  void seek(unsigned long topos);
+  void error();
+  long add00(long b);
+  long addff(long b);
+  int  bit();
+  int  bitOffset();
+  void done();
+
+#ifdef USE_LONG_LONG
+  // extras for longlong.h
+  void seek_LL(mg_ullong pos);
+  mg_ullong tell_LL();
+#endif
+};
+
+
+/*#define ENCODE_START(f,l)						\
+  {									\
+    random_bitio_buffer buffer(f, l);
+
+#define ENCODE_CONTINUE(b)						\
+  {									\
+    random_bitio_buffer buffer;                                               \
+    buffer.unpause(b);
+
+#define SEEK fprintf(stderr, "Seek to %d\n",buffer.base)
+#define READ fprintf(stderr, "Read of %d\n",buffer.len)
+#define WRITE fprintf(stderr, "Write of %d\n",buffer.used)
+
+#define WRITE_READ buffer.writeRead()
+
+#define ENCODE_PAUSE(b)	buffer.pause(&b);}
+
+#define ENCODE_FLUSH buffer.flush();
+
+#define ENCODE_DONE buffer.done();}							
+
+#define DECODE_START(f,l) \
+  {									\
+    random_bitio_buffer buffer(f, l);
+
+#define DECODE_CONTINUE(b) \
+  {									\
+    random_bitio_buffer buffer;                                               \
+    buffer.unpause(b);
+
+#define DECODE_BIT buffer.bit()
+
+#define DECODE_ADD_FF(b) b = buffer.addff(b)
+
+#define DECODE_ADD_00(b) b = buffer.add00(b)
+
+#define DECODE_DONE buffer.done();}
+
+#define DECODE_PAUSE(b)	buffer.pause(&b);}
+
+#define ENCODE_TELL buffer.tell()
+
+#define DECODE_TELL buffer.tell()
+*/
+
+
+
+#endif
Index: /main/tags/2.25/gsdl/src/mgpp/lib/bitio_m_stdio.cpp
===================================================================
--- /main/tags/2.25/gsdl/src/mgpp/lib/bitio_m_stdio.cpp	(revision 21064)
+++ /main/tags/2.25/gsdl/src/mgpp/lib/bitio_m_stdio.cpp	(revision 21064)
@@ -0,0 +1,125 @@
+#include <stdlib.h>
+#include <stdio.h>
+
+#include "bitio_m_stdio.h"
+
+stdio_bitio_buffer::stdio_bitio_buffer(FILE *f) {
+  attachFile (f);
+}
+
+void stdio_bitio_buffer::attachFile (FILE *f) {
+  file = f;
+  buffer = 0;
+  btg = 0;
+  bytesWritten = 0;
+}
+
+void stdio_bitio_buffer::encodeStart() {
+  btg = sizeof(buffer) * 8;
+}
+
+void stdio_bitio_buffer::error() {
+  fprintf(stderr, "Unexpected EOF in \"%s\" on line %d", __FILE__, __LINE__);
+  exit(1);
+}
+
+void stdio_bitio_buffer::seek (unsigned long byte, unsigned char bit) {
+  if (fseek (file, byte, SEEK_SET) != 0) return;
+  buffer = getc(file);
+  btg = bit;
+  bytesWritten = 0;
+}
+
+void stdio_bitio_buffer::seek(unsigned long topos) {
+  if (fseek(file, topos >> 3, SEEK_SET) != 0) return;
+  buffer = getc(file);
+  btg = 8 - (topos & 0x07);
+  bytesWritten = 0;
+}
+
+long stdio_bitio_buffer::addff(long b)
+{
+  if (!btg)
+    {
+      register int val;
+      val = getc(file);
+      if (val == EOF)
+	{
+	  buffer = 0x0ff;
+	}
+      else
+	{
+	  buffer = val;
+	}
+      btg = sizeof(buffer) * 8;
+    }
+  b = b + b + ((buffer >> --btg) & 0x01);
+
+  return b;
+}
+
+long stdio_bitio_buffer::add00(long b)
+{
+  if (!btg)
+    {
+      register int val;
+      val = getc(file);
+      if (val == EOF)
+	{
+	  buffer = 0xff;
+	}
+      else
+	{
+	  buffer = val;
+	}
+      btg = sizeof(buffer) * 8;
+    }
+  b = b + b + ((buffer >> --btg) & 0x01);
+  
+  return b;
+}
+
+void stdio_bitio_buffer::encodeBit(int b)
+{
+  btg--;
+  if (b != 0)
+    buffer |= (1 << btg);
+
+  if (btg == 0)
+    {
+      putc(buffer, file);
+      bytesWritten += sizeof (buffer);
+      buffer = 0;
+      btg = sizeof(buffer)*8;
+    }
+}
+
+int stdio_bitio_buffer::bit()
+{
+  if (btg == 0)
+    {
+      buffer = getc(file);
+      if (feof(file))
+	{
+	  error();
+	  return 0;
+	}
+      else
+	{
+	  btg = sizeof(buffer) * 8;
+	}
+    }
+  return ((buffer >> --btg) & 0x01);
+}
+
+void stdio_bitio_buffer::done() {
+  // no tidying required
+}
+
+void stdio_bitio_buffer::encodeDone() {
+  if (btg != sizeof(buffer) * 8) {
+    putc(buffer, file);
+    bytesWritten += sizeof (buffer);
+  }
+}
+
Index: /main/tags/2.25/gsdl/src/mgpp/lib/bitio_m_stdio.h
===================================================================
--- /main/tags/2.25/gsdl/src/mgpp/lib/bitio_m_stdio.h	(revision 21064)
+++ /main/tags/2.25/gsdl/src/mgpp/lib/bitio_m_stdio.h	(revision 21064)
@@ -0,0 +1,103 @@
+/**************************************************************************
+ *
+ * bitio_m_stdio.h -- Macros for bitio to a file
+ * Copyright (C) 1994  Neil Sharman
+ *
+ * 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.
+ *
+ * $Id$
+ *
+ **************************************************************************
+ *
+ *  This file contains macros for doing bitwise input and output on a FILE*.
+ *  With these routines you cannot mix reads and writes on the FILE,
+ *  or multiple writes, at the same time and guarantee them to work, also you 
+ *  cannot seek to a point and do a write. The decode routine can detect when
+ *  you run off the end of the file and will produce an approate error message.
+ *
+ *
+ **************************************************************************/
+
+#ifndef H_BITIO_M_STDIO
+#define H_BITIO_M_STDIO
+
+#include "bitio_m_abstract.h"
+
+
+class stdio_bitio_buffer : public bitio_buffer {
+protected:
+  FILE *file;
+  unsigned char buffer;
+  unsigned char btg;
+  unsigned long bytesWritten;
+  
+public:
+  stdio_bitio_buffer (FILE *f = NULL);
+
+  void attachFile (FILE *f);
+
+  unsigned char GetBtg () { return btg; }
+  unsigned long GetBytesWritten () { return bytesWritten; }
+  
+  void seek (unsigned long byte, unsigned char bit);
+  void seek (unsigned long topos);
+  void error();
+  long add00(long b);
+  long addff(long b);
+  int  bit();
+  int  bitOffset() { return btg; }
+  void done();
+
+  void encodeStart();
+  void encodeBit(int bit);
+  void encodeDone();
+};
+
+
+/*#define ENCODE_START(f)							\
+  {									\
+    stdio_bitio_buffer buffer(f);                                       \
+    buffer.encodeStart();
+
+#define ENCODE_CONTINUE(b)						\
+  {									\
+    stdio_bitio_buffer buffer;                                          \
+    buffer.unpause(b);
+
+#define ENCODE_PAUSE(b) buffer.pause(&b);}
+
+#define ENCODE_DONE buffer.encodeDone();}
+
+#define DECODE_START(f)							\
+  {		                                                        \
+    stdio_bitio_buffer buffer(f);
+
+#define DECODE_CONTINUE(b)						\
+  {									\
+    stdio_bitio_buffer buffer;                                          \
+     buffer.unpause(b);
+
+#define DECODE_ADD_FF(b) b = buffer.addff(b)
+
+#define DECODE_ADD_00(b) b = buffer.add00(b)
+
+#define DECODE_BIT buffer.bit()
+
+#define DECODE_DONE buffer.done();}
+
+#define DECODE_PAUSE(b) buffer.pause(&b);}
+*/
+
+#endif
Index: /main/tags/2.25/gsdl/src/mgpp/lib/ftruncate.cpp
===================================================================
--- /main/tags/2.25/gsdl/src/mgpp/lib/ftruncate.cpp	(revision 21064)
+++ /main/tags/2.25/gsdl/src/mgpp/lib/ftruncate.cpp	(revision 21064)
@@ -0,0 +1,99 @@
+/* ftruncate emulations that work on some System V's.
+   This file is in the public domain.  */
+
+#ifdef HAVE_CONFIG_H
+# ifdef __WIN32__  /* [RPAP - Feb 97: WIN32 Port] */
+#  include <win32cfg.h>
+# else
+#  include <sysfuncs.h>
+# endif
+#endif
+
+#include <sys/types.h>
+#include <fcntl.h>
+
+#ifdef F_CHSIZE
+
+int
+ftruncate (int fd, off_t length)
+{
+  return fcntl (fd, F_CHSIZE, length);
+}
+
+#else /* not F_CHSIZE */
+#ifdef F_FREESP
+
+/* By William Kucharski <kucharsk@netcom.com>.  */
+
+#include <sys/stat.h>
+#include <errno.h>
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+
+int
+ftruncate (int fd, off_t length)
+{
+  struct flock fl;
+  struct stat filebuf;
+
+  if (fstat (fd, &filebuf) < 0)
+    return -1;
+
+  if (filebuf.st_size < length)
+    {
+      /* Extend file length. */
+      if (lseek (fd, (length - 1), SEEK_SET) < 0)
+	return -1;
+
+      /* Write a "0" byte. */
+      if (write (fd, "", 1) != 1)
+	return -1;
+    }
+  else
+    {
+
+      /* Truncate length. */
+
+      fl.l_whence = 0;
+      fl.l_len = 0;
+      fl.l_start = length;
+      fl.l_type = F_WRLCK;	/* write lock on file space */
+
+      /* This relies on the *undocumented* F_FREESP argument to fcntl,
+	 which truncates the file so that it ends at the position
+	 indicated by fl.l_start.  Will minor miracles never cease?  */
+
+      if (fcntl (fd, F_FREESP, &fl) < 0)
+	return -1;
+    }
+
+  return 0;
+}
+
+#else /* not F_CHSIZE nor F_FREESP */
+#ifdef HAVE_CHSIZE
+
+int
+ftruncate (int fd, off_t length)
+{
+  return chsize (fd, length);
+}
+
+#else /* not F_CHSIZE nor F_FREESP nor HAVE_CHSIZE */
+
+#include <errno.h>
+#ifndef errno
+extern int errno;
+#endif
+
+int
+ftruncate (int fd, off_t length)
+{
+  errno = EIO;
+  return -1;
+}
+
+#endif /* not HAVE_CHSIZE */
+#endif /* not F_FREESP */
+#endif /* not F_CHSIZE */
Index: /main/tags/2.25/gsdl/src/mgpp/lib/getopt.cpp
===================================================================
--- /main/tags/2.25/gsdl/src/mgpp/lib/getopt.cpp	(revision 21064)
+++ /main/tags/2.25/gsdl/src/mgpp/lib/getopt.cpp	(revision 21064)
@@ -0,0 +1,750 @@
+/* Getopt for GNU.
+   NOTE: getopt is now part of the C library, so if you don't know what
+   "Keep this file name-space clean" means, talk to roland@gnu.ai.mit.edu
+   before changing it!
+
+   Copyright (C) 1987, 88, 89, 90, 91, 92, 1993
+   Free Software Foundation, Inc.
+
+   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, 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, 675 Mass Ave, Cambridge, MA 02139, USA.  */
+
+
+#ifdef HAVE_CONFIG_H
+#include "sysfuncs.h"
+#endif
+
+#if !__STDC__ && !defined(const) && IN_GCC
+#define const
+#endif
+
+/* This tells Alpha OSF/1 not to define a getopt prototype in <stdio.h>.  */
+#ifndef _NO_PROTO
+#define _NO_PROTO
+#endif
+
+#include <stdio.h>
+
+/* Comment out all this code if we are using the GNU C Library, and are not
+   actually compiling the library itself.  This code is part of the GNU C
+   Library, but also included in many other GNU distributions.  Compiling
+   and linking in this code is a waste when using the GNU C library
+   (especially if it is a shared library).  Rather than having every GNU
+   program understand `configure --with-gnu-libc' and omit the object files,
+   it is simpler to just do this in the source for each such file.  */
+
+#if defined (_LIBC) || !defined (__GNU_LIBRARY__)
+
+
+/* This needs to come after some library #include
+   to get __GNU_LIBRARY__ defined.  */
+#ifdef	__GNU_LIBRARY__
+/* Don't include stdlib.h for non-GNU C libraries because some of them
+   contain conflicting prototypes for getopt.  */
+#include <stdlib.h>
+#endif /* GNU C library.  */
+
+/* If GETOPT_COMPAT is defined, `+' as well as `--' can introduce a
+   long-named option.  Because this is not POSIX.2 compliant, it is
+   being phased out.  */
+/* #define GETOPT_COMPAT */
+
+/* This version of `getopt' appears to the caller like standard Unix `getopt'
+   but it behaves differently for the user, since it allows the user
+   to intersperse the options with the other arguments.
+
+   As `getopt' works, it permutes the elements of ARGV so that,
+   when it is done, all the options precede everything else.  Thus
+   all application programs are extended to handle flexible argument order.
+
+   Setting the environment variable POSIXLY_CORRECT disables permutation.
+   Then the behavior is completely standard.
+
+   GNU application programs can use a third alternative mode in which
+   they can distinguish the relative order of options and other arguments.  */
+
+#include "getopt.h"
+
+/* For communication from `getopt' to the caller.
+   When `getopt' finds an option that takes an argument,
+   the argument value is returned here.
+   Also, when `ordering' is RETURN_IN_ORDER,
+   each non-option ARGV-element is returned here.  */
+
+char *optarg = 0;
+
+/* Index in ARGV of the next element to be scanned.
+   This is used for communication to and from the caller
+   and for communication between successive calls to `getopt'.
+
+   On entry to `getopt', zero means this is the first call; initialize.
+
+   When `getopt' returns EOF, this is the index of the first of the
+   non-option elements that the caller should itself scan.
+
+   Otherwise, `optind' communicates from one call to the next
+   how much of ARGV has been scanned so far.  */
+
+/* XXX 1003.2 says this must be 1 before any call.  */
+int optind = 0;
+
+/* The next char to be scanned in the option-element
+   in which the last option character we returned was found.
+   This allows us to pick up the scan where we left off.
+
+   If this is zero, or a null string, it means resume the scan
+   by advancing to the next ARGV-element.  */
+
+static char *nextchar;
+
+/* Callers store zero here to inhibit the error message
+   for unrecognized options.  */
+
+int opterr = 1;
+
+/* Set to an option character which was unrecognized.
+   This must be initialized on some systems to avoid linking in the
+   system's own getopt implementation.  */
+
+int optopt = '?';
+
+/* Describe how to deal with options that follow non-option ARGV-elements.
+
+   If the caller did not specify anything,
+   the default is REQUIRE_ORDER if the environment variable
+   POSIXLY_CORRECT is defined, PERMUTE otherwise.
+
+   REQUIRE_ORDER means don't recognize them as options;
+   stop option processing when the first non-option is seen.
+   This is what Unix does.
+   This mode of operation is selected by either setting the environment
+   variable POSIXLY_CORRECT, or using `+' as the first character
+   of the list of option characters.
+
+   PERMUTE is the default.  We permute the contents of ARGV as we scan,
+   so that eventually all the non-options are at the end.  This allows options
+   to be given in any order, even with programs that were not written to
+   expect this.
+
+   RETURN_IN_ORDER is an option available to programs that were written
+   to expect options and other ARGV-elements in any order and that care about
+   the ordering of the two.  We describe each non-option ARGV-element
+   as if it were the argument of an option with character code 1.
+   Using `-' as the first character of the list of option characters
+   selects this mode of operation.
+
+   The special argument `--' forces an end of option-scanning regardless
+   of the value of `ordering'.  In the case of RETURN_IN_ORDER, only
+   `--' can cause `getopt' to return EOF with `optind' != ARGC.  */
+
+static enum
+  {
+    REQUIRE_ORDER, PERMUTE, RETURN_IN_ORDER
+  }
+ordering;
+
+
+#ifdef	__GNU_LIBRARY__
+/* We want to avoid inclusion of string.h with non-GNU libraries
+   because there are many ways it can cause trouble.
+   On some systems, it contains special magic macros that don't work
+   in GCC.  */
+#include <string.h>
+#define	my_index	strchr
+#else
+
+/* Avoid depending on library functions or files
+   whose names are inconsistent.  */
+
+char *getenv ();
+
+static char *
+my_index (str, chr)
+     const char *str;
+     int chr;
+{
+  while (*str)
+    {
+      if (*str == chr)
+	return (char *) str;
+      str++;
+    }
+  return 0;
+}
+
+/* If using GCC, we can safely declare strlen this way.
+   If not using GCC, it is ok not to declare it.  */
+#ifdef __GNUC__
+#ifdef IN_GCC
+#include "gstddef.h"
+#else
+#include <stddef.h>
+#endif
+extern size_t strlen (const char *);
+#endif
+
+#endif /* GNU C library.  */
+
+
+/* Handle permutation of arguments.  */
+
+/* Describe the part of ARGV that contains non-options that have
+   been skipped.  `first_nonopt' is the index in ARGV of the first of them;
+   `last_nonopt' is the index after the last of them.  */
+
+static int first_nonopt;
+static int last_nonopt;
+
+/* Exchange two adjacent subsequences of ARGV.
+   One subsequence is elements [first_nonopt,last_nonopt)
+   which contains all the non-options that have been skipped so far.
+   The other is elements [last_nonopt,optind), which contains all
+   the options processed since those non-options were skipped.
+
+   `first_nonopt' and `last_nonopt' are relocated so that they describe
+   the new indices of the non-options in ARGV after they are moved.  */
+
+static void
+exchange (argv)
+     char **argv;
+{
+  int bottom = first_nonopt;
+  int middle = last_nonopt;
+  int top = optind;
+  char *tem;
+
+  /* Exchange the shorter segment with the far end of the longer segment.
+     That puts the shorter segment into the right place.
+     It leaves the longer segment in the right place overall,
+     but it consists of two parts that need to be swapped next.  */
+
+  while (top > middle && middle > bottom)
+    {
+      if (top - middle > middle - bottom)
+	{
+	  /* Bottom segment is the short one.  */
+	  int len = middle - bottom;
+	  register int i;
+
+	  /* Swap it with the top part of the top segment.  */
+	  for (i = 0; i < len; i++)
+	    {
+	      tem = argv[bottom + i];
+	      argv[bottom + i] = argv[top - (middle - bottom) + i];
+	      argv[top - (middle - bottom) + i] = tem;
+	    }
+	  /* Exclude the moved bottom segment from further swapping.  */
+	  top -= len;
+	}
+      else
+	{
+	  /* Top segment is the short one.  */
+	  int len = top - middle;
+	  register int i;
+
+	  /* Swap it with the bottom part of the bottom segment.  */
+	  for (i = 0; i < len; i++)
+	    {
+	      tem = argv[bottom + i];
+	      argv[bottom + i] = argv[middle + i];
+	      argv[middle + i] = tem;
+	    }
+	  /* Exclude the moved top segment from further swapping.  */
+	  bottom += len;
+	}
+    }
+
+  /* Update records for the slots the non-options now occupy.  */
+
+  first_nonopt += (optind - last_nonopt);
+  last_nonopt = optind;
+}
+
+
+/* Scan elements of ARGV (whose length is ARGC) for option characters
+   given in OPTSTRING.
+
+   If an element of ARGV starts with '-', and is not exactly "-" or "--",
+   then it is an option element.  The characters of this element
+   (aside from the initial '-') are option characters.  If `getopt'
+   is called repeatedly, it returns successively each of the option characters
+   from each of the option elements.
+
+   If `getopt' finds another option character, it returns that character,
+   updating `optind' and `nextchar' so that the next call to `getopt' can
+   resume the scan with the following option character or ARGV-element.
+
+   If there are no more option characters, `getopt' returns `EOF'.
+   Then `optind' is the index in ARGV of the first ARGV-element
+   that is not an option.  (The ARGV-elements have been permuted
+   so that those that are not options now come last.)
+
+   OPTSTRING is a string containing the legitimate option characters.
+   If an option character is seen that is not listed in OPTSTRING,
+   return '?' after printing an error message.  If you set `opterr' to
+   zero, the error message is suppressed but we still return '?'.
+
+   If a char in OPTSTRING is followed by a colon, that means it wants an arg,
+   so the following text in the same ARGV-element, or the text of the following
+   ARGV-element, is returned in `optarg'.  Two colons mean an option that
+   wants an optional arg; if there is text in the current ARGV-element,
+   it is returned in `optarg', otherwise `optarg' is set to zero.
+
+   If OPTSTRING starts with `-' or `+', it requests different methods of
+   handling the non-option ARGV-elements.
+   See the comments about RETURN_IN_ORDER and REQUIRE_ORDER, above.
+
+   Long-named options begin with `--' instead of `-'.
+   Their names may be abbreviated as long as the abbreviation is unique
+   or is an exact match for some defined option.  If they have an
+   argument, it follows the option name in the same ARGV-element, separated
+   from the option name by a `=', or else the in next ARGV-element.
+   When `getopt' finds a long-named option, it returns 0 if that option's
+   `flag' field is nonzero, the value of the option's `val' field
+   if the `flag' field is zero.
+
+   The elements of ARGV aren't really const, because we permute them.
+   But we pretend they're const in the prototype to be compatible
+   with other systems.
+
+   LONGOPTS is a vector of `struct option' terminated by an
+   element containing a name which is zero.
+
+   LONGIND returns the index in LONGOPT of the long-named option found.
+   It is only valid when a long-named option has been found by the most
+   recent call.
+
+   If LONG_ONLY is nonzero, '-' as well as '--' can introduce
+   long-named options.  */
+
+int
+_getopt_internal (argc, argv, optstring, longopts, longind, long_only)
+     int argc;
+     char *const *argv;
+     const char *optstring;
+     const struct option *longopts;
+     int *longind;
+     int long_only;
+{
+  int option_index;
+
+  optarg = 0;
+
+  /* Initialize the internal data when the first call is made.
+     Start processing options with ARGV-element 1 (since ARGV-element 0
+     is the program name); the sequence of previously skipped
+     non-option ARGV-elements is empty.  */
+
+  if (optind == 0)
+    {
+      first_nonopt = last_nonopt = optind = 1;
+
+      nextchar = NULL;
+
+      /* Determine how to handle the ordering of options and nonoptions.  */
+
+      if (optstring[0] == '-')
+	{
+	  ordering = RETURN_IN_ORDER;
+	  ++optstring;
+	}
+      else if (optstring[0] == '+')
+	{
+	  ordering = REQUIRE_ORDER;
+	  ++optstring;
+	}
+      else if (getenv ("POSIXLY_CORRECT") != NULL)
+	ordering = REQUIRE_ORDER;
+      else
+	ordering = PERMUTE;
+    }
+
+  if (nextchar == NULL || *nextchar == '\0')
+    {
+      if (ordering == PERMUTE)
+	{
+	  /* If we have just processed some options following some non-options,
+	     exchange them so that the options come first.  */
+
+	  if (first_nonopt != last_nonopt && last_nonopt != optind)
+	    exchange ((char **) argv);
+	  else if (last_nonopt != optind)
+	    first_nonopt = optind;
+
+	  /* Now skip any additional non-options
+	     and extend the range of non-options previously skipped.  */
+
+	  while (optind < argc
+		 && (argv[optind][0] != '-' || argv[optind][1] == '\0')
+#ifdef GETOPT_COMPAT
+		 && (longopts == NULL
+		     || argv[optind][0] != '+' || argv[optind][1] == '\0')
+#endif /* GETOPT_COMPAT */
+	    )
+	    optind++;
+	  last_nonopt = optind;
+	}
+
+      /* Special ARGV-element `--' means premature end of options.
+         Skip it like a null option,
+         then exchange with previous non-options as if it were an option,
+         then skip everything else like a non-option.  */
+
+      if (optind != argc && !strcmp (argv[optind], "--"))
+	{
+	  optind++;
+
+	  if (first_nonopt != last_nonopt && last_nonopt != optind)
+	    exchange ((char **) argv);
+	  else if (first_nonopt == last_nonopt)
+	    first_nonopt = optind;
+	  last_nonopt = argc;
+
+	  optind = argc;
+	}
+
+      /* If we have done all the ARGV-elements, stop the scan
+         and back over any non-options that we skipped and permuted.  */
+
+      if (optind == argc)
+	{
+	  /* Set the next-arg-index to point at the non-options
+	     that we previously skipped, so the caller will digest them.  */
+	  if (first_nonopt != last_nonopt)
+	    optind = first_nonopt;
+	  return EOF;
+	}
+
+      /* If we have come to a non-option and did not permute it,
+         either stop the scan or describe it to the caller and pass it by.  */
+
+      if ((argv[optind][0] != '-' || argv[optind][1] == '\0')
+#ifdef GETOPT_COMPAT
+	  && (longopts == NULL
+	      || argv[optind][0] != '+' || argv[optind][1] == '\0')
+#endif /* GETOPT_COMPAT */
+	)
+	{
+	  if (ordering == REQUIRE_ORDER)
+	    return EOF;
+	  optarg = argv[optind++];
+	  return 1;
+	}
+
+      /* We have found another option-ARGV-element.
+         Start decoding its characters.  */
+
+      nextchar = (argv[optind] + 1
+		  + (longopts != NULL && argv[optind][1] == '-'));
+    }
+
+  if (longopts != NULL
+      && ((argv[optind][0] == '-'
+	   && (argv[optind][1] == '-' || long_only))
+#ifdef GETOPT_COMPAT
+	  || argv[optind][0] == '+'
+#endif /* GETOPT_COMPAT */
+      ))
+    {
+      const struct option *p;
+      char *s = nextchar;
+      int exact = 0;
+      int ambig = 0;
+      const struct option *pfound = NULL;
+      int indfound;
+
+      while (*s && *s != '=')
+	s++;
+
+      /* Test all options for either exact match or abbreviated matches.  */
+      for (p = longopts, option_index = 0; p->name;
+	   p++, option_index++)
+	if (!strncmp (p->name, nextchar, s - nextchar))
+	  {
+	    if (s - nextchar == strlen (p->name))
+	      {
+		/* Exact match found.  */
+		pfound = p;
+		indfound = option_index;
+		exact = 1;
+		break;
+	      }
+	    else if (pfound == NULL)
+	      {
+		/* First nonexact match found.  */
+		pfound = p;
+		indfound = option_index;
+	      }
+	    else
+	      /* Second nonexact match found.  */
+	      ambig = 1;
+	  }
+
+      if (ambig && !exact)
+	{
+	  if (opterr)
+	    fprintf (stderr, "%s: option `%s' is ambiguous\n",
+		     argv[0], argv[optind]);
+	  nextchar += strlen (nextchar);
+	  optind++;
+	  return '?';
+	}
+
+      if (pfound != NULL)
+	{
+	  option_index = indfound;
+	  optind++;
+	  if (*s)
+	    {
+	      /* Don't test has_arg with >, because some C compilers don't
+	         allow it to be used on enums.  */
+	      if (pfound->has_arg)
+		optarg = s + 1;
+	      else
+		{
+		  if (opterr)
+		    {
+		      if (argv[optind - 1][1] == '-')
+			/* --option */
+			fprintf (stderr,
+			    "%s: option `--%s' doesn't allow an argument\n",
+				 argv[0], pfound->name);
+		      else
+			/* +option or -option */
+			fprintf (stderr,
+			    "%s: option `%c%s' doesn't allow an argument\n",
+				 argv[0], argv[optind - 1][0], pfound->name);
+		    }
+		  nextchar += strlen (nextchar);
+		  return '?';
+		}
+	    }
+	  else if (pfound->has_arg == 1)
+	    {
+	      if (optind < argc)
+		optarg = argv[optind++];
+	      else
+		{
+		  if (opterr)
+		    fprintf (stderr, "%s: option `%s' requires an argument\n",
+			     argv[0], argv[optind - 1]);
+		  nextchar += strlen (nextchar);
+		  return optstring[0] == ':' ? ':' : '?';
+		}
+	    }
+	  nextchar += strlen (nextchar);
+	  if (longind != NULL)
+	    *longind = option_index;
+	  if (pfound->flag)
+	    {
+	      *(pfound->flag) = pfound->val;
+	      return 0;
+	    }
+	  return pfound->val;
+	}
+      /* Can't find it as a long option.  If this is not getopt_long_only,
+         or the option starts with '--' or is not a valid short
+         option, then it's an error.
+         Otherwise interpret it as a short option.  */
+      if (!long_only || argv[optind][1] == '-'
+#ifdef GETOPT_COMPAT
+	  || argv[optind][0] == '+'
+#endif /* GETOPT_COMPAT */
+	  || my_index (optstring, *nextchar) == NULL)
+	{
+	  if (opterr)
+	    {
+	      if (argv[optind][1] == '-')
+		/* --option */
+		fprintf (stderr, "%s: unrecognized option `--%s'\n",
+			 argv[0], nextchar);
+	      else
+		/* +option or -option */
+		fprintf (stderr, "%s: unrecognized option `%c%s'\n",
+			 argv[0], argv[optind][0], nextchar);
+	    }
+	  nextchar = (char *) "";
+	  optind++;
+	  return '?';
+	}
+    }
+
+  /* Look at and handle the next option-character.  */
+
+  {
+    char c = *nextchar++;
+    char *temp = my_index (optstring, c);
+
+    /* Increment `optind' when we start to process its last character.  */
+    if (*nextchar == '\0')
+      ++optind;
+
+    if (temp == NULL || c == ':')
+      {
+	if (opterr)
+	  {
+#if 0
+	    if (c < 040 || c >= 0177)
+	      fprintf (stderr, "%s: unrecognized option, character code 0%o\n",
+		       argv[0], c);
+	    else
+	      fprintf (stderr, "%s: unrecognized option `-%c'\n", argv[0], c);
+#else
+	    /* 1003.2 specifies the format of this message.  */
+	    fprintf (stderr, "%s: illegal option -- %c\n", argv[0], c);
+#endif
+	  }
+	optopt = c;
+	return '?';
+      }
+    if (temp[1] == ':')
+      {
+	if (temp[2] == ':')
+	  {
+	    /* This is an option that accepts an argument optionally.  */
+	    if (*nextchar != '\0')
+	      {
+		optarg = nextchar;
+		optind++;
+	      }
+	    else
+	      optarg = 0;
+	    nextchar = NULL;
+	  }
+	else
+	  {
+	    /* This is an option that requires an argument.  */
+	    if (*nextchar != '\0')
+	      {
+		optarg = nextchar;
+		/* If we end this ARGV-element by taking the rest as an arg,
+		   we must advance to the next element now.  */
+		optind++;
+	      }
+	    else if (optind == argc)
+	      {
+		if (opterr)
+		  {
+#if 0
+		    fprintf (stderr, "%s: option `-%c' requires an argument\n",
+			     argv[0], c);
+#else
+		    /* 1003.2 specifies the format of this message.  */
+		    fprintf (stderr, "%s: option requires an argument -- %c\n",
+			     argv[0], c);
+#endif
+		  }
+		optopt = c;
+		if (optstring[0] == ':')
+		  c = ':';
+		else
+		  c = '?';
+	      }
+	    else
+	      /* We already incremented `optind' once;
+	         increment it again when taking next ARGV-elt as argument.  */
+	      optarg = argv[optind++];
+	    nextchar = NULL;
+	  }
+      }
+    return c;
+  }
+}
+
+int
+getopt (argc, argv, optstring)
+     int argc;
+     char *const *argv;
+     const char *optstring;
+{
+  return _getopt_internal (argc, argv, optstring,
+			   (const struct option *) 0,
+			   (int *) 0,
+			   0);
+}
+
+#endif /* _LIBC or not __GNU_LIBRARY__.  */
+
+
+#ifdef TEST
+
+/* Compile with -DTEST to make an executable for use in testing
+   the above definition of `getopt'.  */
+
+int
+main (argc, argv)
+     int argc;
+     char **argv;
+{
+  int c;
+  int digit_optind = 0;
+
+  while (1)
+    {
+      int this_option_optind = optind ? optind : 1;
+
+      c = getopt (argc, argv, "abc:d:0123456789");
+      if (c == EOF)
+	break;
+
+      switch (c)
+	{
+	case '0':
+	case '1':
+	case '2':
+	case '3':
+	case '4':
+	case '5':
+	case '6':
+	case '7':
+	case '8':
+	case '9':
+	  if (digit_optind != 0 && digit_optind != this_option_optind)
+	    printf ("digits occur in two different argv-elements.\n");
+	  digit_optind = this_option_optind;
+	  printf ("option %c\n", c);
+	  break;
+
+	case 'a':
+	  printf ("option a\n");
+	  break;
+
+	case 'b':
+	  printf ("option b\n");
+	  break;
+
+	case 'c':
+	  printf ("option c with value `%s'\n", optarg);
+	  break;
+
+	case '?':
+	  break;
+
+	default:
+	  printf ("?? getopt returned character code 0%o ??\n", c);
+	}
+    }
+
+  if (optind < argc)
+    {
+      printf ("non-option ARGV-elements: ");
+      while (optind < argc)
+	printf ("%s ", argv[optind++]);
+      printf ("\n");
+    }
+
+  exit (0);
+}
+
+#endif /* TEST */
Index: /main/tags/2.25/gsdl/src/mgpp/lib/getopt.h
===================================================================
--- /main/tags/2.25/gsdl/src/mgpp/lib/getopt.h	(revision 21064)
+++ /main/tags/2.25/gsdl/src/mgpp/lib/getopt.h	(revision 21064)
@@ -0,0 +1,130 @@
+/* Declarations for getopt.
+   Copyright (C) 1989, 1990, 1991, 1992, 1993 Free Software Foundation, Inc.
+
+   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, 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, 675 Mass Ave, Cambridge, MA 02139, USA.  */
+
+#ifndef _GETOPT_H
+#define _GETOPT_H 1
+
+#ifdef	__cplusplus
+extern "C"
+{
+#endif
+
+/* For communication from `getopt' to the caller.
+   When `getopt' finds an option that takes an argument,
+   the argument value is returned here.
+   Also, when `ordering' is RETURN_IN_ORDER,
+   each non-option ARGV-element is returned here.  */
+
+  extern char *optarg;
+
+/* Index in ARGV of the next element to be scanned.
+   This is used for communication to and from the caller
+   and for communication between successive calls to `getopt'.
+
+   On entry to `getopt', zero means this is the first call; initialize.
+
+   When `getopt' returns EOF, this is the index of the first of the
+   non-option elements that the caller should itself scan.
+
+   Otherwise, `optind' communicates from one call to the next
+   how much of ARGV has been scanned so far.  */
+
+  extern int optind;
+
+/* Callers store zero here to inhibit the error message `getopt' prints
+   for unrecognized options.  */
+
+  extern int opterr;
+
+/* Set to an option character which was unrecognized.  */
+
+  extern int optopt;
+
+/* Describe the long-named options requested by the application.
+   The LONG_OPTIONS argument to getopt_long or getopt_long_only is a vector
+   of `struct option' terminated by an element containing a name which is
+   zero.
+
+   The field `has_arg' is:
+   no_argument          (or 0) if the option does not take an argument,
+   required_argument    (or 1) if the option requires an argument,
+   optional_argument    (or 2) if the option takes an optional argument.
+
+   If the field `flag' is not NULL, it points to a variable that is set
+   to the value given in the field `val' when the option is found, but
+   left unchanged if the option is not found.
+
+   To have a long-named option do something other than set an `int' to
+   a compiled-in constant, such as set a value from `optarg', set the
+   option's `flag' field to zero and its `val' field to a nonzero
+   value (the equivalent single-letter option character, if there is
+   one).  For long options that have a zero `flag' field, `getopt'
+   returns the contents of the `val' field.  */
+
+  struct option
+    {
+#if	__STDC__
+      const char *name;
+#else
+      char *name;
+#endif
+      /* has_arg can't be an enum because some compilers complain about
+         type mismatches in all the code that assumes it is an int.  */
+      int has_arg;
+      int *flag;
+      int val;
+    };
+
+/* Names for the values of the `has_arg' field of `struct option'.  */
+
+#define	no_argument		0
+#define required_argument	1
+#define optional_argument	2
+
+#if __STDC__
+#if defined(__GNU_LIBRARY__)
+/* Many other libraries have conflicting prototypes for getopt, with
+   differences in the consts, in stdlib.h.  To avoid compilation
+   errors, only prototype getopt for the GNU C library.  */
+  extern int getopt (int argc, char *const *argv, const char *shortopts);
+#else				/* not __GNU_LIBRARY__ */
+  extern int getopt ();
+#endif				/* not __GNU_LIBRARY__ */
+  extern int getopt_long (int argc, char *const *argv, const char *shortopts,
+			  const struct option *longopts, int *longind);
+  extern int getopt_long_only (int argc, char *const *argv,
+			       const char *shortopts,
+			       const struct option *longopts, int *longind);
+
+/* Internal only.  Users should not call this directly.  */
+  extern int _getopt_internal (int argc, char *const *argv,
+			       const char *shortopts,
+			       const struct option *longopts, int *longind,
+			       int long_only);
+#else				/* not __STDC__ */
+  extern int getopt ();
+  extern int getopt_long ();
+  extern int getopt_long_only ();
+
+  extern int _getopt_internal ();
+#endif				/* not __STDC__ */
+
+#ifdef	__cplusplus
+}
+#endif
+
+#endif				/* _GETOPT_H */
Index: /main/tags/2.25/gsdl/src/mgpp/lib/getopt1.cpp
===================================================================
--- /main/tags/2.25/gsdl/src/mgpp/lib/getopt1.cpp	(revision 21064)
+++ /main/tags/2.25/gsdl/src/mgpp/lib/getopt1.cpp	(revision 21064)
@@ -0,0 +1,178 @@
+/* getopt_long and getopt_long_only entry points for GNU getopt.
+   Copyright (C) 1987, 88, 89, 90, 91, 92, 1993
+   Free Software Foundation, Inc.
+
+   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, 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, 675 Mass Ave, Cambridge, MA 02139, USA.  */
+
+
+#ifdef HAVE_CONFIG_H
+#include "sysfuncs.h"
+#endif
+
+#include "getopt.h"
+
+#if !__STDC__ && !defined(const) && IN_GCC
+#define const
+#endif
+
+#include <stdio.h>
+
+/* Comment out all this code if we are using the GNU C Library, and are not
+   actually compiling the library itself.  This code is part of the GNU C
+   Library, but also included in many other GNU distributions.  Compiling
+   and linking in this code is a waste when using the GNU C library
+   (especially if it is a shared library).  Rather than having every GNU
+   program understand `configure --with-gnu-libc' and omit the object files,
+   it is simpler to just do this in the source for each such file.  */
+
+#if defined (_LIBC) || !defined (__GNU_LIBRARY__)
+
+
+/* This needs to come after some library #include
+   to get __GNU_LIBRARY__ defined.  */
+#ifdef __GNU_LIBRARY__
+#include <stdlib.h>
+#else
+char *getenv ();
+#endif
+
+#ifndef	NULL
+#define NULL 0
+#endif
+
+int
+getopt_long (argc, argv, options, long_options, opt_index)
+     int argc;
+     char *const *argv;
+     const char *options;
+     const struct option *long_options;
+     int *opt_index;
+{
+  return _getopt_internal (argc, argv, options, long_options, opt_index, 0);
+}
+
+/* Like getopt_long, but '-' as well as '--' can indicate a long option.
+   If an option that starts with '-' (not '--') doesn't match a long option,
+   but does match a short option, it is parsed as a short option
+   instead.  */
+
+int
+getopt_long_only (argc, argv, options, long_options, opt_index)
+     int argc;
+     char *const *argv;
+     const char *options;
+     const struct option *long_options;
+     int *opt_index;
+{
+  return _getopt_internal (argc, argv, options, long_options, opt_index, 1);
+}
+
+
+#endif /* _LIBC or not __GNU_LIBRARY__.  */
+
+
+#ifdef TEST
+
+#include <stdio.h>
+
+int
+main (argc, argv)
+     int argc;
+     char **argv;
+{
+  int c;
+  int digit_optind = 0;
+
+  while (1)
+    {
+      int this_option_optind = optind ? optind : 1;
+      int option_index = 0;
+      static struct option long_options[] =
+      {
+	{"add", 1, 0, 0},
+	{"append", 0, 0, 0},
+	{"delete", 1, 0, 0},
+	{"verbose", 0, 0, 0},
+	{"create", 0, 0, 0},
+	{"file", 1, 0, 0},
+	{0, 0, 0, 0}
+      };
+
+      c = getopt_long (argc, argv, "abc:d:0123456789",
+		       long_options, &option_index);
+      if (c == EOF)
+	break;
+
+      switch (c)
+	{
+	case 0:
+	  printf ("option %s", long_options[option_index].name);
+	  if (optarg)
+	    printf (" with arg %s", optarg);
+	  printf ("\n");
+	  break;
+
+	case '0':
+	case '1':
+	case '2':
+	case '3':
+	case '4':
+	case '5':
+	case '6':
+	case '7':
+	case '8':
+	case '9':
+	  if (digit_optind != 0 && digit_optind != this_option_optind)
+	    printf ("digits occur in two different argv-elements.\n");
+	  digit_optind = this_option_optind;
+	  printf ("option %c\n", c);
+	  break;
+
+	case 'a':
+	  printf ("option a\n");
+	  break;
+
+	case 'b':
+	  printf ("option b\n");
+	  break;
+
+	case 'c':
+	  printf ("option c with value `%s'\n", optarg);
+	  break;
+
+	case 'd':
+	  printf ("option d with value `%s'\n", optarg);
+	  break;
+
+	case '?':
+	  break;
+
+	default:
+	  printf ("?? getopt returned character code 0%o ??\n", c);
+	}
+    }
+
+  if (optind < argc)
+    {
+      printf ("non-option ARGV-elements: ");
+      while (optind < argc)
+	printf ("%s ", argv[optind++]);
+      printf ("\n");
+    }
+
+  exit (0);
+}
+
+#endif /* TEST */
Index: /main/tags/2.25/gsdl/src/mgpp/lib/getpagesize.h
===================================================================
--- /main/tags/2.25/gsdl/src/mgpp/lib/getpagesize.h	(revision 21064)
+++ /main/tags/2.25/gsdl/src/mgpp/lib/getpagesize.h	(revision 21064)
@@ -0,0 +1,38 @@
+/* Emulate getpagesize on systems that lack it.  */
+
+#ifndef HAVE_GETPAGESIZE
+
+#ifdef VMS
+#define getpagesize() 512
+#endif
+
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+
+#ifdef _SC_PAGESIZE
+#define getpagesize() sysconf(_SC_PAGESIZE)
+#else
+
+/* [RPAP - Feb 97: WIN32 Port] */
+#ifndef __WIN32__
+#include <sys/param.h>
+#endif
+
+#ifdef EXEC_PAGESIZE
+#define getpagesize() EXEC_PAGESIZE
+#else
+#ifdef NBPG
+#define getpagesize() NBPG * CLSIZE
+#ifndef CLSIZE
+#define CLSIZE 1
+#endif /* no CLSIZE */
+#else /* no NBPG */
+#ifdef NBPC
+#define getpagesize() NBPC
+#endif /* NBPC */
+#endif /* no NBPG */
+#endif /* no EXEC_PAGESIZE */
+#endif /* no _SC_PAGESIZE */
+
+#endif /* not HAVE_GETPAGESIZE */
Index: /main/tags/2.25/gsdl/src/mgpp/lib/gmalloc.c
===================================================================
--- /main/tags/2.25/gsdl/src/mgpp/lib/gmalloc.c	(revision 21064)
+++ /main/tags/2.25/gsdl/src/mgpp/lib/gmalloc.c	(revision 21064)
@@ -0,0 +1,1318 @@
+/* DO NOT EDIT THIS FILE -- it is automagically generated.  -*- C -*- */
+
+#define _MALLOC_INTERNAL
+
+/* The malloc headers and source files from the C library follow here.  */
+
+/* Declarations for `malloc' and friends.
+   Copyright 1990, 1991, 1992, 1993 Free Software Foundation, Inc.
+		  Written May 1989 by Mike Haertel.
+
+This library is free software; you can redistribute it and/or
+modify it under the terms of the GNU Library General Public License as
+published by the Free Software Foundation; either version 2 of the
+License, or (at your option) any later version.
+
+This library is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+Library General Public License for more details.
+
+You should have received a copy of the GNU Library General Public
+License along with this library; see the file COPYING.LIB.  If
+not, write to the Free Software Foundation, Inc., 675 Mass Ave,
+Cambridge, MA 02139, USA.
+
+   The author may be reached (Email) at the address mike@ai.mit.edu,
+   or (US mail) as Mike Haertel c/o Free Software Foundation.  */
+
+#ifndef _MALLOC_H
+
+#define _MALLOC_H	1
+
+#ifdef _MALLOC_INTERNAL
+
+#ifdef	HAVE_CONFIG_H
+#include <sysfuncs.h>
+#endif
+
+#if	defined(_LIBC) || defined(STDC_HEADERS) || defined(USG)
+#include <string.h>
+#else
+#ifndef memset
+#define	memset(s, zero, n)	bzero ((s), (n))
+#endif
+#ifndef memcpy
+#define	memcpy(d, s, n)		bcopy ((s), (d), (n))
+#endif
+#endif
+
+#if	defined(__GNU_LIBRARY__) || __STDC__
+#include <limits.h>
+#else
+#define	CHAR_BIT	8
+#endif
+
+#ifdef	HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+
+#endif	/* _MALLOC_INTERNAL.  */
+
+
+#ifdef	__cplusplus
+extern "C"
+{
+#endif
+
+#if defined (__cplusplus) || __STDC__
+#undef	__P
+#define	__P(args)	args
+#undef	__ptr_t
+#define	__ptr_t		void *
+#else /* Not C++ or ANSI C.  */
+#undef	__P
+#define	__P(args)	()
+#undef	const
+#define	const
+#undef	__ptr_t
+#define	__ptr_t		char *
+#endif /* C++ or ANSI C.  */
+
+#if	__STDC__
+#include <stddef.h>
+#else
+#undef	size_t
+#define	size_t		unsigned int
+#undef	ptrdiff_t
+#define	ptrdiff_t	int
+#endif
+
+#ifndef	NULL
+#define	NULL	0
+#endif
+
+
+/* Allocate SIZE bytes of memory.  */
+extern __ptr_t malloc __P ((size_t __size));
+/* Re-allocate the previously allocated block
+   in __ptr_t, making the new block SIZE bytes long.  */
+extern __ptr_t realloc __P ((__ptr_t __ptr, size_t __size));
+/* Allocate NMEMB elements of SIZE bytes each, all initialized to 0.  */
+extern __ptr_t calloc __P ((size_t __nmemb, size_t __size));
+/* Free a block allocated by `malloc', `realloc' or `calloc'.  */
+extern void free __P ((__ptr_t __ptr));
+
+/* Allocate SIZE bytes allocated to ALIGNMENT bytes.  */
+extern __ptr_t memalign __P ((size_t __alignment, size_t __size));
+
+/* Allocate SIZE bytes on a page boundary.  */
+extern __ptr_t valloc __P ((size_t __size));
+
+
+#ifdef _MALLOC_INTERNAL
+
+/* The allocator divides the heap into blocks of fixed size; large
+   requests receive one or more whole blocks, and small requests
+   receive a fragment of a block.  Fragment sizes are powers of two,
+   and all fragments of a block are the same size.  When all the
+   fragments in a block have been freed, the block itself is freed.  */
+#define INT_BIT		(CHAR_BIT * sizeof(int))
+#define BLOCKLOG	(INT_BIT > 16 ? 12 : 9)
+#define BLOCKSIZE	(1 << BLOCKLOG)
+#define BLOCKIFY(SIZE)	(((SIZE) + BLOCKSIZE - 1) / BLOCKSIZE)
+
+/* Determine the amount of memory spanned by the initial heap table
+   (not an absolute limit).  */
+#define HEAP		(INT_BIT > 16 ? 4194304 : 65536)
+
+/* Number of contiguous free blocks allowed to build up at the end of
+   memory before they will be returned to the system.  */
+#define FINAL_FREE_BLOCKS	8
+
+/* Data structure giving per-block information.  */
+typedef union
+  {
+    /* Heap information for a busy block.  */
+    struct
+      {
+	/* Zero for a large block, or positive giving the
+	   logarithm to the base two of the fragment size.  */
+	int type;
+	union
+	  {
+	    struct
+	      {
+		size_t nfree;	/* Free fragments in a fragmented block.  */
+		size_t first;	/* First free fragment of the block.  */
+	      } frag;
+	    /* Size (in blocks) of a large cluster.  */
+	    size_t size;
+	  } info;
+      } busy;
+    /* Heap information for a free block
+       (that may be the first of a free cluster).  */
+    struct
+      {
+	size_t size;		/* Size (in blocks) of a free cluster.  */
+	size_t next;		/* Index of next free cluster.  */
+	size_t prev;		/* Index of previous free cluster.  */
+      } free;
+  } malloc_info;
+
+/* Pointer to first block of the heap.  */
+extern char *_heapbase;
+
+/* Table indexed by block number giving per-block information.  */
+extern malloc_info *_heapinfo;
+
+/* Address to block number and vice versa.  */
+#define BLOCK(A)	(((char *) (A) - _heapbase) / BLOCKSIZE + 1)
+#define ADDRESS(B)	((__ptr_t) (((B) - 1) * BLOCKSIZE + _heapbase))
+
+/* Current search index for the heap table.  */
+extern size_t _heapindex;
+
+/* Limit of valid info table indices.  */
+extern size_t _heaplimit;
+
+/* Doubly linked lists of free fragments.  */
+struct list
+  {
+    struct list *next;
+    struct list *prev;
+  };
+
+/* Free list headers for each fragment size.  */
+extern struct list _fraghead[];
+
+/* List of blocks allocated with `memalign' (or `valloc').  */
+struct alignlist
+  {
+    struct alignlist *next;
+    __ptr_t aligned;		/* The address that memaligned returned.  */
+    __ptr_t exact;		/* The address that malloc returned.  */
+  };
+extern struct alignlist *_aligned_blocks;
+
+/* Instrumentation.  */
+extern size_t _chunks_used;
+extern size_t _bytes_used;
+extern size_t _chunks_free;
+extern size_t _bytes_free;
+
+/* Internal version of `free' used in `morecore' (malloc.c). */
+extern void _free_internal __P ((__ptr_t __ptr));
+
+#endif /* _MALLOC_INTERNAL.  */
+
+/* Underlying allocation function; successive calls should
+   return contiguous pieces of memory.  */
+extern __ptr_t (*__morecore) __P ((ptrdiff_t __size));
+
+/* Default value of `__morecore'.  */
+extern __ptr_t __default_morecore __P ((ptrdiff_t __size));
+
+/* If not NULL, this function is called after each time
+   `__morecore' is called to increase the data size.  */
+extern void (*__after_morecore_hook) __P ((void));
+
+/* Nonzero if `malloc' has been called and done its initialization.  */
+extern int __malloc_initialized;
+
+/* Hooks for debugging versions.  */
+extern void (*__free_hook) __P ((__ptr_t __ptr));
+extern __ptr_t (*__malloc_hook) __P ((size_t __size));
+extern __ptr_t (*__realloc_hook) __P ((__ptr_t __ptr, size_t __size));
+
+/* Return values for `mprobe': these are the kinds of inconsistencies that
+   `mcheck' enables detection of.  */
+enum mcheck_status
+  {
+    MCHECK_DISABLED = -1,	/* Consistency checking is not turned on.  */
+    MCHECK_OK,			/* Block is fine.  */
+    MCHECK_FREE,		/* Block freed twice.  */
+    MCHECK_HEAD,		/* Memory before the block was clobbered.  */
+    MCHECK_TAIL			/* Memory after the block was clobbered.  */
+  };
+
+/* Activate a standard collection of debugging hooks.  This must be called
+   before `malloc' is ever called.  ABORTFUNC is called with an error code
+   (see enum above) when an inconsistency is detected.  If ABORTFUNC is
+   null, the standard function prints on stderr and then calls `abort'.  */
+extern int mcheck __P ((void (*__abortfunc) __P ((enum mcheck_status))));
+
+/* Check for aberrations in a particular malloc'd block.  You must have
+   called `mcheck' already.  These are the same checks that `mcheck' does
+   when you free or reallocate a block.  */
+extern enum mcheck_status mprobe __P ((__ptr_t __ptr));
+
+/* Activate a standard collection of tracing hooks.  */
+extern void mtrace __P ((void));
+
+/* Statistics available to the user.  */
+struct mstats
+  {
+    size_t bytes_total;		/* Total size of the heap. */
+    size_t chunks_used;		/* Chunks allocated by the user. */
+    size_t bytes_used;		/* Byte total of user-allocated chunks. */
+    size_t chunks_free;		/* Chunks in the free list. */
+    size_t bytes_free;		/* Byte total of chunks in the free list. */
+  };
+
+/* Pick up the current statistics. */
+extern struct mstats mstats __P ((void));
+
+/* Call WARNFUN with a warning message when memory usage is high.  */
+extern void memory_warnings __P ((__ptr_t __start,
+				  void (*__warnfun) __P ((const char *))));
+
+
+/* Relocating allocator.  */
+
+/* Allocate SIZE bytes, and store the address in *HANDLEPTR.  */
+extern __ptr_t r_alloc __P ((__ptr_t *__handleptr, size_t __size));
+
+/* Free the storage allocated in HANDLEPTR.  */
+extern void r_alloc_free __P ((__ptr_t *__handleptr));
+
+/* Adjust the block at HANDLEPTR to be SIZE bytes long.  */
+extern __ptr_t r_re_alloc __P ((__ptr_t *__handleptr, size_t __size));
+
+
+#ifdef	__cplusplus
+}
+#endif
+
+#endif /* malloc.h  */
+/* Allocate memory on a page boundary.
+   Copyright (C) 1991, 1992, 1993 Free Software Foundation, Inc.
+
+This library is free software; you can redistribute it and/or
+modify it under the terms of the GNU Library General Public License as
+published by the Free Software Foundation; either version 2 of the
+License, or (at your option) any later version.
+
+This library is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+Library General Public License for more details.
+
+You should have received a copy of the GNU Library General Public
+License along with this library; see the file COPYING.LIB.  If
+not, write to the Free Software Foundation, Inc., 675 Mass Ave,
+Cambridge, MA 02139, USA.
+
+   The author may be reached (Email) at the address mike@ai.mit.edu,
+   or (US mail) as Mike Haertel c/o Free Software Foundation.  */
+
+#if defined (__GNU_LIBRARY__) || defined (_LIBC)
+#include <stddef.h>
+#include <sys/cdefs.h>
+extern size_t __getpagesize __P ((void));
+#else
+#include "getpagesize.h"
+#define	 __getpagesize()	getpagesize()
+#endif
+
+#ifndef	_MALLOC_INTERNAL
+#define	_MALLOC_INTERNAL
+#include <malloc.h>
+#endif
+
+static size_t pagesize;
+
+__ptr_t
+valloc (size)
+     size_t size;
+{
+  if (pagesize == 0)
+    pagesize = __getpagesize ();
+
+  return memalign (pagesize, size);
+}
+/* Memory allocator `malloc'.
+   Copyright 1990, 1991, 1992, 1993, 1994 Free Software Foundation
+		  Written May 1989 by Mike Haertel.
+
+This library is free software; you can redistribute it and/or
+modify it under the terms of the GNU Library General Public License as
+published by the Free Software Foundation; either version 2 of the
+License, or (at your option) any later version.
+
+This library is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+Library General Public License for more details.
+
+You should have received a copy of the GNU Library General Public
+License along with this library; see the file COPYING.LIB.  If
+not, write to the Free Software Foundation, Inc., 675 Mass Ave,
+Cambridge, MA 02139, USA.
+
+   The author may be reached (Email) at the address mike@ai.mit.edu,
+   or (US mail) as Mike Haertel c/o Free Software Foundation.  */
+
+#ifndef	_MALLOC_INTERNAL
+#define _MALLOC_INTERNAL
+#include <malloc.h>
+#endif
+
+/* How to really get more memory.  */
+__ptr_t (*__morecore) __P ((ptrdiff_t __size)) = __default_morecore;
+
+/* Debugging hook for `malloc'.  */
+__ptr_t (*__malloc_hook) __P ((size_t __size));
+
+/* Pointer to the base of the first block.  */
+char *_heapbase;
+
+/* Block information table.  Allocated with align/__free (not malloc/free).  */
+malloc_info *_heapinfo;
+
+/* Number of info entries.  */
+static size_t heapsize;
+
+/* Search index in the info table.  */
+size_t _heapindex;
+
+/* Limit of valid info table indices.  */
+size_t _heaplimit;
+
+/* Free lists for each fragment size.  */
+struct list _fraghead[BLOCKLOG];
+
+/* Instrumentation.  */
+size_t _chunks_used;
+size_t _bytes_used;
+size_t _chunks_free;
+size_t _bytes_free;
+
+/* Are you experienced?  */
+int __malloc_initialized;
+
+void (*__after_morecore_hook) __P ((void));
+
+/* Aligned allocation.  */
+static __ptr_t align __P ((size_t));
+static __ptr_t
+align (size)
+     size_t size;
+{
+  __ptr_t result;
+  unsigned long int adj;
+
+  result = (*__morecore) (size);
+  adj = (unsigned long int) ((unsigned long int) ((char *) result -
+						  (char *) NULL)) % BLOCKSIZE;
+  if (adj != 0)
+    {
+      adj = BLOCKSIZE - adj;
+      (void) (*__morecore) (adj);
+      result = (char *) result + adj;
+    }
+
+  if (__after_morecore_hook)
+    (*__after_morecore_hook) ();
+
+  return result;
+}
+
+/* Set everything up and remember that we have.  */
+static int initialize __P ((void));
+static int
+initialize ()
+{
+  heapsize = HEAP / BLOCKSIZE;
+  _heapinfo = (malloc_info *) align (heapsize * sizeof (malloc_info));
+  if (_heapinfo == NULL)
+    return 0;
+  memset (_heapinfo, 0, heapsize * sizeof (malloc_info));
+  _heapinfo[0].free.size = 0;
+  _heapinfo[0].free.next = _heapinfo[0].free.prev = 0;
+  _heapindex = 0;
+  _heapbase = (char *) _heapinfo;
+
+  /* Account for the _heapinfo block itself in the statistics.  */
+  _bytes_used = heapsize * sizeof (malloc_info);
+  _chunks_used = 1;
+
+  __malloc_initialized = 1;
+  return 1;
+}
+
+/* Get neatly aligned memory, initializing or
+   growing the heap info table as necessary. */
+static __ptr_t morecore __P ((size_t));
+static __ptr_t
+morecore (size)
+     size_t size;
+{
+  __ptr_t result;
+  malloc_info *newinfo, *oldinfo;
+  size_t newsize;
+
+  result = align (size);
+  if (result == NULL)
+    return NULL;
+
+  /* Check if we need to grow the info table.  */
+  if ((size_t) BLOCK ((char *) result + size) > heapsize)
+    {
+      newsize = heapsize;
+      while ((size_t) BLOCK ((char *) result + size) > newsize)
+	newsize *= 2;
+      newinfo = (malloc_info *) align (newsize * sizeof (malloc_info));
+      if (newinfo == NULL)
+	{
+	  (*__morecore) (-size);
+	  return NULL;
+	}
+      memcpy (newinfo, _heapinfo, heapsize * sizeof (malloc_info));
+      memset (&newinfo[heapsize], 0,
+	      (newsize - heapsize) * sizeof (malloc_info));
+      oldinfo = _heapinfo;
+      newinfo[BLOCK (oldinfo)].busy.type = 0;
+      newinfo[BLOCK (oldinfo)].busy.info.size
+	= BLOCKIFY (heapsize * sizeof (malloc_info));
+      _heapinfo = newinfo;
+      /* Account for the _heapinfo block itself in the statistics.  */
+      _bytes_used += newsize * sizeof (malloc_info);
+      ++_chunks_used;
+      _free_internal (oldinfo);
+      heapsize = newsize;
+    }
+
+  _heaplimit = BLOCK ((char *) result + size);
+  return result;
+}
+
+/* Allocate memory from the heap.  */
+__ptr_t
+malloc (size)
+     size_t size;
+{
+  __ptr_t result;
+  size_t block, blocks, lastblocks, start;
+  register size_t i;
+  struct list *next;
+
+  /* ANSI C allows `malloc (0)' to either return NULL, or to return a
+     valid address you can realloc and free (though not dereference).
+
+     It turns out that some extant code (sunrpc, at least Ultrix's version)
+     expects `malloc (0)' to return non-NULL and breaks otherwise.
+     Be compatible.  */
+
+#if	0
+  if (size == 0)
+    return NULL;
+#endif
+
+  if (__malloc_hook != NULL)
+    return (*__malloc_hook) (size);
+
+  if (!__malloc_initialized)
+    if (!initialize ())
+      return NULL;
+
+  if (size < sizeof (struct list))
+      size = sizeof (struct list);
+
+#ifdef SUNOS_LOCALTIME_BUG
+  if (size < 16)
+    size = 16;
+#endif
+
+  /* Determine the allocation policy based on the request size.  */
+  if (size <= BLOCKSIZE / 2)
+    {
+      /* Small allocation to receive a fragment of a block.
+	 Determine the logarithm to base two of the fragment size. */
+      register size_t log = 1;
+      --size;
+      while ((size /= 2) != 0)
+	++log;
+
+      /* Look in the fragment lists for a
+	 free fragment of the desired size. */
+      next = _fraghead[log].next;
+      if (next != NULL)
+	{
+	  /* There are free fragments of this size.
+	     Pop a fragment out of the fragment list and return it.
+	     Update the block's nfree and first counters. */
+	  result = (__ptr_t) next;
+	  next->prev->next = next->next;
+	  if (next->next != NULL)
+	    next->next->prev = next->prev;
+	  block = BLOCK (result);
+	  if (--_heapinfo[block].busy.info.frag.nfree != 0)
+	    _heapinfo[block].busy.info.frag.first = (unsigned long int)
+	      ((unsigned long int) ((char *) next->next - (char *) NULL)
+	       % BLOCKSIZE) >> log;
+
+	  /* Update the statistics.  */
+	  ++_chunks_used;
+	  _bytes_used += 1 << log;
+	  --_chunks_free;
+	  _bytes_free -= 1 << log;
+	}
+      else
+	{
+	  /* No free fragments of the desired size, so get a new block
+	     and break it into fragments, returning the first.  */
+	  result = malloc (BLOCKSIZE);
+	  if (result == NULL)
+	    return NULL;
+
+	  /* Link all fragments but the first into the free list.  */
+	  for (i = 1; i < (size_t) (BLOCKSIZE >> log); ++i)
+	    {
+	      next = (struct list *) ((char *) result + (i << log));
+	      next->next = _fraghead[log].next;
+	      next->prev = &_fraghead[log];
+	      next->prev->next = next;
+	      if (next->next != NULL)
+		next->next->prev = next;
+	    }
+
+	  /* Initialize the nfree and first counters for this block.  */
+	  block = BLOCK (result);
+	  _heapinfo[block].busy.type = log;
+	  _heapinfo[block].busy.info.frag.nfree = i - 1;
+	  _heapinfo[block].busy.info.frag.first = i - 1;
+
+	  _chunks_free += (BLOCKSIZE >> log) - 1;
+	  _bytes_free += BLOCKSIZE - (1 << log);
+	  _bytes_used -= BLOCKSIZE - (1 << log);
+	}
+    }
+  else
+    {
+      /* Large allocation to receive one or more blocks.
+	 Search the free list in a circle starting at the last place visited.
+	 If we loop completely around without finding a large enough
+	 space we will have to get more memory from the system.  */
+      blocks = BLOCKIFY (size);
+      start = block = _heapindex;
+      while (_heapinfo[block].free.size < blocks)
+	{
+	  block = _heapinfo[block].free.next;
+	  if (block == start)
+	    {
+	      /* Need to get more from the system.  Check to see if
+		 the new core will be contiguous with the final free
+		 block; if so we don't need to get as much.  */
+	      block = _heapinfo[0].free.prev;
+	      lastblocks = _heapinfo[block].free.size;
+	      if (_heaplimit != 0 && block + lastblocks == _heaplimit &&
+		  (*__morecore) (0) == ADDRESS (block + lastblocks) &&
+		  (morecore ((blocks - lastblocks) * BLOCKSIZE)) != NULL)
+		{
+ 		  /* Which block we are extending (the `final free
+ 		     block' referred to above) might have changed, if
+ 		     it got combined with a freed info table.  */
+ 		  block = _heapinfo[0].free.prev;
+  		  _heapinfo[block].free.size += (blocks - lastblocks);
+		  _bytes_free += (blocks - lastblocks) * BLOCKSIZE;
+		  continue;
+		}
+	      result = morecore (blocks * BLOCKSIZE);
+	      if (result == NULL)
+		return NULL;
+	      block = BLOCK (result);
+	      _heapinfo[block].busy.type = 0;
+	      _heapinfo[block].busy.info.size = blocks;
+	      ++_chunks_used;
+	      _bytes_used += blocks * BLOCKSIZE;
+	      return result;
+	    }
+	}
+
+      /* At this point we have found a suitable free list entry.
+	 Figure out how to remove what we need from the list. */
+      result = ADDRESS (block);
+      if (_heapinfo[block].free.size > blocks)
+	{
+	  /* The block we found has a bit left over,
+	     so relink the tail end back into the free list. */
+	  _heapinfo[block + blocks].free.size
+	    = _heapinfo[block].free.size - blocks;
+	  _heapinfo[block + blocks].free.next
+	    = _heapinfo[block].free.next;
+	  _heapinfo[block + blocks].free.prev
+	    = _heapinfo[block].free.prev;
+	  _heapinfo[_heapinfo[block].free.prev].free.next
+	    = _heapinfo[_heapinfo[block].free.next].free.prev
+	    = _heapindex = block + blocks;
+	}
+      else
+	{
+	  /* The block exactly matches our requirements,
+	     so just remove it from the list. */
+	  _heapinfo[_heapinfo[block].free.next].free.prev
+	    = _heapinfo[block].free.prev;
+	  _heapinfo[_heapinfo[block].free.prev].free.next
+	    = _heapindex = _heapinfo[block].free.next;
+	  --_chunks_free;
+	}
+
+      _heapinfo[block].busy.type = 0;
+      _heapinfo[block].busy.info.size = blocks;
+      ++_chunks_used;
+      _bytes_used += blocks * BLOCKSIZE;
+      _bytes_free -= blocks * BLOCKSIZE;
+    }
+
+  return result;
+}
+
+
+#ifndef _LIBC
+
+/* On some ANSI C systems, some libc functions call _malloc, _free
+   and _realloc.  Make them use the GNU functions.  */
+
+__ptr_t
+_malloc (size)
+     size_t size;
+{
+  return malloc (size);
+}
+
+void
+_free (ptr)
+     __ptr_t ptr;
+{
+  free (ptr);
+}
+
+__ptr_t
+_realloc (ptr, size)
+     __ptr_t ptr;
+     size_t size;
+{
+  return realloc (ptr, size);
+}
+
+#endif
+/* Free a block of memory allocated by `malloc'.
+   Copyright 1990, 1991, 1992 Free Software Foundation
+		  Written May 1989 by Mike Haertel.
+
+This library is free software; you can redistribute it and/or
+modify it under the terms of the GNU Library General Public License as
+published by the Free Software Foundation; either version 2 of the
+License, or (at your option) any later version.
+
+This library is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+Library General Public License for more details.
+
+You should have received a copy of the GNU Library General Public
+License along with this library; see the file COPYING.LIB.  If
+not, write to the Free Software Foundation, Inc., 675 Mass Ave,
+Cambridge, MA 02139, USA.
+
+   The author may be reached (Email) at the address mike@ai.mit.edu,
+   or (US mail) as Mike Haertel c/o Free Software Foundation.  */
+
+#ifndef	_MALLOC_INTERNAL
+#define _MALLOC_INTERNAL
+#include <malloc.h>
+#endif
+
+/* Debugging hook for free.  */
+void (*__free_hook) __P ((__ptr_t __ptr));
+
+/* List of blocks allocated by memalign.  */
+struct alignlist *_aligned_blocks = NULL;
+
+/* Return memory to the heap.
+   Like `free' but don't call a __free_hook if there is one.  */
+void
+_free_internal (ptr)
+     __ptr_t ptr;
+{
+  int type;
+  size_t block, blocks;
+  register size_t i;
+  struct list *prev, *next;
+
+  block = BLOCK (ptr);
+
+  type = _heapinfo[block].busy.type;
+  switch (type)
+    {
+    case 0:
+      /* Get as many statistics as early as we can.  */
+      --_chunks_used;
+      _bytes_used -= _heapinfo[block].busy.info.size * BLOCKSIZE;
+      _bytes_free += _heapinfo[block].busy.info.size * BLOCKSIZE;
+
+      /* Find the free cluster previous to this one in the free list.
+	 Start searching at the last block referenced; this may benefit
+	 programs with locality of allocation.  */
+      i = _heapindex;
+      if (i > block)
+	while (i > block)
+	  i = _heapinfo[i].free.prev;
+      else
+	{
+	  do
+	    i = _heapinfo[i].free.next;
+	  while (i > 0 && i < block);
+	  i = _heapinfo[i].free.prev;
+	}
+
+      /* Determine how to link this block into the free list.  */
+      if (block == i + _heapinfo[i].free.size)
+	{
+	  /* Coalesce this block with its predecessor.  */
+	  _heapinfo[i].free.size += _heapinfo[block].busy.info.size;
+	  block = i;
+	}
+      else
+	{
+	  /* Really link this block back into the free list.  */
+	  _heapinfo[block].free.size = _heapinfo[block].busy.info.size;
+	  _heapinfo[block].free.next = _heapinfo[i].free.next;
+	  _heapinfo[block].free.prev = i;
+	  _heapinfo[i].free.next = block;
+	  _heapinfo[_heapinfo[block].free.next].free.prev = block;
+	  ++_chunks_free;
+	}
+
+      /* Now that the block is linked in, see if we can coalesce it
+	 with its successor (by deleting its successor from the list
+	 and adding in its size).  */
+      if (block + _heapinfo[block].free.size == _heapinfo[block].free.next)
+	{
+	  _heapinfo[block].free.size
+	    += _heapinfo[_heapinfo[block].free.next].free.size;
+	  _heapinfo[block].free.next
+	    = _heapinfo[_heapinfo[block].free.next].free.next;
+	  _heapinfo[_heapinfo[block].free.next].free.prev = block;
+	  --_chunks_free;
+	}
+
+      /* Now see if we can return stuff to the system.  */
+      blocks = _heapinfo[block].free.size;
+      if (blocks >= FINAL_FREE_BLOCKS && block + blocks == _heaplimit
+	  && (*__morecore) (0) == ADDRESS (block + blocks))
+	{
+	  register size_t bytes = blocks * BLOCKSIZE;
+	  _heaplimit -= blocks;
+	  (*__morecore) (-bytes);
+	  _heapinfo[_heapinfo[block].free.prev].free.next
+	    = _heapinfo[block].free.next;
+	  _heapinfo[_heapinfo[block].free.next].free.prev
+	    = _heapinfo[block].free.prev;
+	  block = _heapinfo[block].free.prev;
+	  --_chunks_free;
+	  _bytes_free -= bytes;
+	}
+
+      /* Set the next search to begin at this block.  */
+      _heapindex = block;
+      break;
+
+    default:
+      /* Do some of the statistics.  */
+      --_chunks_used;
+      _bytes_used -= 1 << type;
+      ++_chunks_free;
+      _bytes_free += 1 << type;
+
+      /* Get the address of the first free fragment in this block.  */
+      prev = (struct list *) ((char *) ADDRESS (block) +
+			   (_heapinfo[block].busy.info.frag.first << type));
+
+      if (_heapinfo[block].busy.info.frag.nfree == (BLOCKSIZE >> type) - 1)
+	{
+	  /* If all fragments of this block are free, remove them
+	     from the fragment list and free the whole block.  */
+	  next = prev;
+	  for (i = 1; i < (size_t) (BLOCKSIZE >> type); ++i)
+	    next = next->next;
+	  prev->prev->next = next;
+	  if (next != NULL)
+	    next->prev = prev->prev;
+	  _heapinfo[block].busy.type = 0;
+	  _heapinfo[block].busy.info.size = 1;
+
+	  /* Keep the statistics accurate.  */
+	  ++_chunks_used;
+	  _bytes_used += BLOCKSIZE;
+	  _chunks_free -= BLOCKSIZE >> type;
+	  _bytes_free -= BLOCKSIZE;
+
+	  free (ADDRESS (block));
+	}
+      else if (_heapinfo[block].busy.info.frag.nfree != 0)
+	{
+	  /* If some fragments of this block are free, link this
+	     fragment into the fragment list after the first free
+	     fragment of this block. */
+	  next = (struct list *) ptr;
+	  next->next = prev->next;
+	  next->prev = prev;
+	  prev->next = next;
+	  if (next->next != NULL)
+	    next->next->prev = next;
+	  ++_heapinfo[block].busy.info.frag.nfree;
+	}
+      else
+	{
+	  /* No fragments of this block are free, so link this
+	     fragment into the fragment list and announce that
+	     it is the first free fragment of this block. */
+	  prev = (struct list *) ptr;
+	  _heapinfo[block].busy.info.frag.nfree = 1;
+	  _heapinfo[block].busy.info.frag.first = (unsigned long int)
+	    ((unsigned long int) ((char *) ptr - (char *) NULL)
+	     % BLOCKSIZE >> type);
+	  prev->next = _fraghead[type].next;
+	  prev->prev = &_fraghead[type];
+	  prev->prev->next = prev;
+	  if (prev->next != NULL)
+	    prev->next->prev = prev;
+	}
+      break;
+    }
+}
+
+/* Return memory to the heap.  */
+void
+free (ptr)
+     __ptr_t ptr;
+{
+  register struct alignlist *l;
+
+  if (ptr == NULL)
+    return;
+
+  for (l = _aligned_blocks; l != NULL; l = l->next)
+    if (l->aligned == ptr)
+      {
+	l->aligned = NULL;	/* Mark the slot in the list as free.  */
+	ptr = l->exact;
+	break;
+      }
+
+  if (__free_hook != NULL)
+    (*__free_hook) (ptr);
+  else
+    _free_internal (ptr);
+}
+/* Copyright (C) 1991, 1993, 1994 Free Software Foundation, Inc.
+This file is part of the GNU C Library.
+
+The GNU C Library is free software; you can redistribute it and/or
+modify it under the terms of the GNU Library General Public License as
+published by the Free Software Foundation; either version 2 of the
+License, or (at your option) any later version.
+
+The GNU C Library is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+Library General Public License for more details.
+
+You should have received a copy of the GNU Library General Public
+License along with the GNU C Library; see the file COPYING.LIB.  If
+not, write to the Free Software Foundation, Inc., 675 Mass Ave,
+Cambridge, MA 02139, USA.  */
+
+#ifndef	_MALLOC_INTERNAL
+#define _MALLOC_INTERNAL
+#include <malloc.h>
+#endif
+
+#ifdef _LIBC
+
+#include <ansidecl.h>
+#include <gnu-stabs.h>
+
+#undef	cfree
+
+function_alias(cfree, free, void, (ptr),
+	       DEFUN(cfree, (ptr), PTR ptr))
+
+#else
+
+void
+cfree (ptr)
+     __ptr_t ptr;
+{
+  free (ptr);
+}
+
+#endif
+/* Change the size of a block allocated by `malloc'.
+   Copyright 1990, 1991, 1992, 1993, 1994 Free Software Foundation, Inc.
+		     Written May 1989 by Mike Haertel.
+
+This library is free software; you can redistribute it and/or
+modify it under the terms of the GNU Library General Public License as
+published by the Free Software Foundation; either version 2 of the
+License, or (at your option) any later version.
+
+This library is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+Library General Public License for more details.
+
+You should have received a copy of the GNU Library General Public
+License along with this library; see the file COPYING.LIB.  If
+not, write to the Free Software Foundation, Inc., 675 Mass Ave,
+Cambridge, MA 02139, USA.
+
+   The author may be reached (Email) at the address mike@ai.mit.edu,
+   or (US mail) as Mike Haertel c/o Free Software Foundation.  */
+
+#ifndef	_MALLOC_INTERNAL
+#define _MALLOC_INTERNAL
+#include <malloc.h>
+#endif
+
+#if  (defined (MEMMOVE_MISSING) || \
+      !defined(_LIBC) && !defined(STDC_HEADERS) && !defined(USG))
+
+/* Snarfed directly from Emacs src/dispnew.c:
+   XXX Should use system bcopy if it handles overlap.  */
+#ifndef emacs
+
+/* Like bcopy except never gets confused by overlap.  */
+
+static void
+safe_bcopy (from, to, size)
+     char *from, *to;
+     int size;
+{
+  if (size <= 0 || from == to)
+    return;
+
+  /* If the source and destination don't overlap, then bcopy can
+     handle it.  If they do overlap, but the destination is lower in
+     memory than the source, we'll assume bcopy can handle that.  */
+  if (to < from || from + size <= to)
+    bcopy (from, to, size);
+
+  /* Otherwise, we'll copy from the end.  */
+  else
+    {
+      register char *endf = from + size;
+      register char *endt = to + size;
+
+      /* If TO - FROM is large, then we should break the copy into
+	 nonoverlapping chunks of TO - FROM bytes each.  However, if
+	 TO - FROM is small, then the bcopy function call overhead
+	 makes this not worth it.  The crossover point could be about
+	 anywhere.  Since I don't think the obvious copy loop is too
+	 bad, I'm trying to err in its favor.  */
+      if (to - from < 64)
+	{
+	  do
+	    *--endt = *--endf;
+	  while (endf != from);
+	}
+      else
+	{
+	  for (;;)
+	    {
+	      endt -= (to - from);
+	      endf -= (to - from);
+
+	      if (endt < to)
+		break;
+
+	      bcopy (endf, endt, to - from);
+	    }
+
+	  /* If SIZE wasn't a multiple of TO - FROM, there will be a
+	     little left over.  The amount left over is
+	     (endt + (to - from)) - to, which is endt - from.  */
+	  bcopy (from, to, endt - from);
+	}
+    }
+}     
+#endif	/* Not emacs.  */
+
+#define memmove(to, from, size) safe_bcopy ((from), (to), (size))
+
+#endif
+
+
+#define min(A, B) ((A) < (B) ? (A) : (B))
+
+/* Debugging hook for realloc.  */
+__ptr_t (*__realloc_hook) __P ((__ptr_t __ptr, size_t __size));
+
+/* Resize the given region to the new size, returning a pointer
+   to the (possibly moved) region.  This is optimized for speed;
+   some benchmarks seem to indicate that greater compactness is
+   achieved by unconditionally allocating and copying to a
+   new region.  This module has incestuous knowledge of the
+   internals of both free and malloc. */
+__ptr_t
+realloc (ptr, size)
+     __ptr_t ptr;
+     size_t size;
+{
+  __ptr_t result;
+  int type;
+  size_t block, blocks, oldlimit;
+
+  if (size == 0)
+    {
+      free (ptr);
+      return malloc (0);
+    }
+  else if (ptr == NULL)
+    return malloc (size);
+
+  if (__realloc_hook != NULL)
+    return (*__realloc_hook) (ptr, size);
+
+  block = BLOCK (ptr);
+
+  type = _heapinfo[block].busy.type;
+  switch (type)
+    {
+    case 0:
+      /* Maybe reallocate a large block to a small fragment.  */
+      if (size <= BLOCKSIZE / 2)
+	{
+	  result = malloc (size);
+	  if (result != NULL)
+	    {
+	      memcpy (result, ptr, size);
+	      _free_internal (ptr);
+	      return result;
+	    }
+	}
+
+      /* The new size is a large allocation as well;
+	 see if we can hold it in place. */
+      blocks = BLOCKIFY (size);
+      if (blocks < _heapinfo[block].busy.info.size)
+	{
+	  /* The new size is smaller; return
+	     excess memory to the free list. */
+	  _heapinfo[block + blocks].busy.type = 0;
+	  _heapinfo[block + blocks].busy.info.size
+	    = _heapinfo[block].busy.info.size - blocks;
+	  _heapinfo[block].busy.info.size = blocks;
+	  /* We have just created a new chunk by splitting a chunk in two.
+	     Now we will free this chunk; increment the statistics counter
+	     so it doesn't become wrong when _free_internal decrements it.  */
+	  ++_chunks_used;
+	  _free_internal (ADDRESS (block + blocks));
+	  result = ptr;
+	}
+      else if (blocks == _heapinfo[block].busy.info.size)
+	/* No size change necessary.  */
+	result = ptr;
+      else
+	{
+	  /* Won't fit, so allocate a new region that will.
+	     Free the old region first in case there is sufficient
+	     adjacent free space to grow without moving. */
+	  blocks = _heapinfo[block].busy.info.size;
+	  /* Prevent free from actually returning memory to the system.  */
+	  oldlimit = _heaplimit;
+	  _heaplimit = 0;
+	  _free_internal (ptr);
+	  _heaplimit = oldlimit;
+	  result = malloc (size);
+	  if (result == NULL)
+	    {
+	      /* Now we're really in trouble.  We have to unfree
+		 the thing we just freed.  Unfortunately it might
+		 have been coalesced with its neighbors.  */
+	      if (_heapindex == block)
+	        (void) malloc (blocks * BLOCKSIZE);
+	      else
+		{
+		  __ptr_t previous = malloc ((block - _heapindex) * BLOCKSIZE);
+		  (void) malloc (blocks * BLOCKSIZE);
+		  _free_internal (previous);
+		}
+	      return NULL;
+	    }
+	  if (ptr != result)
+	    memmove (result, ptr, blocks * BLOCKSIZE);
+	}
+      break;
+
+    default:
+      /* Old size is a fragment; type is logarithm
+	 to base two of the fragment size.  */
+      if (size > (size_t) (1 << (type - 1)) && size <= (size_t) (1 << type))
+	/* The new size is the same kind of fragment.  */
+	result = ptr;
+      else
+	{
+	  /* The new size is different; allocate a new space,
+	     and copy the lesser of the new size and the old. */
+	  result = malloc (size);
+	  if (result == NULL)
+	    return NULL;
+	  memcpy (result, ptr, min (size, (size_t) 1 << type));
+	  free (ptr);
+	}
+      break;
+    }
+
+  return result;
+}
+/* Copyright (C) 1991, 1992 Free Software Foundation, Inc.
+
+This library is free software; you can redistribute it and/or
+modify it under the terms of the GNU Library General Public License as
+published by the Free Software Foundation; either version 2 of the
+License, or (at your option) any later version.
+
+This library is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+Library General Public License for more details.
+
+You should have received a copy of the GNU Library General Public
+License along with this library; see the file COPYING.LIB.  If
+not, write to the Free Software Foundation, Inc., 675 Mass Ave,
+Cambridge, MA 02139, USA.
+
+   The author may be reached (Email) at the address mike@ai.mit.edu,
+   or (US mail) as Mike Haertel c/o Free Software Foundation.  */
+
+#ifndef	_MALLOC_INTERNAL
+#define	_MALLOC_INTERNAL
+#include <malloc.h>
+#endif
+
+/* Allocate an array of NMEMB elements each SIZE bytes long.
+   The entire array is initialized to zeros.  */
+__ptr_t
+calloc (nmemb, size)
+     register size_t nmemb;
+     register size_t size;
+{
+  register __ptr_t result = malloc (nmemb * size);
+
+  if (result != NULL)
+    (void) memset (result, 0, nmemb * size);
+
+  return result;
+}
+/* Copyright (C) 1991, 1992, 1993 Free Software Foundation, Inc.
+This file is part of the GNU C Library.
+
+The GNU C Library 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, or (at your option)
+any later version.
+
+The GNU C Library is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with the GNU C Library; see the file COPYING.  If not, write to
+the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.  */
+
+#ifndef	_MALLOC_INTERNAL
+#define	_MALLOC_INTERNAL
+#include <malloc.h>
+#endif
+
+#ifndef	__GNU_LIBRARY__
+#define	__sbrk	sbrk
+#endif
+
+#ifdef __GNU_LIBRARY__
+/* It is best not to declare this and cast its result on foreign operating
+   systems with potentially hostile include files.  */
+extern __ptr_t __sbrk __P ((int increment));
+#endif
+
+#ifndef NULL
+#define NULL 0
+#endif
+
+/* Allocate INCREMENT more bytes of data space,
+   and return the start of data space, or NULL on errors.
+   If INCREMENT is negative, shrink data space.  */
+__ptr_t
+__default_morecore (increment)
+     ptrdiff_t increment;
+{
+  __ptr_t result = (__ptr_t) __sbrk ((int) increment);
+  if (result == (__ptr_t) -1)
+    return NULL;
+  return result;
+}
+/* Copyright (C) 1991, 1992, 1993 Free Software Foundation, Inc.
+
+This library is free software; you can redistribute it and/or
+modify it under the terms of the GNU Library General Public License as
+published by the Free Software Foundation; either version 2 of the
+License, or (at your option) any later version.
+
+This library is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+Library General Public License for more details.
+
+You should have received a copy of the GNU Library General Public
+License along with this library; see the file COPYING.LIB.  If
+not, write to the Free Software Foundation, Inc., 675 Mass Ave,
+Cambridge, MA 02139, USA.  */
+
+#ifndef	_MALLOC_INTERNAL
+#define _MALLOC_INTERNAL
+#include <malloc.h>
+#endif
+
+__ptr_t
+memalign (alignment, size)
+     size_t alignment;
+     size_t size;
+{
+  __ptr_t result;
+  unsigned long int adj;
+
+  size = ((size + alignment - 1) / alignment) * alignment;
+
+  result = malloc (size);
+  if (result == NULL)
+    return NULL;
+  adj = (unsigned long int) ((unsigned long int) ((char *) result -
+						  (char *) NULL)) % alignment;
+  if (adj != 0)
+    {
+      struct alignlist *l;
+      for (l = _aligned_blocks; l != NULL; l = l->next)
+	if (l->aligned == NULL)
+	  /* This slot is free.  Use it.  */
+	  break;
+      if (l == NULL)
+	{
+	  l = (struct alignlist *) malloc (sizeof (struct alignlist));
+	  if (l == NULL)
+	    {
+	      free (result);
+	      return NULL;
+	    }
+	  l->next = _aligned_blocks;
+	  _aligned_blocks = l;
+	}
+      l->exact = result;
+      result = l->aligned = (char *) result + alignment - adj;
+    }
+
+  return result;
+}
Index: /main/tags/2.25/gsdl/src/mgpp/lib/huffman.cpp
===================================================================
--- /main/tags/2.25/gsdl/src/mgpp/lib/huffman.cpp	(revision 21064)
+++ /main/tags/2.25/gsdl/src/mgpp/lib/huffman.cpp	(revision 21064)
@@ -0,0 +1,411 @@
+/**************************************************************************
+ *
+ * huffman.c -- Huffman coding functions
+ * Copyright (C) 1994  Neil Sharman
+ *
+ * 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.
+ *
+ * $Id$
+ *
+ **************************************************************************/
+
+/*
+   $Log$
+   Revision 1.1  2000/01/14 02:17:06  sjboddie
+   Rodgers new C++ mg
+
+   Revision 1.2  1999/10/17 23:39:13  cs025
+   Changes to eradicate Xmalloc etc
+
+   Revision 1.1  1999/10/11 02:55:09  cs025
+   Base install of MG-PP
+
+   Revision 1.1  1999/08/10 21:16:51  sjboddie
+   renamed mg-1.3d directory mg
+
+   Revision 1.1  1998/11/17 09:32:03  rjmcnab
+   *** empty log message ***
+
+   * Revision 1.1  1994/08/22  00:24:44  tes
+   * Initial placement under CVS.
+   *
+ */
+
+static char *RCSID = "$Id$";
+
+#include "sysfuncs.h"
+#include "memlib.h"
+#include "huffman.h"
+#include "messages.h"
+#include "netorder.h"  /* [RPAP - Jan 97: Endian Ordering] */
+
+/* ->data on success,  
+   NULL on error 
+ */
+huff_data *
+Generate_Huffman_Data (int num, long *freqs, huff_data * data,
+		       u_long * mem)
+{
+  int HNum, i, count;
+  unsigned long *heap;
+  huff_data *hd = data;
+  if (!hd)
+    {
+      if (!(hd = new huff_data))
+	goto error0;
+    }
+  if (!(heap = new (unsigned long)[num * 2]))
+    goto error1;
+  if (!(hd->clens = new char[num]))
+      goto error2;
+  hd->num_codes = num;
+  if (mem)
+    {
+      if (hd != data)
+	*mem += sizeof (huff_data);
+      *mem += num * sizeof (char);
+    }
+  bcopy ((void *) freqs, (void *) &heap[num], num * sizeof (*heap));
+  bzero ((char *) heap, num * sizeof (*heap));
+
+  /* Initialise the pointers to the leaves */
+  for (count = i = 0; i < num; i++)
+    if (heap[num + i])
+      heap[count++] = num + i;
+
+  /* Reorganise the pointers so that it is a heap */
+  HNum = count;
+  for (i = HNum / 2; i > 0; i--)
+    {
+      register int curr, child;
+      curr = i;
+      child = curr * 2;
+      while (child <= HNum)
+	{
+	  if (child < HNum && heap[heap[child]] < heap[heap[child - 1]])
+	    child++;
+	  if (heap[heap[curr - 1]] > heap[heap[child - 1]])
+	    {
+	      register u_long temp;
+	      temp = heap[child - 1];
+	      heap[child - 1] = heap[curr - 1];
+	      heap[curr - 1] = temp;
+	      curr = child;
+	      child = 2 * curr;
+	    }
+	  else
+	    break;
+	}
+    }
+
+
+  /* Form the huffman tree */
+  while (HNum > 1)
+    {
+      int pos[2];
+
+      for (i = 0; i < 2; i++)
+	{
+	  register int curr, child;
+	  pos[i] = heap[0];
+	  heap[0] = heap[--HNum];
+	  curr = 1;
+	  child = 2;
+	  while (child <= HNum)
+	    {
+	      if (child < HNum &&
+		  heap[heap[child]] < heap[heap[child - 1]])
+		child++;
+	      if (heap[heap[curr - 1]] > heap[heap[child - 1]])
+		{
+		  register int temp;
+		  temp = heap[child - 1];
+		  heap[child - 1] = heap[curr - 1];
+		  heap[curr - 1] = temp;
+		  curr = child;
+		  child = 2 * curr;
+		}
+	      else
+		break;
+	    }
+	}
+
+      heap[HNum + 1] = heap[pos[0]] + heap[pos[1]];
+      heap[pos[0]] = heap[pos[1]] = HNum + 1;
+
+      heap[HNum] = HNum + 1;
+
+      {
+	register int parent, curr;
+	HNum++;
+	curr = HNum;
+	parent = curr >> 1;
+	while (parent && heap[heap[parent - 1]] > heap[heap[curr - 1]])
+	  {
+	    register int temp;
+	    temp = heap[parent - 1];
+	    heap[parent - 1] = heap[curr - 1];
+	    heap[curr - 1] = temp;
+	    curr = parent;
+	    parent = curr >> 1;
+	  }
+      }
+    }
+
+
+  /* Calculate the code lens */
+  heap[0] = -1UL;
+  heap[1] = 0;
+  for (i = 2; i < num * 2; i++)
+    heap[i] = heap[heap[i]] + 1;
+
+  /* zero the lencount's array */
+  bzero ((char *) hd->lencount, sizeof (hd->lencount));
+  hd->maxcodelen = 0;
+  hd->mincodelen = 100;
+
+  /* Set the code length of each leaf in the huffman tree */
+  for (i = 0; i < num; i++)
+    {
+      register u_long codelen = heap[i + num];
+      hd->clens[i] = (char) codelen;
+      if (!codelen)
+	continue;
+      if (codelen > hd->maxcodelen)
+	hd->maxcodelen = codelen;
+      if (codelen < hd->mincodelen)
+	hd->mincodelen = codelen;
+      hd->lencount[codelen]++;
+    }
+
+
+  if (hd->maxcodelen == 0 && hd->mincodelen == 100)
+    {
+      hd->num_codes = 0;
+    }
+  else
+    {
+      /* Calculate the current codes for each different code length */
+      hd->min_code[hd->maxcodelen] = 0;
+      for (i = hd->maxcodelen - 1; i>=0; i--)
+	hd->min_code[i] = (hd->min_code[i + 1] + hd->lencount[i + 1]) >> 1;
+    }
+  delete heap;
+  return (hd);
+
+error2:
+  delete heap;
+error1:
+  if (!data)
+    delete hd;
+error0:
+  return (NULL);
+
+}
+
+unsigned long *
+Generate_Huffman_Codes (huff_data * data, u_long * mem)
+{
+  int i;
+  unsigned long *codes;
+  unsigned long mc[MAX_HUFFCODE_LEN + 1];
+
+  if (!data)
+    return (NULL);
+  if (!(codes = new unsigned long[data->num_codes]))
+    return (NULL);
+  if (mem)
+    *mem += data->num_codes * sizeof (*codes);
+  bcopy ((void *) data->min_code, (void *) mc, sizeof (mc));
+  for (i = 0; i < data->num_codes; i++)
+    if (data->clens[i])
+      codes[i] = mc[(int) (data->clens[i])]++;
+
+  return (codes);
+}
+
+
+unsigned long **
+Generate_Huffman_Vals (huff_data * data, u_long * mem)
+{
+  int i;
+  unsigned long *fcode[MAX_HUFFCODE_LEN + 1];
+  unsigned long **values;
+  unsigned long *vals;
+
+  if (!data)
+    return (NULL);
+  if (!(vals = new unsigned long[data->num_codes]))
+    return (NULL);
+  if (!(values = new (unsigned long *)[MAX_HUFFCODE_LEN + 1]))
+    {
+      delete vals;
+      return (NULL);
+    }
+
+  bzero ((char *) values, (MAX_HUFFCODE_LEN + 1) * sizeof (unsigned long *));
+
+  if (mem)
+    *mem += data->num_codes * sizeof (*vals) +
+      (MAX_HUFFCODE_LEN + 1) * sizeof (unsigned long *);
+
+  fcode[0] = values[0] = &vals[0];
+  for (i = 1; i <= data->maxcodelen; i++)
+    fcode[i] = values[i] = &vals[(values[i - 1] - vals) + data->lencount[i - 1]];
+
+  for (i = 0; i < data->num_codes; i++)
+    if (data->clens[i])
+      *fcode[(int) (data->clens[i])]++ = i;
+  return (values);
+}
+
+
+
+double 
+Calculate_Huffman_Size (int num, long *freqs, long *counts)
+{
+  double size = 0;
+  huff_data hd;
+  int i;
+  if (!Generate_Huffman_Data (num, freqs, &hd, NULL))
+    return -1;
+  for (i = 0; i < num; i++)
+    size += counts[i] * hd.clens[i];
+  delete hd.clens;
+  return size;
+}
+
+
+
+int 
+Write_Huffman_Data (FILE * f, huff_data * hd)
+{
+  /* [RPAP - Jan 97: Endian Ordering] */
+  HTONSI(hd->num_codes);
+  HTONSI(hd->mincodelen);
+  HTONSI(hd->maxcodelen);
+
+  if (fwrite (&hd->num_codes, sizeof (hd->num_codes), 1, f) != 1)
+    return -1;
+
+  if (fwrite (&hd->mincodelen, sizeof (hd->mincodelen), 1, f) != 1)
+    return -1;
+
+  if (fwrite (&hd->maxcodelen, sizeof (hd->maxcodelen), 1, f) != 1)
+    return -1;
+
+  /* [RPAP - Jan 97: Endian Ordering] */
+  NTOHSI(hd->num_codes);
+  NTOHSI(hd->mincodelen);
+  NTOHSI(hd->maxcodelen);
+
+  if (hd->num_codes)
+    {
+      /* [RPAP - Jan 97: Endian Ordering] */
+      int i;
+      for (i = hd->mincodelen; i < hd->maxcodelen + 1; i++)
+	HTONSI(hd->lencount[i]);
+      for (i = 0; i < hd->maxcodelen + 1; i++)
+	HTONUL(hd->min_code[i]);
+
+      if (fwrite (hd->lencount + hd->mincodelen, sizeof (*hd->lencount),
+		  hd->maxcodelen - hd->mincodelen + 1, f) !=
+	  hd->maxcodelen - hd->mincodelen + 1)
+	return -1;
+
+      if (fwrite (hd->min_code, sizeof (*hd->min_code), hd->maxcodelen + 1, f) !=
+	  hd->maxcodelen + 1)
+	return -1;
+
+      if (fwrite (hd->clens, sizeof (*hd->clens), hd->num_codes, f) != hd->num_codes)
+	return -1;
+
+      /* [RPAP - Jan 97: Endian Ordering] */
+      for (i = hd->mincodelen; i < hd->maxcodelen + 1; i++)
+	NTOHSI(hd->lencount[i]);
+      for (i = 0; i < hd->maxcodelen + 1; i++)
+	NTOHUL(hd->min_code[i]);
+    }
+  return 0;
+}
+
+
+
+int Read_Huffman_Data (FILE * f, huff_data * hd, u_long * mem, u_long * disk) {
+  if (fread (&hd->num_codes, sizeof (hd->num_codes), 1, f) != 1)
+    return -1;
+
+  if (fread (&hd->mincodelen, sizeof (hd->mincodelen), 1, f) != 1)
+    return -1;
+
+  if (fread (&hd->maxcodelen, sizeof (hd->maxcodelen), 1, f) != 1)
+    return -1;
+
+  /* [RPAP - Jan 97: Endian Ordering] */
+  NTOHSI(hd->num_codes);
+  NTOHSI(hd->mincodelen);
+  NTOHSI(hd->maxcodelen);
+
+  if (disk)
+    (*disk) += sizeof (hd->num_codes) + sizeof (hd->mincodelen) +
+      sizeof (hd->maxcodelen);
+
+  hd->clens = NULL;
+
+  if (hd->num_codes)
+    {
+      int i;  /* [RPAP - Jan 97: Endian Ordering] */
+
+      bzero ((char *) (hd->lencount), sizeof (hd->lencount));
+      if (fread (hd->lencount + hd->mincodelen, sizeof (*hd->lencount),
+	      hd->maxcodelen - hd->mincodelen + 1, f) !=
+	  hd->maxcodelen - hd->mincodelen + 1)
+	return -1;
+
+      /* [RPAP - Jan 97: Endian Ordering] */
+      for (i = hd->mincodelen; i < hd->maxcodelen + 1; i++)
+	NTOHSI(hd->lencount[i]);
+
+      if (disk)
+	(*disk) += sizeof (*hd->lencount) * (hd->maxcodelen - hd->mincodelen + 1);
+
+      bzero ((char *) (hd->min_code), sizeof (hd->min_code));
+
+      if (fread (hd->min_code, sizeof (*hd->min_code), hd->maxcodelen + 1, f) !=
+	  hd->maxcodelen + 1)
+	return -1;
+
+      /* [RPAP - Jan 97: Endian Ordering] */
+      for (i = 0; i < hd->maxcodelen + 1; i++)
+	NTOHUL(hd->min_code[i]);
+
+      if (disk)
+	(*disk) += sizeof (*hd->min_code) * (hd->maxcodelen + 1);
+
+      if (!(hd->clens = new char[hd->num_codes]))
+	return -1;
+
+
+      if (fread (hd->clens, sizeof (*hd->clens), hd->num_codes, f) != hd->num_codes)
+	return -1;
+
+      if (disk)
+	(*disk) += sizeof (*hd->clens) * hd->num_codes;
+    }
+
+  if (mem)
+    *mem += sizeof (*hd->clens) * hd->num_codes;
+  return 0;
+}
Index: /main/tags/2.25/gsdl/src/mgpp/lib/huffman.h
===================================================================
--- /main/tags/2.25/gsdl/src/mgpp/lib/huffman.h	(revision 21064)
+++ /main/tags/2.25/gsdl/src/mgpp/lib/huffman.h	(revision 21064)
@@ -0,0 +1,59 @@
+/**************************************************************************
+ *
+ * huffman.h -- Huffman coding functions
+ * Copyright (C) 1994  Neil Sharman
+ *
+ * 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.
+ *
+ * $Id$
+ *
+ **************************************************************************/
+
+#ifndef H_HUFFMAN
+#define H_HUFFMAN
+
+#include "sysfuncs.h"
+#include "bitio_m_abstract.h"
+
+#define MAX_HUFFCODE_LEN 31
+
+struct huff_data {
+  int num_codes;
+  int mincodelen;
+  int maxcodelen;
+  int lencount[MAX_HUFFCODE_LEN + 1];
+  unsigned long min_code[MAX_HUFFCODE_LEN + 1];
+  char *clens;
+};
+
+
+huff_data *Generate_Huffman_Data (int num, long *freqs, huff_data * data,
+				  u_long * mem);
+
+unsigned long *Generate_Huffman_Codes (huff_data * data, u_long * mem);
+
+unsigned long **Generate_Huffman_Vals (huff_data * data, u_long * mem);
+
+int Write_Huffman_Data (FILE * f, huff_data * hd);
+
+int Read_Huffman_Data (FILE * f, huff_data * hd, u_long * mem, u_long * disk);
+
+/* Calculate the number of bits required to code the data with the
+   specified frequencies. Normally freqs and counts should point to
+   the same array. */
+double Calculate_Huffman_Size (int num, long *freqs, long *counts);
+
+
+#endif
Index: /main/tags/2.25/gsdl/src/mgpp/lib/local_strings.cpp
===================================================================
--- /main/tags/2.25/gsdl/src/mgpp/lib/local_strings.cpp	(revision 21064)
+++ /main/tags/2.25/gsdl/src/mgpp/lib/local_strings.cpp	(revision 21064)
@@ -0,0 +1,415 @@
+/**************************************************************************
+ *
+ * local_strings -- provides some extra string routines
+ * Copyright (C) 1994  Authors
+ *
+ * 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.
+ *
+ * $Id$
+ *
+ **************************************************************************/
+
+static char *RCSID = "$Id$";
+
+#include "sysfuncs.h"
+
+#include "local_strings.h"
+#include "memlib.h"
+
+/* =========================================================================
+ * Function: arg_atoi
+ * Description: 
+ *      Converts an ascii string to an integer
+ *      but allows a scale string immediately following.
+ *      i.e. "10Mb" or "20Kb" or "40Megabytes"
+ *      There must be no gap between the last digit and the scale.
+ *      Only the fist letter is significant.
+ *      K = Kilo
+ *      M = Mega
+ *      G = Giga
+ * Input: 
+ *      string of form: xxxxxxK or xxxxxxxM or xxxxxxxG
+ *      where x is a digit
+ * Output: 
+ *      a scaled integer
+ * ========================================================================= */
+
+#define KILO 	1024
+#define MEGA	1024*1024
+#define GIGA	1024*1024*1024
+
+int 
+arg_atoi (char *str)
+{
+  char *str_ptr = str;
+  char ch = '\0';
+  long scale = 1;
+
+  /* find any scale letter immediately after digits */
+  ch = *str_ptr;
+  while (!isalpha (ch) && (ch != '\0'))
+    ch = *str_ptr++;
+
+  /* replace scale letter by end-of-string character */
+  *str_ptr = '\0';
+
+  /* set scale appropriately */
+  switch (ch)
+    {
+    case 'K':
+      scale = KILO;
+      break;
+    case 'M':
+      scale = MEGA;
+      break;
+    case 'G':
+      scale = GIGA;
+      break;
+    default:
+      scale = 1;
+      break;
+    }
+
+  return (atoi (str) * scale);
+
+}
+
+/* ===============================================================================
+ * Function: compare
+ * Description: Compare two strings. 
+ * Input: Two binary strings, first byte of string indicates length. 
+ * Output: Like standard strcmp.
+ *      = 0 if s1 = s2
+ *      < 0 if s1 < s2
+ *      > 0 if s1 > s2
+ * =============================================================================== */
+int 
+compare (u_char * s1, u_char * s2)
+{
+  int l1 = *s1, l2 = *s2;
+  int l = (l1 < l2) ? l1 : l2;
+
+  while (l--)
+    if (*++s1 != *++s2)
+      return (*s1 - *s2);
+  return (l1 - l2);
+
+}
+
+/*
+ * This array is designed for mapping upper and lower case letter
+ * together for a case independent comparison.  The mappings are
+ * based upon ascii character sequences.
+ */
+static unsigned char casecharmap[] = {
+	'\000', '\001', '\002', '\003', '\004', '\005', '\006', '\007',
+	'\010', '\011', '\012', '\013', '\014', '\015', '\016', '\017',
+	'\020', '\021', '\022', '\023', '\024', '\025', '\026', '\027',
+	'\030', '\031', '\032', '\033', '\034', '\035', '\036', '\037',
+	'\040', '\041', '\042', '\043', '\044', '\045', '\046', '\047',
+	'\050', '\051', '\052', '\053', '\054', '\055', '\056', '\057',
+	'\060', '\061', '\062', '\063', '\064', '\065', '\066', '\067',
+	'\070', '\071', '\072', '\073', '\074', '\075', '\076', '\077',
+	'\100', '\141', '\142', '\143', '\144', '\145', '\146', '\147',
+	'\150', '\151', '\152', '\153', '\154', '\155', '\156', '\157',
+	'\160', '\161', '\162', '\163', '\164', '\165', '\166', '\167',
+	'\170', '\171', '\172', '\133', '\134', '\135', '\136', '\137',
+	'\140', '\141', '\142', '\143', '\144', '\145', '\146', '\147',
+	'\150', '\151', '\152', '\153', '\154', '\155', '\156', '\157',
+	'\160', '\161', '\162', '\163', '\164', '\165', '\166', '\167',
+	'\170', '\171', '\172', '\173', '\174', '\175', '\176', '\177',
+	'\200', '\201', '\202', '\203', '\204', '\205', '\206', '\207',
+	'\210', '\211', '\212', '\213', '\214', '\215', '\216', '\217',
+	'\220', '\221', '\222', '\223', '\224', '\225', '\226', '\227',
+	'\230', '\231', '\232', '\233', '\234', '\235', '\236', '\237',
+	'\240', '\241', '\242', '\243', '\244', '\245', '\246', '\247',
+	'\250', '\251', '\252', '\253', '\254', '\255', '\256', '\257',
+	'\260', '\261', '\262', '\263', '\264', '\265', '\266', '\267',
+	'\270', '\271', '\272', '\273', '\274', '\275', '\276', '\277',
+	'\300', '\341', '\342', '\343', '\344', '\345', '\346', '\347',
+	'\350', '\351', '\352', '\353', '\354', '\355', '\356', '\357',
+	'\360', '\361', '\362', '\363', '\364', '\365', '\366', '\367',
+	'\370', '\371', '\372', '\333', '\334', '\335', '\336', '\337',
+	'\340', '\341', '\342', '\343', '\344', '\345', '\346', '\347',
+	'\350', '\351', '\352', '\353', '\354', '\355', '\356', '\357',
+	'\360', '\361', '\362', '\363', '\364', '\365', '\366', '\367',
+	'\370', '\371', '\372', '\373', '\374', '\375', '\376', '\377',
+};
+
+/* ===============================================================================
+ * Function: casecompare   [RPAP - Jan 97: Stem Index Change]
+ * Description: Compare two strings in dictionary order
+ * Input: Two binary strings, first byte of string indicates length. 
+ * Output:
+ *      = 0 if s1 = s2
+ *      < 0 if s1 < s2
+ *      > 0 if s1 > s2
+ * =============================================================================== */
+int 
+casecompare (u_char * s1, u_char * s2)
+{
+  int l1 = *s1, l2 = *s2;
+  int l = (l1 < l2) ? l1 : l2;
+  int pos = 0;
+  register int diff = 0;
+
+  while (l--)
+    if ((diff = casecharmap[*++s1] - casecharmap[*++s2]) != 0)
+      return (diff);
+    else if ((diff = *s1 - *s2) != 0)
+      if (!pos)
+	pos = diff;
+
+  return ((l1 - l2) ? (l1 - l2) : (pos));
+
+}
+
+/* =========================================================================
+ * Function: copy_string
+ * Description: 
+ *      Copies a string with the len in 1st byte
+ * Input: 
+ * Output: 
+ * ========================================================================= */
+
+u_char *
+copy_string (u_char * src_str)
+{
+  u_char *copy = new u_char(src_str[0] + 1);
+
+  if (!copy)
+    return NULL;
+
+  bcopy ((void *) src_str, (void *) (copy), src_str[0] + 1);
+  return copy;
+
+}
+
+
+/* ===============================================================================
+ * Function: prefixlen
+ * Description: Returns length of common prefix string between s1 and s2.
+ * Input: two binary strings
+ * Output: prefix length
+ * =============================================================================== */
+int 
+prefixlen (u_char * s1, u_char * s2)
+{
+  int l = (*s1 < *s2) ? *s1 : *s2;
+  int i = 0;
+
+  while (i < l && *++s1 == *++s2)
+    i++;
+  return (i);
+}
+
+
+/* ===============================================================================
+ * Function: char2str
+ * Description: 
+ *      Ensures that non-printable characters are converted to a string
+ *      which is printable i.e. it indentifies the character.
+ *      e.g. carriage-return = "\n".
+ * Input: character (may be non-printable)
+ * Output: pointer to static string
+ * =============================================================================== */
+
+char *
+char2str (u_char c)
+{
+  static char buf[10];
+  switch (c)
+    {
+    case '\n':
+      sprintf (buf, "\\n");
+      break;
+    case '\b':
+      sprintf (buf, "\\b");
+      break;
+    case '\f':
+      sprintf (buf, "\\f");
+      break;
+    case '\t':
+      sprintf (buf, "\\t");
+      break;
+    default:
+	if (c >= ' ' && c <= 126)
+	switch (c)
+	  {
+	  case '\\':
+	    sprintf (buf, "\\\\");
+	    break;
+	  case '\"':
+	    sprintf (buf, "\\\"");
+	    break;
+	  case '\'':
+	    sprintf (buf, "\\\'");
+	    break;
+	  default:
+	    buf[0] = c;
+	    buf[1] = '\0';
+	    break;
+	  }
+      else
+	sprintf (buf, "\\x%02x", c);
+      break;
+    }
+  return buf;
+}
+
+/* ===============================================================================
+ * Function: word2str
+ * Description: 
+ *      Converts a string with possible non-printable characters into a string
+ *      consisting entirely of printable characters.
+ * Input: string, length stored in first byte
+ * Output: pointer to static string
+ * =============================================================================== */
+
+char *
+word2str (u_char * s)
+{
+  static char buf[1024];
+  char *p = buf;
+  int i, len = (int) *s++;
+
+  bzero (buf, sizeof (buf));
+  for (i = 0; i < len; i++)
+    {
+      strcpy (p, char2str (s[i]));
+      p = strchr (p, '\0');
+    }
+  return buf;
+}
+
+
+/* =========================================================================
+ * Function: de_escape_string
+ * Description: 
+ *      Turn a string containing \ escapes into real characters
+ *      Note this destroys the string s in the process
+ * Input: string to de-escape 
+ * Output: the de-escaped string
+ * ========================================================================= */
+char *
+de_escape_string (char *s)
+{
+  char *org = s;
+  char *d = s;
+  while (*s)
+    {
+      if (*s == '\\')
+	{
+	  s++;
+	  switch (*s++)
+	    {
+	    case '\0':
+	      *d++ = '\\';
+	      s--;
+	      break;
+	    case '\\':
+	      *d++ = '\\';
+	      break;
+	    case 'b':
+	      *d++ = '\b';
+	      break;
+	    case 'f':
+	      *d++ = '\f';
+	      break;
+	    case 'n':
+	      *d++ = '\n';
+	      break;
+	    case 'r':
+	      *d++ = '\r';
+	      break;
+	    case 't':
+	      *d++ = '\r';
+	      break;
+	    case '\"':
+	      *d++ = '\"';
+	      break;
+	    case '\'':
+	      *d++ = '\'';
+	      break;
+	    case 'x':
+	      {
+		int num = 0;
+		if (isxdigit (*s))
+		  {
+		    char ch = toupper (*s++);
+		    num = ch <= '9' ? ch - '0' : ch - 'A' + 10;
+		  }
+		if (isxdigit (*s))
+		  {
+		    char ch = toupper (*s++);
+		    num = (num << 4) + (ch <= '9' ? ch - '0' : ch - 'A' + 10);
+		  }
+		*d++ = num;
+		break;
+	      }
+	    case '0':
+	    case '1':
+	    case '2':
+	    case '3':
+	    case '4':
+	    case '5':
+	    case '6':
+	    case '7':
+	      {
+		int num = *(s - 1) - '0';
+		if (*s >= '0' && *s <= '7')
+		  num = (num << 3) + *s++ - '0';
+		if (*s >= '0' && *s <= '7')
+		  num = (num << 3) + *s++ - '0';
+		*d++ = num;
+		break;
+	      }
+	    }
+	}
+      else
+	*d++ = *s++;
+    }
+  *d = '\0';
+  return (org);
+}
+
+/* =========================================================================
+ * Function: str255_to_string 
+ * Description: 
+ * Input: 
+ * Output: 
+ * ========================================================================= */
+
+char *
+str255_to_string (u_char * str255, char *str)
+{
+  static char buf[256];
+  char *str_base = NULL;
+  int len = *str255++;
+  int i = 0;
+
+  /* if haven't been given a str to write to then use local buffer */
+  if (!str)
+    str = &(buf[0]);
+
+  str_base = str;
+  for (i = 0; i < len; i++)
+    {
+      *str++ = *str255++;
+    }
+  *str = '\0';
+
+  return str_base;
+}
Index: /main/tags/2.25/gsdl/src/mgpp/lib/local_strings.h
===================================================================
--- /main/tags/2.25/gsdl/src/mgpp/lib/local_strings.h	(revision 21064)
+++ /main/tags/2.25/gsdl/src/mgpp/lib/local_strings.h	(revision 21064)
@@ -0,0 +1,81 @@
+/**************************************************************************
+ *
+ * local_strings.h -- string routines
+ * Copyright (C) 1994  Neil Sharman
+ *
+ * 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.
+ *
+ * $Id$
+ *
+ **************************************************************************/
+
+#ifndef LOCAL_STRINGS_H
+#define LOCAL_STRINGS_H
+
+#include "sysfuncs.h"
+
+class mgString
+{
+  u_char *data;
+ public:
+  inline int length()
+    {
+      return data[0];
+    }
+  inline u_char *rawdata()
+    {
+      return data;
+    }
+  inline void read(u_char **base)
+    {
+      unsigned int copy, suff;
+      
+      copy  = **base;
+      *base = *base + 1;
+      suff  = **base;
+      *base = *base + 1;
+      bcopy((char *) *base, (char *) (data + copy + 1), suff);
+      *data = copy + suff;
+      *base += suff;
+    }
+  inline void read(FILE *dict)
+    {
+      unsigned int copy, suff;
+      copy = fgetc(dict);
+      suff = fgetc(dict);
+      fread(data + copy + 1, sizeof(u_char), suff, dict);
+      *data = copy + suff;
+    }
+  inline static void readString(u_char **base, u_char *prev)
+    {
+      ((mgString *) &prev)->read(base);
+    }
+  inline static void readString(FILE *dict, u_char *prev)
+    { 
+      ((mgString *) &prev)->read(dict);
+    }
+};
+
+int arg_atoi (char *str);
+int compare (u_char * s1, u_char * s2);
+int casecompare (u_char * s1, u_char * s2);   /* [RPAP - Jan 97: Stem Index Change] */
+u_char *copy_string (u_char * src_str);
+char *str255_to_string (u_char * str255, char *str);
+int prefixlen (u_char * s1, u_char * s2);
+char *char2str (u_char c);
+char *word2str (u_char * s);
+char *de_escape_string (char *s);
+
+#endif
Index: /main/tags/2.25/gsdl/src/mgpp/lib/longlong.h
===================================================================
--- /main/tags/2.25/gsdl/src/mgpp/lib/longlong.h	(revision 21064)
+++ /main/tags/2.25/gsdl/src/mgpp/lib/longlong.h	(revision 21064)
@@ -0,0 +1,79 @@
+/**************************************************************************
+ *
+ * longlong.h -- Use of GCC's long long integer types
+ * Copyright (C) 1999 Tim A.H. Bell
+ *
+ * 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.
+ *
+ **************************************************************************/
+
+#ifndef H_LONGLONG
+#define H_LONGLONG
+
+#include "config.h"
+
+/*
+  Use GCC's "long long" integer types for certain variables, to avoid
+  overflowing 32 bit integers.
+
+  Other files affected:
+  
+    lib:
+        bitio_random.c
+        bitio_random.h
+	
+    src/text:
+        ivf.pass1.c
+        ivf.pass2.c
+        build.h
+        mg_passes.c
+        text.h
+    
+*/
+
+/*#define TESTING_OVERFLOW*/
+
+#ifdef TESTING_OVERFLOW
+
+/* Test the overflow detection by using tiny (16-bit) types */
+typedef unsigned short int mg_ullong;
+typedef short int mg_llong;
+
+#define ULL_FS "u"
+#define LL_FS "d"
+
+#elif defined __GNUC__ && ! defined DISABLE_LONG_LONG
+
+/* We're using GCC, so it's okay to use "long long" (64-bit) types */
+#define USE_LONG_LONG
+
+typedef unsigned long long int mg_ullong;
+typedef long long int mg_llong;
+
+#define ULL_FS "llu"
+#define LL_FS "lld"
+
+#else
+
+/* Not using GCC, so fall back on plain "long" (32-bit) types */
+typedef unsigned long int mg_ullong;
+typedef long int mg_llong;
+
+#define ULL_FS "lu"
+#define LL_FS "ld"
+
+#endif /* __GNUC__ */
+
+#endif
Index: /main/tags/2.25/gsdl/src/mgpp/lib/lovinstem.cpp
===================================================================
--- /main/tags/2.25/gsdl/src/mgpp/lib/lovinstem.cpp	(revision 21064)
+++ /main/tags/2.25/gsdl/src/mgpp/lib/lovinstem.cpp	(revision 21064)
@@ -0,0 +1,1176 @@
+/**************************************************************************
+ *
+ * lovinstem.c -- Stemming code
+ * Copyright (C) 1994  Linh Huynh (linh@kbs.citri.edu.au)
+ *
+ * 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.
+ *
+ * $Id$
+ *
+ **************************************************************************/
+
+static char *RCSID = "$Id$";
+
+#include "sysfuncs.h"
+
+
+/*****************************************************************************
+ *
+ *   Transformational Rules used in Recoding Stem Terminations
+ *
+ *   Parameter in functions:
+ *       ch : the second last character of the old ending
+ *            (after removing one of double consonants) 
+ *
+ ****************************************************************************/
+
+
+/************ Conditional rules associated with transformations **************/
+
+/*static int aio ();
+static int s ();
+static int pt ();
+static int m ();
+static int n ();*/
+
+static int 
+aio (char ch)			/* Rule number 9     */
+{
+  return ((ch != 'a') && (ch != 'i') && (ch != 'o'));
+}
+
+static int 
+s (char ch)				/* Rule Number 24    */
+{
+  return (ch != 's');
+}
+
+static int 
+pt (char ch)				/* Rule number 28    */
+{
+  return ((ch != 'p') && (ch != 't'));
+}
+
+static int 
+m (char ch)				/* Rule number 30    */
+{
+  return (ch != 'm');
+}
+
+static int 
+n (char ch)				/* Rule number 32    */
+{
+  return (ch != 'n');
+}
+
+
+/**************************************************************************
+ *
+ *  Context-sensitive rules associated with certain endings.
+ *
+ *  The notations of the rules are the same as in Lovins' paper
+ *  except that rule A is replaced by a NULL in the data structure.
+ *
+ *  Function parameters:
+ *      - stem_length: possible stem length
+ *      - end        : pointer points to the end of the possible stem.
+ *
+ *************************************************************************/
+
+
+/********* Context-sensitive rule function declarations ******************/
+
+/*static int B ();
+static int C ();
+static int D ();
+static int E ();
+static int F ();
+static int G ();
+static int H ();
+static int I ();
+static int J ();
+static int K ();
+static int L ();
+static int M ();
+static int N ();
+static int O ();
+static int P ();
+static int Q ();
+static int R ();
+static int S ();
+static int T ();
+static int U ();
+static int V ();
+static int W ();
+static int X ();
+static int Y ();
+static int Z ();
+static int AA ();
+static int BB ();
+static int CC ();
+*/
+static int 
+B (int stem_length, char *end)
+{
+  return (stem_length >= 3);
+}
+
+static int 
+C (int stem_length, char *end)
+{
+  return (stem_length >= 4);
+}
+
+static int 
+D (int stem_length, char *end)
+{
+  return (stem_length >= 5);
+}
+
+static int 
+E (int stem_length, char *end)
+
+     
+{
+  return (*end != 'e');
+}
+
+static int 
+F (int stem_length, char *end)
+     
+     
+{
+  return ((stem_length >= 3) && (*end != 'e'));
+}
+
+static int 
+G (int stem_length, char *end)
+     
+     
+{
+  return ((stem_length >= 3) && (*end == 'f'));
+}
+
+static int 
+H (int stem_length, char *end)
+     
+     
+{
+  char p1, p2;
+  p1 = *end;
+  p2 = *(end - 1);
+  return ((p1 == 't') || ((p1 == 'l') && (p2 == 'l')));
+}
+
+static int 
+I (int stem_length, char *end)
+     
+     
+{
+  char p1;
+  p1 = *end;
+  return ((p1 != 'o') && (p1 != 'e'));
+}
+
+static int 
+J (int stem_length, char *end)
+     
+     
+{
+  char p1;
+  p1 = *end;
+  return ((p1 != 'a') && (p1 != 'e'));
+}
+
+static int 
+K (int stem_length, char *end)
+     
+     
+{
+  char p1;
+  p1 = *end;
+  return ((stem_length >= 3) &&
+	  ((p1 == 'l') || (p1 == 'i') ||
+	   ((p1 == 'e') && (*(end - 2) == 'u'))));
+}
+
+static int 
+L (int stem_length, char *end)
+     
+     
+{
+  char p1, p2;
+  p1 = *end;
+  p2 = *(end - 1);
+  if (p1 == 's')
+    return (p2 == 'o');
+  else
+    return ((p1 != 'u') && (p1 != 'x'));
+}
+
+static int 
+M (int stem_length, char *end)
+     
+     
+{
+  char p1;
+  p1 = *end;
+  return ((p1 != 'a') && (p1 != 'c') &&
+	  (p1 != 'e') && (p1 != 'm'));
+}
+
+static int 
+N (int stem_length, char *end)
+     
+     
+{
+  if (stem_length >= 3)
+    {
+      if (*(end - 2) == 's')
+	return (stem_length >= 4);
+      else
+	return 1;
+    }
+  else
+    return 0;
+}
+
+static int 
+O (int stem_length, char *end)
+     
+     
+{
+  char p1;
+  p1 = *end;
+  return ((p1 == 'l') || (p1 == 'i'));
+}
+
+static int 
+P (int stem_length, char *end)
+     
+     
+{
+  return (*end != 'c');
+}
+
+static int 
+Q (int stem_length, char *end)
+     
+     
+{
+  char p1;
+  p1 = *end;
+
+  return ((stem_length >= 3) && (p1 != 'l') && (p1 != 'n'));
+}
+
+static int 
+R (int stem_length, char *end)
+     
+     
+{
+  char p1;
+  p1 = *end;
+  return ((p1 == 'n') || (p1 == 'r'));
+}
+
+static int 
+S (int stem_length, char *end)
+     
+     
+{
+  char p1, p2;
+  p1 = *end;
+  p2 = *(end - 1);
+
+  if (p1 == 't')
+    return (p2 != 't');
+  else
+    return ((p1 == 'r') && (p2 == 'd'));
+}
+
+static int 
+T (int stem_length, char *end)
+     
+     
+{
+  char p1, p2;
+  p1 = *end;
+  p2 = *(end - 1);
+
+  if (p1 == 't')
+    return (p2 != 'o');
+  else
+    return (p1 == 's');
+}
+
+static int 
+U (int stem_length, char *end)
+     
+     
+{
+  char p1;
+  p1 = *end;
+
+  return ((p1 == 'l') || (p1 == 'm') ||
+	  (p1 == 'n') || (p1 == 'r'));
+}
+
+static int 
+V (int stem_length, char *end)
+     
+     
+{
+  return (*end == 'c');
+}
+
+static int 
+W (int stem_length, char *end)
+     
+     
+{
+  char p1;
+  p1 = *end;
+
+  return ((p1 != 's') && (p1 != 'u'));
+}
+
+static int 
+X (int stem_length, char *end)
+     
+     
+{
+  char p1;
+  p1 = *end;
+
+  if (p1 == 'e')
+    return ((stem_length >= 3) && (*(end - 2) == 'u'));
+  else
+    return ((p1 == 'l') || (p1 == 'i'));
+}
+
+static int 
+Y (int stem_length, char *end)
+     
+     
+{
+  return ((*end == 'n') && (*(end - 1) == 'i'));
+}
+
+static int 
+Z (int stem_length, char *end)
+     
+     
+{
+  return (*end != 'f');
+}
+
+static int 
+AA (int stem_length, char *end)
+     
+     
+{
+  char p1, p2;
+  p1 = *end;
+  p2 = *(end - 1);
+
+  if (p1 == 'h')
+    return ((p2 == 'p') || (p2 == 't'));
+  else if (p1 == 'r')
+    return ((p2 == 'e') || (p2 == 'o'));
+  else if (p1 == 's')
+    return (p2 == 'e');
+  else
+    return ((p1 == 'd') || (p1 == 'f') ||
+	    (p1 == 'l') || (p1 == 't'));
+}
+
+static int 
+BB (int stem_length, char *end)
+     
+     
+{
+  if (stem_length >= 3)
+    {
+      if (stem_length >= 4)
+	return (strncmp (end - 3, "ryst", 4) != 0);
+      else
+	return (strncmp (end - 2, "met", 3) != 0);
+    }
+  else
+    return 0;
+}
+
+static int 
+CC (int stem_length, char *end)
+     
+     
+{
+  return (*end == 'l');
+}
+
+/**************************************************************************/
+
+#define MIN_STEM_LENGTH 2
+#define MAX_ENDING_SIZE 11
+#define PREDEFINED_SIZE (MAX_ENDING_SIZE + MIN_STEM_LENGTH)
+#define EOS     '\0'
+/* [RPAP - Jan 97: Stem Index Change] */
+#define MAX_STEM_LENGTH 255
+
+static char *remove_ending (char *word, int w_len);
+static void recode_stem (char *stem_end);
+
+/* =========================================================================
+ * Function: stem
+ * Description: 
+ *      Implemetation of the Lovins' stemming algorithm described in
+ *      J.B. Lovins, "Development of a Stemming Algorithm",
+ *      Mechanical Translation and Computational Linguistics, Vol 11,1968.
+ * Input: a word string with the length in the first byte
+ * Output: the stemmed word
+ * ========================================================================= */
+
+void
+lovinstem (u_char * word)
+{
+  char *word_start;		/* points to first letter of word */
+  char *stem_end;		/* points to last character of stem portion */
+  int old_length;		/* length of word */
+  int new_length;		/* length after stemming */
+
+  /* [RPAP - Jan 97: Stem Index Change] */
+  u_char copy[MAX_STEM_LENGTH + 2];
+  bcopy ((void *) word, (void *) copy, *word + 1);
+
+  old_length = *copy; /* [RPAP - Jan 97: Stem Index Change] */
+
+  /* The word must be at least MIN_STEM_LENGTH characters long. */
+  if (old_length <= MIN_STEM_LENGTH)
+    return;
+
+  word_start = (char *) copy + 1;	/* jump over length byte */ /* [RPAP - Jan 97: Stem Index Change] */
+  copy[old_length + 1] = '\0';	/* null terminate string */ /* [RPAP - Jan 97: Stem Index Change] */
+
+  stem_end = remove_ending (word_start, old_length);
+  recode_stem (stem_end);
+
+  /* fix up new length */
+  /* have to use strlen because have no other way of telling length */
+  new_length = strlen (word_start);
+  *copy = new_length;  /* [RPAP - Jan 97: Stem Index Change] */
+
+  /* [RPAP - Jan 97: Stem Index Change] */
+  bcopy ((void *) copy, (void *) word, *copy + 1);
+
+}				/*stem_complex */
+
+/* =========================================================================
+
+ *   Data structure for recoding and the method for recoding the stem. 
+ *
+ * ========================================================================= */
+
+typedef struct
+{
+  char *old_end;		/* old ending */
+  char *new_end;		/* new ending */
+  char old_offset;		/* length of the old ending - 1 */
+  int (*cond) (char);	        /* condition rule */
+  char end_group;		/* signal the end of the group */
+}
+Recode_Rules;
+
+/*  
+   Stem terminations are divided into groups having the same last
+   character
+ */
+
+static Recode_Rules Rules[] =
+{
+  "uad", "uas", 2, NULL, 0,
+  "vad", "vas", 2, NULL, 0,
+  "cid", "cis", 2, NULL, 0,
+  "lid", "lis", 2, NULL, 0,
+  "erid", "eris", 3, NULL, 0,
+  "pand", "pans", 3, NULL, 0,
+  "end", "ens", 2, s, 0,
+  "end", "ens", 2, m, 0,
+  "ond", "ons", 2, NULL, 0,
+  "lud", "lus", 2, NULL, 0,
+  "rud", "rus", 2, NULL, 1,
+
+  "ul", "l", 1, aio, 1,
+
+  "istr", "ister", 3, NULL, 0,
+  "metr", "meter", 3, NULL, 0,
+  "her", "hes", 2, pt, 1,
+
+  "urs", "ur", 2, NULL, 1,
+
+  "uct", "uc", 2, NULL, 0,
+  "umpt", "um", 3, NULL, 0,
+  "rpt", "rb", 2, NULL, 0,
+  "mit", "mis", 2, NULL, 0,
+  "ert", "ers", 2, NULL, 0,
+  "et", "es", 1, n, 0,
+  "yt", "ys", 1, NULL, 1,
+
+  "iev", "ief", 2, NULL, 0,
+  "olv", "olut", 2, NULL, 1,
+
+  "bex", "bic", 2, NULL, 0,
+  "dex", "dic", 2, NULL, 0,
+  "pex", "pic", 2, NULL, 0,
+  "tex", "tic", 2, NULL, 0,
+  "ax", "ac", 1, NULL, 0,
+  "ex", "ec", 1, NULL, 0,
+  "ix", "ic", 1, NULL, 0,
+  "lux", "luc", 2, NULL, 1,
+
+  "yz", "ys", 1, NULL, 1
+};
+
+typedef struct last
+  {
+    char c;			/* The last character */
+    struct last *left;		/* used in balanced   */
+    struct last *right;		/* binary tree        */
+    Recode_Rules *pt;		/* location of approriate group */
+  }
+Last_Char_Node;
+
+/*------------
+       s
+     /   \
+    l     x
+   / \   / \
+  d   r t   z
+         \
+          v
+---------------*/
+static Last_Char_Node pr[] =
+{
+  'd', NULL, NULL, Rules,
+  'l', pr, pr + 2, Rules + 11,
+  'r', NULL, NULL, Rules + 12,
+  's', pr + 1, pr + 6, Rules + 15,
+  't', NULL, pr + 5, Rules + 16,
+  'v', NULL, NULL, Rules + 23,
+  'x', pr + 4, pr + 7, Rules + 25,
+  'z', NULL, NULL, Rules + 33,
+};
+
+
+/*****************************************************************************
+ *
+ *  Recode the stem according to the transformation rules.
+ *
+ *****************************************************************************/
+
+static void
+recode_stem (char *stem_end)
+{
+  static Last_Char_Node *root = pr + 3;
+  Last_Char_Node *p_last = root;
+  Recode_Rules *rule;		/* points to the transformation list */
+  char *h,			/* points to start of possible ending */
+    ch,				/* last character of the old ending  */
+    ch2;
+
+  h = stem_end - 1;
+  ch = *stem_end;
+  if (*h == ch)			/* Check for double consonant        */
+    {
+      if (strchr ("bdglmnprst", ch) != NULL)
+	{
+	  *stem_end = EOS;
+	  stem_end = h;
+	}
+    }
+
+  do				/* Check for the last character       */
+    {
+      ch2 = p_last->c;
+      if (ch == ch2)
+	break;
+      else if (ch > ch2)
+	p_last = p_last->right;
+      else
+	p_last = p_last->left;
+    }
+  while (p_last != NULL);
+
+  if (p_last != NULL)		/* Check for the rest of suffix list */
+    {
+      rule = p_last->pt;
+      for (;;)
+	{
+	  h = stem_end - rule->old_offset;
+	  if (strcmp (h, rule->old_end) == 0)
+	    {
+	      if (!rule->cond || (*rule->cond) (*(h - 1)))
+		{
+		  (void) strcpy (h, rule->new_end);
+		  break;
+		}
+	    }
+	  if (rule->end_group)
+	    break;
+	  rule++;
+	}
+    }
+}
+
+/* ======================================================================
+
+ *    List of endings and the method to remove the ending 
+ *
+ * ======================================================================*/
+
+/************ Data structures for list of endings  ********************/
+
+typedef struct
+{
+  char *ending;			/* old ending                */
+  int (*cond) (int length, char *end);		/* conditional rule          */
+  signed char left_offset;	/* used to find the siblings */
+  signed char right_offset;	/* in balanced binary tree   */
+}
+Ending_List;
+
+/*
+   The original list of endings is re-organised into groups having
+   the same length and the same first character.
+ */
+
+static Ending_List List[] =
+{
+  "a", NULL, 0, 0,
+
+  "ae", NULL, 0, 0,
+  "al", BB, -1, 2,
+  "ar", X, 0, 0,
+  "as", B, -1, 0,
+
+  "acy", NULL, 0, 1,
+  "age", B, 0, 0,
+  "aic", NULL, -2, 1,
+  "als", BB, 0, 0,
+  "ant", B, -2, 2,
+  "ars", O, 0, 0,
+  "ary", F, -1, 2,
+  "ata", NULL, 0, 0,
+  "ate", NULL, -1, 0,
+
+  "able", NULL, 0, 1,
+  "ably", NULL, 0, 0,
+  "ages", B, -2, 2,
+  "ally", B, 0, 0,
+  "ance", B, -1, 1,
+  "ancy", B, 0, 0,
+  "ants", B, -4, 4,
+  "aric", NULL, 0, 0,
+  "arly", K, -1, 1,
+  "ated", I, 0, 0,
+  "ates", NULL, -2, 2,
+  "atic", B, 0, 0,
+  "ator", NULL, -1, 0,
+
+  "acies", NULL, 0, 0,
+  "acity", NULL, -1, 1,
+  "aging", B, 0, 0,
+  "aical", NULL, -2, 2,
+  "alist", NULL, 0, 0,
+  "alism", B, -1, 0,
+  "ality", NULL, -3, 3,
+  "alize", NULL, 0, 1,
+  "allic", BB, 0, 0,
+  "anced", B, -2, 2,
+  "ances", B, 0, 0,
+  "antic", C, -1, 0,
+  "arial", NULL, -6, 6,
+  "aries", NULL, 0, 1,
+  "arily", NULL, 0, 0,
+  "arity", B, -2, 2,
+  "arize", NULL, 0, 0,
+  "aroid", NULL, -1, 0,
+  "ately", NULL, -3, 3,
+  "ating", I, 0, 1,
+  "ation", B, 0, 0,
+  "ative", NULL, -2, 2,
+  "ators", NULL, 0, 0,
+  "atory", NULL, -1, 1,
+  "ature", E, 0, 0,
+
+  "aceous", NULL, 0, 1,
+  "acious", B, 0, 0,
+  "action", G, -2, 2,
+  "alness", NULL, 0, 0,
+  "ancial", NULL, -1, 1,
+  "ancies", NULL, 0, 0,
+  "ancing", B, -4, 4,
+  "ariser", NULL, 0, 0,
+  "arized", NULL, -1, 1,
+  "arizer", NULL, 0, 0,
+  "atable", NULL, -2, 2,
+  "ations", B, 0, 0,
+  "atives", NULL, -1, 0,
+
+  "ability", NULL, 0, 1,
+  "aically", NULL, 0, 0,
+  "alistic", B, -2, 2,
+  "alities", NULL, 0, 0,
+  "ariness", E, -1, 0,
+  "aristic", NULL, -3, 3,
+  "arizing", NULL, 0, 1,
+  "ateness", NULL, 0, 0,
+  "atingly", NULL, -2, 2,
+  "ational", B, 0, 0,
+  "atively", NULL, -1, 1,
+  "ativism", NULL, 0, 0,
+
+  "ableness", NULL, 0, 1,
+  "arizable", NULL, 0, 0,
+
+  "allically", C, 0, 0,
+  "antaneous", NULL, -1, 1,
+  "antiality", NULL, 0, 0,
+  "arisation", NULL, -2, 2,
+  "arization", NULL, 0, 0,
+  "ationally", B, -1, 1,
+  "ativeness", NULL, 0, 0,
+
+  "antialness", NULL, 0, 0,
+  "arisations", NULL, -1, 1,
+  "arizations", NULL, 0, 0,
+
+  "alistically", B, 0, 1,
+  "arizability", NULL, 0, 0,
+
+  "e", NULL, 0, 0,
+
+  "ed", E, 0, 0,
+  "en", F, -1, 1,
+  "es", E, 0, 0,
+
+  "eal", Y, 0, 0,
+  "ear", Y, -1, 1,
+  "ely", E, 0, 0,
+  "ene", E, -2, 2,
+  "ent", C, 0, 0,
+  "ery", E, -1, 1,
+  "ese", NULL, 0, 0,
+
+  "ealy", Y, 0, 1,
+  "edly", E, 0, 0,
+  "eful", NULL, -2, 1,
+  "eity", NULL, 0, 0,
+  "ence", NULL, -2, 2,
+  "ency", NULL, 0, 0,
+  "ened", E, -1, 2,
+  "enly", E, 0, 0,
+  "eous", NULL, -1, 0,
+
+  "early", Y, 0, 1,
+  "ehood", NULL, 0, 0,
+  "eless", NULL, -2, 2,
+  "elity", NULL, 0, 0,
+  "ement", NULL, -1, 0,
+  "enced", NULL, -3, 3,
+  "ences", NULL, 0, 1,
+  "eness", E, 0, 0,
+  "ening", E, -2, 2,
+  "ental", NULL, 0, 0,
+  "ented", C, -1, 1,
+  "ently", NULL, 0, 0,
+
+  "eature", Z, 0, 0,
+  "efully", NULL, -1, 1,
+  "encies", NULL, 0, 0,
+  "encing", NULL, -2, 2,
+  "ential", NULL, 0, 0,
+  "enting", C, -1, 1,
+  "entist", NULL, 0, 1,
+  "eously", NULL, 0, 0,
+
+  "elihood", E, 0, 1,
+  "encible", NULL, 0, 0,
+  "entally", NULL, -2, 2,
+  "entials", NULL, 0, 0,
+  "entiate", NULL, -1, 1,
+  "entness", NULL, 0, 0,
+
+  "entation", NULL, 0, 0,
+  "entially", NULL, -1, 1,
+  "eousness", NULL, 0, 0,
+
+  "eableness", E, 0, 1,
+  "entations", NULL, 0, 0,
+  "entiality", NULL, -2, 2,
+  "entialize", NULL, 0, 0,
+  "entiation", NULL, -1, 0,
+
+  "entialness", NULL, 0, 0,
+
+  "ful", NULL, 0, 0,
+
+  "fully", NULL, 0, 0,
+
+  "fulness", NULL, 0, 0,
+
+  "hood", NULL, 0, 0,
+
+  "i", NULL, 0, 0,
+
+  "ia", NULL, 0, 0,
+  "ic", NULL, -1, 1,
+  "is", NULL, 0, 0,
+
+  "ial", NULL, 0, 0,
+  "ian", NULL, -1, 1,
+  "ics", NULL, 0, 1,
+  "ide", L, 0, 0,
+  "ied", NULL, -3, 3,
+  "ier", NULL, 0, 0,
+  "ies", P, -1, 0,
+  "ily", NULL, -1, 1,
+  "ine", M, 0, 0,
+  "ing", N, -5, 5,
+  "ion", Q, 0, 0,
+  "ish", C, -1, 1,
+  "ism", B, 0, 1,
+  "ist", NULL, 0, 0,
+  "ite", AA, -3, 3,
+  "ity", NULL, 0, 0,
+  "ium", NULL, -1, 0,
+  "ive", NULL, -1, 1,
+  "ize", F, 0, 0,
+
+  "ials", NULL, 0, 0,
+  "ians", NULL, -1, 0,
+  "ible", NULL, -1, 1,
+  "ibly", NULL, 0, 0,
+  "ical", NULL, -2, 2,
+  "ides", L, 0, 0,
+  "iers", NULL, -1, 1,
+  "iful", NULL, 0, 0,
+  "ines", M, -4, 4,
+  "ings", N, 0, 0,
+  "ions", B, -1, 1,
+  "ious", NULL, 0, 0,
+  "isms", B, -2, 2,
+  "ists", NULL, 0, 0,
+  "itic", H, -1, 1,
+  "ized", F, 0, 1,
+  "izer", F, 0, 0,
+
+  "ially", NULL, 0, 0,
+  "icant", NULL, -1, 1,
+  "ician", NULL, 0, 0,
+  "icide", NULL, -2, 2,
+  "icism", NULL, 0, 0,
+  "icist", NULL, -1, 0,
+  "icity", NULL, -3, 3,
+  "idine", I, 0, 1,
+  "iedly", NULL, 0, 0,
+  "ihood", NULL, -2, 2,
+  "inate", NULL, 0, 0,
+  "iness", NULL, -1, 0,
+  "ingly", B, -6, 6,
+  "inism", J, 0, 1,
+  "inity", CC, 0, 0,
+  "ional", NULL, -2, 2,
+  "ioned", NULL, 0, 0,
+  "ished", NULL, -1, 0,
+  "istic", NULL, -3, 3,
+  "ities", NULL, 0, 1,
+  "itous", NULL, 0, 0,
+  "ively", NULL, -2, 2,
+  "ivity", NULL, 0, 0,
+  "izers", F, -1, 1,
+  "izing", F, 0, 0,
+
+  "ialist", NULL, 0, 0,
+  "iality", NULL, -1, 1,
+  "ialize", NULL, 0, 0,
+  "ically", NULL, -2, 2,
+  "icance", NULL, 0, 0,
+  "icians", NULL, -1, 1,
+  "icists", NULL, 0, 0,
+  "ifully", NULL, -4, 4,
+  "ionals", NULL, 0, 0,
+  "ionate", D, -1, 1,
+  "ioning", NULL, 0, 0,
+  "ionist", NULL, -2, 2,
+  "iously", NULL, 0, 0,
+  "istics", NULL, -1, 1,
+  "izable", E, 0, 0,
+
+  "ibility", NULL, 0, 0,
+  "icalism", NULL, -1, 1,
+  "icalist", NULL, 0, 1,
+  "icality", NULL, 0, 0,
+  "icalize", NULL, -3, 3,
+  "ication", G, 0, 0,
+  "icianry", NULL, -1, 0,
+  "ination", NULL, -1, 1,
+  "ingness", NULL, 0, 0,
+  "ionally", NULL, -5, 5,
+  "isation", NULL, 0, 0,
+  "ishness", NULL, -1, 1,
+  "istical", NULL, 0, 1,
+  "iteness", NULL, 0, 0,
+  "iveness", NULL, -3, 3,
+  "ivistic", NULL, 0, 0,
+  "ivities", NULL, -1, 0,
+  "ization", F, -1, 1,
+  "izement", NULL, 0, 0,
+
+  "ibleness", NULL, 0, 0,
+  "icalness", NULL, -1, 1,
+  "ionalism", NULL, 0, 0,
+  "ionality", NULL, -2, 2,
+  "ionalize", NULL, 0, 0,
+  "iousness", NULL, -1, 1,
+  "izations", NULL, 0, 0,
+
+  "ionalness", NULL, 0, 1,
+  "istically", NULL, 0, 0,
+  "itousness", NULL, -2, 2,
+  "izability", NULL, 0, 0,
+  "izational", NULL, -1, 0,
+
+  "izationally", B, 0, 0,
+
+  "ly", B, 0, 0,
+
+  "less", NULL, 0, 1,
+  "lily", NULL, 0, 0,
+
+  "lessly", NULL, 0, 0,
+
+  "lessness", NULL, 0, 0,
+
+  "ness", NULL, 0, 0,
+
+  "nesses", NULL, 0, 0,
+
+  "o", NULL, 0, 0,
+
+  "on", S, 0, 1,
+  "or", T, 0, 0,
+
+  "oid", NULL, 0, 0,
+  "one", R, -1, 1,
+  "ous", NULL, 0, 0,
+
+  "ogen", NULL, 0, 0,
+
+  "oidal", NULL, 0, 0,
+  "oides", NULL, -1, 2,
+  "otide", NULL, 0, 0,
+  "ously", NULL, -1, 0,
+
+  "oidism", NULL, 0, 0,
+
+  "oidally", NULL, 0, 1,
+  "ousness", NULL, 0, 0,
+
+  "s", W, 0, 0,
+
+  "s'", NULL, 0, 0,
+
+  "um", U, 0, 1,
+  "us", V, 0, 0,
+
+  "ward", NULL, 0, 1,
+  "wise", NULL, 0, 0,
+
+  "y", B, 0, 0,
+
+  "yl", R, 0, 0,
+
+  "ying", B, 0, 1,
+  "yish", NULL, 0, 0,
+
+  "'s", NULL, 0, 0,
+};
+
+typedef struct node
+  {
+    char c;			/* First character  */
+    struct node *left;		/* used in balanced */
+    struct node *right;		/* binary tree      */
+    Ending_List *ptr[11];	/* the approriate location */
+  }
+First_Char_Node;
+
+static First_Char_Node First[] =
+{
+  '\'', NULL, NULL,
+  {NULL,
+   List + 293, NULL, NULL, NULL, NULL,
+   NULL, NULL, NULL, NULL, NULL},
+
+  'a', First, NULL,
+  {List,
+   List + 2, List + 9, List + 20, List + 39, List + 58,
+   List + 70, List + 77, List + 82, List + 87, List + 89},
+
+  'e', First + 1, First + 4,
+  {List + 91,
+   List + 93, List + 98, List + 106, List + 116, List + 126,
+   List + 133, List + 138, List + 142, List + 145, NULL},
+
+  'f', NULL, NULL,
+  {NULL,
+   NULL, List + 146, NULL, List + 147, NULL,
+   List + 148, NULL, NULL, NULL, NULL},
+
+  'h', First + 3, First + 5,
+  {NULL,
+   NULL, NULL, List + 149, NULL, NULL,
+   NULL, NULL, NULL, NULL, NULL},
+
+  'i', NULL, NULL,
+  {List + 150,
+   List + 152, List + 163, List + 181, List + 202, List + 222,
+   List + 239, List + 252, List + 258, NULL, List + 261},
+
+  'l', First + 2, First + 10,
+  {NULL,
+   List + 262, NULL, List + 263, NULL, List + 265,
+   NULL, List + 266, NULL, NULL, NULL},
+
+  'n', NULL, NULL,
+  {NULL,
+   NULL, NULL, List + 267, NULL, List + 268,
+   NULL, NULL, NULL, NULL, NULL},
+
+  'o', First + 7, First + 9,
+  {List + 269,
+   List + 270, List + 273, List + 275, List + 277, List + 280,
+   List + 281, NULL, NULL, NULL, NULL},
+
+  's', NULL, NULL,
+  {List + 283,
+   List + 284, NULL, NULL, NULL, NULL,
+   NULL, NULL, NULL, NULL, NULL},
+
+  'u', First + 8, First + 12,
+  {NULL,
+   List + 285, NULL, NULL, NULL, NULL,
+   NULL, NULL, NULL, NULL, NULL},
+
+  'w', NULL, NULL,
+  {NULL,
+   NULL, NULL, List + 287, NULL, NULL,
+   NULL, NULL, NULL, NULL, NULL},
+
+  'y', First + 11, NULL,
+  {List + 289,
+   List + 290, NULL, List + 291, NULL, NULL,
+   NULL, NULL, NULL, NULL, NULL},
+};
+
+
+/******************************************************************************
+ *
+ *  Look for a match in the suffix list.
+ *  Return the pointer to the end of the new stem if there is a match.
+ *  Otherwise, return the pointer to the end of the original word.
+ *
+ *  Method:
+ *      * Search for the first character in the suffix list.
+ *      * If there is match, search for the rest of the suffix list.
+ *         
+ *****************************************************************************/
+
+static char *
+remove_ending (char *word, int w_len)
+{
+  static First_Char_Node *root = First + 6;	/* the root of binary tree is 'l' */
+  First_Char_Node *p_first;	/* Points to the first character      */
+  /* of the possible suffix             */
+  Ending_List *p_list;		/* Points to the List of Endings      */
+  char *suffix_start,		/* Points to start of possible suffix */
+   *stem_end,			/* Points to the end of possible stem */
+    ch1, ch2;
+  int s_len,			/* Possible stem length               */
+    e_offset,			/* Offset from the end to the start of */
+  /* possible suffix                    */
+    not_done = 1, cmp;
+
+  stem_end = word + w_len - 1;
+  if (w_len > PREDEFINED_SIZE)	/* find the start of suffix   */
+    suffix_start = word + w_len - MAX_ENDING_SIZE;
+  else
+    suffix_start = word + MIN_STEM_LENGTH;
+
+  ch1 = *suffix_start;
+  do				/* Search for the first character     */
+    {
+      p_first = root;
+      do
+	{
+	  ch2 = p_first->c;
+	  if (ch1 == ch2)
+	    break;
+	  else if (ch1 > ch2)
+	    p_first = p_first->right;
+	  else
+	    p_first = p_first->left;
+	}
+      while (p_first != NULL);
+
+      if (p_first != NULL)	/* Search for the rest */
+	{
+	  e_offset = stem_end - suffix_start;
+	  if ((p_list = p_first->ptr[e_offset]) != NULL)
+	    {
+	      for (;;)		/* no need to compare the first char  */
+		{
+		  cmp = strcmp (suffix_start + 1, p_list->ending + 1);
+		  if (cmp > 0)
+		    if (p_list->right_offset)
+		      p_list += p_list->right_offset;
+		    else
+		      break;
+		  else if (cmp < 0)
+		    if (p_list->left_offset)
+		      p_list += p_list->left_offset;
+		    else
+		      break;
+		  else
+		    {
+		      s_len = suffix_start - word;
+		      if (!p_list->cond ||
+			  (*p_list->cond) (s_len, suffix_start - 1))
+			{
+			  *suffix_start = EOS;
+			  stem_end = suffix_start - 1;
+			  not_done = 0;
+			}
+		      break;
+		    }
+		}
+	    }
+	}
+      suffix_start++;
+    }
+  while (not_done && ((ch1 = *suffix_start) != EOS));
+  return (stem_end);
+}
Index: /main/tags/2.25/gsdl/src/mgpp/lib/lovinstem.h
===================================================================
--- /main/tags/2.25/gsdl/src/mgpp/lib/lovinstem.h	(revision 21064)
+++ /main/tags/2.25/gsdl/src/mgpp/lib/lovinstem.h	(revision 21064)
@@ -0,0 +1,59 @@
+/**************************************************************************
+ *
+ * lovinstem.h -- Lovins' stemmer header
+ * Copyright (C) 1994  Linh Huynh, 
+ *                     (glued into library by tes@kbs.citri.edu.au)
+ *
+ * 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.
+ *
+ * $Id$
+ *
+ **************************************************************************/
+
+/*
+   $Log$
+   Revision 1.1  2000/01/14 02:17:09  sjboddie
+   Rodgers new C++ mg
+
+   Revision 1.1  1999/10/11 02:55:15  cs025
+   Base install of MG-PP
+
+   Revision 1.1  1999/08/10 21:16:54  sjboddie
+   renamed mg-1.3d directory mg
+
+   Revision 1.1  1998/11/25 07:55:36  rjmcnab
+
+   Modified mg to that you can specify the stemmer you want
+   to use via a command line option. You specify it to
+   mg_passes during the build process. The number of the
+   stemmer that you used is stored within the inverted
+   dictionary header and the stemmed dictionary header so
+   the correct stemmer is used in later stages of building
+   and querying.
+
+   Revision 1.1  1998/11/17 09:32:47  rjmcnab
+   *** empty log message ***
+
+   * Revision 1.2  1994/09/20  04:20:10  tes
+   * Changes made for 1.1
+   *
+   *
+ */
+#ifndef LOVINSTEM_H
+#define LOVINSTEM_H
+
+void lovinstem (unsigned char *word);
+
+#endif
Index: /main/tags/2.25/gsdl/src/mgpp/lib/memlib.cpp
===================================================================
--- /main/tags/2.25/gsdl/src/mgpp/lib/memlib.cpp	(revision 21064)
+++ /main/tags/2.25/gsdl/src/mgpp/lib/memlib.cpp	(revision 21064)
@@ -0,0 +1,68 @@
+/**************************************************************************
+ *
+ * memlib.c -- Malloc wrappers
+ * Copyright (C) 1994  Neil Sharman
+ *
+ * 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.
+ *
+ * $Id$
+ *
+ **************************************************************************/
+
+/*
+   $Log$
+   Revision 1.1  2000/01/14 02:17:09  sjboddie
+   Rodgers new C++ mg
+
+   Revision 1.2  1999/10/17 23:39:45  cs025
+   Changes to eradicate Xmalloc etc
+
+   Revision 1.1  1999/10/11 02:55:15  cs025
+   Base install of MG-PP
+
+   Revision 1.1  1999/08/10 21:16:54  sjboddie
+   renamed mg-1.3d directory mg
+
+   Revision 1.1  1998/11/17 09:32:10  rjmcnab
+   *** empty log message ***
+
+   * Revision 1.1  1994/08/22  00:24:47  tes
+   * Initial placement under CVS.
+   *
+ */
+
+static char *RCSID = "$Id$";
+
+
+#include "sysfuncs.h"
+#include "memlib.h"
+
+/* Defined as strdup is not an ANSI function */
+char *
+my_strdup(const char *str)
+{
+  char *ret_str = new char[strlen(str)+1];
+  if (ret_str) return strcpy(ret_str, str);
+  else return (char*) 0;
+}
+
+
+Malloc_func Xmalloc = malloc;
+
+Realloc_func Xrealloc = realloc;
+
+Free_func Xfree = free;
+
+Strdup_func Xstrdup = my_strdup;
Index: /main/tags/2.25/gsdl/src/mgpp/lib/memlib.h
===================================================================
--- /main/tags/2.25/gsdl/src/mgpp/lib/memlib.h	(revision 21064)
+++ /main/tags/2.25/gsdl/src/mgpp/lib/memlib.h	(revision 21064)
@@ -0,0 +1,51 @@
+/**************************************************************************
+ *
+ * memlib.h -- Malloc wrappers
+ * Copyright (C) 1994  Neil Sharman
+ *
+ * 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.
+ *
+ * $Id$
+ *
+ **************************************************************************/
+
+
+#ifndef H_MEMLIB
+#define H_MEMLIB
+
+#ifdef STD_MEM
+
+#define Xmalloc malloc
+#define Xrealloc realloc
+#define Xfree free
+#define Xstrdup strdup
+
+#else
+
+
+#include "sysfuncs.h"
+
+typedef void *(*Malloc_func) (size_t);
+typedef void *(*Realloc_func) (void *, size_t);
+typedef void (*Free_func) (void *);
+typedef char *(*Strdup_func) (const char *);
+
+extern Malloc_func Xmalloc;
+extern Realloc_func Xrealloc;
+extern Free_func Xfree;
+extern Strdup_func Xstrdup;
+#endif
+
+#endif
Index: /main/tags/2.25/gsdl/src/mgpp/lib/messages.cpp
===================================================================
--- /main/tags/2.25/gsdl/src/mgpp/lib/messages.cpp	(revision 21064)
+++ /main/tags/2.25/gsdl/src/mgpp/lib/messages.cpp	(revision 21064)
@@ -0,0 +1,105 @@
+/**************************************************************************
+ *
+ * messages.c -- Message and error functions
+ * Copyright (C) 1994  Neil Sharman
+ *
+ * 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.
+ *
+ * $Id$
+ *
+ **************************************************************************/
+
+/*
+   $Log$
+   Revision 1.2  2000/01/18 03:53:19  rjmcnab
+   Fixed a couple of bugs and made building silent if needed.
+
+   Revision 1.1  2000/01/14 02:17:10  sjboddie
+   Rodgers new C++ mg
+
+   Revision 1.1  1999/10/11 02:55:16  cs025
+   Base install of MG-PP
+
+   Revision 1.1  1999/08/10 21:16:55  sjboddie
+   renamed mg-1.3d directory mg
+
+   Revision 1.2  1998/11/23 03:38:06  rjmcnab
+
+   combined unix and windows versions of mg
+
+   Revision 1.1  1998/11/19 03:00:32  sjboddie
+   Added windows gdbm and mg versions
+
+   * Revision 1.1  1994/08/22  00:24:48  tes
+   * Initial placement under CVS.
+   *
+ */
+
+static char *RCSID = "$Id$";
+
+#include "sysfuncs.h"
+
+#include <stdarg.h>
+#include "messages.h"
+
+char *msg_prefix = "";
+
+
+void VOLATILE 
+FatalError (int ExitCode, const char *fmt,...)
+{
+  char buf[1024];
+  char *s, *pfx;
+  va_list args;
+  va_start (args, fmt);
+  vsprintf (buf, fmt, args);
+  s = strrchr (buf, '\n');
+  if (!s || *(s + 1) != '\0')
+    strcat (buf, "\n");
+  pfx = strrchr (msg_prefix, '/');
+  pfx = pfx ? pfx + 1 : msg_prefix;
+  fprintf (stderr, "%s%s%s", pfx, *pfx ? " : " : "", buf);
+  exit (ExitCode);
+}
+
+
+
+/*
+ * This function writes messages to stderr. Due to the fact that I can't 
+ * guarantee that the fprintf call is monatomic I have to implement a 
+ * semaphore system.
+ */
+void 
+Message (const char *fmt,...)
+{
+  char buf[1024];
+  char *s, *pfx;
+  va_list args;
+
+#ifdef SILENT
+  return; /* stop those messages!!!! */
+#endif  
+
+  va_start (args, fmt);
+  vsprintf (buf, fmt, args);
+  s = strrchr (buf, '\n');
+  if (!s || *(s + 1) != '\0')
+    strcat (buf, "\n");
+
+  pfx = strrchr (msg_prefix, '/');
+  pfx = pfx ? pfx + 1 : msg_prefix;
+  fprintf (stderr, "%s%s%s", pfx, *pfx ? " : " : "", buf);
+
+}
Index: /main/tags/2.25/gsdl/src/mgpp/lib/messages.h
===================================================================
--- /main/tags/2.25/gsdl/src/mgpp/lib/messages.h	(revision 21064)
+++ /main/tags/2.25/gsdl/src/mgpp/lib/messages.h	(revision 21064)
@@ -0,0 +1,51 @@
+/**************************************************************************
+ *
+ * messages.h -- Message and error functions
+ * Copyright (C) 1994  Neil Sharman
+ *
+ * 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.
+ *
+ * $Id$
+ *
+ **************************************************************************/
+
+#ifndef H_MESSAGES
+#define H_MESSAGES
+
+#ifdef __GNUC__
+#define VOLATILE volatile
+#else
+#define VOLATILE
+#endif
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+extern char *msg_prefix;
+
+void VOLATILE FatalError (int ExitCode, const char *fmt,...);
+void Message (const char *fmt,...);
+
+#ifdef __cplusplus
+}
+#endif
+
+
+#endif
+
+
+
+
Index: /main/tags/2.25/gsdl/src/mgpp/lib/mgheap.cpp
===================================================================
--- /main/tags/2.25/gsdl/src/mgpp/lib/mgheap.cpp	(revision 21064)
+++ /main/tags/2.25/gsdl/src/mgpp/lib/mgheap.cpp	(revision 21064)
@@ -0,0 +1,176 @@
+/**************************************************************************
+ *
+ * mgheap.c -- Heap routines
+ * Copyright (C) 1994  Neil Sharman
+ *
+ * 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.
+ *
+ * $Id$
+ *
+ **************************************************************************/
+
+/*
+   $Log$
+   Revision 1.1  2000/01/14 02:17:11  sjboddie
+   Rodgers new C++ mg
+
+   Revision 1.1  1999/10/11 02:55:18  cs025
+   Base install of MG-PP
+
+   Revision 1.1  1999/08/10 21:16:55  sjboddie
+   renamed mg-1.3d directory mg
+
+   Revision 1.1  1999/01/15 03:05:50  rjmcnab
+
+   Renamed lib/heap to be lib/mgheap (it was causing some problems with
+   some versions of the STL libraries which contained a heap.h)
+
+   Revision 1.1  1998/11/17 09:32:01  rjmcnab
+   *** empty log message ***
+
+   * Revision 1.1  1994/08/22  00:24:43  tes
+   * Initial placement under CVS.
+   *
+ */
+
+static char *RCSID = "$Id$";
+
+#include "mgheap.h"
+
+#define SWAP(s, a, b) 						\
+do {								\
+     register int __i;						\
+     register char *__a = (a), *__b = (b);			\
+     for (__i = (s); __i; __i--)				\
+       {							\
+         register char __t = *__a;				\
+	 *__a++ = *__b; *__b++ = __t;				\
+       }							\
+} while(0)
+
+
+
+#define COPY(s, dst, src) 					\
+do {								\
+     register int __i;						\
+     register char *__dst = (dst), *__src = (src);		\
+     for (__i = (s); __i; __i--)				\
+       *__dst++ = *__src++;					\
+} while(0)
+
+
+
+static void 
+heap_heapify (void *heap, int size, int num, int curr, heap_comp hc)
+{
+  register int child = curr * 2;
+  while (child <= num)
+    {
+      if (child < num && hc ((char *) heap + child * size,
+			     (char *) heap + child * size - size) < 0)
+	child++;
+      if (hc ((char *) heap + (curr - 1) * size, (char *) heap + (child - 1) * size) > 0)
+	{
+	  SWAP (size, (char *) heap + (curr - 1) * size,
+		(char *) heap + (child - 1) * size);
+	  curr = child;
+	  child = child * 2;
+	}
+      else
+	break;
+    }
+}
+
+static void 
+heap_pullup (void *heap, int size, int num, heap_comp hc)
+{
+  register int curr = num;
+  register int parent = curr >> 1;
+  while (parent &&
+	 hc ((char *) heap + (curr - 1) * size, (char *) heap + (parent - 1) * size) < 0)
+    {
+      SWAP (size, (char *) heap + (curr - 1) * size,
+	    (char *) heap + (parent - 1) * size);
+      curr = parent;
+      parent = curr >> 1;
+    }
+}
+
+/************************************************************************
+ *
+ * NOTE: If you choose to change the comparison function the first thing 
+ *       you do after changing the function is call heap_build.
+ *
+ */
+void 
+heap_build (void *heap, int size, int num, heap_comp hc)
+{
+  register int i;
+  for (i = num / 2; i > 0; i--)
+    heap_heapify (heap, size, num, i, hc);
+}
+
+
+
+/****************************************************
+ *
+ * NOTE : The heap must be built before heap_sort is called. 
+ *        This has the effect of reversing the order of the array.
+ *		e.g. if your comparison function is designed to pull the
+ *                   biggest thing off the heap first then the result of
+ *		     sorting with this function will be to put the bigest
+ *                   thing at the end of the array.
+ *
+ */
+void 
+heap_sort (void *heap, int size, int num, heap_comp hc)
+{
+  register int i;
+  for (i = num; i > 1; i--)
+    {
+      SWAP (size, (char *) heap, (char *) heap + (i - 1) * size);
+      heap_heapify (heap, size, i - 1, 1, hc);
+    }
+}
+
+
+void 
+heap_deletehead (void *heap, int size, int *num, heap_comp hc)
+{
+  (*num)--;
+  SWAP (size, (char *) heap, (char *) heap + *num * size);
+  heap_heapify (heap, size, *num, 1, hc);
+}
+
+
+void 
+heap_changedhead (void *heap, int size, int num, heap_comp hc)
+{
+  heap_heapify (heap, size, num, 1, hc);
+}
+
+
+/***********************************************************************
+ *
+ * This assumes that the item has been added to the end of the
+ * array that is the heap. But that num has not been changed. 
+ *
+ */
+void 
+heap_additem (void *heap, int size, int *num, heap_comp hc)
+{
+  (*num)++;
+  heap_pullup (heap, size, *num, hc);
+}
Index: /main/tags/2.25/gsdl/src/mgpp/lib/mgheap.h
===================================================================
--- /main/tags/2.25/gsdl/src/mgpp/lib/mgheap.h	(revision 21064)
+++ /main/tags/2.25/gsdl/src/mgpp/lib/mgheap.h	(revision 21064)
@@ -0,0 +1,84 @@
+/**************************************************************************
+ *
+ * mgheap.h -- Heap routines
+ * Copyright (C) 1994  Neil Sharman
+ *
+ * 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.
+ *
+ * $Id$
+ *
+ **************************************************************************/
+
+/* Care should be taken when using these routines as NO error checking is
+ * done.
+ */
+
+
+
+/* The heap comparison routine should return 
+ * <0 : If a should be before b
+ *  0 : If a and b are equal
+ * >0 : If a should be after b
+ */
+typedef int (*heap_comp) (void *a, void *b);
+
+
+/************************************************************************
+ *
+ * NOTE: If you choose to change the comparison function the first thing 
+ *       you do after changing the function is call heap_build.
+ *
+ */
+void heap_build (void *heap, int size, int num, heap_comp hc);
+
+
+
+/************************************************************************
+ *
+ * NOTE : The heap must be built before heap_sort is called.
+ *        This has the effect of reversing the order of the array.
+ *		e.g. if your comparison function is designed to pull the
+ *                   biggest thing off the heap first then the result of
+ *		     sorting with this function will be to put the bigest
+ *                   thing at the end of the array.
+ *
+ */
+void heap_sort (void *heap, int size, int num, heap_comp hc);
+
+/***********************************************************************
+ *
+ * NOTE: After deleting the head the heap will be one item shorter.
+ *       The deleted item will be placed at the end of the heap.
+ *
+ */
+void heap_deletehead (void *heap, int size, int *num, heap_comp hc);
+
+
+/***********************************************************************
+ *
+ * If you change the "value" of the root node of the heap then you
+ * should call this to re-pritorize the heap.
+ *
+ */
+void heap_changedhead (void *heap, int size, int num, heap_comp hc);
+
+
+/***********************************************************************
+ *
+ * This assumes that the item has been added to the end of the
+ * array that is the heap. But that num has not been changed. 
+ *
+ */
+void heap_additem (void *heap, int size, int *num, heap_comp hc);
Index: /main/tags/2.25/gsdl/src/mgpp/lib/netorder.h
===================================================================
--- /main/tags/2.25/gsdl/src/mgpp/lib/netorder.h	(revision 21064)
+++ /main/tags/2.25/gsdl/src/mgpp/lib/netorder.h	(revision 21064)
@@ -0,0 +1,189 @@
+#ifndef NETORDER_H
+#define NETORDER_H
+
+#include "sysfuncs.h"
+
+/* [RPAP - Feb 97: WIN32 Port] */
+#ifdef __WIN32__
+#include "win32in.h"
+#else
+# include <netinet/in.h>
+#endif
+
+#if defined (BIG_ENDIAN) || defined (_BIG_ENDIAN) || defined (__BIG_ENDIAN)
+# ifndef _BIG_ENDIAN
+#  define _BIG_ENDIAN
+# endif
+#endif
+
+#if defined (LITTLE_ENDIAN) || defined (_LITTLE_ENDIAN) || defined(__LITTLE_ENDIAN)
+# ifndef _LITTLE_ENDIAN
+#  define _LITTLE_ENDIAN
+# endif
+#endif
+
+#ifdef _LITTLE_ENDIAN
+
+/* double */
+#define HTOND(d)                                                                                  \
+        do {                                                                                      \
+             unsigned long tmph, tmpl;                                                            \
+	     bcopy ((void *) &d, (void *) &tmph, sizeof(double) >> 1);                            \
+	     bcopy ((void *) ((unsigned int) &d + (sizeof(double) >> 1)), (void *) &tmpl, sizeof (double) >> 1);   \
+	     tmph = htonl (tmph);                                                                 \
+	     tmpl = htonl (tmpl);                                                                 \
+	     bcopy ((void *) &tmpl, (void *) &d, sizeof (double) >> 1);                           \
+	     bcopy ((void *) &tmph, (void *) ((unsigned int) &d + (sizeof(double) >> 1)), sizeof (double) >> 1);   \
+	}while(0)
+#define NTOHD(d)                                                                                  \
+        do {                                                                                      \
+             unsigned long tmph, tmpl;                                                            \
+	     bcopy ((void *) &d, (void *) &tmph, sizeof(double) >> 1);                            \
+	     bcopy ((void *) ((int) &d + (sizeof(double) >> 1)), (void *) &tmpl, sizeof (double) >> 1);   \
+	     tmph = ntohl (tmph);                                                                 \
+	     tmpl = ntohl (tmpl);                                                                 \
+	     bcopy ((void *) &tmpl, (void *) &d, sizeof (double) >> 1);                           \
+	     bcopy ((void *) &tmph, (void *) ((int) &d + (sizeof(double) >> 1)), sizeof (double) >> 1);   \
+        }while(0)
+#define HTOND2(hd, nd)                                                                            \
+        do {                                                                                      \
+             unsigned long tmph, tmpl;                                                            \
+	     bcopy ((void *) &hd, (void *) &tmph, sizeof(double) >> 1);                           \
+	     bcopy ((void *) ((unsigned int) &hd + (sizeof(double) >> 1)), (void *) &tmpl, sizeof (double) >> 1);  \
+	     tmph = htonl (tmph);                                                                 \
+	     tmpl = htonl (tmpl);                                                                 \
+	     bcopy ((void *) &tmpl, (void *) &nd, sizeof (double) >> 1);                          \
+	     bcopy ((void *) &tmph, (void *) ((unsigned int) &nd + (sizeof(double) >> 1)), sizeof (double) >> 1);  \
+	}while(0)
+#define NTOHD2(nd, hd)                                                                            \
+        do {                                                                                      \
+             unsigned long tmph, tmpl;                                                            \
+	     bcopy ((void *) &nd, (void *) &tmph, sizeof(double) >> 1);                           \
+	     bcopy ((void *) &nd + (sizeof(double) >> 1), (void *) &tmpl, sizeof (double) >> 1);  \
+	     tmph = ntohl (tmph);                                                                 \
+	     tmpl = ntohl (tmpl);                                                                 \
+	     bcopy ((void *) &tmpl, (void *) &hd, sizeof (double) >> 1);                          \
+	     bcopy ((void *) &tmph, (void *) &hd + (sizeof(double) >> 1), sizeof (double) >> 1);  \
+        }while(0)
+
+/* float */
+#define HTONF(f)                                                                   \
+        do {                                                                       \
+             unsigned long tmp;                                                    \
+             bcopy ((void *) &(f), (void *) &tmp, sizeof (float));                 \
+             HTONUL (tmp);                                                         \
+	     bcopy ((void *) &tmp, (void *) &(f), sizeof (float));                 \
+	}while(0)
+#define NTOHF(f)                                                                   \
+        do {                                                                       \
+             unsigned long tmp;                                                    \
+             bcopy ((void *) &(f), (void *) &tmp, sizeof (float));                 \
+	     NTOHUL (tmp);                                                         \
+	     bcopy ((void *) &tmp, (void *) &(f), sizeof (float));                 \
+	}while(0)
+#define HTONF2(hf, nf)                                                             \
+        do {                                                                       \
+             unsigned long tmp;                                                    \
+             bcopy ((void *) &(hf), (void *) &tmp, sizeof (float));                \
+             HTONUL (tmp);                                                         \
+	     bcopy ((void *) &tmp, (void *) &(nf), sizeof (float));                \
+	}while(0)
+#define NTOHF2(nf, hf)                                                             \
+        do {                                                                       \
+             unsigned long tmp;                                                    \
+             bcopy ((void *) &(nf), (void *) &tmp, sizeof (float));                \
+	     NTOHUL (tmp);                                                         \
+	     bcopy ((void *) &tmp, (void *) &(hf), sizeof (float));                \
+	}while(0)
+
+/* pointers */
+#define HTONP(p)          ((p) = (void *) htonl ((unsigned long) p))
+#define NTOHP(p)          ((p) = (void *) ntohl ((unsigned long) p))
+#define HTONP2(hp, np)    ((np) = (void *) htonl ((unsigned long) hp))
+#define NTOHP2(np, hp)    ((hp) = (void *) ntohl ((unsigned long) np))
+
+/* unsigned long */
+#define HTONUL(l)         ((l) = htonl((l)))
+#define NTOHUL(l)         ((l) = ntohl((l)))
+#define HTONUL2(hl, nl)   ((nl) = htonl ((hl)))
+#define NTOHUL2(nl, hl)   ((hl) = ntohl ((nl)))
+
+/* signed long */
+#define HTONSL(l)         ((l) = (long) htonl ((unsigned long) (l)))
+#define NTOHSL(l)         ((l) = (long) ntohl ((unsigned long) (l)))
+#define HTONSL2(hl, nl)   ((nl) = (long) htonl ((unsigned long) (hl)))
+#define NTOHSL2(nl, hl)   ((hl) = (long) ntohl ((unsigned long) (nl)))
+
+/* unsigned int */
+#define HTONUI(i)         ((i) = (unsigned int) htonl ((unsigned long) (i)))
+#define NTOHUI(i)         ((i) = (unsigned int) ntohl ((unsigned long) (i)))
+#define HTONUI2(hi, ni)   ((ni) = (unsigned int) htonl ((unsigned long) (hi)))
+#define NTOHUI2(ni, hi)   ((hi) = (unsigned int) ntohl ((unsigned long) (ni)))
+
+/* signed int */
+#define HTONSI(i)         ((i) = (int) htonl ((unsigned long) (i)))
+#define NTOHSI(i)         ((i) = (int) ntohl ((unsigned long) (i)))
+#define HTONSI2(hi, ni)   ((ni) = (int) htonl ((unsigned long) (hi)))
+#define NTOHSI2(ni, hi)   ((hi) = (int) ntohl ((unsigned long) (ni)))
+
+/* unsigned short */
+#define HTONUS(s)         ((s) = htons((s)))
+#define NTOHUS(s)         ((s) = ntohs((s)))
+#define HTONUS2(hs, ns)   ((ns) = htons((hs)))
+#define NTOHUS2(ns, hs)   ((hs) = ntohs((ns)))
+
+#else   /* _BIG_ENDIAN */
+
+/* double */
+#define HTOND(d)          (d)
+#define NTOHD(d)          (d)
+#define HTOND2(hd, nd)    ((hd) = (nd))
+#define NTOHD2(nd, hd)    ((nd) = (hd))
+
+/* float */
+#define HTONF(f)          (f)
+#define NTOHF(f)          (f)
+#define HTONF2(hf, nf)    ((nf) = (hf))
+#define NTOHF2(nf, hf)    ((hf) = (nf))
+
+/* pointers */
+#define HTONP(p)          (p)
+#define NTOHP(p)          (p)
+#define HTONP2(hp, np)    ((np) = (hp))
+#define NTOHP2(np, hp)    ((hp) = (np))
+
+/* unsigned long */
+#define HTONUL(l)         (l)
+#define NTOHUL(l)         (l)
+#define HTONUL2(hl, nl)   ((nl) = (hl))
+#define NTOHUL2(nl, hl)   ((hl) = (nl))
+
+/* signed long */
+#define HTONSL(l)         (l)
+#define NTOHSL(l)         (l)
+#define HTONSL2(hl, nl)   ((nl) = (hl))
+#define NTOHSL2(nl, hl)   ((hl) = (nl))
+
+/* unsigned int */
+#define HTONUI(i)         (i)
+#define NTOHUI(i)         (i)
+#define HTONUI2(hi, ni)   ((ni) = (hi))
+#define NTOHUI2(ni, hi)   ((hi) = (ni))
+
+/* signed int */
+#define HTONSI(i)         (i)
+#define NTOHSI(i)         (i)
+#define HTONSI2(hi, ni)   ((ni) = (hi))
+#define NTOHSI2(ni, hi)   ((hi) = (ni))
+
+/* unsigned short */
+#define HTONUS(s)         (s)
+#define NTOHUS(s)         (s)
+#define HTONUS2(hs, ns)   ((ns) = (hs))
+#define NTOHUS2(ns, hs)   ((hs) = (ns))
+
+
+
+#endif
+
+#endif /* netorder.h */
Index: /main/tags/2.25/gsdl/src/mgpp/lib/non_ansi.h
===================================================================
--- /main/tags/2.25/gsdl/src/mgpp/lib/non_ansi.h	(revision 21064)
+++ /main/tags/2.25/gsdl/src/mgpp/lib/non_ansi.h	(revision 21064)
@@ -0,0 +1,9 @@
+extern "C" int fileno(FILE *);
+extern "C" int ftruncate(int, long);
+
+extern "C" int pclose(FILE *);
+extern "C" FILE *popen(const char *command, const char *type);
+
+extern "C" int getpagesize();
+
+extern "C" int strcasecmp(const char *, const char *);
Index: /main/tags/2.25/gsdl/src/mgpp/lib/pathmax.h
===================================================================
--- /main/tags/2.25/gsdl/src/mgpp/lib/pathmax.h	(revision 21064)
+++ /main/tags/2.25/gsdl/src/mgpp/lib/pathmax.h	(revision 21064)
@@ -0,0 +1,53 @@
+/* Define PATH_MAX somehow.  Requires sys/types.h.
+   Copyright (C) 1992 Free Software Foundation, Inc.
+
+   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, 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.  */
+
+#ifndef _PATHMAX_H
+#define _PATHMAX_H
+
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+
+/* Non-POSIX BSD systems might have gcc's limits.h, which doesn't define
+   PATH_MAX but might cause redefinition warnings when sys/param.h is
+   later included (as on MORE/BSD 4.3).  */
+#if defined(_POSIX_VERSION) || (defined(HAVE_LIMITS_H) && !defined(__GNUC__))
+#include <limits.h>
+#endif
+
+#ifndef _POSIX_PATH_MAX
+#define _POSIX_PATH_MAX 255
+#endif
+
+#if !defined(PATH_MAX) && defined(_PC_PATH_MAX)
+#define PATH_MAX (pathconf ("/", _PC_PATH_MAX) < 1 ? 1024 : pathconf ("/", _PC_PATH_MAX))
+#endif
+
+/* Don't include sys/param.h if it already has been.  */
+#if defined(HAVE_SYS_PARAM_H) && !defined(PATH_MAX) && !defined(MAXPATHLEN)
+#include <sys/param.h>
+#endif
+
+#if !defined(PATH_MAX) && defined(MAXPATHLEN)
+#define PATH_MAX MAXPATHLEN
+#endif
+
+#ifndef PATH_MAX
+#define PATH_MAX _POSIX_PATH_MAX
+#endif
+
+#endif /* _PATHMAX_H */
Index: /main/tags/2.25/gsdl/src/mgpp/lib/perf_hash.cpp
===================================================================
--- /main/tags/2.25/gsdl/src/mgpp/lib/perf_hash.cpp	(revision 21064)
+++ /main/tags/2.25/gsdl/src/mgpp/lib/perf_hash.cpp	(revision 21064)
@@ -0,0 +1,1098 @@
+/**************************************************************************
+ *
+ * perf_hash.c -- Perfect hashing functions
+ * Copyright (C) 1992  Bohdan S. Majewski
+ *
+ * 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.
+ *
+ * $Id$
+ *
+ **************************************************************************
+ *
+ * 1994 Neil Sharman
+ *      Small modifications were made to the interface so that it fitted in
+ *      with mg.
+ *
+ **************************************************************************/
+
+/*
+   $Log$
+   Revision 1.1  2000/01/14 02:17:13  sjboddie
+   Rodgers new C++ mg
+
+   Revision 1.1  1998/11/17 09:32:17  rjmcnab
+   *** empty log message ***
+
+   * Revision 1.2  1994/08/22  00:26:30  tes
+   * Made perf_hash take the ceiling of 1.23 * num
+   * in lieu of the floor.
+   * This was done so that perf_hash works ok on
+   * a small number of keys.
+   *
+   * Revision 1.1  1994/08/22  00:24:49  tes
+   * Initial placement under CVS.
+   *
+ */
+
+static char *RCSID = "$Id$";
+
+
+#define STRUCT
+
+#include <time.h>  /* for call to time () in SEED_RANDOM() */
+#include "sysfuncs.h"
+
+#include "local_strings.h"
+#include "memlib.h"
+#include "messages.h"
+#include "perf_hash.h"
+#include "netorder.h"  /* [RPAP - Jan 97: Endian Ordering] */
+
+#define FALSE 0
+#define TRUE  1
+
+#define STATIC 0
+
+/* Random Number stuff */
+
+long irandm (long is[2]);  /* from random.c */
+
+static long seed[] = {0, 0};
+#define RANDOM() irandm(seed)
+#define SEED_RANDOM(the_seed) do{ seed[0] = the_seed; }while(0)
+
+/* Max number of keys - must be a power of 2 minus 1 */
+static int MAX_M;
+
+
+static int MAX_CH;
+
+
+/* the width of the mapping tables  */
+static int MAX_L;
+
+
+
+#define c     1.23
+static int MAX_N;
+
+
+
+
+static u_char *translate;
+
+#define MEMBER 0
+#define ERASED 1
+
+
+
+/* direction constants for the edge oriented 3-graph representation */
+#define A              0
+#define B        (MAX_M)
+#define C          (2*B)
+
+/* NODEa, NODEb, NODEc, FIRST and NEXT are used to represent a 3-graph */
+static int *NODEa, *NODEb, *NODEc;
+static int *FIRST;
+static int *NEXT;
+
+
+#define norm(e) ((e) % MAX_M)
+/* in general should be ((e) % MAX_M) but MAX_M = 2^k - 1 */
+
+
+static char *mk;		/* for marking edges/vertices as removed */
+static int *g;			/* array g defines a minimal perfect hash function */
+
+
+
+/* stack of edges, created during the independency */
+/* test, used in the assignment step               */
+static struct
+  {
+    int sp;
+    int *st;
+  }
+S;
+#define push(s, e) s.st[s.sp++] = (e)
+#define pop(s, e)  e = s.st[--s.sp]
+
+#ifndef STRUCT
+static long **tb0, **tb1, **tb2;
+#else
+struct tb_entry **tb;
+#endif
+
+
+static int 
+unique (int v)
+{				/* checks if vertex v belongs to only one edge */
+  return (FIRST[v] != 0 && NEXT[FIRST[v]] == 0) ? FIRST[v] : 0;
+}				/*unique */
+
+
+
+
+
+
+
+
+static void 
+_delete (int v, int e)
+{				/* deletes edge e from list of v */
+
+  int b;
+
+  b = FIRST[v];
+  assert (norm (b) != 0);
+  if (norm (b) == e)
+    FIRST[v] = NEXT[FIRST[v]];
+  else
+    {
+      while (norm (NEXT[b]) != e)
+	{
+	  b = NEXT[b];
+	  assert (norm (b) != 0);
+	}
+      NEXT[b] = NEXT[NEXT[b]];
+    }
+}				/*delete */
+
+
+
+
+
+
+#if 0
+/* recursively removes the edges of a 3-graph which have at least */
+/* one unique vertex. The removed edges are placed on stack S     */
+static void 
+ph_remove (int e, int v)
+{
+  int b;
+  mk[e] = ERASED;
+  push (S, e);
+
+  if (NODEa[e] != v)
+    _delete (NODEa[e], e);
+  if (NODEb[e] != v)
+    _delete (NODEb[e], e);
+  if (NODEc[e] != v)
+    _delete (NODEc[e], e);
+
+  if (NODEa[e] != v && mk[b = norm (unique (NODEa[e]))] == MEMBER)
+    ph_remove (b, NODEa[e]);
+  if (NODEb[e] != v && mk[b = norm (unique (NODEb[e]))] == MEMBER)
+    ph_remove (b, NODEb[e]);
+  if (NODEc[e] != v && mk[b = norm (unique (NODEc[e]))] == MEMBER)
+    ph_remove (b, NODEc[e]);
+}
+#else
+
+
+static int StackPos, StackMax;
+static struct Stack
+  {
+    int e, v, m;
+  }
+ *Stack = NULL;
+
+#define StackAdd(_e, _v, _m)						\
+  do {									\
+    if (StackPos == StackMax)						\
+      {									\
+        StackMax <<= 1;							\
+	if (!(Stack = (struct Stack *)Xrealloc(Stack, sizeof(*Stack) * StackMax)))	\
+	  return(-1);							\
+      }									\
+    Stack[StackPos].e = (_e);						\
+    Stack[StackPos].v = (_v);						\
+    Stack[StackPos++].m = (_m);						\
+  } while(0)
+
+
+static int 
+ph_remove (int e, int v)
+{
+  if (!Stack)
+    {
+      StackMax = 256;
+      if (!(Stack = (struct Stack *) Xmalloc (sizeof (*Stack) * StackMax)))
+	return (-1);
+      StackPos = 0;
+    }
+  Stack[StackPos].e = e;
+  Stack[StackPos].v = v;
+  Stack[StackPos].m = 0;
+  StackPos++;
+  while (StackPos)
+    {
+      int m, b;
+      StackPos--;
+      e = Stack[StackPos].e;
+      v = Stack[StackPos].v;
+      m = Stack[StackPos].m;
+
+
+      switch (m)
+	{
+	case 0:
+	  {
+	    mk[e] = ERASED;
+	    push (S, e);
+
+	    if (NODEa[e] != v)
+	      _delete (NODEa[e], e);
+	    if (NODEb[e] != v)
+	      _delete (NODEb[e], e);
+	    if (NODEc[e] != v)
+	      _delete (NODEc[e], e);
+
+	    if (NODEa[e] != v && mk[b = norm (unique (NODEa[e]))] == MEMBER)
+	      {
+		Stack[StackPos++].m = 1;
+		StackAdd (b, NODEa[e], 0);
+		break;
+	      }
+	  }
+	case 1:
+	  {
+	    if (NODEb[e] != v && mk[b = norm (unique (NODEb[e]))] == MEMBER)
+	      {
+		Stack[StackPos++].m = 2;
+		StackAdd (b, NODEb[e], 0);
+		break;
+	      }
+	  }
+	case 2:
+	  if (NODEc[e] != v && mk[b = norm (unique (NODEc[e]))] == MEMBER)
+	    StackAdd (b, NODEc[e], 0);
+	}
+    }
+  return (0);
+}
+#endif
+
+
+
+
+
+/* returns TRUE if and only if set of edges created in the tree_builder */
+/* procedure form a 3-graph with independent edges. Edges of a 3-graph  */
+/* are independent iff repeated deletion of edges containing vertices   */
+/* of degree 1 results in a graph with no edges in it.                  */
+static int 
+acyclic (int m, int n)
+{
+
+  int v, e;
+  /* build list of edges for each node */
+  for (v = 1; v <= n; FIRST[v++] = 0);
+  for (e = 1; e <= m; e++)
+    {
+      NEXT[A + e] = FIRST[NODEa[e]];
+      FIRST[NODEa[e]] = A + e;
+      NEXT[B + e] = FIRST[NODEb[e]];
+      FIRST[NODEb[e]] = B + e;
+      NEXT[C + e] = FIRST[NODEc[e]];
+      FIRST[NODEc[e]] = C + e;
+
+      /* mark edge e as belonging to the hypergraph */
+      mk[e] = MEMBER;
+    }
+
+
+  S.sp = 0;			/* empty the stack */
+  mk[0] = ERASED;		/* a sentinel for the test below */
+  for (v = 1; v <= n; v++)
+    {
+      if (mk[e = norm (unique (v))] == MEMBER)
+	ph_remove (e, v);
+    }
+
+  /* check if any edges were left in the graph */
+  return S.sp == m;
+}				/*acyclic */
+
+
+
+
+
+
+
+
+/* repeatedly maps words into edges of a 3-graph until the edges */
+/* are independent.                                              */
+static int 
+tree_builder (int num, u_char ** keys, int *n)
+{
+
+  int e, k = 0;
+  int i, j;
+  u_char *w;
+
+  do
+    {
+      *n = (int) (num * c + 1);
+      /* initialize tables of random integers */
+      for (i = 0; i < MAX_CH; i++)
+	for (j = 0; j < MAX_L; j++)
+	  {
+#ifndef STRUCT
+	    tb0[i][j] = RANDOM () % *n;
+	    tb1[i][j] = RANDOM () % *n;
+	    tb2[i][j] = RANDOM () % *n;
+#else
+	    struct tb_entry *tbp = &tb[i][j];
+	    tbp->tb0 = RANDOM () % *n;
+	    tbp->tb1 = RANDOM () % *n;
+	    tbp->tb2 = RANDOM () % *n;
+#endif
+	  }
+
+      /* compute an edge (NODEa[e], NODEb[e], NODEc[e]) for each word */
+      for (e = 1; e <= num; e++)
+	{
+	  /*generate an edge corresponding to the ith word */
+	  int x = 0, y = 0, z = 0, l;
+	  w = keys[e - 1];
+
+	  l = *w++;
+	  j = (l - 1) % MAX_L;
+
+	  do
+	    {
+#ifndef STRUCT
+	      x += tb0[translate[*w]][j];
+	      y += tb1[translate[*w]][j];
+	      z += tb2[translate[*w]][j];
+#else
+	      struct tb_entry *tbp = &tb[translate[*w]][j];
+	      x += tbp->tb0;
+	      y += tbp->tb1;
+	      z += tbp->tb2;
+#endif
+	      if (++j >= MAX_L)
+		j = 0;
+	      w++;
+	    }
+	  while (--l);
+	  x = (x % *n) + 1;
+	  y = (y % *n) + 1;
+	  z = (z % *n) + 1;
+	  if (y == x && ++y > *n)
+	    y = 1;
+	  if (z == x && ++z > *n)
+	    z = 1;
+	  if (z == y)
+	    {
+	      if (++z > *n)
+		z = 1;
+	      if (z == x && ++z > *n)
+		z = 1;
+	    }
+
+	  NODEa[e] = x;
+	  NODEb[e] = y;
+	  NODEc[e] = z;
+	}
+      if (++k > 50)		/* make sure we will not wait for ever */
+	FatalError (1, "Unable to generate the perfect hash function. "
+		    "This is probably because there aren't enough words");
+    }
+  while (!acyclic (num, *n));
+  return k;
+}				/*tree_builder */
+
+
+
+
+
+
+
+
+
+/* calculates values of the g function/array so that i-th word is */
+/* placed at the (i-1)st position of a hash table.                */
+static void 
+assign (int n)
+{
+
+  int v, w = 0, e;
+
+  /* mark all the vertices of the 3-graph as unassigned */
+  for (v = 1; v <= n; mk[v++] = FALSE);
+
+  while (S.sp > 0)
+    {
+      int _xor = 0;
+      pop (S, e);
+      v = NODEa[e];
+      if (mk[v])
+	_xor ^= g[v];
+      else
+	{
+	  g[w = v] = 0;
+	  mk[v] = TRUE;
+	}
+      v = NODEb[e];
+      if (mk[v])
+	_xor ^= g[v];
+      else
+	{
+	  g[w = v] = 0;
+	  mk[v] = TRUE;
+	}
+      v = NODEc[e];
+      if (mk[v])
+	_xor ^= g[v];
+      else
+	{
+	  g[w = v] = 0;
+	  mk[v] = TRUE;
+	}
+      g[w] = (e - 1) ^ _xor;
+    }
+}				/*assign */
+
+
+
+
+
+
+
+
+
+/*check returns 0 if no error in mphf is detected, else returns error code */
+static int 
+check (int m)
+{
+
+  int e, err_code = 0;
+
+  /*for each word compute its place in hash table and check if correct */
+  for (e = 1; e <= m; e++)
+    {
+      if ((e - 1) != (g[NODEa[e]] ^ g[NODEb[e]] ^ g[NODEc[e]]))
+	{
+	  (void) fprintf (stderr, "Error for %dth word detected.\n", e);
+	  err_code = e;
+	}
+    }
+  return err_code;
+}				/*check */
+
+
+
+
+
+
+
+#if 0
+void 
+outputh (int m, int n)
+{
+
+  int i, j, w = (int) ceil (log10 ((double) n + 1.0)) + 1;
+
+#if 0
+  char *PRG =
+  "int h(char *s)\n"
+  "{\n"
+  "  int u, v, w, i;\n"
+  "i = (strlen(s) - 1) % _HXL;\n"
+  "  u = v = w = 0;\n"
+  "  while(*s)\n"
+  "    {\n"
+  "      u += mt1[(*s) - _HFC][i];\n"
+  "      v += mt2[(*s) - _HFC][i];\n"
+  "      w += mt3[(*s++) - _HFC][i];\n"
+  "      if(++i >= _HXL) i = 0;\n"
+  "    }\n"
+  "  u %= _HFN; v %= _HFN; w %= _HFN;\n"
+  "  if(u == v && ++v >= _HFN) v = 0;\n"
+  "  if(w == u && ++w >= _HFN) w = 0;\n"
+  "  if(w == v && ++w >= _HFN) w = 0;\n"
+  "  if(w == u && ++w >= _HFN) w = 0;\n"
+  "  return (g[u] ^ g[v] ^ g[w]) % _HFM;\n"
+  "};\n\n";
+#endif
+
+  char *PRG =
+  "int h(char *s)\n"
+  "{\n"
+  "  int u, v, w, i;\n"
+  "  i = (strlen(s) - 1) % _HXL;\n"
+  "  u = v = w = 0;\n"
+  "  while(*s)\n"
+  "    {\n"
+  "      if((u += mt1[(*s) - _HFC][i]) >= _HFN) u -= _HFN;\n"
+  "      if((v += mt2[(*s) - _HFC][i]) >= _HFN) v -= _HFN;\n"
+  "      if((w += mt3[(*s++) - _HFC][i]) >= _HFN) w -= _HFN;\n"
+  "      if(++i >= _HXL) i = 0;\n"
+  "    }\n"
+  "  if(u == v && ++v >= _HFN) v = 0;\n"
+  "  if(w == v) \n"
+  "    {\n"
+  "      if(++w >= _HFN) w = 0;\n"
+  "      if(w == u && ++w >= _HFN) w = 0;\n"
+  "    }\n"
+  "  else\n"
+  "    if(w == u)\n"
+  "      {\n"
+  "	     if(++w >= _HFN) w = 0;\n"
+  "	     if(w == v && ++w >= _HFN) w = 0;\n"
+  "      }\n"
+  "  return ((g[u] ^ g[v] ^ g[w]) > _HFM)? 0 : (g[u] ^ g[v] ^ g[w]);\n"
+  "}\n\n";
+
+  printf ("#define _HFN %d\n#define _HFC %d\n", n, fc);
+  printf ("#define _HFM %d\n#define _HXL %d\n", m, MAX_L);
+  printf ("#define _HFA %d\n\nstatic int g[_HFN] = {\n", lc - fc + 1);
+  for (i = 1; i < n; i++)
+    {
+      if (i % 8 == 0)
+	putchar ('\n');
+      printf ("%5d, ", g[i]);
+    }
+  printf ("%5d};\n\n", g[n]);
+
+  printf ("static int mt1[_HFA][_HXL] = {\n");
+  for (j = fc; j < lc; j++)
+    {
+      printf ("{");
+      for (i = 0; i < MAX_L - 1; i++)
+	printf ("%*d,", w, tb0[j][i]);
+      printf ("%*d},\n", w, tb0[j][MAX_L - 1]);
+    }
+  printf ("{");
+  for (i = 0; i < MAX_L - 1; i++)
+    printf ("%*d,", w, tb0[lc][i]);
+  printf ("%*d}\n", w, tb0[lc][MAX_L - 1]);
+  printf ("};\n\n");
+
+  printf ("static int mt2[_HFA][_HXL] = {\n");
+  for (j = fc; j < lc; j++)
+    {
+      printf ("{");
+      for (i = 0; i < MAX_L - 1; i++)
+	printf ("%*d,", w, tb1[j][i]);
+      printf ("%*d},\n", w, tb1[j][MAX_L - 1]);
+    }
+  printf ("{");
+  for (i = 0; i < MAX_L - 1; i++)
+    printf ("%*d,", w, tb1[lc][i]);
+  printf ("%*d}\n", w, tb1[lc][MAX_L - 1]);
+  printf ("};\n\n");
+
+  printf ("static int mt3[_HFA][_HXL] = {\n");
+  for (j = fc; j < lc; j++)
+    {
+      printf ("{");
+      for (i = 0; i < MAX_L - 1; i++)
+	printf ("%*d,", w, tb2[j][i]);
+      printf ("%*d},\n", w, tb2[j][MAX_L - 1]);
+    }
+  printf ("{");
+  for (i = 0; i < MAX_L - 1; i++)
+    printf ("%*d,", w, tb2[lc][i]);
+  printf ("%*d}\n", w, tb2[lc][MAX_L - 1]);
+  printf ("};\n\n");
+
+  printf ("%s", PRG);
+}				/*outputh */
+#endif
+
+
+
+
+
+
+
+static void 
+make_trans_func (int num, u_char ** keys)
+{
+  int i, j;
+
+  bzero ((char *) translate, sizeof (translate));
+
+  MAX_L = 1;
+  for (i = 0; i < num; i++)
+    {
+      unsigned len = keys[i][0];
+      u_char *s = keys[i] + 1;
+      for (; len; len--, s++)
+	translate[*s] = 1;
+      if (i)
+	{
+	  int l;
+	  l = prefixlen (keys[i - 1], keys[i]);
+	  if (l + 1 > MAX_L)
+	    MAX_L = l + 1;
+	}
+    }
+  j = 0;
+  for (i = 0; i < 256; i++)
+    if (translate[i])
+      translate[i] = j++;
+  MAX_CH = j;
+}
+
+
+static void 
+temp_free (void)
+{
+  if (NODEa)
+    Xfree (NODEa);
+  if (NODEb)
+    Xfree (NODEb);
+  if (NODEc)
+    Xfree (NODEc);
+  if (FIRST)
+    Xfree (FIRST);
+  if (NEXT)
+    Xfree (NEXT);
+  if (S.st)
+    Xfree (S.st);
+  if (mk)
+    Xfree (mk);
+}
+
+static void 
+all_free (void)
+{
+  int i;
+  temp_free ();
+  if (translate)
+    Xfree (translate);
+  if (g)
+    Xfree (g);
+#ifndef STRUCT
+  for (i = 0; i < MAX_CH; i++)
+    {
+      if (tb0 && tb0[i])
+	Xfree (tb0[i]);
+      if (tb1 && tb1[i])
+	Xfree (tb1[i]);
+      if (tb2 && tb2[i])
+	Xfree (tb2[i]);
+    }
+  if (tb0)
+    Xfree (tb0);
+  if (tb1)
+    Xfree (tb1);
+  if (tb2)
+    Xfree (tb2);
+#else
+  for (i = 0; i < MAX_CH; i++)
+    if (tb && tb[i])
+      Xfree (tb[i]);
+  if (tb)
+    Xfree (tb);
+#endif
+}
+
+static int 
+allocate_memory (void)
+{
+  int i, ok = 1;
+  NODEa = (int *) Xmalloc (sizeof (int) * (MAX_M + 1));
+  NODEb = (int *)Xmalloc (sizeof (int) * (MAX_M + 1));
+  NODEc = (int *)Xmalloc (sizeof (int) * (MAX_M + 1));
+  FIRST = (int *)Xmalloc (sizeof (int) * (MAX_N + 1));
+  NEXT = (int *)Xmalloc (sizeof (int) * (MAX_M + 1) * 3);
+  S.st = (int *)Xmalloc (sizeof (int) * MAX_M);
+  mk = (char *)Xmalloc (sizeof (char) * (MAX_N + 1));
+  g = (int *)Xmalloc (sizeof (int) * (MAX_N + 1));
+#ifndef STRUCT
+  tb0 = Xmalloc (sizeof (int *) * MAX_CH);
+  tb1 = Xmalloc (sizeof (int *) * MAX_CH);
+  tb2 = Xmalloc (sizeof (int *) * MAX_CH);
+  for (i = 0; i < MAX_CH; i++)
+    {
+      if (tb0)
+	if (!(tb0[i] = Xmalloc (sizeof (long) * MAX_L)))
+	    ok = 0;
+      if (tb1)
+	if (!(tb1[i] = Xmalloc (sizeof (long) * MAX_L)))
+	    ok = 0;
+      if (tb2)
+	if (!(tb2[i] = Xmalloc (sizeof (long) * MAX_L)))
+	    ok = 0;
+    }
+
+  if (!(NODEa && NODEb && NODEc && FIRST && NEXT && S.st && mk && g &&
+	tb0 && tb1 && tb2 && ok))
+    {
+      all_free ();
+      return (-1);
+    }
+#else
+  tb = (tb_entry **)Xmalloc (sizeof (struct tb_entry *) * MAX_CH);
+  for (i = 0; i < MAX_CH; i++)
+    if (tb)
+      if (!(tb[i] = (tb_entry *)Xmalloc (sizeof (struct tb_entry) * MAX_L)))
+	  ok = 0;
+
+  if (!(NODEa && NODEb && NODEc && FIRST && NEXT && S.st && mk && g &&
+	tb && ok))
+    {
+      all_free ();
+      return (-1);
+    }
+#endif
+  return (0);
+}
+
+
+perf_hash_data *
+gen_hash_func (int num, u_char ** keys, int r)
+{
+  int n;
+  perf_hash_data *phd;
+  translate = (u_char *)Xmalloc (sizeof (u_char) * 256);
+  bzero ((char *) translate, sizeof (u_char) * 256);  /* [RPAP - Feb 97: WIN32 Port] */
+  make_trans_func (num, keys);
+
+  if (r <= 0)
+    SEED_RANDOM ((long) time ((time_t *) NULL));
+  else
+    SEED_RANDOM (r);
+
+  MAX_M = num + 1;
+
+  MAX_N = MAX_M + MAX_M / 4;
+
+  if (allocate_memory () == -1)
+    return (NULL);
+
+  /* construct an "acyclic" hypergraph */
+  tree_builder (num, keys, &n);
+  /* compute function g */
+  assign (n);
+
+  if (check (num) != 0)
+    FatalError (1, "An error has been detected in the mphf.");
+  temp_free ();
+
+  if (!(phd = (perf_hash_data *)Xmalloc (sizeof (perf_hash_data))))
+    return (NULL);
+
+  bcopy ((char *) &g[1], (char *) g, n * sizeof (int));
+
+  phd->MAX_L = MAX_L;
+  phd->MAX_N = n;
+  phd->MAX_M = num;
+  phd->MAX_CH = MAX_CH;
+  phd->translate = translate;
+  phd->g = g;
+#ifndef STRUCT
+  phd->tb0 = tb0;
+  phd->tb1 = tb1;
+  phd->tb2 = tb2;
+#else
+  phd->tb = tb;
+#endif
+  return (phd);
+}
+
+int 
+write_perf_hash_data (FILE * f, perf_hash_data * phd)
+{
+  int tot, i;
+  /* [RPAP - Jan 97: Endian Ordering] */
+  HTONSI(phd->MAX_L);
+  HTONSI(phd->MAX_N);
+  HTONSI(phd->MAX_M);
+  HTONSI(phd->MAX_CH);
+
+  tot = fwrite ((char *) &phd->MAX_L, sizeof (int), 1, f) * sizeof (int);
+  tot += fwrite ((char *) &phd->MAX_N, sizeof (int), 1, f) * sizeof (int);
+  tot += fwrite ((char *) &phd->MAX_M, sizeof (int), 1, f) * sizeof (int);
+  tot += fwrite ((char *) &phd->MAX_CH, sizeof (int), 1, f) * sizeof (int);
+
+  /* [RPAP - Jan 97: Endian Ordering] */
+  NTOHSI(phd->MAX_L);
+  NTOHSI(phd->MAX_N);
+  NTOHSI(phd->MAX_M);
+  NTOHSI(phd->MAX_CH);
+
+  tot += fwrite ((char *) phd->translate, sizeof (u_char), 256, f);
+
+  /* [RPAP - Jan 97: Endian Ordering] */
+  for (i = 0; i < phd->MAX_N + 1; i++)
+    HTONSI(phd->g[i]);
+
+  tot += fwrite ((char *) phd->g, sizeof (int), phd->MAX_N + 1, f) * sizeof (int);
+
+  /* [RPAP - Jan 97: Endian Ordering] */
+  for (i = 0; i < phd->MAX_N + 1; i++)
+    NTOHSI(phd->g[i]);
+
+#ifndef STRUCT
+  for (i = 0; i < phd->MAX_CH; i++)
+    {
+      /* [RPAP - Jan 97: Endian Ordering] */
+      int j;
+      for (j = 0; j < phd->MAX_L; j++)
+	{
+	  HTONSI(phd->tb0[i][j]);
+	  HTONSI(phd->tb1[i][j]);
+	  HTONSI(phd->tb2[i][j]);
+	}
+
+      tot += fwrite ((char *) phd->tb0[i], sizeof (int), phd->MAX_L, f) *
+        sizeof (int);
+      tot += fwrite ((char *) phd->tb1[i], sizeof (int), phd->MAX_L, f) *
+        sizeof (int);
+      tot += fwrite ((char *) phd->tb2[i], sizeof (int), phd->MAX_L, f) *
+        sizeof (int);
+
+      /* [RPAP - Jan 97: Endian Ordering] */
+      for (j = 0; j < phd->MAX_L; j++)
+	{
+	  NTOHSI(phd->tb0[i][j]);
+	  NTOHSI(phd->tb1[i][j]);
+	  NTOHSI(phd->tb2[i][j]);
+	}
+    }
+#else
+  for (i = 0; i < phd->MAX_CH; i++)
+    {
+      /* [RPAP - Jan 97: Endian Ordering] */
+      int j;
+      for (j = 0; j < phd->MAX_L; j++)
+	{
+	  HTONSL(phd->tb[i][j].tb0);
+	  HTONSL(phd->tb[i][j].tb1);
+	  HTONSL(phd->tb[i][j].tb2);
+	}
+
+      tot += fwrite ((char *) phd->tb[i], sizeof (struct tb_entry), phd->MAX_L, f) *
+	sizeof (struct tb_entry);
+
+      /* [RPAP - Jan 97: Endian Ordering] */
+      for (j = 0; j < phd->MAX_L; j++)
+	{
+	  NTOHSL(phd->tb[i][j].tb0);
+	  NTOHSL(phd->tb[i][j].tb1);
+	  NTOHSL(phd->tb[i][j].tb2);
+	}
+    }
+#endif
+  return (tot);
+}
+
+
+perf_hash_data *
+read_perf_hash_data (FILE * f)
+{
+  perf_hash_data *phd;
+  int i, tot, ok = 1;
+  if (!(phd = (perf_hash_data *)Xmalloc (sizeof (perf_hash_data))))
+    return (NULL);
+  tot = fread ((char *) &phd->MAX_L, sizeof (int), 1, f) * sizeof (int);
+  tot += fread ((char *) &phd->MAX_N, sizeof (int), 1, f) * sizeof (int);
+  tot += fread ((char *) &phd->MAX_M, sizeof (int), 1, f) * sizeof (int);
+  tot += fread ((char *) &phd->MAX_CH, sizeof (int), 1, f) * sizeof (int);
+
+  /* [RPAP - Jan 97: Endian Ordering] */
+  NTOHSI(phd->MAX_L);
+  NTOHSI(phd->MAX_N);
+  NTOHSI(phd->MAX_M);
+  NTOHSI(phd->MAX_CH);
+
+  if (tot != 4 * sizeof (int))
+      return (NULL);
+  phd->translate = (u_char *)Xmalloc (sizeof (u_char) * 256);
+  phd->g = (int *)Xmalloc (sizeof (int) * (phd->MAX_N + 1));
+#ifndef STRUCT
+  phd->tb0 = Xmalloc (sizeof (int *) * phd->MAX_CH);
+  phd->tb1 = Xmalloc (sizeof (int *) * phd->MAX_CH);
+  phd->tb2 = Xmalloc (sizeof (int *) * phd->MAX_CH);
+  for (i = 0; i < phd->MAX_CH; i++)
+    {
+      if (phd->tb0)
+	if (!(phd->tb0[i] = Xmalloc (sizeof (long) * phd->MAX_L)))
+	    ok = 0;
+      if (phd->tb1)
+	if (!(phd->tb1[i] = Xmalloc (sizeof (long) * phd->MAX_L)))
+	    ok = 0;
+      if (phd->tb2)
+	if (!(phd->tb2[i] = Xmalloc (sizeof (long) * phd->MAX_L)))
+	    ok = 0;
+    }
+  if (!(phd->translate && phd->g && phd->tb0 && phd->tb1 && phd->tb2 && ok))
+    {
+      if (phd->translate)
+	Xfree (phd->translate);
+      if (phd->g)
+	Xfree (phd->g);
+      for (i = 0; i < MAX_CH; i++)
+	{
+	  if (phd->tb0 && phd->tb0[i])
+	    Xfree (phd->tb0[i]);
+	  if (phd->tb1 && phd->tb1[i])
+	    Xfree (phd->tb1[i]);
+	  if (phd->tb2 && phd->tb2[i])
+	    Xfree (phd->tb2[i]);
+	}
+      if (phd->tb0)
+	Xfree (phd->tb0);
+      if (phd->tb1)
+	Xfree (phd->tb1);
+      if (phd->tb2)
+	Xfree (phd->tb2);
+      Xfree (phd);
+      return (NULL);
+    }
+  tot += fread ((char *) phd->translate, sizeof (u_char), 256, f);
+  tot += fread ((char *) phd->g, sizeof (int), phd->MAX_N + 1, f) * sizeof (int);
+
+  /* [RPAP - Jan 97: Endian Ordering] */
+  for (i = 0; i < phd->MAX_N + 1; i++)
+    NTOHSI(phd->g[i]);
+
+  for (i = 0; i < phd->MAX_CH; i++)
+    {
+      int j;
+
+      tot += fread ((char *) phd->tb0[i], sizeof (long), phd->MAX_L, f) *
+        sizeof (int);
+      tot += fread ((char *) phd->tb1[i], sizeof (long), phd->MAX_L, f) *
+        sizeof (int);
+      tot += fread ((char *) phd->tb2[i], sizeof (long), phd->MAX_L, f) *
+        sizeof (int);
+
+      /* [RPAP - Jan 97: Endian Ordering] */
+      for (j = 0; j < phd->MAX_L; j++)
+	{
+	  NTOHSI(phd->tb0[i][j]);
+	  NTOHSI(phd->tb1[i][j]);
+	  NTOHSI(phd->tb2[i][j]);
+	}
+    }
+#else
+  phd->tb = (struct tb_entry **)Xmalloc (sizeof (struct tb_entry *) * phd->MAX_CH);
+  for (i = 0; i < phd->MAX_CH; i++)
+    if (phd->tb)
+      if (!(phd->tb[i] = (struct tb_entry *)Xmalloc (sizeof (struct tb_entry) * phd->MAX_L)))
+	  ok = 0;
+  if (!(phd->translate && phd->g && phd->tb && ok))
+    {
+      if (phd->translate)
+	Xfree (phd->translate);
+      if (phd->g)
+	Xfree (phd->g);
+      for (i = 0; i < MAX_CH; i++)
+	if (phd->tb && phd->tb[i])
+	  Xfree (phd->tb[i]);
+      if (phd->tb)
+	Xfree (phd->tb);
+      Xfree (phd);
+      return (NULL);
+    }
+  tot += fread ((char *) phd->translate, sizeof (u_char), 256, f);
+  tot += fread ((char *) phd->g, sizeof (int), phd->MAX_N + 1, f) * sizeof (int);
+
+  /* [RPAP - Jan 97: Endian Ordering] */
+  for (i = 0; i < phd->MAX_N + 1; i++)
+    NTOHSI(phd->g[i]);
+
+  for (i = 0; i < phd->MAX_CH; i++)
+    {
+      int j;
+
+      tot += fread ((char *) phd->tb[i], sizeof (struct tb_entry), phd->MAX_L, f) *
+	sizeof (struct tb_entry);
+
+      /* [RPAP - Jan 97: Endian Ordering] */
+      for (j = 0; j < phd->MAX_L; j++)
+	{
+	  NTOHSL(phd->tb[i][j].tb0);
+	  NTOHSL(phd->tb[i][j].tb1);
+	  NTOHSL(phd->tb[i][j].tb2);
+	}
+    }
+#endif
+  return (phd);
+}
+
+void 
+free_perf_hash (perf_hash_data * phd)
+{
+  int i;
+  if (phd->translate)
+    Xfree (phd->translate);
+  if (phd->g)
+    Xfree (phd->g);
+  for (i = 0; i < phd->MAX_CH; i++)
+    if (phd->tb && phd->tb[i])
+      Xfree (phd->tb[i]);
+  if (phd->tb)
+    Xfree (phd->tb);
+  Xfree (phd);
+}
+
+
+int 
+perf_hash (perf_hash_data * phd, u_char * s)
+{
+  int u, v, w, i, l;
+  l = *s++;
+  i = (l - 1) % phd->MAX_L;
+  u = v = w = 0;
+  while (l)
+    {
+#ifndef STRUCT
+      if ((u += phd->tb0[phd->translate[*s]][i]) >= phd->MAX_N)
+	u -= phd->MAX_N;
+      if ((v += phd->tb1[phd->translate[*s]][i]) >= phd->MAX_N)
+	v -= phd->MAX_N;
+      if ((w += phd->tb2[phd->translate[*s]][i]) >= phd->MAX_N)
+	w -= phd->MAX_N;
+#else
+      struct tb_entry *tbp = &phd->tb[phd->translate[*s]][i];
+      if ((u += tbp->tb0) >= phd->MAX_N)
+	u -= phd->MAX_N;
+      if ((v += tbp->tb1) >= phd->MAX_N)
+	v -= phd->MAX_N;
+      if ((w += tbp->tb2) >= phd->MAX_N)
+	w -= phd->MAX_N;
+#endif
+      if (++i >= phd->MAX_L)
+	i = 0;
+      l--;
+      s++;
+    }
+  if (u == v && ++v >= phd->MAX_N)
+    v = 0;
+  if (w == v)
+    {
+      if (++w >= phd->MAX_N)
+	w = 0;
+      if (w == u && ++w >= phd->MAX_N)
+	w = 0;
+    }
+  else if (w == u)
+    {
+      if (++w >= phd->MAX_N)
+	w = 0;
+      if (w == v && ++w >= phd->MAX_N)
+	w = 0;
+    }
+  return ((phd->g[u] ^ phd->g[v] ^ phd->g[w]) > phd->MAX_M) ? 0 :
+    (phd->g[u] ^ phd->g[v] ^ phd->g[w]);
+}
Index: /main/tags/2.25/gsdl/src/mgpp/lib/perf_hash.h
===================================================================
--- /main/tags/2.25/gsdl/src/mgpp/lib/perf_hash.h	(revision 21064)
+++ /main/tags/2.25/gsdl/src/mgpp/lib/perf_hash.h	(revision 21064)
@@ -0,0 +1,57 @@
+/**************************************************************************
+ *
+ * perf_hash.h -- Perfect hashing functions
+ * Copyright (C) 1994  Bohdan S. Majewski and Neil Sharman
+ *
+ * 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.
+ *
+ * $Id$
+ *
+ **************************************************************************/
+
+#ifndef H_PERF_HASH
+#define H_PERF_HASH
+
+
+
+
+struct tb_entry
+  {
+    long tb0, tb1, tb2;
+  };
+
+typedef struct
+  {
+    int MAX_L;
+    int MAX_N;
+    int MAX_M;
+    int MAX_CH;
+    u_char *translate;
+    int *g;
+    struct tb_entry **tb;
+  }
+perf_hash_data;
+
+perf_hash_data *gen_hash_func (int num, u_char ** keys, int r);
+
+int perf_hash (perf_hash_data * phd, u_char * s);
+
+int write_perf_hash_data (FILE * f, perf_hash_data * phd);
+
+void free_perf_hash (perf_hash_data * phd);
+
+perf_hash_data *read_perf_hash_data (FILE * f);
+
+#endif
Index: /main/tags/2.25/gsdl/src/mgpp/lib/random.cpp
===================================================================
--- /main/tags/2.25/gsdl/src/mgpp/lib/random.cpp	(revision 21064)
+++ /main/tags/2.25/gsdl/src/mgpp/lib/random.cpp	(revision 21064)
@@ -0,0 +1,231 @@
+/**************************************************************************
+ *
+ * random.c -- pseudo random number generator
+ * Copyright (C) 1994  Chris Wallace (csw@bruce.cs.monash.edu.au)
+ *
+ * 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.
+ *
+ * $Id$
+ *
+ **************************************************************************/
+
+/*
+$Log$
+Revision 1.1  2000/01/14 02:17:14  sjboddie
+Rodgers new C++ mg
+
+Revision 1.1  1999/10/11 02:55:22  cs025
+Base install of MG-PP
+
+Revision 1.1  1999/08/10 21:16:57  sjboddie
+renamed mg-1.3d directory mg
+
+Revision 1.1  1998/11/17 09:32:20  rjmcnab
+*** empty log message ***
+
+*/
+
+static char *RCSID = "$Id$";
+
+/*
+ *	A random number generator called as a function by
+ *	random (iseed)	or	irandm (iseed)
+ *	The parameter should be a pointer to a 2-element long vector.
+ *	The first function returns a double uniform in 0 .. 1.
+ *	The second returns a long integer uniform in 0 .. 2**31-1
+ *	Both update iseed[] in exactly the same way.
+ *	iseed[] must be a 2-element integer vector.
+ *	The initial value of the second element may be anything.
+ *
+ *	The period of the random sequence is 2**32 * (2**32-1)
+ *	The table mt[0:127] is defined by mt[i] = 69069 ** (128-i)
+ */
+
+#define MASK ((long) 593970775)
+/*	or in hex, 23674657	*/
+
+#define SCALE ((double) 1.0 / (1024.0 * 1024.0 * 1024.0 * 2.0))
+/*	i.e. 2 to power -31	*/
+
+static long mt [128] =   {
+      902906369,
+     2030498053,
+     -473499623,
+     1640834941,
+      723406961,
+     1993558325,
+     -257162999,
+    -1627724755,
+      913952737,
+      278845029,
+     1327502073,
+    -1261253155,
+      981676113,
+    -1785280363,
+     1700077033,
+      366908557,
+    -1514479167,
+     -682799163,
+      141955545,
+     -830150595,
+      317871153,
+     1542036469,
+     -946413879,
+    -1950779155,
+      985397153,
+      626515237,
+      530871481,
+      783087261,
+    -1512358895,
+     1031357269,
+    -2007710807,
+    -1652747955,
+    -1867214463,
+      928251525,
+     1243003801,
+    -2132510467,
+     1874683889,
+     -717013323,
+      218254473,
+    -1628774995,
+    -2064896159,
+       69678053,
+      281568889,
+    -2104168611,
+     -165128239,
+     1536495125,
+      -39650967,
+      546594317,
+     -725987007,
+     1392966981,
+     1044706649,
+      687331773,
+    -2051306575,
+     1544302965,
+     -758494647,
+    -1243934099,
+      -75073759,
+      293132965,
+    -1935153095,
+      118929437,
+      807830417,
+    -1416222507,
+    -1550074071,
+      -84903219,
+     1355292929,
+     -380482555,
+    -1818444007,
+     -204797315,
+      170442609,
+    -1636797387,
+      868931593,
+     -623503571,
+     1711722209,
+      381210981,
+     -161547783,
+     -272740131,
+    -1450066095,
+     2116588437,
+     1100682473,
+      358442893,
+    -1529216831,
+     2116152005,
+     -776333095,
+     1265240893,
+     -482278607,
+     1067190005,
+      333444553,
+       86502381,
+      753481377,
+       39000101,
+     1779014585,
+      219658653,
+     -920253679,
+     2029538901,
+     1207761577,
+    -1515772851,
+     -236195711,
+      442620293,
+      423166617,
+    -1763648515,
+     -398436623,
+    -1749358155,
+     -538598519,
+     -652439379,
+      430550625,
+    -1481396507,
+     2093206905,
+    -1934691747,
+     -962631983,
+     1454463253,
+    -1877118871,
+     -291917555,
+    -1711673279,
+      201201733,
+     -474645415,
+      -96764739,
+    -1587365199,
+     1945705589,
+     1303896393,
+     1744831853,
+      381957665,
+     2135332261,
+      -55996615,
+    -1190135011,
+     1790562961,
+    -1493191723,
+      475559465,
+          69069
+		};
+
+double 
+random (long is [2])
+{
+	long it, leh, nit;
+
+	it = is [0];
+	leh = is [1];
+	if (it <= 0)	
+		it = (it + it) ^ MASK;
+	else
+		it = it + it;
+	nit = it - 1;
+/*	to ensure all-ones pattern omitted    */
+	leh = leh * mt[nit & 127] + nit;
+	is [0] = it;    is [1] = leh;
+	if (leh < 0) leh = ~leh;
+	return (SCALE * ((long) (leh | 1)));
+}
+
+
+
+long 
+irandm (long is [2])
+{
+	long it, leh, nit;
+
+	it = is [0];
+	leh = is [1];
+	if (it <= 0)	
+		it = (it + it) ^ MASK;
+	else
+		it = it + it;
+	nit = it - 1;
+/*	to ensure all-ones pattern omitted    */
+	leh = leh * mt[nit & 127] + nit;
+	is [0] = it;    is [1] = leh;
+	if (leh < 0) leh = ~leh;
+	return (leh);
+}
Index: /main/tags/2.25/gsdl/src/mgpp/lib/random.h
===================================================================
--- /main/tags/2.25/gsdl/src/mgpp/lib/random.h	(revision 21064)
+++ /main/tags/2.25/gsdl/src/mgpp/lib/random.h	(revision 21064)
@@ -0,0 +1,60 @@
+/**************************************************************************
+ *
+ * random.h -- pseudo random number generator
+ * Copyright (C) 1994  Chris Wallace (csw@bruce.cs.monash.edu.au)
+ *
+ * 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.
+ *
+ * $Id$
+ *
+ **************************************************************************/
+
+/*
+$Log$
+Revision 1.1  2000/01/14 02:17:15  sjboddie
+Rodgers new C++ mg
+
+Revision 1.1  1999/10/11 02:55:22  cs025
+Base install of MG-PP
+
+Revision 1.1  1999/08/10 21:16:58  sjboddie
+renamed mg-1.3d directory mg
+
+Revision 1.1  1998/11/17 09:32:21  rjmcnab
+*** empty log message ***
+
+*/
+
+#ifndef RANDOM_H
+#define RANDOM_H
+
+/*
+ *	A random number generator called as a function by
+ *	random (iseed)	or	irandm (iseed)
+ *	The parameter should be a pointer to a 2-element long vector.
+ *	The first function returns a double uniform in 0 .. 1.
+ *	The second returns a long integer uniform in 0 .. 2**31-1
+ *	Both update iseed[] in exactly the same way.
+ *	iseed[] must be a 2-element integer vector.
+ *	The initial value of the second element may be anything.
+ *
+ *	The period of the random sequence is 2**32 * (2**32-1)
+ *	The table mt[0:127] is defined by mt[i] = 69069 ** (128-i)
+ */
+
+double random (long is [2]);
+long irandm (long is [2]);
+
+#endif
Index: /main/tags/2.25/gsdl/src/mgpp/lib/simplefrenchstem.cpp
===================================================================
--- /main/tags/2.25/gsdl/src/mgpp/lib/simplefrenchstem.cpp	(revision 21064)
+++ /main/tags/2.25/gsdl/src/mgpp/lib/simplefrenchstem.cpp	(revision 21064)
@@ -0,0 +1,72 @@
+/**************************************************************************
+ *
+ * simplefrenchstem.c -- a simple french stemmer
+ *
+ * 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.
+ *
+ * $Id$
+ *
+ **************************************************************************/
+
+#include "simplefrenchstem.h"
+#include "unitool.h"
+
+
+/* =========================================================================
+ * Function: simplefrenchstem
+ * Description: a simple french stemmer
+ * Input: a word string with the length in the first byte
+ * Output: the stemmed word
+ * ========================================================================= */
+
+void simplefrenchstem (unsigned char *word) {      
+  unsigned short out[256]; /* temp space */
+  unsigned short *wordstart; /* points to first letter of word */
+  int last;                  /* last points to the last character */
+
+  /* decode */
+  utf8_word_to_unicode (word, out, 255);
+  wordstart = out + 1;
+  last = out[0]-1;
+  
+
+  if (last > 4) {
+    if (wordstart[last]=='x') {
+      if (wordstart[last-1]=='u' && wordstart[last-2]=='a') {
+	wordstart[last-1]='l';
+      }
+      last--;
+
+    } else {
+      if (last>=0 && wordstart[last]=='s') last--;
+      if (last>=0 && wordstart[last]=='r') last--;
+      if (last>=0 && wordstart[last]=='e') last--;
+
+      /* letter with accent e + ' -- there are two possible encodings  */
+      if (last>=0 && wordstart[last]==0xe9) { 
+	last--;
+      } else if (last>=1 && wordstart[last-1]=='e' && wordstart[last]==0x301) {
+	last -= 2; 
+      }
+
+      if (last >= 1 && wordstart[last]==wordstart[last-1]) last--;
+    }  /* end else */
+
+    out[0] = (unsigned char)(last+1);
+  } /* end if (len > 4) */
+
+  /* re-code, make sure the result is not longer than the input */
+  unicode_to_utf8_word (out, word, word[0]+1);
+}
Index: /main/tags/2.25/gsdl/src/mgpp/lib/simplefrenchstem.h
===================================================================
--- /main/tags/2.25/gsdl/src/mgpp/lib/simplefrenchstem.h	(revision 21064)
+++ /main/tags/2.25/gsdl/src/mgpp/lib/simplefrenchstem.h	(revision 21064)
@@ -0,0 +1,56 @@
+/**************************************************************************
+ *
+ * simplefrenchstem.h -- a simple french stemmer
+ *
+ * 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.
+ *
+ * $Id$
+ *
+ **************************************************************************/
+
+/*
+   $Log$
+   Revision 1.1  2000/01/14 02:17:15  sjboddie
+   Rodgers new C++ mg
+
+   Revision 1.1  1999/10/11 02:55:29  cs025
+   Base install of MG-PP
+
+   Revision 1.1  1999/08/10 21:17:04  sjboddie
+   renamed mg-1.3d directory mg
+
+   Revision 1.1  1998/11/25 07:55:37  rjmcnab
+
+   Modified mg to that you can specify the stemmer you want
+   to use via a command line option. You specify it to
+   mg_passes during the build process. The number of the
+   stemmer that you used is stored within the inverted
+   dictionary header and the stemmed dictionary header so
+   the correct stemmer is used in later stages of building
+   and querying.
+
+   Revision 1.1  1998/11/24 06:37:53  rjmcnab
+
+   Incorporated the french stemmer better.
+
+
+ */
+
+#ifndef SIMPLEFRENCHSTEM_H
+#define SIMPLEFRENCHSTEM_H
+
+void simplefrenchstem (unsigned char *word);
+
+#endif
Index: /main/tags/2.25/gsdl/src/mgpp/lib/strcasecmp.cpp
===================================================================
--- /main/tags/2.25/gsdl/src/mgpp/lib/strcasecmp.cpp	(revision 21064)
+++ /main/tags/2.25/gsdl/src/mgpp/lib/strcasecmp.cpp	(revision 21064)
@@ -0,0 +1,74 @@
+/*
+ * Copyright (c) 1987 Regents of the University of California.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms are permitted
+ * provided that this notice is preserved and that due credit is given
+ * to the University of California at Berkeley. The name of the University
+ * may not be used to endorse or promote products derived from this
+ * software without specific written prior permission. This software
+ * is provided ``as is'' without express or implied warranty.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static char sccsid[] = "@(#)strcasecmp.c	5.5 (Berkeley) 11/24/87";
+#endif /* LIBC_SCCS and not lint */
+
+/*
+ * This array is designed for mapping upper and lower case letter
+ * together for a case independent comparison.  The mappings are
+ * based upon ascii character sequences.
+ */
+static unsigned char charmap[] = {
+	'\000', '\001', '\002', '\003', '\004', '\005', '\006', '\007',
+	'\010', '\011', '\012', '\013', '\014', '\015', '\016', '\017',
+	'\020', '\021', '\022', '\023', '\024', '\025', '\026', '\027',
+	'\030', '\031', '\032', '\033', '\034', '\035', '\036', '\037',
+	'\040', '\041', '\042', '\043', '\044', '\045', '\046', '\047',
+	'\050', '\051', '\052', '\053', '\054', '\055', '\056', '\057',
+	'\060', '\061', '\062', '\063', '\064', '\065', '\066', '\067',
+	'\070', '\071', '\072', '\073', '\074', '\075', '\076', '\077',
+	'\100', '\141', '\142', '\143', '\144', '\145', '\146', '\147',
+	'\150', '\151', '\152', '\153', '\154', '\155', '\156', '\157',
+	'\160', '\161', '\162', '\163', '\164', '\165', '\166', '\167',
+	'\170', '\171', '\172', '\133', '\134', '\135', '\136', '\137',
+	'\140', '\141', '\142', '\143', '\144', '\145', '\146', '\147',
+	'\150', '\151', '\152', '\153', '\154', '\155', '\156', '\157',
+	'\160', '\161', '\162', '\163', '\164', '\165', '\166', '\167',
+	'\170', '\171', '\172', '\173', '\174', '\175', '\176', '\177',
+	'\200', '\201', '\202', '\203', '\204', '\205', '\206', '\207',
+	'\210', '\211', '\212', '\213', '\214', '\215', '\216', '\217',
+	'\220', '\221', '\222', '\223', '\224', '\225', '\226', '\227',
+	'\230', '\231', '\232', '\233', '\234', '\235', '\236', '\237',
+	'\240', '\241', '\242', '\243', '\244', '\245', '\246', '\247',
+	'\250', '\251', '\252', '\253', '\254', '\255', '\256', '\257',
+	'\260', '\261', '\262', '\263', '\264', '\265', '\266', '\267',
+	'\270', '\271', '\272', '\273', '\274', '\275', '\276', '\277',
+	'\300', '\341', '\342', '\343', '\344', '\345', '\346', '\347',
+	'\350', '\351', '\352', '\353', '\354', '\355', '\356', '\357',
+	'\360', '\361', '\362', '\363', '\364', '\365', '\366', '\367',
+	'\370', '\371', '\372', '\333', '\334', '\335', '\336', '\337',
+	'\340', '\341', '\342', '\343', '\344', '\345', '\346', '\347',
+	'\350', '\351', '\352', '\353', '\354', '\355', '\356', '\357',
+	'\360', '\361', '\362', '\363', '\364', '\365', '\366', '\367',
+	'\370', '\371', '\372', '\373', '\374', '\375', '\376', '\377',
+};
+
+int
+strcasecmp(s1, s2)
+    char *s1, *s2;
+{
+    register unsigned char u1, u2;
+
+    for (;;) {
+	u1 = (unsigned char) *s1++;
+	u2 = (unsigned char) *s2++;
+	if (charmap[u1] != charmap[u2]) {
+	    return charmap[u1] - charmap[u2];
+	}
+	if (u1 == '\0') {
+	    return 0;
+	}
+    }
+}
+
Index: /main/tags/2.25/gsdl/src/mgpp/lib/strstr.cpp
===================================================================
--- /main/tags/2.25/gsdl/src/mgpp/lib/strstr.cpp	(revision 21064)
+++ /main/tags/2.25/gsdl/src/mgpp/lib/strstr.cpp	(revision 21064)
@@ -0,0 +1,44 @@
+/* strstr.c -- return the offset of one string within another
+   Copyright (C) 1989, 1990 Free Software Foundation, Inc.
+
+   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, 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.  */
+
+/* Written by Mike Rendell <michael@cs.mun.ca>.  */
+
+/* Return the starting address of string S2 in S1;
+   return 0 if it is not found. */
+
+char *
+strstr (s1, s2)
+     char *s1;
+     char *s2;
+{
+  int i;
+  char *p1;
+  char *p2;
+  char *s = s1;
+
+  for (p2 = s2, i = 0; *s; p2 = s2, i++, s++)
+    {
+      for (p1 = s; *p1 && *p2 && *p1 == *p2; p1++, p2++)
+	;
+      if (!*p2)
+	break;
+    }
+  if (!*p2)
+    return s1 + i;
+
+  return 0;
+}
Index: /main/tags/2.25/gsdl/src/mgpp/lib/sysfuncs.cpp
===================================================================
--- /main/tags/2.25/gsdl/src/mgpp/lib/sysfuncs.cpp	(revision 21064)
+++ /main/tags/2.25/gsdl/src/mgpp/lib/sysfuncs.cpp	(revision 21064)
@@ -0,0 +1,6 @@
+#include <stdlib.h>
+
+void *bcopy(void *s, void *d, int n)
+{ return memcpy(d, s, n);
+}
+
Index: /main/tags/2.25/gsdl/src/mgpp/lib/sysfuncs.h
===================================================================
--- /main/tags/2.25/gsdl/src/mgpp/lib/sysfuncs.h	(revision 21064)
+++ /main/tags/2.25/gsdl/src/mgpp/lib/sysfuncs.h	(revision 21064)
@@ -0,0 +1,378 @@
+/* System dependent definitions for GNU tar.
+   Copyright (C) 1994 Free Software Foundation, Inc.
+
+   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, 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.
+ */
+
+/*
+ * [TS:Aug/95]
+ * Based on code from system.h file in GNU's tar package 
+ *
+ */
+
+#ifndef SYSFUNCS_H
+#define SYSFUNCS_H
+
+#include <sys/stat.h>
+
+/* [RPAP - Feb 97: WIN32 Port] */
+#ifdef HAVE_CONFIG_H
+# ifdef __WIN32__
+#  include <WIN32cfg.h>
+# else
+#  include <config.h>
+# endif
+#endif
+
+/* Declare alloca.  AIX requires this to be the first thing in the file.  */
+
+#ifdef __GNUC__
+#define alloca __builtin_alloca
+#else
+#if HAVE_ALLOCA_H
+#include <alloca.h>
+#else
+#ifdef _AIX
+#pragma alloca
+#else
+#ifndef alloca
+char *alloca ();
+#endif
+#endif
+#endif
+#endif
+
+#include <sys/types.h>
+
+/* ------------------------------------------------- */
+/* [TS:Aug/95]
+ * Some extra include files that mg needs
+ */
+#include <stdlib.h>
+#include <math.h>
+
+#ifndef log2
+# ifndef M_LN2
+#  define M_LN2 0.69314718055994530942
+# endif
+# define log2(x) (log(x)/M_LN2)
+#endif
+
+
+#ifndef HAVE_SETBUFFER
+# define setbuffer(f, b, s)  setvbuf(f, b, _IOFBF, s)
+#endif
+
+/* [RPAP - Feb 97: WIN32 Port] */
+#if defined(__MSDOS__)  && !defined(__WIN32__)
+# define SHORT_SUFFIX 1
+#endif
+
+
+
+#include <assert.h>
+
+/* ------------------------------------------------- */
+
+/* Declare a generic pointer type.  */
+#if __STDC__ || defined(__TURBOC__)
+#define voidstar void *
+#else
+#define voidstar char *
+#endif
+
+/* Declare ISASCII.  */
+
+#include <ctype.h>
+
+#if STDC_HEADERS
+#define ISASCII(Char) 1
+#else
+#ifdef isascii
+#define ISASCII(Char) isascii (Char)
+#else
+#if HAVE_ISASCII
+#define ISASCII(Char) isascii (Char)
+#else
+#define ISASCII(Char) 1
+#endif
+#endif
+#endif
+
+
+/* ------------------------------------------------- */
+/* [TS:Aug/95] 
+ * The following is copied from GNU Autoconf.Info (1.1)   
+ * It sets up the approriate string and memory functions.
+ */
+
+#if STDC_HEADERS || HAVE_STRING_H
+#include <string.h>
+   /* An ANSI string.h and pre-ANSI memory.h might conflict */
+#if !STDC_HEADERS && HAVE_MEMORY_H
+#include <memory.h>
+#endif /* not STDC_HEADERS and HAVE_MEMORY_H */
+#ifndef index
+/*#define index strchr 
+ *
+ * this is stuffing up our code so its commented out */
+#endif
+#ifndef rindex
+#define rindex strrchr
+#endif
+
+#ifdef __cplusplus /* compiling for C++ */
+#include <stdlib.h>
+#ifndef __bcopy
+inline void *bcopy(void *s, void *d, int n)
+{ return memcpy(d, s, n);
+}
+#define __bcopy 1
+#endif
+#ifndef __bcmp
+inline int bcmp(void *s1, void *s2, int n)
+{ return memcmp(s1, s2, n);
+}
+#define __bcmp 1
+#endif
+#ifndef __bzero
+inline void bzero(void *m, int n)
+{ memset(m, 0, n);
+}
+#define __bzero 1
+#endif
+#else              /* compiling for C */
+#ifndef bcopy
+#define bcopy(s, d, n) memcpy((d), (s), (n))
+#endif
+#ifndef bcmp
+#define bcmp(s1, s2, n) memcmp((s1), (s2), (n))
+#endif
+#ifndef bzero
+#define bzero(s, n) memset((s), 0, (n))
+#endif
+#endif
+
+#else /* not STDC_HEADERS and not HAVE_STRING_H */
+#include <strings.h>
+   /* memory.h and strings.h conflict on some systems */
+#endif
+/* ------------------------------------------------- */
+
+
+/* Declare errno.  */
+
+#include <errno.h>
+#ifndef errno
+extern int errno;
+#endif
+
+/* Declare open parameters.  */
+
+#ifdef HAVE_FCNTL_H
+#include <fcntl.h>
+#else
+#include <sys/file.h>
+#endif
+
+#ifndef	O_BINARY
+#define O_BINARY 0
+#endif
+#ifndef O_CREAT
+#define O_CREAT 0
+#endif
+#ifndef	O_NDELAY
+#define O_NDELAY 0
+#endif
+#ifndef	O_RDONLY
+#define O_RDONLY 0
+#endif
+#ifndef O_RDWR
+#define O_RDWR 2
+#endif
+
+/* Declare file status routines and bits.  */
+
+#ifdef STAT_MACROS_BROKEN
+#undef S_ISBLK
+#undef S_ISCHR
+#undef S_ISDIR
+#undef S_ISFIFO
+#undef S_ISLNK
+#undef S_ISMPB
+#undef S_ISMPC
+#undef S_ISNWK
+#undef S_ISREG
+#undef S_ISSOCK
+#endif
+
+/* On MSDOS, there are missing things from <sys/stat.h>.  */
+#ifdef __MSDOS__
+#define S_ISUID 0
+#define S_ISGID 0
+#define S_ISVTX 0
+#endif
+
+#ifndef S_ISREG			/* POSIX.1 stat stuff missing */
+#define mode_t unsigned short
+#endif
+#if !defined(S_ISBLK) && defined(S_IFBLK)
+#define S_ISBLK(Mode) (((Mode) & S_IFMT) == S_IFBLK)
+#endif
+#if !defined(S_ISCHR) && defined(S_IFCHR)
+#define S_ISCHR(Mode) (((Mode) & S_IFMT) == S_IFCHR)
+#endif
+#if !defined(S_ISDIR) && defined(S_IFDIR)
+#define S_ISDIR(Mode) (((Mode) & S_IFMT) == S_IFDIR)
+#endif
+#if !defined(S_ISREG) && defined(S_IFREG)
+#define S_ISREG(Mode) (((Mode) & S_IFMT) == S_IFREG)
+#endif
+#if !defined(S_ISFIFO) && defined(S_IFIFO)
+#define S_ISFIFO(Mode) (((Mode) & S_IFMT) == S_IFIFO)
+#endif
+#if !defined(S_ISLNK) && defined(S_IFLNK)
+#define S_ISLNK(Mode) (((Mode) & S_IFMT) == S_IFLNK)
+#endif
+#if !defined(S_ISSOCK) && defined(S_IFSOCK)
+#define S_ISSOCK(Mode) (((Mode) & S_IFMT) == S_IFSOCK)
+#endif
+#if !defined(S_ISMPB) && defined(S_IFMPB)	/* V7 */
+#define S_ISMPB(Mode) (((Mode) & S_IFMT) == S_IFMPB)
+#define S_ISMPC(Mode) (((Mode) & S_IFMT) == S_IFMPC)
+#endif
+#if !defined(S_ISNWK) && defined(S_IFNWK)	/* HP/UX */
+#define S_ISNWK(Mode) (((Mode) & S_IFMT) == S_IFNWK)
+#endif
+
+#if !defined(S_ISCTG) && defined(S_IFCTG)	/* contiguous file */
+#define S_ISCTG(Mode) (((Mode) & S_IFMT) == S_IFCTG)
+#endif
+#if !defined(S_ISVTX)
+#define S_ISVTX 0001000
+#endif
+
+/* [RPAP - Feb 97: WIN32 Port] */
+#if !defined(_POSIX_SOURCE) && !defined(__WIN32__)
+#include <sys/param.h>
+#endif
+
+/* Include <unistd.h> before any preprocessor test of _POSIX_VERSION.  */
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+
+
+/* Declare standard functions.  */
+
+#ifdef STDC_HEADERS
+#include <stdlib.h>
+#else
+voidstar malloc ();
+voidstar realloc ();
+char *getenv ();
+#endif
+
+#include <stdio.h>
+
+#ifndef _POSIX_VERSION
+#ifdef __MSDOS__
+#include <io.h>
+#else
+off_t lseek ();
+#endif
+#endif
+
+#include <pathmax.h>
+
+/* Until getoptold function is declared in getopt.h, we need this here for
+   struct option.  */
+#include <getopt.h>
+
+#ifdef WITH_DMALLOC
+#undef HAVE_VALLOC
+#define DMALLOC_FUNC_CHECK
+#include <dmalloc.h>
+#endif
+
+/* Prototypes for external functions.  */
+
+#ifndef __P
+#if PROTOTYPES
+#define __P(Args) Args
+#else
+#define __P(Args) ()
+#endif
+#endif
+
+#if HAVE_LOCALE_H
+#include <locale.h>
+#endif
+#if !HAVE_SETLOCALE
+#define setlocale(Category, Locale)
+#endif
+
+#if ENABLE_NLS
+#include <libintl.h>
+#define _(Text) gettext (Text)
+#else
+#define textdomain(Domain)
+#define _(Text) Text
+#endif
+
+/* Library modules.  */
+
+#ifdef HAVE_VPRINTF
+void error __P ((int, int, const char *,...));
+#else
+void error ();
+#endif
+
+#ifndef HAVE_STRSTR
+char *strstr __P ((const char *, const char *));
+#endif
+
+/* [RB/TS:Oct/95] commented out. Used by lib/gmalloc.c - but it defines it anyway ???
+ *#ifndef HAVE_VALLOC
+ *#define valloc(Size) malloc (Size)
+ *#endif
+ */
+
+voidstar xmalloc __P ((size_t));
+voidstar xrealloc __P ((voidstar, size_t));
+char *xstrdup __P ((const char *));
+
+/* [TS:Aug/95] 
+ * These were required by files which referred 
+ * to these as function pointers. 
+ * e.g. huffman.c - fread,  mgfelics.c - fgetc
+ */
+#ifndef HAVE_FREAD_DECL
+extern size_t   fread __P ((void *, size_t, size_t, FILE *));
+#endif
+#ifndef HAVE_FGETC_DECL
+extern int      fgetc __P ((FILE *));
+#endif
+
+/* [RPAP - Feb 97: WIN32 Port] */
+#ifndef u_long
+# define u_long unsigned long
+#endif
+#ifndef u_char
+# define u_char unsigned char
+#endif
+
+
+#endif /* SYSFUNCS_H */
Index: /main/tags/2.25/gsdl/src/mgpp/lib/unitool.cpp
===================================================================
--- /main/tags/2.25/gsdl/src/mgpp/lib/unitool.cpp	(revision 21064)
+++ /main/tags/2.25/gsdl/src/mgpp/lib/unitool.cpp	(revision 21064)
@@ -0,0 +1,1756 @@
+#include "unitool.h"
+#include "sysfuncs.h"
+
+
+/* unicode_cat_data is a combination of the letter, digit, and
+ * space information in a form that is quick to look up.
+ * The information about each byte is stored in two bits
+ *
+ * 00 - neither letter, digit or space
+ * 01 - letter
+ * 10 - space
+ * 11 - digit
+ *
+ * You can test for letter | space by looking at the right
+ * column
+ */
+unsigned long *unicode_cat_data=NULL;
+
+
+typedef struct unidecompose {
+  unsigned short ch;
+  unsigned short str[3];
+} unidecompose;
+
+typedef struct unirelate {
+  unsigned short ch1;
+  unsigned short ch2;
+} unirelate;
+
+typedef struct unirange {
+  unsigned short first;
+  unsigned short last;
+} unirange;
+
+
+
+/* This decomposition data only includes canonical decompositional
+ * characters.  Any unused bytes are set to 0x0. */
+
+#define NUM_DECOMPOSE_INFO 1269
+static const unidecompose decompose_info[NUM_DECOMPOSE_INFO] = {
+  {0xC0,0x41,0x300,0x0}, {0xC1,0x41,0x301,0x0}, {0xC2,0x41,0x302,0x0}, 
+  {0xC3,0x41,0x303,0x0}, {0xC4,0x41,0x308,0x0}, {0xC5,0x41,0x30A,0x0}, 
+  {0xC7,0x43,0x327,0x0}, {0xC8,0x45,0x300,0x0}, {0xC9,0x45,0x301,0x0}, 
+  {0xCA,0x45,0x302,0x0}, {0xCB,0x45,0x308,0x0}, {0xCC,0x49,0x300,0x0}, 
+  {0xCD,0x49,0x301,0x0}, {0xCE,0x49,0x302,0x0}, {0xCF,0x49,0x308,0x0}, 
+  {0xD1,0x4E,0x303,0x0}, {0xD2,0x4F,0x300,0x0}, {0xD3,0x4F,0x301,0x0}, 
+  {0xD4,0x4F,0x302,0x0}, {0xD5,0x4F,0x303,0x0}, {0xD6,0x4F,0x308,0x0}, 
+  {0xD9,0x55,0x300,0x0}, {0xDA,0x55,0x301,0x0}, {0xDB,0x55,0x302,0x0}, 
+  {0xDC,0x55,0x308,0x0}, {0xDD,0x59,0x301,0x0}, {0xE0,0x61,0x300,0x0}, 
+  {0xE1,0x61,0x301,0x0}, {0xE2,0x61,0x302,0x0}, {0xE3,0x61,0x303,0x0}, 
+  {0xE4,0x61,0x308,0x0}, {0xE5,0x61,0x30A,0x0}, {0xE7,0x63,0x327,0x0}, 
+  {0xE8,0x65,0x300,0x0}, {0xE9,0x65,0x301,0x0}, {0xEA,0x65,0x302,0x0}, 
+  {0xEB,0x65,0x308,0x0}, {0xEC,0x69,0x300,0x0}, {0xED,0x69,0x301,0x0}, 
+  {0xEE,0x69,0x302,0x0}, {0xEF,0x69,0x308,0x0}, {0xF1,0x6E,0x303,0x0}, 
+  {0xF2,0x6F,0x300,0x0}, {0xF3,0x6F,0x301,0x0}, {0xF4,0x6F,0x302,0x0}, 
+  {0xF5,0x6F,0x303,0x0}, {0xF6,0x6F,0x308,0x0}, {0xF9,0x75,0x300,0x0}, 
+  {0xFA,0x75,0x301,0x0}, {0xFB,0x75,0x302,0x0}, {0xFC,0x75,0x308,0x0}, 
+  {0xFD,0x79,0x301,0x0}, {0xFF,0x79,0x308,0x0}, {0x100,0x41,0x304,0x0}, 
+  {0x101,0x61,0x304,0x0}, {0x102,0x41,0x306,0x0}, {0x103,0x61,0x306,0x0}, 
+  {0x104,0x41,0x328,0x0}, {0x105,0x61,0x328,0x0}, {0x106,0x43,0x301,0x0}, 
+  {0x107,0x63,0x301,0x0}, {0x108,0x43,0x302,0x0}, {0x109,0x63,0x302,0x0}, 
+  {0x10A,0x43,0x307,0x0}, {0x10B,0x63,0x307,0x0}, {0x10C,0x43,0x30C,0x0}, 
+  {0x10D,0x63,0x30C,0x0}, {0x10E,0x44,0x30C,0x0}, {0x10F,0x64,0x30C,0x0}, 
+  {0x112,0x45,0x304,0x0}, {0x113,0x65,0x304,0x0}, {0x114,0x45,0x306,0x0}, 
+  {0x115,0x65,0x306,0x0}, {0x116,0x45,0x307,0x0}, {0x117,0x65,0x307,0x0}, 
+  {0x118,0x45,0x328,0x0}, {0x119,0x65,0x328,0x0}, {0x11A,0x45,0x30C,0x0}, 
+  {0x11B,0x65,0x30C,0x0}, {0x11C,0x47,0x302,0x0}, {0x11D,0x67,0x302,0x0}, 
+  {0x11E,0x47,0x306,0x0}, {0x11F,0x67,0x306,0x0}, {0x120,0x47,0x307,0x0}, 
+  {0x121,0x67,0x307,0x0}, {0x122,0x47,0x327,0x0}, {0x123,0x67,0x327,0x0}, 
+  {0x124,0x48,0x302,0x0}, {0x125,0x68,0x302,0x0}, {0x128,0x49,0x303,0x0}, 
+  {0x129,0x69,0x303,0x0}, {0x12A,0x49,0x304,0x0}, {0x12B,0x69,0x304,0x0}, 
+  {0x12C,0x49,0x306,0x0}, {0x12D,0x69,0x306,0x0}, {0x12E,0x49,0x328,0x0}, 
+  {0x12F,0x69,0x328,0x0}, {0x130,0x49,0x307,0x0}, {0x134,0x4A,0x302,0x0}, 
+  {0x135,0x6A,0x302,0x0}, {0x136,0x4B,0x327,0x0}, {0x137,0x6B,0x327,0x0}, 
+  {0x139,0x4C,0x301,0x0}, {0x13A,0x6C,0x301,0x0}, {0x13B,0x4C,0x327,0x0}, 
+  {0x13C,0x6C,0x327,0x0}, {0x13D,0x4C,0x30C,0x0}, {0x13E,0x6C,0x30C,0x0}, 
+  {0x143,0x4E,0x301,0x0}, {0x144,0x6E,0x301,0x0}, {0x145,0x4E,0x327,0x0}, 
+  {0x146,0x6E,0x327,0x0}, {0x147,0x4E,0x30C,0x0}, {0x148,0x6E,0x30C,0x0}, 
+  {0x14C,0x4F,0x304,0x0}, {0x14D,0x6F,0x304,0x0}, {0x14E,0x4F,0x306,0x0}, 
+  {0x14F,0x6F,0x306,0x0}, {0x150,0x4F,0x30B,0x0}, {0x151,0x6F,0x30B,0x0}, 
+  {0x154,0x52,0x301,0x0}, {0x155,0x72,0x301,0x0}, {0x156,0x52,0x327,0x0}, 
+  {0x157,0x72,0x327,0x0}, {0x158,0x52,0x30C,0x0}, {0x159,0x72,0x30C,0x0}, 
+  {0x15A,0x53,0x301,0x0}, {0x15B,0x73,0x301,0x0}, {0x15C,0x53,0x302,0x0}, 
+  {0x15D,0x73,0x302,0x0}, {0x15E,0x53,0x327,0x0}, {0x15F,0x73,0x327,0x0}, 
+  {0x160,0x53,0x30C,0x0}, {0x161,0x73,0x30C,0x0}, {0x162,0x54,0x327,0x0}, 
+  {0x163,0x74,0x327,0x0}, {0x164,0x54,0x30C,0x0}, {0x165,0x74,0x30C,0x0}, 
+  {0x168,0x55,0x303,0x0}, {0x169,0x75,0x303,0x0}, {0x16A,0x55,0x304,0x0}, 
+  {0x16B,0x75,0x304,0x0}, {0x16C,0x55,0x306,0x0}, {0x16D,0x75,0x306,0x0}, 
+  {0x16E,0x55,0x30A,0x0}, {0x16F,0x75,0x30A,0x0}, {0x170,0x55,0x30B,0x0}, 
+  {0x171,0x75,0x30B,0x0}, {0x172,0x55,0x328,0x0}, {0x173,0x75,0x328,0x0}, 
+  {0x174,0x57,0x302,0x0}, {0x175,0x77,0x302,0x0}, {0x176,0x59,0x302,0x0}, 
+  {0x177,0x79,0x302,0x0}, {0x178,0x59,0x308,0x0}, {0x179,0x5A,0x301,0x0}, 
+  {0x17A,0x7A,0x301,0x0}, {0x17B,0x5A,0x307,0x0}, {0x17C,0x7A,0x307,0x0}, 
+  {0x17D,0x5A,0x30C,0x0}, {0x17E,0x7A,0x30C,0x0}, {0x1A0,0x4F,0x31B,0x0}, 
+  {0x1A1,0x6F,0x31B,0x0}, {0x1AF,0x55,0x31B,0x0}, {0x1B0,0x75,0x31B,0x0}, 
+  {0x1CD,0x41,0x30C,0x0}, {0x1CE,0x61,0x30C,0x0}, {0x1CF,0x49,0x30C,0x0}, 
+  {0x1D0,0x69,0x30C,0x0}, {0x1D1,0x4F,0x30C,0x0}, {0x1D2,0x6F,0x30C,0x0}, 
+  {0x1D3,0x55,0x30C,0x0}, {0x1D4,0x75,0x30C,0x0}, {0x1D5,0xDC,0x304,0x0}, 
+  {0x1D6,0xFC,0x304,0x0}, {0x1D7,0xDC,0x301,0x0}, {0x1D8,0xFC,0x301,0x0}, 
+  {0x1D9,0xDC,0x30C,0x0}, {0x1DA,0xFC,0x30C,0x0}, {0x1DB,0xDC,0x300,0x0}, 
+  {0x1DC,0xFC,0x300,0x0}, {0x1DE,0xC4,0x304,0x0}, {0x1DF,0xE4,0x304,0x0}, 
+  {0x1E0,0x41,0x307,0x304}, {0x1E1,0x61,0x307,0x304}, {0x1E2,0xC6,0x304,0x0}, 
+  {0x1E3,0xE6,0x304,0x0}, {0x1E6,0x47,0x30C,0x0}, {0x1E7,0x67,0x30C,0x0}, 
+  {0x1E8,0x4B,0x30C,0x0}, {0x1E9,0x6B,0x30C,0x0}, {0x1EA,0x4F,0x328,0x0}, 
+  {0x1EB,0x6F,0x328,0x0}, {0x1EC,0x1EA,0x304,0x0}, {0x1ED,0x1EB,0x304,0x0}, 
+  {0x1EE,0x1B7,0x30C,0x0}, {0x1EF,0x292,0x30C,0x0}, {0x1F0,0x6A,0x30C,0x0}, 
+  {0x1F4,0x47,0x301,0x0}, {0x1F5,0x67,0x301,0x0}, {0x1FA,0xC5,0x301,0x0}, 
+  {0x1FB,0xE5,0x301,0x0}, {0x1FC,0xC6,0x301,0x0}, {0x1FD,0xE6,0x301,0x0}, 
+  {0x1FE,0xD8,0x301,0x0}, {0x1FF,0xF8,0x301,0x0}, {0x200,0x41,0x30F,0x0}, 
+  {0x201,0x61,0x30F,0x0}, {0x202,0x41,0x311,0x0}, {0x203,0x61,0x311,0x0}, 
+  {0x204,0x45,0x30F,0x0}, {0x205,0x65,0x30F,0x0}, {0x206,0x45,0x311,0x0}, 
+  {0x207,0x65,0x311,0x0}, {0x208,0x49,0x30F,0x0}, {0x209,0x69,0x30F,0x0}, 
+  {0x20A,0x49,0x311,0x0}, {0x20B,0x69,0x311,0x0}, {0x20C,0x4F,0x30F,0x0}, 
+  {0x20D,0x6F,0x30F,0x0}, {0x20E,0x4F,0x311,0x0}, {0x20F,0x6F,0x311,0x0}, 
+  {0x210,0x52,0x30F,0x0}, {0x211,0x72,0x30F,0x0}, {0x212,0x52,0x311,0x0}, 
+  {0x213,0x72,0x311,0x0}, {0x214,0x55,0x30F,0x0}, {0x215,0x75,0x30F,0x0}, 
+  {0x216,0x55,0x311,0x0}, {0x217,0x75,0x311,0x0}, {0x310,0x306,0x307,0x0}, 
+  {0x340,0x300,0x0,0x0}, {0x341,0x301,0x0,0x0}, {0x343,0x313,0x0,0x0}, 
+  {0x344,0x308,0x30D,0x0}, {0x374,0x2B9,0x0,0x0}, {0x37E,0x3B,0x0,0x0}, 
+  {0x385,0xA8,0x30D,0x0}, {0x386,0x391,0x30D,0x0}, {0x387,0xB7,0x0,0x0}, 
+  {0x388,0x395,0x30D,0x0}, {0x389,0x397,0x30D,0x0}, {0x38A,0x399,0x30D,0x0}, 
+  {0x38C,0x39F,0x30D,0x0}, {0x38E,0x3A5,0x30D,0x0}, {0x38F,0x3A9,0x30D,0x0}, 
+  {0x390,0x3B9,0x344,0x0}, {0x3AA,0x399,0x308,0x0}, {0x3AB,0x3A5,0x308,0x0}, 
+  {0x3AC,0x3B1,0x30D,0x0}, {0x3AD,0x3B5,0x30D,0x0}, {0x3AE,0x3B7,0x30D,0x0}, 
+  {0x3AF,0x3B9,0x30D,0x0}, {0x3B0,0x3C5,0x344,0x0}, {0x3CA,0x3B9,0x308,0x0}, 
+  {0x3CB,0x3C5,0x308,0x0}, {0x3CC,0x3BF,0x30D,0x0}, {0x3CD,0x3C5,0x30D,0x0}, 
+  {0x3CE,0x3C9,0x30D,0x0}, {0x3D3,0x3D2,0x30D,0x0}, {0x3D4,0x3D2,0x308,0x0}, 
+  {0x401,0x415,0x308,0x0}, {0x403,0x413,0x301,0x0}, {0x407,0x406,0x308,0x0}, 
+  {0x40C,0x41A,0x301,0x0}, {0x40E,0x423,0x306,0x0}, {0x419,0x418,0x306,0x0}, 
+  {0x439,0x438,0x306,0x0}, {0x451,0x435,0x308,0x0}, {0x453,0x433,0x301,0x0}, 
+  {0x457,0x456,0x308,0x0}, {0x45C,0x43A,0x301,0x0}, {0x45E,0x443,0x306,0x0}, 
+  {0x476,0x474,0x30F,0x0}, {0x477,0x475,0x30F,0x0}, {0x4C1,0x416,0x306,0x0}, 
+  {0x4C2,0x436,0x306,0x0}, {0x4D0,0x410,0x306,0x0}, {0x4D1,0x430,0x306,0x0}, 
+  {0x4D2,0x410,0x308,0x0}, {0x4D3,0x430,0x308,0x0}, {0x4D6,0x415,0x306,0x0}, 
+  {0x4D7,0x435,0x306,0x0}, {0x4DA,0x4D8,0x308,0x0}, {0x4DB,0x4D9,0x308,0x0}, 
+  {0x4DC,0x416,0x308,0x0}, {0x4DD,0x436,0x308,0x0}, {0x4DE,0x417,0x308,0x0}, 
+  {0x4DF,0x437,0x308,0x0}, {0x4E2,0x418,0x304,0x0}, {0x4E3,0x438,0x304,0x0}, 
+  {0x4E4,0x418,0x308,0x0}, {0x4E5,0x438,0x308,0x0}, {0x4E6,0x41E,0x308,0x0}, 
+  {0x4E7,0x43E,0x308,0x0}, {0x4EA,0x4E8,0x308,0x0}, {0x4EB,0x4E9,0x308,0x0}, 
+  {0x4EE,0x423,0x304,0x0}, {0x4EF,0x443,0x304,0x0}, {0x4F0,0x423,0x308,0x0}, 
+  {0x4F1,0x443,0x308,0x0}, {0x4F2,0x423,0x30B,0x0}, {0x4F3,0x443,0x30B,0x0}, 
+  {0x4F4,0x427,0x308,0x0}, {0x4F5,0x447,0x308,0x0}, {0x4F8,0x42B,0x308,0x0}, 
+  {0x4F9,0x44B,0x308,0x0}, {0x929,0x928,0x93C,0x0}, {0x931,0x930,0x93C,0x0}, 
+  {0x934,0x933,0x93C,0x0}, {0x958,0x915,0x93C,0x0}, {0x959,0x916,0x93C,0x0}, 
+  {0x95A,0x917,0x93C,0x0}, {0x95B,0x91C,0x93C,0x0}, {0x95C,0x921,0x93C,0x0}, 
+  {0x95D,0x922,0x93C,0x0}, {0x95E,0x92B,0x93C,0x0}, {0x95F,0x92F,0x93C,0x0}, 
+  {0x9B0,0x9AC,0x9BC,0x0}, {0x9CB,0x9C7,0x9BE,0x0}, {0x9CC,0x9C7,0x9D7,0x0}, 
+  {0x9DC,0x9A1,0x9BC,0x0}, {0x9DD,0x9A2,0x9BC,0x0}, {0x9DF,0x9AF,0x9BC,0x0}, 
+  {0xA59,0xA16,0xA3C,0x0}, {0xA5A,0xA17,0xA3C,0x0}, {0xA5B,0xA1C,0xA3C,0x0}, 
+  {0xA5C,0xA21,0xA3C,0x0}, {0xA5E,0xA2B,0xA3C,0x0}, {0xB48,0xB47,0xB56,0x0}, 
+  {0xB4B,0xB47,0xB3E,0x0}, {0xB4C,0xB47,0xB57,0x0}, {0xB5C,0xB21,0xB3C,0x0}, 
+  {0xB5D,0xB22,0xB3C,0x0}, {0xB5F,0xB2F,0xB3C,0x0}, {0xB94,0xB92,0xBD7,0x0}, 
+  {0xBCA,0xBC6,0xBBE,0x0}, {0xBCB,0xBC7,0xBBE,0x0}, {0xBCC,0xBC6,0xBD7,0x0}, 
+  {0xC48,0xC46,0xC56,0x0}, {0xCC0,0xCBF,0xCD5,0x0}, {0xCC7,0xCC6,0xCD5,0x0}, 
+  {0xCC8,0xCC6,0xCD6,0x0}, {0xCCA,0xCC6,0xCC2,0x0}, {0xCCB,0xCC6,0xCC2,0xCD5}, 
+  {0xD4A,0xD46,0xD3E,0x0}, {0xD4B,0xD47,0xD3E,0x0}, {0xD4C,0xD46,0xD57,0x0}, 
+  {0xE33,0xE4D,0xE32,0x0}, {0xEB3,0xECD,0xEB2,0x0}, {0xF43,0xF42,0xFB7,0x0}, 
+  {0xF4D,0xF4C,0xFB7,0x0}, {0xF52,0xF51,0xFB7,0x0}, {0xF57,0xF56,0xFB7,0x0}, 
+  {0xF5C,0xF5B,0xFB7,0x0}, {0xF69,0xF40,0xFB5,0x0}, {0xF73,0xF72,0xF71,0x0}, 
+  {0xF75,0xF71,0xF74,0x0}, {0xF76,0xFB2,0xF80,0x0}, {0xF77,0xF76,0xF71,0x0}, 
+  {0xF78,0xFB3,0xF80,0x0}, {0xF79,0xF78,0xF71,0x0}, {0xF81,0xF80,0xF71,0x0}, 
+  {0xF93,0xF92,0xFB7,0x0}, {0xF9D,0xF9C,0xFB7,0x0}, {0xFA2,0xFA1,0xFB7,0x0}, 
+  {0xFA7,0xFA6,0xFB7,0x0}, {0xFAC,0xFAB,0xFB7,0x0}, {0xFB9,0xF90,0xFB5,0x0}, 
+  {0x1E00,0x41,0x325,0x0}, {0x1E01,0x61,0x325,0x0}, {0x1E02,0x42,0x307,0x0}, 
+  {0x1E03,0x62,0x307,0x0}, {0x1E04,0x42,0x323,0x0}, {0x1E05,0x62,0x323,0x0}, 
+  {0x1E06,0x42,0x331,0x0}, {0x1E07,0x62,0x331,0x0}, {0x1E08,0xC7,0x301,0x0}, 
+  {0x1E09,0xE7,0x301,0x0}, {0x1E0A,0x44,0x307,0x0}, {0x1E0B,0x64,0x307,0x0}, 
+  {0x1E0C,0x44,0x323,0x0}, {0x1E0D,0x64,0x323,0x0}, {0x1E0E,0x44,0x331,0x0}, 
+  {0x1E0F,0x64,0x331,0x0}, {0x1E10,0x44,0x327,0x0}, {0x1E11,0x64,0x327,0x0}, 
+  {0x1E12,0x44,0x32D,0x0}, {0x1E13,0x64,0x32D,0x0}, {0x1E14,0x112,0x300,0x0}, 
+  {0x1E15,0x113,0x300,0x0}, {0x1E16,0x112,0x301,0x0}, {0x1E17,0x113,0x301,0x0}, 
+  {0x1E18,0x45,0x32D,0x0}, {0x1E19,0x65,0x32D,0x0}, {0x1E1A,0x45,0x330,0x0}, 
+  {0x1E1B,0x65,0x330,0x0}, {0x1E1C,0x114,0x327,0x0}, {0x1E1D,0x115,0x327,0x0}, 
+  {0x1E1E,0x46,0x307,0x0}, {0x1E1F,0x66,0x307,0x0}, {0x1E20,0x47,0x304,0x0}, 
+  {0x1E21,0x67,0x304,0x0}, {0x1E22,0x48,0x307,0x0}, {0x1E23,0x68,0x307,0x0}, 
+  {0x1E24,0x48,0x323,0x0}, {0x1E25,0x68,0x323,0x0}, {0x1E26,0x48,0x308,0x0}, 
+  {0x1E27,0x68,0x308,0x0}, {0x1E28,0x48,0x327,0x0}, {0x1E29,0x68,0x327,0x0}, 
+  {0x1E2A,0x48,0x32E,0x0}, {0x1E2B,0x68,0x32E,0x0}, {0x1E2C,0x49,0x330,0x0}, 
+  {0x1E2D,0x69,0x330,0x0}, {0x1E2E,0xCF,0x301,0x0}, {0x1E2F,0xEF,0x301,0x0}, 
+  {0x1E30,0x4B,0x301,0x0}, {0x1E31,0x6B,0x301,0x0}, {0x1E32,0x4B,0x323,0x0}, 
+  {0x1E33,0x6B,0x323,0x0}, {0x1E34,0x4B,0x331,0x0}, {0x1E35,0x6B,0x331,0x0}, 
+  {0x1E36,0x4C,0x323,0x0}, {0x1E37,0x6C,0x323,0x0}, {0x1E38,0x1E36,0x304,0x0}, 
+  {0x1E39,0x1E37,0x304,0x0}, {0x1E3A,0x4C,0x331,0x0}, {0x1E3B,0x6C,0x331,0x0}, 
+  {0x1E3C,0x4C,0x32D,0x0}, {0x1E3D,0x6C,0x32D,0x0}, {0x1E3E,0x4D,0x301,0x0}, 
+  {0x1E3F,0x6D,0x301,0x0}, {0x1E40,0x4D,0x307,0x0}, {0x1E41,0x6D,0x307,0x0}, 
+  {0x1E42,0x4D,0x323,0x0}, {0x1E43,0x6D,0x323,0x0}, {0x1E44,0x4E,0x307,0x0}, 
+  {0x1E45,0x6E,0x307,0x0}, {0x1E46,0x4E,0x323,0x0}, {0x1E47,0x6E,0x323,0x0}, 
+  {0x1E48,0x4E,0x331,0x0}, {0x1E49,0x6E,0x331,0x0}, {0x1E4A,0x4E,0x32D,0x0}, 
+  {0x1E4B,0x6E,0x32D,0x0}, {0x1E4C,0xD5,0x301,0x0}, {0x1E4D,0xF5,0x301,0x0}, 
+  {0x1E4E,0xD5,0x308,0x0}, {0x1E4F,0xF5,0x308,0x0}, {0x1E50,0x14C,0x300,0x0}, 
+  {0x1E51,0x14D,0x300,0x0}, {0x1E52,0x14C,0x301,0x0}, {0x1E53,0x14D,0x301,0x0}, 
+  {0x1E54,0x50,0x301,0x0}, {0x1E55,0x70,0x301,0x0}, {0x1E56,0x50,0x307,0x0}, 
+  {0x1E57,0x70,0x307,0x0}, {0x1E58,0x52,0x307,0x0}, {0x1E59,0x72,0x307,0x0}, 
+  {0x1E5A,0x52,0x323,0x0}, {0x1E5B,0x72,0x323,0x0}, {0x1E5C,0x1E5A,0x304,0x0}, 
+  {0x1E5D,0x1E5B,0x304,0x0}, {0x1E5E,0x52,0x331,0x0}, {0x1E5F,0x72,0x331,0x0}, 
+  {0x1E60,0x53,0x307,0x0}, {0x1E61,0x73,0x307,0x0}, {0x1E62,0x53,0x323,0x0}, 
+  {0x1E63,0x73,0x323,0x0}, {0x1E64,0x15A,0x307,0x0}, {0x1E65,0x15B,0x307,0x0}, 
+  {0x1E66,0x160,0x307,0x0}, {0x1E67,0x161,0x307,0x0}, {0x1E68,0x1E62,0x307,0x0}, 
+  {0x1E69,0x1E63,0x307,0x0}, {0x1E6A,0x54,0x307,0x0}, {0x1E6B,0x74,0x307,0x0}, 
+  {0x1E6C,0x54,0x323,0x0}, {0x1E6D,0x74,0x323,0x0}, {0x1E6E,0x54,0x331,0x0}, 
+  {0x1E6F,0x74,0x331,0x0}, {0x1E70,0x54,0x32D,0x0}, {0x1E71,0x74,0x32D,0x0}, 
+  {0x1E72,0x55,0x324,0x0}, {0x1E73,0x75,0x324,0x0}, {0x1E74,0x55,0x330,0x0}, 
+  {0x1E75,0x75,0x330,0x0}, {0x1E76,0x55,0x32D,0x0}, {0x1E77,0x75,0x32D,0x0}, 
+  {0x1E78,0x168,0x301,0x0}, {0x1E79,0x169,0x301,0x0}, {0x1E7A,0x16A,0x308,0x0}, 
+  {0x1E7B,0x16B,0x308,0x0}, {0x1E7C,0x56,0x303,0x0}, {0x1E7D,0x76,0x303,0x0}, 
+  {0x1E7E,0x56,0x323,0x0}, {0x1E7F,0x76,0x323,0x0}, {0x1E80,0x57,0x300,0x0}, 
+  {0x1E81,0x77,0x300,0x0}, {0x1E82,0x57,0x301,0x0}, {0x1E83,0x77,0x301,0x0}, 
+  {0x1E84,0x57,0x308,0x0}, {0x1E85,0x77,0x308,0x0}, {0x1E86,0x57,0x307,0x0}, 
+  {0x1E87,0x77,0x307,0x0}, {0x1E88,0x57,0x323,0x0}, {0x1E89,0x77,0x323,0x0}, 
+  {0x1E8A,0x58,0x307,0x0}, {0x1E8B,0x78,0x307,0x0}, {0x1E8C,0x58,0x308,0x0}, 
+  {0x1E8D,0x78,0x308,0x0}, {0x1E8E,0x59,0x307,0x0}, {0x1E8F,0x79,0x307,0x0}, 
+  {0x1E90,0x5A,0x302,0x0}, {0x1E91,0x7A,0x302,0x0}, {0x1E92,0x5A,0x323,0x0}, 
+  {0x1E93,0x7A,0x323,0x0}, {0x1E94,0x5A,0x331,0x0}, {0x1E95,0x7A,0x331,0x0}, 
+  {0x1E96,0x68,0x331,0x0}, {0x1E97,0x74,0x308,0x0}, {0x1E98,0x77,0x30A,0x0}, 
+  {0x1E99,0x79,0x30A,0x0}, {0x1E9B,0x17F,0x307,0x0}, {0x1EA0,0x41,0x323,0x0}, 
+  {0x1EA1,0x61,0x323,0x0}, {0x1EA2,0x41,0x309,0x0}, {0x1EA3,0x61,0x309,0x0}, 
+  {0x1EA4,0xC2,0x301,0x0}, {0x1EA5,0xE2,0x301,0x0}, {0x1EA6,0xC2,0x300,0x0}, 
+  {0x1EA7,0xE2,0x300,0x0}, {0x1EA8,0xC2,0x309,0x0}, {0x1EA9,0xE2,0x309,0x0}, 
+  {0x1EAA,0xC2,0x303,0x0}, {0x1EAB,0xE2,0x303,0x0}, {0x1EAC,0xC2,0x323,0x0}, 
+  {0x1EAD,0xE2,0x323,0x0}, {0x1EAE,0x102,0x301,0x0}, {0x1EAF,0x103,0x301,0x0}, 
+  {0x1EB0,0x102,0x300,0x0}, {0x1EB1,0x103,0x300,0x0}, {0x1EB2,0x102,0x309,0x0}, 
+  {0x1EB3,0x103,0x309,0x0}, {0x1EB4,0x102,0x303,0x0}, {0x1EB5,0x103,0x303,0x0}, 
+  {0x1EB6,0x102,0x323,0x0}, {0x1EB7,0x103,0x323,0x0}, {0x1EB8,0x45,0x323,0x0}, 
+  {0x1EB9,0x65,0x323,0x0}, {0x1EBA,0x45,0x309,0x0}, {0x1EBB,0x65,0x309,0x0}, 
+  {0x1EBC,0x45,0x303,0x0}, {0x1EBD,0x65,0x303,0x0}, {0x1EBE,0xCA,0x301,0x0}, 
+  {0x1EBF,0xEA,0x301,0x0}, {0x1EC0,0xCA,0x300,0x0}, {0x1EC1,0xEA,0x300,0x0}, 
+  {0x1EC2,0xCA,0x309,0x0}, {0x1EC3,0xEA,0x309,0x0}, {0x1EC4,0xCA,0x303,0x0}, 
+  {0x1EC5,0xEA,0x303,0x0}, {0x1EC6,0xCA,0x323,0x0}, {0x1EC7,0xEA,0x323,0x0}, 
+  {0x1EC8,0x49,0x309,0x0}, {0x1EC9,0x69,0x309,0x0}, {0x1ECA,0x49,0x323,0x0}, 
+  {0x1ECB,0x69,0x323,0x0}, {0x1ECC,0x4F,0x323,0x0}, {0x1ECD,0x6F,0x323,0x0}, 
+  {0x1ECE,0x4F,0x309,0x0}, {0x1ECF,0x6F,0x309,0x0}, {0x1ED0,0xD4,0x301,0x0}, 
+  {0x1ED1,0xF4,0x301,0x0}, {0x1ED2,0xD4,0x300,0x0}, {0x1ED3,0xF4,0x300,0x0}, 
+  {0x1ED4,0xD4,0x309,0x0}, {0x1ED5,0xF4,0x309,0x0}, {0x1ED6,0xD4,0x303,0x0}, 
+  {0x1ED7,0xF4,0x303,0x0}, {0x1ED8,0xD4,0x323,0x0}, {0x1ED9,0xF4,0x323,0x0}, 
+  {0x1EDA,0x1A0,0x301,0x0}, {0x1EDB,0x1A1,0x301,0x0}, {0x1EDC,0x1A0,0x300,0x0}, 
+  {0x1EDD,0x1A1,0x300,0x0}, {0x1EDE,0x1A0,0x309,0x0}, {0x1EDF,0x1A1,0x309,0x0}, 
+  {0x1EE0,0x1A0,0x303,0x0}, {0x1EE1,0x1A1,0x303,0x0}, {0x1EE2,0x1A0,0x323,0x0}, 
+  {0x1EE3,0x1A1,0x323,0x0}, {0x1EE4,0x55,0x323,0x0}, {0x1EE5,0x75,0x323,0x0}, 
+  {0x1EE6,0x55,0x309,0x0}, {0x1EE7,0x75,0x309,0x0}, {0x1EE8,0x1AF,0x301,0x0}, 
+  {0x1EE9,0x1B0,0x301,0x0}, {0x1EEA,0x1AF,0x300,0x0}, {0x1EEB,0x1B0,0x300,0x0}, 
+  {0x1EEC,0x1AF,0x309,0x0}, {0x1EED,0x1B0,0x309,0x0}, {0x1EEE,0x1AF,0x303,0x0}, 
+  {0x1EEF,0x1B0,0x303,0x0}, {0x1EF0,0x1AF,0x323,0x0}, {0x1EF1,0x1B0,0x323,0x0}, 
+  {0x1EF2,0x59,0x300,0x0}, {0x1EF3,0x79,0x300,0x0}, {0x1EF4,0x59,0x323,0x0}, 
+  {0x1EF5,0x79,0x323,0x0}, {0x1EF6,0x59,0x309,0x0}, {0x1EF7,0x79,0x309,0x0}, 
+  {0x1EF8,0x59,0x303,0x0}, {0x1EF9,0x79,0x303,0x0}, {0x1F00,0x3B1,0x313,0x0}, 
+  {0x1F01,0x3B1,0x314,0x0}, {0x1F02,0x1F00,0x300,0x0}, {0x1F03,0x1F01,0x300,0x0}, 
+  {0x1F04,0x1F00,0x301,0x0}, {0x1F05,0x1F01,0x301,0x0}, {0x1F06,0x1F00,0x342,0x0}, 
+  {0x1F07,0x1F01,0x342,0x0}, {0x1F08,0x391,0x313,0x0}, {0x1F09,0x391,0x314,0x0}, 
+  {0x1F0A,0x1F08,0x300,0x0}, {0x1F0B,0x1F09,0x300,0x0}, {0x1F0C,0x1F08,0x301,0x0}, 
+  {0x1F0D,0x1F09,0x301,0x0}, {0x1F0E,0x1F08,0x342,0x0}, {0x1F0F,0x1F09,0x342,0x0}, 
+  {0x1F10,0x3B5,0x313,0x0}, {0x1F11,0x3B5,0x314,0x0}, {0x1F12,0x1F10,0x300,0x0}, 
+  {0x1F13,0x1F11,0x300,0x0}, {0x1F14,0x1F10,0x301,0x0}, {0x1F15,0x1F11,0x301,0x0}, 
+  {0x1F18,0x395,0x313,0x0}, {0x1F19,0x395,0x314,0x0}, {0x1F1A,0x1F18,0x300,0x0}, 
+  {0x1F1B,0x1F19,0x300,0x0}, {0x1F1C,0x1F18,0x301,0x0}, {0x1F1D,0x1F19,0x301,0x0}, 
+  {0x1F20,0x3B7,0x313,0x0}, {0x1F21,0x3B7,0x314,0x0}, {0x1F22,0x1F20,0x300,0x0}, 
+  {0x1F23,0x1F21,0x300,0x0}, {0x1F24,0x1F20,0x301,0x0}, {0x1F25,0x1F21,0x301,0x0}, 
+  {0x1F26,0x1F20,0x342,0x0}, {0x1F27,0x1F21,0x342,0x0}, {0x1F28,0x397,0x313,0x0}, 
+  {0x1F29,0x397,0x314,0x0}, {0x1F2A,0x1F28,0x300,0x0}, {0x1F2B,0x1F29,0x300,0x0}, 
+  {0x1F2C,0x1F28,0x301,0x0}, {0x1F2D,0x1F29,0x301,0x0}, {0x1F2E,0x1F28,0x342,0x0}, 
+  {0x1F2F,0x1F29,0x342,0x0}, {0x1F30,0x3B9,0x313,0x0}, {0x1F31,0x3B9,0x314,0x0}, 
+  {0x1F32,0x1F30,0x300,0x0}, {0x1F33,0x1F31,0x300,0x0}, {0x1F34,0x1F30,0x301,0x0}, 
+  {0x1F35,0x1F31,0x301,0x0}, {0x1F36,0x1F30,0x342,0x0}, {0x1F37,0x1F31,0x342,0x0}, 
+  {0x1F38,0x399,0x313,0x0}, {0x1F39,0x399,0x314,0x0}, {0x1F3A,0x1F38,0x300,0x0}, 
+  {0x1F3B,0x1F39,0x300,0x0}, {0x1F3C,0x1F38,0x301,0x0}, {0x1F3D,0x1F39,0x301,0x0}, 
+  {0x1F3E,0x1F38,0x342,0x0}, {0x1F3F,0x1F39,0x342,0x0}, {0x1F40,0x3BF,0x313,0x0}, 
+  {0x1F41,0x3BF,0x314,0x0}, {0x1F42,0x1F40,0x300,0x0}, {0x1F43,0x1F41,0x300,0x0}, 
+  {0x1F44,0x1F40,0x301,0x0}, {0x1F45,0x1F41,0x301,0x0}, {0x1F48,0x39F,0x313,0x0}, 
+  {0x1F49,0x39F,0x314,0x0}, {0x1F4A,0x1F48,0x300,0x0}, {0x1F4B,0x1F49,0x300,0x0}, 
+  {0x1F4C,0x1F48,0x301,0x0}, {0x1F4D,0x1F49,0x301,0x0}, {0x1F50,0x3C5,0x313,0x0}, 
+  {0x1F51,0x3C5,0x314,0x0}, {0x1F52,0x1F50,0x300,0x0}, {0x1F53,0x1F51,0x300,0x0}, 
+  {0x1F54,0x1F50,0x301,0x0}, {0x1F55,0x1F51,0x301,0x0}, {0x1F56,0x1F50,0x342,0x0}, 
+  {0x1F57,0x1F51,0x342,0x0}, {0x1F59,0x3A5,0x314,0x0}, {0x1F5B,0x1F59,0x300,0x0}, 
+  {0x1F5D,0x1F59,0x301,0x0}, {0x1F5F,0x1F59,0x342,0x0}, {0x1F60,0x3C9,0x313,0x0}, 
+  {0x1F61,0x3C9,0x314,0x0}, {0x1F62,0x1F60,0x300,0x0}, {0x1F63,0x1F61,0x300,0x0}, 
+  {0x1F64,0x1F60,0x301,0x0}, {0x1F65,0x1F61,0x301,0x0}, {0x1F66,0x1F60,0x342,0x0}, 
+  {0x1F67,0x1F61,0x342,0x0}, {0x1F68,0x3A9,0x313,0x0}, {0x1F69,0x3A9,0x314,0x0}, 
+  {0x1F6A,0x1F68,0x300,0x0}, {0x1F6B,0x1F69,0x300,0x0}, {0x1F6C,0x1F68,0x301,0x0}, 
+  {0x1F6D,0x1F69,0x301,0x0}, {0x1F6E,0x1F68,0x342,0x0}, {0x1F6F,0x1F69,0x342,0x0}, 
+  {0x1F70,0x3B1,0x300,0x0}, {0x1F71,0x3B1,0x301,0x0}, {0x1F72,0x3B5,0x300,0x0}, 
+  {0x1F73,0x3B5,0x301,0x0}, {0x1F74,0x3B7,0x300,0x0}, {0x1F75,0x3B7,0x301,0x0}, 
+  {0x1F76,0x3B9,0x300,0x0}, {0x1F77,0x3B9,0x301,0x0}, {0x1F78,0x3BF,0x300,0x0}, 
+  {0x1F79,0x3BF,0x301,0x0}, {0x1F7A,0x3C5,0x300,0x0}, {0x1F7B,0x3C5,0x301,0x0}, 
+  {0x1F7C,0x3C9,0x300,0x0}, {0x1F7D,0x3C9,0x301,0x0}, {0x1F80,0x1F00,0x345,0x0}, 
+  {0x1F81,0x1F01,0x345,0x0}, {0x1F82,0x1F02,0x345,0x0}, {0x1F83,0x1F03,0x345,0x0}, 
+  {0x1F84,0x1F04,0x345,0x0}, {0x1F85,0x1F05,0x345,0x0}, {0x1F86,0x1F06,0x345,0x0}, 
+  {0x1F87,0x1F07,0x345,0x0}, {0x1F88,0x1F08,0x345,0x0}, {0x1F89,0x1F09,0x345,0x0}, 
+  {0x1F8A,0x1F0A,0x345,0x0}, {0x1F8B,0x1F0B,0x345,0x0}, {0x1F8C,0x1F0C,0x345,0x0}, 
+  {0x1F8D,0x1F0D,0x345,0x0}, {0x1F8E,0x1F0E,0x345,0x0}, {0x1F8F,0x1F0F,0x345,0x0}, 
+  {0x1F90,0x1F20,0x345,0x0}, {0x1F91,0x1F21,0x345,0x0}, {0x1F92,0x1F22,0x345,0x0}, 
+  {0x1F93,0x1F23,0x345,0x0}, {0x1F94,0x1F24,0x345,0x0}, {0x1F95,0x1F25,0x345,0x0}, 
+  {0x1F96,0x1F26,0x345,0x0}, {0x1F97,0x1F27,0x345,0x0}, {0x1F98,0x1F28,0x345,0x0}, 
+  {0x1F99,0x1F29,0x345,0x0}, {0x1F9A,0x1F2A,0x345,0x0}, {0x1F9B,0x1F2B,0x345,0x0}, 
+  {0x1F9C,0x1F2C,0x345,0x0}, {0x1F9D,0x1F2D,0x345,0x0}, {0x1F9E,0x1F2E,0x345,0x0}, 
+  {0x1F9F,0x1F2F,0x345,0x0}, {0x1FA0,0x1F60,0x345,0x0}, {0x1FA1,0x1F61,0x345,0x0}, 
+  {0x1FA2,0x1F62,0x345,0x0}, {0x1FA3,0x1F63,0x345,0x0}, {0x1FA4,0x1F64,0x345,0x0}, 
+  {0x1FA5,0x1F65,0x345,0x0}, {0x1FA6,0x1F66,0x345,0x0}, {0x1FA7,0x1F67,0x345,0x0}, 
+  {0x1FA8,0x1F68,0x345,0x0}, {0x1FA9,0x1F69,0x345,0x0}, {0x1FAA,0x1F6A,0x345,0x0}, 
+  {0x1FAB,0x1F6B,0x345,0x0}, {0x1FAC,0x1F6C,0x345,0x0}, {0x1FAD,0x1F6D,0x345,0x0}, 
+  {0x1FAE,0x1F6E,0x345,0x0}, {0x1FAF,0x1F6F,0x345,0x0}, {0x1FB0,0x3B1,0x306,0x0}, 
+  {0x1FB1,0x3B1,0x304,0x0}, {0x1FB2,0x1F70,0x345,0x0}, {0x1FB3,0x3B1,0x345,0x0}, 
+  {0x1FB4,0x1F71,0x345,0x0}, {0x1FB6,0x3B1,0x342,0x0}, {0x1FB7,0x1FB6,0x345,0x0}, 
+  {0x1FB8,0x391,0x306,0x0}, {0x1FB9,0x391,0x304,0x0}, {0x1FBA,0x391,0x300,0x0}, 
+  {0x1FBB,0x391,0x301,0x0}, {0x1FBC,0x391,0x345,0x0}, {0x1FBE,0x3B9,0x0,0x0}, 
+  {0x1FC1,0xA8,0x342,0x0}, {0x1FC2,0x1F74,0x345,0x0}, {0x1FC3,0x3B7,0x345,0x0}, 
+  {0x1FC4,0x1F75,0x345,0x0}, {0x1FC6,0x3B7,0x342,0x0}, {0x1FC7,0x1FC6,0x345,0x0}, 
+  {0x1FC8,0x395,0x300,0x0}, {0x1FC9,0x395,0x301,0x0}, {0x1FCA,0x397,0x300,0x0}, 
+  {0x1FCB,0x397,0x301,0x0}, {0x1FCC,0x397,0x345,0x0}, {0x1FCD,0x1FBF,0x300,0x0}, 
+  {0x1FCE,0x1FBF,0x301,0x0}, {0x1FCF,0x1FBF,0x342,0x0}, {0x1FD0,0x3B9,0x306,0x0}, 
+  {0x1FD1,0x3B9,0x304,0x0}, {0x1FD2,0x3CA,0x300,0x0}, {0x1FD3,0x3CA,0x301,0x0}, 
+  {0x1FD6,0x3B9,0x342,0x0}, {0x1FD7,0x3CA,0x342,0x0}, {0x1FD8,0x399,0x306,0x0}, 
+  {0x1FD9,0x399,0x304,0x0}, {0x1FDA,0x399,0x300,0x0}, {0x1FDB,0x399,0x301,0x0}, 
+  {0x1FDD,0x1FFE,0x300,0x0}, {0x1FDE,0x1FFE,0x301,0x0}, {0x1FDF,0x1FFE,0x342,0x0}, 
+  {0x1FE0,0x3C5,0x306,0x0}, {0x1FE1,0x3C5,0x304,0x0}, {0x1FE2,0x3CB,0x300,0x0}, 
+  {0x1FE3,0x3CB,0x301,0x0}, {0x1FE4,0x3C1,0x313,0x0}, {0x1FE5,0x3C1,0x314,0x0}, 
+  {0x1FE6,0x3C5,0x342,0x0}, {0x1FE7,0x3CB,0x342,0x0}, {0x1FE8,0x3A5,0x306,0x0}, 
+  {0x1FE9,0x3A5,0x304,0x0}, {0x1FEA,0x3A5,0x300,0x0}, {0x1FEB,0x3A5,0x301,0x0}, 
+  {0x1FEC,0x3A1,0x314,0x0}, {0x1FED,0xA8,0x300,0x0}, {0x1FEE,0xA8,0x301,0x0}, 
+  {0x1FEF,0x60,0x0,0x0}, {0x1FF2,0x1F7C,0x345,0x0}, {0x1FF3,0x3C9,0x345,0x0}, 
+  {0x1FF4,0x1F79,0x345,0x0}, {0x1FF6,0x3C9,0x342,0x0}, {0x1FF7,0x1FF6,0x345,0x0}, 
+  {0x1FF8,0x39F,0x300,0x0}, {0x1FF9,0x39F,0x301,0x0}, {0x1FFA,0x3A9,0x300,0x0}, 
+  {0x1FFB,0x3A9,0x301,0x0}, {0x1FFC,0x3A9,0x345,0x0}, {0x1FFD,0xB4,0x0,0x0}, 
+  {0x2000,0x2002,0x0,0x0}, {0x2001,0x2003,0x0,0x0}, {0x2126,0x3A9,0x0,0x0}, 
+  {0x212A,0x4B,0x0,0x0}, {0x212B,0xC5,0x0,0x0}, {0x2204,0x2203,0x338,0x0}, 
+  {0x2209,0x2208,0x338,0x0}, {0x220C,0x220B,0x338,0x0}, {0x2224,0x2223,0x338,0x0}, 
+  {0x2226,0x2225,0x338,0x0}, {0x2241,0x7E,0x338,0x0}, {0x2244,0x2243,0x338,0x0}, 
+  {0x2247,0x2245,0x338,0x0}, {0x2249,0x2248,0x338,0x0}, {0x2260,0x3D,0x338,0x0}, 
+  {0x2262,0x2261,0x338,0x0}, {0x226D,0x224D,0x338,0x0}, {0x226E,0x3C,0x338,0x0}, 
+  {0x226F,0x3E,0x338,0x0}, {0x2270,0x2264,0x338,0x0}, {0x2271,0x2265,0x338,0x0}, 
+  {0x2274,0x2272,0x338,0x0}, {0x2275,0x2273,0x338,0x0}, {0x2278,0x2276,0x338,0x0}, 
+  {0x2279,0x2277,0x338,0x0}, {0x2280,0x227A,0x338,0x0}, {0x2281,0x227B,0x338,0x0}, 
+  {0x2284,0x2282,0x338,0x0}, {0x2285,0x2283,0x338,0x0}, {0x2288,0x2286,0x338,0x0}, 
+  {0x2289,0x2287,0x338,0x0}, {0x22AC,0x22A2,0x338,0x0}, {0x22AD,0x22A8,0x338,0x0}, 
+  {0x22AE,0x22A9,0x338,0x0}, {0x22AF,0x22AB,0x338,0x0}, {0x22E0,0x227C,0x338,0x0}, 
+  {0x22E1,0x227D,0x338,0x0}, {0x22E2,0x2291,0x338,0x0}, {0x22E3,0x2292,0x338,0x0}, 
+  {0x22EA,0x22B2,0x338,0x0}, {0x22EB,0x22B3,0x338,0x0}, {0x22EC,0x22B4,0x338,0x0}, 
+  {0x22ED,0x22B5,0x338,0x0}, {0x2329,0x3008,0x0,0x0}, {0x232A,0x3009,0x0,0x0}, 
+  {0x304C,0x304B,0x3099,0x0}, {0x304E,0x304D,0x3099,0x0}, {0x3050,0x304F,0x3099,0x0}, 
+  {0x3052,0x3051,0x3099,0x0}, {0x3054,0x3053,0x3099,0x0}, {0x3056,0x3055,0x3099,0x0}, 
+  {0x3058,0x3057,0x3099,0x0}, {0x305A,0x3059,0x3099,0x0}, {0x305C,0x305B,0x3099,0x0}, 
+  {0x305E,0x305D,0x3099,0x0}, {0x3060,0x305F,0x3099,0x0}, {0x3062,0x3061,0x3099,0x0}, 
+  {0x3065,0x3064,0x3099,0x0}, {0x3067,0x3066,0x3099,0x0}, {0x3069,0x3068,0x3099,0x0}, 
+  {0x3070,0x306F,0x3099,0x0}, {0x3071,0x306F,0x309A,0x0}, {0x3073,0x3072,0x3099,0x0}, 
+  {0x3074,0x3072,0x309A,0x0}, {0x3076,0x3075,0x3099,0x0}, {0x3077,0x3075,0x309A,0x0}, 
+  {0x3079,0x3078,0x3099,0x0}, {0x307A,0x3078,0x309A,0x0}, {0x307C,0x307B,0x3099,0x0}, 
+  {0x307D,0x307B,0x309A,0x0}, {0x3094,0x3046,0x3099,0x0}, {0x309E,0x309D,0x3099,0x0}, 
+  {0x30AC,0x30AB,0x3099,0x0}, {0x30AE,0x30AD,0x3099,0x0}, {0x30B0,0x30AF,0x3099,0x0}, 
+  {0x30B2,0x30B1,0x3099,0x0}, {0x30B4,0x30B3,0x3099,0x0}, {0x30B6,0x30B5,0x3099,0x0}, 
+  {0x30B8,0x30B7,0x3099,0x0}, {0x30BA,0x30B9,0x3099,0x0}, {0x30BC,0x30BB,0x3099,0x0}, 
+  {0x30BE,0x30BD,0x3099,0x0}, {0x30C0,0x30BF,0x3099,0x0}, {0x30C2,0x30C1,0x3099,0x0}, 
+  {0x30C5,0x30C4,0x3099,0x0}, {0x30C7,0x30C6,0x3099,0x0}, {0x30C9,0x30C8,0x3099,0x0}, 
+  {0x30D0,0x30CF,0x3099,0x0}, {0x30D1,0x30CF,0x309A,0x0}, {0x30D3,0x30D2,0x3099,0x0}, 
+  {0x30D4,0x30D2,0x309A,0x0}, {0x30D6,0x30D5,0x3099,0x0}, {0x30D7,0x30D5,0x309A,0x0}, 
+  {0x30D9,0x30D8,0x3099,0x0}, {0x30DA,0x30D8,0x309A,0x0}, {0x30DC,0x30DB,0x3099,0x0}, 
+  {0x30DD,0x30DB,0x309A,0x0}, {0x30F4,0x30A6,0x3099,0x0}, {0x30F7,0x30EF,0x3099,0x0}, 
+  {0x30F8,0x30F0,0x3099,0x0}, {0x30F9,0x30F1,0x3099,0x0}, {0x30FA,0x30F2,0x3099,0x0}, 
+  {0x30FE,0x30FD,0x3099,0x0}, {0xF900,0x8C48,0x0,0x0}, {0xF901,0x66F4,0x0,0x0}, 
+  {0xF902,0x8ECA,0x0,0x0}, {0xF903,0x8CC8,0x0,0x0}, {0xF904,0x6ED1,0x0,0x0}, 
+  {0xF905,0x4E32,0x0,0x0}, {0xF906,0x53E5,0x0,0x0}, {0xF907,0x9F9C,0x0,0x0}, 
+  {0xF908,0x9F9C,0x0,0x0}, {0xF909,0x5951,0x0,0x0}, {0xF90A,0x91D1,0x0,0x0}, 
+  {0xF90B,0x5587,0x0,0x0}, {0xF90C,0x5948,0x0,0x0}, {0xF90D,0x61F6,0x0,0x0}, 
+  {0xF90E,0x7669,0x0,0x0}, {0xF90F,0x7F85,0x0,0x0}, {0xF910,0x863F,0x0,0x0}, 
+  {0xF911,0x87BA,0x0,0x0}, {0xF912,0x88F8,0x0,0x0}, {0xF913,0x908F,0x0,0x0}, 
+  {0xF914,0x6A02,0x0,0x0}, {0xF915,0x6D1B,0x0,0x0}, {0xF916,0x70D9,0x0,0x0}, 
+  {0xF917,0x73DE,0x0,0x0}, {0xF918,0x843D,0x0,0x0}, {0xF919,0x916A,0x0,0x0}, 
+  {0xF91A,0x99F1,0x0,0x0}, {0xF91B,0x4E82,0x0,0x0}, {0xF91C,0x5375,0x0,0x0}, 
+  {0xF91D,0x6B04,0x0,0x0}, {0xF91E,0x721B,0x0,0x0}, {0xF91F,0x862D,0x0,0x0}, 
+  {0xF920,0x9E1E,0x0,0x0}, {0xF921,0x5D50,0x0,0x0}, {0xF922,0x6FEB,0x0,0x0}, 
+  {0xF923,0x85CD,0x0,0x0}, {0xF924,0x8964,0x0,0x0}, {0xF925,0x62C9,0x0,0x0}, 
+  {0xF926,0x81D8,0x0,0x0}, {0xF927,0x881F,0x0,0x0}, {0xF928,0x5ECA,0x0,0x0}, 
+  {0xF929,0x6717,0x0,0x0}, {0xF92A,0x6D6A,0x0,0x0}, {0xF92B,0x72FC,0x0,0x0}, 
+  {0xF92C,0x90CE,0x0,0x0}, {0xF92D,0x4F86,0x0,0x0}, {0xF92E,0x51B7,0x0,0x0}, 
+  {0xF92F,0x52DE,0x0,0x0}, {0xF930,0x64C4,0x0,0x0}, {0xF931,0x6AD3,0x0,0x0}, 
+  {0xF932,0x7210,0x0,0x0}, {0xF933,0x76E7,0x0,0x0}, {0xF934,0x8001,0x0,0x0}, 
+  {0xF935,0x8606,0x0,0x0}, {0xF936,0x865C,0x0,0x0}, {0xF937,0x8DEF,0x0,0x0}, 
+  {0xF938,0x9732,0x0,0x0}, {0xF939,0x9B6F,0x0,0x0}, {0xF93A,0x9DFA,0x0,0x0}, 
+  {0xF93B,0x788C,0x0,0x0}, {0xF93C,0x797F,0x0,0x0}, {0xF93D,0x7DA0,0x0,0x0}, 
+  {0xF93E,0x83C9,0x0,0x0}, {0xF93F,0x9304,0x0,0x0}, {0xF940,0x9E7F,0x0,0x0}, 
+  {0xF941,0x8AD6,0x0,0x0}, {0xF942,0x58DF,0x0,0x0}, {0xF943,0x5F04,0x0,0x0}, 
+  {0xF944,0x7C60,0x0,0x0}, {0xF945,0x807E,0x0,0x0}, {0xF946,0x7262,0x0,0x0}, 
+  {0xF947,0x78CA,0x0,0x0}, {0xF948,0x8CC2,0x0,0x0}, {0xF949,0x96F7,0x0,0x0}, 
+  {0xF94A,0x58D8,0x0,0x0}, {0xF94B,0x5C62,0x0,0x0}, {0xF94C,0x6A13,0x0,0x0}, 
+  {0xF94D,0x6DDA,0x0,0x0}, {0xF94E,0x6F0F,0x0,0x0}, {0xF94F,0x7D2F,0x0,0x0}, 
+  {0xF950,0x7E37,0x0,0x0}, {0xF951,0x96FB,0x0,0x0}, {0xF952,0x52D2,0x0,0x0}, 
+  {0xF953,0x808B,0x0,0x0}, {0xF954,0x51DC,0x0,0x0}, {0xF955,0x51CC,0x0,0x0}, 
+  {0xF956,0x7A1C,0x0,0x0}, {0xF957,0x7DBE,0x0,0x0}, {0xF958,0x83F1,0x0,0x0}, 
+  {0xF959,0x9675,0x0,0x0}, {0xF95A,0x8B80,0x0,0x0}, {0xF95B,0x62CF,0x0,0x0}, 
+  {0xF95C,0x6A02,0x0,0x0}, {0xF95D,0x8AFE,0x0,0x0}, {0xF95E,0x4E39,0x0,0x0}, 
+  {0xF95F,0x5BE7,0x0,0x0}, {0xF960,0x6012,0x0,0x0}, {0xF961,0x7387,0x0,0x0}, 
+  {0xF962,0x7570,0x0,0x0}, {0xF963,0x5317,0x0,0x0}, {0xF964,0x78FB,0x0,0x0}, 
+  {0xF965,0x4FBF,0x0,0x0}, {0xF966,0x5FA9,0x0,0x0}, {0xF967,0x4E0D,0x0,0x0}, 
+  {0xF968,0x6CCC,0x0,0x0}, {0xF969,0x6578,0x0,0x0}, {0xF96A,0x7D22,0x0,0x0}, 
+  {0xF96B,0x53C3,0x0,0x0}, {0xF96C,0x585E,0x0,0x0}, {0xF96D,0x7701,0x0,0x0}, 
+  {0xF96E,0x8449,0x0,0x0}, {0xF96F,0x8AAA,0x0,0x0}, {0xF970,0x6BBA,0x0,0x0}, 
+  {0xF971,0x8FB0,0x0,0x0}, {0xF972,0x6C88,0x0,0x0}, {0xF973,0x62FE,0x0,0x0}, 
+  {0xF974,0x82E5,0x0,0x0}, {0xF975,0x63A0,0x0,0x0}, {0xF976,0x7565,0x0,0x0}, 
+  {0xF977,0x4EAE,0x0,0x0}, {0xF978,0x5169,0x0,0x0}, {0xF979,0x51C9,0x0,0x0}, 
+  {0xF97A,0x6881,0x0,0x0}, {0xF97B,0x7CE7,0x0,0x0}, {0xF97C,0x826F,0x0,0x0}, 
+  {0xF97D,0x8AD2,0x0,0x0}, {0xF97E,0x91CF,0x0,0x0}, {0xF97F,0x52F5,0x0,0x0}, 
+  {0xF980,0x5442,0x0,0x0}, {0xF981,0x5973,0x0,0x0}, {0xF982,0x5EEC,0x0,0x0}, 
+  {0xF983,0x65C5,0x0,0x0}, {0xF984,0x6FFE,0x0,0x0}, {0xF985,0x792A,0x0,0x0}, 
+  {0xF986,0x95AD,0x0,0x0}, {0xF987,0x9A6A,0x0,0x0}, {0xF988,0x9E97,0x0,0x0}, 
+  {0xF989,0x9ECE,0x0,0x0}, {0xF98A,0x529B,0x0,0x0}, {0xF98B,0x66C6,0x0,0x0}, 
+  {0xF98C,0x6B77,0x0,0x0}, {0xF98D,0x8F62,0x0,0x0}, {0xF98E,0x5E74,0x0,0x0}, 
+  {0xF98F,0x6190,0x0,0x0}, {0xF990,0x6200,0x0,0x0}, {0xF991,0x649A,0x0,0x0}, 
+  {0xF992,0x6F23,0x0,0x0}, {0xF993,0x7149,0x0,0x0}, {0xF994,0x7489,0x0,0x0}, 
+  {0xF995,0x79CA,0x0,0x0}, {0xF996,0x7DF4,0x0,0x0}, {0xF997,0x806F,0x0,0x0}, 
+  {0xF998,0x8F26,0x0,0x0}, {0xF999,0x84EE,0x0,0x0}, {0xF99A,0x9023,0x0,0x0}, 
+  {0xF99B,0x934A,0x0,0x0}, {0xF99C,0x5217,0x0,0x0}, {0xF99D,0x52A3,0x0,0x0}, 
+  {0xF99E,0x54BD,0x0,0x0}, {0xF99F,0x70C8,0x0,0x0}, {0xF9A0,0x88C2,0x0,0x0}, 
+  {0xF9A1,0x8AAA,0x0,0x0}, {0xF9A2,0x5EC9,0x0,0x0}, {0xF9A3,0x5FF5,0x0,0x0}, 
+  {0xF9A4,0x637B,0x0,0x0}, {0xF9A5,0x6BAE,0x0,0x0}, {0xF9A6,0x7C3E,0x0,0x0}, 
+  {0xF9A7,0x7375,0x0,0x0}, {0xF9A8,0x4EE4,0x0,0x0}, {0xF9A9,0x56F9,0x0,0x0}, 
+  {0xF9AA,0x5BE7,0x0,0x0}, {0xF9AB,0x5DBA,0x0,0x0}, {0xF9AC,0x601C,0x0,0x0}, 
+  {0xF9AD,0x73B2,0x0,0x0}, {0xF9AE,0x7469,0x0,0x0}, {0xF9AF,0x7F9A,0x0,0x0}, 
+  {0xF9B0,0x8046,0x0,0x0}, {0xF9B1,0x9234,0x0,0x0}, {0xF9B2,0x96F6,0x0,0x0}, 
+  {0xF9B3,0x9748,0x0,0x0}, {0xF9B4,0x9818,0x0,0x0}, {0xF9B5,0x4F8B,0x0,0x0}, 
+  {0xF9B6,0x79AE,0x0,0x0}, {0xF9B7,0x91B4,0x0,0x0}, {0xF9B8,0x96B8,0x0,0x0}, 
+  {0xF9B9,0x60E1,0x0,0x0}, {0xF9BA,0x4E86,0x0,0x0}, {0xF9BB,0x50DA,0x0,0x0}, 
+  {0xF9BC,0x5BEE,0x0,0x0}, {0xF9BD,0x5C3F,0x0,0x0}, {0xF9BE,0x6599,0x0,0x0}, 
+  {0xF9BF,0x6A02,0x0,0x0}, {0xF9C0,0x71CE,0x0,0x0}, {0xF9C1,0x7642,0x0,0x0}, 
+  {0xF9C2,0x84FC,0x0,0x0}, {0xF9C3,0x907C,0x0,0x0}, {0xF9C4,0x9F8D,0x0,0x0}, 
+  {0xF9C5,0x6688,0x0,0x0}, {0xF9C6,0x962E,0x0,0x0}, {0xF9C7,0x5289,0x0,0x0}, 
+  {0xF9C8,0x677B,0x0,0x0}, {0xF9C9,0x67F3,0x0,0x0}, {0xF9CA,0x6D41,0x0,0x0}, 
+  {0xF9CB,0x6E9C,0x0,0x0}, {0xF9CC,0x7409,0x0,0x0}, {0xF9CD,0x7559,0x0,0x0}, 
+  {0xF9CE,0x786B,0x0,0x0}, {0xF9CF,0x7D10,0x0,0x0}, {0xF9D0,0x985E,0x0,0x0}, 
+  {0xF9D1,0x516D,0x0,0x0}, {0xF9D2,0x622E,0x0,0x0}, {0xF9D3,0x9678,0x0,0x0}, 
+  {0xF9D4,0x502B,0x0,0x0}, {0xF9D5,0x5D19,0x0,0x0}, {0xF9D6,0x6DEA,0x0,0x0}, 
+  {0xF9D7,0x8F2A,0x0,0x0}, {0xF9D8,0x5F8B,0x0,0x0}, {0xF9D9,0x6144,0x0,0x0}, 
+  {0xF9DA,0x6817,0x0,0x0}, {0xF9DB,0x7387,0x0,0x0}, {0xF9DC,0x9686,0x0,0x0}, 
+  {0xF9DD,0x5229,0x0,0x0}, {0xF9DE,0x540F,0x0,0x0}, {0xF9DF,0x5C65,0x0,0x0}, 
+  {0xF9E0,0x6613,0x0,0x0}, {0xF9E1,0x674E,0x0,0x0}, {0xF9E2,0x68A8,0x0,0x0}, 
+  {0xF9E3,0x6CE5,0x0,0x0}, {0xF9E4,0x7406,0x0,0x0}, {0xF9E5,0x75E2,0x0,0x0}, 
+  {0xF9E6,0x7F79,0x0,0x0}, {0xF9E7,0x88CF,0x0,0x0}, {0xF9E8,0x88E1,0x0,0x0}, 
+  {0xF9E9,0x91CC,0x0,0x0}, {0xF9EA,0x96E2,0x0,0x0}, {0xF9EB,0x533F,0x0,0x0}, 
+  {0xF9EC,0x6EBA,0x0,0x0}, {0xF9ED,0x541D,0x0,0x0}, {0xF9EE,0x71D0,0x0,0x0}, 
+  {0xF9EF,0x7498,0x0,0x0}, {0xF9F0,0x85FA,0x0,0x0}, {0xF9F1,0x96A3,0x0,0x0}, 
+  {0xF9F2,0x9C57,0x0,0x0}, {0xF9F3,0x9E9F,0x0,0x0}, {0xF9F4,0x6797,0x0,0x0}, 
+  {0xF9F5,0x6DCB,0x0,0x0}, {0xF9F6,0x81E8,0x0,0x0}, {0xF9F7,0x7ACB,0x0,0x0}, 
+  {0xF9F8,0x7B20,0x0,0x0}, {0xF9F9,0x7C92,0x0,0x0}, {0xF9FA,0x72C0,0x0,0x0}, 
+  {0xF9FB,0x7099,0x0,0x0}, {0xF9FC,0x8B58,0x0,0x0}, {0xF9FD,0x4EC0,0x0,0x0}, 
+  {0xF9FE,0x8336,0x0,0x0}, {0xF9FF,0x523A,0x0,0x0}, {0xFA00,0x5207,0x0,0x0}, 
+  {0xFA01,0x5EA6,0x0,0x0}, {0xFA02,0x62D3,0x0,0x0}, {0xFA03,0x7CD6,0x0,0x0}, 
+  {0xFA04,0x5B85,0x0,0x0}, {0xFA05,0x6D1E,0x0,0x0}, {0xFA06,0x66B4,0x0,0x0}, 
+  {0xFA07,0x8F3B,0x0,0x0}, {0xFA08,0x884C,0x0,0x0}, {0xFA09,0x964D,0x0,0x0}, 
+  {0xFA0A,0x898B,0x0,0x0}, {0xFA0B,0x5ED3,0x0,0x0}, {0xFA0C,0x5140,0x0,0x0}, 
+  {0xFA0D,0x55C0,0x0,0x0}, {0xFA10,0x585A,0x0,0x0}, {0xFA12,0x6674,0x0,0x0}, 
+  {0xFA15,0x51DE,0x0,0x0}, {0xFA16,0x732A,0x0,0x0}, {0xFA17,0x76CA,0x0,0x0}, 
+  {0xFA18,0x793C,0x0,0x0}, {0xFA19,0x795E,0x0,0x0}, {0xFA1A,0x7965,0x0,0x0}, 
+  {0xFA1B,0x798F,0x0,0x0}, {0xFA1C,0x9756,0x0,0x0}, {0xFA1D,0x7CBE,0x0,0x0}, 
+  {0xFA1E,0x7FBD,0x0,0x0}, {0xFA20,0x8612,0x0,0x0}, {0xFA22,0x8AF8,0x0,0x0}, 
+  {0xFA25,0x9038,0x0,0x0}, {0xFA26,0x90FD,0x0,0x0}, {0xFA2A,0x98EF,0x0,0x0}, 
+  {0xFA2B,0x98FC,0x0,0x0}, {0xFA2C,0x9928,0x0,0x0}, {0xFA2D,0x9DB4,0x0,0x0}, 
+  {0xFB1F,0x5F2,0x5B7,0x0}, {0xFB2A,0x5E9,0x5C1,0x0}, {0xFB2B,0x5E9,0x5C2,0x0}, 
+  {0xFB2C,0x5E9,0x5BC,0x5C1}, {0xFB2D,0x5E9,0x5BC,0x5C2}, {0xFB2E,0x5D0,0x5B7,0x0}, 
+  {0xFB2F,0x5D0,0x5B8,0x0}, {0xFB30,0x5D0,0x5BC,0x0}, {0xFB31,0x5D1,0x5BC,0x0}, 
+  {0xFB32,0x5D2,0x5BC,0x0}, {0xFB33,0x5D3,0x5BC,0x0}, {0xFB34,0x5D4,0x5BC,0x0}, 
+  {0xFB35,0x5D5,0x5BC,0x0}, {0xFB36,0x5D6,0x5BC,0x0}, {0xFB38,0x5D8,0x5BC,0x0}, 
+  {0xFB39,0x5D9,0x5BC,0x0}, {0xFB3A,0x5DA,0x5BC,0x0}, {0xFB3B,0x5DB,0x5BC,0x0}, 
+  {0xFB3C,0x5DC,0x5BC,0x0}, {0xFB3E,0x5DE,0x5BC,0x0}, {0xFB40,0x5E0,0x5BC,0x0}, 
+  {0xFB41,0x5E1,0x5BC,0x0}, {0xFB43,0x5E3,0x5BC,0x0}, {0xFB44,0x5E4,0x5BC,0x0}, 
+  {0xFB46,0x5E6,0x5BC,0x0}, {0xFB47,0x5E7,0x5BC,0x0}, {0xFB48,0x5E8,0x5BC,0x0}, 
+  {0xFB49,0x5E9,0x5BC,0x0}, {0xFB4A,0x5EA,0x5BC,0x0}, {0xFB4B,0x5D5,0x5B9,0x0}, 
+  {0xFB4C,0x5D1,0x5BF,0x0}, {0xFB4D,0x5DB,0x5BF,0x0}, {0xFB4E,0x5E4,0x5BF,0x0} 
+};
+
+
+/* All upper-case translations are included here */
+
+#define NUM_TOUPPER_INFO 677
+static const unirelate toupper_info[NUM_TOUPPER_INFO] = {
+  {0x61,0x41}, {0x62,0x42}, {0x63,0x43}, {0x64,0x44}, {0x65,0x45}, 
+  {0x66,0x46}, {0x67,0x47}, {0x68,0x48}, {0x69,0x49}, {0x6A,0x4A}, 
+  {0x6B,0x4B}, {0x6C,0x4C}, {0x6D,0x4D}, {0x6E,0x4E}, {0x6F,0x4F}, 
+  {0x70,0x50}, {0x71,0x51}, {0x72,0x52}, {0x73,0x53}, {0x74,0x54}, 
+  {0x75,0x55}, {0x76,0x56}, {0x77,0x57}, {0x78,0x58}, {0x79,0x59}, 
+  {0x7A,0x5A}, {0xE0,0xC0}, {0xE1,0xC1}, {0xE2,0xC2}, {0xE3,0xC3}, 
+  {0xE4,0xC4}, {0xE5,0xC5}, {0xE6,0xC6}, {0xE7,0xC7}, {0xE8,0xC8}, 
+  {0xE9,0xC9}, {0xEA,0xCA}, {0xEB,0xCB}, {0xEC,0xCC}, {0xED,0xCD}, 
+  {0xEE,0xCE}, {0xEF,0xCF}, {0xF0,0xD0}, {0xF1,0xD1}, {0xF2,0xD2}, 
+  {0xF3,0xD3}, {0xF4,0xD4}, {0xF5,0xD5}, {0xF6,0xD6}, {0xF8,0xD8}, 
+  {0xF9,0xD9}, {0xFA,0xDA}, {0xFB,0xDB}, {0xFC,0xDC}, {0xFD,0xDD}, 
+  {0xFE,0xDE}, {0xFF,0x178}, {0x101,0x100}, {0x103,0x102}, {0x105,0x104}, 
+  {0x107,0x106}, {0x109,0x108}, {0x10B,0x10A}, {0x10D,0x10C}, {0x10F,0x10E}, 
+  {0x111,0x110}, {0x113,0x112}, {0x115,0x114}, {0x117,0x116}, {0x119,0x118}, 
+  {0x11B,0x11A}, {0x11D,0x11C}, {0x11F,0x11E}, {0x121,0x120}, {0x123,0x122}, 
+  {0x125,0x124}, {0x127,0x126}, {0x129,0x128}, {0x12B,0x12A}, {0x12D,0x12C}, 
+  {0x12F,0x12E}, {0x131,0x49}, {0x133,0x132}, {0x135,0x134}, {0x137,0x136}, 
+  {0x13A,0x139}, {0x13C,0x13B}, {0x13E,0x13D}, {0x140,0x13F}, {0x142,0x141}, 
+  {0x144,0x143}, {0x146,0x145}, {0x148,0x147}, {0x14B,0x14A}, {0x14D,0x14C}, 
+  {0x14F,0x14E}, {0x151,0x150}, {0x153,0x152}, {0x155,0x154}, {0x157,0x156}, 
+  {0x159,0x158}, {0x15B,0x15A}, {0x15D,0x15C}, {0x15F,0x15E}, {0x161,0x160}, 
+  {0x163,0x162}, {0x165,0x164}, {0x167,0x166}, {0x169,0x168}, {0x16B,0x16A}, 
+  {0x16D,0x16C}, {0x16F,0x16E}, {0x171,0x170}, {0x173,0x172}, {0x175,0x174}, 
+  {0x177,0x176}, {0x17A,0x179}, {0x17C,0x17B}, {0x17E,0x17D}, {0x17F,0x53}, 
+  {0x183,0x182}, {0x185,0x184}, {0x188,0x187}, {0x18C,0x18B}, {0x192,0x191}, 
+  {0x199,0x198}, {0x1A1,0x1A0}, {0x1A3,0x1A2}, {0x1A5,0x1A4}, {0x1A8,0x1A7}, 
+  {0x1AD,0x1AC}, {0x1B0,0x1AF}, {0x1B4,0x1B3}, {0x1B6,0x1B5}, {0x1B9,0x1B8}, 
+  {0x1BD,0x1BC}, {0x1C5,0x1C4}, {0x1C6,0x1C4}, {0x1C8,0x1C7}, {0x1C9,0x1C7}, 
+  {0x1CB,0x1CA}, {0x1CC,0x1CA}, {0x1CE,0x1CD}, {0x1D0,0x1CF}, {0x1D2,0x1D1}, 
+  {0x1D4,0x1D3}, {0x1D6,0x1D5}, {0x1D8,0x1D7}, {0x1DA,0x1D9}, {0x1DC,0x1DB}, 
+  {0x1DD,0x18E}, {0x1DF,0x1DE}, {0x1E1,0x1E0}, {0x1E3,0x1E2}, {0x1E5,0x1E4}, 
+  {0x1E7,0x1E6}, {0x1E9,0x1E8}, {0x1EB,0x1EA}, {0x1ED,0x1EC}, {0x1EF,0x1EE}, 
+  {0x1F2,0x1F1}, {0x1F3,0x1F1}, {0x1F5,0x1F4}, {0x1FB,0x1FA}, {0x1FD,0x1FC}, 
+  {0x1FF,0x1FE}, {0x201,0x200}, {0x203,0x202}, {0x205,0x204}, {0x207,0x206}, 
+  {0x209,0x208}, {0x20B,0x20A}, {0x20D,0x20C}, {0x20F,0x20E}, {0x211,0x210}, 
+  {0x213,0x212}, {0x215,0x214}, {0x217,0x216}, {0x253,0x181}, {0x254,0x186}, 
+  {0x256,0x189}, {0x257,0x18A}, {0x259,0x18F}, {0x25B,0x190}, {0x260,0x193}, 
+  {0x263,0x194}, {0x268,0x197}, {0x269,0x196}, {0x26F,0x19C}, {0x272,0x19D}, 
+  {0x275,0x19F}, {0x283,0x1A9}, {0x288,0x1AE}, {0x28A,0x1B1}, {0x28B,0x1B2}, 
+  {0x292,0x1B7}, {0x3AC,0x386}, {0x3AD,0x388}, {0x3AE,0x389}, {0x3AF,0x38A}, 
+  {0x3B1,0x391}, {0x3B2,0x392}, {0x3B3,0x393}, {0x3B4,0x394}, {0x3B5,0x395}, 
+  {0x3B6,0x396}, {0x3B7,0x397}, {0x3B8,0x398}, {0x3B9,0x399}, {0x3BA,0x39A}, 
+  {0x3BB,0x39B}, {0x3BC,0x39C}, {0x3BD,0x39D}, {0x3BE,0x39E}, {0x3BF,0x39F}, 
+  {0x3C0,0x3A0}, {0x3C1,0x3A1}, {0x3C2,0x3A3}, {0x3C3,0x3A3}, {0x3C4,0x3A4}, 
+  {0x3C5,0x3A5}, {0x3C6,0x3A6}, {0x3C7,0x3A7}, {0x3C8,0x3A8}, {0x3C9,0x3A9}, 
+  {0x3CA,0x3AA}, {0x3CB,0x3AB}, {0x3CC,0x38C}, {0x3CD,0x38E}, {0x3CE,0x38F}, 
+  {0x3D0,0x392}, {0x3D1,0x398}, {0x3D5,0x3A6}, {0x3D6,0x3A0}, {0x3E3,0x3E2}, 
+  {0x3E5,0x3E4}, {0x3E7,0x3E6}, {0x3E9,0x3E8}, {0x3EB,0x3EA}, {0x3ED,0x3EC}, 
+  {0x3EF,0x3EE}, {0x3F0,0x39A}, {0x3F1,0x3A1}, {0x3F2,0x3A3}, {0x430,0x410}, 
+  {0x431,0x411}, {0x432,0x412}, {0x433,0x413}, {0x434,0x414}, {0x435,0x415}, 
+  {0x436,0x416}, {0x437,0x417}, {0x438,0x418}, {0x439,0x419}, {0x43A,0x41A}, 
+  {0x43B,0x41B}, {0x43C,0x41C}, {0x43D,0x41D}, {0x43E,0x41E}, {0x43F,0x41F}, 
+  {0x440,0x420}, {0x441,0x421}, {0x442,0x422}, {0x443,0x423}, {0x444,0x424}, 
+  {0x445,0x425}, {0x446,0x426}, {0x447,0x427}, {0x448,0x428}, {0x449,0x429}, 
+  {0x44A,0x42A}, {0x44B,0x42B}, {0x44C,0x42C}, {0x44D,0x42D}, {0x44E,0x42E}, 
+  {0x44F,0x42F}, {0x451,0x401}, {0x452,0x402}, {0x453,0x403}, {0x454,0x404}, 
+  {0x455,0x405}, {0x456,0x406}, {0x457,0x407}, {0x458,0x408}, {0x459,0x409}, 
+  {0x45A,0x40A}, {0x45B,0x40B}, {0x45C,0x40C}, {0x45E,0x40E}, {0x45F,0x40F}, 
+  {0x461,0x460}, {0x463,0x462}, {0x465,0x464}, {0x467,0x466}, {0x469,0x468}, 
+  {0x46B,0x46A}, {0x46D,0x46C}, {0x46F,0x46E}, {0x471,0x470}, {0x473,0x472}, 
+  {0x475,0x474}, {0x477,0x476}, {0x479,0x478}, {0x47B,0x47A}, {0x47D,0x47C}, 
+  {0x47F,0x47E}, {0x481,0x480}, {0x491,0x490}, {0x493,0x492}, {0x495,0x494}, 
+  {0x497,0x496}, {0x499,0x498}, {0x49B,0x49A}, {0x49D,0x49C}, {0x49F,0x49E}, 
+  {0x4A1,0x4A0}, {0x4A3,0x4A2}, {0x4A5,0x4A4}, {0x4A7,0x4A6}, {0x4A9,0x4A8}, 
+  {0x4AB,0x4AA}, {0x4AD,0x4AC}, {0x4AF,0x4AE}, {0x4B1,0x4B0}, {0x4B3,0x4B2}, 
+  {0x4B5,0x4B4}, {0x4B7,0x4B6}, {0x4B9,0x4B8}, {0x4BB,0x4BA}, {0x4BD,0x4BC}, 
+  {0x4BF,0x4BE}, {0x4C2,0x4C1}, {0x4C4,0x4C3}, {0x4C8,0x4C7}, {0x4CC,0x4CB}, 
+  {0x4D1,0x4D0}, {0x4D3,0x4D2}, {0x4D5,0x4D4}, {0x4D7,0x4D6}, {0x4D9,0x4D8}, 
+  {0x4DB,0x4DA}, {0x4DD,0x4DC}, {0x4DF,0x4DE}, {0x4E1,0x4E0}, {0x4E3,0x4E2}, 
+  {0x4E5,0x4E4}, {0x4E7,0x4E6}, {0x4E9,0x4E8}, {0x4EB,0x4EA}, {0x4EF,0x4EE}, 
+  {0x4F1,0x4F0}, {0x4F3,0x4F2}, {0x4F5,0x4F4}, {0x4F9,0x4F8}, {0x561,0x531}, 
+  {0x562,0x532}, {0x563,0x533}, {0x564,0x534}, {0x565,0x535}, {0x566,0x536}, 
+  {0x567,0x537}, {0x568,0x538}, {0x569,0x539}, {0x56A,0x53A}, {0x56B,0x53B}, 
+  {0x56C,0x53C}, {0x56D,0x53D}, {0x56E,0x53E}, {0x56F,0x53F}, {0x570,0x540}, 
+  {0x571,0x541}, {0x572,0x542}, {0x573,0x543}, {0x574,0x544}, {0x575,0x545}, 
+  {0x576,0x546}, {0x577,0x547}, {0x578,0x548}, {0x579,0x549}, {0x57A,0x54A}, 
+  {0x57B,0x54B}, {0x57C,0x54C}, {0x57D,0x54D}, {0x57E,0x54E}, {0x57F,0x54F}, 
+  {0x580,0x550}, {0x581,0x551}, {0x582,0x552}, {0x583,0x553}, {0x584,0x554}, 
+  {0x585,0x555}, {0x586,0x556}, {0x1E01,0x1E00}, {0x1E03,0x1E02}, {0x1E05,0x1E04}, 
+  {0x1E07,0x1E06}, {0x1E09,0x1E08}, {0x1E0B,0x1E0A}, {0x1E0D,0x1E0C}, {0x1E0F,0x1E0E}, 
+  {0x1E11,0x1E10}, {0x1E13,0x1E12}, {0x1E15,0x1E14}, {0x1E17,0x1E16}, {0x1E19,0x1E18}, 
+  {0x1E1B,0x1E1A}, {0x1E1D,0x1E1C}, {0x1E1F,0x1E1E}, {0x1E21,0x1E20}, {0x1E23,0x1E22}, 
+  {0x1E25,0x1E24}, {0x1E27,0x1E26}, {0x1E29,0x1E28}, {0x1E2B,0x1E2A}, {0x1E2D,0x1E2C}, 
+  {0x1E2F,0x1E2E}, {0x1E31,0x1E30}, {0x1E33,0x1E32}, {0x1E35,0x1E34}, {0x1E37,0x1E36}, 
+  {0x1E39,0x1E38}, {0x1E3B,0x1E3A}, {0x1E3D,0x1E3C}, {0x1E3F,0x1E3E}, {0x1E41,0x1E40}, 
+  {0x1E43,0x1E42}, {0x1E45,0x1E44}, {0x1E47,0x1E46}, {0x1E49,0x1E48}, {0x1E4B,0x1E4A}, 
+  {0x1E4D,0x1E4C}, {0x1E4F,0x1E4E}, {0x1E51,0x1E50}, {0x1E53,0x1E52}, {0x1E55,0x1E54}, 
+  {0x1E57,0x1E56}, {0x1E59,0x1E58}, {0x1E5B,0x1E5A}, {0x1E5D,0x1E5C}, {0x1E5F,0x1E5E}, 
+  {0x1E61,0x1E60}, {0x1E63,0x1E62}, {0x1E65,0x1E64}, {0x1E67,0x1E66}, {0x1E69,0x1E68}, 
+  {0x1E6B,0x1E6A}, {0x1E6D,0x1E6C}, {0x1E6F,0x1E6E}, {0x1E71,0x1E70}, {0x1E73,0x1E72}, 
+  {0x1E75,0x1E74}, {0x1E77,0x1E76}, {0x1E79,0x1E78}, {0x1E7B,0x1E7A}, {0x1E7D,0x1E7C}, 
+  {0x1E7F,0x1E7E}, {0x1E81,0x1E80}, {0x1E83,0x1E82}, {0x1E85,0x1E84}, {0x1E87,0x1E86}, 
+  {0x1E89,0x1E88}, {0x1E8B,0x1E8A}, {0x1E8D,0x1E8C}, {0x1E8F,0x1E8E}, {0x1E91,0x1E90}, 
+  {0x1E93,0x1E92}, {0x1E95,0x1E94}, {0x1E9B,0x1E60}, {0x1EA1,0x1EA0}, {0x1EA3,0x1EA2}, 
+  {0x1EA5,0x1EA4}, {0x1EA7,0x1EA6}, {0x1EA9,0x1EA8}, {0x1EAB,0x1EAA}, {0x1EAD,0x1EAC}, 
+  {0x1EAF,0x1EAE}, {0x1EB1,0x1EB0}, {0x1EB3,0x1EB2}, {0x1EB5,0x1EB4}, {0x1EB7,0x1EB6}, 
+  {0x1EB9,0x1EB8}, {0x1EBB,0x1EBA}, {0x1EBD,0x1EBC}, {0x1EBF,0x1EBE}, {0x1EC1,0x1EC0}, 
+  {0x1EC3,0x1EC2}, {0x1EC5,0x1EC4}, {0x1EC7,0x1EC6}, {0x1EC9,0x1EC8}, {0x1ECB,0x1ECA}, 
+  {0x1ECD,0x1ECC}, {0x1ECF,0x1ECE}, {0x1ED1,0x1ED0}, {0x1ED3,0x1ED2}, {0x1ED5,0x1ED4}, 
+  {0x1ED7,0x1ED6}, {0x1ED9,0x1ED8}, {0x1EDB,0x1EDA}, {0x1EDD,0x1EDC}, {0x1EDF,0x1EDE}, 
+  {0x1EE1,0x1EE0}, {0x1EE3,0x1EE2}, {0x1EE5,0x1EE4}, {0x1EE7,0x1EE6}, {0x1EE9,0x1EE8}, 
+  {0x1EEB,0x1EEA}, {0x1EED,0x1EEC}, {0x1EEF,0x1EEE}, {0x1EF1,0x1EF0}, {0x1EF3,0x1EF2}, 
+  {0x1EF5,0x1EF4}, {0x1EF7,0x1EF6}, {0x1EF9,0x1EF8}, {0x1F00,0x1F08}, {0x1F01,0x1F09}, 
+  {0x1F02,0x1F0A}, {0x1F03,0x1F0B}, {0x1F04,0x1F0C}, {0x1F05,0x1F0D}, {0x1F06,0x1F0E}, 
+  {0x1F07,0x1F0F}, {0x1F10,0x1F18}, {0x1F11,0x1F19}, {0x1F12,0x1F1A}, {0x1F13,0x1F1B}, 
+  {0x1F14,0x1F1C}, {0x1F15,0x1F1D}, {0x1F20,0x1F28}, {0x1F21,0x1F29}, {0x1F22,0x1F2A}, 
+  {0x1F23,0x1F2B}, {0x1F24,0x1F2C}, {0x1F25,0x1F2D}, {0x1F26,0x1F2E}, {0x1F27,0x1F2F}, 
+  {0x1F30,0x1F38}, {0x1F31,0x1F39}, {0x1F32,0x1F3A}, {0x1F33,0x1F3B}, {0x1F34,0x1F3C}, 
+  {0x1F35,0x1F3D}, {0x1F36,0x1F3E}, {0x1F37,0x1F3F}, {0x1F40,0x1F48}, {0x1F41,0x1F49}, 
+  {0x1F42,0x1F4A}, {0x1F43,0x1F4B}, {0x1F44,0x1F4C}, {0x1F45,0x1F4D}, {0x1F51,0x1F59}, 
+  {0x1F53,0x1F5B}, {0x1F55,0x1F5D}, {0x1F57,0x1F5F}, {0x1F60,0x1F68}, {0x1F61,0x1F69}, 
+  {0x1F62,0x1F6A}, {0x1F63,0x1F6B}, {0x1F64,0x1F6C}, {0x1F65,0x1F6D}, {0x1F66,0x1F6E}, 
+  {0x1F67,0x1F6F}, {0x1F70,0x1FBA}, {0x1F71,0x1FBB}, {0x1F72,0x1FC8}, {0x1F73,0x1FC9}, 
+  {0x1F74,0x1FCA}, {0x1F75,0x1FCB}, {0x1F76,0x1FDA}, {0x1F77,0x1FDB}, {0x1F78,0x1FF8}, 
+  {0x1F79,0x1FF9}, {0x1F7A,0x1FEA}, {0x1F7B,0x1FEB}, {0x1F7C,0x1FFA}, {0x1F7D,0x1FFB}, 
+  {0x1F80,0x1F88}, {0x1F81,0x1F89}, {0x1F82,0x1F8A}, {0x1F83,0x1F8B}, {0x1F84,0x1F8C}, 
+  {0x1F85,0x1F8D}, {0x1F86,0x1F8E}, {0x1F87,0x1F8F}, {0x1F90,0x1F98}, {0x1F91,0x1F99}, 
+  {0x1F92,0x1F9A}, {0x1F93,0x1F9B}, {0x1F94,0x1F9C}, {0x1F95,0x1F9D}, {0x1F96,0x1F9E}, 
+  {0x1F97,0x1F9F}, {0x1FA0,0x1FA8}, {0x1FA1,0x1FA9}, {0x1FA2,0x1FAA}, {0x1FA3,0x1FAB}, 
+  {0x1FA4,0x1FAC}, {0x1FA5,0x1FAD}, {0x1FA6,0x1FAE}, {0x1FA7,0x1FAF}, {0x1FB0,0x1FB8}, 
+  {0x1FB1,0x1FB9}, {0x1FB3,0x1FBC}, {0x1FC3,0x1FCC}, {0x1FD0,0x1FD8}, {0x1FD1,0x1FD9}, 
+  {0x1FE0,0x1FE8}, {0x1FE1,0x1FE9}, {0x1FE5,0x1FEC}, {0x1FF3,0x1FFC}, {0x2170,0x2160}, 
+  {0x2171,0x2161}, {0x2172,0x2162}, {0x2173,0x2163}, {0x2174,0x2164}, {0x2175,0x2165}, 
+  {0x2176,0x2166}, {0x2177,0x2167}, {0x2178,0x2168}, {0x2179,0x2169}, {0x217A,0x216A}, 
+  {0x217B,0x216B}, {0x217C,0x216C}, {0x217D,0x216D}, {0x217E,0x216E}, {0x217F,0x216F}, 
+  {0x24D0,0x24B6}, {0x24D1,0x24B7}, {0x24D2,0x24B8}, {0x24D3,0x24B9}, {0x24D4,0x24BA}, 
+  {0x24D5,0x24BB}, {0x24D6,0x24BC}, {0x24D7,0x24BD}, {0x24D8,0x24BE}, {0x24D9,0x24BF}, 
+  {0x24DA,0x24C0}, {0x24DB,0x24C1}, {0x24DC,0x24C2}, {0x24DD,0x24C3}, {0x24DE,0x24C4}, 
+  {0x24DF,0x24C5}, {0x24E0,0x24C6}, {0x24E1,0x24C7}, {0x24E2,0x24C8}, {0x24E3,0x24C9}, 
+  {0x24E4,0x24CA}, {0x24E5,0x24CB}, {0x24E6,0x24CC}, {0x24E7,0x24CD}, {0x24E8,0x24CE}, 
+  {0x24E9,0x24CF}, {0xFF41,0xFF21}, {0xFF42,0xFF22}, {0xFF43,0xFF23}, {0xFF44,0xFF24}, 
+  {0xFF45,0xFF25}, {0xFF46,0xFF26}, {0xFF47,0xFF27}, {0xFF48,0xFF28}, {0xFF49,0xFF29}, 
+  {0xFF4A,0xFF2A}, {0xFF4B,0xFF2B}, {0xFF4C,0xFF2C}, {0xFF4D,0xFF2D}, {0xFF4E,0xFF2E}, 
+  {0xFF4F,0xFF2F}, {0xFF50,0xFF30}, {0xFF51,0xFF31}, {0xFF52,0xFF32}, {0xFF53,0xFF33}, 
+  {0xFF54,0xFF34}, {0xFF55,0xFF35}, {0xFF56,0xFF36}, {0xFF57,0xFF37}, {0xFF58,0xFF38}, 
+  {0xFF59,0xFF39}, {0xFF5A,0xFF3A} 
+};
+
+
+
+/* All lower-case translations are included here */
+
+#define NUM_TOLOWER_INFO 705
+static const unirelate tolower_info[NUM_TOLOWER_INFO] = {
+  {0x41,0x61}, {0x42,0x62}, {0x43,0x63}, {0x44,0x64}, {0x45,0x65}, 
+  {0x46,0x66}, {0x47,0x67}, {0x48,0x68}, {0x49,0x69}, {0x4A,0x6A}, 
+  {0x4B,0x6B}, {0x4C,0x6C}, {0x4D,0x6D}, {0x4E,0x6E}, {0x4F,0x6F}, 
+  {0x50,0x70}, {0x51,0x71}, {0x52,0x72}, {0x53,0x73}, {0x54,0x74}, 
+  {0x55,0x75}, {0x56,0x76}, {0x57,0x77}, {0x58,0x78}, {0x59,0x79}, 
+  {0x5A,0x7A}, {0xC0,0xE0}, {0xC1,0xE1}, {0xC2,0xE2}, {0xC3,0xE3}, 
+  {0xC4,0xE4}, {0xC5,0xE5}, {0xC6,0xE6}, {0xC7,0xE7}, {0xC8,0xE8}, 
+  {0xC9,0xE9}, {0xCA,0xEA}, {0xCB,0xEB}, {0xCC,0xEC}, {0xCD,0xED}, 
+  {0xCE,0xEE}, {0xCF,0xEF}, {0xD0,0xF0}, {0xD1,0xF1}, {0xD2,0xF2}, 
+  {0xD3,0xF3}, {0xD4,0xF4}, {0xD5,0xF5}, {0xD6,0xF6}, {0xD8,0xF8}, 
+  {0xD9,0xF9}, {0xDA,0xFA}, {0xDB,0xFB}, {0xDC,0xFC}, {0xDD,0xFD}, 
+  {0xDE,0xFE}, {0x100,0x101}, {0x102,0x103}, {0x104,0x105}, {0x106,0x107}, 
+  {0x108,0x109}, {0x10A,0x10B}, {0x10C,0x10D}, {0x10E,0x10F}, {0x110,0x111}, 
+  {0x112,0x113}, {0x114,0x115}, {0x116,0x117}, {0x118,0x119}, {0x11A,0x11B}, 
+  {0x11C,0x11D}, {0x11E,0x11F}, {0x120,0x121}, {0x122,0x123}, {0x124,0x125}, 
+  {0x126,0x127}, {0x128,0x129}, {0x12A,0x12B}, {0x12C,0x12D}, {0x12E,0x12F}, 
+  {0x130,0x69}, {0x132,0x133}, {0x134,0x135}, {0x136,0x137}, {0x139,0x13A}, 
+  {0x13B,0x13C}, {0x13D,0x13E}, {0x13F,0x140}, {0x141,0x142}, {0x143,0x144}, 
+  {0x145,0x146}, {0x147,0x148}, {0x14A,0x14B}, {0x14C,0x14D}, {0x14E,0x14F}, 
+  {0x150,0x151}, {0x152,0x153}, {0x154,0x155}, {0x156,0x157}, {0x158,0x159}, 
+  {0x15A,0x15B}, {0x15C,0x15D}, {0x15E,0x15F}, {0x160,0x161}, {0x162,0x163}, 
+  {0x164,0x165}, {0x166,0x167}, {0x168,0x169}, {0x16A,0x16B}, {0x16C,0x16D}, 
+  {0x16E,0x16F}, {0x170,0x171}, {0x172,0x173}, {0x174,0x175}, {0x176,0x177}, 
+  {0x178,0xFF}, {0x179,0x17A}, {0x17B,0x17C}, {0x17D,0x17E}, {0x181,0x253}, 
+  {0x182,0x183}, {0x184,0x185}, {0x186,0x254}, {0x187,0x188}, {0x189,0x256}, 
+  {0x18A,0x257}, {0x18B,0x18C}, {0x18E,0x1DD}, {0x18F,0x259}, {0x190,0x25B}, 
+  {0x191,0x192}, {0x193,0x260}, {0x194,0x263}, {0x196,0x269}, {0x197,0x268}, 
+  {0x198,0x199}, {0x19C,0x26F}, {0x19D,0x272}, {0x19F,0x275}, {0x1A0,0x1A1}, 
+  {0x1A2,0x1A3}, {0x1A4,0x1A5}, {0x1A7,0x1A8}, {0x1A9,0x283}, {0x1AC,0x1AD}, 
+  {0x1AE,0x288}, {0x1AF,0x1B0}, {0x1B1,0x28A}, {0x1B2,0x28B}, {0x1B3,0x1B4}, 
+  {0x1B5,0x1B6}, {0x1B7,0x292}, {0x1B8,0x1B9}, {0x1BC,0x1BD}, {0x1C4,0x1C6}, 
+  {0x1C5,0x1C6}, {0x1C7,0x1C9}, {0x1C8,0x1C9}, {0x1CA,0x1CC}, {0x1CB,0x1CC}, 
+  {0x1CD,0x1CE}, {0x1CF,0x1D0}, {0x1D1,0x1D2}, {0x1D3,0x1D4}, {0x1D5,0x1D6}, 
+  {0x1D7,0x1D8}, {0x1D9,0x1DA}, {0x1DB,0x1DC}, {0x1DE,0x1DF}, {0x1E0,0x1E1}, 
+  {0x1E2,0x1E3}, {0x1E4,0x1E5}, {0x1E6,0x1E7}, {0x1E8,0x1E9}, {0x1EA,0x1EB}, 
+  {0x1EC,0x1ED}, {0x1EE,0x1EF}, {0x1F1,0x1F3}, {0x1F2,0x1F3}, {0x1F4,0x1F5}, 
+  {0x1FA,0x1FB}, {0x1FC,0x1FD}, {0x1FE,0x1FF}, {0x200,0x201}, {0x202,0x203}, 
+  {0x204,0x205}, {0x206,0x207}, {0x208,0x209}, {0x20A,0x20B}, {0x20C,0x20D}, 
+  {0x20E,0x20F}, {0x210,0x211}, {0x212,0x213}, {0x214,0x215}, {0x216,0x217}, 
+  {0x386,0x3AC}, {0x388,0x3AD}, {0x389,0x3AE}, {0x38A,0x3AF}, {0x38C,0x3CC}, 
+  {0x38E,0x3CD}, {0x38F,0x3CE}, {0x391,0x3B1}, {0x392,0x3B2}, {0x393,0x3B3}, 
+  {0x394,0x3B4}, {0x395,0x3B5}, {0x396,0x3B6}, {0x397,0x3B7}, {0x398,0x3B8}, 
+  {0x399,0x3B9}, {0x39A,0x3BA}, {0x39B,0x3BB}, {0x39C,0x3BC}, {0x39D,0x3BD}, 
+  {0x39E,0x3BE}, {0x39F,0x3BF}, {0x3A0,0x3C0}, {0x3A1,0x3C1}, {0x3A3,0x3C3}, 
+  {0x3A4,0x3C4}, {0x3A5,0x3C5}, {0x3A6,0x3C6}, {0x3A7,0x3C7}, {0x3A8,0x3C8}, 
+  {0x3A9,0x3C9}, {0x3AA,0x3CA}, {0x3AB,0x3CB}, {0x3E2,0x3E3}, {0x3E4,0x3E5}, 
+  {0x3E6,0x3E7}, {0x3E8,0x3E9}, {0x3EA,0x3EB}, {0x3EC,0x3ED}, {0x3EE,0x3EF}, 
+  {0x401,0x451}, {0x402,0x452}, {0x403,0x453}, {0x404,0x454}, {0x405,0x455}, 
+  {0x406,0x456}, {0x407,0x457}, {0x408,0x458}, {0x409,0x459}, {0x40A,0x45A}, 
+  {0x40B,0x45B}, {0x40C,0x45C}, {0x40E,0x45E}, {0x40F,0x45F}, {0x410,0x430}, 
+  {0x411,0x431}, {0x412,0x432}, {0x413,0x433}, {0x414,0x434}, {0x415,0x435}, 
+  {0x416,0x436}, {0x417,0x437}, {0x418,0x438}, {0x419,0x439}, {0x41A,0x43A}, 
+  {0x41B,0x43B}, {0x41C,0x43C}, {0x41D,0x43D}, {0x41E,0x43E}, {0x41F,0x43F}, 
+  {0x420,0x440}, {0x421,0x441}, {0x422,0x442}, {0x423,0x443}, {0x424,0x444}, 
+  {0x425,0x445}, {0x426,0x446}, {0x427,0x447}, {0x428,0x448}, {0x429,0x449}, 
+  {0x42A,0x44A}, {0x42B,0x44B}, {0x42C,0x44C}, {0x42D,0x44D}, {0x42E,0x44E}, 
+  {0x42F,0x44F}, {0x460,0x461}, {0x462,0x463}, {0x464,0x465}, {0x466,0x467}, 
+  {0x468,0x469}, {0x46A,0x46B}, {0x46C,0x46D}, {0x46E,0x46F}, {0x470,0x471}, 
+  {0x472,0x473}, {0x474,0x475}, {0x476,0x477}, {0x478,0x479}, {0x47A,0x47B}, 
+  {0x47C,0x47D}, {0x47E,0x47F}, {0x480,0x481}, {0x490,0x491}, {0x492,0x493}, 
+  {0x494,0x495}, {0x496,0x497}, {0x498,0x499}, {0x49A,0x49B}, {0x49C,0x49D}, 
+  {0x49E,0x49F}, {0x4A0,0x4A1}, {0x4A2,0x4A3}, {0x4A4,0x4A5}, {0x4A6,0x4A7}, 
+  {0x4A8,0x4A9}, {0x4AA,0x4AB}, {0x4AC,0x4AD}, {0x4AE,0x4AF}, {0x4B0,0x4B1}, 
+  {0x4B2,0x4B3}, {0x4B4,0x4B5}, {0x4B6,0x4B7}, {0x4B8,0x4B9}, {0x4BA,0x4BB}, 
+  {0x4BC,0x4BD}, {0x4BE,0x4BF}, {0x4C1,0x4C2}, {0x4C3,0x4C4}, {0x4C7,0x4C8}, 
+  {0x4CB,0x4CC}, {0x4D0,0x4D1}, {0x4D2,0x4D3}, {0x4D4,0x4D5}, {0x4D6,0x4D7}, 
+  {0x4D8,0x4D9}, {0x4DA,0x4DB}, {0x4DC,0x4DD}, {0x4DE,0x4DF}, {0x4E0,0x4E1}, 
+  {0x4E2,0x4E3}, {0x4E4,0x4E5}, {0x4E6,0x4E7}, {0x4E8,0x4E9}, {0x4EA,0x4EB}, 
+  {0x4EE,0x4EF}, {0x4F0,0x4F1}, {0x4F2,0x4F3}, {0x4F4,0x4F5}, {0x4F8,0x4F9}, 
+  {0x531,0x561}, {0x532,0x562}, {0x533,0x563}, {0x534,0x564}, {0x535,0x565}, 
+  {0x536,0x566}, {0x537,0x567}, {0x538,0x568}, {0x539,0x569}, {0x53A,0x56A}, 
+  {0x53B,0x56B}, {0x53C,0x56C}, {0x53D,0x56D}, {0x53E,0x56E}, {0x53F,0x56F}, 
+  {0x540,0x570}, {0x541,0x571}, {0x542,0x572}, {0x543,0x573}, {0x544,0x574}, 
+  {0x545,0x575}, {0x546,0x576}, {0x547,0x577}, {0x548,0x578}, {0x549,0x579}, 
+  {0x54A,0x57A}, {0x54B,0x57B}, {0x54C,0x57C}, {0x54D,0x57D}, {0x54E,0x57E}, 
+  {0x54F,0x57F}, {0x550,0x580}, {0x551,0x581}, {0x552,0x582}, {0x553,0x583}, 
+  {0x554,0x584}, {0x555,0x585}, {0x556,0x586}, {0x10A0,0x10D0}, {0x10A1,0x10D1}, 
+  {0x10A2,0x10D2}, {0x10A3,0x10D3}, {0x10A4,0x10D4}, {0x10A5,0x10D5}, {0x10A6,0x10D6}, 
+  {0x10A7,0x10D7}, {0x10A8,0x10D8}, {0x10A9,0x10D9}, {0x10AA,0x10DA}, {0x10AB,0x10DB}, 
+  {0x10AC,0x10DC}, {0x10AD,0x10DD}, {0x10AE,0x10DE}, {0x10AF,0x10DF}, {0x10B0,0x10E0}, 
+  {0x10B1,0x10E1}, {0x10B2,0x10E2}, {0x10B3,0x10E3}, {0x10B4,0x10E4}, {0x10B5,0x10E5}, 
+  {0x10B6,0x10E6}, {0x10B7,0x10E7}, {0x10B8,0x10E8}, {0x10B9,0x10E9}, {0x10BA,0x10EA}, 
+  {0x10BB,0x10EB}, {0x10BC,0x10EC}, {0x10BD,0x10ED}, {0x10BE,0x10EE}, {0x10BF,0x10EF}, 
+  {0x10C0,0x10F0}, {0x10C1,0x10F1}, {0x10C2,0x10F2}, {0x10C3,0x10F3}, {0x10C4,0x10F4}, 
+  {0x10C5,0x10F5}, {0x1E00,0x1E01}, {0x1E02,0x1E03}, {0x1E04,0x1E05}, {0x1E06,0x1E07}, 
+  {0x1E08,0x1E09}, {0x1E0A,0x1E0B}, {0x1E0C,0x1E0D}, {0x1E0E,0x1E0F}, {0x1E10,0x1E11}, 
+  {0x1E12,0x1E13}, {0x1E14,0x1E15}, {0x1E16,0x1E17}, {0x1E18,0x1E19}, {0x1E1A,0x1E1B}, 
+  {0x1E1C,0x1E1D}, {0x1E1E,0x1E1F}, {0x1E20,0x1E21}, {0x1E22,0x1E23}, {0x1E24,0x1E25}, 
+  {0x1E26,0x1E27}, {0x1E28,0x1E29}, {0x1E2A,0x1E2B}, {0x1E2C,0x1E2D}, {0x1E2E,0x1E2F}, 
+  {0x1E30,0x1E31}, {0x1E32,0x1E33}, {0x1E34,0x1E35}, {0x1E36,0x1E37}, {0x1E38,0x1E39}, 
+  {0x1E3A,0x1E3B}, {0x1E3C,0x1E3D}, {0x1E3E,0x1E3F}, {0x1E40,0x1E41}, {0x1E42,0x1E43}, 
+  {0x1E44,0x1E45}, {0x1E46,0x1E47}, {0x1E48,0x1E49}, {0x1E4A,0x1E4B}, {0x1E4C,0x1E4D}, 
+  {0x1E4E,0x1E4F}, {0x1E50,0x1E51}, {0x1E52,0x1E53}, {0x1E54,0x1E55}, {0x1E56,0x1E57}, 
+  {0x1E58,0x1E59}, {0x1E5A,0x1E5B}, {0x1E5C,0x1E5D}, {0x1E5E,0x1E5F}, {0x1E60,0x1E61}, 
+  {0x1E62,0x1E63}, {0x1E64,0x1E65}, {0x1E66,0x1E67}, {0x1E68,0x1E69}, {0x1E6A,0x1E6B}, 
+  {0x1E6C,0x1E6D}, {0x1E6E,0x1E6F}, {0x1E70,0x1E71}, {0x1E72,0x1E73}, {0x1E74,0x1E75}, 
+  {0x1E76,0x1E77}, {0x1E78,0x1E79}, {0x1E7A,0x1E7B}, {0x1E7C,0x1E7D}, {0x1E7E,0x1E7F}, 
+  {0x1E80,0x1E81}, {0x1E82,0x1E83}, {0x1E84,0x1E85}, {0x1E86,0x1E87}, {0x1E88,0x1E89}, 
+  {0x1E8A,0x1E8B}, {0x1E8C,0x1E8D}, {0x1E8E,0x1E8F}, {0x1E90,0x1E91}, {0x1E92,0x1E93}, 
+  {0x1E94,0x1E95}, {0x1EA0,0x1EA1}, {0x1EA2,0x1EA3}, {0x1EA4,0x1EA5}, {0x1EA6,0x1EA7}, 
+  {0x1EA8,0x1EA9}, {0x1EAA,0x1EAB}, {0x1EAC,0x1EAD}, {0x1EAE,0x1EAF}, {0x1EB0,0x1EB1}, 
+  {0x1EB2,0x1EB3}, {0x1EB4,0x1EB5}, {0x1EB6,0x1EB7}, {0x1EB8,0x1EB9}, {0x1EBA,0x1EBB}, 
+  {0x1EBC,0x1EBD}, {0x1EBE,0x1EBF}, {0x1EC0,0x1EC1}, {0x1EC2,0x1EC3}, {0x1EC4,0x1EC5}, 
+  {0x1EC6,0x1EC7}, {0x1EC8,0x1EC9}, {0x1ECA,0x1ECB}, {0x1ECC,0x1ECD}, {0x1ECE,0x1ECF}, 
+  {0x1ED0,0x1ED1}, {0x1ED2,0x1ED3}, {0x1ED4,0x1ED5}, {0x1ED6,0x1ED7}, {0x1ED8,0x1ED9}, 
+  {0x1EDA,0x1EDB}, {0x1EDC,0x1EDD}, {0x1EDE,0x1EDF}, {0x1EE0,0x1EE1}, {0x1EE2,0x1EE3}, 
+  {0x1EE4,0x1EE5}, {0x1EE6,0x1EE7}, {0x1EE8,0x1EE9}, {0x1EEA,0x1EEB}, {0x1EEC,0x1EED}, 
+  {0x1EEE,0x1EEF}, {0x1EF0,0x1EF1}, {0x1EF2,0x1EF3}, {0x1EF4,0x1EF5}, {0x1EF6,0x1EF7}, 
+  {0x1EF8,0x1EF9}, {0x1F08,0x1F00}, {0x1F09,0x1F01}, {0x1F0A,0x1F02}, {0x1F0B,0x1F03}, 
+  {0x1F0C,0x1F04}, {0x1F0D,0x1F05}, {0x1F0E,0x1F06}, {0x1F0F,0x1F07}, {0x1F18,0x1F10}, 
+  {0x1F19,0x1F11}, {0x1F1A,0x1F12}, {0x1F1B,0x1F13}, {0x1F1C,0x1F14}, {0x1F1D,0x1F15}, 
+  {0x1F28,0x1F20}, {0x1F29,0x1F21}, {0x1F2A,0x1F22}, {0x1F2B,0x1F23}, {0x1F2C,0x1F24}, 
+  {0x1F2D,0x1F25}, {0x1F2E,0x1F26}, {0x1F2F,0x1F27}, {0x1F38,0x1F30}, {0x1F39,0x1F31}, 
+  {0x1F3A,0x1F32}, {0x1F3B,0x1F33}, {0x1F3C,0x1F34}, {0x1F3D,0x1F35}, {0x1F3E,0x1F36}, 
+  {0x1F3F,0x1F37}, {0x1F48,0x1F40}, {0x1F49,0x1F41}, {0x1F4A,0x1F42}, {0x1F4B,0x1F43}, 
+  {0x1F4C,0x1F44}, {0x1F4D,0x1F45}, {0x1F59,0x1F51}, {0x1F5B,0x1F53}, {0x1F5D,0x1F55}, 
+  {0x1F5F,0x1F57}, {0x1F68,0x1F60}, {0x1F69,0x1F61}, {0x1F6A,0x1F62}, {0x1F6B,0x1F63}, 
+  {0x1F6C,0x1F64}, {0x1F6D,0x1F65}, {0x1F6E,0x1F66}, {0x1F6F,0x1F67}, {0x1F88,0x1F80}, 
+  {0x1F89,0x1F81}, {0x1F8A,0x1F82}, {0x1F8B,0x1F83}, {0x1F8C,0x1F84}, {0x1F8D,0x1F85}, 
+  {0x1F8E,0x1F86}, {0x1F8F,0x1F87}, {0x1F98,0x1F90}, {0x1F99,0x1F91}, {0x1F9A,0x1F92}, 
+  {0x1F9B,0x1F93}, {0x1F9C,0x1F94}, {0x1F9D,0x1F95}, {0x1F9E,0x1F96}, {0x1F9F,0x1F97}, 
+  {0x1FA8,0x1FA0}, {0x1FA9,0x1FA1}, {0x1FAA,0x1FA2}, {0x1FAB,0x1FA3}, {0x1FAC,0x1FA4}, 
+  {0x1FAD,0x1FA5}, {0x1FAE,0x1FA6}, {0x1FAF,0x1FA7}, {0x1FB8,0x1FB0}, {0x1FB9,0x1FB1}, 
+  {0x1FBA,0x1F70}, {0x1FBB,0x1F71}, {0x1FBC,0x1FB3}, {0x1FC8,0x1F72}, {0x1FC9,0x1F73}, 
+  {0x1FCA,0x1F74}, {0x1FCB,0x1F75}, {0x1FCC,0x1FC3}, {0x1FD8,0x1FD0}, {0x1FD9,0x1FD1}, 
+  {0x1FDA,0x1F76}, {0x1FDB,0x1F77}, {0x1FE8,0x1FE0}, {0x1FE9,0x1FE1}, {0x1FEA,0x1F7A}, 
+  {0x1FEB,0x1F7B}, {0x1FEC,0x1FE5}, {0x1FF8,0x1F78}, {0x1FF9,0x1F79}, {0x1FFA,0x1F7C}, 
+  {0x1FFB,0x1F7D}, {0x1FFC,0x1FF3}, {0x2160,0x2170}, {0x2161,0x2171}, {0x2162,0x2172}, 
+  {0x2163,0x2173}, {0x2164,0x2174}, {0x2165,0x2175}, {0x2166,0x2176}, {0x2167,0x2177}, 
+  {0x2168,0x2178}, {0x2169,0x2179}, {0x216A,0x217A}, {0x216B,0x217B}, {0x216C,0x217C}, 
+  {0x216D,0x217D}, {0x216E,0x217E}, {0x216F,0x217F}, {0x24B6,0x24D0}, {0x24B7,0x24D1}, 
+  {0x24B8,0x24D2}, {0x24B9,0x24D3}, {0x24BA,0x24D4}, {0x24BB,0x24D5}, {0x24BC,0x24D6}, 
+  {0x24BD,0x24D7}, {0x24BE,0x24D8}, {0x24BF,0x24D9}, {0x24C0,0x24DA}, {0x24C1,0x24DB}, 
+  {0x24C2,0x24DC}, {0x24C3,0x24DD}, {0x24C4,0x24DE}, {0x24C5,0x24DF}, {0x24C6,0x24E0}, 
+  {0x24C7,0x24E1}, {0x24C8,0x24E2}, {0x24C9,0x24E3}, {0x24CA,0x24E4}, {0x24CB,0x24E5}, 
+  {0x24CC,0x24E6}, {0x24CD,0x24E7}, {0x24CE,0x24E8}, {0x24CF,0x24E9}, {0xFF21,0xFF41}, 
+  {0xFF22,0xFF42}, {0xFF23,0xFF43}, {0xFF24,0xFF44}, {0xFF25,0xFF45}, {0xFF26,0xFF46}, 
+  {0xFF27,0xFF47}, {0xFF28,0xFF48}, {0xFF29,0xFF49}, {0xFF2A,0xFF4A}, {0xFF2B,0xFF4B}, 
+  {0xFF2C,0xFF4C}, {0xFF2D,0xFF4D}, {0xFF2E,0xFF4E}, {0xFF2F,0xFF4F}, {0xFF30,0xFF50}, 
+  {0xFF31,0xFF51}, {0xFF32,0xFF52}, {0xFF33,0xFF53}, {0xFF34,0xFF54}, {0xFF35,0xFF55}, 
+  {0xFF36,0xFF56}, {0xFF37,0xFF57}, {0xFF38,0xFF58}, {0xFF39,0xFF59}, {0xFF3A,0xFF5A}
+};
+
+
+
+#define NUM_TOSIMPLIFIED_INFO 2145
+static const unirelate tosimplified_info[NUM_TOSIMPLIFIED_INFO] = {
+  {0x4E48,0x9EBD}, {0x4E82,0x4E71}, {0x4E9E,0x4E9A}, {0x4F47,0x4F2B}, {0x4F59,0x9980}, 
+  {0x4F86,0x6765}, {0x4F96,0x4ED1}, {0x4FE0,0x4FA0}, {0x5000,0x4F25}, {0x5006,0x4FE9}, 
+  {0x5009,0x4ED3}, {0x500B,0x4E2A}, {0x5011,0x4EEC}, {0x502B,0x4F26}, {0x5049,0x4F1F}, 
+  {0x5074,0x4FA7}, {0x5075,0x4FA6}, {0x5096,0x4F27}, {0x5098,0x4F1E}, {0x5099,0x5907}, 
+  {0x50AD,0x4F63}, {0x50B3,0x4F20}, {0x50B4,0x4F1B}, {0x50B5,0x503A}, {0x50B7,0x4F24}, 
+  {0x50BE,0x503E}, {0x50C2,0x507B}, {0x50C5,0x4EC5}, {0x50C9,0x4F65}, {0x50D1,0x4FA8}, 
+  {0x50D5,0x4EC6}, {0x50DE,0x4F2A}, {0x50E5,0x4FA5}, {0x50E8,0x507E}, {0x50F9,0x4EF7}, 
+  {0x5100,0x4EEA}, {0x5102,0x4FAC}, {0x5104,0x4EBF}, {0x5108,0x4FA9}, {0x5109,0x4FED}, 
+  {0x5110,0x50A7}, {0x5114,0x4FE6}, {0x5115,0x4FAA}, {0x511F,0x507F}, {0x512A,0x4F18}, 
+  {0x5132,0x50A8}, {0x5137,0x4FEA}, {0x513A,0x50A9}, {0x513B,0x50A5}, {0x513C,0x4FE8}, 
+  {0x5152,0x513F}, {0x5169,0x4E24}, {0x51C8,0x51C0}, {0x51CD,0x51BB}, {0x51F1,0x51EF}, 
+  {0x5244,0x522D}, {0x5247,0x5219}, {0x525B,0x521A}, {0x526E,0x5250}, {0x5274,0x5240}, 
+  {0x5275,0x521B}, {0x5283,0x5212}, {0x5287,0x5267}, {0x5289,0x5218}, {0x528A,0x523D}, 
+  {0x528C,0x523F}, {0x528D,0x5251}, {0x5291,0x5242}, {0x52C1,0x52B2}, {0x52D5,0x52A8}, 
+  {0x52D9,0x52A1}, {0x52DB,0x52CB}, {0x52DD,0x80DC}, {0x52DE,0x52B3}, {0x52E2,0x52BF}, 
+  {0x52F1,0x52A2}, {0x52F5,0x52B1}, {0x52F8,0x529D}, {0x532D,0x5326}, {0x532F,0x6C47}, 
+  {0x5331,0x532E}, {0x5340,0x533A}, {0x5354,0x534F}, {0x5399,0x538D}, {0x53A0,0x5395}, 
+  {0x53AD,0x538C}, {0x53B2,0x5389}, {0x53B4,0x53A3}, {0x53C3,0x53C2}, {0x53E2,0x4E1B}, 
+  {0x540E,0x5F8C}, {0x54BC,0x5459}, {0x54E1,0x5458}, {0x5504,0x5457}, {0x554F,0x95EE}, 
+  {0x5553,0x542F}, {0x555E,0x54D1}, {0x559A,0x5524}, {0x55AA,0x4E27}, {0x55AC,0x4E54}, 
+  {0x55AE,0x5355}, {0x55B2,0x54DF}, {0x55C6,0x545B}, {0x55C7,0x556C}, {0x55CE,0x5417}, 
+  {0x55DA,0x545C}, {0x55E9,0x5522}, {0x55F6,0x54D4}, {0x5606,0x53F9}, {0x560D,0x55BD}, 
+  {0x5614,0x5455}, {0x5616,0x5567}, {0x5617,0x5C1D}, {0x561C,0x551B}, {0x5629,0x54D7}, 
+  {0x562E,0x5520}, {0x562F,0x5578}, {0x5630,0x53FD}, {0x5635,0x54D3}, {0x5638,0x5452}, 
+  {0x565D,0x549D}, {0x5660,0x54D2}, {0x5665,0x54DD}, {0x5666,0x54D5}, {0x566F,0x55F3}, 
+  {0x5672,0x54D9}, {0x5674,0x55B7}, {0x5678,0x5428}, {0x5680,0x549B}, {0x5687,0x5413}, 
+  {0x568C,0x54DC}, {0x5695,0x565C}, {0x5699,0x556E}, {0x56A6,0x5456}, {0x56A8,0x5499}, 
+  {0x56B3,0x55BE}, {0x56B4,0x4E25}, {0x56B6,0x5624}, {0x56C0,0x556D}, {0x56C1,0x55EB}, 
+  {0x56C2,0x56A3}, {0x56C5,0x5181}, {0x56C8,0x5453}, {0x56D1,0x5631}, {0x5707,0x56F5}, 
+  {0x570B,0x56FD}, {0x570D,0x56F4}, {0x5712,0x56ED}, {0x5713,0x5706}, {0x5716,0x56FE}, 
+  {0x5718,0x56E2}, {0x57E1,0x57AD}, {0x57F7,0x6267}, {0x5805,0x575A}, {0x580A,0x57A9}, 
+  {0x5816,0x57B4}, {0x581D,0x57DA}, {0x582F,0x5C27}, {0x5831,0x62A5}, {0x5834,0x573A}, 
+  {0x584A,0x5757}, {0x584B,0x8314}, {0x584F,0x57B2}, {0x5852,0x57D8}, {0x5857,0x6D82}, 
+  {0x5862,0x575E}, {0x5864,0x57D9}, {0x5875,0x5C18}, {0x5879,0x5811}, {0x588A,0x57AB}, 
+  {0x589C,0x5760}, {0x58AE,0x5815}, {0x58B3,0x575F}, {0x58BB,0x5899}, {0x58BE,0x57A6}, 
+  {0x58C7,0x575B}, {0x58D3,0x538B}, {0x58D8,0x5792}, {0x58D9,0x5739}, {0x58DA,0x5786}, 
+  {0x58DE,0x574F}, {0x58DF,0x5784}, {0x58E0,0x5785}, {0x58E2,0x575C}, {0x58E9,0x575D}, 
+  {0x58EF,0x58EE}, {0x58FA,0x58F6}, {0x58FD,0x5BFF}, {0x5922,0x68A6}, {0x593E,0x5939}, 
+  {0x5950,0x5942}, {0x5969,0x5941}, {0x596A,0x593A}, {0x596C,0x5956}, {0x596E,0x594B}, 
+  {0x599D,0x5986}, {0x5A41,0x5A04}, {0x5A66,0x5987}, {0x5A6D,0x5A05}, {0x5AA7,0x5A32}, 
+  {0x5ABD,0x5988}, {0x5AD7,0x59AA}, {0x5AF5,0x59A9}, {0x5AFB,0x5A34}, {0x5B00,0x59AB}, 
+  {0x5B08,0x5A06}, {0x5B0B,0x5A75}, {0x5B0C,0x5A07}, {0x5B19,0x5AF1}, {0x5B21,0x5AD2}, 
+  {0x5B2A,0x5AD4}, {0x5B30,0x5A74}, {0x5B38,0x5A76}, {0x5B4C,0x5A08}, {0x5B6B,0x5B59}, 
+  {0x5B78,0x5B66}, {0x5B7F,0x5B6A}, {0x5BE2,0x5BDD}, {0x5BE6,0x5B9E}, {0x5BE7,0x5B81}, 
+  {0x5BE9,0x5BA1}, {0x5BEB,0x5199}, {0x5BEC,0x5BBD}, {0x5BF5,0x5BA0}, {0x5BF6,0x5B9D}, 
+  {0x5C07,0x5C06}, {0x5C08,0x4E13}, {0x5C0B,0x5BFB}, {0x5C0D,0x5BF9}, {0x5C0E,0x5BFC}, 
+  {0x5C37,0x5C34}, {0x5C62,0x5C61}, {0x5C64,0x5C42}, {0x5C68,0x5C66}, {0x5C6C,0x5C5E}, 
+  {0x5CA1,0x5188}, {0x5CF4,0x5C98}, {0x5CF6,0x5C9B}, {0x5CFD,0x5CE1}, {0x5D0D,0x5D03}, 
+  {0x5D17,0x5C97}, {0x5D22,0x5CE5}, {0x5D2C,0x5CBD}, {0x5D50,0x5C9A}, {0x5D81,0x5D5D}, 
+  {0x5D84,0x5D2D}, {0x5D87,0x5C96}, {0x5D97,0x5D02}, {0x5DA0,0x5CE4}, {0x5DA7,0x5CC4}, 
+  {0x5DB8,0x5D58}, {0x5DBA,0x5CAD}, {0x5DBC,0x5C7F}, {0x5DCB,0x5CBF}, {0x5DD2,0x5CE6}, 
+  {0x5DD4,0x5DC5}, {0x5DF0,0x5DEF}, {0x5E25,0x5E05}, {0x5E2B,0x5E08}, {0x5E33,0x5E10}, 
+  {0x5E36,0x5E26}, {0x5E40,0x5E27}, {0x5E43,0x5E0F}, {0x5E57,0x5E3C}, {0x5E58,0x5E3B}, 
+  {0x5E5F,0x5E1C}, {0x5E63,0x5E01}, {0x5E6B,0x5E2E}, {0x5E6C,0x5E31}, {0x5E79,0x5E72}, 
+  {0x5E7E,0x51E0}, {0x5EAB,0x5E93}, {0x5EDF,0x5E99}, {0x5EE0,0x5382}, {0x5EE1,0x5E91}, 
+  {0x5EE2,0x5E9F}, {0x5EE3,0x5E7F}, {0x5EEC,0x5E90}, {0x5EF3,0x5385}, {0x5F33,0x5F2A}, 
+  {0x5F35,0x5F20}, {0x5F48,0x5F39}, {0x5F4C,0x5F25}, {0x5F4E,0x5F2F}, {0x5F8C,0x540E}, 
+  {0x5F91,0x5F84}, {0x5F9E,0x4ECE}, {0x5FA0,0x5F95}, {0x5FA9,0x590D}, {0x5FB9,0x5F7B}, 
+  {0x60B5,0x6005}, {0x60B6,0x95F7}, {0x60E1,0x6076}, {0x60F1,0x607C}, {0x60F2,0x607D}, 
+  {0x60FB,0x607B}, {0x611B,0x7231}, {0x611C,0x60EC}, {0x6134,0x6006}, {0x6137,0x607A}, 
+  {0x613E,0x5FFE}, {0x614B,0x6001}, {0x6158,0x60E8}, {0x615A,0x60ED}, {0x615F,0x6078}, 
+  {0x6163,0x60EF}, {0x6164,0x60AB}, {0x616A,0x6004}, {0x616B,0x6002}, {0x616E,0x8651}, 
+  {0x6173,0x60AD}, {0x6176,0x5E86}, {0x6182,0x5FE7}, {0x618A,0x60EB}, {0x6190,0x601C}, 
+  {0x6191,0x51ED}, {0x6192,0x6126}, {0x619A,0x60EE}, {0x61A4,0x6124}, {0x61AB,0x60AF}, 
+  {0x61AE,0x6003}, {0x61B2,0x5BAA}, {0x61B6,0x5FC6}, {0x61C7,0x6073}, {0x61C9,0x5E94}, 
+  {0x61CC,0x603F}, {0x61DF,0x603C}, {0x61E3,0x61D1}, {0x61E8,0x6079}, {0x61F2,0x60E9}, 
+  {0x61F6,0x61D2}, {0x61F7,0x6000}, {0x61F8,0x60AC}, {0x61FA,0x5FCF}, {0x61FC,0x60E7}, 
+  {0x61FE,0x6151}, {0x6200,0x604B}, {0x6207,0x6206}, {0x6214,0x620B}, {0x6227,0x6217}, 
+  {0x6229,0x622C}, {0x6230,0x6218}, {0x6232,0x620F}, {0x633E,0x631F}, {0x6368,0x820D}, 
+  {0x636B,0x626A}, {0x6383,0x626B}, {0x6384,0x62A1}, {0x6399,0x6323}, {0x63C0,0x62E3}, 
+  {0x63DA,0x626C}, {0x63DB,0x6362}, {0x63EE,0x6325}, {0x640D,0x635F}, {0x6417,0x6363}, 
+  {0x6436,0x62A2}, {0x6451,0x63B4}, {0x645C,0x63BC}, {0x645F,0x6402}, {0x646F,0x631A}, 
+  {0x6473,0x62A0}, {0x6476,0x629F}, {0x647B,0x63BA}, {0x6488,0x635E}, {0x6493,0x6320}, 
+  {0x649F,0x6322}, {0x64A3,0x63B8}, {0x64A5,0x62E8}, {0x64AB,0x629A}, {0x64B2,0x6251}, 
+  {0x64B3,0x63FF}, {0x64BB,0x631E}, {0x64BE,0x631D}, {0x64BF,0x6361}, {0x64C1,0x62E5}, 
+  {0x64C4,0x63B3}, {0x64C7,0x62E9}, {0x64CA,0x51FB}, {0x64CB,0x6321}, {0x64D4,0x62C5}, 
+  {0x64DA,0x636E}, {0x64E0,0x6324}, {0x64EC,0x62DF}, {0x64EF,0x6448}, {0x64F0,0x62E7}, 
+  {0x64F1,0x6401}, {0x64F2,0x63B7}, {0x64F4,0x6269}, {0x64F7,0x64B7}, {0x64FA,0x6446}, 
+  {0x64FB,0x64DE}, {0x64FC,0x64B8}, {0x64FE,0x6270}, {0x6504,0x6445}, {0x6506,0x64B5}, 
+  {0x650F,0x62E2}, {0x6514,0x62E6}, {0x6516,0x6484}, {0x6519,0x6400}, {0x651B,0x64BA}, 
+  {0x651D,0x6444}, {0x6522,0x6512}, {0x6523,0x631B}, {0x6524,0x644A}, {0x652A,0x6405}, 
+  {0x652C,0x63FD}, {0x6557,0x8D25}, {0x6575,0x654C}, {0x6578,0x6570}, {0x6582,0x655B}, 
+  {0x6583,0x6BD9}, {0x6595,0x6593}, {0x65AC,0x65A9}, {0x65B7,0x65AD}, {0x6642,0x65F6}, 
+  {0x6649,0x664B}, {0x665D,0x663C}, {0x6688,0x6655}, {0x6689,0x6656}, {0x66A2,0x7545}, 
+  {0x66AB,0x6682}, {0x66C4,0x6654}, {0x66C7,0x6619}, {0x66C9,0x6653}, {0x66D6,0x66A7}, 
+  {0x66E0,0x65F7}, {0x66EC,0x6652}, {0x66F8,0x4E66}, {0x6703,0x4F1A}, {0x6727,0x80E7}, 
+  {0x6771,0x4E1C}, {0x6898,0x67A7}, {0x689D,0x6761}, {0x689F,0x67AD}, {0x68C4,0x5F03}, 
+  {0x68D6,0x67A8}, {0x68D7,0x67A3}, {0x68DF,0x680B}, {0x68E7,0x6808}, {0x68F2,0x6816}, 
+  {0x690F,0x6860}, {0x694A,0x6768}, {0x6953,0x67AB}, {0x6968,0x6862}, {0x696D,0x4E1A}, 
+  {0x6975,0x6781}, {0x69AA,0x6769}, {0x69AE,0x8363}, {0x69BF,0x6864}, {0x69CB,0x6784}, 
+  {0x69CD,0x67AA}, {0x69E7,0x6920}, {0x69F3,0x6868}, {0x6A01,0x6869}, {0x6A02,0x4E50}, 
+  {0x6A05,0x679E}, {0x6A13,0x697C}, {0x6A19,0x6807}, {0x6A1E,0x67A2}, {0x6A23,0x6837}, 
+  {0x6A38,0x6734}, {0x6A39,0x6811}, {0x6A3A,0x6866}, {0x6A48,0x6861}, {0x6A4B,0x6865}, 
+  {0x6A5F,0x673A}, {0x6A62,0x692D}, {0x6A89,0x67FD}, {0x6A94,0x6863}, {0x6A9C,0x6867}, 
+  {0x6AA2,0x68C0}, {0x6AA3,0x6A2F}, {0x6AB3,0x69DF}, {0x6AB8,0x67E0}, {0x6ABB,0x69DB}, 
+  {0x6AC3,0x67DC}, {0x6AD3,0x6A79}, {0x6ADA,0x6988}, {0x6ADB,0x6809}, {0x6ADD,0x691F}, 
+  {0x6ADE,0x6A7C}, {0x6ADF,0x680E}, {0x6AE7,0x69E0}, {0x6AE8,0x680C}, {0x6AEA,0x67A5}, 
+  {0x6AEC,0x6987}, {0x6AF3,0x680A}, {0x6AF8,0x6989}, {0x6AFB,0x6A31}, {0x6B04,0x680F}, 
+  {0x6B0A,0x6743}, {0x6B0F,0x6924}, {0x6B12,0x683E}, {0x6B16,0x6984}, {0x6B1E,0x68C2}, 
+  {0x6B3D,0x94A6}, {0x6B50,0x6B27}, {0x6B5F,0x6B24}, {0x6B61,0x6B22}, {0x6B72,0x5C81}, 
+  {0x6B77,0x5386}, {0x6B78,0x5F52}, {0x6B98,0x6B8B}, {0x6B9E,0x6B92}, {0x6BA4,0x6B87}, 
+  {0x6BAB,0x6B9A}, {0x6BAE,0x6B93}, {0x6BAF,0x6BA1}, {0x6BB2,0x6B7C}, {0x6BBA,0x6740}, 
+  {0x6BBB,0x58F3}, {0x6BC6,0x6BB4}, {0x6BFF,0x6BF5}, {0x6C08,0x6BE1}, {0x6C0C,0x6C07}, 
+  {0x6C23,0x6C14}, {0x6C2B,0x6C22}, {0x6C2C,0x6C29}, {0x6D79,0x6D43}, {0x6D87,0x6CFE}, 
+  {0x6DEA,0x6CA6}, {0x6DF5,0x6E0A}, {0x6DF6,0x6D9E}, {0x6DFA,0x6D45}, {0x6E19,0x6DA3}, 
+  {0x6E26,0x6DA1}, {0x6E2C,0x6D4B}, {0x6E3E,0x6D51}, {0x6E5E,0x6D48}, {0x6E6F,0x6C64}, 
+  {0x6E96,0x51C6}, {0x6E9D,0x6C9F}, {0x6EC4,0x6CA7}, {0x6EC5,0x706D}, {0x6ECC,0x6DA4}, 
+  {0x6ECE,0x8365}, {0x6EEC,0x6CAA}, {0x6EEF,0x6EDE}, {0x6EF2,0x6E17}, {0x6EF7,0x5364}, 
+  {0x6EF8,0x6D52}, {0x6EFF,0x6EE1}, {0x6F01,0x6E14}, {0x6F1A,0x6CA4}, {0x6F22,0x6C49}, 
+  {0x6F23,0x6D9F}, {0x6F2C,0x6E0D}, {0x6F32,0x6DA8}, {0x6F38,0x6E10}, {0x6F3F,0x6D46}, 
+  {0x6F41,0x988D}, {0x6F51,0x6CFC}, {0x6F54,0x6D01}, {0x6F59,0x6CA9}, {0x6F5B,0x6F5C}, 
+  {0x6F64,0x6DA6}, {0x6F6F,0x6D54}, {0x6F70,0x6E83}, {0x6F77,0x6ED7}, {0x6F7F,0x6DA0}, 
+  {0x6F80,0x6DA9}, {0x6F86,0x6D47}, {0x6F87,0x6D9D}, {0x6F97,0x6DA7}, {0x6FA0,0x6E11}, 
+  {0x6FA4,0x6CFD}, {0x6FA9,0x6CF6}, {0x6FAE,0x6D4D}, {0x6FB1,0x6DC0}, {0x6FC1,0x6D4A}, 
+  {0x6FC3,0x6D53}, {0x6FD5,0x6E7F}, {0x6FD8,0x6CDE}, {0x6FDF,0x6D4E}, {0x6FE4,0x6D9B}, 
+  {0x6FEB,0x6EE5}, {0x6FF0,0x6F4D}, {0x6FF1,0x6EE8}, {0x6FFA,0x6E85}, {0x6FFC,0x6CFA}, 
+  {0x6FFE,0x6EE4}, {0x7005,0x6EE2}, {0x7006,0x6E0E}, {0x7009,0x6CFB}, {0x700B,0x6E16}, 
+  {0x700F,0x6D4F}, {0x7015,0x6FD2}, {0x7018,0x6CF8}, {0x701D,0x6CA5}, {0x701F,0x6F47}, 
+  {0x7020,0x6F46}, {0x7027,0x6CF7}, {0x7028,0x6FD1}, {0x7032,0x6F4B}, {0x703E,0x6F9C}, 
+  {0x7043,0x6CA3}, {0x7044,0x6EE0}, {0x7051,0x6D12}, {0x7055,0x6F13}, {0x7058,0x6EE9}, 
+  {0x705D,0x704F}, {0x7063,0x6E7E}, {0x7064,0x6EE6}, {0x7067,0x6EDF}, {0x70CF,0x4E4C}, 
+  {0x70F4,0x70C3}, {0x7121,0x65E0}, {0x7149,0x70BC}, {0x7152,0x709C}, {0x7162,0x8315}, 
+  {0x7165,0x7115}, {0x7169,0x70E6}, {0x716C,0x7080}, {0x7192,0x8367}, {0x7197,0x709D}, 
+  {0x71B1,0x70ED}, {0x71BE,0x70BD}, {0x71C1,0x70E8}, {0x71C8,0x706F}, {0x71D2,0x70E7}, 
+  {0x71D9,0x70EB}, {0x71DC,0x7116}, {0x71DF,0x8425}, {0x71E6,0x707F}, {0x71ED,0x70DB}, 
+  {0x71F4,0x70E9}, {0x71FC,0x70EC}, {0x71FE,0x7118}, {0x720D,0x70C1}, {0x7210,0x7089}, 
+  {0x721B,0x70C2}, {0x722D,0x4E89}, {0x7232,0x4E3A}, {0x723A,0x7237}, {0x723E,0x5C14}, 
+  {0x7258,0x724D}, {0x727D,0x7275}, {0x7296,0x8366}, {0x72A2,0x728A}, {0x72A7,0x727A}, 
+  {0x72C0,0x72B6}, {0x72F9,0x72ED}, {0x72FD,0x72C8}, {0x7319,0x72F0}, {0x7336,0x72B9}, 
+  {0x733B,0x72F2}, {0x7341,0x72B8}, {0x7344,0x72F1}, {0x7345,0x72EE}, {0x7368,0x72EC}, 
+  {0x736A,0x72EF}, {0x736B,0x7303}, {0x7370,0x72DE}, {0x7372,0x83B7}, {0x7375,0x730E}, 
+  {0x7377,0x72B7}, {0x7378,0x517D}, {0x737A,0x736D}, {0x737B,0x732E}, {0x737C,0x7315}, 
+  {0x7380,0x7321}, {0x73FE,0x73B0}, {0x743F,0x73F2}, {0x744B,0x73AE}, {0x7463,0x7410}, 
+  {0x7469,0x83B9}, {0x746A,0x739B}, {0x7489,0x740F}, {0x74A3,0x7391}, {0x74A6,0x7477}, 
+  {0x74B0,0x73AF}, {0x74BD,0x73BA}, {0x74CA,0x743C}, {0x74CF,0x73D1}, {0x74D4,0x748E}, 
+  {0x74DA,0x74D2}, {0x750C,0x74EF}, {0x7523,0x4EA7}, {0x755D,0x4EA9}, {0x7562,0x6BD5}, 
+  {0x756B,0x753B}, {0x7576,0x5F53}, {0x7587,0x7574}, {0x758A,0x53E0}, {0x75D9,0x75C9}, 
+  {0x7602,0x75D6}, {0x760B,0x75AF}, {0x760D,0x75A1}, {0x7613,0x75EA}, {0x761E,0x7617}, 
+  {0x7621,0x75AE}, {0x7627,0x759F}, {0x763B,0x7618}, {0x7642,0x7597}, {0x7646,0x75E8}, 
+  {0x7647,0x75EB}, {0x7649,0x7605}, {0x7658,0x75A0}, {0x765F,0x762A}, {0x7662,0x75D2}, 
+  {0x7664,0x7596}, {0x7665,0x75C7}, {0x7667,0x75AC}, {0x7669,0x765E}, {0x766C,0x7663}, 
+  {0x766D,0x763F}, {0x766E,0x763E}, {0x7670,0x75C8}, {0x7671,0x762B}, {0x7672,0x766B}, 
+  {0x767C,0x53D1}, {0x769A,0x7691}, {0x76B8,0x76B2}, {0x76BA,0x76B1}, {0x76DE,0x76CF}, 
+  {0x76E1,0x5C3D}, {0x76E3,0x76D1}, {0x76E4,0x76D8}, {0x76E7,0x5362}, {0x775C,0x7741}, 
+  {0x775E,0x7750}, {0x7798,0x770D}, {0x779E,0x7792}, {0x77BC,0x7751}, {0x77DA,0x77A9}, 
+  {0x77EF,0x77EB}, {0x7864,0x7856}, {0x7868,0x7817}, {0x786F,0x781A}, {0x78A9,0x7855}, 
+  {0x78AD,0x7800}, {0x78B8,0x781C}, {0x78BA,0x786E}, {0x78BC,0x7801}, {0x78DA,0x7816}, 
+  {0x78E3,0x789C}, {0x78E7,0x789B}, {0x78EF,0x77F6}, {0x78FD,0x7857}, {0x790E,0x7840}, 
+  {0x7919,0x788D}, {0x7926,0x77FF}, {0x792A,0x783A}, {0x792B,0x783E}, {0x792C,0x77FE}, 
+  {0x7931,0x783B}, {0x798D,0x7978}, {0x798E,0x796F}, {0x79AA,0x7985}, {0x79AE,0x793C}, 
+  {0x79B0,0x7962}, {0x79B1,0x7977}, {0x7A2E,0x79CD}, {0x7A31,0x79F0}, {0x7A4C,0x7A23}, 
+  {0x7A4D,0x79EF}, {0x7A4E,0x9896}, {0x7A61,0x7A51}, {0x7A62,0x79FD}, {0x7A69,0x7A33}, 
+  {0x7AA9,0x7A9D}, {0x7AAA,0x6D3C}, {0x7AAE,0x7A77}, {0x7AB6,0x7AAD}, {0x7ABA,0x7AA5}, 
+  {0x7AC4,0x7A9C}, {0x7AC5,0x7A8D}, {0x7AC7,0x7AA6}, {0x7AC8,0x7076}, {0x7ACA,0x7A83}, 
+  {0x7AEA,0x7AD6}, {0x7AF6,0x7ADE}, {0x7B46,0x7B14}, {0x7B67,0x7B15}, {0x7B8B,0x7B3A}, 
+  {0x7B8F,0x7B5D}, {0x7BC0,0x8282}, {0x7BC4,0x8303}, {0x7BC9,0x7B51}, {0x7BCB,0x7BA7}, 
+  {0x7BE4,0x7B03}, {0x7BE9,0x7B5B}, {0x7BF3,0x7B5A}, {0x7C00,0x7BA6}, {0x7C0D,0x7BD3}, 
+  {0x7C1E,0x7BAA}, {0x7C21,0x7B80}, {0x7C23,0x7BD1}, {0x7C2B,0x7BAB}, {0x7C3D,0x7B7E}, 
+  {0x7C3E,0x5E18}, {0x7C43,0x7BEE}, {0x7C4C,0x7B79}, {0x7C5C,0x7BA8}, {0x7C5F,0x7C41}, 
+  {0x7C60,0x7B3C}, {0x7C69,0x7B3E}, {0x7C6A,0x7C16}, {0x7C6C,0x7BF1}, {0x7C6E,0x7BA9}, 
+  {0x7CDD,0x7CC1}, {0x7CDE,0x7CAA}, {0x7CE7,0x7CAE}, {0x7CF2,0x7C9D}, {0x7CF4,0x7C74}, 
+  {0x7CF6,0x7C9C}, {0x7CF9,0x7E9F}, {0x7CFE,0x7EA0}, {0x7D00,0x7EAA}, {0x7D02,0x7EA3}, 
+  {0x7D04,0x7EA6}, {0x7D05,0x7EA2}, {0x7D06,0x7EA1}, {0x7D07,0x7EA5}, {0x7D08,0x7EA8}, 
+  {0x7D09,0x7EAB}, {0x7D0B,0x7EB9}, {0x7D0D,0x7EB3}, {0x7D10,0x7EBD}, {0x7D13,0x7EBE}, 
+  {0x7D14,0x7EAF}, {0x7D15,0x7EB0}, {0x7D17,0x7EB1}, {0x7D19,0x7EB8}, {0x7D1A,0x7EA7}, 
+  {0x7D1B,0x7EB7}, {0x7D1C,0x7EAD}, {0x7D21,0x7EBA}, {0x7D30,0x7EC6}, {0x7D31,0x7EC2}, 
+  {0x7D32,0x7EC1}, {0x7D33,0x7EC5}, {0x7D39,0x7ECD}, {0x7D3A,0x7EC0}, {0x7D3C,0x7ECB}, 
+  {0x7D3F,0x7ED0}, {0x7D40,0x7ECC}, {0x7D42,0x7EC8}, {0x7D44,0x7EC4}, {0x7D46,0x7ECA}, 
+  {0x7D4E,0x7ED7}, {0x7D50,0x7ED3}, {0x7D5D,0x7ED4}, {0x7D5E,0x7EDE}, {0x7D61,0x7EDC}, 
+  {0x7D62,0x7EDA}, {0x7D66,0x7ED9}, {0x7D68,0x7ED2}, {0x7D71,0x7EDF}, {0x7D72,0x4E1D}, 
+  {0x7D73,0x7EDB}, {0x7D76,0x7EDD}, {0x7D79,0x7EE2}, {0x7D81,0x7ED1}, {0x7D83,0x7EE1}, 
+  {0x7D86,0x7EE0}, {0x7D88,0x7EE8}, {0x7D89,0x7EE3}, {0x7D8F,0x7EE5}, {0x7D93,0x7ECF}, 
+  {0x7D9C,0x7EFC}, {0x7D9E,0x7F0D}, {0x7DA2,0x7EF8}, {0x7DA3,0x7EFB}, {0x7DAB,0x7EBF}, 
+  {0x7DAC,0x7EF6}, {0x7DAD,0x7EF4}, {0x7DB0,0x7EFE}, {0x7DB1,0x7EB2}, {0x7DB2,0x7F51}, 
+  {0x7DB3,0x7EF7}, {0x7DB4,0x7F00}, {0x7DB8,0x7EB6}, {0x7DB9,0x7EFA}, {0x7DBA,0x7EEE}, 
+  {0x7DBB,0x7EFD}, {0x7DBD,0x7EF0}, {0x7DBE,0x7EEB}, {0x7DBF,0x7EF5}, {0x7DC4,0x7EF2}, 
+  {0x7DC7,0x7F01}, {0x7DCA,0x7D27}, {0x7DCB,0x7EEF}, {0x7DD1,0x7EFF}, {0x7DD2,0x7EEA}, 
+  {0x7DD4,0x7EF1}, {0x7DD7,0x7F03}, {0x7DD8,0x7F04}, {0x7DD9,0x7F02}, {0x7DDD,0x7F09}, 
+  {0x7DDE,0x7F0E}, {0x7DE0,0x7F14}, {0x7DE1,0x7F17}, {0x7DE3,0x7F18}, {0x7DE6,0x7F0C}, 
+  {0x7DE8,0x7F16}, {0x7DE9,0x7F13}, {0x7DEC,0x7F05}, {0x7DEF,0x7EAC}, {0x7DF1,0x7F11}, 
+  {0x7DF2,0x7F08}, {0x7DF4,0x7EC3}, {0x7DF6,0x7F0F}, {0x7DF9,0x7F07}, {0x7E08,0x8426}, 
+  {0x7E09,0x7F19}, {0x7E0A,0x7F22}, {0x7E0B,0x7F12}, {0x7E10,0x7EC9}, {0x7E11,0x7F23}, 
+  {0x7E1B,0x7F1A}, {0x7E1D,0x7F1C}, {0x7E1E,0x7F1F}, {0x7E1F,0x7F1B}, {0x7E23,0x53BF}, 
+  {0x7E27,0x7EE6}, {0x7E2B,0x7F1D}, {0x7E2D,0x7F21}, {0x7E2E,0x7F29}, {0x7E31,0x7EB5}, 
+  {0x7E32,0x7F27}, {0x7E35,0x7F26}, {0x7E36,0x7D77}, {0x7E37,0x7F15}, {0x7E39,0x7F25}, 
+  {0x7E3D,0x603B}, {0x7E3E,0x7EE9}, {0x7E45,0x7F2B}, {0x7E46,0x7F2A}, {0x7E52,0x7F2F}, 
+  {0x7E54,0x7EC7}, {0x7E55,0x7F2E}, {0x7E5A,0x7F2D}, {0x7E5E,0x7ED5}, {0x7E62,0x7F0B}, 
+  {0x7E69,0x7EF3}, {0x7E6A,0x7ED8}, {0x7E6D,0x8327}, {0x7E6E,0x7F30}, {0x7E6F,0x7F33}, 
+  {0x7E70,0x7F32}, {0x7E73,0x7F34}, {0x7E79,0x7ECE}, {0x7E7C,0x7EE7}, {0x7E7D,0x7F24}, 
+  {0x7E7E,0x7F31}, {0x7E88,0x7F2C}, {0x7E8A,0x7EA9}, {0x7E8C,0x7EED}, {0x7E8F,0x7F20}, 
+  {0x7E93,0x7F28}, {0x7E96,0x7EA4}, {0x7E98,0x7F35}, {0x7E9C,0x7F06}, {0x7F4C,0x7F42}, 
+  {0x7F70,0x7F5A}, {0x7F77,0x7F62}, {0x7F85,0x7F57}, {0x7F86,0x7F74}, {0x7F88,0x7F81}, 
+  {0x7FA5,0x7F9F}, {0x7FA9,0x4E49}, {0x7FD2,0x4E60}, {0x7FF9,0x7FD8}, {0x802C,0x8027}, 
+  {0x802E,0x8022}, {0x8056,0x5723}, {0x805E,0x95FB}, {0x806F,0x8054}, {0x8070,0x806A}, 
+  {0x8072,0x58F0}, {0x8073,0x8038}, {0x8075,0x8069}, {0x8076,0x8042}, {0x8077,0x804C}, 
+  {0x8079,0x804D}, {0x807D,0x542C}, {0x807E,0x804B}, {0x8085,0x8083}, {0x8105,0x80C1}, 
+  {0x811B,0x80EB}, {0x8139,0x80C0}, {0x814E,0x80BE}, {0x8156,0x80E8}, {0x8161,0x8136}, 
+  {0x8166,0x8111}, {0x816B,0x80BF}, {0x8178,0x80A0}, {0x819A,0x80A4}, {0x81A0,0x80F6}, 
+  {0x81A9,0x817B}, {0x81BD,0x80C6}, {0x81BE,0x810D}, {0x81BF,0x8113}, {0x81C9,0x8138}, 
+  {0x81CD,0x8110}, {0x81CF,0x8191}, {0x81D8,0x814A}, {0x81DA,0x80EA}, {0x81DF,0x810F}, 
+  {0x81E0,0x8114}, {0x81E8,0x4E34}, {0x81FA,0x53F0}, {0x8207,0x4E0E}, {0x8208,0x5174}, 
+  {0x8209,0x4E3E}, {0x820A,0x65E7}, {0x8259,0x8231}, {0x8264,0x8223}, {0x8266,0x8230}, 
+  {0x826B,0x823B}, {0x8271,0x8270}, {0x8277,0x8273}, {0x82BB,0x520D}, {0x82E7,0x82CE}, 
+  {0x838A,0x5E84}, {0x8396,0x830E}, {0x83A2,0x835A}, {0x83A7,0x82CB}, {0x83EF,0x534E}, 
+  {0x8407,0x82CC}, {0x840A,0x83B1}, {0x842C,0x4E07}, {0x8435,0x83B4}, {0x8449,0x53F6}, 
+  {0x8452,0x836D}, {0x8464,0x836E}, {0x8466,0x82C7}, {0x8477,0x8364}, {0x8493,0x83BC}, 
+  {0x8494,0x83B3}, {0x84BC,0x82CD}, {0x84C0,0x836A}, {0x84CB,0x76D6}, {0x84EE,0x83B2}, 
+  {0x84EF,0x82C1}, {0x84FD,0x835C}, {0x851E,0x848C}, {0x8523,0x848B}, {0x8526,0x8311}, 
+  {0x852D,0x836B}, {0x8541,0x8368}, {0x8546,0x8487}, {0x854E,0x835E}, {0x8552,0x836C}, 
+  {0x8553,0x82B8}, {0x8555,0x83B8}, {0x8558,0x835B}, {0x8562,0x8489}, {0x8569,0x8361}, 
+  {0x856A,0x829C}, {0x856D,0x8427}, {0x8577,0x84E3}, {0x8588,0x835F}, {0x858A,0x84DF}, 
+  {0x858C,0x8297}, {0x8594,0x8537}, {0x859F,0x83B6}, {0x85A6,0x8350}, {0x85A9,0x8428}, 
+  {0x85BA,0x8360}, {0x85CD,0x84DD}, {0x85CE,0x8369}, {0x85DD,0x827A}, {0x85E5,0x836F}, 
+  {0x85EA,0x85AE}, {0x85F4,0x8574}, {0x85F6,0x82C8}, {0x85F9,0x853C}, {0x85FA,0x853A}, 
+  {0x8604,0x8572}, {0x8606,0x82A6}, {0x8607,0x82CF}, {0x860B,0x82F9}, {0x861A,0x85D3}, 
+  {0x861E,0x8539}, {0x8622,0x830F}, {0x862D,0x5170}, {0x863A,0x84E0}, {0x863F,0x841D}, 
+  {0x8655,0x5904}, {0x865C,0x864F}, {0x865F,0x53F7}, {0x8667,0x4E8F}, {0x86FA,0x86F1}, 
+  {0x8706,0x86AC}, {0x8755,0x8680}, {0x8766,0x867E}, {0x8778,0x8717}, {0x8784,0x86F3}, 
+  {0x879E,0x8682}, {0x87A2,0x8424}, {0x87BB,0x877C}, {0x87C4,0x86F0}, {0x87C8,0x8748}, 
+  {0x87CE,0x87A8}, {0x87E3,0x866E}, {0x87EC,0x8749}, {0x87EF,0x86F2}, {0x87F2,0x866B}, 
+  {0x87F6,0x86CF}, {0x87FB,0x8681}, {0x8805,0x8747}, {0x8806,0x867F}, {0x8810,0x86F4}, 
+  {0x8811,0x877E}, {0x881F,0x8721}, {0x8823,0x86CE}, {0x8831,0x86CA}, {0x8836,0x8695}, 
+  {0x883B,0x86EE}, {0x8846,0x4F17}, {0x8853,0x672F}, {0x885B,0x536B}, {0x885D,0x51B2}, 
+  {0x8879,0x53EA}, {0x88CA,0x8885}, {0x88CF,0x91CC}, {0x88DC,0x8865}, {0x88DD,0x88C5}, 
+  {0x8932,0x88E4}, {0x8933,0x88E2}, {0x8938,0x891B}, {0x893B,0x4EB5}, {0x8947,0x88E5}, 
+  {0x8956,0x8884}, {0x895D,0x88E3}, {0x8960,0x88C6}, {0x8964,0x8934}, {0x896A,0x889C}, 
+  {0x896F,0x886C}, {0x8972,0x88AD}, {0x898B,0x89C1}, {0x898F,0x89C4}, {0x8993,0x89C5}, 
+  {0x8996,0x89C6}, {0x8998,0x89C7}, {0x89A1,0x89CB}, {0x89A6,0x89CE}, {0x89AA,0x4EB2}, 
+  {0x89AC,0x89CA}, {0x89AF,0x89CF}, {0x89B2,0x89D0}, {0x89B7,0x89D1}, {0x89BA,0x89C9}, 
+  {0x89BD,0x89C8}, {0x89BF,0x89CC}, {0x89C0,0x89C2}, {0x89F4,0x89DE}, {0x89F6,0x89EF}, 
+  {0x89F8,0x89E6}, {0x8A01,0x8BA0}, {0x8A02,0x8BA2}, {0x8A03,0x8BA3}, {0x8A08,0x8BA1}, 
+  {0x8A0A,0x8BAF}, {0x8A0C,0x8BA7}, {0x8A0E,0x8BA8}, {0x8A10,0x8BA6}, {0x8A13,0x8BAD}, 
+  {0x8A15,0x8BAA}, {0x8A16,0x8BAB}, {0x8A18,0x8BB0}, {0x8A1B,0x8BB9}, {0x8A1D,0x8BB6}, 
+  {0x8A1F,0x8BBC}, {0x8A23,0x8BC0}, {0x8A25,0x8BB7}, {0x8A2A,0x8BBF}, {0x8A2D,0x8BBE}, 
+  {0x8A31,0x8BB8}, {0x8A34,0x8BC9}, {0x8A36,0x8BC3}, {0x8A3A,0x8BCA}, {0x8A41,0x8BC2}, 
+  {0x8A46,0x8BCB}, {0x8A4E,0x8BB5}, {0x8A50,0x8BC8}, {0x8A52,0x8BD2}, {0x8A54,0x8BCF}, 
+  {0x8A55,0x8BC4}, {0x8A58,0x8BCE}, {0x8A5B,0x8BC5}, {0x8A5E,0x8BCD}, {0x8A61,0x8BE9}, 
+  {0x8A62,0x8BE2}, {0x8A63,0x8BE3}, {0x8A66,0x8BD5}, {0x8A69,0x8BD7}, {0x8A6B,0x8BE7}, 
+  {0x8A6C,0x8BDF}, {0x8A6D,0x8BE1}, {0x8A6E,0x8BE0}, {0x8A70,0x8BD8}, {0x8A71,0x8BDD}, 
+  {0x8A72,0x8BE5}, {0x8A73,0x8BE6}, {0x8A75,0x8BDC}, {0x8A7C,0x8BD9}, {0x8A7F,0x8BD6}, 
+  {0x8A84,0x8BD4}, {0x8A85,0x8BDB}, {0x8A86,0x8BD3}, {0x8A87,0x5938}, {0x8A8D,0x8BA4}, 
+  {0x8A91,0x8BF3}, {0x8A92,0x8BF6}, {0x8A95,0x8BDE}, {0x8A98,0x8BF1}, {0x8A9A,0x8BEE}, 
+  {0x8A9E,0x8BED}, {0x8AA0,0x8BDA}, {0x8AA1,0x8BEB}, {0x8AA3,0x8BEC}, {0x8AA4,0x8BEF}, 
+  {0x8AA5,0x8BF0}, {0x8AA6,0x8BF5}, {0x8AA8,0x8BF2}, {0x8AAC,0x8BF4}, {0x8AB0,0x8C01}, 
+  {0x8AB2,0x8BFE}, {0x8AB6,0x8C07}, {0x8AB9,0x8BFD}, {0x8ABC,0x8C0A}, {0x8ABF,0x8C03}, 
+  {0x8AC2,0x8C04}, {0x8AC4,0x8C06}, {0x8AC7,0x8C08}, {0x8AC9,0x8BFF}, {0x8ACB,0x8BF7}, 
+  {0x8ACD,0x8BE4}, {0x8ACF,0x8BF9}, {0x8AD1,0x8BFC}, {0x8AD2,0x8C05}, {0x8AD6,0x8BBA}, 
+  {0x8AD7,0x8C02}, {0x8ADB,0x8C00}, {0x8ADC,0x8C0D}, {0x8ADE,0x8C1D}, {0x8AE2,0x8BE8}, 
+  {0x8AE4,0x8C14}, {0x8AE6,0x8C1B}, {0x8AE7,0x8C10}, {0x8AEB,0x8C0F}, {0x8AED,0x8C15}, 
+  {0x8AEE,0x8C18}, {0x8AF1,0x8BB3}, {0x8AF3,0x8C19}, {0x8AF6,0x8C0C}, {0x8AF7,0x8BBD}, 
+  {0x8AF8,0x8BF8}, {0x8AFA,0x8C1A}, {0x8AFC,0x8C16}, {0x8AFE,0x8BFA}, {0x8B00,0x8C0B}, 
+  {0x8B01,0x8C12}, {0x8B02,0x8C13}, {0x8B04,0x8A8A}, {0x8B05,0x8BCC}, {0x8B0A,0x8C0E}, 
+  {0x8B0E,0x8C1C}, {0x8B10,0x8C27}, {0x8B14,0x8C11}, {0x8B16,0x8C21}, {0x8B17,0x8C24}, 
+  {0x8B19,0x8C26}, {0x8B1A,0x8C25}, {0x8B1B,0x8BB2}, {0x8B1D,0x8C22}, {0x8B21,0x8C23}, 
+  {0x8B28,0x8C1F}, {0x8B2B,0x8C2A}, {0x8B2C,0x8C2C}, {0x8B2D,0x8C2B}, {0x8B33,0x8BB4}, 
+  {0x8B39,0x8C28}, {0x8B3E,0x8C29}, {0x8B49,0x8BC1}, {0x8B4E,0x8C32}, {0x8B4F,0x8BA5}, 
+  {0x8B56,0x8C2E}, {0x8B58,0x8BC6}, {0x8B59,0x8C2F}, {0x8B5A,0x8C2D}, {0x8B5C,0x8C31}, 
+  {0x8B6B,0x8C35}, {0x8B6F,0x8BD1}, {0x8B70,0x8BAE}, {0x8B74,0x8C34}, {0x8B77,0x62A4}, 
+  {0x8B7D,0x8A89}, {0x8B80,0x8BFB}, {0x8B8A,0x53D8}, {0x8B8E,0x96E0}, {0x8B92,0x8C17}, 
+  {0x8B93,0x8BA9}, {0x8B95,0x8C30}, {0x8B96,0x8C36}, {0x8B9C,0x8C20}, {0x8B9E,0x8C33}, 
+  {0x8C48,0x5C82}, {0x8C50,0x4E30}, {0x8C9D,0x8D1D}, {0x8C9E,0x8D1E}, {0x8CA0,0x8D1F}, 
+  {0x8CA1,0x8D22}, {0x8CA2,0x8D21}, {0x8CA7,0x8D2B}, {0x8CA8,0x8D27}, {0x8CA9,0x8D29}, 
+  {0x8CAA,0x8D2A}, {0x8CAB,0x8D2F}, {0x8CAC,0x8D23}, {0x8CAF,0x8D2E}, {0x8CB0,0x8D33}, 
+  {0x8CB2,0x8D40}, {0x8CB3,0x8D30}, {0x8CB4,0x8D35}, {0x8CB6,0x8D2C}, {0x8CB7,0x4E70}, 
+  {0x8CB8,0x8D37}, {0x8CBA,0x8D36}, {0x8CBB,0x8D39}, {0x8CBC,0x8D34}, {0x8CBD,0x8D3B}, 
+  {0x8CBF,0x8D38}, {0x8CC0,0x8D3A}, {0x8CC1,0x8D32}, {0x8CC2,0x8D42}, {0x8CC3,0x8D41}, 
+  {0x8CC4,0x8D3F}, {0x8CC5,0x8D45}, {0x8CC7,0x8D44}, {0x8CC8,0x8D3E}, {0x8CCA,0x8D3C}, 
+  {0x8CD1,0x8D48}, {0x8CD2,0x8D4A}, {0x8CD3,0x5BBE}, {0x8CD5,0x8D47}, {0x8CDA,0x8D49}, 
+  {0x8CDC,0x8D50}, {0x8CDE,0x8D4F}, {0x8CE0,0x8D54}, {0x8CE1,0x8D53}, {0x8CE2,0x8D24}, 
+  {0x8CE3,0x5356}, {0x8CE4,0x8D31}, {0x8CE6,0x8D4B}, {0x8CE7,0x8D55}, {0x8CEA,0x8D28}, 
+  {0x8CEB,0x8D4D}, {0x8CEC,0x8D26}, {0x8CED,0x8D4C}, {0x8CF4,0x8D56}, {0x8CFA,0x8D5A}, 
+  {0x8CFB,0x8D59}, {0x8CFC,0x8D2D}, {0x8CFD,0x8D5B}, {0x8CFE,0x8D5C}, {0x8D04,0x8D3D}, 
+  {0x8D05,0x8D58}, {0x8D08,0x8D60}, {0x8D0A,0x8D5E}, {0x8D0B,0x8D5D}, {0x8D0D,0x8D61}, 
+  {0x8D0F,0x8D62}, {0x8D10,0x8D46}, {0x8D16,0x8D4E}, {0x8D1B,0x8D63}, {0x8D1C,0x8D43}, 
+  {0x8D95,0x8D76}, {0x8D99,0x8D75}, {0x8DA8,0x8D8B}, {0x8DB2,0x8DB1}, {0x8E10,0x8DF5}, 
+  {0x8E34,0x8E0A}, {0x8E4C,0x8DC4}, {0x8E55,0x8DF8}, {0x8E63,0x8E52}, {0x8E7A,0x8DF7}, 
+  {0x8E89,0x8DB8}, {0x8E8A,0x8E0C}, {0x8E8B,0x8DFB}, {0x8E8D,0x8DC3}, {0x8E91,0x8E2F}, 
+  {0x8E92,0x8DDE}, {0x8E93,0x8E2C}, {0x8E9A,0x8DF9}, {0x8EA1,0x8E51}, {0x8EA5,0x8E7F}, 
+  {0x8EA6,0x8E9C}, {0x8EAA,0x8E8F}, {0x8EC0,0x8EAF}, {0x8ECA,0x8F66}, {0x8ECB,0x8F67}, 
+  {0x8ECC,0x8F68}, {0x8ECD,0x519B}, {0x8ED2,0x8F69}, {0x8ED4,0x8F6B}, {0x8EDB,0x8F6D}, 
+  {0x8EDF,0x8F6F}, {0x8EE4,0x8F77}, {0x8EEB,0x8F78}, {0x8EF2,0x8F71}, {0x8EF8,0x8F74}, 
+  {0x8EF9,0x8F75}, {0x8EFA,0x8F7A}, {0x8EFB,0x8F72}, {0x8EFC,0x8F76}, {0x8EFE,0x8F7C}, 
+  {0x8F03,0x8F83}, {0x8F05,0x8F82}, {0x8F07,0x8F81}, {0x8F09,0x8F7D}, {0x8F0A,0x8F7E}, 
+  {0x8F12,0x8F84}, {0x8F14,0x8F85}, {0x8F15,0x8F7B}, {0x8F1B,0x8F86}, {0x8F1C,0x8F8E}, 
+  {0x8F1D,0x8F89}, {0x8F1E,0x8F8B}, {0x8F1F,0x8F8D}, {0x8F25,0x8F8A}, {0x8F26,0x8F87}, 
+  {0x8F29,0x8F88}, {0x8F2A,0x8F6E}, {0x8F2F,0x8F91}, {0x8F33,0x8F8F}, {0x8F38,0x8F93}, 
+  {0x8F3B,0x8F90}, {0x8F3E,0x8F97}, {0x8F3F,0x8206}, {0x8F42,0x6BC2}, {0x8F44,0x8F96}, 
+  {0x8F45,0x8F95}, {0x8F46,0x8F98}, {0x8F49,0x8F6C}, {0x8F4D,0x8F99}, {0x8F4E,0x8F7F}, 
+  {0x8F54,0x8F9A}, {0x8F5F,0x8F70}, {0x8F61,0x8F94}, {0x8F62,0x8F79}, {0x8F64,0x8F73}, 
+  {0x8FA6,0x529E}, {0x8FAD,0x8F9E}, {0x8FAE,0x8FAB}, {0x8FAF,0x8FA9}, {0x8FB2,0x519C}, 
+  {0x9015,0x8FF3}, {0x9019,0x8FD9}, {0x9023,0x8FDE}, {0x9032,0x8FDB}, {0x904B,0x8FD0}, 
+  {0x904E,0x8FC7}, {0x9054,0x8FBE}, {0x9055,0x8FDD}, {0x905C,0x900A}, {0x905E,0x9012}, 
+  {0x9060,0x8FDC}, {0x9069,0x9002}, {0x9072,0x8FDF}, {0x9077,0x8FC1}, {0x9078,0x9009}, 
+  {0x907A,0x9057}, {0x907C,0x8FBD}, {0x9081,0x8FC8}, {0x9084,0x8FD8}, {0x9087,0x8FE9}, 
+  {0x908A,0x8FB9}, {0x908F,0x903B}, {0x9090,0x9026}, {0x90DF,0x90CF}, {0x90F5,0x90AE}, 
+  {0x9106,0x90D3}, {0x9109,0x4E61}, {0x9112,0x90B9}, {0x9114,0x90AC}, {0x9116,0x90E7}, 
+  {0x9127,0x9093}, {0x912D,0x90D1}, {0x9130,0x90BB}, {0x9132,0x90F8}, {0x9134,0x90BA}, 
+  {0x9136,0x90D0}, {0x913A,0x909D}, {0x9148,0x90E6}, {0x9196,0x915D}, {0x919C,0x4E11}, 
+  {0x91AB,0x533B}, {0x91AC,0x9171}, {0x91C0,0x917F}, {0x91C1,0x8845}, {0x91C3,0x917E}, 
+  {0x91C5,0x917D}, {0x91CB,0x91CA}, {0x91D2,0x9485}, {0x91D3,0x9486}, {0x91D4,0x9487}, 
+  {0x91D5,0x948C}, {0x91D7,0x948A}, {0x91D8,0x9489}, {0x91D9,0x948B}, {0x91DD,0x9488}, 
+  {0x91E3,0x9493}, {0x91E4,0x9490}, {0x91E7,0x948F}, {0x91E9,0x9492}, {0x91F5,0x9497}, 
+  {0x91F7,0x948D}, {0x91F9,0x9495}, {0x91FA,0x948E}, {0x9200,0x94AF}, {0x9201,0x94AB}, 
+  {0x9204,0x94AD}, {0x9208,0x949A}, {0x9209,0x94A0}, {0x920D,0x949D}, {0x920E,0x94A9}, 
+  {0x9210,0x94A4}, {0x9211,0x94A3}, {0x9214,0x949E}, {0x9215,0x94AE}, {0x921E,0x94A7}, 
+  {0x9223,0x9499}, {0x9225,0x94AC}, {0x9226,0x949B}, {0x9227,0x94AA}, {0x922E,0x94CC}, 
+  {0x9230,0x94C8}, {0x9233,0x94B6}, {0x9234,0x94C3}, {0x9237,0x94B4}, {0x9238,0x94B9}, 
+  {0x9239,0x94CD}, {0x923A,0x94B0}, {0x923D,0x94B8}, {0x923E,0x94C0}, {0x923F,0x94BF}, 
+  {0x9240,0x94BE}, {0x9245,0x949C}, {0x9248,0x94CA}, {0x9249,0x94C9}, {0x924D,0x94CB}, 
+  {0x9251,0x94C2}, {0x9255,0x94B7}, {0x9257,0x94B3}, {0x925A,0x94C6}, {0x925B,0x94C5}, 
+  {0x925E,0x94BA}, {0x9262,0x94B5}, {0x9266,0x94B2}, {0x926C,0x94BC}, {0x926D,0x94BD}, 
+  {0x9278,0x94F0}, {0x927A,0x94D2}, {0x927B,0x94EC}, {0x927F,0x94EA}, {0x9280,0x94F6}, 
+  {0x9283,0x94F3}, {0x9285,0x94DC}, {0x9291,0x94E3}, {0x9293,0x94E8}, {0x9296,0x94E2}, 
+  {0x9298,0x94ED}, {0x929A,0x94EB}, {0x929C,0x8854}, {0x92A0,0x94D1}, {0x92A3,0x94F7}, 
+  {0x92A5,0x94F1}, {0x92A6,0x94DF}, {0x92A8,0x94F5}, {0x92A9,0x94E5}, {0x92AA,0x94D5}, 
+  {0x92AB,0x94EF}, {0x92AC,0x94D0}, {0x92B1,0x94DE}, {0x92B7,0x9500}, {0x92B9,0x9508}, 
+  {0x92BB,0x9511}, {0x92BC,0x9509}, {0x92C1,0x94DD}, {0x92C3,0x9512}, {0x92C5,0x950C}, 
+  {0x92C7,0x94A1}, {0x92CC,0x94E4}, {0x92CF,0x94D7}, {0x92D2,0x950B}, {0x92DD,0x950A}, 
+  {0x92DF,0x9513}, {0x92E3,0x94D8}, {0x92E4,0x9504}, {0x92E5,0x9503}, {0x92E6,0x9514}, 
+  {0x92E8,0x9507}, {0x92EA,0x94FA}, {0x92ED,0x9510}, {0x92EE,0x94D6}, {0x92EF,0x9506}, 
+  {0x92F0,0x9502}, {0x92F1,0x94FD}, {0x92F6,0x950D}, {0x92F8,0x952F}, {0x92FC,0x94A2}, 
+  {0x9301,0x951E}, {0x9306,0x9516}, {0x9307,0x952B}, {0x9308,0x9529}, {0x9310,0x9525}, 
+  {0x9312,0x9515}, {0x9315,0x951F}, {0x9318,0x9524}, {0x9319,0x9531}, {0x931A,0x94EE}, 
+  {0x931B,0x951B}, {0x931F,0x952C}, {0x9320,0x952D}, {0x9322,0x94B1}, {0x9326,0x9526}, 
+  {0x9328,0x951A}, {0x932B,0x9521}, {0x932E,0x9522}, {0x932F,0x9519}, {0x9332,0x5F55}, 
+  {0x9333,0x9530}, {0x9338,0x94FC}, {0x9340,0x951D}, {0x9341,0x9528}, {0x9343,0x952A}, 
+  {0x9346,0x9494}, {0x9347,0x9534}, {0x934B,0x9505}, {0x934D,0x9540}, {0x9354,0x9537}, 
+  {0x9358,0x94E1}, {0x935B,0x953B}, {0x9364,0x9538}, {0x9365,0x9532}, {0x9369,0x9518}, 
+  {0x936C,0x9539}, {0x9370,0x953E}, {0x9375,0x952E}, {0x9376,0x9536}, {0x937A,0x9517}, 
+  {0x937E,0x953A}, {0x9382,0x9541}, {0x9384,0x953F}, {0x9387,0x9545}, {0x938A,0x9551}, 
+  {0x9396,0x9501}, {0x9398,0x9549}, {0x93A2,0x94A8}, {0x93A3,0x84E5}, {0x93A6,0x954F}, 
+  {0x93A7,0x94E0}, {0x93A9,0x94E9}, {0x93AA,0x953C}, {0x93AC,0x9550}, {0x93AE,0x9547}, 
+  {0x93B0,0x9552}, {0x93B3,0x954D}, {0x93B5,0x9553}, {0x93B8,0x954C}, {0x93BF,0x954E}, 
+  {0x93C3,0x955E}, {0x93C7,0x955F}, {0x93C8,0x94FE}, {0x93CC,0x9546}, {0x93CD,0x9559}, 
+  {0x93D1,0x955D}, {0x93D7,0x94FF}, {0x93D8,0x9535}, {0x93DC,0x9557}, {0x93DD,0x9558}, 
+  {0x93DE,0x955B}, {0x93DF,0x94F2}, {0x93E1,0x955C}, {0x93E2,0x9556}, {0x93E4,0x9542}, 
+  {0x93E8,0x933E}, {0x93F5,0x94E7}, {0x93F7,0x9564}, {0x93F9,0x956A}, {0x9403,0x94D9}, 
+  {0x940B,0x94F4}, {0x9410,0x9563}, {0x9412,0x94F9}, {0x9413,0x9566}, {0x9414,0x9561}, 
+  {0x9418,0x949F}, {0x9419,0x956B}, {0x941D,0x9562}, {0x9420,0x9568}, {0x9426,0x950E}, 
+  {0x9427,0x950F}, {0x9428,0x9544}, {0x942E,0x9570}, {0x9432,0x956F}, {0x9433,0x956D}, 
+  {0x9435,0x94C1}, {0x9438,0x94CE}, {0x943A,0x94DB}, {0x943F,0x9571}, {0x9444,0x94F8}, 
+  {0x944A,0x956C}, {0x944C,0x9554}, {0x9452,0x9274}, {0x9454,0x9572}, {0x9460,0x94C4}, 
+  {0x9463,0x9573}, {0x9465,0x9565}, {0x946D,0x9567}, {0x9470,0x94A5}, {0x9472,0x9576}, 
+  {0x9477,0x954A}, {0x9479,0x9569}, {0x947C,0x9523}, {0x947D,0x94BB}, {0x947E,0x92AE}, 
+  {0x947F,0x51FF}, {0x9577,0x957F}, {0x9580,0x95E8}, {0x9582,0x95E9}, {0x9583,0x95EA}, 
+  {0x9586,0x95EB}, {0x9589,0x95ED}, {0x958B,0x5F00}, {0x958C,0x95F6}, {0x958E,0x95F3}, 
+  {0x958F,0x95F0}, {0x9591,0x95F2}, {0x9593,0x95F4}, {0x9594,0x95F5}, {0x9598,0x95F8}, 
+  {0x95A1,0x9602}, {0x95A3,0x9601}, {0x95A5,0x9600}, {0x95A8,0x95FA}, {0x95A9,0x95FD}, 
+  {0x95AB,0x9603}, {0x95AC,0x9606}, {0x95AD,0x95FE}, {0x95B2,0x9605}, {0x95B6,0x960A}, 
+  {0x95B9,0x9609}, {0x95BB,0x960E}, {0x95BC,0x960F}, {0x95BD,0x960D}, {0x95BE,0x9608}, 
+  {0x95BF,0x960C}, {0x95C3,0x9612}, {0x95C8,0x95F1}, {0x95CA,0x9614}, {0x95CB,0x9615}, 
+  {0x95CC,0x9611}, {0x95D0,0x9617}, {0x95D4,0x9616}, {0x95D5,0x9619}, {0x95D6,0x95EF}, 
+  {0x95DC,0x5173}, {0x95DE,0x961A}, {0x95E1,0x9610}, {0x95E5,0x95FC}, {0x9658,0x9649}, 
+  {0x965D,0x9655}, {0x9663,0x9635}, {0x9670,0x9634}, {0x9673,0x9648}, {0x9678,0x9646}, 
+  {0x967D,0x9633}, {0x9689,0x9667}, {0x968A,0x961F}, {0x968E,0x9636}, {0x9695,0x9668}, 
+  {0x969B,0x9645}, {0x96A8,0x968F}, {0x96AA,0x9669}, {0x96B1,0x9690}, {0x96B4,0x9647}, 
+  {0x96B8,0x96B6}, {0x96D6,0x867D}, {0x96D9,0x53CC}, {0x96DB,0x96CF}, {0x96DC,0x6742}, 
+  {0x96E2,0x79BB}, {0x96E3,0x96BE}, {0x96F2,0x4E91}, {0x96FB,0x7535}, {0x9727,0x96FE}, 
+  {0x973D,0x9701}, {0x9742,0x96F3}, {0x9744,0x972D}, {0x9748,0x7075}, {0x975A,0x9753}, 
+  {0x975C,0x9759}, {0x9768,0x9765}, {0x978F,0x5DE9}, {0x97BD,0x9792}, {0x97C3,0x9791}, 
+  {0x97C9,0x97AF}, {0x97CB,0x97E6}, {0x97CC,0x97E7}, {0x97D3,0x97E9}, {0x97D9,0x97EA}, 
+  {0x97DC,0x97EC}, {0x97DE,0x97EB}, {0x97FF,0x54CD}, {0x9801,0x9875}, {0x9802,0x9876}, 
+  {0x9803,0x9877}, {0x9805,0x9879}, {0x9806,0x987A}, {0x9807,0x9878}, {0x9808,0x987B}, 
+  {0x980A,0x987C}, {0x980C,0x9882}, {0x980E,0x9880}, {0x980F,0x9883}, {0x9810,0x9884}, 
+  {0x9811,0x987D}, {0x9812,0x9881}, {0x9813,0x987F}, {0x9817,0x9887}, {0x9818,0x9886}, 
+  {0x981C,0x988C}, {0x9821,0x9889}, {0x9824,0x9890}, {0x9826,0x988F}, {0x982D,0x5934}, 
+  {0x9830,0x988A}, {0x9837,0x9894}, {0x9838,0x9888}, {0x983B,0x9891}, {0x983D,0x9893}, 
+  {0x9846,0x9897}, {0x984C,0x9898}, {0x984D,0x989D}, {0x984E,0x989A}, {0x9853,0x989B}, 
+  {0x9854,0x989C}, {0x9858,0x613F}, {0x9859,0x98A1}, {0x985B,0x98A0}, {0x985E,0x7C7B}, 
+  {0x9862,0x989F}, {0x9865,0x98A2}, {0x9867,0x987E}, {0x986B,0x98A4}, {0x986C,0x98A5}, 
+  {0x986F,0x663E}, {0x9870,0x98A6}, {0x9871,0x9885}, {0x9873,0x989E}, {0x9874,0x98A7}, 
+  {0x98A8,0x98CE}, {0x98AE,0x98D1}, {0x98AF,0x98D2}, {0x98B6,0x98D3}, {0x98BC,0x98D5}, 
+  {0x98C4,0x98D8}, {0x98C6,0x98D9}, {0x98C8,0x98DA}, {0x98DB,0x98DE}, {0x98E0,0x9963}, 
+  {0x98E9,0x9968}, {0x98EA,0x996A}, {0x98EB,0x996B}, {0x98ED,0x996C}, {0x98EF,0x996D}, 
+  {0x98F2,0x996E}, {0x98F4,0x9974}, {0x98FC,0x9972}, {0x98FD,0x9971}, {0x98FE,0x9970}, 
+  {0x9903,0x997A}, {0x9905,0x997C}, {0x9909,0x9977}, {0x990A,0x517B}, {0x990C,0x9975}, 
+  {0x9911,0x997D}, {0x9912,0x9981}, {0x9913,0x997F}, {0x9918,0x4F59}, {0x991B,0x9984}, 
+  {0x991E,0x996F}, {0x9921,0x9985}, {0x9928,0x9986}, {0x9933,0x9967}, {0x9937,0x9987}, 
+  {0x993C,0x9969}, {0x993E,0x998F}, {0x993F,0x998A}, {0x9943,0x998D}, {0x9945,0x9992}, 
+  {0x9948,0x9990}, {0x9949,0x9991}, {0x994A,0x9993}, {0x994B,0x9988}, {0x994C,0x9994}, 
+  {0x9951,0x9965}, {0x9952,0x9976}, {0x9957,0x98E8}, {0x995C,0x990D}, {0x995E,0x998B}, 
+  {0x9962,0x9995}, {0x99AC,0x9A6C}, {0x99AD,0x9A6D}, {0x99AE,0x51AF}, {0x99B1,0x9A6E}, 
+  {0x99B3,0x9A70}, {0x99B4,0x9A6F}, {0x99C1,0x9A73}, {0x99D0,0x9A7B}, {0x99D1,0x9A7D}, 
+  {0x99D2,0x9A79}, {0x99D4,0x9A75}, {0x99D5,0x9A7E}, {0x99D8,0x9A80}, {0x99D9,0x9A78}, 
+  {0x99DB,0x9A76}, {0x99DD,0x9A7C}, {0x99DF,0x9A77}, {0x99E1,0x9A82}, {0x99E2,0x9A88}, 
+  {0x99ED,0x9A87}, {0x99F1,0x9A86}, {0x99FF,0x9A8F}, {0x9A01,0x9A8B}, {0x9A05,0x9A93}, 
+  {0x9A0D,0x9A92}, {0x9A0E,0x9A91}, {0x9A0F,0x9A90}, {0x9A16,0x9A9B}, {0x9A19,0x9A97}, 
+  {0x9A2B,0x9A9E}, {0x9A2D,0x9A98}, {0x9A2E,0x9A9D}, {0x9A30,0x817E}, {0x9A36,0x9A7A}, 
+  {0x9A37,0x9A9A}, {0x9A38,0x9A9F}, {0x9A3E,0x9AA1}, {0x9A40,0x84E6}, {0x9A41,0x9A9C}, 
+  {0x9A42,0x9A96}, {0x9A43,0x9AA0}, {0x9A44,0x9AA2}, {0x9A45,0x9A71}, {0x9A4A,0x9A85}, 
+  {0x9A4D,0x9A81}, {0x9A4F,0x9AA3}, {0x9A55,0x9A84}, {0x9A57,0x9A8C}, {0x9A5A,0x60CA}, 
+  {0x9A5B,0x9A7F}, {0x9A5F,0x9AA4}, {0x9A62,0x9A74}, {0x9A64,0x9AA7}, {0x9A65,0x9AA5}, 
+  {0x9A6A,0x9A8A}, {0x9AAF,0x80AE}, {0x9ACF,0x9AC5}, {0x9AD4,0x4F53}, {0x9AD5,0x9ACC}, 
+  {0x9AD6,0x9ACB}, {0x9B06,0x677E}, {0x9B22,0x9B13}, {0x9B25,0x6597}, {0x9B27,0x95F9}, 
+  {0x9B29,0x960B}, {0x9B2E,0x9604}, {0x9B31,0x90C1}, {0x9B4E,0x9B49}, {0x9B58,0x9B47}, 
+  {0x9B5A,0x9C7C}, {0x9B6F,0x9C81}, {0x9B74,0x9C82}, {0x9B77,0x9C7F}, {0x9B81,0x9C85}, 
+  {0x9B83,0x9C86}, {0x9B8E,0x9C87}, {0x9B90,0x9C90}, {0x9B91,0x9C8D}, {0x9B92,0x9C8B}, 
+  {0x9B9A,0x9C92}, {0x9B9D,0x9C9E}, {0x9B9E,0x9C95}, {0x9BAA,0x9C94}, {0x9BAB,0x9C9B}, 
+  {0x9BAD,0x9C91}, {0x9BAE,0x9C9C}, {0x9BC0,0x9CA7}, {0x9BC1,0x9CA0}, {0x9BC7,0x9CA9}, 
+  {0x9BC9,0x9CA4}, {0x9BCA,0x9CA8}, {0x9BD4,0x9CBB}, {0x9BD6,0x9CAD}, {0x9BDB,0x9CB7}, 
+  {0x9BDD,0x9CB4}, {0x9BE1,0x9CB1}, {0x9BE2,0x9CB5}, {0x9BE4,0x9CB2}, {0x9BE7,0x9CB3}, 
+  {0x9BE8,0x9CB8}, {0x9BEA,0x9CAE}, {0x9BEB,0x9CB0}, {0x9BF0,0x9CB6}, {0x9BF4,0x9CBA}, 
+  {0x9BFD,0x9CAB}, {0x9BFF,0x9CCA}, {0x9C08,0x9CBD}, {0x9C09,0x9CC7}, {0x9C0D,0x9CC5}, 
+  {0x9C10,0x9CC4}, {0x9C12,0x9CC6}, {0x9C13,0x9CC3}, {0x9C20,0x9CCB}, {0x9C23,0x9CA5}, 
+  {0x9C25,0x9CCF}, {0x9C28,0x9CCE}, {0x9C29,0x9CD0}, {0x9C2D,0x9CCD}, {0x9C31,0x9CA2}, 
+  {0x9C32,0x9CCC}, {0x9C33,0x9CD3}, {0x9C35,0x9CD8}, {0x9C37,0x9CA6}, {0x9C39,0x9CA3}, 
+  {0x9C3B,0x9CD7}, {0x9C3E,0x9CD4}, {0x9C45,0x9CD9}, {0x9C48,0x9CD5}, {0x9C49,0x9CD6}, 
+  {0x9C52,0x9CDF}, {0x9C54,0x9CDD}, {0x9C56,0x9CDC}, {0x9C57,0x9CDE}, {0x9C58,0x9C9F}, 
+  {0x9C5D,0x9CBC}, {0x9C5F,0x9C8E}, {0x9C67,0x9CE2}, {0x9C6D,0x9C9A}, {0x9C78,0x9C88}, 
+  {0x9C7A,0x9CA1}, {0x9CE5,0x9E1F}, {0x9CE9,0x9E20}, {0x9CEC,0x51EB}, {0x9CF3,0x51E4}, 
+  {0x9CF4,0x9E23}, {0x9CF6,0x9E22}, {0x9D06,0x9E29}, {0x9D07,0x9E28}, {0x9D09,0x9E26}, 
+  {0x9D15,0x9E35}, {0x9D1B,0x9E33}, {0x9D1D,0x9E32}, {0x9D1F,0x9E31}, {0x9D23,0x9E2A}, 
+  {0x9D26,0x9E2F}, {0x9D28,0x9E2D}, {0x9D2F,0x9E38}, {0x9D30,0x9E39}, {0x9D3B,0x9E3F}, 
+  {0x9D3F,0x9E3D}, {0x9D42,0x9E3A}, {0x9D51,0x9E43}, {0x9D52,0x9E46}, {0x9D53,0x9E41}, 
+  {0x9D5C,0x9E48}, {0x9D5D,0x9E45}, {0x9D60,0x9E44}, {0x9D61,0x9E49}, {0x9D6A,0x9E4C}, 
+  {0x9D6C,0x9E4F}, {0x9D6F,0x9E4E}, {0x9D72,0x9E4A}, {0x9D87,0x9E2B}, {0x9D89,0x9E51}, 
+  {0x9D93,0x9E4B}, {0x9D98,0x9E55}, {0x9D9A,0x9E57}, {0x9DA5,0x9E5B}, {0x9DA9,0x9E5C}, 
+  {0x9DAF,0x83BA}, {0x9DB4,0x9E64}, {0x9DBB,0x9E58}, {0x9DBC,0x9E63}, {0x9DC0,0x9E5A}, 
+  {0x9DC2,0x9E5E}, {0x9DC4,0x9E21}, {0x9DD3,0x9E67}, {0x9DD7,0x9E25}, {0x9DD9,0x9E37}, 
+  {0x9DDA,0x9E68}, {0x9DE5,0x9E36}, {0x9DE6,0x9E6A}, {0x9DEF,0x9E69}, {0x9DF2,0x9E6B}, 
+  {0x9DF3,0x9E47}, {0x9DF8,0x9E6C}, {0x9DF9,0x9E70}, {0x9DFA,0x9E6D}, {0x9E0C,0x9E71}, 
+  {0x9E15,0x9E2C}, {0x9E1A,0x9E66}, {0x9E1B,0x9E73}, {0x9E1D,0x9E42}, {0x9E1E,0x9E3E}, 
+  {0x9E7A,0x9E7E}, {0x9E7C,0x7877}, {0x9E7D,0x76D0}, {0x9E97,0x4E3D}, {0x9EA5,0x9EA6}, 
+  {0x9EA9,0x9EB8}, {0x9EBD,0x4E48}, {0x9ECC,0x9EC9}, {0x9EDE,0x70B9}, {0x9EE8,0x515A}, 
+  {0x9EF2,0x9EEA}, {0x9EF7,0x9EE9}, {0x9EFD,0x9EFE}, {0x9EFF,0x9F0B}, {0x9F09,0x9F0D}, 
+  {0x9F4A,0x9F50}, {0x9F4B,0x658B}, {0x9F4F,0x9F51}, {0x9F52,0x9F7F}, {0x9F54,0x9F80}, 
+  {0x9F59,0x9F85}, {0x9F5C,0x9F87}, {0x9F5F,0x9F83}, {0x9F60,0x9F86}, {0x9F61,0x9F84}, 
+  {0x9F66,0x9F88}, {0x9F6A,0x9F8A}, {0x9F6C,0x9F89}, {0x9F72,0x9F8B}, {0x9F77,0x9F8C}, 
+  {0x9F8D,0x9F99}, {0x9F90,0x5E9E}, {0x9F94,0x9F9A}, {0x9F95,0x9F9B}, {0x9F9C,0x9F9F}
+};
+
+
+
+/* the letters correspond to unicode characters which
+ * have Lu, Ll, Lt, Lm, Lo, Mn, Mc, or Me in their
+ * GENERAL CATEGORY */
+
+#define NUM_LETTER_INFO 274
+static const unirange letter_info[NUM_LETTER_INFO] = {
+  {0x41,0x5a}, {0x61,0x7a}, {0xaa,0xaa}, {0xb5,0xb5}, 
+  {0xba,0xba}, {0xc0,0xd6}, {0xd8,0xf6}, {0xf8,0x1f5}, 
+  {0x1fa,0x217}, {0x250,0x2a8}, {0x2b0,0x2b8}, {0x2bb,0x2c1}, 
+  {0x2d0,0x2d1}, {0x2e0,0x2e4}, {0x300,0x345}, {0x360,0x361}, 
+  {0x37a,0x37a}, {0x386,0x386}, {0x388,0x38a}, {0x38c,0x38c}, 
+  {0x38e,0x3a1}, {0x3a3,0x3ce}, {0x3d0,0x3d6}, {0x3da,0x3da}, 
+  {0x3dc,0x3dc}, {0x3de,0x3de}, {0x3e0,0x3e0}, {0x3e2,0x3f3}, 
+  {0x401,0x40c}, {0x40e,0x44f}, {0x451,0x45c}, {0x45e,0x481}, 
+  {0x483,0x486}, {0x490,0x4c4}, {0x4c7,0x4c8}, {0x4cb,0x4cc}, 
+  {0x4d0,0x4eb}, {0x4ee,0x4f5}, {0x4f8,0x4f9}, {0x531,0x556}, 
+  {0x559,0x559}, {0x561,0x587}, {0x591,0x5a1}, {0x5a3,0x5b9}, 
+  {0x5bb,0x5bd}, {0x5bf,0x5bf}, {0x5c1,0x5c2}, {0x5c4,0x5c4}, 
+  {0x5d0,0x5ea}, {0x5f0,0x5f2}, {0x621,0x63a}, {0x640,0x652}, 
+  {0x670,0x6b7}, {0x6ba,0x6be}, {0x6c0,0x6ce}, {0x6d0,0x6d3}, 
+  {0x6d5,0x6e8}, {0x6ea,0x6ed}, {0x901,0x903}, {0x905,0x939}, 
+  {0x93c,0x94d}, {0x951,0x954}, {0x958,0x963}, {0x981,0x983}, 
+  {0x985,0x98c}, {0x98f,0x990}, {0x993,0x9a8}, {0x9aa,0x9b0}, 
+  {0x9b2,0x9b2}, {0x9b6,0x9b9}, {0x9bc,0x9bc}, {0x9be,0x9c4}, 
+  {0x9c7,0x9c8}, {0x9cb,0x9cd}, {0x9d7,0x9d7}, {0x9dc,0x9dd}, 
+  {0x9df,0x9e3}, {0x9f0,0x9f1}, {0xa02,0xa02}, {0xa05,0xa0a}, 
+  {0xa0f,0xa10}, {0xa13,0xa28}, {0xa2a,0xa30}, {0xa32,0xa33}, 
+  {0xa35,0xa36}, {0xa38,0xa39}, {0xa3c,0xa3c}, {0xa3e,0xa42}, 
+  {0xa47,0xa48}, {0xa4b,0xa4d}, {0xa59,0xa5c}, {0xa5e,0xa5e}, 
+  {0xa70,0xa74}, {0xa81,0xa83}, {0xa85,0xa8b}, {0xa8d,0xa8d}, 
+  {0xa8f,0xa91}, {0xa93,0xaa8}, {0xaaa,0xab0}, {0xab2,0xab3}, 
+  {0xab5,0xab9}, {0xabc,0xac5}, {0xac7,0xac9}, {0xacb,0xacd}, 
+  {0xae0,0xae0}, {0xb01,0xb03}, {0xb05,0xb0c}, {0xb0f,0xb10}, 
+  {0xb13,0xb28}, {0xb2a,0xb30}, {0xb32,0xb33}, {0xb36,0xb39}, 
+  {0xb3c,0xb43}, {0xb47,0xb48}, {0xb4b,0xb4d}, {0xb56,0xb57}, 
+  {0xb5c,0xb5d}, {0xb5f,0xb61}, {0xb82,0xb83}, {0xb85,0xb8a}, 
+  {0xb8e,0xb90}, {0xb92,0xb95}, {0xb99,0xb9a}, {0xb9c,0xb9c}, 
+  {0xb9e,0xb9f}, {0xba3,0xba4}, {0xba8,0xbaa}, {0xbae,0xbb5}, 
+  {0xbb7,0xbb9}, {0xbbe,0xbc2}, {0xbc6,0xbc8}, {0xbca,0xbcd}, 
+  {0xbd7,0xbd7}, {0xc01,0xc03}, {0xc05,0xc0c}, {0xc0e,0xc10}, 
+  {0xc12,0xc28}, {0xc2a,0xc33}, {0xc35,0xc39}, {0xc3e,0xc44}, 
+  {0xc46,0xc48}, {0xc4a,0xc4d}, {0xc55,0xc56}, {0xc60,0xc61}, 
+  {0xc82,0xc83}, {0xc85,0xc8c}, {0xc8e,0xc90}, {0xc92,0xca8}, 
+  {0xcaa,0xcb3}, {0xcb5,0xcb9}, {0xcbe,0xcc4}, {0xcc6,0xcc8}, 
+  {0xcca,0xccd}, {0xcd5,0xcd6}, {0xcde,0xcde}, {0xce0,0xce1}, 
+  {0xd02,0xd03}, {0xd05,0xd0c}, {0xd0e,0xd10}, {0xd12,0xd28}, 
+  {0xd2a,0xd39}, {0xd3e,0xd43}, {0xd46,0xd48}, {0xd4a,0xd4d}, 
+  {0xd57,0xd57}, {0xd60,0xd61}, {0xe01,0xe2e}, {0xe30,0xe3a}, 
+  {0xe40,0xe4e}, {0xe81,0xe82}, {0xe84,0xe84}, {0xe87,0xe88}, 
+  {0xe8a,0xe8a}, {0xe8d,0xe8d}, {0xe94,0xe97}, {0xe99,0xe9f}, 
+  {0xea1,0xea3}, {0xea5,0xea5}, {0xea7,0xea7}, {0xeaa,0xeab}, 
+  {0xead,0xeae}, {0xeb0,0xeb9}, {0xebb,0xebd}, {0xec0,0xec4}, 
+  {0xec6,0xec6}, {0xec8,0xecd}, {0xedc,0xedd}, {0xf18,0xf19}, 
+  {0xf35,0xf35}, {0xf37,0xf37}, {0xf39,0xf39}, {0xf40,0xf47}, 
+  {0xf49,0xf69}, {0xf71,0xf84}, {0xf86,0xf87}, {0xf90,0xf95}, 
+  {0xf97,0xf97}, {0xf99,0xfad}, {0xfb1,0xfb7}, {0xfb9,0xfb9}, 
+  {0x10a0,0x10c5}, {0x10d0,0x10f6}, {0x1100,0x1159}, {0x115f,0x11a2}, 
+  {0x11a8,0x11f9}, {0x1e00,0x1e9b}, {0x1ea0,0x1ef9}, {0x1f00,0x1f15}, 
+  {0x1f18,0x1f1d}, {0x1f20,0x1f45}, {0x1f48,0x1f4d}, {0x1f50,0x1f57}, 
+  {0x1f59,0x1f59}, {0x1f5b,0x1f5b}, {0x1f5d,0x1f5d}, {0x1f5f,0x1f7d}, 
+  {0x1f80,0x1fb4}, {0x1fb6,0x1fbc}, {0x1fbe,0x1fbe}, {0x1fc2,0x1fc4}, 
+  {0x1fc6,0x1fcc}, {0x1fd0,0x1fd3}, {0x1fd6,0x1fdb}, {0x1fe0,0x1fec}, 
+  {0x1ff2,0x1ff4}, {0x1ff6,0x1ffc}, {0x207f,0x207f}, {0x20d0,0x20e1}, 
+  {0x2102,0x2102}, {0x2107,0x2107}, {0x210a,0x2113}, {0x2115,0x2115}, 
+  {0x2118,0x211d}, {0x2124,0x2124}, {0x2126,0x2126}, {0x2128,0x2128}, 
+  {0x212a,0x2131}, {0x2133,0x2138}, {0x3005,0x3005}, {0x302a,0x302f}, 
+  {0x3031,0x3035}, {0x3041,0x3094}, {0x3099,0x309e}, {0x30a1,0x30fa}, 
+  {0x30fc,0x30fe}, {0x3105,0x312c}, {0x3131,0x318e}, {0x4e00,0x9fa5}, 
+  {0xac00,0xd7a3}, {0xf900,0xfa2d}, {0xfb00,0xfb06}, {0xfb13,0xfb17}, 
+  {0xfb1e,0xfb28}, {0xfb2a,0xfb36}, {0xfb38,0xfb3c}, {0xfb3e,0xfb3e}, 
+  {0xfb40,0xfb41}, {0xfb43,0xfb44}, {0xfb46,0xfbb1}, {0xfbd3,0xfd3d}, 
+  {0xfd50,0xfd8f}, {0xfd92,0xfdc7}, {0xfdf0,0xfdfb}, {0xfe20,0xfe23}, 
+  {0xfe70,0xfe72}, {0xfe74,0xfe74}, {0xfe76,0xfefc}, {0xff21,0xff3a}, 
+  {0xff41,0xff5a}, {0xff66,0xffbe}, {0xffc2,0xffc7}, {0xffca,0xffcf}, 
+  {0xffd2,0xffd7}, {0xffda,0xffdc}
+};
+
+
+/* the digits correspond to unicode characters which
+ * have Nd in their GENERAL CATEGORY */
+
+#define NUM_DIGIT_INFO 16
+static const unirange digit_info[NUM_DIGIT_INFO] = {
+  {0x30,0x39}, {0x660,0x669}, {0x6f0,0x6f9}, {0x966,0x96f}, 
+  {0x9e6,0x9ef}, {0xa66,0xa6f}, {0xae6,0xaef}, {0xb66,0xb6f}, 
+  {0xbe7,0xbef}, {0xc66,0xc6f}, {0xce6,0xcef}, {0xd66,0xd6f}, 
+  {0xe50,0xe59}, {0xed0,0xed9}, {0xf20,0xf29}, {0xff10,0xff19}
+};
+
+
+/* the spaces correspond to unicode characters which
+ * have Zs, Zl, or Zp in their GENERAL CATEGORY */
+
+#define NUM_SPACE_INFO 5
+static const unirange space_info[NUM_SPACE_INFO] = {
+  {0x20,0x20}, {0xa0,0xa0}, {0x2000,0x200b}, {0x2028,0x2029}, 
+  {0x3000,0x3000}
+};
+
+
+
+/* parse_utf8_char parses the next utf-8 character, placing its
+ * unicode equivalent in *value. The length of the utf-8 character
+ * is returned */
+int parse_utf8_char(const unsigned char *here,
+		    const unsigned char *end,
+		    unsigned short *value) {
+  unsigned short c1;
+  unsigned short c2;
+  unsigned short c3;
+  
+  *value = 0; /* will be the value for illegal characters */
+  
+  if (here <= end) {
+    c1 = (unsigned short)(*here);
+    
+    if (c1 <= 0x7f) {
+      /* found a one-byte character */
+      *value = c1;
+      return 1;
+      
+    } else if (c1 >= 0xc0 && c1 <= 0xdf && here+1 <= end &&
+	       (c2=(unsigned short)(*(here+1))) >= 0x80) {
+      /* found a two-byte character */
+      *value = ((c1 & 0x1f) << 6) + (c2 & 0x3f);
+      return 2;
+      
+    } else if (c1 >= 0xe0 && c1 <= 0xef && here+2 <= end &&
+	       (c2=(unsigned int)(*(here+1))) >= 0x80 &&
+	       (c3=(unsigned int)(*(here+2))) >= 0x80) {
+      /* found a three-byte character */
+      *value = ((c1 & 0xf) << 12) + ((c2 & 0x3f) << 6) +
+	(c3 & 0x3f);
+      return 3;
+      
+    } else {
+      /* error in encoding, return the length as 1 */
+      return 1;
+    }
+  }
+
+  /* end of string */
+  return 0;
+}
+
+
+/* output_utf8_char encodes a unicode character as a UTF-8 character.
+ * The length of the encoding is returned. If the string was not
+ * long enough to encode the character 0 is returned. */
+int output_utf8_char (unsigned short value,
+		      unsigned char *here,
+		      unsigned char *end) {
+  int len = (int)(end - here + 1); /* end is the last character */
+  if (value < 0x80) {
+    /* will be encoded in one byte */
+    if (len >= 1) {
+      *here = (unsigned char)value;
+      return 1;
+    }
+
+  } else if (value < 0x800) {
+    /* will be encoded in two bytes */
+    if (len >= 2) {
+      *here++ = 0xc0 | (unsigned char)((value >> 6) & 0x1f);
+      *here = 0x80 | (unsigned char)(value & 0x3f);
+
+      return 2;
+    }
+
+  } else {
+    /* will be encoded in three bytes */
+    if (len >= 3) {
+      *here++ = 0xe0 | (unsigned char)((value >> 12) & 0xf);
+      *here++ = 0x80 | (unsigned char)((value >> 6) & 0x3f);
+      *here = 0x80 | (unsigned char)(value & 0x3f);
+      return 3;
+    }
+  }
+
+  return 0;
+}
+
+
+static int lookup_decompose_table (unsigned short value) {
+  int first = 0;
+  int last = NUM_DECOMPOSE_INFO;
+  int here;
+
+  while (first < last) {
+    here = (last-first)/2 + first;
+    if (value < decompose_info[here].ch) {
+      last = here;
+    } else if (value > decompose_info[here].ch) {
+      first = here+1;
+    } else {
+      return here;
+    }
+  }
+
+  return -1;
+}
+
+/* decompose_str will decompose a unicode string into its canonical
+ * equivalents. NULL is returned if the input array was not 
+ * large enough to contain the fully decomposed string (the array
+ * will be in a correct, but partially decomposed state). The input 
+ * must be null-terminated. */
+unsigned short *decompose_str (unsigned short *input,
+			       int max_output_len) {
+  int curpos = 0;
+  int curlen = unicode_strlen (input);
+  int tablepos = 0;
+  int leninc;
+  int i;
+
+  while (input[curpos] != 0) {
+    tablepos = lookup_decompose_table (input[curpos]);
+    if (tablepos >= 0) {
+      /* found a decomposition */
+      leninc = unicode_strnlen (decompose_info[tablepos].str, 3)-1;
+      if (curlen+leninc < max_output_len) {
+	/* enough space for this decomposition */
+
+	if (leninc > 1) {
+	  /* we have to shift the array along */
+	  for (i=curlen-1; i>=curpos; i--) {
+	    input[i+leninc] = input[i];
+	  }
+	  input[curlen+leninc] = 0;
+	  curlen += leninc;
+	}
+
+	/* decompose the character */
+	for (i=0; i<=leninc; i++) {
+	  input[curpos+i] = decompose_info[tablepos].str[i];
+	}
+
+	/* note: curpos is not incremented because the decomposed */
+	/*       characters might need decomposing */
+
+      } else {
+	/* no space left in string */
+	return NULL;
+      }
+
+    } else {
+      /* the character cannot be decomposed */
+      curpos++;
+    }
+  }
+
+  return input;
+}
+
+
+
+/* unicode_cat_data is a combination of the letter, digit, and
+ * space information in a form that is quick to look up.
+ * The information about each byte is stored in two bits
+ *
+ * 00 - neither letter, digit or space
+ * 01 - letter
+ * 10 - space
+ * 11 - digit
+ *
+ * You can test for letter | space by looking at the right
+ * column
+ */
+/*unsigned long *unicode_cat_data;*/
+
+void create_unicat_data () {
+  int i=0;
+  int min_start=0;
+  int min_end=0;
+  register unsigned long min_value=0; /* filling the whole byte */
+  
+  const unirange *letter_here = letter_info;
+  const unirange *letter_end = letter_info+NUM_LETTER_INFO;
+  const unirange *digit_here = digit_info;
+  const unirange *digit_end = digit_info+NUM_DIGIT_INFO;
+  const unirange *space_here = space_info;
+  const unirange *space_end = space_info+NUM_SPACE_INFO;
+
+  if (unicode_cat_data != NULL) return;
+  unicode_cat_data = (unsigned long *) malloc (0x10000/4);
+  if (unicode_cat_data == NULL) return;
+  
+  while (i <= 0xffff) {
+    /* decide what to fill with next */
+    min_start = i;
+    min_end = 0xffff;
+    min_value = 0; /* 00 */
+    
+    while (letter_here < letter_end && letter_here->last < i) letter_here++;
+    if (letter_here < letter_end && letter_here->last <= min_end) {
+      min_start = letter_here->first;
+      min_end = letter_here->last;
+      min_value = 0x55555555; /* 01 */
+    }
+    
+    while (digit_here < digit_end && digit_here->last < i) digit_here++;
+    if (digit_here < digit_end && digit_here->last <= min_end) {
+      min_start = digit_here->first;
+      min_end = digit_here->last;
+      min_value = 0xffffffff; /* 11 */
+    }
+    
+    while (space_here < space_end && space_here->last < i) space_here++;
+    if (space_here < space_end && space_here->last <= min_end) {
+      min_start = space_here->first;
+      min_end = space_here->last;
+      min_value = 0xaaaaaaaa; /* 10 */
+    }
+
+    if (min_start < i) min_start = i;
+    else if (min_start > i) {
+      min_end = min_start-1;
+      min_start = i;
+      min_value = 0; /* 00 */
+    }
+
+    /* fill the entries from min_start to min_end with min_value */
+    while (i <= min_end) {
+      /* special version for common case */
+      if (i % 16 == 0) {
+	unicode_cat_data[i/16] = min_value; /* doesn't matter if too long */
+	i += 16;
+	if (i > min_end) {
+	  i = min_end+1;
+	  break;
+	}
+	
+      } else {
+	register unsigned long mask = 3 << ((i % 16) * 2);
+	unicode_cat_data[i/16] = (unicode_cat_data[i/16] & (~mask)) |
+				  (min_value & mask);
+	i++;
+      }
+    }
+  }
+}
+
+/* does a binary search on a range table */
+static int in_unirange (const unirange *info, int num_info,
+			unsigned short value) {
+  int first = 0;
+  int last = num_info;
+  int here;
+
+  while (first < last) {
+    here = (last-first)/2 + first;
+    if (value < info[here].first) {
+      last = here;
+    } else if (value > info[here].last) {
+      first = here+1;
+    } else {
+      return 1;
+    }
+  }
+
+  return 0;
+}
+
+
+
+/* tests to see whether 'value' is a valid Unicode letter */
+int is_unicode_letter (unsigned short value) {
+  if (unicode_cat_data == NULL) create_unicat_data ();
+  if (unicode_cat_data == NULL) {
+    /* use old method */
+    return in_unirange(letter_info, NUM_LETTER_INFO, value);
+  }
+
+  return (((unicode_cat_data[value/16] >> ((value%16)*2)) & 0x3) == 0x1);
+}
+
+/* tests to see whether 'value' is a valid Unicode digit */
+int is_unicode_digit (unsigned short value) {
+  if (unicode_cat_data == NULL) create_unicat_data ();
+  if (unicode_cat_data == NULL) {
+    /* use old method */
+    return in_unirange(digit_info, NUM_DIGIT_INFO, value);
+  }
+
+  return (((unicode_cat_data[value/16] >> ((value%16)*2)) & 0x3) == 0x3);
+}
+
+/* tests to see whether 'value' is a valid Unicode letter or 
+ * digit */
+int is_unicode_letdig (unsigned short value) {
+  if (unicode_cat_data == NULL) create_unicat_data ();
+  if (unicode_cat_data == NULL) {
+    /* use old method */
+    return (in_unirange(letter_info, NUM_LETTER_INFO, value) ||
+	    in_unirange(digit_info, NUM_DIGIT_INFO, value));
+    
+  }
+
+  return ((unicode_cat_data[value/16] >> ((value%16)*2)) & 0x1);
+}
+
+/* tests to see whether 'value' is a valid space
+ * The test includes both "C" spaces and "Unicode" spaces, i.e. 
+ * form-feed, newline, carriage return, horizontal tab,
+ * vertical tab, and the Zs, Zl, and Zp Unicode categorizations */
+int is_unicode_space (unsigned short value) {
+  if (value < 0x80) return isspace (value);
+  if (unicode_cat_data == NULL) create_unicat_data ();
+  if (unicode_cat_data == NULL) {
+    /* use old method */
+    return in_unirange(space_info, NUM_SPACE_INFO, value);
+  }
+
+  return (((unicode_cat_data[value/16] >> ((value%16)*2)) & 0x3) == 0x2);
+}
+
+/* returns the length of the unicode string */
+int unicode_strlen (const unsigned short *str) {
+  int len = 0;
+
+  /* keep going till you find the null-terminator */
+  while (*str != 0) {
+    len++;
+    str++;
+  }
+
+  return len;
+}
+
+/* returns the length of the unicode string, up to a maximum */
+int unicode_strnlen (const unsigned short *str, int max_length) {
+  int len = 0;
+
+  /* keep going till you find the null-terminator */
+  while (*str != 0 && len < max_length ) {
+    len++;
+    str++;
+  }
+
+  return len;
+}
+
+
+/* Does a binary search on a relate table, returns -1 if it is not
+ * found. */
+static int search_unirelate (const unirelate *info, int num_info,
+			     unsigned short value) {
+  int first = 0;
+  int last = num_info;
+  int here;
+
+  while (first < last) {
+    here = (last-first)/2 + first;
+    if (value < info[here].ch1) {
+      last = here;
+    } else if (value > info[here].ch1) {
+      first = here+1;
+    } else {
+      return here;
+    }
+  }
+
+  return -1;
+}
+
+
+/* returns the upper-case equivalent of value */
+unsigned short unicode_toupper (unsigned short value) {
+  int related = search_unirelate (toupper_info, NUM_TOUPPER_INFO, value);
+  if (related >= 0) {
+    value = toupper_info[related].ch2;
+  }
+  return value;
+}
+
+/* returns the lower-case equivalent of value */
+unsigned short unicode_tolower (unsigned short value) {
+  int related = search_unirelate (tolower_info, NUM_TOLOWER_INFO, value);
+  if (related >= 0) {
+    value = tolower_info[related].ch2;
+  }
+  return value;
+}
+
+/* returns the simplified Chinese character equivalent of 
+ * another Chinese character */
+unsigned short unicode_tosimplified (unsigned short value) {
+  int related = search_unirelate (tosimplified_info, NUM_TOSIMPLIFIED_INFO, value);
+  if (related >= 0) {
+    value = tosimplified_info[related].ch2;
+  }
+  return value;
+}
+
+
+/* converts a utf-8 word (string with length stored in the first byte
+ * to a Unicode array. To handle all situations the output buffer should
+ * be 256 unsigned shorts long. The output will also have the length as
+ * the first entry. */
+unsigned short *utf8_word_to_unicode (const unsigned char *input,
+				      unsigned short *output,
+				      int max_output_length) {
+  int inlen = *input;
+  const unsigned char *inhere = input+1;
+  const unsigned char *inend = &inhere[inlen-1];
+  unsigned short c;
+  int clen;
+  
+  int outlen = 0;
+  unsigned short *outhere = output+1;
+  
+  while (inhere <= inend && inlen < max_output_length-1) {
+    /* decode the character */
+    clen = parse_utf8_char (inhere, inend, &c);
+    inhere += clen;
+
+    if (clen > 0) {
+      /* store the character */
+      *outhere = c;
+      outhere++;
+      outlen++;
+    }
+  }
+
+  output[0] = outlen;
+  return output;
+}
+
+
+/* converts a unicode word buffer (with the length stored in the
+ * entry) to a utf8 encoded word output (with the length stored in
+ * the first byte. Only 255 bytes (not characters) can be stored 
+ * in the output. */
+unsigned char *unicode_to_utf8_word (const unsigned short *input,
+				     unsigned char *output,
+				     int max_output_length) {
+  int inlen = *input;
+  const unsigned short *word = input + 1;
+  int in_i = 0;
+  int clen;
+
+  int outlen = 0;
+  unsigned char *outhere = output+1;
+  unsigned char *outend = output+max_output_length;
+
+  while (in_i < inlen) {
+    if ((clen=output_utf8_char(word[in_i], outhere, outend)) == 0) {
+      /* ran out of space to encode the character */
+      break;
+    }
+
+    outhere += clen;
+    outlen += clen;
+    in_i++;
+  }
+
+  output[0] = outlen;
+
+  return output;
+}
+
Index: /main/tags/2.25/gsdl/src/mgpp/lib/unitool.h
===================================================================
--- /main/tags/2.25/gsdl/src/mgpp/lib/unitool.h	(revision 21064)
+++ /main/tags/2.25/gsdl/src/mgpp/lib/unitool.h	(revision 21064)
@@ -0,0 +1,88 @@
+#ifndef UNITOOL_H
+#define UNITOOL_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+
+/* This module is based on Unicode 2.1 */
+
+
+/* parse_utf8_char parses the next utf-8 character, placing its
+ * unicode equivalent in *value. The length of the utf-8 character
+ * is returned. end is the address of the last character. */
+int parse_utf8_char (const unsigned char *here,
+		     const unsigned char *end,
+		     unsigned short *value);
+
+/* output_utf8_char encodes a unicode character as a UTF-8 character.
+ * The length of the encoding is returned. If the string was not
+ * long enough to encode the character 0 is returned. end is the
+ * address of the last character */
+int output_utf8_char (unsigned short value,
+		      unsigned char *here,
+		      unsigned char *end);
+
+/* decompose_str will decompose a unicode string into its canonical
+ * equivalents. NULL is returned if the input array was not 
+ * large enough to contain the fully decomposed string (the array
+ * will be in a correct, but partially decomposed state). The input 
+ * must be null-terminated. */
+unsigned short *decompose_str (unsigned short *input,
+			       int max_output_len);
+
+/* tests to see whether 'value' is a valid Unicode letter */
+int is_unicode_letter (unsigned short value);
+
+/* tests to see whether 'value' is a valid Unicode digit */
+int is_unicode_digit (unsigned short value);
+
+/* tests to see whether 'value' is a valid Unicode letter or 
+ * digit */
+int is_unicode_letdig (unsigned short value);
+
+/* tests to see whether 'value' is a valid space
+ * The test includes both "C" spaces and "Unicode" spaces, i.e. 
+ * form-feed, newline, carriage return, horizontal tab,
+ * vertical tab, and the Zs, Zl, and Zp Unicode categorizations */
+int is_unicode_space (unsigned short value);
+
+/* returns the length of the unicode string */
+int unicode_strlen (const unsigned short *str);
+
+/* returns the length of the unicode string, up to a maximum */
+int unicode_strnlen (const unsigned short *str, int max_length);
+
+/* returns the upper-case equivalent of value */
+unsigned short unicode_toupper (unsigned short value);
+
+/* returns the lower-case equivalent of value */
+unsigned short unicode_tolower (unsigned short value);
+
+/* returns the simplified Chinese character equivalent of 
+ * another Chinese character */
+unsigned short unicode_tosimplified (unsigned short value);
+
+
+/* converts a utf-8 word (string with length stored in the first byte
+ * to a Unicode array. To handle all situations the output buffer should
+ * be 256 unsigned shorts long. The output will also have the length as
+ * the first entry. */
+unsigned short *utf8_word_to_unicode (const unsigned char *input,
+				      unsigned short *output,
+				      int max_output_length);
+
+/* converts a unicode word buffer (with the length stored in the
+ * entry) to a utf8 encoded word output (with the length stored in
+ * the first byte. Only 255 bytes (not characters) can be stored 
+ * in the output. */
+unsigned char *unicode_to_utf8_word (const unsigned short *input,
+				     unsigned char *output,
+				     int max_output_length);
+
+#ifdef __cplusplus
+	   }
+#endif
+
+#endif
Index: /main/tags/2.25/gsdl/src/mgpp/lib/win32in.c
===================================================================
--- /main/tags/2.25/gsdl/src/mgpp/lib/win32in.c	(revision 21064)
+++ /main/tags/2.25/gsdl/src/mgpp/lib/win32in.c	(revision 21064)
@@ -0,0 +1,84 @@
+/* This module provides an equivalent of <netinet/in.h> on  */
+/* unix systems. */
+
+unsigned long htonl(unsigned long x) {
+#if defined (LITTLE_ENDIAN) || defined (_LITTLE_ENDIAN) || defined(__LITTLE_ENDIAN)
+	x = ((x >> 24) & 0x000000FF) | ((x >> 8) & 0x0000FF00) |
+		((x << 8) & 0x00FF0000) | ((x << 24) & 0xFF000000);
+#endif
+
+	return x;
+}
+
+mg_ullong ntohll(mg_ullong y)
+{
+#if defined (LITTLE_ENDIAN) || defined(_LITTLE_ENDIAN) || defined(__LITTLE_ENDIAN)
+	x = 
+	  ((x >> 56) & 0x00000000000000FF) | ((x >> 40) & 0x000000000000FF00) |
+	  ((x >> 24) & 0x0000000000FF0000) | ((x >> 8)  & 0x00000000FF000000) |
+	  ((x << 8)  & 0x000000FF00000000) | ((x << 24) & 0x0000FF0000000000) |
+		((x << 40) & 0x00FF000000000000) | ((x << 56) & 0xFF00000000000000);
+#endif
+  return x;
+}
+
+unsigned long ntohl(unsigned long x) {
+#if defined (LITTLE_ENDIAN) || defined (_LITTLE_ENDIAN) || defined(__LITTLE_ENDIAN)
+	x = ((x >> 24) & 0x000000FF) | ((x >> 8) & 0x0000FF00) |
+		((x << 8) & 0x00FF0000) | ((x << 24) & 0xFF000000);
+#endif
+	return x;
+}
+
+unsigned short htons(unsigned short x) {
+#if defined (LITTLE_ENDIAN) || defined (_LITTLE_ENDIAN) || defined(__LITTLE_ENDIAN)
+	x = ((x >> 8) & 0x00FF) | ((x << 8) & 0xFF00);
+#endif
+	return x;
+}
+
+unsigned short ntohs(unsigned short x) {
+#if defined (LITTLE_ENDIAN) || defined (_LITTLE_ENDIAN) || defined(__LITTLE_ENDIAN)
+	x = ((x >> 8) & 0x00FF) | ((x << 8) & 0xFF00);
+#endif
+	return x;
+}
+
+/* just to test stuff
+#include <stdio.h>
+
+main () {
+	long x;
+	short sx;
+
+	x = 0x000000FF;
+	printf ("before %i, ",(int)x);
+	x = htonl (x);
+	printf ("after %i\n",(int)x);
+
+	x = 0x0000FF00;
+	printf ("before %i, ",(int)x);
+	x = htonl (x);
+	printf ("after %i\n",(int)x);
+
+	x = 0x00FF0000;
+	printf ("before %i, ",(int)x);
+	x = htonl (x);
+	printf ("after %i\n",(int)x);
+
+	x = 0xFF000000;
+	printf ("before %i, ",(int)x);
+	x = htonl (x);
+	printf ("after %i\n\n",(int)x);
+
+	sx = 0x00FF;
+	printf ("before %i, ",(int)sx);
+	sx = htons (sx);
+	printf ("after %i\n",(int)sx);
+
+	sx = 0xFF00;
+	printf ("before %i, ",(int)sx);
+	sx = htons (sx);
+	printf ("after %i\n",(int)sx);
+}
+*/
Index: /main/tags/2.25/gsdl/src/mgpp/lib/win32in.h
===================================================================
--- /main/tags/2.25/gsdl/src/mgpp/lib/win32in.h	(revision 21064)
+++ /main/tags/2.25/gsdl/src/mgpp/lib/win32in.h	(revision 21064)
@@ -0,0 +1,8 @@
+/* This module provides an equivalent of <netinet/in.h> on  */
+/* unix systems. */
+
+unsigned long htonl(unsigned long x);
+unsigned long ntohl(unsigned long x);
+mg_ullong ntohll(mg_ullong x);
+unsigned short htons(unsigned short x);
+unsigned short ntohs(unsigned short x);
Index: /main/tags/2.25/gsdl/src/mgpp/lib/xmalloc.c
===================================================================
--- /main/tags/2.25/gsdl/src/mgpp/lib/xmalloc.c	(revision 21064)
+++ /main/tags/2.25/gsdl/src/mgpp/lib/xmalloc.c	(revision 21064)
@@ -0,0 +1,103 @@
+/* xmalloc.c -- malloc with out of memory checking
+   Copyright (C) 1990, 91, 92, 93, 94 Free Software Foundation, Inc.
+
+   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, 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.  */
+
+#ifdef HAVE_CONFIG_H
+# ifdef __WIN32__  /* [RPAP - Feb 97: WIN32 Port] */
+#  include <win32cfg.h>
+# else
+#  include <sysfuncs.h>
+# endif
+#endif
+
+#if __STDC__
+#define VOID void
+#else
+#define VOID char
+#endif
+
+#include <sys/types.h>
+
+#if STDC_HEADERS
+#include <stdlib.h>
+#else
+VOID *malloc ();
+VOID *realloc ();
+void free ();
+#endif
+
+/* This is for other GNU distributions with internationalized messages.
+   The GNU C Library itself does not yet support such messages.  */
+#if HAVE_LIBINTL_H
+# include <libintl.h>
+#else
+# define gettext(msgid) (msgid)
+#endif
+
+#ifndef EXIT_FAILURE
+#define EXIT_FAILURE 1
+#endif
+
+/* Exit value when the requested amount of memory is not available.
+   The caller may set it to some other value.  */
+int xmalloc_exit_failure = EXIT_FAILURE;
+
+#if __STDC__ && (HAVE_VPRINTF || HAVE_DOPRNT)
+void error (int, int, const char *, ...);
+#else
+void error ();
+#endif
+
+static VOID *
+fixup_null_alloc (size_t n)
+{
+  VOID *p;
+
+  p = 0;
+  if (n == 0)
+    p = malloc ((size_t) 1);
+  if (p == 0)
+    error (xmalloc_exit_failure, 0, gettext ("Memory exhausted"));
+  return p;
+}
+
+/* Allocate N bytes of memory dynamically, with error checking.  */
+
+VOID *
+xmalloc (size_t n)
+{
+  VOID *p;
+
+  p = malloc (n);
+  if (p == 0)
+    p = fixup_null_alloc (n);
+  return p;
+}
+
+/* Change the size of an allocated block of memory P to N bytes,
+   with error checking.
+   If P is NULL, run xmalloc.  */
+
+VOID *
+xrealloc (VOID *p, size_t n)
+{
+  if (p == 0)
+    return xmalloc (n);
+  p = realloc (p, n);
+  if (p == 0)
+    p = fixup_null_alloc (n);
+  return p;
+}
Index: /main/tags/2.25/gsdl/src/mgpp/mkinstalldirs
===================================================================
--- /main/tags/2.25/gsdl/src/mgpp/mkinstalldirs	(revision 21064)
+++ /main/tags/2.25/gsdl/src/mgpp/mkinstalldirs	(revision 21064)
@@ -0,0 +1,32 @@
+#! /bin/sh
+# mkinstalldirs --- make directory hierarchy
+# Author: Noah Friedman <friedman@prep.ai.mit.edu>
+# Created: 1993-05-16
+# Last modified: 1994-03-25
+# Public domain
+
+errstatus=0
+
+for file in ${1+"$@"} ; do 
+   set fnord `echo ":$file" | sed -ne 's/^:\//#/;s/^://;s/\// /g;s/^#/\//;p'`
+   shift
+
+   pathcomp=
+   for d in ${1+"$@"} ; do
+     pathcomp="$pathcomp$d"
+     case "$pathcomp" in
+       -* ) pathcomp=./$pathcomp ;;
+     esac
+
+     if test ! -d "$pathcomp"; then
+        echo "mkdir $pathcomp" 1>&2
+        mkdir "$pathcomp" || errstatus=$?
+     fi
+
+     pathcomp="$pathcomp/"
+   done
+done
+
+exit $errstatus
+
+# mkinstalldirs ends here
Index: /main/tags/2.25/gsdl/src/mgpp/stamp-h
===================================================================
--- /main/tags/2.25/gsdl/src/mgpp/stamp-h	(revision 21064)
+++ /main/tags/2.25/gsdl/src/mgpp/stamp-h	(revision 21064)
@@ -0,0 +1,1 @@
+timestamp
Index: /main/tags/2.25/gsdl/src/mgpp/stamp-h.in
===================================================================
--- /main/tags/2.25/gsdl/src/mgpp/stamp-h.in	(revision 21064)
+++ /main/tags/2.25/gsdl/src/mgpp/stamp-h.in	(revision 21064)
@@ -0,0 +1,1 @@
+timestamp
Index: /main/tags/2.25/gsdl/src/mgpp/text/FIvfLevelInfo.cpp
===================================================================
--- /main/tags/2.25/gsdl/src/mgpp/text/FIvfLevelInfo.cpp	(revision 21064)
+++ /main/tags/2.25/gsdl/src/mgpp/text/FIvfLevelInfo.cpp	(revision 21064)
@@ -0,0 +1,131 @@
+/**************************************************************************
+ *
+ * FIvfLevelInfo.cpp -- File functions for document levels
+ * Copyright (C) 1999  Rodger McNab
+ *
+ * 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.
+ *
+ * $Id$
+ *
+ **************************************************************************/
+
+#include "FIvfLevelInfo.h"
+
+
+IvfLevelInfo::IvfLevelInfo () {
+  Clear();
+}
+
+void IvfLevelInfo::Clear () {
+  levelTag.erase (levelTag.begin(), levelTag.end());
+  numEntries = 0;
+  approxWeightsDiskPtr = 0;
+  exactWeightsDiskPtr = 0;
+  workInLevel = false;
+}
+
+bool IvfLevelInfo::Read (FILE *f) {
+  workInLevel = false;
+  return (ReadUCArray (f, levelTag) &&
+	  ReadUL (f, numEntries) &&
+	  ReadUL (f, approxWeightsDiskPtr) &&
+	  ReadUL (f, exactWeightsDiskPtr));
+}
+
+bool IvfLevelInfo::Write (FILE *f) const {
+  return (WriteUCArray (f, levelTag) &&
+	  WriteUL (f, numEntries) &&
+	  WriteUL (f, approxWeightsDiskPtr) &&
+	  WriteUL (f, exactWeightsDiskPtr));
+}
+
+// stream output for debugging purposes
+ostream &operator<<(ostream &s, const IvfLevelInfo &l) {
+  s << "  Tag: \"" << l.levelTag << "\"\n"
+    << "  numEntries: " << l.numEntries << "\n"
+    << "  approxWeightsDiskPtr: " << l.approxWeightsDiskPtr << "\n"
+    << "  exactWeightsDiskPtr: " << l.exactWeightsDiskPtr << "\n"
+    << "  workInLevel: " << ((l.workInLevel) ? "true" : "false") << "\n\n";
+  
+  return s;
+}
+
+
+
+FIvfLevel::FIvfLevel () {
+  Clear ();
+}
+
+void FIvfLevel::Clear () {
+  docTag.erase (docTag.begin(), docTag.end());
+  indexLevel.erase (indexLevel.begin(), indexLevel.end());
+  levelInfo.erase (levelInfo.begin(), levelInfo.end());
+}
+
+bool FIvfLevel::Read (FILE *f) {
+  if (!ReadUCArray (f, docTag) ||
+      !ReadUCArray (f, indexLevel))
+    return false;
+  
+  // read in the array size
+  unsigned long arrSize = 0;
+  if (!ReadVarLenUL (f, arrSize)) return false;
+  
+  IvfLevelInfo thisLevel;
+  while (arrSize > 0) {
+    // read and insert the next level information
+    if (!thisLevel.Read (f)) return false;
+    levelInfo[thisLevel.levelTag] = thisLevel;
+    
+    arrSize--;
+  }
+
+  return true;
+}
+
+bool FIvfLevel::Write (FILE *f) const {
+  if (!WriteUCArray (f, docTag) ||
+      !WriteUCArray (f, indexLevel))
+    return false;
+  
+  // write out the array size
+  if (!WriteVarLenUL (f, levelInfo.size())) return false;
+
+  // write out each level info
+  IvfLevelInfoMap::const_iterator here = levelInfo.begin();
+  IvfLevelInfoMap::const_iterator end = levelInfo.end();
+  while (here != end) {
+    if (!(*here).second.Write (f)) return false;
+    
+    here++;
+  }
+
+  return true;
+}
+
+// stream output for debugging purposes
+ostream &operator<<(ostream &s, const FIvfLevel &l) {
+  s << "docTag: \"" << l.docTag << "\"\n"
+    << "indexLevel: \"" << l.indexLevel << "\"\n";
+  
+  IvfLevelInfoMap::const_iterator here = l.levelInfo.begin ();
+  IvfLevelInfoMap::const_iterator end = l.levelInfo.end ();
+  while (here != end) {
+    s << (*here).second;
+    here++;
+  }
+  
+  return s;
+}
Index: /main/tags/2.25/gsdl/src/mgpp/text/FIvfLevelInfo.h
===================================================================
--- /main/tags/2.25/gsdl/src/mgpp/text/FIvfLevelInfo.h	(revision 21064)
+++ /main/tags/2.25/gsdl/src/mgpp/text/FIvfLevelInfo.h	(revision 21064)
@@ -0,0 +1,79 @@
+/**************************************************************************
+ *
+ * FIvfLevelInfo.h -- File functions for document levels
+ * Copyright (C) 1999  Rodger McNab
+ *
+ * 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.
+ *
+ * $Id$
+ *
+ **************************************************************************/
+
+#ifndef FIVFLEVELINFO_H
+#define FIVFLEVELINFO_H
+
+#if defined(GSDL_USE_OBJECTSPACE)
+#  include <ospace\std\map>
+#elif defined(GSDL_USE_STL_H)
+#  include <map.h>
+#else
+#  include <map>
+#endif
+
+#include <stdio.h>
+#include "UCArray.h"
+
+
+class IvfLevelInfo {
+public:
+  UCArray levelTag;
+  unsigned long numEntries; // N for level
+  unsigned long approxWeightsDiskPtr;
+  unsigned long exactWeightsDiskPtr;
+  bool workInLevel;  // this is just a working variable,
+                     // it is not saved or read from the file
+  
+  IvfLevelInfo ();
+  void Clear ();
+
+  bool Read (FILE *f);
+  bool Write (FILE *f) const;
+};
+
+// stream output for debugging purposes
+ostream &operator<<(ostream &s, const IvfLevelInfo &l);
+
+
+typedef map<UCArray, IvfLevelInfo, LTUCArray> IvfLevelInfoMap;
+
+
+class FIvfLevel {
+public:
+  UCArray docTag;
+  UCArray indexLevel;    // empty for word level index
+  IvfLevelInfoMap levelInfo;
+  
+  FIvfLevel ();
+  void Clear ();
+
+  bool Read (FILE *f);
+  bool Write (FILE *f) const;
+};
+
+// stream output for debugging purposes
+ostream &operator<<(ostream &s, const FIvfLevel &l);
+
+
+#endif
Index: /main/tags/2.25/gsdl/src/mgpp/text/FText.cpp
===================================================================
--- /main/tags/2.25/gsdl/src/mgpp/text/FText.cpp	(revision 21064)
+++ /main/tags/2.25/gsdl/src/mgpp/text/FText.cpp	(revision 21064)
@@ -0,0 +1,251 @@
+/**************************************************************************
+ *
+ * FText.cpp -- File structures for text compression
+ * Copyright (C) 1999  Rodger McNab
+ *
+ * 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.
+ *
+ * $Id$
+ *
+ **************************************************************************/
+
+#include "FText.h"
+#include "netorder.h"  /* [RPAP - Jan 97: Endian Ordering] */
+
+
+BitAddr::BitAddr () {
+  Clear ();  
+}
+
+void BitAddr::Clear () {
+  byte = 0;
+  bit = 0;
+}
+
+bool BitAddr::Read (FILE *f) {
+  return (ReadUL (f, byte) && ReadUC (f, bit));
+}
+
+bool BitAddr::Write (FILE *f) const {
+  return (WriteUL (f, byte) && WriteUC (f, bit));
+}
+
+#define BITADDRLEN (sizeof(unsigned long) + sizeof(unsigned char))
+
+  
+TextLevelInfo::TextLevelInfo () {
+  Clear();
+}
+
+void TextLevelInfo::Clear () {
+  levelTag.erase (levelTag.begin(), levelTag.end());
+  textIdxPtr = 0;
+  numEntries = 0;
+}
+
+bool TextLevelInfo::Read (FILE *f) {
+  return (ReadUCArray (f, levelTag) &&
+	  ReadUL (f, textIdxPtr) &&
+	  ReadUL (f, numEntries));
+}
+
+bool TextLevelInfo::Write (FILE *f) const {
+  return (WriteUCArray (f, levelTag) &&
+	  WriteUL (f, textIdxPtr) &&
+	  WriteUL (f, numEntries));
+}
+
+ostream &operator<<(ostream &s, const TextLevelInfo &l) {
+  s << "  Tag: \"" << l.levelTag << "\"\n"
+    << "  textIdxPtr: " << l.textIdxPtr << "\n"
+    << "  numEntries: " << l.numEntries << "\n\n";
+  
+  return s;
+}
+
+
+FTextLevel::FTextLevel () {
+  Clear();
+}
+
+void FTextLevel::Clear () {
+  levelInfo.erase (levelInfo.begin(), levelInfo.end());
+}
+
+bool FTextLevel::Read (FILE *f) {
+  // read in the array size
+  unsigned long arrSize = 0;
+  if (!ReadVarLenUL (f, arrSize)) return false;
+
+  TextLevelInfo thisLevel;
+  while (arrSize > 0) {
+    // read and insert the next level information
+    if (!thisLevel.Read (f)) return false;
+    levelInfo[thisLevel.levelTag] = thisLevel;
+    
+    arrSize--;
+  }
+
+  return true;
+}
+
+bool FTextLevel::Write (FILE *f) const {
+  // write out the array size
+  if (!WriteVarLenUL (f, levelInfo.size())) return false;
+
+  // write out each level info
+  TextLevelInfoMap::const_iterator here = levelInfo.begin();
+  TextLevelInfoMap::const_iterator end = levelInfo.end();
+  while (here != end) {
+    if (!(*here).second.Write (f)) return false;
+    
+    here++;
+  }
+
+  return true;
+}
+
+ostream &operator<<(ostream &s, const FTextLevel &l) {
+  TextLevelInfoMap::const_iterator here = l.levelInfo.begin ();
+  TextLevelInfoMap::const_iterator end = l.levelInfo.end ();
+  while (here != end) {
+    s << (*here).second;
+    here++;
+  }
+  
+  return s;
+}
+
+
+TextIdx::TextIdx () {
+  Clear ();
+}
+
+void TextIdx::Clear () {
+  start.Clear();
+  end.Clear();
+  which = 0;
+}
+
+#define TEXTIDXLEN (BITADDRLEN*2 + sizeof(char))
+
+bool TextIdx::Read (FILE *f, const TextLevelInfo &levelInfo,
+		    unsigned long docNum) {
+  if (!SeekTextIdx (f, levelInfo, docNum)) return false;
+  return Read (f);
+}
+
+bool TextIdx::Read (FILE *f) {
+  return (start.Read (f) && end.Read (f) && ReadUC (f, which));
+}
+
+bool TextIdx::Write (FILE *f) const {
+  return (start.Write (f) && end.Write (f) && WriteUC (f, which));
+}
+
+ostream &operator<<(ostream &s, const TextIdx &t) {
+  s << "start byte: " << t.start.byte << "\n";
+  s << "start bit:  " << (int)t.start.bit << "\n";
+  s << "end byte:   " << t.end.byte << "\n";
+  s << "end bit:    " << (int)t.end.bit << "\n";
+  s << "which:      " << (int)t.which << "\n\n";
+  
+  return s;
+}
+
+
+bool SeekTextIdx (FILE *f, const TextLevelInfo &levelInfo,
+		  unsigned long docNum) {
+  if (docNum == 0 || docNum > levelInfo.numEntries) return false;
+  
+  unsigned long seekPos = levelInfo.textIdxPtr + (docNum-1) * TEXTIDXLEN;
+  if (fseek (f, seekPos, SEEK_SET) != 0) return false;
+  
+  return true;
+}
+
+
+bool ReadTextIdxArray (FILE *f, TextIdxArray &a, unsigned long arrSize) {
+  // clear the array
+  a.erase (a.begin(), a.end());
+
+  // read in each element
+  TextIdx idx;
+  while (arrSize > 0) {
+    if (!idx.Read(f)) return false;
+    a.push_back (idx);
+    arrSize --;
+  }
+
+  return true;
+}
+
+bool WriteTextIdxArray (FILE *f, const TextIdxArray &a) {
+  TextIdxArray::const_iterator here = a.begin();
+  TextIdxArray::const_iterator end = a.end();
+  while (here != end) {
+    if (!(*here).Write(f)) return false;
+    here++;
+  }
+  
+  return true;
+}
+
+
+CompressTextInfo::CompressTextInfo () {
+  Clear();
+}
+
+void CompressTextInfo::Clear () {
+  ResetStart();
+  docPtrs.erase (docPtrs.begin(), docPtrs.end());
+}
+
+void CompressTextInfo::ResetStart () {
+  inDoc = false;
+  start.Clear();
+  which = 0;
+}
+  
+void CompressTextInfo::SetStart (unsigned long startPos,
+				 unsigned char startBit,
+				 unsigned char startWhich) {
+  // place an imaginary end tag if needed
+  // note: the document tag always needs a closing tag
+  if (inDoc) SetEnd (startPos, startBit);
+
+  // remember start of level
+  inDoc = true;
+  start.byte = startPos;
+  start.bit = startBit;
+  which = startWhich;
+}
+
+void CompressTextInfo::SetEnd (unsigned long endPos,
+			       unsigned char endBit) {
+  if (inDoc) {
+    // add completed entry to list of ptrs
+    TextIdx textIdx;
+    textIdx.start = start;
+    textIdx.end.byte = endPos;
+    textIdx.end.bit = endBit;
+    textIdx.which = which;
+    docPtrs.push_back (textIdx);
+    
+    // reset this entry
+    ResetStart();
+  }
+}
+
Index: /main/tags/2.25/gsdl/src/mgpp/text/FText.h
===================================================================
--- /main/tags/2.25/gsdl/src/mgpp/text/FText.h	(revision 21064)
+++ /main/tags/2.25/gsdl/src/mgpp/text/FText.h	(revision 21064)
@@ -0,0 +1,152 @@
+/**************************************************************************
+ *
+ * FText.h -- File structures for text compression
+ * Copyright (C) 1999  Rodger McNab
+ *
+ * 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.
+ *
+ * $Id$
+ *
+ **************************************************************************/
+
+#ifndef FTEXT_H
+#define FTEXT_H
+
+#if defined(GSDL_USE_OBJECTSPACE)
+#  include <ospace\std\map>
+#elif defined(GSDL_USE_STL_H)
+#  include <map.h>
+#else
+#  include <map>
+#endif
+
+#include <stdio.h>
+#include "UCArray.h"
+
+
+// holds a bit address
+class BitAddr {
+public:
+  unsigned long byte;
+  unsigned char bit;
+
+  BitAddr ();
+  void Clear ();
+
+  bool Read (FILE *f);
+  bool Write (FILE *f) const;
+};
+
+
+class TextLevelInfo {
+public:
+  UCArray levelTag;
+  unsigned long textIdxPtr;
+  unsigned long numEntries;
+
+  TextLevelInfo ();
+  void Clear ();
+
+  bool Read (FILE *f);
+  bool Write (FILE *f) const;
+};
+
+// stream output for debugging purposes
+ostream &operator<<(ostream &s, const TextLevelInfo &l);
+
+
+typedef map<UCArray, TextLevelInfo, LTUCArray> TextLevelInfoMap;
+
+
+class FTextLevel {
+public:
+  TextLevelInfoMap levelInfo;
+  
+  FTextLevel ();
+  void Clear ();
+
+  bool Read (FILE *f);
+  bool Write (FILE *f) const;
+};
+
+// stream output for debugging purposes
+ostream &operator<<(ostream &s, const FTextLevel &l);
+
+
+// the text.idx file points into the compressed text
+class TextIdx {
+public:
+  BitAddr start;       // the first bit of the compressed text
+  BitAddr end;         // the first bit past the end of the text
+  unsigned char which; // 0 = non-word, 1 = word
+  
+  TextIdx ();
+  void Clear ();
+
+  // does a seek and reads the appropriate record
+  bool Read (FILE *f, const TextLevelInfo &levelInfo,
+	     unsigned long docNum);
+
+  bool Read (FILE *f);
+  bool Write (FILE *f) const;
+};
+
+// stream output for debugging purposes
+ostream &operator<<(ostream &s, const TextIdx &t);
+
+
+// note: document numbers start at 1
+
+bool SeekTextIdx (FILE *f, const TextLevelInfo &levelInfo,
+		  unsigned long docNum);
+
+
+// used to store the pointers while compressing the text
+typedef vector<TextIdx> TextIdxArray;
+
+bool ReadTextIdxArray (FILE *f, TextIdxArray &a, unsigned long arrSize);
+bool WriteTextIdxArray (FILE *f, const TextIdxArray &a);
+
+
+// used to store information about a level while compressing the text
+class CompressTextInfo {
+public:
+  bool inDoc;
+  BitAddr start;
+  unsigned char which;
+  TextIdxArray docPtrs;
+
+  CompressTextInfo ();
+  void Clear ();
+
+  // clears inDoc, start, and which (not the docPtrs)
+  void ResetStart ();
+  
+  // set the start of a level (closing off the last opening
+  // tag if needed)
+  void SetStart (unsigned long startPos,
+		 unsigned char startBit,
+		 unsigned char startWhich);
+
+  // if in a document, it will set the end, add the document to the
+  // list of document ptrs, and then call ResetStart
+  void SetEnd (unsigned long endPos,
+	       unsigned char endBit);
+};
+
+typedef map<UCArray, CompressTextInfo, LTUCArray> CompressTextInfoMap;
+
+
+#endif
Index: /main/tags/2.25/gsdl/src/mgpp/text/FileBuf.cpp
===================================================================
--- /main/tags/2.25/gsdl/src/mgpp/text/FileBuf.cpp	(revision 21064)
+++ /main/tags/2.25/gsdl/src/mgpp/text/FileBuf.cpp	(revision 21064)
@@ -0,0 +1,49 @@
+/**************************************************************************
+ *
+ * FileBuf.cpp -- File buffer
+ * Copyright (C) 1999  Rodger McNab
+ *
+ * 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.
+ *
+ * $Id$
+ *
+ **************************************************************************/
+
+#include "FileBuf.h"
+#include "sysfuncs.h"
+
+
+bool FileBuf::NextBuf () {
+  if (fd < 0) return false;
+
+  int numbytes = read (fd, buf, FILEBUFSIZE);
+  if (numbytes < 0) numbytes = 0;
+  
+  here = buf;
+  end = here + numbytes;
+
+  return (numbytes > 0);
+}
+
+FileBuf::FileBuf () {
+  here = end = buf;
+  fd = -1;
+}
+
+void FileBuf::SetFD (int _fd) {
+  here = end = buf;
+  fd = _fd;
+}
+
Index: /main/tags/2.25/gsdl/src/mgpp/text/FileBuf.h
===================================================================
--- /main/tags/2.25/gsdl/src/mgpp/text/FileBuf.h	(revision 21064)
+++ /main/tags/2.25/gsdl/src/mgpp/text/FileBuf.h	(revision 21064)
@@ -0,0 +1,65 @@
+/**************************************************************************
+ *
+ * FileBuf.h -- File buffer
+ * Copyright (C) 1999  Rodger McNab
+ *
+ * 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.
+ *
+ * $Id$
+ *
+ **************************************************************************/
+
+#ifndef FILEBUF_H
+#define FILEBUF_H
+
+#define FILEBUFSIZE 65536
+
+
+class FileBuf {
+protected:
+  unsigned char buf[FILEBUFSIZE];
+  unsigned char *here;
+  unsigned char *end;
+
+  int fd;
+
+  // gets a new buffer if need be, returns true if
+  // more could be got. if true is returned the caller
+  // can assume that here != end
+  bool NextBuf ();
+  
+public:
+  FileBuf ();
+
+  void SetFD (int _fd);
+
+  inline bool Get (unsigned char &c) {
+    if (here != end || NextBuf()) { c = *here++; return true; }
+    return false;
+  }
+  
+  inline bool Peek (unsigned char &c) {
+    if (here != end || NextBuf()) { c = *here; return true; }
+    return false;
+  }
+
+  inline bool Next () {
+    if (here != end || NextBuf()) { here++; return true; }
+    return false;
+  }
+};
+
+
+#endif
Index: /main/tags/2.25/gsdl/src/mgpp/text/FragLevelConvert.cpp
===================================================================
--- /main/tags/2.25/gsdl/src/mgpp/text/FragLevelConvert.cpp	(revision 21064)
+++ /main/tags/2.25/gsdl/src/mgpp/text/FragLevelConvert.cpp	(revision 21064)
@@ -0,0 +1,107 @@
+/**************************************************************************
+ *
+ * FragLevelConvert.cpp -- converting between fragment and document numbers
+ * Copyright (C) 1999  Rodger McNab
+ *
+ * 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.
+ *
+ * $Id$
+ *
+ **************************************************************************/
+
+#include "FragLevelConvert.h"
+#include "bitio_m_stdio.h"
+#include "bitio_gen.h"
+
+
+FragLevelConvert::FragLevelConvert () {
+  numFrags = 0;
+  numLevelDocs = 0;
+}
+
+bool FragLevelConvert::Read (FILE *invfFile,
+			     unsigned long levelPtr,
+			     unsigned long _numFrags,
+			     unsigned long _numLevelDocs) {
+  levelStarts.erase (levelStarts.begin(), levelStarts.end());
+  numFrags = _numFrags;
+  numLevelDocs = _numLevelDocs;
+
+  // seek to the appropriate place in the inverted file
+  fseek (invfFile, levelPtr, SEEK_SET);
+
+  stdio_bitio_buffer buffer(invfFile);
+  
+  unsigned long pTag = numLevelDocs*2;
+  unsigned long B = BIO_Bblock_Init (numFrags+pTag, pTag);
+  unsigned long fragNum = 0;
+  unsigned long i;
+  for (i=0; i<numLevelDocs; i++) {
+    unsigned long delta = buffer.bblock_decode (B, NULL)-1;
+    fragNum += delta;
+
+    levelStarts.push_back (fragNum);
+
+    // ignore end, assume every fragment is in a level
+    delta = buffer.bblock_decode (B, NULL)-1;
+    fragNum += delta;
+  }
+
+  // fragNum would be the starting fragment of the next document
+  // if there was one
+  levelStarts.push_back (fragNum);
+  
+  buffer.done();
+
+  return true;
+}
+
+bool FragLevelConvert::FragToLevel (unsigned long fragNum,
+				    unsigned long &levelDocNum) const {
+  // do binary search for something containing this fragment number
+  unsigned long low = 1, high = numLevelDocs;
+  unsigned long mid;
+
+  while ((mid = (low+high)/2) >= 1 && low <= high) {
+    if (fragNum > levelStarts[mid]) low = mid+1;
+    else if (fragNum <= levelStarts[mid-1]) high = mid-1;
+    else {
+      levelDocNum = mid;
+      return true;
+    }
+  }
+  return false;
+}
+
+
+bool FragLevelConvert::LevelToLevel (FragLevelConvert sectionLevelConvert,
+		 unsigned long levelNum, unsigned long &DocNum) {
+  
+  if (levelNum==1) {
+    DocNum=1;
+    return true;
+  }
+  unsigned long levelfragnum = sectionLevelConvert.levelStarts[levelNum-1]+1;
+
+  if (FragToLevel(levelfragnum, DocNum)) {
+    return true;
+  } 
+  return false;
+  
+
+}
+
+
+
Index: /main/tags/2.25/gsdl/src/mgpp/text/FragLevelConvert.h
===================================================================
--- /main/tags/2.25/gsdl/src/mgpp/text/FragLevelConvert.h	(revision 21064)
+++ /main/tags/2.25/gsdl/src/mgpp/text/FragLevelConvert.h	(revision 21064)
@@ -0,0 +1,73 @@
+/**************************************************************************
+ *
+ * FragLevelConvert.h -- converting between fragment and document numbers
+ * Copyright (C) 1999  Rodger McNab
+ *
+ * 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.
+ *
+ * $Id$
+ *
+ **************************************************************************/
+
+#ifndef FRAGLEVELCONVERT_H
+#define FRAGLEVELCONVERT_H
+
+#include <stdio.h>
+#include "UCArray.h"
+
+
+/*Notes about levelStarts (kjm18) - this is my interpretation of
+whats going on, feel free to correct this if its wrong.
+
+say you have 5 docs, consisting of fragments:
+1:  1-55
+2: 56-83
+3: 84-106
+4: 107-152
+5: 153-211
+
+then levelStarts would have the values
+0  1  2   3   4   5 
+?  55 83 106 152 211
+I dont know whats in position 0.
+
+*/
+class FragLevelConvert {
+protected:
+  // note fragment start is one before before real start
+  vector<unsigned long> levelStarts;
+  unsigned long numFrags;
+  unsigned long numLevelDocs;
+  
+public:
+  FragLevelConvert ();
+
+  bool Read (FILE *invfFile, unsigned long levelPtr,
+	     unsigned long _numFrags, unsigned long _numLevelDocs);
+
+  bool FragToLevel (unsigned long fragNum, unsigned long &levelDocNum) const;
+
+  // this function converts from one level number to another
+  // the FragLevelConvert thats calling the method should be loaded with
+  // the level that you want to convert to, while the sectionLevelConvert
+  // should be loaded with the level converting from.
+  // level Num has the old level, DocNum will be returned with the new
+  // coresponding level
+  bool LevelToLevel (FragLevelConvert sectionLevelConvert,
+		   unsigned long levelNum, unsigned long &DocNum);
+};
+
+
+#endif
Index: /main/tags/2.25/gsdl/src/mgpp/text/GSDLQueryLex.cpp
===================================================================
--- /main/tags/2.25/gsdl/src/mgpp/text/GSDLQueryLex.cpp	(revision 21064)
+++ /main/tags/2.25/gsdl/src/mgpp/text/GSDLQueryLex.cpp	(revision 21064)
@@ -0,0 +1,200 @@
+/**************************************************************************
+ *
+ * GSDLQueryLex.cpp -- Lexical analyser for a simple query language
+ * Copyright (C) 2000  Rodger McNab
+ *
+ * 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.
+ *
+ * $Id$
+ *
+ **************************************************************************/
+
+#include "GSDLQueryLex.h"
+#include "unitool.h"
+#include "words.h"
+
+inline void AddNChar (UCArray::const_iterator &here,
+		      UCArray &text,
+		      int len) {
+  while (len > 0) {
+    text.push_back (*here++);
+    len--;
+  }
+}
+
+static bool ParseInteger (UCArray::const_iterator &here,
+			  UCArray::const_iterator end,
+			  LexEl &el) {
+  el.Clear();
+
+  // this version of end is used in unitool
+  UCArray::const_iterator endMinus1 = end-1;
+
+  int charLen;
+  unsigned short c; // one character lookahead
+  charLen = parse_utf8_char (here, endMinus1, &c);
+
+  // check for positive or negative
+  bool neg = false;
+  if (c == '+') {
+    AddNChar (here, el.text, charLen);
+    charLen = parse_utf8_char (here, endMinus1, &c);
+  } else if (c == '-') {
+    neg = true;
+    AddNChar (here, el.text, charLen);
+    charLen = parse_utf8_char (here, endMinus1, &c);
+  }
+
+  // read in number part
+  el.num = 0;
+  el.lexType = IntegerE;
+  while (c >= '0' && c <= '9') {
+    el.num = el.num*10 + c - '0';
+    AddNChar (here, el.text, charLen);
+    charLen = parse_utf8_char (here, endMinus1, &c);
+  }
+
+  if (neg) el.num *= -1;
+
+  return (!el.text.empty());
+}
+
+static bool ParseTerm (UCArray::const_iterator &here,
+		       UCArray::const_iterator end,
+		       UCArray &text) {
+  UCArray::const_iterator endMinus1 = end-1;
+  here = ParseIndexWord (here, endMinus1, text);
+  return !text.empty();
+}
+
+
+bool ParseLexEl (UCArray::const_iterator &here,
+		 UCArray::const_iterator end,
+		 LexEl &el) {
+  el.Clear();
+
+  // strange things can happen if here == end == 0
+  if (here == end) return false;
+  
+  // this version of end is used in unitool
+  UCArray::const_iterator endMinus1 = end-1;
+  
+  // ignore all white space
+  int charLen;
+  unsigned short c; // one character lookahead
+  charLen = parse_utf8_char (here, endMinus1, &c);
+  while (here != end && is_unicode_space (c)) {
+    here += charLen;
+    charLen = parse_utf8_char (here, endMinus1, &c);
+  }
+  if (here == end) return false;
+
+  if (c == '(') {
+    el.lexType = OpenBracketE;
+    AddNChar (here, el.text, charLen);
+    return true;
+    
+  } else if (c == ')') {
+    el.lexType = CloseBracketE;
+    AddNChar (here, el.text, charLen);
+    return true;
+
+  } else if (c =='[') {
+    el.lexType = OpenSquareBracketE;
+    AddNChar (here, el.text, charLen);
+    return true;
+  
+  } else if (c ==']') {
+    el.lexType = CloseSquareBracketE;
+    AddNChar (here, el.text, charLen);
+    return true;
+  
+  } else if (c == '\"') {
+    el.lexType = QuoteE;
+    AddNChar (here, el.text, charLen);
+    return true;
+    
+  } else if (c == '/') {
+    el.lexType = TermWeightE;
+    AddNChar (here, el.text, charLen);
+    return true;
+    
+  } else if (c == '#') {
+    el.lexType = StemMethodE;
+    AddNChar (here, el.text, charLen);
+    return true;
+    
+  } else if (c == '^') {
+    el.lexType = RangeE;
+    AddNChar (here, el.text, charLen);
+    return true;
+    
+  } else if (c == '@') {
+    el.lexType = AtE;
+    AddNChar (here, el.text, charLen);
+    return true;
+    
+  } else if (c == ':') {
+    el.lexType = TagE;
+    AddNChar (here, el.text, charLen);
+    return true;
+    
+  } else if (c=='&') {
+    el.lexType = AndOpE;
+    AddNChar (here, el.text, charLen);
+    return true;
+    
+  } else if (c == '|') {
+    el.lexType = OrOpE;
+    AddNChar (here, el.text, charLen);
+    return true;
+    
+  } else if (c == '!') {
+    el.lexType = NotOpE;
+    AddNChar (here, el.text, charLen);
+    return true;
+    
+  } else if (c == '+' || c == '-' ||
+	     (c >= '0' && c <= '9')) {
+    return ParseInteger (here, end, el);
+  }
+
+  // assume it is a term of some sort
+  if (!ParseTerm (here, end, el.text)) return false;
+
+  UCArray AND; SetCStr (AND, "AND");
+  if (el.text == AND) {
+    el.lexType = AndOpE;
+    return true;
+  }
+  UCArray OR; SetCStr (OR, "OR");
+  if (el.text == OR) {
+    el.lexType = OrOpE;
+    return true;
+  }
+  UCArray NOT; SetCStr (NOT, "NOT");
+  if (el.text == NOT) {
+    el.lexType = NotOpE;
+    return true;
+  }
+  UCArray NEAR; SetCStr (NEAR, "NEAR");
+  if (PrefixLen(el.text, NEAR)==4) {
+    el.lexType = NearOpE;
+    return true;
+  }
+  el.lexType = TermE;
+  return true;
+}
+
Index: /main/tags/2.25/gsdl/src/mgpp/text/GSDLQueryLex.h
===================================================================
--- /main/tags/2.25/gsdl/src/mgpp/text/GSDLQueryLex.h	(revision 21064)
+++ /main/tags/2.25/gsdl/src/mgpp/text/GSDLQueryLex.h	(revision 21064)
@@ -0,0 +1,65 @@
+/**************************************************************************
+ *
+ * GSDLQueryLex.h -- Lexical analyser for a simple query language, for GSDL
+ * Copyright (C) 2000  Rodger McNab
+ *
+ * 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.
+ *
+ * $Id$
+ *
+ **************************************************************************/
+
+#ifndef GSDLQUERYLEX_H
+#define GSDLQUERYLEX_H
+
+#include "UCArray.h"
+
+
+// note: white space is ignored
+enum LexType {NoTypeE, OpenBracketE, CloseBracketE, TermE, AndOpE, OrOpE,
+	      NotOpE, NearOpE, QuoteE, IntegerE, TermWeightE, StemMethodE,
+	      RangeE, AtE, TagE, OpenSquareBracketE, CloseSquareBracketE};
+
+struct LexEl {
+  LexType lexType;
+  UCArray text;
+  int num; // for IntegerE
+
+  void Clear () {
+    lexType = NoTypeE;
+    UCArrayClear (text);
+    num = 0;
+  }
+  LexEl () { Clear (); }
+};
+
+
+// returns true if another lexical element could be parsed.
+bool ParseLexEl (UCArray::const_iterator &here,
+		 UCArray::const_iterator end,
+		 LexEl &el);
+
+
+#endif
+
+
+
+
+
+
+
+
+
+
Index: /main/tags/2.25/gsdl/src/mgpp/text/GSDLQueryParser.cpp
===================================================================
--- /main/tags/2.25/gsdl/src/mgpp/text/GSDLQueryParser.cpp	(revision 21064)
+++ /main/tags/2.25/gsdl/src/mgpp/text/GSDLQueryParser.cpp	(revision 21064)
@@ -0,0 +1,374 @@
+/**************************************************************************
+ *
+ * QueryParser.cpp -- Query parser for a simple query language
+ * Copyright (C) 2000  Rodger McNab
+ *
+ * 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.
+ *
+ * $Id$
+ *
+ **************************************************************************/
+
+#include "GSDLQueryParser.h"
+#include "GSDLQueryLex.h"
+
+
+static QueryNode *ParseExpression (UCArray::const_iterator &here,
+				   UCArray::const_iterator end, 
+				   int defaultStemMethod);
+
+static QueryNode *AndAdd (QueryNode *t1, QueryNode *t2) {
+  if (t1 == NULL) return t2;
+  if (t2 == NULL) return t1;
+
+  AndQueryNode *andNode = new AndQueryNode;
+  andNode->leftNode = t1;
+  andNode->rightNode = t2;
+  return andNode;
+}
+
+static QueryNode *OrAdd (QueryNode *t1, QueryNode *t2) {
+  if (t1 == NULL) return t2;
+  if (t2 == NULL) return t1;
+
+  OrQueryNode *orNode = new OrQueryNode;
+  orNode->leftNode = t1;
+  orNode->rightNode = t2;
+  return orNode;
+}
+
+static QueryNode *NotAdd (QueryNode *t1, QueryNode *t2) {
+  if (t1 == NULL) return t2;
+  if (t2 == NULL) return t1;
+
+  NotQueryNode *notNode = new NotQueryNode;
+  notNode->queryNode = t1;
+  notNode->notNode = t2;
+  return notNode;
+}
+
+// expects the opening bracket to have already been parsed
+// and discarded
+static QueryNode *ParseBracketExpression (UCArray::const_iterator &here,
+					  UCArray::const_iterator end, 
+					  int defaultStemMethod) {
+  // get everything in the expression
+  QueryNode *curTree = ParseExpression (here, end, defaultStemMethod);
+  
+  // gobble up tokens until a closing bracket is found
+  // or the end of the string
+  LexEl el;
+  while (ParseLexEl (here, end, el)) {
+    if (el.lexType == CloseBracketE) break;
+  }
+
+  return curTree;
+}
+
+static int ParseInt (UCArray::const_iterator &here,
+		     UCArray::const_iterator end) {
+  LexEl el;
+  UCArray::const_iterator oldHere = here;
+  if (ParseLexEl (here, end, el) && el.lexType == IntegerE)
+    return el.num;
+  
+  here = oldHere; // not an integer
+  return 0;
+}
+
+// default is within 20 words
+static void SetRangeValues (TermNode &termNode,
+			    UCArray &near) {
+  UCArray NEAR; SetCStr(NEAR, "NEAR");
+  if (near == NEAR) { // no modifier
+    termNode.startRange = -21;
+    termNode.endRange = 20;
+  }
+  else { // extract number
+    UCArray::const_iterator here = near.begin()+4;
+    UCArray::const_iterator end = near.end();
+    int size=0;
+    while (here != end) {
+      size = size*10 + (*here-'0');
+      here++;
+    }
+    cerr <<"size= "<<size<<endl;
+    termNode.startRange = -1 * (size+1);
+    termNode.endRange = size;
+  }
+
+
+}
+static unsigned long GetStemMethod(LexEl &el, int defaultStemMethod) {
+  // here expect el to contain some of c,s,i,u
+  // stem method 0 = c,u  00
+  // stem method 1 = i,u  01  - default for DL
+  // stem method 2 = c, s  10
+  // stem method 3 = i,s  11
+
+  unsigned long stem = (unsigned long)defaultStemMethod;
+      
+  UCArray::const_iterator here = el.text.begin();
+  UCArray::const_iterator end = el.text.end();
+
+  unsigned char c1 = *here; 
+  if (!(c1 == 'c'| c1 == 'i' | c1 == 'u' | c1 == 's')) 
+    return 4; // incorrect format
+  
+  here++;
+  unsigned char c2 = 'a';
+  if (here !=end) {
+    c2 = *here;
+    if (!(c2 == 'c'| c2 == 'i' | c2 == 'u' | c2 == 's')) 
+      return 4; // incorrect format
+  }
+  
+  if (c1 == 'i'|| c2=='i') stem |= 1; // set bit 0 to 1
+  if (c1 == 'c' || c2 == 'c') stem &=0xe; //set bit 0 to 0
+  if (c1 == 's'|| c2 == 's') stem |= 2; // set bit 1 to 1
+  if (c1 == 'u' || c2 =='u') stem &=0xd; // set bit 1 to 0
+  cerr << "stem is "<<stem<<endl;
+  return stem;
+}
+  
+
+static void ParseTermModifiers (UCArray::const_iterator &here,
+				UCArray::const_iterator end,
+				TermNode &termNode,
+				int defaultStemMethod) {
+ 
+  termNode.stemMethod = defaultStemMethod;
+
+  LexEl el;
+  UCArray::const_iterator oldHere = here;
+  while (ParseLexEl (here, end, el)) {
+    if (el.lexType == TermWeightE) {
+      termNode.termWeight = ParseInt (here, end);
+      
+    } else if (el.lexType == StemMethodE) {
+      oldHere = here;
+      LexEl stem;
+      if (ParseLexEl (here, end, stem) && stem.lexType == TermE) {
+	termNode.stemMethod = GetStemMethod(stem, defaultStemMethod);
+	if (termNode.stemMethod == 4) { // error so backtrack
+	  here = oldHere;
+	  termNode.stemMethod = (unsigned long)defaultStemMethod;
+	} 
+      }else here = oldHere; //ignore - wrong syntax
+
+    } else if (el.lexType == RangeE) {
+      termNode.startRange = ParseInt (here, end);
+      termNode.endRange = ParseInt (here, end);
+      
+    } else if (el.lexType == AtE) {
+      termNode.startRange = termNode.endRange = ParseInt (here, end);
+      
+    } else {
+      // no term modifiers
+      here = oldHere;
+      break;
+    }
+    
+    oldHere = here;
+  }  
+}
+
+static void ParseProxModifiers (UCArray::const_iterator &here,
+				UCArray::const_iterator end,
+				ProxMatchQueryNode *proxNode) {
+  // so far only have one - the tag stuff
+  LexEl el;
+  UCArray::const_iterator oldHere = here;
+  while (ParseLexEl (here, end, el)) {
+    if (el.lexType == TagE) {
+      oldHere = here; // don't backtrack past here
+      if (ParseLexEl (here, end, el) && el.lexType == TermE) {
+	proxNode->tagNodePtr = new TagNode;
+	proxNode->tagNodePtr->tagName = el.text;
+	
+      }
+      else { // error in tag
+	here = oldHere;
+      }
+    } // TagE
+    // add in other cases here
+    else {
+      // no modifiers
+      here = oldHere;
+      break;
+    }
+    oldHere = here;
+  }//while
+
+
+}
+
+// expects starting brackets to have been parsed
+static void ParseSquareBrackets(UCArray::const_iterator &here,
+				UCArray::const_iterator end,
+				ProxMatchQueryNode *proxNode,
+				int defaultStemMethod) {
+
+  LexEl el;
+  while (ParseLexEl (here, end, el)) {
+    if (el.lexType == TermE || el.lexType == IntegerE) {
+      TermNode termNode;
+      termNode.term = el.text;
+      ParseTermModifiers (here, end, termNode, defaultStemMethod);
+      proxNode->terms.push_back(termNode);
+    }
+    else if (el.lexType == CloseSquareBracketE) {
+      break;
+    }
+    else if (el.lexType == AndOpE) {
+      // ignore, the words are AND'ed anyway
+      cerr << "and inside []\n";
+    }
+    else if (el.lexType == OrOpE) {
+      cerr << "or inside []\n";
+    }
+    else {
+      //error
+      // just ignore for now
+      cerr <<"bad syntax inside []\n";
+    }
+  } // while
+
+}
+// expects the starting quote to have been parsed
+// and discarded
+// is now for exact phrases
+static void ParsePhrase (UCArray::const_iterator &here,
+			 UCArray::const_iterator end,
+			 ProxMatchQueryNode &proxNode) {
+  LexEl el;
+  bool first = true;
+  while (ParseLexEl (here, end, el)) {
+    if (el.lexType == TermE || el.lexType == IntegerE) {
+      TermNode termNode;
+      termNode.term = el.text;
+      //ParseTermModifiers (here, end, termNode);
+      if (first) {
+	first = false;
+      }
+      else {
+	termNode.startRange = -2;
+	termNode.endRange = -1;
+      }
+      proxNode.terms.push_back (termNode);
+      
+    } else if (el.lexType == QuoteE) {
+      break;
+      
+    } else {
+      // error
+      break;
+    }
+  }
+}
+
+static QueryNode *ParseTerm (UCArray::const_iterator &here,
+			     UCArray::const_iterator end,
+			     int defaultStemMethod) {
+  LexEl el;
+
+  UCArray::const_iterator oldHere = here;
+  if (!ParseLexEl (here, end, el)) return NULL;
+
+  if (el.lexType == OpenBracketE)
+    return ParseBracketExpression (here, end, defaultStemMethod);
+
+  ProxMatchQueryNode *proxNode = new ProxMatchQueryNode;
+
+  if (el.lexType == TermE || el.lexType == IntegerE) {
+    TermNode termNode;
+    termNode.term = el.text;
+    ParseTermModifiers (here, end, termNode, defaultStemMethod);
+    oldHere = here;  // dont backtrack past here
+    if (ParseLexEl(here, end, el) && el.lexType == NearOpE) {
+      delete proxNode;
+      proxNode = (ProxMatchQueryNode *)ParseTerm(here, end, defaultStemMethod);
+      SetRangeValues(termNode, el.text);
+      proxNode->terms.push_back (termNode);
+      return proxNode;
+    }
+    else {
+      here = oldHere; // backtrack
+      proxNode->terms.push_back (termNode);
+      ParseProxModifiers(here, end, proxNode);
+      return proxNode;
+    }
+  } else if (el.lexType == QuoteE) {
+    ParsePhrase (here, end, *proxNode);
+    return proxNode;
+  }
+  else if (el.lexType == OpenSquareBracketE) {
+    ParseSquareBrackets (here, end, proxNode, defaultStemMethod);
+    ParseProxModifiers (here, end, proxNode);
+    return proxNode;
+  }
+
+  // not a term
+  here = oldHere;
+  delete proxNode;
+  return NULL;
+}
+
+
+static QueryNode *ParseExpression (UCArray::const_iterator &here,
+				   UCArray::const_iterator end,
+				   int defaultStemMethod) {
+  LexEl el;
+  QueryNode *curTree = NULL;
+
+  UCArray::const_iterator oldHere = here;
+  while (ParseLexEl (here, end, el)) {
+    if (el.lexType == OpenSquareBracketE ||
+	el.lexType == OpenBracketE ||
+	el.lexType == TermE ||
+	el.lexType == QuoteE ||
+	el.lexType == IntegerE ) {
+	//	el.lexType == TagE) { //tag at end of term now
+      // some type of term, back track and parse it
+      here = oldHere;
+      curTree = OrAdd (curTree, ParseTerm (here, end, defaultStemMethod));
+      
+    } else if (el.lexType == AndOpE) {
+      curTree = AndAdd (curTree, ParseTerm (here, end, defaultStemMethod));
+      
+    } else if (el.lexType == OrOpE) {
+      curTree = OrAdd (curTree, ParseTerm (here, end, defaultStemMethod));
+      
+    } else if (el.lexType == NotOpE) {
+      curTree = NotAdd (curTree, ParseTerm (here, end, defaultStemMethod));
+      
+    } else if (el.lexType == CloseBracketE) {
+      // parsebracketexpression is waiting for the last bracket, so put it back
+      here = oldHere;
+      break;
+    
+    } else break;
+    
+    oldHere = here;
+  }
+
+  return curTree;
+}
+
+QueryNode *ParseQuery (const UCArray &queryStr, int defaultStemMethod) {
+  UCArray::const_iterator here = queryStr.begin();
+  UCArray::const_iterator end = queryStr.end();
+  return ParseExpression (here, end, defaultStemMethod);
+}
Index: /main/tags/2.25/gsdl/src/mgpp/text/GSDLQueryParser.h
===================================================================
--- /main/tags/2.25/gsdl/src/mgpp/text/GSDLQueryParser.h	(revision 21064)
+++ /main/tags/2.25/gsdl/src/mgpp/text/GSDLQueryParser.h	(revision 21064)
@@ -0,0 +1,36 @@
+/**************************************************************************
+ *
+ * QueryParser.h -- Query parser for a simple query language
+ * Copyright (C) 2000  Rodger McNab
+ *
+ * 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.
+ *
+ * $Id$
+ *
+ **************************************************************************/
+
+#ifndef GSDLQUERYPARSER_H
+#define GSDLQUERYPARSER_H
+
+#include "UCArray.h"
+#include "MGQuery.h"
+
+// returns NULL if the query could not be parsed
+// defaultStemMethod used to set stemming and casefolding for terms where
+// its not set explicitly in the query string. THe defaultStemMethod value
+// should be set using the values from the preferences page
+QueryNode *ParseQuery (const UCArray &queryStr, int defaultStemMethod);
+
+#endif
Index: /main/tags/2.25/gsdl/src/mgpp/text/IndexData.cpp
===================================================================
--- /main/tags/2.25/gsdl/src/mgpp/text/IndexData.cpp	(revision 21064)
+++ /main/tags/2.25/gsdl/src/mgpp/text/IndexData.cpp	(revision 21064)
@@ -0,0 +1,209 @@
+/**************************************************************************
+ *
+ * IndexData.cpp -- Information needed for querying
+ * Copyright (C) 1999 Rodger McNab
+ *
+ * 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.
+ *
+ * $Id$
+ *
+ **************************************************************************/
+
+#include "IndexData.h"
+#include "string.h"
+#include "mg_files.h"
+
+IndexData::IndexData () {
+  basePath[0] = '\0';
+  filename[0] = '\0';
+
+  dictFile = NULL;
+
+  stem1File = NULL;
+  stem2File = NULL;
+  stem3File = NULL;
+
+  invfFile = NULL;
+
+  approxWeightsFile = NULL;
+  exactWeightsFile = NULL;
+
+  curLevelNum = 0;
+}
+
+IndexData::~IndexData () {
+  UnloadData ();
+}
+
+bool IndexData::LoadData (const char *_basePath, const char *_filename) {
+  if (_filename[0] == '\0') return false;
+  
+  // make sure this data has not already been loaded
+  if (strcmp (_basePath, basePath) == 0 &&
+      strcmp (_filename, filename) == 0) return true;
+  
+  // make sure there is nothing else loaded
+  UnloadData ();
+
+  strcpy (basePath, _basePath);
+  strcpy (filename, _filename);
+
+  set_basepath (basePath);
+
+  // load in the level information
+  FILE *ivfLevelFile;
+  ivfLevelFile = open_file (filename, INVF_LEVEL_SUFFIX, "rb",
+			    MAGIC_INVF_LEVELS, MG_ABORT);
+  levels.Read (ivfLevelFile);
+  fclose (ivfLevelFile);
+
+  // blocked dictionary
+  dictFile = open_file (filename, INVF_DICT_BLOCKED_SUFFIX, "rb",
+			MAGIC_STEM, MG_ABORT);
+  if (!bdh.Read (dictFile)) { UnloadData (); return false; }
+
+  fseek (dictFile, bdh.wblk_idx_start, SEEK_SET);
+  if (!ReadBlockIdx (dictFile, biWords)) { UnloadData (); return false; }
+
+  fseek (dictFile, bdh.tblk_idx_start, SEEK_SET);
+  if (!ReadBlockIdx (dictFile, biTags)) { UnloadData (); return false; }
+
+  // blocked stem index 1
+  stem1File = open_file (filename, INVF_DICT_BLOCKED_1_SUFFIX,
+			 "rb", MAGIC_STEM_1, MG_ABORT);
+  if (!sih1.Read (stem1File)) { UnloadData (); return false; }
+
+  fseek (stem1File, sih1.block_idx_start, SEEK_SET);
+  if (!ReadBlockIdx (stem1File, sii1)) { UnloadData (); return false; }
+  
+  // blocked stem index 2
+  stem2File = open_file (filename, INVF_DICT_BLOCKED_2_SUFFIX,
+			 "rb", MAGIC_STEM_2, MG_ABORT);
+  if (!sih2.Read (stem2File)) { UnloadData (); return false; }
+
+  fseek (stem2File, sih2.block_idx_start, SEEK_SET);
+  if (!ReadBlockIdx (stem2File, sii2)) { UnloadData (); return false; }
+  
+  // blocked stem index 3
+  stem3File = open_file (filename, INVF_DICT_BLOCKED_3_SUFFIX,
+			 "rb", MAGIC_STEM_3, MG_ABORT);
+  if (!sih3.Read (stem3File)) { UnloadData (); return false; }
+
+  fseek (stem3File, sih3.block_idx_start, SEEK_SET);
+  if (!ReadBlockIdx (stem3File, sii3)) { UnloadData (); return false; }
+
+  // inverted file
+  invfFile = open_file (filename, INVF_SUFFIX, "rb",
+			MAGIC_INVF, MG_ABORT);
+  ifh.Read (invfFile);
+
+  // weights
+  approxWeightsFile = open_file (filename, APPROX_WEIGHTS_SUFFIX, "rb",
+				 MAGIC_WGHT_APPROX, MG_ABORT);
+  exactWeightsFile = open_file (filename, WEIGHTS_SUFFIX, "rb",
+				MAGIC_WGHT, MG_ABORT);
+
+  return true;
+}
+
+bool IndexData::UnloadData () {
+  basePath[0] = '\0';
+  filename[0] = '\0';
+
+  if (dictFile != NULL) {
+    fclose (dictFile); dictFile = NULL;
+  }
+
+  if (stem1File != NULL) {
+    fclose (stem1File); stem1File = NULL;
+  }
+  if (stem2File != NULL) {
+    fclose (stem2File); stem2File = NULL;
+  }
+  if (stem3File != NULL) {
+    fclose (stem3File); stem3File = NULL;
+  }
+
+  if (invfFile != NULL) {
+    fclose (invfFile); invfFile = NULL;
+  }
+
+  if (approxWeightsFile != NULL) {
+    fclose (approxWeightsFile); approxWeightsFile = NULL;
+  }
+  if (exactWeightsFile != NULL) {
+    fclose (exactWeightsFile); exactWeightsFile = NULL;
+  }
+
+  UnloadLevel();
+  
+  return true;
+}
+
+
+bool IndexData::LoadLevel (const UCArray &level) {
+  // make sure this level is not already loaded
+  if (level == curLevel) return true;
+
+  // unload any levels currently loaded
+  UnloadLevel();
+
+  // make sure the required files are open
+  if (dictFile == NULL || invfFile == NULL ||
+      approxWeightsFile == NULL || exactWeightsFile == NULL)
+    return false;
+  
+  // read in the information from the dictionary
+  block_dict_el tagEl;
+  unsigned long tagElNum;
+  if (!SearchBlockDictEl (dictFile, biTags, bdh.entries_per_tblk,
+			  bdh.tag_dict_size, level, tagEl, tagElNum))
+    return false;
+
+  // read in the level conversion information
+  if (!levelConverter.Read (invfFile, tagEl.invf_ptr,
+			    bdh.num_frags, tagEl.frag_occur))
+    return false;
+
+  // read in the approximate weights
+  if (!weightData.Read (approxWeightsFile,
+			levels.levelInfo[level].approxWeightsDiskPtr,
+			levels.levelInfo[level].numEntries))
+    return false;
+  
+  // find the level number
+  curLevelNum = 0;
+  IvfLevelInfoMap::const_iterator levelHere, levelEnd;
+  for (levelHere=levels.levelInfo.begin(), levelEnd=levels.levelInfo.end();
+       levelHere!=levelEnd && (*levelHere).first != level; levelHere++)
+    curLevelNum++;
+
+  // make sure we found the level
+  if (levelHere == levelEnd) return false;
+
+  curLevel = level;
+
+  return true;
+}
+
+bool IndexData::UnloadLevel () {
+  curLevel.erase (curLevel.begin(), curLevel.end());
+  curLevelNum = 0;
+  
+  weightData.Free ();
+    
+  return true;
+}
+
Index: /main/tags/2.25/gsdl/src/mgpp/text/IndexData.h
===================================================================
--- /main/tags/2.25/gsdl/src/mgpp/text/IndexData.h	(revision 21064)
+++ /main/tags/2.25/gsdl/src/mgpp/text/IndexData.h	(revision 21064)
@@ -0,0 +1,84 @@
+/**************************************************************************
+ *
+ * IndexData.h -- Information needed for querying
+ * Copyright (C) 1999 Rodger McNab
+ *
+ * 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.
+ *
+ * $Id$
+ *
+ **************************************************************************/
+
+#ifndef INDEXDATA_H
+#define INDEXDATA_H
+
+#include <stdio.h>
+#include "invf.h"
+#include "FIvfLevelInfo.h"
+#include "FragLevelConvert.h"
+#include "Weights.h"
+
+
+class IndexData {
+public:
+  // general information
+  char basePath[512];
+  char filename[512];
+  FIvfLevel levels;
+  
+  // blocked dictionary
+  FILE *dictFile;
+  block_dict_header bdh;
+  block_idx biWords;
+  block_idx biTags;
+
+  // stem indexes
+  FILE *stem1File;
+  FILE *stem2File;
+  FILE *stem3File;
+  stem_idx_header sih1;
+  stem_idx_header sih2;
+  stem_idx_header sih3;
+  block_idx sii1;
+  block_idx sii2;
+  block_idx sii3;
+
+  // inverted file
+  FILE *invfFile;
+  invf_file_header ifh;
+
+  // weights
+  FILE *approxWeightsFile;
+  FILE *exactWeightsFile;
+
+  // level specific information
+  UCArray curLevel; // last level that was loaded
+  unsigned long curLevelNum;
+  FragLevelConvert levelConverter;
+  ApproxWeightsData weightData;
+  
+  IndexData ();
+  ~IndexData ();
+
+  // LoadData will only load the data if it has not been loaded before
+  bool LoadData (const char *_basePath, const char *_filename);
+  bool UnloadData ();
+
+  bool LoadLevel (const UCArray &level);
+  bool UnloadLevel ();
+};
+
+
+#endif
Index: /main/tags/2.25/gsdl/src/mgpp/text/MGQuery.cpp
===================================================================
--- /main/tags/2.25/gsdl/src/mgpp/text/MGQuery.cpp	(revision 21064)
+++ /main/tags/2.25/gsdl/src/mgpp/text/MGQuery.cpp	(revision 21064)
@@ -0,0 +1,748 @@
+/**************************************************************************
+ *
+ * MGQuery.cpp -- Query related functions
+ * Copyright (C) 1999  Rodger McNab
+ *
+ * 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.
+ *
+ * $Id$
+ *
+ **************************************************************************/
+
+#include "MGQuery.h"
+#include "bitio_m_stdio.h"
+#include "bitio_gen.h"
+#include "Terms.h"
+#include "QueryResultsSort.h"
+#include <assert.h>
+
+
+void PrintIndent (ostream &s, int indent) {
+  while (indent-- > 0) s << " ";
+}
+
+
+void PrintIndentText (ostream &s, char *text, int indent) {
+  PrintIndent (s, indent);
+  s << text;
+}
+
+void PrintNode (ostream &s, QueryNode *node, int indent) {
+  if (node == NULL) {
+    PrintIndentText (s, "NULL\n", indent);
+  } else {
+    node->Print (s, indent+2);
+  }
+}
+
+
+
+QueryNode::QueryNode () {
+}
+
+QueryNode::~QueryNode () {
+}
+
+void QueryNode::Calculate (IndexData &/*indexData*/,
+			   const QueryInfo &/*queryInfo*/,
+			   QueryResult &result) const {
+  result.Clear();
+}
+
+void QueryNode::Free () {
+}
+
+void QueryNode::Print (ostream &/*s*/, int /*indent*/) const {
+}
+
+
+
+AndQueryNode::AndQueryNode () {
+  leftNode = NULL;
+  rightNode = NULL;
+}
+
+AndQueryNode::~AndQueryNode () {
+  Free ();
+}
+
+void AndQueryNode::Calculate (IndexData &indexData, const QueryInfo &queryInfo,
+			      QueryResult &result) const {
+  result.Clear();
+
+  // an And between nothing and something is nothing...
+  if (leftNode == NULL || rightNode == NULL) return;
+  
+  // calculate the result from the left tree and the result
+  // from the right tree
+  QueryResult rightResult;
+  leftNode->Calculate (indexData, queryInfo, result);
+  rightNode->Calculate (indexData, queryInfo, rightResult);
+
+  // merge the results, this can be done in place as the results
+  // will always shrink with an And
+
+  bool haveAccum = (queryInfo.sortByRank || queryInfo.needRankInfo);
+  if (haveAccum && (result.ranks.size() != result.docs.size() ||
+		    rightResult.ranks.size() != rightResult.docs.size())) {
+    // shouldn't ever get here
+    haveAccum = false;
+    assert (0);
+  }
+
+  // combine document numbers and corresponding ranks
+  unsigned long leftI = 0;
+  unsigned long rightI = 0;
+  unsigned long outI = 0;
+  while (leftI < result.docs.size() &&
+	 rightI < rightResult.docs.size()) {
+    if (result.docs[leftI] < rightResult.docs[rightI]) {
+      leftI++;
+    } else if (result.docs[leftI] > rightResult.docs[rightI]) {
+      rightI++;
+    } else {
+      // the documents are equal
+      result.docs[outI] = result.docs[leftI];
+      if (haveAccum)
+	result.ranks[outI] = result.ranks[leftI] + rightResult.ranks[rightI];
+      leftI++;
+      rightI++;
+      outI++;
+    }
+  }
+
+  // erase unused document numbers and ranks
+  result.docs.erase(result.docs.begin()+outI, result.docs.end());
+  if (haveAccum)
+    result.ranks.erase(result.ranks.begin()+outI, result.ranks.end());
+    
+  // combine term frequency information
+  if (queryInfo.needTermFreqs)
+    result.termFreqs.insert (result.termFreqs.end(),
+			     rightResult.termFreqs.begin(),
+			     rightResult.termFreqs.end());
+}
+
+void AndQueryNode::Free () {
+  if (leftNode != NULL) {
+    delete leftNode;
+    leftNode = NULL;
+  }
+  if (rightNode != NULL) {
+    delete rightNode;
+    rightNode = NULL;
+  }
+}
+
+void AndQueryNode::Print (ostream &s, int indent) const {
+  PrintIndentText (s, "leftNode:\n", indent);
+  PrintNode (s, leftNode, indent+2);
+  PrintIndentText (s, "AND\n", indent);
+  PrintIndentText (s, "rightNode:\n", indent);
+  PrintNode (s, rightNode, indent+2);
+}
+
+
+OrQueryNode::OrQueryNode () {
+  leftNode = NULL;
+  rightNode = NULL;
+}
+
+OrQueryNode::~OrQueryNode () {
+  Free ();
+}
+
+void OrQueryNode::Calculate (IndexData &indexData, const QueryInfo &queryInfo,
+			      QueryResult &result) const {
+  result.Clear();
+  
+  // calculate the result from the left tree and the result
+  // from the right tree
+  QueryResult leftResult;
+  QueryResult rightResult;
+  if (leftNode != NULL)
+    leftNode->Calculate (indexData, queryInfo, leftResult);
+  if (rightNode != NULL)
+    rightNode->Calculate (indexData, queryInfo, rightResult);
+
+  // merge the results
+  
+  bool haveAccum = (queryInfo.sortByRank || queryInfo.needRankInfo);
+  if (haveAccum && (leftResult.ranks.size() != leftResult.docs.size() ||
+		    rightResult.ranks.size() != rightResult.docs.size())) {
+    // shouldn't ever get here
+    haveAccum = false;
+    assert (0);
+  }
+
+  // combine document numbers and corresponding ranks
+  unsigned long leftSize = leftResult.docs.size();
+  unsigned long rightSize = rightResult.docs.size();
+  unsigned long leftI = 0;
+  unsigned long rightI = 0;
+  unsigned long leftDocNum = 0;
+  unsigned long rightDocNum = 0;
+  while (leftI < leftSize || rightI < rightSize) {
+    // check leftI
+    if (leftI < leftResult.docs.size())
+      leftDocNum = leftResult.docs[leftI];
+    else leftDocNum = ULONG_MAX;
+    
+    // check rightI
+    if (rightI < rightResult.docs.size())
+      rightDocNum = rightResult.docs[rightI];
+    else rightDocNum = ULONG_MAX;
+    
+    // combine
+    if (leftDocNum < rightDocNum) {
+      result.docs.push_back (leftDocNum);
+      if (haveAccum)
+	result.ranks.push_back (leftResult.ranks[leftI]);
+      leftI++;
+      
+    } else if (leftDocNum > rightDocNum) {
+      result.docs.push_back (rightDocNum);
+      if (haveAccum)
+	result.ranks.push_back (rightResult.ranks[rightI]);
+      rightI++;
+      
+    } else { // equal
+      result.docs.push_back (leftDocNum);
+      if (haveAccum)
+	result.ranks.push_back (leftResult.ranks[leftI] +
+				rightResult.ranks[rightI]);
+      leftI++;
+      rightI++;
+    }
+  }
+
+  // combine term frequency information
+  if (queryInfo.needTermFreqs) {
+    result.termFreqs.insert (result.termFreqs.end(),
+			     leftResult.termFreqs.begin(),
+			     leftResult.termFreqs.end());
+    result.termFreqs.insert (result.termFreqs.end(),
+			     rightResult.termFreqs.begin(),
+			     rightResult.termFreqs.end());
+  }
+}
+
+void OrQueryNode::Free () {
+  if (leftNode != NULL) {
+    delete leftNode;
+    leftNode = NULL;
+  }
+  if (rightNode != NULL) {
+    delete rightNode;
+    rightNode = NULL;
+  }
+}
+
+void OrQueryNode::Print (ostream &s, int indent) const {
+  PrintIndentText (s, "leftNode:\n", indent);
+  PrintNode (s, leftNode, indent+2);
+  PrintIndentText (s, "OR\n", indent);
+  PrintIndentText (s, "rightNode:\n", indent);
+  PrintNode (s, rightNode, indent+2);
+}
+
+
+
+NotQueryNode::NotQueryNode () {
+  queryNode = NULL;
+  notNode = NULL;
+}
+
+NotQueryNode::~NotQueryNode () {
+  Free ();
+}
+
+void NotQueryNode::Calculate (IndexData &indexData, const QueryInfo &queryInfo,
+			      QueryResult &result) const {
+  result.Clear();
+
+  // check for nothing
+  if (queryNode == NULL) return;
+  if (notNode == NULL) {
+    queryNode->Calculate (indexData, queryInfo, result);
+    return;
+  }
+  
+  // calculate the result from the query tree and the result
+  // from the not tree
+  QueryResult notResult;
+  queryNode->Calculate (indexData, queryInfo, result);
+  notNode->Calculate (indexData, queryInfo, notResult);
+
+  // merge the results, this can be done in place as the results
+  // will always shrink with a Not
+
+  bool haveAccum = (queryInfo.sortByRank || queryInfo.needRankInfo);
+  if (haveAccum && (result.ranks.size() != result.docs.size() ||
+		    notResult.ranks.size() != notResult.docs.size())) {
+    // shouldn't ever get here
+    haveAccum = false;
+    assert (0);
+  }
+
+  // combine document numbers and corresponding ranks
+  unsigned long queryI = 0;
+  unsigned long notI = 0;
+  unsigned long outI = 0;
+  while (queryI < result.docs.size() &&
+	 notI < notResult.docs.size()) {
+    if (result.docs[queryI] < notResult.docs[notI]) {
+      // found a document not in the notResults
+      result.docs[outI] = result.docs[queryI];
+      if (haveAccum)
+	result.ranks[outI] = result.ranks[queryI];
+      queryI++;
+      outI++;
+    } else if (result.docs[queryI] > notResult.docs[notI]) {
+      notI++;
+    } else {
+      // the documents are equal, ignore both
+      queryI++;
+      notI++;
+    }
+  }
+
+  // erase unused document numbers and ranks
+  result.docs.erase(result.docs.begin()+outI, result.docs.end());
+  if (haveAccum)
+    result.ranks.erase(result.ranks.begin()+outI, result.ranks.end());
+  
+  // combine term frequency information
+  if (queryInfo.needTermFreqs)
+    result.termFreqs.insert (result.termFreqs.end(),
+			     notResult.termFreqs.begin(),
+			     notResult.termFreqs.end());
+}
+
+void NotQueryNode::Free () {
+  if (queryNode != NULL) {
+    delete queryNode;
+    queryNode = NULL;
+  }
+  if (notNode != NULL) {
+    delete notNode;
+    notNode = NULL;
+  }
+}
+
+void NotQueryNode::Print (ostream &s, int indent) const {
+  PrintIndentText (s, "queryNode:\n", indent);
+  PrintNode (s, queryNode, indent+2);
+  PrintIndentText (s, "NOT\n", indent);
+  PrintIndentText (s, "notNode:\n", indent);
+  PrintNode (s, notNode, indent+2);
+}
+
+
+void TagNode::Clear () {
+  UCArrayClear (tagName);
+}
+
+void TagNode::Calculate (IndexData &indexData,
+			 FragRangeArray &fragRange) const {
+  fragRange.erase (fragRange.begin(), fragRange.end());
+  if (tagName.empty()) return;
+
+  // get information about this tag
+  block_dict_el tagEl;
+  unsigned long tagElNum;
+  if (!SearchBlockDictEl (indexData.dictFile, indexData.biTags,
+			  indexData.bdh.entries_per_tblk,
+			  indexData.bdh.tag_dict_size,
+			  tagName, tagEl, tagElNum))
+    return;
+
+  // seek to the appropriate place in the inverted file
+  fseek (indexData.invfFile, tagEl.invf_ptr, SEEK_SET);
+
+  stdio_bitio_buffer buffer(indexData.invfFile);
+  
+  unsigned long pTag = tagEl.frag_occur*2;
+  unsigned long B = BIO_Bblock_Init (indexData.bdh.num_frags+pTag, pTag);
+  unsigned long fragNum = 0;
+  unsigned long i;
+  FragRange thisFrag;
+  for (i=0; i<tagEl.frag_occur; i++) {
+    // get start
+    unsigned long delta = buffer.bblock_decode (B, NULL)-1;
+    fragNum += delta;
+
+    thisFrag.rangeStart = fragNum;
+
+    // get end
+    delta = buffer.bblock_decode (B, NULL)-1;
+    fragNum += delta;
+
+    thisFrag.rangeEnd = fragNum;
+    fragRange.push_back (thisFrag);
+  }
+
+  buffer.done();
+}
+
+void TagNode::Free () {
+  Clear ();
+}
+
+void TagNode::Print (ostream &s, int indent) const {
+  PrintIndent (s, indent);
+  s << "TAG: \"" << tagName << "\"\n";
+}
+
+
+void TermNode::Clear () {
+  UCArrayClear (term);
+  termWeight = 1;
+  stemMethod = 0;
+  startRange = NO_TERM_RANGE_START;
+  endRange = NO_TERM_RANGE_END;
+}
+
+TermNode::TermNode () {
+  Clear ();
+}
+
+void TermNode::Calculate (IndexData &indexData,
+			  bool needFragFreqs,
+			  FragRangeArray *fragLimits,
+			  FragData &fragData) const {
+  fragData.Clear ();
+
+  // get a list of term numbers
+  vector<unsigned long> equivWords;
+  FindWordNumbers (indexData, term, stemMethod, equivWords);
+
+  // get the information for each word and merge it with
+  // previous results
+  FragData tempFragData1;
+  FragData tempFragData2;
+  vector<unsigned long>::iterator here = equivWords.begin();
+  vector<unsigned long>::iterator end = equivWords.end();
+  while (here != end) {
+    // get the information for this word
+    ReadTermFragData (indexData, needFragFreqs, *here,
+		      tempFragData1, fragLimits);
+
+    // combine with last results
+    tempFragData2 = fragData;
+    CombineFragData (needFragFreqs, tempFragData1, tempFragData2, fragData);
+    
+    here++;
+  }
+}
+
+void TermNode::Free () {
+  Clear ();
+}
+
+void TermNode::Print (ostream &s, int indent) const {
+  PrintIndent (s, indent);
+  s << "TERM: \"" << term << "\"\n";
+  PrintIndent (s, indent+2);
+  s << "termWeight: " << termWeight << "\n";
+  PrintIndent (s, indent+2);
+  s << "stemMethod: " << stemMethod << "\n";
+  PrintIndent (s, indent+2);
+  s << "startRange: " << startRange << "\n";
+  PrintIndent (s, indent+2);
+  s << "endRange: " << endRange << "\n";
+}
+
+
+ProxMatchQueryNode::ProxMatchQueryNode () {
+  tagNodePtr = NULL;
+}
+
+ProxMatchQueryNode::~ProxMatchQueryNode () {
+  Free ();
+}
+
+void ProxMatchQueryNode::Calculate (IndexData &indexData,
+				    const QueryInfo &queryInfo,
+				    QueryResult &result) const {
+  result.Clear ();
+
+  bool needFragFreqs = (queryInfo.sortByRank || queryInfo.needRankInfo);
+
+  // read in the tag if needed
+  FragRangeArray fragLimits;
+  FragRangeArray *fragLimitsPtr = NULL;
+  if (tagNodePtr == NULL && terms.size() > 1) {
+    // multiple terms must be compared relative to some tag
+    // otherwise phrase matches could span documents
+    TagNode tempTagNode;
+    tempTagNode.tagName = indexData.curLevel;
+    tempTagNode.Calculate (indexData, fragLimits);
+    fragLimitsPtr = &fragLimits;
+    
+  } else if (tagNodePtr != NULL) {
+    (*tagNodePtr).Calculate (indexData, fragLimits);
+    fragLimitsPtr = &fragLimits;
+  }
+
+  UCArray tagOrLevel = indexData.curLevel;
+  if (tagNodePtr != NULL) tagOrLevel = (*tagNodePtr).tagName;
+
+  // read in the first term
+  FragData termData;
+  TermNodeArray::const_iterator termHere=terms.begin(), termEnd = terms.end();
+  if (termHere != termEnd) {
+    (*termHere).Calculate (indexData, needFragFreqs, fragLimitsPtr, termData);
+
+    // convert initial fragment information
+    FragsToQueryResult (indexData,
+			queryInfo,
+			termData,
+			tagOrLevel,
+			(*termHere).term,
+			(*termHere).stemMethod,
+			(*termHere).termWeight,
+			result);
+  
+    termHere++;
+
+    if (termHere == termEnd) return; // nothing more to do
+  }
+
+  // read and combine the rest of the terms
+  FragData comTermData;
+  while (termHere != termEnd) {
+    (*termHere).Calculate (indexData, needFragFreqs,
+			   fragLimitsPtr, comTermData);
+
+    AndFragsToQueryResult (indexData,
+			   queryInfo,
+			   comTermData,
+			   tagOrLevel,
+			   (*termHere).term,
+			   (*termHere).stemMethod,
+			   (*termHere).termWeight,
+			   result);
+    
+    AndCombineFragData (needFragFreqs, termData, comTermData,
+			(*termHere).startRange,
+			(*termHere).endRange,
+			fragLimitsPtr);
+    termHere++;
+  }
+
+  // remove unwanted document numbers
+  RemoveUnwantedResults (indexData,
+			 queryInfo,
+			 termData,
+			 result);
+}
+
+void ProxMatchQueryNode::Free () {
+  if (tagNodePtr != NULL) {
+    delete tagNodePtr;
+    tagNodePtr = NULL;
+  }
+  terms.erase (terms.begin(), terms.end());
+}
+
+void ProxMatchQueryNode::Print (ostream &s, int indent) const {
+  PrintIndentText (s, "PROXMATCH\n", indent);
+  if (tagNodePtr != NULL) tagNodePtr->Print (s, indent+2);
+  
+  TermNodeArray::const_iterator here = terms.begin();
+  TermNodeArray::const_iterator end = terms.end();
+  while (here != end) {
+    (*here).Print (s, indent+2);
+    here++;
+  }
+}
+
+
+void BrowseQueryNode::Clear () {
+  UCArrayClear(term);
+}
+
+void BrowseQueryNode::Calculate (IndexData &indexData, BrowseQueryResult &result) const {
+
+  unsigned long number=0;
+  FindNearestWordNumber(indexData, term, number);
+  if (number + startPosition > 0 ) {
+    number = number+startPosition;
+  }
+  else {
+    number = 1;
+  }
+
+  GetTermList (indexData, number, numTerms, result.termFreqs);
+
+}
+
+
+
+void BrowseQueryNode::Free () {
+  Clear();
+}
+
+
+void BrowseQueryNode::Print (ostream &s, int indent) const {
+  PrintIndentText(s, "BROWSEQUERYNODE\n", indent);
+  PrintIndent (s, indent+2);
+  s << "TERM:"<<term<<"\n";
+  PrintIndent (s, indent+2);
+  s << "Start position: "<< startPosition<<", Num terms: "<< numTerms<<"\n";
+
+
+}
+
+
+
+void MGQuery (IndexData &indexData,
+	      const QueryInfo &queryInfo,
+	      const QueryNode *queryTree,
+	      QueryResult &result) {
+  result.Clear ();
+
+  // make sure level is current
+  indexData.LoadLevel (queryInfo.docLevel);
+  
+  // do query
+  if (queryTree != NULL)
+    (*queryTree).Calculate (indexData, queryInfo, result);
+
+  // make weights into ranks if needed
+  unsigned long i;
+  if (queryInfo.sortByRank || queryInfo.needRankInfo) {
+    for (i=0; i<result.ranks.size(); i++) {
+      result.ranks[i] /=
+	indexData.weightData.GetLowerApproxDocWeight (result.docs[i]);
+    }
+  }
+
+  unsigned long resultsSize = queryInfo.maxDocs;
+  if (resultsSize == 0 || resultsSize > result.docs.size())
+    resultsSize = result.docs.size();
+  
+  // sort results by rank if needed
+  GTRank gtRank;
+  if (queryInfo.sortByRank) {
+    // need in ascending order for SelectAddHeap
+    MakeHeap (result.docs.begin(), result.ranks.begin(),
+	      resultsSize, gtRank);
+    SelectAddHeap (result.docs.begin(), result.ranks.begin(), resultsSize,
+		   result.docs.begin()+resultsSize,
+		   result.ranks.begin()+resultsSize,
+		   result.ranks.size()-resultsSize, gtRank);
+
+    // sort into descending order
+    SortHeap (result.docs.begin(), result.ranks.begin(), resultsSize, gtRank);
+  }
+  
+  // get exact weights if needed
+  if (queryInfo.exactWeights &&
+      (queryInfo.sortByRank || queryInfo.needRankInfo)) {
+    unsigned long exactDiskPtr =
+      indexData.levels.levelInfo[indexData.curLevel].exactWeightsDiskPtr;
+    
+    for (i=0; i<resultsSize; i++) {
+      result.ranks[i] =  result.ranks[i] *
+	indexData.weightData.GetLowerApproxDocWeight (result.docs[i]) /
+	GetExactDocWeight (indexData.exactWeightsFile, exactDiskPtr,
+			   result.docs[i]);
+    }
+
+    // re-sort top candidates based on exact weights
+    if (queryInfo.sortByRank) {
+      MakeHeap (result.docs.begin(), result.ranks.begin(),
+		resultsSize, gtRank);
+      SortHeap (result.docs.begin(), result.ranks.begin(),
+		resultsSize, gtRank);
+    }
+  }
+
+  // get rid of unwanted ranking results
+  if (result.ranks.empty()) {
+    // do nothing
+  } else if (!queryInfo.needRankInfo) {
+    result.ranks.erase(result.ranks.begin(), result.ranks.end());
+  } else {
+    result.ranks.erase(result.ranks.begin()+resultsSize, result.ranks.end());
+  }
+  result.docs.erase(result.docs.begin()+resultsSize, result.docs.end());
+}
+
+// new MGQuery to retrieve doc and section nums
+// this will return doc nums for the level queried at (set in queryInfo)
+// in QueryResult.docs and if a second level is specified, 
+// it will return corresponding docnums for that level in QueryResult.levels
+void MGQuery (IndexData &indexData,
+	      const QueryInfo &queryInfo,
+	      const QueryNode *queryTree,
+	      ExtQueryResult &realresult, UCArray &level) {
+  realresult.Clear ();
+  QueryResult result; // temp result
+
+  // do the normal query
+  MGQuery (indexData, queryInfo, queryTree, result);
+
+  // now that have the final result stuff, convert to ExtQueryResult,
+  // add in level nums if needed
+
+  realresult.docs = result.docs;
+  realresult.ranks = result.ranks;
+  realresult.termFreqs = result.termFreqs;
+
+  if (queryInfo.docLevel == level || level.empty()) {
+    realresult.levels = result.docs;
+    return;
+  }
+
+  // else need to convert from queryInfo.docLevel to level
+
+  // the original level info
+  FragLevelConvert sectionLevelConverter = indexData.levelConverter;
+
+  // the new level info
+  indexData.LoadLevel(level);
+  
+  unsigned long DocNum = 0;
+  
+  for (unsigned long i=0; i<realresult.docs.size(); i++) {
+
+    // do an if ! here????
+    indexData.levelConverter.LevelToLevel(sectionLevelConverter, realresult.docs[i], DocNum);
+    realresult.levels.push_back(DocNum);
+  }
+  
+}
+
+
+
+// new function for full text browsing, 
+void MGBrowseQuery (IndexData &indexData, UCArray &level,
+		  const BrowseQueryNode &node,
+		  BrowseQueryResult &result) {
+
+  indexData.LoadLevel(level);
+  node.Calculate(indexData, result); 
+
+}
+
+
+
+
+
+
+
Index: /main/tags/2.25/gsdl/src/mgpp/text/MGQuery.h
===================================================================
--- /main/tags/2.25/gsdl/src/mgpp/text/MGQuery.h	(revision 21064)
+++ /main/tags/2.25/gsdl/src/mgpp/text/MGQuery.h	(revision 21064)
@@ -0,0 +1,210 @@
+/**************************************************************************
+ *
+ * MGQuery.h -- Query related functions
+ * Copyright (C) 1999  Rodger McNab
+ *
+ * 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.
+ *
+ * $Id$
+ *
+ **************************************************************************/
+
+#ifndef MGQUERY_H
+#define MGQUERY_H
+
+#include "IndexData.h"
+#include <limits.h>
+#include "Terms.h"
+
+
+
+// forms base for defining and calculating the boolean
+// part of a query
+class QueryNode {
+public:
+  QueryNode ();
+  virtual ~QueryNode ();
+
+  virtual void Calculate (IndexData &indexData, const QueryInfo &queryInfo,
+			  QueryResult &result) const;
+  virtual void Free ();
+  virtual void Print (ostream &s, int indent=0) const;
+};
+
+
+
+void PrintIndent (ostream &s, int indent);
+void PrintIndentText (ostream &s, char *text, int indent);
+void PrintNode (ostream &s, QueryNode *node, int indent=0);
+
+
+
+// basic boolean nodes
+
+class AndQueryNode : public QueryNode {
+public:
+  QueryNode *leftNode;
+  QueryNode *rightNode;
+  
+  AndQueryNode ();
+  ~AndQueryNode ();
+
+  void Calculate (IndexData &indexData, const QueryInfo &queryInfo,
+		  QueryResult &result) const;
+  void Free ();
+  void Print (ostream &s, int indent=0) const;
+};
+
+class OrQueryNode : public QueryNode {
+public:
+  QueryNode *leftNode;
+  QueryNode *rightNode;
+  
+  OrQueryNode ();
+  ~OrQueryNode ();
+
+  void Calculate (IndexData &indexData, const QueryInfo &queryInfo,
+		  QueryResult &result) const;
+  void Free ();
+  void Print (ostream &s, int indent=0) const;
+};
+
+class NotQueryNode : public QueryNode {
+public:
+  QueryNode *queryNode;
+  QueryNode *notNode;
+  
+  NotQueryNode ();
+  ~NotQueryNode ();
+
+  void Calculate (IndexData &indexData, const QueryInfo &queryInfo,
+		  QueryResult &result) const;
+  void Free ();
+  void Print (ostream &s, int indent=0) const;
+};
+
+
+
+class TagNode {
+public:
+  UCArray tagName;
+
+  void Clear ();
+  TagNode () { Clear (); }
+
+  void Calculate (IndexData &indexData, FragRangeArray &fragRange) const;
+  void Free ();
+  void Print (ostream &s, int indent=0) const;
+};
+
+
+#define NO_TERM_RANGE_START (LONG_MIN/2)
+#define NO_TERM_RANGE_END   (LONG_MAX/2)
+
+/* NOTE: range stuff - the range values are for the previous term relative
+to the current term. So if searching for the phrase "the cat", 'the' doesn't 
+need range limits, but 'cat' has a range of -2 to -1. ie, if have found 'cat'
+then 'the' has to be at position between -2 and -1 relative to 'cat'.
+"the cat" could also be searched for by 'cat' with no range limits, then 'the' with range 0 to 1.
+range values are relative to the gaps between words:
+   x   y   z   X   a   b   c
+    -3   -2  -1  0   1   2   3
+
+ */
+class TermNode {
+public:
+  UCArray term;
+  unsigned long termWeight;
+  unsigned long stemMethod;
+  signed long startRange; // range relative to last term
+  signed long endRange;
+  
+  void Clear ();
+  TermNode ();
+
+  // fragLimits can be NULL if not neede
+  void Calculate (IndexData &indexData,
+		  bool needFragFreqs,
+		  FragRangeArray *fragLimits,
+		  FragData &fragData) const;
+  void Free ();
+  void Print (ostream &s, int indent=0) const;
+};
+
+typedef vector<TermNode> TermNodeArray;
+
+
+class ProxMatchQueryNode : public QueryNode {
+public:
+  TagNode *tagNodePtr; // optional field
+  TermNodeArray terms;
+  
+  ProxMatchQueryNode ();
+  ~ProxMatchQueryNode ();
+
+  void Calculate (IndexData &indexData, const QueryInfo &queryInfo,
+		  QueryResult &result) const;
+  void Free ();
+  void Print (ostream &s, int indent=0) const;
+};
+
+class BrowseQueryNode :public QueryNode {
+ public:
+  UCArray term;
+  signed long startPosition;
+  unsigned long numTerms;
+
+  void Clear();
+  BrowseQueryNode () { Clear(); }
+  //  ~BrowseQueryNode ();
+
+  void Calculate (IndexData &indexData, BrowseQueryResult &result) const;
+  void Free ();
+  void Print (ostream &s, int indent=0) const;
+
+
+
+
+};
+
+void MGQuery (IndexData &indexData,
+	      const QueryInfo &queryInfo,
+	      const QueryNode *queryTree,
+	      QueryResult &result);
+
+// this function for retrieving results with both section doc nums
+// and Document docnums
+void MGQuery (IndexData &indexData,
+	      const QueryInfo &queryInfo,
+	      const QueryNode *queryTree,
+	      ExtQueryResult &result, UCArray &level);
+
+
+// new function for full text browsing, 
+void MGBrowseQuery (IndexData &indexData, UCArray &level,
+		  const BrowseQueryNode &node,
+		  BrowseQueryResult &result);
+
+#endif
+
+
+
+
+
+
+
+
+
+
Index: /main/tags/2.25/gsdl/src/mgpp/text/Makefile.in
===================================================================
--- /main/tags/2.25/gsdl/src/mgpp/text/Makefile.in	(revision 21064)
+++ /main/tags/2.25/gsdl/src/mgpp/text/Makefile.in	(revision 21064)
@@ -0,0 +1,315 @@
+###########################################################################
+#
+# Makefile.in -- Makefile for the MG system
+# Copyright (C) 1994  Neil Sharman;  1995 Tim Shimmin
+#
+# 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.
+#
+#       @(#)Makefile.in	1.10 22 Mar 1994
+#
+###########################################################################
+
+PACKAGE = @PACKAGE@
+VERSION = @VERSION@
+
+SHELL = /bin/sh
+VPATH = @srcdir@
+exec_prefix = @exec_prefix@
+prefix = @prefix@
+srcdir = @srcdir@
+subdir = text
+top_srcdir = @top_srcdir@
+transform = @program_transform_name@
+
+AR = ar
+CC = @CC@
+CPP = @CXX@
+CFLAGS = @CFLAGS@ -ansi -Wall -Wunused -pedantic -W -Woverloaded-virtual -g  -DSILENT -DSHORT_SUFFIX
+CPPFLAGS = @CPPFLAGS@ -ansi -Wall -Wunused -pedantic -W -Woverloaded-virtual -g -DSILENT -DSHORT_SUFFIX
+DEFS = @DEFS@
+RANLIB = @RANLIB@
+INSTALL = @INSTALL@
+INSTALL_DATA = @INSTALL_DATA@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@
+LDFLAGS = @LDFLAGS@
+LIBS = ../lib/libmg.a -lstdc++ @LIBS@
+TOUCH = echo timestamp >
+AWK = @AWK@
+
+##########################################
+# George Buchanan - August 1999
+# 
+# compiling with make NZDL=1 to ensure that 
+# the NZDL compile mode is used - this has been changed to the default - kjm18
+#
+##########################################
+
+
+bindir = $(exec_prefix)/bin
+datadir = $(prefix)/share
+libexecdir = $(exec_prefix)/libexec
+localedir = $(datadir)/locale
+mandir = $(prefix)/man/man1
+
+COMPILE = $(CC) -c $(DEFS) $(TREC_MODE) $(READLINE) $(INCLUDES) $(CPPFLAGS) $(CFLAGS)
+CPPCOMPILE = $(CPP) -c $(DEFS) $(TREC_MODE) $(READLINE) $(INCLUDES) $(CPPFLAGS) $(CFLAGS)
+LINK = $(CC) $(LDFLAGS) -o $@
+
+.SUFFIXES:
+.SUFFIXES: .c .o
+.c.o:
+	$(COMPILE) $<
+
+.SUFFIXES: .cpp .o
+.cpp.o:
+	$(CPPCOMPILE) -D__cplusplus $<
+
+
+ANSI2KNR = @ANSI2KNR@
+o = .@U@o
+
+.SUFFIXES: ._c ._o
+.c._c:
+	./ansi2knr $< > $*.tmp && mv $*.tmp $@
+._c._o:
+	@echo $(COMPILE) $<
+	@rm -f _$*.c
+	@ln $< _$*.c && $(COMPILE) _$*.c && mv _$*.o $@ && rm _$*.c
+.c._o:
+	./ansi2knr $< > $*.tmp && mv $*.tmp $*._c
+	@echo $(COMPILE) $*._c
+	@rm -f _$*.c
+	@ln $*._c _$*.c && $(COMPILE) _$*.c && mv _$*.o $@ && rm _$*.c
+
+INCLUDES = -I../ -I../lib -I.
+
+#############################################################################
+#
+# Uncomment (and possibly edit) the following lines if you wish
+# to use the GNU readline library for the input in mgquery
+# 
+#READLINE = -DGNU_READLINE -I/opt/gnu/include/readline -L/opt/gnu/lib
+#READLINE_LIBS = -lreadline -ltermcap
+#
+#
+#############################################################################
+
+SOURCES = \
+  FIvfLevelInfo.cpp        ivf.pass1.cpp            mg_invf_dump.cpp       \
+  FText.cpp                ivf.pass2.cpp            mg_passes.cpp          \
+  FileBuf.cpp              locallib.cpp             mg_perf_hash_build.cpp \
+  FragLevelConvert.cpp     mg.special.cpp           mg_stem_idx.cpp        \
+  IndexData.cpp            mg_compression_dict.cpp  mg_weights_build.cpp   \
+  TagInfo.cpp              mg_decompress_text.cpp   stemmer.cpp            \
+  TextEl.cpp               mg_errors.cpp            text.cpp               \
+  TextGet.cpp              mg_fast_comp_dict.cpp    text.pass1.cpp         \
+  UCArray.cpp              mg_files.cpp             text.pass2.cpp         \
+  comp_dict.cpp            mg_invf_dict.cpp         words.cpp              \
+  invf.cpp                 mg_invf_dict_dump.cpp    Weights.cpp            \
+  MGQuery.cpp              Terms.cpp                QueryTester.cpp        \
+  QueryLex.cpp             QueryParser.cpp         \
+  GSDLQueryLex.cpp	   GSDLQueryParser.cpp      Queryer.cpp
+
+
+HEADERS = \
+  FIvfLevelInfo.h     TextEl.h            hash.h              stemmer.h  \
+  FText.h             TextGet.h           invf.h              text.h     \
+  FileBuf.h           UCArray.h           locallib.h          words.h    \
+  FragLevelConvert.h  WordData.h          mg.h                           \
+  IndexData.h         build.h             mg_errors.h                    \
+  TagInfo.h           comp_dict.h         mg_files.h          Weights.h  \
+  MGQuery.h           Terms.h             QueryLex.h          QueryParser.h \
+  GSDLQueryLex.h	GSDLQueryParser.h
+
+
+MISC          = Makefile.in 
+
+ALLFILES      =	$(SOURCES) $(HEADERS) $(MISC) $(MAN)
+
+DISTFILES     = $(ALLFILES) 
+
+EXEC          = mg_passes mg_decompress_text mg_perf_hash_build \
+                mg_invf_dump mg_weights_build mg_invf_dict mg_stem_idx \
+                mg_invf_dict_dump mg_compression_dict mg_fast_comp_dict \
+                QueryTester Queryer
+
+MAN           =  mg_weights_build.1  mg_invf_dict.1 \
+                 mg_passes.1 mg_perf_hash_build.1 \
+                 mg_compression_dict.1  mg_fast_comp_dict.1 \
+                 mg_stem_idx.1
+
+# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
+
+
+all:	$(EXEC) libtextin.a
+
+depend:
+	makedepend -Y -- $(DEFS) $(INCLUDES) $(CPPFLAGS) $(CFLAGS) -- $(SOURCES)
+
+# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
+
+
+PASSES_OBJS = \
+	mg_passes$o text.pass1$o comp_dict$o \
+	text.pass2$o locallib$o \
+	ivf.pass1$o ivf.pass2$o mg.special$o mg_files$o \
+	words$o invf$o FileBuf$o TextEl$o UCArray$o TagInfo$o \
+        FText$o text$o FIvfLevelInfo$o
+
+mg_passes: $(PASSES_OBJS)
+	$(LINK) $(PASSES_OBJS) $(LIBS)
+
+# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
+
+QUERYER_OBJS = Queryer$o mg_files$o mg_errors$o locallib$o invf$o UCArray$o \
+               FIvfLevelInfo$o FragLevelConvert$o Terms$o MGQuery$o \
+               IndexData$o stemmer$o Weights$o TextGet$o text$o FText$o \
+               GSDLQueryParser$o GSDLQueryLex$o words$o
+
+Queryer: $(QUERYER_OBJS)
+	$(LINK) $(QUERYER_OBJS) $(LIBS)
+
+QUERY_TESTER_OBJS = QueryTester$o mg_files$o invf$o UCArray$o \
+                    FIvfLevelInfo$o FragLevelConvert$o Terms$o MGQuery$o \
+                    IndexData$o stemmer$o Weights$o
+
+QueryTester: $(QUERY_TESTER_OBJS)
+	$(LINK) $(QUERY_TESTER_OBJS) $(LIBS)
+
+WEIGHTS_BUILD_OBJS = mg_weights_build$o mg_files$o invf$o UCArray$o \
+                     FIvfLevelInfo$o FragLevelConvert$o
+
+mg_weights_build: $(WEIGHTS_BUILD_OBJS)
+	$(LINK) $(WEIGHTS_BUILD_OBJS) $(LIBS)
+
+COMP_DICT_OBJS = mg_compression_dict$o mg_files$o locallib$o
+
+mg_compression_dict: $(COMP_DICT_OBJS)
+	$(LINK) $(COMP_DICT_OBJS) $(LIBS)
+
+FAST_COMP_OBJS = mg_fast_comp_dict$o mg_files$o locallib$o
+
+mg_fast_comp_dict: $(FAST_COMP_OBJS)
+	$(LINK) $(FAST_COMP_OBJS) $(LIBS)
+
+INVF_DUMP_OBJS = mg_invf_dump$o locallib$o mg_files$o invf$o UCArray$o
+
+mg_invf_dump: $(INVF_DUMP_OBJS)
+	$(LINK) $(INVF_DUMP_OBJS) $(LIBS)
+
+INVF_DICT_OBJS = mg_invf_dict$o mg_files$o invf$o UCArray$o
+
+mg_invf_dict: $(INVF_DICT_OBJS)
+	$(LINK) $(INVF_DICT_OBJS) $(LIBS)
+
+INVF_DICT_DUMP_OBJS = mg_invf_dict_dump$o mg_files$o invf$o UCArray$o
+
+mg_invf_dict_dump: $(INVF_DICT_DUMP_OBJS)
+	$(LINK) $(INVF_DICT_DUMP_OBJS) $(LIBS)
+
+PERF_HASH_OBJS = mg_perf_hash_build$o mg_files$o invf$o UCArray$o
+
+mg_perf_hash_build: $(PERF_HASH_OBJS)
+	$(LINK) $(PERF_HASH_OBJS) $(LIBS)
+
+STEM_IDX_OBJS = mg_stem_idx$o mg_files$o stemmer$o \
+                invf$o UCArray$o
+
+mg_stem_idx: $(STEM_IDX_OBJS)
+	$(LINK) $(STEM_IDX_OBJS) $(LIBS)
+
+DECOMPRESS_TEXT_OBJS = \
+                mg_decompress_text$o mg_files$o mg_errors$o \
+                locallib$o text$o UCArray$o TextGet$o FText$o
+
+mg_decompress_text: $(DECOMPRESS_TEXT_OBJS)
+	$(LINK) $(DECOMPRESS_TEXT_OBJS) $(LIBS)
+
+# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
+
+ansi2knr: ansi2knr.o
+	$(LINK) ansi2knr.o $(LIBS)
+
+install: execinstall maninstall
+uninstall: execuninstall manuninstall
+
+execinstall: $(EXEC)
+	$(top_srcdir)/mkinstalldirs $(bindir); \
+	for name in $(EXEC); do \
+	  $(INSTALL_PROGRAM) $$name \
+	  $(bindir)/`echo $$name | sed '$(transform)'`; \
+	done
+
+execuninstall:
+	for name in $(EXEC); do \
+	 rm -f $(bindir)/`echo $$name | sed '$(transform)'`; \
+	done
+
+maninstall: $(MAN)
+	$(top_srcdir)/mkinstalldirs $(mandir); \
+	for f in $(MAN); do \
+	  $(INSTALL_DATA) $$f $(mandir)/$$f ;\
+	done
+
+manuninstall: $(MAN)
+	for f in $(MAN); do \
+	  rm -f $(mandir)/$$f ;\
+	done
+
+#mg_errors$o removed from LIB_OBJS to avoid conflict with mg's libtextin.a
+LIB_OBJS = mg_files$o  mg_errors$o locallib$o invf$o UCArray$o \
+           FIvfLevelInfo$o FragLevelConvert$o Terms$o MGQuery$o \
+           IndexData$o stemmer$o Weights$o TextGet$o text$o FText$o \
+           GSDLQueryParser$o GSDLQueryLex$o words$o
+
+libtextin.a: $(LIB_OBJS)
+	rm -f libtextin.a
+	$(AR) cru libtextin.a $(LIB_OBJS)
+	$(RANLIB) libtextin.a
+
+
+mostlyclean:
+	rm -f *$o _*.c _*.o *._c *._o core core.*
+
+clean: mostlyclean
+	rm -f $(EXEC)
+
+distclean: clean
+	rm -f ansi2knr
+	rm -f Makefile
+
+maintainer-clean: distclean
+	@echo "This command is intended only for maintainers to use;"
+	@echo "rebuilding the deleted files may require special tools."
+
+dist: $(DISTFILES)
+	for file in $(DISTFILES); do \
+	  ln $(srcdir)/$$file $(distdir) 2> /dev/null \
+	  || cp -p $(srcdir)/$$file $(distdir); \
+	done
+
+movclean:
+	for file in $(SOURCES); do \
+          test = $$file; \
+          echo $("test.c"##*.c); \
+        done 
+
+Makefile: Makefile.in ../../../config.status
+	cd ../../.. && CONFIG_FILES=$(subdir)/$@ CONFIG_HEADERS= ./config.status
+
+# Tell versions [3.59,3.63) of GNU make not to export all variables.
+# Otherwise a system limit (for SysV at least) may be exc
+
+
Index: /main/tags/2.25/gsdl/src/mgpp/text/QueryLex.cpp
===================================================================
--- /main/tags/2.25/gsdl/src/mgpp/text/QueryLex.cpp	(revision 21064)
+++ /main/tags/2.25/gsdl/src/mgpp/text/QueryLex.cpp	(revision 21064)
@@ -0,0 +1,171 @@
+/**************************************************************************
+ *
+ * QueryLex.cpp -- Lexical analyser for a simple query language
+ * Copyright (C) 2000  Rodger McNab
+ *
+ * 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.
+ *
+ * $Id$
+ *
+ **************************************************************************/
+
+#include "QueryLex.h"
+#include "unitool.h"
+#include "words.h"
+
+inline void AddNChar (UCArray::const_iterator &here,
+		      UCArray &text,
+		      int len) {
+  while (len > 0) {
+    text.push_back (*here++);
+    len--;
+  }
+}
+
+static bool ParseInteger (UCArray::const_iterator &here,
+			  UCArray::const_iterator end,
+			  LexEl &el) {
+  el.Clear();
+
+  // this version of end is used in unitool
+  UCArray::const_iterator endMinus1 = end-1;
+
+  int charLen;
+  unsigned short c; // one character lookahead
+  charLen = parse_utf8_char (here, endMinus1, &c);
+
+  // check for positive or negative
+  bool neg = false;
+  if (c == '+') {
+    AddNChar (here, el.text, charLen);
+    charLen = parse_utf8_char (here, endMinus1, &c);
+  } else if (c == '-') {
+    neg = true;
+    AddNChar (here, el.text, charLen);
+    charLen = parse_utf8_char (here, endMinus1, &c);
+  }
+
+  // read in number part
+  el.num = 0;
+  el.lexType = IntegerE;
+  while (c >= '0' && c <= '9') {
+    el.num = el.num*10 + c - '0';
+    AddNChar (here, el.text, charLen);
+    charLen = parse_utf8_char (here, endMinus1, &c);
+  }
+
+  if (neg) el.num *= -1;
+
+  return (!el.text.empty());
+}
+
+static bool ParseTerm (UCArray::const_iterator &here,
+		       UCArray::const_iterator end,
+		       UCArray &text) {
+  UCArray::const_iterator endMinus1 = end-1;
+  here = ParseIndexWord (here, endMinus1, text);
+  return !text.empty();
+}
+
+
+bool ParseLexEl (UCArray::const_iterator &here,
+		 UCArray::const_iterator end,
+		 LexEl &el) {
+  el.Clear();
+
+  // strange things can happen if here == end == 0
+  if (here == end) return false;
+  
+  // this version of end is used in unitool
+  UCArray::const_iterator endMinus1 = end-1;
+  
+  // ignore all white space
+  int charLen;
+  unsigned short c; // one character lookahead
+  charLen = parse_utf8_char (here, endMinus1, &c);
+  while (here != end && is_unicode_space (c)) {
+    here += charLen;
+    charLen = parse_utf8_char (here, endMinus1, &c);
+  }
+  if (here == end) return false;
+
+  if (c == '(') {
+    el.lexType = OpenBracketE;
+    AddNChar (here, el.text, charLen);
+    return true;
+    
+  } else if (c == ')') {
+    el.lexType = CloseBracketE;
+    AddNChar (here, el.text, charLen);
+    return true;
+    
+  } else if (c == '\"') {
+    el.lexType = QuoteE;
+    AddNChar (here, el.text, charLen);
+    return true;
+    
+  } else if (c == '#') {
+    el.lexType = TermWeightE;
+    AddNChar (here, el.text, charLen);
+    return true;
+    
+  } else if (c == '$') {
+    el.lexType = StemMethodE;
+    AddNChar (here, el.text, charLen);
+    return true;
+    
+  } else if (c == '^') {
+    el.lexType = RangeE;
+    AddNChar (here, el.text, charLen);
+    return true;
+    
+  } else if (c == '@') {
+    el.lexType = AtE;
+    AddNChar (here, el.text, charLen);
+    return true;
+    
+  } else if (c == ':') {
+    el.lexType = TagE;
+    AddNChar (here, el.text, charLen);
+    return true;
+    
+  } else if (c == '+' || c == '-' ||
+	     (c >= '0' && c <= '9')) {
+    return ParseInteger (here, end, el);
+  }
+
+  // assume it is a term of some sort
+  if (!ParseTerm (here, end, el.text)) return false;
+
+  UCArray AND; SetCStr (AND, "AND");
+  if (el.text == AND) {
+    el.lexType = AndOpE;
+    return true;
+  }
+  UCArray OR; SetCStr (OR, "OR");
+  if (el.text == OR) {
+    el.lexType = OrOpE;
+    return true;
+  }
+  UCArray NOT; SetCStr (NOT, "NOT");
+  if (el.text == NOT) {
+    el.lexType = NotOpE;
+    return true;
+  }
+
+  el.lexType = TermE;
+  return true;
+}
+
Index: /main/tags/2.25/gsdl/src/mgpp/text/QueryLex.h
===================================================================
--- /main/tags/2.25/gsdl/src/mgpp/text/QueryLex.h	(revision 21064)
+++ /main/tags/2.25/gsdl/src/mgpp/text/QueryLex.h	(revision 21064)
@@ -0,0 +1,55 @@
+/**************************************************************************
+ *
+ * QueryLex.h -- Lexical analyser for a simple query language
+ * Copyright (C) 2000  Rodger McNab
+ *
+ * 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.
+ *
+ * $Id$
+ *
+ **************************************************************************/
+
+#ifndef QUERYLEX_H
+#define QUERYLEX_H
+
+#include "UCArray.h"
+
+
+// note: white space is ignored
+enum LexType {NoTypeE, OpenBracketE, CloseBracketE, TermE, AndOpE, OrOpE,
+	      NotOpE, QuoteE, IntegerE, TermWeightE, StemMethodE,
+	      RangeE, AtE, TagE};
+
+struct LexEl {
+  LexType lexType;
+  UCArray text;
+  int num; // for IntegerE
+
+  void Clear () {
+    lexType = NoTypeE;
+    UCArrayClear (text);
+    num = 0;
+  }
+  LexEl () { Clear (); }
+};
+
+
+// returns true if another lexical element could be parsed.
+bool ParseLexEl (UCArray::const_iterator &here,
+		 UCArray::const_iterator end,
+		 LexEl &el);
+
+
+#endif
Index: /main/tags/2.25/gsdl/src/mgpp/text/QueryParser.cpp
===================================================================
--- /main/tags/2.25/gsdl/src/mgpp/text/QueryParser.cpp	(revision 21064)
+++ /main/tags/2.25/gsdl/src/mgpp/text/QueryParser.cpp	(revision 21064)
@@ -0,0 +1,221 @@
+/**************************************************************************
+ *
+ * QueryParser.cpp -- Query parser for a simple query language
+ * Copyright (C) 2000  Rodger McNab
+ *
+ * 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.
+ *
+ * $Id$
+ *
+ **************************************************************************/
+
+#include "QueryParser.h"
+#include "QueryLex.h"
+
+
+static QueryNode *ParseExpression (UCArray::const_iterator &here,
+				   UCArray::const_iterator end);
+
+static QueryNode *AndAdd (QueryNode *t1, QueryNode *t2) {
+  if (t1 == NULL) return t2;
+  if (t2 == NULL) return t1;
+
+  AndQueryNode *andNode = new AndQueryNode;
+  andNode->leftNode = t1;
+  andNode->rightNode = t2;
+  return andNode;
+}
+
+static QueryNode *OrAdd (QueryNode *t1, QueryNode *t2) {
+  if (t1 == NULL) return t2;
+  if (t2 == NULL) return t1;
+
+  OrQueryNode *orNode = new OrQueryNode;
+  orNode->leftNode = t1;
+  orNode->rightNode = t2;
+  return orNode;
+}
+
+static QueryNode *NotAdd (QueryNode *t1, QueryNode *t2) {
+  if (t1 == NULL) return t2;
+  if (t2 == NULL) return t1;
+
+  NotQueryNode *notNode = new NotQueryNode;
+  notNode->queryNode = t1;
+  notNode->notNode = t2;
+  return notNode;
+}
+
+// expects the opening bracket to have already been parsed
+// and discarded
+static QueryNode *ParseBracketExpression (UCArray::const_iterator &here,
+					  UCArray::const_iterator end) {
+  // get everything in the expression
+  QueryNode *curTree = ParseExpression (here, end);
+  
+  // gobble up tokens until a closing bracket is found
+  // or the end of the string
+  LexEl el;
+  while (ParseLexEl (here, end, el)) {
+    if (el.lexType == CloseBracketE) break;
+  }
+
+  return curTree;
+}
+
+static int ParseInt (UCArray::const_iterator &here,
+		     UCArray::const_iterator end) {
+  LexEl el;
+  UCArray::const_iterator oldHere = here;
+  if (ParseLexEl (here, end, el) && el.lexType == IntegerE)
+    return el.num;
+  
+  here = oldHere; // not an integer
+  return 0;
+}
+
+
+static void ParseTermModifiers (UCArray::const_iterator &here,
+				UCArray::const_iterator end,
+				TermNode &termNode) {
+  LexEl el;
+  UCArray::const_iterator oldHere = here;
+  while (ParseLexEl (here, end, el)) {
+    if (el.lexType == TermWeightE) {
+      termNode.termWeight = ParseInt (here, end);
+      
+    } else if (el.lexType == StemMethodE) {
+      termNode.stemMethod = ParseInt (here, end);
+      
+    } else if (el.lexType == RangeE) {
+      termNode.startRange = ParseInt (here, end);
+      termNode.endRange = ParseInt (here, end);
+      
+    } else if (el.lexType == AtE) {
+      termNode.startRange = termNode.endRange = ParseInt (here, end);
+      
+    } else {
+      // no term modifiers
+      here = oldHere;
+      break;
+    }
+    
+    oldHere = here;
+  }  
+}
+
+// expects the starting quote to have been parsed
+// and discarded
+static void ParsePhrase (UCArray::const_iterator &here,
+			 UCArray::const_iterator end,
+			 ProxMatchQueryNode &proxNode) {
+  LexEl el;
+  while (ParseLexEl (here, end, el)) {
+    if (el.lexType == TermE || el.lexType == IntegerE) {
+      TermNode termNode;
+      termNode.term = el.text;
+      ParseTermModifiers (here, end, termNode);
+      proxNode.terms.push_back (termNode);
+      
+    } else if (el.lexType == QuoteE) {
+      break;
+      
+    } else {
+      // error
+      break;
+    }
+  }
+}
+
+static QueryNode *ParseTerm (UCArray::const_iterator &here,
+			     UCArray::const_iterator end) {
+  LexEl el;
+
+  UCArray::const_iterator oldHere = here;
+  if (!ParseLexEl (here, end, el)) return NULL;
+
+  if (el.lexType == OpenBracketE)
+    return ParseBracketExpression (here, end);
+
+  ProxMatchQueryNode *proxNode = new ProxMatchQueryNode;
+
+  // check for a tag
+  if (el.lexType == TagE) {
+    oldHere = here; // don't backtrack past here
+    if (!ParseLexEl (here, end, el)) return NULL;
+    if (el.lexType == TermE) {
+      proxNode->tagNodePtr = new TagNode;
+      proxNode->tagNodePtr->tagName = el.text;
+      if (!ParseLexEl (here, end, el)) return NULL;
+    }
+  }
+  
+  if (el.lexType == TermE || el.lexType == IntegerE) {
+    TermNode termNode;
+    termNode.term = el.text;
+    ParseTermModifiers (here, end, termNode);
+    proxNode->terms.push_back (termNode);
+    return proxNode;
+    
+  } else if (el.lexType == QuoteE) {
+    ParsePhrase (here, end, *proxNode);
+    return proxNode;
+  }
+
+  // not a term
+  here = oldHere;
+  delete proxNode;
+  return NULL;
+}
+
+
+static QueryNode *ParseExpression (UCArray::const_iterator &here,
+				   UCArray::const_iterator end) {
+  LexEl el;
+  QueryNode *curTree = NULL;
+
+  UCArray::const_iterator oldHere = here;
+  while (ParseLexEl (here, end, el)) {
+    if (el.lexType == OpenBracketE ||
+	el.lexType == TermE ||
+	el.lexType == QuoteE ||
+	el.lexType == IntegerE ||
+	el.lexType == TagE) {
+      // some type of term, back track and parse it
+      here = oldHere;
+      curTree = OrAdd (curTree, ParseTerm (here, end));
+      
+    } else if (el.lexType == AndOpE) {
+      curTree = AndAdd (curTree, ParseTerm (here, end));
+      
+    } else if (el.lexType == OrOpE) {
+      curTree = OrAdd (curTree, ParseTerm (here, end));
+      
+    } else if (el.lexType == NotOpE) {
+      curTree = NotAdd (curTree, ParseTerm (here, end));
+      
+    } else break;
+    
+    oldHere = here;
+  }
+
+  return curTree;
+}
+
+QueryNode *ParseQuery (const UCArray &queryStr) {
+  UCArray::const_iterator here = queryStr.begin();
+  UCArray::const_iterator end = queryStr.end();
+  return ParseExpression (here, end);
+}
Index: /main/tags/2.25/gsdl/src/mgpp/text/QueryParser.h
===================================================================
--- /main/tags/2.25/gsdl/src/mgpp/text/QueryParser.h	(revision 21064)
+++ /main/tags/2.25/gsdl/src/mgpp/text/QueryParser.h	(revision 21064)
@@ -0,0 +1,33 @@
+/**************************************************************************
+ *
+ * QueryParser.h -- Query parser for a simple query language
+ * Copyright (C) 2000  Rodger McNab
+ *
+ * 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.
+ *
+ * $Id$
+ *
+ **************************************************************************/
+
+#ifndef QUERYPARSER_H
+#define QUERYPARSER_H
+
+#include "UCArray.h"
+#include "MGQuery.h"
+
+// returns NULL if the query could not be parsed
+QueryNode *ParseQuery (const UCArray &queryStr);
+
+#endif
Index: /main/tags/2.25/gsdl/src/mgpp/text/QueryResultsSort.h
===================================================================
--- /main/tags/2.25/gsdl/src/mgpp/text/QueryResultsSort.h	(revision 21064)
+++ /main/tags/2.25/gsdl/src/mgpp/text/QueryResultsSort.h	(revision 21064)
@@ -0,0 +1,142 @@
+/**************************************************************************
+ *
+ * QueryResultsSort.h -- Functions to sort query results and parallel data
+ * Copyright (C) 1999  Rodger McNab
+ *
+ * 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.
+ *
+ * $Id$
+ *
+ **************************************************************************/
+
+#ifndef QUERYRESULTSSORT_H
+#define QUERYRESULTSSORT_H
+
+#include "Terms.h"
+
+
+struct LTRank {
+  bool operator()(const float &f1, const float &f2) const
+    { return (f1 < f2); }
+};
+
+struct GTRank {
+  bool operator()(const float &f1, const float &f2) const
+    { return (f1 > f2); }
+};
+
+
+
+// assumes the rank vector is the same size as the document
+// number vector. assumes the value to be pushed is in
+// docNumHeap + heapSize - 1 and rankHeap + heapSize - 1
+// topIndex can be set
+template <class RandomAccessIterator, class Compare>
+void PushHeap (DocNumArray::iterator docNumHeap,
+	       RandomAccessIterator parallelHeap,
+	       unsigned long heapSize,
+	       const Compare &comp) {
+  unsigned long holeIndex = heapSize-1;
+  unsigned long parent = (holeIndex - 1) / 2;
+  while (holeIndex > 0 && comp (*(parallelHeap+parent),
+				*(parallelHeap+holeIndex))) {
+    swap (*(parallelHeap+holeIndex), *(parallelHeap+parent));
+    swap (*(docNumHeap+holeIndex), *(docNumHeap+parent));
+    holeIndex = parent;
+    parent = (holeIndex - 1) / 2;
+  }
+}
+
+// AdjustHeap is used to add a element to a heap after one
+// element in the heap has been replaced with a new one
+template <class RandomAccessIterator, class Compare>
+void AdjustHeap (DocNumArray::iterator docNumHeap,
+		     RandomAccessIterator parallelHeap,
+		     unsigned long holeIndex,
+		     unsigned long heapSize,
+		     const Compare &comp) {
+  unsigned long secondChild = 2 * holeIndex + 2;
+  while (secondChild < heapSize) {
+    if (comp(*(parallelHeap + secondChild),
+	     *(parallelHeap + (secondChild - 1))))
+      secondChild--;
+    swap (*(parallelHeap+holeIndex), *(parallelHeap+secondChild));
+    swap (*(docNumHeap+holeIndex), *(docNumHeap+secondChild));
+    holeIndex = secondChild;
+    secondChild = 2 * secondChild + 2;
+  }
+  if (secondChild == heapSize) {
+    swap (*(parallelHeap+holeIndex), *(parallelHeap+(secondChild-1)));
+    swap (*(docNumHeap+holeIndex), *(docNumHeap+(secondChild-1)));
+    holeIndex = secondChild - 1;
+  }
+  PushHeap (docNumHeap, parallelHeap, holeIndex+1, comp);
+}
+
+template <class RandomAccessIterator, class Compare>
+void PopHeap (DocNumArray::iterator docNumHeap,
+	      RandomAccessIterator parallelHeap,
+	      unsigned long heapSize,
+	      const Compare &comp) {
+  swap (*(parallelHeap), *(parallelHeap+heapSize-1));
+  swap (*(docNumHeap), *(docNumHeap+heapSize-1));
+  AdjustHeap (docNumHeap, parallelHeap, 0, heapSize-1, comp);
+}
+
+template <class RandomAccessIterator, class Compare>
+void MakeHeap (DocNumArray::iterator docNumHeap,
+	       RandomAccessIterator parallelHeap,
+	       unsigned long size,
+	       const Compare &comp) {
+  if (size < 2) return;
+  
+  unsigned long i = 0;
+  for (i=1; i<=size; i++)
+    PushHeap (docNumHeap, parallelHeap, i, comp);
+}
+
+ 
+template <class RandomAccessIterator, class Compare>
+void SortHeap (DocNumArray::iterator docNumHeap,
+	       RandomAccessIterator parallelHeap,
+	       unsigned long size,
+	       const Compare &comp) {
+  if (size < 2) return;
+
+  unsigned long i;
+  for (i=size; i>1; i--)
+    PopHeap (docNumHeap, parallelHeap, i, comp);
+}
+
+// uses the heap to get the top "size" elements
+template <class RandomAccessIterator, class Compare>
+void SelectAddHeap (DocNumArray::iterator docNumHeap,
+		    RandomAccessIterator parallelHeap,
+		    unsigned long heapSize,
+		    DocNumArray::iterator docNumAdd,
+		    RandomAccessIterator parallelAdd,
+		    unsigned long addSize,
+		    const Compare &comp) {
+  unsigned long i;
+  for (i=0; i<addSize; i++) {
+    if (comp(*(parallelAdd+i), *(parallelHeap))) {
+      swap (*(docNumHeap), *(docNumAdd+i));
+      swap (*(parallelHeap), *(parallelAdd+i));
+      AdjustHeap (docNumHeap, parallelHeap, 0, heapSize, comp);
+    }
+  }
+}
+
+#endif
Index: /main/tags/2.25/gsdl/src/mgpp/text/QueryTester.cpp
===================================================================
--- /main/tags/2.25/gsdl/src/mgpp/text/QueryTester.cpp	(revision 21064)
+++ /main/tags/2.25/gsdl/src/mgpp/text/QueryTester.cpp	(revision 21064)
@@ -0,0 +1,449 @@
+/**************************************************************************
+ *
+ * QueryTester.cpp -- 
+ * Copyright (C) 1999  Rodger McNab
+ *
+ * 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.
+ *
+ * $Id$
+ *
+ **************************************************************************/
+
+#include "MGQuery.h"
+
+
+class SetQueryNode : public QueryNode {
+public:
+  QueryResult queryResult;
+  
+  SetQueryNode () {}
+  ~SetQueryNode () {}
+
+  void Calculate (IndexData &/*indexData*/, const QueryInfo &queryInfo,
+		  QueryResult &result) const {
+    result = queryResult;
+    if (!queryInfo.sortByRank && !queryInfo.needRankInfo)
+      result.ranks.erase (result.ranks.begin(), result.ranks.end());
+    if (!queryInfo.needTermFreqs)
+      result.termFreqs.erase (result.termFreqs.begin(),
+			      result.termFreqs.end());
+  }
+  void Free () { queryResult.Clear(); }
+};
+
+
+bool Test1 () {
+  AndQueryNode andNode;
+
+  SetQueryNode *setNode1 = new SetQueryNode;
+  DocNumArray &docSet1 = setNode1->queryResult.docs;
+  RankArray &rankSet1 = setNode1->queryResult.ranks;
+  docSet1.push_back (1);  rankSet1.push_back (0.1);
+  docSet1.push_back (10); rankSet1.push_back (0.2);
+  docSet1.push_back (15); rankSet1.push_back (0.2);
+  docSet1.push_back (18); rankSet1.push_back (0.4);
+  docSet1.push_back (19); rankSet1.push_back (0.5);
+
+  SetQueryNode *setNode2 = new SetQueryNode;
+  DocNumArray &docSet2 = setNode2->queryResult.docs;
+  RankArray &rankSet2 = setNode2->queryResult.ranks;
+  docSet2.push_back (2);  rankSet2.push_back (0.1);
+  docSet2.push_back (11); rankSet2.push_back (0.2);
+  docSet2.push_back (12); rankSet2.push_back (0.3);
+  docSet2.push_back (13); rankSet2.push_back (0.4);
+  docSet2.push_back (14); rankSet2.push_back (0.5);
+  docSet2.push_back (15); rankSet2.push_back (0.6);
+  docSet2.push_back (16); rankSet2.push_back (0.7);
+  docSet2.push_back (17); rankSet2.push_back (0.8);
+  docSet2.push_back (19); rankSet2.push_back (0.9);
+  docSet2.push_back (20); rankSet2.push_back (0.1);
+  docSet2.push_back (21); rankSet2.push_back (0.2);
+
+  cout << "\n" << setNode1->queryResult << "AND\n\n"
+       << setNode2->queryResult;
+  
+
+  andNode.leftNode = setNode1;
+  andNode.rightNode = setNode2;
+
+  IndexData indexData; // this will not be used anywhere
+  QueryInfo queryInfo;
+  queryInfo.maxDocs = 0;
+  queryInfo.sortByRank = true;
+  queryInfo.needRankInfo = true;
+  queryInfo.needTermFreqs = true;
+  
+  QueryResult result;
+
+  andNode.Calculate(indexData, queryInfo, result);
+
+  cout << "EQUALS\n\n" << result << "\n";
+
+  QueryResult resultCompare;
+  DocNumArray &rcDocSet = resultCompare.docs;
+  RankArray &rcRankSet = resultCompare.ranks;
+  rcDocSet.push_back (15);  rcRankSet.push_back (0.2+0.6);
+  rcDocSet.push_back (19);  rcRankSet.push_back (1.4);
+
+  if (result != resultCompare) {
+    cout << "Test failed!!!\n";
+    cout << resultCompare;
+    return false;
+  }
+
+  return true;
+}
+
+bool Test1b () {
+  AndQueryNode andNode;
+
+  SetQueryNode *setNode1 = new SetQueryNode;
+  DocNumArray &docSet1 = setNode1->queryResult.docs;
+  docSet1.push_back (1); 
+  docSet1.push_back (10);
+  docSet1.push_back (15);
+  docSet1.push_back (18);
+  docSet1.push_back (19);
+
+  SetQueryNode *setNode2 = new SetQueryNode;
+  DocNumArray &docSet2 = setNode2->queryResult.docs;
+  docSet2.push_back (2); 
+  docSet2.push_back (11);
+  docSet2.push_back (12);
+  docSet2.push_back (13);
+  docSet2.push_back (14);
+  docSet2.push_back (15);
+  docSet2.push_back (16);
+  docSet2.push_back (17);
+  docSet2.push_back (19);
+  docSet2.push_back (20);
+  docSet2.push_back (21);
+
+  cout << "\n" << setNode1->queryResult << "AND\n\n"
+       << setNode2->queryResult;
+  
+
+  andNode.leftNode = setNode1;
+  andNode.rightNode = setNode2;
+
+  IndexData indexData; // this will not be used anywhere
+  QueryInfo queryInfo;
+  queryInfo.maxDocs = 0;
+  queryInfo.sortByRank = false;
+  queryInfo.needRankInfo = false;
+  queryInfo.needTermFreqs = true;
+  
+  QueryResult result;
+
+  andNode.Calculate(indexData, queryInfo, result);
+
+  cout << "EQUALS\n\n" << result << "\n";
+
+  QueryResult resultCompare;
+  DocNumArray &rcDocSet = resultCompare.docs;
+  rcDocSet.push_back (15); 
+  rcDocSet.push_back (19); 
+
+  if (result != resultCompare) {
+    cout << "Test failed!!!\n";
+    cout << resultCompare;
+    return false;
+  }
+
+  return true;
+}
+
+bool Test2 () {
+  OrQueryNode orNode;
+
+  SetQueryNode *setNode1 = new SetQueryNode;
+  DocNumArray &docSet1 = setNode1->queryResult.docs;
+  RankArray &rankSet1 = setNode1->queryResult.ranks;
+  docSet1.push_back (1);  rankSet1.push_back (0.1);
+  docSet1.push_back (10); rankSet1.push_back (0.2);
+  docSet1.push_back (15); rankSet1.push_back (0.2);
+  docSet1.push_back (18); rankSet1.push_back (0.4);
+  docSet1.push_back (19); rankSet1.push_back (0.5);
+
+  SetQueryNode *setNode2 = new SetQueryNode;
+  DocNumArray &docSet2 = setNode2->queryResult.docs;
+  RankArray &rankSet2 = setNode2->queryResult.ranks;
+  docSet2.push_back (2);  rankSet2.push_back (0.1);
+  docSet2.push_back (11); rankSet2.push_back (0.2);
+  docSet2.push_back (12); rankSet2.push_back (0.3);
+  docSet2.push_back (13); rankSet2.push_back (0.4);
+  docSet2.push_back (14); rankSet2.push_back (0.5);
+  docSet2.push_back (15); rankSet2.push_back (0.6);
+  docSet2.push_back (16); rankSet2.push_back (0.7);
+  docSet2.push_back (17); rankSet2.push_back (0.8);
+  docSet2.push_back (19); rankSet2.push_back (0.9);
+  docSet2.push_back (20); rankSet2.push_back (0.1);
+  docSet2.push_back (21); rankSet2.push_back (0.2);
+
+  cout << "\n" << setNode1->queryResult << "OR\n\n"
+       << setNode2->queryResult;
+  
+
+  orNode.leftNode = setNode1;
+  orNode.rightNode = setNode2;
+
+  IndexData indexData; // this will not be used anywhere
+  QueryInfo queryInfo;
+  queryInfo.maxDocs = 0;
+  queryInfo.sortByRank = true;
+  queryInfo.needRankInfo = true;
+  queryInfo.needTermFreqs = true;
+  
+  QueryResult result;
+
+  orNode.Calculate(indexData, queryInfo, result);
+
+  cout << "EQUALS\n\n" << result << "\n";
+
+  QueryResult resultCompare;
+  DocNumArray &rcDocSet = resultCompare.docs;
+  RankArray &rcRankSet = resultCompare.ranks;
+  rcDocSet.push_back (1);  rcRankSet.push_back (0.1);
+  rcDocSet.push_back (2);  rcRankSet.push_back (0.1);
+  rcDocSet.push_back (10); rcRankSet.push_back (0.2);
+  rcDocSet.push_back (11); rcRankSet.push_back (0.2);
+  rcDocSet.push_back (12); rcRankSet.push_back (0.3);
+  rcDocSet.push_back (13); rcRankSet.push_back (0.4);
+  rcDocSet.push_back (14); rcRankSet.push_back (0.5);
+  rcDocSet.push_back (15); rcRankSet.push_back (0.2+0.6);
+  rcDocSet.push_back (16); rcRankSet.push_back (0.7);
+  rcDocSet.push_back (17); rcRankSet.push_back (0.8);
+  rcDocSet.push_back (18); rcRankSet.push_back (0.4);
+  rcDocSet.push_back (19); rcRankSet.push_back (0.9+0.5);
+  rcDocSet.push_back (20); rcRankSet.push_back (0.1);
+  rcDocSet.push_back (21); rcRankSet.push_back (0.2);
+  
+
+  if (result != resultCompare) {
+    cout << "Test failed!!!\n";
+    cout << resultCompare;
+    return false;
+  }
+
+  return true;
+}
+
+bool Test2b () {
+  OrQueryNode orNode;
+
+  SetQueryNode *setNode1 = new SetQueryNode;
+  DocNumArray &docSet1 = setNode1->queryResult.docs;
+  docSet1.push_back (1); 
+  docSet1.push_back (10);
+  docSet1.push_back (15);
+  docSet1.push_back (18);
+  docSet1.push_back (19);
+
+  SetQueryNode *setNode2 = new SetQueryNode;
+  DocNumArray &docSet2 = setNode2->queryResult.docs;
+  docSet2.push_back (2);
+  docSet2.push_back (11);
+  docSet2.push_back (12);
+  docSet2.push_back (13);
+  docSet2.push_back (14);
+  docSet2.push_back (15);
+  docSet2.push_back (16);
+  docSet2.push_back (17);
+  docSet2.push_back (19);
+  docSet2.push_back (20);
+  docSet2.push_back (21);
+
+  cout << "\n" << setNode1->queryResult << "OR\n\n"
+       << setNode2->queryResult;
+  
+
+  orNode.leftNode = setNode1;
+  orNode.rightNode = setNode2;
+
+  IndexData indexData; // this will not be used anywhere
+  QueryInfo queryInfo;
+  queryInfo.maxDocs = 0;
+  queryInfo.sortByRank = false;
+  queryInfo.needRankInfo = false;
+  queryInfo.needTermFreqs = true;
+  
+  QueryResult result;
+
+  orNode.Calculate(indexData, queryInfo, result);
+
+  cout << "EQUALS\n\n" << result << "\n";
+
+  QueryResult resultCompare;
+  DocNumArray &rcDocSet = resultCompare.docs;
+  rcDocSet.push_back (1);
+  rcDocSet.push_back (2); 
+  rcDocSet.push_back (10);
+  rcDocSet.push_back (11);
+  rcDocSet.push_back (12);
+  rcDocSet.push_back (13);
+  rcDocSet.push_back (14);
+  rcDocSet.push_back (15);
+  rcDocSet.push_back (16);
+  rcDocSet.push_back (17);
+  rcDocSet.push_back (18);
+  rcDocSet.push_back (19);
+  rcDocSet.push_back (20);
+  rcDocSet.push_back (21);
+  
+
+  if (result != resultCompare) {
+    cout << "Test failed!!!\n";
+    cout << resultCompare;
+    return false;
+  }
+
+  return true;
+}
+
+bool Test3 () {
+  NotQueryNode notNode;
+
+  SetQueryNode *setNode1 = new SetQueryNode;
+  DocNumArray &docSet1 = setNode1->queryResult.docs;
+  RankArray &rankSet1 = setNode1->queryResult.ranks;
+  docSet1.push_back (1);  rankSet1.push_back (0.1);
+  docSet1.push_back (10); rankSet1.push_back (0.2);
+  docSet1.push_back (15); rankSet1.push_back (0.2);
+  docSet1.push_back (18); rankSet1.push_back (0.4);
+  docSet1.push_back (19); rankSet1.push_back (0.5);
+
+  SetQueryNode *setNode2 = new SetQueryNode;
+  DocNumArray &docSet2 = setNode2->queryResult.docs;
+  RankArray &rankSet2 = setNode2->queryResult.ranks;
+  docSet2.push_back (2);  rankSet2.push_back (0.1);
+  docSet2.push_back (11); rankSet2.push_back (0.2);
+  docSet2.push_back (12); rankSet2.push_back (0.3);
+  docSet2.push_back (13); rankSet2.push_back (0.4);
+  docSet2.push_back (14); rankSet2.push_back (0.5);
+  docSet2.push_back (15); rankSet2.push_back (0.6);
+  docSet2.push_back (16); rankSet2.push_back (0.7);
+  docSet2.push_back (17); rankSet2.push_back (0.8);
+  docSet2.push_back (19); rankSet2.push_back (0.9);
+  docSet2.push_back (20); rankSet2.push_back (0.1);
+  docSet2.push_back (21); rankSet2.push_back (0.2);
+
+  cout << "\n" << setNode1->queryResult << "NOT\n\n"
+       << setNode2->queryResult;
+  
+
+  notNode.queryNode = setNode1;
+  notNode.notNode = setNode2;
+
+  IndexData indexData; // this will not be used anywhere
+  QueryInfo queryInfo;
+  queryInfo.maxDocs = 0;
+  queryInfo.sortByRank = true;
+  queryInfo.needRankInfo = true;
+  queryInfo.needTermFreqs = true;
+  
+  QueryResult result;
+
+  notNode.Calculate(indexData, queryInfo, result);
+
+  cout << "EQUALS\n\n" << result << "\n";
+
+  QueryResult resultCompare;
+  DocNumArray &rcDocSet = resultCompare.docs;
+  RankArray &rcRankSet = resultCompare.ranks;
+  rcDocSet.push_back (1);  rcRankSet.push_back (0.1);
+  rcDocSet.push_back (10); rcRankSet.push_back (0.2);
+  rcDocSet.push_back (18); rcRankSet.push_back (0.4);
+  
+
+  if (result != resultCompare) {
+    cout << "Test failed!!!\n";
+    cout << resultCompare;
+    return false;
+  }
+
+  return true;
+}
+
+bool Test3b () {
+  NotQueryNode notNode;
+
+  SetQueryNode *setNode1 = new SetQueryNode;
+  DocNumArray &docSet1 = setNode1->queryResult.docs;
+  docSet1.push_back (1); 
+  docSet1.push_back (10);
+  docSet1.push_back (15);
+  docSet1.push_back (18);
+  docSet1.push_back (19);
+
+  SetQueryNode *setNode2 = new SetQueryNode;
+  DocNumArray &docSet2 = setNode2->queryResult.docs;
+  docSet2.push_back (2); 
+  docSet2.push_back (11);
+  docSet2.push_back (12);
+  docSet2.push_back (13);
+  docSet2.push_back (14);
+  docSet2.push_back (15);
+  docSet2.push_back (16);
+  docSet2.push_back (17);
+  docSet2.push_back (19);
+  docSet2.push_back (20);
+  docSet2.push_back (21);
+
+  cout << "\n" << setNode1->queryResult << "NOT\n\n"
+       << setNode2->queryResult;
+  
+
+  notNode.queryNode = setNode1;
+  notNode.notNode = setNode2;
+
+  IndexData indexData; // this will not be used anywhere
+  QueryInfo queryInfo;
+  queryInfo.maxDocs = 0;
+  queryInfo.sortByRank = false;
+  queryInfo.needRankInfo = false;
+  queryInfo.needTermFreqs = true;
+  
+  QueryResult result;
+
+  notNode.Calculate(indexData, queryInfo, result);
+
+  cout << "EQUALS\n\n" << result << "\n";
+
+  QueryResult resultCompare;
+  DocNumArray &rcDocSet = resultCompare.docs;
+  rcDocSet.push_back (1); 
+  rcDocSet.push_back (10);
+  rcDocSet.push_back (18);
+  
+
+  if (result != resultCompare) {
+    cout << "Test failed!!!\n";
+    cout << resultCompare;
+    return false;
+  }
+
+  return true;
+}
+
+
+int main () {
+  if (!Test1 () ||
+      !Test2 () ||
+      !Test2b () ||
+      !Test3 () ||
+      !Test3b ()) return 1;
+  
+  return 0;
+}
Index: /main/tags/2.25/gsdl/src/mgpp/text/Queryer.cpp
===================================================================
--- /main/tags/2.25/gsdl/src/mgpp/text/Queryer.cpp	(revision 21064)
+++ /main/tags/2.25/gsdl/src/mgpp/text/Queryer.cpp	(revision 21064)
@@ -0,0 +1,188 @@
+/**************************************************************************
+ *
+ * Queryer.cpp -- simple interactive query program
+ * Copyright (C) 1999  Rodger McNab
+ *
+ * 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.
+ *
+ * $Id$
+ *
+ **************************************************************************/
+
+#include "MGQuery.h"
+#include "TextGet.h"
+
+#include "messages.h"
+#include "mg_files.h"
+
+#include "GSDLQueryParser.h"
+
+
+int main (int argc, char **argv) {
+  int ch;
+  char *textfilename = "";
+  char *indexfilename = "";
+  char *basePath = "";
+  
+  opterr = 0;
+  msg_prefix = argv[0];
+  
+  // process the command line arguments
+  while ((ch = getopt (argc, argv, "f:t:d:h")) != -1) {
+    switch (ch) {
+    case 'f':		/* input file */
+      indexfilename = optarg;
+      break;
+    case 't':
+      textfilename = optarg;
+      break;
+    case 'd':
+      basePath = optarg;
+      set_basepath (basePath);
+      break;
+    case 'h':
+    case '?':
+      fprintf (stderr, "usage: %s [-h] [-d directory] -f indexname -t textname\n", argv[0]);
+      exit (1);
+    }
+  }
+
+  if (textfilename[0] == '\0' || indexfilename[0] == '\0') {
+    FatalError (1, "Index and text file names must be specified with -f and -t \n");
+  }
+  
+  // init the text system
+  TextData textData;
+  if (!textData.LoadData (basePath, textfilename)) {
+    FatalError (1, "Couldn't load text information for \"%s\"", textfilename);
+  }
+  
+  // init the query system
+  IndexData indexData;
+  if (!indexData.LoadData (basePath, indexfilename)) {
+    FatalError (1, "Couldn't load index information for \"%s\"", indexfilename);
+  }
+
+  // do querying
+  QueryInfo queryInfo;
+  SetCStr (queryInfo.docLevel, "Document");
+  queryInfo.maxDocs = 50;
+  queryInfo.sortByRank = true;
+  queryInfo.exactWeights = false;
+  queryInfo.needRankInfo = true;
+  queryInfo.needTermFreqs = true;
+  
+  ExtQueryResult queryResult;
+  char query[2048];
+  UCArray queryArray;
+  QueryNode *queryTree = NULL;
+
+
+  UCArray docLevel;
+  SetCStr(docLevel, "Document");
+
+  UCArray level;
+  UCArrayClear(level);
+  //SetCStr(level, "");
+   
+  int defaultStemMethod = 1; // casefolded, unstemmed
+
+  BrowseQueryNode browseNode;
+  browseNode.startPosition = -10;
+  browseNode.numTerms = 40;
+
+  BrowseQueryResult browseResult;
+
+  while (true) {
+    //    cerr << "getting next line\n";
+    cout << "> ";
+    cin.getline(query, 2048, '\n');
+    SetCStr (queryArray, query);
+
+    // check for commands
+    if (queryArray.size() >= 2 && queryArray[0] == '.') {
+      if (queryArray[1] == 'q') break;  // quit
+      
+
+      if (queryArray[1] == 'i') {
+	cout << "current index="<< queryInfo.docLevel << "\nchange to index:";
+	cin >> query;
+	UCArrayClear(queryInfo.docLevel);
+	SetCStr(queryInfo.docLevel, query);
+	cout << "index set to " << queryInfo.docLevel <<"\n";
+	cin.getline(query, 2048, '\n');
+      }
+      if (queryArray[1] == 'l') {
+	cout << "current level="<< level << "\nchange to level:";
+	cin >> query;
+	UCArrayClear(level);
+	SetCStr(level, query);
+	cout << "level set to " << level <<"\n";
+	cin.getline(query, 2048, '\n');
+      }
+
+
+      else if (queryArray[1] == 'p') {
+	// print
+	UCArray docText;
+	unsigned long docNum = 0;
+	cin >> docNum;
+	cin.getline(query, 2048, '\n'); // eat up return
+
+	if (!GetDocText (textData, queryInfo.docLevel, docNum, docText)) {
+	  FatalError (1, "Error while trying to get document %u", docNum);
+	}
+
+	cout << docText << "\n";
+      }
+      else if (queryArray[1] == 'b') {
+	// full text browse
+	cout<<"enter a few letters to start browsing from:";
+	cin>>query;
+	UCArrayClear(browseNode.term);
+	SetCStr(browseNode.term, query);
+	cin.getline(query, 2048, '\n'); // get rest of line
+
+	// print the query
+	PrintNode (cout, &browseNode);
+
+	MGBrowseQuery(indexData, docLevel, browseNode, browseResult);
+	cout << browseResult;
+	cout << "\n";
+
+    } 
+    } else {
+      // regular query
+      queryTree = ParseQuery (queryArray, defaultStemMethod);
+
+      // print the query
+      PrintNode (cout, queryTree);
+
+      MGQuery (indexData, queryInfo, queryTree, queryResult, level);
+      cout << queryResult;
+      cout << "\n";
+      
+      // delete the query
+      if (queryTree != NULL) delete queryTree;
+      queryTree = NULL;
+    }
+  }
+
+
+  // clean up, everybody clean up
+  textData.UnloadData ();
+  indexData.UnloadData ();
+}
+
Index: /main/tags/2.25/gsdl/src/mgpp/text/TagInfo.cpp
===================================================================
--- /main/tags/2.25/gsdl/src/mgpp/text/TagInfo.cpp	(revision 21064)
+++ /main/tags/2.25/gsdl/src/mgpp/text/TagInfo.cpp	(revision 21064)
@@ -0,0 +1,76 @@
+/**************************************************************************
+ *
+ * TagInfo.cpp -- 
+ * Copyright (C) 1999  Rodger McNab
+ *
+ * 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.
+ *
+ * $Id$
+ *
+ **************************************************************************/
+
+#include "TagInfo.h"
+
+
+void TagInfo::SetDocTag (const char *cStr) {
+  SetCStr (docTag, cStr);
+}
+
+void TagInfo::SetIndexLevel (const char *cStr) {
+  SetCStr (indexLevel, cStr);
+}
+void TagInfo::AddLevelTag (const char *cStr) {
+  // convert the string
+  UCArray cArr;
+  SetCStr (cArr, cStr);
+
+  // insert the tag
+  levelTags.insert (cArr);
+}
+
+
+TagInfo::TagInfo () {
+  Clear ();
+}
+
+void TagInfo::Clear () {
+  docTag.erase (docTag.begin(), docTag.end());
+  indexLevel.erase (indexLevel.begin(), indexLevel.end());
+  levelTags.erase (levelTags.begin(), levelTags.end());
+}
+
+ostream &operator<<(ostream &s, const TagInfo &t) {
+  // output docTag
+  s << "docTag: \"" << t.docTag << "\"\n";
+
+  // output indexLevel
+  s << "indexLevel: \"" << t.indexLevel << "\"\n";
+
+  // output levelTags
+  s << "levelTags: ";
+
+  UCArraySet::const_iterator here = t.levelTags.begin();
+  UCArraySet::const_iterator end = t.levelTags.end();
+  while (here != end) {
+    s << "\"" << (*here) << "\"";
+    here++;
+    if (here != end) s << ", ";
+  }
+
+  s << "\n";
+  
+  return s;
+}
+
Index: /main/tags/2.25/gsdl/src/mgpp/text/TagInfo.h
===================================================================
--- /main/tags/2.25/gsdl/src/mgpp/text/TagInfo.h	(revision 21064)
+++ /main/tags/2.25/gsdl/src/mgpp/text/TagInfo.h	(revision 21064)
@@ -0,0 +1,48 @@
+/**************************************************************************
+ *
+ * TagInfo.h -- 
+ * Copyright (C) 1999  Rodger McNab
+ *
+ * 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.
+ *
+ * $Id$
+ *
+ **************************************************************************/
+
+#ifndef TAGINFO_H
+#define TAGINFO_H
+
+#include "UCArray.h"
+
+
+class TagInfo {
+public:
+  UCArray docTag;
+  UCArray indexLevel;    // empty for word level index
+  UCArraySet levelTags;
+
+  void SetDocTag (const char *cStr);
+  void SetIndexLevel (const char *cStr);
+  void AddLevelTag (const char *cStr);
+  
+  TagInfo ();
+  void Clear ();
+};
+
+// stream operator to print TagInfo
+ostream &operator<<(ostream &s, const TagInfo &t);
+
+
+#endif
Index: /main/tags/2.25/gsdl/src/mgpp/text/Terms.cpp
===================================================================
--- /main/tags/2.25/gsdl/src/mgpp/text/Terms.cpp	(revision 21064)
+++ /main/tags/2.25/gsdl/src/mgpp/text/Terms.cpp	(revision 21064)
@@ -0,0 +1,768 @@
+/**************************************************************************
+ *
+ * Terms.cpp -- Query related functions
+ * Copyright (C) 1999  Rodger McNab
+ *
+ * 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.
+ *
+ * $Id$
+ *
+ **************************************************************************/
+
+#include "Terms.h"
+#include "words.h"
+#include "stemmer.h"
+#include "bitio_gen.h"
+#include "bitio_m_stdio.h"
+
+void QueryInfo::Clear () {
+  UCArrayClear (docLevel);
+  maxDocs = 0;
+  sortByRank = true;
+  exactWeights = false;
+  needRankInfo = false;
+  needTermFreqs = false;
+}
+
+
+
+void TermFreqData::Clear () {
+  UCArrayClear (tag);
+  UCArrayClear (term);
+  stemMethod = 0;
+  matchDocs = 0;
+  termFreq = 0;
+}
+
+ostream &operator<< (ostream &s, const TermFreqData &t) {
+  s << "<" << t.tag << ">\"" << t.term << "\"stem("
+    << t.stemMethod << ")docs(" << t.matchDocs << ")"
+    << "count("<<t.termFreq<<")";
+  return s;
+}
+
+bool operator== (const TermFreqData &t1, const TermFreqData &t2) {
+  return ((t1.tag == t2.tag) &&
+	  (t1.term == t2.term) &&
+	  (t1.stemMethod == t2.stemMethod) &&
+	  (t1.matchDocs == t2.matchDocs) &&
+	  (t1.termFreq == t2.termFreq));
+}
+
+
+void QueryResult::Clear () {
+  docs.erase (docs.begin(), docs.end());
+  ranks.erase (ranks.begin(), ranks.end());
+  termFreqs.erase (termFreqs.begin(), termFreqs.end());
+}
+
+QueryResult::QueryResult () {
+  Clear ();
+}
+
+
+
+ostream &operator<< (ostream &s, const QueryResult &r) {
+  s << "docs: ";
+  unsigned long i;
+  for (i=0; i<r.docs.size(); i++)
+    s << r.docs[i] << ", ";
+  
+  s << "\nranks: ";
+  for (i=0; i<r.ranks.size(); i++)
+    s << r.ranks[i] << ", ";
+
+  s << "\ntermFreqs: ";
+  for (i=0; i<r.termFreqs.size(); i++)
+    s << r.termFreqs[i] << ", ";
+  s << "\n\n";
+
+  return s;
+}
+
+
+bool operator== (const QueryResult &r1, const QueryResult &r2) {
+  return ((r1.docs == r2.docs) &&
+	  (r1.ranks == r2.ranks) &&
+	  (r1.termFreqs == r2.termFreqs));
+}
+
+//---------------------------------------------------
+// new ExtQueryResult stuff
+void ExtQueryResult::Clear () {
+  docs.erase (docs.begin(), docs.end());
+  levels.erase (levels.begin(), levels.end());
+  ranks.erase (ranks.begin(), ranks.end());
+  termFreqs.erase (termFreqs.begin(), termFreqs.end());
+}
+
+ExtQueryResult::ExtQueryResult () {
+  Clear ();
+}
+
+ostream &operator<< (ostream &s, const ExtQueryResult &r) {
+  s << "docs: ";
+  unsigned long i;
+  for (i=0; i<r.docs.size(); i++)
+    s << r.docs[i] << ", ";
+
+  s << "\nlevels: ";
+  for (i=0; i<r.levels.size(); i++)
+    s << r.levels[i] << ", ";
+
+  
+  s << "\nranks: ";
+  for (i=0; i<r.ranks.size(); i++)
+    s << r.ranks[i] << ", ";
+
+  s << "\ntermFreqs: ";
+  for (i=0; i<r.termFreqs.size(); i++)
+    s << r.termFreqs[i] << ", ";
+  s << "\n\n";
+
+  return s;
+}
+
+
+bool operator== (const ExtQueryResult &r1, const ExtQueryResult &r2) {
+  return ((r1.docs == r2.docs) &&
+	  (r1.levels == r2.levels) &&
+	  (r1.ranks == r2.ranks) &&
+	  (r1.termFreqs == r2.termFreqs));
+}
+
+//-------------------------------------------------------
+// new BrowseQueryResult stuff
+void BrowseQueryResult::Clear () {
+  termFreqs.erase (termFreqs.begin(), termFreqs.end());
+}
+
+BrowseQueryResult::BrowseQueryResult () {
+  Clear ();
+}
+
+
+
+ostream &operator<< (ostream &s, const BrowseQueryResult &r) {
+  s << "terms: ";
+  unsigned long i;
+  for (i=0; i<r.termFreqs.size(); i++)
+    s << r.termFreqs[i] << ", ";
+    s << "\n\n";
+  return s;
+}
+
+
+bool operator== (const BrowseQueryResult &r1, const BrowseQueryResult &r2) {
+  return ((r1.termFreqs == r2.termFreqs));
+	 
+}
+
+
+
+
+//--------------------------------------
+void FragData::Clear () {
+  matchDocs = 0;
+  fragNums.erase (fragNums.begin(), fragNums.end());
+  fragFreqs.erase (fragFreqs.begin(), fragFreqs.end());
+}
+
+
+
+
+void FindWordNumbers (IndexData &indexData,
+		      const UCArray &term,
+		      unsigned long stemMethod,
+		      vector<unsigned long> &equivWords) {
+  equivWords.erase (equivWords.begin(), equivWords.end());
+  
+  if (stemMethod == 0) {
+    // don't need to stem the word,
+    // find the word number for this term
+    unsigned long wordElNum = 0;
+    unsigned long numLevels = indexData.bdh.num_levels;
+    word_block_dict_el wordDictEl;
+    wordDictEl.SetNumLevels (numLevels);
+    if (SearchWordBlockDictEl (indexData.dictFile, indexData.biWords,
+			       indexData.bdh.entries_per_wblk,
+			       indexData.bdh.word_dict_size,
+			       numLevels, term, wordDictEl, wordElNum))
+      equivWords.push_back (wordElNum);
+    
+    return;
+    
+  }
+
+
+  // need to stem this word and find it in the blocked stem index
+  
+  unsigned char  mgWord[MAXSTEMLEN + 1];
+  UCArray stemTerm;
+  unsigned long stemmerNum = 0;
+  
+  if (stemMethod == 1) stemmerNum = indexData.sih1.stemmer_num;
+  else if (stemMethod == 2) stemmerNum = indexData.sih2.stemmer_num;
+  else if (stemMethod == 3) stemmerNum = indexData.sih3.stemmer_num;
+  
+  
+  // convert the word to an "mg word"
+  mgWord[0] = term.size();
+  bcopy ((char *)term.begin(), (char *)&mgWord[1], term.size());
+  
+  // stem the word
+  stemmer (stemMethod, stemmerNum, mgWord);
+
+  // convert the result back to a UCArray
+  stemTerm.insert (stemTerm.end(), &mgWord[1], &mgWord[1] + mgWord[0]);
+
+  // need to look up this term in the appropriate dictionary
+  stem_block_dict_el stemDictEl;
+  unsigned long stemElNum;
+  if (stemMethod == 1) {
+    SearchStemBlockDictEl (indexData.stem1File,
+			   indexData.sii1,
+			   indexData.sih1.entries_per_block,
+			   indexData.sih1.dict_size,
+			   stemTerm,
+			   stemDictEl,
+			   stemElNum);
+
+  } else if (stemMethod == 2) {
+    SearchStemBlockDictEl (indexData.stem2File,
+			   indexData.sii2,
+			   indexData.sih2.entries_per_block,
+			   indexData.sih2.dict_size,
+			   stemTerm,
+			   stemDictEl,
+			   stemElNum);
+
+  } else if (stemMethod == 3) {
+    SearchStemBlockDictEl (indexData.stem3File,
+			   indexData.sii3,
+			   indexData.sih3.entries_per_block,
+			   indexData.sih3.dict_size,
+			   stemTerm,
+			   stemDictEl,
+			   stemElNum);
+  }
+
+  equivWords = stemDictEl.equivWords;  
+}
+
+
+
+void ReadTermFragData (IndexData &indexData,
+		       bool needFragFreqs,
+		       unsigned long termNum,
+		       FragData &fragData,
+		       FragRangeArray *fragLimits) {
+  fragData.Clear();
+
+  // look up the word in the dictionary
+  unsigned long numLevels = indexData.bdh.num_levels;
+  word_block_dict_el wordDictEl;
+  wordDictEl.SetNumLevels (numLevels);
+  if (!SearchWordBlockDictElNum (indexData.dictFile,
+				 indexData.biWords,
+				 indexData.bdh.entries_per_wblk,
+				 indexData.bdh.word_dict_size,
+				 numLevels,
+				 termNum, wordDictEl))
+    return; // nothing more to do
+
+  fragData.matchDocs = wordDictEl.levelFreqs[indexData.curLevelNum];
+
+  // seek to the appropriate place in the inverted file
+  fseek (indexData.invfFile, wordDictEl.invf_ptr, SEEK_SET);
+  stdio_bitio_buffer buffer (indexData.invfFile);
+    
+  unsigned long B = BIO_Bblock_Init (indexData.bdh.num_frags,
+				     wordDictEl.frag_occur);
+  unsigned long fragNum = 0;
+  unsigned long termFreq = 0;
+
+  unsigned long fragLimitI = 0;
+  unsigned long i;
+  for (i=0; i<wordDictEl.frag_occur; i++) {
+    fragNum += buffer.bblock_decode (B, NULL);
+    if (!indexData.ifh.word_level_index) termFreq = buffer.gamma_decode (NULL);
+    else termFreq = 1;
+
+    // get the right fragment range
+    if (fragLimits != NULL) {
+      while (fragLimitI+1 < (*fragLimits).size() &&
+	     fragNum > (*fragLimits)[fragLimitI+1].rangeStart) {
+	fragLimitI++;
+      }
+    }
+
+    // add the entry if it is within the limits
+    if ((fragLimits == NULL) ||
+	(fragLimitI < (*fragLimits).size() &&
+	 fragNum > (*fragLimits)[fragLimitI].rangeStart &&
+	 fragNum <= (*fragLimits)[fragLimitI].rangeEnd)) {
+      fragData.fragNums.push_back (fragNum);
+      if (needFragFreqs)
+	fragData.fragFreqs.push_back (termFreq);
+    }
+  }
+
+  buffer.done();
+}
+
+
+void CombineFragData (bool needFragFreqs,
+		      const FragData &f1,
+		      const FragData &f2,
+		      FragData &outFragData) {
+  outFragData.Clear();
+
+  // the new number of matching documents is the maximum
+  // of the two input matching number of documents -- it
+  // is assumed that these are at the same document level
+  outFragData.matchDocs = (f1.matchDocs > f2.matchDocs) ?
+    f1.matchDocs : f2.matchDocs;
+
+  // do or
+  unsigned long f1I = 0, f1Size = f1.fragNums.size();
+  unsigned long f2I = 0, f2Size = f2.fragNums.size();
+  while (f1I < f1Size || f2I < f2Size) {
+    if (f2I < f2Size &&
+	(f1I >= f1Size ||
+	 f1.fragNums[f1I] > f2.fragNums[f2I])) {
+      // output f2I
+      outFragData.fragNums.push_back (f2.fragNums[f2I]);
+      if (needFragFreqs)
+	outFragData.fragFreqs.push_back (f2.fragFreqs[f2I]);
+      f2I++;
+      
+    } else if (f1I < f1Size &&
+	       (f2I >= f2Size ||
+		f1.fragNums[f1I] < f2.fragNums[f2I])) {
+      // output f1I
+      outFragData.fragNums.push_back (f1.fragNums[f1I]);
+      if (needFragFreqs)
+	outFragData.fragFreqs.push_back (f1.fragFreqs[f1I]);
+      f1I++;
+      
+    } else {
+      // must be equal combine f1I and f2I
+      outFragData.fragNums.push_back (f1.fragNums[f1I]);
+      if (needFragFreqs)
+	outFragData.fragFreqs.push_back (f1.fragFreqs[f1I]+f2.fragFreqs[f2I]);
+      f1I++;
+      f2I++;
+    }
+  }
+}
+
+
+void AndCombineFragData (bool needFragFreqs,
+			 FragData &fragData,
+			 const FragData &comFragData,
+			 signed long startRange,
+			 signed long endRange,
+			 const FragRangeArray *fragLimits) {
+  // sanity check on range
+  if (startRange > endRange) {
+    signed long temp = endRange;
+    endRange = startRange;
+    startRange = temp;
+  }
+
+  // get min matchdocs
+  if (comFragData.matchDocs < fragData.matchDocs)
+    fragData.matchDocs = comFragData.matchDocs;
+  
+  unsigned long fragDataI = 0;
+  unsigned long fragDataSize = fragData.fragNums.size();
+  unsigned long comFragDataI = 0;
+  unsigned long comFragDataSize = comFragData.fragNums.size();
+  unsigned long fragLimitI = 0;
+  unsigned long fragLimitSize = (fragLimits==NULL) ? 0 : (*fragLimits).size();
+  unsigned long outI = 0;
+
+  while (fragDataI < fragDataSize &&
+	 comFragDataI < comFragDataSize) {
+    signed long fragNum = (signed long)fragData.fragNums[fragDataI];
+    signed long comFragNum = (signed long)comFragData.fragNums[comFragDataI];
+    
+    // go to the right fragment limit (for the com frag)
+    if (fragLimits != NULL) {
+      while (fragLimitI+1 < fragLimitSize &&
+	     comFragNum > (signed long)(*fragLimits)[fragLimitI+1].rangeStart) {
+	fragLimitI++;
+      }
+    }
+
+    if (fragNum <= comFragNum+startRange ||
+	(fragLimits!=NULL &&
+	 fragNum<=(signed long)(*fragLimits)[fragLimitI].rangeStart)) {
+      fragDataI++;
+      
+    } else if (fragNum > comFragNum+endRange ||
+	       (fragLimits!=NULL &&
+		fragNum>(signed long)(*fragLimits)[fragLimitI].rangeEnd)) {
+      comFragDataI++;
+      
+    } else {
+      // equal and within tag
+      fragData.fragNums[outI] = comFragNum;
+      if (needFragFreqs) {
+	fragData.fragFreqs[outI] =
+	  (fragData.fragFreqs[fragDataI] < comFragData.fragFreqs[comFragDataI]) ?
+	  fragData.fragFreqs[fragDataI] : comFragData.fragFreqs[comFragDataI];
+      }
+      fragDataI++;
+      comFragDataI++;
+      outI++;
+    }
+  }
+
+  // erase unused part of fragData
+  fragData.fragNums.erase (fragData.fragNums.begin()+outI,
+			   fragData.fragNums.end());
+  if (needFragFreqs)
+    fragData.fragFreqs.erase (fragData.fragFreqs.begin()+outI,
+			      fragData.fragFreqs.end());
+  else
+    fragData.fragFreqs.erase (fragData.fragFreqs.begin(),
+			      fragData.fragFreqs.end());
+}
+
+
+void FragsToQueryResult (IndexData &indexData,
+			 const QueryInfo &queryInfo,
+			 const FragData &termData,
+			 const UCArray &tag,
+			 const UCArray &term,
+			 unsigned long stemMethod,
+			 unsigned long termWeight,
+			 QueryResult &result) {
+  bool needRanks = (queryInfo.sortByRank || queryInfo.needRankInfo);
+  
+  result.Clear();
+
+  // log (N / ft)
+  unsigned long N = indexData.levels.levelInfo[indexData.curLevel].numEntries;
+  float wordLog = log((double)N / (double)termData.matchDocs);
+
+  // Wqt = fqt * log (N / ft)
+  // note: terms are allowed to have a weight of zero so
+  // they can be excluded from the ranking
+  float Wqt = termWeight * wordLog;
+
+  // Wdt = fdt * log (N / ft)
+  float Wdt;
+  
+  unsigned long termDataI = 0;
+  unsigned long termDataSize = termData.fragNums.size();
+  unsigned long levelDocNum = 0;
+  
+  unsigned long termDocFreq = 0;
+  unsigned long lastLevelDocNum = 0;
+  unsigned long overallwordfreq = 0;
+  
+  while (termDataI < termDataSize) {
+    if (indexData.levelConverter.FragToLevel (termData.fragNums[termDataI],
+					      levelDocNum)) {
+      if (levelDocNum != lastLevelDocNum) {
+	if (lastLevelDocNum > 0) {
+	  // add this doc information
+	  if (needRanks) {
+	    Wdt = termDocFreq * wordLog;
+	    result.ranks.push_back (Wqt * Wdt);
+	  }
+	  result.docs.push_back (lastLevelDocNum);
+	}
+	
+	lastLevelDocNum = levelDocNum;
+	termDocFreq = 0;
+      }
+
+      if (needRanks)
+	termDocFreq += termData.fragFreqs[termDataI];
+      overallwordfreq += termData.fragFreqs[termDataI];
+    }
+    
+    termDataI++;
+  }
+
+  if (lastLevelDocNum > 0) {
+    // add the last document information
+    if (needRanks) {
+      Wdt = termDocFreq * wordLog;
+      result.ranks.push_back (Wqt * Wdt);
+    }
+    result.docs.push_back (lastLevelDocNum);
+  }
+
+  // add the term frequency information
+  if (queryInfo.needTermFreqs) {
+    TermFreqData termFreqData;
+    termFreqData.tag = tag;
+    termFreqData.term = term;
+    termFreqData.stemMethod = stemMethod;
+    termFreqData.matchDocs = termData.matchDocs;
+    termFreqData.termFreq = overallwordfreq;
+    result.termFreqs.push_back (termFreqData);
+  }
+}
+
+void AndFragsToQueryResult (IndexData &indexData,
+			    const QueryInfo &queryInfo,
+			    const FragData &termData,
+			    const UCArray &tag,
+			    const UCArray &term,
+			    unsigned long stemMethod,
+			    unsigned long termWeight,
+			    QueryResult &result) {
+  bool needRanks = (queryInfo.sortByRank || queryInfo.needRankInfo);
+  
+  // log (N / ft)
+  float wordLog =
+    log((double)indexData.levels.levelInfo[indexData.curLevel].numEntries/
+	(double)termData.matchDocs);
+
+  // Wqt = fqt * log (N / ft)
+  // note: terms are allowed to have a weight of zero so
+  // they can be excluded from the ranking
+  float Wqt = termWeight * wordLog;
+
+  // Wdt = fdt * log (N / ft)
+  float Wdt;
+  
+  unsigned long termDataI = 0;
+  unsigned long termDataSize = termData.fragNums.size();
+  unsigned long levelDocNum = 0;
+  
+  unsigned long termDocFreq = 0;
+  unsigned long lastLevelDocNum = 0;
+  unsigned long overallwordfreq = 0;
+  unsigned long resultI = 0;
+  unsigned long resultSize = result.docs.size();
+  unsigned long resultOutI = 0;
+  
+  
+  while (termDataI < termDataSize) {
+    if (indexData.levelConverter.FragToLevel (termData.fragNums[termDataI],
+					      levelDocNum)) {
+      if (levelDocNum != lastLevelDocNum) {
+	if (lastLevelDocNum > 0) {
+	  // add this doc information
+	  Wdt = termDocFreq * wordLog;
+	  
+	  // find this document number
+	  while (resultI < resultSize &&
+		 result.docs[resultI] < lastLevelDocNum)
+	    resultI++;
+	  
+	  // store the result
+	  if (resultI < resultSize && result.docs[resultI] == lastLevelDocNum) {
+	    result.docs[resultOutI] = lastLevelDocNum;
+	    if (needRanks)
+	      result.ranks[resultOutI] = result.ranks[resultI] + Wqt * Wdt;
+	    resultI++;
+	    resultOutI++;
+	  }
+	}
+	
+	lastLevelDocNum = levelDocNum;
+	termDocFreq = 0;
+      }
+
+      if (needRanks)
+	termDocFreq += termData.fragFreqs[termDataI];
+     overallwordfreq += termData.fragFreqs[termDataI]; 
+    }
+    
+    termDataI++;
+  } // while
+
+  if (lastLevelDocNum > 0) {
+    // add the last document information
+    Wdt = termDocFreq * wordLog;
+
+    // find this document number
+    while (resultI < resultSize &&
+	   result.docs[resultI] < lastLevelDocNum)
+      resultI++;
+    
+    // store the result
+    if (resultI < resultSize && result.docs[resultI] == lastLevelDocNum) {
+      result.docs[resultOutI] = lastLevelDocNum;
+      if (needRanks)
+	result.ranks[resultOutI] = result.ranks[resultI] + Wqt * Wdt;
+      resultI++;
+      resultOutI++;
+    }
+  }
+
+  // remove unneeded entries
+  result.docs.erase (result.docs.begin()+resultOutI, result.docs.end());
+  if (needRanks)
+    result.ranks.erase (result.ranks.begin()+resultOutI, result.ranks.end());
+  else
+    result.ranks.erase (result.ranks.begin(), result.ranks.end());
+  
+  // add the term frequency information
+  if (queryInfo.needTermFreqs) {
+    TermFreqData termFreqData;
+    termFreqData.tag = tag;
+    termFreqData.term = term;
+    termFreqData.stemMethod = stemMethod;
+    termFreqData.matchDocs = termData.matchDocs;
+    termFreqData.termFreq = overallwordfreq;
+    result.termFreqs.push_back (termFreqData);
+  }
+}
+
+
+void RemoveUnwantedResults (IndexData &indexData,
+			    const QueryInfo &queryInfo,
+			    const FragData &termData,
+			    QueryResult &result) {
+  bool needRanks = (queryInfo.sortByRank || queryInfo.needRankInfo);
+
+  unsigned long termDataI = 0;
+  unsigned long termDataSize = termData.fragNums.size();
+  unsigned long levelDocNum = 0;
+  
+  unsigned long lastLevelDocNum = 0;
+
+  unsigned long resultI = 0;
+  unsigned long resultSize = result.docs.size();
+  unsigned long resultOutI = 0;
+  
+  while (termDataI < termDataSize) {
+    if (indexData.levelConverter.FragToLevel (termData.fragNums[termDataI],
+					      levelDocNum)) {
+      if (levelDocNum != lastLevelDocNum) {
+	if (lastLevelDocNum > 0) {
+	  // find this document number
+	  while (resultI < resultSize &&
+		 result.docs[resultI] < lastLevelDocNum)
+	    resultI++;
+	  
+	  // store the result
+	  if (resultI < resultSize && result.docs[resultI] == lastLevelDocNum) {
+	    result.docs[resultOutI] = lastLevelDocNum;
+	    if (needRanks)
+	      result.ranks[resultOutI] = result.ranks[resultI];
+	    resultI++;
+	  resultOutI++;
+	  }
+	}
+	
+	lastLevelDocNum = levelDocNum;
+      }
+    }
+    
+    termDataI++;
+  }
+
+  if (lastLevelDocNum > 0) {
+    // find this document number
+    while (resultI < resultSize &&
+	   result.docs[resultI] < lastLevelDocNum)
+      resultI++;
+    
+    // store the result
+    if (resultI < resultSize && result.docs[resultI] == lastLevelDocNum) {
+      result.docs[resultOutI] = lastLevelDocNum;
+      if (needRanks) 
+	result.ranks[resultOutI] = result.ranks[resultI];
+      resultI++;
+      resultOutI++;
+    }
+  }
+
+  // remove unneeded entries
+  result.docs.erase (result.docs.begin()+resultOutI, result.docs.end());
+  if (needRanks)
+    result.ranks.erase (result.ranks.begin()+resultOutI, result.ranks.end());
+  else
+    result.ranks.erase (result.ranks.begin(), result.ranks.end());
+}
+
+
+
+//--------------------------------------------------------------
+// functions to support full text browse
+
+void FindNearestWordNumber (IndexData &indexData,
+			    const UCArray &term,
+			    unsigned long &number) {
+
+    // find the word number for this term
+    unsigned long wordElNum = 0;
+    unsigned long numLevels = indexData.bdh.num_levels;
+    word_block_dict_el wordDictEl;
+    wordDictEl.SetNumLevels (numLevels);
+    if (NearestSearchWordBlockDictEl (indexData.dictFile, indexData.biWords,
+				      indexData.bdh.entries_per_wblk,
+				      indexData.bdh.word_dict_size,
+				      numLevels, term, wordDictEl, wordElNum))
+      number = wordElNum;
+
+}
+
+void GetTermList(IndexData &indexData,
+		 unsigned long startTerm,
+		 unsigned long numTerms,
+		 TermFreqArray &terms) {
+
+  word_block_dict_el_array wordBlocks; // = new word_block_dict_el_array();
+  TermFreqData termdata;
+
+  terms.erase(terms.begin(), terms.end());
+
+  SearchWordBlockDictElNumRange (indexData.dictFile, indexData.biWords,
+				 indexData.bdh.entries_per_wblk,
+				 indexData.bdh.word_dict_size,
+				 indexData.bdh.num_levels, startTerm,
+				 numTerms, wordBlocks);
+
+  word_block_dict_el_array::iterator here = wordBlocks.begin();
+  word_block_dict_el_array::iterator end = wordBlocks.end();
+
+  while (here != end) {
+    termdata.Clear();
+    termdata.term = (*here).el;
+    termdata.termFreq = (*here).freq;
+    terms.push_back(termdata);
+    here++;
+  }
+
+}
+
+void GetTermList(IndexData &indexData,
+		 unsigned long startTerm,
+		 unsigned long numTerms,
+		 UCArrayVector &terms) {
+
+  
+  
+  SearchWordBlockDictElNumRange (indexData.dictFile, indexData.biWords,
+				 indexData.bdh.entries_per_wblk,
+				 indexData.bdh.word_dict_size,
+				 indexData.bdh.num_levels, startTerm,
+				 numTerms, terms);
+
+}
+
+
+
Index: /main/tags/2.25/gsdl/src/mgpp/text/Terms.h
===================================================================
--- /main/tags/2.25/gsdl/src/mgpp/text/Terms.h	(revision 21064)
+++ /main/tags/2.25/gsdl/src/mgpp/text/Terms.h	(revision 21064)
@@ -0,0 +1,216 @@
+/**************************************************************************
+ *
+ * Terms.h -- Query related functions
+ * Copyright (C) 1999  Rodger McNab
+ *
+ * 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.
+ *
+ * $Id$
+ *
+ **************************************************************************/
+
+#ifndef TERMS_H
+#define TERMS_H
+
+#include "IndexData.h"
+
+#if defined(GSDL_USE_OBJECTSPACE)
+#  include <ospace\std\iostream>
+#elif defined(GSDL_USE_IOS_H)
+#  include <iostream.h>
+#else
+#  include <iostream>
+#endif
+
+
+class QueryInfo {
+public:
+  // general query information
+  UCArray docLevel;
+  unsigned long maxDocs; // 0 = all
+  bool sortByRank;
+  bool exactWeights;
+
+  // information need to return
+  bool needRankInfo;
+  bool needTermFreqs;
+
+  void Clear ();
+  QueryInfo () { Clear (); }
+};
+
+
+class TermFreqData {
+public:
+  UCArray tag;  // level tag or query tag
+  UCArray term; // unstemmed term
+  int stemMethod;
+  unsigned long matchDocs; // tf for level - num levels
+			   // containing this term
+  unsigned long termFreq;  // overall term freq - num words that
+				// are this term
+  void Clear ();
+  TermFreqData () { Clear (); }
+};
+
+ostream &operator<< (ostream &s, const TermFreqData &t);
+bool operator== (const TermFreqData &t1, const TermFreqData &t2);
+
+typedef vector<TermFreqData> TermFreqArray;
+
+
+typedef vector<float> RankArray;
+typedef vector<unsigned long> DocNumArray;
+
+class QueryResult {
+public:
+  DocNumArray docs;
+  RankArray ranks; // used for accumulators during query
+  
+  TermFreqArray termFreqs;
+  
+  void Clear ();
+  QueryResult ();
+};
+
+ostream &operator<< (ostream &s, const QueryResult &r);
+bool operator== (const QueryResult &r1, const QueryResult &r2);
+
+typedef vector<unsigned long> FragNumArray;
+typedef vector<unsigned long> FragFreqArray;
+
+class FragData {
+public:
+  unsigned long matchDocs;    // ft for level
+  FragNumArray fragNums;
+  FragFreqArray fragFreqs;
+
+  void Clear ();
+  FragData () { Clear (); }
+};
+
+
+class FragRange {
+public:
+  unsigned long rangeStart;
+  unsigned long rangeEnd;
+
+  void Clear () { rangeStart = rangeEnd = 0; }
+  FragRange () { Clear (); }
+};
+
+typedef vector<FragRange> FragRangeArray;
+
+
+
+void FindWordNumbers (IndexData &indexData,
+		      const UCArray &term,
+		      unsigned long stemMethod,
+		      vector<unsigned long> &equivWords);
+
+void ReadTermFragData (IndexData &indexData,
+		       bool needFragFreqs,
+		       unsigned long termNum,
+		       FragData &fragData,
+		       FragRangeArray *fragLimits);
+
+void CombineFragData (bool needFragFreqs,
+		      const FragData &f1,
+		      const FragData &f2,
+		      FragData &outFragData);
+
+// output will be in fragData (as this is an and operation)
+void AndCombineFragData (bool needFragFreqs,
+			 FragData &fragData,
+			 const FragData &comFragData,
+			 signed long startRange,
+			 signed long endRange,
+			 const FragRangeArray *fragLimits);
+
+void FragsToQueryResult (IndexData &indexData,
+			 const QueryInfo &queryInfo,
+			 const FragData &termData,
+			 const UCArray &tag,
+			 const UCArray &term,
+			 unsigned long stemMethod,
+			 unsigned long termWeight,
+			 QueryResult &result);
+
+void AndFragsToQueryResult (IndexData &indexData,
+			    const QueryInfo &queryInfo,
+			    const FragData &termData,
+			    const UCArray &tag,
+			    const UCArray &term,
+			    unsigned long stemMethod,
+			    unsigned long termWeight,
+			    QueryResult &result);
+
+void RemoveUnwantedResults (IndexData &indexData,
+			    const QueryInfo &queryInfo,
+			    const FragData &termData,
+			    QueryResult &result);
+
+//-----------------------------------------------------------------
+// new QueryResult class to handle retrieval of doc and level nums.
+// Use this class with extended version of MGQuery
+
+class ExtQueryResult : public QueryResult {
+public:
+  DocNumArray levels; // used for returning a different granularity, eg
+  // search sections but return Document numbers, or search Documents, 
+  // return Section numbers.
+ 
+  void Clear ();
+  ExtQueryResult ();
+};
+
+ostream &operator<< (ostream &s, const ExtQueryResult &r);
+bool operator== (const ExtQueryResult &r1, const ExtQueryResult &r2);
+
+//------------------------------------------------------------
+// new functions to handle full text browse
+
+class BrowseQueryResult {
+ public:
+  TermFreqArray termFreqs;
+  void Clear();
+  BrowseQueryResult ();
+
+};
+
+
+ostream &operator<< (ostream &s, const BrowseQueryResult &r);
+bool operator== (const BrowseQueryResult &r1, const BrowseQueryResult &r2);
+
+void FindNearestWordNumber (IndexData &indexData,
+			    const UCArray &term,
+			    unsigned long &number);
+
+void GetTermList(IndexData &indexData,
+		 unsigned long startTerm,
+		 unsigned long numTerms,
+		 TermFreqArray &terms);
+
+void GetTermList (IndexData &indexData,
+		 unsigned long startTerm,
+		 unsigned long numTerms,
+		 UCArrayVector &terms);
+
+#endif
+
+
+
+
+
Index: /main/tags/2.25/gsdl/src/mgpp/text/TextEl.cpp
===================================================================
--- /main/tags/2.25/gsdl/src/mgpp/text/TextEl.cpp	(revision 21064)
+++ /main/tags/2.25/gsdl/src/mgpp/text/TextEl.cpp	(revision 21064)
@@ -0,0 +1,213 @@
+/**************************************************************************
+ *
+ * TextEl.cpp -- Data structures for parsed documents
+ * Copyright (C) 1999  Rodger McNab
+ *
+ * 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.
+ *
+ * $Id$
+ *
+ **************************************************************************/
+
+#include "TextEl.h"
+#include "ctype.h"
+
+#define REC_TERM   '\002'
+#define PARA_TERM  '\003'
+
+
+void TextEl::Clear () {
+  elType = TextE;
+  tagName.erase (tagName.begin(), tagName.end());
+  text.erase (text.begin(), text.end());
+}
+
+
+static bool ReadTextTag (FileBuf &buf, TextEl &el) {
+  // we must have some sort of tag
+  unsigned char c;
+  if (!buf.Peek(c)) return false;
+  
+  // get the '<'
+  if (c != '<') return false;
+  el.text.push_back (c);
+  if (!buf.Next() || !buf.Peek (c)) return false;
+  
+  // see if we have a '/'
+  if (c == '/') {
+    // we have a closing tag
+    el.text.push_back (c);
+    if (!buf.Next() || !buf.Peek (c)) return false;
+    el.elType = CloseTagE;
+  } else {
+    // we have an opening tag
+    el.elType = OpenTagE;
+  }
+
+  // get the tag name
+  while (isalnum(c)) {
+    el.text.push_back (c);
+    el.tagName.push_back (c);
+    if (!buf.Next() || !buf.Peek (c)) return false;
+  }
+  
+  // get everything up to the closing '>'
+  while (c != '>') {
+    el.text.push_back (c);
+    if (!buf.Next() || !buf.Peek (c)) return false;
+  }
+
+  // get the closing '>'
+  el.text.push_back (c);
+  buf.Next();
+
+  // if there is no tag name then make this a text element
+  if (el.tagName.empty()) el.elType = TextE;
+  
+  return true;
+}
+
+static void ToggleParaTag (TextEl &el, bool &compatInPara) {
+  SetCStr (el.tagName, "Paragraph");
+  el.text.erase (el.text.begin(), el.text.end());
+  if (compatInPara) {
+    el.elType = CloseTagE;
+    el.text.push_back (PARA_TERM);
+  } else el.elType = OpenTagE;
+  compatInPara = !compatInPara;
+}
+
+static void SetRecTag (TextEl &el, TextElType elType) {
+  el.elType = elType;
+  SetCStr (el.tagName, "Document");
+  el.text.erase (el.text.begin(), el.text.end());
+  if (elType == CloseTagE)
+    el.text.push_back (REC_TERM);
+}
+
+
+bool ReadTextEl (FileBuf &buf, TextEl &el,
+		 bool compatMode, bool &compatInPara) {
+  el.Clear();
+
+  unsigned char c;
+  if (!buf.Peek (c)) return false;
+
+  if (compatMode) {
+    if (c == PARA_TERM) {
+      ToggleParaTag (el, compatInPara);
+      if (!compatInPara) buf.Next();
+      return true;
+    }
+    if (c == REC_TERM) {
+      if (compatInPara) {
+	// need to close this paragraph
+	ToggleParaTag (el, compatInPara);
+	return true;
+      }
+      // can close this document
+      buf.Next();
+      SetRecTag (el, CloseTagE);
+      return true;
+    }
+    if (!compatInPara) {
+      // need to open a paragraph
+      ToggleParaTag (el, compatInPara);
+      return true;
+    }
+  }
+  
+  // see if we have some sort of tag
+  if (c == '<') return ReadTextTag (buf, el);
+
+  // read in a text element
+  el.elType = TextE;
+  while (c != '<' && !(compatMode && (c == PARA_TERM || c == REC_TERM))) {
+    el.text.push_back (c);
+    if (!buf.Next() || !buf.Peek (c)) break;
+  }
+
+  return true;
+}
+
+static void AddTextEl (TextElArray &doc, unsigned long &docLen,
+		       const TextEl &el) {
+  doc.push_back (el);
+  docLen += el.text.size();
+
+//    cout << "elType:  " << el.elType << "\n";
+//    cout << "tagName: " << el.tagName << "\n";
+//    cout << "text:    \"" << el.text << "\"\n\n";
+}
+
+
+bool ReadDoc (FileBuf &buf, const UCArray &docTag,
+	      TextElArray &doc, unsigned long &docLen,
+	      bool compatMode) {
+  bool compatInPara = false;
+  bool foundDocEl = false;
+  TextEl el;
+  
+  doc.erase (doc.begin(), doc.end());
+  docLen = 0;
+
+  if (compatMode) {
+    // add <Document><Paragraph>
+    SetRecTag (el, OpenTagE);
+    AddTextEl (doc, docLen, el);
+    ToggleParaTag (el, compatInPara);
+    AddTextEl (doc, docLen, el);
+    
+  } else {
+    // look for an opening docTag
+    do {
+      if (!ReadTextEl (buf, el, compatMode, compatInPara)) return false;
+    } while (el.elType != OpenTagE || el.tagName != docTag);
+    
+    AddTextEl (doc, docLen, el);
+  }
+
+  
+  // get all elements until the closing docTag
+  while (ReadTextEl (buf, el, compatMode, compatInPara)) {
+    foundDocEl = true;
+    AddTextEl (doc, docLen, el);
+    if (el.elType == CloseTagE && el.tagName == docTag)
+      return true;
+  }
+
+  
+  if (compatMode) {
+    if (!foundDocEl) { // end of text
+      doc.erase (doc.begin(), doc.end());
+      return false;
+    }
+
+    // if we got here then the eof was encountered before
+    // the closing document tag
+    if (compatInPara) {
+      // need to close this paragraph
+      ToggleParaTag (el, compatInPara);
+      AddTextEl (doc, docLen, el);
+    }
+    // close this document
+    SetRecTag (el, CloseTagE);
+    AddTextEl (doc, docLen, el);
+  }
+  
+  return true;
+}
+
+
Index: /main/tags/2.25/gsdl/src/mgpp/text/TextEl.h
===================================================================
--- /main/tags/2.25/gsdl/src/mgpp/text/TextEl.h	(revision 21064)
+++ /main/tags/2.25/gsdl/src/mgpp/text/TextEl.h	(revision 21064)
@@ -0,0 +1,64 @@
+/**************************************************************************
+ *
+ * TextEl.h -- Data structures for parsed documents
+ * Copyright (C) 1999  Rodger McNab
+ *
+ * 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.
+ *
+ * $Id$
+ *
+ **************************************************************************/
+
+#ifndef TEXTEL_H
+#define TEXTEL_H
+
+#include "UCArray.h"
+#include "FileBuf.h"
+
+
+enum TextElType {OpenTagE, CloseTagE, TextE};
+
+class TextEl {
+protected:
+  bool ReadTextTag (FileBuf &buf, TextEl &el);
+public:
+  TextElType elType;
+  UCArray tagName;
+  UCArray text; // complete text, including tag
+
+  TextEl () { Clear (); }
+  void Clear ();
+};
+
+
+typedef vector<TextEl> TextElArray;
+
+
+// compatMode parses documents similar to "old mg" -- ie with
+// C-b between documents and C-c between paragraphs
+
+// returns true if a text element could be read
+bool ReadTextEl (FileBuf &buf, TextEl &el,
+		 bool compatMode, bool &compatInPara);
+
+// looks for an opening docTag and reads all text elements up
+// to a corresponding closing docTag. note that this does not
+// hierarchically parse the document so you can't nest documents.
+// returns true if a document could be found
+bool ReadDoc (FileBuf &buf, const UCArray &docTag,
+	      TextElArray &doc, unsigned long &docLen,
+	      bool compatMode=false);
+
+#endif
Index: /main/tags/2.25/gsdl/src/mgpp/text/TextGet.cpp
===================================================================
--- /main/tags/2.25/gsdl/src/mgpp/text/TextGet.cpp	(revision 21064)
+++ /main/tags/2.25/gsdl/src/mgpp/text/TextGet.cpp	(revision 21064)
@@ -0,0 +1,678 @@
+/**************************************************************************
+ *
+ * TextGet.cpp -- Decompressing the text
+ * Copyright (C) 1999  Rodger McNab
+ *
+ * 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.
+ *
+ * $Id$
+ *
+ **************************************************************************/
+
+#include "TextGet.h"
+#include "mg_files.h"
+#include "netorder.h"
+#include "mg_errors.h"
+#include "locallib.h"
+#include "words.h"
+#include "local_strings.h"
+#include "bitio_m_stdio.h"
+
+typedef enum huff_type {lengths, chars};
+
+
+static auxiliary_dict *LoadAuxDict (compression_dict &cd, FILE *text_aux_dict) {
+  auxiliary_dict *ad;
+  int i;
+
+  if (!(ad = new auxiliary_dict))
+    {
+      mg_errno = MG_NOMEM;
+      return (NULL);
+    }
+
+  bzero ((char *) ad, sizeof (*ad));
+
+  for (i = 0; i <= 1; i++)
+    {
+      int j;
+      u_char *pos;
+
+      fread (&ad->afh[i], sizeof (aux_frags_header), 1, text_aux_dict);
+
+      /* [RPAP - Jan 97: Endian Ordering] */
+      NTOHUL(ad->afh[i].num_frags);
+      NTOHUL(ad->afh[i].mem_for_frags);
+
+      if (!(ad->word_data[i] = new u_char[ad->afh[i].mem_for_frags]))
+	{
+	  mg_errno = MG_NOMEM;
+	  delete ad;
+	  return (NULL);
+	}
+      if (!(ad->words[i] = new u_char* [ad->afh[i].num_frags]))
+	{
+	  mg_errno = MG_NOMEM;
+	  delete ad;
+	  return (NULL);
+	}
+
+      fread (ad->word_data[i], ad->afh[i].mem_for_frags, sizeof (u_char),
+	     text_aux_dict);
+
+      pos = ad->word_data[i];
+      for (j = 0; j < (int)ad->afh[i].num_frags; j++)
+	{
+	  ad->words[i][j] = pos;
+	  pos += *pos + 1;
+	}
+      if (cd.cdh.novel_method == MG_NOVEL_HYBRID)
+	{
+	  int num;
+	  num = 1;
+	  ad->blk_start[i][0] = 0;
+	  ad->blk_end[i][0] = cd.cdh.num_words[i] - 1;
+	  while (num < 33)
+	    {
+	      ad->blk_start[i][num] = ad->blk_end[i][num - 1] + 1;
+	      ad->blk_end[i][num] = ad->blk_start[i][num] +
+		(ad->blk_end[i][num - 1] - ad->blk_start[i][num - 1]) * 2;
+	      num++;
+	    }
+	}
+    }
+  return (ad);
+}
+
+
+static u_char ***ReadInWords (FILE *dict, compression_dict &cd,
+			      comp_frags_header *cfh, u_char **escape) {
+  int i, lookback;
+  int ptrs_reqd = 0;
+  int mem_reqd = 0;
+  int num_set[MAX_HUFFCODE_LEN + 1];
+  u_char *next_word[MAX_HUFFCODE_LEN + 1];
+  u_char **vals;
+  u_char ***values;
+  u_char word[MAXWORDLEN + 1];
+  u_char last_word[MAX_HUFFCODE_LEN + 1][MAXWORDLEN + 1];
+
+  lookback = cd.cdh.lookback;
+
+  for (i = cfh->hd.mincodelen; i <= cfh->hd.maxcodelen; i++) {
+    ptrs_reqd += (cfh->hd.lencount[i] + ((1 << lookback) - 1)) >> lookback;
+    mem_reqd += cfh->huff_words_size[i];
+  }
+
+  if (!(vals = new u_char* [ptrs_reqd]))
+    return (NULL);
+
+  if (!(values = new u_char** [MAX_HUFFCODE_LEN + 1]))
+    return (NULL);
+
+  if (!(next_word[0] = new u_char[mem_reqd])) 
+    return (NULL);
+
+  cd.MemForCompDict += ptrs_reqd * sizeof (*vals) +
+    (MAX_HUFFCODE_LEN + 1) * sizeof (u_char **) +
+    mem_reqd;
+
+  values[0] = vals;
+  values[0][0] = next_word[0];
+  for (i = 1; i <= cfh->hd.maxcodelen; i++)
+    {
+      int next_start = (values[i - 1] - vals) +
+      ((cfh->hd.lencount[i - 1] + ((1 << lookback) - 1)) >> lookback);
+      values[i] = &vals[next_start];
+      next_word[i] = next_word[i - 1] + cfh->huff_words_size[i - 1];
+      values[i][0] = next_word[i];
+    }
+
+  bzero ((char *) num_set, sizeof (num_set));
+
+  for (i = 0; i < cfh->hd.num_codes; i++)
+    {
+      register int val, copy;
+      register int len = cfh->hd.clens[i];
+      val = getc (dict);
+      copy = (val >> 4) & 0xf;
+      val &= 0xf;
+
+      fread (word + copy + 1, sizeof (u_char), val, dict);
+      *word = val + copy;
+
+      if ((num_set[len] & ((1 << lookback) - 1)) == 0)
+	{
+	  values[len][num_set[len] >> lookback] = next_word[len];
+	  memcpy (next_word[len], word, *word + 1);
+	  if (escape && i == cfh->hd.num_codes - 1)
+	    *escape = next_word[len];
+	  next_word[len] += *word + 1;
+	}
+      else
+	{
+	  copy = prefixlen (last_word[len], word);
+	  memcpy (next_word[len] + 1, word + copy + 1, *word - copy);
+	  *next_word[len] = (copy << 4) + (*word - copy);
+	  if (escape && i == cfh->hd.num_codes - 1)
+	    *escape = next_word[len];
+	  next_word[len] += (*word - copy) + 1;
+	}
+      memcpy (last_word[len], word, *word + 1);
+      num_set[len]++;
+    }
+  if (cfh->hd.clens)
+    delete cfh->hd.clens;
+  cfh->hd.clens = NULL;
+  return values;
+}
+
+static int Load_Comp_HuffData(compression_dict &cd, int which, FILE *dict, 
+			      huff_type type) {
+  huff_data * hd;
+  u_long **   vals;
+
+  if (!(hd = new huff_data))
+    return 1;
+  cd.MemForCompDict += sizeof (huff_data);
+  if (Read_Huffman_Data (dict, hd, &cd.MemForCompDict, NULL) == -1)
+    return 2;
+  if (!(vals = Generate_Huffman_Vals (hd, &cd.MemForCompDict)))
+    return 3;
+  if (hd->clens)
+    delete hd->clens;
+  hd->clens = NULL;
+  if (type == chars)
+    {
+      cd.chars_huff[which] = hd;
+      cd.chars_vals[which] = vals;
+    }
+  else
+    {
+      cd.lens_huff[which] = hd;
+      cd.lens_vals[which] = vals;
+    }
+
+  return 0;
+}
+
+static int Load_Comp_FragsHeader(compression_dict &cd, int which, int getEscape,
+				 FILE *dict) {
+  if (!(cd.cfh[which] = new comp_frags_header))
+    return 1;
+  cd.MemForCompDict += sizeof (*cd.cfh[which]);
+  if (Read_cfh (dict, cd.cfh[which], &cd.MemForCompDict, NULL) == -1)
+    return 2;
+
+  if (!(cd.values[which] = ReadInWords (dict, cd, cd.cfh[which],
+					getEscape == 0 ? NULL : &cd.escape[which])))
+    return 3;
+  
+  return 0;
+}
+
+static bool LoadSlowCompDict (FILE *dict, FILE *aux_dict, compression_dict &cd) {
+  if (dict == NULL) return false;
+
+  int which;
+
+  bzero ((char *) &cd, sizeof (compression_dict));
+
+  cd.MemForCompDict = sizeof (compression_dict);
+
+  if (Read_cdh (dict, &cd.cdh, &cd.MemForCompDict, NULL) == -1)
+    return false;
+
+  for (which = 0; which < 2; which++)
+    switch (cd.cdh.dict_type)
+      {
+      case MG_COMPLETE_DICTIONARY:
+	{
+	  if (Load_Comp_FragsHeader(cd, which, 0, dict) != 0)
+	    return false;
+	  cd.escape[which] = NULL;
+
+	}
+	break;
+      case MG_PARTIAL_DICTIONARY:
+	{
+	  if (cd.cdh.num_words[which])
+	    {
+	      if (Load_Comp_FragsHeader(cd, which, 1, dict) != 0)
+		return false;
+	    }
+
+	  if (Load_Comp_HuffData(cd, which, dict, chars) != 0)
+	    return false;
+
+	  if (Load_Comp_HuffData(cd, which, dict, lengths) != 0)
+	    return false;
+	}
+	break;
+      case MG_SEED_DICTIONARY:
+	{
+	  if (cd.cdh.num_words[which])
+	    {
+	      if (Load_Comp_FragsHeader(cd, which, 1, dict) != 0)
+		return false;
+	    }
+	  switch (cd.cdh.novel_method)
+	    {
+	    case MG_NOVEL_HUFFMAN_CHARS:
+	      if (Load_Comp_HuffData(cd, which, dict, chars) != 0)
+		return false;
+
+	      if (Load_Comp_HuffData(cd, which, dict, lengths) != 0)
+		return false;
+	      break;
+	    case MG_NOVEL_DELTA:
+	      break;
+	    case MG_NOVEL_HYBRID:
+	      break;
+	    }
+	  break;
+	}
+      }
+
+  if (cd.cdh.novel_method == MG_NOVEL_DELTA ||
+      cd.cdh.novel_method == MG_NOVEL_HYBRID)
+    {
+      if (!aux_dict)
+	{
+	  mg_errno = MG_NOFILE;
+	  cd.Clear();
+	  return false;
+	}
+
+      if (!(cd.ad = LoadAuxDict (cd, aux_dict)))
+	{
+	  cd.Clear();
+	  return false;
+	}
+    }
+
+  mg_errno = MG_NOERROR;
+
+  cd.fast_loaded = 0;
+  
+  return true;
+}
+
+
+
+#define WORDNO(p, base) ((((char*)(p))-((char*)(base)))/sizeof(u_char*))
+#define IS_FIXUP(p) ((fixup[WORDNO(p,cd)/8] & (1<<(WORDNO(p,cd) & 7))) != 0)
+
+// fast loading really needs to be totally re-writen. "Unloading" the
+// text data will currently cause a crash because memory is being
+// deleted multiple times (and probably a zillion other reasons).
+static bool LoadFastCompDict (FILE *text_fast_comp_dict, compression_dict &_cd) {
+  if (text_fast_comp_dict == NULL) return false;
+  
+  u_long *p, *end;
+  u_char *fixup;
+  u_long mem;
+  u_long fixup_mem;
+  int i;  /* [RPAP - Jan 97: Endian Ordering] */
+
+  fread (&mem, sizeof (mem), 1, text_fast_comp_dict);
+  NTOHUL(mem);  /* [RPAP - Jan 97: Endian Ordering] */
+  fread (&fixup_mem, sizeof (fixup_mem), 1, text_fast_comp_dict);
+  NTOHUL(fixup_mem);  /* [RPAP - Jan 97: Endian Ordering] */
+
+  compression_dict *cd;
+  if (!(cd = (compression_dict *)malloc (mem))) {
+    mg_errno = MG_NOMEM;
+    return false;
+  }
+
+  end = (u_long *) (((u_char *) cd) + mem);
+  fread (cd, sizeof (u_char), mem, text_fast_comp_dict);
+
+  if (!(fixup = new u_char[fixup_mem]))
+    {
+      mg_errno = MG_NOMEM;
+      return false;
+    }
+
+  fread (fixup, fixup_mem, sizeof (u_char), text_fast_comp_dict);
+
+  for (p = (u_long *) cd; (u_long) p < (u_long) end; p++)
+    if (IS_FIXUP (p))
+      {
+	NTOHUL(*p);  /* [RPAP - Jan 97: Endian Ordering] */
+	*p = *p + (u_long) cd;
+      }
+
+  /* [RPAP - Jan 97: Endian Ordering] */
+  /* cdh */
+  NTOHUL(cd->cdh.dict_type);
+  NTOHUL(cd->cdh.novel_method);
+  for (i = 0; i < TEXT_PARAMS; i++)
+    NTOHUL(cd->cdh.params[i]);
+  NTOHUL(cd->cdh.num_words[0]);
+  NTOHUL(cd->cdh.num_words[1]);
+  NTOHUL(cd->cdh.num_word_chars[0]);
+  NTOHUL(cd->cdh.num_word_chars[1]);
+  NTOHUL(cd->cdh.lookback);
+  /* cfh */
+  for (i = 0; i <= 1; i++)
+    {
+      int j;
+
+      NTOHSI(cd->cfh[i]->hd.num_codes);
+      NTOHSI(cd->cfh[i]->hd.mincodelen);
+      NTOHSI(cd->cfh[i]->hd.maxcodelen);
+      for (j = 0; j < MAX_HUFFCODE_LEN + 1; j++)
+	{
+	  NTOHSI(cd->cfh[i]->hd.lencount[j]);
+	  NTOHUL(cd->cfh[i]->hd.min_code[j]);
+	}
+      NTOHUL(cd->cfh[i]->uncompressed_size);
+      for (j = 0; j < MAX_HUFFCODE_LEN + 1; j++)
+	NTOHUL(cd->cfh[i]->huff_words_size[j]);
+    }
+  NTOHUL(cd->MemForCompDict);
+  /* ad */
+  if (cd->cdh.novel_method == MG_NOVEL_DELTA ||
+      cd->cdh.novel_method == MG_NOVEL_HYBRID)
+    for (i = 0; i <= 1; i++)
+      {
+	int j;
+	
+	NTOHUL(cd->ad->afh[i].num_frags);
+	NTOHUL(cd->ad->afh[i].mem_for_frags);
+	for (j = 0; j < 33; j++)
+	  {
+	    NTOHSI(cd->ad->blk_start[i][j]);
+	    NTOHSI(cd->ad->blk_end[i][j]);
+	  }
+      }
+  NTOHSI(cd->fast_loaded);
+
+  delete fixup;
+
+  // the whole fast comp dict is a bit of a hack so I don't
+  // feel too bad about the next line :-) -- Rodger.
+  _cd = *cd;
+  
+  return true;
+}
+
+
+static bool LoadCompDict (FILE *compDictFile,
+			  FILE *auxDictFile,
+			  FILE *fastCompDictFile,
+			  compression_dict &cd) {
+  // see if we have a fast loading compression dictionary
+  if (fastCompDictFile != NULL)
+    return LoadFastCompDict (fastCompDictFile, cd);
+  
+  // slow compression dictionary
+  return LoadSlowCompDict (compDictFile, auxDictFile, cd);
+}
+
+
+// try to open the dictionary files and load the dictionary
+static bool OpenLoadCompDict (char *textname, compression_dict &cd) {
+  FILE *compDictFile = NULL;
+  FILE *auxDictFile = NULL;
+  FILE *fastCompDictFile = NULL;
+
+  fastCompDictFile = open_file (textname, TEXT_DICT_FAST_SUFFIX,
+				"rb", MAGIC_FAST_DICT, MG_CONTINUE);
+  
+  if (fastCompDictFile == NULL) {
+    compDictFile = open_file (textname, TEXT_DICT_SUFFIX,
+			      "rb", MAGIC_DICT, MG_MESSAGE);
+    auxDictFile =  open_file (textname, TEXT_DICT_AUX_SUFFIX,
+			      "rb", MAGIC_AUX_DICT, MG_CONTINUE);
+  }
+  
+  bool res = LoadCompDict (compDictFile, auxDictFile, fastCompDictFile, cd);
+
+  if (compDictFile != NULL) fclose (compDictFile);
+  if (auxDictFile != NULL) fclose (auxDictFile);
+  if (fastCompDictFile != NULL) fclose (fastCompDictFile);
+  
+  return res;
+}
+
+static bool LoadLevels (char *textname, FTextLevel &levels) {
+  FILE *levelFile = NULL;
+
+  // open the text level file
+  levelFile = open_file (textname, TEXT_LEVEL_SUFFIX,
+			 "rb", MAGIC_TEXT_LEVELS, MG_CONTINUE);
+  if (levelFile == NULL) return false;
+
+  // seek to the appropriate place and read the level information
+  bool res = ((fseek (levelFile, sizeof (u_long), SEEK_SET) == 0) &&
+	      levels.Read (levelFile));
+
+  // close the file
+  fclose (levelFile);
+  
+  return res;
+}
+
+
+TextData::TextData () {
+  // put file pointers in known state first
+  textFile = NULL;
+  textIdxFile = NULL;
+  Clear ();
+}
+
+void TextData::Clear () {
+  cd.Clear(); 
+  textFile = NULL;
+  textIdxFile = NULL;
+  cth.Clear();
+  levels.Clear();
+}
+
+bool TextData::LoadData (char *basepath, char *textname) {
+  
+  if (textname[0] == '\0') return false;
+  
+  // set the basepath
+  set_basepath(basepath);
+  
+  // load the compression dictionary
+  if (!OpenLoadCompDict (textname, cd)) return false;
+
+  // open the compressed text and text index file
+  textFile = open_file (textname, TEXT_SUFFIX, "rb", MAGIC_TEXT, MG_CONTINUE);
+  if (textFile == NULL) return false;
+
+  textIdxFile = open_file (textname, TEXT_IDX_SUFFIX, "rb", MAGIC_TEXI, MG_CONTINUE);
+  if (textIdxFile == NULL) return false;
+
+  // read in the compressed text header
+  if ((fseek (textFile, sizeof (u_long), SEEK_SET) != 0) || !cth.Read (textFile))
+    return false;
+
+  // read in the level information
+  if (!LoadLevels (textname, levels)) return false;
+  
+  return true;
+}
+
+bool TextData::UnloadData () {
+  // close any open files
+  if (textFile != NULL) {
+    fclose (textFile);
+    textFile = NULL;
+  }
+  if (textIdxFile != NULL) {
+    fclose (textIdxFile);
+    textIdxFile = NULL;
+  }
+
+  // do general clear
+  Clear ();
+  
+  return true;  
+}
+
+
+bool GetDocIdx (TextData &td, const UCArray &docLevel,
+		unsigned long docNum, TextIdx &docIdx) {
+  // make sure the text index file was opened successfully
+  if (td.textIdxFile == NULL) return false;
+
+  // read in the index
+  TextLevelInfo &levelInfo = td.levels.levelInfo[docLevel];
+  if (!docIdx.Read (td.textIdxFile, levelInfo, docNum)) return false;
+  
+  return true;
+}
+
+
+
+
+#define MY_HUFF_DECODE(len, code, mcodes)				\
+  do {									\
+    register unsigned long *__min_code = (mcodes);			\
+    register unsigned long *__mclen = __min_code;			\
+    register unsigned long __code = 0;					\
+    do									\
+      {									\
+        __code += __code + buffer.bit();	                  	\
+      }									\
+    while (__code < *++__mclen);					\
+    (len) = __mclen - __min_code;					\
+    (code) = __code - *__mclen;						\
+  } while(0);
+
+
+bool GetDocText (TextData &td, const UCArray &docLevel,
+		 unsigned long docNum, UCArray &docText) {
+  // erase the current text
+  docText.erase (docText.begin(), docText.end());
+
+  // look up the information about this document
+  TextIdx docIdx;
+  if (!GetDocIdx (td, docLevel, docNum, docIdx)) return false;
+
+  // do seek to appropriate position
+  stdio_bitio_buffer buffer (td.textFile);
+  buffer.seek (docIdx.start.byte, docIdx.start.bit);
+  
+  // decompress the document
+  compression_dict &cd = td.cd;
+  auxiliary_dict *ad = cd.ad;
+  int which = docIdx.which;
+  unsigned long num_bits = (docIdx.end.byte*8+(8-docIdx.end.bit)) -
+    (docIdx.start.byte*8+(8-docIdx.start.bit));
+  unsigned long bits = 0;
+
+  // keep decoding bits until enough bits have been decoded
+  while (bits < num_bits) {
+    register unsigned code, len;
+    register int r;
+    register u_char *t, *b = NULL;
+    u_char word[MAXWORDLEN + 1];
+    
+    if (cd.cfh[which]) {
+      MY_HUFF_DECODE (len, code, cd.cfh[which]->hd.min_code);
+      bits += len;
+      
+      r = code & ((1 << cd.cdh.lookback) - 1);
+      t = cd.values[which][len][code >> cd.cdh.lookback];
+      
+      /* step through from base pointer */
+      b = word + 1;
+      while (r--) {
+	register int copy = *t >> 4;
+	memcpy (word + copy + 1, t + 1, *t & 0xf);
+	word[0] = copy + (*t & 0xf);
+	t += ((*t) & 0xf) + 1;
+      }
+    } else t = NULL;
+    
+    if (t == cd.escape[which]) {
+      switch (cd.cdh.novel_method) {
+      case MG_NOVEL_HUFFMAN_CHARS:
+	{
+	  int len, i;
+	  int c;
+	  len = buffer.huff_decode(cd.lens_huff[which]->min_code,
+				   cd.lens_vals[which], &bits);
+	  for (i = 0; i < len; i++) {
+	    c = buffer.huff_decode(cd.chars_huff[which]->min_code,
+				   cd.chars_vals[which], &bits);
+	    docText.push_back (c);
+	  }
+	}
+	break;
+      case MG_NOVEL_DELTA:
+      case MG_NOVEL_HYBRID:
+	{
+	  int idx = 0, len;
+	  u_char *base;
+	  switch (cd.cdh.novel_method)
+	    {
+	    case MG_NOVEL_DELTA:
+	      {
+		idx = buffer.delta_decode (&bits);
+		idx--;
+	      }
+	      break;
+	    case MG_NOVEL_HYBRID:
+	      {
+		int k;
+		k = buffer.gamma_decode (&bits);
+		k--;
+		idx = buffer.binary_decode(ad->blk_end[which][k] -
+					   ad->blk_start[which][k] + 1, 
+					   &bits);
+		idx += ad->blk_start[which][k] - 1;
+	      }
+	      break;
+	    }
+	  base = ad->words[which][idx];
+	  len = *base++;
+	  for (; len; len--)
+	    {
+	      docText.push_back (*base++);
+	    }
+	}
+	break;
+      }
+    }
+    else
+      {
+	/* copy over the matching prefix */
+	r = (*t >> 4);
+	while (r--) {
+	  docText.push_back (*b++);
+	}
+	
+	/* and the stored suffix */
+	r = ((*t) & 0xf);
+	while (r--) {
+	  docText.push_back (*++t);
+	}
+      }
+    which = !which;
+  }
+  
+  buffer.done();
+  
+  return true;
+}
+
Index: /main/tags/2.25/gsdl/src/mgpp/text/TextGet.h
===================================================================
--- /main/tags/2.25/gsdl/src/mgpp/text/TextGet.h	(revision 21064)
+++ /main/tags/2.25/gsdl/src/mgpp/text/TextGet.h	(revision 21064)
@@ -0,0 +1,60 @@
+/**************************************************************************
+ *
+ * TextGet.h -- Decompressing the text
+ * Copyright (C) 1999  Rodger McNab
+ *
+ * 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.
+ *
+ * $Id$
+ *
+ **************************************************************************/
+
+#ifndef TEXTGET_H
+#define TEXTGET_H
+
+#include "text.h"
+#include "FText.h"
+
+
+class TextData {
+public:
+  compression_dict cd;
+  FILE *textFile;
+  FILE *textIdxFile;
+  compressed_text_header cth;
+  FTextLevel levels;
+
+  TextData ();
+  void Clear ();
+
+  // loads compression dictionary, the compressed text header,
+  // and all level informaiton
+  bool LoadData (char *basepath, char *textname);
+  bool UnloadData ();
+};
+
+
+// note: document numbers start at 1
+
+// get information about where a document starts and finishes
+bool GetDocIdx (TextData &td, const UCArray &docLevel,
+		unsigned long docNum, TextIdx &docIdx);
+
+
+// decompress a document's text
+bool GetDocText (TextData &td, const UCArray &docLevel,
+		 unsigned long docNum, UCArray &docText);
+
+#endif
Index: /main/tags/2.25/gsdl/src/mgpp/text/UCArray.cpp
===================================================================
--- /main/tags/2.25/gsdl/src/mgpp/text/UCArray.cpp	(revision 21064)
+++ /main/tags/2.25/gsdl/src/mgpp/text/UCArray.cpp	(revision 21064)
@@ -0,0 +1,277 @@
+/**************************************************************************
+ *
+ * UCArray.cpp -- vector based string class
+ * Copyright (C) 1999  Rodger McNab
+ *
+ * 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.
+ *
+ * $Id$
+ *
+ **************************************************************************/
+
+#include "UCArray.h"
+#include "netorder.h"  /* [RPAP - Jan 97: Endian Ordering] */
+
+
+void SetCStr (UCArray &text, const char *cStr) {
+  text.erase(text.begin(), text.end());
+  
+  while (*cStr != '\0') {
+    text.push_back (*cStr);
+    cStr++;
+  }
+}
+
+char * GetCStr(UCArray text) {
+
+  char *cstr = new char[text.size()+1];
+  UCArray::const_iterator here = text.begin();
+  UCArray::const_iterator end = text.end();
+
+  int i = 0;
+  while (here != end) {
+    cstr[i] = (char)*here;
+    here++; i++;
+  }
+  cstr[i]='\0';
+  return cstr;
+}
+
+ostream &operator<<(ostream &s, const UCArray &a) {
+  UCArray::const_iterator here = a.begin();
+  UCArray::const_iterator end = a.end();
+  while (here != end) {
+    s << *here;
+    here++;
+  }
+
+  return s;
+}
+
+
+bool ReadVarLenUL (FILE *f, unsigned long &n) {
+  register unsigned long temp = 0;
+  register unsigned int bitPos = 0;
+  unsigned char b = 0;
+
+  do {
+    b = fgetc (f);
+    if (feof(f)) return false;
+    temp |= (b & 0x7f) << bitPos;
+    bitPos += 7;
+  } while (b >= 0x80 && bitPos < 32);
+
+  n = temp;
+  
+  return true;
+}
+
+bool WriteVarLenUL (FILE *f, unsigned long n) {
+  register unsigned long temp = n;
+  register unsigned char b = 0;
+  do {
+    b = static_cast<unsigned char> (temp & 0x7f);
+    if (temp >= 0x80) b |= 0x80;
+    fputc (b, f);
+    if (ferror (f) != 0) return false;
+  } while ((temp = temp >> 7) > 0);
+  
+  return true;
+}
+
+
+bool ReadUL (FILE *f, unsigned long &n) {
+  if (fread (&n, sizeof (unsigned long), 1, f) <= 0) return false;
+  NTOHUL (n);
+  return true;
+}
+
+
+bool WriteUL (FILE *f, unsigned long n) {
+  HTONUL (n);
+  return (fwrite (&n, sizeof (unsigned long), 1, f) > 0);
+}
+
+bool ReadF (FILE *f, float &n) {
+  if (fread (&n, sizeof (float), 1, f) <= 0) return false;
+  NTOHF(n);
+  return true;
+}
+
+bool WriteF (FILE *f, float n) {
+  HTONF(n);
+  return (fwrite (&n, sizeof (float), 1, f) > 0);
+}
+
+bool ReadD (FILE *f, double &n) {
+  if (fread (&n, sizeof (double), 1, f) <= 0) return false;
+  NTOHD(n);
+  return true;
+}
+
+bool WriteD (FILE *f, double n) {
+  HTOND(n);
+  return (fwrite (&n, sizeof (double), 1, f) > 0);
+}
+
+bool ReadUCArray (FILE *f, UCArray &a) {
+  // clear the array in preparation
+  a.erase (a.begin(), a.end());
+
+  // read in the array size
+  unsigned long arraySize = 0;
+  if (!ReadVarLenUL (f, arraySize)) return false;
+
+  // read in the array
+  unsigned char b = 0;
+  while (arraySize > 0) {
+    b = fgetc (f);
+    if (feof(f)) return false;
+    a.push_back (b);
+    
+    arraySize--;
+  }
+  
+  return true;
+}
+
+bool WriteUCArray (FILE *f, const UCArray &a) {
+  // write out the array size
+  if (!WriteVarLenUL (f, a.size())) return false;
+
+  UCArray::const_iterator here = a.begin();
+  UCArray::const_iterator end = a.end();
+  while (here != end) {
+    fputc (*here, f);
+    if (ferror (f) != 0) return false;
+    
+    here++;
+  }
+  
+  return true;
+}
+
+/*
+ * This array is designed for mapping upper and lower case letter
+ * together for a case independent comparison.  The mappings are
+ * based upon ascii character sequences.
+ */
+static unsigned char casecharmap[] = {
+	'\000', '\001', '\002', '\003', '\004', '\005', '\006', '\007',
+	'\010', '\011', '\012', '\013', '\014', '\015', '\016', '\017',
+	'\020', '\021', '\022', '\023', '\024', '\025', '\026', '\027',
+	'\030', '\031', '\032', '\033', '\034', '\035', '\036', '\037',
+	'\040', '\041', '\042', '\043', '\044', '\045', '\046', '\047',
+	'\050', '\051', '\052', '\053', '\054', '\055', '\056', '\057',
+	'\060', '\061', '\062', '\063', '\064', '\065', '\066', '\067',
+	'\070', '\071', '\072', '\073', '\074', '\075', '\076', '\077',
+	'\100', '\141', '\142', '\143', '\144', '\145', '\146', '\147',
+	'\150', '\151', '\152', '\153', '\154', '\155', '\156', '\157',
+	'\160', '\161', '\162', '\163', '\164', '\165', '\166', '\167',
+	'\170', '\171', '\172', '\133', '\134', '\135', '\136', '\137',
+	'\140', '\141', '\142', '\143', '\144', '\145', '\146', '\147',
+	'\150', '\151', '\152', '\153', '\154', '\155', '\156', '\157',
+	'\160', '\161', '\162', '\163', '\164', '\165', '\166', '\167',
+	'\170', '\171', '\172', '\173', '\174', '\175', '\176', '\177',
+	'\200', '\201', '\202', '\203', '\204', '\205', '\206', '\207',
+	'\210', '\211', '\212', '\213', '\214', '\215', '\216', '\217',
+	'\220', '\221', '\222', '\223', '\224', '\225', '\226', '\227',
+	'\230', '\231', '\232', '\233', '\234', '\235', '\236', '\237',
+	'\240', '\241', '\242', '\243', '\244', '\245', '\246', '\247',
+	'\250', '\251', '\252', '\253', '\254', '\255', '\256', '\257',
+	'\260', '\261', '\262', '\263', '\264', '\265', '\266', '\267',
+	'\270', '\271', '\272', '\273', '\274', '\275', '\276', '\277',
+	'\300', '\341', '\342', '\343', '\344', '\345', '\346', '\347',
+	'\350', '\351', '\352', '\353', '\354', '\355', '\356', '\357',
+	'\360', '\361', '\362', '\363', '\364', '\365', '\366', '\367',
+	'\370', '\371', '\372', '\333', '\334', '\335', '\336', '\337',
+	'\340', '\341', '\342', '\343', '\344', '\345', '\346', '\347',
+	'\350', '\351', '\352', '\353', '\354', '\355', '\356', '\357',
+	'\360', '\361', '\362', '\363', '\364', '\365', '\366', '\367',
+	'\370', '\371', '\372', '\373', '\374', '\375', '\376', '\377',
+};
+
+
+int DictCompare (const UCArray &a1, const UCArray &a2) {
+  unsigned int l1 = a1.size();
+  unsigned int l2 = a2.size();
+  unsigned int l = (l1 < l2) ? l1 : l2;
+  int pos = 0;
+  register int diff = 0;
+
+  UCArray::const_iterator a1Here = a1.begin();
+  UCArray::const_iterator a2Here = a2.begin();
+  
+  while (l--) {
+    if ((diff = casecharmap[*a1Here] - casecharmap[*a2Here]) != 0)
+      return diff;
+    if (pos == 0 && (diff = *a1Here - *a2Here) != 0)
+      pos = diff;
+
+    a1Here++;
+    a2Here++;
+  }
+
+  return ((l1 - l2) ? (l1 - l2) : (pos));
+}
+
+unsigned long PrefixLen (const UCArray &a1, const UCArray &a2) {
+  unsigned long l = (a1.size() < a2.size()) ? a1.size() : a2.size();
+  unsigned long i = 0;
+
+  UCArray::const_iterator a1Here = a1.begin();
+  UCArray::const_iterator a2Here = a2.begin();
+
+  while (i < l && *a1Here == *a2Here) {
+    i++; a1Here++; a2Here++;
+  }
+  
+  return i;
+}
+
+bool WritePreSufStr (FILE *f, const UCArray *prev, const UCArray &a) {
+  unsigned char preLen;
+  unsigned char sufLen;
+  
+  if (prev != NULL) preLen = PrefixLen (*prev, a);
+  else preLen = 0;
+  sufLen = a.size() - preLen;
+
+  // output the prefix length, suffix length, and the suffix
+  fputc (preLen, f);
+  if (ferror(f) != 0) return false;
+  fputc (sufLen, f);
+  if (ferror(f) != 0) return false;
+  return (fwrite ((char *)a.begin()+preLen, sizeof (char), sufLen, f) == sufLen);
+}
+
+// a also used for prev
+bool ReadPreSufStr (FILE *f, UCArray &a) {
+  unsigned char preLen = 0;
+  unsigned char sufLen = 0;
+
+  preLen = fgetc(f);
+  sufLen = fgetc(f);
+
+  if (a.size () > preLen) a.erase (a.begin()+preLen, a.end());
+  while (sufLen > 0) {
+    unsigned char c = fgetc (f);
+    a.push_back (c);
+    sufLen--;
+  }
+
+  return true;
+}
+
Index: /main/tags/2.25/gsdl/src/mgpp/text/UCArray.h
===================================================================
--- /main/tags/2.25/gsdl/src/mgpp/text/UCArray.h	(revision 21064)
+++ /main/tags/2.25/gsdl/src/mgpp/text/UCArray.h	(revision 21064)
@@ -0,0 +1,119 @@
+/**************************************************************************
+ *
+ * UCArray.h -- vector based string class
+ * Copyright (C) 1999  Rodger McNab
+ *
+ * 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.
+ *
+ * $Id$
+ *
+ **************************************************************************/
+
+#ifndef UCARRAY_H
+#define UCARRAY_H
+
+#if defined(GSDL_USE_OBJECTSPACE)
+#  include <ospace\std\vector>
+#  include <ospace\std\set>
+#elif defined(GSDL_USE_STL_H)
+#  include <vector.h>
+#  include <set.h>
+#else
+#  include <vector>
+#  include <set>
+#endif
+
+#if defined(GSDL_USE_OBJECTSPACE)
+#  include <ospace\std\iostream>
+#elif defined(GSDL_USE_IOS_H)
+#  include <iostream.h>
+#else
+#  include <iostream>
+#endif
+
+#include <stdio.h>
+
+
+typedef vector<unsigned char> UCArray;
+
+// functions to manipulate UCArrays
+void SetCStr (UCArray &text, const char *cStr);
+char * GetCStr(UCArray text);
+inline void UCArrayClear (UCArray &a) {
+  a.erase (a.begin(), a.end());
+}
+
+// stream operator to print UCArray
+ostream &operator<<(ostream &s, const UCArray &a);
+
+// used for reading and writing unsigned characters
+inline bool ReadUC (FILE *f, unsigned char &c) {
+  return (fread (&c, sizeof (unsigned char), 1, f) == 1);
+}
+inline bool WriteUC (FILE *f, unsigned char c) {
+  return (fwrite (&c, sizeof (unsigned char), 1, f) == 1);
+}
+
+// used for reading and writing variable length unsigned longs
+bool ReadVarLenUL (FILE *f, unsigned long &n);
+bool WriteVarLenUL (FILE *f, unsigned long n);
+
+// used for reading and writing unsigned longs
+bool ReadUL (FILE *f, unsigned long &n);
+bool WriteUL (FILE *f, unsigned long n);
+
+// used for reading and writing floats
+bool ReadF (FILE *f, float &n);
+bool WriteF (FILE *f, float n);
+
+// used for reading and writing doubles
+bool ReadD (FILE *f, double &n);
+bool WriteD (FILE *f, double n);
+
+// used for reading and writing arrays to files
+bool ReadUCArray (FILE *f, UCArray &a);
+bool WriteUCArray (FILE *f, const UCArray &a);
+
+
+// compares the two strings in dictionary order
+int DictCompare (const UCArray &a1, const UCArray &a2);
+
+struct LTUCArray {
+  bool operator()(const UCArray &a1, const UCArray &a2) const
+    { return (a1 < a2); }
+};
+
+struct DictLTUCArray {
+  bool operator() (const UCArray &a1, const UCArray &a2) const
+    { return (DictCompare (a1, a2) < 0); }
+};
+
+
+typedef set<UCArray, LTUCArray> UCArraySet;
+typedef vector<UCArray> UCArrayVector;
+
+unsigned long PrefixLen (const UCArray &a1, const UCArray &a2);
+
+// prev == NULL if no previous string
+bool WritePreSufStr (FILE *f, const UCArray *prev, const UCArray &a);
+bool ReadPreSufStr (FILE *f, UCArray &a); // a also used for prev
+
+
+#endif
+
+
+
+
+
Index: /main/tags/2.25/gsdl/src/mgpp/text/WIN32.MAK
===================================================================
--- /main/tags/2.25/gsdl/src/mgpp/text/WIN32.MAK	(revision 21064)
+++ /main/tags/2.25/gsdl/src/mgpp/text/WIN32.MAK	(revision 21064)
@@ -0,0 +1,240 @@
+#PACKAGE = mg
+#VERSION = 1.3
+
+#SHELL = /bin/sh
+#exec_prefix = ${prefix}
+#prefix = /image/httpd/mg-1.2
+#srcdir = .
+#subdir = src/text
+#top_srcdir = ../..
+#transform = s,x,x,
+
+CC = cl
+#CC = cl /Z7  this gives symbol and line number debugging (set /DEBUG on link)
+#CFLAGS = -g -O
+CPPFLAGS =
+DEFS = -DNZDL -DQUIET -DSHORT_SUFFIX -DPARADOCNUM -DHAVE_CONFIG_H -D__WIN32__ -D_LITTLE_ENDIAN
+#INSTALL = /usr/local/gnu/bin/install -c
+#INSTALL_DATA = ${INSTALL} -m 644
+#INSTALL_PROGRAM = ${INSTALL}
+LDFLAGS =
+LIBS = ..\..\lib\libmg.lib
+#TOUCH = echo timestamp >
+#AWK = gawk
+
+#bindir = $(exec_prefix)/bin
+#datadir = $(prefix)/share
+#libexecdir = $(exec_prefix)/libexec
+#localedir = $(datadir)/locale
+#mandir = $(prefix)/man/man1
+
+COMPILE = $(CC) -c $(DEFS) -I. -I..\.. -I..\..\lib
+LINK = $(CC) $(LDFLAGS)
+
+.SUFFIXES:
+.SUFFIXES: .c .obj .cpp
+.c.obj:
+	$(COMPILE) $<
+.cpp.obj:
+	$(COMPILE) $<
+
+o = .obj
+e = .exe
+
+#############################################################################
+#
+# Uncomment (and possibly edit) the following lines if you wish
+# to use the GNU readline library for the input in mgquery
+#
+#READLINE = -DGNU_READLINE -I/opt/gnu/include/readline -L/opt/gnu/lib
+#READLINE_LIBS = -lreadline -ltermcap
+#
+#
+#############################################################################
+
+
+SOURCES = \
+  FIvfLevelInfo.cpp        ivf.pass1.cpp            mg_invf_dump.cpp       \
+  FText.cpp                ivf.pass2.cpp            mg_passes.cpp          \
+  FileBuf.cpp              locallib.cpp             mg_perf_hash_build.cpp \
+  FragLevelConvert.cpp     mg.special.cpp           mg_stem_idx.cpp        \
+  IndexData.cpp            mg_compression_dict.cpp  mg_weights_build.cpp   \
+  TagInfo.cpp              mg_decompress_text.cpp   stemmer.cpp            \
+  TextEl.cpp               mg_errors.cpp            text.cpp               \
+  TextGet.cpp              mg_fast_comp_dict.cpp    text.pass1.cpp         \
+  UCArray.cpp              mg_files.cpp             text.pass2.cpp         \
+  comp_dict.cpp            mg_invf_dict.cpp         words.cpp              \
+  invf.cpp                 mg_invf_dict_dump.cpp    Weights.cpp            \
+  MGQuery.cpp              Terms.cpp                QueryTester.cpp        \
+  QueryLex.cpp             QueryParser.cpp          Queryer.cpp
+
+
+HEADERS = \
+  FIvfLevelInfo.h     TextEl.h            hash.h              stemmer.h  \
+  FText.h             TextGet.h           invf.h              text.h     \
+  FileBuf.h           UCArray.h           locallib.h          words.h    \
+  FragLevelConvert.h  WordData.h          mg.h                           \
+  IndexData.h         build.h             mg_errors.h                    \
+  TagInfo.h           comp_dict.h         mg_files.h          Weights.h  \
+  MGQuery.h           Terms.h             QueryLex.h          QueryParser.h
+
+#MISC          = Makefile.in 
+
+ALLFILES      = $(SOURCES) $(HEADERS) $(MISC) $(MAN)
+
+DISTFILES     = $(ALLFILES)
+
+EXEC          = mg_passes$e mg_decompress_text$e mg_perf_hash_build$e \
+                mg_invf_dump$e mg_weights_build$e mg_invf_dict$e mg_stem_idx$e \
+                mg_invf_dict_dump$e mg_compression_dict$e mg_fast_comp_dict$e \
+                QueryTester$e Queryer$e
+
+MAN           =  mg_weights_build.1  mg_invf_dict.1 \
+                 mg_passes.1 mg_perf_hash_build.1 \
+                 mg_compression_dict.1  mg_fast_comp_dict.1 \
+                 mg_stem_idx.1
+
+# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
+
+
+all:    $(EXEC) libtextin.lib
+
+
+# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
+
+HILITE_OBJS = mg_hilite_words$o stemmer$o locallib$o words$o
+
+mg_hilite_words$e: $(HILITE_OBJS)
+	$(LINK) $(HILITE_OBJS) $(LIBS)
+
+# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
+
+PASSES_OBJS = \
+	mg_passes$o text.pass1$o comp_dict$o \
+	text.pass2$o locallib$o \
+	ivf.pass1$o ivf.pass2$o mg.special$o mg_files$o \
+	words$o invf$o FileBuf$o TextEl$o UCArray$o TagInfo$o \
+        FText$o text$o FIvfLevelInfo$o
+
+mg_passes: $(PASSES_OBJS)
+	$(LINK) $(PASSES_OBJS) $(LIBS)
+
+# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
+
+QUERYER_OBJS = Queryer$o mg_files$o mg_errors$o locallib$o invf$o UCArray$o \
+               FIvfLevelInfo$o FragLevelConvert$o Terms$o MGQuery$o \
+               IndexData$o stemmer$o Weights$o TextGet$o text$o FText$o \
+               QueryParser$o QueryLex$o words$o
+
+Queryer: $(QUERYER_OBJS)
+	$(LINK) $(QUERYER_OBJS) $(LIBS)
+
+QUERY_TESTER_OBJS = QueryTester$o mg_files$o invf$o UCArray$o \
+                    FIvfLevelInfo$o FragLevelConvert$o Terms$o MGQuery$o \
+                    IndexData$o stemmer$o Weights$o
+
+QueryTester: $(QUERY_TESTER_OBJS)
+	$(LINK) $(QUERY_TESTER_OBJS) $(LIBS)
+
+WEIGHTS_BUILD_OBJS = mg_weights_build$o mg_files$o invf$o UCArray$o \
+                     FIvfLevelInfo$o FragLevelConvert$o
+
+mg_weights_build: $(WEIGHTS_BUILD_OBJS)
+	$(LINK) $(WEIGHTS_BUILD_OBJS) $(LIBS)
+
+COMP_DICT_OBJS = mg_compression_dict$o mg_files$o locallib$o
+
+mg_compression_dict: $(COMP_DICT_OBJS)
+	$(LINK) $(COMP_DICT_OBJS) $(LIBS)
+
+FAST_COMP_OBJS = mg_fast_comp_dict$o mg_files$o locallib$o
+
+mg_fast_comp_dict: $(FAST_COMP_OBJS)
+	$(LINK) $(FAST_COMP_OBJS) $(LIBS)
+
+INVF_DUMP_OBJS = mg_invf_dump$o locallib$o mg_files$o invf$o UCArray$o
+
+mg_invf_dump: $(INVF_DUMP_OBJS)
+	$(LINK) $(INVF_DUMP_OBJS) $(LIBS)
+
+INVF_DICT_OBJS = mg_invf_dict$o mg_files$o invf$o UCArray$o
+
+mg_invf_dict: $(INVF_DICT_OBJS)
+	$(LINK) $(INVF_DICT_OBJS) $(LIBS)
+
+INVF_DICT_DUMP_OBJS = mg_invf_dict_dump$o mg_files$o invf$o UCArray$o
+
+mg_invf_dict_dump: $(INVF_DICT_DUMP_OBJS)
+	$(LINK) $(INVF_DICT_DUMP_OBJS) $(LIBS)
+
+PERF_HASH_OBJS = mg_perf_hash_build$o mg_files$o invf$o UCArray$o
+
+mg_perf_hash_build: $(PERF_HASH_OBJS)
+	$(LINK) $(PERF_HASH_OBJS) $(LIBS)
+
+STEM_IDX_OBJS = mg_stem_idx$o mg_files$o stemmer$o \
+                invf$o UCArray$o
+
+mg_stem_idx: $(STEM_IDX_OBJS)
+	$(LINK) $(STEM_IDX_OBJS) $(LIBS)
+
+DECOMPRESS_TEXT_OBJS = \
+                mg_decompress_text$o mg_files$o mg_errors$o \
+                locallib$o text$o UCArray$o TextGet$o FText$o
+
+mg_decompress_text: $(DECOMPRESS_TEXT_OBJS)
+	$(LINK) $(DECOMPRESS_TEXT_OBJS) $(LIBS)
+
+# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
+
+install: execinstall maninstall
+uninstall: execuninstall manuninstall
+
+maninstall: $(MAN)
+	$(top_srcdir)/mkinstalldirs $(mandir); \
+	for f in $(MAN); do \
+	  $(INSTALL_DATA) $$f $(mandir)/$$f ;\
+	done
+
+manuninstall: $(MAN)
+	for f in $(MAN); do \
+	  rm -f $(mandir)/$$f ;\
+	done
+
+
+LIB_OBJS = Queryer$o mg_files$o mg_errors$o locallib$o invf$o UCArray$o \
+           FIvfLevelInfo$o FragLevelConvert$o Terms$o MGQuery$o \
+           IndexData$o stemmer$o Weights$o TextGet$o text$o FText$o \
+           QueryParser$o QueryLex$o words$o
+
+libtextin.lib: $(LIB_OBJS)
+	del libtextin.lib
+	lib /out:libtextin.lib $(LIB_OBJS)
+
+
+mostlyclean:
+	rm -f *$o _*.c _*.o *._c *._o core core.*
+ 
+clean: mostlyclean
+	rm -f $(EXEC)
+ 
+distclean: clean
+	rm -f ansi2knr
+	rm -f Makefile
+ 
+maintainer-clean: distclean
+	@echo "This command is intended only for maintainers to use;"
+	@echo "rebuilding the deleted files may require special tools."
+ 
+#dist: $(DISTFILES)
+#        for file in $(DISTFILES); do \
+#          ln $(srcdir)/$$file $(distdir) 2> /dev/null \
+#          || cp -p $(srcdir)/$$file $(distdir); \
+#        done
+ 
+#Makefile: Makefile.in ../../config.status
+#        cd ../.. && CONFIG_FILES=$(subdir)/$@ CONFIG_HEADERS= ./config.status
+ 
+# Tell versions [3.59,3.63) of GNU make not to export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+#.NOEXPORT:
Index: /main/tags/2.25/gsdl/src/mgpp/text/Weights.cpp
===================================================================
--- /main/tags/2.25/gsdl/src/mgpp/text/Weights.cpp	(revision 21064)
+++ /main/tags/2.25/gsdl/src/mgpp/text/Weights.cpp	(revision 21064)
@@ -0,0 +1,128 @@
+/**************************************************************************
+ *
+ * Weights.cpp -- Dealing with document weights
+ * Copyright (C) 1999  Rodger McNab
+ *
+ * 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.
+ *
+ * $Id$
+ *
+ **************************************************************************/
+
+#include "Weights.h"
+#include "sysfuncs.h"
+#include "UCArray.h"
+
+#define MAXBITS (sizeof(unsigned long) * 8)
+
+
+ApproxWeightsData::ApproxWeightsData () {
+  weightBuf = NULL;
+  table = NULL;
+  Free();
+}
+
+ApproxWeightsData::~ApproxWeightsData () {
+  Free ();
+}
+
+void ApproxWeightsData::Free () {
+  bits = 0;
+  mask = 0;
+  L = 0.0;
+  B = 0.0;
+  numLevelDocs = 0;
+  if (weightBuf != NULL) {
+    delete [] weightBuf;
+    weightBuf = NULL;
+  }
+  if (table != NULL) {
+    delete [] table;
+    table = NULL;
+  }
+}
+
+bool ApproxWeightsData::Read (FILE *approxWeightsFile, unsigned long diskPtr,
+			      unsigned long _numLevelDocs) {
+  Free ();
+  
+  // go to the appropriate place in the weights file
+  fseek (approxWeightsFile, diskPtr, SEEK_SET);
+
+  // read in approx weights parameters
+  ReadUC (approxWeightsFile, bits);
+  ReadD (approxWeightsFile, L);
+  ReadD (approxWeightsFile, B);
+
+  mask = (bits == 32) ? 0xffffffff : (1 << bits) - 1;
+  numLevelDocs = _numLevelDocs;
+
+  // allocate buffer for the weights
+  unsigned long arrSize = (bits*numLevelDocs+sizeof(unsigned long)-1) / 32;
+  weightBuf = new unsigned long[arrSize];
+
+  // read in the weights
+  unsigned long i;
+  for (i=0; i<arrSize; i++) {
+    ReadUL (approxWeightsFile, weightBuf[i]);
+  }
+
+  // create precomputed table of values if it will be small enough
+  // (if not small enough table == NULL
+  if (bits <= 12) {
+    unsigned long i, tableSize = (1 << bits);
+    table = new float[tableSize];
+    table[0] = L;
+    for (i = 1; i < tableSize; i++)
+      table[i] = table[i - 1] * B;
+  }
+
+  return true;
+}
+
+float ApproxWeightsData::GetLowerApproxDocWeight (unsigned long levelDocNum) {
+  // sanity check
+  if (bits == 0 || weightBuf == NULL) return 1.0;
+
+  register unsigned long c, pos;
+  register unsigned long *dw;
+
+  // get the compressed version of the weight
+  pos = levelDocNum * bits;
+  dw = &weightBuf[pos / MAXBITS];
+  pos &= (MAXBITS - 1);
+  c = *dw >> pos;
+  if (pos + bits > MAXBITS)
+    c |= *(dw + 1) << (MAXBITS - pos);
+  c &= mask;
+
+  // decompress the weight
+  if (table != NULL) return table[c];
+  return (L * pow (B, (double) c));
+}
+
+
+
+float GetExactDocWeight (FILE *exactWeightsFile, unsigned long diskPtr,
+			 unsigned long levelDocNum) {
+  // go to the appropriate place in the weights file
+  fseek (exactWeightsFile, diskPtr+sizeof(float)*levelDocNum, SEEK_SET);
+
+  // read in the exact weight
+  float weight;
+  ReadF (exactWeightsFile, weight);
+  
+  return weight;
+}
Index: /main/tags/2.25/gsdl/src/mgpp/text/Weights.h
===================================================================
--- /main/tags/2.25/gsdl/src/mgpp/text/Weights.h	(revision 21064)
+++ /main/tags/2.25/gsdl/src/mgpp/text/Weights.h	(revision 21064)
@@ -0,0 +1,58 @@
+/**************************************************************************
+ *
+ * Weights.h -- Dealing with document weights
+ * Copyright (C) 1999  Rodger McNab
+ *
+ * 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.
+ *
+ * $Id$
+ *
+ **************************************************************************/
+
+#ifndef WEIGHTS_H
+#define WEIGHTS_H
+
+#include <stdio.h>
+
+
+class ApproxWeightsData {
+public:
+  unsigned char bits;
+  unsigned long mask;
+  double L;
+  double B;
+  unsigned long numLevelDocs;
+  unsigned long *weightBuf;
+  float *table;   // precomputed translation table
+  
+  ApproxWeightsData ();
+  ~ApproxWeightsData ();
+
+  void Free (); // frees any allocated memory
+  
+  bool Read (FILE *approxWeightsFile, unsigned long diskPtr,
+	     unsigned long _numLevelDocs);
+
+  float GetLowerApproxDocWeight (unsigned long levelDocNum);
+};
+
+
+// diskPtr points to the start of the exact document weights
+// for this level
+float GetExactDocWeight (FILE *exactWeightsFile, unsigned long diskPtr,
+			 unsigned long levelDocNum);
+
+
+#endif
Index: /main/tags/2.25/gsdl/src/mgpp/text/WordData.h
===================================================================
--- /main/tags/2.25/gsdl/src/mgpp/text/WordData.h	(revision 21064)
+++ /main/tags/2.25/gsdl/src/mgpp/text/WordData.h	(revision 21064)
@@ -0,0 +1,49 @@
+/**************************************************************************
+ *
+ * WordData.h -- 
+ * Copyright (C) 1999  NZDL
+ *
+ * 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.
+ *
+ * $Id$
+ *
+ **************************************************************************/
+
+class WordData
+{
+
+ public:
+  unsigned long docCount;
+  unsigned long wordCount;
+
+  inline void read(FILE *f)
+    {
+      fread((char *) &docCount, sizeof(docCount), 1, f);
+      fread((char *) &wordCount, sizeof(wordCount), 1, f);
+
+      NTOHUL(docCount);
+      NTOHUL(wordCount);
+    }
+
+  inline unsigned long documents()
+    {
+      return docCount;
+    }
+
+  inline int words()
+    {
+      return wordCount;
+    }
+};
Index: /main/tags/2.25/gsdl/src/mgpp/text/build.h
===================================================================
--- /main/tags/2.25/gsdl/src/mgpp/text/build.h	(revision 21064)
+++ /main/tags/2.25/gsdl/src/mgpp/text/build.h	(revision 21064)
@@ -0,0 +1,88 @@
+/**************************************************************************
+ *
+ * build.h -- Global information for the passes of mg_passes
+ * Copyright (C) 1994  Neil Sharman, Alistair Moffat and Lachlan Andrew
+ * Copyright (C) 1999  Rodger McNab
+ *
+ * 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.
+ *
+ * $Id$
+ *
+ **************************************************************************/
+
+
+#ifndef H_BUILD
+#define H_BUILD
+
+#include "longlong.h"
+
+#include "TextEl.h"
+#include "TagInfo.h"
+
+
+int init_special (const TagInfo &tagInfo, char *file_name);
+int init_text_1 (const TagInfo &tagInfo, char *file_name);
+int init_text_2 (const TagInfo &tagInfo, char *file_name);
+int init_ivf_1 (const TagInfo &tagInfo, char *file_name);
+int init_ivf_2 (const TagInfo &tagInfo, char *file_name);
+/*
+ * file_name  IN      The name of the dictionary file
+ * 
+ * returns      COMPALLOK for all ok,
+ *              COMPERROR for any error.  e.g. cannot read file
+ */
+
+
+
+
+
+int process_special (const TagInfo &tagInfo, const TextElArray &doc);
+int process_text_1 (const TagInfo &tagInfo, const TextElArray &doc);
+int process_text_2 (const TagInfo &tagInfo, const TextElArray &doc);
+int process_ivf_1 (const TagInfo &tagInfo, const TextElArray &doc);
+int process_ivf_2 (const TagInfo &tagInfo, const TextElArray &doc);
+/*
+ * returns      COMPALLOK for all ok,
+ *              COMPERROR for any error.  e.g. cannot read file
+ *
+ * The calling routine is responsible for ensuring that s_out is long 
+ * enough.
+ */
+
+
+
+
+
+int done_special (const TagInfo &tagInfo, char *filename);
+int done_text_1 (const TagInfo &tagInfo, char *filename);
+int done_text_2 (const TagInfo &tagInfo, char *filename);
+int done_ivf_1 (const TagInfo &tagInfo, char *filename);
+int done_ivf_2 (const TagInfo &tagInfo, char *filename);
+/*
+ * returns    COMPALLOK for all ok,
+ *              COMPERROR for any error.  e.g. cannot write file
+ */
+
+
+
+
+extern unsigned long invf_buffer_size;
+/*
+ * The amount of memory to allocate to the invertion buffer.
+ */
+
+
+
+#endif
Index: /main/tags/2.25/gsdl/src/mgpp/text/comp_dict.cpp
===================================================================
--- /main/tags/2.25/gsdl/src/mgpp/text/comp_dict.cpp	(revision 21064)
+++ /main/tags/2.25/gsdl/src/mgpp/text/comp_dict.cpp	(revision 21064)
@@ -0,0 +1,255 @@
+/**************************************************************************
+ *
+ * comp_dict.cpp -- Functions for loading the compression dictionary
+ * Copyright (C) 1994  Neil Sharman
+ *
+ * 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.
+ *
+ * $Id$
+ *
+ **************************************************************************/
+
+#include "sysfuncs.h"
+
+#include "huffman.h"
+#include "local_strings.h"
+#include "memlib.h"
+#include "messages.h"
+
+#include "mg.h"
+#include "hash.h"
+#include "text.h"
+#include "comp_dict.h"
+#include "locallib.h"
+#include "mg_files.h"
+
+/*
+   $Log$
+   Revision 1.1  2000/01/14 02:26:04  sjboddie
+   Rodgers new C++ mg
+
+   Revision 1.1  1999/10/11 02:57:10  cs025
+   Base install of MG-PP
+
+   Revision 1.1  1999/08/10 21:17:48  sjboddie
+   renamed mg-1.3d directory mg
+
+   Revision 1.1  1998/11/17 09:34:34  rjmcnab
+   *** empty log message ***
+
+   * Revision 1.3  1994/10/20  03:56:41  tes
+   * I have rewritten the boolean query optimiser and abstracted out the
+   * components of the boolean query.
+   *
+   * Revision 1.2  1994/09/20  04:41:24  tes
+   * For version 1.1
+   *
+ */
+
+
+compression_dict_header cdh;
+compressed_text_header cth;
+comp_frags_header cfh[2];
+
+dict_hash_table *ht[2];
+
+huff_data char_huff[2];
+huff_data lens_huff[2];
+u_long *char_codes[2], *lens_codes[2];
+u_long Words_disk = 0;
+u_long Chars_disk = 0;
+
+
+static dict_hash_table *
+ReadInWords (FILE * dict, comp_frags_header * cfh,
+	     int esc)
+{
+  int i;
+  u_char *allwords, *prev = NULL;
+  dict_hash_table *ht;
+  u_char **words;
+  u_long ht_size;
+
+  ht_size = prime (cfh->hd.num_codes * HASH_RATIO);
+  if (!(ht = (dict_hash_table *) Xmalloc (sizeof (dict_hash_table) +
+		                            (ht_size - 1) * sizeof (ht->table[0]))))
+    {
+      Message ("no memory for hash_table\n");
+      return NULL;
+    }
+
+  ht->size = ht_size;
+  ht->hd = &cfh->hd;
+
+  if (!(ht->codes = Generate_Huffman_Codes (&cfh->hd, NULL)))
+    {
+      Message ("no memory for huffman codes\n");
+      return NULL;
+    }
+
+  if (!(ht->words = (u_char **) Xmalloc (sizeof (u_char *) * cfh->hd.num_codes)))
+    {
+      Message ("no memory for word pointers\n");
+      return NULL;
+    }
+  words = ht->words;
+
+  bzero ((char *) ht->table, ht_size * sizeof (ht->table[0]));
+
+  if (!(allwords = (u_char *) Xmalloc (sizeof (u_char) * cfh->uncompressed_size)))
+    {
+      Message ("no memory for words\n");
+      return NULL;
+    }
+
+  for (i = 0; i < cfh->hd.num_codes; i++, words++)
+    {
+      register int val, copy;
+      val = fgetc (dict);
+      copy = (val >> 4) & 0xf;
+      val &= 0xf;
+
+      *words = allwords;
+
+      memcpy (allwords + 1, prev + 1, copy);
+      fread (allwords + copy + 1, sizeof (u_char), val, dict);
+      *allwords = val + copy;
+
+      Words_disk += val + 1;
+
+      /* insert into the hash table */
+      if (i < cfh->hd.num_codes - esc)
+	{
+	  register u_char **wptr;
+	  register unsigned long tsize = ht->size;
+	  register unsigned long hashval, step;
+
+	  HASH (hashval, step, allwords, tsize);
+
+	  wptr = ht->table[hashval];
+	  for (; wptr;)
+	    {
+	      hashval += step;
+	      if (hashval >= tsize)
+		hashval -= tsize;
+	      wptr = ht->table[hashval];
+	    }
+	  ht->table[hashval] = words;
+	}
+      prev = allwords;
+      allwords += *allwords + 1;
+    }
+  return ht;
+}
+
+inline int LoadWords(FILE *dict, int which)
+{
+  if (Read_cfh (dict, &cfh[which], NULL, &Words_disk) == -1)
+    return 1;
+  
+  if (!(ht[which] = ReadInWords (dict, &cfh[which], 0)))
+    return 1;
+
+  return 0;
+}
+
+inline int LoadHuffmanCodes(FILE *dict, int which)
+{
+  if (Read_Huffman_Data (dict, &char_huff[which], NULL,
+			 &Chars_disk) == -1)
+    return 1;
+  if (!(char_codes[which] =
+	Generate_Huffman_Codes (&char_huff[which], NULL)))
+    return 2;
+  if (Read_Huffman_Data (dict, &lens_huff[which], NULL,
+			 &Chars_disk) == -1)
+    return 3;
+  if (!(lens_codes[which] =
+	Generate_Huffman_Codes (&lens_huff[which], NULL)))
+    return 4;
+
+  return 0;
+}
+
+int 
+LoadCompressionDictionary (char *dict_file_name)
+{
+  FILE *dict;
+  int which;
+  if (!(dict = open_named_file (dict_file_name, "rb", MAGIC_DICT, MG_MESSAGE)))  /* [RPAP - Feb 97: WIN32 Port] */
+    return COMPERROR;
+
+  Words_disk = sizeof (u_long);
+
+  if (Read_cdh (dict, &cdh, NULL, &Words_disk) == -1)
+    goto error;
+
+  for (which = 0; which < 2; which++)
+    switch (cdh.dict_type)
+      {
+      case MG_COMPLETE_DICTIONARY:
+	{
+	  if (LoadWords(dict, which) != 0)
+	    goto error;
+	}
+	break;
+      case MG_PARTIAL_DICTIONARY:
+	{
+	  if (cdh.num_words[which])
+	    {
+	      if (LoadWords(dict, which) != 0)
+		goto error;
+	    }
+	  else
+	    ht[which] = NULL;
+	  if (LoadHuffmanCodes(dict, which) != 0)
+	    goto error;
+	}
+	break;
+      case MG_SEED_DICTIONARY:
+	{
+	  if (cdh.num_words[which])
+	    {
+	      if (LoadWords(dict, which) != 0)
+		goto error;
+	    }
+	  else
+	    ht[which] = NULL;
+	  switch (cdh.novel_method)
+	    {
+	    case MG_NOVEL_HUFFMAN_CHARS:
+	      if (LoadHuffmanCodes(dict, which) != 0)
+		goto error;
+	      break;
+	    case MG_NOVEL_DELTA:
+	      break;
+	    case MG_NOVEL_HYBRID:
+	      break;
+	    default:
+	      FatalError (1, "Bad novel method");
+	    }
+	}
+	break;
+      default:
+	FatalError (1, "Bad dictionary kind\n");
+      }
+
+  return (COMPALLOK);
+
+
+error:
+  fclose (dict);
+  return (COMPERROR);
+}
Index: /main/tags/2.25/gsdl/src/mgpp/text/comp_dict.h
===================================================================
--- /main/tags/2.25/gsdl/src/mgpp/text/comp_dict.h	(revision 21064)
+++ /main/tags/2.25/gsdl/src/mgpp/text/comp_dict.h	(revision 21064)
@@ -0,0 +1,59 @@
+/**************************************************************************
+ *
+ * comp_dict.h -- Functions for loading the compression dictionary
+ * Copyright (C) 1994  Neil Sharman
+ *
+ * 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.
+ *
+ * $Id$
+ *
+ **************************************************************************/
+
+
+
+
+#define HASH_RATIO 2
+
+
+
+
+typedef struct dict_hash_table
+  {
+    u_long size;
+    huff_data *hd;
+    u_long *codes;
+    u_char **words;
+    u_char **table[1];
+  }
+dict_hash_table;
+
+
+
+
+extern compression_dict_header cdh;
+extern compressed_text_header cth;
+extern comp_frags_header cfh[2];
+
+extern dict_hash_table *ht[2];
+
+extern huff_data char_huff[2];
+extern huff_data lens_huff[2];
+extern u_long *char_codes[2], *lens_codes[2];
+extern u_long Words_disk;
+extern u_long Chars_disk;
+
+
+
+int LoadCompressionDictionary (char *dict_file_name);
Index: /main/tags/2.25/gsdl/src/mgpp/text/hash.h
===================================================================
--- /main/tags/2.25/gsdl/src/mgpp/text/hash.h	(revision 21064)
+++ /main/tags/2.25/gsdl/src/mgpp/text/hash.h	(revision 21064)
@@ -0,0 +1,44 @@
+/**************************************************************************
+ *
+ * hash.h -- Hash function
+ * Copyright (C) 1994  Neil Sharman
+ *
+ * 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.
+ *
+ * $Id$
+ *
+ **************************************************************************/
+
+
+#ifndef H_HASH
+#define H_HASH
+
+
+
+#define HASH(h, step, wd, tablesize)			\
+	do {						\
+		register u_char *p=wd;			\
+		register long len = *p++;		\
+		register unsigned long hval;		\
+		if (len>25) len = 25;			\
+		for (hval=0; len; len--)		\
+		  hval = (hval << 5) - hval + *p++;	\
+		step = hval % (tablesize - 2) + 1;	\
+		h = hval % tablesize;			\
+	} while (0)
+
+
+
+#endif
Index: /main/tags/2.25/gsdl/src/mgpp/text/invf.cpp
===================================================================
--- /main/tags/2.25/gsdl/src/mgpp/text/invf.cpp	(revision 21064)
+++ /main/tags/2.25/gsdl/src/mgpp/text/invf.cpp	(revision 21064)
@@ -0,0 +1,842 @@
+/**************************************************************************
+ *
+ * invf.cpp -- Data structures for inverted files
+ * Copyright (C) 1999  Rodger McNab
+ *
+ * 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.
+ *
+ * $Id$
+ *
+ **************************************************************************/
+
+#include "invf.h"
+#include "UCArray.h"
+
+
+invf_dict_header::invf_dict_header () {
+  Clear();
+}
+
+invf_dict_header::~invf_dict_header () {
+}
+
+void invf_dict_header::Clear() {
+  lookback = 0;
+  word_dict_start = 0;
+  word_dict_size = 0;
+  tag_dict_start = 0;
+  tag_dict_size = 0;
+  num_docs = 0;
+  num_frags = 0;
+  num_words = 0;
+  total_bytes = 0;
+  index_string_bytes = 0;
+  num_levels = 0;
+}
+
+bool invf_dict_header::Read (FILE *f) {
+  return (ReadUL (f, lookback) &&
+	  ReadUL (f, word_dict_start) &&
+	  ReadUL (f, word_dict_size) &&
+	  ReadUL (f, tag_dict_start) &&
+	  ReadUL (f, tag_dict_size) &&
+	  ReadUL (f, num_docs) &&
+	  ReadUL (f, num_frags) &&
+	  ReadUL (f, num_words) &&
+	  ReadUL (f, total_bytes) &&
+	  ReadUL (f, index_string_bytes) &&
+	  ReadUL (f, num_levels));
+}
+
+bool invf_dict_header::Write (FILE *f) const {
+  return (WriteUL (f, lookback) &&
+	  WriteUL (f, word_dict_start) &&
+	  WriteUL (f, word_dict_size) &&
+	  WriteUL (f, tag_dict_start) &&
+	  WriteUL (f, tag_dict_size) &&
+	  WriteUL (f, num_docs) &&
+	  WriteUL (f, num_frags) &&
+	  WriteUL (f, num_words) &&
+	  WriteUL (f, total_bytes) &&
+	  WriteUL (f, index_string_bytes) &&
+	  WriteUL (f, num_levels));
+}
+
+
+
+void dict_el::Clear () {
+  el.erase (el.begin(), el.end());
+  frag_occur = 0;
+  freq = 0;
+}
+
+bool dict_el::Read (FILE *f) {
+  return (ReadPreSufStr (f, el) &&
+	  ReadUL (f, frag_occur) &&
+	  ReadUL (f, freq));
+}
+
+bool dict_el::Write (FILE *f, const UCArray *lastEl) const {
+  return (WritePreSufStr (f, lastEl, el) &&
+	  WriteUL (f, frag_occur) &&
+	  WriteUL (f, freq));
+}
+
+
+void word_dict_el::Clear () {
+  dict_el::Clear();
+  if (levelFreqs != NULL) delete [] levelFreqs;
+  levelFreqs = NULL;
+}
+
+word_dict_el::~word_dict_el () {
+  if (levelFreqs != NULL) delete [] levelFreqs;
+}
+
+void word_dict_el::SetNumLevels (unsigned long numLevels) {
+  if (levelFreqs != NULL) delete [] levelFreqs;
+  levelFreqs = new unsigned long [numLevels];
+}
+  
+bool word_dict_el::Read (FILE *f, unsigned long numLevels) {
+  if (!dict_el::Read (f)) return false;
+
+  if (levelFreqs == NULL) return false;
+  
+  unsigned long i;
+  for (i=0; i<numLevels; i++) {
+    if (!ReadUL (f, levelFreqs[i])) return false;
+  }
+
+  return true;
+}
+
+bool word_dict_el::Write (FILE *f, const UCArray *lastEl,
+			  unsigned long numLevels) const {
+  if (!dict_el::Write (f, lastEl)) return false;
+
+  if (levelFreqs == NULL) return false;
+
+  unsigned long i;
+  for (i=0; i<numLevels; i++) {
+    if (!WriteUL (f, levelFreqs[i])) return false;
+  }
+
+  return true;
+}
+
+
+
+block_dict_header::block_dict_header () {
+  Clear();
+}
+
+void block_dict_header::Clear () {
+  invf_dict_header::Clear();
+
+  entries_per_wblk = 0;
+  num_wblks = 0;
+  max_wblk_size = 0;
+  wblk_start = 0;
+  wblk_idx_start = 0;
+  
+  entries_per_tblk = 0;
+  num_tblks = 0;
+  max_tblk_size = 0;
+  tblk_start = 0;
+  tblk_idx_start = 0;
+}
+
+bool block_dict_header::Read (FILE *f) {
+  return (invf_dict_header::Read (f) &&
+
+	  ReadUL (f, entries_per_wblk) &&
+	  ReadUL (f, num_wblks) &&
+	  ReadUL (f, max_wblk_size) &&
+	  ReadUL (f, wblk_start) &&
+	  ReadUL (f, wblk_idx_start) &&
+  
+	  ReadUL (f, entries_per_tblk) &&
+	  ReadUL (f, num_tblks) &&
+	  ReadUL (f, max_tblk_size) &&
+	  ReadUL (f, tblk_start) &&
+	  ReadUL (f, tblk_idx_start));
+}
+
+bool block_dict_header::Write (FILE *f) const {
+  return (invf_dict_header::Write (f) &&
+
+	  WriteUL (f, entries_per_wblk) &&
+	  WriteUL (f, num_wblks) &&
+	  WriteUL (f, max_wblk_size) &&
+	  WriteUL (f, wblk_start) &&
+	  WriteUL (f, wblk_idx_start) &&
+  
+	  WriteUL (f, entries_per_tblk) &&
+	  WriteUL (f, num_tblks) &&
+	  WriteUL (f, max_tblk_size) &&
+	  WriteUL (f, tblk_start) &&
+	  WriteUL (f, tblk_idx_start));
+}
+
+
+
+
+
+void block_dict_el::Clear () {
+  el.erase (el.begin(), el.end());
+  frag_occur = 0;
+  freq = 0;
+  invf_ptr = 0;
+}
+
+bool block_dict_el::Read (FILE *f) {
+  return (ReadPreSufStr (f, el) &&
+	  ReadUL (f, frag_occur) &&
+	  ReadUL (f, freq) &&
+	  ReadUL (f, invf_ptr));
+}
+
+bool block_dict_el::Write (FILE *f, const UCArray *lastEl) const {
+  return (WritePreSufStr (f, lastEl, el) &&
+	  WriteUL (f, frag_occur) &&
+	  WriteUL (f, freq) &&
+	  WriteUL (f, invf_ptr));
+}
+
+
+
+
+
+void word_block_dict_el::Clear () {
+  block_dict_el::Clear();
+  if (levelFreqs != NULL) delete [] levelFreqs;
+  levelFreqs = NULL;
+}
+
+word_block_dict_el::~word_block_dict_el () {
+  if (levelFreqs != NULL) delete [] levelFreqs;
+}
+
+void word_block_dict_el::SetNumLevels (unsigned long numLevels) {
+  if (levelFreqs != NULL) delete [] levelFreqs;
+  levelFreqs = new unsigned long [numLevels];
+}
+
+bool word_block_dict_el::Read (FILE *f, unsigned long numLevels) {
+  if (!block_dict_el::Read (f)) return false;
+  
+  if (levelFreqs == NULL) return false;
+  
+  unsigned long i;
+  for (i=0; i<numLevels; i++) {
+    if (!ReadUL (f, levelFreqs[i])) return false;
+  }
+
+  return true;
+}
+
+bool word_block_dict_el::Write (FILE *f, const UCArray *lastEl,
+				unsigned long numLevels) const {
+  if (!block_dict_el::Write (f, lastEl)) return false;
+  
+  if (levelFreqs == NULL) return false;
+  
+  unsigned long i;
+  for (i=0; i<numLevels; i++) {
+    if (!WriteUL (f, levelFreqs[i])) return false;
+  }
+  
+  return true;
+}
+
+
+
+
+block_idx_info::block_idx_info () {
+  Clear ();
+}
+
+void block_idx_info::Clear () {
+  el.erase (el.begin(), el.end());
+  block_ptr = 0;
+}
+
+bool block_idx_info::Read (FILE *f) {
+  return (ReadUCArray (f, el) &&
+	  ReadUL (f, block_ptr));
+}
+
+bool block_idx_info::Write (FILE *f) const {
+  return (WriteUCArray (f, el) &&
+	  WriteUL (f, block_ptr));
+}
+
+
+bool ReadBlockIdx (FILE *f, block_idx &blockIdx) {
+  blockIdx.erase (blockIdx.begin(), blockIdx.end());
+  
+  // read in the array size
+  unsigned long arraySize = 0;
+  if (!ReadVarLenUL (f, arraySize)) return false;
+  
+  // read in the array
+  block_idx_info bi;
+  while (arraySize > 0) {
+    if (!bi.Read (f)) return false;
+    blockIdx.push_back (bi);
+    
+    arraySize--;
+  }
+  
+  return true;
+}
+
+bool WriteBlockIdx (FILE *f, const block_idx &blockIdx) {
+  // write out the array size
+  if (!WriteVarLenUL (f, blockIdx.size())) return false;
+
+  block_idx::const_iterator here = blockIdx.begin();
+  block_idx::const_iterator end = blockIdx.end();
+  while (here != end) {
+    if (!(*here).Write (f)) return false;
+    here++;
+  }
+
+  return true;
+}
+
+
+
+
+stem_idx_header::stem_idx_header () {
+  Clear ();
+}
+
+void stem_idx_header::Clear () {
+  lookback = 0;
+  dict_size = 0;
+
+  entries_per_block = 0;
+  num_blocks = 0;
+  max_block_size = 0;
+  blocks_start = 0;
+  block_idx_start = 0;
+  
+  stemmer_num = 0;
+  stem_method = 0;
+}
+
+bool stem_idx_header::Read (FILE *f) {
+  return (ReadUL (f, lookback) &&
+	  ReadUL (f, dict_size) &&
+	  
+	  ReadUL (f, entries_per_block) &&
+	  ReadUL (f, num_blocks) &&
+	  ReadUL (f, max_block_size) &&
+	  ReadUL (f, blocks_start) &&
+	  ReadUL (f, block_idx_start) &&
+	  
+	  ReadUL (f, stemmer_num) &&
+	  ReadUL (f, stem_method));
+}
+
+bool stem_idx_header::Write (FILE *f) const {
+  return (WriteUL (f, lookback) &&
+	  WriteUL (f, dict_size) &&
+	  
+	  WriteUL (f, entries_per_block) &&
+	  WriteUL (f, num_blocks) &&
+	  WriteUL (f, max_block_size) &&
+	  WriteUL (f, blocks_start) &&
+	  WriteUL (f, block_idx_start) &&
+	  
+	  WriteUL (f, stemmer_num) &&
+	  WriteUL (f, stem_method));
+}
+
+
+
+stem_block_dict_el::stem_block_dict_el () {
+  Clear ();
+}
+
+void stem_block_dict_el::Clear () {
+  el.erase (el.begin(), el.end());
+  equivWords.erase (equivWords.begin(), equivWords.end());
+}
+
+bool stem_block_dict_el::Read (FILE *f) {
+  equivWords.erase (equivWords.begin(), equivWords.end());
+  
+  if (!ReadPreSufStr (f, el)) return false;
+  
+  // read in the array size
+  unsigned long arraySize = 0;
+  if (!ReadVarLenUL (f, arraySize)) return false;
+  
+  // read in the array
+  unsigned long wordNum;
+  while (arraySize > 0) {
+    if (!ReadUL (f, wordNum)) return false;
+    equivWords.push_back (wordNum);
+    
+    arraySize--;
+  }
+  
+  return true;
+}
+
+bool stem_block_dict_el::Write (FILE *f, const UCArray *lastEl) const {
+  if (!WritePreSufStr (f, lastEl, el)) return false;
+
+  // write out the array size
+  if (!WriteVarLenUL (f, equivWords.size())) return false;
+
+  vector<unsigned long>::const_iterator here = equivWords.begin();
+  vector<unsigned long>::const_iterator end = equivWords.end();
+  while (here != end) {
+    if (!WriteUL (f, (*here))) return false;
+    here++;
+  }
+
+  return true;
+}
+
+
+
+
+invf_file_header::invf_file_header () {
+  Clear ();
+}
+
+void invf_file_header::Clear () {
+  no_of_words = 0;
+  no_of_tags = 0;
+  skip_mode = SKIP_MODE_NO_SKIPS;
+  word_level_index = 0;
+  
+  int i;
+  for (i=0; i<16; i++) params[i] = 0;
+}
+  
+bool invf_file_header::Read (FILE *f) {
+  if (!ReadUL (f, no_of_words) ||
+      !ReadUL (f, no_of_tags) ||
+      !ReadUL (f, skip_mode) ||
+      !ReadUL (f, word_level_index)) return false;
+
+  int i;
+  for (i=0; i<16; i++) {
+    if (!ReadUL (f, params[i])) return false;
+  }
+
+  return true;
+}
+
+bool invf_file_header::Write (FILE *f) const {
+  if (!WriteUL (f, no_of_words) ||
+      !WriteUL (f, no_of_tags) ||
+      !WriteUL (f, skip_mode) ||
+      !WriteUL (f, word_level_index)) return false;
+
+  int i;
+  for (i=0; i<16; i++) {
+    if (!WriteUL (f, params[i])) return false;
+  }
+
+  return true;
+}
+
+
+
+
+
+bool SearchElNum (const block_idx &bIdx,
+		  unsigned long entriesPerBlock,
+		  unsigned long elNum,
+		  unsigned long &blockIdxNum,
+		  unsigned long &blockStartElNum) {
+  blockIdxNum = 0;
+  blockStartElNum = 0;
+
+  // make sure the element number isn't out of range
+  if (elNum > bIdx.size()*entriesPerBlock) return false;
+
+  blockIdxNum = elNum / entriesPerBlock;
+  blockStartElNum = blockIdxNum * entriesPerBlock;
+  
+  return true;
+}
+
+bool SearchEl (const block_idx &bIdx,
+	       unsigned long entriesPerBlock,
+	       const UCArray &el,
+	       unsigned long &blockIdxNum,
+	       unsigned long &blockStartElNum) {
+  blockIdxNum = 0;
+  blockStartElNum = 0;
+
+  unsigned long begin = 0;
+  unsigned long bIdxEnd = bIdx.size();
+  unsigned long end = bIdxEnd;
+  unsigned long mid;
+  while (begin < end) {
+    mid = (begin+end)/2;
+    if (DictCompare (el, bIdx[mid].el) < 0) {
+      end = mid;
+    } else if (mid+1 < bIdxEnd &&
+	       DictCompare (el, bIdx[mid+1].el) >= 0) {
+      begin = mid+1;
+    } else {
+      blockIdxNum = mid;
+      blockStartElNum = blockIdxNum * entriesPerBlock;
+      return true;
+    }
+  }
+  
+  return false;
+}
+
+
+
+// use the block dictionary functions for tag entries, and word block dict
+// functions for word entries.
+
+
+bool SearchBlockDictElNum (FILE *dictFile,
+			   const block_idx &bIdx,
+			   unsigned long entriesPerBlock,
+			   unsigned long dictSize,
+			   unsigned long elNum,
+			   block_dict_el &dictEl) {
+  UCArrayClear (dictEl.el);
+  if (elNum >= dictSize) return false;
+
+  // find the block that contains the element
+  unsigned long blockIdxNum, curElNum;
+  if (!SearchElNum (bIdx, entriesPerBlock, elNum,
+		    blockIdxNum, curElNum))
+    return false;
+
+  // look for the block
+  fseek (dictFile, bIdx[blockIdxNum].block_ptr, SEEK_SET);
+  do {
+    dictEl.Read (dictFile);
+  } while (curElNum++ < elNum);
+
+  return true;
+}
+
+bool SearchBlockDictEl (FILE *dictFile,
+			const block_idx &bIdx,
+			unsigned long entriesPerBlock,
+			unsigned long dictSize,
+			const UCArray &el,
+			block_dict_el &dictEl,
+			unsigned long &elNum) {
+  UCArrayClear (dictEl.el);
+
+  // find the block that contains the element
+  unsigned long blockIdxNum;
+  if (!SearchEl (bIdx, entriesPerBlock, el,
+		 blockIdxNum, elNum))
+    return false;
+
+  unsigned long blockEndElNum = elNum + entriesPerBlock;
+  if (blockEndElNum > dictSize) blockEndElNum = dictSize;
+
+  // look for the block
+  fseek (dictFile, bIdx[blockIdxNum].block_ptr, SEEK_SET);
+  while (elNum < blockEndElNum) {
+    dictEl.Read (dictFile);
+    int res = DictCompare (dictEl.el, el);
+    if (res == 0) return true; // found it
+    else if (res > 0) break; // not here
+    
+    elNum++;
+  }
+
+  return false;
+}
+
+
+
+
+bool SearchWordBlockDictElNum (FILE *dictFile,
+			       const block_idx &bIdx,
+			       unsigned long entriesPerBlock,
+			       unsigned long dictSize,
+			       unsigned long numLevels,
+			       unsigned long elNum,
+			       word_block_dict_el &dictEl) {
+  UCArrayClear (dictEl.el);
+  if (elNum >= dictSize) return false;
+
+  // find the block that contains the element
+  unsigned long blockIdxNum, curElNum;
+  if (!SearchElNum (bIdx, entriesPerBlock, elNum,
+		    blockIdxNum, curElNum))
+    return false;
+
+  // look for the block
+  fseek (dictFile, bIdx[blockIdxNum].block_ptr, SEEK_SET);
+  do {
+    dictEl.Read (dictFile, numLevels);
+  } while (curElNum++ < elNum);
+
+  return true;
+}
+
+bool SearchWordBlockDictEl (FILE *dictFile,
+			    const block_idx &bIdx,
+			    unsigned long entriesPerBlock,
+			    unsigned long dictSize,
+			    unsigned long numLevels,
+			    const UCArray &el,
+			    word_block_dict_el &dictEl,
+			    unsigned long &elNum) {
+  UCArrayClear (dictEl.el);
+
+  // find the block that contains the element
+  unsigned long blockIdxNum;
+  if (!SearchEl (bIdx, entriesPerBlock, el,
+		 blockIdxNum, elNum))
+    return false;
+
+  unsigned long blockEndElNum = elNum + entriesPerBlock;
+  if (blockEndElNum > dictSize) blockEndElNum = dictSize;
+
+  // look for the block
+  fseek (dictFile, bIdx[blockIdxNum].block_ptr, SEEK_SET);
+  while (elNum < blockEndElNum) {
+    dictEl.Read (dictFile, numLevels);
+    int res = DictCompare (dictEl.el, el);
+    if (res == 0) return true; // found it
+    else if (res > 0) break; // not here
+    
+    elNum++;
+  }
+
+  return false;
+}
+
+
+
+
+bool SearchStemBlockDictElNum (FILE *dictFile,
+			       const block_idx &bIdx,
+			       unsigned long entriesPerBlock,
+			       unsigned long dictSize,
+			       unsigned long elNum,
+			       stem_block_dict_el &dictEl) {
+  UCArrayClear (dictEl.el);
+  if (elNum >= dictSize) return false;
+
+  // find the block that contains the element
+  unsigned long blockIdxNum, curElNum;
+  if (!SearchElNum (bIdx, entriesPerBlock, elNum,
+		    blockIdxNum, curElNum))
+    return false;
+
+  // look for the block
+  fseek (dictFile, bIdx[blockIdxNum].block_ptr, SEEK_SET);
+  do {
+    dictEl.Read (dictFile);
+  } while (curElNum++ < elNum);
+
+  return true;
+}
+
+bool SearchStemBlockDictEl (FILE *dictFile,
+			    const block_idx &bIdx,
+			    unsigned long entriesPerBlock,
+			    unsigned long dictSize,
+			    const UCArray &el,
+			    stem_block_dict_el &dictEl,
+			    unsigned long &elNum) {
+  UCArrayClear (dictEl.el);
+
+  // find the block that contains the element
+  unsigned long blockIdxNum;
+  if (!SearchEl (bIdx, entriesPerBlock, el,
+		 blockIdxNum, elNum))
+    return false;
+
+  unsigned long blockEndElNum = elNum + entriesPerBlock;
+  if (blockEndElNum > dictSize) blockEndElNum = dictSize;
+
+  // look for the block
+  fseek (dictFile, bIdx[blockIdxNum].block_ptr, SEEK_SET);
+  while (elNum < blockEndElNum) {
+    dictEl.Read (dictFile);
+    int res = DictCompare (dictEl.el, el);
+    if (res == 0) return true; // found it
+    else if (res > 0) break; // not here
+    
+    elNum++;
+  }
+
+  return false;
+}
+
+//----------------------------------------------------------------
+// functions for full text browse
+
+bool NearestSearchWordBlockDictEl (FILE *dictFile,
+				   const block_idx &bIdx,
+				   unsigned long entriesPerBlock,
+				   unsigned long dictSize,
+				   unsigned long numLevels,
+				   const UCArray &el,
+				   word_block_dict_el &dictEl,
+				   unsigned long &elNum) {
+
+  UCArrayClear (dictEl.el);
+
+  // find the block that contains the element
+  unsigned long blockIdxNum;
+  if (!SearchEl (bIdx, entriesPerBlock, el,
+		 blockIdxNum, elNum))
+    return false;
+
+  unsigned long blockEndElNum = elNum + entriesPerBlock;
+  if (blockEndElNum > dictSize) blockEndElNum = dictSize;
+
+  // look for the block
+  fseek (dictFile, bIdx[blockIdxNum].block_ptr, SEEK_SET);
+  while (elNum < blockEndElNum) {
+    dictEl.Read (dictFile, numLevels);
+    int res = DictCompare (el, dictEl.el); // look for the first word that is
+                                     // greater or equal to the el
+    if (res <= 0) {
+      return true; // found one
+   } 
+    
+    elNum++;
+  }
+  // it must be the last term
+  return true;
+
+
+}
+
+
+bool SearchWordBlockDictElNumRange (FILE *dictFile,
+				    const block_idx &bIdx,
+				    unsigned long entriesPerBlock,
+				    unsigned long dictSize,
+				    unsigned long numLevels,
+				    unsigned long elNum,
+				    unsigned long numWords,
+				    UCArrayVector &terms) {
+
+  word_block_dict_el dictEl;  
+  dictEl.SetNumLevels (numLevels);
+  UCArrayClear(dictEl.el);
+
+  terms.erase(terms.begin(), terms.end());
+
+  if (elNum >= dictSize) return false;
+  
+  // find the block that contains the element
+  unsigned long blockIdxNum, curElNum;
+  if (!SearchElNum (bIdx, entriesPerBlock, elNum,
+		    blockIdxNum, curElNum))
+    return false;
+
+  unsigned long lastElNum = elNum + numWords - 1;
+  if (lastElNum > dictSize) lastElNum = dictSize;
+
+  // look for the block
+  fseek (dictFile, bIdx[blockIdxNum].block_ptr, SEEK_SET);
+  
+  // get the first term
+  do {
+    dictEl.Read (dictFile, numLevels);
+  } while (curElNum++ < elNum);
+
+  terms.push_back(dictEl.el);
+  while (curElNum <= lastElNum ) {
+    dictEl.Read(dictFile, numLevels);
+    terms.push_back(dictEl.el);
+    curElNum++;
+  }
+  
+
+  return true;
+}
+
+// NOte: before each addition of dictEl to the array, the level freqs array
+// is deleted, as this was causing problems - generating a seg fault, I think if
+// the vector had to be reallocated or something.
+// setNumLevels has to be called each time before a read, now, to set up the level
+//freqs array. this is necessary.
+bool SearchWordBlockDictElNumRange (FILE *dictFile,
+				    const block_idx &bIdx,
+				    unsigned long entriesPerBlock,
+				    unsigned long dictSize,
+				    unsigned long numLevels,
+				    unsigned long elNum,
+				    unsigned long numWords,
+				    word_block_dict_el_array &terms) {
+
+  word_block_dict_el dictEl;
+  dictEl.SetNumLevels (numLevels);
+  UCArrayClear(dictEl.el);
+
+  block_dict_el elem;
+  terms.erase(terms.begin(), terms.end());
+
+  if (elNum >= dictSize) return false;
+  
+  // find the block that contains the element
+  unsigned long blockIdxNum, curElNum;
+  if (!SearchElNum (bIdx, entriesPerBlock, elNum,
+		    blockIdxNum, curElNum))
+    return false;
+
+  unsigned long lastElNum = elNum + numWords - 1;
+  if (lastElNum > dictSize) lastElNum = dictSize;
+
+  // look for the block
+  fseek (dictFile, bIdx[blockIdxNum].block_ptr, SEEK_SET);
+  // get the first term
+  do {
+    dictEl.Read (dictFile, numLevels);
+  } while (curElNum++ < elNum);
+
+  dictEl.levelFreqs = NULL;
+  terms.push_back(dictEl);
+
+  while (curElNum <= lastElNum ) { 
+    dictEl.SetNumLevels(numLevels);
+    dictEl.Read(dictFile, numLevels);
+    dictEl.levelFreqs = NULL;
+    terms.push_back(dictEl);
+    curElNum++;
+  }
+
+  return true;
+}
+
+
+
+
+
+
+
+
+
Index: /main/tags/2.25/gsdl/src/mgpp/text/invf.h
===================================================================
--- /main/tags/2.25/gsdl/src/mgpp/text/invf.h	(revision 21064)
+++ /main/tags/2.25/gsdl/src/mgpp/text/invf.h	(revision 21064)
@@ -0,0 +1,339 @@
+/**************************************************************************
+ *
+ * invf.h -- Data structures for inverted files
+ * Copyright (C) 1999  Rodger McNab
+ *
+ * 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.
+ *
+ * $Id$
+ *
+ **************************************************************************/
+
+
+#ifndef H_INVF
+#define H_INVF
+
+#include <stdio.h>
+
+#include "UCArray.h"
+
+// NOTE: This does not include the magic number
+// header info for .invf.dict file
+struct invf_dict_header {
+  unsigned long lookback;
+  unsigned long word_dict_start;
+  unsigned long word_dict_size;
+  unsigned long tag_dict_start;
+  unsigned long tag_dict_size;
+  unsigned long num_docs;
+  unsigned long num_frags;
+  unsigned long num_words;
+  unsigned long total_bytes;
+  unsigned long index_string_bytes;
+  unsigned long num_levels;
+
+  invf_dict_header ();
+  virtual ~invf_dict_header ();
+  virtual void Clear();
+
+  virtual bool Read (FILE *f);
+  virtual bool Write (FILE *f) const;
+};
+
+
+struct dict_el {
+  UCArray el; // word or tag
+  unsigned long frag_occur;
+  unsigned long freq;
+
+  virtual void Clear ();
+  dict_el () { Clear (); }
+  virtual ~dict_el () { }
+
+  // Read assumes that the last word is in el
+  bool Read (FILE *f);
+  bool Write (FILE *f, const UCArray *lastEl) const;
+};
+
+
+struct word_dict_el : public dict_el {
+  unsigned long *levelFreqs;
+
+  void Clear ();
+  word_dict_el () { levelFreqs = NULL; Clear (); }
+  ~word_dict_el ();
+
+  void SetNumLevels (unsigned long numLevels);
+
+  // SetNumLevels should be called before either
+  // reading or writing using Read and Write
+  
+  // Read assumes that the last word is in el
+  bool Read (FILE *f, unsigned long numLevels);
+  bool Write (FILE *f, const UCArray *lastEl,
+	      unsigned long numLevels) const;
+};
+
+
+// wblk = word block
+// tblk = tag block
+// this version of the blocked dictionary uses a fixed number
+// of entries per block, not a fixed block size
+// info for .invf.dict.blocked file
+// blocked dict has a heap of blocks, some for words, some for tags
+// and an index into each set of blocks. The index has pointers to
+// the first entry in each block. Can do a binary search on the index
+// to find out which block an elemnet is in
+struct block_dict_header : public invf_dict_header {
+  // note: word_dict_start and tag_dict_start are undefined
+  // for blocked dictionaries
+
+  unsigned long entries_per_wblk; // word blocks
+  unsigned long num_wblks;
+  unsigned long max_wblk_size;
+  unsigned long wblk_start;
+  unsigned long wblk_idx_start;
+  
+  unsigned long entries_per_tblk; // tag blocks
+  unsigned long num_tblks;
+  unsigned long max_tblk_size;
+  unsigned long tblk_start;
+  unsigned long tblk_idx_start;
+  
+  block_dict_header ();
+  void Clear ();
+  
+  bool Read (FILE *f);
+  bool Write (FILE *f) const;
+};
+
+
+struct block_dict_el {
+  UCArray el; // word or tag
+  unsigned long frag_occur; // # entries in invf file - if have a
+  // word level index, this is the same as freq, otherwise, its the number
+  // of fragments containing this word
+  unsigned long freq; // # of times this word occurs
+  unsigned long invf_ptr; // pointer into inverted file
+
+  virtual void Clear ();
+  block_dict_el () { Clear (); }
+  virtual ~block_dict_el () { }
+
+  // Read assumes that the last word is in el
+  // set lastEl = NULL when no lookback is wanted (eg
+  // for the start of a block
+  bool Read (FILE *f);
+  bool Write (FILE *f, const UCArray *lastEl) const;
+};
+
+struct word_block_dict_el : public block_dict_el {
+  unsigned long *levelFreqs; // freq of the word at each level
+
+  void Clear ();
+  word_block_dict_el () { levelFreqs = NULL; Clear (); }
+  ~word_block_dict_el ();
+
+  void SetNumLevels (unsigned long numLevels);
+
+  // SetNumLevels should be called before either
+  // reading or writing using Read and Write
+  
+  // Read assumes that the last word is in el
+  bool Read (FILE *f, unsigned long numLevels);
+  bool Write (FILE *f, const UCArray *lastEl,
+	      unsigned long numLevels) const;
+};
+
+typedef vector<word_block_dict_el> word_block_dict_el_array;
+
+struct block_idx_info {
+  UCArray el;
+  unsigned long block_ptr;
+
+  block_idx_info ();
+  void Clear ();
+
+  bool Read (FILE *f);
+  bool Write (FILE *f) const;
+};
+
+// used for an index into the word and tag blocks
+typedef vector<block_idx_info> block_idx;
+
+bool ReadBlockIdx (FILE *f, block_idx &blockIdx);
+bool WriteBlockIdx (FILE *f, const block_idx &blockIdx);
+
+
+
+struct stem_idx_header {
+  unsigned long lookback;
+  unsigned long dict_size;
+
+  unsigned long entries_per_block;
+  unsigned long num_blocks;
+  unsigned long max_block_size;
+  unsigned long blocks_start;
+  unsigned long block_idx_start;
+  
+  unsigned long stemmer_num;
+  unsigned long stem_method;
+
+  stem_idx_header ();
+  void Clear ();
+
+  bool Read (FILE *f);
+  bool Write (FILE *f) const;
+};
+
+struct stem_block_dict_el {
+  UCArray el; // word or tag
+  vector<unsigned long> equivWords;
+  
+  stem_block_dict_el ();
+  void Clear ();
+
+  // Read assumes that the last word is in el
+  // set lastEl = NULL when no lookback is wanted (eg
+  // for the start of a block
+  bool Read (FILE *f);
+  bool Write (FILE *f, const UCArray *lastEl) const;
+};
+
+
+
+#define SKIP_MODE_NO_SKIPS 0
+
+// invf file - has a list of frags for each word, but the word is not 
+//  stored in the invf file - the dictionaries store the words, along
+// with num entries, and a pointer into invf file
+struct invf_file_header {
+  unsigned long no_of_words;
+  unsigned long no_of_tags;
+  unsigned long skip_mode;
+  unsigned long word_level_index; // 1 if word level index
+  unsigned long params[16];
+
+  invf_file_header ();
+  void Clear ();
+  
+  bool Read (FILE *f);
+  bool Write (FILE *f) const;
+};
+
+
+
+
+
+
+// the search functions returns true if a block that could
+// satisfy the request is found. these functions assume that
+// the block index is sorted by DictCompare (or DictLTUCArray)
+bool SearchElNum (const block_idx &bIdx,
+		  unsigned long entriesPerBlock,
+		  unsigned long elNum,
+		  unsigned long &blockIdxNum,
+		  unsigned long &blockStartElNum);
+bool SearchEl (const block_idx &bIdx,
+	       unsigned long entriesPerBlock,
+	       const UCArray &el,
+	       unsigned long &blockIdxNum,
+	       unsigned long &blockStartElNum);
+
+
+// The next six functions use SearchElNum and SearchEl
+// for a particular type of dictionary (Block, WordBlock, or StemBlock)
+// and then look up the entry
+bool SearchBlockDictElNum (FILE *dictFile,
+			   const block_idx &bIdx,
+			   unsigned long entriesPerBlock,
+			   unsigned long dictSize,
+			   unsigned long elNum,
+			   block_dict_el &dictEl);
+bool SearchBlockDictEl (FILE *dictFile,
+			const block_idx &bIdx,
+			unsigned long entriesPerBlock,
+			unsigned long dictSize,
+			const UCArray &el,
+			block_dict_el &dictEl,
+			unsigned long &elNum);
+
+// assumes the numLevels has been set for dictEl
+bool SearchWordBlockDictElNum (FILE *dictFile,
+			       const block_idx &bIdx,
+			       unsigned long entriesPerBlock,
+			       unsigned long dictSize,
+			       unsigned long numLevels,
+			       unsigned long elNum,
+			       word_block_dict_el &dictEl);
+bool SearchWordBlockDictEl (FILE *dictFile,
+			    const block_idx &bIdx,
+			    unsigned long entriesPerBlock,
+			    unsigned long dictSize,
+			    unsigned long numLevels,
+			    const UCArray &el,
+			    word_block_dict_el &dictEl,
+			    unsigned long &elNum);
+
+bool SearchStemBlockDictElNum (FILE *dictFile,
+			       const block_idx &bIdx,
+			       unsigned long entriesPerBlock,
+			       unsigned long dictSize,
+			       unsigned long elNum,
+			       stem_block_dict_el &dictEl);
+bool SearchStemBlockDictEl (FILE *dictFile,
+			    const block_idx &bIdx,
+			    unsigned long entriesPerBlock,
+			    unsigned long dictSize,
+			    const UCArray &el,
+			    stem_block_dict_el &dictEl,
+			    unsigned long &elNum);
+
+//----------------------------------------------------------
+
+// new functions for full text browse
+
+bool NearestSearchWordBlockDictEl (FILE *dictFile,
+			    const block_idx &bIdx,
+			    unsigned long entriesPerBlock,
+			    unsigned long dictSize,
+			    unsigned long numLevels,
+			    const UCArray &el,
+			    word_block_dict_el &dictEl,
+			    unsigned long &elNum);
+
+// returns a list of word_block_dict_el, with no levelfreqs
+bool SearchWordBlockDictElNumRange (FILE *dictFile,
+				    const block_idx &bIdx,
+				    unsigned long entriesPerBlock,
+				    unsigned long dictSize,
+				    unsigned long numLevels,
+				    unsigned long elNum,
+				    unsigned long numWords,
+				    word_block_dict_el_array &terms);
+				    
+// just returns a list of terms
+bool SearchWordBlockDictElNumRange (FILE *dictFile,
+				    const block_idx &bIdx,
+				    unsigned long entriesPerBlock,
+				    unsigned long dictSize,
+				    unsigned long numLevels,
+				    unsigned long elNum,
+				    unsigned long numWords,
+				    UCArrayVector &terms);
+				    
+
+
+#endif
Index: /main/tags/2.25/gsdl/src/mgpp/text/ivf.pass1.cpp
===================================================================
--- /main/tags/2.25/gsdl/src/mgpp/text/ivf.pass1.cpp	(revision 21064)
+++ /main/tags/2.25/gsdl/src/mgpp/text/ivf.pass1.cpp	(revision 21064)
@@ -0,0 +1,789 @@
+/**************************************************************************
+ *
+ * ivf.pass1.cpp -- Memory efficient pass 1 inversion
+ * Copyright (C) 1999  Rodger McNab
+ *
+ * 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.
+ *
+ * $Id$
+ *
+ **************************************************************************/
+
+#include "sysfuncs.h"
+
+#include "mg_files.h"
+#include "invf.h"
+#include "mg.h"
+#include "build.h"
+#include "locallib.h"
+#include "UCArray.h"
+#include "bitio_m_stdio.h"
+#include "bitio_gen.h"
+#include <stdio.h>
+#include "words.h"
+#include "messages.h"
+#include "netorder.h"
+#include "FIvfLevelInfo.h"
+
+#include "longlong.h"
+
+#if defined(GSDL_USE_OBJECTSPACE)
+#  include <ospace\std\map>
+#elif defined(GSDL_USE_STL_H)
+#  include <map.h>
+#else
+#  include <map>
+#endif
+
+
+/*
+   $Log$
+   Revision 1.1  2000/01/14 02:26:07  sjboddie
+   Rodgers new C++ mg
+
+   *
+ */
+
+
+
+// a fragment corresponds to the index level (word-level is the
+// minimum index level)
+
+
+// structure to determine level information
+struct LevelWorker {
+  unsigned long lastLevelDocNum;
+  unsigned long count;
+
+  LevelWorker () {
+    lastLevelDocNum = count = 0;
+  }
+};
+
+
+// note: the word is stored in the map
+struct IvfWordInfo {
+  unsigned long wordCount;      // word frequency
+  unsigned long fragCount;      // number of fragments that contain the word
+  unsigned long lastFragNum;    // last fragment to contain the word
+  unsigned long chunkWordCount; // word frequency within this chunk
+  unsigned long chunkFragCount; // number of fragments within this chunk that
+                                //   contain the word
+
+  LevelWorker *levels;          // level info for this word
+  
+  IvfWordInfo ();
+  ~IvfWordInfo ();
+  void Clear ();                // will delete levels
+};
+
+typedef map<UCArray, IvfWordInfo, DictLTUCArray> IvfWordInfoMap;
+typedef vector<IvfWordInfoMap::iterator> IvfWordInfoItArray;
+
+// tags don't require as much information
+struct IvfTagInfo {
+  unsigned long tagCount;       // tag frequency
+  unsigned long fragCount;      // number of fragments that contain the tag
+  unsigned long lastFragNum;    // last fragment to contain the tag
+  unsigned long chunkFragCount; // number of fragments within this chunk that
+                                //   contain the tag
+
+  IvfTagInfo ();
+  void Clear ();
+};
+
+typedef map<UCArray, IvfTagInfo, DictLTUCArray> IvfTagInfoMap;
+typedef vector<IvfTagInfoMap::iterator> IvfTagInfoItArray;
+
+
+#define INIT_CHECK_FRAC 0.10
+#define CHECK_FRAC 0.75
+#define CHECK_CLOSE 0.999
+#define CHECK_DIV 1.5
+
+
+static FILE *ic;		// the invf chunk file
+static stdio_bitio_buffer icb;
+
+IvfWordInfoMap ivfWordInfo;
+IvfWordInfoItArray ivfWordInfoOccurOrder;
+IvfTagInfoMap ivfTagInfo;
+IvfTagInfoItArray ivfTagInfoOccurOrder;
+
+static unsigned long chunksWritten;
+static unsigned long maxMemNeeded;
+
+static unsigned long numDocs;
+static unsigned long numChunkDocs;
+
+static unsigned long numFrags;
+static unsigned long numChunkFrags;
+
+static unsigned long numWords;
+
+// the number of document numbers in the inverted file
+static unsigned long numChunkEntries;
+
+// next entry in the inverted file to check memory
+// requirements for the current chunk
+static unsigned long entryCheckPoint;
+
+// information about all the different levels
+static FIvfLevel ivfLevel;
+
+
+
+IvfWordInfo::IvfWordInfo () {
+  levels = NULL;
+  Clear();
+}
+
+IvfWordInfo::~IvfWordInfo () {
+  if (levels != NULL) delete [] levels;
+}
+
+void IvfWordInfo::Clear () {
+  wordCount = 0;
+  chunkWordCount = 0;
+  lastFragNum = 0;
+  fragCount = 0;
+  chunkFragCount = 0;
+
+  if (levels != NULL) {
+    delete [] levels;
+    levels = NULL;
+  }
+}
+
+
+IvfTagInfo::IvfTagInfo () {
+  Clear();
+}
+
+void IvfTagInfo::Clear () {
+  tagCount = 0;
+  lastFragNum = 0;
+  fragCount = 0;
+  chunkFragCount = 0;
+}
+
+
+
+int init_ivf_1 (const TagInfo &tagInfo, char *file_name) {
+  // set up the chunk file
+  if (!(ic = create_file (file_name, INVF_CHUNK_SUFFIX, "wb",
+			  MAGIC_CHUNK, MG_MESSAGE)))
+    return COMPERROR;
+  fwrite ("    ", sizeof (u_long), 1, ic);	// Space for the maxmem
+  icb.attachFile (ic);
+  icb.encodeStart();
+
+  // reset global variables
+  ivfWordInfo.erase (ivfWordInfo.begin(), ivfWordInfo.end());
+  ivfWordInfoOccurOrder.erase (ivfWordInfoOccurOrder.begin(), ivfWordInfoOccurOrder.end());
+  ivfTagInfo.erase (ivfTagInfo.begin(), ivfTagInfo.end());
+  ivfTagInfoOccurOrder.erase (ivfTagInfoOccurOrder.begin(), ivfTagInfoOccurOrder.end());
+  
+  chunksWritten = 0;
+  maxMemNeeded = 0;
+ 
+  numDocs = 0;
+  numChunkDocs = 0;
+
+  numFrags = 0;
+  numChunkFrags = 0;
+
+  numWords = 0;
+
+  numChunkEntries = 0;
+  entryCheckPoint = (unsigned long) ((invf_buffer_size * INIT_CHECK_FRAC) / CHECK_DIV);
+
+  // init the level information
+  ivfLevel.Clear();
+  ivfLevel.docTag = tagInfo.docTag;
+  ivfLevel.indexLevel = tagInfo.indexLevel;
+  IvfLevelInfo blankLevel;
+  UCArraySet::const_iterator levelHere = tagInfo.levelTags.begin();
+  UCArraySet::const_iterator levelEnd = tagInfo.levelTags.end();
+  while (levelHere != levelEnd) {
+    blankLevel.levelTag = *levelHere;
+    ivfLevel.levelInfo[*levelHere] = blankLevel;
+    levelHere++;
+  }
+  
+  return COMPALLOK;
+}
+
+static void ProcessOpenTag (const TagInfo &tagInfo, const TextEl &el,
+			    bool &inFrag) {
+  bool wordLevelIndex = tagInfo.indexLevel.empty();
+
+  // check for start of next fragment
+  if (!wordLevelIndex && el.tagName == tagInfo.indexLevel) {
+    numFrags++;
+    numChunkFrags++;
+    inFrag = true;
+  }
+  
+  // update tag stats
+  IvfTagInfo &i = ivfTagInfo[el.tagName];
+  if (i.tagCount == 0) {
+    // new tag, add to list of iterators
+    IvfTagInfoMap::iterator iIt = ivfTagInfo.find (el.tagName);
+    ivfTagInfoOccurOrder.push_back (iIt);
+  }
+  i.tagCount++;
+
+  // all open tags count as new tags
+  numChunkEntries++;
+  i.fragCount++;
+  i.chunkFragCount++;
+  i.lastFragNum = numFrags;
+  
+  // update level information
+  IvfLevelInfoMap::iterator levelIt = ivfLevel.levelInfo.find (el.tagName);
+  if (levelIt != ivfLevel.levelInfo.end()) {
+    // is a level tag
+    (*levelIt).second.numEntries++;
+    (*levelIt).second.workInLevel = true;
+  }
+}
+
+static void ProcessCloseTag (const TagInfo &tagInfo, const TextEl &el,
+			     bool &inFrag) {
+  bool wordLevelIndex = tagInfo.indexLevel.empty();
+
+  // check for end of fragment
+  if (!wordLevelIndex && el.tagName == tagInfo.indexLevel) {
+    inFrag = false;
+  }
+
+  // update level information
+  IvfLevelInfoMap::iterator levelIt = ivfLevel.levelInfo.find (el.tagName);
+  if (levelIt != ivfLevel.levelInfo.end()) {
+    // is a level tag
+    (*levelIt).second.workInLevel = false;
+  }
+}
+
+static void ProcessText (const TagInfo &tagInfo, const TextEl &el,
+			 bool &inFrag) {
+  bool wordLevelIndex = tagInfo.indexLevel.empty();
+
+  // make sure this text is to be indexed
+  if (!wordLevelIndex && !inFrag) return;
+
+  const unsigned char *textHere = el.text.begin();
+  const unsigned char *textEnd = el.text.end() - 1;
+  UCArray word;
+  
+  if (!inaword (textHere, textEnd))
+    ParseNonindexWord (textHere, textEnd);
+
+  
+  // Alternately parse off words and non-words from the input
+  // Each token is then inserted into the set if it does
+  // not exist or has it's frequency count incremented if it does.
+
+  while (textHere <= textEnd) {
+    textHere = ParseIndexWord (textHere, textEnd, word);
+    textHere = ParseNonindexWord (textHere, textEnd);
+
+    if (!word.empty()) {
+      numWords++;
+
+      if (wordLevelIndex) {
+	numFrags++;
+	numChunkFrags++;
+      }
+      
+      // update word stats
+
+      IvfWordInfo &i = ivfWordInfo[word];
+      if (i.wordCount == 0) {
+	// new word
+	// add to list of iterators
+	IvfWordInfoMap::iterator iIt = ivfWordInfo.find (word);
+	ivfWordInfoOccurOrder.push_back (iIt);
+
+	// add level information array
+	if (ivfLevel.levelInfo.size() > 0) 
+	  i.levels = new LevelWorker [ivfLevel.levelInfo.size()];
+      }
+
+      i.wordCount++;
+      i.chunkWordCount++;
+      if (numFrags > i.lastFragNum) {
+	numChunkEntries++;
+	i.fragCount++;
+	i.chunkFragCount++;
+	i.lastFragNum = numFrags;
+      }
+
+      // update level information for this word
+      if (i.levels != NULL) {
+	IvfLevelInfoMap::iterator levelHere = ivfLevel.levelInfo.begin();
+	IvfLevelInfoMap::iterator levelEnd = ivfLevel.levelInfo.end();
+	LevelWorker *levelWorkerPtr = i.levels;
+	while (levelHere != levelEnd) {
+
+	  // check to make sure the level encompases this fragment
+	  if (!(*levelHere).second.workInLevel) {
+	    cerr << "Level tag <" << (*levelHere).first
+		 << "> does not encompass all fragments\n";
+	    exit (1);
+	  }
+	  
+	  if ((*levelHere).second.numEntries > (*levelWorkerPtr).lastLevelDocNum) {
+	    (*levelWorkerPtr).lastLevelDocNum = (*levelHere).second.numEntries;
+	    (*levelWorkerPtr).count ++;
+	  }
+	  
+	  levelHere++;
+	  levelWorkerPtr++;
+	}
+      }
+    }
+  }
+}
+
+
+static unsigned long MemoryRequired (bool wordLevelIndex) {
+  register unsigned long total = 0;
+
+  // add memory required for word entries
+  IvfWordInfoMap::const_iterator wordHere = ivfWordInfo.begin();
+  IvfWordInfoMap::const_iterator wordEnd = ivfWordInfo.end();
+  while (wordHere != wordEnd) {
+    register const IvfWordInfo &info = (*wordHere).second;
+    if (info.chunkFragCount > 0) {
+      total += BIO_Bblock_Bound (numChunkFrags, info.chunkFragCount);
+      if (!wordLevelIndex) {
+	total += info.chunkWordCount;
+      }
+    }
+    
+    wordHere++;
+  }
+
+  // add memory required for tag entries
+  IvfTagInfoMap::const_iterator tagHere = ivfTagInfo.begin();
+  IvfTagInfoMap::const_iterator tagEnd = ivfTagInfo.end();
+  while (tagHere != tagEnd) {
+    register const IvfTagInfo &info = (*tagHere).second;
+    if (info.chunkFragCount > 0) {
+      // two d entries for each frag entry
+      unsigned long pTag = info.chunkFragCount*2;
+      total += BIO_Bblock_Bound (numChunkFrags+pTag, pTag);
+    }
+    
+    tagHere++;
+  }
+  
+  total = (total + 7) >> 3;
+  return total;
+}
+
+
+/*
+static void PrintChunkInfo (unsigned long mem) {
+  cout << "Chunk Number: " << chunksWritten << "\n";
+  cout << "numChunkDocs " << numChunkDocs << "\n";
+  cout << "numChunkFrags " << numChunkFrags << "\n";
+  cout << "mem " << mem << "\n";
+  cout << "numWords " << ivfWordInfo.size() << "\n";
+  cout << "numTags " << ivfTagInfo.size() << "\n\n";
+
+  // output debug tag information in dictionary order
+  IvfTagInfoMap::iterator tagMapHere = ivfTagInfo.begin();
+  IvfTagInfoMap::iterator tagMapEnd = ivfTagInfo.end();
+  unsigned long tagNum = 0;
+  while (tagMapHere != tagMapEnd) {
+    cout << (*tagMapHere).first << " " << tagNum
+	 << " " << (*tagMapHere).second.chunkFragCount << "\n";
+    tagNum++;
+    tagMapHere++;
+  }
+}
+*/
+
+static void OutputChunkInfo (unsigned long mem, bool /*wordLevelIndex*/) {
+  chunksWritten++;
+
+  // sanity check
+  if (ivfWordInfo.size() != ivfWordInfoOccurOrder.size()) {
+    Message ("ERROR: Word information size mismatch: %u vs %u\n",
+	     (unsigned int)ivfWordInfo.size(),
+	     (unsigned int)ivfWordInfoOccurOrder.size());
+    exit (1);
+  }
+  if (ivfTagInfo.size() != ivfTagInfoOccurOrder.size()) {
+    Message ("ERROR: Tag information size mismatch: %u vs %u\n",
+	     (unsigned int)ivfTagInfo.size(),
+	     (unsigned int)ivfTagInfoOccurOrder.size());
+    exit (1);
+  }
+
+  icb.gamma_encode (numChunkDocs + 1, NULL);
+  icb.gamma_encode (numChunkFrags + 1, NULL);
+  icb.gamma_encode (mem + 1, NULL);
+  icb.gamma_encode (ivfWordInfo.size() + 1, NULL);
+  icb.gamma_encode (ivfTagInfo.size() + 1, NULL);
+
+  /*  PrintChunkInfo (mem);*/
+
+  // output word information in occurance order
+  IvfWordInfoItArray::iterator wordHere = ivfWordInfoOccurOrder.begin();
+  IvfWordInfoItArray::iterator wordEnd = ivfWordInfoOccurOrder.end();
+  while (wordHere != wordEnd) {
+    register IvfWordInfo &ivfWordInfo = (*(*wordHere)).second;
+    
+    icb.gamma_encode (ivfWordInfo.chunkWordCount + 1, NULL);
+    if (ivfWordInfo.chunkWordCount >= 2) {
+      icb.gamma_encode (ivfWordInfo.chunkFragCount, NULL);
+    }
+
+    ivfWordInfo.lastFragNum = 0;
+    ivfWordInfo.chunkWordCount = 0;
+    ivfWordInfo.chunkFragCount = 0;
+    
+    wordHere++;
+  }
+
+  // output tag information in occurance order
+  IvfTagInfoItArray::iterator tagHere = ivfTagInfoOccurOrder.begin();
+  IvfTagInfoItArray::iterator tagEnd = ivfTagInfoOccurOrder.end();
+  while (tagHere != tagEnd) {
+    register IvfTagInfo &ivfTagInfo = (*(*tagHere)).second;
+
+    icb.gamma_encode (ivfTagInfo.chunkFragCount + 1, NULL);
+
+    ivfTagInfo.lastFragNum = 0;
+    ivfTagInfo.chunkFragCount = 0;
+    
+    tagHere++;
+  }
+
+  numChunkDocs = 0;
+  numChunkFrags = 0;
+  numChunkEntries = 0;
+}
+
+
+int process_ivf_1 (const TagInfo &tagInfo, const TextElArray &doc) {
+  bool wordLevelIndex = tagInfo.indexLevel.empty();
+  bool inFrag = false;
+  if (wordLevelIndex) inFrag = true; // unconditional
+  
+  numDocs++;
+  numChunkDocs++;
+
+  // process each text element in this document
+  TextElArray::const_iterator here = doc.begin();
+  TextElArray::const_iterator end = doc.end();
+  while (here != end) {
+    if ((*here).elType == OpenTagE)
+      ProcessOpenTag (tagInfo, *here, inFrag);
+    else if ((*here).elType == CloseTagE)
+      ProcessCloseTag (tagInfo, *here, inFrag);
+    else if ((*here).elType == TextE)
+      ProcessText (tagInfo, *here, inFrag);
+    
+    here++;
+  }
+
+  // check the amount of memory needed for this chunk
+  if (numChunkEntries >= entryCheckPoint) {
+    unsigned long mem = MemoryRequired (wordLevelIndex);
+    if (mem >= invf_buffer_size * CHECK_CLOSE) {
+      if (mem > maxMemNeeded) maxMemNeeded = mem;
+      OutputChunkInfo (mem, wordLevelIndex);
+      entryCheckPoint = (unsigned long)
+	((invf_buffer_size * INIT_CHECK_FRAC) / CHECK_DIV);
+      
+    } else {
+      entryCheckPoint = (unsigned long)
+	(entryCheckPoint * ((CHECK_FRAC * (invf_buffer_size - mem)) / mem) +
+	 entryCheckPoint);
+      if (entryCheckPoint <= numChunkEntries)
+	entryCheckPoint = numChunkEntries + 1;
+    }
+  }
+  
+  return COMPALLOK;
+}
+
+
+static void CalcInvfDictSize (unsigned long &totalBytes,
+			      unsigned long &indexStringBytes) {
+  totalBytes = 0;	// The sum of the length of all words, including 
+			// the length byte
+  indexStringBytes = 0; // The amount of space required to store the 
+			// words in the diction, this takes into account 
+			// the prefixes
+  const UCArray *lastWord = NULL;
+  
+  // calculate size of word information
+  IvfWordInfoMap::iterator wordHere = ivfWordInfo.begin();
+  IvfWordInfoMap::iterator wordEnd = ivfWordInfo.end();
+  while (wordHere != wordEnd) {
+    unsigned long wordSize = (*wordHere).first.size();
+    totalBytes += wordSize + 1;
+    indexStringBytes += wordSize + 2;
+    if (lastWord != NULL)
+      indexStringBytes -= PrefixLen (*lastWord, (*wordHere).first);
+    lastWord = &((*wordHere).first);
+    
+    wordHere++;
+  }
+
+  // calculate size of tag information
+  lastWord = NULL;
+  IvfTagInfoMap::iterator tagHere = ivfTagInfo.begin();
+  IvfTagInfoMap::iterator tagEnd = ivfTagInfo.end();
+  while (tagHere != tagEnd) {
+    unsigned long tagSize = (*tagHere).first.size();
+    totalBytes += tagSize + 1;
+    indexStringBytes += tagSize + 2;
+    if (lastWord != NULL)
+      indexStringBytes -= PrefixLen (*lastWord, (*tagHere).first);
+    lastWord = &((*tagHere).first);
+    
+    tagHere++;
+  }
+}
+
+
+//      OutputInvfDict ():
+//                writes out the stemmed dictionary file
+//                in the following format 
+//                        lookback value (int)
+//                        totalbytes value (int)
+//                        indexstringbytes (int)
+//                        for each word 
+//                          wordlen (4 bits)
+//                          prefix match (4 bits)
+//                          word (wordlen bytes)
+//                          word frequency (int)
+//                          word count (int)
+//
+//        Accesses outside variables:     
+//
+//        Return value...:                
+static void OutputInvfDict (char *filename) {
+  // create the dictionary header
+  invf_dict_header idh;
+  idh.word_dict_size = ivfWordInfo.size();
+  idh.tag_dict_size = ivfTagInfo.size();
+  idh.num_docs = numDocs;
+  idh.num_frags = numFrags;
+  idh.num_words = numWords;
+  idh.num_levels = ivfLevel.levelInfo.size();
+  CalcInvfDictSize (idh.total_bytes, idh.index_string_bytes);
+
+  // create the inverted dictionary file
+  FILE *sp;
+  if (!(sp = create_file (filename, INVF_DICT_SUFFIX, "wb", MAGIC_STEM_BUILD,
+			  MG_MESSAGE)))
+    return;
+
+  // write out the dictionary header
+  if (!idh.Write (sp)) { fclose (sp); return; }
+
+  // remember where the word dictionary starts
+  idh.word_dict_start = ftell (sp);
+  
+  // output the word dictionary
+  const UCArray *lastWord = NULL;
+  IvfWordInfoMap::iterator wordHere = ivfWordInfo.begin();
+  IvfWordInfoMap::iterator wordEnd = ivfWordInfo.end();
+  while (wordHere != wordEnd) {
+    // get the prefix and suffix lengths
+    const UCArray &thisWord = (*wordHere).first;
+    WritePreSufStr (sp, lastWord, thisWord);
+
+    // output the number of fragments the word appeared in and the
+    // number of times the word appeared
+    WriteUL (sp, (*wordHere).second.fragCount);
+    WriteUL (sp, (*wordHere).second.wordCount);
+
+    // output frequency information for each level
+    // note that we are expecting every word to have
+    // level information
+    LevelWorker *lwHere = (*wordHere).second.levels;
+    LevelWorker *lwEnd = lwHere + idh.num_levels;
+    while (lwHere != lwEnd) {
+      WriteUL (sp, (*lwHere).count);
+      lwHere++;
+    }
+    
+    lastWord = &thisWord;
+    wordHere++;
+  }
+
+  // remember where the tag dictionary starts
+  idh.tag_dict_start = ftell (sp);
+  
+  // output the tag dictionary
+  const UCArray *lastTag = NULL;
+  IvfTagInfoMap::iterator tagHere = ivfTagInfo.begin();
+  IvfTagInfoMap::iterator tagEnd = ivfTagInfo.end();
+  while (tagHere != tagEnd) {
+    // get the prefix and suffix lengths
+    const UCArray &thisTag = (*tagHere).first;
+    WritePreSufStr (sp, lastTag, thisTag);
+
+    // output the number of fragments the tag appeared in and the
+    // number of times the tag appeared
+    WriteUL (sp, (*tagHere).second.fragCount);
+    WriteUL (sp, (*tagHere).second.tagCount);
+    
+    lastTag = &thisTag;
+    tagHere++;
+  }
+
+  // write out the updated header
+  fseek (sp, sizeof (u_long), SEEK_SET);
+  if (!idh.Write (sp)) { fclose (sp); return; }
+  
+  fclose (sp);
+}
+
+static void OutputLevelFile (char *filename) {
+  // create the level file
+  FILE *f;
+  if (!(f = create_file (filename, INVF_LEVEL_SUFFIX, "wb", MAGIC_INVF_LEVELS,
+			 MG_MESSAGE)))
+    return;
+
+  // write out the information
+  ivfLevel.Write (f);
+  
+  // close the file
+  fclose (f);
+}
+
+static void OutputTransFile (char *filename) {
+  // save the word number (in lastFragNum :-/)
+  int i = 0;
+  IvfWordInfoMap::iterator wordHere = ivfWordInfo.begin();
+  IvfWordInfoMap::iterator wordEnd = ivfWordInfo.end();
+  while (wordHere != wordEnd) {
+    (*wordHere).second.lastFragNum = i;
+    i++; wordHere++;
+  }
+
+  // save the tag number (in lastFragNum :-/)
+  i = 0;
+  IvfTagInfoMap::iterator tagHere = ivfTagInfo.begin();
+  IvfTagInfoMap::iterator tagEnd = ivfTagInfo.end();
+  while (tagHere != tagEnd) {
+    (*tagHere).second.lastFragNum = i;
+    i++; tagHere++;
+  }
+  
+  // create the translation file
+  FILE *f;
+  if (!(f = create_file (filename, INVF_CHUNK_TRANS_SUFFIX, "wb",
+			 MAGIC_CHUNK_TRANS, MG_MESSAGE)))
+    return;
+
+  stdio_bitio_buffer buffer(f);
+  buffer.encodeStart();
+
+  // write out the word translation table
+  unsigned long wordDictSize = ivfWordInfoOccurOrder.size();
+  IvfWordInfoItArray::iterator wordItHere = ivfWordInfoOccurOrder.begin();
+  IvfWordInfoItArray::iterator wordItEnd = ivfWordInfoOccurOrder.end();
+  unsigned long oN = 0;
+  while (wordItHere != wordItEnd) {
+    register IvfWordInfo &ivfWordInfo = (*(*wordItHere)).second;
+    buffer.binary_encode (ivfWordInfo.lastFragNum + 1, wordDictSize + 1, NULL);
+    oN++;
+    wordItHere++;
+  }
+
+  // write out the tag translation table
+  unsigned long tagDictSize = ivfTagInfoOccurOrder.size();
+  IvfTagInfoItArray::iterator tagItHere = ivfTagInfoOccurOrder.begin();
+  IvfTagInfoItArray::iterator tagItEnd = ivfTagInfoOccurOrder.end();
+  while (tagItHere != tagItEnd) {
+    register IvfTagInfo &ivfTagInfo = (*(*tagItHere)).second;
+    buffer.binary_encode (ivfTagInfo.lastFragNum + 1, tagDictSize + 1, NULL);
+    oN++;
+    tagItHere++;
+  }
+
+  // finish encoding and close the file
+  buffer.encodeDone();
+  fclose (f);
+}
+
+#ifndef SILENT
+static void PrintStats () {
+  Message ("Inverted buffer size:          %8u bytes\n", invf_buffer_size);
+  Message ("Max memory needed for 1 chunk: %8u bytes\n", maxMemNeeded);
+
+  Message ("Number of chunks written:      %8u\n", chunksWritten);
+  Message ("Number of documents:           %8u\n", numDocs);
+  Message ("Number of fragments:           %8u\n", numFrags);
+  Message ("Number of words:               %8u\n", numWords);
+
+  Message ("Size of word dictionary:       %8u\n", ivfWordInfo.size());
+  Message ("Size of tag dictionary:        %8u\n", ivfTagInfo.size());
+}
+#endif
+
+int done_ivf_1 (const TagInfo &tagInfo, char * filename) {
+  bool wordLevelIndex = tagInfo.indexLevel.empty();
+
+  char *temp_str = msg_prefix;
+  msg_prefix = "ivf.pass1";
+
+  // output the last chunk
+  if (numChunkDocs > 0) {
+    unsigned long mem = MemoryRequired (wordLevelIndex);
+    OutputChunkInfo (mem, wordLevelIndex);
+    if (mem > maxMemNeeded) maxMemNeeded = mem;
+  }
+  
+  // write out and encoded 1 to say there are no more chunks
+  icb.gamma_encode (1, NULL);
+  icb.encodeDone ();
+
+  // write out the maximum memory required and close the file
+  fseek (ic, sizeof (long), 0);
+  WriteUL (ic, maxMemNeeded);
+  fclose (ic);
+
+  // output the inverted dictionary
+  OutputInvfDict (filename);
+
+  // write out the translation file
+  OutputTransFile (filename);
+
+  // output the level information
+  OutputLevelFile (filename);
+  
+  // output statistics
+#ifndef SILENT
+  PrintStats ();
+#endif
+  
+  msg_prefix = temp_str;
+
+  return COMPALLOK;
+}
+
Index: /main/tags/2.25/gsdl/src/mgpp/text/ivf.pass2.cpp
===================================================================
--- /main/tags/2.25/gsdl/src/mgpp/text/ivf.pass2.cpp	(revision 21064)
+++ /main/tags/2.25/gsdl/src/mgpp/text/ivf.pass2.cpp	(revision 21064)
@@ -0,0 +1,1116 @@
+/**************************************************************************
+ *
+ * ivf.pass2.cpp -- Memory efficient pass 2 inversion
+ * Copyright (C) 1999  Rodger McNab
+ *
+ * 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.
+ *
+ * $Id$
+ *
+ **************************************************************************/
+
+/*
+   $Log$
+   Revision 1.1  2000/01/14 02:26:07  sjboddie
+   Rodgers new C++ mg
+
+ */
+
+#include <stdio.h>
+#include <unistd.h>
+
+#include "non_ansi.h"
+
+#include "sysfuncs.h"
+
+#include "mg_files.h"
+#include "invf.h"
+#include "mg.h"
+#include "build.h"
+#include "locallib.h"
+#include "UCArray.h"
+#include "bitio_m_random.h"
+#include "bitio_m_stdio.h"
+#include "bitio_m_mems.h"
+#include "bitio_gen.h"
+#include <stdio.h>
+#include "words.h"
+#include "messages.h"
+#include "netorder.h"
+#include "FIvfLevelInfo.h"
+#include "perf_hash.h"
+#include "string.h"
+
+#include "longlong.h"
+
+#ifdef __WIN32_
+#include <io.h>
+#endif
+
+#if defined(GSDL_USE_OBJECTSPACE)
+#  include <ospace\std\map>
+#elif defined(GSDL_USE_STL_H)
+#  include <map.h>
+#else
+#  include <map>
+#endif
+
+
+#ifdef USE_LONG_LONG
+#define SEEK_X seek_LL
+#define TELL_X tell_LL
+#else
+#define SEEK_X seek
+#define TELL_X tell
+#endif
+
+#ifndef RND_BUF_SIZE
+#define RND_BUF_SIZE 8*1024
+#endif
+
+
+static unsigned long numDocs = 0;
+static unsigned long numChunkDocs = 0;
+static unsigned long numDocsInChunk = 0;
+
+static unsigned long numFrags = 0;
+static unsigned long numFragsInChunk = 0;
+static unsigned long chunkStartFragNum = 0;
+
+
+
+
+struct BitPtr {
+  unsigned long start;
+  unsigned long here;
+  unsigned long lastFragNum;
+  unsigned long lgB;
+  
+  void Clear () { start = here = lastFragNum = lgB = 0; }
+  BitPtr () { Clear(); }
+};
+
+class WordBitPtrs {
+protected:
+  unsigned long numWords;
+  unsigned long numTags;
+  unsigned long size;
+  BitPtr *wordBitPtrs;
+
+  void CheckBufOverrun (unsigned long num) {
+    if (wordBitPtrs[num].here > wordBitPtrs[num+1].start) {
+      cerr << "numDocs: " << numDocs << "\n";
+      cerr << "numChunkDocs: " << numChunkDocs << "\n";
+      cerr << "numDocsInChunk: " << numDocsInChunk << "\n";
+      cerr << "numFrags: " << numFrags << "\n";
+      cerr << "numFragsInChunk: " << numFragsInChunk << "\n";
+      cerr << "chunkStartFragNum: " << chunkStartFragNum << "\n";
+      cerr << "num: " << num << "\n";
+      cerr << "[num].start: " << wordBitPtrs[num].start << "\n";
+      cerr << "[num].here: " << wordBitPtrs[num].here << "\n";
+      cerr << "[num+1].start: " << wordBitPtrs[num+1].start << "\n";
+      FatalError (1, "Bit buffer overrun");
+    }
+  }
+  
+public:
+  void Clear ();
+  WordBitPtrs () { wordBitPtrs = NULL; Clear(); }
+  ~WordBitPtrs ();
+  void SetSize (unsigned long _numWords,
+		unsigned long _numTags);
+
+  void ResetPtrs () {
+    if (wordBitPtrs == NULL) return;
+    unsigned long i;
+    for (i=0; i<size; i++) wordBitPtrs[i].Clear();
+  }
+  
+  BitPtr &GetWordBitPtr (unsigned long wordNum)
+    { return wordBitPtrs[wordNum]; }
+  unsigned long &GetWordStart (unsigned long wordNum)
+    { return wordBitPtrs[wordNum].start; }
+  unsigned long &GetWordHere (unsigned long wordNum)
+    { return wordBitPtrs[wordNum].here; }
+  void CheckWordBufOverrun (unsigned long wordNum)
+    { CheckBufOverrun (wordNum); }
+
+  BitPtr &GetTagBitPtr (unsigned long tagNum)
+    { return wordBitPtrs[tagNum + numWords]; }
+  unsigned long &GetTagStart (unsigned long tagNum)
+    { return wordBitPtrs[tagNum + numWords].start; }
+  unsigned long &GetTagHere (unsigned long tagNum)
+    { return wordBitPtrs[tagNum + numWords].here; }
+  void CheckTagBufOverrun (unsigned long tagNum)
+    { CheckBufOverrun (tagNum + numWords); }
+
+  BitPtr &GetEndBitPtr ()
+    { return wordBitPtrs[size-1]; }
+  unsigned long &GetEndStart ()
+    { return wordBitPtrs[size-1].start; }
+  unsigned long &GetEndHere ()
+    { return wordBitPtrs[size-1].here; }
+};
+
+
+struct IP2TagInfo {
+  bool inTag;
+  unsigned long startFrag;
+  unsigned long tagNum;
+
+  IP2TagInfo () {
+    inTag = false;
+    startFrag = 0;
+    tagNum = 0;
+  }
+};
+
+// maps tags to tag information
+typedef map<UCArray, IP2TagInfo, DictLTUCArray> TagMapDict;
+
+
+// class to handle the translation of occurrence order
+// to dictionary order for words and tags
+class OccurToDictConverter {
+protected:
+  unsigned long pos;
+  unsigned long val;
+  FILE *transFile;
+  random_bitio_buffer rbs;
+
+  unsigned long wordDictSize;
+  unsigned long tagDictSize;
+
+  void SeekStart ();
+  unsigned long TranslateNum (unsigned long num);
+  
+public:
+  OccurToDictConverter ();
+  ~OccurToDictConverter ();
+
+  void Open (char *filename, unsigned long _wordDictSize,
+	     unsigned long _tagDictSize);
+
+  // Close frees all allocated memory
+  void Close ();
+
+  unsigned long TranslateWord (unsigned long occurNum)
+    { return TranslateNum (occurNum); }
+  unsigned long TranslateTag (unsigned long occurNum)
+    { return TranslateNum (occurNum+wordDictSize); }
+};
+
+
+struct InvfStateRec {
+  mg_ullong start;
+  mg_ullong here;
+  unsigned long lastFragNum;
+  unsigned long B;
+
+  void Clear () {
+    start = here = 0;
+    lastFragNum = B = 0;
+  }
+  InvfStateRec () { Clear (); }
+};
+
+
+#define ISR_SIZE 1024
+
+class InvfStateCache {
+protected:
+  InvfStateRec recCache [ISR_SIZE];
+  unsigned long startNum;
+
+  FILE *stateFile;
+
+  void ClearCache () {
+    unsigned int i = 0;
+    for (i=0; i<ISR_SIZE; i++) recCache[i].Clear();
+  }
+  
+public:
+  InvfStateCache ();
+  ~InvfStateCache ();
+  
+  void Open (char *filename);
+  void Close ();
+
+  // previous references to state records may be
+  // invalidated calling GetRec
+  InvfStateRec &GetRec (unsigned long num);
+};
+
+
+static invf_dict_header idh;
+static WordBitPtrs bitPtrs;
+
+static FILE *chunkFile = NULL;
+static stdio_bitio_buffer chunkBuf;
+
+static unsigned long ivfMemBufSize = 0;
+static char *ivfMemBuf = NULL;
+
+// word and tag dictionaries. a map is used for the tag dictionary
+// as it should never be very big (and the perfect hash function
+// sometimes has trouble with small values).
+static perf_hash_data *wordHashDict = NULL;
+static TagMapDict tagMapDict;
+
+// information about all the different levels
+static FIvfLevel ivfLevel;
+
+static OccurToDictConverter occurConvert;
+
+// information about the state of the inverted file
+static InvfStateCache invfState;
+
+static char collectFilename[512];
+
+
+void WordBitPtrs::Clear () {
+  numWords = 0;
+  numTags = 0;
+  size=0;
+  if (wordBitPtrs != NULL) delete [] wordBitPtrs;
+  wordBitPtrs = NULL;
+}
+
+WordBitPtrs::~WordBitPtrs () {
+  if (wordBitPtrs != NULL) delete [] wordBitPtrs;
+}
+
+void WordBitPtrs::SetSize (unsigned long _numWords,
+			   unsigned long _numTags){
+  Clear();
+  numWords = _numWords;
+  numTags = _numTags;
+  size = numWords + numTags + 1;
+  wordBitPtrs = new BitPtr [size];
+}
+
+
+void OccurToDictConverter::SeekStart () {
+  if (transFile == NULL) return;
+  rbs.SEEK_X (sizeof (unsigned long) * 8);
+  pos = 0;
+}
+
+unsigned long OccurToDictConverter::TranslateNum (unsigned long num) {
+  if (num < pos) SeekStart ();
+  while (pos <= num) {
+    if (pos < wordDictSize)
+      val = rbs.binary_decode (wordDictSize + 1, NULL) - 1;
+    else 
+      val = rbs.binary_decode (tagDictSize + 1, NULL) - 1;
+    pos++;
+  }
+  return val;
+}
+
+OccurToDictConverter::OccurToDictConverter () {
+  pos = 0;
+  val = 0;
+  transFile = NULL;
+  wordDictSize = 0;
+  tagDictSize = 0;
+}
+
+OccurToDictConverter::~OccurToDictConverter () {
+  if (transFile != NULL) Close ();
+}
+
+void OccurToDictConverter::Open (char *filename, unsigned long _wordDictSize,
+				 unsigned long _tagDictSize) {
+  if (transFile != NULL) Close ();
+
+  wordDictSize = _wordDictSize;
+  tagDictSize = _tagDictSize;
+
+  transFile = open_file (filename, INVF_CHUNK_TRANS_SUFFIX, "rb",
+			 MAGIC_CHUNK_TRANS, MG_ABORT);
+  rbs.attachFile (transFile, RND_BUF_SIZE);
+  SeekStart ();
+  val = 0;
+}
+
+void OccurToDictConverter::Close () {
+  if (transFile == NULL) return;
+
+  rbs.done ();
+  fclose (transFile);
+  transFile = NULL;
+  pos = 0;
+  val = 0;
+
+  wordDictSize = 0;
+  tagDictSize = 0;
+}
+
+
+
+
+InvfStateCache::InvfStateCache () {
+  startNum = 0;
+  stateFile = NULL;
+}
+
+InvfStateCache::~InvfStateCache () {
+  if (stateFile != NULL) Close ();
+}
+  
+void InvfStateCache::Open (char *filename) {
+  if (stateFile != NULL) Close();
+
+  // open the state file
+  char path[512];
+  sprintf (path, FILE_NAME_FORMAT ".%ld", get_basepath (), filename,
+	   ".invf.state", (long) getpid ());
+  if (!(stateFile = fopen (path, "wb+"))) {
+    Message ("Unable to create \"%s\"", path);
+    exit (1);
+  }
+  unlink (path); // file will be deleted after it is closed
+  
+  // reset the buffer
+  startNum = 0;
+  ClearCache();
+}
+
+void InvfStateCache::Close () {
+  if (stateFile == NULL) return;
+  fclose (stateFile);
+  stateFile = NULL;
+  startNum = 0;
+}
+
+InvfStateRec &InvfStateCache::GetRec (unsigned long num) {
+  // see if cached
+  if ((num >= startNum) && (num < startNum + ISR_SIZE))
+    return recCache[num-startNum];
+
+  // not cached, write out this lot of records and read in
+  fseek (stateFile, startNum*sizeof (InvfStateRec), SEEK_SET);
+  fwrite ((char *) recCache, sizeof (InvfStateRec), ISR_SIZE, stateFile);
+
+  // read in the new set of records
+  ClearCache ();
+  startNum = num - (num % ISR_SIZE);
+  fseek (stateFile, startNum*sizeof (InvfStateRec), SEEK_SET);
+  fread ((char *) recCache, sizeof (InvfStateRec), ISR_SIZE, stateFile);
+
+  return recCache[num-startNum];
+}
+
+
+
+static void ClearCharBuf (char *buf, unsigned long size) {
+  char *end = buf + size;
+  while (buf != end) *buf++ = 0;
+}
+
+static void ReadWordDict (char *filename) {
+  // read in the perfect hash function for the word dictionary
+  FILE *wordHashFile = open_file (filename, INVF_DICT_HASH_SUFFIX, "rb",
+				  MAGIC_HASH, MG_ABORT);
+  if (!(wordHashDict = read_perf_hash_data (wordHashFile))) {
+    FatalError (1, "Unable to read in hash data for word dictionary");
+  }
+  fclose (wordHashFile);
+}
+
+static void ReadTagDict (char *filename, invf_dict_header &_idh) {
+  // open the file
+  FILE *dictFile = open_file (filename, INVF_DICT_SUFFIX, "rb",
+			      MAGIC_STEM_BUILD, MG_ABORT);
+
+  // seek to the start of the tag dictionary
+  fseek (dictFile, _idh.tag_dict_start, SEEK_SET);
+  
+  unsigned long tagNum;
+  dict_el thisEl;
+  for (tagNum = 0; tagNum < _idh.tag_dict_size; tagNum++) {
+    thisEl.Read (dictFile);
+    tagMapDict[thisEl.el].tagNum = tagNum;
+  }
+  
+  fclose (dictFile);
+}
+
+static void ReadLevelFile (char *filename) {
+  FILE *f;
+  f = open_file (filename, INVF_LEVEL_SUFFIX, "rb",
+		 MAGIC_INVF_LEVELS, MG_ABORT);
+  ivfLevel.Read (f);
+  fclose (f);
+}
+
+void CheckIntOverflow (mg_ullong totalIBits, mg_ullong lastTotalIBits) {
+  if (totalIBits < lastTotalIBits) {
+    fprintf(stderr, "ERROR: The totalIBits counter (%d byte unsigned integer) has overflowed.\n", sizeof (mg_ullong));
+    if (sizeof (mg_ullong) < 8) {
+      fprintf(stderr, "       Try compiling with GCC to enable use of 8 bytes for this counter.\n");
+    }
+    fprintf(stderr, "       Build aborted.\n");
+    exit(1);
+  }
+}
+
+// assumes the inverted file state file has been opened
+static void InitInvfState (char *filename,
+			   invf_dict_header &_idh,
+			   InvfStateCache &_invfState,
+			   mg_ullong &totalIBits,
+			   bool wordLevelIndex) {
+  // read in the dictionary, setting inverted state information
+  FILE *dictFile = open_file (filename, INVF_DICT_SUFFIX, "rb",
+			      MAGIC_STEM_BUILD, MG_ABORT);
+
+  // seek to the start of the word dictionary
+  fseek (dictFile, _idh.word_dict_start, SEEK_SET);
+
+  // add the word entries
+  word_dict_el wordEl;
+  wordEl.SetNumLevels (_idh.num_levels);
+  unsigned long dictWordNum, p;
+  mg_ullong lastTotalIBits;
+  unsigned long N = _idh.num_frags;
+  for (dictWordNum=0; dictWordNum<_idh.word_dict_size; dictWordNum++) {
+    // lastTotalIBits is used to detect integer overflow
+    lastTotalIBits = totalIBits;
+
+    // read the next word and associated information
+    wordEl.Read (dictFile, _idh.num_levels);
+
+    // update the state record
+    p = wordEl.frag_occur;
+    InvfStateRec &wisr = _invfState.GetRec (dictWordNum);
+    wisr.start = totalIBits;
+    wisr.here = totalIBits;
+    wisr.B = BIO_Bblock_Init (N, p);
+    
+    // add the length of the fragment numbers
+    totalIBits += BIO_Bblock_Bound_b (N, p, wisr.B);
+
+    // if needed, add the length of the fragment frequency information
+    if (!wordLevelIndex)
+      totalIBits += BIO_Gamma_Bound (wordEl.freq, wordEl.frag_occur);
+
+    // align next byte
+#ifdef USE_LONG_LONG
+    totalIBits = (totalIBits + 7ull) & 0xfffffffffffffff8ull;
+#else
+    totalIBits = (totalIBits + 7ul) & 0xfffffff8ul;
+#endif
+
+    CheckIntOverflow (totalIBits, lastTotalIBits);
+  }
+
+  
+  // seek to the start of the tag dictionary
+  fseek (dictFile, _idh.tag_dict_start, SEEK_SET);
+
+  // add the tag entries
+  dict_el tagEl;
+  unsigned long dictTagNum;
+  N = _idh.num_frags;
+  for (dictTagNum=0; dictTagNum<_idh.tag_dict_size; dictTagNum++) {
+    // lastTotalIBits is used to detect integer overflow
+    lastTotalIBits = totalIBits;
+
+    // read the next tag and associated information
+    tagEl.Read (dictFile);
+
+    // update the state record
+    p = tagEl.frag_occur*2;
+    InvfStateRec &tisr = _invfState.GetRec (dictTagNum + _idh.word_dict_size);
+    tisr.start = totalIBits;
+    tisr.here = totalIBits;
+    tisr.B = BIO_Bblock_Init (N+p, p);
+    
+    // add the length of the fragment numbers (two numbers for each
+    // tag, one for start and one for end)
+    totalIBits += BIO_Bblock_Bound_b (N+p, p, tisr.B);
+
+    // align next byte
+#ifdef USE_LONG_LONG
+    totalIBits = (totalIBits + 7ull) & 0xfffffffffffffff8ull;
+#else
+    totalIBits = (totalIBits + 7ul) & 0xfffffff8ul;
+#endif
+
+    CheckIntOverflow (totalIBits, lastTotalIBits);
+  }
+
+  fclose (dictFile);
+}
+
+/*
+// assumes the chunk tag information has been placed in .first
+static void PrintChunkInfo (unsigned long chunkMem,
+			    unsigned long numChunkWords,
+			    unsigned long numChunkTags) {
+  static unsigned long chunksRead = 0;
+  chunksRead++;
+  cout << "Chunk Number: " << chunksRead << "\n";
+  cout << "numChunkDocs " << numDocsInChunk << "\n";
+  cout << "numChunkFrags " << numFragsInChunk << "\n";
+  cout << "mem " << chunkMem << "\n";
+  cout << "numWords " << numChunkWords << "\n";
+  cout << "numTags " << numChunkTags << "\n\n";
+
+  TagMapDict::iterator tagMapHere = tagMapDict.begin();
+  TagMapDict::iterator tagMapEnd = tagMapDict.end();
+  while (tagMapHere != tagMapEnd) {
+    unsigned long tagMapNum = (*tagMapHere).second.tagNum;
+    cout << (*tagMapHere).first << " " << tagMapNum << " "
+	 << bitPtrs.GetTagBitPtr(tagMapNum).here << "\n";
+    tagMapHere++;
+  }
+}
+*/
+
+void ReadChunk (invf_dict_header &_idh, bool wordLevelIndex) {
+  // reset globals
+  numChunkDocs = 0;
+  chunkStartFragNum = numFrags;
+
+  // read in information about this chunk
+  numDocsInChunk = chunkBuf.gamma_decode (NULL) - 1;
+  if (numDocsInChunk == 0)
+    FatalError (1, "The number of docs in the current chunk is 0");
+
+  numFragsInChunk = chunkBuf.gamma_decode (NULL) - 1;
+  unsigned long chunkMem = chunkBuf.gamma_decode (NULL) - 1;
+
+  if (chunkMem > ivfMemBufSize)
+    FatalError (1, "Chunk memory size is greater than maximum");
+  
+  unsigned long numChunkWords = chunkBuf.gamma_decode (NULL) - 1;
+  unsigned long numChunkTags = chunkBuf.gamma_decode (NULL) - 1;
+
+  
+  // reset stuff
+  ClearCharBuf (ivfMemBuf, ivfMemBufSize);
+  bitPtrs.ResetPtrs();  
+
+  // read in the entries in occurrence order storing the
+  // "chunkWordCount" in "start" and the "chunkFragCount"
+  // in "here"
+  unsigned long numOccur;
+  unsigned long wordNum;
+  for (numOccur=0; numOccur<numChunkWords; numOccur++) {
+    wordNum = occurConvert.TranslateWord (numOccur);
+    BitPtr &wordPtr = bitPtrs.GetWordBitPtr (wordNum);
+    wordPtr.start = chunkBuf.gamma_decode (NULL) - 1;
+    if (wordPtr.start >= 2)
+      wordPtr.here = chunkBuf.gamma_decode (NULL);
+    else wordPtr.here = wordPtr.start;
+  }
+  unsigned long tagNum;
+  for (numOccur=0; numOccur<numChunkTags; numOccur++) {
+    tagNum = occurConvert.TranslateTag (numOccur);
+    BitPtr &tagPtr = bitPtrs.GetTagBitPtr (tagNum);
+    // only chunkFragCount is encoded for tags
+    tagPtr.start = chunkBuf.gamma_decode (NULL) - 1;
+    tagPtr.here = tagPtr.start;
+  }
+
+  /*  PrintChunkInfo (chunkMem, numChunkWords, numChunkTags);*/
+  
+  // create the bit ptrs in dictionary order
+  unsigned long totalIBits = 0; // only dealing with memory
+  unsigned long chunkWordCount, chunkFragCount;
+  for (wordNum=0; wordNum<_idh.word_dict_size; wordNum++) {
+    BitPtr &wordPtr = bitPtrs.GetWordBitPtr (wordNum);
+    chunkWordCount = wordPtr.start;
+    chunkFragCount = wordPtr.here;
+    wordPtr.start = totalIBits;
+    wordPtr.here = totalIBits;
+    wordPtr.lastFragNum = chunkStartFragNum;
+    wordPtr.lgB = 0;
+    if (chunkWordCount > 0) {
+      wordPtr.lgB = floorlog_2 (BIO_Bblock_Init_W (numFragsInChunk,
+						   chunkFragCount));
+      totalIBits += BIO_Bblock_Bound (numFragsInChunk, chunkFragCount);
+      // use unary encoding for memory buffer encoding of fragment freq
+      if (!wordLevelIndex) {
+	totalIBits += chunkWordCount;
+      }
+    }
+  }
+  for (tagNum=0; tagNum<_idh.tag_dict_size; tagNum++) {
+    BitPtr &tagPtr = bitPtrs.GetTagBitPtr (tagNum);
+    chunkFragCount = tagPtr.here;
+    tagPtr.start = totalIBits;
+    tagPtr.here = totalIBits;
+    tagPtr.lastFragNum = chunkStartFragNum;
+    tagPtr.lgB = 0;
+    if (chunkFragCount > 0) {
+      unsigned long pTag = chunkFragCount*2;
+      tagPtr.lgB = floorlog_2 (BIO_Bblock_Init_W (numFragsInChunk+pTag,
+						  pTag));
+      unsigned long bLen = BIO_Bblock_Bound (numFragsInChunk+pTag,
+					     pTag);
+//        cout << tagNum + _idh.word_dict_size << " ";
+//        cout << "numFrags: " << numFragsInChunk
+//    	   << " chunkFragCount: " << chunkFragCount
+//    	   << " B: " << 1 << tagPtr.lgB
+//    	   << " blen: " << blen << "\n";
+      totalIBits += bLen;
+    }
+  }
+  bitPtrs.GetEndStart() = totalIBits;
+  bitPtrs.GetEndHere() = totalIBits;
+
+  if ((totalIBits + 7ul) >> 3ul > chunkMem) {
+    cerr << "totalIBits: " << totalIBits << "\n";
+    cerr << "bytes: " << ((totalIBits + 7ul) >> 3ul) << "\n";
+    cerr << "chunkMem: " << chunkMem << "\n";
+    FatalError (1, "Pointers exceed buffer size");
+  }
+}
+
+
+
+
+int init_ivf_2 (const TagInfo &/*tagInfo*/, char *filename) {
+  // read in compressed dictionary header
+  FILE *dictFile = open_file (filename, INVF_DICT_SUFFIX, "rb",
+			      MAGIC_STEM_BUILD, MG_ABORT);
+  idh.Read (dictFile);
+  fclose (dictFile);
+
+  // set the size of the bit ptrs
+  bitPtrs.SetSize (idh.word_dict_size, idh.tag_dict_size);
+
+  // open the chunk file and read in the maximum memory needed
+  // for the inverted memory buffer
+  chunkFile = open_file (filename, INVF_CHUNK_SUFFIX, "rb",
+			 MAGIC_CHUNK, MG_ABORT);
+  ReadUL (chunkFile, ivfMemBufSize);
+  chunkBuf.attachFile (chunkFile);
+
+  // allocate memory for the inverted buffer
+  ivfMemBuf = new char [ivfMemBufSize];
+  ClearCharBuf (ivfMemBuf, ivfMemBufSize);
+
+  // read in the word dictionary
+  ReadWordDict (filename);
+
+  // read in the tag dictionary
+  ReadTagDict (filename, idh);
+
+  // read in the level information
+  ReadLevelFile (filename);
+  bool wordLevelIndex = ivfLevel.indexLevel.empty();
+  
+  // set up the translation table file
+  occurConvert.Open (filename, idh.word_dict_size, idh.tag_dict_size);
+
+  // reset some globals
+  numDocs = 0;
+  numChunkDocs = 0;
+  numDocsInChunk = 0;
+  numFrags = 0;
+  numFragsInChunk = 0;
+  chunkStartFragNum = 0;
+
+  strcpy (collectFilename, filename);
+  
+  
+  // create the inverted file
+  mg_ullong totalIBits = 0;
+  FILE *invfFile = create_file (filename, INVF_SUFFIX, "wb",
+				MAGIC_INVF, MG_ABORT);
+  totalIBits += sizeof (unsigned long) * 8; // magic number
+  totalIBits += 8 * 200;                    // 200 byte gap -- why??????
+  fclose (invfFile);
+
+  // init the inverted file state cache
+  invfState.Open (filename);
+  InitInvfState (filename, idh, invfState, totalIBits, wordLevelIndex);
+
+  return COMPALLOK;
+}
+
+static void CloseTextTag (IP2TagInfo &tInfo, const UCArray &/*tagName*/) {
+  if (!tInfo.inTag) return;
+
+    // add this tag to the inverted list
+  BitPtr &tagBitPtr = bitPtrs.GetTagBitPtr (tInfo.tagNum);
+  unsigned long endFrag = numFrags;
+  int b = 1 << tagBitPtr.lgB;
+
+  /*
+  cout << (tInfo.tagNum+idh.word_dict_size) << " \"<" << tagName << ">\" "
+       << tInfo.startFrag << " " << endFrag << "\n";
+  */
+    
+  mems_bitio_buffer buffer ((u_char *) ivfMemBuf, tagBitPtr.here);
+  buffer.bblock_encode (tInfo.startFrag - tagBitPtr.lastFragNum + 1,
+			b, NULL);
+  buffer.bblock_encode (endFrag - tInfo.startFrag + 1, b, NULL);
+  tagBitPtr.lastFragNum = endFrag;
+  tagBitPtr.here = buffer.position();
+  buffer.encodeDone();
+  
+  // check for buffer overrun
+  bitPtrs.CheckTagBufOverrun (tInfo.tagNum);
+  
+  // reset information about this tag
+  tInfo.inTag = false;
+  tInfo.startFrag = 0;
+}
+
+static void ProcessOpenTag (const TextEl &el, bool &inFrag) {
+  // close tag if open
+  IP2TagInfo &tInfo = tagMapDict[el.tagName];
+  if (tInfo.inTag) CloseTextTag (tInfo, el.tagName);
+
+  // open this tag
+  tInfo.inTag = true;
+  tInfo.startFrag = numFrags;
+
+  // check for start of next fragment
+  bool wordLevelIndex = ivfLevel.indexLevel.empty();
+  if (!wordLevelIndex && el.tagName == ivfLevel.indexLevel) {
+    numFrags++;
+    inFrag = true;
+  }
+}
+
+static void ProcessCloseTag (const TextEl &el, bool &inFrag) {
+  // check for end of fragment
+  bool wordLevelIndex = ivfLevel.indexLevel.empty();
+  if (!wordLevelIndex && el.tagName == ivfLevel.indexLevel) {
+    inFrag = false;
+  }
+
+  IP2TagInfo &tInfo = tagMapDict[el.tagName];
+  CloseTextTag (tInfo, el.tagName);
+}
+
+static void ProcessText (const TextEl &el, bool &inFrag) {
+  // make sure this text is to be indexed
+  bool wordLevelIndex = ivfLevel.indexLevel.empty();
+  if (!wordLevelIndex && !inFrag) return;
+
+  const unsigned char *textHere = el.text.begin();
+  const unsigned char *textEnd = el.text.end() - 1;
+  unsigned char mgWord[MAXSTEMLEN + 1];
+  
+  if (!inaword (textHere, textEnd))
+    ParseNonindexWord (textHere, textEnd);
+
+  
+  // Alternately parse off words and non-words from the input
+
+  while (textHere <= textEnd) {
+    textHere = ParseIndexMGWord (textHere, textEnd, mgWord);
+    textHere = ParseNonindexWord (textHere, textEnd);
+
+    if (mgWord[0] > 0) {
+      if (wordLevelIndex) numFrags++;
+
+      unsigned long wordNum = perf_hash (wordHashDict, mgWord);
+
+      /*
+      cout << wordNum << " \"";
+      cout.write (mgWord+1, *mgWord);
+      cout << "\" " << numFrags << "\n";
+      */
+      
+      // add this word to the inverted list
+      BitPtr &wordBitPtr = bitPtrs.GetWordBitPtr (wordNum);
+      unsigned long fragNum = numFrags;
+      int b = 1 << wordBitPtr.lgB;
+  
+      mems_bitio_buffer buffer ((u_char *) ivfMemBuf, wordBitPtr.here);
+
+      // note: this assumes that fragments don't carry over between
+      // chunks (which they don't because all tags are closed at the
+      // end of each document and chunks are based on document
+      // boundaries), i.e. the first fragment number must be greater
+      // than the starting fragment number of the chunk.
+      if (fragNum > wordBitPtr.lastFragNum) {
+	buffer.bblock_encode ((fragNum - wordBitPtr.lastFragNum - 1) + 1,
+			      b, NULL);
+	if (!wordLevelIndex) buffer.encodeBit (1); // freq = 1
+	
+      } else if (!wordLevelIndex) {
+	// add one to the frequency count for this word
+	buffer.seek (buffer.position()-1);
+	buffer.encodeBit (0); // unary encoding -- last = 1
+	buffer.encodeBit (1);
+      }
+      
+      wordBitPtr.lastFragNum = fragNum;
+      wordBitPtr.here = buffer.position();
+      buffer.encodeDone();
+      
+      // check for buffer overrun
+      bitPtrs.CheckWordBufOverrun (wordNum);
+    }
+  }
+}
+
+// combine the in memory inverted buffer with the disk
+// based inverted file
+static void DiskMerge (char *filename) {
+  bool wordLevelIndex = ivfLevel.indexLevel.empty();
+
+      // make sure we have something to process
+  if (numChunkDocs <= 0) return;
+    
+  // open the inverted file
+  FILE *invfFile = open_file (filename, INVF_SUFFIX, "rb+",
+			      MAGIC_INVF, MG_ABORT);
+  random_bitio_buffer invfOutBuf (invfFile);
+
+  // set up to decode the entries in memory
+  mems_bitio_buffer memInBuf ((u_char *) ivfMemBuf, 0);
+
+  // write out the word information
+  unsigned long wordNum;
+  int b;
+  unsigned long currFragNum;
+  unsigned long delta;
+  unsigned long currFreq;
+  for (wordNum=0; wordNum<idh.word_dict_size; wordNum++) {
+    // go to the end of the last inverted file entry
+    InvfStateRec &wordDiskState = invfState.GetRec (wordNum);
+    invfOutBuf.SEEK_X (wordDiskState.here);
+
+    // go to the start of the inverted chunk info in memory
+    BitPtr &wordBitPtr = bitPtrs.GetWordBitPtr (wordNum);
+    memInBuf.seek(wordBitPtr.start);
+
+    // decode each entry and re-write to disk
+    currFragNum = chunkStartFragNum;
+    while (memInBuf.position() < wordBitPtr.here) {
+      // decode word entry
+      b = 1 << wordBitPtr.lgB;
+      delta = memInBuf.bblock_decode (b, NULL);
+      currFragNum += delta;
+      if (!wordLevelIndex) currFreq = memInBuf.unary_decode (NULL);
+      else currFreq = 1;
+
+      // recode on disk
+      invfOutBuf.bblock_encode (currFragNum-wordDiskState.lastFragNum,
+				wordDiskState.B, NULL);
+      if (!wordLevelIndex) invfOutBuf.gamma_encode (currFreq, NULL);
+      wordDiskState.lastFragNum = currFragNum;
+    }
+
+    wordDiskState.here = invfOutBuf.TELL_X();
+  }
+
+  // write out the tag information
+  unsigned long tagNum;
+  unsigned long currTagStart;
+  unsigned long currTagEnd;
+  for (tagNum=0; tagNum<idh.tag_dict_size; tagNum++) {
+    // go to the end of the last inverted file entry
+    InvfStateRec &tagDiskState = invfState.GetRec (tagNum+idh.word_dict_size);
+    invfOutBuf.SEEK_X (tagDiskState.here);
+
+    // go to the start of the inverted chunk info in memory
+    BitPtr &tagBitPtr = bitPtrs.GetTagBitPtr (tagNum);
+    memInBuf.seek(tagBitPtr.start);
+
+    // decode each entry and re-write to disk
+    currTagEnd = chunkStartFragNum;
+    while (memInBuf.position() < tagBitPtr.here) {
+      // decode tag entry
+      b = 1 << tagBitPtr.lgB;
+      delta = memInBuf.bblock_decode (b, NULL) - 1;
+      currTagStart = currTagEnd + delta;
+      delta = memInBuf.bblock_decode (b, NULL) - 1;
+      currTagEnd = currTagStart + delta;
+
+      // recode on disk
+      invfOutBuf.bblock_encode (currTagStart-tagDiskState.lastFragNum+1,
+				tagDiskState.B, NULL);
+      invfOutBuf.bblock_encode (currTagEnd-currTagStart+1,
+				tagDiskState.B, NULL);
+
+      tagDiskState.lastFragNum = currTagEnd;
+    }
+
+    tagDiskState.here = invfOutBuf.TELL_X();
+  }
+
+  memInBuf.done();
+
+  invfOutBuf.encodeDone();
+  fclose (invfFile);
+}
+
+
+int process_ivf_2 (const TagInfo &/*tagInfo*/, const TextElArray &doc) {
+  bool wordLevelIndex = ivfLevel.indexLevel.empty();
+  bool inFrag = false;
+  if (wordLevelIndex) inFrag = true; // unconditional
+  
+  // get next chunk information if need to. the chunk information
+  // is needed before the first document is processed
+  if (numChunkDocs >= numDocsInChunk) ReadChunk (idh, wordLevelIndex);
+
+  // process each text element
+  TextElArray::const_iterator here = doc.begin();
+  TextElArray::const_iterator end = doc.end();
+  while (here != end) {
+    // process this element
+    if ((*here).elType == OpenTagE) ProcessOpenTag (*here, inFrag);
+    else if ((*here).elType == CloseTagE) ProcessCloseTag (*here, inFrag);
+    else ProcessText (*here, inFrag);
+    
+    here++;
+  }
+
+  // close off any unclosed tags
+  TagMapDict::iterator tdHere = tagMapDict.begin();
+  TagMapDict::iterator tdEnd = tagMapDict.end();
+  while (tdHere != tdEnd) {
+    CloseTextTag ((*tdHere).second, (*tdHere).first);
+    tdHere++;
+  }
+  
+  // we've processed one more document
+  numDocs++;
+  numChunkDocs++;
+
+  // merge the memory based inverted file with the one on
+  // disk if this is the end of this chunk
+  if (numChunkDocs >= numDocsInChunk) DiskMerge (collectFilename);
+  
+  return COMPALLOK;
+}
+
+
+static void CondenseInvfFile (char *filename, unsigned long &bytesOutput) {
+  FILE *inInvfFile = open_file (filename, INVF_SUFFIX, "rb",
+				MAGIC_INVF, MG_ABORT);
+  FILE *outInvfFile = open_file (filename, INVF_SUFFIX, "rb+",
+				 MAGIC_INVF, MG_ABORT);
+
+  // skip the magic number
+  fseek (outInvfFile, sizeof (unsigned long), SEEK_SET);
+  
+  // write the inverted file header -- use defaults for most things
+  invf_file_header ifh;
+  ifh.no_of_words = idh.word_dict_size;
+  ifh.no_of_tags = idh.tag_dict_size;
+  ifh.word_level_index = (ivfLevel.indexLevel.empty()) ? 1 : 0;
+  ifh.Write (outInvfFile);
+
+  bytesOutput = ftell (outInvfFile);
+
+  // process each meaningful byte in the file
+  unsigned long numEntries = ifh.no_of_words + ifh.no_of_tags;
+  unsigned long entryNum;
+  mg_ullong lastStart = 0;
+  for (entryNum = 0; entryNum < numEntries; entryNum++) {
+    InvfStateRec &stateRec = invfState.GetRec (entryNum);
+
+    // overrun check
+    if (stateRec.start < lastStart)
+      FatalError (1, "Inverted file Buffer overrun");
+    lastStart = stateRec.start;
+    
+    unsigned long oldEntryStart = stateRec.start >> 3;
+    unsigned long oldEntryStartOver = stateRec.start & 7; // should be 0
+    unsigned long oldEntryEnd = (stateRec.here + 7) >> 3;  // byte after end
+    unsigned long oldEntryEndOver = stateRec.here & 7;
+
+    fseek (inInvfFile, oldEntryStart, SEEK_SET);
+
+    stateRec.here -= stateRec.start;
+    stateRec.start = bytesOutput * 8 + oldEntryStartOver;
+    stateRec.here += stateRec.start;
+    while (oldEntryStart < oldEntryEnd) {
+      unsigned char c = getc (inInvfFile);
+      if (oldEntryStart == oldEntryEnd - 1) {
+	u_char ands[8] =
+	{0xff, 0x80, 0xc0, 0xe0, 0xf0, 0xf8, 0xfc, 0xfe};
+	c &= ands[oldEntryEndOver];
+      }
+      putc (c, outInvfFile);
+      bytesOutput++;
+      oldEntryStart++;
+    }
+  }  
+
+  fclose (inInvfFile);
+
+#ifdef __WIN32__
+  if (!(_chsize (_fileno (outInvfFile), bytesOutput)))
+    Message ("Could not truncate invf.");
+#else
+  ftruncate (fileno (outInvfFile), bytesOutput);
+#endif
+
+  fclose (outInvfFile);
+}
+
+static void OutputInvfIdx (char *filename, unsigned long invfNumBytes) {
+  FILE *invfIdxFile = create_file (filename, INVF_IDX_SUFFIX, "wb",
+				   MAGIC_INVI, MG_ABORT);
+
+  // process each meaningful byte in the file
+  unsigned long numEntries = idh.word_dict_size + idh.tag_dict_size;
+  unsigned long entryNum;
+  for (entryNum = 0; entryNum < numEntries; entryNum++) {
+    InvfStateRec &stateRec = invfState.GetRec (entryNum);
+
+    // assumes that inverted entries start at beginning of each byte
+    if (!WriteUL (invfIdxFile, (stateRec.start >> 3))) break;
+  }
+
+  WriteUL (invfIdxFile, invfNumBytes);
+
+  fclose (invfIdxFile);
+}
+
+
+int done_ivf_2 (const TagInfo &/*tagInfo*/, char *filename) {
+  // close most open files
+  if (chunkFile != NULL) {
+    chunkBuf.done();
+    fclose (chunkFile);
+    chunkFile = NULL;
+  }
+  occurConvert.Close();
+  
+  // free allocated memory
+  bitPtrs.Clear();
+  if (ivfMemBuf != NULL) { delete [] ivfMemBuf; ivfMemBuf = NULL; }
+  free_perf_hash (wordHashDict);
+  wordHashDict = NULL;
+  tagMapDict.erase (tagMapDict.begin(), tagMapDict.end());
+
+  // condense the inverted file and truncate it
+  // this function also writes out the inverted header
+  unsigned long invfNumBytes = 0;
+  CondenseInvfFile (filename, invfNumBytes);
+
+  OutputInvfIdx (filename, invfNumBytes);
+
+  // close the rest of the open files
+  invfState.Close ();
+  
+  return COMPALLOK;
+}
Index: /main/tags/2.25/gsdl/src/mgpp/text/locallib.cpp
===================================================================
--- /main/tags/2.25/gsdl/src/mgpp/text/locallib.cpp	(revision 21064)
+++ /main/tags/2.25/gsdl/src/mgpp/text/locallib.cpp	(revision 21064)
@@ -0,0 +1,244 @@
+/**************************************************************************
+ *
+ * locallib.cpp -- Misc functions
+ * Copyright (C) 1994  Gary Eddy, Alistair Moffat and Neil Sharman
+ *
+ * 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.
+ *
+ * $Id$
+ *
+ **************************************************************************/
+
+#include "sysfuncs.h"
+
+#include "memlib.h"
+#include "bitio_gen.h"
+#include "huffman.h"
+#include "netorder.h"  /* [RPAP - Jan 97: Endian Ordering] */
+
+#include "locallib.h"
+#include "text.h"
+
+/*
+   $Log$
+   Revision 1.1  2000/01/14 02:26:08  sjboddie
+   Rodgers new C++ mg
+
+   Revision 1.1  1999/10/11 02:57:43  cs025
+   Base install of MG-PP
+
+   Revision 1.1  1999/08/10 21:18:02  sjboddie
+   renamed mg-1.3d directory mg
+
+   Revision 1.1  1998/11/17 09:34:49  rjmcnab
+   *** empty log message ***
+
+   * Revision 1.3  1994/10/20  03:56:51  tes
+   * I have rewritten the boolean query optimiser and abstracted out the
+   * components of the boolean query.
+   *
+   * Revision 1.2  1994/09/20  04:41:38  tes
+   * For version 1.1
+   *
+ */
+
+
+int 
+vecentropy (int *A, int n)
+{
+  int total = 0, i;
+  double bits = 0.0;
+
+  for (i = 0; i < n; i++)
+    total += A[i];
+  for (i = 0; i < n; i++)
+    if (A[i])
+      bits += A[i] * log2 (1.0 * total / A[i]);
+  return ((int) (bits + 0.9999));
+
+}
+
+static void 
+siftdown (int *A, int i, int n)
+{
+  int ms, t;
+
+  while (2 * i + 1 <= n - 1)
+    {
+      if (2 * i + 1 == n - 1 || A[2 * i + 1] < A[2 * i + 2])
+	ms = 2 * i + 1;
+      else
+	ms = 2 * i + 2;
+      if (A[i] > A[ms])
+	{
+	  t = A[i];
+	  A[i] = A[ms];
+	  A[ms] = t;
+	}
+      i = ms;
+    }
+}
+
+static void 
+buildheap (int *A, int n)
+{
+  int i;
+  for (i = n / 2 - 1; i >= 0; i--)
+    siftdown (A, i, n);
+}
+
+int 
+huffcodebits (unsigned long *A, int n)
+{
+  int i, j, tot = 0, bits = 0, v1, v2, *B;
+
+  B = (int *) Xmalloc (n * sizeof (int));
+  j = 0;
+  for (i = 0; i < n; i++)
+    {
+      if (A[i])
+	{
+	  tot += (B[j++] = A[i]);
+	}
+    }
+  n = j;
+
+  if (n == 0 || tot == 0)
+    return (0);
+
+  buildheap (B, n);
+  while (n > 1)
+    {
+      v1 = B[0];
+      B[0] = B[n - 1];
+      n--;
+      siftdown (B, 0, n);
+      v2 = B[0];
+      B[0] = v1 + v2;
+      siftdown (B, 0, n);
+      bits += v1 + v2;
+    }
+  Xfree (B);
+  return (bits);
+}
+
+
+int 
+modelbits (unsigned long *A, int n)
+{
+  int i, bits = 0, last, N = 0;
+
+  last = -1;
+  for (i = 0; i < n; i++)
+    {
+      if (A[i])
+	{
+	  bits += BIO_Gamma_Length (i - last) + BIO_Gamma_Length (A[i]);
+	  last = i;
+	  N++;
+	}
+    }
+  if (N == 0)
+    return (0);
+  bits += BIO_Gamma_Length (N);
+  return (bits);
+}
+
+
+
+
+
+/* Find the next prime number larger than p */
+int 
+prime (int p)
+{
+  int limit;
+  p += (p & 1) + 1;
+  limit = (int) sqrt ((double) p) + 1;
+  do
+    {
+      int j;
+      while (limit * limit < p)
+	limit++;
+      for (j = 3; j <= limit && p % j; j += 2)
+	;			/* NULLBODY */
+      if (j > limit)
+	break;
+      p += 2;
+    }
+  while (1);
+  return (p);
+}
+
+
+
+int Read_cdh (FILE * f, compression_dict_header * cdh, u_long * /*mem*/,
+	      u_long * disk) {
+  if (disk)
+    (*disk) += sizeof (*cdh);
+
+  /* [RPAP - Jan 97: Endian Ordering] */
+  if (fread (cdh, sizeof (*cdh), 1, f) == 1)
+    {
+      int i;
+      NTOHUL(cdh->dict_type);
+      NTOHUL(cdh->novel_method);
+      for (i = 0; i < TEXT_PARAMS; i++)
+	NTOHUL(cdh->params[i]);
+      NTOHUL(cdh->num_words[0]);
+      NTOHUL(cdh->num_words[1]);
+      NTOHUL(cdh->num_word_chars[0]);
+      NTOHUL(cdh->num_word_chars[1]);
+      NTOHUL(cdh->lookback);
+      return 0;
+    }
+  else
+    return -1;
+}
+
+
+int 
+Read_cfh (FILE * f, comp_frags_header * cfh, u_long * mem, u_long * disk)
+{
+  int i;  /* [RPAP - Jan 97: Endian Ordering] */
+
+  if (Read_Huffman_Data (f, &cfh->hd, mem, disk) == -1)
+    return -1;
+  if (fread (&cfh->uncompressed_size,
+	     sizeof (cfh->uncompressed_size), 1, f) != 1)
+    return -1;
+  NTOHUL(cfh->uncompressed_size);  /* [RPAP - Jan 97: Endian Ordering] */
+
+  if (disk)
+    (*disk) += sizeof (cfh->uncompressed_size);
+
+  bzero ((char *) cfh->huff_words_size, sizeof (cfh->huff_words_size));
+
+  if ((int)fread (cfh->huff_words_size + cfh->hd.mincodelen,
+	     sizeof (*cfh->huff_words_size),
+	     cfh->hd.maxcodelen - cfh->hd.mincodelen + 1, f) !=
+      cfh->hd.maxcodelen - cfh->hd.mincodelen + 1)
+    return -1;
+
+  /* [RPAP - Jan 97: Endian Ordering] */
+  for (i = cfh->hd.mincodelen; i < cfh->hd.maxcodelen + 1; i++)
+    NTOHUL(cfh->huff_words_size[i]);
+
+  if (disk)
+    (*disk) += sizeof (*cfh->huff_words_size) *
+      (cfh->hd.maxcodelen - cfh->hd.mincodelen + 1);
+  return 0;
+}
+
Index: /main/tags/2.25/gsdl/src/mgpp/text/locallib.h
===================================================================
--- /main/tags/2.25/gsdl/src/mgpp/text/locallib.h	(revision 21064)
+++ /main/tags/2.25/gsdl/src/mgpp/text/locallib.h	(revision 21064)
@@ -0,0 +1,47 @@
+/**************************************************************************
+ *
+ * locallib.h -- Misc functions
+ * Copyright (C) 1994  Gary Eddy, Alistair Moffat and Neil Sharman
+ *
+ * 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.
+ *
+ * $Id$
+ *
+ **************************************************************************/
+
+#ifndef LOCALLIB_H
+#define LOCALLIB_H
+
+#include "sysfuncs.h"
+
+#include "text.h"
+
+#define NUMOF(a) (sizeof(a)/sizeof((a)[0]))
+
+int vecentropy (int *A, int n);
+
+int huffcodebits (unsigned long *A, int n);
+
+int modelbits (unsigned long *A, int n);
+
+int prime (int p);
+
+
+int Read_cdh (FILE * f, compression_dict_header * cdh, u_long * mem, u_long * disk);
+
+int Read_cfh (FILE * f, comp_frags_header * cfh, u_long * mem, u_long * disk);
+
+
+#endif
Index: /main/tags/2.25/gsdl/src/mgpp/text/mg.h
===================================================================
--- /main/tags/2.25/gsdl/src/mgpp/text/mg.h	(revision 21064)
+++ /main/tags/2.25/gsdl/src/mgpp/text/mg.h	(revision 21064)
@@ -0,0 +1,42 @@
+/**************************************************************************
+ *
+ * mg.h -- General header file
+ * Copyright (C) 1994  Neil Sharman, Alistair Moffat and Lachlan Andrew
+ *
+ * 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.
+ *
+ * $Id$
+ *
+ **************************************************************************/
+
+
+#ifndef H_MG
+#define H_MG
+
+
+#define COMPALLOK	(0)
+#define COMPERROR	(-1)
+
+#define MAXSTRING       3000000
+#define BUFFERSIZE      (MAXSTRING+30000)
+
+
+
+
+#define	MAXLN	65536
+#define WORDS           1
+#define NONWORDS        0
+
+#endif
Index: /main/tags/2.25/gsdl/src/mgpp/text/mg.special.cpp
===================================================================
--- /main/tags/2.25/gsdl/src/mgpp/text/mg.special.cpp	(revision 21064)
+++ /main/tags/2.25/gsdl/src/mgpp/text/mg.special.cpp	(revision 21064)
@@ -0,0 +1,81 @@
+/**************************************************************************
+ *
+ * mg.special.cpp -- Special pass for mg_passes
+ * Copyright (C) 1994  Neil Sharman
+ *
+ * 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.
+ *
+ * $Id$
+ *
+ **************************************************************************/
+
+#include "sysfuncs.h"
+
+#include "mg.h"
+#include "build.h"
+
+
+/*
+   $Log$
+   Revision 1.1  2000/01/14 02:26:10  sjboddie
+   Rodgers new C++ mg
+
+   Revision 1.1  1999/10/11 02:57:45  cs025
+   Base install of MG-PP
+
+   Revision 1.1  1999/08/10 21:18:03  sjboddie
+   renamed mg-1.3d directory mg
+
+   Revision 1.1  1998/11/17 09:34:51  rjmcnab
+   *** empty log message ***
+
+   * Revision 1.3  1994/10/20  03:56:53  tes
+   * I have rewritten the boolean query optimiser and abstracted out the
+   * components of the boolean query.
+   *
+   * Revision 1.2  1994/09/20  04:41:44  tes
+   * For version 1.1
+   *
+ */
+
+
+int init_special (const TagInfo &/*tagInfo*/, char * /*FileName*/) {
+  return COMPALLOK;
+}
+
+int process_special (const TagInfo &/*tagInfo*/, const TextElArray &doc) {
+  // print out the document
+  TextElArray::const_iterator here = doc.begin();
+  TextElArray::const_iterator end = doc.end();
+  while (here != end) {
+    if ((*here).elType == OpenTagE) {
+      cout << "** OpenTag  \"" << (*here).tagName << "\"\tText \""
+	   << (*here).text << "\"\n"; 
+    } else if ((*here).elType == CloseTagE) {
+      cout << "** CloseTag \"" << (*here).tagName << "\"\tText \""
+	   << (*here).text << "\"\n";
+    } else {
+      cout << "** Text     \"" << (*here).text << "\"\n";
+    }
+    
+    here++;
+  }
+  
+  return COMPALLOK;
+}
+
+int done_special (const TagInfo &/*tagInfo*/, char * /*FileName*/) {
+  return COMPALLOK;
+}
Index: /main/tags/2.25/gsdl/src/mgpp/text/mg_compression_dict.1
===================================================================
--- /main/tags/2.25/gsdl/src/mgpp/text/mg_compression_dict.1	(revision 21064)
+++ /main/tags/2.25/gsdl/src/mgpp/text/mg_compression_dict.1	(revision 21064)
@@ -0,0 +1,189 @@
+.\"------------------------------------------------------------
+.\" Id - set Rv,revision, and Dt, Date using rcs-Id tag.
+.de Id
+.ds Rv \\$3
+.ds Dt \\$4
+..
+.Id $Id$
+.\"------------------------------------------------------------
+.TH mg_compression_dict 1 \*(Dt CITRI
+.SH NAME
+mg_compression_dict \- build a compression dictionary.
+.SH SYNOPSIS
+.B mg_compression_dict
+[
+.B \-h
+]
+[
+.BR \-C " |"
+.BR \-P " |"
+.B  \-S
+]
+.if n .ti +9n
+[
+.BR \-0 " |"
+.BR \-1 " |"
+.BR \-2 " |"
+.B  \-3
+]
+[
+.BR \-H " |"
+.BR \-B " |"
+.BR \-D " |"
+.BR \-Y " |"
+]
+.if n .ti +9n
+.if t .ti +.5i
+[
+.BI \-l " lookback"
+]
+[
+.BI \-k " mem"
+]
+[
+.BI \-d " directory"
+]
+.BI \-f " name"
+.SH DESCRIPTION
+.B mg_compression_dict
+builds a compression dictionary based on the statistics gathered
+during the first pass over the text.  The options to the program are
+mainly concerned with limiting the amount of memory the dictionary
+will use and with how the text compressor will cope with any novel
+words found during the compression phase.
+.SH OPTIONS
+Options may appear in any order.
+.TP "\w'\fB\-d\fP \fIdirectory\fP'u+2n"
+.B \-h
+This displays a usage line on
+.IR stderr .
+.TP
+.B \-C
+Build a complete dictionary from the statistics file.  If during the
+text compression phase a novel word is found, then the compressor will
+produce an error message and stop.
+.TP
+.B \-P
+Build a partial dictionary from the statistics file.  This dictionary
+assumes that the statistics file are based on the entire text.  The
+statistics of words not includes in the dictionary are used to
+calculate the escape probability.  If novel words are being coded
+character by character, then there may not be a Huffman code for every
+possible character.  This means that the compressor may fail if a novel
+word contains a novel character.
+.TP
+.B \-S
+Build a seed dictionary from the statistics file.  This dictionary
+assumes that the statistics file is based on only a portion of the
+text to be compressed.  The probability of a novel word is based on the
+number of words that have only occurred once.  If novel words are being
+coded character by character, then the Huffman codes for characters are
+based on the frequency of characters in the dictionary.
+.TP
+.B \-0
+All words from the statistics file are included in the built
+dictionary.
+.TP
+.B \-1
+Words are included in the dictionary until the dictionary reaches the
+desired size.  Words are selected for the dictionary based on the order
+they occurred in the source text.
+.TP
+.B \-2
+Words are included in the dictionary until the dictionary reaches the
+desired size.  The most frequent words are included in the dictionary
+first; where there is a tie for frequency, the shortest word is
+included first.
+.TP
+.B \-3
+Words are included in the dictionary until the dictionary reaches the
+desired size.  The most frequent words are included in the dictionary
+first; where there is a tie for frequency, the shortest word is
+included first.  Words are the shuffled back and forth between the
+`keep' and `discard' lists to find the `optimal' set of words that
+should be in the dictionary.
+.TP
+.B \-H
+This specifies that novel words will be coded character by character
+using Huffman codes.
+.TP
+.B \-B
+This specifies that an auxiliary dictionary will be built by the
+compressor.  Each novel word found will be placed at the end of the
+auxiliary dictionary.  Novel words will be coded in the compressed text
+using binary codes.  The binary code represents their occurrence
+position in the auxiliary dictionary.
+.TP
+.B \-D
+This specifies that an auxiliary dictionary will be built by the
+compressor.  Each novel word found will be placed at the end of the
+auxiliary dictionary.  Novel words will be coded in the compressed text
+using delta codes.  The delta code represents their occurrence position
+in the auxiliary dictionary.
+.TP
+.B \-Y
+This specifies that an auxiliary dictionary will be built by the
+compressor.  Each novel word found will be placed at the end of the
+auxiliary dictionary.  Novel words will be coded in the compressed text
+using a combination of gamma and binary codes.  The code represents
+their occurrence position in the auxiliary dictionary.  This generally
+produces better compression than
+.B \-B
+or
+.BR \-D .
+.TP
+.BI \-l " lookback"
+The generated dictionary is designed to be front coded when it is
+loaded into memory.  Under normal circumstances, a front-coded
+dictionary would require scanning from the beginning in order to find
+any particular word.  However, every
+.I lookback
+words in the dictionary, the whole word is stored and a pointer to that
+word maintained.  E.g., if
+.I lookback
+is 4, then every fourth word is stored in its entirety.
+.TP
+.BI \-k " mem"
+This limits the amount of memory to use for the generated
+dictionary.  Words are selected for the dictionary based of the text
+statistics, and whether
+.BR \-0 , " \-1" , " \-2"
+or
+.B \-3
+is specified.  The memory is calculated assuming a lookback of 0,
+irrespective of what actual lookback is specified.  This means that if
+a non-zero lookback is given, the dictionary will actually occupy
+less space than specified by
+.BR \-k .
+.TP
+.BI \-d " directory"
+This specifies the directory where the document collection can be found.
+.TP
+.BI \-f " name"
+This specifies the base name of the document collection.
+.SH ENVIRONMENT
+.TP "\w'\fBMGDATA\fP'u+2n"
+.SB MGDATA
+If this environment variable exists, then its value is used as the
+default directory where the mg
+collection files are.  If this variable does not exist, then the
+directory \*(lq\fB.\fP\*(rq is used by default.  The command line
+option
+.BI \-d " directory"
+overrides the directory in
+.BR MGDATA .
+.SH FILES
+.TP 20
+.B *.text.stats
+Statistics about the source text.
+.TP
+.B *.text.dict
+Compression dictionary for the source text.
+.SH "SEE ALSO"
+.na
+.BR mg_fast_comp_dict (1),
+.BR mg_invf_dict (1),
+.BR mg_passes (1),
+.BR mg_perf_hash_build (1),
+.BR mg_stem_idx (1),
+.BR mg_weights_build (1)
Index: /main/tags/2.25/gsdl/src/mgpp/text/mg_compression_dict.cpp
===================================================================
--- /main/tags/2.25/gsdl/src/mgpp/text/mg_compression_dict.cpp	(revision 21064)
+++ /main/tags/2.25/gsdl/src/mgpp/text/mg_compression_dict.cpp	(revision 21064)
@@ -0,0 +1,1066 @@
+/**************************************************************************
+ *
+ * mg_compression_dict.cpp -- Routines for creating compression dictionary
+ * Copyright (C) 1994  Neil Sharman
+ *
+ * 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.
+ *
+ * $Id$
+ *
+ **************************************************************************/
+
+#include "sysfuncs.h"
+
+#include "memlib.h"
+#include "messages.h"
+#include "local_strings.h"
+#include "bitio_gen.h"
+#include "bitio_m_stdio.h"
+#include "mgheap.h"
+#include "netorder.h"  /* [RPAP - Jan 97: Endian Ordering] */
+
+#include "mg_files.h"
+#include "locallib.h"
+#include "invf.h"
+#include "text.h"
+#include "words.h"
+#include "mg.h"
+#include "WordData.h"
+
+#define MAXBITS (sizeof(unsigned long) * 8)
+
+/*
+   $Log$
+   Revision 1.2  2000/01/18 03:53:22  rjmcnab
+   Fixed a couple of bugs and made building silent if needed.
+
+   Revision 1.1  2000/01/14 02:26:11  sjboddie
+   Rodgers new C++ mg
+
+   Revision 1.3  1999/10/17 23:43:25  cs025
+   Changes to eradicate Xmalloc
+
+   Revision 1.2  1999/10/11 22:03:03  cs025
+   Changed mistaken use of NTOHUL on a double to NTOHD as per report
+   from Craig Neville-Manning of problems installing mg/gsdl.
+
+   Revision 1.1  1999/10/11 02:57:46  cs025
+   Base install of MG-PP
+
+   Revision 1.1  1999/08/10 21:18:04  sjboddie
+   renamed mg-1.3d directory mg
+
+   Revision 1.4  1999/01/15 03:05:51  rjmcnab
+
+   Renamed lib/heap to be lib/mgheap (it was causing some problems with
+   some versions of the STL libraries which contained a heap.h)
+
+   Revision 1.3  1998/12/17 09:12:52  rjmcnab
+
+   Altered mg to process utf-8 encoded Unicode. The main changes
+   are in the parsing of the input, the casefolding, and the stemming.
+
+   Revision 1.2  1998/11/25 07:55:44  rjmcnab
+
+   Modified mg to that you can specify the stemmer you want
+   to use via a command line option. You specify it to
+   mg_passes during the build process. The number of the
+   stemmer that you used is stored within the inverted
+   dictionary header and the stemmed dictionary header so
+   the correct stemmer is used in later stages of building
+   and querying.
+
+   Revision 1.1  1998/11/17 09:34:52  rjmcnab
+   *** empty log message ***
+
+   * Revision 1.3  1994/10/20  03:56:54  tes
+   * I have rewritten the boolean query optimiser and abstracted out the
+   * components of the boolean query.
+   *
+   * Revision 1.2  1994/09/20  04:41:45  tes
+   * For version 1.1
+   *
+ */
+
+/* #define DEBUG1 */
+
+/* #define DEBUG */
+
+#define is_power_of_two(a) ((a) != 0 && (((a) & ((a)-1)) == 0))
+
+#define MAX_RECALCULATIONS 100
+
+typedef struct DictWordData : public WordData
+  {
+    float saving;
+    float char_bit_cost;
+    u_long num_trans;
+    u_char *word;
+  }
+DictWordData;
+
+static DictWordData *Words[2];
+static u_long Num[2];
+static u_long chars[2];
+
+#define KIND(p) (((p) >= Words[0] && (p) < Words[0] + Num[0]) ? 0 : 1)
+#define IsWord(p) (((p) >= Words[1] && (p) < Words[1] + Num[1]) ? 1 : 0)
+#define IsNonWord(p) (((p) >= Words[0] && (p) < Words[0] + Num[0]) ? 1 : 0)
+
+
+typedef struct DictData
+  {
+    DictWordData **wd;
+    u_long num_wds;
+    u_long chars;
+  }
+DictData;
+
+typedef DictData DictInfo[2];
+
+static DictInfo keep, discard, all;
+static compression_stats_header csh;
+
+static char *file_name = "";
+static u_long novel_method = MG_NOVEL_HUFFMAN_CHARS;
+
+
+static void ReadInWords (char *);
+static void Select_on (int k, heap_comp hc);
+static void Method3 (int k);
+static void Select_all (void);
+static u_long WriteOutWords (char *, u_long, int);
+static int DecFreqIncWL (void *a, void *b);
+static int OccuranceOrder (void *a, void *b);
+
+
+
+int main (int argc, char **argv)
+{
+  int ch;
+  char type = 'C';
+  char mode = '0';
+  int lookback = 2;
+  double k = 0;
+  u_long mem_reqd;
+  opterr = 0;
+  msg_prefix = argv[0];
+  while ((ch = getopt (argc, argv, "0123CPSf:d:l:hk:HDY")) != -1)
+    switch (ch)
+      {
+      case 'H':
+	novel_method = MG_NOVEL_HUFFMAN_CHARS;
+	break;
+      case 'D':
+	novel_method = MG_NOVEL_DELTA;
+	break;
+      case 'Y':
+	novel_method = MG_NOVEL_HYBRID;
+	break;
+      case 'f':		/* input file */
+	file_name = optarg;
+	break;
+      case 'd':
+	set_basepath (optarg);
+	break;
+      case 'C':
+      case 'P':
+      case 'S':
+	type = ch;
+	break;
+      case '0':
+      case '1':
+      case '2':
+      case '3':
+	mode = ch;
+	break;
+      case 'l':
+	lookback = atoi (optarg);
+	if (!is_power_of_two (lookback))
+	  FatalError (1, "The lookback value must be a power of 2");
+	lookback = floorlog_2 (lookback);
+	break;
+      case 'k':
+	k = atof (optarg) * 1024;
+	break;
+      case 'h':
+      case '?':
+	fprintf (stderr, "usage: %s [-l lookback] [-f input_file]"
+	"[-d data directory] [-h] [-0|-1|-2|-3] [-C|-P|-S] [-k mem (Kb)]\n",
+		 argv[0]);
+	exit (1);
+      }
+
+  ReadInWords (file_name);
+
+  if (type == 'C')
+    {
+      Select_all ();
+      mem_reqd = WriteOutWords (file_name, MG_COMPLETE_DICTIONARY, lookback);
+    }
+  else
+    {
+      switch (mode)
+	{
+	case '0':
+	  Select_all ();
+	  break;
+	case '1':
+#ifndef SILENT
+	  Message ("Dictionary limit of %.2f Kb", k / 1024);
+#endif
+	  Select_on ((int) k, OccuranceOrder);
+	  break;
+	case '2':
+#ifndef SILENT
+	  Message ("Dictionary limit of %.2f Kb", k / 1024);
+#endif
+	  Select_on ((int) k, DecFreqIncWL);
+	  break;
+	case '3':
+#ifndef SILENT
+	  Message ("Dictionary limit of %.2f Kb", k / 1024);
+#endif
+	  Method3 ((int) k);
+	  break;
+	}
+      if (type == 'P')
+	{
+	  mem_reqd = WriteOutWords (file_name, MG_PARTIAL_DICTIONARY, lookback);
+	}
+      else
+	{
+	  mem_reqd = WriteOutWords (file_name, MG_SEED_DICTIONARY, lookback);
+	}
+    }
+
+#ifndef SILENT
+  Message ("Num words           : %8u -> %8u\n", Num[1], keep[1].num_wds);
+  Message ("Num non-words       : %8u -> %8u\n", Num[0], keep[0].num_wds);
+  Message ("Chars of words      : %8u -> %8u\n", chars[1], keep[1].chars);
+  Message ("Chars of non-words  : %8u -> %8u\n", chars[0], keep[0].chars);
+  Message ("Mem usage           : %8u -> %8u\n",
+	   (Num[0] + Num[1]) * sizeof (char *) + chars[0] + chars[1],
+	     (keep[0].num_wds + keep[1].num_wds) * sizeof (char *) +
+	   keep[0].chars + keep[1].chars);
+  Message ("Actual mem required : %8u\n", mem_reqd);
+#endif
+  exit (0);
+}
+
+
+
+
+static void 
+ReadInWords (char *filename)
+{
+  FILE *f;
+  unsigned long i;
+  f = open_file (filename, TEXT_STATS_DICT_SUFFIX, "rb",
+		 MAGIC_STATS_DICT, MG_ABORT);  /* [RPAP - Feb 97: WIN32 Port] */
+
+  fread (&csh, sizeof (csh), 1, f);
+
+  /* [RPAP - Jan 97: Endian Ordering] */
+  NTOHUL(csh.num_docs);
+  NTOHD(csh.num_bytes);
+
+  for (i = 0; i < 2; i++)
+    {
+      frags_stats_header fsh;
+      char *buf;
+      DictWordData *wd;
+      chars[i] = 0;
+
+      fread (&fsh, sizeof (fsh), 1, f);
+      /* [RPAP - Jan 97: Endian Ordering] */
+      NTOHUL(fsh.num_frags);
+      NTOHUL(fsh.mem_for_frags);
+
+      Num[i] = all[i].num_wds = fsh.num_frags;
+
+      /* The +1 on the following line is to leave room for the esc code. */
+      all[i].wd = (DictWordData **) Xmalloc (sizeof (DictWordData *) * Num[i] + 1);
+
+      buf = (char *) Xmalloc (fsh.mem_for_frags);
+      wd = Words[i] = (DictWordData *) Xmalloc (sizeof (DictWordData) * Num[i]);
+      unsigned int j;
+      for (j = 0; j < Num[i]; j++, wd++)
+	{
+	  int len;
+
+	  // read docCount and wordCount
+	  wd->read(f);
+
+	  // read an mgString
+	  len = fgetc (f);
+	  wd->word = (u_char *) buf;
+	  *buf++ = len;
+	  fread (buf, len, 1, f);
+	  buf += len;
+	  all[i].wd[j] = wd;
+	}
+      chars[i] = fsh.mem_for_frags - fsh.num_frags;
+    }
+  fclose (f);
+}
+
+
+static void 
+Alloc_keep_discard (void)
+{
+  keep[0].num_wds = 0;
+  keep[0].wd = (DictWordData **) Xmalloc ((Num[0] + 1) * sizeof (DictWordData *));
+  keep[1].num_wds = 0;
+  keep[1].wd = (DictWordData **) Xmalloc ((Num[1] + 1) * sizeof (DictWordData *));
+  discard[0].num_wds = 0;
+  discard[0].wd = (DictWordData **) Xmalloc ((Num[0] + 1) * sizeof (DictWordData *));
+  discard[1].num_wds = 0;
+  discard[1].wd = (DictWordData **) Xmalloc ((Num[1] + 1) * sizeof (DictWordData *));
+}
+
+
+static int 
+sort_comp (const void *a, const void *b)
+{
+  DictWordData *aa = *(DictWordData **) a;
+  DictWordData *bb = *(DictWordData **) b;
+  return casecompare (aa->word, bb->word);  /* [RPAP - Jan 97: Stem Index Change] */
+}
+
+
+
+static void 
+SortAndCount_DictData (DictData * dd)
+{
+  unsigned int i;
+  DictWordData **wd;
+  qsort (dd->wd, dd->num_wds, sizeof (DictWordData *), sort_comp);
+  dd->chars = 0;
+  wd = dd->wd;
+  for (i = 0; i < dd->num_wds; i++, wd++)
+    dd->chars += (*wd)->word[0];
+}
+
+
+static void 
+Select_all (void)
+{
+  unsigned int i;
+  Alloc_keep_discard ();
+  keep[0].num_wds = Num[0];
+  for (i = 0; i < Num[0]; i++)
+    keep[0].wd[i] = Words[0] + i;
+  keep[1].num_wds = Num[1];
+  for (i = 0; i < Num[1]; i++)
+    keep[1].wd[i] = Words[1] + i;
+  SortAndCount_DictData (&keep[0]);
+  SortAndCount_DictData (&keep[1]);
+}
+
+
+
+
+static int 
+DecFreqIncWL (void *a, void *b)
+{
+  DictWordData *aa = *(DictWordData **) a;
+  DictWordData *bb = *(DictWordData **) b;
+  if (aa->docCount > bb->docCount)
+    return -1;
+  else if (aa->docCount < bb->docCount)
+    return 1;
+  else
+    return bb->word[0] - aa->word[0];
+}
+
+
+static int 
+OccuranceOrder (void *a, void *b)
+{
+  DictWordData *aa = *(DictWordData **) a;
+  DictWordData *bb = *(DictWordData **) b;
+  if (aa->words() > bb->words())
+    return 1;
+  else if (aa->words() < bb->words())
+    return -1;
+  else
+    return 0;
+}
+
+
+static void 
+Select_on (int k, heap_comp hc)
+{
+  int i, num, mem;
+  DictWordData **wd;
+
+  Alloc_keep_discard ();
+
+  num = Num[0] + Num[1];
+  wd = (DictWordData **) Xmalloc (num * sizeof (DictWordData *));
+  for (i = 0; (unsigned int)i < Num[0]; i++)
+    wd[i] = Words[0] + i;
+  for (i = 0; (unsigned int)i < Num[1]; i++)
+    wd[i + Num[0]] = Words[1] + i;
+
+  heap_build (wd, sizeof (*wd), num, hc);
+
+  mem = 0;
+  while (k > mem && num)
+    {
+      int idx;
+      DictWordData *word = wd[0];
+#ifdef DEBUG
+      fprintf (stderr, "%4d:%4d:%8d :%8d :%8d : \"%s\"\n",
+	       keep[0].num_wds, keep[1].num_wds,
+	       mem, word->documents(), word->word, word2str (word->word));
+#endif
+      mem += sizeof (u_char *) + word->word[0];
+      heap_deletehead (wd, sizeof (*wd), &num, hc);
+      idx = KIND (word);
+      keep[idx].wd[keep[idx].num_wds++] = word;
+    }
+
+  for (i = 0; i < num; i++)
+    {
+      DictWordData *word = wd[i];
+      int idx = KIND (word);
+      discard[idx].wd[discard[idx].num_wds++] = word;
+    }
+  SortAndCount_DictData (&keep[0]);
+  SortAndCount_DictData (&keep[1]);
+  SortAndCount_DictData (&discard[0]);
+  SortAndCount_DictData (&discard[1]);
+
+  assert (keep[0].num_wds + discard[0].num_wds == Num[0]);
+  assert (keep[1].num_wds + discard[1].num_wds == Num[1]);
+
+}
+
+
+
+static int 
+BigSaving (void *a, void *b)
+{
+  DictWordData *aa = *(DictWordData **) a;
+  DictWordData *bb = *(DictWordData **) b;
+  return (aa->saving > bb->saving) ? -1 : (aa->saving < bb->saving);
+}
+
+static int 
+SmallSaving (void *a, void *b)
+{
+  DictWordData *aa = *(DictWordData **) a;
+  DictWordData *bb = *(DictWordData **) b;
+  return (aa->saving < bb->saving) ? -1 : (aa->saving > bb->saving);
+}
+
+
+static void 
+CalcCharCounts (DictWordData ** wd, int num,
+		char *char_lens[2], char *len_lens[2],
+		u_long escape[2])
+{
+  long char_freqs[2][256];
+  long len_freqs[2][16];
+  huff_data hd;
+  int i;
+  escape[0] = 0;
+  escape[1] = 0;
+  bzero ((char *) char_freqs, sizeof (char_freqs));
+  bzero ((char *) len_freqs, sizeof (len_freqs));
+  for (i = 0; i < num; i++, wd++)
+    {
+      u_long freq = (*wd)->documents();
+      u_char *buf = (*wd)->word;
+      int len = *buf++;
+      int idx = KIND (*wd);
+      len_freqs[idx][len] += freq;
+      escape[idx] += freq;
+      for (; len; len--, buf++)
+	char_freqs[idx][(u_long) (*buf)] += freq;
+    }
+  Generate_Huffman_Data (256, char_freqs[0], &hd, NULL);
+  char_lens[0] = hd.clens;
+  Generate_Huffman_Data (256, char_freqs[1], &hd, NULL);
+  char_lens[1] = hd.clens;
+
+  Generate_Huffman_Data (16, len_freqs[0], &hd, NULL);
+  len_lens[0] = hd.clens;
+  Generate_Huffman_Data (16, len_freqs[1], &hd, NULL);
+  len_lens[1] = hd.clens;
+}
+
+
+
+
+
+inline void CalcBitCostForWordData(DictWordData **word, int num,
+				   double freqs_trans[2], u_long escape[2],
+				   char * char_lens[2], char *len_lens[2], 
+				   double esc[2], int num_trans)
+{ 
+  int j;
+
+  for (j = 0; j < num; j++, word++)
+    {
+      float   cbc, wbc;
+      u_char *buf = (*word)->word;
+      int     len = *buf++;
+      u_long  freq = (*word)->documents();
+      int     idx = KIND (*word);
+
+      cbc = len_lens[idx][len];
+      for (; len; len--, buf++)
+	cbc += char_lens[idx][(u_long) (*buf)];
+
+      (*word)->char_bit_cost = (cbc + esc[idx]) * freq;
+
+      wbc = -log2 (freq / (freqs_trans[idx] + escape[idx])) * freq;
+
+      (*word)->saving = ((*word)->char_bit_cost - wbc) /
+	(sizeof (char *) + (*word)->word[0]);
+
+      (*word)->num_trans = num_trans;
+    }
+}
+
+
+
+void 
+CalcBitCost (DictWordData ** discard_word, int discard_num,
+	     DictWordData ** keep_word, int keep_num, double freqs_trans[2],
+	     u_long escape[2], int num_trans)
+{
+  char *char_lens[2];
+  char *len_lens[2];
+  double esc[2];
+  CalcCharCounts (discard_word, discard_num, char_lens, len_lens, escape);
+  esc[0] = -log2 (escape[0] / (freqs_trans[0] + escape[0]));
+  esc[1] = -log2 (escape[1] / (freqs_trans[1] + escape[1]));
+  CalcBitCostForWordData(discard_word, discard_num, freqs_trans, escape,
+			 char_lens, len_lens, esc, num_trans);
+  CalcBitCostForWordData(keep_word, keep_num, freqs_trans, escape,
+			 char_lens, len_lens, esc, num_trans);
+  Xfree (char_lens[0]);
+  Xfree (char_lens[1]);
+  Xfree (len_lens[0]);
+  Xfree (len_lens[1]);
+}
+
+inline void m3_transferWord(DictWordData **toHeap, int *toNum, heap_comp toSaving,
+			    DictWordData **fromHeap, int *fromNum, heap_comp fromSaving,
+			    int *num_trans, double freqs_trans[], int *mem, double *total,
+			    int *count)
+{
+  /* Transfer the word at the top of the keep heap to the
+     discard heap. */
+  DictWordData *word = fromHeap[0];
+  int idx = KIND (word);
+  heap_deletehead (fromHeap, sizeof (word), fromNum, fromSaving);
+  toHeap[*toNum] = word;
+  heap_additem (toHeap, sizeof (word), toNum, toSaving);
+  freqs_trans[idx] -= word->documents();
+  *mem = (*mem) - sizeof (u_char *) + word->word[0];
+  *num_trans += 1;
+  *total += word->saving;
+  *count += 1;
+#ifdef DEBUG
+  fprintf (stderr,
+	   "KEEP -> DISCARD %8d :%8d :%8.0f :%8.0f : \"%s\"\n",
+	   *mem, word->documents(), word->char_bit_cost,
+	   word->saving, word2str (word->word));
+#endif
+}
+
+inline void m3_storeWord(DictWordData **wordHeap, int wordNum, int num_trans, 
+			 double freqs_trans[], u_long escape[], heap_comp hc)
+{
+  DictWordData *word = wordHeap[0];
+  int idx = KIND (word);
+  float wbc;
+#ifdef DEBUG1
+  fprintf (stderr, "KEEP \"%s\" %.2f ->", word2str (word->word),
+	   word->saving);
+#endif
+  wbc = -log2 (word->documents() / (freqs_trans[idx] + escape[idx])) *
+    word->documents();
+  word->saving = (word->char_bit_cost - wbc) /
+    (sizeof (char *) + word->word[0]);
+#ifdef DEBUG1
+  fprintf (stderr, " %.2f\n", word->saving);
+#endif
+  word->num_trans = num_trans;
+  heap_changedhead (wordHeap, sizeof (word), wordNum, hc);
+}
+
+
+static void 
+Method3 (int k)
+{
+  int i, keep_num, discard_num, mem, num_trans, recalc_reqd;
+  int keep_to_discard = 0;
+  int discard_to_keep = 0;
+  int recalcs = 0;
+  double freqs_trans[2], total;
+  u_long escape[2];
+  DictWordData **keep_heap, **discard_heap;
+
+  freqs_trans[0] = freqs_trans[1] = 0;
+  num_trans = 0;
+
+  discard_num = Num[0] + Num[1];
+  discard_heap = (DictWordData **) Xmalloc (discard_num * sizeof (DictWordData *));
+
+  keep_num = 0;
+  keep_heap = (DictWordData **) Xmalloc (discard_num * sizeof (DictWordData *));
+
+
+  for (i = 0; (unsigned int)i < Num[0]; i++)
+    discard_heap[i] = Words[0] + i;
+  for (i = 0; (unsigned int)i < Num[1]; i++)
+    discard_heap[i + Num[0]] = Words[1] + i;
+
+  heap_build (discard_heap, sizeof (*discard_heap), discard_num, DecFreqIncWL);
+
+  mem = 0;
+  while (k > mem && discard_num)
+    {
+      DictWordData *word = discard_heap[0];
+      mem += sizeof (u_char *) + word->word[0];
+      heap_deletehead (discard_heap, sizeof (word), &discard_num, DecFreqIncWL);
+      keep_heap[keep_num++] = word;
+      freqs_trans[KIND (word)] += word->documents();
+      num_trans++;
+    }
+
+  CalcBitCost (discard_heap, discard_num, keep_heap, keep_num,
+	       freqs_trans, escape, num_trans);
+  heap_build (discard_heap, sizeof (*discard_heap), discard_num, BigSaving);
+  heap_build (keep_heap, sizeof (*keep_heap), keep_num, SmallSaving);
+
+  total = 0;
+  recalc_reqd = 0;
+  while (keep_num && discard_num)
+    {
+      if ((keep_num && keep_heap[0]->num_trans < (unsigned)num_trans) ||
+	  (discard_num && discard_heap[0]->num_trans < (unsigned)num_trans))
+	{
+	  if (keep_num && keep_heap[0]->num_trans < (unsigned)num_trans)
+	    {
+	      m3_storeWord(keep_heap, keep_num, num_trans, freqs_trans, escape, SmallSaving);
+	    }
+
+	  if (discard_num && discard_heap[0]->num_trans < (unsigned)num_trans)
+	    {
+	      m3_storeWord(discard_heap, discard_num, num_trans, freqs_trans, escape, BigSaving);
+	    }
+	}
+      else if (keep_heap[0]->saving < discard_heap[0]->saving)
+	{
+	  assert (keep_num && discard_num);
+	  if (keep_num && mem + sizeof (char *) + discard_heap[0]->word[0] > (unsigned)k)
+	    {
+	      /* Transfer the word at the top of the keep heap to the
+	         discard heap. */
+	      m3_transferWord(discard_heap, &discard_num, BigSaving,
+			      keep_heap, &keep_num, SmallSaving,
+			      &num_trans, freqs_trans, &mem, &total, &keep_to_discard);
+	    }
+	  else
+	    {
+	      /* Transfer the word at the top of the discard heap to the
+	         keep heap. */
+	      m3_transferWord(keep_heap, &keep_num, SmallSaving,
+			      discard_heap, &discard_num, BigSaving,
+			      &num_trans, freqs_trans, &mem, &total, &discard_to_keep);
+	    }
+
+	  recalc_reqd = 1;
+
+	}
+      else
+	{
+	  if (recalc_reqd == 0)
+	    break;
+#ifdef DEBUG1
+	  fprintf (stderr, "--------------\n");
+#endif
+	  if (recalcs == MAX_RECALCULATIONS)
+	    break;
+	  CalcBitCost (discard_heap, discard_num, keep_heap, keep_num,
+		       freqs_trans, escape, num_trans);
+	  heap_build (discard_heap, sizeof (*discard_heap),
+		      discard_num, BigSaving);
+	  heap_build (keep_heap, sizeof (keep_heap), keep_num, SmallSaving);
+	  recalc_reqd = 0;
+	  recalcs++;
+	}
+    }
+
+  Alloc_keep_discard ();
+
+  for (i = 0; i < discard_num; i++)
+    {
+      DictWordData *word = discard_heap[i];
+      int idx = KIND (word);
+      assert (IsWord (word) || IsNonWord (word));
+      discard[idx].wd[discard[idx].num_wds++] = word;
+    }
+  for (i = 0; i < keep_num; i++)
+    {
+      DictWordData *word = keep_heap[i];
+      int idx = KIND (word);
+      assert (IsWord (word) || IsNonWord (word));
+      keep[idx].wd[keep[idx].num_wds++] = word;
+    }
+  SortAndCount_DictData (&keep[0]);
+  SortAndCount_DictData (&keep[1]);
+  SortAndCount_DictData (&discard[0]);
+  SortAndCount_DictData (&discard[1]);
+
+  assert (keep[0].num_wds + discard[0].num_wds == Num[0]);
+  assert (keep[1].num_wds + discard[1].num_wds == Num[1]);
+#ifndef SILENT
+  Message ("Keep -> Discard        : %8d", keep_to_discard);
+  Message ("Discard -> Keep        : %8d", discard_to_keep);
+  Message ("Huffman Recalculations : %8d", recalcs);
+  if (recalcs == MAX_RECALCULATIONS)
+    Message ("WARNING: The number of recalculations == %d", MAX_RECALCULATIONS);
+#endif
+}
+
+
+
+
+
+
+
+
+
+
+/****************************************************************************
+ *****									*****
+ *****			Dictionary saving code				*****
+ *****									*****
+ ****************************************************************************/
+
+
+
+static void 
+Write_cdh (FILE * f, compression_dict_header * cdh)
+{
+  /* [RPAP - Jan 97: Endian Ordering] */
+  int i;
+  compression_dict_header tmp = *cdh;
+  HTONUL(tmp.dict_type);
+  HTONUL(tmp.novel_method);
+  for (i = 0; i < TEXT_PARAMS; i++)
+    HTONUL(tmp.params[i]);
+  HTONUL(tmp.num_words[0]);
+  HTONUL(tmp.num_words[1]);
+  HTONUL(tmp.num_word_chars[0]);
+  HTONUL(tmp.num_word_chars[1]);
+  HTONUL(tmp.lookback);
+
+  fwrite (&tmp, sizeof (tmp), 1, f);
+}
+
+
+static void 
+Write_words (FILE * f, DictData * dd)
+{
+  unsigned int i;
+  u_char *curr, *prev = NULL;
+  for (i = 0; i < dd->num_wds; i++)
+    {
+      int len;
+      curr = dd->wd[i]->word;
+      if (prev)
+	/* look for prefix match with prev string */
+	len = prefixlen (prev, curr);
+      else
+	len = 0;
+      fputc ((len << 4) + (curr[0] - len), f);
+      fwrite (curr + len + 1, sizeof (u_char), curr[0] - len, f);
+      prev = curr;
+    }
+
+}
+
+
+static int 
+Uncompressed_size (DictData * dd)
+{
+  unsigned int i, us;
+  for (us = i = 0; i < dd->num_wds; i++)
+    us += dd->wd[i]->word[0];
+  return us;
+}
+
+
+static u_long 
+Write_data (FILE * f, DictData * dd, int lookback)
+{
+  u_long mem_reqd;
+  huff_data *hd;
+  int i; 
+  u_long us = dd->num_wds;
+  long *freqs;
+  u_long huff_words_size[MAX_HUFFCODE_LEN + 1];
+  u_long lencounts[MAX_HUFFCODE_LEN + 1];
+  u_char *lastword[MAX_HUFFCODE_LEN + 1];
+
+  if (!(freqs = new long [dd->num_wds]))
+    FatalError (1, "Unable to allocate memory for freqs");
+
+  for (i = 0; (unsigned)i < dd->num_wds; i++)
+    {
+      freqs[i] = dd->wd[i]->documents();
+      us += dd->wd[i]->word[0];
+    }
+
+  if (!(hd = Generate_Huffman_Data (dd->num_wds, freqs, NULL, NULL)))
+    FatalError (1, "Unable to allocate memory for huffman data");
+
+  delete (freqs);
+  freqs = NULL;
+
+  if (Write_Huffman_Data (f, hd) == -1)
+    FatalError (1, "Unable to write huffman data");
+
+  HTONUL(us);  /* [RPAP - Jan 97: Endian Ordering] */
+  fwrite (&us, sizeof (us), 1, f);
+  NTOHUL(us);  /* [RPAP - Jan 97: Endian Ordering] */
+
+
+/* Calculate the amount of memory that will be required to store the text for
+   each different huffman code len. Every 1<<lookback words for each different
+   codelen length will not be prefixed by previous strings. */
+
+
+  bzero ((char *) &huff_words_size, sizeof (huff_words_size));
+  bzero ((char *) &lencounts, sizeof (lencounts));
+
+  mem_reqd = 0;
+
+  for (i = 0; (unsigned)i < dd->num_wds; i++)
+    {
+      int codelen = hd->clens[i];
+      u_char *word = dd->wd[i]->word;
+
+      if (!codelen)
+	FatalError (1, "The length of a code for a word was zero");
+
+      huff_words_size[codelen] += word[0] + 1;
+      mem_reqd += word[0] + (lookback != 0);
+#if 0
+      if ((lencounts[codelen] & ((1 << lookback) - 1)) == 0)
+	lastword[codelen] = word;
+      else
+	huff_words_size[codelen] -= prefixlen (lastword[codelen], word);
+#else
+      if ((lencounts[codelen] & ((1 << lookback) - 1)) != 0)
+	{
+	  int save = prefixlen (lastword[codelen], word);
+	  mem_reqd -= save;
+	  huff_words_size[codelen] -= save;
+	}
+      else
+	{
+	  mem_reqd += sizeof (u_char *);
+	}
+      lastword[codelen] = word;
+#endif
+      lencounts[codelen]++;
+    }
+
+  /* [RPAP - Jan 97: Endian Ordering] */
+  for (i = hd->mincodelen; i < hd->maxcodelen + 1; i++)
+    HTONUL(huff_words_size[i]);
+
+  fwrite (huff_words_size + hd->mincodelen, sizeof (*huff_words_size),
+	  hd->maxcodelen - hd->mincodelen + 1, f);
+
+  /* [RPAP - Jan 97: Endian Ordering] */
+  for (i = hd->mincodelen; i < hd->maxcodelen + 1; i++)
+    NTOHUL(huff_words_size[i]);
+
+  Write_words (f, dd);
+
+  delete hd->clens;
+  delete hd;
+
+  return mem_reqd;
+}
+
+
+
+static void 
+Write_charfreqs (FILE * f, DictData * dd, int words,
+		 int zero_freq_permitted)
+{
+  unsigned int j;
+  long freqs[256];
+  DictWordData **wd = dd->wd;
+  huff_data *hd;
+
+  bzero ((char *) freqs, sizeof (freqs));
+
+  for (j = 0; j < dd->num_wds; j++, wd++)
+    {
+      u_char *buf = (*wd)->word;
+      int len = *buf++;
+      for (; len; len--, buf++)
+	freqs[(u_long) (*buf)] += (*wd)->documents();
+    }
+
+  if (!zero_freq_permitted)
+    for (j = 0; j < 256; j++)
+      if (!freqs[j] && PESINAWORD (j) == words)
+	freqs[j] = 1;
+
+  if (!(hd = Generate_Huffman_Data (256, freqs, NULL, NULL)))
+    FatalError (1, "Unable to allocate memory for huffman data");
+
+  if (Write_Huffman_Data (f, hd) == -1)
+    FatalError (1, "Unable to write huffman data");
+
+  delete hd->clens;
+  delete hd;
+}
+
+
+
+
+static void 
+Write_wordlens (FILE * f, DictData * dd, int zero_freq_permitted)
+{
+  unsigned int j;
+  long freqs[16];
+  DictWordData **wd = dd->wd;
+  huff_data *hd;
+
+  bzero ((char *) freqs, sizeof (freqs));
+
+  for (j = 0; j < dd->num_wds; j++, wd++)
+    freqs[(*wd)->word[0]] += (*wd)->documents();
+
+  if (!zero_freq_permitted)
+    for (j = 0; j < 16; j++)
+      if (!freqs[j])
+	freqs[j] = 1;
+
+  if (!(hd = Generate_Huffman_Data (16, freqs, NULL, NULL)))
+    FatalError (1, "Unable to allocate memory for huffman data");
+
+  if (Write_Huffman_Data (f, hd) == -1)
+    FatalError (1, "Unable to write huffman data");
+
+
+  delete hd->clens;
+  delete hd;
+}
+
+
+
+static u_long 
+WriteOutWords (char *file_name, u_long type, int lookback)
+{
+  FILE *f;
+  int i;
+  u_long mem_reqd = 0;
+
+  compression_dict_header cdh;
+  f = create_file (file_name, TEXT_DICT_SUFFIX, "w+b",
+		   MAGIC_DICT, MG_ABORT);  /* [RPAP - Feb 97: WIN32 Port] */
+
+  bzero((char *) &cdh, sizeof(cdh));
+
+  cdh.dict_type = type;
+  cdh.novel_method = (type == MG_SEED_DICTIONARY) ? novel_method :
+    MG_NOVEL_HUFFMAN_CHARS;
+
+  cdh.num_words[1] = keep[1].num_wds;
+  cdh.num_words[0] = keep[0].num_wds;
+  cdh.num_word_chars[1] = Uncompressed_size (&keep[1]);
+  cdh.num_word_chars[0] = Uncompressed_size (&keep[0]);
+  cdh.lookback = lookback;
+
+  Write_cdh (f, &cdh);
+
+  for (i = 0; i < 2; i++)
+    switch (type)
+      {
+      case MG_COMPLETE_DICTIONARY:
+	{
+	  mem_reqd += Write_data (f, &keep[i], lookback);
+	}
+	break;
+      case MG_PARTIAL_DICTIONARY:
+	{
+	  if (keep[i].num_wds)
+	    {
+	      int j;
+	      DictWordData esc;
+	      esc.docCount = 0;
+	      esc.word = (u_char *) "";
+	      keep[i].wd[keep[i].num_wds++] = &esc;
+	      for (j = 0; (unsigned)j < discard[i].num_wds; j++)
+		esc.docCount += discard[i].wd[j]->documents();
+	      if (!esc.docCount)
+		esc.docCount++;
+	      mem_reqd += Write_data (f, &keep[i], lookback);
+	    }
+	  Write_charfreqs (f, &discard[i], i, 1);
+	  Write_wordlens (f, &discard[i], 1);
+	}
+	break;
+      case MG_SEED_DICTIONARY:
+	{
+	  if (keep[i].num_wds)
+	    {
+	      int j;
+	      DictWordData esc;
+	      esc.docCount = 0;
+	      esc.word = (u_char *) "";
+	      keep[i].wd[keep[i].num_wds++] = &esc;
+	      for (j = 0; (unsigned)j < all[i].num_wds; j++)
+		if (all[i].wd[j]->documents() == 1)
+		  esc.docCount++;
+	      if (!esc.docCount)
+		esc.docCount++;
+	      mem_reqd += Write_data (f, &keep[i], lookback);
+	    }
+	  switch (novel_method)
+	    {
+	    case MG_NOVEL_HUFFMAN_CHARS:
+	      Write_charfreqs (f, &all[i], i, 0);
+	      Write_wordlens (f, &all[i], 0);
+	      break;
+	    case MG_NOVEL_DELTA:
+	      break;
+	    case MG_NOVEL_HYBRID:
+	      break;
+	    default:
+	      FatalError (1, "Bad novel method");
+	    }
+	}
+	break;
+      }
+  fclose (f);
+  return mem_reqd;
+}
Index: /main/tags/2.25/gsdl/src/mgpp/text/mg_decompress_text.cpp
===================================================================
--- /main/tags/2.25/gsdl/src/mgpp/text/mg_decompress_text.cpp	(revision 21064)
+++ /main/tags/2.25/gsdl/src/mgpp/text/mg_decompress_text.cpp	(revision 21064)
@@ -0,0 +1,95 @@
+/**************************************************************************
+ *
+ * mg_decompress_text.cpp -- 
+ * Copyright (C) 1999  Rodger McNab
+ *
+ * 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.
+ *
+ * $Id$
+ *
+ **************************************************************************/
+
+#include "sysfuncs.h"
+
+#include "TextGet.h"
+#include "UCArray.h"
+
+#include "messages.h"
+#include "mg_files.h"
+
+
+int main (int argc, char **argv) {
+  int ch;
+  char *filename = "";
+  char *basePath = "";
+  UCArray level;
+  SetCStr (level, "Document");
+
+  opterr = 0;
+  msg_prefix = argv[0];
+
+  // process the command line arguments
+  while ((ch = getopt (argc, argv, "f:d:K:h")) != -1) {
+    switch (ch) {
+    case 'f':		/* input file */
+      filename = optarg;
+      break;
+    case 'd':
+      basePath = optarg;
+      set_basepath (optarg);
+      break;
+    case 'K':
+      SetCStr (level, optarg);
+      break;
+    case 'h':
+    case '?':
+      fprintf (stderr, "usage: %s [-h] [-K level] [-d directory] -f name\n",
+	       argv[0]);
+      exit (1);
+    }
+  }
+
+  // load up the text information
+  TextData td;
+  if (!td.LoadData (basePath, filename)) {
+    FatalError (1, "Couldn't load text information for \"%s\"", filename);
+  }
+  
+  // output each document in the level
+//    cout << td.levels << "\n";
+  
+  TextLevelInfo levelInfo = td.levels.levelInfo[level];
+  unsigned long docNum = 1;
+  UCArray docText;
+  while (docNum <= levelInfo.numEntries) {
+//      TextIdx docIdx;
+//      if (GetDocIdx (td, level, docNum, docIdx)) {
+//        cout << "doc: " << docNum << "\n";
+//        cout << docIdx;
+//      }
+    
+    if (!GetDocText (td, level, docNum, docText)) {
+      FatalError (1, "Error while trying to get document %u", docNum);
+    }
+
+    cout << docText << "\n";
+    
+    docNum++;
+  }
+  
+  return 0;
+}
+
+
Index: /main/tags/2.25/gsdl/src/mgpp/text/mg_errors.cpp
===================================================================
--- /main/tags/2.25/gsdl/src/mgpp/text/mg_errors.cpp	(revision 21064)
+++ /main/tags/2.25/gsdl/src/mgpp/text/mg_errors.cpp	(revision 21064)
@@ -0,0 +1,73 @@
+/**************************************************************************
+ *
+ * mg_errors.cpp -- Error related stuff for mgquery
+ * Copyright (C) 1994  Neil Sharman
+ *
+ * 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.
+ *
+ * $Id$
+ *
+ **************************************************************************/
+
+#include "sysfuncs.h"
+#include "memlib.h"
+
+#include "mg_errors.h"
+
+
+
+int mg_errno = MG_NOERROR;
+
+char *mg_errorstrs[] =
+{
+  "No error",
+  "Out of memory",
+  "File \"%s\" not found",
+  "Bad magic number in \"%s\"",
+  "Error reading \"%s\"",
+  "MG_BUFTOOSMALL",
+  "Files required for level 2 and 3 inversion are missing"};
+
+
+/* [RJM 07/98: Memory Leak] -- rest of file */
+
+static char null_data[] = "";
+char *mg_error_data = null_data;
+
+
+void MgErrorData (char *s)
+{
+  /* free the current error string, unless it is the null string */
+  if ((mg_error_data != NULL) && (mg_error_data != null_data)) {
+    delete mg_error_data;
+    mg_error_data = null_data;
+  }
+
+  /* make a copy of the string */
+  mg_error_data = Xstrdup (s);
+
+  /* if the alloc failed set the error to the null string */
+  if (!mg_error_data) mg_error_data = null_data;
+}
+
+
+void MgErrorDeinit (void)
+{
+  /* free the current error string, unless it is the null string */
+  if ((mg_error_data != NULL) && (mg_error_data != null_data)) {
+    delete mg_error_data;
+    mg_error_data = null_data;
+  }
+}
Index: /main/tags/2.25/gsdl/src/mgpp/text/mg_errors.h
===================================================================
--- /main/tags/2.25/gsdl/src/mgpp/text/mg_errors.h	(revision 21064)
+++ /main/tags/2.25/gsdl/src/mgpp/text/mg_errors.h	(revision 21064)
@@ -0,0 +1,39 @@
+/**************************************************************************
+ *
+ * mg_errors.h -- Error related stuff for mgquery
+ * Copyright (C) 1994  Neil Sharman
+ *
+ * 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.
+ *
+ * $Id$
+ *
+ **************************************************************************/
+
+
+extern int mg_errno;
+extern char *mg_error_data;
+extern char *mg_errorstrs[];
+
+
+#define MG_NOERROR 0
+#define MG_NOMEM 1
+#define MG_NOFILE 2
+#define MG_BADMAGIC 3
+#define MG_READERR 4
+#define MG_BUFTOOSMALL 5
+#define MG_INVERSION 6
+
+void MgErrorData (char *s);
+void MgErrorDeinit (void);
Index: /main/tags/2.25/gsdl/src/mgpp/text/mg_fast_comp_dict.1
===================================================================
--- /main/tags/2.25/gsdl/src/mgpp/text/mg_fast_comp_dict.1	(revision 21064)
+++ /main/tags/2.25/gsdl/src/mgpp/text/mg_fast_comp_dict.1	(revision 21064)
@@ -0,0 +1,70 @@
+.\"------------------------------------------------------------
+.\" Id - set Rv,revision, and Dt, Date using rcs-Id tag.
+.de Id
+.ds Rv \\$3
+.ds Dt \\$4
+..
+.Id $Id$
+.\"------------------------------------------------------------
+.TH mg_fast_comp_dict 1 \*(Dt CITRI
+.SH NAME
+mg_fast_comp_dict \- build a fast loading compression dictionary
+.SH SYNOPSIS
+.B mg_fast_comp_dict
+[
+.B \-h
+]
+[
+.BI \-d " directory"
+]
+.BI \-f " name"
+.SH DESCRIPTION
+.B mg_fast_comp_dict
+builds a fast-loading compression dictionary from the standard
+compression dictionary.  The new dictionary has the property that
+.BR mgquery (1)
+can load it in very quickly, making the startup time for
+.BR mgquery (1)
+much shorter.  The new dictionary is larger on disk than the original,
+but they are no different when it comes to memory usage.
+.SH OPTIONS
+Options may appear in any order.
+.TP "\w'\fB\-d\fP \fIdirectory\fP'u+2n"
+.B \-h
+This displays a usage line on
+.IR stderr .
+.TP
+.BI \-d " directory"
+This specifies the directory where the document collection can be found.
+.TP
+.BI \-f " name"
+This specifies the base name of the document collection.
+.SH ENVIRONMENT
+.TP "\w'\fBMGDATA\fP'u+2n"
+.SB MGDATA
+If this environment variable exists, then its value is used as the
+default directory where the mg
+collection files are.  If this variable does not exist, then the
+directory \*(lq\fB.\fP\*(rq is used by default.  The command line
+option
+.BI \-d " directory"
+overrides the directory in
+.BR MGDATA .
+.SH FILES
+.TP 20
+.B *.text.dict
+Compression dictionary.
+.TP
+.B *.text.dict.fast
+Fast loading compression dictionary.
+.TP
+.B *.text.dict.aux
+Auxiliary compression dictionary.
+.SH "SEE ALSO"
+.na
+.BR mg_compression_dict (1),
+.BR mg_invf_dict (1),
+.BR mg_passes (1),
+.BR mg_perf_hash_build (1),
+.BR mg_stem_idx (1),
+.BR mg_weights_build (1)
Index: /main/tags/2.25/gsdl/src/mgpp/text/mg_fast_comp_dict.cpp
===================================================================
--- /main/tags/2.25/gsdl/src/mgpp/text/mg_fast_comp_dict.cpp	(revision 21064)
+++ /main/tags/2.25/gsdl/src/mgpp/text/mg_fast_comp_dict.cpp	(revision 21064)
@@ -0,0 +1,736 @@
+/**************************************************************************
+ *
+ * mg_fast_comp_dict.cpp -- Program to generate a fast compression dictionary
+ * Copyright (C) 1994  Neil Sharman
+ *
+ * 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.
+ *
+ * $Id$
+ *
+ **************************************************************************/
+
+
+/*
+   $Log$
+   Revision 1.2  2000/01/18 03:53:23  rjmcnab
+   Fixed a couple of bugs and made building silent if needed.
+
+   Revision 1.1  2000/01/14 02:26:13  sjboddie
+   Rodgers new C++ mg
+
+   Revision 1.2  1999/10/17 23:43:26  cs025
+   Changes to eradicate Xmalloc
+
+   Revision 1.1  1999/10/11 02:57:50  cs025
+   Base install of MG-PP
+
+   Revision 1.1  1999/08/10 21:18:06  sjboddie
+   renamed mg-1.3d directory mg
+
+   Revision 1.2  1998/11/25 07:55:44  rjmcnab
+
+   Modified mg to that you can specify the stemmer you want
+   to use via a command line option. You specify it to
+   mg_passes during the build process. The number of the
+   stemmer that you used is stored within the inverted
+   dictionary header and the stemmed dictionary header so
+   the correct stemmer is used in later stages of building
+   and querying.
+
+   Revision 1.1  1998/11/17 09:34:57  rjmcnab
+   *** empty log message ***
+
+   * Revision 1.3  1994/10/20  03:56:55  tes
+   * I have rewritten the boolean query optimiser and abstracted out the
+   * components of the boolean query.
+   *
+   * Revision 1.2  1994/09/20  04:41:47  tes
+   * For version 1.1
+   *
+ */
+
+#include "sysfuncs.h"
+
+#include "huffman.h"
+#include "messages.h"
+#include "memlib.h"
+#include "netorder.h"  /* [RPAP - Jan 97: Endian Ordering] */
+
+#include "local_strings.h"
+#include "mg.h"
+#include "text.h"
+#include "invf.h"
+#include "mg_files.h"
+#include "locallib.h"
+#include "words.h"
+
+
+
+#define ALIGN_SIZE(p,t) (((p) + (sizeof(t)-1)) & (~(sizeof(t)-1)))
+
+#define WORDNO(p, base) ((((char*)(p))-((char*)(base)))/sizeof(u_char*))
+#define FIXUP(p) (fixup[WORDNO(p,buffer)/8] |= (1<<(WORDNO(p, buffer) & 7)))
+
+#define IS_FIXUP(p) ((fixup[WORDNO(p,buffer)/8] & (1<<(WORDNO(p, buffer) & 7))) != 0)
+
+#define FIXUP_VALS(vals) do {						\
+	int i;								\
+	for (i=0; i < MAX_HUFFCODE_LEN+1; i++)				\
+	  FIXUP(&vals[i]);						\
+      } while(0)
+
+
+
+static u_long mem_for_comp_dict (char *filename);
+static void load_comp_dict (char *filename);
+static void save_fast_dict (char *filename);
+static void unfixup_buffer (void);
+
+
+static void *buffer;
+static void *cur;
+static u_char *fixup;
+static u_long mem, fixup_mem;
+
+int main (int argc, char **argv)
+{
+  int ch;
+  char *filename = "";
+  opterr = 0;
+  msg_prefix = argv[0];
+  while ((ch = getopt (argc, argv, "f:d:h")) != -1)
+    switch (ch)
+      {
+      case 'f':		/* input file */
+	filename = optarg;
+	break;
+      case 'd':
+	set_basepath (optarg);
+	break;
+      case 'h':
+      case '?':
+	fprintf (stderr, "usage: %s [-f input_file] [-d data directory] [-h]\n",
+		 argv[0]);
+	exit (1);
+      }
+
+  mem = mem_for_comp_dict (filename);
+
+  fixup_mem = (ALIGN_SIZE (mem, u_char *) / sizeof (u_char *) + 7) / 8;
+
+  cur = buffer = Xmalloc (mem);
+  bzero (buffer, mem);
+  fixup = (u_char *) Xmalloc (fixup_mem);
+  bzero (fixup, fixup_mem);
+
+#ifndef SILENT
+  Message ("Estimated memory for fast_dict %u", mem);
+  Message ("Estimated memory for fixups %u", fixup_mem);
+#endif
+
+  load_comp_dict (filename);
+
+#ifndef SILENT
+  Message ("Actual memory for fast_dict %u", (char *) cur - (char *) buffer);
+#endif
+
+  if ((u_long) cur > (u_long) buffer + mem)
+    FatalError (1, "The buffer was not big enough for the dictionary");
+
+  {
+    /* [RPAP - Jan 97: Endian Ordering] */
+    compression_dict *cd = (compression_dict *) buffer;
+    int i, which;
+
+    /* cfh */
+    for (which = 0; which <= 1; which++)
+      {
+	int j;
+	
+	HTONSI(cd->cfh[which]->hd.num_codes);
+	HTONSI(cd->cfh[which]->hd.mincodelen);
+	HTONSI(cd->cfh[which]->hd.maxcodelen);
+	for (j = 0; j < MAX_HUFFCODE_LEN + 1; j++)
+	  {
+	    HTONSI(cd->cfh[which]->hd.lencount[j]);
+	    HTONUL(cd->cfh[which]->hd.min_code[j]);
+	  }
+	HTONUL(cd->cfh[which]->uncompressed_size);
+	for (j = 0; j < MAX_HUFFCODE_LEN + 1; j++)
+	  HTONUL(cd->cfh[which]->huff_words_size[j]);
+      }
+    HTONUL(cd->MemForCompDict);
+    /* ad */
+    if (cd->cdh.novel_method == MG_NOVEL_DELTA ||
+	cd->cdh.novel_method == MG_NOVEL_HYBRID)
+      for (which = 0; which <= 1; which++)
+	{
+	  int j;
+	  
+	  HTONUL(cd->ad->afh[which].num_frags);
+	  HTONUL(cd->ad->afh[which].mem_for_frags);
+	  for (j = 0; j < 33; j++)
+	    {
+	      HTONSI(cd->ad->blk_start[which][j]);
+	      HTONSI(cd->ad->blk_end[which][j]);
+	    }
+	}
+    /* cdh */
+    HTONUL(cd->cdh.dict_type);
+    HTONUL(cd->cdh.novel_method);
+    for (i = 0; i < TEXT_PARAMS; i++)
+      HTONUL(cd->cdh.params[which]);
+    HTONUL(cd->cdh.num_words[0]);
+    HTONUL(cd->cdh.num_words[1]);
+    HTONUL(cd->cdh.num_word_chars[0]);
+    HTONUL(cd->cdh.num_word_chars[1]);
+    HTONUL(cd->cdh.lookback);
+    HTONSI(cd->fast_loaded);
+  }
+
+  unfixup_buffer ();
+
+  save_fast_dict (filename);
+
+  exit (0);
+}
+
+
+
+static void 
+unfixup_buffer ()
+{
+  u_long *p;
+  for (p = (u_long *) buffer; (u_long) p < (u_long) cur; p++)
+    {
+      if (IS_FIXUP (p))
+	*p = *p - (u_long) buffer;
+    }
+}
+
+
+
+
+static u_long 
+mem_for_aux_dict (compression_dict_header * /*cdh*/, char *filename)
+{
+  int i;
+  u_long mem = sizeof (auxiliary_dict);
+  FILE *aux;
+
+  aux = open_file (filename, TEXT_DICT_AUX_SUFFIX, "rb",
+		   MAGIC_AUX_DICT, MG_ABORT);  /* [RPAP - Feb 97: WIN32 Port] */
+
+  for (i = 0; i <= 1; i++)
+    {
+      aux_frags_header afh;
+      fread (&afh, sizeof (afh), 1, aux);
+      NTOHUL(afh.num_frags);  /* [RPAP - Jan 97: Endian Ordering] */
+      NTOHUL(afh.mem_for_frags);  /* [RPAP - Jan 97: Endian Ordering] */
+      mem += afh.num_frags * sizeof (u_char *);
+      mem = ALIGN_SIZE (mem + afh.mem_for_frags, u_char *);
+      fseek (aux, afh.mem_for_frags, SEEK_CUR);
+    }
+  fclose (aux);
+
+  return mem;
+}
+
+
+
+static u_long 
+mem_for_words (FILE * dict, compression_dict_header * cdh,
+	       comp_frags_header * cfh)
+{
+  u_long mem = 0;
+  long i, lookback;
+  int ptrs_reqd = 0;
+  int mem_reqd = 0;
+
+  lookback = cdh->lookback;
+
+  for (i = cfh->hd.mincodelen; i <= cfh->hd.maxcodelen; i++)
+    {
+      ptrs_reqd += (cfh->hd.lencount[i] + ((1 << lookback) - 1)) >> lookback;
+      mem_reqd += cfh->huff_words_size[i];
+    }
+
+  mem += ptrs_reqd * sizeof (u_char *);
+  mem += (MAX_HUFFCODE_LEN + 1) * sizeof (u_char **);
+  mem += mem_reqd;
+
+  for (i = 0; i < cfh->hd.num_codes; i++)
+    {
+      register int val;
+      for (val = getc (dict) & 0xf; val; val--)
+	getc (dict);
+    }
+  return ALIGN_SIZE (mem, u_char *);
+}
+
+static u_long mem_skip_hd(FILE *dict, u_long mem)
+{ huff_data hd;
+
+  mem += sizeof (hd);
+  Read_Huffman_Data (dict, &hd, NULL, NULL);
+  if (hd.clens)
+    delete hd.clens;
+  mem += hd.num_codes * sizeof (unsigned long);
+  mem += (MAX_HUFFCODE_LEN + 1) * sizeof (unsigned long *);
+  return mem;
+}
+
+static u_long mem_read_cfh(FILE *dict, compression_dict_header *cdh, comp_frags_header *cfh, 
+			   u_long mem)
+{
+  mem += sizeof (comp_frags_header);
+  Read_cfh (dict, cfh, NULL, NULL);
+
+  /* Don't need to count the space for the clens of the huffman data */
+
+  mem += mem_for_words (dict, cdh, cfh);
+  if (cfh->hd.clens)
+    delete cfh->hd.clens;
+
+  return mem;
+}
+
+
+static u_long 
+mem_for_comp_dict (char *filename)
+{
+  u_long mem = sizeof (compression_dict);
+  compression_dict_header cdh;
+  comp_frags_header cfh;
+  FILE *dict;
+  int which;
+  int i;  /* [RPAP - Jan 97: Endian Ordering] */
+
+  dict = open_file (filename, TEXT_DICT_SUFFIX, "rb",
+		    MAGIC_DICT, MG_ABORT);  /* [RPAP - Feb 97: WIN32 Port] */
+
+  fread (&cdh, sizeof (cdh), 1, dict);
+  /* [RPAP - Jan 97: Endian Ordering] */
+  NTOHUL(cdh.dict_type);
+  NTOHUL(cdh.novel_method);
+  for (i = 0; i < TEXT_PARAMS; i++)
+    NTOHUL(cdh.params[i]);
+  NTOHUL(cdh.num_words[0]);
+  NTOHUL(cdh.num_words[1]);
+  NTOHUL(cdh.num_word_chars[0]);
+  NTOHUL(cdh.num_word_chars[1]);
+  NTOHUL(cdh.lookback);
+
+  for (which = 0; which < 2; which++)
+    switch (cdh.dict_type)
+      {
+      case MG_COMPLETE_DICTIONARY:
+	{
+	  mem = mem_read_cfh(dict, &cdh, &cfh, mem);
+	}
+	break;
+      case MG_PARTIAL_DICTIONARY:
+	{
+	  // huff_data hd;
+	  if (cdh.num_words[which])
+	    {
+	      mem = mem_read_cfh(dict, &cdh, &cfh, mem);
+	    }
+
+	  mem = mem_skip_hd(dict, mem);
+	  mem = mem_skip_hd(dict, mem);
+	}
+	break;
+      case MG_SEED_DICTIONARY:
+	{
+	  // huff_data hd;
+	  if (cdh.num_words[which])
+	    {
+	      mem = mem_read_cfh(dict, &cdh, &cfh, mem);
+	    }
+	  switch (cdh.novel_method)
+	    {
+	    case MG_NOVEL_HUFFMAN_CHARS:
+	      mem = mem_skip_hd(dict, mem);
+	      mem = mem_skip_hd(dict, mem);
+	      break;
+	    case MG_NOVEL_DELTA:
+	      break;
+	    case MG_NOVEL_HYBRID:
+	      break;
+	    }
+	  break;
+	}
+      }
+  fclose (dict);
+
+  if (cdh.novel_method == MG_NOVEL_DELTA ||
+      cdh.novel_method == MG_NOVEL_HYBRID)
+    mem += mem_for_aux_dict (&cdh, filename);
+
+  return ALIGN_SIZE (mem, u_char *);
+}
+
+
+
+void *
+getmem (u_long size, int align)
+{
+  void *res;
+  cur = (void *) (((u_long) cur + (align - 1)) & (~(align - 1)));
+  res = cur;
+  cur = (char *) cur + size;
+  if ((u_long) cur > (u_long)buffer + mem)
+    FatalError (1, "The buffer was not big enough for the dictionary");
+  return res;
+}
+
+
+
+
+
+
+
+
+
+
+
+static auxiliary_dict *
+LoadAuxDict (compression_dict_header * cdh,
+	     char *filename)
+{
+  auxiliary_dict *ad;
+  int i;
+  FILE *aux;
+
+  aux = open_file (filename, TEXT_DICT_AUX_SUFFIX, "rb",
+		   MAGIC_AUX_DICT, MG_ABORT);  /* [RPAP - Feb 97: WIN32 Port] */
+
+  ad = (auxiliary_dict *) getmem (sizeof (auxiliary_dict), sizeof (u_char *));
+
+  for (i = 0; i <= 1; i++)
+    {
+      unsigned int j;
+      u_char *pos;
+
+      fread (&ad->afh[i], sizeof (aux_frags_header), 1, aux);
+
+      /* [RPAP - Jan 97: Endian Ordering] */
+      NTOHUL(ad->afh[i].num_frags);
+      NTOHUL(ad->afh[i].mem_for_frags);
+
+      ad->word_data[i] = (u_char *) getmem (ad->afh[i].mem_for_frags, 1);
+      FIXUP (&ad->word_data[i]);
+
+      ad->words[i] = (u_char **) getmem (ad->afh[i].num_frags * sizeof (u_char *),
+			     sizeof (u_char *));
+      FIXUP (&ad->words[i]);
+
+      fread (ad->word_data[i], ad->afh[i].mem_for_frags, sizeof (u_char), aux);
+
+      pos = ad->word_data[i];
+      for (j = 0; j < ad->afh[i].num_frags; j++)
+	{
+	  ad->words[i][j] = pos;
+	  FIXUP (&ad->words[i][j]);
+	  pos += *pos + 1;
+	}
+      if (cdh->novel_method == MG_NOVEL_HYBRID)
+	{
+	  int num;
+	  num = 1;
+	  ad->blk_start[i][0] = 0;
+	  ad->blk_end[i][0] = cdh->num_words[i] - 1;
+	  while (num < 33)
+	    {
+	      ad->blk_start[i][num] = ad->blk_end[i][num - 1] + 1;
+	      ad->blk_end[i][num] = ad->blk_start[i][num] +
+		(ad->blk_end[i][num - 1] - ad->blk_start[i][num - 1]) * 2;
+	      num++;
+	    }
+	}
+    }
+  fclose (aux);
+  return (ad);
+}
+
+
+
+
+
+static u_char ***
+ReadInWords (FILE * dict, compression_dict * cd,
+	     comp_frags_header * cfh, u_char ** escape)
+{
+  int i, lookback;
+  int ptrs_reqd = 0;
+  int mem_reqd = 0;
+  int num_set[MAX_HUFFCODE_LEN + 1];
+  u_char *next_word[MAX_HUFFCODE_LEN + 1];
+  u_char **vals;
+  u_char ***values;
+  u_char word[MAXWORDLEN + 1];
+  u_char last_word[MAX_HUFFCODE_LEN + 1][MAXWORDLEN + 1];
+
+  lookback = cd->cdh.lookback;
+
+  for (i = cfh->hd.mincodelen; i <= cfh->hd.maxcodelen; i++)
+    {
+      ptrs_reqd += (cfh->hd.lencount[i] + ((1 << lookback) - 1)) >> lookback;
+      mem_reqd += cfh->huff_words_size[i];
+    }
+
+  vals = (u_char **) getmem (ptrs_reqd * sizeof (*vals), sizeof (u_char *));
+
+  values = (u_char ***) getmem ((MAX_HUFFCODE_LEN + 1) * sizeof (u_char **), sizeof (u_char **));
+
+  next_word[0] = (u_char *) getmem (mem_reqd, sizeof (char));
+
+  cd->MemForCompDict += ptrs_reqd * sizeof (*vals) +
+    (MAX_HUFFCODE_LEN + 1) * sizeof (u_char **) +
+    mem_reqd;
+
+  values[0] = vals;
+  FIXUP (&values[0]);
+  values[0][0] = next_word[0];
+  FIXUP (&values[0][0]);
+  for (i = 1; i <= cfh->hd.maxcodelen; i++)
+    {
+      int next_start = (values[i - 1] - vals) +
+      ((cfh->hd.lencount[i - 1] + ((1 << lookback) - 1)) >> lookback);
+      values[i] = &vals[next_start];
+      FIXUP (&values[i]);
+      next_word[i] = next_word[i - 1] + cfh->huff_words_size[i - 1];
+      values[i][0] = next_word[i];
+      FIXUP (&values[i][0]);
+    }
+
+  bzero ((char *) num_set, sizeof (num_set));
+
+  for (i = 0; i < cfh->hd.num_codes; i++)
+    {
+      register int val, copy;
+      register int len = cfh->hd.clens[i];
+      val = getc (dict);
+      copy = (val >> 4) & 0xf;
+      val &= 0xf;
+
+      fread (word + copy + 1, sizeof (u_char), val, dict);
+      *word = val + copy;
+
+      if ((num_set[len] & ((1 << lookback) - 1)) == 0)
+	{
+	  values[len][num_set[len] >> lookback] = next_word[len];
+	  FIXUP (&values[len][num_set[len] >> lookback]);
+	  memcpy (next_word[len], word, *word + 1);
+	  if (escape && i == cfh->hd.num_codes - 1)
+	    {
+	      *escape = next_word[len];
+	      FIXUP (escape);
+	    }
+	  next_word[len] += *word + 1;
+	}
+      else
+	{
+	  copy = prefixlen (last_word[len], word);
+	  memcpy (next_word[len] + 1, word + copy + 1, *word - copy);
+	  *next_word[len] = (copy << 4) + (*word - copy);
+	  if (escape && i == cfh->hd.num_codes - 1)
+	    {
+	      *escape = next_word[len];
+	      FIXUP (escape);
+	    }
+	  next_word[len] += (*word - copy) + 1;
+	}
+      memcpy (last_word[len], word, *word + 1);
+      num_set[len]++;
+    }
+  if (cfh->hd.clens)
+    delete cfh->hd.clens;
+  cfh->hd.clens = NULL;
+  return values;
+}
+
+
+static unsigned long **
+Generate_Fast_Huffman_Vals (huff_data * data, u_long * mem)
+{
+  int i;
+  unsigned long *fcode[MAX_HUFFCODE_LEN + 1];
+  unsigned long **values;
+  unsigned long *vals;
+
+  if (!data)
+    return (NULL);
+  vals = (unsigned long *) getmem (data->num_codes * sizeof (*vals), sizeof (long *));
+  values = (unsigned long **) getmem ((MAX_HUFFCODE_LEN + 1) * sizeof (unsigned long *),
+		   sizeof (long *));
+
+  bzero ((char *) values, (MAX_HUFFCODE_LEN + 1) * sizeof (unsigned long *));
+
+  if (mem)
+    *mem += data->num_codes * sizeof (*vals) +
+      (MAX_HUFFCODE_LEN + 1) * sizeof (unsigned long *);
+
+  fcode[0] = values[0] = &vals[0];
+  FIXUP (&values[0]);
+  for (i = 1; i <= data->maxcodelen; i++)
+    {
+      fcode[i] = values[i] = &vals[(values[i - 1] - vals) + data->lencount[i - 1]];
+      FIXUP (&values[i]);
+    }
+
+  for (i = 0; i < data->num_codes; i++)
+    if (data->clens[i])
+      *fcode[(int) (data->clens[i])]++ = i;
+  return (values);
+}
+
+
+static void load_read_huffman(FILE *dict, compression_dict *cd, int which)
+{
+  huff_data *hd;
+  u_long   **vals;
+
+  hd = (huff_data *) getmem (sizeof (huff_data), sizeof (char *));
+  cd->MemForCompDict += sizeof (huff_data);
+  Read_Huffman_Data (dict, hd, &cd->MemForCompDict, NULL);
+  vals = Generate_Fast_Huffman_Vals (hd, &cd->MemForCompDict);
+  cd->chars_huff[which] = hd;
+  FIXUP (&cd->chars_huff[which]);
+  cd->chars_vals[which] = vals;
+  FIXUP (&cd->chars_vals[which]);
+  if (hd->clens)
+    delete hd->clens;
+  hd->clens = NULL;
+}
+
+static void load_read_words(FILE *dict, compression_dict *cd, int which, int fixescape)
+{
+  cd->cfh[which] = (comp_frags_header *) getmem (sizeof (*cd->cfh[which]), sizeof (u_char *));
+  cd->MemForCompDict += sizeof (*cd->cfh[which]);
+  Read_cfh (dict, cd->cfh[which], &cd->MemForCompDict, NULL);
+
+  cd->values[which] = ReadInWords (dict, cd, cd->cfh[which], NULL);
+  FIXUP (&cd->cfh[which]);
+  FIXUP (&cd->values[which]);
+  if (fixescape)
+    { FIXUP(&cd->escape[which]);
+    }
+  else
+    {
+      cd->escape[which] = NULL;
+    }
+}
+
+static void 
+load_comp_dict (char *filename)
+{
+  FILE *dict;
+  int which;
+  compression_dict *cd;
+
+  cd = (compression_dict *) getmem (sizeof (compression_dict), sizeof (u_char *));
+  cd->fast_loaded = 1;
+
+  dict = open_file (filename, TEXT_DICT_SUFFIX, "rb",
+		    MAGIC_DICT, MG_ABORT);  /* [RPAP - Feb 97: WIN32 Port] */
+
+  Read_cdh (dict, &cd->cdh, NULL, NULL);
+
+  for (which = 0; which < 2; which++)
+    switch (cd->cdh.dict_type)
+      {
+      case MG_COMPLETE_DICTIONARY:
+	{
+	  load_read_words(dict, cd, which, 0);
+	}
+	break;
+      case MG_PARTIAL_DICTIONARY:
+	{
+	  if (cd->cdh.num_words[which])
+	    {
+	      load_read_words(dict, cd, which, 1);
+	    }
+
+	  load_read_huffman(dict, cd, which);
+	  load_read_huffman(dict, cd, which);
+	}
+	break;
+      case MG_SEED_DICTIONARY:
+	{
+	  if (cd->cdh.num_words[which])
+	    {
+	      load_read_words(dict, cd, which, 1);
+	    }
+	  switch (cd->cdh.novel_method)
+	    {
+	    case MG_NOVEL_HUFFMAN_CHARS:
+	      load_read_huffman(dict, cd, which);
+	      load_read_huffman(dict, cd, which);
+	      break;
+	    case MG_NOVEL_DELTA:
+	      break;
+	    case MG_NOVEL_HYBRID:
+	      break;
+	    }
+	  break;
+	}
+      }
+  fclose (dict);
+
+
+  if (cd->cdh.novel_method == MG_NOVEL_DELTA ||
+      cd->cdh.novel_method == MG_NOVEL_HYBRID)
+    {
+      cd->ad = LoadAuxDict (&cd->cdh, filename);
+      FIXUP (&cd->ad);
+    }
+}
+
+
+static void 
+save_fast_dict (char *filename)
+{
+  FILE *fdict;
+
+  fdict = create_file (filename, TEXT_DICT_FAST_SUFFIX, "wb",
+		       MAGIC_FAST_DICT, MG_ABORT);  /* [RPAP - Feb 97: WIN32 Port] */
+
+  {
+    u_long *p;
+    for (p = (u_long *) buffer; (u_long) p < (u_long) cur; p++)
+      {
+	if (IS_FIXUP (p))
+	  HTONUL(*p);
+      }
+  }
+
+  /* [RPAP - Jan 97: Endian Ordering] */
+  HTONUL(mem);
+  HTONUL(fixup_mem);
+
+  fwrite (&mem, sizeof (mem), 1, fdict);
+  fwrite (&fixup_mem, sizeof (fixup_mem), 1, fdict);
+
+  /* [RPAP - Jan 97: Endian Ordering] */
+  NTOHUL(mem);
+  NTOHUL(fixup_mem);
+
+  fwrite (buffer, sizeof (u_char), mem, fdict);
+  fwrite (fixup, sizeof (u_char), fixup_mem, fdict);
+
+  fclose (fdict);
+}
Index: /main/tags/2.25/gsdl/src/mgpp/text/mg_files.cpp
===================================================================
--- /main/tags/2.25/gsdl/src/mgpp/text/mg_files.cpp	(revision 21064)
+++ /main/tags/2.25/gsdl/src/mgpp/text/mg_files.cpp	(revision 21064)
@@ -0,0 +1,261 @@
+/**************************************************************************
+ *
+ * mg_files.cpp -- Routines for handling files for the auxillary programs
+ * Copyright (C) 1994  Neil Sharman
+ *
+ * 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.
+ *
+ * $Id$
+ *
+ **************************************************************************/
+
+#include "sysfuncs.h"
+#include "memlib.h"
+#include "messages.h"
+#include "netorder.h"  /* [RPAP - Jan 97: Endian Ordering] */
+
+#include "mg_files.h"
+
+
+/* This must contain a valid path without a trailing slash */
+static char *basepath = NULL;
+
+
+
+/* This sets the base path for all file operations */
+void 
+set_basepath (const char *bp)
+{
+/* [RPAP - Feb 97: WIN32 Port] */
+#ifdef __WIN32__
+  basepath = "";
+#else
+  char *s;
+  /* Free the memory for the base path if it has already been allocated */
+  if (basepath)
+    {
+      delete basepath;
+      basepath = NULL;
+    }
+
+  if (!bp || *bp == '\0')
+    bp = ".";
+
+  s = strrchr (bp, '/');
+  if (s && *(s + 1) == '\0')
+    {
+      basepath = new char[strlen (bp) + 2];
+      if (!basepath)
+	return;
+      strcpy (basepath, bp);
+      strcat (basepath, ".");
+    }
+  else
+    basepath = Xstrdup (bp);
+#endif
+}
+
+
+
+/* return the currently defined basepath */
+char *
+get_basepath (void)
+{
+  if (!basepath)
+    set_basepath (getenv ("MGDATA"));
+  return basepath;
+}
+
+
+
+/* This generates the name of a file. It places the name in the buffer
+   specified or if that is NULL it uses a static buffer. */
+char *
+make_name (const char *name, const char *suffix, char *buffer)
+{
+  static char path[512];
+  if (!buffer)
+    buffer = path;
+  if (!basepath)
+    set_basepath (getenv ("MGDATA"));
+  sprintf (buffer, FILE_NAME_FORMAT, basepath, name, suffix);  /* [RPAP - Feb 97: WIN32 Port] */
+  return buffer;
+}
+
+
+
+/* This will open the specified file and check its magic number.
+   Mode may take on the following values
+   MG_ABORT    : causes an error message to be generated and the
+   program aborted if there is an error.
+   MG_MESSAGE  : causes a message to be generated and a NULL value to
+   be returned if there is an error.
+   MG_CONTINUE : causes a NULL value to be returned if there is an error.
+
+   On success if returns the FILE *. On failure it will return a NULL value
+   and possibly generate an error message, or it will exit the program with
+   an error message.   */
+FILE *
+open_named_file (const char *name, const char *mode,
+		 u_long magic_num, int err_mode)
+{
+  unsigned long magic;
+  FILE *f = NULL;
+  char *err;
+  f = fopen (name, mode);
+
+  if (!f)
+    {
+      err = "Unable to open \"%s\"";
+      goto error;
+    }
+
+  if (magic_num)
+    {
+      if (fread (&magic, sizeof (magic), 1, f) != 1)
+	{
+	  err = "No magic number \"%s\"";
+	  goto error;
+	}
+
+      NTOHUL(magic);  /* [RPAP - Jan 97: Endian Ordering] */
+
+      if (!IS_MAGIC (magic))
+	{
+	  err = "No MG magic number \"%s\"";
+	  goto error;
+	}
+
+      if (magic != magic_num)
+	{
+	  err = "Wrong MG magic number \"%s\"";
+	  goto error;
+	}
+    }
+  return f;
+
+error:
+  if (f)
+    fclose (f);
+  if (err_mode == MG_ABORT)
+    FatalError (1, err, name);
+  if (err_mode == MG_MESSAGE)
+    Message (err, name);
+  return NULL;
+}
+
+
+
+/* This will open the specified file and check its magic number.
+   Mode may take on the following values
+   MG_ABORT    : causes an error message to be generated and the
+   program aborted if there is an error.
+   MG_MESSAGE  : causes a message to be generated and a NULL value to
+   be returned if there is an error.
+   MG_CONTINUE : causes a NULL value to be returned if there is an error.
+
+   On success if returns the FILE *. On failure it will return a NULL value
+   and possibly generate an error message, or it will exit the program with
+   an error message.   */
+FILE *
+open_file (const char *name, const char *suffix, const char *mode,
+	   u_long magic_num, int err_mode)
+{
+  char path[512];
+  if (!basepath)
+    set_basepath (getenv ("MGDATA"));
+  sprintf (path, FILE_NAME_FORMAT, basepath, name, suffix);  /* [RPAP - Feb 97: WIN32 Port] */
+  return open_named_file (path, mode, magic_num, err_mode);
+}
+
+
+
+
+
+
+/* This will create the specified file and set its magic number.
+
+   Mode may take on the following values
+   MG_ABORT    : causes an error message to be generated and the
+   program aborted if there is an error.
+   MG_MESSAGE  : causes a message to be generated and a NULL value to
+   be returned if there is an error.
+   MG_CONTINUE : causes a NULL value to be returned if there is an error.
+
+   On success if returns the FILE *. On failure it will return a NULL value
+   and possibly generate an error message, or it will exit the program with
+   an error message.   */
+FILE *
+create_named_file (const char *name, const char *mode,
+		   u_long magic_num, int err_mode)
+{
+  FILE *f = NULL;
+  char *err;
+  f = fopen (name, mode);
+
+  if (!f)
+    {
+      err = "Unable to open \"%s\"";
+      goto error;
+    }
+
+  if (magic_num)
+    HTONUL(magic_num);  /* [RPAP - Jan 97: Endian Ordering] */
+    if (fwrite (&magic_num, sizeof (magic_num), 1, f) != 1)
+      {
+	err = "Couldn't write magic number \"%s\"";
+	goto error;
+      }
+
+  return f;
+
+error:
+  if (f)
+    fclose (f);
+  if (err_mode == MG_ABORT)
+    FatalError (1, err, name);
+  if (err_mode == MG_MESSAGE)
+    Message (err, name);
+  return NULL;
+}
+
+
+
+
+
+
+
+/* This will create the specified file and set its magic number.
+
+   Mode may take on the following values
+   MG_ABORT    : causes an error message to be generated and the
+   program aborted if there is an error.
+   MG_MESSAGE  : causes a message to be generated and a NULL value to
+   be returned if there is an error.
+   MG_CONTINUE : causes a NULL value to be returned if there is an error.
+
+   On success if returns the FILE *. On failure it will return a NULL value
+   and possibly generate an error message, or it will exit the program with
+   an error message.   */
+FILE *
+create_file (const char *name, const char *suffix, const char *mode,
+	     u_long magic_num, int err_mode)
+{
+  char path[512];
+  if (!basepath)
+    set_basepath (getenv ("MGDATA"));
+  sprintf (path, FILE_NAME_FORMAT, basepath, name, suffix);  /* [RPAP - Feb 97: WIN32 Port] */
+  return create_named_file (path, mode, magic_num, err_mode);
+}
Index: /main/tags/2.25/gsdl/src/mgpp/text/mg_files.h
===================================================================
--- /main/tags/2.25/gsdl/src/mgpp/text/mg_files.h	(revision 21064)
+++ /main/tags/2.25/gsdl/src/mgpp/text/mg_files.h	(revision 21064)
@@ -0,0 +1,345 @@
+/**************************************************************************
+ *
+ * mg_files.h -- Routines for handling files for the auxillary programs
+ * Copyright (C) 1994  Neil Sharman
+ *
+ * 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.
+ *
+ * $Id$
+ *
+ **************************************************************************/
+
+#ifndef MG_FILES_H
+#define MG_FILES_H
+
+#include "sysfuncs.h"
+
+/* Magic numbers for the different types of files */
+
+#define GEN_MAGIC(a,b,c,d) ((unsigned long)(((a)<<24) + ((b)<<16) + \
+					    ((c)<<8) + (d)))
+
+#define MAGIC_XXXX		GEN_MAGIC('M','G', 0 , 0)
+#define MAGIC_STATS_DICT	GEN_MAGIC('M','G','S','D')
+#define MAGIC_AUX_DICT		GEN_MAGIC('M','G','A','D')
+#define MAGIC_FAST_DICT		GEN_MAGIC('M','G','F','D')
+#define MAGIC_DICT		GEN_MAGIC('M','G','D', 0 )
+#define MAGIC_STEM_BUILD	GEN_MAGIC('M','G','S', 0 )
+#define MAGIC_HASH		GEN_MAGIC('M','G','H', 0 )
+#define MAGIC_STEM		GEN_MAGIC('M','G','s', 0 )
+#define MAGIC_CHUNK		GEN_MAGIC('M','G','C', 0 )
+#define MAGIC_CHUNK_TRANS	GEN_MAGIC('M','G','c', 0 )
+#define MAGIC_TEXT		GEN_MAGIC('M','G','T', 0 )
+#define MAGIC_TEXI		GEN_MAGIC('M','G','t', 0 )
+#define MAGIC_TEXT_LEVELS	GEN_MAGIC('M','G','t','L')
+#define MAGIC_TEXI_WGT		GEN_MAGIC('M','G','t','W')
+#define MAGIC_INVF		GEN_MAGIC('M','G','I', 0 )
+#define MAGIC_INVF_LEVELS	GEN_MAGIC('M','G','I','L')
+#define MAGIC_INVI		GEN_MAGIC('M','G','i', 0 )
+#define MAGIC_WGHT		GEN_MAGIC('M','G','W', 0 )
+#define MAGIC_WGHT_APPROX	GEN_MAGIC('M','G','w', 0 )
+#define MAGIC_PARAGRAPH		GEN_MAGIC('M','G','P', 0 )
+/* [RPAP - Jan 97: Stem Index Change] */
+#define MAGIC_STEM_1            GEN_MAGIC('M','G','s','1')
+#define MAGIC_STEM_2            GEN_MAGIC('M','G','s','2')
+#define MAGIC_STEM_3            GEN_MAGIC('M','G','s','3')
+
+#define IS_MAGIC(a) ((((u_long)(a)) & 0xffff0000) == MAGIC_XXXX)
+
+
+/* err_mode values for open_file and create_file */
+#define MG_ABORT 0
+#define MG_MESSAGE 1
+#define MG_CONTINUE 2
+
+
+
+
+
+/* File suffixes */
+
+
+/* The compression dictionary built by txt.pass1 */
+#ifdef SHORT_SUFFIX
+# define TEXT_STATS_DICT_SUFFIX	 ".tsd"
+#else
+# define TEXT_STATS_DICT_SUFFIX	 ".text.stats"
+#endif
+
+/* The compression dictionary built by text.pass1 and comp_dict.process */
+#ifdef SHORT_SUFFIX
+# define TEXT_DICT_SUFFIX	 ".td"
+#else
+# define TEXT_DICT_SUFFIX	 ".text.dict"
+#endif
+
+/* The compression dictionary built by mg_make_fast_dict */
+#ifdef SHORT_SUFFIX
+# define TEXT_DICT_FAST_SUFFIX	 ".tdf"
+#else
+# define TEXT_DICT_FAST_SUFFIX	 ".text.dict.fast"
+#endif
+
+/* The auxilary dictionary built by text.pass2 */
+#ifdef SHORT_SUFFIX
+# define TEXT_DICT_AUX_SUFFIX	 ".tda"
+#else
+# define TEXT_DICT_AUX_SUFFIX	 ".text.dict.aux"
+#endif
+
+/* The compressed text build by text.pass2 */
+#ifdef SHORT_SUFFIX
+# define TEXT_SUFFIX		 ".t"
+#else
+# define TEXT_SUFFIX		 ".text"
+#endif
+
+/* The combined compressed text index and document weight file */
+#ifdef SHORT_SUFFIX
+# define TEXT_IDX_WGT_SUFFIX	 ".tiw"
+#else
+# define TEXT_IDX_WGT_SUFFIX	 ".text.idx.wgt"
+#endif
+
+/* The compressed text index file */
+#ifdef SHORT_SUFFIX
+# define TEXT_IDX_SUFFIX	 	".ti"
+#else
+# define TEXT_IDX_SUFFIX	 	".text.idx"
+#endif
+
+/* The document levels in the text */
+#ifdef SHORT_SUFFIX
+# define TEXT_LEVEL_SUFFIX	 	".tl"
+#else
+# define TEXT_LEVEL_SUFFIX	 	".text.level"
+#endif
+
+/* The dictionary of stemmed words build by invf.pass1 and ivf.pass1 */
+#ifdef SHORT_SUFFIX
+# define INVF_DICT_SUFFIX         ".id"
+#else
+# define INVF_DICT_SUFFIX         ".invf.dict"
+#endif
+
+/* The dictionary of stemmed words build by stem.process */
+#ifdef SHORT_SUFFIX
+# define INVF_DICT_BLOCKED_SUFFIX ".idb"
+#else
+# define INVF_DICT_BLOCKED_SUFFIX ".invf.dict.blocked"
+#endif
+
+/* The exact document weights file build by make.weights, invf.pass2,
+   or ivf.pass2 */
+#ifdef SHORT_SUFFIX
+# define WEIGHTS_SUFFIX           ".w"
+#else
+# define WEIGHTS_SUFFIX           ".weight"
+#endif
+
+/* The approximate weights file built by make.weights */
+#ifdef SHORT_SUFFIX
+# define APPROX_WEIGHTS_SUFFIX    ".wa"
+#else
+# define APPROX_WEIGHTS_SUFFIX    ".weight.approx"
+#endif
+
+/* The inverted file build by invf.pass2 or ivf.pass2 */
+#ifdef SHORT_SUFFIX
+# define INVF_SUFFIX              ".i"
+#else
+# define INVF_SUFFIX              ".invf"
+#endif
+
+/* The level information for the inverted text */
+#ifdef SHORT_SUFFIX
+# define INVF_LEVEL_SUFFIX              ".il"
+#else
+# define INVF_LEVEL_SUFFIX              ".invf.level"
+#endif
+
+/* The inverted file index build by invf.pass2 or ivf.pass2 */
+#ifdef SHORT_SUFFIX
+# define INVF_IDX_SUFFIX          ".ii"
+#else
+# define INVF_IDX_SUFFIX          ".invf.idx"
+#endif
+
+/* The inverted file chunk descriptor built by ivf.pass1 */
+#ifdef SHORT_SUFFIX
+# define INVF_CHUNK_SUFFIX        ".ic"
+#else
+# define INVF_CHUNK_SUFFIX        ".invf.chunk"
+#endif
+
+/* The word index translation file built by ivf.pass1 */
+#ifdef SHORT_SUFFIX
+# define INVF_CHUNK_TRANS_SUFFIX  ".ict"
+#else
+# define INVF_CHUNK_TRANS_SUFFIX  ".invf.chunk.trans"
+#endif
+
+/* The hashed stemmed dictionary built by make.perf_hash */
+#ifdef SHORT_SUFFIX
+# define INVF_DICT_HASH_SUFFIX    ".idh"
+#else
+# define INVF_DICT_HASH_SUFFIX    ".invf.dict.hash"
+#endif
+
+/* The paragraph descriptior file built by invf.pass1 or ivf.pass1 */
+#ifdef SHORT_SUFFIX
+# define INVF_PARAGRAPH_SUFFIX    ".ip"
+#else
+# define INVF_PARAGRAPH_SUFFIX    ".invf.paragraph"
+#endif
+
+/* The trace file build by mg.builder. */
+#ifdef SHORT_SUFFIX
+# define TRACE_SUFFIX             ".trc"
+#else
+# define TRACE_SUFFIX             ".trace"
+#endif
+
+/* The compression stats file build by mg.builder. */
+#ifdef SHORT_SUFFIX
+# define COMPRESSION_STATS_SUFFIX ".cs"
+#else
+# define COMPRESSION_STATS_SUFFIX ".compression.stats"
+#endif
+
+/* [RPAP - Jan 97: Stem Index Change] */
+/* The casefolded index into the stemmed dictionary */
+#ifdef SHORT_SUFFIX
+# define INVF_DICT_BLOCKED_1_SUFFIX ".ib1"
+#else
+# define INVF_DICT_BLOCKED_1_SUFFIX ".invf.dict.blocked.1"
+#endif
+
+/* [RPAP - Jan 97: Stem Index Change] */
+/* The stemmed index into the stemmed dictionary */
+#ifdef SHORT_SUFFIX
+# define INVF_DICT_BLOCKED_2_SUFFIX ".ib2"
+#else
+# define INVF_DICT_BLOCKED_2_SUFFIX ".invf.dict.blocked.2"
+#endif
+
+/* [RPAP - Jan 97: Stem Index Change] */
+/* The casefolded and stemmed  index into the stemmed dictionary */
+#ifdef SHORT_SUFFIX
+# define INVF_DICT_BLOCKED_3_SUFFIX ".ib3"
+#else
+# define INVF_DICT_BLOCKED_3_SUFFIX ".invf.dict.blocked.3"
+#endif
+
+/* [RPAP - Feb 97: WIN32 Port] */
+#ifdef __WIN32__
+#define FILE_NAME_FORMAT "%s%s%s"
+#else
+#define FILE_NAME_FORMAT "%s/%s%s"
+#endif
+
+
+/* This sets the base path for all file operations */
+void set_basepath (const char *bp);
+
+
+/* return the currently defined basepath */
+char *get_basepath (void);
+
+
+
+
+/* This generates the name of a file. It places the name in the buffer
+   specified or if that is NULL it uses a static buffer. */
+char *make_name (const char *name, const char *suffix, char *buffer);
+
+
+
+
+
+
+
+/* This will open the specified file and check its magic number.
+   Mode may take on the following values
+   MG_ABORT    : causes an error message to be generated and the
+   program aborted if there is an error.
+   MG_MESSAGE  : causes a message to be generated and a NULL value to
+   be returned if there is an error.
+   MG_CONTINUE : causes a NULL value to be returned if there is an error.
+
+   On success if returns the FILE *. On failure it will return a NULL value
+   and possibly generate an error message, or it will exit the program with
+   an error message.   */
+FILE *open_named_file (const char *name, const char *mode,
+		       u_long magic_num, int err_mode);
+
+
+
+
+/* This will open the specified file and check its magic number.
+
+   err_mode may take on the following values
+   MG_ABORT    : causes an error message to be generated and the
+   program aborted if there is an error.
+   MG_MESSAGE  : causes a message to be generated and a NULL value to
+   be returned if there is an error.
+   MG_CONTINUE : causes a NULL value to be returned if there is an error.
+
+   On success if returns the FILE *. On failure it will return a NULL value
+   and possibly generate an error message, or it will exit the program with
+   an error message.   */
+FILE *open_file (const char *name, const char *suffix, const char *mode,
+		 u_long magic_num, int err_mode);
+
+
+
+
+
+/* This will create the specified file and set its magic number.
+
+   Mode may take on the following values
+   MG_ABORT    : causes an error message to be generated and the
+   program aborted if there is an error.
+   MG_MESSAGE  : causes a message to be generated and a NULL value to
+   be returned if there is an error.
+   MG_CONTINUE : causes a NULL value to be returned if there is an error.
+
+   On success if returns the FILE *. On failure it will return a NULL value
+   and possibly generate an error message, or it will exit the program with
+   an error message.   */
+FILE *create_named_file (const char *name, const char *mode,
+			 u_long magic_num, int err_mode);
+
+
+
+/* This will create the specified file and set its magic number.
+
+   err_mode may take on the following values
+   MG_ABORT    : causes an error message to be generated and the
+   program aborted if there is an error.
+   MG_MESSAGE  : causes a message to be generated and a NULL value to
+   be returned if there is an error.
+   MG_CONTINUE : causes a NULL value to be returned if there is an error.
+
+   On success if returns the FILE *. On failure it will return a NULL value
+   and possibly generate an error message, or it will exit the program with
+   an error message.   */
+FILE *create_file (const char *name, const char *suffix, const char *mode,
+		   u_long magic_num, int err_mode);
+
+
+
+
+#endif
Index: /main/tags/2.25/gsdl/src/mgpp/text/mg_invf_dict.1
===================================================================
--- /main/tags/2.25/gsdl/src/mgpp/text/mg_invf_dict.1	(revision 21064)
+++ /main/tags/2.25/gsdl/src/mgpp/text/mg_invf_dict.1	(revision 21064)
@@ -0,0 +1,80 @@
+.\"------------------------------------------------------------
+.\" Id - set Rv,revision, and Dt, Date using rcs-Id tag.
+.de Id
+.ds Rv \\$3
+.ds Dt \\$4
+..
+.Id $Id$
+.\"------------------------------------------------------------
+.TH mg_invf_dict 1 \*(Dt CITRI
+.SH NAME
+mg_invf_dict \- build an `on-disk' stemmed dictionary
+.SH SYNOPSIS
+.B mg_invf_dict
+[
+.B \-h
+]
+[
+.BI \-b " entries-per-block"
+]
+.if n .ti +13n
+[
+.BI \-d " directory"
+]
+.BI \-f " name"
+.SH DESCRIPTION
+.B mg_invf_dict
+builds an `on-disk' stemmed dictionary from the
+compressed stemmed dictionary that can be used during querying.
+Each entry in the dictionary contains the disk
+pointer to the associated inverted file entry, and various other pieces
+of information about the stemmed word. The dictionary is blocked with
+each block containing the same number of entries (not the same size).
+.SH OPTIONS
+Options may appear in any order.
+.TP "\w'\fB\-d\fP \fIdirectoryyyyyyyy\fP'u+2n"
+.B \-h
+This displays a usage line on
+.IR stderr .
+.TP
+.BI \-b " entries-per-block"
+The dictionary is stored in blocks on disk; this option is used to 
+specify the number of entries per block. The default is 16.
+.TP
+.BI \-d " directory"
+This specifies the directory where the document collection can be found.
+.TP
+.BI \-f " name"
+This specifies the base name of the document collection.
+.SH ENVIRONMENT
+.TP "\w'\fBMGDATA\fP'u+2n"
+.SB MGDATA
+If this environment variable exists, then its value is used as the
+default directory where the mg
+collection files are.  If this variable does not exist, then the
+directory \*(lq\fB.\fP\*(rq is used by default.  The command line
+option
+.BI \-d " directory"
+overrides the directory in
+.BR MGDATA .
+.SH FILES
+.TP 20
+.B *.invf
+Inverted file.
+.TP
+.B *.invf.dict
+Compressed stemmed dictionary.
+.TP
+.B *.invf.dict.blocked
+The `on-disk' stemmed dictionary.
+.TP
+.B *.invf.idx
+The index into the inverted file.
+.SH "SEE ALSO"
+.na
+.BR mg_compression_dict (1),
+.BR mg_fast_comp_dict (1),
+.BR mg_passes (1),
+.BR mg_perf_hash_build (1),
+.BR mg_stem_idx (1),
+.BR mg_weights_build (1)
Index: /main/tags/2.25/gsdl/src/mgpp/text/mg_invf_dict.cpp
===================================================================
--- /main/tags/2.25/gsdl/src/mgpp/text/mg_invf_dict.cpp	(revision 21064)
+++ /main/tags/2.25/gsdl/src/mgpp/text/mg_invf_dict.cpp	(revision 21064)
@@ -0,0 +1,236 @@
+/**************************************************************************
+ *
+ * mg_invf_dict.cpp -- Program to build the blocked stemmed dictionary
+ * Copyright (C) 1999  Rodger McNab
+ *
+ * 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.
+ *
+ * $Id$
+ *
+ **************************************************************************/
+
+#include "sysfuncs.h"
+#include "messages.h"
+
+#include "mg_files.h"
+#include "invf.h"
+
+/*
+   $Log$
+   Revision 1.2  2000/01/18 03:53:24  rjmcnab
+   Fixed a couple of bugs and made building silent if needed.
+
+   Revision 1.1  2000/01/14 02:26:16  sjboddie
+   Rodgers new C++ mg
+
+ */
+
+
+static void process_files (char *filename, unsigned long entriesPerBlock) {
+  // open the dictionary
+  FILE *dictFile = open_file (filename, INVF_DICT_SUFFIX, "rb",
+			      MAGIC_STEM_BUILD, MG_ABORT);
+  invf_dict_header idh;
+  idh.Read (dictFile);
+
+  // open the inverted index file
+  FILE *invfIdxFile = open_file (filename, INVF_IDX_SUFFIX, "rb",
+				 MAGIC_INVI, MG_ABORT);
+
+  // create the blocked dictionary
+  FILE *blockDictFile = create_file (filename, INVF_DICT_BLOCKED_SUFFIX, "wb",
+				     MAGIC_STEM, MG_ABORT);
+  block_dict_header bdh;
+  bdh.lookback = idh.lookback;
+  bdh.word_dict_start = idh.word_dict_start;
+  bdh.word_dict_size = idh.word_dict_size;
+  bdh.tag_dict_start = idh.tag_dict_start;
+  bdh.tag_dict_size = idh.tag_dict_size;
+  bdh.num_docs = idh.num_docs;
+  bdh.num_frags = idh.num_frags;
+  bdh.num_words = idh.num_words;
+  bdh.total_bytes = idh.total_bytes;
+  bdh.index_string_bytes = idh.index_string_bytes;
+  bdh.num_levels = idh.num_levels;
+  bdh.Write (blockDictFile);
+
+  
+  // write out the word part of the dictionary
+
+  bdh.entries_per_wblk = entriesPerBlock;
+  bdh.max_wblk_size = 0;
+  bdh.wblk_start = ftell (blockDictFile);
+  
+  fseek (dictFile, idh.word_dict_start, SEEK_SET);
+
+  block_idx wordIdx;
+  word_block_dict_el wordBlockEl;
+  wordBlockEl.SetNumLevels (idh.num_levels);
+  
+  
+  unsigned long wordNum;
+  unsigned long wordInvfPtr;
+  UCArray lastEl;
+  word_dict_el wordEl;
+  wordEl.SetNumLevels (idh.num_levels);
+  for (wordNum=0; wordNum<idh.word_dict_size; wordNum++) {
+    // read in the next word and inverted file pointer
+    wordEl.Read (dictFile, idh.num_levels);
+    ReadUL (invfIdxFile, wordInvfPtr);
+
+    // remember this word (and position) if this is the start
+    // of a new block
+    if (wordNum % entriesPerBlock == 0) {
+      block_idx_info elIdx;
+      elIdx.el = wordEl.el;
+      elIdx.block_ptr = ftell (blockDictFile);
+
+      // see if this block is the longest so far
+      if (wordIdx.size() > 0) {
+	unsigned long blockLen = elIdx.block_ptr -
+	  (*(wordIdx.end()-1)).block_ptr;
+	if (blockLen > bdh.max_wblk_size) bdh.max_wblk_size = blockLen;
+      }
+      
+      wordIdx.push_back (elIdx);
+      lastEl.erase (lastEl.begin(), lastEl.end()); // output full word
+    }
+
+    // copy the information for this word
+    wordBlockEl.el = wordEl.el;
+    wordBlockEl.frag_occur = wordEl.frag_occur;
+    wordBlockEl.freq = wordEl.freq;
+    wordBlockEl.invf_ptr = wordInvfPtr;
+    unsigned long tempI;
+    for (tempI=0; tempI<idh.num_levels; tempI++)
+      wordBlockEl.levelFreqs[tempI] = wordEl.levelFreqs[tempI];
+
+    // write out the word
+    wordBlockEl.Write (blockDictFile, &lastEl, idh.num_levels);
+
+    lastEl = wordBlockEl.el;
+  }
+
+
+  // write out the tag part of the dictionary
+
+  bdh.entries_per_tblk = entriesPerBlock;
+  bdh.max_tblk_size = 0;
+  bdh.tblk_start = ftell (blockDictFile);
+  
+  fseek (dictFile, idh.tag_dict_start, SEEK_SET);
+
+  block_idx tagIdx;
+  block_dict_el tagBlockEl;
+  
+  unsigned long tagNum;
+  unsigned long tagInvfPtr;
+  dict_el tagEl;
+  lastEl.erase (lastEl.begin(), lastEl.end());
+  for (tagNum=0; tagNum<idh.tag_dict_size; tagNum++) {
+    // read in the next tag and inverted file pointer
+    tagEl.Read (dictFile);
+    ReadUL (invfIdxFile, tagInvfPtr);
+
+    // remember this tag (and position) if this is the start
+    // of a new block
+    if (tagNum % entriesPerBlock == 0) {
+      block_idx_info elIdx;
+      elIdx.el = tagEl.el;
+      elIdx.block_ptr = ftell (blockDictFile);
+
+      // see if this block is the longest so far
+      if (tagIdx.size() > 0) {
+	unsigned long blockLen = elIdx.block_ptr -
+	  (*(tagIdx.end()-1)).block_ptr;
+	if (blockLen > bdh.max_tblk_size) bdh.max_tblk_size = blockLen;
+      }
+      
+      tagIdx.push_back (elIdx);
+      lastEl.erase (lastEl.begin(), lastEl.end()); // output full word
+    }
+
+    // copy the information for this tag
+    tagBlockEl.el = tagEl.el;
+    tagBlockEl.frag_occur = tagEl.frag_occur;
+    tagBlockEl.freq = tagEl.freq;
+    tagBlockEl.invf_ptr = tagInvfPtr;
+
+    // write out the tag
+    tagBlockEl.Write (blockDictFile, &lastEl);
+
+    lastEl = tagBlockEl.el;
+  }
+
+
+  // write out the element indexes
+  bdh.num_wblks = wordIdx.size();
+  bdh.wblk_idx_start = ftell (blockDictFile);
+  WriteBlockIdx (blockDictFile, wordIdx);
+  
+  bdh.num_tblks = tagIdx.size();
+  bdh.tblk_idx_start = ftell (blockDictFile);
+  WriteBlockIdx (blockDictFile, tagIdx);
+
+  // write out the blocked dictionary header
+  fseek (blockDictFile, sizeof(unsigned long), SEEK_SET);
+  bdh.Write (blockDictFile);
+
+
+  // close open files
+  fclose (blockDictFile);
+  fclose (invfIdxFile);
+  fclose (dictFile);
+  
+  // print out information
+#ifndef SILENT
+  Message ("Max word block size = %d\n", bdh.max_wblk_size);
+  Message ("Max tag block size = %d\n", bdh.max_tblk_size);
+  Message ("Number of word blocks written = %d\n", bdh.num_wblks);
+  Message ("Number of tag blocks written = %d\n", bdh.num_tblks);
+#endif
+}
+
+
+int main (int argc, char **argv) {
+  unsigned long entriesPerBlock = 16;
+  char *filename = "";
+  int ch;
+  msg_prefix = argv[0];
+  opterr = 0;
+
+  while ((ch = getopt (argc, argv, "f:d:b:h")) != -1) {
+    switch (ch) {
+    case 'f':		// input file
+      filename = optarg;
+      break;
+    case 'd':
+      set_basepath (optarg);
+      break;
+    case 'b':
+      entriesPerBlock = atoi (optarg);
+      break;
+    case 'h':
+    case '?':
+      fprintf (stderr, "usage: %s [-f input_file] "
+	       "[-d data directory] [-b entries-per-block] "
+	       "[-h]\n", argv[0]);
+      exit (1);
+    }
+  }
+
+  process_files (filename, entriesPerBlock);
+  return 0;
+}
Index: /main/tags/2.25/gsdl/src/mgpp/text/mg_invf_dict_dump.cpp
===================================================================
--- /main/tags/2.25/gsdl/src/mgpp/text/mg_invf_dict_dump.cpp	(revision 21064)
+++ /main/tags/2.25/gsdl/src/mgpp/text/mg_invf_dict_dump.cpp	(revision 21064)
@@ -0,0 +1,137 @@
+/**************************************************************************
+ *
+ * mg_invf_dict_dump.cpp -- Program to printthe various inverted dictionaries
+ * Copyright (C) 1999  Rodger McNab
+ *
+ * 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.
+ *
+ * $Id$
+ *
+ **************************************************************************/
+
+#include "sysfuncs.h"
+#include "messages.h"
+
+#include "mg_files.h"
+#include "invf.h"
+
+/*
+   $Log$
+   Revision 1.1  2000/01/14 02:17:51  sjboddie
+   Rodgers new C++ mg
+
+ */
+
+
+static void process_files (char *filename,
+			   bool printHeader,
+			   bool printWords,
+			   bool printTags) {
+  // open the dictionary
+  FILE *dictFile = open_file (filename, INVF_DICT_SUFFIX, "rb",
+			      MAGIC_STEM_BUILD, MG_ABORT);
+  invf_dict_header idh;
+  idh.Read (dictFile);
+
+  // print the information from the inverted dictionary file header
+  if (printHeader) {
+    cout << "lookback: " << idh.lookback << "\n";
+    cout << "word_dict_start: " << idh.word_dict_start << "\n";
+    cout << "word_dict_size: " << idh.word_dict_size << "\n";
+    cout << "tag_dict_start: " << idh.tag_dict_start << "\n";
+    cout << "tag_dict_size: " << idh.tag_dict_size << "\n";
+    cout << "num_docs: " << idh.num_docs << "\n";
+    cout << "num_frags: " << idh.num_frags << "\n";
+    cout << "num_words: " << idh.num_words << "\n";
+    cout << "total_bytes: " << idh.total_bytes << "\n";
+    cout << "index_string_bytes: " << idh.index_string_bytes << "\n";
+    cout << "num_levels: " << idh.num_levels << "\n";
+
+    cout << "\n";
+  }
+
+
+  if (printWords) {
+    fseek (dictFile, idh.word_dict_start, SEEK_SET);
+    
+    unsigned long wordNum;
+    word_dict_el wordEl;
+    wordEl.SetNumLevels (idh.num_levels);
+    for (wordNum=0; wordNum<idh.word_dict_size; wordNum++) {
+      wordEl.Read (dictFile, idh.num_levels);
+      cout << "\"" << wordEl.el << "\"\n";// (" << wordNum << ")\n";
+    }
+    
+    cout << "\n";
+  }
+
+  // write out the tag part of the dictionary
+  if (printTags) {
+    fseek (dictFile, idh.tag_dict_start, SEEK_SET);
+    
+    unsigned long tagNum;
+    dict_el tagEl;
+    for (tagNum=0; tagNum<idh.tag_dict_size; tagNum++) {
+      // read in the next tag and inverted file pointer
+      tagEl.Read (dictFile);
+      
+      cout << "\"" << tagEl.el << "\" (" << tagNum << ")\n";
+    }
+  }
+  
+  // close open files
+  fclose (dictFile);
+}
+
+
+int main (int argc, char **argv) {
+  char *filename = "";
+  int ch;
+  msg_prefix = argv[0];
+  opterr = 0;
+
+  bool printHeader = false;
+  bool printWords = false;
+  bool printTags = false;
+
+  while ((ch = getopt (argc, argv, "f:d:rwth")) != -1) {
+    switch (ch) {
+    case 'f':		// input file
+      filename = optarg;
+      break;
+    case 'd':
+      set_basepath (optarg);
+      break;
+    case 'r':
+      printHeader = true;
+      break;
+    case 'w':
+      printWords = true;
+      break;
+    case 't':
+      printTags = true;
+      break;
+    case 'h':
+    case '?':
+      fprintf (stderr, "usage: %s [-f input_file] "
+	       "[-d data directory] "
+	       "[-h]\n", argv[0]);
+      exit (1);
+    }
+  }
+
+  process_files (filename, printHeader, printWords, printTags);
+  return 0;
+}
Index: /main/tags/2.25/gsdl/src/mgpp/text/mg_invf_dump.cpp
===================================================================
--- /main/tags/2.25/gsdl/src/mgpp/text/mg_invf_dump.cpp	(revision 21064)
+++ /main/tags/2.25/gsdl/src/mgpp/text/mg_invf_dump.cpp	(revision 21064)
@@ -0,0 +1,232 @@
+/**************************************************************************
+ *
+ * mg_invf_dump.cpp -- Program to dump uot an inverted fil
+ * Copyright (C) 1994  Neil Sharman
+ *
+ * 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.
+ *
+ * $Id$
+ *
+ **************************************************************************/
+
+#include "sysfuncs.h"
+
+#include "messages.h"
+#include "bitio_m_stdio.h"
+#include "bitio_gen.h"
+#include "netorder.h"  /* [RPAP - Jan 97: Endian Ordering] */
+
+#include "mg_files.h"
+#include "locallib.h"
+#include "words.h"
+#include "invf.h"
+#include "WordData.h"
+
+/*
+   $Log$
+   Revision 1.1  2000/01/14 02:26:17  sjboddie
+   Rodgers new C++ mg
+
+   Revision 1.1  1999/10/11 02:57:55  cs025
+   Base install of MG-PP
+
+   Revision 1.1  1999/08/10 21:18:09  sjboddie
+   renamed mg-1.3d directory mg
+
+   Revision 1.2  1998/11/25 07:55:46  rjmcnab
+
+   Modified mg to that you can specify the stemmer you want
+   to use via a command line option. You specify it to
+   mg_passes during the build process. The number of the
+   stemmer that you used is stored within the inverted
+   dictionary header and the stemmed dictionary header so
+   the correct stemmer is used in later stages of building
+   and querying.
+
+   Revision 1.1  1998/11/17 09:35:05  rjmcnab
+   *** empty log message ***
+
+   * Revision 1.3  1994/11/29  00:32:01  tes
+   * Committing the new merged files and changes.
+   *
+   * Revision 1.2  1994/09/20  04:41:50  tes
+   * For version 1.1
+   *
+ */
+
+
+static void PrintInvfWord (FILE *invfFile,
+			   invf_dict_header &idh,
+			   invf_file_header &ifh,
+			   word_dict_el &wordEl,
+			   unsigned long wordStart) {
+  cout << wordEl.frag_occur << " \"" << wordEl.el << "\"\n";
+  
+  // seek to the appropriate place in the inverted file
+  fseek (invfFile, wordStart, SEEK_SET);
+
+  stdio_bitio_buffer buffer(invfFile);
+  
+  unsigned long B = BIO_Bblock_Init (idh.num_frags, wordEl.frag_occur);
+  unsigned long fragNum = 0;
+  unsigned long i;
+  for (i=0; i<wordEl.frag_occur; i++) {
+    unsigned long delta = buffer.bblock_decode (B, NULL);
+    fragNum += delta;
+    cout << " " << fragNum;
+    
+    if (!ifh.word_level_index ) {
+      unsigned long count = buffer.gamma_decode (NULL);
+      cout << "(" << count << ")";
+    } else {
+      cout << "(1)";
+    }
+  }
+
+  cout << "\n";
+  
+  buffer.done();
+}
+
+static void PrintInvfTag (FILE *invfFile,
+			  invf_dict_header &idh,
+			  invf_file_header &/*ifh*/,
+			  dict_el &tagEl,
+			  unsigned long tagStart) {
+  cout << tagEl.frag_occur << " \"<" << tagEl.el << ">\"\n";
+  
+  // seek to the appropriate place in the inverted file
+  fseek (invfFile, tagStart, SEEK_SET);
+
+  stdio_bitio_buffer buffer(invfFile);
+  
+  unsigned long pTag = tagEl.frag_occur*2;
+  unsigned long B = BIO_Bblock_Init (idh.num_frags+pTag, pTag);
+  unsigned long fragNum = 0;
+  unsigned long i;
+  for (i=0; i<tagEl.frag_occur; i++) {
+    unsigned long delta = buffer.bblock_decode (B, NULL)-1;
+    fragNum += delta;
+    cout << " " << fragNum;
+    cout << "-";
+    delta = buffer.bblock_decode (B, NULL)-1;
+    fragNum += delta;
+    cout << fragNum;
+  }
+
+  cout << "\n";
+  
+  buffer.done();
+}
+
+static void PrintHeaderInfo (invf_dict_header &idh,
+			     invf_file_header &ifh) {
+  cerr << "Lookback:         " << idh.lookback << "\n";
+  cerr << "Word Dict Size:   " << idh.word_dict_size << "\n";
+  cerr << "Tag Dict Size:    " << idh.tag_dict_size << "\n";
+  cerr << "Num Documents:    " << idh.num_docs << "\n";
+  cerr << "Num Fragments:    " << idh.num_frags << "\n";
+  cerr << "Num Words:        " << idh.num_words << "\n";
+
+  cerr << "Skip Mode:        " << ifh.skip_mode << "\n";
+  cerr << "Word Level Index: " << ifh.word_level_index << "\n";
+
+  cerr << "\n";
+}
+
+
+static void process_files (char *filename) {
+  // open the dictionary
+  FILE *dictFile = open_file (filename, INVF_DICT_SUFFIX, "rb",
+			MAGIC_STEM_BUILD, MG_ABORT);
+  invf_dict_header idh;
+  idh.Read (dictFile);
+
+  // open the inverted file
+  FILE *invfFile = open_file (filename, INVF_SUFFIX, "rb",
+			MAGIC_INVF, MG_ABORT);
+  
+  invf_file_header ifh;
+  ifh.Read (invfFile);
+
+  if (ifh.skip_mode != SKIP_MODE_NO_SKIPS)
+    FatalError (1, "The invf file contains skips. Unable to dump.");
+
+  // print out header information
+  PrintHeaderInfo (idh, ifh);
+  
+  // open the inverted index
+  FILE *invfIdxFile = open_file (filename, INVF_IDX_SUFFIX, "rb",
+				 MAGIC_INVI, MG_ABORT);
+
+  // go to the start of the word dictionary
+  fseek (dictFile, idh.word_dict_start, SEEK_SET);
+
+  // process all the words
+  unsigned long wordNum;
+  unsigned long wordStart;
+  word_dict_el wordEl;
+  wordEl.SetNumLevels (idh.num_levels);
+  for (wordNum=0; wordNum<idh.word_dict_size; wordNum++) {
+    wordEl.Read (dictFile, idh.num_levels);
+    ReadUL (invfIdxFile, wordStart);
+    PrintInvfWord (invfFile, idh, ifh, wordEl, wordStart);
+  }
+
+  // process all the tags
+  unsigned long tagNum;
+  unsigned long tagStart;
+  dict_el tagEl;
+  for (tagNum=0; tagNum<idh.tag_dict_size; tagNum++) {
+    tagEl.Read (dictFile);
+    ReadUL (invfIdxFile, tagStart);
+    PrintInvfTag (invfFile, idh, ifh, tagEl, tagStart);
+  }
+  
+  // close the open files
+  fclose (invfIdxFile);
+  fclose (invfFile);
+  fclose (dictFile);
+}
+
+
+int main (int argc, char **argv) {
+  char *dir_name, *filename = "";
+  int ch;
+  msg_prefix = argv[0];
+  dir_name = getenv ("MGDATA");
+  opterr = 0;
+  
+  msg_prefix = argv[0];
+  while ((ch = getopt (argc, argv, "hbwtf:d:")) != -1) {
+    switch (ch) {
+    case 'f':		// input file
+      filename = optarg;
+      break;
+    case 'd':
+      set_basepath(optarg);
+      break;
+    case 'h':
+    case '?':
+      fprintf (stderr, "usage: %s [-h] [-b] [-w] [-t] [-f input_file]"
+	       "[-d data directory]\n", argv[0]);
+      exit (1);
+    }
+  }
+  
+  process_files (filename);
+
+  return 0;
+}
Index: /main/tags/2.25/gsdl/src/mgpp/text/mg_passes.1
===================================================================
--- /main/tags/2.25/gsdl/src/mgpp/text/mg_passes.1	(revision 21064)
+++ /main/tags/2.25/gsdl/src/mgpp/text/mg_passes.1	(revision 21064)
@@ -0,0 +1,324 @@
+.\"------------------------------------------------------------
+.\" Id - set Rv,revision, and Dt, Date using rcs-Id tag.
+.de Id
+.ds Rv \\$3
+.ds Dt \\$4
+..
+.Id $Id$
+.\"------------------------------------------------------------
+.TH mg_passes 1 \*(Dt CITRI
+.SH NAME
+mg_passes \- builds mg databases
+.SH SYNOPSIS
+.B mg_passes
+[
+.BI \-J " doc-tag"
+]
+[
+.BI \-K " level-tag"
+]
+.if n .ti +10n
+[
+.BI \-L " index-level"
+]
+[
+.BI \-m " invf-mem-buffer"
+]
+.if n .ti +10n
+[
+.B \-T1
+]
+[
+.B \-T2
+]
+[
+.B \-I1
+]
+[
+.B \-I2
+]
+[
+.B \-S
+]
+[
+.B \-C
+]
+.if n .ti +10n
+[
+.B \-h
+]
+[
+.BI \-d " directory"
+]
+.BI \-f " name"
+[
+.I filename(s)
+]
+.SH DESCRIPTION
+.B mg_passes
+is the program that does most of the work when building mg
+database systems.  The input documents can come from either
+.I stdin
+or from a list of files on the command line.  In general,
+.B mg_passes
+must be run twice to build a database, first with the
+.B \-T1
+and
+.B \-I1
+options, and second with the
+.B \-T2
+and
+.B \-I2
+options.  Several other programs must be run in order to get an
+mg database.  The
+.SB EXAMPLE
+section below gives an example of how to build a complete
+mg database.
+.SH OPTIONS
+Options may appear in any order, but the
+.IR filename(s) ,
+if specified, must be last.
+.TP "\w'\fB\-C\fP \fIcompstatpointt\fP'u+2n"
+.BI \-J " doc-tag"
+Specifies the SGML tag that encloses each document.  Text appearing
+outside this tag is ignored.  The document tag defines the highest
+level document that can be queried and printed.  The default document
+tag is 'Document'.
+.TP
+.BI \-K " level-tag"
+Specifies the SGML tag of a sub document level.  A level tag must
+enclose all text enclosed by the document tag.  Levels can be
+queried and printed as if they were separate documents.  Multiple
+document levels can be specified (the document tag is always
+added as a document level).
+.TP
+.BI \-L " index-level"
+Specifies the SGML tag enclosing the smallest indexed element.  The
+index level should be no larger than the smallest document 
+level.  An empty string can be used to specify a word level index 
+(which is the default).
+.TP
+.BI \-m " invf-mem-buffer"
+Maximum amount of memory to use for the pass-2 file inversion in
+megabytes.  This option is only useful when used in conjunction with
+the option
+.BR \-I1 .
+The larger this value, the faster the pass-2 inversion will proceed.
+The default value is 5 MB.
+.TP
+.B \-T1
+Generate the
+.I *.text.stats
+file.
+.TP
+.B \-T2
+Generate the
+.IR *.text ,
+.IR *.text.idx ,
+.IR *.text.level ,
+and possibly the
+.I *.text.dict.aux
+files.  Using this option requires that the
+.I *.text.dict
+file be present.
+.TP
+.B \-I1
+Generate the
+.IR *.invf.dict ,
+.IR *.invf.level ,
+.IR *.invf.chunk ,
+and
+.I *.invf.chunk.trans
+files.
+.TP
+.B \-I2
+Generate the
+.I *.invf
+and
+.I *.invf.idx
+files.  Using this option requires
+that the
+.IR *.invf.dict.hash ,
+.IR *.invf.level ,
+.IR *.invf.chunk ,
+and
+.I *.invf.chunk.trans
+files be present.  The
+.I *.invf.dict.hash
+file is generated by
+.BR mg_perf_hash_build (1)
+from the
+.I *.invf.dict
+file.
+.TP
+.B \-S
+This option causes a special pass to be executed.  It is up to a user
+to modify
+.I mg.special.c
+in the source code to do something with the documents it is given.
+.TP 
+.B \-C
+This activates the compatibility parsing mode.  When using this
+mode documents are separated by control-B and paragraphs are separated
+by control-C.  Internally these are converted to documents surrounded
+by 'Document' tags and paragraphs surrounded by 'Paragraph' tags.
+.TP
+.B \-h
+This displays a usage line on
+.IR stderr .
+.TP
+.BI \-d " directory"
+This specifies the directory where the document collection is to be
+written.
+.TP
+.BI \-f " name"
+This specifies the base name of the document collection that will be
+created.
+.TP
+.I filename(s)
+This specifies the source text. If this is not specified, then the
+program expects the source text from
+.IR stdin .
+.SH EXAMPLE
+What follows is a UNIX
+.BR csh (1)
+script as an example of how to build an mg document collection.
+.LP
+.nf
+.DT
+.ft B
+.I #! /bin/csh
+.I
+# The first argument on the command line specifies the
+.I
+#   source of the text
+set source = ($1)
+.PP
+.I
+# The second argument is the name of the collection
+set text = ($2)
+.PP
+.I
+# Create *.text.stats, *.invf.dict, *.invf.level
+.I
+#   *.invf.chunk and *.invf.chunks.trans
+${source} | mg_passes -T1 -I1 -f ${text}
+.PP
+.I
+# Create *.text.dict
+mg_compression_dict -f ${text}
+.PP
+.I
+# Create *.invf.dict.hash
+mg_perf_hash_build -f ${text}
+.PP
+.I
+# Create *.text, *.text.idx, *.text.level
+.I
+#   *.invf and *.invf.idx
+${source} | mg_passes -T2 -I2 -f ${text}
+.PP
+.I
+# Create *.text.weight and *.weight.approx
+mg_weights_build -f ${text}
+.PP
+.I
+# Create *.invf.dict.blocked
+mg_invf_dict -f ${text}
+.PP
+.I
+# Create *.invf.dict.blocked.1
+mg_stem_idx -s 1 -f ${text}
+.PP
+.I
+# Create *.invf.dict.blocked.2
+mg_stem_idx -s 2 -f ${text}
+.PP
+.I
+# Create *.invf.dict.blocked.3
+mg_stem_idx -s 3 -f ${text}
+.PP
+.I
+# Create *.text.dict.fast
+mg_fast_comp_dict -f ${text}
+.ft R
+.fi
+.SH ENVIRONMENT
+.TP "\w'\fBMGDATA\fP'u+2n"
+.SB MGDATA
+If this environment variable exists, then its value is used as the
+default directory where the mg
+collection files are.  If this variable does not exist, then the
+directory \*(lq\fB.\fP\*(rq is used by default.  The command line
+option
+.BI \-d " directory"
+overrides the directory in
+.BR MGDATA .
+.SH FILES
+.TP 22
+.B *.invf
+Inverted file.
+.TP
+.B *.invf.chunk
+Inverted file chunk descriptor file.  When the inverted file is
+created it is created in chunks that use no more than a set amount of
+memory.  This file describes those chunks.
+.TP
+.B *.invf.chunk.trans
+Word-occurrence-order to lexical-order translation file.  The
+.B *.invf.chunk
+file is written in word-occurrence order but is required by
+.B \-I2
+to be in lexical order.
+.TP
+.B *.invf.dict
+Compressed stemmed dictionary.
+.TP
+.B *.invf.dict.blocked
+Compressed stemmed dictionary with index into the dictionary.
+.TP
+.B *.invf.dict.blocked.n
+Transformation dictionary from words stemmed with method 
+.B n
+to unstemmed words.
+.TP
+.B *.invf.dict.hash
+Data for an order-preserving perfect hash function.
+.TP
+.B *.invf.idx
+The index into the inverted file.
+.TP
+.B *.invf.level
+Information about the document levels needed for querying.
+.TP
+.B *.text
+Compressed text.
+.TP
+.B *.text.dict
+Compressed compression dictionary.
+.TP
+.B *.text.dict.fast
+A fast loading version of the compressed compression dictionary.
+.TP
+.B *.text.idx
+Index into the compressed documents.
+.TP
+.B *.text.level
+Information about the document levels needed for text decompression.
+.TP
+.B *.text.stats
+Statistics about the text.
+.TP
+.B *.weight
+The exact weights file.
+.TP
+.B *.weight.approx
+The approximate weights file.
+.SH "SEE ALSO"
+.na
+.BR mg_compression_dict (1),
+.BR mg_fast_comp_dict (1),
+.BR mg_invf_dict (1),
+.BR mg_perf_hash_build (1),
+.BR mg_stem_idx (1),
+.BR mg_weights_build (1)
Index: /main/tags/2.25/gsdl/src/mgpp/text/mg_passes.cpp
===================================================================
--- /main/tags/2.25/gsdl/src/mgpp/text/mg_passes.cpp	(revision 21064)
+++ /main/tags/2.25/gsdl/src/mgpp/text/mg_passes.cpp	(revision 21064)
@@ -0,0 +1,291 @@
+/**************************************************************************
+ *
+ * mg_passes.cpp -- Driver for the various passes
+ * Copyright (C) 1994  Neil Sharman
+ * Copyright (C) 1999  Rodger McNab
+ *
+ * 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.
+ *
+ * $Id$
+ *
+ **************************************************************************/
+
+#include "sysfuncs.h"
+
+#ifdef HAVE_MALLINFO
+# include <malloc.h> 
+#endif
+
+#include "memlib.h"
+#include "messages.h"
+
+#include "longlong.h"
+
+#include "mg_files.h"
+#include "mg.h"
+#include "build.h"
+#include "text.h"
+#include "stemmer.h"
+
+#include "FileBuf.h"
+#include "TextEl.h"
+#include "TagInfo.h"
+
+
+/*
+   $Log$
+   Revision 1.1  2000/01/14 02:26:18  sjboddie
+   Rodgers new C++ mg
+
+   Revision 1.1  1999/10/11 02:58:00  cs025
+   Base install of MG-PP
+
+   Revision 1.1  1999/08/10 21:18:12  sjboddie
+   renamed mg-1.3d directory mg
+
+   Revision 1.3  1998/12/17 09:12:53  rjmcnab
+
+   Altered mg to process utf-8 encoded Unicode. The main changes
+   are in the parsing of the input, the casefolding, and the stemming.
+
+   Revision 1.2  1998/11/25 07:55:47  rjmcnab
+
+   Modified mg to that you can specify the stemmer you want
+   to use via a command line option. You specify it to
+   mg_passes during the build process. The number of the
+   stemmer that you used is stored within the inverted
+   dictionary header and the stemmed dictionary header so
+   the correct stemmer is used in later stages of building
+   and querying.
+
+   Revision 1.1  1998/11/17 09:35:13  rjmcnab
+   *** empty log message ***
+
+   * Revision 1.3  1994/10/20  03:56:57  tes
+   * I have rewritten the boolean query optimiser and abstracted out the
+   * components of the boolean query.
+   *
+   * Revision 1.2  1994/09/20  04:41:52  tes
+   * For version 1.1
+   *
+ */
+
+#define MAX_PASSES 5
+
+#define SPECIAL 1
+#define TEXT_PASS_1 2
+#define TEXT_PASS_2 4
+#define IVF_PASS_1 8
+#define IVF_PASS_2 16
+
+#define MIN_BUF 8192
+
+
+unsigned long invf_buffer_size = 5 * 1024 * 1024;	/* 5Mb */
+
+static char Passes = 0;
+static char **files = NULL;
+static int num_files = 0;
+
+
+struct pass_data {
+  char *name;
+  int (*init) (const TagInfo &tagInfo, char *);
+  int (*process) (const TagInfo &tagInfo, const TextElArray &doc);
+  int (*done) (const TagInfo &tagInfo, char *);
+};
+
+
+static pass_data PassData[MAX_PASSES] = {
+  {"special", init_special, process_special, done_special},
+  {"text.pass1", init_text_1, process_text_1, done_text_1},
+  {"text.pass2", init_text_2, process_text_2, done_text_2},
+  {"ivf.pass1", init_ivf_1, process_ivf_1, done_ivf_1},
+  {"ivf.pass2", init_ivf_2, process_ivf_2, done_ivf_2},
+};
+
+static char *usage_str = "\nUSAGE:\n"
+"  %s [-J doc-tag] [-K level-tag] [-L index-level]\n"
+"  %*s [-m invf-memory] [-T1] [-T2] [-I1] [-I2] [-S]\n"
+"  %*s [-C] [-h] [-d directory] -f name\n\n";
+
+
+
+static void Usage (char *err) {
+  if (err) Message (err);
+  fprintf (stderr, usage_str, msg_prefix, strlen (msg_prefix), "",
+	   strlen (msg_prefix), "");
+  exit (1);
+}
+
+
+
+
+int OpenNextFile (int in_fd) {
+  if (in_fd > 0) close (in_fd);
+  if (num_files == 0) return (-1);
+  if ((in_fd = open (files[0], O_RDONLY)) == -1)
+    FatalError (1, "Cannot open %s", files[0]);
+  files++;
+  num_files--;
+  return (in_fd);
+}
+
+
+static void Driver (int in_fd, char *file_name,
+		    const TagInfo &tagInfo, bool compatMode) {
+  //  cout << tagInfo;
+
+  int pass;
+
+  unsigned long numBytes = 0;
+  unsigned long numDocs = 0;
+
+  // initialise all the passes
+  for (pass = 0; pass < MAX_PASSES; pass++) {
+    if (Passes & (1 << pass)) {
+      if (PassData[pass].init (tagInfo, file_name) == COMPERROR)
+	FatalError (1, "Error during init of \"%s\"", PassData[pass].name);
+    }
+  }
+
+  
+  // set up various variables
+  FileBuf buf;
+  TextElArray doc;
+  unsigned long docLen = 0;
+
+  // read and process each file (start with an open file)
+  do {
+    
+    // read and process each document in this file
+    buf.SetFD (in_fd);
+    while (ReadDoc (buf, tagInfo.docTag, doc, docLen, compatMode)) {
+
+      // give this document to each pass
+      for (pass = 0; pass < MAX_PASSES; pass++) {
+	if (Passes & (1 << pass)) {
+	  if (PassData[pass].process (tagInfo, doc) == COMPERROR)
+	    FatalError(1,"Error during processing of \"%s\"",PassData[pass].name);
+	}
+      }
+      
+      // another document has been processed
+      numBytes += docLen;
+      numDocs++;
+    }
+    
+  } while ((in_fd = OpenNextFile (in_fd)) > 0);
+
+  
+  // do done for each pass
+  for (pass = 0; pass < MAX_PASSES; pass++) {
+    if (Passes & (1 << pass)) {
+      if (PassData[pass].done (tagInfo, file_name) == COMPERROR)
+	FatalError (1, "Error during done of \"%s\"", PassData[pass].name);
+    }
+  }
+}
+
+
+
+int main (int argc, char **argv) {
+  int ch, in_fd;
+  char *filename = NULL;
+  bool compatMode = false;
+  TagInfo tagInfo;
+  tagInfo.SetDocTag ("Document");
+  
+  msg_prefix = argv[0];
+
+  opterr = 0;
+  while ((ch=getopt(argc, argv, "J:K:L:f:d:m:I:T:SCh"))!=-1){
+    switch (ch) {
+    case 'J':
+      tagInfo.SetDocTag (optarg);
+      break;
+    case 'K':
+      tagInfo.AddLevelTag (optarg);
+      break;
+    case 'L':
+      tagInfo.SetIndexLevel (optarg);
+      break;
+    case 'f':
+      filename = optarg;
+      break;
+    case 'd':
+      set_basepath (optarg);
+      break;
+    case 'm':
+      invf_buffer_size = (int) (atof (optarg) * 1024 * 1024);
+      break;
+    case 'I':
+      if (*optarg == '1')
+	Passes |= IVF_PASS_1;
+      else if (*optarg == '2')
+	Passes |= IVF_PASS_2;
+      else
+	Usage ("Invalid pass number");
+      break;
+    case 'T':
+      if (*optarg == '1')
+	Passes |= TEXT_PASS_1;
+      else if (*optarg == '2')
+	Passes |= TEXT_PASS_2;
+      else
+	Usage ("Invalid pass number");
+      break;
+    case 'S':
+      Passes |= SPECIAL;
+      break;
+    case 'C':
+      compatMode = true;
+      break;
+    case 'h':
+    case '?':
+      Usage (NULL);
+    }
+  }
+
+  if (!filename || *filename == '\0')
+    FatalError (1, "A document collection name must be specified.");
+
+  if ((Passes & (IVF_PASS_1 | IVF_PASS_2)) == (IVF_PASS_1 | IVF_PASS_2))
+    FatalError (1, "I1 and I2 cannot be done simultaneously.");
+
+  if ((Passes & (TEXT_PASS_1 | TEXT_PASS_2)) == (TEXT_PASS_1 | TEXT_PASS_2))
+    FatalError (1, "T1 and T2 cannot be done simultaneously.");
+
+  if (!Passes)
+    FatalError (1, "S, T1, T2, I1 or I2 must be specified.");
+
+  if (optind < argc) {
+    if ((in_fd = open (argv[optind], O_RDONLY)) == -1)
+      FatalError (1, "Cannot open %s", argv[optind]);
+    files = &argv[optind + 1];
+    num_files = argc - (optind + 1);
+    
+  } else in_fd = 0;  // stdin
+
+  
+  if (compatMode) tagInfo.SetDocTag ("Document");
+
+  // a document tag is also a level tag
+  tagInfo.levelTags.insert (tagInfo.docTag); 
+  
+  Driver (in_fd, filename, tagInfo, compatMode);
+
+  exit (0);
+}
Index: /main/tags/2.25/gsdl/src/mgpp/text/mg_perf_hash_build.1
===================================================================
--- /main/tags/2.25/gsdl/src/mgpp/text/mg_perf_hash_build.1	(revision 21064)
+++ /main/tags/2.25/gsdl/src/mgpp/text/mg_perf_hash_build.1	(revision 21064)
@@ -0,0 +1,73 @@
+.\"------------------------------------------------------------
+.\" Id - set Rv,revision, and Dt, Date using rcs-Id tag.
+.de Id
+.ds Rv \\$3
+.ds Dt \\$4
+..
+.Id $Id$
+.\"------------------------------------------------------------
+.TH mg_perf_hash_build 1 \*(Dt CITRI
+.SH NAME
+mg_perf_hash_build \- generate an order-preserving hash function for the stemmed dictionary
+.SH SYNOPSIS
+.B mg_perf_hash_build
+[
+.B \-h
+]
+[
+.BI \-r " rndseed"
+]
+[
+.BI \-d  " directory"
+]
+.if n .ti +9n
+.BI \-f " name"
+.SH DESCRIPTION
+.B mg_perf_hash_build
+generates an order-preserving hashing function from the compressed
+stemmed dictionary and writes it out to disk.
+.BR mg_passes (1)
+will make use of the hash function when it builds the inverted file.
+.SH OPTIONS
+Options may appear in any order.
+.TP "\w'\fB\-d\fP \fIdirectory\fP'u+2n"
+.B \-h
+This displays a usage line on
+.IR stderr .
+.TP
+.BI \-r " rndseed"
+This specifies the random seed to be used in the generation of the
+hash function; it must be an integer.  If this is not specified, the
+current time will be used as the random seed.
+.TP
+.BI \-d " directory"
+This specifies the directory where the document collection can be found.
+.TP
+.BI \-f " name"
+This specifies the base name of the document collection.
+.SH ENVIRONMENT
+.TP "\w'\fBMGDATA\fP'u+2n"
+.SB MGDATA
+If this environment variable exists, then its value is used as the
+default directory where the mg
+collection files are.  If this variable does not exist, then the
+directory \*(lq\fB.\fP\*(rq is used by default.  The command line
+option
+.BI \-d " directory"
+overrides the directory in
+.BR MGDATA .
+.SH FILES
+.TP 20
+.B *.invf.dict
+Stemmed dictionary.
+.TP
+.B *.invf.dict.hash
+Data for a order-preserving perfect hash function.
+.SH "SEE ALSO"
+.na
+.BR mg_compression_dict (1),
+.BR mg_fast_comp_dict (1),
+.BR mg_invf_dict (1),
+.BR mg_passes (1),
+.BR mg_stem_idx (1),
+.BR mg_weights_build (1)
Index: /main/tags/2.25/gsdl/src/mgpp/text/mg_perf_hash_build.cpp
===================================================================
--- /main/tags/2.25/gsdl/src/mgpp/text/mg_perf_hash_build.cpp	(revision 21064)
+++ /main/tags/2.25/gsdl/src/mgpp/text/mg_perf_hash_build.cpp	(revision 21064)
@@ -0,0 +1,177 @@
+/**************************************************************************
+ *
+ * mg_perf_hash_build.cpp -- Program to build a perfect hash function
+ * Copyright (C) 1999  Rodger McNab
+ *
+ * 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.
+ *
+ * $Id$
+ *
+ **************************************************************************/
+
+#include "sysfuncs.h"
+#include "memlib.h"
+#include "messages.h"
+#include "local_strings.h"
+#include "perf_hash.h"
+#include "netorder.h"
+
+#include "mg_files.h"
+#include "invf.h"
+#include "locallib.h"
+#include "words.h"
+#include "mg.h"
+
+/*
+   $Log$
+   Revision 1.2  2000/02/15 22:45:22  kjm18
+   added feature to retrieve doc nums at a different level than the level
+   queried at. eg query at Document level, but retrieve section level docnums
+   bug in mg_perf_hash_build.cpp fixed
+
+   Revision 1.1  2000/01/14 02:26:19  sjboddie
+   Rodgers new C++ mg
+
+   Revision 1.2  1999/10/17 23:43:27  cs025
+   Changes to eradicate Xmalloc
+
+   Revision 1.1  1999/10/11 02:58:01  cs025
+   Base install of MG-PP
+
+   Revision 1.1  1999/08/10 21:18:13  sjboddie
+   renamed mg-1.3d directory mg
+
+   Revision 1.2  1998/11/25 07:55:47  rjmcnab
+
+   Modified mg to that you can specify the stemmer you want
+   to use via a command line option. You specify it to
+   mg_passes during the build process. The number of the
+   stemmer that you used is stored within the inverted
+   dictionary header and the stemmed dictionary header so
+   the correct stemmer is used in later stages of building
+   and querying.
+
+   Revision 1.1  1998/11/17 09:35:15  rjmcnab
+   *** empty log message ***
+
+   * Revision 1.3  1994/10/20  03:56:58  tes
+   * I have rewritten the boolean query optimiser and abstracted out the
+   * components of the boolean query.
+   *
+   * Revision 1.2  1994/09/20  04:41:53  tes
+   * For version 1.1
+   *
+ */
+
+
+
+#define POOL_SIZE 1024*1024
+
+
+static void ProcessFiles (char *filename, int r) {
+  FILE *dictFile, *hashFile;
+  unsigned long i;
+  invf_dict_header idh;
+  perf_hash_data *phd;
+  u_char *pool;
+  unsigned long pool_left;
+  u_char **starts;
+
+  // read in the dictionary
+  dictFile = open_file (filename, INVF_DICT_SUFFIX, "rb",
+			MAGIC_STEM_BUILD, MG_ABORT);
+  if (dictFile==NULL) {
+    FatalError(1, "unable to open file");
+  }
+  idh.Read (dictFile);
+
+  //cerr << idh.lookback<<" "<<idh.word_dict_start<<endl;
+  // go to the start of the word dictionary
+  fseek (dictFile, idh.word_dict_start, SEEK_SET);
+  
+  if (!(pool = (u_char *) Xmalloc (POOL_SIZE)))
+    FatalError (1, "Out of memory");
+  pool_left = POOL_SIZE;
+
+  if (!(starts = (u_char **) Xmalloc (sizeof (u_char *) * idh.word_dict_size)))
+    FatalError (1, "Out of memory");
+  //cerr << "size= "<< idh.word_dict_size<<endl;
+  word_dict_el wordEl;
+  wordEl.SetNumLevels (idh.num_levels);
+  for (i = 0; i < idh.word_dict_size; i++) {
+    // read the next word and associated information
+    wordEl.Read (dictFile, idh.num_levels);
+
+    // push string onto pool data
+    register unsigned long l;
+    l = wordEl.el.size() + 1;
+    if (pool_left < l) {
+      pool = (u_char *) Xmalloc (POOL_SIZE);
+      pool_left = POOL_SIZE;
+    }
+    starts[i] = pool;
+    
+    *pool++ = wordEl.el.size();
+    bcopy ((char *) wordEl.el.begin(), (char *) pool, wordEl.el.size());
+    //cerr << pool<<"   " <<starts[i]<<endl;
+    pool += wordEl.el.size();
+    pool_left -= l;
+    
+  }
+  fclose (dictFile);
+  //cerr << pool<<"   " <<starts[i-1]<<endl;
+  //cerr<<"starts  "<<starts[113529]<<endl;
+  //cerr << starts[17][1] << " "<<starts[25][4]<<endl;
+  // create perfect hash file
+  hashFile = create_file (filename, INVF_DICT_HASH_SUFFIX, "wb",
+			  MAGIC_HASH, MG_ABORT);
+  if (!(phd = gen_hash_func (idh.word_dict_size, starts, r)))
+    FatalError (1, "Unable to generate hash function");
+  if (write_perf_hash_data (hashFile, phd) == -1)
+    FatalError (1, "Unable to write hash function");
+  fclose (hashFile);
+}
+
+
+
+int main (int argc, char **argv) {
+  int r = -1;
+  char *filename = "";
+  int ch;
+  msg_prefix = argv[0];
+  opterr = 0;
+
+  while ((ch = getopt (argc, argv, "f:d:r:h")) != -1) {
+    switch (ch) {
+    case 'f':		// input file
+      filename = optarg;
+      break;
+    case 'd':
+      set_basepath (optarg);
+      break;
+    case 'r':
+      r = atoi (optarg);
+      break;
+    case 'h':
+    case '?':
+      fprintf (stderr, "usage: %s [-f input_file]"
+	       "[-d data directory] [-r random seed] [-h]\n", argv[0]);
+      exit (1);
+    }
+  }
+
+  ProcessFiles (filename, r);
+  return 0;
+}
Index: /main/tags/2.25/gsdl/src/mgpp/text/mg_stem_idx.1
===================================================================
--- /main/tags/2.25/gsdl/src/mgpp/text/mg_stem_idx.1	(revision 21064)
+++ /main/tags/2.25/gsdl/src/mgpp/text/mg_stem_idx.1	(revision 21064)
@@ -0,0 +1,96 @@
+.\"------------------------------------------------------------
+.\" Id - set Rv,revision, and Dt, Date using rcs-Id tag.
+.de Id
+.ds Rv \\$3
+.ds Dt \\$4
+..
+.Id $Id$
+.\"------------------------------------------------------------
+.TH mg_stem_idx 1 \*(Dt CITRI
+.SH NAME
+mg_stem_idx \- builds a stem index file
+.SH SYNOPSIS
+.B mg_stem_idx
+[
+.B \-h
+]
+[
+.BI \-b " entries-per-block"
+]
+.if n .ti +12n
+[
+.BI \-a " stemmer"
+]
+[
+.BI \-d " directory"
+]
+.if n .ti +12n
+.B \-s 1|2|3
+.BI \-f " name"
+.SH DESCRIPTION
+.B mg_stem_idx
+generates a stem index file for a collection.
+This program should be called three times: once for each
+.B -s
+parameter.  It uses the stemmed dictionary to create the stem index which
+contains pointers into the stemmed dictionary.
+.SH OPTIONS
+Options may appear in any order.
+.TP "\w'\fB\-d\fP \fIdirectoryyyyyyyy\fP'u+2n"
+.B \-h
+This displays a usage line on
+.IR stderr .
+.TP
+.BI \-b " entries-per-block"
+The dictionary is stored in blocks on disk; this option is used to set
+the number of entries per block. The default is 16.
+.TP
+.BI \-a " stemmer"
+The name of the stemmer to use, the default is the Lovin stemmer.
+.TP
+.B -s 1|2|3
+The stem method to apply for the stem index.
+.br
+1 = casefolded and non-stemmed
+.br
+2 = non-casefolded and stemmed
+.br
+3 = casefolded and stemmed
+.TP
+.BI \-d " directory"
+This specifies the directory where the document collection can be found.
+.TP
+.BI \-f " name"
+This specifies the base name of the document collection.
+.SH ENVIRONMENT
+.TP "\w'\fBMGDATA\fP'u+2n"
+.SB MGDATA
+If this environment variable exists, then its value is used as the
+default directory where the mg
+collection files are.  If this variable does not exist, then the
+directory \*(lq\fB.\fP\*(rq is used by default.  The command line
+option
+.BI \-d " directory"
+overrides the directory in
+.BR MGDATA .
+.SH FILES
+.TP 22
+.B *.invf.dict
+Compressed stemmed dictionary.
+.TP
+.B *.invf.dict.blocked.1
+Stem index with stem index method 1.
+.TP
+.B *.invf.dict.blocked.2
+Stem index with stem index method 2.
+.TP
+.B *.invf.dict.blocked.3
+Stem index with stem index method 3.
+.SH "SEE ALSO"
+.na
+.BR mg_compression_dict (1),
+.BR mg_fast_comp_dict (1),
+.BR mg_invf_dict (1),
+.BR mg_passes (1),
+.BR mg_perf_hash_build (1),
+.BR mg_weights_build (1)
Index: /main/tags/2.25/gsdl/src/mgpp/text/mg_stem_idx.cpp
===================================================================
--- /main/tags/2.25/gsdl/src/mgpp/text/mg_stem_idx.cpp	(revision 21064)
+++ /main/tags/2.25/gsdl/src/mgpp/text/mg_stem_idx.cpp	(revision 21064)
@@ -0,0 +1,247 @@
+/**************************************************************************
+ *
+ * mg_stem_idx.cpp -- stem index builder
+ * Copyright (C) 1999  Rodger McNab
+ *
+ * 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.
+ *
+ **************************************************************************/
+
+
+#include "sysfuncs.h"
+#include "messages.h"
+
+#include "mg_files.h"
+#include "invf.h"
+#include "UCArray.h"
+#include "words.h"
+
+#include "stemmer.h"
+
+
+#if defined(GSDL_USE_OBJECTSPACE)
+#  include <ospace\std\map>
+#  include <ospace\std\vector>
+#elif defined(GSDL_USE_STL_H)
+#  include <map.h>
+#  include <vector.h>
+#else
+#  include <map>
+#  include <vector>
+#endif
+
+
+/*
+   $Log$
+   Revision 1.3  2000/01/18 03:53:24  rjmcnab
+   Fixed a couple of bugs and made building silent if needed.
+
+   Revision 1.2  2000/01/14 02:45:51  sjboddie
+   fixed compiler warning
+
+   Revision 1.1  2000/01/14 02:26:20  sjboddie
+   Rodgers new C++ mg
+
+ */
+
+
+typedef vector<unsigned long> WordNumList;
+typedef map<UCArray, WordNumList, DictLTUCArray> StemMapDict;
+
+
+void CreateStemDict (char *filename,
+		     StemMapDict &stemDict,
+		     int stemMethod,
+		     int stemmerNum) {
+  stemDict.erase (stemDict.begin(), stemDict.end());
+
+  // open the dictionary
+  FILE *dictFile = open_file (filename, INVF_DICT_SUFFIX, "rb",
+			      MAGIC_STEM_BUILD, MG_ABORT);
+  invf_dict_header idh;
+  idh.Read (dictFile);
+
+  fseek (dictFile, idh.word_dict_start, SEEK_SET);
+
+  unsigned long wordNum;
+  u_char mgWord[MAXSTEMLEN + 1];
+  word_dict_el wordEl;
+  UCArray stemEl;
+  wordEl.SetNumLevels (idh.num_levels);
+  for (wordNum=0; wordNum<idh.word_dict_size; wordNum++) {
+    // read in the next word
+    wordEl.Read (dictFile, idh.num_levels);
+
+    // convert the word to an "mg word"
+    mgWord[0] = wordEl.el.size();
+    bcopy ((char *)wordEl.el.begin(), (char *)&mgWord[1], wordEl.el.size());
+
+    // stem the word
+    stemmer (stemMethod, stemmerNum, mgWord);
+
+    // convert the result back to a UCArray
+    stemEl.erase (stemEl.begin(), stemEl.end());
+    stemEl.insert (stemEl.end(), &mgWord[1], &mgWord[1] + mgWord[0]);
+
+//      cout << "\"" << stemEl << "\" -> \"" << wordEl.el << "\"\n";
+    
+    // add this word number to the list of word numbers for this word
+    stemDict[stemEl].push_back (wordNum);
+  }
+
+  fclose (dictFile);
+}
+
+
+void WriteStemDict (char *filename,
+		    StemMapDict &stemDict,
+		    int stemMethod,
+		    int stemmerNum,
+		    unsigned long entriesPerBlock) {
+  // Create appropriate stem index file
+  FILE *stemDictFile = NULL;
+  if (stemMethod == 1) {
+    stemDictFile = create_file (filename, INVF_DICT_BLOCKED_1_SUFFIX,
+				"wb", MAGIC_STEM_1, MG_ABORT);
+  } else if (stemMethod == 2) {
+    stemDictFile = create_file (filename, INVF_DICT_BLOCKED_2_SUFFIX,
+				"wb", MAGIC_STEM_2, MG_ABORT);
+  } else if (stemMethod == 3) {
+    stemDictFile = create_file (filename, INVF_DICT_BLOCKED_3_SUFFIX,
+				"wb", MAGIC_STEM_3, MG_ABORT);
+  } else {
+    FatalError (1, "Unknown stem method %d", stemMethod);
+  }
+
+  stem_idx_header sih;
+  sih.lookback = 0;
+  sih.dict_size = stemDict.size();
+  sih.entries_per_block = entriesPerBlock;
+  sih.max_block_size = 0;
+  
+  sih.stemmer_num = stemmerNum;
+  sih.stem_method = stemMethod;
+
+  // write out a place-holder version of the header
+  sih.Write (stemDictFile);
+
+  sih.blocks_start = ftell (stemDictFile);
+
+  block_idx stemIdx;
+  unsigned long stemNum = 0;
+  stem_block_dict_el stemEl;
+  UCArray lastEl;
+
+  StemMapDict::const_iterator here = stemDict.begin();
+  StemMapDict::const_iterator end = stemDict.end();
+  while (here != end) {
+    // remember this stem (and position) if this is the start
+    // of a new block
+    if (stemNum % entriesPerBlock == 0) {
+      block_idx_info elIdx;
+      elIdx.el = (*here).first;
+      elIdx.block_ptr = ftell (stemDictFile);
+
+      // see if this block is the longest so far
+      if (stemIdx.size() > 0) {
+	unsigned long blockLen = elIdx.block_ptr -
+	  (*(stemIdx.end()-1)).block_ptr;
+	if (blockLen > sih.max_block_size) sih.max_block_size = blockLen;
+      }
+      
+      stemIdx.push_back (elIdx);
+      lastEl.erase (lastEl.begin(), lastEl.end()); // output full word
+    }
+
+    // copy the information for this stem
+    stemEl.el = (*here).first;
+    stemEl.equivWords = (*here).second;
+
+    // write out the stem
+    stemEl.Write (stemDictFile, &lastEl);
+    
+    here++; stemNum++;
+  }
+
+
+  // write out the element indexes
+  sih.num_blocks = stemIdx.size();
+  sih.block_idx_start = ftell (stemDictFile);
+  WriteBlockIdx (stemDictFile, stemIdx);
+  
+  // write out the stem dictionary header
+  fseek (stemDictFile, sizeof(unsigned long), SEEK_SET);
+  sih.Write (stemDictFile);
+
+
+  // close open files
+  fclose (stemDictFile);
+  
+  // print out information
+#ifndef SILENT
+  Message ("Num word stems = %d\n", sih.dict_size);
+  Message ("Max stem block size = %d\n", sih.max_block_size);
+  Message ("Number of stem blocks written = %d\n", sih.num_blocks);
+#endif
+}
+
+
+int main (int argc, char **argv) {
+  unsigned long entriesPerBlock = 16;
+  char *filename = "";
+  int ch;
+  int stemMethod = 0; // illegal value (no translation)
+  int stemmerNum = 0; // English stemmer
+  msg_prefix = argv[0];
+  opterr = 0;
+
+  while ((ch = getopt (argc, argv, "f:d:b:s:h")) != -1) {
+    switch (ch) {
+    case 'f':		// input file
+      filename = optarg;
+      break;
+    case 'd':
+      set_basepath (optarg);
+      break;
+    case 'b':
+      entriesPerBlock = atoi (optarg);
+      break;
+    case 's':
+      stemMethod = atoi (optarg);
+      break;
+    case 'a':
+      stemmerNum = stemmernumber ((unsigned char *) optarg);
+      break;
+    case 'h':
+    case '?':
+      fprintf (stderr, "usage: %s [-d directory] "
+	       "[-b entries-per-block] [-h] -s 1|2|3 "
+	       "[-a stemmer-method] -f name\n", argv[0]);
+      exit (1);
+    }
+  }
+  
+  if (stemMethod < 1 || stemMethod > 3)
+    FatalError (1, "Stem method must be 1, 2 or 3");
+
+  // read in the dictionary and create the in memory dictionary
+  StemMapDict stemDict;
+  CreateStemDict (filename, stemDict, stemMethod, stemmerNum);
+  
+  // write out the dictionary as a blocked file
+  WriteStemDict (filename, stemDict, stemMethod, stemmerNum, entriesPerBlock);
+  
+  return 0;
+}
Index: /main/tags/2.25/gsdl/src/mgpp/text/mg_weights_build.1
===================================================================
--- /main/tags/2.25/gsdl/src/mgpp/text/mg_weights_build.1	(revision 21064)
+++ /main/tags/2.25/gsdl/src/mgpp/text/mg_weights_build.1	(revision 21064)
@@ -0,0 +1,80 @@
+.\"------------------------------------------------------------
+.\" Id - set Rv,revision, and Dt, Date using rcs-Id tag.
+.de Id
+.ds Rv \\$3
+.ds Dt \\$4
+..
+.Id $Id$
+.\"------------------------------------------------------------
+.TH mg_weights_build 1 \*(Dt CITRI
+.SH NAME
+mg_weights_build \- builds the approximate weights file
+.SH SYNOPSIS
+.B mg_weights_build
+[
+.B \-h
+]
+[
+.BI \-b " num-bits"
+]
+.if n .ti +17n
+[
+.BI \-d " directory"
+]
+.BI \-f " name"
+.SH DESCRIPTION
+.B mg_weights_build
+is the program that generates the exact and approximate weights 
+files.  To do this, it uses the inverted file
+and dictionary.
+.SH OPTIONS
+Options may appear in any order.
+.TP "\w'\fB\-d\fP \fIirectory\fP'u+2n"
+.B \-h
+This displays a usage line on
+.IR stderr .
+.TP
+.BI \-b " num-bits"
+This specifies the number of bits of precision that should be used for
+the approximate weights.  If not specified, it defaults to 8.
+.TP
+.BI \-d " directory"
+This specifies the directory where the document collection is.
+.TP
+.BI \-f " name"
+This specifies the base name of the document collection.
+.SH ENVIRONMENT
+.TP "\w'\fBMGDATA\fP'u+2n"
+.SB MGDATA
+If this environment variable exists, then its value is used as the
+default directory where the mg
+collection files are.  If this variable does not exist, then the
+directory \*(lq\fB.\fP\*(rq is used by default.  The command line
+option
+.BI \-d " directory"
+overrides the directory in
+.BR MGDATA .
+.SH FILES
+.TP 20
+.B *.invf
+Inverted file.
+.TP
+.B *.invf.dict
+Compressed stemmed dictionary.
+.TP
+.B *.text.idx
+Index into the compressed documents.
+.TP
+.B *.weight
+The exact weights file.
+.TP
+.B *.weight.approx
+Approximate document weights.
+.SH "SEE ALSO"
+.na
+.BR mg_compression_dict (1),
+.BR mg_fast_comp_dict (1),
+.BR mg_invf_dict (1),
+.BR mg_passes (1),
+.BR mg_perf_hash_build (1),
+.BR mg_stem_idx (1)
Index: /main/tags/2.25/gsdl/src/mgpp/text/mg_weights_build.cpp
===================================================================
--- /main/tags/2.25/gsdl/src/mgpp/text/mg_weights_build.cpp	(revision 21064)
+++ /main/tags/2.25/gsdl/src/mgpp/text/mg_weights_build.cpp	(revision 21064)
@@ -0,0 +1,436 @@
+/**************************************************************************
+ *
+ * mg_weights_build.cpp -- Program to build the document weights file
+ * Copyright (C) 1999  Rodger McNab
+ *
+ * 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.
+ *
+ * $Id$
+ *
+ **************************************************************************/
+
+#include "sysfuncs.h"
+#include "memlib.h"
+#include "messages.h"
+#include "local_strings.h"
+#include "bitio_gen.h"
+#include "bitio_m_stdio.h"
+
+#include "mg_files.h"
+#include "locallib.h"
+#include "invf.h"
+// #include "WordData.h"
+#include "UCArray.h"
+#include "FIvfLevelInfo.h"
+#include "FragLevelConvert.h"
+
+#if defined(GSDL_USE_OBJECTSPACE)
+#  include <ospace\std\map>
+#elif defined(GSDL_USE_STL_H)
+#  include <map.h>
+#else
+#  include <map>
+#endif
+
+
+/*
+   $Log$
+   Revision 1.3  2000/01/18 23:24:19  rjmcnab
+   fixed a few more bugs
+
+   Revision 1.2  2000/01/18 03:53:24  rjmcnab
+   Fixed a couple of bugs and made building silent if needed.
+
+   Revision 1.1  2000/01/14 02:26:21  sjboddie
+   Rodgers new C++ mg
+
+   Revision 1.1  1999/10/11 02:58:06  cs025
+   Base install of MG-PP
+
+   Revision 1.1  1999/08/10 21:18:16  sjboddie
+   renamed mg-1.3d directory mg
+
+   Revision 1.2  1998/11/25 07:55:49  rjmcnab
+
+   Modified mg to that you can specify the stemmer you want
+   to use via a command line option. You specify it to
+   mg_passes during the build process. The number of the
+   stemmer that you used is stored within the inverted
+   dictionary header and the stemmed dictionary header so
+   the correct stemmer is used in later stages of building
+   and querying.
+
+   Revision 1.1  1998/11/17 09:35:22  rjmcnab
+   *** empty log message ***
+
+   * Revision 1.4  1994/11/29  00:32:05  tes
+   * Committing the new merged files and changes.
+   *
+   * Revision 1.3  1994/10/20  03:57:00  tes
+   * I have rewritten the boolean query optimiser and abstracted out the
+   * components of the boolean query.
+   *
+   * Revision 1.2  1994/09/20  04:41:55  tes
+   * For version 1.1
+   *
+ */
+
+#define MAXBITS (sizeof(unsigned long) * 8)
+
+struct WBTagPtr {
+  unsigned long tagNum;
+  unsigned long tagPtr;
+  unsigned long fragOccur;
+  
+  WBTagPtr () {
+    tagNum = 0;
+    tagPtr = 0;
+    fragOccur = 0;
+  }
+};
+
+// maps tags to tag information
+typedef map<UCArray, WBTagPtr, DictLTUCArray> WBTagDict;
+
+typedef vector<float> Weights;
+
+
+static void ReadTagDict (const invf_dict_header &idh,
+			 FILE *dictFile,
+			 FILE *invfIdxFile,
+			 WBTagDict &tagDict) {
+  tagDict.erase (tagDict.begin(), tagDict.end());
+
+  // seek to the start of the tag information
+  fseek (dictFile, idh.tag_dict_start, SEEK_SET);
+  fseek (invfIdxFile, sizeof(unsigned long) +
+	 idh.word_dict_size*sizeof(unsigned long), SEEK_SET);
+  
+  unsigned long tagNum;
+  unsigned long tagPtr;
+  dict_el thisEl;
+  for (tagNum = 0; tagNum < idh.tag_dict_size; tagNum++) {
+    thisEl.Read (dictFile);
+    ReadUL (invfIdxFile, tagPtr);
+    tagDict[thisEl.el].tagNum = tagNum;
+    tagDict[thisEl.el].tagPtr = tagPtr;
+    tagDict[thisEl.el].fragOccur = thisEl.frag_occur;
+  }
+}
+
+static void AddWeight (Weights &w,
+		       unsigned long levelDocNum,
+		       unsigned long termFreq,
+		       float idf) {
+  double weight = termFreq * idf;
+  w[levelDocNum-1] += weight * weight;
+}
+
+static void GenerateLevelWeights (const invf_dict_header &idh,
+				  const invf_file_header &ifh,
+				  unsigned long numLevelDocs,
+				  unsigned long levelNum,
+				  FILE *dictFile,
+				  FILE *invfFile,
+				  FILE *invfIdxFile,
+				  const FragLevelConvert &fragLevelConvert,
+				  Weights &w) {
+  // pre-allocate the right number of weights
+  w.erase (w.begin(), w.end());
+  w.insert (w.end(), (Weights::size_type)numLevelDocs, (float)0.0);
+
+  double logN = log ((double) numLevelDocs);
+
+  // reset the files
+  fseek (dictFile, idh.word_dict_start, SEEK_SET);
+  fseek (invfIdxFile, sizeof (unsigned long), SEEK_SET);
+  
+  // process each word adding its contributions to the document weights
+  unsigned long wordNum;
+  unsigned long wordStart;
+  word_dict_el wordEl;
+  wordEl.SetNumLevels (idh.num_levels);
+  for (wordNum=0; wordNum<idh.word_dict_size; wordNum++) {
+#ifndef SILENT
+    // give a little feedback every 4096 words
+    if ((wordNum & 0xfff) == 0) fprintf (stderr, ".");
+#endif
+    
+    wordEl.Read (dictFile, idh.num_levels);
+    ReadUL (invfIdxFile, wordStart);
+
+    float idf = logN - log ((double) wordEl.levelFreqs[levelNum]);
+
+    // seek to the appropriate place in the inverted file
+    fseek (invfFile, wordStart, SEEK_SET);
+    stdio_bitio_buffer buffer (invfFile);
+    
+    unsigned long B = BIO_Bblock_Init (idh.num_frags, wordEl.frag_occur);
+    unsigned long fragNum = 0;
+    unsigned long levelDocNum = 0;
+    unsigned long lastLevelDocNum = 0;
+    unsigned long termFreq = 0;
+    unsigned long checkLevelFreq = 0;
+    
+    unsigned long count, i;
+    for (i=0; i<wordEl.frag_occur; i++) {
+      fragNum += buffer.bblock_decode (B, NULL);
+      if (!ifh.word_level_index) count = buffer.gamma_decode (NULL);
+      else count = 1;
+
+      if (fragNum > idh.num_frags)
+	FatalError (1, "fragNum = %d, "
+		    "number of fragments = %d\n"
+		    "wordNum = %d\n"
+		    "i = %d, frag_occur = %d\n",
+		    fragNum, idh.num_frags, wordNum, i, wordEl.frag_occur);
+
+      if (!fragLevelConvert.FragToLevel (fragNum, levelDocNum))
+	FatalError (1, "could not convert fragment number %d", fragNum);
+
+      if (levelDocNum == 0 || levelDocNum > numLevelDocs)
+	FatalError (1, "bad level document number %d", levelDocNum);
+      
+      if (levelDocNum != lastLevelDocNum) {
+	// new level document
+	if (lastLevelDocNum > 0) {
+	  AddWeight (w, lastLevelDocNum, termFreq, idf);
+	  checkLevelFreq++;
+	}
+	lastLevelDocNum = levelDocNum;
+	termFreq = 0;
+      }
+      termFreq += count;
+    }
+
+    if (lastLevelDocNum > 0) {
+      AddWeight (w, lastLevelDocNum, termFreq, idf);
+      checkLevelFreq++;
+    }
+
+    if (checkLevelFreq != wordEl.levelFreqs[levelNum]) {
+      cerr << "bad level freq " << checkLevelFreq << " != "
+	   << wordEl.levelFreqs[levelNum] << ", word \""
+	   << wordEl.el << "\" (" << wordNum << ")\n";
+      exit (1);
+    }
+    
+    buffer.done();
+  }
+
+  if (w.size() != numLevelDocs) 
+    FatalError (1, "wrong number of weights created %d != %d",
+		w.size(), numLevelDocs);
+}
+
+static void WriteExactWeights (FILE *weightsFile,
+			       unsigned long &diskPtr,
+			       const Weights &w) {
+  diskPtr = ftell(weightsFile);
+
+  Weights::const_iterator here = w.begin();
+  Weights::const_iterator end = w.end();
+  while (here != end) {
+//      cout << *here << "\n";
+    WriteF (weightsFile, sqrt (*here));
+    here++;
+  }
+}
+
+static void WriteApproxWeights (FILE *approxWeightsFile,
+				unsigned long &diskPtr,
+				const Weights &w,
+				unsigned char bits) {
+  diskPtr = ftell(approxWeightsFile);
+
+  // calculate L, U and B
+  double L = 1e300;
+  double U = 0;
+  float wgt;
+  Weights::const_iterator here = w.begin();
+  Weights::const_iterator end = w.end();
+  while (here != end) {
+    wgt = sqrt (*here);
+    if (wgt > U) U = wgt;
+    if (wgt > 0 && wgt < L) L = wgt;
+    here++;
+  }
+
+  double B = pow (U / L, pow (2.0, -(double) bits));
+
+#ifndef SILENT
+  fprintf (stderr, "L = %f\n", L);
+  fprintf (stderr, "U = %f\n", U);
+  fprintf (stderr, "B = %f\n", B);
+#endif
+  
+  WriteUC (approxWeightsFile, bits);
+  WriteD (approxWeightsFile, L);
+  WriteD (approxWeightsFile, B);
+  
+
+  unsigned long max = (bits == 32) ? 0xffffffff : (1 << bits) - 1;;
+  unsigned long i=0, buf=0, pos=0;
+  here = w.begin();
+  end = w.end();
+  while (here != end) {
+    unsigned long fx;
+    wgt = sqrt (*here);
+    if (wgt == 0) {
+      wgt = L;
+#ifndef SILENT
+      Message ("Warning: Document %d had a weight of 0.", i);
+#endif
+    }
+    fx = (unsigned long) floor (log (wgt / L) / log (B));
+
+    if (fx > max) fx = max;
+
+    buf |= (fx << pos);
+    pos += bits;
+
+    if (pos >= MAXBITS) {
+      WriteUL (approxWeightsFile, buf);
+      buf = fx >> (bits - (pos - MAXBITS));
+      pos = pos - MAXBITS;
+    }
+
+    here++; i++;
+  }
+
+  // write out the last bits
+  if (pos > 0) WriteUL (approxWeightsFile, buf);
+}
+
+int main (int argc, char **argv) {
+  unsigned char bits = 8;
+  char *filename = "";
+  int ch;
+  opterr = 0;
+  msg_prefix = argv[0];
+
+  while ((ch = getopt (argc, argv, "f:d:b:h")) != -1) {
+    switch (ch) {
+    case 'f':		// input file
+      filename = optarg;
+      break;
+    case 'd':
+      set_basepath (optarg);
+      break;
+    case 'b':
+      bits = atoi (optarg);
+      if (bits > 32) {
+	fprintf (stderr, "b may only take values 0-32\n");
+	exit (1);
+      }
+      break;
+    case 'h':
+    case '?':
+      fprintf (stderr, "usage: %s [-f input_file]"
+	       "[-d data directory] [-b bits] [-h]\n", argv[0]);
+      exit (1);
+    }
+  }
+
+  
+  // open the dictionary
+  FILE *dictFile = open_file (filename, INVF_DICT_SUFFIX, "rb",
+			      MAGIC_STEM_BUILD, MG_ABORT);
+  invf_dict_header idh;
+  idh.Read (dictFile);
+
+  // open the inverted file
+  FILE *invfFile = open_file (filename, INVF_SUFFIX, "rb",
+			MAGIC_INVF, MG_ABORT);
+  invf_file_header ifh;
+  ifh.Read (invfFile);
+  if (ifh.skip_mode != SKIP_MODE_NO_SKIPS)
+    FatalError (1, "The invf file contains skips. Unable to create weights.");
+
+  // open the inverted index file
+  FILE *invfIdxFile = open_file (filename, INVF_IDX_SUFFIX, "rb",
+				 MAGIC_INVI, MG_ABORT);
+  
+  // read the level information
+  FILE *levelFile = open_file (filename, INVF_LEVEL_SUFFIX, "rb",
+			       MAGIC_INVF_LEVELS, MG_ABORT);
+  FIvfLevel ivfLevel;
+  ivfLevel.Read (levelFile);
+  fclose (levelFile);
+
+  // read in the tag dictionary and inverted file pointers
+  WBTagDict tagDict;
+  ReadTagDict (idh, dictFile, invfIdxFile, tagDict);
+
+  
+  // create the weights file
+  FILE *weightsFile = create_file (filename, WEIGHTS_SUFFIX, "wb",
+				   MAGIC_WGHT, MG_ABORT);
+
+  // create the approx weights file
+  FILE *approxWeightsFile = create_file (filename, APPROX_WEIGHTS_SUFFIX, "wb",
+					 MAGIC_WGHT_APPROX, MG_ABORT);
+
+  
+  // create weights for each document level
+  FragLevelConvert fragLevelConvert;
+  Weights w;
+  IvfLevelInfoMap::iterator levelHere = ivfLevel.levelInfo.begin();
+  IvfLevelInfoMap::iterator levelEnd = ivfLevel.levelInfo.end();
+  unsigned long levelNum = 0;
+  while (levelHere != levelEnd) {
+    const UCArray &levelName = (*levelHere).first;
+    
+    // read the tag information about this level
+    fragLevelConvert.Read(invfFile, tagDict[levelName].tagPtr,
+			  idh.num_frags, tagDict[levelName].fragOccur);
+    
+    // create the weights for this level
+    GenerateLevelWeights (idh, ifh, tagDict[levelName].fragOccur,
+			  levelNum, dictFile, invfFile, invfIdxFile,
+			  fragLevelConvert, w);
+
+    // write out the exact weights
+    WriteExactWeights (weightsFile,
+		       (*levelHere).second.exactWeightsDiskPtr,
+		       w);
+    
+    // write out the approximate weights
+    WriteApproxWeights (approxWeightsFile,
+			(*levelHere).second.approxWeightsDiskPtr,
+			w, bits);
+    
+    levelHere++; levelNum++;
+  }
+  
+
+  // close input files
+  fclose (dictFile);
+  fclose (invfFile);
+  fclose (invfIdxFile);
+
+  // update the level information
+  levelFile = create_file (filename, INVF_LEVEL_SUFFIX, "wb",
+			   MAGIC_INVF_LEVELS, MG_ABORT);
+  ivfLevel.Write (levelFile);
+  fclose (levelFile);
+
+  // close output files
+  fclose (weightsFile);
+  fclose (approxWeightsFile);
+
+
+  return 0;
+}
Index: /main/tags/2.25/gsdl/src/mgpp/text/stemmer.cpp
===================================================================
--- /main/tags/2.25/gsdl/src/mgpp/text/stemmer.cpp	(revision 21064)
+++ /main/tags/2.25/gsdl/src/mgpp/text/stemmer.cpp	(revision 21064)
@@ -0,0 +1,146 @@
+/**************************************************************************
+ *
+ * stemmer.cpp -- The stemmer/case folder
+ * Copyright (C) 1994  Neil Sharman
+ *
+ * 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.
+ *
+ * $Id$
+ *
+ **************************************************************************/
+
+#include "sysfuncs.h"
+#include "stemmer.h"
+
+#include "lovinstem.h"
+#include "simplefrenchstem.h"
+#include "unitool.h"
+
+/*
+   $Log$
+   Revision 1.1  2000/01/14 02:26:22  sjboddie
+   Rodgers new C++ mg
+
+   Revision 1.1  1999/10/11 02:58:34  cs025
+   Base install of MG-PP
+
+   Revision 1.1  1999/08/10 21:18:23  sjboddie
+   renamed mg-1.3d directory mg
+
+   Revision 1.3  1998/12/17 09:12:54  rjmcnab
+
+   Altered mg to process utf-8 encoded Unicode. The main changes
+   are in the parsing of the input, the casefolding, and the stemming.
+
+   Revision 1.2  1998/11/25 07:55:51  rjmcnab
+
+   Modified mg to that you can specify the stemmer you want
+   to use via a command line option. You specify it to
+   mg_passes during the build process. The number of the
+   stemmer that you used is stored within the inverted
+   dictionary header and the stemmed dictionary header so
+   the correct stemmer is used in later stages of building
+   and querying.
+
+   Revision 1.1  1998/11/17 09:35:42  rjmcnab
+   *** empty log message ***
+
+   * Revision 1.3  1994/10/20  03:57:05  tes
+   * I have rewritten the boolean query optimiser and abstracted out the
+   * components of the boolean query.
+   *
+   * Revision 1.2  1994/09/20  04:42:10  tes
+   * For version 1.1
+   *
+ */
+
+
+#define LOVINSTEMMER        0
+#define SIMPLEFRENCHSTEMMER 1
+
+
+/* decode the utf-8 encoded unicode, casefold and then recode 
+ * making sure the final length doesn't exceed the original
+ * length */
+static void unicode_casefold (u_char *word) {
+  unsigned short out[256]; /* temp space */
+  int i;
+  int len;
+
+  /* decode */
+  utf8_word_to_unicode (word, out, 255);
+  len = out[0];
+
+  /* casefold and simplify-fold */
+  for (i=0; i<len; i++) {
+    out[i+1] = unicode_tosimplified(unicode_tolower(out[i+1]));
+  }
+
+  /* re-code */
+  unicode_to_utf8_word (out, word, word[0]+1);
+}
+
+
+int stemmernumber (u_char *stemmerdescription) {
+  u_char descript[MAX_STEM_DESCRIPTION_LEN];
+  int i;
+
+  /* copy and case-fold the description */
+  for (i=0; (stemmerdescription[i] != '\0') && 
+	 (i < MAX_STEM_DESCRIPTION_LEN-1); i++)
+    descript[i] = tolower (stemmerdescription[i]);
+  descript[i] = '\0';
+
+  /* map the description to its number */
+
+  if ((strcmp ((char *) descript,  "0") == 0) ||
+      (strcmp ((char *) descript, "english") == 0) ||
+      (strcmp ((char *) descript, "lovin") == 0))
+    return LOVINSTEMMER;
+
+  if ((strcmp ((char *) descript, "1") == 1) ||
+      (strcmp ((char *) descript, "french") == 0) ||
+      (strcmp ((char *) descript, "simplefrench") == 0))
+    return SIMPLEFRENCHSTEMMER;
+
+  return -1;
+}
+
+
+
+/*
+ * Method 0 - Do not stem or case fold.
+ * Method 1 - Case fold.
+ * Method 2 - Stem.
+ * Method 3 - Case fold and stem.
+ *
+ * The stemmer number should be obtained using
+ * the stemmernumber function above.
+ */
+void 
+stemmer (int method, int stemmer, u_char *word) {
+  if (method & 1) {
+    unicode_casefold (word);
+  }
+
+  if (method & 2) {
+    switch (stemmer) {
+    case LOVINSTEMMER: lovinstem (word);
+      break;
+    case SIMPLEFRENCHSTEMMER: simplefrenchstem (word);
+      break;
+    }
+  }
+}
Index: /main/tags/2.25/gsdl/src/mgpp/text/stemmer.h
===================================================================
--- /main/tags/2.25/gsdl/src/mgpp/text/stemmer.h	(revision 21064)
+++ /main/tags/2.25/gsdl/src/mgpp/text/stemmer.h	(revision 21064)
@@ -0,0 +1,67 @@
+/**************************************************************************
+ *
+ * stemmer.h -- The stemmer/case folder
+ * Copyright (C) 1994  Neil Sharman
+ *
+ * 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.
+ *
+ * $Id$
+ *
+ **************************************************************************/
+
+#ifndef STEMMER_H
+#define STEMMER_H
+
+#include "sysfuncs.h"
+
+#define STEMMER_MASK 3
+#define MAX_STEM_DESCRIPTION_LEN 16
+
+/* stemmernumber will return the stemmer for
+ * a description of the stemmer. Stemmer descriptions
+ * are not case sensitive. Valid descriptions are:
+ *
+ *   'English'
+ *   'Lovin'
+ *   'French'
+ *   'SimpleFrench'
+ *
+ * More than one description might result in the same
+ * stemmer number (for example, for stemming 'English'
+ * we currently use the 'Lovin' stemmer).
+ *
+ * stemmerdescription is a normal C, null-terminated,
+ * string.
+ *
+ * stemmernumber will return -1 if it doesn't know the
+ * stemmer description.
+ */
+int stemmernumber (u_char *stemmerdescription);
+
+/*
+ * Method 0 - Do not stem or case fold.
+ * Method 1 - Case fold.
+ * Method 2 - Stem.
+ * Method 3 - Case fold and stem.
+ *
+ * The stemmer number should be obtained using function
+ * stemmernumber above.
+ */
+#ifdef __cplusplus
+extern "C" 
+#endif
+void stemmer (int method, int stemmer, u_char * word);
+
+#endif
Index: /main/tags/2.25/gsdl/src/mgpp/text/text.cpp
===================================================================
--- /main/tags/2.25/gsdl/src/mgpp/text/text.cpp	(revision 21064)
+++ /main/tags/2.25/gsdl/src/mgpp/text/text.cpp	(revision 21064)
@@ -0,0 +1,151 @@
+/**************************************************************************
+ *
+ * text.h -- Header file for compression related stuff
+ * Copyright (C) 1999  Rodger McNab
+ *
+ * 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.
+ *
+ * $Id$
+ *
+ **************************************************************************/
+
+#include "text.h"
+
+// UCArray currently contains all the basic reading and writing
+// functions
+#include "UCArray.h"
+
+
+compressed_text_header::compressed_text_header () {
+  Clear();
+}
+
+void compressed_text_header::Clear () {
+  num_of_docs = 0;
+  num_of_words = 0;
+  num_of_bytes = 0.0;
+}
+
+
+bool compressed_text_header::Read (FILE *f) {
+  return (ReadUL (f, num_of_docs) &&
+	  ReadUL (f, num_of_words) &&
+	  ReadD (f, num_of_bytes));
+}
+
+bool compressed_text_header::Write (FILE *f) const {
+  return (WriteUL (f, num_of_docs) &&
+	  WriteUL (f, num_of_words) &&
+	  WriteD (f, num_of_bytes));
+}
+
+
+auxiliary_dict::auxiliary_dict () {
+  word_data[0] = NULL;
+  word_data[1] = NULL;
+  words[0] = NULL;
+  words[1] = NULL;
+}
+
+auxiliary_dict::~auxiliary_dict () {
+  Clear ();
+}
+
+void auxiliary_dict::Clear () {
+  if (word_data[0] != NULL) {
+    delete word_data[0];
+    word_data[0] = NULL;
+  }
+  if (word_data[1] != NULL) {
+    delete word_data[1];
+    word_data[1] = NULL;
+  }
+  if (words[0] != NULL) {
+    delete words[0];
+    words[0] = NULL;
+  }
+  if (words[1] != NULL) {
+    delete words[1];
+    words[1] = NULL;
+  }
+}
+
+
+compression_dict::compression_dict () {
+  int which;
+  for (which = 0; which < 2; which++) {
+    cfh[which] = NULL;
+    values[which] = NULL;
+    escape[which] = NULL;
+    chars_huff[which] = NULL;
+    chars_vals[which] = NULL;
+    lens_huff[which] = NULL;
+    lens_vals[which] = NULL;
+  }
+
+  MemForCompDict = 0;
+  ad = NULL;
+  fast_loaded = 0;
+}
+
+compression_dict::~compression_dict () {
+  Clear ();
+}
+
+void compression_dict::Clear () {
+  int which;
+  for (which = 0; which < 2; which++) {
+    if (cfh[which] != NULL) {
+      delete cfh[which];
+      cfh[which] = NULL;
+    }
+    if (values[which] != NULL) {
+      delete values[which][0][0];
+      delete values[which][0];
+      delete values[which];
+      values[which] = NULL;
+    }
+    if (escape[which] != NULL) { // don't know if needed
+      //delete escape[which]; // this was causing a seg fault
+      escape[which] = NULL;
+    }
+    if (chars_huff[which] != NULL) {
+      delete chars_huff[which];
+      chars_huff[which] = NULL;
+    }
+    if (chars_vals[which] != NULL) {
+      delete chars_vals[which][0];
+      delete chars_vals[which];
+      chars_vals[which] = NULL;
+    }
+    if (lens_huff[which] != NULL) {
+      delete lens_huff[which];
+      lens_huff[which] = NULL;
+    }
+    if (lens_vals[which] != NULL) {
+      delete lens_vals[which][0];
+      delete lens_vals[which];
+      lens_vals[which] = NULL;
+    }
+  }
+
+  if (ad != NULL) {
+    delete ad;
+    ad = NULL;
+  }
+
+  MemForCompDict = 0;
+  fast_loaded = 0;
+}
Index: /main/tags/2.25/gsdl/src/mgpp/text/text.h
===================================================================
--- /main/tags/2.25/gsdl/src/mgpp/text/text.h	(revision 21064)
+++ /main/tags/2.25/gsdl/src/mgpp/text/text.h	(revision 21064)
@@ -0,0 +1,195 @@
+/**************************************************************************
+ *
+ * text.h -- Header file for compression related stuff
+ * Copyright (C) 1994  Neil Sharman
+ *
+ * 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.
+ *
+ * $Id$
+ *
+ **************************************************************************/
+
+
+
+#ifndef H_TEXT
+#define H_TEXT
+
+#include "huffman.h"
+#include <stdio.h>
+
+
+
+
+/*****************************************************************************
+ *
+ * There are several different methods of compressing the text of the
+ * database. The following defines list the different methods of text
+ * compression
+ *
+ */
+
+
+/* The dictionary contains all the fragments that occur in the collection
+   i.e. escapes are not possible */
+#define MG_COMPLETE_DICTIONARY 0
+
+
+/* Certain words have been deleted from the dictionary. The words deleted
+   have been used to create the frequency huffman codes of the characters. 
+   This dictionary has an escape code and may be used to compress novel
+   words. This dictionary may fail if there is a novel character. */
+#define MG_PARTIAL_DICTIONARY 1
+
+
+/* This dictionary has an escape so that novel words and non-words can be 
+   coded. The method for coding the novel words and non-words is determined
+   by a dictionary parameter. */
+#define MG_SEED_DICTIONARY 2
+
+
+
+
+
+
+
+
+
+/*****************************************************************************
+ *
+ * With a seed dictionary there are several methods for coding the novel
+ * words and non-words the following defined values specify the different
+ * methods of coding.
+ *
+ */
+
+
+/* Code novel words and non-words character by character using huffman codes.
+   The huffman codes for the word and non-word lengths and characters are 
+   generated from the distribution of lengths and characters in the
+   dictionary. */
+#define MG_NOVEL_HUFFMAN_CHARS 0
+
+
+/* This method codes novel words using delta codes. The novel words are stored
+   in a auxillary dictionary which is built by pass two. */
+#define MG_NOVEL_DELTA 2
+
+
+/* This method codes novel words using hybrid version of delta. The novel
+   words are stored in a auxillary dictionary which is built by pass two. */
+#define MG_NOVEL_HYBRID 3
+
+
+
+
+
+
+/* This specified an amount of extra space allocated in the
+   compression_dict_header for adding new parameters. As new
+   parameters are added this should be decreased. */
+#define TEXT_PARAMS 15
+
+
+
+struct compression_dict_header {
+  u_long dict_type;
+  u_long novel_method;
+  u_long params[TEXT_PARAMS];
+  u_long num_words[2];
+  u_long num_word_chars[2];
+  u_long lookback;
+};
+
+
+struct comp_frags_header {
+  huff_data hd;
+  u_long uncompressed_size;
+  u_long huff_words_size[MAX_HUFFCODE_LEN + 1];
+};
+
+// BOGUSTEXTLEN is used to replace the ratio
+// in the compressed_text_header while preparing
+// for UCArray
+#define BOGUSTEXTLEN 1000000
+
+struct compressed_text_header {
+  u_long num_of_docs;
+  u_long num_of_words; // number of words in collection
+  double num_of_bytes;
+
+  compressed_text_header ();
+  void Clear ();
+
+  // you must seek to the appropriate place before calling
+  // Read or Write
+  bool Read (FILE *f);
+  bool Write (FILE *f) const;
+};
+
+
+struct compression_stats_header {
+  u_long num_docs;
+  u_long dummy;     // alignment
+  double num_bytes; 
+};
+
+
+struct frags_stats_header {
+  u_long num_frags;
+  u_long mem_for_frags;
+};
+
+
+struct aux_frags_header {
+  u_long num_frags;
+  u_long mem_for_frags;
+};
+
+
+struct auxiliary_dict {
+  aux_frags_header afh[2];
+  u_char *word_data[2];
+  u_char **words[2];
+  int blk_start[2][33], blk_end[2][33];	/* blk_start and blk_end are required
+					   for the hybrid methods */
+
+  auxiliary_dict ();
+  ~auxiliary_dict ();
+
+  void Clear ();
+};
+
+
+struct compression_dict {
+  compression_dict_header cdh;
+  comp_frags_header *cfh[2];
+  unsigned long MemForCompDict;
+  u_char ***values[2];
+  u_char *escape[2];
+  huff_data *chars_huff[2];
+  u_long **chars_vals[2];
+  huff_data *lens_huff[2];
+  u_long **lens_vals[2];
+  auxiliary_dict *ad;
+  int fast_loaded;
+
+  compression_dict ();
+  ~compression_dict ();
+
+  void Clear ();
+};
+
+
+#endif
Index: /main/tags/2.25/gsdl/src/mgpp/text/text.pass1.cpp
===================================================================
--- /main/tags/2.25/gsdl/src/mgpp/text/text.pass1.cpp	(revision 21064)
+++ /main/tags/2.25/gsdl/src/mgpp/text/text.pass1.cpp	(revision 21064)
@@ -0,0 +1,409 @@
+/**************************************************************************
+ *
+ * text.pass1.cpp -- Text compression (Pass 1)
+ * Copyright (C) 1994  Neil Sharman, Gary Eddy and Alistair Moffat
+ * Copyright (C) 1999  Rodger McNab
+ *
+ * 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.
+ *
+ * $Id$
+ *
+ **************************************************************************/
+
+#include "sysfuncs.h"
+
+#include "memlib.h"
+#include "messages.h"
+#include "huffman.h"
+#include "netorder.h"  /* [RPAP - Jan 97: Endian Ordering] */
+
+
+#include "mg_files.h"
+#include "mg.h"
+#include "build.h"
+#include "locallib.h"
+#include "words.h"
+#include "text.h"
+#include "hash.h"
+#include "local_strings.h"
+
+#include "TextEl.h"
+
+
+/*
+   $Log$
+   Revision 1.1  2000/01/14 02:26:23  sjboddie
+   Rodgers new C++ mg
+
+   Revision 1.1  1999/10/11 02:58:37  cs025
+   Base install of MG-PP
+
+   Revision 1.1  1999/08/10 21:18:25  sjboddie
+   renamed mg-1.3d directory mg
+
+   Revision 1.2  1998/12/17 09:12:54  rjmcnab
+
+   Altered mg to process utf-8 encoded Unicode. The main changes
+   are in the parsing of the input, the casefolding, and the stemming.
+
+   Revision 1.1  1998/11/17 09:35:46  rjmcnab
+   *** empty log message ***
+
+   * Revision 1.4  1994/11/25  03:47:47  tes
+   * Committing files before adding the merge stuff.
+   *
+   * Revision 1.3  1994/10/20  03:57:09  tes
+   * I have rewritten the boolean query optimiser and abstracted out the
+   * components of the boolean query.
+   *
+   * Revision 1.2  1994/09/20  04:42:13  tes
+   * For version 1.1
+   *
+ */
+
+
+#define POOL_SIZE 1024*1024
+#define INITIAL_HASH_SIZE 7927
+
+
+
+
+
+
+
+typedef struct hash_rec
+  {
+    unsigned long wcnt;		/* word frequency */
+    unsigned long occurance_num;
+    u_char *word;
+  }
+hash_rec;
+
+typedef struct dict_data
+  {
+    hash_rec *HashTable;
+    unsigned long HashSize;
+    unsigned long HashUsed;
+    unsigned long wordnum;
+    unsigned long words_read;
+    unsigned long bytes_diff;
+    huff_data hd;
+  }
+dict_data;
+
+
+
+static unsigned long longestDoc = 0;
+static unsigned long occurance_num = 0;
+static dict_data DictData[2];
+
+static u_char *Pool;
+static int PoolLeft;
+static double inputbytes = 0; /* [RJM 07/97: 4G limit] */
+static unsigned long MaxMemInUse = 0;
+static unsigned long MemInUse = 0;
+static compression_stats_header csh = {0, 0, 0.0}; /* [RJM 07/97: 4G limit] */
+
+
+static void ChangeMem (int Change) {
+  MemInUse += Change;
+  if (MemInUse > MaxMemInUse) MaxMemInUse = MemInUse;
+}
+
+
+int init_text_1 (const TagInfo &/*tagInfo*/, char * /*FileName*/) {
+  int which;
+  
+  if (!(Pool = (u_char *) Xmalloc (POOL_SIZE))) {
+    Message ("Unable to allocate memory for pool");
+    return (COMPERROR);
+  }
+  PoolLeft = POOL_SIZE;
+  ChangeMem (POOL_SIZE);
+  
+  for (which = 1; which >= 0; which--) {
+    u_char *word;
+    hash_rec *ent;
+    dict_data *dd = &DictData[which];
+    
+    dd->wordnum = 0;
+    dd->words_read = 0;
+    dd->bytes_diff = 0;
+    dd->HashSize = INITIAL_HASH_SIZE;
+    dd->HashUsed = 0;
+    
+    if (!(dd->HashTable = (hash_rec *) Xmalloc (sizeof (hash_rec) * dd->HashSize))) {
+      Message ("Unable to allocate memory for table");
+      return (COMPERROR);
+    }
+    ChangeMem (sizeof (hash_rec) * dd->HashSize);
+    bzero ((char *) (dd->HashTable), sizeof (hash_rec) * dd->HashSize);
+
+    word = Pool;
+    *Pool++ = '\0';
+    PoolLeft--;
+    {
+      register u_char *wptr;
+      register int hsize = dd->HashSize;
+      register unsigned long hashval, step;
+      
+      HASH (hashval, step, word, hsize);
+      wptr = (dd->HashTable + hashval)->word;
+      while (wptr) {
+	hashval += step;
+	if (hashval >= (unsigned long)hsize)
+	  hashval -= hsize;
+	wptr = (dd->HashTable + hashval)->word;
+      }
+      ent = dd->HashTable + hashval;
+    }
+    ent->wcnt = 1;
+    ent->word = word;
+    dd->HashUsed = 1;
+  }
+  return (COMPALLOK);
+}
+
+
+static int process_text_element (const u_char *s_in, int l_in) {
+  const u_char *end = s_in + l_in - 1;
+  
+   /*
+   ** Alternately parse off words and non-words from the input
+   ** stream beginning with a non-word. Each token is then
+   ** inserted into the set if it does not exist or has it's
+   ** frequency count incremented if it does.
+   */
+  
+  bool which = false; // non-word
+  for (; s_in <= end; which = !which) {
+    u_char Word[MAXWORDLEN + 1];
+    dict_data *dd = &DictData[which];
+    
+    /* First parse a word or non-word out of the string */
+    if (which) PARSE_WORD (Word, s_in, end);
+    else PARSE_NON_WORD (Word, s_in, end);
+    
+    dd->wordnum++;
+    inputbytes += *Word;
+    dd->words_read++;
+    
+    /* Search the hash table for Word */
+    {
+      register unsigned long hashval, step;
+      register int hsize = dd->HashSize;
+      HASH (hashval, step, Word, hsize);
+      for (;;) {
+	register u_char *s1;
+	register u_char *s2;
+	register int len;
+	register hash_rec *ent;
+	ent = dd->HashTable + hashval;
+	if (!ent->word) {
+	  int len = *Word + 1;
+	  if (len > PoolLeft) {
+	    if (!(Pool = (u_char *) Xmalloc (POOL_SIZE))) {
+	      Message ("Unable to allocate memory for pool");
+	      return (COMPERROR);
+	    }
+	    PoolLeft = POOL_SIZE;
+	    ChangeMem (POOL_SIZE);
+	  }
+	  ent->occurance_num = occurance_num++;
+	  ent->wcnt = 1;
+	  ent->word = Pool;
+	  memcpy (Pool, Word, len);
+	  Pool += len;
+	  PoolLeft -= len;
+	  dd->HashUsed++;
+	  dd->bytes_diff += Word[0];
+	  break;
+	}
+	
+	/* Compare the words */
+	s1 = Word;
+	s2 = ent->word;
+	len = *s1 + 1;
+	for (; len; len--)
+	  if (*s1++ != *s2++) break;
+	
+	if (len) {
+	  hashval = (hashval + step);
+	  if (hashval >= (unsigned long)hsize) hashval -= hsize;
+	} else {
+	  ent->wcnt++;
+	  break;
+	}
+      }
+    }
+
+    
+    if (dd->HashUsed >= dd->HashSize >> 1) {
+      hash_rec *ht;
+      unsigned long size;
+      unsigned long i;
+      size = prime (dd->HashSize * 2);
+      if (!(ht = (hash_rec *) Xmalloc (sizeof (hash_rec) * size))) {
+	Message ("Unable to allocate memory for table");
+	return (COMPERROR);
+      }
+      ChangeMem (sizeof (hash_rec) * size);
+      bzero ((char *) ht, sizeof (hash_rec) * size);
+
+      for (i = 0; i < dd->HashSize; i++)
+	if (dd->HashTable[i].word) {
+	  register u_char *wptr;
+	  register unsigned long hashval, step;
+	  
+	  wptr = dd->HashTable[i].word;
+	  HASH (hashval, step, wptr, size);
+	  wptr = (ht + hashval)->word;
+	  while (wptr) {
+	    hashval += step;
+	    if (hashval >= size) hashval -= size;
+	    wptr = (ht + hashval)->word;
+	  }
+	  ht[hashval] = dd->HashTable[i];
+	}
+      Xfree (dd->HashTable);
+      ChangeMem (-sizeof (hash_rec) * dd->HashSize);
+      dd->HashTable = ht;
+      dd->HashSize = size;
+    }
+  }
+
+  return COMPALLOK;
+}
+
+
+int process_text_1 (const TagInfo &/*tagInfo*/, const TextElArray &doc) {
+  unsigned long textLen = 0;
+  unsigned long docLen = 0;
+  int retValue;
+
+  // process each text element in this document
+  TextElArray::const_iterator here = doc.begin();
+  TextElArray::const_iterator end = doc.end();
+  while (here != end) {
+    textLen = (*here).text.size();
+    docLen += textLen;
+
+    retValue = process_text_element ((*here).text.begin(), textLen);
+    if (retValue != COMPALLOK) return retValue;
+    
+    here++;
+  }
+
+  // get max document length
+  if (docLen > longestDoc) longestDoc = docLen;
+
+  // update header information
+  csh.num_docs++;
+  csh.num_bytes += docLen;
+  
+  return COMPALLOK;
+}
+
+
+static int PackHashTable (dict_data * dd) {
+  int s, d;
+  for (s = d = 0; (unsigned int)s < dd->HashSize; s++)
+    if (dd->HashTable[s].word)
+      dd->HashTable[d++] = dd->HashTable[s];
+  
+  ChangeMem (-sizeof (hash_rec) * dd->HashSize);
+  ChangeMem (sizeof (hash_rec) * dd->HashUsed);
+  
+  if (!(dd->HashTable = (hash_rec *) Xrealloc (dd->HashTable,
+			   sizeof (hash_rec) * dd->HashUsed))) {
+    Message ("Out of memory");
+    return COMPERROR;
+  }
+  dd->HashSize = dd->HashUsed;
+  return COMPALLOK;
+}
+
+
+static int ent_comp (const void *s1, const void *s2) {
+  return casecompare (((hash_rec *) s1)->word, ((hash_rec *) s2)->word);
+}
+
+
+static void WriteHashTable (FILE * fp, dict_data * dd) {
+  frags_stats_header fsh;
+  u_long j = 0;
+  u_char *curr;
+
+  if (PackHashTable (dd) == COMPERROR) return;
+  
+  qsort (dd->HashTable, dd->HashUsed, sizeof (hash_rec), ent_comp);
+  
+  fsh.num_frags = dd->HashSize;
+  fsh.mem_for_frags = dd->HashSize;
+  for (j = 0; j < dd->HashSize; j++)
+    fsh.mem_for_frags += dd->HashTable[j].word[0];
+  
+  /* [RPAP - Jan 97: Endian Ordering] */
+  HTONUL(fsh.num_frags);
+  HTONUL(fsh.mem_for_frags);
+  
+  fwrite (&fsh, sizeof (fsh), 1, fp);
+  
+  for (j = 0; j < dd->HashSize; j++) {
+    curr = dd->HashTable[j].word;
+    
+    /* [RPAP - Jan 97: Endian Ordering] */
+    HTONUL(dd->HashTable[j].wcnt);
+    HTONUL(dd->HashTable[j].occurance_num);
+    
+    fwrite (&dd->HashTable[j].wcnt, sizeof (dd->HashTable[j].wcnt), 1, fp);
+    fwrite (&dd->HashTable[j].occurance_num,
+	    sizeof (dd->HashTable[j].occurance_num), 1, fp);
+    
+    /* [RPAP - Jan 97: Endian Ordering] */
+    NTOHUL(dd->HashTable[j].wcnt);
+    NTOHUL(dd->HashTable[j].occurance_num);
+    
+    fwrite (curr, sizeof (u_char), curr[0] + 1, fp);
+  }
+}
+
+
+int done_text_1 (const TagInfo &/*tagInfo*/, char *file_name) {
+  char *temp_str;
+  FILE *fp;
+  
+  if (!(fp = create_file (file_name, TEXT_STATS_DICT_SUFFIX, "wb",
+			  MAGIC_STATS_DICT, MG_MESSAGE)))  /* [RPAP - Feb 97: WIN32 Port] */
+    return COMPERROR;
+  
+  temp_str = msg_prefix;
+  msg_prefix = "text.pass1";
+  
+  /* [RPAP - Jan 97: Endian Ordering] */
+  HTONUL(csh.num_docs);
+  HTOND(csh.num_bytes); /* [RJM 07/97: 4G limit] */
+
+  fwrite (&csh, sizeof (csh), 1, fp);
+
+  /* [RPAP - Jan 97: Endian Ordering] */
+  NTOHUL(csh.num_docs);
+  NTOHD(csh.num_bytes); /* [RJM 07/97: 4G limit] */
+
+  WriteHashTable (fp, &DictData[0]);
+  WriteHashTable (fp, &DictData[1]);
+  msg_prefix = temp_str;
+  return COMPALLOK;
+}
Index: /main/tags/2.25/gsdl/src/mgpp/text/text.pass2.cpp
===================================================================
--- /main/tags/2.25/gsdl/src/mgpp/text/text.pass2.cpp	(revision 21064)
+++ /main/tags/2.25/gsdl/src/mgpp/text/text.pass2.cpp	(revision 21064)
@@ -0,0 +1,605 @@
+/**************************************************************************
+ *
+ * text.pass2.cpp -- Text compression (Pass 2)
+ * Copyright (C) 1994  Neil Sharman, Gary Eddy and Alistair Moffat
+ * Copyright (C) 1999  Rodger McNab
+ *
+ * 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.
+ *
+ * $Id$
+ *
+ **************************************************************************/
+
+
+#include "sysfuncs.h"
+
+#include "memlib.h"
+#include "messages.h"
+#include "local_strings.h"
+#include "bitio_m_stdio.h"
+#include "huffman.h"
+#include "netorder.h"  /* [RPAP - Jan 97: Endian Ordering] */
+
+#include "mg.h"
+#include "mg_files.h"
+#include "build.h"
+#include "words.h"
+#include "text.h"
+#include "hash.h"
+#include "locallib.h"
+#include "comp_dict.h"
+
+#include "FText.h"
+
+
+/*
+   $Log$
+   Revision 1.1  2000/01/14 02:26:24  sjboddie
+   Rodgers new C++ mg
+
+   Revision 1.1  1999/10/11 02:58:38  cs025
+   Base install of MG-PP
+
+   Revision 1.1  1999/08/10 21:18:25  sjboddie
+   renamed mg-1.3d directory mg
+
+   Revision 1.2  1998/12/17 09:12:54  rjmcnab
+
+   Altered mg to process utf-8 encoded Unicode. The main changes
+   are in the parsing of the input, the casefolding, and the stemming.
+
+   Revision 1.1  1998/11/17 09:35:47  rjmcnab
+   *** empty log message ***
+
+   * Revision 1.3  1994/10/20  03:57:10  tes
+   * I have rewritten the boolean query optimiser and abstracted out the
+   * components of the boolean query.
+   *
+   * Revision 1.2  1994/09/20  04:42:14  tes
+   * For version 1.1
+   *
+ */
+
+#define POOL_SIZE 1024*256
+
+struct char_pool {
+  struct char_pool *next;
+  u_long left;
+  u_char *ptr;
+  u_char pool[POOL_SIZE];
+};
+
+struct novel_hash_rec {
+  u_long ordinal_num;
+  u_char *word;
+};
+
+
+#define INITIAL_HASH_SIZE 7927
+
+struct novel_hash_table {
+  novel_hash_rec *HashTable;
+  u_long HashSize, HashUsed;
+  char_pool *first_pool;
+  char_pool *pool;
+  u_long next_num, binary_start;
+  novel_hash_rec **code_to_nhr;
+};
+
+
+static FILE *text;
+static stdio_bitio_buffer textOutBuf;
+static u_long headLen;
+
+static novel_hash_table nht[2];
+
+int blk_start[2][33], blk_end[2][33];
+
+// 0 = non-word, 1 = word
+unsigned char whichWordType = 0;
+
+CompressTextInfoMap textInfoMap;
+
+
+static char_pool *new_pool (char_pool * pool) {
+  char_pool *p = (char_pool *) Xmalloc (sizeof (char_pool));
+  if (!p) FatalError (1, "Unable to allocate memory for pool");
+  
+  if (pool) pool->next = p;
+  p->next = NULL;
+  p->left = POOL_SIZE;
+  p->ptr = p->pool;
+  return p;
+}
+
+
+int init_text_2 (const TagInfo &/*tagInfo*/, char *fileName) {
+  char path[512];
+
+  // load the compression dictionary
+  if (LoadCompressionDictionary (make_name (fileName, TEXT_DICT_SUFFIX,
+					    path)) == COMPERROR)
+    return COMPERROR;
+
+  // create the compressed text file and attach it to the text buffer
+  if (!(text = create_file (fileName, TEXT_SUFFIX, "w+b",
+			    MAGIC_TEXT, MG_MESSAGE)))
+    return COMPERROR;
+  textOutBuf.attachFile (text);
+  textOutBuf.encodeStart ();
+  
+  // write out the compressed text header
+  bzero ((char *) &cth, sizeof (cth));
+  if (fwrite (&cth, sizeof (cth), 1, text) != 1)
+    return COMPERROR;
+
+  // the length of the compressed header is the size of the
+  // magic number plus the size of the compressed text header
+  headLen = sizeof (u_long) + sizeof (cth);
+
+  // start off with non-word
+  whichWordType = 0;
+
+  // clear the text pointers
+  textInfoMap.erase (textInfoMap.begin(), textInfoMap.end());
+  
+  // set up the hash table of novel words
+  int i;
+  if (cdh.novel_method != MG_NOVEL_HUFFMAN_CHARS)
+    for (i = 0; i <= 1; i++)
+      {
+	nht[i].HashSize = INITIAL_HASH_SIZE;
+	nht[i].HashTable = (novel_hash_rec *) Xmalloc (sizeof (novel_hash_rec) * nht[i].HashSize);
+	bzero ((char *) nht[i].HashTable,
+	       sizeof (novel_hash_rec) * nht[i].HashSize);
+	nht[i].HashUsed = 0;
+	nht[i].HashSize = INITIAL_HASH_SIZE;
+	nht[i].pool = nht[i].first_pool = new_pool (NULL);
+	nht[i].next_num = 1;
+	nht[i].binary_start = 1;
+	nht[i].code_to_nhr = NULL;
+	if (cdh.novel_method == MG_NOVEL_HYBRID)
+	  {
+	    int num;
+	    num = 1;
+	    blk_start[i][0] = 0;
+	    blk_end[i][0] = cdh.num_words[i] - 1;
+	    while (num < 33)
+	      {
+		blk_start[i][num] = blk_end[i][num - 1] + 1;
+		blk_end[i][num] = blk_start[i][num] +
+		  (blk_end[i][num - 1] - blk_start[i][num - 1]) * 2;
+		num++;
+	      }
+	  }
+      }
+
+  return (COMPALLOK);
+}
+
+
+static int compress_text (bitio_buffer &buffer, const u_char *s_in,
+			  int l_in, unsigned char &which,
+			  unsigned long &numWords) {
+  const u_char *end = s_in + l_in - 1;
+
+  for (; s_in <= end; which = !which) {
+    u_char Word[MAXWORDLEN + 1];
+    int res;
+    
+    if (which) numWords++;
+
+    /* First parse a word or non-word out of the string */
+    if (which) PARSE_WORD (Word, s_in, end);
+    else PARSE_NON_WORD (Word, s_in, end);
+
+    /* Search the hash table for Word */
+    if (ht[which]) {
+      register unsigned long hashval, step;
+      register int tsize = ht[which]->size;
+      register u_char **wptr;
+      HASH (hashval, step, Word, tsize);
+      for (;;) {
+	register u_char *s1;
+	register u_char *s2;
+	register int len;
+	wptr = ht[which]->table[hashval];
+	if (wptr == NULL) {
+	  res = COMPERROR;
+	  break;
+	}
+
+	/* Compare the words */
+	s1 = Word;
+	s2 = *wptr;
+	len = *s1 + 1;
+	for (; len; len--)
+	  if (*s1++ != *s2++) break;
+	
+	if (len) {
+	  hashval += step;
+	  if (hashval >= (unsigned long)tsize) hashval -= tsize;
+	  
+	} else {
+	  res = ht[which]->table[hashval] - ht[which]->words;
+	  break;
+	}
+      }
+    }
+    else
+      res = COMPERROR;
+    /* Check that the word was found in the dictionary */
+    if (res == COMPERROR)
+      {
+	if (cdh.dict_type == MG_COMPLETE_DICTIONARY)
+	  {
+	    Message ("Unknown word \"%.*s\"\n", *Word, Word + 1);
+	    return (COMPERROR);
+	  }
+	if (cdh.dict_type == MG_PARTIAL_DICTIONARY)
+	  {
+	    u_long i;
+	    if (ht[which])
+	      {
+		res = ht[which]->hd->num_codes - 1;
+		buffer.huff_encode (res, ht[which]->codes, ht[which]->hd->clens, NULL);
+	      }
+	    buffer.huff_encode (Word[0], lens_codes[which], lens_huff[which].clens, NULL);
+	    for (i = 0; i < Word[0]; i++)
+	      buffer.huff_encode (Word[i + 1], char_codes[which],
+				  char_huff[which].clens, NULL);
+	  }
+	if (cdh.dict_type == MG_SEED_DICTIONARY)
+	  {
+	    if (ht[which])
+	      {
+		res = ht[which]->hd->num_codes - 1;
+		buffer.huff_encode (res, ht[which]->codes, ht[which]->hd->clens, NULL);
+	      }
+	    switch (cdh.novel_method)
+	      {
+	      case MG_NOVEL_HUFFMAN_CHARS:
+		{
+		  u_long i;
+		  buffer.huff_encode (Word[0], lens_codes[which],
+				      lens_huff[which].clens, NULL);
+		  for (i = 0; i < Word[0]; i++)
+		    buffer.huff_encode (Word[i + 1], char_codes[which],
+					char_huff[which].clens, NULL);
+		}
+		break;
+	      case MG_NOVEL_DELTA:
+	      case MG_NOVEL_HYBRID:
+		{
+		  register unsigned long hashval, step;
+		  register novel_hash_table *h = &nht[which];
+		  register int hsize = h->HashSize;
+		  register novel_hash_rec *ent;
+		  HASH (hashval, step, Word, hsize);
+		  for (;;)
+		    {
+		      register u_char *s1, *s2;
+		      register int len;
+		      ent = h->HashTable + hashval;
+		      if (!ent->word)
+			{
+			  int len = *Word + 1;
+			  if ((unsigned)len > h->pool->left)
+			    h->pool = new_pool (h->pool);
+			  ent->word = h->pool->ptr;
+			  ent->ordinal_num = h->next_num++;
+			  memcpy (h->pool->ptr, Word, len);
+			  h->pool->ptr += len;
+			  h->pool->left -= len;
+			  h->HashUsed++;
+			  break;
+			}
+		      /* Compare the words */
+		      s1 = Word;
+		      s2 = ent->word;
+		      len = *s1 + 1;
+		      for (; len; len--)
+			if (*s1++ != *s2++)
+			  break;
+		      
+		      if (!len)
+			break;
+		      
+		      hashval = (hashval + step);
+		      if (hashval >= (unsigned)hsize) hashval -= hsize;
+		    }
+		  
+		  switch (cdh.novel_method) {
+		  case MG_NOVEL_DELTA:
+		    buffer.delta_encode (ent->ordinal_num, NULL);
+		    break;
+		  case MG_NOVEL_HYBRID:
+		    int k = 0;
+		    int j = ent->ordinal_num - 1;
+		    while (j > blk_end[which][k])
+		      k++;
+		    assert (j - blk_start[which][k] + 1 >= 1 &&
+			    j - blk_start[which][k] + 1 <=
+			    blk_end[which][k] - blk_start[which][k] + 1);
+		    
+		    buffer.gamma_encode (k + 1, NULL);
+		    buffer.binary_encode (j - blk_start[which][k] + 1,
+					  blk_end[which][k] - blk_start[which][k] + 1,
+					  NULL);
+		    break;
+		  }
+		  
+		  if (h->HashUsed >= h->HashSize >> 1)
+		    {
+		      novel_hash_rec *ht;
+		      unsigned long size;
+		      unsigned long i;
+		      size = prime (h->HashSize * 2);
+		      if (!(ht = (novel_hash_rec *) Xmalloc (sizeof (novel_hash_rec) * size)))
+			{
+			  Message ("Unable to allocate memory for table");
+			  return (COMPERROR);
+			}
+		      bzero ((char *) ht, sizeof (novel_hash_rec) * size);
+		      
+		      for (i = 0; i < h->HashSize; i++)
+			if (h->HashTable[i].word)
+			  {
+			    register u_char *wptr;
+			    register unsigned long hashval, step;
+			    
+			    wptr = h->HashTable[i].word;
+			    HASH (hashval, step, wptr, size);
+			    wptr = (ht + hashval)->word;
+			    while (wptr)
+			      {
+				hashval += step;
+				if (hashval >= size)
+				  hashval -= size;
+				wptr = (ht + hashval)->word;
+			      }
+			    ht[hashval] = h->HashTable[i];
+			  }
+		      Xfree (h->HashTable);
+		      h->HashTable = ht;
+		      h->HashSize = size;
+		    }
+		}
+		break;
+	      }
+	  }
+      }
+    else
+      {
+	buffer.huff_encode (res, ht[which]->codes, ht[which]->hd->clens, NULL);
+      }
+  }
+  
+  return COMPALLOK;
+}
+
+
+int process_text_2 (const TagInfo &tagInfo, const TextElArray &doc) {
+  // we need to remember where the last text element ends
+  unsigned char endBit = textOutBuf.GetBtg (); // 8=high bit, 1=low bit
+  unsigned long endPos = textOutBuf.GetBytesWritten () + headLen;
+
+  // process each text element
+  TextElArray::const_iterator here = doc.begin();
+  TextElArray::const_iterator end = doc.end();
+  while (here != end) {
+    // remember current place in compressed text
+    unsigned char startWhich = whichWordType;
+    unsigned char startBit = textOutBuf.GetBtg (); // 8=high bit, 1=low bit
+    unsigned long startPos = textOutBuf.GetBytesWritten () + headLen;
+
+    // compress the text
+    if (compress_text (textOutBuf,
+		       (*here).text.begin(),
+		       (*here).text.size(),
+		       whichWordType,
+		       cth.num_of_words) != COMPALLOK)
+      return COMPERROR;
+
+    endBit = textOutBuf.GetBtg (); // 8=high bit, 1=low bit
+    endPos = textOutBuf.GetBytesWritten () + headLen;
+    
+    // update the pointers if this is a level tag
+    if (tagInfo.levelTags.find ((*here).tagName) != tagInfo.levelTags.end()) {
+      if ((*here).elType == OpenTagE) {
+	// set the start of the document
+	textInfoMap[(*here).tagName].SetStart (startPos, startBit, startWhich);
+	
+      } else if ((*here).elType == CloseTagE) {
+	// set the end of the document
+	textInfoMap[(*here).tagName].SetEnd (endPos, endBit);
+	
+      } else {
+	// TextE, nothing needs to be done
+      }
+    }
+    
+    cth.num_of_bytes += (*here).text.size();
+    here++;
+  }
+
+  // close off any unclosed tags
+  CompressTextInfoMap::iterator tiHere = textInfoMap.begin ();
+  CompressTextInfoMap::iterator tiEnd = textInfoMap.end ();
+  while (tiHere != tiEnd) {
+    if ((*tiHere).second.inDoc) (*tiHere).second.SetEnd (endPos, endBit);
+    tiHere++;
+  }
+  
+  // we've processed one more document
+  cth.num_of_docs++;
+
+  return COMPALLOK;
+}
+
+
+static int write_aux_dict (char *fileName) {
+  int i;
+  FILE *aux;
+  if (!(aux = create_file (fileName, TEXT_DICT_AUX_SUFFIX, "wb",
+			   MAGIC_AUX_DICT, MG_MESSAGE)))
+    return COMPERROR;
+  
+  for (i = 0; i <= 1; i++)
+    {
+      aux_frags_header afh;
+      char_pool *cp;
+      
+      afh.num_frags = nht[i].HashUsed;
+      afh.mem_for_frags = 0;
+      for (cp = nht[i].first_pool; cp; cp = cp->next)
+	afh.mem_for_frags += POOL_SIZE - cp->left;
+      
+      /* [RPAP - Jan 97: Endian Ordering] */
+      HTONUL(afh.num_frags);
+      HTONUL(afh.mem_for_frags);
+      
+      fwrite (&afh, sizeof (afh), 1, aux);
+      
+      for (cp = nht[i].first_pool; cp; cp = cp->next)
+	fwrite (cp->pool, POOL_SIZE - cp->left, sizeof (u_char), aux);
+    }
+  fclose (aux);
+  return COMPALLOK;
+}
+
+
+static void estimate_compressed_aux_dict (void) {
+  int i;
+  u_long aux_compressed = 0, total_uncomp = 0;
+  for (i = 0; i <= 1; i++)
+    {
+      int j;
+      long chars[256], fchars[256];
+      long lens[16], flens[16];
+      char_pool *cp;
+      bzero ((char *) chars, sizeof (chars));
+      bzero ((char *) lens, sizeof (lens));
+      for (cp = nht[i].first_pool; cp; cp = cp->next)
+	{
+	  u_char *buf = cp->pool;
+	  while (buf != cp->ptr)
+	    {
+	      int len = *buf++;
+	      lens[len]++;
+	      total_uncomp += len + 4;
+	      for (; len; len--)
+		chars[*buf++]++;
+	    }
+	}
+      for (j = 0; j < 256; j++)
+	if (!chars[j] && PESINAWORD (j) == i)
+	  fchars[j] = 1;
+	else
+	  fchars[j] = chars[j];
+      for (j = 0; j < 16; j++)
+	if (!lens[j])
+	  flens[j] = 1;
+	else
+	  flens[j] = lens[j];
+      
+      aux_compressed += (long unsigned int) ((Calculate_Huffman_Size (16, flens, lens) +
+					      Calculate_Huffman_Size (256, fchars, chars)) / 8);
+      
+    }
+}
+
+
+
+static bool WriteTextIdx (char *fileName, FTextLevel &textLevels) {
+  // create the text index
+  FILE *textIdxFile;
+  if (!(textIdxFile = create_file (fileName, TEXT_IDX_SUFFIX, "w+b",
+				MAGIC_TEXI, MG_MESSAGE)))
+    return false;
+
+  // output each level
+  CompressTextInfoMap::iterator tiHere = textInfoMap.begin ();
+  CompressTextInfoMap::iterator tiEnd = textInfoMap.end ();
+  while (tiHere != tiEnd) {
+    // remember the level information
+    TextLevelInfo levelInfo;
+    levelInfo.levelTag = (*tiHere).first;
+    levelInfo.textIdxPtr = ftell (textIdxFile);
+    levelInfo.numEntries = (*tiHere).second.docPtrs.size();
+    textLevels.levelInfo[levelInfo.levelTag] = levelInfo;
+
+    // write out the index array for this level
+    if (!WriteTextIdxArray (textIdxFile, (*tiHere).second.docPtrs))
+      return false;
+    
+    tiHere++;
+  }
+
+  // close the file
+  fclose (textIdxFile);
+
+  return true;
+}
+
+
+bool WriteTextLevels (char *fileName, const FTextLevel &textLevels) {
+  //  cout << textLevels;
+  
+  // create the text index
+  FILE *textLevelFile;
+  if (!(textLevelFile = create_file (fileName, TEXT_LEVEL_SUFFIX, "w+b",
+				     MAGIC_TEXT_LEVELS, MG_MESSAGE)))
+    return false;
+
+  // output each level
+  if (!textLevels.Write (textLevelFile)) return false;
+  
+  // close the file
+  fclose (textLevelFile);
+
+  return true;
+}
+
+
+int done_text_2 (const TagInfo &/*tagInfo*/, char *fileName) {
+  // write out any remaining bits
+  textOutBuf.encodeDone();
+
+  // write out the compressed text header (with updated statistics)
+  if (fseek (text, sizeof (u_long), SEEK_SET) == -1 || !cth.Write (text))
+    return COMPERROR;
+  fclose (text);
+
+  // write out the text index file and get the level information
+  FTextLevel textLevels;
+  if (!WriteTextIdx (fileName, textLevels)) return COMPERROR;
+  
+  // write out the text level information
+  if (!WriteTextLevels (fileName, textLevels)) return COMPERROR;
+
+  // write out the auxiliary dictionary
+  if (cdh.dict_type != MG_COMPLETE_DICTIONARY &&
+      (cdh.novel_method == MG_NOVEL_DELTA ||
+       cdh.novel_method == MG_NOVEL_HYBRID)) {
+    if (write_aux_dict (fileName) == COMPERROR) return COMPERROR;
+    estimate_compressed_aux_dict ();
+    
+  } else {
+    unlink (make_name (fileName, TEXT_DICT_AUX_SUFFIX, NULL));
+  }
+
+  return (COMPALLOK);
+}
Index: /main/tags/2.25/gsdl/src/mgpp/text/words.cpp
===================================================================
--- /main/tags/2.25/gsdl/src/mgpp/text/words.cpp	(revision 21064)
+++ /main/tags/2.25/gsdl/src/mgpp/text/words.cpp	(revision 21064)
@@ -0,0 +1,97 @@
+/**************************************************************************
+ *
+ * words.cpp -- Functions for parsing out words from the source text
+ * Copyright (C) 1999  Rodger McNab
+ *
+ * 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.
+ *
+ * $Id$
+ *
+ **************************************************************************/
+
+#include "words.h"
+
+
+/* Takes the place of the old INAWORD macro. It determines
+   whether a given place in a UTF-8 encoded Unicode string
+   is part of a word. */
+int inaword (const u_char *here, const u_char *end) {
+  unsigned short c;
+  if (parse_utf8_char(here, end, &c) > 0) return is_unicode_letdig (c);
+  return 0;
+}
+
+const unsigned char *ParseIndexWord (const unsigned char *textHere,
+				     const unsigned char *textEnd,
+				     UCArray &word) {
+  word.erase (word.begin(), word.end());
+
+  register int charlength = 0;
+  register int length = 0;
+  register int numeric = 0;
+  unsigned short c;
+  
+  charlength = parse_utf8_char (textHere, textEnd, &c);
+  
+  while (length+charlength <= MAXSTEMLEN && charlength > 0 &&
+	 (is_unicode_letter(c) || (is_unicode_digit(c) &&
+				   ++numeric <= MAXNUMERIC))) {
+    while (charlength-- > 0) {
+      word.push_back (*textHere++); length++;
+    }
+    charlength = parse_utf8_char (textHere, textEnd, &c);
+  }
+  
+  return textHere;
+}
+
+const unsigned char *ParseIndexMGWord (const unsigned char *textHere,
+				       const unsigned char *textEnd,
+				       unsigned char *mgWord) {
+  register int charlength = 0;
+  register int length = 0;
+  register int numeric = 0;
+  unsigned short c;
+  
+  charlength = parse_utf8_char (textHere, textEnd, &c);
+  
+  while (length+charlength <= MAXSTEMLEN && charlength > 0 &&
+	 (is_unicode_letter(c) || (is_unicode_digit(c) &&
+				   ++numeric <= MAXNUMERIC))) {
+    while (charlength-- > 0) {
+      mgWord[++length] = *textHere++;
+    }
+    charlength = parse_utf8_char (textHere, textEnd, &c);
+  }
+
+  mgWord[0] = length;
+  
+  return textHere;
+}
+
+const unsigned char *ParseNonindexWord (const unsigned char *textHere,
+					const unsigned char *textEnd) {
+  register int charlength = 0;
+  unsigned short c;
+  
+  charlength = parse_utf8_char(textHere, textEnd, &c);
+  
+  while (charlength > 0 && !is_unicode_letdig(c)) {
+    textHere += charlength;
+    charlength = parse_utf8_char (textHere, textEnd, &c);
+  }
+  
+  return textHere;
+}
Index: /main/tags/2.25/gsdl/src/mgpp/text/words.h
===================================================================
--- /main/tags/2.25/gsdl/src/mgpp/text/words.h	(revision 21064)
+++ /main/tags/2.25/gsdl/src/mgpp/text/words.h	(revision 21064)
@@ -0,0 +1,157 @@
+/**************************************************************************
+ *
+ * words.h -- Macros for parsing out words from the source text
+ * Copyright (C) 1994  Neil Sharman
+ *
+ * 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.
+ *
+ * $Id$
+ *
+ **************************************************************************/
+
+#include "sysfuncs.h"
+
+#include "unitool.h"
+#include "UCArray.h"
+
+
+/*
+ * This has been cleaned up by Tim Shimmin. 
+ */
+
+/*
+ * ---NOTE---
+ *
+ * "WORD" refers to a word in the compressed text.
+ * "STEM" or "STEM_WORD" refers to a word for indexing on
+ *
+ */
+
+#define MAXWORDLEN	15
+	/* Maximum length in bytes of any word or non-word. Note that
+	   variations to MAXWORDLEN may have dramatic effects on the rest
+	   of the program, as the length and the prefix match are packed
+	   together into a four bit nibble, and there is not check that
+	   this is possible, i.e., leave MAXWORDLEN alone... */
+
+#define MAXSTEMLEN	255
+	/* Maximum length in bytes of any stem. Note that
+	   variations to MAXSTEMLEN may have dramatic effects on the rest
+	   of the program, , i.e., leave MAXSTEMLEN alone... */
+
+#define MAXNUMERIC	4
+	/* Maximum number of numeric characters permitted in a word.
+	   This avoids long sequences of numbers creating just one
+	   word occurrence for each number. At most 10,000 all numeric
+	   words will be permitted. */
+
+/* [RPAP - Jan 97: Stem Index Change] */
+#define MAXPARAMLEN     20
+        /* Maximum number of bytes to read for a parameter value for a
+	   term in a query. */
+#define WEIGHTPARAM     '/'
+#define STEMPARAM       '#'
+
+/* [RJM 07/97: Ranked Required Terms] */
+#define MUSTMATCHPARAM     '+'
+
+
+#define PESINAWORD(c)      (isalnum(c) || ((c) >= 0x80 && (c) <= 0xff))
+        /* The definition of what characters are permitted in a word.
+	   This macro is pessimistic, you cannot tell from a particular
+	   byte above 0x80 whether it is a character or not. This function
+	   is needed by various functions relating to huffman coding
+	   where frequency counts need to be primed, it should not be
+	   used in parsing the UTF-8 encoded input. */
+
+#ifdef __cplusplus
+extern "C"
+#endif
+int inaword (const u_char *here, const u_char *end);
+        /* Takes the place of the old INAWORD macro. It determines
+	   whether a given place in a UTF-8 encoded Unicode string
+	   is part of a word. */
+
+
+const unsigned char *ParseIndexWord (const unsigned char *textHere,
+				     const unsigned char *textEnd,
+				     UCArray &word);
+const unsigned char *ParseIndexMGWord (const unsigned char *textHere,
+				       const unsigned char *textEnd,
+				       unsigned char *mgWord);
+const unsigned char *ParseNonindexWord (const unsigned char *textHere,
+					const unsigned char *textEnd);
+
+
+
+/* =========================================================================
+ * Macro: PARSE_WORD
+ * Description: 
+ *      Extract a word out for compressing text
+ * Input: 
+ *      s_in = string start in buffer
+ *      end = string end in buffer
+ * Output: 
+ *      Word = extracted word with length in 1st byte
+ *      s_in = ptr to next character in buffer yet to be processed
+ * ========================================================================= */
+#define PARSE_WORD(Word, s_in, end)                                \
+  do {                                                             \
+    register int charlength = 0;                                   \
+    register u_char *wptr = (Word)+1;                              \
+    register int length = 0;                                       \
+    register int numeric = 0;                                      \
+    unsigned short c;                                              \
+                                                                   \
+    charlength = parse_utf8_char((s_in),(end),&c);                 \
+                                                                   \
+    while (length+charlength <= MAXWORDLEN && charlength > 0 &&    \
+	   (is_unicode_letter(c) || (is_unicode_digit(c) &&        \
+				     ++numeric <= MAXNUMERIC))) {  \
+      while (charlength-- > 0) {                                   \
+        *wptr++ = *(s_in)++; length++;                             \
+      }                                                            \
+      charlength = parse_utf8_char((s_in),(end),&c);               \
+    }                                                              \
+    *(Word) = length;                                              \
+  }while(0)
+
+
+
+/* =========================================================================
+ * Macro: PARSE_NON_WORD
+ * Description: 
+ *      Extract a non-word out for storing compressed text
+ * Input: as above
+ * Output: as above
+ * ========================================================================= */
+#define PARSE_NON_WORD(Word, s_in, end)                            \
+  do {                                                             \
+    register int charlength = 0;                                   \
+    register u_char *wptr = (Word)+1;                              \
+    register int length = 0;                                       \
+    unsigned short c;                                              \
+                                                                   \
+    charlength = parse_utf8_char((s_in),(end),&c);                 \
+                                                                   \
+    while (length+charlength <= MAXWORDLEN && charlength > 0 &&    \
+	   !is_unicode_letdig(c)) {                                \
+      while (charlength-- > 0) {                                   \
+        *wptr++ = *(s_in)++; length++;                             \
+      }                                                            \
+      charlength = parse_utf8_char((s_in),(end),&c);               \
+    }                                                              \
+    *(Word) = length;                                              \
+  }while(0)
Index: /main/tags/2.25/gsdl/src/recpt/GCC.mak
===================================================================
--- /main/tags/2.25/gsdl/src/recpt/GCC.mak	(revision 21064)
+++ /main/tags/2.25/gsdl/src/recpt/GCC.mak	(revision 21064)
@@ -0,0 +1,141 @@
+###########################################################################
+#
+# gcc win32 makefile -- src/recpt
+# A component of the Greenstone digital library software
+# from the New Zealand Digital Library Project at the
+# University of Waikato, New Zealand.
+#
+# Copyright (C) 2000  The 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.
+#
+###########################################################################
+
+AR = ar
+RANLIB = ranlib
+CC = g++
+DELETE = del
+INSTALL = copy
+
+o = .o
+/ = \\
+
+CPPFLAGS = -g -Wall
+DEFS = -D__WIN32__ -DGSDL_USE_IOS_H
+LIBS = ..$/..$/packages$/wingdbm$/gdbm.a ..$/..$/packages$/wincrypt$/crypt.a
+
+INCLUDES = -I"..$/..$/lib" -I"..$/colservr" -I"..$/..$/packages$/mg$/lib" \
+           -I"..$/..$/packages$/mg$/src$/text" -I"..$/..$/packages$/wincrypt" \
+           -I"..$/..$/packages$/wingdbm" -I"."
+ 
+COMPILE = $(CC) -c $(DEFS) $(INCLUDES) $(CPPFLAGS)
+LINK = $(CC) $(LDFLAGS) -o $@
+ 
+.SUFFIXES:
+.SUFFIXES: .c $o
+.c$o:
+	$(COMPILE) $<
+
+.SUFFIXES: .cpp $o
+.cpp$o:
+	$(COMPILE) $< 
+
+COMMONHEADERS = receptionist.h cgiwrapper.h cgiargs.h action.h browserclass.h \
+                converter.h recptconfig.h cgiutils.h OIDtools.h browsetools.h htmlgen.h \
+		statusaction.h pageaction.h comtypes.h recptproto.h \
+		pingaction.h queryaction.h documentaction.h \
+		extlinkaction.h buildaction.h htmlutils.h \
+		querytools.h formattools.h tipaction.h authenaction.h infodbclass.h \
+                userdb.h usersaction.h vlistbrowserclass.h hlistbrowserclass.h \
+		datelistbrowserclass.h invbrowserclass.h pagedbrowserclass.h \
+		htmlbrowserclass.h delhistoryaction.h historydb.h
+
+RECEPTHEADERS = 
+
+LIBRARYHEADERS = nullproto.h
+
+HEADERS = $(COMMONHEADERS) $(RECPTHEADERS) $(LIBRARYHEADERS)
+
+
+COMMONSOURCES = receptionist.cpp cgiwrapper.cpp cgiargs.cpp action.cpp browserclass.cpp \
+                converter.cpp recptconfig.cpp cgiutils.cpp OIDtools.cpp browsetools.cpp \
+		htmlgen.cpp statusaction.cpp pageaction.cpp comtypes.cpp \
+		recptproto.cpp pingaction.cpp queryaction.cpp documentaction.cpp \
+		extlinkaction.cpp buildaction.cpp htmlutils.cpp querytools.cpp formattools.cpp \
+		tipaction.cpp authenaction.cpp infodbclass.cpp userdb.cpp usersaction.cpp \
+		vlistbrowserclass.cpp hlistbrowserclass.cpp datelistbrowserclass.cpp \
+		invbrowserclass.cpp pagedbrowserclass.cpp htmlbrowserclass.cpp \
+		delhistoryaction.cpp historydb.cpp
+
+RECPTSOURCES = recptmain.cpp
+
+LIBRARYSOURCES = nullproto.cpp librarymain.cpp
+
+SOURCES = $(COMMONSOURCES) $(RECPTSOURCES) $(LIBRARYSOURCES)
+
+
+COMMONOBJECTS = receptionist$o cgiwrapper$o cgiargs$o action$o browserclass$o \
+                converter$o recptconfig$o cgiutils$o OIDtools$o browsetools$o \
+		htmlgen$o statusaction$o pageaction$o comtypes$o \
+		recptproto$o pingaction$o queryaction$o documentaction$o \
+		extlinkaction$o buildaction$o htmlutils$o querytools$o \
+		formattools$o tipaction$o authenaction$o \
+                infodbclass$o userdb$o usersaction$o vlistbrowserclass$o \
+		hlistbrowserclass$o datelistbrowserclass$o invbrowserclass$o \
+		pagedbrowserclass$o htmlbrowserclass$o delhistoryaction$o \
+		historydb$o
+
+RECPTOBJECTS = recptmain$o
+
+LIBRARYOBJECTS = nullproto$o librarymain$o
+
+OBJECTS = $(COMMONOBJECTS) $(RECPTOBJECTS) $(LIBRARYOBJECTS)
+
+
+COLSERVROBJECTS = ..$/colservr$/mgq$o \
+                  ..$/colservr$/mgsearch$o \
+                  ..$/colservr$/querycache$o \
+                  ..$/colservr$/queryinfo$o \
+                  ..$/colservr$/collectserver$o \
+                  ..$/colservr$/colservrconfig$o \
+                  ..$/colservr$/maptools$o \
+                  ..$/colservr$/filter$o \
+                  ..$/colservr$/source$o \
+                  ..$/colservr$/browsefilter$o \
+                  ..$/colservr$/queryfilter$o \
+                  ..$/colservr$/mggdbmsource$o \
+                  ..$/colservr$/phrasesearch$o \
+                  ..$/colservr$/phrasequeryfilter$o
+
+
+EXEC = library.exe
+
+all: $(EXEC)
+
+clean:
+	if EXIST *$o $(DELETE) *$o
+	if EXIST $(EXEC) $(DELETE) $(EXEC)
+
+install:
+	$(INSTALL) $(EXEC) ..$/..$/cgi-bin$/
+
+LIBRARY_OBJS = $(COMMONOBJECTS) $(LIBRARYOBJECTS) $(COLSERVROBJECTS) \
+    ..$/..$/lib$/gsdllib.a  \
+    ..$/..$/packages$/mg$/src$/text$/libtextin.a \
+    ..$/..$/packages$/mg$/lib$/libmg.a
+
+library.exe: $(LIBRARY_OBJS)
+	$(LINK) $(LIBRARY_OBJS) $(LIBS) 
Index: /main/tags/2.25/gsdl/src/recpt/Makefile.in
===================================================================
--- /main/tags/2.25/gsdl/src/recpt/Makefile.in	(revision 21064)
+++ /main/tags/2.25/gsdl/src/recpt/Makefile.in	(revision 21064)
@@ -0,0 +1,205 @@
+###########################################################################
+#
+# Makefile -- src/recpt
+# A component of the Greenstone digital library software
+# from the New Zealand Digital Library Project at the
+# University of Waikato, New Zealand.
+#
+# Copyright (C) 1999  The 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.
+#
+###########################################################################
+
+AR = ar
+CC = @CC@
+#CCFLAGS = @CFLAGS@ -Wall -Wunused -pedantic -W -Woverloaded-virtual
+CCFLAGS = @CFLAGS@
+
+USE_FASTCGI = @USE_FASTCGI@
+ifneq ($(USE_FASTCGI), 1)
+DEFS = -DNZDL -DQUIET -DSHORT_SUFFIX -DPARADOCNUM -DGSDLSERVER \
+       -DGSDLUSAGELOG @DEFS@
+
+INCLUDES = -I../../lib -I. -I../colservr -I../../packages/mg \
+	   -I../../packages/mg/lib -I../../packages/mg/src/text \
+	   -I../mgpp/lib -I../mgpp/text
+else 
+DEFS = -DNZDL -DQUIET -DSHORT_SUFFIX -DPARADOCNUM -DGSDLSERVER \
+       -DGSDLUSAGELOG -DUSE_FASTCGI @DEFS@
+
+INCLUDES = -I../../lib -I. -I../colservr -I../../packages/mg \
+	   -I../../packages/mg/lib -I../../packages/mg/src/text \
+           -I../../packages/fcgi/include -I../mgpp/lib \
+	   -I../mgpp/text
+endif
+
+RANLIB = @RANLIB@
+LDFLAGS = @LDFLAGS@
+LIBS = @LIBS@
+
+GSDLOS = @gsdlos@
+
+
+COMPILE = $(CC) -c $(CCFLAGS) $(DEFS) $(INCLUDES)
+LINK = $(CC) $(LDFLAGS) -o $@
+
+.SUFFIXES:
+.SUFFIXES: .c .o
+.c.o:
+	$(COMPILE) $<
+
+.SUFFIXES: .cpp .o
+.cpp.o:
+	$(COMPILE) $< 
+
+COMMONHEADERS = receptionist.h cgiwrapper.h cgiargs.h action.h browserclass.h \
+                converter.h recptconfig.h cgiutils.h OIDtools.h browsetools.h htmlgen.h \
+		statusaction.h pageaction.h comtypes.h recptproto.h \
+		pingaction.h queryaction.h documentaction.h \
+		extlinkaction.h buildaction.h htmlutils.h \
+		querytools.h formattools.h tipaction.h authenaction.h infodbclass.h \
+                userdb.h usersaction.h vlistbrowserclass.h hlistbrowserclass.h \
+		datelistbrowserclass.h invbrowserclass.h pagedbrowserclass.h \
+		htmlbrowserclass.h delhistoryaction.h historydb.h
+
+RECEPTHEADERS = 
+
+LIBRARYHEADERS = nullproto.h
+
+HEADERS = $(COMMONHEADERS) $(RECPTHEADERS) $(LIBRARYHEADERS)
+
+
+COMMONSOURCES = receptionist.cpp cgiwrapper.cpp cgiargs.cpp action.cpp browserclass.cpp \
+                converter.cpp recptconfig.cpp cgiutils.cpp OIDtools.cpp browsetools.cpp \
+		htmlgen.cpp statusaction.cpp pageaction.cpp comtypes.cpp \
+		recptproto.cpp pingaction.cpp queryaction.cpp documentaction.cpp \
+		extlinkaction.cpp buildaction.cpp htmlutils.cpp querytools.cpp formattools.cpp \
+		tipaction.cpp authenaction.cpp infodbclass.cpp userdb.cpp usersaction.cpp \
+		vlistbrowserclass.cpp hlistbrowserclass.cpp datelistbrowserclass.cpp \
+		invbrowserclass.cpp pagedbrowserclass.cpp htmlbrowserclass.cpp \
+		delhistoryaction.cpp historydb.cpp
+
+
+RECPTSOURCES = recptmain.cpp
+
+LIBRARYSOURCES = nullproto.cpp librarymain.cpp
+
+SOURCES = $(COMMONSOURCES) $(RECPTSOURCES) $(LIBRARYSOURCES)
+
+
+COMMONOBJECTS = receptionist.o cgiwrapper.o cgiargs.o action.o browserclass.o \
+                converter.o recptconfig.o cgiutils.o OIDtools.o browsetools.o \
+		htmlgen.o statusaction.o pageaction.o comtypes.o \
+		recptproto.o pingaction.o queryaction.o documentaction.o \
+		extlinkaction.o buildaction.o htmlutils.o querytools.o \
+		formattools.o tipaction.o authenaction.o \
+                infodbclass.o userdb.o usersaction.o vlistbrowserclass.o \
+		hlistbrowserclass.o datelistbrowserclass.o invbrowserclass.o \
+		pagedbrowserclass.o htmlbrowserclass.o delhistoryaction.o \
+		historydb.o
+
+RECPTOBJECTS = recptmain.o
+
+LIBRARYOBJECTS = nullproto.o librarymain.o
+
+OBJECTS = $(COMMONOBJECTS) $(RECPTOBJECTS) $(LIBRARYOBJECTS)
+
+
+COLSERVROBJECTS = ../colservr/mgq.o \
+		  ../colservr/search.o \
+                  ../colservr/mgsearch.o \
+                  ../colservr/querycache.o \
+                  ../colservr/queryinfo.o \
+                  ../colservr/collectserver.o \
+                  ../colservr/colservrconfig.o \
+                  ../colservr/maptools.o \
+                  ../colservr/filter.o \
+                  ../colservr/source.o \
+                  ../colservr/browsefilter.o \
+                  ../colservr/queryfilter.o \
+                  ../colservr/mggdbmsource.o \
+                  ../colservr/phrasesearch.o \
+                  ../colservr/phrasequeryfilter.o \
+		  ../colservr/mgqueryfilter.o \
+		  ../colservr/mgppsearch.o \
+		  ../colservr/mgppqueryfilter.o
+
+
+EXEC = recpt library
+
+all: $(EXEC)
+
+distclean:
+	rm -f $(OBJECTS) $(EXEC) Makefile
+
+clean:
+	rm -f $(OBJECTS) $(EXEC)
+
+install:
+	install -m 755 -s library ../../cgi-bin/library
+
+depend:
+	makedepend -Y -- $(DEFS) $(INCLUDES) $(CCFLAGS) -- $(SOURCES)
+
+# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
+
+ifneq ($(USE_FASTCGI), 1)
+RECPT_OBJS = $(COMMONOBJECTS) $(RECPTOBJECTS) \
+    ../../lib/gsdllib.a  \
+    ../../packages/mg/src/text/libtextin.a \
+    ../../packages/mg/lib/libmg.a \
+    ../mgpp/text/libtextin.a \
+    ../mgpp/lib/libmg.a 
+else
+RECPT_OBJS = $(COMMONOBJECTS) $(RECPTOBJECTS) \
+    ../../lib/gsdllib.a  \
+    ../../packages/mg/src/text/libtextin.a \
+    ../../packages/mg/lib/libmg.a \
+    ../../packages/fcgi/libfcgi/libfcgi.a \
+    ../mgpp/text/libtextin.a \
+    ../mgpp/lib/libmg.a 
+endif
+
+recpt: $(RECPT_OBJS)
+	$(LINK) $(RECPT_OBJS) $(LIBS) 
+
+# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
+
+ifneq ($(USE_FASTCGI), 1)
+LIBRARY_OBJS = $(COMMONOBJECTS) $(LIBRARYOBJECTS) $(COLSERVROBJECTS) \
+    ../../lib/gsdllib.a  \
+    ../../packages/mg/src/text/libtextin.a \
+    ../../packages/mg/lib/libmg.a \
+    ../mgpp/text/libtextin.a \
+    ../mgpp/lib/libmg.a 
+else
+LIBRARY_OBJS = $(COMMONOBJECTS) $(LIBRARYOBJECTS) $(COLSERVROBJECTS) \
+    ../../lib/gsdllib.a  \
+    ../../packages/mg/src/text/libtextin.a \
+    ../../packages/mg/lib/libmg.a \
+    ../../packages/fcgi/libfcgi/libfcgi.a \
+    ../mgpp/text/libtextin.a \
+    ../mgpp/lib/libmg.a 
+endif
+
+library: $(LIBRARY_OBJS)
+	$(LINK) $(LIBRARY_OBJS) $(LIBS) 
+
+
+
+
+
Index: /main/tags/2.25/gsdl/src/recpt/OIDtools.cpp
===================================================================
--- /main/tags/2.25/gsdl/src/recpt/OIDtools.cpp	(revision 21064)
+++ /main/tags/2.25/gsdl/src/recpt/OIDtools.cpp	(revision 21064)
@@ -0,0 +1,306 @@
+/**********************************************************************
+ *
+ * OIDtools.cpp -- 
+ * Copyright (C) 1999  The New Zealand Digital Library Project
+ *
+ * A component of the Greenstone digital library software
+ * from the New Zealand Digital Library Project at the
+ * University of Waikato, New Zealand.
+ *
+ * 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.
+ *
+ *********************************************************************/
+
+#include "OIDtools.h"
+
+
+// returns (in top) the top level of OID (i.e. everything
+// up until the first dot)
+void get_top (const text_t &OID, text_t &top) {
+
+  top.clear();
+  if (OID.empty()) return;
+
+  text_t::const_iterator begin = OID.begin();
+  text_t::const_iterator end = OID.end();
+
+  top.appendrange (begin, findchar(begin, end, '.'));
+}	
+
+
+// checks if OID is top level (i.e. contains no dots)
+bool is_top (const text_t &OID) {
+
+  if (OID.empty()) return true;
+
+  text_t::const_iterator here = OID.begin();
+  text_t::const_iterator end = OID.end();
+  here = findchar (here, end, '.');
+
+  if (here == end) return true;
+  return false;
+}
+
+
+// get_parents_array loads the parents array with all the parents of the
+// document or classification specified by OID (not including OID itself)
+void get_parents_array (const text_t &OID, text_tarray &parents) {
+
+  text_t::const_iterator here = OID.begin ();
+  text_t::const_iterator end = OID.end ();
+  text_t thisparent;
+
+  while (here != end) {
+    if (*here == '.') parents.push_back(thisparent);
+    thisparent.push_back(*here);
+    here ++;
+  }
+}
+
+
+// get_info does a protocol call and returns (in response) the metadata 
+// associated with OID. Metadata should be loaded with whatever
+// metadata fields are to be requested.
+
+bool get_info (const text_t &OID, const text_t &collection,
+	       const text_tset &metadata, bool getParents,
+	       recptproto *collectproto, FilterResponse_t &response, 
+	       ostream &logout) {
+
+  response.clear();
+
+  comerror_t err;
+  FilterRequest_t request;
+
+  request.filterName = "NullFilter";
+  request.filterResultOptions = FRmetadata;
+  request.getParents = getParents;
+  request.fields = metadata;
+  request.docSet.push_back (OID);
+  
+  collectproto->filter (collection, request, response, err, logout);
+  if (err != noError) {
+    outconvertclass text_t2ascii;
+    logout << text_t2ascii
+	   << "Error: call to filter failed for " << OID
+	   << " in OIDtools::get_info (" 
+	   << get_comerror_string (err) << ")\n";
+    return false;
+  }
+  
+  return true;
+}
+
+bool get_info (const text_tarray &OIDs, const text_t &collection,
+	       const text_tset &metadata, bool getParents,
+	       recptproto *collectproto, FilterResponse_t &response, 
+	       ostream &logout) {
+
+  response.clear();
+  if (OIDs.empty()) return true;
+
+  comerror_t err;
+  FilterRequest_t request;
+
+  request.filterName = "NullFilter";
+  request.filterResultOptions = FRmetadata;
+  request.getParents = getParents;
+  request.fields = metadata;
+
+  request.docSet = OIDs;
+  
+  collectproto->filter (collection, request, response, err, logout);
+  if (err != noError) {
+    outconvertclass text_t2ascii;
+    logout << text_t2ascii
+	   << "Error: call to filter failed in OIDtools::get_info (" 
+	   << get_comerror_string (err) << ")\n";
+    return false;
+  }
+
+  return true;
+}
+
+// has_children returns true if OID has children
+bool has_children (const text_t &OID, const text_t &collection, 
+		   recptproto *collectproto, ostream &logout) {
+
+  FilterResponse_t response;
+  text_tset metadata;
+  metadata.insert ("haschildren");
+
+  if (get_info (OID, collection, metadata, false, collectproto,	response, logout)) {
+    if (response.docInfo[0].metadata["haschildren"].values[0] == "1")
+      return true;
+  }
+  return false;
+}
+
+
+// get_children does a protocol call and returns (in response) the OIDs and 
+// metadata of all the children of OID. The metadata set should be loaded
+// with whatever metadata fields are to be requested.
+
+bool get_children (const text_t &OID, const text_t &collection, 
+		   const text_tset &metadata, bool getParents,
+		   recptproto *collectproto, FilterResponse_t &response, 
+		   ostream &logout) {
+  
+  response.clear();
+
+  comerror_t err;
+  FilterRequest_t request;
+  OptionValue_t option;
+
+  option.name = "ParentNode";
+  option.value = OID;
+  request.filterOptions.push_back (option);
+  request.filterName = "BrowseFilter";
+  request.filterResultOptions = FROID | FRmetadata;
+  request.fields = metadata;
+  request.getParents = getParents;
+
+  collectproto->filter (collection, request, response, err, logout);
+
+  if (err != noError) {
+    outconvertclass text_t2ascii;
+    logout << text_t2ascii
+	   << "Error: call to filter failed for " << OID 
+	   << " in OIDtools::get_children (" 
+	   << get_comerror_string (err) << ")\n";
+    return false;
+  }
+  return true;
+}
+
+// get_parent returns the parent of the document or classification
+// specified by OID
+text_t get_parent (text_t OID) {
+
+  if (OID.empty() || is_top (OID)) return "";
+
+  text_t::const_iterator begin = OID.begin();
+  text_t::const_iterator here = (OID.end() - 1);
+
+  while (here >= begin) {
+    OID.pop_back();
+    if (*here == '.') break;
+    here --;
+  }
+  return OID;
+}
+
+// takes an OID like ".2 and replaces the " with parent
+void translate_parent (text_t &OID, const text_t &parent) {
+
+  text_t::const_iterator here = OID.begin();
+  text_t::const_iterator end = OID.end();
+  text_t temp;
+
+  while (here != end) {
+    if (*here == '"') temp += parent;
+    else temp.push_back (*here);
+    here ++;
+  }
+  OID = temp;
+}
+
+// shrink_parent does the opposite to translate_parent
+void shrink_parent (text_t &OID) {
+  
+  text_tarray tmp;
+  splitchar (OID.begin(), OID.end(), '.', tmp);
+  OID = "\"." + tmp.back();
+}
+
+// checks if OID uses ".fc", ".lc", ".pr", ".ns",
+// or ".ps" syntax (first child, last child, parent,
+// next sibling, previous sibling)
+bool needs_translating (const text_t &OID) {
+
+  if (OID.size() < 4) return false;
+
+  text_t tail = substr (OID.end()-3, OID.end());
+  if (tail == ".fc" || tail == ".lc" || tail == ".pr" || 
+      tail == ".ns" || tail == ".ps") return true;
+
+  return false;
+}
+
+// strips the ".fc", ".lc", ".pr", ".ns",
+// or ".ps" suffix from the end of OID
+void strip_suffix (text_t &OID) {
+
+  text_t tail = substr (OID.end()-3, OID.end());
+  while (tail == ".fc" || tail == ".lc" || tail == ".pr" || 
+	 tail == ".ns" || tail == ".ps") {
+    OID.erase (OID.end()-3, OID.end());
+    tail = substr (OID.end()-3, OID.end());
+  }
+}
+
+static void recurse_contents (ResultDocInfo_t section, const bool &is_classify, 
+			      const text_t &collection, const text_tset &metadata, 
+			      recptproto *collectproto, FilterResponse_t &response, 
+			      ostream &logout) {
+
+  int haschildren = section.metadata["haschildren"].values[0].getint();
+  const text_t &doctype = section.metadata["doctype"].values[0];
+
+  if ((haschildren == 1) && ((!is_classify) || (doctype == "classify"))) {
+    FilterResponse_t tmp;
+    bool getParents = false;
+    get_children (section.OID, collection, metadata, getParents, collectproto, tmp, logout);
+    ResultDocInfo_tarray::iterator thisdoc = tmp.docInfo.begin();
+    ResultDocInfo_tarray::iterator lastdoc = tmp.docInfo.end();
+    while (thisdoc != lastdoc) {
+      response.docInfo.push_back (*thisdoc);
+      recurse_contents (*thisdoc, is_classify, collection, metadata, 
+			collectproto, response, logout);
+      thisdoc ++;
+    }
+  }
+}
+
+// get_contents returns OIDs and metadata of all contents 
+// below (and including) OID.
+void get_contents (const text_t &topOID, const bool &is_classify, 
+		   text_tset &metadata, const text_t &collection, 
+		   recptproto *collectproto, FilterResponse_t &response, 
+		   ostream &logout) {
+
+  if (topOID.empty()) return;
+  response.clear();
+
+  metadata.insert ("haschildren");
+  metadata.insert ("doctype");
+
+  // get topOIDs info
+  if (get_info (topOID, collection, metadata, false, collectproto, response, logout))
+      recurse_contents (response.docInfo[0], is_classify, collection, 
+			metadata, collectproto, response, logout);
+}
+
+// is_child_of returns true if OID2 is a child of OID1
+bool is_child_of(const text_t &OID1, const text_t &OID2) {
+
+  text_t parent = get_parent(OID2);
+
+  while (!parent.empty()) {
+    if (parent == OID1) return true;
+    parent = get_parent(parent);
+  }
+  return false;
+}
Index: /main/tags/2.25/gsdl/src/recpt/OIDtools.h
===================================================================
--- /main/tags/2.25/gsdl/src/recpt/OIDtools.h	(revision 21064)
+++ /main/tags/2.25/gsdl/src/recpt/OIDtools.h	(revision 21064)
@@ -0,0 +1,98 @@
+/**********************************************************************
+ *
+ * OIDtools.h -- 
+ * Copyright (C) 1999  The New Zealand Digital Library Project
+ *
+ * A component of the Greenstone digital library software
+ * from the New Zealand Digital Library Project at the
+ * University of Waikato, New Zealand.
+ *
+ * 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.
+ *
+ *********************************************************************/
+
+
+#ifndef OIDTOOLS_H
+#define OIDTOOLS_H
+
+#include "text_t.h"
+#include "recptproto.h"
+
+// returns (in top) the top level of OID (i.e. everything
+// up until the first dot)
+void get_top (const text_t &OID, text_t &top);
+
+// checks if OID is top level (i.e. contains no dots)
+bool is_top (const text_t &OID);
+
+// get_parents_array loads the parents array with all the parents of the
+// document or classification specified by OID (not including OID itself)
+void get_parents_array (const text_t &OID, text_tarray &parents);
+
+// get_info does a protocol call and returns (in response) the info 
+// associated with OID. Metadata should be loaded with whatever
+// metadata fields are to be requested
+bool get_info (const text_t &OID, const text_t &collection,
+	       const text_tset &metadata, bool getParents,
+	       recptproto *collectproto, FilterResponse_t &response, 
+	       ostream &logout);
+bool get_info (const text_tarray &OIDs, const text_t &collection,
+	       const text_tset &metadata, bool getParents,
+	       recptproto *collectproto, FilterResponse_t &response, 
+	       ostream &logout);
+
+// has_children returns true if OID has children
+bool has_children (const text_t &OID, const text_t &collection, 
+		   recptproto *collectproto, ostream &logout);
+
+// get_children does a protocol call and returns (in response) the OIDs and 
+// metadata of all the children of OID. The metadata set should be loaded
+// with whatever metadata fields are to be requested.
+bool get_children (const text_t &OID, const text_t &collection, 
+		   const text_tset &metadata, bool getParents,
+		   recptproto *collectproto, FilterResponse_t &response, 
+		   ostream &logout);
+
+// get_parent returns the parent of the document or classification
+// specified by OID
+text_t get_parent (text_t OID);
+
+// takes an OID like ".2.3 and replaces the " with parent
+void translate_parent (text_t &OID, const text_t &parent);
+
+// shrink_parent does the opposite to translate_parent
+void shrink_parent (text_t &OID);
+
+// checks if OID uses ".fc", ".lc", ".pr", ".ns",
+// or ".ps" syntax (first child, last child, parent,
+// next sibling, previous sibling)
+bool needs_translating (const text_t &OID);
+
+// strips the ".fc", ".lc", ".pr", ".ns",
+// or ".ps" suffix from the end of OID
+void strip_suffix (text_t &OID);
+
+// get_contents returns OIDs and metadata of all contents 
+// below (and including) OID.
+void get_contents (const text_t &topOID, const bool &is_classify, 
+		   text_tset &metadata, const text_t &collection, 
+		   recptproto *collectproto, FilterResponse_t &response, 
+		   ostream &logout);
+
+// is_child_of returns true if OID2 is a child of OID1
+bool is_child_of(const text_t &OID1, const text_t &OID2);
+
+
+#endif
Index: /main/tags/2.25/gsdl/src/recpt/action.cpp
===================================================================
--- /main/tags/2.25/gsdl/src/recpt/action.cpp	(revision 21064)
+++ /main/tags/2.25/gsdl/src/recpt/action.cpp	(revision 21064)
@@ -0,0 +1,153 @@
+/**********************************************************************
+ *
+ * action.cpp -- 
+ * Copyright (C) 1999  The New Zealand Digital Library Project
+ *
+ * A component of the Greenstone digital library software
+ * from the New Zealand Digital Library Project at the
+ * University of Waikato, New Zealand.
+ *
+ * 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.
+ *
+ *********************************************************************/
+
+#include "action.h"
+#include <assert.h>
+
+
+// define all the macros which are related to pages generated
+// by this action
+void action::define_internal_macros (displayclass &/*disp*/, cgiargsclass &/*args*/, 
+				     recptprotolistclass * /*protos*/, ostream &/*logout*/) {
+}
+
+action::action () {
+}
+
+action::~action () {
+}
+
+// configure should be called once for each configuration line
+void action::configure (const text_t &key, const text_tarray &cfgline) {
+  if (key == "gsdlhome") {gsdlhome = cfgline[0];}
+}
+
+// init should be called after all the configuration is done but
+// before any other methods are called
+bool action::init (ostream &/*logout*/) {
+  return true;
+}
+
+// returns the "a" argument value that will specify this action
+// this name should be short but does not have to be one character
+// long
+text_t action::get_action_name () {
+  return "nzdl";
+}
+
+// check_cgiargs should be called before get_cgihead_info, 
+// define_external_macros, and do_action. If an error is found
+// a message will be written to logout, if the error is severe
+// then the function will return false and no page content
+// should be produced based on the arguments.
+bool action::check_cgiargs (cgiargsinfoclass &/*argsinfo*/, cgiargsclass &/*args*/, 
+			    ostream &/*logout*/) {
+  return true;
+}
+
+// check_external_cgiargs should be called after check_cgiargs
+// for all actions. It should only be used to override some other
+// normal behaviour, for example, producing a login page when
+// the requested page needs authentication.
+bool action::check_external_cgiargs (cgiargsinfoclass &/*argsinfo*/,
+				     cgiargsclass &/*args*/,
+				     outconvertclass &/*outconvert*/,
+				     const text_t &/*saveconf*/,
+				     ostream &/*logout*/) {
+  return true;
+}
+
+// get_cgihead_info determines the cgi header information for
+// a set of cgi arguments. If response contains location then
+// response_data contains the redirect address. If reponse
+// contains content then reponse_data contains the content-type.
+// Note that images can now be produced by the receptionist.
+void action::get_cgihead_info (cgiargsclass &/*args*/, recptprotolistclass * /*protos*/,
+			       response_t &response, text_t &response_data, 
+			       ostream &/*logout*/) {
+  response = location;
+  response_data = "http://www.nzdl.org";
+}
+  
+// uses_display should return true if the receptionist should return
+// true if the display class is needed to output the page content
+// The default is to return true.
+bool action::uses_display (cgiargsclass &/*args*/) {
+  return true;
+}
+
+
+// define all the macros which might be used by other actions
+// to produce pages. These macros should be well documented.
+void action::define_external_macros (displayclass &/*disp*/, cgiargsclass &/*args*/, 
+				     recptprotolistclass * /*protos*/, ostream &/*logout*/) {
+}
+
+// returns false if there was an error which prevented the action
+// from outputing anything.
+bool action::do_action (cgiargsclass &/*args*/, recptprotolistclass * /*protos*/, 
+			browsermapclass * /*browsers*/, displayclass &/*disp*/, 
+			outconvertclass &/*outconvert*/, ostream &/*textout*/, 
+			ostream &/*logout*/) {
+  return true;
+}
+
+
+bool operator==(const actionptr &x, const actionptr &y) {
+  return (x.a == y.a);
+}
+
+bool operator<(const actionptr &x, const actionptr &y) {
+  return (x.a < y.a);
+}
+
+
+// theaction remains the property of the calling code but
+// should not be deleted until it is removed from this list.
+void actionmapclass::addaction (action *theaction) {
+  // can't add a null action
+  assert (theaction != NULL);
+  if (theaction == NULL) return;
+  
+  // can't add an action with no name
+  assert (!(theaction->get_action_name()).empty());
+  if ((theaction->get_action_name()).empty()) return;
+
+  actionptr aptr;
+  aptr.a = theaction;
+  actionptrs[theaction->get_action_name()] = aptr;
+}
+
+// getaction will return NULL if the action could not be found
+action *actionmapclass::getaction (const text_t &key) {
+  // can't find an action with no name
+  assert (!key.empty());
+  if (key.empty()) return NULL;
+
+  iterator here = actionptrs.find (key);
+  if (here == actionptrs.end()) return NULL;
+  
+  return (*here).second.a;
+}
Index: /main/tags/2.25/gsdl/src/recpt/action.h
===================================================================
--- /main/tags/2.25/gsdl/src/recpt/action.h	(revision 21064)
+++ /main/tags/2.25/gsdl/src/recpt/action.h	(revision 21064)
@@ -0,0 +1,179 @@
+/**********************************************************************
+ *
+ * action.h -- 
+ * Copyright (C) 1999  The New Zealand Digital Library Project
+ *
+ * A component of the Greenstone digital library software
+ * from the New Zealand Digital Library Project at the
+ * University of Waikato, New Zealand.
+ *
+ * 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.
+ *
+ *********************************************************************/
+
+
+#ifndef ACTION_H
+#define ACTION_H
+
+#include "gsdlconf.h"
+#include "text_t.h"
+#include "cgiargs.h"
+#include "display.h"
+#include "recptproto.h"
+#include "browserclass.h"
+
+#if defined(GSDL_USE_OBJECTSPACE)
+#  include <ospace\std\iostream>
+#elif defined(GSDL_USE_IOS_H)
+#  include <iostream.h>
+#else
+#  include <iostream>
+#endif
+
+
+class action {
+protected:
+  cgiargsinfoclass argsinfo;
+  text_t gsdlhome;
+
+public:
+  action ();
+  virtual ~action ();
+
+  // configure should be called once for each configuration line
+  virtual void configure (const text_t &key, const text_tarray &cfgline);
+
+  // init should be called after all the configuration is done but
+  // before any other methods are called
+  virtual bool init (ostream &logout);
+
+  // returns the "a" argument value that will specify this action
+  // this name should be short but does not have to be one character
+  // long
+  virtual text_t get_action_name ();
+
+  // check_cgiargs should be called before get_cgihead_info, 
+  // define_external_macros, and do_action. If an error is found
+  // a message will be written to logout, if the error is severe
+  // then the function will return false and no page content
+  // should be produced based on the arguments.
+  virtual bool check_cgiargs (cgiargsinfoclass &argsinfo, cgiargsclass &args, 
+			      ostream &logout);
+
+  // check_external_cgiargs should be called after check_cgiargs
+  // for all actions. It should only be used to override some other
+  // normal behaviour, for example, producing a login page when
+  // the requested page needs authentication.
+  virtual bool check_external_cgiargs (cgiargsinfoclass &argsinfo,
+				       cgiargsclass &args,
+				       outconvertclass &outconvert,
+				       const text_t &saveconf,
+				       ostream &logout);
+
+  // get_cgihead_info determines the cgi header information for
+  // a set of cgi arguments. If response contains location then
+  // response_data contains the redirect address. If reponse
+  // contains content then reponse_data contains the content-type.
+  // Note that images can now be produced by the receptionist.
+  virtual void get_cgihead_info (cgiargsclass &args, recptprotolistclass *protos,
+				 response_t &response, text_t &response_data, 
+				 ostream &logout);
+  
+  // uses_display should return true if the receptionist should return
+  // true if the display class is needed to output the page content.
+  // The default is to return true.
+  virtual bool uses_display (cgiargsclass &args);
+
+  // define all the macros which are related to pages generated
+  // by this action
+  virtual void define_internal_macros (displayclass &disp, cgiargsclass &args, 
+				       recptprotolistclass *protos, ostream &logout);
+
+  // define all the macros which might be used by other actions
+  // to produce pages. These macros should be well documented.
+  virtual void define_external_macros (displayclass &disp, cgiargsclass &args, 
+				       recptprotolistclass *protos, ostream &logout);
+
+  // returns false if there was an error which prevented the action
+  // from outputing anything.
+  virtual bool do_action (cgiargsclass &args, recptprotolistclass *protos, 
+			  browsermapclass *browsers, displayclass &disp, 
+			  outconvertclass &outconvert, ostream &textout, 
+			  ostream &logout);
+  
+  // getargsinfo should be called after all configuration files
+  // have been read
+  cgiargsinfoclass getargsinfo () {return argsinfo;};
+};
+
+
+// The actionptr function does not 'own' the action. The 
+// action should be deleted by the code which created it.
+class actionptr {
+public:
+  action *a;
+
+  actionptr () {a=NULL;}
+};
+
+bool operator==(const actionptr &x, const actionptr &y);
+bool operator<(const actionptr &x, const actionptr &y);
+
+typedef map<text_t, actionptr, lttext_t> actionptrmap;
+
+// contains a list of actions indexed by their name
+class actionmapclass {
+protected:
+  actionptrmap actionptrs;
+
+public:
+  // type support for actionptrmap
+  typedef actionptrmap::iterator iterator;
+  typedef actionptrmap::const_iterator const_iterator;
+  typedef actionptrmap::reference reference;
+  typedef actionptrmap::const_reference const_reference;
+  typedef actionptrmap::size_type size_type;
+
+  typedef actionptrmap::difference_type difference_type;
+  typedef actionptrmap::const_reverse_iterator const_reverse_iterator;
+  typedef actionptrmap::reverse_iterator reverse_iterator;
+  
+  // basic container support
+  iterator begin () {return actionptrs.begin();}
+  const_iterator begin () const {return actionptrs.begin();}
+  iterator end () {return actionptrs.end();}
+  const_iterator end () const {return actionptrs.end();}
+
+  void erase(iterator pos) {actionptrs.erase(pos);}
+  void erase(iterator first, iterator last) {actionptrs.erase(first, last);}
+  actionmapclass &operator=(const actionmapclass &x) {actionptrs=x.actionptrs;return *this;}
+
+  bool empty () const {return actionptrs.empty();}
+  size_type size() const {return actionptrs.size();}
+
+
+  // added functionality
+  void clear () {actionptrs.erase(actionptrs.begin(),actionptrs.end());}
+
+  // theaction remains the property of the calling code but
+  // should not be deleted until it is removed from this list.
+  void addaction (action *theaction);
+
+  // getaction will return NULL if the action could not be found
+  action *getaction (const text_t &key);
+};
+
+
+#endif
Index: /main/tags/2.25/gsdl/src/recpt/authenaction.cpp
===================================================================
--- /main/tags/2.25/gsdl/src/recpt/authenaction.cpp	(revision 21064)
+++ /main/tags/2.25/gsdl/src/recpt/authenaction.cpp	(revision 21064)
@@ -0,0 +1,318 @@
+/**********************************************************************
+ *
+ * authenaction.cpp -- authenticating users
+ * Copyright (C) 1999  DigiLib Systems Limited, New Zealand
+ *
+ * A component of the Greenstone digital library software
+ * from the New Zealand Digital Library Project at the
+ * University of Waikato, New Zealand.
+ *
+ * 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.
+ *
+ *********************************************************************/
+
+#include "authenaction.h"
+#include "fileutil.h"
+#include "cfgread.h"
+#include "cgiutils.h"
+#include "infodbclass.h"
+#include "gsdltimes.h"
+#include "userdb.h"
+
+
+///////////////
+// authenaction
+///////////////
+
+authenaction::authenaction () {
+  keydecay = 600; // 10 minutes
+  recpt = NULL;
+
+  // this action uses cgi variable "a"
+  cgiarginfo arg_ainfo;
+  arg_ainfo.shortname = "a";
+  arg_ainfo.longname = "action";
+  arg_ainfo.multiplechar = true;
+  arg_ainfo.defaultstatus = cgiarginfo::weak;
+  arg_ainfo.argdefault = "a";
+  arg_ainfo.savedarginfo = cgiarginfo::must;
+  argsinfo.addarginfo (NULL, arg_ainfo);
+
+  // "us"
+  arg_ainfo.shortname = "us";
+  arg_ainfo.longname = "user account status";
+  arg_ainfo.multiplechar = true;
+  arg_ainfo.defaultstatus = cgiarginfo::weak;
+  arg_ainfo.argdefault = "invalid";
+  arg_ainfo.savedarginfo = cgiarginfo::mustnot;
+  argsinfo.addarginfo (NULL, arg_ainfo);
+
+  // "ug"
+  arg_ainfo.shortname = "ug";
+  arg_ainfo.longname = "user groups"; // comma seperated list
+  arg_ainfo.multiplechar = true;
+  arg_ainfo.defaultstatus = cgiarginfo::weak;
+  arg_ainfo.argdefault = "";
+  arg_ainfo.savedarginfo = cgiarginfo::mustnot;
+  argsinfo.addarginfo (NULL, arg_ainfo);
+
+  // "un"
+  arg_ainfo.shortname = "un";
+  arg_ainfo.longname = "user name";
+  arg_ainfo.multiplechar = true;
+  arg_ainfo.defaultstatus = cgiarginfo::weak;
+  arg_ainfo.argdefault = "";
+  arg_ainfo.savedarginfo = cgiarginfo::must;
+  argsinfo.addarginfo (NULL, arg_ainfo);
+
+  // "pw"
+  arg_ainfo.shortname = "pw";
+  arg_ainfo.longname = "password";
+  arg_ainfo.multiplechar = true;
+  arg_ainfo.defaultstatus = cgiarginfo::weak;
+  arg_ainfo.argdefault = "";
+  arg_ainfo.savedarginfo = cgiarginfo::mustnot;
+  argsinfo.addarginfo (NULL, arg_ainfo);
+
+  // "ky" - gives a specific user authentication for a
+  // limited amount of time
+  arg_ainfo.shortname = "ky";
+  arg_ainfo.longname = "user time key";
+  arg_ainfo.multiplechar = true;
+  arg_ainfo.defaultstatus = cgiarginfo::weak;
+  arg_ainfo.argdefault = "";
+  arg_ainfo.savedarginfo = cgiarginfo::must;
+  argsinfo.addarginfo (NULL, arg_ainfo);
+
+  // "ua" - ""=no, "1"=yes 
+  arg_ainfo.shortname = "ua";
+  arg_ainfo.longname = "whether a user has been authenticated";
+  arg_ainfo.multiplechar = true;
+  arg_ainfo.defaultstatus = cgiarginfo::weak;
+  arg_ainfo.argdefault = "";
+  arg_ainfo.savedarginfo = cgiarginfo::mustnot;
+  argsinfo.addarginfo (NULL, arg_ainfo);
+
+  // "er" - compressed arguments for the referer page
+  arg_ainfo.shortname = "er";
+  arg_ainfo.longname = "the compressed args of the refer page";
+  arg_ainfo.multiplechar = true;
+  arg_ainfo.defaultstatus = cgiarginfo::weak;
+  arg_ainfo.argdefault = "";
+  arg_ainfo.savedarginfo = cgiarginfo::mustnot;
+  argsinfo.addarginfo (NULL, arg_ainfo);
+
+  // "uan" - whether user authentication is needed
+  arg_ainfo.shortname = "uan";
+  arg_ainfo.longname = "whether user authentication is needed";
+  arg_ainfo.multiplechar = true;
+  arg_ainfo.defaultstatus = cgiarginfo::weak;
+  arg_ainfo.argdefault = "";
+  arg_ainfo.savedarginfo = cgiarginfo::mustnot;
+  argsinfo.addarginfo (NULL, arg_ainfo);
+}
+
+void authenaction::configure (const text_t &key, const text_tarray &cfgline) {
+  // get the password filename
+  if (cfgline.size() == 1) {
+    if (key == "usersfile") usersfile = cfgline[0];
+    else if (key == "keyfile") keyfile = cfgline[0];
+    else if (key == "keydecay") keydecay = cfgline[0].getint();
+    else if (key == "gsdlhome") {
+      if (usersfile.empty())
+	usersfile = filename_cat (cfgline[0], "etc", "users.db");
+      if (keyfile.empty())
+	keyfile = filename_cat (cfgline[0], "etc", "key.db");
+    }
+  }
+
+  action::configure (key, cfgline);
+}
+
+bool authenaction::init (ostream &logout) {
+  return action::init (logout);
+}
+
+bool authenaction::check_cgiargs (cgiargsinfoclass &/*argsinfo*/, cgiargsclass &/*args*/, 
+				  ostream &/*logout*/) {
+  return true;
+}
+
+// returns false if there is a major problem with the cgi arguments -- not
+// if authentication fails. If the authentication fails "un" will be empty
+bool authenaction::check_external_cgiargs (cgiargsinfoclass &argsinfo,
+					   cgiargsclass &args,
+					   outconvertclass &outconvert,
+					   const text_t &saveconf,
+					   ostream &logout) {
+  // failure means we have to redirect to this action to get authentication
+  // (if we are not already doing this)
+
+  userinfo_t thisuser;
+
+  text_t &args_uan = args["uan"];  text_t &args_un = args["un"];
+  text_t &args_pw = args["pw"];    text_t &args_us = args["us"];
+  text_t &args_ug = args["ug"];    text_t &args_ky = args["ky"];
+  text_t &args_ua = args["ua"];    text_t &args_a = args["a"];
+
+  // we must have a username and a password or a key to
+  // do any authentication
+  args_ua.clear(); // default = false;
+  if (args_un.empty() || args_pw.empty()) args_us = "invalid";
+  else args_us = "failed";
+
+  // make sure we have a username
+  if (!args_un.empty() && get_user_info (usersfile, args_un, thisuser)) {
+    if (!args_pw.empty()) {
+      // we are authenticating using a password
+      if (check_passwd (thisuser, args_pw)) args_ua = "1"; // succeeded
+      
+    } else if (!args_ky.empty()) {
+      // we are authenticating using a key
+      if (check_key (keyfile, thisuser, args_ky, args_ug, keydecay)) args_ua = "1";
+      else args_us = "stalekey";
+    }
+  }
+
+  args_pw.clear(); // password goes no further
+  if (!args_ua.empty()) {
+    if (thisuser.enabled) {
+      bool haspermission = true;
+      // check to make sure the user is in the required group
+      if (!args_ug.empty()) {
+	haspermission = false;
+	text_t::const_iterator group_here = thisuser.groups.begin();
+	text_t::const_iterator group_end = thisuser.groups.end();
+	text_t thisgroup;
+	while (group_here != group_end) {
+	  group_here = getdelimitstr (group_here, group_end, ',', thisgroup);
+	  if (thisgroup == args_ug) {
+	    haspermission = true;
+	    break;
+	  }
+	}
+      }
+
+      if (haspermission) {
+	// succeeded, get info about this user
+	// note: we don't need to set "ug" as it is already set to what it needs to be
+	args_us = "enabled";
+	args_ky = generate_key (keyfile, args_un); // new key
+
+	// delete old keys around every 50 accesses
+	if (rand()%50 == 1) remove_old_keys (keyfile, keydecay);
+	
+      } else {
+	// succeeded, however, the user is not in the correct group
+	args_ua.clear();
+	args_us = "permissiondenied";
+	args_ky.clear();
+      }
+
+    } else {
+      // succeeded, however, the account is disabled
+      args_ua.clear();
+      args_us = "disabled";
+      args_ky.clear();
+    }
+
+  } else {
+    // failure, reset info about the user
+    args_ky.clear();
+  }
+
+  // we will have to redirect the user if authentication is needed,
+  // it failed, and we weren't on our way to be authenticated anyway
+  if ((!args_uan.empty()) && (args_ua.empty()) && (args_a != "a")) {
+    // need to save the current arguments in "er"
+    text_t &arg_er = args["er"];
+    if (!compress_save_args(argsinfo, saveconf, args, arg_er, outconvert, logout))
+      arg_er.clear();
+    
+    // redirect to this action
+    args_a = "a";
+  }
+  
+  return true;
+}
+
+void authenaction::get_cgihead_info (cgiargsclass &/*args*/, recptprotolistclass * /*protos*/,
+				     response_t &response, text_t &response_data, 
+				     ostream &/*logout*/) {
+  response = content;
+  response_data = "text/html";
+}
+
+void authenaction::define_internal_macros (displayclass &disp, cgiargsclass &args, 
+					   recptprotolistclass * /*protos*/, ostream &/*logout*/) {
+  // sets _authen:messageextra_ based on the value of args["us"]
+  //      _authen:hiddenargs_   to contain all the arguments that were
+  //                            explicitly set
+  disp.setmacro ("messagestatus", "authen", ("_authen:message" + args["us"]
+					     + "_"));
+  // change style of header and footer if page is a frame
+  if ((args["sp"].empty()) || (args["sp"] == "frameset")) {
+    disp.setmacro ("header", "authen", "_status:infoheader_(Log in)");
+    disp.setmacro ("header", "authenok", "_status:infoheader_(Log in)");
+    disp.setmacro ("footer", "authen", "_status:infofooter_(Log in)");
+    disp.setmacro ("footer", "authenok", "_status:infofooter_(Log in)");
+  }
+
+  // get a list of saved configuration arguments (if possible)
+  text_t saveconf;
+  text_tset saveconfset;
+  if (recpt != NULL) {
+    saveconf = recpt->get_configinfo().saveconf;
+    splitchar (saveconf.begin(), saveconf.end(), '-', saveconfset);
+  }
+  
+  text_t hiddenargs;
+  cgiargsclass::const_iterator args_here = args.begin();
+  cgiargsclass::const_iterator args_end = args.end();
+  while (args_here != args_end) {
+    // set this as a hidden argument if it came from the cgi arguments,
+    // its not the compressed arguments, the query string, a user name or
+    // password, and if it is not in the compressed arguments
+    if ((*args_here).second.source == cgiarg_t::cgi_arg &&
+	(*args_here).first != "e" && (*args_here).first != "q" &&
+	(*args_here).first != "un" && (*args_here).first != "pw" &&
+	saveconfset.find((*args_here).first) == saveconfset.end()) {
+      hiddenargs += "<input type=hidden name=\"" + (*args_here).first +
+	"\" value=\"_cgiarg" + (*args_here).first + "_\">\n";
+    }
+    
+    args_here++;
+  }
+
+  disp.setmacro ("hiddenargs", "authen", hiddenargs);
+}
+
+bool authenaction::do_action (cgiargsclass &args, recptprotolistclass * /*protos*/, 
+			      browsermapclass * /*browsers*/, displayclass &disp, 
+			      outconvertclass &outconvert, ostream &textout, 
+			      ostream &/*logout*/) {
+  if (args["us"] == "enabled") {
+    // have been authenticated
+    textout << outconvert << disp
+	    << "_authenok:header_\n_authenok:content_\n_authenok:footer_\n";
+    return true;
+  }
+  
+  // need to be authenticated
+  textout << outconvert << disp
+	  << "_authen:header_\n_authen:content_\n_authen:footer_\n";
+
+  return true;
+}
Index: /main/tags/2.25/gsdl/src/recpt/authenaction.h
===================================================================
--- /main/tags/2.25/gsdl/src/recpt/authenaction.h	(revision 21064)
+++ /main/tags/2.25/gsdl/src/recpt/authenaction.h	(revision 21064)
@@ -0,0 +1,82 @@
+/**********************************************************************
+ *
+ * authenaction.h -- authenticating users
+ * Copyright (C) 1999  DigiLib Systems Limited, New Zealand
+ *
+ * A component of the Greenstone digital library software
+ * from the New Zealand Digital Library Project at the
+ * University of Waikato, New Zealand.
+ *
+ * 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.
+ *
+ *********************************************************************/
+
+
+#ifndef AUTHENACTION_H
+#define AUTHENACTION_H
+
+#include "gsdlconf.h"
+#include "action.h"
+#include "text_t.h"
+#include "receptionist.h"
+
+
+// note: you need to tell this action about the receptionist
+// using set_receptionist
+
+class authenaction : public action {
+protected:
+  text_t usersfile;
+  text_t keyfile;
+  int keydecay;
+
+  receptionist *recpt;
+  
+public:
+  authenaction ();
+  virtual ~authenaction () {}
+
+  void set_receptionist (receptionist *therecpt) {recpt=therecpt;}
+  
+  void configure (const text_t &key, const text_tarray &cfgline);
+
+  bool init (ostream &logout);
+  
+  text_t get_action_name () {return "a";}
+  
+  bool check_cgiargs (cgiargsinfoclass &argsinfo, cgiargsclass &args, 
+		      ostream &logout);
+
+  bool check_external_cgiargs (cgiargsinfoclass &argsinfo,
+			       cgiargsclass &args,
+			       outconvertclass &outconvert,
+			       const text_t &saveconf,
+			       ostream &logout);
+
+  void get_cgihead_info (cgiargsclass &args, recptprotolistclass *protos,
+			 response_t &response, text_t &response_data, 
+			 ostream &logout);
+  
+  void define_internal_macros (displayclass &disp, cgiargsclass &args, 
+			       recptprotolistclass *protos, ostream &logout);
+  
+  bool do_action (cgiargsclass &args, recptprotolistclass *protos, 
+		  browsermapclass *browsers, displayclass &disp, 
+		  outconvertclass &outconvert, ostream &textout, 
+		  ostream &logout);
+};
+
+
+#endif
Index: /main/tags/2.25/gsdl/src/recpt/browserclass.cpp
===================================================================
--- /main/tags/2.25/gsdl/src/recpt/browserclass.cpp	(revision 21064)
+++ /main/tags/2.25/gsdl/src/recpt/browserclass.cpp	(revision 21064)
@@ -0,0 +1,160 @@
+/**********************************************************************
+ *
+ * browserclass.cpp -- 
+ * Copyright (C) 1999  The New Zealand Digital Library Project
+ *
+ * A component of the Greenstone digital library software
+ * from the New Zealand Digital Library Project at the
+ * University of Waikato, New Zealand.
+ *
+ * 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.
+ *
+ *********************************************************************/
+
+#include "browserclass.h"
+#include <assert.h>
+
+
+browserclass::browserclass () {
+}
+
+browserclass::~browserclass () {
+}
+
+// configure should be called once for each configuration line
+// the default version does nothing
+void browserclass::configure (const text_t &/*key*/, const text_tarray &/*cfgline*/) {
+}
+
+// init should be called after all the configuration is done but
+// before any other methods are called
+bool browserclass::init (ostream &/*logout*/) {
+  return true;
+}
+
+// returns the name that specifies the browserclass type
+text_t browserclass::get_browser_name () {
+  return "";
+}
+
+void browserclass::processOID (cgiargsclass &/*args*/, recptproto * /*collectproto*/, ostream &/*logout*/) {
+}
+
+void browserclass::load_metadata_defaults (text_tset &/*metadata*/) {
+}
+
+text_t browserclass::get_default_formatstring () {
+  return "";
+}
+
+void browserclass::set_filter_options (FilterRequest_t &request, cgiargsclass &args) {
+  
+  OptionValue_t option;
+
+  if (args["a"] == "q") {
+    int arg_m = args.getintarg("m");
+    
+    option.name = "StartResults";
+    option.value = args["r"];
+    request.filterOptions.push_back (option);
+    
+    option.name = "EndResults";
+    int endresults = args.getintarg("o") + (args.getintarg("r") - 1);
+    //    int endresults = (args.getintarg("o")*3) + (args.getintarg("r") - 1);
+    if ((endresults > arg_m) && (arg_m != -1)) endresults = arg_m;
+    option.value = endresults;
+    request.filterOptions.push_back (option);
+
+  } else {
+    option.name = "StartResults";
+    option.value = args["r"];
+    request.filterOptions.push_back (option);
+    
+    option.name = "EndResults";
+    int endresults = 20 + (args.getintarg("r") - 1);
+    option.value = endresults;
+    request.filterOptions.push_back (option);
+  }
+}
+
+int browserclass::output_section_group (ResultDocInfo_t &/*section*/, cgiargsclass &/*args*/,
+					const text_t &/*collection*/, int /*colnumber*/, 
+					format_t * /*formatlistptr*/, bool /*use_table*/, 
+					text_tset &/*metadata*/, bool &/*getParents*/,
+					recptproto * /*collectproto*/, displayclass &/*disp*/, 
+					outconvertclass &/*outconvert*/, ostream &/*textout*/, 
+					ostream &/*logout*/) {
+  return 0;
+}
+
+int browserclass::output_section_group (FilterResponse_t &/*sections*/, cgiargsclass &/*args*/,
+					const text_t &/*collection*/, int /*colnumber*/, 
+					format_t * /*formatlistptr*/, bool /*use_table*/, 
+					text_tset &/*metadata*/, bool &/*getParents*/,
+					recptproto * /*collectproto*/, displayclass &/*disp*/, 
+					outconvertclass &/*outconvert*/, ostream &/*textout*/, 
+					ostream &/*logout*/) {
+  return 0;
+}
+
+bool operator==(const browserptr &x, const browserptr &y) {
+  return (x.b == y.b);
+}
+
+bool operator<(const browserptr &x, const browserptr &y) {
+  return (x.b < y.b);
+}
+
+// thebrowserclass remains the property of the calling code but
+// should not be deleted until it is removed from this list.
+void browsermapclass::addbrowser (browserclass *thebrowserclass) {
+  // can't add a null browserclass
+  assert (thebrowserclass != NULL);
+  if (thebrowserclass == NULL) return;
+  
+  // can't add a browserclass with no name
+  assert (!(thebrowserclass->get_browser_name()).empty());
+  if ((thebrowserclass->get_browser_name()).empty()) return;
+
+  browserptr aptr;
+  aptr.b = thebrowserclass;
+  browserptrs[thebrowserclass->get_browser_name()] = aptr;
+}
+
+// getbrowser will return the default browser if the browser 
+// could not be found
+browserclass *browsermapclass::getbrowser (const text_t &key) {
+  // can't find a browser with no name
+  if (key.empty()) return get_default_browser();
+
+  iterator here = browserptrs.find (key);
+  if (here == browserptrs.end()) return get_default_browser();
+  
+  return (*here).second.b;
+}
+
+void browsermapclass::setdefaultbrowser (const text_t &browsername) {
+  defaultbrowser = browsername;
+}
+
+browserclass *browsermapclass::get_default_browser () {
+
+  iterator here = browserptrs.find (defaultbrowser);
+  if (here == browserptrs.end())
+    // we'll just take the first in the list if
+    // no valid default was set
+    here = browserptrs.begin();
+  return (*here).second.b;
+}
Index: /main/tags/2.25/gsdl/src/recpt/browserclass.h
===================================================================
--- /main/tags/2.25/gsdl/src/recpt/browserclass.h	(revision 21064)
+++ /main/tags/2.25/gsdl/src/recpt/browserclass.h	(revision 21064)
@@ -0,0 +1,158 @@
+/**********************************************************************
+ *
+ * browserclass.h -- 
+ * Copyright (C) 1999  The New Zealand Digital Library Project
+ *
+ * A component of the Greenstone digital library software
+ * from the New Zealand Digital Library Project at the
+ * University of Waikato, New Zealand.
+ *
+ * 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.
+ *
+ *********************************************************************/
+
+
+#ifndef BROWSERCLASS_H
+#define BROWSERCLASS_H
+
+#include "gsdlconf.h"
+#include "text_t.h"
+#include "cgiargs.h"
+#include "display.h"
+#include "recptproto.h"
+#include "formattools.h"
+
+#if defined(GSDL_USE_OBJECTSPACE)
+#  include <ospace\std\iostream>
+#elif defined(GSDL_USE_IOS_H)
+#  include <iostream.h>
+#else
+#  include <iostream>
+#endif
+
+
+class browserclass {
+protected:
+
+public:
+  browserclass ();
+  virtual ~browserclass ();
+
+  // configure should be called once for each configuration line
+  virtual void configure (const text_t &key, const text_tarray &cfgline);
+
+  // init should be called after all the configuration is done but
+  // before any other methods are called
+  virtual bool init (ostream &logout);
+
+  // returns the name that specifies the browserclass type
+  virtual text_t get_browser_name ();
+  
+  virtual void processOID (cgiargsclass &args, recptproto *collectproto, ostream &logout);
+  
+  // load_metadata_defaults should be called before
+  // doing protocol call to get metadata for OID to
+  // be displayed by this browserclass. it adds fields
+  // to the metadata set that are needed by browserclass
+  // during display
+  virtual void load_metadata_defaults (text_tset &metadata);
+
+  virtual text_t get_default_formatstring ();
+
+  void set_filter_options (FilterRequest_t &request, cgiargsclass &args);
+  
+  // returns the number of tabs to add before displaying the
+  // next section group
+  virtual int output_section_group (ResultDocInfo_t &section, cgiargsclass &args,
+				    const text_t &collection, int colnumber, 
+				    format_t *formatlistptr, bool use_table, 
+				    text_tset &metadata, bool &getParents,
+				    recptproto *collectproto, displayclass &disp, 
+				    outconvertclass &outconvert, ostream &textout, 
+				    ostream &logout);
+
+  virtual int output_section_group (FilterResponse_t &sections, cgiargsclass &args,
+				    const text_t &collection, int colnumber, 
+				    format_t *formatlistptr, bool use_table, 
+				    text_tset &metadata, bool &getParents,
+				    recptproto *collectproto, displayclass &disp, 
+				    outconvertclass &outconvert, ostream &textout, 
+				    ostream &logout);
+};
+
+
+// The browserptr function does not 'own' the browser. The 
+// browser should be deleted by the code which created it.
+class browserptr {
+public:
+  browserclass *b;
+
+  browserptr () {b=NULL;}
+};
+
+bool operator==(const browserptr &x, const browserptr &y);
+bool operator<(const browserptr &x, const browserptr &y);
+
+typedef map<text_t, browserptr, lttext_t> browserptrmap;
+
+// contains a list of browsers indexed by their name
+class browsermapclass {
+protected:
+  browserptrmap browserptrs;
+  text_t defaultbrowser;
+
+public:
+  // type support for browserptrmap
+  typedef browserptrmap::iterator iterator;
+  typedef browserptrmap::const_iterator const_iterator;
+  typedef browserptrmap::reference reference;
+  typedef browserptrmap::const_reference const_reference;
+  typedef browserptrmap::size_type size_type;
+
+  typedef browserptrmap::difference_type difference_type;
+  typedef browserptrmap::const_reverse_iterator const_reverse_iterator;
+  typedef browserptrmap::reverse_iterator reverse_iterator;
+  
+  // basic container support
+  iterator begin () {return browserptrs.begin();}
+  const_iterator begin () const {return browserptrs.begin();}
+  iterator end () {return browserptrs.end();}
+  const_iterator end () const {return browserptrs.end();}
+
+  void erase(iterator pos) {browserptrs.erase(pos);}
+  void erase(iterator first, iterator last) {browserptrs.erase(first, last);}
+  browsermapclass &operator=(const browsermapclass &x) {browserptrs=x.browserptrs;return *this;}
+
+  bool empty () const {return browserptrs.empty();}
+  size_type size() const {return browserptrs.size();}
+
+
+  // added functionality
+  void clear () {browserptrs.erase(browserptrs.begin(),browserptrs.end());}
+
+  // thebrowserclass remains the property of the calling code but
+  // should not be deleted until it is removed from this list.
+  void addbrowser (browserclass *thebrowserclass);
+
+  // getbrowser will return NULL if the browser could not be found
+  browserclass *getbrowser (const text_t &key);
+
+  void setdefaultbrowser (const text_t &browsername);
+
+  browserclass *get_default_browser ();
+};
+
+
+#endif
Index: /main/tags/2.25/gsdl/src/recpt/browsetools.cpp
===================================================================
--- /main/tags/2.25/gsdl/src/recpt/browsetools.cpp	(revision 21064)
+++ /main/tags/2.25/gsdl/src/recpt/browsetools.cpp	(revision 21064)
@@ -0,0 +1,547 @@
+
+/**********************************************************************
+ *
+ * browsetools.cpp -- 
+ * Copyright (C) 1999  The New Zealand Digital Library Project
+ *
+ * A component of the Greenstone digital library software
+ * from the New Zealand Digital Library Project at the
+ * University of Waikato, New Zealand.
+ *
+ * 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.
+ *
+ *********************************************************************/
+
+#include "browsetools.h"
+#include "OIDtools.h"
+
+
+// output_controls displays the detach, expand/contract contents,
+// expand/contract text and highlighting/no highlighting buttons
+
+void output_controls (cgiargsclass &args, const text_tarray &ibuttons,
+		      recptproto * /*collectproto*/, displayclass &disp, 
+		      outconvertclass &outconvert, ostream &textout, 
+		      ostream &/*logout*/) {
+
+  if (args["u"] != "1") {
+    
+    FilterResponse_t response;
+    text_tarray metadata;
+    text_tarray buttons;
+    
+    text_tarray::const_iterator here = ibuttons.begin();
+    text_tarray::const_iterator end = ibuttons.end();
+    
+    while (here != end) {
+      
+      if (*here == "Detach")
+	buttons.push_back ("_document:imagedetach_");
+      else if (*here == "Highlight") {
+	if (args["hl"] == "1") 
+	  buttons.push_back ("_document:imagenohighlight_");
+	else 
+	  buttons.push_back ("_document:imagehighlight_");
+      } else if (*here == "Expand Contents") {
+	if (args["gc"] == "1")
+	  buttons.push_back ("_document:imagecontracttoc_");
+	else 
+	  buttons.push_back ("_document:imageexpandtoc_");
+      } else if (*here == "Expand Text") {
+	if (args.getintarg("gt"))
+	  buttons.push_back ("_document:imagecontracttext_");
+	else 
+	  buttons.push_back ("_document:imageexpandtext_");
+      }
+      here ++;
+    }
+    
+    here = buttons.begin();
+    end = buttons.end();
+    int count = 0;
+    while (here != end) {
+      if ((count != 0) && ((count % 2) == 0)) textout << "<br>\n";
+      textout << outconvert << disp << *here;
+      count ++;
+      here ++;
+    }
+  }
+}
+
+
+// at the moment this just writes out the html to display 
+// the cover image (assuming it's called cover.jpg)
+// this whole thing should be done with a call to the collection
+// server which would send a link to the cover image if there
+// was one otherwise send title, author and stuff
+void output_cover_image (cgiargsclass &args, recptproto * /*collectproto*/, 
+			 displayclass &disp, outconvertclass &outconvert, 
+			 ostream &textout, ostream &/*logout*/) {
+  
+  if (args["d"].empty()) return;
+  
+  textout << outconvert << disp << 
+    "<img src=\"_httpcollimg_/_thisOID_/cover.jpg\"><br>\n";
+}
+
+void output_titles (cgiargsclass &args, recptproto *collectproto, 
+		    formatinfo_t &formatinfo, displayclass &disp, 
+		    outconvertclass &outconvert, ostream &textout, 
+		    ostream &logout) {
+
+  if (args["d"].empty()) return;
+  
+  text_tset metadata;
+  bool getParents;
+  FilterResponse_t response;
+
+  format_t *formatlistptr = new format_t();
+  parse_formatstring (formatinfo.DocumentHeading, formatlistptr, metadata, getParents);
+
+  if (!get_info (args["d"], args["c"], metadata, getParents, collectproto, response, logout))
+    return;
+
+  textout << outconvert << disp << get_formatted_string (response.docInfo[0], formatlistptr);
+}
+
+
+static void recurse_contents (ResultDocInfo_t &section, cgiargsclass &args, bool fulltoc,
+			      browserclass *bptr, text_tset &metadata, bool &getParents, 
+			      format_t *formatlistptr, format_tmap &formatlistmap, 
+			      formatinfo_t &formatinfo, browsermapclass *browsermap, 
+			      int tabcount, recptproto *collectproto, displayclass &disp, 
+			      outconvertclass &outconvert, ostream &textout, ostream &logout) {
+  text_t formatstring;
+
+  bool is_classify = false;
+  if (args["d"].empty() || fulltoc) is_classify = true;
+
+  // output this section 
+  bool use_table = is_table_content (formatlistptr);
+  tabcount += bptr->output_section_group (section, args, "", tabcount, formatlistptr, use_table, 
+					  metadata, getParents, collectproto, disp, outconvert, 
+					  textout, logout);
+
+  text_t classification;
+  if (!is_classify) classification = "Document";
+  else get_top (args["cl"], classification);
+
+  int haschildren = section.metadata["haschildren"].values[0].getint();
+  const text_t &doctype = section.metadata["doctype"].values[0];
+  text_t classifytype = section.metadata["childtype"].values[0];
+  // HLists and DateLists are displayed as VLists when contents 
+  // are expanded, Paged documents are displayed as HLists
+  if (classifytype == "HList" || classifytype == "DateList") classifytype = "VList";
+  if (classifytype == "Paged") classifytype = "HList";
+
+  // recurse through children
+  if ((haschildren == 1) && (!is_classify || fulltoc || doctype == "classify")) {
+
+    // get browser for displaying children
+    bptr = browsermap->getbrowser (classifytype);
+    bptr->load_metadata_defaults (metadata);
+
+    // get the formatstring if there is one 
+    if (!get_formatstring (classification, classifytype, 
+			   formatinfo.formatstrings, formatstring))
+      formatstring = bptr->get_default_formatstring();
+
+    format_tmap::const_iterator it = formatlistmap.find (formatstring);
+    // check if formatlistptr is cached
+    if (it != formatlistmap.end()) formatlistptr = (*it).second;
+    else {
+      formatlistptr = new format_t();
+      parse_formatstring (formatstring, formatlistptr, metadata, getParents);
+      formatlistmap[formatstring] = formatlistptr;
+    }
+
+    FilterResponse_t tmp;
+    get_children (section.OID, args["c"], metadata, getParents, collectproto, tmp, logout);
+    ResultDocInfo_tarray::iterator thisdoc = tmp.docInfo.begin();
+    ResultDocInfo_tarray::iterator lastdoc = tmp.docInfo.end();
+
+    while (thisdoc != lastdoc) {
+      recurse_contents (*thisdoc, args, fulltoc, bptr, metadata, getParents, 
+			formatlistptr, formatlistmap, formatinfo, browsermap, 
+			tabcount, collectproto, disp, outconvert, textout, logout);
+      thisdoc ++;
+    }
+  }
+}
+
+
+// expanded_contents recurses through all contents. there's a special case
+// for an HList when contents are expanded (i.e. it's displayed as a VList)
+//
+// if we're inside a document we expand all contents from the top,
+// if we're at classification level we'll just expand out those contents below 
+// the current one
+
+void expanded_contents (cgiargsclass &args, int tabcount, bool fulltoc,
+			browsermapclass *browsermap, formatinfo_t &formatinfo, 
+			recptproto *collectproto, displayclass &disp, 
+			outconvertclass &outconvert, ostream &textout, 
+			ostream &logout) {
+  
+  if (args["d"].empty() && args["cl"].empty()) return;
+  text_t OID;
+  
+  FilterResponse_t response;
+  bool getParents = false;
+  text_tset metadata;
+  text_t classifytype, classification, formatstring;
+
+  if (!args["d"].empty()) {
+    // document level
+    if (fulltoc) {
+      get_top (args["cl"], OID);
+      classification = OID;
+    }
+    else {
+      // always expand document level from top
+      get_top (args["d"], OID);
+      classification = "Document";
+    }
+  } else {
+    // classification level
+    OID = args["cl"];
+    get_top (args["cl"], classification);
+  }
+
+  // get classifytype of this level
+  text_t tOID;
+  if (is_top(OID)) {
+    classifytype = "thistype";
+    tOID = OID;
+  } else {
+    classifytype = "childtype";
+    tOID = get_parent (OID);
+  }
+  metadata.insert (classifytype);
+
+  if (!get_info (tOID, args["c"], metadata, getParents, collectproto, response, logout))
+    return;
+  classifytype = response.docInfo[0].metadata[classifytype].values[0];
+  // if we still don't have a classifytype we'll use the default
+  if (classifytype.empty()) {
+    browserclass *bptr = browsermap->get_default_browser ();
+    classifytype = bptr->get_browser_name ();
+  }
+
+  // HLists are displayed as VLists when contents are expanded,
+  // Paged documents are displayed as HLists
+  if (classifytype == "HList") {
+    classifytype = "VList";
+    text_t pOID = get_parent (OID);
+    if (!pOID.empty()) {
+      OID = pOID;
+      // this is assuming that top levels are always 'Invisible' !!!
+      if (is_top (OID)) classifytype = "Invisible";
+    }
+  }
+  if (classifytype == "Paged") classifytype = "HList";
+
+  metadata.erase (metadata.begin(), metadata.end());
+		  
+  // metadata elements needed by recurse_contents
+  metadata.insert ("childtype");
+  metadata.insert ("doctype");
+  metadata.insert ("haschildren");
+
+  // load up metadata array with browser defaults
+  browserclass *bptr = browsermap->getbrowser (classifytype);
+  bptr->load_metadata_defaults (metadata);
+
+  // get the formatstring if there is one or use the browsers default
+  if (!get_formatstring (classification, classifytype, 
+			 formatinfo.formatstrings, formatstring))
+    formatstring = bptr->get_default_formatstring();
+
+  format_t *formatlistptr = new format_t();
+  parse_formatstring (formatstring, formatlistptr, metadata, getParents);
+
+  // protocol call
+  if (!get_info (OID, args["c"], metadata, getParents, collectproto, response, logout))
+    return;
+
+  format_tmap formatlistmap;
+  formatlistmap[formatstring] = formatlistptr;
+
+  recurse_contents (response.docInfo[0], args, fulltoc, bptr, metadata, 
+		    getParents, formatlistptr, formatlistmap, formatinfo, browsermap, 
+		    tabcount, collectproto, disp, outconvert, textout, logout);
+
+  // clean up format list pointers
+  format_tmap::const_iterator here = formatlistmap.begin();
+  format_tmap::const_iterator end = formatlistmap.end();
+  while (here != end) {
+    delete (*here).second;
+    here ++;
+  }
+}
+
+
+static void load_formatstring (const text_t &classifytype, text_tset &metadata,
+			       bool &getParents, const text_t &classification, 
+			       browsermapclass *browsermap, formatinfo_t &formatinfo,
+			       format_tmap &formatlistmap) {
+  text_t formatstring;
+
+  // load up metadata array with browser defaults
+  browserclass *bptr = browsermap->getbrowser (classifytype);
+  bptr->load_metadata_defaults (metadata);
+
+  // get the formatstring if there is one or use the browsers default
+  if (!get_formatstring (classification, classifytype, 
+			 formatinfo.formatstrings, formatstring))
+    formatstring = bptr->get_default_formatstring();
+
+  // see if it's cached
+  format_tmap::const_iterator it = formatlistmap.find (formatstring);
+  if (it == formatlistmap.end()) {
+    format_t *formatlistptr = new format_t();
+    parse_formatstring (formatstring, formatlistptr, metadata, getParents);
+    formatlistmap[formatstring] = formatlistptr;
+  }
+}
+
+static void load_formatstrings (FilterResponse_t &response, text_tset &metadata,
+				bool &getParents, const text_t &classification,
+				browsermapclass *browsermap, formatinfo_t &formatinfo, 
+				format_tmap &formatlistmap) {
+
+  text_tset cache;
+
+  ResultDocInfo_tarray::iterator thisdoc = response.docInfo.begin();
+  ResultDocInfo_tarray::iterator lastdoc = response.docInfo.end();
+
+  while (thisdoc != lastdoc) {
+
+    if (is_top ((*thisdoc).OID))
+      load_formatstring ((*thisdoc).metadata["thistype"].values[0], metadata, 
+			 getParents, classification, browsermap, formatinfo, 
+			 formatlistmap);
+
+    text_t &childtype = (*thisdoc).metadata["childtype"].values[0];
+    text_tset::const_iterator it = cache.find (childtype);
+    if (it == cache.end()) {
+      load_formatstring (childtype, metadata, getParents, classification,
+			 browsermap, formatinfo, formatlistmap);
+      cache.insert (childtype);
+    }
+    thisdoc ++;
+  }
+}
+
+static void output_parents (FilterResponse_t &response, cgiargsclass &args, 
+			    browsermapclass *browsermap, formatinfo_t &formatinfo, 
+			    format_tmap &formatlistmap, const text_t &classification,
+			    int &tabcount, text_tset &metadata, bool &getParents,
+			    recptproto *collectproto, displayclass &disp, 
+			    outconvertclass &outconvert, ostream &textout, 
+			    ostream &logout) {
+
+  format_t *formatlistptr = NULL;
+  text_t classifytype, formatstring;
+  bool use_table, first = true;
+  ResultDocInfo_tarray::iterator thisparent = response.docInfo.begin();
+  ResultDocInfo_tarray::iterator lastparent = response.docInfo.end();
+  while (thisparent != lastparent) {
+
+    // get classifytype of this level
+    if (is_top ((*thisparent).OID)) classifytype = (*thisparent).metadata["thistype"].values[0];
+    else if (!first) classifytype = (*(thisparent-1)).metadata["childtype"].values[0];
+    
+    // if we still don't have a classifytype we'll use the default
+    if (classifytype.empty()) {
+      browserclass *bptr = browsermap->get_default_browser ();
+      classifytype = bptr->get_browser_name ();
+    }
+    
+    browserclass *bptr = browsermap->getbrowser (classifytype);
+
+    // get the formatstring if there is one or use the browsers default
+    if (!get_formatstring (classification, classifytype, 
+			   formatinfo.formatstrings, formatstring))
+      formatstring = bptr->get_default_formatstring();
+    
+    // see if it's cached
+    format_tmap::const_iterator it = formatlistmap.find (formatstring);
+    if (it != formatlistmap.end()) formatlistptr = (*it).second;
+    else {
+      logout << "browsetools error\n";
+      return;
+    }
+    
+    use_table = is_table_content (formatlistptr);
+    tabcount += bptr->output_section_group (*thisparent, args, "", tabcount, formatlistptr, 
+					    use_table, metadata, getParents, collectproto, 
+					    disp, outconvert, textout, logout);
+    first = false;
+    thisparent ++;
+  }
+}
+
+void contracted_contents (cgiargsclass &args, int tabcount, bool fulltoc, 
+			  browsermapclass *browsermap, formatinfo_t &formatinfo, 
+			  recptproto *collectproto, displayclass &disp, 
+			  outconvertclass &outconvert, ostream &textout, 
+			  ostream &logout) {
+
+  FilterResponse_t response;
+  text_tset metadata;
+  bool getParents = false;
+  text_t formatstring;
+  text_tarray parents;
+  text_t OID = args["d"];
+  text_t classification = "Document";
+  if (OID.empty()) {
+    OID = args["cl"];
+    get_top (OID, classification);
+  } else if (fulltoc)
+    get_top (args["cl"], classification);    
+
+  bool haschildren = has_children (OID, args["c"], collectproto, logout);
+
+  if ((!args["d"].empty()) && fulltoc)
+    get_parents_array (args["cl"] + ".fc", parents);
+  if (haschildren) get_parents_array (OID + ".fc", parents);
+  else get_parents_array (OID, parents);
+
+  if (!parents.empty()) {
+    // get classifytypes of each parent
+    metadata.insert ("thistype");
+    metadata.insert ("childtype");
+    
+    if (!get_info (parents, args["c"], metadata, getParents, collectproto, response, logout))
+      return;
+    
+    // get formatstrings for all parents
+    format_tmap formatlistmap;  
+    load_formatstrings (response, metadata, getParents, classification, 
+			browsermap, formatinfo, formatlistmap);
+
+    if (!get_info (parents, args["c"], metadata, getParents, collectproto, response, logout))
+      return;
+    
+    // display each parent
+    output_parents (response, args, browsermap, formatinfo, formatlistmap, 
+		    classification, tabcount, metadata, getParents, 
+		    collectproto, disp, outconvert, textout, logout);
+    
+    metadata.erase (metadata.begin(), metadata.end());
+    
+    // clean up cached format list pointers
+    format_tmap::const_iterator here = formatlistmap.begin();
+    format_tmap::const_iterator end = formatlistmap.end();
+    while (here != end) {
+      delete (*here).second;
+      here ++;
+    }
+  }
+
+  // get childrens classifytype
+  text_t classifytype;
+  int numparents = response.docInfo.size();
+  if (!parents.empty())
+    classifytype = response.docInfo[numparents-1].metadata["childtype"].values[0];
+  else {
+    // use the default
+    browserclass *bptr = browsermap->get_default_browser ();
+    classifytype = bptr->get_browser_name ();
+  }
+    
+  // load up metadata array with browser defaults
+  browserclass *bptr = browsermap->getbrowser (classifytype);
+  bptr->load_metadata_defaults (metadata);
+
+  // get the formatstring if there is one or use the browsers default
+  if (!get_formatstring (classification, classifytype, 
+			 formatinfo.formatstrings, formatstring))
+    formatstring = bptr->get_default_formatstring();
+
+  format_t *formatlistptr = new format_t();
+  parse_formatstring (formatstring, formatlistptr, metadata, getParents);
+
+  if (haschildren) 
+    get_children (OID, args["c"], metadata, getParents,
+		  collectproto, response, logout);
+  else if (!is_top(OID)) {
+    get_children (OID + ".pr", args["c"], metadata, getParents, 
+		  collectproto, response, logout);
+    haschildren = true;
+  }
+
+  // display children
+  if (haschildren) {
+    bool use_table = is_table_content (formatlistptr);
+    bptr->output_section_group (response, args, "", tabcount, formatlistptr, use_table, 
+				metadata, getParents, collectproto, disp, outconvert, 
+				textout, logout);
+  }
+  
+  delete formatlistptr;
+}
+
+void output_toc (cgiargsclass &args, browsermapclass *browsermap,
+                 formatinfo_t &formatinfo, recptproto *collectproto,
+                 displayclass &disp, outconvertclass &outconvert,
+                 ostream &textout, ostream &logout) {
+
+  int tabcount = 0;
+  bool havecontrols = false;
+  bool fulltoc = false;
+
+  if (args["cl"] != "search") {
+    // see if there's a FullTOC string
+    text_t cl_top, full_toc;
+    get_top (args["cl"], cl_top);
+    if (get_formatstring (cl_top, "FullTOC", formatinfo.formatstrings, full_toc))
+      if (full_toc == "true") fulltoc = true;
+  }
+  
+  // get the cover image (if there is one) and the control buttons
+  // if we're inside a book
+  if ((!fulltoc) && (!args["d"].empty())) {
+    textout << "<p><table cellpadding=0 cellspacing=0><tr>\n";
+    textout << "<td valign=top";
+    if (formatinfo.DocumentContents) textout << " width=200>\n";
+    else textout << " width=100%>\n";
+    if (formatinfo.DocumentImages) 
+      output_cover_image (args, collectproto, disp, outconvert, textout, logout);
+    else if (formatinfo.DocumentTitles)
+      output_titles (args, collectproto, formatinfo, disp, outconvert, textout, logout);
+    output_controls (args, formatinfo.DocumentButtons, collectproto, disp, 
+		     outconvert, textout, logout);
+    textout << "</td><td valign=top>\n";
+    havecontrols = true;
+  }
+
+  if (formatinfo.DocumentContents || args["d"].empty()) {
+    if (args.getintarg("gc") == 1) {
+      
+      // expanded table of contents
+      expanded_contents (args, tabcount, fulltoc, browsermap, formatinfo, 
+			 collectproto, disp, outconvert, textout, logout);
+    } else {
+      
+      // contracted table of contents
+      contracted_contents (args, tabcount, fulltoc, browsermap, formatinfo, 
+			   collectproto, disp, outconvert, textout, logout);
+    }
+  }
+
+  if (havecontrols) textout << "</td></tr></table>\n";
+}
Index: /main/tags/2.25/gsdl/src/recpt/browsetools.h
===================================================================
--- /main/tags/2.25/gsdl/src/recpt/browsetools.h	(revision 21064)
+++ /main/tags/2.25/gsdl/src/recpt/browsetools.h	(revision 21064)
@@ -0,0 +1,72 @@
+/**********************************************************************
+ *
+ * browsetools.h --
+ * Copyright (C) 1999  The New Zealand Digital Library Project
+ *
+ * A component of the Greenstone digital library software
+ * from the New Zealand Digital Library Project at the
+ * University of Waikato, New Zealand.
+ *
+ * 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.
+ *
+ *********************************************************************/
+
+
+#ifndef BROWSETOOLS_H
+#define BROWSETOOLS_H
+
+#include "gsdlconf.h"
+#include "text_t.h"
+#include "cgiargs.h"
+#include "display.h"
+#include "recptproto.h"
+#include "formattools.h"
+#include "browserclass.h"
+
+typedef map<text_t, format_t*, lttext_t> format_tmap; 
+
+void expanded_contents (cgiargsclass &args, int tabcount, bool fulltoc,
+			browsermapclass *browsermap, formatinfo_t &formatinfo, 
+			recptproto *collectproto, displayclass &disp, 
+			outconvertclass &outconvert, ostream &textout, 
+			ostream &logout);
+
+void contracted_contents (cgiargsclass &args, int tabcount, bool fulltoc, 
+			  browsermapclass *browsermap, formatinfo_t &formatinfo, 
+			  recptproto *collectproto, displayclass &disp, 
+			  outconvertclass &outconvert, ostream &textout, 
+			  ostream &logout);
+
+void output_toc (cgiargsclass &args, browsermapclass *browsermap,
+                 formatinfo_t &formatinfo, recptproto *collectproto,
+                 displayclass &disp, outconvertclass &outconvert,
+                 ostream &textout, ostream &logout);
+
+void output_titles (cgiargsclass &args, recptproto *collectproto, 
+		    formatinfo_t &formatinfo, displayclass &disp, 
+		    outconvertclass &outconvert, ostream &textout, 
+		    ostream &logout);
+
+void output_controls (cgiargsclass &args, const text_tarray &ibuttons,
+		      recptproto *collectproto, displayclass &disp, 
+		      outconvertclass &outconvert, ostream &textout, 
+		      ostream &logout);
+    
+void output_cover_image (cgiargsclass &args, recptproto *collectproto, 
+			 displayclass &disp, outconvertclass &outconvert, 
+			 ostream &textout, ostream &logout);
+
+
+#endif
Index: /main/tags/2.25/gsdl/src/recpt/buildaction.cpp
===================================================================
--- /main/tags/2.25/gsdl/src/recpt/buildaction.cpp	(revision 21064)
+++ /main/tags/2.25/gsdl/src/recpt/buildaction.cpp	(revision 21064)
@@ -0,0 +1,546 @@
+/**********************************************************************
+ *
+ * buildaction.cpp -- building collections
+ * Copyright (C) 1999  The New Zealand Digital Library Project
+ *
+ * A component of the Greenstone digital library software
+ * from the New Zealand Digital Library Project at the
+ * University of Waikato, New Zealand.
+ *
+ * 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.
+ *
+ *********************************************************************/
+
+#include "OIDtools.h"
+#include "fileutil.h"
+#include "htmlutils.h"
+#include "gsdltools.h"
+#include "buildaction.h"
+
+///////////////
+// buildaction
+///////////////
+
+buildaction::buildaction () {
+  // this action uses cgi variable "a"
+  cgiarginfo arg_ainfo;
+  arg_ainfo.shortname = "a";
+  arg_ainfo.longname = "action";
+  arg_ainfo.multiplechar = true;
+  arg_ainfo.defaultstatus = cgiarginfo::weak;
+  arg_ainfo.argdefault = "bc"; // build collection
+  arg_ainfo.savedarginfo = cgiarginfo::must;
+  argsinfo.addarginfo (NULL, arg_ainfo);
+
+  // "bca"
+  arg_ainfo.shortname = "bca";
+  arg_ainfo.longname = "build collection action";
+  arg_ainfo.multiplechar = true;
+  arg_ainfo.defaultstatus = cgiarginfo::weak;
+  arg_ainfo.argdefault = "editcol";
+  arg_ainfo.savedarginfo = cgiarginfo::mustnot;
+  argsinfo.addarginfo (NULL, arg_ainfo);
+
+
+  // "mess"
+  arg_ainfo.shortname = "mess";
+  arg_ainfo.longname = "macro name of text for the message page";
+  arg_ainfo.multiplechar = true;
+  arg_ainfo.defaultstatus = cgiarginfo::weak;
+  arg_ainfo.argdefault = "";
+  arg_ainfo.savedarginfo = cgiarginfo::mustnot;
+  argsinfo.addarginfo (NULL, arg_ainfo);
+
+  // "head"
+  arg_ainfo.shortname = "head";
+  arg_ainfo.longname = "macro name of text to use as header for the message page";
+  arg_ainfo.multiplechar = true;
+  arg_ainfo.defaultstatus = cgiarginfo::weak;
+  arg_ainfo.argdefault = "";
+  arg_ainfo.savedarginfo = cgiarginfo::mustnot;
+  argsinfo.addarginfo (NULL, arg_ainfo);
+
+}
+
+bool buildaction::check_cgiargs (cgiargsinfoclass &/*argsinfo*/, cgiargsclass &args, 
+				 ostream &/*logout*/) {
+
+  text_t &arg_bca = args["bca"];
+  if (!((arg_bca == "buildstatus") || (arg_bca == "collog") || (arg_bca == "blankpage") 
+	|| ((arg_bca == "buildcol") && (args["wizard"] == "buildexec"))))
+    {
+      // authenticate the user if authentication is avaiable
+      args["uan"] = 1;
+      args["ug"] = "colbuilder";
+    }
+  return true;
+}
+
+void buildaction::get_cgihead_info (cgiargsclass &/*args*/, recptprotolistclass * /*protos*/,
+				    response_t &response,text_t &response_data, 
+				    ostream &/*logout*/) {
+
+  response = content;
+  response_data = "text/html";
+}
+
+void buildaction::define_internal_macros (displayclass &disp, cgiargsclass &args, 
+					  recptprotolistclass *protos, ostream &logout) {
+
+  // make sure we know about a receptionist
+  if (recpt == NULL) {
+    logout << "The build action does not contain information\n"
+           << "about any receptionists. The method set_receptionist\n"
+           << "was probably not called from the module which instantiated\n"
+           << "this build action.\n";
+    return;
+  }
+
+  recptprotolistclass *rprotolist = recpt->get_recptprotolist_ptr ();
+  if (rprotolist == NULL) return;
+  
+  // build up javascript and HTML code useful in web forms
+  text_t first_dirname = "";
+  text_t fullnamelist = "var fullnamelist = new Array(";
+  text_t dirnamelist  = "var dirnamelist = new Array(";
+  text_t fullnamemenu = "<input type=hidden name=\"bc1fullnameindex\"";
+  fullnamemenu += " value=\"_bcargfullnameindex_\">\n";
+  fullnamemenu += "<select name=\"bc1fullnamemenu\" onChange=fullnameindex_changed()>\n";
+  int rcount = 1;
+  int fcount = 1;
+  int starting_fullname_index = 0;
+  disp.setmacro("bcargfirsttime","build","false");
+
+  recptprotolistclass::iterator rprotolist_here = protos->begin();
+  recptprotolistclass::iterator rprotolist_end = protos->end();
+  while (rprotolist_here != rprotolist_end) {
+    if ((*rprotolist_here).p != NULL) {
+      text_tarray collist;
+      comerror_t err;
+      (*rprotolist_here).p->get_collection_list (collist, err, logout);
+      if (err == noError) {
+	text_tarray::iterator collist_here = collist.begin();
+	text_tarray::iterator collist_end = collist.end();
+
+	if (rcount>1) { fullnamelist += ","; }
+	fullnamelist += "new Array(";
+
+	FilterResponse_t response;
+	text_tset metadata;
+	metadata.insert ("collectionname");
+	
+	int ccount = 1;
+
+	while (collist_here != collist_end) {
+
+	  ColInfoResponse_t *cinfo = recpt->get_collectinfo_ptr ((*rprotolist_here).p, *collist_here, logout);
+	  if (cinfo != NULL) {
+	    text_t collectionname = *collist_here;
+	    if (!cinfo->collectionmeta["collectionname"].empty())
+	      {
+		// get collection name from the collection cfg file
+		collectionname = cinfo->collectionmeta["collectionname"];
+	      }
+	    else
+	      {
+		if (get_info ("collection", *collist_here, metadata, false, (*rprotolist_here).p, 
+			      response, logout))
+		  {
+		    // get collection name from gdbm file
+		    collectionname = response.docInfo[0].metadata["collectionname"].values[0];
+		  }
+	      }
+	  
+	    if (ccount>1) { fullnamelist += ","; dirnamelist += ","; }
+	    fullnamelist += (text_t)"\"" + collectionname + "\"";
+	    dirnamelist += (text_t)"\"" + *collist_here + "\"";
+
+	    fullnamemenu += "<option value=\"" + collectionname;
+	    fullnamemenu.push_back ('"');
+	    if (args["bc1dirname"].empty())
+	      {
+		if ((rcount==1) && (ccount==1)) 
+		  { 
+		    fullnamemenu += " selected"; 
+		    first_dirname = *collist_here;
+		    starting_fullname_index = 0;
+		  }
+	      }
+	    else
+	      {
+		if (args["bc1dirname"] == *collist_here)
+		  {
+		    fullnamemenu += " selected"; 
+		    first_dirname = *collist_here;
+		    starting_fullname_index = fcount-1;
+		  }
+	      }
+	    fullnamemenu += (text_t)">" + collectionname;
+
+	    // check to see if the "collection" is writable
+	    text_t cfg_fname 
+	      = filename_cat(gsdlhome, "collect", *collist_here, "etc", "collect.cfg");
+	    if (!file_writable(cfg_fname))
+	      {
+		fullnamemenu += " <b>(write protected)</b>";
+	      }
+
+	    fullnamemenu += "\n";
+
+	    if (args["bca"]=="buildcol")
+	      {
+		if (((args["bc1dirname"].empty()) && (rcount==1) && (ccount==1))
+		    || (args["bc1dirname"]==*collist_here))
+		  {
+		    disp.setmacro("bcargingsdlarea","build",cinfo->building["ingsdlarea"]);
+		    disp.setmacro("bcargcopydir","build",cinfo->building["copydir"]);
+		    
+		    if (cinfo->buildDate==0) // not built
+		      {
+			// assume that's because this is the first build ever for the collection
+			args["bc1copydata"]="true";
+			disp.setmacro("bcargcopydata","build","true");
+			disp.setmacro("bcargfirsttime","build","true"); // override value
+		      }
+		  }
+	      }
+
+	    ccount++;
+	    fcount++;
+	  }
+	  collist_here ++;
+	}
+
+	fullnamelist += ")";
+      }
+      rcount ++;
+    }
+    fullnamelist += ");\n";
+    dirnamelist += ");\n";
+
+    fullnamemenu += "</select>\n";
+    rprotolist_here ++;
+  }
+
+  if ((args["bca"]=="newcol") || (args["bca"]=="editcol"))
+    {
+      disp.setmacro ("fullnamelist", "build", fullnamelist); 
+    }
+
+  if ((args["bca"]=="delcol") || (args["bca"]=="editcol") || 
+      (args["bca"]=="buildcol") || (args["bca"]=="collog"))
+    {
+      disp.setmacro ("dirnamelist", "build", dirnamelist);
+      disp.setmacro ("fullnamemenu", "build", fullnamemenu); 
+      disp.setmacro ("bcargfullnameindex", "build", starting_fullname_index);
+    }
+
+
+  // define special "wizard" form value so webform building process can 
+  // keep track of which page it is on
+  text_t wizard_value
+    = (args["wizard"] == "") ? (text_t)"textinfo" : args["wizard"];
+  text_t hiddenargs 
+    = "<input type=\"hidden\" name=\"wizard\" value=\""+wizard_value+"\">\n";
+  disp.setmacro ("hiddenargs", "build", hiddenargs); 
+  disp.setmacro ("wizard", "build", wizard_value);
+
+  // cache any cgi arguments starting "newcol:" (from previous webform)
+  cgiargsclass::const_iterator args_here = args.begin();
+  cgiargsclass::const_iterator args_end = args.end();
+  while (args_here != args_end) {
+    // define macro if args came from a previous col building webpage
+    text_t args_entry = (*args_here).first;
+
+    if (substr(args_entry.begin(),args_entry.begin()+3) == "bc1")
+      {
+	text_t bc1name = substr(args_entry.begin()+3,args_entry.end());
+	text_t cached_cgiarg = "bcarg" + bc1name;
+	disp.setmacro(cached_cgiarg, "build", dm_safe(args[args_entry]));
+      }
+    args_here++;
+  }
+
+  // set macro cfgperm based on whether config file can be read or no
+  text_t dirname = (args["bc1dirname"] == "") ? first_dirname : args["bc1dirname"];
+  text_t cfg_fname = filename_cat(gsdlhome, "collect", dirname, "etc", "collect.cfg");
+  text_t cfgperm = (file_writable(cfg_fname)) ? text_t("read/write") : text_t("readonly");
+  disp.setmacro("cfgperm","build",cfgperm);
+
+  // if edit collection, read in collect.cfg file
+  if (args["bca"]=="editcol")
+    {
+      text_t dirname 
+	= (args["bc1dirname"] == "") ? first_dirname : args["bc1dirname"];
+
+      // read in collect.cfg      
+      text_t cfg_fname 
+	= filename_cat(gsdlhome, "collect", dirname, "etc", "collect.cfg");
+
+#ifdef GSDL_USE_IOS_H
+      ifstream cfg_ifs (cfg_fname.getcstr(), ios::in | ios::nocreate);
+#else
+      ifstream cfg_ifs (cfg_fname.getcstr(), ios::in);
+#endif
+
+      if (cfg_ifs) 
+	{  
+	  // read in collect.cfg      
+	  text_t cfg_text = "";
+	  
+	  char c;
+	  cfg_ifs.get(c);
+	  while (!cfg_ifs.eof ()) {
+	    cfg_text.push_back(c);
+	    if (c=='\\') { cfg_text.push_back('\\'); }
+	    cfg_ifs.get(c);
+	  }
+    
+	  cfg_ifs.close();
+	  if (cfgperm=="readonly") cfg_text = html_safe(cfg_text);
+
+	  // define it as a macro
+	  disp.setmacro("cfgfile","build",cfg_text);
+	} 
+      else 
+	{
+	  text_t error_mess = "Unable to read configuration file: "+cfg_fname;
+	  disp.setmacro("cfgfile","build",error_mess);
+	}
+    }
+
+  // if view log, read in collect.bld file
+  if (args["bca"]=="collog")
+    {
+      text_t dirname 
+	= (args["bc1dirname"] == "") ? first_dirname : args["bc1dirname"];
+
+      // read in collect.bld
+      text_t bld_fname = filename_cat(gsdlhome, "etc", dirname+ ".bld");
+
+#ifdef GSDL_USE_IOS_H
+      ifstream bld_ifs (bld_fname.getcstr(), ios::in | ios::nocreate);
+#else
+      ifstream bld_ifs (bld_fname.getcstr(), ios::in);
+#endif
+
+      if (bld_ifs) 
+	{
+	  text_t bld_text = "";
+	  
+	  char c;
+	  bld_ifs.get(c);
+	  while (!bld_ifs.eof ()) {
+	    bld_text.push_back(c);
+	    if (c=='\\') { bld_text.push_back('\\'); }
+	    bld_ifs.get(c);
+	  }
+    
+	  bld_ifs.close();
+	  bld_text = html_safe(bld_text);
+
+	  // define it as a macro
+	  disp.setmacro("bldfile","build",bld_text);
+	} 
+      else 
+	{
+	  text_t error_mess = "Log file currently empty.";
+	  disp.setmacro("bldfile","build",error_mess);
+	}
+    }
+}
+
+bool buildaction::do_action (cgiargsclass &args, recptprotolistclass * /*protos*/, 
+			     browsermapclass * /*browsers*/, displayclass &disp, 
+			     outconvertclass &outconvert, ostream &textout, 
+			     ostream &logout) {
+
+  // make sure we know about a receptionist
+  if (recpt == NULL) {
+    logout << "The page action does not contain information\n"
+           << "about any receptionists. The method set_receptionist\n"
+           << "was probably not called from the module which instantiated\n"
+           << "this page action.\n";
+    return false;
+  }
+
+  if (args["bca"] == "newcol") {
+    return do_newcol (args, disp, outconvert, textout, logout);
+  }
+  else if (args["bca"] == "editcol") {
+    return do_editcol (args, disp, outconvert, textout, logout);
+  }
+  else if (args["bca"] == "buildcol") {
+    return do_buildcol (args, disp, outconvert, textout, logout);
+  }
+  else if (args["bca"] == "buildstatus") {
+    return do_buildstatus (args, disp, outconvert, textout, logout);
+  }
+  else if (args["bca"] == "delcol") {
+    return do_delcol (args, disp, outconvert, textout, logout);
+  }
+  else if (args["bca"] == "collog") {
+    return do_collog (args, disp, outconvert, textout, logout);
+  }
+  else if (args["bca"] == "mess") {
+    return do_mess (args, disp, outconvert, textout, logout);
+  }
+
+  // default (bca == blankpage)
+  textout << outconvert << "<html><body bgcolor=#ffffff></body></html>\n";
+
+  return true;
+}
+
+
+
+bool buildaction::do_newcol  (cgiargsclass &args, displayclass &disp, 
+			      outconvertclass &outconvert, ostream &textout, 
+			      ostream &/*logout*/) {
+
+  text_tarray wizard_split;
+  const text_t& wizard = (args["wizard"] == "") ? (text_t)"textinfo" : args["wizard"];
+  splitchar(wizard.begin(),wizard.end(),':',wizard_split);
+  const text_t& wizard_last = wizard_split.back();
+
+  text_t content  = "_build:content"  + wizard_last + "_\n";
+  text_t headmess = "_build:header_(_build:headmess" + wizard_last + "_)\n";
+
+  textout << outconvert << disp << (headmess) << (content) << ("_build:wizardfooter_\n");
+
+  return true;
+}
+
+
+bool buildaction::do_editcol (cgiargsclass &/*args*/, displayclass &disp, 
+			      outconvertclass &outconvert, ostream &textout, 
+			      ostream &/*logout*/) {
+
+  textout << outconvert << disp << ("_build:header_(_build:headmesseditcol_)\n")
+	  << ("_build:contenteditcol_\n")
+	  << ("_build:wizardfooter_\n");
+
+  return true;
+}
+
+bool buildaction::do_buildcol (cgiargsclass &args, displayclass &disp, 
+			       outconvertclass &outconvert, ostream &textout, 
+			       ostream &logout) {
+
+  text_tarray wizard_split;
+  const text_t wizard = (args["wizard"].empty()) ? "buildcol" : args["wizard"];
+  splitchar(wizard.begin(),wizard.end(),':',wizard_split);
+  const text_t wizard_last = wizard_split.back();
+  
+  if (wizard_last != "buildframe")
+    {     
+      text_t headmess = "_build:header_(_build:headmess" + wizard_last + "_)\n";
+      text_t content  = "_build:content"  + wizard_last + "_\n";
+  
+      textout << outconvert << disp << headmess << content << "_build:wizardfooter_\n";
+    }
+  else
+    {
+      text_t dirname = (args["bc1dirname"] == "") ? 
+	"unknown" : args["bc1dirname"];
+
+      text_t tmpname = dirname+"_XXXXXX";
+      char *cstr_tmpname = tmpname.getcstr();
+
+      if (GSDL_MKTEMP (cstr_tmpname)==NULL)
+	logout << "Failed to create temporary filename" << endl;
+
+      delete cstr_tmpname;
+
+      disp.setmacro("bcargtmpname","build",tmpname);
+
+
+      text_t headmess = "_build:frameheader_(_build:headmess" + wizard_last + "_)\n";
+      text_t content  = "_build:content"  + wizard_last + "_\n";
+  
+      textout << outconvert << disp << headmess << content << "_build:framefooter_\n";
+      text_t cmd = "perl \"" + 
+	filename_cat(gsdlhome, "cgi-bin", "webpage_buildcol.pl") + "\"";
+      cmd += " \"httpbuild="+args["httpbuild"]+"\"";
+      cmd += " \"bc1copydata="+args["bc1copydata"]+"\"";
+      cmd += " \"bc1doimport="+args["bc1doimport"]+"\"";
+      cmd += " \"bc1dobuild="+args["bc1dobuild"]+"\"";
+      cmd += " \"bc1dirname="+args["bc1dirname"]+"\" \"bc1tmpname="+tmpname+"\"";
+      // run webpage_buildcol.pl in background on unix systems
+#if !defined (__WIN32__)
+      cmd += " &";
+#endif
+
+      char *cstr_cmd = cmd.getcstr();
+
+#if defined (__WIN32__)
+      gsdl_system (cstr_cmd, logout);
+#else
+      system (cstr_cmd);
+#endif
+
+      delete cstr_cmd;
+    }
+
+  return true;
+}
+
+bool buildaction::do_buildstatus (cgiargsclass &args, displayclass &disp, 
+				  outconvertclass &outconvert, ostream &textout, 
+				  ostream &/*logout*/) {
+
+  disp.setmacro("contentpara","buildstatus", args["mess"]);
+
+  textout << outconvert << disp << ("_buildstatus:header_\n")
+	  << ("_buildstatus:content_\n")
+	  << ("_buildstatus:footer_\n");
+
+  return true;
+}
+
+bool buildaction::do_delcol  (cgiargsclass &/*args*/, displayclass &disp, 
+			      outconvertclass &outconvert, ostream &textout, 
+			      ostream &/*logout*/) {
+
+  textout << outconvert << disp << ("_build:header_(_build:headmessdelcol_)\n")
+	  << ("_build:contentdelcol_\n")
+	  << ("_build:footer_\n");
+
+  return true;
+}
+
+
+bool buildaction::do_collog  (cgiargsclass &/*args*/, displayclass &disp, 
+			    outconvertclass &outconvert, ostream &textout, 
+			    ostream &/*logout*/) {
+  textout << outconvert << disp << ("_build:header_(_build:headmesscollog_)\n")
+	  << ("_build:contentcollog_\n")
+	  << ("_build:wizardfooter_\n");
+
+  return true;
+}
+
+bool buildaction::do_mess  (cgiargsclass &args, displayclass &disp, 
+			    outconvertclass &outconvert, ostream &textout, 
+			    ostream &/*logout*/) {
+
+  disp.setmacro("contentpara","buildmess", args["mess"]);
+  disp.setmacro("headmess","buildmess", args["head"]);
+  textout << outconvert << disp << ("_build:header_(_buildmess:headmess_)\n")
+	  << ("_buildmess:content_\n")
+	  << ("_build:footer_\n");
+
+  return true;
+}
Index: /main/tags/2.25/gsdl/src/recpt/buildaction.h
===================================================================
--- /main/tags/2.25/gsdl/src/recpt/buildaction.h	(revision 21064)
+++ /main/tags/2.25/gsdl/src/recpt/buildaction.h	(revision 21064)
@@ -0,0 +1,93 @@
+/**********************************************************************
+ *
+ * buildaction.h -- building collections
+ * Copyright (C) 1999  The New Zealand Digital Library Project
+ *
+ * A component of the Greenstone digital library software
+ * from the New Zealand Digital Library Project at the
+ * University of Waikato, New Zealand.
+ *
+ * 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.
+ *
+ *********************************************************************/
+
+
+#ifndef BUILDACTION_H
+#define BUILDACTION_H
+
+#include "action.h"
+#include "receptionist.h"
+
+class buildaction : public action {
+protected:
+  receptionist *recpt;
+
+public:
+  buildaction ();
+  virtual ~buildaction () {}
+
+  text_t get_action_name () {return "bc";}
+  
+  void set_receptionist (receptionist *therecpt) {recpt=therecpt;}
+
+  bool check_cgiargs (cgiargsinfoclass &argsinfo, cgiargsclass &args, 
+		      ostream &logout);
+
+
+  void get_cgihead_info (cgiargsclass &args, recptprotolistclass *protos,
+			 response_t &response,text_t &response_data, 
+			 ostream &logout);
+  
+  void define_internal_macros (displayclass &disp, cgiargsclass &args, 
+			       recptprotolistclass *protos, ostream &logout);
+  
+  bool do_action (cgiargsclass &args, recptprotolistclass *protos, 
+		  browsermapclass *browsers, displayclass &disp, 
+		  outconvertclass &outconvert, ostream &textout, 
+		  ostream &logout);
+
+protected:
+  bool do_newcol (cgiargsclass &args, displayclass &disp, 
+		  outconvertclass &outconvert, ostream &textout, 
+		  ostream &logout);
+
+  bool do_editcol (cgiargsclass &args, displayclass &disp, 
+		   outconvertclass &outconvert, ostream &textout, 
+		   ostream &logout);
+
+  bool do_buildcol (cgiargsclass &args, displayclass &disp, 
+		    outconvertclass &outconvert, ostream &textout, 
+		    ostream &logout);
+
+  bool do_buildstatus (cgiargsclass &args, displayclass &disp, 
+		       outconvertclass &outconvert, ostream &textout, 
+		       ostream &logout);
+
+  bool do_delcol (cgiargsclass &args, displayclass &disp, 
+		  outconvertclass &outconvert, ostream &textout, 
+		  ostream &logout);
+
+  bool do_collog (cgiargsclass &args, displayclass &disp, 
+		  outconvertclass &outconvert, ostream &textout, 
+		  ostream &logout);
+
+  bool do_mess (cgiargsclass &args, displayclass &disp, 
+		outconvertclass &outconvert, ostream &textout, 
+		ostream &logout);
+
+};
+
+
+#endif
Index: /main/tags/2.25/gsdl/src/recpt/cgiargs.cpp
===================================================================
--- /main/tags/2.25/gsdl/src/recpt/cgiargs.cpp	(revision 21064)
+++ /main/tags/2.25/gsdl/src/recpt/cgiargs.cpp	(revision 21064)
@@ -0,0 +1,274 @@
+/**********************************************************************
+ *
+ * cgiargs.cpp -- 
+ * Copyright (C) 1999  The New Zealand Digital Library Project
+ *
+ * A component of the Greenstone digital library software
+ * from the New Zealand Digital Library Project at the
+ * University of Waikato, New Zealand.
+ *
+ * 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.
+ *
+ *********************************************************************/
+
+#include "cgiargs.h"
+#include "gsdlunicode.h"
+
+
+
+void cgiarg_t::clear () {
+  value.clear();
+  source = program_arg;
+}
+
+cgiarg_t &cgiarg_t::operator=(const cgiarg_t &x) {
+  value=x.value;
+  source=x.source;
+  return *this;
+}
+
+
+bool operator==(const cgiarg_t &x, const cgiarg_t &y) {
+  return ((x.value == y.value) && (x.source == y.source));
+}
+
+bool operator<(const cgiarg_t &x, const cgiarg_t &y) {
+  return ((x.value < y.value) ||
+	  ((x.value == y.value) && (x.source == y.source)));
+}
+
+
+
+
+// constructors
+cgiargsclass::cgiargsclass () {
+}
+
+
+// this returns NULL if there isn't an entry with a value of
+// 'key' already defined
+
+void cgiargsclass::setarg (const text_t &key, const text_t &value,
+			   cgiarg_t::source_t source) {
+  cgiarg_t temparg;
+  temparg.value = value;
+  temparg.source = source;
+  args[key] = temparg;
+}
+
+void cgiargsclass::setdefaultarg (const text_t &key, const text_t &value,
+				  cgiarg_t::source_t source) {
+  if (getarg(key) == NULL) setarg (key, value, source);
+}
+
+void cgiargsclass::setintarg (const text_t &key, int value,
+			      cgiarg_t::source_t source) {
+  setarg (key, value, source);
+}
+
+void cgiargsclass::setdefaultintarg (const text_t &key, int value,
+				     cgiarg_t::source_t source) {
+  if (getarg(key) == NULL) setintarg (key, value, source);
+}
+
+void cgiargsclass::setcarg (const text_t &key, unsigned short c,
+			    cgiarg_t::source_t source) {
+  text_t t; 
+  t.push_back(c);
+  setarg(key,t, source);
+}
+
+void cgiargsclass::setdefaultcarg (const text_t &key, unsigned short c,
+				   cgiarg_t::source_t source) {
+  if (getarg(key) == NULL) setcarg (key, c, source);
+}
+
+text_t *cgiargsclass::getarg (const text_t &key) {
+  iterator here = args.find (key);
+  if (here == args.end()) return NULL;
+
+  return &((*here).second.value);
+}
+
+int cgiargsclass::getintarg (const text_t &key) {
+  text_t *text = getarg (key);
+  if (text == NULL) return 0;
+  return text->getint();
+}
+
+
+
+// stream operators to print cgi arguments for debugging purposes
+ostream &operator<<(ostream &outs, const cgiargsclass &args) {
+  utf8outconvertclass text_t2utf8;
+  cgiargsclass::const_iterator here = args.begin ();
+  cgiargsclass::const_iterator end = args.end ();
+
+  outs << "*** cgiargsclass\n";
+  
+  while (here != end) {
+    outs << text_t2utf8 << " \"" << (*here).first << "\"=\"" << 
+      (*here).second.value << "\"\n";
+    here++;
+  }
+  outs << "\n";
+
+  return outs;
+}
+
+
+
+cgiarginfo::cgiarginfo () {
+  multiplechar = false;
+  multiplevalue = false;
+  defaultstatus = weak;
+  argdefault.clear();
+  savedarginfo = can;
+}
+
+
+bool operator==(const cgiarginfo &x, const cgiarginfo &y) {
+  return ((x.shortname == y.shortname) &&
+	  (x.longname == y.longname) &&
+	  (x.multiplechar == y.multiplechar) &&
+	  (x.multiplevalue == y.multiplevalue) &&
+	  (x.defaultstatus == y.defaultstatus) &&
+	  (x.argdefault == y.argdefault) &&
+	  (x.savedarginfo == y.savedarginfo));
+}
+
+bool operator<(const cgiarginfo &x, const cgiarginfo &y) {
+  return ((x.shortname < y.shortname) ||
+	  ((x.shortname == y.shortname) &&
+	   ((x.longname < y.longname) ||
+	    ((x.longname == y.longname) &&
+	     ((x.multiplevalue < y.multiplevalue) ||
+	      ((x.multiplevalue == y.multiplevalue) &&
+	       ((x.multiplechar < y.multiplechar) ||
+		((x.multiplechar == y.multiplechar) &&
+		 ((x.defaultstatus < y.defaultstatus) ||
+		  ((x.defaultstatus == y.defaultstatus) &&
+		   ((x.argdefault < y.argdefault) ||
+		    ((x.argdefault == y.argdefault) &&
+		     ((x.savedarginfo < y.savedarginfo))))))))))))));
+}
+
+
+// constructor
+cgiargsinfoclass::cgiargsinfoclass () {
+}
+
+// addarginfo will combine the information with the present
+// information. If name clashes were detected then the information
+// will be written to logout and addarginfo will return false. No
+// processing with the arguments should be done if this happens
+// as the results will be meaningless.
+bool cgiargsinfoclass::addarginfo (ostream *logout, const cgiarginfo &info) {
+  outconvertclass text_t2ascii;
+
+  cgiarginfo *orginfo = getarginfo (info.shortname);
+  if (orginfo == NULL) {
+    argsinfo[info.shortname] = info;
+    return true; // no clashes
+  }
+
+  if (orginfo->longname != info.longname) {
+    if (logout != NULL) {
+      (*logout) << text_t2ascii << "Error: cgi argument name clash for argument \""
+		<< info.shortname << "\".\nOne long name was\n  \"" << orginfo->longname 
+		<< "\"\nand the other was\n  \"" << info.longname << "\".\n\n";
+    }
+    return false; // found a clash
+  }
+
+  if (orginfo->multiplevalue != info.multiplevalue) {
+    if (logout != NULL) {
+      (*logout) << text_t2ascii << "Error: cgi argument \"" << info.shortname 
+		<< "\" was given as being a single value option\n"
+		<< "and a multiple value option.\n\n";
+    }
+    return false; // found a clash
+  }
+
+  if (orginfo->multiplechar != info.multiplechar) {
+    if (logout != NULL) {
+      (*logout) << text_t2ascii << "Error: cgi argument \"" << info.shortname 
+		<< "\" was given as being a single character option\n"
+		<< "and a multiple character option.\n\n";
+    }
+    return false; // found a clash
+  }
+  
+  if (!info.multiplechar && info.argdefault.size() > 1) {
+    if (logout != NULL) {
+      (*logout) << text_t2ascii << "Error: cgi argument \"" << info.shortname
+		<< "\" was defined as being a single character option\n"
+		<< "but a multiple character default was given.\n\n";
+    }
+    return false;  // found a problem
+  }
+
+  // make sure there is no clashes in the savedarginfo
+  if ((orginfo->savedarginfo==cgiarginfo::mustnot && 
+       info.savedarginfo==cgiarginfo::must) ||
+      (orginfo->savedarginfo==cgiarginfo::must && 
+       info.savedarginfo==cgiarginfo::mustnot)) {
+    if (logout != NULL) {
+      (*logout) << text_t2ascii << "Error: it was specified that cgi argument \"" 
+		<< info.shortname << "\" should be saved in the state\n"
+		<< "information and that it should not be save in the state information.\n\n";
+    }
+    return false; // found a clash
+  }
+  // the only time orginfo->savedarginfo can change is when it is set
+  // to "can"
+  if (orginfo->savedarginfo == cgiarginfo::can) 
+    orginfo->savedarginfo = info.savedarginfo;
+
+
+  if (orginfo->defaultstatus > info.defaultstatus) {
+    return true;
+  }
+  orginfo->defaultstatus = info.defaultstatus;
+  orginfo->argdefault = info.argdefault;
+
+  return true;
+}
+
+bool cgiargsinfoclass::addarginfo (ostream *logout, const cgiargsinfoclass &info) {
+  const_iterator here = info.begin ();
+  const_iterator end = info.end ();
+
+  while (here != end) {
+    if (!addarginfo (logout, (*here).second)) return false;
+    here++;
+  }
+  
+  return true; // made it, no clashes
+}
+
+cgiarginfo *cgiargsinfoclass::getarginfo (const text_t &key) {
+  iterator here = argsinfo.find (key);
+  if (here == argsinfo.end()) return NULL;
+
+  return &((*here).second);
+}
+
+const cgiarginfo *cgiargsinfoclass::getarginfo (const text_t &key) const {
+  const_iterator here = argsinfo.find (key);
+  if (here == argsinfo.end()) return NULL;
+
+  return &((*here).second);
+}
Index: /main/tags/2.25/gsdl/src/recpt/cgiargs.h
===================================================================
--- /main/tags/2.25/gsdl/src/recpt/cgiargs.h	(revision 21064)
+++ /main/tags/2.25/gsdl/src/recpt/cgiargs.h	(revision 21064)
@@ -0,0 +1,233 @@
+/**********************************************************************
+ *
+ * cgiargs.h -- 
+ * Copyright (C) 1999  The New Zealand Digital Library Project
+ *
+ * A component of the Greenstone digital library software
+ * from the New Zealand Digital Library Project at the
+ * University of Waikato, New Zealand.
+ *
+ * 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.
+ *
+ *********************************************************************/
+
+
+#ifndef CGIARGS_H
+#define CGIARGS_H
+
+#include "gsdlconf.h"
+#include "text_t.h"
+
+#if defined(GSDL_USE_OBJECTSPACE)
+#  include <ospace\std\iostream>
+#elif defined(GSDL_USE_IOS_H)
+#  include <iostream.h>
+#else
+#  include <iostream>
+#endif
+
+#if defined(GSDL_USE_OBJECTSPACE)
+#  include <ospace\std\map>
+#elif defined(GSDL_USE_STL_H)
+#  include <map.h>
+#else
+#  include <map>
+#endif
+
+
+// response_t is used to define what type of cgi header 
+// should be produced
+enum response_t {location, content};
+
+
+struct cgiarg_t {
+  void clear ();
+  cgiarg_t () {clear();}
+  cgiarg_t &operator=(const cgiarg_t &x);
+  
+  enum source_t {default_arg, compressed_arg, cgi_arg, program_arg};
+  
+  text_t value;
+  source_t source;
+};
+
+bool operator==(const cgiarg_t &x, const cgiarg_t &y);
+bool operator<(const cgiarg_t &x, const cgiarg_t &y);
+
+typedef map<text_t, cgiarg_t, lttext_t> cgiarg_tmap;
+
+// cgiargsclass is used to store a particular set
+// of cgi arguments.
+class cgiargsclass {
+protected:
+  cgiarg_tmap args;
+
+public:
+  //type support for cgiarg_tmap
+  typedef cgiarg_tmap::iterator iterator;
+  typedef cgiarg_tmap::const_iterator const_iterator;
+  typedef cgiarg_tmap::reference reference;
+  typedef cgiarg_tmap::const_reference const_reference;
+  typedef cgiarg_tmap::size_type size_type;
+  typedef cgiarg_tmap::difference_type difference_type;
+  typedef cgiarg_tmap::const_reverse_iterator const_reverse_iterator;
+  typedef cgiarg_tmap::reverse_iterator reverse_iterator;
+  
+  // constructors
+  cgiargsclass ();
+
+  // basic container support
+  iterator begin () {return args.begin();}
+  const_iterator begin () const {return args.begin();}
+  iterator end () {return args.end();}
+  const_iterator end () const {return args.end();}
+
+  void erase(iterator pos) {args.erase(pos);}
+  void erase(iterator first, iterator last) {args.erase(first, last);}
+  cgiargsclass &operator=(const cgiargsclass &x) {args=x.args;return *this;}
+
+  bool empty () const {return args.empty();}
+  size_type size() const {return args.size();}
+
+
+  // added functionality
+  void clear () {args.erase(args.begin(),args.end());}
+
+  // setdefaultarg, setdefaultintarg, and setdefaultcarg will 
+  // only set the argument if it is not already set
+  // getargs returns NULL if there isn't an entry with
+  // 'key' already defined, getintarg returns 0 if there wasn't an
+  // entry with 'key' defined and operator[] returns "" if
+  // 'key' wasn't already defined (and sets 'key'="").
+  void setarg (const text_t &key, const text_t &value,
+	       cgiarg_t::source_t source=cgiarg_t::program_arg);
+  void setdefaultarg (const text_t &key, const text_t &value,
+		      cgiarg_t::source_t source=cgiarg_t::default_arg);
+  void setintarg (const text_t &key, int value,
+		  cgiarg_t::source_t source=cgiarg_t::program_arg);
+  void setdefaultintarg (const text_t &key, int value,
+			 cgiarg_t::source_t source=cgiarg_t::default_arg);
+  void setcarg (const text_t &key, unsigned short c,
+		cgiarg_t::source_t source=cgiarg_t::program_arg);
+  void setdefaultcarg (const text_t &key, unsigned short c,
+		       cgiarg_t::source_t source=cgiarg_t::default_arg);
+  text_t *getarg (const text_t &key);
+  int getintarg (const text_t &key);
+  text_t &operator[] (const text_t &key) {return args[key].value;}
+  cgiarg_t &lookupcgiarg (const text_t &key) {return args[key];}
+};
+
+// stream operators to print cgi arguments for debugging purposes
+ostream &operator<<(ostream &outs, const cgiargsclass &args);
+
+
+
+// cgiarginfo holds information relating to a cgi argument
+class cgiarginfo {
+public:
+  cgiarginfo ();
+
+  // shortname is the name used in cgi arguments
+  text_t shortname;
+
+  // longname is the name used when giving information 
+  // about the argument and to spot name duplication
+  text_t longname;
+
+  // multiplechar should be set to true if the value can be
+  // more than one character long
+  bool multiplechar;
+
+  // multiplevalue should be set to true the argument may have 
+  // multiple values (as is the case when multiple checkboxes
+  // use the same name)
+  bool multiplevalue;
+
+  // defaultstatus_t indicates how good the default is when different
+  // defaults are given for one argument. "none" means there is no default
+  // (a default might be given elsewhere). "weak" is a basic guess that
+  // doesn't hold much weight, "good" is a better guess, "config" was a default
+  // given in a configuration file, and "imperative" means it must not
+  // be overriden at any costs (unless there is another "imperative"...)
+  enum defaultstatus_t {none=0, weak=1, good=2, config=3, imperative=4};
+
+  defaultstatus_t defaultstatus;
+  text_t argdefault;   // a default value
+
+  // savedarginfo_t indicates whether the argument should be saved
+  // between pages (e.g. using the compressed argument) or not. The
+  // value of an argument can change from "can" to "mustnot" and 
+  // "can" to "must" but not "mustnot" to "must" or "must" to "mustnot".
+  enum savedarginfo_t {mustnot, can, must};
+
+  savedarginfo_t savedarginfo;
+};
+
+bool operator==(const cgiarginfo &x, const cgiarginfo &y);
+bool operator<(const cgiarginfo &x, const cgiarginfo &y);
+
+typedef map<text_t, cgiarginfo, lttext_t> argsinfomap;
+
+// contains a list of cgi argument information
+class cgiargsinfoclass {
+protected:
+  argsinfomap argsinfo;
+
+public:
+  // type support for arginfomap
+  typedef argsinfomap::iterator iterator;
+  typedef argsinfomap::const_iterator const_iterator;
+  typedef argsinfomap::reference reference;
+  typedef argsinfomap::const_reference const_reference;
+  typedef argsinfomap::size_type size_type;
+  typedef argsinfomap::difference_type difference_type;
+  typedef argsinfomap::const_reverse_iterator const_reverse_iterator;
+  typedef argsinfomap::reverse_iterator reverse_iterator;
+  
+  // constructors
+  cgiargsinfoclass ();
+
+  // basic container support
+  iterator begin () {return argsinfo.begin();}
+  const_iterator begin () const {return argsinfo.begin();}
+  iterator end () {return argsinfo.end();}
+  const_iterator end () const {return argsinfo.end();}
+
+  void erase(iterator pos) {argsinfo.erase(pos);}
+  void erase(iterator first, iterator last) {argsinfo.erase(first, last);}
+  cgiargsinfoclass &operator=(const cgiargsinfoclass &x) {argsinfo=x.argsinfo;return *this;}
+
+  bool empty () const {return argsinfo.empty();}
+  size_type size() const {return argsinfo.size();}
+
+
+  // added functionality
+  void clear () {argsinfo.erase(argsinfo.begin(),argsinfo.end());}
+
+  // addarginfo will combine the information with the present
+  // information. If name clashes were detected then the information
+  // will be written to logout and addarginfo will return false. No
+  // processing with the arguments should be done if this happens
+  // as the results will be meaningless.
+  bool addarginfo (ostream *logout, const cgiarginfo &info);
+  bool addarginfo (ostream *logout, const cgiargsinfoclass &info);
+
+  cgiarginfo *getarginfo (const text_t &key);
+  const cgiarginfo *getarginfo (const text_t &key) const;
+  cgiarginfo &operator[] (const text_t &key) {return argsinfo[key];}
+};
+
+
+#endif
Index: /main/tags/2.25/gsdl/src/recpt/cgiutils.cpp
===================================================================
--- /main/tags/2.25/gsdl/src/recpt/cgiutils.cpp	(revision 21064)
+++ /main/tags/2.25/gsdl/src/recpt/cgiutils.cpp	(revision 21064)
@@ -0,0 +1,466 @@
+/**********************************************************************
+ *
+ * cgiutils.cpp -- general cgi utilities
+ * Copyright (C) 1999  The New Zealand Digital Library Project
+ *
+ * A component of the Greenstone digital library software
+ * from the New Zealand Digital Library Project at the
+ * University of Waikato, New Zealand.
+ *
+ * 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.
+ *
+ *********************************************************************/
+
+#include "cgiutils.h"
+
+
+static unsigned short hexdigit (unsigned short c) {
+  if (c >= '0' && c <= '9') return (c-'0');
+  if (c >= 'a' && c <= 'f') return (c-'a'+10);
+  if (c >= 'A' && c <= 'F') return (c-'A'+10);
+  return c;
+}
+
+
+static void c2hex (unsigned short c, text_t &t) {
+  t.clear();
+  
+  if (c >= 256) {
+    t = "20"; // ' '
+    return;
+  }
+  
+  unsigned short o1, o2;
+  
+  o1 = (c/16) % 16;
+  o2 = c % 16;
+  if (o1 >= 10) o1 += 'a' - 10;
+  else o1 += '0';
+  if (o2 >= 10) o2 += 'a' - 10;
+  else o2 += '0';
+  
+  t.push_back(o1);
+  t.push_back(o2);
+}
+
+// convert %xx and + to their appropriate equivalents
+void decode_cgi_arg (text_t &argstr) {
+  text_t::iterator in = argstr.begin();
+  text_t::iterator out = in;
+  text_t::iterator end = argstr.end();
+  
+  while (in != end) {
+    if (*in == '+') *out = ' ';
+    
+    else if (*in == '%') {
+      unsigned short c = '%';
+      in++;
+      if (in != end) {
+	c = hexdigit (*in);
+	in++;
+      }
+      if (in != end && c < 16) { // sanity check on the previous character
+	c = c*16 + hexdigit (*in);
+      }
+      
+      *out = c;
+    } else *out = *in;
+    
+    if (in != end) in++;
+    out++;
+  }
+  
+  // remove the excess characters
+  argstr.erase (out, end);
+}
+
+
+// split up the cgi arguments
+void split_cgi_args (const cgiargsinfoclass &argsinfo, text_t argstr, 
+		     cgiargsclass &args) {
+  args.clear();
+  
+  text_t::iterator here = argstr.begin();
+  text_t::iterator end = argstr.end();
+  text_t key, value;
+  
+  // extract out the key=value pairs
+  while (here != end) {
+    // get the next key and value pair
+    here = getdelimitstr (here, end, '=', key);
+    here = getdelimitstr (here, end, '&', value);
+    
+    // convert %xx and + to their appropriate equivalents
+    decode_cgi_arg (value);
+
+    value.setencoding(1); // other encoding
+    // store this key=value pair
+    if (!key.empty()) {
+      // if arg occurs multiple times (as is the case with
+      // multiple checkboxes using the same name) we'll 
+      // create a comma separated list of all the values
+      // (if multiplevalue)
+      if (!args[key].empty()) {
+	const cgiarginfo *info = argsinfo.getarginfo (key);
+	if (info != NULL && info->multiplevalue)
+	  args[key] += "," + value;
+	else args.setarg (key, value, cgiarg_t::cgi_arg);
+      } else 
+	args.setarg (key, value, cgiarg_t::cgi_arg);
+    }
+  }
+}
+
+text_t minus_safe (const text_t &intext) {
+
+  text_t outtext;
+
+  text_t::const_iterator here = intext.begin ();
+  text_t::const_iterator end = intext.end ();
+
+  while (here != end) {
+    if (*here == '-') outtext += "Z-";
+    else outtext.push_back (*here);
+    here ++;
+  }
+  outtext = cgi_safe (outtext);
+  return outtext;
+}
+
+text_t cgi_safe (const text_t &intext) {
+  text_t outtext;
+  
+  text_t::const_iterator here = intext.begin ();
+  text_t::const_iterator end = intext.end ();
+  unsigned short c;
+  text_t ttmp;
+  
+  while (here != end) {
+    c = *here;
+    if (((c >= 'a') && (c <= 'z')) ||
+	((c >= 'A') && (c <= 'Z')) ||
+	((c >= '0') && (c <= '9')) ||
+	(c == '+') || (c == '%') || (c == '-')) {
+      // alphanumeric character
+      outtext.push_back(c);
+    } else if (c == ' ') {
+      // space
+      outtext.push_back('+');
+    } else {
+      // everything else
+      outtext.push_back('%');
+      c2hex(c, ttmp);
+      outtext += ttmp;
+    }
+    
+    here++;
+  }
+  
+  return outtext;
+}
+
+
+
+
+static text_t::const_iterator get_next_save_arg (text_t::const_iterator first, 
+					   text_t::const_iterator last,
+					   text_t &argname) {
+  first = getdelimitstr (first, last, '-', argname);
+  return first;
+}
+
+
+// check_save_conf_str checks the configuration string for
+// the saved args and makes sure it does not conflict with
+// the information about the arguments. If an error is encountered
+// it will return false and the program should not produce any
+// output.
+bool check_save_conf_str (const text_t &saveconf, 
+			  const cgiargsinfoclass &argsinfo,
+			  ostream &logout) {
+  outconvertclass text_t2ascii;
+
+  text_tset argsset;
+  text_t::const_iterator saveconfhere = saveconf.begin ();
+  text_t::const_iterator saveconfend = saveconf.end ();
+  text_t argname;
+  const cgiarginfo *info;
+
+  // first check to make sure all saved arguments can be saved
+  
+  while (saveconfhere != saveconfend) {
+    saveconfhere = get_next_save_arg (saveconfhere, saveconfend, argname);
+
+    if (!argname.empty()) {
+      // save the argument name for later
+      argsset.insert (argname);
+
+      // check the argument
+      info =  argsinfo.getarginfo (argname);
+      if (info == NULL) {
+	logout << text_t2ascii << "Error: the cgi argument \"" << argname 
+	       << "\" is used in the configuration string for the\n"
+	       << "saved arguments but does not exist as a valid argument.\n\n";
+	return false;
+      }
+      if (info->savedarginfo == cgiarginfo::mustnot) {
+	logout << text_t2ascii << "Error: the cgi argument \"" << argname
+	       << "\" is used in the configuration string for the\n"
+	       << "saved arguments but has been specified as an argument whose\n"
+	       << "state must not be saved.\n\n";
+	return false;
+      }
+    }
+  }
+
+
+  // next check that all saved arguments that should be saved
+  // are saved
+  cgiargsinfoclass::const_iterator argsinfohere = argsinfo.begin ();
+  cgiargsinfoclass::const_iterator argsinfoend = argsinfo.end ();
+
+  while (argsinfohere != argsinfoend) {
+    if (((*argsinfohere).second.savedarginfo == cgiarginfo::must) &&
+	(argsset.find((*argsinfohere).second.shortname) == argsset.end())) {
+      logout << text_t2ascii << "Error: the cgi argument \"" 
+	     << (*argsinfohere).second.shortname << "\" was specified as needing to\n"
+	     << "be save but was not listed in the saved arguments.\n\n";
+      return false;
+    }
+
+    argsinfohere++;
+  }
+  
+  return true; // made it, no clashes
+}
+
+
+// create_save_conf_str will create a configuration string
+// based on the information in argsinfo. This method of configuration
+// is not recomended as small changes can produce large changes in
+// the resulting configuration string (for instance a totally different
+// ordering). Only arguments which "must" be saved are included in
+// the resulting string.
+text_t create_save_conf_str (const cgiargsinfoclass &argsinfo,
+			     ostream &/*logout*/) {
+  cgiargsinfoclass::const_iterator argsinfohere = argsinfo.begin ();
+  cgiargsinfoclass::const_iterator argsinfoend = argsinfo.end ();
+  text_t saveconf;
+  bool first = true;
+
+  while (argsinfohere != argsinfoend) {
+    // save this argument if it must be saved
+    if ((*argsinfohere).second.savedarginfo == cgiarginfo::must) {
+      if (!first) saveconf.push_back ('-');
+      else first = false;
+      saveconf += (*argsinfohere).second.shortname;
+    }
+
+    argsinfohere++;
+  }
+  
+  return saveconf;
+}
+
+
+// expand_save_args will expand the saved arguments based
+// on saveconf placing the results in args if they are not
+// already defined. If it encounters an error it will return false
+// and output more information to logout.
+bool expand_save_args (const cgiargsinfoclass &argsinfo,
+		       const text_t &saveconf, 
+		       cgiargsclass &args,
+		       ostream &logout) {
+  outconvertclass text_t2ascii;
+
+  text_t *arg_e = args.getarg("e");
+  if (arg_e == NULL) return true; // no compressed arguments
+  if (arg_e->empty()) return true; // no compressed arguments
+
+  text_t argname, argvalue;
+  const cgiarginfo *argnameinfo;
+  
+  text_t::const_iterator saveconfhere = saveconf.begin();
+  text_t::const_iterator saveconfend = saveconf.end();
+  
+  text_t::iterator arg_ehere = arg_e->begin();
+  text_t::iterator arg_eend = arg_e->end();
+  while (saveconfhere != saveconfend && arg_ehere != arg_eend) {
+    saveconfhere = get_next_save_arg (saveconfhere, saveconfend, argname);
+
+    if (!argname.empty()) {
+      // found another entry
+      argnameinfo = argsinfo.getarginfo (argname);
+
+      if (argnameinfo == NULL) {
+	// no information about the argument could be found
+	// we can't keep going because we don't know whether
+	// this argument is a single or multiple character value
+	logout << text_t2ascii << "Error: the cgi argument \"" << argname
+	       << "\" was specified as being a compressed argument\n"
+	       << "but no information about it could be found within the "
+	       << "cgiargsinfoclass.\n";
+	return false;
+
+      } else {
+
+	// found the argument information
+	if (argnameinfo->multiplechar) {
+	  text_t::const_iterator sav = arg_ehere;
+	  arg_ehere = getdelimitstr (arg_ehere, arg_eend, '-', argvalue);
+	  // replace any '-' chars escaped with 'Z'
+	  if (*(arg_ehere-2) == 'Z') {
+	    argvalue.clear();
+	    arg_ehere = (findchar (arg_ehere, arg_eend, '-')) + 1;
+	    while (sav != (arg_ehere-1)) {
+	      if (!((*sav == 'Z') && (*(sav+1) == '-'))) argvalue.push_back (*sav);
+	      sav ++;
+	    }
+	  }
+
+	  argvalue.setencoding(1); // other encoding
+	  if (!argvalue.empty()) args.setdefaultarg (argname, argvalue, cgiarg_t::compressed_arg);
+	} else {
+	  args.setdefaultcarg (argname,*arg_ehere, cgiarg_t::compressed_arg);
+	  arg_ehere++;
+	}
+      }
+    }
+  }
+
+  return true;
+}
+
+
+// adds the default values for those arguments which have not
+// been specified
+void add_default_args (const cgiargsinfoclass &argsinfo,
+		       cgiargsclass &args,
+		       ostream &/*logout*/) {
+  cgiargsinfoclass::const_iterator argsinfohere = argsinfo.begin ();
+  cgiargsinfoclass::const_iterator argsinfoend = argsinfo.end ();
+
+  while (argsinfohere != argsinfoend) {
+    if ((*argsinfohere).second.defaultstatus != cgiarginfo::none) {
+      args.setdefaultarg ((*argsinfohere).second.shortname,
+			  (*argsinfohere).second.argdefault, cgiarg_t::default_arg);
+    }
+    argsinfohere++;
+  }
+}
+
+
+// compress_save_args will compress the arguments and return
+// them in compressed_args. If an error was encountered
+// compressed_args will be set to to "", an error will be
+// written to logout, and the function will return false.
+bool compress_save_args (const cgiargsinfoclass &argsinfo,
+			 const text_t &saveconf,
+			 cgiargsclass &args,
+			 text_t &compressed_args,
+			 outconvertclass &outconvert,
+			 ostream &logout) {
+  outconvertclass text_t2ascii;
+
+  compressed_args.clear();
+
+  text_t argname, argvalue;
+  const cgiarginfo *argnameinfo;
+  
+  text_t::const_iterator saveconfhere = saveconf.begin();
+  text_t::const_iterator saveconfend = saveconf.end();
+  
+  while (saveconfhere != saveconfend) {
+    saveconfhere = get_next_save_arg (saveconfhere, saveconfend, argname);
+
+    if (!argname.empty()) {
+      // found another entry
+      argnameinfo = argsinfo.getarginfo (argname);
+
+      if (argnameinfo == NULL) {
+	// no information about the argument could be found
+	// we can't keep going because we don't know whether
+	// this argument is a single or multiple character value
+	logout << text_t2ascii << "Error: the cgi argument \"" << argname
+	       << "\" was specified as being a compressed argument\n"
+	       << "but no information about it could be found within the "
+	       << "cgiargsinfoclass.\n";
+	compressed_args.clear();
+	return false;
+
+      } else {
+	// found the argument information
+	if (argnameinfo->multiplechar) {
+	  // multiple character argument -- sort out any '-' chars
+	  compressed_args += minus_safe (outconvert.convert(args[argname]));
+	  if (saveconfhere != saveconfend) compressed_args.push_back ('-');
+
+	} else {
+	  // single character argument
+	  if (args[argname].size() == 0) {
+	    logout << text_t2ascii << "Error: the cgi argument \"" << argname
+		   << "\" was specified as being a compressed argument which\n"
+		   << "should have a one character value but it was empty.\n\n";
+	    compressed_args.clear ();
+	    return false;
+
+	  } else if (args[argname].size() > 1) {
+	    logout << text_t2ascii << "Error: the cgi argument \"" << argname
+		   << "\" was specified as being a compressed argument which\n"
+		   << "should have a one character value but it had multiple characters.\n\n";
+	    compressed_args.clear ();
+	    return false;
+	  }
+
+	  // everything is ok
+	  compressed_args += args[argname];
+	}
+      }
+    }
+  }
+
+  return true;
+}
+
+
+// args_tounicode converts any arguments which are not in unicode
+// to unicode using inconvert
+void args_tounicode (cgiargsclass &args, inconvertclass &inconvert) {
+  cgiargsclass::iterator here = args.begin();
+  cgiargsclass::iterator end = args.end();
+
+  while (here != end) {
+    if ((*here).second.value.getencoding() > 0) {
+      (*here).second.value = inconvert.convert((*here).second.value);
+    }
+    
+    here++;
+  }
+}
+
+// fcgienv will be loaded with environment name-value pairs
+// if using fastcgi (had to do this as getenv doesn't work
+// with our implementation of fastcgi). if fcgienv is empty
+// we'll simply use getenv
+text_t gsdl_getenv (const text_t &name, text_tmap &fcgienv) {
+  if (fcgienv.empty()) {
+    char *n = name.getcstr();
+    char *v = getenv(n);
+    delete n;
+    if (v != NULL) return v;
+    return "";
+
+  } else return fcgienv[name];
+}
Index: /main/tags/2.25/gsdl/src/recpt/cgiutils.h
===================================================================
--- /main/tags/2.25/gsdl/src/recpt/cgiutils.h	(revision 21064)
+++ /main/tags/2.25/gsdl/src/recpt/cgiutils.h	(revision 21064)
@@ -0,0 +1,98 @@
+/**********************************************************************
+ *
+ * cgiutils.h -- general cgi utilities
+ * Copyright (C) 1999  The New Zealand Digital Library Project
+ *
+ * A component of the Greenstone digital library software
+ * from the New Zealand Digital Library Project at the
+ * University of Waikato, New Zealand.
+ *
+ * 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.
+ *
+ *********************************************************************/
+
+
+#ifndef CGIUTILS_H
+#define CGIUTILS_H
+
+#include "gsdlconf.h"
+#include "text_t.h"
+#include "cgiargs.h"
+
+
+// convert %xx and + to their appropriate equivalents
+void decode_cgi_arg (text_t &argstr);
+
+// split up the cgi arguments
+void split_cgi_args (const cgiargsinfoclass &argsinfo, text_t argstr, 
+		     cgiargsclass &args);
+
+// turns any '-' in a cgi argument into "(-)"
+text_t minus_safe (const text_t &intext);
+
+// returns the encoded version of a cgi argument
+text_t cgi_safe (const text_t &intext);
+
+// check_save_conf_str checks the configuration string for
+// the saved args and makes sure it does not conflict with
+// the information about the arguments. If an error is encountered
+// it will return false and the program should not produce any
+// output.
+bool check_save_conf_str (const text_t &saveconf, 
+			  const cgiargsinfoclass &argsinfo,
+			  ostream &logout);
+
+// create_save_conf_str will create a configuration string
+// based on the information in argsinfo. This method of configuration
+// is not recomended as small changes can produce large changes in
+// the resulting configuration string (for instance a totally different
+// ordering). Only arguments which "must" be saved are included in
+// the resulting string.
+text_t create_save_conf_str (const cgiargsinfoclass &argsinfo,
+			     ostream &logout);
+
+// expand_compress_args will expand the compressed arguments based
+// on compressconf placing the results in args if they are not
+// already defined. If it encounters an error it will return false
+// and output more information to logout.
+bool expand_save_args (const cgiargsinfoclass &argsinfo,
+		       const text_t &saveconf, 
+		       cgiargsclass &args,
+		       ostream &logout);
+
+// adds the default values for those arguments which have not
+// been specified
+void add_default_args (const cgiargsinfoclass &argsinfo,
+		       cgiargsclass &args,
+		       ostream &logout);
+
+// compress_save_args will compress the arguments and return
+// them in compressed_args. If an error was encountered
+// compressed_args will be set to to "", an error will be
+// written to logout, and the function will return false.
+bool compress_save_args (const cgiargsinfoclass &argsinfo,
+			 const text_t &saveconf,
+			 cgiargsclass &args,
+			 text_t &compressed_args,
+			 outconvertclass &outconvert,
+			 ostream &logout);
+
+// args_tounicode converts any arguments which are not in unicode
+// to unicode using inconvert
+void args_tounicode (cgiargsclass &args, inconvertclass &inconvert);
+
+text_t gsdl_getenv (const text_t &name, text_tmap &fcgienv);
+
+#endif
Index: /main/tags/2.25/gsdl/src/recpt/cgiwrapper.cpp
===================================================================
--- /main/tags/2.25/gsdl/src/recpt/cgiwrapper.cpp	(revision 21064)
+++ /main/tags/2.25/gsdl/src/recpt/cgiwrapper.cpp	(revision 21064)
@@ -0,0 +1,674 @@
+/**********************************************************************
+ *
+ * cgiwrapper.cpp -- output pages using the cgi protocol
+ * Copyright (C) 1999  The New Zealand Digital Library Project
+ *
+ * A component of the Greenstone digital library software
+ * from the New Zealand Digital Library Project at the
+ * University of Waikato, New Zealand.
+ *
+ * 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.
+ *
+ *********************************************************************/
+
+#include "gsdlconf.h"
+#include "cgiwrapper.h"
+#include "recptconfig.h"
+#include "fileutil.h"
+#include <stdlib.h>
+#include <assert.h>
+
+#if defined(GSDL_USE_OBJECTSPACE)
+#  include <ospace/std/iostream>
+#  include <ospace/std/fstream>
+#elif defined(GSDL_USE_IOS_H)
+#  include <iostream.h>
+#  include <fstream.h>
+#else
+#  include <iostream>
+#  include <fstream>
+#endif
+
+#ifdef USE_FASTCGI
+#include "fcgiapp.h"
+#endif
+
+
+#ifdef USE_FASTCGI
+// used to output the text from receptionist
+class fcgistreambuf : public streambuf {
+public:
+  fcgistreambuf ();
+  int sync ();
+  int overflow (int ch);
+  int underflow () {return EOF;}
+  
+  void fcgisbreset() {fcgx_stream = NULL; other_ostream = NULL;};
+  void set_fcgx_stream(FCGX_Stream *newone) {fcgx_stream=newone;};
+  void set_other_ostream(ostream *newone) {other_ostream=newone;};
+  
+private:
+  FCGX_Stream *fcgx_stream;
+  ostream *other_ostream;
+};
+
+fcgistreambuf::fcgistreambuf() {
+  fcgisbreset();
+  if (base() == ebuf()) allocate();
+  setp (base(), ebuf());
+};
+
+int fcgistreambuf::sync () {
+  if ((fcgx_stream != NULL) &&
+      (FCGX_PutStr (pbase(), out_waiting(), fcgx_stream) < 0)) {
+    fcgx_stream = NULL;
+  }
+
+  if (other_ostream != NULL) {
+    char *thepbase=pbase();
+    for (int i=0;i<out_waiting();i++) (*other_ostream).put(thepbase[i]);
+  }
+  
+  setp (pbase(), epptr());
+  
+  return 0;
+}
+
+int fcgistreambuf::overflow (int ch) {
+  if (sync () == EOF) return EOF;
+  if (ch != EOF) sputc (ch);
+  return 0;
+}
+
+#endif
+
+static void format_error_string (text_t &errorpage, const text_t &errortext, bool debug) {
+
+  errorpage.clear();
+
+  if (debug) {
+    errorpage += "\n";
+    errorpage += "ERROR: " + errortext;
+    errorpage += "\n";
+    
+  } else {
+
+    errorpage += "Content-type: text/html\n\n";
+    
+    errorpage += "<html>\n";
+    errorpage += "<head>\n";
+    errorpage += "<title>Error</title>\n";
+    errorpage += "</head>\n";
+    errorpage += "<body>\n";
+    errorpage += "<h2>Oops!</h2>\n";
+    errorpage += errortext;
+    errorpage += "</body>\n";
+    errorpage += "</html>\n";
+  }
+}
+
+static void page_errorcollect (const text_t &gsdlhome, text_t &errorpage, bool debug) {
+
+  text_t collectdir = filename_cat (gsdlhome, "collect");
+
+  text_t errortext = "No valid collections were found: Check that your collect directory\n";
+  errortext += "(" + collectdir + ") is readable and contains at least one valid collection.\n";
+  errortext += "Note that modelcol is NOT a valid collection.\n";
+  errortext += "If the path to your collect directory is wrong edit the 'gsdlhome' field\n";
+  errortext += "in your gsdlsite.cfg configuration file.\n";
+
+  format_error_string (errorpage, errortext, debug);
+}
+
+static void page_errorsitecfg (text_t &errorpage, bool debug, int mode) {
+
+  text_t errortext;
+
+  if (mode == 0) {
+    errortext += "The gsdlsite.cfg configuration file could not be found. This\n";
+    errortext += "file should contain configuration information relating to this\n";
+    errortext += "site's setup.\n";
+
+  } else if (mode == 1) {
+    errortext += "The gsdlsite.cfg configuration file does not contain a valid\n";
+    errortext += "gsdlhome entry.\n";
+  }
+
+  if (debug) {
+    errortext += "gsdlsite.cfg should reside in the directory from which the\n";
+    errortext += "library executable was run.\n";
+  } else {
+    errortext += "gsdlsite.cfg should reside in the same directory as the library\n";
+    errortext += "executable file.\n";
+  }
+
+  format_error_string (errorpage, errortext, debug);
+}
+
+
+static void page_errormaincfg (const text_t &gsdlhome, const text_t &collection,
+			       bool debug, text_t &errorpage) {
+
+  text_t errortext;
+
+  if (collection.empty()) {
+    text_t main_cfg_file = filename_cat (gsdlhome, "etc", "main.cfg");
+    errortext += "The main.cfg configuration file could not be found. This file\n";
+    errortext += "should contain configuration information relating to the\n";
+    errortext += "setup of the interface. As this receptionist is not being run\n";
+    errortext += "in collection specific mode the file should reside at\n";
+    errortext += main_cfg_file + ".\n";
+  } else {
+    text_t collect_cfg_file = filename_cat (gsdlhome, "collect", collection, "etc", "collect.cfg");
+    text_t main_collect_cfg_file = filename_cat (gsdlhome, "etc", "collect.cfg");
+    text_t main_cfg_file = filename_cat (gsdlhome, "etc", "main.cfg");
+    errortext += "Either the collect.cfg or main.cfg configuration file could\n";
+    errortext += "not be found. This file should contain configuration information\n";
+    errortext += "relating to the setup of the interface. As this receptionist is\n";
+    errortext += "being run in collection specific mode the file should reside\n";
+    errortext += "at either " + collect_cfg_file + ",\n";
+    errortext += main_collect_cfg_file + " or " + main_cfg_file + ".\n";
+  }
+
+  format_error_string (errorpage, errortext, debug);
+}
+
+
+static void page_errorinit (const text_t &gsdlhome, bool debug, text_t &errorpage) {
+
+  text_t errortext = "An error occurred during the initialisation of the Greenstone Digital\n";
+  errortext += "Library software. It is likely that the software has not been setup\n";
+  errortext += "correctly.\n";
+
+  text_t init_file = filename_cat (gsdlhome, "etc", "initout.txt");
+  char *ifile = init_file.getcstr();
+  ifstream initin (ifile);
+  delete ifile;
+  if (initin) {
+    errortext += "The initialisation error log, " + init_file + ", contains the\n";
+    errortext += "following information:\n\n";
+    if (!debug) errortext += "<pre>\n";
+
+    char c;
+    initin.get(c);
+    while (!initin.eof ()) {
+      errortext.push_back(c);
+      initin.get(c);
+    }
+    
+    if (!debug) errortext += "</pre>\n";
+
+    initin.close();
+
+  } else {
+    errortext += "Please consult " + init_file + " for more information.\n";
+  }
+
+  format_error_string (errorpage, errortext, debug);
+}
+
+static void page_errorparseargs (const text_t &gsdlhome, bool debug, text_t &errorpage) {
+
+  text_t errortext = "An error occurred during the parsing of the cgi arguments.\n";
+
+  text_t error_file = filename_cat (gsdlhome, "etc", "errout.txt");
+  char *efile = error_file.getcstr();
+  ifstream errin (efile);
+  delete efile;
+  if (errin) {
+    errortext += "The error log, " + error_file + ", contains the\n";
+    errortext += "following information:\n\n";
+    if (!debug) errortext += "<pre>\n";
+
+    char c;
+    errin.get(c);
+    while (!errin.eof ()) {
+      errortext.push_back(c);
+      errin.get(c);
+    }
+    if (!debug) errortext += "</pre>\n";
+    errin.close();
+
+  } else {
+    errortext += "Please consult " + error_file + " for more information.\n";
+  }
+
+  format_error_string (errorpage, errortext, debug);
+}
+
+static void page_errorcgipage (const text_t &gsdlhome, bool debug, text_t &errorpage) {
+
+  text_t errortext = "An error occurred during the construction of the cgi page.\n";
+
+  text_t error_file = filename_cat (gsdlhome, "etc", "errout.txt");
+  char *efile = error_file.getcstr();
+  ifstream errin (efile);
+  delete efile;
+  if (errin) {
+    errortext += "The error log, " + error_file + ", contains the\n";
+    errortext += "following information:\n\n";
+    if (!debug) errortext += "<pre>\n";
+
+    char c;
+    errin.get(c);
+    while (!errin.eof ()) {
+      errortext.push_back(c);
+      errin.get(c);
+    }
+    if (!debug) errortext += "</pre>\n";
+    errin.close();
+
+  } else {
+    errortext += "Please consult " + error_file + " for more information.\n";
+  }
+
+  format_error_string (errorpage, errortext, debug);
+}
+
+static void print_debug_info (receptionist &recpt) {
+
+  outconvertclass text_t2ascii;
+  recptconf configinfo = recpt.get_configinfo ();
+  text_t etc_dir = filename_cat (configinfo.gsdlhome, "etc");
+
+  cout << "\n";
+  cout << text_t2ascii
+       << "------------------------------------------------------------\n"
+       << "Configuration and initialization completed successfully.\n"
+       << "  Note that more debug information may be available in the\n"
+       << "  initialization and error logs initout.txt and errout.txt\n"
+       << "  in " << etc_dir << ".\n"
+       << "------------------------------------------------------------\n\n";
+
+  bool colspec = false;
+  if (configinfo.collection.empty()) {
+    cout << "Receptionist is running in \"general\" (i.e. not \"collection\n"
+	 << "specific\") mode.\n";
+  } else {
+    cout << text_t2ascii 
+	 << "Receptionist is running in \"collection specific\" mode.\n"
+	 << "  collection=" << configinfo.collection << "\n"
+	 << "  collection directory=" << configinfo.collectdir << "\n";
+    colspec = true;
+  }
+  
+  cout << text_t2ascii << "gsdlhome=" << configinfo.gsdlhome << "\n";
+  if (!configinfo.gdbmhome.empty())
+    cout << text_t2ascii << "gdbmhome=" << configinfo.gdbmhome << "\n";
+  cout << text_t2ascii << "httpprefix=" << configinfo.httpprefix << "\n";
+  cout << text_t2ascii << "httpimg=" << configinfo.httpimg << "\n";
+  cout << text_t2ascii << "gwcgi=" << configinfo.gwcgi << "\n"
+       << "  Note that unless gwcgi has been set from a configuration\n"
+       << "  file it is dependent on environment variables set by your\n"
+       << "  webserver. Therefore it may not have the same value when run\n"
+       << "  from the command line as it would be when run from your\n"
+       << "  web server.\n";
+  if (configinfo.usecookies) 
+    cout << "cookies are enabled\n";
+  else 
+    cout << "cookies are disabled\n";
+  if (configinfo.logcgiargs) 
+    cout << "logging is enabled\n";
+  else 
+    cout << "logging is disabled\n";
+  cout << "------------------------------------------------------------\n\n";
+
+  text_tset::const_iterator this_mfile = configinfo.macrofiles.begin();
+  text_tset::const_iterator end_mfile = configinfo.macrofiles.end();
+  cout << "Macro Files:\n"
+       << "------------\n";
+  text_t mfile;
+  bool found;
+  while (this_mfile != end_mfile) {
+    cout << text_t2ascii << *this_mfile;
+    int spaces = (22 - (*this_mfile).size());
+    if (spaces < 2) spaces = 2;
+    text_t outspaces;
+    for (int i = 0; i < spaces; i++) outspaces.push_back (' ');
+    cout << text_t2ascii << outspaces;
+
+    found = false;
+    if (colspec) {
+      // collection specific - try collectdir/macros first
+      mfile = filename_cat (configinfo.collectdir, "macros", *this_mfile);
+      if (file_exists (mfile)) {
+	cout << text_t2ascii << "found (" << mfile << ")\n";
+	found = true;
+      }
+    }
+ 
+    if (!found) {
+      // try main macro directory
+      mfile = filename_cat (configinfo.gsdlhome, "macros", *this_mfile);
+      if (file_exists (mfile)) {
+	cout << text_t2ascii << "found (" << mfile << ")\n";
+	found = true;
+      }
+    }
+
+    if (!found)
+      cout << text_t2ascii << "NOT FOUND\n";
+
+    this_mfile ++;
+  }
+
+  cout << "------------------------------------------------------------\n\n"
+       << "Collections:\n"
+       << "------------\n"
+       << "  Note that collections will only appear as \"running\" if\n"
+       << "  their build.cfg files exist, are readable, contain a valid\n"
+       << "  builddate field (i.e. > 0), and are in the collection's\n"
+       << "  index directory (i.e. NOT the building directory)\n\n";
+
+  recptprotolistclass *protos = recpt.get_recptprotolist_ptr();
+  recptprotolistclass::iterator rprotolist_here = protos->begin();
+  recptprotolistclass::iterator rprotolist_end = protos->end();
+  bool found_valid_col = false;
+  while (rprotolist_here != rprotolist_end) {
+    if ((*rprotolist_here).p != NULL) {
+
+      text_tarray collist;
+      comerror_t err;
+      (*rprotolist_here).p->get_collection_list (collist, err, cerr);
+      if (err == noError) {
+	text_tarray::iterator collist_here = collist.begin();
+	text_tarray::iterator collist_end = collist.end();
+
+	while (collist_here != collist_end) {
+	  
+	  cout << text_t2ascii << *collist_here;
+
+	  int spaces = (22 - (*collist_here).size());
+	  if (spaces < 2) spaces = 2;
+	  text_t outspaces;
+	  for (int i = 0; i < spaces; i++) outspaces.push_back (' ');
+	  cout << text_t2ascii << outspaces;
+
+	  ColInfoResponse_t *cinfo = recpt.get_collectinfo_ptr ((*rprotolist_here).p, *collist_here, cerr);
+	  if (cinfo != NULL) {
+	    if (cinfo->isPublic) cout << "public ";
+	    else cout << "private";
+
+	    if (cinfo->buildDate > 0) {
+	      cout << "   running    ";
+	      found_valid_col = true;
+	    } else {
+	      cout << "   not running";
+	    }
+	  }
+
+	  cout << "\n";
+
+	  collist_here ++;
+	}
+      }
+    }
+    rprotolist_here ++;
+  }
+  
+  if (!found_valid_col) {
+    cout << "WARNING: No \"running\" collections were found. You need to\n";
+    cout << "         build one of the above collections\n";
+  }
+
+  cout << "\n------------------------------------------------------------\n";
+  cout << "------------------------------------------------------------\n\n";
+  cout << "receptionist running in command line debug mode\n";
+  cout << "enter cgi arguments as name=value pairs (e.g. 'a=p&p=home'):\n";
+
+}
+
+// cgiwrapper does everything necessary to output a page
+// using the cgi protocol. If this is being run for a particular
+// collection then "collection" should be set, otherwise it
+// should equal "".
+void cgiwrapper (receptionist &recpt, text_t collection) {
+  
+  int numrequests = 0;
+  bool debug = false;
+  recptconf configinfo = recpt.get_configinfo ();
+
+  // find out whether this is being run as a cgi-script
+  // or a fastcgi script
+#ifdef USE_FASTCGI
+  fcgistreambuf outbuf;
+  int isfastcgi = !FCGX_IsCGI();
+  FCGX_Stream *fcgiin, *fcgiout, *fcgierr;
+  FCGX_ParamArray fcgienvp;
+#else
+  int isfastcgi = 0;
+#endif
+
+  // get the query string if it is not being run as a fastcgi
+  // script
+  text_t argstr = "";
+  cgiargsclass args;
+  char *aURIStr;
+  if (!isfastcgi) {
+    char *request_method_str = getenv("REQUEST_METHOD");
+    char *content_length_str = getenv("CONTENT_LENGTH");
+    if (request_method_str != NULL && strcmp(request_method_str, "POST") == 0 &&
+	content_length_str != NULL)  {
+      // POST form data
+      int content_length = text_t(content_length_str).getint();
+      if (content_length > 0) {
+	char c;
+	do {
+	  cin.get(c);
+	  if (cin.eof()) break;
+	  argstr.push_back (c);
+	  content_length--;
+	} while (content_length > 0);
+      }
+      
+    } else {
+      aURIStr = getenv("QUERY_STRING");
+      if ((request_method_str != NULL && strcmp(request_method_str, "GET") == 0)
+	  || aURIStr != NULL) {
+	// GET form data
+	if (aURIStr != NULL) argstr = aURIStr;
+      } else {
+	// debugging from command line
+	debug = true;
+      }
+    }
+  }
+
+  if (debug) {
+    cout << "Configuring Greenstone...\n";
+    cout << flush;
+  }
+
+  // init stuff - we can't output error pages directly with
+  // fastcgi so the pages are stored until we can output them
+  text_t errorpage;
+  outconvertclass text_t2ascii;
+
+  // set defaults
+  int maxrequests = 10000;
+  recpt.configure ("collection", collection);
+  recpt.configure ("httpimg", "/gsdl/images");
+  char *script_name = getenv("SCRIPT_NAME");
+  if (script_name != NULL) recpt.configure("gwcgi", script_name);
+  else recpt.configure("gwcgi", "/cgi-bin/gw");
+
+  // read in the configuration files.
+  text_t gsdlhome;
+  if (!site_cfg_read (recpt, gsdlhome, maxrequests)) {
+    // couldn't find the site configuration file
+    page_errorsitecfg (errorpage, debug, 0);
+  } else if (gsdlhome.empty()) {
+    // no gsdlhome in gsdlsite.cfg
+    page_errorsitecfg (errorpage, debug, 1);
+  } else if (!main_cfg_read (recpt, gsdlhome, collection)) {
+    // couldn't find the main configuration file
+    page_errormaincfg (gsdlhome, collection, debug, errorpage);
+  } else  if (configinfo.collectinfo.empty()) {
+    // don't have any collections
+    page_errorcollect (gsdlhome, errorpage, debug);
+  }
+
+  if (errorpage.empty()) {
+
+    // initialise the library software
+    if (debug) {
+      cout << "Initializing...\n";
+      cout << flush;
+    }
+
+    text_t init_file = filename_cat (gsdlhome, "etc", "initout.txt");
+    char *iout = init_file.getcstr();
+    ofstream initout (iout);
+    delete iout;
+    if (!recpt.init(initout)) {
+      // an error occurred during the initialisation
+      initout.close();
+      page_errorinit(gsdlhome, debug, errorpage);
+    }
+    initout.close();
+  }
+
+  if (debug && errorpage.empty()) {
+    // get query string from command line
+    print_debug_info (recpt);
+    char cinURIStr[1024];
+    cin.get(cinURIStr, 1024);
+    argstr = cinURIStr;
+  }
+
+  // cgi scripts only deal with one request
+  if (!isfastcgi) maxrequests = 1;
+
+  // Page-request loop. If this is not being run as a fastcgi
+  // process then only one request will be processed and then
+  // the process will exit.
+  while (numrequests < maxrequests) {
+#ifdef USE_FASTCGI
+    if (isfastcgi) {
+      if (FCGX_Accept(&fcgiin, &fcgiout, &fcgierr, &fcgienvp) < 0) break;
+
+      char *request_method_str = FCGX_GetParam ("REQUEST_METHOD", fcgienvp);
+      char *content_length_str = FCGX_GetParam ("CONTENT_LENGTH", fcgienvp);
+
+      if (request_method_str != NULL && strcmp(request_method_str, "POST") == 0 &&
+	  content_length_str != NULL)  {
+	// POST form data
+	int content_length = text_t(content_length_str).getint();
+	if (content_length > 0) {
+	  argstr.clear();
+	  int c;
+	  do {
+	    c = FCGX_GetChar (fcgiin);
+	    if (c < 0) break;
+	    argstr.push_back (c);
+	    content_length--;
+	  } while (content_length > 0);
+	}
+
+      } else {
+	// GET form data
+	aURIStr = FCGX_GetParam("QUERY_STRING", fcgienvp);
+	if (aURIStr != NULL) argstr = aURIStr;
+	else argstr = "";
+      }
+    }
+#endif
+
+    // get output streams ready
+#ifdef USE_FASTCGI
+    outbuf.fcgisbreset ();
+    if (isfastcgi) outbuf.set_fcgx_stream (fcgiout);
+    else outbuf.set_other_ostream (&cout);
+    ostream pageout (&outbuf);
+#else
+#define pageout cout
+#endif
+
+    // if using fastcgi we'll load environment into a map,
+    // otherwise simply pass empty map (can't get environment
+    // variables using getenv() while using FCGX versions
+    // of fastcgi - at least I can't ;-) - Stefan)
+    text_tmap fastcgienv;
+#ifdef USE_FASTCGI
+    if (isfastcgi) {
+      for(; *fcgienvp != NULL; fcgienvp++) {
+	text_t fvalue = *fcgienvp;
+	text_t::const_iterator begin = fvalue.begin();
+	text_t::const_iterator end = fvalue.end();
+	text_t::const_iterator equals_sign = findchar (begin, end, '=');
+	if (equals_sign != end)
+	  fastcgienv[substr(begin, equals_sign)] = substr(equals_sign+1, end);
+      }
+    }
+#endif
+
+    // temporarily need to configure gwcgi here when using fastcgi as I can't
+    // get it to pass the SCRIPT_NAME environment variable to the initial 
+    // environment (if anyone can work out how to do this using the apache 
+    // server, let me know). Note that this overrides the gwcgi field in 
+    // site.cfg (which it shouldn't do) but I can't at present set gwcgi 
+    // from site.cfg as I have old receptionists laying around that wouldn't
+    // appreciate it. The following 5 lines of code should be deleted once
+    // I either a: get the server to pass SCRIPT_NAME at initialization
+    // time or b: convert all the collections using old receptionists over
+    // to this version and uncomment gwcgi in the site.cfg file -- Stefan.
+#ifdef USE_FASTCGI
+    if (isfastcgi) {
+      recpt.configure("gwcgi", fastcgienv["SCRIPT_NAME"]);
+    }
+#endif
+
+
+    if (errorpage.empty()) {
+      text_t error_file = filename_cat (gsdlhome, "etc", "errout.txt");
+      char *eout = error_file.getcstr();
+      ofstream errout (eout, ios::app);
+      delete eout;
+      // note that the following line appears to cause a runtime 
+      // error using debug versions of VC++ 6.0 (on windows)
+      cerr = errout;
+    
+      // parse the cgi arguments and produce the resulting page if there
+      // has been no errors so far
+      if (!recpt.parse_cgi_args (argstr, args, errout, fastcgienv)) {
+	errout.close ();
+	page_errorparseargs(gsdlhome, debug, errorpage);
+      } else {
+	if (!recpt.produce_cgi_page (args, pageout, errout, fastcgienv)) {
+	  errout.close ();
+	  page_errorcgipage(gsdlhome, debug, errorpage);
+	}
+	recpt.log_cgi_args (args, errout, fastcgienv);
+	errout.close ();
+      }
+    }
+    // there was an error, output the error page
+    if (!errorpage.empty()) {
+      pageout << text_t2ascii << errorpage;
+      errorpage.clear();
+      numrequests = maxrequests; // make this the last page
+    }
+    pageout << flush;
+    
+    // finish with the output streams
+#ifdef USE_FASTCGI
+    if (isfastcgi) FCGX_Finish();
+#endif
+
+    numrequests++;
+  }
+
+  return;
+}
Index: /main/tags/2.25/gsdl/src/recpt/cgiwrapper.h
===================================================================
--- /main/tags/2.25/gsdl/src/recpt/cgiwrapper.h	(revision 21064)
+++ /main/tags/2.25/gsdl/src/recpt/cgiwrapper.h	(revision 21064)
@@ -0,0 +1,40 @@
+/**********************************************************************
+ *
+ * cgiwrapper.h -- 
+ * Copyright (C) 1999  The New Zealand Digital Library Project
+ *
+ * A component of the Greenstone digital library software
+ * from the New Zealand Digital Library Project at the
+ * University of Waikato, New Zealand.
+ *
+ * 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.
+ *
+ *********************************************************************/
+
+
+#ifndef CGIWRAPPER_H
+#define CGIWRAPPER_H
+
+
+#include "receptionist.h"
+
+// cgiwrapper does everything necessary to output a page
+// using the cgi protocol. If this is being run for a particular
+// collection then "collection" should be set, otherwise it
+// should equal "".
+void cgiwrapper (receptionist &recpt, text_t collection);
+
+
+#endif
Index: /main/tags/2.25/gsdl/src/recpt/comproto.asn
===================================================================
--- /main/tags/2.25/gsdl/src/recpt/comproto.asn	(revision 21064)
+++ /main/tags/2.25/gsdl/src/recpt/comproto.asn	(revision 21064)
@@ -0,0 +1,376 @@
+-- The protocol data unit (PDU) is the
+-- message that is transmitted between receptionists and
+-- collectionservers (colservers?).
+--
+-- Comments in ASN.1 start with two dashes and continue to the end
+-- of a line (or to the next two dashes, whichever is first).
+-- 
+-- Z39.50 has inspired much of this but I have tried to keep
+-- it simple. Its hard to tell if I have succeeded ;-)
+
+
+GSDL-APDU DEFINITIONS ::=
+BEGIN
+
+
+-- PDU is the basic message type. Note: in ASN.1 the
+-- field name comes first and the field type second (opposite
+-- to C). Ignore the numbers in the square brackets (e.g. [0]),
+-- they're just tags to disambiguate certain circumstances and to
+-- make the protocol easier to extend. The keyword 'IMPLICIT' just
+-- makes the tags a little more efficient.
+--
+-- A SEQUENCE is a list of fields where the order is important
+
+PDU ::= SEQUENCE {
+  header  StandardHeader,
+  message Message
+}
+
+
+-- ????? Is there anything else we want in the header ?????
+--
+-- Anonymous transactions should leave out the idAuthentication field
+
+StandardHeader ::= SEQUENCE {
+  protocolVersion       [0] IMPLICIT INTEGER,
+  idAuthentication      [1] IMPLICIT IdAuthentication OPTIONAL
+}
+
+IdAuthentication ::= SEQUENCE {
+  userId   GeneralString,
+  groupId  GeneralString,
+  password GeneralString
+}
+
+
+-- A CHOICE is like a union in C.
+-- 
+-- Short forms: Auth (Authority), Mir (Mirror), Col (Collection),
+--   Doc (Document), Info (Information)
+
+Message ::= CHOICE {
+  -- General
+  error                      [0]  IMPLICIT Error,
+  pingRequest                [1]  IMPLICIT PingRequest,
+  pingResponse               [2]  IMPLICIT PingResponse,
+
+  -- Authority
+--  authListRequest            [12] IMPLICIT AuthListRequest,
+--  authListResponse           [13] IMPLICIT AuthListResponse,
+--  editAuthListRequest        [14] IMPLICIT EditAuthListRequest,
+--  editAuthListResponse       [15] IMPLICIT EditAuthListResponse,
+
+  -- an authority mirror is a mirror of THIS authority
+--  authMirListRequest         [16] IMPLICIT AuthMirListRequest,
+--  authMirListResponse        [17] IMPLICIT AuthMirListResponse,
+--  editAuthMirListRequest     [18] IMPLICIT EditAuthMirListRequest,
+--  editAuthMirListResponse    [19] IMPLICIT EditAuthMirListResponse,
+
+  colListRequest             [20] IMPLICIT ColListRequest,
+  colListResponse            [21] IMPLICIT ColListResponse,
+--  editColListRequest         [22] IMPLICIT EditColListRequest,
+--  editColListResponse        [23] IMPLICIT EditColListResponse,
+
+--  colMirListRequest          [24] IMPLICIT ColMirListRequest,
+--  colMirListResponse         [25] IMPLICIT ColMirListResponse, 
+--  editColMirListRequest      [26] IMPLICIT EditColMirListRequest, 
+--  editColMirListResponse     [27] IMPLICIT EditColMirListResponse,
+
+  -- Collection
+  colInfoRequest             [40] IMPLICIT ColInfoRequest,
+  colInfoResponse            [41] IMPLICIT ColInfoResponse,
+
+  -- Document
+  documentRequest            [52] IMPLICIT DocumentRequest,
+  documentResponse           [53] IMPLICIT DocumentResponse,
+
+  -- Access (searching, browsing, and metadata information)
+  infoFiltersRequest         [60] IMPLICIT InfoFiltersRequest,
+  infoFiltersResponse        [61] IMPLICIT InfoFiltersResponse,
+  infoFilterOptionsRequest   [62] IMPLICIT InfoFilterOptionsRequest,
+  infoFilterOptionsResponse  [63] IMPLICIT InfoFilterOptionsResponse,
+  filterRequest              [64] IMPLICIT FilterRequest,
+  filterResponse             [65] IMPLICIT FilterResponse
+}
+
+
+
+-- ------------------------------
+-- GENERAL
+-- ------------------------------
+
+
+-- The error list is not complete yet ...
+
+Error ::= ENUMERATED {
+  authenticationFailure(0), protocolError(1), systemProblem(2)
+}
+
+
+PingRequest ::= SEQUENCE {
+}
+
+PingResponse ::= SEQUENCE {
+}
+
+
+
+-- ------------------------------
+-- AUTHORITY
+-- ------------------------------
+
+
+-- Support for subscription is optional for both the clients and
+-- the servers. It is recomended that it is not implemented yet
+-- for simplicity.
+
+-- AuthListRequest ::= SEQUENCE {
+-- }
+
+-- AuthListResponse ::= SEQUENCE {
+--   authList  [1] IMPLICIT StringSet
+-- }
+
+
+-- EditAuthListRequest ::= SEQUENCE {
+--   editAction EditAction,
+--   authority  GeneralString
+-- }
+
+-- EditAuthListResponse ::= SEQUENCE {
+-- }
+
+
+-- AuthMirListRequest ::= SEQUENCE {
+--   limitNumber [1] IMPLICIT INTEGER OPTIONAL,
+--   limitDomain [2] IMPLICIT GeneralString OPTIONAL
+-- }
+
+-- AuthMirListResponse ::= SEQUENCE {
+--   authMirList [1] IMPLICIT HostPortSet
+-- }
+
+
+-- EditAuthMirListRequest ::= SEQUENCE {
+--   editAction EditAction,
+--   authMir    HostPort
+-- }
+
+-- EditAuthMirListResponse ::= SEQUENCE {
+-- }
+
+
+ColListRequest ::= SEQUENCE {
+}
+
+ColListResponse ::= SEQUENCE {
+  colList   [1] IMPLICIT ShortColInfoSet
+}
+
+
+-- EditColListRequest ::= SEQUENCE {
+--   editAction EditAction,
+--   colInfo    ShortColInfo
+-- }
+
+-- EditColListResponse ::= SEQUENCE {
+-- }
+
+
+-- ColMirListRequest ::= SEQUENCE {
+--   limitNumber [1] IMPLICIT INTEGER OPTIONAL,
+--   limitDomain [2] IMPLICIT GeneralString OPTIONAL
+-- }
+
+-- ColMirListResponse ::= SEQUENCE {
+--   colMirList [1] IMPLICIT ShortColInfoSet
+-- }
+
+
+-- EditColMirListRequest ::= SEQUENCE {
+--   editAction EditAction,
+--   colMirInfo ShortColInfo
+-- }
+
+-- EditColMirListResponse ::= SEQUENCE {
+-- }
+
+
+
+
+-- ------------------------------
+-- COLLECTION
+-- ------------------------------
+
+
+ColInfoRequest ::= SEQUENCE {
+}
+
+ColInfoResponse ::= SEQUENCE {
+  shortInfo   [0] IMPLICIT ShortCollectionInfo,
+  isPublic    [2] IMPLICIT BOOLEAN,    -- whether has anonymous access
+  isBeta      [3] IMPLICIT BOOLEAN,    -- beta if still under development
+  builddate   [4] IMPLICIT GeneralizedTime,
+  languages   [5] IMPLICIT StringSet,  -- languages in the collection
+  numDocs     [6] IMPLICIT INTEGER,
+  numWords    [7] IMPLICIT INTEGER OPTIONAL,
+  numBytes    [8] IMPLICIT INTEGER OPTIONAL
+}
+
+
+
+-- ------------------------------
+-- DOCUMENT
+-- ------------------------------
+
+
+
+DocumentRequest ::= SEQUENCE {
+  OID       GeneralString,
+  docType   GeneralString,
+  docFormat GeneralString
+}
+
+DocumentResponse ::= SEQUENCE {
+  doc OCTET STRING
+}
+
+
+-- ------------------------------
+-- ACCESS (SEARCH AND BROWSE)
+-- ------------------------------
+
+
+-- filter options which might be supported for the QueryFilter
+--
+-- onePerQuery StartResults   integer
+-- onePerQuery EndResults     integer
+-- onePerQuery QueryType      enumerated (boolean, ranked)
+-- onePerTerm  Term           string ???
+-- onePerTerm  Casefold       boolean
+-- onePerTerm  Stem           boolean
+-- onePerTerm  Index          enumerated
+-- onePerTerm  Subcollection  enumerated
+--
+-- filter options which might be supported for the BrowseFilter
+--
+-- onePerQuery StartResults   integer
+-- onePerQuery EndResults     integer
+-- onePerQuery ParentNode     string ("" will return the browsing available)
+--
+-- The NullFilter always returns the set it was given, it doesn't have
+-- any options
+
+InfoFiltersRequest ::= SEQUENCE {
+}
+
+InfoFiltersResponse ::= SEQUENCE {
+  filterNames StringSet
+}
+
+InfoFilterOptionsRequest ::= SEQUENCE {
+  filterName GeneralString
+}
+
+InfoFilterOptionsResponse ::= SEQUENCE {
+  filterOptions SET OF FilterOption
+}
+
+FilterOption ::= SEQUENCE {
+  name         GeneralString,
+  type         ENUMERATED {booleant(0), integert(1), enumeratedt(2), stringt(3)},
+  repeatable   ENUMERATED {onePerQuery(0), onePerTerm(1), nPerTerm(2)},
+  defaultValue GeneralString,
+  -- the interpretation of the validValues depends on the type
+  -- for boolean: the first value is the false value, the second is true value
+  -- for integer: the first value is the minimum, the second the maximum
+  -- for enumerated: all values a listed
+  -- for string: this value is ignored
+  validValues  StringSequence
+}
+
+
+-- Terms are presented in the same order that they are requested,
+-- any information relating to the terms is in reference to the
+-- index specified for that term.
+-- Metadata is presented in the same order that it is requested.
+
+FilterRequest ::= SEQUENCE {
+  filterName          [0] GeneralString,
+  filterOptions       [1] IMPLICIT SEQUENCE OF OptionValue,
+  docSet              [2] IMPLICIT StringSequence, -- the OID "" represents everything
+  filterResultOptions [3] IMPLICIT BIT STRING {termFreq(0), matchTerms(1), OID(2), 
+                                               subCol(3), ranking(4), docFreq(5), 
+                                               metadata(6)}
+
+  -- the next set of options are for the metadata request, 
+  -- they can be left blank if metadata is not wanted
+  requestParams       [4] IMPLICIT GeneralString, -- used to negotiate the metadata content
+  refParams           [5] IMPLICIT GeneralString, -- used to decide whether to return a 
+                                                  -- reference to the data or the actual data
+  fields              [6] IMPLICIT StringSequence
+}
+
+OptionValue ::= SEQUENCE {
+  name  GeneralString,
+  value GeneralString
+}
+
+FilterResponse ::= SEQUENCE {
+  numDocs   [0] IMPLICIT INTEGER,
+  isApprox  [1] IMPLICIT BOOLEAN,                  -- whether numDocs is approximate
+  termInfo  [2] IMPLICIT SEQUENCE OF TermInfo,     -- empty if not required
+  docInfo   [3] IMPLICIT SEQUENCE OF ResultDocInfo -- empty if not required
+}
+
+TermInfo ::= SEQUENCE {
+  term       [0] GeneralString,
+  freq       [1] IMPLICIT INTEGER,       -- 0 if not requested
+  matchTerms [2] IMPLICIT StringSequence -- empty if not requested
+}
+
+ResultDocInfo ::= SEQUENCE {
+  OID      [0] IMPLICIT GeneralString,
+  ranking  [1] IMPLICIT INTEGER,             -- 0 if not requested, range 0-10000
+  docFreq  [2] IMPLICIT SEQUENCE OF INTEGER, -- empty if not requested
+  metadata [3] IMPLICIT SEQUENCE OF MetadataInfo
+}
+
+
+MetadataInfo ::= SEQUENCE {
+  params  [0] IMPLICIT GeneralString,
+  isRef   [1] IMPLICIT BOOLEAN,
+  field   [3] IMPLICIT GeneralString,
+  value   [4] IMPLICIT GeneralString
+}
+
+
+-- ------------------------------
+-- Useful Types
+-- ------------------------------
+
+-- HostPortSet ::= SET OF HostPort
+
+-- HostPort ::= SEQUENCE {
+--   host [0] IMPLICIT GeneralString,
+--   port [1] IMPLICIT INTEGER
+-- }
+
+ShortColInfoSet ::= SET OF ShortColInfo
+
+ShortColInfo ::= SEQUENCE {
+  name GeneralString,
+  host GeneralString,
+  port INTEGER
+}
+
+-- EditAction ::= ENUMERATED {
+--   update(0), delete(1)
+-- }
+
+StringSequence ::= SEQUENCE OF GeneralString
+StringSet ::= SET OF GeneralString
+
+
+END
Index: /main/tags/2.25/gsdl/src/recpt/comtypes.cpp
===================================================================
--- /main/tags/2.25/gsdl/src/recpt/comtypes.cpp	(revision 21064)
+++ /main/tags/2.25/gsdl/src/recpt/comtypes.cpp	(revision 21064)
@@ -0,0 +1,259 @@
+/**********************************************************************
+ *
+ * comtypes.cpp -- 
+ * Copyright (C) 1999  The New Zealand Digital Library Project
+ *
+ * A component of the Greenstone digital library software
+ * from the New Zealand Digital Library Project at the
+ * University of Waikato, New Zealand.
+ *
+ * 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.
+ *
+ *********************************************************************/
+
+#include "comtypes.h"
+
+
+text_t get_comerror_string (comerror_t err) {
+  if (err == noError) return "no error";
+  else if (err == authenticationFailure) return "authentication failure";
+  else if (err == protocolError) return "protocol error";
+  else if (err == configurationError) return "configuration error";
+  else if (err == systemProblem) return "system problem";
+
+  return "unknown problem";
+}
+
+
+void ShortColInfo_t::clear() {
+  name.clear();
+  host.clear();
+  port = 0;
+}
+
+void ColInfoResponse_t::clear () {
+  shortInfo.clear();
+  isPublic=false;
+  isBeta=false;
+  languages.erase(languages.begin(), languages.end());
+  ccsCols.erase(ccsCols.begin(), ccsCols.end());
+  buildDate=0;
+  buildType.clear();
+  numDocs=0;
+  numSections=0;
+  numWords=0;
+  numBytes=0;
+  format.erase(format.begin(), format.end());
+  building.erase(format.begin(), format.end());
+  receptionist.clear();
+}
+
+void InfoFiltersResponse_t::clear () {
+  filterNames.erase(filterNames.begin(), filterNames.end());
+}
+
+
+void InfoFilterOptionsRequest_t::clear () {
+  filterName.clear();
+}
+
+
+void FilterOption_t::clear () {
+  name.clear();
+  type = booleant;
+  repeatable = onePerQuery;
+  defaultValue.clear();
+  validValues.erase(validValues.begin(), validValues.end());
+}
+
+void FilterOption_t::check_defaultValue () {
+  text_tarray::iterator here, end;
+
+  // how the default is interpreted depends on the option type
+  switch (type) {
+  case booleant: 
+  case enumeratedt: // has to be one of the validValues
+    here = validValues.begin ();
+    end = validValues.end ();
+    while (here != end) {
+      if (*here == defaultValue) return;
+      here++;
+    }
+    
+    break;
+
+  case integert: // has to be in the validValues range
+    if ((validValues.size() >= 2) &&
+	(validValues[0].getint() <= defaultValue.getint()) &&
+	(validValues[1].getint() >= defaultValue.getint()))
+      return;
+    break;
+
+  case stringt: // any value is valid
+    return; 
+  }
+
+  // did not find the defaultValue
+  if (validValues.empty()) defaultValue.clear();
+  else defaultValue = validValues[0];
+}
+
+
+bool operator==(const FilterOption_t &x, const FilterOption_t &y) {
+  return ((x.name == y.name) &&
+	  (x.type == y.type) &&
+	  (x.repeatable == y.repeatable) &&
+	  (x.defaultValue == y.defaultValue) &&
+	  (x.validValues == y.validValues));
+}
+
+bool operator<(const FilterOption_t &x, const FilterOption_t &y) {
+  return ((x.name < y.name) ||
+	  ((x.name == y.name) &&
+	   ((x.type < y.type) ||
+	    ((x.type == y.type) &&
+	     ((x.repeatable < y.repeatable) ||
+	      ((x.repeatable == y.repeatable) &&
+	       ((x.defaultValue < y.defaultValue) ||
+		((x.defaultValue == y.defaultValue) &&
+		 (x.validValues < y.validValues)))))))));
+}
+
+
+
+void InfoFilterOptionsResponse_t::clear () {
+  filterOptions.erase(filterOptions.begin(), filterOptions.end());
+}
+
+
+void OptionValue_t::clear () {
+  name.clear();
+  value.clear();
+}
+
+
+void FilterRequest_t::clear () {
+  filterName.clear();
+  filterOptions.erase(filterOptions.begin(), filterOptions.end());
+  docSet.erase(docSet.begin(), docSet.end());
+  filterResultOptions = 0;
+  requestParams.clear();
+  refParams.clear();
+  fields.erase(fields.begin(), fields.end());
+  getParents = false;
+}
+
+
+void TermInfo_t::clear () {
+  term.clear();
+  freq = 0;
+  matchTerms.erase (matchTerms.begin(), matchTerms.end());
+}
+
+
+void MetadataInfo_t::clear () {
+  params.clear();
+  isRef = false;
+  values.erase(values.begin(), values.end());
+  if (parent != NULL) {
+    delete parent;
+    parent = NULL;
+  }
+}
+
+MetadataInfo_t::MetadataInfo_t () {parent=NULL;clear();}
+
+// copy constructor
+MetadataInfo_t::MetadataInfo_t (const MetadataInfo_t &x) {
+  params = x.params;
+  isRef = x.isRef;
+  values = x.values;
+  if (x.parent == NULL) parent = NULL;
+  else {
+    parent = new MetadataInfo_t ();
+    *parent = *(x.parent);
+  }
+}
+
+MetadataInfo_t::~MetadataInfo_t () {
+  if (parent != NULL) {
+    delete parent;
+    parent = NULL;
+  }
+}
+
+MetadataInfo_t &MetadataInfo_t::operator=(const MetadataInfo_t &x) {
+  if (&x != this) {
+    params = x.params;
+    isRef = x.isRef;
+    values = x.values;
+    if (x.parent == NULL) parent = NULL;
+    else {
+      parent = new MetadataInfo_t ();
+      *parent = *(x.parent);
+    }
+  }
+  return *this;
+}
+
+void ResultDocInfo_t::clear () {
+  OID.clear ();
+  ranking = 0;
+  result_num = 0;
+  num_terms_matched = 0;
+  num_phrase_match = 0;
+  docFreq.erase(docFreq.begin(), docFreq.end());
+  metadata.erase(metadata.begin(), metadata.end());
+  classifier_metadata_type.erase(classifier_metadata_type.begin(), 
+				 classifier_metadata_type.end());
+  classifier_metadata_offset = 0;
+  
+}
+
+ResultDocInfo_t &ResultDocInfo_t::operator=(const ResultDocInfo_t &x) {
+  OID = x.OID; 
+  ranking = x.ranking;
+  result_num = x.result_num;
+  num_terms_matched = x.num_terms_matched;
+  num_phrase_match = x.num_phrase_match;
+  docFreq = x.docFreq; 
+  metadata = x.metadata;
+  return *this;
+}
+
+void FilterResponse_t::clear () {
+  numDocs = 0;
+  isApprox = Exact;
+  termInfo.erase (termInfo.begin(), termInfo.end());
+  docInfo.erase (docInfo.begin(), docInfo.end());
+}
+
+FilterResponse_t &FilterResponse_t::operator=(const FilterResponse_t &x) {
+  numDocs = x.numDocs;
+  isApprox = x.isApprox;
+  termInfo = x.termInfo;
+  docInfo = x.docInfo;
+  return *this;
+}
+
+void DocumentRequest_t::clear () {
+  OID.clear();
+  docType.clear();
+  docFormat.clear();
+}
+
+void DocumentResponse_t::clear () {
+  doc.clear();
+}
Index: /main/tags/2.25/gsdl/src/recpt/comtypes.h
===================================================================
--- /main/tags/2.25/gsdl/src/recpt/comtypes.h	(revision 21064)
+++ /main/tags/2.25/gsdl/src/recpt/comtypes.h	(revision 21064)
@@ -0,0 +1,365 @@
+/**********************************************************************
+ *
+ * comtypes.h -- 
+ * Copyright (C) 1999  The New Zealand Digital Library Project
+ *
+ * A component of the Greenstone digital library software
+ * from the New Zealand Digital Library Project at the
+ * University of Waikato, New Zealand.
+ *
+ * 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.
+ *
+ *********************************************************************/
+
+
+#ifndef COMTYPES_H
+#define COMTYPES_H
+
+#include "gsdlconf.h"
+#include "text_t.h"
+
+#if defined(GSDL_USE_OBJECTSPACE)
+#  include <ospace\std\vector>
+#  include <ospace\std\list>
+#  include <ospace\std\map>
+#elif defined(GSDL_USE_STL_H)
+#  include <vector.h>
+#  include <list.h>
+#  include <map.h>
+#else
+#  include <vector>
+#  include <list>
+#  include <map>
+#endif
+
+
+enum comerror_t {noError, authenticationFailure, protocolError, 
+		 configurationError, systemProblem};
+text_t get_comerror_string (comerror_t err);
+
+// ShortColInfo ::= SEQUENCE {
+//   name GeneralString,
+//   host GeneralString,
+//   port INTEGER
+// }
+struct ShortColInfo_t {
+  void clear ();
+  ShortColInfo_t () {clear();}
+
+  text_t name;
+  text_t host;
+  int port;
+};
+
+
+// ColInfoResponse ::= SEQUENCE {
+//   shortInfo      [0]  IMPLICIT ShortCollectionInfo,
+//   isPublic       [2]  IMPLICIT BOOLEAN,    -- whether has anonymous access
+//   isBeta         [3]  IMPLICIT BOOLEAN,    -- beta if still under development
+//   buildDate      [4]  IMPLICIT GeneralizedTime,
+//   ccsCols        [5]  IMPLICIT StringSet,  -- collections that form cross-col search
+//   languages      [6]  IMPLICIT StringSet,  -- languages in the collection
+//   numDocs        [7]  IMPLICIT INTEGER,
+//   numSections    [8]  IMPLICIT INTEGER OPTIONAL,
+//   numWords       [9]  IMPLICIT INTEGER OPTIONAL,
+//   numBytes       [10] IMPLICIT INTEGER OPTIONAL
+//   collectionmeta [11] IMPLICIT StringSet
+//   format         [12] IMPLICIT StringSet
+//   building       [13] IMPLICIT StringSet
+//   receptionist   [14] IMPLICIT GeneralString
+//   buildType      [15] IMPLICIT GeneralString
+// }
+struct ColInfoResponse_t {
+  void clear ();
+  ColInfoResponse_t () {clear();}
+
+  ShortColInfo_t shortInfo;
+  bool isPublic;
+  bool isBeta;
+  unsigned long buildDate;
+  text_tarray ccsCols;    // empty if collection does not use cross-collection searching
+  text_tarray languages;
+  unsigned long numDocs;     // 0 if not known
+  unsigned long numSections; // 0 if not known
+  unsigned long numWords;    // 0 if not known
+  unsigned long numBytes;    // 0 if not known
+  text_tmap collectionmeta;
+  text_tmap format;
+  text_tmap building;
+  text_t receptionist;
+  text_t  buildType;  // MG or MGPP
+};
+
+
+// -- filter options which might be supported for the QueryFilter
+// --
+// -- onePerQuery StartResults   integer
+// -- onePerQuery EndResults     integer
+// -- onePerQuery QueryType      enumerated (boolean, ranked)
+// -- onePerTerm  Term           string ???
+// -- onePerTerm  Casefold       boolean
+// -- onePerTerm  Stem           boolean
+// -- onePerTerm  Index          enumerated
+// -- onePerTerm  Subcollection  enumerated
+// --
+// -- filter options which might be supported for the BrowseFilter
+// --
+// -- onePerQuery StartResults   integer
+// -- onePerQuery EndResults     integer
+// -- onePerQuery ParentNode     string ("" will return the browsing available)
+// --
+// -- The NullFilter always returns the set it was given, it doesn't have
+// -- any options
+
+// InfoFiltersResponse ::= SEQUENCE {
+//   filterNames StringSet
+// }
+struct InfoFiltersResponse_t {
+  void clear ();
+
+  text_tset filterNames;
+};
+
+// InfoFilterOptionsRequest ::= SEQUENCE {
+//   filterName GeneralString
+// }
+struct InfoFilterOptionsRequest_t {
+  void clear ();
+
+  text_t filterName;
+};
+
+// FilterOption ::= SEQUENCE {
+//   name         GeneralString,
+//   type         ENUMERATED {booleant(0), integert(1), enumeratedt(2), stringt(3)},
+//   repeatable   ENUMERATED {onePerQuery(0), onePerTerm(1), nPerTerm(2)},
+//   defaultValue GeneralString,
+//   -- the interpretation of the validValues depends on the type
+//   -- for boolean: the first value is the false value, the second is true value
+//   -- for integer: the first value is the minimum, the second the maximum
+//   -- for enumerated: all values a listed
+//   -- for string: this value is ignored
+//   validValues  StringSequence
+// }
+struct FilterOption_t {
+  void clear ();
+  void check_defaultValue ();
+  FilterOption_t () {clear();}
+
+  text_t name;
+
+  enum type_t {booleant=0, integert=1, enumeratedt=2, stringt=3};
+  type_t type;
+
+  enum repeatable_t {onePerQuery=0, onePerTerm=1, nPerTerm=2};
+  repeatable_t repeatable;
+
+  text_t defaultValue;
+  text_tarray validValues;
+};
+
+bool operator==(const FilterOption_t &x, const FilterOption_t &y);
+bool operator<(const FilterOption_t &x, const FilterOption_t &y);
+
+
+typedef map<text_t, FilterOption_t, lttext_t> FilterOption_tmap;
+
+
+// InfoFilterOptionsResponse ::= SEQUENCE {
+//   filterOptions SET OF FilterOption
+// }
+struct InfoFilterOptionsResponse_t {
+  void clear ();
+
+  FilterOption_tmap filterOptions;
+};
+
+
+// OptionValue ::= SEQUENCE {
+//   name  GeneralString,
+//   value GeneralString
+// }
+struct OptionValue_t {
+  void clear ();
+
+  text_t name;
+  text_t value;
+};
+
+typedef vector<OptionValue_t> OptionValue_tarray;
+
+
+// -- Terms are presented in the same order that they are requested,
+// -- any information relating to the terms is in reference to the
+// -- index specified for that term.
+//
+// FilterRequest ::= SEQUENCE {
+//   filterName          [0] GeneralString,
+//   filterOptions       [1] IMPLICIT SEQUENCE OF OptionValue,
+//   docSet              [2] IMPLICIT StringSequence, -- the OID "" represents everything
+//   filterResultOptions [3] IMPLICIT BIT STRING {termFreq(0), matchTerms(1), OID(2), 
+//                                                subCol(3), ranking(4), docFreq(5), 
+//                                                metadata(6)}
+// 
+//   -- the next set of options are for the metadata request, 
+//   -- they can be left blank if metadata is not wanted
+//   requestParams       [4] IMPLICIT GeneralString, -- used to negotiate the metadata content
+//   refParams           [5] IMPLICIT GeneralString, -- used to decide whether to return a 
+//                                                   -- reference to the data or the actual data
+//   fields              [6] IMPLICIT StringSet
+//   getParents          [7] IMPLICIT BOOLEAN        -- gets metadata of all parents too
+// }
+#define FRtermFreq   1
+#define FRmatchTerms 2
+#define FROID        4
+#define FRsubCol     8
+#define FRranking    16
+#define FRdocFreq    32
+#define FRmetadata   64
+// used to indicate a full text browse query for mgpp
+#define FRfullTextBrowse  128
+
+struct FilterRequest_t {
+  void clear ();
+  FilterRequest_t () {clear();}
+
+  text_t filterName;
+  OptionValue_tarray filterOptions;
+  text_tarray docSet;        // empty if not used
+  int filterResultOptions; // use the FR* defines above
+
+  text_t requestParams; // empty if not used
+  text_t refParams;     // empty if not used
+  text_tset fields;   // empty if not used
+  bool getParents;      // defaults to false
+};
+
+
+// TermInfo ::= SEQUENCE {
+//   term       [0] GeneralString,
+//   freq       [1] IMPLICIT INTEGER,       -- 0 if not requested
+//   matchTerms [2] IMPLICIT StringSequence -- empty if not requested
+// }
+struct TermInfo_t {
+  void clear ();
+  TermInfo_t () {clear();}
+
+  text_t term;
+  int freq; // 0 if not requested
+  text_tarray matchTerms; // empty if not requested
+};
+
+typedef vector<TermInfo_t> TermInfo_tarray;
+
+
+// MetadataInfo ::= SEQUENCE {
+//   params  [0] IMPLICIT GeneralString,
+//   isRef   [1] IMPLICIT BOOLEAN,
+//   values  [3] IMPLICIT SEQUENCE OF GeneralString,
+//   name    [4] IMPLICIT GeneralString
+// }
+struct MetadataInfo_t {
+  text_t params;
+  bool isRef;
+  text_tarray values;
+  MetadataInfo_t *parent;
+
+  void clear ();
+  MetadataInfo_t ();
+  MetadataInfo_t (const MetadataInfo_t &x); // copy constructor
+  ~MetadataInfo_t ();
+  MetadataInfo_t &operator=(const MetadataInfo_t &x);
+};
+
+typedef map<text_t, MetadataInfo_t, lttext_t> MetadataInfo_tmap;
+
+// ResultDocInfo ::= SEQUENCE {
+//   OID      [0] IMPLICIT GeneralString,
+//   ranking  [1] IMPLICIT INTEGER,             -- 0 if not requested, range 0-10000
+//   docFreq  [2] IMPLICIT SEQUENCE OF INTEGER, -- empty if not requested
+//   metadata [3] IMPLICIT SEQUENCE OF MetadataInfo, -- no longer a SEQUENCE (SET maybe??)
+//   classifier_metadata_type   [4] IMPLICIT GeneralString,       -- empty if not requested
+//   classifier_metadata_offset [5] IMPLICIT INTEGER,             -- 0 if not requested
+// }
+struct ResultDocInfo_t {
+  void clear ();
+  ResultDocInfo_t () {clear();}
+
+  text_t OID;
+  int result_num;          // place in results list
+  int ranking;             // 0 if not requested (real ranking*10000)
+  int num_terms_matched;   // not available on all versions of mg
+  int num_phrase_match;    // not available on all versions of mg
+  vector<int> docFreq;           // empty if not requested
+  MetadataInfo_tmap metadata;    // empty if not requested
+  text_t classifier_metadata_type;        // empty if not requested
+  int    classifier_metadata_offset;      // 0 if not requested
+  ResultDocInfo_t &operator=(const ResultDocInfo_t &x);
+};
+
+typedef vector<ResultDocInfo_t> ResultDocInfo_tarray;
+
+
+// FilterResponse ::= SEQUENCE {
+//   numDocs   [0] IMPLICIT INTEGER,
+//   isApprox  [1] ENUMERATED {Exact(0), Approximate(1), MoreThan(2)}, -- whether numDocs is approximate
+//   termInfo  [2] IMPLICIT SEQUENCE OF TermInfo,                      -- empty if not required
+//   docInfo   [3] IMPLICIT SEQUENCE OF ResultDocInfo                  -- empty if not required
+// }
+
+enum isapprox {Exact=0, Approximate=1, MoreThan=2};
+
+struct FilterResponse_t {
+  void clear ();
+  FilterResponse_t () {clear();}
+
+  int numDocs;
+  isapprox isApprox;
+  TermInfo_tarray termInfo; // empty if not requested
+  ResultDocInfo_tarray docInfo; // empty if not requested
+
+  FilterResponse_t &operator=(const FilterResponse_t &x);
+};
+
+
+// DocumentRequest ::= SEQUENCE {
+//   OID       GeneralString,
+//   docType   GeneralString,
+//   docFormat GeneralString
+// }
+struct DocumentRequest_t {
+  void clear ();
+  DocumentRequest_t () {clear();}
+
+  text_t OID;
+  text_t docType;
+  text_t docFormat;
+};
+
+
+// DocumentResponse ::= SEQUENCE {
+//   doc OCTET STRING
+// }
+
+struct DocumentResponse_t {
+  void clear ();
+  DocumentResponse_t () {clear();}
+
+  text_t doc;
+};
+
+
+#endif
+
Index: /main/tags/2.25/gsdl/src/recpt/converter.cpp
===================================================================
--- /main/tags/2.25/gsdl/src/recpt/converter.cpp	(revision 21064)
+++ /main/tags/2.25/gsdl/src/recpt/converter.cpp	(revision 21064)
@@ -0,0 +1,77 @@
+/**********************************************************************
+ *
+ * converter.cpp -- 
+ * Copyright (C) 1999  The New Zealand Digital Library Project
+ *
+ * A component of the Greenstone digital library software
+ * from the New Zealand Digital Library Project at the
+ * University of Waikato, New Zealand.
+ *
+ * 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.
+ *
+ *********************************************************************/
+
+#include "converter.h"
+
+
+
+// the converters within converterinfo become the property of
+// of this class after add_converter has been called. The converters
+// remain the responsability of the calling code and will not be
+// deleted by this class.
+void convertinfoclass::add_converter (const text_t &name, inconvertclass *inconverter,
+				      rzwsoutconvertclass *outconverter) {
+  // can't add a null converter or an action with no name
+  if (inconverter == NULL || outconverter == NULL || name.empty()) {
+    return;
+  }
+
+  converterinfo info;
+  info.name = name;
+  info.inconverter = inconverter;
+  info.outconverter = outconverter;
+  converters[name] = info;
+}
+
+
+bool operator==(const converterinfo &x, const converterinfo &y) {
+  return ((x.name == y.name) && (x.inconverter == y.inconverter) &&
+	  (x.outconverter == y.outconverter));
+}
+
+bool operator<(const converterinfo &x, const converterinfo &y) {
+  return ((x.name < y.name) ||
+	  ((x.name == y.name) &&
+	   ((x.inconverter < y.inconverter) ||
+	    ((x.inconverter == y.inconverter) &&
+	     ((x.outconverter < y.outconverter))))));
+}
+
+
+// get_inconverter will return NULL if the convert could not be found
+inconvertclass *convertinfoclass::get_inconverter (const text_t &name) {
+  iterator here = converters.find (name);
+  if (here == converters.end()) return NULL;
+
+  return (*here).second.inconverter;
+}
+
+// get_outconverter will return NULL if the convert could not be found
+rzwsoutconvertclass *convertinfoclass::get_outconverter (const text_t &name) {
+  iterator here = converters.find (name);
+  if (here == converters.end()) return NULL;
+
+  return (*here).second.outconverter;
+}
Index: /main/tags/2.25/gsdl/src/recpt/converter.h
===================================================================
--- /main/tags/2.25/gsdl/src/recpt/converter.h	(revision 21064)
+++ /main/tags/2.25/gsdl/src/recpt/converter.h	(revision 21064)
@@ -0,0 +1,121 @@
+/**********************************************************************
+ *
+ * converter.h -- 
+ * Copyright (C) 1999  The New Zealand Digital Library Project
+ *
+ * A component of the Greenstone digital library software
+ * from the New Zealand Digital Library Project at the
+ * University of Waikato, New Zealand.
+ *
+ * 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.
+ *
+ *********************************************************************/
+
+
+#ifndef CONVERTER_H
+#define CONVERTER_H
+
+
+#include "gsdlconf.h"
+#include "text_t.h"
+#include "gsdlunicode.h"
+
+#if defined(GSDL_USE_OBJECTSPACE)
+#  include <ospace\std\map>
+#elif defined(GSDL_USE_STL_H)
+#  include <map.h>
+#else
+#  include <map>
+#endif
+
+
+// inconverter and outconverter ARE NOT destroyed by this class
+// they should be destroyed by the code which created them after
+// no more pointers to the class exist.
+//
+// The above condition enables the class to be copied without
+// copying the converters which might contain a lot of data (and
+// be of an unknown derived type).
+class converterinfo {
+public:
+  text_t name;
+  inconvertclass *inconverter;
+  rzwsoutconvertclass *outconverter;
+
+  converterinfo() {inconverter=NULL; outconverter=NULL;}
+};
+
+bool operator==(const converterinfo &x, const converterinfo &y);
+bool operator<(const converterinfo &x, const converterinfo &y);
+
+
+typedef map<text_t, converterinfo, lttext_t> convertmap;
+
+// convertinfoclass is used to store a number of converters
+// indexing them by their name
+class convertinfoclass {
+protected:
+  convertmap converters;
+
+public:
+  // type support for convertmap
+  typedef convertmap::iterator iterator;
+  typedef convertmap::const_iterator const_iterator;
+  typedef convertmap::reference reference;
+  typedef convertmap::const_reference const_reference;
+  typedef convertmap::size_type size_type;
+  typedef convertmap::difference_type difference_type;
+  typedef convertmap::const_reverse_iterator const_reverse_iterator;
+  typedef convertmap::reverse_iterator reverse_iterator;
+  
+  // constructors
+  convertinfoclass () {}
+
+  // basic container support
+  iterator begin () {return converters.begin();}
+  const_iterator begin () const {return converters.begin();}
+  iterator end () {return converters.end();}
+  const_iterator end () const {return converters.end();}
+
+  void erase(iterator pos) {converters.erase(pos);}
+  void erase(iterator first, iterator last) {converters.erase(first, last);}
+  convertinfoclass &operator=(const convertinfoclass &x) 
+    {converters=x.converters;return *this;}
+
+  bool empty () const {return converters.empty();}
+  size_type size() const {return converters.size();}
+
+
+  // added functionality
+  void clear () {converters.erase(converters.begin(),converters.end());}
+
+  // the converters within converterinfo become the property of
+  // of this class after add_converter has been called. The converters
+  // remain the responsability of the calling code and will not be
+  // deleted by this class.
+  void add_converter (const text_t &name, inconvertclass *inconverter,
+		      rzwsoutconvertclass *outconverter);
+
+  // get_inconverter will return NULL if the convert could not be found
+  inconvertclass *get_inconverter (const text_t &name);
+
+  // get_outconverter will return NULL if the convert could not be found
+  rzwsoutconvertclass *get_outconverter (const text_t &name);
+};
+
+
+
+
+#endif
Index: /main/tags/2.25/gsdl/src/recpt/datelistbrowserclass.cpp
===================================================================
--- /main/tags/2.25/gsdl/src/recpt/datelistbrowserclass.cpp	(revision 21064)
+++ /main/tags/2.25/gsdl/src/recpt/datelistbrowserclass.cpp	(revision 21064)
@@ -0,0 +1,140 @@
+/**********************************************************************
+ *
+ * datelistbrowserclass.cpp -- 
+ * Copyright (C) 1999  The New Zealand Digital Library Project
+ *
+ * A component of the Greenstone digital library software
+ * from the New Zealand Digital Library Project at the
+ * University of Waikato, New Zealand.
+ *
+ * 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.
+ *
+ *********************************************************************/
+
+#include "datelistbrowserclass.h"
+#include <assert.h>
+
+
+datelistbrowserclass::datelistbrowserclass () {
+}
+
+datelistbrowserclass::~datelistbrowserclass () {
+}
+
+text_t datelistbrowserclass::get_browser_name () {
+  return "DateList";
+}
+
+void datelistbrowserclass::load_metadata_defaults (text_tset &metadata) {
+  metadata.insert ("Date");
+  metadata.insert ("doctype");
+}
+
+text_t datelistbrowserclass::get_default_formatstring () {
+  return "<td>[link][icon][/link]</td><td>[highlight]{Or}{[Title],Untitled}[/highlight]</td><td>[Date]</td>";
+}
+
+int datelistbrowserclass::output_section_group (ResultDocInfo_t &/*section*/, cgiargsclass &/*args*/,
+						const text_t &/*collection*/, int /*colnumber*/, 
+						format_t * /*formatlistptr*/, bool /*use_table*/, 
+						text_tset &/*metadata*/, bool &/*getParents*/,
+						recptproto * /*collectproto*/, displayclass &/*disp*/, 
+						outconvertclass &/*outconvert*/, ostream &/*textout*/, 
+						ostream &/*logout*/) {
+  return 0;
+}
+
+int datelistbrowserclass::output_section_group (FilterResponse_t &sections, cgiargsclass &args,
+						const text_t &/*collection*/, int colnumber, format_t *formatlistptr, 
+						bool use_table, text_tset &/*metadata*/, bool &/*getParents*/,
+						recptproto * /*collectproto*/, displayclass &disp, 
+						outconvertclass &outconvert, ostream &textout, ostream &/*logout*/) {
+
+  text_t lastyear = "0000";
+  text_t lastmonth = "00";
+  text_t tabbing, endtabbing;
+
+  if (use_table || colnumber > 0) {
+    textout << "<table><tr><td>";
+    // get tab size
+    text_t tab; int itab;
+    disp.expandstring ("Global", "_tabwidth_", tab);
+    itab = tab.getint();
+    if (colnumber > 0) 
+      textout << "<img src=\"_httpimg_/space.gif\" width=" << (itab*colnumber) << ">";
+    textout<< "</td><td>";
+  }
+
+  textout << "<table>\n";
+
+  ResultDocInfo_tarray::iterator thissection = sections.docInfo.begin();
+  ResultDocInfo_tarray::iterator endsection = sections.docInfo.end();
+
+  while (thissection != endsection) {
+
+    text_t &doctype = (*thissection).metadata["doctype"].values[0];
+    text_t &date = (*thissection).metadata["Date"].values[0]; 
+
+    // bail on this document if it has no date
+    if (date.empty()) continue;
+
+    text_t::const_iterator datebegin = date.begin();
+    int datesize = date.size();
+    
+    if (datesize < 4) continue;
+    text_t thisyear = substr (datebegin, datebegin+4);
+    text_t thismonth = "00";
+    if (datesize >= 6)
+      thismonth = substr (datebegin+4, datebegin+6); 
+
+    text_t link = "<a href=\"_httpdocument_&cl=";
+    text_t icon = "_document:iconclosedbook_";
+      
+    if (doctype == "classify") {
+      icon = "_document:iconclosedbookshelf_";
+      link += (*thissection).OID + "\">";
+    } else link += args["cl"] + "&d=" + (*thissection).OID + "\">";
+
+    textout << "<tr valign=top>";
+
+    if (thisyear != lastyear) {
+      textout << outconvert << "<td><b>" << thisyear << "</b></td>";
+      lastyear = thisyear;
+    } else
+      textout << "<td></td>";
+    
+    if (thismonth != lastmonth) {
+      textout << outconvert << disp << ("<td><b>_textmonth" + thismonth + "_</b></td>");
+      lastmonth = thismonth;
+    } else
+      textout << "<td></td>";
+    
+    if (!use_table) textout << "<td>\n";
+    
+    textout << outconvert << disp 
+            << get_formatted_string (*thissection, formatlistptr, link, icon) << "\n";
+    
+    if (!use_table) textout << "</td>";
+    
+    textout << "</tr>\n";
+    
+    thissection ++;
+  }
+
+  textout << "</table>\n";
+
+  if (use_table  || colnumber > 0) textout << "</td></tr></table>\n";
+  return 1;
+}
Index: /main/tags/2.25/gsdl/src/recpt/datelistbrowserclass.h
===================================================================
--- /main/tags/2.25/gsdl/src/recpt/datelistbrowserclass.h	(revision 21064)
+++ /main/tags/2.25/gsdl/src/recpt/datelistbrowserclass.h	(revision 21064)
@@ -0,0 +1,58 @@
+/**********************************************************************
+ *
+ * datelistbrowserclass.h -- 
+ * Copyright (C) 1999  The New Zealand Digital Library Project
+ *
+ * A component of the Greenstone digital library software
+ * from the New Zealand Digital Library Project at the
+ * University of Waikato, New Zealand.
+ *
+ * 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.
+ *
+ *********************************************************************/
+
+
+#ifndef DATELISTBROWSERCLASS_H
+#define DATELISTBROWSERCLASS_H
+
+#include "browserclass.h"
+
+class datelistbrowserclass : public browserclass {
+protected:
+
+public:
+  datelistbrowserclass ();
+  virtual ~datelistbrowserclass ();
+
+  text_t get_browser_name ();
+
+  virtual void load_metadata_defaults (text_tset &metadata);
+
+  virtual text_t get_default_formatstring ();
+
+  virtual int output_section_group (ResultDocInfo_t &section, cgiargsclass &args,
+				    const text_t &collection, int colnumber, format_t *formatlistptr, 
+				    bool use_table, text_tset &metadata, bool &getParents,
+				    recptproto *collectproto, displayclass &disp, 
+				    outconvertclass &outconvert, ostream &textout, ostream &logout);
+  
+  virtual int output_section_group (FilterResponse_t &sections, cgiargsclass &args,
+				    const text_t &collection, int colnumber, format_t *formatlistptr, 
+				    bool use_table, text_tset &metadata, bool &getParents,
+				    recptproto *collectproto, displayclass &disp, 
+				    outconvertclass &outconvert, ostream &textout, ostream &logout);
+};
+
+#endif
Index: /main/tags/2.25/gsdl/src/recpt/delhistoryaction.cpp
===================================================================
--- /main/tags/2.25/gsdl/src/recpt/delhistoryaction.cpp	(revision 21064)
+++ /main/tags/2.25/gsdl/src/recpt/delhistoryaction.cpp	(revision 21064)
@@ -0,0 +1,207 @@
+/**********************************************************************
+ *
+ * delhistoryaction.cpp -- allows user to select history items to delete
+ * Copyright (C) 1999  The New Zealand Digital Library Project
+ *
+ * A component of the Greenstone digital library software
+ * from the New Zealand Digital Library Project at the
+ * University of Waikato, New Zealand.
+ *
+ * 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.
+ *
+ *********************************************************************/
+
+#include "delhistoryaction.h"
+#include "cgiutils.h"
+#include "text_t.h"
+#include "historydb.h"
+
+delhistoryaction::delhistoryaction () {
+
+  // this action uses cgi variable "a"
+  cgiarginfo arg_ainfo;
+  arg_ainfo.shortname = "a";
+  arg_ainfo.longname = "action";
+  arg_ainfo.multiplechar = true;
+  arg_ainfo.defaultstatus = cgiarginfo::weak;
+  arg_ainfo.argdefault = "dh";
+  arg_ainfo.savedarginfo = cgiarginfo::must;
+  argsinfo.addarginfo (NULL, arg_ainfo);
+
+  // "hmode" -- indicate whether selected records are to be
+  // saved or deleted
+  arg_ainfo.shortname = "hmode";
+  arg_ainfo.longname = "history deletion mode";
+  arg_ainfo.multiplechar = true;
+  arg_ainfo.defaultstatus = cgiarginfo::weak;
+  arg_ainfo.argdefault = "delete";
+  arg_ainfo.savedarginfo = cgiarginfo::mustnot;
+  argsinfo.addarginfo (NULL, arg_ainfo);
+
+  // "hsr" -- the selected records
+  arg_ainfo.shortname = "hsr";
+  arg_ainfo.longname = "history selected records";
+  arg_ainfo.multiplechar = true;
+  arg_ainfo.multiplevalue = true;
+  arg_ainfo.defaultstatus = cgiarginfo::weak;
+  arg_ainfo.argdefault = "";
+  arg_ainfo.savedarginfo = cgiarginfo::mustnot;
+  argsinfo.addarginfo (NULL, arg_ainfo);
+
+  // "hdh" delete history for current user
+  // clear history = 0 = delete some, 1 = delete all
+  arg_ainfo.shortname = "hdh";
+  arg_ainfo.longname = "history delete history";
+  arg_ainfo.multiplechar = false;
+  arg_ainfo.multiplevalue = false;
+  arg_ainfo.defaultstatus = cgiarginfo::weak;
+  arg_ainfo.argdefault = "0";
+  arg_ainfo.savedarginfo = cgiarginfo::mustnot;
+  argsinfo.addarginfo (NULL, arg_ainfo);
+
+}
+
+void delhistoryaction::configure (const text_t &key, const text_tarray &cfgline) {
+  action::configure (key, cfgline);
+}
+
+bool delhistoryaction::init (ostream &logout) {
+  return action::init (logout);
+}
+
+bool delhistoryaction::check_cgiargs (cgiargsinfoclass & /*argsinfo*/, cgiargsclass & /*args*/, 
+				      ostream &/*logout*/) {
+  //dont check anything yet
+  return true;
+}
+
+void delhistoryaction::get_cgihead_info (cgiargsclass &/*args*/, recptprotolistclass * /*protos*/,
+					 response_t &response, text_t &response_data, 
+					 ostream &/*logout*/) {
+  response = content;
+  response_data = "text/html";
+}
+
+void delhistoryaction::define_internal_macros (displayclass &/*disp*/, cgiargsclass &/*args*/, 
+					       recptprotolistclass * /*protos*/, 
+					       ostream &/*logout*/) {
+
+  // define_internal_macros sets the following macros:
+  //_searchhistorylist_
+
+  //  define_history_macros(disp, args, protos, logout);
+
+}
+
+
+void delhistoryaction::define_external_macros (displayclass &/*disp*/, cgiargsclass &/*args*/, 
+					       recptprotolistclass * /*protos*/, ostream &/*logout*/) {
+
+  // define_external_macros sets the following macros:
+  
+  // can't do anything if collectproto is null (i.e. no collection was specified)
+  //recptproto *collectproto = protos->getrecptproto (args["c"], logout);
+  //if (collectproto == NULL) return;
+  
+  // define_history_macros(disp, args, protos, logout);
+  
+}
+
+
+void delhistoryaction::define_history_macros(displayclass &disp, cgiargsclass &args, 
+					     recptprotolistclass *protos, ostream &logout) {
+
+  // defines the following macros
+
+  // _searchhistorylist_
+
+    text_t historylist = "<!-- Search History List -->\n";
+   
+    text_t userid = args["z"];
+    text_tarray entries;
+
+    historylist += "<table align=center width=500 border=1> \n <tr><th colspan=4 align=center>";
+    historylist += "_query:textsearchhistory_</th></tr>\n";
+    historylist += "<tr><th width=60>_textselect_</th><th width=40>#</th>\n<th width=340>_query:textquery_</th>\n";
+    historylist += "<th width=60>_query:textresults_</th></tr>\n";
+    if (get_history_info (userid, entries, gsdlhome, logout)) {
+      int count = 1;
+      text_tarray::iterator here = entries.begin();
+      text_tarray::iterator end = entries.end();
+      //      int size=(int)entries.size();
+      while (here !=end ) {
+	text_t c=count;
+	text_t querynum;
+	text_t query;
+	text_t numdocs;
+	text_t cgiargs;
+	text_t  userinfo;
+	split_saved_query(*here, querynum, numdocs, cgiargs);
+	parse_saved_args(cgiargs, "q", query); // get query string out
+	decode_cgi_arg(query); // un cgisafe it
+	
+	format_user_info(cgiargs, userinfo, protos, logout);
+	
+	historylist += "<tr> <td width=60 align=center><input type=checkbox name=hsr value=\""+querynum+"\"></td>";
+	historylist += "<td width=40 align=center>"+querynum+"</td>\n";
+	historylist += "<td width=340 align=left>"+query+"</td><td width=60 align=center>"+numdocs+"</td>\n";
+	here++;
+	count++;
+      }
+     
+     
+    } // if
+    else { // have an empty row
+      historylist += "";
+    }
+    historylist+="</table>";
+    historylist += "<p><! ---- end of history list ----->\n";
+    disp.setmacro("searchhistorylist", "delhistory", historylist);
+
+} // define history macros
+
+
+bool delhistoryaction::do_action (cgiargsclass &args, recptprotolistclass *protos, 
+				  browsermapclass * /*browsers*/, displayclass &disp, 
+				  outconvertclass &outconvert, ostream &textout, 
+				  ostream &logout) {
+
+  if (args["hdh"] !="") {
+    delete_search_history(args);
+  }
+  define_history_macros(disp, args, protos, logout);
+  textout << outconvert << disp << ("_delhistory:header_\n")
+	  << ("_delhistory:content_\n")
+	  << ("_delhistory:footer_\n");
+
+  return true;
+}
+
+
+bool delhistoryaction::delete_search_history (cgiargsclass &args) {
+  
+  bool result;
+  text_t userid = args["z"];
+  text_t type = args["hdh"];
+  if (type == "1") {
+    result = delete_all_history_info (userid, gsdlhome);
+  } else {
+    text_t records = args["hsr"];
+    text_t deletemode = args["hmode"];
+    result = delete_history_info (userid, deletemode, records, gsdlhome);
+  }
+
+  return result;
+}
Index: /main/tags/2.25/gsdl/src/recpt/delhistoryaction.h
===================================================================
--- /main/tags/2.25/gsdl/src/recpt/delhistoryaction.h	(revision 21064)
+++ /main/tags/2.25/gsdl/src/recpt/delhistoryaction.h	(revision 21064)
@@ -0,0 +1,75 @@
+/**********************************************************************
+ *
+ * delhistoryaction.h --  allows user to select history items to delete
+ * Copyright (C) 1999  The New Zealand Digital Library Project
+ *
+ * A component of the Greenstone digital library software
+ * from the New Zealand Digital Library Project at the
+ * University of Waikato, New Zealand.
+ *
+ * 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.
+ *
+ *********************************************************************/
+
+
+#ifndef DELHISTORYACTION_H
+#define DELHISTORYACTION_H
+
+#include "gsdlconf.h"
+#include "action.h"
+
+
+class delhistoryaction : public action {
+
+protected:
+
+  void define_history_macros (displayclass &disp, cgiargsclass &args, 
+			       recptprotolistclass *protos, ostream &logout);
+
+  void set_option_macro (const text_t &macroname, text_t current_value,
+			 const FilterOption_t &option, displayclass &disp);
+
+
+  bool delete_search_history(cgiargsclass &args);
+
+public:
+  delhistoryaction ();
+  virtual ~delhistoryaction () {}
+  
+  void configure (const text_t &key, const text_tarray &cfgline);
+  bool init (ostream &logout);
+  
+  text_t get_action_name () {return "dh";}
+  
+  bool check_cgiargs (cgiargsinfoclass &argsinfo, cgiargsclass &args, 
+		      ostream &logout);
+
+  void get_cgihead_info (cgiargsclass &args, recptprotolistclass *protos,
+			 response_t &response, text_t &response_data, 
+			 ostream &logout);
+  
+  void define_internal_macros (displayclass &disp, cgiargsclass &args, 
+			       recptprotolistclass *protos, ostream &logout);
+
+  void define_external_macros (displayclass &disp, cgiargsclass &args, 
+			       recptprotolistclass *protos, ostream &logout);
+  
+  bool do_action (cgiargsclass &args, recptprotolistclass *protos, 
+		  browsermapclass *browsers, displayclass &disp, 
+		  outconvertclass &outconvert, ostream &textout, 
+		  ostream &logout);
+};
+
+#endif
Index: /main/tags/2.25/gsdl/src/recpt/documentaction.cpp
===================================================================
--- /main/tags/2.25/gsdl/src/recpt/documentaction.cpp	(revision 21064)
+++ /main/tags/2.25/gsdl/src/recpt/documentaction.cpp	(revision 21064)
@@ -0,0 +1,958 @@
+/**********************************************************************
+ *
+ * documentaction.cpp -- 
+ * Copyright (C) 1999  The New Zealand Digital Library Project
+ *
+ * A component of the Greenstone digital library software
+ * from the New Zealand Digital Library Project at the
+ * University of Waikato, New Zealand.
+ *
+ * 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.
+ *
+ *********************************************************************/
+
+#include <string.h>
+#include "documentaction.h"
+#include "browsetools.h"
+#include "OIDtools.h"
+#include "querytools.h"
+#include "unitool.h"
+#include "gsdltools.h"
+
+documentaction::documentaction () {
+  recpt = NULL;
+
+
+  // this action uses cgi variables "a", "d", "cl",
+  // "x", "gc", "gt", "gp", and "hl"
+  cgiarginfo arg_ainfo;
+  arg_ainfo.shortname = "a";
+  arg_ainfo.longname = "action";
+  arg_ainfo.multiplechar = true;
+  arg_ainfo.defaultstatus = cgiarginfo::weak;
+  arg_ainfo.argdefault = "p";
+  arg_ainfo.savedarginfo = cgiarginfo::must;
+  argsinfo.addarginfo (NULL, arg_ainfo);
+
+  arg_ainfo.shortname = "d";
+  arg_ainfo.longname = "document OID";
+  arg_ainfo.multiplechar = true;
+  arg_ainfo.defaultstatus = cgiarginfo::none;
+  arg_ainfo.argdefault = "";
+  arg_ainfo.savedarginfo = cgiarginfo::can;
+  argsinfo.addarginfo (NULL, arg_ainfo);
+
+  // whether or not a document should be retrieved from the 
+  // library or the Web.
+  arg_ainfo.shortname = "il";
+  arg_ainfo.longname = "internal link preference";
+  arg_ainfo.multiplechar = false;
+  arg_ainfo.defaultstatus = cgiarginfo::weak;
+  arg_ainfo.argdefault = "l";
+  arg_ainfo.savedarginfo = cgiarginfo::must;
+  argsinfo.addarginfo (NULL, arg_ainfo);
+
+  arg_ainfo.shortname = "cl";
+  arg_ainfo.longname = "classification OID";
+  arg_ainfo.multiplechar = true;
+  arg_ainfo.defaultstatus = cgiarginfo::none;
+  arg_ainfo.argdefault = "";
+  arg_ainfo.savedarginfo = cgiarginfo::can;
+  argsinfo.addarginfo (NULL, arg_ainfo);
+
+  // in this action "gc" controls the expand/contract
+  // contents function
+  arg_ainfo.shortname = "gc";
+  arg_ainfo.longname = "expand contents";
+  arg_ainfo.multiplechar = false;
+  arg_ainfo.defaultstatus = cgiarginfo::weak;
+  arg_ainfo.argdefault = "0";
+  arg_ainfo.savedarginfo = cgiarginfo::can;
+  argsinfo.addarginfo (NULL, arg_ainfo);
+
+  // in this action "gt" controls the expand/contract
+  // text function 0 = not expanded, 1 = expand unless 
+  // there are more than 10 sections containing text,
+  // 2 = expand all
+  arg_ainfo.shortname = "gt";
+  arg_ainfo.longname = "expand text";
+  arg_ainfo.multiplechar = false;
+  arg_ainfo.defaultstatus = cgiarginfo::weak;
+  arg_ainfo.argdefault = "0";
+  arg_ainfo.savedarginfo = cgiarginfo::can;
+  argsinfo.addarginfo (NULL, arg_ainfo);
+
+  // in this action "gp" is the "go to page" control
+  // used by the Book type of toc
+  arg_ainfo.shortname = "gp";
+  arg_ainfo.longname = "go to page";
+  arg_ainfo.multiplechar = true;
+  arg_ainfo.defaultstatus = cgiarginfo::none;
+  arg_ainfo.argdefault = "";
+  arg_ainfo.savedarginfo = cgiarginfo::mustnot;
+  argsinfo.addarginfo (NULL, arg_ainfo);
+
+  // in this action "hl" is the "highlighting on/
+  // highlighting off control
+  arg_ainfo.shortname = "hl";
+  arg_ainfo.longname = "highlighting on/off";
+  arg_ainfo.multiplechar = false;
+  arg_ainfo.defaultstatus = cgiarginfo::weak;
+  arg_ainfo.argdefault = "1";
+  arg_ainfo.savedarginfo = cgiarginfo::must;
+  argsinfo.addarginfo (NULL, arg_ainfo);
+
+  // "x" is 0 normally or 1 if page
+  // has been "detached"
+  arg_ainfo.shortname = "x";
+  arg_ainfo.longname = "detached page";
+  arg_ainfo.multiplechar = false;
+  arg_ainfo.defaultstatus = cgiarginfo::weak;
+  arg_ainfo.argdefault = "0";
+  arg_ainfo.savedarginfo = cgiarginfo::must;
+  argsinfo.addarginfo (NULL, arg_ainfo);
+
+  // f arg is set to 1 if document is to 
+  // be displayed in a frame
+  arg_ainfo.shortname = "f";
+  arg_ainfo.longname = "frame";
+  arg_ainfo.multiplechar = false;
+  arg_ainfo.defaultstatus = cgiarginfo::weak;
+  arg_ainfo.argdefault = "0";
+  arg_ainfo.savedarginfo = cgiarginfo::mustnot;
+  argsinfo.addarginfo (NULL, arg_ainfo);
+
+  // fc arg is "1" if search bar is to be included (i.e. if "fc" == 1
+  // the httpdocument macro will include "&f=1"
+  arg_ainfo.shortname = "fc";
+  arg_ainfo.longname = "include search bar";
+  arg_ainfo.multiplechar = false;
+  arg_ainfo.defaultstatus = cgiarginfo::weak;
+  arg_ainfo.argdefault = "1";
+  arg_ainfo.savedarginfo = cgiarginfo::must;
+  argsinfo.addarginfo (NULL, arg_ainfo);
+}
+
+documentaction::~documentaction () {
+}
+
+bool documentaction::check_cgiargs (cgiargsinfoclass &argsinfo, cgiargsclass &args, 
+				    ostream &logout) {
+
+  // check gc argument
+  int arg_gc = args.getintarg("gc");
+  if (arg_gc != 0 && arg_gc != 1) {
+    logout << "Warning: \"gc\" argument out of range (" << arg_gc << ")\n";
+    cgiarginfo *gcinfo = argsinfo.getarginfo ("gc");
+    if (gcinfo != NULL) args["gc"] = gcinfo->argdefault;
+  }
+
+  // check gt argument (may be either 0, 1 or 2)
+  int arg_gt = args.getintarg("gt");
+  if (arg_gt != 0 && arg_gt != 1 && arg_gt != 2) {
+    logout << "Warning: \"gt\" argument out of range (" << arg_gt << ")\n";
+    cgiarginfo *gtinfo = argsinfo.getarginfo ("gt");
+    if (gtinfo != NULL) args["gt"] = gtinfo->argdefault;
+  }
+
+  // check hl argument
+  int arg_hl = args.getintarg("hl");
+  if (arg_hl != 0 && arg_hl != 1) {
+    logout << "Warning: \"hl\" argument out of range (" << arg_hl << ")\n";
+    cgiarginfo *hlinfo = argsinfo.getarginfo ("hl");
+    if (hlinfo != NULL) args["hl"] = hlinfo->argdefault;
+  }
+
+  // check x argument
+  int arg_x = args.getintarg("x");
+  if (arg_x != 0 && arg_x != 1) {
+    logout << "Warning: \"x\" argument out of range (" << arg_x << ")\n";
+    cgiarginfo *xinfo = argsinfo.getarginfo ("x");
+    if (xinfo != NULL) args["x"] = xinfo->argdefault;
+  }
+
+  return true;
+}
+
+void documentaction::get_cgihead_info (cgiargsclass &args, recptprotolistclass *protos,
+				       response_t &response,text_t &response_data, 
+				       ostream &logout) {
+
+  if ((args["il"] == "w") && (!args["d"].empty())) {
+
+    recptproto* collectproto = protos->getrecptproto (args["c"], logout);
+    if (collectproto != NULL) {
+      
+      text_tset metadata;
+      FilterResponse_t filt_response;
+      text_t top;
+
+      metadata.insert ("URL");
+      
+      // get metadata for parent document
+      get_top (args["d"], top);
+      if (get_info (top, args["c"], metadata, false, collectproto, filt_response, logout)) {
+	text_t url = filt_response.docInfo[0].metadata["URL"].values[0];
+	
+	response = location;
+	response_data = url;
+	return;
+      } else {
+	// error, no URL
+	logout << "Error: documentaction::get_cgihead_info failed on get_info" << endl;
+      }
+    }
+  }
+  response = content;
+  response_data = "text/html";
+}
+
+// set_widthtspace calculates how wide the spaces in the nav bar should
+// be and sets the appropriate macro
+void documentaction::set_spacemacro (displayclass &disp, FilterResponse_t &response) {
+
+  text_t width;
+  int twidth, swidth, iwidth = 0;
+
+  int numc = response.docInfo.size();
+  ResultDocInfo_tarray::iterator dochere = response.docInfo.begin();
+  ResultDocInfo_tarray::iterator docend = response.docInfo.end();
+	
+  disp.expandstring ("Global", "_pagewidth_", width);
+  twidth = width.getint();
+	  
+  disp.expandstring ("query", "_searchwidth_", width);
+  iwidth += width.getint();
+  
+  
+  
+  while (dochere != docend) {
+    const text_t &title = (*dochere).metadata["Title"].values[0];
+
+    disp.expandstring ("document", "_" + title + "width_", width);
+    if (width == ("_" + title + "width_")) 
+      disp.expandstring ("document", "_defaultwidth_", width);
+    iwidth += width.getint();
+    dochere ++;
+  }
+  if ((twidth - iwidth) < numc) swidth = 2;
+  else {
+    swidth = twidth - iwidth;
+    if (numc > 0) swidth = swidth / numc;
+  }
+  disp.setmacro ("widthtspace", "Global", swidth);
+}
+
+// set_navbarmacros sets _navigationbar_, _javaimagesnavbar_ and _httpbrowseXXX_ macros
+// reponse contains 1 metadata field (Title)
+void documentaction::set_navbarmacros (displayclass &disp, FilterResponse_t &response, 
+				       cgiargsclass &args) {
+
+  text_t javaimagesnavbar, topparent;
+  text_t &arg_d = args["d"];
+  text_t navigationbar = "<!-- Navigation Bar -->\n";
+
+  get_top (args["cl"], topparent);
+  int numc = response.docInfo.size();
+  ResultDocInfo_tarray::iterator dochere = response.docInfo.begin();
+  ResultDocInfo_tarray::iterator docend = response.docInfo.end();
+
+  navigationbar += "<nobr>\n";
+  if (args["a"] == "q") {
+    navigationbar += "_icontabsearchgreen_";
+  } else {
+    navigationbar += "_imagesearch_";
+    javaimagesnavbar = "_javasearch_";
+  }
+  
+  
+  if (numc == 0) navigationbar += "_imagespacer_";
+	
+  while (dochere != docend) {
+    text_t title = (*dochere).metadata["Title"].values[0];
+
+    bool unknown = false;
+
+    // test the _XXXwidth_ macro to see if image macros are
+    // defined for this type of classification - if not we'll
+    // just display the text
+    text_t tmpwidth;
+    disp.expandstring ("document", "_" + title + "width_", tmpwidth);
+    if (tmpwidth == ("_" + title + "width_")) unknown = true;
+
+    // if we're inside a document all the classification buttons should be enabled
+    if (arg_d.empty() && ((*dochere).OID == topparent)) {
+      if (unknown) navigationbar += "_imagespacer_&nbsp;" + title + "&nbsp;";
+      else navigationbar += "_imagespacer__icontab" + title + "green_";
+    } else {
+
+      // set the _httpbrowseXXX_ macro for this classification
+      if (unknown) navigationbar += "_imagespacer_&nbsp;<a href=\"_httpdocument_&cl=" + 
+		     (*dochere).OID + "\">" + title + "</a>&nbsp;";
+      else {
+        navigationbar += "_imagespacer__image" + title + "_";
+        disp.setmacro ("httpbrowse" + title, "Global", "_httpdocument_&cl=" + (*dochere).OID);
+      }
+    }
+    if (!unknown) javaimagesnavbar += "_java" + title + "_";
+    dochere ++;
+  }
+  navigationbar += "\n</nobr>\n";
+  navigationbar += "<!-- End of Navigation Bar -->\n";
+  disp.setmacro ("navigationbar", "Global", navigationbar);
+  if (args.getintarg("v") == 0)
+    disp.setmacro ("javaimagesnavbar", "Global", javaimagesnavbar);
+}
+
+// define all the macros which might be used by other actions
+// to produce pages. 
+void documentaction::define_external_macros (displayclass &disp, cgiargsclass &args, 
+					     recptprotolistclass *protos, ostream &logout) {
+  
+  // define_external_macros sets the following macros:
+
+  // _navigationbar_     this is the navigation bar containing the search button
+  //                     and any classification buttons - it goes at the top of 
+  //                     most pages. for now we're assuming that there'll always 
+  //                     be a search button - we should probably check that there
+  //                     is a query action before making this assumption
+
+  // _httpbrowseXXX_     the http macros for each classification (i.e. if there
+  //                     are Title and Creator classifications _httpbrowseTitle_
+  //                     and _httpbrowseCreator_ will be set
+
+  // _javaimagesnavbar_  this is the javascript code to shove in to make the 
+  //                     flashy images used by _navigationbar_ work
+
+  // _widthtspace_       the width of the spacers between buttons in navigation
+  //                     bar
+  
+  // _httpdocument_      has '&f=1' added if displaying document inside a frame
+
+  // _gsdltop_           macro to replace _top targets with
+
+  // _httppagehome_      overridden home url if html collections have own homepage
+
+  // must have a valid collection server to continue
+  text_t &collection = args["c"];
+  if (collection.empty()) return;
+  recptproto *collectproto = protos->getrecptproto (collection, logout);
+  if (collectproto == NULL) return;
+  
+  if (recpt == NULL) {
+    logout << "ERROR (documentaction::define_external_macros): This action does not contain\n"
+	   << "      information about any receptionists. The method set_receptionist was\n"
+	   << "      probably not called from the module which instantiated this action.\n";
+    return;
+  }
+
+  outconvertclass text_t2ascii;
+  comerror_t err;
+  InfoFiltersResponse_t filterinfo;
+  FilterResponse_t response;
+  text_tset metadata;
+
+  ColInfoResponse_t *cinfo = recpt->get_collectinfo_ptr (collectproto, collection, logout);
+  if (cinfo == NULL) {
+    logout << "ERROR (documentaction::define_external_macros): get_collectinfo_ptr returned NULL\n";
+    return;
+  }
+  load_formatinfo (cinfo->format, args.getintarg("gt"));
+
+  if (formatinfo.DocumentUseHTML) {
+
+    // frame stuff
+    if (args["fc"] == "1") {
+      text_t httpdocument;
+      disp.expandstring ("Global", "_httpdocument_", httpdocument);
+      httpdocument += "&f=1";
+      disp.setmacro ("httpdocument", "Global", httpdocument);
+      disp.setmacro ("gsdltop", "Global", "documenttop");
+    }
+    text_tmap::iterator it = cinfo->format.find ("homepage");
+    if (it != cinfo->format.end()) {
+      text_t httppagehome;
+      if (get_link (args, protos, (*it).second, httppagehome, logout))
+	disp.setmacro ("httppagehome", "Global", httppagehome);
+    } 
+  }
+
+  // don't want navigation bar if page is 'detached'
+  if (!args.getintarg("x")) {
+
+    collectproto->get_filterinfo (collection, filterinfo, err, logout);
+    if (err == noError) {
+      // check that there's a browse filter
+      if (filterinfo.filterNames.find ("BrowseFilter") != filterinfo.filterNames.end()) {
+	
+	metadata.insert ("Title");
+	bool getParents = false;
+	get_children ("", collection, metadata, getParents, collectproto, response, logout);
+	
+	// calculate width of spacers and set _widthtspace_ macro
+	if (args.getintarg("v") == 0) set_spacemacro (disp, response);
+
+	// set _navigationbar_ and _javaimagesnavbar_ macros
+	set_navbarmacros (disp, response, args);
+   
+      }
+    } else {
+      logout << text_t2ascii 
+	     << "Error (documentaction::define_external_macros()) in call to get_filterinfo() " 
+	     << get_comerror_string (err);
+    }
+  }
+}
+
+bool documentaction::get_link (cgiargsclass &args, recptprotolistclass *protos,
+			       const text_t &inlink, text_t &outlink, ostream &logout) {
+
+  FilterResponse_t response;
+  text_tset metadata;
+  metadata.insert ("section");
+  
+  // check current collection first
+  recptproto *collectproto = protos->getrecptproto (args["c"], logout);
+
+  if (get_info (inlink, args["c"], metadata, false, collectproto, response, logout)) {
+    if (!response.docInfo[0].metadata["section"].values[0].empty()) {
+      outlink = "_httpdocument_&d=" + response.docInfo[0].metadata["section"].values[0];
+      return true;
+    }
+  }
+
+  // check all the other enabled collections
+
+  if (args["ccs"] == "1" && !args["cc"].empty()) {
+    text_tarray collections;
+    splitchar (args["cc"].begin(), args["cc"].end(), ',', collections);
+    
+    text_tarray::const_iterator col_here = collections.begin();
+    text_tarray::const_iterator col_end = collections.end();
+
+    while (col_here != col_end) {
+	  
+      // don't need to check current collection again
+      if (*col_here == args["c"]) {col_here ++; continue;}
+	  
+      collectproto = protos->getrecptproto (*col_here, logout);
+      
+      if (get_info (inlink, *col_here, metadata, false, collectproto, response, logout)) {
+	if (!response.docInfo[0].metadata["section"].values[0].empty()) {
+	  outlink = "_httpdocument_&c=" + *col_here + "&d=" +
+	    response.docInfo[0].metadata["section"].values[0];
+	  return true;
+	}
+      }
+      col_here ++;
+    }
+  }
+  return false;
+}
+
+void documentaction::load_formatinfo (const text_tmap &colformat, int gt) {
+
+  formatinfo.clear();
+  text_tmap::const_iterator format_here = colformat.begin();
+  text_tmap::const_iterator format_end = colformat.end();
+
+  while (format_here != format_end) {
+    if (((*format_here).first == "DocumentImages") && 
+	((*format_here).second == "true"))
+      formatinfo.DocumentImages = true;
+    else if (((*format_here).first == "DocumentTitles") && 
+	     ((*format_here).second == "false"))
+      formatinfo.DocumentTitles = false;
+    else if ((*format_here).first == "DocumentHeading") 
+      formatinfo.DocumentHeading = (*format_here).second;
+    else if (((*format_here).first == "DocumentContents") && 
+	     ((*format_here).second == "false"))
+      formatinfo.DocumentContents = false;
+    else if (((*format_here).first == "DocumentArrowsBottom") && 
+	     ((*format_here).second == "false"))
+      formatinfo.DocumentArrowsBottom = false;
+    else if ((*format_here).first == "DocumentButtons")
+      splitchar ((*format_here).second.begin(), (*format_here).second.end(),
+		 '|', formatinfo.DocumentButtons);
+    else if ((*format_here).first == "DocumentText") 
+      formatinfo.DocumentText = (*format_here).second;
+    else if (((*format_here).first == "DocumentUseHTML") && 
+	     ((*format_here).second == "true"))
+      formatinfo.DocumentUseHTML = true;
+    else 
+      formatinfo.formatstrings[(*format_here).first] = (*format_here).second;
+    
+    format_here ++;
+  }
+
+  // never want arrows when text is expanded
+  if (gt) formatinfo.DocumentArrowsBottom = false;
+}
+
+void documentaction::set_java_macros (cgiargsclass &args, displayclass &disp) {
+
+  text_t javaimagescontent = "_javaextras_";
+	
+  int arg_gt = args.getintarg("gt");
+  int arg_gc = args.getintarg("gc");
+  int arg_hl = args.getintarg("hl");
+
+  text_tarray::const_iterator button_here = formatinfo.DocumentButtons.begin();
+  text_tarray::const_iterator button_end = formatinfo.DocumentButtons.end();
+
+  while (button_here != button_end) {
+    if (*button_here == "Detach") 
+      javaimagescontent += "_javadetach_";
+    else if (*button_here == "Expand Text") {
+      if (arg_gt == 1)
+	javaimagescontent += "_javacontracttext__javacontinue_";
+      else if (arg_gt == 2)
+	javaimagescontent += "_javacontracttext_";
+      else
+	javaimagescontent += "_javaexpandtext_";
+    } else if (*button_here == "Expand Contents") {
+      if (arg_gc == 1)
+	javaimagescontent += "_javacontractcontents_";
+      else
+	javaimagescontent += "_javaexpandcontents_";
+    } else if (*button_here == "Highlight") {
+      if (arg_hl == 1)
+	javaimagescontent += "_javanohighlighting_";
+      else 
+	javaimagescontent += "_javahighlighting_";
+    }
+    button_here ++;
+  }
+  disp.setmacro ("javaimagescontent", "document", javaimagescontent);
+}
+
+
+// define all the macros which are related to pages generated
+// by this action. we also load up the formatinfo structure 
+// here (it's used in do_action as well as here)
+void documentaction::define_internal_macros (displayclass &disp, cgiargsclass &args, 
+					     recptprotolistclass *protos, ostream &logout) {
+  
+  // define_internal_macros sets the following macros:
+  
+  // _pagetitle_            the title to be displayed at the top of the browser window
+  
+  // _imagethispage_        the title image to be displayed at top right of page
+
+  // _navarrows_            this may be overridden to "" when format option 
+  //                        DocumentArrowsBottom is false
+
+  // _header_               the header macro is overridden if we're not at a top level 
+  //                        classification to remove the title block
+
+  // _javaimagescontent_    this is the javascript code to shove in to make the 
+  //                        flashy buttons work
+
+  // _thisOID_              the OID (directory) of the current document - this corresponds
+  //                        to the archivedir metadata element
+
+  // must have a valid collection server to continue
+  text_t &collection = args["c"];
+  if (collection.empty()) return;
+  recptproto *collectproto = protos->getrecptproto (collection, logout);
+  if (collectproto == NULL) return;
+
+  text_tset metadata;
+  FilterResponse_t response;
+  text_t &arg_d = args["d"];
+  text_t &arg_cl = args["cl"];
+
+  if (!formatinfo.DocumentArrowsBottom)
+    disp.setmacro("navarrows", "document", "");
+
+  metadata.insert ("Title");
+
+  bool fulltoc = false;
+
+  if (args["cl"] != "search") {
+    // see if there's a FullTOC string
+    text_t cl_top, full_toc;
+    get_top (arg_cl, cl_top);
+    if (get_formatstring (cl_top, "FullTOC", formatinfo.formatstrings, full_toc))
+      if (full_toc == "true") fulltoc = true;
+  }
+  
+  if (!arg_d.empty() && !fulltoc) {
+    // we're at document level
+
+    metadata.insert ("archivedir");
+    
+    // get metadata for this document and it's parents
+    if (get_info (arg_d, collection, metadata, true, collectproto, response, logout)) {
+      disp.setmacro ("header", "document", "_textheader_");
+
+      text_tarray pagetitlearray;
+      if (!response.docInfo[0].metadata["Title"].values[0].empty())
+	pagetitlearray.push_back (response.docInfo[0].metadata["Title"].values[0]);
+      if (args["gt"] != "1") {
+	MetadataInfo_t *parenttitle = response.docInfo[0].metadata["Title"].parent;
+	while (parenttitle != NULL) {
+	  if (!parenttitle->values[0].empty())
+	    pagetitlearray.push_back (parenttitle->values[0]);
+	  parenttitle = parenttitle->parent;
+	}
+      }
+      reverse (pagetitlearray.begin(), pagetitlearray.end());
+      text_t pagetitle;
+      joinchar (pagetitlearray, ": ", pagetitle);
+      disp.setmacro ("pagetitle", "document", pagetitle);
+
+      if (is_top (arg_d))
+	disp.setmacro ("thisOID", "Global", dm_safe(response.docInfo[0].metadata["archivedir"].values[0]));
+      else {
+	MetadataInfo_t *parentad = response.docInfo[0].metadata["archivedir"].parent;
+	text_t thisOID;
+	while (parentad != NULL) {
+	  thisOID = parentad->values[0];
+	  parentad = parentad->parent;
+	}
+	disp.setmacro ("thisOID", "Global", dm_safe(thisOID));
+      }
+      
+      if (args["u"] != "1")
+	set_java_macros (args, disp);
+
+    }
+  } else {
+    if (!arg_cl.empty()) {
+	
+      // get metadata for top level classification
+      text_t classtop;
+      get_top (arg_cl, classtop);
+      if (get_info (classtop, collection, metadata, false, collectproto, response, logout)) {
+	  
+	text_t &title = response.docInfo[0].metadata["Title"].values[0];
+	bool unknown = false;
+
+	// test the _XXXwidth_ macro to see if image macros are
+	// defined for this type of classification - if not we'll
+	// just display the text
+	text_t tmp;
+	disp.expandstring ("document", "_" + title + "width_", tmp);
+	if (tmp == ("_" + title + "width_")) unknown = true;
+
+	if (unknown) {
+	  disp.setmacro ("pagetitle", "document", title);
+	  disp.setmacro ("imagethispage", "document", "<h2>" + title + "</h2>");
+	} else {
+	  disp.setmacro ("pagetitle", "document", "_text" + title + "page_");
+	  disp.setmacro ("imagethispage", "document", "_icon" + title + "page_");
+	}
+      }
+    }
+  }
+}
+
+
+bool documentaction::do_action (cgiargsclass &args, recptprotolistclass *protos, 
+				browsermapclass *browsers, displayclass &disp, 
+				outconvertclass &outconvert, ostream &textout, 
+				ostream &logout) {
+
+
+  // must have a valid collection server
+  recptproto *collectproto = protos->getrecptproto (args["c"], logout);
+  if (collectproto == NULL) {
+    logout << "documentaction::do_action called with NULL collectproto\n";
+    textout << outconvert << disp << "_document:header_\n" 
+	    << "Error: Attempt to get document without setting collection\n"
+	    << "_document:footer_\n";
+  } else {  
+    
+    text_t OID = args["d"];
+    if (OID.empty()) OID = args["cl"];
+    if (OID.empty()) {
+      textout << outconvert << disp << "Document contains no data_document:footer_\n";
+      return true;
+    }
+
+    if (formatinfo.DocumentUseHTML) {
+      
+      if (!args["d"].empty()) {
+	if (args["f"] == "1") {
+	  textout << outconvert << disp 
+		  << "<html><head></head>\n"
+		  << "<frameset rows=\"68,*\" noresize border=0>\n"
+		  << "<frame scrolling=no frameborder=0 src=\"_gwcgi_?e=_compressedoptions_&a=p&p=nav\">\n"
+		  << "<frame name=\"documenttop\" frameborder=0 src=\"_gwcgi_?e=_compressedoptions_&a=d&d=" 
+		  << args["d"] << "\">"
+		  << "<noframes>\n"
+		  << "<p>You must have a frame enabled browser to view this.</p>\n"
+		  << "</noframes>\n"
+		  << "</frameset>\n"
+		  << "</html>\n";
+	} else {
+	  output_document (OID, args, collectproto, disp, outconvert, textout, logout);	
+	}
+	return true;
+      }
+    }
+
+    textout << outconvert << disp << "_document:header_\n"
+	    << "_document:content_\n";
+      
+    // output the table of contents
+    output_toc (args, browsers, formatinfo, collectproto, 
+		disp, outconvert, textout, logout);
+    
+    // output the document text
+    textout << "<p>\n";
+    output_document (OID, args, collectproto, disp, outconvert, textout, logout);
+
+    textout << outconvert << disp << "_document:footer_\n";
+  }
+  return true;
+}
+
+void documentaction::output_text (ResultDocInfo_t &docinfo, format_t *formatlistptr,
+				  const TermInfo_tarray &terminfo, const text_t &OID,
+				  bool highlight, int hastxt, int wanttext, 
+				  text_t &collection, recptproto *collectproto, 
+				  displayclass &disp, outconvertclass &outconvert, 
+				  ostream &textout, ostream &logout) {
+  
+  DocumentRequest_t docrequest;
+  DocumentResponse_t docresponse;
+  comerror_t err;
+
+  if (hastxt == 1) {
+
+    if (wanttext) {
+      // get the text
+      docrequest.OID = OID;
+      collectproto->get_document (collection, docrequest, docresponse, err, logout);
+
+      // cut down on overhead by not using formattools if we only want the text
+      // (wanttext will equal 2 if we want text and other stuff too)
+      if (wanttext == 1)
+	if (highlight)
+	  highlighttext(docresponse.doc, terminfo, disp, outconvert, textout, logout);
+	else
+	  textout << outconvert << disp << docresponse.doc;
+    }
+  
+    if (wanttext != 1) {
+      text_t doctext = get_formatted_string (docinfo, formatlistptr, docresponse.doc); 
+      
+      if (highlight)
+	highlighttext(doctext, terminfo, disp, outconvert, textout, logout);
+      else
+	textout << outconvert << disp << doctext;
+    }
+  }
+}
+
+
+void documentaction::output_document (const text_t &OID, cgiargsclass &args, 
+				      recptproto *collectproto, displayclass &disp, 
+				      outconvertclass &outconvert, ostream &textout, 
+				      ostream &logout) {
+  FilterResponse_t inforesponse;
+  FilterResponse_t queryresponse;
+  text_tset metadata;
+  bool getParents = false;
+  bool highlight = false;
+  int wanttext = 0;
+  int arg_gt = args.getintarg("gt");
+  text_t &collection = args["c"];
+    
+  // if we have a query string and highlighting is turned on we need
+  // to redo the query to get the terms for highlighting
+  if (!args["q"].empty() && args.getintarg("hl")) {
+    FilterRequest_t request;
+    comerror_t err;
+    request.filterResultOptions = FRmatchTerms;
+    text_t formattedstring = args["q"];
+    format_querystring (formattedstring, args.getintarg("b"));
+    set_queryfilter_options (request, formattedstring, args);
+    collectproto->filter (args["c"], request, queryresponse, err, logout);
+    if (err != noError) {
+      outconvertclass text_t2ascii;
+      logout << text_t2ascii
+	     << "documentaction::output_document: call to QueryFilter failed "
+	     << "for " << args["c"] << " collection (" << get_comerror_string (err) << ")\n";
+      highlight = false;
+    } else {
+      highlight = true;
+    }
+  }
+
+  format_t *formatlistptr = new format_t();
+  parse_formatstring (formatinfo.DocumentText, formatlistptr, metadata, getParents);
+
+  metadata.insert ("hastxt");
+  metadata.insert ("haschildren");
+  
+  if (formatinfo.DocumentText == "[Text]")
+    wanttext = 1;
+  else {
+    char *docformat = formatinfo.DocumentText.getcstr();
+    if (strstr (docformat, "[Text]") != NULL)
+      wanttext = 2;
+    delete docformat;
+  }
+    
+  if (get_info (OID, collection, metadata, getParents, collectproto, inforesponse, logout)) {
+    int hastxt = inforesponse.docInfo[0].metadata["hastxt"].values[0].getint();
+    int haschildren = inforesponse.docInfo[0].metadata["haschildren"].values[0].getint();
+    
+    if (arg_gt == 0) {
+      output_text (inforesponse.docInfo[0], formatlistptr, queryresponse.termInfo, 
+		   OID, highlight, hastxt, wanttext, collection, collectproto, 
+		   disp, outconvert, textout, logout);
+
+
+    } else {
+
+      ResultDocInfo_t thisdocinfo = inforesponse.docInfo[0];
+	
+      // text is to be expanded
+      text_t exOID = OID;
+      if (haschildren != 1) exOID = get_parent (OID);
+      if (exOID.empty()) exOID = OID;
+	
+      // if we're not in a document (i.e. we're in a top level classification)
+      // we need to pass "is_classify = true" to get_contents so that it 
+      // doesn't recurse all the way through each document in the classification
+      bool is_classify = false;
+      if (args["d"].empty()) is_classify = true;
+
+      get_contents (exOID, is_classify, metadata, collection, 
+		    collectproto, inforesponse, logout);
+	
+      ResultDocInfo_tarray::iterator sechere = inforesponse.docInfo.begin();
+      ResultDocInfo_tarray::iterator secend = inforesponse.docInfo.end();
+	
+      if (arg_gt == 1) {
+	// check if there are more than 10 sections containing text to be expanded - 
+	// if there are output warning message - this isn't a great way to do this
+	// since the sections may be very large or very small - one day I'll fix it 
+	// -- Stefan.
+	int seccount = 0;
+	while (sechere != secend) {
+	  int shastxt = (*sechere).metadata["hastxt"].values[0].getint();
+	  if (shastxt == 1) seccount ++;
+	  if (seccount > 10) break;
+	  sechere ++;
+	}
+	if (seccount > 10) {
+	  // more than 10 sections so output warning message and text 
+	  // for current section only
+	  textout << outconvert << disp << "_document:textltwarning_";
+
+	  output_text (thisdocinfo, formatlistptr, queryresponse.termInfo, 
+		       OID, highlight, hastxt, wanttext, collection, 
+		       collectproto, disp, outconvert, textout, logout);
+	  
+	}
+	else arg_gt = 2;
+      }
+
+      if (arg_gt == 2) {
+	// get the text for each section
+	sechere = inforesponse.docInfo.begin();
+	int count = 0;
+	while (sechere != secend) {
+	  textout << outconvert << disp << "\n<p><a name=" << count << "></a>\n";
+
+	  int shastxt = (*sechere).metadata["hastxt"].values[0].getint();
+
+	  output_text (*sechere, formatlistptr, queryresponse.termInfo, 
+		       (*sechere).OID, highlight, shastxt, wanttext, collection, 
+		       collectproto, disp, outconvert, textout, logout);
+	  count ++;
+	  sechere ++;
+	}
+      }
+    }
+  }
+  delete formatlistptr;
+}
+
+// highlighttext highlights query terms in text string and outputs the resulting text string
+void documentaction::highlighttext(text_t &text, const TermInfo_tarray &terms, 
+				   displayclass &disp, outconvertclass &outconvert, 
+				   ostream &textout, ostream &/*logout*/) {
+
+  text_tmap allterms;
+  text_tmap::const_iterator it;
+
+  // first load all the term variations into a map
+  TermInfo_tarray::const_iterator this_term = terms.begin();
+  TermInfo_tarray::const_iterator last_term = terms.end();
+  while (this_term != last_term) {
+    text_tarray::const_iterator this_var = (*this_term).matchTerms.begin();
+    text_tarray::const_iterator last_var = (*this_term).matchTerms.end();
+    while (this_var != last_var) {
+      allterms[*this_var] = 1;
+      this_var ++;
+    }
+    this_term ++;
+  }
+
+  // get the text to start and end a hightlight
+  text_t starthighlight = "<b><u>";
+  text_t endhighlight = "</u></b>";
+  if (disp.isdefaultmacro("Global", "starthighlight"))
+    disp.expandstring("Global", "_starthighlight_", starthighlight);
+  if (disp.isdefaultmacro("Global", "endhighlight"))
+    disp.expandstring("Global", "_endhighlight_", endhighlight);
+
+
+  text_t::iterator here = text.begin(); 
+  text_t::iterator end = text.end();
+  text_t word, buffer;
+  while (here != end) {
+    if (is_unicode_letdig(*here)) {
+      // not word boundary
+      word.push_back(*here);
+      here++;
+
+    } else {
+      // found word boundary
+      // add last word if there was one
+      if (!word.empty()) {
+	it = allterms.find(word);
+	if (it != allterms.end()) {
+	  word = starthighlight + word + endhighlight;
+	}
+	buffer += word;
+        word.clear();
+      }
+
+      if (*here == '<') {
+        // skip over rest of html tag
+	while ((here != end) && (*here != '>')) {
+	  buffer.push_back(*here);
+	  here++;
+	}
+      }
+
+      buffer.push_back(*here);
+      here++;
+
+      if (buffer.size() > 1024) {
+	textout << outconvert << disp << buffer;
+	buffer.clear();
+      }
+    }
+  }
+  textout << outconvert << disp << buffer;
+}
Index: /main/tags/2.25/gsdl/src/recpt/documentaction.h
===================================================================
--- /main/tags/2.25/gsdl/src/recpt/documentaction.h	(revision 21064)
+++ /main/tags/2.25/gsdl/src/recpt/documentaction.h	(revision 21064)
@@ -0,0 +1,105 @@
+/**********************************************************************
+ *
+ * documentaction.h -- 
+ * Copyright (C) 1999  The New Zealand Digital Library Project
+ *
+ * A component of the Greenstone digital library software
+ * from the New Zealand Digital Library Project at the
+ * University of Waikato, New Zealand.
+ *
+ * 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.
+ *
+ *********************************************************************/
+
+
+#ifndef DOCUMENTACTION_H
+#define DOCUMENTACTION_H
+
+#include "action.h"
+#include "gsdlconf.h"
+#include "formattools.h"
+#include "receptionist.h"
+
+class documentaction : public action {
+
+protected:
+
+  receptionist *recpt;
+
+  bool get_link (cgiargsclass &args, recptprotolistclass *protos,
+		 const text_t &inlink, text_t &outlink, ostream &logout);
+
+  void load_formatinfo (const text_tmap &colformat, int gt);
+
+  void set_spacemacro (displayclass &disp, FilterResponse_t &response);
+
+  void set_navbarmacros (displayclass &disp, FilterResponse_t &response, 
+			 cgiargsclass &args);
+
+  virtual void set_java_macros (cgiargsclass &args, displayclass &disp);
+
+  void get_classificationlinks (const text_t &arg_cl, const text_t &collection,
+				recptproto *collectproto, displayclass &disp, 
+				ostream &logout);
+
+  virtual void output_text (ResultDocInfo_t &docinfo, format_t *formatlistptr,
+			    const TermInfo_tarray &terminfo, const text_t &OID,
+			    bool highlight, int hastxt, int wanttext, 
+			    text_t &collection, recptproto *collectproto,
+			    displayclass &disp, outconvertclass &outconvert,
+			    ostream &textout, ostream &logout);
+
+  virtual void output_document (const text_t &OID, cgiargsclass &args, 
+				recptproto *collectproto, displayclass &disp, 
+				outconvertclass &outconvert, ostream &textout, 
+				ostream &logout);
+
+  void highlighttext(text_t &text, const TermInfo_tarray &terms, 
+		     displayclass &disp, outconvertclass &outconvert, 
+		     ostream &textout, ostream &logout);
+
+  formatinfo_t formatinfo;
+
+public:
+  documentaction ();
+  virtual ~documentaction ();
+
+  void set_receptionist (receptionist *therecpt) {recpt=therecpt;}
+
+  text_t get_action_name () {return "d";}
+
+  bool check_cgiargs (cgiargsinfoclass &argsinfo, cgiargsclass &args, 
+		      ostream &logout);
+
+  void get_cgihead_info (cgiargsclass &args, recptprotolistclass *protos,
+			 response_t &response,text_t &response_data, 
+			 ostream &logout);
+
+  void define_external_macros (displayclass &disp, cgiargsclass &args, 
+			       recptprotolistclass *protos, ostream &logout);
+
+  void define_internal_macros (displayclass &disp, cgiargsclass &args, 
+			       recptprotolistclass *protos, ostream &logout);
+
+  bool do_action (cgiargsclass &args, recptprotolistclass *protos, 
+		  browsermapclass *browsers, displayclass &disp, 
+		  outconvertclass &outconvert, ostream &textout, 
+		  ostream &logout);
+
+};
+
+
+
+#endif
Index: /main/tags/2.25/gsdl/src/recpt/extlinkaction.cpp
===================================================================
--- /main/tags/2.25/gsdl/src/recpt/extlinkaction.cpp	(revision 21064)
+++ /main/tags/2.25/gsdl/src/recpt/extlinkaction.cpp	(revision 21064)
@@ -0,0 +1,249 @@
+/**********************************************************************
+ *
+ * extlinkaction.cpp -- 
+ * Copyright (C) 1999  The New Zealand Digital Library Project
+ *
+ * A component of the Greenstone digital library software
+ * from the New Zealand Digital Library Project at the
+ * University of Waikato, New Zealand.
+ *
+ * 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.
+ *
+ *********************************************************************/
+
+
+#include <string.h>
+#include "extlinkaction.h"
+#include "OIDtools.h"
+#include "cgiutils.h"
+
+extlinkaction::extlinkaction () {
+
+  // this action uses cgi variables "a", "d", and "href"
+
+  cgiarginfo arg_ainfo;
+  arg_ainfo.shortname = "a";
+  arg_ainfo.longname = "action";
+  arg_ainfo.multiplechar = true;
+  arg_ainfo.defaultstatus = cgiarginfo::weak;
+  arg_ainfo.argdefault = "extlink";
+  arg_ainfo.savedarginfo = cgiarginfo::must;
+  argsinfo.addarginfo (NULL, arg_ainfo);
+
+  arg_ainfo.shortname = "el";
+  arg_ainfo.longname = "external link preference";
+  arg_ainfo.multiplechar = true;
+  arg_ainfo.defaultstatus = cgiarginfo::weak;
+  arg_ainfo.argdefault = "prompt";
+  arg_ainfo.savedarginfo = cgiarginfo::must;
+  argsinfo.addarginfo (NULL, arg_ainfo);
+
+  arg_ainfo.shortname = "d";
+  arg_ainfo.longname = "document OID";
+  arg_ainfo.multiplechar = true;
+  arg_ainfo.defaultstatus = cgiarginfo::none;
+  arg_ainfo.argdefault = "";
+  arg_ainfo.savedarginfo = cgiarginfo::can;
+  argsinfo.addarginfo (NULL, arg_ainfo);
+
+  arg_ainfo.shortname = "href";
+  arg_ainfo.longname = "URL of external link";
+  arg_ainfo.multiplechar = true;
+  arg_ainfo.defaultstatus = cgiarginfo::none;
+  arg_ainfo.argdefault = "";
+  arg_ainfo.savedarginfo = cgiarginfo::can;
+  argsinfo.addarginfo (NULL, arg_ainfo);
+
+  arg_ainfo.shortname = "rl";
+  arg_ainfo.longname = "is relative link";
+  arg_ainfo.multiplechar = false;
+  arg_ainfo.defaultstatus = cgiarginfo::none;
+  arg_ainfo.argdefault = "0";
+  arg_ainfo.savedarginfo = cgiarginfo::mustnot;
+  argsinfo.addarginfo (NULL, arg_ainfo);
+
+}
+
+extlinkaction::~extlinkaction () {
+}
+
+
+void extlinkaction::get_cgihead_info (cgiargsclass &args, recptprotolistclass *protos,
+				      response_t &response, text_t &response_data, 
+				      ostream &logout) {
+
+  text_t link;
+  if (get_link (args, protos, link, logout)) {
+    response = location;
+    response_data = link;
+    return;
+  }
+
+  // external link
+  if (!link.empty()) {
+    if (args["el"] == "direct") {
+      response = location;
+      response_data = link;
+      return;
+    }
+  }
+
+  response = content;
+  response_data = "text/html";
+}
+
+void extlinkaction::define_internal_macros (displayclass &disp, cgiargsclass &args, 
+					    recptprotolistclass * /*protos*/, 
+					    ostream &/*logout*/) {
+  
+  // define_internal_macros sets the following macros:
+
+  // _nexturl_             link to external page
+  // _prevdoc_             link to previous document
+  
+  disp.setmacro("nexturl", "extlink", args["href"]);
+  disp.setmacro("prevdoc", "extlink", args["d"]);
+}
+
+
+// if link is found returns true and url in link, otherwise returns
+// false
+bool extlinkaction::get_link (cgiargsclass &args, recptprotolistclass *protos,
+			      text_t &link, ostream &logout) {
+
+    text_t &arg_href = args["href"];
+    text_t &thiscollection = args["c"];
+    if (arg_href.empty()) return false;
+
+    if (args["rl"] == "1") {
+
+      FilterResponse_t response;
+      text_tset metadata;
+      metadata.insert ("section");
+	  
+      recptproto *collectproto = protos->getrecptproto (thiscollection, logout);
+
+      if (get_info (arg_href, thiscollection, metadata, false, collectproto, response, logout)) {
+	if (!response.docInfo[0].metadata["section"].values[0].empty()) {
+	  link = "_httpdoc_&d=" + response.docInfo[0].metadata["section"].values[0];
+	  return true;
+	}
+      }
+
+      // need to see if link exists in any other collection
+      // if cross-collection searching/browsing is turned on 
+      if (args["ccs"] == "1" && !args["cc"].empty()) {
+	text_tarray collections;
+	splitchar (args["cc"].begin(), args["cc"].end(), ',', collections);
+
+	text_tarray::const_iterator col_here = collections.begin();
+	text_tarray::const_iterator col_end = collections.end();
+
+	while (col_here != col_end) {
+	  
+	  // don't need to check current collection again
+	  if (*col_here == thiscollection) {col_here ++; continue;}
+	  
+	  recptproto *collectproto = protos->getrecptproto (*col_here, logout);
+	  if (collectproto == NULL) {col_here ++; continue;}
+
+	  if (get_info (arg_href, *col_here, metadata, false, collectproto, response, logout)) {
+	    if (!response.docInfo[0].metadata["section"].values[0].empty()) {
+	      link = "_httpdoc_&c=" + *col_here + "&d=" +
+		response.docInfo[0].metadata["section"].values[0];
+	      return true;
+	    }
+	  }
+	  col_here ++;
+	}
+      }
+      return false;
+      
+    } else {
+      // link is external 
+      link = arg_href;
+      return false;
+    }
+}
+
+
+bool extlinkaction::do_action (cgiargsclass &args, recptprotolistclass *protos, 
+			       browsermapclass * /*browsers*/, displayclass &disp,
+			       outconvertclass &outconvert, ostream &textout,
+			       ostream &logout) {
+
+  if (args["href"].empty()) {
+    // oops, this shouldn't happen
+    textout << outconvert << disp << ("_extlink:header_\n")
+	    << ("_extlink:notfoundcontent_\n")
+	    << ("_extlink:footer_\n");
+    return true;
+  }
+
+  if (args["rl"] == "1") {
+    // need to see if link exists in any other collection
+    // if cross-collection searching/browsing is turned on 
+    if (args["ccs"] == "1" && !args["cc"].empty()) {
+      
+      FilterResponse_t response;
+      text_tset metadata;
+      metadata.insert ("section");
+      text_tarray collections;
+      splitchar (args["cc"].begin(), args["cc"].end(), ',', collections);
+      
+      text_tarray::const_iterator col_here = collections.begin();
+      text_tarray::const_iterator col_end = collections.end();
+      
+      while (col_here != col_end) {
+	
+	// don't need to check current collection
+	if (*col_here == args["c"]) {col_here ++; continue;}
+	
+	recptproto *collectproto = protos->getrecptproto (*col_here, logout);
+	
+	if (get_info (args["href"], *col_here, metadata, false, collectproto, response, logout)) {
+	  if (!response.docInfo[0].metadata["section"].values[0].empty()) {
+	    text_t collectionname = *col_here;
+	    metadata.erase (metadata.begin(), metadata.end());
+	    metadata.insert ("collectionname");
+	    FilterResponse_t nresponse;
+	    if (get_info ("collection", *col_here, metadata, false, collectproto, nresponse, logout)) {
+	      if (!nresponse.docInfo[0].metadata["collectionname"].values[0].empty())
+		collectionname = nresponse.docInfo[0].metadata["collectionname"].values[0];
+	    }
+	    textout << outconvert << disp << ("_extlink:header_\n")
+		    << ("_extlink:foundintcontent_(" + *col_here + ", " + collectionname + 
+			", " + response.docInfo[0].metadata["section"].values[0] + "\n")
+		    << ("_extlink:footer_\n");
+	    return true;
+	  }
+	}
+	col_here ++;
+      }
+    }
+    textout << outconvert << disp << ("_extlink:header_\n")
+	    << ("_extlink:notfoundcontent_\n")
+	    << ("_extlink:footer_\n");
+    
+    
+  } else {
+    // link is external 
+    textout << outconvert << disp << ("_extlink:header_\n")
+	    << ("_extlink:foundcontent_\n")
+	    << ("_extlink:footer_\n");
+  }
+
+  return true;
+}
Index: /main/tags/2.25/gsdl/src/recpt/extlinkaction.h
===================================================================
--- /main/tags/2.25/gsdl/src/recpt/extlinkaction.h	(revision 21064)
+++ /main/tags/2.25/gsdl/src/recpt/extlinkaction.h	(revision 21064)
@@ -0,0 +1,62 @@
+/**********************************************************************
+ *
+ * extlinkaction.h -- 
+ * Copyright (C) 1999  The New Zealand Digital Library Project
+ *
+ * A component of the Greenstone digital library software
+ * from the New Zealand Digital Library Project at the
+ * University of Waikato, New Zealand.
+ *
+ * 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.
+ *
+ *********************************************************************/
+
+
+#ifndef EXTLINKACTION_H
+#define EXTLINKACTION_H
+
+#include "action.h"
+
+class extlinkaction : public action {
+
+
+public:
+  extlinkaction ();
+  virtual ~extlinkaction ();
+
+  text_t get_action_name () {return "extlink";}
+  void get_cgihead_info (cgiargsclass &args, recptprotolistclass *protos,
+			 response_t &response, text_t &response_data, 
+			 ostream &logout);
+
+  void define_internal_macros (displayclass &disp, cgiargsclass &args, 
+			       recptprotolistclass *protos, 
+			       ostream &logout);
+
+  bool do_action (cgiargsclass &args, recptprotolistclass *protos, 
+		  browsermapclass *browsers, displayclass &disp,
+		  outconvertclass &outconvert, ostream &textout,
+		  ostream &logout);
+
+
+protected:
+  bool get_link (cgiargsclass &args, recptprotolistclass *protos,
+		 text_t &link, ostream &logout);
+
+};
+
+
+
+#endif
Index: /main/tags/2.25/gsdl/src/recpt/formattools.cpp
===================================================================
--- /main/tags/2.25/gsdl/src/recpt/formattools.cpp	(revision 21064)
+++ /main/tags/2.25/gsdl/src/recpt/formattools.cpp	(revision 21064)
@@ -0,0 +1,642 @@
+/**********************************************************************
+ *
+ * formattools.cpp -- 
+ * Copyright (C) 1999  The New Zealand Digital Library Project
+ *
+ * A component of the Greenstone digital library software
+ * from the New Zealand Digital Library Project at the
+ * University of Waikato, New Zealand.
+ *
+ * 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.
+ *
+ *********************************************************************/
+
+#include "formattools.h"
+#include "cgiutils.h"
+#include <assert.h>
+
+// a few function prototypes
+static text_t format_string (ResultDocInfo_t &docinfo, format_t *formatlistptr,
+			     const text_t &link, const text_t &icon, 
+			     const text_t &text, bool highlight);
+
+static bool parse_action (text_t::const_iterator &here, const text_t::const_iterator &end, 
+			  format_t *formatlistptr, text_tset &metadata, bool &getParents);
+
+void metadata_t::clear() {
+  metaname.clear();
+  metacommand = mNone;
+  parentcommand = pNone;
+  parentoptions.clear();
+}
+
+void decision_t::clear() {
+  command = dMeta;
+  meta.clear();
+}
+
+void format_t::clear() {
+  command = comText;
+  decision.clear();
+  text.clear();
+  meta.clear();
+  nextptr = NULL;
+  ifptr = NULL;
+  elseptr = NULL;
+  orptr = NULL;
+}
+
+void formatinfo_t::clear() {
+  DocumentImages = false;
+  DocumentTitles = true;
+  DocumentHeading = "{Or}{[parent(Top):Title],[Title],untitled}<br>";
+  DocumentContents = true;
+  DocumentArrowsBottom = true;
+  DocumentButtons.erase (DocumentButtons.begin(), DocumentButtons.end());
+  DocumentButtons.push_back ("Expand Text");
+  DocumentButtons.push_back ("Expand Contents");
+  DocumentButtons.push_back ("Detach");
+  DocumentButtons.push_back ("Highlight");
+  DocumentText = "[Text]";
+  formatstrings.erase (formatstrings.begin(), formatstrings.end());
+  DocumentUseHTML = false;
+}
+
+// simply checks to see if formatstring begins with a <td> tag
+bool is_table_content (const text_t &formatstring) {
+  text_t::const_iterator here = formatstring.begin();
+  text_t::const_iterator end = formatstring.end();
+  
+  while (here != end) {
+    if (*here != ' ') {
+      if ((*here == '<') && ((here+3) < end)) {
+	if ((*(here+1) == 't' || *(here+1) == 'T') &&
+	    (*(here+2) == 'd' || *(here+2) == 'D') &&
+	    (*(here+3) == '>' || *(here+3) == ' '))
+	  return true;
+      } else return false;
+    }
+    here ++;
+  }
+  return false;
+}
+
+bool is_table_content (const format_t *formatlistptr) {
+
+  if (formatlistptr == NULL) return false;
+  
+  if (formatlistptr->command == comText)
+    return is_table_content (formatlistptr->text);
+    
+  return false;
+}
+
+// returns false if key isn't in formatstringmap
+bool get_formatstring (const text_t &key, const text_tmap &formatstringmap,
+		       text_t &formatstring) {
+
+  formatstring.clear();
+  text_tmap::const_iterator it = formatstringmap.find(key);
+  if (it == formatstringmap.end()) return false;
+  formatstring = (*it).second;
+  return true;
+}
+
+// tries to find "key1key2" then "key1" then "key2"
+bool get_formatstring (const text_t &key1, const text_t &key2,  
+		       const text_tmap &formatstringmap,
+		       text_t &formatstring) {
+
+  formatstring.clear();
+  text_tmap::const_iterator it = formatstringmap.find(key1 + key2);
+  if (it != formatstringmap.end()) {
+    formatstring = (*it).second;
+    return true;
+  }
+  it = formatstringmap.find(key1);
+  if (it != formatstringmap.end()) {
+    formatstring = (*it).second;
+    return true;
+  }
+  it = formatstringmap.find(key2);
+  if (it != formatstringmap.end()) {
+    formatstring = (*it).second;
+    return true;
+  }
+  return false;
+}
+
+
+// returns a date of form _textmonthnn_ 31, 1999 
+// input is date of type 19991231
+// at least the year must be present in date
+text_t format_date (const text_t &date) {
+
+  if (date.size() < 4) return "";
+
+  text_t::const_iterator datebegin = date.begin();
+
+  text_t year = substr (datebegin, datebegin+4);
+
+  if (date.size() < 6) return year;
+
+  text_t month = "_textmonth" + substr (datebegin+4, datebegin+6) + "_";
+  int imonth = month.getint();
+  if (imonth < 0 || imonth > 12) return year;
+
+  if (date.size() < 8) return month + ", " + year;
+
+  text_t day = substr (datebegin+6, datebegin+8);
+  if (day[0] == '0') day = substr (day.begin()+1, day.end());
+  int iday = day.getint();
+  if (iday < 0 || iday > 31) return month + ", " + year;
+    
+  return month + " " + day + ", " + year;
+}  
+
+static void get_parent_options (text_t &instring, metadata_t &metaoption) {
+
+  assert (instring.size() > 7);
+  if (instring.size() <= 7) return;
+
+  text_t meta, com, op;
+  bool inbraces = false;
+  bool inquotes = false;
+  bool foundcolon = false;
+  text_t::const_iterator here = instring.begin()+6;
+  text_t::const_iterator end = instring.end();
+  while (here != end) {
+    if (*here == '(') inbraces = true;
+    else if (*here == ')') inbraces = false;
+    else if (*here == '\'' && !inquotes) inquotes = true;
+    else if (*here == '\'' && inquotes) inquotes = false;
+    else if (*here == ':' && !inbraces) foundcolon = true;
+    else if (foundcolon) meta.push_back (*here);
+    else if (inquotes) op.push_back (*here);
+    else com.push_back (*here);
+    here ++;
+  }
+  instring = meta;
+  if (com.empty())
+    metaoption.parentcommand = pImmediate;
+  else if (com == "Top")
+    metaoption.parentcommand = pTop;
+  else if (com == "All") {
+    metaoption.parentcommand = pAll;
+    metaoption.parentoptions = op;
+  }
+}
+
+static void parse_meta (text_t &meta, metadata_t &metaoption,
+			text_tset &metadata, bool &getParents) {
+
+  if (meta.size() > 8 && (substr(meta.begin(), meta.begin()+8) == "cgisafe:")) {
+    metaoption.metacommand = mCgiSafe;
+    meta = substr (meta.begin()+8, meta.end());
+  }
+
+  if (meta.size() > 7 && (substr (meta.begin(), meta.begin()+6) == "parent")) {
+    getParents = true;
+    get_parent_options (meta, metaoption);
+  } 
+
+  metadata.insert (meta);
+  metaoption.metaname = meta;
+}
+
+static void parse_meta (text_t &meta, format_t *formatlistptr,
+			text_tset &metadata, bool &getParents) {
+  
+  if (meta == "link")
+    formatlistptr->command = comLink;
+  else if (meta == "/link")
+    formatlistptr->command = comEndLink;
+
+  else if (meta == "num")
+    formatlistptr->command = comNum;
+
+  else if (meta == "icon")
+    formatlistptr->command = comIcon;
+
+  else if (meta == "Text")
+    formatlistptr->command = comDoc;
+
+  else if (meta == "highlight")
+    formatlistptr->command = comHighlight;
+
+  else if (meta == "/highlight")
+    formatlistptr->command = comEndHighlight;
+
+  else {
+    formatlistptr->command = comMeta;
+    parse_meta (meta, formatlistptr->meta, metadata, getParents);
+  }
+}
+
+static bool parse_string (const text_t &formatstring, format_t *formatlistptr, 
+			  text_tset &metadata, bool &getParents) {
+
+  text_t text;
+  text_t::const_iterator here = formatstring.begin();
+  text_t::const_iterator end = formatstring.end();
+
+  while (here != end) {
+
+    if (*here == '\\') {
+      here ++;
+      if (here != end) text.push_back (*here);
+
+    } else if (*here == '{') {
+      if (!text.empty()) {
+	formatlistptr->command = comText;
+	formatlistptr->text = text;
+	formatlistptr->nextptr = new format_t();
+	formatlistptr = formatlistptr->nextptr;
+	
+	text.clear();
+      }
+      if (parse_action (++here, end, formatlistptr, metadata, getParents)) {
+	formatlistptr->nextptr = new format_t();
+	formatlistptr = formatlistptr->nextptr;
+	if (here == end) break;
+      }
+    } else if (*here == '[') {
+      if (!text.empty()) {
+	formatlistptr->command = comText;
+	formatlistptr->text = text;
+	formatlistptr->nextptr = new format_t();
+	formatlistptr = formatlistptr->nextptr;
+
+	text.clear();
+      }
+      text_t meta;
+      here ++;
+      while (*here != ']') {
+	if (here == end) return false;
+	meta.push_back (*here);
+	here ++;
+      }
+      parse_meta (meta, formatlistptr, metadata, getParents);
+      formatlistptr->nextptr = new format_t();
+      formatlistptr = formatlistptr->nextptr;
+
+    } else 
+      text.push_back (*here);
+
+    if (here != end) here ++;
+  }
+  if (!text.empty()) {
+    formatlistptr->command = comText;
+    formatlistptr->text = text;
+    formatlistptr->nextptr = new format_t();
+    formatlistptr = formatlistptr->nextptr;
+
+  }
+  return true;
+}
+
+
+static bool parse_action (text_t::const_iterator &here, const text_t::const_iterator &end, 
+			  format_t *formatlistptr, text_tset &metadata, bool &getParents) {
+
+  text_t::const_iterator it = findchar (here, end, '}');
+  if (it == end) return false;
+
+  text_t com = substr (here, it);
+  here = findchar (it, end, '{');
+  if (here == end) return false;
+  else here ++;
+
+  if (com == "If") formatlistptr->command = comIf;
+  else if (com == "Or") formatlistptr->command = comOr;
+  else return false;
+
+  int curlycount = 0;
+  int commacount = 0;
+  text_t text;
+  while (here != end) {
+
+    if (*here == '\\') {
+      here++;
+      if (here != end) text.push_back(*here);
+      
+    } else if (*here == '{') {curlycount ++; text.push_back(*here);}
+    else if (*here == '}' && curlycount > 0) {
+      curlycount --; 
+      text.push_back(*here);
+    }
+
+    else if ((*here == ',' || *here == '}') && curlycount <= 0) {
+
+      if (formatlistptr->command == comOr) {
+	// the {Or}{this, or this, or this, or this} statement
+	// or'ed statements may be either [metadata] or plain text
+	format_t *or_ptr;
+	
+	// find the next unused orptr
+	if (formatlistptr->orptr == NULL) {
+	  formatlistptr->orptr = new format_t();
+	  or_ptr = formatlistptr->orptr;
+	} else {
+	  or_ptr = formatlistptr->orptr;
+	  while (or_ptr->nextptr != NULL)
+	    or_ptr = or_ptr->nextptr;
+	  or_ptr->nextptr = new format_t();
+	  or_ptr = or_ptr->nextptr;
+	}
+
+	text_t::const_iterator beginbracket = text.begin();
+	text_t::const_iterator endbracket = (text.end() - 1);
+	if ((*beginbracket == '[') && (*endbracket == ']')) {
+	  // it's metadata
+	  text_t meta = substr (beginbracket+1, endbracket);
+	  parse_meta (meta, or_ptr, metadata, getParents);
+
+	} else {
+	  parse_string (text, or_ptr, metadata, getParents);
+	}
+	text.clear();
+
+      } else {
+	// the {If}{decide,do,else} statement
+	if (commacount == 0) {
+	  // If decision only supports metadata at present
+	  
+	  // remove the surrounding square brackets
+	  text_t::const_iterator beginbracket = text.begin();
+	  text_t::const_iterator endbracket = (text.end() - 1);
+	  if ((*beginbracket == '[') && (*endbracket == ']')) {
+	    text_t meta = substr (beginbracket+1, endbracket);
+	    parse_meta (meta, formatlistptr->decision.meta, metadata, getParents);
+	    commacount ++;
+	    text.clear();
+	  } 
+	  
+	} else if (commacount == 1) {
+	  formatlistptr->ifptr = new format_t();
+	  parse_string (text, formatlistptr->ifptr, metadata, getParents);
+	  commacount ++;
+	  text.clear();
+	  
+	} else if (commacount == 2) {
+	  formatlistptr->elseptr = new format_t();
+	  parse_string (text, formatlistptr->elseptr, metadata, getParents);
+	  commacount ++;
+	  text.clear();
+	}
+      }
+      if (*here == '}') break;
+      
+    } else text.push_back(*here);
+    
+    if (here != end) here ++;
+  }
+
+  return true;
+}
+
+
+bool parse_formatstring (const text_t &formatstring, format_t *formatlistptr, 
+			 text_tset &metadata, bool &getParents) {
+
+  formatlistptr->clear();
+  getParents = false;
+
+  return (parse_string (formatstring, formatlistptr, metadata, getParents));
+}
+
+
+// note: all the format_date stuff is assuming that all Date metadata is going to
+// be of the form yyyymmdd, this is of course, crap ;)
+
+static text_t get_meta (ResultDocInfo_t &docinfo, const metadata_t &meta) {
+  
+  // make sure we have the requested metadata
+  MetadataInfo_tmap::iterator it = docinfo.metadata.find (meta.metaname);
+  if (it == docinfo.metadata.end()) return "";
+
+  MetadataInfo_t *parent = docinfo.metadata[meta.metaname].parent;
+
+  switch (meta.parentcommand) {
+  case pNone:
+    {
+      text_t classifier_metaname = docinfo.classifier_metadata_type;
+       int metaname_index 
+	= (classifier_metaname == meta.metaname) ? docinfo.classifier_metadata_offset : 0;
+      text_t metadata_item = docinfo.metadata[meta.metaname].values[metaname_index];
+      
+      if (meta.metaname == "Date")
+	return format_date (metadata_item);
+      if (meta.metacommand == mCgiSafe) 
+	return cgi_safe (metadata_item);
+      else return metadata_item;
+    }
+
+  case pImmediate:
+    if (parent != NULL) {
+      if (meta.metaname == "Date") 
+	return format_date (parent->values[0]);
+      if (meta.metacommand == mCgiSafe) 
+	return cgi_safe (parent->values[0]);
+      else return parent->values[0];
+    }
+    break;
+
+  case pTop:
+    if (parent != NULL) {
+      while (parent->parent != NULL) parent = parent->parent;
+
+      if (meta.metaname == "Date") 
+	return format_date (parent->values[0]);
+      if (meta.metacommand == mCgiSafe) 
+	return cgi_safe (parent->values[0]);
+      else return parent->values[0];
+    }
+    break;
+
+  case pAll:
+    MetadataInfo_t *parent = docinfo.metadata[meta.metaname].parent;
+    if (parent != NULL) {
+      text_tarray tmparray;
+      while (parent != NULL) {
+	tmparray.push_back (parent->values[0]);
+	parent = parent->parent;
+      }
+      bool first = true;
+      text_t tmp;
+      text_tarray::reverse_iterator here = tmparray.rbegin();
+      text_tarray::reverse_iterator end = tmparray.rend();
+      while (here != end) {
+	if (!first) tmp += meta.parentoptions;
+	if (meta.metaname == "Date") tmp += format_date (*here);
+	else tmp += *here;
+	first = false;
+	here ++;
+      }
+      if (meta.metacommand == mCgiSafe) return cgi_safe (tmp);
+      else return tmp;
+    }
+  }
+  return "";
+}
+
+static text_t get_or (ResultDocInfo_t &docinfo, format_t *orptr,
+		      const text_t &link, const text_t &icon, 
+		      const text_t &text, bool highlight) {
+
+  text_t tmp;
+  while (orptr != NULL) {
+
+    tmp = format_string (docinfo, orptr, link, icon, text, highlight);
+    if (!tmp.empty()) return tmp;
+
+    orptr = orptr->nextptr;
+  }
+  return "";
+}
+
+static text_t get_if (ResultDocInfo_t &docinfo, const decision_t &decision,
+		      format_t *ifptr, format_t *elseptr, const text_t &link, 
+		      const text_t &icon, const text_t &text, bool highlight) {
+
+  // not much of a choice yet ...
+  if (decision.command == dMeta) {
+    if (get_meta (docinfo, decision.meta) != "") {
+      if (ifptr != NULL)
+	return get_formatted_string (docinfo, ifptr, link, icon, text, highlight);
+    }
+    else {
+      if (elseptr != NULL)
+	return get_formatted_string (docinfo, elseptr, link, icon, text, highlight);
+    }
+  }
+  return "";
+}
+
+text_t format_string (ResultDocInfo_t &docinfo, format_t *formatlistptr,
+		      const text_t &link, const text_t &icon, 
+		      const text_t &text, bool highlight) {
+
+  if (formatlistptr == NULL) return "";
+
+  switch (formatlistptr->command) {
+  case comText:
+    return formatlistptr->text;
+  case comLink:
+    return link;
+  case comEndLink:
+    if (link.empty()) return "";
+    else return "</a>";
+  case comIcon:
+    return icon;
+  case comNum:
+    return docinfo.result_num;
+  case comMeta:
+    return get_meta (docinfo, formatlistptr->meta);
+  case comDoc:
+    return text;
+  case comHighlight:
+    if (highlight) return "<b>";
+    break;
+  case comEndHighlight:
+    if (highlight) return "</b>";
+    break;
+  case comIf:
+    return get_if (docinfo, formatlistptr->decision, formatlistptr->ifptr, 
+		   formatlistptr->elseptr, link, icon, text, highlight);
+  case comOr:
+    return get_or (docinfo, formatlistptr->orptr, link, icon, text, highlight);
+  }
+  return "";
+}
+
+
+text_t get_formatted_string (ResultDocInfo_t &docinfo, format_t *formatlistptr,
+			     const text_t &link, const text_t &icon) {
+
+  text_t text;
+
+  text_t ft;
+  while (formatlistptr != NULL) {
+    ft += format_string (docinfo, formatlistptr, link, icon, text, false);
+    formatlistptr = formatlistptr->nextptr;
+  }
+  return ft;
+}
+
+
+text_t get_formatted_string (ResultDocInfo_t &docinfo, format_t *formatlistptr) {
+
+  text_t link = "<a href=\"_httpdocument_&cl=search&d=" + docinfo.OID + "\">";
+  text_t icon = "_icontext_";
+  text_t text;
+
+  text_t ft;
+  while (formatlistptr != NULL) {
+    ft += format_string (docinfo, formatlistptr, link, icon, text, false);
+    formatlistptr = formatlistptr->nextptr;
+  }
+  return ft;
+}
+
+
+text_t get_formatted_string (ResultDocInfo_t &docinfo, format_t *formatlistptr,
+			     const text_t &text) {
+
+  text_t link = "<a href=\"_httpdocument_&cl=search&d=" + docinfo.OID + "\">";
+  text_t icon = "_icontext_";
+
+  text_t ft;
+  while (formatlistptr != NULL) {
+    ft += format_string (docinfo, formatlistptr, link, icon, text, false);
+    formatlistptr = formatlistptr->nextptr;
+  }
+  return ft;
+}
+
+
+text_t get_formatted_string (ResultDocInfo_t &docinfo, format_t *formatlistptr,
+			     const text_t &link, const text_t &icon, const text_t &text) {
+
+  text_t ft;
+  while (formatlistptr != NULL) {
+    ft += format_string (docinfo, formatlistptr, link, icon, text, false);
+    formatlistptr = formatlistptr->nextptr;
+  }
+  return ft;
+}
+
+text_t get_formatted_string (ResultDocInfo_t &docinfo, format_t *formatlistptr,
+			     const text_t &link, const text_t &icon, bool highlight) {
+
+  text_t text, ft;
+  while (formatlistptr != NULL) {
+    ft += format_string (docinfo, formatlistptr, link, icon, text, highlight);
+    formatlistptr = formatlistptr->nextptr;
+  }
+  return ft;
+}
+
+text_t get_formatted_string (ResultDocInfo_t &docinfo, format_t *formatlistptr,
+			     const text_t &link, const text_t &icon, 
+			     const text_t &text, bool highlight) {
+
+  text_t ft;
+  while (formatlistptr != NULL) {
+    ft += format_string (docinfo, formatlistptr, link, icon, text, highlight);
+    formatlistptr = formatlistptr->nextptr;
+  }
+  return ft;
+}
Index: /main/tags/2.25/gsdl/src/recpt/formattools.h
===================================================================
--- /main/tags/2.25/gsdl/src/recpt/formattools.h	(revision 21064)
+++ /main/tags/2.25/gsdl/src/recpt/formattools.h	(revision 21064)
@@ -0,0 +1,120 @@
+/**********************************************************************
+ *
+ * formattools.h -- 
+ * Copyright (C) 1999  The New Zealand Digital Library Project
+ *
+ * A component of the Greenstone digital library software
+ * from the New Zealand Digital Library Project at the
+ * University of Waikato, New Zealand.
+ *
+ * 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.
+ *
+ *********************************************************************/
+
+
+#ifndef FORMATTOOLS_H
+#define FORMATTOOLS_H
+
+#include "text_t.h"
+#include "comtypes.h"
+
+enum command_t {comIf, comOr, comMeta, comText, comLink, comEndLink, comNum, comIcon, 
+		comDoc, comHighlight, comEndHighlight};
+enum pcommand_t {pNone, pImmediate, pTop, pAll};
+enum dcommand_t {dMeta};
+enum mcommand_t {mNone, mCgiSafe};
+
+struct metadata_t {
+  void clear();
+  metadata_t () {clear();}
+
+  text_t metaname;
+  mcommand_t metacommand;
+  pcommand_t parentcommand;
+  text_t parentoptions;
+};
+
+struct decision_t {
+  void clear();
+  decision_t () {clear();}
+
+  dcommand_t command;
+  metadata_t meta;
+};
+
+struct format_t {
+  void clear();
+  format_t () {clear();}
+
+  command_t command;
+  decision_t decision;
+  text_t text;
+  metadata_t meta;
+  format_t *nextptr;
+  format_t *ifptr;
+  format_t *elseptr;
+  format_t *orptr;
+};
+
+// the format structure used by this receptionist
+struct formatinfo_t {
+  void clear();
+  formatinfo_t () {clear();}
+
+  bool DocumentImages;
+  bool DocumentTitles;
+  text_t DocumentHeading;
+  bool DocumentContents;
+  bool DocumentArrowsBottom;
+  text_tarray DocumentButtons;
+  text_t DocumentText;
+  text_tmap formatstrings;
+  bool DocumentUseHTML;
+};
+
+bool is_table_content (const text_t &formatstring);
+bool is_table_content (const format_t *formatlistptr);
+
+bool get_formatstring (const text_t &key, const text_tmap &formatstringmap,
+		       text_t &formatstring);
+bool get_formatstring (const text_t &key1, const text_t &key2,  
+		       const text_tmap &formatstringmap,
+		       text_t &formatstring);
+
+text_t format_date (const text_t &date);
+
+bool parse_formatstring (const text_t &formatstring, format_t *formatlistptr, 
+			 text_tset &metadata, bool &getParents);
+
+text_t get_formatted_string (ResultDocInfo_t &docinfo, format_t *formatlistptr,
+			     const text_t &link, const text_t &icon);
+
+text_t get_formatted_string (ResultDocInfo_t &docinfo, format_t *formatlistptr);
+
+text_t get_formatted_string (ResultDocInfo_t &docinfo, format_t *formatlistptr,
+			     const text_t &text);
+
+text_t get_formatted_string (ResultDocInfo_t &docinfo, format_t *formatlistptr,
+			     const text_t &link, const text_t &icon, const text_t &text);
+
+text_t get_formatted_string (ResultDocInfo_t &docinfo, format_t *formatlistptr,
+			     const text_t &link, const text_t &icon, bool highlight);
+
+text_t get_formatted_string (ResultDocInfo_t &docinfo, format_t *formatlistptr,
+			     const text_t &link, const text_t &icon, 
+			     const text_t &text, bool highlight);
+
+
+#endif
Index: /main/tags/2.25/gsdl/src/recpt/historydb.cpp
===================================================================
--- /main/tags/2.25/gsdl/src/recpt/historydb.cpp	(revision 21064)
+++ /main/tags/2.25/gsdl/src/recpt/historydb.cpp	(revision 21064)
@@ -0,0 +1,607 @@
+/**********************************************************************
+ *
+ * historydb.cpp -- 
+ * Copyright (C) 1999  The New Zealand Digital Library Project
+ *
+ * A component of the Greenstone digital library software
+ * from the New Zealand Digital Library Project at the
+ * University of Waikato, New Zealand.
+ *
+ * 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.
+ *
+ *********************************************************************/
+
+#include "historydb.h"
+#include "fileutil.h"
+#include "cgiutils.h"
+#include "recptproto.h"
+#include "OIDtools.h"
+
+
+// returns true on success (in which case historyinfo will contain
+// the information for this history)
+bool get_history_info (const text_t &userid, text_tarray &historyinfo, 
+		       const text_t &gsdlhome, ostream &logout) {
+
+  text_t historyfile = filename_cat(gsdlhome, "etc", "history.db");
+  
+  bool result = false;
+  // open the history database  
+  gdbmclass historydb;
+  
+  if (historydb.opendatabase(historyfile, GDBM_READER, 1000, true)) {
+    // get history list
+    text_t historyresult;
+    
+    historydb.getkeydata(userid, historyresult);
+    
+    if (historyresult != "") { //  there are entries, process them
+      
+      splitchar(historyresult.begin(), historyresult.end(), '\n', historyinfo);
+      result = true;
+    }
+    historydb.closedatabase();
+    
+  } else {
+    outconvertclass text_t2ascii;
+    logout << text_t2ascii << "couldn't open history database " << historyfile << "\n";
+  }
+  return result;
+}
+
+
+// returns true on success
+bool set_history_info (const text_t &userid, const text_t &history, const text_t &gsdlhome) {
+
+  text_t historyfile = filename_cat(gsdlhome, "etc", "history.db");
+  
+  bool result = false;
+  // open the history database  
+  gdbmclass historydb;
+  
+  text_t querynum;
+  text_t historyresult;
+
+  
+  if ( !historydb.opendatabase(historyfile, GDBM_READER, 1000, true)) {
+    // not created yet
+    historyresult="";
+    querynum="1";
+  }
+  else {
+
+    // get history list
+   if (! historydb.getkeydata(userid, historyresult)) {
+     historyresult="";
+     querynum="1";
+   }
+   historydb.closedatabase();
+  }
+
+  // get next query num
+  if (historyresult!="") {
+    text_tarray entries;
+    splitchar(historyresult.begin(), historyresult.end(), '\n', entries);
+    get_query_num(entries.back(), querynum);
+    querynum.setint(querynum.getint()+1);
+  }
+  
+  // open for writing
+  if (!historydb.opendatabase(historyfile, GDBM_WRCREAT, 1000, true)) return false;
+    
+  // add on new line
+  historyresult += querynum;
+  historyresult += ":";
+  historyresult += history;
+  historyresult += "\n";
+  
+    if (historydb.setinfo(userid, historyresult)) 
+      result=true; 
+    
+    historydb.closedatabase();
+    return result;
+}
+
+// deletes all a users history
+bool delete_all_history_info (const text_t &userid, const text_t &gsdlhome) {
+
+  text_t historyfile = filename_cat(gsdlhome, "etc", "history.db");
+  
+  // open the history database  
+  gdbmclass historydb;
+  
+  if ( !historydb.opendatabase(historyfile, GDBM_WRITER, 1000, true)) return false;
+
+  historydb.deletekey(userid);
+  historydb.closedatabase();
+  return true;
+  
+}
+
+//deletes only the selected records
+bool delete_history_info (const text_t &userid, const text_t &deletemode, 
+			  const text_t &selection, const text_t &gsdlhome) {
+
+  text_t historyfile = filename_cat(gsdlhome, "etc", "history.db");
+  bool result = false;
+  // open the history database  
+  gdbmclass historydb;
+  
+  if ( !historydb.opendatabase(historyfile, GDBM_READER, 1000, true)) return false;
+
+  // get history list
+  text_t historyresult;
+
+  if (! historydb.getkeydata(userid, historyresult)) return false;
+   
+  historydb.closedatabase();
+
+  text_t newhistory; // for the new list of search history
+  // get list of queries
+  text_tarray queries;
+  splitchar(historyresult.begin(), historyresult.end(), '\n', queries);
+  text_tarray::iterator begin=queries.begin();
+  text_tarray::iterator end=queries.end();
+  
+  // get list of numbers to delete
+  text_tarray numbers;
+  splitchar(selection.begin(), selection.end(), ',', numbers);
+  text_tarray::iterator numbegin=numbers.begin();
+  text_tarray::iterator numend=numbers.end();
+
+  bool tdefault, tset;
+  if (deletemode=="delete") {
+    tdefault=true;
+    tset=false;
+  }
+  else {// deletemode == save
+    tdefault=false;
+    tset=true;
+  }
+
+  // create a HistRecord map of all the entries
+  HistRecordmap records;
+  while (begin != end) {
+    HistRecord rec;
+    rec.entry=*begin;
+    rec.save=tdefault;
+    text_t num;
+    get_query_num(*begin, num);
+    records[num] = rec;
+    begin++;
+  }
+
+ 
+  // now set the save field for all records that are selected
+  while(numbegin != numend) {
+    
+    if (is_number(*numbegin)) {
+      if (records.count(*numbegin)==1) {
+	records[*numbegin].save=tset;
+      } // else invalid number
+    }
+    else{
+      int start, stop;
+      if (get_selection_params(*numbegin, start, stop)) {
+	for (int i=start; i<=stop; i++) {
+	  text_t num = i;
+	  if (records.count(num)==1) {
+	    records[num].save=tset;
+	  }
+	}}
+	else { // dodgy format 
+	  // error message
+	}
+      
+    }
+    numbegin++;
+  } // while
+	
+  HistRecordmap::iterator recbegin = records.begin();
+  HistRecordmap::iterator recend = records.end();
+ 
+  //create new history record - go through all Records
+  // and add to new history those with save set to true
+  while (recbegin != recend) {
+    if ((*recbegin).second.save) {
+      expand_query((*recbegin).second, records);
+      newhistory += (*recbegin).second.entry + "\n";
+    }
+    recbegin++;
+  }
+  
+  // open for writing
+  if (!historydb.opendatabase(historyfile, GDBM_WRITER, 1000, true)) return false;
+  
+  if (historydb.setinfo(userid, newhistory)) result = true; 
+  
+  historydb.closedatabase();
+  return result;
+}
+
+bool get_selection_params (text_t &data, int &start, int &stop) {
+  
+  text_tarray results;
+  
+  splitchar(data.begin(), data.end(), '-', results);
+  if (results.size()==2 && is_number(results[0]) && is_number(results[1])) {
+    start=results[0].getint();
+    stop=results[1].getint();
+    return true;
+  }
+  
+  // error message
+  return false;
+}
+
+// expand query takes a HistRecord, and expands out any hashes in
+// the query string for queries that aren't to be saved
+bool expand_query(HistRecord &record,  HistRecordmap &records) {
+
+  text_tarray args;
+  splitchar(record.entry.begin(), record.entry.end(), '&', args);
+
+  text_tarray::iterator begin=args.begin();
+  text_tarray::iterator end=args.end();
+
+  text_t query;
+  // find the q argument
+  while(begin != end) {
+    if ((*begin)[0] == 'q'&& (*begin)[1] == '=') {
+      query=*begin;
+      args.erase(begin);
+      break;
+    } else begin++;
+  }
+  if (query !="") {
+    
+    //remove the q=
+    text_t::iterator front = query.begin();
+    query.erase(front);
+    front=query.begin();
+    
+    query.erase(front);
+    decode_cgi_arg(query);
+    // now have just the query string
+    // check any refs in it to see if they are still valid
+    combine_query(query, records);
+    text_t formattedquery = cgi_safe(query);
+    text_t newquery = "q=";
+    newquery += formattedquery;
+
+    args.push_back(newquery);
+    joinchar(args, '&', record.entry); 
+    
+    return true;
+  } 
+  return false;
+}
+
+// replaces a reference to a previous query with the search
+// string from that query
+bool combine_query(text_t &userid, text_t &query, const text_t &gsdlhome) 
+{
+  text_t::iterator begin = query.begin();
+  text_t::iterator end = query.end();
+  text_t::iterator it = findchar(begin, end, '#');
+  if (it==end) return true;  // no need to swap anything
+   
+ 
+  text_t queryresult = "";
+  text_t historyfile = filename_cat(gsdlhome, "etc", "history.db");
+  text_t historyresult;
+  // open the history database  
+  gdbmclass historydb;
+  bool exists = false;
+  if (historydb.opendatabase(historyfile, GDBM_READER, 1000, true)) {
+    // get history list
+    if (historydb.getkeydata(userid, historyresult)) {
+      exists=true;
+      
+      historydb.closedatabase();
+    }
+  }
+  if (!exists) {// cant open history file, or user entry doesn't exist. replace #x with blanks 
+    while(it !=end) {
+      queryresult += substr(begin, it);
+      it++;
+      while(*it>='0'&&*it<='9') it++;
+      begin=it;
+      it=findchar(begin, end, '#');
+    }
+    queryresult += substr(begin, end);
+    query = queryresult;
+    return false;
+  }
+  bool result=true;
+
+  // if have got to here, have a previous history in historyresult
+  text_tarray historyinfo;
+  splitchar(historyresult.begin(), historyresult.end(), '\n', historyinfo);
+  text_tarray::iterator histbegin = historyinfo.begin();
+  text_tarray::iterator histend = historyinfo.end();
+  
+  text_tmap historymap;
+  // put all entries into a map, so can pull out the appropriate one easily
+  while (histbegin != histend) {
+    text_t num;
+    get_query_num(*histbegin, num);
+    historymap[num]=*histbegin;
+    histbegin++;
+  }
+  while(it!=end) { // while there still is a hash present
+    text_t querynum;
+    text_t newquery;
+    
+    while (begin!=end) {
+      if (*begin==text_t('#')) {
+	begin++;
+	while(begin !=end && *begin>='0'&&*begin<='9') {
+	  querynum.push_back(*begin);
+	  begin++;
+	}
+        text_t oldquery = historymap[querynum];
+	if (oldquery !="") {   // valid entry
+	  parse_saved_args(oldquery, "q", newquery);
+	  decode_cgi_arg(newquery);
+	  queryresult += newquery;
+	}
+	else {
+	  result=false;
+	}
+	querynum.clear();
+        // else do nothing (replace #x with nothing)
+      } // if
+      else {
+	queryresult.push_back(*begin);
+	begin++;
+      }
+    } // while begin!=end
+    
+    // have got to end of query string, 
+    // now go back and check for internal #
+    query = queryresult;
+    begin = query.begin();
+    end = query.end();
+    it = findchar(begin, end, '#');
+    queryresult.clear();
+    
+  } // while it !=end
+  
+  
+  return result;
+  
+} // combine query
+
+
+// replaces a reference to a previous query with the search
+// string from that query, uses the Histrecordmap rather than the GDBM file
+bool combine_query( text_t &query, HistRecordmap &records) 
+{
+  text_t::iterator begin = query.begin();
+  text_t::iterator end = query.end();
+  text_t::iterator it = findchar(begin, end, '#');
+  if (it==end) return true;  // no need to swap anything
+    
+  text_t queryresult = "";
+  bool changed=true;
+  while(it!=end && changed) { // while there still is a hash present
+                              // and query has changed since last time round
+                              // we are leaving some #X in 
+    text_t querynum;
+    text_t newquery;
+    changed=false;
+    while (begin!=end) { // go through the query looking for hash
+      if (*begin==text_t('#')) {
+	begin++;
+	while(begin !=end && *begin>='0'&&*begin<='9') {
+	  querynum.push_back(*begin);
+	  begin++;
+	}
+	if(records.count(querynum)>0) { // valid entry
+	  if (!records[querynum].save){ // referenced record to be deleted
+	    // get the q arg out of referenced query
+	    parse_saved_args(records[querynum].entry, "q", newquery);
+	    decode_cgi_arg(newquery);
+	    queryresult += newquery;
+	    changed=true;
+	  }
+	  else { // leave the #x in
+	   queryresult.push_back('#');
+	   queryresult +=  querynum;
+	  }
+	}
+	querynum.clear();
+	newquery.clear();
+	// else do nothing (replace #x with nothing)
+      } // if its a hash
+      else {
+	queryresult.push_back(*begin);
+	begin++;
+      }
+    } // while begin!=end
+    
+    // have got to end of query string, 
+    // now go back and check for internal #
+    query = queryresult;
+    begin = query.begin();
+    end = query.end();
+    it = findchar(begin, end, '#');
+    queryresult.clear();
+    
+  } // while it !=end
+  
+  return true;
+} // combine query
+
+// retrieves the value of one of the arguments
+void parse_saved_args(text_t &args, text_t key, text_t &value)
+{
+  text_t::iterator here = args.begin();
+  text_t::iterator end = args.end();
+  text_t::iterator it;
+  while (here != end) {
+    if(*here==key[0]) {
+      it=findchar(here, end, '=');
+      if (it==end) {
+	value=""; return;
+      }
+      text_t entry = substr(here, it);
+      if (entry==key) {
+	here=it+1;
+      	it=findchar(here, end, '&');
+	value = substr(here, it);
+	return;
+      }
+    }
+    here++;
+  }// while
+}
+
+// retrieves the value of all of the arguments
+void parse_saved_args(text_t &args, infodbclass &info)
+{
+  text_t::iterator here = args.begin();
+  text_t::iterator end = args.end();
+  text_t::iterator it;
+  text_tarray values;
+
+  splitchar(here, end, '&', values);
+  
+  text_tarray::iterator start = values.begin();
+  text_tarray::iterator stop = values.end();
+
+  text_t key;
+  text_t value;
+  while(start!=stop) {
+
+    here=(*start).begin();
+    end=(*start).end();
+    it=findchar(here, end, '=');
+    if (it!=end) {
+      key = substr(here, it);
+      value = substr(it+1, end);
+      
+      info[key]=value;
+    }
+    start++;
+  }
+}
+
+void get_query_num(text_t &query, text_t &querynum)
+{
+  text_t::iterator begin = query.begin();
+
+  while (*begin >='0'&& *begin <='9') { // get the digits
+    querynum.push_back(*begin);
+    begin++;
+  }
+  if (*begin != ':') {
+    // something has gone wrong
+  }   
+}
+
+void split_saved_query(text_t &query, text_t &querynum, text_t &numdocs, text_t &cgiargs)
+{
+  text_t::iterator begin = query.begin();
+  text_t::iterator end = query.end();
+  
+  while (*begin >='0'&& *begin <='9') { // get the digits
+    querynum.push_back(*begin);
+    begin++;
+  }
+  if (*begin != ':') {
+    // something has gone wrong
+  }
+  else begin++;
+  while (*begin >='0'&& *begin <='9') { // get the digits
+    numdocs.push_back(*begin);
+    begin++;
+  }                                                                                                                         
+  if (*begin == '+') {  // get the + if there
+    numdocs.push_back(*begin);
+    begin++;
+  }
+
+  cgiargs += (substr(begin, end));  // put rest of query into cgiargs
+
+}
+
+void format_user_info (text_t &cgiargs, text_t &userinfo,  recptprotolistclass *protos, ostream &logout) 
+{
+  logout << "in format user info";
+  text_tset metadata;
+  
+  infodbclass argsinfo;
+  parse_saved_args(cgiargs, argsinfo);
+  
+  text_t collect = argsinfo["c"];
+  if (collect=="") {
+    userinfo="";
+    return;
+  }
+  recptproto *collectproto = protos->getrecptproto(collect,logout);
+  if (collectproto == NULL) {
+    userinfo="";
+    return;
+  }
+  metadata.insert(argsinfo["h"]);
+  FilterResponse_t response;
+
+  get_info("collection", collect, metadata, false, collectproto, response, logout);
+
+  text_t index = response.docInfo[0].metadata[argsinfo["h"]].values[0];
+  
+  text_t mode;
+  if (argsinfo["b"]=="0") { // simple mode
+    if (argsinfo["t"]=="0") {
+      mode = "all words";
+    }
+    else { // t=1
+      mode = "some words";
+    }
+    
+  } 
+  else { // advanced mode
+    if (argsinfo["t"]=="0") {
+      mode = "boolean";
+    }
+    else {
+      mode = "ranked";
+    }
+  }
+  
+  text_t options;
+  if (argsinfo["k"]=="0") {
+    options = "case must match";
+  }
+  else {
+    options = "ignore case";
+  }
+  if (argsinfo["s"]=="0") {
+    options += ", whole word must match";
+  }
+  else {
+    options += ", ignore word endings";
+  }
+  
+  userinfo.clear();
+  userinfo = "collection ("+argsinfo["c"] + ") ";
+  userinfo += "search (" + index + ") ";
+  userinfo += "mode (" + mode +") ";
+  userinfo += "options (" + options + ")";
+
+  logout << "in format user info - end";
+}
Index: /main/tags/2.25/gsdl/src/recpt/historydb.h
===================================================================
--- /main/tags/2.25/gsdl/src/recpt/historydb.h	(revision 21064)
+++ /main/tags/2.25/gsdl/src/recpt/historydb.h	(revision 21064)
@@ -0,0 +1,93 @@
+/**********************************************************************
+ *
+ * historydb.h -- 
+ * Copyright (C) 1999  The New Zealand Digital Library Project
+ *
+ * A component of the Greenstone digital library software
+ * from the New Zealand Digital Library Project at the
+ * University of Waikato, New Zealand.
+ *
+ * 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.
+ *
+ *********************************************************************/
+
+
+#ifndef HISTORYDB_H
+#define HISTORYDB_H
+
+#include "infodbclass.h"
+#include "text_t.h"
+#include "recptproto.h"
+
+struct HistRecord {
+  text_t entry;
+  bool save;
+};
+
+struct ltinttext_t
+{
+  bool operator()(const text_t &t1, const text_t &t2) const
+  { return t1.getint() < t2.getint(); }
+};
+
+
+typedef map<text_t, HistRecord, ltinttext_t> HistRecordmap;
+
+// returns true on success (in which case historyinfo will contain
+// the information for this history)
+bool get_history_info (const text_t &userid, text_tarray &historyinfo, 
+		       const text_t &gsdlhome, ostream &logout);
+
+// returns true on success
+bool set_history_info (const text_t &userid, const text_t &historyinfo, 
+		       const text_t &gsdlhome);
+
+bool delete_all_history_info (const text_t &userid, const text_t &gsdlhome);
+
+// deletes only the entries specified
+bool delete_history_info(const text_t &userid, const text_t &deletemode,
+			 const text_t &selection, const text_t &gsdlhome);
+
+// takes a text_t with x-y, and retrieves the x and y params
+bool get_selection_params (text_t &data, int &start, int &stop);
+
+bool expand_query(HistRecord &query, HistRecordmap &records);
+
+// combine query looks for #x and replaces it with the query
+// string from the xth entry. THe first one looks up the xth
+// query in the database (used before running a query), the 
+// second version looks it up inthe records map (used in
+// delete history -are doing a lotof #x replacing at once.
+bool combine_query(text_t &userid, text_t &query, const text_t &gsdlhome);
+bool combine_query(text_t &userid, HistRecordmap  &records);
+
+// retrieves the value of an arg (key) from a list of cgi args
+// in the form a=q&b=1&...
+void parse_saved_args(text_t &args, text_t key, text_t &value);
+
+// extracts out the components of an entry in the database
+// currently:
+// querynum:numdocs cgiargs
+void split_saved_query(text_t &query, text_t &querynum, text_t &numdocs, text_t &cgiargs);
+
+// just extracts the query number out of the entry
+void get_query_num(text_t &query, text_t &querynum);
+
+// takes the cgiarg string, and outputs it in some form useful
+// to the user
+void format_user_info (text_t &cgiargs, text_t &info, 
+		       recptprotolistclass *protos, ostream &logout);
+
+#endif
Index: /main/tags/2.25/gsdl/src/recpt/hlistbrowserclass.cpp
===================================================================
--- /main/tags/2.25/gsdl/src/recpt/hlistbrowserclass.cpp	(revision 21064)
+++ /main/tags/2.25/gsdl/src/recpt/hlistbrowserclass.cpp	(revision 21064)
@@ -0,0 +1,157 @@
+/**********************************************************************
+ *
+ * hlistbrowserclass.cpp -- 
+ * Copyright (C) 1999  The New Zealand Digital Library Project
+ *
+ * A component of the Greenstone digital library software
+ * from the New Zealand Digital Library Project at the
+ * University of Waikato, New Zealand.
+ *
+ * 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.
+ *
+ *********************************************************************/
+
+#include "hlistbrowserclass.h"
+#include <assert.h>
+#include "OIDtools.h"
+
+hlistbrowserclass::hlistbrowserclass () {
+}
+
+hlistbrowserclass::~hlistbrowserclass () {
+}
+
+// returns the name that specifies the browserclass type
+text_t hlistbrowserclass::get_browser_name () {
+  return "HList";
+}
+
+void hlistbrowserclass::load_metadata_defaults (text_tset &metadata) {
+  metadata.insert ("doctype");
+}
+
+text_t hlistbrowserclass::get_default_formatstring () {
+  return "[link][highlight][Title][/highlight][/link]";
+}
+
+// need to change OID to it's child 
+void hlistbrowserclass::processOID (cgiargsclass &args, recptproto *collectproto,
+				    ostream &logout) {
+
+  text_t OID = args["d"];
+  bool is_classify = false;
+  if (OID.empty()) {
+    is_classify = true;
+    OID = args["cl"];
+  }
+
+  FilterResponse_t response;
+  text_tset metadata;
+  metadata.insert ("childtype");
+  text_t classifytype = "Invisible";
+  text_t child_doctype;
+
+  text_tarray OIDs;
+
+  while (classifytype == "Invisible") {
+    OIDs.erase (OIDs.begin(), OIDs.end());
+    
+    OIDs.push_back (OID);
+    OIDs.push_back (OID + ".fc");
+
+    get_info (OIDs, args["c"], metadata, false, collectproto, response, logout);
+
+    OID = response.docInfo[1].OID;
+    classifytype = response.docInfo[0].metadata["childtype"].values[0];
+  }
+  if (is_classify) args["cl"] = OID;
+  else args["d"] = OID;
+}
+
+int hlistbrowserclass::output_section_group (ResultDocInfo_t &section, cgiargsclass &args,
+					     const text_t &/*collection*/, int colnumber, 
+					     format_t *formatlistptr, bool use_table, 
+					     text_tset &metadata, bool &getParents, 
+					     recptproto *collectproto, displayclass &disp, 
+					     outconvertclass &outconvert, ostream &textout, 
+					     ostream &logout) {
+
+  // expanded contents are going to cause some nasty recursions
+  // so we'll only continue if being passed the current section
+  if ((args["gc"] == 1) && (section.OID != args["d"])) return 0;
+
+  // get all siblings
+  FilterResponse_t response;
+  text_t &arg_cl = args["cl"];
+  get_children (section.OID + ".pr", args["c"], metadata, getParents, 
+		collectproto, response, logout);
+
+					
+  if (use_table || colnumber > 0) {
+    textout << "<table><tr><td>";
+    // get tab size
+    text_t tab; int itab;
+    disp.expandstring ("Global", "_tabwidth_", tab);
+    itab = tab.getint();
+    if (colnumber > 0) textout << outconvert << disp 
+			       << "<img src=\"_httpimg_/space.gif\" width=" 
+			       << (itab*colnumber) << ">";
+    textout << "</td>\n";
+  }
+
+  textout << "<table><tr>\n";
+
+  ResultDocInfo_tarray::iterator tsibling = response.docInfo.begin();
+  ResultDocInfo_tarray::iterator esibling = response.docInfo.end();
+
+  text_t icon, link;
+  while (tsibling != esibling) {
+
+    bool highlight = false;
+    textout << "<td>";
+    text_t &doctype = (*tsibling).metadata["doctype"].values[0];
+
+    if ((*tsibling).OID == section.OID) {
+      link.clear();
+      highlight = true;
+    } else {
+      link = "<a href=\"_httpdocument_";
+      if (doctype == "classify") 
+	link += "&cl=" + (*tsibling).OID + "\">";
+      else
+	link += "&cl=" + arg_cl + "&d=" + (*tsibling).OID + "\">";
+    }
+
+    textout << outconvert << disp 
+	    << get_formatted_string (*tsibling, formatlistptr, link, icon, highlight);
+
+    textout << "</td>\n";
+    tsibling ++;
+  }
+
+  textout << "</tr></table>\n";
+  if (use_table  || colnumber > 0) textout << "</tr></table>\n";
+  return 0;
+}
+
+int hlistbrowserclass::output_section_group (FilterResponse_t &/*sections*/, cgiargsclass &/*args*/,
+					     const text_t &/*collection*/, int /*colnumber*/, 
+					     format_t * /*formatlistptr*/, bool /*use_table*/, 
+					     text_tset &/*metadata*/, bool &/*getParents*/,
+					     recptproto * /*collectproto*/, displayclass &/*disp*/, 
+					     outconvertclass &/*outconvert*/, ostream &/*textout*/, 
+					     ostream &/*logout*/) {
+  return 0;
+}
Index: /main/tags/2.25/gsdl/src/recpt/hlistbrowserclass.h
===================================================================
--- /main/tags/2.25/gsdl/src/recpt/hlistbrowserclass.h	(revision 21064)
+++ /main/tags/2.25/gsdl/src/recpt/hlistbrowserclass.h	(revision 21064)
@@ -0,0 +1,63 @@
+/**********************************************************************
+ *
+ * hlistbrowserclass.h -- 
+ * Copyright (C) 1999  The New Zealand Digital Library Project
+ *
+ * A component of the Greenstone digital library software
+ * from the New Zealand Digital Library Project at the
+ * University of Waikato, New Zealand.
+ *
+ * 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.
+ *
+ *********************************************************************/
+
+
+#ifndef HLISTBROWSERCLASS_H
+#define HLISTBROWSERCLASS_H
+
+#include "browserclass.h"
+
+class hlistbrowserclass : public browserclass {
+protected:
+
+public:
+  hlistbrowserclass ();
+  virtual ~hlistbrowserclass ();
+
+  // returns the name that specifies the browserclass type
+  text_t get_browser_name ();
+
+  virtual void load_metadata_defaults (text_tset &metadata);
+
+  virtual text_t get_default_formatstring ();
+  
+  virtual void processOID (cgiargsclass &args, recptproto *collectproto,
+			   ostream &logout);
+
+  virtual int output_section_group (ResultDocInfo_t &section, cgiargsclass &args,
+				    const text_t &collection, int colnumber, format_t *formatlistptr, 
+				    bool use_table, text_tset &metadata, bool &getParents,
+				    recptproto *collectproto, displayclass &disp, 
+				    outconvertclass &outconvert, ostream &textout, ostream &logout);
+
+  virtual int output_section_group (FilterResponse_t &sections, cgiargsclass &args,
+				    const text_t &collection, int colnumber, format_t *formatlistptr, 
+				    bool use_table, text_tset &metadata, bool &getParents,
+				    recptproto *collectproto, displayclass &disp, 
+				    outconvertclass &outconvert, ostream &textout, ostream &logout);
+
+};
+
+#endif
Index: /main/tags/2.25/gsdl/src/recpt/htmlbrowserclass.cpp
===================================================================
--- /main/tags/2.25/gsdl/src/recpt/htmlbrowserclass.cpp	(revision 21064)
+++ /main/tags/2.25/gsdl/src/recpt/htmlbrowserclass.cpp	(revision 21064)
@@ -0,0 +1,63 @@
+/**********************************************************************
+ *
+ * htmlbrowserclass.cpp -- 
+ * Copyright (C) 1999  The New Zealand Digital Library Project
+ *
+ * A component of the Greenstone digital library software
+ * from the New Zealand Digital Library Project at the
+ * University of Waikato, New Zealand.
+ *
+ * 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.
+ *
+ *********************************************************************/
+
+#include "htmlbrowserclass.h"
+#include <assert.h>
+#include "OIDtools.h"
+
+htmlbrowserclass::htmlbrowserclass () {
+}
+
+htmlbrowserclass::~htmlbrowserclass () {
+}
+
+// returns the name that specifies the browserclass type
+text_t htmlbrowserclass::get_browser_name () {
+  return "HTML";
+}
+
+// redirect to html page
+void htmlbrowserclass::processOID (cgiargsclass &args, recptproto *collectproto,
+				   ostream &logout) {
+
+  // should only reach here from within a classification
+  if (!args["d"].empty()) return;
+  if (args["cl"].empty()) return;
+
+  FilterRequest_t request;
+  FilterResponse_t response;
+  comerror_t err;
+  request.filterName = "NullFilter";
+  request.filterResultOptions = FROID;
+  request.docSet.push_back (args["cl"] + ".fc");
+  collectproto->filter (args["c"], request, response, err, logout);
+
+  if (err != noError || response.docInfo[0].OID.empty()) return;
+
+  // redirect to html page
+  args["a"] = "p";
+  args["p"] = "html";
+  args["hp"] = response.docInfo[0].OID;
+}
Index: /main/tags/2.25/gsdl/src/recpt/htmlbrowserclass.h
===================================================================
--- /main/tags/2.25/gsdl/src/recpt/htmlbrowserclass.h	(revision 21064)
+++ /main/tags/2.25/gsdl/src/recpt/htmlbrowserclass.h	(revision 21064)
@@ -0,0 +1,49 @@
+/**********************************************************************
+ *
+ * htmlbrowserclass.h -- 
+ * Copyright (C) 1999  The New Zealand Digital Library Project
+ *
+ * A component of the Greenstone digital library software
+ * from the New Zealand Digital Library Project at the
+ * University of Waikato, New Zealand.
+ *
+ * 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.
+ *
+ *********************************************************************/
+
+
+#ifndef HTMLBROWSERCLASS_H
+#define HTMLBROWSERCLASS_H
+
+#include "browserclass.h"
+
+class htmlbrowserclass : public browserclass {
+protected:
+
+public:
+
+  htmlbrowserclass ();
+  virtual ~htmlbrowserclass ();
+
+  // returns the name that specifies the browserclass type
+  virtual text_t get_browser_name ();
+
+  void processOID (cgiargsclass &args, recptproto *collectproto,
+		   ostream &logout);
+
+
+};
+
+#endif
Index: /main/tags/2.25/gsdl/src/recpt/htmlgen.cpp
===================================================================
--- /main/tags/2.25/gsdl/src/recpt/htmlgen.cpp	(revision 21064)
+++ /main/tags/2.25/gsdl/src/recpt/htmlgen.cpp	(revision 21064)
@@ -0,0 +1,97 @@
+/**********************************************************************
+ *
+ * htmlgen.cpp -- 
+ * Copyright (C) 1999  The New Zealand Digital Library Project
+ *
+ * A component of the Greenstone digital library software
+ * from the New Zealand Digital Library Project at the
+ * University of Waikato, New Zealand.
+ *
+ * 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.
+ *
+ *********************************************************************/
+
+#include "htmlgen.h"
+#include "unitool.h"
+
+#if defined(GSDL_USE_OBJECTSPACE)
+#  include <ospace\std\map>
+#elif defined(GSDL_USE_STL_H)
+#  include <map.h>
+#else
+#  include <map>
+#endif
+
+
+
+// highlighttext highlights query terms in text string and 
+// outputs the resulting text string
+void highlighttext (text_tarray &termvars, displayclass &disp, text_t &text,
+		    outconvertclass &outconvert, ostream &textout, ostream &/*logout*/) {
+  map<text_t, int, lttext_t> terms;
+  map<text_t, int, lttext_t>::const_iterator it;
+  for (unsigned int i = 0; i < termvars.size(); i++) {
+    terms[termvars[i]] = 1;
+  }
+
+  // get the text to start and end a hightlight
+  text_t starthighlight = "<b><u>";
+  text_t endhighlight = "</u></b>";
+  if (disp.isdefaultmacro("Global", "starthighlight"))
+    disp.expandstring("Global", "_starthighlight_", starthighlight);
+  if (disp.isdefaultmacro("Global", "endhighlight"))
+    disp.expandstring("Global", "_endhighlight_", endhighlight);
+
+
+  text_t::iterator here = text.begin(); 
+  text_t::iterator end = text.end();
+  text_t word, buffer;
+  while (here != end) {
+    if (is_unicode_letdig(*here)) {
+      // not word boundary
+      word.push_back(*here);
+      here++;
+
+    } else {
+      // found word boundary
+      // add last word if there was one
+      if (!word.empty()) {
+	it = terms.find(word);
+	if (it != terms.end()) {
+	  word = starthighlight + word + endhighlight;
+	}
+	buffer += word;
+        word.clear();
+      }
+
+      if (*here == '<') {
+        // skip over rest of html tag
+	while ((here != end) && (*here != '>')) {
+	  buffer.push_back(*here);
+	  here++;
+	}
+      }
+
+      buffer.push_back(*here);
+      here++;
+
+      if (buffer.size() > 1024) {
+	textout << outconvert << buffer;
+	buffer.clear();
+      }
+    }
+  }
+  textout << outconvert << buffer;
+}
Index: /main/tags/2.25/gsdl/src/recpt/htmlgen.h
===================================================================
--- /main/tags/2.25/gsdl/src/recpt/htmlgen.h	(revision 21064)
+++ /main/tags/2.25/gsdl/src/recpt/htmlgen.h	(revision 21064)
@@ -0,0 +1,50 @@
+/**********************************************************************
+ *
+ * htmlgen.h -- 
+ * Copyright (C) 1999  The New Zealand Digital Library Project
+ *
+ * A component of the Greenstone digital library software
+ * from the New Zealand Digital Library Project at the
+ * University of Waikato, New Zealand.
+ *
+ * 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.
+ *
+ *********************************************************************/
+
+
+#ifndef HTMLGEN_H
+#define HTMLGEN_H
+
+#include "gsdlconf.h"
+#include "text_t.h"
+#include "display.h"
+
+#if defined(GSDL_USE_OBJECTSPACE)
+#  include <ospace\std\iostream>
+#elif defined(GSDL_USE_IOS_H)
+#  include <iostream.h>
+#else
+#  include <iostream>
+#endif
+
+
+
+// highlighttext highlights query terms in text string and 
+// outputs the resulting text string
+void highlighttext (text_tarray &termvars, displayclass &disp, text_t &text,
+		    outconvertclass &outconvert, ostream &textout, ostream &logout);
+
+
+#endif
Index: /main/tags/2.25/gsdl/src/recpt/htmlutils.cpp
===================================================================
--- /main/tags/2.25/gsdl/src/recpt/htmlutils.cpp	(revision 21064)
+++ /main/tags/2.25/gsdl/src/recpt/htmlutils.cpp	(revision 21064)
@@ -0,0 +1,42 @@
+/**********************************************************************
+ *
+ * htmlutils.cpp -- 
+ * Copyright (C) 1999  The New Zealand Digital Library Project
+ *
+ * A component of the Greenstone digital library software
+ * from the New Zealand Digital Library Project at the
+ * University of Waikato, New Zealand.
+ *
+ * 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.
+ *
+ *********************************************************************/
+
+#include "htmlutils.h"
+
+text_t html_safe (const text_t &instring) {
+  
+  text_t outstring;
+  text_t::const_iterator here = instring.begin();
+  text_t::const_iterator end = instring.end();
+  while (here != end) {
+    if (*here == '"') outstring += "&quot;";
+    else if (*here == '&') outstring += "&amp;";
+    else if (*here == '<') outstring += "&lt;";
+    else if (*here == '>') outstring += "&gt;";
+    else outstring.push_back(*here);
+    here ++;
+  }
+  return outstring;
+}
Index: /main/tags/2.25/gsdl/src/recpt/htmlutils.h
===================================================================
--- /main/tags/2.25/gsdl/src/recpt/htmlutils.h	(revision 21064)
+++ /main/tags/2.25/gsdl/src/recpt/htmlutils.h	(revision 21064)
@@ -0,0 +1,35 @@
+/**********************************************************************
+ *
+ * htmlutils.h -- 
+ * Copyright (C) 1999  The New Zealand Digital Library Project
+ *
+ * A component of the Greenstone digital library software
+ * from the New Zealand Digital Library Project at the
+ * University of Waikato, New Zealand.
+ *
+ * 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.
+ *
+ *********************************************************************/
+
+
+#ifndef HTMLUTILS_H
+#define HTMLUTILS_H
+
+#include "gsdlconf.h"
+#include "text_t.h"
+
+text_t html_safe (const text_t &instring);
+
+#endif
Index: /main/tags/2.25/gsdl/src/recpt/infodbclass.cpp
===================================================================
--- /main/tags/2.25/gsdl/src/recpt/infodbclass.cpp	(revision 21064)
+++ /main/tags/2.25/gsdl/src/recpt/infodbclass.cpp	(revision 21064)
@@ -0,0 +1,546 @@
+/**********************************************************************
+ *
+ * infodbclass.cpp -- 
+ * Copyright (C) 1999  The New Zealand Digital Library Project
+ *
+ * A component of the Greenstone digital library software
+ * from the New Zealand Digital Library Project at the
+ * University of Waikato, New Zealand.
+ *
+ * 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.
+ *
+ *********************************************************************/
+
+#include "infodbclass.h"
+#include "unitool.h"
+#include "gsdlunicode.h"
+#include "fileutil.h"
+#include "OIDtools.h"
+#include <stdlib.h>
+
+
+
+
+// constructors
+infodbclass::infodbclass () {
+}
+
+void infodbclass::setinfo (const text_t &key, const text_t &value) {
+  text_tarray &tarr = info[key];
+  tarr.erase(tarr.begin(), tarr.end());
+  tarr.push_back(value);
+}
+
+void infodbclass::setintinfo (const text_t &key, int value) {
+  setinfo (key, value);
+}
+
+void infodbclass::setcinfo (const text_t &key, unsigned short c) {
+  text_t t;
+  t.push_back (c);
+  setinfo (key, t);
+}
+
+text_t *infodbclass::getinfo (const text_t &key) {
+  iterator here = info.find (key);
+  if (here == info.end()) return NULL;
+
+  if ((*here).second.empty()) return NULL;
+  
+  return &((*here).second[0]);
+}
+
+int infodbclass::getintinfo (const text_t &key) {
+  text_t *t = getinfo (key);
+  if (t == NULL) return 0;
+  return t->getint();
+}
+
+text_t &infodbclass::operator[] (const text_t &key) {
+  text_tarray &tarr = info[key];
+  if (tarr.empty()) {
+    text_t e;
+    tarr.push_back(e);
+  }
+  return tarr[0];
+}
+
+
+void infodbclass::addinfo (const text_t &key, const text_t &value) {
+  text_tarray &tarr = info[key];
+  tarr.push_back (value);
+}
+
+void infodbclass::addintinfo (const text_t &key, int value) {
+  addinfo (key, value);
+}
+
+void infodbclass::addcinfo (const text_t &key, unsigned short c) {
+  text_t t;
+  t.push_back(c);
+  addinfo (key, t);
+}
+
+text_tarray *infodbclass::getmultinfo (const text_t &key) {
+  iterator here = info.find (key);
+  if (here == info.end()) return NULL;
+
+  return &((*here).second);
+}
+
+
+
+
+// returns true if opened
+bool gdbmclass::opendatabase (const text_t &filename, int mode, int num_retrys, 
+#ifdef __WIN32__
+			      bool need_filelock
+#else
+                              bool
+#endif
+			      ) {
+  text_t data_location;
+  int block_size = 512;
+  
+  if (gdbmfile != NULL) {
+    if (openfile == filename) return true;
+    else closedatabase ();
+  }
+
+  openfile = filename;
+  
+  char *namebuffer = filename.getcstr();
+  do {
+#ifdef __WIN32__
+    gdbmfile = gdbm_open (namebuffer, block_size, mode, 00664, NULL, (need_filelock) ? 1 : 0);
+#else
+    gdbmfile = gdbm_open (namebuffer, block_size, mode, 00664, NULL);
+#endif
+    num_retrys--;
+  } while (num_retrys>0 && gdbmfile==NULL &&
+	   (gdbm_errno==GDBM_CANT_BE_READER || gdbm_errno==GDBM_CANT_BE_WRITER));
+  delete namebuffer;
+  
+  if (gdbmfile == NULL && logout != NULL) {
+    outconvertclass text_t2ascii;
+    (*logout) << text_t2ascii << "database open failed on: " << filename << "\n";
+  }
+
+  return (gdbmfile != NULL);
+}
+
+void gdbmclass::closedatabase () {
+  if (gdbmfile == NULL) return;
+  
+  gdbm_close (gdbmfile);
+  gdbmfile = NULL;
+  openfile.clear();
+}
+
+
+// returns true on success
+bool gdbmclass::setinfo (const text_t &key, const infodbclass &info) {
+  if (gdbmfile == NULL) return false;
+
+  text_t subkey;
+  text_t data;
+
+  // get all the keys and values
+  infodbclass::const_iterator info_here = info.begin();
+  infodbclass::const_iterator info_end = info.end();
+  while (info_here != info_end) {
+    // add the key
+    subkey.clear();
+    subkey.push_back('<');
+    text_t::const_iterator subkey_here = (*info_here).first.begin();
+    text_t::const_iterator subkey_end = (*info_here).first.end();
+    while (subkey_here != subkey_end) {
+      if (*subkey_here == '>') {
+	subkey.push_back('\\'); subkey.push_back('>');
+      } else if (*subkey_here == '\n') {
+	subkey.push_back('\\'); subkey.push_back('n');
+      } else if (*subkey_here == '\r') {
+	subkey.push_back('\\'); subkey.push_back('r');
+      } else {
+	subkey.push_back (*subkey_here);
+      }
+      subkey_here++;
+    }
+    subkey.push_back('>');
+
+    // add the values
+    text_tarray::const_iterator subvalue_here = (*info_here).second.begin();
+    text_tarray::const_iterator subvalue_end = (*info_here).second.end();
+    while (subvalue_here != subvalue_end) {
+      data += subkey;
+      
+      text_t::const_iterator thissubvalue_here = (*subvalue_here).begin();
+      text_t::const_iterator thissubvalue_end = (*subvalue_here).end();
+      while (thissubvalue_here != thissubvalue_end) {
+	if (*thissubvalue_here == '>') {
+	  data.push_back('\\'); data.push_back('>');
+	} else if (*thissubvalue_here == '\n') {
+	  data.push_back('\\'); data.push_back('n');
+	} else if (*thissubvalue_here == '\r') {
+	  data.push_back('\\'); data.push_back('r');
+	} else {
+	  data.push_back (*thissubvalue_here);
+	}
+	
+	thissubvalue_here++;
+      }
+      
+      data.push_back('\n');
+      subvalue_here++;
+    }
+
+    info_here++;
+  }
+
+  // store the value
+  datum key_data;
+  datum data_data;
+
+  // get a utf-8 encoded c string of the unicode key
+  key_data.dptr = (to_utf8(key)).getcstr();
+  if (key_data.dptr == NULL) {
+    if (logout != NULL) (*logout) << "gdbmclass: out of memory\n";
+    return false;
+  }
+  key_data.dsize = strlen (key_data.dptr);
+
+  data_data.dptr = (to_utf8(data)).getcstr();
+  if (data_data.dptr == NULL) {
+    if (logout != NULL) (*logout) << "gdbmclass: out of memory\n";
+    delete key_data.dptr;
+  }
+  data_data.dsize = strlen (data_data.dptr);
+
+  int ret = gdbm_store (gdbmfile, key_data, data_data, GDBM_REPLACE);
+  delete key_data.dptr;
+  delete data_data.dptr;
+
+  return (ret == 0);
+
+}
+
+//returns true on success
+bool gdbmclass::setinfo (const text_t &key, const text_t &data) {
+  if (gdbmfile == NULL) return false;
+  
+  // store the value
+  datum key_data;
+  datum data_data;
+
+  // get a utf-8 encoded c string of the unicode key
+  key_data.dptr = (to_utf8(key)).getcstr();
+  if (key_data.dptr == NULL) {
+    if (logout != NULL) (*logout) << "gdbmclass: out of memory\n";
+    return false;
+  }
+  key_data.dsize = strlen (key_data.dptr);
+
+  data_data.dptr = (to_utf8(data)).getcstr();
+  if (data_data.dptr == NULL) {
+    if (logout != NULL) (*logout) << "gdbmclass: out of memory\n";
+    delete key_data.dptr;
+  }
+  data_data.dsize = strlen (data_data.dptr);
+
+  int ret = gdbm_store (gdbmfile, key_data, data_data, GDBM_REPLACE);
+  delete key_data.dptr;
+  delete data_data.dptr;
+
+  return (ret == 0);
+
+}
+
+
+void gdbmclass::deletekey (const text_t &key) {
+  if (gdbmfile == NULL) return;
+
+  // get a utf-8 encoded c string of the unicode key
+  datum key_data;
+  key_data.dptr = (to_utf8(key)).getcstr();
+  if (key_data.dptr == NULL) return;
+  key_data.dsize = strlen (key_data.dptr);
+
+  // delete the key
+  gdbm_delete (gdbmfile, key_data);
+
+  // free up the key memory
+  delete key_data.dptr;
+}
+
+
+// getfirstkey and getnextkey are used for traversing the database
+// no insertions or deletions should be carried out while traversing
+// the database. when there are no keys left to visit in the database
+// an empty string is returned.
+text_t gdbmclass::getfirstkey () {
+  if (gdbmfile == NULL) return "";
+
+  // get the first key
+  datum firstkey_data = gdbm_firstkey (gdbmfile);
+  if (firstkey_data.dptr == NULL) return "";
+
+  // convert it to text_t
+  text_t firstkey;
+  firstkey.setcarr (firstkey_data.dptr, firstkey_data.dsize);
+  free (firstkey_data.dptr);
+  return to_uni(firstkey);  // convert to unicode
+}
+
+text_t gdbmclass::getnextkey (const text_t &key) {
+  if (gdbmfile == NULL || key.empty()) return "";
+
+  // get a utf-8 encoded c string of the unicode key
+  datum key_data;
+  key_data.dptr = (to_utf8(key)).getcstr();
+  if (key_data.dptr == NULL) return "";
+  key_data.dsize = strlen (key_data.dptr);
+  
+  // get the next key
+  datum nextkey_data = gdbm_nextkey (gdbmfile, key_data);
+  if (nextkey_data.dptr == NULL) {
+    delete key_data.dptr;
+    return "";
+  }
+
+  // convert it to text_t
+  text_t nextkey;
+  nextkey.setcarr (nextkey_data.dptr, nextkey_data.dsize);
+  free (nextkey_data.dptr);
+  delete key_data.dptr;
+  return to_uni(nextkey);  // convert to unicode
+}
+
+
+// replaces the .fc, .lc, .pr, .ns and .ps syntax (first child, 
+// last child, parent, next sibling, previous sibling) 
+// it expects child, parent, etc. to exist if syntax has been used
+// so you should test before using
+text_t gdbmclass::translate_OID (const text_t &inOID, infodbclass &info) {
+
+  if (inOID.size() < 4) return inOID;
+  if (findchar (inOID.begin(), inOID.end(), '.') == inOID.end()) return inOID;
+
+  text_t OID = inOID;
+  text_tarray tailarray;
+  text_t tail = substr (OID.end()-3, OID.end());
+  while (tail == ".fc" || tail == ".lc" || tail == ".pr" || 
+	 tail == ".ns" || tail == ".ps") {
+    tailarray.push_back(tail);
+    OID.erase (OID.end()-3, OID.end());
+    tail = substr (OID.end()-3, OID.end());
+  }
+
+  if (!tailarray.size()) return inOID;
+  text_tarray::const_iterator begin = tailarray.begin();
+  text_tarray::const_iterator here = tailarray.end() - 1;
+
+  while (here >= begin) {
+
+    if (*here == ".fc")
+      get_first_child (OID, info);
+    else if (*here == ".lc")
+      get_last_child (OID, info);
+    else if (*here == ".pr")
+      OID = get_parent (OID);
+    else if (*here == ".ns")
+      get_next_sibling (OID, info);
+    else if (*here == ".ps")
+      get_previous_sibling (OID, info);
+    
+    here --;
+  }
+  return OID;
+}
+
+void gdbmclass::get_first_child (text_t &OID, infodbclass &info) {
+
+  text_t firstchild;
+  if (getinfo (OID, info)) {
+    text_t &contains = info["contains"];
+    if (!contains.empty()) {
+      text_t parent = OID;
+      getdelimitstr (contains.begin(), contains.end(), ';', firstchild);
+      if (firstchild.empty()) OID = contains;
+      else OID = firstchild;
+      if (*(OID.begin()) == '"') translate_parent (OID, parent);
+    }
+  }
+}
+
+void gdbmclass::get_last_child (text_t &OID, infodbclass &info) {
+
+  text_tarray children;
+  if (getinfo (OID, info)) {
+    text_t &contains = info["contains"];
+    if (!contains.empty()) {
+      text_t parent = OID;
+      splitchar (contains.begin(), contains.end(), ';', children);
+      OID = children.back();
+      if (*(OID.begin()) == '"') translate_parent (OID, parent);
+    }
+  }
+}
+  
+void gdbmclass::get_next_sibling (text_t &OID, infodbclass &info) {
+
+  text_tarray siblings;
+  text_t parent = get_parent (OID);
+	     
+  if (getinfo (parent, info)) {
+    text_t &contains = info["contains"];
+    if (!contains.empty()) {
+      splitchar (contains.begin(), contains.end(), ';', siblings);
+      text_tarray::const_iterator here = siblings.begin();
+      text_tarray::const_iterator end = siblings.end();
+      text_t shrunk_OID = OID;
+      shrink_parent (shrunk_OID);
+      while (here != end) {
+	if (*here == shrunk_OID && (here+1 != end)) {
+	  OID = *(here+1);
+	  if (*(OID.begin()) == '"') translate_parent (OID, parent);
+	  break;
+	}
+	here ++;
+      }
+    }
+  }
+}
+
+void gdbmclass::get_previous_sibling (text_t &OID, infodbclass &info) {
+
+  text_tarray siblings;
+  text_t parent = get_parent (OID);
+
+  if (getinfo (parent, info)) {
+    text_t &contains = info["contains"];
+    if (!contains.empty()) {
+      splitchar (contains.begin(), contains.end(), ';', siblings);
+      text_tarray::const_iterator here = siblings.begin();
+      text_tarray::const_iterator end = siblings.end();
+      text_t shrunk_OID = OID;
+      shrink_parent (shrunk_OID);
+      while (here != end) {
+	if (*here == shrunk_OID && (here != siblings.begin())) {
+	  OID = *(here-1);
+	  if (*(OID.begin()) == '"') translate_parent (OID, parent);
+	  break;
+	}
+	here ++;
+      }
+    }
+  }
+}
+
+// returns true on success
+bool gdbmclass::getinfo (text_t key, infodbclass &info) {
+  text_t data;
+  
+  if (!getkeydata (key, data)) return false;
+  text_t::iterator here = data.begin ();
+  text_t::iterator end = data.end ();
+  
+  text_t ikey, ivalue;
+  info.clear (); // reset info
+  
+  while (getinfoline (here, end, ikey, ivalue)) {
+    info.addinfo (ikey, ivalue);
+  }
+  
+  return true;
+}
+
+// returns true if exists
+bool gdbmclass::exists (text_t key) {
+  text_t data;
+  return getkeydata (key, data);
+}
+
+// returns true on success
+bool gdbmclass::getkeydata (text_t key, text_t &data) {
+  datum key_data;
+  datum return_data;
+
+  if (gdbmfile == NULL) return false;
+  
+  // get a utf-8 encoded c string of the unicode key
+  key_data.dptr = (to_utf8(key)).getcstr();
+  if (key_data.dptr == NULL) {
+    if (logout != NULL) (*logout) << "gdbmclass: out of memory\n";
+    return false;
+  }
+  key_data.dsize = strlen (key_data.dptr);
+  
+  // fetch the result
+  return_data = gdbm_fetch (gdbmfile, key_data);
+  delete key_data.dptr;
+  
+  if (return_data.dptr == NULL) return false;
+
+  data.setcarr (return_data.dptr, return_data.dsize);
+  free (return_data.dptr);
+  data = to_uni(data);  // convert to unicode
+
+  return true;
+}
+
+// returns true on success
+bool gdbmclass::getinfoline (text_t::iterator &here, text_t::iterator end, 
+			     text_t &key, text_t &value) {
+  key.clear();
+  value.clear();
+
+  // ignore white space
+  while (here != end && is_unicode_space (*here)) here++;
+
+  // get the '<'
+  if (here == end || *here != '<') return false;
+  here++;
+  
+  // get the key
+  while (here != end && *here != '>') {
+    key.push_back(*here);
+    here++;
+  }
+  
+  // get the '>'
+  if (here == end || *here != '>') return false;
+  here++;
+  
+  // get the value
+  while (here != end && *here != '\n') {
+    if (*here == '\\') { 
+      // found escape character
+      here++;
+      if (here != end) {
+	if (*here == 'n') value.push_back ('\n');
+	else if (*here == 'r') value.push_back ('\r');
+	else value.push_back(*here);
+      }
+
+    } else {
+      // a normal character
+      value.push_back(*here);
+    }
+
+    here++;
+  }
+
+  return true;
+}
Index: /main/tags/2.25/gsdl/src/recpt/infodbclass.h
===================================================================
--- /main/tags/2.25/gsdl/src/recpt/infodbclass.h	(revision 21064)
+++ /main/tags/2.25/gsdl/src/recpt/infodbclass.h	(revision 21064)
@@ -0,0 +1,185 @@
+/**********************************************************************
+ *
+ * infodbclass.h -- 
+ * Copyright (C) 1999  The New Zealand Digital Library Project
+ *
+ * A component of the Greenstone digital library software
+ * from the New Zealand Digital Library Project at the
+ * University of Waikato, New Zealand.
+ *
+ * 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.
+ *
+ *********************************************************************/
+
+
+#ifndef INFODBCLASS_H
+#define INFODBCLASS_H
+
+
+#include "gsdlconf.h"
+#include "text_t.h"
+
+#if defined(GSDL_USE_OBJECTSPACE)
+#  include <ospace\std\iostream>
+#  include <ospace\std\fstream>
+#elif defined(GSDL_USE_IOS_H)
+#  include <iostream.h>
+#  include <fstream.h>
+#else
+#  include <iostream>
+#  include <fstream>
+#endif
+
+#ifdef __WIN32__
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+#include "autoconf.h"
+#include "systems.h"
+#include "gdbmconst.h"
+#include "gdbm.h"
+#ifdef __cplusplus
+}
+#endif
+
+#else
+#include <gdbm.h>
+#endif
+
+
+typedef map<text_t, text_tarray, lttext_t> text_tarraymap;
+
+
+// infodbclass is used to store information about a object
+class infodbclass {
+protected:
+  text_tarraymap info;
+
+public:
+  // type support for text_tarraymap
+  typedef text_tarraymap::iterator iterator;
+  typedef text_tarraymap::const_iterator const_iterator;
+  typedef text_tarraymap::reference reference;
+  typedef text_tarraymap::const_reference const_reference;
+  typedef text_tarraymap::size_type size_type;
+  typedef text_tarraymap::difference_type difference_type;
+  typedef text_tarraymap::const_reverse_iterator const_reverse_iterator;
+  typedef text_tarraymap::reverse_iterator reverse_iterator;
+  
+  // constructors
+  infodbclass ();
+
+  // basic container support
+  iterator begin () {return info.begin();}
+  const_iterator begin () const {return info.begin();}
+  iterator end () {return info.end();}
+  const_iterator end () const {return info.end();}
+
+  void erase(iterator pos) {info.erase(pos);}
+  void erase(iterator first, iterator last) {info.erase(first, last);}
+  infodbclass &operator=(const infodbclass &x) {info=x.info;return *this;}
+
+  bool empty () const {return info.empty();}
+  size_type size() const {return info.size();}
+
+
+  // added functionality
+  void clear () {info.erase(info.begin(),info.end());}
+
+  // the following functions deal with keys that can only
+  // have one value for compatibility
+  
+  // getinfo returns NULL if there isn't an entry with
+  // 'key' already defined, getintinfo returns 0 if there wasn't an
+  // entry with 'key' defined and operator[] returns "" if
+  // 'key' wasn't already defined (and sets 'key'="").
+  void setinfo (const text_t &key, const text_t &value);
+  void setintinfo (const text_t &key, int value);
+  void setcinfo (const text_t &key, unsigned short c);
+  text_t *getinfo (const text_t &key);
+  int getintinfo (const text_t &key);
+  text_t &operator[] (const text_t &key);
+
+
+  // the next set of functions allow you to set and access keys
+  // that can have more than one value
+
+  // getmultinfo returns NULL if there isn't an entry with
+  // 'key' already defined
+  void addinfo (const text_t &key, const text_t &value);
+  void addintinfo (const text_t &key, int value);
+  void addcinfo (const text_t &key, unsigned short c);
+  text_tarray *getmultinfo (const text_t &key);
+};
+
+
+class gdbmclass {
+public:
+  gdbmclass() {gdbmfile = NULL; logout = &cerr;};
+  ~gdbmclass() {};
+  
+  // returns true if opened
+  bool opendatabase (const text_t &filename, int mode, int num_retrys, 
+		     bool need_filelock);
+  void closedatabase ();
+
+  // replaces the .c, .p, .n, .l syntax (child, parent, next, previous) 
+  // it expects child, parent, etc. to exist if syntax has been used
+  // so you should test before using
+  text_t translate_OID (const text_t &OID, infodbclass &info);
+
+  // returns true on success
+  bool getinfo (text_t key, infodbclass &info);
+  void setlogout (ostream *thelogout) {logout = thelogout;}
+
+  // returns true if exists
+  bool exists (text_t key);
+
+  // returns true on success
+  bool setinfo (const text_t &key, const infodbclass &info);
+  // returns true on success
+  bool setinfo (const text_t &key, const text_t &data);
+
+  void deletekey (const text_t &key);
+
+  // getfirstkey and getnextkey are used for traversing the database
+  // no insertions or deletions should be carried out while traversing
+  // the database. when there are no keys left to visit in the database
+  // an empty string is returned.
+  text_t getfirstkey ();
+  text_t getnextkey (const text_t &key);
+
+    // returns true on success
+  bool getkeydata (text_t key, text_t &data);
+
+protected:
+  text_t openfile;
+  GDBM_FILE gdbmfile;
+  ostream *logout;
+
+  void get_first_child (text_t &OID, infodbclass &info);
+  void get_last_child (text_t &OID, infodbclass &info);
+  void get_next_sibling (text_t &OID, infodbclass &info);
+  void get_previous_sibling (text_t &OID, infodbclass &info);
+
+
+  // returns true on success
+  bool getinfoline (text_t::iterator &here, text_t::iterator end, 
+		   text_t &key, text_t &value);
+};
+
+
+#endif
Index: /main/tags/2.25/gsdl/src/recpt/invbrowserclass.cpp
===================================================================
--- /main/tags/2.25/gsdl/src/recpt/invbrowserclass.cpp	(revision 21064)
+++ /main/tags/2.25/gsdl/src/recpt/invbrowserclass.cpp	(revision 21064)
@@ -0,0 +1,39 @@
+/**********************************************************************
+ *
+ * invbrowserclass.cpp -- 
+ * Copyright (C) 1999  The New Zealand Digital Library Project
+ *
+ * A component of the Greenstone digital library software
+ * from the New Zealand Digital Library Project at the
+ * University of Waikato, New Zealand.
+ *
+ * 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.
+ *
+ *********************************************************************/
+
+#include "invbrowserclass.h"
+#include <assert.h>
+#include "OIDtools.h"
+
+invbrowserclass::invbrowserclass () {
+}
+
+invbrowserclass::~invbrowserclass () {
+}
+
+// returns the name that specifies the browserclass type
+text_t invbrowserclass::get_browser_name () {
+  return "Invisible";
+}
Index: /main/tags/2.25/gsdl/src/recpt/invbrowserclass.h
===================================================================
--- /main/tags/2.25/gsdl/src/recpt/invbrowserclass.h	(revision 21064)
+++ /main/tags/2.25/gsdl/src/recpt/invbrowserclass.h	(revision 21064)
@@ -0,0 +1,49 @@
+/**********************************************************************
+ *
+ * invbrowserclass.h -- 
+ * Copyright (C) 1999  The New Zealand Digital Library Project
+ *
+ * A component of the Greenstone digital library software
+ * from the New Zealand Digital Library Project at the
+ * University of Waikato, New Zealand.
+ *
+ * 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.
+ *
+ *********************************************************************/
+
+
+#ifndef INVBROWSERCLASS_H
+#define INVBROWSERCLASS_H
+
+#include "browserclass.h"
+
+class invbrowserclass : public browserclass {
+protected:
+
+public:
+
+  // this browser class does nothing by default - it should
+  // be overridden for receptionists wanting to display 
+  // 'Invisible' classifications in some way
+
+  invbrowserclass ();
+  virtual ~invbrowserclass ();
+
+  // returns the name that specifies the browserclass type
+  text_t get_browser_name ();
+
+};
+
+#endif
Index: /main/tags/2.25/gsdl/src/recpt/librarymain.cpp
===================================================================
--- /main/tags/2.25/gsdl/src/recpt/librarymain.cpp	(revision 21064)
+++ /main/tags/2.25/gsdl/src/recpt/librarymain.cpp	(revision 21064)
@@ -0,0 +1,256 @@
+/**********************************************************************
+ *
+ * librarymain.cpp -- 
+ * Copyright (C) 1999  The New Zealand Digital Library Project
+ *
+ * A component of the Greenstone digital library software
+ * from the New Zealand Digital Library Project at the
+ * University of Waikato, New Zealand.
+ *
+ * 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.
+ *
+ *********************************************************************/
+
+#include "receptionist.h"
+#include "cgiwrapper.h"
+#include "nullproto.h"
+#include "collectserver.h"
+#include "filter.h"
+#include "browsefilter.h"
+#include "mgqueryfilter.h"
+#include "mgppqueryfilter.h"
+#include "infodbclass.h"
+#include "mggdbmsource.h"
+#include "mgsearch.h"
+#include "mgppsearch.h"
+#include "fileutil.h"
+#include <assert.h>
+
+#include "action.h"
+#include "statusaction.h"
+#include "pageaction.h"
+#include "pingaction.h"
+#include "queryaction.h"
+#include "documentaction.h"
+#include "authenaction.h"
+#include "usersaction.h"
+#include "extlinkaction.h"
+#include "buildaction.h"
+#include "delhistoryaction.h"
+
+#include "browserclass.h"
+#include "vlistbrowserclass.h"
+#include "hlistbrowserclass.h"
+#include "datelistbrowserclass.h"
+#include "invbrowserclass.h"
+#include "pagedbrowserclass.h"
+#include "htmlbrowserclass.h"
+
+#include "recptconfig.h"
+
+int main () {
+  receptionist recpt;
+  nullproto nproto;
+
+  text_tarray collections;
+
+  // get gsdlhome
+  text_t gsdlhome;
+  site_cfg_read (gsdlhome);
+  text_t collectdir = filename_cat (gsdlhome, "collect");
+  read_dir (collectdir, collections);
+  
+  text_tarray::const_iterator thiscol = collections.begin();
+  text_tarray::const_iterator endcol = collections.end();
+  
+  while (thiscol != endcol) {
+    
+    // ignore the modelcol
+
+    if (*thiscol == "modelcol") {
+      thiscol ++;
+      continue;
+    }
+    
+    // read config file to see if built with mg or mgpp
+    text_t buildtype = "mg"; // mg is default
+    text_tarray cfgline;
+    text_t key;
+    text_t filename = filename_cat(collectdir, *thiscol, "index/build.cfg");
+    ifstream confin(filename.getcstr());
+
+    if (confin) {
+      while (read_cfg_line(confin, cfgline) >= 0) {
+	if (cfgline.size() ==2 ) {
+	  key = cfgline[0];
+	  cfgline.erase(cfgline.begin());
+	  if (key =="buildtype") {
+	    buildtype = cfgline[0];
+	    break;
+	  }
+	}
+      }
+    }
+    
+    confin.close();
+
+    // this memory is created but never destroyed
+    // we're also not doing any error checking to make sure we didn't
+    // run out of memory
+    collectserver *cserver = new collectserver();
+    gdbmclass *gdbmhandler = new gdbmclass();
+
+    // add a null filter
+    filterclass *filter = new filterclass ();
+    cserver->add_filter (filter);
+      
+    // add a browse filter
+    browsefilterclass *browsefilter = new browsefilterclass();
+    browsefilter->set_gdbmptr (gdbmhandler);
+    cserver->add_filter (browsefilter);  
+ 
+    if (buildtype == "mg") {
+       mgsearchclass *mgsearch = new mgsearchclass();
+ 
+       // add a query filter
+       mgqueryfilterclass *queryfilter = new mgqueryfilterclass();
+       queryfilter->set_gdbmptr (gdbmhandler);
+       queryfilter->set_mgsearchptr (mgsearch);
+       cserver->add_filter (queryfilter);
+       
+       // add a mg and gdbm source
+       mggdbmsourceclass *mggdbmsource = new mggdbmsourceclass ();
+       mggdbmsource->set_gdbmptr (gdbmhandler);
+       mggdbmsource->set_mgsearchptr (mgsearch);
+       cserver->add_source (mggdbmsource);
+   
+    }
+    else if (buildtype == "mgpp") {
+      
+      mgppsearchclass *mgsearch = new mgppsearchclass();
+
+      // add a query filter
+      mgppqueryfilterclass *queryfilter = new mgppqueryfilterclass();
+      queryfilter->set_gdbmptr (gdbmhandler);
+      queryfilter->set_mgsearchptr (mgsearch);
+      cserver->add_filter (queryfilter);
+      
+      // add a mg and gdbm source
+      mggdbmsourceclass *mggdbmsource = new mggdbmsourceclass ();
+      mggdbmsource->set_gdbmptr (gdbmhandler);
+      mggdbmsource->set_mgsearchptr (mgsearch);
+      cserver->add_source (mggdbmsource);
+   
+    }
+    
+    // inform collection server and everything it contains about its
+    // collection name
+    cserver->configure ("collection", *thiscol);
+  
+    // configure receptionist's collectinfo structure 
+    text_tarray colinfo;
+    colinfo.push_back (*thiscol);
+    colinfo.push_back (gsdlhome);
+    colinfo.push_back (gsdlhome);
+    recpt.configure ("collectinfo", colinfo);
+  
+    nproto.add_collectserver (cserver);
+    thiscol ++;
+  }
+  
+  // add the protocol to the receptionist
+  recpt.add_protocol (&nproto);
+  
+  // add other converters
+  utf8inconvertclass utf8inconvert;
+  utf8outconvertclass utf8outconvert;
+  recpt.add_converter ("u", &utf8inconvert, &utf8outconvert);
+
+  mapinconvertclass gbinconvert;
+  gbinconvert.setmapfile (gsdlhome, "gbku", 0x25a1);
+  mapoutconvertclass gboutconvert;
+  gboutconvert.setmapfile (gsdlhome, "ugbk", 0xa1f5);
+  recpt.add_converter ("g", &gbinconvert, &gboutconvert);
+
+  text_t armapfile = filename_cat (gsdlhome, "unicode", "MAPPINGS");
+  armapfile = filename_cat (armapfile, "WINDOWS", "1256.TXT");
+  simplemapinconvertclass arinconvert;
+  arinconvert.setmapfile (armapfile);
+  simplemapoutconvertclass aroutconvert;
+  aroutconvert.setmapfile (armapfile);
+  recpt.add_converter ("a", &arinconvert, &aroutconvert);  
+
+
+  // the list of actions. Note: these actions will become invalid
+  // at the end of this function.
+  statusaction astatusaction;
+  astatusaction.set_receptionist (&recpt);
+  recpt.add_action (&astatusaction);
+
+  pageaction apageaction;
+  apageaction.set_receptionist (&recpt);
+  recpt.add_action (&apageaction);
+
+  pingaction apingaction;
+  recpt.add_action (&apingaction);
+
+  queryaction aqueryaction;
+  aqueryaction.set_receptionist (&recpt);
+  recpt.add_action (&aqueryaction);
+
+  documentaction adocumentaction;
+  adocumentaction.set_receptionist (&recpt);
+  recpt.add_action (&adocumentaction);
+
+  usersaction ausersaction;
+  recpt.add_action (&ausersaction);
+
+  extlinkaction anextlinkaction;
+  recpt.add_action (&anextlinkaction);
+
+  buildaction abuildaction;
+  abuildaction.set_receptionist (&recpt);
+  recpt.add_action (&abuildaction);
+
+  authenaction aauthenaction;
+  aauthenaction.set_receptionist(&recpt);
+  recpt.add_action (&aauthenaction);
+
+  delhistoryaction adelhistoryaction;
+  recpt.add_action(&adelhistoryaction);
+
+  // list of browsers
+  vlistbrowserclass avlistbrowserclass;
+  recpt.add_browser (&avlistbrowserclass);
+  recpt.setdefaultbrowser ("VList");
+
+  hlistbrowserclass ahlistbrowserclass;
+  recpt.add_browser (&ahlistbrowserclass);
+
+  datelistbrowserclass adatelistbrowserclass;
+  recpt.add_browser (&adatelistbrowserclass);
+
+  invbrowserclass ainvbrowserclass;
+  recpt.add_browser (&ainvbrowserclass);
+
+  pagedbrowserclass apagedbrowserclass;
+  recpt.add_browser (&apagedbrowserclass);
+
+  htmlbrowserclass ahtmlbrowserclass;
+  recpt.add_browser (&ahtmlbrowserclass);
+
+  cgiwrapper (recpt, "");
+  return 0;
+}
Index: /main/tags/2.25/gsdl/src/recpt/nullproto.cpp
===================================================================
--- /main/tags/2.25/gsdl/src/recpt/nullproto.cpp	(revision 21064)
+++ /main/tags/2.25/gsdl/src/recpt/nullproto.cpp	(revision 21064)
@@ -0,0 +1,181 @@
+/**********************************************************************
+ *
+ * nullproto.cpp -- 
+ * Copyright (C) 1999  The New Zealand Digital Library Project
+ *
+ * A component of the Greenstone digital library software
+ * from the New Zealand Digital Library Project at the
+ * University of Waikato, New Zealand.
+ *
+ * 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.
+ *
+ *********************************************************************/
+
+#include "nullproto.h"
+#include "colservrconfig.h"
+#include <assert.h>
+
+
+// this configure will configure each of the collection servers
+void nullproto::configure (const text_t &key, const text_tarray &cfgline) {
+  // the naming of the collection should not be done here,
+  // it should be done just after the collection server has been 
+  // created
+  if (key == "collection" || key == "collectdir") return;
+
+  collectservermapclass::iterator here = cservers.begin();
+  collectservermapclass::iterator end = cservers.end();
+
+  while (here != end) {
+    assert ((*here).second.c != NULL);
+    if ((*here).second.c != NULL) {
+      if (key == "collectinfo") {
+	if ((*here).first == cfgline[0]) {
+	  (*here).second.c->configure ("gsdlhome", cfgline[1]);
+	  (*here).second.c->configure ("gdbmhome", cfgline[2]);
+	}
+      } else {
+	(*here).second.c->configure (key, cfgline);
+      }
+    }
+
+    here++;
+  }
+}
+
+// this init will configure and init each of the collection servers
+bool nullproto::init (ostream &logout) {
+  collectservermapclass::iterator here = cservers.begin();
+  collectservermapclass::iterator end = cservers.end();
+
+  while (here != end) {
+    assert ((*here).second.c != NULL);
+    if ((*here).second.c != NULL) {
+      const colservrconf &configinfo = (*here).second.c->get_configinfo ();
+      bool failed = false;
+
+      // configure this collection server
+
+      // note that we read build.cfg before collect.cfg so that the indexmaps
+      // are available to decode defaultindex, defaultsubcollection, and
+      // defaultlanguage
+      if (!build_cfg_read (*((*here).second.c), configinfo.gsdlhome,
+			   configinfo.collection)) {
+	outconvertclass text_t2ascii;
+	logout << text_t2ascii 
+	       << "Warning: couldn't read build.cfg file for collection \"" //****
+	       << configinfo.collection << "\", gsdlhome=\""
+	       << configinfo.gsdlhome << "\"\n";
+	failed = true; 
+      }
+
+      if (!collect_cfg_read (*((*here).second.c), configinfo.gsdlhome,
+			     configinfo.collection)) {
+	outconvertclass text_t2ascii;
+	logout << text_t2ascii 
+	       << "Warning: couldn't read collect.cfg file for collection \""
+	       << configinfo.collection << "\", gsdlhome=\"" 
+	       << configinfo.gsdlhome << "\"\n";
+	failed = true;
+      }
+
+      // don't bother initializing if one of the config files
+      // wasn't read correctly
+      if (!failed) {
+	if (!(*here).second.c->init (logout)) return false;
+      }
+    }
+    here++;
+  }
+
+  return true;
+}
+
+text_t nullproto::get_protocol_name () {
+  return "nullproto";
+}
+
+
+void nullproto::get_collection_list (text_tarray &collist, comerror_t &err, 
+				     ostream &/*logout*/) {
+  collist.erase(collist.begin(),collist.end());
+  err = noError;
+
+  collectservermapclass::iterator here = cservers.begin();
+  collectservermapclass::iterator end = cservers.end();
+  while (here != end) {
+    assert ((*here).second.c != NULL);
+    if ((*here).second.c != NULL) {
+      collist.push_back ((*here).second.c->get_collection_name());
+    }
+    here++;
+  }
+}
+
+void nullproto::has_collection (const text_t &collection, bool &hascollection, 
+				comerror_t &err, ostream &/*logout*/) {
+  hascollection = (cservers.getcollectserver(collection) != NULL);
+  err = noError;
+}
+
+void nullproto::ping (const text_t &collection, bool &wassuccess, 
+		      comerror_t &err, ostream &/*logout*/) {
+  wassuccess = (cservers.getcollectserver(collection) != NULL);
+  err = noError;
+}
+
+void nullproto::get_collectinfo (const text_t &collection, 
+				 ColInfoResponse_t &collectinfo,
+				 comerror_t &err, ostream &logout) {
+  collectserver *cserver = cservers.getcollectserver (collection);
+  if (cserver != NULL) cserver->get_collectinfo (collectinfo, err, logout);
+  else err = protocolError;
+}
+
+
+void nullproto::get_filterinfo (const text_t &collection,
+				InfoFiltersResponse_t &response,
+				comerror_t &err, ostream &logout) {
+  collectserver *cserver = cservers.getcollectserver (collection);
+  if (cserver != NULL) cserver->get_filterinfo (response, err, logout);
+  else err = protocolError;
+}
+
+void nullproto::get_filteroptions (const text_t &collection,
+				   const InfoFilterOptionsRequest_t &request,
+				   InfoFilterOptionsResponse_t &response, 
+				   comerror_t &err, ostream &logout) {
+  collectserver *cserver = cservers.getcollectserver (collection);
+  if (cserver != NULL) cserver->get_filteroptions (request, response, err, logout);
+  else err = protocolError;
+}
+
+void nullproto::filter (const text_t &collection,
+			FilterRequest_t &request,
+			FilterResponse_t &response,
+			comerror_t &err, ostream &logout) {
+  collectserver *cserver = cservers.getcollectserver (collection);
+  if (cserver != NULL) cserver->filter (request, response, err, logout);
+  else err = protocolError;
+}
+
+void nullproto::get_document (const text_t &collection,
+			      const DocumentRequest_t &request,
+			      DocumentResponse_t &response,
+			      comerror_t &err, ostream &logout) {
+  collectserver *cserver = cservers.getcollectserver (collection);
+  if (cserver != NULL) cserver->get_document (request, response, err, logout);
+  else err = protocolError;
+}
Index: /main/tags/2.25/gsdl/src/recpt/nullproto.h
===================================================================
--- /main/tags/2.25/gsdl/src/recpt/nullproto.h	(revision 21064)
+++ /main/tags/2.25/gsdl/src/recpt/nullproto.h	(revision 21064)
@@ -0,0 +1,82 @@
+/**********************************************************************
+ *
+ * nullproto.h -- 
+ * Copyright (C) 1999  The New Zealand Digital Library Project
+ *
+ * A component of the Greenstone digital library software
+ * from the New Zealand Digital Library Project at the
+ * University of Waikato, New Zealand.
+ *
+ * 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.
+ *
+ *********************************************************************/
+
+
+#ifndef NULLPROTO_H
+#define NULLPROTO_H
+
+#include "gsdlconf.h"
+#include "collectserver.h"
+#include "recptproto.h"
+
+
+class nullproto : public recptproto {
+protected:
+  collectservermapclass cservers;
+public:
+  virtual ~nullproto() {}
+
+  // add_collectserver should be called for each collection server
+  // before any configuration is done
+  void add_collectserver (collectserver *thecserver) 
+    {cservers.addcollectserver(thecserver);}
+
+  // this configure will configure each of the collection servers
+  void configure (const text_t &key, const text_tarray &cfgline);
+
+  // this init will init each of the collection servers
+  bool init (ostream &logout);
+
+  text_t get_protocol_name ();
+  void get_collection_list (text_tarray &collist, comerror_t &err, 
+			    ostream &logout);
+  void has_collection (const text_t &collection, bool &hascollection, 
+		       comerror_t &err, ostream &logout);
+  void ping (const text_t &collection, bool &wassuccess, 
+	     comerror_t &err, ostream &logout);
+  void get_collectinfo (const text_t &collection, 
+			ColInfoResponse_t &collectinfo,
+			comerror_t &err, ostream &logout);
+  void get_filterinfo (const text_t &collection,
+		       InfoFiltersResponse_t &response,
+		       comerror_t &err, ostream &logout);
+  void get_filteroptions (const text_t &collection,
+			  const InfoFilterOptionsRequest_t &request,
+			  InfoFilterOptionsResponse_t &response, 
+			  comerror_t &err, ostream &logout);
+  void filter (const text_t &collection,
+	       FilterRequest_t &request,
+	       FilterResponse_t &response,
+	       comerror_t &err, ostream &logout);
+
+  void get_document (const text_t &collection,
+		     const DocumentRequest_t &request,
+		     DocumentResponse_t &response,
+		     comerror_t &err, ostream &logout);
+
+};
+
+
+#endif
Index: /main/tags/2.25/gsdl/src/recpt/pageaction.cpp
===================================================================
--- /main/tags/2.25/gsdl/src/recpt/pageaction.cpp	(revision 21064)
+++ /main/tags/2.25/gsdl/src/recpt/pageaction.cpp	(revision 21064)
@@ -0,0 +1,429 @@
+/**********************************************************************
+ *
+ * pageaction.cpp -- 
+ * Copyright (C) 1999  The New Zealand Digital Library Project
+ *
+ * A component of the Greenstone digital library software
+ * from the New Zealand Digital Library Project at the
+ * University of Waikato, New Zealand.
+ *
+ * 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.
+ *
+ *********************************************************************/
+
+#include "OIDtools.h"
+#include "pageaction.h"
+#include "receptionist.h"
+#include <time.h>
+
+pageaction::pageaction () {
+
+  recpt = NULL;
+
+  // this action uses cgi variables "a", "p", and "hp"
+  cgiarginfo arg_ainfo;
+  arg_ainfo.shortname = "a";
+  arg_ainfo.longname = "action";
+  arg_ainfo.multiplechar = true;
+  arg_ainfo.defaultstatus = cgiarginfo::weak;
+  arg_ainfo.argdefault = "p";
+  arg_ainfo.savedarginfo = cgiarginfo::must;
+  argsinfo.addarginfo (NULL, arg_ainfo);
+
+  arg_ainfo.shortname = "p";
+  arg_ainfo.longname = "page";
+  arg_ainfo.multiplechar = true;
+  arg_ainfo.defaultstatus = cgiarginfo::weak;
+  arg_ainfo.argdefault = "home";
+  arg_ainfo.savedarginfo = cgiarginfo::must;
+  argsinfo.addarginfo (NULL, arg_ainfo);
+
+  arg_ainfo.shortname = "hp";
+  arg_ainfo.longname = "html page";
+  arg_ainfo.multiplechar = true;
+  arg_ainfo.defaultstatus = cgiarginfo::weak;
+  arg_ainfo.argdefault = "";
+  arg_ainfo.savedarginfo = cgiarginfo::mustnot;
+  argsinfo.addarginfo (NULL, arg_ainfo);
+}
+
+pageaction::~pageaction () {
+}
+
+bool pageaction::check_cgiargs (cgiargsinfoclass &/*argsinfo*/, cgiargsclass &/*args*/, 
+				ostream &/*logout*/) {
+  // don't want to check anything yet.
+  return true;
+}
+
+void pageaction::get_cgihead_info (cgiargsclass &/*args*/, recptprotolistclass * /*protos*/,
+				   response_t &response,text_t &response_data, 
+				   ostream &/*logout*/) {
+  response = content;
+  response_data = "text/html";
+}
+
+void pageaction::set_homeextra_macro (displayclass &disp, recptprotolistclass *protos, 
+				      ostream &logout) {
+
+  text_t homeextra = "<center><table width=_pagewidth_><tr valign=top>\n";
+  bool found_valid_col = false;
+  
+  recptprotolistclass::iterator rprotolist_here = protos->begin();
+  recptprotolistclass::iterator rprotolist_end = protos->end();
+  while (rprotolist_here != rprotolist_end) {
+    if ((*rprotolist_here).p != NULL) {
+
+      text_tarray collist;
+      comerror_t err;
+      (*rprotolist_here).p->get_collection_list (collist, err, logout);
+      if (err == noError) {
+	text_tarray::iterator collist_here = collist.begin();
+	text_tarray::iterator collist_end = collist.end();
+
+	int count = 0;
+	bool first = true;
+	while (collist_here != collist_end) {
+	  
+	  ColInfoResponse_t *cinfo = recpt->get_collectinfo_ptr ((*rprotolist_here).p, *collist_here, logout);
+	  
+	  if (cinfo != NULL) {
+	    if (cinfo->isPublic && (cinfo->buildDate > 0)) {
+	      
+	      found_valid_col = true;
+	      FilterResponse_t response;
+	      text_tset metadata;
+	      metadata.insert ("collectionname");
+	      metadata.insert ("iconcollection");
+	      metadata.insert ("iconcollectionsmall");
+	      text_t collectionname = *collist_here;
+	      text_t alt = collectionname;
+	      if (get_info ("collection", *collist_here, metadata, false, 
+			    (*rprotolist_here).p, response, logout)) {
+		if (!response.docInfo[0].metadata["collectionname"].values[0].empty())
+		  alt = response.docInfo[0].metadata["collectionname"].values[0];
+		
+		if (!response.docInfo[0].metadata["iconcollectionsmall"].values[0].empty())
+		    collectionname = "<img width=150 border=1 src=\""
+		      + response.docInfo[0].metadata["iconcollectionsmall"].values[0]
+		      + "\" alt=\"" + alt + "\">";
+		else if (!response.docInfo[0].metadata["iconcollection"].values[0].empty())
+		  collectionname = "<img width=150 border=1 src=\""
+		    + response.docInfo[0].metadata["iconcollection"].values[0]
+		    + "\" alt=\"" + alt + "\">";
+		else collectionname = alt;
+	      }
+		
+	      if ((count%3 == 0) && (!first))
+		homeextra += "</tr><tr valign=top>\n";
+	      
+	      text_t link = "<a href=\"_gwcgi_?a=p&p=about&c=" + *collist_here + "\">";
+	      if (*collist_here == "chinese")
+		link = "<a href=\"_gwcgi_?a=p&p=about&l=zh&nw=u&c=" + *collist_here + "\">";
+	      if (*collist_here == "arabic")
+		link = "<a href=\"_gwcgi_?a=p&p=about&l=ar&nw=u&c=" + *collist_here + "\">";
+
+	      if (!cinfo->receptionist.empty()) 
+		link = "<a href=\"" + cinfo->receptionist + "\">";
+	      
+	      homeextra += "<td>" + link + collectionname + "</a></td>\n";
+	      
+	      count ++;
+	      first = false;
+	    }
+	  }
+	  
+	  collist_here ++;
+	}
+	for (; count%3 != 0; count ++) homeextra += "<td></td>\n";
+      }
+    }
+    rprotolist_here ++;
+  }
+
+  if (!found_valid_col) {
+    homeextra += "<td>No valid (i.e. built and public) collections are available</td>\n";
+  }
+  homeextra += "</tr></table></center>\n";
+  disp.setmacro ("homeextra", "home", homeextra); 
+
+}
+
+void pageaction::define_internal_macros (displayclass &disp, cgiargsclass &args, 
+					 recptprotolistclass *protos, ostream &logout) {
+
+  // define_internal_macros sets the following macros:
+
+  // _numdocs_             the number of documents in the collection
+
+  // _builddate_           the date last built
+
+
+  // if page is "home"
+  // _homeextra_           this is the list of available collections and collection info
+  //                       to be displayed on the home page
+
+
+  // if page is "preferences"
+  // _collectionoption_    collections to search/browse (if cross-collection-searching is on)
+
+  // _htmloptions_         set to _htmloptionson_ if DocumentUseHTML is set
+
+  // _PreferencesDocsFromWeb_ set to 1 if corresponding format option is set
+
+  // _languageoption_      interface languages to select from (dependant on PreferenceLanguages)
+
+  // _encodingoption_      will be overridden to "" if chinese language interface isn't specified
+
+  // if page is "about"
+  // _textsubcollections_  the text on which subcollections make up the collection (if 
+  //                       cross-collection searching is being used
+
+  // _textbrowseoptions_   the 'how to find information' text in the about and help pages
+
+  // _numbrowseoptions_    the number of browsing options 
+
+
+  // if page is "help"
+  // _textbrowseoptions_   the 'how to find information' text in the about and help pages
+
+  // _numbrowseoptions_    the number of browsing options 
+
+  // _topicreadingdocs_    this section of the help text differs depending on what type of 
+  // _textreadingdocs_     collection it is (e.g. html collection, bibliographic collection etc.)
+  // _texthelpreadingdocs_ 
+
+  
+  if (recpt == NULL) {
+    logout << "ERROR (pageaction::define_internal_macros): This action does not contain\n"
+	   << "      information about any receptionists. The method set_receptionist was\n"
+	   << "      probably not called from the module which instantiated this action.\n";
+    return;
+  }
+
+  text_t &arg_p = args["p"];
+  text_t &arg_c = args["c"];
+  ColInfoResponse_t *cinfo = NULL;
+
+  recptproto* collectproto = protos->getrecptproto (arg_c, logout);
+  if (collectproto != NULL) {
+    cinfo = recpt->get_collectinfo_ptr (collectproto, arg_c, logout);
+
+    disp.setmacro ("numdocs", "Global", cinfo->numDocs);
+    unsigned long current_time = time(NULL);
+    unsigned long builddate = (current_time - cinfo->buildDate) / 86400;
+    disp.setmacro ("builddate", "Global", builddate);
+  }
+
+  if (arg_p == "home") set_homeextra_macro (disp, protos, logout);
+
+  else if (arg_p == "preferences") {
+    
+    // _collectionoption_
+
+    if (args["ccs"] == "1" && collectproto != NULL && (cinfo->ccsCols.size() > 1)) {
+      text_t collectionoption = "_textcollectionoption_";
+      text_tarray::const_iterator col_here = cinfo->ccsCols.begin();
+      text_tarray::const_iterator col_end = cinfo->ccsCols.end();
+      int count = 0;
+      while (col_here != col_end) {
+	text_t colname;
+	if (*col_here == arg_c) {
+	    colname = cinfo->collectionmeta["collectionname"];
+	} else {
+	  ColInfoResponse_t *this_cinfo = recpt->get_collectinfo_ptr (collectproto, *col_here, logout);
+	  if (this_cinfo == NULL) {col_here ++; continue;}
+	  colname = this_cinfo->collectionmeta["collectionname"];
+	}
+
+	count ++;
+	collectionoption += "<input type=checkbox name=\"cc\" value=\"" + 
+	  *col_here + "\" onClick=\"updatecc(\'" + *col_here + "\');\"> " +
+	  colname + "<br>\n";
+	col_here ++;
+      }
+      
+      if (count > 1)
+	disp.setmacro ("collectionoption", "preferences", collectionoption);
+    }
+
+    // _htmloptions_
+    
+    text_tmap::const_iterator it = cinfo->format.find ("DocumentUseHTML");
+    if ((it != cinfo->format.end()) && ((*it).second == "true")) {
+      disp.setmacro ("htmloptions", "preferences", "_htmloptionson_");
+
+
+      // _PreferenceDocsFromWeb_
+
+      it = cinfo->format.find ("PreferenceDocsFromWeb");
+      if ((it == cinfo->format.end()) || ((*it).second == "true"))
+	disp.setmacro ("PreferenceDocsFromWeb", "preferences", "1");
+    }
+
+    // _languageoption_
+    // this is kind of a hack (another one!!). note that there're potential 
+    // problems here as no checking is done anywhere to make sure language
+    // is set to a valid value. this does allow us to set which languages 
+    // should go in the preference selection box (from collect.cfg) however
+    // and that's sufficient for current requirements
+    
+    // currently supported languages (_languageoption_ will default to all
+    // these languages unless PreferenceLanguages is set
+    text_tarray languages;
+    languages.push_back ("en");
+    languages.push_back ("fr");
+    languages.push_back ("de");
+    languages.push_back ("es");
+    languages.push_back ("mi");
+    languages.push_back ("zh");
+    languages.push_back ("ar");
+    text_tarray::const_iterator this_lang = languages.begin();
+    text_tarray::const_iterator end_lang = languages.end();
+
+    text_t languageoption = "_textlanguage_\n<select name=\"l\" onChange=\"updatel();\">\n";
+    it = cinfo->format.find ("PreferenceLanguages");
+    if ((it != cinfo->format.end()) && (!(*it).second.empty())) {
+      text_tset pref_langs;
+      splitchar ((*it).second.begin(), (*it).second.end(), '|', pref_langs);
+      if (pref_langs.size() > 1) {
+	while (this_lang != end_lang) {
+	  if (pref_langs.find(*this_lang) != pref_langs.end())
+	    languageoption += "_" + *this_lang + "languageoption_\n";
+	  this_lang ++;
+	}
+	languageoption += "</select>\n";
+	disp.setmacro ("languageoption", "preferences", languageoption);
+      }
+	
+      // _encodingoption_
+
+      if (pref_langs.find("zh") == pref_langs.end())
+	disp.setmacro ("encodingoption", "preferences", "");
+
+    } else {
+      while (this_lang != end_lang) {
+	languageoption += "_" + *this_lang + "languageoption_\n";
+	this_lang ++;
+      }
+      languageoption += "</select>\n";
+      disp.setmacro ("languageoption", "preferences", languageoption);
+    }
+    
+  } else if (arg_p == "about" || arg_p == "help") {
+    if (collectproto == NULL) return;
+    
+    // _textbrowseoptions_ and _numbrowseoptions_
+    
+    FilterResponse_t response;
+    text_tset metadata;
+    metadata.insert ("Title");
+    bool getParents = false;
+    get_children ("", args["c"], metadata, getParents, collectproto, response, logout);
+
+    disp.setmacro ("numbrowseoptions", "help", response.docInfo.size()+1);
+
+    ResultDocInfo_tarray::iterator here = response.docInfo.begin();
+    ResultDocInfo_tarray::iterator end = response.docInfo.end();
+
+    // we're assuming that we've always got a search button
+    text_t shorttext = "<ul><li>_textSearchshort_\n";
+    text_t longtext = "_textSearchlong_";
+
+    while (here != end) {
+      text_t title = (*here).metadata["Title"].values[0];
+
+      text_t stext, ltext;
+      disp.expandstring ("help", "_text" + title + "short_", stext);
+      if (stext == ("_text" + title + "short_")) {
+	shorttext += "<li>_help:textdefaultshorttext_";
+	longtext += "_help:textdefaultlongtext_";
+      } else {
+	shorttext += "<li>" + stext;
+	longtext += "_help:text" + title + "long_";
+      }
+
+      here ++;
+    }
+    shorttext += "</ul>\n";
+    if (response.docInfo.size() > 1) disp.setmacro ("textbrowseoptions", "help", shorttext + longtext);
+    else disp.setmacro ("textbrowseoptions", "help", longtext);
+
+    if (arg_p == "help") {
+
+      // _topicreadingdocs_  _textreadingdocs_  _texthelpreadingdocs_
+          
+      // if HTML collection there's no how to read document text
+      text_tmap::const_iterator it = cinfo->format.find ("HelpNoDocs");
+      if ((it != cinfo->format.end()) && ((*it).second == "true")) {
+	disp.setmacro ("topicreadingdocs", "help", "");
+	disp.setmacro ("texthelpreadingdocs", "help", "");
+      }
+      it = cinfo->format.find ("HelpBibDocs");
+      if ((it != cinfo->format.end()) && ((*it).second == "true")) {
+	disp.setmacro ("texthelpreadingdocs", "help", "_bibtexthelpreadingdocs_");
+	disp.setmacro ("textreadingdocs", "help", "_bibtextreadingdocs_");
+      }
+      it = cinfo->format.find ("HelpBookDocs");
+      if ((it != cinfo->format.end()) && ((*it).second == "true")) {
+	disp.setmacro ("texthelpreadingdocs", "help", "_booktexthelpreadingdocs_");
+	disp.setmacro ("textreadingdocs", "help", "_booktextreadingdocs_");
+      }
+
+    }
+    if (arg_p == "about") {
+
+      // _textsubcollections_
+      if (args["ccs"] == "1" && (cinfo->ccsCols.size() > 1)) {
+	text_t textsubcollections = "_textsubcols1_(" + text_t(cinfo->ccsCols.size()) + ")";
+	text_tarray::const_iterator here = cinfo->ccsCols.begin();
+	text_tarray::const_iterator end = cinfo->ccsCols.end();
+	bool first = true;
+	int count = 0;
+	while (here != end) {
+	  if (*here == arg_c) {
+	    if (!first) textsubcollections += "<br>";
+	    textsubcollections += "\n" + cinfo->collectionmeta["collectionname"] + "\n";
+	  } else {
+	    ColInfoResponse_t *this_cinfo = recpt->get_collectinfo_ptr (collectproto, *here, logout);
+	    if (this_cinfo == NULL) {here ++; continue;}
+	    if (!first) textsubcollections += "<br>";
+	    textsubcollections += "\n" + this_cinfo->collectionmeta["collectionname"] + "\n";
+	  }
+	  count ++;
+	  first = false;
+	  here ++;
+	}
+	textsubcollections += "_textsubcols2_";
+	if (count > 1) 
+	  disp.setmacro ("textsubcollections", "about", textsubcollections);
+      }
+    }
+  }
+}
+
+bool pageaction::do_action (cgiargsclass &args, recptprotolistclass * /*protos*/, 
+			    browsermapclass * /*browsers*/, displayclass &disp, 
+			    outconvertclass &outconvert, ostream &textout, 
+			    ostream &/*logout*/) {
+
+  text_t &arg_p = args["p"];
+
+  textout << outconvert << disp << ("_" + arg_p + ":header_\n")
+	  << ("_" + arg_p + ":content_\n")
+	  << ("_" + arg_p + ":footer_\n");
+
+  return true;
+}
Index: /main/tags/2.25/gsdl/src/recpt/pageaction.h
===================================================================
--- /main/tags/2.25/gsdl/src/recpt/pageaction.h	(revision 21064)
+++ /main/tags/2.25/gsdl/src/recpt/pageaction.h	(revision 21064)
@@ -0,0 +1,73 @@
+/**********************************************************************
+ *
+ * pageaction.h -- 
+ * Copyright (C) 1999  The New Zealand Digital Library Project
+ *
+ * A component of the Greenstone digital library software
+ * from the New Zealand Digital Library Project at the
+ * University of Waikato, New Zealand.
+ *
+ * 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.
+ *
+ *********************************************************************/
+
+
+#ifndef PAGEACTION_H
+#define PAGEACTION_H
+
+
+#include "gsdlconf.h"
+#include "action.h"
+#include "receptionist.h"
+
+
+class pageaction : public action {
+  
+protected:
+  receptionist *recpt;
+
+  text_tset classify_meta;
+
+public:
+  pageaction ();
+  virtual ~pageaction ();
+
+  void set_receptionist (receptionist *therecpt) {recpt=therecpt;}
+
+  text_t get_action_name () {return "p";}
+
+  bool check_cgiargs (cgiargsinfoclass &argsinfo, cgiargsclass &args, 
+		      ostream &logout);
+
+  void get_cgihead_info (cgiargsclass &args, recptprotolistclass *protos,
+			 response_t &response,text_t &response_data, 
+			 ostream &logout);
+
+  void define_internal_macros (displayclass &disp, cgiargsclass &args, 
+			       recptprotolistclass *protos, ostream &logout);
+
+  bool do_action (cgiargsclass &args, recptprotolistclass *protos, 
+		  browsermapclass *browsers, displayclass &disp, 
+		  outconvertclass &outconvert, ostream &textout, 
+		  ostream &logout);
+
+protected:
+  void set_homeextra_macro (displayclass &disp, recptprotolistclass *protos, 
+			    ostream &logout);
+
+};
+
+
+#endif
Index: /main/tags/2.25/gsdl/src/recpt/pagedbrowserclass.cpp
===================================================================
--- /main/tags/2.25/gsdl/src/recpt/pagedbrowserclass.cpp	(revision 21064)
+++ /main/tags/2.25/gsdl/src/recpt/pagedbrowserclass.cpp	(revision 21064)
@@ -0,0 +1,189 @@
+/**********************************************************************
+ *
+ * pagedbrowserclass.cpp -- 
+ * Copyright (C) 1999  The New Zealand Digital Library Project
+ *
+ * A component of the Greenstone digital library software
+ * from the New Zealand Digital Library Project at the
+ * University of Waikato, New Zealand.
+ *
+ * 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.
+ *
+ *********************************************************************/
+
+#include "pagedbrowserclass.h"
+#include <assert.h>
+#include "OIDtools.h"
+
+pagedbrowserclass::pagedbrowserclass () {
+}
+
+pagedbrowserclass::~pagedbrowserclass () {
+}
+
+// returns the name that specifies the browserclass type
+text_t pagedbrowserclass::get_browser_name () {
+  return "Paged";
+}
+
+
+void pagedbrowserclass::load_metadata_defaults (text_tset &metadata) {
+  metadata.insert ("Title");
+}
+
+// if the "gp" (go to page) argument is set we need to set
+// the "d" argument to the corresponding page
+// also want to set "d" argument to first child if we're at
+// an 'Invisible' top level
+void pagedbrowserclass::processOID (cgiargsclass &args, recptproto *collectproto,
+                                    ostream &logout) {
+
+  text_t &arg_d = args["d"];
+  text_t &arg_gp = args["gp"];
+  text_tset metadata;
+  bool getParents = false;
+  FilterResponse_t response;
+
+  if ((!arg_d.empty()) && (!arg_gp.empty()) && (is_number (arg_gp))) {
+    text_t top;
+    get_top (arg_d, top);
+    metadata.insert ("Title");
+    get_children (top, args["c"], metadata, getParents, collectproto, response, logout);
+    ResultDocInfo_tarray::iterator dochere = response.docInfo.begin();
+    ResultDocInfo_tarray::iterator docend = response.docInfo.end();
+    while (dochere != docend) {
+      if ((*dochere).metadata["Title"].values[0] == arg_gp) {
+        arg_d = (*dochere).OID;
+        break;
+      }
+      dochere ++;
+    }
+
+  } else if (!arg_d.empty() && is_top(arg_d)) { // if top level doc, check if not invisible
+    metadata.insert("thistype");
+    if (get_info(arg_d, args["c"], metadata, getParents, collectproto, response, logout)) {
+      text_t type = response.docInfo[0].metadata["thistype"].values[0];
+      if (type=="Invisible") { // display first child
+        arg_d = arg_d + ".fc";
+      }
+    }
+  }
+}
+
+int pagedbrowserclass::output_section_group (ResultDocInfo_t &section, cgiargsclass &args,
+					     const text_t &/*collection*/, int /*colnumber*/, 
+					     format_t * /*formatlistptr*/, bool /*use_table*/, 
+					     text_tset &/*metadata*/, bool &/*getParents*/,
+					     recptproto * /*collectproto*/, displayclass &disp, 
+					     outconvertclass &outconvert, ostream &textout, 
+					     ostream &/*logout*/) {
+
+  // this browser class only handles document levels
+  if (args["d"].empty()) return 0;
+
+  if (section.OID != args["d"]) {
+    text_t httpprevarrow = "_httpdocument_&cl=" + args["cl"] + "&d=" + section.OID;
+    text_t parentarrow = "<a href=\"" + httpprevarrow + "\">_iconprev_</a>\n";
+    disp.setmacro ("httpprevarrow", "document", httpprevarrow);
+    disp.setmacro ("parentarrow", "document", parentarrow);
+    return 0;
+  }
+
+  // must be at top level to get to here!
+  textout << outconvert << disp << "<b>" << section.metadata["Title"].values[0] 
+	  << "_document:textintro_</b>\n";
+  
+  return 0;
+}
+
+int pagedbrowserclass::output_section_group (FilterResponse_t &sections, cgiargsclass &args,
+					     const text_t &/*collection*/, int /*colnumber*/, 
+					     format_t * /*formatlistptr*/, bool /*use_table*/, 
+					     text_tset &/*metadata*/, bool &/*getParents*/,
+					     recptproto * /*collectproto*/, displayclass &disp, 
+					     outconvertclass &outconvert, ostream &textout, 
+					     ostream &/*logout*/) {
+
+  text_t &arg_d = args["d"];
+
+  // this browser class only handles document levels
+  if (arg_d.empty()) return 0;
+
+  text_t previousOID, previoustitle, nextOID, nexttitle;
+  text_t previousarrow, nextarrow, httpprevarrow, httpnextarrow;
+  bool found = false;
+
+  // this should be our list of pages
+
+  ResultDocInfo_tarray::iterator thissection = sections.docInfo.begin();
+  ResultDocInfo_tarray::iterator endsection = sections.docInfo.end();
+
+  while (thissection != endsection) {
+    if (arg_d == (*thissection).OID) {
+      found = true;
+      textout << outconvert << disp 
+	      << "<table><tr valign=top><td colspan=3><center><b>_page_"
+	      << (*thissection).metadata["Title"].values[0] << "</b>\n";
+      if (thissection != sections.docInfo.begin()) {
+	previousOID = (*(thissection-1)).OID;
+	previoustitle = (*(thissection-1)).metadata["Title"].values[0];
+      } else {
+	previousarrow = "_document:parentarrow_";
+      }
+
+      if ((thissection+1) != endsection) {
+	nextOID = (*(thissection+1)).OID;
+	nexttitle = (*(thissection+1)).metadata["Title"].values[0];
+      }
+      break;
+    }
+    thissection ++;
+  }
+
+  if (!found) {
+    textout << outconvert << disp 
+	    << "<table><tr valign=top> <td colspan=3><center>\n";
+  }
+  int numpages = sections.docInfo.size();
+  textout << outconvert << disp 
+	  << ("_document:textnumpages_(" + text_t(numpages) + ")</center></td></tr>\n");
+
+  if (!found) {
+    httpnextarrow = "_httpdocument_&cl=" + args["cl"] + "&d=" + sections.docInfo[0].OID;
+    nextarrow = "<a href=\"" + httpnextarrow + "\">" + 
+      sections.docInfo[0].metadata["Title"].values[0] + "_iconnext_</a>\n";
+
+  } else {
+    if (!previousOID.empty()) {
+      httpprevarrow = "_httpdocument_&cl=" + args["cl"] + "&d=" + previousOID;
+      previousarrow = "<a href=\"" + httpprevarrow + "\">_iconprev_" + previoustitle + "</a>\n";
+    }
+    if (!nextOID.empty()) {
+      httpnextarrow = "_httpdocument_&cl=" + args["cl"] + "&d=" + nextOID;
+      nextarrow = "<a href=\"" + httpnextarrow + "\">" + nexttitle + "_iconnext_</a>\n";
+    }
+  }
+
+  if (!httpprevarrow.empty()) disp.setmacro ("httpprevarrow", "document", httpprevarrow);
+  if (!httpnextarrow.empty()) disp.setmacro ("httpnextarrow", "document", httpnextarrow);
+
+  textout << outconvert << disp << "<tr valign=middle>\n"
+	  << "<td align=right>" << previousarrow << "</td>\n"
+	  << "<td align=center valign=top>_document:gotoform_</td>"
+	  << "<td align=left>" << nextarrow << "</td>\n"
+	  << "</tr></table>\n";
+
+  return 0;
+}
Index: /main/tags/2.25/gsdl/src/recpt/pagedbrowserclass.h
===================================================================
--- /main/tags/2.25/gsdl/src/recpt/pagedbrowserclass.h	(revision 21064)
+++ /main/tags/2.25/gsdl/src/recpt/pagedbrowserclass.h	(revision 21064)
@@ -0,0 +1,63 @@
+/**********************************************************************
+ *
+ * pagedbrowserclass.h -- 
+ * Copyright (C) 1999  The New Zealand Digital Library Project
+ *
+ * A component of the Greenstone digital library software
+ * from the New Zealand Digital Library Project at the
+ * University of Waikato, New Zealand.
+ *
+ * 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.
+ *
+ *********************************************************************/
+
+
+#ifndef PAGEDBROWSERCLASS_H
+#define PAGEDBROWSERCLASS_H
+
+#include "browserclass.h"
+
+class pagedbrowserclass : public browserclass {
+protected:
+
+public:
+
+  pagedbrowserclass ();
+  virtual ~pagedbrowserclass ();
+
+  // returns the name that specifies the browserclass type
+  virtual text_t get_browser_name ();
+
+  void load_metadata_defaults (text_tset &metadata);
+
+  virtual void processOID (cgiargsclass &args, recptproto *collectproto,
+			   ostream &logout);
+
+
+  virtual int output_section_group (ResultDocInfo_t &section, cgiargsclass &args,
+				    const text_t &collection, int colnumber, format_t *formatlistptr, 
+				    bool use_table, text_tset &metadata, bool &getParents,
+				    recptproto *collectproto, displayclass &disp, 
+				    outconvertclass &outconvert, ostream &textout, ostream &logout);
+
+  virtual int output_section_group (FilterResponse_t &sections, cgiargsclass &args,
+				    const text_t &collection, int colnumber, format_t *formatlistptr, 
+				    bool use_table, text_tset &metadata, bool &getParents,
+				    recptproto *collectproto, displayclass &disp, 
+				    outconvertclass &outconvert, ostream &textout, ostream &logout);
+
+};
+
+#endif
Index: /main/tags/2.25/gsdl/src/recpt/pingaction.cpp
===================================================================
--- /main/tags/2.25/gsdl/src/recpt/pingaction.cpp	(revision 21064)
+++ /main/tags/2.25/gsdl/src/recpt/pingaction.cpp	(revision 21064)
@@ -0,0 +1,82 @@
+/**********************************************************************
+ *
+ * pingaction.cpp -- 
+ * Copyright (C) 1999  The New Zealand Digital Library Project
+ *
+ * A component of the Greenstone digital library software
+ * from the New Zealand Digital Library Project at the
+ * University of Waikato, New Zealand.
+ *
+ * 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.
+ *
+ *********************************************************************/
+
+#include "pingaction.h"
+
+pingaction::pingaction () {
+  // this action uses cgi variable "a"
+  cgiarginfo arg_ainfo;
+  arg_ainfo.shortname = "a";
+  arg_ainfo.longname = "action";
+  arg_ainfo.multiplechar = true;
+  arg_ainfo.defaultstatus = cgiarginfo::weak;
+  arg_ainfo.argdefault = "ping";
+  arg_ainfo.savedarginfo = cgiarginfo::must;
+
+  argsinfo.addarginfo (NULL, arg_ainfo);
+
+}
+
+void pingaction::get_cgihead_info (cgiargsclass &/*args*/, recptprotolistclass * /*protos*/,
+				   response_t &response, text_t &response_data, 
+				   ostream &/*logout*/) {
+  response = content;
+  response_data = "text/html";
+}
+
+
+bool pingaction::do_action (cgiargsclass &args, recptprotolistclass *protos, 
+			    browsermapclass * /*browsers*/, displayclass &/*disp*/, 
+			    outconvertclass &outconvert, ostream &textout, 
+			    ostream &logout) {
+  bool wassuccess = false;
+  comerror_t err;
+  
+  recptproto *collectproto = protos->getrecptproto (args["c"], logout);
+  if (!args["c"].empty() && (collectproto != NULL)) {
+    collectproto->ping (args["c"], wassuccess, err, logout);
+    if (err != noError) wassuccess = false; // a communication error
+  }
+
+  textout << outconvert
+	  << "<html>\n"
+	  << "<head>\n"
+	  << "<title>Ping</title>\n"
+	  << "</head>\n"
+	  << "<body>\n"
+	  << "Ping for \"" << args["c"] << "\" ";
+
+  if (wassuccess) {
+    textout << outconvert << " succeeded.\n";
+  } else {
+    textout << outconvert << " did not succeed.\n";
+  }
+
+  textout << outconvert 
+	  << "</body>\n"
+	  << "</html>\n";
+
+  return true;
+};
Index: /main/tags/2.25/gsdl/src/recpt/pingaction.h
===================================================================
--- /main/tags/2.25/gsdl/src/recpt/pingaction.h	(revision 21064)
+++ /main/tags/2.25/gsdl/src/recpt/pingaction.h	(revision 21064)
@@ -0,0 +1,52 @@
+/**********************************************************************
+ *
+ * pingaction.h -- 
+ * Copyright (C) 1999  The New Zealand Digital Library Project
+ *
+ * A component of the Greenstone digital library software
+ * from the New Zealand Digital Library Project at the
+ * University of Waikato, New Zealand.
+ *
+ * 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.
+ *
+ *********************************************************************/
+
+
+#ifndef PINGACTION_H
+#define PINGACTION_H
+
+#include "gsdlconf.h"
+#include "action.h"
+
+
+class pingaction : public action {
+public:
+  pingaction ();
+  virtual ~pingaction () {}
+
+  text_t get_action_name () {return "ping";}
+
+  void get_cgihead_info (cgiargsclass &args, recptprotolistclass *protos,
+			 response_t &response, text_t &response_data, 
+			 ostream &logout);
+
+  bool do_action (cgiargsclass &args, recptprotolistclass *protos, 
+		  browsermapclass *browsers, displayclass &disp, 
+		  outconvertclass &outconvert, ostream &textout, 
+		  ostream &logout);
+};
+
+
+#endif
Index: /main/tags/2.25/gsdl/src/recpt/queryaction.cpp
===================================================================
--- /main/tags/2.25/gsdl/src/recpt/queryaction.cpp	(revision 21064)
+++ /main/tags/2.25/gsdl/src/recpt/queryaction.cpp	(revision 21064)
@@ -0,0 +1,1134 @@
+/**********************************************************************
+ *
+ * queryaction.cpp -- 
+ * Copyright (C) 1999  The New Zealand Digital Library Project
+ *
+ * A component of the Greenstone digital library software
+ * from the New Zealand Digital Library Project at the
+ * University of Waikato, New Zealand.
+ *
+ * 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.
+ *
+ *********************************************************************/
+
+#include "queryaction.h"
+#include "querytools.h"
+#include "formattools.h"
+#include "cgiutils.h"
+#include "OIDtools.h"
+//#include "infodbclass.h"
+#include "fileutil.h"
+#include "text_t.h"
+#include "historydb.h"
+
+void colinfo_t::clear () {
+  formatlistptr = NULL;
+  browserptr = NULL;
+}
+
+void QueryResult_t::clear() {
+  doc.clear();
+  collection.clear();
+}
+
+queryaction::queryaction () {
+
+  recpt = NULL;
+  num_phrases = 0;
+
+  // this action uses cgi variable "a"
+  cgiarginfo arg_ainfo;
+  arg_ainfo.shortname = "a";
+  arg_ainfo.longname = "action";
+  arg_ainfo.multiplechar = true;
+  arg_ainfo.defaultstatus = cgiarginfo::weak;
+  arg_ainfo.argdefault = "q";
+  arg_ainfo.savedarginfo = cgiarginfo::must;
+  argsinfo.addarginfo (NULL, arg_ainfo);
+
+  // "b" - 0 = simple, 1 = advanced
+  arg_ainfo.shortname = "b";
+  arg_ainfo.longname = "query mode";
+  arg_ainfo.multiplechar = false;
+  arg_ainfo.defaultstatus = cgiarginfo::weak;
+  arg_ainfo.argdefault = "0";
+  arg_ainfo.savedarginfo = cgiarginfo::must;
+  argsinfo.addarginfo (NULL, arg_ainfo);
+
+  // "h"
+  arg_ainfo.shortname = "h";
+  arg_ainfo.longname = "main index";
+  arg_ainfo.multiplechar = true;
+  arg_ainfo.defaultstatus = cgiarginfo::weak;
+  arg_ainfo.argdefault = "";
+  arg_ainfo.savedarginfo = cgiarginfo::must;
+  argsinfo.addarginfo (NULL, arg_ainfo);
+
+  // "h2"
+  arg_ainfo.shortname = "h2";
+  arg_ainfo.longname = "main index for second query";
+  arg_ainfo.multiplechar = true;
+  arg_ainfo.defaultstatus = cgiarginfo::weak;
+  arg_ainfo.argdefault = "";
+  arg_ainfo.savedarginfo = cgiarginfo::must;
+  argsinfo.addarginfo (NULL, arg_ainfo);
+
+  // "j"
+  arg_ainfo.shortname = "j";
+  arg_ainfo.longname = "sub collection index";
+  arg_ainfo.multiplechar = true;
+  arg_ainfo.defaultstatus = cgiarginfo::weak;
+  arg_ainfo.argdefault = "";
+  arg_ainfo.savedarginfo = cgiarginfo::must;
+  argsinfo.addarginfo (NULL, arg_ainfo);
+
+  // "j2"
+  arg_ainfo.shortname = "j2";
+  arg_ainfo.longname = "sub collection index for second query";
+  arg_ainfo.multiplechar = true;
+  arg_ainfo.defaultstatus = cgiarginfo::weak;
+  arg_ainfo.argdefault = "";
+  arg_ainfo.savedarginfo = cgiarginfo::must;
+  argsinfo.addarginfo (NULL, arg_ainfo);
+
+  // "n"
+  arg_ainfo.shortname = "n";
+  arg_ainfo.longname = "language index";
+  arg_ainfo.multiplechar = true;
+  arg_ainfo.defaultstatus = cgiarginfo::weak;
+  arg_ainfo.argdefault = "";
+  arg_ainfo.savedarginfo = cgiarginfo::must;
+  argsinfo.addarginfo (NULL, arg_ainfo);
+
+  // "n2"
+  arg_ainfo.shortname = "n2";
+  arg_ainfo.longname = "language index for second query";
+  arg_ainfo.multiplechar = true;
+  arg_ainfo.defaultstatus = cgiarginfo::weak;
+  arg_ainfo.argdefault = "";
+  arg_ainfo.savedarginfo = cgiarginfo::must;
+  argsinfo.addarginfo (NULL, arg_ainfo);
+
+  // "q"
+  arg_ainfo.shortname = "q";
+  arg_ainfo.longname = "query string";
+  arg_ainfo.multiplechar = true;
+  arg_ainfo.defaultstatus = cgiarginfo::weak;
+  arg_ainfo.argdefault = "";
+  arg_ainfo.savedarginfo = cgiarginfo::must;
+  argsinfo.addarginfo (NULL, arg_ainfo);
+
+  // "q2"
+  arg_ainfo.shortname = "q2";
+  arg_ainfo.longname = "query string for second query";
+  arg_ainfo.multiplechar = true;
+  arg_ainfo.defaultstatus = cgiarginfo::weak;
+  arg_ainfo.argdefault = "";
+  arg_ainfo.savedarginfo = cgiarginfo::must;
+  argsinfo.addarginfo (NULL, arg_ainfo);
+
+  // "cq2" ""=don't combine, "and", "or", "not"
+  arg_ainfo.shortname = "cq2";
+  arg_ainfo.longname = "combine queries";
+  arg_ainfo.multiplechar = true;
+  arg_ainfo.defaultstatus = cgiarginfo::weak;
+  arg_ainfo.argdefault = "";
+  arg_ainfo.savedarginfo = cgiarginfo::must;
+  argsinfo.addarginfo (NULL, arg_ainfo);
+
+  // "t" - 1 = ranked 0 = boolean
+  arg_ainfo.shortname = "t";
+  arg_ainfo.longname = "search type";
+  arg_ainfo.multiplechar = false;
+  arg_ainfo.defaultstatus = cgiarginfo::weak;
+  arg_ainfo.argdefault = "1";
+  arg_ainfo.savedarginfo = cgiarginfo::must;
+  argsinfo.addarginfo (NULL, arg_ainfo);
+
+  // "k"
+  arg_ainfo.shortname = "k";
+  arg_ainfo.longname = "casefolding";
+  arg_ainfo.multiplechar = false;
+  arg_ainfo.defaultstatus = cgiarginfo::weak;
+  arg_ainfo.argdefault = "1";
+  arg_ainfo.savedarginfo = cgiarginfo::must;
+  argsinfo.addarginfo (NULL, arg_ainfo);
+
+  // "s"
+  arg_ainfo.shortname = "s";
+  arg_ainfo.longname = "stemming";
+  arg_ainfo.multiplechar = false;
+  arg_ainfo.defaultstatus = cgiarginfo::weak;
+  arg_ainfo.argdefault ="0";
+  arg_ainfo.savedarginfo = cgiarginfo::must;
+  argsinfo.addarginfo (NULL, arg_ainfo);
+
+  // "m"
+  arg_ainfo.shortname = "m";
+  arg_ainfo.longname = "maximum number of documents";
+  arg_ainfo.multiplechar = true;
+  arg_ainfo.defaultstatus = cgiarginfo::weak;
+  arg_ainfo.argdefault = "50";
+  arg_ainfo.savedarginfo = cgiarginfo::must;
+  argsinfo.addarginfo (NULL, arg_ainfo);
+
+  // "o"
+  arg_ainfo.shortname = "o";
+  arg_ainfo.longname = "hits per page";
+  arg_ainfo.multiplechar = true;
+  arg_ainfo.defaultstatus = cgiarginfo::weak;
+  arg_ainfo.argdefault = "20";
+  arg_ainfo.savedarginfo = cgiarginfo::must;
+  argsinfo.addarginfo (NULL, arg_ainfo);
+
+  // "r"
+  arg_ainfo.shortname = "r";
+  arg_ainfo.longname = "start results from";
+  arg_ainfo.multiplechar = true;
+  arg_ainfo.defaultstatus = cgiarginfo::weak;
+  arg_ainfo.argdefault = "1";
+  arg_ainfo.savedarginfo = cgiarginfo::must;
+  argsinfo.addarginfo (NULL, arg_ainfo);
+
+  // "ccs"
+  arg_ainfo.shortname = "ccs";
+  arg_ainfo.longname = "cross collection searching";
+  arg_ainfo.multiplechar = false;
+  arg_ainfo.defaultstatus = cgiarginfo::weak;
+  arg_ainfo.argdefault = "0";
+  arg_ainfo.savedarginfo = cgiarginfo::must;
+  argsinfo.addarginfo (NULL, arg_ainfo);
+
+  // "ccp"
+  arg_ainfo.shortname = "ccp";
+  arg_ainfo.longname = "cross collection page";
+  arg_ainfo.multiplechar = false;
+  arg_ainfo.defaultstatus = cgiarginfo::weak;
+  arg_ainfo.argdefault = "0";
+  arg_ainfo.savedarginfo = cgiarginfo::must;
+  argsinfo.addarginfo (NULL, arg_ainfo);
+
+  // "cc"
+  arg_ainfo.shortname = "cc";
+  arg_ainfo.longname = "collections to search";
+  arg_ainfo.multiplechar = true;
+  arg_ainfo.multiplevalue = true;
+  arg_ainfo.defaultstatus = cgiarginfo::weak;
+  arg_ainfo.argdefault = "";
+  arg_ainfo.savedarginfo = cgiarginfo::must;
+  argsinfo.addarginfo (NULL, arg_ainfo);
+
+  // "hd" history display  - search history only displayed when
+  // this var set.
+  arg_ainfo.shortname = "hd";
+  arg_ainfo.longname = "history display";
+  arg_ainfo.multiplechar = false;
+  arg_ainfo.multiplevalue = false;
+  arg_ainfo.defaultstatus = cgiarginfo::weak;
+  arg_ainfo.argdefault = "0";
+  arg_ainfo.savedarginfo = cgiarginfo::must;
+  argsinfo.addarginfo (NULL, arg_ainfo);
+	    
+
+ // "hs"  save - set to 1 in query form, so only save when submit
+  // query
+  // 0 = no save 1 = save
+  arg_ainfo.shortname = "hs";
+  arg_ainfo.longname = "history save";
+  arg_ainfo.multiplechar = false;
+  arg_ainfo.defaultstatus = cgiarginfo::weak;
+  arg_ainfo.argdefault = "0";
+  arg_ainfo.savedarginfo = cgiarginfo::mustnot;
+  argsinfo.addarginfo (NULL, arg_ainfo);
+
+
+  // "hcl" compress the list (show only the last 5)
+  // 0 = expand, 1 = compress
+
+  arg_ainfo.shortname = "hcl";
+  arg_ainfo.longname = "history compress list";
+  arg_ainfo.multiplechar = false;
+  arg_ainfo.defaultstatus = cgiarginfo::weak;
+  arg_ainfo.argdefault = "1";
+  arg_ainfo.savedarginfo = cgiarginfo::must;
+  argsinfo.addarginfo (NULL, arg_ainfo);
+
+
+  // new arg for granularity, for mgpp collections
+  arg_ainfo.shortname = "g";
+  arg_ainfo.longname = "granularity";
+  arg_ainfo.multiplechar = true;
+  arg_ainfo.defaultstatus = cgiarginfo::weak;
+  arg_ainfo.argdefault = "Document";
+  arg_ainfo.savedarginfo = cgiarginfo::must;
+  argsinfo.addarginfo (NULL, arg_ainfo);
+
+
+
+}
+
+void queryaction::configure (const text_t &key, const text_tarray &cfgline) {
+  action::configure (key, cfgline);
+}
+
+bool queryaction::init (ostream &logout) {
+  return action::init (logout);
+}
+
+bool queryaction::check_cgiargs (cgiargsinfoclass &argsinfo, cgiargsclass &args, 
+				 ostream &logout) {
+
+  // check t argument
+  int arg_t = args.getintarg("t");
+  if (arg_t != 0 && arg_t != 1) {
+    logout << "Warning: \"t\" argument out of range (" << arg_t << ")\n";
+    cgiarginfo *tinfo = argsinfo.getarginfo ("t");
+    if (tinfo != NULL) args["t"] = tinfo->argdefault;
+  }
+
+  // check k argument
+  int arg_k = args.getintarg("k");
+  if (arg_k != 0 && arg_k != 1) {
+    logout << "Warning: \"k\" argument out of range (" << arg_k << ")\n";
+    cgiarginfo *kinfo = argsinfo.getarginfo ("k");
+    if (kinfo != NULL) args["k"] = kinfo->argdefault;
+  }
+
+  // check s argument
+  int arg_s = args.getintarg("s");
+  if (arg_s != 0 && arg_s != 1) {
+    logout << "Warning: \"s\" argument out of range (" << arg_s << ")\n";
+    cgiarginfo *sinfo = argsinfo.getarginfo ("s");
+    if (sinfo != NULL) args["s"] = sinfo->argdefault;
+  }
+
+  // check m argument
+  int arg_m = args.getintarg("m");
+  if (arg_m < -1) {
+    logout << "Warning: \"m\" argument less than -1 (" << arg_m << ")\n";
+    cgiarginfo *minfo = argsinfo.getarginfo ("m");
+    if (minfo != NULL) args["m"] = minfo->argdefault;
+  }
+
+  // check o argument
+  int arg_o = args.getintarg("o");
+  if (arg_o < -1) {
+    logout << "Warning: \"o\" argument less than -1 (" << arg_o << ")\n";
+    cgiarginfo *oinfo = argsinfo.getarginfo ("o");
+    if (oinfo != NULL) args["o"] = oinfo->argdefault;
+  }
+
+  // check r argument
+  int arg_r = args.getintarg("r");
+  if (arg_r < 1) {
+    logout << "Warning: \"r\" argument less than 1 (" << arg_r << ")\n";
+    cgiarginfo *rinfo = argsinfo.getarginfo ("r");
+    if (rinfo != NULL) args["r"] = rinfo->argdefault;
+  }
+  //check hd argument
+    int arg_hd = args.getintarg("hd");
+    if (arg_hd !=0 && arg_hd !=1) {
+      logout << "Warning: \"hd\" argument out of range (" << arg_hd << ")\n";
+          cgiarginfo *hdinfo = argsinfo.getarginfo ("hd");
+	      if (hdinfo != NULL) args["hd"] = hdinfo->argdefault;
+    }  
+  //check hs argument
+  int arg_hs = args.getintarg("hs");
+  if (arg_hs !=0 && arg_hs !=1) {
+    logout << "Warning: \"hs\" argument out of range (" << arg_hs << ")\n";
+    cgiarginfo *hsinfo = argsinfo.getarginfo ("hs");
+    if (hsinfo != NULL) args["hs"] = hsinfo->argdefault;
+  }
+
+  // chech hcl argument
+  int arg_hcl = args.getintarg("hcl");
+  if (arg_hcl !=0 && arg_hcl !=1) {
+    logout << "Warning: \"hcl\" argument out of range (" << arg_hcl << ")\n";
+    cgiarginfo *hclinfo = argsinfo.getarginfo ("hcl");
+    if (hclinfo != NULL) args["hcl"] = hclinfo->argdefault;
+  }
+
+  return true;
+}
+
+void queryaction::get_cgihead_info (cgiargsclass &/*args*/, recptprotolistclass * /*protos*/,
+				    response_t &response, text_t &response_data, 
+				    ostream &/*logout*/) {
+  response = content;
+  response_data = "text/html";
+}
+
+void queryaction::define_internal_macros (displayclass &disp, cgiargsclass &args, 
+					  recptprotolistclass * /*protos*/, 
+					  ostream &/*logout*/) {
+
+  // define_internal_macros sets the following macros:
+
+  // _quotedquery_  the part of the query string that was quoted for post-processing
+
+
+
+  // The following macros are set later (in define_query_macros) as they can't be set until 
+  // the query has been done.
+
+  // _freqmsg_      the term frequency string
+
+  // _resultline_   the "x documents matched the query" string
+
+  // _prevfirst_    these are used when setting up the links to previous/next
+  // _prevlast_     pages of results (_thisfirst_ and _thislast_ are used to set
+  // _nextfirst_    the 'results x-x for query: xxxx' string in the title bar)
+  // _nextlast_
+  // _thisfirst_
+  // _thislast_
+
+
+  // get the quoted bits of the query string and set _quotedquery_
+  text_tarray phrases;
+  get_phrases (args["q"], phrases);
+  num_phrases = phrases.size();
+  text_tarray::const_iterator phere = phrases.begin();
+  text_tarray::const_iterator pend = phrases.end();
+  bool first = true;
+  text_t quotedquery;
+  while (phere != pend) {
+    if (!first)
+      if ((phere +1) == pend) quotedquery += " and ";
+      else quotedquery += ", ";
+	
+    quotedquery += "\"" + *phere + "\"";
+    first = false;
+    phere ++;
+  }
+  if (args.getintarg("s")) quotedquery += "_textstemon_";
+  disp.setmacro ("quotedquery", "query", quotedquery);
+}
+
+// sets the selection box macros _hselection_, _jselection_, and _nselection_.
+void queryaction::set_option_macro (const text_t &macroname, text_t current_value,
+				    const FilterOption_t &option, displayclass &disp) {
+  
+  if (option.validValues.empty()) return;
+  else if (option.validValues.size() == 1) {
+    disp.setmacro (macroname + "selection", "Global", "_" + option.defaultValue + "_");
+    return;
+  } 
+  if (option.validValues.size() < 2) return;
+  
+  text_t macrovalue = "<select name=\"" + macroname + "\">\n";
+  
+  if (current_value.empty()) current_value = option.defaultValue;
+  
+  text_tarray::const_iterator thisvalue = option.validValues.begin();
+  text_tarray::const_iterator endvalue = option.validValues.end();
+
+  while (thisvalue != endvalue) {
+    macrovalue += "<option value=\"" + *thisvalue + "\"";
+    if (*thisvalue == current_value)
+      macrovalue += " selected";
+    macrovalue += ">_" + *thisvalue + "_\n";
+    thisvalue ++;
+  }
+  macrovalue += "</select>\n";
+  disp.setmacro (macroname + "selection", "Global", macrovalue);
+}
+
+void queryaction::define_external_macros (displayclass &disp, cgiargsclass &args, 
+					  recptprotolistclass *protos, ostream &logout) {
+
+  // define_external_macros sets the following macros:
+
+  // some or all of these may not be required to be set
+  // _hselection_, _h2selection_  the selection box for the main part of the index
+  // _jselection_, _j2selection_  the selection box for the subcollection part of the index
+  // _nselection_, _n2selection_  the selection box for the language part of the index
+  // _cq2selection                the selection box for combining two queries
+  
+
+  // can't do anything if collectproto is null (i.e. no collection was specified)
+  recptproto *collectproto = protos->getrecptproto (args["c"], logout);
+  if (collectproto == NULL) return;
+
+  comerror_t err;
+  InfoFilterOptionsResponse_t response;
+  InfoFilterOptionsRequest_t request;
+  request.filterName = "QueryFilter";
+  
+  collectproto->get_filteroptions (args["c"], request, response, err, logout);
+  if (err == noError) {
+    
+    FilterOption_tmap::const_iterator it;
+    FilterOption_tmap::const_iterator end = response.filterOptions.end();
+    
+    // _hselection_ and _h2selection_ (Index)
+    it = response.filterOptions.find ("Index");
+    if (it != end) set_option_macro ("h", args["h"], (*it).second, disp);
+    if (it != end) set_option_macro ("h2", args["h2"], (*it).second, disp);
+    
+    // _jselection_ and _j2selection_ (Subcollection)
+    it = response.filterOptions.find ("Subcollection");
+    if (it != end) set_option_macro ("j", args["j"], (*it).second, disp);
+    if (it != end) set_option_macro ("j2", args["j2"], (*it).second, disp);
+    
+    // _nselection_ and _n2selection_ (Language)
+    it = response.filterOptions.find ("Language");
+    if (it != end) set_option_macro ("n", args["n"], (*it).second, disp);
+    if (it != end) set_option_macro ("n2", args["n2"], (*it).second, disp);
+
+    // _cq2selection_ (CombineQuery)
+    it = response.filterOptions.find ("CombineQuery");
+    if (it != end) set_option_macro ("cq2", args["cq2"], (*it).second, disp);
+
+    // _gselection_ (Level) // for mgpp collections
+    it = response.filterOptions.find("Level");
+    if (it!=end) set_option_macro("g", args["g"], (*it).second, disp);
+
+    // define_history_macros(disp, args, protos, logout);
+  }
+} // define external macros
+
+void queryaction::define_history_macros (displayclass &disp, cgiargsclass &args, 
+					 recptprotolistclass *protos, ostream &logout) {
+
+  // defines the following macros
+
+  // _searchhistorylist_
+
+  text_t historylist;
+  int arghd = args.getintarg("hd");
+  if (arghd != 1) {
+    historylist="";
+  }
+  else {
+    historylist = "<!-- Search History List -->\n";
+   
+    text_t userid = args["z"];
+    text_tarray entries;
+    if (get_history_info (userid, entries, gsdlhome, logout)) {
+      int count = 1;
+      text_tarray::iterator here = entries.begin();
+      text_tarray::iterator end = entries.end();
+      int size=(int)entries.size();
+      if (args["hcl"]==1&&size>5) { // compress the list 
+	here = end-5;
+	count=size-4;
+      }
+      historylist += "<table align=center width=500 border=0>\n";
+      historylist += "<tr><td width=300 align=center>";
+      historylist += "<a href=\"_httpclearhistory_\">_textclearhistory_</a></td>\n";
+
+      if (size>5&&args["hcl"]==1) { //compress the list, show the expand button
+       
+      historylist += "<td><a href=\"_gwcgi_?e=_compressedoptions_&a=q&hcl=0\">_textexpand_</a></td>\n";
+      }
+      else if (size >5 && args["hcl"]==0) { // expand the list, show contract button
+	historylist += "<td><a href=\"_gwcgi_?e=_compressedoptions_&a=q&hcl=1\">_textcontract_</a></td>\n";
+      }
+      historylist += "</table>\n";
+      historylist += "<table align=center width=500 border=1>\n<tr><th colspan=4 align=center>";
+      historylist += "_textsearchhistory_</th></tr>\n";
+      historylist += "<tr><th width=40>#</th>\n<th width=340>_textquery_</th>\n";
+      historylist += "<th width=60>_textresults_</th><th width=60>_textview_</th></tr>\n";
+
+      while (here !=end ) {
+	text_t c;
+	text_t query;
+	text_t numdocs;
+	text_t cgiargs;
+	text_t  userinfo;
+	split_saved_query(*here,c, numdocs, cgiargs);
+	parse_saved_args(cgiargs, "q", query); // get query string out
+	decode_cgi_arg(query); // un cgisafe it
+	
+	format_user_info(cgiargs, userinfo, protos, logout);
+	
+	historylist += "<tr> <td width=40 align=center>"+c+"</td>\n";
+	historylist += "<td width=340 align=left>"+query+"</td><td width=60 align=center>"+numdocs+"</td>\n";
+	historylist += "<td width=60 align=center><a href=\"_gwcgi_?e=_compressedoptions_&";
+	historylist += *here+"\"><img name=\"display\" src=\"_httpicondisplay_\" width=_widthdisplay_ ";
+	historylist += "height=_heightdisplay_ border=\"0\" alt=\"" + userinfo +"\"></a></td></tr>\n";
+	here++;
+	count++;
+      }
+      historylist+="</table>\n\n";
+     
+    } // if
+    else {
+      historylist += "_textnohistory_";
+    }
+    historylist += "<p><! ---- end of history list ----->\n";
+  } // else display list
+  disp.setmacro("searchhistorylist", "query", historylist);
+  
+} // define history macros
+
+void queryaction::output_ccp (cgiargsclass &args, recptprotolistclass *protos,
+			      displayclass &disp, outconvertclass &outconvert,
+			      ostream &textout, ostream &logout) {
+
+  ColInfoResponse_t *cinfo = NULL;
+  comerror_t err;
+  InfoFilterOptionsResponse_t fresponse;
+  InfoFilterOptionsRequest_t frequest;
+  frequest.filterName = "QueryFilter";
+
+  text_t &index = args["h"];
+  text_t &subcollection = args["j"];
+  text_t &language = args["n"];
+
+  text_tset collections;
+  text_t arg_cc = args["cc"];
+  decode_cgi_arg (arg_cc);
+  splitchar (arg_cc.begin(), arg_cc.end(), ',', collections);
+
+  textout << outconvert << disp << "_query:header_\n"
+	  << "<center>_navigationbar_</center><br>\n"
+	  << "<form name=QueryForm method=get action=\"_gwcgi_\">\n"
+	  << "<input type=hidden name=a value=\"q\">\n"
+	  << "<input type=hidden name=e value=\"_compressedoptions_\">\n"
+	  << "<input type=hidden name=ccp value=\"1\">\n"
+	  << "<center><table width=_pagewidth_><tr valign=top>\n"
+	  << "<td>Select collections to search for \"" << args["q"] 
+	  << "\" <i>(index=" << index << " subcollection=" << subcollection
+	  << " language=" << language << ")</i></td>\n"
+	  << "<td><input type=\"submit\" value=\"_query:textbeginsearch_\"></td>\n"
+	  << "</tr></table></center>\n"
+	  << "<center><table width=_pagewidth_>\n"
+	  << "<tr><td>\n";
+  
+  recptprotolistclass::iterator rprotolist_here = protos->begin();
+  recptprotolistclass::iterator rprotolist_end = protos->end();
+  while (rprotolist_here != rprotolist_end) {
+    if ((*rprotolist_here).p != NULL) {
+      
+      text_tarray collist;
+      (*rprotolist_here).p->get_collection_list (collist, err, logout);
+      if (err == noError) {
+	text_tarray::iterator collist_here = collist.begin();
+	text_tarray::iterator collist_end = collist.end();
+	while (collist_here != collist_end) {
+	  
+	  cinfo = recpt->get_collectinfo_ptr ((*rprotolist_here).p, *collist_here, logout);
+	  //	  if (err == noError && cinfo.isPublic && (cinfo.buildDate > 0)) {
+	  if (cinfo != NULL && (cinfo->buildDate > 0)) {
+	    
+	    (*rprotolist_here).p->get_filteroptions (*collist_here, frequest, fresponse, err, logout);
+	    if (err == noError) {
+	      
+	      FilterOption_tmap::const_iterator it;
+	      FilterOption_tmap::const_iterator end = fresponse.filterOptions.end();
+	      if (!index.empty()) {
+		it = fresponse.filterOptions.find ("Index");
+		if (it == end) {collist_here ++; continue;}
+		text_tarray::const_iterator there = (*it).second.validValues.begin();
+		text_tarray::const_iterator tend = (*it).second.validValues.end();
+		while (there != tend) {
+		  if (*there == index) break;
+		  there ++;
+		}
+		if (there == tend) {collist_here++; continue;}
+	      }
+	      if (!subcollection.empty()) {
+		it = fresponse.filterOptions.find ("Subcollection");
+		if (it == end) {collist_here++; continue;}
+		text_tarray::const_iterator there = (*it).second.validValues.begin();
+		text_tarray::const_iterator tend = (*it).second.validValues.end();
+		while (there != tend) {
+		  if (*there == subcollection) break;
+		  there ++;
+		}
+		if (there == tend) {collist_here++; continue;}
+	      }
+	      if (!language.empty()) {
+		it = fresponse.filterOptions.find ("Language");
+		if (it == end) {collist_here++; continue;}
+		text_tarray::const_iterator there = (*it).second.validValues.begin();
+		text_tarray::const_iterator tend = (*it).second.validValues.end();
+		while (there != tend) {
+		  if (*there == language) break;
+		  there ++;
+		}
+		if (there == tend) {collist_here++; continue;}
+	      }
+	    
+	      // we've got a matching collection
+	      textout << "<input type=checkbox";
+
+	      text_tset::const_iterator t = collections.find (*collist_here);
+	      if (t != collections.end()) textout << " checked";
+
+	      textout << outconvert 
+		      << " name=cc value=\"" << *collist_here << "\">";
+	      
+	      if (!cinfo->collectionmeta["collectionname"].empty())
+		textout << outconvert << disp << cinfo->collectionmeta["collectionname"];
+	      else 
+		textout << outconvert << *collist_here;
+	      
+	      textout << "<br>\n";
+	      
+	    }
+	  }
+	  collist_here ++;
+	}
+      }
+    }
+    rprotolist_here ++;
+  }
+  textout << outconvert << disp 
+	  << "</td></tr></table></center>\n"
+	  << "</form>\n"
+	  << "_query:footer_\n";
+  
+}
+
+bool queryaction::do_action (cgiargsclass &args, recptprotolistclass *protos, 
+			     browsermapclass *browsers, displayclass &disp, 
+			     outconvertclass &outconvert, ostream &textout, 
+			     ostream &logout) {
+  
+  if (recpt == NULL) {
+    logout << "ERROR (queryaction::do_action): This action does not contain information\n"
+	   << "      about any receptionists. The method set_receptionist was probably\n"
+	   << "      not called from the module which instantiated this action.\n";
+    return true;
+  }
+
+
+  if (args["ccs"] == "1") {
+    if (!args["cc"].empty()) {
+      // query the selected collections
+      text_t::const_iterator b = args["cc"].begin();
+      text_t::const_iterator e = args["cc"].end();
+      if (findchar (b, e, ',') != e) {
+	if (!search_multiple_collections (args, protos, browsers, disp, outconvert,
+					  textout, logout)) return false;
+	return true;
+      } else {
+	if (!search_single_collection (args, args["cc"], protos, browsers, disp, 
+				       outconvert, textout, logout)) return false;
+  	return true;
+      }
+    }
+  }
+
+  // simply query the current collection
+  if (!search_single_collection (args, args["c"], protos, browsers, disp, 
+				 outconvert, textout, logout)) return false;
+  return true;
+}
+
+bool queryaction::search_multiple_collections (cgiargsclass &args, recptprotolistclass *protos,
+					       browsermapclass *browsers, displayclass &disp,
+					       outconvertclass &outconvert, ostream &textout,
+					       ostream &logout) {
+
+  text_tarray collections;
+  
+  text_t arg_cc = args["cc"];
+  decode_cgi_arg (arg_cc);
+  splitchar (arg_cc.begin(), arg_cc.end(), ',', collections);
+
+  if (collections.empty()) {
+    logout << "queryaction::search_multiple_collections: No collections "
+	   << "set for doing multiple query - will search current collection\n";
+    textout << outconvert << disp << "_query:textwarningnocollections_\n";
+    return search_single_collection (args, args["c"], protos, browsers, disp, 
+				     outconvert, textout, logout);
+  }
+
+  // queryaction uses "VList" browser to display results,
+  // a queries clasification is "Search"
+  text_t browsertype = "VList";
+  text_t classification = "Search";
+
+  QueryResult_tset results;
+  map<text_t, colinfo_t, lttext_t> colinfomap;
+
+  ColInfoResponse_t *cinfo = NULL;
+  comerror_t err;
+  FilterRequest_t request;
+  FilterResponse_t response;
+  request.filterResultOptions = FROID | FRmetadata | FRtermFreq | FRranking;
+  text_t formattedstring = args["q"];
+  text_t freqmsg = "_textfreqmsg1_";
+  int numdocs = 0;
+  isapprox isApprox = Exact;
+
+  format_querystring (formattedstring, args.getintarg("b"));
+  set_queryfilter_options (request, formattedstring, args);
+
+  // need to retrieve maxdocs matches for each collection
+  // (will eventually want to tidy this up, do so caching etc.)
+  OptionValue_t option;
+  option.name = "StartResults";
+  option.value = "1";
+  request.filterOptions.push_back (option);
+  
+  option.name = "EndResults";
+  option.value = args["m"];
+  request.filterOptions.push_back (option);
+
+  text_tarray::iterator col_here = collections.begin();
+  text_tarray::iterator col_end = collections.end();
+
+  map<text_t, int, lttext_t> termfreqs;
+  while (col_here != col_end) {
+
+    request.fields.erase (request.fields.begin(), request.fields.end());
+    request.getParents = false;
+
+    recptproto *collectproto = protos->getrecptproto (*col_here, logout);
+    if (collectproto == NULL) {
+      logout << outconvert << "queryaction::search_multiple_collections: " << *col_here 
+	     << " collection has a NULL collectproto, ignoring\n";
+      col_here ++;
+      continue;
+    }
+    cinfo = recpt->get_collectinfo_ptr (collectproto, *col_here, logout);
+    if (cinfo == NULL) {
+      logout << "ERROR (query_action::search_multiple_collections): get_collectinfo_ptr returned NULL\n";
+      col_here ++;
+      continue;
+    }
+    
+    browserclass *bptr = browsers->getbrowser (browsertype);
+
+    // get the formatstring if there is one 
+    text_t formatstring;
+    if (!get_formatstring (classification, browsertype, 
+			   cinfo->format, formatstring))
+      formatstring = bptr->get_default_formatstring();
+
+    bptr->load_metadata_defaults (request.fields);
+
+    format_t *formatlistptr = new format_t();
+    parse_formatstring (formatstring, formatlistptr, request.fields, request.getParents);
+
+    colinfo_t thiscolinfo;
+    thiscolinfo.formatlistptr = formatlistptr;
+    thiscolinfo.browserptr = bptr;
+    colinfomap[*col_here] = thiscolinfo;
+    
+    // do the query
+    collectproto->filter (*col_here, request, response, err, logout);
+    if (err != noError) {
+      outconvertclass text_t2ascii;
+      logout << text_t2ascii
+	     << "queryaction::search_multiple_collections: call to QueryFilter failed "
+	     << "for " << *col_here << " collection (" << get_comerror_string (err) << ")\n";
+      return false;
+    }
+
+    if (isApprox == Exact)
+      isApprox = response.isApprox;
+    else if (isApprox == MoreThan)
+      if (response.isApprox == Approximate)
+	isApprox = response.isApprox;
+
+    TermInfo_tarray::const_iterator this_term = response.termInfo.begin();
+    TermInfo_tarray::const_iterator end_term = response.termInfo.end();
+    while (this_term != end_term) {
+      termfreqs[(*this_term).term] += (*this_term).freq;
+      if ((col_here+1) == col_end) {
+	freqmsg += (*this_term).term + ": " + termfreqs[(*this_term).term];
+	if ((this_term+1) != end_term) freqmsg += ", ";
+      }
+      this_term ++;
+    }
+    
+    if (response.numDocs > 0) {
+      numdocs += response.numDocs;
+
+      QueryResult_t thisresult;
+      thisresult.collection = *col_here;
+      ResultDocInfo_tarray::iterator doc_here = response.docInfo.begin();
+      ResultDocInfo_tarray::iterator doc_end = response.docInfo.end();
+      while (doc_here != doc_end) {
+	thisresult.doc = *doc_here;
+	results.insert (thisresult);
+	doc_here ++;
+      }
+    }
+    col_here ++;
+  }
+
+  disp.setmacro ("freqmsg", "query", freqmsg);
+
+  text_t resline;
+  if (num_phrases > 0) isApprox = Exact;
+  if (isApprox == Approximate) resline = "_textapprox_";
+  else if (isApprox == MoreThan) resline = "_textmorethan_";
+  
+  if (numdocs == 0) resline = "_textnodocs_";
+  else if (numdocs == 1) resline += "_text1doc_";
+  else resline += text_t(numdocs) + " _textlotsdocs_";
+  disp.setmacro("resultline", "query", resline);
+
+  QueryResult_tset::iterator res_here = results.begin();
+  QueryResult_tset::iterator res_end = results.end();
+  text_tset metadata; // empty !!
+  bool getParents = false; // don't care !!
+  recptproto *collectproto = NULL;
+  bool use_table;
+  ResultDocInfo_t thisdoc;
+  format_t *formatlistptr = NULL;
+  browserclass *browserptr = NULL;
+
+  int maxdocs = args.getintarg("m");
+  int firstdoc = args.getintarg("r");
+  int hitsperpage = args.getintarg("o");
+  if (numdocs > maxdocs) numdocs = maxdocs;
+  if (hitsperpage == -1) hitsperpage = numdocs;
+
+  // set up _thisfirst_ and _thislast_ macros
+  disp.setmacro ("thisfirst", "query", firstdoc);
+  int thislast = firstdoc + (hitsperpage - 1);
+  if (thislast > numdocs) thislast = numdocs;
+  disp.setmacro ("thislast", "query", thislast);
+
+  // set up _prevfirst_ and _prevlast_ macros
+  if (firstdoc > 1) {
+    disp.setmacro ("prevlast", "query", firstdoc - 1);
+    int prevfirst = firstdoc - hitsperpage;
+    if (prevfirst < 1) prevfirst = 1;
+    disp.setmacro ("prevfirst", "query", prevfirst);
+  }
+
+  // set up _nextfirst_ and _nextlast_ macros
+  if (thislast < numdocs) {
+    disp.setmacro ("nextfirst", "query", thislast + 1);
+    int nextlast = thislast + hitsperpage;
+    if (nextlast > numdocs) nextlast = numdocs;
+    disp.setmacro ("nextlast", "query", nextlast);
+  }
+
+  textout << outconvert << disp << "_query:header_\n"
+	  << "_query:content_";
+
+  int count = 1;
+
+  // output results
+  while (res_here != res_end) {
+    if (count < firstdoc) {count ++; res_here ++; continue;}
+    if (count > thislast) break;
+    formatlistptr = colinfomap[(*res_here).collection].formatlistptr;
+    browserptr = colinfomap[(*res_here).collection].browserptr;
+    thisdoc = (*res_here).doc;
+    use_table = is_table_content (formatlistptr);
+    browserptr->output_section_group (thisdoc, args, (*res_here).collection, 0, 
+    				      formatlistptr, use_table, metadata, getParents, 
+    				      collectproto, disp, outconvert, textout, logout);
+    //    textout << outconvert << "(ranking: " << (*res_here).doc.ranking << ")\n";
+    res_here ++;
+    count ++;
+  }
+
+  textout << outconvert << disp << "_query:footer_";
+  
+  // clean up the format_t pointers
+  map<text_t, colinfo_t, lttext_t>::iterator here =  colinfomap.begin();
+  map<text_t, colinfo_t, lttext_t>::iterator end =  colinfomap.end();
+  while (here != end) {
+    delete ((*here).second.formatlistptr);
+    here ++;
+  }
+  return true;
+}
+
+bool queryaction::search_single_collection (cgiargsclass &args, const text_t &collection,
+					    recptprotolistclass *protos, browsermapclass *browsers, 
+					    displayclass &disp, outconvertclass &outconvert, 
+					    ostream &textout, ostream &logout) {
+
+  recptproto *collectproto = protos->getrecptproto (collection, logout);
+  if (collectproto == NULL) {
+    logout << outconvert << "queryaction::search_single_collection: " << collection
+	   << " collection has a NULL collectproto\n";
+    return false;
+  }
+
+  // queryaction uses "VList" browser to display results,
+  // a queries clasification is "Search"
+  text_t browsertype = "VList";
+  text_t classification = "Search";
+
+  comerror_t err;
+  ColInfoResponse_t *cinfo = recpt->get_collectinfo_ptr (collectproto, collection, logout);
+
+  if (cinfo == NULL) {
+    logout << "ERROR (query_action::search_single_collection): get_collectinfo_ptr returned NULL\n";
+    return false;
+  }
+    
+  browserclass *bptr = browsers->getbrowser (browsertype);
+
+  // get the formatstring if there is one 
+  text_t formatstring;
+  if (!get_formatstring (classification, browsertype, 
+			 cinfo->format, formatstring))
+    formatstring = bptr->get_default_formatstring();
+
+  FilterRequest_t request;
+  FilterResponse_t response;
+  bptr->set_filter_options (request, args);
+  bptr->load_metadata_defaults (request.fields);
+
+  format_t *formatlistptr = new format_t();
+  parse_formatstring (formatstring, formatlistptr, request.fields, request.getParents);
+    
+  // do the query
+  request.filterResultOptions = FROID | FRmetadata | FRtermFreq;
+  text_t formattedstring = args["q"];
+  if (!combine_query (args["z"], formattedstring, gsdlhome)) {
+    args["q"]=formattedstring; 
+  }
+  format_querystring (formattedstring, args.getintarg("b"));
+  set_queryfilter_options (request, formattedstring, args);
+  collectproto->filter (collection, request, response, err, logout);
+  if (err != noError) {
+    outconvertclass text_t2ascii;
+    logout << text_t2ascii
+	   << "queryaction::search_single_collections: call to QueryFilter failed "
+	   << "for " << collection << " collection (" << get_comerror_string (err) << ")\n";
+    return false;
+  }
+
+  
+  define_query_macros (args, disp, response);
+
+  // save the query if appropriate
+  if (!save_search_history(args, response))
+    logout << "save failed";
+
+  define_history_macros (disp, args, protos, logout);
+
+  textout << outconvert << disp << "_query:header_\n"
+	  << "_query:content_";
+
+  // output the results
+  bool use_table = is_table_content (formatlistptr);
+  bptr->output_section_group (response, args, collection, 0, formatlistptr, 
+			      use_table, request.fields, request.getParents, 
+			      collectproto, disp, outconvert, textout, logout);
+  
+
+  textout << outconvert << disp << "_query:footer_";
+  
+  delete (formatlistptr);
+  
+  return true;
+}
+  
+// define_query_macros sets the macros that couldn't be set until the
+// query had been done. Those macros are _freqmsg_, _quotedquery_,
+// _resultline_, _nextfirst_, _nextlast_, _prevfirst_, _prevlast_,
+// _thisfirst_, and _thislast_
+void queryaction::define_query_macros (cgiargsclass &args, displayclass &disp, 
+				       const FilterResponse_t &response) { 
+  // set up _freqmsg_ and _quotedquery_ macros
+  text_t freqmsg = "_textfreqmsg1_";
+  TermInfo_tarray::const_iterator this_term = response.termInfo.begin();
+  TermInfo_tarray::const_iterator end_term = response.termInfo.end();
+  while (this_term != end_term) {
+    freqmsg += (*this_term).term + ": " + (*this_term).freq;
+    if ((this_term + 1) != end_term)
+      freqmsg += ", ";
+    this_term ++;
+  }
+  disp.setmacro ("freqmsg", "query", freqmsg);
+
+
+  // set up _resultline_ macro
+  text_t resline;
+  int maxdocs = args.getintarg("m");
+  int numdocs = response.numDocs;
+  if (maxdocs == -1) maxdocs = response.numDocs;
+  isapprox isApprox = response.isApprox;
+
+  // if there were phrases (post-processing) we're not going to include 
+  // those documents that didn't match 
+  if (num_phrases > 0) isApprox = Exact;
+
+  if (isApprox == Approximate) resline = "_textapprox_";
+  else if (isApprox == MoreThan) resline = "_textmorethan_";
+  
+  if (numdocs == 0) resline = "_textnodocs_";
+  else if (numdocs == 1) resline += "_text1doc_";
+  else resline += text_t(numdocs) + " _textlotsdocs_";
+  
+  disp.setmacro("resultline", "query", resline);
+
+  int firstdoc = args.getintarg("r");
+  int hitsperpage = args.getintarg("o");
+  if (hitsperpage == -1) hitsperpage = numdocs;
+
+  // set up _thisfirst_ and _thislast_ macros
+  disp.setmacro ("thisfirst", "query", firstdoc);
+  int thislast = firstdoc + (hitsperpage - 1);
+  if (thislast > numdocs) thislast = numdocs;
+  disp.setmacro ("thislast", "query", thislast);
+
+  // set up _prevfirst_ and _prevlast_ macros
+  if (firstdoc > 1) {
+    disp.setmacro ("prevlast", "query", firstdoc - 1);
+    int prevfirst = firstdoc - hitsperpage;
+    if (prevfirst < 1) prevfirst = 1;
+    disp.setmacro ("prevfirst", "query", prevfirst);
+  }
+
+  // set up _nextfirst_ and _nextlast_ macros
+  if (thislast < numdocs) {
+    disp.setmacro ("nextfirst", "query", thislast + 1);
+    int nextlast = thislast + hitsperpage;
+    if (nextlast > numdocs) nextlast = numdocs;
+    disp.setmacro ("nextlast", "query", nextlast);
+  }
+}
+
+bool queryaction::save_search_history (cgiargsclass &args, const FilterResponse_t &response) 
+{
+
+  if (args["q"]=="") return true; // null query, dont save
+  if (args["hs"]=="0") return true; // only save when submit query
+
+  // get userid
+  text_t userid = args["z"];
+
+  // the number of docs goes on the front of the query string
+  int numdocs= response.numDocs;
+  text_t query = text_t(numdocs);
+  if (response.isApprox==MoreThan) { // there were more docs found
+    query.push_back('+');
+  }
+  query += "a=q";
+  query += "&c="+args["c"];
+  query += "&h="+args["h"];
+  query += "&t="+args["t"];
+  query += "&b="+args["b"];
+  query += "&j="+args["j"];
+  query += "&n="+args["n"];
+  query += "&s="+args["s"];
+  query += "&k="+args["k"];
+   
+  text_t qstring = args["q"];
+  text_t formattedquery =cgi_safe(qstring);
+  query += "&q="+formattedquery;
+
+  if (set_history_info(userid, query, gsdlhome)) return true;
+  else return false;
+
+
+}
Index: /main/tags/2.25/gsdl/src/recpt/queryaction.h
===================================================================
--- /main/tags/2.25/gsdl/src/recpt/queryaction.h	(revision 21064)
+++ /main/tags/2.25/gsdl/src/recpt/queryaction.h	(revision 21064)
@@ -0,0 +1,128 @@
+/**********************************************************************
+ *
+ * queryaction.h -- 
+ * Copyright (C) 1999  The New Zealand Digital Library Project
+ *
+ * A component of the Greenstone digital library software
+ * from the New Zealand Digital Library Project at the
+ * University of Waikato, New Zealand.
+ *
+ * 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.
+ *
+ *********************************************************************/
+
+
+#ifndef QUERYACTION_H
+#define QUERYACTION_H
+
+#include "gsdlconf.h"
+#include "action.h"
+#include "receptionist.h"
+
+struct colinfo_t {
+  void clear();
+  colinfo_t () {clear();}
+
+  format_t *formatlistptr;
+  browserclass *browserptr;
+};
+
+struct QueryResult_t {
+  void clear ();
+  QueryResult_t () {clear();}
+
+  ResultDocInfo_t doc;
+  text_t collection;
+};
+
+struct gteqQueryResult_t 
+{
+  bool operator()(const QueryResult_t &t1, const QueryResult_t &t2) const
+  { return t1.doc.ranking >= t2.doc.ranking; }
+};
+
+typedef set<QueryResult_t, gteqQueryResult_t> QueryResult_tset;
+
+
+class queryaction : public action {
+
+protected:
+
+  receptionist *recpt;
+
+  text_t formatstring;
+  int num_phrases;
+
+  virtual void define_query_macros (cgiargsclass &args, displayclass &disp, 
+			    const FilterResponse_t &response); 
+
+  void define_history_macros (displayclass &disp, cgiargsclass &args, 
+			       recptprotolistclass *protos, ostream &logout);
+
+  virtual void set_option_macro (const text_t &macroname, text_t current_value,
+			 const FilterOption_t &option, displayclass &disp);
+
+  void output_ccp (cgiargsclass &args, recptprotolistclass *protos,
+		   displayclass &disp, outconvertclass &outconvert,
+		   ostream &textout, ostream &logout);
+  
+
+
+  bool search_multiple_collections (cgiargsclass &args, recptprotolistclass *protos,
+				    browsermapclass *browsers, displayclass &disp,
+				    outconvertclass &outconvert, ostream &textout,
+				    ostream &logout);
+
+
+  bool search_single_collection (cgiargsclass &args, const text_t &collection,
+				 recptprotolistclass *protos, browsermapclass *browsers, 
+				 displayclass &disp, outconvertclass &outconvert, 
+				 ostream &textout, ostream &logout);
+
+
+  bool save_search_history(cgiargsclass &args, const FilterResponse_t &response); 
+  bool delete_search_history(cgiargsclass &args);
+
+public:
+  queryaction ();
+  virtual ~queryaction () {}
+
+  void set_receptionist (receptionist *therecpt) {recpt=therecpt;}
+  
+  void configure (const text_t &key, const text_tarray &cfgline);
+  bool init (ostream &logout);
+  
+  virtual text_t get_action_name () {return "q";}
+  
+  virtual bool check_cgiargs (cgiargsinfoclass &argsinfo, cgiargsclass &args, 
+		      ostream &logout);
+
+  void get_cgihead_info (cgiargsclass &args, recptprotolistclass *protos,
+			 response_t &response, text_t &response_data, 
+			 ostream &logout);
+  
+  virtual void define_internal_macros (displayclass &disp, cgiargsclass &args, 
+			       recptprotolistclass *protos, ostream &logout);
+
+  virtual void define_external_macros (displayclass &disp, cgiargsclass &args, 
+			       recptprotolistclass *protos, ostream &logout);
+  
+  virtual bool do_action (cgiargsclass &args, recptprotolistclass *protos, 
+		  browsermapclass *browsers, displayclass &disp, 
+		  outconvertclass &outconvert, ostream &textout, 
+		  ostream &logout);
+};
+
+#endif
Index: /main/tags/2.25/gsdl/src/recpt/querytools.cpp
===================================================================
--- /main/tags/2.25/gsdl/src/recpt/querytools.cpp	(revision 21064)
+++ /main/tags/2.25/gsdl/src/recpt/querytools.cpp	(revision 21064)
@@ -0,0 +1,213 @@
+/**********************************************************************
+ *
+ * querytools.cpp -- 
+ * Copyright (C) 1999  The New Zealand Digital Library Project
+ *
+ * A component of the Greenstone digital library software
+ * from the New Zealand Digital Library Project at the
+ * University of Waikato, New Zealand.
+ *
+ * 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.
+ *
+ *********************************************************************/
+
+#include "querytools.h"
+
+
+// request.filterResultOptions and request.fields (if required) should
+// be set from the calling code
+void set_queryfilter_options (FilterRequest_t &request, const text_t &querystring,
+			      cgiargsclass &args) {
+
+  request.filterName = "QueryFilter";
+
+  OptionValue_t option;
+
+  option.name = "Term";
+  option.value = querystring;
+  request.filterOptions.push_back (option);
+
+  option.name = "QueryType";
+  option.value = (args.getintarg("t")) ? "ranked" : "boolean";
+  request.filterOptions.push_back (option);
+
+  option.name = "Casefold";
+  option.value = (args.getintarg("k")) ? "true" : "false";
+  request.filterOptions.push_back (option);
+
+  option.name = "Stem";
+  option.value = (args.getintarg("s")) ? "true" : "false";
+  request.filterOptions.push_back (option);
+
+  if (!args["h"].empty()) {
+    option.name = "Index";
+    option.value = args["h"];
+    request.filterOptions.push_back (option);
+  }
+
+  if (!args["j"].empty()) {
+    option.name = "Subcollection";
+    option.value = args["j"];
+    request.filterOptions.push_back (option);
+  }
+
+  if (!args["n"].empty()) {
+    option.name = "Language";
+    option.value = args["n"];
+    request.filterOptions.push_back (option);
+  }
+  
+  if (!args["g"].empty()) { // granularity for mgpp
+    option.name = "Level";
+    option.value = args["g"];
+    request.filterOptions.push_back (option);
+  }
+
+  set_more_queryfilter_options (request, args);
+}
+
+void set_queryfilter_options (FilterRequest_t &request, const text_t &querystring1,
+			      const text_t &querystring2, cgiargsclass &args) {
+
+  set_queryfilter_options (request, querystring1, args);
+
+  // fill in the second query if needed
+  if (!args["cq2"].empty()) {
+    OptionValue_t option;
+
+    option.name = "CombineQuery";
+    option.value = args["cq2"];
+    request.filterOptions.push_back (option);
+    
+    option.name = "Term";
+    option.value = querystring2;
+    request.filterOptions.push_back (option);
+    
+    option.name = "QueryType";
+    option.value = (args.getintarg("t")) ? "ranked" : "boolean";
+    request.filterOptions.push_back (option);
+
+    option.name = "Casefold";
+    option.value = (args.getintarg("k")) ? "true" : "false";
+    request.filterOptions.push_back (option);
+
+    option.name = "Stem";
+    option.value = (args.getintarg("s")) ? "true" : "false";
+    request.filterOptions.push_back (option);
+
+    if (!args["h2"].empty()) {
+      option.name = "Index";
+      option.value = args["h2"];
+      request.filterOptions.push_back (option);
+    }
+
+    if (!args["j2"].empty()) {
+      option.name = "Subcollection";
+      option.value = args["j2"];
+      request.filterOptions.push_back (option);
+    }
+
+    if (!args["n2"].empty()) {
+      option.name = "Language";
+      option.value = args["n2"];
+      request.filterOptions.push_back (option);
+    }
+  }
+  set_more_queryfilter_options (request, args);
+}
+
+void set_more_queryfilter_options (FilterRequest_t &request, cgiargsclass &args) {
+
+  OptionValue_t option;
+  int arg_m = args.getintarg("m");
+  
+  option.name = "Maxdocs";
+  option.value = arg_m;
+  request.filterOptions.push_back (option);
+
+  //  option.name = "StartResults";
+  //  option.value = args["r"];
+  //  request.filterOptions.push_back (option);
+
+  //  option.name = "EndResults";
+  //  int endresults = args.getintarg("o") + (args.getintarg("r") - 1);
+  //  if ((endresults > arg_m) && (arg_m != -1)) endresults = arg_m;
+  //  option.value = endresults;
+  //  request.filterOptions.push_back (option);
+}
+
+void format_querystring (text_t &querystring, int querymode) {
+  text_t formattedstring;
+
+  text_t::const_iterator here = querystring.begin();
+  text_t::const_iterator end = querystring.end();
+
+  // space is used to insert spaces between Chinese
+  // characters. No space is needed before the first
+  // Chinese character.
+  bool space = false;
+
+  // want to remove ()|!& from querystring so boolean queries are just
+  // "all the words" queries (unless querymode is advanced)
+  while (here != end) {
+    if ((querymode == 0) && (*here == '(' || *here == ')' || *here == '|' ||
+			     *here == '!' || *here == '&')) {
+      formattedstring.push_back(' ');
+    } else {
+      if ((*here >= 0x4e00 && *here <= 0x9fa5) ||
+	  (*here >= 0xf900 && *here <= 0xfa2d)) {
+	// Chinese character
+	if (space) formattedstring.push_back (0x200b);
+	formattedstring.push_back (*here);
+	formattedstring.push_back (0x200b);
+	space = true;
+      } else {
+	// non-Chinese character
+	formattedstring.push_back (*here);
+	space = false;
+      }
+    }
+    here ++;
+  }
+  querystring = formattedstring;
+}
+
+void get_phrases (const text_t &querystring, text_tarray &phrases) {
+
+  phrases.erase (phrases.begin(), phrases.end());
+  if (!querystring.empty()) {
+    
+    text_t::const_iterator end = querystring.end();
+    text_t::const_iterator here = findchar (querystring.begin(), end, '"');
+    if (here != end) {
+      text_t tmptext;
+      bool foundquote = false;
+      while (here != end) {
+	if (*here == '"') {
+	  if (foundquote) {
+	    if (!tmptext.empty()) {
+	      phrases.push_back(tmptext);
+	      tmptext.clear();
+	    }
+	    foundquote = false;
+	  } else foundquote = true;
+	} else {
+	  if (foundquote) tmptext.push_back (*here);
+	}
+	here ++;
+      }
+    }
+  }
+}
Index: /main/tags/2.25/gsdl/src/recpt/querytools.h
===================================================================
--- /main/tags/2.25/gsdl/src/recpt/querytools.h	(revision 21064)
+++ /main/tags/2.25/gsdl/src/recpt/querytools.h	(revision 21064)
@@ -0,0 +1,46 @@
+/**********************************************************************
+ *
+ * querytools.h -- 
+ * Copyright (C) 1999  The New Zealand Digital Library Project
+ *
+ * A component of the Greenstone digital library software
+ * from the New Zealand Digital Library Project at the
+ * University of Waikato, New Zealand.
+ *
+ * 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.
+ *
+ *********************************************************************/
+
+
+#ifndef QUERYTOOLS_H
+#define QUERYTOOLS_H
+
+#include "cgiargs.h"
+#include "recptproto.h"
+
+void set_queryfilter_options (FilterRequest_t &request, const text_t &querystring,
+			      cgiargsclass &args);
+
+void set_queryfilter_options (FilterRequest_t &request, const text_t &querystring1,
+			      const text_t &querystring2, cgiargsclass &args);
+
+// don't hastle the function name ... it's been a long day ;)
+void set_more_queryfilter_options (FilterRequest_t &request, cgiargsclass &args);
+
+void format_querystring (text_t &querystring, int querymode);
+
+void get_phrases (const text_t &querystring, text_tarray &phrases);
+
+#endif
Index: /main/tags/2.25/gsdl/src/recpt/receptionist.cpp
===================================================================
--- /main/tags/2.25/gsdl/src/recpt/receptionist.cpp	(revision 21064)
+++ /main/tags/2.25/gsdl/src/recpt/receptionist.cpp	(revision 21064)
@@ -0,0 +1,1176 @@
+/**********************************************************************
+ *
+ * receptionist.cpp -- a web interface for the gsdl
+ * Copyright (C) 1999  The New Zealand Digital Library Project
+ *
+ * A component of the Greenstone digital library software
+ * from the New Zealand Digital Library Project at the
+ * University of Waikato, New Zealand.
+ *
+ * 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.
+ *
+ *********************************************************************/
+
+#include "receptionist.h"
+#include "fileutil.h"
+#include "cgiutils.h"
+#include "htmlutils.h"
+#include "gsdltools.h"
+#include "OIDtools.h"
+#include <assert.h>
+#include <time.h>
+#include <stdio.h>
+#if defined (GSDL_USE_IOS_H)
+#include <fstream.h>
+#else 
+#include <fstream>
+#endif
+
+#if defined (__WIN32_)
+#include "wincgiutils.h"
+#endif
+
+void recptconf::clear () {
+  gsdlhome.clear();
+  gdbmhome.clear();
+  collectinfo.erase(collectinfo.begin(), collectinfo.end());
+  collection.clear();
+  collectdir.clear();
+  httpprefix.clear();
+  httpimg = "/images";
+  gwcgi.clear();
+  macrofiles.erase(macrofiles.begin(), macrofiles.end());
+  saveconf.clear();
+  usecookies = false;
+  logcgiargs = false;
+
+  // these default page parameters can always be overriden
+  // in the configuration file
+  pageparams.erase(pageparams.begin(), pageparams.end());
+  pageparams["c"] = ""; 
+  pageparams["l"] = "en"; 
+
+#ifdef MACROPRECEDENCE
+  macroprecedence = MACROPRECEDENCE;
+#else
+  macroprecedence.clear();
+#endif
+}
+
+void collectioninfo_t::clear () {
+  gsdl_gsdlhome.clear();
+  gsdl_gdbmhome.clear();
+
+  info_loaded = false;
+  info.clear();
+}
+
+receptionist::receptionist () {
+  // create a list of cgi arguments
+  // this must be done before the configuration
+
+  cgiarginfo ainfo;
+
+  ainfo.shortname = "e";
+  ainfo.longname = "compressed arguments";
+  ainfo.multiplechar = true;
+  ainfo.defaultstatus = cgiarginfo::good;
+  ainfo.argdefault = "";
+  ainfo.savedarginfo = cgiarginfo::mustnot;
+  argsinfo.addarginfo (NULL, ainfo);
+
+  ainfo.shortname = "a";
+  ainfo.longname = "action";
+  ainfo.multiplechar = true;
+  ainfo.defaultstatus = cgiarginfo::none;
+  ainfo.argdefault = "";
+  ainfo.savedarginfo = cgiarginfo::must;
+  argsinfo.addarginfo (NULL, ainfo);
+
+  // w=western
+  ainfo.shortname = "w";
+  ainfo.longname = "encoding";
+  ainfo.multiplechar = true;
+  ainfo.defaultstatus = cgiarginfo::weak;
+  ainfo.argdefault = "w";
+  ainfo.savedarginfo = cgiarginfo::must;
+  argsinfo.addarginfo (NULL, ainfo);
+  
+  ainfo.shortname = "nw";
+  ainfo.longname = "new encoding";
+  ainfo.multiplechar = true;
+  ainfo.defaultstatus = cgiarginfo::none;
+  ainfo.argdefault = "";
+  ainfo.savedarginfo = cgiarginfo::mustnot;
+  argsinfo.addarginfo (NULL, ainfo);
+  
+  ainfo.shortname = "c";
+  ainfo.longname = "collection";
+  ainfo.multiplechar = true;
+  ainfo.defaultstatus = cgiarginfo::none;
+  ainfo.argdefault = "";
+  ainfo.savedarginfo = cgiarginfo::must;
+  argsinfo.addarginfo (NULL, ainfo);
+  
+  // the interface language name should use the ISO 639
+  // standard
+  ainfo.shortname = "l";
+  ainfo.longname = "interface language";
+  ainfo.multiplechar = true;
+  ainfo.defaultstatus = cgiarginfo::weak;
+  ainfo.argdefault = "en";
+  ainfo.savedarginfo = cgiarginfo::must;
+  argsinfo.addarginfo (NULL, ainfo);
+
+  // the GSDL_UID (cookie)
+  ainfo.shortname = "z";
+  ainfo.longname = "gsdl uid";
+  ainfo.multiplechar = true;
+  ainfo.defaultstatus = cgiarginfo::none;
+  ainfo.argdefault = "";
+  ainfo.savedarginfo = cgiarginfo::mustnot;
+  argsinfo.addarginfo (NULL, ainfo);
+}
+
+
+void receptionist::add_action (action *theaction) {
+  // make sure we have an action to add
+  if (theaction == NULL) return;
+
+  // add this action to the list of actions
+  actions.addaction(theaction);
+  
+  // add the cgi arguments from this action
+  argsinfo.addarginfo (NULL, theaction->getargsinfo());
+}
+
+
+void receptionist::add_browser (browserclass *thebrowser) {
+  // make sure we have a browser to add
+  if (thebrowser == NULL) return;
+
+  // add this browser to the list of browsers
+  browsers.addbrowser(thebrowser);
+}
+
+
+void receptionist::setdefaultbrowser (const text_t &browsername) {
+  browsers.setdefaultbrowser (browsername);
+}
+
+
+// configure should be called for each line in the
+// configuration files to configure the receptionist and everything
+// it contains. The configuration should take place after everything
+// has been added but before the initialisation.
+void receptionist::configure (const text_t &key, const text_tarray &cfgline) {
+  // configure the receptionist
+  if (cfgline.size() >= 1) {
+    cgiarginfo *info = NULL;
+    if (key == "gsdlhome") configinfo.gsdlhome = cfgline[0];
+    else if (key == "collection") {
+      configinfo.collection = cfgline[0];
+      // also need to set the default arg to this collection
+      if ((info = argsinfo.getarginfo("c")) != NULL) {
+	info->defaultstatus = cgiarginfo::good;
+	info->argdefault = cfgline[0];
+      }
+      
+    } else if (key == "collectdir") configinfo.collectdir = cfgline[0];
+    else if (key == "httpprefix") configinfo.httpprefix = cfgline[0];
+    else if (key == "httpimg") configinfo.httpimg = cfgline[0];
+    else if (key == "gwcgi") configinfo.gwcgi = cfgline[0];
+    else if (key == "macrofiles") {
+      // want to append to macrofiles (i.e. may be several config files
+      // contributing, maybe from several collections).
+      text_tarray::const_iterator here = cfgline.begin();
+      text_tarray::const_iterator end = cfgline.end();
+      while (here != end) {
+	configinfo.macrofiles.insert (*here);
+	here ++;
+      }
+    }
+    else if (key == "saveconf") configinfo.saveconf = cfgline[0];
+    else if (key == "usecookies") configinfo.usecookies = (cfgline[0] == "true");
+    else if (key == "logcgiargs") configinfo.logcgiargs = (cfgline[0] == "true");
+    else if (key == "pageparam") {
+      if (cfgline.size() >= 2) configinfo.pageparams[cfgline[0]] = cfgline[1];
+      else configinfo.pageparams[cfgline[0]] = "";
+    }
+    else if (key == "macroprecedence") configinfo.macroprecedence = cfgline[0];
+    else if (key == "collectinfo") {
+      if (cfgline.size() >= 3) {
+	collectioninfo_t cinfo;
+	cinfo.gsdl_gsdlhome = cfgline[1];
+	cinfo.gsdl_gdbmhome = cfgline[2];
+	configinfo.collectinfo[cfgline[0]] = cinfo;
+      }
+    }
+    
+    else if (key == "cgiarg") {
+      // get shortname
+      bool seen_defaultstatus = false;
+      text_t subkey, subvalue;
+      text_t shortname;
+      text_t::const_iterator cfglinesub_here;
+      text_tarray::const_iterator cfgline_here = cfgline.begin();
+      text_tarray::const_iterator cfgline_end = cfgline.end();
+      while (cfgline_here != cfgline_end) {
+	cfglinesub_here = getdelimitstr((*cfgline_here).begin(),
+					(*cfgline_here).end(), '=', subkey);
+	if (subkey == "shortname") {
+	  shortname = substr (cfglinesub_here, (*cfgline_here).end());
+	}
+	cfgline_here++;
+      }
+
+      // if we found the shortname process the line again filling in values
+      if (!shortname.empty()) {
+	cgiarginfo &chinfo = argsinfo[shortname];
+	chinfo.shortname = shortname; // in case this is a new argument
+	
+	cfgline_here = cfgline.begin();
+	while (cfgline_here != cfgline_end) {
+	  cfglinesub_here = getdelimitstr((*cfgline_here).begin(),
+					  (*cfgline_here).end(), '=', subkey);
+	  subvalue = substr (cfglinesub_here, (*cfgline_here).end());
+
+	  if (subkey == "longname") chinfo.longname = subvalue;
+	  else if (subkey == "multiplechar") chinfo.multiplechar = (subvalue == "true");
+	  else if (subkey == "defaultstatus") {
+	    seen_defaultstatus = true;
+	    if (subvalue == "none") chinfo.defaultstatus = cgiarginfo::none;
+	    else if (subvalue == "weak") chinfo.defaultstatus = cgiarginfo::weak;
+	    else if (subvalue == "good") chinfo.defaultstatus = cgiarginfo::good;
+	    else if (subvalue == "config") chinfo.defaultstatus = cgiarginfo::config;
+	    else if (subvalue == "imperative") chinfo.defaultstatus = cgiarginfo::imperative;
+	  }
+	  else if (subkey == "argdefault") {
+	    chinfo.argdefault = subvalue;
+	    if (!seen_defaultstatus) chinfo.defaultstatus = cgiarginfo::config;
+	  }
+	  else if (subkey == "savedarginfo") {
+	    if (subvalue == "mustnot") chinfo.savedarginfo = cgiarginfo::mustnot;
+	    else if (subvalue == "can") chinfo.savedarginfo = cgiarginfo::can;
+	    else if (subvalue == "must") chinfo.savedarginfo = cgiarginfo::must;
+	  }
+	  
+	  cfgline_here++;
+	}
+      }
+    }
+  }
+  
+  // configure the actions
+  actionptrmap::iterator actionhere = actions.begin ();
+  actionptrmap::iterator actionend = actions.end ();
+
+  while (actionhere != actionend) {
+    assert ((*actionhere).second.a != NULL);
+    if ((*actionhere).second.a != NULL) 
+      (*actionhere).second.a->configure(key, cfgline);
+
+    actionhere++;
+  }
+
+  // configure the protocols
+  recptprotolistclass::iterator protohere = protocols.begin ();
+  recptprotolistclass::iterator protoend = protocols.end ();
+
+  while (protohere != protoend) {
+    assert ((*protohere).p != NULL);
+    if ((*protohere).p != NULL) 
+      (*protohere).p->configure(key, cfgline);
+    
+    protohere++;
+  }
+
+  // configure the browsers
+  browserptrmap::iterator browserhere = browsers.begin ();
+  browserptrmap::iterator browserend = browsers.end ();
+
+  while (browserhere != browserend) {
+    assert ((*browserhere).second.b != NULL);
+    if ((*browserhere).second.b != NULL) 
+      (*browserhere).second.b->configure(key, cfgline);
+    
+    browserhere++;
+  }
+}
+
+
+void receptionist::configure (const text_t &key, const text_t &value) {
+  text_tarray cfgline;
+  cfgline.push_back (value);
+  configure(key, cfgline);
+}
+
+
+// init should be called after all the actions, protocols, and
+// converters have been added to the receptionist and after everything
+// has been configured but before any pages are created.
+// It returns true on success and false on failure. If false is
+// returned getpage should not be called (without producing
+// meaningless output), instead an error page should be
+// produced by the calling code.
+bool receptionist::init (ostream &logout) {
+  // first configure collectdir
+  text_t thecollectdir = configinfo.gsdlhome;
+  if (!configinfo.collection.empty()) {
+    // collection specific mode
+    if (!configinfo.collectdir.empty()) {
+      // has already been configured
+      thecollectdir = configinfo.collectdir;
+    } else {
+      // decide where collectdir is by searching for collect.cfg
+      // look in $GSDLHOME/collect/collection-name/etc/collect.cfg and
+      // then $GSDLHOME/etc/collect.cfg
+      thecollectdir = filename_cat (configinfo.gsdlhome, "collect");
+      thecollectdir = filename_cat (thecollectdir, configinfo.collection);
+      text_t filename = filename_cat (thecollectdir, "etc");
+      filename = filename_cat (filename, "collect.cfg");
+
+      if (!file_exists(filename)) thecollectdir = configinfo.gsdlhome;
+    }
+  }
+  configure("collectdir", thecollectdir);
+
+  // read in the macro files
+  if (!read_macrofiles (logout)) return false;
+
+  // there must be at least one action defined
+  if (actions.empty()) {
+    logout << "Error: no actions have been added to the receptionist\n";
+    return false;
+  }
+
+  // there must be at least one browser defined
+  if (browsers.empty()) {
+    logout << "Error: no browsers have been added to the receptionist\n";
+    return false;
+  }
+
+  // create a saveconf string if there isn't one already
+  if (configinfo.saveconf.empty())
+    configinfo.saveconf = create_save_conf_str (argsinfo, logout);
+
+  // check the saveconf string
+  if (!check_save_conf_str (configinfo.saveconf, argsinfo, logout))
+    return false;
+
+  // set a random seed
+  srand (time(NULL));
+
+  // make the output converters remove all the zero-width spaces
+  convertinfoclass::iterator converthere = converters.begin ();
+  convertinfoclass::iterator convertend = converters.end ();
+  text_t defaultconvertname;
+  while (converthere != convertend) {
+    assert ((*converthere).second.outconverter != NULL);
+    if ((*converthere).second.outconverter != NULL) {
+      (*converthere).second.outconverter->set_rzws(1);
+      if (defaultconvertname.empty())
+	defaultconvertname = (*converthere).second.name;
+    }
+    converthere++;
+  }
+  
+  // set default converter if no good one has been defined
+  if (!defaultconvertname.empty()) {
+    cgiarginfo *ainfo = argsinfo.getarginfo ("w");
+    if (ainfo->argdefault != "w") {
+      if ((ainfo != NULL) && (converters.get_outconverter(ainfo->argdefault) == NULL)) {
+	ainfo->defaultstatus = cgiarginfo::good;
+	ainfo->argdefault = defaultconvertname;
+      }
+    }
+  }
+
+  // init the actions
+  actionptrmap::iterator actionhere = actions.begin ();
+  actionptrmap::iterator actionend = actions.end ();
+  while (actionhere != actionend) {
+    if (((*actionhere).second.a == NULL) || 
+	!(*actionhere).second.a->init(logout)) return false;
+    actionhere++;
+  }
+
+  // init the protocols
+  recptprotolistclass::iterator protohere = protocols.begin ();
+  recptprotolistclass::iterator protoend = protocols.end ();
+  while (protohere != protoend) {
+    if (((*protohere).p == NULL) ||
+	!(*protohere).p->init(logout)) return false;
+    protohere++;
+  }
+
+  // init the browsers
+  browserptrmap::iterator browserhere = browsers.begin ();
+  browserptrmap::iterator browserend = browsers.end ();
+  while (browserhere != browserend) {
+    if (((*browserhere).second.b == NULL) || 
+	!(*browserhere).second.b->init(logout)) return false;
+    browserhere++;
+  }
+
+  return true;
+}
+
+
+// parse_cgi_args parses cgi arguments into an argument class.
+// This function should be called for each page request. It returns false
+// if there was a major problem with the cgi arguments.
+bool receptionist::parse_cgi_args (const text_t &argstr, cgiargsclass &args, 
+				   ostream &logout, text_tmap &fcgienv) {
+  outconvertclass text_t2ascii;
+
+  // get an initial list of cgi arguments
+  args.clear();
+  split_cgi_args (argsinfo, argstr, args);
+
+  // expand the compressed argument (if there was one)
+  if (!expand_save_args (argsinfo, configinfo.saveconf, args, logout)) return false;
+
+  // add the defaults
+  add_default_args (argsinfo, args, logout);
+
+  // get the cookie
+  if (configinfo.usecookies) get_cookie(args["z"], fcgienv);
+  
+  // get the input encoding
+  text_t &arg_w = args["w"];
+  inconvertclass defaultinconvert;
+  inconvertclass *inconvert = converters.get_inconverter (arg_w);
+  if (inconvert == NULL) inconvert = &defaultinconvert;
+
+  // see if the next page will have a different encoding
+  if (args.getarg("nw") != NULL) arg_w = args["nw"];
+
+  // convert arguments which aren't in unicode to unicode
+  args_tounicode (args, *inconvert);
+
+
+  // decide on the output conversion class (needed for checking the external
+  // cgi arguments)
+  rzwsoutconvertclass defaultoutconverter;
+  rzwsoutconvertclass *outconverter = converters.get_outconverter (arg_w);
+  if (outconverter == NULL) outconverter = &defaultoutconverter;
+  outconverter->reset();
+
+  // check the main cgi arguments
+  if (!check_mainargs (args, logout)) return false;
+
+  // check the arguments for the action
+  action *a = actions.getaction (args["a"]);
+  if (a != NULL) {
+    if (!a->check_cgiargs (argsinfo, args, logout)) return false;
+  } else {
+    // the action was not found!!
+    logout << text_t2ascii << "Error: the action \"" << args["a"] 
+	   << "\" could not be found.\n";
+    return false;
+  }
+
+  // check external cgi arguments for each action
+  actionptrmap::iterator actionhere = actions.begin ();
+  actionptrmap::iterator actionend = actions.end ();
+  while (actionhere != actionend) {
+    assert ((*actionhere).second.a != NULL);
+    if ((*actionhere).second.a != NULL) {
+      if (!(*actionhere).second.a->check_external_cgiargs (argsinfo, args, *outconverter,
+							   configinfo.saveconf, logout))
+	return false;
+    }
+    actionhere++;
+  }
+
+  // the action might have changed but we will assume that
+  // the cgiargs were checked properly when the change was made
+
+  return true;
+}
+
+// returns true if cookie already existed, false
+// if it was generated
+bool receptionist::get_cookie (text_t &cookie, text_tmap &fcgienv) {
+
+  text_t cookiestring = gsdl_getenv ("HTTP_COOKIE", fcgienv);
+    
+  text_t::const_iterator end = cookiestring.end();  
+  text_t::const_iterator here = findchar (cookiestring.begin(), end, 'G');
+
+  while (here+9 < end) { 
+    
+    if (substr(here, here+8) == "GSDL_UID") {
+      cookie = substr (here+9, findchar (here+9, end, ';')); 
+      return true;
+    }
+    here = findchar (cookiestring.begin(), end, 'G');
+  }
+
+  cookie.clear();
+  text_t host = gsdl_getenv("REMOTE_ADDR", fcgienv);
+  time_t ttime = time(NULL);
+  if (!host.empty()) {
+    cookie += host;
+    cookie.push_back ('-');
+  }
+  cookie += text_t(ttime);
+  
+  return false;
+}
+
+// as above but just tests if cookie exists
+bool receptionist::get_cookie (text_tmap &fcgienv) {
+
+  text_t c = gsdl_getenv("HTTP_COOKIE", fcgienv);
+  if (!c.empty()) {
+    text_t cookiestring = c;
+    
+    text_t::const_iterator end = cookiestring.end();  
+    text_t::const_iterator here = findchar (cookiestring.begin(), end, 'G');
+
+    while (here+9 < end) { 
+      if (substr(here, here+8) == "GSDL_UID") return true;
+      here = findchar (cookiestring.begin(), end, 'G');
+    }
+  }
+  return false;
+}
+
+bool receptionist::log_cgi_args (cgiargsclass &args, ostream &logout, text_tmap &fcgienv) {
+
+  // see if we want to log the cgi arguments
+  if (!configinfo.logcgiargs) return true;
+  
+  text_t host = gsdl_getenv ("REMOTE_HOST", fcgienv);
+  text_t script_name = gsdl_getenv ("SCRIPT_NAME", fcgienv);
+  if (host.empty()) host = gsdl_getenv ("REMOTE_ADDR", fcgienv);
+  text_t browser = gsdl_getenv ("HTTP_USER_AGENT", fcgienv);
+  time_t ttime = time(NULL);
+
+  cgiargsclass::const_iterator args_here = args.begin();
+  cgiargsclass::const_iterator args_end = args.end();
+
+  text_t argstr;
+  bool first = true;
+  while (args_here != args_end) {
+    if (!first) argstr += ", ";
+    argstr += (*args_here).first + "=" + (*args_here).second.value;
+    first = false;
+    args_here ++;
+  }
+
+  text_t logfile = filename_cat (configinfo.gsdlhome, "etc");
+  logfile = filename_cat (logfile, "usage.txt");
+
+  text_t logstr = script_name;
+  logstr += " " + host;
+  logstr += " [";
+  logstr += ttime;
+  logstr += "] (" + argstr + ") \"";
+  logstr += browser;
+  logstr += "\"\n";
+
+  return append_logstr (logfile, logstr, logout);
+}
+
+bool receptionist::append_logstr (const text_t &filename, const text_t &logstr,
+				  ostream &logout) {
+
+  utf8outconvertclass text_t2utf8;
+  char *lfile = filename.getcstr();
+
+  ofstream log (lfile, ios::app);
+  
+  if (!log) {
+    logout << "Error: Couldn't open file " << lfile << "\n";
+    delete lfile;
+    return false;
+  }
+
+  int fd = GSDL_GET_FILEDESC(log);
+
+  // lock_val is set to 0 if file is locked successfully
+  int lock_val = 1;
+  GSDL_LOCK_FILE (fd);
+  if (lock_val == 0) {
+    log << text_t2utf8 << logstr;
+    GSDL_UNLOCK_FILE (fd);
+  } else {
+    logout << "Error: Couldn't lock file " << lfile << "\n";
+    log.close();
+    delete lfile;
+    return false;
+  }
+
+  log.close();
+		
+  delete lfile;
+  return true;
+}
+
+text_t receptionist::expandmacros (const text_t &astring, cgiargsclass &args, 
+				   ostream &logout) {
+  text_t outstring;
+  outconvertclass text_t2ascii;
+
+  action *a = actions.getaction (args["a"]);
+  prepare_page (a, args, text_t2ascii, logout);
+  disp.expandstring ("Global", astring, outstring);
+  return outstring;
+}
+
+// produce_cgi_page will call get_cgihead_info and 
+// produce_content in the appropriate way to output a cgi header and
+// the page content (if needed). If a page could not be created it
+// will return false
+bool receptionist::produce_cgi_page (cgiargsclass &args, ostream &contentout, 
+				     ostream &logout, text_tmap &fcgienv) {
+  outconvertclass text_t2ascii;
+
+  response_t response;
+  text_t response_data;
+
+  // produce cgi header
+  get_cgihead_info (args, response, response_data, logout, fcgienv);
+  if (response == location) {
+    // location response (url may contain macros!!)
+    response_data = expandmacros (response_data, args, logout);
+    contentout << text_t2ascii << "Location: " << response_data << "\n\n";
+    contentout << flush;
+    return true;
+  } else if (response == content) {
+    // content response
+    contentout << text_t2ascii << "Content-type: " << response_data << "\n\n";
+  } else {
+    // unknown response
+    logout << "Error: get_cgihead_info returned an unknown response type.\n";
+    return false;
+  }
+
+  // produce cgi page
+  if (!produce_content (args, contentout, logout)) return false;
+
+  // flush contentout
+  contentout << flush;
+  return true;
+}
+
+
+// get_cgihead_info determines the cgi header information for
+// a set of cgi arguments. If response contains location then
+// response_data contains the redirect address. If reponse
+// contains content then reponse_data contains the content-type.
+// Note that images can now be produced by the receptionist.
+void receptionist::get_cgihead_info (cgiargsclass &args, response_t &response,
+				     text_t &response_data, ostream &logout, 
+				     text_tmap &fcgienv) {
+  outconvertclass text_t2ascii;
+
+  // get the action
+  action *a = actions.getaction (args["a"]);
+  if (a != NULL) {
+    a->get_cgihead_info (args, &protocols, response, response_data, logout);
+
+  } else {
+    // the action was not found!!
+    logout << text_t2ascii << "Error receptionist::get_cgihead_info: the action \"" 
+	   << args["a"] << "\" could not be found.\n";
+    response = content;
+    response_data = "text/html";
+  }
+
+  // add the encoding information
+  if (response == content) {
+    if (args["w"] == "u") {
+      response_data += "; charset=UTF-8";
+    } else if (args["w"] == "g") {
+      response_data += "; charset=GBK";
+    } else if (args["w"] == "a") {
+      response_data += "; charset=windows-1256";
+    } else {
+      response_data += "; charset=ISO-8859-1";      
+    }
+
+    // add cookie if required
+    if (configinfo.usecookies && !get_cookie(fcgienv))
+      response_data += "\nSet-Cookie: GSDL_UID=" + args["z"]
+	+ "; expires=25-Dec-37 00:00:00 GMT";
+  }
+}
+
+
+// produce the page content
+bool receptionist::produce_content (cgiargsclass &args, ostream &contentout,
+				    ostream &logout) {
+
+  // decide on the output conversion class
+  text_t &arg_w = args["w"];
+  rzwsoutconvertclass defaultoutconverter;
+  rzwsoutconvertclass *outconverter = converters.get_outconverter (arg_w);
+  if (outconverter == NULL) outconverter = &defaultoutconverter;
+  outconverter->reset();
+
+
+  recptproto *collectproto = protocols.getrecptproto (args["c"], logout);
+  if (collectproto != NULL) {
+    // get browsers to process OID
+    text_t OID = args["d"];
+    if (OID.empty()) OID = args["cl"];
+    if (!OID.empty()) {
+      text_tset metadata;
+      text_tarray OIDs;
+      OIDs.push_back (OID);
+      if (!is_top(OID)) OIDs.push_back (OID + ".pr");
+      FilterResponse_t response;
+      metadata.insert ("childtype");
+      if (get_info (OIDs, args["c"], metadata, false, collectproto, response, logout)) {
+	text_t classifytype;
+	if (!response.docInfo[0].metadata["childtype"].values[0].empty())
+	  classifytype = response.docInfo[0].metadata["childtype"].values[0];
+	else if (!is_top (OID)) {
+	  if (!response.docInfo[1].metadata["childtype"].values[0].empty())
+	    classifytype = response.docInfo[1].metadata["childtype"].values[0];
+	}
+	browserclass *b = browsers.getbrowser (classifytype);
+	b->processOID (args, collectproto, logout);
+      }
+    }
+  
+    // translate "d" and "cl" arguments if required
+    translate_OIDs (args, collectproto, logout);
+  }
+  
+  // produce the page using the desired action
+  action *a = actions.getaction (args["a"]);
+  if (a != NULL) {
+    if (a->uses_display(args)) prepare_page (a, args, (*outconverter), logout);
+    if (!a->do_action (args, &protocols, &browsers, disp, (*outconverter), contentout, logout))
+      return false;
+
+  } else {
+    // the action was not found!!
+    outconvertclass text_t2ascii;
+
+    logout << text_t2ascii << "Error receptionist::produce_content: the action \"" 
+	   << args["a"] << "\" could not be found.\n";
+    
+    contentout << (*outconverter) 
+	       << "<html>\n"
+	       << "<head>\n"
+	       << "<title>Error</title>\n"
+	       << "</head>\n"
+	       << "<body>\n"
+	       << "<h2>Oops!</h2>\n"
+	       << "Undefined Page. The action \"" 
+	       << args["a"] << "\" could not be found.\n"
+	       << "</body>\n"
+	       << "</html>\n";
+  }
+  return true;
+}
+
+
+// returns the compressed argument ("e") corresponding to the argument
+// list. This can be used to save preferences between sessions.
+text_t receptionist::get_compressed_arg (cgiargsclass &args, ostream &logout) {
+  // decide on the output conversion class
+  text_t &arg_w = args["w"];
+  rzwsoutconvertclass defaultoutconverter;
+  rzwsoutconvertclass *outconverter = converters.get_outconverter (arg_w);
+  if (outconverter == NULL) outconverter = &defaultoutconverter;
+  outconverter->reset();
+
+  text_t compressed_args;
+  if (compress_save_args (argsinfo, configinfo.saveconf, args, 
+			  compressed_args, *outconverter, logout))
+    return compressed_args;
+
+  return "";
+}
+
+
+// will read in all the macro files. If one is not found an
+// error message will be written to logout and the method will
+// return false.
+bool receptionist::read_macrofiles (ostream &logout) {
+  outconvertclass text_t2ascii;
+
+  // redirect the error output to logout
+  ostream *savedlogout = disp.setlogout (&logout);
+
+  // load up the default macro files, the collection directory
+  // is searched first for the file (if this is being used in
+  // collection specific mode) and then the main directory(s)
+  text_t colmacrodir = filename_cat (configinfo.collectdir, "macros");
+
+  text_tset maindirs;
+  text_t gsdlmacrodir = filename_cat (configinfo.gsdlhome, "macros");
+  maindirs.insert (gsdlmacrodir);
+  colinfo_tmap::iterator colhere = configinfo.collectinfo.begin();
+  colinfo_tmap::iterator colend = configinfo.collectinfo.end();
+  while (colhere != colend) {
+    if (!((*colhere).second.gsdl_gsdlhome).empty()) {
+      gsdlmacrodir = filename_cat ((*colhere).second.gsdl_gsdlhome, "macros");
+      maindirs.insert (gsdlmacrodir);
+    }
+    colhere ++;
+  }
+
+  text_tset::iterator arrhere = configinfo.macrofiles.begin();
+  text_tset::iterator arrend = configinfo.macrofiles.end();
+  text_t filename;
+  while (arrhere != arrend) {
+    bool foundfile = false;
+
+    // try in the collection directory if this is being
+    // run in collection specific mode
+    if (!configinfo.collection.empty()) {
+      filename = filename_cat (colmacrodir, *arrhere);
+      if (file_exists (filename)) {
+	disp.loaddefaultmacros(filename);
+	foundfile = true;
+      }
+    }
+
+    // if we haven't found the macro file yet try in
+    // the main macro directory(s)
+    // if file is found in more than one main directory
+    // we'll load all copies
+    if (!foundfile) {
+      text_tset::const_iterator dirhere = maindirs.begin();
+      text_tset::const_iterator dirend = maindirs.end();
+      while (dirhere != dirend) {
+	filename = filename_cat (*dirhere, *arrhere);
+	if (file_exists (filename)) {
+	  disp.loaddefaultmacros(filename);
+	  foundfile = true;
+	}
+	dirhere ++;
+      }
+    }
+
+    // see if we found the file or not
+    if (!foundfile) {
+      logout << text_t2ascii 
+	     << "Error: the macro file \"" << *arrhere << "\" could not be found.\n";
+      if (configinfo.collection.empty()) {
+	text_t dirs;
+	joinchar (maindirs, ", ", dirs);
+	logout << text_t2ascii 
+	       << "It should be in either of the following directories ("
+	       << dirs << ").\n\n";
+
+      } else {
+	logout << text_t2ascii
+	       << "It should be in either " << colmacrodir << " or in " 
+	       << gsdlmacrodir << ".\n\n";
+      }
+      // reset logout to what it was
+      disp.setlogout (savedlogout);
+      return false;
+    }
+    arrhere++;
+  }
+
+  // success
+
+  // reset logout to what it was
+  disp.setlogout (savedlogout);
+  return true;
+}
+
+
+// check_mainargs will check all the main arguments. If a major
+// error is found it will return false and no cgi page should
+// be created using the arguments.
+bool receptionist::check_mainargs (cgiargsclass &args, ostream &logout) {
+  // if this receptionist is running in collection dependant mode
+  // then it should always set the collection argument to the
+  // collection
+  if (!configinfo.collection.empty()) args["c"] = configinfo.collection;
+
+  // if current collection uses ccscols make sure
+  // "ccs" argument is set and make "cc" default to
+  // all collections in "ccs"
+  if (!args["c"].empty()) {
+
+    text_t &arg_c = args["c"];
+    recptproto *collectproto = protocols.getrecptproto (arg_c, logout);
+    if (collectproto == NULL) {
+      // oops, this collection isn't valid
+      outconvertclass text_t2ascii;
+      logout << text_t2ascii << "ERROR: Invalid collection: " << arg_c << "\n";
+      args["c"].clear();
+
+    } else {
+
+      ColInfoResponse_t *cinfo = get_collectinfo_ptr (collectproto, arg_c, logout);
+
+      if (cinfo != NULL) {
+	if (!cinfo->ccsCols.empty()) {
+	  args["ccs"] = 1;
+	  if (args["cc"].empty()) {
+	    text_tarray::const_iterator col_here = cinfo->ccsCols.begin();
+	    text_tarray::const_iterator col_end = cinfo->ccsCols.end();
+	    bool first = true;
+	    while (col_here != col_end) {
+	      // make sure it's a valid collection
+	      if (protocols.getrecptproto (*col_here, logout) != NULL) {
+		if (!first) args["cc"].push_back (',');
+		args["cc"] += *col_here;
+		first = false;
+	      }
+	      col_here ++;
+	    }
+	  }
+	}
+      } else {
+	logout << "ERROR (receptionist::check_mainargs): get_collectinfo_ptr returned NULL\n";
+      }
+    }
+  }
+
+  // argument "v" can only be 0 or 1. Use the default value
+  // if it is out of range
+  int arg_v = args.getintarg ("v");
+  if (arg_v != 0 && arg_v != 1) {
+    cgiarginfo *vinfo = argsinfo.getarginfo ("v");
+    if (vinfo != NULL) args["v"] = vinfo->argdefault;
+  }
+
+  // argument "f" can only be 0 or 1. Use the default value
+  // if it is out of range
+  int arg_f = args.getintarg ("f");
+  if (arg_f != 0 && arg_f != 1) {
+    cgiarginfo *finfo = argsinfo.getarginfo ("f");
+    if (finfo != NULL) args["f"] = finfo->argdefault;
+  }
+
+  return true;
+}
+
+// translate_OIDs translates the "d" and "cl" arguments to their correct values
+// if they use the tricky ".fc", ".lc" type syntax.
+void receptionist::translate_OIDs (cgiargsclass &args, recptproto *collectproto, 
+				   ostream &logout) {
+
+  FilterResponse_t response;
+  FilterRequest_t request;
+  comerror_t err;
+  text_t &arg_d = args["d"];
+  text_t &arg_cl = args["cl"];
+  text_t &collection = args["c"];
+  
+  // do a call to translate OIDs if required
+  request.filterName = "NullFilter";
+  request.filterResultOptions = FROID;
+  if (!arg_d.empty() && needs_translating (arg_d)) {
+    request.docSet.push_back (arg_d);
+    collectproto->filter (collection, request, response, err, logout);
+    arg_d = response.docInfo[0].OID;
+    request.clear();
+  }
+  // we'll also check here that the "cl" argument has a "classify" doctype 
+  // (in case ".fc" or ".lc" have screwed up)
+  if (needs_translating (arg_cl)) {
+    request.fields.insert ("doctype");
+    request.docSet.push_back (arg_cl);
+    request.filterResultOptions = FRmetadata;
+    collectproto->filter (collection, request, response, err, logout);
+    // set to original value (without .xx stuff) if doctype isn't "classify"
+    if (response.docInfo[0].metadata["doctype"].values[0] != "classify")
+      strip_suffix (arg_cl);
+    else
+      arg_cl = response.docInfo[0].OID;
+  }
+}
+
+// prepare_page sets up page parameters, sets display macros
+// and opens the page ready for output 
+void receptionist::prepare_page (action *a, cgiargsclass &args, 
+				 outconvertclass &outconvert, 
+				 ostream &logout) {
+  // set up page parameters
+  text_t pageparams;
+  bool first = true;
+
+  text_tmap::iterator params_here = configinfo.pageparams.begin();
+  text_tmap::iterator params_end = configinfo.pageparams.end();
+  while (params_here != params_end) {
+    if (args[(*params_here).first] != (*params_here).second) {
+      if (!first) pageparams += ",";
+      first = false;
+      pageparams += (*params_here).first;
+      pageparams += "=";
+      pageparams += args[(*params_here).first];
+    }
+    
+    params_here++;
+  }
+  
+
+  // open the page
+  disp.openpage(pageparams, configinfo.macroprecedence);
+
+
+  // define external macros for each action
+  actionptrmap::iterator actionhere = actions.begin ();
+  actionptrmap::iterator actionend = actions.end ();
+
+  while (actionhere != actionend) {
+    assert ((*actionhere).second.a != NULL);
+    if ((*actionhere).second.a != NULL) 
+      (*actionhere).second.a->define_external_macros (disp, args, &protocols, logout);
+    actionhere++;
+  }
+
+  // define internal macros for the current action
+  a->define_internal_macros (disp, args, &protocols, logout);
+  
+  // define general macros. the defining of general macros is done here so that
+  // the last possible version of the cgi arguments are used
+  define_general_macros (args, outconvert, logout);
+}
+
+void receptionist::define_general_macros (cgiargsclass &args, outconvertclass &/*outconvert*/, 
+					  ostream &logout) {
+
+  text_t &collection = args["c"];
+
+  disp.setmacro ("gsdlhome", "Global", dm_safe(configinfo.gsdlhome));
+  disp.setmacro ("gwcgi", "Global", configinfo.gwcgi);
+  disp.setmacro ("httpimg", "Global", configinfo.httpimg);
+  disp.setmacro ("httpprefix", "Global", configinfo.httpprefix);
+  text_t compressedoptions = get_compressed_arg(args, logout);
+  disp.setmacro ("compressedoptions", "Global", dm_safe(compressedoptions));
+  // need a decoded version of compressedoptions for use within forms
+  // as browsers encode values from forms before sending to server
+  // (e.g. %25 becomes %2525)
+  decode_cgi_arg (compressedoptions);
+  disp.setmacro ("decodedcompressedoptions", "Global", dm_safe(compressedoptions));
+
+#if defined (__WIN32__)
+  disp.setmacro ("win32", "Global", "1");
+#endif
+
+  // set macron macros if encoding is utf8
+  if (args["w"] == "u") {
+    disp.setmacro ("Amn", "Global", "&#256;");
+    disp.setmacro ("amn", "Global", "&#257;");
+    disp.setmacro ("Emn", "Global", "&#274;");
+    disp.setmacro ("emn", "Global", "&#275;");
+    disp.setmacro ("Imn", "Global", "&#298;");
+    disp.setmacro ("imn", "Global", "&#299;");
+    disp.setmacro ("Omn", "Global", "&#332;");
+    disp.setmacro ("omn", "Global", "&#333;");
+    disp.setmacro ("Umn", "Global", "&#362;");
+    disp.setmacro ("umn", "Global", "&#363;");
+  }
+
+  // set _cgiargX_ macros for each cgi argument
+  cgiargsclass::const_iterator argshere = args.begin();
+  cgiargsclass::const_iterator argsend = args.end();
+  while (argshere != argsend) {
+    if (((*argshere).first == "q") ||
+	((*argshere).first == "qa") ||
+	((*argshere).first == "qtt") ||
+	((*argshere).first == "qty") ||
+	((*argshere).first == "qp") ||
+	((*argshere).first == "qpl") ||
+	((*argshere).first == "qr") ||
+	((*argshere).first == "q2"))
+      // need to escape special characters from query string
+      disp.setmacro ("cgiarg" + (*argshere).first, 
+		     "Global", html_safe((*argshere).second.value));
+    else 
+      disp.setmacro ("cgiarg" + (*argshere).first, "Global", dm_safe((*argshere).second.value));
+    argshere ++;
+  }
+
+  // display text right to left if language is arabic (and if browser can support it)
+  if (args["l"] == "ar")
+    disp.setmacro ("htmlextra", "Global", " dir=rtl");
+
+  // set collection specific macros
+  if (!collection.empty()) {
+    recptproto *collectproto = protocols.getrecptproto (collection, logout);
+    if (collectproto != NULL) {
+      FilterResponse_t response;
+      text_tset metadata;
+      get_info ("collection", collection, metadata, false, 
+		collectproto, response, logout);
+      
+      if (!response.docInfo[0].metadata.empty()) {
+	MetadataInfo_tmap::const_iterator here = response.docInfo[0].metadata.begin();
+	MetadataInfo_tmap::const_iterator end = response.docInfo[0].metadata.end();
+	while (here != end) {
+	  if (((*here).first != "haschildren") && ((*here).first != "hasnext") &&
+	      ((*here).first != "hasprevious")) {
+	    disp.setmacro ((*here).first, "Global", (*here).second.values[0]);
+	  }
+	  here ++;
+	}
+      }
+    }
+  }
+}
+
+// gets collection info from cache if found or 
+// calls collection server (and updates cache)
+// returns NULL if there's an error
+ColInfoResponse_t *receptionist::get_collectinfo_ptr (recptproto *collectproto, 
+						      const text_t &collection, 
+						      ostream &logout) {
+  
+  // check the cache
+  colinfo_tmap::iterator it = configinfo.collectinfo.find (collection);
+  if ((it != configinfo.collectinfo.end()) && ((*it).second.info_loaded)) {
+    // found it
+    return &((*it).second.info);
+  }
+
+  // not cached, get info from collection server
+  if (collectproto == NULL) {
+    logout << "ERROR: receptionist::get_collectinfo_ptr passed null collectproto\n";
+    return NULL;
+  }
+   
+  comerror_t err;
+  if (it == configinfo.collectinfo.end()) {
+    collectioninfo_t cinfo;
+    collectproto->get_collectinfo (collection, cinfo.info, err, logout);
+    if (err != noError) {
+      outconvertclass text_t2ascii;
+      logout << text_t2ascii << "ERROR (receptionist::getcollectinfo_ptr): \""
+	     << get_comerror_string (err) << "\"while getting collectinfo\n";
+      return NULL;
+    }
+    cinfo.info_loaded = true;
+    configinfo.collectinfo[collection] = cinfo;
+    return &(configinfo.collectinfo[collection].info);
+  } else {
+    collectproto->get_collectinfo (collection, (*it).second.info, err, logout);
+    if (err != noError) {
+      outconvertclass text_t2ascii;
+      logout << text_t2ascii << "ERROR (receptionist::getcollectinfo_ptr): \""
+	     << get_comerror_string (err) << "\"while getting collectinfo\n";
+      return NULL;
+    }
+    (*it).second.info_loaded = true;
+    return &((*it).second.info);
+  }
+}
Index: /main/tags/2.25/gsdl/src/recpt/receptionist.h
===================================================================
--- /main/tags/2.25/gsdl/src/recpt/receptionist.h	(revision 21064)
+++ /main/tags/2.25/gsdl/src/recpt/receptionist.h	(revision 21064)
@@ -0,0 +1,231 @@
+/**********************************************************************
+ *
+ * receptionist.h -- a web interface for the gsdl
+ * Copyright (C) 1999  The New Zealand Digital Library Project
+ *
+ * A component of the Greenstone digital library software
+ * from the New Zealand Digital Library Project at the
+ * University of Waikato, New Zealand.
+ *
+ * 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.
+ *
+ *********************************************************************/
+
+
+#ifndef RECEPTIONIST_H
+#define RECEPTIONIST_H
+
+#include "gsdlconf.h"
+#include "text_t.h"
+#include "cgiargs.h"
+#include "display.h"
+#include "browserclass.h"
+#include "recptproto.h"
+#include "converter.h"
+#include "cfgread.h"
+#include "action.h"
+
+// the MACROPRECEDENCE macro is used as a default. override
+// it using something like:
+//
+// macroprecedence c,l
+//
+// in your configuration file
+#ifndef MACROPRECEDENCE
+#define MACROPRECEDENCE "c,l"
+#endif
+
+
+struct collectioninfo_t {
+  void clear ();
+  collectioninfo_t () {clear();}
+
+  text_t gsdl_gsdlhome;
+  text_t gsdl_gdbmhome;
+
+  bool info_loaded;
+  ColInfoResponse_t info;
+};
+
+typedef map<text_t, collectioninfo_t, lttext_t> colinfo_tmap;
+
+
+struct recptconf {
+  text_t gsdlhome;
+  text_t gdbmhome;   // will equal gsdlhome if not set
+  text_t collection; // will equal "" in 'general' mode
+  text_t collectdir; // will equal gsdlhome in 'general' mode
+  colinfo_tmap collectinfo;
+  text_t httpprefix;
+  text_t httpimg;    // will equal /images if not set
+  text_t gwcgi;
+  text_tset macrofiles;
+  text_t saveconf;
+  bool usecookies;  // true if we want cookies set
+  bool logcgiargs;  // true if we want to log cgi arguments
+
+  text_tmap pageparams;
+  text_t macroprecedence;
+  
+  void clear ();
+  recptconf () {clear();}
+};
+
+class receptionist {
+protected:
+  recptconf configinfo;
+
+  cgiargsinfoclass argsinfo;
+  actionmapclass actions;
+  browsermapclass browsers;
+  recptprotolistclass protocols;
+  displayclass disp;
+  convertinfoclass converters;
+  ColInfoResponse_t collectinfo;
+  
+  // prepare_page sets up page parameters, sets display macros
+  // and opens the page ready for output 
+  virtual void prepare_page (action *a, cgiargsclass &args, 
+			     outconvertclass &outconvert, 
+			     ostream &logout);
+  
+  virtual void translate_OIDs (cgiargsclass &args, recptproto *collectproto,
+			       ostream &logout);
+
+  bool get_cookie (text_t &cookie, text_tmap &fcgienv);
+  bool get_cookie (text_tmap &fcgienv);
+
+  virtual void define_general_macros (cgiargsclass &args, outconvertclass &outconvert, 
+				      ostream &logout);
+
+  bool append_logstr (const text_t &filename, const text_t &logstr,
+		      ostream &logout);
+
+public:
+  receptionist ();
+  virtual ~receptionist() {}
+
+  // add_action makes another action available to the receptionist
+  // the action remains the property of the calling code and that
+  // code should destroy the action after the recptionist has been
+  // destroyed.
+  void add_action (action *theaction);
+  actionmapclass *get_actionmap_ptr () {return &actions;}
+
+  // add_browser makes another browser available to the receptionist
+  // the browser remains the property of the calling code and that
+  // code should destroy it after the recptionist has been
+  // destroyed.
+  void add_browser (browserclass *thebrowser);
+  browsermapclass *get_browsermap_ptr () {return &browsers;}
+  void setdefaultbrowser (const text_t &browsername);
+
+  // add_protocol makes another protocol available to the receptionist
+  // without any protocols, no collections will be available. The
+  // protocols remain the property of the calling code.
+  void add_protocol (recptproto *theprotocol) {protocols.addrecptproto(theprotocol);}
+  recptprotolistclass *get_recptprotolist_ptr () {return &protocols;}
+  
+  // add_converter makes another converter available to the receptionist.
+  // Converters are needed to display pages using different encodings.
+  // The converters remain the property of the calling code.
+  void add_converter (const text_t &name, inconvertclass *inconverter,
+		      rzwsoutconvertclass *outconverter) {
+    converters.add_converter(name, inconverter, outconverter);}
+  convertinfoclass *get_convertinfo_ptr () {return &converters;}
+  
+  
+  // configure should be called for each line in the
+  // configuration files to configure the receptionist and everything
+  // it contains. The configuration should take place after everything
+  // has been added but before the initialisation.
+  virtual void configure (const text_t &key, const text_tarray &cfgline);
+  virtual void configure (const text_t &key, const text_t &value);
+  const recptconf &get_configinfo () {return configinfo;}
+  cgiargsinfoclass *get_cgiargsinfo_ptr () {return &argsinfo;}
+  
+
+  // init should be called after all the actions, protocols, and
+  // converters have been added to the receptionist and after everything
+  // has been configured but before any pages are created.
+  // It returns true on success and false on failure. If false is
+  // returned getpage should not be called (without producing
+  // meaningless output), instead an error page should be
+  // produced by the calling code.
+  virtual bool init (ostream &logout);
+  
+  // There are two ways to produce a page. You can either call parse_cgi_args,
+  // get_cgihead_info, and produce_content or you can just call parse_cgi_args and
+  // produce_cgi_page (which will be satisfactory in most cases). You might want to call
+  // parse_cgi_args, get_cgihead_info, and produce_content when you want to
+  // interface directly with a web server for which the standard header is inappropriate.
+
+  // parse_cgi_args parses cgi arguments into an argument class.
+  // This function should be called for each page request. It returns false
+  // if there was a major problem with the cgi arguments.
+  virtual bool parse_cgi_args (const text_t &argstr, cgiargsclass &args, 
+			       ostream &logout, text_tmap &fcgienv);
+
+  virtual bool log_cgi_args (cgiargsclass &args, ostream &logout, text_tmap &fcgienv);
+
+  text_t expandmacros (const text_t &astring, cgiargsclass &args, 
+		       ostream &logout);
+
+  // produce_cgi_page will call get_cgihead_info and 
+  // produce_content in the appropriate way to output a cgi header and
+  // the page content (if needed). If a page could not be created it
+  // will return false
+  virtual bool produce_cgi_page (cgiargsclass &args, ostream &contentout, 
+				 ostream &logout, text_tmap &fcgienv);
+  
+  // get_cgihead_info determines the cgi header information for
+  // a set of cgi arguments. If response contains location then
+  // response_data contains the redirect address. If reponse
+  // contains content then reponse_data contains the content-type.
+  // Note that images can now be produced by the receptionist.
+  virtual void get_cgihead_info (cgiargsclass &args, response_t &response,
+				 text_t &response_data, ostream &logout,
+				 text_tmap &fcgienv);
+  
+  // produce the page content
+  virtual bool produce_content (cgiargsclass &args, ostream &contentout,
+				ostream &logout);
+  
+  // returns the compressed argument ("e") corresponding to the argument
+  // list. This can be used to save preferences between sessions.
+  text_t get_compressed_arg (cgiargsclass &args, ostream &logout);
+
+  // gets collection info from cache if found or 
+  // calls collection server (and updates cache)
+  // returns NULL if there's an error
+  ColInfoResponse_t *get_collectinfo_ptr (recptproto *collectproto, 
+					  const text_t &collection, 
+					  ostream &logout);
+
+  
+protected:
+  // will read in all the macro files. If one is not found an
+  // error message will be written to logout and the method will
+  // return false.
+  virtual bool read_macrofiles (ostream &logout);
+  
+  // check_mainargs will check all the main arguments. If a major
+  // error is found it will return false and no cgi page should
+  // be created using the arguments.
+  virtual bool check_mainargs (cgiargsclass &args, ostream &logout);
+};
+
+
+#endif
Index: /main/tags/2.25/gsdl/src/recpt/recptconfig.cpp
===================================================================
--- /main/tags/2.25/gsdl/src/recpt/recptconfig.cpp	(revision 21064)
+++ /main/tags/2.25/gsdl/src/recpt/recptconfig.cpp	(revision 21064)
@@ -0,0 +1,193 @@
+/**********************************************************************
+ *
+ * recptconfig.cpp -- 
+ * Copyright (C) 1999  The New Zealand Digital Library Project
+ *
+ * A component of the Greenstone digital library software
+ * from the New Zealand Digital Library Project at the
+ * University of Waikato, New Zealand.
+ *
+ * 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.
+ *
+ *********************************************************************/
+
+#include "recptconfig.h"
+#include "fileutil.h"
+#include "cfgread.h"
+
+
+#if defined(GSDL_USE_OBJECTSPACE)
+#  include <ospace/std/iostream>
+#  include <ospace/std/fstream>
+#elif defined(GSDL_USE_IOS_H)
+#  include <iostream.h>
+#  include <fstream.h>
+#else
+#  include <iostream>
+#  include <fstream>
+#endif
+
+
+// reads site configuration file returning true on success
+// also sets gsdlhome and maxrequests 
+// gsdlsite.cfg should be in same directory as library executable
+bool site_cfg_read (receptionist &recpt, text_t &gsdlhome, int &maxrequests) {
+
+  gsdlhome.clear();
+
+  // Look for gsdlsite.cfg in same directory that executable is in.
+  text_tarray cfgline;
+  text_t key;
+
+#ifdef GSDL_USE_IOS_H
+  ifstream confin ("gsdlsite.cfg", ios::in | ios::nocreate);
+#else
+  ifstream confin ("gsdlsite.cfg", ios::in);
+#endif
+
+  if (confin) {
+    while (read_cfg_line(confin, cfgline) >= 0) {
+      if (cfgline.size () >= 2) {
+	key = cfgline[0];
+	cfgline.erase(cfgline.begin());
+	
+	if (key == "maxrequests") {
+	  maxrequests = cfgline[0].getint();
+	  if (maxrequests < 1) maxrequests = 1;
+	}
+
+	if (key == "gsdlhome")
+	  gsdlhome = cfgline[0];
+
+	// configure the receptionist
+	recpt.configure (key, cfgline);
+      }
+    }
+    confin.close ();
+    return true;
+  }
+  return false;
+}
+
+// this version just grabs gsdlhome, returning true
+// unless unable to read gsdlsite.cfg
+bool site_cfg_read (text_t &gsdlhome) {
+
+  gsdlhome.clear();
+
+  // Look for gsdlsite.cfg in same directory that executable is in.
+  text_tarray cfgline;
+  text_t key;
+
+#ifdef GSDL_USE_IOS_H
+  ifstream confin ("gsdlsite.cfg", ios::in | ios::nocreate);
+#else
+  ifstream confin ("gsdlsite.cfg", ios::in);
+#endif
+
+  if (confin) {
+    while (read_cfg_line(confin, cfgline) >= 0) {
+      if (cfgline.size () >= 2) {
+	if (cfgline[0] == "gsdlhome") {
+	  gsdlhome = cfgline[1];
+	  break;
+	}
+      }
+    }
+    return true;
+    confin.close ();
+  }
+  return false;
+}
+
+// main_cfg_read reads both main.cfg and collect.cfg. It attempts
+// to read main.cfg first so values in collect.cfg override those
+// set earlier by main.cfg
+bool main_cfg_read (receptionist &recpt, const text_t &gsdlhome,
+		     const text_t &collection) {
+
+  // read in the main configuration file
+  bool rv = false;
+  text_t key, filename;
+  text_tarray cfgline;
+  filename = filename_cat (gsdlhome, "etc");
+  filename = filename_cat (filename, "main.cfg");
+  if (file_exists (filename)) {
+    char *cstr = filename.getcstr();
+    
+#ifdef GSDL_USE_IOS_H
+    ifstream confin (cstr, ios::in | ios::nocreate);
+#else
+    ifstream confin (cstr, ios::in);
+#endif
+
+    delete cstr;
+  
+    if (confin) {
+      while (read_cfg_line(confin, cfgline) >= 0) {
+	if (cfgline.size () >= 2) {
+	  key = cfgline[0];
+	  cfgline.erase(cfgline.begin());
+	
+	  // configure the receptionist
+	  recpt.configure (key, cfgline);
+	}
+      }
+      confin.close ();
+      rv = true;
+    }
+  }
+  
+  // Look for collect.cfg in GSDLHOME/collect/collection-name/etc directory 
+  // (if this is for a particular collection), and then GSDLHOME/etc.
+  if (!collection.empty()) {
+    filename = filename_cat (gsdlhome, "collect");
+    filename = filename_cat (filename, collection);
+    filename = filename_cat (filename, "etc");
+    filename = filename_cat (filename, "collect.cfg");
+    if (!file_exists (filename)) {
+      filename = filename_cat (gsdlhome, "etc");
+      filename = filename_cat (filename, "collect.cfg");
+      if (!file_exists (filename)) filename.clear();
+    }
+
+    if (!filename.empty()) {
+      char *cstr = filename.getcstr();
+
+#ifdef GSDL_USE_IOS_H
+      ifstream confin (cstr, ios::in | ios::nocreate);
+#else
+      ifstream confin (cstr, ios::in);
+#endif
+      
+      delete cstr;
+      
+      if (confin) {
+	while (read_cfg_line(confin, cfgline) >= 0) {
+	  if (cfgline.size () >= 2) {
+	    key = cfgline[0];
+	    cfgline.erase(cfgline.begin());
+	    
+	    // configure the receptionist
+	    recpt.configure (key, cfgline);
+	  }
+	}
+	confin.close ();
+	rv = true;
+      }
+    }
+  }
+  return rv;
+}
Index: /main/tags/2.25/gsdl/src/recpt/recptconfig.h
===================================================================
--- /main/tags/2.25/gsdl/src/recpt/recptconfig.h	(revision 21064)
+++ /main/tags/2.25/gsdl/src/recpt/recptconfig.h	(revision 21064)
@@ -0,0 +1,47 @@
+/**********************************************************************
+ *
+ * recptconfig.h -- 
+ * Copyright (C) 1999  The New Zealand Digital Library Project
+ *
+ * A component of the Greenstone digital library software
+ * from the New Zealand Digital Library Project at the
+ * University of Waikato, New Zealand.
+ *
+ * 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.
+ *
+ *********************************************************************/
+
+
+#ifndef RECPTCONFIG_H
+#define RECPTCONFIG_H
+
+
+#include "gsdlconf.h"
+#include "text_t.h"
+#include "receptionist.h"
+
+
+// reads site configuration file returning true on success
+bool site_cfg_read (receptionist &recpt, text_t &gsdlhome, int &maxrequests);
+bool site_cfg_read (text_t &gsdlhome);
+
+// main_cfg_read reads either collect.cfg or main.cfg and returning 
+// true on success. It attempts to read collect.cfg first if a
+// collection is specified and then it tries to read in main.cfg
+bool main_cfg_read (receptionist &recpt, const text_t &gsdlhome,
+		    const text_t &collection);
+
+
+#endif
Index: /main/tags/2.25/gsdl/src/recpt/recptmain.cpp
===================================================================
--- /main/tags/2.25/gsdl/src/recpt/recptmain.cpp	(revision 21064)
+++ /main/tags/2.25/gsdl/src/recpt/recptmain.cpp	(revision 21064)
@@ -0,0 +1,34 @@
+/**********************************************************************
+ *
+ * recptmain.cpp -- 
+ * Copyright (C) 1999  The New Zealand Digital Library Project
+ *
+ * A component of the Greenstone digital library software
+ * from the New Zealand Digital Library Project at the
+ * University of Waikato, New Zealand.
+ *
+ * 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.
+ *
+ *********************************************************************/
+
+#include "receptionist.h"
+#include "cgiwrapper.h"
+#include <assert.h>
+
+int main () {
+  receptionist recpt;
+  cgiwrapper (recpt, "");
+  return 0;
+}
Index: /main/tags/2.25/gsdl/src/recpt/recptproto.cpp
===================================================================
--- /main/tags/2.25/gsdl/src/recpt/recptproto.cpp	(revision 21064)
+++ /main/tags/2.25/gsdl/src/recpt/recptproto.cpp	(revision 21064)
@@ -0,0 +1,151 @@
+/**********************************************************************
+ *
+ * recptproto.cpp -- 
+ * Copyright (C) 1999  The New Zealand Digital Library Project
+ *
+ * A component of the Greenstone digital library software
+ * from the New Zealand Digital Library Project at the
+ * University of Waikato, New Zealand.
+ *
+ * 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.
+ *
+ *********************************************************************/
+
+#include "recptproto.h"
+#include <assert.h>
+
+
+// configure should be called for each line in the configuration file
+void recptproto::configure (const text_t &/*key*/, const text_tarray &/*cfgline*/) {
+}
+
+// init should be called after the configuration but before any other
+// functions are called. If init returns false a message will be written
+// out to the log file and no other output should be produced.
+bool recptproto::init (ostream &/*logout*/) {
+  return true;
+}
+
+// get_protocol_name should return the name of this protocol (e.g. recptproto)
+// that can be used to do run time type identification and display information
+// about the protocol.
+text_t recptproto::get_protocol_name () {
+  return "recptproto";
+}
+
+// get_collection_list returns the list of collections that
+// this protocol knows about
+void recptproto::get_collection_list (text_tarray &collist, comerror_t &err, 
+				      ostream &/*logout*/) {
+  collist.erase(collist.begin(),collist.end());
+  err = noError;
+}
+
+// has_collection sets 'hascollection' to be true if the protocol
+// can communicate with the collection (i.e. it is within its 
+// collection list). This function should be implemented in as
+// efficient time as possible as it will be called for each page
+// access and for each protocol.
+void recptproto::has_collection (const text_t &/*collection*/, bool &hascollection, 
+				 comerror_t &err, ostream &/*logout*/) {
+  hascollection = false;
+  err = noError;
+}
+
+// sets 'wassuccess' to be true if a successful ping was done to
+// the given collection.
+void recptproto::ping (const text_t &/*collection*/, bool &wassuccess, 
+		       comerror_t &err, ostream &/*logout*/) {
+  wassuccess = false; // no collections are supported by this class
+  err = noError;
+}
+
+// obtains general information about the collection
+void recptproto::get_collectinfo (const text_t &/*collection*/, 
+				  ColInfoResponse_t &/*collectinfo*/,
+				  comerror_t &err, ostream &/*logout*/) {
+  err = protocolError;
+}
+
+// gets a list of all the filters
+void recptproto::get_filterinfo (const text_t &/*collection*/,
+				 InfoFiltersResponse_t &/*reponse*/,
+				 comerror_t &err, ostream &/*logout*/) {
+  err = protocolError;
+}
+
+// gets all the filter options for a particular filter
+void recptproto::get_filteroptions (const text_t &/*collection*/,
+				    const InfoFilterOptionsRequest_t &/*request*/,
+				    InfoFilterOptionsResponse_t &/*response*/, 
+				    comerror_t &err, ostream &/*logout*/) {
+  err = protocolError;
+}
+
+// filters (search or browse) a result set
+void recptproto::filter (const text_t &/*collection*/,
+			 FilterRequest_t &/*request*/,
+			 FilterResponse_t &/*response*/,
+			 comerror_t &err, ostream &/*logout*/) {
+  err = protocolError;
+}
+
+void recptproto::get_document (const text_t &/*collection*/,
+			       const DocumentRequest_t &/*request*/,
+			       DocumentResponse_t &/*response*/,
+			       comerror_t &err, ostream &/*logout*/) {
+  err = protocolError;
+}
+
+
+
+
+
+
+
+// therecptproto remains the property of the calling code but
+// should not be deleted until it is removed from this list.
+void recptprotolistclass::addrecptproto (recptproto *therecptproto) {
+  // can't add a protocol that doesn't exist
+  assert (therecptproto != NULL);
+  if (therecptproto == NULL) return;
+
+  recptprotoptr rpp;
+  rpp.p = therecptproto;
+
+  recptprotoptrs.push_back(rpp);
+}
+
+// getrecptproto will return NULL if a recptproto for the given colelction
+// could not be found
+recptproto *recptprotolistclass::getrecptproto (const text_t &collection, 
+						ostream &logout) {
+  iterator here = recptprotoptrs.begin ();
+  iterator end = recptprotoptrs.end ();
+  bool hascollection;
+  comerror_t err;
+
+  while (here != end) {
+    assert ((*here).p != NULL);
+    if ((*here).p != NULL) {
+      (*here).p->has_collection (collection, hascollection, err, logout);
+      if ((err == noError) && (hascollection == true)) return (*here).p;
+    }
+    
+    here++;
+  }
+  
+  return NULL;
+}
Index: /main/tags/2.25/gsdl/src/recpt/recptproto.h
===================================================================
--- /main/tags/2.25/gsdl/src/recpt/recptproto.h	(revision 21064)
+++ /main/tags/2.25/gsdl/src/recpt/recptproto.h	(revision 21064)
@@ -0,0 +1,176 @@
+/**********************************************************************
+ *
+ * recptproto.h -- 
+ * Copyright (C) 1999  The New Zealand Digital Library Project
+ *
+ * A component of the Greenstone digital library software
+ * from the New Zealand Digital Library Project at the
+ * University of Waikato, New Zealand.
+ *
+ * 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.
+ *
+ *********************************************************************/
+
+
+#ifndef RECPTPROTO_H
+#define RECPTPROTO_H
+
+#include "gsdlconf.h"
+#include "text_t.h"
+#include "comtypes.h"
+
+#if defined(GSDL_USE_OBJECTSPACE)
+#  include <ospace\std\vector>
+#elif defined(GSDL_USE_STL_H)
+#  include <vector.h>
+#else
+#  include <vector>
+#endif
+
+#if defined(GSDL_USE_OBJECTSPACE)
+#  include <ospace\std\iostream>
+#elif defined(GSDL_USE_IOS_H)
+#  include <iostream.h>
+#else
+#  include <iostream>
+#endif
+
+
+// recptproto is a generalisation of a protocol for communicating
+// with a collection server.
+class recptproto {
+public:
+  // configure should be called for each line in the configuration file
+  virtual void configure (const text_t &key, const text_tarray &cfgline);
+
+  // init should be called after the configuration but before any other
+  // functions are called. If init returns false a message will be written
+  // out to the log file and no other output should be produced.
+  virtual bool init (ostream &logout);
+
+  // get_protocol_name should return the name of this protocol (e.g. recptproto)
+  // that can be used to do run time type identification and display information
+  // about the protocol.
+  virtual text_t get_protocol_name ();
+
+  // get_collection_list returns the list of collections that
+  // this protocol knows about
+  virtual void get_collection_list (text_tarray &collist, comerror_t &err, 
+				    ostream &logout);
+
+  // has_collection sets 'hascollection' to be true if the protocol
+  // can communicate with the collection (i.e. it is within its 
+  // collection list). This function should be implemented in as
+  // efficient time as possible as it will be called for each page
+  // access and for each protocol.
+  virtual void has_collection (const text_t &collection, bool &hascollection, 
+			       comerror_t &err, ostream &logout);
+
+  // sets 'wassuccess' to be true if a successful ping was done to
+  // the given collection.
+  virtual void ping (const text_t &collection, bool &wassuccess, 
+		     comerror_t &err, ostream &logout);
+
+  // obtains general information about the collection
+  virtual void get_collectinfo (const text_t &collection, 
+				ColInfoResponse_t &collectinfo,
+				comerror_t &err, ostream &logout);
+
+  // gets a list of all the filters
+  virtual void get_filterinfo (const text_t &collection,
+			       InfoFiltersResponse_t &response,
+			       comerror_t &err, ostream &logout);
+
+  // gets all the filter options for a particular filter
+  virtual void get_filteroptions (const text_t &collection,
+				  const InfoFilterOptionsRequest_t &request,
+				  InfoFilterOptionsResponse_t &response, 
+				  comerror_t &err, ostream &logout);
+
+  // filters (search or browse) a result set and returns information
+  // about the filtered set including term frequency information and 
+  // metadata
+  virtual void filter (const text_t &collection,
+		       FilterRequest_t &request,
+		       FilterResponse_t &response,
+		       comerror_t &err, ostream &logout);
+
+  // gets a document (duh!)
+  virtual void get_document (const text_t &collection,
+			     const DocumentRequest_t &request,
+			     DocumentResponse_t &response,
+			     comerror_t &err, ostream &logout);
+};
+
+
+// The recptprotoptr function does not 'own' the recptproto. The 
+// recptproto should be deleted by the code which created it.
+class recptprotoptr {
+public:
+  recptproto *p;
+
+  recptprotoptr () {p=NULL;}
+  ~recptprotoptr () {}
+};
+
+typedef vector<recptprotoptr> recptprotoptrlist;
+
+
+// contains a list of recptprotos
+class recptprotolistclass {
+protected:
+  recptprotoptrlist recptprotoptrs;
+
+public:
+  // type support for recptprotolistclass
+  typedef recptprotoptrlist::iterator iterator;
+  typedef recptprotoptrlist::const_iterator const_iterator;
+  typedef recptprotoptrlist::reference reference;
+  typedef recptprotoptrlist::const_reference const_reference;
+  typedef recptprotoptrlist::size_type size_type;
+
+  typedef recptprotoptrlist::difference_type difference_type;
+  typedef recptprotoptrlist::const_reverse_iterator const_reverse_iterator;
+  typedef recptprotoptrlist::reverse_iterator reverse_iterator;
+  
+  // basic container support
+  iterator begin () {return recptprotoptrs.begin();}
+  const_iterator begin () const {return recptprotoptrs.begin();}
+  iterator end () {return recptprotoptrs.end();}
+  const_iterator end () const {return recptprotoptrs.end();}
+
+  void erase(iterator pos) {recptprotoptrs.erase(pos);}
+  void erase(iterator first, iterator last) {recptprotoptrs.erase(first, last);}
+  recptprotolistclass &operator=(const recptprotolistclass &x) 
+    {recptprotoptrs=x.recptprotoptrs;return *this;}
+
+  bool empty () const {return recptprotoptrs.empty();}
+  size_type size() const {return recptprotoptrs.size();}
+
+
+  // added functionality
+  void clear () {recptprotoptrs.erase(recptprotoptrs.begin(),recptprotoptrs.end());}
+
+  // therecptproto remains the property of the calling code but
+  // should not be deleted until it is removed from this list.
+  void addrecptproto (recptproto *therecptproto);
+
+  // getrecptproto will return NULL if a recptproto for the given collection
+  // could not be found
+  recptproto *getrecptproto (const text_t &collection, ostream &logout);
+};
+
+
+#endif
Index: /main/tags/2.25/gsdl/src/recpt/statusaction.cpp
===================================================================
--- /main/tags/2.25/gsdl/src/recpt/statusaction.cpp	(revision 21064)
+++ /main/tags/2.25/gsdl/src/recpt/statusaction.cpp	(revision 21064)
@@ -0,0 +1,967 @@
+/**********************************************************************
+ *
+ * statusaction.cpp -- 
+ * Copyright (C) 1999  The New Zealand Digital Library Project
+ *
+ * A component of the Greenstone digital library software
+ * from the New Zealand Digital Library Project at the
+ * University of Waikato, New Zealand.
+ *
+ * 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.
+ *
+ *********************************************************************/
+
+#include "statusaction.h"
+#include "fileutil.h"
+#include "htmlutils.h"
+#include <assert.h>
+
+
+void statusaction::output_frameset (cgiargsclass &/*args*/, displayclass &disp, 
+				    outconvertclass &outconvert, 
+				    ostream &textout, ostream &/*logout*/) {
+  textout << outconvert << disp << "_status:frameset_\n";
+}
+
+void statusaction::output_select (cgiargsclass &/*args*/, displayclass &disp, 
+				  outconvertclass &outconvert, 
+				  ostream &textout, ostream &/*logout*/) {
+  textout << outconvert << disp << "_status:header_(selector)\n"
+    "_status:select_\n"
+    "_status:footer_\n";
+}
+
+void statusaction::output_welcome (cgiargsclass &/*args*/, recptprotolistclass *protos, 
+				   displayclass &disp, outconvertclass &outconvert, 
+				   ostream &textout, ostream &logout) {
+
+  if (recpt == NULL) return;
+
+  textout << outconvert << disp 
+	  << "_status:infoheader_(_titlewelcome_)\n"
+	  << "_status:welcome_"
+	  << "<center><table width=_pagewidth_>\n"
+	  << "<th align=left>abbrev.</th><th align=left>collection</th>"
+	  << "<th align=left>public?</th><th align=left>running?</th></tr>\n";
+
+  recptprotolistclass::iterator rprotolist_here = protos->begin();
+  recptprotolistclass::iterator rprotolist_end = protos->end();
+  while (rprotolist_here != rprotolist_end) {
+    if ((*rprotolist_here).p != NULL) {
+      text_t protoname = (*rprotolist_here).p->get_protocol_name();
+      text_tarray collist;
+      comerror_t err;
+      (*rprotolist_here).p->get_collection_list (collist, err, logout);
+      if (err == noError) {
+	text_tarray::iterator collist_here = collist.begin();
+	text_tarray::iterator collist_end = collist.end();
+
+	while (collist_here != collist_end) {
+
+	    textout << outconvert << disp
+		    << "<tr><td><a href=\"_gwcgi_?e=_compressedoptions_&a=status&sp=collectioninfo&pr="
+		    << protoname
+		    << "&c="
+		    << *collist_here
+		    << "\">"
+		    << *collist_here 
+		    << "</a></td>";
+
+	  ColInfoResponse_t *cinfo = recpt->get_collectinfo_ptr ((*rprotolist_here).p, *collist_here, logout);
+	  if (cinfo != NULL) {
+	    text_t collname = *collist_here;
+	    text_tmap::iterator it = cinfo->collectionmeta.find("collectionname");
+	    if (it != cinfo->collectionmeta.end()) collname = (*it).second;
+
+	    textout << "<td>";
+	    if (cinfo->buildDate > 0)
+	      textout << outconvert << disp 
+		      << "<a href=\"_httppagex_(about)&c=" << *collist_here
+		      << "\" target=\\_top>";
+
+	    textout << outconvert << disp << collname;
+
+	    if (cinfo->buildDate > 0) textout << "</a>";
+
+	    textout << "</td>";
+
+	    if (cinfo->isPublic) textout << "<td>yes</td>";
+	    else textout << "<td>no</td>";
+	    
+	    if (cinfo->buildDate > 0)
+	      textout << outconvert << "<td>yes</td>";
+	    else
+	      textout << "<td>no</td>";
+	    
+	  } else {
+	    textout << "<td></td><td></td><td></td>";
+	  }
+
+	  textout << "</tr>\n";
+	  collist_here ++;
+	}
+      }
+    }
+    rprotolist_here ++;
+  }
+
+  textout << "</table></center>\n";
+  textout << outconvert << disp << "_status:infofooter_\n";
+}
+
+void statusaction::output_generalinfo (cgiargsclass &/*args*/, displayclass &disp, 
+				       outconvertclass &outconvert, 
+				       ostream &textout, ostream &/*logout*/) {
+  if (recpt == NULL) return;
+  const recptconf &rcinfo = recpt->get_configinfo ();
+  
+  textout << outconvert << disp << "_status:infoheader_(General Information)\n";
+  textout << outconvert 
+	  << "<h2>General information</h2>\n"
+	  << "<table>\n"
+	  << "<tr valign=top><th>gsdlhome</th><td>\"" << rcinfo.gsdlhome
+	  << "\"</td></tr>\n"
+	  << "<tr valign=top><th>collection</th><td>\"" << rcinfo.collection
+	  << "\"</td></tr>\n"
+	  << "<tr valign=top><th>collectdir</th><td>\"" << rcinfo.collectdir
+	  << "\"</td></tr>\n"
+	  << "<tr valign=top><th>httpprefix</th><td>\"" << rcinfo.httpprefix
+	  << "\"</td></tr>\n"
+	  << "<tr valign=top><th>httpimg</th><td>\"" << rcinfo.httpimg
+	  << "\"</td></tr>\n"
+	  << "<tr valign=top><th>gwcgi</th><td>\"" << rcinfo.gwcgi
+	  << "\"</td></tr>\n";
+    
+  // macrofiles
+  textout << outconvert << "<tr valign=top><th>macrofiles</th><td>";
+  text_tset::const_iterator macrohere = rcinfo.macrofiles.begin ();
+  text_tset::const_iterator macroend = rcinfo.macrofiles.end ();
+  bool macrofirst = true;
+  while (macrohere != macroend) {
+    if (!macrofirst) textout << outconvert << ", ";
+    macrofirst = false;
+    textout << outconvert << "\"" << *macrohere << "\"";
+    macrohere++;
+  }
+  textout << outconvert << "</td></tr>\n";
+  
+  // saveconf
+  textout << outconvert << "<tr valign=top><th>saveconf</th><td>\"" << rcinfo.saveconf
+	  << "\"</td></tr>\n";
+
+  // usecookies
+  textout << outconvert << "<tr valign=top><th>usecookies</th><td>\"";
+  if (rcinfo.usecookies) textout << outconvert << "true";
+  else textout << outconvert << "false";
+  textout << outconvert << "\"</td></tr>\n";
+  
+  // logcgiargs
+  textout << outconvert << "<tr valign=top><th>logcgiargs</th><td>\"";
+  if (rcinfo.logcgiargs) textout << outconvert << "true";
+  else textout << outconvert << "false";
+  textout << outconvert << "\"</td></tr>\n";
+
+  // pageparams
+  textout << outconvert << "<tr valign=top><th>pageparams</th><td>";
+  text_tmap::const_iterator params_here = rcinfo.pageparams.begin();
+  text_tmap::const_iterator params_end = rcinfo.pageparams.end();
+  bool params_first = true;
+  while (params_here != params_end) {
+    if (!params_first) textout << outconvert << ", ";
+    params_first = false;
+    textout << outconvert << "\"" << (*params_here).first << "\" != \""
+	    << (*params_here).second << "\"";
+    
+    params_here++;
+  }
+  textout << outconvert << "</td></tr>\n";
+
+  // macroprecedence
+  textout << outconvert << "<tr valign=top><th>macroprecedence</th><td>\"" << rcinfo.macroprecedence
+	  << "\"</td></tr>\n";
+
+  // arguments
+  cgiargsinfoclass *rcargsinfo = recpt->get_cgiargsinfo_ptr ();
+  if (rcargsinfo != NULL) {
+    textout << outconvert << "<tr valign=top><th>arguments</th><td>";
+    
+    cgiargsinfoclass::const_iterator argsinfohere = rcargsinfo->begin ();
+    cgiargsinfoclass::const_iterator argsinfoend = rcargsinfo->end ();
+    bool argsinfofirst = true;
+    while (argsinfohere != argsinfoend) {
+      if (!argsinfofirst) textout << outconvert << ", ";
+      argsinfofirst = false;
+      textout << outconvert << "\"" << (*argsinfohere).second.shortname << "\"";
+      argsinfohere++;
+    }
+    
+    textout << outconvert << "</td></tr>\n";
+  }      
+  
+  // actions
+  actionmapclass *actions = recpt->get_actionmap_ptr();
+  if (actions != NULL) {
+    textout << outconvert << "<tr valign=top><th>actions</th><td>";
+    
+    actionptrmap::iterator actionshere = actions->begin ();
+    actionptrmap::iterator actionsend = actions->end ();
+    bool actionsfirst = true;
+    while (actionshere != actionsend) {
+      if (!actionsfirst) textout << outconvert << ", ";
+      actionsfirst = false;
+      assert ((*actionshere).second.a != NULL);
+      if ((*actionshere).second.a != NULL) {
+	textout << outconvert << "\"" << (*actionshere).second.a->get_action_name() << "\"";
+      }
+      actionshere++;
+    }
+    
+    textout << outconvert << "</td></tr>\n";
+  }
+  
+  // browsers
+  browsermapclass *browsers = recpt->get_browsermap_ptr();
+  if (browsers != NULL) {
+    textout << outconvert << "<tr valign=top><th>browsers</th><td>";
+    
+    browserptrmap::iterator browsershere = browsers->begin ();
+    browserptrmap::iterator browsersend = browsers->end ();
+    bool browsersfirst = true;
+    while (browsershere != browsersend) {
+      if (!browsersfirst) textout << outconvert << ", ";
+      browsersfirst = false;
+      assert ((*browsershere).second.b != NULL);
+      if ((*browsershere).second.b != NULL) {
+	textout << outconvert << "\"" << (*browsershere).second.b->get_browser_name() << "\"";
+      }
+      browsershere++;
+    }
+    
+    textout << outconvert << "</td></tr>\n";
+  }
+
+  // protocols
+  recptprotolistclass *protocols = recpt->get_recptprotolist_ptr ();
+  if (protocols != NULL) {
+    textout << outconvert << "<tr valign=top><th>protocols</th><td>";
+    
+    recptprotolistclass::iterator protohere = protocols->begin ();
+    recptprotolistclass::iterator protoend = protocols->end ();
+    bool protofirst = true;
+    while (protohere != protoend) {
+      if (!protofirst) textout << outconvert << ", ";
+      protofirst = false;
+      if ((*protohere).p != NULL) {
+	textout << outconvert << "\"" << (*protohere).p->get_protocol_name() << "\"";
+      }
+      protohere++;
+    }
+    
+    textout << outconvert << "</td></tr>\n";
+  }
+  
+  // converters
+  convertinfoclass *converters = recpt->get_convertinfo_ptr ();
+  if (converters != NULL) {
+    textout << outconvert << "<tr valign=top><th>converters</th><td>";
+    
+    convertinfoclass::iterator converthere = converters->begin ();
+    convertinfoclass::iterator convertend = converters->end ();
+    bool convertfirst = true;
+    while (converthere != convertend) {
+      if (!convertfirst) textout << outconvert << ", ";
+      convertfirst = false;
+      textout << outconvert << "\"" << (*converthere).second.name << "\"";
+      converthere++;
+    }
+    
+    textout << outconvert << "</td></tr>\n";
+  }
+  
+  textout << outconvert << disp << "</table>\n_status:infofooter_\n";
+}
+
+void statusaction::output_argumentinfo (cgiargsclass &args, displayclass &disp, 
+					outconvertclass &outconvert, 
+					ostream &textout, ostream &/*logout*/) {
+  if (recpt == NULL) return;
+  cgiargsinfoclass *rcargsinfo = recpt->get_cgiargsinfo_ptr ();
+  if (rcargsinfo == NULL) return;
+
+  textout << outconvert << disp << "_status:infoheader_(Argument Information)\n";
+  textout << outconvert
+	  << "<h2>Argument information</h2>\n"
+	  << "<table>";
+
+  // argument information
+  textout << outconvert << "<tr valign=top><th>short name</th><th>long name</th>"
+	  << "<th>multiple char?</th>"
+	  << "<th>multiple value?</th>"
+	  << "<th>default</th><th>default status</th><th>saved args</th>"
+	  << "<th>current value</th></tr>\n";
+  
+
+  cgiargsinfoclass::const_iterator argsinfohere = rcargsinfo->begin();
+  cgiargsinfoclass::const_iterator argsinfoend = rcargsinfo->end();
+  text_t *arg_value;
+  while (argsinfohere != argsinfoend) {
+    const cgiarginfo &ainfo = (*argsinfohere).second;
+    textout << outconvert 
+	    << "<tr valign=top><td>" << ainfo.shortname << "</td>\n";
+    
+    textout << outconvert << "<td>" << ainfo.longname << "</td>\n";
+    if (ainfo.multiplechar) textout << outconvert << "<td>yes</td>\n";
+    else textout << outconvert << "<td>no</td>\n";
+    if (ainfo.multiplevalue) textout << outconvert << "<td>yes</td>\n";
+    else textout << outconvert << "<td>no</td>\n";
+    textout << outconvert << "<td>" << ainfo.argdefault << "</td>\n";
+    switch (ainfo.defaultstatus) {
+    case cgiarginfo::none: textout << outconvert << "<td>none</td>\n"; break;
+    case cgiarginfo::weak: textout << outconvert << "<td>weak</td>\n"; break;
+    case cgiarginfo::good: textout << outconvert << "<td>good</td>\n"; break;
+    case cgiarginfo::config: textout << outconvert << "<td>config</td>\n"; break;
+    case cgiarginfo::imperative: textout << outconvert << "<td>imperative</td>\n"; break;
+    }
+    switch (ainfo.savedarginfo) {
+    case cgiarginfo::mustnot: textout << outconvert << "<td>mustnot</td>\n"; break;
+    case cgiarginfo::can: textout << outconvert << "<td>can</td>\n"; break;
+    case cgiarginfo::must: textout << outconvert << "<td>must</td>\n"; break;
+    }
+    
+    arg_value = args.getarg (ainfo.shortname);
+    if (arg_value == NULL) textout << outconvert << "<td></td></tr>\n";
+    else textout << outconvert << "<td>\"" << *arg_value << "\"</td></tr>\n";
+    
+    argsinfohere ++;
+  }
+  
+  textout << outconvert << disp << "</table>\n_status:infofooter_\n";
+}
+
+void statusaction::output_actioninfo (cgiargsclass &/*args*/, displayclass &disp, 
+				      outconvertclass &outconvert, 
+				      ostream &textout, ostream &/*logout*/) {
+  if (recpt == NULL) return;
+  actionmapclass *actions = recpt->get_actionmap_ptr();
+
+  textout << outconvert << disp << "_status:infoheader_(Action Information)\n";
+  textout << outconvert
+	  << "<h2>Action information</h2>\n"
+	  << "<table>";
+
+  // action information
+  if (actions != NULL) {
+    textout << outconvert 
+	    << "<tr><th>action name</th><th>cgi arguments</th></tr>\n";
+	
+    actionptrmap::iterator actionshere = actions->begin ();
+    actionptrmap::iterator actionsend = actions->end ();
+    while (actionshere != actionsend) {
+      assert ((*actionshere).second.a != NULL);
+      if ((*actionshere).second.a != NULL) {
+	textout << outconvert 
+		<< "<tr><td>" << (*actionshere).second.a->get_action_name()
+		<< "</td><td>";
+	
+	cgiargsinfoclass argsinfo = (*actionshere).second.a->getargsinfo();
+	cgiargsinfoclass::const_iterator argsinfohere = argsinfo.begin ();
+	cgiargsinfoclass::const_iterator argsinfoend = argsinfo.end ();
+	bool aifirst = true;
+	while (argsinfohere != argsinfoend) {
+	  if (!aifirst) textout << outconvert << ", ";
+	  aifirst = false;
+	  textout << outconvert << (*argsinfohere).second.shortname;
+	  argsinfohere++;
+	}
+	
+	textout << outconvert << "</td></tr>\n";
+      }
+      actionshere++;
+    }
+  }
+  
+  textout << outconvert << disp << "</table>\n_status:infofooter_\n";
+}
+
+void statusaction::output_browserinfo (cgiargsclass &/*args*/, displayclass &disp, 
+				       outconvertclass &outconvert, 
+				       ostream &textout, ostream &/*logout*/) {
+  if (recpt == NULL) return;
+  browsermapclass *browsers = recpt->get_browsermap_ptr();
+
+  textout << outconvert << disp << "_status:infoheader_(Browser Information)\n";
+  textout << outconvert
+	  << "<h2>Browser information</h2>\n"
+	  << "<table>";
+
+  // browser information
+  if (browsers != NULL) {
+    textout << outconvert 
+	    << "<tr><th>browser name</th><th>default formatstring</th></tr>\n";
+	
+    browserptrmap::iterator browsershere = browsers->begin ();
+    browserptrmap::iterator browsersend = browsers->end ();
+    while (browsershere != browsersend) {
+      assert ((*browsershere).second.b != NULL);
+      if ((*browsershere).second.b != NULL) {
+	textout << outconvert 
+		<< "<tr><td>" << (*browsershere).second.b->get_browser_name()
+		<< "</td><td>" << html_safe ((*browsershere).second.b->get_default_formatstring())
+		<< "</td></tr>\n";
+      }
+      browsershere++;
+    }
+  }
+  
+  textout << outconvert << disp << "</table>\n_status:infofooter_\n";
+}
+
+void statusaction::output_protocolinfo (cgiargsclass &/*args*/, displayclass &disp, 
+					outconvertclass &outconvert, 
+					ostream &textout, ostream &logout) {
+  if (recpt == NULL) return;
+  const recptconf &rcinfo = recpt->get_configinfo ();
+  bool colspecific = !rcinfo.collection.empty();
+  bool unreachablecol = false;
+
+  recptprotolistclass *rprotolist = recpt->get_recptprotolist_ptr ();
+  if (rprotolist == NULL) return;
+
+  textout << outconvert << disp << "_status:infoheader_(Protocol Information)\n";
+  textout << outconvert
+	  << "<h2>Protocol information</h2>\n"
+	  << "<table>\n"
+	  << "<tr><th>protocol</th><th>collections</th></tr>\n";
+
+  text_t protoname;
+  recptprotolistclass::iterator rprotolist_here = rprotolist->begin();
+  recptprotolistclass::iterator rprotolist_end = rprotolist->end();
+  while (rprotolist_here != rprotolist_end) {
+    if ((*rprotolist_here).p != NULL) {
+      protoname = (*rprotolist_here).p->get_protocol_name();
+      textout << outconvert
+	      << "<tr><td>"
+	      << protoname
+	      << "</td><td>";
+
+      text_tarray collist;
+      comerror_t err;
+      (*rprotolist_here).p->get_collection_list (collist, err, logout);
+      if (err == noError) {
+	text_tarray::iterator collist_here = collist.begin();
+	text_tarray::iterator collist_end = collist.end();
+	bool first = true;
+	while (collist_here != collist_end) {
+	  if (!first) textout << outconvert << ", ";
+	  first = false;
+
+	  if (colspecific && *collist_here != rcinfo.collection) {
+	    unreachablecol = true;
+	    textout << outconvert << "\"" << *collist_here << "\"";
+	  } else {
+	    textout << outconvert << disp
+		    << "\"<a href=\"_gwcgi_?e=_compressedoptions_&a=status&sp=collectioninfo&pr="
+		    << protoname
+		    << "&c="
+		    << *collist_here
+		    << "\">"
+		    << *collist_here 
+		    << "</a>\"";
+	  }
+
+	  collist_here++;
+	}
+
+      } else {
+	textout << outconvert << "Error (" << get_comerror_string (err) 
+		<< ") while getting collect list\n";
+      }
+
+      textout << outconvert 
+	      << "</td></tr>\n";
+    }
+
+    rprotolist_here++;
+  }
+
+  textout << outconvert << "</table>\n";
+  if (unreachablecol) {
+    textout << outconvert 
+	    << "<b>Warning:</b> the receptionist is running in collection specific\n"
+	    << "mode making some of the collections unreachable.\n";
+  }
+  textout << outconvert << disp << "_status:infofooter_\n";
+}
+
+void statusaction::output_collectioninfo (cgiargsclass &args, displayclass &disp, 
+					  outconvertclass &outconvert, 
+					  ostream &textout, ostream &logout) {
+  if (recpt == NULL) return;
+
+  textout << outconvert << disp << "_status:infoheader_(Collection info)\n";
+  textout << outconvert << "<h2>Collection info</h2>\n";
+
+  // get the list of protocols
+  recptprotolistclass *rprotolist = recpt->get_recptprotolist_ptr ();
+  if (rprotolist == NULL) return;
+
+  // look for the desired protocol
+  text_t &arg_pr = args["pr"];
+  text_t &arg_c = args["c"];
+  recptproto *rproto = NULL;
+  recptprotolistclass::iterator rprotolist_here = rprotolist->begin();
+  recptprotolistclass::iterator rprotolist_end = rprotolist->end();
+  while (rprotolist_here != rprotolist_end) {
+    rproto = (*rprotolist_here).p;
+    if (rproto != NULL && rproto->get_protocol_name() == arg_pr) {
+      // see if the protocol has the collection
+      bool hascollection;
+      comerror_t err;
+      rproto->has_collection (arg_c, hascollection, err, logout);
+      if (err == noError && hascollection) break;
+    }
+    rprotolist_here++;
+  }
+  
+  if (rprotolist_here == rprotolist_end) {
+    textout << outconvert << "Protocol \"" << arg_pr << "\" with collection \""
+	    << arg_c << "\" was not found\n";
+
+  } else {
+    // rproto can't be NULL to get here
+    ColInfoResponse_t *collectinfo = recpt->get_collectinfo_ptr (rproto, arg_c, logout);
+    if (collectinfo != NULL) {
+      textout << outconvert << "<table>\n"
+	      << "<tr><th>collection name</th><td>\""
+	      << collectinfo->shortInfo.name
+	      << "\"</td></tr>\n"
+
+	      << "<tr><th>host</th><td>\""
+	      << collectinfo->shortInfo.host
+	      << "\"</td></tr>\n"
+
+	      << "<tr><th>port</th><td>\""
+	      << collectinfo->shortInfo.port
+	      << "\"</td></tr>\n"
+
+	      << "<tr><th>is public?</th><td>";
+      if (collectinfo->isPublic) textout << outconvert << "true";
+      else textout << outconvert << "false";
+      textout << outconvert 
+	      << "</td></tr>\n"
+
+	      << "<tr><th>is beta?</th><td>";
+      if (collectinfo->isBeta) textout << outconvert << "true";
+      else textout << outconvert << "false";
+      textout << outconvert 
+	      << "</td></tr>\n"
+
+	      << "<tr><th>build date</th><td>\""
+	      << collectinfo->buildDate
+	      << "\"</td></tr>\n"
+
+	      << "<tr><th>interface languages</th><td>";
+      text_tarray::iterator languages_here = collectinfo->languages.begin();
+      text_tarray::iterator languages_end = collectinfo->languages.end();
+      bool languages_first = true;
+      while (languages_here != languages_end) {
+	if (!languages_first) textout << outconvert << ", ";
+	languages_first = false;
+	textout << outconvert << "\"" << *languages_here << "\"";
+	languages_here++;
+      }
+
+      textout << "<tr><th valign=top>collection metadata</th><td><table>\n";
+      text_tmap::iterator meta_here = collectinfo->collectionmeta.begin();
+      text_tmap::iterator meta_end = collectinfo->collectionmeta.end();
+      while (meta_here != meta_end) {
+	textout << outconvert << "<tr><td>" << (*meta_here).first
+		<< "</td><td>" << (*meta_here).second << "</td></tr>\n";
+	meta_here ++;
+      }
+      textout << "</table></td></tr>\n";
+
+      textout << "<tr><th valign=top>format info</th><td><table>\n";
+      text_tmap::iterator format_here = collectinfo->format.begin();
+      text_tmap::iterator format_end = collectinfo->format.end();
+      while (format_here != format_end) {
+	textout << outconvert << "<tr><td>" << (*format_here).first
+		<< "</td><td>" << html_safe((*format_here).second) << "</td></tr>\n";
+	format_here ++;
+      }
+      textout << "</table></td></tr>\n";
+
+      textout << "<tr><th valign=top>building info</th><td><table>\n";
+      text_tmap::iterator building_here = collectinfo->building.begin();
+      text_tmap::iterator building_end = collectinfo->building.end();
+      while (building_here != building_end) {
+	textout << outconvert << "<tr><td>" << (*building_here).first
+		<< "</td><td>" << (*building_here).second << "</td></tr>\n";
+	building_here ++;
+      }
+      textout << "</table></td></tr>\n";
+
+      textout << outconvert 
+	      << "</td></tr>\n"
+
+	      << "<tr><th>number of documents</th><td>\""
+	      << collectinfo->numDocs
+	      << "\"</td></tr>\n"
+
+	      << "<tr><th>number of sections</th><td>\""
+	      << collectinfo->numSections
+	      << "\"</td></tr>\n"
+
+	      << "<tr><th>number of words</th><td>\""
+	      << collectinfo->numWords
+	      << "\"</td></tr>\n"
+
+	      << "<tr><th>number of bytes</th><td>\""
+	      << collectinfo->numBytes
+	      << "\"</td></tr>\n"
+
+	      << "<tr><th>preferred receptionist</th><td>\""
+	      << collectinfo->receptionist
+	      << "\"</td></tr>\n"
+
+	      << "</table>";
+      
+    } else {
+      textout << "ERROR (statusaction::output_collectioninfo): while getting collect information\n";
+    }
+
+
+    InfoFiltersResponse_t filterinfo;
+    InfoFilterOptionsRequest_t filteroptions_request;
+    InfoFilterOptionsResponse_t filteroptions;
+    comerror_t err;
+    rproto->get_filterinfo (arg_c, filterinfo, err, logout);
+    if (err == noError) {
+      text_tset::iterator filternames_here = filterinfo.filterNames.begin();
+      text_tset::iterator filternames_end = filterinfo.filterNames.end();
+      while (filternames_here != filternames_end) {
+	textout << outconvert 
+		<< "<hr>\n"
+		<< "<h3>Filter options for \"" << (*filternames_here) << "\"</h3>\n"
+		<< "<table>\n"
+		<< "<tr><th>option name</th><th>type</th><th>repeatable</th>"
+		<< "<th>default value</th><th>valid values</th></tr>\n";
+
+	filteroptions_request.clear();
+	filteroptions_request.filterName = *filternames_here;
+	rproto->get_filteroptions (arg_c, filteroptions_request,
+				   filteroptions, err, logout);
+	if (err == noError) {
+	  FilterOption_tmap::iterator filteropt_here = 
+	    filteroptions.filterOptions.begin();
+	  FilterOption_tmap::iterator filteropt_end = 
+	    filteroptions.filterOptions.end();
+	  while (filteropt_here != filteropt_end) {
+	    textout << outconvert
+		    << "<tr><td>\""
+		    << (*filteropt_here).second.name
+		    << "\"</td>\n"
+	      
+		    << "<td>";
+	    text_t type_string;
+	    switch ((*filteropt_here).second.type) {
+	    case FilterOption_t::booleant: type_string = "boolean"; break;
+	    case FilterOption_t::integert: type_string = "integer"; break;
+	    case FilterOption_t::enumeratedt: type_string = "enumerated"; break;
+	    case FilterOption_t::stringt: type_string = "string"; break;
+	    }
+	    textout << outconvert
+		    << type_string
+		    << "</td>\n"
+	      
+		    << "<td>";
+	    text_t repeat_string;
+	    switch ((*filteropt_here).second.repeatable) {
+	    case FilterOption_t::onePerQuery: repeat_string = "one per query"; break;
+	    case FilterOption_t::onePerTerm: repeat_string = "one per term"; break;
+	    case FilterOption_t::nPerTerm: repeat_string = "n per term"; break;
+	    }
+	    textout << outconvert
+		    << repeat_string
+		    << "</td>\n"
+	      
+		    << "<td>\""
+		    << (*filteropt_here).second.defaultValue
+		    << "\"</td>\n"
+	      
+		    << "<td>";
+	    
+	    text_tarray::iterator valid_here = 
+	      (*filteropt_here).second.validValues.begin();
+	    text_tarray::iterator valid_end = 
+	      (*filteropt_here).second.validValues.end();
+	    bool valid_first = true;
+	    while (valid_here != valid_end) {
+	      if (!valid_first) textout << outconvert << ", ";
+	      valid_first = false;
+	      textout << outconvert << "\"" << *valid_here << "\"";
+	      valid_here++;
+	    }
+	    textout << outconvert
+		    << "</td></tr>\n";
+
+	    filteropt_here++;
+	  }
+
+	  textout << outconvert
+		  << "</table>\n";
+
+	} else {
+	  textout << outconvert << "Error (" << get_comerror_string (err) 
+		  << ") while getting filter option information\n";
+	}
+
+	filternames_here++;
+      }
+
+    } else {
+      textout << outconvert << "Error (" << get_comerror_string (err) 
+	      << ") while getting filter information\n";
+    }
+  }
+  
+  textout << outconvert << disp << "_status:infofooter_\n";
+}
+
+void statusaction::output_initlog (cgiargsclass &/*args*/, displayclass &disp,
+				   outconvertclass &outconvert, 
+				   ostream &textout, ostream &/*logout*/) {
+  if (recpt == NULL) return;
+  const recptconf &rcinfo = recpt->get_configinfo ();
+  text_t initfilename = filename_cat (rcinfo.gsdlhome, "etc", "initout.txt");
+  char *cinitfilename = initfilename.getcstr();
+  if (cinitfilename == NULL) return;
+
+  textout << outconvert << disp << "_status:infoheader_(Init log)\n";
+  textout << outconvert << "<h2>Init log</h2>\n";
+
+#ifdef GSDL_USE_IOS_H
+  ifstream initin (cinitfilename, ios::in | ios::nocreate);
+#else
+  ifstream initin (cinitfilename, ios::in);
+#endif
+
+  delete cinitfilename;
+  if (initin) {
+    textout << outconvert << "<p>The initialisation error log, "
+		<< initfilename << ", contains the\n";
+    textout << outconvert << "following information:\n\n";
+    text_t errorpage = "<p><pre>\n";
+    
+    char c;
+    initin.get(c);
+    while (!initin.eof ()) {
+      errorpage.push_back(c);
+      initin.get(c);
+    }
+    
+    errorpage += "</pre>\n";
+    initin.close();
+    textout << outconvert << errorpage;
+    
+  } else {
+    textout << outconvert << "Couldn't read initialisation error log, " 
+		<< initfilename << ".\n";
+  }
+
+  textout << outconvert << disp << "_status:infofooter_\n";
+}
+
+void statusaction::output_errorlog (cgiargsclass &/*args*/, displayclass &disp, 
+				    outconvertclass &outconvert, 
+				    ostream &textout, ostream &logout) {
+  if (recpt == NULL) return;
+  const recptconf &rcinfo = recpt->get_configinfo ();
+  text_t errfilename = filename_cat (rcinfo.gsdlhome, "etc", "errout.txt");
+  char *cerrfilename = errfilename.getcstr();
+  if (cerrfilename == NULL) return;
+
+  textout << outconvert << disp << "_status:infoheader_(Error log)\n";
+  textout << outconvert << "<h2>Error log</h2>\n";
+  logout << flush;
+
+#ifdef GSDL_USE_IOS_H
+  ifstream errin (cerrfilename, ios::in | ios::nocreate);
+#else
+  ifstream errin (cerrfilename, ios::in);
+#endif
+
+  delete cerrfilename;
+  if (errin) {
+    textout << outconvert << "<p>The error log, "
+		<< errfilename << ", contains the\n";
+    textout << outconvert << "following information:\n\n";
+    text_t errorpage = "<p><pre>\n";
+
+    char c;
+    errin.get(c);
+    while (!errin.eof ()) {
+      errorpage.push_back(c);
+      errin.get(c);
+    }
+    
+    errorpage += "</pre>\n";
+    errin.close();
+    textout << outconvert << errorpage;
+
+  } else {
+    textout << outconvert << "Couldn't read error log, " 
+		<< errfilename << ".\n";
+  }
+
+  textout << outconvert << disp << "_status:infofooter_\n";
+}
+
+void statusaction::output_errorpage (outconvertclass &outconvert, 
+				     ostream &textout, ostream &/*logout*/,
+				     text_t message) {
+  textout << outconvert 
+	  << "<html>\n"
+	  << "<head>\n"
+	  << "<title>Error</title>\n"
+	  << "</head>\n"
+	  << "<body bgcolor=\"#ffffff\" text=\"#000000\" link=\"#006666\" "
+	  << "alink=\"#cc9900\" vlink=\"#666633\">\n"
+	  << "<h2>Oops!</h2>\n" 
+	  << message
+	  << "\n</body>\n"
+	  << "</html>\n";
+  return;
+}
+
+
+
+statusaction::statusaction () {
+  disabled = true;
+  recpt = NULL;
+
+  // this action uses cgi variable "a"
+  cgiarginfo arg_ainfo;
+  arg_ainfo.shortname = "a";
+  arg_ainfo.longname = "action";
+  arg_ainfo.multiplechar = true;
+  arg_ainfo.defaultstatus = cgiarginfo::weak;
+  arg_ainfo.argdefault = "status";
+  arg_ainfo.savedarginfo = cgiarginfo::must;
+  argsinfo.addarginfo (NULL, arg_ainfo);
+
+  // "sp" -- status page
+  arg_ainfo.shortname = "sp";
+  arg_ainfo.longname = "status page";
+  arg_ainfo.multiplechar = true;
+  arg_ainfo.defaultstatus = cgiarginfo::good;
+  arg_ainfo.argdefault = "frameset";
+  arg_ainfo.savedarginfo = cgiarginfo::can;
+  argsinfo.addarginfo (NULL, arg_ainfo);
+
+  // "pr" -- protocol
+  arg_ainfo.shortname = "pr";
+  arg_ainfo.longname = "protocol";
+  arg_ainfo.multiplechar = true;
+  arg_ainfo.defaultstatus = cgiarginfo::none;
+  arg_ainfo.argdefault = "";
+  arg_ainfo.savedarginfo = cgiarginfo::can;
+  argsinfo.addarginfo (NULL, arg_ainfo);
+}
+
+statusaction::~statusaction () {
+}
+
+bool statusaction::check_cgiargs (cgiargsinfoclass &/*argsinfo*/, cgiargsclass &/*args*/, 
+				  ostream &/*logout*/) {
+  return true;
+}
+
+void statusaction::get_cgihead_info (cgiargsclass &/*args*/, recptprotolistclass * /*protos*/,
+				     response_t &response, text_t &response_data, 
+				     ostream &/*logout*/) {
+  response = content;
+  response_data = "text/html";
+}
+
+bool statusaction::do_action (cgiargsclass &args, recptprotolistclass *protos, 
+			      browsermapclass * /*browsers*/, displayclass &disp, 
+			      outconvertclass &outconvert, ostream &textout, 
+			      ostream &logout) {
+  // make sure the status function is enabled
+  if (disabled) {
+    output_errorpage (outconvert, textout, logout, 
+		      "The status action is disabled. "
+		      "See the documentation (what documentation!) on how "
+		      "to enable it.");
+    return true;
+  }
+  
+  // make sure we know about a receptionist
+  if (recpt == NULL) {
+    output_errorpage (outconvert, textout, logout, 
+		      "The status action does not contain information\n"
+		      "about any receptionists. The method set_receptionist\n"
+		      "was probably not called from the module which instantiated\n"
+		      "this status action.\n");
+    return true;
+  }
+
+  // check to make sure status.dm was read in
+  const recptconf &rcinfo = recpt->get_configinfo ();
+  text_tset::const_iterator macrohere = rcinfo.macrofiles.begin ();
+  text_tset::const_iterator macroend = rcinfo.macrofiles.end ();
+  while (macrohere != macroend) {
+    if (*macrohere == "status.dm") break;
+    macrohere++;
+  }
+  if (macrohere == macroend) {
+    output_errorpage (outconvert, textout, logout, 
+		      "The status.dm file was not read in. This macro file is\n" 
+		      "needed to display configuration and status information.\n");
+    return true;
+  }
+
+  // output the required status page
+  text_t &arg_sp = args["sp"];
+  if (arg_sp == "frameset") output_frameset (args, disp, outconvert, textout, logout);
+  else if (arg_sp == "select") output_select (args, disp, outconvert, textout, logout);
+  else if (arg_sp == "welcome") output_welcome (args, protos, disp, outconvert, textout, logout);
+  else if (arg_sp == "generalinfo") output_generalinfo (args, disp, outconvert, textout, logout);
+  else if (arg_sp == "argumentinfo") output_argumentinfo (args, disp, outconvert, textout, logout);
+  else if (arg_sp == "actioninfo") output_actioninfo (args, disp, outconvert, textout, logout);
+  else if (arg_sp == "browserinfo") output_browserinfo (args, disp, outconvert, textout, logout);
+  else if (arg_sp == "protocolinfo") output_protocolinfo (args, disp, outconvert, textout, logout);
+  else if (arg_sp == "collectioninfo") output_collectioninfo (args, disp, outconvert, textout, logout);
+  else if (arg_sp == "initlog") output_initlog (args, disp, outconvert, textout, logout);
+  else if (arg_sp == "errorlog") output_errorlog (args, disp, outconvert, textout, logout);
+  else {
+    output_errorpage (outconvert, textout, logout, 
+		      "Unknown page \"" + arg_sp + "\".\n");
+  }
+
+  return true;
+}
+
+void statusaction::configure (const text_t &key, const text_tarray &cfgline) {
+  if ((key == "status") && (cfgline.size() == 1) && 
+      (cfgline[0] == "true" || cfgline[0] == "on" || cfgline[0] == "enabled")) {
+    disabled = false;
+  } else {
+    // call the parent class to deal with the things which
+    // are not dealt with here
+    action::configure (key, cfgline);
+  }
+}
Index: /main/tags/2.25/gsdl/src/recpt/statusaction.h
===================================================================
--- /main/tags/2.25/gsdl/src/recpt/statusaction.h	(revision 21064)
+++ /main/tags/2.25/gsdl/src/recpt/statusaction.h	(revision 21064)
@@ -0,0 +1,113 @@
+/**********************************************************************
+ *
+ * statusaction.h -- 
+ * Copyright (C) 1999  The New Zealand Digital Library Project
+ *
+ * A component of the Greenstone digital library software
+ * from the New Zealand Digital Library Project at the
+ * University of Waikato, New Zealand.
+ *
+ * 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.
+ *
+ *********************************************************************/
+
+
+#ifndef STATUSACTION_H
+#define STATUSACTION_H
+
+
+#include "gsdlconf.h"
+#include "action.h"
+#include "receptionist.h"
+
+
+class statusaction : public action {
+protected:
+  bool disabled;
+  receptionist *recpt;
+
+  void output_frameset (cgiargsclass &args, displayclass &disp, 
+			outconvertclass &outconvert, 
+			ostream &textout, ostream &logout);
+
+  void output_select (cgiargsclass &args, displayclass &disp, 
+		      outconvertclass &outconvert, 
+		      ostream &textout, ostream &logout);
+
+  void output_welcome (cgiargsclass &args, recptprotolistclass *protos,
+		       displayclass &disp, outconvertclass &outconvert, 
+		       ostream &textout, ostream &logout);
+
+  void output_generalinfo (cgiargsclass &args, displayclass &disp, 
+			   outconvertclass &outconvert, 
+			   ostream &textout, ostream &logout);
+
+  void output_argumentinfo (cgiargsclass &args, displayclass &disp, 
+			    outconvertclass &outconvert, 
+			    ostream &textout, ostream &logout);
+
+  void output_actioninfo (cgiargsclass &args, displayclass &disp, 
+			  outconvertclass &outconvert, 
+			  ostream &textout, ostream &logout);
+
+  void output_browserinfo (cgiargsclass &args, displayclass &disp, 
+			   outconvertclass &outconvert, 
+			   ostream &textout, ostream &logout);
+
+  void output_protocolinfo (cgiargsclass &args, displayclass &disp, 
+			    outconvertclass &outconvert, 
+			    ostream &textout, ostream &logout);
+
+  void output_collectioninfo (cgiargsclass &args, displayclass &disp, 
+			      outconvertclass &outconvert, 
+			      ostream &textout, ostream &logout);
+
+  void output_initlog (cgiargsclass &args, displayclass &disp, 
+		       outconvertclass &outconvert, 
+		       ostream &textout, ostream &logout);
+
+  void output_errorlog (cgiargsclass &args, displayclass &disp, 
+			outconvertclass &outconvert, 
+			ostream &textout, ostream &logout);
+
+  void output_errorpage (outconvertclass &outconvert, 
+			 ostream &textout, ostream &logout,
+			 text_t message);
+
+public:
+  statusaction ();
+  virtual ~statusaction ();
+
+  text_t get_action_name () {return "status";}
+
+  void set_receptionist (receptionist *therecpt) {recpt=therecpt;}
+
+  bool check_cgiargs (cgiargsinfoclass &argsinfo, cgiargsclass &args, 
+		      ostream &logout);
+
+  void get_cgihead_info (cgiargsclass &args, recptprotolistclass *protos,
+			 response_t &response, text_t &response_data, 
+			 ostream &logout);
+
+  bool do_action (cgiargsclass &args, recptprotolistclass *protos, 
+		  browsermapclass *browsers, displayclass &disp, 
+		  outconvertclass &outconvert, ostream &textout, 
+		  ostream &logout);
+
+  void configure (const text_t &key, const text_tarray &cfgline);
+};
+
+
+#endif
Index: /main/tags/2.25/gsdl/src/recpt/tipaction.cpp
===================================================================
--- /main/tags/2.25/gsdl/src/recpt/tipaction.cpp	(revision 21064)
+++ /main/tags/2.25/gsdl/src/recpt/tipaction.cpp	(revision 21064)
@@ -0,0 +1,66 @@
+/**********************************************************************
+ *
+ * tipaction.cpp -- define random tip macros
+ * Copyright (C) 1999  DigiLib Systems Limited, New Zealand
+ *
+ * A component of the Greenstone digital library software
+ * from the New Zealand Digital Library Project at the
+ * University of Waikato, New Zealand.
+ *
+ * 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.
+ *
+ *********************************************************************/
+
+#include "tipaction.h"
+#include <stdlib.h>
+
+
+tipaction::tipaction () {
+  // "st" show tips - "0"=no, "1"=yes
+  cgiarginfo arg_ainfo;
+  arg_ainfo.shortname = "st";
+  arg_ainfo.longname = "show tips";
+  arg_ainfo.multiplechar = true;
+  arg_ainfo.defaultstatus = cgiarginfo::weak;
+  arg_ainfo.argdefault = "1";
+  arg_ainfo.savedarginfo = cgiarginfo::must;
+  argsinfo.addarginfo (NULL, arg_ainfo);
+}
+
+void tipaction::define_external_macros (displayclass &disp, cgiargsclass &args, 
+					recptprotolistclass * /*protos*/, ostream &logout) {
+
+  // define_external_macros sets the following macros:
+
+  // _tip:thistip_  - a random tip (defined if st == "1")
+
+  if (args["st"].getint()) {
+    // get the maximum tip number (_tip:tipmax_)
+    text_t tipmax_str;
+    disp.expandstring ("tip", "_tipmax_", tipmax_str);
+    if (tipmax_str.empty()) {
+      logout << "Warning: _tip:tipmax_ not set. This macro is needed for displaying tips.\n";
+      return;
+    }
+    
+    int tipmax = tipmax_str.getint();
+    if (tipmax < 1) {
+      logout << "Warning: _tip:tipmax_ was less than 1. No tips were set.\n";
+      return;
+    }
+    
+    disp.setmacro("thistip", "tip", "_tip" + text_t((rand()%tipmax) + 1) + "_");
+  }
+}
Index: /main/tags/2.25/gsdl/src/recpt/tipaction.h
===================================================================
--- /main/tags/2.25/gsdl/src/recpt/tipaction.h	(revision 21064)
+++ /main/tags/2.25/gsdl/src/recpt/tipaction.h	(revision 21064)
@@ -0,0 +1,46 @@
+/**********************************************************************
+ *
+ * tipaction.h -- define tip macros
+ * Copyright (C) 1999  DigiLib Systems Limited, New Zealand
+ *
+ * A component of the Greenstone digital library software
+ * from the New Zealand Digital Library Project at the
+ * University of Waikato, New Zealand.
+ *
+ * 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.
+ *
+ *********************************************************************/
+
+
+#ifndef TIPACTION_H
+#define TIPACTION_H
+
+#include "gsdlconf.h"
+#include "action.h"
+
+
+// tipaction exists just for the benefit of defining external macros
+class tipaction : public action {
+public:
+  tipaction ();
+  virtual ~tipaction () {}
+  text_t get_action_name () {return "tip";}
+  
+  void define_external_macros (displayclass &disp, cgiargsclass &args, 
+			       recptprotolistclass *protos, ostream &logout);
+};
+
+
+#endif
Index: /main/tags/2.25/gsdl/src/recpt/userdb.cpp
===================================================================
--- /main/tags/2.25/gsdl/src/recpt/userdb.cpp	(revision 21064)
+++ /main/tags/2.25/gsdl/src/recpt/userdb.cpp	(revision 21064)
@@ -0,0 +1,362 @@
+/**********************************************************************
+ *
+ * userdb.cpp -- functions to handle a user database
+ * Copyright (C) 1999  DigiLib Systems Limited, New Zealand
+ *
+ * A component of the Greenstone digital library software
+ * from the New Zealand Digital Library Project at the
+ * University of Waikato, New Zealand.
+ *
+ * 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.
+ *
+ *********************************************************************/
+
+#include "gsdlconf.h"
+#include "userdb.h"
+#include "gsdltimes.h"
+#include "fileutil.h"
+#include <stdlib.h>
+
+// include crypt
+#if defined(__WIN32__)
+#include "crypt.h"
+#else
+#if defined(HAVE_CRYPT_H)
+#include <crypt.h>
+#else 
+#include <unistd.h>
+#endif
+#endif
+
+
+// few useful functions
+
+text_t crypt_text (const text_t &text) {
+  static const char *salt = "Tp";
+  text_t crypt_password;
+
+  if (text.empty()) return "";
+
+  // encrypt the password
+  char *text_cstr = text.getcstr();
+  if (text_cstr == NULL) return "";
+  crypt_password = crypt(text_cstr, salt);
+  delete text_cstr;
+
+  return crypt_password;
+}
+
+
+// username_ok tests to make sure a username is ok. a username
+// must be at least 2 characters long, but no longer than 30
+// characters long. it can contain the characters a-z A-Z 0-9
+// . and _
+bool username_ok (const text_t &username) {
+  if (username.size() < 2 || username.size() > 30) return false;
+
+  text_t::const_iterator here = username.begin();
+  text_t::const_iterator end = username.end();
+  while (here != end) {
+    if ((*here >= 'a' && *here <= 'z') ||
+	(*here >= 'A' && *here <= 'Z') ||
+	(*here >= '0' && *here <= '9') ||
+	*here == '.' ||
+	*here == '_') {
+      // ok
+    } else return false;
+    here++;
+  }
+
+  return true;
+}
+
+// password_ok tests to make sure a password is ok. a password
+// must be at least 3 characters long but no longer than 8 characters
+// long. it can contain any character in the range 0x20-0x7e
+bool password_ok (const text_t &password) {
+  if (password.size() < 3 || password.size() > 8) return false;
+
+  text_t::const_iterator here = password.begin();
+  text_t::const_iterator end = password.end();
+  while (here != end) {
+    if (*here >= 0x20 && *here <= 0x7e) {
+      // ok
+    } else return false;
+    here++;
+  }
+
+  return true;
+}
+
+
+
+
+/////////////
+// userinfo_t
+/////////////
+
+void userinfo_t::clear () {
+  username.clear();
+  password.clear();
+  enabled = false;
+  groups.clear();
+  comment.clear();
+}
+
+userinfo_t &userinfo_t::operator=(const userinfo_t &x) {
+  username = x.username;
+  password = x.password;
+  enabled = x.enabled;
+  groups = x.groups;
+  comment = x.comment;
+  
+  return *this;
+}
+
+
+
+// functions dealing with user databases
+
+// returns true on success (in which case userinfo will contain
+// the information for this user)
+bool get_user_info (gdbmclass &userdb, const text_t &username,
+		    userinfo_t &userinfo) {
+  userinfo.clear();
+  
+  infodbclass info;
+  if (userdb.getinfo (username, info)) {
+    userinfo.username = info["username"];
+    userinfo.password = info["password"];
+    userinfo.enabled = (info["enabled"] == "true");
+    userinfo.groups = info["groups"];
+    userinfo.comment = info["comment"];
+    return true;
+  }
+
+  return false;
+}
+
+bool get_user_info (const text_t &userdbfile, const text_t &username,
+		    userinfo_t &userinfo) {
+  gdbmclass userdb;
+  if (!userdb.opendatabase(userdbfile, GDBM_READER, 1000, true)) {
+/*    if (!userdbfile.empty() && !file_exists (userdbfile) &&
+	username == "admin") {*/
+    if (!userdbfile.empty() && username == "admin") {
+      // no database -- create a database with an initial account
+      userinfo.clear();
+      userinfo.username = "admin";
+      userinfo.password = crypt_text("admin");
+      userinfo.enabled = true;
+      userinfo.groups = "administrator,colbuilder";
+      userinfo.comment = "change the password for this account as soon as possible";
+      return set_user_info (userdbfile, username, userinfo);
+    }
+    return false;
+  }
+
+  bool success = get_user_info (userdb, username, userinfo);
+  userdb.closedatabase();
+
+  return success;
+}
+
+// returns true on success
+bool set_user_info (gdbmclass &userdb, const text_t &username,
+		    const userinfo_t &userinfo) {
+  infodbclass info;
+  info["username"] = userinfo.username;
+  info["password"] = userinfo.password;
+  info["enabled"] = userinfo.enabled ? "true" : "false";
+  info["groups"] = userinfo.groups;
+  info["comment"] = userinfo.comment;
+
+  return userdb.setinfo (username, info);
+}
+
+bool set_user_info (const text_t &userdbfile, const text_t &username,
+		    const userinfo_t &userinfo) {
+  gdbmclass userdb;
+  if (!userdb.opendatabase(userdbfile, GDBM_WRCREAT, 1000, true)) return false;
+
+  bool success = set_user_info (userdb, username, userinfo);
+  userdb.closedatabase();
+
+  return success;
+}
+
+// removes a user from the user database -- forever
+void delete_user (gdbmclass &userdb, const text_t &username) {
+  userdb.deletekey (username);
+}
+
+void delete_user (const text_t &userdbfile, const text_t &username) {
+  gdbmclass userdb;
+  if (!userdb.opendatabase(userdbfile, GDBM_WRCREAT, 1000, true)) return;
+
+  delete_user (userdb, username);
+  userdb.closedatabase();
+}
+
+// gets a list of all the users in the database. returns true
+// on success
+void get_user_list (gdbmclass &userdb, text_tarray &userlist) {
+  userlist.erase (userlist.begin(), userlist.end());
+  
+  text_t user = userdb.getfirstkey ();
+  while (!user.empty()) {
+    userlist.push_back(user);
+    user = userdb.getnextkey (user);
+  }
+}
+
+// returns true if the user's password is correct.
+bool check_passwd (const userinfo_t &thisuser, const text_t &password) {
+  // couple of basic checks
+  if (thisuser.username.empty() || thisuser.password.empty() ||
+      password.empty()) return false;
+
+  text_t crypt_password = crypt_text(password);
+  return (thisuser.password == crypt_password);
+}
+
+
+// functions dealing with databases of temporary keys
+
+// generates a random key for the user, stores it in the database and
+// returns it so that it can be used in page generation
+// returns "" on failure
+text_t generate_key (gdbmclass &keydb, const text_t &username) {
+  static const char *numconvert = "0123456789abcdefghijklmnopqrstuvwxyz"
+    "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
+
+  // loop looking for a suitable new key
+  text_t userkey;
+  text_t crypt_userkey;
+  do {
+    // convert to base 62 :-)
+    int userkey_int = rand ();
+    while (userkey_int > 0) {
+      userkey.push_back (numconvert[userkey_int%62]);
+      userkey_int /= 62;
+    }
+
+    // make sure this key is not in the database
+    crypt_userkey = crypt_text(userkey);
+    if (keydb.exists (crypt_userkey)) userkey.clear();
+  } while (userkey.empty());
+
+  // enter the key into the database
+  infodbclass keydata;
+  keydata["user"] = username;
+  keydata["time"] = time2text(time(NULL));
+  
+  if (!keydb.setinfo (crypt_userkey, keydata)) {
+    userkey.clear(); // failed
+  }
+  
+  return userkey;
+}
+
+text_t generate_key (const text_t &keydbfile, const text_t &username) {
+  gdbmclass keydb;
+  if (!keydb.opendatabase(keydbfile, GDBM_WRCREAT, 1000, true)) return "";
+
+  text_t key = generate_key (keydb, username);
+  keydb.closedatabase();
+
+  return key;
+}
+
+
+// checks to see if there is a key for this particular user in the
+// database that hasn't decayed. a short decay is used when group
+// is set to administrator
+bool check_key (gdbmclass &keydb, const userinfo_t &thisuser,
+		const text_t &key, const text_t &group, int keydecay) {
+  if (thisuser.username.empty() || key.empty()) return false;
+
+  // the keydecay is set to 5 minute for things requiring the
+  // administrator
+  if (group == "administrator") keydecay = 300;
+  
+  // success if there is a key in the key database that is owned by this
+  // user whose creation time is less that keydecay
+  text_t crypt_key = crypt_text(key);
+  infodbclass info;
+  if (keydb.getinfo (crypt_key, info))  {
+    if (info["user"] == thisuser.username) {
+      time_t keycreation = text2time (info["time"]);
+      if (keycreation != (time_t)-1 && difftime (text2time(time2text(time(NULL))),
+						 keycreation) <= keydecay) {
+	// succeeded, update the key's time
+	info["time"] = time2text(time(NULL));
+	keydb.setinfo (crypt_key, info);
+	return true;
+      }
+    }
+  }
+  
+  return false;;
+}
+
+bool check_key (const text_t &keydbfile, const userinfo_t &thisuser,
+		const text_t &key, const text_t &group, int keydecay) {
+  gdbmclass keydb;
+  if (!keydb.opendatabase(keydbfile, GDBM_WRCREAT, 1000, true)) return false;
+
+  bool success = check_key (keydb, thisuser, key, group, keydecay);
+  keydb.closedatabase();
+
+  return success;
+}
+
+
+// remove_old_keys will remove all keys created more than keydecay ago.
+// use sparingly, it can be quite an expensive function
+void remove_old_keys (const text_t &keydbfile, int keydecay) {
+  // open the key database
+  gdbmclass keydb;
+  if (!keydb.opendatabase(keydbfile, GDBM_WRCREAT, 1000, true)) return;
+
+  // get a list of keys created more than keydecay seconds agon
+  text_tarray oldkeys;
+  text_t key = keydb.getfirstkey ();
+  infodbclass info;
+  time_t timenow = text2time(time2text(time(NULL)));
+  time_t keycreation = (time_t)-1;
+  while (!key.empty()) {
+    if (keydb.getinfo (key, info))  {
+      keycreation = text2time (info["time"]);
+      if (keycreation != (time_t)-1 && difftime (timenow, keycreation) > keydecay) {
+	// found an old key
+	oldkeys.push_back(key);
+      }
+    }
+    
+    key = keydb.getnextkey (key);
+  }
+
+  // delete the keys
+  text_tarray::iterator keys_here = oldkeys.begin();
+  text_tarray::iterator keys_end = oldkeys.end();
+  while (keys_here != keys_end) {
+    keydb.deletekey(*keys_here);
+    keys_here++;
+  }
+  
+  // close the key database
+  keydb.closedatabase();
+}
Index: /main/tags/2.25/gsdl/src/recpt/userdb.h
===================================================================
--- /main/tags/2.25/gsdl/src/recpt/userdb.h	(revision 21064)
+++ /main/tags/2.25/gsdl/src/recpt/userdb.h	(revision 21064)
@@ -0,0 +1,125 @@
+/**********************************************************************
+ *
+ * userdb.h -- functions to handle a user database
+ * Copyright (C) 1999  DigiLib Systems Limited, New Zealand
+ *
+ * A component of the Greenstone digital library software
+ * from the New Zealand Digital Library Project at the
+ * University of Waikato, New Zealand.
+ *
+ * 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.
+ *
+ *********************************************************************/
+
+
+#ifndef USERDB_H
+#define USERDB_H
+
+#include "infodbclass.h"
+
+
+// the password line in the userinfo_t must be encrypted using
+// this function
+text_t crypt_text (const text_t &text);
+
+// username_ok tests to make sure a username is ok. a username
+// must be at least 2 characters long, but no longer than 30
+// characters long. it can contain the characters a-z A-Z 0-9
+// . and _
+bool username_ok (const text_t &username);
+
+// password_ok tests to make sure a password is ok. a password
+// must be at least 3 characters long but no longer than 8 characters
+// long. it can contain any character in the range 0x20-0x7e
+bool password_ok (const text_t &password);
+
+
+// information about a single user
+struct userinfo_t {
+  void clear ();
+  userinfo_t () {clear();}
+  userinfo_t &operator=(const userinfo_t &x);
+  
+  text_t username;
+  text_t password;
+  bool enabled;
+  text_t groups; // comma separated list
+  text_t comment;
+};
+
+
+// these functions deal with user and key databases that are already open
+// they should have been opened with gdbmclass::opendatabase
+// as soon as the databases are finished with they should be closed with
+// gdbmclass::closedatabase so that another process can access the database
+//
+// some of the functions need the databases opened with write access, an
+// appropriate call would be something like:
+//
+//   success = keydb.opendatabase (keyfile, GDBM_WRCREAT, 1000);
+//
+// note: passwords and keys are encrypted, so you can't just compare passwords
+// in a userinfo_t with a password given by the user. use check_passwd
+
+
+// functions dealing with user databases
+
+// returns true on success (in which case userinfo will contain
+// the information for this user)
+bool get_user_info (gdbmclass &userdb, const text_t &username,
+		    userinfo_t &userinfo);
+bool get_user_info (const text_t &userdbfile, const text_t &username,
+		    userinfo_t &userinfo);
+
+// returns true on success
+bool set_user_info (gdbmclass &userdb, const text_t &username,
+		    const userinfo_t &userinfo);
+bool set_user_info (const text_t &userdbfile, const text_t &username,
+		    const userinfo_t &userinfo);
+
+// removes a user from the user database -- forever
+void delete_user (gdbmclass &userdb, const text_t &username);
+void delete_user (const text_t &userdbfile, const text_t &username);
+
+// gets a list of all the users in the database. returns true
+// on success
+void get_user_list (gdbmclass &userdb, text_tarray &userlist);
+
+// returns true if the user's password is correct.
+bool check_passwd (const userinfo_t &thisuser, const text_t &password);
+
+
+// functions dealing with databases of temporary keys
+
+// generates a random key for the user, stores it in the database and
+// returns it so that it can be used in page generation
+// returns "" on failure
+text_t generate_key (gdbmclass &keydb, const text_t &username);
+text_t generate_key (const text_t &keydbfile, const text_t &username);
+
+// checks to see if there is a key for this particular user in the
+// database that hasn't decayed. a short decay is used when group
+// is set to administrator
+bool check_key (gdbmclass &keydb, const userinfo_t &thisuser,
+		const text_t &key, const text_t &group, int keydecay);
+bool check_key (const text_t &keydbfile, const userinfo_t &thisuser,
+		const text_t &key, const text_t &group, int keydecay);
+
+// remove_old_keys will remove all keys created more than keydecay ago.
+// use sparingly, it can be quite an expensive function
+void remove_old_keys (const text_t &keydbfile, int keydecay);
+
+
+#endif
Index: /main/tags/2.25/gsdl/src/recpt/usersaction.cpp
===================================================================
--- /main/tags/2.25/gsdl/src/recpt/usersaction.cpp	(revision 21064)
+++ /main/tags/2.25/gsdl/src/recpt/usersaction.cpp	(revision 21064)
@@ -0,0 +1,413 @@
+/**********************************************************************
+ *
+ * usersaction.cpp -- managing users
+ * Copyright (C) 1999  DigiLib Systems Limited, New Zealand
+ *
+ * A component of the Greenstone digital library software
+ * from the New Zealand Digital Library Project at the
+ * University of Waikato, New Zealand.
+ *
+ * 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.
+ *
+ *********************************************************************/
+
+#include "usersaction.h"
+#include "fileutil.h"
+#include "userdb.h"
+
+
+///////////////
+// usersaction
+///////////////
+
+usersaction::usersaction () {
+  // this action uses cgi variable "a"
+  cgiarginfo arg_ainfo;
+  arg_ainfo.shortname = "a";
+  arg_ainfo.longname = "action";
+  arg_ainfo.multiplechar = true;
+  arg_ainfo.defaultstatus = cgiarginfo::weak;
+  arg_ainfo.argdefault = "um"; // user management
+  arg_ainfo.savedarginfo = cgiarginfo::must;
+  argsinfo.addarginfo (NULL, arg_ainfo);
+
+  // "uma"
+  arg_ainfo.shortname = "uma";
+  arg_ainfo.longname = "user management action";
+  arg_ainfo.multiplechar = true;
+  arg_ainfo.defaultstatus = cgiarginfo::weak;
+  arg_ainfo.argdefault = "listusers";
+  arg_ainfo.savedarginfo = cgiarginfo::mustnot;
+  argsinfo.addarginfo (NULL, arg_ainfo);
+
+  // "umun"
+  arg_ainfo.shortname = "umun";
+  arg_ainfo.longname = "user management user name";
+  arg_ainfo.multiplechar = true;
+  arg_ainfo.defaultstatus = cgiarginfo::weak;
+  arg_ainfo.argdefault = "";
+  arg_ainfo.savedarginfo = cgiarginfo::mustnot;
+  argsinfo.addarginfo (NULL, arg_ainfo);
+
+  // "umpw"
+  arg_ainfo.shortname = "umpw";
+  arg_ainfo.longname = "user management password";
+  arg_ainfo.multiplechar = true;
+  arg_ainfo.defaultstatus = cgiarginfo::weak;
+  arg_ainfo.argdefault = "";
+  arg_ainfo.savedarginfo = cgiarginfo::mustnot;
+  argsinfo.addarginfo (NULL, arg_ainfo);
+
+  // "umnpw1"
+  arg_ainfo.shortname = "umnpw1";
+  arg_ainfo.longname = "user management new password 1";
+  arg_ainfo.multiplechar = true;
+  arg_ainfo.defaultstatus = cgiarginfo::weak;
+  arg_ainfo.argdefault = "";
+  arg_ainfo.savedarginfo = cgiarginfo::mustnot;
+  argsinfo.addarginfo (NULL, arg_ainfo);
+
+  // "umnpw2"
+  arg_ainfo.shortname = "umnpw2";
+  arg_ainfo.longname = "user management new password 2";
+  arg_ainfo.multiplechar = true;
+  arg_ainfo.defaultstatus = cgiarginfo::weak;
+  arg_ainfo.argdefault = "";
+  arg_ainfo.savedarginfo = cgiarginfo::mustnot;
+  argsinfo.addarginfo (NULL, arg_ainfo);
+
+  // "umus"
+  arg_ainfo.shortname = "umus";
+  arg_ainfo.longname = "user management account status";
+  arg_ainfo.multiplechar = true;
+  arg_ainfo.defaultstatus = cgiarginfo::weak;
+  arg_ainfo.argdefault = "";
+  arg_ainfo.savedarginfo = cgiarginfo::mustnot;
+  argsinfo.addarginfo (NULL, arg_ainfo);
+
+  // "umug"
+  arg_ainfo.shortname = "umug";
+  arg_ainfo.longname = "user management groups"; // comma seperated list
+  arg_ainfo.multiplechar = true;
+  arg_ainfo.defaultstatus = cgiarginfo::weak;
+  arg_ainfo.argdefault = "";
+  arg_ainfo.savedarginfo = cgiarginfo::mustnot;
+  argsinfo.addarginfo (NULL, arg_ainfo);
+
+  // "umc"
+  arg_ainfo.shortname = "umc";
+  arg_ainfo.longname = "user management comment";
+  arg_ainfo.multiplechar = true;
+  arg_ainfo.defaultstatus = cgiarginfo::weak;
+  arg_ainfo.argdefault = "";
+  arg_ainfo.savedarginfo = cgiarginfo::mustnot;
+  argsinfo.addarginfo (NULL, arg_ainfo);
+
+  // "bcp"
+  arg_ainfo.shortname = "bcp";
+  arg_ainfo.longname = "change password submit button";
+  arg_ainfo.multiplechar = true;
+  arg_ainfo.defaultstatus = cgiarginfo::weak;
+  arg_ainfo.argdefault = "";
+  arg_ainfo.savedarginfo = cgiarginfo::mustnot;
+  argsinfo.addarginfo (NULL, arg_ainfo);
+
+  // "beu"
+  arg_ainfo.shortname = "beu";
+  arg_ainfo.longname = "edit user submit button";
+  arg_ainfo.multiplechar = true;
+  arg_ainfo.defaultstatus = cgiarginfo::weak;
+  arg_ainfo.argdefault = "";
+  arg_ainfo.savedarginfo = cgiarginfo::mustnot;
+  argsinfo.addarginfo (NULL, arg_ainfo);
+
+  // "cm"
+  arg_ainfo.shortname = "cm";
+  arg_ainfo.longname = "confirm an action";
+  arg_ainfo.multiplechar = true;
+  arg_ainfo.defaultstatus = cgiarginfo::weak;
+  arg_ainfo.argdefault = "";
+  arg_ainfo.savedarginfo = cgiarginfo::mustnot;
+  argsinfo.addarginfo (NULL, arg_ainfo);
+}
+
+void usersaction::configure (const text_t &key, const text_tarray &cfgline) {
+  // get the password filename
+  if (cfgline.size() == 1) {
+    if (key == "usersfile") usersfile = cfgline[0];
+    else if (key == "gsdlhome") {
+      if (usersfile.empty())
+	usersfile = filename_cat (cfgline[0], "etc", "users.db");
+    }
+  }
+
+  action::configure (key, cfgline);
+}
+
+bool usersaction::check_cgiargs (cgiargsinfoclass &/*argsinfo*/, cgiargsclass &args, 
+				  ostream &/*logout*/) {
+  args["uan"] = "1"; // user authentication is needed
+
+  if (args["uma"] == "changepasswd") {
+    // no particular group is needed to change a password
+    args["ug"].clear(); 
+  } else {
+    // administrator is needed for all other management tasks
+    args["ug"] = "administrator";
+  }
+  
+  return true;
+}
+
+void usersaction::get_cgihead_info (cgiargsclass &/*args*/, recptprotolistclass * /*protos*/,
+				    response_t &response, text_t &response_data, 
+				    ostream &/*logout*/) {
+  response = content;
+  response_data = "text/html";
+}
+
+bool usersaction::do_action (cgiargsclass &args, recptprotolistclass * /*protos*/, 
+			     browsermapclass * /*browsers*/, displayclass &disp, 
+			     outconvertclass &outconvert, ostream &textout, 
+			     ostream &logout) {
+
+  if (args["uma"] == "adduser" || args["uma"] == "edituser") {
+    // adduser is handled by edituser
+    return do_edituser (args, disp, outconvert, textout, logout);
+    
+  } else if (args["uma"] == "deleteuser") {
+    return do_deleteuser (args, disp, outconvert, textout, logout);
+    
+  } else if (args["uma"] == "changepasswd") {
+    return do_changepasswd (args, disp, outconvert, textout, logout);  
+  }
+
+  // default
+  return do_listusers (args, disp, outconvert, textout, logout);
+}
+
+bool usersaction::do_listusers (cgiargsclass &/*args*/, displayclass &disp, 
+				outconvertclass &outconvert, ostream &textout, 
+				ostream &/*logout*/) {
+
+  textout << outconvert << disp
+	  << "_userslistusers:header_\n_userslistusers:contentstart_\n";
+
+
+  // open the user database (it will be used a lot)
+  gdbmclass userdb;
+  text_tarray userlist;
+  if (userdb.opendatabase(usersfile, GDBM_READER, 1000, true)) {
+    // get user list
+    get_user_list (userdb, userlist);
+  }
+
+  // sort the list
+  sort(userlist.begin(), userlist.end());
+  
+  // output the information for each user
+  userinfo_t userinfo;
+  text_tarray::iterator users_here = userlist.begin();
+  text_tarray::iterator users_end = userlist.end();
+  while (users_here != users_end) {
+    if (get_user_info (userdb, *users_here, userinfo)) {
+      textout << outconvert << disp
+	      << "<tr><td bgcolor=\"\\#eeeeee\">" << userinfo.username << "</td>\n"
+       	      << "<td bgcolor=\"\\#eeeeee\">" << (char *) (userinfo.enabled ? "enabled" : "disabled") << "</td>\n"
+	      << "<td bgcolor=\"\\#eeeeee\">" << userinfo.groups << "&nbsp;</td>\n"
+	      << "<td bgcolor=\"\\#eeeeee\">" << userinfo.comment << "&nbsp;</td>\n"
+	      << "<td><a href=\"_httpcurrentdocument_&a=um&uma=edituser&umun="
+	      << userinfo.username << "\">_userslistusers:textedituser_</a> "
+	      << "<a href=\"_httpcurrentdocument_&a=um&uma=deleteuser&umun="
+	      << userinfo.username << "\">_userslistusers:textdeleteuser_</a>"
+	      << "</td></tr>\n\n";
+
+    } else {
+      textout << outconvert << disp
+	      << "<tr><td bgcolor=\"\\#eeeeee\">" << *users_here << "</td>\n"
+	      << "<td bgcolor=\"\\#eeeeee\">&nbsp;</td>\n"
+	      << "<td bgcolor=\"\\#eeeeee\">&nbsp;</td>\n"
+	      << "<td bgcolor=\"\\#eeeeee\">&nbsp;</td>\n"
+	      << "<td>&nbsp;</td></tr>\n\n";
+    }
+    
+    users_here++;
+  }
+
+  userdb.closedatabase();
+  
+  textout << outconvert << disp
+	  << "_userslistusers:contentend_\n_userslistusers:footer_\n";
+  return true;
+}
+
+void usersaction::define_user_macros (cgiargsclass &args, displayclass &disp) {
+  disp.setmacro ("usersargun", "users", args["umun"]);
+  disp.setmacro ("usersargpw", "users", args["umpw"]);
+  disp.setmacro ("usersargus", "users", args["umus"]);
+  disp.setmacro ("usersargug", "users", args["umug"]);
+  disp.setmacro ("usersargc", "users", args["umc"]);
+}
+
+
+bool usersaction::do_edituser (cgiargsclass &args, displayclass &disp, 
+			       outconvertclass &outconvert, ostream &textout, 
+			       ostream &logout) {
+  userinfo_t userinfo;
+  text_t messagestatus;
+  bool noproblems = true;
+  
+  // fill in defaults from user database (if appropriate)
+  if (args["umun"].empty()) {
+    noproblems = false;
+    
+  } else if (!username_ok (args["umun"])) {
+    // problem with username
+    noproblems = false;
+    messagestatus += "_users:messageinvalidusername_";
+    
+  } else if (get_user_info (usersfile, args["umun"], userinfo)) {
+    if (args["uma"] == "adduser") {
+      // must not add a user that has the same name as another user
+      noproblems = false;
+      messagestatus += "_users:messageuserexists_";
+      
+    } else {
+      // only fill in the data if there is no user status defined
+      if (args["umus"].empty()) {
+	args["umus"] = userinfo.enabled ? "enabled" : "disabled";
+	if (args["umug"].empty()) args["umug"] = userinfo.groups;
+	if (args["umc"].empty()) args["umc"] = userinfo.comment;
+      }
+    }
+  }
+
+  // fill in the user status default
+  if (args["umus"].empty()) {
+    noproblems = false;
+    args["umus"] = "enabled";
+  }
+  
+  // make sure the password is ok
+  if (args["umpw"].empty()) {
+    // password must not be empty if none were supplied from database
+    // and we have had no other problems
+    if (userinfo.password.empty() && noproblems) {
+      noproblems = false;
+      messagestatus += "_users:messageemptypassword_";
+    }
+    
+  } else if (!password_ok(args["umpw"])) {
+    noproblems = false;
+    messagestatus += "_users:messageinvalidpassword_";
+  }
+
+  // set this info if no problems have been encounted
+  // and the submit button was pressed
+  if (noproblems && !args["beu"].empty()) {
+    userinfo.username = args["umun"];
+    if (!args["umpw"].empty()) {
+      // only set the password if it is not empty
+      userinfo.password = crypt_text(args["umpw"]);
+    }
+    userinfo.enabled = (args["umus"] == "enabled");
+    userinfo.groups = args["umug"];
+    userinfo.comment = args["umc"];
+    
+    set_user_info (usersfile, args["umun"], userinfo);
+    
+    // show list of users
+    return do_listusers (args, disp, outconvert, textout, logout);
+  }
+  
+  // define the macros for the user
+  define_user_macros (args, disp);
+  disp.setmacro ("messagestatus", "users", messagestatus);
+  
+  textout << outconvert << disp
+	  << "_usersedituser:header_\n_usersedituser:content_\n_usersedituser:footer_\n";
+
+  return true;
+}
+
+bool usersaction::do_deleteuser (cgiargsclass &args, displayclass &disp, 
+				 outconvertclass &outconvert, ostream &textout, 
+				 ostream &logout) {
+  if (!args["cm"].empty()) {
+    if (args["cm"] == "yes" && !args["umun"].empty()) {
+      // user confirmed the deletion of the user
+      delete_user (usersfile, args["umun"]);
+    }
+    
+    // redirect the user back to the listusers page
+    return do_listusers (args, disp, outconvert, textout, logout);
+  }
+
+  define_user_macros (args, disp);
+  textout << outconvert << disp
+	  << "_usersdeleteuser:header_\n_usersdeleteuser:content_\n_usersdeleteuser:footer_\n";
+  
+  return true;
+}
+
+bool usersaction::do_changepasswd (cgiargsclass &args, displayclass &disp, 
+				   outconvertclass &outconvert, ostream &textout, 
+				   ostream &/*logout*/) {
+  text_t messagestatus;
+  
+  if (!args["bcp"].empty()) {
+    if (args["un"].empty()) {
+      messagestatus = "_users:messageusernameempty_";
+    } else if (args["umpw"].empty()) {
+      messagestatus = "_users:messagepasswordempty_";
+    } else if (args["umnpw1"].empty()) {
+      messagestatus = "_users:messagenewpass1empty_";
+    } else if (args["umnpw2"].empty()) {
+      messagestatus = "_users:messagenewpass2empty_";
+    } else if (args["umnpw1"] != args["umnpw2"]) {
+      messagestatus = "_users:messagenewpassmismatch_";
+    } else if (!password_ok(args["umnpw1"])) {
+      messagestatus = "_users:messageinvalidpassword_";
+    } else {
+      userinfo_t userinfo;
+      if (get_user_info (usersfile, args["un"], userinfo)) {
+	// check old password
+	if (userinfo.password != crypt_text(args["umpw"])) {
+	  messagestatus = "_users:messagefailed_";
+	  
+	} else {
+	  userinfo.password = crypt_text(args["umnpw1"]);
+	  if (set_user_info (usersfile, args["un"], userinfo)) {
+	    // everything is ok
+	    textout << outconvert << disp
+		    << "_userschangepasswdok:header_\n"
+	      "_userschangepasswdok:content_\n"
+	      "_userschangepasswdok:footer_\n";
+	    return true;
+	  }
+	}
+      }
+    }
+  }
+
+  disp.setmacro ("messagestatus", "users", messagestatus);
+
+  textout << outconvert << disp
+	  << "_userschangepasswd:header_\n"
+    "_userschangepasswd:content_\n"
+    "_userschangepasswd:footer_\n";
+
+  return true;
+}
Index: /main/tags/2.25/gsdl/src/recpt/usersaction.h
===================================================================
--- /main/tags/2.25/gsdl/src/recpt/usersaction.h	(revision 21064)
+++ /main/tags/2.25/gsdl/src/recpt/usersaction.h	(revision 21064)
@@ -0,0 +1,80 @@
+/**********************************************************************
+ *
+ * usersaction.h -- managing users
+ * Copyright (C) 1999  DigiLib Systems Limited, New Zealand
+ *
+ * A component of the Greenstone digital library software
+ * from the New Zealand Digital Library Project at the
+ * University of Waikato, New Zealand.
+ *
+ * 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.
+ *
+ *********************************************************************/
+
+
+#ifndef USERSACTION_H
+#define USERSACTION_H
+
+#include "gsdlconf.h"
+#include "action.h"
+#include "text_t.h"
+
+
+class usersaction : public action {
+protected:
+  text_t usersfile;
+
+public:
+  usersaction ();
+  virtual ~usersaction () {}
+
+  void configure (const text_t &key, const text_tarray &cfgline);
+  
+  text_t get_action_name () {return "um";}
+  
+  bool check_cgiargs (cgiargsinfoclass &argsinfo, cgiargsclass &args, 
+		      ostream &logout);
+
+  void get_cgihead_info (cgiargsclass &args, recptprotolistclass *protos,
+			 response_t &response, text_t &response_data, 
+			 ostream &logout);
+  
+  bool do_action (cgiargsclass &args, recptprotolistclass *protos, 
+		  browsermapclass *browsers, displayclass &disp, 
+		  outconvertclass &outconvert, ostream &textout, 
+		  ostream &logout);
+
+protected:
+  void define_user_macros (cgiargsclass &args, displayclass &disp);
+  
+  bool do_listusers (cgiargsclass &args, displayclass &disp, 
+		     outconvertclass &outconvert, ostream &textout, 
+		     ostream &logout);
+
+  bool do_edituser (cgiargsclass &args, displayclass &disp, 
+		    outconvertclass &outconvert, ostream &textout, 
+		    ostream &logout);
+
+  bool do_deleteuser (cgiargsclass &args, displayclass &disp, 
+		      outconvertclass &outconvert, ostream &textout, 
+		      ostream &logout);
+
+  bool do_changepasswd (cgiargsclass &args, displayclass &disp, 
+			outconvertclass &outconvert, ostream &textout, 
+			ostream &logout);
+};
+
+
+#endif
Index: /main/tags/2.25/gsdl/src/recpt/vlistbrowserclass.cpp
===================================================================
--- /main/tags/2.25/gsdl/src/recpt/vlistbrowserclass.cpp	(revision 21064)
+++ /main/tags/2.25/gsdl/src/recpt/vlistbrowserclass.cpp	(revision 21064)
@@ -0,0 +1,211 @@
+/**********************************************************************
+ *
+ * vlistbrowserclass.cpp -- 
+ * Copyright (C) 1999  The New Zealand Digital Library Project
+ *
+ * A component of the Greenstone digital library software
+ * from the New Zealand Digital Library Project at the
+ * University of Waikato, New Zealand.
+ *
+ * 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.
+ *
+ *********************************************************************/
+
+#include "vlistbrowserclass.h"
+#include <assert.h>
+#include "OIDtools.h"
+
+vlistbrowserclass::vlistbrowserclass () {
+}
+
+vlistbrowserclass::~vlistbrowserclass () {
+}
+
+// returns the name that specifies the browserclass type
+text_t vlistbrowserclass::get_browser_name () {
+  return "VList";
+}
+
+void vlistbrowserclass::load_metadata_defaults (text_tset &metadata) {
+  metadata.insert ("haschildren");
+  metadata.insert ("doctype");
+}
+
+text_t vlistbrowserclass::get_default_formatstring () {
+  return "<td>[link][icon][/link]</td><td>[highlight]{Or}{[Title],Untitled}[/highlight]</td>";
+}
+
+int vlistbrowserclass::output_section_group (ResultDocInfo_t &section, cgiargsclass &args,
+					     const text_t &collection, int colnumber, 
+					     format_t *formatlistptr, bool use_table, 
+					     text_tset &/*metadata*/, bool &/*getParents*/, 
+					     recptproto * /*collectproto*/, displayclass &disp, 
+					     outconvertclass &outconvert, ostream &textout, 
+					     ostream &/*logout*/) {
+
+  text_t link, icon;
+
+  text_t collink = collection;
+  if (!collink.empty()) collink = "&c=" + collink;
+
+  get_link_icon (section, args, collink, link, icon);
+  bool highlight = false;
+  if (!args["d"].empty()) {
+    if (args["d"] == section.OID) highlight = true;
+  } else 
+    if (args["cl"] == section.OID) highlight = true;
+
+
+  if (use_table || colnumber > 0) {
+    textout << "<table><tr valign=top>";
+    // get tab size
+    text_t tab; int itab;
+    disp.expandstring ("Global", "_tabwidth_", tab);
+    itab = tab.getint();
+    if (colnumber > 0) textout << outconvert << disp 
+			       << "<td><img src=\"_httpimg_/space.gif\" width=" 
+			       << (itab*colnumber) << "></td>";
+  }
+
+  textout << outconvert << disp << get_formatted_string (section, formatlistptr, 
+							 link, icon, highlight);
+  
+  if (use_table  || colnumber > 0) textout << "</tr></table>\n";
+
+  return 1;
+}
+
+int vlistbrowserclass::output_section_group (FilterResponse_t &sections, cgiargsclass &args,
+					     const text_t &collection, int colnumber, 
+					     format_t *formatlistptr, bool use_table, 
+					     text_tset &/*metadata*/, bool &/*getParents*/, 
+					     recptproto * /*collectproto*/, displayclass &disp, 
+					     outconvertclass &outconvert, ostream &textout, 
+					     ostream &/*logout*/) {
+
+  text_t link, icon;
+  text_t &arg_d = args["d"];
+  text_t &arg_cl = args["cl"];
+
+  text_t collink = collection;
+  if (!collink.empty()) collink = "&c=" + collink;
+
+  if (colnumber > 0) {
+    textout << "<table><tr valign=top>";
+    // get tab size
+    text_t tab; int itab;
+    disp.expandstring ("Global", "_tabwidth_", tab);
+    itab = tab.getint();
+    if (colnumber > 0) textout << outconvert << disp 
+			       << "<td><img src=\"_httpimg_/space.gif\" width=" 
+			       << (itab*colnumber) << "></td>";
+    textout << "<td>";
+  }
+  if (use_table) textout << "<table>\n";
+
+  ResultDocInfo_tarray::iterator thissection = sections.docInfo.begin();
+  ResultDocInfo_tarray::iterator endsection = sections.docInfo.end();
+
+  while (thissection != endsection) {
+
+    get_link_icon (*thissection, args, collink, link, icon);
+    bool highlight = false;
+    if (!arg_d.empty()) {
+      if (arg_d == (*thissection).OID) highlight = true;
+    } else 
+      if (arg_cl == (*thissection).OID) highlight = true;
+
+    if (use_table || colnumber > 0) textout << "<tr valign=top>";
+    textout << outconvert << disp << get_formatted_string (*thissection, formatlistptr, 
+							   link, icon, highlight);
+    if (use_table || colnumber > 0) textout << "</tr>";
+    textout << "\n";
+    thissection ++;
+  }
+
+  if (use_table) textout << "</table>\n";
+  if (colnumber > 0) textout << "</table></td></tr></table>\n";
+
+  return 1;
+}
+
+
+// get_link_icon attempts to work out what type of icon should be displayed for
+// the given section and what it should link to.
+void vlistbrowserclass::get_link_icon (ResultDocInfo_t &section, cgiargsclass &args,
+				       const text_t &collink, text_t &link, text_t &icon) {
+
+  link = "<a href=\"_httpdocument_" + collink;
+  icon = "_document:icontext_";
+  int haschildren = 0;
+
+  if (section.metadata.count("haschildren")>0)
+    haschildren = section.metadata["haschildren"].values[0].getint();
+
+  text_t doctype;
+  if (section.metadata.count("doctype")>0)
+    doctype = section.metadata["doctype"].values[0];
+
+  text_t &arg_d = args["d"];
+  text_t &arg_cl = args["cl"];
+
+  if (args["a"] == "q") {
+    // query results
+    if (is_top (section.OID)) icon = "_document:iconclosedbook_";
+    else if (haschildren == 1) icon = "_document:iconclosedfolder_";
+    link += "&cl=search&d=" + section.OID + "\">";
+
+  } else if (!arg_d.empty()) {
+    // document level
+    if (is_top(section.OID)) {
+      icon = "_document:iconopenbook_";
+      if (arg_cl == "search") link = "<a href=\"_httpquery_\">";
+      else link += "&cl=" + arg_cl + "\">";
+    
+    } else if (haschildren == 1) {
+      if ((args["gc"] == "1") || 
+	  (is_child_of (section.OID, arg_d)) ||
+	  (section.OID == arg_d)) {
+	icon = "_document:iconopenfolder_";
+	link += "&cl=" + arg_cl + "&d=" + section.OID + ".pr\">";
+      } else {
+	icon = "_document:iconclosedfolder_";
+	link += "&cl=" + arg_cl + "&d=" + section.OID + "\">";
+      }
+    } else link += "&cl=" + arg_cl + "&d=" + section.OID + "\">";
+
+  } else {
+    // classification level
+    if (haschildren == 1) {
+      if (doctype == "classify") {
+	if ((args["gc"] == "1") || 
+	    (is_child_of (section.OID, arg_cl)) || 
+	    (section.OID == arg_cl)) {
+	  icon = "_document:iconopenbookshelf_";
+	  link += "&cl=" + section.OID + ".pr\">";
+	} else {
+	  icon = "_document:iconclosedbookshelf_";
+	  link += "&cl=" + section.OID + "\">";
+	}
+      } else {
+	icon = "_document:iconclosedbook_";
+	link += "&cl=" + arg_cl + "&d=" + section.OID + "\">";
+      }
+    } else {
+      if (doctype == "classify") link = "";
+      else link += "&cl=" + arg_cl + "&d=" + section.OID + "\">";
+    }
+  }
+}
Index: /main/tags/2.25/gsdl/src/recpt/vlistbrowserclass.h
===================================================================
--- /main/tags/2.25/gsdl/src/recpt/vlistbrowserclass.h	(revision 21064)
+++ /main/tags/2.25/gsdl/src/recpt/vlistbrowserclass.h	(revision 21064)
@@ -0,0 +1,63 @@
+/**********************************************************************
+ *
+ * vlistbrowserclass.h -- 
+ * Copyright (C) 1999  The New Zealand Digital Library Project
+ *
+ * A component of the Greenstone digital library software
+ * from the New Zealand Digital Library Project at the
+ * University of Waikato, New Zealand.
+ *
+ * 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.
+ *
+ *********************************************************************/
+
+
+#ifndef VLISTBROWSERCLASS_H
+#define VLISTBROWSERCLASS_H
+
+#include "browserclass.h"
+
+class vlistbrowserclass : public browserclass {
+protected:
+
+public:
+  vlistbrowserclass ();
+  virtual ~vlistbrowserclass ();
+
+  text_t get_browser_name ();
+
+  virtual void load_metadata_defaults (text_tset &metadata);
+
+  virtual text_t get_default_formatstring ();
+
+  virtual int output_section_group (ResultDocInfo_t &section, cgiargsclass &args,
+				    const text_t &collection, int colnumber, format_t *formatlistptr, 
+				    bool use_table, text_tset &metadata, bool &getParents,
+				    recptproto *collectproto, displayclass &disp, 
+				    outconvertclass &outconvert, ostream &textout, ostream &logout);
+
+  virtual int output_section_group (FilterResponse_t &sections, cgiargsclass &args,
+				    const text_t &collection, int colnumber, format_t *formatlistptr, 
+				    bool use_table, text_tset &metadata, bool &getParents,
+				    recptproto *collectproto, displayclass &disp, 
+				    outconvertclass &outconvert, ostream &textout, ostream &logout);
+
+protected:
+
+  virtual void get_link_icon (ResultDocInfo_t &section, cgiargsclass &args,
+			      const text_t &collink, text_t &link, text_t &icon);
+};
+
+#endif
Index: /main/tags/2.25/gsdl/src/recpt/win32.mak
===================================================================
--- /main/tags/2.25/gsdl/src/recpt/win32.mak	(revision 21064)
+++ /main/tags/2.25/gsdl/src/recpt/win32.mak	(revision 21064)
@@ -0,0 +1,155 @@
+###########################################################################
+#
+# win32 makefile -- src/recpt
+# A component of the Greenstone digital library software
+# from the New Zealand Digital Library Project at the
+# University of Waikato, New Zealand.
+#
+# Copyright (C) 1999  The 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.
+#
+###########################################################################
+
+GSDLHOME = c:\gsdl
+STLPATH = c:\stlport
+
+AR = lib
+CC = cl
+CPPFLAGS =
+LDFLAGS =
+DEFS = -DNZDL -DQUIET -D__WIN32__ -DGSDL_NAMESPACE_BROKEN -DGSDL_USE_IOS_H \
+       -DSHORT_SUFFIX -DPARADOCNUM -DHAVE_CONFIG_H -D__STL_NO_NEW_IOSTREAMS \
+       -DGSDLSERVER -DGSDLUSAGELOG	
+INCLUDES = -I$(GSDLHOME)\src\recpt -I$(GSDLHOME)\lib -I$(GSDLHOME)\src\colservr \
+	   -I$(GSDLHOME)\packages\mg -I$(GSDLHOME)\packages\mg\lib \
+	   -I$(GSDLHOME)\packages\mg\src\text -I$(GSDLHOME)\packages\wingdbm \
+	   -I$(STLPATH) -I$(GSDLHOME)\packages\wincrypt
+
+LIBS = $(GSDLHOME)\packages\wingdbm\gdbm.lib $(GSDLHOME)\packages\wincrypt\crypt.lib
+
+COMPILE = $(CC) -c $(CPPFLAGS) $(DEFS) $(INCLUDES)
+LINK = $(CC) $(LDFLAGS) -o $@
+
+.SUFFIXES:
+.SUFFIXES: .c .obj
+.c.obj:
+	$(COMPILE) $<
+
+.SUFFIXES: .cpp .obj
+.cpp.obj:
+	$(COMPILE) $< 
+
+
+COMMONHEADERS = receptionist.h cgiwrapper.h cgiargs.h action.h browserclass.h \
+                converter.h recptconfig.h cgiutils.h OIDtools.h browsetools.h htmlgen.h \
+		statusaction.h pageaction.h comtypes.h recptproto.h \
+		pingaction.h queryaction.h documentaction.h \
+		extlinkaction.h buildaction.h htmlutils.h \
+		querytools.h formattools.h tipaction.h authenaction.h infodbclass.h \
+                userdb.h usersaction.h vlistbrowserclass.h hlistbrowserclass.h \
+		datelistbrowserclass.h invbrowserclass.h pagedbrowserclass.h \
+		htmlbrowserclass.h delhistoryaction.h historydb.h
+
+RECEPTHEADERS = 
+
+LIBRARYHEADERS = nullproto.h
+
+HEADERS = $(COMMONHEADERS) $(RECPTHEADERS) $(LIBRARYHEADERS)
+
+
+COMMONSOURCES = receptionist.cpp cgiwrapper.cpp cgiargs.cpp action.cpp browserclass.cpp \
+                converter.cpp recptconfig.cpp cgiutils.cpp OIDtools.cpp browsetools.cpp \
+		htmlgen.cpp statusaction.cpp pageaction.cpp comtypes.cpp \
+		recptproto.cpp pingaction.cpp queryaction.cpp documentaction.cpp \
+		extlinkaction.cpp buildaction.cpp htmlutils.cpp querytools.cpp formattools.cpp \
+		tipaction.cpp authenaction.cpp infodbclass.cpp userdb.cpp usersaction.cpp \
+		vlistbrowserclass.cpp hlistbrowserclass.cpp datelistbrowserclass.cpp \
+		invbrowserclass.cpp pagedbrowserclass.cpp htmlbrowserclass.cpp \
+		delhistoryaction.cpp historydb.cpp
+
+
+RECPTSOURCES = recptmain.cpp
+
+LIBRARYSOURCES = nullproto.cpp librarymain.cpp
+
+SOURCES = $(COMMONSOURCES) $(RECPTSOURCES) $(LIBRARYSOURCES)
+
+
+COMMONOBJECTS = receptionist.obj cgiwrapper.obj cgiargs.obj action.obj browserclass.obj \
+                converter.obj recptconfig.obj cgiutils.obj OIDtools.obj browsetools.obj \
+		htmlgen.obj statusaction.obj pageaction.obj comtypes.obj \
+		recptproto.obj pingaction.obj queryaction.obj documentaction.obj \
+		extlinkaction.obj buildaction.obj htmlutils.obj querytools.obj \
+		formattools.obj tipaction.obj authenaction.obj \
+                infodbclass.obj userdb.obj usersaction.obj vlistbrowserclass.obj \
+		hlistbrowserclass.obj datelistbrowserclass.obj invbrowserclass.obj \
+		pagedbrowserclass.obj htmlbrowserclass.obj delhistoryaction.obj \
+		historydb.obj
+
+RECPTOBJECTS = recptmain.obj
+
+LIBRARYOBJECTS = nullproto.obj librarymain.obj
+
+OBJECTS = $(COMMONOBJECTS) $(RECPTOBJECTS) $(LIBRARYOBJECTS)
+
+
+COLSERVROBJECTS = $(GSDLHOME)\src\colservr\mgq.obj \
+                  $(GSDLHOME)\src\colservr\mgsearch.obj \
+                  $(GSDLHOME)\src\colservr\querycache.obj \
+                  $(GSDLHOME)\src\colservr\queryinfo.obj \
+                  $(GSDLHOME)\src\colservr\collectserver.obj \
+                  $(GSDLHOME)\src\colservr\colservrconfig.obj \
+                  $(GSDLHOME)\src\colservr\maptools.obj \
+                  $(GSDLHOME)\src\colservr\filter.obj \
+                  $(GSDLHOME)\src\colservr\source.obj \
+                  $(GSDLHOME)\src\colservr\browsefilter.obj \
+                  $(GSDLHOME)\src\colservr\queryfilter.obj \
+                  $(GSDLHOME)\src\colservr\mggdbmsource.obj \
+                  $(GSDLHOME)\src\colservr\phrasesearch.obj \
+                  $(GSDLHOME)\src\colservr\phrasequeryfilter.obj
+
+EXEC = recpt.exe library.exe
+
+all: $(EXEC)
+
+clean:
+	del *.obj
+	del recpt.exe
+	del library.exe
+
+install:
+	copy library.exe $(GSDLHOME)\cgi-bin\library.exe
+
+# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
+
+RECPT_OBJS = $(COMMONOBJECTS) $(RECPTOBJECTS) \
+    $(GSDLHOME)\lib\gsdllib.lib  \
+    $(GSDLHOME)\packages\mg\src\text\libtextin.lib \
+    $(GSDLHOME)\packages\mg\lib\libmg.lib
+
+recpt.exe: $(RECPT_OBJS)
+           $(LINK) $(RECPT_OBJS) $(LIBS) 
+
+# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
+
+LIBRARY_OBJS = $(COMMONOBJECTS) $(LIBRARYOBJECTS) $(COLSERVROBJECTS) \
+    $(GSDLHOME)\lib\gsdllib.lib \
+    $(GSDLHOME)\packages\mg\src\text\libtextin.lib \
+    $(GSDLHOME)\packages\mg\lib\libmg.lib
+
+library.exe: $(LIBRARY_OBJS)
+	     $(LINK) $(LIBRARY_OBJS) $(LIBS) 
Index: /main/tags/2.25/gsdl/src/recpt/z3950proto.cpp
===================================================================
--- /main/tags/2.25/gsdl/src/recpt/z3950proto.cpp	(revision 21064)
+++ /main/tags/2.25/gsdl/src/recpt/z3950proto.cpp	(revision 21064)
@@ -0,0 +1,253 @@
+/**********************************************************************
+ *
+ * z3950proto.cpp --
+ * Copyright (C) 2000  The New Zealand Digital Library Project
+ *
+ * A component of the Greenstone digital library software
+ * from the New Zealand Digital Library Project at the
+ * University of Waikato, New Zealand.
+ *
+ * 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.
+ *
+ *********************************************************************/
+
+#include "z3950proto.h"
+#include "comtypes.h"
+#include <stdio.h>
+
+/*** 
+    We will use the "collection" argument as the name of the database
+    to query on the z3950 server.
+***/
+
+
+z3950_server::z3950_server() {
+  count=0;
+  info=NULL;
+  meta["iconcollection"]="/~johnmcp/gsdl/images/zserver.png";
+}
+
+
+
+
+// z3950 Protocol functions
+z3950proto::z3950proto() {
+  zserver_count=0;
+}
+
+void z3950proto::add_server (const z3950_server& zserver) {
+
+  // append the new server
+  zserver_count++;
+  zservers.push_back(zserver);
+}
+
+void z3950proto::configure (const text_t &/*key*/, 
+			    const text_tarray &/*cfgline*/) {
+
+  // this is called for each line in the gsdlsite.cfg file
+  /*  cerr << "z3950proto::configure called:"
+      << "key is " << key.getcstr()
+      << "\n1st line is " << cfgline[0].getcstr() << endl;
+  */
+}
+
+
+bool z3950proto::init (ostream &/*logout*/) {
+  // set up tcp connection to server here?
+  // we might also read in the config file here (instead of librarymain.cpp)
+
+  // 
+
+  // logout goes to initout.txt
+  //  logout <<"zdebug:init:Number of z3950 servers: "<< zserver_count << "\n";
+  //logout << "\t1st server name: " << zservers[0].getName().getcstr() << "\n";
+  return true;
+
+}
+
+/*text_t z3950proto::get_protocol_name () {
+  return "z3950proto";
+}
+*/
+
+void z3950proto::get_collection_list (text_tarray &collist, 
+				      comerror_t &/*err*/,
+				      ostream &/*logout*/) {
+  // logout here DOESN'T go to initout.txt
+  // logout << "zdebug: get_collection_list called:\n";
+
+  /** *** for now, we are assuming that each SERVER is a GSDL collection,
+      as opposed to each DATABASE on the servers.
+  */
+  z3950_server_array::iterator here = zservers.begin();
+  z3950_server_array::iterator end = zservers.end();
+  while (here != end) {
+    collist.push_back(here->getName());
+    //const ShortColInfo_t *info=here->getInfo();
+    //collist.push_back(info->name);
+    here++;
+  }
+}
+
+void z3950proto::has_collection (const text_t &collection, bool &hascollection,
+				 comerror_t &/*err*/, ostream &/*logout*/) {
+  z3950_server_array::iterator here = zservers.begin();
+  z3950_server_array::iterator end = zservers.end();
+  while (here != end) {
+    if(here->getName()==collection) {
+      hascollection=true;
+      return;
+    }
+    here++;
+  }
+  hascollection=false;
+}
+
+void z3950proto::ping (const text_t &/*collection*/, bool &wassuccess, 
+		       comerror_t &/*err*/, ostream &/*logout*/) {
+  // should we just ping the server, or actually create a connection
+  // to the z39.50 server process on the machine ?
+  wassuccess = true;
+}
+
+void z3950proto::get_collectinfo (const text_t &collection,
+				  ColInfoResponse_t &collectinfo,
+				  comerror_t &err, ostream &logout) {
+
+  // set err to protocolError if something goes wrong...
+
+  z3950_server_array::iterator here = zservers.begin();
+  z3950_server_array::iterator end = zservers.end();
+  while (here != end) {
+    if(here->getName()==collection) {
+      break;
+    }
+    here++;
+  }
+
+  // is this right? ie does end refer to the last element, or AFTER the
+  // last element?
+  if (here==end) {
+    err=protocolError;
+    logout << "z39.50: couldn't find collection" 
+	   << collection.getcstr()
+	   << endl;
+    return;
+  }
+
+  /*  collectinfo.shortInfo.name="sdfg";
+      collectinfo.shortInfo.host="localhost";
+      collectinfo.shortInfo.port=0; */
+  const ShortColInfo_t *colinfo=here->getInfo();
+  collectinfo.shortInfo.name=colinfo->name;
+  collectinfo.shortInfo.host=colinfo->host;
+  collectinfo.shortInfo.port=colinfo->port;
+
+  collectinfo.isPublic=true;
+  // don't use beta field
+  /*collectinfo.isBeta=false;*/
+  collectinfo.buildDate=1;
+  // leave ccsCols empty (no cross-coll. searching - for now)
+  /*collectinfo.ccsCols=(text_tarray);*/ //not like this!!!
+  collectinfo.languages.push_back("en");
+  collectinfo.languages.push_back("fr");
+  collectinfo.numDocs=0;
+  collectinfo.numWords=0;
+  collectinfo.numBytes=0;
+  // copy the text maps over.
+  //  collectinfo.collectionmeta; // text_tmap
+  //  delete collectinfo.collectionmeta;
+  collectinfo.collectionmeta=*(here->getMeta());
+  /* collectinfo.format; //text_tmap
+    collectinfo.building; //text_tmap
+  */
+
+collectinfo.receptionist="z3950"; /* for now... this is a url,
+				    relative to .../cgi-bin   */
+}
+
+void z3950proto::get_filterinfo (const text_t &/*collection*/,
+				 InfoFiltersResponse_t &/*response*/,
+				 comerror_t &/*err*/, ostream &/*logout*/) {
+
+}
+
+void z3950proto::filter (const text_t &collection,
+			 FilterRequest_t &request,
+			 FilterResponse_t &response,
+			 comerror_t &err, ostream &logout) {
+  // assume this function is only called when creating the title page,
+  // and looking for the metadata regarding icons.
+  response.numDocs=0;
+  response.isApprox=Approximate; // Exact | Approximate | MoreThan
+  // leave response.termInfo empty
+  // leave response.docInfo empty
+  /* got the following for first query:
+     request.filterResultOptions=FRmetadata;
+     request.getParents=getParents
+     request.fields=metadata
+     request.docSet (includes OID);
+  */
+  // fill in the metadata for each of the OIDs (if it is requested)
+  if (request.filterResultOptions & FRmetadata) {
+    // request.fields // type text_tset
+    // docInfo is type ResultDocInfo_tarray
+    ColInfoResponse_t *info = new ColInfoResponse_t;
+    get_collectinfo (collection, *info, err, logout);
+    // should check err returned here....
+
+    ResultDocInfo_t *docInfo=new ResultDocInfo_t;
+    
+    text_tmap::iterator it=info->collectionmeta.find("collectionname");
+    // cerr now goes to errout.txt in etc directory
+    // "(*it).first" is key, "(*it).second" is value(s).
+    if (it!=info->collectionmeta.end()) 
+      docInfo->metadata["collectionname"].values.push_back((*it).second);
+    else // needs to exist, but be empty
+      docInfo->metadata["collectionname"].values.push_back("");
+
+    it=info->collectionmeta.find("iconcollection");
+    if (it!=info->collectionmeta.end()) 
+      docInfo->metadata["iconcollection"].values.push_back((*it).second);
+    else // needs to exist, but be empty
+      docInfo->metadata["iconcollection"].values.push_back("");
+
+    it=info->collectionmeta.find("iconcollectionsmall");
+    if (it!=info->collectionmeta.end()) 
+      docInfo->metadata["iconcollectionsmall"].values.push_back((*it).second);
+    else // needs to exist, but be empty
+      docInfo->metadata["iconcollectionsmall"].values.push_back("");
+    
+
+    response.docInfo.push_back(*docInfo);
+  }
+
+  err=noError;
+}
+
+void z3950proto::get_document (const text_t &/*collection*/,
+			       const DocumentRequest_t &/*request*/,
+			       DocumentResponse_t &/*response*/,
+			       comerror_t &err, ostream &logout) {
+
+  if (0) {
+    err=protocolError;
+    logout << "Some error\n";
+  }
+}
+
+
+#endif
Index: /main/tags/2.25/gsdl/src/recpt/z3950proto.h
===================================================================
--- /main/tags/2.25/gsdl/src/recpt/z3950proto.h	(revision 21064)
+++ /main/tags/2.25/gsdl/src/recpt/z3950proto.h	(revision 21064)
@@ -0,0 +1,144 @@
+/**********************************************************************
+ *
+ * z3950proto.h --
+ * Copyright (C) 2000  The New Zealand Digital Library Project
+ *
+ * A component of the Greenstone digital library software
+ * from the New Zealand Digital Library Project at the
+ * University of Waikato, New Zealand.
+ *
+ * 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.
+ *
+ *********************************************************************/
+
+#ifndef Z3950PROTO_H
+#define Z3950PROTO_H
+
+#include "recptproto.h"
+
+// each server can have one or more databases
+/*
+  class z3950_DB {
+  protected:
+  text_t name; // Descriptive name
+  text_t database; // name for server
+  
+  public:
+  z3950_DB();     // constructor
+  ~z3950_DB();    // deconstructor
+  const text_t getName() {return name;}                // this gets name
+  void setName(text_t newName) {name=newName;} // this sets name
+  // need to get next (for linked list)
+  };
+  
+
+  typedef  vector<z3950_DB>  z3950_DB_array;
+*/
+
+/*class z3950_DB_Array {
+  protected:
+  int count;
+  // some arraytype...
+  public:
+  z3950_DB first();
+  z3950_DB last();
+  void     add(z3950_DB *db);
+  void     remove(z3950_DB *db);
+  };
+*/
+
+
+class z3950_server {
+ protected:
+  text_t title;    // Descriptive name
+  text_t hostname; // network name (IP or host+domain name)
+  text_tmap meta;  // metadata for this collection (ie server/database pair)
+  // this is currently only iconcollection (and iconcollectionsmall)
+  int count;
+  //  z3950_DB_array* db;
+  ShortColInfo_t *info; // has  (database) name, host and port
+
+ public:
+  z3950_server();
+  // z3950_DB_array getDBs();
+  const text_t getName() {return title;}
+  void setName(const text_t &newname) {title=newname;}
+  //  void setHostname(const text_t &newname) {hostname=newname;}
+  void setInfo(ShortColInfo_t *newinfo) {info=newinfo;}
+  const ShortColInfo_t *getInfo() {return info;}
+  const text_tmap *getMeta() {return &meta;}
+};
+
+typedef  vector<z3950_server>  z3950_server_array;
+
+
+
+
+class z3950proto : public recptproto {
+protected:
+  int zserver_count;
+  z3950_server_array zservers;
+public:
+  z3950proto();
+  virtual ~z3950proto() {}
+
+  /*
+  void add_collectserver (collectserver *thecserver) 
+        {cservers.addcollectserver(thecserver);}
+  */
+
+  void add_server(const z3950_server& zserver);
+
+  void configure (const text_t &key, const text_tarray &cfgline);
+
+  bool init (ostream &logout);
+
+  text_t get_protocol_name () {return "z3950proto";}
+
+  void get_collection_list (text_tarray &collist, comerror_t &err, 
+			    ostream &logout);
+
+  void has_collection (const text_t &collection, bool &hascollection, 
+		       comerror_t &err, ostream &logout);
+  
+  void ping (const text_t &collection, bool &wassuccess, 
+	     comerror_t &err, ostream &logout);
+  
+  void get_collectinfo (const text_t &collection, 
+			ColInfoResponse_t &collectinfo,
+			comerror_t &err, ostream &logout);
+  
+  void get_filterinfo (const text_t &collection,
+		       InfoFiltersResponse_t &response,
+		       comerror_t &err, ostream &logout);
+  
+  /*  void get_info (const text_t &collection, const text_tset &metadata,
+      FilterResponse_t &response, ostream &logout);
+  */
+  
+  void filter (const text_t &collection,
+	       FilterRequest_t &request,
+	       FilterResponse_t &response,
+	       comerror_t &err, ostream &logout);
+  
+  void get_document (const text_t &collection,
+		     const DocumentRequest_t &request,
+		     DocumentResponse_t &response,
+		     comerror_t &err, ostream &logout);
+
+};
+
+
+#endif
Index: /main/tags/2.25/gsdl/src/txt2db/Makefile.in
===================================================================
--- /main/tags/2.25/gsdl/src/txt2db/Makefile.in	(revision 21064)
+++ /main/tags/2.25/gsdl/src/txt2db/Makefile.in	(revision 21064)
@@ -0,0 +1,90 @@
+###########################################################################
+#
+# Makefile -- Makefile for txt2db
+# A component of the Greenstone digital library software
+# from the New Zealand Digital Library Project at the
+# University of Waikato, New Zealand.
+#
+# Copyright (C) 1999 Rodger McNab, Stefan Boddie
+#
+# 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.
+#
+#       @(#)Makefile.in	1.3 16 Mar 1994
+#
+###########################################################################
+
+ 
+AR = ar
+CC = @CC@
+CCFLAGS = -Wall @CFLAGS@
+DEFS = @DEFS@
+RANLIB = @RANLIB@
+INCLUDES = -I../../lib
+LDFLAGS = @LDFLAGS@ 
+DPLIBS = ../../lib/gsdllib.a ../../packages/mg/lib/unitool.o
+#LIBS = ../../lib/gsdllib.a ../../packages/mg/lib/unitool.o -lstdc++ -lgdbm
+LIBS = ../../lib/gsdllib.a ../../packages/mg/lib/unitool.o @LIBS@
+GSDLOS = @gsdlos@
+
+ 
+COMPILE = $(CC) -c $(DEFS) $(INCLUDES) $(CCFLAGS)
+LINK = $(CC) $(LDFLAGS) -o $@
+ 
+.SUFFIXES:
+.SUFFIXES: .c .o
+.c.o:
+	$(COMPILE) $<
+
+.SUFFIXES: .cpp .o
+.cpp.o:
+	$(COMPILE) $< 
+ 
+
+HEADERS = 
+
+SOURCES = txt2db.cpp
+
+OBJECTS = txt2db.o
+
+EXEC    = txt2db
+ 
+all : $(EXEC)
+
+install: $(EXEC)
+	install -d ../../bin/$(GSDLOS)
+	install -m 755 -s $(EXEC) ../../bin/$(GSDLOS)
+
+distclean:
+	rm -f $(OBJECTS) $(EXEC) Makefile
+
+clean:
+	rm -f $(OBJECTS) $(EXEC)
+
+depend:
+	makedepend -Y -- $(DEFS) $(INCLUDES) $(CCFLAGS) -- $(SOURCES)
+
+
+# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
+
+TXT2DB_OBJS = txt2db.o
+
+txt2db: $(TXT2DB_OBJS) $(DPLIBS)
+	$(LINK) $(TXT2DB_OBJS) $(LIBS)
+
+
+
+
+
+
Index: /main/tags/2.25/gsdl/src/txt2db/txt2db.cpp
===================================================================
--- /main/tags/2.25/gsdl/src/txt2db/txt2db.cpp	(revision 21064)
+++ /main/tags/2.25/gsdl/src/txt2db/txt2db.cpp	(revision 21064)
@@ -0,0 +1,171 @@
+/**********************************************************************
+ *
+ * txt2db.cpp -- 
+ * A component of the Greenstone digital library software
+ * from the New Zealand Digital Library Project at the 
+ * University of Waikato, New Zealand.
+ *
+ * Copyright (C) 1999  The 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.
+ *
+ **********************************************************************/
+
+
+#ifdef __WIN32__
+#include "autoconf.h"
+#include "systems.h"
+#include "gdbmconst.h"
+#include "gdbm.h"
+
+#else
+#include <gdbm.h>
+#endif
+
+#include "gsdlconf.h"
+#include "text_t.h"
+#include <stdlib.h>
+
+#if defined(GSDL_USE_OBJECTSPACE)
+#  include <ospace\std\iostream>
+#elif defined(GSDL_USE_IOS_H)
+#  include <iostream.h>
+#else
+#  include <iostream>
+#endif
+
+
+void print_usage (char *program_name) {
+  cerr << "usage: " << program_name << " [options] database-name\n\n";
+  cerr << "options:\n";
+  cerr << " -append        append to existing database\n\n";
+}
+
+
+int main (int argc, char *argv[]) {
+  int block_size = 0;
+  GDBM_FILE dbf;
+  char c;
+  text_t key;
+  text_t value;
+  text_t tmp;
+  int num_dashes = 0;
+
+  // sanity check
+  if (argc != 2 && argc != 3) {
+    print_usage (argv[0]);
+    exit (0);
+  }
+  
+  char *dbname;
+  int append = 0;
+  if (argc == 3) {
+    if (strcmp (argv[1], "-append") == 0) {
+      append = 1;
+      dbname = argv[2];
+    } else {
+      cerr << argv[1] << " is not a valid option.\n\n";
+      print_usage (argv[0]);
+      exit (0);
+    }
+  } else dbname = argv[1];
+
+  
+  // open the database
+  // note that GDBM_FAST is obsolete on newer versions of gdbm
+  int read_write = GDBM_NEWDB | GDBM_FAST;
+  if (append) read_write = GDBM_WRCREAT | GDBM_FAST;
+  
+#ifdef __WIN32__
+  dbf = gdbm_open (dbname, block_size, read_write, 00664, NULL, 1);
+#else
+  dbf = gdbm_open  (dbname, block_size, read_write, 00664, NULL);
+#endif
+  if (dbf == NULL) {
+    cerr << "couldn't create " << dbname << "\n";
+    exit (0);
+  }
+  
+  cin.get(c);
+  while (!cin.eof()) {
+    num_dashes = 0;
+    key = "";
+    value = "";
+    
+    // look for [key]\n
+    while (!cin.eof() && c != '[') cin.get(c);
+    if (!cin.eof()) cin.get(c); // skip [
+    while (!cin.eof() && c != ']') {
+      key.push_back ((unsigned char)c);
+      cin.get(c);
+    }
+    if (!cin.eof()) cin.get(c); // skip ]
+    while (!cin.eof() && (c == '\n' || c == 'r')) cin.get(c);
+    
+    // look for 70 dashes
+    tmp = "";
+    while (!cin.eof() && (num_dashes < 70)) {
+      if (c == '\n' || c == '\r') {
+	tmp.push_back ((unsigned char)c);
+	num_dashes = 0;
+	
+      } else if (c == '-') {
+	tmp.push_back ((unsigned char)c);
+	num_dashes++;
+	
+      } else {
+	value += tmp;
+	value.push_back ((unsigned char)c);
+	tmp = "";
+	num_dashes = 0;
+      }
+      cin.get(c);
+    }
+    
+    // if the key is not an empty string store this key-value pair
+    if (!key.empty()) {
+      // convert key to a datum datatype
+      datum key_data;
+      key_data.dptr = key.getcstr();
+      if (key_data.dptr == NULL) {
+	cerr << "NULL key_data.dptr\n";
+	exit (0);
+      }
+      key_data.dsize = strlen(key_data.dptr);
+      
+      // convert value to a datum datatype
+      datum value_data;
+      value_data.dptr = value.getcstr();
+      if (value_data.dptr == NULL) {
+	cerr << "NULL value_data.dptr\n";
+	exit (0);
+      }
+      value_data.dsize = strlen(value_data.dptr);
+      
+      // store the value
+      if (gdbm_store (dbf, key_data, value_data, GDBM_REPLACE) < 0) {
+	cerr << "gdbm_store returned an error\n";
+	exit (0);
+      }
+      
+      delete key_data.dptr;
+      delete value_data.dptr;
+    }
+  }
+  
+  gdbm_close (dbf);
+  
+  return 0;
+}
Index: /main/tags/2.25/gsdl/src/txt2db/win32.mak
===================================================================
--- /main/tags/2.25/gsdl/src/txt2db/win32.mak	(revision 21064)
+++ /main/tags/2.25/gsdl/src/txt2db/win32.mak	(revision 21064)
@@ -0,0 +1,72 @@
+###########################################################################
+#
+# win32 makefile -- txt2db
+# A component of the Greenstone digital library software
+# from the New Zealand Digital Library Project at the
+# University of Waikato, New Zealand.
+#
+# Copyright (C) 1999  The 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.
+#
+###########################################################################
+
+GSDLHOME = d:\home\dl\gsdl
+STLPATH = d:\home\dl\stl\stlport
+
+AR = lib
+CC = cl
+CPPFLAGS = 
+LDFLAGS =
+DEFS = -DQUIET -DHAVE_CONFIG_H -D__WIN32__ -D__STL_NO_NEW_IOSTREAMS \
+       -DGSDL_NAMESPACE_BROKEN -DSHORT_SUFFIX -DGSDL_USE_IOS_H
+INCLUDES = -I$(GSDLHOME)\src\txt2db -I$(GSDLHOME)\lib -I$(GSDLHOME)\packages\mg\lib \
+	   -I$(STLPATH) -I$(GSDLHOME)\packages\wingdbm
+LIBS = $(GSDLHOME)\packages\mg\lib\unitool.obj $(GSDLHOME)\lib\gsdllib.lib \
+       $(GSDLHOME)\packages\wingdbm\gdbm.lib
+
+COMPILE = $(CC) -c -GX $(DEFS) $(INCLUDES)
+LINK = $(CC) $(LDFLAGS)
+
+.SUFFIXES:
+.SUFFIXES: .cpp .obj
+.cpp.obj:
+	$(COMPILE) $<
+
+ANSI2KNR = 
+o = .obj
+e = .exe
+ 
+HEADERS = 
+
+SOURCES = txt2db.cpp
+
+OBJECTS = txt2db$o
+
+EXEC = txt2db$e
+ 
+all : $(EXEC)
+
+install: $(EXEC)
+	if NOT EXIST $(GSDLHOME)\bin\windows mkdir $(GSDLHOME)\bin\windows
+	copy $(EXEC) $(GSDLHOME)\bin\windows\$(EXEC)
+
+clean:
+	del *.obj
+	del $(EXEC)
+
+txt2db$e: $(OBJECTS) $(LIBS)
+	  $(LINK) $(OBJECTS) $(LIBS)
Index: /main/tags/2.25/gsdl/src/w32server/cgiwrapper.cpp
===================================================================
--- /main/tags/2.25/gsdl/src/w32server/cgiwrapper.cpp	(revision 21064)
+++ /main/tags/2.25/gsdl/src/w32server/cgiwrapper.cpp	(revision 21064)
@@ -0,0 +1,781 @@
+/**********************************************************************
+ *
+ * cgiwrapper.cpp -- windows local library cgiwrapper
+ * Copyright (C) 1999  The New Zealand Digital Library Project
+ *
+ * A component of the Greenstone digital library software
+ * from the New Zealand Digital Library Project at the
+ * University of Waikato, New Zealand.
+ *
+ * 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.
+ *
+ *********************************************************************/
+
+#include "text_t.h"
+
+#include <windows.h>
+#include <string.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <assert.h>
+#include <direct.h>
+#include "cgiwrapper.h"
+#include "netio.h"
+#include "wincgiutils.h"
+#include "settings.h"
+#include "fileutil.h"
+
+#include "gsdlconf.h"
+#include "recptconfig.h"
+
+#if defined (GSDL_USE_OBJECTSPACE)
+#include <ospace\std\iostream>
+#include <ospace\std\fstream>
+#elif defined (GSDL_USE_IOS_H)
+#include <iostream.h>
+#include <fstream.h>
+#else
+#include <iostream>
+#include <fstream>
+#endif
+
+#include "receptionist.h"
+#include "nullproto.h"
+#include "collectserver.h"
+#include "infodbclass.h"
+#include "mggdbmsource.h"
+
+// actions
+#include "statusaction.h"
+#include "pageaction.h"
+#include "pingaction.h"
+#include "queryaction.h"
+#include "documentaction.h"
+#include "tipaction.h"
+#include "authenaction.h"
+#include "usersaction.h"
+#include "extlinkaction.h"
+#include "buildaction.h"
+#include "delhistoryaction.h"
+
+// browsers
+#include "vlistbrowserclass.h"
+#include "hlistbrowserclass.h"
+#include "datelistbrowserclass.h"
+#include "invbrowserclass.h"
+#include "pagedbrowserclass.h"
+#include "htmlbrowserclass.h"
+
+// filters
+#include "filter.h"
+#include "browsefilter.h"
+#include "queryfilter.h"
+#include "phrasequeryfilter.h"
+
+// the number of times the library has been accessed
+int libaccessnum = 0;
+
+// used to output the text from receptionist
+class textstreambuf : public streambuf
+{
+public:
+  textstreambuf ();
+  int sync ();
+  int overflow (int ch);
+  int underflow () {return EOF;}
+  
+  void tsbreset() {RInfo=NULL;casostr=NULL;}
+  void setrequestinfo (RequestInfoT *theRInfo) {RInfo=theRInfo;}
+  void cascadeoutput (ostream *thecasostr) {casostr=thecasostr;}
+  
+private:
+  RequestInfoT *RInfo;
+  ostream *casostr;
+#if !defined (GSDL_USE_IOS_H)
+  char buffer[256];
+#endif
+};
+
+textstreambuf::textstreambuf() {
+  tsbreset();
+#if !defined (GSDL_USE_IOS_H)
+  setp (&buffer[0], &buffer[255]);
+#else
+  if (base() == ebuf()) allocate();
+  setp (base(), ebuf());
+#endif
+};
+
+int textstreambuf::sync () {
+  if ((RInfo != NULL) && 
+      (Send_String_N(pbase(), pptr()-pbase(), RInfo) < 0)) {
+    RInfo = NULL;
+  }
+  
+  if (casostr != NULL) {
+    char *thepbase=pbase();
+    for (int i=0;i<(pptr()-pbase());i++) (*casostr).put(thepbase[i]);
+  }
+  
+  setp (pbase(), epptr());
+  
+  return 0;
+}
+
+int textstreambuf::overflow (int ch) {
+  if (sync () == EOF) return EOF;
+  if (ch != EOF) sputc (ch);
+  return 0;
+}
+
+
+// used to output all the log and error messages
+// from receptionist
+class logstreambuf : public streambuf
+{
+public:
+  logstreambuf ();
+  int sync ();
+  int overflow (int ch);
+  int underflow () {return EOF;}
+
+#if !defined (GSDL_USE_IOS_H)
+private:
+  char buffer[256];
+#endif
+};
+
+logstreambuf::logstreambuf () {
+#if !defined (GSDL_USE_IOS_H)
+  setp (&buffer[0], &buffer[255]);
+#else
+  if (base() == ebuf()) allocate();
+  setp (base(), ebuf());
+#endif
+}
+
+int logstreambuf::sync () {
+  if (gsdl_keep_log || gsdl_show_console) {
+    log_message ("LOCAL LIB MESSAGE: ");
+		log_message_N (pbase(), pptr()-pbase());
+  }
+
+  setp (pbase(), epptr());
+  return 0;
+}
+
+int logstreambuf::overflow (int ch) {
+  if (sync () == EOF) return EOF;
+  if (ch != EOF) sputc (ch);
+  return 0;
+}
+
+
+
+#ifndef MAX_FILENAME_SIZE
+#define MAX_FILENAME_SIZE 2048
+#endif
+
+
+receptionist recpt;
+nullproto nproto;
+textstreambuf textstream;
+logstreambuf logstream;
+DWORD lastlibaccesstime;
+DWORD baseavailvirtual;
+
+static void page_errormaincfg (const text_t &gsdlhome, const text_t &collection) {
+
+  if (collection.empty()) {
+    text_t message = "Error\n\n"
+      "The main.cfg configuration file could not be found. This file\n"
+      "should contain configuration information relating to the\n"
+      "setup of the interface. As this program is not being run\n"
+      "in collection specific mode the file should reside at\n" +
+      gsdlhome + "\\etc\\main.cfg.\n";
+
+    MessageBox(NULL, message.getcstr(),
+	       "Greenstone Digital Library Software"
+	       ,MB_OK|MB_SYSTEMMODAL);
+  } else {
+    text_t message = "Neither the collect.cfg or main.cfg configuration files could\n"
+      "be found. This file should contain configuration information\n"
+      "relating to the setup of the interface. As this cgi script is\n"
+      "being run in collection specific mode the file should reside\n"
+      "at either " + gsdlhome + "\\collect\\" + collection + "\\etc\\collect.cfg,\n" +
+      gsdlhome + "\\etc\\collect.cfg or " + gsdlhome + "\\etc\\main.cfg.\n";
+
+    MessageBox(NULL, message.getcstr(),
+	       "Greenstone Digital Library Software"
+	       ,MB_OK|MB_SYSTEMMODAL);
+  }
+}
+
+static void page_errorinit (const text_t &/*gsdlhome*/) {
+
+  text_t message = "Error\n\n"
+    "An error occurred during the initialisation of the Greenstone Digital\n"
+    "Library software. It is likely that the software has not been setup\n"
+    "correctly.\n";
+
+  MessageBox(NULL, message.getcstr(),
+	     "Greenstone Digital Library Software"
+	     ,MB_OK|MB_SYSTEMMODAL);
+}
+
+static void page_errorparseargs (const text_t &gsdlhome) {
+
+  text_t message = "Error\n\n"
+    "An error occurred during the parsing of the cgi arguments.\n";
+
+  MessageBox(NULL, message.getcstr(),
+	     "Greenstone Digital Library Software"
+	     ,MB_OK|MB_SYSTEMMODAL);
+}
+
+static void page_errorcgipage (const text_t &gsdlhome) {
+
+  text_t message = "Error\n\n"
+    "An error occurred during the construction of the cgi page.\n";
+
+  MessageBox(NULL, message.getcstr(),
+	     "Greenstone Digital Library Software"
+	     ,MB_OK|MB_SYSTEMMODAL);
+}
+
+// returns 0 if the directories can't be found
+// and the user wants to quit (it returns 1
+// if everything is ok)
+int checkdir (const text_t &thedir) {
+  UINT curerrormode;
+  int drive = _getdrive();
+  char cwd[1024];
+  char rootpath[4];
+  UINT drivetype;
+  char *cstrthedir = thedir.getcstr();
+  int returnvalue = 1;
+  
+  // make sure no rude error messages are presented to the user
+  curerrormode = SetErrorMode(SEM_FAILCRITICALERRORS | SEM_NOOPENFILEERRORBOX);
+  
+  // get the drive name
+  if (thedir.size() >= 2 && thedir[1] == ':') {
+    if (thedir[0] >= 'a' && thedir[0] <= 'z') {
+      drive = thedir[0] - 'a' + 1;
+      
+    } else if (thedir[0] >= 'A' && thedir[0] <= 'Z') {
+      drive = thedir[0] - 'A' + 1;
+    }
+  }
+  
+  // find the drive type
+  rootpath[0] = drive + 'A' - 1;
+  rootpath[1] = ':';
+  rootpath[2] = '\\';
+  rootpath[3] = '\0';
+  drivetype = GetDriveType (rootpath);
+  
+  // try and set this directory to be the current working
+  // directory
+  _getcwd(cwd, 1024);
+  while (_chdir(cstrthedir) != 0) {
+    // failed
+    if (drivetype == DRIVE_CDROM) {
+      // message to insert the cdrom
+      if (MessageBox (NULL, 
+		      "Please insert the Greenstone Digital Library\n"
+		      "CD-ROM into the CD-ROM drive and press 'OK'.\n\n"
+		      "If you don't have the CD-ROM press 'Cancel' to exit\n"
+		      "this program.", "Greenstone Digital Library Software", 
+		      MB_OKCANCEL | MB_TASKMODAL) == IDCANCEL) {
+	
+	returnvalue = 0;
+	break;
+      }
+      
+    } else {
+      // message saying that the system was unable
+      // to find a certain directory
+      text_t message = "Failed to find the directory:\n\n" + thedir;
+      message += "\n\n"
+	"This directory is needed for the successful operation\n"
+	"of this software. Make sure it hasn't been deleted or\n"
+	"moved, and restart the software. You may need to\n"
+	"reinstall this software to correct the problem.";
+      char *cstrmessage = message.getcstr();
+      
+      MessageBox (NULL, cstrmessage, "Greenstone Digital Library Software",
+		  MB_OK | MB_TASKMODAL);
+      
+      delete cstrmessage;
+      
+      returnvalue = 0;
+      break;
+    }
+  }
+  
+  // revert to the previous error and cwd states
+  _chdir(cwd);
+  SetErrorMode(curerrormode);
+  
+  // free the allocated C string
+  delete cstrthedir;
+  
+  return returnvalue;
+}
+
+
+// c-string version of checkdir for the outside
+// world
+int cstrcheckdir (char *cstrthedir) {
+  return checkdir (cstrthedir);
+}
+
+
+// returns 1 if successful, 0 if unsuccessful
+int gsdl_init () {
+#if defined (GSDL_USE_IOS_H)
+  cerr = &logstream;
+  cout = &textstream;
+#else
+  cerr.rdbuf(&logstream);
+  cout.rdbuf(&textstream);
+#endif
+
+  // collection should be set to "" unless in 
+  // collection specific mode
+  text_t collection = "";
+  text_tset gsdlhomes;
+  text_tarray collections;
+  colinfo_tmap::const_iterator this_info = gsdl_collectinfo.begin();
+  colinfo_tmap::const_iterator end_info = gsdl_collectinfo.end();
+
+  // note the current time
+  lastlibaccesstime = GetTickCount();
+
+  // before we do the init we should make sure
+  // that we can find the relevant directories
+  if (!checkdir (gsdl_gsdlhome + "\\")) return 0;
+  if (!checkdir (gsdl_gsdlhome + "\\macros\\")) return 0;
+
+  if (collection.empty()) {
+
+    // get all collections from each gsdlhome (this relies 
+    // on there not being more than one collection with the same 
+    // name)
+    read_dir (filename_cat (gsdl_gsdlhome, "collect"), collections);
+    gsdlhomes.insert (gsdl_gsdlhome);
+    while (this_info != end_info) {
+      if (gsdlhomes.find ((*this_info).second.gsdl_gsdlhome) == gsdlhomes.end()) {
+	read_dir (filename_cat ((*this_info).second.gsdl_gsdlhome, "collect"), collections);
+	gsdlhomes.insert ((*this_info).second.gsdl_gsdlhome);
+      }
+      this_info ++;
+    }
+  } else {
+    collections.push_back (collection);
+  }
+  
+  text_tarray::const_iterator thiscol = collections.begin();
+  text_tarray::const_iterator endcol = collections.end();
+
+  while (thiscol != endcol) {
+
+    // this memory is created but never destroyed
+    // we're also not doing any error checking to make sure we didn't
+    // run out of memory
+    collectserver *cserver = new collectserver();
+    gdbmclass *gdbmhandler = new gdbmclass();
+    mgsearchclass *mgsearch = new mgsearchclass();
+    
+    // add a null filter
+    filterclass *filter = new filterclass();
+    cserver->add_filter (filter);
+    
+    // add a browse filter
+    browsefilterclass *browsefilter = new browsefilterclass();
+    browsefilter->set_gdbmptr (gdbmhandler);
+    cserver->add_filter (browsefilter);
+    
+    // add a query filter
+    queryfilterclass *queryfilter = new queryfilterclass();
+    queryfilter->set_gdbmptr (gdbmhandler);
+    queryfilter->set_mgsearchptr (mgsearch);
+    cserver->add_filter (queryfilter);
+    
+    // add an mg and gdbm source
+    mggdbmsourceclass *mggdbmsource = new mggdbmsourceclass();
+    mggdbmsource->set_gdbmptr (gdbmhandler);
+    mggdbmsource->set_mgsearchptr (mgsearch);
+    cserver->add_source (mggdbmsource);
+    
+    // inform collection server and everything it contains about
+    // its collection name
+    cserver->configure ("collection", *thiscol);
+    
+    nproto.add_collectserver (cserver);
+    
+    thiscol ++;
+  }
+  
+  // add the protocol to the receptionist
+  recpt.add_protocol (&nproto);
+
+  // add other converters
+  utf8inconvertclass *utf8inconvert = new utf8inconvertclass();
+  utf8outconvertclass *utf8outconvert = new utf8outconvertclass();
+  recpt.add_converter ("u", utf8inconvert, utf8outconvert);
+  
+  mapinconvertclass *gbinconvert = new mapinconvertclass();
+  gbinconvert->setmapfile (gsdl_gsdlhome, "gbku", 0x25a1);
+  mapoutconvertclass *gboutconvert = new mapoutconvertclass();
+  gboutconvert->setmapfile (gsdl_gsdlhome, "ugbk", 0xa1f5);
+  recpt.add_converter ("g", gbinconvert, gboutconvert);
+  
+  // the list of actions.
+  statusaction *astatusaction = new statusaction();
+  astatusaction->set_receptionist (&recpt);
+  recpt.add_action (astatusaction);
+  
+  pageaction *apageaction = new pageaction();
+  apageaction->set_receptionist (&recpt);
+  recpt.add_action (apageaction);
+  
+  pingaction *apingaction = new pingaction();
+  recpt.add_action (apingaction);
+  
+  tipaction *atipaction = new tipaction();
+  recpt.add_action (atipaction);
+  
+  queryaction *aqueryaction = new queryaction();
+  aqueryaction->set_receptionist (&recpt);
+  recpt.add_action (aqueryaction);
+  
+  documentaction *adocumentaction = new documentaction();
+  adocumentaction->set_receptionist (&recpt);
+  recpt.add_action (adocumentaction);
+  
+  usersaction *ausersaction = new usersaction();
+  recpt.add_action (ausersaction);
+
+  extlinkaction *anextlinkaction = new extlinkaction();
+  recpt.add_action (anextlinkaction);
+
+  buildaction *abuildaction = new buildaction();
+  abuildaction->set_receptionist (&recpt);
+  recpt.add_action (abuildaction);
+  
+  authenaction *aauthenaction = new authenaction();
+  aauthenaction->set_receptionist(&recpt);
+  recpt.add_action (aauthenaction);
+
+  delhistoryaction *adelhistoryaction = new delhistoryaction();
+  recpt.add_action (adelhistoryaction);
+
+
+  // list of browsers
+  vlistbrowserclass *avlistbrowserclass = new vlistbrowserclass();
+  recpt.add_browser (avlistbrowserclass);
+  recpt.setdefaultbrowser ("VList");
+
+  hlistbrowserclass *ahlistbrowserclass = new hlistbrowserclass();
+  recpt.add_browser (ahlistbrowserclass);
+
+  datelistbrowserclass *adatelistbrowserclass = new datelistbrowserclass();
+  recpt.add_browser (adatelistbrowserclass);
+
+  invbrowserclass *ainvbrowserclass = new invbrowserclass();
+  recpt.add_browser (ainvbrowserclass);
+
+  pagedbrowserclass *apagedbrowserclass = new pagedbrowserclass();
+  recpt.add_browser (apagedbrowserclass);
+
+  htmlbrowserclass *ahtmlbrowserclass = new htmlbrowserclass();
+  recpt.add_browser (ahtmlbrowserclass);
+  
+  // set defaults
+  recpt.configure ("gsdlhome", gsdl_gsdlhome);
+  recpt.configure ("collection", collection);
+
+  int maxrequests = 1;
+  text_tset seenhomes;
+  this_info = gsdl_collectinfo.begin();
+
+  // configure any collections with gsdlhome (or gdbmhome) 
+  // different from the default
+  while (this_info != end_info) {
+    if (((*this_info).second.gsdl_gsdlhome != gsdl_gsdlhome) ||
+	((*this_info).second.gsdl_gdbmhome != gsdl_gdbmhome) &&
+	(seenhomes.find ((*this_info).second.gsdl_gsdlhome + 
+			 (*this_info).second.gsdl_gdbmhome) == seenhomes.end())) {
+      text_tarray tmpconf;
+      tmpconf.push_back ((*this_info).first);
+      tmpconf.push_back ((*this_info).second.gsdl_gsdlhome);
+      tmpconf.push_back ((*this_info).second.gsdl_gdbmhome);
+      recpt.configure ("collectinfo", tmpconf);
+      seenhomes.insert ((*this_info).second.gsdl_gsdlhome + 
+			(*this_info).second.gsdl_gdbmhome);
+    }
+    this_info ++;
+  }
+
+  // read in config files of each gsdlhome (in no particular order)
+  // those read in last will override those read earlier
+  // collections being used together in this way should be 
+  // careful not to have main.cfg files that might 
+  // screw with each other.
+  text_tset::const_iterator thome = gsdlhomes.begin();
+  text_tset::const_iterator ehome = gsdlhomes.end();
+  while (thome != ehome) {
+    if (!main_cfg_read (recpt, *thome, collection)) {
+      // couldn't find the main configuration file
+      page_errormaincfg (*thome, collection);
+      return 0;
+    }
+    thome ++;
+  }
+
+  // w32server relies on gwcgi being set to "gw"
+  recpt.configure ("gwcgi", "gw");
+	
+  // initialise the library software
+  if (!recpt.init(cerr)) {
+    // an error occurred during the initialisation
+    page_errorinit(gsdl_gsdlhome);
+    return 0;
+  }
+
+  // get memory information
+  MEMORYSTATUS memstatus;
+  memstatus.dwLength = sizeof(MEMORYSTATUS);
+  GlobalMemoryStatus(&memstatus);
+  baseavailvirtual = memstatus.dwAvailVirtual; // save for later comparison
+	
+  return 1;
+}
+
+
+static void rememberpref (char *tailstr) {
+
+  //  gsdl_enterlib = tailstr;
+}
+
+
+static void send_file_from_disk(char *filename,
+                                RequestInfoT *RInfo,
+                                RequestFieldsT *RFields)
+{
+  int len, nr;  char *tail, *kind;
+  FILE *thefile;  
+  
+  // select appropriate mime type from file name
+  len = strlen(filename);
+  while (len > 0 && filename[len-1] != '.') len--;
+  kind = "unknown";
+  if (len > 0) {
+    tail = &filename[len];
+    if (stricmp("gif",tail) == 0) kind = "image/gif";
+    else if (stricmp("jpg",tail) == 0 ||
+             stricmp("jpeg",tail) == 0) kind = "image/jpeg";
+    else if (stricmp("htm",tail) == 0 ||
+             stricmp("html",tail) == 0) kind = "text/html";
+  }
+
+  // set up file name
+  text_t filenamet = text_t(gsdl_gsdlhome) + filename;
+  text_t::iterator here = filenamet.begin();
+  text_t::iterator end = filenamet.end();
+  while (here != end) {
+	  if (*here == '/') *here = '\\';
+	  here ++;
+  }
+
+  filename = filenamet.getcstr();
+	
+  // try to open it
+  thefile = fopen(filename, "rb");
+  if (thefile == NULL) {
+    log_message("file not found\n");
+    send_retrieve_error(404, "File not found",
+			"Could not find the local file requested", RInfo);
+    return;
+  }
+  
+  char buffer[2048];
+  // send back required information
+  if (send_header(kind, RInfo) >= 0) {
+    if (strcmpi(RFields->MethodStr, "HEAD") != 0) {
+      for (;;) {
+        nr = fread(buffer, 1, 2048, thefile);
+        if (nr <= 0) break;
+        if (SendData(RInfo->ClientSocket,
+                     (BYTE *)buffer, nr,
+		     RInfo->ThreadNum) < 0) break;        
+      }
+    }
+  }
+  fclose(thefile);
+}
+
+static void handle_library_request(char *TailStr, RequestInfoT *RInfo,
+				   RequestFieldsT *RequestFields) {
+  // check for a "?" at the start of the tail string
+  if (*TailStr == '?') TailStr++;
+
+  outconvertclass text_t2ascii;
+  
+  // parse the cgi arguments and produce the resulting page if there
+  // has been no errors so far
+  cgiargsclass args;
+  text_tmap empty; // don't use this (it's for fastcgi on unix)
+  if (!recpt.parse_cgi_args (TailStr, args, cerr, empty)) {
+    page_errorparseargs(gsdl_gsdlhome);
+    return;
+  } 
+  
+  // produce cgi header
+  response_t response;
+  text_t response_data;
+
+  recpt.get_cgihead_info (args, response, response_data, cerr, empty);
+
+  if (response == location) {
+    // location response
+    response_data = "@" + recpt.expandmacros (response_data, args, cerr);
+    char *response_data_c = response_data.getcstr();
+    send_header(response_data_c, RInfo);
+    delete response_data_c;
+    return;
+  } else if (response == content) {
+    // content response
+    char *response_data_c = response_data.getcstr();
+    if (send_header(response_data_c, RInfo) < 0) {
+      delete response_data_c;
+      return;
+    }
+    delete response_data_c;
+  } else {
+    // unknown response
+    cerr << "Error: get_cgihead_info returned an unknown response type.\n";
+    return;
+  }
+
+  textstream.tsbreset();
+  textstream.setrequestinfo (RInfo);
+  
+  if (!recpt.produce_content (args, cout, cerr)) {
+    page_errorcgipage(gsdl_gsdlhome);
+    return;
+  } 
+  recpt.log_cgi_args (args, cerr, empty);
+
+  cout << flush;
+  cerr << flush;
+  
+  libaccessnum++;
+}
+
+static void handle_server_request(char *initialTailStr, 
+				  RequestInfoT *RequestInfo,
+				  RequestFieldsT *RequestFields) {
+  char tmpstr[1024];
+  char tailstr[MAX_URL_SIZE];
+  
+  // do any url adjustments necessary
+  if (strcmp(initialTailStr, "/") == 0) {
+    strcpy (tailstr, "/cgi-bin/gw");
+  } else strcpy (tailstr, initialTailStr);
+  
+  // test to see if this is a library request or a local
+  // file request
+  if ((strncmp(tailstr, "/cgi-bin/gw", 11) == 0) &&
+      ((tailstr[11] == '\0') || (tailstr[11] == '?'))) {
+    // library request
+    
+    // log the difference in access times
+    DWORD thislibaccesstime = GetTickCount();
+    if (gsdl_keep_log||gsdl_show_console) {
+      sprintf(tmpstr, "DELTA LIB ACCESS TIME: %i\n", (int)(thislibaccesstime - lastlibaccesstime));
+      log_message (tmpstr);
+    }
+    lastlibaccesstime = thislibaccesstime;
+    
+    // log this request
+    if (gsdl_keep_log||gsdl_show_console) {
+      sprintf (tmpstr, "LOCAL LIB: %s\n", tailstr);
+      log_message (tmpstr);
+    }
+    
+    handle_library_request (&tailstr[11], RequestInfo, RequestFields);
+    
+    // remember the preferences
+    rememberpref (tailstr);
+    
+    // log memory information
+    if (gsdl_keep_log||gsdl_show_console) {
+      MEMORYSTATUS memstatus;
+      memstatus.dwLength = sizeof(MEMORYSTATUS);
+      GlobalMemoryStatus(&memstatus);
+      sprintf (tmpstr, "BDELTA AVAIL VIRTUAL: %i K\n", 
+	       (int)((baseavailvirtual - memstatus.dwAvailVirtual)/1024));
+      log_message (tmpstr);
+    }
+    
+  } else {
+    // local file
+    if (gsdl_keep_log||gsdl_show_console) {
+      sprintf (tmpstr, "LOCAL FILE: %s\n", tailstr);
+      log_message (tmpstr);
+    }
+    send_file_from_disk (tailstr, RequestInfo, RequestFields);
+  }
+}
+
+static void fix_prefix(char *dest, char *pref, char *suff)
+{
+  strcpy(dest,pref);
+  if (*suff != '/') strcat(dest,"/");
+  if (strlen(dest) + strlen(suff) + 1 > MAX_URL_SIZE)
+    strcpy(dest,"http://gsdl/name-too-long");
+  else
+    strcat(dest,suff);
+}
+
+int ExamineURIStr(char *URIStr,RequestInfoT *RequestInfo,
+		  RequestFieldsT *RequestFields)
+{
+  char *protocol, *machine, *rest;  int port;
+  char URICopyA[MAX_URL_SIZE], URICopyB[MAX_URL_SIZE];
+  strcpy(URICopyA,URIStr);
+  
+  if (parse_url(URICopyA,&protocol,&machine,&port,&rest)!=http_ok) {
+    /* Alter local file request to address 'gsdl' */
+    fix_prefix(URICopyB, "http://gsdl", URIStr);
+    URIStr = URICopyB;
+    strcpy(URICopyA, URICopyB);
+    parse_url(URICopyA,&protocol,&machine,&port,&rest);
+  }
+
+  if (strncmp(machine, "gsdl", 5) == 0) {
+    // a local file request
+    handle_server_request(rest, RequestInfo, RequestFields);
+    
+  } else {
+    send_retrieve_error(404, "File not found",
+			"Could not find the local file requested", RequestInfo);
+  }
+  
+  return 1;
+}
Index: /main/tags/2.25/gsdl/src/w32server/cgiwrapper.h
===================================================================
--- /main/tags/2.25/gsdl/src/w32server/cgiwrapper.h	(revision 21064)
+++ /main/tags/2.25/gsdl/src/w32server/cgiwrapper.h	(revision 21064)
@@ -0,0 +1,51 @@
+/**********************************************************************
+ *
+ * cgiwrapper.h -- windows local library cgiwrapper
+ * Copyright (C) 1999  The New Zealand Digital Library Project
+ *
+ * A component of the Greenstone digital library software
+ * from the New Zealand Digital Library Project at the
+ * University of Waikato, New Zealand.
+ *
+ * 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.
+ *
+ *********************************************************************/
+
+#ifndef CGIWRAPPER_H
+#define CGIWRAPPER_H
+
+#include "httpreq.h"
+#include "locate.h"
+#include "receptionist.h"
+
+// the number of times the library has been accessed
+extern int libaccessnum;
+
+//void configure_httpprefix ();
+
+int ExamineURIStr(char *URIStr,RequestInfoT *RequestInfo,
+		  RequestFieldsT *RequestFields);
+
+// reads any configure file that has been set up and
+// sets up the library
+// returns 1 if successful, 0 if unsuccessful
+int gsdl_init ();
+
+// returns 0 if the directories cant be found
+// and the user wants to quit (it returns 1
+// if everything is ok)
+int cstrcheckdir (char *cstrthedir);
+
+#endif
Index: /main/tags/2.25/gsdl/src/w32server/conftools.cpp
===================================================================
--- /main/tags/2.25/gsdl/src/w32server/conftools.cpp	(revision 21064)
+++ /main/tags/2.25/gsdl/src/w32server/conftools.cpp	(revision 21064)
@@ -0,0 +1,55 @@
+/**********************************************************************
+ *
+ * conftools.cpp
+ * Copyright (C) 1999  The New Zealand Digital Library Project
+ *
+ * A component of the Greenstone digital library software
+ * from the New Zealand Digital Library Project at the
+ * University of Waikato, New Zealand.
+ *
+ * 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.
+ *
+ *********************************************************************/
+
+#include "text_t.h"
+#include "conftools.h"
+
+int write_confline (ofstream &fileout, const text_t &key, const text_t value) {
+  if (key.empty() || value.empty()) return -1;
+  outconvertclass text_t2ascii;
+  fileout << text_t2ascii << key << "=" << value << "\n";
+  return 0;
+}
+
+int get_confline (ifstream &filein, text_t &key, text_t &value) {
+  if (filein.eof()) return -1;
+
+  key.clear();
+  value.clear();
+  char c;
+  filein.get(c);
+
+  int foundeq = 0;
+  while (!filein.eof() && c != '\n') {
+    if (!foundeq && c == '=') {foundeq = 1; filein.get(c);}
+
+    if (foundeq) value.push_back(c);
+    else key.push_back(c);
+    filein.get(c);
+  }
+  if (key.empty()) return -1;
+  return 0;
+} 
+
Index: /main/tags/2.25/gsdl/src/w32server/conftools.h
===================================================================
--- /main/tags/2.25/gsdl/src/w32server/conftools.h	(revision 21064)
+++ /main/tags/2.25/gsdl/src/w32server/conftools.h	(revision 21064)
@@ -0,0 +1,40 @@
+/**********************************************************************
+ *
+ * conftools.h
+ * Copyright (C) 1999  The New Zealand Digital Library Project
+ *
+ * A component of the Greenstone digital library software
+ * from the New Zealand Digital Library Project at the
+ * University of Waikato, New Zealand.
+ *
+ * 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.
+ *
+ *********************************************************************/
+
+#ifndef CONFTOOLS_H
+#define CONFTOOLS_H
+
+#if defined (GSDL_USE_OBJECTSPACE)
+#include <ospace/std/fstream>
+#elif defined (GSDL_USE_IOS_H)
+#include <fstream.h>
+#else
+#include <fstream>
+#endif
+
+int write_confline (ofstream &fileout, const text_t &key, const text_t value);
+int get_confline (ifstream &filein, text_t &key, text_t &value);
+
+#endif
Index: /main/tags/2.25/gsdl/src/w32server/d_winsock.cpp
===================================================================
--- /main/tags/2.25/gsdl/src/w32server/d_winsock.cpp	(revision 21064)
+++ /main/tags/2.25/gsdl/src/w32server/d_winsock.cpp	(revision 21064)
@@ -0,0 +1,642 @@
+#include <windows.h>
+#include "d_winsock.h"
+
+
+typedef SOCKET (PASCAL FAR *accept_Type)(SOCKET s, struct sockaddr FAR *addr, 
+					 int FAR *addrlen);
+typedef int (PASCAL FAR *bind_Type)(SOCKET s, const struct sockaddr FAR *addr, int namelen);
+typedef int (PASCAL FAR *closesocket_Type)(SOCKET s);
+typedef int (PASCAL FAR *connect_Type)(SOCKET s, const struct sockaddr FAR *name, 
+				       int namelen);
+typedef int (PASCAL FAR *ioctlsocket_Type)(SOCKET s, long cmd, u_long FAR *argp);
+typedef int (PASCAL FAR *getpeername_Type)(SOCKET s, struct sockaddr FAR *name,
+					   int FAR * namelen);
+typedef int (PASCAL FAR *getsockname_Type)(SOCKET s, struct sockaddr FAR *name,
+					   int FAR * namelen);
+typedef int (PASCAL FAR *getsockopt_Type)(SOCKET s, int level, int optname,
+					  char FAR * optval, int FAR *optlen);
+typedef u_long (PASCAL FAR *htonl_Type)(u_long hostlong);
+typedef u_short (PASCAL FAR *htons_Type)(u_short hostshort);
+typedef unsigned long (PASCAL FAR *inet_addr_Type)(const char FAR * cp);
+typedef char FAR * (PASCAL FAR *inet_ntoa_Type)(struct in_addr in);
+typedef int (PASCAL FAR *listen_Type)(SOCKET s, int backlog);
+typedef u_long (PASCAL FAR *ntohl_Type)(u_long netlong);
+typedef u_short (PASCAL FAR *ntohs_Type)(u_short netshort);
+typedef int (PASCAL FAR *recv_Type)(SOCKET s, char FAR * buf, int len, int flags);
+typedef int (PASCAL FAR *recvfrom_Type)(SOCKET s, char FAR * buf, int len, int flags,
+					struct sockaddr FAR *from, int FAR * fromlen);
+typedef int (PASCAL FAR *select_Type)(int nfds, fd_set FAR *readfds, fd_set FAR *writefds,
+				      fd_set FAR *exceptfds, const struct timeval FAR *timeout);
+typedef int (PASCAL FAR *send_Type)(SOCKET s, const char FAR * buf, int len, int flags);
+typedef int (PASCAL FAR *sendto_Type)(SOCKET s, const char FAR * buf, int len, int flags,
+				      const struct sockaddr FAR *to, int tolen);
+typedef int (PASCAL FAR *setsockopt_Type)(SOCKET s, int level, int optname,
+					  const char FAR * optval, int optlen);
+typedef int (PASCAL FAR *shutdown_Type)(SOCKET s, int how);
+typedef SOCKET (PASCAL FAR *socket_Type)(int af, int type, int protocol);
+typedef struct hostent FAR * (PASCAL FAR *gethostbyaddr_Type)(const char FAR * addr,
+							      int len, int type);
+typedef struct hostent FAR * (PASCAL FAR *gethostbyname_Type)(const char FAR * name);
+typedef int (PASCAL FAR *gethostname_Type) (char FAR * name, int namelen);
+typedef struct servent FAR * (PASCAL FAR *getservbyport_Type)(int port, const char FAR * proto);
+typedef struct servent FAR * (PASCAL FAR *getservbyname_Type)(const char FAR * name,
+							      const char FAR * proto);
+typedef struct protoent FAR * (PASCAL FAR *getprotobynumber_Type)(int proto);
+typedef struct protoent FAR * (PASCAL FAR *getprotobyname_Type)(const char FAR * name);
+typedef int (PASCAL FAR *WSAStartup_Type)(WORD wVersionRequired, LPWSADATA lpWSAData);
+typedef int (PASCAL FAR *WSACleanup_Type)(void);
+typedef void (PASCAL FAR *WSASetLastError_Type)(int iError);
+typedef int (PASCAL FAR *WSAGetLastError_Type)(void);
+typedef BOOL (PASCAL FAR *WSAIsBlocking_Type)(void);
+typedef int (PASCAL FAR *WSAUnhookBlockingHook_Type)(void);
+typedef FARPROC (PASCAL FAR *WSASetBlockingHook_Type)(FARPROC lpBlockFunc);
+typedef int (PASCAL FAR *WSACancelBlockingCall_Type)(void);
+typedef HANDLE (PASCAL FAR *WSAAsyncGetServByName_Type)(HWND hWnd, u_int wMsg,
+							const char FAR * name,
+							const char FAR * proto,
+							char FAR * buf, int buflen);
+typedef HANDLE (PASCAL FAR *WSAAsyncGetServByPort_Type)(HWND hWnd, u_int wMsg, int port,
+							const char FAR * proto, char FAR * buf,
+							int buflen);
+typedef HANDLE (PASCAL FAR *WSAAsyncGetProtoByName_Type)(HWND hWnd, u_int wMsg,
+							 const char FAR * name, char FAR * buf,
+							 int buflen);
+typedef HANDLE (PASCAL FAR *WSAAsyncGetProtoByNumber_Type)(HWND hWnd, u_int wMsg,
+							   int number, char FAR * buf,
+							   int buflen);
+typedef HANDLE (PASCAL FAR *WSAAsyncGetHostByName_Type)(HWND hWnd, u_int wMsg,
+							const char FAR * name, char FAR * buf,
+							int buflen);
+typedef HANDLE (PASCAL FAR *WSAAsyncGetHostByAddr_Type)(HWND hWnd, u_int wMsg,
+							const char FAR * addr, int len, int type,
+							char FAR * buf, int buflen);
+typedef int (PASCAL FAR *WSACancelAsyncRequest_Type)(HANDLE hAsyncTaskHandle);
+typedef int (PASCAL FAR *WSAAsyncSelect_Type)(SOCKET s, HWND hWnd, u_int wMsg,
+					      long lEvent);
+
+
+
+static accept_Type accept_Ptr = NULL;
+static bind_Type bind_Ptr = NULL;
+static closesocket_Type closesocket_Ptr = NULL;
+static connect_Type connect_Ptr = NULL;
+static ioctlsocket_Type ioctlsocket_Ptr = NULL;
+static getpeername_Type getpeername_Ptr = NULL;
+static getsockname_Type getsockname_Ptr = NULL;
+static getsockopt_Type getsockopt_Ptr = NULL;
+static htonl_Type htonl_Ptr = NULL;
+static htons_Type htons_Ptr = NULL;
+static inet_addr_Type inet_addr_Ptr = NULL;
+static inet_ntoa_Type inet_ntoa_Ptr = NULL;
+static listen_Type listen_Ptr = NULL;
+static ntohl_Type ntohl_Ptr = NULL;
+static ntohs_Type ntohs_Ptr = NULL;
+static recv_Type recv_Ptr = NULL;
+static recvfrom_Type recvfrom_Ptr = NULL;
+static select_Type select_Ptr = NULL;
+static send_Type send_Ptr = NULL;
+static sendto_Type sendto_Ptr = NULL;
+static setsockopt_Type setsockopt_Ptr = NULL;
+static shutdown_Type shutdown_Ptr = NULL;
+static socket_Type socket_Ptr = NULL;
+static gethostbyaddr_Type gethostbyaddr_Ptr = NULL;
+static gethostbyname_Type gethostbyname_Ptr = NULL;
+static gethostname_Type gethostname_Ptr = NULL;
+static getservbyport_Type getservbyport_Ptr = NULL;
+static getservbyname_Type getservbyname_Ptr = NULL;
+static getprotobynumber_Type getprotobynumber_Ptr = NULL;
+static getprotobyname_Type getprotobyname_Ptr = NULL;
+static WSAStartup_Type WSAStartup_Ptr = NULL;
+static WSACleanup_Type WSACleanup_Ptr = NULL;
+static WSASetLastError_Type WSASetLastError_Ptr = NULL;
+static WSAGetLastError_Type WSAGetLastError_Ptr = NULL;
+static WSAIsBlocking_Type WSAIsBlocking_Ptr = NULL;
+static WSAUnhookBlockingHook_Type WSAUnhookBlockingHook_Ptr = NULL;
+static WSASetBlockingHook_Type WSASetBlockingHook_Ptr = NULL;
+static WSACancelBlockingCall_Type WSACancelBlockingCall_Ptr = NULL;
+static WSAAsyncGetServByName_Type WSAAsyncGetServByName_Ptr = NULL;
+static WSAAsyncGetServByPort_Type WSAAsyncGetServByPort_Ptr = NULL;
+static WSAAsyncGetProtoByName_Type WSAAsyncGetProtoByName_Ptr = NULL;
+static WSAAsyncGetProtoByNumber_Type WSAAsyncGetProtoByNumber_Ptr = NULL;
+static WSAAsyncGetHostByName_Type WSAAsyncGetHostByName_Ptr = NULL;
+static WSAAsyncGetHostByAddr_Type WSAAsyncGetHostByAddr_Ptr = NULL;
+static WSACancelAsyncRequest_Type WSACancelAsyncRequest_Ptr = NULL;
+static WSAAsyncSelect_Type WSAAsyncSelect_Ptr = NULL;
+
+
+static HINSTANCE wsock32lib = NULL;
+static HINSTANCE winsocklib = NULL;
+
+
+
+// set all the pointers back to null
+static void ResetWSPtrs () {
+  accept_Ptr = NULL;
+  bind_Ptr = NULL;
+  closesocket_Ptr = NULL;
+  connect_Ptr = NULL;
+  ioctlsocket_Ptr = NULL;
+  getpeername_Ptr = NULL;
+  getsockname_Ptr = NULL;
+  getsockopt_Ptr = NULL;
+  htonl_Ptr = NULL;
+  htons_Ptr = NULL;
+  inet_addr_Ptr = NULL;
+  inet_ntoa_Ptr = NULL;
+  listen_Ptr = NULL;
+  ntohl_Ptr = NULL;
+  ntohs_Ptr = NULL;
+  recv_Ptr = NULL;
+  recvfrom_Ptr = NULL;
+  select_Ptr = NULL;
+  send_Ptr = NULL;
+  sendto_Ptr = NULL;
+  setsockopt_Ptr = NULL;
+  shutdown_Ptr = NULL;
+  socket_Ptr = NULL;
+  gethostbyaddr_Ptr = NULL;
+  gethostbyname_Ptr = NULL;
+  gethostname_Ptr = NULL;
+  getservbyport_Ptr = NULL;
+  getservbyname_Ptr = NULL;
+  getprotobynumber_Ptr = NULL;
+  getprotobyname_Ptr = NULL;
+  WSAStartup_Ptr = NULL;
+  WSACleanup_Ptr = NULL;
+  WSASetLastError_Ptr = NULL;
+  WSAGetLastError_Ptr = NULL;
+  WSAIsBlocking_Ptr = NULL;
+  WSAUnhookBlockingHook_Ptr = NULL;
+  WSASetBlockingHook_Ptr = NULL;
+  WSACancelBlockingCall_Ptr = NULL;
+  WSAAsyncGetServByName_Ptr = NULL;
+  WSAAsyncGetServByPort_Ptr = NULL;
+  WSAAsyncGetProtoByName_Ptr = NULL;
+  WSAAsyncGetProtoByNumber_Ptr = NULL;
+  WSAAsyncGetHostByName_Ptr = NULL;
+  WSAAsyncGetHostByAddr_Ptr = NULL;
+  WSACancelAsyncRequest_Ptr = NULL;
+  WSAAsyncSelect_Ptr = NULL;
+}
+
+// get the pointers to all the socket functions
+static void SetupWSPtrs (HINSTANCE socketlib) {
+  if (socketlib == NULL) return;
+
+  accept_Ptr = (accept_Type)GetProcAddress(socketlib,"accept");
+  bind_Ptr = (bind_Type)GetProcAddress(socketlib,"bind");
+  closesocket_Ptr = (closesocket_Type)GetProcAddress(socketlib,"closesocket");
+  connect_Ptr = (connect_Type)GetProcAddress(socketlib,"connect");
+  ioctlsocket_Ptr = (ioctlsocket_Type)GetProcAddress(socketlib,"ioctlsocket");
+  getpeername_Ptr = (getpeername_Type)GetProcAddress(socketlib,"getpeername");
+  getsockname_Ptr = (getsockname_Type)GetProcAddress(socketlib,"getsockname");
+  getsockopt_Ptr = (getsockopt_Type)GetProcAddress(socketlib,"getsockopt");
+  htonl_Ptr = (htonl_Type)GetProcAddress(socketlib,"htonl");
+  htons_Ptr = (htons_Type)GetProcAddress(socketlib,"htons");
+  inet_addr_Ptr = (inet_addr_Type)GetProcAddress(socketlib,"inet_addr");
+  inet_ntoa_Ptr = (inet_ntoa_Type)GetProcAddress(socketlib,"inet_ntoa");
+  listen_Ptr = (listen_Type)GetProcAddress(socketlib,"listen");
+  ntohl_Ptr = (ntohl_Type)GetProcAddress(socketlib,"ntohl");
+  ntohs_Ptr = (ntohs_Type)GetProcAddress(socketlib,"ntohs");
+  recv_Ptr = (recv_Type)GetProcAddress(socketlib,"recv");
+  recvfrom_Ptr = (recvfrom_Type)GetProcAddress(socketlib,"recvfrom");
+  select_Ptr = (select_Type)GetProcAddress(socketlib,"select");
+  send_Ptr = (send_Type)GetProcAddress(socketlib,"send");
+  sendto_Ptr = (sendto_Type)GetProcAddress(socketlib,"sendto");
+  setsockopt_Ptr = (setsockopt_Type)GetProcAddress(socketlib,"setsockopt");
+  shutdown_Ptr = (shutdown_Type)GetProcAddress(socketlib,"shutdown");
+  socket_Ptr = (socket_Type)GetProcAddress(socketlib,"socket");
+  gethostbyaddr_Ptr = (gethostbyaddr_Type)GetProcAddress(socketlib,"gethostbyaddr");
+  gethostbyname_Ptr = (gethostbyname_Type)GetProcAddress(socketlib,"gethostbyname");
+  gethostname_Ptr = (gethostname_Type)GetProcAddress(socketlib,"gethostname");
+  getservbyport_Ptr = (getservbyport_Type)GetProcAddress(socketlib,"getservbyport");
+  getservbyname_Ptr = (getservbyname_Type)GetProcAddress(socketlib,"getservbyname");
+  getprotobynumber_Ptr = (getprotobynumber_Type)GetProcAddress(socketlib,"getprotobynumber");
+  getprotobyname_Ptr = (getprotobyname_Type)GetProcAddress(socketlib,"getprotobyname");
+  WSAStartup_Ptr = (WSAStartup_Type)GetProcAddress(socketlib,"WSAStartup");
+  WSACleanup_Ptr = (WSACleanup_Type)GetProcAddress(socketlib,"WSACleanup");
+  WSASetLastError_Ptr = (WSASetLastError_Type)GetProcAddress(socketlib,"WSASetLastError");
+  WSAGetLastError_Ptr = (WSAGetLastError_Type)GetProcAddress(socketlib,"WSAGetLastError");
+  WSAIsBlocking_Ptr = (WSAIsBlocking_Type)GetProcAddress(socketlib,"WSAIsBlocking");
+  WSAUnhookBlockingHook_Ptr = 
+    (WSAUnhookBlockingHook_Type)GetProcAddress(socketlib,"WSAUnhookBlockingHook");
+  WSASetBlockingHook_Ptr = 
+    (WSASetBlockingHook_Type)GetProcAddress(socketlib,"WSASetBlockingHook");
+  WSACancelBlockingCall_Ptr = 
+    (WSACancelBlockingCall_Type)GetProcAddress(socketlib,"WSACancelBlockingCall");
+  WSAAsyncGetServByName_Ptr = 
+    (WSAAsyncGetServByName_Type)GetProcAddress(socketlib,"WSAAsyncGetServByName");
+  WSAAsyncGetServByPort_Ptr = 
+    (WSAAsyncGetServByPort_Type)GetProcAddress(socketlib,"WSAAsyncGetServByPort");
+  WSAAsyncGetProtoByName_Ptr = 
+    (WSAAsyncGetProtoByName_Type)GetProcAddress(socketlib,"WSAAsyncGetProtoByName");
+  WSAAsyncGetProtoByNumber_Ptr = 
+    (WSAAsyncGetProtoByNumber_Type)GetProcAddress(socketlib,"WSAAsyncGetProtoByNumber");
+  WSAAsyncGetHostByName_Ptr = 
+    (WSAAsyncGetHostByName_Type)GetProcAddress(socketlib,"WSAAsyncGetHostByName");
+  WSAAsyncGetHostByAddr_Ptr = 
+    (WSAAsyncGetHostByAddr_Type)GetProcAddress(socketlib,"WSAAsyncGetHostByAddr");
+  WSACancelAsyncRequest_Ptr = 
+    (WSACancelAsyncRequest_Type)GetProcAddress(socketlib,"WSACancelAsyncRequest");
+  WSAAsyncSelect_Ptr = (WSAAsyncSelect_Type)GetProcAddress(socketlib,"WSAAsyncSelect");
+}
+
+
+
+// expects path to be NULL, a empty string, or a path which ends in a slash
+// returns D_NOERROR on success,
+// D_ERR_UNEXPECTED or D_ERR_LOADFAILED on failure
+int d_LoadWinsock (char *path) {
+  char dllname[2048]; // HARD LIMIT!!!!
+  OSVERSIONINFO osver;
+
+  if ((wsock32lib != NULL) || (winsocklib != NULL)) return D_ERR_UNEXPECTED;
+
+  // set the error mode so that no nasty dialog boxes come
+  // up when things aren't installed
+  int olderrormode = SetErrorMode(SEM_NOOPENFILEERRORBOX|SEM_FAILCRITICALERRORS);
+
+  // get the operating system version information
+  memset(&osver, 0, sizeof(OSVERSIONINFO));
+  osver.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
+  if (!GetVersionEx(&osver)) {
+    SetErrorMode(olderrormode);
+    return D_ERR_UNEXPECTED;
+  }
+
+  // see if we should load winsock before wsock32
+  if ((osver.dwPlatformId == VER_PLATFORM_WIN32s) && (path != NULL)) {
+    strcpy (dllname, path);
+    strcat (dllname, "winsock.dll");
+
+    // attempt to load the library
+    winsocklib = LoadLibrary (dllname);
+    if (winsocklib == NULL) {
+      SetErrorMode(olderrormode);
+      return D_ERR_LOADFAILED;
+    }
+  }
+
+  // attempt to load wsock32
+  int err = D_NOERROR;
+  dllname[0] = '\0';
+  if ((osver.dwPlatformId != VER_PLATFORM_WIN32s) && (path != NULL)) {
+    strcpy (dllname, path);
+  }
+  strcat (dllname, "wsock32.dll");
+  wsock32lib = LoadLibrary (dllname);
+  if (wsock32lib == NULL) err = D_ERR_LOADFAILED;
+  else SetupWSPtrs (wsock32lib);
+
+
+  // perform a few tests
+
+  // first try starting-up (and check the szDescription field)
+  if (err == D_NOERROR) {
+    WSADATA Data;
+    memset(&Data, 0, sizeof(WSADATA));
+    if ((d_WSAStartup(257, &Data) != 0) ||
+	(Data.szDescription == NULL) || 
+	(Data.szDescription[0] == '\0'))
+      err = D_ERR_LOADFAILED;
+  }
+
+  // next try setting and getting an error
+  if (err == D_NOERROR) {
+    d_WSASetLastError (WSAENOTSOCK);
+    if (d_WSAGetLastError () != WSAENOTSOCK) err = D_ERR_LOADFAILED;
+    d_WSASetLastError (0);
+  }
+
+  // last try cleaning up (if an error occurs here we might
+  // not be able to unload anything)
+  if ((err == D_NOERROR) && (d_WSACleanup() == SOCKET_ERROR))
+    err = D_ERR_LOADFAILED;
+
+  // if an error occurred then we need to unload everything
+  if (err != D_NOERROR) d_UnloadWinsock ();
+
+  SetErrorMode(olderrormode);
+  return err;
+}
+
+// returns D_NOERROR on success,
+// D_ERR_FREELIBFAILED on failure
+int d_UnloadWinsock () {
+  int err = D_NOERROR;
+
+  // unload wsock32
+  if ((wsock32lib != NULL) && !FreeLibrary (wsock32lib)) {
+    err = D_ERR_FREELIBFAILED;
+  }
+  wsock32lib = NULL;
+
+  // unload winsock
+  if ((winsocklib != NULL) && !FreeLibrary (winsocklib)) {
+    err = D_ERR_FREELIBFAILED;
+  }
+  winsocklib = NULL;
+  
+  // reset all the function pointers
+  ResetWSPtrs ();
+
+  return err;
+}
+
+
+
+
+// socket functions, these just call the dynamically loaded version
+
+SOCKET d_accept (SOCKET s, struct sockaddr *addr, int *addrlen) {
+  if (accept_Ptr != NULL) 
+    return (*accept_Ptr)(s, addr, addrlen);
+  return INVALID_SOCKET; // error winsock not loaded
+}
+
+int d_bind (SOCKET s, const struct sockaddr *addr, int namelen) {
+  if (bind_Ptr != NULL) 
+    return (*bind_Ptr)(s, addr, namelen);
+  return WSANOTINITIALISED; // error winsock not loaded
+}
+
+int d_closesocket (SOCKET s) {
+  if (closesocket_Ptr != NULL) 
+    return (*closesocket_Ptr)(s);
+  return SOCKET_ERROR; // error winsock not loaded
+}
+
+int d_connect (SOCKET s, const struct sockaddr *name, int namelen) {
+  if (connect_Ptr != NULL) 
+    return (*connect_Ptr)(s, name, namelen);
+  return SOCKET_ERROR; // error winsock not loaded
+}
+
+int d_ioctlsocket (SOCKET s, long cmd, u_long *argp) {
+  if (ioctlsocket_Ptr != NULL) 
+    return (*ioctlsocket_Ptr)(s, cmd, argp);
+  return SOCKET_ERROR; // error winsock not loaded
+}
+
+int d_getpeername (SOCKET s, struct sockaddr *name, int *namelen) {
+  if (getpeername_Ptr != NULL) 
+    return (*getpeername_Ptr)(s, name, namelen);
+  return SOCKET_ERROR; // error winsock not loaded
+}
+
+int d_getsockname (SOCKET s, struct sockaddr *name, int *namelen) {
+  if (getsockname_Ptr != NULL) 
+    return (*getsockname_Ptr)(s, name, namelen);
+  return SOCKET_ERROR; // error winsock not loaded
+}
+
+int d_getsockopt (SOCKET s, int level, int optname, char *optval, int *optlen) {
+  if (getsockopt_Ptr != NULL) 
+    return (*getsockopt_Ptr)(s, level, optname, optval, optlen);
+  return SOCKET_ERROR; // error winsock not loaded
+}
+
+u_long d_htonl (u_long hostlong) {
+  if (htonl_Ptr != NULL) 
+    return (*htonl_Ptr)(hostlong);
+  return hostlong; // error winsock not loaded
+}
+
+u_short d_htons (u_short hostshort) {
+  if (htons_Ptr != NULL) 
+    return (*htons_Ptr)(hostshort);
+  return hostshort; // error winsock not loaded
+}
+
+unsigned long d_inet_addr (const char *cp) {
+  if (inet_addr_Ptr != NULL) 
+    return (*inet_addr_Ptr)(cp);
+  return INADDR_NONE; // error winsock not loaded
+}
+
+char *d_inet_ntoa (struct in_addr in) {
+  if (inet_ntoa_Ptr != NULL) 
+    return (*inet_ntoa_Ptr)(in);
+  return NULL; // error winsock not loaded
+}
+
+int d_listen (SOCKET s, int backlog) {
+  if (listen_Ptr != NULL) 
+    return (*listen_Ptr)(s, backlog);
+  return SOCKET_ERROR; // error winsock not loaded
+}
+
+u_long d_ntohl (u_long netlong) {
+  if (ntohl_Ptr != NULL) 
+    return (*ntohl_Ptr)(netlong);
+  return netlong; // error winsock not loaded
+}
+
+u_short d_ntohs (u_short netshort) {
+  if (ntohs_Ptr != NULL) 
+    return (*ntohs_Ptr)(netshort);
+  return netshort; // error winsock not loaded
+}
+
+int d_recv (SOCKET s, char *buf, int len, int flags) {
+  if (recv_Ptr != NULL) 
+    return (*recv_Ptr)(s, buf, len, flags);
+  return SOCKET_ERROR; // error winsock not loaded
+}
+
+int d_recvfrom (SOCKET s, char *buf, int len, int flags,
+		struct sockaddr *from, int *fromlen) {
+  if (recvfrom_Ptr != NULL) 
+    return (*recvfrom_Ptr)(s, buf, len, flags, from, fromlen);
+  return SOCKET_ERROR; // error winsock not loaded
+}
+
+int d_select (int nfds, fd_set *readfds, fd_set *writefds,
+	      fd_set *exceptfds, const struct timeval *timeout) {
+  if (select_Ptr != NULL) 
+    return (*select_Ptr)(nfds, readfds, writefds, exceptfds, timeout);
+  return SOCKET_ERROR; // error winsock not loaded
+}
+
+int d_send (SOCKET s, const char *buf, int len, int flags) {
+  if (send_Ptr != NULL) 
+    return (*send_Ptr)(s, buf, len, flags);
+  return SOCKET_ERROR; // error winsock not loaded
+}
+
+int d_sendto (SOCKET s, const char *buf, int len, int flags,
+	      const struct sockaddr *to, int tolen) {
+  if (sendto_Ptr != NULL) 
+    return (*sendto_Ptr)(s, buf, len, flags, to, tolen);
+  return SOCKET_ERROR; // error winsock not loaded
+}
+
+int d_setsockopt (SOCKET s, int level, int optname,
+		  const char *optval, int optlen) {
+  if (setsockopt_Ptr != NULL) 
+    return (*setsockopt_Ptr)(s, level, optname, optval, optlen);
+  return SOCKET_ERROR; // error winsock not loaded
+}
+
+int d_shutdown (SOCKET s, int how) {
+  if (shutdown_Ptr != NULL) 
+    return (*shutdown_Ptr)(s, how);
+  return SOCKET_ERROR; // error winsock not loaded
+}
+
+SOCKET d_socket (int af, int type, int protocol) {
+  if (socket_Ptr != NULL) 
+    return (*socket_Ptr)(af, type, protocol);
+  return INVALID_SOCKET; // error winsock not loaded
+}
+
+hostent *d_gethostbyaddr(const char *addr, int len, int type) {
+  if (gethostbyaddr_Ptr != NULL) 
+    return (*gethostbyaddr_Ptr)(addr, len, type);
+  return NULL; // error winsock not loaded
+}
+
+hostent *d_gethostbyname(const char *name) {
+  if (gethostbyname_Ptr != NULL) 
+    return (*gethostbyname_Ptr)(name);
+  return NULL; // error winsock not loaded
+}
+
+int d_gethostname (char *name, int namelen) {
+  if (gethostname_Ptr != NULL) 
+    return (*gethostname_Ptr)(name, namelen);
+  return SOCKET_ERROR; // error winsock not loaded
+}
+
+servent *d_getservbyport(int port, const char *proto) {
+  if (getservbyport_Ptr != NULL) 
+    return (*getservbyport_Ptr)(port, proto);
+  return NULL; // error winsock not loaded
+}
+
+servent *d_getservbyname(const char *name, const char *proto) {
+  if (getservbyname_Ptr != NULL) 
+    return (*getservbyname_Ptr)(name, proto);
+  return NULL; // error winsock not loaded
+}
+
+protoent *d_getprotobynumber(int proto) {
+  if (getprotobynumber_Ptr != NULL) 
+    return (*getprotobynumber_Ptr)(proto);
+  return NULL; // error winsock not loaded
+}
+
+protoent *d_getprotobyname(const char *name) {
+  if (getprotobyname_Ptr != NULL) 
+    return (*getprotobyname_Ptr)(name);
+  return NULL; // error winsock not loaded
+}
+
+int d_WSAStartup(WORD wVersionRequired, LPWSADATA lpWSAData) {
+  if (WSAStartup_Ptr != NULL) 
+    return (*WSAStartup_Ptr)(wVersionRequired, lpWSAData);
+  return WSASYSNOTREADY; // error winsock not loaded
+}
+
+int d_WSACleanup(void) {
+  if (WSACleanup_Ptr != NULL) 
+    return (*WSACleanup_Ptr)();
+  return WSANOTINITIALISED; // error winsock not loaded
+}
+
+void d_WSASetLastError(int iError) {
+  if (WSASetLastError_Ptr != NULL) (*WSASetLastError_Ptr)(iError);
+}
+
+int d_WSAGetLastError(void) {
+  if (WSAGetLastError_Ptr != NULL) 
+    return (*WSAGetLastError_Ptr)();
+  return WSANOTINITIALISED; // error winsock not loaded
+}
+
+BOOL d_WSAIsBlocking(void) {
+  if (WSAIsBlocking_Ptr != NULL) 
+    return (*WSAIsBlocking_Ptr)();
+  return FALSE; // error winsock not loaded
+}
+
+int d_WSAUnhookBlockingHook(void) {
+  if (WSAUnhookBlockingHook_Ptr != NULL) 
+    return (*WSAUnhookBlockingHook_Ptr)();
+  return SOCKET_ERROR; // error winsock not loaded
+}
+
+FARPROC d_WSASetBlockingHook(FARPROC lpBlockFunc) {
+  if (WSASetBlockingHook_Ptr != NULL) 
+    return (*WSASetBlockingHook_Ptr)(lpBlockFunc);
+  return NULL; // error winsock not loaded
+}
+
+int d_WSACancelBlockingCall(void) {
+  if (WSACancelBlockingCall_Ptr != NULL) 
+    return (*WSACancelBlockingCall_Ptr)();
+  return SOCKET_ERROR; // error winsock not loaded
+}
+
+HANDLE d_WSAAsyncGetServByName(HWND hWnd, u_int wMsg,
+			       const char *name,
+			       const char *proto,
+			       char *buf, int buflen) {
+  if (WSAAsyncGetServByName_Ptr != NULL) 
+    return (*WSAAsyncGetServByName_Ptr)(hWnd, wMsg, name, proto, buf, buflen);
+  return NULL; // error winsock not loaded
+}
+
+HANDLE d_WSAAsyncGetServByPort(HWND hWnd, u_int wMsg, int port,
+			       const char *proto, char *buf,
+			       int buflen) {
+  if (WSAAsyncGetServByPort_Ptr != NULL) 
+    return (*WSAAsyncGetServByPort_Ptr)(hWnd, wMsg, port, proto, buf, buflen);
+  return NULL; // error winsock not loaded
+}
+
+HANDLE d_WSAAsyncGetProtoByName(HWND hWnd, u_int wMsg,
+				const char *name, char *buf,
+				int buflen) {
+  if (WSAAsyncGetProtoByName_Ptr != NULL) 
+    return (*WSAAsyncGetProtoByName_Ptr)(hWnd, wMsg, name, buf, buflen);
+  return NULL; // error winsock not loaded
+}
+
+HANDLE d_WSAAsyncGetProtoByNumber(HWND hWnd, u_int wMsg,
+				  int number, char *buf,
+				  int buflen) {
+  if (WSAAsyncGetProtoByNumber_Ptr != NULL) 
+    return (*WSAAsyncGetProtoByNumber_Ptr)(hWnd, wMsg, number, buf, buflen);
+  return NULL; // error winsock not loaded
+}
+
+HANDLE d_WSAAsyncGetHostByName(HWND hWnd, u_int wMsg,
+			       const char *name, char *buf,
+			       int buflen) {
+  if (WSAAsyncGetHostByName_Ptr != NULL) 
+    return (*WSAAsyncGetHostByName_Ptr)(hWnd, wMsg, name, buf, buflen);
+  return NULL; // error winsock not loaded
+}
+
+HANDLE d_WSAAsyncGetHostByAddr(HWND hWnd, u_int wMsg,
+                                        const char *addr, int len, int type,
+                                        char *buf, int buflen) {
+  if (WSAAsyncGetHostByAddr_Ptr != NULL) 
+    return (*WSAAsyncGetHostByAddr_Ptr)(hWnd, wMsg, addr, len, type, buf, buflen);
+  return NULL; // error winsock not loaded
+}
+
+int d_WSACancelAsyncRequest(HANDLE hAsyncTaskHandle) {
+  if (WSACancelAsyncRequest_Ptr != NULL) 
+    return (*WSACancelAsyncRequest_Ptr)(hAsyncTaskHandle);
+  return SOCKET_ERROR; // error winsock not loaded
+}
+
+int d_WSAAsyncSelect(SOCKET s, HWND hWnd, u_int wMsg,
+                               long lEvent) {
+  if (WSAAsyncSelect_Ptr != NULL) 
+    return (*WSAAsyncSelect_Ptr)(s, hWnd, wMsg, lEvent);
+  return SOCKET_ERROR; // error winsock not loaded
+}
+
Index: /main/tags/2.25/gsdl/src/w32server/d_winsock.h
===================================================================
--- /main/tags/2.25/gsdl/src/w32server/d_winsock.h	(revision 21064)
+++ /main/tags/2.25/gsdl/src/w32server/d_winsock.h	(revision 21064)
@@ -0,0 +1,103 @@
+#ifndef D_WINSOCK_H
+#define D_WINSOCK_H
+
+
+/* get most definitions from the real winsock */
+#include <winsock.h>
+
+
+#define D_NOERROR           0
+#define D_ERR_UNEXPECTED    1
+#define D_ERR_LOADFAILED    2
+#define D_ERR_FREELIBFAILED 3
+
+
+
+// d_LoadWinsock must be called before an normal winsock
+// functions
+
+
+// expects path to be NULL, a empty string, or a path which ends in a slash
+// returns D_NOERROR on success,
+// D_ERR_UNEXPECTED or D_ERR_LOADFAILED on failure
+int d_LoadWinsock (char *path);
+
+// returns D_NOERROR on success,
+// D_ERR_FREELIBFAILED on failure
+int d_UnloadWinsock ();
+
+
+// dynamically loaded versions of the winsock functions
+
+SOCKET d_accept (SOCKET s, struct sockaddr *addr, int *addrlen);
+int d_bind (SOCKET s, const struct sockaddr *addr, int namelen);
+int d_closesocket (SOCKET s);
+int d_connect (SOCKET s, const struct sockaddr *name, int namelen);
+int d_ioctlsocket (SOCKET s, long cmd, u_long *argp);
+int d_getpeername (SOCKET s, struct sockaddr *name, int *namelen);
+int d_getsockname (SOCKET s, struct sockaddr *name, int *namelen);
+int d_getsockopt (SOCKET s, int level, int optname, char *optval, int *optlen);
+u_long d_htonl (u_long hostlong);
+u_short d_htons (u_short hostshort);
+unsigned long d_inet_addr (const char *cp);
+char *d_inet_ntoa (struct in_addr in);
+int d_listen (SOCKET s, int backlog);
+u_long d_ntohl (u_long netlong);
+u_short d_ntohs (u_short netshort);
+int d_recv (SOCKET s, char *buf, int len, int flags);
+int d_recvfrom (SOCKET s, char *buf, int len, int flags,
+		struct sockaddr *from, int *fromlen);
+int d_select (int nfds, fd_set *readfds, fd_set *writefds,
+	      fd_set *exceptfds, const struct timeval *timeout);
+int d_send (SOCKET s, const char *buf, int len, int flags);
+int d_sendto (SOCKET s, const char *buf, int len, int flags,
+	      const struct sockaddr *to, int tolen);
+int d_setsockopt (SOCKET s, int level, int optname,
+		  const char *optval, int optlen);
+int d_shutdown (SOCKET s, int how);
+SOCKET d_socket (int af, int type, int protocol);
+
+hostent *d_gethostbyaddr(const char *addr, int len, int type);
+hostent *d_gethostbyname(const char *name);
+int d_gethostname (char *name, int namelen);
+servent *d_getservbyport(int port, const char *proto);
+servent *d_getservbyname(const char *name, const char *proto);
+protoent *d_getprotobynumber(int proto);
+protoent *d_getprotobyname(const char *name);
+
+int d_WSAStartup(WORD wVersionRequired, LPWSADATA lpWSAData);
+int d_WSACleanup(void);
+void d_WSASetLastError(int iError);
+int d_WSAGetLastError(void);
+BOOL d_WSAIsBlocking(void);
+int d_WSAUnhookBlockingHook(void);
+FARPROC d_WSASetBlockingHook(FARPROC lpBlockFunc);
+int d_WSACancelBlockingCall(void);
+HANDLE d_WSAAsyncGetServByName(HWND hWnd, u_int wMsg,
+			       const char *name,
+			       const char *proto,
+			       char *buf, int buflen);
+HANDLE d_WSAAsyncGetServByPort(HWND hWnd, u_int wMsg, int port,
+			       const char *proto, char *buf,
+			       int buflen);
+HANDLE d_WSAAsyncGetProtoByName(HWND hWnd, u_int wMsg,
+				const char *name, char *buf,
+				int buflen);
+HANDLE d_WSAAsyncGetProtoByNumber(HWND hWnd, u_int wMsg,
+				  int number, char *buf,
+				  int buflen);
+HANDLE d_WSAAsyncGetHostByName(HWND hWnd, u_int wMsg,
+			       const char *name, char *buf,
+			       int buflen);
+HANDLE d_WSAAsyncGetHostByAddr(HWND hWnd, u_int wMsg,
+			       const char *addr, int len, int type,
+			       char *buf, int buflen);
+int d_WSACancelAsyncRequest(HANDLE hAsyncTaskHandle);
+int d_WSAAsyncSelect(SOCKET s, HWND hWnd, u_int wMsg,
+		     long lEvent);
+
+
+
+
+
+#endif
Index: /main/tags/2.25/gsdl/src/w32server/fnord.cpp
===================================================================
--- /main/tags/2.25/gsdl/src/w32server/fnord.cpp	(revision 21064)
+++ /main/tags/2.25/gsdl/src/w32server/fnord.cpp	(revision 21064)
@@ -0,0 +1,1063 @@
+/*
+Copyright (C) 1996
+
+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.
+
+The author can be contacted via Email at bmorin@wpi.edu
+*/
+#include "text_t.h"
+#include <windows.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <memory.h>
+#pragma hdrstop
+#include "netio.h"
+#include "settings.h"
+#include "httpsrv.h"
+#include "resource.h"
+#include "locate.h"
+#include "cgiwrapper.h"
+#include "startbrowser.h"
+#include "d_winsock.h"
+
+#define MAINWINDOWWIDTH 400
+#define MAINWINDOWHEIGHT 200
+
+#define WASTEHEIGHT 44  // Error in ht due to caption and menu bar
+#define WASTEWIDTH 6
+#define SPACERWIDTH 5
+
+// size and position of the collection title
+#define COLTITLEWIDTH 351
+#define COLTITLEHEIGHT 35
+#define COLTITLEX ((MAINWINDOWWIDTH-COLTITLEWIDTH)/2)
+#define COLTITLEY 10
+
+// size and position of the version string
+#define VERSIONWIDTH MAINWINDOWWIDTH
+#define VERSIONHEIGHT 20
+#define VERSIONX 0
+#define VERSIONY (COLTITLEY+COLTITLEHEIGHT)
+
+// size and position of the Greenstone digital library logo
+#define LOGOWIDTH 135
+#define LOGOHEIGHT 55
+#define LOGOX (MAINWINDOWWIDTH-(LOGOWIDTH+SPACERWIDTH))
+#define LOGOY (MAINWINDOWHEIGHT-(LOGOHEIGHT+SPACERWIDTH))
+
+// size and position of the enter button
+#define ENTERBUTTONWIDTH 160
+#define ENTERBUTTONHEIGHT 30
+#define ENTERBUTTONX SPACERWIDTH
+#define ENTERBUTTONY ((MAINWINDOWHEIGHT-(LOGOHEIGHT+SPACERWIDTH))-(ENTERBUTTONHEIGHT+SPACERWIDTH))
+
+// size and position of the enter string
+#define ENTERSTRINGX (ENTERBUTTONX+ENTERBUTTONWIDTH+SPACERWIDTH)
+#define ENTERSTRINGY ENTERBUTTONY
+#define ENTERSTRINGWIDTH (MAINWINDOWWIDTH-(ENTERBUTTONWIDTH+SPACERWIDTH+SPACERWIDTH+SPACERWIDTH))
+#define ENTERSTRINGHEIGHT ENTERBUTTONHEIGHT
+
+// size and position of the info string
+#define INFOWIDTH MAINWINDOWWIDTH
+#define INFOHEIGHT (MAINWINDOWHEIGHT-INFOY)
+#define INFOX 0
+#define INFOY ENTERBUTTONY
+
+// size and position of restricted buttons
+#define ALTERNATIVEBUTTONWIDTH 160
+#define ALTERNATIVEBUTTONHEIGHT 30
+#define ALTERNATIVEBUTTONX SPACERWIDTH
+#define ALTERNATIVEBUTTONY LOGOY
+
+#define INFOBUTTONWIDTH 30
+
+// size and position of restart button
+#define RESTARTBUTTONWIDTH 160
+#define RESTARTBUTTONHEIGHT 30
+#define RESTARTBUTTONX 50
+#define RESTARTBUTTONY (MAINWINDOWHEIGHT-RESTARTBUTTONHEIGHT-15)
+
+
+#define VERSIONSTRING "version x.xx"
+const char versionstring[] = VERSIONSTRING;
+
+const char strnothing[] = "";
+const char strinit[] = "Initialising...";
+const char strsb[] = "Starting browser...";
+const char strrestartlib[] = "Press the 'Restart Library' button to start a browser\n"
+"and enter library";
+const char strenterlib[] = "Press this button to begin using\n"
+"the library";
+const char *enterstring = NULL; // points to the current enter string
+const char *infostring = NULL; // points to the current info string
+
+
+// globals to do with networking and browsers
+int have_networking = 0;
+int netscapeneeded = 0;
+char startbrowserdir[1024] = ""; // HARD LIMIT!!!!!
+
+
+// stats to do with the last time the enter library button was pressed
+// these stats are needed to make suggestions about the proxy
+int enterlib_libaccessnum = -1; // -1 = NA
+DWORD enterlib_time = 0;
+
+
+enum { undefined_window, console_window, plain_window }
+window_state;
+
+HDC coltitledc = NULL;
+HBITMAP defcoltitlebitmap = NULL, coltitlebitmap=NULL;
+
+HDC logodc=NULL;
+HBITMAP deflogobitmap=NULL, logobitmap=NULL;
+
+HWND GoButton = NULL;
+HWND Enter = NULL;
+HWND EnterRestricted = NULL;
+HWND InfoRestricted = NULL;
+int init_type = 0;
+int init_done = 0;
+
+void finish_up() {
+  // remember the current preferences
+  write_settings();
+
+  // Shutdown the HTTP server
+  EndHTTPServer();
+  
+  // Shutdown the main server modules
+  CleanUpNetIO();
+  //    RemoveFnordFromTray();
+  
+  // Unload the wsock32 dll
+  d_UnloadWinsock();
+  
+  // Clean up graphics stuff from window
+  
+  if (defcoltitlebitmap != NULL)
+    SelectObject (coltitledc, defcoltitlebitmap);
+  if (coltitlebitmap != NULL)
+    DeleteObject (coltitlebitmap);
+  if (coltitledc != NULL)
+    DeleteDC (coltitledc);
+  
+  if (deflogobitmap != NULL)
+    SelectObject (logodc, deflogobitmap);
+  if (logobitmap != NULL)
+    DeleteObject (logobitmap);
+  if (logodc != NULL)
+    DeleteDC (logodc);
+  
+  // Shutdown the main window
+  PostQuitMessage(0);
+}
+
+
+int overlap(int left, int top, int right, int bottom,
+            RECT &r2)
+{
+  if (left <= r2.right && r2.left <= right &&
+      top <= r2.bottom && r2.top <= bottom)
+    return 1;
+  else
+    return 0;
+}
+
+
+void paint_window (HDC pdc, RECT &updateRect) {
+  // make sure the various DCs are set up
+  if (coltitledc == NULL) {
+    coltitledc = CreateCompatibleDC(pdc);
+    defcoltitlebitmap = (HBITMAP)SelectObject (coltitledc, coltitlebitmap);
+  }
+  
+  if (logodc == NULL) {
+    logodc = CreateCompatibleDC(pdc);
+    deflogobitmap = (HBITMAP)SelectObject (logodc, logobitmap);
+  }
+
+  // remove any remaining sign of initial buttons
+  if (init_done && (overlap (ENTERBUTTONX, ENTERBUTTONY, ENTERBUTTONX+ENTERBUTTONWIDTH,
+		ALTERNATIVEBUTTONY+ALTERNATIVEBUTTONHEIGHT, updateRect))) {
+    RECT initRect;
+    initRect.left = ENTERBUTTONX;
+    initRect.top = ENTERBUTTONY;
+    initRect.right = ENTERBUTTONX+ENTERBUTTONWIDTH;
+    initRect.bottom = ALTERNATIVEBUTTONY+ALTERNATIVEBUTTONHEIGHT;
+    FillRect(pdc, &initRect, (HBRUSH)GetStockObject(WHITE_BRUSH));
+  }
+
+  // update the collection title if needed
+  if (overlap(COLTITLEX, COLTITLEY,
+	      COLTITLEX+COLTITLEWIDTH, COLTITLEY+COLTITLEHEIGHT, 
+	      updateRect)) {
+    BitBlt (pdc, COLTITLEX, COLTITLEY, 
+	    COLTITLEX+COLTITLEWIDTH, COLTITLEY+COLTITLEHEIGHT,
+	    coltitledc, 0, 0, SRCCOPY);
+  }
+  
+  // update the version string if needed
+  if (overlap (VERSIONX, VERSIONY, 
+	       VERSIONX+VERSIONWIDTH, VERSIONY+VERSIONHEIGHT,
+	       updateRect)) {
+    RECT versionRect;
+    versionRect.left = VERSIONX;
+    versionRect.top = VERSIONY;
+    versionRect.right = VERSIONX+VERSIONWIDTH;
+    versionRect.bottom = VERSIONY+VERSIONHEIGHT;
+    DrawText(pdc, versionstring, -1, &versionRect, DT_CENTER);
+  }
+  
+  // decide what we want to draw
+  if (init_done && gsdl_show_console) {
+    // we want to draw a "console" window
+    if (window_state != console_window ||
+	overlap (text_rect.left, text_rect.top,
+		 text_rect.right, text_rect.bottom,
+		 updateRect)) {
+      refresh_console (pdc);
+    }
+    
+    window_state = console_window;
+    
+  } else {
+    // we want to draw a "plain" window
+    
+    // update the enter string if needed
+    if (overlap (ENTERSTRINGX, ENTERSTRINGY, ENTERSTRINGX+ENTERSTRINGWIDTH, 
+		 ENTERSTRINGY+ENTERSTRINGHEIGHT, updateRect)) {
+
+	RECT enterstringRect;
+	enterstringRect.left = ENTERSTRINGX;
+	enterstringRect.top = ENTERSTRINGY;
+	enterstringRect.right = ENTERSTRINGX+ENTERSTRINGWIDTH;
+	enterstringRect.bottom = ENTERSTRINGY+ENTERSTRINGHEIGHT;
+	FillRect(pdc, &enterstringRect, (HBRUSH)GetStockObject(WHITE_BRUSH));
+
+	if ((enterstring != NULL) && (strlen(enterstring) > 0)) {
+      
+	  int cury = ENTERSTRINGY;
+	  int startline = 0, here = 0;
+	  while (enterstring[here] != '\0') {
+	    if (enterstring[here] < ' ') {
+	      if (here - startline > 0) {
+		// output the text
+		TextOut (pdc, ENTERSTRINGX, cury, 
+			 &enterstring[startline], here-startline);
+		cury += line_spacing;
+	      }
+	      startline = here+1;
+	    }
+	    here++;
+	  }
+	  // output any remaining text
+	  if (here - startline > 0) {
+	    TextOut (pdc, ENTERSTRINGX, cury, &enterstring[startline], here-startline);
+	  }
+	}
+    }
+    
+    window_state = plain_window;
+  }
+  
+  // update the info string if needed
+  if (init_done && !gsdl_show_console && 
+      ((infostring != NULL) && overlap (INFOX, INFOY, 
+					INFOX+INFOWIDTH, INFOY+INFOHEIGHT,
+					updateRect))) {
+    RECT infoRect;
+    infoRect.left = INFOX;
+    infoRect.top = INFOY;
+    infoRect.right = INFOX+INFOWIDTH;
+    infoRect.bottom = INFOY+INFOHEIGHT;
+    FillRect(pdc, &infoRect, (HBRUSH)GetStockObject(WHITE_BRUSH));
+    DrawText(pdc, infostring, -1, &infoRect, DT_CENTER);
+  }
+
+  // update the logo (always)
+  BitBlt (pdc, LOGOX, LOGOY, LOGOX+LOGOWIDTH, LOGOY+LOGOHEIGHT,
+	  logodc, 0, 0, SRCCOPY);
+}
+
+
+void handle_painting (HWND Window) {
+  HDC pdc;  PAINTSTRUCT ps;
+  pdc = BeginPaint(Window, &ps);
+  
+  paint_window (pdc, ps.rcPaint);
+  
+  EndPaint(Window, &ps);
+}
+
+
+// returns 1 on success, 0 otherwise
+int enter_library (HWND Window) {
+  int res;
+  
+  // get the url and attempt to start a browser
+  char *localname = GetLocalName(NULL);
+  if (have_networking) {
+    text_t url = "http://" + text_t(localname);
+    if (gsdl_port_num != 80)
+      url += ":" + text_t(gsdl_port_num);
+    
+    url += gsdl_enterlib;
+
+    // add a unique ending so it will always result in a request
+    text_t::const_iterator it = 
+      findchar (gsdl_enterlib.begin(), gsdl_enterlib.end(), '?');
+    if (it == gsdl_enterlib.end()) url.push_back ('?');
+    else url.push_back ('&');
+    int tcount = GetTickCount();
+    url += "uq=" + text_t(tcount);
+    
+    // remember the library access number for later proxy checking
+    enterlib_libaccessnum = libaccessnum;
+    
+    // do a quick check to make sure we're using netscape when
+    // we should be (it might have been just installed)
+    if (netscapeneeded) gsdl_check_browser_settings (netscapeneeded);
+    
+    char *cstr_url = url.getcstr();
+    if (strlen (startbrowserdir) <= 0) {
+      res = startbrowser (cstr_url, gsdl_browser_exe, NULL);
+      
+    } else res = startbrowser (cstr_url, gsdl_browser_exe, startbrowserdir);
+    
+    delete cstr_url;
+
+  }
+  
+  if (res == SB_NOERROR) {
+    // success !!
+    
+    // remember the time the browser was started for later proxy checking
+    if (have_networking) enterlib_time = GetTickCount();
+    
+    return 1;
+  }
+  
+  // no browser was started
+  enterlib_libaccessnum = -1;
+  
+  if ((res == SB_FAIL_BADFORMAT) || (res == SB_FAIL_NOTFOUND)) {
+    if (!netscapeneeded) { // any browser
+      MessageBox(Window,
+		 "Failed to start your chosen browser. It seems that your\n"
+		 "chosen browser has been removed or corrupted.\n"
+		 "Please check you browser choice by going to the\n"
+		 "'Settings...' item under the 'File' menu.",
+		 "Greenstone Digital Library Software", MB_OK);
+    } else { // netscape used
+      MessageBox(Window,
+		 "Failed to start Netscape. It seems that Netscape has\n"
+		 "been removed or corrupted. You need Netscape\n"
+		 "installed to use the Greenstone Digital Library\n"
+		 "software on non-networked machines.\n\n"
+		 "You can install Netscape by choosing\n"
+		 "'Install Netscape 4.05' from the 'File' menu.",
+		 "Greenstone Digital Library Software", MB_OK);
+    }
+    
+  } else {
+    MessageBox(Window,
+	       "Failed to start your browser. This may have been\n"
+	       "because there was not enough memory available. Shut\n"
+	       "down all other applications you have running, and\n"
+	       "try again.",
+	       "Greenstone Digital Library Software", MB_OK);
+  }
+  
+  return 0; // failed
+}
+
+
+void install_netscape (HWND Window) {
+  char installpath[256];
+  
+  // try to find the browser directory
+  char *gsdlhome = gsdl_gsdlhome.getcstr();
+  strcpy (installpath, gsdlhome); // use gsdlhome to find the CD-ROM drive...
+  delete gsdlhome;
+  
+  // remove any slashes from the pathname
+  int len = strlen (installpath);
+  while ((len > 0) && ((installpath[len-1] == '\\') || (installpath[len-1] == '/'))) {
+    len--;
+  }
+  // remove '\gsdl'
+  len = len - 5;
+  installpath[len] = '\0';
+  
+  strcat (installpath, "\\netscape\\");
+  
+  // check this directory
+  if (!cstrcheckdir(installpath)) {
+    return;
+  }
+  
+  // get the operating system information
+  OSVERSIONINFO osver;
+  memset(&osver, 0, sizeof(OSVERSIONINFO));
+  osver.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
+  GetVersionEx(&osver);
+
+  // get the install program for this operating system
+  if (osver.dwPlatformId == VER_PLATFORM_WIN32s) {
+    strcat (installpath, "n16e405.exe");
+  } else {
+    strcat (installpath, "n32e405.exe");
+  }
+  
+  // run the install program
+  int res = WinExec (installpath, SW_SHOW);
+  if (res == 0) {
+    // out of resources or memory
+    MessageBox (Window,
+		"Did not have enough resources or memory to run the\n"
+		"install program. Try shutting down all other programs\n"
+		"and trying again.",
+		"Greenstone Digital Library Software",
+		MB_OK|MB_APPLMODAL);
+    
+  } else if (res == ERROR_BAD_FORMAT) {
+    // executable image is corrupt -- ????
+    MessageBox (Window,
+		"The install program seems to be corrupt.",
+		"Greenstone Digital Library Software",
+		MB_OK|MB_APPLMODAL);
+    
+  } else if ((res == ERROR_FILE_NOT_FOUND) || (res == ERROR_PATH_NOT_FOUND)) {
+    // couldn't find the executable -- ????
+    MessageBox (Window,
+		"Could not find the install program. Try installing\n"
+		"Netscape from the Greenstone Digital Library\n"
+		"software's install program.",
+		"Greenstone Digital Library Software",
+		MB_OK|MB_APPLMODAL);
+  }
+}
+
+void open_help () {
+  char topdir[256], cmd[256];
+  
+  // try to find the browser directory
+  char *gsdlhome = gsdl_gsdlhome.getcstr();
+  strcpy (topdir, gsdlhome); // use gsdlhome to find the CD-ROM drive...
+  delete gsdlhome;
+  strcpy (cmd, "notepad ");
+  
+  // remove any slashes from the pathname
+  int len = strlen (topdir);
+  while ((len > 0) && ((topdir[len-1] == '\\') || (topdir[len-1] == '/'))) {
+    len--;
+  }
+  // remove the '\gsdl'
+  len = len - 5;
+  topdir[len] = '\0';
+
+  strcat (topdir, "\\README.txt");
+  strcat (cmd, topdir);
+  
+  WinExec (cmd, SW_SHOW);
+}
+
+
+long __stdcall WndProc(HWND Window, UINT Message, WPARAM WParam, LPARAM LParam) {
+  switch(Message) {
+    // Constant Messages
+  case WM_CREATE:
+    break;
+    
+  case WM_COMMAND:
+    if ((GoButton != NULL) && ((HWND)LParam == GoButton)) {
+      // attempt to start a browser
+      if (enter_library (Window) && !gsdl_show_console) 
+    	ShowWindow(Window,SW_MINIMIZE);
+
+    } else if ((Enter != NULL) && ((HWND)LParam == Enter)) {
+      init_done = 1;
+      init_type = 1;
+
+    } else if ((EnterRestricted != NULL) && ((HWND)LParam == EnterRestricted)) {
+      init_done = 1;
+      init_type = 0;
+
+    } else if ((InfoRestricted != NULL) && ((HWND)LParam == InfoRestricted)) {
+      MessageBox (NULL, "The Greenstone system automatically determines whether your computer has\n"
+		  "network software installed or is connected to a network.  It operates correctly\n"
+		  "under any of these conditions.\n\n"
+		  "The restricted version is intended for use when the standard one\n\n"
+		  "   (a) causes an unwanted telephone dialup operation;\n"
+		  "   (b) fails to run because network software is installed, but installed\n"
+		  "         incorrectly.\n\n"
+		  "The restricted version only works with Netscape (not Internet Explorer).\n\n"
+		  "Unless these problems arise, you should always use the standard version\n"
+		  "(press the 'Enter Library' button).\n",
+		  "Greenstone Digital Library Software", 
+		  MB_OK | MB_ICONINFORMATION | MB_APPLMODAL);
+
+    } else {
+      switch (LOWORD(WParam)) {
+      case ID_PROJECT_SETTINGS:
+	Settings_Dialog(Window, netscapeneeded);
+	break;
+      case ID_INSTALL_NETSCAPE:
+	install_netscape(Window);
+	break;
+      case IDHELP:
+	open_help();
+	break;
+      case ID_PROJECT_EXIT:
+        finish_up();
+        break;
+      default:
+        break;
+      }
+    }
+    break;
+    
+  case WM_PAINT:
+    handle_painting(Window);
+    break;
+    
+  case HTTP_SERVER_MSG:
+    ProcessHTTPServerMsg(WParam, LParam);
+    break;
+    
+  case WM_DESTROY:
+    finish_up();
+    break;
+    
+  default:
+    //Unhandled Messages end up here (DefWindowProc)
+    return DefWindowProc(Window, Message, WParam, LParam);
+  }
+  
+  return(0);
+}
+
+// returns 0 if successful,
+// otherwise a WSA error number
+int tryinitnetwork (HANDLE Instance, HWND MsgWindow, char *path) {
+  // try to load winsock
+  int err = d_LoadWinsock (path);
+  
+  if (err == D_NOERROR) {
+    // next, try to init netio
+    err = InitNetIO();
+    
+    if (err == 0) {
+      // next, try to start the http server
+      err = StartHTTPServer(MsgWindow);
+      
+      if (err == 0) {
+	// finally, get the host name (no error value
+	// is returned from this function)
+	GetLocalName((HINSTANCE)Instance);
+	
+      } else {
+	// couldn't start the http server, 
+	// deinit netio and unload winsock
+	CleanUpNetIO();
+	d_UnloadWinsock();
+      }
+      
+    } else {
+      // couldn't init netio, unload winsock
+      d_UnloadWinsock();
+    }
+    
+  } else {
+    // couldn't load winsock
+    err = WSASYSNOTREADY;
+  }
+  
+  return err;
+}
+
+
+// inits all the network functionality
+// returns 0 if an unrecoverable error occurred,
+// and 1 if everything successfully initialised.
+int initnetwork (HANDLE Instance, HWND MsgWindow) {
+  OSVERSIONINFO osver;
+  
+  // get the operating system information
+  memset(&osver, 0, sizeof(OSVERSIONINFO));
+  osver.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
+  GetVersionEx(&osver);
+  
+  // first try to initialise the network with system installed
+  // networking software
+  startbrowserdir[0] = '\0';
+  netscapeneeded = 0;
+  int err = 1;
+  if (init_type == 1) err = tryinitnetwork (Instance, MsgWindow, NULL);
+  
+  // if an error occurred, try again with billsock
+  if (err != 0) {
+    // get the path of billsock (current directory + ("net16" | "net32"))
+    char winsockpath[1024]; // HARD LIMIT!!!!
+    
+    find_location();
+    strcpy (winsockpath, data_location);
+    
+    // remove all the slashes at the end of billpath
+    int len = strlen (winsockpath);
+    while ((len > 0) && ((winsockpath[len-1] == '\\') || (winsockpath[len-1] == '/'))) {
+      len--;
+    }
+    winsockpath[len] = '\0';
+    
+    if (osver.dwPlatformId == VER_PLATFORM_WIN32s)
+      strcat (winsockpath, "\\net16\\");
+    else {
+      strcat (winsockpath, "\\net32\\");
+      strcpy (startbrowserdir, winsockpath);
+    }
+    
+    // try again
+    err = tryinitnetwork (Instance, MsgWindow, winsockpath);
+    
+    if (err == 0) {
+      // we will need to use netscape on 95/98/NT machines
+      if (osver.dwPlatformId != VER_PLATFORM_WIN32s) {
+	netscapeneeded = 1;
+	// make sure the browser state is in step with the network condition
+	gsdl_check_browser_settings (netscapeneeded);
+      }
+      
+      // check to see if a browser is running
+      if (browserrunning(gsdl_browser_exe) == NO_ERROR) {
+	MessageBox (NULL, 
+		    "The Greenstone Digital Library software has detected a\n"
+		    "running browser. To let our networking software\n"
+		    "correctly initialize, please shut down your browser\n"
+		    "and restart the Greenstone Digital Library software.",
+		    "Greenstone Digital Library Software", MB_OK|MB_APPLMODAL);
+	PostMessage(MsgWindow,WM_CLOSE,0,0);
+	finish_up(); // will unload winsock
+	exit(0);      // nothing more to do
+      }
+    }
+  }
+  
+  // if an error occurred display a nice error message
+  if (err != 0) {
+    
+    // WSASYSNOTREADY	Couldn't load winsock
+    // WSAVERNOTSUPPORTED	The version of Windows Sockets support requested 
+    //			is not provided by this particular Windows Sockets implementation.
+    // WSAEINVAL	The Windows Sockets version specified by the application 
+    //			is not supported by this DLL.
+    // WSAEPROTONOSUPPORT	The specified protocol is not supported.
+    // WSAEPROTOTYPE	The specified protocol is the wrong type for this socket.
+    // WSAESOCKTNOSUPPORT	The specified socket type is not supported in 
+    //		this address family.
+    // WSANOTINITIALISED	A successful WSAStartup must occur before 
+    //		using this function.
+    // WSAENETDOWN	The Windows Sockets implementation 
+    //		has detected that the network subsystem has failed.
+    // WSAEADDRINUSE 	The specified address 
+    //		is already in use. (See the SO_REUSEADDR socket option under setsockopt.)
+    // WSAEFAULT	The namelen argument is too small (less 
+    //		than the size of a struct sockaddr).
+    // WSAEINPROGRESS	A blocking Windows Sockets call is in progress.
+    // WSAEAFNOSUPPORT	The specified address family is not supported 
+    //		by this protocol.
+    // WSAENOBUFS	Not enough buffers available, too many connections.
+    // WSAENOTSOCK	The descriptor is not a socket.
+    // WSAEISCONN	The socket is already connected.
+    // WSAEMFILE	No more file descriptors are available.
+    // WSAEOPNOTSUPP	The referenced socket is not of a type that 
+    //		supports the listen operation.
+    
+    // get a text version of the error number
+    char errstr[256];
+    
+    switch (err) {
+    case WSASYSNOTREADY: strcpy(errstr, "WSASYSNOTREADY"); 
+      break;
+    case WSAVERNOTSUPPORTED: strcpy (errstr, "WSAVERNOTSUPPORTED");
+      break;
+    case WSAEINVAL: strcpy (errstr, "WSAEINVAL");
+      break;
+    case WSAEPROTONOSUPPORT: strcpy (errstr, "WSAEPROTONOSUPPORT");
+      break;
+    case WSAEPROTOTYPE: strcpy (errstr, "WSAEPROTOTYPE");
+      break;
+    case WSAESOCKTNOSUPPORT: strcpy (errstr, "WSAESOCKTNOSUPPORT");
+      break;
+    case WSANOTINITIALISED: strcpy (errstr, "WSANOTINITIALISED");
+      break;
+    case WSAEFAULT: strcpy (errstr, "WSAEFAULT");
+      break;
+    case WSAEAFNOSUPPORT: strcpy (errstr, "WSAEAFNOSUPPORT");
+      break;
+    case WSAENOTSOCK: strcpy (errstr, "WSAENOTSOCK");
+      break;
+    case WSAEISCONN: strcpy (errstr, "WSAEISCONN");
+      break;
+    case WSAEOPNOTSUPP: strcpy (errstr, "WSAEOPNOTSUPP");
+      break;
+    case WSAENETDOWN: strcpy (errstr, "WSAENETDOWN");
+      break;
+    case WSAEADDRINUSE: strcpy (errstr, "WSAEADDRINUSE");
+      break;
+    case WSAEINPROGRESS: strcpy (errstr, "WSAEINPROGRESS");
+      break;
+    case WSAENOBUFS: strcpy (errstr, "WSAENOBUFS");
+      break;
+    case WSAEMFILE: strcpy (errstr, "WSAEMFILE");
+      break;
+    default: sprintf (errstr, "WSA ERROR: %i", err);
+      break;
+    }
+    
+    // create a nice error message
+    char message[2048];
+    
+    switch (err) {
+    case WSAEADDRINUSE:
+      // couldn't bind socket
+      sprintf (message, "Could not find a free socket.", errstr);
+      break;
+      
+    default:
+      // cannot init winsock
+      sprintf (message, "Could not initialize the network\n"
+	       " (Reason: %s).", errstr);
+      break;
+    }
+    
+    strcat (message, "\n\n"
+	    "Please submit a bug report using the support.htm file\n"
+	    "on the CD-ROM.");
+    
+    MessageBox (NULL, message, "Greenstone Digital Library Software", MB_OK);
+  }
+  
+  return (err == 0);
+}
+
+
+void log_computer_info () {
+  char tmpstr[1024];
+  
+  // get various information about this computer
+  if (gsdl_keep_log || gsdl_show_console) {
+    // get operating system information
+    OSVERSIONINFO osver;
+    osver.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
+    
+    if (GetVersionEx(&osver)) {
+      if (osver.dwPlatformId == VER_PLATFORM_WIN32s) {
+	log_message ("Platform: win32s\n");
+      } else if (osver.dwPlatformId == VER_PLATFORM_WIN32_WINDOWS) {
+	log_message ("Platform: windows 95\n");
+      } else if (osver.dwPlatformId == VER_PLATFORM_WIN32_NT) {
+	log_message ("Platform: windows NT\n");
+      }
+      
+      sprintf (tmpstr, "MajorVersion: %i\n", (int)osver.dwMajorVersion);
+      log_message(tmpstr);
+      sprintf (tmpstr, "MinorVersion: %i\n", (int)osver.dwMinorVersion);
+      log_message(tmpstr);
+      sprintf (tmpstr, "BuildNumber: %i\n", (int)osver.dwBuildNumber);
+      log_message(tmpstr);
+      sprintf (tmpstr, "CSDVersion: %s\n\n", osver.szCSDVersion);
+      log_message(tmpstr);
+    }
+    
+    // get memory information
+    MEMORYSTATUS memstatus;
+    memstatus.dwLength = sizeof(MEMORYSTATUS);
+    GlobalMemoryStatus(&memstatus);
+    
+    sprintf (tmpstr, "TotalPhys: %i Meg\n", (int)(memstatus.dwTotalPhys/1024/1024));
+    log_message (tmpstr);
+    sprintf (tmpstr, "AvailPhys: %i Meg\n", (int)(memstatus.dwAvailPhys/1024/1024));
+    log_message (tmpstr);
+    sprintf (tmpstr, "TotalPageFile: %i Meg\n", (int)(memstatus.dwTotalPageFile/1024/1024));
+    log_message (tmpstr);
+    sprintf (tmpstr, "AvailPageFile: %i Meg\n", (int)(memstatus.dwAvailPageFile/1024/1024));
+    log_message (tmpstr);
+    sprintf (tmpstr, "TotalVirtual: %i Meg\n", (int)(memstatus.dwTotalVirtual/1024/1024));
+    log_message (tmpstr);
+    sprintf (tmpstr, "AvailVirtual: %i Meg\n\n", (int)(memstatus.dwAvailVirtual/1024/1024));
+    log_message (tmpstr);
+    
+    // log the version number
+    log_message("GSDL version: " VERSIONSTRING "\n");
+  }
+  
+}
+
+
+int __stdcall WinMain(HINSTANCE Instance, HINSTANCE /*PrevInstance*/, LPSTR CmdLineStr, int /*CmdShow*/) {
+  HWND MainWindow;  MSG Message;  WNDCLASS MainClass;  
+  
+  //Create a window class
+  MainClass.style = CS_HREDRAW | CS_VREDRAW;
+  MainClass.lpfnWndProc = WndProc;
+  MainClass.cbClsExtra = 0;
+  MainClass.cbWndExtra = 0;
+  MainClass.hInstance = Instance;
+  MainClass.hIcon     = LoadIcon(Instance, MAKEINTRESOURCE(TRAY_ICON));
+  MainClass.hCursor   = LoadCursor(NULL, IDC_ARROW);
+  MainClass.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH);
+  MainClass.lpszMenuName = MAKEINTRESOURCE(Main_Menu);
+  MainClass.lpszClassName = "Greenstone Digital Library Software";
+  if (!RegisterClass(&MainClass))
+    return 0;
+  
+
+  // Load various bitmaps
+  coltitlebitmap = LoadBitmap (Instance, MAKEINTRESOURCE(GSDL_COL_TITLE));
+  logobitmap= LoadBitmap (Instance, MAKEINTRESOURCE(GSDL_LOGO));
+
+  // Create the main window
+  MainWindow = CreateWindow("Greenstone Digital Library Software", 
+			    "Greenstone Digital Library Software",
+			    WS_OVERLAPPED | WS_CAPTION | WS_SYSMENU |
+			    WS_MINIMIZEBOX,
+			    CW_USEDEFAULT, CW_USEDEFAULT, 
+			    MAINWINDOWWIDTH + WASTEWIDTH, 
+			    MAINWINDOWHEIGHT + WASTEHEIGHT,
+			    NULL, NULL, Instance, NULL);
+  
+  text_rect.left = 0;  
+  text_rect.top = VERSIONY+VERSIONHEIGHT + 5;
+  text_rect.right = MAINWINDOWWIDTH;
+  text_rect.bottom = LOGOY-SPACERWIDTH;
+  
+  window_state = undefined_window;
+  
+  ShowWindow(MainWindow, SW_SHOW); 
+  set_location(CmdLineStr);
+  
+  // get ready to draw the main window
+  RECT windowRect;
+  GetClientRect (MainWindow, &windowRect);
+  HDC pdc = GetDC (MainWindow);
+  
+  // retrieve and save the text metrics
+  TEXTMETRIC tm;
+  GetTextMetrics(pdc, &tm);
+  line_spacing = tm.tmHeight + tm.tmExternalLeading;
+  GSDL_Window = MainWindow;
+  
+  // init various modules
+  read_settings (0); // don't know if netscape is needed at this point
+
+  if (!gsdl_auto_enter) {
+
+    // add the select version checkbox
+    Enter = CreateWindow("BUTTON",             // predefined class 
+			 "Enter Library",      // button text 
+			 WS_VISIBLE | WS_CHILD | WS_TABSTOP | BS_DEFPUSHBUTTON,  // styles 
+			 ENTERBUTTONX,         // starting x position 
+			 ENTERBUTTONY,         // starting y position 
+			 ENTERBUTTONWIDTH,     // button width 
+			 ENTERBUTTONHEIGHT,    // button height 
+			 MainWindow,           // parent window 
+			 NULL,                 // No menu 
+			 Instance, 
+			 NULL);                // pointer not needed 
+    
+    EnterRestricted = CreateWindow("Button",                // predefined class 
+				   "Restricted Version",    // button text 
+				   WS_VISIBLE | WS_CHILD | WS_TABSTOP | BS_PUSHBUTTON,   // styles 
+				   ALTERNATIVEBUTTONX,      // starting x position 
+				   ALTERNATIVEBUTTONY,      // starting y position 
+				   ALTERNATIVEBUTTONWIDTH-(INFOBUTTONWIDTH+SPACERWIDTH),  // button width 
+				   ALTERNATIVEBUTTONHEIGHT, // button height 
+				   MainWindow,              // parent window 
+				   (HMENU)NULL,             // No menu 
+				   Instance, 
+				   NULL);                   // pointer not needed 
+    
+    InfoRestricted = CreateWindow("Button",                // predefined class 
+				  NULL,
+				  WS_VISIBLE | WS_CHILD | WS_TABSTOP | BS_BITMAP,   // styles 
+				  ALTERNATIVEBUTTONWIDTH-INFOBUTTONWIDTH+SPACERWIDTH, // starting x position 
+				  ALTERNATIVEBUTTONY,      // starting y position 
+				  INFOBUTTONWIDTH,         // button width 
+				  ALTERNATIVEBUTTONHEIGHT, // button height 
+				  MainWindow,              // parent window 
+				  (HMENU)NULL,             // No menu 
+				  Instance, 
+				  NULL);                   // pointer not needed 
+
+    HANDLE i_icon = LoadImage (Instance, MAKEINTRESOURCE(GSDL_ICBMP), IMAGE_BITMAP, 
+			       INFOBUTTONWIDTH-4, ALTERNATIVEBUTTONHEIGHT-4, LR_DEFAULTCOLOR);
+    SendMessage (InfoRestricted, BM_SETIMAGE, IMAGE_BITMAP, (LPARAM)i_icon);
+
+    SetFocus (Enter);
+    
+    enterstring = strenterlib;
+    paint_window (pdc, windowRect);
+
+    // message loop for init buttons
+    while (!init_done) {
+      if (PeekMessage(&Message, NULL, 0, 0, PM_REMOVE)) {
+	if (Message.message == WM_QUIT) return Message.wParam;
+	if (!IsDialogMessage (MainWindow, &Message)) {
+	  TranslateMessage(&Message); /* translate keyboard messages */
+	  DispatchMessage(&Message);  /* return control to Windows NT */
+	}
+      } else {
+	Sleep (1);
+      }
+    }
+
+    // don't want these buttons anymore
+    DestroyWindow (Enter);
+    DestroyWindow (EnterRestricted);
+    DestroyWindow (InfoRestricted);
+
+    enterstring = strnothing;
+    paint_window (pdc, windowRect);
+
+  } else {
+    // auto enter is enabled - start up standard version
+    init_type = 1;
+    init_done = 1;
+  }
+
+  // draw the main window containing an init message
+  infostring = strinit;
+  paint_window (pdc, windowRect);
+  DWORD lastcheck = GetTickCount();
+
+  have_networking = initnetwork (Instance, MainWindow);
+  if (!have_networking) {
+    MessageBox(NULL,
+	       "Failed to initialize networking.",
+	       "Greenstone Digital Library Software",MB_OK|MB_SYSTEMMODAL);	
+    exit (0);
+  }
+
+  if (!gsdl_init()) // quit if can't initialise the library correctly
+    exit (0);
+  initstartbrowser();
+  log_computer_info ();
+
+  // show the initialising message for at least 1 second
+  while (DiffTickCounts (lastcheck, GetTickCount()) < 1000) {
+    Sleep (1);
+  }
+  
+  // attempt to start a browser
+  if (gsdl_show_console) infostring = strnothing;
+  else infostring = strsb;
+  paint_window (pdc, windowRect);
+  lastcheck = GetTickCount();
+  if (enter_library (MainWindow) && !gsdl_show_console) {
+    // stay maximised for at least 1 second
+    while (DiffTickCounts (lastcheck, GetTickCount()) < 1000) Sleep (1);
+    ShowWindow(MainWindow,SW_MINIMIZE);
+  }
+  
+  // add the "restart library" button
+  GoButton = CreateWindow("BUTTON",              // predefined class 
+			  "Restart Library",     // button text 
+			  WS_VISIBLE | WS_CHILD | BS_DEFPUSHBUTTON, // styles 
+			  RESTARTBUTTONX,        // starting x position 
+			  RESTARTBUTTONY,        // starting y position 
+			  RESTARTBUTTONWIDTH,    // button width 
+			  RESTARTBUTTONHEIGHT,   // button height 
+			  MainWindow,            // parent window 
+			  NULL,                  // No menu 
+			  Instance, 
+			  NULL);                 // pointer not needed 
+  
+  infostring = strrestartlib;
+  paint_window (pdc, windowRect);
+
+  // release the DC used to display the init messages
+  ReleaseDC (MainWindow, pdc);
+  
+  //Message loop
+  lastcheck = GetTickCount();
+  int seenbrowser = 0;	// if we see a browser then it disappears
+                        // we will ask if they want to close the
+                        // the library down
+  char last_gsdl_browser_exe[MAX_FILENAME_SIZE]; // need to notice when the
+                                                 // browser setting changes
+  strcpy (last_gsdl_browser_exe, gsdl_browser_exe);
+  
+  for (;;) {
+    if (PeekMessage(&Message, NULL, 0, 0, PM_REMOVE)) {
+      if (Message.message == WM_QUIT) break;
+      if (!IsDialogMessage (MainWindow, &Message)) {
+	TranslateMessage(&Message); /* translate keyboard messages */
+	DispatchMessage(&Message);  /* return control to Windows NT */
+      }
+      
+    } else {
+      if (DiffTickCounts (lastcheck, GetTickCount()) > 500) {
+	// make sure the browser hasn't changed
+	if (strcmp (last_gsdl_browser_exe, gsdl_browser_exe) != 0) {
+	  seenbrowser = 0;
+	  strcpy (last_gsdl_browser_exe, gsdl_browser_exe);
+	}
+	
+	// do check
+	lastcheck = GetTickCount();
+	if (browserrunning(gsdl_browser_exe) == NO_ERROR) {
+	  // we were able to connect to a browser
+	  seenbrowser = 1;
+	  
+	  // see if the enter library button has been pressed
+	  // with nothing happening for 20 seconds
+	  if ((enterlib_libaccessnum >= 0) && 
+	      (enterlib_libaccessnum == libaccessnum) &&
+	      (DiffTickCounts (enterlib_time, GetTickCount()) > 20000)) {
+	    // something could be wrong!! (most likely cause is a proxy)
+	    MessageBox(NULL,
+		       "Your browser does not seem to be responding to the 'Enter Library'\n"
+		       "request. Try turning off all proxy servers in your browser settings.",
+		       "Greenstone Digital Library Software",MB_OK|MB_SYSTEMMODAL);
+	    enterlib_libaccessnum = -1;
+	  }
+	  
+	  
+	} else {
+	  // no browser was found
+
+	  if (seenbrowser) {
+	    // we have seen a browser in the past
+	    if (MessageBox(NULL,
+			   "The Greenstone Digital Library software has noticed that you\n"
+			   "shut down your browser. Would you also like to shut down the\n"
+			   "Greenstone Digital Library software?",
+			   "Greenstone Digital Library Software",MB_YESNO|MB_SYSTEMMODAL) == IDYES)
+	      PostMessage(MainWindow,WM_CLOSE,0,0);
+	  }
+	  seenbrowser = 0;
+	}
+      }
+      
+      Sleep (1); // millisecond
+    }
+  }
+  
+  return Message.wParam;
+}
Index: /main/tags/2.25/gsdl/src/w32server/httpreq.cpp
===================================================================
--- /main/tags/2.25/gsdl/src/w32server/httpreq.cpp	(revision 21064)
+++ /main/tags/2.25/gsdl/src/w32server/httpreq.cpp	(revision 21064)
@@ -0,0 +1,440 @@
+/*
+Copyright (C) 1996
+
+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.
+
+The author can be contacted via Email at bmorin@wpi.edu
+*/
+#include "text_t.h"
+#include <windows.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <memory.h>
+#pragma hdrstop
+#include "parse.h"
+#include "netio.h"
+#include "settings.h"
+#include "httpreq.h" //Had to put myself here because of the global types...
+#include "httpsrv.h"
+#include "httpsend.h"
+#include "cgiwrapper.h"
+
+/*
+Implementation Notes:
+
+HTTP field names, method and version strings are converted to upper case
+right after being read from the client in order to allow case insensitive
+string comparisons to be done on them.  Since these fields are worked with a
+lot, this should help performance.
+*/
+
+//Private Data and declarations
+#define IO_BUFFER_SIZE 16384        //16K IO Buffer
+#define MAX_HTTP_LINE_LEN 1024      //Max length of line in a header of 1024
+#define MAX_HTTP_FIELD_NAME_LEN 128 //Max length of name field in line
+#define MAX_HTTP_FIELD_LEN 1024     //Max length of data in line
+
+//Private Function Declarations with Return Contstants
+
+/*
+Function Name: DispatchRequest
+Purpose: Manages having the request parsed, then sent to the right function
+         to send a response or handle an error.
+Parameters:
+         ClientSocket - Socket the client is on
+	 ClientSockAddr - Address of client
+	 AddrLen - Length of address of client
+	 IOBuffer - Pointer to buffer allocated for IO operations
+	 ThreadNum - Number of thread that called this function for debugging purposes
+Notes:   I'm still playing with the keep alive support.  I commented out
+	 the stuff for giving a client a timeout because I was unable to detect
+	 disconnects.
+More Notes: Not sure if this organization will allow me to easily add support
+	    for ISAPI filter DLLs.
+*/
+void DispatchRequest(SOCKET ClientSocket, SOCKADDR_IN ClientSockAddr, int AddrLen, BYTE *IOBuffer);
+
+/*
+Function Name: Get HTTP Headers
+Purpose: Manages having the request parsed, then sent to the right function
+         to send a response or handle an error.
+Parameters:
+	RequestInfo - Request information structure (see httpreq.h)
+	RequestFields - HTTP request fields structure (see httpreq.h)
+Returns: GH_ERROR on error (diconnect, bad data, Windows in a bad mood, etc.)
+			GH_UNKNOWN_VERSION if the version number is not HTTP/0.9 or HTTP/1.x
+			GH_SIMPLE_REQUEST on a properly formated HTTP/0.9 request
+			GH_10_REQUEST on a properly formated HTTP/1.x request
+*/
+int GetHTTPHeaders(RequestInfoT &RequestInfo, RequestFieldsT &RequestFields);
+#define GH_ERROR           -1
+#define GH_UNKNOWN_VERSION  0
+#define GH_SIMPLE_REQUEST   1
+#define GH_10_REQUEST       2
+
+/*
+Function Name: Clean Up HTTP Headers
+Purpose: Cleans up memory dynamicly allocated for headers
+Parameters:
+	RequestInfo - Request information structure (see httpreq.h)
+	RequestFields - HTTP request fields structure (see httpreq.h)
+Returns: Nothing
+*/
+void CleanUpHTTPHeaders(RequestInfoT &RequestInfo, RequestFieldsT &RequestFields);
+
+/*
+Function Name: Split Query
+Purpose: Splits the file and query part of a URI.  In other words, it
+	 puts the parts before and after the "?" in differnet strings.
+Parameters:
+	 URIStr - The requested URI
+	 FileStr - String to contain the name of the path + file part of the URI
+	 QueryStr - String to contain the query part of the URI
+Returns: TRUE if there is a query, else FALSE
+*/
+BOOL SplitQuery(char *URIStr, char *FileStr, char *QueryStr, int ThreadNum);
+
+/*
+Function Name: Get File
+Purpose: Attempts to find a given file, including looking for index.html.
+	 Updates the given URI string so it points to the true document location
+Parameters:
+	 FilePath - Path of file, may be modified to best reflect the retrived file
+				  or directory
+	 URIStr - URI string, minus the query
+Returns: GF_ERROR on error
+			GF_FILE_FOUND on success
+			GF_INDEX_FOUND if file is a directory with an index.html file in it
+			GF_DIRECTORY if file is a directory
+			GF_FILE_NOT_FOUND if file was found
+*/
+
+/*
+Function Name: Process Simple Request
+Purpose: Sends a reply to a HTTP 0.9 "simple" request
+Parameters:
+	ClientSocket - Socket the client is on
+	RequestInfo - Structure storing the parsed headers
+	IOBuffer - Pointer to buffer allocated for IO operations
+	TheadNum - Number of calling thread for debugging
+Notes: I should really test this and see if it works...
+*/
+void ProcessSimpleRequest(RequestInfoT &RequestInfo, RequestFieldsT &RequestFields);
+
+//Public Functions
+/******************************************************************************/
+void RequestThread(RequestThreadMessageT *Parameters) {
+  SOCKADDR_IN ClientSockAddr;
+  SOCKET ClientSocket;
+  int AddrLen;
+  //Allocate an IO buffer for this thread
+  BYTE *IOBuffer = new BYTE[IO_BUFFER_SIZE];
+
+  //Get the parameters for the request
+  ClientSocket = Parameters->ClientSocket;
+  ClientSockAddr = Parameters->ClientSockAddr;
+  AddrLen = Parameters->AddrLen;
+  DispatchRequest(ClientSocket, ClientSockAddr, AddrLen, IOBuffer);
+}
+/******************************************************************************/
+
+//Private Functions
+
+/******************************************************************************/
+void DispatchRequest(SOCKET ClientSocket, SOCKADDR_IN ClientSockAddr, int AddrLen,  BYTE *IOBuffer) {
+  RequestInfoT RequestInfo;
+  RequestFieldsT RequestFields;
+
+  // TrayAddConnection();
+
+  //Setup the RequestInfo structure
+  memset(&RequestInfo, 0, sizeof(RequestInfoT));
+  RequestInfo.ThreadNum = 0;
+  RequestInfo.IOBuffer = IOBuffer;
+  RequestInfo.IOBufferSize = IO_BUFFER_SIZE;
+  RequestInfo.ClientSocket = ClientSocket;
+  RequestInfo.ClientSockAddr = ClientSockAddr;
+  RequestInfo.AddrLen = AddrLen;
+  RequestInfo.KeepAlive = FALSE;
+  
+  int GetHeadersResult;
+  do {
+    //Get Headers
+    GetHeadersResult = GetHTTPHeaders(RequestInfo, RequestFields);
+    //Figure out what version we're dealing with and deal with it
+    switch (GetHeadersResult) {
+    case GH_SIMPLE_REQUEST :
+      SendHTTPError(400, "HTTP Request not supported", "Only 1.x requests supported", RequestInfo, RequestFields);
+      // TrayIncNumServed();
+      break;
+    case GH_10_REQUEST :
+      ExamineURIStr(RequestFields.URIStr,&RequestInfo,&RequestFields);
+      // TrayIncNumServed();
+      break;
+    case GH_UNKNOWN_VERSION :
+      SendHTTPError(400, "HTTP Version not supported", "Only 1.x requests supported", RequestInfo, RequestFields);
+      // TrayIncNumServed();
+      break;
+    case GH_ERROR:
+      //Disconnect
+      RequestInfo.KeepAlive = FALSE;
+      break;
+    }
+    CleanUpHTTPHeaders(RequestInfo, RequestFields);
+  } while (0/*RequestInfo.KeepAlive == TRUE*/);
+  //Close connection
+  CloseSocket(RequestInfo.ClientSocket);
+  // TrayRemoveConnection();
+}
+
+/******************************************************************************/
+int GetHTTPHeaders(RequestInfoT &RequestInfo, RequestFieldsT &RequestFields) {
+  //Parsing and IO buffers
+  char CurLine[NETIO_MAX_LINE];
+  char NextLine[NETIO_MAX_LINE];
+  char FieldNameStr[MAX_HTTP_FIELD_NAME_LEN];
+  char FieldValStr[MAX_HTTP_FIELD_LEN];
+  
+  //Parsing and IO working vars
+  int ReadBufferIndex;
+  int DataInBuffer;
+  int Start;
+  int End;
+  int Len;
+
+  //Clear all the fields
+  memset(&RequestFields, 0, sizeof(RequestFieldsT));
+
+  ReadBufferIndex = 0;
+  DataInBuffer = 0;
+  
+  //Get First Line
+  if (GetLine(CurLine, RequestInfo.ClientSocket, RequestInfo.IOBuffer,
+	      RequestInfo.IOBufferSize, ReadBufferIndex, DataInBuffer,
+	      RequestInfo.ThreadNum) != 0) return GH_ERROR;
+  do {//Get Next Line, append it if the first charactor is space
+    if(GetLine(NextLine, RequestInfo.ClientSocket, RequestInfo.IOBuffer,
+	       RequestInfo.IOBufferSize, ReadBufferIndex, DataInBuffer,
+	       RequestInfo.ThreadNum) != 0) return GH_ERROR;
+    if ((NextLine[0] == ' ') || (NextLine[0] == '\t'))
+      strcat(CurLine, NextLine);
+  } while ((NextLine[0] == ' ') || (NextLine[0] == '\t'));
+  //Method String (first word)
+  Start = 0;
+  GetWord(RequestFields.MethodStr, CurLine, Start, End);
+  CharUpper(RequestFields.MethodStr);
+  
+  //Version String (last word)
+  GetLastWord(RequestFields.VersionStr, CurLine, Start);
+  CharUpper(RequestFields.VersionStr);
+
+  if (strncmp(RequestFields.VersionStr, "HTTP/", 5) != 0) {
+    //No version, assume simple request
+    //part after method is URI
+    memcpy(RequestFields.URIStr, CurLine + End, strlen(CurLine) + 1 - End);
+    return GH_SIMPLE_REQUEST;
+  }
+
+  //URI String (in between End of first and Start of last)
+  //<Method> <WhiteSpace> <URI> <WhiteSpace> <Version> <CRLF>
+  //                  End^             Start^
+  int URIStrLen = Start - End;;
+  if (URIStrLen > ReqURIStrLen-1) URIStrLen = ReqURIStrLen - 1;
+  memcpy(RequestFields.URIStr, CurLine + End, URIStrLen);
+  RequestFields.URIStr[URIStrLen] = 0;
+  TrimRight(RequestFields.URIStr); //Remove trailing space
+  
+  //Only accept requests from HTTP/0.9 or HTTP/1.X clients, we'll
+  //assume that anything else will require an upgrade or patch
+  if (strncmp(RequestFields.VersionStr, "HTTP/1.", 7) != 0)
+    return GH_UNKNOWN_VERSION;
+  
+  //Get the rest of the lines
+  
+  strcpy(CurLine, NextLine);
+  
+  while (CurLine[0] != 0) {//Blank Line, we're done
+    do {//Get Next Line, append it if the first charactor is space
+      if (GetLine(NextLine, RequestInfo.ClientSocket, RequestInfo.IOBuffer,
+		  RequestInfo.IOBufferSize, ReadBufferIndex, DataInBuffer,
+		  RequestInfo.ThreadNum) != 0)
+	return GH_ERROR;
+      if ((NextLine[0] == ' ') || (NextLine[0] == '\t'))
+	strcat(CurLine, NextLine);
+    } while ((NextLine[0] == ' ') || (NextLine[0] == '\t'));
+    
+    Start = 0;
+    GetWord(FieldNameStr, CurLine, Start, End);
+    CharUpper(FieldNameStr);
+    
+    Len = strlen(CurLine) - End;
+    memcpy(FieldValStr, CurLine + End, Len);
+    FieldValStr[Len] = 0;
+    
+    //Process it
+    //In order of expected commonality
+    //All constants are in canonized, thus in upper case and case sensitive
+    //comparisons are used
+    //--Just About Always--
+    if (strcmp("ACCEPT:", FieldNameStr) == 0) {
+      if (RequestFields.AcceptStr[0] == '\0') {
+        strncpy(RequestFields.AcceptStr, FieldValStr, ReqAcceptStrLen - 1);
+	//  		if (Len >= ReqAcceptStrLen)
+	//        if (log_debug) log_message("Accept field truncated");
+      }
+      else {
+       	//Append it with a comma
+        int AcceptStrLen = strlen(RequestFields.AcceptStr);
+        if ((ReqAcceptStrLen - AcceptStrLen) >= 10) {
+          strncat(RequestFields.AcceptStr, ", ", ReqAcceptStrLen - AcceptStrLen - 1);
+          strncat(RequestFields.AcceptStr, FieldValStr, ReqAcceptStrLen - AcceptStrLen - 3);
+	}
+      }
+    }
+    else if (strcmp("DATE:", FieldNameStr) == 0) {
+      strncpy(RequestFields.DateStr, FieldValStr, ReqDateStrLen - 1);
+      //			if (Len >= ReqDateStrLen) LogError("Date field truncated");
+    }
+    else if (strcmp("USER-AGENT:", FieldNameStr) == 0) {
+      strncpy(RequestFields.UserAgentStr, FieldValStr, ReqUserAgentStrLen - 1);
+      //			if (Len >= ReqUserAgentStrLen) {
+      //         	LogError("User Agent field truncated, value follows");
+      //            LogError(RequestFields.UserAgentStr);
+      //            }
+    }
+    else if (strcmp("CONNECTION:", FieldNameStr) == 0) {
+      strncpy(RequestFields.ConnectionStr, FieldValStr, ReqConnectionStrLen - 1);
+      //			if (Len >= ReqConnectionStrLen) LogError("Connection field truncated");
+    }
+    //--Sometimes--
+    else if (strcmp("ACCEPT-LANGUAGE:", FieldNameStr) == 0) {
+      strncpy(RequestFields.AcceptLangStr, FieldValStr, ReqAcceptLangStrLen - 1);
+      //			if (Len >= ReqAcceptLangStrLen) LogError("Accept-Language field truncated");
+    }
+    else if (strcmp("REFERER:", FieldNameStr) == 0) {
+      strncpy(RequestFields.RefererStr, FieldValStr, ReqRefererStrLen - 1);
+      //			if (Len >= ReqRefererStrLen) LogError("Referer field truncated");
+    }
+    else if (strcmp("IF-MODIFIED-SINCE:", FieldNameStr) == 0) {
+      strncpy(RequestFields.IfModSinceStr, FieldValStr, ReqIfModSinceStrLen - 1);
+      //			if (Len >= ReqIfModSinceStrLen) LogError("If Modified Since field truncated");
+    }
+    //--Uncommon--
+    else if (strcmp("FROM:", FieldNameStr) == 0) {
+      strncpy(RequestFields.FromStr, FieldValStr, ReqFromStrLen - 1);
+      //			if (Len >= ReqFromStrLen) LogError("From field truncated");
+    }
+    else if (strcmp("MIME-VERSION:", FieldNameStr) == 0) {
+      strncpy(RequestFields.MIMEVerStr, FieldValStr, ReqMIMEVerStrLen - 1);
+      //			if (Len >= ReqMIMEVerStrLen) LogError("MIME Version field truncated");
+    }
+    else if (strcmp("PRAGMA:", FieldNameStr) == 0) {
+      strncpy(RequestFields.PragmaStr, FieldValStr, ReqPragmaStrLen - 1);
+      //			if (Len >= ReqPragmaStrLen) LogError("Pragma field truncated");
+    }
+    //--Special case--
+    else if (strcmp("AUTHORIZATION:", FieldNameStr) == 0) {
+      strncpy(RequestFields.AuthorizationStr, FieldValStr, ReqAuthorizationStrLen - 1);
+      //			if (Len >= ReqAuthorizationStrLen) LogError("Authorization field truncated");
+    }
+    else if (strcmp("CONTENT-LENGTH:", FieldNameStr) == 0) {
+      strncpy(RequestFields.ContentLengthStr, FieldValStr, ReqContentLengthStrLen - 1);
+      //			if (Len >= ReqContentLengthStrLen) LogError("Content Length field truncated");
+    }
+    else if (strcmp("CONTENT-TYPE:", FieldNameStr) == 0) {
+      strncpy(RequestFields.ContentTypeStr, FieldValStr, ReqContentTypeStrLen - 1);
+      //			if (Len >= ReqContentTypeStrLen) LogError("Content Type field truncated");
+    }
+    else if (strcmp("CONTENT-ENCODING:", FieldNameStr) == 0) {
+      strncpy(RequestFields.ContentEncodingStr, FieldValStr, ReqContentEncodingStrLen - 1);
+      //			if (Len >= ReqContentEncodingStrLen) LogError("Content Encoding field truncated");
+    }
+    else {
+      //Add it to the other headers
+      int VarLen = strlen(FieldNameStr);
+      if (FieldNameStr[VarLen - 1] == ':') {
+	//Remove the colon
+	FieldNameStr[VarLen - 1] = '\0';
+	VarLen--;
+      }
+      RequestFields.OtherHeaders[RequestFields.NumOtherHeaders].Var = new char[VarLen + 1];
+      RequestFields.OtherHeaders[RequestFields.NumOtherHeaders].Val = new char[Len + 1];
+      strcpy(RequestFields.OtherHeaders[RequestFields.NumOtherHeaders].Var, FieldNameStr);
+      strcpy(RequestFields.OtherHeaders[RequestFields.NumOtherHeaders].Val, FieldValStr);
+      RequestFields.NumOtherHeaders++;
+    }
+    strcpy(CurLine, NextLine);
+  }
+  
+  
+  if (RequestFields.ContentLengthStr[0] != 0) { //Do we have attached data?
+    unsigned int NumRecv;
+    
+    RequestFields.ContentLength = atol(RequestFields.ContentLengthStr);
+    if (RequestFields.ContentLength > 0) {
+      //			ThreadDebugMessage(RequestInfo.ThreadNum, "Getting content");
+      
+      //Allocate memory
+      RequestFields.Content = new BYTE[RequestFields.ContentLength];
+      
+      //Get rest of data from get lines
+      NumRecv = DataInBuffer - ReadBufferIndex;
+      
+      if (NumRecv >RequestFields.ContentLength) {
+	//Overflow, only read what they said they'd send
+	NumRecv = RequestFields.ContentLength;
+      }
+      memcpy(RequestFields.Content, RequestInfo.IOBuffer + ReadBufferIndex,
+	     NumRecv);
+      
+      while (NumRecv < RequestFields.ContentLength) {
+	NumRecv = GetData(RequestInfo.ClientSocket,
+			  RequestFields.Content + NumRecv,
+			  RequestFields.ContentLength - NumRecv,
+			  RequestInfo.ThreadNum);
+	if (NumRecv < 0) return GH_ERROR;
+      }
+    }
+    else {
+      RequestFields.Content = NULL;
+      RequestFields.ContentLength = 0;
+    }
+  }
+  else {
+    RequestFields.Content = NULL;
+    RequestFields.ContentLength = 0;
+  }
+  
+  return GH_10_REQUEST;
+}
+
+/******************************************************************************/
+void CleanUpHTTPHeaders(RequestInfoT &RequestInfo, RequestFieldsT &RequestFields) {
+  //Clean up memory allocated for the Content
+  if (RequestFields.Content != NULL)
+    delete[] RequestFields.Content;
+  while (RequestFields.NumOtherHeaders > 0) {
+    RequestFields.NumOtherHeaders--;
+    delete[] RequestFields.OtherHeaders[RequestFields.NumOtherHeaders].Var;
+    delete[] RequestFields.OtherHeaders[RequestFields.NumOtherHeaders].Val;
+  }
+  
+  // clean up memory allocated for the IOBuffer
+  if (RequestInfo.IOBuffer != NULL) {
+    delete[] RequestInfo.IOBuffer;
+    RequestInfo.IOBuffer = NULL;
+  }
+}
Index: /main/tags/2.25/gsdl/src/w32server/httpreq.h
===================================================================
--- /main/tags/2.25/gsdl/src/w32server/httpreq.h	(revision 21064)
+++ /main/tags/2.25/gsdl/src/w32server/httpreq.h	(revision 21064)
@@ -0,0 +1,159 @@
+#ifndef HTTPREQ_H
+#define HTTPREQ_H
+
+/*
+Copyright (C) 1996
+
+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.
+
+The author can be contacted via Email at bmorin@wpi.edu
+*/
+
+/*
+Module Name: HTTP Reqeust
+Purpose: Parses HTTP requests and then calls the appropriate function
+	to respond to the request
+Public Functions:
+	Request Thread
+*/
+
+// Public Data Structures
+
+//Used for sending information to the request thread
+struct RequestThreadMessageT {
+	SOCKADDR_IN ClientSockAddr;
+	SOCKET ClientSocket;
+	int AddrLen;
+	};
+
+//Length constants for RequestFieldsT
+#define ReqMethodStrLen           24
+#define ReqURIStrLen             255
+#define ReqVersionStrLen          24
+#define ReqDateStrLen             48
+#define ReqMIMEVerStrLen          24
+#define ReqPragmaStrLen          128
+#define ReqAuthorizationStrLen   512
+#define ReqFromStrLen            128
+#define ReqIfModSinceStrLen       48
+#define ReqRefererStrLen         512
+#define ReqUserAgentStrLen       256
+#define ReqContentEncodingStrLen 128
+#define ReqContentTypeStrLen     128
+#define ReqContentLengthStrLen    48
+#define ReqAcceptStrLen          256
+#define ReqAcceptLangStrLen       48
+#define ReqConnectionStrLen       24
+#define ReqAuthorizedUserStrLen   48
+#define ReqPathInfoStrLen        512
+#define ReqPathTranslatedStrLen  512
+#define ReqScriptNameStrLen      512
+//                               ---
+//                              4436
+
+#define MAX_OTHER_HEADERS 100
+
+struct RequestHeaderT {
+	char *Var;
+   char *Val;
+	};
+
+struct RequestFieldsT {
+	//Simple request line info v0.9
+	char MethodStr[ReqMethodStrLen];
+	char URIStr[ReqURIStrLen];
+	//added v1.0
+	char VersionStr[ReqVersionStrLen];
+	//General Header
+	char DateStr[ReqDateStrLen];
+	char MIMEVerStr[ReqMIMEVerStrLen];
+	char PragmaStr[ReqPragmaStrLen];
+	//Request Header
+	char AuthorizationStr[ReqAuthorizationStrLen];
+	char FromStr[ReqFromStrLen];
+	char IfModSinceStr[ReqIfModSinceStrLen];
+	char RefererStr[ReqRefererStrLen];
+	char UserAgentStr[ReqUserAgentStrLen];
+	//Entity Header (Only CGI stuff)
+	char ContentEncodingStr[ReqContentEncodingStrLen];
+	char ContentTypeStr[ReqContentTypeStrLen];
+	char ContentLengthStr[ReqContentLengthStrLen];
+   //v1.0 Optional (the more common ones)
+   char AcceptStr[ReqAcceptStrLen];
+   char AcceptLangStr[ReqAcceptLangStrLen];
+	//v1.1 Exentions
+	char ConnectionStr[ReqConnectionStrLen];
+	//Pointer to buffer containing the content
+	DWORD ContentLength;
+	BYTE *Content;
+
+	//Authorized user, filled in if a user is authorized from Auth..Str above
+	char AuthorizedUserStr[ReqAuthorizedUserStrLen];
+
+   //CGI style fields
+   char PathInfoStr[ReqPathInfoStrLen];
+   char PathTranslatedStr[ReqPathTranslatedStrLen];
+   char ScriptNameStr[ReqScriptNameStrLen];
+
+   //Other Headers
+   int NumOtherHeaders;
+   RequestHeaderT OtherHeaders[MAX_OTHER_HEADERS];
+	};
+
+struct RequestInfoT {
+	int ThreadNum;
+
+	//Buffer for IO operations (so we're not constantly reallocating buffers)
+	BYTE *IOBuffer;
+   int IOBufferSize;
+
+	//Socket the request is on and its address
+	SOCKET ClientSocket;
+	SOCKADDR_IN ClientSockAddr;
+	int AddrLen;
+
+	//Should we keep the connection alive?
+	BOOL KeepAlive;
+	};
+
+
+// Public Functions
+
+/*
+Function Name: RequestThread
+Purpose: Was the HTTP request processing thread
+         Now just a standard procedure called to process a request
+Parameters:
+	       Pointer to packed parameter structure
+*/
+void RequestThread(RequestThreadMessageT *Parameters);
+
+/*
+Function Name: Process 1.0 Request
+Purpose: Sends a HTTP 1.0 (plus some) reply to a HTTP 1.x request
+Parameters:
+	ClientSocket - Socket the client is on
+	ClientSockAddr - Address of client
+	AddrLen - Length of client address
+	RequestInfo - Structure storing the parsed headers
+	KeepAlive - To be set to true if we are maintainig the connection
+	IOBuffer - Pointer to buffer allocated for IO operations
+	TheadNum - Number of calling thread for debugging
+Notes: The function uses "Connection: Keep-Alive" as written in the HTTP/1.1
+	draft and implemented by Netscape and MSIE
+*/
+void Process10Request(RequestInfoT &RequestInfo, RequestFieldsT &RequestFields);
+
+#endif
Index: /main/tags/2.25/gsdl/src/w32server/httpsend.cpp
===================================================================
--- /main/tags/2.25/gsdl/src/w32server/httpsend.cpp	(revision 21064)
+++ /main/tags/2.25/gsdl/src/w32server/httpsend.cpp	(revision 21064)
@@ -0,0 +1,100 @@
+/*
+Copyright (C) 1996
+
+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.
+
+The author can be contacted via Email at bmorin@wpi.edu
+*/
+#include <windows.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <memory.h>
+#pragma hdrstop
+#include "parse.h"
+#include "netio.h"
+#include "httpreq.h"
+#include "httpsend.h"
+
+//Private Function Declarations
+/*
+Function Name: Check IMS Date
+Purpose: Checks the string date of an "If Modified Since" header against
+	a file date stamp.
+Parameters:
+	FileTime - Time stamp on file
+	IMSStr - "If Modified Since" date string
+Returns: TRUE if the file has been modified since the given date or
+	the data can not be resolved (the string to date function will log
+	any errors)
+*/
+BOOL CheckIMSDate(SYSTEMTIME &FileTime, char *IMSStr);
+
+//Public Functions
+/******************************************************************************/
+
+void SendHTTPError(int ErrorNum, char *ErrorTitleStr, char *ErrorDescStr, RequestInfoT &RequestInfo, RequestFieldsT &RequestFields)
+{
+	char Header[512];
+	char Body[512];
+
+	char ErrorNumStr[17];
+
+	DWORD BodyLength;
+	char BodyLengthStr[17];
+
+	int HeaderLength;
+
+	itoa(ErrorNum, ErrorNumStr, 10);
+
+		//Didn't find it, build the message manualry
+		Body[0] = 0;
+		strcat(Body, "<HTML><HEAD><TITLE>Server Error</TITLE></HEAD><BODY>\n");
+		strcat(Body, "<H1>Error ");
+		strcat(Body, ErrorNumStr);
+		strcat(Body, ": ");
+		strcat(Body, ErrorTitleStr);
+		strcat(Body, "</H1>\n");
+		strcat(Body, ErrorDescStr);
+		strcat(Body, "\n</BODY></HTML>");
+		BodyLength = (DWORD) strlen(Body);
+
+	//Build Header
+	Header[0] = 0;
+	//Status Line
+	strcat(Header, "HTTP/1.0 ");
+	strcat(Header, ErrorNumStr);
+	strcat(Header, " ");
+	strcat(Header, ErrorDescStr);
+	strcat(Header, "\r\n");
+	//Server
+	strcat(Header, "Server: GSDL\r\n");
+	//Content Type (assume HTML)
+	strcat(Header, "Content-Type: text/html\r\n");
+	//Content Length
+	itoa(BodyLength, BodyLengthStr, 10);
+	strcat(Header, "Content-Length: ");
+	strcat(Header, BodyLengthStr);
+	strcat(Header, "\r\n");
+	//Single CRLF to end header
+	strcat(Header, "\r\n");
+
+	HeaderLength = strlen(Header);
+
+  //Send header
+  SendData(RequestInfo.ClientSocket, (BYTE *) Header, strlen(Header), RequestInfo.ThreadNum);
+  //Send generated data
+  SendData(RequestInfo.ClientSocket, (BYTE *) Body, BodyLength, RequestInfo.ThreadNum);
+}
Index: /main/tags/2.25/gsdl/src/w32server/httpsend.h
===================================================================
--- /main/tags/2.25/gsdl/src/w32server/httpsend.h	(revision 21064)
+++ /main/tags/2.25/gsdl/src/w32server/httpsend.h	(revision 21064)
@@ -0,0 +1,43 @@
+/*
+Copyright (C) 1996
+
+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.
+
+The author can be contacted via Email at bmorin@wpi.edu
+*/
+
+/*
+Module Name: HTTP Send
+Purpose: Functions for sending HTTP responses to 1.X requests
+Public Functions:
+	SendHTTPError
+Notes: Considering adding a version number parameter to these functions.  Right
+	now the way people are implementing HTTP/1.1 is by adding the new stuff
+	to 1.0 requests.  I don't know of any browsers sending 1.1 requests yet.
+*/
+
+/*
+Function Name: Send HTTP Error
+Purpose: Sends a given error message to the client with either the error file
+			as a body or a default error message body.  Common and refenece log
+			entries are written, but not to the count log.
+Parameters:
+	ErrorNum - HTTP error number to send
+  ErrorTitleStr - Title of the error
+	ErrorDescStr - String describing the error
+	RequestInfo - HTTP request information (see httpreq.h)
+	RequestFields - Parsed HTTP header info (see httpreq.h)
+*/
+void SendHTTPError(int ErrorNum, char *ErrorTitleStr, char *ErrorDescStr, RequestInfoT &RequestInfo, RequestFieldsT &RequestFields);
Index: /main/tags/2.25/gsdl/src/w32server/httpsrv.cpp
===================================================================
--- /main/tags/2.25/gsdl/src/w32server/httpsrv.cpp	(revision 21064)
+++ /main/tags/2.25/gsdl/src/w32server/httpsrv.cpp	(revision 21064)
@@ -0,0 +1,96 @@
+/*
+Copyright (C) 1996
+
+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.
+
+The author can be contacted via Email at bmorin@wpi.edu
+*/
+#include "text_t.h"
+#include <windows.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <memory.h>
+#pragma hdrstop
+#include "netio.h"
+#include "settings.h"
+#include "httpreq.h"
+#include "httpsrv.h"
+#include "locate.h"
+
+//Private Functions
+
+/*
+Function Name: HTTP Server Answer
+Purpose: Answers messages saying that a connection is ready to start
+*/
+void HTTPServerAnswer();
+
+//Module Vars
+static SOCKET ServerSocket = INVALID_SOCKET;
+
+static HWND MsgWindow;
+
+/******************************************************************************/
+// returns 0 on success, and a WSA error otherwise
+int StartHTTPServer(HWND PassedMsgWindow) {
+
+  MsgWindow = PassedMsgWindow;
+  //Create the server socket
+  return CreateListeningSocket(gsdl_port_num, MsgWindow, HTTP_SERVER_MSG, ServerSocket);
+}
+
+/******************************************************************************/
+void EndHTTPServer()
+{
+  //Stop the listening socket
+  DestroyListeningSocket(ServerSocket, MsgWindow);
+}
+
+/******************************************************************************/
+void ProcessHTTPServerMsg(WPARAM Socket, LPARAM MsgInfo) {
+	log_message("accept message arrived\n");
+	if (Socket != ServerSocket) {
+		if (gsdl_keep_log || gsdl_show_console) log_message("Incorrect socket sent in message");
+		}
+	switch (WSAGETSELECTEVENT(MsgInfo)) {
+		case FD_ACCEPT:
+			switch (WSAGETSELECTERROR(MsgInfo)) {
+				case WSAENETDOWN:
+					LogCriticalError("1","Network Down");
+					break;
+				default: //No Error
+					HTTPServerAnswer();
+				}
+			break;
+		}
+}
+
+/******************************************************************************/
+void HTTPServerAnswer() {
+	SOCKADDR_IN ClientSockAddr;
+	SOCKET ClientSocket;
+	int AddrLen = sizeof(SOCKADDR_IN);
+	RequestThreadMessageT Parameters;
+  while (AnswerListeningSocket(ServerSocket, ClientSocket, ClientSockAddr, AddrLen) == 0) {
+    log_message("Answering socket\n");
+	  //Call the thread procedure to handle the connection
+    Parameters.ClientSockAddr = ClientSockAddr;
+  	Parameters.ClientSocket = ClientSocket;
+  	Parameters.AddrLen = AddrLen;
+    RequestThread(&Parameters);
+  }
+}
+	
Index: /main/tags/2.25/gsdl/src/w32server/httpsrv.h
===================================================================
--- /main/tags/2.25/gsdl/src/w32server/httpsrv.h	(revision 21064)
+++ /main/tags/2.25/gsdl/src/w32server/httpsrv.h	(revision 21064)
@@ -0,0 +1,47 @@
+/*
+Copyright (C) 1996
+
+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.
+
+The author can be contacted via Email at bmorin@wpi.edu
+*/
+#define HTTP_SERVER_MSG WM_USER + 23
+
+/*
+Function Name: Start HTTP Server
+Purpose: Starts the HTTP server.  Inits Winsock, MIME, loads registry stuff,
+			etc.
+Parameters:
+	PassedMsgWindow - The handle of the window that handles messages.  Needed
+							to setup WSASelect notification of socket events and
+							to send a shutdown message on error.
+*/
+// returns 0 on success, and a WSA error otherwise
+int StartHTTPServer(HWND PassedMsgWindow);
+
+/*
+Function Name: End HTTP Server
+Purpose: Ends the HTTP server.  Cleans up MIME, users, etc.
+*/
+void EndHTTPServer();
+
+/*
+Function Name: Process HTTP Server Message
+Purpose: Processes HTTP_SERVER_MSG messages.
+Parameters:
+	Socket - The socket the message is regarding (WPARAM)
+	MsgInfo - The messsage (LPARAM)
+*/
+void ProcessHTTPServerMsg(WPARAM Socket, LPARAM MsgInfo);
Index: /main/tags/2.25/gsdl/src/w32server/locate.cpp
===================================================================
--- /main/tags/2.25/gsdl/src/w32server/locate.cpp	(revision 21064)
+++ /main/tags/2.25/gsdl/src/w32server/locate.cpp	(revision 21064)
@@ -0,0 +1,240 @@
+#include "text_t.h"
+#include <windows.h>
+#include <stdio.h>
+#include "locate.h"
+#include "settings.h"
+
+/* The following values are inserted or used by FNORD.CPP */
+HWND GSDL_Window;
+int line_spacing;
+RECT text_rect;
+
+
+static FILE *log_file=NULL;
+
+static int location_found=0;
+char data_location[MAX_URL_SIZE];
+
+void set_location(char *possible)
+{
+  if (location_found != 0) return;
+  if (possible != NULL && *possible != 0) {
+    strcpy(data_location, possible);
+    if (data_location[strlen(data_location)-1] != '\\')
+      strcat(data_location,"\\");
+    location_found = 1;
+    }
+}
+
+void find_location(void)
+{
+  char *send;
+  if (location_found != 0) return;
+  if (GetModuleFileName(NULL,data_location,MAX_URL_SIZE) <= 0)
+    send = data_location;
+  else {
+    send = strrchr(data_location,'\\');
+    if (send != NULL)
+      send++;
+    else {
+      send = strchr(data_location,':');
+      if (send != NULL)
+        send++;
+      else
+        send == data_location;
+      }
+    }
+  *send = 0;
+  location_found = 1;
+}
+
+void open_log_file()
+{
+  if (log_file != NULL) fclose(log_file);
+  log_file = fopen(gsdl_log_name, "a");
+  if (log_file != NULL) {
+	  fprintf (log_file, "\n\n-----------\n");
+	  fprintf (log_file, "log started\n");
+	  fprintf (log_file, "-----------\n\n");
+  }
+}
+
+void close_log_file()
+{
+  if (log_file != NULL) {
+    fclose(log_file);
+    log_file = NULL;
+  }
+}
+
+#define CONSOLE_BUFFER_SIZE 2048
+char console_buffer[CONSOLE_BUFFER_SIZE];
+char *next_console, *last_console;
+int console_top, console_y;
+
+void activate_console(void)
+{
+  gsdl_show_console = 1;
+  next_console = console_buffer;
+  *next_console = 0;
+  last_console = next_console;
+  console_y = console_top = text_rect.top +
+    (text_rect.bottom - text_rect.top + 1) % line_spacing / 2;
+  InvalidateRect(GSDL_Window,NULL,TRUE);
+}
+
+void deactivate_console(void)
+{
+  gsdl_show_console = 0;
+  InvalidateRect(GSDL_Window,NULL,TRUE);
+}
+
+void refresh_console(HDC dc)
+{
+  int loc;  char *b, *e;
+  loc = console_top;
+  for (e = console_buffer;;) {
+    b = e;
+    while (*e >= ' ') e++;
+    TextOut(dc,0,loc,b,e-b);
+    loc += line_spacing;
+    if (*e == 0) break;
+    e++;
+    if (*e == 0) break;
+    }
+}
+
+void scroll(HDC dc, int nbits)
+{
+  RECT scroll, clip, update;
+
+  scroll.left = clip.left = text_rect.left;
+  scroll.right = clip.right = text_rect.right;
+  clip.top = console_top;
+  clip.bottom = text_rect.bottom;
+  scroll.top = clip.top + nbits;
+  scroll.bottom = text_rect.bottom;
+  ScrollDC(dc,0,-nbits,&scroll,&clip,NULL,&update);
+  FillRect(dc,&update, (HBRUSH)GetStockObject(WHITE_BRUSH));
+}
+
+int remove_line()
+{
+  char *bin, *bout;
+  bin = bout = console_buffer;
+  while (*bin >= ' ') bin++;
+  if (*bin != 0) {
+    bin++;
+    if (*bin != 0) {
+      while (*bin != 0) *bout++ = *bin++;
+      *bout = *bin;
+      last_console -= (bin - bout);
+      next_console = bout;
+      return line_spacing;
+      }
+    }
+  next_console = console_buffer;
+  *next_console = 0;
+  last_console = next_console;
+  return 0;
+}
+
+void display_line(HDC dc, char *line, int nch)
+{
+  int scroll_needed = 0;
+  while (next_console + nch + 1 
+         > console_buffer + CONSOLE_BUFFER_SIZE)
+    scroll_needed += remove_line();
+  console_y -= scroll_needed;
+  if (*last_console == '\n') {
+    console_y += line_spacing;
+    if (console_y + line_spacing > text_rect.bottom) {
+      scroll_needed += remove_line();
+      console_y -= line_spacing;
+      }
+    last_console = next_console;
+    }
+  if (scroll_needed != 0) scroll(dc, scroll_needed);
+  while (nch-- > 0) *next_console++ = *line++;
+  TextOut(dc,0,console_y,last_console,next_console-last_console);
+  *next_console = *line;
+  if (*next_console != 0) {
+    last_console = next_console;
+    next_console++;
+    *next_console = 0;
+    }
+}
+
+void display_text(HDC dc, char *buffer)
+{
+  char *bl, *bp;
+  for (bl = buffer;;) {
+    for (bp = bl;;) {
+      if (*bp == '\t') *bp = ' ';
+      if (*bp < ' ') break;
+      bp++;
+      }
+    if (*bp != 0) *bp = '\n';
+    display_line(dc, bl, bp-bl);
+    if (*bp == 0) break;
+    bl = bp+1;
+    if (*bl == 0) break;
+    }
+}
+
+void log_message(char *msg)
+{
+  if (log_file != NULL) {
+    fprintf(log_file,"%s",msg);
+    fflush(log_file);
+    }
+  if (gsdl_show_console) {
+    char buffer[1024];  HDC dc;
+    sprintf(buffer,"%s",msg);
+    dc = GetDC(GSDL_Window);
+    display_text(dc,buffer);
+    ReleaseDC(GSDL_Window,dc);
+    }
+}
+
+void log_message_N(char*msg, int n)
+{
+  if (log_file != NULL) {
+	  int len = 0;
+	  while (len < n) {
+		  fputc (msg[len], log_file);
+		  len++;
+	  }
+	  fflush(log_file);
+  }
+
+  // these messages are not send to the console
+  if (gsdl_show_console) {
+    HDC dc;
+    dc = GetDC(GSDL_Window);
+    display_text(dc,"message only written to log file\n");
+    ReleaseDC(GSDL_Window,dc);
+    }
+}
+
+void LogCriticalError(char *cderr, char *Msg)
+{
+	char MsgBoxStr[200];
+
+	strcpy(MsgBoxStr, "Critical Error Number ");
+	strcat(MsgBoxStr, cderr);
+	strcat(MsgBoxStr, "\n");
+	strcat(MsgBoxStr, Msg);
+	strcat(MsgBoxStr, "\nGreenstone Digital Library software\nshutting down");
+	MessageBox(GSDL_Window, MsgBoxStr, "Greenstone Digital Library Software",
+		MB_OK | MB_ICONERROR);
+	PostMessage(GSDL_Window, WM_DESTROY, 0, 0);
+}
+
+
+/* returns second-first taking into account wrap around */
+DWORD DiffTickCounts (DWORD first, DWORD second) 
+{
+	if (second >= first) return (second-first);
+	return (MAXDWORD-first+1+second);
+}
Index: /main/tags/2.25/gsdl/src/w32server/locate.h
===================================================================
--- /main/tags/2.25/gsdl/src/w32server/locate.h	(revision 21064)
+++ /main/tags/2.25/gsdl/src/w32server/locate.h	(revision 21064)
@@ -0,0 +1,26 @@
+#define MAX_URL_SIZE 256
+
+extern HWND GSDL_Window;
+extern int line_spacing;
+extern RECT text_rect;
+
+void refresh_console(HDC dc);
+
+
+extern char data_location[MAX_URL_SIZE];
+
+extern void set_location(char *possible);
+extern void find_location(void);
+
+extern void open_log_file(void);
+extern void close_log_file(void);
+extern void log_message(char *msg);
+extern void log_message_N(char*msg, int n);
+
+extern void activate_console(void);
+extern void deactivate_console(void);
+
+extern void LogCriticalError(char *cderr, char *Msg);
+
+/* returns first-second taking into account wrap around */
+extern DWORD DiffTickCounts (DWORD first, DWORD second);
Index: /main/tags/2.25/gsdl/src/w32server/netio.cpp
===================================================================
--- /main/tags/2.25/gsdl/src/w32server/netio.cpp	(revision 21064)
+++ /main/tags/2.25/gsdl/src/w32server/netio.cpp	(revision 21064)
@@ -0,0 +1,478 @@
+/*
+Copyright (C) 1996
+
+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.
+
+The author can be contacted via Email at bmorin@wpi.edu
+*/
+
+#include <windows.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <memory.h>
+#pragma hdrstop
+#include "netio.h"
+#include "locate.h"
+#include "d_winsock.h"
+
+//Private Variables and Declarations
+
+//Max string size for a host name
+#define MAXHOSTNAME 100
+
+//Timeout for waiting between "packets" in seconds
+#define NETIO_CONN_TIMEOUT 20 //3 sec  was 180 @@@@@ WJR
+
+#define HTTP_DNS_MSG WM_USER + 1
+int dns_msg_received = 0;
+int dns_msg_error = 0;
+
+
+DWORD LocalIPNumber;
+char LocalName[MAXHOSTNAME];
+
+
+//Private Function Declarations
+DWORD GetHostID();
+
+
+// returns 0 on success,
+// WSASYSNOTREADY, WSAVERNOTSUPPORTED, or WSAEINVAL on failure
+int InitNetIO() {
+	WSADATA Data;
+
+	// Load Winsock
+	int err = d_WSAStartup(MAKEWORD(1, 1), &Data);
+
+	// get local IP number
+	if (err == 0) LocalIPNumber = GetHostID();
+	else LocalIPNumber = INADDR_ANY;
+
+	// set the Local Name to "" for now
+	LocalName[0] = 0;
+	
+	return err;
+}
+
+
+void CleanUpNetIO() {
+	//Experimental, heard this will better clean up, especialy if a call is
+	//blocking....
+	d_WSAUnhookBlockingHook();
+
+	//Clean up Winsock
+	d_WSACleanup() == SOCKET_ERROR;
+}
+
+
+void ResetNetIO() {
+	//Figure out the local name on first querry, set to "" until then...
+	LocalName[0] = 0;
+}
+
+
+DWORD GetLocalIP() {
+	return LocalIPNumber;
+}
+
+
+
+
+
+long __stdcall DNSWindowProc(HWND hWnd,UINT wMsg, WPARAM wParam, LPARAM lParam) {
+	if (wMsg == HTTP_DNS_MSG) {
+		dns_msg_received = 1;
+		dns_msg_error = WSAGETASYNCERROR(lParam);
+		return 0;
+	}
+
+	return DefWindowProc(hWnd, wMsg, wParam, lParam);
+}
+
+char *GetLocalName(HINSTANCE hInstance) {
+	// static in case it is written to after the function has finished
+	// (I did not error checking on WSACancelAsyncRequest)
+	static char buf[MAXGETHOSTSTRUCT];
+
+	
+	if (LocalName[0] == 0) {
+		hostent *DNSResult = NULL;
+		in_addr LocalInAddr;
+
+		// if we failed to get the local IP number
+		// use the loop-back device
+		if (LocalIPNumber == INADDR_ANY) {
+			strcpy(LocalName, "127.0.0.1"); // loop-back device
+			return LocalName;
+		}
+
+		//Convert the number to an in_addr struct
+		LocalInAddr.s_addr = LocalIPNumber;
+
+		// if we fail to find the domain name we will
+		// still want the IP address
+		strcpy(LocalName, d_inet_ntoa(LocalInAddr));
+
+
+		// make sure they actually passed in an instance handle
+		if (hInstance == NULL) return LocalName;
+
+		// do a async domain name lookup so that we
+		// can control the timeout
+
+		// create a window class and window to handle the async messages
+		WNDCLASS wc; HWND hwndDNS;
+	
+		wc.style = 0;
+		wc.lpfnWndProc = DNSWindowProc;
+		wc.cbClsExtra = 0;
+		wc.cbWndExtra = 0;
+		wc.hInstance = hInstance;
+		wc.hIcon = NULL;
+		wc.hCursor = NULL;
+		wc.hbrBackground = NULL;
+		wc.lpszMenuName = NULL;
+		wc.lpszClassName = "GSDL DNS Window";
+		if (!RegisterClass(&wc)) return LocalName;
+
+		hwndDNS = CreateWindow("GSDL DNS Window", "", 
+			WS_OVERLAPPEDWINDOW, 0, 0, 100, 100, 
+			NULL, NULL, hInstance, NULL);
+		if (!hwndDNS) return LocalName;
+
+		// process all messages currently on the queue
+		MSG Message;
+		while (PeekMessage(&Message, NULL, 0, 0, PM_REMOVE)) {
+			TranslateMessage(&Message); /* translate keyboard messages */
+			DispatchMessage(&Message);  /* return control to Windows NT */
+		}
+
+		//Do a async DNS lookup on the IP number
+		dns_msg_received = 0;
+		dns_msg_error = 0;
+		HANDLE asyncGetHostReq = d_WSAAsyncGetHostByAddr(
+		    hwndDNS, HTTP_DNS_MSG, (char *)&(LocalInAddr), 
+			4, PF_INET, buf, MAXGETHOSTSTRUCT);
+	
+		if (asyncGetHostReq != NULL) {
+			// wait 5 seconds for the request to complete
+			int now = GetTickCount();
+			while ((DiffTickCounts(now, GetTickCount()) < 5000) && !dns_msg_received) {
+				if (PeekMessage(&Message, NULL, 0, 0, PM_REMOVE)) {
+					TranslateMessage(&Message); /* translate keyboard messages */
+					DispatchMessage(&Message);  /* return control to Windows NT */
+				} else {
+					Sleep(1);
+				}
+			}
+			if (!dns_msg_received)
+				d_WSACancelAsyncRequest(asyncGetHostReq);
+		}
+
+		DestroyWindow(hwndDNS);
+
+		if (dns_msg_received && (dns_msg_error == 0)) {
+   	    	//Worked, use the primary name
+			strcpy(LocalName, ((hostent *)(buf))->h_name);
+      		//Convert it to lower case for cosmedic reasons
+			CharLower(LocalName);
+		}
+   	}
+	return LocalName;
+}
+
+
+// returns 0 on success, and a WSA error message on failure.
+// possible error messages include:
+// WSANOTINITIALISED, WSAENETDOWN, WSAEAFNOSUPPORT, WSAEINPROGRESS, WSAEMFILE,
+// WSAENOBUFS, WSAEPROTONOSUPPORT, WSAEPROTOTYPE, WSAESOCKTNOSUPPORT,
+// WSAEADDRINUSE, WSAEINVAL, WSAEISCONN, WSAENOTSOCK, WSAEOPNOTSUPP
+
+#define MAXBINDCOUNT 4096
+int CreateListeningSocket(int &PortNum, HWND MsgWindow, WORD SocketMsg, SOCKET &ServerSocket) {
+	int err = 0;
+	SOCKADDR_IN ServerSockAddr;
+	int bind_port, bind_count;
+
+	//Create the Server Socket
+	ServerSocket = d_socket(AF_INET, SOCK_STREAM, 0);
+	if (ServerSocket == INVALID_SOCKET) return d_WSAGetLastError();
+
+	bind_port = PortNum;
+	for (bind_count=0; bind_count < MAXBINDCOUNT; bind_count++) {
+		// Set up the Server Socket Address
+		memset(&ServerSockAddr, 0, sizeof(ServerSockAddr)); //Needed?
+		ServerSockAddr.sin_port = d_htons( (WORD) bind_port);
+		ServerSockAddr.sin_family = AF_INET;
+		ServerSockAddr.sin_addr.s_addr = d_htonl(INADDR_ANY);
+
+		// Try to bind the socket with the address
+		if (d_bind(ServerSocket, (LPSOCKADDR) &ServerSockAddr,
+				sizeof(ServerSockAddr)) != SOCKET_ERROR) {
+			PortNum = bind_port;
+			break;
+		}
+
+		// make sure it failed to bind because it was
+		// already bound
+		err = d_WSAGetLastError ();
+		if (err != WSAEADDRINUSE) return err;
+
+		// Or choose another port number to try
+		if (bind_port == 80) bind_port = IPPORT_RESERVED+1;
+		else if (bind_count == 0) bind_port = 80;
+		else bind_port++;
+	}
+
+	// return an error in we couldn't find a valid port
+	if (bind_count == MAXBINDCOUNT) return WSAEADDRINUSE;
+
+	// Start listening for connections
+	if (d_listen(ServerSocket, SOMAXCONN) == SOCKET_ERROR)
+		return d_WSAGetLastError ();	
+
+	// Set up event for new connections
+	if (d_WSAAsyncSelect(ServerSocket, MsgWindow, SocketMsg, FD_ACCEPT) == SOCKET_ERROR)
+		return d_WSAGetLastError ();
+
+	return 0;
+}
+
+
+int AnswerListeningSocket(SOCKET ServerSocket, SOCKET &ClientSocket, SOCKADDR_IN &ClientSockAddr, int AddrLen) {
+	if (d_WSAIsBlocking()) {
+		log_message("rejected connect due blocking\n");
+		return -1;
+	}
+
+	ClientSocket = d_accept(ServerSocket, (LPSOCKADDR) &ClientSockAddr, &AddrLen);
+	if (ClientSocket == INVALID_SOCKET) {
+		log_message("accept failed - connection lost\n");
+		return -1;
+	}
+
+	log_message("accept success - connection made\n");
+	return 0;
+}
+
+
+void DestroyListeningSocket(SOCKET &ServerSocket, HWND MsgWindow) {
+	//Remove any message notification
+	d_WSAAsyncSelect(ServerSocket, MsgWindow, 0, 0);
+
+	//Close the socket
+	CloseSocket(ServerSocket);
+}
+
+
+void CloseSocket(SOCKET &TargetSocket) {
+	if (TargetSocket != INVALID_SOCKET) {
+		//Since we're closing the socket, there's not much I can do about errors
+		//now so I'm not gonna bother checking...
+
+		//Shutdown both ends, assume we have all data...
+		d_shutdown(TargetSocket, 2);
+
+		d_closesocket(TargetSocket);
+
+		//Make sure we can't use the old handle again...
+		TargetSocket = INVALID_SOCKET;
+	}
+}
+
+
+int GetData(SOCKET ClientSocket, BYTE *IOBuffer, int IOBufferSize,
+													int ThreadNum) {
+
+	int NumRecv;
+	int Error;
+	struct timeval Timeout;
+	fd_set SocketSet;
+
+	//Set up a socket set structure with just ClientSocket for  select(..)
+	FD_ZERO(&SocketSet);
+	FD_SET(ClientSocket, &SocketSet);
+
+	//set timeout
+	Timeout.tv_sec = NETIO_CONN_TIMEOUT;
+	Timeout.tv_usec = 0;
+
+	do {
+		NumRecv = d_recv(ClientSocket, (char *) IOBuffer, IOBufferSize, 0);
+		if (NumRecv == 0) {
+			//Lost connect
+			return -1;
+
+		} else if (NumRecv == SOCKET_ERROR) {
+			Error = d_WSAGetLastError();
+			if (Error == WSAEWOULDBLOCK) {
+				NumRecv = 0;
+				//Wait for socket to be readable
+				if (d_select(0, &SocketSet, NULL, NULL, &Timeout) != 1) {
+					//Timeout
+					return -1;
+				}
+
+			} else {
+			//Assume connection terminated
+			return -1;
+			}
+		}
+	} while(NumRecv == 0);
+	return NumRecv;
+}
+
+
+int GetLine(char *OutStr, SOCKET ClientSocket, BYTE *IOBuffer, int IOBufferSize,
+				int &BufferIndex, int &DataInBuffer, int ThreadNum) {
+
+	int i;
+	char CurChar;
+
+	i = 0;
+	do {
+		if (BufferIndex == DataInBuffer) { //Need more data
+			DataInBuffer = GetData(ClientSocket, IOBuffer, IOBufferSize, ThreadNum);
+			if (DataInBuffer == -1) {
+				//Lost connect
+				return -1;
+			}
+			BufferIndex = 0;
+		}
+		CurChar = IOBuffer[BufferIndex];
+		BufferIndex++;
+		if ((CurChar != 10) && (CurChar != 13))  {
+			OutStr[i] = CurChar;
+			i++;
+		}
+	} while ((CurChar != 10) && (i < NETIO_MAX_LINE));
+	if (i == NETIO_MAX_LINE) {
+		return -1;
+	}
+
+	OutStr[i] = 0;
+	return 0;
+}
+
+
+int SendData(SOCKET ClientSocket, BYTE *SendBuffer, int NumToSend,
+								int ThreadNum) {
+
+	int NumSent = 0;
+	int Error;
+	struct timeval Timeout;
+	fd_set SocketSet;
+
+	char NumSentStr[50];
+	itoa(NumToSend, NumSentStr, 10);
+
+	//Set up a socket set structure with just ClientSocket for  select(..)
+	FD_ZERO(&SocketSet);
+	FD_SET(ClientSocket, &SocketSet);
+	//set timeout
+	Timeout.tv_sec = NETIO_CONN_TIMEOUT;
+	Timeout.tv_usec = 0;
+
+	while (NumToSend > 0) {
+		NumSent = d_send(ClientSocket, (char *) SendBuffer + NumSent, NumToSend, 0);
+		if (NumSent == 0) {
+			//Lost connect
+			return -1;
+		}
+		else if (NumSent == SOCKET_ERROR) {
+			Error = d_WSAGetLastError();
+			if (Error == WSAEWOULDBLOCK) {
+				NumSent = 0;
+				if (d_select(0, NULL, &SocketSet, NULL, &Timeout) != 1) {
+					//Timeout
+					return -1;
+				}
+			}
+			else {
+				//Lost Connection
+				return -1;
+			}
+		}
+		NumToSend -= NumSent;
+	}
+	return 0;
+}
+
+
+
+/******************************************************************************/
+//Private Functions
+/******************************************************************************/
+/*-----------------------------------------------------------
+ * Function: GetHostID()
+ *
+ * Description:
+ *  Get the Local IP address using the following algorithm:
+ *    - get local hostname with gethostname()
+ *    - attempt to resolve local hostname with gethostbyname()
+ *    if that fails:
+ *    - get a UDP socket
+ *    - connect UDP socket to arbitrary address and port
+ *    - use getsockname() to get local address
+ *
+ * Notes: Copyright by Bob Quinn, 1995, taken from his Winsock library
+ *        was removed from its original module unmodified
+ */
+DWORD GetHostID () {
+	 char szLclHost [MAXHOSTNAME];
+	 LPHOSTENT lpstHostent;
+	 SOCKADDR_IN stLclAddr;
+	 SOCKADDR_IN stRmtAddr;
+	 int nAddrSize = sizeof(SOCKADDR);
+	 SOCKET hSock;
+	 int nRet;
+
+	 /* Init local address (to zero) */
+	 stLclAddr.sin_addr.s_addr = INADDR_ANY;
+
+	 /* Get the local hostname */
+	 nRet = d_gethostname(szLclHost, MAXHOSTNAME);
+	 if (nRet != SOCKET_ERROR) {
+		/* Resolve hostname for local address */
+		lpstHostent = d_gethostbyname((LPSTR)szLclHost);
+		if (lpstHostent)
+		  stLclAddr.sin_addr.s_addr = *((u_long FAR*) (lpstHostent->h_addr));
+	 }
+
+	 /* If still not resolved, then try second strategy */
+	 if (stLclAddr.sin_addr.s_addr == INADDR_ANY) {
+		/* Get a UDP socket */
+		hSock = d_socket(AF_INET, SOCK_DGRAM, 0);
+		if (hSock != INVALID_SOCKET)  {
+		  /* Connect to arbitrary port and address (NOT loopback) */
+		  stRmtAddr.sin_family = AF_INET;
+		  stRmtAddr.sin_port   = d_htons(IPPORT_ECHO);
+		  stRmtAddr.sin_addr.s_addr = d_inet_addr("128.127.50.1");
+		  nRet = d_connect(hSock,
+							  (LPSOCKADDR)&stRmtAddr,
+							  sizeof(SOCKADDR));
+		  if (nRet != SOCKET_ERROR) {
+			 /* Get local address */
+			 d_getsockname(hSock,
+							 (LPSOCKADDR)&stLclAddr,
+							 (int FAR*)&nAddrSize);
+		  }
+		  d_closesocket(hSock);   /* we're done with the socket */
+		}
+	 }
+	 return (stLclAddr.sin_addr.s_addr);
+}
+
Index: /main/tags/2.25/gsdl/src/w32server/netio.h
===================================================================
--- /main/tags/2.25/gsdl/src/w32server/netio.h	(revision 21064)
+++ /main/tags/2.25/gsdl/src/w32server/netio.h	(revision 21064)
@@ -0,0 +1,151 @@
+/*
+Copyright (C) 1996
+
+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.
+
+The author can be contacted via Email at bmorin@wpi.edu
+*/
+
+/*
+Module Name: Net IO
+Purpose: High level Socket IO and Misc socket routines
+Public Functions:
+	InitNetIO
+   CleanUpNetIO
+
+	GetLocalIP
+	GetLocalName
+
+   CreateListeningSocket
+   AnswerListeningSocket
+   DestroyListeningSocket
+
+   CloseSocket
+
+	GetData
+	GetLine
+
+	SendData
+	SendFile
+*/
+
+//Public definitions
+//Max line size for GetLine
+#define NETIO_MAX_LINE 300
+
+//Public Functions
+
+/*
+Function Name: Init Net IO
+Purpose: Initializes the module so calls can be made querying network
+	information for the local macnine.
+Notes: MUST be called before GetLocalIP and GetLocalName
+*/
+
+// returns 0 on success,
+// WSASYSNOTREADY, WSAVERNOTSUPPORTED, or WSAEINVAL on failure
+int InitNetIO();
+
+/*
+Function Name: Cleanup Net IO
+Purpose: Cleans up the module and unloads Winsock
+*/
+void CleanUpNetIO();
+
+/*
+Function Name: Reset Net IO
+Purpose: Resets internal data in NetIO to reflect registry changes, etc.
+*/
+void ResetNetIO();
+
+/*
+Function Name: Get Local IP
+Purpose: Gets the local IP number
+Returns: The local IP number as an double word (4 bytes)
+*/
+DWORD GetLocalIP();
+
+/*
+Function Name: Get Local Name
+Purpose: Gets the local Domain name, or if there is none, then the server
+address in dotted format.
+Returns: A string containing the local address
+*/
+char *GetLocalName(HINSTANCE hInstance);
+
+// returns 0 on success, and a WSA error message on failure.
+// possible error messages include:
+// WSANOTINITIALISED, WSAENETDOWN, WSAEAFNOSUPPORT, WSAEINPROGRESS, WSAEMFILE,
+// WSAENOBUFS, WSAEPROTONOSUPPORT, WSAEPROTOTYPE, WSAESOCKTNOSUPPORT,
+// WSAEADDRINUSE, WSAEINVAL, WSAEISCONN, WSAENOTSOCK, WSAEOPNOTSUPP
+int CreateListeningSocket(int &PortNum, HWND MsgWindow, WORD SocketMsg, SOCKET &ServerSocket);
+
+int AnswerListeningSocket(SOCKET ServerSocket, SOCKET &ClientSocket, SOCKADDR_IN &ClientSockAddr, int AddrLen);
+
+void DestroyListeningSocket(SOCKET &ServerSocket, HWND MsgWindow);
+
+void CloseSocket(SOCKET &TargetSocket);
+
+/*
+Function Name: Get Data
+Purpose: Gets data from a socket with muli-threaded debugging
+Parameters:
+	ClientSocket - The socket to get data from
+	IOBuffer - A pointer to a chunk of memory to put data in
+	IOBufferSize - Size of the buffer
+	ThreadNum - Number of the thread that called this functions used for debugging
+
+Returns: -1 on error, else the number of bytes received
+
+Notes:
+Removed socket error checking because I was unable to isolate what
+errors I was getting when getting a "rude" disconnect
+*/
+int GetData(SOCKET ClientSocket, BYTE *IOBuffer, int IOBufferSize, int ThreadNum);
+
+/*
+Function Name: Get Line
+Purpose: Gets a line of text (ended by a LF (10)) from a socket with buffered
+			input.  If the buffer is empty this function fills the buffer, else it
+			just changes an index. Also has the ability to do multi-threaded debuging
+Parameters:
+	OutStr - Varible were output is put (a length of NETIO_MAX_LINE is assumed)
+	ClientSocket - The socket to get data from
+	IOBuffer - A pointer to a chunk of memory to put data in
+	IOBufferSize - Size of the buffer
+	BufferIndex - A zero based index of what charactor in the buffer we're at
+	DataInBuffer - Amount of data in the buffer
+	ThreadNum - Number of the thread that called this functions used for debugging
+
+Returns: -1 on disconnect or error (abort connection), 0 on success
+*/
+int GetLine(char *OutStr, SOCKET ClientSocket, BYTE *IOBuffer, int IOBufferSize, int &BufferIndex, int &DataInBuffer, int ThreadNum);
+
+/*
+Function Name: Send Data
+Purpose: Sends data to a socket with muli-thread debugging
+Parameters:
+	ClientSocket - The socket to get data from
+	SendBuffer - A pointer to a chunk of memory to put data in
+	NumToSend - Number of bytes to send from buffer
+	ThreadNum - Number of the thread that called this functions used for debugging
+
+Returns: -1 on error, 0 on success
+
+Notes:
+Removed socket error checking because I was unable to isolate what
+errors I was getting when getting a "rude" disconnect
+*/
+int SendData(SOCKET ClientSocket, BYTE *SendBuffer, int NumToSend, int ThreadNum);
Index: /main/tags/2.25/gsdl/src/w32server/parse.cpp
===================================================================
--- /main/tags/2.25/gsdl/src/w32server/parse.cpp	(revision 21064)
+++ /main/tags/2.25/gsdl/src/w32server/parse.cpp	(revision 21064)
@@ -0,0 +1,194 @@
+/*
+Copyright (C) 1996
+
+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.
+
+The author can be contacted via Email at bmorin@wpi.edu
+*/
+#include <windows.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <memory.h>
+#pragma hdrstop
+
+#include "parse.h"
+
+//Public Functions
+/******************************************************************************/
+void Left(char *DestStr, const char *SourceStr, const int Len) {
+  memcpy(DestStr, SourceStr, Len);
+  DestStr[Len] = 0;
+}
+/******************************************************************************/
+void Right(char *DestStr, const char *SourceStr, const int Len) {
+  int SourceLen, Offset;
+  
+  SourceLen = strlen(SourceStr);
+  Offset = SourceLen - Len;
+  
+  memcpy(DestStr, SourceStr + Offset, Len + 1);
+  //The null is already copied
+}
+/******************************************************************************/
+void TrimLeft(char *TargetStr) {
+  int i, NewStrSize;
+  
+  i = 0;
+  //Find the first non-space charactor
+  while ( (TargetStr[i] == ' ') || (TargetStr[i] == '\t') ) {
+    i++;
+  }
+  //If we have space to get rid of, move the string
+  if (i > 0) {
+    NewStrSize = strlen(TargetStr) - i + 1; //Include the NULL in the size
+    memmove(TargetStr, TargetStr + i, NewStrSize);
+  }
+}
+/******************************************************************************/
+void TrimRight(char *TargetStr) {
+  int i;
+  
+  //Find the last non-space charactor (index i)
+  i = strlen(TargetStr) - 1;
+  while ((i >= 0) && ((TargetStr[i] == ' ') || (TargetStr[i] == '\t')) ) {
+    i--;
+  }
+  //Set the NULL 1 after the last non-space charactor
+  TargetStr[i+1] = 0;
+}
+/******************************************************************************/
+void Trim(char *TargetStr) {
+  TrimRight(TargetStr);
+  TrimLeft(TargetStr);
+}
+/******************************************************************************/
+void GetWord(char *DestStr, const char *SourceStr, const int Start, int &End) {
+  int i, Len;
+  
+  Len = 0;
+  i = Start;
+  while ((SourceStr[i] != ' ') && (SourceStr[i] != '\t') && (SourceStr[i] != 0)) {
+    Len++;
+    i++;
+  }
+  //Create the substring
+  memcpy(DestStr, SourceStr + Start, Len);
+  DestStr[Len] = 0;
+  //Set End
+  while ((SourceStr[i] != 0) &&
+	 ((SourceStr[i] == ' ') || (SourceStr[i] == '\t'))) {
+    i ++;
+  }
+  End = i;
+}
+/******************************************************************************/
+void GetLastWord(char *DestString, const char *SourceStr, int &Start) {
+  int SourceLen, i, Len;
+  
+  Len = 0;
+  SourceLen = strlen(SourceStr);
+  i = SourceLen - 1;
+  while ((i >= 0) && (SourceStr[i] != ' ') && (SourceStr[i] != '\t')) {
+    Len++;
+    i--;
+  }
+  //Create the substring
+  memcpy(DestString, SourceStr + SourceLen - Len, Len);
+  DestString[Len] = 0;
+  Start = i + 1;
+}
+/******************************************************************************/
+void SplitPath(char *Path, char *Dir, char *FileName) {
+  int SplitPoint;
+  SplitPoint = strlen(Path) - 1;
+  while ((SplitPoint > 0) && (Path[SplitPoint] != '\\')) {
+    SplitPoint--;
+  }
+  if ((SplitPoint == 0) && (Path[SplitPoint] != '\\')) {
+    //No directory, just a file name
+    Dir[0] = 0;
+    strcpy(FileName, Path);
+  }
+  else {
+    //Move past the last slash
+    SplitPoint++;
+    
+    //Directory
+    int i = 0;
+    while (i < SplitPoint) {
+      Dir[i] = Path[i];
+      i++;
+    }
+    Dir[i] = 0;
+    
+    //File name
+    int j = 0;
+    while (Path[i] != 0) {
+      FileName[j] = Path[i];
+      j++;
+      i++;
+    }
+    FileName[j] = 0;
+  }
+}
+/******************************************************************************/
+void GetExtention(char *Path, char *Extention) {
+  int Dot;
+  int PathLen;
+  
+  PathLen = strlen(Path) - 1;
+  Dot = PathLen;
+  while ((Dot > 0) && (Path[Dot] != '.')) {
+    Dot--;
+  }
+  if (Dot > 0) {
+    strcpy(Extention, Path + Dot + 1);
+  }
+  else {
+    Extention[0] = 0;
+  }
+}
+/******************************************************************************/
+void TranslateEscapeString(char *TargetStr) {
+  int i = 0;
+  int j = 0;
+  
+  while (TargetStr[i] != 0) {
+    if ((TargetStr[i] == '%') && (TargetStr[i+1] != 0) && (TargetStr[i+2] != 0)) {
+      //Escaped value (did checking to make sure there are 2 more chars)
+      //         #pragma warn -sig //Suppress significant digit loss warning (BC++)
+      TargetStr[j] = 16 * HexVal(TargetStr[i+1]) + HexVal(TargetStr[i+2]);
+      //         #pragma warn +sig   //Restore significant digit loss warning (BC++)
+      i += 3;
+    }
+    else {
+      TargetStr[j] = TargetStr[i];
+      i++;
+    }
+    j++;
+  }
+  TargetStr[j] = 0;
+}
+/******************************************************************************/
+int HexVal(char c) {
+  //   #pragma warn -sig //Suppress significant digit loss warning (BC++)
+  if (c >= '0' && c <= '9') return c - '0';
+  else if (c >= 'a' && c <= 'f') return c - 'a' + 10;
+  else if (c >= 'A' && c <= 'F') return c - 'A' + 10;
+  else return 0;
+  //   #pragma warn +sig   //Restore significant digit loss warning (BC++)
+}
+/******************************************************************************/
Index: /main/tags/2.25/gsdl/src/w32server/parse.h
===================================================================
--- /main/tags/2.25/gsdl/src/w32server/parse.h	(revision 21064)
+++ /main/tags/2.25/gsdl/src/w32server/parse.h	(revision 21064)
@@ -0,0 +1,153 @@
+/*
+Copyright (C) 1996
+
+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.
+
+The author can be contacted via Email at bmorin@wpi.edu
+*/
+
+/*
+Module Name: Parse
+Purpose: General string parsing.  These are functions that are not in string.h,
+	but are found in many other libraries and high level languages.
+Public Functions:
+	Left
+	Right
+
+	Trim
+	TrimLeft
+	TrimRight
+
+	GetWord
+	GetLastWord
+
+   Split Path
+   GetExtention
+*/
+
+/*
+Function Name: Left
+Purpose: Copies the leftmost x number of charactors of a string to a buffer
+Parameters:
+	DestStr - Destination buffer for substring
+	SourceStr - Source string to make substing from
+	Len - Length of substring
+
+Notes: If Len is greater than strlen(SourceStr) a memory error may occur.
+*/
+void Left(char *DestStr, const char *SourceStr, const int Len);
+
+/*
+Function Name: Right
+Purpose: Copies the rightmost x number of charactors of a string to a buffer
+Parameters:
+	DestStr - Destination buffer for substring
+	SourceStr - Source string to make substing from
+	Len - Length of substring
+
+Notes: If Len is greater than strlen(SourceStr) then a memory error may
+		 occur.
+*/
+void Right(char *DestStr, const char *SourceStr, const int Len);
+
+/*
+Function Name: TrimLeft
+Purpose: Removes spaces and tabs from the left end of a string.
+Parameters:
+	TargetString - String to be trimmed
+*/
+void TrimLeft(char *TargetStr);
+
+/*
+Function Name: TrimRight
+Purpose: Removes spaces and tabs from the right end of a string.
+Parameters:
+	TargetString - String to be trimmed
+*/
+void TrimRight(char *TargetStr);
+
+/*
+Function Name: Trim
+Purpose: Removes spaces and tabs from both ends of a string.
+Parameters:
+	TargetString - String to be trimmed
+*/
+void Trim(char *TargetStr);
+
+/*
+Function Name: GetWord
+Purpose: Gets leftmost substring without a space, starts at any position at
+	 the start string and sets End to be the next non-space charactor in the
+	 string.  ' ' and '\t' and considered spaces
+Parameters:
+	 DestString - Destination buffer for substring
+	 SourceString - Source string to make substing from
+	 Start - 0 based string index to start at
+	 End - At end of function call is set to the location of next non-space
+               charactor
+
+Notes: If Start is greater than strlen(SourceStr) then a memory error may
+		 occur.
+*/
+void GetWord(char *DestStr, const char *SourceStr, const int Start, int &End);
+
+/*
+Function Name: GetLastWord
+Purpose: Gets rightmost substring without a space sets Start to be the 0 based
+	index of where the substring starts in the original string.
+Parameters:
+	DestString - Destination buffer for substring
+	SourceString - Source string to make substing from
+	Start - 0 based string index where the DestString starts at
+*/
+void GetLastWord(char *DestString, const char *SourceStr, int &Start);
+
+
+/*
+Function Name: Split Path
+Purpose: Splits a path string into directory and file name
+Parameters:
+	Path - Path string (example "c:\Fnord\SomeFile.Ext")
+	Dir - Directory part of the Path (example "c:\Fnord\")
+	FileName - File name part of the path (example "SomeFile.Ext")
+*/
+void SplitPath(char *Path, char *Dir, char *FileName);
+
+/*
+Function Name: Get Extention
+Purpose: Splits a path string into directory and file name
+Parameters:
+	Path - Path string or file name (example "c:\Fnord\SomeFile.Ext")
+	Extention - Extention part of the path (example "Ext")
+*/
+void GetExtention(char *Path, char *Extention);
+
+/*
+Function Name: Translate Escape String
+Purpose: Translates all URL escape sequences, such as "%20" where "20" is
+	the resulting charactor in hexidecimal
+Parameters:
+	TargetStr - String that may contain URL escape sequences.  All sequences
+   	are decoded on return.
+*/
+void TranslateEscapeString(char *TargetStr);
+
+/*
+Function Name: Hex Value
+Purpose: Returns the value of a hexidecimal digit character as an integer
+Parameters:
+	c - Charactor to translate
+*/
+int HexVal(char c);
Index: /main/tags/2.25/gsdl/src/w32server/resource.h
===================================================================
--- /main/tags/2.25/gsdl/src/w32server/resource.h	(revision 21064)
+++ /main/tags/2.25/gsdl/src/w32server/resource.h	(revision 21064)
@@ -0,0 +1,50 @@
+//{{NO_DEPENDENCIES}}
+// Microsoft Developer Studio generated include file.
+// Used by server.rc
+//
+#define TRAY_ICON                       101
+#define COMMS_DIALOG                    102
+#define COMMS_DIALOG_DEBUG              102
+#define Main_Menu                       103
+#define COMMS_DIALOG2                   103
+#define GSDL_LOGO                       108
+#define GSDL_COL_TITLE                  109
+#define IDD_DIALOG1                     118
+#define GSDL_ICBMP                      126
+#define APPLY_BUTTON                    1000
+#define REMOTE_CHECK                    1001
+#define PROXY_CHECK                     1002
+#define CONSOLE_CHECK                   1003
+#define PROXY_EDIT_BOX                  1004
+#define PROXY_PORT_EDIT_BOX             1005
+#define TrayID                          1006
+#define LOG_DEBUG_CHECK                 1007
+#define SERVER_PORT_EDIT_BOX            1008
+#define LOG_LOCAL_CHECK                 1009
+#define LOG_REMOTE_CHECK                1010
+#define LOG_NAME_BOX                    1011
+#define LOG_CHECK                       1012
+#define SAVE_NAME_BOX                   1013
+#define SAVE_CHECK                      1014
+#define ID_AUTO_ENTER_LIBRARY           1015
+#define ID_RADIO_NETSCAPE               1016
+#define ID_RADIO_IE                     1017
+#define ID_RADIO_OTHER                  1018
+#define ID_OTHER_NAME                   1019
+#define ID_BROWSE_BUTTON                1020
+#define ID_OK_BUTTON                    1021
+#define ID_CANCEL_BUTTON                1022
+#define ID_PROJECT_SETTINGS             40001
+#define ID_PROJECT_EXIT                 40002
+#define ID_INSTALL_NETSCAPE             40007
+
+// Next default values for new objects
+// 
+#ifdef APSTUDIO_INVOKED
+#ifndef APSTUDIO_READONLY_SYMBOLS
+#define _APS_NEXT_RESOURCE_VALUE        127
+#define _APS_NEXT_COMMAND_VALUE         40011
+#define _APS_NEXT_CONTROL_VALUE         1026
+#define _APS_NEXT_SYMED_VALUE           102
+#endif
+#endif
Index: /main/tags/2.25/gsdl/src/w32server/settings.cpp
===================================================================
--- /main/tags/2.25/gsdl/src/w32server/settings.cpp	(revision 21064)
+++ /main/tags/2.25/gsdl/src/w32server/settings.cpp	(revision 21064)
@@ -0,0 +1,793 @@
+#include "text_t.h"
+
+#if defined(GSDL_USE_OBJECTSPACE)
+#  include <ospace\std\fstream>
+#elif defined(GSDL_USE_IOS_H)
+#  include <fstream.h>
+#else
+#  include <fstream>
+#endif
+
+#include <windows.h>
+#include "httpsrv.h"
+#include "settings.h"
+#include "locate.h"
+#include "resource.h"
+#include "cgiwrapper.h"
+
+// library settings
+text_t gsdl_enterlib;
+text_t gsdl_gsdlhome;
+text_t gsdl_gdbmhome;
+text_t gsdl_collections;
+colinfo_tmap gsdl_collectinfo;
+
+char gsdl_staticpages[MAX_FILENAME_SIZE];
+
+// debug settings
+char gsdl_log_name[MAX_FILENAME_SIZE] = "c:\\gsdl.log";
+int gsdl_keep_log = 0;
+int gsdl_show_console = 0;
+
+// general settings
+int gsdl_port_num = 80;
+int gsdl_auto_enter = 0;
+int gsdl_browser = GS_NETSCAPE;
+char gsdl_browser_exe[MAX_FILENAME_SIZE] = "";
+
+
+// private data
+
+// pathnames of the latest installed versions of netscape and
+// internet explorer
+static char netscape_exe[MAX_FILENAME_SIZE]="";
+static char iexplore_exe[MAX_FILENAME_SIZE]="";
+
+// pathname of the default browser
+static char default_browser_exe[MAX_FILENAME_SIZE]="";
+
+// whether netscape is needed (used in the settings dialog box)
+static int gsdl_netscapeneeded = 0;
+
+static void remove_end_slashes(char *str) {
+  int len = strlen (str);
+  while ((len > 0) && ((str[len-1] == '\\') || (str[len-1] == '/'))) {
+    len --;
+  }
+  str[len] = '\0';
+}
+
+static void remove_end_slashes (text_t &str) {
+  char *cstr = str.getcstr();
+  remove_end_slashes (cstr);
+  str = cstr;
+  delete cstr;
+}
+
+// returns 1 if successful, 0 otherwise
+// checks for a file's existence
+static int check_program_exe (char *path) {
+  UINT curerrormode;
+  OFSTRUCT reOpenBuff;
+  int retvalue = 0;
+  
+  reOpenBuff.cBytes = sizeof (OFSTRUCT);
+  
+  curerrormode = SetErrorMode(SEM_FAILCRITICALERRORS | SEM_NOOPENFILEERRORBOX);
+  if (OpenFile(path, &reOpenBuff, OF_EXIST) != HFILE_ERROR) retvalue = 1;
+  SetErrorMode(curerrormode);
+  
+  return retvalue;
+}
+
+
+// returns 1 if successful, 0 otherwise
+static int get_default_browser_path (char *providedhtmltype, char *path, int maxsize) {
+  HKEY hk1, hk2;
+  char htmltype[256];
+  long size;
+  int retval = 0;
+  
+  htmltype[0] = '\0';
+  path[0] = '\0';
+  
+  // try and get information about the default browser from the 
+  // registry
+  
+  if (providedhtmltype != NULL) strcpy (htmltype, providedhtmltype);
+  
+  else if (RegOpenKey(HKEY_CLASSES_ROOT, ".htm", &hk1) == ERROR_SUCCESS) {
+    size = 256;
+    RegQueryValue(hk1, NULL, htmltype, &size);
+    RegCloseKey(hk1);
+  }
+  
+  if (RegOpenKey(HKEY_CLASSES_ROOT, htmltype, &hk1) == ERROR_SUCCESS) {
+    if (RegOpenKey(hk1, "shell\\open", &hk2) == ERROR_SUCCESS) {
+      // look for the command to start the browser
+      size = maxsize;
+      if (RegQueryValue(hk2,"command",path,&size) == ERROR_SUCCESS) {
+				// strip all excess stuff off the command
+	char endchar = ' ';
+	int i = 0, len = 0;
+	int state = 0; // 0=strip initial white-space and quotes, 1=grab path
+	while (path[i] != '\0') {
+	  if (state == 0) {
+	    if (path[i] == ' ') {
+	      // do nothing
+	    } else if (path[i] == '"') {
+	      endchar = '"';
+	      state = 1;
+	    } else {
+	      state = 1;
+	      path[len] = path[i];
+	      len++;
+	    }
+	  } else {
+	    if (path[i] == endchar) break;
+	    path[len] = path[i];
+	    len++;
+	  }
+	  i++;
+	}
+	path[len] = '\0';
+	
+	// check the resulting pathname
+	if (check_program_exe (path)) {
+	  retval = 1; // succeeded
+	} else {
+	  path[0] = '\0'; // failed (must have been deleted or something...)
+	}
+      }
+      RegCloseKey(hk2);
+    }
+    RegCloseKey(hk1);
+  }
+  
+  return retval;
+}
+
+
+// returns 1 if successful, 0 otherwise
+// note that appname should include .exe (e.g. netscape.exe)
+static int registry_get_app_paths (char *appname, char *path, int maxsize) {
+  HKEY hk1;
+  long size;
+  int retval = 0;
+  
+  path[0] = '\0';
+  
+  if (RegOpenKey(HKEY_LOCAL_MACHINE, 
+		 "Software\\Microsoft\\Windows\\CurrentVersion\\App Paths", 
+		 &hk1) == ERROR_SUCCESS) {
+    size = maxsize;
+    if (RegQueryValue (hk1, appname, path, &size) == ERROR_SUCCESS &&
+	check_program_exe (path));
+    retval = 1;
+    
+    RegCloseKey(hk1);
+  }
+  
+  return retval;
+}
+
+static void check_installed_browsers (int netscapeneeded) {
+  netscape_exe[0] = '\0';
+  iexplore_exe[0] = '\0';
+  default_browser_exe[0] = '\0';
+  
+  // update the default browser information (if netscape isn't needed)
+  if (!netscapeneeded) {
+    get_default_browser_path (NULL, default_browser_exe, MAX_FILENAME_SIZE);
+    _strlwr (default_browser_exe);
+  }
+  
+  // look for netscape
+  
+  // first look for netscape in the registry
+  if (!registry_get_app_paths("netscape.exe", netscape_exe, MAX_FILENAME_SIZE)) {
+    // next look for "NetscapeMarkup"
+    if (get_default_browser_path ("NetscapeMarkup", netscape_exe, MAX_FILENAME_SIZE)) {
+      _strlwr (netscape_exe);
+      if (!strstr (netscape_exe, "netscape.exe")) {
+	netscape_exe[0] = '\0';
+	
+	// next look for \netscape\netscape.exe
+	
+	// get drive letter of the windows directory
+	GetWindowsDirectory(netscape_exe, MAX_FILENAME_SIZE);
+	netscape_exe[1] = '\0';
+	strcat (netscape_exe, ":\\netscape\\netscape.exe");
+	
+	if (!check_program_exe (netscape_exe)) {
+	  // lastly look for \netscape\program\netscape.exe
+	  netscape_exe[1] = '\0';
+	  strcat (netscape_exe, ":\\netscape\\program\\netscape.exe");
+	  
+	}
+      }
+    }
+  }
+  _strlwr (netscape_exe);
+  if ((strlen (netscape_exe) > 0) && !check_program_exe (netscape_exe)) {
+    netscape_exe[0] = '\0';  // couldn't find netscape
+  }
+  
+  // look for internet explorer (if netscape isn't needed)
+  
+  // first look for iexplore in the registry
+  if (!netscapeneeded && !registry_get_app_paths("iexplore.exe", 
+						 iexplore_exe, MAX_FILENAME_SIZE)) {
+    // next look for "htmlfile"
+    if (get_default_browser_path ("htmlfile", iexplore_exe, MAX_FILENAME_SIZE)) {
+      _strlwr (iexplore_exe);
+      if (!strstr (iexplore_exe, "iexplore.exe")) {
+	iexplore_exe[0] = '\0';
+	
+	// next look for \iexplore\iexplore.exe
+	
+	// get drive letter of the windows directory
+	GetWindowsDirectory(iexplore_exe, MAX_FILENAME_SIZE);
+	iexplore_exe[1] = '\0';
+	strcat (iexplore_exe, ":\\iexplore\\iexplore.exe");
+      }
+    }
+  }
+  _strlwr (iexplore_exe);
+  if ((strlen (iexplore_exe) > 0) && !check_program_exe (iexplore_exe)) {
+    iexplore_exe[0] = '\0';  // couldn't find internet explorer
+  }
+}
+
+void write_settings () {
+  char conffile[MAX_FILENAME_SIZE];
+  
+  strcpy (conffile, data_location);
+  remove_end_slashes (conffile);
+  strcat (conffile, "\\gsdl.ini");
+  
+  ofstream fout (conffile);
+  if (fout) {
+    
+    outconvertclass text_t2ascii;
+
+    // top (gsdl) level stuff
+    fout << "[gsdl]\n";
+    write_ini_line(fout, "enterlib", gsdl_enterlib);
+    write_ini_line(fout, "gsdlhome", gsdl_gsdlhome);
+    write_ini_line(fout, "gdbmhome", gsdl_gdbmhome);
+    
+    write_ini_line(fout, "logfilename", gsdl_log_name);
+    write_ini_line(fout, "keeplog", text_t(gsdl_keep_log));
+    write_ini_line(fout, "consolelog", text_t(gsdl_show_console));
+    
+    write_ini_line(fout, "portnumber", text_t(gsdl_port_num));
+    write_ini_line(fout, "autoenter", text_t(gsdl_auto_enter));
+    write_ini_line(fout, "browser", text_t(gsdl_browser));
+    write_ini_line(fout, "browserexe", gsdl_browser_exe);
+    write_ini_line(fout, "collections", gsdl_collections);
+    
+    // collection levels
+    colinfo_tmap::iterator here = gsdl_collectinfo.begin();
+    colinfo_tmap::iterator end = gsdl_collectinfo.end();
+    while (here != end) {
+      fout << text_t2ascii << "[" << (*here).first << "]\n";
+      if (!(*here).second.gsdl_gsdlhome.empty()) 
+	write_ini_line(fout, "gsdlhome", (*here).second.gsdl_gsdlhome);
+      if (!(*here).second.gsdl_gdbmhome.empty()) 
+	write_ini_line(fout, "gdbmhome", (*here).second.gsdl_gdbmhome);
+      
+      here ++;
+    }
+    fout.close();
+  }
+}
+
+
+// browser_compare assumes that check_exe is in lowercase
+static int browser_compare (char *browser_exe_path, char *check_exe) {
+  char tmp_exe[MAX_FILENAME_SIZE];
+  strcpy (tmp_exe, browser_exe_path);
+  _strlwr (tmp_exe);
+  return (strstr (tmp_exe, check_exe) != NULL);
+}
+
+// This function assumes that check_installed_browsers
+// has been recently called
+// It also assumes that browser_exe is large
+// enough to receive any path names to any browser
+static void check_browser_settings (int &browser, char *browser_exe, 
+				    int netscapeneeded) {
+  
+  // sort out which browser to use
+  if ((browser == GS_NETSCAPE) && (netscape_exe[0] == '\0'))
+    browser = GS_IEXPLORE;
+  if ((browser == GS_IEXPLORE) && (netscapeneeded || (iexplore_exe[0] == '\0'))) {
+    if (netscape_exe[0] != '\0') browser = GS_NETSCAPE;
+    else browser = GS_OTHER;
+  }
+  if ((browser == GS_OTHER) && netscapeneeded && 
+      !browser_compare (browser_exe, "netscape.exe") && (netscape_exe[0] != '\0')) {
+    // this other browser isn't netscape and netscape is available
+    browser = GS_NETSCAPE;
+  }
+  
+  
+  // get the browser's executable
+  if (browser == GS_NETSCAPE) {
+    strcpy (browser_exe, netscape_exe);
+  } else if (browser == GS_IEXPLORE) {
+    strcpy (browser_exe, iexplore_exe);
+  } else {
+    browser = GS_OTHER;
+    
+    // if the browser should be netscape then check to
+    // make sure it is
+    if (netscapeneeded && !browser_compare (browser_exe, "netscape.exe")) {
+      // not netscape, set to no browser
+      browser_exe[0] = '\0';
+    }
+  }
+}
+
+
+static void revert_defaults (int netscapeneeded) {
+  find_location();
+  
+  // library settings
+  gsdl_enterlib = "/cgi-bin/gw";
+  gsdl_gsdlhome = data_location;
+  gsdl_gdbmhome = data_location;
+  
+  // debug settings
+  gsdl_keep_log = 0;
+  strcpy (gsdl_log_name, "c:\\gsdl.log");
+  gsdl_show_console = 0;
+  
+  // general settings
+  gsdl_port_num = 80;
+  gsdl_auto_enter = 0;
+  
+  check_installed_browsers (netscapeneeded);
+  gsdl_browser = GS_NETSCAPE;
+  strcpy (gsdl_browser_exe, default_browser_exe);
+  check_browser_settings (gsdl_browser, gsdl_browser_exe, netscapeneeded);
+}
+
+void read_settings (int netscapeneeded) {
+  char conffile[MAX_FILENAME_SIZE];
+  
+  find_location();
+  
+  strcpy (conffile, data_location);
+  remove_end_slashes (conffile);
+  strcat (conffile, "\\gsdl.ini");
+  
+  // set up defaults
+  revert_defaults (netscapeneeded);
+  
+  text_t key, value, section;
+  char *cstr_value;
+#if defined (GSDL_USE_IOS_H)
+  ifstream conf (conffile, ios::nocreate);
+#else
+  ifstream conf (conffile);
+#endif
+  if (conf) {
+    while (read_ini_line(conf, key, value) >= 0) {
+      if (value.empty()) {
+	// should be a section title
+	section = key;
+	// remove square brackets
+	section.erase (section.begin());
+	section.erase (section.end()-1);
+
+      } else {
+
+	cstr_value = value.getcstr ();
+      
+	if (section == "gsdl") {
+
+	  if (key == "enterlib") {
+	    gsdl_enterlib = value;
+	  
+	    // 'logfilename' should occur in the configuration file
+	    // before 'keeplog'
+	  } else if (key == "logfilename") {
+	    strcpy (gsdl_log_name, cstr_value);
+	  
+	  } else if (key == "keeplog") {
+	    gsdl_keep_log = value.getint();
+	    if (gsdl_keep_log) open_log_file();
+	
+	  } else if (key == "consolelog") {
+	    if (value.getint()) activate_console();
+	    else deactivate_console();
+	
+	  } else if (key == "portnumber") {
+	    gsdl_port_num = value.getint();
+	    
+	  } else if (key == "autoenter") {
+	    gsdl_auto_enter = value.getint();
+	
+	  } else if (key == "browser") {
+	    gsdl_browser = value.getint();
+	
+	  } else if (key == "browserexe") {
+	    strcpy (gsdl_browser_exe, cstr_value);
+
+	  } else if (key == "collections") {
+	    gsdl_collections = value;
+
+	  // gsdlhome must occur in file before gdbmhome	    
+	  } else if (key == "gsdlhome") {
+	    gsdl_gsdlhome = value;
+	    gsdl_gdbmhome = value;
+	  
+	  } else if (key == "gdbmhome") {
+	    gsdl_gdbmhome = value;
+	  }
+	} else {
+	  
+	  // gsdlhome must occur in file before gdbmhome
+	  if (key == "gsdlhome") {
+	    gsdl_collectinfo[section].gsdl_gsdlhome = value;
+	    gsdl_collectinfo[section].gsdl_gdbmhome = value;
+	  } else if (key == "gdbmhome") {
+	    gsdl_collectinfo[section].gsdl_gdbmhome = value;
+	  }
+	}
+	delete cstr_value;
+      }
+    }
+    conf.close();
+  }
+  
+  // check the homes to make sure they don't contain
+  // extra slashes at the end
+  remove_end_slashes (gsdl_gsdlhome);
+  remove_end_slashes (gsdl_gdbmhome);
+  colinfo_tmap::iterator here = gsdl_collectinfo.begin();
+  colinfo_tmap::iterator end = gsdl_collectinfo.end();
+  while (here != end) {
+    remove_end_slashes ((*here).second.gsdl_gsdlhome);
+    remove_end_slashes ((*here).second.gsdl_gdbmhome);
+    here ++;
+  }
+
+  // check the browser settings
+  check_browser_settings (gsdl_browser, gsdl_browser_exe, netscapeneeded);
+}
+
+void gsdl_check_browser_settings (int netscapeneeded) {
+  check_installed_browsers (netscapeneeded);
+  check_browser_settings (gsdl_browser, gsdl_browser_exe, netscapeneeded);
+}
+
+
+static void dialog_update_enables (HWND hwndDlg) {
+  int res;
+  
+  // if they want to use another browser, they should be able
+  // edit its filename
+  res = SendDlgItemMessage(hwndDlg, ID_RADIO_OTHER, BM_GETCHECK,0,0);
+  SendDlgItemMessage(hwndDlg, ID_OTHER_NAME, WM_ENABLE, (res == 1), 0);
+}
+
+
+static int read_dialog_browser_field (HWND hwndDlg) {
+  if (SendDlgItemMessage(hwndDlg, ID_RADIO_NETSCAPE,
+			 BM_GETCHECK, 0, 0) == 1) return GS_NETSCAPE;
+  if (SendDlgItemMessage(hwndDlg, ID_RADIO_IE,
+			 BM_GETCHECK, 0, 0) == 1) return GS_IEXPLORE;
+  if (SendDlgItemMessage(hwndDlg, ID_RADIO_OTHER,
+			 BM_GETCHECK, 0, 0) == 1) return GS_OTHER;
+  return GS_NETSCAPE;
+}
+
+
+
+static void set_dialog_browser_field (HWND hwndDlg, int browser, char *othername) {
+  // if we are trying to set the browser to netscape or
+  // internet explorer and we can't find them, set the browser
+  // to 'other'
+  if ((browser == GS_NETSCAPE) && (netscape_exe[0] == '\0'))
+    browser = GS_IEXPLORE;
+  if ((browser == GS_IEXPLORE) && (iexplore_exe[0] == '\0')) {
+    if (netscape_exe[0] != '\0') browser = GS_NETSCAPE;
+    else browser = GS_OTHER;
+  }
+  
+  // update the radio buttons
+  SendDlgItemMessage(hwndDlg, ID_RADIO_NETSCAPE, BM_SETCHECK,
+		     (browser == GS_NETSCAPE) ? BST_CHECKED : BST_UNCHECKED, 0);
+  SendDlgItemMessage(hwndDlg, ID_RADIO_IE, BM_SETCHECK,
+		     (browser == GS_IEXPLORE) ? BST_CHECKED : BST_UNCHECKED, 0);
+  SendDlgItemMessage(hwndDlg, ID_RADIO_OTHER, BM_SETCHECK,
+		     (browser == GS_OTHER) ? BST_CHECKED : BST_UNCHECKED, 0);
+  
+  // update the other name field
+  if (browser == GS_NETSCAPE) {
+    SetDlgItemText(hwndDlg, ID_OTHER_NAME, netscape_exe);
+  } else if (browser == GS_IEXPLORE) {
+    SetDlgItemText(hwndDlg, ID_OTHER_NAME, iexplore_exe);
+  } else if (othername != NULL) {
+    SetDlgItemText(hwndDlg, ID_OTHER_NAME, othername);
+  }
+}
+
+
+static void read_browser_exe_field (HWND hwndDlg, char *filename, int maxsize) {
+  filename[0] = '\0';
+  GetDlgItemText(hwndDlg, ID_OTHER_NAME, filename, maxsize);
+}
+
+
+static void read_dialog_fields (HWND hwndDlg) {
+  int res;  BOOL bres;
+  
+  // port number
+  gsdl_port_num = GetDlgItemInt(hwndDlg, SERVER_PORT_EDIT_BOX, &bres, 0);
+  if (!bres) gsdl_port_num = 80;
+  
+  // whether to enter the library automatically on startup
+  res = SendDlgItemMessage(hwndDlg, ID_AUTO_ENTER_LIBRARY, BM_GETCHECK, 0, 0);
+  gsdl_auto_enter = (res == 1);
+  
+  // which browser to use
+  gsdl_browser = read_dialog_browser_field (hwndDlg);
+  
+  // find out where the browser exe lives
+  read_browser_exe_field (hwndDlg, gsdl_browser_exe, MAX_FILENAME_SIZE);
+}
+
+
+
+
+static BOOL CALLBACK dialog_proc(HWND hwndDlg, UINT uMsg, 
+				 WPARAM wParam,LPARAM  lParam) {
+  int wNotifyCode = HIWORD(wParam);
+  int wID = LOWORD(wParam);
+  char *filefilter = "Program Files (*.exe)\0*.exe\0All Files (*.*)\0*.*\0\0";
+  OPENFILENAME fname;
+  char filename[MAX_FILENAME_SIZE];
+  
+  switch (uMsg) {
+  case WM_INITDIALOG:
+    // set current values
+    SetDlgItemInt(hwndDlg, SERVER_PORT_EDIT_BOX, gsdl_port_num, FALSE);
+    SendDlgItemMessage(hwndDlg, ID_AUTO_ENTER_LIBRARY, BM_SETCHECK,
+		       gsdl_auto_enter ? 1 : 0, 0);
+    set_dialog_browser_field (hwndDlg, gsdl_browser, gsdl_browser_exe);
+    dialog_update_enables(hwndDlg);
+    
+    // make sure that the netscape and internet explorer
+    // radio buttons are only enabled if they could be found
+    if (netscape_exe[0] == '\0')
+      EnableWindow (GetDlgItem (hwndDlg, ID_RADIO_NETSCAPE), FALSE);
+    if (iexplore_exe[0] == '\0')
+      EnableWindow (GetDlgItem (hwndDlg, ID_RADIO_IE), FALSE);
+    
+    return 1;
+    
+  case WM_COMMAND:
+    if (wNotifyCode == BN_CLICKED) {
+      switch (wID) {
+      case ID_CANCEL_BUTTON:
+	EndDialog(hwndDlg, 0);
+	return 1;
+	
+      case ID_OK_BUTTON:
+	// check to make sure we can find the browser
+	filename[0] = '\0';
+	read_browser_exe_field (hwndDlg, filename, MAX_FILENAME_SIZE);
+	if (check_program_exe (filename)) { 
+	  // the file exists
+	  // if netscape is needed, make sure the browser is netscape
+	  _strlwr(filename);
+	  if (!gsdl_netscapeneeded || strstr (filename, "netscape.exe") != NULL) {
+	    // everything is ok
+	    read_dialog_fields(hwndDlg);
+	    EndDialog(hwndDlg, 1);
+	    
+	  } else {
+	    // message: must use netscape with this version
+	    MessageBox(hwndDlg,
+		       "You are using this software on a machine which\n"
+		       "currently does not have a working TCP/IP network layer.\n"
+		       "To allow the Greenstone Digital Library software to use\n"
+		       "its own TCP/IP network layer you must use a Netscape\n"
+		       "browser. If you do not have Netscape installed, please\n"
+		       "choose 'Install Netscape 4.05' from the 'Files' menu.",
+		       "Greenstone Digital Library Software",
+		       MB_OK|MB_APPLMODAL);
+	  }
+	} else {
+	  // message: the file did not exist
+	  MessageBox(hwndDlg,
+		     "Could not find the selected browser. If you do not\n"
+		     "have a browser installed, please choose\n"
+		     "'Install Netscape 4.05' from the 'Files' menu.",
+		     "Greenstone Digital Library Software",
+		     MB_OK|MB_APPLMODAL);
+	}
+	return 1;
+	
+      case ID_RADIO_NETSCAPE:
+	set_dialog_browser_field (hwndDlg, GS_NETSCAPE, NULL);
+	dialog_update_enables(hwndDlg);
+	return 1;
+	
+      case ID_RADIO_IE:
+	set_dialog_browser_field (hwndDlg, GS_IEXPLORE, NULL);
+	dialog_update_enables(hwndDlg);
+	return 1;
+	
+      case ID_RADIO_OTHER:
+	set_dialog_browser_field (hwndDlg, GS_OTHER, NULL);
+	dialog_update_enables(hwndDlg);
+	return 1;
+	
+      case ID_BROWSE_BUTTON:
+	filename[0] = '\0';
+	memset(&fname, 0, sizeof(OPENFILENAME));
+	fname.lStructSize = sizeof(OPENFILENAME);
+	fname.hwndOwner = hwndDlg;
+	fname.hInstance = NULL;
+	fname.lpstrFilter = filefilter;
+	fname.lpstrCustomFilter = NULL;
+	fname.nMaxCustFilter = 0;
+	fname.nFilterIndex = 1;
+	fname.lpstrFile = filename;
+	fname.nMaxFile = MAX_FILENAME_SIZE-1;
+	fname.lpstrFileTitle = NULL;
+	fname.nMaxFileTitle = 0;
+	fname.lpstrInitialDir = NULL;
+	fname.lpstrTitle = "Choose Web Browser";
+	fname.Flags = OFN_FILEMUSTEXIST | OFN_HIDEREADONLY;
+	
+	if(GetOpenFileName(&fname)) {
+	  set_dialog_browser_field (hwndDlg, GS_OTHER, filename);
+	  dialog_update_enables(hwndDlg);
+	}
+	return 1;
+      }
+    }
+    return 0;
+    
+  case WM_CLOSE:
+  case WM_DESTROY:
+    EndDialog(hwndDlg, 0);
+    return 1;
+  }
+  
+  return 0;
+}
+
+static void dialog_debug_update_enables (HWND hwndDlg) {
+  int res;
+  
+  // if they want a log of program use allow them to
+  // edit its filename
+  res = SendDlgItemMessage(hwndDlg, LOG_CHECK, BM_GETCHECK,0,0);
+  SendDlgItemMessage(hwndDlg, LOG_NAME_BOX, WM_ENABLE, (res == 1), 0);
+}
+
+
+static void read_dialog_debug_fields (HWND hwndDlg) {
+  int res;
+  
+  // whether to log program use
+  res = SendDlgItemMessage(hwndDlg, LOG_CHECK, BM_GETCHECK,0,0);
+  gsdl_keep_log = (res == 1);
+  
+  // log filename
+  res = SendDlgItemMessage(hwndDlg, LOG_NAME_BOX, EM_GETMODIFY,0,0);
+  if (res != 0) {
+    res = GetDlgItemText(hwndDlg, LOG_NAME_BOX, gsdl_log_name, MAX_FILENAME_SIZE);
+  }
+  
+  // whether to display log information on console
+  res = SendDlgItemMessage(hwndDlg, CONSOLE_CHECK, BM_GETCHECK,0,0);
+  gsdl_show_console = (res == 1);
+}
+
+
+static BOOL CALLBACK dialog_debug_proc(HWND hwndDlg, UINT uMsg, 
+				       WPARAM wParam,LPARAM  lParam) {
+  int wNotifyCode = HIWORD(wParam);
+  int wID = LOWORD(wParam);
+  
+  switch (uMsg) {
+  case WM_INITDIALOG:
+    // set current values
+    SendDlgItemMessage(hwndDlg, LOG_CHECK, BM_SETCHECK,
+		       gsdl_keep_log ? 1 : 0, 0);
+    SetDlgItemText(hwndDlg, LOG_NAME_BOX, gsdl_log_name);
+    SendDlgItemMessage(hwndDlg, CONSOLE_CHECK, BM_SETCHECK,
+		       gsdl_show_console ? 1 : 0, 0);
+    dialog_debug_update_enables(hwndDlg);
+    return 1;
+    
+  case WM_COMMAND:
+    if (wNotifyCode == BN_CLICKED) {
+      switch (wID) {
+      case ID_CANCEL_BUTTON:
+	EndDialog(hwndDlg, 0);
+	return 1;
+	
+      case ID_OK_BUTTON:
+	read_dialog_debug_fields(hwndDlg);
+	EndDialog(hwndDlg, 1);
+	return 1;
+	
+      case LOG_CHECK:
+	dialog_debug_update_enables(hwndDlg);
+	return 1;
+      }
+    }
+    return 0;
+    
+  case WM_CLOSE:
+  case WM_DESTROY:
+    EndDialog(hwndDlg, 0);
+    return 1;
+  }
+  
+  return 0;
+}
+
+
+void Settings_Dialog(HWND window, int netscapeneeded)
+{
+  int old_gsdl_show_console = gsdl_show_console;
+  int old_gsdl_port_num = gsdl_port_num;
+  
+  int res = 0;
+  
+  gsdl_netscapeneeded = netscapeneeded;
+  
+  if ((GetAsyncKeyState(VK_CONTROL) & 0x8000) && 
+      (GetAsyncKeyState(VkKeyScan('d')) & 0x8000)) {
+    // control-D was pressed, display debug settings
+    // dialog box
+    res = DialogBox (NULL, MAKEINTRESOURCE(COMMS_DIALOG_DEBUG),
+		     window, (DLGPROC)dialog_debug_proc);
+    
+    if (res == 1) {
+      // only update if exited via the OK button
+      if (gsdl_keep_log) open_log_file(); 
+      else close_log_file();
+      
+      // turn the console on/off if we need to
+      if (gsdl_show_console != old_gsdl_show_console) {
+	if (gsdl_show_console) activate_console ();
+	else deactivate_console ();
+      }
+    }
+    
+  } else {
+    // display normal settings dialog box
+    
+    // make sure everything is up-to-date
+    gsdl_check_browser_settings (netscapeneeded);
+    
+    res = DialogBox (NULL, MAKEINTRESOURCE(COMMS_DIALOG2),
+		     window, (DLGPROC)dialog_proc);
+
+    if (res == 1) {
+      // only update if exited via the OK button
+      if (gsdl_port_num != old_gsdl_port_num) {
+	EndHTTPServer();
+	StartHTTPServer(window);
+      }
+    }
+  }
+  
+  // save the settings if we exited via the ok button
+  if (res == 1) {
+    write_settings();
+    // reset httpprefix in case port number was changed
+    //    configure_httpprefix ();
+  }
+}
Index: /main/tags/2.25/gsdl/src/w32server/settings.h
===================================================================
--- /main/tags/2.25/gsdl/src/w32server/settings.h	(revision 21064)
+++ /main/tags/2.25/gsdl/src/w32server/settings.h	(revision 21064)
@@ -0,0 +1,43 @@
+#ifndef SETTINGS_H
+#define SETTINGS_H
+
+#ifndef MAX_FILENAME_SIZE
+#define MAX_FILENAME_SIZE 1024
+#endif
+
+#define GS_NETSCAPE 0
+#define GS_IEXPLORE 1
+#define GS_OTHER    2
+
+#include "text_t.h"
+#include "cfgread.h"
+#include "receptionist.h"
+
+// library settings
+extern text_t gsdl_enterlib;
+extern text_t gsdl_gsdlhome;
+extern text_t gsdl_gdbmhome;
+extern text_t gsdl_collections;
+extern colinfo_tmap gsdl_collectinfo;
+
+extern char gsdl_staticpages[MAX_FILENAME_SIZE];
+
+// debug settings
+extern char gsdl_log_name[MAX_FILENAME_SIZE];
+extern int gsdl_keep_log;
+extern int gsdl_show_console;
+
+// general settings
+extern int gsdl_port_num;
+extern int gsdl_auto_enter;
+extern int gsdl_browser;
+extern char gsdl_browser_exe[MAX_FILENAME_SIZE];
+
+void Settings_Dialog(HWND window, int netscapeneeded);
+
+void read_settings (int netscapeneeded);
+void write_settings ();
+
+void gsdl_check_browser_settings (int netscapeneeded);
+
+#endif
Index: /main/tags/2.25/gsdl/src/w32server/startbrowser.cpp
===================================================================
--- /main/tags/2.25/gsdl/src/w32server/startbrowser.cpp	(revision 21064)
+++ /main/tags/2.25/gsdl/src/w32server/startbrowser.cpp	(revision 21064)
@@ -0,0 +1,277 @@
+#include "startbrowser.h"
+#include <windows.h>
+#include <DDE.H>
+#include <DDEML.H>
+#include <string.h>
+#include <direct.h>
+#include "locate.h"
+
+#define SB_COMLEN 1024
+#define SB_DDETIMEOUT 60000UL  // One minute in milliseconds
+
+int numbrowserstarted = 0;
+
+static int inited = 0;
+
+static DWORD idInst = 0;
+static HINSTANCE hinst = NULL;
+static HSZ hszNetscapeName = NULL;
+static HSZ hszIExploreName = NULL;
+static HSZ hszOpenURLTopic = NULL;
+static HSZ hszActivateTopic = NULL;
+
+
+// budget callback
+HDDEDATA CALLBACK DdeCallback(UINT uType,     /* transaction type                 */
+							  UINT uFmt,      /* clipboard data format            */
+							  HCONV hconv,    /* handle of conversation           */
+							  HSZ hsz1,       /* handle of string                 */
+							  HSZ hsz2,       /* handle of string                 */
+							  HDDEDATA hdata, /* handle of global memory object   */
+							  DWORD dwData1,  /* transaction-specific data        */
+							  DWORD dwData2)  /* transaction-specific data        */ 
+{
+	return (HDDEDATA) NULL; 
+}
+
+
+// returns 0 on failure
+static int talkdde (HSZ hszServName, HSZ hszSysTopic, char *requeststr) {
+	HSZ hszRequest;
+	HCONV hConv;
+	HDDEDATA result;
+
+	// try to connect to the newly started browser
+	hConv = DdeConnect (idInst, hszServName, hszSysTopic, (PCONVCONTEXT) NULL);
+	if (hConv == NULL) return 0;
+
+	hszRequest = DdeCreateStringHandle (idInst, requeststr, CP_WINANSI);
+
+//HDDEDATA hRetVal = DdeClientTransaction(NULL, 0ul, m_hConv, 
+//								hszItem, CF_TEXT, 
+//								XTYP_REQUEST, 
+//								DDETIMEOUT, NULL);
+	result = DdeClientTransaction (
+		NULL,			// pointer to data to pass to server
+		0,				// length of data
+		hConv,			// handle to conversation
+		hszRequest,		// handle to item name string
+		CF_TEXT,		// clipboard data format
+		XTYP_REQUEST,	// transaction type
+		SB_DDETIMEOUT,	// time-out duration
+		NULL		 	// pointer to transaction result
+	);
+
+	if (result != NULL) DdeFreeDataHandle (result);
+	DdeDisconnect(hConv);
+	DdeFreeStringHandle (idInst, hszRequest);
+
+	return 1;
+}
+
+
+// returns 0 on failure
+static int openurl(HSZ hszServName, HSZ hszActivateTopic, HSZ hszOpenURLTopic, char *url) {
+	char requeststr[65600];
+
+	// bring the browser to the front, don't worry if this fails
+	talkdde (hszServName, hszActivateTopic, "0xFFFFFFFF,0x0");
+
+	// tell the browser to open a url
+	strcpy (requeststr, "\"");
+	strcat (requeststr, url);
+	strcat (requeststr, "\",,0xFFFFFFFF,0x0,,,");
+
+	return talkdde (hszServName, hszOpenURLTopic, requeststr);
+}
+
+// returns 0 on failure
+static int tryconnect(HSZ hszServName, HSZ hszSysTopic) {
+	// try to connect to a running browser
+	HCONV hConv = DdeConnect (idInst, hszServName, hszSysTopic, (PCONVCONTEXT) NULL);
+	if (hConv == NULL) return 0;
+	DdeDisconnect(hConv);
+	return 1;
+}
+
+static void freestrings () {
+	// free up any currently allocated strings
+	if (hszNetscapeName != NULL) DdeFreeStringHandle (idInst, hszNetscapeName);
+	hszNetscapeName = NULL;
+	if (hszIExploreName != NULL) DdeFreeStringHandle (idInst, hszIExploreName);
+	hszIExploreName = NULL;
+	if (hszOpenURLTopic != NULL) DdeFreeStringHandle (idInst, hszOpenURLTopic);
+	hszOpenURLTopic = NULL;
+	if (hszActivateTopic != NULL) DdeFreeStringHandle (idInst, hszActivateTopic);
+	hszActivateTopic = NULL;
+}
+
+
+
+static void getbrowserinfo() {
+	freestrings();
+
+	hszNetscapeName = DdeCreateStringHandle(idInst,"NETSCAPE",CP_WINANSI);
+	hszIExploreName = DdeCreateStringHandle(idInst,"IExplore",CP_WINANSI);
+
+	hszOpenURLTopic = DdeCreateStringHandle(idInst,"WWW_OpenURL",CP_WINANSI);
+	hszActivateTopic = DdeCreateStringHandle(idInst,"WWW_Activate",CP_WINANSI);
+}
+
+
+
+// returns SB_NOERROR on success, 
+// SB_ALREADYINIT or SB_DDE_FAILINIT on failure
+int initstartbrowser () {
+	if (inited) return SB_ALREADYINIT;
+
+// from nstest if(DdeInitialize(&CDDEObject::m_dwidInst, NstestDdeCallBack, APPCLASS_STANDARD, 0ul))
+	if (DdeInitialize (&idInst, (PFNCALLBACK) DdeCallback, 
+		APPCLASS_STANDARD, 0)
+//		CBF_FAIL_EXECUTES | CBF_SKIP_ALLNOTIFICATIONS, 0)
+			!= DMLERR_NO_ERROR) {
+		freestrings();
+		inited = 0;
+		return SB_DDE_FAILINIT;
+	}
+
+	getbrowserinfo();
+	
+	inited = 1;
+	return SB_NOERROR;
+}
+
+
+// returns SB_NOERROR on success,
+// SB_DDE_FAILDEINIT of failure
+int deinitstartbrowser () {
+	// make sure this has been inited
+	// not being inited here, however, is not
+	// important
+	if (!inited) return SB_NOERROR;
+	inited = 0;
+
+	freestrings();
+
+	if (DdeUninitialize(idInst)) return SB_NOERROR;
+
+	return SB_DDE_FAILDEINIT;
+}
+
+
+// startbrowser will try to start a browser (or connect to a running browser).
+//
+// Returns SB_NOERROR on success,
+// SB_NOTINITED, SB_FAIL_BADFORMAT, SB_FAIL_NOTFOUND, SB_FAIL_NORESOURCES, or
+// SB_FAILCONNECTBROWSER on failure
+int startbrowser (char *url, char *browser_exe, char *startdir) {
+	char newcommand[SB_COMLEN];
+	int usingnetscape = 0;
+	int usingiexplore = 0;
+
+	if (!inited) return SB_NOTINITED; // has to be inited first
+
+	// find out which browser we are dealing with
+	strcpy (newcommand, browser_exe);
+	_strlwr (newcommand);
+	if (strstr (newcommand, "netscape.exe") != NULL) { 
+		// netscape
+		usingnetscape = 1;
+	} else if (strstr (newcommand, "iexplore.exe") != NULL) { 
+		// internet explorer
+		usingiexplore = 1;
+	}
+
+	// only try to communicate with a running browser if a startdir
+	// is not specified
+	if (startdir == NULL) {
+		if (usingnetscape && hszNetscapeName != NULL && 
+					openurl(hszNetscapeName, hszActivateTopic, hszOpenURLTopic, url)) {
+			return SB_NOERROR;
+		}
+		if (usingiexplore && hszIExploreName != NULL && 
+					openurl(hszIExploreName, hszActivateTopic, hszOpenURLTopic, url)) {
+			return SB_NOERROR;
+		}
+	}
+
+	strcpy (newcommand, browser_exe);
+
+	// don't put the url on the command line for internet explorer
+	if (usingiexplore) {
+		strcat (newcommand, " -nohome");
+
+	} else {
+		// will have to put the url on the command line
+		strcat (newcommand, " \"");
+		strcat (newcommand, url);
+		strcat (newcommand, "\"");
+	}
+
+	// change the working directory (if needed)
+	char cwd[1024];
+	cwd[0] = '\0';
+	if (startdir != NULL) {
+		_getcwd(cwd, 1024);
+		_chdir(startdir);
+	}
+
+	// attempt to start the browser
+	int res = WinExec(newcommand, SW_SHOW);
+
+	// change the working directory back (if needed)
+	if (startdir != NULL) _chdir(cwd);
+
+	if (res == ERROR_BAD_FORMAT) return SB_FAIL_BADFORMAT;
+	if ((res == ERROR_FILE_NOT_FOUND) || (res == ERROR_PATH_NOT_FOUND)) 
+		return SB_FAIL_NOTFOUND;
+	if (res <= 31) return SB_FAIL_NORESOURCES;
+
+	numbrowserstarted++;
+
+	// if we aren't using iexplore then the url was
+	// put on the command line and there is nothing left to do
+	if (!usingiexplore) return SB_NOERROR;
+
+	// connect to the browser and get it to open a page,
+	// time out after 1 minute
+	DWORD lastcheck = GetTickCount ();
+	while (DiffTickCounts (lastcheck, GetTickCount()) <= 60000) {
+		if (usingnetscape && hszNetscapeName != NULL && 
+					openurl(hszNetscapeName, hszActivateTopic, hszOpenURLTopic, url)) {
+			return SB_NOERROR;
+		}
+		if (usingiexplore && hszIExploreName != NULL && 
+					openurl(hszIExploreName, hszActivateTopic, hszOpenURLTopic, url)) {
+			return SB_NOERROR;
+		}
+	}
+
+	// timed out trying to connect to the browser
+	return SB_FAILCONNECTBROWSER;
+}
+
+
+
+// returns SB_NOERROR on success,
+// SB_NOTINITED, SB_FAILCONNECTBROWSER on failure
+int browserrunning (char *browser_exe) {
+	char newcommand[SB_COMLEN];
+	if (!inited) return SB_NOTINITED; // has to be inited first
+
+	strcpy (newcommand, browser_exe);
+	_strlwr (newcommand);
+
+	if ((strstr (newcommand, "netscape.exe") != NULL) && (hszNetscapeName != NULL) && 
+			tryconnect(hszNetscapeName, hszOpenURLTopic)) {
+		// succeeded connecting to netscape
+		return SB_NOERROR;
+
+	} else if ((strstr (newcommand, "iexplore.exe") != NULL) && (hszIExploreName != NULL) && 
+			tryconnect(hszIExploreName, hszOpenURLTopic)) {
+		// succeeded connecting to internet explorer
+		return SB_NOERROR;
+	}
+
+	return SB_FAILCONNECTBROWSER;
+}
Index: /main/tags/2.25/gsdl/src/w32server/startbrowser.h
===================================================================
--- /main/tags/2.25/gsdl/src/w32server/startbrowser.h	(revision 21064)
+++ /main/tags/2.25/gsdl/src/w32server/startbrowser.h	(revision 21064)
@@ -0,0 +1,33 @@
+#define SB_NOERROR            0
+#define SB_ALREADYINIT        1
+#define SB_DDE_FAILINIT       2
+#define SB_DDE_FAILDEINIT     3
+#define SB_NOTINITED          4
+#define SB_FAIL_BADFORMAT     5
+#define SB_FAIL_NOTFOUND      6
+#define SB_FAIL_NORESOURCES   7
+#define SB_FAILCONNECTBROWSER 9
+
+
+extern int numbrowserstarted;
+
+// initstartbrowser should be called before startbrowser
+//
+// returns SB_NOERROR on success, 
+// SB_ALREADYINIT or SB_DDE_FAILINIT on failure
+int initstartbrowser ();
+
+// returns SB_NOERROR on success,
+// SB_DDE_FAILDEINIT of failure
+int deinitstartbrowser ();
+
+// startbrowser will try to start a browser (or connect to a running browser).
+//
+// Returns SB_NOERROR on success,
+// SB_NOTINITED, SB_FAIL_BADFORMAT, SB_FAIL_NOTFOUND, or SB_FAIL_NORESOURCES, 
+//  on failure
+int startbrowser (char *url, char *browser_exe, char *startdir);
+
+// returns SB_NOERROR on success,
+// SB_NOTINITED, SB_FAILCONNECTBROWSER on failure
+int browserrunning (char *browser_exe);
Index: /main/tags/2.25/gsdl/src/w32server/win32.mak
===================================================================
--- /main/tags/2.25/gsdl/src/w32server/win32.mak	(revision 21064)
+++ /main/tags/2.25/gsdl/src/w32server/win32.mak	(revision 21064)
@@ -0,0 +1,214 @@
+###########################################################################
+#
+# win32 makefile -- src/w32server
+# A component of the Greenstone digital library software
+# from the New Zealand Digital Library Project at the
+# University of Waikato, New Zealand.
+#
+# Copyright (C) 1999  The 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.
+#
+###########################################################################
+
+GSDLHOME = d:\home\dl\gsdl
+STLPATH = d:\home\dl\stl\stlport
+
+AR = lib
+CC = cl
+RSC = rc
+CPPFLAGS =
+LDFLAGS =
+DEFS = -DNZDL -DQUIET -D__WIN32__ -DGSDL_NAMESPACE_BROKEN -DGSDL_USE_IOS_H \
+       -DSHORT_SUFFIX -DPARADOCNUM -DHAVE_CONFIG_H -D__STL_NO_NEW_IOSTREAMS \
+       -DGSDLSERVER -DGSDLUSAGELOG
+INCLUDES = -I$(GSDLHOME)\src\w32server -I$(GSDLHOME)\src\recpt -I$(GSDLHOME)\lib \
+	   -I$(GSDLHOME)\src\colservr -I$(GSDLHOME)\packages\mg \
+	   -I$(GSDLHOME)\packages\mg\lib -I$(GSDLHOME)\packages\mg\src\text \
+	   -I$(GSDLHOME)\packages\wingdbm -I$(STLPATH) -I$(GSDLHOME)\packages\wincrypt
+
+LIBS = $(GSDLHOME)\packages\wingdbm\gdbm.lib $(GSDLHOME)\packages\wincrypt\crypt.lib \
+       $(GSDLHOME)\lib\gsdllib.lib $(GSDLHOME)\packages\mg\src\text\libtextin.lib \
+       $(GSDLHOME)\packages\mg\lib\libmg.lib \
+       kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib \
+       shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib
+
+
+COMPILE = $(CC) -c $(CPPFLAGS) $(DEFS) $(INCLUDES)
+LINK = $(CC) $(LDFLAGS) -o $@
+
+.SUFFIXES:
+.SUFFIXES: .c .obj
+.c.obj:
+	$(COMPILE) $<
+
+.SUFFIXES: .cpp .obj
+.cpp.obj:
+	$(COMPILE) $< 
+
+HEADERS = cgiwrapper.h conftools.h d_winsock.h fnord.h httpreq.h httpsend.h \
+          httpsrv.h locate.h netio.h parse.h settings.h startbrowser.h \
+	  wincgiutils.h
+
+SOURCES = cgiwrapper.cpp conftools.cpp d_winsock.cpp fnord.cpp httpreq.cpp httpsend.cpp \
+          httpsrv.cpp locate.cpp netio.cpp parse.cpp settings.cpp startbrowser.cpp \
+	  wincgiutils.cpp
+
+OBJECTS = cgiwrapper.obj conftools.obj d_winsock.obj fnord.obj httpreq.obj httpsend.obj \
+          httpsrv.obj locate.obj netio.obj parse.obj settings.obj startbrowser.obj \
+	  wincgiutils.obj server.res
+
+#RECPTOBJECTS = $(GSDLHOME)\src\recpt\receptionist.obj \
+#	       $(GSDLHOME)\src\recpt\cgiargs.obj \
+#               $(GSDLHOME)\src\recpt\action.obj \
+#               $(GSDLHOME)\src\recpt\browserclass.obj \
+#               $(GSDLHOME)\src\recpt\converter.obj \
+#	        $(GSDLHOME)\src\recpt\recptconfig.obj \
+#               $(GSDLHOME)\src\recpt\cgiutils.obj \
+#               $(GSDLHOME)\src\recpt\OIDtools.obj \
+#               $(GSDLHOME)\src\recpt\browsetools.obj \
+#               $(GSDLHOME)\src\recpt\htmlgen.obj \
+#               $(GSDLHOME)\src\recpt\statusaction.obj \
+#               $(GSDLHOME)\src\recpt\pageaction.obj \
+#               $(GSDLHOME)\src\recpt\comtypes.obj \
+#               $(GSDLHOME)\src\recpt\recptproto.obj \
+#               $(GSDLHOME)\src\recpt\pingaction.obj \
+#               $(GSDLHOME)\src\recpt\queryaction.obj \
+#               $(GSDLHOME)\src\recpt\documentaction.obj \
+#               $(GSDLHOME)\src\recpt\extlinkaction.obj \
+#               $(GSDLHOME)\src\recpt\buildaction.obj \
+#               $(GSDLHOME)\src\recpt\htmlutils.obj \
+#               $(GSDLHOME)\src\recpt\querytools.obj \
+#               $(GSDLHOME)\src\recpt\formattools.obj \
+#               $(GSDLHOME)\src\recpt\tipaction.obj \
+#               $(GSDLHOME)\src\recpt\authenaction.obj \
+#               $(GSDLHOME)\src\recpt\infodbclass.obj \
+#               $(GSDLHOME)\src\recpt\userdb.obj \
+#               $(GSDLHOME)\src\recpt\usersaction.obj \
+#               $(GSDLHOME)\src\recpt\vlistbrowserclass.obj \
+#               $(GSDLHOME)\src\recpt\hlistbrowserclass.obj \
+#               $(GSDLHOME)\src\recpt\datelistbrowserclass.obj \
+#               $(GSDLHOME)\src\recpt\invbrowserclass.obj \
+#               $(GSDLHOME)\src\recpt\pagedbrowserclass.obj \
+#               $(GSDLHOME)\src\recpt\htmlbrowserclass.obj \
+#               $(GSDLHOME)\src\recpt\delhistoryaction.obj \
+#               $(GSDLHOME)\src\recpt\historydb.obj
+
+#LIBRARYOBJECTS = $(GSDLHOME)\src\recpt\nullproto.obj
+
+#COLSERVROBJECTS = $(GSDLHOME)\src\colservr\mgq.obj \
+#                  $(GSDLHOME)\src\colservr\mgsearch.obj \
+#                  $(GSDLHOME)\src\colservr\querycache.obj \
+#                  $(GSDLHOME)\src\colservr\queryinfo.obj \
+#                  $(GSDLHOME)\src\colservr\collectserver.obj \
+#                  $(GSDLHOME)\src\colservr\colservrconfig.obj \
+#                  $(GSDLHOME)\src\colservr\maptools.obj \
+#                  $(GSDLHOME)\src\colservr\filter.obj \
+#                  $(GSDLHOME)\src\colservr\source.obj \
+#                  $(GSDLHOME)\src\colservr\browsefilter.obj \
+#                  $(GSDLHOME)\src\colservr\queryfilter.obj \
+#                  $(GSDLHOME)\src\colservr\mggdbmsource.obj \
+#                  $(GSDLHOME)\src\colservr\phrasesearch.obj \
+#                  $(GSDLHOME)\src\colservr\phrasequeryfilter.obj
+
+RECPTOBJECTS = ..\recpt\receptionist.obj \
+	       ..\recpt\cgiargs.obj \
+               ..\recpt\action.obj \
+               ..\recpt\browserclass.obj \
+               ..\recpt\converter.obj \
+	       ..\recpt\recptconfig.obj \
+               ..\recpt\cgiutils.obj \
+               ..\recpt\OIDtools.obj \
+               ..\recpt\browsetools.obj \
+               ..\recpt\htmlgen.obj \
+               ..\recpt\statusaction.obj \
+               ..\recpt\pageaction.obj \
+               ..\recpt\comtypes.obj \
+               ..\recpt\recptproto.obj \
+               ..\recpt\pingaction.obj \
+               ..\recpt\queryaction.obj \
+               ..\recpt\documentaction.obj \
+               ..\recpt\extlinkaction.obj \
+               ..\recpt\buildaction.obj \
+               ..\recpt\htmlutils.obj \
+               ..\recpt\querytools.obj \
+               ..\recpt\formattools.obj \
+               ..\recpt\tipaction.obj \
+               ..\recpt\authenaction.obj \
+               ..\recpt\infodbclass.obj \
+               ..\recpt\userdb.obj \
+               ..\recpt\usersaction.obj \
+               ..\recpt\vlistbrowserclass.obj \
+               ..\recpt\hlistbrowserclass.obj \
+               ..\recpt\datelistbrowserclass.obj \
+               ..\recpt\invbrowserclass.obj \
+               ..\recpt\pagedbrowserclass.obj \
+               ..\recpt\htmlbrowserclass.obj \
+               ..\recpt\delhistoryaction.obj \
+               ..\recpt\historydb.obj
+
+LIBRARYOBJECTS = ..\recpt\nullproto.obj
+
+COLSERVROBJECTS = ..\colservr\mgq.obj \
+                  ..\colservr\mgsearch.obj \
+                  ..\colservr\querycache.obj \
+                  ..\colservr\queryinfo.obj \
+                  ..\colservr\collectserver.obj \
+                  ..\colservr\colservrconfig.obj \
+                  ..\colservr\maptools.obj \
+                  ..\colservr\filter.obj \
+                  ..\colservr\source.obj \
+                  ..\colservr\browsefilter.obj \
+                  ..\colservr\queryfilter.obj \
+                  ..\colservr\mggdbmsource.obj \
+                  ..\colservr\phrasesearch.obj \
+                  ..\colservr\phrasequeryfilter.obj
+
+EXEC = server.exe
+
+all: $(EXEC)
+
+clean:
+	del *.obj
+	del $(EXEC)
+
+install:
+	copy $(EXEC) $(GSDLHOME)\$(EXEC)
+
+LIBRARY_OBJS = $(OBJECTS) $(RECPTOBJECTS) $(LIBRARYOBJECTS) $(COLSERVROBJECTS)
+server.exe: $(LIBRARY_OBJS)
+	    $(LINK) $(LIBRARY_OBJS) $(LIBS) 
+
+
+SOURCE = $(GSDLHOME)\src\w32server\newgsdl.bmp
+SOURCE = $(GSDLHOME)\src\w32server\resource.h
+SOURCE = $(GSDLHOME)\src\w32server\server.ico
+SOURCE = $(GSDLHOME)\src\w32server\gsdlcol.bmp
+SOURCE = $(GSDLHOME)\src\w32server\server.rc
+DEP_RSC_SERVE=\
+	"$(GSDLHOME)\src\w32server\gsdlcol.bmp"\
+	"$(GSDLHOME)\src\w32server\newgsdl.bmp"\
+	"$(GSDLHOME)\src\w32server\server.ico"\
+
+server.res : $(SOURCE) $(DEP_RSC_SERVE) "$(GSDLHOME)\src\w32server"
+   $(RSC) /l 0x409 /fo"$(GSDLHOME)\src\w32server\server.res" /i "$(GSDLHOME)\src\w32server" \
+ /d "NDEBUG" $(SOURCE)
+
+
+"$(GSDLHOME)\src\w32server\server.res" : $(SOURCE) $(DEP_RSC_SERVE) "$(GSDLHOME)\src\w32server"
+   $(RSC) /l 0x409 /fo"$(GSDLHOME)\src\w32server\server.res" /i "$(GSDLHOME)\src\w32server" \
+ /d "NDEBUG" $(SOURCE)
+
Index: /main/tags/2.25/gsdl/src/w32server/wincgiutils.cpp
===================================================================
--- /main/tags/2.25/gsdl/src/w32server/wincgiutils.cpp	(revision 21064)
+++ /main/tags/2.25/gsdl/src/w32server/wincgiutils.cpp	(revision 21064)
@@ -0,0 +1,156 @@
+#include <windows.h>
+#include <string.h>
+#include "netio.h"
+#include "httpreq.h"
+// #include "locate.h"
+#include "wincgiutils.h"
+
+
+#define url_limit 256
+#define file_limit 102400   /*should be large enough for a header line*/
+#define default_http_port 80
+
+
+int parse_url(char *url,
+	      char **protocol, char **machine, int *port, char **name)
+/* Attempt to break a url into segments.  If the parsing
+   fails, 'name' is left pointing to the unparsed portion.
+   This routine may extend the url string by one character */
+{
+  char next, thiss;
+  *protocol = *machine = "";
+  *port = default_http_port;
+  
+  *name = url;       /* In case there is no protocol */
+  while (*url != ':' && *url != 0) url++;
+  if (*url == 0) return http_error_url_invalid;
+  url++;
+  if (*url != '/') return http_error_url_invalid;
+  *url++ = 0;
+  if (*url != '/') return http_error_url_invalid;
+  url++;
+  
+  *protocol = *name;
+  *machine = url;
+  while (*url != ':' && *url != '/' && *url != 0) url++;
+  if (*url == ':') {
+    *url = 0;
+    url++; *port = 0;
+    while (*url >= '0' && *url <= '9')
+      *port = *port * 10 + (*url++ - '0');
+    }
+  if (*url == '/') {
+    *url++ = 0;
+    next = '/';
+    *name = url;
+    while (*url != 0) {
+      thiss = *url;  *url++ = next;  next = thiss; }
+    *url++ = next;
+    *url = 0;
+    }
+  else if (*url == 0) {
+    url++;
+    *name = url;
+    *url++ = '/';
+    *url = 0;
+    }
+  else {
+    *name = url;
+    return http_error_url_invalid;
+  }
+  return http_ok;
+}
+
+
+
+
+int Send_String(char *str, RequestInfoT *RInfo)
+{
+  return
+    SendData(RInfo->ClientSocket, (BYTE *)str, strlen(str), RInfo->ThreadNum);
+}
+
+int Send_String_N(char *str, int n,  RequestInfoT *RInfo)
+{
+  return
+    SendData(RInfo->ClientSocket, (BYTE *)str, n, RInfo->ThreadNum);
+}
+
+int send_header(char *content, RequestInfoT *RequestInfo)
+{
+  char Header[1536];  int len, lenc;
+	//Build Header
+	Header[0] = 0;
+	//Status Line
+	if (content[0] != '@')          /*No redirection needed*/
+	  strcat(Header, "HTTP/1.0 200 OK\r\n");
+	else                            /*Redirection*/
+	  strcat(Header, "HTTP/1.0 302 Relocation\r\n");
+	//Server
+	strcat(Header, "Server: GSDL\r\n");
+	//Content Type
+	strcat(Header, "Content-type: ");
+	if (content[0] != '@')          /*No redirection needed*/
+	  strcat(Header, content);
+	else {                          /*Redirection entry*/
+	  strcat(Header, "text/html \r\n");
+	  strcat(Header, "Location: ");
+	  len = strlen(Header);
+	  lenc = strlen(content) - 1;
+	  strncpy(&Header[len], &content[1], lenc);
+	  Header[len+lenc] = 0;
+	  }
+	strcat(Header, " \r\n");
+	//Single CRLF to end header
+	strcat(Header, "\r\n");
+
+   return Send_String(Header, RequestInfo);
+}
+
+void send_retrieve_error(int error_num, char *msg1, char *msg2, RequestInfoT *RequestInfo)
+{
+  char Header[512], Body[512], ErrorNumStr[17], BodyLengthStr[17];
+  DWORD BodyLength; int HeaderLength;
+
+  itoa(error_num, ErrorNumStr, 10);
+
+  //Build Data (so we can determine length for the header)
+  Body[0] = 0;
+  strcat(Body, "<HTML><HEAD><TITLE>Server Error</TITLE></HEAD><BODY>\n");
+  strcat(Body, "<H1>Error ");
+  strcat(Body, ErrorNumStr);
+  strcat(Body, ": ");
+  strcat(Body, msg1);
+  strcat(Body, "</H1>\n");
+  strcat(Body, msg2);
+  strcat(Body, "\n</BODY></HTML>");
+  BodyLength = (DWORD) strlen(Body);
+
+  //Build Header
+  Header[0] = 0;
+  //Status Line
+  strcat(Header, "HTTP/1.0 ");
+  strcat(Header, ErrorNumStr);
+  strcat(Header, " ");
+  strcat(Header, msg1);
+  strcat(Header, "\r\n");
+  //Server
+  strcat(Header, "Server: GSDL\r\n");
+  strcat(Header, "Content-Type: text/html\r\n");
+  //Content Length
+  itoa(BodyLength, BodyLengthStr, 10);
+  strcat(Header, "Content-Length: ");
+  strcat(Header, BodyLengthStr);
+  strcat(Header, "\r\n");
+  //Single CRLF to end header
+  strcat(Header, "\r\n");
+  HeaderLength = strlen(Header);
+
+   //Send the file if we have one (and if it's not a HEAD request)
+  SendData(RequestInfo->ClientSocket, (BYTE *) Header, strlen(Header), RequestInfo->ThreadNum);
+//   if ((FileFound == FALSE) && (strcmpi(RequestFields.MethodStr, "HEAD") != 0)) {
+	//Send generated data
+  SendData(RequestInfo->ClientSocket, (BYTE *) Body, BodyLength, RequestInfo->ThreadNum);
+
+}
+
Index: /main/tags/2.25/gsdl/src/w32server/wincgiutils.h
===================================================================
--- /main/tags/2.25/gsdl/src/w32server/wincgiutils.h	(revision 21064)
+++ /main/tags/2.25/gsdl/src/w32server/wincgiutils.h	(revision 21064)
@@ -0,0 +1,37 @@
+#define http_ok 0
+#define http_error_url_invalid 11
+
+
+int parse_url(char *url,
+	      char **protocol, char **machine, int *port, char **name);
+
+
+struct param_vals {char *name, *value; int vsize; char *dfault; };
+
+
+int Send_String(char *str, RequestInfoT *RInfo);
+int Send_String_N(char *str, int n,  RequestInfoT *RInfo);
+void send_retrieve_error(int error_num, char *msg1, char *msg2, RequestInfoT *RequestInfo);
+int send_header(char *content, RequestInfoT *RequestInfo);
+void decode(char *st);
+void decode_template(int ntemp, param_vals tmplate[]);
+void parse_query_string(char *qstring, int ntemp, param_vals tmplate[]);
+int mg_sender(char *UDoc, int ULen, int DocNum, float Weight, void *RInfo);
+
+#define OUT_CONST_A(t) \
+{if (Send_String_N(t, sizeof(t), RInfo) < 0) return;}
+
+#define OUT_CONST_B(t) \
+{if (Send_String_N(t, sizeof(t), (RequestInfoT *)RInfo) < 0) return -1;}
+
+#define OUT_STRING_A(t) \
+{if (Send_String(t, RInfo) < 0) return;}
+
+#define OUT_STRING_B(t) \
+{if (Send_String(t, (RequestInfoT *)RInfo) < 0) return -1;}
+
+#define OUT_STRING_N_A(t,n) \
+{if (Send_String_N(t, n, RInfo) < 0) return;}
+
+#define OUT_STRING_N_B(t,n) \
+{if (Send_String_N(t, n, (RequestInfoT *)RInfo) < 0) return -1;}
Index: /main/tags/2.25/gsdl/unicode/MAPPINGS/EASTASIA/GB/GB12345.TXT
===================================================================
--- /main/tags/2.25/gsdl/unicode/MAPPINGS/EASTASIA/GB/GB12345.TXT	(revision 21064)
+++ /main/tags/2.25/gsdl/unicode/MAPPINGS/EASTASIA/GB/GB12345.TXT	(revision 21064)
@@ -0,0 +1,7604 @@
+#
+#	Name:             GB12345-80 to Unicode table (complete, hex format)
+#	Unicode version:  1.1
+#	Table version:    0.0d1
+#	Table format:     Format A
+#	Date:             6 December 1993
+#	Author:           Glenn Adams <glenn@metis.com>
+#                     John H. Jenkins <John_Jenkins@taligent.com>
+#
+#	Copyright (c) 1991-1994 Unicode, Inc.  All Rights reserved.
+#
+#	This file is provided as-is by Unicode, Inc. (The Unicode Consortium).
+#	No claims are made as to fitness for any particular purpose.  No
+#	warranties of any kind are expressed or implied.  The recipient
+#	agrees to determine applicability of information provided.  If this
+#	file has been provided on magnetic media by Unicode, Inc., the sole
+#	remedy for any claim will be exchange of defective media within 90
+#	days of receipt.
+#
+#	Recipient is granted the right to make copies in any form for
+#	internal distribution and to freely use the information supplied
+#	in the creation of products supporting Unicode.  Unicode, Inc.
+#	specifically excludes the right to re-distribute this file directly
+#	to third parties or other organizations whether for profit or not.
+#
+#	General notes:
+#
+#	This table contains the data Metis and Taligent currently have on how
+#       GB12345-90 characters map into Unicode.
+#
+#	Format:  Three tab-separated columns
+#		 Column #1 is the GB12345 code (in hex as 0xXXXX)
+#		 Column #2 is the Unicode (in hex as 0xXXXX)
+#		 Column #3 the Unicode name (follows a comment sign, '#')
+#					The official names for Unicode characters U+4E00
+#					to U+9FA5, inclusive, is "CJK UNIFIED IDEOGRAPH-XXXX",
+#					where XXXX is the code point.  Including all these
+#					names in this file increases its size substantially
+#					and needlessly.  The token "<CJK>" is used for the
+#					name of these characters.  If necessary, it can be
+#					expanded algorithmically by a parser or editor.
+#
+#	The entries are in GB12345 order
+#
+#	The following algorithms can be used to change the hex form
+#		of GB12345 to other standard forms:
+#
+#		To change hex to EUC form, add 0x8080
+#		To change hex to kuten form, first subtract 0x2020.  Then
+#			the high and low bytes correspond to the ku and ten of
+#			the kuten form.  For example, 0x2121 -> 0x0101 -> 0101;
+#			0x777E -> 0x575E -> 8794
+#
+#	Any comments or problems, contact <John_Jenkins@taligent.com>
+#
+#
+0x2121	0x3000	# IDEOGRAPHIC SPACE
+0x2122	0x3001	# IDEOGRAPHIC COMMA
+0x2123	0x3002	# IDEOGRAPHIC FULL STOP
+0x2124	0x30FB	# KATAKANA MIDDLE DOT
+0x2125	0x02C9	# MODIFIER LETTER MACRON (Mandarin Chinese first tone)
+0x2126	0x02C7	# CARON (Mandarin Chinese third tone)
+0x2127	0x00A8	# DIAERESIS
+0x2128	0x3003	# DITTO MARK
+0x2129	0x3005	# IDEOGRAPHIC ITERATION MARK
+0x212A	0x2015	# HORIZONTAL BAR
+0x212B	0xFF5E	# FULLWIDTH TILDE
+0x212C	0x2225	# PARALLEL TO
+0x212D	0x2026	# HORIZONTAL ELLIPSIS
+0x212E	0x2018	# LEFT SINGLE QUOTATION MARK
+0x212F	0x2019	# RIGHT SINGLE QUOTATION MARK
+0x2130	0x201C	# LEFT DOUBLE QUOTATION MARK
+0x2131	0x201D	# RIGHT DOUBLE QUOTATION MARK
+0x2132	0x3014	# LEFT TORTOISE SHELL BRACKET
+0x2133	0x3015	# RIGHT TORTOISE SHELL BRACKET
+0x2134	0x3008	# LEFT ANGLE BRACKET
+0x2135	0x3009	# RIGHT ANGLE BRACKET
+0x2136	0x300A	# LEFT DOUBLE ANGLE BRACKET
+0x2137	0x300B	# RIGHT DOUBLE ANGLE BRACKET
+0x2138	0x300C	# LEFT CORNER BRACKET
+0x2139	0x300D	# RIGHT CORNER BRACKET
+0x213A	0x300E	# LEFT WHITE CORNER BRACKET
+0x213B	0x300F	# RIGHT WHITE CORNER BRACKET
+0x213C	0x3016	# LEFT WHITE LENTICULAR BRACKET
+0x213D	0x3017	# RIGHT WHITE LENTICULAR BRACKET
+0x213E	0x3010	# LEFT BLACK LENTICULAR BRACKET
+0x213F	0x3011	# RIGHT BLACK LENTICULAR BRACKET
+0x2140	0x00B1	# PLUS-MINUS SIGN
+0x2141	0x00D7	# MULTIPLICATION SIGN
+0x2142	0x00F7	# DIVISION SIGN
+0x2143	0x2236	# RATIO
+0x2144	0x2227	# LOGICAL AND
+0x2145	0x2228	# LOGICAL OR
+0x2146	0x2211	# N-ARY SUMMATION
+0x2147	0x220F	# N-ARY PRODUCT
+0x2148	0x222A	# UNION
+0x2149	0x2229	# INTERSECTION
+0x214A	0x2208	# ELEMENT OF
+0x214B	0x2237	# PROPORTION
+0x214C	0x221A	# SQUARE ROOT
+0x214D	0x22A5	# UP TACK
+0x214E	0x2225	# PARALLEL TO
+0x214F	0x2220	# ANGLE
+0x2150	0x2312	# ARC
+0x2151	0x2299	# CIRCLED DOT OPERATOR
+0x2152	0x222B	# INTEGRAL
+0x2153	0x222E	# CONTOUR INTEGRAL
+0x2154	0x2261	# IDENTICAL TO
+0x2155	0x224C	# ALL EQUAL TO
+0x2156	0x2248	# ALMOST EQUAL TO
+0x2157	0x223D	# REVERSED TILDE
+0x2158	0x221D	# PROPORTIONAL TO
+0x2159	0x2260	# NOT EQUAL TO
+0x215A	0x226E	# NOT LESS-THAN
+0x215B	0x226F	# NOT GREATER-THAN
+0x215C	0x2264	# LESS-THAN OR EQUAL TO
+0x215D	0x2265	# GREATER-THAN OR EQUAL TO
+0x215E	0x221E	# INFINITY
+0x215F	0x2235	# BECAUSE
+0x2160	0x2234	# THEREFORE
+0x2161	0x2642	# MALE SIGN
+0x2162	0x2640	# FEMALE SIGN
+0x2163	0x00B0	# DEGREE SIGN
+0x2164	0x2032	# PRIME
+0x2165	0x2033	# DOUBLE PRIME
+0x2166	0x2103	# DEGREE CELSIUS
+0x2167	0xFF04	# FULLWIDTH DOLLAR SIGN
+0x2168	0x00A4	# CURRENCY SIGN
+0x2169	0xFFE0	# FULLWIDTH CENT SIGN
+0x216A	0xFFE1	# FULLWIDTH POUND SIGN
+0x216B	0x2030	# PER MILLE SIGN
+0x216C	0x00A7	# SECTION SIGN
+0x216D	0x2116	# NUMERO SIGN
+0x216E	0x2606	# WHITE STAR
+0x216F	0x2605	# BLACK STAR
+0x2170	0x25CB	# WHITE CIRCLE
+0x2171	0x25CF	# BLACK CIRCLE
+0x2172	0x25CE	# BULLSEYE
+0x2173	0x25C7	# WHITE DIAMOND
+0x2174	0x25C6	# BLACK DIAMOND
+0x2175	0x25A1	# WHITE SQUARE
+0x2176	0x25A0	# BLACK SQUARE
+0x2177	0x25B3	# WHITE UP-POINTING TRIANGLE
+0x2178	0x25B2	# BLACK UP-POINTING TRIANGLE
+0x2179	0x203B	# REFERENCE MARK
+0x217A	0x2192	# RIGHTWARDS ARROW
+0x217B	0x2190	# LEFTWARDS ARROW
+0x217C	0x2191	# UPWARDS ARROW
+0x217D	0x2193	# DOWNWARDS ARROW
+0x217E	0x3013	# GETA MARK
+0x2231	0x2488	# DIGIT ONE FULL STOP
+0x2232	0x2489	# DIGIT TWO FULL STOP
+0x2233	0x248A	# DIGIT THREE FULL STOP
+0x2234	0x248B	# DIGIT FOUR FULL STOP
+0x2235	0x248C	# DIGIT FIVE FULL STOP
+0x2236	0x248D	# DIGIT SIX FULL STOP
+0x2237	0x248E	# DIGIT SEVEN FULL STOP
+0x2238	0x248F	# DIGIT EIGHT FULL STOP
+0x2239	0x2490	# DIGIT NINE FULL STOP
+0x223A	0x2491	# NUMBER TEN FULL STOP
+0x223B	0x2492	# NUMBER ELEVEN FULL STOP
+0x223C	0x2493	# NUMBER TWELVE FULL STOP
+0x223D	0x2494	# NUMBER THIRTEEN FULL STOP
+0x223E	0x2495	# NUMBER FOURTEEN FULL STOP
+0x223F	0x2496	# NUMBER FIFTEEN FULL STOP
+0x2240	0x2497	# NUMBER SIXTEEN FULL STOP
+0x2241	0x2498	# NUMBER SEVENTEEN FULL STOP
+0x2242	0x2499	# NUMBER EIGHTEEN FULL STOP
+0x2243	0x249A	# NUMBER NINETEEN FULL STOP
+0x2244	0x249B	# NUMBER TWENTY FULL STOP
+0x2245	0x2474	# PARENTHESIZED DIGIT ONE
+0x2246	0x2475	# PARENTHESIZED DIGIT TWO
+0x2247	0x2476	# PARENTHESIZED DIGIT THREE
+0x2248	0x2477	# PARENTHESIZED DIGIT FOUR
+0x2249	0x2478	# PARENTHESIZED DIGIT FIVE
+0x224A	0x2479	# PARENTHESIZED DIGIT SIX
+0x224B	0x247A	# PARENTHESIZED DIGIT SEVEN
+0x224C	0x247B	# PARENTHESIZED DIGIT EIGHT
+0x224D	0x247C	# PARENTHESIZED DIGIT NINE
+0x224E	0x247D	# PARENTHESIZED NUMBER TEN
+0x224F	0x247E	# PARENTHESIZED NUMBER ELEVEN
+0x2250	0x247F	# PARENTHESIZED NUMBER TWELVE
+0x2251	0x2480	# PARENTHESIZED NUMBER THIRTEEN
+0x2252	0x2481	# PARENTHESIZED NUMBER FOURTEEN
+0x2253	0x2482	# PARENTHESIZED NUMBER FIFTEEN
+0x2254	0x2483	# PARENTHESIZED NUMBER SIXTEEN
+0x2255	0x2484	# PARENTHESIZED NUMBER SEVENTEEN
+0x2256	0x2485	# PARENTHESIZED NUMBER EIGHTEEN
+0x2257	0x2486	# PARENTHESIZED NUMBER NINETEEN
+0x2258	0x2487	# PARENTHESIZED NUMBER TWENTY
+0x2259	0x2460	# CIRCLED DIGIT ONE
+0x225A	0x2461	# CIRCLED DIGIT TWO
+0x225B	0x2462	# CIRCLED DIGIT THREE
+0x225C	0x2463	# CIRCLED DIGIT FOUR
+0x225D	0x2464	# CIRCLED DIGIT FIVE
+0x225E	0x2465	# CIRCLED DIGIT SIX
+0x225F	0x2466	# CIRCLED DIGIT SEVEN
+0x2260	0x2467	# CIRCLED DIGIT EIGHT
+0x2261	0x2468	# CIRCLED DIGIT NINE
+0x2262	0x2469	# CIRCLED NUMBER TEN
+0x2265	0x3220	# PARENTHESIZED IDEOGRAPH ONE
+0x2266	0x3221	# PARENTHESIZED IDEOGRAPH TWO
+0x2267	0x3222	# PARENTHESIZED IDEOGRAPH THREE
+0x2268	0x3223	# PARENTHESIZED IDEOGRAPH FOUR
+0x2269	0x3224	# PARENTHESIZED IDEOGRAPH FIVE
+0x226A	0x3225	# PARENTHESIZED IDEOGRAPH SIX
+0x226B	0x3226	# PARENTHESIZED IDEOGRAPH SEVEN
+0x226C	0x3227	# PARENTHESIZED IDEOGRAPH EIGHT
+0x226D	0x3228	# PARENTHESIZED IDEOGRAPH NINE
+0x226E	0x3229	# PARENTHESIZED IDEOGRAPH TEN
+0x2271	0x2160	# ROMAN NUMERAL ONE
+0x2272	0x2161	# ROMAN NUMERAL TWO
+0x2273	0x2162	# ROMAN NUMERAL THREE
+0x2274	0x2163	# ROMAN NUMERAL FOUR
+0x2275	0x2164	# ROMAN NUMERAL FIVE
+0x2276	0x2165	# ROMAN NUMERAL SIX
+0x2277	0x2166	# ROMAN NUMERAL SEVEN
+0x2278	0x2167	# ROMAN NUMERAL EIGHT
+0x2279	0x2168	# ROMAN NUMERAL NINE
+0x227A	0x2169	# ROMAN NUMERAL TEN
+0x227B	0x216A	# ROMAN NUMERAL ELEVEN
+0x227C	0x216B	# ROMAN NUMERAL TWELVE
+0x2321	0xFF01	# FULLWIDTH EXCLAMATION MARK
+0x2322	0xFF02	# FULLWIDTH QUOTATION MARK
+0x2323	0xFF03	# FULLWIDTH NUMBER SIGN
+0x2324	0xFFE5	# FULLWIDTH YEN SIGN
+0x2325	0xFF05	# FULLWIDTH PERCENT SIGN
+0x2326	0xFF06	# FULLWIDTH AMPERSAND
+0x2327	0xFF07	# FULLWIDTH APOSTROPHE
+0x2328	0xFF08	# FULLWIDTH LEFT PARENTHESIS
+0x2329	0xFF09	# FULLWIDTH RIGHT PARENTHESIS
+0x232A	0xFF0A	# FULLWIDTH ASTERISK
+0x232B	0xFF0B	# FULLWIDTH PLUS SIGN
+0x232C	0xFF0C	# FULLWIDTH COMMA
+0x232D	0xFF0D	# FULLWIDTH HYPHEN-MINUS
+0x232E	0xFF0E	# FULLWIDTH FULL STOP
+0x232F	0xFF0F	# FULLWIDTH SOLIDUS
+0x2330	0xFF10	# FULLWIDTH DIGIT ZERO
+0x2331	0xFF11	# FULLWIDTH DIGIT ONE
+0x2332	0xFF12	# FULLWIDTH DIGIT TWO
+0x2333	0xFF13	# FULLWIDTH DIGIT THREE
+0x2334	0xFF14	# FULLWIDTH DIGIT FOUR
+0x2335	0xFF15	# FULLWIDTH DIGIT FIVE
+0x2336	0xFF16	# FULLWIDTH DIGIT SIX
+0x2337	0xFF17	# FULLWIDTH DIGIT SEVEN
+0x2338	0xFF18	# FULLWIDTH DIGIT EIGHT
+0x2339	0xFF19	# FULLWIDTH DIGIT NINE
+0x233A	0xFF1A	# FULLWIDTH COLON
+0x233B	0xFF1B	# FULLWIDTH SEMICOLON
+0x233C	0xFF1C	# FULLWIDTH LESS-THAN SIGN
+0x233D	0xFF1D	# FULLWIDTH EQUALS SIGN
+0x233E	0xFF1E	# FULLWIDTH GREATER-THAN SIGN
+0x233F	0xFF1F	# FULLWIDTH QUESTION MARK
+0x2340	0xFF20	# FULLWIDTH COMMERCIAL AT
+0x2341	0xFF21	# FULLWIDTH LATIN CAPITAL LETTER A
+0x2342	0xFF22	# FULLWIDTH LATIN CAPITAL LETTER B
+0x2343	0xFF23	# FULLWIDTH LATIN CAPITAL LETTER C
+0x2344	0xFF24	# FULLWIDTH LATIN CAPITAL LETTER D
+0x2345	0xFF25	# FULLWIDTH LATIN CAPITAL LETTER E
+0x2346	0xFF26	# FULLWIDTH LATIN CAPITAL LETTER F
+0x2347	0xFF27	# FULLWIDTH LATIN CAPITAL LETTER G
+0x2348	0xFF28	# FULLWIDTH LATIN CAPITAL LETTER H
+0x2349	0xFF29	# FULLWIDTH LATIN CAPITAL LETTER I
+0x234A	0xFF2A	# FULLWIDTH LATIN CAPITAL LETTER J
+0x234B	0xFF2B	# FULLWIDTH LATIN CAPITAL LETTER K
+0x234C	0xFF2C	# FULLWIDTH LATIN CAPITAL LETTER L
+0x234D	0xFF2D	# FULLWIDTH LATIN CAPITAL LETTER M
+0x234E	0xFF2E	# FULLWIDTH LATIN CAPITAL LETTER N
+0x234F	0xFF2F	# FULLWIDTH LATIN CAPITAL LETTER O
+0x2350	0xFF30	# FULLWIDTH LATIN CAPITAL LETTER P
+0x2351	0xFF31	# FULLWIDTH LATIN CAPITAL LETTER Q
+0x2352	0xFF32	# FULLWIDTH LATIN CAPITAL LETTER R
+0x2353	0xFF33	# FULLWIDTH LATIN CAPITAL LETTER S
+0x2354	0xFF34	# FULLWIDTH LATIN CAPITAL LETTER T
+0x2355	0xFF35	# FULLWIDTH LATIN CAPITAL LETTER U
+0x2356	0xFF36	# FULLWIDTH LATIN CAPITAL LETTER V
+0x2357	0xFF37	# FULLWIDTH LATIN CAPITAL LETTER W
+0x2358	0xFF38	# FULLWIDTH LATIN CAPITAL LETTER X
+0x2359	0xFF39	# FULLWIDTH LATIN CAPITAL LETTER Y
+0x235A	0xFF3A	# FULLWIDTH LATIN CAPITAL LETTER Z
+0x235B	0xFF3B	# FULLWIDTH LEFT SQUARE BRACKET
+0x235C	0xFF3C	# FULLWIDTH REVERSE SOLIDUS
+0x235D	0xFF3D	# FULLWIDTH RIGHT SQUARE BRACKET
+0x235E	0xFF3E	# FULLWIDTH CIRCUMFLEX ACCENT
+0x235F	0xFF3F	# FULLWIDTH LOW LINE
+0x2360	0xFF40	# FULLWIDTH GRAVE ACCENT
+0x2361	0xFF41	# FULLWIDTH LATIN SMALL LETTER A
+0x2362	0xFF42	# FULLWIDTH LATIN SMALL LETTER B
+0x2363	0xFF43	# FULLWIDTH LATIN SMALL LETTER C
+0x2364	0xFF44	# FULLWIDTH LATIN SMALL LETTER D
+0x2365	0xFF45	# FULLWIDTH LATIN SMALL LETTER E
+0x2366	0xFF46	# FULLWIDTH LATIN SMALL LETTER F
+0x2367	0xFF47	# FULLWIDTH LATIN SMALL LETTER G
+0x2368	0xFF48	# FULLWIDTH LATIN SMALL LETTER H
+0x2369	0xFF49	# FULLWIDTH LATIN SMALL LETTER I
+0x236A	0xFF4A	# FULLWIDTH LATIN SMALL LETTER J
+0x236B	0xFF4B	# FULLWIDTH LATIN SMALL LETTER K
+0x236C	0xFF4C	# FULLWIDTH LATIN SMALL LETTER L
+0x236D	0xFF4D	# FULLWIDTH LATIN SMALL LETTER M
+0x236E	0xFF4E	# FULLWIDTH LATIN SMALL LETTER N
+0x236F	0xFF4F	# FULLWIDTH LATIN SMALL LETTER O
+0x2370	0xFF50	# FULLWIDTH LATIN SMALL LETTER P
+0x2371	0xFF51	# FULLWIDTH LATIN SMALL LETTER Q
+0x2372	0xFF52	# FULLWIDTH LATIN SMALL LETTER R
+0x2373	0xFF53	# FULLWIDTH LATIN SMALL LETTER S
+0x2374	0xFF54	# FULLWIDTH LATIN SMALL LETTER T
+0x2375	0xFF55	# FULLWIDTH LATIN SMALL LETTER U
+0x2376	0xFF56	# FULLWIDTH LATIN SMALL LETTER V
+0x2377	0xFF57	# FULLWIDTH LATIN SMALL LETTER W
+0x2378	0xFF58	# FULLWIDTH LATIN SMALL LETTER X
+0x2379	0xFF59	# FULLWIDTH LATIN SMALL LETTER Y
+0x237A	0xFF5A	# FULLWIDTH LATIN SMALL LETTER Z
+0x237B	0xFF5B	# FULLWIDTH LEFT CURLY BRACKET
+0x237C	0xFF5C	# FULLWIDTH VERTICAL LINE
+0x237D	0xFF5D	# FULLWIDTH RIGHT CURLY BRACKET
+0x237E	0xFFE3	# FULLWIDTH MACRON
+0x2421	0x3041	# HIRAGANA LETTER SMALL A
+0x2422	0x3042	# HIRAGANA LETTER A
+0x2423	0x3043	# HIRAGANA LETTER SMALL I
+0x2424	0x3044	# HIRAGANA LETTER I
+0x2425	0x3045	# HIRAGANA LETTER SMALL U
+0x2426	0x3046	# HIRAGANA LETTER U
+0x2427	0x3047	# HIRAGANA LETTER SMALL E
+0x2428	0x3048	# HIRAGANA LETTER E
+0x2429	0x3049	# HIRAGANA LETTER SMALL O
+0x242A	0x304A	# HIRAGANA LETTER O
+0x242B	0x304B	# HIRAGANA LETTER KA
+0x242C	0x304C	# HIRAGANA LETTER GA
+0x242D	0x304D	# HIRAGANA LETTER KI
+0x242E	0x304E	# HIRAGANA LETTER GI
+0x242F	0x304F	# HIRAGANA LETTER KU
+0x2430	0x3050	# HIRAGANA LETTER GU
+0x2431	0x3051	# HIRAGANA LETTER KE
+0x2432	0x3052	# HIRAGANA LETTER GE
+0x2433	0x3053	# HIRAGANA LETTER KO
+0x2434	0x3054	# HIRAGANA LETTER GO
+0x2435	0x3055	# HIRAGANA LETTER SA
+0x2436	0x3056	# HIRAGANA LETTER ZA
+0x2437	0x3057	# HIRAGANA LETTER SI
+0x2438	0x3058	# HIRAGANA LETTER ZI
+0x2439	0x3059	# HIRAGANA LETTER SU
+0x243A	0x305A	# HIRAGANA LETTER ZU
+0x243B	0x305B	# HIRAGANA LETTER SE
+0x243C	0x305C	# HIRAGANA LETTER ZE
+0x243D	0x305D	# HIRAGANA LETTER SO
+0x243E	0x305E	# HIRAGANA LETTER ZO
+0x243F	0x305F	# HIRAGANA LETTER TA
+0x2440	0x3060	# HIRAGANA LETTER DA
+0x2441	0x3061	# HIRAGANA LETTER TI
+0x2442	0x3062	# HIRAGANA LETTER DI
+0x2443	0x3063	# HIRAGANA LETTER SMALL TU
+0x2444	0x3064	# HIRAGANA LETTER TU
+0x2445	0x3065	# HIRAGANA LETTER DU
+0x2446	0x3066	# HIRAGANA LETTER TE
+0x2447	0x3067	# HIRAGANA LETTER DE
+0x2448	0x3068	# HIRAGANA LETTER TO
+0x2449	0x3069	# HIRAGANA LETTER DO
+0x244A	0x306A	# HIRAGANA LETTER NA
+0x244B	0x306B	# HIRAGANA LETTER NI
+0x244C	0x306C	# HIRAGANA LETTER NU
+0x244D	0x306D	# HIRAGANA LETTER NE
+0x244E	0x306E	# HIRAGANA LETTER NO
+0x244F	0x306F	# HIRAGANA LETTER HA
+0x2450	0x3070	# HIRAGANA LETTER BA
+0x2451	0x3071	# HIRAGANA LETTER PA
+0x2452	0x3072	# HIRAGANA LETTER HI
+0x2453	0x3073	# HIRAGANA LETTER BI
+0x2454	0x3074	# HIRAGANA LETTER PI
+0x2455	0x3075	# HIRAGANA LETTER HU
+0x2456	0x3076	# HIRAGANA LETTER BU
+0x2457	0x3077	# HIRAGANA LETTER PU
+0x2458	0x3078	# HIRAGANA LETTER HE
+0x2459	0x3079	# HIRAGANA LETTER BE
+0x245A	0x307A	# HIRAGANA LETTER PE
+0x245B	0x307B	# HIRAGANA LETTER HO
+0x245C	0x307C	# HIRAGANA LETTER BO
+0x245D	0x307D	# HIRAGANA LETTER PO
+0x245E	0x307E	# HIRAGANA LETTER MA
+0x245F	0x307F	# HIRAGANA LETTER MI
+0x2460	0x3080	# HIRAGANA LETTER MU
+0x2461	0x3081	# HIRAGANA LETTER ME
+0x2462	0x3082	# HIRAGANA LETTER MO
+0x2463	0x3083	# HIRAGANA LETTER SMALL YA
+0x2464	0x3084	# HIRAGANA LETTER YA
+0x2465	0x3085	# HIRAGANA LETTER SMALL YU
+0x2466	0x3086	# HIRAGANA LETTER YU
+0x2467	0x3087	# HIRAGANA LETTER SMALL YO
+0x2468	0x3088	# HIRAGANA LETTER YO
+0x2469	0x3089	# HIRAGANA LETTER RA
+0x246A	0x308A	# HIRAGANA LETTER RI
+0x246B	0x308B	# HIRAGANA LETTER RU
+0x246C	0x308C	# HIRAGANA LETTER RE
+0x246D	0x308D	# HIRAGANA LETTER RO
+0x246E	0x308E	# HIRAGANA LETTER SMALL WA
+0x246F	0x308F	# HIRAGANA LETTER WA
+0x2470	0x3090	# HIRAGANA LETTER WI
+0x2471	0x3091	# HIRAGANA LETTER WE
+0x2472	0x3092	# HIRAGANA LETTER WO
+0x2473	0x3093	# HIRAGANA LETTER N
+0x2521	0x30A1	# KATAKANA LETTER SMALL A
+0x2522	0x30A2	# KATAKANA LETTER A
+0x2523	0x30A3	# KATAKANA LETTER SMALL I
+0x2524	0x30A4	# KATAKANA LETTER I
+0x2525	0x30A5	# KATAKANA LETTER SMALL U
+0x2526	0x30A6	# KATAKANA LETTER U
+0x2527	0x30A7	# KATAKANA LETTER SMALL E
+0x2528	0x30A8	# KATAKANA LETTER E
+0x2529	0x30A9	# KATAKANA LETTER SMALL O
+0x252A	0x30AA	# KATAKANA LETTER O
+0x252B	0x30AB	# KATAKANA LETTER KA
+0x252C	0x30AC	# KATAKANA LETTER GA
+0x252D	0x30AD	# KATAKANA LETTER KI
+0x252E	0x30AE	# KATAKANA LETTER GI
+0x252F	0x30AF	# KATAKANA LETTER KU
+0x2530	0x30B0	# KATAKANA LETTER GU
+0x2531	0x30B1	# KATAKANA LETTER KE
+0x2532	0x30B2	# KATAKANA LETTER GE
+0x2533	0x30B3	# KATAKANA LETTER KO
+0x2534	0x30B4	# KATAKANA LETTER GO
+0x2535	0x30B5	# KATAKANA LETTER SA
+0x2536	0x30B6	# KATAKANA LETTER ZA
+0x2537	0x30B7	# KATAKANA LETTER SI
+0x2538	0x30B8	# KATAKANA LETTER ZI
+0x2539	0x30B9	# KATAKANA LETTER SU
+0x253A	0x30BA	# KATAKANA LETTER ZU
+0x253B	0x30BB	# KATAKANA LETTER SE
+0x253C	0x30BC	# KATAKANA LETTER ZE
+0x253D	0x30BD	# KATAKANA LETTER SO
+0x253E	0x30BE	# KATAKANA LETTER ZO
+0x253F	0x30BF	# KATAKANA LETTER TA
+0x2540	0x30C0	# KATAKANA LETTER DA
+0x2541	0x30C1	# KATAKANA LETTER TI
+0x2542	0x30C2	# KATAKANA LETTER DI
+0x2543	0x30C3	# KATAKANA LETTER SMALL TU
+0x2544	0x30C4	# KATAKANA LETTER TU
+0x2545	0x30C5	# KATAKANA LETTER DU
+0x2546	0x30C6	# KATAKANA LETTER TE
+0x2547	0x30C7	# KATAKANA LETTER DE
+0x2548	0x30C8	# KATAKANA LETTER TO
+0x2549	0x30C9	# KATAKANA LETTER DO
+0x254A	0x30CA	# KATAKANA LETTER NA
+0x254B	0x30CB	# KATAKANA LETTER NI
+0x254C	0x30CC	# KATAKANA LETTER NU
+0x254D	0x30CD	# KATAKANA LETTER NE
+0x254E	0x30CE	# KATAKANA LETTER NO
+0x254F	0x30CF	# KATAKANA LETTER HA
+0x2550	0x30D0	# KATAKANA LETTER BA
+0x2551	0x30D1	# KATAKANA LETTER PA
+0x2552	0x30D2	# KATAKANA LETTER HI
+0x2553	0x30D3	# KATAKANA LETTER BI
+0x2554	0x30D4	# KATAKANA LETTER PI
+0x2555	0x30D5	# KATAKANA LETTER HU
+0x2556	0x30D6	# KATAKANA LETTER BU
+0x2557	0x30D7	# KATAKANA LETTER PU
+0x2558	0x30D8	# KATAKANA LETTER HE
+0x2559	0x30D9	# KATAKANA LETTER BE
+0x255A	0x30DA	# KATAKANA LETTER PE
+0x255B	0x30DB	# KATAKANA LETTER HO
+0x255C	0x30DC	# KATAKANA LETTER BO
+0x255D	0x30DD	# KATAKANA LETTER PO
+0x255E	0x30DE	# KATAKANA LETTER MA
+0x255F	0x30DF	# KATAKANA LETTER MI
+0x2560	0x30E0	# KATAKANA LETTER MU
+0x2561	0x30E1	# KATAKANA LETTER ME
+0x2562	0x30E2	# KATAKANA LETTER MO
+0x2563	0x30E3	# KATAKANA LETTER SMALL YA
+0x2564	0x30E4	# KATAKANA LETTER YA
+0x2565	0x30E5	# KATAKANA LETTER SMALL YU
+0x2566	0x30E6	# KATAKANA LETTER YU
+0x2567	0x30E7	# KATAKANA LETTER SMALL YO
+0x2568	0x30E8	# KATAKANA LETTER YO
+0x2569	0x30E9	# KATAKANA LETTER RA
+0x256A	0x30EA	# KATAKANA LETTER RI
+0x256B	0x30EB	# KATAKANA LETTER RU
+0x256C	0x30EC	# KATAKANA LETTER RE
+0x256D	0x30ED	# KATAKANA LETTER RO
+0x256E	0x30EE	# KATAKANA LETTER SMALL WA
+0x256F	0x30EF	# KATAKANA LETTER WA
+0x2570	0x30F0	# KATAKANA LETTER WI
+0x2571	0x30F1	# KATAKANA LETTER WE
+0x2572	0x30F2	# KATAKANA LETTER WO
+0x2573	0x30F3	# KATAKANA LETTER N
+0x2574	0x30F4	# KATAKANA LETTER VU
+0x2575	0x30F5	# KATAKANA LETTER SMALL KA
+0x2576	0x30F6	# KATAKANA LETTER SMALL KE
+0x2621	0x0391	# GREEK CAPITAL LETTER ALPHA
+0x2622	0x0392	# GREEK CAPITAL LETTER BETA
+0x2623	0x0393	# GREEK CAPITAL LETTER GAMMA
+0x2624	0x0394	# GREEK CAPITAL LETTER DELTA
+0x2625	0x0395	# GREEK CAPITAL LETTER EPSILON
+0x2626	0x0396	# GREEK CAPITAL LETTER ZETA
+0x2627	0x0397	# GREEK CAPITAL LETTER ETA
+0x2628	0x0398	# GREEK CAPITAL LETTER THETA
+0x2629	0x0399	# GREEK CAPITAL LETTER IOTA
+0x262A	0x039A	# GREEK CAPITAL LETTER KAPPA
+0x262B	0x039B	# GREEK CAPITAL LETTER LAMDA
+0x262C	0x039C	# GREEK CAPITAL LETTER MU
+0x262D	0x039D	# GREEK CAPITAL LETTER NU
+0x262E	0x039E	# GREEK CAPITAL LETTER XI
+0x262F	0x039F	# GREEK CAPITAL LETTER OMICRON
+0x2630	0x03A0	# GREEK CAPITAL LETTER PI
+0x2631	0x03A1	# GREEK CAPITAL LETTER RHO
+0x2632	0x03A3	# GREEK CAPITAL LETTER SIGMA
+0x2633	0x03A4	# GREEK CAPITAL LETTER TAU
+0x2634	0x03A5	# GREEK CAPITAL LETTER UPSILON
+0x2635	0x03A6	# GREEK CAPITAL LETTER PHI
+0x2636	0x03A7	# GREEK CAPITAL LETTER CHI
+0x2637	0x03A8	# GREEK CAPITAL LETTER PSI
+0x2638	0x03A9	# GREEK CAPITAL LETTER OMEGA
+0x2641	0x03B1	# GREEK SMALL LETTER ALPHA
+0x2642	0x03B2	# GREEK SMALL LETTER BETA
+0x2643	0x03B3	# GREEK SMALL LETTER GAMMA
+0x2644	0x03B4	# GREEK SMALL LETTER DELTA
+0x2645	0x03B5	# GREEK SMALL LETTER EPSILON
+0x2646	0x03B6	# GREEK SMALL LETTER ZETA
+0x2647	0x03B7	# GREEK SMALL LETTER ETA
+0x2648	0x03B8	# GREEK SMALL LETTER THETA
+0x2649	0x03B9	# GREEK SMALL LETTER IOTA
+0x264A	0x03BA	# GREEK SMALL LETTER KAPPA
+0x264B	0x03BB	# GREEK SMALL LETTER LAMDA
+0x264C	0x03BC	# GREEK SMALL LETTER MU
+0x264D	0x03BD	# GREEK SMALL LETTER NU
+0x264E	0x03BE	# GREEK SMALL LETTER XI
+0x264F	0x03BF	# GREEK SMALL LETTER OMICRON
+0x2650	0x03C0	# GREEK SMALL LETTER PI
+0x2651	0x03C1	# GREEK SMALL LETTER RHO
+0x2652	0x03C3	# GREEK SMALL LETTER SIGMA
+0x2653	0x03C4	# GREEK SMALL LETTER TAU
+0x2654	0x03C5	# GREEK SMALL LETTER UPSILON
+0x2655	0x03C6	# GREEK SMALL LETTER PHI
+0x2656	0x03C7	# GREEK SMALL LETTER CHI
+0x2657	0x03C8	# GREEK SMALL LETTER PSI
+0x2658	0x03C9	# GREEK SMALL LETTER OMEGA
+0x2721	0x0410	# CYRILLIC CAPITAL LETTER A
+0x2722	0x0411	# CYRILLIC CAPITAL LETTER BE
+0x2723	0x0412	# CYRILLIC CAPITAL LETTER VE
+0x2724	0x0413	# CYRILLIC CAPITAL LETTER GHE
+0x2725	0x0414	# CYRILLIC CAPITAL LETTER DE
+0x2726	0x0415	# CYRILLIC CAPITAL LETTER IE
+0x2727	0x0401	# CYRILLIC CAPITAL LETTER IO
+0x2728	0x0416	# CYRILLIC CAPITAL LETTER ZHE
+0x2729	0x0417	# CYRILLIC CAPITAL LETTER ZE
+0x272A	0x0418	# CYRILLIC CAPITAL LETTER I
+0x272B	0x0419	# CYRILLIC CAPITAL LETTER SHORT I
+0x272C	0x041A	# CYRILLIC CAPITAL LETTER KA
+0x272D	0x041B	# CYRILLIC CAPITAL LETTER EL
+0x272E	0x041C	# CYRILLIC CAPITAL LETTER EM
+0x272F	0x041D	# CYRILLIC CAPITAL LETTER EN
+0x2730	0x041E	# CYRILLIC CAPITAL LETTER O
+0x2731	0x041F	# CYRILLIC CAPITAL LETTER PE
+0x2732	0x0420	# CYRILLIC CAPITAL LETTER ER
+0x2733	0x0421	# CYRILLIC CAPITAL LETTER ES
+0x2734	0x0422	# CYRILLIC CAPITAL LETTER TE
+0x2735	0x0423	# CYRILLIC CAPITAL LETTER U
+0x2736	0x0424	# CYRILLIC CAPITAL LETTER EF
+0x2737	0x0425	# CYRILLIC CAPITAL LETTER HA
+0x2738	0x0426	# CYRILLIC CAPITAL LETTER TSE
+0x2739	0x0427	# CYRILLIC CAPITAL LETTER CHE
+0x273A	0x0428	# CYRILLIC CAPITAL LETTER SHA
+0x273B	0x0429	# CYRILLIC CAPITAL LETTER SHCHA
+0x273C	0x042A	# CYRILLIC CAPITAL LETTER HARD SIGN
+0x273D	0x042B	# CYRILLIC CAPITAL LETTER YERU
+0x273E	0x042C	# CYRILLIC CAPITAL LETTER SOFT SIGN
+0x273F	0x042D	# CYRILLIC CAPITAL LETTER E
+0x2740	0x042E	# CYRILLIC CAPITAL LETTER YU
+0x2741	0x042F	# CYRILLIC CAPITAL LETTER YA
+0x2751	0x0430	# CYRILLIC SMALL LETTER A
+0x2752	0x0431	# CYRILLIC SMALL LETTER BE
+0x2753	0x0432	# CYRILLIC SMALL LETTER VE
+0x2754	0x0433	# CYRILLIC SMALL LETTER GHE
+0x2755	0x0434	# CYRILLIC SMALL LETTER DE
+0x2756	0x0435	# CYRILLIC SMALL LETTER IE
+0x2757	0x0451	# CYRILLIC SMALL LETTER IO
+0x2758	0x0436	# CYRILLIC SMALL LETTER ZHE
+0x2759	0x0437	# CYRILLIC SMALL LETTER ZE
+0x275A	0x0438	# CYRILLIC SMALL LETTER I
+0x275B	0x0439	# CYRILLIC SMALL LETTER SHORT I
+0x275C	0x043A	# CYRILLIC SMALL LETTER KA
+0x275D	0x043B	# CYRILLIC SMALL LETTER EL
+0x275E	0x043C	# CYRILLIC SMALL LETTER EM
+0x275F	0x043D	# CYRILLIC SMALL LETTER EN
+0x2760	0x043E	# CYRILLIC SMALL LETTER O
+0x2761	0x043F	# CYRILLIC SMALL LETTER PE
+0x2762	0x0440	# CYRILLIC SMALL LETTER ER
+0x2763	0x0441	# CYRILLIC SMALL LETTER ES
+0x2764	0x0442	# CYRILLIC SMALL LETTER TE
+0x2765	0x0443	# CYRILLIC SMALL LETTER U
+0x2766	0x0444	# CYRILLIC SMALL LETTER EF
+0x2767	0x0445	# CYRILLIC SMALL LETTER HA
+0x2768	0x0446	# CYRILLIC SMALL LETTER TSE
+0x2769	0x0447	# CYRILLIC SMALL LETTER CHE
+0x276A	0x0448	# CYRILLIC SMALL LETTER SHA
+0x276B	0x0449	# CYRILLIC SMALL LETTER SHCHA
+0x276C	0x044A	# CYRILLIC SMALL LETTER HARD SIGN
+0x276D	0x044B	# CYRILLIC SMALL LETTER YERU
+0x276E	0x044C	# CYRILLIC SMALL LETTER SOFT SIGN
+0x276F	0x044D	# CYRILLIC SMALL LETTER E
+0x2770	0x044E	# CYRILLIC SMALL LETTER YU
+0x2771	0x044F	# CYRILLIC SMALL LETTER YA
+0x2821	0x0101	# LATIN SMALL LETTER A WITH MACRON
+0x2822	0x00E1	# LATIN SMALL LETTER A WITH ACUTE
+0x2823	0x01CE	# LATIN SMALL LETTER A WITH CARON
+0x2824	0x00E0	# LATIN SMALL LETTER A WITH GRAVE
+0x2825	0x0113	# LATIN SMALL LETTER E WITH MACRON
+0x2826	0x00E9	# LATIN SMALL LETTER E WITH ACUTE
+0x2827	0x011B	# LATIN SMALL LETTER E WITH CARON
+0x2828	0x00E8	# LATIN SMALL LETTER E WITH GRAVE
+0x2829	0x012B	# LATIN SMALL LETTER I WITH MACRON
+0x282A	0x00ED	# LATIN SMALL LETTER I WITH ACUTE
+0x282B	0x01D0	# LATIN SMALL LETTER I WITH CARON
+0x282C	0x00EC	# LATIN SMALL LETTER I WITH GRAVE
+0x282D	0x014D	# LATIN SMALL LETTER O WITH MACRON
+0x282E	0x00F3	# LATIN SMALL LETTER O WITH ACUTE
+0x282F	0x01D2	# LATIN SMALL LETTER O WITH CARON
+0x2830	0x00F2	# LATIN SMALL LETTER O WITH GRAVE
+0x2831	0x016B	# LATIN SMALL LETTER U WITH MACRON
+0x2832	0x00FA	# LATIN SMALL LETTER U WITH ACUTE
+0x2833	0x01D4	# LATIN SMALL LETTER U WITH CARON
+0x2834	0x00F9	# LATIN SMALL LETTER U WITH GRAVE
+0x2835	0x01D6	# LATIN SMALL LETTER U WITH DIAERESIS AND MACRON
+0x2836	0x01D8	# LATIN SMALL LETTER U WITH DIAERESIS AND ACUTE
+0x2837	0x01DA	# LATIN SMALL LETTER U WITH DIAERESIS AND CARON
+0x2838	0x01DC	# LATIN SMALL LETTER U WITH DIAERESIS AND GRAVE
+0x2839	0x00FC	# LATIN SMALL LETTER U WITH DIAERESIS
+0x283A	0x00EA	# LATIN SMALL LETTER E WITH CIRCUMFLEX
+0x2845	0x3105	# BOPOMOFO LETTER B
+0x2846	0x3106	# BOPOMOFO LETTER P
+0x2847	0x3107	# BOPOMOFO LETTER M
+0x2848	0x3108	# BOPOMOFO LETTER F
+0x2849	0x3109	# BOPOMOFO LETTER D
+0x284A	0x310A	# BOPOMOFO LETTER T
+0x284B	0x310B	# BOPOMOFO LETTER N
+0x284C	0x310C	# BOPOMOFO LETTER L
+0x284D	0x310D	# BOPOMOFO LETTER G
+0x284E	0x310E	# BOPOMOFO LETTER K
+0x284F	0x310F	# BOPOMOFO LETTER H
+0x2850	0x3110	# BOPOMOFO LETTER J
+0x2851	0x3111	# BOPOMOFO LETTER Q
+0x2852	0x3112	# BOPOMOFO LETTER X
+0x2853	0x3113	# BOPOMOFO LETTER ZH
+0x2854	0x3114	# BOPOMOFO LETTER CH
+0x2855	0x3115	# BOPOMOFO LETTER SH
+0x2856	0x3116	# BOPOMOFO LETTER R
+0x2857	0x3117	# BOPOMOFO LETTER Z
+0x2858	0x3118	# BOPOMOFO LETTER C
+0x2859	0x3119	# BOPOMOFO LETTER S
+0x285A	0x311A	# BOPOMOFO LETTER A
+0x285B	0x311B	# BOPOMOFO LETTER O
+0x285C	0x311C	# BOPOMOFO LETTER E
+0x285D	0x311D	# BOPOMOFO LETTER EH
+0x285E	0x311E	# BOPOMOFO LETTER AI
+0x285F	0x311F	# BOPOMOFO LETTER EI
+0x2860	0x3120	# BOPOMOFO LETTER AU
+0x2861	0x3121	# BOPOMOFO LETTER OU
+0x2862	0x3122	# BOPOMOFO LETTER AN
+0x2863	0x3123	# BOPOMOFO LETTER EN
+0x2864	0x3124	# BOPOMOFO LETTER ANG
+0x2865	0x3125	# BOPOMOFO LETTER ENG
+0x2866	0x3126	# BOPOMOFO LETTER ER
+0x2867	0x3127	# BOPOMOFO LETTER I
+0x2868	0x3128	# BOPOMOFO LETTER U
+0x2869	0x3129	# BOPOMOFO LETTER IU
+0x2924	0x2500	# BOX DRAWINGS LIGHT HORIZONTAL
+0x2925	0x2501	# BOX DRAWINGS HEAVY HORIZONTAL
+0x2926	0x2502	# BOX DRAWINGS LIGHT VERTICAL
+0x2927	0x2503	# BOX DRAWINGS HEAVY VERTICAL
+0x2928	0x2504	# BOX DRAWINGS LIGHT TRIPLE DASH HORIZONTAL
+0x2929	0x2505	# BOX DRAWINGS HEAVY TRIPLE DASH HORIZONTAL
+0x292A	0x2506	# BOX DRAWINGS LIGHT TRIPLE DASH VERTICAL
+0x292B	0x2507	# BOX DRAWINGS HEAVY TRIPLE DASH VERTICAL
+0x292C	0x2508	# BOX DRAWINGS LIGHT QUADRUPLE DASH HORIZONTAL
+0x292D	0x2509	# BOX DRAWINGS HEAVY QUADRUPLE DASH HORIZONTAL
+0x292E	0x250A	# BOX DRAWINGS LIGHT QUADRUPLE DASH VERTICAL
+0x292F	0x250B	# BOX DRAWINGS HEAVY QUADRUPLE DASH VERTICAL
+0x2930	0x250C	# BOX DRAWINGS LIGHT DOWN AND RIGHT
+0x2931	0x250D	# BOX DRAWINGS DOWN LIGHT AND RIGHT HEAVY
+0x2932	0x250E	# BOX DRAWINGS DOWN HEAVY AND RIGHT LIGHT
+0x2933	0x250F	# BOX DRAWINGS HEAVY DOWN AND RIGHT
+0x2934	0x2510	# BOX DRAWINGS LIGHT DOWN AND LEFT
+0x2935	0x2511	# BOX DRAWINGS DOWN LIGHT AND LEFT HEAVY
+0x2936	0x2512	# BOX DRAWINGS DOWN HEAVY AND LEFT LIGHT
+0x2937	0x2513	# BOX DRAWINGS HEAVY DOWN AND LEFT
+0x2938	0x2514	# BOX DRAWINGS LIGHT UP AND RIGHT
+0x2939	0x2515	# BOX DRAWINGS UP LIGHT AND RIGHT HEAVY
+0x293A	0x2516	# BOX DRAWINGS UP HEAVY AND RIGHT LIGHT
+0x293B	0x2517	# BOX DRAWINGS HEAVY UP AND RIGHT
+0x293C	0x2518	# BOX DRAWINGS LIGHT UP AND LEFT
+0x293D	0x2519	# BOX DRAWINGS UP LIGHT AND LEFT HEAVY
+0x293E	0x251A	# BOX DRAWINGS UP HEAVY AND LEFT LIGHT
+0x293F	0x251B	# BOX DRAWINGS HEAVY UP AND LEFT
+0x2940	0x251C	# BOX DRAWINGS LIGHT VERTICAL AND RIGHT
+0x2941	0x251D	# BOX DRAWINGS VERTICAL LIGHT AND RIGHT HEAVY
+0x2942	0x251E	# BOX DRAWINGS UP HEAVY AND RIGHT DOWN LIGHT
+0x2943	0x251F	# BOX DRAWINGS DOWN HEAVY AND RIGHT UP LIGHT
+0x2944	0x2520	# BOX DRAWINGS VERTICAL HEAVY AND RIGHT LIGHT
+0x2945	0x2521	# BOX DRAWINGS DOWN LIGHT AND RIGHT UP HEAVY
+0x2946	0x2522	# BOX DRAWINGS UP LIGHT AND RIGHT DOWN HEAVY
+0x2947	0x2523	# BOX DRAWINGS HEAVY VERTICAL AND RIGHT
+0x2948	0x2524	# BOX DRAWINGS LIGHT VERTICAL AND LEFT
+0x2949	0x2525	# BOX DRAWINGS VERTICAL LIGHT AND LEFT HEAVY
+0x294A	0x2526	# BOX DRAWINGS UP HEAVY AND LEFT DOWN LIGHT
+0x294B	0x2527	# BOX DRAWINGS DOWN HEAVY AND LEFT UP LIGHT
+0x294C	0x2528	# BOX DRAWINGS VERTICAL HEAVY AND LEFT LIGHT
+0x294D	0x2529	# BOX DRAWINGS DOWN LIGHT AND LEFT UP HEAVY
+0x294E	0x252A	# BOX DRAWINGS UP LIGHT AND LEFT DOWN HEAVY
+0x294F	0x252B	# BOX DRAWINGS HEAVY VERTICAL AND LEFT
+0x2950	0x252C	# BOX DRAWINGS LIGHT DOWN AND HORIZONTAL
+0x2951	0x252D	# BOX DRAWINGS LEFT HEAVY AND RIGHT DOWN LIGHT
+0x2952	0x252E	# BOX DRAWINGS RIGHT HEAVY AND LEFT DOWN LIGHT
+0x2953	0x252F	# BOX DRAWINGS DOWN LIGHT AND HORIZONTAL HEAVY
+0x2954	0x2530	# BOX DRAWINGS DOWN HEAVY AND HORIZONTAL LIGHT
+0x2955	0x2531	# BOX DRAWINGS RIGHT LIGHT AND LEFT DOWN HEAVY
+0x2956	0x2532	# BOX DRAWINGS LEFT LIGHT AND RIGHT DOWN HEAVY
+0x2957	0x2533	# BOX DRAWINGS HEAVY DOWN AND HORIZONTAL
+0x2958	0x2534	# BOX DRAWINGS LIGHT UP AND HORIZONTAL
+0x2959	0x2535	# BOX DRAWINGS LEFT HEAVY AND RIGHT UP LIGHT
+0x295A	0x2536	# BOX DRAWINGS RIGHT HEAVY AND LEFT UP LIGHT
+0x295B	0x2537	# BOX DRAWINGS UP LIGHT AND HORIZONTAL HEAVY
+0x295C	0x2538	# BOX DRAWINGS UP HEAVY AND HORIZONTAL LIGHT
+0x295D	0x2539	# BOX DRAWINGS RIGHT LIGHT AND LEFT UP HEAVY
+0x295E	0x253A	# BOX DRAWINGS LEFT LIGHT AND RIGHT UP HEAVY
+0x295F	0x253B	# BOX DRAWINGS HEAVY UP AND HORIZONTAL
+0x2960	0x253C	# BOX DRAWINGS LIGHT VERTICAL AND HORIZONTAL
+0x2961	0x253D	# BOX DRAWINGS LEFT HEAVY AND RIGHT VERTICAL LIGHT
+0x2962	0x253E	# BOX DRAWINGS RIGHT HEAVY AND LEFT VERTICAL LIGHT
+0x2963	0x253F	# BOX DRAWINGS VERTICAL LIGHT AND HORIZONTAL HEAVY
+0x2964	0x2540	# BOX DRAWINGS UP HEAVY AND DOWN HORIZONTAL LIGHT
+0x2965	0x2541	# BOX DRAWINGS DOWN HEAVY AND UP HORIZONTAL LIGHT
+0x2966	0x2542	# BOX DRAWINGS VERTICAL HEAVY AND HORIZONTAL LIGHT
+0x2967	0x2543	# BOX DRAWINGS LEFT UP HEAVY AND RIGHT DOWN LIGHT
+0x2968	0x2544	# BOX DRAWINGS RIGHT UP HEAVY AND LEFT DOWN LIGHT
+0x2969	0x2545	# BOX DRAWINGS LEFT DOWN HEAVY AND RIGHT UP LIGHT
+0x296A	0x2546	# BOX DRAWINGS RIGHT DOWN HEAVY AND LEFT UP LIGHT
+0x296B	0x2547	# BOX DRAWINGS DOWN LIGHT AND UP HORIZONTAL HEAVY
+0x296C	0x2548	# BOX DRAWINGS UP LIGHT AND DOWN HORIZONTAL HEAVY
+0x296D	0x2549	# BOX DRAWINGS RIGHT LIGHT AND LEFT VERTICAL HEAVY
+0x296E	0x254A	# BOX DRAWINGS LEFT LIGHT AND RIGHT VERTICAL HEAVY
+0x296F	0x254B	# BOX DRAWINGS HEAVY VERTICAL AND HORIZONTAL
+0x3021	0x554A	# <CJK>
+0x3022	0x963F	# <CJK>
+0x3023	0x57C3	# <CJK>
+0x3024	0x6328	# <CJK>
+0x3025	0x54CE	# <CJK>
+0x3026	0x5509	# <CJK>
+0x3027	0x54C0	# <CJK>
+0x3028	0x769A	# <CJK>
+0x3029	0x764C	# <CJK>
+0x302A	0x85F9	# <CJK>
+0x302B	0x77EE	# <CJK>
+0x302C	0x827E	# <CJK>
+0x302D	0x7919	# <CJK>
+0x302E	0x611B	# <CJK>
+0x302F	0x9698	# <CJK>
+0x3030	0x978D	# <CJK>
+0x3031	0x6C28	# <CJK>
+0x3032	0x5B89	# <CJK>
+0x3033	0x4FFA	# <CJK>
+0x3034	0x6309	# <CJK>
+0x3035	0x6697	# <CJK>
+0x3036	0x5CB8	# <CJK>
+0x3037	0x80FA	# <CJK>
+0x3038	0x6848	# <CJK>
+0x3039	0x9AAF	# <CJK>
+0x303A	0x6602	# <CJK>
+0x303B	0x76CE	# <CJK>
+0x303C	0x51F9	# <CJK>
+0x303D	0x6556	# <CJK>
+0x303E	0x71AC	# <CJK>
+0x303F	0x7FF1	# <CJK>
+0x3040	0x8956	# <CJK>
+0x3041	0x50B2	# <CJK>
+0x3042	0x5965	# <CJK>
+0x3043	0x61CA	# <CJK>
+0x3044	0x6FB3	# <CJK>
+0x3045	0x82AD	# <CJK>
+0x3046	0x634C	# <CJK>
+0x3047	0x6252	# <CJK>
+0x3048	0x53ED	# <CJK>
+0x3049	0x5427	# <CJK>
+0x304A	0x7B06	# <CJK>
+0x304B	0x516B	# <CJK>
+0x304C	0x75A4	# <CJK>
+0x304D	0x5DF4	# <CJK>
+0x304E	0x62D4	# <CJK>
+0x304F	0x8DCB	# <CJK>
+0x3050	0x9776	# <CJK>
+0x3051	0x628A	# <CJK>
+0x3052	0x8019	# <CJK>
+0x3053	0x58E9	# <CJK>
+0x3054	0x9738	# <CJK>
+0x3055	0x7F77	# <CJK>
+0x3056	0x7238	# <CJK>
+0x3057	0x767D	# <CJK>
+0x3058	0x67CF	# <CJK>
+0x3059	0x767E	# <CJK>
+0x305A	0x64FA	# <CJK>
+0x305B	0x4F70	# <CJK>
+0x305C	0x6557	# <CJK>
+0x305D	0x62DC	# <CJK>
+0x305E	0x7A17	# <CJK>
+0x305F	0x6591	# <CJK>
+0x3060	0x73ED	# <CJK>
+0x3061	0x642C	# <CJK>
+0x3062	0x6273	# <CJK>
+0x3063	0x822C	# <CJK>
+0x3064	0x9812	# <CJK>
+0x3065	0x677F	# <CJK>
+0x3066	0x7248	# <CJK>
+0x3067	0x626E	# <CJK>
+0x3068	0x62CC	# <CJK>
+0x3069	0x4F34	# <CJK>
+0x306A	0x74E3	# <CJK>
+0x306B	0x534A	# <CJK>
+0x306C	0x8FA6	# <CJK>
+0x306D	0x7D46	# <CJK>
+0x306E	0x90A6	# <CJK>
+0x306F	0x5E6B	# <CJK>
+0x3070	0x6886	# <CJK>
+0x3071	0x699C	# <CJK>
+0x3072	0x8180	# <CJK>
+0x3073	0x7D81	# <CJK>
+0x3074	0x68D2	# <CJK>
+0x3075	0x78C5	# <CJK>
+0x3076	0x868C	# <CJK>
+0x3077	0x938A	# <CJK>
+0x3078	0x508D	# <CJK>
+0x3079	0x8B17	# <CJK>
+0x307A	0x82DE	# <CJK>
+0x307B	0x80DE	# <CJK>
+0x307C	0x5305	# <CJK>
+0x307D	0x8912	# <CJK>
+0x307E	0x5265	# <CJK>
+0x3121	0x8584	# <CJK>
+0x3122	0x96F9	# <CJK>
+0x3123	0x4FDD	# <CJK>
+0x3124	0x5821	# <CJK>
+0x3125	0x98FD	# <CJK>
+0x3126	0x5BF6	# <CJK>
+0x3127	0x62B1	# <CJK>
+0x3128	0x5831	# <CJK>
+0x3129	0x66B4	# <CJK>
+0x312A	0x8C79	# <CJK>
+0x312B	0x9B91	# <CJK>
+0x312C	0x7206	# <CJK>
+0x312D	0x676F	# <CJK>
+0x312E	0x7891	# <CJK>
+0x312F	0x60B2	# <CJK>
+0x3130	0x5351	# <CJK>
+0x3131	0x5317	# <CJK>
+0x3132	0x8F29	# <CJK>
+0x3133	0x80CC	# <CJK>
+0x3134	0x8C9D	# <CJK>
+0x3135	0x92C7	# <CJK>
+0x3136	0x500D	# <CJK>
+0x3137	0x72FD	# <CJK>
+0x3138	0x5099	# <CJK>
+0x3139	0x618A	# <CJK>
+0x313A	0x7119	# <CJK>
+0x313B	0x88AB	# <CJK>
+0x313C	0x5954	# <CJK>
+0x313D	0x82EF	# <CJK>
+0x313E	0x672C	# <CJK>
+0x313F	0x7B28	# <CJK>
+0x3140	0x5D29	# <CJK>
+0x3141	0x7DB3	# <CJK>
+0x3142	0x752D	# <CJK>
+0x3143	0x6CF5	# <CJK>
+0x3144	0x8E66	# <CJK>
+0x3145	0x8FF8	# <CJK>
+0x3146	0x903C	# <CJK>
+0x3147	0x9F3B	# <CJK>
+0x3148	0x6BD4	# <CJK>
+0x3149	0x9119	# <CJK>
+0x314A	0x7B46	# <CJK>
+0x314B	0x5F7C	# <CJK>
+0x314C	0x78A7	# <CJK>
+0x314D	0x84D6	# <CJK>
+0x314E	0x853D	# <CJK>
+0x314F	0x7562	# <CJK>
+0x3150	0x6583	# <CJK>
+0x3151	0x6BD6	# <CJK>
+0x3152	0x5E63	# <CJK>
+0x3153	0x5E87	# <CJK>
+0x3154	0x75F9	# <CJK>
+0x3155	0x9589	# <CJK>
+0x3156	0x655D	# <CJK>
+0x3157	0x5F0A	# <CJK>
+0x3158	0x5FC5	# <CJK>
+0x3159	0x8F9F	# <CJK>
+0x315A	0x58C1	# <CJK>
+0x315B	0x81C2	# <CJK>
+0x315C	0x907F	# <CJK>
+0x315D	0x965B	# <CJK>
+0x315E	0x97AD	# <CJK>
+0x315F	0x908A	# <CJK>
+0x3160	0x7DE8	# <CJK>
+0x3161	0x8CB6	# <CJK>
+0x3162	0x6241	# <CJK>
+0x3163	0x4FBF	# <CJK>
+0x3164	0x8B8A	# <CJK>
+0x3165	0x535E	# <CJK>
+0x3166	0x8FA8	# <CJK>
+0x3167	0x8FAF	# <CJK>
+0x3168	0x8FAE	# <CJK>
+0x3169	0x904D	# <CJK>
+0x316A	0x6A19	# <CJK>
+0x316B	0x5F6A	# <CJK>
+0x316C	0x8198	# <CJK>
+0x316D	0x8868	# <CJK>
+0x316E	0x9C49	# <CJK>
+0x316F	0x618B	# <CJK>
+0x3170	0x522B	# <CJK>
+0x3171	0x765F	# <CJK>
+0x3172	0x5F6C	# <CJK>
+0x3173	0x658C	# <CJK>
+0x3174	0x7015	# <CJK>
+0x3175	0x6FF1	# <CJK>
+0x3176	0x8CD3	# <CJK>
+0x3177	0x64EF	# <CJK>
+0x3178	0x5175	# <CJK>
+0x3179	0x51B0	# <CJK>
+0x317A	0x67C4	# <CJK>
+0x317B	0x4E19	# <CJK>
+0x317C	0x79C9	# <CJK>
+0x317D	0x9905	# <CJK>
+0x317E	0x70B3	# <CJK>
+0x3221	0x75C5	# <CJK>
+0x3222	0x5E76	# <CJK>
+0x3223	0x73BB	# <CJK>
+0x3224	0x83E0	# <CJK>
+0x3225	0x64AD	# <CJK>
+0x3226	0x64A5	# <CJK>
+0x3227	0x9262	# <CJK>
+0x3228	0x6CE2	# <CJK>
+0x3229	0x535A	# <CJK>
+0x322A	0x52C3	# <CJK>
+0x322B	0x640F	# <CJK>
+0x322C	0x9251	# <CJK>
+0x322D	0x7B94	# <CJK>
+0x322E	0x4F2F	# <CJK>
+0x322F	0x5E1B	# <CJK>
+0x3230	0x8236	# <CJK>
+0x3231	0x8116	# <CJK>
+0x3232	0x818A	# <CJK>
+0x3233	0x6E24	# <CJK>
+0x3234	0x6CCA	# <CJK>
+0x3235	0x99C1	# <CJK>
+0x3236	0x6355	# <CJK>
+0x3237	0x535C	# <CJK>
+0x3238	0x54FA	# <CJK>
+0x3239	0x88DC	# <CJK>
+0x323A	0x57E0	# <CJK>
+0x323B	0x4E0D	# <CJK>
+0x323C	0x5E03	# <CJK>
+0x323D	0x6B65	# <CJK>
+0x323E	0x7C3F	# <CJK>
+0x323F	0x90E8	# <CJK>
+0x3240	0x6016	# <CJK>
+0x3241	0x64E6	# <CJK>
+0x3242	0x731C	# <CJK>
+0x3243	0x88C1	# <CJK>
+0x3244	0x6750	# <CJK>
+0x3245	0x624D	# <CJK>
+0x3246	0x8CA1	# <CJK>
+0x3247	0x776C	# <CJK>
+0x3248	0x8E29	# <CJK>
+0x3249	0x91C7	# <CJK>
+0x324A	0x5F69	# <CJK>
+0x324B	0x83DC	# <CJK>
+0x324C	0x8521	# <CJK>
+0x324D	0x9910	# <CJK>
+0x324E	0x53C3	# <CJK>
+0x324F	0x8836	# <CJK>
+0x3250	0x6B98	# <CJK>
+0x3251	0x615A	# <CJK>
+0x3252	0x6158	# <CJK>
+0x3253	0x71E6	# <CJK>
+0x3254	0x84BC	# <CJK>
+0x3255	0x8259	# <CJK>
+0x3256	0x5009	# <CJK>
+0x3257	0x6EC4	# <CJK>
+0x3258	0x85CF	# <CJK>
+0x3259	0x64CD	# <CJK>
+0x325A	0x7CD9	# <CJK>
+0x325B	0x69FD	# <CJK>
+0x325C	0x66F9	# <CJK>
+0x325D	0x8349	# <CJK>
+0x325E	0x53A0	# <CJK>
+0x325F	0x7B56	# <CJK>
+0x3260	0x5074	# <CJK>
+0x3261	0x518C	# <CJK>
+0x3262	0x6E2C	# <CJK>
+0x3263	0x5C64	# <CJK>
+0x3264	0x8E6D	# <CJK>
+0x3265	0x63D2	# <CJK>
+0x3266	0x53C9	# <CJK>
+0x3267	0x832C	# <CJK>
+0x3268	0x8336	# <CJK>
+0x3269	0x67E5	# <CJK>
+0x326A	0x78B4	# <CJK>
+0x326B	0x643D	# <CJK>
+0x326C	0x5BDF	# <CJK>
+0x326D	0x5C94	# <CJK>
+0x326E	0x5DEE	# <CJK>
+0x326F	0x8A6B	# <CJK>
+0x3270	0x62C6	# <CJK>
+0x3271	0x67F4	# <CJK>
+0x3272	0x8C7A	# <CJK>
+0x3273	0x6519	# <CJK>
+0x3274	0x647B	# <CJK>
+0x3275	0x87EC	# <CJK>
+0x3276	0x995E	# <CJK>
+0x3277	0x8B92	# <CJK>
+0x3278	0x7E8F	# <CJK>
+0x3279	0x93DF	# <CJK>
+0x327A	0x7523	# <CJK>
+0x327B	0x95E1	# <CJK>
+0x327C	0x986B	# <CJK>
+0x327D	0x660C	# <CJK>
+0x327E	0x7316	# <CJK>
+0x3321	0x5834	# <CJK>
+0x3322	0x5617	# <CJK>
+0x3323	0x5E38	# <CJK>
+0x3324	0x9577	# <CJK>
+0x3325	0x511F	# <CJK>
+0x3326	0x8178	# <CJK>
+0x3327	0x5EE0	# <CJK>
+0x3328	0x655E	# <CJK>
+0x3329	0x66A2	# <CJK>
+0x332A	0x5531	# <CJK>
+0x332B	0x5021	# <CJK>
+0x332C	0x8D85	# <CJK>
+0x332D	0x6284	# <CJK>
+0x332E	0x9214	# <CJK>
+0x332F	0x671D	# <CJK>
+0x3330	0x5632	# <CJK>
+0x3331	0x6F6E	# <CJK>
+0x3332	0x5DE2	# <CJK>
+0x3333	0x5435	# <CJK>
+0x3334	0x7092	# <CJK>
+0x3335	0x8ECA	# <CJK>
+0x3336	0x626F	# <CJK>
+0x3337	0x64A4	# <CJK>
+0x3338	0x63A3	# <CJK>
+0x3339	0x5FB9	# <CJK>
+0x333A	0x6F88	# <CJK>
+0x333B	0x90F4	# <CJK>
+0x333C	0x81E3	# <CJK>
+0x333D	0x8FB0	# <CJK>
+0x333E	0x5875	# <CJK>
+0x333F	0x6668	# <CJK>
+0x3340	0x5FF1	# <CJK>
+0x3341	0x6C89	# <CJK>
+0x3342	0x9673	# <CJK>
+0x3343	0x8D81	# <CJK>
+0x3344	0x896F	# <CJK>
+0x3345	0x6491	# <CJK>
+0x3346	0x7A31	# <CJK>
+0x3347	0x57CE	# <CJK>
+0x3348	0x6A59	# <CJK>
+0x3349	0x6210	# <CJK>
+0x334A	0x5448	# <CJK>
+0x334B	0x4E58	# <CJK>
+0x334C	0x7A0B	# <CJK>
+0x334D	0x61F2	# <CJK>
+0x334E	0x6F84	# <CJK>
+0x334F	0x8AA0	# <CJK>
+0x3350	0x627F	# <CJK>
+0x3351	0x901E	# <CJK>
+0x3352	0x9A01	# <CJK>
+0x3353	0x79E4	# <CJK>
+0x3354	0x5403	# <CJK>
+0x3355	0x75F4	# <CJK>
+0x3356	0x6301	# <CJK>
+0x3357	0x5319	# <CJK>
+0x3358	0x6C60	# <CJK>
+0x3359	0x9072	# <CJK>
+0x335A	0x5F1B	# <CJK>
+0x335B	0x99B3	# <CJK>
+0x335C	0x803B	# <CJK>
+0x335D	0x9F52	# <CJK>
+0x335E	0x4F88	# <CJK>
+0x335F	0x5C3A	# <CJK>
+0x3360	0x8D64	# <CJK>
+0x3361	0x7FC5	# <CJK>
+0x3362	0x65A5	# <CJK>
+0x3363	0x71BE	# <CJK>
+0x3364	0x5145	# <CJK>
+0x3365	0x885D	# <CJK>
+0x3366	0x87F2	# <CJK>
+0x3367	0x5D07	# <CJK>
+0x3368	0x5BF5	# <CJK>
+0x3369	0x62BD	# <CJK>
+0x336A	0x916C	# <CJK>
+0x336B	0x7587	# <CJK>
+0x336C	0x8E8A	# <CJK>
+0x336D	0x7A20	# <CJK>
+0x336E	0x6101	# <CJK>
+0x336F	0x7C4C	# <CJK>
+0x3370	0x4EC7	# <CJK>
+0x3371	0x7DA2	# <CJK>
+0x3372	0x7785	# <CJK>
+0x3373	0x919C	# <CJK>
+0x3374	0x81ED	# <CJK>
+0x3375	0x521D	# <CJK>
+0x3376	0x51FA	# <CJK>
+0x3377	0x6A71	# <CJK>
+0x3378	0x53A8	# <CJK>
+0x3379	0x8E87	# <CJK>
+0x337A	0x92E4	# <CJK>
+0x337B	0x96DB	# <CJK>
+0x337C	0x6EC1	# <CJK>
+0x337D	0x9664	# <CJK>
+0x337E	0x695A	# <CJK>
+0x3421	0x790E	# <CJK>
+0x3422	0x5132	# <CJK>
+0x3423	0x77D7	# <CJK>
+0x3424	0x6410	# <CJK>
+0x3425	0x89F8	# <CJK>
+0x3426	0x8655	# <CJK>
+0x3427	0x63E3	# <CJK>
+0x3428	0x5DDD	# <CJK>
+0x3429	0x7A7F	# <CJK>
+0x342A	0x693D	# <CJK>
+0x342B	0x50B3	# <CJK>
+0x342C	0x8239	# <CJK>
+0x342D	0x5598	# <CJK>
+0x342E	0x4E32	# <CJK>
+0x342F	0x7621	# <CJK>
+0x3430	0x7A97	# <CJK>
+0x3431	0x5E62	# <CJK>
+0x3432	0x5E8A	# <CJK>
+0x3433	0x95D6	# <CJK>
+0x3434	0x5275	# <CJK>
+0x3435	0x5439	# <CJK>
+0x3436	0x708A	# <CJK>
+0x3437	0x6376	# <CJK>
+0x3438	0x9318	# <CJK>
+0x3439	0x5782	# <CJK>
+0x343A	0x6625	# <CJK>
+0x343B	0x693F	# <CJK>
+0x343C	0x9187	# <CJK>
+0x343D	0x5507	# <CJK>
+0x343E	0x6DF3	# <CJK>
+0x343F	0x7D14	# <CJK>
+0x3440	0x8822	# <CJK>
+0x3441	0x6233	# <CJK>
+0x3442	0x7DBD	# <CJK>
+0x3443	0x75B5	# <CJK>
+0x3444	0x8328	# <CJK>
+0x3445	0x78C1	# <CJK>
+0x3446	0x96CC	# <CJK>
+0x3447	0x8FAD	# <CJK>
+0x3448	0x6148	# <CJK>
+0x3449	0x74F7	# <CJK>
+0x344A	0x8A5E	# <CJK>
+0x344B	0x6B64	# <CJK>
+0x344C	0x523A	# <CJK>
+0x344D	0x8CDC	# <CJK>
+0x344E	0x6B21	# <CJK>
+0x344F	0x8070	# <CJK>
+0x3450	0x8471	# <CJK>
+0x3451	0x56F1	# <CJK>
+0x3452	0x5306	# <CJK>
+0x3453	0x5F9E	# <CJK>
+0x3454	0x53E2	# <CJK>
+0x3455	0x51D1	# <CJK>
+0x3456	0x7C97	# <CJK>
+0x3457	0x918B	# <CJK>
+0x3458	0x7C07	# <CJK>
+0x3459	0x4FC3	# <CJK>
+0x345A	0x8EA5	# <CJK>
+0x345B	0x7BE1	# <CJK>
+0x345C	0x7AC4	# <CJK>
+0x345D	0x6467	# <CJK>
+0x345E	0x5D14	# <CJK>
+0x345F	0x50AC	# <CJK>
+0x3460	0x8106	# <CJK>
+0x3461	0x7601	# <CJK>
+0x3462	0x7CB9	# <CJK>
+0x3463	0x6DEC	# <CJK>
+0x3464	0x7FE0	# <CJK>
+0x3465	0x6751	# <CJK>
+0x3466	0x5B58	# <CJK>
+0x3467	0x5BF8	# <CJK>
+0x3468	0x78CB	# <CJK>
+0x3469	0x64AE	# <CJK>
+0x346A	0x6413	# <CJK>
+0x346B	0x63AA	# <CJK>
+0x346C	0x632B	# <CJK>
+0x346D	0x932F	# <CJK>
+0x346E	0x642D	# <CJK>
+0x346F	0x9054	# <CJK>
+0x3470	0x7B54	# <CJK>
+0x3471	0x7629	# <CJK>
+0x3472	0x6253	# <CJK>
+0x3473	0x5927	# <CJK>
+0x3474	0x5446	# <CJK>
+0x3475	0x6B79	# <CJK>
+0x3476	0x50A3	# <CJK>
+0x3477	0x6234	# <CJK>
+0x3478	0x5E36	# <CJK>
+0x3479	0x6B86	# <CJK>
+0x347A	0x4EE3	# <CJK>
+0x347B	0x8CB8	# <CJK>
+0x347C	0x888B	# <CJK>
+0x347D	0x5F85	# <CJK>
+0x347E	0x902E	# <CJK>
+0x3521	0x6020	# <CJK>
+0x3522	0x803D	# <CJK>
+0x3523	0x64D4	# <CJK>
+0x3524	0x4E39	# <CJK>
+0x3525	0x55AE	# <CJK>
+0x3526	0x9132	# <CJK>
+0x3527	0x64A3	# <CJK>
+0x3528	0x81BD	# <CJK>
+0x3529	0x65E6	# <CJK>
+0x352A	0x6C2E	# <CJK>
+0x352B	0x4F46	# <CJK>
+0x352C	0x619A	# <CJK>
+0x352D	0x6DE1	# <CJK>
+0x352E	0x8A95	# <CJK>
+0x352F	0x5F48	# <CJK>
+0x3530	0x86CB	# <CJK>
+0x3531	0x7576	# <CJK>
+0x3532	0x64CB	# <CJK>
+0x3533	0x9EE8	# <CJK>
+0x3534	0x8569	# <CJK>
+0x3535	0x6A94	# <CJK>
+0x3536	0x5200	# <CJK>
+0x3537	0x6417	# <CJK>
+0x3538	0x8E48	# <CJK>
+0x3539	0x5012	# <CJK>
+0x353A	0x5CF6	# <CJK>
+0x353B	0x79B1	# <CJK>
+0x353C	0x5C0E	# <CJK>
+0x353D	0x5230	# <CJK>
+0x353E	0x7A3B	# <CJK>
+0x353F	0x60BC	# <CJK>
+0x3540	0x9053	# <CJK>
+0x3541	0x76D7	# <CJK>
+0x3542	0x5FB7	# <CJK>
+0x3543	0x5F97	# <CJK>
+0x3544	0x7684	# <CJK>
+0x3545	0x8E6C	# <CJK>
+0x3546	0x71C8	# <CJK>
+0x3547	0x767B	# <CJK>
+0x3548	0x7B49	# <CJK>
+0x3549	0x77AA	# <CJK>
+0x354A	0x51F3	# <CJK>
+0x354B	0x9127	# <CJK>
+0x354C	0x5824	# <CJK>
+0x354D	0x4F4E	# <CJK>
+0x354E	0x6EF4	# <CJK>
+0x354F	0x8FEA	# <CJK>
+0x3550	0x6575	# <CJK>
+0x3551	0x7B1B	# <CJK>
+0x3552	0x72C4	# <CJK>
+0x3553	0x6ECC	# <CJK>
+0x3554	0x7FDF	# <CJK>
+0x3555	0x5AE1	# <CJK>
+0x3556	0x62B5	# <CJK>
+0x3557	0x5E95	# <CJK>
+0x3558	0x5730	# <CJK>
+0x3559	0x8482	# <CJK>
+0x355A	0x7B2C	# <CJK>
+0x355B	0x5E1D	# <CJK>
+0x355C	0x5F1F	# <CJK>
+0x355D	0x905E	# <CJK>
+0x355E	0x7DE0	# <CJK>
+0x355F	0x985B	# <CJK>
+0x3560	0x6382	# <CJK>
+0x3561	0x6EC7	# <CJK>
+0x3562	0x7898	# <CJK>
+0x3563	0x9EDE	# <CJK>
+0x3564	0x5178	# <CJK>
+0x3565	0x975B	# <CJK>
+0x3566	0x588A	# <CJK>
+0x3567	0x96FB	# <CJK>
+0x3568	0x4F43	# <CJK>
+0x3569	0x7538	# <CJK>
+0x356A	0x5E97	# <CJK>
+0x356B	0x60E6	# <CJK>
+0x356C	0x5960	# <CJK>
+0x356D	0x6FB1	# <CJK>
+0x356E	0x6BBF	# <CJK>
+0x356F	0x7889	# <CJK>
+0x3570	0x53FC	# <CJK>
+0x3571	0x96D5	# <CJK>
+0x3572	0x51CB	# <CJK>
+0x3573	0x5201	# <CJK>
+0x3574	0x6389	# <CJK>
+0x3575	0x540A	# <CJK>
+0x3576	0x91E3	# <CJK>
+0x3577	0x8ABF	# <CJK>
+0x3578	0x8DCC	# <CJK>
+0x3579	0x7239	# <CJK>
+0x357A	0x789F	# <CJK>
+0x357B	0x8776	# <CJK>
+0x357C	0x8FED	# <CJK>
+0x357D	0x8ADC	# <CJK>
+0x357E	0x758A	# <CJK>
+0x3621	0x4E01	# <CJK>
+0x3622	0x76EF	# <CJK>
+0x3623	0x53EE	# <CJK>
+0x3624	0x91D8	# <CJK>
+0x3625	0x9802	# <CJK>
+0x3626	0x9F0E	# <CJK>
+0x3627	0x9320	# <CJK>
+0x3628	0x5B9A	# <CJK>
+0x3629	0x8A02	# <CJK>
+0x362A	0x4E22	# <CJK>
+0x362B	0x6771	# <CJK>
+0x362C	0x51AC	# <CJK>
+0x362D	0x8463	# <CJK>
+0x362E	0x61C2	# <CJK>
+0x362F	0x52D5	# <CJK>
+0x3630	0x68DF	# <CJK>
+0x3631	0x4F97	# <CJK>
+0x3632	0x606B	# <CJK>
+0x3633	0x51CD	# <CJK>
+0x3634	0x6D1E	# <CJK>
+0x3635	0x515C	# <CJK>
+0x3636	0x6296	# <CJK>
+0x3637	0x9B25	# <CJK>
+0x3638	0x9661	# <CJK>
+0x3639	0x8C46	# <CJK>
+0x363A	0x9017	# <CJK>
+0x363B	0x75D8	# <CJK>
+0x363C	0x90FD	# <CJK>
+0x363D	0x7763	# <CJK>
+0x363E	0x6BD2	# <CJK>
+0x363F	0x72A2	# <CJK>
+0x3640	0x7368	# <CJK>
+0x3641	0x8B80	# <CJK>
+0x3642	0x5835	# <CJK>
+0x3643	0x7779	# <CJK>
+0x3644	0x8CED	# <CJK>
+0x3645	0x675C	# <CJK>
+0x3646	0x934D	# <CJK>
+0x3647	0x809A	# <CJK>
+0x3648	0x5EA6	# <CJK>
+0x3649	0x6E21	# <CJK>
+0x364A	0x5992	# <CJK>
+0x364B	0x7AEF	# <CJK>
+0x364C	0x77ED	# <CJK>
+0x364D	0x935B	# <CJK>
+0x364E	0x6BB5	# <CJK>
+0x364F	0x65B7	# <CJK>
+0x3650	0x7DDE	# <CJK>
+0x3651	0x5806	# <CJK>
+0x3652	0x5151	# <CJK>
+0x3653	0x968A	# <CJK>
+0x3654	0x5C0D	# <CJK>
+0x3655	0x58A9	# <CJK>
+0x3656	0x5678	# <CJK>
+0x3657	0x8E72	# <CJK>
+0x3658	0x6566	# <CJK>
+0x3659	0x9813	# <CJK>
+0x365A	0x56E4	# <CJK>
+0x365B	0x920D	# <CJK>
+0x365C	0x76FE	# <CJK>
+0x365D	0x9041	# <CJK>
+0x365E	0x6387	# <CJK>
+0x365F	0x54C6	# <CJK>
+0x3660	0x591A	# <CJK>
+0x3661	0x596A	# <CJK>
+0x3662	0x579B	# <CJK>
+0x3663	0x8EB2	# <CJK>
+0x3664	0x6735	# <CJK>
+0x3665	0x8DFA	# <CJK>
+0x3666	0x8235	# <CJK>
+0x3667	0x5241	# <CJK>
+0x3668	0x60F0	# <CJK>
+0x3669	0x58AE	# <CJK>
+0x366A	0x86FE	# <CJK>
+0x366B	0x5CE8	# <CJK>
+0x366C	0x9D5D	# <CJK>
+0x366D	0x4FC4	# <CJK>
+0x366E	0x984D	# <CJK>
+0x366F	0x8A1B	# <CJK>
+0x3670	0x5A25	# <CJK>
+0x3671	0x60E1	# <CJK>
+0x3672	0x5384	# <CJK>
+0x3673	0x627C	# <CJK>
+0x3674	0x904F	# <CJK>
+0x3675	0x9102	# <CJK>
+0x3676	0x9913	# <CJK>
+0x3677	0x6069	# <CJK>
+0x3678	0x800C	# <CJK>
+0x3679	0x5152	# <CJK>
+0x367A	0x8033	# <CJK>
+0x367B	0x723E	# <CJK>
+0x367C	0x990C	# <CJK>
+0x367D	0x6D31	# <CJK>
+0x367E	0x4E8C	# <CJK>
+0x3721	0x8CB3	# <CJK>
+0x3722	0x767C	# <CJK>
+0x3723	0x7F70	# <CJK>
+0x3724	0x7B4F	# <CJK>
+0x3725	0x4F10	# <CJK>
+0x3726	0x4E4F	# <CJK>
+0x3727	0x95A5	# <CJK>
+0x3728	0x6CD5	# <CJK>
+0x3729	0x73D0	# <CJK>
+0x372A	0x85E9	# <CJK>
+0x372B	0x5E06	# <CJK>
+0x372C	0x756A	# <CJK>
+0x372D	0x7FFB	# <CJK>
+0x372E	0x6A0A	# <CJK>
+0x372F	0x792C	# <CJK>
+0x3730	0x91E9	# <CJK>
+0x3731	0x7E41	# <CJK>
+0x3732	0x51E1	# <CJK>
+0x3733	0x7169	# <CJK>
+0x3734	0x53CD	# <CJK>
+0x3735	0x8FD4	# <CJK>
+0x3736	0x7BC4	# <CJK>
+0x3737	0x8CA9	# <CJK>
+0x3738	0x72AF	# <CJK>
+0x3739	0x98EF	# <CJK>
+0x373A	0x6CDB	# <CJK>
+0x373B	0x574A	# <CJK>
+0x373C	0x82B3	# <CJK>
+0x373D	0x65B9	# <CJK>
+0x373E	0x80AA	# <CJK>
+0x373F	0x623F	# <CJK>
+0x3740	0x9632	# <CJK>
+0x3741	0x59A8	# <CJK>
+0x3742	0x4EFF	# <CJK>
+0x3743	0x8A2A	# <CJK>
+0x3744	0x7D21	# <CJK>
+0x3745	0x653E	# <CJK>
+0x3746	0x83F2	# <CJK>
+0x3747	0x975E	# <CJK>
+0x3748	0x5561	# <CJK>
+0x3749	0x98DB	# <CJK>
+0x374A	0x80A5	# <CJK>
+0x374B	0x532A	# <CJK>
+0x374C	0x8AB9	# <CJK>
+0x374D	0x5420	# <CJK>
+0x374E	0x80BA	# <CJK>
+0x374F	0x5EE2	# <CJK>
+0x3750	0x6CB8	# <CJK>
+0x3751	0x8CBB	# <CJK>
+0x3752	0x82AC	# <CJK>
+0x3753	0x915A	# <CJK>
+0x3754	0x5429	# <CJK>
+0x3755	0x6C1B	# <CJK>
+0x3756	0x5206	# <CJK>
+0x3757	0x7D1B	# <CJK>
+0x3758	0x58B3	# <CJK>
+0x3759	0x711A	# <CJK>
+0x375A	0x6C7E	# <CJK>
+0x375B	0x7C89	# <CJK>
+0x375C	0x596E	# <CJK>
+0x375D	0x4EFD	# <CJK>
+0x375E	0x5FFF	# <CJK>
+0x375F	0x61A4	# <CJK>
+0x3760	0x7CDE	# <CJK>
+0x3761	0x8C50	# <CJK>
+0x3762	0x5C01	# <CJK>
+0x3763	0x6953	# <CJK>
+0x3764	0x8702	# <CJK>
+0x3765	0x5CF0	# <CJK>
+0x3766	0x92D2	# <CJK>
+0x3767	0x98A8	# <CJK>
+0x3768	0x760B	# <CJK>
+0x3769	0x70FD	# <CJK>
+0x376A	0x9022	# <CJK>
+0x376B	0x99AE	# <CJK>
+0x376C	0x7E2B	# <CJK>
+0x376D	0x8AF7	# <CJK>
+0x376E	0x5949	# <CJK>
+0x376F	0x9CF3	# <CJK>
+0x3770	0x4F5B	# <CJK>
+0x3771	0x5426	# <CJK>
+0x3772	0x592B	# <CJK>
+0x3773	0x6577	# <CJK>
+0x3774	0x819A	# <CJK>
+0x3775	0x5B75	# <CJK>
+0x3776	0x6276	# <CJK>
+0x3777	0x62C2	# <CJK>
+0x3778	0x8F3B	# <CJK>
+0x3779	0x5E45	# <CJK>
+0x377A	0x6C1F	# <CJK>
+0x377B	0x7B26	# <CJK>
+0x377C	0x4F0F	# <CJK>
+0x377D	0x4FD8	# <CJK>
+0x377E	0x670D	# <CJK>
+0x3821	0x6D6E	# <CJK>
+0x3822	0x6DAA	# <CJK>
+0x3823	0x798F	# <CJK>
+0x3824	0x88B1	# <CJK>
+0x3825	0x5F17	# <CJK>
+0x3826	0x752B	# <CJK>
+0x3827	0x64AB	# <CJK>
+0x3828	0x8F14	# <CJK>
+0x3829	0x4FEF	# <CJK>
+0x382A	0x91DC	# <CJK>
+0x382B	0x65A7	# <CJK>
+0x382C	0x812F	# <CJK>
+0x382D	0x8151	# <CJK>
+0x382E	0x5E9C	# <CJK>
+0x382F	0x8150	# <CJK>
+0x3830	0x8D74	# <CJK>
+0x3831	0x526F	# <CJK>
+0x3832	0x8986	# <CJK>
+0x3833	0x8CE6	# <CJK>
+0x3834	0x5FA9	# <CJK>
+0x3835	0x5085	# <CJK>
+0x3836	0x4ED8	# <CJK>
+0x3837	0x961C	# <CJK>
+0x3838	0x7236	# <CJK>
+0x3839	0x8179	# <CJK>
+0x383A	0x8CA0	# <CJK>
+0x383B	0x5BCC	# <CJK>
+0x383C	0x8A03	# <CJK>
+0x383D	0x9644	# <CJK>
+0x383E	0x5A66	# <CJK>
+0x383F	0x7E1B	# <CJK>
+0x3840	0x5490	# <CJK>
+0x3841	0x5676	# <CJK>
+0x3842	0x560E	# <CJK>
+0x3843	0x8A72	# <CJK>
+0x3844	0x6539	# <CJK>
+0x3845	0x6982	# <CJK>
+0x3846	0x9223	# <CJK>
+0x3847	0x84CB	# <CJK>
+0x3848	0x6E89	# <CJK>
+0x3849	0x5E79	# <CJK>
+0x384A	0x7518	# <CJK>
+0x384B	0x6746	# <CJK>
+0x384C	0x67D1	# <CJK>
+0x384D	0x7AFF	# <CJK>
+0x384E	0x809D	# <CJK>
+0x384F	0x8D95	# <CJK>
+0x3850	0x611F	# <CJK>
+0x3851	0x79C6	# <CJK>
+0x3852	0x6562	# <CJK>
+0x3853	0x8D1B	# <CJK>
+0x3854	0x5CA1	# <CJK>
+0x3855	0x525B	# <CJK>
+0x3856	0x92FC	# <CJK>
+0x3857	0x7F38	# <CJK>
+0x3858	0x809B	# <CJK>
+0x3859	0x7DB1	# <CJK>
+0x385A	0x5D17	# <CJK>
+0x385B	0x6E2F	# <CJK>
+0x385C	0x6760	# <CJK>
+0x385D	0x7BD9	# <CJK>
+0x385E	0x768B	# <CJK>
+0x385F	0x9AD8	# <CJK>
+0x3860	0x818F	# <CJK>
+0x3861	0x7F94	# <CJK>
+0x3862	0x7CD5	# <CJK>
+0x3863	0x641E	# <CJK>
+0x3864	0x93AC	# <CJK>
+0x3865	0x7A3F	# <CJK>
+0x3866	0x544A	# <CJK>
+0x3867	0x54E5	# <CJK>
+0x3868	0x6B4C	# <CJK>
+0x3869	0x64F1	# <CJK>
+0x386A	0x6208	# <CJK>
+0x386B	0x9D3F	# <CJK>
+0x386C	0x80F3	# <CJK>
+0x386D	0x7599	# <CJK>
+0x386E	0x5272	# <CJK>
+0x386F	0x9769	# <CJK>
+0x3870	0x845B	# <CJK>
+0x3871	0x683C	# <CJK>
+0x3872	0x86E4	# <CJK>
+0x3873	0x95A3	# <CJK>
+0x3874	0x9694	# <CJK>
+0x3875	0x927B	# <CJK>
+0x3876	0x500B	# <CJK>
+0x3877	0x5404	# <CJK>
+0x3878	0x7D66	# <CJK>
+0x3879	0x6839	# <CJK>
+0x387A	0x8DDF	# <CJK>
+0x387B	0x8015	# <CJK>
+0x387C	0x66F4	# <CJK>
+0x387D	0x5E9A	# <CJK>
+0x387E	0x7FB9	# <CJK>
+0x3921	0x57C2	# <CJK>
+0x3922	0x803F	# <CJK>
+0x3923	0x6897	# <CJK>
+0x3924	0x5DE5	# <CJK>
+0x3925	0x653B	# <CJK>
+0x3926	0x529F	# <CJK>
+0x3927	0x606D	# <CJK>
+0x3928	0x9F94	# <CJK>
+0x3929	0x4F9B	# <CJK>
+0x392A	0x8EAC	# <CJK>
+0x392B	0x516C	# <CJK>
+0x392C	0x5BAB	# <CJK>
+0x392D	0x5F13	# <CJK>
+0x392E	0x978F	# <CJK>
+0x392F	0x6C5E	# <CJK>
+0x3930	0x62F1	# <CJK>
+0x3931	0x8CA2	# <CJK>
+0x3932	0x5171	# <CJK>
+0x3933	0x920E	# <CJK>
+0x3934	0x52FE	# <CJK>
+0x3935	0x6E9D	# <CJK>
+0x3936	0x82DF	# <CJK>
+0x3937	0x72D7	# <CJK>
+0x3938	0x57A2	# <CJK>
+0x3939	0x69CB	# <CJK>
+0x393A	0x8CFC	# <CJK>
+0x393B	0x591F	# <CJK>
+0x393C	0x8F9C	# <CJK>
+0x393D	0x83C7	# <CJK>
+0x393E	0x5495	# <CJK>
+0x393F	0x7B8D	# <CJK>
+0x3940	0x4F30	# <CJK>
+0x3941	0x6CBD	# <CJK>
+0x3942	0x5B64	# <CJK>
+0x3943	0x59D1	# <CJK>
+0x3944	0x9F13	# <CJK>
+0x3945	0x53E4	# <CJK>
+0x3946	0x8831	# <CJK>
+0x3947	0x9AA8	# <CJK>
+0x3948	0x8C37	# <CJK>
+0x3949	0x80A1	# <CJK>
+0x394A	0x6545	# <CJK>
+0x394B	0x9867	# <CJK>
+0x394C	0x56FA	# <CJK>
+0x394D	0x96C7	# <CJK>
+0x394E	0x522E	# <CJK>
+0x394F	0x74DC	# <CJK>
+0x3950	0x526E	# <CJK>
+0x3951	0x5BE1	# <CJK>
+0x3952	0x6302	# <CJK>
+0x3953	0x8902	# <CJK>
+0x3954	0x4E56	# <CJK>
+0x3955	0x62D0	# <CJK>
+0x3956	0x602A	# <CJK>
+0x3957	0x68FA	# <CJK>
+0x3958	0x95DC	# <CJK>
+0x3959	0x5B98	# <CJK>
+0x395A	0x51A0	# <CJK>
+0x395B	0x89C0	# <CJK>
+0x395C	0x7BA1	# <CJK>
+0x395D	0x9928	# <CJK>
+0x395E	0x7F50	# <CJK>
+0x395F	0x6163	# <CJK>
+0x3960	0x704C	# <CJK>
+0x3961	0x8CAB	# <CJK>
+0x3962	0x5149	# <CJK>
+0x3963	0x5EE3	# <CJK>
+0x3964	0x901B	# <CJK>
+0x3965	0x7470	# <CJK>
+0x3966	0x898F	# <CJK>
+0x3967	0x572D	# <CJK>
+0x3968	0x7845	# <CJK>
+0x3969	0x6B78	# <CJK>
+0x396A	0x9F9C	# <CJK>
+0x396B	0x95A8	# <CJK>
+0x396C	0x8ECC	# <CJK>
+0x396D	0x9B3C	# <CJK>
+0x396E	0x8A6D	# <CJK>
+0x396F	0x7678	# <CJK>
+0x3970	0x6842	# <CJK>
+0x3971	0x6AC3	# <CJK>
+0x3972	0x8DEA	# <CJK>
+0x3973	0x8CB4	# <CJK>
+0x3974	0x528A	# <CJK>
+0x3975	0x8F25	# <CJK>
+0x3976	0x6EDA	# <CJK>
+0x3977	0x68CD	# <CJK>
+0x3978	0x934B	# <CJK>
+0x3979	0x90ED	# <CJK>
+0x397A	0x570B	# <CJK>
+0x397B	0x679C	# <CJK>
+0x397C	0x88F9	# <CJK>
+0x397D	0x904E	# <CJK>
+0x397E	0x54C8	# <CJK>
+0x3A21	0x9AB8	# <CJK>
+0x3A22	0x5B69	# <CJK>
+0x3A23	0x6D77	# <CJK>
+0x3A24	0x6C26	# <CJK>
+0x3A25	0x4EA5	# <CJK>
+0x3A26	0x5BB3	# <CJK>
+0x3A27	0x99ED	# <CJK>
+0x3A28	0x9163	# <CJK>
+0x3A29	0x61A8	# <CJK>
+0x3A2A	0x90AF	# <CJK>
+0x3A2B	0x97D3	# <CJK>
+0x3A2C	0x542B	# <CJK>
+0x3A2D	0x6DB5	# <CJK>
+0x3A2E	0x5BD2	# <CJK>
+0x3A2F	0x51FD	# <CJK>
+0x3A30	0x558A	# <CJK>
+0x3A31	0x7F55	# <CJK>
+0x3A32	0x7FF0	# <CJK>
+0x3A33	0x64BC	# <CJK>
+0x3A34	0x634D	# <CJK>
+0x3A35	0x65F1	# <CJK>
+0x3A36	0x61BE	# <CJK>
+0x3A37	0x608D	# <CJK>
+0x3A38	0x710A	# <CJK>
+0x3A39	0x6C57	# <CJK>
+0x3A3A	0x6F22	# <CJK>
+0x3A3B	0x592F	# <CJK>
+0x3A3C	0x676D	# <CJK>
+0x3A3D	0x822A	# <CJK>
+0x3A3E	0x58D5	# <CJK>
+0x3A3F	0x568E	# <CJK>
+0x3A40	0x8C6A	# <CJK>
+0x3A41	0x6BEB	# <CJK>
+0x3A42	0x90DD	# <CJK>
+0x3A43	0x597D	# <CJK>
+0x3A44	0x8017	# <CJK>
+0x3A45	0x865F	# <CJK>
+0x3A46	0x6D69	# <CJK>
+0x3A47	0x5475	# <CJK>
+0x3A48	0x559D	# <CJK>
+0x3A49	0x8377	# <CJK>
+0x3A4A	0x83CF	# <CJK>
+0x3A4B	0x6838	# <CJK>
+0x3A4C	0x79BE	# <CJK>
+0x3A4D	0x548C	# <CJK>
+0x3A4E	0x4F55	# <CJK>
+0x3A4F	0x5408	# <CJK>
+0x3A50	0x76D2	# <CJK>
+0x3A51	0x8C89	# <CJK>
+0x3A52	0x95A1	# <CJK>
+0x3A53	0x6CB3	# <CJK>
+0x3A54	0x6DB8	# <CJK>
+0x3A55	0x8D6B	# <CJK>
+0x3A56	0x8910	# <CJK>
+0x3A57	0x9DB4	# <CJK>
+0x3A58	0x8CC0	# <CJK>
+0x3A59	0x563F	# <CJK>
+0x3A5A	0x9ED1	# <CJK>
+0x3A5B	0x75D5	# <CJK>
+0x3A5C	0x5F88	# <CJK>
+0x3A5D	0x72E0	# <CJK>
+0x3A5E	0x6068	# <CJK>
+0x3A5F	0x54FC	# <CJK>
+0x3A60	0x4EA8	# <CJK>
+0x3A61	0x6A2A	# <CJK>
+0x3A62	0x8861	# <CJK>
+0x3A63	0x6052	# <CJK>
+0x3A64	0x8F5F	# <CJK>
+0x3A65	0x54C4	# <CJK>
+0x3A66	0x70D8	# <CJK>
+0x3A67	0x8679	# <CJK>
+0x3A68	0x9D3B	# <CJK>
+0x3A69	0x6D2A	# <CJK>
+0x3A6A	0x5B8F	# <CJK>
+0x3A6B	0x5F18	# <CJK>
+0x3A6C	0x7D05	# <CJK>
+0x3A6D	0x5589	# <CJK>
+0x3A6E	0x4FAF	# <CJK>
+0x3A6F	0x7334	# <CJK>
+0x3A70	0x543C	# <CJK>
+0x3A71	0x539A	# <CJK>
+0x3A72	0x5019	# <CJK>
+0x3A73	0x5F8C	# <CJK>
+0x3A74	0x547C	# <CJK>
+0x3A75	0x4E4E	# <CJK>
+0x3A76	0x5FFD	# <CJK>
+0x3A77	0x745A	# <CJK>
+0x3A78	0x58FA	# <CJK>
+0x3A79	0x846B	# <CJK>
+0x3A7A	0x80E1	# <CJK>
+0x3A7B	0x8774	# <CJK>
+0x3A7C	0x72D0	# <CJK>
+0x3A7D	0x7CCA	# <CJK>
+0x3A7E	0x6E56	# <CJK>
+0x3B21	0x5F27	# <CJK>
+0x3B22	0x864E	# <CJK>
+0x3B23	0x552C	# <CJK>
+0x3B24	0x8B77	# <CJK>
+0x3B25	0x4E92	# <CJK>
+0x3B26	0x6EEC	# <CJK>
+0x3B27	0x6237	# <CJK>
+0x3B28	0x82B1	# <CJK>
+0x3B29	0x5629	# <CJK>
+0x3B2A	0x83EF	# <CJK>
+0x3B2B	0x733E	# <CJK>
+0x3B2C	0x6ED1	# <CJK>
+0x3B2D	0x756B	# <CJK>
+0x3B2E	0x5283	# <CJK>
+0x3B2F	0x5316	# <CJK>
+0x3B30	0x8A71	# <CJK>
+0x3B31	0x69D0	# <CJK>
+0x3B32	0x5F8A	# <CJK>
+0x3B33	0x61F7	# <CJK>
+0x3B34	0x6DEE	# <CJK>
+0x3B35	0x58DE	# <CJK>
+0x3B36	0x6B61	# <CJK>
+0x3B37	0x74B0	# <CJK>
+0x3B38	0x6853	# <CJK>
+0x3B39	0x9084	# <CJK>
+0x3B3A	0x7DE9	# <CJK>
+0x3B3B	0x63DB	# <CJK>
+0x3B3C	0x60A3	# <CJK>
+0x3B3D	0x559A	# <CJK>
+0x3B3E	0x7613	# <CJK>
+0x3B3F	0x8C62	# <CJK>
+0x3B40	0x7165	# <CJK>
+0x3B41	0x6E19	# <CJK>
+0x3B42	0x5BA6	# <CJK>
+0x3B43	0x5E7B	# <CJK>
+0x3B44	0x8352	# <CJK>
+0x3B45	0x614C	# <CJK>
+0x3B46	0x9EC4	# <CJK>
+0x3B47	0x78FA	# <CJK>
+0x3B48	0x8757	# <CJK>
+0x3B49	0x7C27	# <CJK>
+0x3B4A	0x7687	# <CJK>
+0x3B4B	0x51F0	# <CJK>
+0x3B4C	0x60F6	# <CJK>
+0x3B4D	0x714C	# <CJK>
+0x3B4E	0x6643	# <CJK>
+0x3B4F	0x5E4C	# <CJK>
+0x3B50	0x604D	# <CJK>
+0x3B51	0x8B0A	# <CJK>
+0x3B52	0x7070	# <CJK>
+0x3B53	0x63EE	# <CJK>
+0x3B54	0x8F1D	# <CJK>
+0x3B55	0x5FBD	# <CJK>
+0x3B56	0x6062	# <CJK>
+0x3B57	0x86D4	# <CJK>
+0x3B58	0x56DE	# <CJK>
+0x3B59	0x6BC1	# <CJK>
+0x3B5A	0x6094	# <CJK>
+0x3B5B	0x6167	# <CJK>
+0x3B5C	0x5349	# <CJK>
+0x3B5D	0x60E0	# <CJK>
+0x3B5E	0x6666	# <CJK>
+0x3B5F	0x8CC4	# <CJK>
+0x3B60	0x7A62	# <CJK>
+0x3B61	0x6703	# <CJK>
+0x3B62	0x71F4	# <CJK>
+0x3B63	0x532F	# <CJK>
+0x3B64	0x8AF1	# <CJK>
+0x3B65	0x8AA8	# <CJK>
+0x3B66	0x7E6A	# <CJK>
+0x3B67	0x8477	# <CJK>
+0x3B68	0x660F	# <CJK>
+0x3B69	0x5A5A	# <CJK>
+0x3B6A	0x9B42	# <CJK>
+0x3B6B	0x6E3E	# <CJK>
+0x3B6C	0x6DF7	# <CJK>
+0x3B6D	0x8C41	# <CJK>
+0x3B6E	0x6D3B	# <CJK>
+0x3B6F	0x4F19	# <CJK>
+0x3B70	0x706B	# <CJK>
+0x3B71	0x7372	# <CJK>
+0x3B72	0x6216	# <CJK>
+0x3B73	0x60D1	# <CJK>
+0x3B74	0x970D	# <CJK>
+0x3B75	0x8CA8	# <CJK>
+0x3B76	0x798D	# <CJK>
+0x3B77	0x64CA	# <CJK>
+0x3B78	0x573E	# <CJK>
+0x3B79	0x57FA	# <CJK>
+0x3B7A	0x6A5F	# <CJK>
+0x3B7B	0x7578	# <CJK>
+0x3B7C	0x7A3D	# <CJK>
+0x3B7D	0x7A4D	# <CJK>
+0x3B7E	0x7B95	# <CJK>
+0x3C21	0x808C	# <CJK>
+0x3C22	0x9951	# <CJK>
+0x3C23	0x8FF9	# <CJK>
+0x3C24	0x6FC0	# <CJK>
+0x3C25	0x8B4F	# <CJK>
+0x3C26	0x9DC4	# <CJK>
+0x3C27	0x59EC	# <CJK>
+0x3C28	0x7E3E	# <CJK>
+0x3C29	0x7DDD	# <CJK>
+0x3C2A	0x5409	# <CJK>
+0x3C2B	0x6975	# <CJK>
+0x3C2C	0x68D8	# <CJK>
+0x3C2D	0x8F2F	# <CJK>
+0x3C2E	0x7C4D	# <CJK>
+0x3C2F	0x96C6	# <CJK>
+0x3C30	0x53CA	# <CJK>
+0x3C31	0x6025	# <CJK>
+0x3C32	0x75BE	# <CJK>
+0x3C33	0x6C72	# <CJK>
+0x3C34	0x5373	# <CJK>
+0x3C35	0x5AC9	# <CJK>
+0x3C36	0x7D1A	# <CJK>
+0x3C37	0x64E0	# <CJK>
+0x3C38	0x5E7E	# <CJK>
+0x3C39	0x810A	# <CJK>
+0x3C3A	0x5DF1	# <CJK>
+0x3C3B	0x858A	# <CJK>
+0x3C3C	0x6280	# <CJK>
+0x3C3D	0x5180	# <CJK>
+0x3C3E	0x5B63	# <CJK>
+0x3C3F	0x4F0E	# <CJK>
+0x3C40	0x796D	# <CJK>
+0x3C41	0x5291	# <CJK>
+0x3C42	0x60B8	# <CJK>
+0x3C43	0x6FDF	# <CJK>
+0x3C44	0x5BC4	# <CJK>
+0x3C45	0x5BC2	# <CJK>
+0x3C46	0x8A08	# <CJK>
+0x3C47	0x8A18	# <CJK>
+0x3C48	0x65E2	# <CJK>
+0x3C49	0x5FCC	# <CJK>
+0x3C4A	0x969B	# <CJK>
+0x3C4B	0x5993	# <CJK>
+0x3C4C	0x7E7C	# <CJK>
+0x3C4D	0x7D00	# <CJK>
+0x3C4E	0x5609	# <CJK>
+0x3C4F	0x67B7	# <CJK>
+0x3C50	0x593E	# <CJK>
+0x3C51	0x4F73	# <CJK>
+0x3C52	0x5BB6	# <CJK>
+0x3C53	0x52A0	# <CJK>
+0x3C54	0x83A2	# <CJK>
+0x3C55	0x9830	# <CJK>
+0x3C56	0x8CC8	# <CJK>
+0x3C57	0x7532	# <CJK>
+0x3C58	0x9240	# <CJK>
+0x3C59	0x5047	# <CJK>
+0x3C5A	0x7A3C	# <CJK>
+0x3C5B	0x50F9	# <CJK>
+0x3C5C	0x67B6	# <CJK>
+0x3C5D	0x99D5	# <CJK>
+0x3C5E	0x5AC1	# <CJK>
+0x3C5F	0x6BB2	# <CJK>
+0x3C60	0x76E3	# <CJK>
+0x3C61	0x5805	# <CJK>
+0x3C62	0x5C16	# <CJK>
+0x3C63	0x7B8B	# <CJK>
+0x3C64	0x9593	# <CJK>
+0x3C65	0x714E	# <CJK>
+0x3C66	0x517C	# <CJK>
+0x3C67	0x80A9	# <CJK>
+0x3C68	0x8271	# <CJK>
+0x3C69	0x5978	# <CJK>
+0x3C6A	0x7DD8	# <CJK>
+0x3C6B	0x7E6D	# <CJK>
+0x3C6C	0x6AA2	# <CJK>
+0x3C6D	0x67EC	# <CJK>
+0x3C6E	0x78B1	# <CJK>
+0x3C6F	0x9E7C	# <CJK>
+0x3C70	0x63C0	# <CJK>
+0x3C71	0x64BF	# <CJK>
+0x3C72	0x7C21	# <CJK>
+0x3C73	0x5109	# <CJK>
+0x3C74	0x526A	# <CJK>
+0x3C75	0x51CF	# <CJK>
+0x3C76	0x85A6	# <CJK>
+0x3C77	0x6ABB	# <CJK>
+0x3C78	0x9452	# <CJK>
+0x3C79	0x8E10	# <CJK>
+0x3C7A	0x8CE4	# <CJK>
+0x3C7B	0x898B	# <CJK>
+0x3C7C	0x9375	# <CJK>
+0x3C7D	0x7BAD	# <CJK>
+0x3C7E	0x4EF6	# <CJK>
+0x3D21	0x5065	# <CJK>
+0x3D22	0x8266	# <CJK>
+0x3D23	0x528D	# <CJK>
+0x3D24	0x991E	# <CJK>
+0x3D25	0x6F38	# <CJK>
+0x3D26	0x6FFA	# <CJK>
+0x3D27	0x6F97	# <CJK>
+0x3D28	0x5EFA	# <CJK>
+0x3D29	0x50F5	# <CJK>
+0x3D2A	0x59DC	# <CJK>
+0x3D2B	0x5C07	# <CJK>
+0x3D2C	0x6F3F	# <CJK>
+0x3D2D	0x6C5F	# <CJK>
+0x3D2E	0x7586	# <CJK>
+0x3D2F	0x8523	# <CJK>
+0x3D30	0x69F3	# <CJK>
+0x3D31	0x596C	# <CJK>
+0x3D32	0x8B1B	# <CJK>
+0x3D33	0x5320	# <CJK>
+0x3D34	0x91AC	# <CJK>
+0x3D35	0x964D	# <CJK>
+0x3D36	0x8549	# <CJK>
+0x3D37	0x6912	# <CJK>
+0x3D38	0x7901	# <CJK>
+0x3D39	0x7126	# <CJK>
+0x3D3A	0x81A0	# <CJK>
+0x3D3B	0x4EA4	# <CJK>
+0x3D3C	0x90CA	# <CJK>
+0x3D3D	0x6F86	# <CJK>
+0x3D3E	0x9A55	# <CJK>
+0x3D3F	0x5B0C	# <CJK>
+0x3D40	0x56BC	# <CJK>
+0x3D41	0x652A	# <CJK>
+0x3D42	0x9278	# <CJK>
+0x3D43	0x77EF	# <CJK>
+0x3D44	0x50E5	# <CJK>
+0x3D45	0x811A	# <CJK>
+0x3D46	0x72E1	# <CJK>
+0x3D47	0x89D2	# <CJK>
+0x3D48	0x9903	# <CJK>
+0x3D49	0x7E73	# <CJK>
+0x3D4A	0x7D5E	# <CJK>
+0x3D4B	0x527F	# <CJK>
+0x3D4C	0x6559	# <CJK>
+0x3D4D	0x9175	# <CJK>
+0x3D4E	0x8F4E	# <CJK>
+0x3D4F	0x8F03	# <CJK>
+0x3D50	0x53EB	# <CJK>
+0x3D51	0x7A96	# <CJK>
+0x3D52	0x63ED	# <CJK>
+0x3D53	0x63A5	# <CJK>
+0x3D54	0x7686	# <CJK>
+0x3D55	0x79F8	# <CJK>
+0x3D56	0x8857	# <CJK>
+0x3D57	0x968E	# <CJK>
+0x3D58	0x622A	# <CJK>
+0x3D59	0x52AB	# <CJK>
+0x3D5A	0x7BC0	# <CJK>
+0x3D5B	0x6854	# <CJK>
+0x3D5C	0x6770	# <CJK>
+0x3D5D	0x6377	# <CJK>
+0x3D5E	0x776B	# <CJK>
+0x3D5F	0x7AED	# <CJK>
+0x3D60	0x6F54	# <CJK>
+0x3D61	0x7D50	# <CJK>
+0x3D62	0x89E3	# <CJK>
+0x3D63	0x59D0	# <CJK>
+0x3D64	0x6212	# <CJK>
+0x3D65	0x85C9	# <CJK>
+0x3D66	0x82A5	# <CJK>
+0x3D67	0x754C	# <CJK>
+0x3D68	0x501F	# <CJK>
+0x3D69	0x4ECB	# <CJK>
+0x3D6A	0x75A5	# <CJK>
+0x3D6B	0x8AA1	# <CJK>
+0x3D6C	0x5C4A	# <CJK>
+0x3D6D	0x5DFE	# <CJK>
+0x3D6E	0x7B4B	# <CJK>
+0x3D6F	0x65A4	# <CJK>
+0x3D70	0x91D1	# <CJK>
+0x3D71	0x4ECA	# <CJK>
+0x3D72	0x6D25	# <CJK>
+0x3D73	0x895F	# <CJK>
+0x3D74	0x7DCA	# <CJK>
+0x3D75	0x9326	# <CJK>
+0x3D76	0x50C5	# <CJK>
+0x3D77	0x8B39	# <CJK>
+0x3D78	0x9032	# <CJK>
+0x3D79	0x9773	# <CJK>
+0x3D7A	0x6649	# <CJK>
+0x3D7B	0x7981	# <CJK>
+0x3D7C	0x8FD1	# <CJK>
+0x3D7D	0x71FC	# <CJK>
+0x3D7E	0x6D78	# <CJK>
+0x3E21	0x76E1	# <CJK>
+0x3E22	0x52C1	# <CJK>
+0x3E23	0x8346	# <CJK>
+0x3E24	0x5162	# <CJK>
+0x3E25	0x8396	# <CJK>
+0x3E26	0x775B	# <CJK>
+0x3E27	0x6676	# <CJK>
+0x3E28	0x9BE8	# <CJK>
+0x3E29	0x4EAC	# <CJK>
+0x3E2A	0x9A5A	# <CJK>
+0x3E2B	0x7CBE	# <CJK>
+0x3E2C	0x7CB3	# <CJK>
+0x3E2D	0x7D93	# <CJK>
+0x3E2E	0x4E95	# <CJK>
+0x3E2F	0x8B66	# <CJK>
+0x3E30	0x666F	# <CJK>
+0x3E31	0x9838	# <CJK>
+0x3E32	0x975C	# <CJK>
+0x3E33	0x5883	# <CJK>
+0x3E34	0x656C	# <CJK>
+0x3E35	0x93E1	# <CJK>
+0x3E36	0x5F91	# <CJK>
+0x3E37	0x75D9	# <CJK>
+0x3E38	0x9756	# <CJK>
+0x3E39	0x7ADF	# <CJK>
+0x3E3A	0x7AF6	# <CJK>
+0x3E3B	0x51C8	# <CJK>
+0x3E3C	0x70AF	# <CJK>
+0x3E3D	0x7A98	# <CJK>
+0x3E3E	0x63EA	# <CJK>
+0x3E3F	0x7A76	# <CJK>
+0x3E40	0x7CFE	# <CJK>
+0x3E41	0x7396	# <CJK>
+0x3E42	0x97ED	# <CJK>
+0x3E43	0x4E45	# <CJK>
+0x3E44	0x7078	# <CJK>
+0x3E45	0x4E5D	# <CJK>
+0x3E46	0x9152	# <CJK>
+0x3E47	0x53A9	# <CJK>
+0x3E48	0x6551	# <CJK>
+0x3E49	0x820A	# <CJK>
+0x3E4A	0x81FC	# <CJK>
+0x3E4B	0x8205	# <CJK>
+0x3E4C	0x548E	# <CJK>
+0x3E4D	0x5C31	# <CJK>
+0x3E4E	0x759A	# <CJK>
+0x3E4F	0x97A0	# <CJK>
+0x3E50	0x62D8	# <CJK>
+0x3E51	0x72D9	# <CJK>
+0x3E52	0x75BD	# <CJK>
+0x3E53	0x5C45	# <CJK>
+0x3E54	0x99D2	# <CJK>
+0x3E55	0x83CA	# <CJK>
+0x3E56	0x5C40	# <CJK>
+0x3E57	0x5480	# <CJK>
+0x3E58	0x77E9	# <CJK>
+0x3E59	0x8209	# <CJK>
+0x3E5A	0x6CAE	# <CJK>
+0x3E5B	0x805A	# <CJK>
+0x3E5C	0x62D2	# <CJK>
+0x3E5D	0x64DA	# <CJK>
+0x3E5E	0x5DE8	# <CJK>
+0x3E5F	0x5177	# <CJK>
+0x3E60	0x8DDD	# <CJK>
+0x3E61	0x8E1E	# <CJK>
+0x3E62	0x92F8	# <CJK>
+0x3E63	0x4FF1	# <CJK>
+0x3E64	0x53E5	# <CJK>
+0x3E65	0x61FC	# <CJK>
+0x3E66	0x70AC	# <CJK>
+0x3E67	0x5287	# <CJK>
+0x3E68	0x6350	# <CJK>
+0x3E69	0x9D51	# <CJK>
+0x3E6A	0x5A1F	# <CJK>
+0x3E6B	0x5026	# <CJK>
+0x3E6C	0x7737	# <CJK>
+0x3E6D	0x5377	# <CJK>
+0x3E6E	0x7D79	# <CJK>
+0x3E6F	0x6485	# <CJK>
+0x3E70	0x652B	# <CJK>
+0x3E71	0x6289	# <CJK>
+0x3E72	0x6398	# <CJK>
+0x3E73	0x5014	# <CJK>
+0x3E74	0x7235	# <CJK>
+0x3E75	0x89BA	# <CJK>
+0x3E76	0x51B3	# <CJK>
+0x3E77	0x8A23	# <CJK>
+0x3E78	0x7D76	# <CJK>
+0x3E79	0x5747	# <CJK>
+0x3E7A	0x83CC	# <CJK>
+0x3E7B	0x921E	# <CJK>
+0x3E7C	0x8ECD	# <CJK>
+0x3E7D	0x541B	# <CJK>
+0x3E7E	0x5CFB	# <CJK>
+0x3F21	0x4FCA	# <CJK>
+0x3F22	0x7AE3	# <CJK>
+0x3F23	0x6D5A	# <CJK>
+0x3F24	0x90E1	# <CJK>
+0x3F25	0x99FF	# <CJK>
+0x3F26	0x5580	# <CJK>
+0x3F27	0x5496	# <CJK>
+0x3F28	0x5361	# <CJK>
+0x3F29	0x54AF	# <CJK>
+0x3F2A	0x958B	# <CJK>
+0x3F2B	0x63E9	# <CJK>
+0x3F2C	0x6977	# <CJK>
+0x3F2D	0x51F1	# <CJK>
+0x3F2E	0x6168	# <CJK>
+0x3F2F	0x520A	# <CJK>
+0x3F30	0x582A	# <CJK>
+0x3F31	0x52D8	# <CJK>
+0x3F32	0x574E	# <CJK>
+0x3F33	0x780D	# <CJK>
+0x3F34	0x770B	# <CJK>
+0x3F35	0x5EB7	# <CJK>
+0x3F36	0x6177	# <CJK>
+0x3F37	0x7CE0	# <CJK>
+0x3F38	0x625B	# <CJK>
+0x3F39	0x6297	# <CJK>
+0x3F3A	0x4EA2	# <CJK>
+0x3F3B	0x7095	# <CJK>
+0x3F3C	0x8003	# <CJK>
+0x3F3D	0x62F7	# <CJK>
+0x3F3E	0x70E4	# <CJK>
+0x3F3F	0x9760	# <CJK>
+0x3F40	0x5777	# <CJK>
+0x3F41	0x82DB	# <CJK>
+0x3F42	0x67EF	# <CJK>
+0x3F43	0x68F5	# <CJK>
+0x3F44	0x78D5	# <CJK>
+0x3F45	0x9846	# <CJK>
+0x3F46	0x79D1	# <CJK>
+0x3F47	0x6BBB	# <CJK>
+0x3F48	0x54B3	# <CJK>
+0x3F49	0x53EF	# <CJK>
+0x3F4A	0x6E34	# <CJK>
+0x3F4B	0x514B	# <CJK>
+0x3F4C	0x523B	# <CJK>
+0x3F4D	0x5BA2	# <CJK>
+0x3F4E	0x8AB2	# <CJK>
+0x3F4F	0x80AF	# <CJK>
+0x3F50	0x5543	# <CJK>
+0x3F51	0x58BE	# <CJK>
+0x3F52	0x61C7	# <CJK>
+0x3F53	0x5751	# <CJK>
+0x3F54	0x542D	# <CJK>
+0x3F55	0x7A7A	# <CJK>
+0x3F56	0x6050	# <CJK>
+0x3F57	0x5B54	# <CJK>
+0x3F58	0x63A7	# <CJK>
+0x3F59	0x6473	# <CJK>
+0x3F5A	0x53E3	# <CJK>
+0x3F5B	0x6263	# <CJK>
+0x3F5C	0x5BC7	# <CJK>
+0x3F5D	0x67AF	# <CJK>
+0x3F5E	0x54ED	# <CJK>
+0x3F5F	0x7A9F	# <CJK>
+0x3F60	0x82E6	# <CJK>
+0x3F61	0x9177	# <CJK>
+0x3F62	0x5EAB	# <CJK>
+0x3F63	0x8932	# <CJK>
+0x3F64	0x8A87	# <CJK>
+0x3F65	0x57AE	# <CJK>
+0x3F66	0x630E	# <CJK>
+0x3F67	0x8DE8	# <CJK>
+0x3F68	0x80EF	# <CJK>
+0x3F69	0x584A	# <CJK>
+0x3F6A	0x7B77	# <CJK>
+0x3F6B	0x5108	# <CJK>
+0x3F6C	0x5FEB	# <CJK>
+0x3F6D	0x5BEC	# <CJK>
+0x3F6E	0x6B3E	# <CJK>
+0x3F6F	0x5321	# <CJK>
+0x3F70	0x7B50	# <CJK>
+0x3F71	0x72C2	# <CJK>
+0x3F72	0x6846	# <CJK>
+0x3F73	0x7926	# <CJK>
+0x3F74	0x7736	# <CJK>
+0x3F75	0x66E0	# <CJK>
+0x3F76	0x51B5	# <CJK>
+0x3F77	0x8667	# <CJK>
+0x3F78	0x76D4	# <CJK>
+0x3F79	0x5DCB	# <CJK>
+0x3F7A	0x7ABA	# <CJK>
+0x3F7B	0x8475	# <CJK>
+0x3F7C	0x594E	# <CJK>
+0x3F7D	0x9B41	# <CJK>
+0x3F7E	0x5080	# <CJK>
+0x4021	0x994B	# <CJK>
+0x4022	0x6127	# <CJK>
+0x4023	0x6F70	# <CJK>
+0x4024	0x5764	# <CJK>
+0x4025	0x6606	# <CJK>
+0x4026	0x6346	# <CJK>
+0x4027	0x56F0	# <CJK>
+0x4028	0x62EC	# <CJK>
+0x4029	0x64F4	# <CJK>
+0x402A	0x5ED3	# <CJK>
+0x402B	0x95CA	# <CJK>
+0x402C	0x5783	# <CJK>
+0x402D	0x62C9	# <CJK>
+0x402E	0x5587	# <CJK>
+0x402F	0x881F	# <CJK>
+0x4030	0x81D8	# <CJK>
+0x4031	0x8FA3	# <CJK>
+0x4032	0x5566	# <CJK>
+0x4033	0x840A	# <CJK>
+0x4034	0x4F86	# <CJK>
+0x4035	0x8CF4	# <CJK>
+0x4036	0x85CD	# <CJK>
+0x4037	0x5A6A	# <CJK>
+0x4038	0x6B04	# <CJK>
+0x4039	0x6514	# <CJK>
+0x403A	0x7C43	# <CJK>
+0x403B	0x95CC	# <CJK>
+0x403C	0x862D	# <CJK>
+0x403D	0x703E	# <CJK>
+0x403E	0x8B95	# <CJK>
+0x403F	0x652C	# <CJK>
+0x4040	0x89BD	# <CJK>
+0x4041	0x61F6	# <CJK>
+0x4042	0x7E9C	# <CJK>
+0x4043	0x721B	# <CJK>
+0x4044	0x6FEB	# <CJK>
+0x4045	0x7405	# <CJK>
+0x4046	0x6994	# <CJK>
+0x4047	0x72FC	# <CJK>
+0x4048	0x5ECA	# <CJK>
+0x4049	0x90CE	# <CJK>
+0x404A	0x6717	# <CJK>
+0x404B	0x6D6A	# <CJK>
+0x404C	0x6488	# <CJK>
+0x404D	0x52DE	# <CJK>
+0x404E	0x7262	# <CJK>
+0x404F	0x8001	# <CJK>
+0x4050	0x4F6C	# <CJK>
+0x4051	0x59E5	# <CJK>
+0x4052	0x916A	# <CJK>
+0x4053	0x70D9	# <CJK>
+0x4054	0x6F87	# <CJK>
+0x4055	0x52D2	# <CJK>
+0x4056	0x6A02	# <CJK>
+0x4057	0x96F7	# <CJK>
+0x4058	0x9433	# <CJK>
+0x4059	0x857E	# <CJK>
+0x405A	0x78CA	# <CJK>
+0x405B	0x7D2F	# <CJK>
+0x405C	0x5121	# <CJK>
+0x405D	0x58D8	# <CJK>
+0x405E	0x64C2	# <CJK>
+0x405F	0x808B	# <CJK>
+0x4060	0x985E	# <CJK>
+0x4061	0x6CEA	# <CJK>
+0x4062	0x68F1	# <CJK>
+0x4063	0x695E	# <CJK>
+0x4064	0x51B7	# <CJK>
+0x4065	0x5398	# <CJK>
+0x4066	0x68A8	# <CJK>
+0x4067	0x7281	# <CJK>
+0x4068	0x9ECE	# <CJK>
+0x4069	0x7C6C	# <CJK>
+0x406A	0x72F8	# <CJK>
+0x406B	0x96E2	# <CJK>
+0x406C	0x7055	# <CJK>
+0x406D	0x7406	# <CJK>
+0x406E	0x674E	# <CJK>
+0x406F	0x88CF	# <CJK>
+0x4070	0x9BC9	# <CJK>
+0x4071	0x79AE	# <CJK>
+0x4072	0x8389	# <CJK>
+0x4073	0x8354	# <CJK>
+0x4074	0x540F	# <CJK>
+0x4075	0x6817	# <CJK>
+0x4076	0x9E97	# <CJK>
+0x4077	0x53B2	# <CJK>
+0x4078	0x52F5	# <CJK>
+0x4079	0x792B	# <CJK>
+0x407A	0x6B77	# <CJK>
+0x407B	0x5229	# <CJK>
+0x407C	0x5088	# <CJK>
+0x407D	0x4F8B	# <CJK>
+0x407E	0x4FD0	# <CJK>
+0x4121	0x75E2	# <CJK>
+0x4122	0x7ACB	# <CJK>
+0x4123	0x7C92	# <CJK>
+0x4124	0x701D	# <CJK>
+0x4125	0x96B8	# <CJK>
+0x4126	0x529B	# <CJK>
+0x4127	0x7483	# <CJK>
+0x4128	0x54E9	# <CJK>
+0x4129	0x5006	# <CJK>
+0x412A	0x806F	# <CJK>
+0x412B	0x84EE	# <CJK>
+0x412C	0x9023	# <CJK>
+0x412D	0x942E	# <CJK>
+0x412E	0x5EC9	# <CJK>
+0x412F	0x6190	# <CJK>
+0x4130	0x6F23	# <CJK>
+0x4131	0x7C3E	# <CJK>
+0x4132	0x6582	# <CJK>
+0x4133	0x81C9	# <CJK>
+0x4134	0x93C8	# <CJK>
+0x4135	0x6200	# <CJK>
+0x4136	0x7149	# <CJK>
+0x4137	0x7DF4	# <CJK>
+0x4138	0x7CE7	# <CJK>
+0x4139	0x51C9	# <CJK>
+0x413A	0x6881	# <CJK>
+0x413B	0x7CB1	# <CJK>
+0x413C	0x826F	# <CJK>
+0x413D	0x5169	# <CJK>
+0x413E	0x8F1B	# <CJK>
+0x413F	0x91CF	# <CJK>
+0x4140	0x667E	# <CJK>
+0x4141	0x4EAE	# <CJK>
+0x4142	0x8AD2	# <CJK>
+0x4143	0x64A9	# <CJK>
+0x4144	0x804A	# <CJK>
+0x4145	0x50DA	# <CJK>
+0x4146	0x7642	# <CJK>
+0x4147	0x71CE	# <CJK>
+0x4148	0x5BE5	# <CJK>
+0x4149	0x907C	# <CJK>
+0x414A	0x6F66	# <CJK>
+0x414B	0x4E86	# <CJK>
+0x414C	0x6482	# <CJK>
+0x414D	0x9410	# <CJK>
+0x414E	0x5ED6	# <CJK>
+0x414F	0x6599	# <CJK>
+0x4150	0x5217	# <CJK>
+0x4151	0x88C2	# <CJK>
+0x4152	0x70C8	# <CJK>
+0x4153	0x52A3	# <CJK>
+0x4154	0x7375	# <CJK>
+0x4155	0x7433	# <CJK>
+0x4156	0x6797	# <CJK>
+0x4157	0x78F7	# <CJK>
+0x4158	0x9716	# <CJK>
+0x4159	0x81E8	# <CJK>
+0x415A	0x9130	# <CJK>
+0x415B	0x9C57	# <CJK>
+0x415C	0x6DCB	# <CJK>
+0x415D	0x51DB	# <CJK>
+0x415E	0x8CC3	# <CJK>
+0x415F	0x541D	# <CJK>
+0x4160	0x62CE	# <CJK>
+0x4161	0x73B2	# <CJK>
+0x4162	0x83F1	# <CJK>
+0x4163	0x96F6	# <CJK>
+0x4164	0x9F61	# <CJK>
+0x4165	0x9234	# <CJK>
+0x4166	0x4F36	# <CJK>
+0x4167	0x7F9A	# <CJK>
+0x4168	0x51CC	# <CJK>
+0x4169	0x9748	# <CJK>
+0x416A	0x9675	# <CJK>
+0x416B	0x5DBA	# <CJK>
+0x416C	0x9818	# <CJK>
+0x416D	0x53E6	# <CJK>
+0x416E	0x4EE4	# <CJK>
+0x416F	0x6E9C	# <CJK>
+0x4170	0x7409	# <CJK>
+0x4171	0x69B4	# <CJK>
+0x4172	0x786B	# <CJK>
+0x4173	0x993E	# <CJK>
+0x4174	0x7559	# <CJK>
+0x4175	0x5289	# <CJK>
+0x4176	0x7624	# <CJK>
+0x4177	0x6D41	# <CJK>
+0x4178	0x67F3	# <CJK>
+0x4179	0x516D	# <CJK>
+0x417A	0x9F8D	# <CJK>
+0x417B	0x807E	# <CJK>
+0x417C	0x56A8	# <CJK>
+0x417D	0x7C60	# <CJK>
+0x417E	0x7ABF	# <CJK>
+0x4221	0x9686	# <CJK>
+0x4222	0x58DF	# <CJK>
+0x4223	0x650F	# <CJK>
+0x4224	0x96B4	# <CJK>
+0x4225	0x6A13	# <CJK>
+0x4226	0x5A41	# <CJK>
+0x4227	0x645F	# <CJK>
+0x4228	0x7C0D	# <CJK>
+0x4229	0x6F0F	# <CJK>
+0x422A	0x964B	# <CJK>
+0x422B	0x8606	# <CJK>
+0x422C	0x76E7	# <CJK>
+0x422D	0x9871	# <CJK>
+0x422E	0x5EEC	# <CJK>
+0x422F	0x7210	# <CJK>
+0x4230	0x64C4	# <CJK>
+0x4231	0x6EF7	# <CJK>
+0x4232	0x865C	# <CJK>
+0x4233	0x9B6F	# <CJK>
+0x4234	0x9E93	# <CJK>
+0x4235	0x788C	# <CJK>
+0x4236	0x9732	# <CJK>
+0x4237	0x8DEF	# <CJK>
+0x4238	0x8CC2	# <CJK>
+0x4239	0x9E7F	# <CJK>
+0x423A	0x6F5E	# <CJK>
+0x423B	0x7984	# <CJK>
+0x423C	0x9332	# <CJK>
+0x423D	0x9678	# <CJK>
+0x423E	0x622E	# <CJK>
+0x423F	0x9A62	# <CJK>
+0x4240	0x5415	# <CJK>
+0x4241	0x92C1	# <CJK>
+0x4242	0x4FA3	# <CJK>
+0x4243	0x65C5	# <CJK>
+0x4244	0x5C65	# <CJK>
+0x4245	0x5C62	# <CJK>
+0x4246	0x7E37	# <CJK>
+0x4247	0x616E	# <CJK>
+0x4248	0x6C2F	# <CJK>
+0x4249	0x5F8B	# <CJK>
+0x424A	0x7387	# <CJK>
+0x424B	0x6FFE	# <CJK>
+0x424C	0x7DD1	# <CJK>
+0x424D	0x5DD2	# <CJK>
+0x424E	0x6523	# <CJK>
+0x424F	0x5B7F	# <CJK>
+0x4250	0x7064	# <CJK>
+0x4251	0x5375	# <CJK>
+0x4252	0x4E82	# <CJK>
+0x4253	0x63A0	# <CJK>
+0x4254	0x7565	# <CJK>
+0x4255	0x6384	# <CJK>
+0x4256	0x8F2A	# <CJK>
+0x4257	0x502B	# <CJK>
+0x4258	0x4F96	# <CJK>
+0x4259	0x6DEA	# <CJK>
+0x425A	0x7DB8	# <CJK>
+0x425B	0x8AD6	# <CJK>
+0x425C	0x863F	# <CJK>
+0x425D	0x87BA	# <CJK>
+0x425E	0x7F85	# <CJK>
+0x425F	0x908F	# <CJK>
+0x4260	0x947C	# <CJK>
+0x4261	0x7C6E	# <CJK>
+0x4262	0x9A3E	# <CJK>
+0x4263	0x88F8	# <CJK>
+0x4264	0x843D	# <CJK>
+0x4265	0x6D1B	# <CJK>
+0x4266	0x99F1	# <CJK>
+0x4267	0x7D61	# <CJK>
+0x4268	0x5ABD	# <CJK>
+0x4269	0x9EBB	# <CJK>
+0x426A	0x746A	# <CJK>
+0x426B	0x78BC	# <CJK>
+0x426C	0x879E	# <CJK>
+0x426D	0x99AC	# <CJK>
+0x426E	0x99E1	# <CJK>
+0x426F	0x561B	# <CJK>
+0x4270	0x55CE	# <CJK>
+0x4271	0x57CB	# <CJK>
+0x4272	0x8CB7	# <CJK>
+0x4273	0x9EA5	# <CJK>
+0x4274	0x8CE3	# <CJK>
+0x4275	0x9081	# <CJK>
+0x4276	0x8109	# <CJK>
+0x4277	0x779E	# <CJK>
+0x4278	0x9945	# <CJK>
+0x4279	0x883B	# <CJK>
+0x427A	0x6EFF	# <CJK>
+0x427B	0x8513	# <CJK>
+0x427C	0x66FC	# <CJK>
+0x427D	0x6162	# <CJK>
+0x427E	0x6F2B	# <CJK>
+0x4321	0x8B3E	# <CJK>
+0x4322	0x8292	# <CJK>
+0x4323	0x832B	# <CJK>
+0x4324	0x76F2	# <CJK>
+0x4325	0x6C13	# <CJK>
+0x4326	0x5FD9	# <CJK>
+0x4327	0x83BD	# <CJK>
+0x4328	0x732B	# <CJK>
+0x4329	0x8305	# <CJK>
+0x432A	0x9328	# <CJK>
+0x432B	0x6BDB	# <CJK>
+0x432C	0x77DB	# <CJK>
+0x432D	0x925A	# <CJK>
+0x432E	0x536F	# <CJK>
+0x432F	0x8302	# <CJK>
+0x4330	0x5192	# <CJK>
+0x4331	0x5E3D	# <CJK>
+0x4332	0x8C8C	# <CJK>
+0x4333	0x8CBF	# <CJK>
+0x4334	0x9EBD	# <CJK>
+0x4335	0x73AB	# <CJK>
+0x4336	0x679A	# <CJK>
+0x4337	0x6885	# <CJK>
+0x4338	0x9176	# <CJK>
+0x4339	0x9709	# <CJK>
+0x433A	0x7164	# <CJK>
+0x433B	0x6CA1	# <CJK>
+0x433C	0x7709	# <CJK>
+0x433D	0x5A92	# <CJK>
+0x433E	0x9382	# <CJK>
+0x433F	0x6BCF	# <CJK>
+0x4340	0x7F8E	# <CJK>
+0x4341	0x6627	# <CJK>
+0x4342	0x5BD0	# <CJK>
+0x4343	0x59B9	# <CJK>
+0x4344	0x5A9A	# <CJK>
+0x4345	0x9580	# <CJK>
+0x4346	0x60B6	# <CJK>
+0x4347	0x5011	# <CJK>
+0x4348	0x840C	# <CJK>
+0x4349	0x8499	# <CJK>
+0x434A	0x6AAC	# <CJK>
+0x434B	0x76DF	# <CJK>
+0x434C	0x9333	# <CJK>
+0x434D	0x731B	# <CJK>
+0x434E	0x5922	# <CJK>
+0x434F	0x5B5F	# <CJK>
+0x4350	0x772F	# <CJK>
+0x4351	0x919A	# <CJK>
+0x4352	0x9761	# <CJK>
+0x4353	0x7CDC	# <CJK>
+0x4354	0x8FF7	# <CJK>
+0x4355	0x8B0E	# <CJK>
+0x4356	0x5F4C	# <CJK>
+0x4357	0x7C73	# <CJK>
+0x4358	0x79D8	# <CJK>
+0x4359	0x8993	# <CJK>
+0x435A	0x6CCC	# <CJK>
+0x435B	0x871C	# <CJK>
+0x435C	0x5BC6	# <CJK>
+0x435D	0x5E42	# <CJK>
+0x435E	0x68C9	# <CJK>
+0x435F	0x7720	# <CJK>
+0x4360	0x7DBF	# <CJK>
+0x4361	0x5195	# <CJK>
+0x4362	0x514D	# <CJK>
+0x4363	0x52C9	# <CJK>
+0x4364	0x5A29	# <CJK>
+0x4365	0x7DEC	# <CJK>
+0x4366	0x9762	# <CJK>
+0x4367	0x82D7	# <CJK>
+0x4368	0x63CF	# <CJK>
+0x4369	0x7784	# <CJK>
+0x436A	0x85D0	# <CJK>
+0x436B	0x79D2	# <CJK>
+0x436C	0x6E3A	# <CJK>
+0x436D	0x5EDF	# <CJK>
+0x436E	0x5999	# <CJK>
+0x436F	0x8511	# <CJK>
+0x4370	0x6EC5	# <CJK>
+0x4371	0x6C11	# <CJK>
+0x4372	0x62BF	# <CJK>
+0x4373	0x76BF	# <CJK>
+0x4374	0x654F	# <CJK>
+0x4375	0x61AB	# <CJK>
+0x4376	0x95A9	# <CJK>
+0x4377	0x660E	# <CJK>
+0x4378	0x879F	# <CJK>
+0x4379	0x9CF4	# <CJK>
+0x437A	0x9298	# <CJK>
+0x437B	0x540D	# <CJK>
+0x437C	0x547D	# <CJK>
+0x437D	0x8B2C	# <CJK>
+0x437E	0x6478	# <CJK>
+0x4421	0x6479	# <CJK>
+0x4422	0x8611	# <CJK>
+0x4423	0x6A21	# <CJK>
+0x4424	0x819C	# <CJK>
+0x4425	0x78E8	# <CJK>
+0x4426	0x6469	# <CJK>
+0x4427	0x9B54	# <CJK>
+0x4428	0x62B9	# <CJK>
+0x4429	0x672B	# <CJK>
+0x442A	0x83AB	# <CJK>
+0x442B	0x58A8	# <CJK>
+0x442C	0x9ED8	# <CJK>
+0x442D	0x6CAB	# <CJK>
+0x442E	0x6F20	# <CJK>
+0x442F	0x5BDE	# <CJK>
+0x4430	0x964C	# <CJK>
+0x4431	0x8B00	# <CJK>
+0x4432	0x725F	# <CJK>
+0x4433	0x67D0	# <CJK>
+0x4434	0x62C7	# <CJK>
+0x4435	0x7261	# <CJK>
+0x4436	0x755D	# <CJK>
+0x4437	0x59C6	# <CJK>
+0x4438	0x6BCD	# <CJK>
+0x4439	0x5893	# <CJK>
+0x443A	0x66AE	# <CJK>
+0x443B	0x5E55	# <CJK>
+0x443C	0x52DF	# <CJK>
+0x443D	0x6155	# <CJK>
+0x443E	0x6728	# <CJK>
+0x443F	0x76EE	# <CJK>
+0x4440	0x7766	# <CJK>
+0x4441	0x7267	# <CJK>
+0x4442	0x7A46	# <CJK>
+0x4443	0x62FF	# <CJK>
+0x4444	0x54EA	# <CJK>
+0x4445	0x5450	# <CJK>
+0x4446	0x9209	# <CJK>
+0x4447	0x90A3	# <CJK>
+0x4448	0x5A1C	# <CJK>
+0x4449	0x7D0D	# <CJK>
+0x444A	0x6C16	# <CJK>
+0x444B	0x4E43	# <CJK>
+0x444C	0x5976	# <CJK>
+0x444D	0x8010	# <CJK>
+0x444E	0x5948	# <CJK>
+0x444F	0x5357	# <CJK>
+0x4450	0x7537	# <CJK>
+0x4451	0x96E3	# <CJK>
+0x4452	0x56CA	# <CJK>
+0x4453	0x6493	# <CJK>
+0x4454	0x8166	# <CJK>
+0x4455	0x60F1	# <CJK>
+0x4456	0x9B27	# <CJK>
+0x4457	0x6DD6	# <CJK>
+0x4458	0x5462	# <CJK>
+0x4459	0x9912	# <CJK>
+0x445A	0x5185	# <CJK>
+0x445B	0x5AE9	# <CJK>
+0x445C	0x80FD	# <CJK>
+0x445D	0x59AE	# <CJK>
+0x445E	0x9713	# <CJK>
+0x445F	0x502A	# <CJK>
+0x4460	0x6CE5	# <CJK>
+0x4461	0x5C3C	# <CJK>
+0x4462	0x64EC	# <CJK>
+0x4463	0x4F60	# <CJK>
+0x4464	0x533F	# <CJK>
+0x4465	0x81A9	# <CJK>
+0x4466	0x9006	# <CJK>
+0x4467	0x6EBA	# <CJK>
+0x4468	0x852B	# <CJK>
+0x4469	0x62C8	# <CJK>
+0x446A	0x5E74	# <CJK>
+0x446B	0x78BE	# <CJK>
+0x446C	0x6506	# <CJK>
+0x446D	0x637B	# <CJK>
+0x446E	0x5FF5	# <CJK>
+0x446F	0x5A18	# <CJK>
+0x4470	0x91C0	# <CJK>
+0x4471	0x9CE5	# <CJK>
+0x4472	0x5C3F	# <CJK>
+0x4473	0x634F	# <CJK>
+0x4474	0x8076	# <CJK>
+0x4475	0x5B7D	# <CJK>
+0x4476	0x5699	# <CJK>
+0x4477	0x9477	# <CJK>
+0x4478	0x93B3	# <CJK>
+0x4479	0x6D85	# <CJK>
+0x447A	0x60A8	# <CJK>
+0x447B	0x6AB8	# <CJK>
+0x447C	0x7370	# <CJK>
+0x447D	0x51DD	# <CJK>
+0x447E	0x5BE7	# <CJK>
+0x4521	0x64F0	# <CJK>
+0x4522	0x6FD8	# <CJK>
+0x4523	0x725B	# <CJK>
+0x4524	0x626D	# <CJK>
+0x4525	0x9215	# <CJK>
+0x4526	0x7D10	# <CJK>
+0x4527	0x81BF	# <CJK>
+0x4528	0x6FC3	# <CJK>
+0x4529	0x8FB2	# <CJK>
+0x452A	0x5F04	# <CJK>
+0x452B	0x5974	# <CJK>
+0x452C	0x52AA	# <CJK>
+0x452D	0x6012	# <CJK>
+0x452E	0x5973	# <CJK>
+0x452F	0x6696	# <CJK>
+0x4530	0x8650	# <CJK>
+0x4531	0x7627	# <CJK>
+0x4532	0x632A	# <CJK>
+0x4533	0x61E6	# <CJK>
+0x4534	0x7CEF	# <CJK>
+0x4535	0x8AFE	# <CJK>
+0x4536	0x54E6	# <CJK>
+0x4537	0x6B50	# <CJK>
+0x4538	0x9DD7	# <CJK>
+0x4539	0x6BC6	# <CJK>
+0x453A	0x85D5	# <CJK>
+0x453B	0x5614	# <CJK>
+0x453C	0x5076	# <CJK>
+0x453D	0x6F1A	# <CJK>
+0x453E	0x556A	# <CJK>
+0x453F	0x8DB4	# <CJK>
+0x4540	0x722C	# <CJK>
+0x4541	0x5E15	# <CJK>
+0x4542	0x6015	# <CJK>
+0x4543	0x7436	# <CJK>
+0x4544	0x62CD	# <CJK>
+0x4545	0x6392	# <CJK>
+0x4546	0x724C	# <CJK>
+0x4547	0x5F98	# <CJK>
+0x4548	0x6E43	# <CJK>
+0x4549	0x6D3E	# <CJK>
+0x454A	0x6500	# <CJK>
+0x454B	0x6F58	# <CJK>
+0x454C	0x76E4	# <CJK>
+0x454D	0x78D0	# <CJK>
+0x454E	0x76FC	# <CJK>
+0x454F	0x7554	# <CJK>
+0x4550	0x5224	# <CJK>
+0x4551	0x53DB	# <CJK>
+0x4552	0x4E53	# <CJK>
+0x4553	0x9F90	# <CJK>
+0x4554	0x65C1	# <CJK>
+0x4555	0x802A	# <CJK>
+0x4556	0x80D6	# <CJK>
+0x4557	0x629B	# <CJK>
+0x4558	0x5486	# <CJK>
+0x4559	0x5228	# <CJK>
+0x455A	0x70AE	# <CJK>
+0x455B	0x888D	# <CJK>
+0x455C	0x8DD1	# <CJK>
+0x455D	0x6CE1	# <CJK>
+0x455E	0x5478	# <CJK>
+0x455F	0x80DA	# <CJK>
+0x4560	0x57F9	# <CJK>
+0x4561	0x88F4	# <CJK>
+0x4562	0x8CE0	# <CJK>
+0x4563	0x966A	# <CJK>
+0x4564	0x914D	# <CJK>
+0x4565	0x4F69	# <CJK>
+0x4566	0x6C9B	# <CJK>
+0x4567	0x5674	# <CJK>
+0x4568	0x76C6	# <CJK>
+0x4569	0x7830	# <CJK>
+0x456A	0x62A8	# <CJK>
+0x456B	0x70F9	# <CJK>
+0x456C	0x6F8E	# <CJK>
+0x456D	0x5F6D	# <CJK>
+0x456E	0x84EC	# <CJK>
+0x456F	0x68DA	# <CJK>
+0x4570	0x787C	# <CJK>
+0x4571	0x7BF7	# <CJK>
+0x4572	0x81A8	# <CJK>
+0x4573	0x670B	# <CJK>
+0x4574	0x9D6C	# <CJK>
+0x4575	0x6367	# <CJK>
+0x4576	0x78B0	# <CJK>
+0x4577	0x576F	# <CJK>
+0x4578	0x7812	# <CJK>
+0x4579	0x9739	# <CJK>
+0x457A	0x6279	# <CJK>
+0x457B	0x62AB	# <CJK>
+0x457C	0x5288	# <CJK>
+0x457D	0x7435	# <CJK>
+0x457E	0x6BD7	# <CJK>
+0x4621	0x5564	# <CJK>
+0x4622	0x813E	# <CJK>
+0x4623	0x75B2	# <CJK>
+0x4624	0x76AE	# <CJK>
+0x4625	0x5339	# <CJK>
+0x4626	0x75DE	# <CJK>
+0x4627	0x50FB	# <CJK>
+0x4628	0x5C41	# <CJK>
+0x4629	0x8B6C	# <CJK>
+0x462A	0x7BC7	# <CJK>
+0x462B	0x504F	# <CJK>
+0x462C	0x7247	# <CJK>
+0x462D	0x9A19	# <CJK>
+0x462E	0x98C4	# <CJK>
+0x462F	0x6F02	# <CJK>
+0x4630	0x74E2	# <CJK>
+0x4631	0x7968	# <CJK>
+0x4632	0x6487	# <CJK>
+0x4633	0x77A5	# <CJK>
+0x4634	0x62FC	# <CJK>
+0x4635	0x983B	# <CJK>
+0x4636	0x8CA7	# <CJK>
+0x4637	0x54C1	# <CJK>
+0x4638	0x8058	# <CJK>
+0x4639	0x4E52	# <CJK>
+0x463A	0x576A	# <CJK>
+0x463B	0x860B	# <CJK>
+0x463C	0x840D	# <CJK>
+0x463D	0x5E73	# <CJK>
+0x463E	0x6191	# <CJK>
+0x463F	0x74F6	# <CJK>
+0x4640	0x8A55	# <CJK>
+0x4641	0x5C4F	# <CJK>
+0x4642	0x5761	# <CJK>
+0x4643	0x6F51	# <CJK>
+0x4644	0x9817	# <CJK>
+0x4645	0x5A46	# <CJK>
+0x4646	0x7834	# <CJK>
+0x4647	0x9B44	# <CJK>
+0x4648	0x8FEB	# <CJK>
+0x4649	0x7C95	# <CJK>
+0x464A	0x5256	# <CJK>
+0x464B	0x64B2	# <CJK>
+0x464C	0x92EA	# <CJK>
+0x464D	0x50D5	# <CJK>
+0x464E	0x8386	# <CJK>
+0x464F	0x8461	# <CJK>
+0x4650	0x83E9	# <CJK>
+0x4651	0x84B2	# <CJK>
+0x4652	0x57D4	# <CJK>
+0x4653	0x6A38	# <CJK>
+0x4654	0x5703	# <CJK>
+0x4655	0x666E	# <CJK>
+0x4656	0x6D66	# <CJK>
+0x4657	0x8B5C	# <CJK>
+0x4658	0x66DD	# <CJK>
+0x4659	0x7011	# <CJK>
+0x465A	0x671F	# <CJK>
+0x465B	0x6B3A	# <CJK>
+0x465C	0x68F2	# <CJK>
+0x465D	0x621A	# <CJK>
+0x465E	0x59BB	# <CJK>
+0x465F	0x4E03	# <CJK>
+0x4660	0x51C4	# <CJK>
+0x4661	0x6F06	# <CJK>
+0x4662	0x67D2	# <CJK>
+0x4663	0x6C8F	# <CJK>
+0x4664	0x5176	# <CJK>
+0x4665	0x68CB	# <CJK>
+0x4666	0x5947	# <CJK>
+0x4667	0x6B67	# <CJK>
+0x4668	0x7566	# <CJK>
+0x4669	0x5D0E	# <CJK>
+0x466A	0x81CD	# <CJK>
+0x466B	0x9F4A	# <CJK>
+0x466C	0x65D7	# <CJK>
+0x466D	0x7948	# <CJK>
+0x466E	0x7941	# <CJK>
+0x466F	0x9A0E	# <CJK>
+0x4670	0x8D77	# <CJK>
+0x4671	0x8C48	# <CJK>
+0x4672	0x4E5E	# <CJK>
+0x4673	0x4F01	# <CJK>
+0x4674	0x5553	# <CJK>
+0x4675	0x5951	# <CJK>
+0x4676	0x780C	# <CJK>
+0x4677	0x5668	# <CJK>
+0x4678	0x6C23	# <CJK>
+0x4679	0x8FC4	# <CJK>
+0x467A	0x68C4	# <CJK>
+0x467B	0x6C7D	# <CJK>
+0x467C	0x6CE3	# <CJK>
+0x467D	0x8A16	# <CJK>
+0x467E	0x6390	# <CJK>
+0x4721	0x6070	# <CJK>
+0x4722	0x6D3D	# <CJK>
+0x4723	0x727D	# <CJK>
+0x4724	0x6266	# <CJK>
+0x4725	0x91FA	# <CJK>
+0x4726	0x925B	# <CJK>
+0x4727	0x5343	# <CJK>
+0x4728	0x9077	# <CJK>
+0x4729	0x7C3D	# <CJK>
+0x472A	0x4EDF	# <CJK>
+0x472B	0x8B19	# <CJK>
+0x472C	0x4E7E	# <CJK>
+0x472D	0x9ED4	# <CJK>
+0x472E	0x9322	# <CJK>
+0x472F	0x9257	# <CJK>
+0x4730	0x524D	# <CJK>
+0x4731	0x6F5B	# <CJK>
+0x4732	0x9063	# <CJK>
+0x4733	0x6DFA	# <CJK>
+0x4734	0x8B74	# <CJK>
+0x4735	0x5879	# <CJK>
+0x4736	0x5D4C	# <CJK>
+0x4737	0x6B20	# <CJK>
+0x4738	0x6B49	# <CJK>
+0x4739	0x69CD	# <CJK>
+0x473A	0x55C6	# <CJK>
+0x473B	0x8154	# <CJK>
+0x473C	0x7F8C	# <CJK>
+0x473D	0x58BB	# <CJK>
+0x473E	0x8594	# <CJK>
+0x473F	0x5F3A	# <CJK>
+0x4740	0x6436	# <CJK>
+0x4741	0x6A47	# <CJK>
+0x4742	0x936C	# <CJK>
+0x4743	0x6572	# <CJK>
+0x4744	0x6084	# <CJK>
+0x4745	0x6A4B	# <CJK>
+0x4746	0x77A7	# <CJK>
+0x4747	0x55AC	# <CJK>
+0x4748	0x50D1	# <CJK>
+0x4749	0x5DE7	# <CJK>
+0x474A	0x9798	# <CJK>
+0x474B	0x64AC	# <CJK>
+0x474C	0x7FF9	# <CJK>
+0x474D	0x5CED	# <CJK>
+0x474E	0x4FCF	# <CJK>
+0x474F	0x7AC5	# <CJK>
+0x4750	0x5207	# <CJK>
+0x4751	0x8304	# <CJK>
+0x4752	0x4E14	# <CJK>
+0x4753	0x602F	# <CJK>
+0x4754	0x7ACA	# <CJK>
+0x4755	0x6B3D	# <CJK>
+0x4756	0x4FB5	# <CJK>
+0x4757	0x89AA	# <CJK>
+0x4758	0x79E6	# <CJK>
+0x4759	0x7434	# <CJK>
+0x475A	0x52E4	# <CJK>
+0x475B	0x82B9	# <CJK>
+0x475C	0x64D2	# <CJK>
+0x475D	0x79BD	# <CJK>
+0x475E	0x5BE2	# <CJK>
+0x475F	0x6C81	# <CJK>
+0x4760	0x9752	# <CJK>
+0x4761	0x8F15	# <CJK>
+0x4762	0x6C2B	# <CJK>
+0x4763	0x50BE	# <CJK>
+0x4764	0x537F	# <CJK>
+0x4765	0x6E05	# <CJK>
+0x4766	0x64CE	# <CJK>
+0x4767	0x6674	# <CJK>
+0x4768	0x6C30	# <CJK>
+0x4769	0x60C5	# <CJK>
+0x476A	0x9803	# <CJK>
+0x476B	0x8ACB	# <CJK>
+0x476C	0x6176	# <CJK>
+0x476D	0x74CA	# <CJK>
+0x476E	0x7AAE	# <CJK>
+0x476F	0x79CB	# <CJK>
+0x4770	0x4E18	# <CJK>
+0x4771	0x90B1	# <CJK>
+0x4772	0x7403	# <CJK>
+0x4773	0x6C42	# <CJK>
+0x4774	0x56DA	# <CJK>
+0x4775	0x914B	# <CJK>
+0x4776	0x6CC5	# <CJK>
+0x4777	0x8DA8	# <CJK>
+0x4778	0x5340	# <CJK>
+0x4779	0x86C6	# <CJK>
+0x477A	0x66F2	# <CJK>
+0x477B	0x8EC0	# <CJK>
+0x477C	0x5C48	# <CJK>
+0x477D	0x9A45	# <CJK>
+0x477E	0x6E20	# <CJK>
+0x4821	0x53D6	# <CJK>
+0x4822	0x5A36	# <CJK>
+0x4823	0x9F72	# <CJK>
+0x4824	0x8DA3	# <CJK>
+0x4825	0x53BB	# <CJK>
+0x4826	0x5708	# <CJK>
+0x4827	0x9874	# <CJK>
+0x4828	0x6B0A	# <CJK>
+0x4829	0x919B	# <CJK>
+0x482A	0x6CC9	# <CJK>
+0x482B	0x5168	# <CJK>
+0x482C	0x75CA	# <CJK>
+0x482D	0x62F3	# <CJK>
+0x482E	0x72AC	# <CJK>
+0x482F	0x5238	# <CJK>
+0x4830	0x52F8	# <CJK>
+0x4831	0x7F3A	# <CJK>
+0x4832	0x7094	# <CJK>
+0x4833	0x7638	# <CJK>
+0x4834	0x5374	# <CJK>
+0x4835	0x9D72	# <CJK>
+0x4836	0x69B7	# <CJK>
+0x4837	0x78BA	# <CJK>
+0x4838	0x96C0	# <CJK>
+0x4839	0x88D9	# <CJK>
+0x483A	0x7FA4	# <CJK>
+0x483B	0x7136	# <CJK>
+0x483C	0x71C3	# <CJK>
+0x483D	0x5189	# <CJK>
+0x483E	0x67D3	# <CJK>
+0x483F	0x74E4	# <CJK>
+0x4840	0x58E4	# <CJK>
+0x4841	0x6518	# <CJK>
+0x4842	0x56B7	# <CJK>
+0x4843	0x8B93	# <CJK>
+0x4844	0x9952	# <CJK>
+0x4845	0x64FE	# <CJK>
+0x4846	0x7E5E	# <CJK>
+0x4847	0x60F9	# <CJK>
+0x4848	0x71B1	# <CJK>
+0x4849	0x58EC	# <CJK>
+0x484A	0x4EC1	# <CJK>
+0x484B	0x4EBA	# <CJK>
+0x484C	0x5FCD	# <CJK>
+0x484D	0x97CC	# <CJK>
+0x484E	0x4EFB	# <CJK>
+0x484F	0x8A8D	# <CJK>
+0x4850	0x5203	# <CJK>
+0x4851	0x598A	# <CJK>
+0x4852	0x7D09	# <CJK>
+0x4853	0x6254	# <CJK>
+0x4854	0x4ECD	# <CJK>
+0x4855	0x65E5	# <CJK>
+0x4856	0x620E	# <CJK>
+0x4857	0x8338	# <CJK>
+0x4858	0x84C9	# <CJK>
+0x4859	0x69AE	# <CJK>
+0x485A	0x878D	# <CJK>
+0x485B	0x7194	# <CJK>
+0x485C	0x6EB6	# <CJK>
+0x485D	0x5BB9	# <CJK>
+0x485E	0x7D68	# <CJK>
+0x485F	0x5197	# <CJK>
+0x4860	0x63C9	# <CJK>
+0x4861	0x67D4	# <CJK>
+0x4862	0x8089	# <CJK>
+0x4863	0x8339	# <CJK>
+0x4864	0x8815	# <CJK>
+0x4865	0x5112	# <CJK>
+0x4866	0x5B7A	# <CJK>
+0x4867	0x5982	# <CJK>
+0x4868	0x8FB1	# <CJK>
+0x4869	0x4E73	# <CJK>
+0x486A	0x6C5D	# <CJK>
+0x486B	0x5165	# <CJK>
+0x486C	0x8925	# <CJK>
+0x486D	0x8EDF	# <CJK>
+0x486E	0x962E	# <CJK>
+0x486F	0x854A	# <CJK>
+0x4870	0x745E	# <CJK>
+0x4871	0x92ED	# <CJK>
+0x4872	0x958F	# <CJK>
+0x4873	0x6F64	# <CJK>
+0x4874	0x82E5	# <CJK>
+0x4875	0x5F31	# <CJK>
+0x4876	0x6492	# <CJK>
+0x4877	0x7051	# <CJK>
+0x4878	0x85A9	# <CJK>
+0x4879	0x816E	# <CJK>
+0x487A	0x9C13	# <CJK>
+0x487B	0x585E	# <CJK>
+0x487C	0x8CFD	# <CJK>
+0x487D	0x4E09	# <CJK>
+0x487E	0x53C1	# <CJK>
+0x4921	0x5098	# <CJK>
+0x4922	0x6563	# <CJK>
+0x4923	0x6851	# <CJK>
+0x4924	0x55D3	# <CJK>
+0x4925	0x55AA	# <CJK>
+0x4926	0x6414	# <CJK>
+0x4927	0x9A37	# <CJK>
+0x4928	0x6383	# <CJK>
+0x4929	0x5AC2	# <CJK>
+0x492A	0x745F	# <CJK>
+0x492B	0x8272	# <CJK>
+0x492C	0x6F80	# <CJK>
+0x492D	0x68EE	# <CJK>
+0x492E	0x50E7	# <CJK>
+0x492F	0x838E	# <CJK>
+0x4930	0x7802	# <CJK>
+0x4931	0x6BBA	# <CJK>
+0x4932	0x5239	# <CJK>
+0x4933	0x6C99	# <CJK>
+0x4934	0x7D17	# <CJK>
+0x4935	0x50BB	# <CJK>
+0x4936	0x5565	# <CJK>
+0x4937	0x715E	# <CJK>
+0x4938	0x7BE9	# <CJK>
+0x4939	0x66EC	# <CJK>
+0x493A	0x73CA	# <CJK>
+0x493B	0x82EB	# <CJK>
+0x493C	0x6749	# <CJK>
+0x493D	0x5C71	# <CJK>
+0x493E	0x5220	# <CJK>
+0x493F	0x717D	# <CJK>
+0x4940	0x886B	# <CJK>
+0x4941	0x9583	# <CJK>
+0x4942	0x965D	# <CJK>
+0x4943	0x64C5	# <CJK>
+0x4944	0x8D0D	# <CJK>
+0x4945	0x81B3	# <CJK>
+0x4946	0x5584	# <CJK>
+0x4947	0x6C55	# <CJK>
+0x4948	0x6247	# <CJK>
+0x4949	0x7E55	# <CJK>
+0x494A	0x5892	# <CJK>
+0x494B	0x50B7	# <CJK>
+0x494C	0x5546	# <CJK>
+0x494D	0x8CDE	# <CJK>
+0x494E	0x664C	# <CJK>
+0x494F	0x4E0A	# <CJK>
+0x4950	0x5C1A	# <CJK>
+0x4951	0x88F3	# <CJK>
+0x4952	0x68A2	# <CJK>
+0x4953	0x634E	# <CJK>
+0x4954	0x7A0D	# <CJK>
+0x4955	0x71D2	# <CJK>
+0x4956	0x828D	# <CJK>
+0x4957	0x52FA	# <CJK>
+0x4958	0x97F6	# <CJK>
+0x4959	0x5C11	# <CJK>
+0x495A	0x54E8	# <CJK>
+0x495B	0x90B5	# <CJK>
+0x495C	0x7D39	# <CJK>
+0x495D	0x5962	# <CJK>
+0x495E	0x8CD2	# <CJK>
+0x495F	0x86C7	# <CJK>
+0x4960	0x820C	# <CJK>
+0x4961	0x6368	# <CJK>
+0x4962	0x8D66	# <CJK>
+0x4963	0x651D	# <CJK>
+0x4964	0x5C04	# <CJK>
+0x4965	0x61FE	# <CJK>
+0x4966	0x6D89	# <CJK>
+0x4967	0x793E	# <CJK>
+0x4968	0x8A2D	# <CJK>
+0x4969	0x7837	# <CJK>
+0x496A	0x7533	# <CJK>
+0x496B	0x547B	# <CJK>
+0x496C	0x4F38	# <CJK>
+0x496D	0x8EAB	# <CJK>
+0x496E	0x6DF1	# <CJK>
+0x496F	0x5A20	# <CJK>
+0x4970	0x7D33	# <CJK>
+0x4971	0x795E	# <CJK>
+0x4972	0x6C88	# <CJK>
+0x4973	0x5BE9	# <CJK>
+0x4974	0x5B38	# <CJK>
+0x4975	0x751A	# <CJK>
+0x4976	0x814E	# <CJK>
+0x4977	0x614E	# <CJK>
+0x4978	0x6EF2	# <CJK>
+0x4979	0x8072	# <CJK>
+0x497A	0x751F	# <CJK>
+0x497B	0x7525	# <CJK>
+0x497C	0x7272	# <CJK>
+0x497D	0x5347	# <CJK>
+0x497E	0x7E69	# <CJK>
+0x4A21	0x7701	# <CJK>
+0x4A22	0x76DB	# <CJK>
+0x4A23	0x5269	# <CJK>
+0x4A24	0x52DD	# <CJK>
+0x4A25	0x8056	# <CJK>
+0x4A26	0x5E2B	# <CJK>
+0x4A27	0x5931	# <CJK>
+0x4A28	0x7345	# <CJK>
+0x4A29	0x65BD	# <CJK>
+0x4A2A	0x6FD5	# <CJK>
+0x4A2B	0x8A69	# <CJK>
+0x4A2C	0x5C38	# <CJK>
+0x4A2D	0x8671	# <CJK>
+0x4A2E	0x5341	# <CJK>
+0x4A2F	0x77F3	# <CJK>
+0x4A30	0x62FE	# <CJK>
+0x4A31	0x6642	# <CJK>
+0x4A32	0x4EC0	# <CJK>
+0x4A33	0x98DF	# <CJK>
+0x4A34	0x8755	# <CJK>
+0x4A35	0x5BE6	# <CJK>
+0x4A36	0x8B58	# <CJK>
+0x4A37	0x53F2	# <CJK>
+0x4A38	0x77E2	# <CJK>
+0x4A39	0x4F7F	# <CJK>
+0x4A3A	0x5C4E	# <CJK>
+0x4A3B	0x99DB	# <CJK>
+0x4A3C	0x59CB	# <CJK>
+0x4A3D	0x5F0F	# <CJK>
+0x4A3E	0x793A	# <CJK>
+0x4A3F	0x58EB	# <CJK>
+0x4A40	0x4E16	# <CJK>
+0x4A41	0x67FF	# <CJK>
+0x4A42	0x4E8B	# <CJK>
+0x4A43	0x62ED	# <CJK>
+0x4A44	0x8A93	# <CJK>
+0x4A45	0x901D	# <CJK>
+0x4A46	0x52E2	# <CJK>
+0x4A47	0x662F	# <CJK>
+0x4A48	0x55DC	# <CJK>
+0x4A49	0x566C	# <CJK>
+0x4A4A	0x9069	# <CJK>
+0x4A4B	0x4ED5	# <CJK>
+0x4A4C	0x4F8D	# <CJK>
+0x4A4D	0x91CB	# <CJK>
+0x4A4E	0x98FE	# <CJK>
+0x4A4F	0x6C0F	# <CJK>
+0x4A50	0x5E02	# <CJK>
+0x4A51	0x6043	# <CJK>
+0x4A52	0x5BA4	# <CJK>
+0x4A53	0x8996	# <CJK>
+0x4A54	0x8A66	# <CJK>
+0x4A55	0x6536	# <CJK>
+0x4A56	0x624B	# <CJK>
+0x4A57	0x9996	# <CJK>
+0x4A58	0x5B88	# <CJK>
+0x4A59	0x58FD	# <CJK>
+0x4A5A	0x6388	# <CJK>
+0x4A5B	0x552E	# <CJK>
+0x4A5C	0x53D7	# <CJK>
+0x4A5D	0x7626	# <CJK>
+0x4A5E	0x7378	# <CJK>
+0x4A5F	0x852C	# <CJK>
+0x4A60	0x6A1E	# <CJK>
+0x4A61	0x68B3	# <CJK>
+0x4A62	0x6B8A	# <CJK>
+0x4A63	0x6292	# <CJK>
+0x4A64	0x8F38	# <CJK>
+0x4A65	0x53D4	# <CJK>
+0x4A66	0x8212	# <CJK>
+0x4A67	0x6DD1	# <CJK>
+0x4A68	0x758F	# <CJK>
+0x4A69	0x66F8	# <CJK>
+0x4A6A	0x8D16	# <CJK>
+0x4A6B	0x5B70	# <CJK>
+0x4A6C	0x719F	# <CJK>
+0x4A6D	0x85AF	# <CJK>
+0x4A6E	0x6691	# <CJK>
+0x4A6F	0x66D9	# <CJK>
+0x4A70	0x7F72	# <CJK>
+0x4A71	0x8700	# <CJK>
+0x4A72	0x9ECD	# <CJK>
+0x4A73	0x9F20	# <CJK>
+0x4A74	0x5C6C	# <CJK>
+0x4A75	0x8853	# <CJK>
+0x4A76	0x8FF0	# <CJK>
+0x4A77	0x6A39	# <CJK>
+0x4A78	0x675F	# <CJK>
+0x4A79	0x620D	# <CJK>
+0x4A7A	0x7AEA	# <CJK>
+0x4A7B	0x5885	# <CJK>
+0x4A7C	0x5EB6	# <CJK>
+0x4A7D	0x6578	# <CJK>
+0x4A7E	0x6F31	# <CJK>
+0x4B21	0x6055	# <CJK>
+0x4B22	0x5237	# <CJK>
+0x4B23	0x800D	# <CJK>
+0x4B24	0x6454	# <CJK>
+0x4B25	0x8870	# <CJK>
+0x4B26	0x7529	# <CJK>
+0x4B27	0x5E25	# <CJK>
+0x4B28	0x6813	# <CJK>
+0x4B29	0x62F4	# <CJK>
+0x4B2A	0x971C	# <CJK>
+0x4B2B	0x96D9	# <CJK>
+0x4B2C	0x723D	# <CJK>
+0x4B2D	0x8AB0	# <CJK>
+0x4B2E	0x6C34	# <CJK>
+0x4B2F	0x7761	# <CJK>
+0x4B30	0x7A0E	# <CJK>
+0x4B31	0x542E	# <CJK>
+0x4B32	0x77AC	# <CJK>
+0x4B33	0x9806	# <CJK>
+0x4B34	0x821C	# <CJK>
+0x4B35	0x8AAC	# <CJK>
+0x4B36	0x78A9	# <CJK>
+0x4B37	0x6714	# <CJK>
+0x4B38	0x720D	# <CJK>
+0x4B39	0x65AF	# <CJK>
+0x4B3A	0x6495	# <CJK>
+0x4B3B	0x5636	# <CJK>
+0x4B3C	0x601D	# <CJK>
+0x4B3D	0x79C1	# <CJK>
+0x4B3E	0x53F8	# <CJK>
+0x4B3F	0x7D72	# <CJK>
+0x4B40	0x6B7B	# <CJK>
+0x4B41	0x8086	# <CJK>
+0x4B42	0x5BFA	# <CJK>
+0x4B43	0x55E3	# <CJK>
+0x4B44	0x56DB	# <CJK>
+0x4B45	0x4F3A	# <CJK>
+0x4B46	0x4F3C	# <CJK>
+0x4B47	0x98FC	# <CJK>
+0x4B48	0x5DF3	# <CJK>
+0x4B49	0x9B06	# <CJK>
+0x4B4A	0x8073	# <CJK>
+0x4B4B	0x616B	# <CJK>
+0x4B4C	0x980C	# <CJK>
+0x4B4D	0x9001	# <CJK>
+0x4B4E	0x5B8B	# <CJK>
+0x4B4F	0x8A1F	# <CJK>
+0x4B50	0x8AA6	# <CJK>
+0x4B51	0x641C	# <CJK>
+0x4B52	0x8258	# <CJK>
+0x4B53	0x64FB	# <CJK>
+0x4B54	0x55FD	# <CJK>
+0x4B55	0x8607	# <CJK>
+0x4B56	0x9165	# <CJK>
+0x4B57	0x4FD7	# <CJK>
+0x4B58	0x7D20	# <CJK>
+0x4B59	0x901F	# <CJK>
+0x4B5A	0x7C9F	# <CJK>
+0x4B5B	0x50F3	# <CJK>
+0x4B5C	0x5851	# <CJK>
+0x4B5D	0x6EAF	# <CJK>
+0x4B5E	0x5BBF	# <CJK>
+0x4B5F	0x8A34	# <CJK>
+0x4B60	0x8085	# <CJK>
+0x4B61	0x9178	# <CJK>
+0x4B62	0x849C	# <CJK>
+0x4B63	0x7B97	# <CJK>
+0x4B64	0x96D6	# <CJK>
+0x4B65	0x968B	# <CJK>
+0x4B66	0x96A8	# <CJK>
+0x4B67	0x7D8F	# <CJK>
+0x4B68	0x9AD3	# <CJK>
+0x4B69	0x788E	# <CJK>
+0x4B6A	0x6B72	# <CJK>
+0x4B6B	0x7A57	# <CJK>
+0x4B6C	0x9042	# <CJK>
+0x4B6D	0x96A7	# <CJK>
+0x4B6E	0x795F	# <CJK>
+0x4B6F	0x5B6B	# <CJK>
+0x4B70	0x640D	# <CJK>
+0x4B71	0x7B0B	# <CJK>
+0x4B72	0x84D1	# <CJK>
+0x4B73	0x68AD	# <CJK>
+0x4B74	0x5506	# <CJK>
+0x4B75	0x7E2E	# <CJK>
+0x4B76	0x7463	# <CJK>
+0x4B77	0x7D22	# <CJK>
+0x4B78	0x9396	# <CJK>
+0x4B79	0x6240	# <CJK>
+0x4B7A	0x584C	# <CJK>
+0x4B7B	0x4ED6	# <CJK>
+0x4B7C	0x5B83	# <CJK>
+0x4B7D	0x5979	# <CJK>
+0x4B7E	0x5854	# <CJK>
+0x4C21	0x737A	# <CJK>
+0x4C22	0x64BB	# <CJK>
+0x4C23	0x8E4B	# <CJK>
+0x4C24	0x8E0F	# <CJK>
+0x4C25	0x80CE	# <CJK>
+0x4C26	0x82D4	# <CJK>
+0x4C27	0x62AC	# <CJK>
+0x4C28	0x81FA	# <CJK>
+0x4C29	0x6CF0	# <CJK>
+0x4C2A	0x915E	# <CJK>
+0x4C2B	0x592A	# <CJK>
+0x4C2C	0x614B	# <CJK>
+0x4C2D	0x6C70	# <CJK>
+0x4C2E	0x574D	# <CJK>
+0x4C2F	0x6524	# <CJK>
+0x4C30	0x8CAA	# <CJK>
+0x4C31	0x7671	# <CJK>
+0x4C32	0x7058	# <CJK>
+0x4C33	0x58C7	# <CJK>
+0x4C34	0x6A80	# <CJK>
+0x4C35	0x75F0	# <CJK>
+0x4C36	0x6F6D	# <CJK>
+0x4C37	0x8B5A	# <CJK>
+0x4C38	0x8AC7	# <CJK>
+0x4C39	0x5766	# <CJK>
+0x4C3A	0x6BEF	# <CJK>
+0x4C3B	0x8892	# <CJK>
+0x4C3C	0x78B3	# <CJK>
+0x4C3D	0x63A2	# <CJK>
+0x4C3E	0x5606	# <CJK>
+0x4C3F	0x70AD	# <CJK>
+0x4C40	0x6E6F	# <CJK>
+0x4C41	0x5858	# <CJK>
+0x4C42	0x642A	# <CJK>
+0x4C43	0x5802	# <CJK>
+0x4C44	0x68E0	# <CJK>
+0x4C45	0x819B	# <CJK>
+0x4C46	0x5510	# <CJK>
+0x4C47	0x7CD6	# <CJK>
+0x4C48	0x5018	# <CJK>
+0x4C49	0x8EBA	# <CJK>
+0x4C4A	0x6DCC	# <CJK>
+0x4C4B	0x8D9F	# <CJK>
+0x4C4C	0x71D9	# <CJK>
+0x4C4D	0x638F	# <CJK>
+0x4C4E	0x6FE4	# <CJK>
+0x4C4F	0x6ED4	# <CJK>
+0x4C50	0x7E27	# <CJK>
+0x4C51	0x8404	# <CJK>
+0x4C52	0x6843	# <CJK>
+0x4C53	0x9003	# <CJK>
+0x4C54	0x6DD8	# <CJK>
+0x4C55	0x9676	# <CJK>
+0x4C56	0x8A0E	# <CJK>
+0x4C57	0x5957	# <CJK>
+0x4C58	0x7279	# <CJK>
+0x4C59	0x85E4	# <CJK>
+0x4C5A	0x9A30	# <CJK>
+0x4C5B	0x75BC	# <CJK>
+0x4C5C	0x8B04	# <CJK>
+0x4C5D	0x68AF	# <CJK>
+0x4C5E	0x5254	# <CJK>
+0x4C5F	0x8E22	# <CJK>
+0x4C60	0x92BB	# <CJK>
+0x4C61	0x63D0	# <CJK>
+0x4C62	0x984C	# <CJK>
+0x4C63	0x8E44	# <CJK>
+0x4C64	0x557C	# <CJK>
+0x4C65	0x9AD4	# <CJK>
+0x4C66	0x66FF	# <CJK>
+0x4C67	0x568F	# <CJK>
+0x4C68	0x60D5	# <CJK>
+0x4C69	0x6D95	# <CJK>
+0x4C6A	0x5243	# <CJK>
+0x4C6B	0x5C49	# <CJK>
+0x4C6C	0x5929	# <CJK>
+0x4C6D	0x6DFB	# <CJK>
+0x4C6E	0x586B	# <CJK>
+0x4C6F	0x7530	# <CJK>
+0x4C70	0x751C	# <CJK>
+0x4C71	0x606C	# <CJK>
+0x4C72	0x8214	# <CJK>
+0x4C73	0x8146	# <CJK>
+0x4C74	0x6311	# <CJK>
+0x4C75	0x689D	# <CJK>
+0x4C76	0x8FE2	# <CJK>
+0x4C77	0x773A	# <CJK>
+0x4C78	0x8DF3	# <CJK>
+0x4C79	0x8CBC	# <CJK>
+0x4C7A	0x9435	# <CJK>
+0x4C7B	0x5E16	# <CJK>
+0x4C7C	0x5EF3	# <CJK>
+0x4C7D	0x807D	# <CJK>
+0x4C7E	0x70F4	# <CJK>
+0x4D21	0x6C40	# <CJK>
+0x4D22	0x5EF7	# <CJK>
+0x4D23	0x505C	# <CJK>
+0x4D24	0x4EAD	# <CJK>
+0x4D25	0x5EAD	# <CJK>
+0x4D26	0x633A	# <CJK>
+0x4D27	0x8247	# <CJK>
+0x4D28	0x901A	# <CJK>
+0x4D29	0x6850	# <CJK>
+0x4D2A	0x916E	# <CJK>
+0x4D2B	0x77B3	# <CJK>
+0x4D2C	0x540C	# <CJK>
+0x4D2D	0x9285	# <CJK>
+0x4D2E	0x5F64	# <CJK>
+0x4D2F	0x7AE5	# <CJK>
+0x4D30	0x6876	# <CJK>
+0x4D31	0x6345	# <CJK>
+0x4D32	0x7B52	# <CJK>
+0x4D33	0x7D71	# <CJK>
+0x4D34	0x75DB	# <CJK>
+0x4D35	0x5077	# <CJK>
+0x4D36	0x6295	# <CJK>
+0x4D37	0x982D	# <CJK>
+0x4D38	0x900F	# <CJK>
+0x4D39	0x51F8	# <CJK>
+0x4D3A	0x79C3	# <CJK>
+0x4D3B	0x7A81	# <CJK>
+0x4D3C	0x5716	# <CJK>
+0x4D3D	0x5F92	# <CJK>
+0x4D3E	0x9014	# <CJK>
+0x4D3F	0x5857	# <CJK>
+0x4D40	0x5C60	# <CJK>
+0x4D41	0x571F	# <CJK>
+0x4D42	0x5410	# <CJK>
+0x4D43	0x5154	# <CJK>
+0x4D44	0x6E4D	# <CJK>
+0x4D45	0x5718	# <CJK>
+0x4D46	0x63A8	# <CJK>
+0x4D47	0x983D	# <CJK>
+0x4D48	0x817F	# <CJK>
+0x4D49	0x8715	# <CJK>
+0x4D4A	0x892A	# <CJK>
+0x4D4B	0x9000	# <CJK>
+0x4D4C	0x541E	# <CJK>
+0x4D4D	0x5C6F	# <CJK>
+0x4D4E	0x81C0	# <CJK>
+0x4D4F	0x62D6	# <CJK>
+0x4D50	0x6258	# <CJK>
+0x4D51	0x8131	# <CJK>
+0x4D52	0x9D15	# <CJK>
+0x4D53	0x9640	# <CJK>
+0x4D54	0x99B1	# <CJK>
+0x4D55	0x99DD	# <CJK>
+0x4D56	0x6A62	# <CJK>
+0x4D57	0x59A5	# <CJK>
+0x4D58	0x62D3	# <CJK>
+0x4D59	0x553E	# <CJK>
+0x4D5A	0x6316	# <CJK>
+0x4D5B	0x54C7	# <CJK>
+0x4D5C	0x86D9	# <CJK>
+0x4D5D	0x7AAA	# <CJK>
+0x4D5E	0x5A03	# <CJK>
+0x4D5F	0x74E6	# <CJK>
+0x4D60	0x896A	# <CJK>
+0x4D61	0x6B6A	# <CJK>
+0x4D62	0x5916	# <CJK>
+0x4D63	0x8C4C	# <CJK>
+0x4D64	0x5F4E	# <CJK>
+0x4D65	0x7063	# <CJK>
+0x4D66	0x73A9	# <CJK>
+0x4D67	0x9811	# <CJK>
+0x4D68	0x4E38	# <CJK>
+0x4D69	0x70F7	# <CJK>
+0x4D6A	0x5B8C	# <CJK>
+0x4D6B	0x7897	# <CJK>
+0x4D6C	0x633D	# <CJK>
+0x4D6D	0x665A	# <CJK>
+0x4D6E	0x7696	# <CJK>
+0x4D6F	0x60CB	# <CJK>
+0x4D70	0x5B9B	# <CJK>
+0x4D71	0x5A49	# <CJK>
+0x4D72	0x842C	# <CJK>
+0x4D73	0x8155	# <CJK>
+0x4D74	0x6C6A	# <CJK>
+0x4D75	0x738B	# <CJK>
+0x4D76	0x4EA1	# <CJK>
+0x4D77	0x6789	# <CJK>
+0x4D78	0x7DB2	# <CJK>
+0x4D79	0x5F80	# <CJK>
+0x4D7A	0x65FA	# <CJK>
+0x4D7B	0x671B	# <CJK>
+0x4D7C	0x5FD8	# <CJK>
+0x4D7D	0x5984	# <CJK>
+0x4D7E	0x5A01	# <CJK>
+0x4E21	0x5DCD	# <CJK>
+0x4E22	0x5FAE	# <CJK>
+0x4E23	0x5371	# <CJK>
+0x4E24	0x97CB	# <CJK>
+0x4E25	0x9055	# <CJK>
+0x4E26	0x6845	# <CJK>
+0x4E27	0x570D	# <CJK>
+0x4E28	0x552F	# <CJK>
+0x4E29	0x60DF	# <CJK>
+0x4E2A	0x7232	# <CJK>
+0x4E2B	0x6FF0	# <CJK>
+0x4E2C	0x7DAD	# <CJK>
+0x4E2D	0x8466	# <CJK>
+0x4E2E	0x840E	# <CJK>
+0x4E2F	0x59D4	# <CJK>
+0x4E30	0x5049	# <CJK>
+0x4E31	0x50DE	# <CJK>
+0x4E32	0x5C3E	# <CJK>
+0x4E33	0x7DEF	# <CJK>
+0x4E34	0x672A	# <CJK>
+0x4E35	0x851A	# <CJK>
+0x4E36	0x5473	# <CJK>
+0x4E37	0x754F	# <CJK>
+0x4E38	0x80C3	# <CJK>
+0x4E39	0x5582	# <CJK>
+0x4E3A	0x9B4F	# <CJK>
+0x4E3B	0x4F4D	# <CJK>
+0x4E3C	0x6E2D	# <CJK>
+0x4E3D	0x8B02	# <CJK>
+0x4E3E	0x5C09	# <CJK>
+0x4E3F	0x6170	# <CJK>
+0x4E40	0x885B	# <CJK>
+0x4E41	0x761F	# <CJK>
+0x4E42	0x6E29	# <CJK>
+0x4E43	0x868A	# <CJK>
+0x4E44	0x6587	# <CJK>
+0x4E45	0x805E	# <CJK>
+0x4E46	0x7D0B	# <CJK>
+0x4E47	0x543B	# <CJK>
+0x4E48	0x7A69	# <CJK>
+0x4E49	0x7D0A	# <CJK>
+0x4E4A	0x554F	# <CJK>
+0x4E4B	0x55E1	# <CJK>
+0x4E4C	0x7FC1	# <CJK>
+0x4E4D	0x74EE	# <CJK>
+0x4E4E	0x64BE	# <CJK>
+0x4E4F	0x8778	# <CJK>
+0x4E50	0x6E26	# <CJK>
+0x4E51	0x7AA9	# <CJK>
+0x4E52	0x6211	# <CJK>
+0x4E53	0x65A1	# <CJK>
+0x4E54	0x5367	# <CJK>
+0x4E55	0x63E1	# <CJK>
+0x4E56	0x6C83	# <CJK>
+0x4E57	0x5DEB	# <CJK>
+0x4E58	0x55DA	# <CJK>
+0x4E59	0x93A2	# <CJK>
+0x4E5A	0x70CF	# <CJK>
+0x4E5B	0x6C61	# <CJK>
+0x4E5C	0x8AA3	# <CJK>
+0x4E5D	0x5C4B	# <CJK>
+0x4E5E	0x7121	# <CJK>
+0x4E5F	0x856A	# <CJK>
+0x4E60	0x68A7	# <CJK>
+0x4E61	0x543E	# <CJK>
+0x4E62	0x5434	# <CJK>
+0x4E63	0x6BCB	# <CJK>
+0x4E64	0x6B66	# <CJK>
+0x4E65	0x4E94	# <CJK>
+0x4E66	0x6342	# <CJK>
+0x4E67	0x5348	# <CJK>
+0x4E68	0x821E	# <CJK>
+0x4E69	0x4F0D	# <CJK>
+0x4E6A	0x4FAE	# <CJK>
+0x4E6B	0x5862	# <CJK>
+0x4E6C	0x620A	# <CJK>
+0x4E6D	0x9727	# <CJK>
+0x4E6E	0x6664	# <CJK>
+0x4E6F	0x7269	# <CJK>
+0x4E70	0x52FF	# <CJK>
+0x4E71	0x52D9	# <CJK>
+0x4E72	0x609F	# <CJK>
+0x4E73	0x8AA4	# <CJK>
+0x4E74	0x6614	# <CJK>
+0x4E75	0x7199	# <CJK>
+0x4E76	0x6790	# <CJK>
+0x4E77	0x897F	# <CJK>
+0x4E78	0x7852	# <CJK>
+0x4E79	0x77FD	# <CJK>
+0x4E7A	0x6670	# <CJK>
+0x4E7B	0x563B	# <CJK>
+0x4E7C	0x5438	# <CJK>
+0x4E7D	0x932B	# <CJK>
+0x4E7E	0x72A7	# <CJK>
+0x4F21	0x7A00	# <CJK>
+0x4F22	0x606F	# <CJK>
+0x4F23	0x5E0C	# <CJK>
+0x4F24	0x6089	# <CJK>
+0x4F25	0x819D	# <CJK>
+0x4F26	0x5915	# <CJK>
+0x4F27	0x60DC	# <CJK>
+0x4F28	0x7184	# <CJK>
+0x4F29	0x70EF	# <CJK>
+0x4F2A	0x6EAA	# <CJK>
+0x4F2B	0x6C50	# <CJK>
+0x4F2C	0x7280	# <CJK>
+0x4F2D	0x6A84	# <CJK>
+0x4F2E	0x8972	# <CJK>
+0x4F2F	0x5E2D	# <CJK>
+0x4F30	0x7FD2	# <CJK>
+0x4F31	0x5AB3	# <CJK>
+0x4F32	0x559C	# <CJK>
+0x4F33	0x9291	# <CJK>
+0x4F34	0x6D17	# <CJK>
+0x4F35	0x7CFB	# <CJK>
+0x4F36	0x9699	# <CJK>
+0x4F37	0x6232	# <CJK>
+0x4F38	0x7D30	# <CJK>
+0x4F39	0x778E	# <CJK>
+0x4F3A	0x8766	# <CJK>
+0x4F3B	0x5323	# <CJK>
+0x4F3C	0x971E	# <CJK>
+0x4F3D	0x8F44	# <CJK>
+0x4F3E	0x6687	# <CJK>
+0x4F3F	0x5CFD	# <CJK>
+0x4F40	0x4FE0	# <CJK>
+0x4F41	0x72F9	# <CJK>
+0x4F42	0x4E0B	# <CJK>
+0x4F43	0x53A6	# <CJK>
+0x4F44	0x590F	# <CJK>
+0x4F45	0x5687	# <CJK>
+0x4F46	0x6380	# <CJK>
+0x4F47	0x9341	# <CJK>
+0x4F48	0x5148	# <CJK>
+0x4F49	0x4ED9	# <CJK>
+0x4F4A	0x9BAE	# <CJK>
+0x4F4B	0x7E96	# <CJK>
+0x4F4C	0x54B8	# <CJK>
+0x4F4D	0x8CE2	# <CJK>
+0x4F4E	0x929C	# <CJK>
+0x4F4F	0x8237	# <CJK>
+0x4F50	0x9591	# <CJK>
+0x4F51	0x6D8E	# <CJK>
+0x4F52	0x5F26	# <CJK>
+0x4F53	0x5ACC	# <CJK>
+0x4F54	0x986F	# <CJK>
+0x4F55	0x96AA	# <CJK>
+0x4F56	0x73FE	# <CJK>
+0x4F57	0x737B	# <CJK>
+0x4F58	0x7E23	# <CJK>
+0x4F59	0x817A	# <CJK>
+0x4F5A	0x9921	# <CJK>
+0x4F5B	0x7FA1	# <CJK>
+0x4F5C	0x61B2	# <CJK>
+0x4F5D	0x9677	# <CJK>
+0x4F5E	0x9650	# <CJK>
+0x4F5F	0x7DAB	# <CJK>
+0x4F60	0x76F8	# <CJK>
+0x4F61	0x53A2	# <CJK>
+0x4F62	0x9472	# <CJK>
+0x4F63	0x9999	# <CJK>
+0x4F64	0x7BB1	# <CJK>
+0x4F65	0x8944	# <CJK>
+0x4F66	0x6E58	# <CJK>
+0x4F67	0x9109	# <CJK>
+0x4F68	0x7FD4	# <CJK>
+0x4F69	0x7965	# <CJK>
+0x4F6A	0x8A73	# <CJK>
+0x4F6B	0x60F3	# <CJK>
+0x4F6C	0x97FF	# <CJK>
+0x4F6D	0x4EAB	# <CJK>
+0x4F6E	0x9805	# <CJK>
+0x4F6F	0x5DF7	# <CJK>
+0x4F70	0x6A61	# <CJK>
+0x4F71	0x50CF	# <CJK>
+0x4F72	0x5411	# <CJK>
+0x4F73	0x8C61	# <CJK>
+0x4F74	0x856D	# <CJK>
+0x4F75	0x785D	# <CJK>
+0x4F76	0x9704	# <CJK>
+0x4F77	0x524A	# <CJK>
+0x4F78	0x54EE	# <CJK>
+0x4F79	0x56C2	# <CJK>
+0x4F7A	0x92B7	# <CJK>
+0x4F7B	0x6D88	# <CJK>
+0x4F7C	0x5BB5	# <CJK>
+0x4F7D	0x6DC6	# <CJK>
+0x4F7E	0x66C9	# <CJK>
+0x5021	0x5C0F	# <CJK>
+0x5022	0x5B5D	# <CJK>
+0x5023	0x6821	# <CJK>
+0x5024	0x8096	# <CJK>
+0x5025	0x562F	# <CJK>
+0x5026	0x7B11	# <CJK>
+0x5027	0x6548	# <CJK>
+0x5028	0x6954	# <CJK>
+0x5029	0x4E9B	# <CJK>
+0x502A	0x6B47	# <CJK>
+0x502B	0x874E	# <CJK>
+0x502C	0x978B	# <CJK>
+0x502D	0x5354	# <CJK>
+0x502E	0x633E	# <CJK>
+0x502F	0x643A	# <CJK>
+0x5030	0x90AA	# <CJK>
+0x5031	0x659C	# <CJK>
+0x5032	0x8105	# <CJK>
+0x5033	0x8AE7	# <CJK>
+0x5034	0x5BEB	# <CJK>
+0x5035	0x68B0	# <CJK>
+0x5036	0x5378	# <CJK>
+0x5037	0x87F9	# <CJK>
+0x5038	0x61C8	# <CJK>
+0x5039	0x6CC4	# <CJK>
+0x503A	0x7009	# <CJK>
+0x503B	0x8B1D	# <CJK>
+0x503C	0x5C51	# <CJK>
+0x503D	0x85AA	# <CJK>
+0x503E	0x82AF	# <CJK>
+0x503F	0x92C5	# <CJK>
+0x5040	0x6B23	# <CJK>
+0x5041	0x8F9B	# <CJK>
+0x5042	0x65B0	# <CJK>
+0x5043	0x5FFB	# <CJK>
+0x5044	0x5FC3	# <CJK>
+0x5045	0x4FE1	# <CJK>
+0x5046	0x91C1	# <CJK>
+0x5047	0x661F	# <CJK>
+0x5048	0x8165	# <CJK>
+0x5049	0x7329	# <CJK>
+0x504A	0x60FA	# <CJK>
+0x504B	0x8208	# <CJK>
+0x504C	0x5211	# <CJK>
+0x504D	0x578B	# <CJK>
+0x504E	0x5F62	# <CJK>
+0x504F	0x90A2	# <CJK>
+0x5050	0x884C	# <CJK>
+0x5051	0x9192	# <CJK>
+0x5052	0x5E78	# <CJK>
+0x5053	0x674F	# <CJK>
+0x5054	0x6027	# <CJK>
+0x5055	0x59D3	# <CJK>
+0x5056	0x5144	# <CJK>
+0x5057	0x51F6	# <CJK>
+0x5058	0x80F8	# <CJK>
+0x5059	0x5308	# <CJK>
+0x505A	0x6C79	# <CJK>
+0x505B	0x96C4	# <CJK>
+0x505C	0x718A	# <CJK>
+0x505D	0x4F11	# <CJK>
+0x505E	0x4FEE	# <CJK>
+0x505F	0x7F9E	# <CJK>
+0x5060	0x673D	# <CJK>
+0x5061	0x55C5	# <CJK>
+0x5062	0x92B9	# <CJK>
+0x5063	0x79C0	# <CJK>
+0x5064	0x8896	# <CJK>
+0x5065	0x7D89	# <CJK>
+0x5066	0x589F	# <CJK>
+0x5067	0x620C	# <CJK>
+0x5068	0x9700	# <CJK>
+0x5069	0x865A	# <CJK>
+0x506A	0x5618	# <CJK>
+0x506B	0x9808	# <CJK>
+0x506C	0x5F90	# <CJK>
+0x506D	0x8A31	# <CJK>
+0x506E	0x84C4	# <CJK>
+0x506F	0x9157	# <CJK>
+0x5070	0x53D9	# <CJK>
+0x5071	0x65ED	# <CJK>
+0x5072	0x5E8F	# <CJK>
+0x5073	0x755C	# <CJK>
+0x5074	0x6064	# <CJK>
+0x5075	0x7D6E	# <CJK>
+0x5076	0x5A7F	# <CJK>
+0x5077	0x7DD2	# <CJK>
+0x5078	0x7E8C	# <CJK>
+0x5079	0x8ED2	# <CJK>
+0x507A	0x55A7	# <CJK>
+0x507B	0x5BA3	# <CJK>
+0x507C	0x61F8	# <CJK>
+0x507D	0x65CB	# <CJK>
+0x507E	0x7384	# <CJK>
+0x5121	0x9078	# <CJK>
+0x5122	0x766C	# <CJK>
+0x5123	0x7729	# <CJK>
+0x5124	0x7D62	# <CJK>
+0x5125	0x9774	# <CJK>
+0x5126	0x859B	# <CJK>
+0x5127	0x5B78	# <CJK>
+0x5128	0x7A74	# <CJK>
+0x5129	0x96EA	# <CJK>
+0x512A	0x8840	# <CJK>
+0x512B	0x52DB	# <CJK>
+0x512C	0x718F	# <CJK>
+0x512D	0x5FAA	# <CJK>
+0x512E	0x65EC	# <CJK>
+0x512F	0x8A62	# <CJK>
+0x5130	0x5C0B	# <CJK>
+0x5131	0x99B4	# <CJK>
+0x5132	0x5DE1	# <CJK>
+0x5133	0x6B89	# <CJK>
+0x5134	0x6C5B	# <CJK>
+0x5135	0x8A13	# <CJK>
+0x5136	0x8A0A	# <CJK>
+0x5137	0x905C	# <CJK>
+0x5138	0x8FC5	# <CJK>
+0x5139	0x58D3	# <CJK>
+0x513A	0x62BC	# <CJK>
+0x513B	0x9D09	# <CJK>
+0x513C	0x9D28	# <CJK>
+0x513D	0x5440	# <CJK>
+0x513E	0x4E2B	# <CJK>
+0x513F	0x82BD	# <CJK>
+0x5140	0x7259	# <CJK>
+0x5141	0x869C	# <CJK>
+0x5142	0x5D16	# <CJK>
+0x5143	0x8859	# <CJK>
+0x5144	0x6DAF	# <CJK>
+0x5145	0x96C5	# <CJK>
+0x5146	0x555E	# <CJK>
+0x5147	0x4E9E	# <CJK>
+0x5148	0x8A1D	# <CJK>
+0x5149	0x7109	# <CJK>
+0x514A	0x54BD	# <CJK>
+0x514B	0x95B9	# <CJK>
+0x514C	0x70DF	# <CJK>
+0x514D	0x6DF9	# <CJK>
+0x514E	0x9E7D	# <CJK>
+0x514F	0x56B4	# <CJK>
+0x5150	0x7814	# <CJK>
+0x5151	0x8712	# <CJK>
+0x5152	0x5CA9	# <CJK>
+0x5153	0x5EF6	# <CJK>
+0x5154	0x8A00	# <CJK>
+0x5155	0x9854	# <CJK>
+0x5156	0x95BB	# <CJK>
+0x5157	0x708E	# <CJK>
+0x5158	0x6CBF	# <CJK>
+0x5159	0x5944	# <CJK>
+0x515A	0x63A9	# <CJK>
+0x515B	0x773C	# <CJK>
+0x515C	0x884D	# <CJK>
+0x515D	0x6F14	# <CJK>
+0x515E	0x8277	# <CJK>
+0x515F	0x5830	# <CJK>
+0x5160	0x71D5	# <CJK>
+0x5161	0x53AD	# <CJK>
+0x5162	0x786F	# <CJK>
+0x5163	0x96C1	# <CJK>
+0x5164	0x5501	# <CJK>
+0x5165	0x5F66	# <CJK>
+0x5166	0x7130	# <CJK>
+0x5167	0x5BB4	# <CJK>
+0x5168	0x8AFA	# <CJK>
+0x5169	0x9A57	# <CJK>
+0x516A	0x6B83	# <CJK>
+0x516B	0x592E	# <CJK>
+0x516C	0x9D26	# <CJK>
+0x516D	0x79E7	# <CJK>
+0x516E	0x694A	# <CJK>
+0x516F	0x63DA	# <CJK>
+0x5170	0x4F6F	# <CJK>
+0x5171	0x760D	# <CJK>
+0x5172	0x7F8A	# <CJK>
+0x5173	0x6D0B	# <CJK>
+0x5174	0x967D	# <CJK>
+0x5175	0x6C27	# <CJK>
+0x5176	0x4EF0	# <CJK>
+0x5177	0x7662	# <CJK>
+0x5178	0x990A	# <CJK>
+0x5179	0x6A23	# <CJK>
+0x517A	0x6F3E	# <CJK>
+0x517B	0x9080	# <CJK>
+0x517C	0x8170	# <CJK>
+0x517D	0x5996	# <CJK>
+0x517E	0x7476	# <CJK>
+0x5221	0x6447	# <CJK>
+0x5222	0x582F	# <CJK>
+0x5223	0x9065	# <CJK>
+0x5224	0x7A91	# <CJK>
+0x5225	0x8B21	# <CJK>
+0x5226	0x59DA	# <CJK>
+0x5227	0x54AC	# <CJK>
+0x5228	0x8200	# <CJK>
+0x5229	0x85E5	# <CJK>
+0x522A	0x8981	# <CJK>
+0x522B	0x8000	# <CJK>
+0x522C	0x6930	# <CJK>
+0x522D	0x564E	# <CJK>
+0x522E	0x8036	# <CJK>
+0x522F	0x723A	# <CJK>
+0x5230	0x91CE	# <CJK>
+0x5231	0x51B6	# <CJK>
+0x5232	0x4E5F	# <CJK>
+0x5233	0x9801	# <CJK>
+0x5234	0x6396	# <CJK>
+0x5235	0x696D	# <CJK>
+0x5236	0x8449	# <CJK>
+0x5237	0x66F3	# <CJK>
+0x5238	0x814B	# <CJK>
+0x5239	0x591C	# <CJK>
+0x523A	0x6DB2	# <CJK>
+0x523B	0x4E00	# <CJK>
+0x523C	0x58F9	# <CJK>
+0x523D	0x91AB	# <CJK>
+0x523E	0x63D6	# <CJK>
+0x523F	0x92A5	# <CJK>
+0x5240	0x4F9D	# <CJK>
+0x5241	0x4F0A	# <CJK>
+0x5242	0x8863	# <CJK>
+0x5243	0x9824	# <CJK>
+0x5244	0x5937	# <CJK>
+0x5245	0x907A	# <CJK>
+0x5246	0x79FB	# <CJK>
+0x5247	0x5100	# <CJK>
+0x5248	0x80F0	# <CJK>
+0x5249	0x7591	# <CJK>
+0x524A	0x6C82	# <CJK>
+0x524B	0x5B9C	# <CJK>
+0x524C	0x59E8	# <CJK>
+0x524D	0x5F5D	# <CJK>
+0x524E	0x6905	# <CJK>
+0x524F	0x87FB	# <CJK>
+0x5250	0x501A	# <CJK>
+0x5251	0x5DF2	# <CJK>
+0x5252	0x4E59	# <CJK>
+0x5253	0x77E3	# <CJK>
+0x5254	0x4EE5	# <CJK>
+0x5255	0x85DD	# <CJK>
+0x5256	0x6291	# <CJK>
+0x5257	0x6613	# <CJK>
+0x5258	0x9091	# <CJK>
+0x5259	0x5C79	# <CJK>
+0x525A	0x5104	# <CJK>
+0x525B	0x5F79	# <CJK>
+0x525C	0x81C6	# <CJK>
+0x525D	0x9038	# <CJK>
+0x525E	0x8084	# <CJK>
+0x525F	0x75AB	# <CJK>
+0x5260	0x4EA6	# <CJK>
+0x5261	0x88D4	# <CJK>
+0x5262	0x610F	# <CJK>
+0x5263	0x6BC5	# <CJK>
+0x5264	0x61B6	# <CJK>
+0x5265	0x7FA9	# <CJK>
+0x5266	0x76CA	# <CJK>
+0x5267	0x6EA2	# <CJK>
+0x5268	0x8A63	# <CJK>
+0x5269	0x8B70	# <CJK>
+0x526A	0x8ABC	# <CJK>
+0x526B	0x8B6F	# <CJK>
+0x526C	0x5F02	# <CJK>
+0x526D	0x7FFC	# <CJK>
+0x526E	0x7FCC	# <CJK>
+0x526F	0x7E79	# <CJK>
+0x5270	0x8335	# <CJK>
+0x5271	0x852D	# <CJK>
+0x5272	0x56E0	# <CJK>
+0x5273	0x6BB7	# <CJK>
+0x5274	0x97F3	# <CJK>
+0x5275	0x9670	# <CJK>
+0x5276	0x59FB	# <CJK>
+0x5277	0x541F	# <CJK>
+0x5278	0x9280	# <CJK>
+0x5279	0x6DEB	# <CJK>
+0x527A	0x5BC5	# <CJK>
+0x527B	0x98F2	# <CJK>
+0x527C	0x5C39	# <CJK>
+0x527D	0x5F15	# <CJK>
+0x527E	0x96B1	# <CJK>
+0x5321	0x5370	# <CJK>
+0x5322	0x82F1	# <CJK>
+0x5323	0x6AFB	# <CJK>
+0x5324	0x5B30	# <CJK>
+0x5325	0x9DF9	# <CJK>
+0x5326	0x61C9	# <CJK>
+0x5327	0x7E93	# <CJK>
+0x5328	0x7469	# <CJK>
+0x5329	0x87A2	# <CJK>
+0x532A	0x71DF	# <CJK>
+0x532B	0x7192	# <CJK>
+0x532C	0x8805	# <CJK>
+0x532D	0x8FCE	# <CJK>
+0x532E	0x8D0F	# <CJK>
+0x532F	0x76C8	# <CJK>
+0x5330	0x5F71	# <CJK>
+0x5331	0x7A4E	# <CJK>
+0x5332	0x786C	# <CJK>
+0x5333	0x6620	# <CJK>
+0x5334	0x55B2	# <CJK>
+0x5335	0x64C1	# <CJK>
+0x5336	0x50AD	# <CJK>
+0x5337	0x81C3	# <CJK>
+0x5338	0x7670	# <CJK>
+0x5339	0x5EB8	# <CJK>
+0x533A	0x96CD	# <CJK>
+0x533B	0x8E34	# <CJK>
+0x533C	0x86F9	# <CJK>
+0x533D	0x548F	# <CJK>
+0x533E	0x6CF3	# <CJK>
+0x533F	0x6D8C	# <CJK>
+0x5340	0x6C38	# <CJK>
+0x5341	0x607F	# <CJK>
+0x5342	0x52C7	# <CJK>
+0x5343	0x7528	# <CJK>
+0x5344	0x5E7D	# <CJK>
+0x5345	0x512A	# <CJK>
+0x5346	0x60A0	# <CJK>
+0x5347	0x6182	# <CJK>
+0x5348	0x5C24	# <CJK>
+0x5349	0x7531	# <CJK>
+0x534A	0x90F5	# <CJK>
+0x534B	0x923E	# <CJK>
+0x534C	0x7336	# <CJK>
+0x534D	0x6CB9	# <CJK>
+0x534E	0x6E38	# <CJK>
+0x534F	0x9149	# <CJK>
+0x5350	0x6709	# <CJK>
+0x5351	0x53CB	# <CJK>
+0x5352	0x53F3	# <CJK>
+0x5353	0x4F51	# <CJK>
+0x5354	0x91C9	# <CJK>
+0x5355	0x8A98	# <CJK>
+0x5356	0x53C8	# <CJK>
+0x5357	0x5E7C	# <CJK>
+0x5358	0x8FC2	# <CJK>
+0x5359	0x6DE4	# <CJK>
+0x535A	0x4E8E	# <CJK>
+0x535B	0x76C2	# <CJK>
+0x535C	0x6986	# <CJK>
+0x535D	0x865E	# <CJK>
+0x535E	0x611A	# <CJK>
+0x535F	0x8F3F	# <CJK>
+0x5360	0x9918	# <CJK>
+0x5361	0x4FDE	# <CJK>
+0x5362	0x903E	# <CJK>
+0x5363	0x9B5A	# <CJK>
+0x5364	0x6109	# <CJK>
+0x5365	0x6E1D	# <CJK>
+0x5366	0x6F01	# <CJK>
+0x5367	0x9685	# <CJK>
+0x5368	0x4E88	# <CJK>
+0x5369	0x5A31	# <CJK>
+0x536A	0x96E8	# <CJK>
+0x536B	0x8207	# <CJK>
+0x536C	0x5DBC	# <CJK>
+0x536D	0x79B9	# <CJK>
+0x536E	0x5B87	# <CJK>
+0x536F	0x8A9E	# <CJK>
+0x5370	0x7FBD	# <CJK>
+0x5371	0x7389	# <CJK>
+0x5372	0x57DF	# <CJK>
+0x5373	0x828B	# <CJK>
+0x5374	0x9B31	# <CJK>
+0x5375	0x5401	# <CJK>
+0x5376	0x9047	# <CJK>
+0x5377	0x55BB	# <CJK>
+0x5378	0x5CEA	# <CJK>
+0x5379	0x5FA1	# <CJK>
+0x537A	0x6108	# <CJK>
+0x537B	0x6B32	# <CJK>
+0x537C	0x7344	# <CJK>
+0x537D	0x80B2	# <CJK>
+0x537E	0x8B7D	# <CJK>
+0x5421	0x6D74	# <CJK>
+0x5422	0x5BD3	# <CJK>
+0x5423	0x88D5	# <CJK>
+0x5424	0x9810	# <CJK>
+0x5425	0x8C6B	# <CJK>
+0x5426	0x99AD	# <CJK>
+0x5427	0x9D1B	# <CJK>
+0x5428	0x6DF5	# <CJK>
+0x5429	0x51A4	# <CJK>
+0x542A	0x5143	# <CJK>
+0x542B	0x57A3	# <CJK>
+0x542C	0x8881	# <CJK>
+0x542D	0x539F	# <CJK>
+0x542E	0x63F4	# <CJK>
+0x542F	0x8F45	# <CJK>
+0x5430	0x5712	# <CJK>
+0x5431	0x54E1	# <CJK>
+0x5432	0x5713	# <CJK>
+0x5433	0x733F	# <CJK>
+0x5434	0x6E90	# <CJK>
+0x5435	0x7DE3	# <CJK>
+0x5436	0x9060	# <CJK>
+0x5437	0x82D1	# <CJK>
+0x5438	0x9858	# <CJK>
+0x5439	0x6028	# <CJK>
+0x543A	0x9662	# <CJK>
+0x543B	0x66F0	# <CJK>
+0x543C	0x7D04	# <CJK>
+0x543D	0x8D8A	# <CJK>
+0x543E	0x8E8D	# <CJK>
+0x543F	0x9470	# <CJK>
+0x5440	0x5CB3	# <CJK>
+0x5441	0x7CA4	# <CJK>
+0x5442	0x6708	# <CJK>
+0x5443	0x60A6	# <CJK>
+0x5444	0x95B2	# <CJK>
+0x5445	0x8018	# <CJK>
+0x5446	0x96F2	# <CJK>
+0x5447	0x9116	# <CJK>
+0x5448	0x5300	# <CJK>
+0x5449	0x9695	# <CJK>
+0x544A	0x5141	# <CJK>
+0x544B	0x904B	# <CJK>
+0x544C	0x85F4	# <CJK>
+0x544D	0x9196	# <CJK>
+0x544E	0x6688	# <CJK>
+0x544F	0x97F5	# <CJK>
+0x5450	0x5B55	# <CJK>
+0x5451	0x531D	# <CJK>
+0x5452	0x7838	# <CJK>
+0x5453	0x96DC	# <CJK>
+0x5454	0x683D	# <CJK>
+0x5455	0x54C9	# <CJK>
+0x5456	0x707E	# <CJK>
+0x5457	0x5BB0	# <CJK>
+0x5458	0x8F09	# <CJK>
+0x5459	0x518D	# <CJK>
+0x545A	0x5728	# <CJK>
+0x545B	0x54B1	# <CJK>
+0x545C	0x6522	# <CJK>
+0x545D	0x66AB	# <CJK>
+0x545E	0x8D0A	# <CJK>
+0x545F	0x8D1C	# <CJK>
+0x5460	0x81DF	# <CJK>
+0x5461	0x846C	# <CJK>
+0x5462	0x906D	# <CJK>
+0x5463	0x7CDF	# <CJK>
+0x5464	0x947F	# <CJK>
+0x5465	0x85FB	# <CJK>
+0x5466	0x68D7	# <CJK>
+0x5467	0x65E9	# <CJK>
+0x5468	0x6FA1	# <CJK>
+0x5469	0x86A4	# <CJK>
+0x546A	0x8E81	# <CJK>
+0x546B	0x566A	# <CJK>
+0x546C	0x9020	# <CJK>
+0x546D	0x7682	# <CJK>
+0x546E	0x7AC8	# <CJK>
+0x546F	0x71E5	# <CJK>
+0x5470	0x8CAC	# <CJK>
+0x5471	0x64C7	# <CJK>
+0x5472	0x5247	# <CJK>
+0x5473	0x6FA4	# <CJK>
+0x5474	0x8CCA	# <CJK>
+0x5475	0x600E	# <CJK>
+0x5476	0x589E	# <CJK>
+0x5477	0x618E	# <CJK>
+0x5478	0x66FE	# <CJK>
+0x5479	0x8D08	# <CJK>
+0x547A	0x624E	# <CJK>
+0x547B	0x55B3	# <CJK>
+0x547C	0x6E23	# <CJK>
+0x547D	0x672D	# <CJK>
+0x547E	0x8ECB	# <CJK>
+0x5521	0x9358	# <CJK>
+0x5522	0x9598	# <CJK>
+0x5523	0x7728	# <CJK>
+0x5524	0x6805	# <CJK>
+0x5525	0x69A8	# <CJK>
+0x5526	0x548B	# <CJK>
+0x5527	0x4E4D	# <CJK>
+0x5528	0x70B8	# <CJK>
+0x5529	0x8A50	# <CJK>
+0x552A	0x6458	# <CJK>
+0x552B	0x9F4B	# <CJK>
+0x552C	0x5B85	# <CJK>
+0x552D	0x7A84	# <CJK>
+0x552E	0x50B5	# <CJK>
+0x552F	0x5BE8	# <CJK>
+0x5530	0x77BB	# <CJK>
+0x5531	0x6C08	# <CJK>
+0x5532	0x8A79	# <CJK>
+0x5533	0x7C98	# <CJK>
+0x5534	0x6CBE	# <CJK>
+0x5535	0x76DE	# <CJK>
+0x5536	0x65AC	# <CJK>
+0x5537	0x8F3E	# <CJK>
+0x5538	0x5D84	# <CJK>
+0x5539	0x5C55	# <CJK>
+0x553A	0x8638	# <CJK>
+0x553B	0x68E7	# <CJK>
+0x553C	0x5360	# <CJK>
+0x553D	0x6230	# <CJK>
+0x553E	0x7AD9	# <CJK>
+0x553F	0x6E5B	# <CJK>
+0x5540	0x7DBB	# <CJK>
+0x5541	0x6A1F	# <CJK>
+0x5542	0x7AE0	# <CJK>
+0x5543	0x5F70	# <CJK>
+0x5544	0x6F33	# <CJK>
+0x5545	0x5F35	# <CJK>
+0x5546	0x638C	# <CJK>
+0x5547	0x6F32	# <CJK>
+0x5548	0x6756	# <CJK>
+0x5549	0x4E08	# <CJK>
+0x554A	0x5E33	# <CJK>
+0x554B	0x8CEC	# <CJK>
+0x554C	0x4ED7	# <CJK>
+0x554D	0x8139	# <CJK>
+0x554E	0x7634	# <CJK>
+0x554F	0x969C	# <CJK>
+0x5550	0x62DB	# <CJK>
+0x5551	0x662D	# <CJK>
+0x5552	0x627E	# <CJK>
+0x5553	0x6CBC	# <CJK>
+0x5554	0x8D99	# <CJK>
+0x5555	0x7167	# <CJK>
+0x5556	0x7F69	# <CJK>
+0x5557	0x5146	# <CJK>
+0x5558	0x8087	# <CJK>
+0x5559	0x53EC	# <CJK>
+0x555A	0x906E	# <CJK>
+0x555B	0x6298	# <CJK>
+0x555C	0x54F2	# <CJK>
+0x555D	0x87C4	# <CJK>
+0x555E	0x8F4D	# <CJK>
+0x555F	0x8005	# <CJK>
+0x5560	0x937A	# <CJK>
+0x5561	0x8517	# <CJK>
+0x5562	0x9019	# <CJK>
+0x5563	0x6D59	# <CJK>
+0x5564	0x73CD	# <CJK>
+0x5565	0x659F	# <CJK>
+0x5566	0x771F	# <CJK>
+0x5567	0x7504	# <CJK>
+0x5568	0x7827	# <CJK>
+0x5569	0x81FB	# <CJK>
+0x556A	0x8C9E	# <CJK>
+0x556B	0x91DD	# <CJK>
+0x556C	0x5075	# <CJK>
+0x556D	0x6795	# <CJK>
+0x556E	0x75B9	# <CJK>
+0x556F	0x8A3A	# <CJK>
+0x5570	0x9707	# <CJK>
+0x5571	0x632F	# <CJK>
+0x5572	0x93AE	# <CJK>
+0x5573	0x9663	# <CJK>
+0x5574	0x84B8	# <CJK>
+0x5575	0x6399	# <CJK>
+0x5576	0x775C	# <CJK>
+0x5577	0x5F81	# <CJK>
+0x5578	0x7319	# <CJK>
+0x5579	0x722D	# <CJK>
+0x557A	0x6014	# <CJK>
+0x557B	0x6574	# <CJK>
+0x557C	0x62EF	# <CJK>
+0x557D	0x6B63	# <CJK>
+0x557E	0x653F	# <CJK>
+0x5621	0x5E40	# <CJK>
+0x5622	0x7665	# <CJK>
+0x5623	0x912D	# <CJK>
+0x5624	0x8B49	# <CJK>
+0x5625	0x829D	# <CJK>
+0x5626	0x679D	# <CJK>
+0x5627	0x652F	# <CJK>
+0x5628	0x5431	# <CJK>
+0x5629	0x8718	# <CJK>
+0x562A	0x77E5	# <CJK>
+0x562B	0x80A2	# <CJK>
+0x562C	0x8102	# <CJK>
+0x562D	0x6C41	# <CJK>
+0x562E	0x4E4B	# <CJK>
+0x562F	0x7E54	# <CJK>
+0x5630	0x8077	# <CJK>
+0x5631	0x76F4	# <CJK>
+0x5632	0x690D	# <CJK>
+0x5633	0x6B96	# <CJK>
+0x5634	0x57F7	# <CJK>
+0x5635	0x503C	# <CJK>
+0x5636	0x4F84	# <CJK>
+0x5637	0x5740	# <CJK>
+0x5638	0x6307	# <CJK>
+0x5639	0x6B62	# <CJK>
+0x563A	0x8DBE	# <CJK>
+0x563B	0x8879	# <CJK>
+0x563C	0x65E8	# <CJK>
+0x563D	0x7D19	# <CJK>
+0x563E	0x5FD7	# <CJK>
+0x563F	0x646F	# <CJK>
+0x5640	0x64F2	# <CJK>
+0x5641	0x81F3	# <CJK>
+0x5642	0x81F4	# <CJK>
+0x5643	0x7F6E	# <CJK>
+0x5644	0x5E5F	# <CJK>
+0x5645	0x5CD9	# <CJK>
+0x5646	0x5236	# <CJK>
+0x5647	0x667A	# <CJK>
+0x5648	0x79E9	# <CJK>
+0x5649	0x7A1A	# <CJK>
+0x564A	0x8CEA	# <CJK>
+0x564B	0x7099	# <CJK>
+0x564C	0x75D4	# <CJK>
+0x564D	0x6EEF	# <CJK>
+0x564E	0x6CBB	# <CJK>
+0x564F	0x7A92	# <CJK>
+0x5650	0x4E2D	# <CJK>
+0x5651	0x76C5	# <CJK>
+0x5652	0x5FE0	# <CJK>
+0x5653	0x9418	# <CJK>
+0x5654	0x8877	# <CJK>
+0x5655	0x7D42	# <CJK>
+0x5656	0x7A2E	# <CJK>
+0x5657	0x816B	# <CJK>
+0x5658	0x91CD	# <CJK>
+0x5659	0x4EF2	# <CJK>
+0x565A	0x8846	# <CJK>
+0x565B	0x821F	# <CJK>
+0x565C	0x5468	# <CJK>
+0x565D	0x5DDE	# <CJK>
+0x565E	0x6D32	# <CJK>
+0x565F	0x8B05	# <CJK>
+0x5660	0x7CA5	# <CJK>
+0x5661	0x8EF8	# <CJK>
+0x5662	0x8098	# <CJK>
+0x5663	0x5E1A	# <CJK>
+0x5664	0x5492	# <CJK>
+0x5665	0x76BA	# <CJK>
+0x5666	0x5B99	# <CJK>
+0x5667	0x665D	# <CJK>
+0x5668	0x9A5F	# <CJK>
+0x5669	0x73E0	# <CJK>
+0x566A	0x682A	# <CJK>
+0x566B	0x86DB	# <CJK>
+0x566C	0x6731	# <CJK>
+0x566D	0x732A	# <CJK>
+0x566E	0x8AF8	# <CJK>
+0x566F	0x8A85	# <CJK>
+0x5670	0x9010	# <CJK>
+0x5671	0x7AF9	# <CJK>
+0x5672	0x71ED	# <CJK>
+0x5673	0x716E	# <CJK>
+0x5674	0x62C4	# <CJK>
+0x5675	0x77DA	# <CJK>
+0x5676	0x56D1	# <CJK>
+0x5677	0x4E3B	# <CJK>
+0x5678	0x8457	# <CJK>
+0x5679	0x67F1	# <CJK>
+0x567A	0x52A9	# <CJK>
+0x567B	0x86C0	# <CJK>
+0x567C	0x8CAF	# <CJK>
+0x567D	0x9444	# <CJK>
+0x567E	0x7BC9	# <CJK>
+0x5721	0x4F4F	# <CJK>
+0x5722	0x6CE8	# <CJK>
+0x5723	0x795D	# <CJK>
+0x5724	0x99D0	# <CJK>
+0x5725	0x6293	# <CJK>
+0x5726	0x722A	# <CJK>
+0x5727	0x62FD	# <CJK>
+0x5728	0x5C08	# <CJK>
+0x5729	0x78DA	# <CJK>
+0x572A	0x8F49	# <CJK>
+0x572B	0x64B0	# <CJK>
+0x572C	0x8CFA	# <CJK>
+0x572D	0x7BC6	# <CJK>
+0x572E	0x6A01	# <CJK>
+0x572F	0x838A	# <CJK>
+0x5730	0x88DD	# <CJK>
+0x5731	0x599D	# <CJK>
+0x5732	0x649E	# <CJK>
+0x5733	0x58EF	# <CJK>
+0x5734	0x72C0	# <CJK>
+0x5735	0x690E	# <CJK>
+0x5736	0x9310	# <CJK>
+0x5737	0x8FFD	# <CJK>
+0x5738	0x8D05	# <CJK>
+0x5739	0x589C	# <CJK>
+0x573A	0x7DB4	# <CJK>
+0x573B	0x8AC4	# <CJK>
+0x573C	0x6E96	# <CJK>
+0x573D	0x6349	# <CJK>
+0x573E	0x62D9	# <CJK>
+0x573F	0x5353	# <CJK>
+0x5740	0x684C	# <CJK>
+0x5741	0x7422	# <CJK>
+0x5742	0x8301	# <CJK>
+0x5743	0x914C	# <CJK>
+0x5744	0x5544	# <CJK>
+0x5745	0x7740	# <CJK>
+0x5746	0x707C	# <CJK>
+0x5747	0x6FC1	# <CJK>
+0x5748	0x5179	# <CJK>
+0x5749	0x54A8	# <CJK>
+0x574A	0x8CC7	# <CJK>
+0x574B	0x59FF	# <CJK>
+0x574C	0x6ECB	# <CJK>
+0x574D	0x6DC4	# <CJK>
+0x574E	0x5B5C	# <CJK>
+0x574F	0x7D2B	# <CJK>
+0x5750	0x4ED4	# <CJK>
+0x5751	0x7C7D	# <CJK>
+0x5752	0x6ED3	# <CJK>
+0x5753	0x5B50	# <CJK>
+0x5754	0x81EA	# <CJK>
+0x5755	0x6F2C	# <CJK>
+0x5756	0x5B57	# <CJK>
+0x5757	0x9B03	# <CJK>
+0x5758	0x68D5	# <CJK>
+0x5759	0x8E2A	# <CJK>
+0x575A	0x5B97	# <CJK>
+0x575B	0x7D9C	# <CJK>
+0x575C	0x7E3D	# <CJK>
+0x575D	0x7E31	# <CJK>
+0x575E	0x9112	# <CJK>
+0x575F	0x8D70	# <CJK>
+0x5760	0x594F	# <CJK>
+0x5761	0x63CD	# <CJK>
+0x5762	0x79DF	# <CJK>
+0x5763	0x8DB3	# <CJK>
+0x5764	0x5352	# <CJK>
+0x5765	0x65CF	# <CJK>
+0x5766	0x7956	# <CJK>
+0x5767	0x8A5B	# <CJK>
+0x5768	0x963B	# <CJK>
+0x5769	0x7D44	# <CJK>
+0x576A	0x947D	# <CJK>
+0x576B	0x7E82	# <CJK>
+0x576C	0x5634	# <CJK>
+0x576D	0x9189	# <CJK>
+0x576E	0x6700	# <CJK>
+0x576F	0x7F6A	# <CJK>
+0x5770	0x5C0A	# <CJK>
+0x5771	0x9075	# <CJK>
+0x5772	0x6628	# <CJK>
+0x5773	0x5DE6	# <CJK>
+0x5774	0x4F50	# <CJK>
+0x5775	0x67DE	# <CJK>
+0x5776	0x505A	# <CJK>
+0x5777	0x4F5C	# <CJK>
+0x5778	0x5750	# <CJK>
+0x5779	0x5EA7	# <CJK>
+0x5821	0x4E8D	# <CJK>
+0x5822	0x4E0C	# <CJK>
+0x5823	0x5140	# <CJK>
+0x5824	0x4E10	# <CJK>
+0x5825	0x5EFF	# <CJK>
+0x5826	0x5345	# <CJK>
+0x5827	0x4E15	# <CJK>
+0x5828	0x4E98	# <CJK>
+0x5829	0x4E1E	# <CJK>
+0x582A	0x9B32	# <CJK>
+0x582B	0x5B6C	# <CJK>
+0x582C	0x5669	# <CJK>
+0x582D	0x4E28	# <CJK>
+0x582E	0x79BA	# <CJK>
+0x582F	0x4E3F	# <CJK>
+0x5830	0x5315	# <CJK>
+0x5831	0x4E47	# <CJK>
+0x5832	0x592D	# <CJK>
+0x5833	0x723B	# <CJK>
+0x5834	0x536E	# <CJK>
+0x5835	0x6C10	# <CJK>
+0x5836	0x56DF	# <CJK>
+0x5837	0x80E4	# <CJK>
+0x5838	0x9997	# <CJK>
+0x5839	0x6BD3	# <CJK>
+0x583A	0x777E	# <CJK>
+0x583B	0x9F17	# <CJK>
+0x583C	0x4E36	# <CJK>
+0x583D	0x4E9F	# <CJK>
+0x583E	0x9F10	# <CJK>
+0x583F	0x4E5C	# <CJK>
+0x5840	0x4E69	# <CJK>
+0x5841	0x4E93	# <CJK>
+0x5842	0x8288	# <CJK>
+0x5843	0x5B5B	# <CJK>
+0x5844	0x55C7	# <CJK>
+0x5845	0x560F	# <CJK>
+0x5846	0x4EC4	# <CJK>
+0x5847	0x5399	# <CJK>
+0x5848	0x539D	# <CJK>
+0x5849	0x53B4	# <CJK>
+0x584A	0x53A5	# <CJK>
+0x584B	0x53AE	# <CJK>
+0x584C	0x9768	# <CJK>
+0x584D	0x8D0B	# <CJK>
+0x584E	0x531A	# <CJK>
+0x584F	0x53F5	# <CJK>
+0x5850	0x532D	# <CJK>
+0x5851	0x5331	# <CJK>
+0x5852	0x533E	# <CJK>
+0x5853	0x8CFE	# <CJK>
+0x5854	0x5366	# <CJK>
+0x5855	0x5363	# <CJK>
+0x5856	0x5202	# <CJK>
+0x5857	0x5208	# <CJK>
+0x5858	0x520E	# <CJK>
+0x5859	0x5244	# <CJK>
+0x585A	0x5233	# <CJK>
+0x585B	0x528C	# <CJK>
+0x585C	0x5274	# <CJK>
+0x585D	0x524C	# <CJK>
+0x585E	0x525E	# <CJK>
+0x585F	0x5261	# <CJK>
+0x5860	0x525C	# <CJK>
+0x5861	0x84AF	# <CJK>
+0x5862	0x527D	# <CJK>
+0x5863	0x5282	# <CJK>
+0x5864	0x5281	# <CJK>
+0x5865	0x5290	# <CJK>
+0x5866	0x5293	# <CJK>
+0x5867	0x5182	# <CJK>
+0x5868	0x7F54	# <CJK>
+0x5869	0x4EBB	# <CJK>
+0x586A	0x4EC3	# <CJK>
+0x586B	0x4EC9	# <CJK>
+0x586C	0x4EC2	# <CJK>
+0x586D	0x4EE8	# <CJK>
+0x586E	0x4EE1	# <CJK>
+0x586F	0x4EEB	# <CJK>
+0x5870	0x4EDE	# <CJK>
+0x5871	0x50B4	# <CJK>
+0x5872	0x4EF3	# <CJK>
+0x5873	0x4F22	# <CJK>
+0x5874	0x4F64	# <CJK>
+0x5875	0x4EF5	# <CJK>
+0x5876	0x5000	# <CJK>
+0x5877	0x5096	# <CJK>
+0x5878	0x4F09	# <CJK>
+0x5879	0x4F47	# <CJK>
+0x587A	0x4F5E	# <CJK>
+0x587B	0x4F67	# <CJK>
+0x587C	0x6538	# <CJK>
+0x587D	0x4F5A	# <CJK>
+0x587E	0x4F5D	# <CJK>
+0x5921	0x4F5F	# <CJK>
+0x5922	0x4F57	# <CJK>
+0x5923	0x4F32	# <CJK>
+0x5924	0x4F3D	# <CJK>
+0x5925	0x4F76	# <CJK>
+0x5926	0x4F74	# <CJK>
+0x5927	0x4F91	# <CJK>
+0x5928	0x4F89	# <CJK>
+0x5929	0x4F83	# <CJK>
+0x592A	0x4F8F	# <CJK>
+0x592B	0x4F7E	# <CJK>
+0x592C	0x4F7B	# <CJK>
+0x592D	0x5115	# <CJK>
+0x592E	0x4F7C	# <CJK>
+0x592F	0x5102	# <CJK>
+0x5930	0x4F94	# <CJK>
+0x5931	0x5114	# <CJK>
+0x5932	0x513C	# <CJK>
+0x5933	0x5137	# <CJK>
+0x5934	0x4FC5	# <CJK>
+0x5935	0x4FDA	# <CJK>
+0x5936	0x4FE3	# <CJK>
+0x5937	0x4FDC	# <CJK>
+0x5938	0x4FD1	# <CJK>
+0x5939	0x4FDF	# <CJK>
+0x593A	0x4FF8	# <CJK>
+0x593B	0x5029	# <CJK>
+0x593C	0x504C	# <CJK>
+0x593D	0x4FF3	# <CJK>
+0x593E	0x502C	# <CJK>
+0x593F	0x500F	# <CJK>
+0x5940	0x502E	# <CJK>
+0x5941	0x502D	# <CJK>
+0x5942	0x4FFE	# <CJK>
+0x5943	0x501C	# <CJK>
+0x5944	0x500C	# <CJK>
+0x5945	0x5025	# <CJK>
+0x5946	0x5028	# <CJK>
+0x5947	0x50E8	# <CJK>
+0x5948	0x5043	# <CJK>
+0x5949	0x5055	# <CJK>
+0x594A	0x5048	# <CJK>
+0x594B	0x504E	# <CJK>
+0x594C	0x506C	# <CJK>
+0x594D	0x50C2	# <CJK>
+0x594E	0x513B	# <CJK>
+0x594F	0x5110	# <CJK>
+0x5950	0x513A	# <CJK>
+0x5951	0x50BA	# <CJK>
+0x5952	0x50D6	# <CJK>
+0x5953	0x5106	# <CJK>
+0x5954	0x50ED	# <CJK>
+0x5955	0x50EC	# <CJK>
+0x5956	0x50E6	# <CJK>
+0x5957	0x50EE	# <CJK>
+0x5958	0x5107	# <CJK>
+0x5959	0x510B	# <CJK>
+0x595A	0x4EDD	# <CJK>
+0x595B	0x6C3D	# <CJK>
+0x595C	0x4F58	# <CJK>
+0x595D	0x50C9	# <CJK>
+0x595E	0x4FCE	# <CJK>
+0x595F	0x9FA0	# <CJK>
+0x5960	0x6C46	# <CJK>
+0x5961	0x7CF4	# <CJK>
+0x5962	0x516E	# <CJK>
+0x5963	0x5DFD	# <CJK>
+0x5964	0x9ECC	# <CJK>
+0x5965	0x9998	# <CJK>
+0x5966	0x56C5	# <CJK>
+0x5967	0x5914	# <CJK>
+0x5968	0x52F9	# <CJK>
+0x5969	0x530D	# <CJK>
+0x596A	0x8A07	# <CJK>
+0x596B	0x5310	# <CJK>
+0x596C	0x9CEC	# <CJK>
+0x596D	0x5919	# <CJK>
+0x596E	0x5155	# <CJK>
+0x596F	0x4EA0	# <CJK>
+0x5970	0x5156	# <CJK>
+0x5971	0x4EB3	# <CJK>
+0x5972	0x886E	# <CJK>
+0x5973	0x88A4	# <CJK>
+0x5974	0x893B	# <CJK>
+0x5975	0x81E0	# <CJK>
+0x5976	0x88D2	# <CJK>
+0x5977	0x7980	# <CJK>
+0x5978	0x5B34	# <CJK>
+0x5979	0x8803	# <CJK>
+0x597A	0x7FB8	# <CJK>
+0x597B	0x51AB	# <CJK>
+0x597C	0x51B1	# <CJK>
+0x597D	0x51BD	# <CJK>
+0x597E	0x51BC	# <CJK>
+0x5A21	0x51C7	# <CJK>
+0x5A22	0x5196	# <CJK>
+0x5A23	0x51A2	# <CJK>
+0x5A24	0x51A5	# <CJK>
+0x5A25	0x8A01	# <CJK>
+0x5A26	0x8A10	# <CJK>
+0x5A27	0x8A0C	# <CJK>
+0x5A28	0x8A15	# <CJK>
+0x5A29	0x8B33	# <CJK>
+0x5A2A	0x8A4E	# <CJK>
+0x5A2B	0x8A25	# <CJK>
+0x5A2C	0x8A41	# <CJK>
+0x5A2D	0x8A36	# <CJK>
+0x5A2E	0x8A46	# <CJK>
+0x5A2F	0x8A54	# <CJK>
+0x5A30	0x8A58	# <CJK>
+0x5A31	0x8A52	# <CJK>
+0x5A32	0x8A86	# <CJK>
+0x5A33	0x8A84	# <CJK>
+0x5A34	0x8A7F	# <CJK>
+0x5A35	0x8A70	# <CJK>
+0x5A36	0x8A7C	# <CJK>
+0x5A37	0x8A75	# <CJK>
+0x5A38	0x8A6C	# <CJK>
+0x5A39	0x8A6E	# <CJK>
+0x5A3A	0x8ACD	# <CJK>
+0x5A3B	0x8AE2	# <CJK>
+0x5A3C	0x8A61	# <CJK>
+0x5A3D	0x8A9A	# <CJK>
+0x5A3E	0x8AA5	# <CJK>
+0x5A3F	0x8A91	# <CJK>
+0x5A40	0x8A92	# <CJK>
+0x5A41	0x8ACF	# <CJK>
+0x5A42	0x8AD1	# <CJK>
+0x5A43	0x8AC9	# <CJK>
+0x5A44	0x8ADB	# <CJK>
+0x5A45	0x8AD7	# <CJK>
+0x5A46	0x8AC2	# <CJK>
+0x5A47	0x8AB6	# <CJK>
+0x5A48	0x8AF6	# <CJK>
+0x5A49	0x8AEB	# <CJK>
+0x5A4A	0x8B14	# <CJK>
+0x5A4B	0x8B01	# <CJK>
+0x5A4C	0x8AE4	# <CJK>
+0x5A4D	0x8AED	# <CJK>
+0x5A4E	0x8AFC	# <CJK>
+0x5A4F	0x8AF3	# <CJK>
+0x5A50	0x8AE6	# <CJK>
+0x5A51	0x8AEE	# <CJK>
+0x5A52	0x8ADE	# <CJK>
+0x5A53	0x8B28	# <CJK>
+0x5A54	0x8B9C	# <CJK>
+0x5A55	0x8B16	# <CJK>
+0x5A56	0x8B1A	# <CJK>
+0x5A57	0x8B10	# <CJK>
+0x5A58	0x8B2B	# <CJK>
+0x5A59	0x8B2D	# <CJK>
+0x5A5A	0x8B56	# <CJK>
+0x5A5B	0x8B59	# <CJK>
+0x5A5C	0x8B4E	# <CJK>
+0x5A5D	0x8B9E	# <CJK>
+0x5A5E	0x8B6B	# <CJK>
+0x5A5F	0x8B96	# <CJK>
+0x5A60	0x5369	# <CJK>
+0x5A61	0x537A	# <CJK>
+0x5A62	0x961D	# <CJK>
+0x5A63	0x9622	# <CJK>
+0x5A64	0x9621	# <CJK>
+0x5A65	0x9631	# <CJK>
+0x5A66	0x962A	# <CJK>
+0x5A67	0x963D	# <CJK>
+0x5A68	0x963C	# <CJK>
+0x5A69	0x9642	# <CJK>
+0x5A6A	0x9658	# <CJK>
+0x5A6B	0x9654	# <CJK>
+0x5A6C	0x965F	# <CJK>
+0x5A6D	0x9689	# <CJK>
+0x5A6E	0x966C	# <CJK>
+0x5A6F	0x9672	# <CJK>
+0x5A70	0x9674	# <CJK>
+0x5A71	0x9688	# <CJK>
+0x5A72	0x968D	# <CJK>
+0x5A73	0x9697	# <CJK>
+0x5A74	0x96B0	# <CJK>
+0x5A75	0x9097	# <CJK>
+0x5A76	0x909B	# <CJK>
+0x5A77	0x913A	# <CJK>
+0x5A78	0x9099	# <CJK>
+0x5A79	0x9114	# <CJK>
+0x5A7A	0x90A1	# <CJK>
+0x5A7B	0x90B4	# <CJK>
+0x5A7C	0x90B3	# <CJK>
+0x5A7D	0x90B6	# <CJK>
+0x5A7E	0x9134	# <CJK>
+0x5B21	0x90B8	# <CJK>
+0x5B22	0x90B0	# <CJK>
+0x5B23	0x90DF	# <CJK>
+0x5B24	0x90C5	# <CJK>
+0x5B25	0x90BE	# <CJK>
+0x5B26	0x9136	# <CJK>
+0x5B27	0x90C4	# <CJK>
+0x5B28	0x90C7	# <CJK>
+0x5B29	0x9106	# <CJK>
+0x5B2A	0x9148	# <CJK>
+0x5B2B	0x90E2	# <CJK>
+0x5B2C	0x90DC	# <CJK>
+0x5B2D	0x90D7	# <CJK>
+0x5B2E	0x90DB	# <CJK>
+0x5B2F	0x90EB	# <CJK>
+0x5B30	0x90EF	# <CJK>
+0x5B31	0x90FE	# <CJK>
+0x5B32	0x9104	# <CJK>
+0x5B33	0x9122	# <CJK>
+0x5B34	0x911E	# <CJK>
+0x5B35	0x9123	# <CJK>
+0x5B36	0x9131	# <CJK>
+0x5B37	0x912F	# <CJK>
+0x5B38	0x9139	# <CJK>
+0x5B39	0x9143	# <CJK>
+0x5B3A	0x9146	# <CJK>
+0x5B3B	0x82BB	# <CJK>
+0x5B3C	0x5950	# <CJK>
+0x5B3D	0x52F1	# <CJK>
+0x5B3E	0x52AC	# <CJK>
+0x5B3F	0x52AD	# <CJK>
+0x5B40	0x52BE	# <CJK>
+0x5B41	0x54FF	# <CJK>
+0x5B42	0x52D0	# <CJK>
+0x5B43	0x52D6	# <CJK>
+0x5B44	0x52F0	# <CJK>
+0x5B45	0x53DF	# <CJK>
+0x5B46	0x71EE	# <CJK>
+0x5B47	0x77CD	# <CJK>
+0x5B48	0x5EF4	# <CJK>
+0x5B49	0x51F5	# <CJK>
+0x5B4A	0x51FC	# <CJK>
+0x5B4B	0x9B2F	# <CJK>
+0x5B4C	0x53B6	# <CJK>
+0x5B4D	0x5F01	# <CJK>
+0x5B4E	0x755A	# <CJK>
+0x5B4F	0x5DF0	# <CJK>
+0x5B50	0x574C	# <CJK>
+0x5B51	0x580A	# <CJK>
+0x5B52	0x57A1	# <CJK>
+0x5B53	0x587E	# <CJK>
+0x5B54	0x58BC	# <CJK>
+0x5B55	0x58C5	# <CJK>
+0x5B56	0x58D1	# <CJK>
+0x5B57	0x5729	# <CJK>
+0x5B58	0x572C	# <CJK>
+0x5B59	0x572A	# <CJK>
+0x5B5A	0x5733	# <CJK>
+0x5B5B	0x58D9	# <CJK>
+0x5B5C	0x572E	# <CJK>
+0x5B5D	0x572F	# <CJK>
+0x5B5E	0x58E2	# <CJK>
+0x5B5F	0x573B	# <CJK>
+0x5B60	0x5742	# <CJK>
+0x5B61	0x5769	# <CJK>
+0x5B62	0x58E0	# <CJK>
+0x5B63	0x576B	# <CJK>
+0x5B64	0x58DA	# <CJK>
+0x5B65	0x577C	# <CJK>
+0x5B66	0x577B	# <CJK>
+0x5B67	0x5768	# <CJK>
+0x5B68	0x576D	# <CJK>
+0x5B69	0x5776	# <CJK>
+0x5B6A	0x5773	# <CJK>
+0x5B6B	0x57E1	# <CJK>
+0x5B6C	0x57A4	# <CJK>
+0x5B6D	0x578C	# <CJK>
+0x5B6E	0x584F	# <CJK>
+0x5B6F	0x57CF	# <CJK>
+0x5B70	0x57A7	# <CJK>
+0x5B71	0x5816	# <CJK>
+0x5B72	0x5793	# <CJK>
+0x5B73	0x57A0	# <CJK>
+0x5B74	0x57D5	# <CJK>
+0x5B75	0x5852	# <CJK>
+0x5B76	0x581D	# <CJK>
+0x5B77	0x5864	# <CJK>
+0x5B78	0x57D2	# <CJK>
+0x5B79	0x57B8	# <CJK>
+0x5B7A	0x57F4	# <CJK>
+0x5B7B	0x57EF	# <CJK>
+0x5B7C	0x57F8	# <CJK>
+0x5B7D	0x57E4	# <CJK>
+0x5B7E	0x57DD	# <CJK>
+0x5C21	0x580B	# <CJK>
+0x5C22	0x580D	# <CJK>
+0x5C23	0x57FD	# <CJK>
+0x5C24	0x57ED	# <CJK>
+0x5C25	0x5800	# <CJK>
+0x5C26	0x581E	# <CJK>
+0x5C27	0x5819	# <CJK>
+0x5C28	0x5844	# <CJK>
+0x5C29	0x5820	# <CJK>
+0x5C2A	0x5865	# <CJK>
+0x5C2B	0x586C	# <CJK>
+0x5C2C	0x5881	# <CJK>
+0x5C2D	0x5889	# <CJK>
+0x5C2E	0x589A	# <CJK>
+0x5C2F	0x5880	# <CJK>
+0x5C30	0x99A8	# <CJK>
+0x5C31	0x9F19	# <CJK>
+0x5C32	0x61FF	# <CJK>
+0x5C33	0x8279	# <CJK>
+0x5C34	0x827D	# <CJK>
+0x5C35	0x827F	# <CJK>
+0x5C36	0x828F	# <CJK>
+0x5C37	0x828A	# <CJK>
+0x5C38	0x82A8	# <CJK>
+0x5C39	0x8284	# <CJK>
+0x5C3A	0x828E	# <CJK>
+0x5C3B	0x8291	# <CJK>
+0x5C3C	0x858C	# <CJK>
+0x5C3D	0x8299	# <CJK>
+0x5C3E	0x82AB	# <CJK>
+0x5C3F	0x8553	# <CJK>
+0x5C40	0x82BE	# <CJK>
+0x5C41	0x82B0	# <CJK>
+0x5C42	0x85F6	# <CJK>
+0x5C43	0x82CA	# <CJK>
+0x5C44	0x82E3	# <CJK>
+0x5C45	0x8298	# <CJK>
+0x5C46	0x82B7	# <CJK>
+0x5C47	0x82AE	# <CJK>
+0x5C48	0x83A7	# <CJK>
+0x5C49	0x8407	# <CJK>
+0x5C4A	0x84EF	# <CJK>
+0x5C4B	0x82A9	# <CJK>
+0x5C4C	0x82B4	# <CJK>
+0x5C4D	0x82A1	# <CJK>
+0x5C4E	0x82AA	# <CJK>
+0x5C4F	0x829F	# <CJK>
+0x5C50	0x82C4	# <CJK>
+0x5C51	0x82E7	# <CJK>
+0x5C52	0x82A4	# <CJK>
+0x5C53	0x82E1	# <CJK>
+0x5C54	0x8309	# <CJK>
+0x5C55	0x82F7	# <CJK>
+0x5C56	0x82E4	# <CJK>
+0x5C57	0x8622	# <CJK>
+0x5C58	0x8307	# <CJK>
+0x5C59	0x82DC	# <CJK>
+0x5C5A	0x82F4	# <CJK>
+0x5C5B	0x82D2	# <CJK>
+0x5C5C	0x82D8	# <CJK>
+0x5C5D	0x830C	# <CJK>
+0x5C5E	0x82FB	# <CJK>
+0x5C5F	0x82D3	# <CJK>
+0x5C60	0x8526	# <CJK>
+0x5C61	0x831A	# <CJK>
+0x5C62	0x8306	# <CJK>
+0x5C63	0x584B	# <CJK>
+0x5C64	0x7162	# <CJK>
+0x5C65	0x82E0	# <CJK>
+0x5C66	0x82D5	# <CJK>
+0x5C67	0x831C	# <CJK>
+0x5C68	0x8351	# <CJK>
+0x5C69	0x8558	# <CJK>
+0x5C6A	0x84FD	# <CJK>
+0x5C6B	0x8308	# <CJK>
+0x5C6C	0x8392	# <CJK>
+0x5C6D	0x833C	# <CJK>
+0x5C6E	0x8334	# <CJK>
+0x5C6F	0x8331	# <CJK>
+0x5C70	0x839B	# <CJK>
+0x5C71	0x854E	# <CJK>
+0x5C72	0x832F	# <CJK>
+0x5C73	0x834F	# <CJK>
+0x5C74	0x8347	# <CJK>
+0x5C75	0x8343	# <CJK>
+0x5C76	0x8588	# <CJK>
+0x5C77	0x8340	# <CJK>
+0x5C78	0x8317	# <CJK>
+0x5C79	0x85BA	# <CJK>
+0x5C7A	0x832D	# <CJK>
+0x5C7B	0x833A	# <CJK>
+0x5C7C	0x8333	# <CJK>
+0x5C7D	0x7296	# <CJK>
+0x5C7E	0x6ECE	# <CJK>
+0x5D21	0x8541	# <CJK>
+0x5D22	0x831B	# <CJK>
+0x5D23	0x85CE	# <CJK>
+0x5D24	0x8552	# <CJK>
+0x5D25	0x84C0	# <CJK>
+0x5D26	0x8452	# <CJK>
+0x5D27	0x8464	# <CJK>
+0x5D28	0x83B0	# <CJK>
+0x5D29	0x8378	# <CJK>
+0x5D2A	0x8494	# <CJK>
+0x5D2B	0x8435	# <CJK>
+0x5D2C	0x83A0	# <CJK>
+0x5D2D	0x83AA	# <CJK>
+0x5D2E	0x8393	# <CJK>
+0x5D2F	0x839C	# <CJK>
+0x5D30	0x8385	# <CJK>
+0x5D31	0x837C	# <CJK>
+0x5D32	0x859F	# <CJK>
+0x5D33	0x83A9	# <CJK>
+0x5D34	0x837D	# <CJK>
+0x5D35	0x8555	# <CJK>
+0x5D36	0x837B	# <CJK>
+0x5D37	0x8398	# <CJK>
+0x5D38	0x839E	# <CJK>
+0x5D39	0x83A8	# <CJK>
+0x5D3A	0x9DAF	# <CJK>
+0x5D3B	0x8493	# <CJK>
+0x5D3C	0x83C1	# <CJK>
+0x5D3D	0x8401	# <CJK>
+0x5D3E	0x83E5	# <CJK>
+0x5D3F	0x83D8	# <CJK>
+0x5D40	0x5807	# <CJK>
+0x5D41	0x8418	# <CJK>
+0x5D42	0x840B	# <CJK>
+0x5D43	0x83DD	# <CJK>
+0x5D44	0x83FD	# <CJK>
+0x5D45	0x83D6	# <CJK>
+0x5D46	0x841C	# <CJK>
+0x5D47	0x8438	# <CJK>
+0x5D48	0x8411	# <CJK>
+0x5D49	0x8406	# <CJK>
+0x5D4A	0x83D4	# <CJK>
+0x5D4B	0x83DF	# <CJK>
+0x5D4C	0x840F	# <CJK>
+0x5D4D	0x8403	# <CJK>
+0x5D4E	0x83F8	# <CJK>
+0x5D4F	0x83F9	# <CJK>
+0x5D50	0x83EA	# <CJK>
+0x5D51	0x83C5	# <CJK>
+0x5D52	0x83C0	# <CJK>
+0x5D53	0x7E08	# <CJK>
+0x5D54	0x83F0	# <CJK>
+0x5D55	0x83E1	# <CJK>
+0x5D56	0x845C	# <CJK>
+0x5D57	0x8451	# <CJK>
+0x5D58	0x845A	# <CJK>
+0x5D59	0x8459	# <CJK>
+0x5D5A	0x8473	# <CJK>
+0x5D5B	0x8546	# <CJK>
+0x5D5C	0x8488	# <CJK>
+0x5D5D	0x847A	# <CJK>
+0x5D5E	0x8562	# <CJK>
+0x5D5F	0x8478	# <CJK>
+0x5D60	0x843C	# <CJK>
+0x5D61	0x8446	# <CJK>
+0x5D62	0x8469	# <CJK>
+0x5D63	0x8476	# <CJK>
+0x5D64	0x851E	# <CJK>
+0x5D65	0x848E	# <CJK>
+0x5D66	0x8431	# <CJK>
+0x5D67	0x846D	# <CJK>
+0x5D68	0x84C1	# <CJK>
+0x5D69	0x84CD	# <CJK>
+0x5D6A	0x84D0	# <CJK>
+0x5D6B	0x9A40	# <CJK>
+0x5D6C	0x84BD	# <CJK>
+0x5D6D	0x84D3	# <CJK>
+0x5D6E	0x84CA	# <CJK>
+0x5D6F	0x84BF	# <CJK>
+0x5D70	0x84BA	# <CJK>
+0x5D71	0x863A	# <CJK>
+0x5D72	0x84A1	# <CJK>
+0x5D73	0x84B9	# <CJK>
+0x5D74	0x84B4	# <CJK>
+0x5D75	0x8497	# <CJK>
+0x5D76	0x93A3	# <CJK>
+0x5D77	0x8577	# <CJK>
+0x5D78	0x850C	# <CJK>
+0x5D79	0x750D	# <CJK>
+0x5D7A	0x8538	# <CJK>
+0x5D7B	0x84F0	# <CJK>
+0x5D7C	0x861E	# <CJK>
+0x5D7D	0x851F	# <CJK>
+0x5D7E	0x85FA	# <CJK>
+0x5E21	0x8556	# <CJK>
+0x5E22	0x853B	# <CJK>
+0x5E23	0x84FF	# <CJK>
+0x5E24	0x84FC	# <CJK>
+0x5E25	0x8559	# <CJK>
+0x5E26	0x8548	# <CJK>
+0x5E27	0x8568	# <CJK>
+0x5E28	0x8564	# <CJK>
+0x5E29	0x855E	# <CJK>
+0x5E2A	0x857A	# <CJK>
+0x5E2B	0x77A2	# <CJK>
+0x5E2C	0x8543	# <CJK>
+0x5E2D	0x8604	# <CJK>
+0x5E2E	0x857B	# <CJK>
+0x5E2F	0x85A4	# <CJK>
+0x5E30	0x85A8	# <CJK>
+0x5E31	0x8587	# <CJK>
+0x5E32	0x858F	# <CJK>
+0x5E33	0x8579	# <CJK>
+0x5E34	0x85EA	# <CJK>
+0x5E35	0x859C	# <CJK>
+0x5E36	0x8585	# <CJK>
+0x5E37	0x85B9	# <CJK>
+0x5E38	0x85B7	# <CJK>
+0x5E39	0x85B0	# <CJK>
+0x5E3A	0x861A	# <CJK>
+0x5E3B	0x85C1	# <CJK>
+0x5E3C	0x85DC	# <CJK>
+0x5E3D	0x85FF	# <CJK>
+0x5E3E	0x8627	# <CJK>
+0x5E3F	0x8605	# <CJK>
+0x5E40	0x8629	# <CJK>
+0x5E41	0x8616	# <CJK>
+0x5E42	0x863C	# <CJK>
+0x5E43	0x5EFE	# <CJK>
+0x5E44	0x5F08	# <CJK>
+0x5E45	0x593C	# <CJK>
+0x5E46	0x5969	# <CJK>
+0x5E47	0x8037	# <CJK>
+0x5E48	0x5955	# <CJK>
+0x5E49	0x595A	# <CJK>
+0x5E4A	0x5958	# <CJK>
+0x5E4B	0x530F	# <CJK>
+0x5E4C	0x5C22	# <CJK>
+0x5E4D	0x5C25	# <CJK>
+0x5E4E	0x5C2C	# <CJK>
+0x5E4F	0x5C37	# <CJK>
+0x5E50	0x624C	# <CJK>
+0x5E51	0x636B	# <CJK>
+0x5E52	0x6476	# <CJK>
+0x5E53	0x62BB	# <CJK>
+0x5E54	0x62CA	# <CJK>
+0x5E55	0x62DA	# <CJK>
+0x5E56	0x62D7	# <CJK>
+0x5E57	0x62EE	# <CJK>
+0x5E58	0x649F	# <CJK>
+0x5E59	0x62F6	# <CJK>
+0x5E5A	0x6339	# <CJK>
+0x5E5B	0x634B	# <CJK>
+0x5E5C	0x6343	# <CJK>
+0x5E5D	0x63AD	# <CJK>
+0x5E5E	0x63F6	# <CJK>
+0x5E5F	0x6371	# <CJK>
+0x5E60	0x637A	# <CJK>
+0x5E61	0x638E	# <CJK>
+0x5E62	0x6451	# <CJK>
+0x5E63	0x636D	# <CJK>
+0x5E64	0x63AC	# <CJK>
+0x5E65	0x638A	# <CJK>
+0x5E66	0x6369	# <CJK>
+0x5E67	0x63AE	# <CJK>
+0x5E68	0x645C	# <CJK>
+0x5E69	0x63F2	# <CJK>
+0x5E6A	0x63F8	# <CJK>
+0x5E6B	0x63E0	# <CJK>
+0x5E6C	0x64B3	# <CJK>
+0x5E6D	0x63C4	# <CJK>
+0x5E6E	0x63DE	# <CJK>
+0x5E6F	0x63CE	# <CJK>
+0x5E70	0x6452	# <CJK>
+0x5E71	0x63C6	# <CJK>
+0x5E72	0x63BE	# <CJK>
+0x5E73	0x6504	# <CJK>
+0x5E74	0x6441	# <CJK>
+0x5E75	0x640B	# <CJK>
+0x5E76	0x641B	# <CJK>
+0x5E77	0x6420	# <CJK>
+0x5E78	0x640C	# <CJK>
+0x5E79	0x6426	# <CJK>
+0x5E7A	0x6421	# <CJK>
+0x5E7B	0x645E	# <CJK>
+0x5E7C	0x6516	# <CJK>
+0x5E7D	0x646D	# <CJK>
+0x5E7E	0x6496	# <CJK>
+0x5F21	0x647A	# <CJK>
+0x5F22	0x64F7	# <CJK>
+0x5F23	0x64FC	# <CJK>
+0x5F24	0x6499	# <CJK>
+0x5F25	0x651B	# <CJK>
+0x5F26	0x64C0	# <CJK>
+0x5F27	0x64D0	# <CJK>
+0x5F28	0x64D7	# <CJK>
+0x5F29	0x64E4	# <CJK>
+0x5F2A	0x64E2	# <CJK>
+0x5F2B	0x6509	# <CJK>
+0x5F2C	0x6525	# <CJK>
+0x5F2D	0x652E	# <CJK>
+0x5F2E	0x5F0B	# <CJK>
+0x5F2F	0x5FD2	# <CJK>
+0x5F30	0x7519	# <CJK>
+0x5F31	0x5F11	# <CJK>
+0x5F32	0x535F	# <CJK>
+0x5F33	0x53F1	# <CJK>
+0x5F34	0x5630	# <CJK>
+0x5F35	0x53E9	# <CJK>
+0x5F36	0x53E8	# <CJK>
+0x5F37	0x53FB	# <CJK>
+0x5F38	0x5412	# <CJK>
+0x5F39	0x5416	# <CJK>
+0x5F3A	0x5406	# <CJK>
+0x5F3B	0x544B	# <CJK>
+0x5F3C	0x5638	# <CJK>
+0x5F3D	0x56C8	# <CJK>
+0x5F3E	0x5454	# <CJK>
+0x5F3F	0x56A6	# <CJK>
+0x5F40	0x5443	# <CJK>
+0x5F41	0x5421	# <CJK>
+0x5F42	0x5504	# <CJK>
+0x5F43	0x54BC	# <CJK>
+0x5F44	0x5423	# <CJK>
+0x5F45	0x5432	# <CJK>
+0x5F46	0x5482	# <CJK>
+0x5F47	0x5494	# <CJK>
+0x5F48	0x5477	# <CJK>
+0x5F49	0x5471	# <CJK>
+0x5F4A	0x5464	# <CJK>
+0x5F4B	0x549A	# <CJK>
+0x5F4C	0x5680	# <CJK>
+0x5F4D	0x5484	# <CJK>
+0x5F4E	0x5476	# <CJK>
+0x5F4F	0x5466	# <CJK>
+0x5F50	0x565D	# <CJK>
+0x5F51	0x54D0	# <CJK>
+0x5F52	0x54AD	# <CJK>
+0x5F53	0x54C2	# <CJK>
+0x5F54	0x54B4	# <CJK>
+0x5F55	0x5660	# <CJK>
+0x5F56	0x54A7	# <CJK>
+0x5F57	0x54A6	# <CJK>
+0x5F58	0x5635	# <CJK>
+0x5F59	0x55F6	# <CJK>
+0x5F5A	0x5472	# <CJK>
+0x5F5B	0x54A3	# <CJK>
+0x5F5C	0x5666	# <CJK>
+0x5F5D	0x54BB	# <CJK>
+0x5F5E	0x54BF	# <CJK>
+0x5F5F	0x54CC	# <CJK>
+0x5F60	0x5672	# <CJK>
+0x5F61	0x54DA	# <CJK>
+0x5F62	0x568C	# <CJK>
+0x5F63	0x54A9	# <CJK>
+0x5F64	0x54AA	# <CJK>
+0x5F65	0x54A4	# <CJK>
+0x5F66	0x5665	# <CJK>
+0x5F67	0x54CF	# <CJK>
+0x5F68	0x54DE	# <CJK>
+0x5F69	0x561C	# <CJK>
+0x5F6A	0x54E7	# <CJK>
+0x5F6B	0x562E	# <CJK>
+0x5F6C	0x54FD	# <CJK>
+0x5F6D	0x5514	# <CJK>
+0x5F6E	0x54F3	# <CJK>
+0x5F6F	0x55E9	# <CJK>
+0x5F70	0x5523	# <CJK>
+0x5F71	0x550F	# <CJK>
+0x5F72	0x5511	# <CJK>
+0x5F73	0x5527	# <CJK>
+0x5F74	0x552A	# <CJK>
+0x5F75	0x5616	# <CJK>
+0x5F76	0x558F	# <CJK>
+0x5F77	0x55B5	# <CJK>
+0x5F78	0x5549	# <CJK>
+0x5F79	0x56C0	# <CJK>
+0x5F7A	0x5541	# <CJK>
+0x5F7B	0x5555	# <CJK>
+0x5F7C	0x553F	# <CJK>
+0x5F7D	0x5550	# <CJK>
+0x5F7E	0x553C	# <CJK>
+0x6021	0x5537	# <CJK>
+0x6022	0x5556	# <CJK>
+0x6023	0x5575	# <CJK>
+0x6024	0x5576	# <CJK>
+0x6025	0x5577	# <CJK>
+0x6026	0x5533	# <CJK>
+0x6027	0x5530	# <CJK>
+0x6028	0x555C	# <CJK>
+0x6029	0x558B	# <CJK>
+0x602A	0x55D2	# <CJK>
+0x602B	0x5583	# <CJK>
+0x602C	0x55B1	# <CJK>
+0x602D	0x55B9	# <CJK>
+0x602E	0x5588	# <CJK>
+0x602F	0x5581	# <CJK>
+0x6030	0x559F	# <CJK>
+0x6031	0x557E	# <CJK>
+0x6032	0x55D6	# <CJK>
+0x6033	0x5591	# <CJK>
+0x6034	0x557B	# <CJK>
+0x6035	0x55DF	# <CJK>
+0x6036	0x560D	# <CJK>
+0x6037	0x56B3	# <CJK>
+0x6038	0x5594	# <CJK>
+0x6039	0x5599	# <CJK>
+0x603A	0x55EA	# <CJK>
+0x603B	0x55F7	# <CJK>
+0x603C	0x55C9	# <CJK>
+0x603D	0x561F	# <CJK>
+0x603E	0x55D1	# <CJK>
+0x603F	0x56C1	# <CJK>
+0x6040	0x55EC	# <CJK>
+0x6041	0x55D4	# <CJK>
+0x6042	0x55E6	# <CJK>
+0x6043	0x55DD	# <CJK>
+0x6044	0x55C4	# <CJK>
+0x6045	0x55EF	# <CJK>
+0x6046	0x55E5	# <CJK>
+0x6047	0x55F2	# <CJK>
+0x6048	0x566F	# <CJK>
+0x6049	0x55CC	# <CJK>
+0x604A	0x55CD	# <CJK>
+0x604B	0x55E8	# <CJK>
+0x604C	0x55F5	# <CJK>
+0x604D	0x55E4	# <CJK>
+0x604E	0x8F61	# <CJK>
+0x604F	0x561E	# <CJK>
+0x6050	0x5608	# <CJK>
+0x6051	0x560C	# <CJK>
+0x6052	0x5601	# <CJK>
+0x6053	0x56B6	# <CJK>
+0x6054	0x5623	# <CJK>
+0x6055	0x55FE	# <CJK>
+0x6056	0x5600	# <CJK>
+0x6057	0x5627	# <CJK>
+0x6058	0x562D	# <CJK>
+0x6059	0x5658	# <CJK>
+0x605A	0x5639	# <CJK>
+0x605B	0x5657	# <CJK>
+0x605C	0x562C	# <CJK>
+0x605D	0x564D	# <CJK>
+0x605E	0x5662	# <CJK>
+0x605F	0x5659	# <CJK>
+0x6060	0x5695	# <CJK>
+0x6061	0x564C	# <CJK>
+0x6062	0x5654	# <CJK>
+0x6063	0x5686	# <CJK>
+0x6064	0x5664	# <CJK>
+0x6065	0x5671	# <CJK>
+0x6066	0x566B	# <CJK>
+0x6067	0x567B	# <CJK>
+0x6068	0x567C	# <CJK>
+0x6069	0x5685	# <CJK>
+0x606A	0x5693	# <CJK>
+0x606B	0x56AF	# <CJK>
+0x606C	0x56D4	# <CJK>
+0x606D	0x56D7	# <CJK>
+0x606E	0x56DD	# <CJK>
+0x606F	0x56E1	# <CJK>
+0x6070	0x5707	# <CJK>
+0x6071	0x56EB	# <CJK>
+0x6072	0x56F9	# <CJK>
+0x6073	0x56FF	# <CJK>
+0x6074	0x5704	# <CJK>
+0x6075	0x570A	# <CJK>
+0x6076	0x5709	# <CJK>
+0x6077	0x571C	# <CJK>
+0x6078	0x5E43	# <CJK>
+0x6079	0x5E19	# <CJK>
+0x607A	0x5E14	# <CJK>
+0x607B	0x5E11	# <CJK>
+0x607C	0x5E6C	# <CJK>
+0x607D	0x5E58	# <CJK>
+0x607E	0x5E57	# <CJK>
+0x6121	0x5E37	# <CJK>
+0x6122	0x5E44	# <CJK>
+0x6123	0x5E54	# <CJK>
+0x6124	0x5E5B	# <CJK>
+0x6125	0x5E5E	# <CJK>
+0x6126	0x5E61	# <CJK>
+0x6127	0x5C8C	# <CJK>
+0x6128	0x5C7A	# <CJK>
+0x6129	0x5C8D	# <CJK>
+0x612A	0x5C90	# <CJK>
+0x612B	0x5D87	# <CJK>
+0x612C	0x5C88	# <CJK>
+0x612D	0x5CF4	# <CJK>
+0x612E	0x5C99	# <CJK>
+0x612F	0x5C91	# <CJK>
+0x6130	0x5D50	# <CJK>
+0x6131	0x5C9C	# <CJK>
+0x6132	0x5CB5	# <CJK>
+0x6133	0x5CA2	# <CJK>
+0x6134	0x5D2C	# <CJK>
+0x6135	0x5CAC	# <CJK>
+0x6136	0x5CAB	# <CJK>
+0x6137	0x5CB1	# <CJK>
+0x6138	0x5CA3	# <CJK>
+0x6139	0x5CC1	# <CJK>
+0x613A	0x5CB7	# <CJK>
+0x613B	0x5DA7	# <CJK>
+0x613C	0x5CD2	# <CJK>
+0x613D	0x5DA0	# <CJK>
+0x613E	0x5CCB	# <CJK>
+0x613F	0x5D22	# <CJK>
+0x6140	0x5D97	# <CJK>
+0x6141	0x5D0D	# <CJK>
+0x6142	0x5D27	# <CJK>
+0x6143	0x5D26	# <CJK>
+0x6144	0x5D2E	# <CJK>
+0x6145	0x5D24	# <CJK>
+0x6146	0x5D1E	# <CJK>
+0x6147	0x5D06	# <CJK>
+0x6148	0x5D1B	# <CJK>
+0x6149	0x5DB8	# <CJK>
+0x614A	0x5D3E	# <CJK>
+0x614B	0x5D34	# <CJK>
+0x614C	0x5D3D	# <CJK>
+0x614D	0x5D6C	# <CJK>
+0x614E	0x5D5B	# <CJK>
+0x614F	0x5D6F	# <CJK>
+0x6150	0x5D81	# <CJK>
+0x6151	0x5D6B	# <CJK>
+0x6152	0x5D4B	# <CJK>
+0x6153	0x5D4A	# <CJK>
+0x6154	0x5D69	# <CJK>
+0x6155	0x5D74	# <CJK>
+0x6156	0x5D82	# <CJK>
+0x6157	0x5D99	# <CJK>
+0x6158	0x5D9D	# <CJK>
+0x6159	0x8C73	# <CJK>
+0x615A	0x5DB7	# <CJK>
+0x615B	0x5DD4	# <CJK>
+0x615C	0x5F73	# <CJK>
+0x615D	0x5F77	# <CJK>
+0x615E	0x5F82	# <CJK>
+0x615F	0x5F87	# <CJK>
+0x6160	0x5F89	# <CJK>
+0x6161	0x540E	# <CJK>
+0x6162	0x5FA0	# <CJK>
+0x6163	0x5F99	# <CJK>
+0x6164	0x5F9C	# <CJK>
+0x6165	0x5FA8	# <CJK>
+0x6166	0x5FAD	# <CJK>
+0x6167	0x5FB5	# <CJK>
+0x6168	0x5FBC	# <CJK>
+0x6169	0x8862	# <CJK>
+0x616A	0x5F61	# <CJK>
+0x616B	0x72AD	# <CJK>
+0x616C	0x72B0	# <CJK>
+0x616D	0x72B4	# <CJK>
+0x616E	0x7377	# <CJK>
+0x616F	0x7341	# <CJK>
+0x6170	0x72C3	# <CJK>
+0x6171	0x72C1	# <CJK>
+0x6172	0x72CE	# <CJK>
+0x6173	0x72CD	# <CJK>
+0x6174	0x72D2	# <CJK>
+0x6175	0x72E8	# <CJK>
+0x6176	0x736A	# <CJK>
+0x6177	0x72E9	# <CJK>
+0x6178	0x733B	# <CJK>
+0x6179	0x72F4	# <CJK>
+0x617A	0x72F7	# <CJK>
+0x617B	0x7301	# <CJK>
+0x617C	0x72F3	# <CJK>
+0x617D	0x736B	# <CJK>
+0x617E	0x72FA	# <CJK>
+0x6221	0x72FB	# <CJK>
+0x6222	0x7317	# <CJK>
+0x6223	0x7313	# <CJK>
+0x6224	0x7380	# <CJK>
+0x6225	0x730A	# <CJK>
+0x6226	0x731E	# <CJK>
+0x6227	0x731D	# <CJK>
+0x6228	0x737C	# <CJK>
+0x6229	0x7322	# <CJK>
+0x622A	0x7339	# <CJK>
+0x622B	0x7325	# <CJK>
+0x622C	0x732C	# <CJK>
+0x622D	0x7338	# <CJK>
+0x622E	0x7331	# <CJK>
+0x622F	0x7350	# <CJK>
+0x6230	0x734D	# <CJK>
+0x6231	0x7357	# <CJK>
+0x6232	0x7360	# <CJK>
+0x6233	0x736C	# <CJK>
+0x6234	0x736F	# <CJK>
+0x6235	0x737E	# <CJK>
+0x6236	0x821B	# <CJK>
+0x6237	0x5925	# <CJK>
+0x6238	0x98E7	# <CJK>
+0x6239	0x5924	# <CJK>
+0x623A	0x5902	# <CJK>
+0x623B	0x98E0	# <CJK>
+0x623C	0x9933	# <CJK>
+0x623D	0x98E9	# <CJK>
+0x623E	0x993C	# <CJK>
+0x623F	0x98EA	# <CJK>
+0x6240	0x98EB	# <CJK>
+0x6241	0x98ED	# <CJK>
+0x6242	0x98F4	# <CJK>
+0x6243	0x9909	# <CJK>
+0x6244	0x9911	# <CJK>
+0x6245	0x4F59	# <CJK>
+0x6246	0x991B	# <CJK>
+0x6247	0x9937	# <CJK>
+0x6248	0x993F	# <CJK>
+0x6249	0x9943	# <CJK>
+0x624A	0x9948	# <CJK>
+0x624B	0x9949	# <CJK>
+0x624C	0x994A	# <CJK>
+0x624D	0x994C	# <CJK>
+0x624E	0x9962	# <CJK>
+0x624F	0x5E80	# <CJK>
+0x6250	0x5EE1	# <CJK>
+0x6251	0x5E8B	# <CJK>
+0x6252	0x5E96	# <CJK>
+0x6253	0x5EA5	# <CJK>
+0x6254	0x5EA0	# <CJK>
+0x6255	0x5EB9	# <CJK>
+0x6256	0x5EB5	# <CJK>
+0x6257	0x5EBE	# <CJK>
+0x6258	0x5EB3	# <CJK>
+0x6259	0x8CE1	# <CJK>
+0x625A	0x5ED2	# <CJK>
+0x625B	0x5ED1	# <CJK>
+0x625C	0x5EDB	# <CJK>
+0x625D	0x5EE8	# <CJK>
+0x625E	0x5EEA	# <CJK>
+0x625F	0x81BA	# <CJK>
+0x6260	0x5FC4	# <CJK>
+0x6261	0x5FC9	# <CJK>
+0x6262	0x5FD6	# <CJK>
+0x6263	0x61FA	# <CJK>
+0x6264	0x61AE	# <CJK>
+0x6265	0x5FEE	# <CJK>
+0x6266	0x616A	# <CJK>
+0x6267	0x5FE1	# <CJK>
+0x6268	0x5FE4	# <CJK>
+0x6269	0x613E	# <CJK>
+0x626A	0x60B5	# <CJK>
+0x626B	0x6134	# <CJK>
+0x626C	0x5FEA	# <CJK>
+0x626D	0x5FED	# <CJK>
+0x626E	0x5FF8	# <CJK>
+0x626F	0x6019	# <CJK>
+0x6270	0x6035	# <CJK>
+0x6271	0x6026	# <CJK>
+0x6272	0x601B	# <CJK>
+0x6273	0x600F	# <CJK>
+0x6274	0x600D	# <CJK>
+0x6275	0x6029	# <CJK>
+0x6276	0x602B	# <CJK>
+0x6277	0x600A	# <CJK>
+0x6278	0x61CC	# <CJK>
+0x6279	0x6021	# <CJK>
+0x627A	0x615F	# <CJK>
+0x627B	0x61E8	# <CJK>
+0x627C	0x60FB	# <CJK>
+0x627D	0x6137	# <CJK>
+0x627E	0x6042	# <CJK>
+0x6321	0x606A	# <CJK>
+0x6322	0x60F2	# <CJK>
+0x6323	0x6096	# <CJK>
+0x6324	0x609A	# <CJK>
+0x6325	0x6173	# <CJK>
+0x6326	0x609D	# <CJK>
+0x6327	0x6083	# <CJK>
+0x6328	0x6092	# <CJK>
+0x6329	0x608C	# <CJK>
+0x632A	0x609B	# <CJK>
+0x632B	0x611C	# <CJK>
+0x632C	0x60BB	# <CJK>
+0x632D	0x60B1	# <CJK>
+0x632E	0x60DD	# <CJK>
+0x632F	0x60D8	# <CJK>
+0x6330	0x60C6	# <CJK>
+0x6331	0x60DA	# <CJK>
+0x6332	0x60B4	# <CJK>
+0x6333	0x6120	# <CJK>
+0x6334	0x6192	# <CJK>
+0x6335	0x6115	# <CJK>
+0x6336	0x6123	# <CJK>
+0x6337	0x60F4	# <CJK>
+0x6338	0x6100	# <CJK>
+0x6339	0x610E	# <CJK>
+0x633A	0x612B	# <CJK>
+0x633B	0x614A	# <CJK>
+0x633C	0x6175	# <CJK>
+0x633D	0x61AC	# <CJK>
+0x633E	0x6194	# <CJK>
+0x633F	0x61A7	# <CJK>
+0x6340	0x61B7	# <CJK>
+0x6341	0x61D4	# <CJK>
+0x6342	0x61F5	# <CJK>
+0x6343	0x5FDD	# <CJK>
+0x6344	0x96B3	# <CJK>
+0x6345	0x9582	# <CJK>
+0x6346	0x9586	# <CJK>
+0x6347	0x95C8	# <CJK>
+0x6348	0x958E	# <CJK>
+0x6349	0x9594	# <CJK>
+0x634A	0x958C	# <CJK>
+0x634B	0x95E5	# <CJK>
+0x634C	0x95AD	# <CJK>
+0x634D	0x95AB	# <CJK>
+0x634E	0x9B2E	# <CJK>
+0x634F	0x95AC	# <CJK>
+0x6350	0x95BE	# <CJK>
+0x6351	0x95B6	# <CJK>
+0x6352	0x9B29	# <CJK>
+0x6353	0x95BF	# <CJK>
+0x6354	0x95BD	# <CJK>
+0x6355	0x95BC	# <CJK>
+0x6356	0x95C3	# <CJK>
+0x6357	0x95CB	# <CJK>
+0x6358	0x95D4	# <CJK>
+0x6359	0x95D0	# <CJK>
+0x635A	0x95D5	# <CJK>
+0x635B	0x95DE	# <CJK>
+0x635C	0x4E2C	# <CJK>
+0x635D	0x723F	# <CJK>
+0x635E	0x6215	# <CJK>
+0x635F	0x6C35	# <CJK>
+0x6360	0x6C54	# <CJK>
+0x6361	0x6C5C	# <CJK>
+0x6362	0x6C4A	# <CJK>
+0x6363	0x7043	# <CJK>
+0x6364	0x6C85	# <CJK>
+0x6365	0x6C90	# <CJK>
+0x6366	0x6C94	# <CJK>
+0x6367	0x6C8C	# <CJK>
+0x6368	0x6C68	# <CJK>
+0x6369	0x6C69	# <CJK>
+0x636A	0x6C74	# <CJK>
+0x636B	0x6C76	# <CJK>
+0x636C	0x6C86	# <CJK>
+0x636D	0x6F59	# <CJK>
+0x636E	0x6CD0	# <CJK>
+0x636F	0x6CD4	# <CJK>
+0x6370	0x6CAD	# <CJK>
+0x6371	0x7027	# <CJK>
+0x6372	0x7018	# <CJK>
+0x6373	0x6CF1	# <CJK>
+0x6374	0x6CD7	# <CJK>
+0x6375	0x6CB2	# <CJK>
+0x6376	0x6CE0	# <CJK>
+0x6377	0x6CD6	# <CJK>
+0x6378	0x6FFC	# <CJK>
+0x6379	0x6CEB	# <CJK>
+0x637A	0x6CEE	# <CJK>
+0x637B	0x6CB1	# <CJK>
+0x637C	0x6CD3	# <CJK>
+0x637D	0x6CEF	# <CJK>
+0x637E	0x6D87	# <CJK>
+0x6421	0x6D39	# <CJK>
+0x6422	0x6D27	# <CJK>
+0x6423	0x6D0C	# <CJK>
+0x6424	0x6D79	# <CJK>
+0x6425	0x6E5E	# <CJK>
+0x6426	0x6D07	# <CJK>
+0x6427	0x6D04	# <CJK>
+0x6428	0x6D19	# <CJK>
+0x6429	0x6D0E	# <CJK>
+0x642A	0x6D2B	# <CJK>
+0x642B	0x6FAE	# <CJK>
+0x642C	0x6D2E	# <CJK>
+0x642D	0x6D35	# <CJK>
+0x642E	0x6D1A	# <CJK>
+0x642F	0x700F	# <CJK>
+0x6430	0x6EF8	# <CJK>
+0x6431	0x6F6F	# <CJK>
+0x6432	0x6D33	# <CJK>
+0x6433	0x6D91	# <CJK>
+0x6434	0x6D6F	# <CJK>
+0x6435	0x6DF6	# <CJK>
+0x6436	0x6F7F	# <CJK>
+0x6437	0x6D5E	# <CJK>
+0x6438	0x6D93	# <CJK>
+0x6439	0x6D94	# <CJK>
+0x643A	0x6D5C	# <CJK>
+0x643B	0x6D60	# <CJK>
+0x643C	0x6D7C	# <CJK>
+0x643D	0x6D63	# <CJK>
+0x643E	0x6E1A	# <CJK>
+0x643F	0x6DC7	# <CJK>
+0x6440	0x6DC5	# <CJK>
+0x6441	0x6DDE	# <CJK>
+0x6442	0x7006	# <CJK>
+0x6443	0x6DBF	# <CJK>
+0x6444	0x6DE0	# <CJK>
+0x6445	0x6FA0	# <CJK>
+0x6446	0x6DE6	# <CJK>
+0x6447	0x6DDD	# <CJK>
+0x6448	0x6DD9	# <CJK>
+0x6449	0x700B	# <CJK>
+0x644A	0x6DAB	# <CJK>
+0x644B	0x6E0C	# <CJK>
+0x644C	0x6DAE	# <CJK>
+0x644D	0x6E2B	# <CJK>
+0x644E	0x6E6E	# <CJK>
+0x644F	0x6E4E	# <CJK>
+0x6450	0x6E6B	# <CJK>
+0x6451	0x6EB2	# <CJK>
+0x6452	0x6E5F	# <CJK>
+0x6453	0x6E86	# <CJK>
+0x6454	0x6E53	# <CJK>
+0x6455	0x6E54	# <CJK>
+0x6456	0x6E32	# <CJK>
+0x6457	0x6E25	# <CJK>
+0x6458	0x6E44	# <CJK>
+0x6459	0x7067	# <CJK>
+0x645A	0x6EB1	# <CJK>
+0x645B	0x6E98	# <CJK>
+0x645C	0x7044	# <CJK>
+0x645D	0x6F2D	# <CJK>
+0x645E	0x7005	# <CJK>
+0x645F	0x6EA5	# <CJK>
+0x6460	0x6EA7	# <CJK>
+0x6461	0x6EBD	# <CJK>
+0x6462	0x6EBB	# <CJK>
+0x6463	0x6EB7	# <CJK>
+0x6464	0x6F77	# <CJK>
+0x6465	0x6EB4	# <CJK>
+0x6466	0x6ECF	# <CJK>
+0x6467	0x6E8F	# <CJK>
+0x6468	0x6EC2	# <CJK>
+0x6469	0x6E9F	# <CJK>
+0x646A	0x6F62	# <CJK>
+0x646B	0x7020	# <CJK>
+0x646C	0x701F	# <CJK>
+0x646D	0x6F24	# <CJK>
+0x646E	0x6F15	# <CJK>
+0x646F	0x6EF9	# <CJK>
+0x6470	0x6F2F	# <CJK>
+0x6471	0x6F36	# <CJK>
+0x6472	0x7032	# <CJK>
+0x6473	0x6F74	# <CJK>
+0x6474	0x6F2A	# <CJK>
+0x6475	0x6F09	# <CJK>
+0x6476	0x6F29	# <CJK>
+0x6477	0x6F89	# <CJK>
+0x6478	0x6F8D	# <CJK>
+0x6479	0x6F8C	# <CJK>
+0x647A	0x6F78	# <CJK>
+0x647B	0x6F72	# <CJK>
+0x647C	0x6F7C	# <CJK>
+0x647D	0x6F7A	# <CJK>
+0x647E	0x7028	# <CJK>
+0x6521	0x6FC9	# <CJK>
+0x6522	0x6FA7	# <CJK>
+0x6523	0x6FB9	# <CJK>
+0x6524	0x6FB6	# <CJK>
+0x6525	0x6FC2	# <CJK>
+0x6526	0x6FE1	# <CJK>
+0x6527	0x6FEE	# <CJK>
+0x6528	0x6FDE	# <CJK>
+0x6529	0x6FE0	# <CJK>
+0x652A	0x6FEF	# <CJK>
+0x652B	0x701A	# <CJK>
+0x652C	0x7023	# <CJK>
+0x652D	0x701B	# <CJK>
+0x652E	0x7039	# <CJK>
+0x652F	0x7035	# <CJK>
+0x6530	0x705D	# <CJK>
+0x6531	0x705E	# <CJK>
+0x6532	0x5B80	# <CJK>
+0x6533	0x5B84	# <CJK>
+0x6534	0x5B95	# <CJK>
+0x6535	0x5B93	# <CJK>
+0x6536	0x5BA5	# <CJK>
+0x6537	0x5BB8	# <CJK>
+0x6538	0x752F	# <CJK>
+0x6539	0x9A2B	# <CJK>
+0x653A	0x6434	# <CJK>
+0x653B	0x5BE4	# <CJK>
+0x653C	0x5BEE	# <CJK>
+0x653D	0x8930	# <CJK>
+0x653E	0x5BF0	# <CJK>
+0x653F	0x8E47	# <CJK>
+0x6540	0x8B07	# <CJK>
+0x6541	0x8FB6	# <CJK>
+0x6542	0x8FD3	# <CJK>
+0x6543	0x8FD5	# <CJK>
+0x6544	0x8FE5	# <CJK>
+0x6545	0x8FEE	# <CJK>
+0x6546	0x8FE4	# <CJK>
+0x6547	0x9087	# <CJK>
+0x6548	0x8FE6	# <CJK>
+0x6549	0x9015	# <CJK>
+0x654A	0x8FE8	# <CJK>
+0x654B	0x9005	# <CJK>
+0x654C	0x9004	# <CJK>
+0x654D	0x900B	# <CJK>
+0x654E	0x9090	# <CJK>
+0x654F	0x9011	# <CJK>
+0x6550	0x900D	# <CJK>
+0x6551	0x9016	# <CJK>
+0x6552	0x9021	# <CJK>
+0x6553	0x9035	# <CJK>
+0x6554	0x9036	# <CJK>
+0x6555	0x902D	# <CJK>
+0x6556	0x902F	# <CJK>
+0x6557	0x9044	# <CJK>
+0x6558	0x9051	# <CJK>
+0x6559	0x9052	# <CJK>
+0x655A	0x9050	# <CJK>
+0x655B	0x9068	# <CJK>
+0x655C	0x9058	# <CJK>
+0x655D	0x9062	# <CJK>
+0x655E	0x905B	# <CJK>
+0x655F	0x66B9	# <CJK>
+0x6560	0x9074	# <CJK>
+0x6561	0x907D	# <CJK>
+0x6562	0x9082	# <CJK>
+0x6563	0x9088	# <CJK>
+0x6564	0x9083	# <CJK>
+0x6565	0x908B	# <CJK>
+0x6566	0x5F50	# <CJK>
+0x6567	0x5F57	# <CJK>
+0x6568	0x5F56	# <CJK>
+0x6569	0x5F58	# <CJK>
+0x656A	0x5C3B	# <CJK>
+0x656B	0x54AB	# <CJK>
+0x656C	0x5C50	# <CJK>
+0x656D	0x5C59	# <CJK>
+0x656E	0x5B71	# <CJK>
+0x656F	0x5C63	# <CJK>
+0x6570	0x5C68	# <CJK>
+0x6571	0x7FBC	# <CJK>
+0x6572	0x5F33	# <CJK>
+0x6573	0x5F29	# <CJK>
+0x6574	0x5F2D	# <CJK>
+0x6575	0x8274	# <CJK>
+0x6576	0x5F3C	# <CJK>
+0x6577	0x9B3B	# <CJK>
+0x6578	0x5C6E	# <CJK>
+0x6579	0x5981	# <CJK>
+0x657A	0x5983	# <CJK>
+0x657B	0x598D	# <CJK>
+0x657C	0x5AF5	# <CJK>
+0x657D	0x5AD7	# <CJK>
+0x657E	0x59A3	# <CJK>
+0x6621	0x5997	# <CJK>
+0x6622	0x59CA	# <CJK>
+0x6623	0x5B00	# <CJK>
+0x6624	0x599E	# <CJK>
+0x6625	0x59A4	# <CJK>
+0x6626	0x59D2	# <CJK>
+0x6627	0x59B2	# <CJK>
+0x6628	0x59AF	# <CJK>
+0x6629	0x59D7	# <CJK>
+0x662A	0x59BE	# <CJK>
+0x662B	0x5A6D	# <CJK>
+0x662C	0x5B08	# <CJK>
+0x662D	0x59DD	# <CJK>
+0x662E	0x5B4C	# <CJK>
+0x662F	0x59E3	# <CJK>
+0x6630	0x59D8	# <CJK>
+0x6631	0x59F9	# <CJK>
+0x6632	0x5A0C	# <CJK>
+0x6633	0x5A09	# <CJK>
+0x6634	0x5AA7	# <CJK>
+0x6635	0x5AFB	# <CJK>
+0x6636	0x5A11	# <CJK>
+0x6637	0x5A23	# <CJK>
+0x6638	0x5A13	# <CJK>
+0x6639	0x5A40	# <CJK>
+0x663A	0x5A67	# <CJK>
+0x663B	0x5A4A	# <CJK>
+0x663C	0x5A55	# <CJK>
+0x663D	0x5A3C	# <CJK>
+0x663E	0x5A62	# <CJK>
+0x663F	0x5B0B	# <CJK>
+0x6640	0x80EC	# <CJK>
+0x6641	0x5AAA	# <CJK>
+0x6642	0x5A9B	# <CJK>
+0x6643	0x5A77	# <CJK>
+0x6644	0x5A7A	# <CJK>
+0x6645	0x5ABE	# <CJK>
+0x6646	0x5AEB	# <CJK>
+0x6647	0x5AB2	# <CJK>
+0x6648	0x5B21	# <CJK>
+0x6649	0x5B2A	# <CJK>
+0x664A	0x5AB8	# <CJK>
+0x664B	0x5AE0	# <CJK>
+0x664C	0x5AE3	# <CJK>
+0x664D	0x5B19	# <CJK>
+0x664E	0x5AD6	# <CJK>
+0x664F	0x5AE6	# <CJK>
+0x6650	0x5AD8	# <CJK>
+0x6651	0x5ADC	# <CJK>
+0x6652	0x5B09	# <CJK>
+0x6653	0x5B17	# <CJK>
+0x6654	0x5B16	# <CJK>
+0x6655	0x5B32	# <CJK>
+0x6656	0x5B37	# <CJK>
+0x6657	0x5B40	# <CJK>
+0x6658	0x5C15	# <CJK>
+0x6659	0x5C1C	# <CJK>
+0x665A	0x5B5A	# <CJK>
+0x665B	0x5B65	# <CJK>
+0x665C	0x5B73	# <CJK>
+0x665D	0x5B51	# <CJK>
+0x665E	0x5B53	# <CJK>
+0x665F	0x5B62	# <CJK>
+0x6660	0x99D4	# <CJK>
+0x6661	0x99DF	# <CJK>
+0x6662	0x99D9	# <CJK>
+0x6663	0x9A36	# <CJK>
+0x6664	0x9A5B	# <CJK>
+0x6665	0x99D1	# <CJK>
+0x6666	0x99D8	# <CJK>
+0x6667	0x9A4D	# <CJK>
+0x6668	0x9A4A	# <CJK>
+0x6669	0x99E2	# <CJK>
+0x666A	0x9A6A	# <CJK>
+0x666B	0x9A0F	# <CJK>
+0x666C	0x9A0D	# <CJK>
+0x666D	0x9A05	# <CJK>
+0x666E	0x9A42	# <CJK>
+0x666F	0x9A2D	# <CJK>
+0x6670	0x9A16	# <CJK>
+0x6671	0x9A41	# <CJK>
+0x6672	0x9A2E	# <CJK>
+0x6673	0x9A38	# <CJK>
+0x6674	0x9A43	# <CJK>
+0x6675	0x9A44	# <CJK>
+0x6676	0x9A4F	# <CJK>
+0x6677	0x9A65	# <CJK>
+0x6678	0x9A64	# <CJK>
+0x6679	0x7CF9	# <CJK>
+0x667A	0x7D06	# <CJK>
+0x667B	0x7D02	# <CJK>
+0x667C	0x7D07	# <CJK>
+0x667D	0x7D08	# <CJK>
+0x667E	0x7E8A	# <CJK>
+0x6721	0x7D1C	# <CJK>
+0x6722	0x7D15	# <CJK>
+0x6723	0x7D13	# <CJK>
+0x6724	0x7D3A	# <CJK>
+0x6725	0x7D32	# <CJK>
+0x6726	0x7D31	# <CJK>
+0x6727	0x7E10	# <CJK>
+0x6728	0x7D3C	# <CJK>
+0x6729	0x7D40	# <CJK>
+0x672A	0x7D3F	# <CJK>
+0x672B	0x7D5D	# <CJK>
+0x672C	0x7D4E	# <CJK>
+0x672D	0x7D73	# <CJK>
+0x672E	0x7D86	# <CJK>
+0x672F	0x7D83	# <CJK>
+0x6730	0x7D88	# <CJK>
+0x6731	0x7DBE	# <CJK>
+0x6732	0x7DBA	# <CJK>
+0x6733	0x7DCB	# <CJK>
+0x6734	0x7DD4	# <CJK>
+0x6735	0x7DC4	# <CJK>
+0x6736	0x7D9E	# <CJK>
+0x6737	0x7DAC	# <CJK>
+0x6738	0x7DB9	# <CJK>
+0x6739	0x7DA3	# <CJK>
+0x673A	0x7DB0	# <CJK>
+0x673B	0x7DC7	# <CJK>
+0x673C	0x7DD9	# <CJK>
+0x673D	0x7DD7	# <CJK>
+0x673E	0x7DF9	# <CJK>
+0x673F	0x7DF2	# <CJK>
+0x6740	0x7E62	# <CJK>
+0x6741	0x7DE6	# <CJK>
+0x6742	0x7DF6	# <CJK>
+0x6743	0x7DF1	# <CJK>
+0x6744	0x7E0B	# <CJK>
+0x6745	0x7DE1	# <CJK>
+0x6746	0x7E09	# <CJK>
+0x6747	0x7E1D	# <CJK>
+0x6748	0x7E1F	# <CJK>
+0x6749	0x7E1E	# <CJK>
+0x674A	0x7E2D	# <CJK>
+0x674B	0x7E0A	# <CJK>
+0x674C	0x7E11	# <CJK>
+0x674D	0x7E7D	# <CJK>
+0x674E	0x7E39	# <CJK>
+0x674F	0x7E35	# <CJK>
+0x6750	0x7E32	# <CJK>
+0x6751	0x7E46	# <CJK>
+0x6752	0x7E45	# <CJK>
+0x6753	0x7E88	# <CJK>
+0x6754	0x7E5A	# <CJK>
+0x6755	0x7E52	# <CJK>
+0x6756	0x7E6E	# <CJK>
+0x6757	0x7E7E	# <CJK>
+0x6758	0x7E70	# <CJK>
+0x6759	0x7E6F	# <CJK>
+0x675A	0x7E98	# <CJK>
+0x675B	0x5E7A	# <CJK>
+0x675C	0x757F	# <CJK>
+0x675D	0x5DDB	# <CJK>
+0x675E	0x753E	# <CJK>
+0x675F	0x9095	# <CJK>
+0x6760	0x738E	# <CJK>
+0x6761	0x74A3	# <CJK>
+0x6762	0x744B	# <CJK>
+0x6763	0x73A2	# <CJK>
+0x6764	0x739F	# <CJK>
+0x6765	0x73CF	# <CJK>
+0x6766	0x73C2	# <CJK>
+0x6767	0x74CF	# <CJK>
+0x6768	0x73B7	# <CJK>
+0x6769	0x73B3	# <CJK>
+0x676A	0x73C0	# <CJK>
+0x676B	0x73C9	# <CJK>
+0x676C	0x73C8	# <CJK>
+0x676D	0x73E5	# <CJK>
+0x676E	0x73D9	# <CJK>
+0x676F	0x980A	# <CJK>
+0x6770	0x740A	# <CJK>
+0x6771	0x73E9	# <CJK>
+0x6772	0x73E7	# <CJK>
+0x6773	0x73DE	# <CJK>
+0x6774	0x74BD	# <CJK>
+0x6775	0x743F	# <CJK>
+0x6776	0x7489	# <CJK>
+0x6777	0x742A	# <CJK>
+0x6778	0x745B	# <CJK>
+0x6779	0x7426	# <CJK>
+0x677A	0x7425	# <CJK>
+0x677B	0x7428	# <CJK>
+0x677C	0x7430	# <CJK>
+0x677D	0x742E	# <CJK>
+0x677E	0x742C	# <CJK>
+0x6821	0x741B	# <CJK>
+0x6822	0x741A	# <CJK>
+0x6823	0x7441	# <CJK>
+0x6824	0x745C	# <CJK>
+0x6825	0x7457	# <CJK>
+0x6826	0x7455	# <CJK>
+0x6827	0x7459	# <CJK>
+0x6828	0x74A6	# <CJK>
+0x6829	0x746D	# <CJK>
+0x682A	0x747E	# <CJK>
+0x682B	0x749C	# <CJK>
+0x682C	0x74D4	# <CJK>
+0x682D	0x7480	# <CJK>
+0x682E	0x7481	# <CJK>
+0x682F	0x7487	# <CJK>
+0x6830	0x748B	# <CJK>
+0x6831	0x749E	# <CJK>
+0x6832	0x74A8	# <CJK>
+0x6833	0x74A9	# <CJK>
+0x6834	0x7490	# <CJK>
+0x6835	0x74A7	# <CJK>
+0x6836	0x74DA	# <CJK>
+0x6837	0x74BA	# <CJK>
+0x6838	0x97D9	# <CJK>
+0x6839	0x97DE	# <CJK>
+0x683A	0x97DC	# <CJK>
+0x683B	0x674C	# <CJK>
+0x683C	0x6753	# <CJK>
+0x683D	0x675E	# <CJK>
+0x683E	0x6748	# <CJK>
+0x683F	0x69AA	# <CJK>
+0x6840	0x6AEA	# <CJK>
+0x6841	0x6787	# <CJK>
+0x6842	0x676A	# <CJK>
+0x6843	0x6773	# <CJK>
+0x6844	0x6798	# <CJK>
+0x6845	0x6898	# <CJK>
+0x6846	0x6775	# <CJK>
+0x6847	0x68D6	# <CJK>
+0x6848	0x6A05	# <CJK>
+0x6849	0x689F	# <CJK>
+0x684A	0x678B	# <CJK>
+0x684B	0x6777	# <CJK>
+0x684C	0x677C	# <CJK>
+0x684D	0x67F0	# <CJK>
+0x684E	0x6ADB	# <CJK>
+0x684F	0x67D8	# <CJK>
+0x6850	0x6AF3	# <CJK>
+0x6851	0x67E9	# <CJK>
+0x6852	0x67B0	# <CJK>
+0x6853	0x6AE8	# <CJK>
+0x6854	0x67D9	# <CJK>
+0x6855	0x67B5	# <CJK>
+0x6856	0x67DA	# <CJK>
+0x6857	0x67B3	# <CJK>
+0x6858	0x67DD	# <CJK>
+0x6859	0x6800	# <CJK>
+0x685A	0x67C3	# <CJK>
+0x685B	0x67B8	# <CJK>
+0x685C	0x67E2	# <CJK>
+0x685D	0x6ADF	# <CJK>
+0x685E	0x67C1	# <CJK>
+0x685F	0x6A89	# <CJK>
+0x6860	0x6832	# <CJK>
+0x6861	0x6833	# <CJK>
+0x6862	0x690F	# <CJK>
+0x6863	0x6A48	# <CJK>
+0x6864	0x684E	# <CJK>
+0x6865	0x6968	# <CJK>
+0x6866	0x6844	# <CJK>
+0x6867	0x69BF	# <CJK>
+0x6868	0x6883	# <CJK>
+0x6869	0x681D	# <CJK>
+0x686A	0x6855	# <CJK>
+0x686B	0x6A3A	# <CJK>
+0x686C	0x6841	# <CJK>
+0x686D	0x6A9C	# <CJK>
+0x686E	0x6840	# <CJK>
+0x686F	0x6B12	# <CJK>
+0x6870	0x684A	# <CJK>
+0x6871	0x6849	# <CJK>
+0x6872	0x6829	# <CJK>
+0x6873	0x68B5	# <CJK>
+0x6874	0x688F	# <CJK>
+0x6875	0x6874	# <CJK>
+0x6876	0x6877	# <CJK>
+0x6877	0x6893	# <CJK>
+0x6878	0x686B	# <CJK>
+0x6879	0x6B1E	# <CJK>
+0x687A	0x696E	# <CJK>
+0x687B	0x68FC	# <CJK>
+0x687C	0x6ADD	# <CJK>
+0x687D	0x69E7	# <CJK>
+0x687E	0x68F9	# <CJK>
+0x6921	0x6B0F	# <CJK>
+0x6922	0x68F0	# <CJK>
+0x6923	0x690B	# <CJK>
+0x6924	0x6901	# <CJK>
+0x6925	0x6957	# <CJK>
+0x6926	0x68E3	# <CJK>
+0x6927	0x6910	# <CJK>
+0x6928	0x6971	# <CJK>
+0x6929	0x6939	# <CJK>
+0x692A	0x6960	# <CJK>
+0x692B	0x6942	# <CJK>
+0x692C	0x695D	# <CJK>
+0x692D	0x6B16	# <CJK>
+0x692E	0x696B	# <CJK>
+0x692F	0x6980	# <CJK>
+0x6930	0x6998	# <CJK>
+0x6931	0x6978	# <CJK>
+0x6932	0x6934	# <CJK>
+0x6933	0x69CC	# <CJK>
+0x6934	0x6AEC	# <CJK>
+0x6935	0x6ADA	# <CJK>
+0x6936	0x69CE	# <CJK>
+0x6937	0x6AF8	# <CJK>
+0x6938	0x6966	# <CJK>
+0x6939	0x6963	# <CJK>
+0x693A	0x6979	# <CJK>
+0x693B	0x699B	# <CJK>
+0x693C	0x69A7	# <CJK>
+0x693D	0x69BB	# <CJK>
+0x693E	0x69AB	# <CJK>
+0x693F	0x69AD	# <CJK>
+0x6940	0x69D4	# <CJK>
+0x6941	0x69B1	# <CJK>
+0x6942	0x69C1	# <CJK>
+0x6943	0x69CA	# <CJK>
+0x6944	0x6AB3	# <CJK>
+0x6945	0x6995	# <CJK>
+0x6946	0x6AE7	# <CJK>
+0x6947	0x698D	# <CJK>
+0x6948	0x69FF	# <CJK>
+0x6949	0x6AA3	# <CJK>
+0x694A	0x69ED	# <CJK>
+0x694B	0x6A17	# <CJK>
+0x694C	0x6A18	# <CJK>
+0x694D	0x6A65	# <CJK>
+0x694E	0x69F2	# <CJK>
+0x694F	0x6A44	# <CJK>
+0x6950	0x6A3E	# <CJK>
+0x6951	0x6AA0	# <CJK>
+0x6952	0x6A50	# <CJK>
+0x6953	0x6A5B	# <CJK>
+0x6954	0x6A35	# <CJK>
+0x6955	0x6A8E	# <CJK>
+0x6956	0x6AD3	# <CJK>
+0x6957	0x6A3D	# <CJK>
+0x6958	0x6A28	# <CJK>
+0x6959	0x6A58	# <CJK>
+0x695A	0x6ADE	# <CJK>
+0x695B	0x6A91	# <CJK>
+0x695C	0x6A90	# <CJK>
+0x695D	0x6AA9	# <CJK>
+0x695E	0x6A97	# <CJK>
+0x695F	0x6AAB	# <CJK>
+0x6960	0x7337	# <CJK>
+0x6961	0x7352	# <CJK>
+0x6962	0x6B81	# <CJK>
+0x6963	0x6B82	# <CJK>
+0x6964	0x6BA4	# <CJK>
+0x6965	0x6B84	# <CJK>
+0x6966	0x6B9E	# <CJK>
+0x6967	0x6BAE	# <CJK>
+0x6968	0x6B8D	# <CJK>
+0x6969	0x6BAB	# <CJK>
+0x696A	0x6B9B	# <CJK>
+0x696B	0x6BAF	# <CJK>
+0x696C	0x6BAA	# <CJK>
+0x696D	0x8ED4	# <CJK>
+0x696E	0x8EDB	# <CJK>
+0x696F	0x8EF2	# <CJK>
+0x6970	0x8EFB	# <CJK>
+0x6971	0x8F64	# <CJK>
+0x6972	0x8EF9	# <CJK>
+0x6973	0x8EFC	# <CJK>
+0x6974	0x8EEB	# <CJK>
+0x6975	0x8EE4	# <CJK>
+0x6976	0x8F62	# <CJK>
+0x6977	0x8EFA	# <CJK>
+0x6978	0x8EFE	# <CJK>
+0x6979	0x8F0A	# <CJK>
+0x697A	0x8F07	# <CJK>
+0x697B	0x8F05	# <CJK>
+0x697C	0x8F12	# <CJK>
+0x697D	0x8F26	# <CJK>
+0x697E	0x8F1E	# <CJK>
+0x6A21	0x8F1F	# <CJK>
+0x6A22	0x8F1C	# <CJK>
+0x6A23	0x8F33	# <CJK>
+0x6A24	0x8F46	# <CJK>
+0x6A25	0x8F54	# <CJK>
+0x6A26	0x8ECE	# <CJK>
+0x6A27	0x6214	# <CJK>
+0x6A28	0x6227	# <CJK>
+0x6A29	0x621B	# <CJK>
+0x6A2A	0x621F	# <CJK>
+0x6A2B	0x6222	# <CJK>
+0x6A2C	0x6221	# <CJK>
+0x6A2D	0x6225	# <CJK>
+0x6A2E	0x6224	# <CJK>
+0x6A2F	0x6229	# <CJK>
+0x6A30	0x81E7	# <CJK>
+0x6A31	0x750C	# <CJK>
+0x6A32	0x74F4	# <CJK>
+0x6A33	0x74FF	# <CJK>
+0x6A34	0x750F	# <CJK>
+0x6A35	0x7511	# <CJK>
+0x6A36	0x7513	# <CJK>
+0x6A37	0x6534	# <CJK>
+0x6A38	0x65EE	# <CJK>
+0x6A39	0x65EF	# <CJK>
+0x6A3A	0x65F0	# <CJK>
+0x6A3B	0x660A	# <CJK>
+0x6A3C	0x66C7	# <CJK>
+0x6A3D	0x6772	# <CJK>
+0x6A3E	0x6603	# <CJK>
+0x6A3F	0x6615	# <CJK>
+0x6A40	0x6600	# <CJK>
+0x6A41	0x7085	# <CJK>
+0x6A42	0x66F7	# <CJK>
+0x6A43	0x661D	# <CJK>
+0x6A44	0x6634	# <CJK>
+0x6A45	0x6631	# <CJK>
+0x6A46	0x6636	# <CJK>
+0x6A47	0x6635	# <CJK>
+0x6A48	0x8006	# <CJK>
+0x6A49	0x665F	# <CJK>
+0x6A4A	0x66C4	# <CJK>
+0x6A4B	0x6641	# <CJK>
+0x6A4C	0x664F	# <CJK>
+0x6A4D	0x6689	# <CJK>
+0x6A4E	0x6661	# <CJK>
+0x6A4F	0x6657	# <CJK>
+0x6A50	0x6677	# <CJK>
+0x6A51	0x6684	# <CJK>
+0x6A52	0x668C	# <CJK>
+0x6A53	0x66D6	# <CJK>
+0x6A54	0x669D	# <CJK>
+0x6A55	0x66BE	# <CJK>
+0x6A56	0x66DB	# <CJK>
+0x6A57	0x66DC	# <CJK>
+0x6A58	0x66E6	# <CJK>
+0x6A59	0x66E9	# <CJK>
+0x6A5A	0x8CC1	# <CJK>
+0x6A5B	0x8CB0	# <CJK>
+0x6A5C	0x8CBA	# <CJK>
+0x6A5D	0x8CBD	# <CJK>
+0x6A5E	0x8D04	# <CJK>
+0x6A5F	0x8CB2	# <CJK>
+0x6A60	0x8CC5	# <CJK>
+0x6A61	0x8D10	# <CJK>
+0x6A62	0x8CD1	# <CJK>
+0x6A63	0x8CDA	# <CJK>
+0x6A64	0x8CD5	# <CJK>
+0x6A65	0x8CEB	# <CJK>
+0x6A66	0x8CE7	# <CJK>
+0x6A67	0x8CFB	# <CJK>
+0x6A68	0x8998	# <CJK>
+0x6A69	0x89AC	# <CJK>
+0x6A6A	0x89A1	# <CJK>
+0x6A6B	0x89BF	# <CJK>
+0x6A6C	0x89A6	# <CJK>
+0x6A6D	0x89AF	# <CJK>
+0x6A6E	0x89B2	# <CJK>
+0x6A6F	0x89B7	# <CJK>
+0x6A70	0x726E	# <CJK>
+0x6A71	0x729F	# <CJK>
+0x6A72	0x725D	# <CJK>
+0x6A73	0x7266	# <CJK>
+0x6A74	0x726F	# <CJK>
+0x6A75	0x727E	# <CJK>
+0x6A76	0x727F	# <CJK>
+0x6A77	0x7284	# <CJK>
+0x6A78	0x728B	# <CJK>
+0x6A79	0x728D	# <CJK>
+0x6A7A	0x728F	# <CJK>
+0x6A7B	0x7292	# <CJK>
+0x6A7C	0x6308	# <CJK>
+0x6A7D	0x6332	# <CJK>
+0x6A7E	0x63B0	# <CJK>
+0x6B21	0x643F	# <CJK>
+0x6B22	0x64D8	# <CJK>
+0x6B23	0x8004	# <CJK>
+0x6B24	0x6BEA	# <CJK>
+0x6B25	0x6BF3	# <CJK>
+0x6B26	0x6BFD	# <CJK>
+0x6B27	0x6BFF	# <CJK>
+0x6B28	0x6BF9	# <CJK>
+0x6B29	0x6C05	# <CJK>
+0x6B2A	0x6C0C	# <CJK>
+0x6B2B	0x6C06	# <CJK>
+0x6B2C	0x6C0D	# <CJK>
+0x6B2D	0x6C15	# <CJK>
+0x6B2E	0x6C18	# <CJK>
+0x6B2F	0x6C19	# <CJK>
+0x6B30	0x6C1A	# <CJK>
+0x6B31	0x6C21	# <CJK>
+0x6B32	0x6C2C	# <CJK>
+0x6B33	0x6C24	# <CJK>
+0x6B34	0x6C2A	# <CJK>
+0x6B35	0x6C32	# <CJK>
+0x6B36	0x6535	# <CJK>
+0x6B37	0x6555	# <CJK>
+0x6B38	0x656B	# <CJK>
+0x6B39	0x7258	# <CJK>
+0x6B3A	0x7252	# <CJK>
+0x6B3B	0x7256	# <CJK>
+0x6B3C	0x7230	# <CJK>
+0x6B3D	0x8662	# <CJK>
+0x6B3E	0x5216	# <CJK>
+0x6B3F	0x809F	# <CJK>
+0x6B40	0x809C	# <CJK>
+0x6B41	0x8093	# <CJK>
+0x6B42	0x80BC	# <CJK>
+0x6B43	0x670A	# <CJK>
+0x6B44	0x80BD	# <CJK>
+0x6B45	0x80B1	# <CJK>
+0x6B46	0x80AB	# <CJK>
+0x6B47	0x80AD	# <CJK>
+0x6B48	0x80B4	# <CJK>
+0x6B49	0x80B7	# <CJK>
+0x6B4A	0x6727	# <CJK>
+0x6B4B	0x8156	# <CJK>
+0x6B4C	0x80E9	# <CJK>
+0x6B4D	0x81DA	# <CJK>
+0x6B4E	0x80DB	# <CJK>
+0x6B4F	0x80C2	# <CJK>
+0x6B50	0x80C4	# <CJK>
+0x6B51	0x80D9	# <CJK>
+0x6B52	0x80CD	# <CJK>
+0x6B53	0x80D7	# <CJK>
+0x6B54	0x6710	# <CJK>
+0x6B55	0x80DD	# <CJK>
+0x6B56	0x811B	# <CJK>
+0x6B57	0x80F1	# <CJK>
+0x6B58	0x80F4	# <CJK>
+0x6B59	0x80ED	# <CJK>
+0x6B5A	0x81BE	# <CJK>
+0x6B5B	0x810E	# <CJK>
+0x6B5C	0x80F2	# <CJK>
+0x6B5D	0x80FC	# <CJK>
+0x6B5E	0x6715	# <CJK>
+0x6B5F	0x8112	# <CJK>
+0x6B60	0x8C5A	# <CJK>
+0x6B61	0x8161	# <CJK>
+0x6B62	0x811E	# <CJK>
+0x6B63	0x812C	# <CJK>
+0x6B64	0x8118	# <CJK>
+0x6B65	0x8132	# <CJK>
+0x6B66	0x8148	# <CJK>
+0x6B67	0x814C	# <CJK>
+0x6B68	0x8153	# <CJK>
+0x6B69	0x8174	# <CJK>
+0x6B6A	0x8159	# <CJK>
+0x6B6B	0x815A	# <CJK>
+0x6B6C	0x8171	# <CJK>
+0x6B6D	0x8160	# <CJK>
+0x6B6E	0x8169	# <CJK>
+0x6B6F	0x817C	# <CJK>
+0x6B70	0x817D	# <CJK>
+0x6B71	0x816D	# <CJK>
+0x6B72	0x8167	# <CJK>
+0x6B73	0x584D	# <CJK>
+0x6B74	0x5AB5	# <CJK>
+0x6B75	0x8188	# <CJK>
+0x6B76	0x8182	# <CJK>
+0x6B77	0x81CF	# <CJK>
+0x6B78	0x6ED5	# <CJK>
+0x6B79	0x81A3	# <CJK>
+0x6B7A	0x81AA	# <CJK>
+0x6B7B	0x81CC	# <CJK>
+0x6B7C	0x6726	# <CJK>
+0x6B7D	0x81CA	# <CJK>
+0x6B7E	0x81BB	# <CJK>
+0x6C21	0x81C1	# <CJK>
+0x6C22	0x81A6	# <CJK>
+0x6C23	0x6B5F	# <CJK>
+0x6C24	0x6B37	# <CJK>
+0x6C25	0x6B39	# <CJK>
+0x6C26	0x6B43	# <CJK>
+0x6C27	0x6B46	# <CJK>
+0x6C28	0x6B59	# <CJK>
+0x6C29	0x98AE	# <CJK>
+0x6C2A	0x98AF	# <CJK>
+0x6C2B	0x98B6	# <CJK>
+0x6C2C	0x98BC	# <CJK>
+0x6C2D	0x98C6	# <CJK>
+0x6C2E	0x98C8	# <CJK>
+0x6C2F	0x6BB3	# <CJK>
+0x6C30	0x5F40	# <CJK>
+0x6C31	0x8F42	# <CJK>
+0x6C32	0x89F3	# <CJK>
+0x6C33	0x6590	# <CJK>
+0x6C34	0x9F4F	# <CJK>
+0x6C35	0x6595	# <CJK>
+0x6C36	0x65BC	# <CJK>
+0x6C37	0x65C6	# <CJK>
+0x6C38	0x65C4	# <CJK>
+0x6C39	0x65C3	# <CJK>
+0x6C3A	0x65CC	# <CJK>
+0x6C3B	0x65CE	# <CJK>
+0x6C3C	0x65D2	# <CJK>
+0x6C3D	0x65D6	# <CJK>
+0x6C3E	0x716C	# <CJK>
+0x6C3F	0x7152	# <CJK>
+0x6C40	0x7096	# <CJK>
+0x6C41	0x7197	# <CJK>
+0x6C42	0x70BB	# <CJK>
+0x6C43	0x70C0	# <CJK>
+0x6C44	0x70B7	# <CJK>
+0x6C45	0x70AB	# <CJK>
+0x6C46	0x70B1	# <CJK>
+0x6C47	0x71C1	# <CJK>
+0x6C48	0x70CA	# <CJK>
+0x6C49	0x7110	# <CJK>
+0x6C4A	0x7113	# <CJK>
+0x6C4B	0x71DC	# <CJK>
+0x6C4C	0x712F	# <CJK>
+0x6C4D	0x7131	# <CJK>
+0x6C4E	0x7173	# <CJK>
+0x6C4F	0x715C	# <CJK>
+0x6C50	0x7168	# <CJK>
+0x6C51	0x7145	# <CJK>
+0x6C52	0x7172	# <CJK>
+0x6C53	0x714A	# <CJK>
+0x6C54	0x7178	# <CJK>
+0x6C55	0x717A	# <CJK>
+0x6C56	0x7198	# <CJK>
+0x6C57	0x71B3	# <CJK>
+0x6C58	0x71B5	# <CJK>
+0x6C59	0x71A8	# <CJK>
+0x6C5A	0x71A0	# <CJK>
+0x6C5B	0x71E0	# <CJK>
+0x6C5C	0x71D4	# <CJK>
+0x6C5D	0x71E7	# <CJK>
+0x6C5E	0x71F9	# <CJK>
+0x6C5F	0x721D	# <CJK>
+0x6C60	0x7228	# <CJK>
+0x6C61	0x706C	# <CJK>
+0x6C62	0x71FE	# <CJK>
+0x6C63	0x7166	# <CJK>
+0x6C64	0x71B9	# <CJK>
+0x6C65	0x623E	# <CJK>
+0x6C66	0x623D	# <CJK>
+0x6C67	0x6243	# <CJK>
+0x6C68	0x6248	# <CJK>
+0x6C69	0x6249	# <CJK>
+0x6C6A	0x793B	# <CJK>
+0x6C6B	0x7940	# <CJK>
+0x6C6C	0x7946	# <CJK>
+0x6C6D	0x7949	# <CJK>
+0x6C6E	0x795B	# <CJK>
+0x6C6F	0x795C	# <CJK>
+0x6C70	0x7953	# <CJK>
+0x6C71	0x795A	# <CJK>
+0x6C72	0x79B0	# <CJK>
+0x6C73	0x7957	# <CJK>
+0x6C74	0x7960	# <CJK>
+0x6C75	0x798E	# <CJK>
+0x6C76	0x7967	# <CJK>
+0x6C77	0x797A	# <CJK>
+0x6C78	0x79AA	# <CJK>
+0x6C79	0x798A	# <CJK>
+0x6C7A	0x799A	# <CJK>
+0x6C7B	0x79A7	# <CJK>
+0x6C7C	0x79B3	# <CJK>
+0x6C7D	0x5FD1	# <CJK>
+0x6C7E	0x5FD0	# <CJK>
+0x6D21	0x61DF	# <CJK>
+0x6D22	0x605D	# <CJK>
+0x6D23	0x605A	# <CJK>
+0x6D24	0x6067	# <CJK>
+0x6D25	0x6041	# <CJK>
+0x6D26	0x6059	# <CJK>
+0x6D27	0x6063	# <CJK>
+0x6D28	0x6164	# <CJK>
+0x6D29	0x6106	# <CJK>
+0x6D2A	0x610D	# <CJK>
+0x6D2B	0x615D	# <CJK>
+0x6D2C	0x61A9	# <CJK>
+0x6D2D	0x619D	# <CJK>
+0x6D2E	0x61CB	# <CJK>
+0x6D2F	0x61E3	# <CJK>
+0x6D30	0x6207	# <CJK>
+0x6D31	0x8080	# <CJK>
+0x6D32	0x807F	# <CJK>
+0x6D33	0x6C93	# <CJK>
+0x6D34	0x6FA9	# <CJK>
+0x6D35	0x6DFC	# <CJK>
+0x6D36	0x78EF	# <CJK>
+0x6D37	0x77F8	# <CJK>
+0x6D38	0x78AD	# <CJK>
+0x6D39	0x7809	# <CJK>
+0x6D3A	0x7868	# <CJK>
+0x6D3B	0x7818	# <CJK>
+0x6D3C	0x7811	# <CJK>
+0x6D3D	0x65AB	# <CJK>
+0x6D3E	0x782D	# <CJK>
+0x6D3F	0x78B8	# <CJK>
+0x6D40	0x781D	# <CJK>
+0x6D41	0x7839	# <CJK>
+0x6D42	0x792A	# <CJK>
+0x6D43	0x7931	# <CJK>
+0x6D44	0x781F	# <CJK>
+0x6D45	0x783C	# <CJK>
+0x6D46	0x7825	# <CJK>
+0x6D47	0x782C	# <CJK>
+0x6D48	0x7823	# <CJK>
+0x6D49	0x7829	# <CJK>
+0x6D4A	0x784E	# <CJK>
+0x6D4B	0x786D	# <CJK>
+0x6D4C	0x7864	# <CJK>
+0x6D4D	0x78FD	# <CJK>
+0x6D4E	0x7826	# <CJK>
+0x6D4F	0x7850	# <CJK>
+0x6D50	0x7847	# <CJK>
+0x6D51	0x784C	# <CJK>
+0x6D52	0x786A	# <CJK>
+0x6D53	0x78E7	# <CJK>
+0x6D54	0x7893	# <CJK>
+0x6D55	0x789A	# <CJK>
+0x6D56	0x7887	# <CJK>
+0x6D57	0x78E3	# <CJK>
+0x6D58	0x78A1	# <CJK>
+0x6D59	0x78A3	# <CJK>
+0x6D5A	0x78B2	# <CJK>
+0x6D5B	0x78B9	# <CJK>
+0x6D5C	0x78A5	# <CJK>
+0x6D5D	0x78D4	# <CJK>
+0x6D5E	0x78D9	# <CJK>
+0x6D5F	0x78C9	# <CJK>
+0x6D60	0x78EC	# <CJK>
+0x6D61	0x78F2	# <CJK>
+0x6D62	0x7905	# <CJK>
+0x6D63	0x78F4	# <CJK>
+0x6D64	0x7913	# <CJK>
+0x6D65	0x7924	# <CJK>
+0x6D66	0x791E	# <CJK>
+0x6D67	0x7934	# <CJK>
+0x6D68	0x9F95	# <CJK>
+0x6D69	0x9EF9	# <CJK>
+0x6D6A	0x9EFB	# <CJK>
+0x6D6B	0x9EFC	# <CJK>
+0x6D6C	0x76F1	# <CJK>
+0x6D6D	0x7704	# <CJK>
+0x6D6E	0x7798	# <CJK>
+0x6D6F	0x76F9	# <CJK>
+0x6D70	0x7707	# <CJK>
+0x6D71	0x7708	# <CJK>
+0x6D72	0x771A	# <CJK>
+0x6D73	0x7722	# <CJK>
+0x6D74	0x7719	# <CJK>
+0x6D75	0x772D	# <CJK>
+0x6D76	0x7726	# <CJK>
+0x6D77	0x7735	# <CJK>
+0x6D78	0x7738	# <CJK>
+0x6D79	0x775E	# <CJK>
+0x6D7A	0x77BC	# <CJK>
+0x6D7B	0x7747	# <CJK>
+0x6D7C	0x7743	# <CJK>
+0x6D7D	0x775A	# <CJK>
+0x6D7E	0x7768	# <CJK>
+0x6E21	0x7762	# <CJK>
+0x6E22	0x7765	# <CJK>
+0x6E23	0x777F	# <CJK>
+0x6E24	0x778D	# <CJK>
+0x6E25	0x777D	# <CJK>
+0x6E26	0x7780	# <CJK>
+0x6E27	0x778C	# <CJK>
+0x6E28	0x7791	# <CJK>
+0x6E29	0x779F	# <CJK>
+0x6E2A	0x77A0	# <CJK>
+0x6E2B	0x77B0	# <CJK>
+0x6E2C	0x77B5	# <CJK>
+0x6E2D	0x77BD	# <CJK>
+0x6E2E	0x753A	# <CJK>
+0x6E2F	0x7540	# <CJK>
+0x6E30	0x754E	# <CJK>
+0x6E31	0x754B	# <CJK>
+0x6E32	0x7548	# <CJK>
+0x6E33	0x755B	# <CJK>
+0x6E34	0x7572	# <CJK>
+0x6E35	0x7579	# <CJK>
+0x6E36	0x7583	# <CJK>
+0x6E37	0x7F58	# <CJK>
+0x6E38	0x7F61	# <CJK>
+0x6E39	0x7F5F	# <CJK>
+0x6E3A	0x8A48	# <CJK>
+0x6E3B	0x7F68	# <CJK>
+0x6E3C	0x7F86	# <CJK>
+0x6E3D	0x7F71	# <CJK>
+0x6E3E	0x7F79	# <CJK>
+0x6E3F	0x7F88	# <CJK>
+0x6E40	0x7F7E	# <CJK>
+0x6E41	0x76CD	# <CJK>
+0x6E42	0x76E5	# <CJK>
+0x6E43	0x8832	# <CJK>
+0x6E44	0x91D2	# <CJK>
+0x6E45	0x91D3	# <CJK>
+0x6E46	0x91D4	# <CJK>
+0x6E47	0x91D9	# <CJK>
+0x6E48	0x91D7	# <CJK>
+0x6E49	0x91D5	# <CJK>
+0x6E4A	0x91F7	# <CJK>
+0x6E4B	0x91E7	# <CJK>
+0x6E4C	0x91E4	# <CJK>
+0x6E4D	0x9346	# <CJK>
+0x6E4E	0x91F5	# <CJK>
+0x6E4F	0x91F9	# <CJK>
+0x6E50	0x9208	# <CJK>
+0x6E51	0x9226	# <CJK>
+0x6E52	0x9245	# <CJK>
+0x6E53	0x9211	# <CJK>
+0x6E54	0x9210	# <CJK>
+0x6E55	0x9201	# <CJK>
+0x6E56	0x9227	# <CJK>
+0x6E57	0x9204	# <CJK>
+0x6E58	0x9225	# <CJK>
+0x6E59	0x9200	# <CJK>
+0x6E5A	0x923A	# <CJK>
+0x6E5B	0x9266	# <CJK>
+0x6E5C	0x9237	# <CJK>
+0x6E5D	0x9233	# <CJK>
+0x6E5E	0x9255	# <CJK>
+0x6E5F	0x923D	# <CJK>
+0x6E60	0x9238	# <CJK>
+0x6E61	0x925E	# <CJK>
+0x6E62	0x926C	# <CJK>
+0x6E63	0x926D	# <CJK>
+0x6E64	0x923F	# <CJK>
+0x6E65	0x9460	# <CJK>
+0x6E66	0x9230	# <CJK>
+0x6E67	0x9249	# <CJK>
+0x6E68	0x9248	# <CJK>
+0x6E69	0x924D	# <CJK>
+0x6E6A	0x922E	# <CJK>
+0x6E6B	0x9239	# <CJK>
+0x6E6C	0x9438	# <CJK>
+0x6E6D	0x92AC	# <CJK>
+0x6E6E	0x92A0	# <CJK>
+0x6E6F	0x927A	# <CJK>
+0x6E70	0x92AA	# <CJK>
+0x6E71	0x92EE	# <CJK>
+0x6E72	0x92CF	# <CJK>
+0x6E73	0x9403	# <CJK>
+0x6E74	0x92E3	# <CJK>
+0x6E75	0x943A	# <CJK>
+0x6E76	0x92B1	# <CJK>
+0x6E77	0x92A6	# <CJK>
+0x6E78	0x93A7	# <CJK>
+0x6E79	0x9296	# <CJK>
+0x6E7A	0x92CC	# <CJK>
+0x6E7B	0x92A9	# <CJK>
+0x6E7C	0x93F5	# <CJK>
+0x6E7D	0x9293	# <CJK>
+0x6E7E	0x927F	# <CJK>
+0x6F21	0x93A9	# <CJK>
+0x6F22	0x929A	# <CJK>
+0x6F23	0x931A	# <CJK>
+0x6F24	0x92AB	# <CJK>
+0x6F25	0x9283	# <CJK>
+0x6F26	0x940B	# <CJK>
+0x6F27	0x92A8	# <CJK>
+0x6F28	0x92A3	# <CJK>
+0x6F29	0x9412	# <CJK>
+0x6F2A	0x9338	# <CJK>
+0x6F2B	0x92F1	# <CJK>
+0x6F2C	0x93D7	# <CJK>
+0x6F2D	0x92E5	# <CJK>
+0x6F2E	0x92F0	# <CJK>
+0x6F2F	0x92EF	# <CJK>
+0x6F30	0x92E8	# <CJK>
+0x6F31	0x92BC	# <CJK>
+0x6F32	0x92DD	# <CJK>
+0x6F33	0x92F6	# <CJK>
+0x6F34	0x9426	# <CJK>
+0x6F35	0x9427	# <CJK>
+0x6F36	0x92C3	# <CJK>
+0x6F37	0x92DF	# <CJK>
+0x6F38	0x92E6	# <CJK>
+0x6F39	0x9312	# <CJK>
+0x6F3A	0x9306	# <CJK>
+0x6F3B	0x9369	# <CJK>
+0x6F3C	0x931B	# <CJK>
+0x6F3D	0x9340	# <CJK>
+0x6F3E	0x9301	# <CJK>
+0x6F3F	0x9315	# <CJK>
+0x6F40	0x932E	# <CJK>
+0x6F41	0x9343	# <CJK>
+0x6F42	0x9307	# <CJK>
+0x6F43	0x9308	# <CJK>
+0x6F44	0x931F	# <CJK>
+0x6F45	0x9319	# <CJK>
+0x6F46	0x9365	# <CJK>
+0x6F47	0x9347	# <CJK>
+0x6F48	0x9376	# <CJK>
+0x6F49	0x9354	# <CJK>
+0x6F4A	0x9364	# <CJK>
+0x6F4B	0x93AA	# <CJK>
+0x6F4C	0x9370	# <CJK>
+0x6F4D	0x9384	# <CJK>
+0x6F4E	0x93E4	# <CJK>
+0x6F4F	0x93D8	# <CJK>
+0x6F50	0x9428	# <CJK>
+0x6F51	0x9387	# <CJK>
+0x6F52	0x93CC	# <CJK>
+0x6F53	0x9398	# <CJK>
+0x6F54	0x93B8	# <CJK>
+0x6F55	0x93BF	# <CJK>
+0x6F56	0x93A6	# <CJK>
+0x6F57	0x93B0	# <CJK>
+0x6F58	0x93B5	# <CJK>
+0x6F59	0x944C	# <CJK>
+0x6F5A	0x93E2	# <CJK>
+0x6F5B	0x93DC	# <CJK>
+0x6F5C	0x93DD	# <CJK>
+0x6F5D	0x93CD	# <CJK>
+0x6F5E	0x93DE	# <CJK>
+0x6F5F	0x93C3	# <CJK>
+0x6F60	0x93C7	# <CJK>
+0x6F61	0x93D1	# <CJK>
+0x6F62	0x9414	# <CJK>
+0x6F63	0x941D	# <CJK>
+0x6F64	0x93F7	# <CJK>
+0x6F65	0x9465	# <CJK>
+0x6F66	0x9413	# <CJK>
+0x6F67	0x946D	# <CJK>
+0x6F68	0x9420	# <CJK>
+0x6F69	0x9479	# <CJK>
+0x6F6A	0x93F9	# <CJK>
+0x6F6B	0x9419	# <CJK>
+0x6F6C	0x944A	# <CJK>
+0x6F6D	0x9432	# <CJK>
+0x6F6E	0x943F	# <CJK>
+0x6F6F	0x9454	# <CJK>
+0x6F70	0x9463	# <CJK>
+0x6F71	0x937E	# <CJK>
+0x6F72	0x77E7	# <CJK>
+0x6F73	0x77EC	# <CJK>
+0x6F74	0x96C9	# <CJK>
+0x6F75	0x79D5	# <CJK>
+0x6F76	0x79ED	# <CJK>
+0x6F77	0x79E3	# <CJK>
+0x6F78	0x79EB	# <CJK>
+0x6F79	0x7A06	# <CJK>
+0x6F7A	0x5D47	# <CJK>
+0x6F7B	0x7A03	# <CJK>
+0x6F7C	0x7A02	# <CJK>
+0x6F7D	0x7A1E	# <CJK>
+0x6F7E	0x7A14	# <CJK>
+0x7021	0x7A39	# <CJK>
+0x7022	0x7A37	# <CJK>
+0x7023	0x7A61	# <CJK>
+0x7024	0x9ECF	# <CJK>
+0x7025	0x99A5	# <CJK>
+0x7026	0x7A70	# <CJK>
+0x7027	0x7688	# <CJK>
+0x7028	0x768E	# <CJK>
+0x7029	0x7693	# <CJK>
+0x702A	0x7699	# <CJK>
+0x702B	0x76A4	# <CJK>
+0x702C	0x74DE	# <CJK>
+0x702D	0x74E0	# <CJK>
+0x702E	0x752C	# <CJK>
+0x702F	0x9CE9	# <CJK>
+0x7030	0x9CF6	# <CJK>
+0x7031	0x9D07	# <CJK>
+0x7032	0x9D06	# <CJK>
+0x7033	0x9D23	# <CJK>
+0x7034	0x9D87	# <CJK>
+0x7035	0x9E15	# <CJK>
+0x7036	0x9D1D	# <CJK>
+0x7037	0x9D1F	# <CJK>
+0x7038	0x9DE5	# <CJK>
+0x7039	0x9D2F	# <CJK>
+0x703A	0x9DD9	# <CJK>
+0x703B	0x9D30	# <CJK>
+0x703C	0x9D42	# <CJK>
+0x703D	0x9E1E	# <CJK>
+0x703E	0x9D53	# <CJK>
+0x703F	0x9E1D	# <CJK>
+0x7040	0x9D60	# <CJK>
+0x7041	0x9D52	# <CJK>
+0x7042	0x9DF3	# <CJK>
+0x7043	0x9D5C	# <CJK>
+0x7044	0x9D61	# <CJK>
+0x7045	0x9D93	# <CJK>
+0x7046	0x9D6A	# <CJK>
+0x7047	0x9D6F	# <CJK>
+0x7048	0x9D89	# <CJK>
+0x7049	0x9D98	# <CJK>
+0x704A	0x9D9A	# <CJK>
+0x704B	0x9DC0	# <CJK>
+0x704C	0x9DA5	# <CJK>
+0x704D	0x9DA9	# <CJK>
+0x704E	0x9DC2	# <CJK>
+0x704F	0x9DBC	# <CJK>
+0x7050	0x9E1A	# <CJK>
+0x7051	0x9DD3	# <CJK>
+0x7052	0x9DDA	# <CJK>
+0x7053	0x9DEF	# <CJK>
+0x7054	0x9DE6	# <CJK>
+0x7055	0x9DF2	# <CJK>
+0x7056	0x9DF8	# <CJK>
+0x7057	0x9E0C	# <CJK>
+0x7058	0x9DFA	# <CJK>
+0x7059	0x9E1B	# <CJK>
+0x705A	0x7592	# <CJK>
+0x705B	0x7594	# <CJK>
+0x705C	0x7664	# <CJK>
+0x705D	0x7658	# <CJK>
+0x705E	0x759D	# <CJK>
+0x705F	0x7667	# <CJK>
+0x7060	0x75A3	# <CJK>
+0x7061	0x75B3	# <CJK>
+0x7062	0x75B4	# <CJK>
+0x7063	0x75B8	# <CJK>
+0x7064	0x75C4	# <CJK>
+0x7065	0x75B1	# <CJK>
+0x7066	0x75B0	# <CJK>
+0x7067	0x75C3	# <CJK>
+0x7068	0x75C2	# <CJK>
+0x7069	0x7602	# <CJK>
+0x706A	0x75CD	# <CJK>
+0x706B	0x75E3	# <CJK>
+0x706C	0x7646	# <CJK>
+0x706D	0x75E6	# <CJK>
+0x706E	0x75E4	# <CJK>
+0x706F	0x7647	# <CJK>
+0x7070	0x75E7	# <CJK>
+0x7071	0x7603	# <CJK>
+0x7072	0x75F1	# <CJK>
+0x7073	0x75FC	# <CJK>
+0x7074	0x75FF	# <CJK>
+0x7075	0x7610	# <CJK>
+0x7076	0x7600	# <CJK>
+0x7077	0x7649	# <CJK>
+0x7078	0x760C	# <CJK>
+0x7079	0x761E	# <CJK>
+0x707A	0x760A	# <CJK>
+0x707B	0x7625	# <CJK>
+0x707C	0x763B	# <CJK>
+0x707D	0x7615	# <CJK>
+0x707E	0x7619	# <CJK>
+0x7121	0x761B	# <CJK>
+0x7122	0x763C	# <CJK>
+0x7123	0x7622	# <CJK>
+0x7124	0x7620	# <CJK>
+0x7125	0x7640	# <CJK>
+0x7126	0x762D	# <CJK>
+0x7127	0x7630	# <CJK>
+0x7128	0x766D	# <CJK>
+0x7129	0x7635	# <CJK>
+0x712A	0x7643	# <CJK>
+0x712B	0x766E	# <CJK>
+0x712C	0x7633	# <CJK>
+0x712D	0x764D	# <CJK>
+0x712E	0x7669	# <CJK>
+0x712F	0x7654	# <CJK>
+0x7130	0x765C	# <CJK>
+0x7131	0x7656	# <CJK>
+0x7132	0x7672	# <CJK>
+0x7133	0x766F	# <CJK>
+0x7134	0x7FCA	# <CJK>
+0x7135	0x7AE6	# <CJK>
+0x7136	0x7A78	# <CJK>
+0x7137	0x7A79	# <CJK>
+0x7138	0x7A80	# <CJK>
+0x7139	0x7A86	# <CJK>
+0x713A	0x7A88	# <CJK>
+0x713B	0x7A95	# <CJK>
+0x713C	0x7AC7	# <CJK>
+0x713D	0x7AA0	# <CJK>
+0x713E	0x7AAC	# <CJK>
+0x713F	0x7AA8	# <CJK>
+0x7140	0x7AB6	# <CJK>
+0x7141	0x7AB3	# <CJK>
+0x7142	0x8864	# <CJK>
+0x7143	0x8869	# <CJK>
+0x7144	0x8872	# <CJK>
+0x7145	0x887D	# <CJK>
+0x7146	0x887F	# <CJK>
+0x7147	0x8882	# <CJK>
+0x7148	0x88A2	# <CJK>
+0x7149	0x8960	# <CJK>
+0x714A	0x88B7	# <CJK>
+0x714B	0x88BC	# <CJK>
+0x714C	0x88C9	# <CJK>
+0x714D	0x8933	# <CJK>
+0x714E	0x88CE	# <CJK>
+0x714F	0x895D	# <CJK>
+0x7150	0x8947	# <CJK>
+0x7151	0x88F1	# <CJK>
+0x7152	0x891A	# <CJK>
+0x7153	0x88FC	# <CJK>
+0x7154	0x88E8	# <CJK>
+0x7155	0x88FE	# <CJK>
+0x7156	0x88F0	# <CJK>
+0x7157	0x8921	# <CJK>
+0x7158	0x8919	# <CJK>
+0x7159	0x8913	# <CJK>
+0x715A	0x8938	# <CJK>
+0x715B	0x890A	# <CJK>
+0x715C	0x8964	# <CJK>
+0x715D	0x892B	# <CJK>
+0x715E	0x8936	# <CJK>
+0x715F	0x8941	# <CJK>
+0x7160	0x8966	# <CJK>
+0x7161	0x897B	# <CJK>
+0x7162	0x758B	# <CJK>
+0x7163	0x80E5	# <CJK>
+0x7164	0x76B8	# <CJK>
+0x7165	0x76B4	# <CJK>
+0x7166	0x77DC	# <CJK>
+0x7167	0x8012	# <CJK>
+0x7168	0x8014	# <CJK>
+0x7169	0x8016	# <CJK>
+0x716A	0x801C	# <CJK>
+0x716B	0x8020	# <CJK>
+0x716C	0x802E	# <CJK>
+0x716D	0x8025	# <CJK>
+0x716E	0x8026	# <CJK>
+0x716F	0x802C	# <CJK>
+0x7170	0x8029	# <CJK>
+0x7171	0x8028	# <CJK>
+0x7172	0x8031	# <CJK>
+0x7173	0x800B	# <CJK>
+0x7174	0x8035	# <CJK>
+0x7175	0x8043	# <CJK>
+0x7176	0x8046	# <CJK>
+0x7177	0x8079	# <CJK>
+0x7178	0x8052	# <CJK>
+0x7179	0x8075	# <CJK>
+0x717A	0x8071	# <CJK>
+0x717B	0x8983	# <CJK>
+0x717C	0x9807	# <CJK>
+0x717D	0x980E	# <CJK>
+0x717E	0x980F	# <CJK>
+0x7221	0x9821	# <CJK>
+0x7222	0x981C	# <CJK>
+0x7223	0x6F41	# <CJK>
+0x7224	0x9826	# <CJK>
+0x7225	0x9837	# <CJK>
+0x7226	0x984E	# <CJK>
+0x7227	0x9853	# <CJK>
+0x7228	0x9873	# <CJK>
+0x7229	0x9862	# <CJK>
+0x722A	0x9859	# <CJK>
+0x722B	0x9865	# <CJK>
+0x722C	0x986C	# <CJK>
+0x722D	0x9870	# <CJK>
+0x722E	0x864D	# <CJK>
+0x722F	0x8654	# <CJK>
+0x7230	0x866C	# <CJK>
+0x7231	0x87E3	# <CJK>
+0x7232	0x8806	# <CJK>
+0x7233	0x867A	# <CJK>
+0x7234	0x867C	# <CJK>
+0x7235	0x867B	# <CJK>
+0x7236	0x86A8	# <CJK>
+0x7237	0x868D	# <CJK>
+0x7238	0x868B	# <CJK>
+0x7239	0x8706	# <CJK>
+0x723A	0x869D	# <CJK>
+0x723B	0x86A7	# <CJK>
+0x723C	0x86A3	# <CJK>
+0x723D	0x86AA	# <CJK>
+0x723E	0x8693	# <CJK>
+0x723F	0x86A9	# <CJK>
+0x7240	0x86B6	# <CJK>
+0x7241	0x86C4	# <CJK>
+0x7242	0x86B5	# <CJK>
+0x7243	0x8823	# <CJK>
+0x7244	0x86B0	# <CJK>
+0x7245	0x86BA	# <CJK>
+0x7246	0x86B1	# <CJK>
+0x7247	0x86AF	# <CJK>
+0x7248	0x86C9	# <CJK>
+0x7249	0x87F6	# <CJK>
+0x724A	0x86B4	# <CJK>
+0x724B	0x86E9	# <CJK>
+0x724C	0x86FA	# <CJK>
+0x724D	0x87EF	# <CJK>
+0x724E	0x86ED	# <CJK>
+0x724F	0x8784	# <CJK>
+0x7250	0x86D0	# <CJK>
+0x7251	0x8713	# <CJK>
+0x7252	0x86DE	# <CJK>
+0x7253	0x8810	# <CJK>
+0x7254	0x86DF	# <CJK>
+0x7255	0x86D8	# <CJK>
+0x7256	0x86D1	# <CJK>
+0x7257	0x8703	# <CJK>
+0x7258	0x8707	# <CJK>
+0x7259	0x86F8	# <CJK>
+0x725A	0x8708	# <CJK>
+0x725B	0x870A	# <CJK>
+0x725C	0x870D	# <CJK>
+0x725D	0x8709	# <CJK>
+0x725E	0x8723	# <CJK>
+0x725F	0x873B	# <CJK>
+0x7260	0x871E	# <CJK>
+0x7261	0x8725	# <CJK>
+0x7262	0x872E	# <CJK>
+0x7263	0x871A	# <CJK>
+0x7264	0x873E	# <CJK>
+0x7265	0x87C8	# <CJK>
+0x7266	0x8734	# <CJK>
+0x7267	0x8731	# <CJK>
+0x7268	0x8729	# <CJK>
+0x7269	0x8737	# <CJK>
+0x726A	0x873F	# <CJK>
+0x726B	0x8782	# <CJK>
+0x726C	0x8722	# <CJK>
+0x726D	0x877D	# <CJK>
+0x726E	0x8811	# <CJK>
+0x726F	0x877B	# <CJK>
+0x7270	0x8760	# <CJK>
+0x7271	0x8770	# <CJK>
+0x7272	0x874C	# <CJK>
+0x7273	0x876E	# <CJK>
+0x7274	0x878B	# <CJK>
+0x7275	0x8753	# <CJK>
+0x7276	0x8763	# <CJK>
+0x7277	0x87BB	# <CJK>
+0x7278	0x8764	# <CJK>
+0x7279	0x8759	# <CJK>
+0x727A	0x8765	# <CJK>
+0x727B	0x8793	# <CJK>
+0x727C	0x87AF	# <CJK>
+0x727D	0x87CE	# <CJK>
+0x727E	0x87D2	# <CJK>
+0x7321	0x87C6	# <CJK>
+0x7322	0x8788	# <CJK>
+0x7323	0x8785	# <CJK>
+0x7324	0x87AD	# <CJK>
+0x7325	0x8797	# <CJK>
+0x7326	0x8783	# <CJK>
+0x7327	0x87AB	# <CJK>
+0x7328	0x87E5	# <CJK>
+0x7329	0x87AC	# <CJK>
+0x732A	0x87B5	# <CJK>
+0x732B	0x87B3	# <CJK>
+0x732C	0x87CB	# <CJK>
+0x732D	0x87D3	# <CJK>
+0x732E	0x87BD	# <CJK>
+0x732F	0x87D1	# <CJK>
+0x7330	0x87C0	# <CJK>
+0x7331	0x87CA	# <CJK>
+0x7332	0x87DB	# <CJK>
+0x7333	0x87EA	# <CJK>
+0x7334	0x87E0	# <CJK>
+0x7335	0x87EE	# <CJK>
+0x7336	0x8816	# <CJK>
+0x7337	0x8813	# <CJK>
+0x7338	0x87FE	# <CJK>
+0x7339	0x880A	# <CJK>
+0x733A	0x881B	# <CJK>
+0x733B	0x8821	# <CJK>
+0x733C	0x8839	# <CJK>
+0x733D	0x883C	# <CJK>
+0x733E	0x7F36	# <CJK>
+0x733F	0x7F4C	# <CJK>
+0x7340	0x7F44	# <CJK>
+0x7341	0x7F45	# <CJK>
+0x7342	0x8210	# <CJK>
+0x7343	0x7AFA	# <CJK>
+0x7344	0x7AFD	# <CJK>
+0x7345	0x7B08	# <CJK>
+0x7346	0x7BE4	# <CJK>
+0x7347	0x7B04	# <CJK>
+0x7348	0x7B67	# <CJK>
+0x7349	0x7B0A	# <CJK>
+0x734A	0x7B2B	# <CJK>
+0x734B	0x7B0F	# <CJK>
+0x734C	0x7B47	# <CJK>
+0x734D	0x7B38	# <CJK>
+0x734E	0x7B2A	# <CJK>
+0x734F	0x7B19	# <CJK>
+0x7350	0x7B2E	# <CJK>
+0x7351	0x7B31	# <CJK>
+0x7352	0x7B20	# <CJK>
+0x7353	0x7B25	# <CJK>
+0x7354	0x7B24	# <CJK>
+0x7355	0x7B33	# <CJK>
+0x7356	0x7C69	# <CJK>
+0x7357	0x7B1E	# <CJK>
+0x7358	0x7B58	# <CJK>
+0x7359	0x7BF3	# <CJK>
+0x735A	0x7B45	# <CJK>
+0x735B	0x7B75	# <CJK>
+0x735C	0x7B4C	# <CJK>
+0x735D	0x7B8F	# <CJK>
+0x735E	0x7B60	# <CJK>
+0x735F	0x7B6E	# <CJK>
+0x7360	0x7B7B	# <CJK>
+0x7361	0x7B62	# <CJK>
+0x7362	0x7B72	# <CJK>
+0x7363	0x7B71	# <CJK>
+0x7364	0x7B90	# <CJK>
+0x7365	0x7C00	# <CJK>
+0x7366	0x7BCB	# <CJK>
+0x7367	0x7BB8	# <CJK>
+0x7368	0x7BAC	# <CJK>
+0x7369	0x7B9D	# <CJK>
+0x736A	0x7C5C	# <CJK>
+0x736B	0x7B85	# <CJK>
+0x736C	0x7C1E	# <CJK>
+0x736D	0x7B9C	# <CJK>
+0x736E	0x7BA2	# <CJK>
+0x736F	0x7C2B	# <CJK>
+0x7370	0x7BB4	# <CJK>
+0x7371	0x7C23	# <CJK>
+0x7372	0x7BC1	# <CJK>
+0x7373	0x7BCC	# <CJK>
+0x7374	0x7BDD	# <CJK>
+0x7375	0x7BDA	# <CJK>
+0x7376	0x7BE5	# <CJK>
+0x7377	0x7BE6	# <CJK>
+0x7378	0x7BEA	# <CJK>
+0x7379	0x7C0C	# <CJK>
+0x737A	0x7BFE	# <CJK>
+0x737B	0x7BFC	# <CJK>
+0x737C	0x7C0F	# <CJK>
+0x737D	0x7C6A	# <CJK>
+0x737E	0x7C0B	# <CJK>
+0x7421	0x7C1F	# <CJK>
+0x7422	0x7C2A	# <CJK>
+0x7423	0x7C26	# <CJK>
+0x7424	0x7C38	# <CJK>
+0x7425	0x7C5F	# <CJK>
+0x7426	0x7C40	# <CJK>
+0x7427	0x81FE	# <CJK>
+0x7428	0x8201	# <CJK>
+0x7429	0x8202	# <CJK>
+0x742A	0x8204	# <CJK>
+0x742B	0x81EC	# <CJK>
+0x742C	0x8844	# <CJK>
+0x742D	0x8221	# <CJK>
+0x742E	0x8222	# <CJK>
+0x742F	0x8264	# <CJK>
+0x7430	0x822D	# <CJK>
+0x7431	0x822F	# <CJK>
+0x7432	0x8228	# <CJK>
+0x7433	0x822B	# <CJK>
+0x7434	0x8238	# <CJK>
+0x7435	0x826B	# <CJK>
+0x7436	0x8233	# <CJK>
+0x7437	0x8234	# <CJK>
+0x7438	0x823E	# <CJK>
+0x7439	0x8244	# <CJK>
+0x743A	0x8249	# <CJK>
+0x743B	0x824B	# <CJK>
+0x743C	0x824F	# <CJK>
+0x743D	0x825A	# <CJK>
+0x743E	0x825F	# <CJK>
+0x743F	0x8268	# <CJK>
+0x7440	0x887E	# <CJK>
+0x7441	0x88CA	# <CJK>
+0x7442	0x8888	# <CJK>
+0x7443	0x88D8	# <CJK>
+0x7444	0x88DF	# <CJK>
+0x7445	0x895E	# <CJK>
+0x7446	0x7F9D	# <CJK>
+0x7447	0x7FA5	# <CJK>
+0x7448	0x7FA7	# <CJK>
+0x7449	0x7FAF	# <CJK>
+0x744A	0x7FB0	# <CJK>
+0x744B	0x7FB2	# <CJK>
+0x744C	0x7C7C	# <CJK>
+0x744D	0x6549	# <CJK>
+0x744E	0x7C91	# <CJK>
+0x744F	0x7CF2	# <CJK>
+0x7450	0x7CF6	# <CJK>
+0x7451	0x7C9E	# <CJK>
+0x7452	0x7CA2	# <CJK>
+0x7453	0x7CB2	# <CJK>
+0x7454	0x7CBC	# <CJK>
+0x7455	0x7CBD	# <CJK>
+0x7456	0x7CDD	# <CJK>
+0x7457	0x7CC7	# <CJK>
+0x7458	0x7CCC	# <CJK>
+0x7459	0x7CCD	# <CJK>
+0x745A	0x7CC8	# <CJK>
+0x745B	0x7CC5	# <CJK>
+0x745C	0x7CD7	# <CJK>
+0x745D	0x7CE8	# <CJK>
+0x745E	0x826E	# <CJK>
+0x745F	0x66A8	# <CJK>
+0x7460	0x7FBF	# <CJK>
+0x7461	0x7FCE	# <CJK>
+0x7462	0x7FD5	# <CJK>
+0x7463	0x7FE5	# <CJK>
+0x7464	0x7FE1	# <CJK>
+0x7465	0x7FE6	# <CJK>
+0x7466	0x7FE9	# <CJK>
+0x7467	0x7FEE	# <CJK>
+0x7468	0x7FF3	# <CJK>
+0x7469	0x7CF8	# <CJK>
+0x746A	0x7E36	# <CJK>
+0x746B	0x7DA6	# <CJK>
+0x746C	0x7DAE	# <CJK>
+0x746D	0x7E47	# <CJK>
+0x746E	0x7E9B	# <CJK>
+0x746F	0x9EA9	# <CJK>
+0x7470	0x9EB4	# <CJK>
+0x7471	0x8D73	# <CJK>
+0x7472	0x8D84	# <CJK>
+0x7473	0x8D94	# <CJK>
+0x7474	0x8D91	# <CJK>
+0x7475	0x8DB2	# <CJK>
+0x7476	0x8D67	# <CJK>
+0x7477	0x8D6D	# <CJK>
+0x7478	0x8C47	# <CJK>
+0x7479	0x8C49	# <CJK>
+0x747A	0x914A	# <CJK>
+0x747B	0x9150	# <CJK>
+0x747C	0x914E	# <CJK>
+0x747D	0x914F	# <CJK>
+0x747E	0x9164	# <CJK>
+0x7521	0x9162	# <CJK>
+0x7522	0x9161	# <CJK>
+0x7523	0x9170	# <CJK>
+0x7524	0x9169	# <CJK>
+0x7525	0x916F	# <CJK>
+0x7526	0x91C5	# <CJK>
+0x7527	0x91C3	# <CJK>
+0x7528	0x9172	# <CJK>
+0x7529	0x9174	# <CJK>
+0x752A	0x9179	# <CJK>
+0x752B	0x918C	# <CJK>
+0x752C	0x9185	# <CJK>
+0x752D	0x9190	# <CJK>
+0x752E	0x918D	# <CJK>
+0x752F	0x9191	# <CJK>
+0x7530	0x91A2	# <CJK>
+0x7531	0x91A3	# <CJK>
+0x7532	0x91AA	# <CJK>
+0x7533	0x91AD	# <CJK>
+0x7534	0x91AE	# <CJK>
+0x7535	0x91AF	# <CJK>
+0x7536	0x91B5	# <CJK>
+0x7537	0x91B4	# <CJK>
+0x7538	0x91BA	# <CJK>
+0x7539	0x8C55	# <CJK>
+0x753A	0x9E7A	# <CJK>
+0x753B	0x8E89	# <CJK>
+0x753C	0x8DEB	# <CJK>
+0x753D	0x8E05	# <CJK>
+0x753E	0x8E59	# <CJK>
+0x753F	0x8E69	# <CJK>
+0x7540	0x8DB5	# <CJK>
+0x7541	0x8DBF	# <CJK>
+0x7542	0x8DBC	# <CJK>
+0x7543	0x8DBA	# <CJK>
+0x7544	0x8E4C	# <CJK>
+0x7545	0x8DD6	# <CJK>
+0x7546	0x8DD7	# <CJK>
+0x7547	0x8DDA	# <CJK>
+0x7548	0x8E92	# <CJK>
+0x7549	0x8DCE	# <CJK>
+0x754A	0x8DCF	# <CJK>
+0x754B	0x8DDB	# <CJK>
+0x754C	0x8DC6	# <CJK>
+0x754D	0x8DEC	# <CJK>
+0x754E	0x8E7A	# <CJK>
+0x754F	0x8E55	# <CJK>
+0x7550	0x8DE3	# <CJK>
+0x7551	0x8E9A	# <CJK>
+0x7552	0x8E8B	# <CJK>
+0x7553	0x8DE4	# <CJK>
+0x7554	0x8E09	# <CJK>
+0x7555	0x8DFD	# <CJK>
+0x7556	0x8E14	# <CJK>
+0x7557	0x8E1D	# <CJK>
+0x7558	0x8E1F	# <CJK>
+0x7559	0x8E93	# <CJK>
+0x755A	0x8E2E	# <CJK>
+0x755B	0x8E23	# <CJK>
+0x755C	0x8E91	# <CJK>
+0x755D	0x8E3A	# <CJK>
+0x755E	0x8E40	# <CJK>
+0x755F	0x8E39	# <CJK>
+0x7560	0x8E35	# <CJK>
+0x7561	0x8E3D	# <CJK>
+0x7562	0x8E31	# <CJK>
+0x7563	0x8E49	# <CJK>
+0x7564	0x8E41	# <CJK>
+0x7565	0x8E42	# <CJK>
+0x7566	0x8EA1	# <CJK>
+0x7567	0x8E63	# <CJK>
+0x7568	0x8E4A	# <CJK>
+0x7569	0x8E70	# <CJK>
+0x756A	0x8E76	# <CJK>
+0x756B	0x8E7C	# <CJK>
+0x756C	0x8E6F	# <CJK>
+0x756D	0x8E74	# <CJK>
+0x756E	0x8E85	# <CJK>
+0x756F	0x8EAA	# <CJK>
+0x7570	0x8E94	# <CJK>
+0x7571	0x8E90	# <CJK>
+0x7572	0x8EA6	# <CJK>
+0x7573	0x8E9E	# <CJK>
+0x7574	0x8C78	# <CJK>
+0x7575	0x8C82	# <CJK>
+0x7576	0x8C8A	# <CJK>
+0x7577	0x8C85	# <CJK>
+0x7578	0x8C98	# <CJK>
+0x7579	0x8C94	# <CJK>
+0x757A	0x659B	# <CJK>
+0x757B	0x89D6	# <CJK>
+0x757C	0x89F4	# <CJK>
+0x757D	0x89DA	# <CJK>
+0x757E	0x89DC	# <CJK>
+0x7621	0x89E5	# <CJK>
+0x7622	0x89EB	# <CJK>
+0x7623	0x89F6	# <CJK>
+0x7624	0x8A3E	# <CJK>
+0x7625	0x8B26	# <CJK>
+0x7626	0x975A	# <CJK>
+0x7627	0x96E9	# <CJK>
+0x7628	0x9742	# <CJK>
+0x7629	0x96EF	# <CJK>
+0x762A	0x9706	# <CJK>
+0x762B	0x973D	# <CJK>
+0x762C	0x9708	# <CJK>
+0x762D	0x970F	# <CJK>
+0x762E	0x970E	# <CJK>
+0x762F	0x972A	# <CJK>
+0x7630	0x9744	# <CJK>
+0x7631	0x9730	# <CJK>
+0x7632	0x973E	# <CJK>
+0x7633	0x9F54	# <CJK>
+0x7634	0x9F5F	# <CJK>
+0x7635	0x9F59	# <CJK>
+0x7636	0x9F60	# <CJK>
+0x7637	0x9F5C	# <CJK>
+0x7638	0x9F66	# <CJK>
+0x7639	0x9F6C	# <CJK>
+0x763A	0x9F6A	# <CJK>
+0x763B	0x9F77	# <CJK>
+0x763C	0x9EFD	# <CJK>
+0x763D	0x9EFF	# <CJK>
+0x763E	0x9F09	# <CJK>
+0x763F	0x96B9	# <CJK>
+0x7640	0x96BC	# <CJK>
+0x7641	0x96BD	# <CJK>
+0x7642	0x96CE	# <CJK>
+0x7643	0x96D2	# <CJK>
+0x7644	0x77BF	# <CJK>
+0x7645	0x8B8E	# <CJK>
+0x7646	0x928E	# <CJK>
+0x7647	0x947E	# <CJK>
+0x7648	0x92C8	# <CJK>
+0x7649	0x93E8	# <CJK>
+0x764A	0x936A	# <CJK>
+0x764B	0x93CA	# <CJK>
+0x764C	0x938F	# <CJK>
+0x764D	0x943E	# <CJK>
+0x764E	0x946B	# <CJK>
+0x764F	0x9B77	# <CJK>
+0x7650	0x9B74	# <CJK>
+0x7651	0x9B81	# <CJK>
+0x7652	0x9B83	# <CJK>
+0x7653	0x9B8E	# <CJK>
+0x7654	0x9C78	# <CJK>
+0x7655	0x7A4C	# <CJK>
+0x7656	0x9B92	# <CJK>
+0x7657	0x9C5F	# <CJK>
+0x7658	0x9B90	# <CJK>
+0x7659	0x9BAD	# <CJK>
+0x765A	0x9B9A	# <CJK>
+0x765B	0x9BAA	# <CJK>
+0x765C	0x9B9E	# <CJK>
+0x765D	0x9C6D	# <CJK>
+0x765E	0x9BAB	# <CJK>
+0x765F	0x9B9D	# <CJK>
+0x7660	0x9C58	# <CJK>
+0x7661	0x9BC1	# <CJK>
+0x7662	0x9C7A	# <CJK>
+0x7663	0x9C31	# <CJK>
+0x7664	0x9C39	# <CJK>
+0x7665	0x9C23	# <CJK>
+0x7666	0x9C37	# <CJK>
+0x7667	0x9BC0	# <CJK>
+0x7668	0x9BCA	# <CJK>
+0x7669	0x9BC7	# <CJK>
+0x766A	0x9BFD	# <CJK>
+0x766B	0x9BD6	# <CJK>
+0x766C	0x9BEA	# <CJK>
+0x766D	0x9BEB	# <CJK>
+0x766E	0x9BE1	# <CJK>
+0x766F	0x9BE4	# <CJK>
+0x7670	0x9BE7	# <CJK>
+0x7671	0x9BDD	# <CJK>
+0x7672	0x9BE2	# <CJK>
+0x7673	0x9BF0	# <CJK>
+0x7674	0x9BDB	# <CJK>
+0x7675	0x9BF4	# <CJK>
+0x7676	0x9BD4	# <CJK>
+0x7677	0x9C5D	# <CJK>
+0x7678	0x9C08	# <CJK>
+0x7679	0x9C10	# <CJK>
+0x767A	0x9C0D	# <CJK>
+0x767B	0x9C12	# <CJK>
+0x767C	0x9C09	# <CJK>
+0x767D	0x9BFF	# <CJK>
+0x767E	0x9C20	# <CJK>
+0x7721	0x9C32	# <CJK>
+0x7722	0x9C2D	# <CJK>
+0x7723	0x9C28	# <CJK>
+0x7724	0x9C25	# <CJK>
+0x7725	0x9C29	# <CJK>
+0x7726	0x9C33	# <CJK>
+0x7727	0x9C3E	# <CJK>
+0x7728	0x9C48	# <CJK>
+0x7729	0x9C3B	# <CJK>
+0x772A	0x9C35	# <CJK>
+0x772B	0x9C45	# <CJK>
+0x772C	0x9C56	# <CJK>
+0x772D	0x9C54	# <CJK>
+0x772E	0x9C52	# <CJK>
+0x772F	0x9C67	# <CJK>
+0x7730	0x977C	# <CJK>
+0x7731	0x9785	# <CJK>
+0x7732	0x97C3	# <CJK>
+0x7733	0x97BD	# <CJK>
+0x7734	0x9794	# <CJK>
+0x7735	0x97C9	# <CJK>
+0x7736	0x97AB	# <CJK>
+0x7737	0x97A3	# <CJK>
+0x7738	0x97B2	# <CJK>
+0x7739	0x97B4	# <CJK>
+0x773A	0x9AB1	# <CJK>
+0x773B	0x9AB0	# <CJK>
+0x773C	0x9AB7	# <CJK>
+0x773D	0x9DBB	# <CJK>
+0x773E	0x9AB6	# <CJK>
+0x773F	0x9ABA	# <CJK>
+0x7740	0x9ABC	# <CJK>
+0x7741	0x9AC1	# <CJK>
+0x7742	0x9AC0	# <CJK>
+0x7743	0x9ACF	# <CJK>
+0x7744	0x9AC2	# <CJK>
+0x7745	0x9AD6	# <CJK>
+0x7746	0x9AD5	# <CJK>
+0x7747	0x9AD1	# <CJK>
+0x7748	0x9B45	# <CJK>
+0x7749	0x9B43	# <CJK>
+0x774A	0x9B58	# <CJK>
+0x774B	0x9B4E	# <CJK>
+0x774C	0x9B48	# <CJK>
+0x774D	0x9B4D	# <CJK>
+0x774E	0x9B51	# <CJK>
+0x774F	0x9957	# <CJK>
+0x7750	0x995C	# <CJK>
+0x7751	0x992E	# <CJK>
+0x7752	0x9955	# <CJK>
+0x7753	0x9954	# <CJK>
+0x7754	0x9ADF	# <CJK>
+0x7755	0x9AE1	# <CJK>
+0x7756	0x9AE6	# <CJK>
+0x7757	0x9AEF	# <CJK>
+0x7758	0x9AEB	# <CJK>
+0x7759	0x9AFB	# <CJK>
+0x775A	0x9AED	# <CJK>
+0x775B	0x9AF9	# <CJK>
+0x775C	0x9B08	# <CJK>
+0x775D	0x9B0F	# <CJK>
+0x775E	0x9B22	# <CJK>
+0x775F	0x9B1F	# <CJK>
+0x7760	0x9B23	# <CJK>
+0x7761	0x4E48	# <CJK>
+0x7762	0x9EBE	# <CJK>
+0x7763	0x7E3B	# <CJK>
+0x7764	0x9E82	# <CJK>
+0x7765	0x9E87	# <CJK>
+0x7766	0x9E88	# <CJK>
+0x7767	0x9E8B	# <CJK>
+0x7768	0x9E92	# <CJK>
+0x7769	0x93D6	# <CJK>
+0x776A	0x9E9D	# <CJK>
+0x776B	0x9E9F	# <CJK>
+0x776C	0x9EDB	# <CJK>
+0x776D	0x9EDC	# <CJK>
+0x776E	0x9EDD	# <CJK>
+0x776F	0x9EE0	# <CJK>
+0x7770	0x9EDF	# <CJK>
+0x7771	0x9EE2	# <CJK>
+0x7772	0x9EF7	# <CJK>
+0x7773	0x9EE7	# <CJK>
+0x7774	0x9EE5	# <CJK>
+0x7775	0x9EF2	# <CJK>
+0x7776	0x9EEF	# <CJK>
+0x7777	0x9F22	# <CJK>
+0x7778	0x9F2C	# <CJK>
+0x7779	0x9F2F	# <CJK>
+0x777A	0x9F39	# <CJK>
+0x777B	0x9F37	# <CJK>
+0x777C	0x9F3D	# <CJK>
+0x777D	0x9F3E	# <CJK>
+0x777E	0x9F44	# <CJK>
+0x7821	0x896C	# <CJK>
+0x7822	0x95C6	# <CJK>
+0x7823	0x9336	# <CJK>
+0x7824	0x5F46	# <CJK>
+0x7825	0x8514	# <CJK>
+0x7826	0x7E94	# <CJK>
+0x7827	0x5382	# <CJK>
+0x7828	0x51B2	# <CJK>
+0x7829	0x4E11	# <CJK>
+0x782A	0x9F63	# <CJK>
+0x782B	0x5679	# <CJK>
+0x782C	0x515A	# <CJK>
+0x782D	0x6DC0	# <CJK>
+0x782E	0x9F15	# <CJK>
+0x782F	0x6597	# <CJK>
+0x7830	0x5641	# <CJK>
+0x7831	0x9AEE	# <CJK>
+0x7832	0x8303	# <CJK>
+0x7833	0x4E30	# <CJK>
+0x7834	0x8907	# <CJK>
+0x7835	0x5E72	# <CJK>
+0x7836	0x7A40	# <CJK>
+0x7837	0x98B3	# <CJK>
+0x7838	0x5E7F	# <CJK>
+0x7839	0x95A4	# <CJK>
+0x783A	0x9B0D	# <CJK>
+0x783B	0x5212	# <CJK>
+0x783C	0x8FF4	# <CJK>
+0x783D	0x5F59	# <CJK>
+0x783E	0x7A6B	# <CJK>
+0x783F	0x98E2	# <CJK>
+0x7840	0x51E0	# <CJK>
+0x7841	0x50A2	# <CJK>
+0x7842	0x4EF7	# <CJK>
+0x7843	0x8350	# <CJK>
+0x7844	0x8591	# <CJK>
+0x7845	0x5118	# <CJK>
+0x7846	0x636E	# <CJK>
+0x7847	0x6372	# <CJK>
+0x7848	0x524B	# <CJK>
+0x7849	0x5938	# <CJK>
+0x784A	0x774F	# <CJK>
+0x784B	0x8721	# <CJK>
+0x784C	0x814A	# <CJK>
+0x784D	0x7E8D	# <CJK>
+0x784E	0x91CC	# <CJK>
+0x784F	0x66C6	# <CJK>
+0x7850	0x5E18	# <CJK>
+0x7851	0x77AD	# <CJK>
+0x7852	0x9E75	# <CJK>
+0x7853	0x56C9	# <CJK>
+0x7854	0x9EF4	# <CJK>
+0x7855	0x6FDB	# <CJK>
+0x7856	0x61DE	# <CJK>
+0x7857	0x77C7	# <CJK>
+0x7858	0x7030	# <CJK>
+0x7859	0x9EB5	# <CJK>
+0x785A	0x884A	# <CJK>
+0x785B	0x95E2	# <CJK>
+0x785C	0x82F9	# <CJK>
+0x785D	0x51ED	# <CJK>
+0x785E	0x6251	# <CJK>
+0x785F	0x4EC6	# <CJK>
+0x7860	0x6734	# <CJK>
+0x7861	0x97C6	# <CJK>
+0x7862	0x7C64	# <CJK>
+0x7863	0x7E34	# <CJK>
+0x7864	0x97A6	# <CJK>
+0x7865	0x9EAF	# <CJK>
+0x7866	0x786E	# <CJK>
+0x7867	0x820D	# <CJK>
+0x7868	0x672F	# <CJK>
+0x7869	0x677E	# <CJK>
+0x786A	0x56CC	# <CJK>
+0x786B	0x53F0	# <CJK>
+0x786C	0x98B1	# <CJK>
+0x786D	0x6AAF	# <CJK>
+0x786E	0x7F4E	# <CJK>
+0x786F	0x6D82	# <CJK>
+0x7870	0x7CF0	# <CJK>
+0x7871	0x4E07	# <CJK>
+0x7872	0x4FC2	# <CJK>
+0x7873	0x7E6B	# <CJK>
+0x7874	0x9E79	# <CJK>
+0x7875	0x56AE	# <CJK>
+0x7876	0x9B1A	# <CJK>
+0x7877	0x846F	# <CJK>
+0x7878	0x53F6	# <CJK>
+0x7879	0x90C1	# <CJK>
+0x787A	0x79A6	# <CJK>
+0x787B	0x7C72	# <CJK>
+0x787C	0x613F	# <CJK>
+0x787D	0x4E91	# <CJK>
+0x787E	0x9AD2	# <CJK>
+0x7921	0x75C7	# <CJK>
+0x7922	0x96BB	# <CJK>
+0x7923	0x53EA	# <CJK>
+0x7924	0x7DFB	# <CJK>
+0x7925	0x88FD	# <CJK>
+0x7926	0x79CD	# <CJK>
+0x7927	0x7843	# <CJK>
+0x7928	0x7B51	# <CJK>
+0x7929	0x51C6	# <CJK>
Index: /main/tags/2.25/gsdl/unicode/MAPPINGS/EASTASIA/GB/GB2312.TXT
===================================================================
--- /main/tags/2.25/gsdl/unicode/MAPPINGS/EASTASIA/GB/GB2312.TXT	(revision 21064)
+++ /main/tags/2.25/gsdl/unicode/MAPPINGS/EASTASIA/GB/GB2312.TXT	(revision 21064)
@@ -0,0 +1,7501 @@
+#
+#	Name:             GB2312-80 to Unicode table (complete, hex format)
+#	Unicode version:  1.1
+#	Table version:    0.0d2
+#	Table format:     Format A
+#	Date:             6 December 1993
+#	Author:           Glenn Adams <glenn@metis.com>
+#                     John H. Jenkins <John_Jenkins@taligent.com>
+#
+#	Copyright (c) 1991-1994 Unicode, Inc.  All Rights reserved.
+#
+#	This file is provided as-is by Unicode, Inc. (The Unicode Consortium).
+#	No claims are made as to fitness for any particular purpose.  No
+#	warranties of any kind are expressed or implied.  The recipient
+#	agrees to determine applicability of information provided.  If this
+#	file has been provided on magnetic media by Unicode, Inc., the sole
+#	remedy for any claim will be exchange of defective media within 90
+#	days of receipt.
+#
+#	Recipient is granted the right to make copies in any form for
+#	internal distribution and to freely use the information supplied
+#	in the creation of products supporting Unicode.  Unicode, Inc.
+#	specifically excludes the right to re-distribute this file directly
+#	to third parties or other organizations whether for profit or not.
+#
+#	General notes:
+#
+#	This table contains the data Metis and Taligent currently have on how
+#       GB2312-80 characters map into Unicode.
+#
+#	Format:  Three tab-separated columns
+#		 Column #1 is the GB2312 code (in hex as 0xXXXX)
+#		 Column #2 is the Unicode (in hex as 0xXXXX)
+#		 Column #3 the Unicode name (follows a comment sign, '#')
+#					The official names for Unicode characters U+4E00
+#					to U+9FA5, inclusive, is "CJK UNIFIED IDEOGRAPH-XXXX",
+#					where XXXX is the code point.  Including all these
+#					names in this file increases its size substantially
+#					and needlessly.  The token "<CJK>" is used for the
+#					name of these characters.  If necessary, it can be
+#					expanded algorithmically by a parser or editor.
+#
+#	The entries are in GB2312 order
+#
+#	The following algorithms can be used to change the hex form
+#		of GB2312 to other standard forms:
+#
+#		To change hex to EUC form, add 0x8080
+#		To change hex to kuten form, first subtract 0x2020.  Then
+#			the high and low bytes correspond to the ku and ten of
+#			the kuten form.  For example, 0x2121 -> 0x0101 -> 0101;
+#			0x777E -> 0x575E -> 8794
+#
+#	Any comments or problems, contact <John_Jenkins@taligent.com>
+#
+#
+0x2121	0x3000	# IDEOGRAPHIC SPACE
+0x2122	0x3001	# IDEOGRAPHIC COMMA
+0x2123	0x3002	# IDEOGRAPHIC FULL STOP
+0x2124	0x30FB	# KATAKANA MIDDLE DOT
+0x2125	0x02C9	# MODIFIER LETTER MACRON (Mandarin Chinese first tone)
+0x2126	0x02C7	# CARON (Mandarin Chinese third tone)
+0x2127	0x00A8	# DIAERESIS
+0x2128	0x3003	# DITTO MARK
+0x2129	0x3005	# IDEOGRAPHIC ITERATION MARK
+0x212A	0x2015	# HORIZONTAL BAR
+0x212B	0xFF5E	# FULLWIDTH TILDE
+0x212C	0x2225	# PARALLEL TO
+0x212D	0x2026	# HORIZONTAL ELLIPSIS
+0x212E	0x2018	# LEFT SINGLE QUOTATION MARK
+0x212F	0x2019	# RIGHT SINGLE QUOTATION MARK
+0x2130	0x201C	# LEFT DOUBLE QUOTATION MARK
+0x2131	0x201D	# RIGHT DOUBLE QUOTATION MARK
+0x2132	0x3014	# LEFT TORTOISE SHELL BRACKET
+0x2133	0x3015	# RIGHT TORTOISE SHELL BRACKET
+0x2134	0x3008	# LEFT ANGLE BRACKET
+0x2135	0x3009	# RIGHT ANGLE BRACKET
+0x2136	0x300A	# LEFT DOUBLE ANGLE BRACKET
+0x2137	0x300B	# RIGHT DOUBLE ANGLE BRACKET
+0x2138	0x300C	# LEFT CORNER BRACKET
+0x2139	0x300D	# RIGHT CORNER BRACKET
+0x213A	0x300E	# LEFT WHITE CORNER BRACKET
+0x213B	0x300F	# RIGHT WHITE CORNER BRACKET
+0x213C	0x3016	# LEFT WHITE LENTICULAR BRACKET
+0x213D	0x3017	# RIGHT WHITE LENTICULAR BRACKET
+0x213E	0x3010	# LEFT BLACK LENTICULAR BRACKET
+0x213F	0x3011	# RIGHT BLACK LENTICULAR BRACKET
+0x2140	0x00B1	# PLUS-MINUS SIGN
+0x2141	0x00D7	# MULTIPLICATION SIGN
+0x2142	0x00F7	# DIVISION SIGN
+0x2143	0x2236	# RATIO
+0x2144	0x2227	# LOGICAL AND
+0x2145	0x2228	# LOGICAL OR
+0x2146	0x2211	# N-ARY SUMMATION
+0x2147	0x220F	# N-ARY PRODUCT
+0x2148	0x222A	# UNION
+0x2149	0x2229	# INTERSECTION
+0x214A	0x2208	# ELEMENT OF
+0x214B	0x2237	# PROPORTION
+0x214C	0x221A	# SQUARE ROOT
+0x214D	0x22A5	# UP TACK
+0x214E	0x2225	# PARALLEL TO
+0x214F	0x2220	# ANGLE
+0x2150	0x2312	# ARC
+0x2151	0x2299	# CIRCLED DOT OPERATOR
+0x2152	0x222B	# INTEGRAL
+0x2153	0x222E	# CONTOUR INTEGRAL
+0x2154	0x2261	# IDENTICAL TO
+0x2155	0x224C	# ALL EQUAL TO
+0x2156	0x2248	# ALMOST EQUAL TO
+0x2157	0x223D	# REVERSED TILDE
+0x2158	0x221D	# PROPORTIONAL TO
+0x2159	0x2260	# NOT EQUAL TO
+0x215A	0x226E	# NOT LESS-THAN
+0x215B	0x226F	# NOT GREATER-THAN
+0x215C	0x2264	# LESS-THAN OR EQUAL TO
+0x215D	0x2265	# GREATER-THAN OR EQUAL TO
+0x215E	0x221E	# INFINITY
+0x215F	0x2235	# BECAUSE
+0x2160	0x2234	# THEREFORE
+0x2161	0x2642	# MALE SIGN
+0x2162	0x2640	# FEMALE SIGN
+0x2163	0x00B0	# DEGREE SIGN
+0x2164	0x2032	# PRIME
+0x2165	0x2033	# DOUBLE PRIME
+0x2166	0x2103	# DEGREE CELSIUS
+0x2167	0xFF04	# FULLWIDTH DOLLAR SIGN
+0x2168	0x00A4	# CURRENCY SIGN
+0x2169	0xFFE0	# FULLWIDTH CENT SIGN
+0x216A	0xFFE1	# FULLWIDTH POUND SIGN
+0x216B	0x2030	# PER MILLE SIGN
+0x216C	0x00A7	# SECTION SIGN
+0x216D	0x2116	# NUMERO SIGN
+0x216E	0x2606	# WHITE STAR
+0x216F	0x2605	# BLACK STAR
+0x2170	0x25CB	# WHITE CIRCLE
+0x2171	0x25CF	# BLACK CIRCLE
+0x2172	0x25CE	# BULLSEYE
+0x2173	0x25C7	# WHITE DIAMOND
+0x2174	0x25C6	# BLACK DIAMOND
+0x2175	0x25A1	# WHITE SQUARE
+0x2176	0x25A0	# BLACK SQUARE
+0x2177	0x25B3	# WHITE UP-POINTING TRIANGLE
+0x2178	0x25B2	# BLACK UP-POINTING TRIANGLE
+0x2179	0x203B	# REFERENCE MARK
+0x217A	0x2192	# RIGHTWARDS ARROW
+0x217B	0x2190	# LEFTWARDS ARROW
+0x217C	0x2191	# UPWARDS ARROW
+0x217D	0x2193	# DOWNWARDS ARROW
+0x217E	0x3013	# GETA MARK
+0x2231	0x2488	# DIGIT ONE FULL STOP
+0x2232	0x2489	# DIGIT TWO FULL STOP
+0x2233	0x248A	# DIGIT THREE FULL STOP
+0x2234	0x248B	# DIGIT FOUR FULL STOP
+0x2235	0x248C	# DIGIT FIVE FULL STOP
+0x2236	0x248D	# DIGIT SIX FULL STOP
+0x2237	0x248E	# DIGIT SEVEN FULL STOP
+0x2238	0x248F	# DIGIT EIGHT FULL STOP
+0x2239	0x2490	# DIGIT NINE FULL STOP
+0x223A	0x2491	# NUMBER TEN FULL STOP
+0x223B	0x2492	# NUMBER ELEVEN FULL STOP
+0x223C	0x2493	# NUMBER TWELVE FULL STOP
+0x223D	0x2494	# NUMBER THIRTEEN FULL STOP
+0x223E	0x2495	# NUMBER FOURTEEN FULL STOP
+0x223F	0x2496	# NUMBER FIFTEEN FULL STOP
+0x2240	0x2497	# NUMBER SIXTEEN FULL STOP
+0x2241	0x2498	# NUMBER SEVENTEEN FULL STOP
+0x2242	0x2499	# NUMBER EIGHTEEN FULL STOP
+0x2243	0x249A	# NUMBER NINETEEN FULL STOP
+0x2244	0x249B	# NUMBER TWENTY FULL STOP
+0x2245	0x2474	# PARENTHESIZED DIGIT ONE
+0x2246	0x2475	# PARENTHESIZED DIGIT TWO
+0x2247	0x2476	# PARENTHESIZED DIGIT THREE
+0x2248	0x2477	# PARENTHESIZED DIGIT FOUR
+0x2249	0x2478	# PARENTHESIZED DIGIT FIVE
+0x224A	0x2479	# PARENTHESIZED DIGIT SIX
+0x224B	0x247A	# PARENTHESIZED DIGIT SEVEN
+0x224C	0x247B	# PARENTHESIZED DIGIT EIGHT
+0x224D	0x247C	# PARENTHESIZED DIGIT NINE
+0x224E	0x247D	# PARENTHESIZED NUMBER TEN
+0x224F	0x247E	# PARENTHESIZED NUMBER ELEVEN
+0x2250	0x247F	# PARENTHESIZED NUMBER TWELVE
+0x2251	0x2480	# PARENTHESIZED NUMBER THIRTEEN
+0x2252	0x2481	# PARENTHESIZED NUMBER FOURTEEN
+0x2253	0x2482	# PARENTHESIZED NUMBER FIFTEEN
+0x2254	0x2483	# PARENTHESIZED NUMBER SIXTEEN
+0x2255	0x2484	# PARENTHESIZED NUMBER SEVENTEEN
+0x2256	0x2485	# PARENTHESIZED NUMBER EIGHTEEN
+0x2257	0x2486	# PARENTHESIZED NUMBER NINETEEN
+0x2258	0x2487	# PARENTHESIZED NUMBER TWENTY
+0x2259	0x2460	# CIRCLED DIGIT ONE
+0x225A	0x2461	# CIRCLED DIGIT TWO
+0x225B	0x2462	# CIRCLED DIGIT THREE
+0x225C	0x2463	# CIRCLED DIGIT FOUR
+0x225D	0x2464	# CIRCLED DIGIT FIVE
+0x225E	0x2465	# CIRCLED DIGIT SIX
+0x225F	0x2466	# CIRCLED DIGIT SEVEN
+0x2260	0x2467	# CIRCLED DIGIT EIGHT
+0x2261	0x2468	# CIRCLED DIGIT NINE
+0x2262	0x2469	# CIRCLED NUMBER TEN
+0x2265	0x3220	# PARENTHESIZED IDEOGRAPH ONE
+0x2266	0x3221	# PARENTHESIZED IDEOGRAPH TWO
+0x2267	0x3222	# PARENTHESIZED IDEOGRAPH THREE
+0x2268	0x3223	# PARENTHESIZED IDEOGRAPH FOUR
+0x2269	0x3224	# PARENTHESIZED IDEOGRAPH FIVE
+0x226A	0x3225	# PARENTHESIZED IDEOGRAPH SIX
+0x226B	0x3226	# PARENTHESIZED IDEOGRAPH SEVEN
+0x226C	0x3227	# PARENTHESIZED IDEOGRAPH EIGHT
+0x226D	0x3228	# PARENTHESIZED IDEOGRAPH NINE
+0x226E	0x3229	# PARENTHESIZED IDEOGRAPH TEN
+0x2271	0x2160	# ROMAN NUMERAL ONE
+0x2272	0x2161	# ROMAN NUMERAL TWO
+0x2273	0x2162	# ROMAN NUMERAL THREE
+0x2274	0x2163	# ROMAN NUMERAL FOUR
+0x2275	0x2164	# ROMAN NUMERAL FIVE
+0x2276	0x2165	# ROMAN NUMERAL SIX
+0x2277	0x2166	# ROMAN NUMERAL SEVEN
+0x2278	0x2167	# ROMAN NUMERAL EIGHT
+0x2279	0x2168	# ROMAN NUMERAL NINE
+0x227A	0x2169	# ROMAN NUMERAL TEN
+0x227B	0x216A	# ROMAN NUMERAL ELEVEN
+0x227C	0x216B	# ROMAN NUMERAL TWELVE
+0x2321	0xFF01	# FULLWIDTH EXCLAMATION MARK
+0x2322	0xFF02	# FULLWIDTH QUOTATION MARK
+0x2323	0xFF03	# FULLWIDTH NUMBER SIGN
+0x2324	0xFFE5	# FULLWIDTH YEN SIGN
+0x2325	0xFF05	# FULLWIDTH PERCENT SIGN
+0x2326	0xFF06	# FULLWIDTH AMPERSAND
+0x2327	0xFF07	# FULLWIDTH APOSTROPHE
+0x2328	0xFF08	# FULLWIDTH LEFT PARENTHESIS
+0x2329	0xFF09	# FULLWIDTH RIGHT PARENTHESIS
+0x232A	0xFF0A	# FULLWIDTH ASTERISK
+0x232B	0xFF0B	# FULLWIDTH PLUS SIGN
+0x232C	0xFF0C	# FULLWIDTH COMMA
+0x232D	0xFF0D	# FULLWIDTH HYPHEN-MINUS
+0x232E	0xFF0E	# FULLWIDTH FULL STOP
+0x232F	0xFF0F	# FULLWIDTH SOLIDUS
+0x2330	0xFF10	# FULLWIDTH DIGIT ZERO
+0x2331	0xFF11	# FULLWIDTH DIGIT ONE
+0x2332	0xFF12	# FULLWIDTH DIGIT TWO
+0x2333	0xFF13	# FULLWIDTH DIGIT THREE
+0x2334	0xFF14	# FULLWIDTH DIGIT FOUR
+0x2335	0xFF15	# FULLWIDTH DIGIT FIVE
+0x2336	0xFF16	# FULLWIDTH DIGIT SIX
+0x2337	0xFF17	# FULLWIDTH DIGIT SEVEN
+0x2338	0xFF18	# FULLWIDTH DIGIT EIGHT
+0x2339	0xFF19	# FULLWIDTH DIGIT NINE
+0x233A	0xFF1A	# FULLWIDTH COLON
+0x233B	0xFF1B	# FULLWIDTH SEMICOLON
+0x233C	0xFF1C	# FULLWIDTH LESS-THAN SIGN
+0x233D	0xFF1D	# FULLWIDTH EQUALS SIGN
+0x233E	0xFF1E	# FULLWIDTH GREATER-THAN SIGN
+0x233F	0xFF1F	# FULLWIDTH QUESTION MARK
+0x2340	0xFF20	# FULLWIDTH COMMERCIAL AT
+0x2341	0xFF21	# FULLWIDTH LATIN CAPITAL LETTER A
+0x2342	0xFF22	# FULLWIDTH LATIN CAPITAL LETTER B
+0x2343	0xFF23	# FULLWIDTH LATIN CAPITAL LETTER C
+0x2344	0xFF24	# FULLWIDTH LATIN CAPITAL LETTER D
+0x2345	0xFF25	# FULLWIDTH LATIN CAPITAL LETTER E
+0x2346	0xFF26	# FULLWIDTH LATIN CAPITAL LETTER F
+0x2347	0xFF27	# FULLWIDTH LATIN CAPITAL LETTER G
+0x2348	0xFF28	# FULLWIDTH LATIN CAPITAL LETTER H
+0x2349	0xFF29	# FULLWIDTH LATIN CAPITAL LETTER I
+0x234A	0xFF2A	# FULLWIDTH LATIN CAPITAL LETTER J
+0x234B	0xFF2B	# FULLWIDTH LATIN CAPITAL LETTER K
+0x234C	0xFF2C	# FULLWIDTH LATIN CAPITAL LETTER L
+0x234D	0xFF2D	# FULLWIDTH LATIN CAPITAL LETTER M
+0x234E	0xFF2E	# FULLWIDTH LATIN CAPITAL LETTER N
+0x234F	0xFF2F	# FULLWIDTH LATIN CAPITAL LETTER O
+0x2350	0xFF30	# FULLWIDTH LATIN CAPITAL LETTER P
+0x2351	0xFF31	# FULLWIDTH LATIN CAPITAL LETTER Q
+0x2352	0xFF32	# FULLWIDTH LATIN CAPITAL LETTER R
+0x2353	0xFF33	# FULLWIDTH LATIN CAPITAL LETTER S
+0x2354	0xFF34	# FULLWIDTH LATIN CAPITAL LETTER T
+0x2355	0xFF35	# FULLWIDTH LATIN CAPITAL LETTER U
+0x2356	0xFF36	# FULLWIDTH LATIN CAPITAL LETTER V
+0x2357	0xFF37	# FULLWIDTH LATIN CAPITAL LETTER W
+0x2358	0xFF38	# FULLWIDTH LATIN CAPITAL LETTER X
+0x2359	0xFF39	# FULLWIDTH LATIN CAPITAL LETTER Y
+0x235A	0xFF3A	# FULLWIDTH LATIN CAPITAL LETTER Z
+0x235B	0xFF3B	# FULLWIDTH LEFT SQUARE BRACKET
+0x235C	0xFF3C	# FULLWIDTH REVERSE SOLIDUS
+0x235D	0xFF3D	# FULLWIDTH RIGHT SQUARE BRACKET
+0x235E	0xFF3E	# FULLWIDTH CIRCUMFLEX ACCENT
+0x235F	0xFF3F	# FULLWIDTH LOW LINE
+0x2360	0xFF40	# FULLWIDTH GRAVE ACCENT
+0x2361	0xFF41	# FULLWIDTH LATIN SMALL LETTER A
+0x2362	0xFF42	# FULLWIDTH LATIN SMALL LETTER B
+0x2363	0xFF43	# FULLWIDTH LATIN SMALL LETTER C
+0x2364	0xFF44	# FULLWIDTH LATIN SMALL LETTER D
+0x2365	0xFF45	# FULLWIDTH LATIN SMALL LETTER E
+0x2366	0xFF46	# FULLWIDTH LATIN SMALL LETTER F
+0x2367	0xFF47	# FULLWIDTH LATIN SMALL LETTER G
+0x2368	0xFF48	# FULLWIDTH LATIN SMALL LETTER H
+0x2369	0xFF49	# FULLWIDTH LATIN SMALL LETTER I
+0x236A	0xFF4A	# FULLWIDTH LATIN SMALL LETTER J
+0x236B	0xFF4B	# FULLWIDTH LATIN SMALL LETTER K
+0x236C	0xFF4C	# FULLWIDTH LATIN SMALL LETTER L
+0x236D	0xFF4D	# FULLWIDTH LATIN SMALL LETTER M
+0x236E	0xFF4E	# FULLWIDTH LATIN SMALL LETTER N
+0x236F	0xFF4F	# FULLWIDTH LATIN SMALL LETTER O
+0x2370	0xFF50	# FULLWIDTH LATIN SMALL LETTER P
+0x2371	0xFF51	# FULLWIDTH LATIN SMALL LETTER Q
+0x2372	0xFF52	# FULLWIDTH LATIN SMALL LETTER R
+0x2373	0xFF53	# FULLWIDTH LATIN SMALL LETTER S
+0x2374	0xFF54	# FULLWIDTH LATIN SMALL LETTER T
+0x2375	0xFF55	# FULLWIDTH LATIN SMALL LETTER U
+0x2376	0xFF56	# FULLWIDTH LATIN SMALL LETTER V
+0x2377	0xFF57	# FULLWIDTH LATIN SMALL LETTER W
+0x2378	0xFF58	# FULLWIDTH LATIN SMALL LETTER X
+0x2379	0xFF59	# FULLWIDTH LATIN SMALL LETTER Y
+0x237A	0xFF5A	# FULLWIDTH LATIN SMALL LETTER Z
+0x237B	0xFF5B	# FULLWIDTH LEFT CURLY BRACKET
+0x237C	0xFF5C	# FULLWIDTH VERTICAL LINE
+0x237D	0xFF5D	# FULLWIDTH RIGHT CURLY BRACKET
+0x237E	0xFFE3	# FULLWIDTH MACRON
+0x2421	0x3041	# HIRAGANA LETTER SMALL A
+0x2422	0x3042	# HIRAGANA LETTER A
+0x2423	0x3043	# HIRAGANA LETTER SMALL I
+0x2424	0x3044	# HIRAGANA LETTER I
+0x2425	0x3045	# HIRAGANA LETTER SMALL U
+0x2426	0x3046	# HIRAGANA LETTER U
+0x2427	0x3047	# HIRAGANA LETTER SMALL E
+0x2428	0x3048	# HIRAGANA LETTER E
+0x2429	0x3049	# HIRAGANA LETTER SMALL O
+0x242A	0x304A	# HIRAGANA LETTER O
+0x242B	0x304B	# HIRAGANA LETTER KA
+0x242C	0x304C	# HIRAGANA LETTER GA
+0x242D	0x304D	# HIRAGANA LETTER KI
+0x242E	0x304E	# HIRAGANA LETTER GI
+0x242F	0x304F	# HIRAGANA LETTER KU
+0x2430	0x3050	# HIRAGANA LETTER GU
+0x2431	0x3051	# HIRAGANA LETTER KE
+0x2432	0x3052	# HIRAGANA LETTER GE
+0x2433	0x3053	# HIRAGANA LETTER KO
+0x2434	0x3054	# HIRAGANA LETTER GO
+0x2435	0x3055	# HIRAGANA LETTER SA
+0x2436	0x3056	# HIRAGANA LETTER ZA
+0x2437	0x3057	# HIRAGANA LETTER SI
+0x2438	0x3058	# HIRAGANA LETTER ZI
+0x2439	0x3059	# HIRAGANA LETTER SU
+0x243A	0x305A	# HIRAGANA LETTER ZU
+0x243B	0x305B	# HIRAGANA LETTER SE
+0x243C	0x305C	# HIRAGANA LETTER ZE
+0x243D	0x305D	# HIRAGANA LETTER SO
+0x243E	0x305E	# HIRAGANA LETTER ZO
+0x243F	0x305F	# HIRAGANA LETTER TA
+0x2440	0x3060	# HIRAGANA LETTER DA
+0x2441	0x3061	# HIRAGANA LETTER TI
+0x2442	0x3062	# HIRAGANA LETTER DI
+0x2443	0x3063	# HIRAGANA LETTER SMALL TU
+0x2444	0x3064	# HIRAGANA LETTER TU
+0x2445	0x3065	# HIRAGANA LETTER DU
+0x2446	0x3066	# HIRAGANA LETTER TE
+0x2447	0x3067	# HIRAGANA LETTER DE
+0x2448	0x3068	# HIRAGANA LETTER TO
+0x2449	0x3069	# HIRAGANA LETTER DO
+0x244A	0x306A	# HIRAGANA LETTER NA
+0x244B	0x306B	# HIRAGANA LETTER NI
+0x244C	0x306C	# HIRAGANA LETTER NU
+0x244D	0x306D	# HIRAGANA LETTER NE
+0x244E	0x306E	# HIRAGANA LETTER NO
+0x244F	0x306F	# HIRAGANA LETTER HA
+0x2450	0x3070	# HIRAGANA LETTER BA
+0x2451	0x3071	# HIRAGANA LETTER PA
+0x2452	0x3072	# HIRAGANA LETTER HI
+0x2453	0x3073	# HIRAGANA LETTER BI
+0x2454	0x3074	# HIRAGANA LETTER PI
+0x2455	0x3075	# HIRAGANA LETTER HU
+0x2456	0x3076	# HIRAGANA LETTER BU
+0x2457	0x3077	# HIRAGANA LETTER PU
+0x2458	0x3078	# HIRAGANA LETTER HE
+0x2459	0x3079	# HIRAGANA LETTER BE
+0x245A	0x307A	# HIRAGANA LETTER PE
+0x245B	0x307B	# HIRAGANA LETTER HO
+0x245C	0x307C	# HIRAGANA LETTER BO
+0x245D	0x307D	# HIRAGANA LETTER PO
+0x245E	0x307E	# HIRAGANA LETTER MA
+0x245F	0x307F	# HIRAGANA LETTER MI
+0x2460	0x3080	# HIRAGANA LETTER MU
+0x2461	0x3081	# HIRAGANA LETTER ME
+0x2462	0x3082	# HIRAGANA LETTER MO
+0x2463	0x3083	# HIRAGANA LETTER SMALL YA
+0x2464	0x3084	# HIRAGANA LETTER YA
+0x2465	0x3085	# HIRAGANA LETTER SMALL YU
+0x2466	0x3086	# HIRAGANA LETTER YU
+0x2467	0x3087	# HIRAGANA LETTER SMALL YO
+0x2468	0x3088	# HIRAGANA LETTER YO
+0x2469	0x3089	# HIRAGANA LETTER RA
+0x246A	0x308A	# HIRAGANA LETTER RI
+0x246B	0x308B	# HIRAGANA LETTER RU
+0x246C	0x308C	# HIRAGANA LETTER RE
+0x246D	0x308D	# HIRAGANA LETTER RO
+0x246E	0x308E	# HIRAGANA LETTER SMALL WA
+0x246F	0x308F	# HIRAGANA LETTER WA
+0x2470	0x3090	# HIRAGANA LETTER WI
+0x2471	0x3091	# HIRAGANA LETTER WE
+0x2472	0x3092	# HIRAGANA LETTER WO
+0x2473	0x3093	# HIRAGANA LETTER N
+0x2521	0x30A1	# KATAKANA LETTER SMALL A
+0x2522	0x30A2	# KATAKANA LETTER A
+0x2523	0x30A3	# KATAKANA LETTER SMALL I
+0x2524	0x30A4	# KATAKANA LETTER I
+0x2525	0x30A5	# KATAKANA LETTER SMALL U
+0x2526	0x30A6	# KATAKANA LETTER U
+0x2527	0x30A7	# KATAKANA LETTER SMALL E
+0x2528	0x30A8	# KATAKANA LETTER E
+0x2529	0x30A9	# KATAKANA LETTER SMALL O
+0x252A	0x30AA	# KATAKANA LETTER O
+0x252B	0x30AB	# KATAKANA LETTER KA
+0x252C	0x30AC	# KATAKANA LETTER GA
+0x252D	0x30AD	# KATAKANA LETTER KI
+0x252E	0x30AE	# KATAKANA LETTER GI
+0x252F	0x30AF	# KATAKANA LETTER KU
+0x2530	0x30B0	# KATAKANA LETTER GU
+0x2531	0x30B1	# KATAKANA LETTER KE
+0x2532	0x30B2	# KATAKANA LETTER GE
+0x2533	0x30B3	# KATAKANA LETTER KO
+0x2534	0x30B4	# KATAKANA LETTER GO
+0x2535	0x30B5	# KATAKANA LETTER SA
+0x2536	0x30B6	# KATAKANA LETTER ZA
+0x2537	0x30B7	# KATAKANA LETTER SI
+0x2538	0x30B8	# KATAKANA LETTER ZI
+0x2539	0x30B9	# KATAKANA LETTER SU
+0x253A	0x30BA	# KATAKANA LETTER ZU
+0x253B	0x30BB	# KATAKANA LETTER SE
+0x253C	0x30BC	# KATAKANA LETTER ZE
+0x253D	0x30BD	# KATAKANA LETTER SO
+0x253E	0x30BE	# KATAKANA LETTER ZO
+0x253F	0x30BF	# KATAKANA LETTER TA
+0x2540	0x30C0	# KATAKANA LETTER DA
+0x2541	0x30C1	# KATAKANA LETTER TI
+0x2542	0x30C2	# KATAKANA LETTER DI
+0x2543	0x30C3	# KATAKANA LETTER SMALL TU
+0x2544	0x30C4	# KATAKANA LETTER TU
+0x2545	0x30C5	# KATAKANA LETTER DU
+0x2546	0x30C6	# KATAKANA LETTER TE
+0x2547	0x30C7	# KATAKANA LETTER DE
+0x2548	0x30C8	# KATAKANA LETTER TO
+0x2549	0x30C9	# KATAKANA LETTER DO
+0x254A	0x30CA	# KATAKANA LETTER NA
+0x254B	0x30CB	# KATAKANA LETTER NI
+0x254C	0x30CC	# KATAKANA LETTER NU
+0x254D	0x30CD	# KATAKANA LETTER NE
+0x254E	0x30CE	# KATAKANA LETTER NO
+0x254F	0x30CF	# KATAKANA LETTER HA
+0x2550	0x30D0	# KATAKANA LETTER BA
+0x2551	0x30D1	# KATAKANA LETTER PA
+0x2552	0x30D2	# KATAKANA LETTER HI
+0x2553	0x30D3	# KATAKANA LETTER BI
+0x2554	0x30D4	# KATAKANA LETTER PI
+0x2555	0x30D5	# KATAKANA LETTER HU
+0x2556	0x30D6	# KATAKANA LETTER BU
+0x2557	0x30D7	# KATAKANA LETTER PU
+0x2558	0x30D8	# KATAKANA LETTER HE
+0x2559	0x30D9	# KATAKANA LETTER BE
+0x255A	0x30DA	# KATAKANA LETTER PE
+0x255B	0x30DB	# KATAKANA LETTER HO
+0x255C	0x30DC	# KATAKANA LETTER BO
+0x255D	0x30DD	# KATAKANA LETTER PO
+0x255E	0x30DE	# KATAKANA LETTER MA
+0x255F	0x30DF	# KATAKANA LETTER MI
+0x2560	0x30E0	# KATAKANA LETTER MU
+0x2561	0x30E1	# KATAKANA LETTER ME
+0x2562	0x30E2	# KATAKANA LETTER MO
+0x2563	0x30E3	# KATAKANA LETTER SMALL YA
+0x2564	0x30E4	# KATAKANA LETTER YA
+0x2565	0x30E5	# KATAKANA LETTER SMALL YU
+0x2566	0x30E6	# KATAKANA LETTER YU
+0x2567	0x30E7	# KATAKANA LETTER SMALL YO
+0x2568	0x30E8	# KATAKANA LETTER YO
+0x2569	0x30E9	# KATAKANA LETTER RA
+0x256A	0x30EA	# KATAKANA LETTER RI
+0x256B	0x30EB	# KATAKANA LETTER RU
+0x256C	0x30EC	# KATAKANA LETTER RE
+0x256D	0x30ED	# KATAKANA LETTER RO
+0x256E	0x30EE	# KATAKANA LETTER SMALL WA
+0x256F	0x30EF	# KATAKANA LETTER WA
+0x2570	0x30F0	# KATAKANA LETTER WI
+0x2571	0x30F1	# KATAKANA LETTER WE
+0x2572	0x30F2	# KATAKANA LETTER WO
+0x2573	0x30F3	# KATAKANA LETTER N
+0x2574	0x30F4	# KATAKANA LETTER VU
+0x2575	0x30F5	# KATAKANA LETTER SMALL KA
+0x2576	0x30F6	# KATAKANA LETTER SMALL KE
+0x2621	0x0391	# GREEK CAPITAL LETTER ALPHA
+0x2622	0x0392	# GREEK CAPITAL LETTER BETA
+0x2623	0x0393	# GREEK CAPITAL LETTER GAMMA
+0x2624	0x0394	# GREEK CAPITAL LETTER DELTA
+0x2625	0x0395	# GREEK CAPITAL LETTER EPSILON
+0x2626	0x0396	# GREEK CAPITAL LETTER ZETA
+0x2627	0x0397	# GREEK CAPITAL LETTER ETA
+0x2628	0x0398	# GREEK CAPITAL LETTER THETA
+0x2629	0x0399	# GREEK CAPITAL LETTER IOTA
+0x262A	0x039A	# GREEK CAPITAL LETTER KAPPA
+0x262B	0x039B	# GREEK CAPITAL LETTER LAMDA
+0x262C	0x039C	# GREEK CAPITAL LETTER MU
+0x262D	0x039D	# GREEK CAPITAL LETTER NU
+0x262E	0x039E	# GREEK CAPITAL LETTER XI
+0x262F	0x039F	# GREEK CAPITAL LETTER OMICRON
+0x2630	0x03A0	# GREEK CAPITAL LETTER PI
+0x2631	0x03A1	# GREEK CAPITAL LETTER RHO
+0x2632	0x03A3	# GREEK CAPITAL LETTER SIGMA
+0x2633	0x03A4	# GREEK CAPITAL LETTER TAU
+0x2634	0x03A5	# GREEK CAPITAL LETTER UPSILON
+0x2635	0x03A6	# GREEK CAPITAL LETTER PHI
+0x2636	0x03A7	# GREEK CAPITAL LETTER CHI
+0x2637	0x03A8	# GREEK CAPITAL LETTER PSI
+0x2638	0x03A9	# GREEK CAPITAL LETTER OMEGA
+0x2641	0x03B1	# GREEK SMALL LETTER ALPHA
+0x2642	0x03B2	# GREEK SMALL LETTER BETA
+0x2643	0x03B3	# GREEK SMALL LETTER GAMMA
+0x2644	0x03B4	# GREEK SMALL LETTER DELTA
+0x2645	0x03B5	# GREEK SMALL LETTER EPSILON
+0x2646	0x03B6	# GREEK SMALL LETTER ZETA
+0x2647	0x03B7	# GREEK SMALL LETTER ETA
+0x2648	0x03B8	# GREEK SMALL LETTER THETA
+0x2649	0x03B9	# GREEK SMALL LETTER IOTA
+0x264A	0x03BA	# GREEK SMALL LETTER KAPPA
+0x264B	0x03BB	# GREEK SMALL LETTER LAMDA
+0x264C	0x03BC	# GREEK SMALL LETTER MU
+0x264D	0x03BD	# GREEK SMALL LETTER NU
+0x264E	0x03BE	# GREEK SMALL LETTER XI
+0x264F	0x03BF	# GREEK SMALL LETTER OMICRON
+0x2650	0x03C0	# GREEK SMALL LETTER PI
+0x2651	0x03C1	# GREEK SMALL LETTER RHO
+0x2652	0x03C3	# GREEK SMALL LETTER SIGMA
+0x2653	0x03C4	# GREEK SMALL LETTER TAU
+0x2654	0x03C5	# GREEK SMALL LETTER UPSILON
+0x2655	0x03C6	# GREEK SMALL LETTER PHI
+0x2656	0x03C7	# GREEK SMALL LETTER CHI
+0x2657	0x03C8	# GREEK SMALL LETTER PSI
+0x2658	0x03C9	# GREEK SMALL LETTER OMEGA
+0x2721	0x0410	# CYRILLIC CAPITAL LETTER A
+0x2722	0x0411	# CYRILLIC CAPITAL LETTER BE
+0x2723	0x0412	# CYRILLIC CAPITAL LETTER VE
+0x2724	0x0413	# CYRILLIC CAPITAL LETTER GHE
+0x2725	0x0414	# CYRILLIC CAPITAL LETTER DE
+0x2726	0x0415	# CYRILLIC CAPITAL LETTER IE
+0x2727	0x0401	# CYRILLIC CAPITAL LETTER IO
+0x2728	0x0416	# CYRILLIC CAPITAL LETTER ZHE
+0x2729	0x0417	# CYRILLIC CAPITAL LETTER ZE
+0x272A	0x0418	# CYRILLIC CAPITAL LETTER I
+0x272B	0x0419	# CYRILLIC CAPITAL LETTER SHORT I
+0x272C	0x041A	# CYRILLIC CAPITAL LETTER KA
+0x272D	0x041B	# CYRILLIC CAPITAL LETTER EL
+0x272E	0x041C	# CYRILLIC CAPITAL LETTER EM
+0x272F	0x041D	# CYRILLIC CAPITAL LETTER EN
+0x2730	0x041E	# CYRILLIC CAPITAL LETTER O
+0x2731	0x041F	# CYRILLIC CAPITAL LETTER PE
+0x2732	0x0420	# CYRILLIC CAPITAL LETTER ER
+0x2733	0x0421	# CYRILLIC CAPITAL LETTER ES
+0x2734	0x0422	# CYRILLIC CAPITAL LETTER TE
+0x2735	0x0423	# CYRILLIC CAPITAL LETTER U
+0x2736	0x0424	# CYRILLIC CAPITAL LETTER EF
+0x2737	0x0425	# CYRILLIC CAPITAL LETTER HA
+0x2738	0x0426	# CYRILLIC CAPITAL LETTER TSE
+0x2739	0x0427	# CYRILLIC CAPITAL LETTER CHE
+0x273A	0x0428	# CYRILLIC CAPITAL LETTER SHA
+0x273B	0x0429	# CYRILLIC CAPITAL LETTER SHCHA
+0x273C	0x042A	# CYRILLIC CAPITAL LETTER HARD SIGN
+0x273D	0x042B	# CYRILLIC CAPITAL LETTER YERU
+0x273E	0x042C	# CYRILLIC CAPITAL LETTER SOFT SIGN
+0x273F	0x042D	# CYRILLIC CAPITAL LETTER E
+0x2740	0x042E	# CYRILLIC CAPITAL LETTER YU
+0x2741	0x042F	# CYRILLIC CAPITAL LETTER YA
+0x2751	0x0430	# CYRILLIC SMALL LETTER A
+0x2752	0x0431	# CYRILLIC SMALL LETTER BE
+0x2753	0x0432	# CYRILLIC SMALL LETTER VE
+0x2754	0x0433	# CYRILLIC SMALL LETTER GHE
+0x2755	0x0434	# CYRILLIC SMALL LETTER DE
+0x2756	0x0435	# CYRILLIC SMALL LETTER IE
+0x2757	0x0451	# CYRILLIC SMALL LETTER IO
+0x2758	0x0436	# CYRILLIC SMALL LETTER ZHE
+0x2759	0x0437	# CYRILLIC SMALL LETTER ZE
+0x275A	0x0438	# CYRILLIC SMALL LETTER I
+0x275B	0x0439	# CYRILLIC SMALL LETTER SHORT I
+0x275C	0x043A	# CYRILLIC SMALL LETTER KA
+0x275D	0x043B	# CYRILLIC SMALL LETTER EL
+0x275E	0x043C	# CYRILLIC SMALL LETTER EM
+0x275F	0x043D	# CYRILLIC SMALL LETTER EN
+0x2760	0x043E	# CYRILLIC SMALL LETTER O
+0x2761	0x043F	# CYRILLIC SMALL LETTER PE
+0x2762	0x0440	# CYRILLIC SMALL LETTER ER
+0x2763	0x0441	# CYRILLIC SMALL LETTER ES
+0x2764	0x0442	# CYRILLIC SMALL LETTER TE
+0x2765	0x0443	# CYRILLIC SMALL LETTER U
+0x2766	0x0444	# CYRILLIC SMALL LETTER EF
+0x2767	0x0445	# CYRILLIC SMALL LETTER HA
+0x2768	0x0446	# CYRILLIC SMALL LETTER TSE
+0x2769	0x0447	# CYRILLIC SMALL LETTER CHE
+0x276A	0x0448	# CYRILLIC SMALL LETTER SHA
+0x276B	0x0449	# CYRILLIC SMALL LETTER SHCHA
+0x276C	0x044A	# CYRILLIC SMALL LETTER HARD SIGN
+0x276D	0x044B	# CYRILLIC SMALL LETTER YERU
+0x276E	0x044C	# CYRILLIC SMALL LETTER SOFT SIGN
+0x276F	0x044D	# CYRILLIC SMALL LETTER E
+0x2770	0x044E	# CYRILLIC SMALL LETTER YU
+0x2771	0x044F	# CYRILLIC SMALL LETTER YA
+0x2821	0x0101	# LATIN SMALL LETTER A WITH MACRON
+0x2822	0x00E1	# LATIN SMALL LETTER A WITH ACUTE
+0x2823	0x01CE	# LATIN SMALL LETTER A WITH CARON
+0x2824	0x00E0	# LATIN SMALL LETTER A WITH GRAVE
+0x2825	0x0113	# LATIN SMALL LETTER E WITH MACRON
+0x2826	0x00E9	# LATIN SMALL LETTER E WITH ACUTE
+0x2827	0x011B	# LATIN SMALL LETTER E WITH CARON
+0x2828	0x00E8	# LATIN SMALL LETTER E WITH GRAVE
+0x2829	0x012B	# LATIN SMALL LETTER I WITH MACRON
+0x282A	0x00ED	# LATIN SMALL LETTER I WITH ACUTE
+0x282B	0x01D0	# LATIN SMALL LETTER I WITH CARON
+0x282C	0x00EC	# LATIN SMALL LETTER I WITH GRAVE
+0x282D	0x014D	# LATIN SMALL LETTER O WITH MACRON
+0x282E	0x00F3	# LATIN SMALL LETTER O WITH ACUTE
+0x282F	0x01D2	# LATIN SMALL LETTER O WITH CARON
+0x2830	0x00F2	# LATIN SMALL LETTER O WITH GRAVE
+0x2831	0x016B	# LATIN SMALL LETTER U WITH MACRON
+0x2832	0x00FA	# LATIN SMALL LETTER U WITH ACUTE
+0x2833	0x01D4	# LATIN SMALL LETTER U WITH CARON
+0x2834	0x00F9	# LATIN SMALL LETTER U WITH GRAVE
+0x2835	0x01D6	# LATIN SMALL LETTER U WITH DIAERESIS AND MACRON
+0x2836	0x01D8	# LATIN SMALL LETTER U WITH DIAERESIS AND ACUTE
+0x2837	0x01DA	# LATIN SMALL LETTER U WITH DIAERESIS AND CARON
+0x2838	0x01DC	# LATIN SMALL LETTER U WITH DIAERESIS AND GRAVE
+0x2839	0x00FC	# LATIN SMALL LETTER U WITH DIAERESIS
+0x283A	0x00EA	# LATIN SMALL LETTER E WITH CIRCUMFLEX
+0x2845	0x3105	# BOPOMOFO LETTER B
+0x2846	0x3106	# BOPOMOFO LETTER P
+0x2847	0x3107	# BOPOMOFO LETTER M
+0x2848	0x3108	# BOPOMOFO LETTER F
+0x2849	0x3109	# BOPOMOFO LETTER D
+0x284A	0x310A	# BOPOMOFO LETTER T
+0x284B	0x310B	# BOPOMOFO LETTER N
+0x284C	0x310C	# BOPOMOFO LETTER L
+0x284D	0x310D	# BOPOMOFO LETTER G
+0x284E	0x310E	# BOPOMOFO LETTER K
+0x284F	0x310F	# BOPOMOFO LETTER H
+0x2850	0x3110	# BOPOMOFO LETTER J
+0x2851	0x3111	# BOPOMOFO LETTER Q
+0x2852	0x3112	# BOPOMOFO LETTER X
+0x2853	0x3113	# BOPOMOFO LETTER ZH
+0x2854	0x3114	# BOPOMOFO LETTER CH
+0x2855	0x3115	# BOPOMOFO LETTER SH
+0x2856	0x3116	# BOPOMOFO LETTER R
+0x2857	0x3117	# BOPOMOFO LETTER Z
+0x2858	0x3118	# BOPOMOFO LETTER C
+0x2859	0x3119	# BOPOMOFO LETTER S
+0x285A	0x311A	# BOPOMOFO LETTER A
+0x285B	0x311B	# BOPOMOFO LETTER O
+0x285C	0x311C	# BOPOMOFO LETTER E
+0x285D	0x311D	# BOPOMOFO LETTER EH
+0x285E	0x311E	# BOPOMOFO LETTER AI
+0x285F	0x311F	# BOPOMOFO LETTER EI
+0x2860	0x3120	# BOPOMOFO LETTER AU
+0x2861	0x3121	# BOPOMOFO LETTER OU
+0x2862	0x3122	# BOPOMOFO LETTER AN
+0x2863	0x3123	# BOPOMOFO LETTER EN
+0x2864	0x3124	# BOPOMOFO LETTER ANG
+0x2865	0x3125	# BOPOMOFO LETTER ENG
+0x2866	0x3126	# BOPOMOFO LETTER ER
+0x2867	0x3127	# BOPOMOFO LETTER I
+0x2868	0x3128	# BOPOMOFO LETTER U
+0x2869	0x3129	# BOPOMOFO LETTER IU
+0x2924	0x2500	# BOX DRAWINGS LIGHT HORIZONTAL
+0x2925	0x2501	# BOX DRAWINGS HEAVY HORIZONTAL
+0x2926	0x2502	# BOX DRAWINGS LIGHT VERTICAL
+0x2927	0x2503	# BOX DRAWINGS HEAVY VERTICAL
+0x2928	0x2504	# BOX DRAWINGS LIGHT TRIPLE DASH HORIZONTAL
+0x2929	0x2505	# BOX DRAWINGS HEAVY TRIPLE DASH HORIZONTAL
+0x292A	0x2506	# BOX DRAWINGS LIGHT TRIPLE DASH VERTICAL
+0x292B	0x2507	# BOX DRAWINGS HEAVY TRIPLE DASH VERTICAL
+0x292C	0x2508	# BOX DRAWINGS LIGHT QUADRUPLE DASH HORIZONTAL
+0x292D	0x2509	# BOX DRAWINGS HEAVY QUADRUPLE DASH HORIZONTAL
+0x292E	0x250A	# BOX DRAWINGS LIGHT QUADRUPLE DASH VERTICAL
+0x292F	0x250B	# BOX DRAWINGS HEAVY QUADRUPLE DASH VERTICAL
+0x2930	0x250C	# BOX DRAWINGS LIGHT DOWN AND RIGHT
+0x2931	0x250D	# BOX DRAWINGS DOWN LIGHT AND RIGHT HEAVY
+0x2932	0x250E	# BOX DRAWINGS DOWN HEAVY AND RIGHT LIGHT
+0x2933	0x250F	# BOX DRAWINGS HEAVY DOWN AND RIGHT
+0x2934	0x2510	# BOX DRAWINGS LIGHT DOWN AND LEFT
+0x2935	0x2511	# BOX DRAWINGS DOWN LIGHT AND LEFT HEAVY
+0x2936	0x2512	# BOX DRAWINGS DOWN HEAVY AND LEFT LIGHT
+0x2937	0x2513	# BOX DRAWINGS HEAVY DOWN AND LEFT
+0x2938	0x2514	# BOX DRAWINGS LIGHT UP AND RIGHT
+0x2939	0x2515	# BOX DRAWINGS UP LIGHT AND RIGHT HEAVY
+0x293A	0x2516	# BOX DRAWINGS UP HEAVY AND RIGHT LIGHT
+0x293B	0x2517	# BOX DRAWINGS HEAVY UP AND RIGHT
+0x293C	0x2518	# BOX DRAWINGS LIGHT UP AND LEFT
+0x293D	0x2519	# BOX DRAWINGS UP LIGHT AND LEFT HEAVY
+0x293E	0x251A	# BOX DRAWINGS UP HEAVY AND LEFT LIGHT
+0x293F	0x251B	# BOX DRAWINGS HEAVY UP AND LEFT
+0x2940	0x251C	# BOX DRAWINGS LIGHT VERTICAL AND RIGHT
+0x2941	0x251D	# BOX DRAWINGS VERTICAL LIGHT AND RIGHT HEAVY
+0x2942	0x251E	# BOX DRAWINGS UP HEAVY AND RIGHT DOWN LIGHT
+0x2943	0x251F	# BOX DRAWINGS DOWN HEAVY AND RIGHT UP LIGHT
+0x2944	0x2520	# BOX DRAWINGS VERTICAL HEAVY AND RIGHT LIGHT
+0x2945	0x2521	# BOX DRAWINGS DOWN LIGHT AND RIGHT UP HEAVY
+0x2946	0x2522	# BOX DRAWINGS UP LIGHT AND RIGHT DOWN HEAVY
+0x2947	0x2523	# BOX DRAWINGS HEAVY VERTICAL AND RIGHT
+0x2948	0x2524	# BOX DRAWINGS LIGHT VERTICAL AND LEFT
+0x2949	0x2525	# BOX DRAWINGS VERTICAL LIGHT AND LEFT HEAVY
+0x294A	0x2526	# BOX DRAWINGS UP HEAVY AND LEFT DOWN LIGHT
+0x294B	0x2527	# BOX DRAWINGS DOWN HEAVY AND LEFT UP LIGHT
+0x294C	0x2528	# BOX DRAWINGS VERTICAL HEAVY AND LEFT LIGHT
+0x294D	0x2529	# BOX DRAWINGS DOWN LIGHT AND LEFT UP HEAVY
+0x294E	0x252A	# BOX DRAWINGS UP LIGHT AND LEFT DOWN HEAVY
+0x294F	0x252B	# BOX DRAWINGS HEAVY VERTICAL AND LEFT
+0x2950	0x252C	# BOX DRAWINGS LIGHT DOWN AND HORIZONTAL
+0x2951	0x252D	# BOX DRAWINGS LEFT HEAVY AND RIGHT DOWN LIGHT
+0x2952	0x252E	# BOX DRAWINGS RIGHT HEAVY AND LEFT DOWN LIGHT
+0x2953	0x252F	# BOX DRAWINGS DOWN LIGHT AND HORIZONTAL HEAVY
+0x2954	0x2530	# BOX DRAWINGS DOWN HEAVY AND HORIZONTAL LIGHT
+0x2955	0x2531	# BOX DRAWINGS RIGHT LIGHT AND LEFT DOWN HEAVY
+0x2956	0x2532	# BOX DRAWINGS LEFT LIGHT AND RIGHT DOWN HEAVY
+0x2957	0x2533	# BOX DRAWINGS HEAVY DOWN AND HORIZONTAL
+0x2958	0x2534	# BOX DRAWINGS LIGHT UP AND HORIZONTAL
+0x2959	0x2535	# BOX DRAWINGS LEFT HEAVY AND RIGHT UP LIGHT
+0x295A	0x2536	# BOX DRAWINGS RIGHT HEAVY AND LEFT UP LIGHT
+0x295B	0x2537	# BOX DRAWINGS UP LIGHT AND HORIZONTAL HEAVY
+0x295C	0x2538	# BOX DRAWINGS UP HEAVY AND HORIZONTAL LIGHT
+0x295D	0x2539	# BOX DRAWINGS RIGHT LIGHT AND LEFT UP HEAVY
+0x295E	0x253A	# BOX DRAWINGS LEFT LIGHT AND RIGHT UP HEAVY
+0x295F	0x253B	# BOX DRAWINGS HEAVY UP AND HORIZONTAL
+0x2960	0x253C	# BOX DRAWINGS LIGHT VERTICAL AND HORIZONTAL
+0x2961	0x253D	# BOX DRAWINGS LEFT HEAVY AND RIGHT VERTICAL LIGHT
+0x2962	0x253E	# BOX DRAWINGS RIGHT HEAVY AND LEFT VERTICAL LIGHT
+0x2963	0x253F	# BOX DRAWINGS VERTICAL LIGHT AND HORIZONTAL HEAVY
+0x2964	0x2540	# BOX DRAWINGS UP HEAVY AND DOWN HORIZONTAL LIGHT
+0x2965	0x2541	# BOX DRAWINGS DOWN HEAVY AND UP HORIZONTAL LIGHT
+0x2966	0x2542	# BOX DRAWINGS VERTICAL HEAVY AND HORIZONTAL LIGHT
+0x2967	0x2543	# BOX DRAWINGS LEFT UP HEAVY AND RIGHT DOWN LIGHT
+0x2968	0x2544	# BOX DRAWINGS RIGHT UP HEAVY AND LEFT DOWN LIGHT
+0x2969	0x2545	# BOX DRAWINGS LEFT DOWN HEAVY AND RIGHT UP LIGHT
+0x296A	0x2546	# BOX DRAWINGS RIGHT DOWN HEAVY AND LEFT UP LIGHT
+0x296B	0x2547	# BOX DRAWINGS DOWN LIGHT AND UP HORIZONTAL HEAVY
+0x296C	0x2548	# BOX DRAWINGS UP LIGHT AND DOWN HORIZONTAL HEAVY
+0x296D	0x2549	# BOX DRAWINGS RIGHT LIGHT AND LEFT VERTICAL HEAVY
+0x296E	0x254A	# BOX DRAWINGS LEFT LIGHT AND RIGHT VERTICAL HEAVY
+0x296F	0x254B	# BOX DRAWINGS HEAVY VERTICAL AND HORIZONTAL
+0x3021	0x554A	# <CJK>
+0x3022	0x963F	# <CJK>
+0x3023	0x57C3	# <CJK>
+0x3024	0x6328	# <CJK>
+0x3025	0x54CE	# <CJK>
+0x3026	0x5509	# <CJK>
+0x3027	0x54C0	# <CJK>
+0x3028	0x7691	# <CJK>
+0x3029	0x764C	# <CJK>
+0x302A	0x853C	# <CJK>
+0x302B	0x77EE	# <CJK>
+0x302C	0x827E	# <CJK>
+0x302D	0x788D	# <CJK>
+0x302E	0x7231	# <CJK>
+0x302F	0x9698	# <CJK>
+0x3030	0x978D	# <CJK>
+0x3031	0x6C28	# <CJK>
+0x3032	0x5B89	# <CJK>
+0x3033	0x4FFA	# <CJK>
+0x3034	0x6309	# <CJK>
+0x3035	0x6697	# <CJK>
+0x3036	0x5CB8	# <CJK>
+0x3037	0x80FA	# <CJK>
+0x3038	0x6848	# <CJK>
+0x3039	0x80AE	# <CJK>
+0x303A	0x6602	# <CJK>
+0x303B	0x76CE	# <CJK>
+0x303C	0x51F9	# <CJK>
+0x303D	0x6556	# <CJK>
+0x303E	0x71AC	# <CJK>
+0x303F	0x7FF1	# <CJK>
+0x3040	0x8884	# <CJK>
+0x3041	0x50B2	# <CJK>
+0x3042	0x5965	# <CJK>
+0x3043	0x61CA	# <CJK>
+0x3044	0x6FB3	# <CJK>
+0x3045	0x82AD	# <CJK>
+0x3046	0x634C	# <CJK>
+0x3047	0x6252	# <CJK>
+0x3048	0x53ED	# <CJK>
+0x3049	0x5427	# <CJK>
+0x304A	0x7B06	# <CJK>
+0x304B	0x516B	# <CJK>
+0x304C	0x75A4	# <CJK>
+0x304D	0x5DF4	# <CJK>
+0x304E	0x62D4	# <CJK>
+0x304F	0x8DCB	# <CJK>
+0x3050	0x9776	# <CJK>
+0x3051	0x628A	# <CJK>
+0x3052	0x8019	# <CJK>
+0x3053	0x575D	# <CJK>
+0x3054	0x9738	# <CJK>
+0x3055	0x7F62	# <CJK>
+0x3056	0x7238	# <CJK>
+0x3057	0x767D	# <CJK>
+0x3058	0x67CF	# <CJK>
+0x3059	0x767E	# <CJK>
+0x305A	0x6446	# <CJK>
+0x305B	0x4F70	# <CJK>
+0x305C	0x8D25	# <CJK>
+0x305D	0x62DC	# <CJK>
+0x305E	0x7A17	# <CJK>
+0x305F	0x6591	# <CJK>
+0x3060	0x73ED	# <CJK>
+0x3061	0x642C	# <CJK>
+0x3062	0x6273	# <CJK>
+0x3063	0x822C	# <CJK>
+0x3064	0x9881	# <CJK>
+0x3065	0x677F	# <CJK>
+0x3066	0x7248	# <CJK>
+0x3067	0x626E	# <CJK>
+0x3068	0x62CC	# <CJK>
+0x3069	0x4F34	# <CJK>
+0x306A	0x74E3	# <CJK>
+0x306B	0x534A	# <CJK>
+0x306C	0x529E	# <CJK>
+0x306D	0x7ECA	# <CJK>
+0x306E	0x90A6	# <CJK>
+0x306F	0x5E2E	# <CJK>
+0x3070	0x6886	# <CJK>
+0x3071	0x699C	# <CJK>
+0x3072	0x8180	# <CJK>
+0x3073	0x7ED1	# <CJK>
+0x3074	0x68D2	# <CJK>
+0x3075	0x78C5	# <CJK>
+0x3076	0x868C	# <CJK>
+0x3077	0x9551	# <CJK>
+0x3078	0x508D	# <CJK>
+0x3079	0x8C24	# <CJK>
+0x307A	0x82DE	# <CJK>
+0x307B	0x80DE	# <CJK>
+0x307C	0x5305	# <CJK>
+0x307D	0x8912	# <CJK>
+0x307E	0x5265	# <CJK>
+0x3121	0x8584	# <CJK>
+0x3122	0x96F9	# <CJK>
+0x3123	0x4FDD	# <CJK>
+0x3124	0x5821	# <CJK>
+0x3125	0x9971	# <CJK>
+0x3126	0x5B9D	# <CJK>
+0x3127	0x62B1	# <CJK>
+0x3128	0x62A5	# <CJK>
+0x3129	0x66B4	# <CJK>
+0x312A	0x8C79	# <CJK>
+0x312B	0x9C8D	# <CJK>
+0x312C	0x7206	# <CJK>
+0x312D	0x676F	# <CJK>
+0x312E	0x7891	# <CJK>
+0x312F	0x60B2	# <CJK>
+0x3130	0x5351	# <CJK>
+0x3131	0x5317	# <CJK>
+0x3132	0x8F88	# <CJK>
+0x3133	0x80CC	# <CJK>
+0x3134	0x8D1D	# <CJK>
+0x3135	0x94A1	# <CJK>
+0x3136	0x500D	# <CJK>
+0x3137	0x72C8	# <CJK>
+0x3138	0x5907	# <CJK>
+0x3139	0x60EB	# <CJK>
+0x313A	0x7119	# <CJK>
+0x313B	0x88AB	# <CJK>
+0x313C	0x5954	# <CJK>
+0x313D	0x82EF	# <CJK>
+0x313E	0x672C	# <CJK>
+0x313F	0x7B28	# <CJK>
+0x3140	0x5D29	# <CJK>
+0x3141	0x7EF7	# <CJK>
+0x3142	0x752D	# <CJK>
+0x3143	0x6CF5	# <CJK>
+0x3144	0x8E66	# <CJK>
+0x3145	0x8FF8	# <CJK>
+0x3146	0x903C	# <CJK>
+0x3147	0x9F3B	# <CJK>
+0x3148	0x6BD4	# <CJK>
+0x3149	0x9119	# <CJK>
+0x314A	0x7B14	# <CJK>
+0x314B	0x5F7C	# <CJK>
+0x314C	0x78A7	# <CJK>
+0x314D	0x84D6	# <CJK>
+0x314E	0x853D	# <CJK>
+0x314F	0x6BD5	# <CJK>
+0x3150	0x6BD9	# <CJK>
+0x3151	0x6BD6	# <CJK>
+0x3152	0x5E01	# <CJK>
+0x3153	0x5E87	# <CJK>
+0x3154	0x75F9	# <CJK>
+0x3155	0x95ED	# <CJK>
+0x3156	0x655D	# <CJK>
+0x3157	0x5F0A	# <CJK>
+0x3158	0x5FC5	# <CJK>
+0x3159	0x8F9F	# <CJK>
+0x315A	0x58C1	# <CJK>
+0x315B	0x81C2	# <CJK>
+0x315C	0x907F	# <CJK>
+0x315D	0x965B	# <CJK>
+0x315E	0x97AD	# <CJK>
+0x315F	0x8FB9	# <CJK>
+0x3160	0x7F16	# <CJK>
+0x3161	0x8D2C	# <CJK>
+0x3162	0x6241	# <CJK>
+0x3163	0x4FBF	# <CJK>
+0x3164	0x53D8	# <CJK>
+0x3165	0x535E	# <CJK>
+0x3166	0x8FA8	# <CJK>
+0x3167	0x8FA9	# <CJK>
+0x3168	0x8FAB	# <CJK>
+0x3169	0x904D	# <CJK>
+0x316A	0x6807	# <CJK>
+0x316B	0x5F6A	# <CJK>
+0x316C	0x8198	# <CJK>
+0x316D	0x8868	# <CJK>
+0x316E	0x9CD6	# <CJK>
+0x316F	0x618B	# <CJK>
+0x3170	0x522B	# <CJK>
+0x3171	0x762A	# <CJK>
+0x3172	0x5F6C	# <CJK>
+0x3173	0x658C	# <CJK>
+0x3174	0x6FD2	# <CJK>
+0x3175	0x6EE8	# <CJK>
+0x3176	0x5BBE	# <CJK>
+0x3177	0x6448	# <CJK>
+0x3178	0x5175	# <CJK>
+0x3179	0x51B0	# <CJK>
+0x317A	0x67C4	# <CJK>
+0x317B	0x4E19	# <CJK>
+0x317C	0x79C9	# <CJK>
+0x317D	0x997C	# <CJK>
+0x317E	0x70B3	# <CJK>
+0x3221	0x75C5	# <CJK>
+0x3222	0x5E76	# <CJK>
+0x3223	0x73BB	# <CJK>
+0x3224	0x83E0	# <CJK>
+0x3225	0x64AD	# <CJK>
+0x3226	0x62E8	# <CJK>
+0x3227	0x94B5	# <CJK>
+0x3228	0x6CE2	# <CJK>
+0x3229	0x535A	# <CJK>
+0x322A	0x52C3	# <CJK>
+0x322B	0x640F	# <CJK>
+0x322C	0x94C2	# <CJK>
+0x322D	0x7B94	# <CJK>
+0x322E	0x4F2F	# <CJK>
+0x322F	0x5E1B	# <CJK>
+0x3230	0x8236	# <CJK>
+0x3231	0x8116	# <CJK>
+0x3232	0x818A	# <CJK>
+0x3233	0x6E24	# <CJK>
+0x3234	0x6CCA	# <CJK>
+0x3235	0x9A73	# <CJK>
+0x3236	0x6355	# <CJK>
+0x3237	0x535C	# <CJK>
+0x3238	0x54FA	# <CJK>
+0x3239	0x8865	# <CJK>
+0x323A	0x57E0	# <CJK>
+0x323B	0x4E0D	# <CJK>
+0x323C	0x5E03	# <CJK>
+0x323D	0x6B65	# <CJK>
+0x323E	0x7C3F	# <CJK>
+0x323F	0x90E8	# <CJK>
+0x3240	0x6016	# <CJK>
+0x3241	0x64E6	# <CJK>
+0x3242	0x731C	# <CJK>
+0x3243	0x88C1	# <CJK>
+0x3244	0x6750	# <CJK>
+0x3245	0x624D	# <CJK>
+0x3246	0x8D22	# <CJK>
+0x3247	0x776C	# <CJK>
+0x3248	0x8E29	# <CJK>
+0x3249	0x91C7	# <CJK>
+0x324A	0x5F69	# <CJK>
+0x324B	0x83DC	# <CJK>
+0x324C	0x8521	# <CJK>
+0x324D	0x9910	# <CJK>
+0x324E	0x53C2	# <CJK>
+0x324F	0x8695	# <CJK>
+0x3250	0x6B8B	# <CJK>
+0x3251	0x60ED	# <CJK>
+0x3252	0x60E8	# <CJK>
+0x3253	0x707F	# <CJK>
+0x3254	0x82CD	# <CJK>
+0x3255	0x8231	# <CJK>
+0x3256	0x4ED3	# <CJK>
+0x3257	0x6CA7	# <CJK>
+0x3258	0x85CF	# <CJK>
+0x3259	0x64CD	# <CJK>
+0x325A	0x7CD9	# <CJK>
+0x325B	0x69FD	# <CJK>
+0x325C	0x66F9	# <CJK>
+0x325D	0x8349	# <CJK>
+0x325E	0x5395	# <CJK>
+0x325F	0x7B56	# <CJK>
+0x3260	0x4FA7	# <CJK>
+0x3261	0x518C	# <CJK>
+0x3262	0x6D4B	# <CJK>
+0x3263	0x5C42	# <CJK>
+0x3264	0x8E6D	# <CJK>
+0x3265	0x63D2	# <CJK>
+0x3266	0x53C9	# <CJK>
+0x3267	0x832C	# <CJK>
+0x3268	0x8336	# <CJK>
+0x3269	0x67E5	# <CJK>
+0x326A	0x78B4	# <CJK>
+0x326B	0x643D	# <CJK>
+0x326C	0x5BDF	# <CJK>
+0x326D	0x5C94	# <CJK>
+0x326E	0x5DEE	# <CJK>
+0x326F	0x8BE7	# <CJK>
+0x3270	0x62C6	# <CJK>
+0x3271	0x67F4	# <CJK>
+0x3272	0x8C7A	# <CJK>
+0x3273	0x6400	# <CJK>
+0x3274	0x63BA	# <CJK>
+0x3275	0x8749	# <CJK>
+0x3276	0x998B	# <CJK>
+0x3277	0x8C17	# <CJK>
+0x3278	0x7F20	# <CJK>
+0x3279	0x94F2	# <CJK>
+0x327A	0x4EA7	# <CJK>
+0x327B	0x9610	# <CJK>
+0x327C	0x98A4	# <CJK>
+0x327D	0x660C	# <CJK>
+0x327E	0x7316	# <CJK>
+0x3321	0x573A	# <CJK>
+0x3322	0x5C1D	# <CJK>
+0x3323	0x5E38	# <CJK>
+0x3324	0x957F	# <CJK>
+0x3325	0x507F	# <CJK>
+0x3326	0x80A0	# <CJK>
+0x3327	0x5382	# <CJK>
+0x3328	0x655E	# <CJK>
+0x3329	0x7545	# <CJK>
+0x332A	0x5531	# <CJK>
+0x332B	0x5021	# <CJK>
+0x332C	0x8D85	# <CJK>
+0x332D	0x6284	# <CJK>
+0x332E	0x949E	# <CJK>
+0x332F	0x671D	# <CJK>
+0x3330	0x5632	# <CJK>
+0x3331	0x6F6E	# <CJK>
+0x3332	0x5DE2	# <CJK>
+0x3333	0x5435	# <CJK>
+0x3334	0x7092	# <CJK>
+0x3335	0x8F66	# <CJK>
+0x3336	0x626F	# <CJK>
+0x3337	0x64A4	# <CJK>
+0x3338	0x63A3	# <CJK>
+0x3339	0x5F7B	# <CJK>
+0x333A	0x6F88	# <CJK>
+0x333B	0x90F4	# <CJK>
+0x333C	0x81E3	# <CJK>
+0x333D	0x8FB0	# <CJK>
+0x333E	0x5C18	# <CJK>
+0x333F	0x6668	# <CJK>
+0x3340	0x5FF1	# <CJK>
+0x3341	0x6C89	# <CJK>
+0x3342	0x9648	# <CJK>
+0x3343	0x8D81	# <CJK>
+0x3344	0x886C	# <CJK>
+0x3345	0x6491	# <CJK>
+0x3346	0x79F0	# <CJK>
+0x3347	0x57CE	# <CJK>
+0x3348	0x6A59	# <CJK>
+0x3349	0x6210	# <CJK>
+0x334A	0x5448	# <CJK>
+0x334B	0x4E58	# <CJK>
+0x334C	0x7A0B	# <CJK>
+0x334D	0x60E9	# <CJK>
+0x334E	0x6F84	# <CJK>
+0x334F	0x8BDA	# <CJK>
+0x3350	0x627F	# <CJK>
+0x3351	0x901E	# <CJK>
+0x3352	0x9A8B	# <CJK>
+0x3353	0x79E4	# <CJK>
+0x3354	0x5403	# <CJK>
+0x3355	0x75F4	# <CJK>
+0x3356	0x6301	# <CJK>
+0x3357	0x5319	# <CJK>
+0x3358	0x6C60	# <CJK>
+0x3359	0x8FDF	# <CJK>
+0x335A	0x5F1B	# <CJK>
+0x335B	0x9A70	# <CJK>
+0x335C	0x803B	# <CJK>
+0x335D	0x9F7F	# <CJK>
+0x335E	0x4F88	# <CJK>
+0x335F	0x5C3A	# <CJK>
+0x3360	0x8D64	# <CJK>
+0x3361	0x7FC5	# <CJK>
+0x3362	0x65A5	# <CJK>
+0x3363	0x70BD	# <CJK>
+0x3364	0x5145	# <CJK>
+0x3365	0x51B2	# <CJK>
+0x3366	0x866B	# <CJK>
+0x3367	0x5D07	# <CJK>
+0x3368	0x5BA0	# <CJK>
+0x3369	0x62BD	# <CJK>
+0x336A	0x916C	# <CJK>
+0x336B	0x7574	# <CJK>
+0x336C	0x8E0C	# <CJK>
+0x336D	0x7A20	# <CJK>
+0x336E	0x6101	# <CJK>
+0x336F	0x7B79	# <CJK>
+0x3370	0x4EC7	# <CJK>
+0x3371	0x7EF8	# <CJK>
+0x3372	0x7785	# <CJK>
+0x3373	0x4E11	# <CJK>
+0x3374	0x81ED	# <CJK>
+0x3375	0x521D	# <CJK>
+0x3376	0x51FA	# <CJK>
+0x3377	0x6A71	# <CJK>
+0x3378	0x53A8	# <CJK>
+0x3379	0x8E87	# <CJK>
+0x337A	0x9504	# <CJK>
+0x337B	0x96CF	# <CJK>
+0x337C	0x6EC1	# <CJK>
+0x337D	0x9664	# <CJK>
+0x337E	0x695A	# <CJK>
+0x3421	0x7840	# <CJK>
+0x3422	0x50A8	# <CJK>
+0x3423	0x77D7	# <CJK>
+0x3424	0x6410	# <CJK>
+0x3425	0x89E6	# <CJK>
+0x3426	0x5904	# <CJK>
+0x3427	0x63E3	# <CJK>
+0x3428	0x5DDD	# <CJK>
+0x3429	0x7A7F	# <CJK>
+0x342A	0x693D	# <CJK>
+0x342B	0x4F20	# <CJK>
+0x342C	0x8239	# <CJK>
+0x342D	0x5598	# <CJK>
+0x342E	0x4E32	# <CJK>
+0x342F	0x75AE	# <CJK>
+0x3430	0x7A97	# <CJK>
+0x3431	0x5E62	# <CJK>
+0x3432	0x5E8A	# <CJK>
+0x3433	0x95EF	# <CJK>
+0x3434	0x521B	# <CJK>
+0x3435	0x5439	# <CJK>
+0x3436	0x708A	# <CJK>
+0x3437	0x6376	# <CJK>
+0x3438	0x9524	# <CJK>
+0x3439	0x5782	# <CJK>
+0x343A	0x6625	# <CJK>
+0x343B	0x693F	# <CJK>
+0x343C	0x9187	# <CJK>
+0x343D	0x5507	# <CJK>
+0x343E	0x6DF3	# <CJK>
+0x343F	0x7EAF	# <CJK>
+0x3440	0x8822	# <CJK>
+0x3441	0x6233	# <CJK>
+0x3442	0x7EF0	# <CJK>
+0x3443	0x75B5	# <CJK>
+0x3444	0x8328	# <CJK>
+0x3445	0x78C1	# <CJK>
+0x3446	0x96CC	# <CJK>
+0x3447	0x8F9E	# <CJK>
+0x3448	0x6148	# <CJK>
+0x3449	0x74F7	# <CJK>
+0x344A	0x8BCD	# <CJK>
+0x344B	0x6B64	# <CJK>
+0x344C	0x523A	# <CJK>
+0x344D	0x8D50	# <CJK>
+0x344E	0x6B21	# <CJK>
+0x344F	0x806A	# <CJK>
+0x3450	0x8471	# <CJK>
+0x3451	0x56F1	# <CJK>
+0x3452	0x5306	# <CJK>
+0x3453	0x4ECE	# <CJK>
+0x3454	0x4E1B	# <CJK>
+0x3455	0x51D1	# <CJK>
+0x3456	0x7C97	# <CJK>
+0x3457	0x918B	# <CJK>
+0x3458	0x7C07	# <CJK>
+0x3459	0x4FC3	# <CJK>
+0x345A	0x8E7F	# <CJK>
+0x345B	0x7BE1	# <CJK>
+0x345C	0x7A9C	# <CJK>
+0x345D	0x6467	# <CJK>
+0x345E	0x5D14	# <CJK>
+0x345F	0x50AC	# <CJK>
+0x3460	0x8106	# <CJK>
+0x3461	0x7601	# <CJK>
+0x3462	0x7CB9	# <CJK>
+0x3463	0x6DEC	# <CJK>
+0x3464	0x7FE0	# <CJK>
+0x3465	0x6751	# <CJK>
+0x3466	0x5B58	# <CJK>
+0x3467	0x5BF8	# <CJK>
+0x3468	0x78CB	# <CJK>
+0x3469	0x64AE	# <CJK>
+0x346A	0x6413	# <CJK>
+0x346B	0x63AA	# <CJK>
+0x346C	0x632B	# <CJK>
+0x346D	0x9519	# <CJK>
+0x346E	0x642D	# <CJK>
+0x346F	0x8FBE	# <CJK>
+0x3470	0x7B54	# <CJK>
+0x3471	0x7629	# <CJK>
+0x3472	0x6253	# <CJK>
+0x3473	0x5927	# <CJK>
+0x3474	0x5446	# <CJK>
+0x3475	0x6B79	# <CJK>
+0x3476	0x50A3	# <CJK>
+0x3477	0x6234	# <CJK>
+0x3478	0x5E26	# <CJK>
+0x3479	0x6B86	# <CJK>
+0x347A	0x4EE3	# <CJK>
+0x347B	0x8D37	# <CJK>
+0x347C	0x888B	# <CJK>
+0x347D	0x5F85	# <CJK>
+0x347E	0x902E	# <CJK>
+0x3521	0x6020	# <CJK>
+0x3522	0x803D	# <CJK>
+0x3523	0x62C5	# <CJK>
+0x3524	0x4E39	# <CJK>
+0x3525	0x5355	# <CJK>
+0x3526	0x90F8	# <CJK>
+0x3527	0x63B8	# <CJK>
+0x3528	0x80C6	# <CJK>
+0x3529	0x65E6	# <CJK>
+0x352A	0x6C2E	# <CJK>
+0x352B	0x4F46	# <CJK>
+0x352C	0x60EE	# <CJK>
+0x352D	0x6DE1	# <CJK>
+0x352E	0x8BDE	# <CJK>
+0x352F	0x5F39	# <CJK>
+0x3530	0x86CB	# <CJK>
+0x3531	0x5F53	# <CJK>
+0x3532	0x6321	# <CJK>
+0x3533	0x515A	# <CJK>
+0x3534	0x8361	# <CJK>
+0x3535	0x6863	# <CJK>
+0x3536	0x5200	# <CJK>
+0x3537	0x6363	# <CJK>
+0x3538	0x8E48	# <CJK>
+0x3539	0x5012	# <CJK>
+0x353A	0x5C9B	# <CJK>
+0x353B	0x7977	# <CJK>
+0x353C	0x5BFC	# <CJK>
+0x353D	0x5230	# <CJK>
+0x353E	0x7A3B	# <CJK>
+0x353F	0x60BC	# <CJK>
+0x3540	0x9053	# <CJK>
+0x3541	0x76D7	# <CJK>
+0x3542	0x5FB7	# <CJK>
+0x3543	0x5F97	# <CJK>
+0x3544	0x7684	# <CJK>
+0x3545	0x8E6C	# <CJK>
+0x3546	0x706F	# <CJK>
+0x3547	0x767B	# <CJK>
+0x3548	0x7B49	# <CJK>
+0x3549	0x77AA	# <CJK>
+0x354A	0x51F3	# <CJK>
+0x354B	0x9093	# <CJK>
+0x354C	0x5824	# <CJK>
+0x354D	0x4F4E	# <CJK>
+0x354E	0x6EF4	# <CJK>
+0x354F	0x8FEA	# <CJK>
+0x3550	0x654C	# <CJK>
+0x3551	0x7B1B	# <CJK>
+0x3552	0x72C4	# <CJK>
+0x3553	0x6DA4	# <CJK>
+0x3554	0x7FDF	# <CJK>
+0x3555	0x5AE1	# <CJK>
+0x3556	0x62B5	# <CJK>
+0x3557	0x5E95	# <CJK>
+0x3558	0x5730	# <CJK>
+0x3559	0x8482	# <CJK>
+0x355A	0x7B2C	# <CJK>
+0x355B	0x5E1D	# <CJK>
+0x355C	0x5F1F	# <CJK>
+0x355D	0x9012	# <CJK>
+0x355E	0x7F14	# <CJK>
+0x355F	0x98A0	# <CJK>
+0x3560	0x6382	# <CJK>
+0x3561	0x6EC7	# <CJK>
+0x3562	0x7898	# <CJK>
+0x3563	0x70B9	# <CJK>
+0x3564	0x5178	# <CJK>
+0x3565	0x975B	# <CJK>
+0x3566	0x57AB	# <CJK>
+0x3567	0x7535	# <CJK>
+0x3568	0x4F43	# <CJK>
+0x3569	0x7538	# <CJK>
+0x356A	0x5E97	# <CJK>
+0x356B	0x60E6	# <CJK>
+0x356C	0x5960	# <CJK>
+0x356D	0x6DC0	# <CJK>
+0x356E	0x6BBF	# <CJK>
+0x356F	0x7889	# <CJK>
+0x3570	0x53FC	# <CJK>
+0x3571	0x96D5	# <CJK>
+0x3572	0x51CB	# <CJK>
+0x3573	0x5201	# <CJK>
+0x3574	0x6389	# <CJK>
+0x3575	0x540A	# <CJK>
+0x3576	0x9493	# <CJK>
+0x3577	0x8C03	# <CJK>
+0x3578	0x8DCC	# <CJK>
+0x3579	0x7239	# <CJK>
+0x357A	0x789F	# <CJK>
+0x357B	0x8776	# <CJK>
+0x357C	0x8FED	# <CJK>
+0x357D	0x8C0D	# <CJK>
+0x357E	0x53E0	# <CJK>
+0x3621	0x4E01	# <CJK>
+0x3622	0x76EF	# <CJK>
+0x3623	0x53EE	# <CJK>
+0x3624	0x9489	# <CJK>
+0x3625	0x9876	# <CJK>
+0x3626	0x9F0E	# <CJK>
+0x3627	0x952D	# <CJK>
+0x3628	0x5B9A	# <CJK>
+0x3629	0x8BA2	# <CJK>
+0x362A	0x4E22	# <CJK>
+0x362B	0x4E1C	# <CJK>
+0x362C	0x51AC	# <CJK>
+0x362D	0x8463	# <CJK>
+0x362E	0x61C2	# <CJK>
+0x362F	0x52A8	# <CJK>
+0x3630	0x680B	# <CJK>
+0x3631	0x4F97	# <CJK>
+0x3632	0x606B	# <CJK>
+0x3633	0x51BB	# <CJK>
+0x3634	0x6D1E	# <CJK>
+0x3635	0x515C	# <CJK>
+0x3636	0x6296	# <CJK>
+0x3637	0x6597	# <CJK>
+0x3638	0x9661	# <CJK>
+0x3639	0x8C46	# <CJK>
+0x363A	0x9017	# <CJK>
+0x363B	0x75D8	# <CJK>
+0x363C	0x90FD	# <CJK>
+0x363D	0x7763	# <CJK>
+0x363E	0x6BD2	# <CJK>
+0x363F	0x728A	# <CJK>
+0x3640	0x72EC	# <CJK>
+0x3641	0x8BFB	# <CJK>
+0x3642	0x5835	# <CJK>
+0x3643	0x7779	# <CJK>
+0x3644	0x8D4C	# <CJK>
+0x3645	0x675C	# <CJK>
+0x3646	0x9540	# <CJK>
+0x3647	0x809A	# <CJK>
+0x3648	0x5EA6	# <CJK>
+0x3649	0x6E21	# <CJK>
+0x364A	0x5992	# <CJK>
+0x364B	0x7AEF	# <CJK>
+0x364C	0x77ED	# <CJK>
+0x364D	0x953B	# <CJK>
+0x364E	0x6BB5	# <CJK>
+0x364F	0x65AD	# <CJK>
+0x3650	0x7F0E	# <CJK>
+0x3651	0x5806	# <CJK>
+0x3652	0x5151	# <CJK>
+0x3653	0x961F	# <CJK>
+0x3654	0x5BF9	# <CJK>
+0x3655	0x58A9	# <CJK>
+0x3656	0x5428	# <CJK>
+0x3657	0x8E72	# <CJK>
+0x3658	0x6566	# <CJK>
+0x3659	0x987F	# <CJK>
+0x365A	0x56E4	# <CJK>
+0x365B	0x949D	# <CJK>
+0x365C	0x76FE	# <CJK>
+0x365D	0x9041	# <CJK>
+0x365E	0x6387	# <CJK>
+0x365F	0x54C6	# <CJK>
+0x3660	0x591A	# <CJK>
+0x3661	0x593A	# <CJK>
+0x3662	0x579B	# <CJK>
+0x3663	0x8EB2	# <CJK>
+0x3664	0x6735	# <CJK>
+0x3665	0x8DFA	# <CJK>
+0x3666	0x8235	# <CJK>
+0x3667	0x5241	# <CJK>
+0x3668	0x60F0	# <CJK>
+0x3669	0x5815	# <CJK>
+0x366A	0x86FE	# <CJK>
+0x366B	0x5CE8	# <CJK>
+0x366C	0x9E45	# <CJK>
+0x366D	0x4FC4	# <CJK>
+0x366E	0x989D	# <CJK>
+0x366F	0x8BB9	# <CJK>
+0x3670	0x5A25	# <CJK>
+0x3671	0x6076	# <CJK>
+0x3672	0x5384	# <CJK>
+0x3673	0x627C	# <CJK>
+0x3674	0x904F	# <CJK>
+0x3675	0x9102	# <CJK>
+0x3676	0x997F	# <CJK>
+0x3677	0x6069	# <CJK>
+0x3678	0x800C	# <CJK>
+0x3679	0x513F	# <CJK>
+0x367A	0x8033	# <CJK>
+0x367B	0x5C14	# <CJK>
+0x367C	0x9975	# <CJK>
+0x367D	0x6D31	# <CJK>
+0x367E	0x4E8C	# <CJK>
+0x3721	0x8D30	# <CJK>
+0x3722	0x53D1	# <CJK>
+0x3723	0x7F5A	# <CJK>
+0x3724	0x7B4F	# <CJK>
+0x3725	0x4F10	# <CJK>
+0x3726	0x4E4F	# <CJK>
+0x3727	0x9600	# <CJK>
+0x3728	0x6CD5	# <CJK>
+0x3729	0x73D0	# <CJK>
+0x372A	0x85E9	# <CJK>
+0x372B	0x5E06	# <CJK>
+0x372C	0x756A	# <CJK>
+0x372D	0x7FFB	# <CJK>
+0x372E	0x6A0A	# <CJK>
+0x372F	0x77FE	# <CJK>
+0x3730	0x9492	# <CJK>
+0x3731	0x7E41	# <CJK>
+0x3732	0x51E1	# <CJK>
+0x3733	0x70E6	# <CJK>
+0x3734	0x53CD	# <CJK>
+0x3735	0x8FD4	# <CJK>
+0x3736	0x8303	# <CJK>
+0x3737	0x8D29	# <CJK>
+0x3738	0x72AF	# <CJK>
+0x3739	0x996D	# <CJK>
+0x373A	0x6CDB	# <CJK>
+0x373B	0x574A	# <CJK>
+0x373C	0x82B3	# <CJK>
+0x373D	0x65B9	# <CJK>
+0x373E	0x80AA	# <CJK>
+0x373F	0x623F	# <CJK>
+0x3740	0x9632	# <CJK>
+0x3741	0x59A8	# <CJK>
+0x3742	0x4EFF	# <CJK>
+0x3743	0x8BBF	# <CJK>
+0x3744	0x7EBA	# <CJK>
+0x3745	0x653E	# <CJK>
+0x3746	0x83F2	# <CJK>
+0x3747	0x975E	# <CJK>
+0x3748	0x5561	# <CJK>
+0x3749	0x98DE	# <CJK>
+0x374A	0x80A5	# <CJK>
+0x374B	0x532A	# <CJK>
+0x374C	0x8BFD	# <CJK>
+0x374D	0x5420	# <CJK>
+0x374E	0x80BA	# <CJK>
+0x374F	0x5E9F	# <CJK>
+0x3750	0x6CB8	# <CJK>
+0x3751	0x8D39	# <CJK>
+0x3752	0x82AC	# <CJK>
+0x3753	0x915A	# <CJK>
+0x3754	0x5429	# <CJK>
+0x3755	0x6C1B	# <CJK>
+0x3756	0x5206	# <CJK>
+0x3757	0x7EB7	# <CJK>
+0x3758	0x575F	# <CJK>
+0x3759	0x711A	# <CJK>
+0x375A	0x6C7E	# <CJK>
+0x375B	0x7C89	# <CJK>
+0x375C	0x594B	# <CJK>
+0x375D	0x4EFD	# <CJK>
+0x375E	0x5FFF	# <CJK>
+0x375F	0x6124	# <CJK>
+0x3760	0x7CAA	# <CJK>
+0x3761	0x4E30	# <CJK>
+0x3762	0x5C01	# <CJK>
+0x3763	0x67AB	# <CJK>
+0x3764	0x8702	# <CJK>
+0x3765	0x5CF0	# <CJK>
+0x3766	0x950B	# <CJK>
+0x3767	0x98CE	# <CJK>
+0x3768	0x75AF	# <CJK>
+0x3769	0x70FD	# <CJK>
+0x376A	0x9022	# <CJK>
+0x376B	0x51AF	# <CJK>
+0x376C	0x7F1D	# <CJK>
+0x376D	0x8BBD	# <CJK>
+0x376E	0x5949	# <CJK>
+0x376F	0x51E4	# <CJK>
+0x3770	0x4F5B	# <CJK>
+0x3771	0x5426	# <CJK>
+0x3772	0x592B	# <CJK>
+0x3773	0x6577	# <CJK>
+0x3774	0x80A4	# <CJK>
+0x3775	0x5B75	# <CJK>
+0x3776	0x6276	# <CJK>
+0x3777	0x62C2	# <CJK>
+0x3778	0x8F90	# <CJK>
+0x3779	0x5E45	# <CJK>
+0x377A	0x6C1F	# <CJK>
+0x377B	0x7B26	# <CJK>
+0x377C	0x4F0F	# <CJK>
+0x377D	0x4FD8	# <CJK>
+0x377E	0x670D	# <CJK>
+0x3821	0x6D6E	# <CJK>
+0x3822	0x6DAA	# <CJK>
+0x3823	0x798F	# <CJK>
+0x3824	0x88B1	# <CJK>
+0x3825	0x5F17	# <CJK>
+0x3826	0x752B	# <CJK>
+0x3827	0x629A	# <CJK>
+0x3828	0x8F85	# <CJK>
+0x3829	0x4FEF	# <CJK>
+0x382A	0x91DC	# <CJK>
+0x382B	0x65A7	# <CJK>
+0x382C	0x812F	# <CJK>
+0x382D	0x8151	# <CJK>
+0x382E	0x5E9C	# <CJK>
+0x382F	0x8150	# <CJK>
+0x3830	0x8D74	# <CJK>
+0x3831	0x526F	# <CJK>
+0x3832	0x8986	# <CJK>
+0x3833	0x8D4B	# <CJK>
+0x3834	0x590D	# <CJK>
+0x3835	0x5085	# <CJK>
+0x3836	0x4ED8	# <CJK>
+0x3837	0x961C	# <CJK>
+0x3838	0x7236	# <CJK>
+0x3839	0x8179	# <CJK>
+0x383A	0x8D1F	# <CJK>
+0x383B	0x5BCC	# <CJK>
+0x383C	0x8BA3	# <CJK>
+0x383D	0x9644	# <CJK>
+0x383E	0x5987	# <CJK>
+0x383F	0x7F1A	# <CJK>
+0x3840	0x5490	# <CJK>
+0x3841	0x5676	# <CJK>
+0x3842	0x560E	# <CJK>
+0x3843	0x8BE5	# <CJK>
+0x3844	0x6539	# <CJK>
+0x3845	0x6982	# <CJK>
+0x3846	0x9499	# <CJK>
+0x3847	0x76D6	# <CJK>
+0x3848	0x6E89	# <CJK>
+0x3849	0x5E72	# <CJK>
+0x384A	0x7518	# <CJK>
+0x384B	0x6746	# <CJK>
+0x384C	0x67D1	# <CJK>
+0x384D	0x7AFF	# <CJK>
+0x384E	0x809D	# <CJK>
+0x384F	0x8D76	# <CJK>
+0x3850	0x611F	# <CJK>
+0x3851	0x79C6	# <CJK>
+0x3852	0x6562	# <CJK>
+0x3853	0x8D63	# <CJK>
+0x3854	0x5188	# <CJK>
+0x3855	0x521A	# <CJK>
+0x3856	0x94A2	# <CJK>
+0x3857	0x7F38	# <CJK>
+0x3858	0x809B	# <CJK>
+0x3859	0x7EB2	# <CJK>
+0x385A	0x5C97	# <CJK>
+0x385B	0x6E2F	# <CJK>
+0x385C	0x6760	# <CJK>
+0x385D	0x7BD9	# <CJK>
+0x385E	0x768B	# <CJK>
+0x385F	0x9AD8	# <CJK>
+0x3860	0x818F	# <CJK>
+0x3861	0x7F94	# <CJK>
+0x3862	0x7CD5	# <CJK>
+0x3863	0x641E	# <CJK>
+0x3864	0x9550	# <CJK>
+0x3865	0x7A3F	# <CJK>
+0x3866	0x544A	# <CJK>
+0x3867	0x54E5	# <CJK>
+0x3868	0x6B4C	# <CJK>
+0x3869	0x6401	# <CJK>
+0x386A	0x6208	# <CJK>
+0x386B	0x9E3D	# <CJK>
+0x386C	0x80F3	# <CJK>
+0x386D	0x7599	# <CJK>
+0x386E	0x5272	# <CJK>
+0x386F	0x9769	# <CJK>
+0x3870	0x845B	# <CJK>
+0x3871	0x683C	# <CJK>
+0x3872	0x86E4	# <CJK>
+0x3873	0x9601	# <CJK>
+0x3874	0x9694	# <CJK>
+0x3875	0x94EC	# <CJK>
+0x3876	0x4E2A	# <CJK>
+0x3877	0x5404	# <CJK>
+0x3878	0x7ED9	# <CJK>
+0x3879	0x6839	# <CJK>
+0x387A	0x8DDF	# <CJK>
+0x387B	0x8015	# <CJK>
+0x387C	0x66F4	# <CJK>
+0x387D	0x5E9A	# <CJK>
+0x387E	0x7FB9	# <CJK>
+0x3921	0x57C2	# <CJK>
+0x3922	0x803F	# <CJK>
+0x3923	0x6897	# <CJK>
+0x3924	0x5DE5	# <CJK>
+0x3925	0x653B	# <CJK>
+0x3926	0x529F	# <CJK>
+0x3927	0x606D	# <CJK>
+0x3928	0x9F9A	# <CJK>
+0x3929	0x4F9B	# <CJK>
+0x392A	0x8EAC	# <CJK>
+0x392B	0x516C	# <CJK>
+0x392C	0x5BAB	# <CJK>
+0x392D	0x5F13	# <CJK>
+0x392E	0x5DE9	# <CJK>
+0x392F	0x6C5E	# <CJK>
+0x3930	0x62F1	# <CJK>
+0x3931	0x8D21	# <CJK>
+0x3932	0x5171	# <CJK>
+0x3933	0x94A9	# <CJK>
+0x3934	0x52FE	# <CJK>
+0x3935	0x6C9F	# <CJK>
+0x3936	0x82DF	# <CJK>
+0x3937	0x72D7	# <CJK>
+0x3938	0x57A2	# <CJK>
+0x3939	0x6784	# <CJK>
+0x393A	0x8D2D	# <CJK>
+0x393B	0x591F	# <CJK>
+0x393C	0x8F9C	# <CJK>
+0x393D	0x83C7	# <CJK>
+0x393E	0x5495	# <CJK>
+0x393F	0x7B8D	# <CJK>
+0x3940	0x4F30	# <CJK>
+0x3941	0x6CBD	# <CJK>
+0x3942	0x5B64	# <CJK>
+0x3943	0x59D1	# <CJK>
+0x3944	0x9F13	# <CJK>
+0x3945	0x53E4	# <CJK>
+0x3946	0x86CA	# <CJK>
+0x3947	0x9AA8	# <CJK>
+0x3948	0x8C37	# <CJK>
+0x3949	0x80A1	# <CJK>
+0x394A	0x6545	# <CJK>
+0x394B	0x987E	# <CJK>
+0x394C	0x56FA	# <CJK>
+0x394D	0x96C7	# <CJK>
+0x394E	0x522E	# <CJK>
+0x394F	0x74DC	# <CJK>
+0x3950	0x5250	# <CJK>
+0x3951	0x5BE1	# <CJK>
+0x3952	0x6302	# <CJK>
+0x3953	0x8902	# <CJK>
+0x3954	0x4E56	# <CJK>
+0x3955	0x62D0	# <CJK>
+0x3956	0x602A	# <CJK>
+0x3957	0x68FA	# <CJK>
+0x3958	0x5173	# <CJK>
+0x3959	0x5B98	# <CJK>
+0x395A	0x51A0	# <CJK>
+0x395B	0x89C2	# <CJK>
+0x395C	0x7BA1	# <CJK>
+0x395D	0x9986	# <CJK>
+0x395E	0x7F50	# <CJK>
+0x395F	0x60EF	# <CJK>
+0x3960	0x704C	# <CJK>
+0x3961	0x8D2F	# <CJK>
+0x3962	0x5149	# <CJK>
+0x3963	0x5E7F	# <CJK>
+0x3964	0x901B	# <CJK>
+0x3965	0x7470	# <CJK>
+0x3966	0x89C4	# <CJK>
+0x3967	0x572D	# <CJK>
+0x3968	0x7845	# <CJK>
+0x3969	0x5F52	# <CJK>
+0x396A	0x9F9F	# <CJK>
+0x396B	0x95FA	# <CJK>
+0x396C	0x8F68	# <CJK>
+0x396D	0x9B3C	# <CJK>
+0x396E	0x8BE1	# <CJK>
+0x396F	0x7678	# <CJK>
+0x3970	0x6842	# <CJK>
+0x3971	0x67DC	# <CJK>
+0x3972	0x8DEA	# <CJK>
+0x3973	0x8D35	# <CJK>
+0x3974	0x523D	# <CJK>
+0x3975	0x8F8A	# <CJK>
+0x3976	0x6EDA	# <CJK>
+0x3977	0x68CD	# <CJK>
+0x3978	0x9505	# <CJK>
+0x3979	0x90ED	# <CJK>
+0x397A	0x56FD	# <CJK>
+0x397B	0x679C	# <CJK>
+0x397C	0x88F9	# <CJK>
+0x397D	0x8FC7	# <CJK>
+0x397E	0x54C8	# <CJK>
+0x3A21	0x9AB8	# <CJK>
+0x3A22	0x5B69	# <CJK>
+0x3A23	0x6D77	# <CJK>
+0x3A24	0x6C26	# <CJK>
+0x3A25	0x4EA5	# <CJK>
+0x3A26	0x5BB3	# <CJK>
+0x3A27	0x9A87	# <CJK>
+0x3A28	0x9163	# <CJK>
+0x3A29	0x61A8	# <CJK>
+0x3A2A	0x90AF	# <CJK>
+0x3A2B	0x97E9	# <CJK>
+0x3A2C	0x542B	# <CJK>
+0x3A2D	0x6DB5	# <CJK>
+0x3A2E	0x5BD2	# <CJK>
+0x3A2F	0x51FD	# <CJK>
+0x3A30	0x558A	# <CJK>
+0x3A31	0x7F55	# <CJK>
+0x3A32	0x7FF0	# <CJK>
+0x3A33	0x64BC	# <CJK>
+0x3A34	0x634D	# <CJK>
+0x3A35	0x65F1	# <CJK>
+0x3A36	0x61BE	# <CJK>
+0x3A37	0x608D	# <CJK>
+0x3A38	0x710A	# <CJK>
+0x3A39	0x6C57	# <CJK>
+0x3A3A	0x6C49	# <CJK>
+0x3A3B	0x592F	# <CJK>
+0x3A3C	0x676D	# <CJK>
+0x3A3D	0x822A	# <CJK>
+0x3A3E	0x58D5	# <CJK>
+0x3A3F	0x568E	# <CJK>
+0x3A40	0x8C6A	# <CJK>
+0x3A41	0x6BEB	# <CJK>
+0x3A42	0x90DD	# <CJK>
+0x3A43	0x597D	# <CJK>
+0x3A44	0x8017	# <CJK>
+0x3A45	0x53F7	# <CJK>
+0x3A46	0x6D69	# <CJK>
+0x3A47	0x5475	# <CJK>
+0x3A48	0x559D	# <CJK>
+0x3A49	0x8377	# <CJK>
+0x3A4A	0x83CF	# <CJK>
+0x3A4B	0x6838	# <CJK>
+0x3A4C	0x79BE	# <CJK>
+0x3A4D	0x548C	# <CJK>
+0x3A4E	0x4F55	# <CJK>
+0x3A4F	0x5408	# <CJK>
+0x3A50	0x76D2	# <CJK>
+0x3A51	0x8C89	# <CJK>
+0x3A52	0x9602	# <CJK>
+0x3A53	0x6CB3	# <CJK>
+0x3A54	0x6DB8	# <CJK>
+0x3A55	0x8D6B	# <CJK>
+0x3A56	0x8910	# <CJK>
+0x3A57	0x9E64	# <CJK>
+0x3A58	0x8D3A	# <CJK>
+0x3A59	0x563F	# <CJK>
+0x3A5A	0x9ED1	# <CJK>
+0x3A5B	0x75D5	# <CJK>
+0x3A5C	0x5F88	# <CJK>
+0x3A5D	0x72E0	# <CJK>
+0x3A5E	0x6068	# <CJK>
+0x3A5F	0x54FC	# <CJK>
+0x3A60	0x4EA8	# <CJK>
+0x3A61	0x6A2A	# <CJK>
+0x3A62	0x8861	# <CJK>
+0x3A63	0x6052	# <CJK>
+0x3A64	0x8F70	# <CJK>
+0x3A65	0x54C4	# <CJK>
+0x3A66	0x70D8	# <CJK>
+0x3A67	0x8679	# <CJK>
+0x3A68	0x9E3F	# <CJK>
+0x3A69	0x6D2A	# <CJK>
+0x3A6A	0x5B8F	# <CJK>
+0x3A6B	0x5F18	# <CJK>
+0x3A6C	0x7EA2	# <CJK>
+0x3A6D	0x5589	# <CJK>
+0x3A6E	0x4FAF	# <CJK>
+0x3A6F	0x7334	# <CJK>
+0x3A70	0x543C	# <CJK>
+0x3A71	0x539A	# <CJK>
+0x3A72	0x5019	# <CJK>
+0x3A73	0x540E	# <CJK>
+0x3A74	0x547C	# <CJK>
+0x3A75	0x4E4E	# <CJK>
+0x3A76	0x5FFD	# <CJK>
+0x3A77	0x745A	# <CJK>
+0x3A78	0x58F6	# <CJK>
+0x3A79	0x846B	# <CJK>
+0x3A7A	0x80E1	# <CJK>
+0x3A7B	0x8774	# <CJK>
+0x3A7C	0x72D0	# <CJK>
+0x3A7D	0x7CCA	# <CJK>
+0x3A7E	0x6E56	# <CJK>
+0x3B21	0x5F27	# <CJK>
+0x3B22	0x864E	# <CJK>
+0x3B23	0x552C	# <CJK>
+0x3B24	0x62A4	# <CJK>
+0x3B25	0x4E92	# <CJK>
+0x3B26	0x6CAA	# <CJK>
+0x3B27	0x6237	# <CJK>
+0x3B28	0x82B1	# <CJK>
+0x3B29	0x54D7	# <CJK>
+0x3B2A	0x534E	# <CJK>
+0x3B2B	0x733E	# <CJK>
+0x3B2C	0x6ED1	# <CJK>
+0x3B2D	0x753B	# <CJK>
+0x3B2E	0x5212	# <CJK>
+0x3B2F	0x5316	# <CJK>
+0x3B30	0x8BDD	# <CJK>
+0x3B31	0x69D0	# <CJK>
+0x3B32	0x5F8A	# <CJK>
+0x3B33	0x6000	# <CJK>
+0x3B34	0x6DEE	# <CJK>
+0x3B35	0x574F	# <CJK>
+0x3B36	0x6B22	# <CJK>
+0x3B37	0x73AF	# <CJK>
+0x3B38	0x6853	# <CJK>
+0x3B39	0x8FD8	# <CJK>
+0x3B3A	0x7F13	# <CJK>
+0x3B3B	0x6362	# <CJK>
+0x3B3C	0x60A3	# <CJK>
+0x3B3D	0x5524	# <CJK>
+0x3B3E	0x75EA	# <CJK>
+0x3B3F	0x8C62	# <CJK>
+0x3B40	0x7115	# <CJK>
+0x3B41	0x6DA3	# <CJK>
+0x3B42	0x5BA6	# <CJK>
+0x3B43	0x5E7B	# <CJK>
+0x3B44	0x8352	# <CJK>
+0x3B45	0x614C	# <CJK>
+0x3B46	0x9EC4	# <CJK>
+0x3B47	0x78FA	# <CJK>
+0x3B48	0x8757	# <CJK>
+0x3B49	0x7C27	# <CJK>
+0x3B4A	0x7687	# <CJK>
+0x3B4B	0x51F0	# <CJK>
+0x3B4C	0x60F6	# <CJK>
+0x3B4D	0x714C	# <CJK>
+0x3B4E	0x6643	# <CJK>
+0x3B4F	0x5E4C	# <CJK>
+0x3B50	0x604D	# <CJK>
+0x3B51	0x8C0E	# <CJK>
+0x3B52	0x7070	# <CJK>
+0x3B53	0x6325	# <CJK>
+0x3B54	0x8F89	# <CJK>
+0x3B55	0x5FBD	# <CJK>
+0x3B56	0x6062	# <CJK>
+0x3B57	0x86D4	# <CJK>
+0x3B58	0x56DE	# <CJK>
+0x3B59	0x6BC1	# <CJK>
+0x3B5A	0x6094	# <CJK>
+0x3B5B	0x6167	# <CJK>
+0x3B5C	0x5349	# <CJK>
+0x3B5D	0x60E0	# <CJK>
+0x3B5E	0x6666	# <CJK>
+0x3B5F	0x8D3F	# <CJK>
+0x3B60	0x79FD	# <CJK>
+0x3B61	0x4F1A	# <CJK>
+0x3B62	0x70E9	# <CJK>
+0x3B63	0x6C47	# <CJK>
+0x3B64	0x8BB3	# <CJK>
+0x3B65	0x8BF2	# <CJK>
+0x3B66	0x7ED8	# <CJK>
+0x3B67	0x8364	# <CJK>
+0x3B68	0x660F	# <CJK>
+0x3B69	0x5A5A	# <CJK>
+0x3B6A	0x9B42	# <CJK>
+0x3B6B	0x6D51	# <CJK>
+0x3B6C	0x6DF7	# <CJK>
+0x3B6D	0x8C41	# <CJK>
+0x3B6E	0x6D3B	# <CJK>
+0x3B6F	0x4F19	# <CJK>
+0x3B70	0x706B	# <CJK>
+0x3B71	0x83B7	# <CJK>
+0x3B72	0x6216	# <CJK>
+0x3B73	0x60D1	# <CJK>
+0x3B74	0x970D	# <CJK>
+0x3B75	0x8D27	# <CJK>
+0x3B76	0x7978	# <CJK>
+0x3B77	0x51FB	# <CJK>
+0x3B78	0x573E	# <CJK>
+0x3B79	0x57FA	# <CJK>
+0x3B7A	0x673A	# <CJK>
+0x3B7B	0x7578	# <CJK>
+0x3B7C	0x7A3D	# <CJK>
+0x3B7D	0x79EF	# <CJK>
+0x3B7E	0x7B95	# <CJK>
+0x3C21	0x808C	# <CJK>
+0x3C22	0x9965	# <CJK>
+0x3C23	0x8FF9	# <CJK>
+0x3C24	0x6FC0	# <CJK>
+0x3C25	0x8BA5	# <CJK>
+0x3C26	0x9E21	# <CJK>
+0x3C27	0x59EC	# <CJK>
+0x3C28	0x7EE9	# <CJK>
+0x3C29	0x7F09	# <CJK>
+0x3C2A	0x5409	# <CJK>
+0x3C2B	0x6781	# <CJK>
+0x3C2C	0x68D8	# <CJK>
+0x3C2D	0x8F91	# <CJK>
+0x3C2E	0x7C4D	# <CJK>
+0x3C2F	0x96C6	# <CJK>
+0x3C30	0x53CA	# <CJK>
+0x3C31	0x6025	# <CJK>
+0x3C32	0x75BE	# <CJK>
+0x3C33	0x6C72	# <CJK>
+0x3C34	0x5373	# <CJK>
+0x3C35	0x5AC9	# <CJK>
+0x3C36	0x7EA7	# <CJK>
+0x3C37	0x6324	# <CJK>
+0x3C38	0x51E0	# <CJK>
+0x3C39	0x810A	# <CJK>
+0x3C3A	0x5DF1	# <CJK>
+0x3C3B	0x84DF	# <CJK>
+0x3C3C	0x6280	# <CJK>
+0x3C3D	0x5180	# <CJK>
+0x3C3E	0x5B63	# <CJK>
+0x3C3F	0x4F0E	# <CJK>
+0x3C40	0x796D	# <CJK>
+0x3C41	0x5242	# <CJK>
+0x3C42	0x60B8	# <CJK>
+0x3C43	0x6D4E	# <CJK>
+0x3C44	0x5BC4	# <CJK>
+0x3C45	0x5BC2	# <CJK>
+0x3C46	0x8BA1	# <CJK>
+0x3C47	0x8BB0	# <CJK>
+0x3C48	0x65E2	# <CJK>
+0x3C49	0x5FCC	# <CJK>
+0x3C4A	0x9645	# <CJK>
+0x3C4B	0x5993	# <CJK>
+0x3C4C	0x7EE7	# <CJK>
+0x3C4D	0x7EAA	# <CJK>
+0x3C4E	0x5609	# <CJK>
+0x3C4F	0x67B7	# <CJK>
+0x3C50	0x5939	# <CJK>
+0x3C51	0x4F73	# <CJK>
+0x3C52	0x5BB6	# <CJK>
+0x3C53	0x52A0	# <CJK>
+0x3C54	0x835A	# <CJK>
+0x3C55	0x988A	# <CJK>
+0x3C56	0x8D3E	# <CJK>
+0x3C57	0x7532	# <CJK>
+0x3C58	0x94BE	# <CJK>
+0x3C59	0x5047	# <CJK>
+0x3C5A	0x7A3C	# <CJK>
+0x3C5B	0x4EF7	# <CJK>
+0x3C5C	0x67B6	# <CJK>
+0x3C5D	0x9A7E	# <CJK>
+0x3C5E	0x5AC1	# <CJK>
+0x3C5F	0x6B7C	# <CJK>
+0x3C60	0x76D1	# <CJK>
+0x3C61	0x575A	# <CJK>
+0x3C62	0x5C16	# <CJK>
+0x3C63	0x7B3A	# <CJK>
+0x3C64	0x95F4	# <CJK>
+0x3C65	0x714E	# <CJK>
+0x3C66	0x517C	# <CJK>
+0x3C67	0x80A9	# <CJK>
+0x3C68	0x8270	# <CJK>
+0x3C69	0x5978	# <CJK>
+0x3C6A	0x7F04	# <CJK>
+0x3C6B	0x8327	# <CJK>
+0x3C6C	0x68C0	# <CJK>
+0x3C6D	0x67EC	# <CJK>
+0x3C6E	0x78B1	# <CJK>
+0x3C6F	0x7877	# <CJK>
+0x3C70	0x62E3	# <CJK>
+0x3C71	0x6361	# <CJK>
+0x3C72	0x7B80	# <CJK>
+0x3C73	0x4FED	# <CJK>
+0x3C74	0x526A	# <CJK>
+0x3C75	0x51CF	# <CJK>
+0x3C76	0x8350	# <CJK>
+0x3C77	0x69DB	# <CJK>
+0x3C78	0x9274	# <CJK>
+0x3C79	0x8DF5	# <CJK>
+0x3C7A	0x8D31	# <CJK>
+0x3C7B	0x89C1	# <CJK>
+0x3C7C	0x952E	# <CJK>
+0x3C7D	0x7BAD	# <CJK>
+0x3C7E	0x4EF6	# <CJK>
+0x3D21	0x5065	# <CJK>
+0x3D22	0x8230	# <CJK>
+0x3D23	0x5251	# <CJK>
+0x3D24	0x996F	# <CJK>
+0x3D25	0x6E10	# <CJK>
+0x3D26	0x6E85	# <CJK>
+0x3D27	0x6DA7	# <CJK>
+0x3D28	0x5EFA	# <CJK>
+0x3D29	0x50F5	# <CJK>
+0x3D2A	0x59DC	# <CJK>
+0x3D2B	0x5C06	# <CJK>
+0x3D2C	0x6D46	# <CJK>
+0x3D2D	0x6C5F	# <CJK>
+0x3D2E	0x7586	# <CJK>
+0x3D2F	0x848B	# <CJK>
+0x3D30	0x6868	# <CJK>
+0x3D31	0x5956	# <CJK>
+0x3D32	0x8BB2	# <CJK>
+0x3D33	0x5320	# <CJK>
+0x3D34	0x9171	# <CJK>
+0x3D35	0x964D	# <CJK>
+0x3D36	0x8549	# <CJK>
+0x3D37	0x6912	# <CJK>
+0x3D38	0x7901	# <CJK>
+0x3D39	0x7126	# <CJK>
+0x3D3A	0x80F6	# <CJK>
+0x3D3B	0x4EA4	# <CJK>
+0x3D3C	0x90CA	# <CJK>
+0x3D3D	0x6D47	# <CJK>
+0x3D3E	0x9A84	# <CJK>
+0x3D3F	0x5A07	# <CJK>
+0x3D40	0x56BC	# <CJK>
+0x3D41	0x6405	# <CJK>
+0x3D42	0x94F0	# <CJK>
+0x3D43	0x77EB	# <CJK>
+0x3D44	0x4FA5	# <CJK>
+0x3D45	0x811A	# <CJK>
+0x3D46	0x72E1	# <CJK>
+0x3D47	0x89D2	# <CJK>
+0x3D48	0x997A	# <CJK>
+0x3D49	0x7F34	# <CJK>
+0x3D4A	0x7EDE	# <CJK>
+0x3D4B	0x527F	# <CJK>
+0x3D4C	0x6559	# <CJK>
+0x3D4D	0x9175	# <CJK>
+0x3D4E	0x8F7F	# <CJK>
+0x3D4F	0x8F83	# <CJK>
+0x3D50	0x53EB	# <CJK>
+0x3D51	0x7A96	# <CJK>
+0x3D52	0x63ED	# <CJK>
+0x3D53	0x63A5	# <CJK>
+0x3D54	0x7686	# <CJK>
+0x3D55	0x79F8	# <CJK>
+0x3D56	0x8857	# <CJK>
+0x3D57	0x9636	# <CJK>
+0x3D58	0x622A	# <CJK>
+0x3D59	0x52AB	# <CJK>
+0x3D5A	0x8282	# <CJK>
+0x3D5B	0x6854	# <CJK>
+0x3D5C	0x6770	# <CJK>
+0x3D5D	0x6377	# <CJK>
+0x3D5E	0x776B	# <CJK>
+0x3D5F	0x7AED	# <CJK>
+0x3D60	0x6D01	# <CJK>
+0x3D61	0x7ED3	# <CJK>
+0x3D62	0x89E3	# <CJK>
+0x3D63	0x59D0	# <CJK>
+0x3D64	0x6212	# <CJK>
+0x3D65	0x85C9	# <CJK>
+0x3D66	0x82A5	# <CJK>
+0x3D67	0x754C	# <CJK>
+0x3D68	0x501F	# <CJK>
+0x3D69	0x4ECB	# <CJK>
+0x3D6A	0x75A5	# <CJK>
+0x3D6B	0x8BEB	# <CJK>
+0x3D6C	0x5C4A	# <CJK>
+0x3D6D	0x5DFE	# <CJK>
+0x3D6E	0x7B4B	# <CJK>
+0x3D6F	0x65A4	# <CJK>
+0x3D70	0x91D1	# <CJK>
+0x3D71	0x4ECA	# <CJK>
+0x3D72	0x6D25	# <CJK>
+0x3D73	0x895F	# <CJK>
+0x3D74	0x7D27	# <CJK>
+0x3D75	0x9526	# <CJK>
+0x3D76	0x4EC5	# <CJK>
+0x3D77	0x8C28	# <CJK>
+0x3D78	0x8FDB	# <CJK>
+0x3D79	0x9773	# <CJK>
+0x3D7A	0x664B	# <CJK>
+0x3D7B	0x7981	# <CJK>
+0x3D7C	0x8FD1	# <CJK>
+0x3D7D	0x70EC	# <CJK>
+0x3D7E	0x6D78	# <CJK>
+0x3E21	0x5C3D	# <CJK>
+0x3E22	0x52B2	# <CJK>
+0x3E23	0x8346	# <CJK>
+0x3E24	0x5162	# <CJK>
+0x3E25	0x830E	# <CJK>
+0x3E26	0x775B	# <CJK>
+0x3E27	0x6676	# <CJK>
+0x3E28	0x9CB8	# <CJK>
+0x3E29	0x4EAC	# <CJK>
+0x3E2A	0x60CA	# <CJK>
+0x3E2B	0x7CBE	# <CJK>
+0x3E2C	0x7CB3	# <CJK>
+0x3E2D	0x7ECF	# <CJK>
+0x3E2E	0x4E95	# <CJK>
+0x3E2F	0x8B66	# <CJK>
+0x3E30	0x666F	# <CJK>
+0x3E31	0x9888	# <CJK>
+0x3E32	0x9759	# <CJK>
+0x3E33	0x5883	# <CJK>
+0x3E34	0x656C	# <CJK>
+0x3E35	0x955C	# <CJK>
+0x3E36	0x5F84	# <CJK>
+0x3E37	0x75C9	# <CJK>
+0x3E38	0x9756	# <CJK>
+0x3E39	0x7ADF	# <CJK>
+0x3E3A	0x7ADE	# <CJK>
+0x3E3B	0x51C0	# <CJK>
+0x3E3C	0x70AF	# <CJK>
+0x3E3D	0x7A98	# <CJK>
+0x3E3E	0x63EA	# <CJK>
+0x3E3F	0x7A76	# <CJK>
+0x3E40	0x7EA0	# <CJK>
+0x3E41	0x7396	# <CJK>
+0x3E42	0x97ED	# <CJK>
+0x3E43	0x4E45	# <CJK>
+0x3E44	0x7078	# <CJK>
+0x3E45	0x4E5D	# <CJK>
+0x3E46	0x9152	# <CJK>
+0x3E47	0x53A9	# <CJK>
+0x3E48	0x6551	# <CJK>
+0x3E49	0x65E7	# <CJK>
+0x3E4A	0x81FC	# <CJK>
+0x3E4B	0x8205	# <CJK>
+0x3E4C	0x548E	# <CJK>
+0x3E4D	0x5C31	# <CJK>
+0x3E4E	0x759A	# <CJK>
+0x3E4F	0x97A0	# <CJK>
+0x3E50	0x62D8	# <CJK>
+0x3E51	0x72D9	# <CJK>
+0x3E52	0x75BD	# <CJK>
+0x3E53	0x5C45	# <CJK>
+0x3E54	0x9A79	# <CJK>
+0x3E55	0x83CA	# <CJK>
+0x3E56	0x5C40	# <CJK>
+0x3E57	0x5480	# <CJK>
+0x3E58	0x77E9	# <CJK>
+0x3E59	0x4E3E	# <CJK>
+0x3E5A	0x6CAE	# <CJK>
+0x3E5B	0x805A	# <CJK>
+0x3E5C	0x62D2	# <CJK>
+0x3E5D	0x636E	# <CJK>
+0x3E5E	0x5DE8	# <CJK>
+0x3E5F	0x5177	# <CJK>
+0x3E60	0x8DDD	# <CJK>
+0x3E61	0x8E1E	# <CJK>
+0x3E62	0x952F	# <CJK>
+0x3E63	0x4FF1	# <CJK>
+0x3E64	0x53E5	# <CJK>
+0x3E65	0x60E7	# <CJK>
+0x3E66	0x70AC	# <CJK>
+0x3E67	0x5267	# <CJK>
+0x3E68	0x6350	# <CJK>
+0x3E69	0x9E43	# <CJK>
+0x3E6A	0x5A1F	# <CJK>
+0x3E6B	0x5026	# <CJK>
+0x3E6C	0x7737	# <CJK>
+0x3E6D	0x5377	# <CJK>
+0x3E6E	0x7EE2	# <CJK>
+0x3E6F	0x6485	# <CJK>
+0x3E70	0x652B	# <CJK>
+0x3E71	0x6289	# <CJK>
+0x3E72	0x6398	# <CJK>
+0x3E73	0x5014	# <CJK>
+0x3E74	0x7235	# <CJK>
+0x3E75	0x89C9	# <CJK>
+0x3E76	0x51B3	# <CJK>
+0x3E77	0x8BC0	# <CJK>
+0x3E78	0x7EDD	# <CJK>
+0x3E79	0x5747	# <CJK>
+0x3E7A	0x83CC	# <CJK>
+0x3E7B	0x94A7	# <CJK>
+0x3E7C	0x519B	# <CJK>
+0x3E7D	0x541B	# <CJK>
+0x3E7E	0x5CFB	# <CJK>
+0x3F21	0x4FCA	# <CJK>
+0x3F22	0x7AE3	# <CJK>
+0x3F23	0x6D5A	# <CJK>
+0x3F24	0x90E1	# <CJK>
+0x3F25	0x9A8F	# <CJK>
+0x3F26	0x5580	# <CJK>
+0x3F27	0x5496	# <CJK>
+0x3F28	0x5361	# <CJK>
+0x3F29	0x54AF	# <CJK>
+0x3F2A	0x5F00	# <CJK>
+0x3F2B	0x63E9	# <CJK>
+0x3F2C	0x6977	# <CJK>
+0x3F2D	0x51EF	# <CJK>
+0x3F2E	0x6168	# <CJK>
+0x3F2F	0x520A	# <CJK>
+0x3F30	0x582A	# <CJK>
+0x3F31	0x52D8	# <CJK>
+0x3F32	0x574E	# <CJK>
+0x3F33	0x780D	# <CJK>
+0x3F34	0x770B	# <CJK>
+0x3F35	0x5EB7	# <CJK>
+0x3F36	0x6177	# <CJK>
+0x3F37	0x7CE0	# <CJK>
+0x3F38	0x625B	# <CJK>
+0x3F39	0x6297	# <CJK>
+0x3F3A	0x4EA2	# <CJK>
+0x3F3B	0x7095	# <CJK>
+0x3F3C	0x8003	# <CJK>
+0x3F3D	0x62F7	# <CJK>
+0x3F3E	0x70E4	# <CJK>
+0x3F3F	0x9760	# <CJK>
+0x3F40	0x5777	# <CJK>
+0x3F41	0x82DB	# <CJK>
+0x3F42	0x67EF	# <CJK>
+0x3F43	0x68F5	# <CJK>
+0x3F44	0x78D5	# <CJK>
+0x3F45	0x9897	# <CJK>
+0x3F46	0x79D1	# <CJK>
+0x3F47	0x58F3	# <CJK>
+0x3F48	0x54B3	# <CJK>
+0x3F49	0x53EF	# <CJK>
+0x3F4A	0x6E34	# <CJK>
+0x3F4B	0x514B	# <CJK>
+0x3F4C	0x523B	# <CJK>
+0x3F4D	0x5BA2	# <CJK>
+0x3F4E	0x8BFE	# <CJK>
+0x3F4F	0x80AF	# <CJK>
+0x3F50	0x5543	# <CJK>
+0x3F51	0x57A6	# <CJK>
+0x3F52	0x6073	# <CJK>
+0x3F53	0x5751	# <CJK>
+0x3F54	0x542D	# <CJK>
+0x3F55	0x7A7A	# <CJK>
+0x3F56	0x6050	# <CJK>
+0x3F57	0x5B54	# <CJK>
+0x3F58	0x63A7	# <CJK>
+0x3F59	0x62A0	# <CJK>
+0x3F5A	0x53E3	# <CJK>
+0x3F5B	0x6263	# <CJK>
+0x3F5C	0x5BC7	# <CJK>
+0x3F5D	0x67AF	# <CJK>
+0x3F5E	0x54ED	# <CJK>
+0x3F5F	0x7A9F	# <CJK>
+0x3F60	0x82E6	# <CJK>
+0x3F61	0x9177	# <CJK>
+0x3F62	0x5E93	# <CJK>
+0x3F63	0x88E4	# <CJK>
+0x3F64	0x5938	# <CJK>
+0x3F65	0x57AE	# <CJK>
+0x3F66	0x630E	# <CJK>
+0x3F67	0x8DE8	# <CJK>
+0x3F68	0x80EF	# <CJK>
+0x3F69	0x5757	# <CJK>
+0x3F6A	0x7B77	# <CJK>
+0x3F6B	0x4FA9	# <CJK>
+0x3F6C	0x5FEB	# <CJK>
+0x3F6D	0x5BBD	# <CJK>
+0x3F6E	0x6B3E	# <CJK>
+0x3F6F	0x5321	# <CJK>
+0x3F70	0x7B50	# <CJK>
+0x3F71	0x72C2	# <CJK>
+0x3F72	0x6846	# <CJK>
+0x3F73	0x77FF	# <CJK>
+0x3F74	0x7736	# <CJK>
+0x3F75	0x65F7	# <CJK>
+0x3F76	0x51B5	# <CJK>
+0x3F77	0x4E8F	# <CJK>
+0x3F78	0x76D4	# <CJK>
+0x3F79	0x5CBF	# <CJK>
+0x3F7A	0x7AA5	# <CJK>
+0x3F7B	0x8475	# <CJK>
+0x3F7C	0x594E	# <CJK>
+0x3F7D	0x9B41	# <CJK>
+0x3F7E	0x5080	# <CJK>
+0x4021	0x9988	# <CJK>
+0x4022	0x6127	# <CJK>
+0x4023	0x6E83	# <CJK>
+0x4024	0x5764	# <CJK>
+0x4025	0x6606	# <CJK>
+0x4026	0x6346	# <CJK>
+0x4027	0x56F0	# <CJK>
+0x4028	0x62EC	# <CJK>
+0x4029	0x6269	# <CJK>
+0x402A	0x5ED3	# <CJK>
+0x402B	0x9614	# <CJK>
+0x402C	0x5783	# <CJK>
+0x402D	0x62C9	# <CJK>
+0x402E	0x5587	# <CJK>
+0x402F	0x8721	# <CJK>
+0x4030	0x814A	# <CJK>
+0x4031	0x8FA3	# <CJK>
+0x4032	0x5566	# <CJK>
+0x4033	0x83B1	# <CJK>
+0x4034	0x6765	# <CJK>
+0x4035	0x8D56	# <CJK>
+0x4036	0x84DD	# <CJK>
+0x4037	0x5A6A	# <CJK>
+0x4038	0x680F	# <CJK>
+0x4039	0x62E6	# <CJK>
+0x403A	0x7BEE	# <CJK>
+0x403B	0x9611	# <CJK>
+0x403C	0x5170	# <CJK>
+0x403D	0x6F9C	# <CJK>
+0x403E	0x8C30	# <CJK>
+0x403F	0x63FD	# <CJK>
+0x4040	0x89C8	# <CJK>
+0x4041	0x61D2	# <CJK>
+0x4042	0x7F06	# <CJK>
+0x4043	0x70C2	# <CJK>
+0x4044	0x6EE5	# <CJK>
+0x4045	0x7405	# <CJK>
+0x4046	0x6994	# <CJK>
+0x4047	0x72FC	# <CJK>
+0x4048	0x5ECA	# <CJK>
+0x4049	0x90CE	# <CJK>
+0x404A	0x6717	# <CJK>
+0x404B	0x6D6A	# <CJK>
+0x404C	0x635E	# <CJK>
+0x404D	0x52B3	# <CJK>
+0x404E	0x7262	# <CJK>
+0x404F	0x8001	# <CJK>
+0x4050	0x4F6C	# <CJK>
+0x4051	0x59E5	# <CJK>
+0x4052	0x916A	# <CJK>
+0x4053	0x70D9	# <CJK>
+0x4054	0x6D9D	# <CJK>
+0x4055	0x52D2	# <CJK>
+0x4056	0x4E50	# <CJK>
+0x4057	0x96F7	# <CJK>
+0x4058	0x956D	# <CJK>
+0x4059	0x857E	# <CJK>
+0x405A	0x78CA	# <CJK>
+0x405B	0x7D2F	# <CJK>
+0x405C	0x5121	# <CJK>
+0x405D	0x5792	# <CJK>
+0x405E	0x64C2	# <CJK>
+0x405F	0x808B	# <CJK>
+0x4060	0x7C7B	# <CJK>
+0x4061	0x6CEA	# <CJK>
+0x4062	0x68F1	# <CJK>
+0x4063	0x695E	# <CJK>
+0x4064	0x51B7	# <CJK>
+0x4065	0x5398	# <CJK>
+0x4066	0x68A8	# <CJK>
+0x4067	0x7281	# <CJK>
+0x4068	0x9ECE	# <CJK>
+0x4069	0x7BF1	# <CJK>
+0x406A	0x72F8	# <CJK>
+0x406B	0x79BB	# <CJK>
+0x406C	0x6F13	# <CJK>
+0x406D	0x7406	# <CJK>
+0x406E	0x674E	# <CJK>
+0x406F	0x91CC	# <CJK>
+0x4070	0x9CA4	# <CJK>
+0x4071	0x793C	# <CJK>
+0x4072	0x8389	# <CJK>
+0x4073	0x8354	# <CJK>
+0x4074	0x540F	# <CJK>
+0x4075	0x6817	# <CJK>
+0x4076	0x4E3D	# <CJK>
+0x4077	0x5389	# <CJK>
+0x4078	0x52B1	# <CJK>
+0x4079	0x783E	# <CJK>
+0x407A	0x5386	# <CJK>
+0x407B	0x5229	# <CJK>
+0x407C	0x5088	# <CJK>
+0x407D	0x4F8B	# <CJK>
+0x407E	0x4FD0	# <CJK>
+0x4121	0x75E2	# <CJK>
+0x4122	0x7ACB	# <CJK>
+0x4123	0x7C92	# <CJK>
+0x4124	0x6CA5	# <CJK>
+0x4125	0x96B6	# <CJK>
+0x4126	0x529B	# <CJK>
+0x4127	0x7483	# <CJK>
+0x4128	0x54E9	# <CJK>
+0x4129	0x4FE9	# <CJK>
+0x412A	0x8054	# <CJK>
+0x412B	0x83B2	# <CJK>
+0x412C	0x8FDE	# <CJK>
+0x412D	0x9570	# <CJK>
+0x412E	0x5EC9	# <CJK>
+0x412F	0x601C	# <CJK>
+0x4130	0x6D9F	# <CJK>
+0x4131	0x5E18	# <CJK>
+0x4132	0x655B	# <CJK>
+0x4133	0x8138	# <CJK>
+0x4134	0x94FE	# <CJK>
+0x4135	0x604B	# <CJK>
+0x4136	0x70BC	# <CJK>
+0x4137	0x7EC3	# <CJK>
+0x4138	0x7CAE	# <CJK>
+0x4139	0x51C9	# <CJK>
+0x413A	0x6881	# <CJK>
+0x413B	0x7CB1	# <CJK>
+0x413C	0x826F	# <CJK>
+0x413D	0x4E24	# <CJK>
+0x413E	0x8F86	# <CJK>
+0x413F	0x91CF	# <CJK>
+0x4140	0x667E	# <CJK>
+0x4141	0x4EAE	# <CJK>
+0x4142	0x8C05	# <CJK>
+0x4143	0x64A9	# <CJK>
+0x4144	0x804A	# <CJK>
+0x4145	0x50DA	# <CJK>
+0x4146	0x7597	# <CJK>
+0x4147	0x71CE	# <CJK>
+0x4148	0x5BE5	# <CJK>
+0x4149	0x8FBD	# <CJK>
+0x414A	0x6F66	# <CJK>
+0x414B	0x4E86	# <CJK>
+0x414C	0x6482	# <CJK>
+0x414D	0x9563	# <CJK>
+0x414E	0x5ED6	# <CJK>
+0x414F	0x6599	# <CJK>
+0x4150	0x5217	# <CJK>
+0x4151	0x88C2	# <CJK>
+0x4152	0x70C8	# <CJK>
+0x4153	0x52A3	# <CJK>
+0x4154	0x730E	# <CJK>
+0x4155	0x7433	# <CJK>
+0x4156	0x6797	# <CJK>
+0x4157	0x78F7	# <CJK>
+0x4158	0x9716	# <CJK>
+0x4159	0x4E34	# <CJK>
+0x415A	0x90BB	# <CJK>
+0x415B	0x9CDE	# <CJK>
+0x415C	0x6DCB	# <CJK>
+0x415D	0x51DB	# <CJK>
+0x415E	0x8D41	# <CJK>
+0x415F	0x541D	# <CJK>
+0x4160	0x62CE	# <CJK>
+0x4161	0x73B2	# <CJK>
+0x4162	0x83F1	# <CJK>
+0x4163	0x96F6	# <CJK>
+0x4164	0x9F84	# <CJK>
+0x4165	0x94C3	# <CJK>
+0x4166	0x4F36	# <CJK>
+0x4167	0x7F9A	# <CJK>
+0x4168	0x51CC	# <CJK>
+0x4169	0x7075	# <CJK>
+0x416A	0x9675	# <CJK>
+0x416B	0x5CAD	# <CJK>
+0x416C	0x9886	# <CJK>
+0x416D	0x53E6	# <CJK>
+0x416E	0x4EE4	# <CJK>
+0x416F	0x6E9C	# <CJK>
+0x4170	0x7409	# <CJK>
+0x4171	0x69B4	# <CJK>
+0x4172	0x786B	# <CJK>
+0x4173	0x998F	# <CJK>
+0x4174	0x7559	# <CJK>
+0x4175	0x5218	# <CJK>
+0x4176	0x7624	# <CJK>
+0x4177	0x6D41	# <CJK>
+0x4178	0x67F3	# <CJK>
+0x4179	0x516D	# <CJK>
+0x417A	0x9F99	# <CJK>
+0x417B	0x804B	# <CJK>
+0x417C	0x5499	# <CJK>
+0x417D	0x7B3C	# <CJK>
+0x417E	0x7ABF	# <CJK>
+0x4221	0x9686	# <CJK>
+0x4222	0x5784	# <CJK>
+0x4223	0x62E2	# <CJK>
+0x4224	0x9647	# <CJK>
+0x4225	0x697C	# <CJK>
+0x4226	0x5A04	# <CJK>
+0x4227	0x6402	# <CJK>
+0x4228	0x7BD3	# <CJK>
+0x4229	0x6F0F	# <CJK>
+0x422A	0x964B	# <CJK>
+0x422B	0x82A6	# <CJK>
+0x422C	0x5362	# <CJK>
+0x422D	0x9885	# <CJK>
+0x422E	0x5E90	# <CJK>
+0x422F	0x7089	# <CJK>
+0x4230	0x63B3	# <CJK>
+0x4231	0x5364	# <CJK>
+0x4232	0x864F	# <CJK>
+0x4233	0x9C81	# <CJK>
+0x4234	0x9E93	# <CJK>
+0x4235	0x788C	# <CJK>
+0x4236	0x9732	# <CJK>
+0x4237	0x8DEF	# <CJK>
+0x4238	0x8D42	# <CJK>
+0x4239	0x9E7F	# <CJK>
+0x423A	0x6F5E	# <CJK>
+0x423B	0x7984	# <CJK>
+0x423C	0x5F55	# <CJK>
+0x423D	0x9646	# <CJK>
+0x423E	0x622E	# <CJK>
+0x423F	0x9A74	# <CJK>
+0x4240	0x5415	# <CJK>
+0x4241	0x94DD	# <CJK>
+0x4242	0x4FA3	# <CJK>
+0x4243	0x65C5	# <CJK>
+0x4244	0x5C65	# <CJK>
+0x4245	0x5C61	# <CJK>
+0x4246	0x7F15	# <CJK>
+0x4247	0x8651	# <CJK>
+0x4248	0x6C2F	# <CJK>
+0x4249	0x5F8B	# <CJK>
+0x424A	0x7387	# <CJK>
+0x424B	0x6EE4	# <CJK>
+0x424C	0x7EFF	# <CJK>
+0x424D	0x5CE6	# <CJK>
+0x424E	0x631B	# <CJK>
+0x424F	0x5B6A	# <CJK>
+0x4250	0x6EE6	# <CJK>
+0x4251	0x5375	# <CJK>
+0x4252	0x4E71	# <CJK>
+0x4253	0x63A0	# <CJK>
+0x4254	0x7565	# <CJK>
+0x4255	0x62A1	# <CJK>
+0x4256	0x8F6E	# <CJK>
+0x4257	0x4F26	# <CJK>
+0x4258	0x4ED1	# <CJK>
+0x4259	0x6CA6	# <CJK>
+0x425A	0x7EB6	# <CJK>
+0x425B	0x8BBA	# <CJK>
+0x425C	0x841D	# <CJK>
+0x425D	0x87BA	# <CJK>
+0x425E	0x7F57	# <CJK>
+0x425F	0x903B	# <CJK>
+0x4260	0x9523	# <CJK>
+0x4261	0x7BA9	# <CJK>
+0x4262	0x9AA1	# <CJK>
+0x4263	0x88F8	# <CJK>
+0x4264	0x843D	# <CJK>
+0x4265	0x6D1B	# <CJK>
+0x4266	0x9A86	# <CJK>
+0x4267	0x7EDC	# <CJK>
+0x4268	0x5988	# <CJK>
+0x4269	0x9EBB	# <CJK>
+0x426A	0x739B	# <CJK>
+0x426B	0x7801	# <CJK>
+0x426C	0x8682	# <CJK>
+0x426D	0x9A6C	# <CJK>
+0x426E	0x9A82	# <CJK>
+0x426F	0x561B	# <CJK>
+0x4270	0x5417	# <CJK>
+0x4271	0x57CB	# <CJK>
+0x4272	0x4E70	# <CJK>
+0x4273	0x9EA6	# <CJK>
+0x4274	0x5356	# <CJK>
+0x4275	0x8FC8	# <CJK>
+0x4276	0x8109	# <CJK>
+0x4277	0x7792	# <CJK>
+0x4278	0x9992	# <CJK>
+0x4279	0x86EE	# <CJK>
+0x427A	0x6EE1	# <CJK>
+0x427B	0x8513	# <CJK>
+0x427C	0x66FC	# <CJK>
+0x427D	0x6162	# <CJK>
+0x427E	0x6F2B	# <CJK>
+0x4321	0x8C29	# <CJK>
+0x4322	0x8292	# <CJK>
+0x4323	0x832B	# <CJK>
+0x4324	0x76F2	# <CJK>
+0x4325	0x6C13	# <CJK>
+0x4326	0x5FD9	# <CJK>
+0x4327	0x83BD	# <CJK>
+0x4328	0x732B	# <CJK>
+0x4329	0x8305	# <CJK>
+0x432A	0x951A	# <CJK>
+0x432B	0x6BDB	# <CJK>
+0x432C	0x77DB	# <CJK>
+0x432D	0x94C6	# <CJK>
+0x432E	0x536F	# <CJK>
+0x432F	0x8302	# <CJK>
+0x4330	0x5192	# <CJK>
+0x4331	0x5E3D	# <CJK>
+0x4332	0x8C8C	# <CJK>
+0x4333	0x8D38	# <CJK>
+0x4334	0x4E48	# <CJK>
+0x4335	0x73AB	# <CJK>
+0x4336	0x679A	# <CJK>
+0x4337	0x6885	# <CJK>
+0x4338	0x9176	# <CJK>
+0x4339	0x9709	# <CJK>
+0x433A	0x7164	# <CJK>
+0x433B	0x6CA1	# <CJK>
+0x433C	0x7709	# <CJK>
+0x433D	0x5A92	# <CJK>
+0x433E	0x9541	# <CJK>
+0x433F	0x6BCF	# <CJK>
+0x4340	0x7F8E	# <CJK>
+0x4341	0x6627	# <CJK>
+0x4342	0x5BD0	# <CJK>
+0x4343	0x59B9	# <CJK>
+0x4344	0x5A9A	# <CJK>
+0x4345	0x95E8	# <CJK>
+0x4346	0x95F7	# <CJK>
+0x4347	0x4EEC	# <CJK>
+0x4348	0x840C	# <CJK>
+0x4349	0x8499	# <CJK>
+0x434A	0x6AAC	# <CJK>
+0x434B	0x76DF	# <CJK>
+0x434C	0x9530	# <CJK>
+0x434D	0x731B	# <CJK>
+0x434E	0x68A6	# <CJK>
+0x434F	0x5B5F	# <CJK>
+0x4350	0x772F	# <CJK>
+0x4351	0x919A	# <CJK>
+0x4352	0x9761	# <CJK>
+0x4353	0x7CDC	# <CJK>
+0x4354	0x8FF7	# <CJK>
+0x4355	0x8C1C	# <CJK>
+0x4356	0x5F25	# <CJK>
+0x4357	0x7C73	# <CJK>
+0x4358	0x79D8	# <CJK>
+0x4359	0x89C5	# <CJK>
+0x435A	0x6CCC	# <CJK>
+0x435B	0x871C	# <CJK>
+0x435C	0x5BC6	# <CJK>
+0x435D	0x5E42	# <CJK>
+0x435E	0x68C9	# <CJK>
+0x435F	0x7720	# <CJK>
+0x4360	0x7EF5	# <CJK>
+0x4361	0x5195	# <CJK>
+0x4362	0x514D	# <CJK>
+0x4363	0x52C9	# <CJK>
+0x4364	0x5A29	# <CJK>
+0x4365	0x7F05	# <CJK>
+0x4366	0x9762	# <CJK>
+0x4367	0x82D7	# <CJK>
+0x4368	0x63CF	# <CJK>
+0x4369	0x7784	# <CJK>
+0x436A	0x85D0	# <CJK>
+0x436B	0x79D2	# <CJK>
+0x436C	0x6E3A	# <CJK>
+0x436D	0x5E99	# <CJK>
+0x436E	0x5999	# <CJK>
+0x436F	0x8511	# <CJK>
+0x4370	0x706D	# <CJK>
+0x4371	0x6C11	# <CJK>
+0x4372	0x62BF	# <CJK>
+0x4373	0x76BF	# <CJK>
+0x4374	0x654F	# <CJK>
+0x4375	0x60AF	# <CJK>
+0x4376	0x95FD	# <CJK>
+0x4377	0x660E	# <CJK>
+0x4378	0x879F	# <CJK>
+0x4379	0x9E23	# <CJK>
+0x437A	0x94ED	# <CJK>
+0x437B	0x540D	# <CJK>
+0x437C	0x547D	# <CJK>
+0x437D	0x8C2C	# <CJK>
+0x437E	0x6478	# <CJK>
+0x4421	0x6479	# <CJK>
+0x4422	0x8611	# <CJK>
+0x4423	0x6A21	# <CJK>
+0x4424	0x819C	# <CJK>
+0x4425	0x78E8	# <CJK>
+0x4426	0x6469	# <CJK>
+0x4427	0x9B54	# <CJK>
+0x4428	0x62B9	# <CJK>
+0x4429	0x672B	# <CJK>
+0x442A	0x83AB	# <CJK>
+0x442B	0x58A8	# <CJK>
+0x442C	0x9ED8	# <CJK>
+0x442D	0x6CAB	# <CJK>
+0x442E	0x6F20	# <CJK>
+0x442F	0x5BDE	# <CJK>
+0x4430	0x964C	# <CJK>
+0x4431	0x8C0B	# <CJK>
+0x4432	0x725F	# <CJK>
+0x4433	0x67D0	# <CJK>
+0x4434	0x62C7	# <CJK>
+0x4435	0x7261	# <CJK>
+0x4436	0x4EA9	# <CJK>
+0x4437	0x59C6	# <CJK>
+0x4438	0x6BCD	# <CJK>
+0x4439	0x5893	# <CJK>
+0x443A	0x66AE	# <CJK>
+0x443B	0x5E55	# <CJK>
+0x443C	0x52DF	# <CJK>
+0x443D	0x6155	# <CJK>
+0x443E	0x6728	# <CJK>
+0x443F	0x76EE	# <CJK>
+0x4440	0x7766	# <CJK>
+0x4441	0x7267	# <CJK>
+0x4442	0x7A46	# <CJK>
+0x4443	0x62FF	# <CJK>
+0x4444	0x54EA	# <CJK>
+0x4445	0x5450	# <CJK>
+0x4446	0x94A0	# <CJK>
+0x4447	0x90A3	# <CJK>
+0x4448	0x5A1C	# <CJK>
+0x4449	0x7EB3	# <CJK>
+0x444A	0x6C16	# <CJK>
+0x444B	0x4E43	# <CJK>
+0x444C	0x5976	# <CJK>
+0x444D	0x8010	# <CJK>
+0x444E	0x5948	# <CJK>
+0x444F	0x5357	# <CJK>
+0x4450	0x7537	# <CJK>
+0x4451	0x96BE	# <CJK>
+0x4452	0x56CA	# <CJK>
+0x4453	0x6320	# <CJK>
+0x4454	0x8111	# <CJK>
+0x4455	0x607C	# <CJK>
+0x4456	0x95F9	# <CJK>
+0x4457	0x6DD6	# <CJK>
+0x4458	0x5462	# <CJK>
+0x4459	0x9981	# <CJK>
+0x445A	0x5185	# <CJK>
+0x445B	0x5AE9	# <CJK>
+0x445C	0x80FD	# <CJK>
+0x445D	0x59AE	# <CJK>
+0x445E	0x9713	# <CJK>
+0x445F	0x502A	# <CJK>
+0x4460	0x6CE5	# <CJK>
+0x4461	0x5C3C	# <CJK>
+0x4462	0x62DF	# <CJK>
+0x4463	0x4F60	# <CJK>
+0x4464	0x533F	# <CJK>
+0x4465	0x817B	# <CJK>
+0x4466	0x9006	# <CJK>
+0x4467	0x6EBA	# <CJK>
+0x4468	0x852B	# <CJK>
+0x4469	0x62C8	# <CJK>
+0x446A	0x5E74	# <CJK>
+0x446B	0x78BE	# <CJK>
+0x446C	0x64B5	# <CJK>
+0x446D	0x637B	# <CJK>
+0x446E	0x5FF5	# <CJK>
+0x446F	0x5A18	# <CJK>
+0x4470	0x917F	# <CJK>
+0x4471	0x9E1F	# <CJK>
+0x4472	0x5C3F	# <CJK>
+0x4473	0x634F	# <CJK>
+0x4474	0x8042	# <CJK>
+0x4475	0x5B7D	# <CJK>
+0x4476	0x556E	# <CJK>
+0x4477	0x954A	# <CJK>
+0x4478	0x954D	# <CJK>
+0x4479	0x6D85	# <CJK>
+0x447A	0x60A8	# <CJK>
+0x447B	0x67E0	# <CJK>
+0x447C	0x72DE	# <CJK>
+0x447D	0x51DD	# <CJK>
+0x447E	0x5B81	# <CJK>
+0x4521	0x62E7	# <CJK>
+0x4522	0x6CDE	# <CJK>
+0x4523	0x725B	# <CJK>
+0x4524	0x626D	# <CJK>
+0x4525	0x94AE	# <CJK>
+0x4526	0x7EBD	# <CJK>
+0x4527	0x8113	# <CJK>
+0x4528	0x6D53	# <CJK>
+0x4529	0x519C	# <CJK>
+0x452A	0x5F04	# <CJK>
+0x452B	0x5974	# <CJK>
+0x452C	0x52AA	# <CJK>
+0x452D	0x6012	# <CJK>
+0x452E	0x5973	# <CJK>
+0x452F	0x6696	# <CJK>
+0x4530	0x8650	# <CJK>
+0x4531	0x759F	# <CJK>
+0x4532	0x632A	# <CJK>
+0x4533	0x61E6	# <CJK>
+0x4534	0x7CEF	# <CJK>
+0x4535	0x8BFA	# <CJK>
+0x4536	0x54E6	# <CJK>
+0x4537	0x6B27	# <CJK>
+0x4538	0x9E25	# <CJK>
+0x4539	0x6BB4	# <CJK>
+0x453A	0x85D5	# <CJK>
+0x453B	0x5455	# <CJK>
+0x453C	0x5076	# <CJK>
+0x453D	0x6CA4	# <CJK>
+0x453E	0x556A	# <CJK>
+0x453F	0x8DB4	# <CJK>
+0x4540	0x722C	# <CJK>
+0x4541	0x5E15	# <CJK>
+0x4542	0x6015	# <CJK>
+0x4543	0x7436	# <CJK>
+0x4544	0x62CD	# <CJK>
+0x4545	0x6392	# <CJK>
+0x4546	0x724C	# <CJK>
+0x4547	0x5F98	# <CJK>
+0x4548	0x6E43	# <CJK>
+0x4549	0x6D3E	# <CJK>
+0x454A	0x6500	# <CJK>
+0x454B	0x6F58	# <CJK>
+0x454C	0x76D8	# <CJK>
+0x454D	0x78D0	# <CJK>
+0x454E	0x76FC	# <CJK>
+0x454F	0x7554	# <CJK>
+0x4550	0x5224	# <CJK>
+0x4551	0x53DB	# <CJK>
+0x4552	0x4E53	# <CJK>
+0x4553	0x5E9E	# <CJK>
+0x4554	0x65C1	# <CJK>
+0x4555	0x802A	# <CJK>
+0x4556	0x80D6	# <CJK>
+0x4557	0x629B	# <CJK>
+0x4558	0x5486	# <CJK>
+0x4559	0x5228	# <CJK>
+0x455A	0x70AE	# <CJK>
+0x455B	0x888D	# <CJK>
+0x455C	0x8DD1	# <CJK>
+0x455D	0x6CE1	# <CJK>
+0x455E	0x5478	# <CJK>
+0x455F	0x80DA	# <CJK>
+0x4560	0x57F9	# <CJK>
+0x4561	0x88F4	# <CJK>
+0x4562	0x8D54	# <CJK>
+0x4563	0x966A	# <CJK>
+0x4564	0x914D	# <CJK>
+0x4565	0x4F69	# <CJK>
+0x4566	0x6C9B	# <CJK>
+0x4567	0x55B7	# <CJK>
+0x4568	0x76C6	# <CJK>
+0x4569	0x7830	# <CJK>
+0x456A	0x62A8	# <CJK>
+0x456B	0x70F9	# <CJK>
+0x456C	0x6F8E	# <CJK>
+0x456D	0x5F6D	# <CJK>
+0x456E	0x84EC	# <CJK>
+0x456F	0x68DA	# <CJK>
+0x4570	0x787C	# <CJK>
+0x4571	0x7BF7	# <CJK>
+0x4572	0x81A8	# <CJK>
+0x4573	0x670B	# <CJK>
+0x4574	0x9E4F	# <CJK>
+0x4575	0x6367	# <CJK>
+0x4576	0x78B0	# <CJK>
+0x4577	0x576F	# <CJK>
+0x4578	0x7812	# <CJK>
+0x4579	0x9739	# <CJK>
+0x457A	0x6279	# <CJK>
+0x457B	0x62AB	# <CJK>
+0x457C	0x5288	# <CJK>
+0x457D	0x7435	# <CJK>
+0x457E	0x6BD7	# <CJK>
+0x4621	0x5564	# <CJK>
+0x4622	0x813E	# <CJK>
+0x4623	0x75B2	# <CJK>
+0x4624	0x76AE	# <CJK>
+0x4625	0x5339	# <CJK>
+0x4626	0x75DE	# <CJK>
+0x4627	0x50FB	# <CJK>
+0x4628	0x5C41	# <CJK>
+0x4629	0x8B6C	# <CJK>
+0x462A	0x7BC7	# <CJK>
+0x462B	0x504F	# <CJK>
+0x462C	0x7247	# <CJK>
+0x462D	0x9A97	# <CJK>
+0x462E	0x98D8	# <CJK>
+0x462F	0x6F02	# <CJK>
+0x4630	0x74E2	# <CJK>
+0x4631	0x7968	# <CJK>
+0x4632	0x6487	# <CJK>
+0x4633	0x77A5	# <CJK>
+0x4634	0x62FC	# <CJK>
+0x4635	0x9891	# <CJK>
+0x4636	0x8D2B	# <CJK>
+0x4637	0x54C1	# <CJK>
+0x4638	0x8058	# <CJK>
+0x4639	0x4E52	# <CJK>
+0x463A	0x576A	# <CJK>
+0x463B	0x82F9	# <CJK>
+0x463C	0x840D	# <CJK>
+0x463D	0x5E73	# <CJK>
+0x463E	0x51ED	# <CJK>
+0x463F	0x74F6	# <CJK>
+0x4640	0x8BC4	# <CJK>
+0x4641	0x5C4F	# <CJK>
+0x4642	0x5761	# <CJK>
+0x4643	0x6CFC	# <CJK>
+0x4644	0x9887	# <CJK>
+0x4645	0x5A46	# <CJK>
+0x4646	0x7834	# <CJK>
+0x4647	0x9B44	# <CJK>
+0x4648	0x8FEB	# <CJK>
+0x4649	0x7C95	# <CJK>
+0x464A	0x5256	# <CJK>
+0x464B	0x6251	# <CJK>
+0x464C	0x94FA	# <CJK>
+0x464D	0x4EC6	# <CJK>
+0x464E	0x8386	# <CJK>
+0x464F	0x8461	# <CJK>
+0x4650	0x83E9	# <CJK>
+0x4651	0x84B2	# <CJK>
+0x4652	0x57D4	# <CJK>
+0x4653	0x6734	# <CJK>
+0x4654	0x5703	# <CJK>
+0x4655	0x666E	# <CJK>
+0x4656	0x6D66	# <CJK>
+0x4657	0x8C31	# <CJK>
+0x4658	0x66DD	# <CJK>
+0x4659	0x7011	# <CJK>
+0x465A	0x671F	# <CJK>
+0x465B	0x6B3A	# <CJK>
+0x465C	0x6816	# <CJK>
+0x465D	0x621A	# <CJK>
+0x465E	0x59BB	# <CJK>
+0x465F	0x4E03	# <CJK>
+0x4660	0x51C4	# <CJK>
+0x4661	0x6F06	# <CJK>
+0x4662	0x67D2	# <CJK>
+0x4663	0x6C8F	# <CJK>
+0x4664	0x5176	# <CJK>
+0x4665	0x68CB	# <CJK>
+0x4666	0x5947	# <CJK>
+0x4667	0x6B67	# <CJK>
+0x4668	0x7566	# <CJK>
+0x4669	0x5D0E	# <CJK>
+0x466A	0x8110	# <CJK>
+0x466B	0x9F50	# <CJK>
+0x466C	0x65D7	# <CJK>
+0x466D	0x7948	# <CJK>
+0x466E	0x7941	# <CJK>
+0x466F	0x9A91	# <CJK>
+0x4670	0x8D77	# <CJK>
+0x4671	0x5C82	# <CJK>
+0x4672	0x4E5E	# <CJK>
+0x4673	0x4F01	# <CJK>
+0x4674	0x542F	# <CJK>
+0x4675	0x5951	# <CJK>
+0x4676	0x780C	# <CJK>
+0x4677	0x5668	# <CJK>
+0x4678	0x6C14	# <CJK>
+0x4679	0x8FC4	# <CJK>
+0x467A	0x5F03	# <CJK>
+0x467B	0x6C7D	# <CJK>
+0x467C	0x6CE3	# <CJK>
+0x467D	0x8BAB	# <CJK>
+0x467E	0x6390	# <CJK>
+0x4721	0x6070	# <CJK>
+0x4722	0x6D3D	# <CJK>
+0x4723	0x7275	# <CJK>
+0x4724	0x6266	# <CJK>
+0x4725	0x948E	# <CJK>
+0x4726	0x94C5	# <CJK>
+0x4727	0x5343	# <CJK>
+0x4728	0x8FC1	# <CJK>
+0x4729	0x7B7E	# <CJK>
+0x472A	0x4EDF	# <CJK>
+0x472B	0x8C26	# <CJK>
+0x472C	0x4E7E	# <CJK>
+0x472D	0x9ED4	# <CJK>
+0x472E	0x94B1	# <CJK>
+0x472F	0x94B3	# <CJK>
+0x4730	0x524D	# <CJK>
+0x4731	0x6F5C	# <CJK>
+0x4732	0x9063	# <CJK>
+0x4733	0x6D45	# <CJK>
+0x4734	0x8C34	# <CJK>
+0x4735	0x5811	# <CJK>
+0x4736	0x5D4C	# <CJK>
+0x4737	0x6B20	# <CJK>
+0x4738	0x6B49	# <CJK>
+0x4739	0x67AA	# <CJK>
+0x473A	0x545B	# <CJK>
+0x473B	0x8154	# <CJK>
+0x473C	0x7F8C	# <CJK>
+0x473D	0x5899	# <CJK>
+0x473E	0x8537	# <CJK>
+0x473F	0x5F3A	# <CJK>
+0x4740	0x62A2	# <CJK>
+0x4741	0x6A47	# <CJK>
+0x4742	0x9539	# <CJK>
+0x4743	0x6572	# <CJK>
+0x4744	0x6084	# <CJK>
+0x4745	0x6865	# <CJK>
+0x4746	0x77A7	# <CJK>
+0x4747	0x4E54	# <CJK>
+0x4748	0x4FA8	# <CJK>
+0x4749	0x5DE7	# <CJK>
+0x474A	0x9798	# <CJK>
+0x474B	0x64AC	# <CJK>
+0x474C	0x7FD8	# <CJK>
+0x474D	0x5CED	# <CJK>
+0x474E	0x4FCF	# <CJK>
+0x474F	0x7A8D	# <CJK>
+0x4750	0x5207	# <CJK>
+0x4751	0x8304	# <CJK>
+0x4752	0x4E14	# <CJK>
+0x4753	0x602F	# <CJK>
+0x4754	0x7A83	# <CJK>
+0x4755	0x94A6	# <CJK>
+0x4756	0x4FB5	# <CJK>
+0x4757	0x4EB2	# <CJK>
+0x4758	0x79E6	# <CJK>
+0x4759	0x7434	# <CJK>
+0x475A	0x52E4	# <CJK>
+0x475B	0x82B9	# <CJK>
+0x475C	0x64D2	# <CJK>
+0x475D	0x79BD	# <CJK>
+0x475E	0x5BDD	# <CJK>
+0x475F	0x6C81	# <CJK>
+0x4760	0x9752	# <CJK>
+0x4761	0x8F7B	# <CJK>
+0x4762	0x6C22	# <CJK>
+0x4763	0x503E	# <CJK>
+0x4764	0x537F	# <CJK>
+0x4765	0x6E05	# <CJK>
+0x4766	0x64CE	# <CJK>
+0x4767	0x6674	# <CJK>
+0x4768	0x6C30	# <CJK>
+0x4769	0x60C5	# <CJK>
+0x476A	0x9877	# <CJK>
+0x476B	0x8BF7	# <CJK>
+0x476C	0x5E86	# <CJK>
+0x476D	0x743C	# <CJK>
+0x476E	0x7A77	# <CJK>
+0x476F	0x79CB	# <CJK>
+0x4770	0x4E18	# <CJK>
+0x4771	0x90B1	# <CJK>
+0x4772	0x7403	# <CJK>
+0x4773	0x6C42	# <CJK>
+0x4774	0x56DA	# <CJK>
+0x4775	0x914B	# <CJK>
+0x4776	0x6CC5	# <CJK>
+0x4777	0x8D8B	# <CJK>
+0x4778	0x533A	# <CJK>
+0x4779	0x86C6	# <CJK>
+0x477A	0x66F2	# <CJK>
+0x477B	0x8EAF	# <CJK>
+0x477C	0x5C48	# <CJK>
+0x477D	0x9A71	# <CJK>
+0x477E	0x6E20	# <CJK>
+0x4821	0x53D6	# <CJK>
+0x4822	0x5A36	# <CJK>
+0x4823	0x9F8B	# <CJK>
+0x4824	0x8DA3	# <CJK>
+0x4825	0x53BB	# <CJK>
+0x4826	0x5708	# <CJK>
+0x4827	0x98A7	# <CJK>
+0x4828	0x6743	# <CJK>
+0x4829	0x919B	# <CJK>
+0x482A	0x6CC9	# <CJK>
+0x482B	0x5168	# <CJK>
+0x482C	0x75CA	# <CJK>
+0x482D	0x62F3	# <CJK>
+0x482E	0x72AC	# <CJK>
+0x482F	0x5238	# <CJK>
+0x4830	0x529D	# <CJK>
+0x4831	0x7F3A	# <CJK>
+0x4832	0x7094	# <CJK>
+0x4833	0x7638	# <CJK>
+0x4834	0x5374	# <CJK>
+0x4835	0x9E4A	# <CJK>
+0x4836	0x69B7	# <CJK>
+0x4837	0x786E	# <CJK>
+0x4838	0x96C0	# <CJK>
+0x4839	0x88D9	# <CJK>
+0x483A	0x7FA4	# <CJK>
+0x483B	0x7136	# <CJK>
+0x483C	0x71C3	# <CJK>
+0x483D	0x5189	# <CJK>
+0x483E	0x67D3	# <CJK>
+0x483F	0x74E4	# <CJK>
+0x4840	0x58E4	# <CJK>
+0x4841	0x6518	# <CJK>
+0x4842	0x56B7	# <CJK>
+0x4843	0x8BA9	# <CJK>
+0x4844	0x9976	# <CJK>
+0x4845	0x6270	# <CJK>
+0x4846	0x7ED5	# <CJK>
+0x4847	0x60F9	# <CJK>
+0x4848	0x70ED	# <CJK>
+0x4849	0x58EC	# <CJK>
+0x484A	0x4EC1	# <CJK>
+0x484B	0x4EBA	# <CJK>
+0x484C	0x5FCD	# <CJK>
+0x484D	0x97E7	# <CJK>
+0x484E	0x4EFB	# <CJK>
+0x484F	0x8BA4	# <CJK>
+0x4850	0x5203	# <CJK>
+0x4851	0x598A	# <CJK>
+0x4852	0x7EAB	# <CJK>
+0x4853	0x6254	# <CJK>
+0x4854	0x4ECD	# <CJK>
+0x4855	0x65E5	# <CJK>
+0x4856	0x620E	# <CJK>
+0x4857	0x8338	# <CJK>
+0x4858	0x84C9	# <CJK>
+0x4859	0x8363	# <CJK>
+0x485A	0x878D	# <CJK>
+0x485B	0x7194	# <CJK>
+0x485C	0x6EB6	# <CJK>
+0x485D	0x5BB9	# <CJK>
+0x485E	0x7ED2	# <CJK>
+0x485F	0x5197	# <CJK>
+0x4860	0x63C9	# <CJK>
+0x4861	0x67D4	# <CJK>
+0x4862	0x8089	# <CJK>
+0x4863	0x8339	# <CJK>
+0x4864	0x8815	# <CJK>
+0x4865	0x5112	# <CJK>
+0x4866	0x5B7A	# <CJK>
+0x4867	0x5982	# <CJK>
+0x4868	0x8FB1	# <CJK>
+0x4869	0x4E73	# <CJK>
+0x486A	0x6C5D	# <CJK>
+0x486B	0x5165	# <CJK>
+0x486C	0x8925	# <CJK>
+0x486D	0x8F6F	# <CJK>
+0x486E	0x962E	# <CJK>
+0x486F	0x854A	# <CJK>
+0x4870	0x745E	# <CJK>
+0x4871	0x9510	# <CJK>
+0x4872	0x95F0	# <CJK>
+0x4873	0x6DA6	# <CJK>
+0x4874	0x82E5	# <CJK>
+0x4875	0x5F31	# <CJK>
+0x4876	0x6492	# <CJK>
+0x4877	0x6D12	# <CJK>
+0x4878	0x8428	# <CJK>
+0x4879	0x816E	# <CJK>
+0x487A	0x9CC3	# <CJK>
+0x487B	0x585E	# <CJK>
+0x487C	0x8D5B	# <CJK>
+0x487D	0x4E09	# <CJK>
+0x487E	0x53C1	# <CJK>
+0x4921	0x4F1E	# <CJK>
+0x4922	0x6563	# <CJK>
+0x4923	0x6851	# <CJK>
+0x4924	0x55D3	# <CJK>
+0x4925	0x4E27	# <CJK>
+0x4926	0x6414	# <CJK>
+0x4927	0x9A9A	# <CJK>
+0x4928	0x626B	# <CJK>
+0x4929	0x5AC2	# <CJK>
+0x492A	0x745F	# <CJK>
+0x492B	0x8272	# <CJK>
+0x492C	0x6DA9	# <CJK>
+0x492D	0x68EE	# <CJK>
+0x492E	0x50E7	# <CJK>
+0x492F	0x838E	# <CJK>
+0x4930	0x7802	# <CJK>
+0x4931	0x6740	# <CJK>
+0x4932	0x5239	# <CJK>
+0x4933	0x6C99	# <CJK>
+0x4934	0x7EB1	# <CJK>
+0x4935	0x50BB	# <CJK>
+0x4936	0x5565	# <CJK>
+0x4937	0x715E	# <CJK>
+0x4938	0x7B5B	# <CJK>
+0x4939	0x6652	# <CJK>
+0x493A	0x73CA	# <CJK>
+0x493B	0x82EB	# <CJK>
+0x493C	0x6749	# <CJK>
+0x493D	0x5C71	# <CJK>
+0x493E	0x5220	# <CJK>
+0x493F	0x717D	# <CJK>
+0x4940	0x886B	# <CJK>
+0x4941	0x95EA	# <CJK>
+0x4942	0x9655	# <CJK>
+0x4943	0x64C5	# <CJK>
+0x4944	0x8D61	# <CJK>
+0x4945	0x81B3	# <CJK>
+0x4946	0x5584	# <CJK>
+0x4947	0x6C55	# <CJK>
+0x4948	0x6247	# <CJK>
+0x4949	0x7F2E	# <CJK>
+0x494A	0x5892	# <CJK>
+0x494B	0x4F24	# <CJK>
+0x494C	0x5546	# <CJK>
+0x494D	0x8D4F	# <CJK>
+0x494E	0x664C	# <CJK>
+0x494F	0x4E0A	# <CJK>
+0x4950	0x5C1A	# <CJK>
+0x4951	0x88F3	# <CJK>
+0x4952	0x68A2	# <CJK>
+0x4953	0x634E	# <CJK>
+0x4954	0x7A0D	# <CJK>
+0x4955	0x70E7	# <CJK>
+0x4956	0x828D	# <CJK>
+0x4957	0x52FA	# <CJK>
+0x4958	0x97F6	# <CJK>
+0x4959	0x5C11	# <CJK>
+0x495A	0x54E8	# <CJK>
+0x495B	0x90B5	# <CJK>
+0x495C	0x7ECD	# <CJK>
+0x495D	0x5962	# <CJK>
+0x495E	0x8D4A	# <CJK>
+0x495F	0x86C7	# <CJK>
+0x4960	0x820C	# <CJK>
+0x4961	0x820D	# <CJK>
+0x4962	0x8D66	# <CJK>
+0x4963	0x6444	# <CJK>
+0x4964	0x5C04	# <CJK>
+0x4965	0x6151	# <CJK>
+0x4966	0x6D89	# <CJK>
+0x4967	0x793E	# <CJK>
+0x4968	0x8BBE	# <CJK>
+0x4969	0x7837	# <CJK>
+0x496A	0x7533	# <CJK>
+0x496B	0x547B	# <CJK>
+0x496C	0x4F38	# <CJK>
+0x496D	0x8EAB	# <CJK>
+0x496E	0x6DF1	# <CJK>
+0x496F	0x5A20	# <CJK>
+0x4970	0x7EC5	# <CJK>
+0x4971	0x795E	# <CJK>
+0x4972	0x6C88	# <CJK>
+0x4973	0x5BA1	# <CJK>
+0x4974	0x5A76	# <CJK>
+0x4975	0x751A	# <CJK>
+0x4976	0x80BE	# <CJK>
+0x4977	0x614E	# <CJK>
+0x4978	0x6E17	# <CJK>
+0x4979	0x58F0	# <CJK>
+0x497A	0x751F	# <CJK>
+0x497B	0x7525	# <CJK>
+0x497C	0x7272	# <CJK>
+0x497D	0x5347	# <CJK>
+0x497E	0x7EF3	# <CJK>
+0x4A21	0x7701	# <CJK>
+0x4A22	0x76DB	# <CJK>
+0x4A23	0x5269	# <CJK>
+0x4A24	0x80DC	# <CJK>
+0x4A25	0x5723	# <CJK>
+0x4A26	0x5E08	# <CJK>
+0x4A27	0x5931	# <CJK>
+0x4A28	0x72EE	# <CJK>
+0x4A29	0x65BD	# <CJK>
+0x4A2A	0x6E7F	# <CJK>
+0x4A2B	0x8BD7	# <CJK>
+0x4A2C	0x5C38	# <CJK>
+0x4A2D	0x8671	# <CJK>
+0x4A2E	0x5341	# <CJK>
+0x4A2F	0x77F3	# <CJK>
+0x4A30	0x62FE	# <CJK>
+0x4A31	0x65F6	# <CJK>
+0x4A32	0x4EC0	# <CJK>
+0x4A33	0x98DF	# <CJK>
+0x4A34	0x8680	# <CJK>
+0x4A35	0x5B9E	# <CJK>
+0x4A36	0x8BC6	# <CJK>
+0x4A37	0x53F2	# <CJK>
+0x4A38	0x77E2	# <CJK>
+0x4A39	0x4F7F	# <CJK>
+0x4A3A	0x5C4E	# <CJK>
+0x4A3B	0x9A76	# <CJK>
+0x4A3C	0x59CB	# <CJK>
+0x4A3D	0x5F0F	# <CJK>
+0x4A3E	0x793A	# <CJK>
+0x4A3F	0x58EB	# <CJK>
+0x4A40	0x4E16	# <CJK>
+0x4A41	0x67FF	# <CJK>
+0x4A42	0x4E8B	# <CJK>
+0x4A43	0x62ED	# <CJK>
+0x4A44	0x8A93	# <CJK>
+0x4A45	0x901D	# <CJK>
+0x4A46	0x52BF	# <CJK>
+0x4A47	0x662F	# <CJK>
+0x4A48	0x55DC	# <CJK>
+0x4A49	0x566C	# <CJK>
+0x4A4A	0x9002	# <CJK>
+0x4A4B	0x4ED5	# <CJK>
+0x4A4C	0x4F8D	# <CJK>
+0x4A4D	0x91CA	# <CJK>
+0x4A4E	0x9970	# <CJK>
+0x4A4F	0x6C0F	# <CJK>
+0x4A50	0x5E02	# <CJK>
+0x4A51	0x6043	# <CJK>
+0x4A52	0x5BA4	# <CJK>
+0x4A53	0x89C6	# <CJK>
+0x4A54	0x8BD5	# <CJK>
+0x4A55	0x6536	# <CJK>
+0x4A56	0x624B	# <CJK>
+0x4A57	0x9996	# <CJK>
+0x4A58	0x5B88	# <CJK>
+0x4A59	0x5BFF	# <CJK>
+0x4A5A	0x6388	# <CJK>
+0x4A5B	0x552E	# <CJK>
+0x4A5C	0x53D7	# <CJK>
+0x4A5D	0x7626	# <CJK>
+0x4A5E	0x517D	# <CJK>
+0x4A5F	0x852C	# <CJK>
+0x4A60	0x67A2	# <CJK>
+0x4A61	0x68B3	# <CJK>
+0x4A62	0x6B8A	# <CJK>
+0x4A63	0x6292	# <CJK>
+0x4A64	0x8F93	# <CJK>
+0x4A65	0x53D4	# <CJK>
+0x4A66	0x8212	# <CJK>
+0x4A67	0x6DD1	# <CJK>
+0x4A68	0x758F	# <CJK>
+0x4A69	0x4E66	# <CJK>
+0x4A6A	0x8D4E	# <CJK>
+0x4A6B	0x5B70	# <CJK>
+0x4A6C	0x719F	# <CJK>
+0x4A6D	0x85AF	# <CJK>
+0x4A6E	0x6691	# <CJK>
+0x4A6F	0x66D9	# <CJK>
+0x4A70	0x7F72	# <CJK>
+0x4A71	0x8700	# <CJK>
+0x4A72	0x9ECD	# <CJK>
+0x4A73	0x9F20	# <CJK>
+0x4A74	0x5C5E	# <CJK>
+0x4A75	0x672F	# <CJK>
+0x4A76	0x8FF0	# <CJK>
+0x4A77	0x6811	# <CJK>
+0x4A78	0x675F	# <CJK>
+0x4A79	0x620D	# <CJK>
+0x4A7A	0x7AD6	# <CJK>
+0x4A7B	0x5885	# <CJK>
+0x4A7C	0x5EB6	# <CJK>
+0x4A7D	0x6570	# <CJK>
+0x4A7E	0x6F31	# <CJK>
+0x4B21	0x6055	# <CJK>
+0x4B22	0x5237	# <CJK>
+0x4B23	0x800D	# <CJK>
+0x4B24	0x6454	# <CJK>
+0x4B25	0x8870	# <CJK>
+0x4B26	0x7529	# <CJK>
+0x4B27	0x5E05	# <CJK>
+0x4B28	0x6813	# <CJK>
+0x4B29	0x62F4	# <CJK>
+0x4B2A	0x971C	# <CJK>
+0x4B2B	0x53CC	# <CJK>
+0x4B2C	0x723D	# <CJK>
+0x4B2D	0x8C01	# <CJK>
+0x4B2E	0x6C34	# <CJK>
+0x4B2F	0x7761	# <CJK>
+0x4B30	0x7A0E	# <CJK>
+0x4B31	0x542E	# <CJK>
+0x4B32	0x77AC	# <CJK>
+0x4B33	0x987A	# <CJK>
+0x4B34	0x821C	# <CJK>
+0x4B35	0x8BF4	# <CJK>
+0x4B36	0x7855	# <CJK>
+0x4B37	0x6714	# <CJK>
+0x4B38	0x70C1	# <CJK>
+0x4B39	0x65AF	# <CJK>
+0x4B3A	0x6495	# <CJK>
+0x4B3B	0x5636	# <CJK>
+0x4B3C	0x601D	# <CJK>
+0x4B3D	0x79C1	# <CJK>
+0x4B3E	0x53F8	# <CJK>
+0x4B3F	0x4E1D	# <CJK>
+0x4B40	0x6B7B	# <CJK>
+0x4B41	0x8086	# <CJK>
+0x4B42	0x5BFA	# <CJK>
+0x4B43	0x55E3	# <CJK>
+0x4B44	0x56DB	# <CJK>
+0x4B45	0x4F3A	# <CJK>
+0x4B46	0x4F3C	# <CJK>
+0x4B47	0x9972	# <CJK>
+0x4B48	0x5DF3	# <CJK>
+0x4B49	0x677E	# <CJK>
+0x4B4A	0x8038	# <CJK>
+0x4B4B	0x6002	# <CJK>
+0x4B4C	0x9882	# <CJK>
+0x4B4D	0x9001	# <CJK>
+0x4B4E	0x5B8B	# <CJK>
+0x4B4F	0x8BBC	# <CJK>
+0x4B50	0x8BF5	# <CJK>
+0x4B51	0x641C	# <CJK>
+0x4B52	0x8258	# <CJK>
+0x4B53	0x64DE	# <CJK>
+0x4B54	0x55FD	# <CJK>
+0x4B55	0x82CF	# <CJK>
+0x4B56	0x9165	# <CJK>
+0x4B57	0x4FD7	# <CJK>
+0x4B58	0x7D20	# <CJK>
+0x4B59	0x901F	# <CJK>
+0x4B5A	0x7C9F	# <CJK>
+0x4B5B	0x50F3	# <CJK>
+0x4B5C	0x5851	# <CJK>
+0x4B5D	0x6EAF	# <CJK>
+0x4B5E	0x5BBF	# <CJK>
+0x4B5F	0x8BC9	# <CJK>
+0x4B60	0x8083	# <CJK>
+0x4B61	0x9178	# <CJK>
+0x4B62	0x849C	# <CJK>
+0x4B63	0x7B97	# <CJK>
+0x4B64	0x867D	# <CJK>
+0x4B65	0x968B	# <CJK>
+0x4B66	0x968F	# <CJK>
+0x4B67	0x7EE5	# <CJK>
+0x4B68	0x9AD3	# <CJK>
+0x4B69	0x788E	# <CJK>
+0x4B6A	0x5C81	# <CJK>
+0x4B6B	0x7A57	# <CJK>
+0x4B6C	0x9042	# <CJK>
+0x4B6D	0x96A7	# <CJK>
+0x4B6E	0x795F	# <CJK>
+0x4B6F	0x5B59	# <CJK>
+0x4B70	0x635F	# <CJK>
+0x4B71	0x7B0B	# <CJK>
+0x4B72	0x84D1	# <CJK>
+0x4B73	0x68AD	# <CJK>
+0x4B74	0x5506	# <CJK>
+0x4B75	0x7F29	# <CJK>
+0x4B76	0x7410	# <CJK>
+0x4B77	0x7D22	# <CJK>
+0x4B78	0x9501	# <CJK>
+0x4B79	0x6240	# <CJK>
+0x4B7A	0x584C	# <CJK>
+0x4B7B	0x4ED6	# <CJK>
+0x4B7C	0x5B83	# <CJK>
+0x4B7D	0x5979	# <CJK>
+0x4B7E	0x5854	# <CJK>
+0x4C21	0x736D	# <CJK>
+0x4C22	0x631E	# <CJK>
+0x4C23	0x8E4B	# <CJK>
+0x4C24	0x8E0F	# <CJK>
+0x4C25	0x80CE	# <CJK>
+0x4C26	0x82D4	# <CJK>
+0x4C27	0x62AC	# <CJK>
+0x4C28	0x53F0	# <CJK>
+0x4C29	0x6CF0	# <CJK>
+0x4C2A	0x915E	# <CJK>
+0x4C2B	0x592A	# <CJK>
+0x4C2C	0x6001	# <CJK>
+0x4C2D	0x6C70	# <CJK>
+0x4C2E	0x574D	# <CJK>
+0x4C2F	0x644A	# <CJK>
+0x4C30	0x8D2A	# <CJK>
+0x4C31	0x762B	# <CJK>
+0x4C32	0x6EE9	# <CJK>
+0x4C33	0x575B	# <CJK>
+0x4C34	0x6A80	# <CJK>
+0x4C35	0x75F0	# <CJK>
+0x4C36	0x6F6D	# <CJK>
+0x4C37	0x8C2D	# <CJK>
+0x4C38	0x8C08	# <CJK>
+0x4C39	0x5766	# <CJK>
+0x4C3A	0x6BEF	# <CJK>
+0x4C3B	0x8892	# <CJK>
+0x4C3C	0x78B3	# <CJK>
+0x4C3D	0x63A2	# <CJK>
+0x4C3E	0x53F9	# <CJK>
+0x4C3F	0x70AD	# <CJK>
+0x4C40	0x6C64	# <CJK>
+0x4C41	0x5858	# <CJK>
+0x4C42	0x642A	# <CJK>
+0x4C43	0x5802	# <CJK>
+0x4C44	0x68E0	# <CJK>
+0x4C45	0x819B	# <CJK>
+0x4C46	0x5510	# <CJK>
+0x4C47	0x7CD6	# <CJK>
+0x4C48	0x5018	# <CJK>
+0x4C49	0x8EBA	# <CJK>
+0x4C4A	0x6DCC	# <CJK>
+0x4C4B	0x8D9F	# <CJK>
+0x4C4C	0x70EB	# <CJK>
+0x4C4D	0x638F	# <CJK>
+0x4C4E	0x6D9B	# <CJK>
+0x4C4F	0x6ED4	# <CJK>
+0x4C50	0x7EE6	# <CJK>
+0x4C51	0x8404	# <CJK>
+0x4C52	0x6843	# <CJK>
+0x4C53	0x9003	# <CJK>
+0x4C54	0x6DD8	# <CJK>
+0x4C55	0x9676	# <CJK>
+0x4C56	0x8BA8	# <CJK>
+0x4C57	0x5957	# <CJK>
+0x4C58	0x7279	# <CJK>
+0x4C59	0x85E4	# <CJK>
+0x4C5A	0x817E	# <CJK>
+0x4C5B	0x75BC	# <CJK>
+0x4C5C	0x8A8A	# <CJK>
+0x4C5D	0x68AF	# <CJK>
+0x4C5E	0x5254	# <CJK>
+0x4C5F	0x8E22	# <CJK>
+0x4C60	0x9511	# <CJK>
+0x4C61	0x63D0	# <CJK>
+0x4C62	0x9898	# <CJK>
+0x4C63	0x8E44	# <CJK>
+0x4C64	0x557C	# <CJK>
+0x4C65	0x4F53	# <CJK>
+0x4C66	0x66FF	# <CJK>
+0x4C67	0x568F	# <CJK>
+0x4C68	0x60D5	# <CJK>
+0x4C69	0x6D95	# <CJK>
+0x4C6A	0x5243	# <CJK>
+0x4C6B	0x5C49	# <CJK>
+0x4C6C	0x5929	# <CJK>
+0x4C6D	0x6DFB	# <CJK>
+0x4C6E	0x586B	# <CJK>
+0x4C6F	0x7530	# <CJK>
+0x4C70	0x751C	# <CJK>
+0x4C71	0x606C	# <CJK>
+0x4C72	0x8214	# <CJK>
+0x4C73	0x8146	# <CJK>
+0x4C74	0x6311	# <CJK>
+0x4C75	0x6761	# <CJK>
+0x4C76	0x8FE2	# <CJK>
+0x4C77	0x773A	# <CJK>
+0x4C78	0x8DF3	# <CJK>
+0x4C79	0x8D34	# <CJK>
+0x4C7A	0x94C1	# <CJK>
+0x4C7B	0x5E16	# <CJK>
+0x4C7C	0x5385	# <CJK>
+0x4C7D	0x542C	# <CJK>
+0x4C7E	0x70C3	# <CJK>
+0x4D21	0x6C40	# <CJK>
+0x4D22	0x5EF7	# <CJK>
+0x4D23	0x505C	# <CJK>
+0x4D24	0x4EAD	# <CJK>
+0x4D25	0x5EAD	# <CJK>
+0x4D26	0x633A	# <CJK>
+0x4D27	0x8247	# <CJK>
+0x4D28	0x901A	# <CJK>
+0x4D29	0x6850	# <CJK>
+0x4D2A	0x916E	# <CJK>
+0x4D2B	0x77B3	# <CJK>
+0x4D2C	0x540C	# <CJK>
+0x4D2D	0x94DC	# <CJK>
+0x4D2E	0x5F64	# <CJK>
+0x4D2F	0x7AE5	# <CJK>
+0x4D30	0x6876	# <CJK>
+0x4D31	0x6345	# <CJK>
+0x4D32	0x7B52	# <CJK>
+0x4D33	0x7EDF	# <CJK>
+0x4D34	0x75DB	# <CJK>
+0x4D35	0x5077	# <CJK>
+0x4D36	0x6295	# <CJK>
+0x4D37	0x5934	# <CJK>
+0x4D38	0x900F	# <CJK>
+0x4D39	0x51F8	# <CJK>
+0x4D3A	0x79C3	# <CJK>
+0x4D3B	0x7A81	# <CJK>
+0x4D3C	0x56FE	# <CJK>
+0x4D3D	0x5F92	# <CJK>
+0x4D3E	0x9014	# <CJK>
+0x4D3F	0x6D82	# <CJK>
+0x4D40	0x5C60	# <CJK>
+0x4D41	0x571F	# <CJK>
+0x4D42	0x5410	# <CJK>
+0x4D43	0x5154	# <CJK>
+0x4D44	0x6E4D	# <CJK>
+0x4D45	0x56E2	# <CJK>
+0x4D46	0x63A8	# <CJK>
+0x4D47	0x9893	# <CJK>
+0x4D48	0x817F	# <CJK>
+0x4D49	0x8715	# <CJK>
+0x4D4A	0x892A	# <CJK>
+0x4D4B	0x9000	# <CJK>
+0x4D4C	0x541E	# <CJK>
+0x4D4D	0x5C6F	# <CJK>
+0x4D4E	0x81C0	# <CJK>
+0x4D4F	0x62D6	# <CJK>
+0x4D50	0x6258	# <CJK>
+0x4D51	0x8131	# <CJK>
+0x4D52	0x9E35	# <CJK>
+0x4D53	0x9640	# <CJK>
+0x4D54	0x9A6E	# <CJK>
+0x4D55	0x9A7C	# <CJK>
+0x4D56	0x692D	# <CJK>
+0x4D57	0x59A5	# <CJK>
+0x4D58	0x62D3	# <CJK>
+0x4D59	0x553E	# <CJK>
+0x4D5A	0x6316	# <CJK>
+0x4D5B	0x54C7	# <CJK>
+0x4D5C	0x86D9	# <CJK>
+0x4D5D	0x6D3C	# <CJK>
+0x4D5E	0x5A03	# <CJK>
+0x4D5F	0x74E6	# <CJK>
+0x4D60	0x889C	# <CJK>
+0x4D61	0x6B6A	# <CJK>
+0x4D62	0x5916	# <CJK>
+0x4D63	0x8C4C	# <CJK>
+0x4D64	0x5F2F	# <CJK>
+0x4D65	0x6E7E	# <CJK>
+0x4D66	0x73A9	# <CJK>
+0x4D67	0x987D	# <CJK>
+0x4D68	0x4E38	# <CJK>
+0x4D69	0x70F7	# <CJK>
+0x4D6A	0x5B8C	# <CJK>
+0x4D6B	0x7897	# <CJK>
+0x4D6C	0x633D	# <CJK>
+0x4D6D	0x665A	# <CJK>
+0x4D6E	0x7696	# <CJK>
+0x4D6F	0x60CB	# <CJK>
+0x4D70	0x5B9B	# <CJK>
+0x4D71	0x5A49	# <CJK>
+0x4D72	0x4E07	# <CJK>
+0x4D73	0x8155	# <CJK>
+0x4D74	0x6C6A	# <CJK>
+0x4D75	0x738B	# <CJK>
+0x4D76	0x4EA1	# <CJK>
+0x4D77	0x6789	# <CJK>
+0x4D78	0x7F51	# <CJK>
+0x4D79	0x5F80	# <CJK>
+0x4D7A	0x65FA	# <CJK>
+0x4D7B	0x671B	# <CJK>
+0x4D7C	0x5FD8	# <CJK>
+0x4D7D	0x5984	# <CJK>
+0x4D7E	0x5A01	# <CJK>
+0x4E21	0x5DCD	# <CJK>
+0x4E22	0x5FAE	# <CJK>
+0x4E23	0x5371	# <CJK>
+0x4E24	0x97E6	# <CJK>
+0x4E25	0x8FDD	# <CJK>
+0x4E26	0x6845	# <CJK>
+0x4E27	0x56F4	# <CJK>
+0x4E28	0x552F	# <CJK>
+0x4E29	0x60DF	# <CJK>
+0x4E2A	0x4E3A	# <CJK>
+0x4E2B	0x6F4D	# <CJK>
+0x4E2C	0x7EF4	# <CJK>
+0x4E2D	0x82C7	# <CJK>
+0x4E2E	0x840E	# <CJK>
+0x4E2F	0x59D4	# <CJK>
+0x4E30	0x4F1F	# <CJK>
+0x4E31	0x4F2A	# <CJK>
+0x4E32	0x5C3E	# <CJK>
+0x4E33	0x7EAC	# <CJK>
+0x4E34	0x672A	# <CJK>
+0x4E35	0x851A	# <CJK>
+0x4E36	0x5473	# <CJK>
+0x4E37	0x754F	# <CJK>
+0x4E38	0x80C3	# <CJK>
+0x4E39	0x5582	# <CJK>
+0x4E3A	0x9B4F	# <CJK>
+0x4E3B	0x4F4D	# <CJK>
+0x4E3C	0x6E2D	# <CJK>
+0x4E3D	0x8C13	# <CJK>
+0x4E3E	0x5C09	# <CJK>
+0x4E3F	0x6170	# <CJK>
+0x4E40	0x536B	# <CJK>
+0x4E41	0x761F	# <CJK>
+0x4E42	0x6E29	# <CJK>
+0x4E43	0x868A	# <CJK>
+0x4E44	0x6587	# <CJK>
+0x4E45	0x95FB	# <CJK>
+0x4E46	0x7EB9	# <CJK>
+0x4E47	0x543B	# <CJK>
+0x4E48	0x7A33	# <CJK>
+0x4E49	0x7D0A	# <CJK>
+0x4E4A	0x95EE	# <CJK>
+0x4E4B	0x55E1	# <CJK>
+0x4E4C	0x7FC1	# <CJK>
+0x4E4D	0x74EE	# <CJK>
+0x4E4E	0x631D	# <CJK>
+0x4E4F	0x8717	# <CJK>
+0x4E50	0x6DA1	# <CJK>
+0x4E51	0x7A9D	# <CJK>
+0x4E52	0x6211	# <CJK>
+0x4E53	0x65A1	# <CJK>
+0x4E54	0x5367	# <CJK>
+0x4E55	0x63E1	# <CJK>
+0x4E56	0x6C83	# <CJK>
+0x4E57	0x5DEB	# <CJK>
+0x4E58	0x545C	# <CJK>
+0x4E59	0x94A8	# <CJK>
+0x4E5A	0x4E4C	# <CJK>
+0x4E5B	0x6C61	# <CJK>
+0x4E5C	0x8BEC	# <CJK>
+0x4E5D	0x5C4B	# <CJK>
+0x4E5E	0x65E0	# <CJK>
+0x4E5F	0x829C	# <CJK>
+0x4E60	0x68A7	# <CJK>
+0x4E61	0x543E	# <CJK>
+0x4E62	0x5434	# <CJK>
+0x4E63	0x6BCB	# <CJK>
+0x4E64	0x6B66	# <CJK>
+0x4E65	0x4E94	# <CJK>
+0x4E66	0x6342	# <CJK>
+0x4E67	0x5348	# <CJK>
+0x4E68	0x821E	# <CJK>
+0x4E69	0x4F0D	# <CJK>
+0x4E6A	0x4FAE	# <CJK>
+0x4E6B	0x575E	# <CJK>
+0x4E6C	0x620A	# <CJK>
+0x4E6D	0x96FE	# <CJK>
+0x4E6E	0x6664	# <CJK>
+0x4E6F	0x7269	# <CJK>
+0x4E70	0x52FF	# <CJK>
+0x4E71	0x52A1	# <CJK>
+0x4E72	0x609F	# <CJK>
+0x4E73	0x8BEF	# <CJK>
+0x4E74	0x6614	# <CJK>
+0x4E75	0x7199	# <CJK>
+0x4E76	0x6790	# <CJK>
+0x4E77	0x897F	# <CJK>
+0x4E78	0x7852	# <CJK>
+0x4E79	0x77FD	# <CJK>
+0x4E7A	0x6670	# <CJK>
+0x4E7B	0x563B	# <CJK>
+0x4E7C	0x5438	# <CJK>
+0x4E7D	0x9521	# <CJK>
+0x4E7E	0x727A	# <CJK>
+0x4F21	0x7A00	# <CJK>
+0x4F22	0x606F	# <CJK>
+0x4F23	0x5E0C	# <CJK>
+0x4F24	0x6089	# <CJK>
+0x4F25	0x819D	# <CJK>
+0x4F26	0x5915	# <CJK>
+0x4F27	0x60DC	# <CJK>
+0x4F28	0x7184	# <CJK>
+0x4F29	0x70EF	# <CJK>
+0x4F2A	0x6EAA	# <CJK>
+0x4F2B	0x6C50	# <CJK>
+0x4F2C	0x7280	# <CJK>
+0x4F2D	0x6A84	# <CJK>
+0x4F2E	0x88AD	# <CJK>
+0x4F2F	0x5E2D	# <CJK>
+0x4F30	0x4E60	# <CJK>
+0x4F31	0x5AB3	# <CJK>
+0x4F32	0x559C	# <CJK>
+0x4F33	0x94E3	# <CJK>
+0x4F34	0x6D17	# <CJK>
+0x4F35	0x7CFB	# <CJK>
+0x4F36	0x9699	# <CJK>
+0x4F37	0x620F	# <CJK>
+0x4F38	0x7EC6	# <CJK>
+0x4F39	0x778E	# <CJK>
+0x4F3A	0x867E	# <CJK>
+0x4F3B	0x5323	# <CJK>
+0x4F3C	0x971E	# <CJK>
+0x4F3D	0x8F96	# <CJK>
+0x4F3E	0x6687	# <CJK>
+0x4F3F	0x5CE1	# <CJK>
+0x4F40	0x4FA0	# <CJK>
+0x4F41	0x72ED	# <CJK>
+0x4F42	0x4E0B	# <CJK>
+0x4F43	0x53A6	# <CJK>
+0x4F44	0x590F	# <CJK>
+0x4F45	0x5413	# <CJK>
+0x4F46	0x6380	# <CJK>
+0x4F47	0x9528	# <CJK>
+0x4F48	0x5148	# <CJK>
+0x4F49	0x4ED9	# <CJK>
+0x4F4A	0x9C9C	# <CJK>
+0x4F4B	0x7EA4	# <CJK>
+0x4F4C	0x54B8	# <CJK>
+0x4F4D	0x8D24	# <CJK>
+0x4F4E	0x8854	# <CJK>
+0x4F4F	0x8237	# <CJK>
+0x4F50	0x95F2	# <CJK>
+0x4F51	0x6D8E	# <CJK>
+0x4F52	0x5F26	# <CJK>
+0x4F53	0x5ACC	# <CJK>
+0x4F54	0x663E	# <CJK>
+0x4F55	0x9669	# <CJK>
+0x4F56	0x73B0	# <CJK>
+0x4F57	0x732E	# <CJK>
+0x4F58	0x53BF	# <CJK>
+0x4F59	0x817A	# <CJK>
+0x4F5A	0x9985	# <CJK>
+0x4F5B	0x7FA1	# <CJK>
+0x4F5C	0x5BAA	# <CJK>
+0x4F5D	0x9677	# <CJK>
+0x4F5E	0x9650	# <CJK>
+0x4F5F	0x7EBF	# <CJK>
+0x4F60	0x76F8	# <CJK>
+0x4F61	0x53A2	# <CJK>
+0x4F62	0x9576	# <CJK>
+0x4F63	0x9999	# <CJK>
+0x4F64	0x7BB1	# <CJK>
+0x4F65	0x8944	# <CJK>
+0x4F66	0x6E58	# <CJK>
+0x4F67	0x4E61	# <CJK>
+0x4F68	0x7FD4	# <CJK>
+0x4F69	0x7965	# <CJK>
+0x4F6A	0x8BE6	# <CJK>
+0x4F6B	0x60F3	# <CJK>
+0x4F6C	0x54CD	# <CJK>
+0x4F6D	0x4EAB	# <CJK>
+0x4F6E	0x9879	# <CJK>
+0x4F6F	0x5DF7	# <CJK>
+0x4F70	0x6A61	# <CJK>
+0x4F71	0x50CF	# <CJK>
+0x4F72	0x5411	# <CJK>
+0x4F73	0x8C61	# <CJK>
+0x4F74	0x8427	# <CJK>
+0x4F75	0x785D	# <CJK>
+0x4F76	0x9704	# <CJK>
+0x4F77	0x524A	# <CJK>
+0x4F78	0x54EE	# <CJK>
+0x4F79	0x56A3	# <CJK>
+0x4F7A	0x9500	# <CJK>
+0x4F7B	0x6D88	# <CJK>
+0x4F7C	0x5BB5	# <CJK>
+0x4F7D	0x6DC6	# <CJK>
+0x4F7E	0x6653	# <CJK>
+0x5021	0x5C0F	# <CJK>
+0x5022	0x5B5D	# <CJK>
+0x5023	0x6821	# <CJK>
+0x5024	0x8096	# <CJK>
+0x5025	0x5578	# <CJK>
+0x5026	0x7B11	# <CJK>
+0x5027	0x6548	# <CJK>
+0x5028	0x6954	# <CJK>
+0x5029	0x4E9B	# <CJK>
+0x502A	0x6B47	# <CJK>
+0x502B	0x874E	# <CJK>
+0x502C	0x978B	# <CJK>
+0x502D	0x534F	# <CJK>
+0x502E	0x631F	# <CJK>
+0x502F	0x643A	# <CJK>
+0x5030	0x90AA	# <CJK>
+0x5031	0x659C	# <CJK>
+0x5032	0x80C1	# <CJK>
+0x5033	0x8C10	# <CJK>
+0x5034	0x5199	# <CJK>
+0x5035	0x68B0	# <CJK>
+0x5036	0x5378	# <CJK>
+0x5037	0x87F9	# <CJK>
+0x5038	0x61C8	# <CJK>
+0x5039	0x6CC4	# <CJK>
+0x503A	0x6CFB	# <CJK>
+0x503B	0x8C22	# <CJK>
+0x503C	0x5C51	# <CJK>
+0x503D	0x85AA	# <CJK>
+0x503E	0x82AF	# <CJK>
+0x503F	0x950C	# <CJK>
+0x5040	0x6B23	# <CJK>
+0x5041	0x8F9B	# <CJK>
+0x5042	0x65B0	# <CJK>
+0x5043	0x5FFB	# <CJK>
+0x5044	0x5FC3	# <CJK>
+0x5045	0x4FE1	# <CJK>
+0x5046	0x8845	# <CJK>
+0x5047	0x661F	# <CJK>
+0x5048	0x8165	# <CJK>
+0x5049	0x7329	# <CJK>
+0x504A	0x60FA	# <CJK>
+0x504B	0x5174	# <CJK>
+0x504C	0x5211	# <CJK>
+0x504D	0x578B	# <CJK>
+0x504E	0x5F62	# <CJK>
+0x504F	0x90A2	# <CJK>
+0x5050	0x884C	# <CJK>
+0x5051	0x9192	# <CJK>
+0x5052	0x5E78	# <CJK>
+0x5053	0x674F	# <CJK>
+0x5054	0x6027	# <CJK>
+0x5055	0x59D3	# <CJK>
+0x5056	0x5144	# <CJK>
+0x5057	0x51F6	# <CJK>
+0x5058	0x80F8	# <CJK>
+0x5059	0x5308	# <CJK>
+0x505A	0x6C79	# <CJK>
+0x505B	0x96C4	# <CJK>
+0x505C	0x718A	# <CJK>
+0x505D	0x4F11	# <CJK>
+0x505E	0x4FEE	# <CJK>
+0x505F	0x7F9E	# <CJK>
+0x5060	0x673D	# <CJK>
+0x5061	0x55C5	# <CJK>
+0x5062	0x9508	# <CJK>
+0x5063	0x79C0	# <CJK>
+0x5064	0x8896	# <CJK>
+0x5065	0x7EE3	# <CJK>
+0x5066	0x589F	# <CJK>
+0x5067	0x620C	# <CJK>
+0x5068	0x9700	# <CJK>
+0x5069	0x865A	# <CJK>
+0x506A	0x5618	# <CJK>
+0x506B	0x987B	# <CJK>
+0x506C	0x5F90	# <CJK>
+0x506D	0x8BB8	# <CJK>
+0x506E	0x84C4	# <CJK>
+0x506F	0x9157	# <CJK>
+0x5070	0x53D9	# <CJK>
+0x5071	0x65ED	# <CJK>
+0x5072	0x5E8F	# <CJK>
+0x5073	0x755C	# <CJK>
+0x5074	0x6064	# <CJK>
+0x5075	0x7D6E	# <CJK>
+0x5076	0x5A7F	# <CJK>
+0x5077	0x7EEA	# <CJK>
+0x5078	0x7EED	# <CJK>
+0x5079	0x8F69	# <CJK>
+0x507A	0x55A7	# <CJK>
+0x507B	0x5BA3	# <CJK>
+0x507C	0x60AC	# <CJK>
+0x507D	0x65CB	# <CJK>
+0x507E	0x7384	# <CJK>
+0x5121	0x9009	# <CJK>
+0x5122	0x7663	# <CJK>
+0x5123	0x7729	# <CJK>
+0x5124	0x7EDA	# <CJK>
+0x5125	0x9774	# <CJK>
+0x5126	0x859B	# <CJK>
+0x5127	0x5B66	# <CJK>
+0x5128	0x7A74	# <CJK>
+0x5129	0x96EA	# <CJK>
+0x512A	0x8840	# <CJK>
+0x512B	0x52CB	# <CJK>
+0x512C	0x718F	# <CJK>
+0x512D	0x5FAA	# <CJK>
+0x512E	0x65EC	# <CJK>
+0x512F	0x8BE2	# <CJK>
+0x5130	0x5BFB	# <CJK>
+0x5131	0x9A6F	# <CJK>
+0x5132	0x5DE1	# <CJK>
+0x5133	0x6B89	# <CJK>
+0x5134	0x6C5B	# <CJK>
+0x5135	0x8BAD	# <CJK>
+0x5136	0x8BAF	# <CJK>
+0x5137	0x900A	# <CJK>
+0x5138	0x8FC5	# <CJK>
+0x5139	0x538B	# <CJK>
+0x513A	0x62BC	# <CJK>
+0x513B	0x9E26	# <CJK>
+0x513C	0x9E2D	# <CJK>
+0x513D	0x5440	# <CJK>
+0x513E	0x4E2B	# <CJK>
+0x513F	0x82BD	# <CJK>
+0x5140	0x7259	# <CJK>
+0x5141	0x869C	# <CJK>
+0x5142	0x5D16	# <CJK>
+0x5143	0x8859	# <CJK>
+0x5144	0x6DAF	# <CJK>
+0x5145	0x96C5	# <CJK>
+0x5146	0x54D1	# <CJK>
+0x5147	0x4E9A	# <CJK>
+0x5148	0x8BB6	# <CJK>
+0x5149	0x7109	# <CJK>
+0x514A	0x54BD	# <CJK>
+0x514B	0x9609	# <CJK>
+0x514C	0x70DF	# <CJK>
+0x514D	0x6DF9	# <CJK>
+0x514E	0x76D0	# <CJK>
+0x514F	0x4E25	# <CJK>
+0x5150	0x7814	# <CJK>
+0x5151	0x8712	# <CJK>
+0x5152	0x5CA9	# <CJK>
+0x5153	0x5EF6	# <CJK>
+0x5154	0x8A00	# <CJK>
+0x5155	0x989C	# <CJK>
+0x5156	0x960E	# <CJK>
+0x5157	0x708E	# <CJK>
+0x5158	0x6CBF	# <CJK>
+0x5159	0x5944	# <CJK>
+0x515A	0x63A9	# <CJK>
+0x515B	0x773C	# <CJK>
+0x515C	0x884D	# <CJK>
+0x515D	0x6F14	# <CJK>
+0x515E	0x8273	# <CJK>
+0x515F	0x5830	# <CJK>
+0x5160	0x71D5	# <CJK>
+0x5161	0x538C	# <CJK>
+0x5162	0x781A	# <CJK>
+0x5163	0x96C1	# <CJK>
+0x5164	0x5501	# <CJK>
+0x5165	0x5F66	# <CJK>
+0x5166	0x7130	# <CJK>
+0x5167	0x5BB4	# <CJK>
+0x5168	0x8C1A	# <CJK>
+0x5169	0x9A8C	# <CJK>
+0x516A	0x6B83	# <CJK>
+0x516B	0x592E	# <CJK>
+0x516C	0x9E2F	# <CJK>
+0x516D	0x79E7	# <CJK>
+0x516E	0x6768	# <CJK>
+0x516F	0x626C	# <CJK>
+0x5170	0x4F6F	# <CJK>
+0x5171	0x75A1	# <CJK>
+0x5172	0x7F8A	# <CJK>
+0x5173	0x6D0B	# <CJK>
+0x5174	0x9633	# <CJK>
+0x5175	0x6C27	# <CJK>
+0x5176	0x4EF0	# <CJK>
+0x5177	0x75D2	# <CJK>
+0x5178	0x517B	# <CJK>
+0x5179	0x6837	# <CJK>
+0x517A	0x6F3E	# <CJK>
+0x517B	0x9080	# <CJK>
+0x517C	0x8170	# <CJK>
+0x517D	0x5996	# <CJK>
+0x517E	0x7476	# <CJK>
+0x5221	0x6447	# <CJK>
+0x5222	0x5C27	# <CJK>
+0x5223	0x9065	# <CJK>
+0x5224	0x7A91	# <CJK>
+0x5225	0x8C23	# <CJK>
+0x5226	0x59DA	# <CJK>
+0x5227	0x54AC	# <CJK>
+0x5228	0x8200	# <CJK>
+0x5229	0x836F	# <CJK>
+0x522A	0x8981	# <CJK>
+0x522B	0x8000	# <CJK>
+0x522C	0x6930	# <CJK>
+0x522D	0x564E	# <CJK>
+0x522E	0x8036	# <CJK>
+0x522F	0x7237	# <CJK>
+0x5230	0x91CE	# <CJK>
+0x5231	0x51B6	# <CJK>
+0x5232	0x4E5F	# <CJK>
+0x5233	0x9875	# <CJK>
+0x5234	0x6396	# <CJK>
+0x5235	0x4E1A	# <CJK>
+0x5236	0x53F6	# <CJK>
+0x5237	0x66F3	# <CJK>
+0x5238	0x814B	# <CJK>
+0x5239	0x591C	# <CJK>
+0x523A	0x6DB2	# <CJK>
+0x523B	0x4E00	# <CJK>
+0x523C	0x58F9	# <CJK>
+0x523D	0x533B	# <CJK>
+0x523E	0x63D6	# <CJK>
+0x523F	0x94F1	# <CJK>
+0x5240	0x4F9D	# <CJK>
+0x5241	0x4F0A	# <CJK>
+0x5242	0x8863	# <CJK>
+0x5243	0x9890	# <CJK>
+0x5244	0x5937	# <CJK>
+0x5245	0x9057	# <CJK>
+0x5246	0x79FB	# <CJK>
+0x5247	0x4EEA	# <CJK>
+0x5248	0x80F0	# <CJK>
+0x5249	0x7591	# <CJK>
+0x524A	0x6C82	# <CJK>
+0x524B	0x5B9C	# <CJK>
+0x524C	0x59E8	# <CJK>
+0x524D	0x5F5D	# <CJK>
+0x524E	0x6905	# <CJK>
+0x524F	0x8681	# <CJK>
+0x5250	0x501A	# <CJK>
+0x5251	0x5DF2	# <CJK>
+0x5252	0x4E59	# <CJK>
+0x5253	0x77E3	# <CJK>
+0x5254	0x4EE5	# <CJK>
+0x5255	0x827A	# <CJK>
+0x5256	0x6291	# <CJK>
+0x5257	0x6613	# <CJK>
+0x5258	0x9091	# <CJK>
+0x5259	0x5C79	# <CJK>
+0x525A	0x4EBF	# <CJK>
+0x525B	0x5F79	# <CJK>
+0x525C	0x81C6	# <CJK>
+0x525D	0x9038	# <CJK>
+0x525E	0x8084	# <CJK>
+0x525F	0x75AB	# <CJK>
+0x5260	0x4EA6	# <CJK>
+0x5261	0x88D4	# <CJK>
+0x5262	0x610F	# <CJK>
+0x5263	0x6BC5	# <CJK>
+0x5264	0x5FC6	# <CJK>
+0x5265	0x4E49	# <CJK>
+0x5266	0x76CA	# <CJK>
+0x5267	0x6EA2	# <CJK>
+0x5268	0x8BE3	# <CJK>
+0x5269	0x8BAE	# <CJK>
+0x526A	0x8C0A	# <CJK>
+0x526B	0x8BD1	# <CJK>
+0x526C	0x5F02	# <CJK>
+0x526D	0x7FFC	# <CJK>
+0x526E	0x7FCC	# <CJK>
+0x526F	0x7ECE	# <CJK>
+0x5270	0x8335	# <CJK>
+0x5271	0x836B	# <CJK>
+0x5272	0x56E0	# <CJK>
+0x5273	0x6BB7	# <CJK>
+0x5274	0x97F3	# <CJK>
+0x5275	0x9634	# <CJK>
+0x5276	0x59FB	# <CJK>
+0x5277	0x541F	# <CJK>
+0x5278	0x94F6	# <CJK>
+0x5279	0x6DEB	# <CJK>
+0x527A	0x5BC5	# <CJK>
+0x527B	0x996E	# <CJK>
+0x527C	0x5C39	# <CJK>
+0x527D	0x5F15	# <CJK>
+0x527E	0x9690	# <CJK>
+0x5321	0x5370	# <CJK>
+0x5322	0x82F1	# <CJK>
+0x5323	0x6A31	# <CJK>
+0x5324	0x5A74	# <CJK>
+0x5325	0x9E70	# <CJK>
+0x5326	0x5E94	# <CJK>
+0x5327	0x7F28	# <CJK>
+0x5328	0x83B9	# <CJK>
+0x5329	0x8424	# <CJK>
+0x532A	0x8425	# <CJK>
+0x532B	0x8367	# <CJK>
+0x532C	0x8747	# <CJK>
+0x532D	0x8FCE	# <CJK>
+0x532E	0x8D62	# <CJK>
+0x532F	0x76C8	# <CJK>
+0x5330	0x5F71	# <CJK>
+0x5331	0x9896	# <CJK>
+0x5332	0x786C	# <CJK>
+0x5333	0x6620	# <CJK>
+0x5334	0x54DF	# <CJK>
+0x5335	0x62E5	# <CJK>
+0x5336	0x4F63	# <CJK>
+0x5337	0x81C3	# <CJK>
+0x5338	0x75C8	# <CJK>
+0x5339	0x5EB8	# <CJK>
+0x533A	0x96CD	# <CJK>
+0x533B	0x8E0A	# <CJK>
+0x533C	0x86F9	# <CJK>
+0x533D	0x548F	# <CJK>
+0x533E	0x6CF3	# <CJK>
+0x533F	0x6D8C	# <CJK>
+0x5340	0x6C38	# <CJK>
+0x5341	0x607F	# <CJK>
+0x5342	0x52C7	# <CJK>
+0x5343	0x7528	# <CJK>
+0x5344	0x5E7D	# <CJK>
+0x5345	0x4F18	# <CJK>
+0x5346	0x60A0	# <CJK>
+0x5347	0x5FE7	# <CJK>
+0x5348	0x5C24	# <CJK>
+0x5349	0x7531	# <CJK>
+0x534A	0x90AE	# <CJK>
+0x534B	0x94C0	# <CJK>
+0x534C	0x72B9	# <CJK>
+0x534D	0x6CB9	# <CJK>
+0x534E	0x6E38	# <CJK>
+0x534F	0x9149	# <CJK>
+0x5350	0x6709	# <CJK>
+0x5351	0x53CB	# <CJK>
+0x5352	0x53F3	# <CJK>
+0x5353	0x4F51	# <CJK>
+0x5354	0x91C9	# <CJK>
+0x5355	0x8BF1	# <CJK>
+0x5356	0x53C8	# <CJK>
+0x5357	0x5E7C	# <CJK>
+0x5358	0x8FC2	# <CJK>
+0x5359	0x6DE4	# <CJK>
+0x535A	0x4E8E	# <CJK>
+0x535B	0x76C2	# <CJK>
+0x535C	0x6986	# <CJK>
+0x535D	0x865E	# <CJK>
+0x535E	0x611A	# <CJK>
+0x535F	0x8206	# <CJK>
+0x5360	0x4F59	# <CJK>
+0x5361	0x4FDE	# <CJK>
+0x5362	0x903E	# <CJK>
+0x5363	0x9C7C	# <CJK>
+0x5364	0x6109	# <CJK>
+0x5365	0x6E1D	# <CJK>
+0x5366	0x6E14	# <CJK>
+0x5367	0x9685	# <CJK>
+0x5368	0x4E88	# <CJK>
+0x5369	0x5A31	# <CJK>
+0x536A	0x96E8	# <CJK>
+0x536B	0x4E0E	# <CJK>
+0x536C	0x5C7F	# <CJK>
+0x536D	0x79B9	# <CJK>
+0x536E	0x5B87	# <CJK>
+0x536F	0x8BED	# <CJK>
+0x5370	0x7FBD	# <CJK>
+0x5371	0x7389	# <CJK>
+0x5372	0x57DF	# <CJK>
+0x5373	0x828B	# <CJK>
+0x5374	0x90C1	# <CJK>
+0x5375	0x5401	# <CJK>
+0x5376	0x9047	# <CJK>
+0x5377	0x55BB	# <CJK>
+0x5378	0x5CEA	# <CJK>
+0x5379	0x5FA1	# <CJK>
+0x537A	0x6108	# <CJK>
+0x537B	0x6B32	# <CJK>
+0x537C	0x72F1	# <CJK>
+0x537D	0x80B2	# <CJK>
+0x537E	0x8A89	# <CJK>
+0x5421	0x6D74	# <CJK>
+0x5422	0x5BD3	# <CJK>
+0x5423	0x88D5	# <CJK>
+0x5424	0x9884	# <CJK>
+0x5425	0x8C6B	# <CJK>
+0x5426	0x9A6D	# <CJK>
+0x5427	0x9E33	# <CJK>
+0x5428	0x6E0A	# <CJK>
+0x5429	0x51A4	# <CJK>
+0x542A	0x5143	# <CJK>
+0x542B	0x57A3	# <CJK>
+0x542C	0x8881	# <CJK>
+0x542D	0x539F	# <CJK>
+0x542E	0x63F4	# <CJK>
+0x542F	0x8F95	# <CJK>
+0x5430	0x56ED	# <CJK>
+0x5431	0x5458	# <CJK>
+0x5432	0x5706	# <CJK>
+0x5433	0x733F	# <CJK>
+0x5434	0x6E90	# <CJK>
+0x5435	0x7F18	# <CJK>
+0x5436	0x8FDC	# <CJK>
+0x5437	0x82D1	# <CJK>
+0x5438	0x613F	# <CJK>
+0x5439	0x6028	# <CJK>
+0x543A	0x9662	# <CJK>
+0x543B	0x66F0	# <CJK>
+0x543C	0x7EA6	# <CJK>
+0x543D	0x8D8A	# <CJK>
+0x543E	0x8DC3	# <CJK>
+0x543F	0x94A5	# <CJK>
+0x5440	0x5CB3	# <CJK>
+0x5441	0x7CA4	# <CJK>
+0x5442	0x6708	# <CJK>
+0x5443	0x60A6	# <CJK>
+0x5444	0x9605	# <CJK>
+0x5445	0x8018	# <CJK>
+0x5446	0x4E91	# <CJK>
+0x5447	0x90E7	# <CJK>
+0x5448	0x5300	# <CJK>
+0x5449	0x9668	# <CJK>
+0x544A	0x5141	# <CJK>
+0x544B	0x8FD0	# <CJK>
+0x544C	0x8574	# <CJK>
+0x544D	0x915D	# <CJK>
+0x544E	0x6655	# <CJK>
+0x544F	0x97F5	# <CJK>
+0x5450	0x5B55	# <CJK>
+0x5451	0x531D	# <CJK>
+0x5452	0x7838	# <CJK>
+0x5453	0x6742	# <CJK>
+0x5454	0x683D	# <CJK>
+0x5455	0x54C9	# <CJK>
+0x5456	0x707E	# <CJK>
+0x5457	0x5BB0	# <CJK>
+0x5458	0x8F7D	# <CJK>
+0x5459	0x518D	# <CJK>
+0x545A	0x5728	# <CJK>
+0x545B	0x54B1	# <CJK>
+0x545C	0x6512	# <CJK>
+0x545D	0x6682	# <CJK>
+0x545E	0x8D5E	# <CJK>
+0x545F	0x8D43	# <CJK>
+0x5460	0x810F	# <CJK>
+0x5461	0x846C	# <CJK>
+0x5462	0x906D	# <CJK>
+0x5463	0x7CDF	# <CJK>
+0x5464	0x51FF	# <CJK>
+0x5465	0x85FB	# <CJK>
+0x5466	0x67A3	# <CJK>
+0x5467	0x65E9	# <CJK>
+0x5468	0x6FA1	# <CJK>
+0x5469	0x86A4	# <CJK>
+0x546A	0x8E81	# <CJK>
+0x546B	0x566A	# <CJK>
+0x546C	0x9020	# <CJK>
+0x546D	0x7682	# <CJK>
+0x546E	0x7076	# <CJK>
+0x546F	0x71E5	# <CJK>
+0x5470	0x8D23	# <CJK>
+0x5471	0x62E9	# <CJK>
+0x5472	0x5219	# <CJK>
+0x5473	0x6CFD	# <CJK>
+0x5474	0x8D3C	# <CJK>
+0x5475	0x600E	# <CJK>
+0x5476	0x589E	# <CJK>
+0x5477	0x618E	# <CJK>
+0x5478	0x66FE	# <CJK>
+0x5479	0x8D60	# <CJK>
+0x547A	0x624E	# <CJK>
+0x547B	0x55B3	# <CJK>
+0x547C	0x6E23	# <CJK>
+0x547D	0x672D	# <CJK>
+0x547E	0x8F67	# <CJK>
+0x5521	0x94E1	# <CJK>
+0x5522	0x95F8	# <CJK>
+0x5523	0x7728	# <CJK>
+0x5524	0x6805	# <CJK>
+0x5525	0x69A8	# <CJK>
+0x5526	0x548B	# <CJK>
+0x5527	0x4E4D	# <CJK>
+0x5528	0x70B8	# <CJK>
+0x5529	0x8BC8	# <CJK>
+0x552A	0x6458	# <CJK>
+0x552B	0x658B	# <CJK>
+0x552C	0x5B85	# <CJK>
+0x552D	0x7A84	# <CJK>
+0x552E	0x503A	# <CJK>
+0x552F	0x5BE8	# <CJK>
+0x5530	0x77BB	# <CJK>
+0x5531	0x6BE1	# <CJK>
+0x5532	0x8A79	# <CJK>
+0x5533	0x7C98	# <CJK>
+0x5534	0x6CBE	# <CJK>
+0x5535	0x76CF	# <CJK>
+0x5536	0x65A9	# <CJK>
+0x5537	0x8F97	# <CJK>
+0x5538	0x5D2D	# <CJK>
+0x5539	0x5C55	# <CJK>
+0x553A	0x8638	# <CJK>
+0x553B	0x6808	# <CJK>
+0x553C	0x5360	# <CJK>
+0x553D	0x6218	# <CJK>
+0x553E	0x7AD9	# <CJK>
+0x553F	0x6E5B	# <CJK>
+0x5540	0x7EFD	# <CJK>
+0x5541	0x6A1F	# <CJK>
+0x5542	0x7AE0	# <CJK>
+0x5543	0x5F70	# <CJK>
+0x5544	0x6F33	# <CJK>
+0x5545	0x5F20	# <CJK>
+0x5546	0x638C	# <CJK>
+0x5547	0x6DA8	# <CJK>
+0x5548	0x6756	# <CJK>
+0x5549	0x4E08	# <CJK>
+0x554A	0x5E10	# <CJK>
+0x554B	0x8D26	# <CJK>
+0x554C	0x4ED7	# <CJK>
+0x554D	0x80C0	# <CJK>
+0x554E	0x7634	# <CJK>
+0x554F	0x969C	# <CJK>
+0x5550	0x62DB	# <CJK>
+0x5551	0x662D	# <CJK>
+0x5552	0x627E	# <CJK>
+0x5553	0x6CBC	# <CJK>
+0x5554	0x8D75	# <CJK>
+0x5555	0x7167	# <CJK>
+0x5556	0x7F69	# <CJK>
+0x5557	0x5146	# <CJK>
+0x5558	0x8087	# <CJK>
+0x5559	0x53EC	# <CJK>
+0x555A	0x906E	# <CJK>
+0x555B	0x6298	# <CJK>
+0x555C	0x54F2	# <CJK>
+0x555D	0x86F0	# <CJK>
+0x555E	0x8F99	# <CJK>
+0x555F	0x8005	# <CJK>
+0x5560	0x9517	# <CJK>
+0x5561	0x8517	# <CJK>
+0x5562	0x8FD9	# <CJK>
+0x5563	0x6D59	# <CJK>
+0x5564	0x73CD	# <CJK>
+0x5565	0x659F	# <CJK>
+0x5566	0x771F	# <CJK>
+0x5567	0x7504	# <CJK>
+0x5568	0x7827	# <CJK>
+0x5569	0x81FB	# <CJK>
+0x556A	0x8D1E	# <CJK>
+0x556B	0x9488	# <CJK>
+0x556C	0x4FA6	# <CJK>
+0x556D	0x6795	# <CJK>
+0x556E	0x75B9	# <CJK>
+0x556F	0x8BCA	# <CJK>
+0x5570	0x9707	# <CJK>
+0x5571	0x632F	# <CJK>
+0x5572	0x9547	# <CJK>
+0x5573	0x9635	# <CJK>
+0x5574	0x84B8	# <CJK>
+0x5575	0x6323	# <CJK>
+0x5576	0x7741	# <CJK>
+0x5577	0x5F81	# <CJK>
+0x5578	0x72F0	# <CJK>
+0x5579	0x4E89	# <CJK>
+0x557A	0x6014	# <CJK>
+0x557B	0x6574	# <CJK>
+0x557C	0x62EF	# <CJK>
+0x557D	0x6B63	# <CJK>
+0x557E	0x653F	# <CJK>
+0x5621	0x5E27	# <CJK>
+0x5622	0x75C7	# <CJK>
+0x5623	0x90D1	# <CJK>
+0x5624	0x8BC1	# <CJK>
+0x5625	0x829D	# <CJK>
+0x5626	0x679D	# <CJK>
+0x5627	0x652F	# <CJK>
+0x5628	0x5431	# <CJK>
+0x5629	0x8718	# <CJK>
+0x562A	0x77E5	# <CJK>
+0x562B	0x80A2	# <CJK>
+0x562C	0x8102	# <CJK>
+0x562D	0x6C41	# <CJK>
+0x562E	0x4E4B	# <CJK>
+0x562F	0x7EC7	# <CJK>
+0x5630	0x804C	# <CJK>
+0x5631	0x76F4	# <CJK>
+0x5632	0x690D	# <CJK>
+0x5633	0x6B96	# <CJK>
+0x5634	0x6267	# <CJK>
+0x5635	0x503C	# <CJK>
+0x5636	0x4F84	# <CJK>
+0x5637	0x5740	# <CJK>
+0x5638	0x6307	# <CJK>
+0x5639	0x6B62	# <CJK>
+0x563A	0x8DBE	# <CJK>
+0x563B	0x53EA	# <CJK>
+0x563C	0x65E8	# <CJK>
+0x563D	0x7EB8	# <CJK>
+0x563E	0x5FD7	# <CJK>
+0x563F	0x631A	# <CJK>
+0x5640	0x63B7	# <CJK>
+0x5641	0x81F3	# <CJK>
+0x5642	0x81F4	# <CJK>
+0x5643	0x7F6E	# <CJK>
+0x5644	0x5E1C	# <CJK>
+0x5645	0x5CD9	# <CJK>
+0x5646	0x5236	# <CJK>
+0x5647	0x667A	# <CJK>
+0x5648	0x79E9	# <CJK>
+0x5649	0x7A1A	# <CJK>
+0x564A	0x8D28	# <CJK>
+0x564B	0x7099	# <CJK>
+0x564C	0x75D4	# <CJK>
+0x564D	0x6EDE	# <CJK>
+0x564E	0x6CBB	# <CJK>
+0x564F	0x7A92	# <CJK>
+0x5650	0x4E2D	# <CJK>
+0x5651	0x76C5	# <CJK>
+0x5652	0x5FE0	# <CJK>
+0x5653	0x949F	# <CJK>
+0x5654	0x8877	# <CJK>
+0x5655	0x7EC8	# <CJK>
+0x5656	0x79CD	# <CJK>
+0x5657	0x80BF	# <CJK>
+0x5658	0x91CD	# <CJK>
+0x5659	0x4EF2	# <CJK>
+0x565A	0x4F17	# <CJK>
+0x565B	0x821F	# <CJK>
+0x565C	0x5468	# <CJK>
+0x565D	0x5DDE	# <CJK>
+0x565E	0x6D32	# <CJK>
+0x565F	0x8BCC	# <CJK>
+0x5660	0x7CA5	# <CJK>
+0x5661	0x8F74	# <CJK>
+0x5662	0x8098	# <CJK>
+0x5663	0x5E1A	# <CJK>
+0x5664	0x5492	# <CJK>
+0x5665	0x76B1	# <CJK>
+0x5666	0x5B99	# <CJK>
+0x5667	0x663C	# <CJK>
+0x5668	0x9AA4	# <CJK>
+0x5669	0x73E0	# <CJK>
+0x566A	0x682A	# <CJK>
+0x566B	0x86DB	# <CJK>
+0x566C	0x6731	# <CJK>
+0x566D	0x732A	# <CJK>
+0x566E	0x8BF8	# <CJK>
+0x566F	0x8BDB	# <CJK>
+0x5670	0x9010	# <CJK>
+0x5671	0x7AF9	# <CJK>
+0x5672	0x70DB	# <CJK>
+0x5673	0x716E	# <CJK>
+0x5674	0x62C4	# <CJK>
+0x5675	0x77A9	# <CJK>
+0x5676	0x5631	# <CJK>
+0x5677	0x4E3B	# <CJK>
+0x5678	0x8457	# <CJK>
+0x5679	0x67F1	# <CJK>
+0x567A	0x52A9	# <CJK>
+0x567B	0x86C0	# <CJK>
+0x567C	0x8D2E	# <CJK>
+0x567D	0x94F8	# <CJK>
+0x567E	0x7B51	# <CJK>
+0x5721	0x4F4F	# <CJK>
+0x5722	0x6CE8	# <CJK>
+0x5723	0x795D	# <CJK>
+0x5724	0x9A7B	# <CJK>
+0x5725	0x6293	# <CJK>
+0x5726	0x722A	# <CJK>
+0x5727	0x62FD	# <CJK>
+0x5728	0x4E13	# <CJK>
+0x5729	0x7816	# <CJK>
+0x572A	0x8F6C	# <CJK>
+0x572B	0x64B0	# <CJK>
+0x572C	0x8D5A	# <CJK>
+0x572D	0x7BC6	# <CJK>
+0x572E	0x6869	# <CJK>
+0x572F	0x5E84	# <CJK>
+0x5730	0x88C5	# <CJK>
+0x5731	0x5986	# <CJK>
+0x5732	0x649E	# <CJK>
+0x5733	0x58EE	# <CJK>
+0x5734	0x72B6	# <CJK>
+0x5735	0x690E	# <CJK>
+0x5736	0x9525	# <CJK>
+0x5737	0x8FFD	# <CJK>
+0x5738	0x8D58	# <CJK>
+0x5739	0x5760	# <CJK>
+0x573A	0x7F00	# <CJK>
+0x573B	0x8C06	# <CJK>
+0x573C	0x51C6	# <CJK>
+0x573D	0x6349	# <CJK>
+0x573E	0x62D9	# <CJK>
+0x573F	0x5353	# <CJK>
+0x5740	0x684C	# <CJK>
+0x5741	0x7422	# <CJK>
+0x5742	0x8301	# <CJK>
+0x5743	0x914C	# <CJK>
+0x5744	0x5544	# <CJK>
+0x5745	0x7740	# <CJK>
+0x5746	0x707C	# <CJK>
+0x5747	0x6D4A	# <CJK>
+0x5748	0x5179	# <CJK>
+0x5749	0x54A8	# <CJK>
+0x574A	0x8D44	# <CJK>
+0x574B	0x59FF	# <CJK>
+0x574C	0x6ECB	# <CJK>
+0x574D	0x6DC4	# <CJK>
+0x574E	0x5B5C	# <CJK>
+0x574F	0x7D2B	# <CJK>
+0x5750	0x4ED4	# <CJK>
+0x5751	0x7C7D	# <CJK>
+0x5752	0x6ED3	# <CJK>
+0x5753	0x5B50	# <CJK>
+0x5754	0x81EA	# <CJK>
+0x5755	0x6E0D	# <CJK>
+0x5756	0x5B57	# <CJK>
+0x5757	0x9B03	# <CJK>
+0x5758	0x68D5	# <CJK>
+0x5759	0x8E2A	# <CJK>
+0x575A	0x5B97	# <CJK>
+0x575B	0x7EFC	# <CJK>
+0x575C	0x603B	# <CJK>
+0x575D	0x7EB5	# <CJK>
+0x575E	0x90B9	# <CJK>
+0x575F	0x8D70	# <CJK>
+0x5760	0x594F	# <CJK>
+0x5761	0x63CD	# <CJK>
+0x5762	0x79DF	# <CJK>
+0x5763	0x8DB3	# <CJK>
+0x5764	0x5352	# <CJK>
+0x5765	0x65CF	# <CJK>
+0x5766	0x7956	# <CJK>
+0x5767	0x8BC5	# <CJK>
+0x5768	0x963B	# <CJK>
+0x5769	0x7EC4	# <CJK>
+0x576A	0x94BB	# <CJK>
+0x576B	0x7E82	# <CJK>
+0x576C	0x5634	# <CJK>
+0x576D	0x9189	# <CJK>
+0x576E	0x6700	# <CJK>
+0x576F	0x7F6A	# <CJK>
+0x5770	0x5C0A	# <CJK>
+0x5771	0x9075	# <CJK>
+0x5772	0x6628	# <CJK>
+0x5773	0x5DE6	# <CJK>
+0x5774	0x4F50	# <CJK>
+0x5775	0x67DE	# <CJK>
+0x5776	0x505A	# <CJK>
+0x5777	0x4F5C	# <CJK>
+0x5778	0x5750	# <CJK>
+0x5779	0x5EA7	# <CJK>
+0x5821	0x4E8D	# <CJK>
+0x5822	0x4E0C	# <CJK>
+0x5823	0x5140	# <CJK>
+0x5824	0x4E10	# <CJK>
+0x5825	0x5EFF	# <CJK>
+0x5826	0x5345	# <CJK>
+0x5827	0x4E15	# <CJK>
+0x5828	0x4E98	# <CJK>
+0x5829	0x4E1E	# <CJK>
+0x582A	0x9B32	# <CJK>
+0x582B	0x5B6C	# <CJK>
+0x582C	0x5669	# <CJK>
+0x582D	0x4E28	# <CJK>
+0x582E	0x79BA	# <CJK>
+0x582F	0x4E3F	# <CJK>
+0x5830	0x5315	# <CJK>
+0x5831	0x4E47	# <CJK>
+0x5832	0x592D	# <CJK>
+0x5833	0x723B	# <CJK>
+0x5834	0x536E	# <CJK>
+0x5835	0x6C10	# <CJK>
+0x5836	0x56DF	# <CJK>
+0x5837	0x80E4	# <CJK>
+0x5838	0x9997	# <CJK>
+0x5839	0x6BD3	# <CJK>
+0x583A	0x777E	# <CJK>
+0x583B	0x9F17	# <CJK>
+0x583C	0x4E36	# <CJK>
+0x583D	0x4E9F	# <CJK>
+0x583E	0x9F10	# <CJK>
+0x583F	0x4E5C	# <CJK>
+0x5840	0x4E69	# <CJK>
+0x5841	0x4E93	# <CJK>
+0x5842	0x8288	# <CJK>
+0x5843	0x5B5B	# <CJK>
+0x5844	0x556C	# <CJK>
+0x5845	0x560F	# <CJK>
+0x5846	0x4EC4	# <CJK>
+0x5847	0x538D	# <CJK>
+0x5848	0x539D	# <CJK>
+0x5849	0x53A3	# <CJK>
+0x584A	0x53A5	# <CJK>
+0x584B	0x53AE	# <CJK>
+0x584C	0x9765	# <CJK>
+0x584D	0x8D5D	# <CJK>
+0x584E	0x531A	# <CJK>
+0x584F	0x53F5	# <CJK>
+0x5850	0x5326	# <CJK>
+0x5851	0x532E	# <CJK>
+0x5852	0x533E	# <CJK>
+0x5853	0x8D5C	# <CJK>
+0x5854	0x5366	# <CJK>
+0x5855	0x5363	# <CJK>
+0x5856	0x5202	# <CJK>
+0x5857	0x5208	# <CJK>
+0x5858	0x520E	# <CJK>
+0x5859	0x522D	# <CJK>
+0x585A	0x5233	# <CJK>
+0x585B	0x523F	# <CJK>
+0x585C	0x5240	# <CJK>
+0x585D	0x524C	# <CJK>
+0x585E	0x525E	# <CJK>
+0x585F	0x5261	# <CJK>
+0x5860	0x525C	# <CJK>
+0x5861	0x84AF	# <CJK>
+0x5862	0x527D	# <CJK>
+0x5863	0x5282	# <CJK>
+0x5864	0x5281	# <CJK>
+0x5865	0x5290	# <CJK>
+0x5866	0x5293	# <CJK>
+0x5867	0x5182	# <CJK>
+0x5868	0x7F54	# <CJK>
+0x5869	0x4EBB	# <CJK>
+0x586A	0x4EC3	# <CJK>
+0x586B	0x4EC9	# <CJK>
+0x586C	0x4EC2	# <CJK>
+0x586D	0x4EE8	# <CJK>
+0x586E	0x4EE1	# <CJK>
+0x586F	0x4EEB	# <CJK>
+0x5870	0x4EDE	# <CJK>
+0x5871	0x4F1B	# <CJK>
+0x5872	0x4EF3	# <CJK>
+0x5873	0x4F22	# <CJK>
+0x5874	0x4F64	# <CJK>
+0x5875	0x4EF5	# <CJK>
+0x5876	0x4F25	# <CJK>
+0x5877	0x4F27	# <CJK>
+0x5878	0x4F09	# <CJK>
+0x5879	0x4F2B	# <CJK>
+0x587A	0x4F5E	# <CJK>
+0x587B	0x4F67	# <CJK>
+0x587C	0x6538	# <CJK>
+0x587D	0x4F5A	# <CJK>
+0x587E	0x4F5D	# <CJK>
+0x5921	0x4F5F	# <CJK>
+0x5922	0x4F57	# <CJK>
+0x5923	0x4F32	# <CJK>
+0x5924	0x4F3D	# <CJK>
+0x5925	0x4F76	# <CJK>
+0x5926	0x4F74	# <CJK>
+0x5927	0x4F91	# <CJK>
+0x5928	0x4F89	# <CJK>
+0x5929	0x4F83	# <CJK>
+0x592A	0x4F8F	# <CJK>
+0x592B	0x4F7E	# <CJK>
+0x592C	0x4F7B	# <CJK>
+0x592D	0x4FAA	# <CJK>
+0x592E	0x4F7C	# <CJK>
+0x592F	0x4FAC	# <CJK>
+0x5930	0x4F94	# <CJK>
+0x5931	0x4FE6	# <CJK>
+0x5932	0x4FE8	# <CJK>
+0x5933	0x4FEA	# <CJK>
+0x5934	0x4FC5	# <CJK>
+0x5935	0x4FDA	# <CJK>
+0x5936	0x4FE3	# <CJK>
+0x5937	0x4FDC	# <CJK>
+0x5938	0x4FD1	# <CJK>
+0x5939	0x4FDF	# <CJK>
+0x593A	0x4FF8	# <CJK>
+0x593B	0x5029	# <CJK>
+0x593C	0x504C	# <CJK>
+0x593D	0x4FF3	# <CJK>
+0x593E	0x502C	# <CJK>
+0x593F	0x500F	# <CJK>
+0x5940	0x502E	# <CJK>
+0x5941	0x502D	# <CJK>
+0x5942	0x4FFE	# <CJK>
+0x5943	0x501C	# <CJK>
+0x5944	0x500C	# <CJK>
+0x5945	0x5025	# <CJK>
+0x5946	0x5028	# <CJK>
+0x5947	0x507E	# <CJK>
+0x5948	0x5043	# <CJK>
+0x5949	0x5055	# <CJK>
+0x594A	0x5048	# <CJK>
+0x594B	0x504E	# <CJK>
+0x594C	0x506C	# <CJK>
+0x594D	0x507B	# <CJK>
+0x594E	0x50A5	# <CJK>
+0x594F	0x50A7	# <CJK>
+0x5950	0x50A9	# <CJK>
+0x5951	0x50BA	# <CJK>
+0x5952	0x50D6	# <CJK>
+0x5953	0x5106	# <CJK>
+0x5954	0x50ED	# <CJK>
+0x5955	0x50EC	# <CJK>
+0x5956	0x50E6	# <CJK>
+0x5957	0x50EE	# <CJK>
+0x5958	0x5107	# <CJK>
+0x5959	0x510B	# <CJK>
+0x595A	0x4EDD	# <CJK>
+0x595B	0x6C3D	# <CJK>
+0x595C	0x4F58	# <CJK>
+0x595D	0x4F65	# <CJK>
+0x595E	0x4FCE	# <CJK>
+0x595F	0x9FA0	# <CJK>
+0x5960	0x6C46	# <CJK>
+0x5961	0x7C74	# <CJK>
+0x5962	0x516E	# <CJK>
+0x5963	0x5DFD	# <CJK>
+0x5964	0x9EC9	# <CJK>
+0x5965	0x9998	# <CJK>
+0x5966	0x5181	# <CJK>
+0x5967	0x5914	# <CJK>
+0x5968	0x52F9	# <CJK>
+0x5969	0x530D	# <CJK>
+0x596A	0x8A07	# <CJK>
+0x596B	0x5310	# <CJK>
+0x596C	0x51EB	# <CJK>
+0x596D	0x5919	# <CJK>
+0x596E	0x5155	# <CJK>
+0x596F	0x4EA0	# <CJK>
+0x5970	0x5156	# <CJK>
+0x5971	0x4EB3	# <CJK>
+0x5972	0x886E	# <CJK>
+0x5973	0x88A4	# <CJK>
+0x5974	0x4EB5	# <CJK>
+0x5975	0x8114	# <CJK>
+0x5976	0x88D2	# <CJK>
+0x5977	0x7980	# <CJK>
+0x5978	0x5B34	# <CJK>
+0x5979	0x8803	# <CJK>
+0x597A	0x7FB8	# <CJK>
+0x597B	0x51AB	# <CJK>
+0x597C	0x51B1	# <CJK>
+0x597D	0x51BD	# <CJK>
+0x597E	0x51BC	# <CJK>
+0x5A21	0x51C7	# <CJK>
+0x5A22	0x5196	# <CJK>
+0x5A23	0x51A2	# <CJK>
+0x5A24	0x51A5	# <CJK>
+0x5A25	0x8BA0	# <CJK>
+0x5A26	0x8BA6	# <CJK>
+0x5A27	0x8BA7	# <CJK>
+0x5A28	0x8BAA	# <CJK>
+0x5A29	0x8BB4	# <CJK>
+0x5A2A	0x8BB5	# <CJK>
+0x5A2B	0x8BB7	# <CJK>
+0x5A2C	0x8BC2	# <CJK>
+0x5A2D	0x8BC3	# <CJK>
+0x5A2E	0x8BCB	# <CJK>
+0x5A2F	0x8BCF	# <CJK>
+0x5A30	0x8BCE	# <CJK>
+0x5A31	0x8BD2	# <CJK>
+0x5A32	0x8BD3	# <CJK>
+0x5A33	0x8BD4	# <CJK>
+0x5A34	0x8BD6	# <CJK>
+0x5A35	0x8BD8	# <CJK>
+0x5A36	0x8BD9	# <CJK>
+0x5A37	0x8BDC	# <CJK>
+0x5A38	0x8BDF	# <CJK>
+0x5A39	0x8BE0	# <CJK>
+0x5A3A	0x8BE4	# <CJK>
+0x5A3B	0x8BE8	# <CJK>
+0x5A3C	0x8BE9	# <CJK>
+0x5A3D	0x8BEE	# <CJK>
+0x5A3E	0x8BF0	# <CJK>
+0x5A3F	0x8BF3	# <CJK>
+0x5A40	0x8BF6	# <CJK>
+0x5A41	0x8BF9	# <CJK>
+0x5A42	0x8BFC	# <CJK>
+0x5A43	0x8BFF	# <CJK>
+0x5A44	0x8C00	# <CJK>
+0x5A45	0x8C02	# <CJK>
+0x5A46	0x8C04	# <CJK>
+0x5A47	0x8C07	# <CJK>
+0x5A48	0x8C0C	# <CJK>
+0x5A49	0x8C0F	# <CJK>
+0x5A4A	0x8C11	# <CJK>
+0x5A4B	0x8C12	# <CJK>
+0x5A4C	0x8C14	# <CJK>
+0x5A4D	0x8C15	# <CJK>
+0x5A4E	0x8C16	# <CJK>
+0x5A4F	0x8C19	# <CJK>
+0x5A50	0x8C1B	# <CJK>
+0x5A51	0x8C18	# <CJK>
+0x5A52	0x8C1D	# <CJK>
+0x5A53	0x8C1F	# <CJK>
+0x5A54	0x8C20	# <CJK>
+0x5A55	0x8C21	# <CJK>
+0x5A56	0x8C25	# <CJK>
+0x5A57	0x8C27	# <CJK>
+0x5A58	0x8C2A	# <CJK>
+0x5A59	0x8C2B	# <CJK>
+0x5A5A	0x8C2E	# <CJK>
+0x5A5B	0x8C2F	# <CJK>
+0x5A5C	0x8C32	# <CJK>
+0x5A5D	0x8C33	# <CJK>
+0x5A5E	0x8C35	# <CJK>
+0x5A5F	0x8C36	# <CJK>
+0x5A60	0x5369	# <CJK>
+0x5A61	0x537A	# <CJK>
+0x5A62	0x961D	# <CJK>
+0x5A63	0x9622	# <CJK>
+0x5A64	0x9621	# <CJK>
+0x5A65	0x9631	# <CJK>
+0x5A66	0x962A	# <CJK>
+0x5A67	0x963D	# <CJK>
+0x5A68	0x963C	# <CJK>
+0x5A69	0x9642	# <CJK>
+0x5A6A	0x9649	# <CJK>
+0x5A6B	0x9654	# <CJK>
+0x5A6C	0x965F	# <CJK>
+0x5A6D	0x9667	# <CJK>
+0x5A6E	0x966C	# <CJK>
+0x5A6F	0x9672	# <CJK>
+0x5A70	0x9674	# <CJK>
+0x5A71	0x9688	# <CJK>
+0x5A72	0x968D	# <CJK>
+0x5A73	0x9697	# <CJK>
+0x5A74	0x96B0	# <CJK>
+0x5A75	0x9097	# <CJK>
+0x5A76	0x909B	# <CJK>
+0x5A77	0x909D	# <CJK>
+0x5A78	0x9099	# <CJK>
+0x5A79	0x90AC	# <CJK>
+0x5A7A	0x90A1	# <CJK>
+0x5A7B	0x90B4	# <CJK>
+0x5A7C	0x90B3	# <CJK>
+0x5A7D	0x90B6	# <CJK>
+0x5A7E	0x90BA	# <CJK>
+0x5B21	0x90B8	# <CJK>
+0x5B22	0x90B0	# <CJK>
+0x5B23	0x90CF	# <CJK>
+0x5B24	0x90C5	# <CJK>
+0x5B25	0x90BE	# <CJK>
+0x5B26	0x90D0	# <CJK>
+0x5B27	0x90C4	# <CJK>
+0x5B28	0x90C7	# <CJK>
+0x5B29	0x90D3	# <CJK>
+0x5B2A	0x90E6	# <CJK>
+0x5B2B	0x90E2	# <CJK>
+0x5B2C	0x90DC	# <CJK>
+0x5B2D	0x90D7	# <CJK>
+0x5B2E	0x90DB	# <CJK>
+0x5B2F	0x90EB	# <CJK>
+0x5B30	0x90EF	# <CJK>
+0x5B31	0x90FE	# <CJK>
+0x5B32	0x9104	# <CJK>
+0x5B33	0x9122	# <CJK>
+0x5B34	0x911E	# <CJK>
+0x5B35	0x9123	# <CJK>
+0x5B36	0x9131	# <CJK>
+0x5B37	0x912F	# <CJK>
+0x5B38	0x9139	# <CJK>
+0x5B39	0x9143	# <CJK>
+0x5B3A	0x9146	# <CJK>
+0x5B3B	0x520D	# <CJK>
+0x5B3C	0x5942	# <CJK>
+0x5B3D	0x52A2	# <CJK>
+0x5B3E	0x52AC	# <CJK>
+0x5B3F	0x52AD	# <CJK>
+0x5B40	0x52BE	# <CJK>
+0x5B41	0x54FF	# <CJK>
+0x5B42	0x52D0	# <CJK>
+0x5B43	0x52D6	# <CJK>
+0x5B44	0x52F0	# <CJK>
+0x5B45	0x53DF	# <CJK>
+0x5B46	0x71EE	# <CJK>
+0x5B47	0x77CD	# <CJK>
+0x5B48	0x5EF4	# <CJK>
+0x5B49	0x51F5	# <CJK>
+0x5B4A	0x51FC	# <CJK>
+0x5B4B	0x9B2F	# <CJK>
+0x5B4C	0x53B6	# <CJK>
+0x5B4D	0x5F01	# <CJK>
+0x5B4E	0x755A	# <CJK>
+0x5B4F	0x5DEF	# <CJK>
+0x5B50	0x574C	# <CJK>
+0x5B51	0x57A9	# <CJK>
+0x5B52	0x57A1	# <CJK>
+0x5B53	0x587E	# <CJK>
+0x5B54	0x58BC	# <CJK>
+0x5B55	0x58C5	# <CJK>
+0x5B56	0x58D1	# <CJK>
+0x5B57	0x5729	# <CJK>
+0x5B58	0x572C	# <CJK>
+0x5B59	0x572A	# <CJK>
+0x5B5A	0x5733	# <CJK>
+0x5B5B	0x5739	# <CJK>
+0x5B5C	0x572E	# <CJK>
+0x5B5D	0x572F	# <CJK>
+0x5B5E	0x575C	# <CJK>
+0x5B5F	0x573B	# <CJK>
+0x5B60	0x5742	# <CJK>
+0x5B61	0x5769	# <CJK>
+0x5B62	0x5785	# <CJK>
+0x5B63	0x576B	# <CJK>
+0x5B64	0x5786	# <CJK>
+0x5B65	0x577C	# <CJK>
+0x5B66	0x577B	# <CJK>
+0x5B67	0x5768	# <CJK>
+0x5B68	0x576D	# <CJK>
+0x5B69	0x5776	# <CJK>
+0x5B6A	0x5773	# <CJK>
+0x5B6B	0x57AD	# <CJK>
+0x5B6C	0x57A4	# <CJK>
+0x5B6D	0x578C	# <CJK>
+0x5B6E	0x57B2	# <CJK>
+0x5B6F	0x57CF	# <CJK>
+0x5B70	0x57A7	# <CJK>
+0x5B71	0x57B4	# <CJK>
+0x5B72	0x5793	# <CJK>
+0x5B73	0x57A0	# <CJK>
+0x5B74	0x57D5	# <CJK>
+0x5B75	0x57D8	# <CJK>
+0x5B76	0x57DA	# <CJK>
+0x5B77	0x57D9	# <CJK>
+0x5B78	0x57D2	# <CJK>
+0x5B79	0x57B8	# <CJK>
+0x5B7A	0x57F4	# <CJK>
+0x5B7B	0x57EF	# <CJK>
+0x5B7C	0x57F8	# <CJK>
+0x5B7D	0x57E4	# <CJK>
+0x5B7E	0x57DD	# <CJK>
+0x5C21	0x580B	# <CJK>
+0x5C22	0x580D	# <CJK>
+0x5C23	0x57FD	# <CJK>
+0x5C24	0x57ED	# <CJK>
+0x5C25	0x5800	# <CJK>
+0x5C26	0x581E	# <CJK>
+0x5C27	0x5819	# <CJK>
+0x5C28	0x5844	# <CJK>
+0x5C29	0x5820	# <CJK>
+0x5C2A	0x5865	# <CJK>
+0x5C2B	0x586C	# <CJK>
+0x5C2C	0x5881	# <CJK>
+0x5C2D	0x5889	# <CJK>
+0x5C2E	0x589A	# <CJK>
+0x5C2F	0x5880	# <CJK>
+0x5C30	0x99A8	# <CJK>
+0x5C31	0x9F19	# <CJK>
+0x5C32	0x61FF	# <CJK>
+0x5C33	0x8279	# <CJK>
+0x5C34	0x827D	# <CJK>
+0x5C35	0x827F	# <CJK>
+0x5C36	0x828F	# <CJK>
+0x5C37	0x828A	# <CJK>
+0x5C38	0x82A8	# <CJK>
+0x5C39	0x8284	# <CJK>
+0x5C3A	0x828E	# <CJK>
+0x5C3B	0x8291	# <CJK>
+0x5C3C	0x8297	# <CJK>
+0x5C3D	0x8299	# <CJK>
+0x5C3E	0x82AB	# <CJK>
+0x5C3F	0x82B8	# <CJK>
+0x5C40	0x82BE	# <CJK>
+0x5C41	0x82B0	# <CJK>
+0x5C42	0x82C8	# <CJK>
+0x5C43	0x82CA	# <CJK>
+0x5C44	0x82E3	# <CJK>
+0x5C45	0x8298	# <CJK>
+0x5C46	0x82B7	# <CJK>
+0x5C47	0x82AE	# <CJK>
+0x5C48	0x82CB	# <CJK>
+0x5C49	0x82CC	# <CJK>
+0x5C4A	0x82C1	# <CJK>
+0x5C4B	0x82A9	# <CJK>
+0x5C4C	0x82B4	# <CJK>
+0x5C4D	0x82A1	# <CJK>
+0x5C4E	0x82AA	# <CJK>
+0x5C4F	0x829F	# <CJK>
+0x5C50	0x82C4	# <CJK>
+0x5C51	0x82CE	# <CJK>
+0x5C52	0x82A4	# <CJK>
+0x5C53	0x82E1	# <CJK>
+0x5C54	0x8309	# <CJK>
+0x5C55	0x82F7	# <CJK>
+0x5C56	0x82E4	# <CJK>
+0x5C57	0x830F	# <CJK>
+0x5C58	0x8307	# <CJK>
+0x5C59	0x82DC	# <CJK>
+0x5C5A	0x82F4	# <CJK>
+0x5C5B	0x82D2	# <CJK>
+0x5C5C	0x82D8	# <CJK>
+0x5C5D	0x830C	# <CJK>
+0x5C5E	0x82FB	# <CJK>
+0x5C5F	0x82D3	# <CJK>
+0x5C60	0x8311	# <CJK>
+0x5C61	0x831A	# <CJK>
+0x5C62	0x8306	# <CJK>
+0x5C63	0x8314	# <CJK>
+0x5C64	0x8315	# <CJK>
+0x5C65	0x82E0	# <CJK>
+0x5C66	0x82D5	# <CJK>
+0x5C67	0x831C	# <CJK>
+0x5C68	0x8351	# <CJK>
+0x5C69	0x835B	# <CJK>
+0x5C6A	0x835C	# <CJK>
+0x5C6B	0x8308	# <CJK>
+0x5C6C	0x8392	# <CJK>
+0x5C6D	0x833C	# <CJK>
+0x5C6E	0x8334	# <CJK>
+0x5C6F	0x8331	# <CJK>
+0x5C70	0x839B	# <CJK>
+0x5C71	0x835E	# <CJK>
+0x5C72	0x832F	# <CJK>
+0x5C73	0x834F	# <CJK>
+0x5C74	0x8347	# <CJK>
+0x5C75	0x8343	# <CJK>
+0x5C76	0x835F	# <CJK>
+0x5C77	0x8340	# <CJK>
+0x5C78	0x8317	# <CJK>
+0x5C79	0x8360	# <CJK>
+0x5C7A	0x832D	# <CJK>
+0x5C7B	0x833A	# <CJK>
+0x5C7C	0x8333	# <CJK>
+0x5C7D	0x8366	# <CJK>
+0x5C7E	0x8365	# <CJK>
+0x5D21	0x8368	# <CJK>
+0x5D22	0x831B	# <CJK>
+0x5D23	0x8369	# <CJK>
+0x5D24	0x836C	# <CJK>
+0x5D25	0x836A	# <CJK>
+0x5D26	0x836D	# <CJK>
+0x5D27	0x836E	# <CJK>
+0x5D28	0x83B0	# <CJK>
+0x5D29	0x8378	# <CJK>
+0x5D2A	0x83B3	# <CJK>
+0x5D2B	0x83B4	# <CJK>
+0x5D2C	0x83A0	# <CJK>
+0x5D2D	0x83AA	# <CJK>
+0x5D2E	0x8393	# <CJK>
+0x5D2F	0x839C	# <CJK>
+0x5D30	0x8385	# <CJK>
+0x5D31	0x837C	# <CJK>
+0x5D32	0x83B6	# <CJK>
+0x5D33	0x83A9	# <CJK>
+0x5D34	0x837D	# <CJK>
+0x5D35	0x83B8	# <CJK>
+0x5D36	0x837B	# <CJK>
+0x5D37	0x8398	# <CJK>
+0x5D38	0x839E	# <CJK>
+0x5D39	0x83A8	# <CJK>
+0x5D3A	0x83BA	# <CJK>
+0x5D3B	0x83BC	# <CJK>
+0x5D3C	0x83C1	# <CJK>
+0x5D3D	0x8401	# <CJK>
+0x5D3E	0x83E5	# <CJK>
+0x5D3F	0x83D8	# <CJK>
+0x5D40	0x5807	# <CJK>
+0x5D41	0x8418	# <CJK>
+0x5D42	0x840B	# <CJK>
+0x5D43	0x83DD	# <CJK>
+0x5D44	0x83FD	# <CJK>
+0x5D45	0x83D6	# <CJK>
+0x5D46	0x841C	# <CJK>
+0x5D47	0x8438	# <CJK>
+0x5D48	0x8411	# <CJK>
+0x5D49	0x8406	# <CJK>
+0x5D4A	0x83D4	# <CJK>
+0x5D4B	0x83DF	# <CJK>
+0x5D4C	0x840F	# <CJK>
+0x5D4D	0x8403	# <CJK>
+0x5D4E	0x83F8	# <CJK>
+0x5D4F	0x83F9	# <CJK>
+0x5D50	0x83EA	# <CJK>
+0x5D51	0x83C5	# <CJK>
+0x5D52	0x83C0	# <CJK>
+0x5D53	0x8426	# <CJK>
+0x5D54	0x83F0	# <CJK>
+0x5D55	0x83E1	# <CJK>
+0x5D56	0x845C	# <CJK>
+0x5D57	0x8451	# <CJK>
+0x5D58	0x845A	# <CJK>
+0x5D59	0x8459	# <CJK>
+0x5D5A	0x8473	# <CJK>
+0x5D5B	0x8487	# <CJK>
+0x5D5C	0x8488	# <CJK>
+0x5D5D	0x847A	# <CJK>
+0x5D5E	0x8489	# <CJK>
+0x5D5F	0x8478	# <CJK>
+0x5D60	0x843C	# <CJK>
+0x5D61	0x8446	# <CJK>
+0x5D62	0x8469	# <CJK>
+0x5D63	0x8476	# <CJK>
+0x5D64	0x848C	# <CJK>
+0x5D65	0x848E	# <CJK>
+0x5D66	0x8431	# <CJK>
+0x5D67	0x846D	# <CJK>
+0x5D68	0x84C1	# <CJK>
+0x5D69	0x84CD	# <CJK>
+0x5D6A	0x84D0	# <CJK>
+0x5D6B	0x84E6	# <CJK>
+0x5D6C	0x84BD	# <CJK>
+0x5D6D	0x84D3	# <CJK>
+0x5D6E	0x84CA	# <CJK>
+0x5D6F	0x84BF	# <CJK>
+0x5D70	0x84BA	# <CJK>
+0x5D71	0x84E0	# <CJK>
+0x5D72	0x84A1	# <CJK>
+0x5D73	0x84B9	# <CJK>
+0x5D74	0x84B4	# <CJK>
+0x5D75	0x8497	# <CJK>
+0x5D76	0x84E5	# <CJK>
+0x5D77	0x84E3	# <CJK>
+0x5D78	0x850C	# <CJK>
+0x5D79	0x750D	# <CJK>
+0x5D7A	0x8538	# <CJK>
+0x5D7B	0x84F0	# <CJK>
+0x5D7C	0x8539	# <CJK>
+0x5D7D	0x851F	# <CJK>
+0x5D7E	0x853A	# <CJK>
+0x5E21	0x8556	# <CJK>
+0x5E22	0x853B	# <CJK>
+0x5E23	0x84FF	# <CJK>
+0x5E24	0x84FC	# <CJK>
+0x5E25	0x8559	# <CJK>
+0x5E26	0x8548	# <CJK>
+0x5E27	0x8568	# <CJK>
+0x5E28	0x8564	# <CJK>
+0x5E29	0x855E	# <CJK>
+0x5E2A	0x857A	# <CJK>
+0x5E2B	0x77A2	# <CJK>
+0x5E2C	0x8543	# <CJK>
+0x5E2D	0x8572	# <CJK>
+0x5E2E	0x857B	# <CJK>
+0x5E2F	0x85A4	# <CJK>
+0x5E30	0x85A8	# <CJK>
+0x5E31	0x8587	# <CJK>
+0x5E32	0x858F	# <CJK>
+0x5E33	0x8579	# <CJK>
+0x5E34	0x85AE	# <CJK>
+0x5E35	0x859C	# <CJK>
+0x5E36	0x8585	# <CJK>
+0x5E37	0x85B9	# <CJK>
+0x5E38	0x85B7	# <CJK>
+0x5E39	0x85B0	# <CJK>
+0x5E3A	0x85D3	# <CJK>
+0x5E3B	0x85C1	# <CJK>
+0x5E3C	0x85DC	# <CJK>
+0x5E3D	0x85FF	# <CJK>
+0x5E3E	0x8627	# <CJK>
+0x5E3F	0x8605	# <CJK>
+0x5E40	0x8629	# <CJK>
+0x5E41	0x8616	# <CJK>
+0x5E42	0x863C	# <CJK>
+0x5E43	0x5EFE	# <CJK>
+0x5E44	0x5F08	# <CJK>
+0x5E45	0x593C	# <CJK>
+0x5E46	0x5941	# <CJK>
+0x5E47	0x8037	# <CJK>
+0x5E48	0x5955	# <CJK>
+0x5E49	0x595A	# <CJK>
+0x5E4A	0x5958	# <CJK>
+0x5E4B	0x530F	# <CJK>
+0x5E4C	0x5C22	# <CJK>
+0x5E4D	0x5C25	# <CJK>
+0x5E4E	0x5C2C	# <CJK>
+0x5E4F	0x5C34	# <CJK>
+0x5E50	0x624C	# <CJK>
+0x5E51	0x626A	# <CJK>
+0x5E52	0x629F	# <CJK>
+0x5E53	0x62BB	# <CJK>
+0x5E54	0x62CA	# <CJK>
+0x5E55	0x62DA	# <CJK>
+0x5E56	0x62D7	# <CJK>
+0x5E57	0x62EE	# <CJK>
+0x5E58	0x6322	# <CJK>
+0x5E59	0x62F6	# <CJK>
+0x5E5A	0x6339	# <CJK>
+0x5E5B	0x634B	# <CJK>
+0x5E5C	0x6343	# <CJK>
+0x5E5D	0x63AD	# <CJK>
+0x5E5E	0x63F6	# <CJK>
+0x5E5F	0x6371	# <CJK>
+0x5E60	0x637A	# <CJK>
+0x5E61	0x638E	# <CJK>
+0x5E62	0x63B4	# <CJK>
+0x5E63	0x636D	# <CJK>
+0x5E64	0x63AC	# <CJK>
+0x5E65	0x638A	# <CJK>
+0x5E66	0x6369	# <CJK>
+0x5E67	0x63AE	# <CJK>
+0x5E68	0x63BC	# <CJK>
+0x5E69	0x63F2	# <CJK>
+0x5E6A	0x63F8	# <CJK>
+0x5E6B	0x63E0	# <CJK>
+0x5E6C	0x63FF	# <CJK>
+0x5E6D	0x63C4	# <CJK>
+0x5E6E	0x63DE	# <CJK>
+0x5E6F	0x63CE	# <CJK>
+0x5E70	0x6452	# <CJK>
+0x5E71	0x63C6	# <CJK>
+0x5E72	0x63BE	# <CJK>
+0x5E73	0x6445	# <CJK>
+0x5E74	0x6441	# <CJK>
+0x5E75	0x640B	# <CJK>
+0x5E76	0x641B	# <CJK>
+0x5E77	0x6420	# <CJK>
+0x5E78	0x640C	# <CJK>
+0x5E79	0x6426	# <CJK>
+0x5E7A	0x6421	# <CJK>
+0x5E7B	0x645E	# <CJK>
+0x5E7C	0x6484	# <CJK>
+0x5E7D	0x646D	# <CJK>
+0x5E7E	0x6496	# <CJK>
+0x5F21	0x647A	# <CJK>
+0x5F22	0x64B7	# <CJK>
+0x5F23	0x64B8	# <CJK>
+0x5F24	0x6499	# <CJK>
+0x5F25	0x64BA	# <CJK>
+0x5F26	0x64C0	# <CJK>
+0x5F27	0x64D0	# <CJK>
+0x5F28	0x64D7	# <CJK>
+0x5F29	0x64E4	# <CJK>
+0x5F2A	0x64E2	# <CJK>
+0x5F2B	0x6509	# <CJK>
+0x5F2C	0x6525	# <CJK>
+0x5F2D	0x652E	# <CJK>
+0x5F2E	0x5F0B	# <CJK>
+0x5F2F	0x5FD2	# <CJK>
+0x5F30	0x7519	# <CJK>
+0x5F31	0x5F11	# <CJK>
+0x5F32	0x535F	# <CJK>
+0x5F33	0x53F1	# <CJK>
+0x5F34	0x53FD	# <CJK>
+0x5F35	0x53E9	# <CJK>
+0x5F36	0x53E8	# <CJK>
+0x5F37	0x53FB	# <CJK>
+0x5F38	0x5412	# <CJK>
+0x5F39	0x5416	# <CJK>
+0x5F3A	0x5406	# <CJK>
+0x5F3B	0x544B	# <CJK>
+0x5F3C	0x5452	# <CJK>
+0x5F3D	0x5453	# <CJK>
+0x5F3E	0x5454	# <CJK>
+0x5F3F	0x5456	# <CJK>
+0x5F40	0x5443	# <CJK>
+0x5F41	0x5421	# <CJK>
+0x5F42	0x5457	# <CJK>
+0x5F43	0x5459	# <CJK>
+0x5F44	0x5423	# <CJK>
+0x5F45	0x5432	# <CJK>
+0x5F46	0x5482	# <CJK>
+0x5F47	0x5494	# <CJK>
+0x5F48	0x5477	# <CJK>
+0x5F49	0x5471	# <CJK>
+0x5F4A	0x5464	# <CJK>
+0x5F4B	0x549A	# <CJK>
+0x5F4C	0x549B	# <CJK>
+0x5F4D	0x5484	# <CJK>
+0x5F4E	0x5476	# <CJK>
+0x5F4F	0x5466	# <CJK>
+0x5F50	0x549D	# <CJK>
+0x5F51	0x54D0	# <CJK>
+0x5F52	0x54AD	# <CJK>
+0x5F53	0x54C2	# <CJK>
+0x5F54	0x54B4	# <CJK>
+0x5F55	0x54D2	# <CJK>
+0x5F56	0x54A7	# <CJK>
+0x5F57	0x54A6	# <CJK>
+0x5F58	0x54D3	# <CJK>
+0x5F59	0x54D4	# <CJK>
+0x5F5A	0x5472	# <CJK>
+0x5F5B	0x54A3	# <CJK>
+0x5F5C	0x54D5	# <CJK>
+0x5F5D	0x54BB	# <CJK>
+0x5F5E	0x54BF	# <CJK>
+0x5F5F	0x54CC	# <CJK>
+0x5F60	0x54D9	# <CJK>
+0x5F61	0x54DA	# <CJK>
+0x5F62	0x54DC	# <CJK>
+0x5F63	0x54A9	# <CJK>
+0x5F64	0x54AA	# <CJK>
+0x5F65	0x54A4	# <CJK>
+0x5F66	0x54DD	# <CJK>
+0x5F67	0x54CF	# <CJK>
+0x5F68	0x54DE	# <CJK>
+0x5F69	0x551B	# <CJK>
+0x5F6A	0x54E7	# <CJK>
+0x5F6B	0x5520	# <CJK>
+0x5F6C	0x54FD	# <CJK>
+0x5F6D	0x5514	# <CJK>
+0x5F6E	0x54F3	# <CJK>
+0x5F6F	0x5522	# <CJK>
+0x5F70	0x5523	# <CJK>
+0x5F71	0x550F	# <CJK>
+0x5F72	0x5511	# <CJK>
+0x5F73	0x5527	# <CJK>
+0x5F74	0x552A	# <CJK>
+0x5F75	0x5567	# <CJK>
+0x5F76	0x558F	# <CJK>
+0x5F77	0x55B5	# <CJK>
+0x5F78	0x5549	# <CJK>
+0x5F79	0x556D	# <CJK>
+0x5F7A	0x5541	# <CJK>
+0x5F7B	0x5555	# <CJK>
+0x5F7C	0x553F	# <CJK>
+0x5F7D	0x5550	# <CJK>
+0x5F7E	0x553C	# <CJK>
+0x6021	0x5537	# <CJK>
+0x6022	0x5556	# <CJK>
+0x6023	0x5575	# <CJK>
+0x6024	0x5576	# <CJK>
+0x6025	0x5577	# <CJK>
+0x6026	0x5533	# <CJK>
+0x6027	0x5530	# <CJK>
+0x6028	0x555C	# <CJK>
+0x6029	0x558B	# <CJK>
+0x602A	0x55D2	# <CJK>
+0x602B	0x5583	# <CJK>
+0x602C	0x55B1	# <CJK>
+0x602D	0x55B9	# <CJK>
+0x602E	0x5588	# <CJK>
+0x602F	0x5581	# <CJK>
+0x6030	0x559F	# <CJK>
+0x6031	0x557E	# <CJK>
+0x6032	0x55D6	# <CJK>
+0x6033	0x5591	# <CJK>
+0x6034	0x557B	# <CJK>
+0x6035	0x55DF	# <CJK>
+0x6036	0x55BD	# <CJK>
+0x6037	0x55BE	# <CJK>
+0x6038	0x5594	# <CJK>
+0x6039	0x5599	# <CJK>
+0x603A	0x55EA	# <CJK>
+0x603B	0x55F7	# <CJK>
+0x603C	0x55C9	# <CJK>
+0x603D	0x561F	# <CJK>
+0x603E	0x55D1	# <CJK>
+0x603F	0x55EB	# <CJK>
+0x6040	0x55EC	# <CJK>
+0x6041	0x55D4	# <CJK>
+0x6042	0x55E6	# <CJK>
+0x6043	0x55DD	# <CJK>
+0x6044	0x55C4	# <CJK>
+0x6045	0x55EF	# <CJK>
+0x6046	0x55E5	# <CJK>
+0x6047	0x55F2	# <CJK>
+0x6048	0x55F3	# <CJK>
+0x6049	0x55CC	# <CJK>
+0x604A	0x55CD	# <CJK>
+0x604B	0x55E8	# <CJK>
+0x604C	0x55F5	# <CJK>
+0x604D	0x55E4	# <CJK>
+0x604E	0x8F94	# <CJK>
+0x604F	0x561E	# <CJK>
+0x6050	0x5608	# <CJK>
+0x6051	0x560C	# <CJK>
+0x6052	0x5601	# <CJK>
+0x6053	0x5624	# <CJK>
+0x6054	0x5623	# <CJK>
+0x6055	0x55FE	# <CJK>
+0x6056	0x5600	# <CJK>
+0x6057	0x5627	# <CJK>
+0x6058	0x562D	# <CJK>
+0x6059	0x5658	# <CJK>
+0x605A	0x5639	# <CJK>
+0x605B	0x5657	# <CJK>
+0x605C	0x562C	# <CJK>
+0x605D	0x564D	# <CJK>
+0x605E	0x5662	# <CJK>
+0x605F	0x5659	# <CJK>
+0x6060	0x565C	# <CJK>
+0x6061	0x564C	# <CJK>
+0x6062	0x5654	# <CJK>
+0x6063	0x5686	# <CJK>
+0x6064	0x5664	# <CJK>
+0x6065	0x5671	# <CJK>
+0x6066	0x566B	# <CJK>
+0x6067	0x567B	# <CJK>
+0x6068	0x567C	# <CJK>
+0x6069	0x5685	# <CJK>
+0x606A	0x5693	# <CJK>
+0x606B	0x56AF	# <CJK>
+0x606C	0x56D4	# <CJK>
+0x606D	0x56D7	# <CJK>
+0x606E	0x56DD	# <CJK>
+0x606F	0x56E1	# <CJK>
+0x6070	0x56F5	# <CJK>
+0x6071	0x56EB	# <CJK>
+0x6072	0x56F9	# <CJK>
+0x6073	0x56FF	# <CJK>
+0x6074	0x5704	# <CJK>
+0x6075	0x570A	# <CJK>
+0x6076	0x5709	# <CJK>
+0x6077	0x571C	# <CJK>
+0x6078	0x5E0F	# <CJK>
+0x6079	0x5E19	# <CJK>
+0x607A	0x5E14	# <CJK>
+0x607B	0x5E11	# <CJK>
+0x607C	0x5E31	# <CJK>
+0x607D	0x5E3B	# <CJK>
+0x607E	0x5E3C	# <CJK>
+0x6121	0x5E37	# <CJK>
+0x6122	0x5E44	# <CJK>
+0x6123	0x5E54	# <CJK>
+0x6124	0x5E5B	# <CJK>
+0x6125	0x5E5E	# <CJK>
+0x6126	0x5E61	# <CJK>
+0x6127	0x5C8C	# <CJK>
+0x6128	0x5C7A	# <CJK>
+0x6129	0x5C8D	# <CJK>
+0x612A	0x5C90	# <CJK>
+0x612B	0x5C96	# <CJK>
+0x612C	0x5C88	# <CJK>
+0x612D	0x5C98	# <CJK>
+0x612E	0x5C99	# <CJK>
+0x612F	0x5C91	# <CJK>
+0x6130	0x5C9A	# <CJK>
+0x6131	0x5C9C	# <CJK>
+0x6132	0x5CB5	# <CJK>
+0x6133	0x5CA2	# <CJK>
+0x6134	0x5CBD	# <CJK>
+0x6135	0x5CAC	# <CJK>
+0x6136	0x5CAB	# <CJK>
+0x6137	0x5CB1	# <CJK>
+0x6138	0x5CA3	# <CJK>
+0x6139	0x5CC1	# <CJK>
+0x613A	0x5CB7	# <CJK>
+0x613B	0x5CC4	# <CJK>
+0x613C	0x5CD2	# <CJK>
+0x613D	0x5CE4	# <CJK>
+0x613E	0x5CCB	# <CJK>
+0x613F	0x5CE5	# <CJK>
+0x6140	0x5D02	# <CJK>
+0x6141	0x5D03	# <CJK>
+0x6142	0x5D27	# <CJK>
+0x6143	0x5D26	# <CJK>
+0x6144	0x5D2E	# <CJK>
+0x6145	0x5D24	# <CJK>
+0x6146	0x5D1E	# <CJK>
+0x6147	0x5D06	# <CJK>
+0x6148	0x5D1B	# <CJK>
+0x6149	0x5D58	# <CJK>
+0x614A	0x5D3E	# <CJK>
+0x614B	0x5D34	# <CJK>
+0x614C	0x5D3D	# <CJK>
+0x614D	0x5D6C	# <CJK>
+0x614E	0x5D5B	# <CJK>
+0x614F	0x5D6F	# <CJK>
+0x6150	0x5D5D	# <CJK>
+0x6151	0x5D6B	# <CJK>
+0x6152	0x5D4B	# <CJK>
+0x6153	0x5D4A	# <CJK>
+0x6154	0x5D69	# <CJK>
+0x6155	0x5D74	# <CJK>
+0x6156	0x5D82	# <CJK>
+0x6157	0x5D99	# <CJK>
+0x6158	0x5D9D	# <CJK>
+0x6159	0x8C73	# <CJK>
+0x615A	0x5DB7	# <CJK>
+0x615B	0x5DC5	# <CJK>
+0x615C	0x5F73	# <CJK>
+0x615D	0x5F77	# <CJK>
+0x615E	0x5F82	# <CJK>
+0x615F	0x5F87	# <CJK>
+0x6160	0x5F89	# <CJK>
+0x6161	0x5F8C	# <CJK>
+0x6162	0x5F95	# <CJK>
+0x6163	0x5F99	# <CJK>
+0x6164	0x5F9C	# <CJK>
+0x6165	0x5FA8	# <CJK>
+0x6166	0x5FAD	# <CJK>
+0x6167	0x5FB5	# <CJK>
+0x6168	0x5FBC	# <CJK>
+0x6169	0x8862	# <CJK>
+0x616A	0x5F61	# <CJK>
+0x616B	0x72AD	# <CJK>
+0x616C	0x72B0	# <CJK>
+0x616D	0x72B4	# <CJK>
+0x616E	0x72B7	# <CJK>
+0x616F	0x72B8	# <CJK>
+0x6170	0x72C3	# <CJK>
+0x6171	0x72C1	# <CJK>
+0x6172	0x72CE	# <CJK>
+0x6173	0x72CD	# <CJK>
+0x6174	0x72D2	# <CJK>
+0x6175	0x72E8	# <CJK>
+0x6176	0x72EF	# <CJK>
+0x6177	0x72E9	# <CJK>
+0x6178	0x72F2	# <CJK>
+0x6179	0x72F4	# <CJK>
+0x617A	0x72F7	# <CJK>
+0x617B	0x7301	# <CJK>
+0x617C	0x72F3	# <CJK>
+0x617D	0x7303	# <CJK>
+0x617E	0x72FA	# <CJK>
+0x6221	0x72FB	# <CJK>
+0x6222	0x7317	# <CJK>
+0x6223	0x7313	# <CJK>
+0x6224	0x7321	# <CJK>
+0x6225	0x730A	# <CJK>
+0x6226	0x731E	# <CJK>
+0x6227	0x731D	# <CJK>
+0x6228	0x7315	# <CJK>
+0x6229	0x7322	# <CJK>
+0x622A	0x7339	# <CJK>
+0x622B	0x7325	# <CJK>
+0x622C	0x732C	# <CJK>
+0x622D	0x7338	# <CJK>
+0x622E	0x7331	# <CJK>
+0x622F	0x7350	# <CJK>
+0x6230	0x734D	# <CJK>
+0x6231	0x7357	# <CJK>
+0x6232	0x7360	# <CJK>
+0x6233	0x736C	# <CJK>
+0x6234	0x736F	# <CJK>
+0x6235	0x737E	# <CJK>
+0x6236	0x821B	# <CJK>
+0x6237	0x5925	# <CJK>
+0x6238	0x98E7	# <CJK>
+0x6239	0x5924	# <CJK>
+0x623A	0x5902	# <CJK>
+0x623B	0x9963	# <CJK>
+0x623C	0x9967	# <CJK>
+0x623D	0x9968	# <CJK>
+0x623E	0x9969	# <CJK>
+0x623F	0x996A	# <CJK>
+0x6240	0x996B	# <CJK>
+0x6241	0x996C	# <CJK>
+0x6242	0x9974	# <CJK>
+0x6243	0x9977	# <CJK>
+0x6244	0x997D	# <CJK>
+0x6245	0x9980	# <CJK>
+0x6246	0x9984	# <CJK>
+0x6247	0x9987	# <CJK>
+0x6248	0x998A	# <CJK>
+0x6249	0x998D	# <CJK>
+0x624A	0x9990	# <CJK>
+0x624B	0x9991	# <CJK>
+0x624C	0x9993	# <CJK>
+0x624D	0x9994	# <CJK>
+0x624E	0x9995	# <CJK>
+0x624F	0x5E80	# <CJK>
+0x6250	0x5E91	# <CJK>
+0x6251	0x5E8B	# <CJK>
+0x6252	0x5E96	# <CJK>
+0x6253	0x5EA5	# <CJK>
+0x6254	0x5EA0	# <CJK>
+0x6255	0x5EB9	# <CJK>
+0x6256	0x5EB5	# <CJK>
+0x6257	0x5EBE	# <CJK>
+0x6258	0x5EB3	# <CJK>
+0x6259	0x8D53	# <CJK>
+0x625A	0x5ED2	# <CJK>
+0x625B	0x5ED1	# <CJK>
+0x625C	0x5EDB	# <CJK>
+0x625D	0x5EE8	# <CJK>
+0x625E	0x5EEA	# <CJK>
+0x625F	0x81BA	# <CJK>
+0x6260	0x5FC4	# <CJK>
+0x6261	0x5FC9	# <CJK>
+0x6262	0x5FD6	# <CJK>
+0x6263	0x5FCF	# <CJK>
+0x6264	0x6003	# <CJK>
+0x6265	0x5FEE	# <CJK>
+0x6266	0x6004	# <CJK>
+0x6267	0x5FE1	# <CJK>
+0x6268	0x5FE4	# <CJK>
+0x6269	0x5FFE	# <CJK>
+0x626A	0x6005	# <CJK>
+0x626B	0x6006	# <CJK>
+0x626C	0x5FEA	# <CJK>
+0x626D	0x5FED	# <CJK>
+0x626E	0x5FF8	# <CJK>
+0x626F	0x6019	# <CJK>
+0x6270	0x6035	# <CJK>
+0x6271	0x6026	# <CJK>
+0x6272	0x601B	# <CJK>
+0x6273	0x600F	# <CJK>
+0x6274	0x600D	# <CJK>
+0x6275	0x6029	# <CJK>
+0x6276	0x602B	# <CJK>
+0x6277	0x600A	# <CJK>
+0x6278	0x603F	# <CJK>
+0x6279	0x6021	# <CJK>
+0x627A	0x6078	# <CJK>
+0x627B	0x6079	# <CJK>
+0x627C	0x607B	# <CJK>
+0x627D	0x607A	# <CJK>
+0x627E	0x6042	# <CJK>
+0x6321	0x606A	# <CJK>
+0x6322	0x607D	# <CJK>
+0x6323	0x6096	# <CJK>
+0x6324	0x609A	# <CJK>
+0x6325	0x60AD	# <CJK>
+0x6326	0x609D	# <CJK>
+0x6327	0x6083	# <CJK>
+0x6328	0x6092	# <CJK>
+0x6329	0x608C	# <CJK>
+0x632A	0x609B	# <CJK>
+0x632B	0x60EC	# <CJK>
+0x632C	0x60BB	# <CJK>
+0x632D	0x60B1	# <CJK>
+0x632E	0x60DD	# <CJK>
+0x632F	0x60D8	# <CJK>
+0x6330	0x60C6	# <CJK>
+0x6331	0x60DA	# <CJK>
+0x6332	0x60B4	# <CJK>
+0x6333	0x6120	# <CJK>
+0x6334	0x6126	# <CJK>
+0x6335	0x6115	# <CJK>
+0x6336	0x6123	# <CJK>
+0x6337	0x60F4	# <CJK>
+0x6338	0x6100	# <CJK>
+0x6339	0x610E	# <CJK>
+0x633A	0x612B	# <CJK>
+0x633B	0x614A	# <CJK>
+0x633C	0x6175	# <CJK>
+0x633D	0x61AC	# <CJK>
+0x633E	0x6194	# <CJK>
+0x633F	0x61A7	# <CJK>
+0x6340	0x61B7	# <CJK>
+0x6341	0x61D4	# <CJK>
+0x6342	0x61F5	# <CJK>
+0x6343	0x5FDD	# <CJK>
+0x6344	0x96B3	# <CJK>
+0x6345	0x95E9	# <CJK>
+0x6346	0x95EB	# <CJK>
+0x6347	0x95F1	# <CJK>
+0x6348	0x95F3	# <CJK>
+0x6349	0x95F5	# <CJK>
+0x634A	0x95F6	# <CJK>
+0x634B	0x95FC	# <CJK>
+0x634C	0x95FE	# <CJK>
+0x634D	0x9603	# <CJK>
+0x634E	0x9604	# <CJK>
+0x634F	0x9606	# <CJK>
+0x6350	0x9608	# <CJK>
+0x6351	0x960A	# <CJK>
+0x6352	0x960B	# <CJK>
+0x6353	0x960C	# <CJK>
+0x6354	0x960D	# <CJK>
+0x6355	0x960F	# <CJK>
+0x6356	0x9612	# <CJK>
+0x6357	0x9615	# <CJK>
+0x6358	0x9616	# <CJK>
+0x6359	0x9617	# <CJK>
+0x635A	0x9619	# <CJK>
+0x635B	0x961A	# <CJK>
+0x635C	0x4E2C	# <CJK>
+0x635D	0x723F	# <CJK>
+0x635E	0x6215	# <CJK>
+0x635F	0x6C35	# <CJK>
+0x6360	0x6C54	# <CJK>
+0x6361	0x6C5C	# <CJK>
+0x6362	0x6C4A	# <CJK>
+0x6363	0x6CA3	# <CJK>
+0x6364	0x6C85	# <CJK>
+0x6365	0x6C90	# <CJK>
+0x6366	0x6C94	# <CJK>
+0x6367	0x6C8C	# <CJK>
+0x6368	0x6C68	# <CJK>
+0x6369	0x6C69	# <CJK>
+0x636A	0x6C74	# <CJK>
+0x636B	0x6C76	# <CJK>
+0x636C	0x6C86	# <CJK>
+0x636D	0x6CA9	# <CJK>
+0x636E	0x6CD0	# <CJK>
+0x636F	0x6CD4	# <CJK>
+0x6370	0x6CAD	# <CJK>
+0x6371	0x6CF7	# <CJK>
+0x6372	0x6CF8	# <CJK>
+0x6373	0x6CF1	# <CJK>
+0x6374	0x6CD7	# <CJK>
+0x6375	0x6CB2	# <CJK>
+0x6376	0x6CE0	# <CJK>
+0x6377	0x6CD6	# <CJK>
+0x6378	0x6CFA	# <CJK>
+0x6379	0x6CEB	# <CJK>
+0x637A	0x6CEE	# <CJK>
+0x637B	0x6CB1	# <CJK>
+0x637C	0x6CD3	# <CJK>
+0x637D	0x6CEF	# <CJK>
+0x637E	0x6CFE	# <CJK>
+0x6421	0x6D39	# <CJK>
+0x6422	0x6D27	# <CJK>
+0x6423	0x6D0C	# <CJK>
+0x6424	0x6D43	# <CJK>
+0x6425	0x6D48	# <CJK>
+0x6426	0x6D07	# <CJK>
+0x6427	0x6D04	# <CJK>
+0x6428	0x6D19	# <CJK>
+0x6429	0x6D0E	# <CJK>
+0x642A	0x6D2B	# <CJK>
+0x642B	0x6D4D	# <CJK>
+0x642C	0x6D2E	# <CJK>
+0x642D	0x6D35	# <CJK>
+0x642E	0x6D1A	# <CJK>
+0x642F	0x6D4F	# <CJK>
+0x6430	0x6D52	# <CJK>
+0x6431	0x6D54	# <CJK>
+0x6432	0x6D33	# <CJK>
+0x6433	0x6D91	# <CJK>
+0x6434	0x6D6F	# <CJK>
+0x6435	0x6D9E	# <CJK>
+0x6436	0x6DA0	# <CJK>
+0x6437	0x6D5E	# <CJK>
+0x6438	0x6D93	# <CJK>
+0x6439	0x6D94	# <CJK>
+0x643A	0x6D5C	# <CJK>
+0x643B	0x6D60	# <CJK>
+0x643C	0x6D7C	# <CJK>
+0x643D	0x6D63	# <CJK>
+0x643E	0x6E1A	# <CJK>
+0x643F	0x6DC7	# <CJK>
+0x6440	0x6DC5	# <CJK>
+0x6441	0x6DDE	# <CJK>
+0x6442	0x6E0E	# <CJK>
+0x6443	0x6DBF	# <CJK>
+0x6444	0x6DE0	# <CJK>
+0x6445	0x6E11	# <CJK>
+0x6446	0x6DE6	# <CJK>
+0x6447	0x6DDD	# <CJK>
+0x6448	0x6DD9	# <CJK>
+0x6449	0x6E16	# <CJK>
+0x644A	0x6DAB	# <CJK>
+0x644B	0x6E0C	# <CJK>
+0x644C	0x6DAE	# <CJK>
+0x644D	0x6E2B	# <CJK>
+0x644E	0x6E6E	# <CJK>
+0x644F	0x6E4E	# <CJK>
+0x6450	0x6E6B	# <CJK>
+0x6451	0x6EB2	# <CJK>
+0x6452	0x6E5F	# <CJK>
+0x6453	0x6E86	# <CJK>
+0x6454	0x6E53	# <CJK>
+0x6455	0x6E54	# <CJK>
+0x6456	0x6E32	# <CJK>
+0x6457	0x6E25	# <CJK>
+0x6458	0x6E44	# <CJK>
+0x6459	0x6EDF	# <CJK>
+0x645A	0x6EB1	# <CJK>
+0x645B	0x6E98	# <CJK>
+0x645C	0x6EE0	# <CJK>
+0x645D	0x6F2D	# <CJK>
+0x645E	0x6EE2	# <CJK>
+0x645F	0x6EA5	# <CJK>
+0x6460	0x6EA7	# <CJK>
+0x6461	0x6EBD	# <CJK>
+0x6462	0x6EBB	# <CJK>
+0x6463	0x6EB7	# <CJK>
+0x6464	0x6ED7	# <CJK>
+0x6465	0x6EB4	# <CJK>
+0x6466	0x6ECF	# <CJK>
+0x6467	0x6E8F	# <CJK>
+0x6468	0x6EC2	# <CJK>
+0x6469	0x6E9F	# <CJK>
+0x646A	0x6F62	# <CJK>
+0x646B	0x6F46	# <CJK>
+0x646C	0x6F47	# <CJK>
+0x646D	0x6F24	# <CJK>
+0x646E	0x6F15	# <CJK>
+0x646F	0x6EF9	# <CJK>
+0x6470	0x6F2F	# <CJK>
+0x6471	0x6F36	# <CJK>
+0x6472	0x6F4B	# <CJK>
+0x6473	0x6F74	# <CJK>
+0x6474	0x6F2A	# <CJK>
+0x6475	0x6F09	# <CJK>
+0x6476	0x6F29	# <CJK>
+0x6477	0x6F89	# <CJK>
+0x6478	0x6F8D	# <CJK>
+0x6479	0x6F8C	# <CJK>
+0x647A	0x6F78	# <CJK>
+0x647B	0x6F72	# <CJK>
+0x647C	0x6F7C	# <CJK>
+0x647D	0x6F7A	# <CJK>
+0x647E	0x6FD1	# <CJK>
+0x6521	0x6FC9	# <CJK>
+0x6522	0x6FA7	# <CJK>
+0x6523	0x6FB9	# <CJK>
+0x6524	0x6FB6	# <CJK>
+0x6525	0x6FC2	# <CJK>
+0x6526	0x6FE1	# <CJK>
+0x6527	0x6FEE	# <CJK>
+0x6528	0x6FDE	# <CJK>
+0x6529	0x6FE0	# <CJK>
+0x652A	0x6FEF	# <CJK>
+0x652B	0x701A	# <CJK>
+0x652C	0x7023	# <CJK>
+0x652D	0x701B	# <CJK>
+0x652E	0x7039	# <CJK>
+0x652F	0x7035	# <CJK>
+0x6530	0x704F	# <CJK>
+0x6531	0x705E	# <CJK>
+0x6532	0x5B80	# <CJK>
+0x6533	0x5B84	# <CJK>
+0x6534	0x5B95	# <CJK>
+0x6535	0x5B93	# <CJK>
+0x6536	0x5BA5	# <CJK>
+0x6537	0x5BB8	# <CJK>
+0x6538	0x752F	# <CJK>
+0x6539	0x9A9E	# <CJK>
+0x653A	0x6434	# <CJK>
+0x653B	0x5BE4	# <CJK>
+0x653C	0x5BEE	# <CJK>
+0x653D	0x8930	# <CJK>
+0x653E	0x5BF0	# <CJK>
+0x653F	0x8E47	# <CJK>
+0x6540	0x8B07	# <CJK>
+0x6541	0x8FB6	# <CJK>
+0x6542	0x8FD3	# <CJK>
+0x6543	0x8FD5	# <CJK>
+0x6544	0x8FE5	# <CJK>
+0x6545	0x8FEE	# <CJK>
+0x6546	0x8FE4	# <CJK>
+0x6547	0x8FE9	# <CJK>
+0x6548	0x8FE6	# <CJK>
+0x6549	0x8FF3	# <CJK>
+0x654A	0x8FE8	# <CJK>
+0x654B	0x9005	# <CJK>
+0x654C	0x9004	# <CJK>
+0x654D	0x900B	# <CJK>
+0x654E	0x9026	# <CJK>
+0x654F	0x9011	# <CJK>
+0x6550	0x900D	# <CJK>
+0x6551	0x9016	# <CJK>
+0x6552	0x9021	# <CJK>
+0x6553	0x9035	# <CJK>
+0x6554	0x9036	# <CJK>
+0x6555	0x902D	# <CJK>
+0x6556	0x902F	# <CJK>
+0x6557	0x9044	# <CJK>
+0x6558	0x9051	# <CJK>
+0x6559	0x9052	# <CJK>
+0x655A	0x9050	# <CJK>
+0x655B	0x9068	# <CJK>
+0x655C	0x9058	# <CJK>
+0x655D	0x9062	# <CJK>
+0x655E	0x905B	# <CJK>
+0x655F	0x66B9	# <CJK>
+0x6560	0x9074	# <CJK>
+0x6561	0x907D	# <CJK>
+0x6562	0x9082	# <CJK>
+0x6563	0x9088	# <CJK>
+0x6564	0x9083	# <CJK>
+0x6565	0x908B	# <CJK>
+0x6566	0x5F50	# <CJK>
+0x6567	0x5F57	# <CJK>
+0x6568	0x5F56	# <CJK>
+0x6569	0x5F58	# <CJK>
+0x656A	0x5C3B	# <CJK>
+0x656B	0x54AB	# <CJK>
+0x656C	0x5C50	# <CJK>
+0x656D	0x5C59	# <CJK>
+0x656E	0x5B71	# <CJK>
+0x656F	0x5C63	# <CJK>
+0x6570	0x5C66	# <CJK>
+0x6571	0x7FBC	# <CJK>
+0x6572	0x5F2A	# <CJK>
+0x6573	0x5F29	# <CJK>
+0x6574	0x5F2D	# <CJK>
+0x6575	0x8274	# <CJK>
+0x6576	0x5F3C	# <CJK>
+0x6577	0x9B3B	# <CJK>
+0x6578	0x5C6E	# <CJK>
+0x6579	0x5981	# <CJK>
+0x657A	0x5983	# <CJK>
+0x657B	0x598D	# <CJK>
+0x657C	0x59A9	# <CJK>
+0x657D	0x59AA	# <CJK>
+0x657E	0x59A3	# <CJK>
+0x6621	0x5997	# <CJK>
+0x6622	0x59CA	# <CJK>
+0x6623	0x59AB	# <CJK>
+0x6624	0x599E	# <CJK>
+0x6625	0x59A4	# <CJK>
+0x6626	0x59D2	# <CJK>
+0x6627	0x59B2	# <CJK>
+0x6628	0x59AF	# <CJK>
+0x6629	0x59D7	# <CJK>
+0x662A	0x59BE	# <CJK>
+0x662B	0x5A05	# <CJK>
+0x662C	0x5A06	# <CJK>
+0x662D	0x59DD	# <CJK>
+0x662E	0x5A08	# <CJK>
+0x662F	0x59E3	# <CJK>
+0x6630	0x59D8	# <CJK>
+0x6631	0x59F9	# <CJK>
+0x6632	0x5A0C	# <CJK>
+0x6633	0x5A09	# <CJK>
+0x6634	0x5A32	# <CJK>
+0x6635	0x5A34	# <CJK>
+0x6636	0x5A11	# <CJK>
+0x6637	0x5A23	# <CJK>
+0x6638	0x5A13	# <CJK>
+0x6639	0x5A40	# <CJK>
+0x663A	0x5A67	# <CJK>
+0x663B	0x5A4A	# <CJK>
+0x663C	0x5A55	# <CJK>
+0x663D	0x5A3C	# <CJK>
+0x663E	0x5A62	# <CJK>
+0x663F	0x5A75	# <CJK>
+0x6640	0x80EC	# <CJK>
+0x6641	0x5AAA	# <CJK>
+0x6642	0x5A9B	# <CJK>
+0x6643	0x5A77	# <CJK>
+0x6644	0x5A7A	# <CJK>
+0x6645	0x5ABE	# <CJK>
+0x6646	0x5AEB	# <CJK>
+0x6647	0x5AB2	# <CJK>
+0x6648	0x5AD2	# <CJK>
+0x6649	0x5AD4	# <CJK>
+0x664A	0x5AB8	# <CJK>
+0x664B	0x5AE0	# <CJK>
+0x664C	0x5AE3	# <CJK>
+0x664D	0x5AF1	# <CJK>
+0x664E	0x5AD6	# <CJK>
+0x664F	0x5AE6	# <CJK>
+0x6650	0x5AD8	# <CJK>
+0x6651	0x5ADC	# <CJK>
+0x6652	0x5B09	# <CJK>
+0x6653	0x5B17	# <CJK>
+0x6654	0x5B16	# <CJK>
+0x6655	0x5B32	# <CJK>
+0x6656	0x5B37	# <CJK>
+0x6657	0x5B40	# <CJK>
+0x6658	0x5C15	# <CJK>
+0x6659	0x5C1C	# <CJK>
+0x665A	0x5B5A	# <CJK>
+0x665B	0x5B65	# <CJK>
+0x665C	0x5B73	# <CJK>
+0x665D	0x5B51	# <CJK>
+0x665E	0x5B53	# <CJK>
+0x665F	0x5B62	# <CJK>
+0x6660	0x9A75	# <CJK>
+0x6661	0x9A77	# <CJK>
+0x6662	0x9A78	# <CJK>
+0x6663	0x9A7A	# <CJK>
+0x6664	0x9A7F	# <CJK>
+0x6665	0x9A7D	# <CJK>
+0x6666	0x9A80	# <CJK>
+0x6667	0x9A81	# <CJK>
+0x6668	0x9A85	# <CJK>
+0x6669	0x9A88	# <CJK>
+0x666A	0x9A8A	# <CJK>
+0x666B	0x9A90	# <CJK>
+0x666C	0x9A92	# <CJK>
+0x666D	0x9A93	# <CJK>
+0x666E	0x9A96	# <CJK>
+0x666F	0x9A98	# <CJK>
+0x6670	0x9A9B	# <CJK>
+0x6671	0x9A9C	# <CJK>
+0x6672	0x9A9D	# <CJK>
+0x6673	0x9A9F	# <CJK>
+0x6674	0x9AA0	# <CJK>
+0x6675	0x9AA2	# <CJK>
+0x6676	0x9AA3	# <CJK>
+0x6677	0x9AA5	# <CJK>
+0x6678	0x9AA7	# <CJK>
+0x6679	0x7E9F	# <CJK>
+0x667A	0x7EA1	# <CJK>
+0x667B	0x7EA3	# <CJK>
+0x667C	0x7EA5	# <CJK>
+0x667D	0x7EA8	# <CJK>
+0x667E	0x7EA9	# <CJK>
+0x6721	0x7EAD	# <CJK>
+0x6722	0x7EB0	# <CJK>
+0x6723	0x7EBE	# <CJK>
+0x6724	0x7EC0	# <CJK>
+0x6725	0x7EC1	# <CJK>
+0x6726	0x7EC2	# <CJK>
+0x6727	0x7EC9	# <CJK>
+0x6728	0x7ECB	# <CJK>
+0x6729	0x7ECC	# <CJK>
+0x672A	0x7ED0	# <CJK>
+0x672B	0x7ED4	# <CJK>
+0x672C	0x7ED7	# <CJK>
+0x672D	0x7EDB	# <CJK>
+0x672E	0x7EE0	# <CJK>
+0x672F	0x7EE1	# <CJK>
+0x6730	0x7EE8	# <CJK>
+0x6731	0x7EEB	# <CJK>
+0x6732	0x7EEE	# <CJK>
+0x6733	0x7EEF	# <CJK>
+0x6734	0x7EF1	# <CJK>
+0x6735	0x7EF2	# <CJK>
+0x6736	0x7F0D	# <CJK>
+0x6737	0x7EF6	# <CJK>
+0x6738	0x7EFA	# <CJK>
+0x6739	0x7EFB	# <CJK>
+0x673A	0x7EFE	# <CJK>
+0x673B	0x7F01	# <CJK>
+0x673C	0x7F02	# <CJK>
+0x673D	0x7F03	# <CJK>
+0x673E	0x7F07	# <CJK>
+0x673F	0x7F08	# <CJK>
+0x6740	0x7F0B	# <CJK>
+0x6741	0x7F0C	# <CJK>
+0x6742	0x7F0F	# <CJK>
+0x6743	0x7F11	# <CJK>
+0x6744	0x7F12	# <CJK>
+0x6745	0x7F17	# <CJK>
+0x6746	0x7F19	# <CJK>
+0x6747	0x7F1C	# <CJK>
+0x6748	0x7F1B	# <CJK>
+0x6749	0x7F1F	# <CJK>
+0x674A	0x7F21	# <CJK>
+0x674B	0x7F22	# <CJK>
+0x674C	0x7F23	# <CJK>
+0x674D	0x7F24	# <CJK>
+0x674E	0x7F25	# <CJK>
+0x674F	0x7F26	# <CJK>
+0x6750	0x7F27	# <CJK>
+0x6751	0x7F2A	# <CJK>
+0x6752	0x7F2B	# <CJK>
+0x6753	0x7F2C	# <CJK>
+0x6754	0x7F2D	# <CJK>
+0x6755	0x7F2F	# <CJK>
+0x6756	0x7F30	# <CJK>
+0x6757	0x7F31	# <CJK>
+0x6758	0x7F32	# <CJK>
+0x6759	0x7F33	# <CJK>
+0x675A	0x7F35	# <CJK>
+0x675B	0x5E7A	# <CJK>
+0x675C	0x757F	# <CJK>
+0x675D	0x5DDB	# <CJK>
+0x675E	0x753E	# <CJK>
+0x675F	0x9095	# <CJK>
+0x6760	0x738E	# <CJK>
+0x6761	0x7391	# <CJK>
+0x6762	0x73AE	# <CJK>
+0x6763	0x73A2	# <CJK>
+0x6764	0x739F	# <CJK>
+0x6765	0x73CF	# <CJK>
+0x6766	0x73C2	# <CJK>
+0x6767	0x73D1	# <CJK>
+0x6768	0x73B7	# <CJK>
+0x6769	0x73B3	# <CJK>
+0x676A	0x73C0	# <CJK>
+0x676B	0x73C9	# <CJK>
+0x676C	0x73C8	# <CJK>
+0x676D	0x73E5	# <CJK>
+0x676E	0x73D9	# <CJK>
+0x676F	0x987C	# <CJK>
+0x6770	0x740A	# <CJK>
+0x6771	0x73E9	# <CJK>
+0x6772	0x73E7	# <CJK>
+0x6773	0x73DE	# <CJK>
+0x6774	0x73BA	# <CJK>
+0x6775	0x73F2	# <CJK>
+0x6776	0x740F	# <CJK>
+0x6777	0x742A	# <CJK>
+0x6778	0x745B	# <CJK>
+0x6779	0x7426	# <CJK>
+0x677A	0x7425	# <CJK>
+0x677B	0x7428	# <CJK>
+0x677C	0x7430	# <CJK>
+0x677D	0x742E	# <CJK>
+0x677E	0x742C	# <CJK>
+0x6821	0x741B	# <CJK>
+0x6822	0x741A	# <CJK>
+0x6823	0x7441	# <CJK>
+0x6824	0x745C	# <CJK>
+0x6825	0x7457	# <CJK>
+0x6826	0x7455	# <CJK>
+0x6827	0x7459	# <CJK>
+0x6828	0x7477	# <CJK>
+0x6829	0x746D	# <CJK>
+0x682A	0x747E	# <CJK>
+0x682B	0x749C	# <CJK>
+0x682C	0x748E	# <CJK>
+0x682D	0x7480	# <CJK>
+0x682E	0x7481	# <CJK>
+0x682F	0x7487	# <CJK>
+0x6830	0x748B	# <CJK>
+0x6831	0x749E	# <CJK>
+0x6832	0x74A8	# <CJK>
+0x6833	0x74A9	# <CJK>
+0x6834	0x7490	# <CJK>
+0x6835	0x74A7	# <CJK>
+0x6836	0x74D2	# <CJK>
+0x6837	0x74BA	# <CJK>
+0x6838	0x97EA	# <CJK>
+0x6839	0x97EB	# <CJK>
+0x683A	0x97EC	# <CJK>
+0x683B	0x674C	# <CJK>
+0x683C	0x6753	# <CJK>
+0x683D	0x675E	# <CJK>
+0x683E	0x6748	# <CJK>
+0x683F	0x6769	# <CJK>
+0x6840	0x67A5	# <CJK>
+0x6841	0x6787	# <CJK>
+0x6842	0x676A	# <CJK>
+0x6843	0x6773	# <CJK>
+0x6844	0x6798	# <CJK>
+0x6845	0x67A7	# <CJK>
+0x6846	0x6775	# <CJK>
+0x6847	0x67A8	# <CJK>
+0x6848	0x679E	# <CJK>
+0x6849	0x67AD	# <CJK>
+0x684A	0x678B	# <CJK>
+0x684B	0x6777	# <CJK>
+0x684C	0x677C	# <CJK>
+0x684D	0x67F0	# <CJK>
+0x684E	0x6809	# <CJK>
+0x684F	0x67D8	# <CJK>
+0x6850	0x680A	# <CJK>
+0x6851	0x67E9	# <CJK>
+0x6852	0x67B0	# <CJK>
+0x6853	0x680C	# <CJK>
+0x6854	0x67D9	# <CJK>
+0x6855	0x67B5	# <CJK>
+0x6856	0x67DA	# <CJK>
+0x6857	0x67B3	# <CJK>
+0x6858	0x67DD	# <CJK>
+0x6859	0x6800	# <CJK>
+0x685A	0x67C3	# <CJK>
+0x685B	0x67B8	# <CJK>
+0x685C	0x67E2	# <CJK>
+0x685D	0x680E	# <CJK>
+0x685E	0x67C1	# <CJK>
+0x685F	0x67FD	# <CJK>
+0x6860	0x6832	# <CJK>
+0x6861	0x6833	# <CJK>
+0x6862	0x6860	# <CJK>
+0x6863	0x6861	# <CJK>
+0x6864	0x684E	# <CJK>
+0x6865	0x6862	# <CJK>
+0x6866	0x6844	# <CJK>
+0x6867	0x6864	# <CJK>
+0x6868	0x6883	# <CJK>
+0x6869	0x681D	# <CJK>
+0x686A	0x6855	# <CJK>
+0x686B	0x6866	# <CJK>
+0x686C	0x6841	# <CJK>
+0x686D	0x6867	# <CJK>
+0x686E	0x6840	# <CJK>
+0x686F	0x683E	# <CJK>
+0x6870	0x684A	# <CJK>
+0x6871	0x6849	# <CJK>
+0x6872	0x6829	# <CJK>
+0x6873	0x68B5	# <CJK>
+0x6874	0x688F	# <CJK>
+0x6875	0x6874	# <CJK>
+0x6876	0x6877	# <CJK>
+0x6877	0x6893	# <CJK>
+0x6878	0x686B	# <CJK>
+0x6879	0x68C2	# <CJK>
+0x687A	0x696E	# <CJK>
+0x687B	0x68FC	# <CJK>
+0x687C	0x691F	# <CJK>
+0x687D	0x6920	# <CJK>
+0x687E	0x68F9	# <CJK>
+0x6921	0x6924	# <CJK>
+0x6922	0x68F0	# <CJK>
+0x6923	0x690B	# <CJK>
+0x6924	0x6901	# <CJK>
+0x6925	0x6957	# <CJK>
+0x6926	0x68E3	# <CJK>
+0x6927	0x6910	# <CJK>
+0x6928	0x6971	# <CJK>
+0x6929	0x6939	# <CJK>
+0x692A	0x6960	# <CJK>
+0x692B	0x6942	# <CJK>
+0x692C	0x695D	# <CJK>
+0x692D	0x6984	# <CJK>
+0x692E	0x696B	# <CJK>
+0x692F	0x6980	# <CJK>
+0x6930	0x6998	# <CJK>
+0x6931	0x6978	# <CJK>
+0x6932	0x6934	# <CJK>
+0x6933	0x69CC	# <CJK>
+0x6934	0x6987	# <CJK>
+0x6935	0x6988	# <CJK>
+0x6936	0x69CE	# <CJK>
+0x6937	0x6989	# <CJK>
+0x6938	0x6966	# <CJK>
+0x6939	0x6963	# <CJK>
+0x693A	0x6979	# <CJK>
+0x693B	0x699B	# <CJK>
+0x693C	0x69A7	# <CJK>
+0x693D	0x69BB	# <CJK>
+0x693E	0x69AB	# <CJK>
+0x693F	0x69AD	# <CJK>
+0x6940	0x69D4	# <CJK>
+0x6941	0x69B1	# <CJK>
+0x6942	0x69C1	# <CJK>
+0x6943	0x69CA	# <CJK>
+0x6944	0x69DF	# <CJK>
+0x6945	0x6995	# <CJK>
+0x6946	0x69E0	# <CJK>
+0x6947	0x698D	# <CJK>
+0x6948	0x69FF	# <CJK>
+0x6949	0x6A2F	# <CJK>
+0x694A	0x69ED	# <CJK>
+0x694B	0x6A17	# <CJK>
+0x694C	0x6A18	# <CJK>
+0x694D	0x6A65	# <CJK>
+0x694E	0x69F2	# <CJK>
+0x694F	0x6A44	# <CJK>
+0x6950	0x6A3E	# <CJK>
+0x6951	0x6AA0	# <CJK>
+0x6952	0x6A50	# <CJK>
+0x6953	0x6A5B	# <CJK>
+0x6954	0x6A35	# <CJK>
+0x6955	0x6A8E	# <CJK>
+0x6956	0x6A79	# <CJK>
+0x6957	0x6A3D	# <CJK>
+0x6958	0x6A28	# <CJK>
+0x6959	0x6A58	# <CJK>
+0x695A	0x6A7C	# <CJK>
+0x695B	0x6A91	# <CJK>
+0x695C	0x6A90	# <CJK>
+0x695D	0x6AA9	# <CJK>
+0x695E	0x6A97	# <CJK>
+0x695F	0x6AAB	# <CJK>
+0x6960	0x7337	# <CJK>
+0x6961	0x7352	# <CJK>
+0x6962	0x6B81	# <CJK>
+0x6963	0x6B82	# <CJK>
+0x6964	0x6B87	# <CJK>
+0x6965	0x6B84	# <CJK>
+0x6966	0x6B92	# <CJK>
+0x6967	0x6B93	# <CJK>
+0x6968	0x6B8D	# <CJK>
+0x6969	0x6B9A	# <CJK>
+0x696A	0x6B9B	# <CJK>
+0x696B	0x6BA1	# <CJK>
+0x696C	0x6BAA	# <CJK>
+0x696D	0x8F6B	# <CJK>
+0x696E	0x8F6D	# <CJK>
+0x696F	0x8F71	# <CJK>
+0x6970	0x8F72	# <CJK>
+0x6971	0x8F73	# <CJK>
+0x6972	0x8F75	# <CJK>
+0x6973	0x8F76	# <CJK>
+0x6974	0x8F78	# <CJK>
+0x6975	0x8F77	# <CJK>
+0x6976	0x8F79	# <CJK>
+0x6977	0x8F7A	# <CJK>
+0x6978	0x8F7C	# <CJK>
+0x6979	0x8F7E	# <CJK>
+0x697A	0x8F81	# <CJK>
+0x697B	0x8F82	# <CJK>
+0x697C	0x8F84	# <CJK>
+0x697D	0x8F87	# <CJK>
+0x697E	0x8F8B	# <CJK>
+0x6A21	0x8F8D	# <CJK>
+0x6A22	0x8F8E	# <CJK>
+0x6A23	0x8F8F	# <CJK>
+0x6A24	0x8F98	# <CJK>
+0x6A25	0x8F9A	# <CJK>
+0x6A26	0x8ECE	# <CJK>
+0x6A27	0x620B	# <CJK>
+0x6A28	0x6217	# <CJK>
+0x6A29	0x621B	# <CJK>
+0x6A2A	0x621F	# <CJK>
+0x6A2B	0x6222	# <CJK>
+0x6A2C	0x6221	# <CJK>
+0x6A2D	0x6225	# <CJK>
+0x6A2E	0x6224	# <CJK>
+0x6A2F	0x622C	# <CJK>
+0x6A30	0x81E7	# <CJK>
+0x6A31	0x74EF	# <CJK>
+0x6A32	0x74F4	# <CJK>
+0x6A33	0x74FF	# <CJK>
+0x6A34	0x750F	# <CJK>
+0x6A35	0x7511	# <CJK>
+0x6A36	0x7513	# <CJK>
+0x6A37	0x6534	# <CJK>
+0x6A38	0x65EE	# <CJK>
+0x6A39	0x65EF	# <CJK>
+0x6A3A	0x65F0	# <CJK>
+0x6A3B	0x660A	# <CJK>
+0x6A3C	0x6619	# <CJK>
+0x6A3D	0x6772	# <CJK>
+0x6A3E	0x6603	# <CJK>
+0x6A3F	0x6615	# <CJK>
+0x6A40	0x6600	# <CJK>
+0x6A41	0x7085	# <CJK>
+0x6A42	0x66F7	# <CJK>
+0x6A43	0x661D	# <CJK>
+0x6A44	0x6634	# <CJK>
+0x6A45	0x6631	# <CJK>
+0x6A46	0x6636	# <CJK>
+0x6A47	0x6635	# <CJK>
+0x6A48	0x8006	# <CJK>
+0x6A49	0x665F	# <CJK>
+0x6A4A	0x6654	# <CJK>
+0x6A4B	0x6641	# <CJK>
+0x6A4C	0x664F	# <CJK>
+0x6A4D	0x6656	# <CJK>
+0x6A4E	0x6661	# <CJK>
+0x6A4F	0x6657	# <CJK>
+0x6A50	0x6677	# <CJK>
+0x6A51	0x6684	# <CJK>
+0x6A52	0x668C	# <CJK>
+0x6A53	0x66A7	# <CJK>
+0x6A54	0x669D	# <CJK>
+0x6A55	0x66BE	# <CJK>
+0x6A56	0x66DB	# <CJK>
+0x6A57	0x66DC	# <CJK>
+0x6A58	0x66E6	# <CJK>
+0x6A59	0x66E9	# <CJK>
+0x6A5A	0x8D32	# <CJK>
+0x6A5B	0x8D33	# <CJK>
+0x6A5C	0x8D36	# <CJK>
+0x6A5D	0x8D3B	# <CJK>
+0x6A5E	0x8D3D	# <CJK>
+0x6A5F	0x8D40	# <CJK>
+0x6A60	0x8D45	# <CJK>
+0x6A61	0x8D46	# <CJK>
+0x6A62	0x8D48	# <CJK>
+0x6A63	0x8D49	# <CJK>
+0x6A64	0x8D47	# <CJK>
+0x6A65	0x8D4D	# <CJK>
+0x6A66	0x8D55	# <CJK>
+0x6A67	0x8D59	# <CJK>
+0x6A68	0x89C7	# <CJK>
+0x6A69	0x89CA	# <CJK>
+0x6A6A	0x89CB	# <CJK>
+0x6A6B	0x89CC	# <CJK>
+0x6A6C	0x89CE	# <CJK>
+0x6A6D	0x89CF	# <CJK>
+0x6A6E	0x89D0	# <CJK>
+0x6A6F	0x89D1	# <CJK>
+0x6A70	0x726E	# <CJK>
+0x6A71	0x729F	# <CJK>
+0x6A72	0x725D	# <CJK>
+0x6A73	0x7266	# <CJK>
+0x6A74	0x726F	# <CJK>
+0x6A75	0x727E	# <CJK>
+0x6A76	0x727F	# <CJK>
+0x6A77	0x7284	# <CJK>
+0x6A78	0x728B	# <CJK>
+0x6A79	0x728D	# <CJK>
+0x6A7A	0x728F	# <CJK>
+0x6A7B	0x7292	# <CJK>
+0x6A7C	0x6308	# <CJK>
+0x6A7D	0x6332	# <CJK>
+0x6A7E	0x63B0	# <CJK>
+0x6B21	0x643F	# <CJK>
+0x6B22	0x64D8	# <CJK>
+0x6B23	0x8004	# <CJK>
+0x6B24	0x6BEA	# <CJK>
+0x6B25	0x6BF3	# <CJK>
+0x6B26	0x6BFD	# <CJK>
+0x6B27	0x6BF5	# <CJK>
+0x6B28	0x6BF9	# <CJK>
+0x6B29	0x6C05	# <CJK>
+0x6B2A	0x6C07	# <CJK>
+0x6B2B	0x6C06	# <CJK>
+0x6B2C	0x6C0D	# <CJK>
+0x6B2D	0x6C15	# <CJK>
+0x6B2E	0x6C18	# <CJK>
+0x6B2F	0x6C19	# <CJK>
+0x6B30	0x6C1A	# <CJK>
+0x6B31	0x6C21	# <CJK>
+0x6B32	0x6C29	# <CJK>
+0x6B33	0x6C24	# <CJK>
+0x6B34	0x6C2A	# <CJK>
+0x6B35	0x6C32	# <CJK>
+0x6B36	0x6535	# <CJK>
+0x6B37	0x6555	# <CJK>
+0x6B38	0x656B	# <CJK>
+0x6B39	0x724D	# <CJK>
+0x6B3A	0x7252	# <CJK>
+0x6B3B	0x7256	# <CJK>
+0x6B3C	0x7230	# <CJK>
+0x6B3D	0x8662	# <CJK>
+0x6B3E	0x5216	# <CJK>
+0x6B3F	0x809F	# <CJK>
+0x6B40	0x809C	# <CJK>
+0x6B41	0x8093	# <CJK>
+0x6B42	0x80BC	# <CJK>
+0x6B43	0x670A	# <CJK>
+0x6B44	0x80BD	# <CJK>
+0x6B45	0x80B1	# <CJK>
+0x6B46	0x80AB	# <CJK>
+0x6B47	0x80AD	# <CJK>
+0x6B48	0x80B4	# <CJK>
+0x6B49	0x80B7	# <CJK>
+0x6B4A	0x80E7	# <CJK>
+0x6B4B	0x80E8	# <CJK>
+0x6B4C	0x80E9	# <CJK>
+0x6B4D	0x80EA	# <CJK>
+0x6B4E	0x80DB	# <CJK>
+0x6B4F	0x80C2	# <CJK>
+0x6B50	0x80C4	# <CJK>
+0x6B51	0x80D9	# <CJK>
+0x6B52	0x80CD	# <CJK>
+0x6B53	0x80D7	# <CJK>
+0x6B54	0x6710	# <CJK>
+0x6B55	0x80DD	# <CJK>
+0x6B56	0x80EB	# <CJK>
+0x6B57	0x80F1	# <CJK>
+0x6B58	0x80F4	# <CJK>
+0x6B59	0x80ED	# <CJK>
+0x6B5A	0x810D	# <CJK>
+0x6B5B	0x810E	# <CJK>
+0x6B5C	0x80F2	# <CJK>
+0x6B5D	0x80FC	# <CJK>
+0x6B5E	0x6715	# <CJK>
+0x6B5F	0x8112	# <CJK>
+0x6B60	0x8C5A	# <CJK>
+0x6B61	0x8136	# <CJK>
+0x6B62	0x811E	# <CJK>
+0x6B63	0x812C	# <CJK>
+0x6B64	0x8118	# <CJK>
+0x6B65	0x8132	# <CJK>
+0x6B66	0x8148	# <CJK>
+0x6B67	0x814C	# <CJK>
+0x6B68	0x8153	# <CJK>
+0x6B69	0x8174	# <CJK>
+0x6B6A	0x8159	# <CJK>
+0x6B6B	0x815A	# <CJK>
+0x6B6C	0x8171	# <CJK>
+0x6B6D	0x8160	# <CJK>
+0x6B6E	0x8169	# <CJK>
+0x6B6F	0x817C	# <CJK>
+0x6B70	0x817D	# <CJK>
+0x6B71	0x816D	# <CJK>
+0x6B72	0x8167	# <CJK>
+0x6B73	0x584D	# <CJK>
+0x6B74	0x5AB5	# <CJK>
+0x6B75	0x8188	# <CJK>
+0x6B76	0x8182	# <CJK>
+0x6B77	0x8191	# <CJK>
+0x6B78	0x6ED5	# <CJK>
+0x6B79	0x81A3	# <CJK>
+0x6B7A	0x81AA	# <CJK>
+0x6B7B	0x81CC	# <CJK>
+0x6B7C	0x6726	# <CJK>
+0x6B7D	0x81CA	# <CJK>
+0x6B7E	0x81BB	# <CJK>
+0x6C21	0x81C1	# <CJK>
+0x6C22	0x81A6	# <CJK>
+0x6C23	0x6B24	# <CJK>
+0x6C24	0x6B37	# <CJK>
+0x6C25	0x6B39	# <CJK>
+0x6C26	0x6B43	# <CJK>
+0x6C27	0x6B46	# <CJK>
+0x6C28	0x6B59	# <CJK>
+0x6C29	0x98D1	# <CJK>
+0x6C2A	0x98D2	# <CJK>
+0x6C2B	0x98D3	# <CJK>
+0x6C2C	0x98D5	# <CJK>
+0x6C2D	0x98D9	# <CJK>
+0x6C2E	0x98DA	# <CJK>
+0x6C2F	0x6BB3	# <CJK>
+0x6C30	0x5F40	# <CJK>
+0x6C31	0x6BC2	# <CJK>
+0x6C32	0x89F3	# <CJK>
+0x6C33	0x6590	# <CJK>
+0x6C34	0x9F51	# <CJK>
+0x6C35	0x6593	# <CJK>
+0x6C36	0x65BC	# <CJK>
+0x6C37	0x65C6	# <CJK>
+0x6C38	0x65C4	# <CJK>
+0x6C39	0x65C3	# <CJK>
+0x6C3A	0x65CC	# <CJK>
+0x6C3B	0x65CE	# <CJK>
+0x6C3C	0x65D2	# <CJK>
+0x6C3D	0x65D6	# <CJK>
+0x6C3E	0x7080	# <CJK>
+0x6C3F	0x709C	# <CJK>
+0x6C40	0x7096	# <CJK>
+0x6C41	0x709D	# <CJK>
+0x6C42	0x70BB	# <CJK>
+0x6C43	0x70C0	# <CJK>
+0x6C44	0x70B7	# <CJK>
+0x6C45	0x70AB	# <CJK>
+0x6C46	0x70B1	# <CJK>
+0x6C47	0x70E8	# <CJK>
+0x6C48	0x70CA	# <CJK>
+0x6C49	0x7110	# <CJK>
+0x6C4A	0x7113	# <CJK>
+0x6C4B	0x7116	# <CJK>
+0x6C4C	0x712F	# <CJK>
+0x6C4D	0x7131	# <CJK>
+0x6C4E	0x7173	# <CJK>
+0x6C4F	0x715C	# <CJK>
+0x6C50	0x7168	# <CJK>
+0x6C51	0x7145	# <CJK>
+0x6C52	0x7172	# <CJK>
+0x6C53	0x714A	# <CJK>
+0x6C54	0x7178	# <CJK>
+0x6C55	0x717A	# <CJK>
+0x6C56	0x7198	# <CJK>
+0x6C57	0x71B3	# <CJK>
+0x6C58	0x71B5	# <CJK>
+0x6C59	0x71A8	# <CJK>
+0x6C5A	0x71A0	# <CJK>
+0x6C5B	0x71E0	# <CJK>
+0x6C5C	0x71D4	# <CJK>
+0x6C5D	0x71E7	# <CJK>
+0x6C5E	0x71F9	# <CJK>
+0x6C5F	0x721D	# <CJK>
+0x6C60	0x7228	# <CJK>
+0x6C61	0x706C	# <CJK>
+0x6C62	0x7118	# <CJK>
+0x6C63	0x7166	# <CJK>
+0x6C64	0x71B9	# <CJK>
+0x6C65	0x623E	# <CJK>
+0x6C66	0x623D	# <CJK>
+0x6C67	0x6243	# <CJK>
+0x6C68	0x6248	# <CJK>
+0x6C69	0x6249	# <CJK>
+0x6C6A	0x793B	# <CJK>
+0x6C6B	0x7940	# <CJK>
+0x6C6C	0x7946	# <CJK>
+0x6C6D	0x7949	# <CJK>
+0x6C6E	0x795B	# <CJK>
+0x6C6F	0x795C	# <CJK>
+0x6C70	0x7953	# <CJK>
+0x6C71	0x795A	# <CJK>
+0x6C72	0x7962	# <CJK>
+0x6C73	0x7957	# <CJK>
+0x6C74	0x7960	# <CJK>
+0x6C75	0x796F	# <CJK>
+0x6C76	0x7967	# <CJK>
+0x6C77	0x797A	# <CJK>
+0x6C78	0x7985	# <CJK>
+0x6C79	0x798A	# <CJK>
+0x6C7A	0x799A	# <CJK>
+0x6C7B	0x79A7	# <CJK>
+0x6C7C	0x79B3	# <CJK>
+0x6C7D	0x5FD1	# <CJK>
+0x6C7E	0x5FD0	# <CJK>
+0x6D21	0x603C	# <CJK>
+0x6D22	0x605D	# <CJK>
+0x6D23	0x605A	# <CJK>
+0x6D24	0x6067	# <CJK>
+0x6D25	0x6041	# <CJK>
+0x6D26	0x6059	# <CJK>
+0x6D27	0x6063	# <CJK>
+0x6D28	0x60AB	# <CJK>
+0x6D29	0x6106	# <CJK>
+0x6D2A	0x610D	# <CJK>
+0x6D2B	0x615D	# <CJK>
+0x6D2C	0x61A9	# <CJK>
+0x6D2D	0x619D	# <CJK>
+0x6D2E	0x61CB	# <CJK>
+0x6D2F	0x61D1	# <CJK>
+0x6D30	0x6206	# <CJK>
+0x6D31	0x8080	# <CJK>
+0x6D32	0x807F	# <CJK>
+0x6D33	0x6C93	# <CJK>
+0x6D34	0x6CF6	# <CJK>
+0x6D35	0x6DFC	# <CJK>
+0x6D36	0x77F6	# <CJK>
+0x6D37	0x77F8	# <CJK>
+0x6D38	0x7800	# <CJK>
+0x6D39	0x7809	# <CJK>
+0x6D3A	0x7817	# <CJK>
+0x6D3B	0x7818	# <CJK>
+0x6D3C	0x7811	# <CJK>
+0x6D3D	0x65AB	# <CJK>
+0x6D3E	0x782D	# <CJK>
+0x6D3F	0x781C	# <CJK>
+0x6D40	0x781D	# <CJK>
+0x6D41	0x7839	# <CJK>
+0x6D42	0x783A	# <CJK>
+0x6D43	0x783B	# <CJK>
+0x6D44	0x781F	# <CJK>
+0x6D45	0x783C	# <CJK>
+0x6D46	0x7825	# <CJK>
+0x6D47	0x782C	# <CJK>
+0x6D48	0x7823	# <CJK>
+0x6D49	0x7829	# <CJK>
+0x6D4A	0x784E	# <CJK>
+0x6D4B	0x786D	# <CJK>
+0x6D4C	0x7856	# <CJK>
+0x6D4D	0x7857	# <CJK>
+0x6D4E	0x7826	# <CJK>
+0x6D4F	0x7850	# <CJK>
+0x6D50	0x7847	# <CJK>
+0x6D51	0x784C	# <CJK>
+0x6D52	0x786A	# <CJK>
+0x6D53	0x789B	# <CJK>
+0x6D54	0x7893	# <CJK>
+0x6D55	0x789A	# <CJK>
+0x6D56	0x7887	# <CJK>
+0x6D57	0x789C	# <CJK>
+0x6D58	0x78A1	# <CJK>
+0x6D59	0x78A3	# <CJK>
+0x6D5A	0x78B2	# <CJK>
+0x6D5B	0x78B9	# <CJK>
+0x6D5C	0x78A5	# <CJK>
+0x6D5D	0x78D4	# <CJK>
+0x6D5E	0x78D9	# <CJK>
+0x6D5F	0x78C9	# <CJK>
+0x6D60	0x78EC	# <CJK>
+0x6D61	0x78F2	# <CJK>
+0x6D62	0x7905	# <CJK>
+0x6D63	0x78F4	# <CJK>
+0x6D64	0x7913	# <CJK>
+0x6D65	0x7924	# <CJK>
+0x6D66	0x791E	# <CJK>
+0x6D67	0x7934	# <CJK>
+0x6D68	0x9F9B	# <CJK>
+0x6D69	0x9EF9	# <CJK>
+0x6D6A	0x9EFB	# <CJK>
+0x6D6B	0x9EFC	# <CJK>
+0x6D6C	0x76F1	# <CJK>
+0x6D6D	0x7704	# <CJK>
+0x6D6E	0x770D	# <CJK>
+0x6D6F	0x76F9	# <CJK>
+0x6D70	0x7707	# <CJK>
+0x6D71	0x7708	# <CJK>
+0x6D72	0x771A	# <CJK>
+0x6D73	0x7722	# <CJK>
+0x6D74	0x7719	# <CJK>
+0x6D75	0x772D	# <CJK>
+0x6D76	0x7726	# <CJK>
+0x6D77	0x7735	# <CJK>
+0x6D78	0x7738	# <CJK>
+0x6D79	0x7750	# <CJK>
+0x6D7A	0x7751	# <CJK>
+0x6D7B	0x7747	# <CJK>
+0x6D7C	0x7743	# <CJK>
+0x6D7D	0x775A	# <CJK>
+0x6D7E	0x7768	# <CJK>
+0x6E21	0x7762	# <CJK>
+0x6E22	0x7765	# <CJK>
+0x6E23	0x777F	# <CJK>
+0x6E24	0x778D	# <CJK>
+0x6E25	0x777D	# <CJK>
+0x6E26	0x7780	# <CJK>
+0x6E27	0x778C	# <CJK>
+0x6E28	0x7791	# <CJK>
+0x6E29	0x779F	# <CJK>
+0x6E2A	0x77A0	# <CJK>
+0x6E2B	0x77B0	# <CJK>
+0x6E2C	0x77B5	# <CJK>
+0x6E2D	0x77BD	# <CJK>
+0x6E2E	0x753A	# <CJK>
+0x6E2F	0x7540	# <CJK>
+0x6E30	0x754E	# <CJK>
+0x6E31	0x754B	# <CJK>
+0x6E32	0x7548	# <CJK>
+0x6E33	0x755B	# <CJK>
+0x6E34	0x7572	# <CJK>
+0x6E35	0x7579	# <CJK>
+0x6E36	0x7583	# <CJK>
+0x6E37	0x7F58	# <CJK>
+0x6E38	0x7F61	# <CJK>
+0x6E39	0x7F5F	# <CJK>
+0x6E3A	0x8A48	# <CJK>
+0x6E3B	0x7F68	# <CJK>
+0x6E3C	0x7F74	# <CJK>
+0x6E3D	0x7F71	# <CJK>
+0x6E3E	0x7F79	# <CJK>
+0x6E3F	0x7F81	# <CJK>
+0x6E40	0x7F7E	# <CJK>
+0x6E41	0x76CD	# <CJK>
+0x6E42	0x76E5	# <CJK>
+0x6E43	0x8832	# <CJK>
+0x6E44	0x9485	# <CJK>
+0x6E45	0x9486	# <CJK>
+0x6E46	0x9487	# <CJK>
+0x6E47	0x948B	# <CJK>
+0x6E48	0x948A	# <CJK>
+0x6E49	0x948C	# <CJK>
+0x6E4A	0x948D	# <CJK>
+0x6E4B	0x948F	# <CJK>
+0x6E4C	0x9490	# <CJK>
+0x6E4D	0x9494	# <CJK>
+0x6E4E	0x9497	# <CJK>
+0x6E4F	0x9495	# <CJK>
+0x6E50	0x949A	# <CJK>
+0x6E51	0x949B	# <CJK>
+0x6E52	0x949C	# <CJK>
+0x6E53	0x94A3	# <CJK>
+0x6E54	0x94A4	# <CJK>
+0x6E55	0x94AB	# <CJK>
+0x6E56	0x94AA	# <CJK>
+0x6E57	0x94AD	# <CJK>
+0x6E58	0x94AC	# <CJK>
+0x6E59	0x94AF	# <CJK>
+0x6E5A	0x94B0	# <CJK>
+0x6E5B	0x94B2	# <CJK>
+0x6E5C	0x94B4	# <CJK>
+0x6E5D	0x94B6	# <CJK>
+0x6E5E	0x94B7	# <CJK>
+0x6E5F	0x94B8	# <CJK>
+0x6E60	0x94B9	# <CJK>
+0x6E61	0x94BA	# <CJK>
+0x6E62	0x94BC	# <CJK>
+0x6E63	0x94BD	# <CJK>
+0x6E64	0x94BF	# <CJK>
+0x6E65	0x94C4	# <CJK>
+0x6E66	0x94C8	# <CJK>
+0x6E67	0x94C9	# <CJK>
+0x6E68	0x94CA	# <CJK>
+0x6E69	0x94CB	# <CJK>
+0x6E6A	0x94CC	# <CJK>
+0x6E6B	0x94CD	# <CJK>
+0x6E6C	0x94CE	# <CJK>
+0x6E6D	0x94D0	# <CJK>
+0x6E6E	0x94D1	# <CJK>
+0x6E6F	0x94D2	# <CJK>
+0x6E70	0x94D5	# <CJK>
+0x6E71	0x94D6	# <CJK>
+0x6E72	0x94D7	# <CJK>
+0x6E73	0x94D9	# <CJK>
+0x6E74	0x94D8	# <CJK>
+0x6E75	0x94DB	# <CJK>
+0x6E76	0x94DE	# <CJK>
+0x6E77	0x94DF	# <CJK>
+0x6E78	0x94E0	# <CJK>
+0x6E79	0x94E2	# <CJK>
+0x6E7A	0x94E4	# <CJK>
+0x6E7B	0x94E5	# <CJK>
+0x6E7C	0x94E7	# <CJK>
+0x6E7D	0x94E8	# <CJK>
+0x6E7E	0x94EA	# <CJK>
+0x6F21	0x94E9	# <CJK>
+0x6F22	0x94EB	# <CJK>
+0x6F23	0x94EE	# <CJK>
+0x6F24	0x94EF	# <CJK>
+0x6F25	0x94F3	# <CJK>
+0x6F26	0x94F4	# <CJK>
+0x6F27	0x94F5	# <CJK>
+0x6F28	0x94F7	# <CJK>
+0x6F29	0x94F9	# <CJK>
+0x6F2A	0x94FC	# <CJK>
+0x6F2B	0x94FD	# <CJK>
+0x6F2C	0x94FF	# <CJK>
+0x6F2D	0x9503	# <CJK>
+0x6F2E	0x9502	# <CJK>
+0x6F2F	0x9506	# <CJK>
+0x6F30	0x9507	# <CJK>
+0x6F31	0x9509	# <CJK>
+0x6F32	0x950A	# <CJK>
+0x6F33	0x950D	# <CJK>
+0x6F34	0x950E	# <CJK>
+0x6F35	0x950F	# <CJK>
+0x6F36	0x9512	# <CJK>
+0x6F37	0x9513	# <CJK>
+0x6F38	0x9514	# <CJK>
+0x6F39	0x9515	# <CJK>
+0x6F3A	0x9516	# <CJK>
+0x6F3B	0x9518	# <CJK>
+0x6F3C	0x951B	# <CJK>
+0x6F3D	0x951D	# <CJK>
+0x6F3E	0x951E	# <CJK>
+0x6F3F	0x951F	# <CJK>
+0x6F40	0x9522	# <CJK>
+0x6F41	0x952A	# <CJK>
+0x6F42	0x952B	# <CJK>
+0x6F43	0x9529	# <CJK>
+0x6F44	0x952C	# <CJK>
+0x6F45	0x9531	# <CJK>
+0x6F46	0x9532	# <CJK>
+0x6F47	0x9534	# <CJK>
+0x6F48	0x9536	# <CJK>
+0x6F49	0x9537	# <CJK>
+0x6F4A	0x9538	# <CJK>
+0x6F4B	0x953C	# <CJK>
+0x6F4C	0x953E	# <CJK>
+0x6F4D	0x953F	# <CJK>
+0x6F4E	0x9542	# <CJK>
+0x6F4F	0x9535	# <CJK>
+0x6F50	0x9544	# <CJK>
+0x6F51	0x9545	# <CJK>
+0x6F52	0x9546	# <CJK>
+0x6F53	0x9549	# <CJK>
+0x6F54	0x954C	# <CJK>
+0x6F55	0x954E	# <CJK>
+0x6F56	0x954F	# <CJK>
+0x6F57	0x9552	# <CJK>
+0x6F58	0x9553	# <CJK>
+0x6F59	0x9554	# <CJK>
+0x6F5A	0x9556	# <CJK>
+0x6F5B	0x9557	# <CJK>
+0x6F5C	0x9558	# <CJK>
+0x6F5D	0x9559	# <CJK>
+0x6F5E	0x955B	# <CJK>
+0x6F5F	0x955E	# <CJK>
+0x6F60	0x955F	# <CJK>
+0x6F61	0x955D	# <CJK>
+0x6F62	0x9561	# <CJK>
+0x6F63	0x9562	# <CJK>
+0x6F64	0x9564	# <CJK>
+0x6F65	0x9565	# <CJK>
+0x6F66	0x9566	# <CJK>
+0x6F67	0x9567	# <CJK>
+0x6F68	0x9568	# <CJK>
+0x6F69	0x9569	# <CJK>
+0x6F6A	0x956A	# <CJK>
+0x6F6B	0x956B	# <CJK>
+0x6F6C	0x956C	# <CJK>
+0x6F6D	0x956F	# <CJK>
+0x6F6E	0x9571	# <CJK>
+0x6F6F	0x9572	# <CJK>
+0x6F70	0x9573	# <CJK>
+0x6F71	0x953A	# <CJK>
+0x6F72	0x77E7	# <CJK>
+0x6F73	0x77EC	# <CJK>
+0x6F74	0x96C9	# <CJK>
+0x6F75	0x79D5	# <CJK>
+0x6F76	0x79ED	# <CJK>
+0x6F77	0x79E3	# <CJK>
+0x6F78	0x79EB	# <CJK>
+0x6F79	0x7A06	# <CJK>
+0x6F7A	0x5D47	# <CJK>
+0x6F7B	0x7A03	# <CJK>
+0x6F7C	0x7A02	# <CJK>
+0x6F7D	0x7A1E	# <CJK>
+0x6F7E	0x7A14	# <CJK>
+0x7021	0x7A39	# <CJK>
+0x7022	0x7A37	# <CJK>
+0x7023	0x7A51	# <CJK>
+0x7024	0x9ECF	# <CJK>
+0x7025	0x99A5	# <CJK>
+0x7026	0x7A70	# <CJK>
+0x7027	0x7688	# <CJK>
+0x7028	0x768E	# <CJK>
+0x7029	0x7693	# <CJK>
+0x702A	0x7699	# <CJK>
+0x702B	0x76A4	# <CJK>
+0x702C	0x74DE	# <CJK>
+0x702D	0x74E0	# <CJK>
+0x702E	0x752C	# <CJK>
+0x702F	0x9E20	# <CJK>
+0x7030	0x9E22	# <CJK>
+0x7031	0x9E28	# <CJK>
+0x7032	0x9E29	# <CJK>
+0x7033	0x9E2A	# <CJK>
+0x7034	0x9E2B	# <CJK>
+0x7035	0x9E2C	# <CJK>
+0x7036	0x9E32	# <CJK>
+0x7037	0x9E31	# <CJK>
+0x7038	0x9E36	# <CJK>
+0x7039	0x9E38	# <CJK>
+0x703A	0x9E37	# <CJK>
+0x703B	0x9E39	# <CJK>
+0x703C	0x9E3A	# <CJK>
+0x703D	0x9E3E	# <CJK>
+0x703E	0x9E41	# <CJK>
+0x703F	0x9E42	# <CJK>
+0x7040	0x9E44	# <CJK>
+0x7041	0x9E46	# <CJK>
+0x7042	0x9E47	# <CJK>
+0x7043	0x9E48	# <CJK>
+0x7044	0x9E49	# <CJK>
+0x7045	0x9E4B	# <CJK>
+0x7046	0x9E4C	# <CJK>
+0x7047	0x9E4E	# <CJK>
+0x7048	0x9E51	# <CJK>
+0x7049	0x9E55	# <CJK>
+0x704A	0x9E57	# <CJK>
+0x704B	0x9E5A	# <CJK>
+0x704C	0x9E5B	# <CJK>
+0x704D	0x9E5C	# <CJK>
+0x704E	0x9E5E	# <CJK>
+0x704F	0x9E63	# <CJK>
+0x7050	0x9E66	# <CJK>
+0x7051	0x9E67	# <CJK>
+0x7052	0x9E68	# <CJK>
+0x7053	0x9E69	# <CJK>
+0x7054	0x9E6A	# <CJK>
+0x7055	0x9E6B	# <CJK>
+0x7056	0x9E6C	# <CJK>
+0x7057	0x9E71	# <CJK>
+0x7058	0x9E6D	# <CJK>
+0x7059	0x9E73	# <CJK>
+0x705A	0x7592	# <CJK>
+0x705B	0x7594	# <CJK>
+0x705C	0x7596	# <CJK>
+0x705D	0x75A0	# <CJK>
+0x705E	0x759D	# <CJK>
+0x705F	0x75AC	# <CJK>
+0x7060	0x75A3	# <CJK>
+0x7061	0x75B3	# <CJK>
+0x7062	0x75B4	# <CJK>
+0x7063	0x75B8	# <CJK>
+0x7064	0x75C4	# <CJK>
+0x7065	0x75B1	# <CJK>
+0x7066	0x75B0	# <CJK>
+0x7067	0x75C3	# <CJK>
+0x7068	0x75C2	# <CJK>
+0x7069	0x75D6	# <CJK>
+0x706A	0x75CD	# <CJK>
+0x706B	0x75E3	# <CJK>
+0x706C	0x75E8	# <CJK>
+0x706D	0x75E6	# <CJK>
+0x706E	0x75E4	# <CJK>
+0x706F	0x75EB	# <CJK>
+0x7070	0x75E7	# <CJK>
+0x7071	0x7603	# <CJK>
+0x7072	0x75F1	# <CJK>
+0x7073	0x75FC	# <CJK>
+0x7074	0x75FF	# <CJK>
+0x7075	0x7610	# <CJK>
+0x7076	0x7600	# <CJK>
+0x7077	0x7605	# <CJK>
+0x7078	0x760C	# <CJK>
+0x7079	0x7617	# <CJK>
+0x707A	0x760A	# <CJK>
+0x707B	0x7625	# <CJK>
+0x707C	0x7618	# <CJK>
+0x707D	0x7615	# <CJK>
+0x707E	0x7619	# <CJK>
+0x7121	0x761B	# <CJK>
+0x7122	0x763C	# <CJK>
+0x7123	0x7622	# <CJK>
+0x7124	0x7620	# <CJK>
+0x7125	0x7640	# <CJK>
+0x7126	0x762D	# <CJK>
+0x7127	0x7630	# <CJK>
+0x7128	0x763F	# <CJK>
+0x7129	0x7635	# <CJK>
+0x712A	0x7643	# <CJK>
+0x712B	0x763E	# <CJK>
+0x712C	0x7633	# <CJK>
+0x712D	0x764D	# <CJK>
+0x712E	0x765E	# <CJK>
+0x712F	0x7654	# <CJK>
+0x7130	0x765C	# <CJK>
+0x7131	0x7656	# <CJK>
+0x7132	0x766B	# <CJK>
+0x7133	0x766F	# <CJK>
+0x7134	0x7FCA	# <CJK>
+0x7135	0x7AE6	# <CJK>
+0x7136	0x7A78	# <CJK>
+0x7137	0x7A79	# <CJK>
+0x7138	0x7A80	# <CJK>
+0x7139	0x7A86	# <CJK>
+0x713A	0x7A88	# <CJK>
+0x713B	0x7A95	# <CJK>
+0x713C	0x7AA6	# <CJK>
+0x713D	0x7AA0	# <CJK>
+0x713E	0x7AAC	# <CJK>
+0x713F	0x7AA8	# <CJK>
+0x7140	0x7AAD	# <CJK>
+0x7141	0x7AB3	# <CJK>
+0x7142	0x8864	# <CJK>
+0x7143	0x8869	# <CJK>
+0x7144	0x8872	# <CJK>
+0x7145	0x887D	# <CJK>
+0x7146	0x887F	# <CJK>
+0x7147	0x8882	# <CJK>
+0x7148	0x88A2	# <CJK>
+0x7149	0x88C6	# <CJK>
+0x714A	0x88B7	# <CJK>
+0x714B	0x88BC	# <CJK>
+0x714C	0x88C9	# <CJK>
+0x714D	0x88E2	# <CJK>
+0x714E	0x88CE	# <CJK>
+0x714F	0x88E3	# <CJK>
+0x7150	0x88E5	# <CJK>
+0x7151	0x88F1	# <CJK>
+0x7152	0x891A	# <CJK>
+0x7153	0x88FC	# <CJK>
+0x7154	0x88E8	# <CJK>
+0x7155	0x88FE	# <CJK>
+0x7156	0x88F0	# <CJK>
+0x7157	0x8921	# <CJK>
+0x7158	0x8919	# <CJK>
+0x7159	0x8913	# <CJK>
+0x715A	0x891B	# <CJK>
+0x715B	0x890A	# <CJK>
+0x715C	0x8934	# <CJK>
+0x715D	0x892B	# <CJK>
+0x715E	0x8936	# <CJK>
+0x715F	0x8941	# <CJK>
+0x7160	0x8966	# <CJK>
+0x7161	0x897B	# <CJK>
+0x7162	0x758B	# <CJK>
+0x7163	0x80E5	# <CJK>
+0x7164	0x76B2	# <CJK>
+0x7165	0x76B4	# <CJK>
+0x7166	0x77DC	# <CJK>
+0x7167	0x8012	# <CJK>
+0x7168	0x8014	# <CJK>
+0x7169	0x8016	# <CJK>
+0x716A	0x801C	# <CJK>
+0x716B	0x8020	# <CJK>
+0x716C	0x8022	# <CJK>
+0x716D	0x8025	# <CJK>
+0x716E	0x8026	# <CJK>
+0x716F	0x8027	# <CJK>
+0x7170	0x8029	# <CJK>
+0x7171	0x8028	# <CJK>
+0x7172	0x8031	# <CJK>
+0x7173	0x800B	# <CJK>
+0x7174	0x8035	# <CJK>
+0x7175	0x8043	# <CJK>
+0x7176	0x8046	# <CJK>
+0x7177	0x804D	# <CJK>
+0x7178	0x8052	# <CJK>
+0x7179	0x8069	# <CJK>
+0x717A	0x8071	# <CJK>
+0x717B	0x8983	# <CJK>
+0x717C	0x9878	# <CJK>
+0x717D	0x9880	# <CJK>
+0x717E	0x9883	# <CJK>
+0x7221	0x9889	# <CJK>
+0x7222	0x988C	# <CJK>
+0x7223	0x988D	# <CJK>
+0x7224	0x988F	# <CJK>
+0x7225	0x9894	# <CJK>
+0x7226	0x989A	# <CJK>
+0x7227	0x989B	# <CJK>
+0x7228	0x989E	# <CJK>
+0x7229	0x989F	# <CJK>
+0x722A	0x98A1	# <CJK>
+0x722B	0x98A2	# <CJK>
+0x722C	0x98A5	# <CJK>
+0x722D	0x98A6	# <CJK>
+0x722E	0x864D	# <CJK>
+0x722F	0x8654	# <CJK>
+0x7230	0x866C	# <CJK>
+0x7231	0x866E	# <CJK>
+0x7232	0x867F	# <CJK>
+0x7233	0x867A	# <CJK>
+0x7234	0x867C	# <CJK>
+0x7235	0x867B	# <CJK>
+0x7236	0x86A8	# <CJK>
+0x7237	0x868D	# <CJK>
+0x7238	0x868B	# <CJK>
+0x7239	0x86AC	# <CJK>
+0x723A	0x869D	# <CJK>
+0x723B	0x86A7	# <CJK>
+0x723C	0x86A3	# <CJK>
+0x723D	0x86AA	# <CJK>
+0x723E	0x8693	# <CJK>
+0x723F	0x86A9	# <CJK>
+0x7240	0x86B6	# <CJK>
+0x7241	0x86C4	# <CJK>
+0x7242	0x86B5	# <CJK>
+0x7243	0x86CE	# <CJK>
+0x7244	0x86B0	# <CJK>
+0x7245	0x86BA	# <CJK>
+0x7246	0x86B1	# <CJK>
+0x7247	0x86AF	# <CJK>
+0x7248	0x86C9	# <CJK>
+0x7249	0x86CF	# <CJK>
+0x724A	0x86B4	# <CJK>
+0x724B	0x86E9	# <CJK>
+0x724C	0x86F1	# <CJK>
+0x724D	0x86F2	# <CJK>
+0x724E	0x86ED	# <CJK>
+0x724F	0x86F3	# <CJK>
+0x7250	0x86D0	# <CJK>
+0x7251	0x8713	# <CJK>
+0x7252	0x86DE	# <CJK>
+0x7253	0x86F4	# <CJK>
+0x7254	0x86DF	# <CJK>
+0x7255	0x86D8	# <CJK>
+0x7256	0x86D1	# <CJK>
+0x7257	0x8703	# <CJK>
+0x7258	0x8707	# <CJK>
+0x7259	0x86F8	# <CJK>
+0x725A	0x8708	# <CJK>
+0x725B	0x870A	# <CJK>
+0x725C	0x870D	# <CJK>
+0x725D	0x8709	# <CJK>
+0x725E	0x8723	# <CJK>
+0x725F	0x873B	# <CJK>
+0x7260	0x871E	# <CJK>
+0x7261	0x8725	# <CJK>
+0x7262	0x872E	# <CJK>
+0x7263	0x871A	# <CJK>
+0x7264	0x873E	# <CJK>
+0x7265	0x8748	# <CJK>
+0x7266	0x8734	# <CJK>
+0x7267	0x8731	# <CJK>
+0x7268	0x8729	# <CJK>
+0x7269	0x8737	# <CJK>
+0x726A	0x873F	# <CJK>
+0x726B	0x8782	# <CJK>
+0x726C	0x8722	# <CJK>
+0x726D	0x877D	# <CJK>
+0x726E	0x877E	# <CJK>
+0x726F	0x877B	# <CJK>
+0x7270	0x8760	# <CJK>
+0x7271	0x8770	# <CJK>
+0x7272	0x874C	# <CJK>
+0x7273	0x876E	# <CJK>
+0x7274	0x878B	# <CJK>
+0x7275	0x8753	# <CJK>
+0x7276	0x8763	# <CJK>
+0x7277	0x877C	# <CJK>
+0x7278	0x8764	# <CJK>
+0x7279	0x8759	# <CJK>
+0x727A	0x8765	# <CJK>
+0x727B	0x8793	# <CJK>
+0x727C	0x87AF	# <CJK>
+0x727D	0x87A8	# <CJK>
+0x727E	0x87D2	# <CJK>
+0x7321	0x87C6	# <CJK>
+0x7322	0x8788	# <CJK>
+0x7323	0x8785	# <CJK>
+0x7324	0x87AD	# <CJK>
+0x7325	0x8797	# <CJK>
+0x7326	0x8783	# <CJK>
+0x7327	0x87AB	# <CJK>
+0x7328	0x87E5	# <CJK>
+0x7329	0x87AC	# <CJK>
+0x732A	0x87B5	# <CJK>
+0x732B	0x87B3	# <CJK>
+0x732C	0x87CB	# <CJK>
+0x732D	0x87D3	# <CJK>
+0x732E	0x87BD	# <CJK>
+0x732F	0x87D1	# <CJK>
+0x7330	0x87C0	# <CJK>
+0x7331	0x87CA	# <CJK>
+0x7332	0x87DB	# <CJK>
+0x7333	0x87EA	# <CJK>
+0x7334	0x87E0	# <CJK>
+0x7335	0x87EE	# <CJK>
+0x7336	0x8816	# <CJK>
+0x7337	0x8813	# <CJK>
+0x7338	0x87FE	# <CJK>
+0x7339	0x880A	# <CJK>
+0x733A	0x881B	# <CJK>
+0x733B	0x8821	# <CJK>
+0x733C	0x8839	# <CJK>
+0x733D	0x883C	# <CJK>
+0x733E	0x7F36	# <CJK>
+0x733F	0x7F42	# <CJK>
+0x7340	0x7F44	# <CJK>
+0x7341	0x7F45	# <CJK>
+0x7342	0x8210	# <CJK>
+0x7343	0x7AFA	# <CJK>
+0x7344	0x7AFD	# <CJK>
+0x7345	0x7B08	# <CJK>
+0x7346	0x7B03	# <CJK>
+0x7347	0x7B04	# <CJK>
+0x7348	0x7B15	# <CJK>
+0x7349	0x7B0A	# <CJK>
+0x734A	0x7B2B	# <CJK>
+0x734B	0x7B0F	# <CJK>
+0x734C	0x7B47	# <CJK>
+0x734D	0x7B38	# <CJK>
+0x734E	0x7B2A	# <CJK>
+0x734F	0x7B19	# <CJK>
+0x7350	0x7B2E	# <CJK>
+0x7351	0x7B31	# <CJK>
+0x7352	0x7B20	# <CJK>
+0x7353	0x7B25	# <CJK>
+0x7354	0x7B24	# <CJK>
+0x7355	0x7B33	# <CJK>
+0x7356	0x7B3E	# <CJK>
+0x7357	0x7B1E	# <CJK>
+0x7358	0x7B58	# <CJK>
+0x7359	0x7B5A	# <CJK>
+0x735A	0x7B45	# <CJK>
+0x735B	0x7B75	# <CJK>
+0x735C	0x7B4C	# <CJK>
+0x735D	0x7B5D	# <CJK>
+0x735E	0x7B60	# <CJK>
+0x735F	0x7B6E	# <CJK>
+0x7360	0x7B7B	# <CJK>
+0x7361	0x7B62	# <CJK>
+0x7362	0x7B72	# <CJK>
+0x7363	0x7B71	# <CJK>
+0x7364	0x7B90	# <CJK>
+0x7365	0x7BA6	# <CJK>
+0x7366	0x7BA7	# <CJK>
+0x7367	0x7BB8	# <CJK>
+0x7368	0x7BAC	# <CJK>
+0x7369	0x7B9D	# <CJK>
+0x736A	0x7BA8	# <CJK>
+0x736B	0x7B85	# <CJK>
+0x736C	0x7BAA	# <CJK>
+0x736D	0x7B9C	# <CJK>
+0x736E	0x7BA2	# <CJK>
+0x736F	0x7BAB	# <CJK>
+0x7370	0x7BB4	# <CJK>
+0x7371	0x7BD1	# <CJK>
+0x7372	0x7BC1	# <CJK>
+0x7373	0x7BCC	# <CJK>
+0x7374	0x7BDD	# <CJK>
+0x7375	0x7BDA	# <CJK>
+0x7376	0x7BE5	# <CJK>
+0x7377	0x7BE6	# <CJK>
+0x7378	0x7BEA	# <CJK>
+0x7379	0x7C0C	# <CJK>
+0x737A	0x7BFE	# <CJK>
+0x737B	0x7BFC	# <CJK>
+0x737C	0x7C0F	# <CJK>
+0x737D	0x7C16	# <CJK>
+0x737E	0x7C0B	# <CJK>
+0x7421	0x7C1F	# <CJK>
+0x7422	0x7C2A	# <CJK>
+0x7423	0x7C26	# <CJK>
+0x7424	0x7C38	# <CJK>
+0x7425	0x7C41	# <CJK>
+0x7426	0x7C40	# <CJK>
+0x7427	0x81FE	# <CJK>
+0x7428	0x8201	# <CJK>
+0x7429	0x8202	# <CJK>
+0x742A	0x8204	# <CJK>
+0x742B	0x81EC	# <CJK>
+0x742C	0x8844	# <CJK>
+0x742D	0x8221	# <CJK>
+0x742E	0x8222	# <CJK>
+0x742F	0x8223	# <CJK>
+0x7430	0x822D	# <CJK>
+0x7431	0x822F	# <CJK>
+0x7432	0x8228	# <CJK>
+0x7433	0x822B	# <CJK>
+0x7434	0x8238	# <CJK>
+0x7435	0x823B	# <CJK>
+0x7436	0x8233	# <CJK>
+0x7437	0x8234	# <CJK>
+0x7438	0x823E	# <CJK>
+0x7439	0x8244	# <CJK>
+0x743A	0x8249	# <CJK>
+0x743B	0x824B	# <CJK>
+0x743C	0x824F	# <CJK>
+0x743D	0x825A	# <CJK>
+0x743E	0x825F	# <CJK>
+0x743F	0x8268	# <CJK>
+0x7440	0x887E	# <CJK>
+0x7441	0x8885	# <CJK>
+0x7442	0x8888	# <CJK>
+0x7443	0x88D8	# <CJK>
+0x7444	0x88DF	# <CJK>
+0x7445	0x895E	# <CJK>
+0x7446	0x7F9D	# <CJK>
+0x7447	0x7F9F	# <CJK>
+0x7448	0x7FA7	# <CJK>
+0x7449	0x7FAF	# <CJK>
+0x744A	0x7FB0	# <CJK>
+0x744B	0x7FB2	# <CJK>
+0x744C	0x7C7C	# <CJK>
+0x744D	0x6549	# <CJK>
+0x744E	0x7C91	# <CJK>
+0x744F	0x7C9D	# <CJK>
+0x7450	0x7C9C	# <CJK>
+0x7451	0x7C9E	# <CJK>
+0x7452	0x7CA2	# <CJK>
+0x7453	0x7CB2	# <CJK>
+0x7454	0x7CBC	# <CJK>
+0x7455	0x7CBD	# <CJK>
+0x7456	0x7CC1	# <CJK>
+0x7457	0x7CC7	# <CJK>
+0x7458	0x7CCC	# <CJK>
+0x7459	0x7CCD	# <CJK>
+0x745A	0x7CC8	# <CJK>
+0x745B	0x7CC5	# <CJK>
+0x745C	0x7CD7	# <CJK>
+0x745D	0x7CE8	# <CJK>
+0x745E	0x826E	# <CJK>
+0x745F	0x66A8	# <CJK>
+0x7460	0x7FBF	# <CJK>
+0x7461	0x7FCE	# <CJK>
+0x7462	0x7FD5	# <CJK>
+0x7463	0x7FE5	# <CJK>
+0x7464	0x7FE1	# <CJK>
+0x7465	0x7FE6	# <CJK>
+0x7466	0x7FE9	# <CJK>
+0x7467	0x7FEE	# <CJK>
+0x7468	0x7FF3	# <CJK>
+0x7469	0x7CF8	# <CJK>
+0x746A	0x7D77	# <CJK>
+0x746B	0x7DA6	# <CJK>
+0x746C	0x7DAE	# <CJK>
+0x746D	0x7E47	# <CJK>
+0x746E	0x7E9B	# <CJK>
+0x746F	0x9EB8	# <CJK>
+0x7470	0x9EB4	# <CJK>
+0x7471	0x8D73	# <CJK>
+0x7472	0x8D84	# <CJK>
+0x7473	0x8D94	# <CJK>
+0x7474	0x8D91	# <CJK>
+0x7475	0x8DB1	# <CJK>
+0x7476	0x8D67	# <CJK>
+0x7477	0x8D6D	# <CJK>
+0x7478	0x8C47	# <CJK>
+0x7479	0x8C49	# <CJK>
+0x747A	0x914A	# <CJK>
+0x747B	0x9150	# <CJK>
+0x747C	0x914E	# <CJK>
+0x747D	0x914F	# <CJK>
+0x747E	0x9164	# <CJK>
+0x7521	0x9162	# <CJK>
+0x7522	0x9161	# <CJK>
+0x7523	0x9170	# <CJK>
+0x7524	0x9169	# <CJK>
+0x7525	0x916F	# <CJK>
+0x7526	0x917D	# <CJK>
+0x7527	0x917E	# <CJK>
+0x7528	0x9172	# <CJK>
+0x7529	0x9174	# <CJK>
+0x752A	0x9179	# <CJK>
+0x752B	0x918C	# <CJK>
+0x752C	0x9185	# <CJK>
+0x752D	0x9190	# <CJK>
+0x752E	0x918D	# <CJK>
+0x752F	0x9191	# <CJK>
+0x7530	0x91A2	# <CJK>
+0x7531	0x91A3	# <CJK>
+0x7532	0x91AA	# <CJK>
+0x7533	0x91AD	# <CJK>
+0x7534	0x91AE	# <CJK>
+0x7535	0x91AF	# <CJK>
+0x7536	0x91B5	# <CJK>
+0x7537	0x91B4	# <CJK>
+0x7538	0x91BA	# <CJK>
+0x7539	0x8C55	# <CJK>
+0x753A	0x9E7E	# <CJK>
+0x753B	0x8DB8	# <CJK>
+0x753C	0x8DEB	# <CJK>
+0x753D	0x8E05	# <CJK>
+0x753E	0x8E59	# <CJK>
+0x753F	0x8E69	# <CJK>
+0x7540	0x8DB5	# <CJK>
+0x7541	0x8DBF	# <CJK>
+0x7542	0x8DBC	# <CJK>
+0x7543	0x8DBA	# <CJK>
+0x7544	0x8DC4	# <CJK>
+0x7545	0x8DD6	# <CJK>
+0x7546	0x8DD7	# <CJK>
+0x7547	0x8DDA	# <CJK>
+0x7548	0x8DDE	# <CJK>
+0x7549	0x8DCE	# <CJK>
+0x754A	0x8DCF	# <CJK>
+0x754B	0x8DDB	# <CJK>
+0x754C	0x8DC6	# <CJK>
+0x754D	0x8DEC	# <CJK>
+0x754E	0x8DF7	# <CJK>
+0x754F	0x8DF8	# <CJK>
+0x7550	0x8DE3	# <CJK>
+0x7551	0x8DF9	# <CJK>
+0x7552	0x8DFB	# <CJK>
+0x7553	0x8DE4	# <CJK>
+0x7554	0x8E09	# <CJK>
+0x7555	0x8DFD	# <CJK>
+0x7556	0x8E14	# <CJK>
+0x7557	0x8E1D	# <CJK>
+0x7558	0x8E1F	# <CJK>
+0x7559	0x8E2C	# <CJK>
+0x755A	0x8E2E	# <CJK>
+0x755B	0x8E23	# <CJK>
+0x755C	0x8E2F	# <CJK>
+0x755D	0x8E3A	# <CJK>
+0x755E	0x8E40	# <CJK>
+0x755F	0x8E39	# <CJK>
+0x7560	0x8E35	# <CJK>
+0x7561	0x8E3D	# <CJK>
+0x7562	0x8E31	# <CJK>
+0x7563	0x8E49	# <CJK>
+0x7564	0x8E41	# <CJK>
+0x7565	0x8E42	# <CJK>
+0x7566	0x8E51	# <CJK>
+0x7567	0x8E52	# <CJK>
+0x7568	0x8E4A	# <CJK>
+0x7569	0x8E70	# <CJK>
+0x756A	0x8E76	# <CJK>
+0x756B	0x8E7C	# <CJK>
+0x756C	0x8E6F	# <CJK>
+0x756D	0x8E74	# <CJK>
+0x756E	0x8E85	# <CJK>
+0x756F	0x8E8F	# <CJK>
+0x7570	0x8E94	# <CJK>
+0x7571	0x8E90	# <CJK>
+0x7572	0x8E9C	# <CJK>
+0x7573	0x8E9E	# <CJK>
+0x7574	0x8C78	# <CJK>
+0x7575	0x8C82	# <CJK>
+0x7576	0x8C8A	# <CJK>
+0x7577	0x8C85	# <CJK>
+0x7578	0x8C98	# <CJK>
+0x7579	0x8C94	# <CJK>
+0x757A	0x659B	# <CJK>
+0x757B	0x89D6	# <CJK>
+0x757C	0x89DE	# <CJK>
+0x757D	0x89DA	# <CJK>
+0x757E	0x89DC	# <CJK>
+0x7621	0x89E5	# <CJK>
+0x7622	0x89EB	# <CJK>
+0x7623	0x89EF	# <CJK>
+0x7624	0x8A3E	# <CJK>
+0x7625	0x8B26	# <CJK>
+0x7626	0x9753	# <CJK>
+0x7627	0x96E9	# <CJK>
+0x7628	0x96F3	# <CJK>
+0x7629	0x96EF	# <CJK>
+0x762A	0x9706	# <CJK>
+0x762B	0x9701	# <CJK>
+0x762C	0x9708	# <CJK>
+0x762D	0x970F	# <CJK>
+0x762E	0x970E	# <CJK>
+0x762F	0x972A	# <CJK>
+0x7630	0x972D	# <CJK>
+0x7631	0x9730	# <CJK>
+0x7632	0x973E	# <CJK>
+0x7633	0x9F80	# <CJK>
+0x7634	0x9F83	# <CJK>
+0x7635	0x9F85	# <CJK>
+0x7636	0x9F86	# <CJK>
+0x7637	0x9F87	# <CJK>
+0x7638	0x9F88	# <CJK>
+0x7639	0x9F89	# <CJK>
+0x763A	0x9F8A	# <CJK>
+0x763B	0x9F8C	# <CJK>
+0x763C	0x9EFE	# <CJK>
+0x763D	0x9F0B	# <CJK>
+0x763E	0x9F0D	# <CJK>
+0x763F	0x96B9	# <CJK>
+0x7640	0x96BC	# <CJK>
+0x7641	0x96BD	# <CJK>
+0x7642	0x96CE	# <CJK>
+0x7643	0x96D2	# <CJK>
+0x7644	0x77BF	# <CJK>
+0x7645	0x96E0	# <CJK>
+0x7646	0x928E	# <CJK>
+0x7647	0x92AE	# <CJK>
+0x7648	0x92C8	# <CJK>
+0x7649	0x933E	# <CJK>
+0x764A	0x936A	# <CJK>
+0x764B	0x93CA	# <CJK>
+0x764C	0x938F	# <CJK>
+0x764D	0x943E	# <CJK>
+0x764E	0x946B	# <CJK>
+0x764F	0x9C7F	# <CJK>
+0x7650	0x9C82	# <CJK>
+0x7651	0x9C85	# <CJK>
+0x7652	0x9C86	# <CJK>
+0x7653	0x9C87	# <CJK>
+0x7654	0x9C88	# <CJK>
+0x7655	0x7A23	# <CJK>
+0x7656	0x9C8B	# <CJK>
+0x7657	0x9C8E	# <CJK>
+0x7658	0x9C90	# <CJK>
+0x7659	0x9C91	# <CJK>
+0x765A	0x9C92	# <CJK>
+0x765B	0x9C94	# <CJK>
+0x765C	0x9C95	# <CJK>
+0x765D	0x9C9A	# <CJK>
+0x765E	0x9C9B	# <CJK>
+0x765F	0x9C9E	# <CJK>
+0x7660	0x9C9F	# <CJK>
+0x7661	0x9CA0	# <CJK>
+0x7662	0x9CA1	# <CJK>
+0x7663	0x9CA2	# <CJK>
+0x7664	0x9CA3	# <CJK>
+0x7665	0x9CA5	# <CJK>
+0x7666	0x9CA6	# <CJK>
+0x7667	0x9CA7	# <CJK>
+0x7668	0x9CA8	# <CJK>
+0x7669	0x9CA9	# <CJK>
+0x766A	0x9CAB	# <CJK>
+0x766B	0x9CAD	# <CJK>
+0x766C	0x9CAE	# <CJK>
+0x766D	0x9CB0	# <CJK>
+0x766E	0x9CB1	# <CJK>
+0x766F	0x9CB2	# <CJK>
+0x7670	0x9CB3	# <CJK>
+0x7671	0x9CB4	# <CJK>
+0x7672	0x9CB5	# <CJK>
+0x7673	0x9CB6	# <CJK>
+0x7674	0x9CB7	# <CJK>
+0x7675	0x9CBA	# <CJK>
+0x7676	0x9CBB	# <CJK>
+0x7677	0x9CBC	# <CJK>
+0x7678	0x9CBD	# <CJK>
+0x7679	0x9CC4	# <CJK>
+0x767A	0x9CC5	# <CJK>
+0x767B	0x9CC6	# <CJK>
+0x767C	0x9CC7	# <CJK>
+0x767D	0x9CCA	# <CJK>
+0x767E	0x9CCB	# <CJK>
+0x7721	0x9CCC	# <CJK>
+0x7722	0x9CCD	# <CJK>
+0x7723	0x9CCE	# <CJK>
+0x7724	0x9CCF	# <CJK>
+0x7725	0x9CD0	# <CJK>
+0x7726	0x9CD3	# <CJK>
+0x7727	0x9CD4	# <CJK>
+0x7728	0x9CD5	# <CJK>
+0x7729	0x9CD7	# <CJK>
+0x772A	0x9CD8	# <CJK>
+0x772B	0x9CD9	# <CJK>
+0x772C	0x9CDC	# <CJK>
+0x772D	0x9CDD	# <CJK>
+0x772E	0x9CDF	# <CJK>
+0x772F	0x9CE2	# <CJK>
+0x7730	0x977C	# <CJK>
+0x7731	0x9785	# <CJK>
+0x7732	0x9791	# <CJK>
+0x7733	0x9792	# <CJK>
+0x7734	0x9794	# <CJK>
+0x7735	0x97AF	# <CJK>
+0x7736	0x97AB	# <CJK>
+0x7737	0x97A3	# <CJK>
+0x7738	0x97B2	# <CJK>
+0x7739	0x97B4	# <CJK>
+0x773A	0x9AB1	# <CJK>
+0x773B	0x9AB0	# <CJK>
+0x773C	0x9AB7	# <CJK>
+0x773D	0x9E58	# <CJK>
+0x773E	0x9AB6	# <CJK>
+0x773F	0x9ABA	# <CJK>
+0x7740	0x9ABC	# <CJK>
+0x7741	0x9AC1	# <CJK>
+0x7742	0x9AC0	# <CJK>
+0x7743	0x9AC5	# <CJK>
+0x7744	0x9AC2	# <CJK>
+0x7745	0x9ACB	# <CJK>
+0x7746	0x9ACC	# <CJK>
+0x7747	0x9AD1	# <CJK>
+0x7748	0x9B45	# <CJK>
+0x7749	0x9B43	# <CJK>
+0x774A	0x9B47	# <CJK>
+0x774B	0x9B49	# <CJK>
+0x774C	0x9B48	# <CJK>
+0x774D	0x9B4D	# <CJK>
+0x774E	0x9B51	# <CJK>
+0x774F	0x98E8	# <CJK>
+0x7750	0x990D	# <CJK>
+0x7751	0x992E	# <CJK>
+0x7752	0x9955	# <CJK>
+0x7753	0x9954	# <CJK>
+0x7754	0x9ADF	# <CJK>
+0x7755	0x9AE1	# <CJK>
+0x7756	0x9AE6	# <CJK>
+0x7757	0x9AEF	# <CJK>
+0x7758	0x9AEB	# <CJK>
+0x7759	0x9AFB	# <CJK>
+0x775A	0x9AED	# <CJK>
+0x775B	0x9AF9	# <CJK>
+0x775C	0x9B08	# <CJK>
+0x775D	0x9B0F	# <CJK>
+0x775E	0x9B13	# <CJK>
+0x775F	0x9B1F	# <CJK>
+0x7760	0x9B23	# <CJK>
+0x7761	0x9EBD	# <CJK>
+0x7762	0x9EBE	# <CJK>
+0x7763	0x7E3B	# <CJK>
+0x7764	0x9E82	# <CJK>
+0x7765	0x9E87	# <CJK>
+0x7766	0x9E88	# <CJK>
+0x7767	0x9E8B	# <CJK>
+0x7768	0x9E92	# <CJK>
+0x7769	0x93D6	# <CJK>
+0x776A	0x9E9D	# <CJK>
+0x776B	0x9E9F	# <CJK>
+0x776C	0x9EDB	# <CJK>
+0x776D	0x9EDC	# <CJK>
+0x776E	0x9EDD	# <CJK>
+0x776F	0x9EE0	# <CJK>
+0x7770	0x9EDF	# <CJK>
+0x7771	0x9EE2	# <CJK>
+0x7772	0x9EE9	# <CJK>
+0x7773	0x9EE7	# <CJK>
+0x7774	0x9EE5	# <CJK>
+0x7775	0x9EEA	# <CJK>
+0x7776	0x9EEF	# <CJK>
+0x7777	0x9F22	# <CJK>
+0x7778	0x9F2C	# <CJK>
+0x7779	0x9F2F	# <CJK>
+0x777A	0x9F39	# <CJK>
+0x777B	0x9F37	# <CJK>
+0x777C	0x9F3D	# <CJK>
+0x777D	0x9F3E	# <CJK>
+0x777E	0x9F44	# <CJK>
Index: /main/tags/2.25/gsdl/unicode/MAPPINGS/EASTASIA/GB/GBK.TXT
===================================================================
--- /main/tags/2.25/gsdl/unicode/MAPPINGS/EASTASIA/GB/GBK.TXT	(revision 21064)
+++ /main/tags/2.25/gsdl/unicode/MAPPINGS/EASTASIA/GB/GBK.TXT	(revision 21064)
@@ -0,0 +1,23941 @@
+0x8140	0x4E02	
+0x8141	0x4E04	
+0x8142	0x4E05	
+0x8143	0x4E06	
+0x8144	0x4E0F	
+0x8145	0x4E12	
+0x8146	0x4E17	
+0x8147	0x4E1F	
+0x8148	0x4E20	
+0x8149	0x4E21	
+0x814A	0x4E23	
+0x814B	0x4E26	
+0x814C	0x4E29	
+0x814D	0x4E2E	
+0x814E	0x4E2F	
+0x814F	0x4E31	
+0x8150	0x4E33	
+0x8151	0x4E35	
+0x8152	0x4E37	
+0x8153	0x4E3C	
+0x8154	0x4E40	
+0x8155	0x4E41	
+0x8156	0x4E42	
+0x8157	0x4E44	
+0x8158	0x4E46	
+0x8159	0x4E4A	
+0x815A	0x4E51	
+0x815B	0x4E55	
+0x815C	0x4E57	
+0x815D	0x4E5A	
+0x815E	0x4E5B	
+0x815F	0x4E62	
+0x8160	0x4E63	
+0x8161	0x4E64	
+0x8162	0x4E65	
+0x8163	0x4E67	
+0x8164	0x4E68	
+0x8165	0x4E6A	
+0x8166	0x4E6B	
+0x8167	0x4E6C	
+0x8168	0x4E6D	
+0x8169	0x4E6E	
+0x816A	0x4E6F	
+0x816B	0x4E72	
+0x816C	0x4E74	
+0x816D	0x4E75	
+0x816E	0x4E76	
+0x816F	0x4E77	
+0x8170	0x4E78	
+0x8171	0x4E79	
+0x8172	0x4E7A	
+0x8173	0x4E7B	
+0x8174	0x4E7C	
+0x8175	0x4E7D	
+0x8176	0x4E7F	
+0x8177	0x4E80	
+0x8178	0x4E81	
+0x8179	0x4E82	
+0x817A	0x4E83	
+0x817B	0x4E84	
+0x817C	0x4E85	
+0x817D	0x4E87	
+0x817E	0x4E8A	
+0x8180	0x4E90	
+0x8181	0x4E96	
+0x8182	0x4E97	
+0x8183	0x4E99	
+0x8184	0x4E9C	
+0x8185	0x4E9D	
+0x8186	0x4E9E	
+0x8187	0x4EA3	
+0x8188	0x4EAA	
+0x8189	0x4EAF	
+0x818A	0x4EB0	
+0x818B	0x4EB1	
+0x818C	0x4EB4	
+0x818D	0x4EB6	
+0x818E	0x4EB7	
+0x818F	0x4EB8	
+0x8190	0x4EB9	
+0x8191	0x4EBC	
+0x8192	0x4EBD	
+0x8193	0x4EBE	
+0x8194	0x4EC8	
+0x8195	0x4ECC	
+0x8196	0x4ECF	
+0x8197	0x4ED0	
+0x8198	0x4ED2	
+0x8199	0x4EDA	
+0x819A	0x4EDB	
+0x819B	0x4EDC	
+0x819C	0x4EE0	
+0x819D	0x4EE2	
+0x819E	0x4EE6	
+0x819F	0x4EE7	
+0x81A0	0x4EE9	
+0x81A1	0x4EED	
+0x81A2	0x4EEE	
+0x81A3	0x4EEF	
+0x81A4	0x4EF1	
+0x81A5	0x4EF4	
+0x81A6	0x4EF8	
+0x81A7	0x4EF9	
+0x81A8	0x4EFA	
+0x81A9	0x4EFC	
+0x81AA	0x4EFE	
+0x81AB	0x4F00	
+0x81AC	0x4F02	
+0x81AD	0x4F03	
+0x81AE	0x4F04	
+0x81AF	0x4F05	
+0x81B0	0x4F06	
+0x81B1	0x4F07	
+0x81B2	0x4F08	
+0x81B3	0x4F0B	
+0x81B4	0x4F0C	
+0x81B5	0x4F12	
+0x81B6	0x4F13	
+0x81B7	0x4F14	
+0x81B8	0x4F15	
+0x81B9	0x4F16	
+0x81BA	0x4F1C	
+0x81BB	0x4F1D	
+0x81BC	0x4F21	
+0x81BD	0x4F23	
+0x81BE	0x4F28	
+0x81BF	0x4F29	
+0x81C0	0x4F2C	
+0x81C1	0x4F2D	
+0x81C2	0x4F2E	
+0x81C3	0x4F31	
+0x81C4	0x4F33	
+0x81C5	0x4F35	
+0x81C6	0x4F37	
+0x81C7	0x4F39	
+0x81C8	0x4F3B	
+0x81C9	0x4F3E	
+0x81CA	0x4F3F	
+0x81CB	0x4F40	
+0x81CC	0x4F41	
+0x81CD	0x4F42	
+0x81CE	0x4F44	
+0x81CF	0x4F45	
+0x81D0	0x4F47	
+0x81D1	0x4F48	
+0x81D2	0x4F49	
+0x81D3	0x4F4A	
+0x81D4	0x4F4B	
+0x81D5	0x4F4C	
+0x81D6	0x4F52	
+0x81D7	0x4F54	
+0x81D8	0x4F56	
+0x81D9	0x4F61	
+0x81DA	0x4F62	
+0x81DB	0x4F66	
+0x81DC	0x4F68	
+0x81DD	0x4F6A	
+0x81DE	0x4F6B	
+0x81DF	0x4F6D	
+0x81E0	0x4F6E	
+0x81E1	0x4F71	
+0x81E2	0x4F72	
+0x81E3	0x4F75	
+0x81E4	0x4F77	
+0x81E5	0x4F78	
+0x81E6	0x4F79	
+0x81E7	0x4F7A	
+0x81E8	0x4F7D	
+0x81E9	0x4F80	
+0x81EA	0x4F81	
+0x81EB	0x4F82	
+0x81EC	0x4F85	
+0x81ED	0x4F86	
+0x81EE	0x4F87	
+0x81EF	0x4F8A	
+0x81F0	0x4F8C	
+0x81F1	0x4F8E	
+0x81F2	0x4F90	
+0x81F3	0x4F92	
+0x81F4	0x4F93	
+0x81F5	0x4F95	
+0x81F6	0x4F96	
+0x81F7	0x4F98	
+0x81F8	0x4F99	
+0x81F9	0x4F9A	
+0x81FA	0x4F9C	
+0x81FB	0x4F9E	
+0x81FC	0x4F9F	
+0x81FD	0x4FA1	
+0x81FE	0x4FA2	
+0x8240	0x4FA4	
+0x8241	0x4FAB	
+0x8242	0x4FAD	
+0x8243	0x4FB0	
+0x8244	0x4FB1	
+0x8245	0x4FB2	
+0x8246	0x4FB3	
+0x8247	0x4FB4	
+0x8248	0x4FB6	
+0x8249	0x4FB7	
+0x824A	0x4FB8	
+0x824B	0x4FB9	
+0x824C	0x4FBA	
+0x824D	0x4FBB	
+0x824E	0x4FBC	
+0x824F	0x4FBD	
+0x8250	0x4FBE	
+0x8251	0x4FC0	
+0x8252	0x4FC1	
+0x8253	0x4FC2	
+0x8254	0x4FC6	
+0x8255	0x4FC7	
+0x8256	0x4FC8	
+0x8257	0x4FC9	
+0x8258	0x4FCB	
+0x8259	0x4FCC	
+0x825A	0x4FCD	
+0x825B	0x4FD2	
+0x825C	0x4FD3	
+0x825D	0x4FD4	
+0x825E	0x4FD5	
+0x825F	0x4FD6	
+0x8260	0x4FD9	
+0x8261	0x4FDB	
+0x8262	0x4FE0	
+0x8263	0x4FE2	
+0x8264	0x4FE4	
+0x8265	0x4FE5	
+0x8266	0x4FE7	
+0x8267	0x4FEB	
+0x8268	0x4FEC	
+0x8269	0x4FF0	
+0x826A	0x4FF2	
+0x826B	0x4FF4	
+0x826C	0x4FF5	
+0x826D	0x4FF6	
+0x826E	0x4FF7	
+0x826F	0x4FF9	
+0x8270	0x4FFB	
+0x8271	0x4FFC	
+0x8272	0x4FFD	
+0x8273	0x4FFF	
+0x8274	0x5000	
+0x8275	0x5001	
+0x8276	0x5002	
+0x8277	0x5003	
+0x8278	0x5004	
+0x8279	0x5005	
+0x827A	0x5006	
+0x827B	0x5007	
+0x827C	0x5008	
+0x827D	0x5009	
+0x827E	0x500A	
+0x8280	0x500B	
+0x8281	0x500E	
+0x8282	0x5010	
+0x8283	0x5011	
+0x8284	0x5013	
+0x8285	0x5015	
+0x8286	0x5016	
+0x8287	0x5017	
+0x8288	0x501B	
+0x8289	0x501D	
+0x828A	0x501E	
+0x828B	0x5020	
+0x828C	0x5022	
+0x828D	0x5023	
+0x828E	0x5024	
+0x828F	0x5027	
+0x8290	0x502B	
+0x8291	0x502F	
+0x8292	0x5030	
+0x8293	0x5031	
+0x8294	0x5032	
+0x8295	0x5033	
+0x8296	0x5034	
+0x8297	0x5035	
+0x8298	0x5036	
+0x8299	0x5037	
+0x829A	0x5038	
+0x829B	0x5039	
+0x829C	0x503B	
+0x829D	0x503D	
+0x829E	0x503F	
+0x829F	0x5040	
+0x82A0	0x5041	
+0x82A1	0x5042	
+0x82A2	0x5044	
+0x82A3	0x5045	
+0x82A4	0x5046	
+0x82A5	0x5049	
+0x82A6	0x504A	
+0x82A7	0x504B	
+0x82A8	0x504D	
+0x82A9	0x5050	
+0x82AA	0x5051	
+0x82AB	0x5052	
+0x82AC	0x5053	
+0x82AD	0x5054	
+0x82AE	0x5056	
+0x82AF	0x5057	
+0x82B0	0x5058	
+0x82B1	0x5059	
+0x82B2	0x505B	
+0x82B3	0x505D	
+0x82B4	0x505E	
+0x82B5	0x505F	
+0x82B6	0x5060	
+0x82B7	0x5061	
+0x82B8	0x5062	
+0x82B9	0x5063	
+0x82BA	0x5064	
+0x82BB	0x5066	
+0x82BC	0x5067	
+0x82BD	0x5068	
+0x82BE	0x5069	
+0x82BF	0x506A	
+0x82C0	0x506B	
+0x82C1	0x506D	
+0x82C2	0x506E	
+0x82C3	0x506F	
+0x82C4	0x5070	
+0x82C5	0x5071	
+0x82C6	0x5072	
+0x82C7	0x5073	
+0x82C8	0x5074	
+0x82C9	0x5075	
+0x82CA	0x5078	
+0x82CB	0x5079	
+0x82CC	0x507A	
+0x82CD	0x507C	
+0x82CE	0x507D	
+0x82CF	0x5081	
+0x82D0	0x5082	
+0x82D1	0x5083	
+0x82D2	0x5084	
+0x82D3	0x5086	
+0x82D4	0x5087	
+0x82D5	0x5089	
+0x82D6	0x508A	
+0x82D7	0x508B	
+0x82D8	0x508C	
+0x82D9	0x508E	
+0x82DA	0x508F	
+0x82DB	0x5090	
+0x82DC	0x5091	
+0x82DD	0x5092	
+0x82DE	0x5093	
+0x82DF	0x5094	
+0x82E0	0x5095	
+0x82E1	0x5096	
+0x82E2	0x5097	
+0x82E3	0x5098	
+0x82E4	0x5099	
+0x82E5	0x509A	
+0x82E6	0x509B	
+0x82E7	0x509C	
+0x82E8	0x509D	
+0x82E9	0x509E	
+0x82EA	0x509F	
+0x82EB	0x50A0	
+0x82EC	0x50A1	
+0x82ED	0x50A2	
+0x82EE	0x50A4	
+0x82EF	0x50A6	
+0x82F0	0x50AA	
+0x82F1	0x50AB	
+0x82F2	0x50AD	
+0x82F3	0x50AE	
+0x82F4	0x50AF	
+0x82F5	0x50B0	
+0x82F6	0x50B1	
+0x82F7	0x50B3	
+0x82F8	0x50B4	
+0x82F9	0x50B5	
+0x82FA	0x50B6	
+0x82FB	0x50B7	
+0x82FC	0x50B8	
+0x82FD	0x50B9	
+0x82FE	0x50BC	
+0x8340	0x50BD	
+0x8341	0x50BE	
+0x8342	0x50BF	
+0x8343	0x50C0	
+0x8344	0x50C1	
+0x8345	0x50C2	
+0x8346	0x50C3	
+0x8347	0x50C4	
+0x8348	0x50C5	
+0x8349	0x50C6	
+0x834A	0x50C7	
+0x834B	0x50C8	
+0x834C	0x50C9	
+0x834D	0x50CA	
+0x834E	0x50CB	
+0x834F	0x50CC	
+0x8350	0x50CD	
+0x8351	0x50CE	
+0x8352	0x50D0	
+0x8353	0x50D1	
+0x8354	0x50D2	
+0x8355	0x50D3	
+0x8356	0x50D4	
+0x8357	0x50D5	
+0x8358	0x50D7	
+0x8359	0x50D8	
+0x835A	0x50D9	
+0x835B	0x50DB	
+0x835C	0x50DC	
+0x835D	0x50DD	
+0x835E	0x50DE	
+0x835F	0x50DF	
+0x8360	0x50E0	
+0x8361	0x50E1	
+0x8362	0x50E2	
+0x8363	0x50E3	
+0x8364	0x50E4	
+0x8365	0x50E5	
+0x8366	0x50E8	
+0x8367	0x50E9	
+0x8368	0x50EA	
+0x8369	0x50EB	
+0x836A	0x50EF	
+0x836B	0x50F0	
+0x836C	0x50F1	
+0x836D	0x50F2	
+0x836E	0x50F4	
+0x836F	0x50F6	
+0x8370	0x50F7	
+0x8371	0x50F8	
+0x8372	0x50F9	
+0x8373	0x50FA	
+0x8374	0x50FC	
+0x8375	0x50FD	
+0x8376	0x50FE	
+0x8377	0x50FF	
+0x8378	0x5100	
+0x8379	0x5101	
+0x837A	0x5102	
+0x837B	0x5103	
+0x837C	0x5104	
+0x837D	0x5105	
+0x837E	0x5108	
+0x8380	0x5109	
+0x8381	0x510A	
+0x8382	0x510C	
+0x8383	0x510D	
+0x8384	0x510E	
+0x8385	0x510F	
+0x8386	0x5110	
+0x8387	0x5111	
+0x8388	0x5113	
+0x8389	0x5114	
+0x838A	0x5115	
+0x838B	0x5116	
+0x838C	0x5117	
+0x838D	0x5118	
+0x838E	0x5119	
+0x838F	0x511A	
+0x8390	0x511B	
+0x8391	0x511C	
+0x8392	0x511D	
+0x8393	0x511E	
+0x8394	0x511F	
+0x8395	0x5120	
+0x8396	0x5122	
+0x8397	0x5123	
+0x8398	0x5124	
+0x8399	0x5125	
+0x839A	0x5126	
+0x839B	0x5127	
+0x839C	0x5128	
+0x839D	0x5129	
+0x839E	0x512A	
+0x839F	0x512B	
+0x83A0	0x512C	
+0x83A1	0x512D	
+0x83A2	0x512E	
+0x83A3	0x512F	
+0x83A4	0x5130	
+0x83A5	0x5131	
+0x83A6	0x5132	
+0x83A7	0x5133	
+0x83A8	0x5134	
+0x83A9	0x5135	
+0x83AA	0x5136	
+0x83AB	0x5137	
+0x83AC	0x5138	
+0x83AD	0x5139	
+0x83AE	0x513A	
+0x83AF	0x513B	
+0x83B0	0x513C	
+0x83B1	0x513D	
+0x83B2	0x513E	
+0x83B3	0x5142	
+0x83B4	0x5147	
+0x83B5	0x514A	
+0x83B6	0x514C	
+0x83B7	0x514E	
+0x83B8	0x514F	
+0x83B9	0x5150	
+0x83BA	0x5152	
+0x83BB	0x5153	
+0x83BC	0x5157	
+0x83BD	0x5158	
+0x83BE	0x5159	
+0x83BF	0x515B	
+0x83C0	0x515D	
+0x83C1	0x515E	
+0x83C2	0x515F	
+0x83C3	0x5160	
+0x83C4	0x5161	
+0x83C5	0x5163	
+0x83C6	0x5164	
+0x83C7	0x5166	
+0x83C8	0x5167	
+0x83C9	0x5169	
+0x83CA	0x516A	
+0x83CB	0x516F	
+0x83CC	0x5172	
+0x83CD	0x517A	
+0x83CE	0x517E	
+0x83CF	0x517F	
+0x83D0	0x5183	
+0x83D1	0x5184	
+0x83D2	0x5186	
+0x83D3	0x5187	
+0x83D4	0x518A	
+0x83D5	0x518B	
+0x83D6	0x518E	
+0x83D7	0x518F	
+0x83D8	0x5190	
+0x83D9	0x5191	
+0x83DA	0x5193	
+0x83DB	0x5194	
+0x83DC	0x5198	
+0x83DD	0x519A	
+0x83DE	0x519D	
+0x83DF	0x519E	
+0x83E0	0x519F	
+0x83E1	0x51A1	
+0x83E2	0x51A3	
+0x83E3	0x51A6	
+0x83E4	0x51A7	
+0x83E5	0x51A8	
+0x83E6	0x51A9	
+0x83E7	0x51AA	
+0x83E8	0x51AD	
+0x83E9	0x51AE	
+0x83EA	0x51B4	
+0x83EB	0x51B8	
+0x83EC	0x51B9	
+0x83ED	0x51BA	
+0x83EE	0x51BE	
+0x83EF	0x51BF	
+0x83F0	0x51C1	
+0x83F1	0x51C2	
+0x83F2	0x51C3	
+0x83F3	0x51C5	
+0x83F4	0x51C8	
+0x83F5	0x51CA	
+0x83F6	0x51CD	
+0x83F7	0x51CE	
+0x83F8	0x51D0	
+0x83F9	0x51D2	
+0x83FA	0x51D3	
+0x83FB	0x51D4	
+0x83FC	0x51D5	
+0x83FD	0x51D6	
+0x83FE	0x51D7	
+0x8440	0x51D8	
+0x8441	0x51D9	
+0x8442	0x51DA	
+0x8443	0x51DC	
+0x8444	0x51DE	
+0x8445	0x51DF	
+0x8446	0x51E2	
+0x8447	0x51E3	
+0x8448	0x51E5	
+0x8449	0x51E6	
+0x844A	0x51E7	
+0x844B	0x51E8	
+0x844C	0x51E9	
+0x844D	0x51EA	
+0x844E	0x51EC	
+0x844F	0x51EE	
+0x8450	0x51F1	
+0x8451	0x51F2	
+0x8452	0x51F4	
+0x8453	0x51F7	
+0x8454	0x51FE	
+0x8455	0x5204	
+0x8456	0x5205	
+0x8457	0x5209	
+0x8458	0x520B	
+0x8459	0x520C	
+0x845A	0x520F	
+0x845B	0x5210	
+0x845C	0x5213	
+0x845D	0x5214	
+0x845E	0x5215	
+0x845F	0x521C	
+0x8460	0x521E	
+0x8461	0x521F	
+0x8462	0x5221	
+0x8463	0x5222	
+0x8464	0x5223	
+0x8465	0x5225	
+0x8466	0x5226	
+0x8467	0x5227	
+0x8468	0x522A	
+0x8469	0x522C	
+0x846A	0x522F	
+0x846B	0x5231	
+0x846C	0x5232	
+0x846D	0x5234	
+0x846E	0x5235	
+0x846F	0x523C	
+0x8470	0x523E	
+0x8471	0x5244	
+0x8472	0x5245	
+0x8473	0x5246	
+0x8474	0x5247	
+0x8475	0x5248	
+0x8476	0x5249	
+0x8477	0x524B	
+0x8478	0x524E	
+0x8479	0x524F	
+0x847A	0x5252	
+0x847B	0x5253	
+0x847C	0x5255	
+0x847D	0x5257	
+0x847E	0x5258	
+0x8480	0x5259	
+0x8481	0x525A	
+0x8482	0x525B	
+0x8483	0x525D	
+0x8484	0x525F	
+0x8485	0x5260	
+0x8486	0x5262	
+0x8487	0x5263	
+0x8488	0x5264	
+0x8489	0x5266	
+0x848A	0x5268	
+0x848B	0x526B	
+0x848C	0x526C	
+0x848D	0x526D	
+0x848E	0x526E	
+0x848F	0x5270	
+0x8490	0x5271	
+0x8491	0x5273	
+0x8492	0x5274	
+0x8493	0x5275	
+0x8494	0x5276	
+0x8495	0x5277	
+0x8496	0x5278	
+0x8497	0x5279	
+0x8498	0x527A	
+0x8499	0x527B	
+0x849A	0x527C	
+0x849B	0x527E	
+0x849C	0x5280	
+0x849D	0x5283	
+0x849E	0x5284	
+0x849F	0x5285	
+0x84A0	0x5286	
+0x84A1	0x5287	
+0x84A2	0x5289	
+0x84A3	0x528A	
+0x84A4	0x528B	
+0x84A5	0x528C	
+0x84A6	0x528D	
+0x84A7	0x528E	
+0x84A8	0x528F	
+0x84A9	0x5291	
+0x84AA	0x5292	
+0x84AB	0x5294	
+0x84AC	0x5295	
+0x84AD	0x5296	
+0x84AE	0x5297	
+0x84AF	0x5298	
+0x84B0	0x5299	
+0x84B1	0x529A	
+0x84B2	0x529C	
+0x84B3	0x52A4	
+0x84B4	0x52A5	
+0x84B5	0x52A6	
+0x84B6	0x52A7	
+0x84B7	0x52AE	
+0x84B8	0x52AF	
+0x84B9	0x52B0	
+0x84BA	0x52B4	
+0x84BB	0x52B5	
+0x84BC	0x52B6	
+0x84BD	0x52B7	
+0x84BE	0x52B8	
+0x84BF	0x52B9	
+0x84C0	0x52BA	
+0x84C1	0x52BB	
+0x84C2	0x52BC	
+0x84C3	0x52BD	
+0x84C4	0x52C0	
+0x84C5	0x52C1	
+0x84C6	0x52C2	
+0x84C7	0x52C4	
+0x84C8	0x52C5	
+0x84C9	0x52C6	
+0x84CA	0x52C8	
+0x84CB	0x52CA	
+0x84CC	0x52CC	
+0x84CD	0x52CD	
+0x84CE	0x52CE	
+0x84CF	0x52CF	
+0x84D0	0x52D1	
+0x84D1	0x52D3	
+0x84D2	0x52D4	
+0x84D3	0x52D5	
+0x84D4	0x52D7	
+0x84D5	0x52D9	
+0x84D6	0x52DA	
+0x84D7	0x52DB	
+0x84D8	0x52DC	
+0x84D9	0x52DD	
+0x84DA	0x52DE	
+0x84DB	0x52E0	
+0x84DC	0x52E1	
+0x84DD	0x52E2	
+0x84DE	0x52E3	
+0x84DF	0x52E5	
+0x84E0	0x52E6	
+0x84E1	0x52E7	
+0x84E2	0x52E8	
+0x84E3	0x52E9	
+0x84E4	0x52EA	
+0x84E5	0x52EB	
+0x84E6	0x52EC	
+0x84E7	0x52ED	
+0x84E8	0x52EE	
+0x84E9	0x52EF	
+0x84EA	0x52F1	
+0x84EB	0x52F2	
+0x84EC	0x52F3	
+0x84ED	0x52F4	
+0x84EE	0x52F5	
+0x84EF	0x52F6	
+0x84F0	0x52F7	
+0x84F1	0x52F8	
+0x84F2	0x52FB	
+0x84F3	0x52FC	
+0x84F4	0x52FD	
+0x84F5	0x5301	
+0x84F6	0x5302	
+0x84F7	0x5303	
+0x84F8	0x5304	
+0x84F9	0x5307	
+0x84FA	0x5309	
+0x84FB	0x530A	
+0x84FC	0x530B	
+0x84FD	0x530C	
+0x84FE	0x530E	
+0x8540	0x5311	
+0x8541	0x5312	
+0x8542	0x5313	
+0x8543	0x5314	
+0x8544	0x5318	
+0x8545	0x531B	
+0x8546	0x531C	
+0x8547	0x531E	
+0x8548	0x531F	
+0x8549	0x5322	
+0x854A	0x5324	
+0x854B	0x5325	
+0x854C	0x5327	
+0x854D	0x5328	
+0x854E	0x5329	
+0x854F	0x532B	
+0x8550	0x532C	
+0x8551	0x532D	
+0x8552	0x532F	
+0x8553	0x5330	
+0x8554	0x5331	
+0x8555	0x5332	
+0x8556	0x5333	
+0x8557	0x5334	
+0x8558	0x5335	
+0x8559	0x5336	
+0x855A	0x5337	
+0x855B	0x5338	
+0x855C	0x533C	
+0x855D	0x533D	
+0x855E	0x5340	
+0x855F	0x5342	
+0x8560	0x5344	
+0x8561	0x5346	
+0x8562	0x534B	
+0x8563	0x534C	
+0x8564	0x534D	
+0x8565	0x5350	
+0x8566	0x5354	
+0x8567	0x5358	
+0x8568	0x5359	
+0x8569	0x535B	
+0x856A	0x535D	
+0x856B	0x5365	
+0x856C	0x5368	
+0x856D	0x536A	
+0x856E	0x536C	
+0x856F	0x536D	
+0x8570	0x5372	
+0x8571	0x5376	
+0x8572	0x5379	
+0x8573	0x537B	
+0x8574	0x537C	
+0x8575	0x537D	
+0x8576	0x537E	
+0x8577	0x5380	
+0x8578	0x5381	
+0x8579	0x5383	
+0x857A	0x5387	
+0x857B	0x5388	
+0x857C	0x538A	
+0x857D	0x538E	
+0x857E	0x538F	
+0x8580	0x5390	
+0x8581	0x5391	
+0x8582	0x5392	
+0x8583	0x5393	
+0x8584	0x5394	
+0x8585	0x5396	
+0x8586	0x5397	
+0x8587	0x5399	
+0x8588	0x539B	
+0x8589	0x539C	
+0x858A	0x539E	
+0x858B	0x53A0	
+0x858C	0x53A1	
+0x858D	0x53A4	
+0x858E	0x53A7	
+0x858F	0x53AA	
+0x8590	0x53AB	
+0x8591	0x53AC	
+0x8592	0x53AD	
+0x8593	0x53AF	
+0x8594	0x53B0	
+0x8595	0x53B1	
+0x8596	0x53B2	
+0x8597	0x53B3	
+0x8598	0x53B4	
+0x8599	0x53B5	
+0x859A	0x53B7	
+0x859B	0x53B8	
+0x859C	0x53B9	
+0x859D	0x53BA	
+0x859E	0x53BC	
+0x859F	0x53BD	
+0x85A0	0x53BE	
+0x85A1	0x53C0	
+0x85A2	0x53C3	
+0x85A3	0x53C4	
+0x85A4	0x53C5	
+0x85A5	0x53C6	
+0x85A6	0x53C7	
+0x85A7	0x53CE	
+0x85A8	0x53CF	
+0x85A9	0x53D0	
+0x85AA	0x53D2	
+0x85AB	0x53D3	
+0x85AC	0x53D5	
+0x85AD	0x53DA	
+0x85AE	0x53DC	
+0x85AF	0x53DD	
+0x85B0	0x53DE	
+0x85B1	0x53E1	
+0x85B2	0x53E2	
+0x85B3	0x53E7	
+0x85B4	0x53F4	
+0x85B5	0x53FA	
+0x85B6	0x53FE	
+0x85B7	0x53FF	
+0x85B8	0x5400	
+0x85B9	0x5402	
+0x85BA	0x5405	
+0x85BB	0x5407	
+0x85BC	0x540B	
+0x85BD	0x5414	
+0x85BE	0x5418	
+0x85BF	0x5419	
+0x85C0	0x541A	
+0x85C1	0x541C	
+0x85C2	0x5422	
+0x85C3	0x5424	
+0x85C4	0x5425	
+0x85C5	0x542A	
+0x85C6	0x5430	
+0x85C7	0x5433	
+0x85C8	0x5436	
+0x85C9	0x5437	
+0x85CA	0x543A	
+0x85CB	0x543D	
+0x85CC	0x543F	
+0x85CD	0x5441	
+0x85CE	0x5442	
+0x85CF	0x5444	
+0x85D0	0x5445	
+0x85D1	0x5447	
+0x85D2	0x5449	
+0x85D3	0x544C	
+0x85D4	0x544D	
+0x85D5	0x544E	
+0x85D6	0x544F	
+0x85D7	0x5451	
+0x85D8	0x545A	
+0x85D9	0x545D	
+0x85DA	0x545E	
+0x85DB	0x545F	
+0x85DC	0x5460	
+0x85DD	0x5461	
+0x85DE	0x5463	
+0x85DF	0x5465	
+0x85E0	0x5467	
+0x85E1	0x5469	
+0x85E2	0x546A	
+0x85E3	0x546B	
+0x85E4	0x546C	
+0x85E5	0x546D	
+0x85E6	0x546E	
+0x85E7	0x546F	
+0x85E8	0x5470	
+0x85E9	0x5474	
+0x85EA	0x5479	
+0x85EB	0x547A	
+0x85EC	0x547E	
+0x85ED	0x547F	
+0x85EE	0x5481	
+0x85EF	0x5483	
+0x85F0	0x5485	
+0x85F1	0x5487	
+0x85F2	0x5488	
+0x85F3	0x5489	
+0x85F4	0x548A	
+0x85F5	0x548D	
+0x85F6	0x5491	
+0x85F7	0x5493	
+0x85F8	0x5497	
+0x85F9	0x5498	
+0x85FA	0x549C	
+0x85FB	0x549E	
+0x85FC	0x549F	
+0x85FD	0x54A0	
+0x85FE	0x54A1	
+0x8640	0x54A2	
+0x8641	0x54A5	
+0x8642	0x54AE	
+0x8643	0x54B0	
+0x8644	0x54B2	
+0x8645	0x54B5	
+0x8646	0x54B6	
+0x8647	0x54B7	
+0x8648	0x54B9	
+0x8649	0x54BA	
+0x864A	0x54BC	
+0x864B	0x54BE	
+0x864C	0x54C3	
+0x864D	0x54C5	
+0x864E	0x54CA	
+0x864F	0x54CB	
+0x8650	0x54D6	
+0x8651	0x54D8	
+0x8652	0x54DB	
+0x8653	0x54E0	
+0x8654	0x54E1	
+0x8655	0x54E2	
+0x8656	0x54E3	
+0x8657	0x54E4	
+0x8658	0x54EB	
+0x8659	0x54EC	
+0x865A	0x54EF	
+0x865B	0x54F0	
+0x865C	0x54F1	
+0x865D	0x54F4	
+0x865E	0x54F5	
+0x865F	0x54F6	
+0x8660	0x54F7	
+0x8661	0x54F8	
+0x8662	0x54F9	
+0x8663	0x54FB	
+0x8664	0x54FE	
+0x8665	0x5500	
+0x8666	0x5502	
+0x8667	0x5503	
+0x8668	0x5504	
+0x8669	0x5505	
+0x866A	0x5508	
+0x866B	0x550A	
+0x866C	0x550B	
+0x866D	0x550C	
+0x866E	0x550D	
+0x866F	0x550E	
+0x8670	0x5512	
+0x8671	0x5513	
+0x8672	0x5515	
+0x8673	0x5516	
+0x8674	0x5517	
+0x8675	0x5518	
+0x8676	0x5519	
+0x8677	0x551A	
+0x8678	0x551C	
+0x8679	0x551D	
+0x867A	0x551E	
+0x867B	0x551F	
+0x867C	0x5521	
+0x867D	0x5525	
+0x867E	0x5526	
+0x8680	0x5528	
+0x8681	0x5529	
+0x8682	0x552B	
+0x8683	0x552D	
+0x8684	0x5532	
+0x8685	0x5534	
+0x8686	0x5535	
+0x8687	0x5536	
+0x8688	0x5538	
+0x8689	0x5539	
+0x868A	0x553A	
+0x868B	0x553B	
+0x868C	0x553D	
+0x868D	0x5540	
+0x868E	0x5542	
+0x868F	0x5545	
+0x8690	0x5547	
+0x8691	0x5548	
+0x8692	0x554B	
+0x8693	0x554C	
+0x8694	0x554D	
+0x8695	0x554E	
+0x8696	0x554F	
+0x8697	0x5551	
+0x8698	0x5552	
+0x8699	0x5553	
+0x869A	0x5554	
+0x869B	0x5557	
+0x869C	0x5558	
+0x869D	0x5559	
+0x869E	0x555A	
+0x869F	0x555B	
+0x86A0	0x555D	
+0x86A1	0x555E	
+0x86A2	0x555F	
+0x86A3	0x5560	
+0x86A4	0x5562	
+0x86A5	0x5563	
+0x86A6	0x5568	
+0x86A7	0x5569	
+0x86A8	0x556B	
+0x86A9	0x556F	
+0x86AA	0x5570	
+0x86AB	0x5571	
+0x86AC	0x5572	
+0x86AD	0x5573	
+0x86AE	0x5574	
+0x86AF	0x5579	
+0x86B0	0x557A	
+0x86B1	0x557D	
+0x86B2	0x557F	
+0x86B3	0x5585	
+0x86B4	0x5586	
+0x86B5	0x558C	
+0x86B6	0x558D	
+0x86B7	0x558E	
+0x86B8	0x5590	
+0x86B9	0x5592	
+0x86BA	0x5593	
+0x86BB	0x5595	
+0x86BC	0x5596	
+0x86BD	0x5597	
+0x86BE	0x559A	
+0x86BF	0x559B	
+0x86C0	0x559E	
+0x86C1	0x55A0	
+0x86C2	0x55A1	
+0x86C3	0x55A2	
+0x86C4	0x55A3	
+0x86C5	0x55A4	
+0x86C6	0x55A5	
+0x86C7	0x55A6	
+0x86C8	0x55A8	
+0x86C9	0x55A9	
+0x86CA	0x55AA	
+0x86CB	0x55AB	
+0x86CC	0x55AC	
+0x86CD	0x55AD	
+0x86CE	0x55AE	
+0x86CF	0x55AF	
+0x86D0	0x55B0	
+0x86D1	0x55B2	
+0x86D2	0x55B4	
+0x86D3	0x55B6	
+0x86D4	0x55B8	
+0x86D5	0x55BA	
+0x86D6	0x55BC	
+0x86D7	0x55BF	
+0x86D8	0x55C0	
+0x86D9	0x55C1	
+0x86DA	0x55C2	
+0x86DB	0x55C3	
+0x86DC	0x55C6	
+0x86DD	0x55C7	
+0x86DE	0x55C8	
+0x86DF	0x55CA	
+0x86E0	0x55CB	
+0x86E1	0x55CE	
+0x86E2	0x55CF	
+0x86E3	0x55D0	
+0x86E4	0x55D5	
+0x86E5	0x55D7	
+0x86E6	0x55D8	
+0x86E7	0x55D9	
+0x86E8	0x55DA	
+0x86E9	0x55DB	
+0x86EA	0x55DE	
+0x86EB	0x55E0	
+0x86EC	0x55E2	
+0x86ED	0x55E7	
+0x86EE	0x55E9	
+0x86EF	0x55ED	
+0x86F0	0x55EE	
+0x86F1	0x55F0	
+0x86F2	0x55F1	
+0x86F3	0x55F4	
+0x86F4	0x55F6	
+0x86F5	0x55F8	
+0x86F6	0x55F9	
+0x86F7	0x55FA	
+0x86F8	0x55FB	
+0x86F9	0x55FC	
+0x86FA	0x55FF	
+0x86FB	0x5602	
+0x86FC	0x5603	
+0x86FD	0x5604	
+0x86FE	0x5605	
+0x8740	0x5606	
+0x8741	0x5607	
+0x8742	0x560A	
+0x8743	0x560B	
+0x8744	0x560D	
+0x8745	0x5610	
+0x8746	0x5611	
+0x8747	0x5612	
+0x8748	0x5613	
+0x8749	0x5614	
+0x874A	0x5615	
+0x874B	0x5616	
+0x874C	0x5617	
+0x874D	0x5619	
+0x874E	0x561A	
+0x874F	0x561C	
+0x8750	0x561D	
+0x8751	0x5620	
+0x8752	0x5621	
+0x8753	0x5622	
+0x8754	0x5625	
+0x8755	0x5626	
+0x8756	0x5628	
+0x8757	0x5629	
+0x8758	0x562A	
+0x8759	0x562B	
+0x875A	0x562E	
+0x875B	0x562F	
+0x875C	0x5630	
+0x875D	0x5633	
+0x875E	0x5635	
+0x875F	0x5637	
+0x8760	0x5638	
+0x8761	0x563A	
+0x8762	0x563C	
+0x8763	0x563D	
+0x8764	0x563E	
+0x8765	0x5640	
+0x8766	0x5641	
+0x8767	0x5642	
+0x8768	0x5643	
+0x8769	0x5644	
+0x876A	0x5645	
+0x876B	0x5646	
+0x876C	0x5647	
+0x876D	0x5648	
+0x876E	0x5649	
+0x876F	0x564A	
+0x8770	0x564B	
+0x8771	0x564F	
+0x8772	0x5650	
+0x8773	0x5651	
+0x8774	0x5652	
+0x8775	0x5653	
+0x8776	0x5655	
+0x8777	0x5656	
+0x8778	0x565A	
+0x8779	0x565B	
+0x877A	0x565D	
+0x877B	0x565E	
+0x877C	0x565F	
+0x877D	0x5660	
+0x877E	0x5661	
+0x8780	0x5663	
+0x8781	0x5665	
+0x8782	0x5666	
+0x8783	0x5667	
+0x8784	0x566D	
+0x8785	0x566E	
+0x8786	0x566F	
+0x8787	0x5670	
+0x8788	0x5672	
+0x8789	0x5673	
+0x878A	0x5674	
+0x878B	0x5675	
+0x878C	0x5677	
+0x878D	0x5678	
+0x878E	0x5679	
+0x878F	0x567A	
+0x8790	0x567D	
+0x8791	0x567E	
+0x8792	0x567F	
+0x8793	0x5680	
+0x8794	0x5681	
+0x8795	0x5682	
+0x8796	0x5683	
+0x8797	0x5684	
+0x8798	0x5687	
+0x8799	0x5688	
+0x879A	0x5689	
+0x879B	0x568A	
+0x879C	0x568B	
+0x879D	0x568C	
+0x879E	0x568D	
+0x879F	0x5690	
+0x87A0	0x5691	
+0x87A1	0x5692	
+0x87A2	0x5694	
+0x87A3	0x5695	
+0x87A4	0x5696	
+0x87A5	0x5697	
+0x87A6	0x5698	
+0x87A7	0x5699	
+0x87A8	0x569A	
+0x87A9	0x569B	
+0x87AA	0x569C	
+0x87AB	0x569D	
+0x87AC	0x569E	
+0x87AD	0x569F	
+0x87AE	0x56A0	
+0x87AF	0x56A1	
+0x87B0	0x56A2	
+0x87B1	0x56A4	
+0x87B2	0x56A5	
+0x87B3	0x56A6	
+0x87B4	0x56A7	
+0x87B5	0x56A8	
+0x87B6	0x56A9	
+0x87B7	0x56AA	
+0x87B8	0x56AB	
+0x87B9	0x56AC	
+0x87BA	0x56AD	
+0x87BB	0x56AE	
+0x87BC	0x56B0	
+0x87BD	0x56B1	
+0x87BE	0x56B2	
+0x87BF	0x56B3	
+0x87C0	0x56B4	
+0x87C1	0x56B5	
+0x87C2	0x56B6	
+0x87C3	0x56B8	
+0x87C4	0x56B9	
+0x87C5	0x56BA	
+0x87C6	0x56BB	
+0x87C7	0x56BD	
+0x87C8	0x56BE	
+0x87C9	0x56BF	
+0x87CA	0x56C0	
+0x87CB	0x56C1	
+0x87CC	0x56C2	
+0x87CD	0x56C3	
+0x87CE	0x56C4	
+0x87CF	0x56C5	
+0x87D0	0x56C6	
+0x87D1	0x56C7	
+0x87D2	0x56C8	
+0x87D3	0x56C9	
+0x87D4	0x56CB	
+0x87D5	0x56CC	
+0x87D6	0x56CD	
+0x87D7	0x56CE	
+0x87D8	0x56CF	
+0x87D9	0x56D0	
+0x87DA	0x56D1	
+0x87DB	0x56D2	
+0x87DC	0x56D3	
+0x87DD	0x56D5	
+0x87DE	0x56D6	
+0x87DF	0x56D8	
+0x87E0	0x56D9	
+0x87E1	0x56DC	
+0x87E2	0x56E3	
+0x87E3	0x56E5	
+0x87E4	0x56E6	
+0x87E5	0x56E7	
+0x87E6	0x56E8	
+0x87E7	0x56E9	
+0x87E8	0x56EA	
+0x87E9	0x56EC	
+0x87EA	0x56EE	
+0x87EB	0x56EF	
+0x87EC	0x56F2	
+0x87ED	0x56F3	
+0x87EE	0x56F6	
+0x87EF	0x56F7	
+0x87F0	0x56F8	
+0x87F1	0x56FB	
+0x87F2	0x56FC	
+0x87F3	0x5700	
+0x87F4	0x5701	
+0x87F5	0x5702	
+0x87F6	0x5705	
+0x87F7	0x5707	
+0x87F8	0x570B	
+0x87F9	0x570C	
+0x87FA	0x570D	
+0x87FB	0x570E	
+0x87FC	0x570F	
+0x87FD	0x5710	
+0x87FE	0x5711	
+0x8840	0x5712	
+0x8841	0x5713	
+0x8842	0x5714	
+0x8843	0x5715	
+0x8844	0x5716	
+0x8845	0x5717	
+0x8846	0x5718	
+0x8847	0x5719	
+0x8848	0x571A	
+0x8849	0x571B	
+0x884A	0x571D	
+0x884B	0x571E	
+0x884C	0x5720	
+0x884D	0x5721	
+0x884E	0x5722	
+0x884F	0x5724	
+0x8850	0x5725	
+0x8851	0x5726	
+0x8852	0x5727	
+0x8853	0x572B	
+0x8854	0x5731	
+0x8855	0x5732	
+0x8856	0x5734	
+0x8857	0x5735	
+0x8858	0x5736	
+0x8859	0x5737	
+0x885A	0x5738	
+0x885B	0x573C	
+0x885C	0x573D	
+0x885D	0x573F	
+0x885E	0x5741	
+0x885F	0x5743	
+0x8860	0x5744	
+0x8861	0x5745	
+0x8862	0x5746	
+0x8863	0x5748	
+0x8864	0x5749	
+0x8865	0x574B	
+0x8866	0x5752	
+0x8867	0x5753	
+0x8868	0x5754	
+0x8869	0x5755	
+0x886A	0x5756	
+0x886B	0x5758	
+0x886C	0x5759	
+0x886D	0x5762	
+0x886E	0x5763	
+0x886F	0x5765	
+0x8870	0x5767	
+0x8871	0x576C	
+0x8872	0x576E	
+0x8873	0x5770	
+0x8874	0x5771	
+0x8875	0x5772	
+0x8876	0x5774	
+0x8877	0x5775	
+0x8878	0x5778	
+0x8879	0x5779	
+0x887A	0x577A	
+0x887B	0x577D	
+0x887C	0x577E	
+0x887D	0x577F	
+0x887E	0x5780	
+0x8880	0x5781	
+0x8881	0x5787	
+0x8882	0x5788	
+0x8883	0x5789	
+0x8884	0x578A	
+0x8885	0x578D	
+0x8886	0x578E	
+0x8887	0x578F	
+0x8888	0x5790	
+0x8889	0x5791	
+0x888A	0x5794	
+0x888B	0x5795	
+0x888C	0x5796	
+0x888D	0x5797	
+0x888E	0x5798	
+0x888F	0x5799	
+0x8890	0x579A	
+0x8891	0x579C	
+0x8892	0x579D	
+0x8893	0x579E	
+0x8894	0x579F	
+0x8895	0x57A5	
+0x8896	0x57A8	
+0x8897	0x57AA	
+0x8898	0x57AC	
+0x8899	0x57AF	
+0x889A	0x57B0	
+0x889B	0x57B1	
+0x889C	0x57B3	
+0x889D	0x57B5	
+0x889E	0x57B6	
+0x889F	0x57B7	
+0x88A0	0x57B9	
+0x88A1	0x57BA	
+0x88A2	0x57BB	
+0x88A3	0x57BC	
+0x88A4	0x57BD	
+0x88A5	0x57BE	
+0x88A6	0x57BF	
+0x88A7	0x57C0	
+0x88A8	0x57C1	
+0x88A9	0x57C4	
+0x88AA	0x57C5	
+0x88AB	0x57C6	
+0x88AC	0x57C7	
+0x88AD	0x57C8	
+0x88AE	0x57C9	
+0x88AF	0x57CA	
+0x88B0	0x57CC	
+0x88B1	0x57CD	
+0x88B2	0x57D0	
+0x88B3	0x57D1	
+0x88B4	0x57D3	
+0x88B5	0x57D6	
+0x88B6	0x57D7	
+0x88B7	0x57DB	
+0x88B8	0x57DC	
+0x88B9	0x57DE	
+0x88BA	0x57E1	
+0x88BB	0x57E2	
+0x88BC	0x57E3	
+0x88BD	0x57E5	
+0x88BE	0x57E6	
+0x88BF	0x57E7	
+0x88C0	0x57E8	
+0x88C1	0x57E9	
+0x88C2	0x57EA	
+0x88C3	0x57EB	
+0x88C4	0x57EC	
+0x88C5	0x57EE	
+0x88C6	0x57F0	
+0x88C7	0x57F1	
+0x88C8	0x57F2	
+0x88C9	0x57F3	
+0x88CA	0x57F5	
+0x88CB	0x57F6	
+0x88CC	0x57F7	
+0x88CD	0x57FB	
+0x88CE	0x57FC	
+0x88CF	0x57FE	
+0x88D0	0x57FF	
+0x88D1	0x5801	
+0x88D2	0x5803	
+0x88D3	0x5804	
+0x88D4	0x5805	
+0x88D5	0x5808	
+0x88D6	0x5809	
+0x88D7	0x580A	
+0x88D8	0x580C	
+0x88D9	0x580E	
+0x88DA	0x580F	
+0x88DB	0x5810	
+0x88DC	0x5812	
+0x88DD	0x5813	
+0x88DE	0x5814	
+0x88DF	0x5816	
+0x88E0	0x5817	
+0x88E1	0x5818	
+0x88E2	0x581A	
+0x88E3	0x581B	
+0x88E4	0x581C	
+0x88E5	0x581D	
+0x88E6	0x581F	
+0x88E7	0x5822	
+0x88E8	0x5823	
+0x88E9	0x5825	
+0x88EA	0x5826	
+0x88EB	0x5827	
+0x88EC	0x5828	
+0x88ED	0x5829	
+0x88EE	0x582B	
+0x88EF	0x582C	
+0x88F0	0x582D	
+0x88F1	0x582E	
+0x88F2	0x582F	
+0x88F3	0x5831	
+0x88F4	0x5832	
+0x88F5	0x5833	
+0x88F6	0x5834	
+0x88F7	0x5836	
+0x88F8	0x5837	
+0x88F9	0x5838	
+0x88FA	0x5839	
+0x88FB	0x583A	
+0x88FC	0x583B	
+0x88FD	0x583C	
+0x88FE	0x583D	
+0x8940	0x583E	
+0x8941	0x583F	
+0x8942	0x5840	
+0x8943	0x5841	
+0x8944	0x5842	
+0x8945	0x5843	
+0x8946	0x5845	
+0x8947	0x5846	
+0x8948	0x5847	
+0x8949	0x5848	
+0x894A	0x5849	
+0x894B	0x584A	
+0x894C	0x584B	
+0x894D	0x584E	
+0x894E	0x584F	
+0x894F	0x5850	
+0x8950	0x5852	
+0x8951	0x5853	
+0x8952	0x5855	
+0x8953	0x5856	
+0x8954	0x5857	
+0x8955	0x5859	
+0x8956	0x585A	
+0x8957	0x585B	
+0x8958	0x585C	
+0x8959	0x585D	
+0x895A	0x585F	
+0x895B	0x5860	
+0x895C	0x5861	
+0x895D	0x5862	
+0x895E	0x5863	
+0x895F	0x5864	
+0x8960	0x5866	
+0x8961	0x5867	
+0x8962	0x5868	
+0x8963	0x5869	
+0x8964	0x586A	
+0x8965	0x586D	
+0x8966	0x586E	
+0x8967	0x586F	
+0x8968	0x5870	
+0x8969	0x5871	
+0x896A	0x5872	
+0x896B	0x5873	
+0x896C	0x5874	
+0x896D	0x5875	
+0x896E	0x5876	
+0x896F	0x5877	
+0x8970	0x5878	
+0x8971	0x5879	
+0x8972	0x587A	
+0x8973	0x587B	
+0x8974	0x587C	
+0x8975	0x587D	
+0x8976	0x587F	
+0x8977	0x5882	
+0x8978	0x5884	
+0x8979	0x5886	
+0x897A	0x5887	
+0x897B	0x5888	
+0x897C	0x588A	
+0x897D	0x588B	
+0x897E	0x588C	
+0x8980	0x588D	
+0x8981	0x588E	
+0x8982	0x588F	
+0x8983	0x5890	
+0x8984	0x5891	
+0x8985	0x5894	
+0x8986	0x5895	
+0x8987	0x5896	
+0x8988	0x5897	
+0x8989	0x5898	
+0x898A	0x589B	
+0x898B	0x589C	
+0x898C	0x589D	
+0x898D	0x58A0	
+0x898E	0x58A1	
+0x898F	0x58A2	
+0x8990	0x58A3	
+0x8991	0x58A4	
+0x8992	0x58A5	
+0x8993	0x58A6	
+0x8994	0x58A7	
+0x8995	0x58AA	
+0x8996	0x58AB	
+0x8997	0x58AC	
+0x8998	0x58AD	
+0x8999	0x58AE	
+0x899A	0x58AF	
+0x899B	0x58B0	
+0x899C	0x58B1	
+0x899D	0x58B2	
+0x899E	0x58B3	
+0x899F	0x58B4	
+0x89A0	0x58B5	
+0x89A1	0x58B6	
+0x89A2	0x58B7	
+0x89A3	0x58B8	
+0x89A4	0x58B9	
+0x89A5	0x58BA	
+0x89A6	0x58BB	
+0x89A7	0x58BD	
+0x89A8	0x58BE	
+0x89A9	0x58BF	
+0x89AA	0x58C0	
+0x89AB	0x58C2	
+0x89AC	0x58C3	
+0x89AD	0x58C4	
+0x89AE	0x58C6	
+0x89AF	0x58C7	
+0x89B0	0x58C8	
+0x89B1	0x58C9	
+0x89B2	0x58CA	
+0x89B3	0x58CB	
+0x89B4	0x58CC	
+0x89B5	0x58CD	
+0x89B6	0x58CE	
+0x89B7	0x58CF	
+0x89B8	0x58D0	
+0x89B9	0x58D2	
+0x89BA	0x58D3	
+0x89BB	0x58D4	
+0x89BC	0x58D6	
+0x89BD	0x58D7	
+0x89BE	0x58D8	
+0x89BF	0x58D9	
+0x89C0	0x58DA	
+0x89C1	0x58DB	
+0x89C2	0x58DC	
+0x89C3	0x58DD	
+0x89C4	0x58DE	
+0x89C5	0x58DF	
+0x89C6	0x58E0	
+0x89C7	0x58E1	
+0x89C8	0x58E2	
+0x89C9	0x58E3	
+0x89CA	0x58E5	
+0x89CB	0x58E6	
+0x89CC	0x58E7	
+0x89CD	0x58E8	
+0x89CE	0x58E9	
+0x89CF	0x58EA	
+0x89D0	0x58ED	
+0x89D1	0x58EF	
+0x89D2	0x58F1	
+0x89D3	0x58F2	
+0x89D4	0x58F4	
+0x89D5	0x58F5	
+0x89D6	0x58F7	
+0x89D7	0x58F8	
+0x89D8	0x58FA	
+0x89D9	0x58FB	
+0x89DA	0x58FC	
+0x89DB	0x58FD	
+0x89DC	0x58FE	
+0x89DD	0x58FF	
+0x89DE	0x5900	
+0x89DF	0x5901	
+0x89E0	0x5903	
+0x89E1	0x5905	
+0x89E2	0x5906	
+0x89E3	0x5908	
+0x89E4	0x5909	
+0x89E5	0x590A	
+0x89E6	0x590B	
+0x89E7	0x590C	
+0x89E8	0x590E	
+0x89E9	0x5910	
+0x89EA	0x5911	
+0x89EB	0x5912	
+0x89EC	0x5913	
+0x89ED	0x5917	
+0x89EE	0x5918	
+0x89EF	0x591B	
+0x89F0	0x591D	
+0x89F1	0x591E	
+0x89F2	0x5920	
+0x89F3	0x5921	
+0x89F4	0x5922	
+0x89F5	0x5923	
+0x89F6	0x5926	
+0x89F7	0x5928	
+0x89F8	0x592C	
+0x89F9	0x5930	
+0x89FA	0x5932	
+0x89FB	0x5933	
+0x89FC	0x5935	
+0x89FD	0x5936	
+0x89FE	0x593B	
+0x8A40	0x593D	
+0x8A41	0x593E	
+0x8A42	0x593F	
+0x8A43	0x5940	
+0x8A44	0x5943	
+0x8A45	0x5945	
+0x8A46	0x5946	
+0x8A47	0x594A	
+0x8A48	0x594C	
+0x8A49	0x594D	
+0x8A4A	0x5950	
+0x8A4B	0x5952	
+0x8A4C	0x5953	
+0x8A4D	0x5959	
+0x8A4E	0x595B	
+0x8A4F	0x595C	
+0x8A50	0x595D	
+0x8A51	0x595E	
+0x8A52	0x595F	
+0x8A53	0x5961	
+0x8A54	0x5963	
+0x8A55	0x5964	
+0x8A56	0x5966	
+0x8A57	0x5967	
+0x8A58	0x5968	
+0x8A59	0x5969	
+0x8A5A	0x596A	
+0x8A5B	0x596B	
+0x8A5C	0x596C	
+0x8A5D	0x596D	
+0x8A5E	0x596E	
+0x8A5F	0x596F	
+0x8A60	0x5970	
+0x8A61	0x5971	
+0x8A62	0x5972	
+0x8A63	0x5975	
+0x8A64	0x5977	
+0x8A65	0x597A	
+0x8A66	0x597B	
+0x8A67	0x597C	
+0x8A68	0x597E	
+0x8A69	0x597F	
+0x8A6A	0x5980	
+0x8A6B	0x5985	
+0x8A6C	0x5989	
+0x8A6D	0x598B	
+0x8A6E	0x598C	
+0x8A6F	0x598E	
+0x8A70	0x598F	
+0x8A71	0x5990	
+0x8A72	0x5991	
+0x8A73	0x5994	
+0x8A74	0x5995	
+0x8A75	0x5998	
+0x8A76	0x599A	
+0x8A77	0x599B	
+0x8A78	0x599C	
+0x8A79	0x599D	
+0x8A7A	0x599F	
+0x8A7B	0x59A0	
+0x8A7C	0x59A1	
+0x8A7D	0x59A2	
+0x8A7E	0x59A6	
+0x8A80	0x59A7	
+0x8A81	0x59AC	
+0x8A82	0x59AD	
+0x8A83	0x59B0	
+0x8A84	0x59B1	
+0x8A85	0x59B3	
+0x8A86	0x59B4	
+0x8A87	0x59B5	
+0x8A88	0x59B6	
+0x8A89	0x59B7	
+0x8A8A	0x59B8	
+0x8A8B	0x59BA	
+0x8A8C	0x59BC	
+0x8A8D	0x59BD	
+0x8A8E	0x59BF	
+0x8A8F	0x59C0	
+0x8A90	0x59C1	
+0x8A91	0x59C2	
+0x8A92	0x59C3	
+0x8A93	0x59C4	
+0x8A94	0x59C5	
+0x8A95	0x59C7	
+0x8A96	0x59C8	
+0x8A97	0x59C9	
+0x8A98	0x59CC	
+0x8A99	0x59CD	
+0x8A9A	0x59CE	
+0x8A9B	0x59CF	
+0x8A9C	0x59D5	
+0x8A9D	0x59D6	
+0x8A9E	0x59D9	
+0x8A9F	0x59DB	
+0x8AA0	0x59DE	
+0x8AA1	0x59DF	
+0x8AA2	0x59E0	
+0x8AA3	0x59E1	
+0x8AA4	0x59E2	
+0x8AA5	0x59E4	
+0x8AA6	0x59E6	
+0x8AA7	0x59E7	
+0x8AA8	0x59E9	
+0x8AA9	0x59EA	
+0x8AAA	0x59EB	
+0x8AAB	0x59ED	
+0x8AAC	0x59EE	
+0x8AAD	0x59EF	
+0x8AAE	0x59F0	
+0x8AAF	0x59F1	
+0x8AB0	0x59F2	
+0x8AB1	0x59F3	
+0x8AB2	0x59F4	
+0x8AB3	0x59F5	
+0x8AB4	0x59F6	
+0x8AB5	0x59F7	
+0x8AB6	0x59F8	
+0x8AB7	0x59FA	
+0x8AB8	0x59FC	
+0x8AB9	0x59FD	
+0x8ABA	0x59FE	
+0x8ABB	0x5A00	
+0x8ABC	0x5A02	
+0x8ABD	0x5A0A	
+0x8ABE	0x5A0B	
+0x8ABF	0x5A0D	
+0x8AC0	0x5A0E	
+0x8AC1	0x5A0F	
+0x8AC2	0x5A10	
+0x8AC3	0x5A12	
+0x8AC4	0x5A14	
+0x8AC5	0x5A15	
+0x8AC6	0x5A16	
+0x8AC7	0x5A17	
+0x8AC8	0x5A19	
+0x8AC9	0x5A1A	
+0x8ACA	0x5A1B	
+0x8ACB	0x5A1D	
+0x8ACC	0x5A1E	
+0x8ACD	0x5A21	
+0x8ACE	0x5A22	
+0x8ACF	0x5A24	
+0x8AD0	0x5A26	
+0x8AD1	0x5A27	
+0x8AD2	0x5A28	
+0x8AD3	0x5A2A	
+0x8AD4	0x5A2B	
+0x8AD5	0x5A2C	
+0x8AD6	0x5A2D	
+0x8AD7	0x5A2E	
+0x8AD8	0x5A2F	
+0x8AD9	0x5A30	
+0x8ADA	0x5A33	
+0x8ADB	0x5A35	
+0x8ADC	0x5A37	
+0x8ADD	0x5A38	
+0x8ADE	0x5A39	
+0x8ADF	0x5A3A	
+0x8AE0	0x5A3B	
+0x8AE1	0x5A3D	
+0x8AE2	0x5A3E	
+0x8AE3	0x5A3F	
+0x8AE4	0x5A41	
+0x8AE5	0x5A42	
+0x8AE6	0x5A43	
+0x8AE7	0x5A44	
+0x8AE8	0x5A45	
+0x8AE9	0x5A47	
+0x8AEA	0x5A48	
+0x8AEB	0x5A4B	
+0x8AEC	0x5A4C	
+0x8AED	0x5A4D	
+0x8AEE	0x5A4E	
+0x8AEF	0x5A4F	
+0x8AF0	0x5A50	
+0x8AF1	0x5A51	
+0x8AF2	0x5A52	
+0x8AF3	0x5A53	
+0x8AF4	0x5A54	
+0x8AF5	0x5A56	
+0x8AF6	0x5A57	
+0x8AF7	0x5A58	
+0x8AF8	0x5A59	
+0x8AF9	0x5A5B	
+0x8AFA	0x5A5C	
+0x8AFB	0x5A5D	
+0x8AFC	0x5A5E	
+0x8AFD	0x5A5F	
+0x8AFE	0x5A60	
+0x8B40	0x5A61	
+0x8B41	0x5A63	
+0x8B42	0x5A64	
+0x8B43	0x5A65	
+0x8B44	0x5A66	
+0x8B45	0x5A68	
+0x8B46	0x5A69	
+0x8B47	0x5A6B	
+0x8B48	0x5A6C	
+0x8B49	0x5A6D	
+0x8B4A	0x5A6E	
+0x8B4B	0x5A6F	
+0x8B4C	0x5A70	
+0x8B4D	0x5A71	
+0x8B4E	0x5A72	
+0x8B4F	0x5A73	
+0x8B50	0x5A78	
+0x8B51	0x5A79	
+0x8B52	0x5A7B	
+0x8B53	0x5A7C	
+0x8B54	0x5A7D	
+0x8B55	0x5A7E	
+0x8B56	0x5A80	
+0x8B57	0x5A81	
+0x8B58	0x5A82	
+0x8B59	0x5A83	
+0x8B5A	0x5A84	
+0x8B5B	0x5A85	
+0x8B5C	0x5A86	
+0x8B5D	0x5A87	
+0x8B5E	0x5A88	
+0x8B5F	0x5A89	
+0x8B60	0x5A8A	
+0x8B61	0x5A8B	
+0x8B62	0x5A8C	
+0x8B63	0x5A8D	
+0x8B64	0x5A8E	
+0x8B65	0x5A8F	
+0x8B66	0x5A90	
+0x8B67	0x5A91	
+0x8B68	0x5A93	
+0x8B69	0x5A94	
+0x8B6A	0x5A95	
+0x8B6B	0x5A96	
+0x8B6C	0x5A97	
+0x8B6D	0x5A98	
+0x8B6E	0x5A99	
+0x8B6F	0x5A9C	
+0x8B70	0x5A9D	
+0x8B71	0x5A9E	
+0x8B72	0x5A9F	
+0x8B73	0x5AA0	
+0x8B74	0x5AA1	
+0x8B75	0x5AA2	
+0x8B76	0x5AA3	
+0x8B77	0x5AA4	
+0x8B78	0x5AA5	
+0x8B79	0x5AA6	
+0x8B7A	0x5AA7	
+0x8B7B	0x5AA8	
+0x8B7C	0x5AA9	
+0x8B7D	0x5AAB	
+0x8B7E	0x5AAC	
+0x8B80	0x5AAD	
+0x8B81	0x5AAE	
+0x8B82	0x5AAF	
+0x8B83	0x5AB0	
+0x8B84	0x5AB1	
+0x8B85	0x5AB4	
+0x8B86	0x5AB6	
+0x8B87	0x5AB7	
+0x8B88	0x5AB9	
+0x8B89	0x5ABA	
+0x8B8A	0x5ABB	
+0x8B8B	0x5ABC	
+0x8B8C	0x5ABD	
+0x8B8D	0x5ABF	
+0x8B8E	0x5AC0	
+0x8B8F	0x5AC3	
+0x8B90	0x5AC4	
+0x8B91	0x5AC5	
+0x8B92	0x5AC6	
+0x8B93	0x5AC7	
+0x8B94	0x5AC8	
+0x8B95	0x5ACA	
+0x8B96	0x5ACB	
+0x8B97	0x5ACD	
+0x8B98	0x5ACE	
+0x8B99	0x5ACF	
+0x8B9A	0x5AD0	
+0x8B9B	0x5AD1	
+0x8B9C	0x5AD3	
+0x8B9D	0x5AD5	
+0x8B9E	0x5AD7	
+0x8B9F	0x5AD9	
+0x8BA0	0x5ADA	
+0x8BA1	0x5ADB	
+0x8BA2	0x5ADD	
+0x8BA3	0x5ADE	
+0x8BA4	0x5ADF	
+0x8BA5	0x5AE2	
+0x8BA6	0x5AE4	
+0x8BA7	0x5AE5	
+0x8BA8	0x5AE7	
+0x8BA9	0x5AE8	
+0x8BAA	0x5AEA	
+0x8BAB	0x5AEC	
+0x8BAC	0x5AED	
+0x8BAD	0x5AEE	
+0x8BAE	0x5AEF	
+0x8BAF	0x5AF0	
+0x8BB0	0x5AF2	
+0x8BB1	0x5AF3	
+0x8BB2	0x5AF4	
+0x8BB3	0x5AF5	
+0x8BB4	0x5AF6	
+0x8BB5	0x5AF7	
+0x8BB6	0x5AF8	
+0x8BB7	0x5AF9	
+0x8BB8	0x5AFA	
+0x8BB9	0x5AFB	
+0x8BBA	0x5AFC	
+0x8BBB	0x5AFD	
+0x8BBC	0x5AFE	
+0x8BBD	0x5AFF	
+0x8BBE	0x5B00	
+0x8BBF	0x5B01	
+0x8BC0	0x5B02	
+0x8BC1	0x5B03	
+0x8BC2	0x5B04	
+0x8BC3	0x5B05	
+0x8BC4	0x5B06	
+0x8BC5	0x5B07	
+0x8BC6	0x5B08	
+0x8BC7	0x5B0A	
+0x8BC8	0x5B0B	
+0x8BC9	0x5B0C	
+0x8BCA	0x5B0D	
+0x8BCB	0x5B0E	
+0x8BCC	0x5B0F	
+0x8BCD	0x5B10	
+0x8BCE	0x5B11	
+0x8BCF	0x5B12	
+0x8BD0	0x5B13	
+0x8BD1	0x5B14	
+0x8BD2	0x5B15	
+0x8BD3	0x5B18	
+0x8BD4	0x5B19	
+0x8BD5	0x5B1A	
+0x8BD6	0x5B1B	
+0x8BD7	0x5B1C	
+0x8BD8	0x5B1D	
+0x8BD9	0x5B1E	
+0x8BDA	0x5B1F	
+0x8BDB	0x5B20	
+0x8BDC	0x5B21	
+0x8BDD	0x5B22	
+0x8BDE	0x5B23	
+0x8BDF	0x5B24	
+0x8BE0	0x5B25	
+0x8BE1	0x5B26	
+0x8BE2	0x5B27	
+0x8BE3	0x5B28	
+0x8BE4	0x5B29	
+0x8BE5	0x5B2A	
+0x8BE6	0x5B2B	
+0x8BE7	0x5B2C	
+0x8BE8	0x5B2D	
+0x8BE9	0x5B2E	
+0x8BEA	0x5B2F	
+0x8BEB	0x5B30	
+0x8BEC	0x5B31	
+0x8BED	0x5B33	
+0x8BEE	0x5B35	
+0x8BEF	0x5B36	
+0x8BF0	0x5B38	
+0x8BF1	0x5B39	
+0x8BF2	0x5B3A	
+0x8BF3	0x5B3B	
+0x8BF4	0x5B3C	
+0x8BF5	0x5B3D	
+0x8BF6	0x5B3E	
+0x8BF7	0x5B3F	
+0x8BF8	0x5B41	
+0x8BF9	0x5B42	
+0x8BFA	0x5B43	
+0x8BFB	0x5B44	
+0x8BFC	0x5B45	
+0x8BFD	0x5B46	
+0x8BFE	0x5B47	
+0x8C40	0x5B48	
+0x8C41	0x5B49	
+0x8C42	0x5B4A	
+0x8C43	0x5B4B	
+0x8C44	0x5B4C	
+0x8C45	0x5B4D	
+0x8C46	0x5B4E	
+0x8C47	0x5B4F	
+0x8C48	0x5B52	
+0x8C49	0x5B56	
+0x8C4A	0x5B5E	
+0x8C4B	0x5B60	
+0x8C4C	0x5B61	
+0x8C4D	0x5B67	
+0x8C4E	0x5B68	
+0x8C4F	0x5B6B	
+0x8C50	0x5B6D	
+0x8C51	0x5B6E	
+0x8C52	0x5B6F	
+0x8C53	0x5B72	
+0x8C54	0x5B74	
+0x8C55	0x5B76	
+0x8C56	0x5B77	
+0x8C57	0x5B78	
+0x8C58	0x5B79	
+0x8C59	0x5B7B	
+0x8C5A	0x5B7C	
+0x8C5B	0x5B7E	
+0x8C5C	0x5B7F	
+0x8C5D	0x5B82	
+0x8C5E	0x5B86	
+0x8C5F	0x5B8A	
+0x8C60	0x5B8D	
+0x8C61	0x5B8E	
+0x8C62	0x5B90	
+0x8C63	0x5B91	
+0x8C64	0x5B92	
+0x8C65	0x5B94	
+0x8C66	0x5B96	
+0x8C67	0x5B9F	
+0x8C68	0x5BA7	
+0x8C69	0x5BA8	
+0x8C6A	0x5BA9	
+0x8C6B	0x5BAC	
+0x8C6C	0x5BAD	
+0x8C6D	0x5BAE	
+0x8C6E	0x5BAF	
+0x8C6F	0x5BB1	
+0x8C70	0x5BB2	
+0x8C71	0x5BB7	
+0x8C72	0x5BBA	
+0x8C73	0x5BBB	
+0x8C74	0x5BBC	
+0x8C75	0x5BC0	
+0x8C76	0x5BC1	
+0x8C77	0x5BC3	
+0x8C78	0x5BC8	
+0x8C79	0x5BC9	
+0x8C7A	0x5BCA	
+0x8C7B	0x5BCB	
+0x8C7C	0x5BCD	
+0x8C7D	0x5BCE	
+0x8C7E	0x5BCF	
+0x8C80	0x5BD1	
+0x8C81	0x5BD4	
+0x8C82	0x5BD5	
+0x8C83	0x5BD6	
+0x8C84	0x5BD7	
+0x8C85	0x5BD8	
+0x8C86	0x5BD9	
+0x8C87	0x5BDA	
+0x8C88	0x5BDB	
+0x8C89	0x5BDC	
+0x8C8A	0x5BE0	
+0x8C8B	0x5BE2	
+0x8C8C	0x5BE3	
+0x8C8D	0x5BE6	
+0x8C8E	0x5BE7	
+0x8C8F	0x5BE9	
+0x8C90	0x5BEA	
+0x8C91	0x5BEB	
+0x8C92	0x5BEC	
+0x8C93	0x5BED	
+0x8C94	0x5BEF	
+0x8C95	0x5BF1	
+0x8C96	0x5BF2	
+0x8C97	0x5BF3	
+0x8C98	0x5BF4	
+0x8C99	0x5BF5	
+0x8C9A	0x5BF6	
+0x8C9B	0x5BF7	
+0x8C9C	0x5BFD	
+0x8C9D	0x5BFE	
+0x8C9E	0x5C00	
+0x8C9F	0x5C02	
+0x8CA0	0x5C03	
+0x8CA1	0x5C05	
+0x8CA2	0x5C07	
+0x8CA3	0x5C08	
+0x8CA4	0x5C0B	
+0x8CA5	0x5C0C	
+0x8CA6	0x5C0D	
+0x8CA7	0x5C0E	
+0x8CA8	0x5C10	
+0x8CA9	0x5C12	
+0x8CAA	0x5C13	
+0x8CAB	0x5C17	
+0x8CAC	0x5C19	
+0x8CAD	0x5C1B	
+0x8CAE	0x5C1E	
+0x8CAF	0x5C1F	
+0x8CB0	0x5C20	
+0x8CB1	0x5C21	
+0x8CB2	0x5C23	
+0x8CB3	0x5C26	
+0x8CB4	0x5C28	
+0x8CB5	0x5C29	
+0x8CB6	0x5C2A	
+0x8CB7	0x5C2B	
+0x8CB8	0x5C2D	
+0x8CB9	0x5C2E	
+0x8CBA	0x5C2F	
+0x8CBB	0x5C30	
+0x8CBC	0x5C32	
+0x8CBD	0x5C33	
+0x8CBE	0x5C35	
+0x8CBF	0x5C36	
+0x8CC0	0x5C37	
+0x8CC1	0x5C43	
+0x8CC2	0x5C44	
+0x8CC3	0x5C46	
+0x8CC4	0x5C47	
+0x8CC5	0x5C4C	
+0x8CC6	0x5C4D	
+0x8CC7	0x5C52	
+0x8CC8	0x5C53	
+0x8CC9	0x5C54	
+0x8CCA	0x5C56	
+0x8CCB	0x5C57	
+0x8CCC	0x5C58	
+0x8CCD	0x5C5A	
+0x8CCE	0x5C5B	
+0x8CCF	0x5C5C	
+0x8CD0	0x5C5D	
+0x8CD1	0x5C5F	
+0x8CD2	0x5C62	
+0x8CD3	0x5C64	
+0x8CD4	0x5C67	
+0x8CD5	0x5C68	
+0x8CD6	0x5C69	
+0x8CD7	0x5C6A	
+0x8CD8	0x5C6B	
+0x8CD9	0x5C6C	
+0x8CDA	0x5C6D	
+0x8CDB	0x5C70	
+0x8CDC	0x5C72	
+0x8CDD	0x5C73	
+0x8CDE	0x5C74	
+0x8CDF	0x5C75	
+0x8CE0	0x5C76	
+0x8CE1	0x5C77	
+0x8CE2	0x5C78	
+0x8CE3	0x5C7B	
+0x8CE4	0x5C7C	
+0x8CE5	0x5C7D	
+0x8CE6	0x5C7E	
+0x8CE7	0x5C80	
+0x8CE8	0x5C83	
+0x8CE9	0x5C84	
+0x8CEA	0x5C85	
+0x8CEB	0x5C86	
+0x8CEC	0x5C87	
+0x8CED	0x5C89	
+0x8CEE	0x5C8A	
+0x8CEF	0x5C8B	
+0x8CF0	0x5C8E	
+0x8CF1	0x5C8F	
+0x8CF2	0x5C92	
+0x8CF3	0x5C93	
+0x8CF4	0x5C95	
+0x8CF5	0x5C9D	
+0x8CF6	0x5C9E	
+0x8CF7	0x5C9F	
+0x8CF8	0x5CA0	
+0x8CF9	0x5CA1	
+0x8CFA	0x5CA4	
+0x8CFB	0x5CA5	
+0x8CFC	0x5CA6	
+0x8CFD	0x5CA7	
+0x8CFE	0x5CA8	
+0x8D40	0x5CAA	
+0x8D41	0x5CAE	
+0x8D42	0x5CAF	
+0x8D43	0x5CB0	
+0x8D44	0x5CB2	
+0x8D45	0x5CB4	
+0x8D46	0x5CB6	
+0x8D47	0x5CB9	
+0x8D48	0x5CBA	
+0x8D49	0x5CBB	
+0x8D4A	0x5CBC	
+0x8D4B	0x5CBE	
+0x8D4C	0x5CC0	
+0x8D4D	0x5CC2	
+0x8D4E	0x5CC3	
+0x8D4F	0x5CC5	
+0x8D50	0x5CC6	
+0x8D51	0x5CC7	
+0x8D52	0x5CC8	
+0x8D53	0x5CC9	
+0x8D54	0x5CCA	
+0x8D55	0x5CCC	
+0x8D56	0x5CCD	
+0x8D57	0x5CCE	
+0x8D58	0x5CCF	
+0x8D59	0x5CD0	
+0x8D5A	0x5CD1	
+0x8D5B	0x5CD3	
+0x8D5C	0x5CD4	
+0x8D5D	0x5CD5	
+0x8D5E	0x5CD6	
+0x8D5F	0x5CD7	
+0x8D60	0x5CD8	
+0x8D61	0x5CDA	
+0x8D62	0x5CDB	
+0x8D63	0x5CDC	
+0x8D64	0x5CDD	
+0x8D65	0x5CDE	
+0x8D66	0x5CDF	
+0x8D67	0x5CE0	
+0x8D68	0x5CE2	
+0x8D69	0x5CE3	
+0x8D6A	0x5CE7	
+0x8D6B	0x5CE9	
+0x8D6C	0x5CEB	
+0x8D6D	0x5CEC	
+0x8D6E	0x5CEE	
+0x8D6F	0x5CEF	
+0x8D70	0x5CF1	
+0x8D71	0x5CF2	
+0x8D72	0x5CF3	
+0x8D73	0x5CF4	
+0x8D74	0x5CF5	
+0x8D75	0x5CF6	
+0x8D76	0x5CF7	
+0x8D77	0x5CF8	
+0x8D78	0x5CF9	
+0x8D79	0x5CFA	
+0x8D7A	0x5CFC	
+0x8D7B	0x5CFD	
+0x8D7C	0x5CFE	
+0x8D7D	0x5CFF	
+0x8D7E	0x5D00	
+0x8D80	0x5D01	
+0x8D81	0x5D04	
+0x8D82	0x5D05	
+0x8D83	0x5D08	
+0x8D84	0x5D09	
+0x8D85	0x5D0A	
+0x8D86	0x5D0B	
+0x8D87	0x5D0C	
+0x8D88	0x5D0D	
+0x8D89	0x5D0F	
+0x8D8A	0x5D10	
+0x8D8B	0x5D11	
+0x8D8C	0x5D12	
+0x8D8D	0x5D13	
+0x8D8E	0x5D15	
+0x8D8F	0x5D17	
+0x8D90	0x5D18	
+0x8D91	0x5D19	
+0x8D92	0x5D1A	
+0x8D93	0x5D1C	
+0x8D94	0x5D1D	
+0x8D95	0x5D1F	
+0x8D96	0x5D20	
+0x8D97	0x5D21	
+0x8D98	0x5D22	
+0x8D99	0x5D23	
+0x8D9A	0x5D25	
+0x8D9B	0x5D28	
+0x8D9C	0x5D2A	
+0x8D9D	0x5D2B	
+0x8D9E	0x5D2C	
+0x8D9F	0x5D2F	
+0x8DA0	0x5D30	
+0x8DA1	0x5D31	
+0x8DA2	0x5D32	
+0x8DA3	0x5D33	
+0x8DA4	0x5D35	
+0x8DA5	0x5D36	
+0x8DA6	0x5D37	
+0x8DA7	0x5D38	
+0x8DA8	0x5D39	
+0x8DA9	0x5D3A	
+0x8DAA	0x5D3B	
+0x8DAB	0x5D3C	
+0x8DAC	0x5D3F	
+0x8DAD	0x5D40	
+0x8DAE	0x5D41	
+0x8DAF	0x5D42	
+0x8DB0	0x5D43	
+0x8DB1	0x5D44	
+0x8DB2	0x5D45	
+0x8DB3	0x5D46	
+0x8DB4	0x5D48	
+0x8DB5	0x5D49	
+0x8DB6	0x5D4D	
+0x8DB7	0x5D4E	
+0x8DB8	0x5D4F	
+0x8DB9	0x5D50	
+0x8DBA	0x5D51	
+0x8DBB	0x5D52	
+0x8DBC	0x5D53	
+0x8DBD	0x5D54	
+0x8DBE	0x5D55	
+0x8DBF	0x5D56	
+0x8DC0	0x5D57	
+0x8DC1	0x5D59	
+0x8DC2	0x5D5A	
+0x8DC3	0x5D5C	
+0x8DC4	0x5D5E	
+0x8DC5	0x5D5F	
+0x8DC6	0x5D60	
+0x8DC7	0x5D61	
+0x8DC8	0x5D62	
+0x8DC9	0x5D63	
+0x8DCA	0x5D64	
+0x8DCB	0x5D65	
+0x8DCC	0x5D66	
+0x8DCD	0x5D67	
+0x8DCE	0x5D68	
+0x8DCF	0x5D6A	
+0x8DD0	0x5D6D	
+0x8DD1	0x5D6E	
+0x8DD2	0x5D70	
+0x8DD3	0x5D71	
+0x8DD4	0x5D72	
+0x8DD5	0x5D73	
+0x8DD6	0x5D75	
+0x8DD7	0x5D76	
+0x8DD8	0x5D77	
+0x8DD9	0x5D78	
+0x8DDA	0x5D79	
+0x8DDB	0x5D7A	
+0x8DDC	0x5D7B	
+0x8DDD	0x5D7C	
+0x8DDE	0x5D7D	
+0x8DDF	0x5D7E	
+0x8DE0	0x5D7F	
+0x8DE1	0x5D80	
+0x8DE2	0x5D81	
+0x8DE3	0x5D83	
+0x8DE4	0x5D84	
+0x8DE5	0x5D85	
+0x8DE6	0x5D86	
+0x8DE7	0x5D87	
+0x8DE8	0x5D88	
+0x8DE9	0x5D89	
+0x8DEA	0x5D8A	
+0x8DEB	0x5D8B	
+0x8DEC	0x5D8C	
+0x8DED	0x5D8D	
+0x8DEE	0x5D8E	
+0x8DEF	0x5D8F	
+0x8DF0	0x5D90	
+0x8DF1	0x5D91	
+0x8DF2	0x5D92	
+0x8DF3	0x5D93	
+0x8DF4	0x5D94	
+0x8DF5	0x5D95	
+0x8DF6	0x5D96	
+0x8DF7	0x5D97	
+0x8DF8	0x5D98	
+0x8DF9	0x5D9A	
+0x8DFA	0x5D9B	
+0x8DFB	0x5D9C	
+0x8DFC	0x5D9E	
+0x8DFD	0x5D9F	
+0x8DFE	0x5DA0	
+0x8E40	0x5DA1	
+0x8E41	0x5DA2	
+0x8E42	0x5DA3	
+0x8E43	0x5DA4	
+0x8E44	0x5DA5	
+0x8E45	0x5DA6	
+0x8E46	0x5DA7	
+0x8E47	0x5DA8	
+0x8E48	0x5DA9	
+0x8E49	0x5DAA	
+0x8E4A	0x5DAB	
+0x8E4B	0x5DAC	
+0x8E4C	0x5DAD	
+0x8E4D	0x5DAE	
+0x8E4E	0x5DAF	
+0x8E4F	0x5DB0	
+0x8E50	0x5DB1	
+0x8E51	0x5DB2	
+0x8E52	0x5DB3	
+0x8E53	0x5DB4	
+0x8E54	0x5DB5	
+0x8E55	0x5DB6	
+0x8E56	0x5DB8	
+0x8E57	0x5DB9	
+0x8E58	0x5DBA	
+0x8E59	0x5DBB	
+0x8E5A	0x5DBC	
+0x8E5B	0x5DBD	
+0x8E5C	0x5DBE	
+0x8E5D	0x5DBF	
+0x8E5E	0x5DC0	
+0x8E5F	0x5DC1	
+0x8E60	0x5DC2	
+0x8E61	0x5DC3	
+0x8E62	0x5DC4	
+0x8E63	0x5DC6	
+0x8E64	0x5DC7	
+0x8E65	0x5DC8	
+0x8E66	0x5DC9	
+0x8E67	0x5DCA	
+0x8E68	0x5DCB	
+0x8E69	0x5DCC	
+0x8E6A	0x5DCE	
+0x8E6B	0x5DCF	
+0x8E6C	0x5DD0	
+0x8E6D	0x5DD1	
+0x8E6E	0x5DD2	
+0x8E6F	0x5DD3	
+0x8E70	0x5DD4	
+0x8E71	0x5DD5	
+0x8E72	0x5DD6	
+0x8E73	0x5DD7	
+0x8E74	0x5DD8	
+0x8E75	0x5DD9	
+0x8E76	0x5DDA	
+0x8E77	0x5DDC	
+0x8E78	0x5DDF	
+0x8E79	0x5DE0	
+0x8E7A	0x5DE3	
+0x8E7B	0x5DE4	
+0x8E7C	0x5DEA	
+0x8E7D	0x5DEC	
+0x8E7E	0x5DED	
+0x8E80	0x5DF0	
+0x8E81	0x5DF5	
+0x8E82	0x5DF6	
+0x8E83	0x5DF8	
+0x8E84	0x5DF9	
+0x8E85	0x5DFA	
+0x8E86	0x5DFB	
+0x8E87	0x5DFC	
+0x8E88	0x5DFF	
+0x8E89	0x5E00	
+0x8E8A	0x5E04	
+0x8E8B	0x5E07	
+0x8E8C	0x5E09	
+0x8E8D	0x5E0A	
+0x8E8E	0x5E0B	
+0x8E8F	0x5E0D	
+0x8E90	0x5E0E	
+0x8E91	0x5E12	
+0x8E92	0x5E13	
+0x8E93	0x5E17	
+0x8E94	0x5E1E	
+0x8E95	0x5E1F	
+0x8E96	0x5E20	
+0x8E97	0x5E21	
+0x8E98	0x5E22	
+0x8E99	0x5E23	
+0x8E9A	0x5E24	
+0x8E9B	0x5E25	
+0x8E9C	0x5E28	
+0x8E9D	0x5E29	
+0x8E9E	0x5E2A	
+0x8E9F	0x5E2B	
+0x8EA0	0x5E2C	
+0x8EA1	0x5E2F	
+0x8EA2	0x5E30	
+0x8EA3	0x5E32	
+0x8EA4	0x5E33	
+0x8EA5	0x5E34	
+0x8EA6	0x5E35	
+0x8EA7	0x5E36	
+0x8EA8	0x5E39	
+0x8EA9	0x5E3A	
+0x8EAA	0x5E3E	
+0x8EAB	0x5E3F	
+0x8EAC	0x5E40	
+0x8EAD	0x5E41	
+0x8EAE	0x5E43	
+0x8EAF	0x5E46	
+0x8EB0	0x5E47	
+0x8EB1	0x5E48	
+0x8EB2	0x5E49	
+0x8EB3	0x5E4A	
+0x8EB4	0x5E4B	
+0x8EB5	0x5E4D	
+0x8EB6	0x5E4E	
+0x8EB7	0x5E4F	
+0x8EB8	0x5E50	
+0x8EB9	0x5E51	
+0x8EBA	0x5E52	
+0x8EBB	0x5E53	
+0x8EBC	0x5E56	
+0x8EBD	0x5E57	
+0x8EBE	0x5E58	
+0x8EBF	0x5E59	
+0x8EC0	0x5E5A	
+0x8EC1	0x5E5C	
+0x8EC2	0x5E5D	
+0x8EC3	0x5E5F	
+0x8EC4	0x5E60	
+0x8EC5	0x5E63	
+0x8EC6	0x5E64	
+0x8EC7	0x5E65	
+0x8EC8	0x5E66	
+0x8EC9	0x5E67	
+0x8ECA	0x5E68	
+0x8ECB	0x5E69	
+0x8ECC	0x5E6A	
+0x8ECD	0x5E6B	
+0x8ECE	0x5E6C	
+0x8ECF	0x5E6D	
+0x8ED0	0x5E6E	
+0x8ED1	0x5E6F	
+0x8ED2	0x5E70	
+0x8ED3	0x5E71	
+0x8ED4	0x5E75	
+0x8ED5	0x5E77	
+0x8ED6	0x5E79	
+0x8ED7	0x5E7E	
+0x8ED8	0x5E81	
+0x8ED9	0x5E82	
+0x8EDA	0x5E83	
+0x8EDB	0x5E85	
+0x8EDC	0x5E88	
+0x8EDD	0x5E89	
+0x8EDE	0x5E8C	
+0x8EDF	0x5E8D	
+0x8EE0	0x5E8E	
+0x8EE1	0x5E92	
+0x8EE2	0x5E98	
+0x8EE3	0x5E9B	
+0x8EE4	0x5E9D	
+0x8EE5	0x5EA1	
+0x8EE6	0x5EA2	
+0x8EE7	0x5EA3	
+0x8EE8	0x5EA4	
+0x8EE9	0x5EA8	
+0x8EEA	0x5EA9	
+0x8EEB	0x5EAA	
+0x8EEC	0x5EAB	
+0x8EED	0x5EAC	
+0x8EEE	0x5EAE	
+0x8EEF	0x5EAF	
+0x8EF0	0x5EB0	
+0x8EF1	0x5EB1	
+0x8EF2	0x5EB2	
+0x8EF3	0x5EB4	
+0x8EF4	0x5EBA	
+0x8EF5	0x5EBB	
+0x8EF6	0x5EBC	
+0x8EF7	0x5EBD	
+0x8EF8	0x5EBF	
+0x8EF9	0x5EC0	
+0x8EFA	0x5EC1	
+0x8EFB	0x5EC2	
+0x8EFC	0x5EC3	
+0x8EFD	0x5EC4	
+0x8EFE	0x5EC5	
+0x8F40	0x5EC6	
+0x8F41	0x5EC7	
+0x8F42	0x5EC8	
+0x8F43	0x5ECB	
+0x8F44	0x5ECC	
+0x8F45	0x5ECD	
+0x8F46	0x5ECE	
+0x8F47	0x5ECF	
+0x8F48	0x5ED0	
+0x8F49	0x5ED4	
+0x8F4A	0x5ED5	
+0x8F4B	0x5ED7	
+0x8F4C	0x5ED8	
+0x8F4D	0x5ED9	
+0x8F4E	0x5EDA	
+0x8F4F	0x5EDC	
+0x8F50	0x5EDD	
+0x8F51	0x5EDE	
+0x8F52	0x5EDF	
+0x8F53	0x5EE0	
+0x8F54	0x5EE1	
+0x8F55	0x5EE2	
+0x8F56	0x5EE3	
+0x8F57	0x5EE4	
+0x8F58	0x5EE5	
+0x8F59	0x5EE6	
+0x8F5A	0x5EE7	
+0x8F5B	0x5EE9	
+0x8F5C	0x5EEB	
+0x8F5D	0x5EEC	
+0x8F5E	0x5EED	
+0x8F5F	0x5EEE	
+0x8F60	0x5EEF	
+0x8F61	0x5EF0	
+0x8F62	0x5EF1	
+0x8F63	0x5EF2	
+0x8F64	0x5EF3	
+0x8F65	0x5EF5	
+0x8F66	0x5EF8	
+0x8F67	0x5EF9	
+0x8F68	0x5EFB	
+0x8F69	0x5EFC	
+0x8F6A	0x5EFD	
+0x8F6B	0x5F05	
+0x8F6C	0x5F06	
+0x8F6D	0x5F07	
+0x8F6E	0x5F09	
+0x8F6F	0x5F0C	
+0x8F70	0x5F0D	
+0x8F71	0x5F0E	
+0x8F72	0x5F10	
+0x8F73	0x5F12	
+0x8F74	0x5F14	
+0x8F75	0x5F16	
+0x8F76	0x5F19	
+0x8F77	0x5F1A	
+0x8F78	0x5F1C	
+0x8F79	0x5F1D	
+0x8F7A	0x5F1E	
+0x8F7B	0x5F21	
+0x8F7C	0x5F22	
+0x8F7D	0x5F23	
+0x8F7E	0x5F24	
+0x8F80	0x5F28	
+0x8F81	0x5F2B	
+0x8F82	0x5F2C	
+0x8F83	0x5F2E	
+0x8F84	0x5F30	
+0x8F85	0x5F32	
+0x8F86	0x5F33	
+0x8F87	0x5F34	
+0x8F88	0x5F35	
+0x8F89	0x5F36	
+0x8F8A	0x5F37	
+0x8F8B	0x5F38	
+0x8F8C	0x5F3B	
+0x8F8D	0x5F3D	
+0x8F8E	0x5F3E	
+0x8F8F	0x5F3F	
+0x8F90	0x5F41	
+0x8F91	0x5F42	
+0x8F92	0x5F43	
+0x8F93	0x5F44	
+0x8F94	0x5F45	
+0x8F95	0x5F46	
+0x8F96	0x5F47	
+0x8F97	0x5F48	
+0x8F98	0x5F49	
+0x8F99	0x5F4A	
+0x8F9A	0x5F4B	
+0x8F9B	0x5F4C	
+0x8F9C	0x5F4D	
+0x8F9D	0x5F4E	
+0x8F9E	0x5F4F	
+0x8F9F	0x5F51	
+0x8FA0	0x5F54	
+0x8FA1	0x5F59	
+0x8FA2	0x5F5A	
+0x8FA3	0x5F5B	
+0x8FA4	0x5F5C	
+0x8FA5	0x5F5E	
+0x8FA6	0x5F5F	
+0x8FA7	0x5F60	
+0x8FA8	0x5F63	
+0x8FA9	0x5F65	
+0x8FAA	0x5F67	
+0x8FAB	0x5F68	
+0x8FAC	0x5F6B	
+0x8FAD	0x5F6E	
+0x8FAE	0x5F6F	
+0x8FAF	0x5F72	
+0x8FB0	0x5F74	
+0x8FB1	0x5F75	
+0x8FB2	0x5F76	
+0x8FB3	0x5F78	
+0x8FB4	0x5F7A	
+0x8FB5	0x5F7D	
+0x8FB6	0x5F7E	
+0x8FB7	0x5F7F	
+0x8FB8	0x5F83	
+0x8FB9	0x5F86	
+0x8FBA	0x5F8D	
+0x8FBB	0x5F8E	
+0x8FBC	0x5F8F	
+0x8FBD	0x5F91	
+0x8FBE	0x5F93	
+0x8FBF	0x5F94	
+0x8FC0	0x5F96	
+0x8FC1	0x5F9A	
+0x8FC2	0x5F9B	
+0x8FC3	0x5F9D	
+0x8FC4	0x5F9E	
+0x8FC5	0x5F9F	
+0x8FC6	0x5FA0	
+0x8FC7	0x5FA2	
+0x8FC8	0x5FA3	
+0x8FC9	0x5FA4	
+0x8FCA	0x5FA5	
+0x8FCB	0x5FA6	
+0x8FCC	0x5FA7	
+0x8FCD	0x5FA9	
+0x8FCE	0x5FAB	
+0x8FCF	0x5FAC	
+0x8FD0	0x5FAF	
+0x8FD1	0x5FB0	
+0x8FD2	0x5FB1	
+0x8FD3	0x5FB2	
+0x8FD4	0x5FB3	
+0x8FD5	0x5FB4	
+0x8FD6	0x5FB6	
+0x8FD7	0x5FB8	
+0x8FD8	0x5FB9	
+0x8FD9	0x5FBA	
+0x8FDA	0x5FBB	
+0x8FDB	0x5FBE	
+0x8FDC	0x5FBF	
+0x8FDD	0x5FC0	
+0x8FDE	0x5FC1	
+0x8FDF	0x5FC2	
+0x8FE0	0x5FC7	
+0x8FE1	0x5FC8	
+0x8FE2	0x5FCA	
+0x8FE3	0x5FCB	
+0x8FE4	0x5FCE	
+0x8FE5	0x5FD3	
+0x8FE6	0x5FD4	
+0x8FE7	0x5FD5	
+0x8FE8	0x5FDA	
+0x8FE9	0x5FDB	
+0x8FEA	0x5FDC	
+0x8FEB	0x5FDE	
+0x8FEC	0x5FDF	
+0x8FED	0x5FE2	
+0x8FEE	0x5FE3	
+0x8FEF	0x5FE5	
+0x8FF0	0x5FE6	
+0x8FF1	0x5FE8	
+0x8FF2	0x5FE9	
+0x8FF3	0x5FEC	
+0x8FF4	0x5FEF	
+0x8FF5	0x5FF0	
+0x8FF6	0x5FF2	
+0x8FF7	0x5FF3	
+0x8FF8	0x5FF4	
+0x8FF9	0x5FF6	
+0x8FFA	0x5FF7	
+0x8FFB	0x5FF9	
+0x8FFC	0x5FFA	
+0x8FFD	0x5FFC	
+0x8FFE	0x6007	
+0x9040	0x6008	
+0x9041	0x6009	
+0x9042	0x600B	
+0x9043	0x600C	
+0x9044	0x6010	
+0x9045	0x6011	
+0x9046	0x6013	
+0x9047	0x6017	
+0x9048	0x6018	
+0x9049	0x601A	
+0x904A	0x601E	
+0x904B	0x601F	
+0x904C	0x6022	
+0x904D	0x6023	
+0x904E	0x6024	
+0x904F	0x602C	
+0x9050	0x602D	
+0x9051	0x602E	
+0x9052	0x6030	
+0x9053	0x6031	
+0x9054	0x6032	
+0x9055	0x6033	
+0x9056	0x6034	
+0x9057	0x6036	
+0x9058	0x6037	
+0x9059	0x6038	
+0x905A	0x6039	
+0x905B	0x603A	
+0x905C	0x603D	
+0x905D	0x603E	
+0x905E	0x6040	
+0x905F	0x6044	
+0x9060	0x6045	
+0x9061	0x6046	
+0x9062	0x6047	
+0x9063	0x6048	
+0x9064	0x6049	
+0x9065	0x604A	
+0x9066	0x604C	
+0x9067	0x604E	
+0x9068	0x604F	
+0x9069	0x6051	
+0x906A	0x6053	
+0x906B	0x6054	
+0x906C	0x6056	
+0x906D	0x6057	
+0x906E	0x6058	
+0x906F	0x605B	
+0x9070	0x605C	
+0x9071	0x605E	
+0x9072	0x605F	
+0x9073	0x6060	
+0x9074	0x6061	
+0x9075	0x6065	
+0x9076	0x6066	
+0x9077	0x606E	
+0x9078	0x6071	
+0x9079	0x6072	
+0x907A	0x6074	
+0x907B	0x6075	
+0x907C	0x6077	
+0x907D	0x607E	
+0x907E	0x6080	
+0x9080	0x6081	
+0x9081	0x6082	
+0x9082	0x6085	
+0x9083	0x6086	
+0x9084	0x6087	
+0x9085	0x6088	
+0x9086	0x608A	
+0x9087	0x608B	
+0x9088	0x608E	
+0x9089	0x608F	
+0x908A	0x6090	
+0x908B	0x6091	
+0x908C	0x6093	
+0x908D	0x6095	
+0x908E	0x6097	
+0x908F	0x6098	
+0x9090	0x6099	
+0x9091	0x609C	
+0x9092	0x609E	
+0x9093	0x60A1	
+0x9094	0x60A2	
+0x9095	0x60A4	
+0x9096	0x60A5	
+0x9097	0x60A7	
+0x9098	0x60A9	
+0x9099	0x60AA	
+0x909A	0x60AE	
+0x909B	0x60B0	
+0x909C	0x60B3	
+0x909D	0x60B5	
+0x909E	0x60B6	
+0x909F	0x60B7	
+0x90A0	0x60B9	
+0x90A1	0x60BA	
+0x90A2	0x60BD	
+0x90A3	0x60BE	
+0x90A4	0x60BF	
+0x90A5	0x60C0	
+0x90A6	0x60C1	
+0x90A7	0x60C2	
+0x90A8	0x60C3	
+0x90A9	0x60C4	
+0x90AA	0x60C7	
+0x90AB	0x60C8	
+0x90AC	0x60C9	
+0x90AD	0x60CC	
+0x90AE	0x60CD	
+0x90AF	0x60CE	
+0x90B0	0x60CF	
+0x90B1	0x60D0	
+0x90B2	0x60D2	
+0x90B3	0x60D3	
+0x90B4	0x60D4	
+0x90B5	0x60D6	
+0x90B6	0x60D7	
+0x90B7	0x60D9	
+0x90B8	0x60DB	
+0x90B9	0x60DE	
+0x90BA	0x60E1	
+0x90BB	0x60E2	
+0x90BC	0x60E3	
+0x90BD	0x60E4	
+0x90BE	0x60E5	
+0x90BF	0x60EA	
+0x90C0	0x60F1	
+0x90C1	0x60F2	
+0x90C2	0x60F5	
+0x90C3	0x60F7	
+0x90C4	0x60F8	
+0x90C5	0x60FB	
+0x90C6	0x60FC	
+0x90C7	0x60FD	
+0x90C8	0x60FE	
+0x90C9	0x60FF	
+0x90CA	0x6102	
+0x90CB	0x6103	
+0x90CC	0x6104	
+0x90CD	0x6105	
+0x90CE	0x6107	
+0x90CF	0x610A	
+0x90D0	0x610B	
+0x90D1	0x610C	
+0x90D2	0x6110	
+0x90D3	0x6111	
+0x90D4	0x6112	
+0x90D5	0x6113	
+0x90D6	0x6114	
+0x90D7	0x6116	
+0x90D8	0x6117	
+0x90D9	0x6118	
+0x90DA	0x6119	
+0x90DB	0x611B	
+0x90DC	0x611C	
+0x90DD	0x611D	
+0x90DE	0x611E	
+0x90DF	0x6121	
+0x90E0	0x6122	
+0x90E1	0x6125	
+0x90E2	0x6128	
+0x90E3	0x6129	
+0x90E4	0x612A	
+0x90E5	0x612C	
+0x90E6	0x612D	
+0x90E7	0x612E	
+0x90E8	0x612F	
+0x90E9	0x6130	
+0x90EA	0x6131	
+0x90EB	0x6132	
+0x90EC	0x6133	
+0x90ED	0x6134	
+0x90EE	0x6135	
+0x90EF	0x6136	
+0x90F0	0x6137	
+0x90F1	0x6138	
+0x90F2	0x6139	
+0x90F3	0x613A	
+0x90F4	0x613B	
+0x90F5	0x613C	
+0x90F6	0x613D	
+0x90F7	0x613E	
+0x90F8	0x6140	
+0x90F9	0x6141	
+0x90FA	0x6142	
+0x90FB	0x6143	
+0x90FC	0x6144	
+0x90FD	0x6145	
+0x90FE	0x6146	
+0x9140	0x6147	
+0x9141	0x6149	
+0x9142	0x614B	
+0x9143	0x614D	
+0x9144	0x614F	
+0x9145	0x6150	
+0x9146	0x6152	
+0x9147	0x6153	
+0x9148	0x6154	
+0x9149	0x6156	
+0x914A	0x6157	
+0x914B	0x6158	
+0x914C	0x6159	
+0x914D	0x615A	
+0x914E	0x615B	
+0x914F	0x615C	
+0x9150	0x615E	
+0x9151	0x615F	
+0x9152	0x6160	
+0x9153	0x6161	
+0x9154	0x6163	
+0x9155	0x6164	
+0x9156	0x6165	
+0x9157	0x6166	
+0x9158	0x6169	
+0x9159	0x616A	
+0x915A	0x616B	
+0x915B	0x616C	
+0x915C	0x616D	
+0x915D	0x616E	
+0x915E	0x616F	
+0x915F	0x6171	
+0x9160	0x6172	
+0x9161	0x6173	
+0x9162	0x6174	
+0x9163	0x6176	
+0x9164	0x6178	
+0x9165	0x6179	
+0x9166	0x617A	
+0x9167	0x617B	
+0x9168	0x617C	
+0x9169	0x617D	
+0x916A	0x617E	
+0x916B	0x617F	
+0x916C	0x6180	
+0x916D	0x6181	
+0x916E	0x6182	
+0x916F	0x6183	
+0x9170	0x6184	
+0x9171	0x6185	
+0x9172	0x6186	
+0x9173	0x6187	
+0x9174	0x6188	
+0x9175	0x6189	
+0x9176	0x618A	
+0x9177	0x618C	
+0x9178	0x618D	
+0x9179	0x618F	
+0x917A	0x6190	
+0x917B	0x6191	
+0x917C	0x6192	
+0x917D	0x6193	
+0x917E	0x6195	
+0x9180	0x6196	
+0x9181	0x6197	
+0x9182	0x6198	
+0x9183	0x6199	
+0x9184	0x619A	
+0x9185	0x619B	
+0x9186	0x619C	
+0x9187	0x619E	
+0x9188	0x619F	
+0x9189	0x61A0	
+0x918A	0x61A1	
+0x918B	0x61A2	
+0x918C	0x61A3	
+0x918D	0x61A4	
+0x918E	0x61A5	
+0x918F	0x61A6	
+0x9190	0x61AA	
+0x9191	0x61AB	
+0x9192	0x61AD	
+0x9193	0x61AE	
+0x9194	0x61AF	
+0x9195	0x61B0	
+0x9196	0x61B1	
+0x9197	0x61B2	
+0x9198	0x61B3	
+0x9199	0x61B4	
+0x919A	0x61B5	
+0x919B	0x61B6	
+0x919C	0x61B8	
+0x919D	0x61B9	
+0x919E	0x61BA	
+0x919F	0x61BB	
+0x91A0	0x61BC	
+0x91A1	0x61BD	
+0x91A2	0x61BF	
+0x91A3	0x61C0	
+0x91A4	0x61C1	
+0x91A5	0x61C3	
+0x91A6	0x61C4	
+0x91A7	0x61C5	
+0x91A8	0x61C6	
+0x91A9	0x61C7	
+0x91AA	0x61C9	
+0x91AB	0x61CC	
+0x91AC	0x61CD	
+0x91AD	0x61CE	
+0x91AE	0x61CF	
+0x91AF	0x61D0	
+0x91B0	0x61D3	
+0x91B1	0x61D5	
+0x91B2	0x61D6	
+0x91B3	0x61D7	
+0x91B4	0x61D8	
+0x91B5	0x61D9	
+0x91B6	0x61DA	
+0x91B7	0x61DB	
+0x91B8	0x61DC	
+0x91B9	0x61DD	
+0x91BA	0x61DE	
+0x91BB	0x61DF	
+0x91BC	0x61E0	
+0x91BD	0x61E1	
+0x91BE	0x61E2	
+0x91BF	0x61E3	
+0x91C0	0x61E4	
+0x91C1	0x61E5	
+0x91C2	0x61E7	
+0x91C3	0x61E8	
+0x91C4	0x61E9	
+0x91C5	0x61EA	
+0x91C6	0x61EB	
+0x91C7	0x61EC	
+0x91C8	0x61ED	
+0x91C9	0x61EE	
+0x91CA	0x61EF	
+0x91CB	0x61F0	
+0x91CC	0x61F1	
+0x91CD	0x61F2	
+0x91CE	0x61F3	
+0x91CF	0x61F4	
+0x91D0	0x61F6	
+0x91D1	0x61F7	
+0x91D2	0x61F8	
+0x91D3	0x61F9	
+0x91D4	0x61FA	
+0x91D5	0x61FB	
+0x91D6	0x61FC	
+0x91D7	0x61FD	
+0x91D8	0x61FE	
+0x91D9	0x6200	
+0x91DA	0x6201	
+0x91DB	0x6202	
+0x91DC	0x6203	
+0x91DD	0x6204	
+0x91DE	0x6205	
+0x91DF	0x6207	
+0x91E0	0x6209	
+0x91E1	0x6213	
+0x91E2	0x6214	
+0x91E3	0x6219	
+0x91E4	0x621C	
+0x91E5	0x621D	
+0x91E6	0x621E	
+0x91E7	0x6220	
+0x91E8	0x6223	
+0x91E9	0x6226	
+0x91EA	0x6227	
+0x91EB	0x6228	
+0x91EC	0x6229	
+0x91ED	0x622B	
+0x91EE	0x622D	
+0x91EF	0x622F	
+0x91F0	0x6230	
+0x91F1	0x6231	
+0x91F2	0x6232	
+0x91F3	0x6235	
+0x91F4	0x6236	
+0x91F5	0x6238	
+0x91F6	0x6239	
+0x91F7	0x623A	
+0x91F8	0x623B	
+0x91F9	0x623C	
+0x91FA	0x6242	
+0x91FB	0x6244	
+0x91FC	0x6245	
+0x91FD	0x6246	
+0x91FE	0x624A	
+0x9240	0x624F	
+0x9241	0x6250	
+0x9242	0x6255	
+0x9243	0x6256	
+0x9244	0x6257	
+0x9245	0x6259	
+0x9246	0x625A	
+0x9247	0x625C	
+0x9248	0x625D	
+0x9249	0x625E	
+0x924A	0x625F	
+0x924B	0x6260	
+0x924C	0x6261	
+0x924D	0x6262	
+0x924E	0x6264	
+0x924F	0x6265	
+0x9250	0x6268	
+0x9251	0x6271	
+0x9252	0x6272	
+0x9253	0x6274	
+0x9254	0x6275	
+0x9255	0x6277	
+0x9256	0x6278	
+0x9257	0x627A	
+0x9258	0x627B	
+0x9259	0x627D	
+0x925A	0x6281	
+0x925B	0x6282	
+0x925C	0x6283	
+0x925D	0x6285	
+0x925E	0x6286	
+0x925F	0x6287	
+0x9260	0x6288	
+0x9261	0x628B	
+0x9262	0x628C	
+0x9263	0x628D	
+0x9264	0x628E	
+0x9265	0x628F	
+0x9266	0x6290	
+0x9267	0x6294	
+0x9268	0x6299	
+0x9269	0x629C	
+0x926A	0x629D	
+0x926B	0x629E	
+0x926C	0x62A3	
+0x926D	0x62A6	
+0x926E	0x62A7	
+0x926F	0x62A9	
+0x9270	0x62AA	
+0x9271	0x62AD	
+0x9272	0x62AE	
+0x9273	0x62AF	
+0x9274	0x62B0	
+0x9275	0x62B2	
+0x9276	0x62B3	
+0x9277	0x62B4	
+0x9278	0x62B6	
+0x9279	0x62B7	
+0x927A	0x62B8	
+0x927B	0x62BA	
+0x927C	0x62BE	
+0x927D	0x62C0	
+0x927E	0x62C1	
+0x9280	0x62C3	
+0x9281	0x62CB	
+0x9282	0x62CF	
+0x9283	0x62D1	
+0x9284	0x62D5	
+0x9285	0x62DD	
+0x9286	0x62DE	
+0x9287	0x62E0	
+0x9288	0x62E1	
+0x9289	0x62E4	
+0x928A	0x62EA	
+0x928B	0x62EB	
+0x928C	0x62F0	
+0x928D	0x62F2	
+0x928E	0x62F5	
+0x928F	0x62F8	
+0x9290	0x62F9	
+0x9291	0x62FA	
+0x9292	0x62FB	
+0x9293	0x6300	
+0x9294	0x6303	
+0x9295	0x6304	
+0x9296	0x6305	
+0x9297	0x6306	
+0x9298	0x630A	
+0x9299	0x630B	
+0x929A	0x630C	
+0x929B	0x630D	
+0x929C	0x630F	
+0x929D	0x6310	
+0x929E	0x6312	
+0x929F	0x6313	
+0x92A0	0x6314	
+0x92A1	0x6315	
+0x92A2	0x6317	
+0x92A3	0x6318	
+0x92A4	0x6319	
+0x92A5	0x631C	
+0x92A6	0x6326	
+0x92A7	0x6327	
+0x92A8	0x6329	
+0x92A9	0x632C	
+0x92AA	0x632D	
+0x92AB	0x632E	
+0x92AC	0x6330	
+0x92AD	0x6331	
+0x92AE	0x6333	
+0x92AF	0x6334	
+0x92B0	0x6335	
+0x92B1	0x6336	
+0x92B2	0x6337	
+0x92B3	0x6338	
+0x92B4	0x633B	
+0x92B5	0x633C	
+0x92B6	0x633E	
+0x92B7	0x633F	
+0x92B8	0x6340	
+0x92B9	0x6341	
+0x92BA	0x6344	
+0x92BB	0x6347	
+0x92BC	0x6348	
+0x92BD	0x634A	
+0x92BE	0x6351	
+0x92BF	0x6352	
+0x92C0	0x6353	
+0x92C1	0x6354	
+0x92C2	0x6356	
+0x92C3	0x6357	
+0x92C4	0x6358	
+0x92C5	0x6359	
+0x92C6	0x635A	
+0x92C7	0x635B	
+0x92C8	0x635C	
+0x92C9	0x635D	
+0x92CA	0x6360	
+0x92CB	0x6364	
+0x92CC	0x6365	
+0x92CD	0x6366	
+0x92CE	0x6368	
+0x92CF	0x636A	
+0x92D0	0x636B	
+0x92D1	0x636C	
+0x92D2	0x636F	
+0x92D3	0x6370	
+0x92D4	0x6372	
+0x92D5	0x6373	
+0x92D6	0x6374	
+0x92D7	0x6375	
+0x92D8	0x6378	
+0x92D9	0x6379	
+0x92DA	0x637C	
+0x92DB	0x637D	
+0x92DC	0x637E	
+0x92DD	0x637F	
+0x92DE	0x6381	
+0x92DF	0x6383	
+0x92E0	0x6384	
+0x92E1	0x6385	
+0x92E2	0x6386	
+0x92E3	0x638B	
+0x92E4	0x638D	
+0x92E5	0x6391	
+0x92E6	0x6393	
+0x92E7	0x6394	
+0x92E8	0x6395	
+0x92E9	0x6397	
+0x92EA	0x6399	
+0x92EB	0x639A	
+0x92EC	0x639B	
+0x92ED	0x639C	
+0x92EE	0x639D	
+0x92EF	0x639E	
+0x92F0	0x639F	
+0x92F1	0x63A1	
+0x92F2	0x63A4	
+0x92F3	0x63A6	
+0x92F4	0x63AB	
+0x92F5	0x63AF	
+0x92F6	0x63B1	
+0x92F7	0x63B2	
+0x92F8	0x63B5	
+0x92F9	0x63B6	
+0x92FA	0x63B9	
+0x92FB	0x63BB	
+0x92FC	0x63BD	
+0x92FD	0x63BF	
+0x92FE	0x63C0	
+0x9340	0x63C1	
+0x9341	0x63C2	
+0x9342	0x63C3	
+0x9343	0x63C5	
+0x9344	0x63C7	
+0x9345	0x63C8	
+0x9346	0x63CA	
+0x9347	0x63CB	
+0x9348	0x63CC	
+0x9349	0x63D1	
+0x934A	0x63D3	
+0x934B	0x63D4	
+0x934C	0x63D5	
+0x934D	0x63D7	
+0x934E	0x63D8	
+0x934F	0x63D9	
+0x9350	0x63DA	
+0x9351	0x63DB	
+0x9352	0x63DC	
+0x9353	0x63DD	
+0x9354	0x63DF	
+0x9355	0x63E2	
+0x9356	0x63E4	
+0x9357	0x63E5	
+0x9358	0x63E6	
+0x9359	0x63E7	
+0x935A	0x63E8	
+0x935B	0x63EB	
+0x935C	0x63EC	
+0x935D	0x63EE	
+0x935E	0x63EF	
+0x935F	0x63F0	
+0x9360	0x63F1	
+0x9361	0x63F3	
+0x9362	0x63F5	
+0x9363	0x63F7	
+0x9364	0x63F9	
+0x9365	0x63FA	
+0x9366	0x63FB	
+0x9367	0x63FC	
+0x9368	0x63FE	
+0x9369	0x6403	
+0x936A	0x6404	
+0x936B	0x6406	
+0x936C	0x6407	
+0x936D	0x6408	
+0x936E	0x6409	
+0x936F	0x640A	
+0x9370	0x640D	
+0x9371	0x640E	
+0x9372	0x6411	
+0x9373	0x6412	
+0x9374	0x6415	
+0x9375	0x6416	
+0x9376	0x6417	
+0x9377	0x6418	
+0x9378	0x6419	
+0x9379	0x641A	
+0x937A	0x641D	
+0x937B	0x641F	
+0x937C	0x6422	
+0x937D	0x6423	
+0x937E	0x6424	
+0x9380	0x6425	
+0x9381	0x6427	
+0x9382	0x6428	
+0x9383	0x6429	
+0x9384	0x642B	
+0x9385	0x642E	
+0x9386	0x642F	
+0x9387	0x6430	
+0x9388	0x6431	
+0x9389	0x6432	
+0x938A	0x6433	
+0x938B	0x6435	
+0x938C	0x6436	
+0x938D	0x6437	
+0x938E	0x6438	
+0x938F	0x6439	
+0x9390	0x643B	
+0x9391	0x643C	
+0x9392	0x643E	
+0x9393	0x6440	
+0x9394	0x6442	
+0x9395	0x6443	
+0x9396	0x6449	
+0x9397	0x644B	
+0x9398	0x644C	
+0x9399	0x644D	
+0x939A	0x644E	
+0x939B	0x644F	
+0x939C	0x6450	
+0x939D	0x6451	
+0x939E	0x6453	
+0x939F	0x6455	
+0x93A0	0x6456	
+0x93A1	0x6457	
+0x93A2	0x6459	
+0x93A3	0x645A	
+0x93A4	0x645B	
+0x93A5	0x645C	
+0x93A6	0x645D	
+0x93A7	0x645F	
+0x93A8	0x6460	
+0x93A9	0x6461	
+0x93AA	0x6462	
+0x93AB	0x6463	
+0x93AC	0x6464	
+0x93AD	0x6465	
+0x93AE	0x6466	
+0x93AF	0x6468	
+0x93B0	0x646A	
+0x93B1	0x646B	
+0x93B2	0x646C	
+0x93B3	0x646E	
+0x93B4	0x646F	
+0x93B5	0x6470	
+0x93B6	0x6471	
+0x93B7	0x6472	
+0x93B8	0x6473	
+0x93B9	0x6474	
+0x93BA	0x6475	
+0x93BB	0x6476	
+0x93BC	0x6477	
+0x93BD	0x647B	
+0x93BE	0x647C	
+0x93BF	0x647D	
+0x93C0	0x647E	
+0x93C1	0x647F	
+0x93C2	0x6480	
+0x93C3	0x6481	
+0x93C4	0x6483	
+0x93C5	0x6486	
+0x93C6	0x6488	
+0x93C7	0x6489	
+0x93C8	0x648A	
+0x93C9	0x648B	
+0x93CA	0x648C	
+0x93CB	0x648D	
+0x93CC	0x648E	
+0x93CD	0x648F	
+0x93CE	0x6490	
+0x93CF	0x6493	
+0x93D0	0x6494	
+0x93D1	0x6497	
+0x93D2	0x6498	
+0x93D3	0x649A	
+0x93D4	0x649B	
+0x93D5	0x649C	
+0x93D6	0x649D	
+0x93D7	0x649F	
+0x93D8	0x64A0	
+0x93D9	0x64A1	
+0x93DA	0x64A2	
+0x93DB	0x64A3	
+0x93DC	0x64A5	
+0x93DD	0x64A6	
+0x93DE	0x64A7	
+0x93DF	0x64A8	
+0x93E0	0x64AA	
+0x93E1	0x64AB	
+0x93E2	0x64AF	
+0x93E3	0x64B1	
+0x93E4	0x64B2	
+0x93E5	0x64B3	
+0x93E6	0x64B4	
+0x93E7	0x64B6	
+0x93E8	0x64B9	
+0x93E9	0x64BB	
+0x93EA	0x64BD	
+0x93EB	0x64BE	
+0x93EC	0x64BF	
+0x93ED	0x64C1	
+0x93EE	0x64C3	
+0x93EF	0x64C4	
+0x93F0	0x64C6	
+0x93F1	0x64C7	
+0x93F2	0x64C8	
+0x93F3	0x64C9	
+0x93F4	0x64CA	
+0x93F5	0x64CB	
+0x93F6	0x64CC	
+0x93F7	0x64CF	
+0x93F8	0x64D1	
+0x93F9	0x64D3	
+0x93FA	0x64D4	
+0x93FB	0x64D5	
+0x93FC	0x64D6	
+0x93FD	0x64D9	
+0x93FE	0x64DA	
+0x9440	0x64DB	
+0x9441	0x64DC	
+0x9442	0x64DD	
+0x9443	0x64DF	
+0x9444	0x64E0	
+0x9445	0x64E1	
+0x9446	0x64E3	
+0x9447	0x64E5	
+0x9448	0x64E7	
+0x9449	0x64E8	
+0x944A	0x64E9	
+0x944B	0x64EA	
+0x944C	0x64EB	
+0x944D	0x64EC	
+0x944E	0x64ED	
+0x944F	0x64EE	
+0x9450	0x64EF	
+0x9451	0x64F0	
+0x9452	0x64F1	
+0x9453	0x64F2	
+0x9454	0x64F3	
+0x9455	0x64F4	
+0x9456	0x64F5	
+0x9457	0x64F6	
+0x9458	0x64F7	
+0x9459	0x64F8	
+0x945A	0x64F9	
+0x945B	0x64FA	
+0x945C	0x64FB	
+0x945D	0x64FC	
+0x945E	0x64FD	
+0x945F	0x64FE	
+0x9460	0x64FF	
+0x9461	0x6501	
+0x9462	0x6502	
+0x9463	0x6503	
+0x9464	0x6504	
+0x9465	0x6505	
+0x9466	0x6506	
+0x9467	0x6507	
+0x9468	0x6508	
+0x9469	0x650A	
+0x946A	0x650B	
+0x946B	0x650C	
+0x946C	0x650D	
+0x946D	0x650E	
+0x946E	0x650F	
+0x946F	0x6510	
+0x9470	0x6511	
+0x9471	0x6513	
+0x9472	0x6514	
+0x9473	0x6515	
+0x9474	0x6516	
+0x9475	0x6517	
+0x9476	0x6519	
+0x9477	0x651A	
+0x9478	0x651B	
+0x9479	0x651C	
+0x947A	0x651D	
+0x947B	0x651E	
+0x947C	0x651F	
+0x947D	0x6520	
+0x947E	0x6521	
+0x9480	0x6522	
+0x9481	0x6523	
+0x9482	0x6524	
+0x9483	0x6526	
+0x9484	0x6527	
+0x9485	0x6528	
+0x9486	0x6529	
+0x9487	0x652A	
+0x9488	0x652C	
+0x9489	0x652D	
+0x948A	0x6530	
+0x948B	0x6531	
+0x948C	0x6532	
+0x948D	0x6533	
+0x948E	0x6537	
+0x948F	0x653A	
+0x9490	0x653C	
+0x9491	0x653D	
+0x9492	0x6540	
+0x9493	0x6541	
+0x9494	0x6542	
+0x9495	0x6543	
+0x9496	0x6544	
+0x9497	0x6546	
+0x9498	0x6547	
+0x9499	0x654A	
+0x949A	0x654B	
+0x949B	0x654D	
+0x949C	0x654E	
+0x949D	0x6550	
+0x949E	0x6552	
+0x949F	0x6553	
+0x94A0	0x6554	
+0x94A1	0x6557	
+0x94A2	0x6558	
+0x94A3	0x655A	
+0x94A4	0x655C	
+0x94A5	0x655F	
+0x94A6	0x6560	
+0x94A7	0x6561	
+0x94A8	0x6564	
+0x94A9	0x6565	
+0x94AA	0x6567	
+0x94AB	0x6568	
+0x94AC	0x6569	
+0x94AD	0x656A	
+0x94AE	0x656D	
+0x94AF	0x656E	
+0x94B0	0x656F	
+0x94B1	0x6571	
+0x94B2	0x6573	
+0x94B3	0x6575	
+0x94B4	0x6576	
+0x94B5	0x6578	
+0x94B6	0x6579	
+0x94B7	0x657A	
+0x94B8	0x657B	
+0x94B9	0x657C	
+0x94BA	0x657D	
+0x94BB	0x657E	
+0x94BC	0x657F	
+0x94BD	0x6580	
+0x94BE	0x6581	
+0x94BF	0x6582	
+0x94C0	0x6583	
+0x94C1	0x6584	
+0x94C2	0x6585	
+0x94C3	0x6586	
+0x94C4	0x6588	
+0x94C5	0x6589	
+0x94C6	0x658A	
+0x94C7	0x658D	
+0x94C8	0x658E	
+0x94C9	0x658F	
+0x94CA	0x6592	
+0x94CB	0x6594	
+0x94CC	0x6595	
+0x94CD	0x6596	
+0x94CE	0x6598	
+0x94CF	0x659A	
+0x94D0	0x659D	
+0x94D1	0x659E	
+0x94D2	0x65A0	
+0x94D3	0x65A2	
+0x94D4	0x65A3	
+0x94D5	0x65A6	
+0x94D6	0x65A8	
+0x94D7	0x65AA	
+0x94D8	0x65AC	
+0x94D9	0x65AE	
+0x94DA	0x65B1	
+0x94DB	0x65B2	
+0x94DC	0x65B3	
+0x94DD	0x65B4	
+0x94DE	0x65B5	
+0x94DF	0x65B6	
+0x94E0	0x65B7	
+0x94E1	0x65B8	
+0x94E2	0x65BA	
+0x94E3	0x65BB	
+0x94E4	0x65BE	
+0x94E5	0x65BF	
+0x94E6	0x65C0	
+0x94E7	0x65C2	
+0x94E8	0x65C7	
+0x94E9	0x65C8	
+0x94EA	0x65C9	
+0x94EB	0x65CA	
+0x94EC	0x65CD	
+0x94ED	0x65D0	
+0x94EE	0x65D1	
+0x94EF	0x65D3	
+0x94F0	0x65D4	
+0x94F1	0x65D5	
+0x94F2	0x65D8	
+0x94F3	0x65D9	
+0x94F4	0x65DA	
+0x94F5	0x65DB	
+0x94F6	0x65DC	
+0x94F7	0x65DD	
+0x94F8	0x65DE	
+0x94F9	0x65DF	
+0x94FA	0x65E1	
+0x94FB	0x65E3	
+0x94FC	0x65E4	
+0x94FD	0x65EA	
+0x94FE	0x65EB	
+0x9540	0x65F2	
+0x9541	0x65F3	
+0x9542	0x65F4	
+0x9543	0x65F5	
+0x9544	0x65F8	
+0x9545	0x65F9	
+0x9546	0x65FB	
+0x9547	0x65FC	
+0x9548	0x65FD	
+0x9549	0x65FE	
+0x954A	0x65FF	
+0x954B	0x6601	
+0x954C	0x6604	
+0x954D	0x6605	
+0x954E	0x6607	
+0x954F	0x6608	
+0x9550	0x6609	
+0x9551	0x660B	
+0x9552	0x660D	
+0x9553	0x6610	
+0x9554	0x6611	
+0x9555	0x6612	
+0x9556	0x6616	
+0x9557	0x6617	
+0x9558	0x6618	
+0x9559	0x661A	
+0x955A	0x661B	
+0x955B	0x661C	
+0x955C	0x661E	
+0x955D	0x6621	
+0x955E	0x6622	
+0x955F	0x6623	
+0x9560	0x6624	
+0x9561	0x6626	
+0x9562	0x6629	
+0x9563	0x662A	
+0x9564	0x662B	
+0x9565	0x662C	
+0x9566	0x662E	
+0x9567	0x6630	
+0x9568	0x6632	
+0x9569	0x6633	
+0x956A	0x6637	
+0x956B	0x6638	
+0x956C	0x6639	
+0x956D	0x663A	
+0x956E	0x663B	
+0x956F	0x663D	
+0x9570	0x663F	
+0x9571	0x6640	
+0x9572	0x6642	
+0x9573	0x6644	
+0x9574	0x6645	
+0x9575	0x6646	
+0x9576	0x6647	
+0x9577	0x6648	
+0x9578	0x6649	
+0x9579	0x664A	
+0x957A	0x664D	
+0x957B	0x664E	
+0x957C	0x6650	
+0x957D	0x6651	
+0x957E	0x6658	
+0x9580	0x6659	
+0x9581	0x665B	
+0x9582	0x665C	
+0x9583	0x665D	
+0x9584	0x665E	
+0x9585	0x6660	
+0x9586	0x6662	
+0x9587	0x6663	
+0x9588	0x6665	
+0x9589	0x6667	
+0x958A	0x6669	
+0x958B	0x666A	
+0x958C	0x666B	
+0x958D	0x666C	
+0x958E	0x666D	
+0x958F	0x6671	
+0x9590	0x6672	
+0x9591	0x6673	
+0x9592	0x6675	
+0x9593	0x6678	
+0x9594	0x6679	
+0x9595	0x667B	
+0x9596	0x667C	
+0x9597	0x667D	
+0x9598	0x667F	
+0x9599	0x6680	
+0x959A	0x6681	
+0x959B	0x6683	
+0x959C	0x6685	
+0x959D	0x6686	
+0x959E	0x6688	
+0x959F	0x6689	
+0x95A0	0x668A	
+0x95A1	0x668B	
+0x95A2	0x668D	
+0x95A3	0x668E	
+0x95A4	0x668F	
+0x95A5	0x6690	
+0x95A6	0x6692	
+0x95A7	0x6693	
+0x95A8	0x6694	
+0x95A9	0x6695	
+0x95AA	0x6698	
+0x95AB	0x6699	
+0x95AC	0x669A	
+0x95AD	0x669B	
+0x95AE	0x669C	
+0x95AF	0x669E	
+0x95B0	0x669F	
+0x95B1	0x66A0	
+0x95B2	0x66A1	
+0x95B3	0x66A2	
+0x95B4	0x66A3	
+0x95B5	0x66A4	
+0x95B6	0x66A5	
+0x95B7	0x66A6	
+0x95B8	0x66A9	
+0x95B9	0x66AA	
+0x95BA	0x66AB	
+0x95BB	0x66AC	
+0x95BC	0x66AD	
+0x95BD	0x66AF	
+0x95BE	0x66B0	
+0x95BF	0x66B1	
+0x95C0	0x66B2	
+0x95C1	0x66B3	
+0x95C2	0x66B5	
+0x95C3	0x66B6	
+0x95C4	0x66B7	
+0x95C5	0x66B8	
+0x95C6	0x66BA	
+0x95C7	0x66BB	
+0x95C8	0x66BC	
+0x95C9	0x66BD	
+0x95CA	0x66BF	
+0x95CB	0x66C0	
+0x95CC	0x66C1	
+0x95CD	0x66C2	
+0x95CE	0x66C3	
+0x95CF	0x66C4	
+0x95D0	0x66C5	
+0x95D1	0x66C6	
+0x95D2	0x66C7	
+0x95D3	0x66C8	
+0x95D4	0x66C9	
+0x95D5	0x66CA	
+0x95D6	0x66CB	
+0x95D7	0x66CC	
+0x95D8	0x66CD	
+0x95D9	0x66CE	
+0x95DA	0x66CF	
+0x95DB	0x66D0	
+0x95DC	0x66D1	
+0x95DD	0x66D2	
+0x95DE	0x66D3	
+0x95DF	0x66D4	
+0x95E0	0x66D5	
+0x95E1	0x66D6	
+0x95E2	0x66D7	
+0x95E3	0x66D8	
+0x95E4	0x66DA	
+0x95E5	0x66DE	
+0x95E6	0x66DF	
+0x95E7	0x66E0	
+0x95E8	0x66E1	
+0x95E9	0x66E2	
+0x95EA	0x66E3	
+0x95EB	0x66E4	
+0x95EC	0x66E5	
+0x95ED	0x66E7	
+0x95EE	0x66E8	
+0x95EF	0x66EA	
+0x95F0	0x66EB	
+0x95F1	0x66EC	
+0x95F2	0x66ED	
+0x95F3	0x66EE	
+0x95F4	0x66EF	
+0x95F5	0x66F1	
+0x95F6	0x66F5	
+0x95F7	0x66F6	
+0x95F8	0x66F8	
+0x95F9	0x66FA	
+0x95FA	0x66FB	
+0x95FB	0x66FD	
+0x95FC	0x6701	
+0x95FD	0x6702	
+0x95FE	0x6703	
+0x9640	0x6704	
+0x9641	0x6705	
+0x9642	0x6706	
+0x9643	0x6707	
+0x9644	0x670C	
+0x9645	0x670E	
+0x9646	0x670F	
+0x9647	0x6711	
+0x9648	0x6712	
+0x9649	0x6713	
+0x964A	0x6716	
+0x964B	0x6718	
+0x964C	0x6719	
+0x964D	0x671A	
+0x964E	0x671C	
+0x964F	0x671E	
+0x9650	0x6720	
+0x9651	0x6721	
+0x9652	0x6722	
+0x9653	0x6723	
+0x9654	0x6724	
+0x9655	0x6725	
+0x9656	0x6727	
+0x9657	0x6729	
+0x9658	0x672E	
+0x9659	0x6730	
+0x965A	0x6732	
+0x965B	0x6733	
+0x965C	0x6736	
+0x965D	0x6737	
+0x965E	0x6738	
+0x965F	0x6739	
+0x9660	0x673B	
+0x9661	0x673C	
+0x9662	0x673E	
+0x9663	0x673F	
+0x9664	0x6741	
+0x9665	0x6744	
+0x9666	0x6745	
+0x9667	0x6747	
+0x9668	0x674A	
+0x9669	0x674B	
+0x966A	0x674D	
+0x966B	0x6752	
+0x966C	0x6754	
+0x966D	0x6755	
+0x966E	0x6757	
+0x966F	0x6758	
+0x9670	0x6759	
+0x9671	0x675A	
+0x9672	0x675B	
+0x9673	0x675D	
+0x9674	0x6762	
+0x9675	0x6763	
+0x9676	0x6764	
+0x9677	0x6766	
+0x9678	0x6767	
+0x9679	0x676B	
+0x967A	0x676C	
+0x967B	0x676E	
+0x967C	0x6771	
+0x967D	0x6774	
+0x967E	0x6776	
+0x9680	0x6778	
+0x9681	0x6779	
+0x9682	0x677A	
+0x9683	0x677B	
+0x9684	0x677D	
+0x9685	0x6780	
+0x9686	0x6782	
+0x9687	0x6783	
+0x9688	0x6785	
+0x9689	0x6786	
+0x968A	0x6788	
+0x968B	0x678A	
+0x968C	0x678C	
+0x968D	0x678D	
+0x968E	0x678E	
+0x968F	0x678F	
+0x9690	0x6791	
+0x9691	0x6792	
+0x9692	0x6793	
+0x9693	0x6794	
+0x9694	0x6796	
+0x9695	0x6799	
+0x9696	0x679B	
+0x9697	0x679F	
+0x9698	0x67A0	
+0x9699	0x67A1	
+0x969A	0x67A4	
+0x969B	0x67A6	
+0x969C	0x67A9	
+0x969D	0x67AC	
+0x969E	0x67AE	
+0x969F	0x67B1	
+0x96A0	0x67B2	
+0x96A1	0x67B4	
+0x96A2	0x67B9	
+0x96A3	0x67BA	
+0x96A4	0x67BB	
+0x96A5	0x67BC	
+0x96A6	0x67BD	
+0x96A7	0x67BE	
+0x96A8	0x67BF	
+0x96A9	0x67C0	
+0x96AA	0x67C2	
+0x96AB	0x67C5	
+0x96AC	0x67C6	
+0x96AD	0x67C7	
+0x96AE	0x67C8	
+0x96AF	0x67C9	
+0x96B0	0x67CA	
+0x96B1	0x67CB	
+0x96B2	0x67CC	
+0x96B3	0x67CD	
+0x96B4	0x67CE	
+0x96B5	0x67D5	
+0x96B6	0x67D6	
+0x96B7	0x67D7	
+0x96B8	0x67DB	
+0x96B9	0x67DF	
+0x96BA	0x67E1	
+0x96BB	0x67E3	
+0x96BC	0x67E4	
+0x96BD	0x67E6	
+0x96BE	0x67E7	
+0x96BF	0x67E8	
+0x96C0	0x67EA	
+0x96C1	0x67EB	
+0x96C2	0x67ED	
+0x96C3	0x67EE	
+0x96C4	0x67F2	
+0x96C5	0x67F5	
+0x96C6	0x67F6	
+0x96C7	0x67F7	
+0x96C8	0x67F8	
+0x96C9	0x67F9	
+0x96CA	0x67FA	
+0x96CB	0x67FB	
+0x96CC	0x67FC	
+0x96CD	0x67FE	
+0x96CE	0x6801	
+0x96CF	0x6802	
+0x96D0	0x6803	
+0x96D1	0x6804	
+0x96D2	0x6806	
+0x96D3	0x680D	
+0x96D4	0x6810	
+0x96D5	0x6812	
+0x96D6	0x6814	
+0x96D7	0x6815	
+0x96D8	0x6818	
+0x96D9	0x6819	
+0x96DA	0x681A	
+0x96DB	0x681B	
+0x96DC	0x681C	
+0x96DD	0x681E	
+0x96DE	0x681F	
+0x96DF	0x6820	
+0x96E0	0x6822	
+0x96E1	0x6823	
+0x96E2	0x6824	
+0x96E3	0x6825	
+0x96E4	0x6826	
+0x96E5	0x6827	
+0x96E6	0x6828	
+0x96E7	0x682B	
+0x96E8	0x682C	
+0x96E9	0x682D	
+0x96EA	0x682E	
+0x96EB	0x682F	
+0x96EC	0x6830	
+0x96ED	0x6831	
+0x96EE	0x6834	
+0x96EF	0x6835	
+0x96F0	0x6836	
+0x96F1	0x683A	
+0x96F2	0x683B	
+0x96F3	0x683F	
+0x96F4	0x6847	
+0x96F5	0x684B	
+0x96F6	0x684D	
+0x96F7	0x684F	
+0x96F8	0x6852	
+0x96F9	0x6856	
+0x96FA	0x6857	
+0x96FB	0x6858	
+0x96FC	0x6859	
+0x96FD	0x685A	
+0x96FE	0x685B	
+0x9740	0x685C	
+0x9741	0x685D	
+0x9742	0x685E	
+0x9743	0x685F	
+0x9744	0x686A	
+0x9745	0x686C	
+0x9746	0x686D	
+0x9747	0x686E	
+0x9748	0x686F	
+0x9749	0x6870	
+0x974A	0x6871	
+0x974B	0x6872	
+0x974C	0x6873	
+0x974D	0x6875	
+0x974E	0x6878	
+0x974F	0x6879	
+0x9750	0x687A	
+0x9751	0x687B	
+0x9752	0x687C	
+0x9753	0x687D	
+0x9754	0x687E	
+0x9755	0x687F	
+0x9756	0x6880	
+0x9757	0x6882	
+0x9758	0x6884	
+0x9759	0x6887	
+0x975A	0x6888	
+0x975B	0x6889	
+0x975C	0x688A	
+0x975D	0x688B	
+0x975E	0x688C	
+0x975F	0x688D	
+0x9760	0x688E	
+0x9761	0x6890	
+0x9762	0x6891	
+0x9763	0x6892	
+0x9764	0x6894	
+0x9765	0x6895	
+0x9766	0x6896	
+0x9767	0x6898	
+0x9768	0x6899	
+0x9769	0x689A	
+0x976A	0x689B	
+0x976B	0x689C	
+0x976C	0x689D	
+0x976D	0x689E	
+0x976E	0x689F	
+0x976F	0x68A0	
+0x9770	0x68A1	
+0x9771	0x68A3	
+0x9772	0x68A4	
+0x9773	0x68A5	
+0x9774	0x68A9	
+0x9775	0x68AA	
+0x9776	0x68AB	
+0x9777	0x68AC	
+0x9778	0x68AE	
+0x9779	0x68B1	
+0x977A	0x68B2	
+0x977B	0x68B4	
+0x977C	0x68B6	
+0x977D	0x68B7	
+0x977E	0x68B8	
+0x9780	0x68B9	
+0x9781	0x68BA	
+0x9782	0x68BB	
+0x9783	0x68BC	
+0x9784	0x68BD	
+0x9785	0x68BE	
+0x9786	0x68BF	
+0x9787	0x68C1	
+0x9788	0x68C3	
+0x9789	0x68C4	
+0x978A	0x68C5	
+0x978B	0x68C6	
+0x978C	0x68C7	
+0x978D	0x68C8	
+0x978E	0x68CA	
+0x978F	0x68CC	
+0x9790	0x68CE	
+0x9791	0x68CF	
+0x9792	0x68D0	
+0x9793	0x68D1	
+0x9794	0x68D3	
+0x9795	0x68D4	
+0x9796	0x68D6	
+0x9797	0x68D7	
+0x9798	0x68D9	
+0x9799	0x68DB	
+0x979A	0x68DC	
+0x979B	0x68DD	
+0x979C	0x68DE	
+0x979D	0x68DF	
+0x979E	0x68E1	
+0x979F	0x68E2	
+0x97A0	0x68E4	
+0x97A1	0x68E5	
+0x97A2	0x68E6	
+0x97A3	0x68E7	
+0x97A4	0x68E8	
+0x97A5	0x68E9	
+0x97A6	0x68EA	
+0x97A7	0x68EB	
+0x97A8	0x68EC	
+0x97A9	0x68ED	
+0x97AA	0x68EF	
+0x97AB	0x68F2	
+0x97AC	0x68F3	
+0x97AD	0x68F4	
+0x97AE	0x68F6	
+0x97AF	0x68F7	
+0x97B0	0x68F8	
+0x97B1	0x68FB	
+0x97B2	0x68FD	
+0x97B3	0x68FE	
+0x97B4	0x68FF	
+0x97B5	0x6900	
+0x97B6	0x6902	
+0x97B7	0x6903	
+0x97B8	0x6904	
+0x97B9	0x6906	
+0x97BA	0x6907	
+0x97BB	0x6908	
+0x97BC	0x6909	
+0x97BD	0x690A	
+0x97BE	0x690C	
+0x97BF	0x690F	
+0x97C0	0x6911	
+0x97C1	0x6913	
+0x97C2	0x6914	
+0x97C3	0x6915	
+0x97C4	0x6916	
+0x97C5	0x6917	
+0x97C6	0x6918	
+0x97C7	0x6919	
+0x97C8	0x691A	
+0x97C9	0x691B	
+0x97CA	0x691C	
+0x97CB	0x691D	
+0x97CC	0x691E	
+0x97CD	0x6921	
+0x97CE	0x6922	
+0x97CF	0x6923	
+0x97D0	0x6925	
+0x97D1	0x6926	
+0x97D2	0x6927	
+0x97D3	0x6928	
+0x97D4	0x6929	
+0x97D5	0x692A	
+0x97D6	0x692B	
+0x97D7	0x692C	
+0x97D8	0x692E	
+0x97D9	0x692F	
+0x97DA	0x6931	
+0x97DB	0x6932	
+0x97DC	0x6933	
+0x97DD	0x6935	
+0x97DE	0x6936	
+0x97DF	0x6937	
+0x97E0	0x6938	
+0x97E1	0x693A	
+0x97E2	0x693B	
+0x97E3	0x693C	
+0x97E4	0x693E	
+0x97E5	0x6940	
+0x97E6	0x6941	
+0x97E7	0x6943	
+0x97E8	0x6944	
+0x97E9	0x6945	
+0x97EA	0x6946	
+0x97EB	0x6947	
+0x97EC	0x6948	
+0x97ED	0x6949	
+0x97EE	0x694A	
+0x97EF	0x694B	
+0x97F0	0x694C	
+0x97F1	0x694D	
+0x97F2	0x694E	
+0x97F3	0x694F	
+0x97F4	0x6950	
+0x97F5	0x6951	
+0x97F6	0x6952	
+0x97F7	0x6953	
+0x97F8	0x6955	
+0x97F9	0x6956	
+0x97FA	0x6958	
+0x97FB	0x6959	
+0x97FC	0x695B	
+0x97FD	0x695C	
+0x97FE	0x695F	
+0x9840	0x6961	
+0x9841	0x6962	
+0x9842	0x6964	
+0x9843	0x6965	
+0x9844	0x6967	
+0x9845	0x6968	
+0x9846	0x6969	
+0x9847	0x696A	
+0x9848	0x696C	
+0x9849	0x696D	
+0x984A	0x696F	
+0x984B	0x6970	
+0x984C	0x6972	
+0x984D	0x6973	
+0x984E	0x6974	
+0x984F	0x6975	
+0x9850	0x6976	
+0x9851	0x697A	
+0x9852	0x697B	
+0x9853	0x697D	
+0x9854	0x697E	
+0x9855	0x697F	
+0x9856	0x6981	
+0x9857	0x6983	
+0x9858	0x6985	
+0x9859	0x698A	
+0x985A	0x698B	
+0x985B	0x698C	
+0x985C	0x698E	
+0x985D	0x698F	
+0x985E	0x6990	
+0x985F	0x6991	
+0x9860	0x6992	
+0x9861	0x6993	
+0x9862	0x6996	
+0x9863	0x6997	
+0x9864	0x6999	
+0x9865	0x699A	
+0x9866	0x699D	
+0x9867	0x699E	
+0x9868	0x699F	
+0x9869	0x69A0	
+0x986A	0x69A1	
+0x986B	0x69A2	
+0x986C	0x69A3	
+0x986D	0x69A4	
+0x986E	0x69A5	
+0x986F	0x69A6	
+0x9870	0x69A9	
+0x9871	0x69AA	
+0x9872	0x69AC	
+0x9873	0x69AE	
+0x9874	0x69AF	
+0x9875	0x69B0	
+0x9876	0x69B2	
+0x9877	0x69B3	
+0x9878	0x69B5	
+0x9879	0x69B6	
+0x987A	0x69B8	
+0x987B	0x69B9	
+0x987C	0x69BA	
+0x987D	0x69BC	
+0x987E	0x69BD	
+0x9880	0x69BE	
+0x9881	0x69BF	
+0x9882	0x69C0	
+0x9883	0x69C2	
+0x9884	0x69C3	
+0x9885	0x69C4	
+0x9886	0x69C5	
+0x9887	0x69C6	
+0x9888	0x69C7	
+0x9889	0x69C8	
+0x988A	0x69C9	
+0x988B	0x69CB	
+0x988C	0x69CD	
+0x988D	0x69CF	
+0x988E	0x69D1	
+0x988F	0x69D2	
+0x9890	0x69D3	
+0x9891	0x69D5	
+0x9892	0x69D6	
+0x9893	0x69D7	
+0x9894	0x69D8	
+0x9895	0x69D9	
+0x9896	0x69DA	
+0x9897	0x69DC	
+0x9898	0x69DD	
+0x9899	0x69DE	
+0x989A	0x69E1	
+0x989B	0x69E2	
+0x989C	0x69E3	
+0x989D	0x69E4	
+0x989E	0x69E5	
+0x989F	0x69E6	
+0x98A0	0x69E7	
+0x98A1	0x69E8	
+0x98A2	0x69E9	
+0x98A3	0x69EA	
+0x98A4	0x69EB	
+0x98A5	0x69EC	
+0x98A6	0x69EE	
+0x98A7	0x69EF	
+0x98A8	0x69F0	
+0x98A9	0x69F1	
+0x98AA	0x69F3	
+0x98AB	0x69F4	
+0x98AC	0x69F5	
+0x98AD	0x69F6	
+0x98AE	0x69F7	
+0x98AF	0x69F8	
+0x98B0	0x69F9	
+0x98B1	0x69FA	
+0x98B2	0x69FB	
+0x98B3	0x69FC	
+0x98B4	0x69FE	
+0x98B5	0x6A00	
+0x98B6	0x6A01	
+0x98B7	0x6A02	
+0x98B8	0x6A03	
+0x98B9	0x6A04	
+0x98BA	0x6A05	
+0x98BB	0x6A06	
+0x98BC	0x6A07	
+0x98BD	0x6A08	
+0x98BE	0x6A09	
+0x98BF	0x6A0B	
+0x98C0	0x6A0C	
+0x98C1	0x6A0D	
+0x98C2	0x6A0E	
+0x98C3	0x6A0F	
+0x98C4	0x6A10	
+0x98C5	0x6A11	
+0x98C6	0x6A12	
+0x98C7	0x6A13	
+0x98C8	0x6A14	
+0x98C9	0x6A15	
+0x98CA	0x6A16	
+0x98CB	0x6A19	
+0x98CC	0x6A1A	
+0x98CD	0x6A1B	
+0x98CE	0x6A1C	
+0x98CF	0x6A1D	
+0x98D0	0x6A1E	
+0x98D1	0x6A20	
+0x98D2	0x6A22	
+0x98D3	0x6A23	
+0x98D4	0x6A24	
+0x98D5	0x6A25	
+0x98D6	0x6A26	
+0x98D7	0x6A27	
+0x98D8	0x6A29	
+0x98D9	0x6A2B	
+0x98DA	0x6A2C	
+0x98DB	0x6A2D	
+0x98DC	0x6A2E	
+0x98DD	0x6A30	
+0x98DE	0x6A32	
+0x98DF	0x6A33	
+0x98E0	0x6A34	
+0x98E1	0x6A36	
+0x98E2	0x6A37	
+0x98E3	0x6A38	
+0x98E4	0x6A39	
+0x98E5	0x6A3A	
+0x98E6	0x6A3B	
+0x98E7	0x6A3C	
+0x98E8	0x6A3F	
+0x98E9	0x6A40	
+0x98EA	0x6A41	
+0x98EB	0x6A42	
+0x98EC	0x6A43	
+0x98ED	0x6A45	
+0x98EE	0x6A46	
+0x98EF	0x6A48	
+0x98F0	0x6A49	
+0x98F1	0x6A4A	
+0x98F2	0x6A4B	
+0x98F3	0x6A4C	
+0x98F4	0x6A4D	
+0x98F5	0x6A4E	
+0x98F6	0x6A4F	
+0x98F7	0x6A51	
+0x98F8	0x6A52	
+0x98F9	0x6A53	
+0x98FA	0x6A54	
+0x98FB	0x6A55	
+0x98FC	0x6A56	
+0x98FD	0x6A57	
+0x98FE	0x6A5A	
+0x9940	0x6A5C	
+0x9941	0x6A5D	
+0x9942	0x6A5E	
+0x9943	0x6A5F	
+0x9944	0x6A60	
+0x9945	0x6A62	
+0x9946	0x6A63	
+0x9947	0x6A64	
+0x9948	0x6A66	
+0x9949	0x6A67	
+0x994A	0x6A68	
+0x994B	0x6A69	
+0x994C	0x6A6A	
+0x994D	0x6A6B	
+0x994E	0x6A6C	
+0x994F	0x6A6D	
+0x9950	0x6A6E	
+0x9951	0x6A6F	
+0x9952	0x6A70	
+0x9953	0x6A72	
+0x9954	0x6A73	
+0x9955	0x6A74	
+0x9956	0x6A75	
+0x9957	0x6A76	
+0x9958	0x6A77	
+0x9959	0x6A78	
+0x995A	0x6A7A	
+0x995B	0x6A7B	
+0x995C	0x6A7D	
+0x995D	0x6A7E	
+0x995E	0x6A7F	
+0x995F	0x6A81	
+0x9960	0x6A82	
+0x9961	0x6A83	
+0x9962	0x6A85	
+0x9963	0x6A86	
+0x9964	0x6A87	
+0x9965	0x6A88	
+0x9966	0x6A89	
+0x9967	0x6A8A	
+0x9968	0x6A8B	
+0x9969	0x6A8C	
+0x996A	0x6A8D	
+0x996B	0x6A8F	
+0x996C	0x6A92	
+0x996D	0x6A93	
+0x996E	0x6A94	
+0x996F	0x6A95	
+0x9970	0x6A96	
+0x9971	0x6A98	
+0x9972	0x6A99	
+0x9973	0x6A9A	
+0x9974	0x6A9B	
+0x9975	0x6A9C	
+0x9976	0x6A9D	
+0x9977	0x6A9E	
+0x9978	0x6A9F	
+0x9979	0x6AA1	
+0x997A	0x6AA2	
+0x997B	0x6AA3	
+0x997C	0x6AA4	
+0x997D	0x6AA5	
+0x997E	0x6AA6	
+0x9980	0x6AA7	
+0x9981	0x6AA8	
+0x9982	0x6AAA	
+0x9983	0x6AAD	
+0x9984	0x6AAE	
+0x9985	0x6AAF	
+0x9986	0x6AB0	
+0x9987	0x6AB1	
+0x9988	0x6AB2	
+0x9989	0x6AB3	
+0x998A	0x6AB4	
+0x998B	0x6AB5	
+0x998C	0x6AB6	
+0x998D	0x6AB7	
+0x998E	0x6AB8	
+0x998F	0x6AB9	
+0x9990	0x6ABA	
+0x9991	0x6ABB	
+0x9992	0x6ABC	
+0x9993	0x6ABD	
+0x9994	0x6ABE	
+0x9995	0x6ABF	
+0x9996	0x6AC0	
+0x9997	0x6AC1	
+0x9998	0x6AC2	
+0x9999	0x6AC3	
+0x999A	0x6AC4	
+0x999B	0x6AC5	
+0x999C	0x6AC6	
+0x999D	0x6AC7	
+0x999E	0x6AC8	
+0x999F	0x6AC9	
+0x99A0	0x6ACA	
+0x99A1	0x6ACB	
+0x99A2	0x6ACC	
+0x99A3	0x6ACD	
+0x99A4	0x6ACE	
+0x99A5	0x6ACF	
+0x99A6	0x6AD0	
+0x99A7	0x6AD1	
+0x99A8	0x6AD2	
+0x99A9	0x6AD3	
+0x99AA	0x6AD4	
+0x99AB	0x6AD5	
+0x99AC	0x6AD6	
+0x99AD	0x6AD7	
+0x99AE	0x6AD8	
+0x99AF	0x6AD9	
+0x99B0	0x6ADA	
+0x99B1	0x6ADB	
+0x99B2	0x6ADC	
+0x99B3	0x6ADD	
+0x99B4	0x6ADE	
+0x99B5	0x6ADF	
+0x99B6	0x6AE0	
+0x99B7	0x6AE1	
+0x99B8	0x6AE2	
+0x99B9	0x6AE3	
+0x99BA	0x6AE4	
+0x99BB	0x6AE5	
+0x99BC	0x6AE6	
+0x99BD	0x6AE7	
+0x99BE	0x6AE8	
+0x99BF	0x6AE9	
+0x99C0	0x6AEA	
+0x99C1	0x6AEB	
+0x99C2	0x6AEC	
+0x99C3	0x6AED	
+0x99C4	0x6AEE	
+0x99C5	0x6AEF	
+0x99C6	0x6AF0	
+0x99C7	0x6AF1	
+0x99C8	0x6AF2	
+0x99C9	0x6AF3	
+0x99CA	0x6AF4	
+0x99CB	0x6AF5	
+0x99CC	0x6AF6	
+0x99CD	0x6AF7	
+0x99CE	0x6AF8	
+0x99CF	0x6AF9	
+0x99D0	0x6AFA	
+0x99D1	0x6AFB	
+0x99D2	0x6AFC	
+0x99D3	0x6AFD	
+0x99D4	0x6AFE	
+0x99D5	0x6AFF	
+0x99D6	0x6B00	
+0x99D7	0x6B01	
+0x99D8	0x6B02	
+0x99D9	0x6B03	
+0x99DA	0x6B04	
+0x99DB	0x6B05	
+0x99DC	0x6B06	
+0x99DD	0x6B07	
+0x99DE	0x6B08	
+0x99DF	0x6B09	
+0x99E0	0x6B0A	
+0x99E1	0x6B0B	
+0x99E2	0x6B0C	
+0x99E3	0x6B0D	
+0x99E4	0x6B0E	
+0x99E5	0x6B0F	
+0x99E6	0x6B10	
+0x99E7	0x6B11	
+0x99E8	0x6B12	
+0x99E9	0x6B13	
+0x99EA	0x6B14	
+0x99EB	0x6B15	
+0x99EC	0x6B16	
+0x99ED	0x6B17	
+0x99EE	0x6B18	
+0x99EF	0x6B19	
+0x99F0	0x6B1A	
+0x99F1	0x6B1B	
+0x99F2	0x6B1C	
+0x99F3	0x6B1D	
+0x99F4	0x6B1E	
+0x99F5	0x6B1F	
+0x99F6	0x6B25	
+0x99F7	0x6B26	
+0x99F8	0x6B28	
+0x99F9	0x6B29	
+0x99FA	0x6B2A	
+0x99FB	0x6B2B	
+0x99FC	0x6B2C	
+0x99FD	0x6B2D	
+0x99FE	0x6B2E	
+0x9A40	0x6B2F	
+0x9A41	0x6B30	
+0x9A42	0x6B31	
+0x9A43	0x6B33	
+0x9A44	0x6B34	
+0x9A45	0x6B35	
+0x9A46	0x6B36	
+0x9A47	0x6B38	
+0x9A48	0x6B3B	
+0x9A49	0x6B3C	
+0x9A4A	0x6B3D	
+0x9A4B	0x6B3F	
+0x9A4C	0x6B40	
+0x9A4D	0x6B41	
+0x9A4E	0x6B42	
+0x9A4F	0x6B44	
+0x9A50	0x6B45	
+0x9A51	0x6B48	
+0x9A52	0x6B4A	
+0x9A53	0x6B4B	
+0x9A54	0x6B4D	
+0x9A55	0x6B4E	
+0x9A56	0x6B4F	
+0x9A57	0x6B50	
+0x9A58	0x6B51	
+0x9A59	0x6B52	
+0x9A5A	0x6B53	
+0x9A5B	0x6B54	
+0x9A5C	0x6B55	
+0x9A5D	0x6B56	
+0x9A5E	0x6B57	
+0x9A5F	0x6B58	
+0x9A60	0x6B5A	
+0x9A61	0x6B5B	
+0x9A62	0x6B5C	
+0x9A63	0x6B5D	
+0x9A64	0x6B5E	
+0x9A65	0x6B5F	
+0x9A66	0x6B60	
+0x9A67	0x6B61	
+0x9A68	0x6B68	
+0x9A69	0x6B69	
+0x9A6A	0x6B6B	
+0x9A6B	0x6B6C	
+0x9A6C	0x6B6D	
+0x9A6D	0x6B6E	
+0x9A6E	0x6B6F	
+0x9A6F	0x6B70	
+0x9A70	0x6B71	
+0x9A71	0x6B72	
+0x9A72	0x6B73	
+0x9A73	0x6B74	
+0x9A74	0x6B75	
+0x9A75	0x6B76	
+0x9A76	0x6B77	
+0x9A77	0x6B78	
+0x9A78	0x6B7A	
+0x9A79	0x6B7D	
+0x9A7A	0x6B7E	
+0x9A7B	0x6B7F	
+0x9A7C	0x6B80	
+0x9A7D	0x6B85	
+0x9A7E	0x6B88	
+0x9A80	0x6B8C	
+0x9A81	0x6B8E	
+0x9A82	0x6B8F	
+0x9A83	0x6B90	
+0x9A84	0x6B91	
+0x9A85	0x6B94	
+0x9A86	0x6B95	
+0x9A87	0x6B97	
+0x9A88	0x6B98	
+0x9A89	0x6B99	
+0x9A8A	0x6B9C	
+0x9A8B	0x6B9D	
+0x9A8C	0x6B9E	
+0x9A8D	0x6B9F	
+0x9A8E	0x6BA0	
+0x9A8F	0x6BA2	
+0x9A90	0x6BA3	
+0x9A91	0x6BA4	
+0x9A92	0x6BA5	
+0x9A93	0x6BA6	
+0x9A94	0x6BA7	
+0x9A95	0x6BA8	
+0x9A96	0x6BA9	
+0x9A97	0x6BAB	
+0x9A98	0x6BAC	
+0x9A99	0x6BAD	
+0x9A9A	0x6BAE	
+0x9A9B	0x6BAF	
+0x9A9C	0x6BB0	
+0x9A9D	0x6BB1	
+0x9A9E	0x6BB2	
+0x9A9F	0x6BB6	
+0x9AA0	0x6BB8	
+0x9AA1	0x6BB9	
+0x9AA2	0x6BBA	
+0x9AA3	0x6BBB	
+0x9AA4	0x6BBC	
+0x9AA5	0x6BBD	
+0x9AA6	0x6BBE	
+0x9AA7	0x6BC0	
+0x9AA8	0x6BC3	
+0x9AA9	0x6BC4	
+0x9AAA	0x6BC6	
+0x9AAB	0x6BC7	
+0x9AAC	0x6BC8	
+0x9AAD	0x6BC9	
+0x9AAE	0x6BCA	
+0x9AAF	0x6BCC	
+0x9AB0	0x6BCE	
+0x9AB1	0x6BD0	
+0x9AB2	0x6BD1	
+0x9AB3	0x6BD8	
+0x9AB4	0x6BDA	
+0x9AB5	0x6BDC	
+0x9AB6	0x6BDD	
+0x9AB7	0x6BDE	
+0x9AB8	0x6BDF	
+0x9AB9	0x6BE0	
+0x9ABA	0x6BE2	
+0x9ABB	0x6BE3	
+0x9ABC	0x6BE4	
+0x9ABD	0x6BE5	
+0x9ABE	0x6BE6	
+0x9ABF	0x6BE7	
+0x9AC0	0x6BE8	
+0x9AC1	0x6BE9	
+0x9AC2	0x6BEC	
+0x9AC3	0x6BED	
+0x9AC4	0x6BEE	
+0x9AC5	0x6BF0	
+0x9AC6	0x6BF1	
+0x9AC7	0x6BF2	
+0x9AC8	0x6BF4	
+0x9AC9	0x6BF6	
+0x9ACA	0x6BF7	
+0x9ACB	0x6BF8	
+0x9ACC	0x6BFA	
+0x9ACD	0x6BFB	
+0x9ACE	0x6BFC	
+0x9ACF	0x6BFE	
+0x9AD0	0x6BFF	
+0x9AD1	0x6C00	
+0x9AD2	0x6C01	
+0x9AD3	0x6C02	
+0x9AD4	0x6C03	
+0x9AD5	0x6C04	
+0x9AD6	0x6C08	
+0x9AD7	0x6C09	
+0x9AD8	0x6C0A	
+0x9AD9	0x6C0B	
+0x9ADA	0x6C0C	
+0x9ADB	0x6C0E	
+0x9ADC	0x6C12	
+0x9ADD	0x6C17	
+0x9ADE	0x6C1C	
+0x9ADF	0x6C1D	
+0x9AE0	0x6C1E	
+0x9AE1	0x6C20	
+0x9AE2	0x6C23	
+0x9AE3	0x6C25	
+0x9AE4	0x6C2B	
+0x9AE5	0x6C2C	
+0x9AE6	0x6C2D	
+0x9AE7	0x6C31	
+0x9AE8	0x6C33	
+0x9AE9	0x6C36	
+0x9AEA	0x6C37	
+0x9AEB	0x6C39	
+0x9AEC	0x6C3A	
+0x9AED	0x6C3B	
+0x9AEE	0x6C3C	
+0x9AEF	0x6C3E	
+0x9AF0	0x6C3F	
+0x9AF1	0x6C43	
+0x9AF2	0x6C44	
+0x9AF3	0x6C45	
+0x9AF4	0x6C48	
+0x9AF5	0x6C4B	
+0x9AF6	0x6C4C	
+0x9AF7	0x6C4D	
+0x9AF8	0x6C4E	
+0x9AF9	0x6C4F	
+0x9AFA	0x6C51	
+0x9AFB	0x6C52	
+0x9AFC	0x6C53	
+0x9AFD	0x6C56	
+0x9AFE	0x6C58	
+0x9B40	0x6C59	
+0x9B41	0x6C5A	
+0x9B42	0x6C62	
+0x9B43	0x6C63	
+0x9B44	0x6C65	
+0x9B45	0x6C66	
+0x9B46	0x6C67	
+0x9B47	0x6C6B	
+0x9B48	0x6C6C	
+0x9B49	0x6C6D	
+0x9B4A	0x6C6E	
+0x9B4B	0x6C6F	
+0x9B4C	0x6C71	
+0x9B4D	0x6C73	
+0x9B4E	0x6C75	
+0x9B4F	0x6C77	
+0x9B50	0x6C78	
+0x9B51	0x6C7A	
+0x9B52	0x6C7B	
+0x9B53	0x6C7C	
+0x9B54	0x6C7F	
+0x9B55	0x6C80	
+0x9B56	0x6C84	
+0x9B57	0x6C87	
+0x9B58	0x6C8A	
+0x9B59	0x6C8B	
+0x9B5A	0x6C8D	
+0x9B5B	0x6C8E	
+0x9B5C	0x6C91	
+0x9B5D	0x6C92	
+0x9B5E	0x6C95	
+0x9B5F	0x6C96	
+0x9B60	0x6C97	
+0x9B61	0x6C98	
+0x9B62	0x6C9A	
+0x9B63	0x6C9C	
+0x9B64	0x6C9D	
+0x9B65	0x6C9E	
+0x9B66	0x6CA0	
+0x9B67	0x6CA2	
+0x9B68	0x6CA8	
+0x9B69	0x6CAC	
+0x9B6A	0x6CAF	
+0x9B6B	0x6CB0	
+0x9B6C	0x6CB4	
+0x9B6D	0x6CB5	
+0x9B6E	0x6CB6	
+0x9B6F	0x6CB7	
+0x9B70	0x6CBA	
+0x9B71	0x6CC0	
+0x9B72	0x6CC1	
+0x9B73	0x6CC2	
+0x9B74	0x6CC3	
+0x9B75	0x6CC6	
+0x9B76	0x6CC7	
+0x9B77	0x6CC8	
+0x9B78	0x6CCB	
+0x9B79	0x6CCD	
+0x9B7A	0x6CCE	
+0x9B7B	0x6CCF	
+0x9B7C	0x6CD1	
+0x9B7D	0x6CD2	
+0x9B7E	0x6CD8	
+0x9B80	0x6CD9	
+0x9B81	0x6CDA	
+0x9B82	0x6CDC	
+0x9B83	0x6CDD	
+0x9B84	0x6CDF	
+0x9B85	0x6CE4	
+0x9B86	0x6CE6	
+0x9B87	0x6CE7	
+0x9B88	0x6CE9	
+0x9B89	0x6CEC	
+0x9B8A	0x6CED	
+0x9B8B	0x6CF2	
+0x9B8C	0x6CF4	
+0x9B8D	0x6CF9	
+0x9B8E	0x6CFF	
+0x9B8F	0x6D00	
+0x9B90	0x6D02	
+0x9B91	0x6D03	
+0x9B92	0x6D05	
+0x9B93	0x6D06	
+0x9B94	0x6D08	
+0x9B95	0x6D09	
+0x9B96	0x6D0A	
+0x9B97	0x6D0D	
+0x9B98	0x6D0F	
+0x9B99	0x6D10	
+0x9B9A	0x6D11	
+0x9B9B	0x6D13	
+0x9B9C	0x6D14	
+0x9B9D	0x6D15	
+0x9B9E	0x6D16	
+0x9B9F	0x6D18	
+0x9BA0	0x6D1C	
+0x9BA1	0x6D1D	
+0x9BA2	0x6D1F	
+0x9BA3	0x6D20	
+0x9BA4	0x6D21	
+0x9BA5	0x6D22	
+0x9BA6	0x6D23	
+0x9BA7	0x6D24	
+0x9BA8	0x6D26	
+0x9BA9	0x6D28	
+0x9BAA	0x6D29	
+0x9BAB	0x6D2C	
+0x9BAC	0x6D2D	
+0x9BAD	0x6D2F	
+0x9BAE	0x6D30	
+0x9BAF	0x6D34	
+0x9BB0	0x6D36	
+0x9BB1	0x6D37	
+0x9BB2	0x6D38	
+0x9BB3	0x6D3A	
+0x9BB4	0x6D3F	
+0x9BB5	0x6D40	
+0x9BB6	0x6D42	
+0x9BB7	0x6D44	
+0x9BB8	0x6D49	
+0x9BB9	0x6D4C	
+0x9BBA	0x6D50	
+0x9BBB	0x6D55	
+0x9BBC	0x6D56	
+0x9BBD	0x6D57	
+0x9BBE	0x6D58	
+0x9BBF	0x6D5B	
+0x9BC0	0x6D5D	
+0x9BC1	0x6D5F	
+0x9BC2	0x6D61	
+0x9BC3	0x6D62	
+0x9BC4	0x6D64	
+0x9BC5	0x6D65	
+0x9BC6	0x6D67	
+0x9BC7	0x6D68	
+0x9BC8	0x6D6B	
+0x9BC9	0x6D6C	
+0x9BCA	0x6D6D	
+0x9BCB	0x6D70	
+0x9BCC	0x6D71	
+0x9BCD	0x6D72	
+0x9BCE	0x6D73	
+0x9BCF	0x6D75	
+0x9BD0	0x6D76	
+0x9BD1	0x6D79	
+0x9BD2	0x6D7A	
+0x9BD3	0x6D7B	
+0x9BD4	0x6D7D	
+0x9BD5	0x6D7E	
+0x9BD6	0x6D7F	
+0x9BD7	0x6D80	
+0x9BD8	0x6D81	
+0x9BD9	0x6D83	
+0x9BDA	0x6D84	
+0x9BDB	0x6D86	
+0x9BDC	0x6D87	
+0x9BDD	0x6D8A	
+0x9BDE	0x6D8B	
+0x9BDF	0x6D8D	
+0x9BE0	0x6D8F	
+0x9BE1	0x6D90	
+0x9BE2	0x6D92	
+0x9BE3	0x6D96	
+0x9BE4	0x6D97	
+0x9BE5	0x6D98	
+0x9BE6	0x6D99	
+0x9BE7	0x6D9A	
+0x9BE8	0x6D9C	
+0x9BE9	0x6DA2	
+0x9BEA	0x6DA5	
+0x9BEB	0x6DAC	
+0x9BEC	0x6DAD	
+0x9BED	0x6DB0	
+0x9BEE	0x6DB1	
+0x9BEF	0x6DB3	
+0x9BF0	0x6DB4	
+0x9BF1	0x6DB6	
+0x9BF2	0x6DB7	
+0x9BF3	0x6DB9	
+0x9BF4	0x6DBA	
+0x9BF5	0x6DBB	
+0x9BF6	0x6DBC	
+0x9BF7	0x6DBD	
+0x9BF8	0x6DBE	
+0x9BF9	0x6DC1	
+0x9BFA	0x6DC2	
+0x9BFB	0x6DC3	
+0x9BFC	0x6DC8	
+0x9BFD	0x6DC9	
+0x9BFE	0x6DCA	
+0x9C40	0x6DCD	
+0x9C41	0x6DCE	
+0x9C42	0x6DCF	
+0x9C43	0x6DD0	
+0x9C44	0x6DD2	
+0x9C45	0x6DD3	
+0x9C46	0x6DD4	
+0x9C47	0x6DD5	
+0x9C48	0x6DD7	
+0x9C49	0x6DDA	
+0x9C4A	0x6DDB	
+0x9C4B	0x6DDC	
+0x9C4C	0x6DDF	
+0x9C4D	0x6DE2	
+0x9C4E	0x6DE3	
+0x9C4F	0x6DE5	
+0x9C50	0x6DE7	
+0x9C51	0x6DE8	
+0x9C52	0x6DE9	
+0x9C53	0x6DEA	
+0x9C54	0x6DED	
+0x9C55	0x6DEF	
+0x9C56	0x6DF0	
+0x9C57	0x6DF2	
+0x9C58	0x6DF4	
+0x9C59	0x6DF5	
+0x9C5A	0x6DF6	
+0x9C5B	0x6DF8	
+0x9C5C	0x6DFA	
+0x9C5D	0x6DFD	
+0x9C5E	0x6DFE	
+0x9C5F	0x6DFF	
+0x9C60	0x6E00	
+0x9C61	0x6E01	
+0x9C62	0x6E02	
+0x9C63	0x6E03	
+0x9C64	0x6E04	
+0x9C65	0x6E06	
+0x9C66	0x6E07	
+0x9C67	0x6E08	
+0x9C68	0x6E09	
+0x9C69	0x6E0B	
+0x9C6A	0x6E0F	
+0x9C6B	0x6E12	
+0x9C6C	0x6E13	
+0x9C6D	0x6E15	
+0x9C6E	0x6E18	
+0x9C6F	0x6E19	
+0x9C70	0x6E1B	
+0x9C71	0x6E1C	
+0x9C72	0x6E1E	
+0x9C73	0x6E1F	
+0x9C74	0x6E22	
+0x9C75	0x6E26	
+0x9C76	0x6E27	
+0x9C77	0x6E28	
+0x9C78	0x6E2A	
+0x9C79	0x6E2C	
+0x9C7A	0x6E2E	
+0x9C7B	0x6E30	
+0x9C7C	0x6E31	
+0x9C7D	0x6E33	
+0x9C7E	0x6E35	
+0x9C80	0x6E36	
+0x9C81	0x6E37	
+0x9C82	0x6E39	
+0x9C83	0x6E3B	
+0x9C84	0x6E3C	
+0x9C85	0x6E3D	
+0x9C86	0x6E3E	
+0x9C87	0x6E3F	
+0x9C88	0x6E40	
+0x9C89	0x6E41	
+0x9C8A	0x6E42	
+0x9C8B	0x6E45	
+0x9C8C	0x6E46	
+0x9C8D	0x6E47	
+0x9C8E	0x6E48	
+0x9C8F	0x6E49	
+0x9C90	0x6E4A	
+0x9C91	0x6E4B	
+0x9C92	0x6E4C	
+0x9C93	0x6E4F	
+0x9C94	0x6E50	
+0x9C95	0x6E51	
+0x9C96	0x6E52	
+0x9C97	0x6E55	
+0x9C98	0x6E57	
+0x9C99	0x6E59	
+0x9C9A	0x6E5A	
+0x9C9B	0x6E5C	
+0x9C9C	0x6E5D	
+0x9C9D	0x6E5E	
+0x9C9E	0x6E60	
+0x9C9F	0x6E61	
+0x9CA0	0x6E62	
+0x9CA1	0x6E63	
+0x9CA2	0x6E64	
+0x9CA3	0x6E65	
+0x9CA4	0x6E66	
+0x9CA5	0x6E67	
+0x9CA6	0x6E68	
+0x9CA7	0x6E69	
+0x9CA8	0x6E6A	
+0x9CA9	0x6E6C	
+0x9CAA	0x6E6D	
+0x9CAB	0x6E6F	
+0x9CAC	0x6E70	
+0x9CAD	0x6E71	
+0x9CAE	0x6E72	
+0x9CAF	0x6E73	
+0x9CB0	0x6E74	
+0x9CB1	0x6E75	
+0x9CB2	0x6E76	
+0x9CB3	0x6E77	
+0x9CB4	0x6E78	
+0x9CB5	0x6E79	
+0x9CB6	0x6E7A	
+0x9CB7	0x6E7B	
+0x9CB8	0x6E7C	
+0x9CB9	0x6E7D	
+0x9CBA	0x6E80	
+0x9CBB	0x6E81	
+0x9CBC	0x6E82	
+0x9CBD	0x6E84	
+0x9CBE	0x6E87	
+0x9CBF	0x6E88	
+0x9CC0	0x6E8A	
+0x9CC1	0x6E8B	
+0x9CC2	0x6E8C	
+0x9CC3	0x6E8D	
+0x9CC4	0x6E8E	
+0x9CC5	0x6E91	
+0x9CC6	0x6E92	
+0x9CC7	0x6E93	
+0x9CC8	0x6E94	
+0x9CC9	0x6E95	
+0x9CCA	0x6E96	
+0x9CCB	0x6E97	
+0x9CCC	0x6E99	
+0x9CCD	0x6E9A	
+0x9CCE	0x6E9B	
+0x9CCF	0x6E9D	
+0x9CD0	0x6E9E	
+0x9CD1	0x6EA0	
+0x9CD2	0x6EA1	
+0x9CD3	0x6EA3	
+0x9CD4	0x6EA4	
+0x9CD5	0x6EA6	
+0x9CD6	0x6EA8	
+0x9CD7	0x6EA9	
+0x9CD8	0x6EAB	
+0x9CD9	0x6EAC	
+0x9CDA	0x6EAD	
+0x9CDB	0x6EAE	
+0x9CDC	0x6EB0	
+0x9CDD	0x6EB3	
+0x9CDE	0x6EB5	
+0x9CDF	0x6EB8	
+0x9CE0	0x6EB9	
+0x9CE1	0x6EBC	
+0x9CE2	0x6EBE	
+0x9CE3	0x6EBF	
+0x9CE4	0x6EC0	
+0x9CE5	0x6EC3	
+0x9CE6	0x6EC4	
+0x9CE7	0x6EC5	
+0x9CE8	0x6EC6	
+0x9CE9	0x6EC8	
+0x9CEA	0x6EC9	
+0x9CEB	0x6ECA	
+0x9CEC	0x6ECC	
+0x9CED	0x6ECD	
+0x9CEE	0x6ECE	
+0x9CEF	0x6ED0	
+0x9CF0	0x6ED2	
+0x9CF1	0x6ED6	
+0x9CF2	0x6ED8	
+0x9CF3	0x6ED9	
+0x9CF4	0x6EDB	
+0x9CF5	0x6EDC	
+0x9CF6	0x6EDD	
+0x9CF7	0x6EE3	
+0x9CF8	0x6EE7	
+0x9CF9	0x6EEA	
+0x9CFA	0x6EEB	
+0x9CFB	0x6EEC	
+0x9CFC	0x6EED	
+0x9CFD	0x6EEE	
+0x9CFE	0x6EEF	
+0x9D40	0x6EF0	
+0x9D41	0x6EF1	
+0x9D42	0x6EF2	
+0x9D43	0x6EF3	
+0x9D44	0x6EF5	
+0x9D45	0x6EF6	
+0x9D46	0x6EF7	
+0x9D47	0x6EF8	
+0x9D48	0x6EFA	
+0x9D49	0x6EFB	
+0x9D4A	0x6EFC	
+0x9D4B	0x6EFD	
+0x9D4C	0x6EFE	
+0x9D4D	0x6EFF	
+0x9D4E	0x6F00	
+0x9D4F	0x6F01	
+0x9D50	0x6F03	
+0x9D51	0x6F04	
+0x9D52	0x6F05	
+0x9D53	0x6F07	
+0x9D54	0x6F08	
+0x9D55	0x6F0A	
+0x9D56	0x6F0B	
+0x9D57	0x6F0C	
+0x9D58	0x6F0D	
+0x9D59	0x6F0E	
+0x9D5A	0x6F10	
+0x9D5B	0x6F11	
+0x9D5C	0x6F12	
+0x9D5D	0x6F16	
+0x9D5E	0x6F17	
+0x9D5F	0x6F18	
+0x9D60	0x6F19	
+0x9D61	0x6F1A	
+0x9D62	0x6F1B	
+0x9D63	0x6F1C	
+0x9D64	0x6F1D	
+0x9D65	0x6F1E	
+0x9D66	0x6F1F	
+0x9D67	0x6F21	
+0x9D68	0x6F22	
+0x9D69	0x6F23	
+0x9D6A	0x6F25	
+0x9D6B	0x6F26	
+0x9D6C	0x6F27	
+0x9D6D	0x6F28	
+0x9D6E	0x6F2C	
+0x9D6F	0x6F2E	
+0x9D70	0x6F30	
+0x9D71	0x6F32	
+0x9D72	0x6F34	
+0x9D73	0x6F35	
+0x9D74	0x6F37	
+0x9D75	0x6F38	
+0x9D76	0x6F39	
+0x9D77	0x6F3A	
+0x9D78	0x6F3B	
+0x9D79	0x6F3C	
+0x9D7A	0x6F3D	
+0x9D7B	0x6F3F	
+0x9D7C	0x6F40	
+0x9D7D	0x6F41	
+0x9D7E	0x6F42	
+0x9D80	0x6F43	
+0x9D81	0x6F44	
+0x9D82	0x6F45	
+0x9D83	0x6F48	
+0x9D84	0x6F49	
+0x9D85	0x6F4A	
+0x9D86	0x6F4C	
+0x9D87	0x6F4E	
+0x9D88	0x6F4F	
+0x9D89	0x6F50	
+0x9D8A	0x6F51	
+0x9D8B	0x6F52	
+0x9D8C	0x6F53	
+0x9D8D	0x6F54	
+0x9D8E	0x6F55	
+0x9D8F	0x6F56	
+0x9D90	0x6F57	
+0x9D91	0x6F59	
+0x9D92	0x6F5A	
+0x9D93	0x6F5B	
+0x9D94	0x6F5D	
+0x9D95	0x6F5F	
+0x9D96	0x6F60	
+0x9D97	0x6F61	
+0x9D98	0x6F63	
+0x9D99	0x6F64	
+0x9D9A	0x6F65	
+0x9D9B	0x6F67	
+0x9D9C	0x6F68	
+0x9D9D	0x6F69	
+0x9D9E	0x6F6A	
+0x9D9F	0x6F6B	
+0x9DA0	0x6F6C	
+0x9DA1	0x6F6F	
+0x9DA2	0x6F70	
+0x9DA3	0x6F71	
+0x9DA4	0x6F73	
+0x9DA5	0x6F75	
+0x9DA6	0x6F76	
+0x9DA7	0x6F77	
+0x9DA8	0x6F79	
+0x9DA9	0x6F7B	
+0x9DAA	0x6F7D	
+0x9DAB	0x6F7E	
+0x9DAC	0x6F7F	
+0x9DAD	0x6F80	
+0x9DAE	0x6F81	
+0x9DAF	0x6F82	
+0x9DB0	0x6F83	
+0x9DB1	0x6F85	
+0x9DB2	0x6F86	
+0x9DB3	0x6F87	
+0x9DB4	0x6F8A	
+0x9DB5	0x6F8B	
+0x9DB6	0x6F8F	
+0x9DB7	0x6F90	
+0x9DB8	0x6F91	
+0x9DB9	0x6F92	
+0x9DBA	0x6F93	
+0x9DBB	0x6F94	
+0x9DBC	0x6F95	
+0x9DBD	0x6F96	
+0x9DBE	0x6F97	
+0x9DBF	0x6F98	
+0x9DC0	0x6F99	
+0x9DC1	0x6F9A	
+0x9DC2	0x6F9B	
+0x9DC3	0x6F9D	
+0x9DC4	0x6F9E	
+0x9DC5	0x6F9F	
+0x9DC6	0x6FA0	
+0x9DC7	0x6FA2	
+0x9DC8	0x6FA3	
+0x9DC9	0x6FA4	
+0x9DCA	0x6FA5	
+0x9DCB	0x6FA6	
+0x9DCC	0x6FA8	
+0x9DCD	0x6FA9	
+0x9DCE	0x6FAA	
+0x9DCF	0x6FAB	
+0x9DD0	0x6FAC	
+0x9DD1	0x6FAD	
+0x9DD2	0x6FAE	
+0x9DD3	0x6FAF	
+0x9DD4	0x6FB0	
+0x9DD5	0x6FB1	
+0x9DD6	0x6FB2	
+0x9DD7	0x6FB4	
+0x9DD8	0x6FB5	
+0x9DD9	0x6FB7	
+0x9DDA	0x6FB8	
+0x9DDB	0x6FBA	
+0x9DDC	0x6FBB	
+0x9DDD	0x6FBC	
+0x9DDE	0x6FBD	
+0x9DDF	0x6FBE	
+0x9DE0	0x6FBF	
+0x9DE1	0x6FC1	
+0x9DE2	0x6FC3	
+0x9DE3	0x6FC4	
+0x9DE4	0x6FC5	
+0x9DE5	0x6FC6	
+0x9DE6	0x6FC7	
+0x9DE7	0x6FC8	
+0x9DE8	0x6FCA	
+0x9DE9	0x6FCB	
+0x9DEA	0x6FCC	
+0x9DEB	0x6FCD	
+0x9DEC	0x6FCE	
+0x9DED	0x6FCF	
+0x9DEE	0x6FD0	
+0x9DEF	0x6FD3	
+0x9DF0	0x6FD4	
+0x9DF1	0x6FD5	
+0x9DF2	0x6FD6	
+0x9DF3	0x6FD7	
+0x9DF4	0x6FD8	
+0x9DF5	0x6FD9	
+0x9DF6	0x6FDA	
+0x9DF7	0x6FDB	
+0x9DF8	0x6FDC	
+0x9DF9	0x6FDD	
+0x9DFA	0x6FDF	
+0x9DFB	0x6FE2	
+0x9DFC	0x6FE3	
+0x9DFD	0x6FE4	
+0x9DFE	0x6FE5	
+0x9E40	0x6FE6	
+0x9E41	0x6FE7	
+0x9E42	0x6FE8	
+0x9E43	0x6FE9	
+0x9E44	0x6FEA	
+0x9E45	0x6FEB	
+0x9E46	0x6FEC	
+0x9E47	0x6FED	
+0x9E48	0x6FF0	
+0x9E49	0x6FF1	
+0x9E4A	0x6FF2	
+0x9E4B	0x6FF3	
+0x9E4C	0x6FF4	
+0x9E4D	0x6FF5	
+0x9E4E	0x6FF6	
+0x9E4F	0x6FF7	
+0x9E50	0x6FF8	
+0x9E51	0x6FF9	
+0x9E52	0x6FFA	
+0x9E53	0x6FFB	
+0x9E54	0x6FFC	
+0x9E55	0x6FFD	
+0x9E56	0x6FFE	
+0x9E57	0x6FFF	
+0x9E58	0x7000	
+0x9E59	0x7001	
+0x9E5A	0x7002	
+0x9E5B	0x7003	
+0x9E5C	0x7004	
+0x9E5D	0x7005	
+0x9E5E	0x7006	
+0x9E5F	0x7007	
+0x9E60	0x7008	
+0x9E61	0x7009	
+0x9E62	0x700A	
+0x9E63	0x700B	
+0x9E64	0x700C	
+0x9E65	0x700D	
+0x9E66	0x700E	
+0x9E67	0x700F	
+0x9E68	0x7010	
+0x9E69	0x7012	
+0x9E6A	0x7013	
+0x9E6B	0x7014	
+0x9E6C	0x7015	
+0x9E6D	0x7016	
+0x9E6E	0x7017	
+0x9E6F	0x7018	
+0x9E70	0x7019	
+0x9E71	0x701C	
+0x9E72	0x701D	
+0x9E73	0x701E	
+0x9E74	0x701F	
+0x9E75	0x7020	
+0x9E76	0x7021	
+0x9E77	0x7022	
+0x9E78	0x7024	
+0x9E79	0x7025	
+0x9E7A	0x7026	
+0x9E7B	0x7027	
+0x9E7C	0x7028	
+0x9E7D	0x7029	
+0x9E7E	0x702A	
+0x9E80	0x702B	
+0x9E81	0x702C	
+0x9E82	0x702D	
+0x9E83	0x702E	
+0x9E84	0x702F	
+0x9E85	0x7030	
+0x9E86	0x7031	
+0x9E87	0x7032	
+0x9E88	0x7033	
+0x9E89	0x7034	
+0x9E8A	0x7036	
+0x9E8B	0x7037	
+0x9E8C	0x7038	
+0x9E8D	0x703A	
+0x9E8E	0x703B	
+0x9E8F	0x703C	
+0x9E90	0x703D	
+0x9E91	0x703E	
+0x9E92	0x703F	
+0x9E93	0x7040	
+0x9E94	0x7041	
+0x9E95	0x7042	
+0x9E96	0x7043	
+0x9E97	0x7044	
+0x9E98	0x7045	
+0x9E99	0x7046	
+0x9E9A	0x7047	
+0x9E9B	0x7048	
+0x9E9C	0x7049	
+0x9E9D	0x704A	
+0x9E9E	0x704B	
+0x9E9F	0x704D	
+0x9EA0	0x704E	
+0x9EA1	0x7050	
+0x9EA2	0x7051	
+0x9EA3	0x7052	
+0x9EA4	0x7053	
+0x9EA5	0x7054	
+0x9EA6	0x7055	
+0x9EA7	0x7056	
+0x9EA8	0x7057	
+0x9EA9	0x7058	
+0x9EAA	0x7059	
+0x9EAB	0x705A	
+0x9EAC	0x705B	
+0x9EAD	0x705C	
+0x9EAE	0x705D	
+0x9EAF	0x705F	
+0x9EB0	0x7060	
+0x9EB1	0x7061	
+0x9EB2	0x7062	
+0x9EB3	0x7063	
+0x9EB4	0x7064	
+0x9EB5	0x7065	
+0x9EB6	0x7066	
+0x9EB7	0x7067	
+0x9EB8	0x7068	
+0x9EB9	0x7069	
+0x9EBA	0x706A	
+0x9EBB	0x706E	
+0x9EBC	0x7071	
+0x9EBD	0x7072	
+0x9EBE	0x7073	
+0x9EBF	0x7074	
+0x9EC0	0x7077	
+0x9EC1	0x7079	
+0x9EC2	0x707A	
+0x9EC3	0x707B	
+0x9EC4	0x707D	
+0x9EC5	0x7081	
+0x9EC6	0x7082	
+0x9EC7	0x7083	
+0x9EC8	0x7084	
+0x9EC9	0x7086	
+0x9ECA	0x7087	
+0x9ECB	0x7088	
+0x9ECC	0x708B	
+0x9ECD	0x708C	
+0x9ECE	0x708D	
+0x9ECF	0x708F	
+0x9ED0	0x7090	
+0x9ED1	0x7091	
+0x9ED2	0x7093	
+0x9ED3	0x7097	
+0x9ED4	0x7098	
+0x9ED5	0x709A	
+0x9ED6	0x709B	
+0x9ED7	0x709E	
+0x9ED8	0x709F	
+0x9ED9	0x70A0	
+0x9EDA	0x70A1	
+0x9EDB	0x70A2	
+0x9EDC	0x70A3	
+0x9EDD	0x70A4	
+0x9EDE	0x70A5	
+0x9EDF	0x70A6	
+0x9EE0	0x70A7	
+0x9EE1	0x70A8	
+0x9EE2	0x70A9	
+0x9EE3	0x70AA	
+0x9EE4	0x70B0	
+0x9EE5	0x70B2	
+0x9EE6	0x70B4	
+0x9EE7	0x70B5	
+0x9EE8	0x70B6	
+0x9EE9	0x70BA	
+0x9EEA	0x70BE	
+0x9EEB	0x70BF	
+0x9EEC	0x70C4	
+0x9EED	0x70C5	
+0x9EEE	0x70C6	
+0x9EEF	0x70C7	
+0x9EF0	0x70C9	
+0x9EF1	0x70CB	
+0x9EF2	0x70CC	
+0x9EF3	0x70CD	
+0x9EF4	0x70CE	
+0x9EF5	0x70CF	
+0x9EF6	0x70D0	
+0x9EF7	0x70D1	
+0x9EF8	0x70D2	
+0x9EF9	0x70D3	
+0x9EFA	0x70D4	
+0x9EFB	0x70D5	
+0x9EFC	0x70D6	
+0x9EFD	0x70D7	
+0x9EFE	0x70DA	
+0x9F40	0x70DC	
+0x9F41	0x70DD	
+0x9F42	0x70DE	
+0x9F43	0x70E0	
+0x9F44	0x70E1	
+0x9F45	0x70E2	
+0x9F46	0x70E3	
+0x9F47	0x70E5	
+0x9F48	0x70EA	
+0x9F49	0x70EE	
+0x9F4A	0x70F0	
+0x9F4B	0x70F1	
+0x9F4C	0x70F2	
+0x9F4D	0x70F3	
+0x9F4E	0x70F4	
+0x9F4F	0x70F5	
+0x9F50	0x70F6	
+0x9F51	0x70F8	
+0x9F52	0x70FA	
+0x9F53	0x70FB	
+0x9F54	0x70FC	
+0x9F55	0x70FE	
+0x9F56	0x70FF	
+0x9F57	0x7100	
+0x9F58	0x7101	
+0x9F59	0x7102	
+0x9F5A	0x7103	
+0x9F5B	0x7104	
+0x9F5C	0x7105	
+0x9F5D	0x7106	
+0x9F5E	0x7107	
+0x9F5F	0x7108	
+0x9F60	0x710B	
+0x9F61	0x710C	
+0x9F62	0x710D	
+0x9F63	0x710E	
+0x9F64	0x710F	
+0x9F65	0x7111	
+0x9F66	0x7112	
+0x9F67	0x7114	
+0x9F68	0x7117	
+0x9F69	0x711B	
+0x9F6A	0x711C	
+0x9F6B	0x711D	
+0x9F6C	0x711E	
+0x9F6D	0x711F	
+0x9F6E	0x7120	
+0x9F6F	0x7121	
+0x9F70	0x7122	
+0x9F71	0x7123	
+0x9F72	0x7124	
+0x9F73	0x7125	
+0x9F74	0x7127	
+0x9F75	0x7128	
+0x9F76	0x7129	
+0x9F77	0x712A	
+0x9F78	0x712B	
+0x9F79	0x712C	
+0x9F7A	0x712D	
+0x9F7B	0x712E	
+0x9F7C	0x7132	
+0x9F7D	0x7133	
+0x9F7E	0x7134	
+0x9F80	0x7135	
+0x9F81	0x7137	
+0x9F82	0x7138	
+0x9F83	0x7139	
+0x9F84	0x713A	
+0x9F85	0x713B	
+0x9F86	0x713C	
+0x9F87	0x713D	
+0x9F88	0x713E	
+0x9F89	0x713F	
+0x9F8A	0x7140	
+0x9F8B	0x7141	
+0x9F8C	0x7142	
+0x9F8D	0x7143	
+0x9F8E	0x7144	
+0x9F8F	0x7146	
+0x9F90	0x7147	
+0x9F91	0x7148	
+0x9F92	0x7149	
+0x9F93	0x714B	
+0x9F94	0x714D	
+0x9F95	0x714F	
+0x9F96	0x7150	
+0x9F97	0x7151	
+0x9F98	0x7152	
+0x9F99	0x7153	
+0x9F9A	0x7154	
+0x9F9B	0x7155	
+0x9F9C	0x7156	
+0x9F9D	0x7157	
+0x9F9E	0x7158	
+0x9F9F	0x7159	
+0x9FA0	0x715A	
+0x9FA1	0x715B	
+0x9FA2	0x715D	
+0x9FA3	0x715F	
+0x9FA4	0x7160	
+0x9FA5	0x7161	
+0x9FA6	0x7162	
+0x9FA7	0x7163	
+0x9FA8	0x7165	
+0x9FA9	0x7169	
+0x9FAA	0x716A	
+0x9FAB	0x716B	
+0x9FAC	0x716C	
+0x9FAD	0x716D	
+0x9FAE	0x716F	
+0x9FAF	0x7170	
+0x9FB0	0x7171	
+0x9FB1	0x7174	
+0x9FB2	0x7175	
+0x9FB3	0x7176	
+0x9FB4	0x7177	
+0x9FB5	0x7179	
+0x9FB6	0x717B	
+0x9FB7	0x717C	
+0x9FB8	0x717E	
+0x9FB9	0x717F	
+0x9FBA	0x7180	
+0x9FBB	0x7181	
+0x9FBC	0x7182	
+0x9FBD	0x7183	
+0x9FBE	0x7185	
+0x9FBF	0x7186	
+0x9FC0	0x7187	
+0x9FC1	0x7188	
+0x9FC2	0x7189	
+0x9FC3	0x718B	
+0x9FC4	0x718C	
+0x9FC5	0x718D	
+0x9FC6	0x718E	
+0x9FC7	0x7190	
+0x9FC8	0x7191	
+0x9FC9	0x7192	
+0x9FCA	0x7193	
+0x9FCB	0x7195	
+0x9FCC	0x7196	
+0x9FCD	0x7197	
+0x9FCE	0x719A	
+0x9FCF	0x719B	
+0x9FD0	0x719C	
+0x9FD1	0x719D	
+0x9FD2	0x719E	
+0x9FD3	0x71A1	
+0x9FD4	0x71A2	
+0x9FD5	0x71A3	
+0x9FD6	0x71A4	
+0x9FD7	0x71A5	
+0x9FD8	0x71A6	
+0x9FD9	0x71A7	
+0x9FDA	0x71A9	
+0x9FDB	0x71AA	
+0x9FDC	0x71AB	
+0x9FDD	0x71AD	
+0x9FDE	0x71AE	
+0x9FDF	0x71AF	
+0x9FE0	0x71B0	
+0x9FE1	0x71B1	
+0x9FE2	0x71B2	
+0x9FE3	0x71B4	
+0x9FE4	0x71B6	
+0x9FE5	0x71B7	
+0x9FE6	0x71B8	
+0x9FE7	0x71BA	
+0x9FE8	0x71BB	
+0x9FE9	0x71BC	
+0x9FEA	0x71BD	
+0x9FEB	0x71BE	
+0x9FEC	0x71BF	
+0x9FED	0x71C0	
+0x9FEE	0x71C1	
+0x9FEF	0x71C2	
+0x9FF0	0x71C4	
+0x9FF1	0x71C5	
+0x9FF2	0x71C6	
+0x9FF3	0x71C7	
+0x9FF4	0x71C8	
+0x9FF5	0x71C9	
+0x9FF6	0x71CA	
+0x9FF7	0x71CB	
+0x9FF8	0x71CC	
+0x9FF9	0x71CD	
+0x9FFA	0x71CF	
+0x9FFB	0x71D0	
+0x9FFC	0x71D1	
+0x9FFD	0x71D2	
+0x9FFE	0x71D3	
+0xA040	0x71D6	
+0xA041	0x71D7	
+0xA042	0x71D8	
+0xA043	0x71D9	
+0xA044	0x71DA	
+0xA045	0x71DB	
+0xA046	0x71DC	
+0xA047	0x71DD	
+0xA048	0x71DE	
+0xA049	0x71DF	
+0xA04A	0x71E1	
+0xA04B	0x71E2	
+0xA04C	0x71E3	
+0xA04D	0x71E4	
+0xA04E	0x71E6	
+0xA04F	0x71E8	
+0xA050	0x71E9	
+0xA051	0x71EA	
+0xA052	0x71EB	
+0xA053	0x71EC	
+0xA054	0x71ED	
+0xA055	0x71EF	
+0xA056	0x71F0	
+0xA057	0x71F1	
+0xA058	0x71F2	
+0xA059	0x71F3	
+0xA05A	0x71F4	
+0xA05B	0x71F5	
+0xA05C	0x71F6	
+0xA05D	0x71F7	
+0xA05E	0x71F8	
+0xA05F	0x71FA	
+0xA060	0x71FB	
+0xA061	0x71FC	
+0xA062	0x71FD	
+0xA063	0x71FE	
+0xA064	0x71FF	
+0xA065	0x7200	
+0xA066	0x7201	
+0xA067	0x7202	
+0xA068	0x7203	
+0xA069	0x7204	
+0xA06A	0x7205	
+0xA06B	0x7207	
+0xA06C	0x7208	
+0xA06D	0x7209	
+0xA06E	0x720A	
+0xA06F	0x720B	
+0xA070	0x720C	
+0xA071	0x720D	
+0xA072	0x720E	
+0xA073	0x720F	
+0xA074	0x7210	
+0xA075	0x7211	
+0xA076	0x7212	
+0xA077	0x7213	
+0xA078	0x7214	
+0xA079	0x7215	
+0xA07A	0x7216	
+0xA07B	0x7217	
+0xA07C	0x7218	
+0xA07D	0x7219	
+0xA07E	0x721A	
+0xA080	0x721B	
+0xA081	0x721C	
+0xA082	0x721E	
+0xA083	0x721F	
+0xA084	0x7220	
+0xA085	0x7221	
+0xA086	0x7222	
+0xA087	0x7223	
+0xA088	0x7224	
+0xA089	0x7225	
+0xA08A	0x7226	
+0xA08B	0x7227	
+0xA08C	0x7229	
+0xA08D	0x722B	
+0xA08E	0x722D	
+0xA08F	0x722E	
+0xA090	0x722F	
+0xA091	0x7232	
+0xA092	0x7233	
+0xA093	0x7234	
+0xA094	0x723A	
+0xA095	0x723C	
+0xA096	0x723E	
+0xA097	0x7240	
+0xA098	0x7241	
+0xA099	0x7242	
+0xA09A	0x7243	
+0xA09B	0x7244	
+0xA09C	0x7245	
+0xA09D	0x7246	
+0xA09E	0x7249	
+0xA09F	0x724A	
+0xA0A0	0x724B	
+0xA0A1	0x724E	
+0xA0A2	0x724F	
+0xA0A3	0x7250	
+0xA0A4	0x7251	
+0xA0A5	0x7253	
+0xA0A6	0x7254	
+0xA0A7	0x7255	
+0xA0A8	0x7257	
+0xA0A9	0x7258	
+0xA0AA	0x725A	
+0xA0AB	0x725C	
+0xA0AC	0x725E	
+0xA0AD	0x7260	
+0xA0AE	0x7263	
+0xA0AF	0x7264	
+0xA0B0	0x7265	
+0xA0B1	0x7268	
+0xA0B2	0x726A	
+0xA0B3	0x726B	
+0xA0B4	0x726C	
+0xA0B5	0x726D	
+0xA0B6	0x7270	
+0xA0B7	0x7271	
+0xA0B8	0x7273	
+0xA0B9	0x7274	
+0xA0BA	0x7276	
+0xA0BB	0x7277	
+0xA0BC	0x7278	
+0xA0BD	0x727B	
+0xA0BE	0x727C	
+0xA0BF	0x727D	
+0xA0C0	0x7282	
+0xA0C1	0x7283	
+0xA0C2	0x7285	
+0xA0C3	0x7286	
+0xA0C4	0x7287	
+0xA0C5	0x7288	
+0xA0C6	0x7289	
+0xA0C7	0x728C	
+0xA0C8	0x728E	
+0xA0C9	0x7290	
+0xA0CA	0x7291	
+0xA0CB	0x7293	
+0xA0CC	0x7294	
+0xA0CD	0x7295	
+0xA0CE	0x7296	
+0xA0CF	0x7297	
+0xA0D0	0x7298	
+0xA0D1	0x7299	
+0xA0D2	0x729A	
+0xA0D3	0x729B	
+0xA0D4	0x729C	
+0xA0D5	0x729D	
+0xA0D6	0x729E	
+0xA0D7	0x72A0	
+0xA0D8	0x72A1	
+0xA0D9	0x72A2	
+0xA0DA	0x72A3	
+0xA0DB	0x72A4	
+0xA0DC	0x72A5	
+0xA0DD	0x72A6	
+0xA0DE	0x72A7	
+0xA0DF	0x72A8	
+0xA0E0	0x72A9	
+0xA0E1	0x72AA	
+0xA0E2	0x72AB	
+0xA0E3	0x72AE	
+0xA0E4	0x72B1	
+0xA0E5	0x72B2	
+0xA0E6	0x72B3	
+0xA0E7	0x72B5	
+0xA0E8	0x72BA	
+0xA0E9	0x72BB	
+0xA0EA	0x72BC	
+0xA0EB	0x72BD	
+0xA0EC	0x72BE	
+0xA0ED	0x72BF	
+0xA0EE	0x72C0	
+0xA0EF	0x72C5	
+0xA0F0	0x72C6	
+0xA0F1	0x72C7	
+0xA0F2	0x72C9	
+0xA0F3	0x72CA	
+0xA0F4	0x72CB	
+0xA0F5	0x72CC	
+0xA0F6	0x72CF	
+0xA0F7	0x72D1	
+0xA0F8	0x72D3	
+0xA0F9	0x72D4	
+0xA0FA	0x72D5	
+0xA0FB	0x72D6	
+0xA0FC	0x72D8	
+0xA0FD	0x72DA	
+0xA0FE	0x72DB	
+# 0xA140	 	
+# 0xA141	 	
+# 0xA142	 	
+# 0xA143	 	
+# 0xA144	 	
+# 0xA145	 	
+# 0xA146	 	
+# 0xA147	 	
+# 0xA148	 	
+# 0xA149	 	
+# 0xA14A	 	
+# 0xA14B	 	
+# 0xA14C	 	
+# 0xA14D	 	
+# 0xA14E	 	
+# 0xA14F	 	
+# 0xA150	 	
+# 0xA151	 	
+# 0xA152	 	
+# 0xA153	 	
+# 0xA154	 	
+# 0xA155	 	
+# 0xA156	 	
+# 0xA157	 	
+# 0xA158	 	
+# 0xA159	 	
+# 0xA15A	 	
+# 0xA15B	 	
+# 0xA15C	 	
+# 0xA15D	 	
+# 0xA15E	 	
+# 0xA15F	 	
+# 0xA160	 	
+# 0xA161	 	
+# 0xA162	 	
+# 0xA163	 	
+# 0xA164	 	
+# 0xA165	 	
+# 0xA166	 	
+# 0xA167	 	
+# 0xA168	 	
+# 0xA169	 	
+# 0xA16A	 	
+# 0xA16B	 	
+# 0xA16C	 	
+# 0xA16D	 	
+# 0xA16E	 	
+# 0xA16F	 	
+# 0xA170	 	
+# 0xA171	 	
+# 0xA172	 	
+# 0xA173	 	
+# 0xA174	 	
+# 0xA175	 	
+# 0xA176	 	
+# 0xA177	 	
+# 0xA178	 	
+# 0xA179	 	
+# 0xA17A	 	
+# 0xA17B	 	
+# 0xA17C	 	
+# 0xA17D	 	
+# 0xA17E	 	
+# 0xA180	 	
+# 0xA181	 	
+# 0xA182	 	
+# 0xA183	 	
+# 0xA184	 	
+# 0xA185	 	
+# 0xA186	 	
+# 0xA187	 	
+# 0xA188	 	
+# 0xA189	 	
+# 0xA18A	 	
+# 0xA18B	 	
+# 0xA18C	 	
+# 0xA18D	 	
+# 0xA18E	 	
+# 0xA18F	 	
+# 0xA190	 	
+# 0xA191	 	
+# 0xA192	 	
+# 0xA193	 	
+# 0xA194	 	
+# 0xA195	 	
+# 0xA196	 	
+# 0xA197	 	
+# 0xA198	 	
+# 0xA199	 	
+# 0xA19A	 	
+# 0xA19B	 	
+# 0xA19C	 	
+# 0xA19D	 	
+# 0xA19E	 	
+# 0xA19F	 	
+# 0xA1A0	 	
+0xA1A1	0x3000	
+0xA1A2	0x3001	
+0xA1A3	0x3002	
+0xA1A4	0x30FB
+0xA1A5	0x02C9	
+0xA1A6	0x02C7	
+0xA1A7	0x00A8	
+0xA1A8	0x3003	
+0xA1A9	0x3005	
+0xA1AA	0x2015	
+0xA1AB	0xFF5E	
+0xA1AC	0x2016	
+0xA1AD	0x2026	
+0xA1AE	0x2018	
+0xA1AF	0x2019	
+0xA1B0	0x201C	
+0xA1B1	0x201D	
+0xA1B2	0x3014	
+0xA1B3	0x3015	
+0xA1B4	0x3008	
+0xA1B5	0x3009	
+0xA1B6	0x300A	
+0xA1B7	0x300B	
+0xA1B8	0x300C	
+0xA1B9	0x300D	
+0xA1BA	0x300E	
+0xA1BB	0x300F	
+0xA1BC	0x3016	
+0xA1BD	0x3017	
+0xA1BE	0x3010	
+0xA1BF	0x3011	
+0xA1C0	0x00B1	
+0xA1C1	0x00D7	
+0xA1C2	0x00F7	
+0xA1C3	0x2236	
+0xA1C4	0x2227	
+0xA1C5	0x2228	
+0xA1C6	0x2211	
+0xA1C7	0x220F	
+0xA1C8	0x222A	
+0xA1C9	0x2229	
+0xA1CA	0x2208	
+0xA1CB	0x2237	
+0xA1CC	0x221A	
+0xA1CD	0x22A5	
+0xA1CE	0x2225	
+0xA1CF	0x2220	
+0xA1D0	0x2312	
+0xA1D1	0x2299	
+0xA1D2	0x222B	
+0xA1D3	0x222E	
+0xA1D4	0x2261	
+0xA1D5	0x224C	
+0xA1D6	0x2248	
+0xA1D7	0x223D	
+0xA1D8	0x221D	
+0xA1D9	0x2260	
+0xA1DA	0x226E	
+0xA1DB	0x226F	
+0xA1DC	0x2264	
+0xA1DD	0x2265	
+0xA1DE	0x221E	
+0xA1DF	0x2235	
+0xA1E0	0x2234	
+0xA1E1	0x2642	
+0xA1E2	0x2640	
+0xA1E3	0x00B0	
+0xA1E4	0x2032	
+0xA1E5	0x2033	
+0xA1E6	0x2103	
+0xA1E7	0xFF04	
+0xA1E8	0x00A4	
+0xA1E9	0xFFE0	
+0xA1EA	0xFFE1	
+0xA1EB	0x2030	
+0xA1EC	0x00A7	
+0xA1ED	0x2116	
+0xA1EE	0x2606	
+0xA1EF	0x2605	
+0xA1F0	0x25CB	
+0xA1F1	0x25CF	
+0xA1F2	0x25CE	
+0xA1F3	0x25C7	
+0xA1F4	0x25C6	
+0xA1F5	0x25A1	
+0xA1F6	0x25A0	
+0xA1F7	0x25B3	
+0xA1F8	0x25B2	
+0xA1F9	0x203B	
+0xA1FA	0x2192	
+0xA1FB	0x2190	
+0xA1FC	0x2191	
+0xA1FD	0x2193	
+0xA1FE	0x3013	
+# 0xA240	 	
+# 0xA241	 	
+# 0xA242	 	
+# 0xA243	 	
+# 0xA244	 	
+# 0xA245	 	
+# 0xA246	 	
+# 0xA247	 	
+# 0xA248	 	
+# 0xA249	 	
+# 0xA24A	 	
+# 0xA24B	 	
+# 0xA24C	 	
+# 0xA24D	 	
+# 0xA24E	 	
+# 0xA24F	 	
+# 0xA250	 	
+# 0xA251	 	
+# 0xA252	 	
+# 0xA253	 	
+# 0xA254	 	
+# 0xA255	 	
+# 0xA256	 	
+# 0xA257	 	
+# 0xA258	 	
+# 0xA259	 	
+# 0xA25A	 	
+# 0xA25B	 	
+# 0xA25C	 	
+# 0xA25D	 	
+# 0xA25E	 	
+# 0xA25F	 	
+# 0xA260	 	
+# 0xA261	 	
+# 0xA262	 	
+# 0xA263	 	
+# 0xA264	 	
+# 0xA265	 	
+# 0xA266	 	
+# 0xA267	 	
+# 0xA268	 	
+# 0xA269	 	
+# 0xA26A	 	
+# 0xA26B	 	
+# 0xA26C	 	
+# 0xA26D	 	
+# 0xA26E	 	
+# 0xA26F	 	
+# 0xA270	 	
+# 0xA271	 	
+# 0xA272	 	
+# 0xA273	 	
+# 0xA274	 	
+# 0xA275	 	
+# 0xA276	 	
+# 0xA277	 	
+# 0xA278	 	
+# 0xA279	 	
+# 0xA27A	 	
+# 0xA27B	 	
+# 0xA27C	 	
+# 0xA27D	 	
+# 0xA27E	 	
+# 0xA280	 	
+# 0xA281	 	
+# 0xA282	 	
+# 0xA283	 	
+# 0xA284	 	
+# 0xA285	 	
+# 0xA286	 	
+# 0xA287	 	
+# 0xA288	 	
+# 0xA289	 	
+# 0xA28A	 	
+# 0xA28B	 	
+# 0xA28C	 	
+# 0xA28D	 	
+# 0xA28E	 	
+# 0xA28F	 	
+# 0xA290	 	
+# 0xA291	 	
+# 0xA292	 	
+# 0xA293	 	
+# 0xA294	 	
+# 0xA295	 	
+# 0xA296	 	
+# 0xA297	 	
+# 0xA298	 	
+# 0xA299	 	
+# 0xA29A	 	
+# 0xA29B	 	
+# 0xA29C	 	
+# 0xA29D	 	
+# 0xA29E	 	
+# 0xA29F	 	
+# 0xA2A0	 	
+0xA2A1	0x2170	
+0xA2A2	0x2171	
+0xA2A3	0x2172	
+0xA2A4	0x2173	
+0xA2A5	0x2174	
+0xA2A6	0x2175	
+0xA2A7	0x2176	
+0xA2A8	0x2177	
+0xA2A9	0x2178	
+0xA2AA	0x2179	
+0xA2AB	0xE586	
+0xA2AC	0xE587	
+0xA2AD	0xE588	
+0xA2AE	0xE589	
+0xA2AF	0xE58A	
+0xA2B0	0xE58B	
+0xA2B1	0x2488	
+0xA2B2	0x2489	
+0xA2B3	0x248A	
+0xA2B4	0x248B	
+0xA2B5	0x248C	
+0xA2B6	0x248D	
+0xA2B7	0x248E	
+0xA2B8	0x248F	
+0xA2B9	0x2490	
+0xA2BA	0x2491	
+0xA2BB	0x2492	
+0xA2BC	0x2493	
+0xA2BD	0x2494	
+0xA2BE	0x2495	
+0xA2BF	0x2496	
+0xA2C0	0x2497	
+0xA2C1	0x2498	
+0xA2C2	0x2499	
+0xA2C3	0x249A	
+0xA2C4	0x249B	
+0xA2C5	0x2474	
+0xA2C6	0x2475	
+0xA2C7	0x2476	
+0xA2C8	0x2477	
+0xA2C9	0x2478	
+0xA2CA	0x2479	
+0xA2CB	0x247A	
+0xA2CC	0x247B	
+0xA2CD	0x247C	
+0xA2CE	0x247D	
+0xA2CF	0x247E	
+0xA2D0	0x247F	
+0xA2D1	0x2480	
+0xA2D2	0x2481	
+0xA2D3	0x2482	
+0xA2D4	0x2483	
+0xA2D5	0x2484	
+0xA2D6	0x2485	
+0xA2D7	0x2486	
+0xA2D8	0x2487	
+0xA2D9	0x2460	
+0xA2DA	0x2461	
+0xA2DB	0x2462	
+0xA2DC	0x2463	
+0xA2DD	0x2464	
+0xA2DE	0x2465	
+0xA2DF	0x2466	
+0xA2E0	0x2467	
+0xA2E1	0x2468	
+0xA2E2	0x2469	
+0xA2E3	0xE58C	
+0xA2E4	0xE58D	
+0xA2E5	0x3220	
+0xA2E6	0x3221	
+0xA2E7	0x3222	
+0xA2E8	0x3223	
+0xA2E9	0x3224	
+0xA2EA	0x3225	
+0xA2EB	0x3226	
+0xA2EC	0x3227	
+0xA2ED	0x3228	
+0xA2EE	0x3229	
+0xA2EF	0xE58E	
+0xA2F0	0xE58F	
+0xA2F1	0x2160	
+0xA2F2	0x2161	
+0xA2F3	0x2162	
+0xA2F4	0x2163	
+0xA2F5	0x2164	
+0xA2F6	0x2165	
+0xA2F7	0x2166	
+0xA2F8	0x2167	
+0xA2F9	0x2168	
+0xA2FA	0x2169	
+0xA2FB	0x216A	
+0xA2FC	0x216B	
+0xA2FD	0xE590	
+0xA2FE	0xE591	
+# 0xA340	 	
+# 0xA341	 	
+# 0xA342	 	
+# 0xA343	 	
+# 0xA344	 	
+# 0xA345	 	
+# 0xA346	 	
+# 0xA347	 	
+# 0xA348	 	
+# 0xA349	 	
+# 0xA34A	 	
+# 0xA34B	 	
+# 0xA34C	 	
+# 0xA34D	 	
+# 0xA34E	 	
+# 0xA34F	 	
+# 0xA350	 	
+# 0xA351	 	
+# 0xA352	 	
+# 0xA353	 	
+# 0xA354	 	
+# 0xA355	 	
+# 0xA356	 	
+# 0xA357	 	
+# 0xA358	 	
+# 0xA359	 	
+# 0xA35A	 	
+# 0xA35B	 	
+# 0xA35C	 	
+# 0xA35D	 	
+# 0xA35E	 	
+# 0xA35F	 	
+# 0xA360	 	
+# 0xA361	 	
+# 0xA362	 	
+# 0xA363	 	
+# 0xA364	 	
+# 0xA365	 	
+# 0xA366	 	
+# 0xA367	 	
+# 0xA368	 	
+# 0xA369	 	
+# 0xA36A	 	
+# 0xA36B	 	
+# 0xA36C	 	
+# 0xA36D	 	
+# 0xA36E	 	
+# 0xA36F	 	
+# 0xA370	 	
+# 0xA371	 	
+# 0xA372	 	
+# 0xA373	 	
+# 0xA374	 	
+# 0xA375	 	
+# 0xA376	 	
+# 0xA377	 	
+# 0xA378	 	
+# 0xA379	 	
+# 0xA37A	 	
+# 0xA37B	 	
+# 0xA37C	 	
+# 0xA37D	 	
+# 0xA37E	 	
+# 0xA380	 	
+# 0xA381	 	
+# 0xA382	 	
+# 0xA383	 	
+# 0xA384	 	
+# 0xA385	 	
+# 0xA386	 	
+# 0xA387	 	
+# 0xA388	 	
+# 0xA389	 	
+# 0xA38A	 	
+# 0xA38B	 	
+# 0xA38C	 	
+# 0xA38D	 	
+# 0xA38E	 	
+# 0xA38F	 	
+# 0xA390	 	
+# 0xA391	 	
+# 0xA392	 	
+# 0xA393	 	
+# 0xA394	 	
+# 0xA395	 	
+# 0xA396	 	
+# 0xA397	 	
+# 0xA398	 	
+# 0xA399	 	
+# 0xA39A	 	
+# 0xA39B	 	
+# 0xA39C	 	
+# 0xA39D	 	
+# 0xA39E	 	
+# 0xA39F	 	
+# 0xA3A0	 	
+0xA3A1	0xFF01	
+0xA3A2	0xFF02	
+0xA3A3	0xFF03	
+0xA3A4	0xFFE5	
+0xA3A5	0xFF05	
+0xA3A6	0xFF06	
+0xA3A7	0xFF07	
+0xA3A8	0xFF08	
+0xA3A9	0xFF09	
+0xA3AA	0xFF0A	
+0xA3AB	0xFF0B	
+0xA3AC	0xFF0C	
+0xA3AD	0xFF0D	
+0xA3AE	0xFF0E	
+0xA3AF	0xFF0F	
+0xA3B0	0xFF10	
+0xA3B1	0xFF11	
+0xA3B2	0xFF12	
+0xA3B3	0xFF13	
+0xA3B4	0xFF14	
+0xA3B5	0xFF15	
+0xA3B6	0xFF16	
+0xA3B7	0xFF17	
+0xA3B8	0xFF18	
+0xA3B9	0xFF19	
+0xA3BA	0xFF1A	
+0xA3BB	0xFF1B	
+0xA3BC	0xFF1C	
+0xA3BD	0xFF1D	
+0xA3BE	0xFF1E	
+0xA3BF	0xFF1F	
+0xA3C0	0xFF20	
+0xA3C1	0xFF21	
+0xA3C2	0xFF22	
+0xA3C3	0xFF23	
+0xA3C4	0xFF24	
+0xA3C5	0xFF25	
+0xA3C6	0xFF26	
+0xA3C7	0xFF27	
+0xA3C8	0xFF28	
+0xA3C9	0xFF29	
+0xA3CA	0xFF2A	
+0xA3CB	0xFF2B	
+0xA3CC	0xFF2C	
+0xA3CD	0xFF2D	
+0xA3CE	0xFF2E	
+0xA3CF	0xFF2F	
+0xA3D0	0xFF30	
+0xA3D1	0xFF31	
+0xA3D2	0xFF32	
+0xA3D3	0xFF33	
+0xA3D4	0xFF34	
+0xA3D5	0xFF35	
+0xA3D6	0xFF36	
+0xA3D7	0xFF37	
+0xA3D8	0xFF38	
+0xA3D9	0xFF39	
+0xA3DA	0xFF3A	
+0xA3DB	0xFF3B	
+0xA3DC	0xFF3C	
+0xA3DD	0xFF3D	
+0xA3DE	0xFF3E	
+0xA3DF	0xFF3F	
+0xA3E0	0xFF40	
+0xA3E1	0xFF41	
+0xA3E2	0xFF42	
+0xA3E3	0xFF43	
+0xA3E4	0xFF44	
+0xA3E5	0xFF45	
+0xA3E6	0xFF46	
+0xA3E7	0xFF47	
+0xA3E8	0xFF48	
+0xA3E9	0xFF49	
+0xA3EA	0xFF4A	
+0xA3EB	0xFF4B	
+0xA3EC	0xFF4C	
+0xA3ED	0xFF4D	
+0xA3EE	0xFF4E	
+0xA3EF	0xFF4F	
+0xA3F0	0xFF50	
+0xA3F1	0xFF51	
+0xA3F2	0xFF52	
+0xA3F3	0xFF53	
+0xA3F4	0xFF54	
+0xA3F5	0xFF55	
+0xA3F6	0xFF56	
+0xA3F7	0xFF57	
+0xA3F8	0xFF58	
+0xA3F9	0xFF59	
+0xA3FA	0xFF5A	
+0xA3FB	0xFF5B	
+0xA3FC	0xFF5C	
+0xA3FD	0xFF5D	
+0xA3FE	0xFFE3	
+# 0xA440	 	
+# 0xA441	 	
+# 0xA442	 	
+# 0xA443	 	
+# 0xA444	 	
+# 0xA445	 	
+# 0xA446	 	
+# 0xA447	 	
+# 0xA448	 	
+# 0xA449	 	
+# 0xA44A	 	
+# 0xA44B	 	
+# 0xA44C	 	
+# 0xA44D	 	
+# 0xA44E	 	
+# 0xA44F	 	
+# 0xA450	 	
+# 0xA451	 	
+# 0xA452	 	
+# 0xA453	 	
+# 0xA454	 	
+# 0xA455	 	
+# 0xA456	 	
+# 0xA457	 	
+# 0xA458	 	
+# 0xA459	 	
+# 0xA45A	 	
+# 0xA45B	 	
+# 0xA45C	 	
+# 0xA45D	 	
+# 0xA45E	 	
+# 0xA45F	 	
+# 0xA460	 	
+# 0xA461	 	
+# 0xA462	 	
+# 0xA463	 	
+# 0xA464	 	
+# 0xA465	 	
+# 0xA466	 	
+# 0xA467	 	
+# 0xA468	 	
+# 0xA469	 	
+# 0xA46A	 	
+# 0xA46B	 	
+# 0xA46C	 	
+# 0xA46D	 	
+# 0xA46E	 	
+# 0xA46F	 	
+# 0xA470	 	
+# 0xA471	 	
+# 0xA472	 	
+# 0xA473	 	
+# 0xA474	 	
+# 0xA475	 	
+# 0xA476	 	
+# 0xA477	 	
+# 0xA478	 	
+# 0xA479	 	
+# 0xA47A	 	
+# 0xA47B	 	
+# 0xA47C	 	
+# 0xA47D	 	
+# 0xA47E	 	
+# 0xA480	 	
+# 0xA481	 	
+# 0xA482	 	
+# 0xA483	 	
+# 0xA484	 	
+# 0xA485	 	
+# 0xA486	 	
+# 0xA487	 	
+# 0xA488	 	
+# 0xA489	 	
+# 0xA48A	 	
+# 0xA48B	 	
+# 0xA48C	 	
+# 0xA48D	 	
+# 0xA48E	 	
+# 0xA48F	 	
+# 0xA490	 	
+# 0xA491	 	
+# 0xA492	 	
+# 0xA493	 	
+# 0xA494	 	
+# 0xA495	 	
+# 0xA496	 	
+# 0xA497	 	
+# 0xA498	 	
+# 0xA499	 	
+# 0xA49A	 	
+# 0xA49B	 	
+# 0xA49C	 	
+# 0xA49D	 	
+# 0xA49E	 	
+# 0xA49F	 	
+# 0xA4A0	 	
+0xA4A1	0x3041	
+0xA4A2	0x3042	
+0xA4A3	0x3043	
+0xA4A4	0x3044	
+0xA4A5	0x3045	
+0xA4A6	0x3046	
+0xA4A7	0x3047	
+0xA4A8	0x3048	
+0xA4A9	0x3049	
+0xA4AA	0x304A	
+0xA4AB	0x304B	
+0xA4AC	0x304C	
+0xA4AD	0x304D	
+0xA4AE	0x304E	
+0xA4AF	0x304F	
+0xA4B0	0x3050	
+0xA4B1	0x3051	
+0xA4B2	0x3052	
+0xA4B3	0x3053	
+0xA4B4	0x3054	
+0xA4B5	0x3055	
+0xA4B6	0x3056	
+0xA4B7	0x3057	
+0xA4B8	0x3058	
+0xA4B9	0x3059	
+0xA4BA	0x305A	
+0xA4BB	0x305B	
+0xA4BC	0x305C	
+0xA4BD	0x305D	
+0xA4BE	0x305E	
+0xA4BF	0x305F	
+0xA4C0	0x3060	
+0xA4C1	0x3061	
+0xA4C2	0x3062	
+0xA4C3	0x3063	
+0xA4C4	0x3064	
+0xA4C5	0x3065	
+0xA4C6	0x3066	
+0xA4C7	0x3067	
+0xA4C8	0x3068	
+0xA4C9	0x3069	
+0xA4CA	0x306A	
+0xA4CB	0x306B	
+0xA4CC	0x306C	
+0xA4CD	0x306D	
+0xA4CE	0x306E	
+0xA4CF	0x306F	
+0xA4D0	0x3070	
+0xA4D1	0x3071	
+0xA4D2	0x3072	
+0xA4D3	0x3073	
+0xA4D4	0x3074	
+0xA4D5	0x3075	
+0xA4D6	0x3076	
+0xA4D7	0x3077	
+0xA4D8	0x3078	
+0xA4D9	0x3079	
+0xA4DA	0x307A	
+0xA4DB	0x307B	
+0xA4DC	0x307C	
+0xA4DD	0x307D	
+0xA4DE	0x307E	
+0xA4DF	0x307F	
+0xA4E0	0x3080	
+0xA4E1	0x3081	
+0xA4E2	0x3082	
+0xA4E3	0x3083	
+0xA4E4	0x3084	
+0xA4E5	0x3085	
+0xA4E6	0x3086	
+0xA4E7	0x3087	
+0xA4E8	0x3088	
+0xA4E9	0x3089	
+0xA4EA	0x308A	
+0xA4EB	0x308B	
+0xA4EC	0x308C	
+0xA4ED	0x308D	
+0xA4EE	0x308E	
+0xA4EF	0x308F	
+0xA4F0	0x3090	
+0xA4F1	0x3091	
+0xA4F2	0x3092
+0xA4F3	0x3093	
+0xA4F4	0xE652	
+0xA4F5	0xE653	
+0xA4F6	0xE654	
+0xA4F7	0xE655	
+0xA4F8	0xE656	
+0xA4F9	0xE657	
+0xA4FA	0xE658	
+0xA4FB	0xE659	
+0xA4FC	0xE65A	
+0xA4FD	0xE65B	
+0xA4FE	0xE65C	
+# 0xA540	 	
+# 0xA541	 	
+# 0xA542	 	
+# 0xA543	 	
+# 0xA544	 	
+# 0xA545	 	
+# 0xA546	 	
+# 0xA547	 	
+# 0xA548	 	
+# 0xA549	 	
+# 0xA54A	 	
+# 0xA54B	 	
+# 0xA54C	 	
+# 0xA54D	 	
+# 0xA54E	 	
+# 0xA54F	 	
+# 0xA550	 	
+# 0xA551	 	
+# 0xA552	 	
+# 0xA553	 	
+# 0xA554	 	
+# 0xA555	 	
+# 0xA556	 	
+# 0xA557	 	
+# 0xA558	 	
+# 0xA559	 	
+# 0xA55A	 	
+# 0xA55B	 	
+# 0xA55C	 	
+# 0xA55D	 	
+# 0xA55E	 	
+# 0xA55F	 	
+# 0xA560	 	
+# 0xA561	 	
+# 0xA562	 	
+# 0xA563	 	
+# 0xA564	 	
+# 0xA565	 	
+# 0xA566	 	
+# 0xA567	 	
+# 0xA568	 	
+# 0xA569	 	
+# 0xA56A	 	
+# 0xA56B	 	
+# 0xA56C	 	
+# 0xA56D	 	
+# 0xA56E	 	
+# 0xA56F	 	
+# 0xA570	 	
+# 0xA571	 	
+# 0xA572	 	
+# 0xA573	 	
+# 0xA574	 	
+# 0xA575	 	
+# 0xA576	 	
+# 0xA577	 	
+# 0xA578	 	
+# 0xA579	 	
+# 0xA57A	 	
+# 0xA57B	 	
+# 0xA57C	 	
+# 0xA57D	 	
+# 0xA57E	 	
+# 0xA580	 	
+# 0xA581	 	
+# 0xA582	 	
+# 0xA583	 	
+# 0xA584	 	
+# 0xA585	 	
+# 0xA586	 	
+# 0xA587	 	
+# 0xA588	 	
+# 0xA589	 	
+# 0xA58A	 	
+# 0xA58B	 	
+# 0xA58C	 	
+# 0xA58D	 	
+# 0xA58E	 	
+# 0xA58F	 	
+# 0xA590	 	
+# 0xA591	 	
+# 0xA592	 	
+# 0xA593	 	
+# 0xA594	 	
+# 0xA595	 	
+# 0xA596	 	
+# 0xA597	 	
+# 0xA598	 	
+# 0xA599	 	
+# 0xA59A	 	
+# 0xA59B	 	
+# 0xA59C	 	
+# 0xA59D	 	
+# 0xA59E	 	
+# 0xA59F	 	
+# 0xA5A0	 	
+0xA5A1	0x30A1	
+0xA5A2	0x30A2	
+0xA5A3	0x30A3	
+0xA5A4	0x30A4	
+0xA5A5	0x30A5	
+0xA5A6	0x30A6	
+0xA5A7	0x30A7	
+0xA5A8	0x30A8	
+0xA5A9	0x30A9	
+0xA5AA	0x30AA	
+0xA5AB	0x30AB	
+0xA5AC	0x30AC	
+0xA5AD	0x30AD	
+0xA5AE	0x30AE	
+0xA5AF	0x30AF	
+0xA5B0	0x30B0	
+0xA5B1	0x30B1	
+0xA5B2	0x30B2	
+0xA5B3	0x30B3	
+0xA5B4	0x30B4	
+0xA5B5	0x30B5	
+0xA5B6	0x30B6	
+0xA5B7	0x30B7	
+0xA5B8	0x30B8	
+0xA5B9	0x30B9	
+0xA5BA	0x30BA	
+0xA5BB	0x30BB	
+0xA5BC	0x30BC	
+0xA5BD	0x30BD	
+0xA5BE	0x30BE	
+0xA5BF	0x30BF	
+0xA5C0	0x30C0	
+0xA5C1	0x30C1	
+0xA5C2	0x30C2	
+0xA5C3	0x30C3	
+0xA5C4	0x30C4	
+0xA5C5	0x30C5	
+0xA5C6	0x30C6	
+0xA5C7	0x30C7	
+0xA5C8	0x30C8	
+0xA5C9	0x30C9	
+0xA5CA	0x30CA	
+0xA5CB	0x30CB	
+0xA5CC	0x30CC	
+0xA5CD	0x30CD	
+0xA5CE	0x30CE	
+0xA5CF	0x30CF	
+0xA5D0	0x30D0	
+0xA5D1	0x30D1	
+0xA5D2	0x30D2	
+0xA5D3	0x30D3	
+0xA5D4	0x30D4	
+0xA5D5	0x30D5	
+0xA5D6	0x30D6	
+0xA5D7	0x30D7	
+0xA5D8	0x30D8	
+0xA5D9	0x30D9	
+0xA5DA	0x30DA	
+0xA5DB	0x30DB	
+0xA5DC	0x30DC	
+0xA5DD	0x30DD	
+0xA5DE	0x30DE	
+0xA5DF	0x30DF	
+0xA5E0	0x30E0	
+0xA5E1	0x30E1	
+0xA5E2	0x30E2	
+0xA5E3	0x30E3	
+0xA5E4	0x30E4	
+0xA5E5	0x30E5	
+0xA5E6	0x30E6	
+0xA5E7	0x30E7	
+0xA5E8	0x30E8	
+0xA5E9	0x30E9	
+0xA5EA	0x30EA	
+0xA5EB	0x30EB	
+0xA5EC	0x30EC	
+0xA5ED	0x30ED	
+0xA5EE	0x30EE	
+0xA5EF	0x30EF	
+0xA5F0	0x30F0	
+0xA5F1	0x30F1	
+0xA5F2	0x30F2	
+0xA5F3	0x30F3	
+0xA5F4	0x30F4	
+0xA5F5	0x30F5	
+0xA5F6	0x30F6	
+0xA5F7	0xE6BD	
+0xA5F8	0xE6BE	
+0xA5F9	0xE6BF	
+0xA5FA	0xE6C0	
+0xA5FB	0xE6C1	
+0xA5FC	0xE6C2	
+0xA5FD	0xE6C3	
+0xA5FE	0xE6C4	
+# 0xA640	 	
+# 0xA641	 	
+# 0xA642	 	
+# 0xA643	 	
+# 0xA644	 	
+# 0xA645	 	
+# 0xA646	 	
+# 0xA647	 	
+# 0xA648	 	
+# 0xA649	 	
+# 0xA64A	 	
+# 0xA64B	 	
+# 0xA64C	 	
+# 0xA64D	 	
+# 0xA64E	 	
+# 0xA64F	 	
+# 0xA650	 	
+# 0xA651	 	
+# 0xA652	 	
+# 0xA653	 	
+# 0xA654	 	
+# 0xA655	 	
+# 0xA656	 	
+# 0xA657	 	
+# 0xA658	 	
+# 0xA659	 	
+# 0xA65A	 	
+# 0xA65B	 	
+# 0xA65C	 	
+# 0xA65D	 	
+# 0xA65E	 	
+# 0xA65F	 	
+# 0xA660	 	
+# 0xA661	 	
+# 0xA662	 	
+# 0xA663	 	
+# 0xA664	 	
+# 0xA665	 	
+# 0xA666	 	
+# 0xA667	 	
+# 0xA668	 	
+# 0xA669	 	
+# 0xA66A	 	
+# 0xA66B	 	
+# 0xA66C	 	
+# 0xA66D	 	
+# 0xA66E	 	
+# 0xA66F	 	
+# 0xA670	 	
+# 0xA671	 	
+# 0xA672	 	
+# 0xA673	 	
+# 0xA674	 	
+# 0xA675	 	
+# 0xA676	 	
+# 0xA677	 	
+# 0xA678	 	
+# 0xA679	 	
+# 0xA67A	 	
+# 0xA67B	 	
+# 0xA67C	 	
+# 0xA67D	 	
+# 0xA67E	 	
+# 0xA680	 	
+# 0xA681	 	
+# 0xA682	 	
+# 0xA683	 	
+# 0xA684	 	
+# 0xA685	 	
+# 0xA686	 	
+# 0xA687	 	
+# 0xA688	 	
+# 0xA689	 	
+# 0xA68A	 	
+# 0xA68B	 	
+# 0xA68C	 	
+# 0xA68D	 	
+# 0xA68E	 	
+# 0xA68F	 	
+# 0xA690	 	
+# 0xA691	 	
+# 0xA692	 	
+# 0xA693	 	
+# 0xA694	 	
+# 0xA695	 	
+# 0xA696	 	
+# 0xA697	 	
+# 0xA698	 	
+# 0xA699	 	
+# 0xA69A	 	
+# 0xA69B	 	
+# 0xA69C	 	
+# 0xA69D	 	
+# 0xA69E	 	
+# 0xA69F	 	
+# 0xA6A0	 	
+0xA6A1	0x0391	
+0xA6A2	0x0392	
+0xA6A3	0x0393	
+0xA6A4	0x0394	
+0xA6A5	0x0395	
+0xA6A6	0x0396	
+0xA6A7	0x0397	
+0xA6A8	0x0398	
+0xA6A9	0x0399	
+0xA6AA	0x039A	
+0xA6AB	0x039B	
+0xA6AC	0x039C	
+0xA6AD	0x039D	
+0xA6AE	0x039E	
+0xA6AF	0x039F	
+0xA6B0	0x03A0	
+0xA6B1	0x03A1	
+0xA6B2	0x03A3	
+0xA6B3	0x03A4	
+0xA6B4	0x03A5	
+0xA6B5	0x03A6	
+0xA6B6	0x03A7	
+0xA6B7	0x03A8	
+0xA6B8	0x03A9	
+0xA6B9	0xE725	
+0xA6BA	0xE726	
+0xA6BB	0xE727	
+0xA6BC	0xE728	
+0xA6BD	0xE729	
+0xA6BE	0xE72A	
+0xA6BF	0xE72B	
+0xA6C0	0xE72C	
+0xA6C1	0x03B1	
+0xA6C2	0x03B2	
+0xA6C3	0x03B3	
+0xA6C4	0x03B4	
+0xA6C5	0x03B5	
+0xA6C6	0x03B6	
+0xA6C7	0x03B7	
+0xA6C8	0x03B8	
+0xA6C9	0x03B9	
+0xA6CA	0x03BA	
+0xA6CB	0x03BB	
+0xA6CC	0x03BC	
+0xA6CD	0x03BD	
+0xA6CE	0x03BE	
+0xA6CF	0x03BF	
+0xA6D0	0x03C0	
+0xA6D1	0x03C1	
+0xA6D2	0x03C3	
+0xA6D3	0x03C4	
+0xA6D4	0x03C5	
+0xA6D5	0x03C6	
+0xA6D6	0x03C7	
+0xA6D7	0x03C8	
+0xA6D8	0x03C9	
+0xA6D9	0xE72D	
+0xA6DA	0xE72E	
+0xA6DB	0xE72F	
+0xA6DC	0xE730	
+0xA6DD	0xE731	
+0xA6DE	0xE732	
+0xA6DF	0xE733	
+0xA6E0	0xFE35	
+0xA6E1	0xFE36	
+0xA6E2	0xFE39	
+0xA6E3	0xFE3A	
+0xA6E4	0xFE3F	
+0xA6E5	0xFE40	
+0xA6E6	0xFE3D	
+0xA6E7	0xFE3E	
+0xA6E8	0xFE41	
+0xA6E9	0xFE42	
+0xA6EA	0xFE43	
+0xA6EB	0xFE44	
+0xA6EC	0xE734	
+0xA6ED	0xE735	
+0xA6EE	0xFE3B	
+0xA6EF	0xFE3C	
+0xA6F0	0xFE37	
+0xA6F1	0xFE38	
+0xA6F2	0xFE31	
+0xA6F3	0xE736	
+0xA6F4	0xFE33	
+0xA6F5	0xFE34	
+0xA6F6	0xE737	
+0xA6F7	0xE738	
+0xA6F8	0xE739	
+0xA6F9	0xE73A	
+0xA6FA	0xE73B	
+0xA6FB	0xE73C	
+0xA6FC	0xE73D	
+0xA6FD	0xE73E	
+0xA6FE	0xE73F	
+# 0xA740	 	
+# 0xA741	 	
+# 0xA742	 	
+# 0xA743	 	
+# 0xA744	 	
+# 0xA745	 	
+# 0xA746	 	
+# 0xA747	 	
+# 0xA748	 	
+# 0xA749	 	
+# 0xA74A	 	
+# 0xA74B	 	
+# 0xA74C	 	
+# 0xA74D	 	
+# 0xA74E	 	
+# 0xA74F	 	
+# 0xA750	 	
+# 0xA751	 	
+# 0xA752	 	
+# 0xA753	 	
+# 0xA754	 	
+# 0xA755	 	
+# 0xA756	 	
+# 0xA757	 	
+# 0xA758	 	
+# 0xA759	 	
+# 0xA75A	 	
+# 0xA75B	 	
+# 0xA75C	 	
+# 0xA75D	 	
+# 0xA75E	 	
+# 0xA75F	 	
+# 0xA760	 	
+# 0xA761	 	
+# 0xA762	 	
+# 0xA763	 	
+# 0xA764	 	
+# 0xA765	 	
+# 0xA766	 	
+# 0xA767	 	
+# 0xA768	 	
+# 0xA769	 	
+# 0xA76A	 	
+# 0xA76B	 	
+# 0xA76C	 	
+# 0xA76D	 	
+# 0xA76E	 	
+# 0xA76F	 	
+# 0xA770	 	
+# 0xA771	 	
+# 0xA772	 	
+# 0xA773	 	
+# 0xA774	 	
+# 0xA775	 	
+# 0xA776	 	
+# 0xA777	 	
+# 0xA778	 	
+# 0xA779	 	
+# 0xA77A	 	
+# 0xA77B	 	
+# 0xA77C	 	
+# 0xA77D	 	
+# 0xA77E	 	
+# 0xA780	 	
+# 0xA781	 	
+# 0xA782	 	
+# 0xA783	 	
+# 0xA784	 	
+# 0xA785	 	
+# 0xA786	 	
+# 0xA787	 	
+# 0xA788	 	
+# 0xA789	 	
+# 0xA78A	 	
+# 0xA78B	 	
+# 0xA78C	 	
+# 0xA78D	 	
+# 0xA78E	 	
+# 0xA78F	 	
+# 0xA790	 	
+# 0xA791	 	
+# 0xA792	 	
+# 0xA793	 	
+# 0xA794	 	
+# 0xA795	 	
+# 0xA796	 	
+# 0xA797	 	
+# 0xA798	 	
+# 0xA799	 	
+# 0xA79A	 	
+# 0xA79B	 	
+# 0xA79C	 	
+# 0xA79D	 	
+# 0xA79E	 	
+# 0xA79F	 	
+# 0xA7A0	 	
+0xA7A1	0x0410	
+0xA7A2	0x0411	
+0xA7A3	0x0412	
+0xA7A4	0x0413	
+0xA7A5	0x0414	
+0xA7A6	0x0415	
+0xA7A7	0x0401	
+0xA7A8	0x0416	
+0xA7A9	0x0417	
+0xA7AA	0x0418	
+0xA7AB	0x0419	
+0xA7AC	0x041A	
+0xA7AD	0x041B	
+0xA7AE	0x041C	
+0xA7AF	0x041D	
+0xA7B0	0x041E	
+0xA7B1	0x041F	
+0xA7B2	0x0420	
+0xA7B3	0x0421	
+0xA7B4	0x0422	
+0xA7B5	0x0423	
+0xA7B6	0x0424	
+0xA7B7	0x0425	
+0xA7B8	0x0426	
+0xA7B9	0x0427	
+0xA7BA	0x0428	
+0xA7BB	0x0429	
+0xA7BC	0x042A	
+0xA7BD	0x042B	
+0xA7BE	0x042C	
+0xA7BF	0x042D	
+0xA7C0	0x042E	
+0xA7C1	0x042F	
+0xA7C2	0xE7A0	
+0xA7C3	0xE7A1	
+0xA7C4	0xE7A2	
+0xA7C5	0xE7A3	
+0xA7C6	0xE7A4	
+0xA7C7	0xE7A5	
+0xA7C8	0xE7A6	
+0xA7C9	0xE7A7	
+0xA7CA	0xE7A8	
+0xA7CB	0xE7A9	
+0xA7CC	0xE7AA	
+0xA7CD	0xE7AB	
+0xA7CE	0xE7AC	
+0xA7CF	0xE7AD	
+0xA7D0	0xE7AE	
+0xA7D1	0x0430	
+0xA7D2	0x0431	
+0xA7D3	0x0432	
+0xA7D4	0x0433	
+0xA7D5	0x0434	
+0xA7D6	0x0435	
+0xA7D7	0x0451	
+0xA7D8	0x0436	
+0xA7D9	0x0437	
+0xA7DA	0x0438	
+0xA7DB	0x0439	
+0xA7DC	0x043A	
+0xA7DD	0x043B	
+0xA7DE	0x043C	
+0xA7DF	0x043D	
+0xA7E0	0x043E	
+0xA7E1	0x043F	
+0xA7E2	0x0440	
+0xA7E3	0x0441	
+0xA7E4	0x0442	
+0xA7E5	0x0443	
+0xA7E6	0x0444	
+0xA7E7	0x0445	
+0xA7E8	0x0446	
+0xA7E9	0x0447	
+0xA7EA	0x0448	
+0xA7EB	0x0449	
+0xA7EC	0x044A	
+0xA7ED	0x044B	
+0xA7EE	0x044C	
+0xA7EF	0x044D	
+0xA7F0	0x044E	
+0xA7F1	0x044F	
+0xA7F2	0xE7AF	
+0xA7F3	0xE7B0	
+0xA7F4	0xE7B1	
+0xA7F5	0xE7B2	
+0xA7F6	0xE7B3	
+0xA7F7	0xE7B4	
+0xA7F8	0xE7B5	
+0xA7F9	0xE7B6	
+0xA7FA	0xE7B7	
+0xA7FB	0xE7B8	
+0xA7FC	0xE7B9	
+0xA7FD	0xE7BA	
+0xA7FE	0xE7BB	
+0xA840	0x02CA	
+0xA841	0x02CB	
+0xA842	0x02D9	
+0xA843	0x2013	
+0xA844	0x2015	
+0xA845	0x2025	
+0xA846	0x2035	
+0xA847	0x2105	
+0xA848	0x2109	
+0xA849	0x2196	
+0xA84A	0x2197	
+0xA84B	0x2198	
+0xA84C	0x2199	
+0xA84D	0x2215	
+0xA84E	0x221F	
+0xA84F	0x2223	
+0xA850	0x2252	
+0xA851	0x2266	
+0xA852	0x2267	
+0xA853	0x22BF	
+0xA854	0x2550	
+0xA855	0x2551	
+0xA856	0x2552	
+0xA857	0x2553	
+0xA858	0x2554	
+0xA859	0x2555	
+0xA85A	0x2556	
+0xA85B	0x2557	
+0xA85C	0x2558	
+0xA85D	0x2559	
+0xA85E	0x255A	
+0xA85F	0x255B	
+0xA860	0x255C	
+0xA861	0x255D	
+0xA862	0x255E	
+0xA863	0x255F	
+0xA864	0x2560	
+0xA865	0x2561	
+0xA866	0x2562	
+0xA867	0x2563	
+0xA868	0x2564	
+0xA869	0x2565	
+0xA86A	0x2566	
+0xA86B	0x2567	
+0xA86C	0x2568	
+0xA86D	0x2569	
+0xA86E	0x256A	
+0xA86F	0x256B	
+0xA870	0x256C	
+0xA871	0x256D	
+0xA872	0x256E	
+0xA873	0x256F	
+0xA874	0x2570	
+0xA875	0x2571	
+0xA876	0x2572	
+0xA877	0x2573	
+0xA878	0x2581	
+0xA879	0x2582	
+0xA87A	0x2583	
+0xA87B	0x2584	
+0xA87C	0x2585	
+0xA87D	0x2586	
+0xA87E	0x2587	
+0xA880	0x2588	
+0xA881	0x2589	
+0xA882	0x258A	
+0xA883	0x258B	
+0xA884	0x258C	
+0xA885	0x258D	
+0xA886	0x258E	
+0xA887	0x258F	
+0xA888	0x2593	
+0xA889	0x2594	
+0xA88A	0x2595	
+0xA88B	0x25BC	
+0xA88C	0x25BD	
+0xA88D	0x25E2	
+0xA88E	0x25E3	
+0xA88F	0x25E4	
+0xA890	0x25E5	
+0xA891	0x2609	
+0xA892	0x2295	
+0xA893	0x3012	
+0xA894	0x301D	
+0xA895	0x301E	
+0xA896	0xE7BC	
+0xA897	0xE7BD	
+0xA898	0xE7BE	
+0xA899	0xE7BF	
+0xA89A	0xE7C0	
+0xA89B	0xE7C1	
+0xA89C	0xE7C2	
+0xA89D	0xE7C3	
+0xA89E	0xE7C4	
+0xA89F	0xE7C5	
+0xA8A0	0xE7C6	
+0xA8A1	0x0101	
+0xA8A2	0x00E1	
+0xA8A3	0x01CE	
+0xA8A4	0x00E0	
+0xA8A5	0x0113	
+0xA8A6	0x00E9	
+0xA8A7	0x011B	
+0xA8A8	0x00E8	
+0xA8A9	0x012B	
+0xA8AA	0x00ED	
+0xA8AB	0x01D0	
+0xA8AC	0x00EC	
+0xA8AD	0x014D	
+0xA8AE	0x00F3	
+0xA8AF	0x01D2	
+0xA8B0	0x00F2	
+0xA8B1	0x016B	
+0xA8B2	0x00FA	
+0xA8B3	0x01D4	
+0xA8B4	0x00F9	
+0xA8B5	0x01D6	
+0xA8B6	0x01D8	
+0xA8B7	0x01DA	
+0xA8B8	0x01DC	
+0xA8B9	0x00FC	
+0xA8BA	0x00EA	
+0xA8BB	0x0251	
+0xA8BC	0xE7C7	
+0xA8BD	0x0144	
+0xA8BE	0x0148	
+0xA8BF	0xE7C8	
+0xA8C0	0x0261	
+0xA8C1	0xE7C9	
+0xA8C2	0xE7CA	
+0xA8C3	0xE7CB	
+0xA8C4	0xE7CC	
+0xA8C5	0x3105	
+0xA8C6	0x3106	
+0xA8C7	0x3107	
+0xA8C8	0x3108	
+0xA8C9	0x3109	
+0xA8CA	0x310A	
+0xA8CB	0x310B	
+0xA8CC	0x310C	
+0xA8CD	0x310D	
+0xA8CE	0x310E	
+0xA8CF	0x310F	
+0xA8D0	0x3110	
+0xA8D1	0x3111	
+0xA8D2	0x3112	
+0xA8D3	0x3113	
+0xA8D4	0x3114	
+0xA8D5	0x3115	
+0xA8D6	0x3116	
+0xA8D7	0x3117	
+0xA8D8	0x3118	
+0xA8D9	0x3119	
+0xA8DA	0x311A	
+0xA8DB	0x311B	
+0xA8DC	0x311C	
+0xA8DD	0x311D	
+0xA8DE	0x311E	
+0xA8DF	0x311F	
+0xA8E0	0x3120	
+0xA8E1	0x3121	
+0xA8E2	0x3122	
+0xA8E3	0x3123	
+0xA8E4	0x3124	
+0xA8E5	0x3125	
+0xA8E6	0x3126	
+0xA8E7	0x3127	
+0xA8E8	0x3128	
+0xA8E9	0x3129	
+0xA8EA	0xE7CD	
+0xA8EB	0xE7CE	
+0xA8EC	0xE7CF	
+0xA8ED	0xE7D0	
+0xA8EE	0xE7D1	
+0xA8EF	0xE7D2	
+0xA8F0	0xE7D3	
+0xA8F1	0xE7D4	
+0xA8F2	0xE7D5	
+0xA8F3	0xE7D6	
+0xA8F4	0xE7D7	
+0xA8F5	0xE7D8	
+0xA8F6	0xE7D9	
+0xA8F7	0xE7DA	
+0xA8F8	0xE7DB	
+0xA8F9	0xE7DC	
+0xA8FA	0xE7DD	
+0xA8FB	0xE7DE	
+0xA8FC	0xE7DF	
+0xA8FD	0xE7E0	
+0xA8FE	0xE7E1	
+0xA940	0x3021	
+0xA941	0x3022	
+0xA942	0x3023	
+0xA943	0x3024	
+0xA944	0x3025	
+0xA945	0x3026	
+0xA946	0x3027	
+0xA947	0x3028	
+0xA948	0x3029	
+0xA949	0x32A3	
+0xA94A	0x338E	
+0xA94B	0x338F	
+0xA94C	0x339C	
+0xA94D	0x339D	
+0xA94E	0x339E	
+0xA94F	0x33A1	
+0xA950	0x33C4	
+0xA951	0x33CE	
+0xA952	0x33D1	
+0xA953	0x33D2	
+0xA954	0x33D5	
+0xA955	0xFE30	
+0xA956	0xFFE2	
+0xA957	0xFFE4	
+0xA958	0xE7E2	
+0xA959	0x2121	
+0xA95A	0x3231	
+0xA95B	0xE7E3	
+0xA95C	0x2010	
+0xA95D	0xE7E4	
+0xA95E	0xE7E5	
+0xA95F	0xE7E6	
+0xA960	0x30FC	
+0xA961	0x309B	
+0xA962	0x309C	
+0xA963	0x30FD	
+0xA964	0x30FE	
+0xA965	0x3006	
+0xA966	0x309D	
+0xA967	0x309E	
+0xA968	0xFE49	
+0xA969	0xFE4A	
+0xA96A	0xFE4B	
+0xA96B	0xFE4C	
+0xA96C	0xFE4D	
+0xA96D	0xFE4E	
+0xA96E	0xFE4F	
+0xA96F	0xFE50	
+0xA970	0xFE51	
+0xA971	0xFE52	
+0xA972	0xFE54	
+0xA973	0xFE55	
+0xA974	0xFE56	
+0xA975	0xFE57	
+0xA976	0xFE59	
+0xA977	0xFE5A	
+0xA978	0xFE5B	
+0xA979	0xFE5C	
+0xA97A	0xFE5D	
+0xA97B	0xFE5E	
+0xA97C	0xFE5F	
+0xA97D	0xFE60	
+0xA97E	0xFE61	
+0xA980	0xFE62	
+0xA981	0xFE63	
+0xA982	0xFE64	
+0xA983	0xFE65	
+0xA984	0xFE66	
+0xA985	0xFE68	
+0xA986	0xFE69	
+0xA987	0xFE6A	
+0xA988	0xFE6B	
+0xA989	0xE7E7	
+0xA98A	0xE7E8	
+0xA98B	0xE7E9	
+0xA98C	0xE7EA	
+0xA98D	0xE7EB	
+0xA98E	0xE7EC	
+0xA98F	0xE7ED	
+0xA990	0xE7EE	
+0xA991	0xE7EF	
+0xA992	0xE7F0	
+0xA993	0xE7F1	
+0xA994	0xE7F2	
+0xA995	0xE7F3	
+0xA996	0x3007	
+0xA997	0xE7F4	
+0xA998	0xE7F5	
+0xA999	0xE7F6	
+0xA99A	0xE7F7	
+0xA99B	0xE7F8	
+0xA99C	0xE7F9	
+0xA99D	0xE7FA	
+0xA99E	0xE7FB	
+0xA99F	0xE7FC	
+0xA9A0	0xE7FD	
+0xA9A1	0xE7FE	
+0xA9A2	0xE7FF	
+0xA9A3	0xE800	
+0xA9A4	0x2500	
+0xA9A5	0x2501	
+0xA9A6	0x2502	
+0xA9A7	0x2503	
+0xA9A8	0x2504	
+0xA9A9	0x2505	
+0xA9AA	0x2506	
+0xA9AB	0x2507	
+0xA9AC	0x2508	
+0xA9AD	0x2509	
+0xA9AE	0x250A	
+0xA9AF	0x250B	
+0xA9B0	0x250C	
+0xA9B1	0x250D	
+0xA9B2	0x250E	
+0xA9B3	0x250F	
+0xA9B4	0x2510	
+0xA9B5	0x2511	
+0xA9B6	0x2512	
+0xA9B7	0x2513	
+0xA9B8	0x2514	
+0xA9B9	0x2515	
+0xA9BA	0x2516	
+0xA9BB	0x2517	
+0xA9BC	0x2518	
+0xA9BD	0x2519	
+0xA9BE	0x251A	
+0xA9BF	0x251B	
+0xA9C0	0x251C	
+0xA9C1	0x251D	
+0xA9C2	0x251E	
+0xA9C3	0x251F	
+0xA9C4	0x2520	
+0xA9C5	0x2521	
+0xA9C6	0x2522	
+0xA9C7	0x2523	
+0xA9C8	0x2524	
+0xA9C9	0x2525	
+0xA9CA	0x2526	
+0xA9CB	0x2527	
+0xA9CC	0x2528	
+0xA9CD	0x2529	
+0xA9CE	0x252A	
+0xA9CF	0x252B	
+0xA9D0	0x252C	
+0xA9D1	0x252D	
+0xA9D2	0x252E	
+0xA9D3	0x252F	
+0xA9D4	0x2530	
+0xA9D5	0x2531	
+0xA9D6	0x2532	
+0xA9D7	0x2533	
+0xA9D8	0x2534	
+0xA9D9	0x2535	
+0xA9DA	0x2536	
+0xA9DB	0x2537	
+0xA9DC	0x2538	
+0xA9DD	0x2539	
+0xA9DE	0x253A	
+0xA9DF	0x253B	
+0xA9E0	0x253C	
+0xA9E1	0x253D	
+0xA9E2	0x253E	
+0xA9E3	0x253F	
+0xA9E4	0x2540	
+0xA9E5	0x2541	
+0xA9E6	0x2542	
+0xA9E7	0x2543	
+0xA9E8	0x2544	
+0xA9E9	0x2545	
+0xA9EA	0x2546	
+0xA9EB	0x2547	
+0xA9EC	0x2548	
+0xA9ED	0x2549	
+0xA9EE	0x254A	
+0xA9EF	0x254B	
+0xA9F0	0xE801	
+0xA9F1	0xE802	
+0xA9F2	0xE803	
+0xA9F3	0xE804	
+0xA9F4	0xE805	
+0xA9F5	0xE806	
+0xA9F6	0xE807	
+0xA9F7	0xE808	
+0xA9F8	0xE809	
+0xA9F9	0xE80A	
+0xA9FA	0xE80B	
+0xA9FB	0xE80C	
+0xA9FC	0xE80D	
+0xA9FD	0xE80E	
+0xA9FE	0xE80F	
+0xAA40	0x72DC	
+0xAA41	0x72DD	
+0xAA42	0x72DF	
+0xAA43	0x72E2	
+0xAA44	0x72E3	
+0xAA45	0x72E4	
+0xAA46	0x72E5	
+0xAA47	0x72E6	
+0xAA48	0x72E7	
+0xAA49	0x72EA	
+0xAA4A	0x72EB	
+0xAA4B	0x72F5	
+0xAA4C	0x72F6	
+0xAA4D	0x72F9	
+0xAA4E	0x72FD	
+0xAA4F	0x72FE	
+0xAA50	0x72FF	
+0xAA51	0x7300	
+0xAA52	0x7302	
+0xAA53	0x7304	
+0xAA54	0x7305	
+0xAA55	0x7306	
+0xAA56	0x7307	
+0xAA57	0x7308	
+0xAA58	0x7309	
+0xAA59	0x730B	
+0xAA5A	0x730C	
+0xAA5B	0x730D	
+0xAA5C	0x730F	
+0xAA5D	0x7310	
+0xAA5E	0x7311	
+0xAA5F	0x7312	
+0xAA60	0x7314	
+0xAA61	0x7318	
+0xAA62	0x7319	
+0xAA63	0x731A	
+0xAA64	0x731F	
+0xAA65	0x7320	
+0xAA66	0x7323	
+0xAA67	0x7324	
+0xAA68	0x7326	
+0xAA69	0x7327	
+0xAA6A	0x7328	
+0xAA6B	0x732D	
+0xAA6C	0x732F	
+0xAA6D	0x7330	
+0xAA6E	0x7332	
+0xAA6F	0x7333	
+0xAA70	0x7335	
+0xAA71	0x7336	
+0xAA72	0x733A	
+0xAA73	0x733B	
+0xAA74	0x733C	
+0xAA75	0x733D	
+0xAA76	0x7340	
+0xAA77	0x7341	
+0xAA78	0x7342	
+0xAA79	0x7343	
+0xAA7A	0x7344	
+0xAA7B	0x7345	
+0xAA7C	0x7346	
+0xAA7D	0x7347	
+0xAA7E	0x7348	
+0xAA80	0x7349	
+0xAA81	0x734A	
+0xAA82	0x734B	
+0xAA83	0x734C	
+0xAA84	0x734E	
+0xAA85	0x734F	
+0xAA86	0x7351	
+0xAA87	0x7353	
+0xAA88	0x7354	
+0xAA89	0x7355	
+0xAA8A	0x7356	
+0xAA8B	0x7358	
+0xAA8C	0x7359	
+0xAA8D	0x735A	
+0xAA8E	0x735B	
+0xAA8F	0x735C	
+0xAA90	0x735D	
+0xAA91	0x735E	
+0xAA92	0x735F	
+0xAA93	0x7361	
+0xAA94	0x7362	
+0xAA95	0x7363	
+0xAA96	0x7364	
+0xAA97	0x7365	
+0xAA98	0x7366	
+0xAA99	0x7367	
+0xAA9A	0x7368	
+0xAA9B	0x7369	
+0xAA9C	0x736A	
+0xAA9D	0x736B	
+0xAA9E	0x736E	
+0xAA9F	0x7370	
+0xAAA0	0x7371	
+# 0xAAA1	 	
+# 0xAAA2	 	
+# 0xAAA3	 	
+# 0xAAA4	 	
+# 0xAAA5	 	
+# 0xAAA6	 	
+# 0xAAA7	 	
+# 0xAAA8	 	
+# 0xAAA9	 	
+# 0xAAAA	 	
+# 0xAAAB	 	
+# 0xAAAC	 	
+# 0xAAAD	 	
+# 0xAAAE	 	
+# 0xAAAF	 	
+# 0xAAB0	 	
+# 0xAAB1	 	
+# 0xAAB2	 	
+# 0xAAB3	 	
+# 0xAAB4	 	
+# 0xAAB5	 	
+# 0xAAB6	 	
+# 0xAAB7	 	
+# 0xAAB8	 	
+# 0xAAB9	 	
+# 0xAABA	 	
+# 0xAABB	 	
+# 0xAABC	 	
+# 0xAABD	 	
+# 0xAABE	 	
+# 0xAABF	 	
+# 0xAAC0	 	
+# 0xAAC1	 	
+# 0xAAC2	 	
+# 0xAAC3	 	
+# 0xAAC4	 	
+# 0xAAC5	 	
+# 0xAAC6	 	
+# 0xAAC7	 	
+# 0xAAC8	 	
+# 0xAAC9	 	
+# 0xAACA	 	
+# 0xAACB	 	
+# 0xAACC	 	
+# 0xAACD	 	
+# 0xAACE	 	
+# 0xAACF	 	
+# 0xAAD0	 	
+# 0xAAD1	 	
+# 0xAAD2	 	
+# 0xAAD3	 	
+# 0xAAD4	 	
+# 0xAAD5	 	
+# 0xAAD6	 	
+# 0xAAD7	 	
+# 0xAAD8	 	
+# 0xAAD9	 	
+# 0xAADA	 	
+# 0xAADB	 	
+# 0xAADC	 	
+# 0xAADD	 	
+# 0xAADE	 	
+# 0xAADF	 	
+# 0xAAE0	 	
+# 0xAAE1	 	
+# 0xAAE2	 	
+# 0xAAE3	 	
+# 0xAAE4	 	
+# 0xAAE5	 	
+# 0xAAE6	 	
+# 0xAAE7	 	
+# 0xAAE8	 	
+# 0xAAE9	 	
+# 0xAAEA	 	
+# 0xAAEB	 	
+# 0xAAEC	 	
+# 0xAAED	 	
+# 0xAAEE	 	
+# 0xAAEF	 	
+# 0xAAF0	 	
+# 0xAAF1	 	
+# 0xAAF2	 	
+# 0xAAF3	 	
+# 0xAAF4	 	
+# 0xAAF5	 	
+# 0xAAF6	 	
+# 0xAAF7	 	
+# 0xAAF8	 	
+# 0xAAF9	 	
+# 0xAAFA	 	
+# 0xAAFB	 	
+# 0xAAFC	 	
+# 0xAAFD	 	
+# 0xAAFE	 	
+0xAB40	0x7372	
+0xAB41	0x7373	
+0xAB42	0x7374	
+0xAB43	0x7375	
+0xAB44	0x7376	
+0xAB45	0x7377	
+0xAB46	0x7378	
+0xAB47	0x7379	
+0xAB48	0x737A	
+0xAB49	0x737B	
+0xAB4A	0x737C	
+0xAB4B	0x737D	
+0xAB4C	0x737F	
+0xAB4D	0x7380	
+0xAB4E	0x7381	
+0xAB4F	0x7382	
+0xAB50	0x7383	
+0xAB51	0x7385	
+0xAB52	0x7386	
+0xAB53	0x7388	
+0xAB54	0x738A	
+0xAB55	0x738C	
+0xAB56	0x738D	
+0xAB57	0x738F	
+0xAB58	0x7390	
+0xAB59	0x7392	
+0xAB5A	0x7393	
+0xAB5B	0x7394	
+0xAB5C	0x7395	
+0xAB5D	0x7397	
+0xAB5E	0x7398	
+0xAB5F	0x7399	
+0xAB60	0x739A	
+0xAB61	0x739C	
+0xAB62	0x739D	
+0xAB63	0x739E	
+0xAB64	0x73A0	
+0xAB65	0x73A1	
+0xAB66	0x73A3	
+0xAB67	0x73A4	
+0xAB68	0x73A5	
+0xAB69	0x73A6	
+0xAB6A	0x73A7	
+0xAB6B	0x73A8	
+0xAB6C	0x73AA	
+0xAB6D	0x73AC	
+0xAB6E	0x73AD	
+0xAB6F	0x73B1	
+0xAB70	0x73B4	
+0xAB71	0x73B5	
+0xAB72	0x73B6	
+0xAB73	0x73B8	
+0xAB74	0x73B9	
+0xAB75	0x73BC	
+0xAB76	0x73BD	
+0xAB77	0x73BE	
+0xAB78	0x73BF	
+0xAB79	0x73C1	
+0xAB7A	0x73C3	
+0xAB7B	0x73C4	
+0xAB7C	0x73C5	
+0xAB7D	0x73C6	
+0xAB7E	0x73C7	
+0xAB80	0x73CB	
+0xAB81	0x73CC	
+0xAB82	0x73CE	
+0xAB83	0x73D2	
+0xAB84	0x73D3	
+0xAB85	0x73D4	
+0xAB86	0x73D5	
+0xAB87	0x73D6	
+0xAB88	0x73D7	
+0xAB89	0x73D8	
+0xAB8A	0x73DA	
+0xAB8B	0x73DB	
+0xAB8C	0x73DC	
+0xAB8D	0x73DD	
+0xAB8E	0x73DF	
+0xAB8F	0x73E1	
+0xAB90	0x73E2	
+0xAB91	0x73E3	
+0xAB92	0x73E4	
+0xAB93	0x73E6	
+0xAB94	0x73E8	
+0xAB95	0x73EA	
+0xAB96	0x73EB	
+0xAB97	0x73EC	
+0xAB98	0x73EE	
+0xAB99	0x73EF	
+0xAB9A	0x73F0	
+0xAB9B	0x73F1	
+0xAB9C	0x73F3	
+0xAB9D	0x73F4	
+0xAB9E	0x73F5	
+0xAB9F	0x73F6	
+0xABA0	0x73F7	
+# 0xABA1	 	
+# 0xABA2	 	
+# 0xABA3	 	
+# 0xABA4	 	
+# 0xABA5	 	
+# 0xABA6	 	
+# 0xABA7	 	
+# 0xABA8	 	
+# 0xABA9	 	
+# 0xABAA	 	
+# 0xABAB	 	
+# 0xABAC	 	
+# 0xABAD	 	
+# 0xABAE	 	
+# 0xABAF	 	
+# 0xABB0	 	
+# 0xABB1	 	
+# 0xABB2	 	
+# 0xABB3	 	
+# 0xABB4	 	
+# 0xABB5	 	
+# 0xABB6	 	
+# 0xABB7	 	
+# 0xABB8	 	
+# 0xABB9	 	
+# 0xABBA	 	
+# 0xABBB	 	
+# 0xABBC	 	
+# 0xABBD	 	
+# 0xABBE	 	
+# 0xABBF	 	
+# 0xABC0	 	
+# 0xABC1	 	
+# 0xABC2	 	
+# 0xABC3	 	
+# 0xABC4	 	
+# 0xABC5	 	
+# 0xABC6	 	
+# 0xABC7	 	
+# 0xABC8	 	
+# 0xABC9	 	
+# 0xABCA	 	
+# 0xABCB	 	
+# 0xABCC	 	
+# 0xABCD	 	
+# 0xABCE	 	
+# 0xABCF	 	
+# 0xABD0	 	
+# 0xABD1	 	
+# 0xABD2	 	
+# 0xABD3	 	
+# 0xABD4	 	
+# 0xABD5	 	
+# 0xABD6	 	
+# 0xABD7	 	
+# 0xABD8	 	
+# 0xABD9	 	
+# 0xABDA	 	
+# 0xABDB	 	
+# 0xABDC	 	
+# 0xABDD	 	
+# 0xABDE	 	
+# 0xABDF	 	
+# 0xABE0	 	
+# 0xABE1	 	
+# 0xABE2	 	
+# 0xABE3	 	
+# 0xABE4	 	
+# 0xABE5	 	
+# 0xABE6	 	
+# 0xABE7	 	
+# 0xABE8	 	
+# 0xABE9	 	
+# 0xABEA	 	
+# 0xABEB	 	
+# 0xABEC	 	
+# 0xABED	 	
+# 0xABEE	 	
+# 0xABEF	 	
+# 0xABF0	 	
+# 0xABF1	 	
+# 0xABF2	 	
+# 0xABF3	 	
+# 0xABF4	 	
+# 0xABF5	 	
+# 0xABF6	 	
+# 0xABF7	 	
+# 0xABF8	 	
+# 0xABF9	 	
+# 0xABFA	 	
+# 0xABFB	 	
+# 0xABFC	 	
+# 0xABFD	 	
+# 0xABFE	 	
+0xAC40	0x73F8	
+0xAC41	0x73F9	
+0xAC42	0x73FA	
+0xAC43	0x73FB	
+0xAC44	0x73FC	
+0xAC45	0x73FD	
+0xAC46	0x73FE	
+0xAC47	0x73FF	
+0xAC48	0x7400	
+0xAC49	0x7401	
+0xAC4A	0x7402	
+0xAC4B	0x7404	
+0xAC4C	0x7407	
+0xAC4D	0x7408	
+0xAC4E	0x740B	
+0xAC4F	0x740C	
+0xAC50	0x740D	
+0xAC51	0x740E	
+0xAC52	0x7411	
+0xAC53	0x7412	
+0xAC54	0x7413	
+0xAC55	0x7414	
+0xAC56	0x7415	
+0xAC57	0x7416	
+0xAC58	0x7417	
+0xAC59	0x7418	
+0xAC5A	0x7419	
+0xAC5B	0x741C	
+0xAC5C	0x741D	
+0xAC5D	0x741E	
+0xAC5E	0x741F	
+0xAC5F	0x7420	
+0xAC60	0x7421	
+0xAC61	0x7423	
+0xAC62	0x7424	
+0xAC63	0x7427	
+0xAC64	0x7429	
+0xAC65	0x742B	
+0xAC66	0x742D	
+0xAC67	0x742F	
+0xAC68	0x7431	
+0xAC69	0x7432	
+0xAC6A	0x7437	
+0xAC6B	0x7438	
+0xAC6C	0x7439	
+0xAC6D	0x743A	
+0xAC6E	0x743B	
+0xAC6F	0x743D	
+0xAC70	0x743E	
+0xAC71	0x743F	
+0xAC72	0x7440	
+0xAC73	0x7442	
+0xAC74	0x7443	
+0xAC75	0x7444	
+0xAC76	0x7445	
+0xAC77	0x7446	
+0xAC78	0x7447	
+0xAC79	0x7448	
+0xAC7A	0x7449	
+0xAC7B	0x744A	
+0xAC7C	0x744B	
+0xAC7D	0x744C	
+0xAC7E	0x744D	
+0xAC80	0x744E	
+0xAC81	0x744F	
+0xAC82	0x7450	
+0xAC83	0x7451	
+0xAC84	0x7452	
+0xAC85	0x7453	
+0xAC86	0x7454	
+0xAC87	0x7456	
+0xAC88	0x7458	
+0xAC89	0x745D	
+0xAC8A	0x7460	
+0xAC8B	0x7461	
+0xAC8C	0x7462	
+0xAC8D	0x7463	
+0xAC8E	0x7464	
+0xAC8F	0x7465	
+0xAC90	0x7466	
+0xAC91	0x7467	
+0xAC92	0x7468	
+0xAC93	0x7469	
+0xAC94	0x746A	
+0xAC95	0x746B	
+0xAC96	0x746C	
+0xAC97	0x746E	
+0xAC98	0x746F	
+0xAC99	0x7471	
+0xAC9A	0x7472	
+0xAC9B	0x7473	
+0xAC9C	0x7474	
+0xAC9D	0x7475	
+0xAC9E	0x7478	
+0xAC9F	0x7479	
+0xACA0	0x747A	
+# 0xACA1	 	
+# 0xACA2	 	
+# 0xACA3	 	
+# 0xACA4	 	
+# 0xACA5	 	
+# 0xACA6	 	
+# 0xACA7	 	
+# 0xACA8	 	
+# 0xACA9	 	
+# 0xACAA	 	
+# 0xACAB	 	
+# 0xACAC	 	
+# 0xACAD	 	
+# 0xACAE	 	
+# 0xACAF	 	
+# 0xACB0	 	
+# 0xACB1	 	
+# 0xACB2	 	
+# 0xACB3	 	
+# 0xACB4	 	
+# 0xACB5	 	
+# 0xACB6	 	
+# 0xACB7	 	
+# 0xACB8	 	
+# 0xACB9	 	
+# 0xACBA	 	
+# 0xACBB	 	
+# 0xACBC	 	
+# 0xACBD	 	
+# 0xACBE	 	
+# 0xACBF	 	
+# 0xACC0	 	
+# 0xACC1	 	
+# 0xACC2	 	
+# 0xACC3	 	
+# 0xACC4	 	
+# 0xACC5	 	
+# 0xACC6	 	
+# 0xACC7	 	
+# 0xACC8	 	
+# 0xACC9	 	
+# 0xACCA	 	
+# 0xACCB	 	
+# 0xACCC	 	
+# 0xACCD	 	
+# 0xACCE	 	
+# 0xACCF	 	
+# 0xACD0	 	
+# 0xACD1	 	
+# 0xACD2	 	
+# 0xACD3	 	
+# 0xACD4	 	
+# 0xACD5	 	
+# 0xACD6	 	
+# 0xACD7	 	
+# 0xACD8	 	
+# 0xACD9	 	
+# 0xACDA	 	
+# 0xACDB	 	
+# 0xACDC	 	
+# 0xACDD	 	
+# 0xACDE	 	
+# 0xACDF	 	
+# 0xACE0	 	
+# 0xACE1	 	
+# 0xACE2	 	
+# 0xACE3	 	
+# 0xACE4	 	
+# 0xACE5	 	
+# 0xACE6	 	
+# 0xACE7	 	
+# 0xACE8	 	
+# 0xACE9	 	
+# 0xACEA	 	
+# 0xACEB	 	
+# 0xACEC	 	
+# 0xACED	 	
+# 0xACEE	 	
+# 0xACEF	 	
+# 0xACF0	 	
+# 0xACF1	 	
+# 0xACF2	 	
+# 0xACF3	 	
+# 0xACF4	 	
+# 0xACF5	 	
+# 0xACF6	 	
+# 0xACF7	 	
+# 0xACF8	 	
+# 0xACF9	 	
+# 0xACFA	 	
+# 0xACFB	 	
+# 0xACFC	 	
+# 0xACFD	 	
+# 0xACFE	 	
+0xAD40	0x747B	
+0xAD41	0x747C	
+0xAD42	0x747D	
+0xAD43	0x747F	
+0xAD44	0x7482	
+0xAD45	0x7484	
+0xAD46	0x7485	
+0xAD47	0x7486	
+0xAD48	0x7488	
+0xAD49	0x7489	
+0xAD4A	0x748A	
+0xAD4B	0x748C	
+0xAD4C	0x748D	
+0xAD4D	0x748F	
+0xAD4E	0x7491	
+0xAD4F	0x7492	
+0xAD50	0x7493	
+0xAD51	0x7494	
+0xAD52	0x7495	
+0xAD53	0x7496	
+0xAD54	0x7497	
+0xAD55	0x7498	
+0xAD56	0x7499	
+0xAD57	0x749A	
+0xAD58	0x749B	
+0xAD59	0x749D	
+0xAD5A	0x749F	
+0xAD5B	0x74A0	
+0xAD5C	0x74A1	
+0xAD5D	0x74A2	
+0xAD5E	0x74A3	
+0xAD5F	0x74A4	
+0xAD60	0x74A5	
+0xAD61	0x74A6	
+0xAD62	0x74AA	
+0xAD63	0x74AB	
+0xAD64	0x74AC	
+0xAD65	0x74AD	
+0xAD66	0x74AE	
+0xAD67	0x74AF	
+0xAD68	0x74B0	
+0xAD69	0x74B1	
+0xAD6A	0x74B2	
+0xAD6B	0x74B3	
+0xAD6C	0x74B4	
+0xAD6D	0x74B5	
+0xAD6E	0x74B6	
+0xAD6F	0x74B7	
+0xAD70	0x74B8	
+0xAD71	0x74B9	
+0xAD72	0x74BB	
+0xAD73	0x74BC	
+0xAD74	0x74BD	
+0xAD75	0x74BE	
+0xAD76	0x74BF	
+0xAD77	0x74C0	
+0xAD78	0x74C1	
+0xAD79	0x74C2	
+0xAD7A	0x74C3	
+0xAD7B	0x74C4	
+0xAD7C	0x74C5	
+0xAD7D	0x74C6	
+0xAD7E	0x74C7	
+0xAD80	0x74C8	
+0xAD81	0x74C9	
+0xAD82	0x74CA	
+0xAD83	0x74CB	
+0xAD84	0x74CC	
+0xAD85	0x74CD	
+0xAD86	0x74CE	
+0xAD87	0x74CF	
+0xAD88	0x74D0	
+0xAD89	0x74D1	
+0xAD8A	0x74D3	
+0xAD8B	0x74D4	
+0xAD8C	0x74D5	
+0xAD8D	0x74D6	
+0xAD8E	0x74D7	
+0xAD8F	0x74D8	
+0xAD90	0x74D9	
+0xAD91	0x74DA	
+0xAD92	0x74DB	
+0xAD93	0x74DD	
+0xAD94	0x74DF	
+0xAD95	0x74E1	
+0xAD96	0x74E5	
+0xAD97	0x74E7	
+0xAD98	0x74E8	
+0xAD99	0x74E9	
+0xAD9A	0x74EA	
+0xAD9B	0x74EB	
+0xAD9C	0x74EC	
+0xAD9D	0x74ED	
+0xAD9E	0x74F0	
+0xAD9F	0x74F1	
+0xADA0	0x74F2	
+# 0xADA1	 	
+# 0xADA2	 	
+# 0xADA3	 	
+# 0xADA4	 	
+# 0xADA5	 	
+# 0xADA6	 	
+# 0xADA7	 	
+# 0xADA8	 	
+# 0xADA9	 	
+# 0xADAA	 	
+# 0xADAB	 	
+# 0xADAC	 	
+# 0xADAD	 	
+# 0xADAE	 	
+# 0xADAF	 	
+# 0xADB0	 	
+# 0xADB1	 	
+# 0xADB2	 	
+# 0xADB3	 	
+# 0xADB4	 	
+# 0xADB5	 	
+# 0xADB6	 	
+# 0xADB7	 	
+# 0xADB8	 	
+# 0xADB9	 	
+# 0xADBA	 	
+# 0xADBB	 	
+# 0xADBC	 	
+# 0xADBD	 	
+# 0xADBE	 	
+# 0xADBF	 	
+# 0xADC0	 	
+# 0xADC1	 	
+# 0xADC2	 	
+# 0xADC3	 	
+# 0xADC4	 	
+# 0xADC5	 	
+# 0xADC6	 	
+# 0xADC7	 	
+# 0xADC8	 	
+# 0xADC9	 	
+# 0xADCA	 	
+# 0xADCB	 	
+# 0xADCC	 	
+# 0xADCD	 	
+# 0xADCE	 	
+# 0xADCF	 	
+# 0xADD0	 	
+# 0xADD1	 	
+# 0xADD2	 	
+# 0xADD3	 	
+# 0xADD4	 	
+# 0xADD5	 	
+# 0xADD6	 	
+# 0xADD7	 	
+# 0xADD8	 	
+# 0xADD9	 	
+# 0xADDA	 	
+# 0xADDB	 	
+# 0xADDC	 	
+# 0xADDD	 	
+# 0xADDE	 	
+# 0xADDF	 	
+# 0xADE0	 	
+# 0xADE1	 	
+# 0xADE2	 	
+# 0xADE3	 	
+# 0xADE4	 	
+# 0xADE5	 	
+# 0xADE6	 	
+# 0xADE7	 	
+# 0xADE8	 	
+# 0xADE9	 	
+# 0xADEA	 	
+# 0xADEB	 	
+# 0xADEC	 	
+# 0xADED	 	
+# 0xADEE	 	
+# 0xADEF	 	
+# 0xADF0	 	
+# 0xADF1	 	
+# 0xADF2	 	
+# 0xADF3	 	
+# 0xADF4	 	
+# 0xADF5	 	
+# 0xADF6	 	
+# 0xADF7	 	
+# 0xADF8	 	
+# 0xADF9	 	
+# 0xADFA	 	
+# 0xADFB	 	
+# 0xADFC	 	
+# 0xADFD	 	
+# 0xADFE	 	
+0xAE40	0x74F3	
+0xAE41	0x74F5	
+0xAE42	0x74F8	
+0xAE43	0x74F9	
+0xAE44	0x74FA	
+0xAE45	0x74FB	
+0xAE46	0x74FC	
+0xAE47	0x74FD	
+0xAE48	0x74FE	
+0xAE49	0x7500	
+0xAE4A	0x7501	
+0xAE4B	0x7502	
+0xAE4C	0x7503	
+0xAE4D	0x7505	
+0xAE4E	0x7506	
+0xAE4F	0x7507	
+0xAE50	0x7508	
+0xAE51	0x7509	
+0xAE52	0x750A	
+0xAE53	0x750B	
+0xAE54	0x750C	
+0xAE55	0x750E	
+0xAE56	0x7510	
+0xAE57	0x7512	
+0xAE58	0x7514	
+0xAE59	0x7515	
+0xAE5A	0x7516	
+0xAE5B	0x7517	
+0xAE5C	0x751B	
+0xAE5D	0x751D	
+0xAE5E	0x751E	
+0xAE5F	0x7520	
+0xAE60	0x7521	
+0xAE61	0x7522	
+0xAE62	0x7523	
+0xAE63	0x7524	
+0xAE64	0x7526	
+0xAE65	0x7527	
+0xAE66	0x752A	
+0xAE67	0x752E	
+0xAE68	0x7534	
+0xAE69	0x7536	
+0xAE6A	0x7539	
+0xAE6B	0x753C	
+0xAE6C	0x753D	
+0xAE6D	0x753F	
+0xAE6E	0x7541	
+0xAE6F	0x7542	
+0xAE70	0x7543	
+0xAE71	0x7544	
+0xAE72	0x7546	
+0xAE73	0x7547	
+0xAE74	0x7549	
+0xAE75	0x754A	
+0xAE76	0x754D	
+0xAE77	0x7550	
+0xAE78	0x7551	
+0xAE79	0x7552	
+0xAE7A	0x7553	
+0xAE7B	0x7555	
+0xAE7C	0x7556	
+0xAE7D	0x7557	
+0xAE7E	0x7558	
+0xAE80	0x755D	
+0xAE81	0x755E	
+0xAE82	0x755F	
+0xAE83	0x7560	
+0xAE84	0x7561	
+0xAE85	0x7562	
+0xAE86	0x7563	
+0xAE87	0x7564	
+0xAE88	0x7567	
+0xAE89	0x7568	
+0xAE8A	0x7569	
+0xAE8B	0x756B	
+0xAE8C	0x756C	
+0xAE8D	0x756D	
+0xAE8E	0x756E	
+0xAE8F	0x756F	
+0xAE90	0x7570	
+0xAE91	0x7571	
+0xAE92	0x7573	
+0xAE93	0x7575	
+0xAE94	0x7576	
+0xAE95	0x7577	
+0xAE96	0x757A	
+0xAE97	0x757B	
+0xAE98	0x757C	
+0xAE99	0x757D	
+0xAE9A	0x757E	
+0xAE9B	0x7580	
+0xAE9C	0x7581	
+0xAE9D	0x7582	
+0xAE9E	0x7584	
+0xAE9F	0x7585	
+0xAEA0	0x7587	
+# 0xAEA1	 	
+# 0xAEA2	 	
+# 0xAEA3	 	
+# 0xAEA4	 	
+# 0xAEA5	 	
+# 0xAEA6	 	
+# 0xAEA7	 	
+# 0xAEA8	 	
+# 0xAEA9	 	
+# 0xAEAA	 	
+# 0xAEAB	 	
+# 0xAEAC	 	
+# 0xAEAD	 	
+# 0xAEAE	 	
+# 0xAEAF	 	
+# 0xAEB0	 	
+# 0xAEB1	 	
+# 0xAEB2	 	
+# 0xAEB3	 	
+# 0xAEB4	 	
+# 0xAEB5	 	
+# 0xAEB6	 	
+# 0xAEB7	 	
+# 0xAEB8	 	
+# 0xAEB9	 	
+# 0xAEBA	 	
+# 0xAEBB	 	
+# 0xAEBC	 	
+# 0xAEBD	 	
+# 0xAEBE	 	
+# 0xAEBF	 	
+# 0xAEC0	 	
+# 0xAEC1	 	
+# 0xAEC2	 	
+# 0xAEC3	 	
+# 0xAEC4	 	
+# 0xAEC5	 	
+# 0xAEC6	 	
+# 0xAEC7	 	
+# 0xAEC8	 	
+# 0xAEC9	 	
+# 0xAECA	 	
+# 0xAECB	 	
+# 0xAECC	 	
+# 0xAECD	 	
+# 0xAECE	 	
+# 0xAECF	 	
+# 0xAED0	 	
+# 0xAED1	 	
+# 0xAED2	 	
+# 0xAED3	 	
+# 0xAED4	 	
+# 0xAED5	 	
+# 0xAED6	 	
+# 0xAED7	 	
+# 0xAED8	 	
+# 0xAED9	 	
+# 0xAEDA	 	
+# 0xAEDB	 	
+# 0xAEDC	 	
+# 0xAEDD	 	
+# 0xAEDE	 	
+# 0xAEDF	 	
+# 0xAEE0	 	
+# 0xAEE1	 	
+# 0xAEE2	 	
+# 0xAEE3	 	
+# 0xAEE4	 	
+# 0xAEE5	 	
+# 0xAEE6	 	
+# 0xAEE7	 	
+# 0xAEE8	 	
+# 0xAEE9	 	
+# 0xAEEA	 	
+# 0xAEEB	 	
+# 0xAEEC	 	
+# 0xAEED	 	
+# 0xAEEE	 	
+# 0xAEEF	 	
+# 0xAEF0	 	
+# 0xAEF1	 	
+# 0xAEF2	 	
+# 0xAEF3	 	
+# 0xAEF4	 	
+# 0xAEF5	 	
+# 0xAEF6	 	
+# 0xAEF7	 	
+# 0xAEF8	 	
+# 0xAEF9	 	
+# 0xAEFA	 	
+# 0xAEFB	 	
+# 0xAEFC	 	
+# 0xAEFD	 	
+# 0xAEFE	 	
+0xAF40	0x7588	
+0xAF41	0x7589	
+0xAF42	0x758A	
+0xAF43	0x758C	
+0xAF44	0x758D	
+0xAF45	0x758E	
+0xAF46	0x7590	
+0xAF47	0x7593	
+0xAF48	0x7595	
+0xAF49	0x7598	
+0xAF4A	0x759B	
+0xAF4B	0x759C	
+0xAF4C	0x759E	
+0xAF4D	0x75A2	
+0xAF4E	0x75A6	
+0xAF4F	0x75A7	
+0xAF50	0x75A8	
+0xAF51	0x75A9	
+0xAF52	0x75AA	
+0xAF53	0x75AD	
+0xAF54	0x75B6	
+0xAF55	0x75B7	
+0xAF56	0x75BA	
+0xAF57	0x75BB	
+0xAF58	0x75BF	
+0xAF59	0x75C0	
+0xAF5A	0x75C1	
+0xAF5B	0x75C6	
+0xAF5C	0x75CB	
+0xAF5D	0x75CC	
+0xAF5E	0x75CE	
+0xAF5F	0x75CF	
+0xAF60	0x75D0	
+0xAF61	0x75D1	
+0xAF62	0x75D3	
+0xAF63	0x75D7	
+0xAF64	0x75D9	
+0xAF65	0x75DA	
+0xAF66	0x75DC	
+0xAF67	0x75DD	
+0xAF68	0x75DF	
+0xAF69	0x75E0	
+0xAF6A	0x75E1	
+0xAF6B	0x75E5	
+0xAF6C	0x75E9	
+0xAF6D	0x75EC	
+0xAF6E	0x75ED	
+0xAF6F	0x75EE	
+0xAF70	0x75EF	
+0xAF71	0x75F2	
+0xAF72	0x75F3	
+0xAF73	0x75F5	
+0xAF74	0x75F6	
+0xAF75	0x75F7	
+0xAF76	0x75F8	
+0xAF77	0x75FA	
+0xAF78	0x75FB	
+0xAF79	0x75FD	
+0xAF7A	0x75FE	
+0xAF7B	0x7602	
+0xAF7C	0x7604	
+0xAF7D	0x7606	
+0xAF7E	0x7607	
+0xAF80	0x7608	
+0xAF81	0x7609	
+0xAF82	0x760B	
+0xAF83	0x760D	
+0xAF84	0x760E	
+0xAF85	0x760F	
+0xAF86	0x7611	
+0xAF87	0x7612	
+0xAF88	0x7613	
+0xAF89	0x7614	
+0xAF8A	0x7616	
+0xAF8B	0x761A	
+0xAF8C	0x761C	
+0xAF8D	0x761D	
+0xAF8E	0x761E	
+0xAF8F	0x7621	
+0xAF90	0x7623	
+0xAF91	0x7627	
+0xAF92	0x7628	
+0xAF93	0x762C	
+0xAF94	0x762E	
+0xAF95	0x762F	
+0xAF96	0x7631	
+0xAF97	0x7632	
+0xAF98	0x7636	
+0xAF99	0x7637	
+0xAF9A	0x7639	
+0xAF9B	0x763A	
+0xAF9C	0x763B	
+0xAF9D	0x763D	
+0xAF9E	0x7641	
+0xAF9F	0x7642	
+0xAFA0	0x7644	
+# 0xAFA1	 	
+# 0xAFA2	 	
+# 0xAFA3	 	
+# 0xAFA4	 	
+# 0xAFA5	 	
+# 0xAFA6	 	
+# 0xAFA7	 	
+# 0xAFA8	 	
+# 0xAFA9	 	
+# 0xAFAA	 	
+# 0xAFAB	 	
+# 0xAFAC	 	
+# 0xAFAD	 	
+# 0xAFAE	 	
+# 0xAFAF	 	
+# 0xAFB0	 	
+# 0xAFB1	 	
+# 0xAFB2	 	
+# 0xAFB3	 	
+# 0xAFB4	 	
+# 0xAFB5	 	
+# 0xAFB6	 	
+# 0xAFB7	 	
+# 0xAFB8	 	
+# 0xAFB9	 	
+# 0xAFBA	 	
+# 0xAFBB	 	
+# 0xAFBC	 	
+# 0xAFBD	 	
+# 0xAFBE	 	
+# 0xAFBF	 	
+# 0xAFC0	 	
+# 0xAFC1	 	
+# 0xAFC2	 	
+# 0xAFC3	 	
+# 0xAFC4	 	
+# 0xAFC5	 	
+# 0xAFC6	 	
+# 0xAFC7	 	
+# 0xAFC8	 	
+# 0xAFC9	 	
+# 0xAFCA	 	
+# 0xAFCB	 	
+# 0xAFCC	 	
+# 0xAFCD	 	
+# 0xAFCE	 	
+# 0xAFCF	 	
+# 0xAFD0	 	
+# 0xAFD1	 	
+# 0xAFD2	 	
+# 0xAFD3	 	
+# 0xAFD4	 	
+# 0xAFD5	 	
+# 0xAFD6	 	
+# 0xAFD7	 	
+# 0xAFD8	 	
+# 0xAFD9	 	
+# 0xAFDA	 	
+# 0xAFDB	 	
+# 0xAFDC	 	
+# 0xAFDD	 	
+# 0xAFDE	 	
+# 0xAFDF	 	
+# 0xAFE0	 	
+# 0xAFE1	 	
+# 0xAFE2	 	
+# 0xAFE3	 	
+# 0xAFE4	 	
+# 0xAFE5	 	
+# 0xAFE6	 	
+# 0xAFE7	 	
+# 0xAFE8	 	
+# 0xAFE9	 	
+# 0xAFEA	 	
+# 0xAFEB	 	
+# 0xAFEC	 	
+# 0xAFED	 	
+# 0xAFEE	 	
+# 0xAFEF	 	
+# 0xAFF0	 	
+# 0xAFF1	 	
+# 0xAFF2	 	
+# 0xAFF3	 	
+# 0xAFF4	 	
+# 0xAFF5	 	
+# 0xAFF6	 	
+# 0xAFF7	 	
+# 0xAFF8	 	
+# 0xAFF9	 	
+# 0xAFFA	 	
+# 0xAFFB	 	
+# 0xAFFC	 	
+# 0xAFFD	 	
+# 0xAFFE	 	
+0xB040	0x7645	
+0xB041	0x7646	
+0xB042	0x7647	
+0xB043	0x7648	
+0xB044	0x7649	
+0xB045	0x764A	
+0xB046	0x764B	
+0xB047	0x764E	
+0xB048	0x764F	
+0xB049	0x7650	
+0xB04A	0x7651	
+0xB04B	0x7652	
+0xB04C	0x7653	
+0xB04D	0x7655	
+0xB04E	0x7657	
+0xB04F	0x7658	
+0xB050	0x7659	
+0xB051	0x765A	
+0xB052	0x765B	
+0xB053	0x765D	
+0xB054	0x765F	
+0xB055	0x7660	
+0xB056	0x7661	
+0xB057	0x7662	
+0xB058	0x7664	
+0xB059	0x7665	
+0xB05A	0x7666	
+0xB05B	0x7667	
+0xB05C	0x7668	
+0xB05D	0x7669	
+0xB05E	0x766A	
+0xB05F	0x766C	
+0xB060	0x766D	
+0xB061	0x766E	
+0xB062	0x7670	
+0xB063	0x7671	
+0xB064	0x7672	
+0xB065	0x7673	
+0xB066	0x7674	
+0xB067	0x7675	
+0xB068	0x7676	
+0xB069	0x7677	
+0xB06A	0x7679	
+0xB06B	0x767A	
+0xB06C	0x767C	
+0xB06D	0x767F	
+0xB06E	0x7680	
+0xB06F	0x7681	
+0xB070	0x7683	
+0xB071	0x7685	
+0xB072	0x7689	
+0xB073	0x768A	
+0xB074	0x768C	
+0xB075	0x768D	
+0xB076	0x768F	
+0xB077	0x7690	
+0xB078	0x7692	
+0xB079	0x7694	
+0xB07A	0x7695	
+0xB07B	0x7697	
+0xB07C	0x7698	
+0xB07D	0x769A	
+0xB07E	0x769B	
+0xB080	0x769C	
+0xB081	0x769D	
+0xB082	0x769E	
+0xB083	0x769F	
+0xB084	0x76A0	
+0xB085	0x76A1	
+0xB086	0x76A2	
+0xB087	0x76A3	
+0xB088	0x76A5	
+0xB089	0x76A6	
+0xB08A	0x76A7	
+0xB08B	0x76A8	
+0xB08C	0x76A9	
+0xB08D	0x76AA	
+0xB08E	0x76AB	
+0xB08F	0x76AC	
+0xB090	0x76AD	
+0xB091	0x76AF	
+0xB092	0x76B0	
+0xB093	0x76B3	
+0xB094	0x76B5	
+0xB095	0x76B6	
+0xB096	0x76B7	
+0xB097	0x76B8	
+0xB098	0x76B9	
+0xB099	0x76BA	
+0xB09A	0x76BB	
+0xB09B	0x76BC	
+0xB09C	0x76BD	
+0xB09D	0x76BE	
+0xB09E	0x76C0	
+0xB09F	0x76C1	
+0xB0A0	0x76C3	
+0xB0A1	0x554A	
+0xB0A2	0x963F	
+0xB0A3	0x57C3	
+0xB0A4	0x6328	
+0xB0A5	0x54CE	
+0xB0A6	0x5509	
+0xB0A7	0x54C0	
+0xB0A8	0x7691	
+0xB0A9	0x764C	
+0xB0AA	0x853C	
+0xB0AB	0x77EE	
+0xB0AC	0x827E	
+0xB0AD	0x788D	
+0xB0AE	0x7231	
+0xB0AF	0x9698	
+0xB0B0	0x978D	
+0xB0B1	0x6C28	
+0xB0B2	0x5B89	
+0xB0B3	0x4FFA	
+0xB0B4	0x6309	
+0xB0B5	0x6697	
+0xB0B6	0x5CB8	
+0xB0B7	0x80FA	
+0xB0B8	0x6848	
+0xB0B9	0x80AE	
+0xB0BA	0x6602	
+0xB0BB	0x76CE	
+0xB0BC	0x51F9	
+0xB0BD	0x6556	
+0xB0BE	0x71AC	
+0xB0BF	0x7FF1	
+0xB0C0	0x8884	
+0xB0C1	0x50B2	
+0xB0C2	0x5965	
+0xB0C3	0x61CA	
+0xB0C4	0x6FB3	
+0xB0C5	0x82AD	
+0xB0C6	0x634C	
+0xB0C7	0x6252	
+0xB0C8	0x53ED	
+0xB0C9	0x5427	
+0xB0CA	0x7B06	
+0xB0CB	0x516B	
+0xB0CC	0x75A4	
+0xB0CD	0x5DF4	
+0xB0CE	0x62D4	
+0xB0CF	0x8DCB	
+0xB0D0	0x9776	
+0xB0D1	0x628A	
+0xB0D2	0x8019	
+0xB0D3	0x575D	
+0xB0D4	0x9738	
+0xB0D5	0x7F62	
+0xB0D6	0x7238	
+0xB0D7	0x767D	
+0xB0D8	0x67CF	
+0xB0D9	0x767E	
+0xB0DA	0x6446	
+0xB0DB	0x4F70	
+0xB0DC	0x8D25	
+0xB0DD	0x62DC	
+0xB0DE	0x7A17	
+0xB0DF	0x6591	
+0xB0E0	0x73ED	
+0xB0E1	0x642C	
+0xB0E2	0x6273	
+0xB0E3	0x822C	
+0xB0E4	0x9881	
+0xB0E5	0x677F	
+0xB0E6	0x7248	
+0xB0E7	0x626E	
+0xB0E8	0x62CC	
+0xB0E9	0x4F34	
+0xB0EA	0x74E3	
+0xB0EB	0x534A	
+0xB0EC	0x529E	
+0xB0ED	0x7ECA	
+0xB0EE	0x90A6	
+0xB0EF	0x5E2E	
+0xB0F0	0x6886	
+0xB0F1	0x699C	
+0xB0F2	0x8180	
+0xB0F3	0x7ED1	
+0xB0F4	0x68D2	
+0xB0F5	0x78C5	
+0xB0F6	0x868C	
+0xB0F7	0x9551	
+0xB0F8	0x508D	
+0xB0F9	0x8C24	
+0xB0FA	0x82DE	
+0xB0FB	0x80DE	
+0xB0FC	0x5305	
+0xB0FD	0x8912	
+0xB0FE	0x5265	
+0xB140	0x76C4	
+0xB141	0x76C7	
+0xB142	0x76C9	
+0xB143	0x76CB	
+0xB144	0x76CC	
+0xB145	0x76D3	
+0xB146	0x76D5	
+0xB147	0x76D9	
+0xB148	0x76DA	
+0xB149	0x76DC	
+0xB14A	0x76DD	
+0xB14B	0x76DE	
+0xB14C	0x76E0	
+0xB14D	0x76E1	
+0xB14E	0x76E2	
+0xB14F	0x76E3	
+0xB150	0x76E4	
+0xB151	0x76E6	
+0xB152	0x76E7	
+0xB153	0x76E8	
+0xB154	0x76E9	
+0xB155	0x76EA	
+0xB156	0x76EB	
+0xB157	0x76EC	
+0xB158	0x76ED	
+0xB159	0x76F0	
+0xB15A	0x76F3	
+0xB15B	0x76F5	
+0xB15C	0x76F6	
+0xB15D	0x76F7	
+0xB15E	0x76FA	
+0xB15F	0x76FB	
+0xB160	0x76FD	
+0xB161	0x76FF	
+0xB162	0x7700	
+0xB163	0x7702	
+0xB164	0x7703	
+0xB165	0x7705	
+0xB166	0x7706	
+0xB167	0x770A	
+0xB168	0x770C	
+0xB169	0x770E	
+0xB16A	0x770F	
+0xB16B	0x7710	
+0xB16C	0x7711	
+0xB16D	0x7712	
+0xB16E	0x7713	
+0xB16F	0x7714	
+0xB170	0x7715	
+0xB171	0x7716	
+0xB172	0x7717	
+0xB173	0x7718	
+0xB174	0x771B	
+0xB175	0x771C	
+0xB176	0x771D	
+0xB177	0x771E	
+0xB178	0x7721	
+0xB179	0x7723	
+0xB17A	0x7724	
+0xB17B	0x7725	
+0xB17C	0x7727	
+0xB17D	0x772A	
+0xB17E	0x772B	
+0xB180	0x772C	
+0xB181	0x772E	
+0xB182	0x7730	
+0xB183	0x7731	
+0xB184	0x7732	
+0xB185	0x7733	
+0xB186	0x7734	
+0xB187	0x7739	
+0xB188	0x773B	
+0xB189	0x773D	
+0xB18A	0x773E	
+0xB18B	0x773F	
+0xB18C	0x7742	
+0xB18D	0x7744	
+0xB18E	0x7745	
+0xB18F	0x7746	
+0xB190	0x7748	
+0xB191	0x7749	
+0xB192	0x774A	
+0xB193	0x774B	
+0xB194	0x774C	
+0xB195	0x774D	
+0xB196	0x774E	
+0xB197	0x774F	
+0xB198	0x7752	
+0xB199	0x7753	
+0xB19A	0x7754	
+0xB19B	0x7755	
+0xB19C	0x7756	
+0xB19D	0x7757	
+0xB19E	0x7758	
+0xB19F	0x7759	
+0xB1A0	0x775C	
+0xB1A1	0x8584	
+0xB1A2	0x96F9	
+0xB1A3	0x4FDD	
+0xB1A4	0x5821	
+0xB1A5	0x9971	
+0xB1A6	0x5B9D	
+0xB1A7	0x62B1	
+0xB1A8	0x62A5	
+0xB1A9	0x66B4	
+0xB1AA	0x8C79	
+0xB1AB	0x9C8D	
+0xB1AC	0x7206	
+0xB1AD	0x676F	
+0xB1AE	0x7891	
+0xB1AF	0x60B2	
+0xB1B0	0x5351	
+0xB1B1	0x5317	
+0xB1B2	0x8F88	
+0xB1B3	0x80CC	
+0xB1B4	0x8D1D	
+0xB1B5	0x94A1	
+0xB1B6	0x500D	
+0xB1B7	0x72C8	
+0xB1B8	0x5907	
+0xB1B9	0x60EB	
+0xB1BA	0x7119	
+0xB1BB	0x88AB	
+0xB1BC	0x5954	
+0xB1BD	0x82EF	
+0xB1BE	0x672C	
+0xB1BF	0x7B28	
+0xB1C0	0x5D29	
+0xB1C1	0x7EF7	
+0xB1C2	0x752D	
+0xB1C3	0x6CF5	
+0xB1C4	0x8E66	
+0xB1C5	0x8FF8	
+0xB1C6	0x903C	
+0xB1C7	0x9F3B	
+0xB1C8	0x6BD4	
+0xB1C9	0x9119	
+0xB1CA	0x7B14	
+0xB1CB	0x5F7C	
+0xB1CC	0x78A7	
+0xB1CD	0x84D6	
+0xB1CE	0x853D	
+0xB1CF	0x6BD5	
+0xB1D0	0x6BD9	
+0xB1D1	0x6BD6	
+0xB1D2	0x5E01	
+0xB1D3	0x5E87	
+0xB1D4	0x75F9	
+0xB1D5	0x95ED	
+0xB1D6	0x655D	
+0xB1D7	0x5F0A	
+0xB1D8	0x5FC5	
+0xB1D9	0x8F9F	
+0xB1DA	0x58C1	
+0xB1DB	0x81C2	
+0xB1DC	0x907F	
+0xB1DD	0x965B	
+0xB1DE	0x97AD	
+0xB1DF	0x8FB9	
+0xB1E0	0x7F16	
+0xB1E1	0x8D2C	
+0xB1E2	0x6241	
+0xB1E3	0x4FBF	
+0xB1E4	0x53D8	
+0xB1E5	0x535E	
+0xB1E6	0x8FA8	
+0xB1E7	0x8FA9	
+0xB1E8	0x8FAB	
+0xB1E9	0x904D	
+0xB1EA	0x6807	
+0xB1EB	0x5F6A	
+0xB1EC	0x8198	
+0xB1ED	0x8868	
+0xB1EE	0x9CD6	
+0xB1EF	0x618B	
+0xB1F0	0x522B	
+0xB1F1	0x762A	
+0xB1F2	0x5F6C	
+0xB1F3	0x658C	
+0xB1F4	0x6FD2	
+0xB1F5	0x6EE8	
+0xB1F6	0x5BBE	
+0xB1F7	0x6448	
+0xB1F8	0x5175	
+0xB1F9	0x51B0	
+0xB1FA	0x67C4	
+0xB1FB	0x4E19	
+0xB1FC	0x79C9	
+0xB1FD	0x997C	
+0xB1FE	0x70B3	
+0xB240	0x775D	
+0xB241	0x775E	
+0xB242	0x775F	
+0xB243	0x7760	
+0xB244	0x7764	
+0xB245	0x7767	
+0xB246	0x7769	
+0xB247	0x776A	
+0xB248	0x776D	
+0xB249	0x776E	
+0xB24A	0x776F	
+0xB24B	0x7770	
+0xB24C	0x7771	
+0xB24D	0x7772	
+0xB24E	0x7773	
+0xB24F	0x7774	
+0xB250	0x7775	
+0xB251	0x7776	
+0xB252	0x7777	
+0xB253	0x7778	
+0xB254	0x777A	
+0xB255	0x777B	
+0xB256	0x777C	
+0xB257	0x7781	
+0xB258	0x7782	
+0xB259	0x7783	
+0xB25A	0x7786	
+0xB25B	0x7787	
+0xB25C	0x7788	
+0xB25D	0x7789	
+0xB25E	0x778A	
+0xB25F	0x778B	
+0xB260	0x778F	
+0xB261	0x7790	
+0xB262	0x7793	
+0xB263	0x7794	
+0xB264	0x7795	
+0xB265	0x7796	
+0xB266	0x7797	
+0xB267	0x7798	
+0xB268	0x7799	
+0xB269	0x779A	
+0xB26A	0x779B	
+0xB26B	0x779C	
+0xB26C	0x779D	
+0xB26D	0x779E	
+0xB26E	0x77A1	
+0xB26F	0x77A3	
+0xB270	0x77A4	
+0xB271	0x77A6	
+0xB272	0x77A8	
+0xB273	0x77AB	
+0xB274	0x77AD	
+0xB275	0x77AE	
+0xB276	0x77AF	
+0xB277	0x77B1	
+0xB278	0x77B2	
+0xB279	0x77B4	
+0xB27A	0x77B6	
+0xB27B	0x77B7	
+0xB27C	0x77B8	
+0xB27D	0x77B9	
+0xB27E	0x77BA	
+0xB280	0x77BC	
+0xB281	0x77BE	
+0xB282	0x77C0	
+0xB283	0x77C1	
+0xB284	0x77C2	
+0xB285	0x77C3	
+0xB286	0x77C4	
+0xB287	0x77C5	
+0xB288	0x77C6	
+0xB289	0x77C7	
+0xB28A	0x77C8	
+0xB28B	0x77C9	
+0xB28C	0x77CA	
+0xB28D	0x77CB	
+0xB28E	0x77CC	
+0xB28F	0x77CE	
+0xB290	0x77CF	
+0xB291	0x77D0	
+0xB292	0x77D1	
+0xB293	0x77D2	
+0xB294	0x77D3	
+0xB295	0x77D4	
+0xB296	0x77D5	
+0xB297	0x77D6	
+0xB298	0x77D8	
+0xB299	0x77D9	
+0xB29A	0x77DA	
+0xB29B	0x77DD	
+0xB29C	0x77DE	
+0xB29D	0x77DF	
+0xB29E	0x77E0	
+0xB29F	0x77E1	
+0xB2A0	0x77E4	
+0xB2A1	0x75C5	
+0xB2A2	0x5E76	
+0xB2A3	0x73BB	
+0xB2A4	0x83E0	
+0xB2A5	0x64AD	
+0xB2A6	0x62E8	
+0xB2A7	0x94B5	
+0xB2A8	0x6CE2	
+0xB2A9	0x535A	
+0xB2AA	0x52C3	
+0xB2AB	0x640F	
+0xB2AC	0x94C2	
+0xB2AD	0x7B94	
+0xB2AE	0x4F2F	
+0xB2AF	0x5E1B	
+0xB2B0	0x8236	
+0xB2B1	0x8116	
+0xB2B2	0x818A	
+0xB2B3	0x6E24	
+0xB2B4	0x6CCA	
+0xB2B5	0x9A73	
+0xB2B6	0x6355	
+0xB2B7	0x535C	
+0xB2B8	0x54FA	
+0xB2B9	0x8865	
+0xB2BA	0x57E0	
+0xB2BB	0x4E0D	
+0xB2BC	0x5E03	
+0xB2BD	0x6B65	
+0xB2BE	0x7C3F	
+0xB2BF	0x90E8	
+0xB2C0	0x6016	
+0xB2C1	0x64E6	
+0xB2C2	0x731C	
+0xB2C3	0x88C1	
+0xB2C4	0x6750	
+0xB2C5	0x624D	
+0xB2C6	0x8D22	
+0xB2C7	0x776C	
+0xB2C8	0x8E29	
+0xB2C9	0x91C7	
+0xB2CA	0x5F69	
+0xB2CB	0x83DC	
+0xB2CC	0x8521	
+0xB2CD	0x9910	
+0xB2CE	0x53C2	
+0xB2CF	0x8695	
+0xB2D0	0x6B8B	
+0xB2D1	0x60ED	
+0xB2D2	0x60E8	
+0xB2D3	0x707F	
+0xB2D4	0x82CD	
+0xB2D5	0x8231	
+0xB2D6	0x4ED3	
+0xB2D7	0x6CA7	
+0xB2D8	0x85CF	
+0xB2D9	0x64CD	
+0xB2DA	0x7CD9	
+0xB2DB	0x69FD	
+0xB2DC	0x66F9	
+0xB2DD	0x8349	
+0xB2DE	0x5395	
+0xB2DF	0x7B56	
+0xB2E0	0x4FA7	
+0xB2E1	0x518C	
+0xB2E2	0x6D4B	
+0xB2E3	0x5C42	
+0xB2E4	0x8E6D	
+0xB2E5	0x63D2	
+0xB2E6	0x53C9	
+0xB2E7	0x832C	
+0xB2E8	0x8336	
+0xB2E9	0x67E5	
+0xB2EA	0x78B4	
+0xB2EB	0x643D	
+0xB2EC	0x5BDF	
+0xB2ED	0x5C94	
+0xB2EE	0x5DEE	
+0xB2EF	0x8BE7	
+0xB2F0	0x62C6	
+0xB2F1	0x67F4	
+0xB2F2	0x8C7A	
+0xB2F3	0x6400	
+0xB2F4	0x63BA	
+0xB2F5	0x8749	
+0xB2F6	0x998B	
+0xB2F7	0x8C17	
+0xB2F8	0x7F20	
+0xB2F9	0x94F2	
+0xB2FA	0x4EA7	
+0xB2FB	0x9610	
+0xB2FC	0x98A4	
+0xB2FD	0x660C	
+0xB2FE	0x7316	
+0xB340	0x77E6	
+0xB341	0x77E8	
+0xB342	0x77EA	
+0xB343	0x77EF	
+0xB344	0x77F0	
+0xB345	0x77F1	
+0xB346	0x77F2	
+0xB347	0x77F4	
+0xB348	0x77F5	
+0xB349	0x77F7	
+0xB34A	0x77F9	
+0xB34B	0x77FA	
+0xB34C	0x77FB	
+0xB34D	0x77FC	
+0xB34E	0x7803	
+0xB34F	0x7804	
+0xB350	0x7805	
+0xB351	0x7806	
+0xB352	0x7807	
+0xB353	0x7808	
+0xB354	0x780A	
+0xB355	0x780B	
+0xB356	0x780E	
+0xB357	0x780F	
+0xB358	0x7810	
+0xB359	0x7813	
+0xB35A	0x7815	
+0xB35B	0x7819	
+0xB35C	0x781B	
+0xB35D	0x781E	
+0xB35E	0x7820	
+0xB35F	0x7821	
+0xB360	0x7822	
+0xB361	0x7824	
+0xB362	0x7828	
+0xB363	0x782A	
+0xB364	0x782B	
+0xB365	0x782E	
+0xB366	0x782F	
+0xB367	0x7831	
+0xB368	0x7832	
+0xB369	0x7833	
+0xB36A	0x7835	
+0xB36B	0x7836	
+0xB36C	0x783D	
+0xB36D	0x783F	
+0xB36E	0x7841	
+0xB36F	0x7842	
+0xB370	0x7843	
+0xB371	0x7844	
+0xB372	0x7846	
+0xB373	0x7848	
+0xB374	0x7849	
+0xB375	0x784A	
+0xB376	0x784B	
+0xB377	0x784D	
+0xB378	0x784F	
+0xB379	0x7851	
+0xB37A	0x7853	
+0xB37B	0x7854	
+0xB37C	0x7858	
+0xB37D	0x7859	
+0xB37E	0x785A	
+0xB380	0x785B	
+0xB381	0x785C	
+0xB382	0x785E	
+0xB383	0x785F	
+0xB384	0x7860	
+0xB385	0x7861	
+0xB386	0x7862	
+0xB387	0x7863	
+0xB388	0x7864	
+0xB389	0x7865	
+0xB38A	0x7866	
+0xB38B	0x7867	
+0xB38C	0x7868	
+0xB38D	0x7869	
+0xB38E	0x786F	
+0xB38F	0x7870	
+0xB390	0x7871	
+0xB391	0x7872	
+0xB392	0x7873	
+0xB393	0x7874	
+0xB394	0x7875	
+0xB395	0x7876	
+0xB396	0x7878	
+0xB397	0x7879	
+0xB398	0x787A	
+0xB399	0x787B	
+0xB39A	0x787D	
+0xB39B	0x787E	
+0xB39C	0x787F	
+0xB39D	0x7880	
+0xB39E	0x7881	
+0xB39F	0x7882	
+0xB3A0	0x7883	
+0xB3A1	0x573A	
+0xB3A2	0x5C1D	
+0xB3A3	0x5E38	
+0xB3A4	0x957F	
+0xB3A5	0x507F	
+0xB3A6	0x80A0	
+0xB3A7	0x5382	
+0xB3A8	0x655E	
+0xB3A9	0x7545	
+0xB3AA	0x5531	
+0xB3AB	0x5021	
+0xB3AC	0x8D85	
+0xB3AD	0x6284	
+0xB3AE	0x949E	
+0xB3AF	0x671D	
+0xB3B0	0x5632	
+0xB3B1	0x6F6E	
+0xB3B2	0x5DE2	
+0xB3B3	0x5435	
+0xB3B4	0x7092	
+0xB3B5	0x8F66	
+0xB3B6	0x626F	
+0xB3B7	0x64A4	
+0xB3B8	0x63A3	
+0xB3B9	0x5F7B	
+0xB3BA	0x6F88	
+0xB3BB	0x90F4	
+0xB3BC	0x81E3	
+0xB3BD	0x8FB0	
+0xB3BE	0x5C18	
+0xB3BF	0x6668	
+0xB3C0	0x5FF1	
+0xB3C1	0x6C89	
+0xB3C2	0x9648	
+0xB3C3	0x8D81	
+0xB3C4	0x886C	
+0xB3C5	0x6491	
+0xB3C6	0x79F0	
+0xB3C7	0x57CE	
+0xB3C8	0x6A59	
+0xB3C9	0x6210	
+0xB3CA	0x5448	
+0xB3CB	0x4E58	
+0xB3CC	0x7A0B	
+0xB3CD	0x60E9	
+0xB3CE	0x6F84	
+0xB3CF	0x8BDA	
+0xB3D0	0x627F	
+0xB3D1	0x901E	
+0xB3D2	0x9A8B	
+0xB3D3	0x79E4	
+0xB3D4	0x5403	
+0xB3D5	0x75F4	
+0xB3D6	0x6301	
+0xB3D7	0x5319	
+0xB3D8	0x6C60	
+0xB3D9	0x8FDF	
+0xB3DA	0x5F1B	
+0xB3DB	0x9A70	
+0xB3DC	0x803B	
+0xB3DD	0x9F7F	
+0xB3DE	0x4F88	
+0xB3DF	0x5C3A	
+0xB3E0	0x8D64	
+0xB3E1	0x7FC5	
+0xB3E2	0x65A5	
+0xB3E3	0x70BD	
+0xB3E4	0x5145	
+0xB3E5	0x51B2	
+0xB3E6	0x866B	
+0xB3E7	0x5D07	
+0xB3E8	0x5BA0	
+0xB3E9	0x62BD	
+0xB3EA	0x916C	
+0xB3EB	0x7574	
+0xB3EC	0x8E0C	
+0xB3ED	0x7A20	
+0xB3EE	0x6101	
+0xB3EF	0x7B79	
+0xB3F0	0x4EC7	
+0xB3F1	0x7EF8	
+0xB3F2	0x7785	
+0xB3F3	0x4E11	
+0xB3F4	0x81ED	
+0xB3F5	0x521D	
+0xB3F6	0x51FA	
+0xB3F7	0x6A71	
+0xB3F8	0x53A8	
+0xB3F9	0x8E87	
+0xB3FA	0x9504	
+0xB3FB	0x96CF	
+0xB3FC	0x6EC1	
+0xB3FD	0x9664	
+0xB3FE	0x695A	
+0xB440	0x7884	
+0xB441	0x7885	
+0xB442	0x7886	
+0xB443	0x7888	
+0xB444	0x788A	
+0xB445	0x788B	
+0xB446	0x788F	
+0xB447	0x7890	
+0xB448	0x7892	
+0xB449	0x7894	
+0xB44A	0x7895	
+0xB44B	0x7896	
+0xB44C	0x7899	
+0xB44D	0x789D	
+0xB44E	0x789E	
+0xB44F	0x78A0	
+0xB450	0x78A2	
+0xB451	0x78A4	
+0xB452	0x78A6	
+0xB453	0x78A8	
+0xB454	0x78A9	
+0xB455	0x78AA	
+0xB456	0x78AB	
+0xB457	0x78AC	
+0xB458	0x78AD	
+0xB459	0x78AE	
+0xB45A	0x78AF	
+0xB45B	0x78B5	
+0xB45C	0x78B6	
+0xB45D	0x78B7	
+0xB45E	0x78B8	
+0xB45F	0x78BA	
+0xB460	0x78BB	
+0xB461	0x78BC	
+0xB462	0x78BD	
+0xB463	0x78BF	
+0xB464	0x78C0	
+0xB465	0x78C2	
+0xB466	0x78C3	
+0xB467	0x78C4	
+0xB468	0x78C6	
+0xB469	0x78C7	
+0xB46A	0x78C8	
+0xB46B	0x78CC	
+0xB46C	0x78CD	
+0xB46D	0x78CE	
+0xB46E	0x78CF	
+0xB46F	0x78D1	
+0xB470	0x78D2	
+0xB471	0x78D3	
+0xB472	0x78D6	
+0xB473	0x78D7	
+0xB474	0x78D8	
+0xB475	0x78DA	
+0xB476	0x78DB	
+0xB477	0x78DC	
+0xB478	0x78DD	
+0xB479	0x78DE	
+0xB47A	0x78DF	
+0xB47B	0x78E0	
+0xB47C	0x78E1	
+0xB47D	0x78E2	
+0xB47E	0x78E3	
+0xB480	0x78E4	
+0xB481	0x78E5	
+0xB482	0x78E6	
+0xB483	0x78E7	
+0xB484	0x78E9	
+0xB485	0x78EA	
+0xB486	0x78EB	
+0xB487	0x78ED	
+0xB488	0x78EE	
+0xB489	0x78EF	
+0xB48A	0x78F0	
+0xB48B	0x78F1	
+0xB48C	0x78F3	
+0xB48D	0x78F5	
+0xB48E	0x78F6	
+0xB48F	0x78F8	
+0xB490	0x78F9	
+0xB491	0x78FB	
+0xB492	0x78FC	
+0xB493	0x78FD	
+0xB494	0x78FE	
+0xB495	0x78FF	
+0xB496	0x7900	
+0xB497	0x7902	
+0xB498	0x7903	
+0xB499	0x7904	
+0xB49A	0x7906	
+0xB49B	0x7907	
+0xB49C	0x7908	
+0xB49D	0x7909	
+0xB49E	0x790A	
+0xB49F	0x790B	
+0xB4A0	0x790C	
+0xB4A1	0x7840	
+0xB4A2	0x50A8	
+0xB4A3	0x77D7	
+0xB4A4	0x6410	
+0xB4A5	0x89E6	
+0xB4A6	0x5904	
+0xB4A7	0x63E3	
+0xB4A8	0x5DDD	
+0xB4A9	0x7A7F	
+0xB4AA	0x693D	
+0xB4AB	0x4F20	
+0xB4AC	0x8239	
+0xB4AD	0x5598	
+0xB4AE	0x4E32	
+0xB4AF	0x75AE	
+0xB4B0	0x7A97	
+0xB4B1	0x5E62	
+0xB4B2	0x5E8A	
+0xB4B3	0x95EF	
+0xB4B4	0x521B	
+0xB4B5	0x5439	
+0xB4B6	0x708A	
+0xB4B7	0x6376	
+0xB4B8	0x9524	
+0xB4B9	0x5782	
+0xB4BA	0x6625	
+0xB4BB	0x693F	
+0xB4BC	0x9187	
+0xB4BD	0x5507	
+0xB4BE	0x6DF3	
+0xB4BF	0x7EAF	
+0xB4C0	0x8822	
+0xB4C1	0x6233	
+0xB4C2	0x7EF0	
+0xB4C3	0x75B5	
+0xB4C4	0x8328	
+0xB4C5	0x78C1	
+0xB4C6	0x96CC	
+0xB4C7	0x8F9E	
+0xB4C8	0x6148	
+0xB4C9	0x74F7	
+0xB4CA	0x8BCD	
+0xB4CB	0x6B64	
+0xB4CC	0x523A	
+0xB4CD	0x8D50	
+0xB4CE	0x6B21	
+0xB4CF	0x806A	
+0xB4D0	0x8471	
+0xB4D1	0x56F1	
+0xB4D2	0x5306	
+0xB4D3	0x4ECE	
+0xB4D4	0x4E1B	
+0xB4D5	0x51D1	
+0xB4D6	0x7C97	
+0xB4D7	0x918B	
+0xB4D8	0x7C07	
+0xB4D9	0x4FC3	
+0xB4DA	0x8E7F	
+0xB4DB	0x7BE1	
+0xB4DC	0x7A9C	
+0xB4DD	0x6467	
+0xB4DE	0x5D14	
+0xB4DF	0x50AC	
+0xB4E0	0x8106	
+0xB4E1	0x7601	
+0xB4E2	0x7CB9	
+0xB4E3	0x6DEC	
+0xB4E4	0x7FE0	
+0xB4E5	0x6751	
+0xB4E6	0x5B58	
+0xB4E7	0x5BF8	
+0xB4E8	0x78CB	
+0xB4E9	0x64AE	
+0xB4EA	0x6413	
+0xB4EB	0x63AA	
+0xB4EC	0x632B	
+0xB4ED	0x9519	
+0xB4EE	0x642D	
+0xB4EF	0x8FBE	
+0xB4F0	0x7B54	
+0xB4F1	0x7629	
+0xB4F2	0x6253	
+0xB4F3	0x5927	
+0xB4F4	0x5446	
+0xB4F5	0x6B79	
+0xB4F6	0x50A3	
+0xB4F7	0x6234	
+0xB4F8	0x5E26	
+0xB4F9	0x6B86	
+0xB4FA	0x4EE3	
+0xB4FB	0x8D37	
+0xB4FC	0x888B	
+0xB4FD	0x5F85	
+0xB4FE	0x902E	
+0xB540	0x790D	
+0xB541	0x790E	
+0xB542	0x790F	
+0xB543	0x7910	
+0xB544	0x7911	
+0xB545	0x7912	
+0xB546	0x7914	
+0xB547	0x7915	
+0xB548	0x7916	
+0xB549	0x7917	
+0xB54A	0x7918	
+0xB54B	0x7919	
+0xB54C	0x791A	
+0xB54D	0x791B	
+0xB54E	0x791C	
+0xB54F	0x791D	
+0xB550	0x791F	
+0xB551	0x7920	
+0xB552	0x7921	
+0xB553	0x7922	
+0xB554	0x7923	
+0xB555	0x7925	
+0xB556	0x7926	
+0xB557	0x7927	
+0xB558	0x7928	
+0xB559	0x7929	
+0xB55A	0x792A	
+0xB55B	0x792B	
+0xB55C	0x792C	
+0xB55D	0x792D	
+0xB55E	0x792E	
+0xB55F	0x792F	
+0xB560	0x7930	
+0xB561	0x7931	
+0xB562	0x7932	
+0xB563	0x7933	
+0xB564	0x7935	
+0xB565	0x7936	
+0xB566	0x7937	
+0xB567	0x7938	
+0xB568	0x7939	
+0xB569	0x793D	
+0xB56A	0x793F	
+0xB56B	0x7942	
+0xB56C	0x7943	
+0xB56D	0x7944	
+0xB56E	0x7945	
+0xB56F	0x7947	
+0xB570	0x794A	
+0xB571	0x794B	
+0xB572	0x794C	
+0xB573	0x794D	
+0xB574	0x794E	
+0xB575	0x794F	
+0xB576	0x7950	
+0xB577	0x7951	
+0xB578	0x7952	
+0xB579	0x7954	
+0xB57A	0x7955	
+0xB57B	0x7958	
+0xB57C	0x7959	
+0xB57D	0x7961	
+0xB57E	0x7963	
+0xB580	0x7964	
+0xB581	0x7966	
+0xB582	0x7969	
+0xB583	0x796A	
+0xB584	0x796B	
+0xB585	0x796C	
+0xB586	0x796E	
+0xB587	0x7970	
+0xB588	0x7971	
+0xB589	0x7972	
+0xB58A	0x7973	
+0xB58B	0x7974	
+0xB58C	0x7975	
+0xB58D	0x7976	
+0xB58E	0x7979	
+0xB58F	0x797B	
+0xB590	0x797C	
+0xB591	0x797D	
+0xB592	0x797E	
+0xB593	0x797F	
+0xB594	0x7982	
+0xB595	0x7983	
+0xB596	0x7986	
+0xB597	0x7987	
+0xB598	0x7988	
+0xB599	0x7989	
+0xB59A	0x798B	
+0xB59B	0x798C	
+0xB59C	0x798D	
+0xB59D	0x798E	
+0xB59E	0x7990	
+0xB59F	0x7991	
+0xB5A0	0x7992	
+0xB5A1	0x6020	
+0xB5A2	0x803D	
+0xB5A3	0x62C5	
+0xB5A4	0x4E39	
+0xB5A5	0x5355	
+0xB5A6	0x90F8	
+0xB5A7	0x63B8	
+0xB5A8	0x80C6	
+0xB5A9	0x65E6	
+0xB5AA	0x6C2E	
+0xB5AB	0x4F46	
+0xB5AC	0x60EE	
+0xB5AD	0x6DE1	
+0xB5AE	0x8BDE	
+0xB5AF	0x5F39	
+0xB5B0	0x86CB	
+0xB5B1	0x5F53	
+0xB5B2	0x6321	
+0xB5B3	0x515A	
+0xB5B4	0x8361	
+0xB5B5	0x6863	
+0xB5B6	0x5200	
+0xB5B7	0x6363	
+0xB5B8	0x8E48	
+0xB5B9	0x5012	
+0xB5BA	0x5C9B	
+0xB5BB	0x7977	
+0xB5BC	0x5BFC	
+0xB5BD	0x5230	
+0xB5BE	0x7A3B	
+0xB5BF	0x60BC	
+0xB5C0	0x9053	
+0xB5C1	0x76D7	
+0xB5C2	0x5FB7	
+0xB5C3	0x5F97	
+0xB5C4	0x7684	
+0xB5C5	0x8E6C	
+0xB5C6	0x706F	
+0xB5C7	0x767B	
+0xB5C8	0x7B49	
+0xB5C9	0x77AA	
+0xB5CA	0x51F3	
+0xB5CB	0x9093	
+0xB5CC	0x5824	
+0xB5CD	0x4F4E	
+0xB5CE	0x6EF4	
+0xB5CF	0x8FEA	
+0xB5D0	0x654C	
+0xB5D1	0x7B1B	
+0xB5D2	0x72C4	
+0xB5D3	0x6DA4	
+0xB5D4	0x7FDF	
+0xB5D5	0x5AE1	
+0xB5D6	0x62B5	
+0xB5D7	0x5E95	
+0xB5D8	0x5730	
+0xB5D9	0x8482	
+0xB5DA	0x7B2C	
+0xB5DB	0x5E1D	
+0xB5DC	0x5F1F	
+0xB5DD	0x9012	
+0xB5DE	0x7F14	
+0xB5DF	0x98A0	
+0xB5E0	0x6382	
+0xB5E1	0x6EC7	
+0xB5E2	0x7898	
+0xB5E3	0x70B9	
+0xB5E4	0x5178	
+0xB5E5	0x975B	
+0xB5E6	0x57AB	
+0xB5E7	0x7535	
+0xB5E8	0x4F43	
+0xB5E9	0x7538	
+0xB5EA	0x5E97	
+0xB5EB	0x60E6	
+0xB5EC	0x5960	
+0xB5ED	0x6DC0	
+0xB5EE	0x6BBF	
+0xB5EF	0x7889	
+0xB5F0	0x53FC	
+0xB5F1	0x96D5	
+0xB5F2	0x51CB	
+0xB5F3	0x5201	
+0xB5F4	0x6389	
+0xB5F5	0x540A	
+0xB5F6	0x9493	
+0xB5F7	0x8C03	
+0xB5F8	0x8DCC	
+0xB5F9	0x7239	
+0xB5FA	0x789F	
+0xB5FB	0x8776	
+0xB5FC	0x8FED	
+0xB5FD	0x8C0D	
+0xB5FE	0x53E0	
+0xB640	0x7993	
+0xB641	0x7994	
+0xB642	0x7995	
+0xB643	0x7996	
+0xB644	0x7997	
+0xB645	0x7998	
+0xB646	0x7999	
+0xB647	0x799B	
+0xB648	0x799C	
+0xB649	0x799D	
+0xB64A	0x799E	
+0xB64B	0x799F	
+0xB64C	0x79A0	
+0xB64D	0x79A1	
+0xB64E	0x79A2	
+0xB64F	0x79A3	
+0xB650	0x79A4	
+0xB651	0x79A5	
+0xB652	0x79A6	
+0xB653	0x79A8	
+0xB654	0x79A9	
+0xB655	0x79AA	
+0xB656	0x79AB	
+0xB657	0x79AC	
+0xB658	0x79AD	
+0xB659	0x79AE	
+0xB65A	0x79AF	
+0xB65B	0x79B0	
+0xB65C	0x79B1	
+0xB65D	0x79B2	
+0xB65E	0x79B4	
+0xB65F	0x79B5	
+0xB660	0x79B6	
+0xB661	0x79B7	
+0xB662	0x79B8	
+0xB663	0x79BC	
+0xB664	0x79BF	
+0xB665	0x79C2	
+0xB666	0x79C4	
+0xB667	0x79C5	
+0xB668	0x79C7	
+0xB669	0x79C8	
+0xB66A	0x79CA	
+0xB66B	0x79CC	
+0xB66C	0x79CE	
+0xB66D	0x79CF	
+0xB66E	0x79D0	
+0xB66F	0x79D3	
+0xB670	0x79D4	
+0xB671	0x79D6	
+0xB672	0x79D7	
+0xB673	0x79D9	
+0xB674	0x79DA	
+0xB675	0x79DB	
+0xB676	0x79DC	
+0xB677	0x79DD	
+0xB678	0x79DE	
+0xB679	0x79E0	
+0xB67A	0x79E1	
+0xB67B	0x79E2	
+0xB67C	0x79E5	
+0xB67D	0x79E8	
+0xB67E	0x79EA	
+0xB680	0x79EC	
+0xB681	0x79EE	
+0xB682	0x79F1	
+0xB683	0x79F2	
+0xB684	0x79F3	
+0xB685	0x79F4	
+0xB686	0x79F5	
+0xB687	0x79F6	
+0xB688	0x79F7	
+0xB689	0x79F9	
+0xB68A	0x79FA	
+0xB68B	0x79FC	
+0xB68C	0x79FE	
+0xB68D	0x79FF	
+0xB68E	0x7A01	
+0xB68F	0x7A04	
+0xB690	0x7A05	
+0xB691	0x7A07	
+0xB692	0x7A08	
+0xB693	0x7A09	
+0xB694	0x7A0A	
+0xB695	0x7A0C	
+0xB696	0x7A0F	
+0xB697	0x7A10	
+0xB698	0x7A11	
+0xB699	0x7A12	
+0xB69A	0x7A13	
+0xB69B	0x7A15	
+0xB69C	0x7A16	
+0xB69D	0x7A18	
+0xB69E	0x7A19	
+0xB69F	0x7A1B	
+0xB6A0	0x7A1C	
+0xB6A1	0x4E01	
+0xB6A2	0x76EF	
+0xB6A3	0x53EE	
+0xB6A4	0x9489	
+0xB6A5	0x9876	
+0xB6A6	0x9F0E	
+0xB6A7	0x952D	
+0xB6A8	0x5B9A	
+0xB6A9	0x8BA2	
+0xB6AA	0x4E22	
+0xB6AB	0x4E1C	
+0xB6AC	0x51AC	
+0xB6AD	0x8463	
+0xB6AE	0x61C2	
+0xB6AF	0x52A8	
+0xB6B0	0x680B	
+0xB6B1	0x4F97	
+0xB6B2	0x606B	
+0xB6B3	0x51BB	
+0xB6B4	0x6D1E	
+0xB6B5	0x515C	
+0xB6B6	0x6296	
+0xB6B7	0x6597	
+0xB6B8	0x9661	
+0xB6B9	0x8C46	
+0xB6BA	0x9017	
+0xB6BB	0x75D8	
+0xB6BC	0x90FD	
+0xB6BD	0x7763	
+0xB6BE	0x6BD2	
+0xB6BF	0x728A	
+0xB6C0	0x72EC	
+0xB6C1	0x8BFB	
+0xB6C2	0x5835	
+0xB6C3	0x7779	
+0xB6C4	0x8D4C	
+0xB6C5	0x675C	
+0xB6C6	0x9540	
+0xB6C7	0x809A	
+0xB6C8	0x5EA6	
+0xB6C9	0x6E21	
+0xB6CA	0x5992	
+0xB6CB	0x7AEF	
+0xB6CC	0x77ED	
+0xB6CD	0x953B	
+0xB6CE	0x6BB5	
+0xB6CF	0x65AD	
+0xB6D0	0x7F0E	
+0xB6D1	0x5806	
+0xB6D2	0x5151	
+0xB6D3	0x961F	
+0xB6D4	0x5BF9	
+0xB6D5	0x58A9	
+0xB6D6	0x5428	
+0xB6D7	0x8E72	
+0xB6D8	0x6566	
+0xB6D9	0x987F	
+0xB6DA	0x56E4	
+0xB6DB	0x949D	
+0xB6DC	0x76FE	
+0xB6DD	0x9041	
+0xB6DE	0x6387	
+0xB6DF	0x54C6	
+0xB6E0	0x591A	
+0xB6E1	0x593A	
+0xB6E2	0x579B	
+0xB6E3	0x8EB2	
+0xB6E4	0x6735	
+0xB6E5	0x8DFA	
+0xB6E6	0x8235	
+0xB6E7	0x5241	
+0xB6E8	0x60F0	
+0xB6E9	0x5815	
+0xB6EA	0x86FE	
+0xB6EB	0x5CE8	
+0xB6EC	0x9E45	
+0xB6ED	0x4FC4	
+0xB6EE	0x989D	
+0xB6EF	0x8BB9	
+0xB6F0	0x5A25	
+0xB6F1	0x6076	
+0xB6F2	0x5384	
+0xB6F3	0x627C	
+0xB6F4	0x904F	
+0xB6F5	0x9102	
+0xB6F6	0x997F	
+0xB6F7	0x6069	
+0xB6F8	0x800C	
+0xB6F9	0x513F	
+0xB6FA	0x8033	
+0xB6FB	0x5C14	
+0xB6FC	0x9975	
+0xB6FD	0x6D31	
+0xB6FE	0x4E8C	
+0xB740	0x7A1D	
+0xB741	0x7A1F	
+0xB742	0x7A21	
+0xB743	0x7A22	
+0xB744	0x7A24	
+0xB745	0x7A25	
+0xB746	0x7A26	
+0xB747	0x7A27	
+0xB748	0x7A28	
+0xB749	0x7A29	
+0xB74A	0x7A2A	
+0xB74B	0x7A2B	
+0xB74C	0x7A2C	
+0xB74D	0x7A2D	
+0xB74E	0x7A2E	
+0xB74F	0x7A2F	
+0xB750	0x7A30	
+0xB751	0x7A31	
+0xB752	0x7A32	
+0xB753	0x7A34	
+0xB754	0x7A35	
+0xB755	0x7A36	
+0xB756	0x7A38	
+0xB757	0x7A3A	
+0xB758	0x7A3E	
+0xB759	0x7A40	
+0xB75A	0x7A41	
+0xB75B	0x7A42	
+0xB75C	0x7A43	
+0xB75D	0x7A44	
+0xB75E	0x7A45	
+0xB75F	0x7A47	
+0xB760	0x7A48	
+0xB761	0x7A49	
+0xB762	0x7A4A	
+0xB763	0x7A4B	
+0xB764	0x7A4C	
+0xB765	0x7A4D	
+0xB766	0x7A4E	
+0xB767	0x7A4F	
+0xB768	0x7A50	
+0xB769	0x7A52	
+0xB76A	0x7A53	
+0xB76B	0x7A54	
+0xB76C	0x7A55	
+0xB76D	0x7A56	
+0xB76E	0x7A58	
+0xB76F	0x7A59	
+0xB770	0x7A5A	
+0xB771	0x7A5B	
+0xB772	0x7A5C	
+0xB773	0x7A5D	
+0xB774	0x7A5E	
+0xB775	0x7A5F	
+0xB776	0x7A60	
+0xB777	0x7A61	
+0xB778	0x7A62	
+0xB779	0x7A63	
+0xB77A	0x7A64	
+0xB77B	0x7A65	
+0xB77C	0x7A66	
+0xB77D	0x7A67	
+0xB77E	0x7A68	
+0xB780	0x7A69	
+0xB781	0x7A6A	
+0xB782	0x7A6B	
+0xB783	0x7A6C	
+0xB784	0x7A6D	
+0xB785	0x7A6E	
+0xB786	0x7A6F	
+0xB787	0x7A71	
+0xB788	0x7A72	
+0xB789	0x7A73	
+0xB78A	0x7A75	
+0xB78B	0x7A7B	
+0xB78C	0x7A7C	
+0xB78D	0x7A7D	
+0xB78E	0x7A7E	
+0xB78F	0x7A82	
+0xB790	0x7A85	
+0xB791	0x7A87	
+0xB792	0x7A89	
+0xB793	0x7A8A	
+0xB794	0x7A8B	
+0xB795	0x7A8C	
+0xB796	0x7A8E	
+0xB797	0x7A8F	
+0xB798	0x7A90	
+0xB799	0x7A93	
+0xB79A	0x7A94	
+0xB79B	0x7A99	
+0xB79C	0x7A9A	
+0xB79D	0x7A9B	
+0xB79E	0x7A9E	
+0xB79F	0x7AA1	
+0xB7A0	0x7AA2	
+0xB7A1	0x8D30	
+0xB7A2	0x53D1	
+0xB7A3	0x7F5A	
+0xB7A4	0x7B4F	
+0xB7A5	0x4F10	
+0xB7A6	0x4E4F	
+0xB7A7	0x9600	
+0xB7A8	0x6CD5	
+0xB7A9	0x73D0	
+0xB7AA	0x85E9	
+0xB7AB	0x5E06	
+0xB7AC	0x756A	
+0xB7AD	0x7FFB	
+0xB7AE	0x6A0A	
+0xB7AF	0x77FE	
+0xB7B0	0x9492	
+0xB7B1	0x7E41	
+0xB7B2	0x51E1	
+0xB7B3	0x70E6	
+0xB7B4	0x53CD	
+0xB7B5	0x8FD4	
+0xB7B6	0x8303	
+0xB7B7	0x8D29	
+0xB7B8	0x72AF	
+0xB7B9	0x996D	
+0xB7BA	0x6CDB	
+0xB7BB	0x574A	
+0xB7BC	0x82B3	
+0xB7BD	0x65B9	
+0xB7BE	0x80AA	
+0xB7BF	0x623F	
+0xB7C0	0x9632	
+0xB7C1	0x59A8	
+0xB7C2	0x4EFF	
+0xB7C3	0x8BBF	
+0xB7C4	0x7EBA	
+0xB7C5	0x653E	
+0xB7C6	0x83F2	
+0xB7C7	0x975E	
+0xB7C8	0x5561	
+0xB7C9	0x98DE	
+0xB7CA	0x80A5	
+0xB7CB	0x532A	
+0xB7CC	0x8BFD	
+0xB7CD	0x5420	
+0xB7CE	0x80BA	
+0xB7CF	0x5E9F	
+0xB7D0	0x6CB8	
+0xB7D1	0x8D39	
+0xB7D2	0x82AC	
+0xB7D3	0x915A	
+0xB7D4	0x5429	
+0xB7D5	0x6C1B	
+0xB7D6	0x5206	
+0xB7D7	0x7EB7	
+0xB7D8	0x575F	
+0xB7D9	0x711A	
+0xB7DA	0x6C7E	
+0xB7DB	0x7C89	
+0xB7DC	0x594B	
+0xB7DD	0x4EFD	
+0xB7DE	0x5FFF	
+0xB7DF	0x6124	
+0xB7E0	0x7CAA	
+0xB7E1	0x4E30	
+0xB7E2	0x5C01	
+0xB7E3	0x67AB	
+0xB7E4	0x8702	
+0xB7E5	0x5CF0	
+0xB7E6	0x950B	
+0xB7E7	0x98CE	
+0xB7E8	0x75AF	
+0xB7E9	0x70FD	
+0xB7EA	0x9022	
+0xB7EB	0x51AF	
+0xB7EC	0x7F1D	
+0xB7ED	0x8BBD	
+0xB7EE	0x5949	
+0xB7EF	0x51E4	
+0xB7F0	0x4F5B	
+0xB7F1	0x5426	
+0xB7F2	0x592B	
+0xB7F3	0x6577	
+0xB7F4	0x80A4	
+0xB7F5	0x5B75	
+0xB7F6	0x6276	
+0xB7F7	0x62C2	
+0xB7F8	0x8F90	
+0xB7F9	0x5E45	
+0xB7FA	0x6C1F	
+0xB7FB	0x7B26	
+0xB7FC	0x4F0F	
+0xB7FD	0x4FD8	
+0xB7FE	0x670D	
+0xB840	0x7AA3	
+0xB841	0x7AA4	
+0xB842	0x7AA7	
+0xB843	0x7AA9	
+0xB844	0x7AAA	
+0xB845	0x7AAB	
+0xB846	0x7AAE	
+0xB847	0x7AAF	
+0xB848	0x7AB0	
+0xB849	0x7AB1	
+0xB84A	0x7AB2	
+0xB84B	0x7AB4	
+0xB84C	0x7AB5	
+0xB84D	0x7AB6	
+0xB84E	0x7AB7	
+0xB84F	0x7AB8	
+0xB850	0x7AB9	
+0xB851	0x7ABA	
+0xB852	0x7ABB	
+0xB853	0x7ABC	
+0xB854	0x7ABD	
+0xB855	0x7ABE	
+0xB856	0x7AC0	
+0xB857	0x7AC1	
+0xB858	0x7AC2	
+0xB859	0x7AC3	
+0xB85A	0x7AC4	
+0xB85B	0x7AC5	
+0xB85C	0x7AC6	
+0xB85D	0x7AC7	
+0xB85E	0x7AC8	
+0xB85F	0x7AC9	
+0xB860	0x7ACA	
+0xB861	0x7ACC	
+0xB862	0x7ACD	
+0xB863	0x7ACE	
+0xB864	0x7ACF	
+0xB865	0x7AD0	
+0xB866	0x7AD1	
+0xB867	0x7AD2	
+0xB868	0x7AD3	
+0xB869	0x7AD4	
+0xB86A	0x7AD5	
+0xB86B	0x7AD7	
+0xB86C	0x7AD8	
+0xB86D	0x7ADA	
+0xB86E	0x7ADB	
+0xB86F	0x7ADC	
+0xB870	0x7ADD	
+0xB871	0x7AE1	
+0xB872	0x7AE2	
+0xB873	0x7AE4	
+0xB874	0x7AE7	
+0xB875	0x7AE8	
+0xB876	0x7AE9	
+0xB877	0x7AEA	
+0xB878	0x7AEB	
+0xB879	0x7AEC	
+0xB87A	0x7AEE	
+0xB87B	0x7AF0	
+0xB87C	0x7AF1	
+0xB87D	0x7AF2	
+0xB87E	0x7AF3	
+0xB880	0x7AF4	
+0xB881	0x7AF5	
+0xB882	0x7AF6	
+0xB883	0x7AF7	
+0xB884	0x7AF8	
+0xB885	0x7AFB	
+0xB886	0x7AFC	
+0xB887	0x7AFE	
+0xB888	0x7B00	
+0xB889	0x7B01	
+0xB88A	0x7B02	
+0xB88B	0x7B05	
+0xB88C	0x7B07	
+0xB88D	0x7B09	
+0xB88E	0x7B0C	
+0xB88F	0x7B0D	
+0xB890	0x7B0E	
+0xB891	0x7B10	
+0xB892	0x7B12	
+0xB893	0x7B13	
+0xB894	0x7B16	
+0xB895	0x7B17	
+0xB896	0x7B18	
+0xB897	0x7B1A	
+0xB898	0x7B1C	
+0xB899	0x7B1D	
+0xB89A	0x7B1F	
+0xB89B	0x7B21	
+0xB89C	0x7B22	
+0xB89D	0x7B23	
+0xB89E	0x7B27	
+0xB89F	0x7B29	
+0xB8A0	0x7B2D	
+0xB8A1	0x6D6E	
+0xB8A2	0x6DAA	
+0xB8A3	0x798F	
+0xB8A4	0x88B1	
+0xB8A5	0x5F17	
+0xB8A6	0x752B	
+0xB8A7	0x629A	
+0xB8A8	0x8F85	
+0xB8A9	0x4FEF	
+0xB8AA	0x91DC	
+0xB8AB	0x65A7	
+0xB8AC	0x812F	
+0xB8AD	0x8151	
+0xB8AE	0x5E9C	
+0xB8AF	0x8150	
+0xB8B0	0x8D74	
+0xB8B1	0x526F	
+0xB8B2	0x8986	
+0xB8B3	0x8D4B	
+0xB8B4	0x590D	
+0xB8B5	0x5085	
+0xB8B6	0x4ED8	
+0xB8B7	0x961C	
+0xB8B8	0x7236	
+0xB8B9	0x8179	
+0xB8BA	0x8D1F	
+0xB8BB	0x5BCC	
+0xB8BC	0x8BA3	
+0xB8BD	0x9644	
+0xB8BE	0x5987	
+0xB8BF	0x7F1A	
+0xB8C0	0x5490	
+0xB8C1	0x5676	
+0xB8C2	0x560E	
+0xB8C3	0x8BE5	
+0xB8C4	0x6539	
+0xB8C5	0x6982	
+0xB8C6	0x9499	
+0xB8C7	0x76D6	
+0xB8C8	0x6E89	
+0xB8C9	0x5E72	
+0xB8CA	0x7518	
+0xB8CB	0x6746	
+0xB8CC	0x67D1	
+0xB8CD	0x7AFF	
+0xB8CE	0x809D	
+0xB8CF	0x8D76	
+0xB8D0	0x611F	
+0xB8D1	0x79C6	
+0xB8D2	0x6562	
+0xB8D3	0x8D63	
+0xB8D4	0x5188	
+0xB8D5	0x521A	
+0xB8D6	0x94A2	
+0xB8D7	0x7F38	
+0xB8D8	0x809B	
+0xB8D9	0x7EB2	
+0xB8DA	0x5C97	
+0xB8DB	0x6E2F	
+0xB8DC	0x6760	
+0xB8DD	0x7BD9	
+0xB8DE	0x768B	
+0xB8DF	0x9AD8	
+0xB8E0	0x818F	
+0xB8E1	0x7F94	
+0xB8E2	0x7CD5	
+0xB8E3	0x641E	
+0xB8E4	0x9550	
+0xB8E5	0x7A3F	
+0xB8E6	0x544A	
+0xB8E7	0x54E5	
+0xB8E8	0x6B4C	
+0xB8E9	0x6401	
+0xB8EA	0x6208	
+0xB8EB	0x9E3D	
+0xB8EC	0x80F3	
+0xB8ED	0x7599	
+0xB8EE	0x5272	
+0xB8EF	0x9769	
+0xB8F0	0x845B	
+0xB8F1	0x683C	
+0xB8F2	0x86E4	
+0xB8F3	0x9601	
+0xB8F4	0x9694	
+0xB8F5	0x94EC	
+0xB8F6	0x4E2A	
+0xB8F7	0x5404	
+0xB8F8	0x7ED9	
+0xB8F9	0x6839	
+0xB8FA	0x8DDF	
+0xB8FB	0x8015	
+0xB8FC	0x66F4	
+0xB8FD	0x5E9A	
+0xB8FE	0x7FB9	
+0xB940	0x7B2F	
+0xB941	0x7B30	
+0xB942	0x7B32	
+0xB943	0x7B34	
+0xB944	0x7B35	
+0xB945	0x7B36	
+0xB946	0x7B37	
+0xB947	0x7B39	
+0xB948	0x7B3B	
+0xB949	0x7B3D	
+0xB94A	0x7B3F	
+0xB94B	0x7B40	
+0xB94C	0x7B41	
+0xB94D	0x7B42	
+0xB94E	0x7B43	
+0xB94F	0x7B44	
+0xB950	0x7B46	
+0xB951	0x7B48	
+0xB952	0x7B4A	
+0xB953	0x7B4D	
+0xB954	0x7B4E	
+0xB955	0x7B53	
+0xB956	0x7B55	
+0xB957	0x7B57	
+0xB958	0x7B59	
+0xB959	0x7B5C	
+0xB95A	0x7B5E	
+0xB95B	0x7B5F	
+0xB95C	0x7B61	
+0xB95D	0x7B63	
+0xB95E	0x7B64	
+0xB95F	0x7B65	
+0xB960	0x7B66	
+0xB961	0x7B67	
+0xB962	0x7B68	
+0xB963	0x7B69	
+0xB964	0x7B6A	
+0xB965	0x7B6B	
+0xB966	0x7B6C	
+0xB967	0x7B6D	
+0xB968	0x7B6F	
+0xB969	0x7B70	
+0xB96A	0x7B73	
+0xB96B	0x7B74	
+0xB96C	0x7B76	
+0xB96D	0x7B78	
+0xB96E	0x7B7A	
+0xB96F	0x7B7C	
+0xB970	0x7B7D	
+0xB971	0x7B7F	
+0xB972	0x7B81	
+0xB973	0x7B82	
+0xB974	0x7B83	
+0xB975	0x7B84	
+0xB976	0x7B86	
+0xB977	0x7B87	
+0xB978	0x7B88	
+0xB979	0x7B89	
+0xB97A	0x7B8A	
+0xB97B	0x7B8B	
+0xB97C	0x7B8C	
+0xB97D	0x7B8E	
+0xB97E	0x7B8F	
+0xB980	0x7B91	
+0xB981	0x7B92	
+0xB982	0x7B93	
+0xB983	0x7B96	
+0xB984	0x7B98	
+0xB985	0x7B99	
+0xB986	0x7B9A	
+0xB987	0x7B9B	
+0xB988	0x7B9E	
+0xB989	0x7B9F	
+0xB98A	0x7BA0	
+0xB98B	0x7BA3	
+0xB98C	0x7BA4	
+0xB98D	0x7BA5	
+0xB98E	0x7BAE	
+0xB98F	0x7BAF	
+0xB990	0x7BB0	
+0xB991	0x7BB2	
+0xB992	0x7BB3	
+0xB993	0x7BB5	
+0xB994	0x7BB6	
+0xB995	0x7BB7	
+0xB996	0x7BB9	
+0xB997	0x7BBA	
+0xB998	0x7BBB	
+0xB999	0x7BBC	
+0xB99A	0x7BBD	
+0xB99B	0x7BBE	
+0xB99C	0x7BBF	
+0xB99D	0x7BC0	
+0xB99E	0x7BC2	
+0xB99F	0x7BC3	
+0xB9A0	0x7BC4	
+0xB9A1	0x57C2	
+0xB9A2	0x803F	
+0xB9A3	0x6897	
+0xB9A4	0x5DE5	
+0xB9A5	0x653B	
+0xB9A6	0x529F	
+0xB9A7	0x606D	
+0xB9A8	0x9F9A	
+0xB9A9	0x4F9B	
+0xB9AA	0x8EAC	
+0xB9AB	0x516C	
+0xB9AC	0x5BAB	
+0xB9AD	0x5F13	
+0xB9AE	0x5DE9	
+0xB9AF	0x6C5E	
+0xB9B0	0x62F1	
+0xB9B1	0x8D21	
+0xB9B2	0x5171	
+0xB9B3	0x94A9	
+0xB9B4	0x52FE	
+0xB9B5	0x6C9F	
+0xB9B6	0x82DF	
+0xB9B7	0x72D7	
+0xB9B8	0x57A2	
+0xB9B9	0x6784	
+0xB9BA	0x8D2D	
+0xB9BB	0x591F	
+0xB9BC	0x8F9C	
+0xB9BD	0x83C7	
+0xB9BE	0x5495	
+0xB9BF	0x7B8D	
+0xB9C0	0x4F30	
+0xB9C1	0x6CBD	
+0xB9C2	0x5B64	
+0xB9C3	0x59D1	
+0xB9C4	0x9F13	
+0xB9C5	0x53E4	
+0xB9C6	0x86CA	
+0xB9C7	0x9AA8	
+0xB9C8	0x8C37	
+0xB9C9	0x80A1	
+0xB9CA	0x6545	
+0xB9CB	0x987E	
+0xB9CC	0x56FA	
+0xB9CD	0x96C7	
+0xB9CE	0x522E	
+0xB9CF	0x74DC	
+0xB9D0	0x5250	
+0xB9D1	0x5BE1	
+0xB9D2	0x6302	
+0xB9D3	0x8902	
+0xB9D4	0x4E56	
+0xB9D5	0x62D0	
+0xB9D6	0x602A	
+0xB9D7	0x68FA	
+0xB9D8	0x5173	
+0xB9D9	0x5B98	
+0xB9DA	0x51A0	
+0xB9DB	0x89C2	
+0xB9DC	0x7BA1	
+0xB9DD	0x9986	
+0xB9DE	0x7F50	
+0xB9DF	0x60EF	
+0xB9E0	0x704C	
+0xB9E1	0x8D2F	
+0xB9E2	0x5149	
+0xB9E3	0x5E7F	
+0xB9E4	0x901B	
+0xB9E5	0x7470	
+0xB9E6	0x89C4	
+0xB9E7	0x572D	
+0xB9E8	0x7845	
+0xB9E9	0x5F52	
+0xB9EA	0x9F9F	
+0xB9EB	0x95FA	
+0xB9EC	0x8F68	
+0xB9ED	0x9B3C	
+0xB9EE	0x8BE1	
+0xB9EF	0x7678	
+0xB9F0	0x6842	
+0xB9F1	0x67DC	
+0xB9F2	0x8DEA	
+0xB9F3	0x8D35	
+0xB9F4	0x523D	
+0xB9F5	0x8F8A	
+0xB9F6	0x6EDA	
+0xB9F7	0x68CD	
+0xB9F8	0x9505	
+0xB9F9	0x90ED	
+0xB9FA	0x56FD	
+0xB9FB	0x679C	
+0xB9FC	0x88F9	
+0xB9FD	0x8FC7	
+0xB9FE	0x54C8	
+0xBA40	0x7BC5	
+0xBA41	0x7BC8	
+0xBA42	0x7BC9	
+0xBA43	0x7BCA	
+0xBA44	0x7BCB	
+0xBA45	0x7BCD	
+0xBA46	0x7BCE	
+0xBA47	0x7BCF	
+0xBA48	0x7BD0	
+0xBA49	0x7BD2	
+0xBA4A	0x7BD4	
+0xBA4B	0x7BD5	
+0xBA4C	0x7BD6	
+0xBA4D	0x7BD7	
+0xBA4E	0x7BD8	
+0xBA4F	0x7BDB	
+0xBA50	0x7BDC	
+0xBA51	0x7BDE	
+0xBA52	0x7BDF	
+0xBA53	0x7BE0	
+0xBA54	0x7BE2	
+0xBA55	0x7BE3	
+0xBA56	0x7BE4	
+0xBA57	0x7BE7	
+0xBA58	0x7BE8	
+0xBA59	0x7BE9	
+0xBA5A	0x7BEB	
+0xBA5B	0x7BEC	
+0xBA5C	0x7BED	
+0xBA5D	0x7BEF	
+0xBA5E	0x7BF0	
+0xBA5F	0x7BF2	
+0xBA60	0x7BF3	
+0xBA61	0x7BF4	
+0xBA62	0x7BF5	
+0xBA63	0x7BF6	
+0xBA64	0x7BF8	
+0xBA65	0x7BF9	
+0xBA66	0x7BFA	
+0xBA67	0x7BFB	
+0xBA68	0x7BFD	
+0xBA69	0x7BFF	
+0xBA6A	0x7C00	
+0xBA6B	0x7C01	
+0xBA6C	0x7C02	
+0xBA6D	0x7C03	
+0xBA6E	0x7C04	
+0xBA6F	0x7C05	
+0xBA70	0x7C06	
+0xBA71	0x7C08	
+0xBA72	0x7C09	
+0xBA73	0x7C0A	
+0xBA74	0x7C0D	
+0xBA75	0x7C0E	
+0xBA76	0x7C10	
+0xBA77	0x7C11	
+0xBA78	0x7C12	
+0xBA79	0x7C13	
+0xBA7A	0x7C14	
+0xBA7B	0x7C15	
+0xBA7C	0x7C17	
+0xBA7D	0x7C18	
+0xBA7E	0x7C19	
+0xBA80	0x7C1A	
+0xBA81	0x7C1B	
+0xBA82	0x7C1C	
+0xBA83	0x7C1D	
+0xBA84	0x7C1E	
+0xBA85	0x7C20	
+0xBA86	0x7C21	
+0xBA87	0x7C22	
+0xBA88	0x7C23	
+0xBA89	0x7C24	
+0xBA8A	0x7C25	
+0xBA8B	0x7C28	
+0xBA8C	0x7C29	
+0xBA8D	0x7C2B	
+0xBA8E	0x7C2C	
+0xBA8F	0x7C2D	
+0xBA90	0x7C2E	
+0xBA91	0x7C2F	
+0xBA92	0x7C30	
+0xBA93	0x7C31	
+0xBA94	0x7C32	
+0xBA95	0x7C33	
+0xBA96	0x7C34	
+0xBA97	0x7C35	
+0xBA98	0x7C36	
+0xBA99	0x7C37	
+0xBA9A	0x7C39	
+0xBA9B	0x7C3A	
+0xBA9C	0x7C3B	
+0xBA9D	0x7C3C	
+0xBA9E	0x7C3D	
+0xBA9F	0x7C3E	
+0xBAA0	0x7C42	
+0xBAA1	0x9AB8	
+0xBAA2	0x5B69	
+0xBAA3	0x6D77	
+0xBAA4	0x6C26	
+0xBAA5	0x4EA5	
+0xBAA6	0x5BB3	
+0xBAA7	0x9A87	
+0xBAA8	0x9163	
+0xBAA9	0x61A8	
+0xBAAA	0x90AF	
+0xBAAB	0x97E9	
+0xBAAC	0x542B	
+0xBAAD	0x6DB5	
+0xBAAE	0x5BD2	
+0xBAAF	0x51FD	
+0xBAB0	0x558A	
+0xBAB1	0x7F55	
+0xBAB2	0x7FF0	
+0xBAB3	0x64BC	
+0xBAB4	0x634D	
+0xBAB5	0x65F1	
+0xBAB6	0x61BE	
+0xBAB7	0x608D	
+0xBAB8	0x710A	
+0xBAB9	0x6C57	
+0xBABA	0x6C49	
+0xBABB	0x592F	
+0xBABC	0x676D	
+0xBABD	0x822A	
+0xBABE	0x58D5	
+0xBABF	0x568E	
+0xBAC0	0x8C6A	
+0xBAC1	0x6BEB	
+0xBAC2	0x90DD	
+0xBAC3	0x597D	
+0xBAC4	0x8017	
+0xBAC5	0x53F7	
+0xBAC6	0x6D69	
+0xBAC7	0x5475	
+0xBAC8	0x559D	
+0xBAC9	0x8377	
+0xBACA	0x83CF	
+0xBACB	0x6838	
+0xBACC	0x79BE	
+0xBACD	0x548C	
+0xBACE	0x4F55	
+0xBACF	0x5408	
+0xBAD0	0x76D2	
+0xBAD1	0x8C89	
+0xBAD2	0x9602	
+0xBAD3	0x6CB3	
+0xBAD4	0x6DB8	
+0xBAD5	0x8D6B	
+0xBAD6	0x8910	
+0xBAD7	0x9E64	
+0xBAD8	0x8D3A	
+0xBAD9	0x563F	
+0xBADA	0x9ED1	
+0xBADB	0x75D5	
+0xBADC	0x5F88	
+0xBADD	0x72E0	
+0xBADE	0x6068	
+0xBADF	0x54FC	
+0xBAE0	0x4EA8	
+0xBAE1	0x6A2A	
+0xBAE2	0x8861	
+0xBAE3	0x6052	
+0xBAE4	0x8F70	
+0xBAE5	0x54C4	
+0xBAE6	0x70D8	
+0xBAE7	0x8679	
+0xBAE8	0x9E3F	
+0xBAE9	0x6D2A	
+0xBAEA	0x5B8F	
+0xBAEB	0x5F18	
+0xBAEC	0x7EA2	
+0xBAED	0x5589	
+0xBAEE	0x4FAF	
+0xBAEF	0x7334	
+0xBAF0	0x543C	
+0xBAF1	0x539A	
+0xBAF2	0x5019	
+0xBAF3	0x540E	
+0xBAF4	0x547C	
+0xBAF5	0x4E4E	
+0xBAF6	0x5FFD	
+0xBAF7	0x745A	
+0xBAF8	0x58F6	
+0xBAF9	0x846B	
+0xBAFA	0x80E1	
+0xBAFB	0x8774	
+0xBAFC	0x72D0	
+0xBAFD	0x7CCA	
+0xBAFE	0x6E56	
+0xBB40	0x7C43	
+0xBB41	0x7C44	
+0xBB42	0x7C45	
+0xBB43	0x7C46	
+0xBB44	0x7C47	
+0xBB45	0x7C48	
+0xBB46	0x7C49	
+0xBB47	0x7C4A	
+0xBB48	0x7C4B	
+0xBB49	0x7C4C	
+0xBB4A	0x7C4E	
+0xBB4B	0x7C4F	
+0xBB4C	0x7C50	
+0xBB4D	0x7C51	
+0xBB4E	0x7C52	
+0xBB4F	0x7C53	
+0xBB50	0x7C54	
+0xBB51	0x7C55	
+0xBB52	0x7C56	
+0xBB53	0x7C57	
+0xBB54	0x7C58	
+0xBB55	0x7C59	
+0xBB56	0x7C5A	
+0xBB57	0x7C5B	
+0xBB58	0x7C5C	
+0xBB59	0x7C5D	
+0xBB5A	0x7C5E	
+0xBB5B	0x7C5F	
+0xBB5C	0x7C60	
+0xBB5D	0x7C61	
+0xBB5E	0x7C62	
+0xBB5F	0x7C63	
+0xBB60	0x7C64	
+0xBB61	0x7C65	
+0xBB62	0x7C66	
+0xBB63	0x7C67	
+0xBB64	0x7C68	
+0xBB65	0x7C69	
+0xBB66	0x7C6A	
+0xBB67	0x7C6B	
+0xBB68	0x7C6C	
+0xBB69	0x7C6D	
+0xBB6A	0x7C6E	
+0xBB6B	0x7C6F	
+0xBB6C	0x7C70	
+0xBB6D	0x7C71	
+0xBB6E	0x7C72	
+0xBB6F	0x7C75	
+0xBB70	0x7C76	
+0xBB71	0x7C77	
+0xBB72	0x7C78	
+0xBB73	0x7C79	
+0xBB74	0x7C7A	
+0xBB75	0x7C7E	
+0xBB76	0x7C7F	
+0xBB77	0x7C80	
+0xBB78	0x7C81	
+0xBB79	0x7C82	
+0xBB7A	0x7C83	
+0xBB7B	0x7C84	
+0xBB7C	0x7C85	
+0xBB7D	0x7C86	
+0xBB7E	0x7C87	
+0xBB80	0x7C88	
+0xBB81	0x7C8A	
+0xBB82	0x7C8B	
+0xBB83	0x7C8C	
+0xBB84	0x7C8D	
+0xBB85	0x7C8E	
+0xBB86	0x7C8F	
+0xBB87	0x7C90	
+0xBB88	0x7C93	
+0xBB89	0x7C94	
+0xBB8A	0x7C96	
+0xBB8B	0x7C99	
+0xBB8C	0x7C9A	
+0xBB8D	0x7C9B	
+0xBB8E	0x7CA0	
+0xBB8F	0x7CA1	
+0xBB90	0x7CA3	
+0xBB91	0x7CA6	
+0xBB92	0x7CA7	
+0xBB93	0x7CA8	
+0xBB94	0x7CA9	
+0xBB95	0x7CAB	
+0xBB96	0x7CAC	
+0xBB97	0x7CAD	
+0xBB98	0x7CAF	
+0xBB99	0x7CB0	
+0xBB9A	0x7CB4	
+0xBB9B	0x7CB5	
+0xBB9C	0x7CB6	
+0xBB9D	0x7CB7	
+0xBB9E	0x7CB8	
+0xBB9F	0x7CBA	
+0xBBA0	0x7CBB	
+0xBBA1	0x5F27	
+0xBBA2	0x864E	
+0xBBA3	0x552C	
+0xBBA4	0x62A4	
+0xBBA5	0x4E92	
+0xBBA6	0x6CAA	
+0xBBA7	0x6237	
+0xBBA8	0x82B1	
+0xBBA9	0x54D7	
+0xBBAA	0x534E	
+0xBBAB	0x733E	
+0xBBAC	0x6ED1	
+0xBBAD	0x753B	
+0xBBAE	0x5212	
+0xBBAF	0x5316	
+0xBBB0	0x8BDD	
+0xBBB1	0x69D0	
+0xBBB2	0x5F8A	
+0xBBB3	0x6000	
+0xBBB4	0x6DEE	
+0xBBB5	0x574F	
+0xBBB6	0x6B22	
+0xBBB7	0x73AF	
+0xBBB8	0x6853	
+0xBBB9	0x8FD8	
+0xBBBA	0x7F13	
+0xBBBB	0x6362	
+0xBBBC	0x60A3	
+0xBBBD	0x5524	
+0xBBBE	0x75EA	
+0xBBBF	0x8C62	
+0xBBC0	0x7115	
+0xBBC1	0x6DA3	
+0xBBC2	0x5BA6	
+0xBBC3	0x5E7B	
+0xBBC4	0x8352	
+0xBBC5	0x614C	
+0xBBC6	0x9EC4	
+0xBBC7	0x78FA	
+0xBBC8	0x8757	
+0xBBC9	0x7C27	
+0xBBCA	0x7687	
+0xBBCB	0x51F0	
+0xBBCC	0x60F6	
+0xBBCD	0x714C	
+0xBBCE	0x6643	
+0xBBCF	0x5E4C	
+0xBBD0	0x604D	
+0xBBD1	0x8C0E	
+0xBBD2	0x7070	
+0xBBD3	0x6325	
+0xBBD4	0x8F89	
+0xBBD5	0x5FBD	
+0xBBD6	0x6062	
+0xBBD7	0x86D4	
+0xBBD8	0x56DE	
+0xBBD9	0x6BC1	
+0xBBDA	0x6094	
+0xBBDB	0x6167	
+0xBBDC	0x5349	
+0xBBDD	0x60E0	
+0xBBDE	0x6666	
+0xBBDF	0x8D3F	
+0xBBE0	0x79FD	
+0xBBE1	0x4F1A	
+0xBBE2	0x70E9	
+0xBBE3	0x6C47	
+0xBBE4	0x8BB3	
+0xBBE5	0x8BF2	
+0xBBE6	0x7ED8	
+0xBBE7	0x8364	
+0xBBE8	0x660F	
+0xBBE9	0x5A5A	
+0xBBEA	0x9B42	
+0xBBEB	0x6D51	
+0xBBEC	0x6DF7	
+0xBBED	0x8C41	
+0xBBEE	0x6D3B	
+0xBBEF	0x4F19	
+0xBBF0	0x706B	
+0xBBF1	0x83B7	
+0xBBF2	0x6216	
+0xBBF3	0x60D1	
+0xBBF4	0x970D	
+0xBBF5	0x8D27	
+0xBBF6	0x7978	
+0xBBF7	0x51FB	
+0xBBF8	0x573E	
+0xBBF9	0x57FA	
+0xBBFA	0x673A	
+0xBBFB	0x7578	
+0xBBFC	0x7A3D	
+0xBBFD	0x79EF	
+0xBBFE	0x7B95	
+0xBC40	0x7CBF	
+0xBC41	0x7CC0	
+0xBC42	0x7CC2	
+0xBC43	0x7CC3	
+0xBC44	0x7CC4	
+0xBC45	0x7CC6	
+0xBC46	0x7CC9	
+0xBC47	0x7CCB	
+0xBC48	0x7CCE	
+0xBC49	0x7CCF	
+0xBC4A	0x7CD0	
+0xBC4B	0x7CD1	
+0xBC4C	0x7CD2	
+0xBC4D	0x7CD3	
+0xBC4E	0x7CD4	
+0xBC4F	0x7CD8	
+0xBC50	0x7CDA	
+0xBC51	0x7CDB	
+0xBC52	0x7CDD	
+0xBC53	0x7CDE	
+0xBC54	0x7CE1	
+0xBC55	0x7CE2	
+0xBC56	0x7CE3	
+0xBC57	0x7CE4	
+0xBC58	0x7CE5	
+0xBC59	0x7CE6	
+0xBC5A	0x7CE7	
+0xBC5B	0x7CE9	
+0xBC5C	0x7CEA	
+0xBC5D	0x7CEB	
+0xBC5E	0x7CEC	
+0xBC5F	0x7CED	
+0xBC60	0x7CEE	
+0xBC61	0x7CF0	
+0xBC62	0x7CF1	
+0xBC63	0x7CF2	
+0xBC64	0x7CF3	
+0xBC65	0x7CF4	
+0xBC66	0x7CF5	
+0xBC67	0x7CF6	
+0xBC68	0x7CF7	
+0xBC69	0x7CF9	
+0xBC6A	0x7CFA	
+0xBC6B	0x7CFC	
+0xBC6C	0x7CFD	
+0xBC6D	0x7CFE	
+0xBC6E	0x7CFF	
+0xBC6F	0x7D00	
+0xBC70	0x7D01	
+0xBC71	0x7D02	
+0xBC72	0x7D03	
+0xBC73	0x7D04	
+0xBC74	0x7D05	
+0xBC75	0x7D06	
+0xBC76	0x7D07	
+0xBC77	0x7D08	
+0xBC78	0x7D09	
+0xBC79	0x7D0B	
+0xBC7A	0x7D0C	
+0xBC7B	0x7D0D	
+0xBC7C	0x7D0E	
+0xBC7D	0x7D0F	
+0xBC7E	0x7D10	
+0xBC80	0x7D11	
+0xBC81	0x7D12	
+0xBC82	0x7D13	
+0xBC83	0x7D14	
+0xBC84	0x7D15	
+0xBC85	0x7D16	
+0xBC86	0x7D17	
+0xBC87	0x7D18	
+0xBC88	0x7D19	
+0xBC89	0x7D1A	
+0xBC8A	0x7D1B	
+0xBC8B	0x7D1C	
+0xBC8C	0x7D1D	
+0xBC8D	0x7D1E	
+0xBC8E	0x7D1F	
+0xBC8F	0x7D21	
+0xBC90	0x7D23	
+0xBC91	0x7D24	
+0xBC92	0x7D25	
+0xBC93	0x7D26	
+0xBC94	0x7D28	
+0xBC95	0x7D29	
+0xBC96	0x7D2A	
+0xBC97	0x7D2C	
+0xBC98	0x7D2D	
+0xBC99	0x7D2E	
+0xBC9A	0x7D30	
+0xBC9B	0x7D31	
+0xBC9C	0x7D32	
+0xBC9D	0x7D33	
+0xBC9E	0x7D34	
+0xBC9F	0x7D35	
+0xBCA0	0x7D36	
+0xBCA1	0x808C	
+0xBCA2	0x9965	
+0xBCA3	0x8FF9	
+0xBCA4	0x6FC0	
+0xBCA5	0x8BA5	
+0xBCA6	0x9E21	
+0xBCA7	0x59EC	
+0xBCA8	0x7EE9	
+0xBCA9	0x7F09	
+0xBCAA	0x5409	
+0xBCAB	0x6781	
+0xBCAC	0x68D8	
+0xBCAD	0x8F91	
+0xBCAE	0x7C4D	
+0xBCAF	0x96C6	
+0xBCB0	0x53CA	
+0xBCB1	0x6025	
+0xBCB2	0x75BE	
+0xBCB3	0x6C72	
+0xBCB4	0x5373	
+0xBCB5	0x5AC9	
+0xBCB6	0x7EA7	
+0xBCB7	0x6324	
+0xBCB8	0x51E0	
+0xBCB9	0x810A	
+0xBCBA	0x5DF1	
+0xBCBB	0x84DF	
+0xBCBC	0x6280	
+0xBCBD	0x5180	
+0xBCBE	0x5B63	
+0xBCBF	0x4F0E	
+0xBCC0	0x796D	
+0xBCC1	0x5242	
+0xBCC2	0x60B8	
+0xBCC3	0x6D4E	
+0xBCC4	0x5BC4	
+0xBCC5	0x5BC2	
+0xBCC6	0x8BA1	
+0xBCC7	0x8BB0	
+0xBCC8	0x65E2	
+0xBCC9	0x5FCC	
+0xBCCA	0x9645	
+0xBCCB	0x5993	
+0xBCCC	0x7EE7	
+0xBCCD	0x7EAA	
+0xBCCE	0x5609	
+0xBCCF	0x67B7	
+0xBCD0	0x5939	
+0xBCD1	0x4F73	
+0xBCD2	0x5BB6	
+0xBCD3	0x52A0	
+0xBCD4	0x835A	
+0xBCD5	0x988A	
+0xBCD6	0x8D3E	
+0xBCD7	0x7532	
+0xBCD8	0x94BE	
+0xBCD9	0x5047	
+0xBCDA	0x7A3C	
+0xBCDB	0x4EF7	
+0xBCDC	0x67B6	
+0xBCDD	0x9A7E	
+0xBCDE	0x5AC1	
+0xBCDF	0x6B7C	
+0xBCE0	0x76D1	
+0xBCE1	0x575A	
+0xBCE2	0x5C16	
+0xBCE3	0x7B3A	
+0xBCE4	0x95F4	
+0xBCE5	0x714E	
+0xBCE6	0x517C	
+0xBCE7	0x80A9	
+0xBCE8	0x8270	
+0xBCE9	0x5978	
+0xBCEA	0x7F04	
+0xBCEB	0x8327	
+0xBCEC	0x68C0	
+0xBCED	0x67EC	
+0xBCEE	0x78B1	
+0xBCEF	0x7877	
+0xBCF0	0x62E3	
+0xBCF1	0x6361	
+0xBCF2	0x7B80	
+0xBCF3	0x4FED	
+0xBCF4	0x526A	
+0xBCF5	0x51CF	
+0xBCF6	0x8350	
+0xBCF7	0x69DB	
+0xBCF8	0x9274	
+0xBCF9	0x8DF5	
+0xBCFA	0x8D31	
+0xBCFB	0x89C1	
+0xBCFC	0x952E	
+0xBCFD	0x7BAD	
+0xBCFE	0x4EF6	
+0xBD40	0x7D37	
+0xBD41	0x7D38	
+0xBD42	0x7D39	
+0xBD43	0x7D3A	
+0xBD44	0x7D3B	
+0xBD45	0x7D3C	
+0xBD46	0x7D3D	
+0xBD47	0x7D3E	
+0xBD48	0x7D3F	
+0xBD49	0x7D40	
+0xBD4A	0x7D41	
+0xBD4B	0x7D42	
+0xBD4C	0x7D43	
+0xBD4D	0x7D44	
+0xBD4E	0x7D45	
+0xBD4F	0x7D46	
+0xBD50	0x7D47	
+0xBD51	0x7D48	
+0xBD52	0x7D49	
+0xBD53	0x7D4A	
+0xBD54	0x7D4B	
+0xBD55	0x7D4C	
+0xBD56	0x7D4D	
+0xBD57	0x7D4E	
+0xBD58	0x7D4F	
+0xBD59	0x7D50	
+0xBD5A	0x7D51	
+0xBD5B	0x7D52	
+0xBD5C	0x7D53	
+0xBD5D	0x7D54	
+0xBD5E	0x7D55	
+0xBD5F	0x7D56	
+0xBD60	0x7D57	
+0xBD61	0x7D58	
+0xBD62	0x7D59	
+0xBD63	0x7D5A	
+0xBD64	0x7D5B	
+0xBD65	0x7D5C	
+0xBD66	0x7D5D	
+0xBD67	0x7D5E	
+0xBD68	0x7D5F	
+0xBD69	0x7D60	
+0xBD6A	0x7D61	
+0xBD6B	0x7D62	
+0xBD6C	0x7D63	
+0xBD6D	0x7D64	
+0xBD6E	0x7D65	
+0xBD6F	0x7D66	
+0xBD70	0x7D67	
+0xBD71	0x7D68	
+0xBD72	0x7D69	
+0xBD73	0x7D6A	
+0xBD74	0x7D6B	
+0xBD75	0x7D6C	
+0xBD76	0x7D6D	
+0xBD77	0x7D6F	
+0xBD78	0x7D70	
+0xBD79	0x7D71	
+0xBD7A	0x7D72	
+0xBD7B	0x7D73	
+0xBD7C	0x7D74	
+0xBD7D	0x7D75	
+0xBD7E	0x7D76	
+0xBD80	0x7D78	
+0xBD81	0x7D79	
+0xBD82	0x7D7A	
+0xBD83	0x7D7B	
+0xBD84	0x7D7C	
+0xBD85	0x7D7D	
+0xBD86	0x7D7E	
+0xBD87	0x7D7F	
+0xBD88	0x7D80	
+0xBD89	0x7D81	
+0xBD8A	0x7D82	
+0xBD8B	0x7D83	
+0xBD8C	0x7D84	
+0xBD8D	0x7D85	
+0xBD8E	0x7D86	
+0xBD8F	0x7D87	
+0xBD90	0x7D88	
+0xBD91	0x7D89	
+0xBD92	0x7D8A	
+0xBD93	0x7D8B	
+0xBD94	0x7D8C	
+0xBD95	0x7D8D	
+0xBD96	0x7D8E	
+0xBD97	0x7D8F	
+0xBD98	0x7D90	
+0xBD99	0x7D91	
+0xBD9A	0x7D92	
+0xBD9B	0x7D93	
+0xBD9C	0x7D94	
+0xBD9D	0x7D95	
+0xBD9E	0x7D96	
+0xBD9F	0x7D97	
+0xBDA0	0x7D98	
+0xBDA1	0x5065	
+0xBDA2	0x8230	
+0xBDA3	0x5251	
+0xBDA4	0x996F	
+0xBDA5	0x6E10	
+0xBDA6	0x6E85	
+0xBDA7	0x6DA7	
+0xBDA8	0x5EFA	
+0xBDA9	0x50F5	
+0xBDAA	0x59DC	
+0xBDAB	0x5C06	
+0xBDAC	0x6D46	
+0xBDAD	0x6C5F	
+0xBDAE	0x7586	
+0xBDAF	0x848B	
+0xBDB0	0x6868	
+0xBDB1	0x5956	
+0xBDB2	0x8BB2	
+0xBDB3	0x5320	
+0xBDB4	0x9171	
+0xBDB5	0x964D	
+0xBDB6	0x8549	
+0xBDB7	0x6912	
+0xBDB8	0x7901	
+0xBDB9	0x7126	
+0xBDBA	0x80F6	
+0xBDBB	0x4EA4	
+0xBDBC	0x90CA	
+0xBDBD	0x6D47	
+0xBDBE	0x9A84	
+0xBDBF	0x5A07	
+0xBDC0	0x56BC	
+0xBDC1	0x6405	
+0xBDC2	0x94F0	
+0xBDC3	0x77EB	
+0xBDC4	0x4FA5	
+0xBDC5	0x811A	
+0xBDC6	0x72E1	
+0xBDC7	0x89D2	
+0xBDC8	0x997A	
+0xBDC9	0x7F34	
+0xBDCA	0x7EDE	
+0xBDCB	0x527F	
+0xBDCC	0x6559	
+0xBDCD	0x9175	
+0xBDCE	0x8F7F	
+0xBDCF	0x8F83	
+0xBDD0	0x53EB	
+0xBDD1	0x7A96	
+0xBDD2	0x63ED	
+0xBDD3	0x63A5	
+0xBDD4	0x7686	
+0xBDD5	0x79F8	
+0xBDD6	0x8857	
+0xBDD7	0x9636	
+0xBDD8	0x622A	
+0xBDD9	0x52AB	
+0xBDDA	0x8282	
+0xBDDB	0x6854	
+0xBDDC	0x6770	
+0xBDDD	0x6377	
+0xBDDE	0x776B	
+0xBDDF	0x7AED	
+0xBDE0	0x6D01	
+0xBDE1	0x7ED3	
+0xBDE2	0x89E3	
+0xBDE3	0x59D0	
+0xBDE4	0x6212	
+0xBDE5	0x85C9	
+0xBDE6	0x82A5	
+0xBDE7	0x754C	
+0xBDE8	0x501F	
+0xBDE9	0x4ECB	
+0xBDEA	0x75A5	
+0xBDEB	0x8BEB	
+0xBDEC	0x5C4A	
+0xBDED	0x5DFE	
+0xBDEE	0x7B4B	
+0xBDEF	0x65A4	
+0xBDF0	0x91D1	
+0xBDF1	0x4ECA	
+0xBDF2	0x6D25	
+0xBDF3	0x895F	
+0xBDF4	0x7D27	
+0xBDF5	0x9526	
+0xBDF6	0x4EC5	
+0xBDF7	0x8C28	
+0xBDF8	0x8FDB	
+0xBDF9	0x9773	
+0xBDFA	0x664B	
+0xBDFB	0x7981	
+0xBDFC	0x8FD1	
+0xBDFD	0x70EC	
+0xBDFE	0x6D78	
+0xBE40	0x7D99	
+0xBE41	0x7D9A	
+0xBE42	0x7D9B	
+0xBE43	0x7D9C	
+0xBE44	0x7D9D	
+0xBE45	0x7D9E	
+0xBE46	0x7D9F	
+0xBE47	0x7DA0	
+0xBE48	0x7DA1	
+0xBE49	0x7DA2	
+0xBE4A	0x7DA3	
+0xBE4B	0x7DA4	
+0xBE4C	0x7DA5	
+0xBE4D	0x7DA7	
+0xBE4E	0x7DA8	
+0xBE4F	0x7DA9	
+0xBE50	0x7DAA	
+0xBE51	0x7DAB	
+0xBE52	0x7DAC	
+0xBE53	0x7DAD	
+0xBE54	0x7DAF	
+0xBE55	0x7DB0	
+0xBE56	0x7DB1	
+0xBE57	0x7DB2	
+0xBE58	0x7DB3	
+0xBE59	0x7DB4	
+0xBE5A	0x7DB5	
+0xBE5B	0x7DB6	
+0xBE5C	0x7DB7	
+0xBE5D	0x7DB8	
+0xBE5E	0x7DB9	
+0xBE5F	0x7DBA	
+0xBE60	0x7DBB	
+0xBE61	0x7DBC	
+0xBE62	0x7DBD	
+0xBE63	0x7DBE	
+0xBE64	0x7DBF	
+0xBE65	0x7DC0	
+0xBE66	0x7DC1	
+0xBE67	0x7DC2	
+0xBE68	0x7DC3	
+0xBE69	0x7DC4	
+0xBE6A	0x7DC5	
+0xBE6B	0x7DC6	
+0xBE6C	0x7DC7	
+0xBE6D	0x7DC8	
+0xBE6E	0x7DC9	
+0xBE6F	0x7DCA	
+0xBE70	0x7DCB	
+0xBE71	0x7DCC	
+0xBE72	0x7DCD	
+0xBE73	0x7DCE	
+0xBE74	0x7DCF	
+0xBE75	0x7DD0	
+0xBE76	0x7DD1	
+0xBE77	0x7DD2	
+0xBE78	0x7DD3	
+0xBE79	0x7DD4	
+0xBE7A	0x7DD5	
+0xBE7B	0x7DD6	
+0xBE7C	0x7DD7	
+0xBE7D	0x7DD8	
+0xBE7E	0x7DD9	
+0xBE80	0x7DDA	
+0xBE81	0x7DDB	
+0xBE82	0x7DDC	
+0xBE83	0x7DDD	
+0xBE84	0x7DDE	
+0xBE85	0x7DDF	
+0xBE86	0x7DE0	
+0xBE87	0x7DE1	
+0xBE88	0x7DE2	
+0xBE89	0x7DE3	
+0xBE8A	0x7DE4	
+0xBE8B	0x7DE5	
+0xBE8C	0x7DE6	
+0xBE8D	0x7DE7	
+0xBE8E	0x7DE8	
+0xBE8F	0x7DE9	
+0xBE90	0x7DEA	
+0xBE91	0x7DEB	
+0xBE92	0x7DEC	
+0xBE93	0x7DED	
+0xBE94	0x7DEE	
+0xBE95	0x7DEF	
+0xBE96	0x7DF0	
+0xBE97	0x7DF1	
+0xBE98	0x7DF2	
+0xBE99	0x7DF3	
+0xBE9A	0x7DF4	
+0xBE9B	0x7DF5	
+0xBE9C	0x7DF6	
+0xBE9D	0x7DF7	
+0xBE9E	0x7DF8	
+0xBE9F	0x7DF9	
+0xBEA0	0x7DFA	
+0xBEA1	0x5C3D	
+0xBEA2	0x52B2	
+0xBEA3	0x8346	
+0xBEA4	0x5162	
+0xBEA5	0x830E	
+0xBEA6	0x775B	
+0xBEA7	0x6676	
+0xBEA8	0x9CB8	
+0xBEA9	0x4EAC	
+0xBEAA	0x60CA	
+0xBEAB	0x7CBE	
+0xBEAC	0x7CB3	
+0xBEAD	0x7ECF	
+0xBEAE	0x4E95	
+0xBEAF	0x8B66	
+0xBEB0	0x666F	
+0xBEB1	0x9888	
+0xBEB2	0x9759	
+0xBEB3	0x5883	
+0xBEB4	0x656C	
+0xBEB5	0x955C	
+0xBEB6	0x5F84	
+0xBEB7	0x75C9	
+0xBEB8	0x9756	
+0xBEB9	0x7ADF	
+0xBEBA	0x7ADE	
+0xBEBB	0x51C0	
+0xBEBC	0x70AF	
+0xBEBD	0x7A98	
+0xBEBE	0x63EA	
+0xBEBF	0x7A76	
+0xBEC0	0x7EA0	
+0xBEC1	0x7396	
+0xBEC2	0x97ED	
+0xBEC3	0x4E45	
+0xBEC4	0x7078	
+0xBEC5	0x4E5D	
+0xBEC6	0x9152	
+0xBEC7	0x53A9	
+0xBEC8	0x6551	
+0xBEC9	0x65E7	
+0xBECA	0x81FC	
+0xBECB	0x8205	
+0xBECC	0x548E	
+0xBECD	0x5C31	
+0xBECE	0x759A	
+0xBECF	0x97A0	
+0xBED0	0x62D8	
+0xBED1	0x72D9	
+0xBED2	0x75BD	
+0xBED3	0x5C45	
+0xBED4	0x9A79	
+0xBED5	0x83CA	
+0xBED6	0x5C40	
+0xBED7	0x5480	
+0xBED8	0x77E9	
+0xBED9	0x4E3E	
+0xBEDA	0x6CAE	
+0xBEDB	0x805A	
+0xBEDC	0x62D2	
+0xBEDD	0x636E	
+0xBEDE	0x5DE8	
+0xBEDF	0x5177	
+0xBEE0	0x8DDD	
+0xBEE1	0x8E1E	
+0xBEE2	0x952F	
+0xBEE3	0x4FF1	
+0xBEE4	0x53E5	
+0xBEE5	0x60E7	
+0xBEE6	0x70AC	
+0xBEE7	0x5267	
+0xBEE8	0x6350	
+0xBEE9	0x9E43	
+0xBEEA	0x5A1F	
+0xBEEB	0x5026	
+0xBEEC	0x7737	
+0xBEED	0x5377	
+0xBEEE	0x7EE2	
+0xBEEF	0x6485	
+0xBEF0	0x652B	
+0xBEF1	0x6289	
+0xBEF2	0x6398	
+0xBEF3	0x5014	
+0xBEF4	0x7235	
+0xBEF5	0x89C9	
+0xBEF6	0x51B3	
+0xBEF7	0x8BC0	
+0xBEF8	0x7EDD	
+0xBEF9	0x5747	
+0xBEFA	0x83CC	
+0xBEFB	0x94A7	
+0xBEFC	0x519B	
+0xBEFD	0x541B	
+0xBEFE	0x5CFB	
+0xBF40	0x7DFB	
+0xBF41	0x7DFC	
+0xBF42	0x7DFD	
+0xBF43	0x7DFE	
+0xBF44	0x7DFF	
+0xBF45	0x7E00	
+0xBF46	0x7E01	
+0xBF47	0x7E02	
+0xBF48	0x7E03	
+0xBF49	0x7E04	
+0xBF4A	0x7E05	
+0xBF4B	0x7E06	
+0xBF4C	0x7E07	
+0xBF4D	0x7E08	
+0xBF4E	0x7E09	
+0xBF4F	0x7E0A	
+0xBF50	0x7E0B	
+0xBF51	0x7E0C	
+0xBF52	0x7E0D	
+0xBF53	0x7E0E	
+0xBF54	0x7E0F	
+0xBF55	0x7E10	
+0xBF56	0x7E11	
+0xBF57	0x7E12	
+0xBF58	0x7E13	
+0xBF59	0x7E14	
+0xBF5A	0x7E15	
+0xBF5B	0x7E16	
+0xBF5C	0x7E17	
+0xBF5D	0x7E18	
+0xBF5E	0x7E19	
+0xBF5F	0x7E1A	
+0xBF60	0x7E1B	
+0xBF61	0x7E1C	
+0xBF62	0x7E1D	
+0xBF63	0x7E1E	
+0xBF64	0x7E1F	
+0xBF65	0x7E20	
+0xBF66	0x7E21	
+0xBF67	0x7E22	
+0xBF68	0x7E23	
+0xBF69	0x7E24	
+0xBF6A	0x7E25	
+0xBF6B	0x7E26	
+0xBF6C	0x7E27	
+0xBF6D	0x7E28	
+0xBF6E	0x7E29	
+0xBF6F	0x7E2A	
+0xBF70	0x7E2B	
+0xBF71	0x7E2C	
+0xBF72	0x7E2D	
+0xBF73	0x7E2E	
+0xBF74	0x7E2F	
+0xBF75	0x7E30	
+0xBF76	0x7E31	
+0xBF77	0x7E32	
+0xBF78	0x7E33	
+0xBF79	0x7E34	
+0xBF7A	0x7E35	
+0xBF7B	0x7E36	
+0xBF7C	0x7E37	
+0xBF7D	0x7E38	
+0xBF7E	0x7E39	
+0xBF80	0x7E3A	
+0xBF81	0x7E3C	
+0xBF82	0x7E3D	
+0xBF83	0x7E3E	
+0xBF84	0x7E3F	
+0xBF85	0x7E40	
+0xBF86	0x7E42	
+0xBF87	0x7E43	
+0xBF88	0x7E44	
+0xBF89	0x7E45	
+0xBF8A	0x7E46	
+0xBF8B	0x7E48	
+0xBF8C	0x7E49	
+0xBF8D	0x7E4A	
+0xBF8E	0x7E4B	
+0xBF8F	0x7E4C	
+0xBF90	0x7E4D	
+0xBF91	0x7E4E	
+0xBF92	0x7E4F	
+0xBF93	0x7E50	
+0xBF94	0x7E51	
+0xBF95	0x7E52	
+0xBF96	0x7E53	
+0xBF97	0x7E54	
+0xBF98	0x7E55	
+0xBF99	0x7E56	
+0xBF9A	0x7E57	
+0xBF9B	0x7E58	
+0xBF9C	0x7E59	
+0xBF9D	0x7E5A	
+0xBF9E	0x7E5B	
+0xBF9F	0x7E5C	
+0xBFA0	0x7E5D	
+0xBFA1	0x4FCA	
+0xBFA2	0x7AE3	
+0xBFA3	0x6D5A	
+0xBFA4	0x90E1	
+0xBFA5	0x9A8F	
+0xBFA6	0x5580	
+0xBFA7	0x5496	
+0xBFA8	0x5361	
+0xBFA9	0x54AF	
+0xBFAA	0x5F00	
+0xBFAB	0x63E9	
+0xBFAC	0x6977	
+0xBFAD	0x51EF	
+0xBFAE	0x6168	
+0xBFAF	0x520A	
+0xBFB0	0x582A	
+0xBFB1	0x52D8	
+0xBFB2	0x574E	
+0xBFB3	0x780D	
+0xBFB4	0x770B	
+0xBFB5	0x5EB7	
+0xBFB6	0x6177	
+0xBFB7	0x7CE0	
+0xBFB8	0x625B	
+0xBFB9	0x6297	
+0xBFBA	0x4EA2	
+0xBFBB	0x7095	
+0xBFBC	0x8003	
+0xBFBD	0x62F7	
+0xBFBE	0x70E4	
+0xBFBF	0x9760	
+0xBFC0	0x5777	
+0xBFC1	0x82DB	
+0xBFC2	0x67EF	
+0xBFC3	0x68F5	
+0xBFC4	0x78D5	
+0xBFC5	0x9897	
+0xBFC6	0x79D1	
+0xBFC7	0x58F3	
+0xBFC8	0x54B3	
+0xBFC9	0x53EF	
+0xBFCA	0x6E34	
+0xBFCB	0x514B	
+0xBFCC	0x523B	
+0xBFCD	0x5BA2	
+0xBFCE	0x8BFE	
+0xBFCF	0x80AF	
+0xBFD0	0x5543	
+0xBFD1	0x57A6	
+0xBFD2	0x6073	
+0xBFD3	0x5751	
+0xBFD4	0x542D	
+0xBFD5	0x7A7A	
+0xBFD6	0x6050	
+0xBFD7	0x5B54	
+0xBFD8	0x63A7	
+0xBFD9	0x62A0	
+0xBFDA	0x53E3	
+0xBFDB	0x6263	
+0xBFDC	0x5BC7	
+0xBFDD	0x67AF	
+0xBFDE	0x54ED	
+0xBFDF	0x7A9F	
+0xBFE0	0x82E6	
+0xBFE1	0x9177	
+0xBFE2	0x5E93	
+0xBFE3	0x88E4	
+0xBFE4	0x5938	
+0xBFE5	0x57AE	
+0xBFE6	0x630E	
+0xBFE7	0x8DE8	
+0xBFE8	0x80EF	
+0xBFE9	0x5757	
+0xBFEA	0x7B77	
+0xBFEB	0x4FA9	
+0xBFEC	0x5FEB	
+0xBFED	0x5BBD	
+0xBFEE	0x6B3E	
+0xBFEF	0x5321	
+0xBFF0	0x7B50	
+0xBFF1	0x72C2	
+0xBFF2	0x6846	
+0xBFF3	0x77FF	
+0xBFF4	0x7736	
+0xBFF5	0x65F7	
+0xBFF6	0x51B5	
+0xBFF7	0x4E8F	
+0xBFF8	0x76D4	
+0xBFF9	0x5CBF	
+0xBFFA	0x7AA5	
+0xBFFB	0x8475	
+0xBFFC	0x594E	
+0xBFFD	0x9B41	
+0xBFFE	0x5080	
+0xC040	0x7E5E	
+0xC041	0x7E5F	
+0xC042	0x7E60	
+0xC043	0x7E61	
+0xC044	0x7E62	
+0xC045	0x7E63	
+0xC046	0x7E64	
+0xC047	0x7E65	
+0xC048	0x7E66	
+0xC049	0x7E67	
+0xC04A	0x7E68	
+0xC04B	0x7E69	
+0xC04C	0x7E6A	
+0xC04D	0x7E6B	
+0xC04E	0x7E6C	
+0xC04F	0x7E6D	
+0xC050	0x7E6E	
+0xC051	0x7E6F	
+0xC052	0x7E70	
+0xC053	0x7E71	
+0xC054	0x7E72	
+0xC055	0x7E73	
+0xC056	0x7E74	
+0xC057	0x7E75	
+0xC058	0x7E76	
+0xC059	0x7E77	
+0xC05A	0x7E78	
+0xC05B	0x7E79	
+0xC05C	0x7E7A	
+0xC05D	0x7E7B	
+0xC05E	0x7E7C	
+0xC05F	0x7E7D	
+0xC060	0x7E7E	
+0xC061	0x7E7F	
+0xC062	0x7E80	
+0xC063	0x7E81	
+0xC064	0x7E83	
+0xC065	0x7E84	
+0xC066	0x7E85	
+0xC067	0x7E86	
+0xC068	0x7E87	
+0xC069	0x7E88	
+0xC06A	0x7E89	
+0xC06B	0x7E8A	
+0xC06C	0x7E8B	
+0xC06D	0x7E8C	
+0xC06E	0x7E8D	
+0xC06F	0x7E8E	
+0xC070	0x7E8F	
+0xC071	0x7E90	
+0xC072	0x7E91	
+0xC073	0x7E92	
+0xC074	0x7E93	
+0xC075	0x7E94	
+0xC076	0x7E95	
+0xC077	0x7E96	
+0xC078	0x7E97	
+0xC079	0x7E98	
+0xC07A	0x7E99	
+0xC07B	0x7E9A	
+0xC07C	0x7E9C	
+0xC07D	0x7E9D	
+0xC07E	0x7E9E	
+0xC080	0x7EAE	
+0xC081	0x7EB4	
+0xC082	0x7EBB	
+0xC083	0x7EBC	
+0xC084	0x7ED6	
+0xC085	0x7EE4	
+0xC086	0x7EEC	
+0xC087	0x7EF9	
+0xC088	0x7F0A	
+0xC089	0x7F10	
+0xC08A	0x7F1E	
+0xC08B	0x7F37	
+0xC08C	0x7F39	
+0xC08D	0x7F3B	
+0xC08E	0x7F3C	
+0xC08F	0x7F3D	
+0xC090	0x7F3E	
+0xC091	0x7F3F	
+0xC092	0x7F40	
+0xC093	0x7F41	
+0xC094	0x7F43	
+0xC095	0x7F46	
+0xC096	0x7F47	
+0xC097	0x7F48	
+0xC098	0x7F49	
+0xC099	0x7F4A	
+0xC09A	0x7F4B	
+0xC09B	0x7F4C	
+0xC09C	0x7F4D	
+0xC09D	0x7F4E	
+0xC09E	0x7F4F	
+0xC09F	0x7F52	
+0xC0A0	0x7F53	
+0xC0A1	0x9988	
+0xC0A2	0x6127	
+0xC0A3	0x6E83	
+0xC0A4	0x5764	
+0xC0A5	0x6606	
+0xC0A6	0x6346	
+0xC0A7	0x56F0	
+0xC0A8	0x62EC	
+0xC0A9	0x6269	
+0xC0AA	0x5ED3	
+0xC0AB	0x9614	
+0xC0AC	0x5783	
+0xC0AD	0x62C9	
+0xC0AE	0x5587	
+0xC0AF	0x8721	
+0xC0B0	0x814A	
+0xC0B1	0x8FA3	
+0xC0B2	0x5566	
+0xC0B3	0x83B1	
+0xC0B4	0x6765	
+0xC0B5	0x8D56	
+0xC0B6	0x84DD	
+0xC0B7	0x5A6A	
+0xC0B8	0x680F	
+0xC0B9	0x62E6	
+0xC0BA	0x7BEE	
+0xC0BB	0x9611	
+0xC0BC	0x5170	
+0xC0BD	0x6F9C	
+0xC0BE	0x8C30	
+0xC0BF	0x63FD	
+0xC0C0	0x89C8	
+0xC0C1	0x61D2	
+0xC0C2	0x7F06	
+0xC0C3	0x70C2	
+0xC0C4	0x6EE5	
+0xC0C5	0x7405	
+0xC0C6	0x6994	
+0xC0C7	0x72FC	
+0xC0C8	0x5ECA	
+0xC0C9	0x90CE	
+0xC0CA	0x6717	
+0xC0CB	0x6D6A	
+0xC0CC	0x635E	
+0xC0CD	0x52B3	
+0xC0CE	0x7262	
+0xC0CF	0x8001	
+0xC0D0	0x4F6C	
+0xC0D1	0x59E5	
+0xC0D2	0x916A	
+0xC0D3	0x70D9	
+0xC0D4	0x6D9D	
+0xC0D5	0x52D2	
+0xC0D6	0x4E50	
+0xC0D7	0x96F7	
+0xC0D8	0x956D	
+0xC0D9	0x857E	
+0xC0DA	0x78CA	
+0xC0DB	0x7D2F	
+0xC0DC	0x5121	
+0xC0DD	0x5792	
+0xC0DE	0x64C2	
+0xC0DF	0x808B	
+0xC0E0	0x7C7B	
+0xC0E1	0x6CEA	
+0xC0E2	0x68F1	
+0xC0E3	0x695E	
+0xC0E4	0x51B7	
+0xC0E5	0x5398	
+0xC0E6	0x68A8	
+0xC0E7	0x7281	
+0xC0E8	0x9ECE	
+0xC0E9	0x7BF1	
+0xC0EA	0x72F8	
+0xC0EB	0x79BB	
+0xC0EC	0x6F13	
+0xC0ED	0x7406	
+0xC0EE	0x674E	
+0xC0EF	0x91CC	
+0xC0F0	0x9CA4	
+0xC0F1	0x793C	
+0xC0F2	0x8389	
+0xC0F3	0x8354	
+0xC0F4	0x540F	
+0xC0F5	0x6817	
+0xC0F6	0x4E3D	
+0xC0F7	0x5389	
+0xC0F8	0x52B1	
+0xC0F9	0x783E	
+0xC0FA	0x5386	
+0xC0FB	0x5229	
+0xC0FC	0x5088	
+0xC0FD	0x4F8B	
+0xC0FE	0x4FD0	
+0xC140	0x7F56	
+0xC141	0x7F59	
+0xC142	0x7F5B	
+0xC143	0x7F5C	
+0xC144	0x7F5D	
+0xC145	0x7F5E	
+0xC146	0x7F60	
+0xC147	0x7F63	
+0xC148	0x7F64	
+0xC149	0x7F65	
+0xC14A	0x7F66	
+0xC14B	0x7F67	
+0xC14C	0x7F6B	
+0xC14D	0x7F6C	
+0xC14E	0x7F6D	
+0xC14F	0x7F6F	
+0xC150	0x7F70	
+0xC151	0x7F73	
+0xC152	0x7F75	
+0xC153	0x7F76	
+0xC154	0x7F77	
+0xC155	0x7F78	
+0xC156	0x7F7A	
+0xC157	0x7F7B	
+0xC158	0x7F7C	
+0xC159	0x7F7D	
+0xC15A	0x7F7F	
+0xC15B	0x7F80	
+0xC15C	0x7F82	
+0xC15D	0x7F83	
+0xC15E	0x7F84	
+0xC15F	0x7F85	
+0xC160	0x7F86	
+0xC161	0x7F87	
+0xC162	0x7F88	
+0xC163	0x7F89	
+0xC164	0x7F8B	
+0xC165	0x7F8D	
+0xC166	0x7F8F	
+0xC167	0x7F90	
+0xC168	0x7F91	
+0xC169	0x7F92	
+0xC16A	0x7F93	
+0xC16B	0x7F95	
+0xC16C	0x7F96	
+0xC16D	0x7F97	
+0xC16E	0x7F98	
+0xC16F	0x7F99	
+0xC170	0x7F9B	
+0xC171	0x7F9C	
+0xC172	0x7FA0	
+0xC173	0x7FA2	
+0xC174	0x7FA3	
+0xC175	0x7FA5	
+0xC176	0x7FA6	
+0xC177	0x7FA8	
+0xC178	0x7FA9	
+0xC179	0x7FAA	
+0xC17A	0x7FAB	
+0xC17B	0x7FAC	
+0xC17C	0x7FAD	
+0xC17D	0x7FAE	
+0xC17E	0x7FB1	
+0xC180	0x7FB3	
+0xC181	0x7FB4	
+0xC182	0x7FB5	
+0xC183	0x7FB6	
+0xC184	0x7FB7	
+0xC185	0x7FBA	
+0xC186	0x7FBB	
+0xC187	0x7FBE	
+0xC188	0x7FC0	
+0xC189	0x7FC2	
+0xC18A	0x7FC3	
+0xC18B	0x7FC4	
+0xC18C	0x7FC6	
+0xC18D	0x7FC7	
+0xC18E	0x7FC8	
+0xC18F	0x7FC9	
+0xC190	0x7FCB	
+0xC191	0x7FCD	
+0xC192	0x7FCF	
+0xC193	0x7FD0	
+0xC194	0x7FD1	
+0xC195	0x7FD2	
+0xC196	0x7FD3	
+0xC197	0x7FD6	
+0xC198	0x7FD7	
+0xC199	0x7FD9	
+0xC19A	0x7FDA	
+0xC19B	0x7FDB	
+0xC19C	0x7FDC	
+0xC19D	0x7FDD	
+0xC19E	0x7FDE	
+0xC19F	0x7FE2	
+0xC1A0	0x7FE3	
+0xC1A1	0x75E2	
+0xC1A2	0x7ACB	
+0xC1A3	0x7C92	
+0xC1A4	0x6CA5	
+0xC1A5	0x96B6	
+0xC1A6	0x529B	
+0xC1A7	0x7483	
+0xC1A8	0x54E9	
+0xC1A9	0x4FE9	
+0xC1AA	0x8054	
+0xC1AB	0x83B2	
+0xC1AC	0x8FDE	
+0xC1AD	0x9570	
+0xC1AE	0x5EC9	
+0xC1AF	0x601C	
+0xC1B0	0x6D9F	
+0xC1B1	0x5E18	
+0xC1B2	0x655B	
+0xC1B3	0x8138	
+0xC1B4	0x94FE	
+0xC1B5	0x604B	
+0xC1B6	0x70BC	
+0xC1B7	0x7EC3	
+0xC1B8	0x7CAE	
+0xC1B9	0x51C9	
+0xC1BA	0x6881	
+0xC1BB	0x7CB1	
+0xC1BC	0x826F	
+0xC1BD	0x4E24	
+0xC1BE	0x8F86	
+0xC1BF	0x91CF	
+0xC1C0	0x667E	
+0xC1C1	0x4EAE	
+0xC1C2	0x8C05	
+0xC1C3	0x64A9	
+0xC1C4	0x804A	
+0xC1C5	0x50DA	
+0xC1C6	0x7597	
+0xC1C7	0x71CE	
+0xC1C8	0x5BE5	
+0xC1C9	0x8FBD	
+0xC1CA	0x6F66	
+0xC1CB	0x4E86	
+0xC1CC	0x6482	
+0xC1CD	0x9563	
+0xC1CE	0x5ED6	
+0xC1CF	0x6599	
+0xC1D0	0x5217	
+0xC1D1	0x88C2	
+0xC1D2	0x70C8	
+0xC1D3	0x52A3	
+0xC1D4	0x730E	
+0xC1D5	0x7433	
+0xC1D6	0x6797	
+0xC1D7	0x78F7	
+0xC1D8	0x9716	
+0xC1D9	0x4E34	
+0xC1DA	0x90BB	
+0xC1DB	0x9CDE	
+0xC1DC	0x6DCB	
+0xC1DD	0x51DB	
+0xC1DE	0x8D41	
+0xC1DF	0x541D	
+0xC1E0	0x62CE	
+0xC1E1	0x73B2	
+0xC1E2	0x83F1	
+0xC1E3	0x96F6	
+0xC1E4	0x9F84	
+0xC1E5	0x94C3	
+0xC1E6	0x4F36	
+0xC1E7	0x7F9A	
+0xC1E8	0x51CC	
+0xC1E9	0x7075	
+0xC1EA	0x9675	
+0xC1EB	0x5CAD	
+0xC1EC	0x9886	
+0xC1ED	0x53E6	
+0xC1EE	0x4EE4	
+0xC1EF	0x6E9C	
+0xC1F0	0x7409	
+0xC1F1	0x69B4	
+0xC1F2	0x786B	
+0xC1F3	0x998F	
+0xC1F4	0x7559	
+0xC1F5	0x5218	
+0xC1F6	0x7624	
+0xC1F7	0x6D41	
+0xC1F8	0x67F3	
+0xC1F9	0x516D	
+0xC1FA	0x9F99	
+0xC1FB	0x804B	
+0xC1FC	0x5499	
+0xC1FD	0x7B3C	
+0xC1FE	0x7ABF	
+0xC240	0x7FE4	
+0xC241	0x7FE7	
+0xC242	0x7FE8	
+0xC243	0x7FEA	
+0xC244	0x7FEB	
+0xC245	0x7FEC	
+0xC246	0x7FED	
+0xC247	0x7FEF	
+0xC248	0x7FF2	
+0xC249	0x7FF4	
+0xC24A	0x7FF5	
+0xC24B	0x7FF6	
+0xC24C	0x7FF7	
+0xC24D	0x7FF8	
+0xC24E	0x7FF9	
+0xC24F	0x7FFA	
+0xC250	0x7FFD	
+0xC251	0x7FFE	
+0xC252	0x7FFF	
+0xC253	0x8002	
+0xC254	0x8007	
+0xC255	0x8008	
+0xC256	0x8009	
+0xC257	0x800A	
+0xC258	0x800E	
+0xC259	0x800F	
+0xC25A	0x8011	
+0xC25B	0x8013	
+0xC25C	0x801A	
+0xC25D	0x801B	
+0xC25E	0x801D	
+0xC25F	0x801E	
+0xC260	0x801F	
+0xC261	0x8021	
+0xC262	0x8023	
+0xC263	0x8024	
+0xC264	0x802B	
+0xC265	0x802C	
+0xC266	0x802D	
+0xC267	0x802E	
+0xC268	0x802F	
+0xC269	0x8030	
+0xC26A	0x8032	
+0xC26B	0x8034	
+0xC26C	0x8039	
+0xC26D	0x803A	
+0xC26E	0x803C	
+0xC26F	0x803E	
+0xC270	0x8040	
+0xC271	0x8041	
+0xC272	0x8044	
+0xC273	0x8045	
+0xC274	0x8047	
+0xC275	0x8048	
+0xC276	0x8049	
+0xC277	0x804E	
+0xC278	0x804F	
+0xC279	0x8050	
+0xC27A	0x8051	
+0xC27B	0x8053	
+0xC27C	0x8055	
+0xC27D	0x8056	
+0xC27E	0x8057	
+0xC280	0x8059	
+0xC281	0x805B	
+0xC282	0x805C	
+0xC283	0x805D	
+0xC284	0x805E	
+0xC285	0x805F	
+0xC286	0x8060	
+0xC287	0x8061	
+0xC288	0x8062	
+0xC289	0x8063	
+0xC28A	0x8064	
+0xC28B	0x8065	
+0xC28C	0x8066	
+0xC28D	0x8067	
+0xC28E	0x8068	
+0xC28F	0x806B	
+0xC290	0x806C	
+0xC291	0x806D	
+0xC292	0x806E	
+0xC293	0x806F	
+0xC294	0x8070	
+0xC295	0x8072	
+0xC296	0x8073	
+0xC297	0x8074	
+0xC298	0x8075	
+0xC299	0x8076	
+0xC29A	0x8077	
+0xC29B	0x8078	
+0xC29C	0x8079	
+0xC29D	0x807A	
+0xC29E	0x807B	
+0xC29F	0x807C	
+0xC2A0	0x807D	
+0xC2A1	0x9686	
+0xC2A2	0x5784	
+0xC2A3	0x62E2	
+0xC2A4	0x9647	
+0xC2A5	0x697C	
+0xC2A6	0x5A04	
+0xC2A7	0x6402	
+0xC2A8	0x7BD3	
+0xC2A9	0x6F0F	
+0xC2AA	0x964B	
+0xC2AB	0x82A6	
+0xC2AC	0x5362	
+0xC2AD	0x9885	
+0xC2AE	0x5E90	
+0xC2AF	0x7089	
+0xC2B0	0x63B3	
+0xC2B1	0x5364	
+0xC2B2	0x864F	
+0xC2B3	0x9C81	
+0xC2B4	0x9E93	
+0xC2B5	0x788C	
+0xC2B6	0x9732	
+0xC2B7	0x8DEF	
+0xC2B8	0x8D42	
+0xC2B9	0x9E7F	
+0xC2BA	0x6F5E	
+0xC2BB	0x7984	
+0xC2BC	0x5F55	
+0xC2BD	0x9646	
+0xC2BE	0x622E	
+0xC2BF	0x9A74	
+0xC2C0	0x5415	
+0xC2C1	0x94DD	
+0xC2C2	0x4FA3	
+0xC2C3	0x65C5	
+0xC2C4	0x5C65	
+0xC2C5	0x5C61	
+0xC2C6	0x7F15	
+0xC2C7	0x8651	
+0xC2C8	0x6C2F	
+0xC2C9	0x5F8B	
+0xC2CA	0x7387	
+0xC2CB	0x6EE4	
+0xC2CC	0x7EFF	
+0xC2CD	0x5CE6	
+0xC2CE	0x631B	
+0xC2CF	0x5B6A	
+0xC2D0	0x6EE6	
+0xC2D1	0x5375	
+0xC2D2	0x4E71	
+0xC2D3	0x63A0	
+0xC2D4	0x7565	
+0xC2D5	0x62A1	
+0xC2D6	0x8F6E	
+0xC2D7	0x4F26	
+0xC2D8	0x4ED1	
+0xC2D9	0x6CA6	
+0xC2DA	0x7EB6	
+0xC2DB	0x8BBA	
+0xC2DC	0x841D	
+0xC2DD	0x87BA	
+0xC2DE	0x7F57	
+0xC2DF	0x903B	
+0xC2E0	0x9523	
+0xC2E1	0x7BA9	
+0xC2E2	0x9AA1	
+0xC2E3	0x88F8	
+0xC2E4	0x843D	
+0xC2E5	0x6D1B	
+0xC2E6	0x9A86	
+0xC2E7	0x7EDC	
+0xC2E8	0x5988	
+0xC2E9	0x9EBB	
+0xC2EA	0x739B	
+0xC2EB	0x7801	
+0xC2EC	0x8682	
+0xC2ED	0x9A6C	
+0xC2EE	0x9A82	
+0xC2EF	0x561B	
+0xC2F0	0x5417	
+0xC2F1	0x57CB	
+0xC2F2	0x4E70	
+0xC2F3	0x9EA6	
+0xC2F4	0x5356	
+0xC2F5	0x8FC8	
+0xC2F6	0x8109	
+0xC2F7	0x7792	
+0xC2F8	0x9992	
+0xC2F9	0x86EE	
+0xC2FA	0x6EE1	
+0xC2FB	0x8513	
+0xC2FC	0x66FC	
+0xC2FD	0x6162	
+0xC2FE	0x6F2B	
+0xC340	0x807E	
+0xC341	0x8081	
+0xC342	0x8082	
+0xC343	0x8085	
+0xC344	0x8088	
+0xC345	0x808A	
+0xC346	0x808D	
+0xC347	0x808E	
+0xC348	0x808F	
+0xC349	0x8090	
+0xC34A	0x8091	
+0xC34B	0x8092	
+0xC34C	0x8094	
+0xC34D	0x8095	
+0xC34E	0x8097	
+0xC34F	0x8099	
+0xC350	0x809E	
+0xC351	0x80A3	
+0xC352	0x80A6	
+0xC353	0x80A7	
+0xC354	0x80A8	
+0xC355	0x80AC	
+0xC356	0x80B0	
+0xC357	0x80B3	
+0xC358	0x80B5	
+0xC359	0x80B6	
+0xC35A	0x80B8	
+0xC35B	0x80B9	
+0xC35C	0x80BB	
+0xC35D	0x80C5	
+0xC35E	0x80C7	
+0xC35F	0x80C8	
+0xC360	0x80C9	
+0xC361	0x80CA	
+0xC362	0x80CB	
+0xC363	0x80CF	
+0xC364	0x80D0	
+0xC365	0x80D1	
+0xC366	0x80D2	
+0xC367	0x80D3	
+0xC368	0x80D4	
+0xC369	0x80D5	
+0xC36A	0x80D8	
+0xC36B	0x80DF	
+0xC36C	0x80E0	
+0xC36D	0x80E2	
+0xC36E	0x80E3	
+0xC36F	0x80E6	
+0xC370	0x80EE	
+0xC371	0x80F5	
+0xC372	0x80F7	
+0xC373	0x80F9	
+0xC374	0x80FB	
+0xC375	0x80FE	
+0xC376	0x80FF	
+0xC377	0x8100	
+0xC378	0x8101	
+0xC379	0x8103	
+0xC37A	0x8104	
+0xC37B	0x8105	
+0xC37C	0x8107	
+0xC37D	0x8108	
+0xC37E	0x810B	
+0xC380	0x810C	
+0xC381	0x8115	
+0xC382	0x8117	
+0xC383	0x8119	
+0xC384	0x811B	
+0xC385	0x811C	
+0xC386	0x811D	
+0xC387	0x811F	
+0xC388	0x8120	
+0xC389	0x8121	
+0xC38A	0x8122	
+0xC38B	0x8123	
+0xC38C	0x8124	
+0xC38D	0x8125	
+0xC38E	0x8126	
+0xC38F	0x8127	
+0xC390	0x8128	
+0xC391	0x8129	
+0xC392	0x812A	
+0xC393	0x812B	
+0xC394	0x812D	
+0xC395	0x812E	
+0xC396	0x8130	
+0xC397	0x8133	
+0xC398	0x8134	
+0xC399	0x8135	
+0xC39A	0x8137	
+0xC39B	0x8139	
+0xC39C	0x813A	
+0xC39D	0x813B	
+0xC39E	0x813C	
+0xC39F	0x813D	
+0xC3A0	0x813F	
+0xC3A1	0x8C29	
+0xC3A2	0x8292	
+0xC3A3	0x832B	
+0xC3A4	0x76F2	
+0xC3A5	0x6C13	
+0xC3A6	0x5FD9	
+0xC3A7	0x83BD	
+0xC3A8	0x732B	
+0xC3A9	0x8305	
+0xC3AA	0x951A	
+0xC3AB	0x6BDB	
+0xC3AC	0x77DB	
+0xC3AD	0x94C6	
+0xC3AE	0x536F	
+0xC3AF	0x8302	
+0xC3B0	0x5192	
+0xC3B1	0x5E3D	
+0xC3B2	0x8C8C	
+0xC3B3	0x8D38	
+0xC3B4	0x4E48	
+0xC3B5	0x73AB	
+0xC3B6	0x679A	
+0xC3B7	0x6885	
+0xC3B8	0x9176	
+0xC3B9	0x9709	
+0xC3BA	0x7164	
+0xC3BB	0x6CA1	
+0xC3BC	0x7709	
+0xC3BD	0x5A92	
+0xC3BE	0x9541	
+0xC3BF	0x6BCF	
+0xC3C0	0x7F8E	
+0xC3C1	0x6627	
+0xC3C2	0x5BD0	
+0xC3C3	0x59B9	
+0xC3C4	0x5A9A	
+0xC3C5	0x95E8	
+0xC3C6	0x95F7	
+0xC3C7	0x4EEC	
+0xC3C8	0x840C	
+0xC3C9	0x8499	
+0xC3CA	0x6AAC	
+0xC3CB	0x76DF	
+0xC3CC	0x9530	
+0xC3CD	0x731B	
+0xC3CE	0x68A6	
+0xC3CF	0x5B5F	
+0xC3D0	0x772F	
+0xC3D1	0x919A	
+0xC3D2	0x9761	
+0xC3D3	0x7CDC	
+0xC3D4	0x8FF7	
+0xC3D5	0x8C1C	
+0xC3D6	0x5F25	
+0xC3D7	0x7C73	
+0xC3D8	0x79D8	
+0xC3D9	0x89C5	
+0xC3DA	0x6CCC	
+0xC3DB	0x871C	
+0xC3DC	0x5BC6	
+0xC3DD	0x5E42	
+0xC3DE	0x68C9	
+0xC3DF	0x7720	
+0xC3E0	0x7EF5	
+0xC3E1	0x5195	
+0xC3E2	0x514D	
+0xC3E3	0x52C9	
+0xC3E4	0x5A29	
+0xC3E5	0x7F05	
+0xC3E6	0x9762	
+0xC3E7	0x82D7	
+0xC3E8	0x63CF	
+0xC3E9	0x7784	
+0xC3EA	0x85D0	
+0xC3EB	0x79D2	
+0xC3EC	0x6E3A	
+0xC3ED	0x5E99	
+0xC3EE	0x5999	
+0xC3EF	0x8511	
+0xC3F0	0x706D	
+0xC3F1	0x6C11	
+0xC3F2	0x62BF	
+0xC3F3	0x76BF	
+0xC3F4	0x654F	
+0xC3F5	0x60AF	
+0xC3F6	0x95FD	
+0xC3F7	0x660E	
+0xC3F8	0x879F	
+0xC3F9	0x9E23	
+0xC3FA	0x94ED	
+0xC3FB	0x540D	
+0xC3FC	0x547D	
+0xC3FD	0x8C2C	
+0xC3FE	0x6478	
+0xC440	0x8140	
+0xC441	0x8141	
+0xC442	0x8142	
+0xC443	0x8143	
+0xC444	0x8144	
+0xC445	0x8145	
+0xC446	0x8147	
+0xC447	0x8149	
+0xC448	0x814D	
+0xC449	0x814E	
+0xC44A	0x814F	
+0xC44B	0x8152	
+0xC44C	0x8156	
+0xC44D	0x8157	
+0xC44E	0x8158	
+0xC44F	0x815B	
+0xC450	0x815C	
+0xC451	0x815D	
+0xC452	0x815E	
+0xC453	0x815F	
+0xC454	0x8161	
+0xC455	0x8162	
+0xC456	0x8163	
+0xC457	0x8164	
+0xC458	0x8166	
+0xC459	0x8168	
+0xC45A	0x816A	
+0xC45B	0x816B	
+0xC45C	0x816C	
+0xC45D	0x816F	
+0xC45E	0x8172	
+0xC45F	0x8173	
+0xC460	0x8175	
+0xC461	0x8176	
+0xC462	0x8177	
+0xC463	0x8178	
+0xC464	0x8181	
+0xC465	0x8183	
+0xC466	0x8184	
+0xC467	0x8185	
+0xC468	0x8186	
+0xC469	0x8187	
+0xC46A	0x8189	
+0xC46B	0x818B	
+0xC46C	0x818C	
+0xC46D	0x818D	
+0xC46E	0x818E	
+0xC46F	0x8190	
+0xC470	0x8192	
+0xC471	0x8193	
+0xC472	0x8194	
+0xC473	0x8195	
+0xC474	0x8196	
+0xC475	0x8197	
+0xC476	0x8199	
+0xC477	0x819A	
+0xC478	0x819E	
+0xC479	0x819F	
+0xC47A	0x81A0	
+0xC47B	0x81A1	
+0xC47C	0x81A2	
+0xC47D	0x81A4	
+0xC47E	0x81A5	
+0xC480	0x81A7	
+0xC481	0x81A9	
+0xC482	0x81AB	
+0xC483	0x81AC	
+0xC484	0x81AD	
+0xC485	0x81AE	
+0xC486	0x81AF	
+0xC487	0x81B0	
+0xC488	0x81B1	
+0xC489	0x81B2	
+0xC48A	0x81B4	
+0xC48B	0x81B5	
+0xC48C	0x81B6	
+0xC48D	0x81B7	
+0xC48E	0x81B8	
+0xC48F	0x81B9	
+0xC490	0x81BC	
+0xC491	0x81BD	
+0xC492	0x81BE	
+0xC493	0x81BF	
+0xC494	0x81C4	
+0xC495	0x81C5	
+0xC496	0x81C7	
+0xC497	0x81C8	
+0xC498	0x81C9	
+0xC499	0x81CB	
+0xC49A	0x81CD	
+0xC49B	0x81CE	
+0xC49C	0x81CF	
+0xC49D	0x81D0	
+0xC49E	0x81D1	
+0xC49F	0x81D2	
+0xC4A0	0x81D3	
+0xC4A1	0x6479	
+0xC4A2	0x8611	
+0xC4A3	0x6A21	
+0xC4A4	0x819C	
+0xC4A5	0x78E8	
+0xC4A6	0x6469	
+0xC4A7	0x9B54	
+0xC4A8	0x62B9	
+0xC4A9	0x672B	
+0xC4AA	0x83AB	
+0xC4AB	0x58A8	
+0xC4AC	0x9ED8	
+0xC4AD	0x6CAB	
+0xC4AE	0x6F20	
+0xC4AF	0x5BDE	
+0xC4B0	0x964C	
+0xC4B1	0x8C0B	
+0xC4B2	0x725F	
+0xC4B3	0x67D0	
+0xC4B4	0x62C7	
+0xC4B5	0x7261	
+0xC4B6	0x4EA9	
+0xC4B7	0x59C6	
+0xC4B8	0x6BCD	
+0xC4B9	0x5893	
+0xC4BA	0x66AE	
+0xC4BB	0x5E55	
+0xC4BC	0x52DF	
+0xC4BD	0x6155	
+0xC4BE	0x6728	
+0xC4BF	0x76EE	
+0xC4C0	0x7766	
+0xC4C1	0x7267	
+0xC4C2	0x7A46	
+0xC4C3	0x62FF	
+0xC4C4	0x54EA	
+0xC4C5	0x5450	
+0xC4C6	0x94A0	
+0xC4C7	0x90A3	
+0xC4C8	0x5A1C	
+0xC4C9	0x7EB3	
+0xC4CA	0x6C16	
+0xC4CB	0x4E43	
+0xC4CC	0x5976	
+0xC4CD	0x8010	
+0xC4CE	0x5948	
+0xC4CF	0x5357	
+0xC4D0	0x7537	
+0xC4D1	0x96BE	
+0xC4D2	0x56CA	
+0xC4D3	0x6320	
+0xC4D4	0x8111	
+0xC4D5	0x607C	
+0xC4D6	0x95F9	
+0xC4D7	0x6DD6	
+0xC4D8	0x5462	
+0xC4D9	0x9981	
+0xC4DA	0x5185	
+0xC4DB	0x5AE9	
+0xC4DC	0x80FD	
+0xC4DD	0x59AE	
+0xC4DE	0x9713	
+0xC4DF	0x502A	
+0xC4E0	0x6CE5	
+0xC4E1	0x5C3C	
+0xC4E2	0x62DF	
+0xC4E3	0x4F60	
+0xC4E4	0x533F	
+0xC4E5	0x817B	
+0xC4E6	0x9006	
+0xC4E7	0x6EBA	
+0xC4E8	0x852B	
+0xC4E9	0x62C8	
+0xC4EA	0x5E74	
+0xC4EB	0x78BE	
+0xC4EC	0x64B5	
+0xC4ED	0x637B	
+0xC4EE	0x5FF5	
+0xC4EF	0x5A18	
+0xC4F0	0x917F	
+0xC4F1	0x9E1F	
+0xC4F2	0x5C3F	
+0xC4F3	0x634F	
+0xC4F4	0x8042	
+0xC4F5	0x5B7D	
+0xC4F6	0x556E	
+0xC4F7	0x954A	
+0xC4F8	0x954D	
+0xC4F9	0x6D85	
+0xC4FA	0x60A8	
+0xC4FB	0x67E0	
+0xC4FC	0x72DE	
+0xC4FD	0x51DD	
+0xC4FE	0x5B81	
+0xC540	0x81D4	
+0xC541	0x81D5	
+0xC542	0x81D6	
+0xC543	0x81D7	
+0xC544	0x81D8	
+0xC545	0x81D9	
+0xC546	0x81DA	
+0xC547	0x81DB	
+0xC548	0x81DC	
+0xC549	0x81DD	
+0xC54A	0x81DE	
+0xC54B	0x81DF	
+0xC54C	0x81E0	
+0xC54D	0x81E1	
+0xC54E	0x81E2	
+0xC54F	0x81E4	
+0xC550	0x81E5	
+0xC551	0x81E6	
+0xC552	0x81E8	
+0xC553	0x81E9	
+0xC554	0x81EB	
+0xC555	0x81EE	
+0xC556	0x81EF	
+0xC557	0x81F0	
+0xC558	0x81F1	
+0xC559	0x81F2	
+0xC55A	0x81F5	
+0xC55B	0x81F6	
+0xC55C	0x81F7	
+0xC55D	0x81F8	
+0xC55E	0x81F9	
+0xC55F	0x81FA	
+0xC560	0x81FD	
+0xC561	0x81FF	
+0xC562	0x8203	
+0xC563	0x8207	
+0xC564	0x8208	
+0xC565	0x8209	
+0xC566	0x820A	
+0xC567	0x820B	
+0xC568	0x820E	
+0xC569	0x820F	
+0xC56A	0x8211	
+0xC56B	0x8213	
+0xC56C	0x8215	
+0xC56D	0x8216	
+0xC56E	0x8217	
+0xC56F	0x8218	
+0xC570	0x8219	
+0xC571	0x821A	
+0xC572	0x821D	
+0xC573	0x8220	
+0xC574	0x8224	
+0xC575	0x8225	
+0xC576	0x8226	
+0xC577	0x8227	
+0xC578	0x8229	
+0xC579	0x822E	
+0xC57A	0x8232	
+0xC57B	0x823A	
+0xC57C	0x823C	
+0xC57D	0x823D	
+0xC57E	0x823F	
+0xC580	0x8240	
+0xC581	0x8241	
+0xC582	0x8242	
+0xC583	0x8243	
+0xC584	0x8245	
+0xC585	0x8246	
+0xC586	0x8248	
+0xC587	0x824A	
+0xC588	0x824C	
+0xC589	0x824D	
+0xC58A	0x824E	
+0xC58B	0x8250	
+0xC58C	0x8251	
+0xC58D	0x8252	
+0xC58E	0x8253	
+0xC58F	0x8254	
+0xC590	0x8255	
+0xC591	0x8256	
+0xC592	0x8257	
+0xC593	0x8259	
+0xC594	0x825B	
+0xC595	0x825C	
+0xC596	0x825D	
+0xC597	0x825E	
+0xC598	0x8260	
+0xC599	0x8261	
+0xC59A	0x8262	
+0xC59B	0x8263	
+0xC59C	0x8264	
+0xC59D	0x8265	
+0xC59E	0x8266	
+0xC59F	0x8267	
+0xC5A0	0x8269	
+0xC5A1	0x62E7	
+0xC5A2	0x6CDE	
+0xC5A3	0x725B	
+0xC5A4	0x626D	
+0xC5A5	0x94AE	
+0xC5A6	0x7EBD	
+0xC5A7	0x8113	
+0xC5A8	0x6D53	
+0xC5A9	0x519C	
+0xC5AA	0x5F04	
+0xC5AB	0x5974	
+0xC5AC	0x52AA	
+0xC5AD	0x6012	
+0xC5AE	0x5973	
+0xC5AF	0x6696	
+0xC5B0	0x8650	
+0xC5B1	0x759F	
+0xC5B2	0x632A	
+0xC5B3	0x61E6	
+0xC5B4	0x7CEF	
+0xC5B5	0x8BFA	
+0xC5B6	0x54E6	
+0xC5B7	0x6B27	
+0xC5B8	0x9E25	
+0xC5B9	0x6BB4	
+0xC5BA	0x85D5	
+0xC5BB	0x5455	
+0xC5BC	0x5076	
+0xC5BD	0x6CA4	
+0xC5BE	0x556A	
+0xC5BF	0x8DB4	
+0xC5C0	0x722C	
+0xC5C1	0x5E15	
+0xC5C2	0x6015	
+0xC5C3	0x7436	
+0xC5C4	0x62CD	
+0xC5C5	0x6392	
+0xC5C6	0x724C	
+0xC5C7	0x5F98	
+0xC5C8	0x6E43	
+0xC5C9	0x6D3E	
+0xC5CA	0x6500	
+0xC5CB	0x6F58	
+0xC5CC	0x76D8	
+0xC5CD	0x78D0	
+0xC5CE	0x76FC	
+0xC5CF	0x7554	
+0xC5D0	0x5224	
+0xC5D1	0x53DB	
+0xC5D2	0x4E53	
+0xC5D3	0x5E9E	
+0xC5D4	0x65C1	
+0xC5D5	0x802A	
+0xC5D6	0x80D6	
+0xC5D7	0x629B	
+0xC5D8	0x5486	
+0xC5D9	0x5228	
+0xC5DA	0x70AE	
+0xC5DB	0x888D	
+0xC5DC	0x8DD1	
+0xC5DD	0x6CE1	
+0xC5DE	0x5478	
+0xC5DF	0x80DA	
+0xC5E0	0x57F9	
+0xC5E1	0x88F4	
+0xC5E2	0x8D54	
+0xC5E3	0x966A	
+0xC5E4	0x914D	
+0xC5E5	0x4F69	
+0xC5E6	0x6C9B	
+0xC5E7	0x55B7	
+0xC5E8	0x76C6	
+0xC5E9	0x7830	
+0xC5EA	0x62A8	
+0xC5EB	0x70F9	
+0xC5EC	0x6F8E	
+0xC5ED	0x5F6D	
+0xC5EE	0x84EC	
+0xC5EF	0x68DA	
+0xC5F0	0x787C	
+0xC5F1	0x7BF7	
+0xC5F2	0x81A8	
+0xC5F3	0x670B	
+0xC5F4	0x9E4F	
+0xC5F5	0x6367	
+0xC5F6	0x78B0	
+0xC5F7	0x576F	
+0xC5F8	0x7812	
+0xC5F9	0x9739	
+0xC5FA	0x6279	
+0xC5FB	0x62AB	
+0xC5FC	0x5288	
+0xC5FD	0x7435	
+0xC5FE	0x6BD7	
+0xC640	0x826A	
+0xC641	0x826B	
+0xC642	0x826C	
+0xC643	0x826D	
+0xC644	0x8271	
+0xC645	0x8275	
+0xC646	0x8276	
+0xC647	0x8277	
+0xC648	0x8278	
+0xC649	0x827B	
+0xC64A	0x827C	
+0xC64B	0x8280	
+0xC64C	0x8281	
+0xC64D	0x8283	
+0xC64E	0x8285	
+0xC64F	0x8286	
+0xC650	0x8287	
+0xC651	0x8289	
+0xC652	0x828C	
+0xC653	0x8290	
+0xC654	0x8293	
+0xC655	0x8294	
+0xC656	0x8295	
+0xC657	0x8296	
+0xC658	0x829A	
+0xC659	0x829B	
+0xC65A	0x829E	
+0xC65B	0x82A0	
+0xC65C	0x82A2	
+0xC65D	0x82A3	
+0xC65E	0x82A7	
+0xC65F	0x82B2	
+0xC660	0x82B5	
+0xC661	0x82B6	
+0xC662	0x82BA	
+0xC663	0x82BB	
+0xC664	0x82BC	
+0xC665	0x82BF	
+0xC666	0x82C0	
+0xC667	0x82C2	
+0xC668	0x82C3	
+0xC669	0x82C5	
+0xC66A	0x82C6	
+0xC66B	0x82C9	
+0xC66C	0x82D0	
+0xC66D	0x82D6	
+0xC66E	0x82D9	
+0xC66F	0x82DA	
+0xC670	0x82DD	
+0xC671	0x82E2	
+0xC672	0x82E7	
+0xC673	0x82E8	
+0xC674	0x82E9	
+0xC675	0x82EA	
+0xC676	0x82EC	
+0xC677	0x82ED	
+0xC678	0x82EE	
+0xC679	0x82F0	
+0xC67A	0x82F2	
+0xC67B	0x82F3	
+0xC67C	0x82F5	
+0xC67D	0x82F6	
+0xC67E	0x82F8	
+0xC680	0x82FA	
+0xC681	0x82FC	
+0xC682	0x82FD	
+0xC683	0x82FE	
+0xC684	0x82FF	
+0xC685	0x8300	
+0xC686	0x830A	
+0xC687	0x830B	
+0xC688	0x830D	
+0xC689	0x8310	
+0xC68A	0x8312	
+0xC68B	0x8313	
+0xC68C	0x8316	
+0xC68D	0x8318	
+0xC68E	0x8319	
+0xC68F	0x831D	
+0xC690	0x831E	
+0xC691	0x831F	
+0xC692	0x8320	
+0xC693	0x8321	
+0xC694	0x8322	
+0xC695	0x8323	
+0xC696	0x8324	
+0xC697	0x8325	
+0xC698	0x8326	
+0xC699	0x8329	
+0xC69A	0x832A	
+0xC69B	0x832E	
+0xC69C	0x8330	
+0xC69D	0x8332	
+0xC69E	0x8337	
+0xC69F	0x833B	
+0xC6A0	0x833D	
+0xC6A1	0x5564	
+0xC6A2	0x813E	
+0xC6A3	0x75B2	
+0xC6A4	0x76AE	
+0xC6A5	0x5339	
+0xC6A6	0x75DE	
+0xC6A7	0x50FB	
+0xC6A8	0x5C41	
+0xC6A9	0x8B6C	
+0xC6AA	0x7BC7	
+0xC6AB	0x504F	
+0xC6AC	0x7247	
+0xC6AD	0x9A97	
+0xC6AE	0x98D8	
+0xC6AF	0x6F02	
+0xC6B0	0x74E2	
+0xC6B1	0x7968	
+0xC6B2	0x6487	
+0xC6B3	0x77A5	
+0xC6B4	0x62FC	
+0xC6B5	0x9891	
+0xC6B6	0x8D2B	
+0xC6B7	0x54C1	
+0xC6B8	0x8058	
+0xC6B9	0x4E52	
+0xC6BA	0x576A	
+0xC6BB	0x82F9	
+0xC6BC	0x840D	
+0xC6BD	0x5E73	
+0xC6BE	0x51ED	
+0xC6BF	0x74F6	
+0xC6C0	0x8BC4	
+0xC6C1	0x5C4F	
+0xC6C2	0x5761	
+0xC6C3	0x6CFC	
+0xC6C4	0x9887	
+0xC6C5	0x5A46	
+0xC6C6	0x7834	
+0xC6C7	0x9B44	
+0xC6C8	0x8FEB	
+0xC6C9	0x7C95	
+0xC6CA	0x5256	
+0xC6CB	0x6251	
+0xC6CC	0x94FA	
+0xC6CD	0x4EC6	
+0xC6CE	0x8386	
+0xC6CF	0x8461	
+0xC6D0	0x83E9	
+0xC6D1	0x84B2	
+0xC6D2	0x57D4	
+0xC6D3	0x6734	
+0xC6D4	0x5703	
+0xC6D5	0x666E	
+0xC6D6	0x6D66	
+0xC6D7	0x8C31	
+0xC6D8	0x66DD	
+0xC6D9	0x7011	
+0xC6DA	0x671F	
+0xC6DB	0x6B3A	
+0xC6DC	0x6816	
+0xC6DD	0x621A	
+0xC6DE	0x59BB	
+0xC6DF	0x4E03	
+0xC6E0	0x51C4	
+0xC6E1	0x6F06	
+0xC6E2	0x67D2	
+0xC6E3	0x6C8F	
+0xC6E4	0x5176	
+0xC6E5	0x68CB	
+0xC6E6	0x5947	
+0xC6E7	0x6B67	
+0xC6E8	0x7566	
+0xC6E9	0x5D0E	
+0xC6EA	0x8110	
+0xC6EB	0x9F50	
+0xC6EC	0x65D7	
+0xC6ED	0x7948	
+0xC6EE	0x7941	
+0xC6EF	0x9A91	
+0xC6F0	0x8D77	
+0xC6F1	0x5C82	
+0xC6F2	0x4E5E	
+0xC6F3	0x4F01	
+0xC6F4	0x542F	
+0xC6F5	0x5951	
+0xC6F6	0x780C	
+0xC6F7	0x5668	
+0xC6F8	0x6C14	
+0xC6F9	0x8FC4	
+0xC6FA	0x5F03	
+0xC6FB	0x6C7D	
+0xC6FC	0x6CE3	
+0xC6FD	0x8BAB	
+0xC6FE	0x6390	
+0xC740	0x833E	
+0xC741	0x833F	
+0xC742	0x8341	
+0xC743	0x8342	
+0xC744	0x8344	
+0xC745	0x8345	
+0xC746	0x8348	
+0xC747	0x834A	
+0xC748	0x834B	
+0xC749	0x834C	
+0xC74A	0x834D	
+0xC74B	0x834E	
+0xC74C	0x8353	
+0xC74D	0x8355	
+0xC74E	0x8356	
+0xC74F	0x8357	
+0xC750	0x8358	
+0xC751	0x8359	
+0xC752	0x835D	
+0xC753	0x8362	
+0xC754	0x8370	
+0xC755	0x8371	
+0xC756	0x8372	
+0xC757	0x8373	
+0xC758	0x8374	
+0xC759	0x8375	
+0xC75A	0x8376	
+0xC75B	0x8379	
+0xC75C	0x837A	
+0xC75D	0x837E	
+0xC75E	0x837F	
+0xC75F	0x8380	
+0xC760	0x8381	
+0xC761	0x8382	
+0xC762	0x8383	
+0xC763	0x8384	
+0xC764	0x8387	
+0xC765	0x8388	
+0xC766	0x838A	
+0xC767	0x838B	
+0xC768	0x838C	
+0xC769	0x838D	
+0xC76A	0x838F	
+0xC76B	0x8390	
+0xC76C	0x8391	
+0xC76D	0x8394	
+0xC76E	0x8395	
+0xC76F	0x8396	
+0xC770	0x8397	
+0xC771	0x8399	
+0xC772	0x839A	
+0xC773	0x839D	
+0xC774	0x839F	
+0xC775	0x83A1	
+0xC776	0x83A2	
+0xC777	0x83A3	
+0xC778	0x83A4	
+0xC779	0x83A5	
+0xC77A	0x83A6	
+0xC77B	0x83A7	
+0xC77C	0x83AC	
+0xC77D	0x83AD	
+0xC77E	0x83AE	
+0xC780	0x83AF	
+0xC781	0x83B5	
+0xC782	0x83BB	
+0xC783	0x83BE	
+0xC784	0x83BF	
+0xC785	0x83C2	
+0xC786	0x83C3	
+0xC787	0x83C4	
+0xC788	0x83C6	
+0xC789	0x83C8	
+0xC78A	0x83C9	
+0xC78B	0x83CB	
+0xC78C	0x83CD	
+0xC78D	0x83CE	
+0xC78E	0x83D0	
+0xC78F	0x83D1	
+0xC790	0x83D2	
+0xC791	0x83D3	
+0xC792	0x83D5	
+0xC793	0x83D7	
+0xC794	0x83D9	
+0xC795	0x83DA	
+0xC796	0x83DB	
+0xC797	0x83DE	
+0xC798	0x83E2	
+0xC799	0x83E3	
+0xC79A	0x83E4	
+0xC79B	0x83E6	
+0xC79C	0x83E7	
+0xC79D	0x83E8	
+0xC79E	0x83EB	
+0xC79F	0x83EC	
+0xC7A0	0x83ED	
+0xC7A1	0x6070	
+0xC7A2	0x6D3D	
+0xC7A3	0x7275	
+0xC7A4	0x6266	
+0xC7A5	0x948E	
+0xC7A6	0x94C5	
+0xC7A7	0x5343	
+0xC7A8	0x8FC1	
+0xC7A9	0x7B7E	
+0xC7AA	0x4EDF	
+0xC7AB	0x8C26	
+0xC7AC	0x4E7E	
+0xC7AD	0x9ED4	
+0xC7AE	0x94B1	
+0xC7AF	0x94B3	
+0xC7B0	0x524D	
+0xC7B1	0x6F5C	
+0xC7B2	0x9063	
+0xC7B3	0x6D45	
+0xC7B4	0x8C34	
+0xC7B5	0x5811	
+0xC7B6	0x5D4C	
+0xC7B7	0x6B20	
+0xC7B8	0x6B49	
+0xC7B9	0x67AA	
+0xC7BA	0x545B	
+0xC7BB	0x8154	
+0xC7BC	0x7F8C	
+0xC7BD	0x5899	
+0xC7BE	0x8537	
+0xC7BF	0x5F3A	
+0xC7C0	0x62A2	
+0xC7C1	0x6A47	
+0xC7C2	0x9539	
+0xC7C3	0x6572	
+0xC7C4	0x6084	
+0xC7C5	0x6865	
+0xC7C6	0x77A7	
+0xC7C7	0x4E54	
+0xC7C8	0x4FA8	
+0xC7C9	0x5DE7	
+0xC7CA	0x9798	
+0xC7CB	0x64AC	
+0xC7CC	0x7FD8	
+0xC7CD	0x5CED	
+0xC7CE	0x4FCF	
+0xC7CF	0x7A8D	
+0xC7D0	0x5207	
+0xC7D1	0x8304	
+0xC7D2	0x4E14	
+0xC7D3	0x602F	
+0xC7D4	0x7A83	
+0xC7D5	0x94A6	
+0xC7D6	0x4FB5	
+0xC7D7	0x4EB2	
+0xC7D8	0x79E6	
+0xC7D9	0x7434	
+0xC7DA	0x52E4	
+0xC7DB	0x82B9	
+0xC7DC	0x64D2	
+0xC7DD	0x79BD	
+0xC7DE	0x5BDD	
+0xC7DF	0x6C81	
+0xC7E0	0x9752	
+0xC7E1	0x8F7B	
+0xC7E2	0x6C22	
+0xC7E3	0x503E	
+0xC7E4	0x537F	
+0xC7E5	0x6E05	
+0xC7E6	0x64CE	
+0xC7E7	0x6674	
+0xC7E8	0x6C30	
+0xC7E9	0x60C5	
+0xC7EA	0x9877	
+0xC7EB	0x8BF7	
+0xC7EC	0x5E86	
+0xC7ED	0x743C	
+0xC7EE	0x7A77	
+0xC7EF	0x79CB	
+0xC7F0	0x4E18	
+0xC7F1	0x90B1	
+0xC7F2	0x7403	
+0xC7F3	0x6C42	
+0xC7F4	0x56DA	
+0xC7F5	0x914B	
+0xC7F6	0x6CC5	
+0xC7F7	0x8D8B	
+0xC7F8	0x533A	
+0xC7F9	0x86C6	
+0xC7FA	0x66F2	
+0xC7FB	0x8EAF	
+0xC7FC	0x5C48	
+0xC7FD	0x9A71	
+0xC7FE	0x6E20	
+0xC840	0x83EE	
+0xC841	0x83EF	
+0xC842	0x83F3	
+0xC843	0x83F4	
+0xC844	0x83F5	
+0xC845	0x83F6	
+0xC846	0x83F7	
+0xC847	0x83FA	
+0xC848	0x83FB	
+0xC849	0x83FC	
+0xC84A	0x83FE	
+0xC84B	0x83FF	
+0xC84C	0x8400	
+0xC84D	0x8402	
+0xC84E	0x8405	
+0xC84F	0x8407	
+0xC850	0x8408	
+0xC851	0x8409	
+0xC852	0x840A	
+0xC853	0x8410	
+0xC854	0x8412	
+0xC855	0x8413	
+0xC856	0x8414	
+0xC857	0x8415	
+0xC858	0x8416	
+0xC859	0x8417	
+0xC85A	0x8419	
+0xC85B	0x841A	
+0xC85C	0x841B	
+0xC85D	0x841E	
+0xC85E	0x841F	
+0xC85F	0x8420	
+0xC860	0x8421	
+0xC861	0x8422	
+0xC862	0x8423	
+0xC863	0x8429	
+0xC864	0x842A	
+0xC865	0x842B	
+0xC866	0x842C	
+0xC867	0x842D	
+0xC868	0x842E	
+0xC869	0x842F	
+0xC86A	0x8430	
+0xC86B	0x8432	
+0xC86C	0x8433	
+0xC86D	0x8434	
+0xC86E	0x8435	
+0xC86F	0x8436	
+0xC870	0x8437	
+0xC871	0x8439	
+0xC872	0x843A	
+0xC873	0x843B	
+0xC874	0x843E	
+0xC875	0x843F	
+0xC876	0x8440	
+0xC877	0x8441	
+0xC878	0x8442	
+0xC879	0x8443	
+0xC87A	0x8444	
+0xC87B	0x8445	
+0xC87C	0x8447	
+0xC87D	0x8448	
+0xC87E	0x8449	
+0xC880	0x844A	
+0xC881	0x844B	
+0xC882	0x844C	
+0xC883	0x844D	
+0xC884	0x844E	
+0xC885	0x844F	
+0xC886	0x8450	
+0xC887	0x8452	
+0xC888	0x8453	
+0xC889	0x8454	
+0xC88A	0x8455	
+0xC88B	0x8456	
+0xC88C	0x8458	
+0xC88D	0x845D	
+0xC88E	0x845E	
+0xC88F	0x845F	
+0xC890	0x8460	
+0xC891	0x8462	
+0xC892	0x8464	
+0xC893	0x8465	
+0xC894	0x8466	
+0xC895	0x8467	
+0xC896	0x8468	
+0xC897	0x846A	
+0xC898	0x846E	
+0xC899	0x846F	
+0xC89A	0x8470	
+0xC89B	0x8472	
+0xC89C	0x8474	
+0xC89D	0x8477	
+0xC89E	0x8479	
+0xC89F	0x847B	
+0xC8A0	0x847C	
+0xC8A1	0x53D6	
+0xC8A2	0x5A36	
+0xC8A3	0x9F8B	
+0xC8A4	0x8DA3	
+0xC8A5	0x53BB	
+0xC8A6	0x5708	
+0xC8A7	0x98A7	
+0xC8A8	0x6743	
+0xC8A9	0x919B	
+0xC8AA	0x6CC9	
+0xC8AB	0x5168	
+0xC8AC	0x75CA	
+0xC8AD	0x62F3	
+0xC8AE	0x72AC	
+0xC8AF	0x5238	
+0xC8B0	0x529D	
+0xC8B1	0x7F3A	
+0xC8B2	0x7094	
+0xC8B3	0x7638	
+0xC8B4	0x5374	
+0xC8B5	0x9E4A	
+0xC8B6	0x69B7	
+0xC8B7	0x786E	
+0xC8B8	0x96C0	
+0xC8B9	0x88D9	
+0xC8BA	0x7FA4	
+0xC8BB	0x7136	
+0xC8BC	0x71C3	
+0xC8BD	0x5189	
+0xC8BE	0x67D3	
+0xC8BF	0x74E4	
+0xC8C0	0x58E4	
+0xC8C1	0x6518	
+0xC8C2	0x56B7	
+0xC8C3	0x8BA9	
+0xC8C4	0x9976	
+0xC8C5	0x6270	
+0xC8C6	0x7ED5	
+0xC8C7	0x60F9	
+0xC8C8	0x70ED	
+0xC8C9	0x58EC	
+0xC8CA	0x4EC1	
+0xC8CB	0x4EBA	
+0xC8CC	0x5FCD	
+0xC8CD	0x97E7	
+0xC8CE	0x4EFB	
+0xC8CF	0x8BA4	
+0xC8D0	0x5203	
+0xC8D1	0x598A	
+0xC8D2	0x7EAB	
+0xC8D3	0x6254	
+0xC8D4	0x4ECD	
+0xC8D5	0x65E5	
+0xC8D6	0x620E	
+0xC8D7	0x8338	
+0xC8D8	0x84C9	
+0xC8D9	0x8363	
+0xC8DA	0x878D	
+0xC8DB	0x7194	
+0xC8DC	0x6EB6	
+0xC8DD	0x5BB9	
+0xC8DE	0x7ED2	
+0xC8DF	0x5197	
+0xC8E0	0x63C9	
+0xC8E1	0x67D4	
+0xC8E2	0x8089	
+0xC8E3	0x8339	
+0xC8E4	0x8815	
+0xC8E5	0x5112	
+0xC8E6	0x5B7A	
+0xC8E7	0x5982	
+0xC8E8	0x8FB1	
+0xC8E9	0x4E73	
+0xC8EA	0x6C5D	
+0xC8EB	0x5165	
+0xC8EC	0x8925	
+0xC8ED	0x8F6F	
+0xC8EE	0x962E	
+0xC8EF	0x854A	
+0xC8F0	0x745E	
+0xC8F1	0x9510	
+0xC8F2	0x95F0	
+0xC8F3	0x6DA6	
+0xC8F4	0x82E5	
+0xC8F5	0x5F31	
+0xC8F6	0x6492	
+0xC8F7	0x6D12	
+0xC8F8	0x8428	
+0xC8F9	0x816E	
+0xC8FA	0x9CC3	
+0xC8FB	0x585E	
+0xC8FC	0x8D5B	
+0xC8FD	0x4E09	
+0xC8FE	0x53C1	
+0xC940	0x847D	
+0xC941	0x847E	
+0xC942	0x847F	
+0xC943	0x8480	
+0xC944	0x8481	
+0xC945	0x8483	
+0xC946	0x8484	
+0xC947	0x8485	
+0xC948	0x8486	
+0xC949	0x848A	
+0xC94A	0x848D	
+0xC94B	0x848F	
+0xC94C	0x8490	
+0xC94D	0x8491	
+0xC94E	0x8492	
+0xC94F	0x8493	
+0xC950	0x8494	
+0xC951	0x8495	
+0xC952	0x8496	
+0xC953	0x8498	
+0xC954	0x849A	
+0xC955	0x849B	
+0xC956	0x849D	
+0xC957	0x849E	
+0xC958	0x849F	
+0xC959	0x84A0	
+0xC95A	0x84A2	
+0xC95B	0x84A3	
+0xC95C	0x84A4	
+0xC95D	0x84A5	
+0xC95E	0x84A6	
+0xC95F	0x84A7	
+0xC960	0x84A8	
+0xC961	0x84A9	
+0xC962	0x84AA	
+0xC963	0x84AB	
+0xC964	0x84AC	
+0xC965	0x84AD	
+0xC966	0x84AE	
+0xC967	0x84B0	
+0xC968	0x84B1	
+0xC969	0x84B3	
+0xC96A	0x84B5	
+0xC96B	0x84B6	
+0xC96C	0x84B7	
+0xC96D	0x84BB	
+0xC96E	0x84BC	
+0xC96F	0x84BE	
+0xC970	0x84C0	
+0xC971	0x84C2	
+0xC972	0x84C3	
+0xC973	0x84C5	
+0xC974	0x84C6	
+0xC975	0x84C7	
+0xC976	0x84C8	
+0xC977	0x84CB	
+0xC978	0x84CC	
+0xC979	0x84CE	
+0xC97A	0x84CF	
+0xC97B	0x84D2	
+0xC97C	0x84D4	
+0xC97D	0x84D5	
+0xC97E	0x84D7	
+0xC980	0x84D8	
+0xC981	0x84D9	
+0xC982	0x84DA	
+0xC983	0x84DB	
+0xC984	0x84DC	
+0xC985	0x84DE	
+0xC986	0x84E1	
+0xC987	0x84E2	
+0xC988	0x84E4	
+0xC989	0x84E7	
+0xC98A	0x84E8	
+0xC98B	0x84E9	
+0xC98C	0x84EA	
+0xC98D	0x84EB	
+0xC98E	0x84ED	
+0xC98F	0x84EE	
+0xC990	0x84EF	
+0xC991	0x84F1	
+0xC992	0x84F2	
+0xC993	0x84F3	
+0xC994	0x84F4	
+0xC995	0x84F5	
+0xC996	0x84F6	
+0xC997	0x84F7	
+0xC998	0x84F8	
+0xC999	0x84F9	
+0xC99A	0x84FA	
+0xC99B	0x84FB	
+0xC99C	0x84FD	
+0xC99D	0x84FE	
+0xC99E	0x8500	
+0xC99F	0x8501	
+0xC9A0	0x8502	
+0xC9A1	0x4F1E	
+0xC9A2	0x6563	
+0xC9A3	0x6851	
+0xC9A4	0x55D3	
+0xC9A5	0x4E27	
+0xC9A6	0x6414	
+0xC9A7	0x9A9A	
+0xC9A8	0x626B	
+0xC9A9	0x5AC2	
+0xC9AA	0x745F	
+0xC9AB	0x8272	
+0xC9AC	0x6DA9	
+0xC9AD	0x68EE	
+0xC9AE	0x50E7	
+0xC9AF	0x838E	
+0xC9B0	0x7802	
+0xC9B1	0x6740	
+0xC9B2	0x5239	
+0xC9B3	0x6C99	
+0xC9B4	0x7EB1	
+0xC9B5	0x50BB	
+0xC9B6	0x5565	
+0xC9B7	0x715E	
+0xC9B8	0x7B5B	
+0xC9B9	0x6652	
+0xC9BA	0x73CA	
+0xC9BB	0x82EB	
+0xC9BC	0x6749	
+0xC9BD	0x5C71	
+0xC9BE	0x5220	
+0xC9BF	0x717D	
+0xC9C0	0x886B	
+0xC9C1	0x95EA	
+0xC9C2	0x9655	
+0xC9C3	0x64C5	
+0xC9C4	0x8D61	
+0xC9C5	0x81B3	
+0xC9C6	0x5584	
+0xC9C7	0x6C55	
+0xC9C8	0x6247	
+0xC9C9	0x7F2E	
+0xC9CA	0x5892	
+0xC9CB	0x4F24	
+0xC9CC	0x5546	
+0xC9CD	0x8D4F	
+0xC9CE	0x664C	
+0xC9CF	0x4E0A	
+0xC9D0	0x5C1A	
+0xC9D1	0x88F3	
+0xC9D2	0x68A2	
+0xC9D3	0x634E	
+0xC9D4	0x7A0D	
+0xC9D5	0x70E7	
+0xC9D6	0x828D	
+0xC9D7	0x52FA	
+0xC9D8	0x97F6	
+0xC9D9	0x5C11	
+0xC9DA	0x54E8	
+0xC9DB	0x90B5	
+0xC9DC	0x7ECD	
+0xC9DD	0x5962	
+0xC9DE	0x8D4A	
+0xC9DF	0x86C7	
+0xC9E0	0x820C	
+0xC9E1	0x820D	
+0xC9E2	0x8D66	
+0xC9E3	0x6444	
+0xC9E4	0x5C04	
+0xC9E5	0x6151	
+0xC9E6	0x6D89	
+0xC9E7	0x793E	
+0xC9E8	0x8BBE	
+0xC9E9	0x7837	
+0xC9EA	0x7533	
+0xC9EB	0x547B	
+0xC9EC	0x4F38	
+0xC9ED	0x8EAB	
+0xC9EE	0x6DF1	
+0xC9EF	0x5A20	
+0xC9F0	0x7EC5	
+0xC9F1	0x795E	
+0xC9F2	0x6C88	
+0xC9F3	0x5BA1	
+0xC9F4	0x5A76	
+0xC9F5	0x751A	
+0xC9F6	0x80BE	
+0xC9F7	0x614E	
+0xC9F8	0x6E17	
+0xC9F9	0x58F0	
+0xC9FA	0x751F	
+0xC9FB	0x7525	
+0xC9FC	0x7272	
+0xC9FD	0x5347	
+0xC9FE	0x7EF3	
+0xCA40	0x8503	
+0xCA41	0x8504	
+0xCA42	0x8505	
+0xCA43	0x8506	
+0xCA44	0x8507	
+0xCA45	0x8508	
+0xCA46	0x8509	
+0xCA47	0x850A	
+0xCA48	0x850B	
+0xCA49	0x850D	
+0xCA4A	0x850E	
+0xCA4B	0x850F	
+0xCA4C	0x8510	
+0xCA4D	0x8512	
+0xCA4E	0x8514	
+0xCA4F	0x8515	
+0xCA50	0x8516	
+0xCA51	0x8518	
+0xCA52	0x8519	
+0xCA53	0x851B	
+0xCA54	0x851C	
+0xCA55	0x851D	
+0xCA56	0x851E	
+0xCA57	0x8520	
+0xCA58	0x8522	
+0xCA59	0x8523	
+0xCA5A	0x8524	
+0xCA5B	0x8525	
+0xCA5C	0x8526	
+0xCA5D	0x8527	
+0xCA5E	0x8528	
+0xCA5F	0x8529	
+0xCA60	0x852A	
+0xCA61	0x852D	
+0xCA62	0x852E	
+0xCA63	0x852F	
+0xCA64	0x8530	
+0xCA65	0x8531	
+0xCA66	0x8532	
+0xCA67	0x8533	
+0xCA68	0x8534	
+0xCA69	0x8535	
+0xCA6A	0x8536	
+0xCA6B	0x853E	
+0xCA6C	0x853F	
+0xCA6D	0x8540	
+0xCA6E	0x8541	
+0xCA6F	0x8542	
+0xCA70	0x8544	
+0xCA71	0x8545	
+0xCA72	0x8546	
+0xCA73	0x8547	
+0xCA74	0x854B	
+0xCA75	0x854C	
+0xCA76	0x854D	
+0xCA77	0x854E	
+0xCA78	0x854F	
+0xCA79	0x8550	
+0xCA7A	0x8551	
+0xCA7B	0x8552	
+0xCA7C	0x8553	
+0xCA7D	0x8554	
+0xCA7E	0x8555	
+0xCA80	0x8557	
+0xCA81	0x8558	
+0xCA82	0x855A	
+0xCA83	0x855B	
+0xCA84	0x855C	
+0xCA85	0x855D	
+0xCA86	0x855F	
+0xCA87	0x8560	
+0xCA88	0x8561	
+0xCA89	0x8562	
+0xCA8A	0x8563	
+0xCA8B	0x8565	
+0xCA8C	0x8566	
+0xCA8D	0x8567	
+0xCA8E	0x8569	
+0xCA8F	0x856A	
+0xCA90	0x856B	
+0xCA91	0x856C	
+0xCA92	0x856D	
+0xCA93	0x856E	
+0xCA94	0x856F	
+0xCA95	0x8570	
+0xCA96	0x8571	
+0xCA97	0x8573	
+0xCA98	0x8575	
+0xCA99	0x8576	
+0xCA9A	0x8577	
+0xCA9B	0x8578	
+0xCA9C	0x857C	
+0xCA9D	0x857D	
+0xCA9E	0x857F	
+0xCA9F	0x8580	
+0xCAA0	0x8581	
+0xCAA1	0x7701	
+0xCAA2	0x76DB	
+0xCAA3	0x5269	
+0xCAA4	0x80DC	
+0xCAA5	0x5723	
+0xCAA6	0x5E08	
+0xCAA7	0x5931	
+0xCAA8	0x72EE	
+0xCAA9	0x65BD	
+0xCAAA	0x6E7F	
+0xCAAB	0x8BD7	
+0xCAAC	0x5C38	
+0xCAAD	0x8671	
+0xCAAE	0x5341	
+0xCAAF	0x77F3	
+0xCAB0	0x62FE	
+0xCAB1	0x65F6	
+0xCAB2	0x4EC0	
+0xCAB3	0x98DF	
+0xCAB4	0x8680	
+0xCAB5	0x5B9E	
+0xCAB6	0x8BC6	
+0xCAB7	0x53F2	
+0xCAB8	0x77E2	
+0xCAB9	0x4F7F	
+0xCABA	0x5C4E	
+0xCABB	0x9A76	
+0xCABC	0x59CB	
+0xCABD	0x5F0F	
+0xCABE	0x793A	
+0xCABF	0x58EB	
+0xCAC0	0x4E16	
+0xCAC1	0x67FF	
+0xCAC2	0x4E8B	
+0xCAC3	0x62ED	
+0xCAC4	0x8A93	
+0xCAC5	0x901D	
+0xCAC6	0x52BF	
+0xCAC7	0x662F	
+0xCAC8	0x55DC	
+0xCAC9	0x566C	
+0xCACA	0x9002	
+0xCACB	0x4ED5	
+0xCACC	0x4F8D	
+0xCACD	0x91CA	
+0xCACE	0x9970	
+0xCACF	0x6C0F	
+0xCAD0	0x5E02	
+0xCAD1	0x6043	
+0xCAD2	0x5BA4	
+0xCAD3	0x89C6	
+0xCAD4	0x8BD5	
+0xCAD5	0x6536	
+0xCAD6	0x624B	
+0xCAD7	0x9996	
+0xCAD8	0x5B88	
+0xCAD9	0x5BFF	
+0xCADA	0x6388	
+0xCADB	0x552E	
+0xCADC	0x53D7	
+0xCADD	0x7626	
+0xCADE	0x517D	
+0xCADF	0x852C	
+0xCAE0	0x67A2	
+0xCAE1	0x68B3	
+0xCAE2	0x6B8A	
+0xCAE3	0x6292	
+0xCAE4	0x8F93	
+0xCAE5	0x53D4	
+0xCAE6	0x8212	
+0xCAE7	0x6DD1	
+0xCAE8	0x758F	
+0xCAE9	0x4E66	
+0xCAEA	0x8D4E	
+0xCAEB	0x5B70	
+0xCAEC	0x719F	
+0xCAED	0x85AF	
+0xCAEE	0x6691	
+0xCAEF	0x66D9	
+0xCAF0	0x7F72	
+0xCAF1	0x8700	
+0xCAF2	0x9ECD	
+0xCAF3	0x9F20	
+0xCAF4	0x5C5E	
+0xCAF5	0x672F	
+0xCAF6	0x8FF0	
+0xCAF7	0x6811	
+0xCAF8	0x675F	
+0xCAF9	0x620D	
+0xCAFA	0x7AD6	
+0xCAFB	0x5885	
+0xCAFC	0x5EB6	
+0xCAFD	0x6570	
+0xCAFE	0x6F31	
+0xCB40	0x8582	
+0xCB41	0x8583	
+0xCB42	0x8586	
+0xCB43	0x8588	
+0xCB44	0x8589	
+0xCB45	0x858A	
+0xCB46	0x858B	
+0xCB47	0x858C	
+0xCB48	0x858D	
+0xCB49	0x858E	
+0xCB4A	0x8590	
+0xCB4B	0x8591	
+0xCB4C	0x8592	
+0xCB4D	0x8593	
+0xCB4E	0x8594	
+0xCB4F	0x8595	
+0xCB50	0x8596	
+0xCB51	0x8597	
+0xCB52	0x8598	
+0xCB53	0x8599	
+0xCB54	0x859A	
+0xCB55	0x859D	
+0xCB56	0x859E	
+0xCB57	0x859F	
+0xCB58	0x85A0	
+0xCB59	0x85A1	
+0xCB5A	0x85A2	
+0xCB5B	0x85A3	
+0xCB5C	0x85A5	
+0xCB5D	0x85A6	
+0xCB5E	0x85A7	
+0xCB5F	0x85A9	
+0xCB60	0x85AB	
+0xCB61	0x85AC	
+0xCB62	0x85AD	
+0xCB63	0x85B1	
+0xCB64	0x85B2	
+0xCB65	0x85B3	
+0xCB66	0x85B4	
+0xCB67	0x85B5	
+0xCB68	0x85B6	
+0xCB69	0x85B8	
+0xCB6A	0x85BA	
+0xCB6B	0x85BB	
+0xCB6C	0x85BC	
+0xCB6D	0x85BD	
+0xCB6E	0x85BE	
+0xCB6F	0x85BF	
+0xCB70	0x85C0	
+0xCB71	0x85C2	
+0xCB72	0x85C3	
+0xCB73	0x85C4	
+0xCB74	0x85C5	
+0xCB75	0x85C6	
+0xCB76	0x85C7	
+0xCB77	0x85C8	
+0xCB78	0x85CA	
+0xCB79	0x85CB	
+0xCB7A	0x85CC	
+0xCB7B	0x85CD	
+0xCB7C	0x85CE	
+0xCB7D	0x85D1	
+0xCB7E	0x85D2	
+0xCB80	0x85D4	
+0xCB81	0x85D6	
+0xCB82	0x85D7	
+0xCB83	0x85D8	
+0xCB84	0x85D9	
+0xCB85	0x85DA	
+0xCB86	0x85DB	
+0xCB87	0x85DD	
+0xCB88	0x85DE	
+0xCB89	0x85DF	
+0xCB8A	0x85E0	
+0xCB8B	0x85E1	
+0xCB8C	0x85E2	
+0xCB8D	0x85E3	
+0xCB8E	0x85E5	
+0xCB8F	0x85E6	
+0xCB90	0x85E7	
+0xCB91	0x85E8	
+0xCB92	0x85EA	
+0xCB93	0x85EB	
+0xCB94	0x85EC	
+0xCB95	0x85ED	
+0xCB96	0x85EE	
+0xCB97	0x85EF	
+0xCB98	0x85F0	
+0xCB99	0x85F1	
+0xCB9A	0x85F2	
+0xCB9B	0x85F3	
+0xCB9C	0x85F4	
+0xCB9D	0x85F5	
+0xCB9E	0x85F6	
+0xCB9F	0x85F7	
+0xCBA0	0x85F8	
+0xCBA1	0x6055	
+0xCBA2	0x5237	
+0xCBA3	0x800D	
+0xCBA4	0x6454	
+0xCBA5	0x8870	
+0xCBA6	0x7529	
+0xCBA7	0x5E05	
+0xCBA8	0x6813	
+0xCBA9	0x62F4	
+0xCBAA	0x971C	
+0xCBAB	0x53CC	
+0xCBAC	0x723D	
+0xCBAD	0x8C01	
+0xCBAE	0x6C34	
+0xCBAF	0x7761	
+0xCBB0	0x7A0E	
+0xCBB1	0x542E	
+0xCBB2	0x77AC	
+0xCBB3	0x987A	
+0xCBB4	0x821C	
+0xCBB5	0x8BF4	
+0xCBB6	0x7855	
+0xCBB7	0x6714	
+0xCBB8	0x70C1	
+0xCBB9	0x65AF	
+0xCBBA	0x6495	
+0xCBBB	0x5636	
+0xCBBC	0x601D	
+0xCBBD	0x79C1	
+0xCBBE	0x53F8	
+0xCBBF	0x4E1D	
+0xCBC0	0x6B7B	
+0xCBC1	0x8086	
+0xCBC2	0x5BFA	
+0xCBC3	0x55E3	
+0xCBC4	0x56DB	
+0xCBC5	0x4F3A	
+0xCBC6	0x4F3C	
+0xCBC7	0x9972	
+0xCBC8	0x5DF3	
+0xCBC9	0x677E	
+0xCBCA	0x8038	
+0xCBCB	0x6002	
+0xCBCC	0x9882	
+0xCBCD	0x9001	
+0xCBCE	0x5B8B	
+0xCBCF	0x8BBC	
+0xCBD0	0x8BF5	
+0xCBD1	0x641C	
+0xCBD2	0x8258	
+0xCBD3	0x64DE	
+0xCBD4	0x55FD	
+0xCBD5	0x82CF	
+0xCBD6	0x9165	
+0xCBD7	0x4FD7	
+0xCBD8	0x7D20	
+0xCBD9	0x901F	
+0xCBDA	0x7C9F	
+0xCBDB	0x50F3	
+0xCBDC	0x5851	
+0xCBDD	0x6EAF	
+0xCBDE	0x5BBF	
+0xCBDF	0x8BC9	
+0xCBE0	0x8083	
+0xCBE1	0x9178	
+0xCBE2	0x849C	
+0xCBE3	0x7B97	
+0xCBE4	0x867D	
+0xCBE5	0x968B	
+0xCBE6	0x968F	
+0xCBE7	0x7EE5	
+0xCBE8	0x9AD3	
+0xCBE9	0x788E	
+0xCBEA	0x5C81	
+0xCBEB	0x7A57	
+0xCBEC	0x9042	
+0xCBED	0x96A7	
+0xCBEE	0x795F	
+0xCBEF	0x5B59	
+0xCBF0	0x635F	
+0xCBF1	0x7B0B	
+0xCBF2	0x84D1	
+0xCBF3	0x68AD	
+0xCBF4	0x5506	
+0xCBF5	0x7F29	
+0xCBF6	0x7410	
+0xCBF7	0x7D22	
+0xCBF8	0x9501	
+0xCBF9	0x6240	
+0xCBFA	0x584C	
+0xCBFB	0x4ED6	
+0xCBFC	0x5B83	
+0xCBFD	0x5979	
+0xCBFE	0x5854	
+0xCC40	0x85F9	
+0xCC41	0x85FA	
+0xCC42	0x85FC	
+0xCC43	0x85FD	
+0xCC44	0x85FE	
+0xCC45	0x8600	
+0xCC46	0x8601	
+0xCC47	0x8602	
+0xCC48	0x8603	
+0xCC49	0x8604	
+0xCC4A	0x8606	
+0xCC4B	0x8607	
+0xCC4C	0x8608	
+0xCC4D	0x8609	
+0xCC4E	0x860A	
+0xCC4F	0x860B	
+0xCC50	0x860C	
+0xCC51	0x860D	
+0xCC52	0x860E	
+0xCC53	0x860F	
+0xCC54	0x8610	
+0xCC55	0x8612	
+0xCC56	0x8613	
+0xCC57	0x8614	
+0xCC58	0x8615	
+0xCC59	0x8617	
+0xCC5A	0x8618	
+0xCC5B	0x8619	
+0xCC5C	0x861A	
+0xCC5D	0x861B	
+0xCC5E	0x861C	
+0xCC5F	0x861D	
+0xCC60	0x861E	
+0xCC61	0x861F	
+0xCC62	0x8620	
+0xCC63	0x8621	
+0xCC64	0x8622	
+0xCC65	0x8623	
+0xCC66	0x8624	
+0xCC67	0x8625	
+0xCC68	0x8626	
+0xCC69	0x8628	
+0xCC6A	0x862A	
+0xCC6B	0x862B	
+0xCC6C	0x862C	
+0xCC6D	0x862D	
+0xCC6E	0x862E	
+0xCC6F	0x862F	
+0xCC70	0x8630	
+0xCC71	0x8631	
+0xCC72	0x8632	
+0xCC73	0x8633	
+0xCC74	0x8634	
+0xCC75	0x8635	
+0xCC76	0x8636	
+0xCC77	0x8637	
+0xCC78	0x8639	
+0xCC79	0x863A	
+0xCC7A	0x863B	
+0xCC7B	0x863D	
+0xCC7C	0x863E	
+0xCC7D	0x863F	
+0xCC7E	0x8640	
+0xCC80	0x8641	
+0xCC81	0x8642	
+0xCC82	0x8643	
+0xCC83	0x8644	
+0xCC84	0x8645	
+0xCC85	0x8646	
+0xCC86	0x8647	
+0xCC87	0x8648	
+0xCC88	0x8649	
+0xCC89	0x864A	
+0xCC8A	0x864B	
+0xCC8B	0x864C	
+0xCC8C	0x8652	
+0xCC8D	0x8653	
+0xCC8E	0x8655	
+0xCC8F	0x8656	
+0xCC90	0x8657	
+0xCC91	0x8658	
+0xCC92	0x8659	
+0xCC93	0x865B	
+0xCC94	0x865C	
+0xCC95	0x865D	
+0xCC96	0x865F	
+0xCC97	0x8660	
+0xCC98	0x8661	
+0xCC99	0x8663	
+0xCC9A	0x8664	
+0xCC9B	0x8665	
+0xCC9C	0x8666	
+0xCC9D	0x8667	
+0xCC9E	0x8668	
+0xCC9F	0x8669	
+0xCCA0	0x866A	
+0xCCA1	0x736D	
+0xCCA2	0x631E	
+0xCCA3	0x8E4B	
+0xCCA4	0x8E0F	
+0xCCA5	0x80CE	
+0xCCA6	0x82D4	
+0xCCA7	0x62AC	
+0xCCA8	0x53F0	
+0xCCA9	0x6CF0	
+0xCCAA	0x915E	
+0xCCAB	0x592A	
+0xCCAC	0x6001	
+0xCCAD	0x6C70	
+0xCCAE	0x574D	
+0xCCAF	0x644A	
+0xCCB0	0x8D2A	
+0xCCB1	0x762B	
+0xCCB2	0x6EE9	
+0xCCB3	0x575B	
+0xCCB4	0x6A80	
+0xCCB5	0x75F0	
+0xCCB6	0x6F6D	
+0xCCB7	0x8C2D	
+0xCCB8	0x8C08	
+0xCCB9	0x5766	
+0xCCBA	0x6BEF	
+0xCCBB	0x8892	
+0xCCBC	0x78B3	
+0xCCBD	0x63A2	
+0xCCBE	0x53F9	
+0xCCBF	0x70AD	
+0xCCC0	0x6C64	
+0xCCC1	0x5858	
+0xCCC2	0x642A	
+0xCCC3	0x5802	
+0xCCC4	0x68E0	
+0xCCC5	0x819B	
+0xCCC6	0x5510	
+0xCCC7	0x7CD6	
+0xCCC8	0x5018	
+0xCCC9	0x8EBA	
+0xCCCA	0x6DCC	
+0xCCCB	0x8D9F	
+0xCCCC	0x70EB	
+0xCCCD	0x638F	
+0xCCCE	0x6D9B	
+0xCCCF	0x6ED4	
+0xCCD0	0x7EE6	
+0xCCD1	0x8404	
+0xCCD2	0x6843	
+0xCCD3	0x9003	
+0xCCD4	0x6DD8	
+0xCCD5	0x9676	
+0xCCD6	0x8BA8	
+0xCCD7	0x5957	
+0xCCD8	0x7279	
+0xCCD9	0x85E4	
+0xCCDA	0x817E	
+0xCCDB	0x75BC	
+0xCCDC	0x8A8A	
+0xCCDD	0x68AF	
+0xCCDE	0x5254	
+0xCCDF	0x8E22	
+0xCCE0	0x9511	
+0xCCE1	0x63D0	
+0xCCE2	0x9898	
+0xCCE3	0x8E44	
+0xCCE4	0x557C	
+0xCCE5	0x4F53	
+0xCCE6	0x66FF	
+0xCCE7	0x568F	
+0xCCE8	0x60D5	
+0xCCE9	0x6D95	
+0xCCEA	0x5243	
+0xCCEB	0x5C49	
+0xCCEC	0x5929	
+0xCCED	0x6DFB	
+0xCCEE	0x586B	
+0xCCEF	0x7530	
+0xCCF0	0x751C	
+0xCCF1	0x606C	
+0xCCF2	0x8214	
+0xCCF3	0x8146	
+0xCCF4	0x6311	
+0xCCF5	0x6761	
+0xCCF6	0x8FE2	
+0xCCF7	0x773A	
+0xCCF8	0x8DF3	
+0xCCF9	0x8D34	
+0xCCFA	0x94C1	
+0xCCFB	0x5E16	
+0xCCFC	0x5385	
+0xCCFD	0x542C	
+0xCCFE	0x70C3	
+0xCD40	0x866D	
+0xCD41	0x866F	
+0xCD42	0x8670	
+0xCD43	0x8672	
+0xCD44	0x8673	
+0xCD45	0x8674	
+0xCD46	0x8675	
+0xCD47	0x8676	
+0xCD48	0x8677	
+0xCD49	0x8678	
+0xCD4A	0x8683	
+0xCD4B	0x8684	
+0xCD4C	0x8685	
+0xCD4D	0x8686	
+0xCD4E	0x8687	
+0xCD4F	0x8688	
+0xCD50	0x8689	
+0xCD51	0x868E	
+0xCD52	0x868F	
+0xCD53	0x8690	
+0xCD54	0x8691	
+0xCD55	0x8692	
+0xCD56	0x8694	
+0xCD57	0x8696	
+0xCD58	0x8697	
+0xCD59	0x8698	
+0xCD5A	0x8699	
+0xCD5B	0x869A	
+0xCD5C	0x869B	
+0xCD5D	0x869E	
+0xCD5E	0x869F	
+0xCD5F	0x86A0	
+0xCD60	0x86A1	
+0xCD61	0x86A2	
+0xCD62	0x86A5	
+0xCD63	0x86A6	
+0xCD64	0x86AB	
+0xCD65	0x86AD	
+0xCD66	0x86AE	
+0xCD67	0x86B2	
+0xCD68	0x86B3	
+0xCD69	0x86B7	
+0xCD6A	0x86B8	
+0xCD6B	0x86B9	
+0xCD6C	0x86BB	
+0xCD6D	0x86BC	
+0xCD6E	0x86BD	
+0xCD6F	0x86BE	
+0xCD70	0x86BF	
+0xCD71	0x86C1	
+0xCD72	0x86C2	
+0xCD73	0x86C3	
+0xCD74	0x86C5	
+0xCD75	0x86C8	
+0xCD76	0x86CC	
+0xCD77	0x86CD	
+0xCD78	0x86D2	
+0xCD79	0x86D3	
+0xCD7A	0x86D5	
+0xCD7B	0x86D6	
+0xCD7C	0x86D7	
+0xCD7D	0x86DA	
+0xCD7E	0x86DC	
+0xCD80	0x86DD	
+0xCD81	0x86E0	
+0xCD82	0x86E1	
+0xCD83	0x86E2	
+0xCD84	0x86E3	
+0xCD85	0x86E5	
+0xCD86	0x86E6	
+0xCD87	0x86E7	
+0xCD88	0x86E8	
+0xCD89	0x86EA	
+0xCD8A	0x86EB	
+0xCD8B	0x86EC	
+0xCD8C	0x86EF	
+0xCD8D	0x86F5	
+0xCD8E	0x86F6	
+0xCD8F	0x86F7	
+0xCD90	0x86FA	
+0xCD91	0x86FB	
+0xCD92	0x86FC	
+0xCD93	0x86FD	
+0xCD94	0x86FF	
+0xCD95	0x8701	
+0xCD96	0x8704	
+0xCD97	0x8705	
+0xCD98	0x8706	
+0xCD99	0x870B	
+0xCD9A	0x870C	
+0xCD9B	0x870E	
+0xCD9C	0x870F	
+0xCD9D	0x8710	
+0xCD9E	0x8711	
+0xCD9F	0x8714	
+0xCDA0	0x8716	
+0xCDA1	0x6C40	
+0xCDA2	0x5EF7	
+0xCDA3	0x505C	
+0xCDA4	0x4EAD	
+0xCDA5	0x5EAD	
+0xCDA6	0x633A	
+0xCDA7	0x8247	
+0xCDA8	0x901A	
+0xCDA9	0x6850	
+0xCDAA	0x916E	
+0xCDAB	0x77B3	
+0xCDAC	0x540C	
+0xCDAD	0x94DC	
+0xCDAE	0x5F64	
+0xCDAF	0x7AE5	
+0xCDB0	0x6876	
+0xCDB1	0x6345	
+0xCDB2	0x7B52	
+0xCDB3	0x7EDF	
+0xCDB4	0x75DB	
+0xCDB5	0x5077	
+0xCDB6	0x6295	
+0xCDB7	0x5934	
+0xCDB8	0x900F	
+0xCDB9	0x51F8	
+0xCDBA	0x79C3	
+0xCDBB	0x7A81	
+0xCDBC	0x56FE	
+0xCDBD	0x5F92	
+0xCDBE	0x9014	
+0xCDBF	0x6D82	
+0xCDC0	0x5C60	
+0xCDC1	0x571F	
+0xCDC2	0x5410	
+0xCDC3	0x5154	
+0xCDC4	0x6E4D	
+0xCDC5	0x56E2	
+0xCDC6	0x63A8	
+0xCDC7	0x9893	
+0xCDC8	0x817F	
+0xCDC9	0x8715	
+0xCDCA	0x892A	
+0xCDCB	0x9000	
+0xCDCC	0x541E	
+0xCDCD	0x5C6F	
+0xCDCE	0x81C0	
+0xCDCF	0x62D6	
+0xCDD0	0x6258	
+0xCDD1	0x8131	
+0xCDD2	0x9E35	
+0xCDD3	0x9640	
+0xCDD4	0x9A6E	
+0xCDD5	0x9A7C	
+0xCDD6	0x692D	
+0xCDD7	0x59A5	
+0xCDD8	0x62D3	
+0xCDD9	0x553E	
+0xCDDA	0x6316	
+0xCDDB	0x54C7	
+0xCDDC	0x86D9	
+0xCDDD	0x6D3C	
+0xCDDE	0x5A03	
+0xCDDF	0x74E6	
+0xCDE0	0x889C	
+0xCDE1	0x6B6A	
+0xCDE2	0x5916	
+0xCDE3	0x8C4C	
+0xCDE4	0x5F2F	
+0xCDE5	0x6E7E	
+0xCDE6	0x73A9	
+0xCDE7	0x987D	
+0xCDE8	0x4E38	
+0xCDE9	0x70F7	
+0xCDEA	0x5B8C	
+0xCDEB	0x7897	
+0xCDEC	0x633D	
+0xCDED	0x665A	
+0xCDEE	0x7696	
+0xCDEF	0x60CB	
+0xCDF0	0x5B9B	
+0xCDF1	0x5A49	
+0xCDF2	0x4E07	
+0xCDF3	0x8155	
+0xCDF4	0x6C6A	
+0xCDF5	0x738B	
+0xCDF6	0x4EA1	
+0xCDF7	0x6789	
+0xCDF8	0x7F51	
+0xCDF9	0x5F80	
+0xCDFA	0x65FA	
+0xCDFB	0x671B	
+0xCDFC	0x5FD8	
+0xCDFD	0x5984	
+0xCDFE	0x5A01	
+0xCE40	0x8719	
+0xCE41	0x871B	
+0xCE42	0x871D	
+0xCE43	0x871F	
+0xCE44	0x8720	
+0xCE45	0x8724	
+0xCE46	0x8726	
+0xCE47	0x8727	
+0xCE48	0x8728	
+0xCE49	0x872A	
+0xCE4A	0x872B	
+0xCE4B	0x872C	
+0xCE4C	0x872D	
+0xCE4D	0x872F	
+0xCE4E	0x8730	
+0xCE4F	0x8732	
+0xCE50	0x8733	
+0xCE51	0x8735	
+0xCE52	0x8736	
+0xCE53	0x8738	
+0xCE54	0x8739	
+0xCE55	0x873A	
+0xCE56	0x873C	
+0xCE57	0x873D	
+0xCE58	0x8740	
+0xCE59	0x8741	
+0xCE5A	0x8742	
+0xCE5B	0x8743	
+0xCE5C	0x8744	
+0xCE5D	0x8745	
+0xCE5E	0x8746	
+0xCE5F	0x874A	
+0xCE60	0x874B	
+0xCE61	0x874D	
+0xCE62	0x874F	
+0xCE63	0x8750	
+0xCE64	0x8751	
+0xCE65	0x8752	
+0xCE66	0x8754	
+0xCE67	0x8755	
+0xCE68	0x8756	
+0xCE69	0x8758	
+0xCE6A	0x875A	
+0xCE6B	0x875B	
+0xCE6C	0x875C	
+0xCE6D	0x875D	
+0xCE6E	0x875E	
+0xCE6F	0x875F	
+0xCE70	0x8761	
+0xCE71	0x8762	
+0xCE72	0x8766	
+0xCE73	0x8767	
+0xCE74	0x8768	
+0xCE75	0x8769	
+0xCE76	0x876A	
+0xCE77	0x876B	
+0xCE78	0x876C	
+0xCE79	0x876D	
+0xCE7A	0x876F	
+0xCE7B	0x8771	
+0xCE7C	0x8772	
+0xCE7D	0x8773	
+0xCE7E	0x8775	
+0xCE80	0x8777	
+0xCE81	0x8778	
+0xCE82	0x8779	
+0xCE83	0x877A	
+0xCE84	0x877F	
+0xCE85	0x8780	
+0xCE86	0x8781	
+0xCE87	0x8784	
+0xCE88	0x8786	
+0xCE89	0x8787	
+0xCE8A	0x8789	
+0xCE8B	0x878A	
+0xCE8C	0x878C	
+0xCE8D	0x878E	
+0xCE8E	0x878F	
+0xCE8F	0x8790	
+0xCE90	0x8791	
+0xCE91	0x8792	
+0xCE92	0x8794	
+0xCE93	0x8795	
+0xCE94	0x8796	
+0xCE95	0x8798	
+0xCE96	0x8799	
+0xCE97	0x879A	
+0xCE98	0x879B	
+0xCE99	0x879C	
+0xCE9A	0x879D	
+0xCE9B	0x879E	
+0xCE9C	0x87A0	
+0xCE9D	0x87A1	
+0xCE9E	0x87A2	
+0xCE9F	0x87A3	
+0xCEA0	0x87A4	
+0xCEA1	0x5DCD	
+0xCEA2	0x5FAE	
+0xCEA3	0x5371	
+0xCEA4	0x97E6	
+0xCEA5	0x8FDD	
+0xCEA6	0x6845	
+0xCEA7	0x56F4	
+0xCEA8	0x552F	
+0xCEA9	0x60DF	
+0xCEAA	0x4E3A	
+0xCEAB	0x6F4D	
+0xCEAC	0x7EF4	
+0xCEAD	0x82C7	
+0xCEAE	0x840E	
+0xCEAF	0x59D4	
+0xCEB0	0x4F1F	
+0xCEB1	0x4F2A	
+0xCEB2	0x5C3E	
+0xCEB3	0x7EAC	
+0xCEB4	0x672A	
+0xCEB5	0x851A	
+0xCEB6	0x5473	
+0xCEB7	0x754F	
+0xCEB8	0x80C3	
+0xCEB9	0x5582	
+0xCEBA	0x9B4F	
+0xCEBB	0x4F4D	
+0xCEBC	0x6E2D	
+0xCEBD	0x8C13	
+0xCEBE	0x5C09	
+0xCEBF	0x6170	
+0xCEC0	0x536B	
+0xCEC1	0x761F	
+0xCEC2	0x6E29	
+0xCEC3	0x868A	
+0xCEC4	0x6587	
+0xCEC5	0x95FB	
+0xCEC6	0x7EB9	
+0xCEC7	0x543B	
+0xCEC8	0x7A33	
+0xCEC9	0x7D0A	
+0xCECA	0x95EE	
+0xCECB	0x55E1	
+0xCECC	0x7FC1	
+0xCECD	0x74EE	
+0xCECE	0x631D	
+0xCECF	0x8717	
+0xCED0	0x6DA1	
+0xCED1	0x7A9D	
+0xCED2	0x6211	
+0xCED3	0x65A1	
+0xCED4	0x5367	
+0xCED5	0x63E1	
+0xCED6	0x6C83	
+0xCED7	0x5DEB	
+0xCED8	0x545C	
+0xCED9	0x94A8	
+0xCEDA	0x4E4C	
+0xCEDB	0x6C61	
+0xCEDC	0x8BEC	
+0xCEDD	0x5C4B	
+0xCEDE	0x65E0	
+0xCEDF	0x829C	
+0xCEE0	0x68A7	
+0xCEE1	0x543E	
+0xCEE2	0x5434	
+0xCEE3	0x6BCB	
+0xCEE4	0x6B66	
+0xCEE5	0x4E94	
+0xCEE6	0x6342	
+0xCEE7	0x5348	
+0xCEE8	0x821E	
+0xCEE9	0x4F0D	
+0xCEEA	0x4FAE	
+0xCEEB	0x575E	
+0xCEEC	0x620A	
+0xCEED	0x96FE	
+0xCEEE	0x6664	
+0xCEEF	0x7269	
+0xCEF0	0x52FF	
+0xCEF1	0x52A1	
+0xCEF2	0x609F	
+0xCEF3	0x8BEF	
+0xCEF4	0x6614	
+0xCEF5	0x7199	
+0xCEF6	0x6790	
+0xCEF7	0x897F	
+0xCEF8	0x7852	
+0xCEF9	0x77FD	
+0xCEFA	0x6670	
+0xCEFB	0x563B	
+0xCEFC	0x5438	
+0xCEFD	0x9521	
+0xCEFE	0x727A	
+0xCF40	0x87A5	
+0xCF41	0x87A6	
+0xCF42	0x87A7	
+0xCF43	0x87A9	
+0xCF44	0x87AA	
+0xCF45	0x87AE	
+0xCF46	0x87B0	
+0xCF47	0x87B1	
+0xCF48	0x87B2	
+0xCF49	0x87B4	
+0xCF4A	0x87B6	
+0xCF4B	0x87B7	
+0xCF4C	0x87B8	
+0xCF4D	0x87B9	
+0xCF4E	0x87BB	
+0xCF4F	0x87BC	
+0xCF50	0x87BE	
+0xCF51	0x87BF	
+0xCF52	0x87C1	
+0xCF53	0x87C2	
+0xCF54	0x87C3	
+0xCF55	0x87C4	
+0xCF56	0x87C5	
+0xCF57	0x87C7	
+0xCF58	0x87C8	
+0xCF59	0x87C9	
+0xCF5A	0x87CC	
+0xCF5B	0x87CD	
+0xCF5C	0x87CE	
+0xCF5D	0x87CF	
+0xCF5E	0x87D0	
+0xCF5F	0x87D4	
+0xCF60	0x87D5	
+0xCF61	0x87D6	
+0xCF62	0x87D7	
+0xCF63	0x87D8	
+0xCF64	0x87D9	
+0xCF65	0x87DA	
+0xCF66	0x87DC	
+0xCF67	0x87DD	
+0xCF68	0x87DE	
+0xCF69	0x87DF	
+0xCF6A	0x87E1	
+0xCF6B	0x87E2	
+0xCF6C	0x87E3	
+0xCF6D	0x87E4	
+0xCF6E	0x87E6	
+0xCF6F	0x87E7	
+0xCF70	0x87E8	
+0xCF71	0x87E9	
+0xCF72	0x87EB	
+0xCF73	0x87EC	
+0xCF74	0x87ED	
+0xCF75	0x87EF	
+0xCF76	0x87F0	
+0xCF77	0x87F1	
+0xCF78	0x87F2	
+0xCF79	0x87F3	
+0xCF7A	0x87F4	
+0xCF7B	0x87F5	
+0xCF7C	0x87F6	
+0xCF7D	0x87F7	
+0xCF7E	0x87F8	
+0xCF80	0x87FA	
+0xCF81	0x87FB	
+0xCF82	0x87FC	
+0xCF83	0x87FD	
+0xCF84	0x87FF	
+0xCF85	0x8800	
+0xCF86	0x8801	
+0xCF87	0x8802	
+0xCF88	0x8804	
+0xCF89	0x8805	
+0xCF8A	0x8806	
+0xCF8B	0x8807	
+0xCF8C	0x8808	
+0xCF8D	0x8809	
+0xCF8E	0x880B	
+0xCF8F	0x880C	
+0xCF90	0x880D	
+0xCF91	0x880E	
+0xCF92	0x880F	
+0xCF93	0x8810	
+0xCF94	0x8811	
+0xCF95	0x8812	
+0xCF96	0x8814	
+0xCF97	0x8817	
+0xCF98	0x8818	
+0xCF99	0x8819	
+0xCF9A	0x881A	
+0xCF9B	0x881C	
+0xCF9C	0x881D	
+0xCF9D	0x881E	
+0xCF9E	0x881F	
+0xCF9F	0x8820	
+0xCFA0	0x8823	
+0xCFA1	0x7A00	
+0xCFA2	0x606F	
+0xCFA3	0x5E0C	
+0xCFA4	0x6089	
+0xCFA5	0x819D	
+0xCFA6	0x5915	
+0xCFA7	0x60DC	
+0xCFA8	0x7184	
+0xCFA9	0x70EF	
+0xCFAA	0x6EAA	
+0xCFAB	0x6C50	
+0xCFAC	0x7280	
+0xCFAD	0x6A84	
+0xCFAE	0x88AD	
+0xCFAF	0x5E2D	
+0xCFB0	0x4E60	
+0xCFB1	0x5AB3	
+0xCFB2	0x559C	
+0xCFB3	0x94E3	
+0xCFB4	0x6D17	
+0xCFB5	0x7CFB	
+0xCFB6	0x9699	
+0xCFB7	0x620F	
+0xCFB8	0x7EC6	
+0xCFB9	0x778E	
+0xCFBA	0x867E	
+0xCFBB	0x5323	
+0xCFBC	0x971E	
+0xCFBD	0x8F96	
+0xCFBE	0x6687	
+0xCFBF	0x5CE1	
+0xCFC0	0x4FA0	
+0xCFC1	0x72ED	
+0xCFC2	0x4E0B	
+0xCFC3	0x53A6	
+0xCFC4	0x590F	
+0xCFC5	0x5413	
+0xCFC6	0x6380	
+0xCFC7	0x9528	
+0xCFC8	0x5148	
+0xCFC9	0x4ED9	
+0xCFCA	0x9C9C	
+0xCFCB	0x7EA4	
+0xCFCC	0x54B8	
+0xCFCD	0x8D24	
+0xCFCE	0x8854	
+0xCFCF	0x8237	
+0xCFD0	0x95F2	
+0xCFD1	0x6D8E	
+0xCFD2	0x5F26	
+0xCFD3	0x5ACC	
+0xCFD4	0x663E	
+0xCFD5	0x9669	
+0xCFD6	0x73B0	
+0xCFD7	0x732E	
+0xCFD8	0x53BF	
+0xCFD9	0x817A	
+0xCFDA	0x9985	
+0xCFDB	0x7FA1	
+0xCFDC	0x5BAA	
+0xCFDD	0x9677	
+0xCFDE	0x9650	
+0xCFDF	0x7EBF	
+0xCFE0	0x76F8	
+0xCFE1	0x53A2	
+0xCFE2	0x9576	
+0xCFE3	0x9999	
+0xCFE4	0x7BB1	
+0xCFE5	0x8944	
+0xCFE6	0x6E58	
+0xCFE7	0x4E61	
+0xCFE8	0x7FD4	
+0xCFE9	0x7965	
+0xCFEA	0x8BE6	
+0xCFEB	0x60F3	
+0xCFEC	0x54CD	
+0xCFED	0x4EAB	
+0xCFEE	0x9879	
+0xCFEF	0x5DF7	
+0xCFF0	0x6A61	
+0xCFF1	0x50CF	
+0xCFF2	0x5411	
+0xCFF3	0x8C61	
+0xCFF4	0x8427	
+0xCFF5	0x785D	
+0xCFF6	0x9704	
+0xCFF7	0x524A	
+0xCFF8	0x54EE	
+0xCFF9	0x56A3	
+0xCFFA	0x9500	
+0xCFFB	0x6D88	
+0xCFFC	0x5BB5	
+0xCFFD	0x6DC6	
+0xCFFE	0x6653	
+0xD040	0x8824	
+0xD041	0x8825	
+0xD042	0x8826	
+0xD043	0x8827	
+0xD044	0x8828	
+0xD045	0x8829	
+0xD046	0x882A	
+0xD047	0x882B	
+0xD048	0x882C	
+0xD049	0x882D	
+0xD04A	0x882E	
+0xD04B	0x882F	
+0xD04C	0x8830	
+0xD04D	0x8831	
+0xD04E	0x8833	
+0xD04F	0x8834	
+0xD050	0x8835	
+0xD051	0x8836	
+0xD052	0x8837	
+0xD053	0x8838	
+0xD054	0x883A	
+0xD055	0x883B	
+0xD056	0x883D	
+0xD057	0x883E	
+0xD058	0x883F	
+0xD059	0x8841	
+0xD05A	0x8842	
+0xD05B	0x8843	
+0xD05C	0x8846	
+0xD05D	0x8847	
+0xD05E	0x8848	
+0xD05F	0x8849	
+0xD060	0x884A	
+0xD061	0x884B	
+0xD062	0x884E	
+0xD063	0x884F	
+0xD064	0x8850	
+0xD065	0x8851	
+0xD066	0x8852	
+0xD067	0x8853	
+0xD068	0x8855	
+0xD069	0x8856	
+0xD06A	0x8858	
+0xD06B	0x885A	
+0xD06C	0x885B	
+0xD06D	0x885C	
+0xD06E	0x885D	
+0xD06F	0x885E	
+0xD070	0x885F	
+0xD071	0x8860	
+0xD072	0x8866	
+0xD073	0x8867	
+0xD074	0x886A	
+0xD075	0x886D	
+0xD076	0x886F	
+0xD077	0x8871	
+0xD078	0x8873	
+0xD079	0x8874	
+0xD07A	0x8875	
+0xD07B	0x8876	
+0xD07C	0x8878	
+0xD07D	0x8879	
+0xD07E	0x887A	
+0xD080	0x887B	
+0xD081	0x887C	
+0xD082	0x8880	
+0xD083	0x8883	
+0xD084	0x8886	
+0xD085	0x8887	
+0xD086	0x8889	
+0xD087	0x888A	
+0xD088	0x888C	
+0xD089	0x888E	
+0xD08A	0x888F	
+0xD08B	0x8890	
+0xD08C	0x8891	
+0xD08D	0x8893	
+0xD08E	0x8894	
+0xD08F	0x8895	
+0xD090	0x8897	
+0xD091	0x8898	
+0xD092	0x8899	
+0xD093	0x889A	
+0xD094	0x889B	
+0xD095	0x889D	
+0xD096	0x889E	
+0xD097	0x889F	
+0xD098	0x88A0	
+0xD099	0x88A1	
+0xD09A	0x88A3	
+0xD09B	0x88A5	
+0xD09C	0x88A6	
+0xD09D	0x88A7	
+0xD09E	0x88A8	
+0xD09F	0x88A9	
+0xD0A0	0x88AA	
+0xD0A1	0x5C0F	
+0xD0A2	0x5B5D	
+0xD0A3	0x6821	
+0xD0A4	0x8096	
+0xD0A5	0x5578	
+0xD0A6	0x7B11	
+0xD0A7	0x6548	
+0xD0A8	0x6954	
+0xD0A9	0x4E9B	
+0xD0AA	0x6B47	
+0xD0AB	0x874E	
+0xD0AC	0x978B	
+0xD0AD	0x534F	
+0xD0AE	0x631F	
+0xD0AF	0x643A	
+0xD0B0	0x90AA	
+0xD0B1	0x659C	
+0xD0B2	0x80C1	
+0xD0B3	0x8C10	
+0xD0B4	0x5199	
+0xD0B5	0x68B0	
+0xD0B6	0x5378	
+0xD0B7	0x87F9	
+0xD0B8	0x61C8	
+0xD0B9	0x6CC4	
+0xD0BA	0x6CFB	
+0xD0BB	0x8C22	
+0xD0BC	0x5C51	
+0xD0BD	0x85AA	
+0xD0BE	0x82AF	
+0xD0BF	0x950C	
+0xD0C0	0x6B23	
+0xD0C1	0x8F9B	
+0xD0C2	0x65B0	
+0xD0C3	0x5FFB	
+0xD0C4	0x5FC3	
+0xD0C5	0x4FE1	
+0xD0C6	0x8845	
+0xD0C7	0x661F	
+0xD0C8	0x8165	
+0xD0C9	0x7329	
+0xD0CA	0x60FA	
+0xD0CB	0x5174	
+0xD0CC	0x5211	
+0xD0CD	0x578B	
+0xD0CE	0x5F62	
+0xD0CF	0x90A2	
+0xD0D0	0x884C	
+0xD0D1	0x9192	
+0xD0D2	0x5E78	
+0xD0D3	0x674F	
+0xD0D4	0x6027	
+0xD0D5	0x59D3	
+0xD0D6	0x5144	
+0xD0D7	0x51F6	
+0xD0D8	0x80F8	
+0xD0D9	0x5308	
+0xD0DA	0x6C79	
+0xD0DB	0x96C4	
+0xD0DC	0x718A	
+0xD0DD	0x4F11	
+0xD0DE	0x4FEE	
+0xD0DF	0x7F9E	
+0xD0E0	0x673D	
+0xD0E1	0x55C5	
+0xD0E2	0x9508	
+0xD0E3	0x79C0	
+0xD0E4	0x8896	
+0xD0E5	0x7EE3	
+0xD0E6	0x589F	
+0xD0E7	0x620C	
+0xD0E8	0x9700	
+0xD0E9	0x865A	
+0xD0EA	0x5618	
+0xD0EB	0x987B	
+0xD0EC	0x5F90	
+0xD0ED	0x8BB8	
+0xD0EE	0x84C4	
+0xD0EF	0x9157	
+0xD0F0	0x53D9	
+0xD0F1	0x65ED	
+0xD0F2	0x5E8F	
+0xD0F3	0x755C	
+0xD0F4	0x6064	
+0xD0F5	0x7D6E	
+0xD0F6	0x5A7F	
+0xD0F7	0x7EEA	
+0xD0F8	0x7EED	
+0xD0F9	0x8F69	
+0xD0FA	0x55A7	
+0xD0FB	0x5BA3	
+0xD0FC	0x60AC	
+0xD0FD	0x65CB	
+0xD0FE	0x7384	
+0xD140	0x88AC	
+0xD141	0x88AE	
+0xD142	0x88AF	
+0xD143	0x88B0	
+0xD144	0x88B2	
+0xD145	0x88B3	
+0xD146	0x88B4	
+0xD147	0x88B5	
+0xD148	0x88B6	
+0xD149	0x88B8	
+0xD14A	0x88B9	
+0xD14B	0x88BA	
+0xD14C	0x88BB	
+0xD14D	0x88BD	
+0xD14E	0x88BE	
+0xD14F	0x88BF	
+0xD150	0x88C0	
+0xD151	0x88C3	
+0xD152	0x88C4	
+0xD153	0x88C7	
+0xD154	0x88C8	
+0xD155	0x88CA	
+0xD156	0x88CB	
+0xD157	0x88CC	
+0xD158	0x88CD	
+0xD159	0x88CF	
+0xD15A	0x88D0	
+0xD15B	0x88D1	
+0xD15C	0x88D3	
+0xD15D	0x88D6	
+0xD15E	0x88D7	
+0xD15F	0x88DA	
+0xD160	0x88DB	
+0xD161	0x88DC	
+0xD162	0x88DD	
+0xD163	0x88DE	
+0xD164	0x88E0	
+0xD165	0x88E1	
+0xD166	0x88E6	
+0xD167	0x88E7	
+0xD168	0x88E9	
+0xD169	0x88EA	
+0xD16A	0x88EB	
+0xD16B	0x88EC	
+0xD16C	0x88ED	
+0xD16D	0x88EE	
+0xD16E	0x88EF	
+0xD16F	0x88F2	
+0xD170	0x88F5	
+0xD171	0x88F6	
+0xD172	0x88F7	
+0xD173	0x88FA	
+0xD174	0x88FB	
+0xD175	0x88FD	
+0xD176	0x88FF	
+0xD177	0x8900	
+0xD178	0x8901	
+0xD179	0x8903	
+0xD17A	0x8904	
+0xD17B	0x8905	
+0xD17C	0x8906	
+0xD17D	0x8907	
+0xD17E	0x8908	
+0xD180	0x8909	
+0xD181	0x890B	
+0xD182	0x890C	
+0xD183	0x890D	
+0xD184	0x890E	
+0xD185	0x890F	
+0xD186	0x8911	
+0xD187	0x8914	
+0xD188	0x8915	
+0xD189	0x8916	
+0xD18A	0x8917	
+0xD18B	0x8918	
+0xD18C	0x891C	
+0xD18D	0x891D	
+0xD18E	0x891E	
+0xD18F	0x891F	
+0xD190	0x8920	
+0xD191	0x8922	
+0xD192	0x8923	
+0xD193	0x8924	
+0xD194	0x8926	
+0xD195	0x8927	
+0xD196	0x8928	
+0xD197	0x8929	
+0xD198	0x892C	
+0xD199	0x892D	
+0xD19A	0x892E	
+0xD19B	0x892F	
+0xD19C	0x8931	
+0xD19D	0x8932	
+0xD19E	0x8933	
+0xD19F	0x8935	
+0xD1A0	0x8937	
+0xD1A1	0x9009	
+0xD1A2	0x7663	
+0xD1A3	0x7729	
+0xD1A4	0x7EDA	
+0xD1A5	0x9774	
+0xD1A6	0x859B	
+0xD1A7	0x5B66	
+0xD1A8	0x7A74	
+0xD1A9	0x96EA	
+0xD1AA	0x8840	
+0xD1AB	0x52CB	
+0xD1AC	0x718F	
+0xD1AD	0x5FAA	
+0xD1AE	0x65EC	
+0xD1AF	0x8BE2	
+0xD1B0	0x5BFB	
+0xD1B1	0x9A6F	
+0xD1B2	0x5DE1	
+0xD1B3	0x6B89	
+0xD1B4	0x6C5B	
+0xD1B5	0x8BAD	
+0xD1B6	0x8BAF	
+0xD1B7	0x900A	
+0xD1B8	0x8FC5	
+0xD1B9	0x538B	
+0xD1BA	0x62BC	
+0xD1BB	0x9E26	
+0xD1BC	0x9E2D	
+0xD1BD	0x5440	
+0xD1BE	0x4E2B	
+0xD1BF	0x82BD	
+0xD1C0	0x7259	
+0xD1C1	0x869C	
+0xD1C2	0x5D16	
+0xD1C3	0x8859	
+0xD1C4	0x6DAF	
+0xD1C5	0x96C5	
+0xD1C6	0x54D1	
+0xD1C7	0x4E9A	
+0xD1C8	0x8BB6	
+0xD1C9	0x7109	
+0xD1CA	0x54BD	
+0xD1CB	0x9609	
+0xD1CC	0x70DF	
+0xD1CD	0x6DF9	
+0xD1CE	0x76D0	
+0xD1CF	0x4E25	
+0xD1D0	0x7814	
+0xD1D1	0x8712	
+0xD1D2	0x5CA9	
+0xD1D3	0x5EF6	
+0xD1D4	0x8A00	
+0xD1D5	0x989C	
+0xD1D6	0x960E	
+0xD1D7	0x708E	
+0xD1D8	0x6CBF	
+0xD1D9	0x5944	
+0xD1DA	0x63A9	
+0xD1DB	0x773C	
+0xD1DC	0x884D	
+0xD1DD	0x6F14	
+0xD1DE	0x8273	
+0xD1DF	0x5830	
+0xD1E0	0x71D5	
+0xD1E1	0x538C	
+0xD1E2	0x781A	
+0xD1E3	0x96C1	
+0xD1E4	0x5501	
+0xD1E5	0x5F66	
+0xD1E6	0x7130	
+0xD1E7	0x5BB4	
+0xD1E8	0x8C1A	
+0xD1E9	0x9A8C	
+0xD1EA	0x6B83	
+0xD1EB	0x592E	
+0xD1EC	0x9E2F	
+0xD1ED	0x79E7	
+0xD1EE	0x6768	
+0xD1EF	0x626C	
+0xD1F0	0x4F6F	
+0xD1F1	0x75A1	
+0xD1F2	0x7F8A	
+0xD1F3	0x6D0B	
+0xD1F4	0x9633	
+0xD1F5	0x6C27	
+0xD1F6	0x4EF0	
+0xD1F7	0x75D2	
+0xD1F8	0x517B	
+0xD1F9	0x6837	
+0xD1FA	0x6F3E	
+0xD1FB	0x9080	
+0xD1FC	0x8170	
+0xD1FD	0x5996	
+0xD1FE	0x7476	
+0xD240	0x8938	
+0xD241	0x8939	
+0xD242	0x893A	
+0xD243	0x893B	
+0xD244	0x893C	
+0xD245	0x893D	
+0xD246	0x893E	
+0xD247	0x893F	
+0xD248	0x8940	
+0xD249	0x8942	
+0xD24A	0x8943	
+0xD24B	0x8945	
+0xD24C	0x8946	
+0xD24D	0x8947	
+0xD24E	0x8948	
+0xD24F	0x8949	
+0xD250	0x894A	
+0xD251	0x894B	
+0xD252	0x894C	
+0xD253	0x894D	
+0xD254	0x894E	
+0xD255	0x894F	
+0xD256	0x8950	
+0xD257	0x8951	
+0xD258	0x8952	
+0xD259	0x8953	
+0xD25A	0x8954	
+0xD25B	0x8955	
+0xD25C	0x8956	
+0xD25D	0x8957	
+0xD25E	0x8958	
+0xD25F	0x8959	
+0xD260	0x895A	
+0xD261	0x895B	
+0xD262	0x895C	
+0xD263	0x895D	
+0xD264	0x8960	
+0xD265	0x8961	
+0xD266	0x8962	
+0xD267	0x8963	
+0xD268	0x8964	
+0xD269	0x8965	
+0xD26A	0x8967	
+0xD26B	0x8968	
+0xD26C	0x8969	
+0xD26D	0x896A	
+0xD26E	0x896B	
+0xD26F	0x896C	
+0xD270	0x896D	
+0xD271	0x896E	
+0xD272	0x896F	
+0xD273	0x8970	
+0xD274	0x8971	
+0xD275	0x8972	
+0xD276	0x8973	
+0xD277	0x8974	
+0xD278	0x8975	
+0xD279	0x8976	
+0xD27A	0x8977	
+0xD27B	0x8978	
+0xD27C	0x8979	
+0xD27D	0x897A	
+0xD27E	0x897C	
+0xD280	0x897D	
+0xD281	0x897E	
+0xD282	0x8980	
+0xD283	0x8982	
+0xD284	0x8984	
+0xD285	0x8985	
+0xD286	0x8987	
+0xD287	0x8988	
+0xD288	0x8989	
+0xD289	0x898A	
+0xD28A	0x898B	
+0xD28B	0x898C	
+0xD28C	0x898D	
+0xD28D	0x898E	
+0xD28E	0x898F	
+0xD28F	0x8990	
+0xD290	0x8991	
+0xD291	0x8992	
+0xD292	0x8993	
+0xD293	0x8994	
+0xD294	0x8995	
+0xD295	0x8996	
+0xD296	0x8997	
+0xD297	0x8998	
+0xD298	0x8999	
+0xD299	0x899A	
+0xD29A	0x899B	
+0xD29B	0x899C	
+0xD29C	0x899D	
+0xD29D	0x899E	
+0xD29E	0x899F	
+0xD29F	0x89A0	
+0xD2A0	0x89A1	
+0xD2A1	0x6447	
+0xD2A2	0x5C27	
+0xD2A3	0x9065	
+0xD2A4	0x7A91	
+0xD2A5	0x8C23	
+0xD2A6	0x59DA	
+0xD2A7	0x54AC	
+0xD2A8	0x8200	
+0xD2A9	0x836F	
+0xD2AA	0x8981	
+0xD2AB	0x8000	
+0xD2AC	0x6930	
+0xD2AD	0x564E	
+0xD2AE	0x8036	
+0xD2AF	0x7237	
+0xD2B0	0x91CE	
+0xD2B1	0x51B6	
+0xD2B2	0x4E5F	
+0xD2B3	0x9875	
+0xD2B4	0x6396	
+0xD2B5	0x4E1A	
+0xD2B6	0x53F6	
+0xD2B7	0x66F3	
+0xD2B8	0x814B	
+0xD2B9	0x591C	
+0xD2BA	0x6DB2	
+0xD2BB	0x4E00	
+0xD2BC	0x58F9	
+0xD2BD	0x533B	
+0xD2BE	0x63D6	
+0xD2BF	0x94F1	
+0xD2C0	0x4F9D	
+0xD2C1	0x4F0A	
+0xD2C2	0x8863	
+0xD2C3	0x9890	
+0xD2C4	0x5937	
+0xD2C5	0x9057	
+0xD2C6	0x79FB	
+0xD2C7	0x4EEA	
+0xD2C8	0x80F0	
+0xD2C9	0x7591	
+0xD2CA	0x6C82	
+0xD2CB	0x5B9C	
+0xD2CC	0x59E8	
+0xD2CD	0x5F5D	
+0xD2CE	0x6905	
+0xD2CF	0x8681	
+0xD2D0	0x501A	
+0xD2D1	0x5DF2	
+0xD2D2	0x4E59	
+0xD2D3	0x77E3	
+0xD2D4	0x4EE5	
+0xD2D5	0x827A	
+0xD2D6	0x6291	
+0xD2D7	0x6613	
+0xD2D8	0x9091	
+0xD2D9	0x5C79	
+0xD2DA	0x4EBF	
+0xD2DB	0x5F79	
+0xD2DC	0x81C6	
+0xD2DD	0x9038	
+0xD2DE	0x8084	
+0xD2DF	0x75AB	
+0xD2E0	0x4EA6	
+0xD2E1	0x88D4	
+0xD2E2	0x610F	
+0xD2E3	0x6BC5	
+0xD2E4	0x5FC6	
+0xD2E5	0x4E49	
+0xD2E6	0x76CA	
+0xD2E7	0x6EA2	
+0xD2E8	0x8BE3	
+0xD2E9	0x8BAE	
+0xD2EA	0x8C0A	
+0xD2EB	0x8BD1	
+0xD2EC	0x5F02	
+0xD2ED	0x7FFC	
+0xD2EE	0x7FCC	
+0xD2EF	0x7ECE	
+0xD2F0	0x8335	
+0xD2F1	0x836B	
+0xD2F2	0x56E0	
+0xD2F3	0x6BB7	
+0xD2F4	0x97F3	
+0xD2F5	0x9634	
+0xD2F6	0x59FB	
+0xD2F7	0x541F	
+0xD2F8	0x94F6	
+0xD2F9	0x6DEB	
+0xD2FA	0x5BC5	
+0xD2FB	0x996E	
+0xD2FC	0x5C39	
+0xD2FD	0x5F15	
+0xD2FE	0x9690	
+0xD340	0x89A2	
+0xD341	0x89A3	
+0xD342	0x89A4	
+0xD343	0x89A5	
+0xD344	0x89A6	
+0xD345	0x89A7	
+0xD346	0x89A8	
+0xD347	0x89A9	
+0xD348	0x89AA	
+0xD349	0x89AB	
+0xD34A	0x89AC	
+0xD34B	0x89AD	
+0xD34C	0x89AE	
+0xD34D	0x89AF	
+0xD34E	0x89B0	
+0xD34F	0x89B1	
+0xD350	0x89B2	
+0xD351	0x89B3	
+0xD352	0x89B4	
+0xD353	0x89B5	
+0xD354	0x89B6	
+0xD355	0x89B7	
+0xD356	0x89B8	
+0xD357	0x89B9	
+0xD358	0x89BA	
+0xD359	0x89BB	
+0xD35A	0x89BC	
+0xD35B	0x89BD	
+0xD35C	0x89BE	
+0xD35D	0x89BF	
+0xD35E	0x89C0	
+0xD35F	0x89C3	
+0xD360	0x89CD	
+0xD361	0x89D3	
+0xD362	0x89D4	
+0xD363	0x89D5	
+0xD364	0x89D7	
+0xD365	0x89D8	
+0xD366	0x89D9	
+0xD367	0x89DB	
+0xD368	0x89DD	
+0xD369	0x89DF	
+0xD36A	0x89E0	
+0xD36B	0x89E1	
+0xD36C	0x89E2	
+0xD36D	0x89E4	
+0xD36E	0x89E7	
+0xD36F	0x89E8	
+0xD370	0x89E9	
+0xD371	0x89EA	
+0xD372	0x89EC	
+0xD373	0x89ED	
+0xD374	0x89EE	
+0xD375	0x89F0	
+0xD376	0x89F1	
+0xD377	0x89F2	
+0xD378	0x89F4	
+0xD379	0x89F5	
+0xD37A	0x89F6	
+0xD37B	0x89F7	
+0xD37C	0x89F8	
+0xD37D	0x89F9	
+0xD37E	0x89FA	
+0xD380	0x89FB	
+0xD381	0x89FC	
+0xD382	0x89FD	
+0xD383	0x89FE	
+0xD384	0x89FF	
+0xD385	0x8A01	
+0xD386	0x8A02	
+0xD387	0x8A03	
+0xD388	0x8A04	
+0xD389	0x8A05	
+0xD38A	0x8A06	
+0xD38B	0x8A08	
+0xD38C	0x8A09	
+0xD38D	0x8A0A	
+0xD38E	0x8A0B	
+0xD38F	0x8A0C	
+0xD390	0x8A0D	
+0xD391	0x8A0E	
+0xD392	0x8A0F	
+0xD393	0x8A10	
+0xD394	0x8A11	
+0xD395	0x8A12	
+0xD396	0x8A13	
+0xD397	0x8A14	
+0xD398	0x8A15	
+0xD399	0x8A16	
+0xD39A	0x8A17	
+0xD39B	0x8A18	
+0xD39C	0x8A19	
+0xD39D	0x8A1A	
+0xD39E	0x8A1B	
+0xD39F	0x8A1C	
+0xD3A0	0x8A1D	
+0xD3A1	0x5370	
+0xD3A2	0x82F1	
+0xD3A3	0x6A31	
+0xD3A4	0x5A74	
+0xD3A5	0x9E70	
+0xD3A6	0x5E94	
+0xD3A7	0x7F28	
+0xD3A8	0x83B9	
+0xD3A9	0x8424	
+0xD3AA	0x8425	
+0xD3AB	0x8367	
+0xD3AC	0x8747	
+0xD3AD	0x8FCE	
+0xD3AE	0x8D62	
+0xD3AF	0x76C8	
+0xD3B0	0x5F71	
+0xD3B1	0x9896	
+0xD3B2	0x786C	
+0xD3B3	0x6620	
+0xD3B4	0x54DF	
+0xD3B5	0x62E5	
+0xD3B6	0x4F63	
+0xD3B7	0x81C3	
+0xD3B8	0x75C8	
+0xD3B9	0x5EB8	
+0xD3BA	0x96CD	
+0xD3BB	0x8E0A	
+0xD3BC	0x86F9	
+0xD3BD	0x548F	
+0xD3BE	0x6CF3	
+0xD3BF	0x6D8C	
+0xD3C0	0x6C38	
+0xD3C1	0x607F	
+0xD3C2	0x52C7	
+0xD3C3	0x7528	
+0xD3C4	0x5E7D	
+0xD3C5	0x4F18	
+0xD3C6	0x60A0	
+0xD3C7	0x5FE7	
+0xD3C8	0x5C24	
+0xD3C9	0x7531	
+0xD3CA	0x90AE	
+0xD3CB	0x94C0	
+0xD3CC	0x72B9	
+0xD3CD	0x6CB9	
+0xD3CE	0x6E38	
+0xD3CF	0x9149	
+0xD3D0	0x6709	
+0xD3D1	0x53CB	
+0xD3D2	0x53F3	
+0xD3D3	0x4F51	
+0xD3D4	0x91C9	
+0xD3D5	0x8BF1	
+0xD3D6	0x53C8	
+0xD3D7	0x5E7C	
+0xD3D8	0x8FC2	
+0xD3D9	0x6DE4	
+0xD3DA	0x4E8E	
+0xD3DB	0x76C2	
+0xD3DC	0x6986	
+0xD3DD	0x865E	
+0xD3DE	0x611A	
+0xD3DF	0x8206	
+0xD3E0	0x4F59	
+0xD3E1	0x4FDE	
+0xD3E2	0x903E	
+0xD3E3	0x9C7C	
+0xD3E4	0x6109	
+0xD3E5	0x6E1D	
+0xD3E6	0x6E14	
+0xD3E7	0x9685	
+0xD3E8	0x4E88	
+0xD3E9	0x5A31	
+0xD3EA	0x96E8	
+0xD3EB	0x4E0E	
+0xD3EC	0x5C7F	
+0xD3ED	0x79B9	
+0xD3EE	0x5B87	
+0xD3EF	0x8BED	
+0xD3F0	0x7FBD	
+0xD3F1	0x7389	
+0xD3F2	0x57DF	
+0xD3F3	0x828B	
+0xD3F4	0x90C1	
+0xD3F5	0x5401	
+0xD3F6	0x9047	
+0xD3F7	0x55BB	
+0xD3F8	0x5CEA	
+0xD3F9	0x5FA1	
+0xD3FA	0x6108	
+0xD3FB	0x6B32	
+0xD3FC	0x72F1	
+0xD3FD	0x80B2	
+0xD3FE	0x8A89	
+0xD440	0x8A1E	
+0xD441	0x8A1F	
+0xD442	0x8A20	
+0xD443	0x8A21	
+0xD444	0x8A22	
+0xD445	0x8A23	
+0xD446	0x8A24	
+0xD447	0x8A25	
+0xD448	0x8A26	
+0xD449	0x8A27	
+0xD44A	0x8A28	
+0xD44B	0x8A29	
+0xD44C	0x8A2A	
+0xD44D	0x8A2B	
+0xD44E	0x8A2C	
+0xD44F	0x8A2D	
+0xD450	0x8A2E	
+0xD451	0x8A2F	
+0xD452	0x8A30	
+0xD453	0x8A31	
+0xD454	0x8A32	
+0xD455	0x8A33	
+0xD456	0x8A34	
+0xD457	0x8A35	
+0xD458	0x8A36	
+0xD459	0x8A37	
+0xD45A	0x8A38	
+0xD45B	0x8A39	
+0xD45C	0x8A3A	
+0xD45D	0x8A3B	
+0xD45E	0x8A3C	
+0xD45F	0x8A3D	
+0xD460	0x8A3F	
+0xD461	0x8A40	
+0xD462	0x8A41	
+0xD463	0x8A42	
+0xD464	0x8A43	
+0xD465	0x8A44	
+0xD466	0x8A45	
+0xD467	0x8A46	
+0xD468	0x8A47	
+0xD469	0x8A49	
+0xD46A	0x8A4A	
+0xD46B	0x8A4B	
+0xD46C	0x8A4C	
+0xD46D	0x8A4D	
+0xD46E	0x8A4E	
+0xD46F	0x8A4F	
+0xD470	0x8A50	
+0xD471	0x8A51	
+0xD472	0x8A52	
+0xD473	0x8A53	
+0xD474	0x8A54	
+0xD475	0x8A55	
+0xD476	0x8A56	
+0xD477	0x8A57	
+0xD478	0x8A58	
+0xD479	0x8A59	
+0xD47A	0x8A5A	
+0xD47B	0x8A5B	
+0xD47C	0x8A5C	
+0xD47D	0x8A5D	
+0xD47E	0x8A5E	
+0xD480	0x8A5F	
+0xD481	0x8A60	
+0xD482	0x8A61	
+0xD483	0x8A62	
+0xD484	0x8A63	
+0xD485	0x8A64	
+0xD486	0x8A65	
+0xD487	0x8A66	
+0xD488	0x8A67	
+0xD489	0x8A68	
+0xD48A	0x8A69	
+0xD48B	0x8A6A	
+0xD48C	0x8A6B	
+0xD48D	0x8A6C	
+0xD48E	0x8A6D	
+0xD48F	0x8A6E	
+0xD490	0x8A6F	
+0xD491	0x8A70	
+0xD492	0x8A71	
+0xD493	0x8A72	
+0xD494	0x8A73	
+0xD495	0x8A74	
+0xD496	0x8A75	
+0xD497	0x8A76	
+0xD498	0x8A77	
+0xD499	0x8A78	
+0xD49A	0x8A7A	
+0xD49B	0x8A7B	
+0xD49C	0x8A7C	
+0xD49D	0x8A7D	
+0xD49E	0x8A7E	
+0xD49F	0x8A7F	
+0xD4A0	0x8A80	
+0xD4A1	0x6D74	
+0xD4A2	0x5BD3	
+0xD4A3	0x88D5	
+0xD4A4	0x9884	
+0xD4A5	0x8C6B	
+0xD4A6	0x9A6D	
+0xD4A7	0x9E33	
+0xD4A8	0x6E0A	
+0xD4A9	0x51A4	
+0xD4AA	0x5143	
+0xD4AB	0x57A3	
+0xD4AC	0x8881	
+0xD4AD	0x539F	
+0xD4AE	0x63F4	
+0xD4AF	0x8F95	
+0xD4B0	0x56ED	
+0xD4B1	0x5458	
+0xD4B2	0x5706	
+0xD4B3	0x733F	
+0xD4B4	0x6E90	
+0xD4B5	0x7F18	
+0xD4B6	0x8FDC	
+0xD4B7	0x82D1	
+0xD4B8	0x613F	
+0xD4B9	0x6028	
+0xD4BA	0x9662	
+0xD4BB	0x66F0	
+0xD4BC	0x7EA6	
+0xD4BD	0x8D8A	
+0xD4BE	0x8DC3	
+0xD4BF	0x94A5	
+0xD4C0	0x5CB3	
+0xD4C1	0x7CA4	
+0xD4C2	0x6708	
+0xD4C3	0x60A6	
+0xD4C4	0x9605	
+0xD4C5	0x8018	
+0xD4C6	0x4E91	
+0xD4C7	0x90E7	
+0xD4C8	0x5300	
+0xD4C9	0x9668	
+0xD4CA	0x5141	
+0xD4CB	0x8FD0	
+0xD4CC	0x8574	
+0xD4CD	0x915D	
+0xD4CE	0x6655	
+0xD4CF	0x97F5	
+0xD4D0	0x5B55	
+0xD4D1	0x531D	
+0xD4D2	0x7838	
+0xD4D3	0x6742	
+0xD4D4	0x683D	
+0xD4D5	0x54C9	
+0xD4D6	0x707E	
+0xD4D7	0x5BB0	
+0xD4D8	0x8F7D	
+0xD4D9	0x518D	
+0xD4DA	0x5728	
+0xD4DB	0x54B1	
+0xD4DC	0x6512	
+0xD4DD	0x6682	
+0xD4DE	0x8D5E	
+0xD4DF	0x8D43	
+0xD4E0	0x810F	
+0xD4E1	0x846C	
+0xD4E2	0x906D	
+0xD4E3	0x7CDF	
+0xD4E4	0x51FF	
+0xD4E5	0x85FB	
+0xD4E6	0x67A3	
+0xD4E7	0x65E9	
+0xD4E8	0x6FA1	
+0xD4E9	0x86A4	
+0xD4EA	0x8E81	
+0xD4EB	0x566A	
+0xD4EC	0x9020	
+0xD4ED	0x7682	
+0xD4EE	0x7076	
+0xD4EF	0x71E5	
+0xD4F0	0x8D23	
+0xD4F1	0x62E9	
+0xD4F2	0x5219	
+0xD4F3	0x6CFD	
+0xD4F4	0x8D3C	
+0xD4F5	0x600E	
+0xD4F6	0x589E	
+0xD4F7	0x618E	
+0xD4F8	0x66FE	
+0xD4F9	0x8D60	
+0xD4FA	0x624E	
+0xD4FB	0x55B3	
+0xD4FC	0x6E23	
+0xD4FD	0x672D	
+0xD4FE	0x8F67	
+0xD540	0x8A81	
+0xD541	0x8A82	
+0xD542	0x8A83	
+0xD543	0x8A84	
+0xD544	0x8A85	
+0xD545	0x8A86	
+0xD546	0x8A87	
+0xD547	0x8A88	
+0xD548	0x8A8B	
+0xD549	0x8A8C	
+0xD54A	0x8A8D	
+0xD54B	0x8A8E	
+0xD54C	0x8A8F	
+0xD54D	0x8A90	
+0xD54E	0x8A91	
+0xD54F	0x8A92	
+0xD550	0x8A94	
+0xD551	0x8A95	
+0xD552	0x8A96	
+0xD553	0x8A97	
+0xD554	0x8A98	
+0xD555	0x8A99	
+0xD556	0x8A9A	
+0xD557	0x8A9B	
+0xD558	0x8A9C	
+0xD559	0x8A9D	
+0xD55A	0x8A9E	
+0xD55B	0x8A9F	
+0xD55C	0x8AA0	
+0xD55D	0x8AA1	
+0xD55E	0x8AA2	
+0xD55F	0x8AA3	
+0xD560	0x8AA4	
+0xD561	0x8AA5	
+0xD562	0x8AA6	
+0xD563	0x8AA7	
+0xD564	0x8AA8	
+0xD565	0x8AA9	
+0xD566	0x8AAA	
+0xD567	0x8AAB	
+0xD568	0x8AAC	
+0xD569	0x8AAD	
+0xD56A	0x8AAE	
+0xD56B	0x8AAF	
+0xD56C	0x8AB0	
+0xD56D	0x8AB1	
+0xD56E	0x8AB2	
+0xD56F	0x8AB3	
+0xD570	0x8AB4	
+0xD571	0x8AB5	
+0xD572	0x8AB6	
+0xD573	0x8AB7	
+0xD574	0x8AB8	
+0xD575	0x8AB9	
+0xD576	0x8ABA	
+0xD577	0x8ABB	
+0xD578	0x8ABC	
+0xD579	0x8ABD	
+0xD57A	0x8ABE	
+0xD57B	0x8ABF	
+0xD57C	0x8AC0	
+0xD57D	0x8AC1	
+0xD57E	0x8AC2	
+0xD580	0x8AC3	
+0xD581	0x8AC4	
+0xD582	0x8AC5	
+0xD583	0x8AC6	
+0xD584	0x8AC7	
+0xD585	0x8AC8	
+0xD586	0x8AC9	
+0xD587	0x8ACA	
+0xD588	0x8ACB	
+0xD589	0x8ACC	
+0xD58A	0x8ACD	
+0xD58B	0x8ACE	
+0xD58C	0x8ACF	
+0xD58D	0x8AD0	
+0xD58E	0x8AD1	
+0xD58F	0x8AD2	
+0xD590	0x8AD3	
+0xD591	0x8AD4	
+0xD592	0x8AD5	
+0xD593	0x8AD6	
+0xD594	0x8AD7	
+0xD595	0x8AD8	
+0xD596	0x8AD9	
+0xD597	0x8ADA	
+0xD598	0x8ADB	
+0xD599	0x8ADC	
+0xD59A	0x8ADD	
+0xD59B	0x8ADE	
+0xD59C	0x8ADF	
+0xD59D	0x8AE0	
+0xD59E	0x8AE1	
+0xD59F	0x8AE2	
+0xD5A0	0x8AE3	
+0xD5A1	0x94E1	
+0xD5A2	0x95F8	
+0xD5A3	0x7728	
+0xD5A4	0x6805	
+0xD5A5	0x69A8	
+0xD5A6	0x548B	
+0xD5A7	0x4E4D	
+0xD5A8	0x70B8	
+0xD5A9	0x8BC8	
+0xD5AA	0x6458	
+0xD5AB	0x658B	
+0xD5AC	0x5B85	
+0xD5AD	0x7A84	
+0xD5AE	0x503A	
+0xD5AF	0x5BE8	
+0xD5B0	0x77BB	
+0xD5B1	0x6BE1	
+0xD5B2	0x8A79	
+0xD5B3	0x7C98	
+0xD5B4	0x6CBE	
+0xD5B5	0x76CF	
+0xD5B6	0x65A9	
+0xD5B7	0x8F97	
+0xD5B8	0x5D2D	
+0xD5B9	0x5C55	
+0xD5BA	0x8638	
+0xD5BB	0x6808	
+0xD5BC	0x5360	
+0xD5BD	0x6218	
+0xD5BE	0x7AD9	
+0xD5BF	0x6E5B	
+0xD5C0	0x7EFD	
+0xD5C1	0x6A1F	
+0xD5C2	0x7AE0	
+0xD5C3	0x5F70	
+0xD5C4	0x6F33	
+0xD5C5	0x5F20	
+0xD5C6	0x638C	
+0xD5C7	0x6DA8	
+0xD5C8	0x6756	
+0xD5C9	0x4E08	
+0xD5CA	0x5E10	
+0xD5CB	0x8D26	
+0xD5CC	0x4ED7	
+0xD5CD	0x80C0	
+0xD5CE	0x7634	
+0xD5CF	0x969C	
+0xD5D0	0x62DB	
+0xD5D1	0x662D	
+0xD5D2	0x627E	
+0xD5D3	0x6CBC	
+0xD5D4	0x8D75	
+0xD5D5	0x7167	
+0xD5D6	0x7F69	
+0xD5D7	0x5146	
+0xD5D8	0x8087	
+0xD5D9	0x53EC	
+0xD5DA	0x906E	
+0xD5DB	0x6298	
+0xD5DC	0x54F2	
+0xD5DD	0x86F0	
+0xD5DE	0x8F99	
+0xD5DF	0x8005	
+0xD5E0	0x9517	
+0xD5E1	0x8517	
+0xD5E2	0x8FD9	
+0xD5E3	0x6D59	
+0xD5E4	0x73CD	
+0xD5E5	0x659F	
+0xD5E6	0x771F	
+0xD5E7	0x7504	
+0xD5E8	0x7827	
+0xD5E9	0x81FB	
+0xD5EA	0x8D1E	
+0xD5EB	0x9488	
+0xD5EC	0x4FA6	
+0xD5ED	0x6795	
+0xD5EE	0x75B9	
+0xD5EF	0x8BCA	
+0xD5F0	0x9707	
+0xD5F1	0x632F	
+0xD5F2	0x9547	
+0xD5F3	0x9635	
+0xD5F4	0x84B8	
+0xD5F5	0x6323	
+0xD5F6	0x7741	
+0xD5F7	0x5F81	
+0xD5F8	0x72F0	
+0xD5F9	0x4E89	
+0xD5FA	0x6014	
+0xD5FB	0x6574	
+0xD5FC	0x62EF	
+0xD5FD	0x6B63	
+0xD5FE	0x653F	
+0xD640	0x8AE4	
+0xD641	0x8AE5	
+0xD642	0x8AE6	
+0xD643	0x8AE7	
+0xD644	0x8AE8	
+0xD645	0x8AE9	
+0xD646	0x8AEA	
+0xD647	0x8AEB	
+0xD648	0x8AEC	
+0xD649	0x8AED	
+0xD64A	0x8AEE	
+0xD64B	0x8AEF	
+0xD64C	0x8AF0	
+0xD64D	0x8AF1	
+0xD64E	0x8AF2	
+0xD64F	0x8AF3	
+0xD650	0x8AF4	
+0xD651	0x8AF5	
+0xD652	0x8AF6	
+0xD653	0x8AF7	
+0xD654	0x8AF8	
+0xD655	0x8AF9	
+0xD656	0x8AFA	
+0xD657	0x8AFB	
+0xD658	0x8AFC	
+0xD659	0x8AFD	
+0xD65A	0x8AFE	
+0xD65B	0x8AFF	
+0xD65C	0x8B00	
+0xD65D	0x8B01	
+0xD65E	0x8B02	
+0xD65F	0x8B03	
+0xD660	0x8B04	
+0xD661	0x8B05	
+0xD662	0x8B06	
+0xD663	0x8B08	
+0xD664	0x8B09	
+0xD665	0x8B0A	
+0xD666	0x8B0B	
+0xD667	0x8B0C	
+0xD668	0x8B0D	
+0xD669	0x8B0E	
+0xD66A	0x8B0F	
+0xD66B	0x8B10	
+0xD66C	0x8B11	
+0xD66D	0x8B12	
+0xD66E	0x8B13	
+0xD66F	0x8B14	
+0xD670	0x8B15	
+0xD671	0x8B16	
+0xD672	0x8B17	
+0xD673	0x8B18	
+0xD674	0x8B19	
+0xD675	0x8B1A	
+0xD676	0x8B1B	
+0xD677	0x8B1C	
+0xD678	0x8B1D	
+0xD679	0x8B1E	
+0xD67A	0x8B1F	
+0xD67B	0x8B20	
+0xD67C	0x8B21	
+0xD67D	0x8B22	
+0xD67E	0x8B23	
+0xD680	0x8B24	
+0xD681	0x8B25	
+0xD682	0x8B27	
+0xD683	0x8B28	
+0xD684	0x8B29	
+0xD685	0x8B2A	
+0xD686	0x8B2B	
+0xD687	0x8B2C	
+0xD688	0x8B2D	
+0xD689	0x8B2E	
+0xD68A	0x8B2F	
+0xD68B	0x8B30	
+0xD68C	0x8B31	
+0xD68D	0x8B32	
+0xD68E	0x8B33	
+0xD68F	0x8B34	
+0xD690	0x8B35	
+0xD691	0x8B36	
+0xD692	0x8B37	
+0xD693	0x8B38	
+0xD694	0x8B39	
+0xD695	0x8B3A	
+0xD696	0x8B3B	
+0xD697	0x8B3C	
+0xD698	0x8B3D	
+0xD699	0x8B3E	
+0xD69A	0x8B3F	
+0xD69B	0x8B40	
+0xD69C	0x8B41	
+0xD69D	0x8B42	
+0xD69E	0x8B43	
+0xD69F	0x8B44	
+0xD6A0	0x8B45	
+0xD6A1	0x5E27	
+0xD6A2	0x75C7	
+0xD6A3	0x90D1	
+0xD6A4	0x8BC1	
+0xD6A5	0x829D	
+0xD6A6	0x679D	
+0xD6A7	0x652F	
+0xD6A8	0x5431	
+0xD6A9	0x8718	
+0xD6AA	0x77E5	
+0xD6AB	0x80A2	
+0xD6AC	0x8102	
+0xD6AD	0x6C41	
+0xD6AE	0x4E4B	
+0xD6AF	0x7EC7	
+0xD6B0	0x804C	
+0xD6B1	0x76F4	
+0xD6B2	0x690D	
+0xD6B3	0x6B96	
+0xD6B4	0x6267	
+0xD6B5	0x503C	
+0xD6B6	0x4F84	
+0xD6B7	0x5740	
+0xD6B8	0x6307	
+0xD6B9	0x6B62	
+0xD6BA	0x8DBE	
+0xD6BB	0x53EA	
+0xD6BC	0x65E8	
+0xD6BD	0x7EB8	
+0xD6BE	0x5FD7	
+0xD6BF	0x631A	
+0xD6C0	0x63B7	
+0xD6C1	0x81F3	
+0xD6C2	0x81F4	
+0xD6C3	0x7F6E	
+0xD6C4	0x5E1C	
+0xD6C5	0x5CD9	
+0xD6C6	0x5236	
+0xD6C7	0x667A	
+0xD6C8	0x79E9	
+0xD6C9	0x7A1A	
+0xD6CA	0x8D28	
+0xD6CB	0x7099	
+0xD6CC	0x75D4	
+0xD6CD	0x6EDE	
+0xD6CE	0x6CBB	
+0xD6CF	0x7A92	
+0xD6D0	0x4E2D	
+0xD6D1	0x76C5	
+0xD6D2	0x5FE0	
+0xD6D3	0x949F	
+0xD6D4	0x8877	
+0xD6D5	0x7EC8	
+0xD6D6	0x79CD	
+0xD6D7	0x80BF	
+0xD6D8	0x91CD	
+0xD6D9	0x4EF2	
+0xD6DA	0x4F17	
+0xD6DB	0x821F	
+0xD6DC	0x5468	
+0xD6DD	0x5DDE	
+0xD6DE	0x6D32	
+0xD6DF	0x8BCC	
+0xD6E0	0x7CA5	
+0xD6E1	0x8F74	
+0xD6E2	0x8098	
+0xD6E3	0x5E1A	
+0xD6E4	0x5492	
+0xD6E5	0x76B1	
+0xD6E6	0x5B99	
+0xD6E7	0x663C	
+0xD6E8	0x9AA4	
+0xD6E9	0x73E0	
+0xD6EA	0x682A	
+0xD6EB	0x86DB	
+0xD6EC	0x6731	
+0xD6ED	0x732A	
+0xD6EE	0x8BF8	
+0xD6EF	0x8BDB	
+0xD6F0	0x9010	
+0xD6F1	0x7AF9	
+0xD6F2	0x70DB	
+0xD6F3	0x716E	
+0xD6F4	0x62C4	
+0xD6F5	0x77A9	
+0xD6F6	0x5631	
+0xD6F7	0x4E3B	
+0xD6F8	0x8457	
+0xD6F9	0x67F1	
+0xD6FA	0x52A9	
+0xD6FB	0x86C0	
+0xD6FC	0x8D2E	
+0xD6FD	0x94F8	
+0xD6FE	0x7B51	
+0xD740	0x8B46	
+0xD741	0x8B47	
+0xD742	0x8B48	
+0xD743	0x8B49	
+0xD744	0x8B4A	
+0xD745	0x8B4B	
+0xD746	0x8B4C	
+0xD747	0x8B4D	
+0xD748	0x8B4E	
+0xD749	0x8B4F	
+0xD74A	0x8B50	
+0xD74B	0x8B51	
+0xD74C	0x8B52	
+0xD74D	0x8B53	
+0xD74E	0x8B54	
+0xD74F	0x8B55	
+0xD750	0x8B56	
+0xD751	0x8B57	
+0xD752	0x8B58	
+0xD753	0x8B59	
+0xD754	0x8B5A	
+0xD755	0x8B5B	
+0xD756	0x8B5C	
+0xD757	0x8B5D	
+0xD758	0x8B5E	
+0xD759	0x8B5F	
+0xD75A	0x8B60	
+0xD75B	0x8B61	
+0xD75C	0x8B62	
+0xD75D	0x8B63	
+0xD75E	0x8B64	
+0xD75F	0x8B65	
+0xD760	0x8B67	
+0xD761	0x8B68	
+0xD762	0x8B69	
+0xD763	0x8B6A	
+0xD764	0x8B6B	
+0xD765	0x8B6D	
+0xD766	0x8B6E	
+0xD767	0x8B6F	
+0xD768	0x8B70	
+0xD769	0x8B71	
+0xD76A	0x8B72	
+0xD76B	0x8B73	
+0xD76C	0x8B74	
+0xD76D	0x8B75	
+0xD76E	0x8B76	
+0xD76F	0x8B77	
+0xD770	0x8B78	
+0xD771	0x8B79	
+0xD772	0x8B7A	
+0xD773	0x8B7B	
+0xD774	0x8B7C	
+0xD775	0x8B7D	
+0xD776	0x8B7E	
+0xD777	0x8B7F	
+0xD778	0x8B80	
+0xD779	0x8B81	
+0xD77A	0x8B82	
+0xD77B	0x8B83	
+0xD77C	0x8B84	
+0xD77D	0x8B85	
+0xD77E	0x8B86	
+0xD780	0x8B87	
+0xD781	0x8B88	
+0xD782	0x8B89	
+0xD783	0x8B8A	
+0xD784	0x8B8B	
+0xD785	0x8B8C	
+0xD786	0x8B8D	
+0xD787	0x8B8E	
+0xD788	0x8B8F	
+0xD789	0x8B90	
+0xD78A	0x8B91	
+0xD78B	0x8B92	
+0xD78C	0x8B93	
+0xD78D	0x8B94	
+0xD78E	0x8B95	
+0xD78F	0x8B96	
+0xD790	0x8B97	
+0xD791	0x8B98	
+0xD792	0x8B99	
+0xD793	0x8B9A	
+0xD794	0x8B9B	
+0xD795	0x8B9C	
+0xD796	0x8B9D	
+0xD797	0x8B9E	
+0xD798	0x8B9F	
+0xD799	0x8BAC	
+0xD79A	0x8BB1	
+0xD79B	0x8BBB	
+0xD79C	0x8BC7	
+0xD79D	0x8BD0	
+0xD79E	0x8BEA	
+0xD79F	0x8C09	
+0xD7A0	0x8C1E	
+0xD7A1	0x4F4F	
+0xD7A2	0x6CE8	
+0xD7A3	0x795D	
+0xD7A4	0x9A7B	
+0xD7A5	0x6293	
+0xD7A6	0x722A	
+0xD7A7	0x62FD	
+0xD7A8	0x4E13	
+0xD7A9	0x7816	
+0xD7AA	0x8F6C	
+0xD7AB	0x64B0	
+0xD7AC	0x8D5A	
+0xD7AD	0x7BC6	
+0xD7AE	0x6869	
+0xD7AF	0x5E84	
+0xD7B0	0x88C5	
+0xD7B1	0x5986	
+0xD7B2	0x649E	
+0xD7B3	0x58EE	
+0xD7B4	0x72B6	
+0xD7B5	0x690E	
+0xD7B6	0x9525	
+0xD7B7	0x8FFD	
+0xD7B8	0x8D58	
+0xD7B9	0x5760	
+0xD7BA	0x7F00	
+0xD7BB	0x8C06	
+0xD7BC	0x51C6	
+0xD7BD	0x6349	
+0xD7BE	0x62D9	
+0xD7BF	0x5353	
+0xD7C0	0x684C	
+0xD7C1	0x7422	
+0xD7C2	0x8301	
+0xD7C3	0x914C	
+0xD7C4	0x5544	
+0xD7C5	0x7740	
+0xD7C6	0x707C	
+0xD7C7	0x6D4A	
+0xD7C8	0x5179	
+0xD7C9	0x54A8	
+0xD7CA	0x8D44	
+0xD7CB	0x59FF	
+0xD7CC	0x6ECB	
+0xD7CD	0x6DC4	
+0xD7CE	0x5B5C	
+0xD7CF	0x7D2B	
+0xD7D0	0x4ED4	
+0xD7D1	0x7C7D	
+0xD7D2	0x6ED3	
+0xD7D3	0x5B50	
+0xD7D4	0x81EA	
+0xD7D5	0x6E0D	
+0xD7D6	0x5B57	
+0xD7D7	0x9B03	
+0xD7D8	0x68D5	
+0xD7D9	0x8E2A	
+0xD7DA	0x5B97	
+0xD7DB	0x7EFC	
+0xD7DC	0x603B	
+0xD7DD	0x7EB5	
+0xD7DE	0x90B9	
+0xD7DF	0x8D70	
+0xD7E0	0x594F	
+0xD7E1	0x63CD	
+0xD7E2	0x79DF	
+0xD7E3	0x8DB3	
+0xD7E4	0x5352	
+0xD7E5	0x65CF	
+0xD7E6	0x7956	
+0xD7E7	0x8BC5	
+0xD7E8	0x963B	
+0xD7E9	0x7EC4	
+0xD7EA	0x94BB	
+0xD7EB	0x7E82	
+0xD7EC	0x5634	
+0xD7ED	0x9189	
+0xD7EE	0x6700	
+0xD7EF	0x7F6A	
+0xD7F0	0x5C0A	
+0xD7F1	0x9075	
+0xD7F2	0x6628	
+0xD7F3	0x5DE6	
+0xD7F4	0x4F50	
+0xD7F5	0x67DE	
+0xD7F6	0x505A	
+0xD7F7	0x4F5C	
+0xD7F8	0x5750	
+0xD7F9	0x5EA7	
+# 0xD7FA	 	
+# 0xD7FB	 	
+# 0xD7FC	 	
+# 0xD7FD	 	
+# 0xD7FE	 	
+0xD840	0x8C38	
+0xD841	0x8C39	
+0xD842	0x8C3A	
+0xD843	0x8C3B	
+0xD844	0x8C3C	
+0xD845	0x8C3D	
+0xD846	0x8C3E	
+0xD847	0x8C3F	
+0xD848	0x8C40	
+0xD849	0x8C42	
+0xD84A	0x8C43	
+0xD84B	0x8C44	
+0xD84C	0x8C45	
+0xD84D	0x8C48	
+0xD84E	0x8C4A	
+0xD84F	0x8C4B	
+0xD850	0x8C4D	
+0xD851	0x8C4E	
+0xD852	0x8C4F	
+0xD853	0x8C50	
+0xD854	0x8C51	
+0xD855	0x8C52	
+0xD856	0x8C53	
+0xD857	0x8C54	
+0xD858	0x8C56	
+0xD859	0x8C57	
+0xD85A	0x8C58	
+0xD85B	0x8C59	
+0xD85C	0x8C5B	
+0xD85D	0x8C5C	
+0xD85E	0x8C5D	
+0xD85F	0x8C5E	
+0xD860	0x8C5F	
+0xD861	0x8C60	
+0xD862	0x8C63	
+0xD863	0x8C64	
+0xD864	0x8C65	
+0xD865	0x8C66	
+0xD866	0x8C67	
+0xD867	0x8C68	
+0xD868	0x8C69	
+0xD869	0x8C6C	
+0xD86A	0x8C6D	
+0xD86B	0x8C6E	
+0xD86C	0x8C6F	
+0xD86D	0x8C70	
+0xD86E	0x8C71	
+0xD86F	0x8C72	
+0xD870	0x8C74	
+0xD871	0x8C75	
+0xD872	0x8C76	
+0xD873	0x8C77	
+0xD874	0x8C7B	
+0xD875	0x8C7C	
+0xD876	0x8C7D	
+0xD877	0x8C7E	
+0xD878	0x8C7F	
+0xD879	0x8C80	
+0xD87A	0x8C81	
+0xD87B	0x8C83	
+0xD87C	0x8C84	
+0xD87D	0x8C86	
+0xD87E	0x8C87	
+0xD880	0x8C88	
+0xD881	0x8C8B	
+0xD882	0x8C8D	
+0xD883	0x8C8E	
+0xD884	0x8C8F	
+0xD885	0x8C90	
+0xD886	0x8C91	
+0xD887	0x8C92	
+0xD888	0x8C93	
+0xD889	0x8C95	
+0xD88A	0x8C96	
+0xD88B	0x8C97	
+0xD88C	0x8C99	
+0xD88D	0x8C9A	
+0xD88E	0x8C9B	
+0xD88F	0x8C9C	
+0xD890	0x8C9D	
+0xD891	0x8C9E	
+0xD892	0x8C9F	
+0xD893	0x8CA0	
+0xD894	0x8CA1	
+0xD895	0x8CA2	
+0xD896	0x8CA3	
+0xD897	0x8CA4	
+0xD898	0x8CA5	
+0xD899	0x8CA6	
+0xD89A	0x8CA7	
+0xD89B	0x8CA8	
+0xD89C	0x8CA9	
+0xD89D	0x8CAA	
+0xD89E	0x8CAB	
+0xD89F	0x8CAC	
+0xD8A0	0x8CAD	
+0xD8A1	0x4E8D	
+0xD8A2	0x4E0C	
+0xD8A3	0x5140	
+0xD8A4	0x4E10	
+0xD8A5	0x5EFF	
+0xD8A6	0x5345	
+0xD8A7	0x4E15	
+0xD8A8	0x4E98	
+0xD8A9	0x4E1E	
+0xD8AA	0x9B32	
+0xD8AB	0x5B6C	
+0xD8AC	0x5669	
+0xD8AD	0x4E28	
+0xD8AE	0x79BA	
+0xD8AF	0x4E3F	
+0xD8B0	0x5315	
+0xD8B1	0x4E47	
+0xD8B2	0x592D	
+0xD8B3	0x723B	
+0xD8B4	0x536E	
+0xD8B5	0x6C10	
+0xD8B6	0x56DF	
+0xD8B7	0x80E4	
+0xD8B8	0x9997	
+0xD8B9	0x6BD3	
+0xD8BA	0x777E	
+0xD8BB	0x9F17	
+0xD8BC	0x4E36	
+0xD8BD	0x4E9F	
+0xD8BE	0x9F10	
+0xD8BF	0x4E5C	
+0xD8C0	0x4E69	
+0xD8C1	0x4E93	
+0xD8C2	0x8288	
+0xD8C3	0x5B5B	
+0xD8C4	0x556C	
+0xD8C5	0x560F	
+0xD8C6	0x4EC4	
+0xD8C7	0x538D	
+0xD8C8	0x539D	
+0xD8C9	0x53A3	
+0xD8CA	0x53A5	
+0xD8CB	0x53AE	
+0xD8CC	0x9765	
+0xD8CD	0x8D5D	
+0xD8CE	0x531A	
+0xD8CF	0x53F5	
+0xD8D0	0x5326	
+0xD8D1	0x532E	
+0xD8D2	0x533E	
+0xD8D3	0x8D5C	
+0xD8D4	0x5366	
+0xD8D5	0x5363	
+0xD8D6	0x5202	
+0xD8D7	0x5208	
+0xD8D8	0x520E	
+0xD8D9	0x522D	
+0xD8DA	0x5233	
+0xD8DB	0x523F	
+0xD8DC	0x5240	
+0xD8DD	0x524C	
+0xD8DE	0x525E	
+0xD8DF	0x5261	
+0xD8E0	0x525C	
+0xD8E1	0x84AF	
+0xD8E2	0x527D	
+0xD8E3	0x5282	
+0xD8E4	0x5281	
+0xD8E5	0x5290	
+0xD8E6	0x5293	
+0xD8E7	0x5182	
+0xD8E8	0x7F54	
+0xD8E9	0x4EBB	
+0xD8EA	0x4EC3	
+0xD8EB	0x4EC9	
+0xD8EC	0x4EC2	
+0xD8ED	0x4EE8	
+0xD8EE	0x4EE1	
+0xD8EF	0x4EEB	
+0xD8F0	0x4EDE	
+0xD8F1	0x4F1B	
+0xD8F2	0x4EF3	
+0xD8F3	0x4F22	
+0xD8F4	0x4F64	
+0xD8F5	0x4EF5	
+0xD8F6	0x4F25	
+0xD8F7	0x4F27	
+0xD8F8	0x4F09	
+0xD8F9	0x4F2B	
+0xD8FA	0x4F5E	
+0xD8FB	0x4F67	
+0xD8FC	0x6538	
+0xD8FD	0x4F5A	
+0xD8FE	0x4F5D	
+0xD940	0x8CAE	
+0xD941	0x8CAF	
+0xD942	0x8CB0	
+0xD943	0x8CB1	
+0xD944	0x8CB2	
+0xD945	0x8CB3	
+0xD946	0x8CB4	
+0xD947	0x8CB5	
+0xD948	0x8CB6	
+0xD949	0x8CB7	
+0xD94A	0x8CB8	
+0xD94B	0x8CB9	
+0xD94C	0x8CBA	
+0xD94D	0x8CBB	
+0xD94E	0x8CBC	
+0xD94F	0x8CBD	
+0xD950	0x8CBE	
+0xD951	0x8CBF	
+0xD952	0x8CC0	
+0xD953	0x8CC1	
+0xD954	0x8CC2	
+0xD955	0x8CC3	
+0xD956	0x8CC4	
+0xD957	0x8CC5	
+0xD958	0x8CC6	
+0xD959	0x8CC7	
+0xD95A	0x8CC8	
+0xD95B	0x8CC9	
+0xD95C	0x8CCA	
+0xD95D	0x8CCB	
+0xD95E	0x8CCC	
+0xD95F	0x8CCD	
+0xD960	0x8CCE	
+0xD961	0x8CCF	
+0xD962	0x8CD0	
+0xD963	0x8CD1	
+0xD964	0x8CD2	
+0xD965	0x8CD3	
+0xD966	0x8CD4	
+0xD967	0x8CD5	
+0xD968	0x8CD6	
+0xD969	0x8CD7	
+0xD96A	0x8CD8	
+0xD96B	0x8CD9	
+0xD96C	0x8CDA	
+0xD96D	0x8CDB	
+0xD96E	0x8CDC	
+0xD96F	0x8CDD	
+0xD970	0x8CDE	
+0xD971	0x8CDF	
+0xD972	0x8CE0	
+0xD973	0x8CE1	
+0xD974	0x8CE2	
+0xD975	0x8CE3	
+0xD976	0x8CE4	
+0xD977	0x8CE5	
+0xD978	0x8CE6	
+0xD979	0x8CE7	
+0xD97A	0x8CE8	
+0xD97B	0x8CE9	
+0xD97C	0x8CEA	
+0xD97D	0x8CEB	
+0xD97E	0x8CEC	
+0xD980	0x8CED	
+0xD981	0x8CEE	
+0xD982	0x8CEF	
+0xD983	0x8CF0	
+0xD984	0x8CF1	
+0xD985	0x8CF2	
+0xD986	0x8CF3	
+0xD987	0x8CF4	
+0xD988	0x8CF5	
+0xD989	0x8CF6	
+0xD98A	0x8CF7	
+0xD98B	0x8CF8	
+0xD98C	0x8CF9	
+0xD98D	0x8CFA	
+0xD98E	0x8CFB	
+0xD98F	0x8CFC	
+0xD990	0x8CFD	
+0xD991	0x8CFE	
+0xD992	0x8CFF	
+0xD993	0x8D00	
+0xD994	0x8D01	
+0xD995	0x8D02	
+0xD996	0x8D03	
+0xD997	0x8D04	
+0xD998	0x8D05	
+0xD999	0x8D06	
+0xD99A	0x8D07	
+0xD99B	0x8D08	
+0xD99C	0x8D09	
+0xD99D	0x8D0A	
+0xD99E	0x8D0B	
+0xD99F	0x8D0C	
+0xD9A0	0x8D0D	
+0xD9A1	0x4F5F	
+0xD9A2	0x4F57	
+0xD9A3	0x4F32	
+0xD9A4	0x4F3D	
+0xD9A5	0x4F76	
+0xD9A6	0x4F74	
+0xD9A7	0x4F91	
+0xD9A8	0x4F89	
+0xD9A9	0x4F83	
+0xD9AA	0x4F8F	
+0xD9AB	0x4F7E	
+0xD9AC	0x4F7B	
+0xD9AD	0x4FAA	
+0xD9AE	0x4F7C	
+0xD9AF	0x4FAC	
+0xD9B0	0x4F94	
+0xD9B1	0x4FE6	
+0xD9B2	0x4FE8	
+0xD9B3	0x4FEA	
+0xD9B4	0x4FC5	
+0xD9B5	0x4FDA	
+0xD9B6	0x4FE3	
+0xD9B7	0x4FDC	
+0xD9B8	0x4FD1	
+0xD9B9	0x4FDF	
+0xD9BA	0x4FF8	
+0xD9BB	0x5029	
+0xD9BC	0x504C	
+0xD9BD	0x4FF3	
+0xD9BE	0x502C	
+0xD9BF	0x500F	
+0xD9C0	0x502E	
+0xD9C1	0x502D	
+0xD9C2	0x4FFE	
+0xD9C3	0x501C	
+0xD9C4	0x500C	
+0xD9C5	0x5025	
+0xD9C6	0x5028	
+0xD9C7	0x507E	
+0xD9C8	0x5043	
+0xD9C9	0x5055	
+0xD9CA	0x5048	
+0xD9CB	0x504E	
+0xD9CC	0x506C	
+0xD9CD	0x507B	
+0xD9CE	0x50A5	
+0xD9CF	0x50A7	
+0xD9D0	0x50A9	
+0xD9D1	0x50BA	
+0xD9D2	0x50D6	
+0xD9D3	0x5106	
+0xD9D4	0x50ED	
+0xD9D5	0x50EC	
+0xD9D6	0x50E6	
+0xD9D7	0x50EE	
+0xD9D8	0x5107	
+0xD9D9	0x510B	
+0xD9DA	0x4EDD	
+0xD9DB	0x6C3D	
+0xD9DC	0x4F58	
+0xD9DD	0x4F65	
+0xD9DE	0x4FCE	
+0xD9DF	0x9FA0	
+0xD9E0	0x6C46	
+0xD9E1	0x7C74	
+0xD9E2	0x516E	
+0xD9E3	0x5DFD	
+0xD9E4	0x9EC9	
+0xD9E5	0x9998	
+0xD9E6	0x5181	
+0xD9E7	0x5914	
+0xD9E8	0x52F9	
+0xD9E9	0x530D	
+0xD9EA	0x8A07	
+0xD9EB	0x5310	
+0xD9EC	0x51EB	
+0xD9ED	0x5919	
+0xD9EE	0x5155	
+0xD9EF	0x4EA0	
+0xD9F0	0x5156	
+0xD9F1	0x4EB3	
+0xD9F2	0x886E	
+0xD9F3	0x88A4	
+0xD9F4	0x4EB5	
+0xD9F5	0x8114	
+0xD9F6	0x88D2	
+0xD9F7	0x7980	
+0xD9F8	0x5B34	
+0xD9F9	0x8803	
+0xD9FA	0x7FB8	
+0xD9FB	0x51AB	
+0xD9FC	0x51B1	
+0xD9FD	0x51BD	
+0xD9FE	0x51BC	
+0xDA40	0x8D0E	
+0xDA41	0x8D0F	
+0xDA42	0x8D10	
+0xDA43	0x8D11	
+0xDA44	0x8D12	
+0xDA45	0x8D13	
+0xDA46	0x8D14	
+0xDA47	0x8D15	
+0xDA48	0x8D16	
+0xDA49	0x8D17	
+0xDA4A	0x8D18	
+0xDA4B	0x8D19	
+0xDA4C	0x8D1A	
+0xDA4D	0x8D1B	
+0xDA4E	0x8D1C	
+0xDA4F	0x8D20	
+0xDA50	0x8D51	
+0xDA51	0x8D52	
+0xDA52	0x8D57	
+0xDA53	0x8D5F	
+0xDA54	0x8D65	
+0xDA55	0x8D68	
+0xDA56	0x8D69	
+0xDA57	0x8D6A	
+0xDA58	0x8D6C	
+0xDA59	0x8D6E	
+0xDA5A	0x8D6F	
+0xDA5B	0x8D71	
+0xDA5C	0x8D72	
+0xDA5D	0x8D78	
+0xDA5E	0x8D79	
+0xDA5F	0x8D7A	
+0xDA60	0x8D7B	
+0xDA61	0x8D7C	
+0xDA62	0x8D7D	
+0xDA63	0x8D7E	
+0xDA64	0x8D7F	
+0xDA65	0x8D80	
+0xDA66	0x8D82	
+0xDA67	0x8D83	
+0xDA68	0x8D86	
+0xDA69	0x8D87	
+0xDA6A	0x8D88	
+0xDA6B	0x8D89	
+0xDA6C	0x8D8C	
+0xDA6D	0x8D8D	
+0xDA6E	0x8D8E	
+0xDA6F	0x8D8F	
+0xDA70	0x8D90	
+0xDA71	0x8D92	
+0xDA72	0x8D93	
+0xDA73	0x8D95	
+0xDA74	0x8D96	
+0xDA75	0x8D97	
+0xDA76	0x8D98	
+0xDA77	0x8D99	
+0xDA78	0x8D9A	
+0xDA79	0x8D9B	
+0xDA7A	0x8D9C	
+0xDA7B	0x8D9D	
+0xDA7C	0x8D9E	
+0xDA7D	0x8DA0	
+0xDA7E	0x8DA1	
+0xDA80	0x8DA2	
+0xDA81	0x8DA4	
+0xDA82	0x8DA5	
+0xDA83	0x8DA6	
+0xDA84	0x8DA7	
+0xDA85	0x8DA8	
+0xDA86	0x8DA9	
+0xDA87	0x8DAA	
+0xDA88	0x8DAB	
+0xDA89	0x8DAC	
+0xDA8A	0x8DAD	
+0xDA8B	0x8DAE	
+0xDA8C	0x8DAF	
+0xDA8D	0x8DB0	
+0xDA8E	0x8DB2	
+0xDA8F	0x8DB6	
+0xDA90	0x8DB7	
+0xDA91	0x8DB9	
+0xDA92	0x8DBB	
+0xDA93	0x8DBD	
+0xDA94	0x8DC0	
+0xDA95	0x8DC1	
+0xDA96	0x8DC2	
+0xDA97	0x8DC5	
+0xDA98	0x8DC7	
+0xDA99	0x8DC8	
+0xDA9A	0x8DC9	
+0xDA9B	0x8DCA	
+0xDA9C	0x8DCD	
+0xDA9D	0x8DD0	
+0xDA9E	0x8DD2	
+0xDA9F	0x8DD3	
+0xDAA0	0x8DD4	
+0xDAA1	0x51C7	
+0xDAA2	0x5196	
+0xDAA3	0x51A2	
+0xDAA4	0x51A5	
+0xDAA5	0x8BA0	
+0xDAA6	0x8BA6	
+0xDAA7	0x8BA7	
+0xDAA8	0x8BAA	
+0xDAA9	0x8BB4	
+0xDAAA	0x8BB5	
+0xDAAB	0x8BB7	
+0xDAAC	0x8BC2	
+0xDAAD	0x8BC3	
+0xDAAE	0x8BCB	
+0xDAAF	0x8BCF	
+0xDAB0	0x8BCE	
+0xDAB1	0x8BD2	
+0xDAB2	0x8BD3	
+0xDAB3	0x8BD4	
+0xDAB4	0x8BD6	
+0xDAB5	0x8BD8	
+0xDAB6	0x8BD9	
+0xDAB7	0x8BDC	
+0xDAB8	0x8BDF	
+0xDAB9	0x8BE0	
+0xDABA	0x8BE4	
+0xDABB	0x8BE8	
+0xDABC	0x8BE9	
+0xDABD	0x8BEE	
+0xDABE	0x8BF0	
+0xDABF	0x8BF3	
+0xDAC0	0x8BF6	
+0xDAC1	0x8BF9	
+0xDAC2	0x8BFC	
+0xDAC3	0x8BFF	
+0xDAC4	0x8C00	
+0xDAC5	0x8C02	
+0xDAC6	0x8C04	
+0xDAC7	0x8C07	
+0xDAC8	0x8C0C	
+0xDAC9	0x8C0F	
+0xDACA	0x8C11	
+0xDACB	0x8C12	
+0xDACC	0x8C14	
+0xDACD	0x8C15	
+0xDACE	0x8C16	
+0xDACF	0x8C19	
+0xDAD0	0x8C1B	
+0xDAD1	0x8C18	
+0xDAD2	0x8C1D	
+0xDAD3	0x8C1F	
+0xDAD4	0x8C20	
+0xDAD5	0x8C21	
+0xDAD6	0x8C25	
+0xDAD7	0x8C27	
+0xDAD8	0x8C2A	
+0xDAD9	0x8C2B	
+0xDADA	0x8C2E	
+0xDADB	0x8C2F	
+0xDADC	0x8C32	
+0xDADD	0x8C33	
+0xDADE	0x8C35	
+0xDADF	0x8C36	
+0xDAE0	0x5369	
+0xDAE1	0x537A	
+0xDAE2	0x961D	
+0xDAE3	0x9622	
+0xDAE4	0x9621	
+0xDAE5	0x9631	
+0xDAE6	0x962A	
+0xDAE7	0x963D	
+0xDAE8	0x963C	
+0xDAE9	0x9642	
+0xDAEA	0x9649	
+0xDAEB	0x9654	
+0xDAEC	0x965F	
+0xDAED	0x9667	
+0xDAEE	0x966C	
+0xDAEF	0x9672	
+0xDAF0	0x9674	
+0xDAF1	0x9688	
+0xDAF2	0x968D	
+0xDAF3	0x9697	
+0xDAF4	0x96B0	
+0xDAF5	0x9097	
+0xDAF6	0x909B	
+0xDAF7	0x909D	
+0xDAF8	0x9099	
+0xDAF9	0x90AC	
+0xDAFA	0x90A1	
+0xDAFB	0x90B4	
+0xDAFC	0x90B3	
+0xDAFD	0x90B6	
+0xDAFE	0x90BA	
+0xDB40	0x8DD5	
+0xDB41	0x8DD8	
+0xDB42	0x8DD9	
+0xDB43	0x8DDC	
+0xDB44	0x8DE0	
+0xDB45	0x8DE1	
+0xDB46	0x8DE2	
+0xDB47	0x8DE5	
+0xDB48	0x8DE6	
+0xDB49	0x8DE7	
+0xDB4A	0x8DE9	
+0xDB4B	0x8DED	
+0xDB4C	0x8DEE	
+0xDB4D	0x8DF0	
+0xDB4E	0x8DF1	
+0xDB4F	0x8DF2	
+0xDB50	0x8DF4	
+0xDB51	0x8DF6	
+0xDB52	0x8DFC	
+0xDB53	0x8DFE	
+0xDB54	0x8DFF	
+0xDB55	0x8E00	
+0xDB56	0x8E01	
+0xDB57	0x8E02	
+0xDB58	0x8E03	
+0xDB59	0x8E04	
+0xDB5A	0x8E06	
+0xDB5B	0x8E07	
+0xDB5C	0x8E08	
+0xDB5D	0x8E0B	
+0xDB5E	0x8E0D	
+0xDB5F	0x8E0E	
+0xDB60	0x8E10	
+0xDB61	0x8E11	
+0xDB62	0x8E12	
+0xDB63	0x8E13	
+0xDB64	0x8E15	
+0xDB65	0x8E16	
+0xDB66	0x8E17	
+0xDB67	0x8E18	
+0xDB68	0x8E19	
+0xDB69	0x8E1A	
+0xDB6A	0x8E1B	
+0xDB6B	0x8E1C	
+0xDB6C	0x8E20	
+0xDB6D	0x8E21	
+0xDB6E	0x8E24	
+0xDB6F	0x8E25	
+0xDB70	0x8E26	
+0xDB71	0x8E27	
+0xDB72	0x8E28	
+0xDB73	0x8E2B	
+0xDB74	0x8E2D	
+0xDB75	0x8E30	
+0xDB76	0x8E32	
+0xDB77	0x8E33	
+0xDB78	0x8E34	
+0xDB79	0x8E36	
+0xDB7A	0x8E37	
+0xDB7B	0x8E38	
+0xDB7C	0x8E3B	
+0xDB7D	0x8E3C	
+0xDB7E	0x8E3E	
+0xDB80	0x8E3F	
+0xDB81	0x8E43	
+0xDB82	0x8E45	
+0xDB83	0x8E46	
+0xDB84	0x8E4C	
+0xDB85	0x8E4D	
+0xDB86	0x8E4E	
+0xDB87	0x8E4F	
+0xDB88	0x8E50	
+0xDB89	0x8E53	
+0xDB8A	0x8E54	
+0xDB8B	0x8E55	
+0xDB8C	0x8E56	
+0xDB8D	0x8E57	
+0xDB8E	0x8E58	
+0xDB8F	0x8E5A	
+0xDB90	0x8E5B	
+0xDB91	0x8E5C	
+0xDB92	0x8E5D	
+0xDB93	0x8E5E	
+0xDB94	0x8E5F	
+0xDB95	0x8E60	
+0xDB96	0x8E61	
+0xDB97	0x8E62	
+0xDB98	0x8E63	
+0xDB99	0x8E64	
+0xDB9A	0x8E65	
+0xDB9B	0x8E67	
+0xDB9C	0x8E68	
+0xDB9D	0x8E6A	
+0xDB9E	0x8E6B	
+0xDB9F	0x8E6E	
+0xDBA0	0x8E71	
+0xDBA1	0x90B8	
+0xDBA2	0x90B0	
+0xDBA3	0x90CF	
+0xDBA4	0x90C5	
+0xDBA5	0x90BE	
+0xDBA6	0x90D0	
+0xDBA7	0x90C4	
+0xDBA8	0x90C7	
+0xDBA9	0x90D3	
+0xDBAA	0x90E6	
+0xDBAB	0x90E2	
+0xDBAC	0x90DC	
+0xDBAD	0x90D7	
+0xDBAE	0x90DB	
+0xDBAF	0x90EB	
+0xDBB0	0x90EF	
+0xDBB1	0x90FE	
+0xDBB2	0x9104	
+0xDBB3	0x9122	
+0xDBB4	0x911E	
+0xDBB5	0x9123	
+0xDBB6	0x9131	
+0xDBB7	0x912F	
+0xDBB8	0x9139	
+0xDBB9	0x9143	
+0xDBBA	0x9146	
+0xDBBB	0x520D	
+0xDBBC	0x5942	
+0xDBBD	0x52A2	
+0xDBBE	0x52AC	
+0xDBBF	0x52AD	
+0xDBC0	0x52BE	
+0xDBC1	0x54FF	
+0xDBC2	0x52D0	
+0xDBC3	0x52D6	
+0xDBC4	0x52F0	
+0xDBC5	0x53DF	
+0xDBC6	0x71EE	
+0xDBC7	0x77CD	
+0xDBC8	0x5EF4	
+0xDBC9	0x51F5	
+0xDBCA	0x51FC	
+0xDBCB	0x9B2F	
+0xDBCC	0x53B6	
+0xDBCD	0x5F01	
+0xDBCE	0x755A	
+0xDBCF	0x5DEF	
+0xDBD0	0x574C	
+0xDBD1	0x57A9	
+0xDBD2	0x57A1	
+0xDBD3	0x587E	
+0xDBD4	0x58BC	
+0xDBD5	0x58C5	
+0xDBD6	0x58D1	
+0xDBD7	0x5729	
+0xDBD8	0x572C	
+0xDBD9	0x572A	
+0xDBDA	0x5733	
+0xDBDB	0x5739	
+0xDBDC	0x572E	
+0xDBDD	0x572F	
+0xDBDE	0x575C	
+0xDBDF	0x573B	
+0xDBE0	0x5742	
+0xDBE1	0x5769	
+0xDBE2	0x5785	
+0xDBE3	0x576B	
+0xDBE4	0x5786	
+0xDBE5	0x577C	
+0xDBE6	0x577B	
+0xDBE7	0x5768	
+0xDBE8	0x576D	
+0xDBE9	0x5776	
+0xDBEA	0x5773	
+0xDBEB	0x57AD	
+0xDBEC	0x57A4	
+0xDBED	0x578C	
+0xDBEE	0x57B2	
+0xDBEF	0x57CF	
+0xDBF0	0x57A7	
+0xDBF1	0x57B4	
+0xDBF2	0x5793	
+0xDBF3	0x57A0	
+0xDBF4	0x57D5	
+0xDBF5	0x57D8	
+0xDBF6	0x57DA	
+0xDBF7	0x57D9	
+0xDBF8	0x57D2	
+0xDBF9	0x57B8	
+0xDBFA	0x57F4	
+0xDBFB	0x57EF	
+0xDBFC	0x57F8	
+0xDBFD	0x57E4	
+0xDBFE	0x57DD	
+0xDC40	0x8E73	
+0xDC41	0x8E75	
+0xDC42	0x8E77	
+0xDC43	0x8E78	
+0xDC44	0x8E79	
+0xDC45	0x8E7A	
+0xDC46	0x8E7B	
+0xDC47	0x8E7D	
+0xDC48	0x8E7E	
+0xDC49	0x8E80	
+0xDC4A	0x8E82	
+0xDC4B	0x8E83	
+0xDC4C	0x8E84	
+0xDC4D	0x8E86	
+0xDC4E	0x8E88	
+0xDC4F	0x8E89	
+0xDC50	0x8E8A	
+0xDC51	0x8E8B	
+0xDC52	0x8E8C	
+0xDC53	0x8E8D	
+0xDC54	0x8E8E	
+0xDC55	0x8E91	
+0xDC56	0x8E92	
+0xDC57	0x8E93	
+0xDC58	0x8E95	
+0xDC59	0x8E96	
+0xDC5A	0x8E97	
+0xDC5B	0x8E98	
+0xDC5C	0x8E99	
+0xDC5D	0x8E9A	
+0xDC5E	0x8E9B	
+0xDC5F	0x8E9D	
+0xDC60	0x8E9F	
+0xDC61	0x8EA0	
+0xDC62	0x8EA1	
+0xDC63	0x8EA2	
+0xDC64	0x8EA3	
+0xDC65	0x8EA4	
+0xDC66	0x8EA5	
+0xDC67	0x8EA6	
+0xDC68	0x8EA7	
+0xDC69	0x8EA8	
+0xDC6A	0x8EA9	
+0xDC6B	0x8EAA	
+0xDC6C	0x8EAD	
+0xDC6D	0x8EAE	
+0xDC6E	0x8EB0	
+0xDC6F	0x8EB1	
+0xDC70	0x8EB3	
+0xDC71	0x8EB4	
+0xDC72	0x8EB5	
+0xDC73	0x8EB6	
+0xDC74	0x8EB7	
+0xDC75	0x8EB8	
+0xDC76	0x8EB9	
+0xDC77	0x8EBB	
+0xDC78	0x8EBC	
+0xDC79	0x8EBD	
+0xDC7A	0x8EBE	
+0xDC7B	0x8EBF	
+0xDC7C	0x8EC0	
+0xDC7D	0x8EC1	
+0xDC7E	0x8EC2	
+0xDC80	0x8EC3	
+0xDC81	0x8EC4	
+0xDC82	0x8EC5	
+0xDC83	0x8EC6	
+0xDC84	0x8EC7	
+0xDC85	0x8EC8	
+0xDC86	0x8EC9	
+0xDC87	0x8ECA	
+0xDC88	0x8ECB	
+0xDC89	0x8ECC	
+0xDC8A	0x8ECD	
+0xDC8B	0x8ECF	
+0xDC8C	0x8ED0	
+0xDC8D	0x8ED1	
+0xDC8E	0x8ED2	
+0xDC8F	0x8ED3	
+0xDC90	0x8ED4	
+0xDC91	0x8ED5	
+0xDC92	0x8ED6	
+0xDC93	0x8ED7	
+0xDC94	0x8ED8	
+0xDC95	0x8ED9	
+0xDC96	0x8EDA	
+0xDC97	0x8EDB	
+0xDC98	0x8EDC	
+0xDC99	0x8EDD	
+0xDC9A	0x8EDE	
+0xDC9B	0x8EDF	
+0xDC9C	0x8EE0	
+0xDC9D	0x8EE1	
+0xDC9E	0x8EE2	
+0xDC9F	0x8EE3	
+0xDCA0	0x8EE4	
+0xDCA1	0x580B	
+0xDCA2	0x580D	
+0xDCA3	0x57FD	
+0xDCA4	0x57ED	
+0xDCA5	0x5800	
+0xDCA6	0x581E	
+0xDCA7	0x5819	
+0xDCA8	0x5844	
+0xDCA9	0x5820	
+0xDCAA	0x5865	
+0xDCAB	0x586C	
+0xDCAC	0x5881	
+0xDCAD	0x5889	
+0xDCAE	0x589A	
+0xDCAF	0x5880	
+0xDCB0	0x99A8	
+0xDCB1	0x9F19	
+0xDCB2	0x61FF	
+0xDCB3	0x8279	
+0xDCB4	0x827D	
+0xDCB5	0x827F	
+0xDCB6	0x828F	
+0xDCB7	0x828A	
+0xDCB8	0x82A8	
+0xDCB9	0x8284	
+0xDCBA	0x828E	
+0xDCBB	0x8291	
+0xDCBC	0x8297	
+0xDCBD	0x8299	
+0xDCBE	0x82AB	
+0xDCBF	0x82B8	
+0xDCC0	0x82BE	
+0xDCC1	0x82B0	
+0xDCC2	0x82C8	
+0xDCC3	0x82CA	
+0xDCC4	0x82E3	
+0xDCC5	0x8298	
+0xDCC6	0x82B7	
+0xDCC7	0x82AE	
+0xDCC8	0x82CB	
+0xDCC9	0x82CC	
+0xDCCA	0x82C1	
+0xDCCB	0x82A9	
+0xDCCC	0x82B4	
+0xDCCD	0x82A1	
+0xDCCE	0x82AA	
+0xDCCF	0x829F	
+0xDCD0	0x82C4	
+0xDCD1	0x82CE	
+0xDCD2	0x82A4	
+0xDCD3	0x82E1	
+0xDCD4	0x8309	
+0xDCD5	0x82F7	
+0xDCD6	0x82E4	
+0xDCD7	0x830F	
+0xDCD8	0x8307	
+0xDCD9	0x82DC	
+0xDCDA	0x82F4	
+0xDCDB	0x82D2	
+0xDCDC	0x82D8	
+0xDCDD	0x830C	
+0xDCDE	0x82FB	
+0xDCDF	0x82D3	
+0xDCE0	0x8311	
+0xDCE1	0x831A	
+0xDCE2	0x8306	
+0xDCE3	0x8314	
+0xDCE4	0x8315	
+0xDCE5	0x82E0	
+0xDCE6	0x82D5	
+0xDCE7	0x831C	
+0xDCE8	0x8351	
+0xDCE9	0x835B	
+0xDCEA	0x835C	
+0xDCEB	0x8308	
+0xDCEC	0x8392	
+0xDCED	0x833C	
+0xDCEE	0x8334	
+0xDCEF	0x8331	
+0xDCF0	0x839B	
+0xDCF1	0x835E	
+0xDCF2	0x832F	
+0xDCF3	0x834F	
+0xDCF4	0x8347	
+0xDCF5	0x8343	
+0xDCF6	0x835F	
+0xDCF7	0x8340	
+0xDCF8	0x8317	
+0xDCF9	0x8360	
+0xDCFA	0x832D	
+0xDCFB	0x833A	
+0xDCFC	0x8333	
+0xDCFD	0x8366	
+0xDCFE	0x8365	
+0xDD40	0x8EE5	
+0xDD41	0x8EE6	
+0xDD42	0x8EE7	
+0xDD43	0x8EE8	
+0xDD44	0x8EE9	
+0xDD45	0x8EEA	
+0xDD46	0x8EEB	
+0xDD47	0x8EEC	
+0xDD48	0x8EED	
+0xDD49	0x8EEE	
+0xDD4A	0x8EEF	
+0xDD4B	0x8EF0	
+0xDD4C	0x8EF1	
+0xDD4D	0x8EF2	
+0xDD4E	0x8EF3	
+0xDD4F	0x8EF4	
+0xDD50	0x8EF5	
+0xDD51	0x8EF6	
+0xDD52	0x8EF7	
+0xDD53	0x8EF8	
+0xDD54	0x8EF9	
+0xDD55	0x8EFA	
+0xDD56	0x8EFB	
+0xDD57	0x8EFC	
+0xDD58	0x8EFD	
+0xDD59	0x8EFE	
+0xDD5A	0x8EFF	
+0xDD5B	0x8F00	
+0xDD5C	0x8F01	
+0xDD5D	0x8F02	
+0xDD5E	0x8F03	
+0xDD5F	0x8F04	
+0xDD60	0x8F05	
+0xDD61	0x8F06	
+0xDD62	0x8F07	
+0xDD63	0x8F08	
+0xDD64	0x8F09	
+0xDD65	0x8F0A	
+0xDD66	0x8F0B	
+0xDD67	0x8F0C	
+0xDD68	0x8F0D	
+0xDD69	0x8F0E	
+0xDD6A	0x8F0F	
+0xDD6B	0x8F10	
+0xDD6C	0x8F11	
+0xDD6D	0x8F12	
+0xDD6E	0x8F13	
+0xDD6F	0x8F14	
+0xDD70	0x8F15	
+0xDD71	0x8F16	
+0xDD72	0x8F17	
+0xDD73	0x8F18	
+0xDD74	0x8F19	
+0xDD75	0x8F1A	
+0xDD76	0x8F1B	
+0xDD77	0x8F1C	
+0xDD78	0x8F1D	
+0xDD79	0x8F1E	
+0xDD7A	0x8F1F	
+0xDD7B	0x8F20	
+0xDD7C	0x8F21	
+0xDD7D	0x8F22	
+0xDD7E	0x8F23	
+0xDD80	0x8F24	
+0xDD81	0x8F25	
+0xDD82	0x8F26	
+0xDD83	0x8F27	
+0xDD84	0x8F28	
+0xDD85	0x8F29	
+0xDD86	0x8F2A	
+0xDD87	0x8F2B	
+0xDD88	0x8F2C	
+0xDD89	0x8F2D	
+0xDD8A	0x8F2E	
+0xDD8B	0x8F2F	
+0xDD8C	0x8F30	
+0xDD8D	0x8F31	
+0xDD8E	0x8F32	
+0xDD8F	0x8F33	
+0xDD90	0x8F34	
+0xDD91	0x8F35	
+0xDD92	0x8F36	
+0xDD93	0x8F37	
+0xDD94	0x8F38	
+0xDD95	0x8F39	
+0xDD96	0x8F3A	
+0xDD97	0x8F3B	
+0xDD98	0x8F3C	
+0xDD99	0x8F3D	
+0xDD9A	0x8F3E	
+0xDD9B	0x8F3F	
+0xDD9C	0x8F40	
+0xDD9D	0x8F41	
+0xDD9E	0x8F42	
+0xDD9F	0x8F43	
+0xDDA0	0x8F44	
+0xDDA1	0x8368	
+0xDDA2	0x831B	
+0xDDA3	0x8369	
+0xDDA4	0x836C	
+0xDDA5	0x836A	
+0xDDA6	0x836D	
+0xDDA7	0x836E	
+0xDDA8	0x83B0	
+0xDDA9	0x8378	
+0xDDAA	0x83B3	
+0xDDAB	0x83B4	
+0xDDAC	0x83A0	
+0xDDAD	0x83AA	
+0xDDAE	0x8393	
+0xDDAF	0x839C	
+0xDDB0	0x8385	
+0xDDB1	0x837C	
+0xDDB2	0x83B6	
+0xDDB3	0x83A9	
+0xDDB4	0x837D	
+0xDDB5	0x83B8	
+0xDDB6	0x837B	
+0xDDB7	0x8398	
+0xDDB8	0x839E	
+0xDDB9	0x83A8	
+0xDDBA	0x83BA	
+0xDDBB	0x83BC	
+0xDDBC	0x83C1	
+0xDDBD	0x8401	
+0xDDBE	0x83E5	
+0xDDBF	0x83D8	
+0xDDC0	0x5807	
+0xDDC1	0x8418	
+0xDDC2	0x840B	
+0xDDC3	0x83DD	
+0xDDC4	0x83FD	
+0xDDC5	0x83D6	
+0xDDC6	0x841C	
+0xDDC7	0x8438	
+0xDDC8	0x8411	
+0xDDC9	0x8406	
+0xDDCA	0x83D4	
+0xDDCB	0x83DF	
+0xDDCC	0x840F	
+0xDDCD	0x8403	
+0xDDCE	0x83F8	
+0xDDCF	0x83F9	
+0xDDD0	0x83EA	
+0xDDD1	0x83C5	
+0xDDD2	0x83C0	
+0xDDD3	0x8426	
+0xDDD4	0x83F0	
+0xDDD5	0x83E1	
+0xDDD6	0x845C	
+0xDDD7	0x8451	
+0xDDD8	0x845A	
+0xDDD9	0x8459	
+0xDDDA	0x8473	
+0xDDDB	0x8487	
+0xDDDC	0x8488	
+0xDDDD	0x847A	
+0xDDDE	0x8489	
+0xDDDF	0x8478	
+0xDDE0	0x843C	
+0xDDE1	0x8446	
+0xDDE2	0x8469	
+0xDDE3	0x8476	
+0xDDE4	0x848C	
+0xDDE5	0x848E	
+0xDDE6	0x8431	
+0xDDE7	0x846D	
+0xDDE8	0x84C1	
+0xDDE9	0x84CD	
+0xDDEA	0x84D0	
+0xDDEB	0x84E6	
+0xDDEC	0x84BD	
+0xDDED	0x84D3	
+0xDDEE	0x84CA	
+0xDDEF	0x84BF	
+0xDDF0	0x84BA	
+0xDDF1	0x84E0	
+0xDDF2	0x84A1	
+0xDDF3	0x84B9	
+0xDDF4	0x84B4	
+0xDDF5	0x8497	
+0xDDF6	0x84E5	
+0xDDF7	0x84E3	
+0xDDF8	0x850C	
+0xDDF9	0x750D	
+0xDDFA	0x8538	
+0xDDFB	0x84F0	
+0xDDFC	0x8539	
+0xDDFD	0x851F	
+0xDDFE	0x853A	
+0xDE40	0x8F45	
+0xDE41	0x8F46	
+0xDE42	0x8F47	
+0xDE43	0x8F48	
+0xDE44	0x8F49	
+0xDE45	0x8F4A	
+0xDE46	0x8F4B	
+0xDE47	0x8F4C	
+0xDE48	0x8F4D	
+0xDE49	0x8F4E	
+0xDE4A	0x8F4F	
+0xDE4B	0x8F50	
+0xDE4C	0x8F51	
+0xDE4D	0x8F52	
+0xDE4E	0x8F53	
+0xDE4F	0x8F54	
+0xDE50	0x8F55	
+0xDE51	0x8F56	
+0xDE52	0x8F57	
+0xDE53	0x8F58	
+0xDE54	0x8F59	
+0xDE55	0x8F5A	
+0xDE56	0x8F5B	
+0xDE57	0x8F5C	
+0xDE58	0x8F5D	
+0xDE59	0x8F5E	
+0xDE5A	0x8F5F	
+0xDE5B	0x8F60	
+0xDE5C	0x8F61	
+0xDE5D	0x8F62	
+0xDE5E	0x8F63	
+0xDE5F	0x8F64	
+0xDE60	0x8F65	
+0xDE61	0x8F6A	
+0xDE62	0x8F80	
+0xDE63	0x8F8C	
+0xDE64	0x8F92	
+0xDE65	0x8F9D	
+0xDE66	0x8FA0	
+0xDE67	0x8FA1	
+0xDE68	0x8FA2	
+0xDE69	0x8FA4	
+0xDE6A	0x8FA5	
+0xDE6B	0x8FA6	
+0xDE6C	0x8FA7	
+0xDE6D	0x8FAA	
+0xDE6E	0x8FAC	
+0xDE6F	0x8FAD	
+0xDE70	0x8FAE	
+0xDE71	0x8FAF	
+0xDE72	0x8FB2	
+0xDE73	0x8FB3	
+0xDE74	0x8FB4	
+0xDE75	0x8FB5	
+0xDE76	0x8FB7	
+0xDE77	0x8FB8	
+0xDE78	0x8FBA	
+0xDE79	0x8FBB	
+0xDE7A	0x8FBC	
+0xDE7B	0x8FBF	
+0xDE7C	0x8FC0	
+0xDE7D	0x8FC3	
+0xDE7E	0x8FC6	
+0xDE80	0x8FC9	
+0xDE81	0x8FCA	
+0xDE82	0x8FCB	
+0xDE83	0x8FCC	
+0xDE84	0x8FCD	
+0xDE85	0x8FCF	
+0xDE86	0x8FD2	
+0xDE87	0x8FD6	
+0xDE88	0x8FD7	
+0xDE89	0x8FDA	
+0xDE8A	0x8FE0	
+0xDE8B	0x8FE1	
+0xDE8C	0x8FE3	
+0xDE8D	0x8FE7	
+0xDE8E	0x8FEC	
+0xDE8F	0x8FEF	
+0xDE90	0x8FF1	
+0xDE91	0x8FF2	
+0xDE92	0x8FF4	
+0xDE93	0x8FF5	
+0xDE94	0x8FF6	
+0xDE95	0x8FFA	
+0xDE96	0x8FFB	
+0xDE97	0x8FFC	
+0xDE98	0x8FFE	
+0xDE99	0x8FFF	
+0xDE9A	0x9007	
+0xDE9B	0x9008	
+0xDE9C	0x900C	
+0xDE9D	0x900E	
+0xDE9E	0x9013	
+0xDE9F	0x9015	
+0xDEA0	0x9018	
+0xDEA1	0x8556	
+0xDEA2	0x853B	
+0xDEA3	0x84FF	
+0xDEA4	0x84FC	
+0xDEA5	0x8559	
+0xDEA6	0x8548	
+0xDEA7	0x8568	
+0xDEA8	0x8564	
+0xDEA9	0x855E	
+0xDEAA	0x857A	
+0xDEAB	0x77A2	
+0xDEAC	0x8543	
+0xDEAD	0x8572	
+0xDEAE	0x857B	
+0xDEAF	0x85A4	
+0xDEB0	0x85A8	
+0xDEB1	0x8587	
+0xDEB2	0x858F	
+0xDEB3	0x8579	
+0xDEB4	0x85AE	
+0xDEB5	0x859C	
+0xDEB6	0x8585	
+0xDEB7	0x85B9	
+0xDEB8	0x85B7	
+0xDEB9	0x85B0	
+0xDEBA	0x85D3	
+0xDEBB	0x85C1	
+0xDEBC	0x85DC	
+0xDEBD	0x85FF	
+0xDEBE	0x8627	
+0xDEBF	0x8605	
+0xDEC0	0x8629	
+0xDEC1	0x8616	
+0xDEC2	0x863C	
+0xDEC3	0x5EFE	
+0xDEC4	0x5F08	
+0xDEC5	0x593C	
+0xDEC6	0x5941	
+0xDEC7	0x8037	
+0xDEC8	0x5955	
+0xDEC9	0x595A	
+0xDECA	0x5958	
+0xDECB	0x530F	
+0xDECC	0x5C22	
+0xDECD	0x5C25	
+0xDECE	0x5C2C	
+0xDECF	0x5C34	
+0xDED0	0x624C	
+0xDED1	0x626A	
+0xDED2	0x629F	
+0xDED3	0x62BB	
+0xDED4	0x62CA	
+0xDED5	0x62DA	
+0xDED6	0x62D7	
+0xDED7	0x62EE	
+0xDED8	0x6322	
+0xDED9	0x62F6	
+0xDEDA	0x6339	
+0xDEDB	0x634B	
+0xDEDC	0x6343	
+0xDEDD	0x63AD	
+0xDEDE	0x63F6	
+0xDEDF	0x6371	
+0xDEE0	0x637A	
+0xDEE1	0x638E	
+0xDEE2	0x63B4	
+0xDEE3	0x636D	
+0xDEE4	0x63AC	
+0xDEE5	0x638A	
+0xDEE6	0x6369	
+0xDEE7	0x63AE	
+0xDEE8	0x63BC	
+0xDEE9	0x63F2	
+0xDEEA	0x63F8	
+0xDEEB	0x63E0	
+0xDEEC	0x63FF	
+0xDEED	0x63C4	
+0xDEEE	0x63DE	
+0xDEEF	0x63CE	
+0xDEF0	0x6452	
+0xDEF1	0x63C6	
+0xDEF2	0x63BE	
+0xDEF3	0x6445	
+0xDEF4	0x6441	
+0xDEF5	0x640B	
+0xDEF6	0x641B	
+0xDEF7	0x6420	
+0xDEF8	0x640C	
+0xDEF9	0x6426	
+0xDEFA	0x6421	
+0xDEFB	0x645E	
+0xDEFC	0x6484	
+0xDEFD	0x646D	
+0xDEFE	0x6496	
+0xDF40	0x9019	
+0xDF41	0x901C	
+0xDF42	0x9023	
+0xDF43	0x9024	
+0xDF44	0x9025	
+0xDF45	0x9027	
+0xDF46	0x9028	
+0xDF47	0x9029	
+0xDF48	0x902A	
+0xDF49	0x902B	
+0xDF4A	0x902C	
+0xDF4B	0x9030	
+0xDF4C	0x9031	
+0xDF4D	0x9032	
+0xDF4E	0x9033	
+0xDF4F	0x9034	
+0xDF50	0x9037	
+0xDF51	0x9039	
+0xDF52	0x903A	
+0xDF53	0x903D	
+0xDF54	0x903F	
+0xDF55	0x9040	
+0xDF56	0x9043	
+0xDF57	0x9045	
+0xDF58	0x9046	
+0xDF59	0x9048	
+0xDF5A	0x9049	
+0xDF5B	0x904A	
+0xDF5C	0x904B	
+0xDF5D	0x904C	
+0xDF5E	0x904E	
+0xDF5F	0x9054	
+0xDF60	0x9055	
+0xDF61	0x9056	
+0xDF62	0x9059	
+0xDF63	0x905A	
+0xDF64	0x905C	
+0xDF65	0x905D	
+0xDF66	0x905E	
+0xDF67	0x905F	
+0xDF68	0x9060	
+0xDF69	0x9061	
+0xDF6A	0x9064	
+0xDF6B	0x9066	
+0xDF6C	0x9067	
+0xDF6D	0x9069	
+0xDF6E	0x906A	
+0xDF6F	0x906B	
+0xDF70	0x906C	
+0xDF71	0x906F	
+0xDF72	0x9070	
+0xDF73	0x9071	
+0xDF74	0x9072	
+0xDF75	0x9073	
+0xDF76	0x9076	
+0xDF77	0x9077	
+0xDF78	0x9078	
+0xDF79	0x9079	
+0xDF7A	0x907A	
+0xDF7B	0x907B	
+0xDF7C	0x907C	
+0xDF7D	0x907E	
+0xDF7E	0x9081	
+0xDF80	0x9084	
+0xDF81	0x9085	
+0xDF82	0x9086	
+0xDF83	0x9087	
+0xDF84	0x9089	
+0xDF85	0x908A	
+0xDF86	0x908C	
+0xDF87	0x908D	
+0xDF88	0x908E	
+0xDF89	0x908F	
+0xDF8A	0x9090	
+0xDF8B	0x9092	
+0xDF8C	0x9094	
+0xDF8D	0x9096	
+0xDF8E	0x9098	
+0xDF8F	0x909A	
+0xDF90	0x909C	
+0xDF91	0x909E	
+0xDF92	0x909F	
+0xDF93	0x90A0	
+0xDF94	0x90A4	
+0xDF95	0x90A5	
+0xDF96	0x90A7	
+0xDF97	0x90A8	
+0xDF98	0x90A9	
+0xDF99	0x90AB	
+0xDF9A	0x90AD	
+0xDF9B	0x90B2	
+0xDF9C	0x90B7	
+0xDF9D	0x90BC	
+0xDF9E	0x90BD	
+0xDF9F	0x90BF	
+0xDFA0	0x90C0	
+0xDFA1	0x647A	
+0xDFA2	0x64B7	
+0xDFA3	0x64B8	
+0xDFA4	0x6499	
+0xDFA5	0x64BA	
+0xDFA6	0x64C0	
+0xDFA7	0x64D0	
+0xDFA8	0x64D7	
+0xDFA9	0x64E4	
+0xDFAA	0x64E2	
+0xDFAB	0x6509	
+0xDFAC	0x6525	
+0xDFAD	0x652E	
+0xDFAE	0x5F0B	
+0xDFAF	0x5FD2	
+0xDFB0	0x7519	
+0xDFB1	0x5F11	
+0xDFB2	0x535F	
+0xDFB3	0x53F1	
+0xDFB4	0x53FD	
+0xDFB5	0x53E9	
+0xDFB6	0x53E8	
+0xDFB7	0x53FB	
+0xDFB8	0x5412	
+0xDFB9	0x5416	
+0xDFBA	0x5406	
+0xDFBB	0x544B	
+0xDFBC	0x5452	
+0xDFBD	0x5453	
+0xDFBE	0x5454	
+0xDFBF	0x5456	
+0xDFC0	0x5443	
+0xDFC1	0x5421	
+0xDFC2	0x5457	
+0xDFC3	0x5459	
+0xDFC4	0x5423	
+0xDFC5	0x5432	
+0xDFC6	0x5482	
+0xDFC7	0x5494	
+0xDFC8	0x5477	
+0xDFC9	0x5471	
+0xDFCA	0x5464	
+0xDFCB	0x549A	
+0xDFCC	0x549B	
+0xDFCD	0x5484	
+0xDFCE	0x5476	
+0xDFCF	0x5466	
+0xDFD0	0x549D	
+0xDFD1	0x54D0	
+0xDFD2	0x54AD	
+0xDFD3	0x54C2	
+0xDFD4	0x54B4	
+0xDFD5	0x54D2	
+0xDFD6	0x54A7	
+0xDFD7	0x54A6	
+0xDFD8	0x54D3	
+0xDFD9	0x54D4	
+0xDFDA	0x5472	
+0xDFDB	0x54A3	
+0xDFDC	0x54D5	
+0xDFDD	0x54BB	
+0xDFDE	0x54BF	
+0xDFDF	0x54CC	
+0xDFE0	0x54D9	
+0xDFE1	0x54DA	
+0xDFE2	0x54DC	
+0xDFE3	0x54A9	
+0xDFE4	0x54AA	
+0xDFE5	0x54A4	
+0xDFE6	0x54DD	
+0xDFE7	0x54CF	
+0xDFE8	0x54DE	
+0xDFE9	0x551B	
+0xDFEA	0x54E7	
+0xDFEB	0x5520	
+0xDFEC	0x54FD	
+0xDFED	0x5514	
+0xDFEE	0x54F3	
+0xDFEF	0x5522	
+0xDFF0	0x5523	
+0xDFF1	0x550F	
+0xDFF2	0x5511	
+0xDFF3	0x5527	
+0xDFF4	0x552A	
+0xDFF5	0x5567	
+0xDFF6	0x558F	
+0xDFF7	0x55B5	
+0xDFF8	0x5549	
+0xDFF9	0x556D	
+0xDFFA	0x5541	
+0xDFFB	0x5555	
+0xDFFC	0x553F	
+0xDFFD	0x5550	
+0xDFFE	0x553C	
+0xE040	0x90C2	
+0xE041	0x90C3	
+0xE042	0x90C6	
+0xE043	0x90C8	
+0xE044	0x90C9	
+0xE045	0x90CB	
+0xE046	0x90CC	
+0xE047	0x90CD	
+0xE048	0x90D2	
+0xE049	0x90D4	
+0xE04A	0x90D5	
+0xE04B	0x90D6	
+0xE04C	0x90D8	
+0xE04D	0x90D9	
+0xE04E	0x90DA	
+0xE04F	0x90DE	
+0xE050	0x90DF	
+0xE051	0x90E0	
+0xE052	0x90E3	
+0xE053	0x90E4	
+0xE054	0x90E5	
+0xE055	0x90E9	
+0xE056	0x90EA	
+0xE057	0x90EC	
+0xE058	0x90EE	
+0xE059	0x90F0	
+0xE05A	0x90F1	
+0xE05B	0x90F2	
+0xE05C	0x90F3	
+0xE05D	0x90F5	
+0xE05E	0x90F6	
+0xE05F	0x90F7	
+0xE060	0x90F9	
+0xE061	0x90FA	
+0xE062	0x90FB	
+0xE063	0x90FC	
+0xE064	0x90FF	
+0xE065	0x9100	
+0xE066	0x9101	
+0xE067	0x9103	
+0xE068	0x9105	
+0xE069	0x9106	
+0xE06A	0x9107	
+0xE06B	0x9108	
+0xE06C	0x9109	
+0xE06D	0x910A	
+0xE06E	0x910B	
+0xE06F	0x910C	
+0xE070	0x910D	
+0xE071	0x910E	
+0xE072	0x910F	
+0xE073	0x9110	
+0xE074	0x9111	
+0xE075	0x9112	
+0xE076	0x9113	
+0xE077	0x9114	
+0xE078	0x9115	
+0xE079	0x9116	
+0xE07A	0x9117	
+0xE07B	0x9118	
+0xE07C	0x911A	
+0xE07D	0x911B	
+0xE07E	0x911C	
+0xE080	0x911D	
+0xE081	0x911F	
+0xE082	0x9120	
+0xE083	0x9121	
+0xE084	0x9124	
+0xE085	0x9125	
+0xE086	0x9126	
+0xE087	0x9127	
+0xE088	0x9128	
+0xE089	0x9129	
+0xE08A	0x912A	
+0xE08B	0x912B	
+0xE08C	0x912C	
+0xE08D	0x912D	
+0xE08E	0x912E	
+0xE08F	0x9130	
+0xE090	0x9132	
+0xE091	0x9133	
+0xE092	0x9134	
+0xE093	0x9135	
+0xE094	0x9136	
+0xE095	0x9137	
+0xE096	0x9138	
+0xE097	0x913A	
+0xE098	0x913B	
+0xE099	0x913C	
+0xE09A	0x913D	
+0xE09B	0x913E	
+0xE09C	0x913F	
+0xE09D	0x9140	
+0xE09E	0x9141	
+0xE09F	0x9142	
+0xE0A0	0x9144	
+0xE0A1	0x5537	
+0xE0A2	0x5556	
+0xE0A3	0x5575	
+0xE0A4	0x5576	
+0xE0A5	0x5577	
+0xE0A6	0x5533	
+0xE0A7	0x5530	
+0xE0A8	0x555C	
+0xE0A9	0x558B	
+0xE0AA	0x55D2	
+0xE0AB	0x5583	
+0xE0AC	0x55B1	
+0xE0AD	0x55B9	
+0xE0AE	0x5588	
+0xE0AF	0x5581	
+0xE0B0	0x559F	
+0xE0B1	0x557E	
+0xE0B2	0x55D6	
+0xE0B3	0x5591	
+0xE0B4	0x557B	
+0xE0B5	0x55DF	
+0xE0B6	0x55BD	
+0xE0B7	0x55BE	
+0xE0B8	0x5594	
+0xE0B9	0x5599	
+0xE0BA	0x55EA	
+0xE0BB	0x55F7	
+0xE0BC	0x55C9	
+0xE0BD	0x561F	
+0xE0BE	0x55D1	
+0xE0BF	0x55EB	
+0xE0C0	0x55EC	
+0xE0C1	0x55D4	
+0xE0C2	0x55E6	
+0xE0C3	0x55DD	
+0xE0C4	0x55C4	
+0xE0C5	0x55EF	
+0xE0C6	0x55E5	
+0xE0C7	0x55F2	
+0xE0C8	0x55F3	
+0xE0C9	0x55CC	
+0xE0CA	0x55CD	
+0xE0CB	0x55E8	
+0xE0CC	0x55F5	
+0xE0CD	0x55E4	
+0xE0CE	0x8F94	
+0xE0CF	0x561E	
+0xE0D0	0x5608	
+0xE0D1	0x560C	
+0xE0D2	0x5601	
+0xE0D3	0x5624	
+0xE0D4	0x5623	
+0xE0D5	0x55FE	
+0xE0D6	0x5600	
+0xE0D7	0x5627	
+0xE0D8	0x562D	
+0xE0D9	0x5658	
+0xE0DA	0x5639	
+0xE0DB	0x5657	
+0xE0DC	0x562C	
+0xE0DD	0x564D	
+0xE0DE	0x5662	
+0xE0DF	0x5659	
+0xE0E0	0x565C	
+0xE0E1	0x564C	
+0xE0E2	0x5654	
+0xE0E3	0x5686	
+0xE0E4	0x5664	
+0xE0E5	0x5671	
+0xE0E6	0x566B	
+0xE0E7	0x567B	
+0xE0E8	0x567C	
+0xE0E9	0x5685	
+0xE0EA	0x5693	
+0xE0EB	0x56AF	
+0xE0EC	0x56D4	
+0xE0ED	0x56D7	
+0xE0EE	0x56DD	
+0xE0EF	0x56E1	
+0xE0F0	0x56F5	
+0xE0F1	0x56EB	
+0xE0F2	0x56F9	
+0xE0F3	0x56FF	
+0xE0F4	0x5704	
+0xE0F5	0x570A	
+0xE0F6	0x5709	
+0xE0F7	0x571C	
+0xE0F8	0x5E0F	
+0xE0F9	0x5E19	
+0xE0FA	0x5E14	
+0xE0FB	0x5E11	
+0xE0FC	0x5E31	
+0xE0FD	0x5E3B	
+0xE0FE	0x5E3C	
+0xE140	0x9145	
+0xE141	0x9147	
+0xE142	0x9148	
+0xE143	0x9151	
+0xE144	0x9153	
+0xE145	0x9154	
+0xE146	0x9155	
+0xE147	0x9156	
+0xE148	0x9158	
+0xE149	0x9159	
+0xE14A	0x915B	
+0xE14B	0x915C	
+0xE14C	0x915F	
+0xE14D	0x9160	
+0xE14E	0x9166	
+0xE14F	0x9167	
+0xE150	0x9168	
+0xE151	0x916B	
+0xE152	0x916D	
+0xE153	0x9173	
+0xE154	0x917A	
+0xE155	0x917B	
+0xE156	0x917C	
+0xE157	0x9180	
+0xE158	0x9181	
+0xE159	0x9182	
+0xE15A	0x9183	
+0xE15B	0x9184	
+0xE15C	0x9186	
+0xE15D	0x9188	
+0xE15E	0x918A	
+0xE15F	0x918E	
+0xE160	0x918F	
+0xE161	0x9193	
+0xE162	0x9194	
+0xE163	0x9195	
+0xE164	0x9196	
+0xE165	0x9197	
+0xE166	0x9198	
+0xE167	0x9199	
+0xE168	0x919C	
+0xE169	0x919D	
+0xE16A	0x919E	
+0xE16B	0x919F	
+0xE16C	0x91A0	
+0xE16D	0x91A1	
+0xE16E	0x91A4	
+0xE16F	0x91A5	
+0xE170	0x91A6	
+0xE171	0x91A7	
+0xE172	0x91A8	
+0xE173	0x91A9	
+0xE174	0x91AB	
+0xE175	0x91AC	
+0xE176	0x91B0	
+0xE177	0x91B1	
+0xE178	0x91B2	
+0xE179	0x91B3	
+0xE17A	0x91B6	
+0xE17B	0x91B7	
+0xE17C	0x91B8	
+0xE17D	0x91B9	
+0xE17E	0x91BB	
+0xE180	0x91BC	
+0xE181	0x91BD	
+0xE182	0x91BE	
+0xE183	0x91BF	
+0xE184	0x91C0	
+0xE185	0x91C1	
+0xE186	0x91C2	
+0xE187	0x91C3	
+0xE188	0x91C4	
+0xE189	0x91C5	
+0xE18A	0x91C6	
+0xE18B	0x91C8	
+0xE18C	0x91CB	
+0xE18D	0x91D0	
+0xE18E	0x91D2	
+0xE18F	0x91D3	
+0xE190	0x91D4	
+0xE191	0x91D5	
+0xE192	0x91D6	
+0xE193	0x91D7	
+0xE194	0x91D8	
+0xE195	0x91D9	
+0xE196	0x91DA	
+0xE197	0x91DB	
+0xE198	0x91DD	
+0xE199	0x91DE	
+0xE19A	0x91DF	
+0xE19B	0x91E0	
+0xE19C	0x91E1	
+0xE19D	0x91E2	
+0xE19E	0x91E3	
+0xE19F	0x91E4	
+0xE1A0	0x91E5	
+0xE1A1	0x5E37	
+0xE1A2	0x5E44	
+0xE1A3	0x5E54	
+0xE1A4	0x5E5B	
+0xE1A5	0x5E5E	
+0xE1A6	0x5E61	
+0xE1A7	0x5C8C	
+0xE1A8	0x5C7A	
+0xE1A9	0x5C8D	
+0xE1AA	0x5C90	
+0xE1AB	0x5C96	
+0xE1AC	0x5C88	
+0xE1AD	0x5C98	
+0xE1AE	0x5C99	
+0xE1AF	0x5C91	
+0xE1B0	0x5C9A	
+0xE1B1	0x5C9C	
+0xE1B2	0x5CB5	
+0xE1B3	0x5CA2	
+0xE1B4	0x5CBD	
+0xE1B5	0x5CAC	
+0xE1B6	0x5CAB	
+0xE1B7	0x5CB1	
+0xE1B8	0x5CA3	
+0xE1B9	0x5CC1	
+0xE1BA	0x5CB7	
+0xE1BB	0x5CC4	
+0xE1BC	0x5CD2	
+0xE1BD	0x5CE4	
+0xE1BE	0x5CCB	
+0xE1BF	0x5CE5	
+0xE1C0	0x5D02	
+0xE1C1	0x5D03	
+0xE1C2	0x5D27	
+0xE1C3	0x5D26	
+0xE1C4	0x5D2E	
+0xE1C5	0x5D24	
+0xE1C6	0x5D1E	
+0xE1C7	0x5D06	
+0xE1C8	0x5D1B	
+0xE1C9	0x5D58	
+0xE1CA	0x5D3E	
+0xE1CB	0x5D34	
+0xE1CC	0x5D3D	
+0xE1CD	0x5D6C	
+0xE1CE	0x5D5B	
+0xE1CF	0x5D6F	
+0xE1D0	0x5D5D	
+0xE1D1	0x5D6B	
+0xE1D2	0x5D4B	
+0xE1D3	0x5D4A	
+0xE1D4	0x5D69	
+0xE1D5	0x5D74	
+0xE1D6	0x5D82	
+0xE1D7	0x5D99	
+0xE1D8	0x5D9D	
+0xE1D9	0x8C73	
+0xE1DA	0x5DB7	
+0xE1DB	0x5DC5	
+0xE1DC	0x5F73	
+0xE1DD	0x5F77	
+0xE1DE	0x5F82	
+0xE1DF	0x5F87	
+0xE1E0	0x5F89	
+0xE1E1	0x5F8C	
+0xE1E2	0x5F95	
+0xE1E3	0x5F99	
+0xE1E4	0x5F9C	
+0xE1E5	0x5FA8	
+0xE1E6	0x5FAD	
+0xE1E7	0x5FB5	
+0xE1E8	0x5FBC	
+0xE1E9	0x8862	
+0xE1EA	0x5F61	
+0xE1EB	0x72AD	
+0xE1EC	0x72B0	
+0xE1ED	0x72B4	
+0xE1EE	0x72B7	
+0xE1EF	0x72B8	
+0xE1F0	0x72C3	
+0xE1F1	0x72C1	
+0xE1F2	0x72CE	
+0xE1F3	0x72CD	
+0xE1F4	0x72D2	
+0xE1F5	0x72E8	
+0xE1F6	0x72EF	
+0xE1F7	0x72E9	
+0xE1F8	0x72F2	
+0xE1F9	0x72F4	
+0xE1FA	0x72F7	
+0xE1FB	0x7301	
+0xE1FC	0x72F3	
+0xE1FD	0x7303	
+0xE1FE	0x72FA	
+0xE240	0x91E6	
+0xE241	0x91E7	
+0xE242	0x91E8	
+0xE243	0x91E9	
+0xE244	0x91EA	
+0xE245	0x91EB	
+0xE246	0x91EC	
+0xE247	0x91ED	
+0xE248	0x91EE	
+0xE249	0x91EF	
+0xE24A	0x91F0	
+0xE24B	0x91F1	
+0xE24C	0x91F2	
+0xE24D	0x91F3	
+0xE24E	0x91F4	
+0xE24F	0x91F5	
+0xE250	0x91F6	
+0xE251	0x91F7	
+0xE252	0x91F8	
+0xE253	0x91F9	
+0xE254	0x91FA	
+0xE255	0x91FB	
+0xE256	0x91FC	
+0xE257	0x91FD	
+0xE258	0x91FE	
+0xE259	0x91FF	
+0xE25A	0x9200	
+0xE25B	0x9201	
+0xE25C	0x9202	
+0xE25D	0x9203	
+0xE25E	0x9204	
+0xE25F	0x9205	
+0xE260	0x9206	
+0xE261	0x9207	
+0xE262	0x9208	
+0xE263	0x9209	
+0xE264	0x920A	
+0xE265	0x920B	
+0xE266	0x920C	
+0xE267	0x920D	
+0xE268	0x920E	
+0xE269	0x920F	
+0xE26A	0x9210	
+0xE26B	0x9211	
+0xE26C	0x9212	
+0xE26D	0x9213	
+0xE26E	0x9214	
+0xE26F	0x9215	
+0xE270	0x9216	
+0xE271	0x9217	
+0xE272	0x9218	
+0xE273	0x9219	
+0xE274	0x921A	
+0xE275	0x921B	
+0xE276	0x921C	
+0xE277	0x921D	
+0xE278	0x921E	
+0xE279	0x921F	
+0xE27A	0x9220	
+0xE27B	0x9221	
+0xE27C	0x9222	
+0xE27D	0x9223	
+0xE27E	0x9224	
+0xE280	0x9225	
+0xE281	0x9226	
+0xE282	0x9227	
+0xE283	0x9228	
+0xE284	0x9229	
+0xE285	0x922A	
+0xE286	0x922B	
+0xE287	0x922C	
+0xE288	0x922D	
+0xE289	0x922E	
+0xE28A	0x922F	
+0xE28B	0x9230	
+0xE28C	0x9231	
+0xE28D	0x9232	
+0xE28E	0x9233	
+0xE28F	0x9234	
+0xE290	0x9235	
+0xE291	0x9236	
+0xE292	0x9237	
+0xE293	0x9238	
+0xE294	0x9239	
+0xE295	0x923A	
+0xE296	0x923B	
+0xE297	0x923C	
+0xE298	0x923D	
+0xE299	0x923E	
+0xE29A	0x923F	
+0xE29B	0x9240	
+0xE29C	0x9241	
+0xE29D	0x9242	
+0xE29E	0x9243	
+0xE29F	0x9244	
+0xE2A0	0x9245	
+0xE2A1	0x72FB	
+0xE2A2	0x7317	
+0xE2A3	0x7313	
+0xE2A4	0x7321	
+0xE2A5	0x730A	
+0xE2A6	0x731E	
+0xE2A7	0x731D	
+0xE2A8	0x7315	
+0xE2A9	0x7322	
+0xE2AA	0x7339	
+0xE2AB	0x7325	
+0xE2AC	0x732C	
+0xE2AD	0x7338	
+0xE2AE	0x7331	
+0xE2AF	0x7350	
+0xE2B0	0x734D	
+0xE2B1	0x7357	
+0xE2B2	0x7360	
+0xE2B3	0x736C	
+0xE2B4	0x736F	
+0xE2B5	0x737E	
+0xE2B6	0x821B	
+0xE2B7	0x5925	
+0xE2B8	0x98E7	
+0xE2B9	0x5924	
+0xE2BA	0x5902	
+0xE2BB	0x9963	
+0xE2BC	0x9967	
+0xE2BD	0x9968	
+0xE2BE	0x9969	
+0xE2BF	0x996A	
+0xE2C0	0x996B	
+0xE2C1	0x996C	
+0xE2C2	0x9974	
+0xE2C3	0x9977	
+0xE2C4	0x997D	
+0xE2C5	0x9980	
+0xE2C6	0x9984	
+0xE2C7	0x9987	
+0xE2C8	0x998A	
+0xE2C9	0x998D	
+0xE2CA	0x9990	
+0xE2CB	0x9991	
+0xE2CC	0x9993	
+0xE2CD	0x9994	
+0xE2CE	0x9995	
+0xE2CF	0x5E80	
+0xE2D0	0x5E91	
+0xE2D1	0x5E8B	
+0xE2D2	0x5E96	
+0xE2D3	0x5EA5	
+0xE2D4	0x5EA0	
+0xE2D5	0x5EB9	
+0xE2D6	0x5EB5	
+0xE2D7	0x5EBE	
+0xE2D8	0x5EB3	
+0xE2D9	0x8D53	
+0xE2DA	0x5ED2	
+0xE2DB	0x5ED1	
+0xE2DC	0x5EDB	
+0xE2DD	0x5EE8	
+0xE2DE	0x5EEA	
+0xE2DF	0x81BA	
+0xE2E0	0x5FC4	
+0xE2E1	0x5FC9	
+0xE2E2	0x5FD6	
+0xE2E3	0x5FCF	
+0xE2E4	0x6003	
+0xE2E5	0x5FEE	
+0xE2E6	0x6004	
+0xE2E7	0x5FE1	
+0xE2E8	0x5FE4	
+0xE2E9	0x5FFE	
+0xE2EA	0x6005	
+0xE2EB	0x6006	
+0xE2EC	0x5FEA	
+0xE2ED	0x5FED	
+0xE2EE	0x5FF8	
+0xE2EF	0x6019	
+0xE2F0	0x6035	
+0xE2F1	0x6026	
+0xE2F2	0x601B	
+0xE2F3	0x600F	
+0xE2F4	0x600D	
+0xE2F5	0x6029	
+0xE2F6	0x602B	
+0xE2F7	0x600A	
+0xE2F8	0x603F	
+0xE2F9	0x6021	
+0xE2FA	0x6078	
+0xE2FB	0x6079	
+0xE2FC	0x607B	
+0xE2FD	0x607A	
+0xE2FE	0x6042	
+0xE340	0x9246	
+0xE341	0x9247	
+0xE342	0x9248	
+0xE343	0x9249	
+0xE344	0x924A	
+0xE345	0x924B	
+0xE346	0x924C	
+0xE347	0x924D	
+0xE348	0x924E	
+0xE349	0x924F	
+0xE34A	0x9250	
+0xE34B	0x9251	
+0xE34C	0x9252	
+0xE34D	0x9253	
+0xE34E	0x9254	
+0xE34F	0x9255	
+0xE350	0x9256	
+0xE351	0x9257	
+0xE352	0x9258	
+0xE353	0x9259	
+0xE354	0x925A	
+0xE355	0x925B	
+0xE356	0x925C	
+0xE357	0x925D	
+0xE358	0x925E	
+0xE359	0x925F	
+0xE35A	0x9260	
+0xE35B	0x9261	
+0xE35C	0x9262	
+0xE35D	0x9263	
+0xE35E	0x9264	
+0xE35F	0x9265	
+0xE360	0x9266	
+0xE361	0x9267	
+0xE362	0x9268	
+0xE363	0x9269	
+0xE364	0x926A	
+0xE365	0x926B	
+0xE366	0x926C	
+0xE367	0x926D	
+0xE368	0x926E	
+0xE369	0x926F	
+0xE36A	0x9270	
+0xE36B	0x9271	
+0xE36C	0x9272	
+0xE36D	0x9273	
+0xE36E	0x9275	
+0xE36F	0x9276	
+0xE370	0x9277	
+0xE371	0x9278	
+0xE372	0x9279	
+0xE373	0x927A	
+0xE374	0x927B	
+0xE375	0x927C	
+0xE376	0x927D	
+0xE377	0x927E	
+0xE378	0x927F	
+0xE379	0x9280	
+0xE37A	0x9281	
+0xE37B	0x9282	
+0xE37C	0x9283	
+0xE37D	0x9284	
+0xE37E	0x9285	
+0xE380	0x9286	
+0xE381	0x9287	
+0xE382	0x9288	
+0xE383	0x9289	
+0xE384	0x928A	
+0xE385	0x928B	
+0xE386	0x928C	
+0xE387	0x928D	
+0xE388	0x928F	
+0xE389	0x9290	
+0xE38A	0x9291	
+0xE38B	0x9292	
+0xE38C	0x9293	
+0xE38D	0x9294	
+0xE38E	0x9295	
+0xE38F	0x9296	
+0xE390	0x9297	
+0xE391	0x9298	
+0xE392	0x9299	
+0xE393	0x929A	
+0xE394	0x929B	
+0xE395	0x929C	
+0xE396	0x929D	
+0xE397	0x929E	
+0xE398	0x929F	
+0xE399	0x92A0	
+0xE39A	0x92A1	
+0xE39B	0x92A2	
+0xE39C	0x92A3	
+0xE39D	0x92A4	
+0xE39E	0x92A5	
+0xE39F	0x92A6	
+0xE3A0	0x92A7	
+0xE3A1	0x606A	
+0xE3A2	0x607D	
+0xE3A3	0x6096	
+0xE3A4	0x609A	
+0xE3A5	0x60AD	
+0xE3A6	0x609D	
+0xE3A7	0x6083	
+0xE3A8	0x6092	
+0xE3A9	0x608C	
+0xE3AA	0x609B	
+0xE3AB	0x60EC	
+0xE3AC	0x60BB	
+0xE3AD	0x60B1	
+0xE3AE	0x60DD	
+0xE3AF	0x60D8	
+0xE3B0	0x60C6	
+0xE3B1	0x60DA	
+0xE3B2	0x60B4	
+0xE3B3	0x6120	
+0xE3B4	0x6126	
+0xE3B5	0x6115	
+0xE3B6	0x6123	
+0xE3B7	0x60F4	
+0xE3B8	0x6100	
+0xE3B9	0x610E	
+0xE3BA	0x612B	
+0xE3BB	0x614A	
+0xE3BC	0x6175	
+0xE3BD	0x61AC	
+0xE3BE	0x6194	
+0xE3BF	0x61A7	
+0xE3C0	0x61B7	
+0xE3C1	0x61D4	
+0xE3C2	0x61F5	
+0xE3C3	0x5FDD	
+0xE3C4	0x96B3	
+0xE3C5	0x95E9	
+0xE3C6	0x95EB	
+0xE3C7	0x95F1	
+0xE3C8	0x95F3	
+0xE3C9	0x95F5	
+0xE3CA	0x95F6	
+0xE3CB	0x95FC	
+0xE3CC	0x95FE	
+0xE3CD	0x9603	
+0xE3CE	0x9604	
+0xE3CF	0x9606	
+0xE3D0	0x9608	
+0xE3D1	0x960A	
+0xE3D2	0x960B	
+0xE3D3	0x960C	
+0xE3D4	0x960D	
+0xE3D5	0x960F	
+0xE3D6	0x9612	
+0xE3D7	0x9615	
+0xE3D8	0x9616	
+0xE3D9	0x9617	
+0xE3DA	0x9619	
+0xE3DB	0x961A	
+0xE3DC	0x4E2C	
+0xE3DD	0x723F	
+0xE3DE	0x6215	
+0xE3DF	0x6C35	
+0xE3E0	0x6C54	
+0xE3E1	0x6C5C	
+0xE3E2	0x6C4A	
+0xE3E3	0x6CA3	
+0xE3E4	0x6C85	
+0xE3E5	0x6C90	
+0xE3E6	0x6C94	
+0xE3E7	0x6C8C	
+0xE3E8	0x6C68	
+0xE3E9	0x6C69	
+0xE3EA	0x6C74	
+0xE3EB	0x6C76	
+0xE3EC	0x6C86	
+0xE3ED	0x6CA9	
+0xE3EE	0x6CD0	
+0xE3EF	0x6CD4	
+0xE3F0	0x6CAD	
+0xE3F1	0x6CF7	
+0xE3F2	0x6CF8	
+0xE3F3	0x6CF1	
+0xE3F4	0x6CD7	
+0xE3F5	0x6CB2	
+0xE3F6	0x6CE0	
+0xE3F7	0x6CD6	
+0xE3F8	0x6CFA	
+0xE3F9	0x6CEB	
+0xE3FA	0x6CEE	
+0xE3FB	0x6CB1	
+0xE3FC	0x6CD3	
+0xE3FD	0x6CEF	
+0xE3FE	0x6CFE	
+0xE440	0x92A8	
+0xE441	0x92A9	
+0xE442	0x92AA	
+0xE443	0x92AB	
+0xE444	0x92AC	
+0xE445	0x92AD	
+0xE446	0x92AF	
+0xE447	0x92B0	
+0xE448	0x92B1	
+0xE449	0x92B2	
+0xE44A	0x92B3	
+0xE44B	0x92B4	
+0xE44C	0x92B5	
+0xE44D	0x92B6	
+0xE44E	0x92B7	
+0xE44F	0x92B8	
+0xE450	0x92B9	
+0xE451	0x92BA	
+0xE452	0x92BB	
+0xE453	0x92BC	
+0xE454	0x92BD	
+0xE455	0x92BE	
+0xE456	0x92BF	
+0xE457	0x92C0	
+0xE458	0x92C1	
+0xE459	0x92C2	
+0xE45A	0x92C3	
+0xE45B	0x92C4	
+0xE45C	0x92C5	
+0xE45D	0x92C6	
+0xE45E	0x92C7	
+0xE45F	0x92C9	
+0xE460	0x92CA	
+0xE461	0x92CB	
+0xE462	0x92CC	
+0xE463	0x92CD	
+0xE464	0x92CE	
+0xE465	0x92CF	
+0xE466	0x92D0	
+0xE467	0x92D1	
+0xE468	0x92D2	
+0xE469	0x92D3	
+0xE46A	0x92D4	
+0xE46B	0x92D5	
+0xE46C	0x92D6	
+0xE46D	0x92D7	
+0xE46E	0x92D8	
+0xE46F	0x92D9	
+0xE470	0x92DA	
+0xE471	0x92DB	
+0xE472	0x92DC	
+0xE473	0x92DD	
+0xE474	0x92DE	
+0xE475	0x92DF	
+0xE476	0x92E0	
+0xE477	0x92E1	
+0xE478	0x92E2	
+0xE479	0x92E3	
+0xE47A	0x92E4	
+0xE47B	0x92E5	
+0xE47C	0x92E6	
+0xE47D	0x92E7	
+0xE47E	0x92E8	
+0xE480	0x92E9	
+0xE481	0x92EA	
+0xE482	0x92EB	
+0xE483	0x92EC	
+0xE484	0x92ED	
+0xE485	0x92EE	
+0xE486	0x92EF	
+0xE487	0x92F0	
+0xE488	0x92F1	
+0xE489	0x92F2	
+0xE48A	0x92F3	
+0xE48B	0x92F4	
+0xE48C	0x92F5	
+0xE48D	0x92F6	
+0xE48E	0x92F7	
+0xE48F	0x92F8	
+0xE490	0x92F9	
+0xE491	0x92FA	
+0xE492	0x92FB	
+0xE493	0x92FC	
+0xE494	0x92FD	
+0xE495	0x92FE	
+0xE496	0x92FF	
+0xE497	0x9300	
+0xE498	0x9301	
+0xE499	0x9302	
+0xE49A	0x9303	
+0xE49B	0x9304	
+0xE49C	0x9305	
+0xE49D	0x9306	
+0xE49E	0x9307	
+0xE49F	0x9308	
+0xE4A0	0x9309	
+0xE4A1	0x6D39	
+0xE4A2	0x6D27	
+0xE4A3	0x6D0C	
+0xE4A4	0x6D43	
+0xE4A5	0x6D48	
+0xE4A6	0x6D07	
+0xE4A7	0x6D04	
+0xE4A8	0x6D19	
+0xE4A9	0x6D0E	
+0xE4AA	0x6D2B	
+0xE4AB	0x6D4D	
+0xE4AC	0x6D2E	
+0xE4AD	0x6D35	
+0xE4AE	0x6D1A	
+0xE4AF	0x6D4F	
+0xE4B0	0x6D52	
+0xE4B1	0x6D54	
+0xE4B2	0x6D33	
+0xE4B3	0x6D91	
+0xE4B4	0x6D6F	
+0xE4B5	0x6D9E	
+0xE4B6	0x6DA0	
+0xE4B7	0x6D5E	
+0xE4B8	0x6D93	
+0xE4B9	0x6D94	
+0xE4BA	0x6D5C	
+0xE4BB	0x6D60	
+0xE4BC	0x6D7C	
+0xE4BD	0x6D63	
+0xE4BE	0x6E1A	
+0xE4BF	0x6DC7	
+0xE4C0	0x6DC5	
+0xE4C1	0x6DDE	
+0xE4C2	0x6E0E	
+0xE4C3	0x6DBF	
+0xE4C4	0x6DE0	
+0xE4C5	0x6E11	
+0xE4C6	0x6DE6	
+0xE4C7	0x6DDD	
+0xE4C8	0x6DD9	
+0xE4C9	0x6E16	
+0xE4CA	0x6DAB	
+0xE4CB	0x6E0C	
+0xE4CC	0x6DAE	
+0xE4CD	0x6E2B	
+0xE4CE	0x6E6E	
+0xE4CF	0x6E4E	
+0xE4D0	0x6E6B	
+0xE4D1	0x6EB2	
+0xE4D2	0x6E5F	
+0xE4D3	0x6E86	
+0xE4D4	0x6E53	
+0xE4D5	0x6E54	
+0xE4D6	0x6E32	
+0xE4D7	0x6E25	
+0xE4D8	0x6E44	
+0xE4D9	0x6EDF	
+0xE4DA	0x6EB1	
+0xE4DB	0x6E98	
+0xE4DC	0x6EE0	
+0xE4DD	0x6F2D	
+0xE4DE	0x6EE2	
+0xE4DF	0x6EA5	
+0xE4E0	0x6EA7	
+0xE4E1	0x6EBD	
+0xE4E2	0x6EBB	
+0xE4E3	0x6EB7	
+0xE4E4	0x6ED7	
+0xE4E5	0x6EB4	
+0xE4E6	0x6ECF	
+0xE4E7	0x6E8F	
+0xE4E8	0x6EC2	
+0xE4E9	0x6E9F	
+0xE4EA	0x6F62	
+0xE4EB	0x6F46	
+0xE4EC	0x6F47	
+0xE4ED	0x6F24	
+0xE4EE	0x6F15	
+0xE4EF	0x6EF9	
+0xE4F0	0x6F2F	
+0xE4F1	0x6F36	
+0xE4F2	0x6F4B	
+0xE4F3	0x6F74	
+0xE4F4	0x6F2A	
+0xE4F5	0x6F09	
+0xE4F6	0x6F29	
+0xE4F7	0x6F89	
+0xE4F8	0x6F8D	
+0xE4F9	0x6F8C	
+0xE4FA	0x6F78	
+0xE4FB	0x6F72	
+0xE4FC	0x6F7C	
+0xE4FD	0x6F7A	
+0xE4FE	0x6FD1	
+0xE540	0x930A	
+0xE541	0x930B	
+0xE542	0x930C	
+0xE543	0x930D	
+0xE544	0x930E	
+0xE545	0x930F	
+0xE546	0x9310	
+0xE547	0x9311	
+0xE548	0x9312	
+0xE549	0x9313	
+0xE54A	0x9314	
+0xE54B	0x9315	
+0xE54C	0x9316	
+0xE54D	0x9317	
+0xE54E	0x9318	
+0xE54F	0x9319	
+0xE550	0x931A	
+0xE551	0x931B	
+0xE552	0x931C	
+0xE553	0x931D	
+0xE554	0x931E	
+0xE555	0x931F	
+0xE556	0x9320	
+0xE557	0x9321	
+0xE558	0x9322	
+0xE559	0x9323	
+0xE55A	0x9324	
+0xE55B	0x9325	
+0xE55C	0x9326	
+0xE55D	0x9327	
+0xE55E	0x9328	
+0xE55F	0x9329	
+0xE560	0x932A	
+0xE561	0x932B	
+0xE562	0x932C	
+0xE563	0x932D	
+0xE564	0x932E	
+0xE565	0x932F	
+0xE566	0x9330	
+0xE567	0x9331	
+0xE568	0x9332	
+0xE569	0x9333	
+0xE56A	0x9334	
+0xE56B	0x9335	
+0xE56C	0x9336	
+0xE56D	0x9337	
+0xE56E	0x9338	
+0xE56F	0x9339	
+0xE570	0x933A	
+0xE571	0x933B	
+0xE572	0x933C	
+0xE573	0x933D	
+0xE574	0x933F	
+0xE575	0x9340	
+0xE576	0x9341	
+0xE577	0x9342	
+0xE578	0x9343	
+0xE579	0x9344	
+0xE57A	0x9345	
+0xE57B	0x9346	
+0xE57C	0x9347	
+0xE57D	0x9348	
+0xE57E	0x9349	
+0xE580	0x934A	
+0xE581	0x934B	
+0xE582	0x934C	
+0xE583	0x934D	
+0xE584	0x934E	
+0xE585	0x934F	
+0xE586	0x9350	
+0xE587	0x9351	
+0xE588	0x9352	
+0xE589	0x9353	
+0xE58A	0x9354	
+0xE58B	0x9355	
+0xE58C	0x9356	
+0xE58D	0x9357	
+0xE58E	0x9358	
+0xE58F	0x9359	
+0xE590	0x935A	
+0xE591	0x935B	
+0xE592	0x935C	
+0xE593	0x935D	
+0xE594	0x935E	
+0xE595	0x935F	
+0xE596	0x9360	
+0xE597	0x9361	
+0xE598	0x9362	
+0xE599	0x9363	
+0xE59A	0x9364	
+0xE59B	0x9365	
+0xE59C	0x9366	
+0xE59D	0x9367	
+0xE59E	0x9368	
+0xE59F	0x9369	
+0xE5A0	0x936B	
+0xE5A1	0x6FC9	
+0xE5A2	0x6FA7	
+0xE5A3	0x6FB9	
+0xE5A4	0x6FB6	
+0xE5A5	0x6FC2	
+0xE5A6	0x6FE1	
+0xE5A7	0x6FEE	
+0xE5A8	0x6FDE	
+0xE5A9	0x6FE0	
+0xE5AA	0x6FEF	
+0xE5AB	0x701A	
+0xE5AC	0x7023	
+0xE5AD	0x701B	
+0xE5AE	0x7039	
+0xE5AF	0x7035	
+0xE5B0	0x704F	
+0xE5B1	0x705E	
+0xE5B2	0x5B80	
+0xE5B3	0x5B84	
+0xE5B4	0x5B95	
+0xE5B5	0x5B93	
+0xE5B6	0x5BA5	
+0xE5B7	0x5BB8	
+0xE5B8	0x752F	
+0xE5B9	0x9A9E	
+0xE5BA	0x6434	
+0xE5BB	0x5BE4	
+0xE5BC	0x5BEE	
+0xE5BD	0x8930	
+0xE5BE	0x5BF0	
+0xE5BF	0x8E47	
+0xE5C0	0x8B07	
+0xE5C1	0x8FB6	
+0xE5C2	0x8FD3	
+0xE5C3	0x8FD5	
+0xE5C4	0x8FE5	
+0xE5C5	0x8FEE	
+0xE5C6	0x8FE4	
+0xE5C7	0x8FE9	
+0xE5C8	0x8FE6	
+0xE5C9	0x8FF3	
+0xE5CA	0x8FE8	
+0xE5CB	0x9005	
+0xE5CC	0x9004	
+0xE5CD	0x900B	
+0xE5CE	0x9026	
+0xE5CF	0x9011	
+0xE5D0	0x900D	
+0xE5D1	0x9016	
+0xE5D2	0x9021	
+0xE5D3	0x9035	
+0xE5D4	0x9036	
+0xE5D5	0x902D	
+0xE5D6	0x902F	
+0xE5D7	0x9044	
+0xE5D8	0x9051	
+0xE5D9	0x9052	
+0xE5DA	0x9050	
+0xE5DB	0x9068	
+0xE5DC	0x9058	
+0xE5DD	0x9062	
+0xE5DE	0x905B	
+0xE5DF	0x66B9	
+0xE5E0	0x9074	
+0xE5E1	0x907D	
+0xE5E2	0x9082	
+0xE5E3	0x9088	
+0xE5E4	0x9083	
+0xE5E5	0x908B	
+0xE5E6	0x5F50	
+0xE5E7	0x5F57	
+0xE5E8	0x5F56	
+0xE5E9	0x5F58	
+0xE5EA	0x5C3B	
+0xE5EB	0x54AB	
+0xE5EC	0x5C50	
+0xE5ED	0x5C59	
+0xE5EE	0x5B71	
+0xE5EF	0x5C63	
+0xE5F0	0x5C66	
+0xE5F1	0x7FBC	
+0xE5F2	0x5F2A	
+0xE5F3	0x5F29	
+0xE5F4	0x5F2D	
+0xE5F5	0x8274	
+0xE5F6	0x5F3C	
+0xE5F7	0x9B3B	
+0xE5F8	0x5C6E	
+0xE5F9	0x5981	
+0xE5FA	0x5983	
+0xE5FB	0x598D	
+0xE5FC	0x59A9	
+0xE5FD	0x59AA	
+0xE5FE	0x59A3	
+0xE640	0x936C	
+0xE641	0x936D	
+0xE642	0x936E	
+0xE643	0x936F	
+0xE644	0x9370	
+0xE645	0x9371	
+0xE646	0x9372	
+0xE647	0x9373	
+0xE648	0x9374	
+0xE649	0x9375	
+0xE64A	0x9376	
+0xE64B	0x9377	
+0xE64C	0x9378	
+0xE64D	0x9379	
+0xE64E	0x937A	
+0xE64F	0x937B	
+0xE650	0x937C	
+0xE651	0x937D	
+0xE652	0x937E	
+0xE653	0x937F	
+0xE654	0x9380	
+0xE655	0x9381	
+0xE656	0x9382	
+0xE657	0x9383	
+0xE658	0x9384	
+0xE659	0x9385	
+0xE65A	0x9386	
+0xE65B	0x9387	
+0xE65C	0x9388	
+0xE65D	0x9389	
+0xE65E	0x938A	
+0xE65F	0x938B	
+0xE660	0x938C	
+0xE661	0x938D	
+0xE662	0x938E	
+0xE663	0x9390	
+0xE664	0x9391	
+0xE665	0x9392	
+0xE666	0x9393	
+0xE667	0x9394	
+0xE668	0x9395	
+0xE669	0x9396	
+0xE66A	0x9397	
+0xE66B	0x9398	
+0xE66C	0x9399	
+0xE66D	0x939A	
+0xE66E	0x939B	
+0xE66F	0x939C	
+0xE670	0x939D	
+0xE671	0x939E	
+0xE672	0x939F	
+0xE673	0x93A0	
+0xE674	0x93A1	
+0xE675	0x93A2	
+0xE676	0x93A3	
+0xE677	0x93A4	
+0xE678	0x93A5	
+0xE679	0x93A6	
+0xE67A	0x93A7	
+0xE67B	0x93A8	
+0xE67C	0x93A9	
+0xE67D	0x93AA	
+0xE67E	0x93AB	
+0xE680	0x93AC	
+0xE681	0x93AD	
+0xE682	0x93AE	
+0xE683	0x93AF	
+0xE684	0x93B0	
+0xE685	0x93B1	
+0xE686	0x93B2	
+0xE687	0x93B3	
+0xE688	0x93B4	
+0xE689	0x93B5	
+0xE68A	0x93B6	
+0xE68B	0x93B7	
+0xE68C	0x93B8	
+0xE68D	0x93B9	
+0xE68E	0x93BA	
+0xE68F	0x93BB	
+0xE690	0x93BC	
+0xE691	0x93BD	
+0xE692	0x93BE	
+0xE693	0x93BF	
+0xE694	0x93C0	
+0xE695	0x93C1	
+0xE696	0x93C2	
+0xE697	0x93C3	
+0xE698	0x93C4	
+0xE699	0x93C5	
+0xE69A	0x93C6	
+0xE69B	0x93C7	
+0xE69C	0x93C8	
+0xE69D	0x93C9	
+0xE69E	0x93CB	
+0xE69F	0x93CC	
+0xE6A0	0x93CD	
+0xE6A1	0x5997	
+0xE6A2	0x59CA	
+0xE6A3	0x59AB	
+0xE6A4	0x599E	
+0xE6A5	0x59A4	
+0xE6A6	0x59D2	
+0xE6A7	0x59B2	
+0xE6A8	0x59AF	
+0xE6A9	0x59D7	
+0xE6AA	0x59BE	
+0xE6AB	0x5A05	
+0xE6AC	0x5A06	
+0xE6AD	0x59DD	
+0xE6AE	0x5A08	
+0xE6AF	0x59E3	
+0xE6B0	0x59D8	
+0xE6B1	0x59F9	
+0xE6B2	0x5A0C	
+0xE6B3	0x5A09	
+0xE6B4	0x5A32	
+0xE6B5	0x5A34	
+0xE6B6	0x5A11	
+0xE6B7	0x5A23	
+0xE6B8	0x5A13	
+0xE6B9	0x5A40	
+0xE6BA	0x5A67	
+0xE6BB	0x5A4A	
+0xE6BC	0x5A55	
+0xE6BD	0x5A3C	
+0xE6BE	0x5A62	
+0xE6BF	0x5A75	
+0xE6C0	0x80EC	
+0xE6C1	0x5AAA	
+0xE6C2	0x5A9B	
+0xE6C3	0x5A77	
+0xE6C4	0x5A7A	
+0xE6C5	0x5ABE	
+0xE6C6	0x5AEB	
+0xE6C7	0x5AB2	
+0xE6C8	0x5AD2	
+0xE6C9	0x5AD4	
+0xE6CA	0x5AB8	
+0xE6CB	0x5AE0	
+0xE6CC	0x5AE3	
+0xE6CD	0x5AF1	
+0xE6CE	0x5AD6	
+0xE6CF	0x5AE6	
+0xE6D0	0x5AD8	
+0xE6D1	0x5ADC	
+0xE6D2	0x5B09	
+0xE6D3	0x5B17	
+0xE6D4	0x5B16	
+0xE6D5	0x5B32	
+0xE6D6	0x5B37	
+0xE6D7	0x5B40	
+0xE6D8	0x5C15	
+0xE6D9	0x5C1C	
+0xE6DA	0x5B5A	
+0xE6DB	0x5B65	
+0xE6DC	0x5B73	
+0xE6DD	0x5B51	
+0xE6DE	0x5B53	
+0xE6DF	0x5B62	
+0xE6E0	0x9A75	
+0xE6E1	0x9A77	
+0xE6E2	0x9A78	
+0xE6E3	0x9A7A	
+0xE6E4	0x9A7F	
+0xE6E5	0x9A7D	
+0xE6E6	0x9A80	
+0xE6E7	0x9A81	
+0xE6E8	0x9A85	
+0xE6E9	0x9A88	
+0xE6EA	0x9A8A	
+0xE6EB	0x9A90	
+0xE6EC	0x9A92	
+0xE6ED	0x9A93	
+0xE6EE	0x9A96	
+0xE6EF	0x9A98	
+0xE6F0	0x9A9B	
+0xE6F1	0x9A9C	
+0xE6F2	0x9A9D	
+0xE6F3	0x9A9F	
+0xE6F4	0x9AA0	
+0xE6F5	0x9AA2	
+0xE6F6	0x9AA3	
+0xE6F7	0x9AA5	
+0xE6F8	0x9AA7	
+0xE6F9	0x7E9F	
+0xE6FA	0x7EA1	
+0xE6FB	0x7EA3	
+0xE6FC	0x7EA5	
+0xE6FD	0x7EA8	
+0xE6FE	0x7EA9	
+0xE740	0x93CE	
+0xE741	0x93CF	
+0xE742	0x93D0	
+0xE743	0x93D1	
+0xE744	0x93D2	
+0xE745	0x93D3	
+0xE746	0x93D4	
+0xE747	0x93D5	
+0xE748	0x93D7	
+0xE749	0x93D8	
+0xE74A	0x93D9	
+0xE74B	0x93DA	
+0xE74C	0x93DB	
+0xE74D	0x93DC	
+0xE74E	0x93DD	
+0xE74F	0x93DE	
+0xE750	0x93DF	
+0xE751	0x93E0	
+0xE752	0x93E1	
+0xE753	0x93E2	
+0xE754	0x93E3	
+0xE755	0x93E4	
+0xE756	0x93E5	
+0xE757	0x93E6	
+0xE758	0x93E7	
+0xE759	0x93E8	
+0xE75A	0x93E9	
+0xE75B	0x93EA	
+0xE75C	0x93EB	
+0xE75D	0x93EC	
+0xE75E	0x93ED	
+0xE75F	0x93EE	
+0xE760	0x93EF	
+0xE761	0x93F0	
+0xE762	0x93F1	
+0xE763	0x93F2	
+0xE764	0x93F3	
+0xE765	0x93F4	
+0xE766	0x93F5	
+0xE767	0x93F6	
+0xE768	0x93F7	
+0xE769	0x93F8	
+0xE76A	0x93F9	
+0xE76B	0x93FA	
+0xE76C	0x93FB	
+0xE76D	0x93FC	
+0xE76E	0x93FD	
+0xE76F	0x93FE	
+0xE770	0x93FF	
+0xE771	0x9400	
+0xE772	0x9401	
+0xE773	0x9402	
+0xE774	0x9403	
+0xE775	0x9404	
+0xE776	0x9405	
+0xE777	0x9406	
+0xE778	0x9407	
+0xE779	0x9408	
+0xE77A	0x9409	
+0xE77B	0x940A	
+0xE77C	0x940B	
+0xE77D	0x940C	
+0xE77E	0x940D	
+0xE780	0x940E	
+0xE781	0x940F	
+0xE782	0x9410	
+0xE783	0x9411	
+0xE784	0x9412	
+0xE785	0x9413	
+0xE786	0x9414	
+0xE787	0x9415	
+0xE788	0x9416	
+0xE789	0x9417	
+0xE78A	0x9418	
+0xE78B	0x9419	
+0xE78C	0x941A	
+0xE78D	0x941B	
+0xE78E	0x941C	
+0xE78F	0x941D	
+0xE790	0x941E	
+0xE791	0x941F	
+0xE792	0x9420	
+0xE793	0x9421	
+0xE794	0x9422	
+0xE795	0x9423	
+0xE796	0x9424	
+0xE797	0x9425	
+0xE798	0x9426	
+0xE799	0x9427	
+0xE79A	0x9428	
+0xE79B	0x9429	
+0xE79C	0x942A	
+0xE79D	0x942B	
+0xE79E	0x942C	
+0xE79F	0x942D	
+0xE7A0	0x942E	
+0xE7A1	0x7EAD	
+0xE7A2	0x7EB0	
+0xE7A3	0x7EBE	
+0xE7A4	0x7EC0	
+0xE7A5	0x7EC1	
+0xE7A6	0x7EC2	
+0xE7A7	0x7EC9	
+0xE7A8	0x7ECB	
+0xE7A9	0x7ECC	
+0xE7AA	0x7ED0	
+0xE7AB	0x7ED4	
+0xE7AC	0x7ED7	
+0xE7AD	0x7EDB	
+0xE7AE	0x7EE0	
+0xE7AF	0x7EE1	
+0xE7B0	0x7EE8	
+0xE7B1	0x7EEB	
+0xE7B2	0x7EEE	
+0xE7B3	0x7EEF	
+0xE7B4	0x7EF1	
+0xE7B5	0x7EF2	
+0xE7B6	0x7F0D	
+0xE7B7	0x7EF6	
+0xE7B8	0x7EFA	
+0xE7B9	0x7EFB	
+0xE7BA	0x7EFE	
+0xE7BB	0x7F01	
+0xE7BC	0x7F02	
+0xE7BD	0x7F03	
+0xE7BE	0x7F07	
+0xE7BF	0x7F08	
+0xE7C0	0x7F0B	
+0xE7C1	0x7F0C	
+0xE7C2	0x7F0F	
+0xE7C3	0x7F11	
+0xE7C4	0x7F12	
+0xE7C5	0x7F17	
+0xE7C6	0x7F19	
+0xE7C7	0x7F1C	
+0xE7C8	0x7F1B	
+0xE7C9	0x7F1F	
+0xE7CA	0x7F21	
+0xE7CB	0x7F22	
+0xE7CC	0x7F23	
+0xE7CD	0x7F24	
+0xE7CE	0x7F25	
+0xE7CF	0x7F26	
+0xE7D0	0x7F27	
+0xE7D1	0x7F2A	
+0xE7D2	0x7F2B	
+0xE7D3	0x7F2C	
+0xE7D4	0x7F2D	
+0xE7D5	0x7F2F	
+0xE7D6	0x7F30	
+0xE7D7	0x7F31	
+0xE7D8	0x7F32	
+0xE7D9	0x7F33	
+0xE7DA	0x7F35	
+0xE7DB	0x5E7A	
+0xE7DC	0x757F	
+0xE7DD	0x5DDB	
+0xE7DE	0x753E	
+0xE7DF	0x9095	
+0xE7E0	0x738E	
+0xE7E1	0x7391	
+0xE7E2	0x73AE	
+0xE7E3	0x73A2	
+0xE7E4	0x739F	
+0xE7E5	0x73CF	
+0xE7E6	0x73C2	
+0xE7E7	0x73D1	
+0xE7E8	0x73B7	
+0xE7E9	0x73B3	
+0xE7EA	0x73C0	
+0xE7EB	0x73C9	
+0xE7EC	0x73C8	
+0xE7ED	0x73E5	
+0xE7EE	0x73D9	
+0xE7EF	0x987C	
+0xE7F0	0x740A	
+0xE7F1	0x73E9	
+0xE7F2	0x73E7	
+0xE7F3	0x73DE	
+0xE7F4	0x73BA	
+0xE7F5	0x73F2	
+0xE7F6	0x740F	
+0xE7F7	0x742A	
+0xE7F8	0x745B	
+0xE7F9	0x7426	
+0xE7FA	0x7425	
+0xE7FB	0x7428	
+0xE7FC	0x7430	
+0xE7FD	0x742E	
+0xE7FE	0x742C	
+0xE840	0x942F	
+0xE841	0x9430	
+0xE842	0x9431	
+0xE843	0x9432	
+0xE844	0x9433	
+0xE845	0x9434	
+0xE846	0x9435	
+0xE847	0x9436	
+0xE848	0x9437	
+0xE849	0x9438	
+0xE84A	0x9439	
+0xE84B	0x943A	
+0xE84C	0x943B	
+0xE84D	0x943C	
+0xE84E	0x943D	
+0xE84F	0x943F	
+0xE850	0x9440	
+0xE851	0x9441	
+0xE852	0x9442	
+0xE853	0x9443	
+0xE854	0x9444	
+0xE855	0x9445	
+0xE856	0x9446	
+0xE857	0x9447	
+0xE858	0x9448	
+0xE859	0x9449	
+0xE85A	0x944A	
+0xE85B	0x944B	
+0xE85C	0x944C	
+0xE85D	0x944D	
+0xE85E	0x944E	
+0xE85F	0x944F	
+0xE860	0x9450	
+0xE861	0x9451	
+0xE862	0x9452	
+0xE863	0x9453	
+0xE864	0x9454	
+0xE865	0x9455	
+0xE866	0x9456	
+0xE867	0x9457	
+0xE868	0x9458	
+0xE869	0x9459	
+0xE86A	0x945A	
+0xE86B	0x945B	
+0xE86C	0x945C	
+0xE86D	0x945D	
+0xE86E	0x945E	
+0xE86F	0x945F	
+0xE870	0x9460	
+0xE871	0x9461	
+0xE872	0x9462	
+0xE873	0x9463	
+0xE874	0x9464	
+0xE875	0x9465	
+0xE876	0x9466	
+0xE877	0x9467	
+0xE878	0x9468	
+0xE879	0x9469	
+0xE87A	0x946A	
+0xE87B	0x946C	
+0xE87C	0x946D	
+0xE87D	0x946E	
+0xE87E	0x946F	
+0xE880	0x9470	
+0xE881	0x9471	
+0xE882	0x9472	
+0xE883	0x9473	
+0xE884	0x9474	
+0xE885	0x9475	
+0xE886	0x9476	
+0xE887	0x9477	
+0xE888	0x9478	
+0xE889	0x9479	
+0xE88A	0x947A	
+0xE88B	0x947B	
+0xE88C	0x947C	
+0xE88D	0x947D	
+0xE88E	0x947E	
+0xE88F	0x947F	
+0xE890	0x9480	
+0xE891	0x9481	
+0xE892	0x9482	
+0xE893	0x9483	
+0xE894	0x9484	
+0xE895	0x9491	
+0xE896	0x9496	
+0xE897	0x9498	
+0xE898	0x94C7	
+0xE899	0x94CF	
+0xE89A	0x94D3	
+0xE89B	0x94D4	
+0xE89C	0x94DA	
+0xE89D	0x94E6	
+0xE89E	0x94FB	
+0xE89F	0x951C	
+0xE8A0	0x9520	
+0xE8A1	0x741B	
+0xE8A2	0x741A	
+0xE8A3	0x7441	
+0xE8A4	0x745C	
+0xE8A5	0x7457	
+0xE8A6	0x7455	
+0xE8A7	0x7459	
+0xE8A8	0x7477	
+0xE8A9	0x746D	
+0xE8AA	0x747E	
+0xE8AB	0x749C	
+0xE8AC	0x748E	
+0xE8AD	0x7480	
+0xE8AE	0x7481	
+0xE8AF	0x7487	
+0xE8B0	0x748B	
+0xE8B1	0x749E	
+0xE8B2	0x74A8	
+0xE8B3	0x74A9	
+0xE8B4	0x7490	
+0xE8B5	0x74A7	
+0xE8B6	0x74D2	
+0xE8B7	0x74BA	
+0xE8B8	0x97EA	
+0xE8B9	0x97EB	
+0xE8BA	0x97EC	
+0xE8BB	0x674C	
+0xE8BC	0x6753	
+0xE8BD	0x675E	
+0xE8BE	0x6748	
+0xE8BF	0x6769	
+0xE8C0	0x67A5	
+0xE8C1	0x6787	
+0xE8C2	0x676A	
+0xE8C3	0x6773	
+0xE8C4	0x6798	
+0xE8C5	0x67A7	
+0xE8C6	0x6775	
+0xE8C7	0x67A8	
+0xE8C8	0x679E	
+0xE8C9	0x67AD	
+0xE8CA	0x678B	
+0xE8CB	0x6777	
+0xE8CC	0x677C	
+0xE8CD	0x67F0	
+0xE8CE	0x6809	
+0xE8CF	0x67D8	
+0xE8D0	0x680A	
+0xE8D1	0x67E9	
+0xE8D2	0x67B0	
+0xE8D3	0x680C	
+0xE8D4	0x67D9	
+0xE8D5	0x67B5	
+0xE8D6	0x67DA	
+0xE8D7	0x67B3	
+0xE8D8	0x67DD	
+0xE8D9	0x6800	
+0xE8DA	0x67C3	
+0xE8DB	0x67B8	
+0xE8DC	0x67E2	
+0xE8DD	0x680E	
+0xE8DE	0x67C1	
+0xE8DF	0x67FD	
+0xE8E0	0x6832	
+0xE8E1	0x6833	
+0xE8E2	0x6860	
+0xE8E3	0x6861	
+0xE8E4	0x684E	
+0xE8E5	0x6862	
+0xE8E6	0x6844	
+0xE8E7	0x6864	
+0xE8E8	0x6883	
+0xE8E9	0x681D	
+0xE8EA	0x6855	
+0xE8EB	0x6866	
+0xE8EC	0x6841	
+0xE8ED	0x6867	
+0xE8EE	0x6840	
+0xE8EF	0x683E	
+0xE8F0	0x684A	
+0xE8F1	0x6849	
+0xE8F2	0x6829	
+0xE8F3	0x68B5	
+0xE8F4	0x688F	
+0xE8F5	0x6874	
+0xE8F6	0x6877	
+0xE8F7	0x6893	
+0xE8F8	0x686B	
+0xE8F9	0x68C2	
+0xE8FA	0x696E	
+0xE8FB	0x68FC	
+0xE8FC	0x691F	
+0xE8FD	0x6920	
+0xE8FE	0x68F9	
+0xE940	0x9527	
+0xE941	0x9533	
+0xE942	0x953D	
+0xE943	0x9543	
+0xE944	0x9548	
+0xE945	0x954B	
+0xE946	0x9555	
+0xE947	0x955A	
+0xE948	0x9560	
+0xE949	0x956E	
+0xE94A	0x9574	
+0xE94B	0x9575	
+0xE94C	0x9577	
+0xE94D	0x9578	
+0xE94E	0x9579	
+0xE94F	0x957A	
+0xE950	0x957B	
+0xE951	0x957C	
+0xE952	0x957D	
+0xE953	0x957E	
+0xE954	0x9580	
+0xE955	0x9581	
+0xE956	0x9582	
+0xE957	0x9583	
+0xE958	0x9584	
+0xE959	0x9585	
+0xE95A	0x9586	
+0xE95B	0x9587	
+0xE95C	0x9588	
+0xE95D	0x9589	
+0xE95E	0x958A	
+0xE95F	0x958B	
+0xE960	0x958C	
+0xE961	0x958D	
+0xE962	0x958E	
+0xE963	0x958F	
+0xE964	0x9590	
+0xE965	0x9591	
+0xE966	0x9592	
+0xE967	0x9593	
+0xE968	0x9594	
+0xE969	0x9595	
+0xE96A	0x9596	
+0xE96B	0x9597	
+0xE96C	0x9598	
+0xE96D	0x9599	
+0xE96E	0x959A	
+0xE96F	0x959B	
+0xE970	0x959C	
+0xE971	0x959D	
+0xE972	0x959E	
+0xE973	0x959F	
+0xE974	0x95A0	
+0xE975	0x95A1	
+0xE976	0x95A2	
+0xE977	0x95A3	
+0xE978	0x95A4	
+0xE979	0x95A5	
+0xE97A	0x95A6	
+0xE97B	0x95A7	
+0xE97C	0x95A8	
+0xE97D	0x95A9	
+0xE97E	0x95AA	
+0xE980	0x95AB	
+0xE981	0x95AC	
+0xE982	0x95AD	
+0xE983	0x95AE	
+0xE984	0x95AF	
+0xE985	0x95B0	
+0xE986	0x95B1	
+0xE987	0x95B2	
+0xE988	0x95B3	
+0xE989	0x95B4	
+0xE98A	0x95B5	
+0xE98B	0x95B6	
+0xE98C	0x95B7	
+0xE98D	0x95B8	
+0xE98E	0x95B9	
+0xE98F	0x95BA	
+0xE990	0x95BB	
+0xE991	0x95BC	
+0xE992	0x95BD	
+0xE993	0x95BE	
+0xE994	0x95BF	
+0xE995	0x95C0	
+0xE996	0x95C1	
+0xE997	0x95C2	
+0xE998	0x95C3	
+0xE999	0x95C4	
+0xE99A	0x95C5	
+0xE99B	0x95C6	
+0xE99C	0x95C7	
+0xE99D	0x95C8	
+0xE99E	0x95C9	
+0xE99F	0x95CA	
+0xE9A0	0x95CB	
+0xE9A1	0x6924	
+0xE9A2	0x68F0	
+0xE9A3	0x690B	
+0xE9A4	0x6901	
+0xE9A5	0x6957	
+0xE9A6	0x68E3	
+0xE9A7	0x6910	
+0xE9A8	0x6971	
+0xE9A9	0x6939	
+0xE9AA	0x6960	
+0xE9AB	0x6942	
+0xE9AC	0x695D	
+0xE9AD	0x6984	
+0xE9AE	0x696B	
+0xE9AF	0x6980	
+0xE9B0	0x6998	
+0xE9B1	0x6978	
+0xE9B2	0x6934	
+0xE9B3	0x69CC	
+0xE9B4	0x6987	
+0xE9B5	0x6988	
+0xE9B6	0x69CE	
+0xE9B7	0x6989	
+0xE9B8	0x6966	
+0xE9B9	0x6963	
+0xE9BA	0x6979	
+0xE9BB	0x699B	
+0xE9BC	0x69A7	
+0xE9BD	0x69BB	
+0xE9BE	0x69AB	
+0xE9BF	0x69AD	
+0xE9C0	0x69D4	
+0xE9C1	0x69B1	
+0xE9C2	0x69C1	
+0xE9C3	0x69CA	
+0xE9C4	0x69DF	
+0xE9C5	0x6995	
+0xE9C6	0x69E0	
+0xE9C7	0x698D	
+0xE9C8	0x69FF	
+0xE9C9	0x6A2F	
+0xE9CA	0x69ED	
+0xE9CB	0x6A17	
+0xE9CC	0x6A18	
+0xE9CD	0x6A65	
+0xE9CE	0x69F2	
+0xE9CF	0x6A44	
+0xE9D0	0x6A3E	
+0xE9D1	0x6AA0	
+0xE9D2	0x6A50	
+0xE9D3	0x6A5B	
+0xE9D4	0x6A35	
+0xE9D5	0x6A8E	
+0xE9D6	0x6A79	
+0xE9D7	0x6A3D	
+0xE9D8	0x6A28	
+0xE9D9	0x6A58	
+0xE9DA	0x6A7C	
+0xE9DB	0x6A91	
+0xE9DC	0x6A90	
+0xE9DD	0x6AA9	
+0xE9DE	0x6A97	
+0xE9DF	0x6AAB	
+0xE9E0	0x7337	
+0xE9E1	0x7352	
+0xE9E2	0x6B81	
+0xE9E3	0x6B82	
+0xE9E4	0x6B87	
+0xE9E5	0x6B84	
+0xE9E6	0x6B92	
+0xE9E7	0x6B93	
+0xE9E8	0x6B8D	
+0xE9E9	0x6B9A	
+0xE9EA	0x6B9B	
+0xE9EB	0x6BA1	
+0xE9EC	0x6BAA	
+0xE9ED	0x8F6B	
+0xE9EE	0x8F6D	
+0xE9EF	0x8F71	
+0xE9F0	0x8F72	
+0xE9F1	0x8F73	
+0xE9F2	0x8F75	
+0xE9F3	0x8F76	
+0xE9F4	0x8F78	
+0xE9F5	0x8F77	
+0xE9F6	0x8F79	
+0xE9F7	0x8F7A	
+0xE9F8	0x8F7C	
+0xE9F9	0x8F7E	
+0xE9FA	0x8F81	
+0xE9FB	0x8F82	
+0xE9FC	0x8F84	
+0xE9FD	0x8F87	
+0xE9FE	0x8F8B	
+0xEA40	0x95CC	
+0xEA41	0x95CD	
+0xEA42	0x95CE	
+0xEA43	0x95CF	
+0xEA44	0x95D0	
+0xEA45	0x95D1	
+0xEA46	0x95D2	
+0xEA47	0x95D3	
+0xEA48	0x95D4	
+0xEA49	0x95D5	
+0xEA4A	0x95D6	
+0xEA4B	0x95D7	
+0xEA4C	0x95D8	
+0xEA4D	0x95D9	
+0xEA4E	0x95DA	
+0xEA4F	0x95DB	
+0xEA50	0x95DC	
+0xEA51	0x95DD	
+0xEA52	0x95DE	
+0xEA53	0x95DF	
+0xEA54	0x95E0	
+0xEA55	0x95E1	
+0xEA56	0x95E2	
+0xEA57	0x95E3	
+0xEA58	0x95E4	
+0xEA59	0x95E5	
+0xEA5A	0x95E6	
+0xEA5B	0x95E7	
+0xEA5C	0x95EC	
+0xEA5D	0x95FF	
+0xEA5E	0x9607	
+0xEA5F	0x9613	
+0xEA60	0x9618	
+0xEA61	0x961B	
+0xEA62	0x961E	
+0xEA63	0x9620	
+0xEA64	0x9623	
+0xEA65	0x9624	
+0xEA66	0x9625	
+0xEA67	0x9626	
+0xEA68	0x9627	
+0xEA69	0x9628	
+0xEA6A	0x9629	
+0xEA6B	0x962B	
+0xEA6C	0x962C	
+0xEA6D	0x962D	
+0xEA6E	0x962F	
+0xEA6F	0x9630	
+0xEA70	0x9637	
+0xEA71	0x9638	
+0xEA72	0x9639	
+0xEA73	0x963A	
+0xEA74	0x963E	
+0xEA75	0x9641	
+0xEA76	0x9643	
+0xEA77	0x964A	
+0xEA78	0x964E	
+0xEA79	0x964F	
+0xEA7A	0x9651	
+0xEA7B	0x9652	
+0xEA7C	0x9653	
+0xEA7D	0x9656	
+0xEA7E	0x9657	
+0xEA80	0x9658	
+0xEA81	0x9659	
+0xEA82	0x965A	
+0xEA83	0x965C	
+0xEA84	0x965D	
+0xEA85	0x965E	
+0xEA86	0x9660	
+0xEA87	0x9663	
+0xEA88	0x9665	
+0xEA89	0x9666	
+0xEA8A	0x966B	
+0xEA8B	0x966D	
+0xEA8C	0x966E	
+0xEA8D	0x966F	
+0xEA8E	0x9670	
+0xEA8F	0x9671	
+0xEA90	0x9673	
+0xEA91	0x9678	
+0xEA92	0x9679	
+0xEA93	0x967A	
+0xEA94	0x967B	
+0xEA95	0x967C	
+0xEA96	0x967D	
+0xEA97	0x967E	
+0xEA98	0x967F	
+0xEA99	0x9680	
+0xEA9A	0x9681	
+0xEA9B	0x9682	
+0xEA9C	0x9683	
+0xEA9D	0x9684	
+0xEA9E	0x9687	
+0xEA9F	0x9689	
+0xEAA0	0x968A	
+0xEAA1	0x8F8D	
+0xEAA2	0x8F8E	
+0xEAA3	0x8F8F	
+0xEAA4	0x8F98	
+0xEAA5	0x8F9A	
+0xEAA6	0x8ECE	
+0xEAA7	0x620B	
+0xEAA8	0x6217	
+0xEAA9	0x621B	
+0xEAAA	0x621F	
+0xEAAB	0x6222	
+0xEAAC	0x6221	
+0xEAAD	0x6225	
+0xEAAE	0x6224	
+0xEAAF	0x622C	
+0xEAB0	0x81E7	
+0xEAB1	0x74EF	
+0xEAB2	0x74F4	
+0xEAB3	0x74FF	
+0xEAB4	0x750F	
+0xEAB5	0x7511	
+0xEAB6	0x7513	
+0xEAB7	0x6534	
+0xEAB8	0x65EE	
+0xEAB9	0x65EF	
+0xEABA	0x65F0	
+0xEABB	0x660A	
+0xEABC	0x6619	
+0xEABD	0x6772	
+0xEABE	0x6603	
+0xEABF	0x6615	
+0xEAC0	0x6600	
+0xEAC1	0x7085	
+0xEAC2	0x66F7	
+0xEAC3	0x661D	
+0xEAC4	0x6634	
+0xEAC5	0x6631	
+0xEAC6	0x6636	
+0xEAC7	0x6635	
+0xEAC8	0x8006	
+0xEAC9	0x665F	
+0xEACA	0x6654	
+0xEACB	0x6641	
+0xEACC	0x664F	
+0xEACD	0x6656	
+0xEACE	0x6661	
+0xEACF	0x6657	
+0xEAD0	0x6677	
+0xEAD1	0x6684	
+0xEAD2	0x668C	
+0xEAD3	0x66A7	
+0xEAD4	0x669D	
+0xEAD5	0x66BE	
+0xEAD6	0x66DB	
+0xEAD7	0x66DC	
+0xEAD8	0x66E6	
+0xEAD9	0x66E9	
+0xEADA	0x8D32	
+0xEADB	0x8D33	
+0xEADC	0x8D36	
+0xEADD	0x8D3B	
+0xEADE	0x8D3D	
+0xEADF	0x8D40	
+0xEAE0	0x8D45	
+0xEAE1	0x8D46	
+0xEAE2	0x8D48	
+0xEAE3	0x8D49	
+0xEAE4	0x8D47	
+0xEAE5	0x8D4D	
+0xEAE6	0x8D55	
+0xEAE7	0x8D59	
+0xEAE8	0x89C7	
+0xEAE9	0x89CA	
+0xEAEA	0x89CB	
+0xEAEB	0x89CC	
+0xEAEC	0x89CE	
+0xEAED	0x89CF	
+0xEAEE	0x89D0	
+0xEAEF	0x89D1	
+0xEAF0	0x726E	
+0xEAF1	0x729F	
+0xEAF2	0x725D	
+0xEAF3	0x7266	
+0xEAF4	0x726F	
+0xEAF5	0x727E	
+0xEAF6	0x727F	
+0xEAF7	0x7284	
+0xEAF8	0x728B	
+0xEAF9	0x728D	
+0xEAFA	0x728F	
+0xEAFB	0x7292	
+0xEAFC	0x6308	
+0xEAFD	0x6332	
+0xEAFE	0x63B0	
+0xEB40	0x968C	
+0xEB41	0x968E	
+0xEB42	0x9691	
+0xEB43	0x9692	
+0xEB44	0x9693	
+0xEB45	0x9695	
+0xEB46	0x9696	
+0xEB47	0x969A	
+0xEB48	0x969B	
+0xEB49	0x969D	
+0xEB4A	0x969E	
+0xEB4B	0x969F	
+0xEB4C	0x96A0	
+0xEB4D	0x96A1	
+0xEB4E	0x96A2	
+0xEB4F	0x96A3	
+0xEB50	0x96A4	
+0xEB51	0x96A5	
+0xEB52	0x96A6	
+0xEB53	0x96A8	
+0xEB54	0x96A9	
+0xEB55	0x96AA	
+0xEB56	0x96AB	
+0xEB57	0x96AC	
+0xEB58	0x96AD	
+0xEB59	0x96AE	
+0xEB5A	0x96AF	
+0xEB5B	0x96B1	
+0xEB5C	0x96B2	
+0xEB5D	0x96B4	
+0xEB5E	0x96B5	
+0xEB5F	0x96B7	
+0xEB60	0x96B8	
+0xEB61	0x96BA	
+0xEB62	0x96BB	
+0xEB63	0x96BF	
+0xEB64	0x96C2	
+0xEB65	0x96C3	
+0xEB66	0x96C8	
+0xEB67	0x96CA	
+0xEB68	0x96CB	
+0xEB69	0x96D0	
+0xEB6A	0x96D1	
+0xEB6B	0x96D3	
+0xEB6C	0x96D4	
+0xEB6D	0x96D6	
+0xEB6E	0x96D7	
+0xEB6F	0x96D8	
+0xEB70	0x96D9	
+0xEB71	0x96DA	
+0xEB72	0x96DB	
+0xEB73	0x96DC	
+0xEB74	0x96DD	
+0xEB75	0x96DE	
+0xEB76	0x96DF	
+0xEB77	0x96E1	
+0xEB78	0x96E2	
+0xEB79	0x96E3	
+0xEB7A	0x96E4	
+0xEB7B	0x96E5	
+0xEB7C	0x96E6	
+0xEB7D	0x96E7	
+0xEB7E	0x96EB	
+0xEB80	0x96EC	
+0xEB81	0x96ED	
+0xEB82	0x96EE	
+0xEB83	0x96F0	
+0xEB84	0x96F1	
+0xEB85	0x96F2	
+0xEB86	0x96F4	
+0xEB87	0x96F5	
+0xEB88	0x96F8	
+0xEB89	0x96FA	
+0xEB8A	0x96FB	
+0xEB8B	0x96FC	
+0xEB8C	0x96FD	
+0xEB8D	0x96FF	
+0xEB8E	0x9702	
+0xEB8F	0x9703	
+0xEB90	0x9705	
+0xEB91	0x970A	
+0xEB92	0x970B	
+0xEB93	0x970C	
+0xEB94	0x9710	
+0xEB95	0x9711	
+0xEB96	0x9712	
+0xEB97	0x9714	
+0xEB98	0x9715	
+0xEB99	0x9717	
+0xEB9A	0x9718	
+0xEB9B	0x9719	
+0xEB9C	0x971A	
+0xEB9D	0x971B	
+0xEB9E	0x971D	
+0xEB9F	0x971F	
+0xEBA0	0x9720	
+0xEBA1	0x643F	
+0xEBA2	0x64D8	
+0xEBA3	0x8004	
+0xEBA4	0x6BEA	
+0xEBA5	0x6BF3	
+0xEBA6	0x6BFD	
+0xEBA7	0x6BF5	
+0xEBA8	0x6BF9	
+0xEBA9	0x6C05	
+0xEBAA	0x6C07	
+0xEBAB	0x6C06	
+0xEBAC	0x6C0D	
+0xEBAD	0x6C15	
+0xEBAE	0x6C18	
+0xEBAF	0x6C19	
+0xEBB0	0x6C1A	
+0xEBB1	0x6C21	
+0xEBB2	0x6C29	
+0xEBB3	0x6C24	
+0xEBB4	0x6C2A	
+0xEBB5	0x6C32	
+0xEBB6	0x6535	
+0xEBB7	0x6555	
+0xEBB8	0x656B	
+0xEBB9	0x724D	
+0xEBBA	0x7252	
+0xEBBB	0x7256	
+0xEBBC	0x7230	
+0xEBBD	0x8662	
+0xEBBE	0x5216	
+0xEBBF	0x809F	
+0xEBC0	0x809C	
+0xEBC1	0x8093	
+0xEBC2	0x80BC	
+0xEBC3	0x670A	
+0xEBC4	0x80BD	
+0xEBC5	0x80B1	
+0xEBC6	0x80AB	
+0xEBC7	0x80AD	
+0xEBC8	0x80B4	
+0xEBC9	0x80B7	
+0xEBCA	0x80E7	
+0xEBCB	0x80E8	
+0xEBCC	0x80E9	
+0xEBCD	0x80EA	
+0xEBCE	0x80DB	
+0xEBCF	0x80C2	
+0xEBD0	0x80C4	
+0xEBD1	0x80D9	
+0xEBD2	0x80CD	
+0xEBD3	0x80D7	
+0xEBD4	0x6710	
+0xEBD5	0x80DD	
+0xEBD6	0x80EB	
+0xEBD7	0x80F1	
+0xEBD8	0x80F4	
+0xEBD9	0x80ED	
+0xEBDA	0x810D	
+0xEBDB	0x810E	
+0xEBDC	0x80F2	
+0xEBDD	0x80FC	
+0xEBDE	0x6715	
+0xEBDF	0x8112	
+0xEBE0	0x8C5A	
+0xEBE1	0x8136	
+0xEBE2	0x811E	
+0xEBE3	0x812C	
+0xEBE4	0x8118	
+0xEBE5	0x8132	
+0xEBE6	0x8148	
+0xEBE7	0x814C	
+0xEBE8	0x8153	
+0xEBE9	0x8174	
+0xEBEA	0x8159	
+0xEBEB	0x815A	
+0xEBEC	0x8171	
+0xEBED	0x8160	
+0xEBEE	0x8169	
+0xEBEF	0x817C	
+0xEBF0	0x817D	
+0xEBF1	0x816D	
+0xEBF2	0x8167	
+0xEBF3	0x584D	
+0xEBF4	0x5AB5	
+0xEBF5	0x8188	
+0xEBF6	0x8182	
+0xEBF7	0x8191	
+0xEBF8	0x6ED5	
+0xEBF9	0x81A3	
+0xEBFA	0x81AA	
+0xEBFB	0x81CC	
+0xEBFC	0x6726	
+0xEBFD	0x81CA	
+0xEBFE	0x81BB	
+0xEC40	0x9721	
+0xEC41	0x9722	
+0xEC42	0x9723	
+0xEC43	0x9724	
+0xEC44	0x9725	
+0xEC45	0x9726	
+0xEC46	0x9727	
+0xEC47	0x9728	
+0xEC48	0x9729	
+0xEC49	0x972B	
+0xEC4A	0x972C	
+0xEC4B	0x972E	
+0xEC4C	0x972F	
+0xEC4D	0x9731	
+0xEC4E	0x9733	
+0xEC4F	0x9734	
+0xEC50	0x9735	
+0xEC51	0x9736	
+0xEC52	0x9737	
+0xEC53	0x973A	
+0xEC54	0x973B	
+0xEC55	0x973C	
+0xEC56	0x973D	
+0xEC57	0x973F	
+0xEC58	0x9740	
+0xEC59	0x9741	
+0xEC5A	0x9742	
+0xEC5B	0x9743	
+0xEC5C	0x9744	
+0xEC5D	0x9745	
+0xEC5E	0x9746	
+0xEC5F	0x9747	
+0xEC60	0x9748	
+0xEC61	0x9749	
+0xEC62	0x974A	
+0xEC63	0x974B	
+0xEC64	0x974C	
+0xEC65	0x974D	
+0xEC66	0x974E	
+0xEC67	0x974F	
+0xEC68	0x9750	
+0xEC69	0x9751	
+0xEC6A	0x9754	
+0xEC6B	0x9755	
+0xEC6C	0x9757	
+0xEC6D	0x9758	
+0xEC6E	0x975A	
+0xEC6F	0x975C	
+0xEC70	0x975D	
+0xEC71	0x975F	
+0xEC72	0x9763	
+0xEC73	0x9764	
+0xEC74	0x9766	
+0xEC75	0x9767	
+0xEC76	0x9768	
+0xEC77	0x976A	
+0xEC78	0x976B	
+0xEC79	0x976C	
+0xEC7A	0x976D	
+0xEC7B	0x976E	
+0xEC7C	0x976F	
+0xEC7D	0x9770	
+0xEC7E	0x9771	
+0xEC80	0x9772	
+0xEC81	0x9775	
+0xEC82	0x9777	
+0xEC83	0x9778	
+0xEC84	0x9779	
+0xEC85	0x977A	
+0xEC86	0x977B	
+0xEC87	0x977D	
+0xEC88	0x977E	
+0xEC89	0x977F	
+0xEC8A	0x9780	
+0xEC8B	0x9781	
+0xEC8C	0x9782	
+0xEC8D	0x9783	
+0xEC8E	0x9784	
+0xEC8F	0x9786	
+0xEC90	0x9787	
+0xEC91	0x9788	
+0xEC92	0x9789	
+0xEC93	0x978A	
+0xEC94	0x978C	
+0xEC95	0x978E	
+0xEC96	0x978F	
+0xEC97	0x9790	
+0xEC98	0x9793	
+0xEC99	0x9795	
+0xEC9A	0x9796	
+0xEC9B	0x9797	
+0xEC9C	0x9799	
+0xEC9D	0x979A	
+0xEC9E	0x979B	
+0xEC9F	0x979C	
+0xECA0	0x979D	
+0xECA1	0x81C1	
+0xECA2	0x81A6	
+0xECA3	0x6B24	
+0xECA4	0x6B37	
+0xECA5	0x6B39	
+0xECA6	0x6B43	
+0xECA7	0x6B46	
+0xECA8	0x6B59	
+0xECA9	0x98D1	
+0xECAA	0x98D2	
+0xECAB	0x98D3	
+0xECAC	0x98D5	
+0xECAD	0x98D9	
+0xECAE	0x98DA	
+0xECAF	0x6BB3	
+0xECB0	0x5F40	
+0xECB1	0x6BC2	
+0xECB2	0x89F3	
+0xECB3	0x6590	
+0xECB4	0x9F51	
+0xECB5	0x6593	
+0xECB6	0x65BC	
+0xECB7	0x65C6	
+0xECB8	0x65C4	
+0xECB9	0x65C3	
+0xECBA	0x65CC	
+0xECBB	0x65CE	
+0xECBC	0x65D2	
+0xECBD	0x65D6	
+0xECBE	0x7080	
+0xECBF	0x709C	
+0xECC0	0x7096	
+0xECC1	0x709D	
+0xECC2	0x70BB	
+0xECC3	0x70C0	
+0xECC4	0x70B7	
+0xECC5	0x70AB	
+0xECC6	0x70B1	
+0xECC7	0x70E8	
+0xECC8	0x70CA	
+0xECC9	0x7110	
+0xECCA	0x7113	
+0xECCB	0x7116	
+0xECCC	0x712F	
+0xECCD	0x7131	
+0xECCE	0x7173	
+0xECCF	0x715C	
+0xECD0	0x7168	
+0xECD1	0x7145	
+0xECD2	0x7172	
+0xECD3	0x714A	
+0xECD4	0x7178	
+0xECD5	0x717A	
+0xECD6	0x7198	
+0xECD7	0x71B3	
+0xECD8	0x71B5	
+0xECD9	0x71A8	
+0xECDA	0x71A0	
+0xECDB	0x71E0	
+0xECDC	0x71D4	
+0xECDD	0x71E7	
+0xECDE	0x71F9	
+0xECDF	0x721D	
+0xECE0	0x7228	
+0xECE1	0x706C	
+0xECE2	0x7118	
+0xECE3	0x7166	
+0xECE4	0x71B9	
+0xECE5	0x623E	
+0xECE6	0x623D	
+0xECE7	0x6243	
+0xECE8	0x6248	
+0xECE9	0x6249	
+0xECEA	0x793B	
+0xECEB	0x7940	
+0xECEC	0x7946	
+0xECED	0x7949	
+0xECEE	0x795B	
+0xECEF	0x795C	
+0xECF0	0x7953	
+0xECF1	0x795A	
+0xECF2	0x7962	
+0xECF3	0x7957	
+0xECF4	0x7960	
+0xECF5	0x796F	
+0xECF6	0x7967	
+0xECF7	0x797A	
+0xECF8	0x7985	
+0xECF9	0x798A	
+0xECFA	0x799A	
+0xECFB	0x79A7	
+0xECFC	0x79B3	
+0xECFD	0x5FD1	
+0xECFE	0x5FD0	
+0xED40	0x979E	
+0xED41	0x979F	
+0xED42	0x97A1	
+0xED43	0x97A2	
+0xED44	0x97A4	
+0xED45	0x97A5	
+0xED46	0x97A6	
+0xED47	0x97A7	
+0xED48	0x97A8	
+0xED49	0x97A9	
+0xED4A	0x97AA	
+0xED4B	0x97AC	
+0xED4C	0x97AE	
+0xED4D	0x97B0	
+0xED4E	0x97B1	
+0xED4F	0x97B3	
+0xED50	0x97B5	
+0xED51	0x97B6	
+0xED52	0x97B7	
+0xED53	0x97B8	
+0xED54	0x97B9	
+0xED55	0x97BA	
+0xED56	0x97BB	
+0xED57	0x97BC	
+0xED58	0x97BD	
+0xED59	0x97BE	
+0xED5A	0x97BF	
+0xED5B	0x97C0	
+0xED5C	0x97C1	
+0xED5D	0x97C2	
+0xED5E	0x97C3	
+0xED5F	0x97C4	
+0xED60	0x97C5	
+0xED61	0x97C6	
+0xED62	0x97C7	
+0xED63	0x97C8	
+0xED64	0x97C9	
+0xED65	0x97CA	
+0xED66	0x97CB	
+0xED67	0x97CC	
+0xED68	0x97CD	
+0xED69	0x97CE	
+0xED6A	0x97CF	
+0xED6B	0x97D0	
+0xED6C	0x97D1	
+0xED6D	0x97D2	
+0xED6E	0x97D3	
+0xED6F	0x97D4	
+0xED70	0x97D5	
+0xED71	0x97D6	
+0xED72	0x97D7	
+0xED73	0x97D8	
+0xED74	0x97D9	
+0xED75	0x97DA	
+0xED76	0x97DB	
+0xED77	0x97DC	
+0xED78	0x97DD	
+0xED79	0x97DE	
+0xED7A	0x97DF	
+0xED7B	0x97E0	
+0xED7C	0x97E1	
+0xED7D	0x97E2	
+0xED7E	0x97E3	
+0xED80	0x97E4	
+0xED81	0x97E5	
+0xED82	0x97E8	
+0xED83	0x97EE	
+0xED84	0x97EF	
+0xED85	0x97F0	
+0xED86	0x97F1	
+0xED87	0x97F2	
+0xED88	0x97F4	
+0xED89	0x97F7	
+0xED8A	0x97F8	
+0xED8B	0x97F9	
+0xED8C	0x97FA	
+0xED8D	0x97FB	
+0xED8E	0x97FC	
+0xED8F	0x97FD	
+0xED90	0x97FE	
+0xED91	0x97FF	
+0xED92	0x9800	
+0xED93	0x9801	
+0xED94	0x9802	
+0xED95	0x9803	
+0xED96	0x9804	
+0xED97	0x9805	
+0xED98	0x9806	
+0xED99	0x9807	
+0xED9A	0x9808	
+0xED9B	0x9809	
+0xED9C	0x980A	
+0xED9D	0x980B	
+0xED9E	0x980C	
+0xED9F	0x980D	
+0xEDA0	0x980E	
+0xEDA1	0x603C	
+0xEDA2	0x605D	
+0xEDA3	0x605A	
+0xEDA4	0x6067	
+0xEDA5	0x6041	
+0xEDA6	0x6059	
+0xEDA7	0x6063	
+0xEDA8	0x60AB	
+0xEDA9	0x6106	
+0xEDAA	0x610D	
+0xEDAB	0x615D	
+0xEDAC	0x61A9	
+0xEDAD	0x619D	
+0xEDAE	0x61CB	
+0xEDAF	0x61D1	
+0xEDB0	0x6206	
+0xEDB1	0x8080	
+0xEDB2	0x807F	
+0xEDB3	0x6C93	
+0xEDB4	0x6CF6	
+0xEDB5	0x6DFC	
+0xEDB6	0x77F6	
+0xEDB7	0x77F8	
+0xEDB8	0x7800	
+0xEDB9	0x7809	
+0xEDBA	0x7817	
+0xEDBB	0x7818	
+0xEDBC	0x7811	
+0xEDBD	0x65AB	
+0xEDBE	0x782D	
+0xEDBF	0x781C	
+0xEDC0	0x781D	
+0xEDC1	0x7839	
+0xEDC2	0x783A	
+0xEDC3	0x783B	
+0xEDC4	0x781F	
+0xEDC5	0x783C	
+0xEDC6	0x7825	
+0xEDC7	0x782C	
+0xEDC8	0x7823	
+0xEDC9	0x7829	
+0xEDCA	0x784E	
+0xEDCB	0x786D	
+0xEDCC	0x7856	
+0xEDCD	0x7857	
+0xEDCE	0x7826	
+0xEDCF	0x7850	
+0xEDD0	0x7847	
+0xEDD1	0x784C	
+0xEDD2	0x786A	
+0xEDD3	0x789B	
+0xEDD4	0x7893	
+0xEDD5	0x789A	
+0xEDD6	0x7887	
+0xEDD7	0x789C	
+0xEDD8	0x78A1	
+0xEDD9	0x78A3	
+0xEDDA	0x78B2	
+0xEDDB	0x78B9	
+0xEDDC	0x78A5	
+0xEDDD	0x78D4	
+0xEDDE	0x78D9	
+0xEDDF	0x78C9	
+0xEDE0	0x78EC	
+0xEDE1	0x78F2	
+0xEDE2	0x7905	
+0xEDE3	0x78F4	
+0xEDE4	0x7913	
+0xEDE5	0x7924	
+0xEDE6	0x791E	
+0xEDE7	0x7934	
+0xEDE8	0x9F9B	
+0xEDE9	0x9EF9	
+0xEDEA	0x9EFB	
+0xEDEB	0x9EFC	
+0xEDEC	0x76F1	
+0xEDED	0x7704	
+0xEDEE	0x770D	
+0xEDEF	0x76F9	
+0xEDF0	0x7707	
+0xEDF1	0x7708	
+0xEDF2	0x771A	
+0xEDF3	0x7722	
+0xEDF4	0x7719	
+0xEDF5	0x772D	
+0xEDF6	0x7726	
+0xEDF7	0x7735	
+0xEDF8	0x7738	
+0xEDF9	0x7750	
+0xEDFA	0x7751	
+0xEDFB	0x7747	
+0xEDFC	0x7743	
+0xEDFD	0x775A	
+0xEDFE	0x7768	
+0xEE40	0x980F	
+0xEE41	0x9810	
+0xEE42	0x9811	
+0xEE43	0x9812	
+0xEE44	0x9813	
+0xEE45	0x9814	
+0xEE46	0x9815	
+0xEE47	0x9816	
+0xEE48	0x9817	
+0xEE49	0x9818	
+0xEE4A	0x9819	
+0xEE4B	0x981A	
+0xEE4C	0x981B	
+0xEE4D	0x981C	
+0xEE4E	0x981D	
+0xEE4F	0x981E	
+0xEE50	0x981F	
+0xEE51	0x9820	
+0xEE52	0x9821	
+0xEE53	0x9822	
+0xEE54	0x9823	
+0xEE55	0x9824	
+0xEE56	0x9825	
+0xEE57	0x9826	
+0xEE58	0x9827	
+0xEE59	0x9828	
+0xEE5A	0x9829	
+0xEE5B	0x982A	
+0xEE5C	0x982B	
+0xEE5D	0x982C	
+0xEE5E	0x982D	
+0xEE5F	0x982E	
+0xEE60	0x982F	
+0xEE61	0x9830	
+0xEE62	0x9831	
+0xEE63	0x9832	
+0xEE64	0x9833	
+0xEE65	0x9834	
+0xEE66	0x9835	
+0xEE67	0x9836	
+0xEE68	0x9837	
+0xEE69	0x9838	
+0xEE6A	0x9839	
+0xEE6B	0x983A	
+0xEE6C	0x983B	
+0xEE6D	0x983C	
+0xEE6E	0x983D	
+0xEE6F	0x983E	
+0xEE70	0x983F	
+0xEE71	0x9840	
+0xEE72	0x9841	
+0xEE73	0x9842	
+0xEE74	0x9843	
+0xEE75	0x9844	
+0xEE76	0x9845	
+0xEE77	0x9846	
+0xEE78	0x9847	
+0xEE79	0x9848	
+0xEE7A	0x9849	
+0xEE7B	0x984A	
+0xEE7C	0x984B	
+0xEE7D	0x984C	
+0xEE7E	0x984D	
+0xEE80	0x984E	
+0xEE81	0x984F	
+0xEE82	0x9850	
+0xEE83	0x9851	
+0xEE84	0x9852	
+0xEE85	0x9853	
+0xEE86	0x9854	
+0xEE87	0x9855	
+0xEE88	0x9856	
+0xEE89	0x9857	
+0xEE8A	0x9858	
+0xEE8B	0x9859	
+0xEE8C	0x985A	
+0xEE8D	0x985B	
+0xEE8E	0x985C	
+0xEE8F	0x985D	
+0xEE90	0x985E	
+0xEE91	0x985F	
+0xEE92	0x9860	
+0xEE93	0x9861	
+0xEE94	0x9862	
+0xEE95	0x9863	
+0xEE96	0x9864	
+0xEE97	0x9865	
+0xEE98	0x9866	
+0xEE99	0x9867	
+0xEE9A	0x9868	
+0xEE9B	0x9869	
+0xEE9C	0x986A	
+0xEE9D	0x986B	
+0xEE9E	0x986C	
+0xEE9F	0x986D	
+0xEEA0	0x986E	
+0xEEA1	0x7762	
+0xEEA2	0x7765	
+0xEEA3	0x777F	
+0xEEA4	0x778D	
+0xEEA5	0x777D	
+0xEEA6	0x7780	
+0xEEA7	0x778C	
+0xEEA8	0x7791	
+0xEEA9	0x779F	
+0xEEAA	0x77A0	
+0xEEAB	0x77B0	
+0xEEAC	0x77B5	
+0xEEAD	0x77BD	
+0xEEAE	0x753A	
+0xEEAF	0x7540	
+0xEEB0	0x754E	
+0xEEB1	0x754B	
+0xEEB2	0x7548	
+0xEEB3	0x755B	
+0xEEB4	0x7572	
+0xEEB5	0x7579	
+0xEEB6	0x7583	
+0xEEB7	0x7F58	
+0xEEB8	0x7F61	
+0xEEB9	0x7F5F	
+0xEEBA	0x8A48	
+0xEEBB	0x7F68	
+0xEEBC	0x7F74	
+0xEEBD	0x7F71	
+0xEEBE	0x7F79	
+0xEEBF	0x7F81	
+0xEEC0	0x7F7E	
+0xEEC1	0x76CD	
+0xEEC2	0x76E5	
+0xEEC3	0x8832	
+0xEEC4	0x9485	
+0xEEC5	0x9486	
+0xEEC6	0x9487	
+0xEEC7	0x948B	
+0xEEC8	0x948A	
+0xEEC9	0x948C	
+0xEECA	0x948D	
+0xEECB	0x948F	
+0xEECC	0x9490	
+0xEECD	0x9494	
+0xEECE	0x9497	
+0xEECF	0x9495	
+0xEED0	0x949A	
+0xEED1	0x949B	
+0xEED2	0x949C	
+0xEED3	0x94A3	
+0xEED4	0x94A4	
+0xEED5	0x94AB	
+0xEED6	0x94AA	
+0xEED7	0x94AD	
+0xEED8	0x94AC	
+0xEED9	0x94AF	
+0xEEDA	0x94B0	
+0xEEDB	0x94B2	
+0xEEDC	0x94B4	
+0xEEDD	0x94B6	
+0xEEDE	0x94B7	
+0xEEDF	0x94B8	
+0xEEE0	0x94B9	
+0xEEE1	0x94BA	
+0xEEE2	0x94BC	
+0xEEE3	0x94BD	
+0xEEE4	0x94BF	
+0xEEE5	0x94C4	
+0xEEE6	0x94C8	
+0xEEE7	0x94C9	
+0xEEE8	0x94CA	
+0xEEE9	0x94CB	
+0xEEEA	0x94CC	
+0xEEEB	0x94CD	
+0xEEEC	0x94CE	
+0xEEED	0x94D0	
+0xEEEE	0x94D1	
+0xEEEF	0x94D2	
+0xEEF0	0x94D5	
+0xEEF1	0x94D6	
+0xEEF2	0x94D7	
+0xEEF3	0x94D9	
+0xEEF4	0x94D8	
+0xEEF5	0x94DB	
+0xEEF6	0x94DE	
+0xEEF7	0x94DF	
+0xEEF8	0x94E0	
+0xEEF9	0x94E2	
+0xEEFA	0x94E4	
+0xEEFB	0x94E5	
+0xEEFC	0x94E7	
+0xEEFD	0x94E8	
+0xEEFE	0x94EA	
+0xEF40	0x986F	
+0xEF41	0x9870	
+0xEF42	0x9871	
+0xEF43	0x9872	
+0xEF44	0x9873	
+0xEF45	0x9874	
+0xEF46	0x988B	
+0xEF47	0x988E	
+0xEF48	0x9892	
+0xEF49	0x9895	
+0xEF4A	0x9899	
+0xEF4B	0x98A3	
+0xEF4C	0x98A8	
+0xEF4D	0x98A9	
+0xEF4E	0x98AA	
+0xEF4F	0x98AB	
+0xEF50	0x98AC	
+0xEF51	0x98AD	
+0xEF52	0x98AE	
+0xEF53	0x98AF	
+0xEF54	0x98B0	
+0xEF55	0x98B1	
+0xEF56	0x98B2	
+0xEF57	0x98B3	
+0xEF58	0x98B4	
+0xEF59	0x98B5	
+0xEF5A	0x98B6	
+0xEF5B	0x98B7	
+0xEF5C	0x98B8	
+0xEF5D	0x98B9	
+0xEF5E	0x98BA	
+0xEF5F	0x98BB	
+0xEF60	0x98BC	
+0xEF61	0x98BD	
+0xEF62	0x98BE	
+0xEF63	0x98BF	
+0xEF64	0x98C0	
+0xEF65	0x98C1	
+0xEF66	0x98C2	
+0xEF67	0x98C3	
+0xEF68	0x98C4	
+0xEF69	0x98C5	
+0xEF6A	0x98C6	
+0xEF6B	0x98C7	
+0xEF6C	0x98C8	
+0xEF6D	0x98C9	
+0xEF6E	0x98CA	
+0xEF6F	0x98CB	
+0xEF70	0x98CC	
+0xEF71	0x98CD	
+0xEF72	0x98CF	
+0xEF73	0x98D0	
+0xEF74	0x98D4	
+0xEF75	0x98D6	
+0xEF76	0x98D7	
+0xEF77	0x98DB	
+0xEF78	0x98DC	
+0xEF79	0x98DD	
+0xEF7A	0x98E0	
+0xEF7B	0x98E1	
+0xEF7C	0x98E2	
+0xEF7D	0x98E3	
+0xEF7E	0x98E4	
+0xEF80	0x98E5	
+0xEF81	0x98E6	
+0xEF82	0x98E9	
+0xEF83	0x98EA	
+0xEF84	0x98EB	
+0xEF85	0x98EC	
+0xEF86	0x98ED	
+0xEF87	0x98EE	
+0xEF88	0x98EF	
+0xEF89	0x98F0	
+0xEF8A	0x98F1	
+0xEF8B	0x98F2	
+0xEF8C	0x98F3	
+0xEF8D	0x98F4	
+0xEF8E	0x98F5	
+0xEF8F	0x98F6	
+0xEF90	0x98F7	
+0xEF91	0x98F8	
+0xEF92	0x98F9	
+0xEF93	0x98FA	
+0xEF94	0x98FB	
+0xEF95	0x98FC	
+0xEF96	0x98FD	
+0xEF97	0x98FE	
+0xEF98	0x98FF	
+0xEF99	0x9900	
+0xEF9A	0x9901	
+0xEF9B	0x9902	
+0xEF9C	0x9903	
+0xEF9D	0x9904	
+0xEF9E	0x9905	
+0xEF9F	0x9906	
+0xEFA0	0x9907	
+0xEFA1	0x94E9	
+0xEFA2	0x94EB	
+0xEFA3	0x94EE	
+0xEFA4	0x94EF	
+0xEFA5	0x94F3	
+0xEFA6	0x94F4	
+0xEFA7	0x94F5	
+0xEFA8	0x94F7	
+0xEFA9	0x94F9	
+0xEFAA	0x94FC	
+0xEFAB	0x94FD	
+0xEFAC	0x94FF	
+0xEFAD	0x9503	
+0xEFAE	0x9502	
+0xEFAF	0x9506	
+0xEFB0	0x9507	
+0xEFB1	0x9509	
+0xEFB2	0x950A	
+0xEFB3	0x950D	
+0xEFB4	0x950E	
+0xEFB5	0x950F	
+0xEFB6	0x9512	
+0xEFB7	0x9513	
+0xEFB8	0x9514	
+0xEFB9	0x9515	
+0xEFBA	0x9516	
+0xEFBB	0x9518	
+0xEFBC	0x951B	
+0xEFBD	0x951D	
+0xEFBE	0x951E	
+0xEFBF	0x951F	
+0xEFC0	0x9522	
+0xEFC1	0x952A	
+0xEFC2	0x952B	
+0xEFC3	0x9529	
+0xEFC4	0x952C	
+0xEFC5	0x9531	
+0xEFC6	0x9532	
+0xEFC7	0x9534	
+0xEFC8	0x9536	
+0xEFC9	0x9537	
+0xEFCA	0x9538	
+0xEFCB	0x953C	
+0xEFCC	0x953E	
+0xEFCD	0x953F	
+0xEFCE	0x9542	
+0xEFCF	0x9535	
+0xEFD0	0x9544	
+0xEFD1	0x9545	
+0xEFD2	0x9546	
+0xEFD3	0x9549	
+0xEFD4	0x954C	
+0xEFD5	0x954E	
+0xEFD6	0x954F	
+0xEFD7	0x9552	
+0xEFD8	0x9553	
+0xEFD9	0x9554	
+0xEFDA	0x9556	
+0xEFDB	0x9557	
+0xEFDC	0x9558	
+0xEFDD	0x9559	
+0xEFDE	0x955B	
+0xEFDF	0x955E	
+0xEFE0	0x955F	
+0xEFE1	0x955D	
+0xEFE2	0x9561	
+0xEFE3	0x9562	
+0xEFE4	0x9564	
+0xEFE5	0x9565	
+0xEFE6	0x9566	
+0xEFE7	0x9567	
+0xEFE8	0x9568	
+0xEFE9	0x9569	
+0xEFEA	0x956A	
+0xEFEB	0x956B	
+0xEFEC	0x956C	
+0xEFED	0x956F	
+0xEFEE	0x9571	
+0xEFEF	0x9572	
+0xEFF0	0x9573	
+0xEFF1	0x953A	
+0xEFF2	0x77E7	
+0xEFF3	0x77EC	
+0xEFF4	0x96C9	
+0xEFF5	0x79D5	
+0xEFF6	0x79ED	
+0xEFF7	0x79E3	
+0xEFF8	0x79EB	
+0xEFF9	0x7A06	
+0xEFFA	0x5D47	
+0xEFFB	0x7A03	
+0xEFFC	0x7A02	
+0xEFFD	0x7A1E	
+0xEFFE	0x7A14	
+0xF040	0x9908	
+0xF041	0x9909	
+0xF042	0x990A	
+0xF043	0x990B	
+0xF044	0x990C	
+0xF045	0x990E	
+0xF046	0x990F	
+0xF047	0x9911	
+0xF048	0x9912	
+0xF049	0x9913	
+0xF04A	0x9914	
+0xF04B	0x9915	
+0xF04C	0x9916	
+0xF04D	0x9917	
+0xF04E	0x9918	
+0xF04F	0x9919	
+0xF050	0x991A	
+0xF051	0x991B	
+0xF052	0x991C	
+0xF053	0x991D	
+0xF054	0x991E	
+0xF055	0x991F	
+0xF056	0x9920	
+0xF057	0x9921	
+0xF058	0x9922	
+0xF059	0x9923	
+0xF05A	0x9924	
+0xF05B	0x9925	
+0xF05C	0x9926	
+0xF05D	0x9927	
+0xF05E	0x9928	
+0xF05F	0x9929	
+0xF060	0x992A	
+0xF061	0x992B	
+0xF062	0x992C	
+0xF063	0x992D	
+0xF064	0x992F	
+0xF065	0x9930	
+0xF066	0x9931	
+0xF067	0x9932	
+0xF068	0x9933	
+0xF069	0x9934	
+0xF06A	0x9935	
+0xF06B	0x9936	
+0xF06C	0x9937	
+0xF06D	0x9938	
+0xF06E	0x9939	
+0xF06F	0x993A	
+0xF070	0x993B	
+0xF071	0x993C	
+0xF072	0x993D	
+0xF073	0x993E	
+0xF074	0x993F	
+0xF075	0x9940	
+0xF076	0x9941	
+0xF077	0x9942	
+0xF078	0x9943	
+0xF079	0x9944	
+0xF07A	0x9945	
+0xF07B	0x9946	
+0xF07C	0x9947	
+0xF07D	0x9948	
+0xF07E	0x9949	
+0xF080	0x994A	
+0xF081	0x994B	
+0xF082	0x994C	
+0xF083	0x994D	
+0xF084	0x994E	
+0xF085	0x994F	
+0xF086	0x9950	
+0xF087	0x9951	
+0xF088	0x9952	
+0xF089	0x9953	
+0xF08A	0x9956	
+0xF08B	0x9957	
+0xF08C	0x9958	
+0xF08D	0x9959	
+0xF08E	0x995A	
+0xF08F	0x995B	
+0xF090	0x995C	
+0xF091	0x995D	
+0xF092	0x995E	
+0xF093	0x995F	
+0xF094	0x9960	
+0xF095	0x9961	
+0xF096	0x9962	
+0xF097	0x9964	
+0xF098	0x9966	
+0xF099	0x9973	
+0xF09A	0x9978	
+0xF09B	0x9979	
+0xF09C	0x997B	
+0xF09D	0x997E	
+0xF09E	0x9982	
+0xF09F	0x9983	
+0xF0A0	0x9989	
+0xF0A1	0x7A39	
+0xF0A2	0x7A37	
+0xF0A3	0x7A51	
+0xF0A4	0x9ECF	
+0xF0A5	0x99A5	
+0xF0A6	0x7A70	
+0xF0A7	0x7688	
+0xF0A8	0x768E	
+0xF0A9	0x7693	
+0xF0AA	0x7699	
+0xF0AB	0x76A4	
+0xF0AC	0x74DE	
+0xF0AD	0x74E0	
+0xF0AE	0x752C	
+0xF0AF	0x9E20	
+0xF0B0	0x9E22	
+0xF0B1	0x9E28	
+0xF0B2	0x9E29	
+0xF0B3	0x9E2A	
+0xF0B4	0x9E2B	
+0xF0B5	0x9E2C	
+0xF0B6	0x9E32	
+0xF0B7	0x9E31	
+0xF0B8	0x9E36	
+0xF0B9	0x9E38	
+0xF0BA	0x9E37	
+0xF0BB	0x9E39	
+0xF0BC	0x9E3A	
+0xF0BD	0x9E3E	
+0xF0BE	0x9E41	
+0xF0BF	0x9E42	
+0xF0C0	0x9E44	
+0xF0C1	0x9E46	
+0xF0C2	0x9E47	
+0xF0C3	0x9E48	
+0xF0C4	0x9E49	
+0xF0C5	0x9E4B	
+0xF0C6	0x9E4C	
+0xF0C7	0x9E4E	
+0xF0C8	0x9E51	
+0xF0C9	0x9E55	
+0xF0CA	0x9E57	
+0xF0CB	0x9E5A	
+0xF0CC	0x9E5B	
+0xF0CD	0x9E5C	
+0xF0CE	0x9E5E	
+0xF0CF	0x9E63	
+0xF0D0	0x9E66	
+0xF0D1	0x9E67	
+0xF0D2	0x9E68	
+0xF0D3	0x9E69	
+0xF0D4	0x9E6A	
+0xF0D5	0x9E6B	
+0xF0D6	0x9E6C	
+0xF0D7	0x9E71	
+0xF0D8	0x9E6D	
+0xF0D9	0x9E73	
+0xF0DA	0x7592	
+0xF0DB	0x7594	
+0xF0DC	0x7596	
+0xF0DD	0x75A0	
+0xF0DE	0x759D	
+0xF0DF	0x75AC	
+0xF0E0	0x75A3	
+0xF0E1	0x75B3	
+0xF0E2	0x75B4	
+0xF0E3	0x75B8	
+0xF0E4	0x75C4	
+0xF0E5	0x75B1	
+0xF0E6	0x75B0	
+0xF0E7	0x75C3	
+0xF0E8	0x75C2	
+0xF0E9	0x75D6	
+0xF0EA	0x75CD	
+0xF0EB	0x75E3	
+0xF0EC	0x75E8	
+0xF0ED	0x75E6	
+0xF0EE	0x75E4	
+0xF0EF	0x75EB	
+0xF0F0	0x75E7	
+0xF0F1	0x7603	
+0xF0F2	0x75F1	
+0xF0F3	0x75FC	
+0xF0F4	0x75FF	
+0xF0F5	0x7610	
+0xF0F6	0x7600	
+0xF0F7	0x7605	
+0xF0F8	0x760C	
+0xF0F9	0x7617	
+0xF0FA	0x760A	
+0xF0FB	0x7625	
+0xF0FC	0x7618	
+0xF0FD	0x7615	
+0xF0FE	0x7619	
+0xF140	0x998C	
+0xF141	0x998E	
+0xF142	0x999A	
+0xF143	0x999B	
+0xF144	0x999C	
+0xF145	0x999D	
+0xF146	0x999E	
+0xF147	0x999F	
+0xF148	0x99A0	
+0xF149	0x99A1	
+0xF14A	0x99A2	
+0xF14B	0x99A3	
+0xF14C	0x99A4	
+0xF14D	0x99A6	
+0xF14E	0x99A7	
+0xF14F	0x99A9	
+0xF150	0x99AA	
+0xF151	0x99AB	
+0xF152	0x99AC	
+0xF153	0x99AD	
+0xF154	0x99AE	
+0xF155	0x99AF	
+0xF156	0x99B0	
+0xF157	0x99B1	
+0xF158	0x99B2	
+0xF159	0x99B3	
+0xF15A	0x99B4	
+0xF15B	0x99B5	
+0xF15C	0x99B6	
+0xF15D	0x99B7	
+0xF15E	0x99B8	
+0xF15F	0x99B9	
+0xF160	0x99BA	
+0xF161	0x99BB	
+0xF162	0x99BC	
+0xF163	0x99BD	
+0xF164	0x99BE	
+0xF165	0x99BF	
+0xF166	0x99C0	
+0xF167	0x99C1	
+0xF168	0x99C2	
+0xF169	0x99C3	
+0xF16A	0x99C4	
+0xF16B	0x99C5	
+0xF16C	0x99C6	
+0xF16D	0x99C7	
+0xF16E	0x99C8	
+0xF16F	0x99C9	
+0xF170	0x99CA	
+0xF171	0x99CB	
+0xF172	0x99CC	
+0xF173	0x99CD	
+0xF174	0x99CE	
+0xF175	0x99CF	
+0xF176	0x99D0	
+0xF177	0x99D1	
+0xF178	0x99D2	
+0xF179	0x99D3	
+0xF17A	0x99D4	
+0xF17B	0x99D5	
+0xF17C	0x99D6	
+0xF17D	0x99D7	
+0xF17E	0x99D8	
+0xF180	0x99D9	
+0xF181	0x99DA	
+0xF182	0x99DB	
+0xF183	0x99DC	
+0xF184	0x99DD	
+0xF185	0x99DE	
+0xF186	0x99DF	
+0xF187	0x99E0	
+0xF188	0x99E1	
+0xF189	0x99E2	
+0xF18A	0x99E3	
+0xF18B	0x99E4	
+0xF18C	0x99E5	
+0xF18D	0x99E6	
+0xF18E	0x99E7	
+0xF18F	0x99E8	
+0xF190	0x99E9	
+0xF191	0x99EA	
+0xF192	0x99EB	
+0xF193	0x99EC	
+0xF194	0x99ED	
+0xF195	0x99EE	
+0xF196	0x99EF	
+0xF197	0x99F0	
+0xF198	0x99F1	
+0xF199	0x99F2	
+0xF19A	0x99F3	
+0xF19B	0x99F4	
+0xF19C	0x99F5	
+0xF19D	0x99F6	
+0xF19E	0x99F7	
+0xF19F	0x99F8	
+0xF1A0	0x99F9	
+0xF1A1	0x761B	
+0xF1A2	0x763C	
+0xF1A3	0x7622	
+0xF1A4	0x7620	
+0xF1A5	0x7640	
+0xF1A6	0x762D	
+0xF1A7	0x7630	
+0xF1A8	0x763F	
+0xF1A9	0x7635	
+0xF1AA	0x7643	
+0xF1AB	0x763E	
+0xF1AC	0x7633	
+0xF1AD	0x764D	
+0xF1AE	0x765E	
+0xF1AF	0x7654	
+0xF1B0	0x765C	
+0xF1B1	0x7656	
+0xF1B2	0x766B	
+0xF1B3	0x766F	
+0xF1B4	0x7FCA	
+0xF1B5	0x7AE6	
+0xF1B6	0x7A78	
+0xF1B7	0x7A79	
+0xF1B8	0x7A80	
+0xF1B9	0x7A86	
+0xF1BA	0x7A88	
+0xF1BB	0x7A95	
+0xF1BC	0x7AA6	
+0xF1BD	0x7AA0	
+0xF1BE	0x7AAC	
+0xF1BF	0x7AA8	
+0xF1C0	0x7AAD	
+0xF1C1	0x7AB3	
+0xF1C2	0x8864	
+0xF1C3	0x8869	
+0xF1C4	0x8872	
+0xF1C5	0x887D	
+0xF1C6	0x887F	
+0xF1C7	0x8882	
+0xF1C8	0x88A2	
+0xF1C9	0x88C6	
+0xF1CA	0x88B7	
+0xF1CB	0x88BC	
+0xF1CC	0x88C9	
+0xF1CD	0x88E2	
+0xF1CE	0x88CE	
+0xF1CF	0x88E3	
+0xF1D0	0x88E5	
+0xF1D1	0x88F1	
+0xF1D2	0x891A	
+0xF1D3	0x88FC	
+0xF1D4	0x88E8	
+0xF1D5	0x88FE	
+0xF1D6	0x88F0	
+0xF1D7	0x8921	
+0xF1D8	0x8919	
+0xF1D9	0x8913	
+0xF1DA	0x891B	
+0xF1DB	0x890A	
+0xF1DC	0x8934	
+0xF1DD	0x892B	
+0xF1DE	0x8936	
+0xF1DF	0x8941	
+0xF1E0	0x8966	
+0xF1E1	0x897B	
+0xF1E2	0x758B	
+0xF1E3	0x80E5	
+0xF1E4	0x76B2	
+0xF1E5	0x76B4	
+0xF1E6	0x77DC	
+0xF1E7	0x8012	
+0xF1E8	0x8014	
+0xF1E9	0x8016	
+0xF1EA	0x801C	
+0xF1EB	0x8020	
+0xF1EC	0x8022	
+0xF1ED	0x8025	
+0xF1EE	0x8026	
+0xF1EF	0x8027	
+0xF1F0	0x8029	
+0xF1F1	0x8028	
+0xF1F2	0x8031	
+0xF1F3	0x800B	
+0xF1F4	0x8035	
+0xF1F5	0x8043	
+0xF1F6	0x8046	
+0xF1F7	0x804D	
+0xF1F8	0x8052	
+0xF1F9	0x8069	
+0xF1FA	0x8071	
+0xF1FB	0x8983	
+0xF1FC	0x9878	
+0xF1FD	0x9880	
+0xF1FE	0x9883	
+0xF240	0x99FA	
+0xF241	0x99FB	
+0xF242	0x99FC	
+0xF243	0x99FD	
+0xF244	0x99FE	
+0xF245	0x99FF	
+0xF246	0x9A00	
+0xF247	0x9A01	
+0xF248	0x9A02	
+0xF249	0x9A03	
+0xF24A	0x9A04	
+0xF24B	0x9A05	
+0xF24C	0x9A06	
+0xF24D	0x9A07	
+0xF24E	0x9A08	
+0xF24F	0x9A09	
+0xF250	0x9A0A	
+0xF251	0x9A0B	
+0xF252	0x9A0C	
+0xF253	0x9A0D	
+0xF254	0x9A0E	
+0xF255	0x9A0F	
+0xF256	0x9A10	
+0xF257	0x9A11	
+0xF258	0x9A12	
+0xF259	0x9A13	
+0xF25A	0x9A14	
+0xF25B	0x9A15	
+0xF25C	0x9A16	
+0xF25D	0x9A17	
+0xF25E	0x9A18	
+0xF25F	0x9A19	
+0xF260	0x9A1A	
+0xF261	0x9A1B	
+0xF262	0x9A1C	
+0xF263	0x9A1D	
+0xF264	0x9A1E	
+0xF265	0x9A1F	
+0xF266	0x9A20	
+0xF267	0x9A21	
+0xF268	0x9A22	
+0xF269	0x9A23	
+0xF26A	0x9A24	
+0xF26B	0x9A25	
+0xF26C	0x9A26	
+0xF26D	0x9A27	
+0xF26E	0x9A28	
+0xF26F	0x9A29	
+0xF270	0x9A2A	
+0xF271	0x9A2B	
+0xF272	0x9A2C	
+0xF273	0x9A2D	
+0xF274	0x9A2E	
+0xF275	0x9A2F	
+0xF276	0x9A30	
+0xF277	0x9A31	
+0xF278	0x9A32	
+0xF279	0x9A33	
+0xF27A	0x9A34	
+0xF27B	0x9A35	
+0xF27C	0x9A36	
+0xF27D	0x9A37	
+0xF27E	0x9A38	
+0xF280	0x9A39	
+0xF281	0x9A3A	
+0xF282	0x9A3B	
+0xF283	0x9A3C	
+0xF284	0x9A3D	
+0xF285	0x9A3E	
+0xF286	0x9A3F	
+0xF287	0x9A40	
+0xF288	0x9A41	
+0xF289	0x9A42	
+0xF28A	0x9A43	
+0xF28B	0x9A44	
+0xF28C	0x9A45	
+0xF28D	0x9A46	
+0xF28E	0x9A47	
+0xF28F	0x9A48	
+0xF290	0x9A49	
+0xF291	0x9A4A	
+0xF292	0x9A4B	
+0xF293	0x9A4C	
+0xF294	0x9A4D	
+0xF295	0x9A4E	
+0xF296	0x9A4F	
+0xF297	0x9A50	
+0xF298	0x9A51	
+0xF299	0x9A52	
+0xF29A	0x9A53	
+0xF29B	0x9A54	
+0xF29C	0x9A55	
+0xF29D	0x9A56	
+0xF29E	0x9A57	
+0xF29F	0x9A58	
+0xF2A0	0x9A59	
+0xF2A1	0x9889	
+0xF2A2	0x988C	
+0xF2A3	0x988D	
+0xF2A4	0x988F	
+0xF2A5	0x9894	
+0xF2A6	0x989A	
+0xF2A7	0x989B	
+0xF2A8	0x989E	
+0xF2A9	0x989F	
+0xF2AA	0x98A1	
+0xF2AB	0x98A2	
+0xF2AC	0x98A5	
+0xF2AD	0x98A6	
+0xF2AE	0x864D	
+0xF2AF	0x8654	
+0xF2B0	0x866C	
+0xF2B1	0x866E	
+0xF2B2	0x867F	
+0xF2B3	0x867A	
+0xF2B4	0x867C	
+0xF2B5	0x867B	
+0xF2B6	0x86A8	
+0xF2B7	0x868D	
+0xF2B8	0x868B	
+0xF2B9	0x86AC	
+0xF2BA	0x869D	
+0xF2BB	0x86A7	
+0xF2BC	0x86A3	
+0xF2BD	0x86AA	
+0xF2BE	0x8693	
+0xF2BF	0x86A9	
+0xF2C0	0x86B6	
+0xF2C1	0x86C4	
+0xF2C2	0x86B5	
+0xF2C3	0x86CE	
+0xF2C4	0x86B0	
+0xF2C5	0x86BA	
+0xF2C6	0x86B1	
+0xF2C7	0x86AF	
+0xF2C8	0x86C9	
+0xF2C9	0x86CF	
+0xF2CA	0x86B4	
+0xF2CB	0x86E9	
+0xF2CC	0x86F1	
+0xF2CD	0x86F2	
+0xF2CE	0x86ED	
+0xF2CF	0x86F3	
+0xF2D0	0x86D0	
+0xF2D1	0x8713	
+0xF2D2	0x86DE	
+0xF2D3	0x86F4	
+0xF2D4	0x86DF	
+0xF2D5	0x86D8	
+0xF2D6	0x86D1	
+0xF2D7	0x8703	
+0xF2D8	0x8707	
+0xF2D9	0x86F8	
+0xF2DA	0x8708	
+0xF2DB	0x870A	
+0xF2DC	0x870D	
+0xF2DD	0x8709	
+0xF2DE	0x8723	
+0xF2DF	0x873B	
+0xF2E0	0x871E	
+0xF2E1	0x8725	
+0xF2E2	0x872E	
+0xF2E3	0x871A	
+0xF2E4	0x873E	
+0xF2E5	0x8748	
+0xF2E6	0x8734	
+0xF2E7	0x8731	
+0xF2E8	0x8729	
+0xF2E9	0x8737	
+0xF2EA	0x873F	
+0xF2EB	0x8782	
+0xF2EC	0x8722	
+0xF2ED	0x877D	
+0xF2EE	0x877E	
+0xF2EF	0x877B	
+0xF2F0	0x8760	
+0xF2F1	0x8770	
+0xF2F2	0x874C	
+0xF2F3	0x876E	
+0xF2F4	0x878B	
+0xF2F5	0x8753	
+0xF2F6	0x8763	
+0xF2F7	0x877C	
+0xF2F8	0x8764	
+0xF2F9	0x8759	
+0xF2FA	0x8765	
+0xF2FB	0x8793	
+0xF2FC	0x87AF	
+0xF2FD	0x87A8	
+0xF2FE	0x87D2	
+0xF340	0x9A5A	
+0xF341	0x9A5B	
+0xF342	0x9A5C	
+0xF343	0x9A5D	
+0xF344	0x9A5E	
+0xF345	0x9A5F	
+0xF346	0x9A60	
+0xF347	0x9A61	
+0xF348	0x9A62	
+0xF349	0x9A63	
+0xF34A	0x9A64	
+0xF34B	0x9A65	
+0xF34C	0x9A66	
+0xF34D	0x9A67	
+0xF34E	0x9A68	
+0xF34F	0x9A69	
+0xF350	0x9A6A	
+0xF351	0x9A6B	
+0xF352	0x9A72	
+0xF353	0x9A83	
+0xF354	0x9A89	
+0xF355	0x9A8D	
+0xF356	0x9A8E	
+0xF357	0x9A94	
+0xF358	0x9A95	
+0xF359	0x9A99	
+0xF35A	0x9AA6	
+0xF35B	0x9AA9	
+0xF35C	0x9AAA	
+0xF35D	0x9AAB	
+0xF35E	0x9AAC	
+0xF35F	0x9AAD	
+0xF360	0x9AAE	
+0xF361	0x9AAF	
+0xF362	0x9AB2	
+0xF363	0x9AB3	
+0xF364	0x9AB4	
+0xF365	0x9AB5	
+0xF366	0x9AB9	
+0xF367	0x9ABB	
+0xF368	0x9ABD	
+0xF369	0x9ABE	
+0xF36A	0x9ABF	
+0xF36B	0x9AC3	
+0xF36C	0x9AC4	
+0xF36D	0x9AC6	
+0xF36E	0x9AC7	
+0xF36F	0x9AC8	
+0xF370	0x9AC9	
+0xF371	0x9ACA	
+0xF372	0x9ACD	
+0xF373	0x9ACE	
+0xF374	0x9ACF	
+0xF375	0x9AD0	
+0xF376	0x9AD2	
+0xF377	0x9AD4	
+0xF378	0x9AD5	
+0xF379	0x9AD6	
+0xF37A	0x9AD7	
+0xF37B	0x9AD9	
+0xF37C	0x9ADA	
+0xF37D	0x9ADB	
+0xF37E	0x9ADC	
+0xF380	0x9ADD	
+0xF381	0x9ADE	
+0xF382	0x9AE0	
+0xF383	0x9AE2	
+0xF384	0x9AE3	
+0xF385	0x9AE4	
+0xF386	0x9AE5	
+0xF387	0x9AE7	
+0xF388	0x9AE8	
+0xF389	0x9AE9	
+0xF38A	0x9AEA	
+0xF38B	0x9AEC	
+0xF38C	0x9AEE	
+0xF38D	0x9AF0	
+0xF38E	0x9AF1	
+0xF38F	0x9AF2	
+0xF390	0x9AF3	
+0xF391	0x9AF4	
+0xF392	0x9AF5	
+0xF393	0x9AF6	
+0xF394	0x9AF7	
+0xF395	0x9AF8	
+0xF396	0x9AFA	
+0xF397	0x9AFC	
+0xF398	0x9AFD	
+0xF399	0x9AFE	
+0xF39A	0x9AFF	
+0xF39B	0x9B00	
+0xF39C	0x9B01	
+0xF39D	0x9B02	
+0xF39E	0x9B04	
+0xF39F	0x9B05	
+0xF3A0	0x9B06	
+0xF3A1	0x87C6	
+0xF3A2	0x8788	
+0xF3A3	0x8785	
+0xF3A4	0x87AD	
+0xF3A5	0x8797	
+0xF3A6	0x8783	
+0xF3A7	0x87AB	
+0xF3A8	0x87E5	
+0xF3A9	0x87AC	
+0xF3AA	0x87B5	
+0xF3AB	0x87B3	
+0xF3AC	0x87CB	
+0xF3AD	0x87D3	
+0xF3AE	0x87BD	
+0xF3AF	0x87D1	
+0xF3B0	0x87C0	
+0xF3B1	0x87CA	
+0xF3B2	0x87DB	
+0xF3B3	0x87EA	
+0xF3B4	0x87E0	
+0xF3B5	0x87EE	
+0xF3B6	0x8816	
+0xF3B7	0x8813	
+0xF3B8	0x87FE	
+0xF3B9	0x880A	
+0xF3BA	0x881B	
+0xF3BB	0x8821	
+0xF3BC	0x8839	
+0xF3BD	0x883C	
+0xF3BE	0x7F36	
+0xF3BF	0x7F42	
+0xF3C0	0x7F44	
+0xF3C1	0x7F45	
+0xF3C2	0x8210	
+0xF3C3	0x7AFA	
+0xF3C4	0x7AFD	
+0xF3C5	0x7B08	
+0xF3C6	0x7B03	
+0xF3C7	0x7B04	
+0xF3C8	0x7B15	
+0xF3C9	0x7B0A	
+0xF3CA	0x7B2B	
+0xF3CB	0x7B0F	
+0xF3CC	0x7B47	
+0xF3CD	0x7B38	
+0xF3CE	0x7B2A	
+0xF3CF	0x7B19	
+0xF3D0	0x7B2E	
+0xF3D1	0x7B31	
+0xF3D2	0x7B20	
+0xF3D3	0x7B25	
+0xF3D4	0x7B24	
+0xF3D5	0x7B33	
+0xF3D6	0x7B3E	
+0xF3D7	0x7B1E	
+0xF3D8	0x7B58	
+0xF3D9	0x7B5A	
+0xF3DA	0x7B45	
+0xF3DB	0x7B75	
+0xF3DC	0x7B4C	
+0xF3DD	0x7B5D	
+0xF3DE	0x7B60	
+0xF3DF	0x7B6E	
+0xF3E0	0x7B7B	
+0xF3E1	0x7B62	
+0xF3E2	0x7B72	
+0xF3E3	0x7B71	
+0xF3E4	0x7B90	
+0xF3E5	0x7BA6	
+0xF3E6	0x7BA7	
+0xF3E7	0x7BB8	
+0xF3E8	0x7BAC	
+0xF3E9	0x7B9D	
+0xF3EA	0x7BA8	
+0xF3EB	0x7B85	
+0xF3EC	0x7BAA	
+0xF3ED	0x7B9C	
+0xF3EE	0x7BA2	
+0xF3EF	0x7BAB	
+0xF3F0	0x7BB4	
+0xF3F1	0x7BD1	
+0xF3F2	0x7BC1	
+0xF3F3	0x7BCC	
+0xF3F4	0x7BDD	
+0xF3F5	0x7BDA	
+0xF3F6	0x7BE5	
+0xF3F7	0x7BE6	
+0xF3F8	0x7BEA	
+0xF3F9	0x7C0C	
+0xF3FA	0x7BFE	
+0xF3FB	0x7BFC	
+0xF3FC	0x7C0F	
+0xF3FD	0x7C16	
+0xF3FE	0x7C0B	
+0xF440	0x9B07	
+0xF441	0x9B09	
+0xF442	0x9B0A	
+0xF443	0x9B0B	
+0xF444	0x9B0C	
+0xF445	0x9B0D	
+0xF446	0x9B0E	
+0xF447	0x9B10	
+0xF448	0x9B11	
+0xF449	0x9B12	
+0xF44A	0x9B14	
+0xF44B	0x9B15	
+0xF44C	0x9B16	
+0xF44D	0x9B17	
+0xF44E	0x9B18	
+0xF44F	0x9B19	
+0xF450	0x9B1A	
+0xF451	0x9B1B	
+0xF452	0x9B1C	
+0xF453	0x9B1D	
+0xF454	0x9B1E	
+0xF455	0x9B20	
+0xF456	0x9B21	
+0xF457	0x9B22	
+0xF458	0x9B24	
+0xF459	0x9B25	
+0xF45A	0x9B26	
+0xF45B	0x9B27	
+0xF45C	0x9B28	
+0xF45D	0x9B29	
+0xF45E	0x9B2A	
+0xF45F	0x9B2B	
+0xF460	0x9B2C	
+0xF461	0x9B2D	
+0xF462	0x9B2E	
+0xF463	0x9B30	
+0xF464	0x9B31	
+0xF465	0x9B33	
+0xF466	0x9B34	
+0xF467	0x9B35	
+0xF468	0x9B36	
+0xF469	0x9B37	
+0xF46A	0x9B38	
+0xF46B	0x9B39	
+0xF46C	0x9B3A	
+0xF46D	0x9B3D	
+0xF46E	0x9B3E	
+0xF46F	0x9B3F	
+0xF470	0x9B40	
+0xF471	0x9B46	
+0xF472	0x9B4A	
+0xF473	0x9B4B	
+0xF474	0x9B4C	
+0xF475	0x9B4E	
+0xF476	0x9B50	
+0xF477	0x9B52	
+0xF478	0x9B53	
+0xF479	0x9B55	
+0xF47A	0x9B56	
+0xF47B	0x9B57	
+0xF47C	0x9B58	
+0xF47D	0x9B59	
+0xF47E	0x9B5A	
+0xF480	0x9B5B	
+0xF481	0x9B5C	
+0xF482	0x9B5D	
+0xF483	0x9B5E	
+0xF484	0x9B5F	
+0xF485	0x9B60	
+0xF486	0x9B61	
+0xF487	0x9B62	
+0xF488	0x9B63	
+0xF489	0x9B64	
+0xF48A	0x9B65	
+0xF48B	0x9B66	
+0xF48C	0x9B67	
+0xF48D	0x9B68	
+0xF48E	0x9B69	
+0xF48F	0x9B6A	
+0xF490	0x9B6B	
+0xF491	0x9B6C	
+0xF492	0x9B6D	
+0xF493	0x9B6E	
+0xF494	0x9B6F	
+0xF495	0x9B70	
+0xF496	0x9B71	
+0xF497	0x9B72	
+0xF498	0x9B73	
+0xF499	0x9B74	
+0xF49A	0x9B75	
+0xF49B	0x9B76	
+0xF49C	0x9B77	
+0xF49D	0x9B78	
+0xF49E	0x9B79	
+0xF49F	0x9B7A	
+0xF4A0	0x9B7B	
+0xF4A1	0x7C1F	
+0xF4A2	0x7C2A	
+0xF4A3	0x7C26	
+0xF4A4	0x7C38	
+0xF4A5	0x7C41	
+0xF4A6	0x7C40	
+0xF4A7	0x81FE	
+0xF4A8	0x8201	
+0xF4A9	0x8202	
+0xF4AA	0x8204	
+0xF4AB	0x81EC	
+0xF4AC	0x8844	
+0xF4AD	0x8221	
+0xF4AE	0x8222	
+0xF4AF	0x8223	
+0xF4B0	0x822D	
+0xF4B1	0x822F	
+0xF4B2	0x8228	
+0xF4B3	0x822B	
+0xF4B4	0x8238	
+0xF4B5	0x823B	
+0xF4B6	0x8233	
+0xF4B7	0x8234	
+0xF4B8	0x823E	
+0xF4B9	0x8244	
+0xF4BA	0x8249	
+0xF4BB	0x824B	
+0xF4BC	0x824F	
+0xF4BD	0x825A	
+0xF4BE	0x825F	
+0xF4BF	0x8268	
+0xF4C0	0x887E	
+0xF4C1	0x8885	
+0xF4C2	0x8888	
+0xF4C3	0x88D8	
+0xF4C4	0x88DF	
+0xF4C5	0x895E	
+0xF4C6	0x7F9D	
+0xF4C7	0x7F9F	
+0xF4C8	0x7FA7	
+0xF4C9	0x7FAF	
+0xF4CA	0x7FB0	
+0xF4CB	0x7FB2	
+0xF4CC	0x7C7C	
+0xF4CD	0x6549	
+0xF4CE	0x7C91	
+0xF4CF	0x7C9D	
+0xF4D0	0x7C9C	
+0xF4D1	0x7C9E	
+0xF4D2	0x7CA2	
+0xF4D3	0x7CB2	
+0xF4D4	0x7CBC	
+0xF4D5	0x7CBD	
+0xF4D6	0x7CC1	
+0xF4D7	0x7CC7	
+0xF4D8	0x7CCC	
+0xF4D9	0x7CCD	
+0xF4DA	0x7CC8	
+0xF4DB	0x7CC5	
+0xF4DC	0x7CD7	
+0xF4DD	0x7CE8	
+0xF4DE	0x826E	
+0xF4DF	0x66A8	
+0xF4E0	0x7FBF	
+0xF4E1	0x7FCE	
+0xF4E2	0x7FD5	
+0xF4E3	0x7FE5	
+0xF4E4	0x7FE1	
+0xF4E5	0x7FE6	
+0xF4E6	0x7FE9	
+0xF4E7	0x7FEE	
+0xF4E8	0x7FF3	
+0xF4E9	0x7CF8	
+0xF4EA	0x7D77	
+0xF4EB	0x7DA6	
+0xF4EC	0x7DAE	
+0xF4ED	0x7E47	
+0xF4EE	0x7E9B	
+0xF4EF	0x9EB8	
+0xF4F0	0x9EB4	
+0xF4F1	0x8D73	
+0xF4F2	0x8D84	
+0xF4F3	0x8D94	
+0xF4F4	0x8D91	
+0xF4F5	0x8DB1	
+0xF4F6	0x8D67	
+0xF4F7	0x8D6D	
+0xF4F8	0x8C47	
+0xF4F9	0x8C49	
+0xF4FA	0x914A	
+0xF4FB	0x9150	
+0xF4FC	0x914E	
+0xF4FD	0x914F	
+0xF4FE	0x9164	
+0xF540	0x9B7C	
+0xF541	0x9B7D	
+0xF542	0x9B7E	
+0xF543	0x9B7F	
+0xF544	0x9B80	
+0xF545	0x9B81	
+0xF546	0x9B82	
+0xF547	0x9B83	
+0xF548	0x9B84	
+0xF549	0x9B85	
+0xF54A	0x9B86	
+0xF54B	0x9B87	
+0xF54C	0x9B88	
+0xF54D	0x9B89	
+0xF54E	0x9B8A	
+0xF54F	0x9B8B	
+0xF550	0x9B8C	
+0xF551	0x9B8D	
+0xF552	0x9B8E	
+0xF553	0x9B8F	
+0xF554	0x9B90	
+0xF555	0x9B91	
+0xF556	0x9B92	
+0xF557	0x9B93	
+0xF558	0x9B94	
+0xF559	0x9B95	
+0xF55A	0x9B96	
+0xF55B	0x9B97	
+0xF55C	0x9B98	
+0xF55D	0x9B99	
+0xF55E	0x9B9A	
+0xF55F	0x9B9B	
+0xF560	0x9B9C	
+0xF561	0x9B9D	
+0xF562	0x9B9E	
+0xF563	0x9B9F	
+0xF564	0x9BA0	
+0xF565	0x9BA1	
+0xF566	0x9BA2	
+0xF567	0x9BA3	
+0xF568	0x9BA4	
+0xF569	0x9BA5	
+0xF56A	0x9BA6	
+0xF56B	0x9BA7	
+0xF56C	0x9BA8	
+0xF56D	0x9BA9	
+0xF56E	0x9BAA	
+0xF56F	0x9BAB	
+0xF570	0x9BAC	
+0xF571	0x9BAD	
+0xF572	0x9BAE	
+0xF573	0x9BAF	
+0xF574	0x9BB0	
+0xF575	0x9BB1	
+0xF576	0x9BB2	
+0xF577	0x9BB3	
+0xF578	0x9BB4	
+0xF579	0x9BB5	
+0xF57A	0x9BB6	
+0xF57B	0x9BB7	
+0xF57C	0x9BB8	
+0xF57D	0x9BB9	
+0xF57E	0x9BBA	
+0xF580	0x9BBB	
+0xF581	0x9BBC	
+0xF582	0x9BBD	
+0xF583	0x9BBE	
+0xF584	0x9BBF	
+0xF585	0x9BC0	
+0xF586	0x9BC1	
+0xF587	0x9BC2	
+0xF588	0x9BC3	
+0xF589	0x9BC4	
+0xF58A	0x9BC5	
+0xF58B	0x9BC6	
+0xF58C	0x9BC7	
+0xF58D	0x9BC8	
+0xF58E	0x9BC9	
+0xF58F	0x9BCA	
+0xF590	0x9BCB	
+0xF591	0x9BCC	
+0xF592	0x9BCD	
+0xF593	0x9BCE	
+0xF594	0x9BCF	
+0xF595	0x9BD0	
+0xF596	0x9BD1	
+0xF597	0x9BD2	
+0xF598	0x9BD3	
+0xF599	0x9BD4	
+0xF59A	0x9BD5	
+0xF59B	0x9BD6	
+0xF59C	0x9BD7	
+0xF59D	0x9BD8	
+0xF59E	0x9BD9	
+0xF59F	0x9BDA	
+0xF5A0	0x9BDB	
+0xF5A1	0x9162	
+0xF5A2	0x9161	
+0xF5A3	0x9170	
+0xF5A4	0x9169	
+0xF5A5	0x916F	
+0xF5A6	0x917D	
+0xF5A7	0x917E	
+0xF5A8	0x9172	
+0xF5A9	0x9174	
+0xF5AA	0x9179	
+0xF5AB	0x918C	
+0xF5AC	0x9185	
+0xF5AD	0x9190	
+0xF5AE	0x918D	
+0xF5AF	0x9191	
+0xF5B0	0x91A2	
+0xF5B1	0x91A3	
+0xF5B2	0x91AA	
+0xF5B3	0x91AD	
+0xF5B4	0x91AE	
+0xF5B5	0x91AF	
+0xF5B6	0x91B5	
+0xF5B7	0x91B4	
+0xF5B8	0x91BA	
+0xF5B9	0x8C55	
+0xF5BA	0x9E7E	
+0xF5BB	0x8DB8	
+0xF5BC	0x8DEB	
+0xF5BD	0x8E05	
+0xF5BE	0x8E59	
+0xF5BF	0x8E69	
+0xF5C0	0x8DB5	
+0xF5C1	0x8DBF	
+0xF5C2	0x8DBC	
+0xF5C3	0x8DBA	
+0xF5C4	0x8DC4	
+0xF5C5	0x8DD6	
+0xF5C6	0x8DD7	
+0xF5C7	0x8DDA	
+0xF5C8	0x8DDE	
+0xF5C9	0x8DCE	
+0xF5CA	0x8DCF	
+0xF5CB	0x8DDB	
+0xF5CC	0x8DC6	
+0xF5CD	0x8DEC	
+0xF5CE	0x8DF7	
+0xF5CF	0x8DF8	
+0xF5D0	0x8DE3	
+0xF5D1	0x8DF9	
+0xF5D2	0x8DFB	
+0xF5D3	0x8DE4	
+0xF5D4	0x8E09	
+0xF5D5	0x8DFD	
+0xF5D6	0x8E14	
+0xF5D7	0x8E1D	
+0xF5D8	0x8E1F	
+0xF5D9	0x8E2C	
+0xF5DA	0x8E2E	
+0xF5DB	0x8E23	
+0xF5DC	0x8E2F	
+0xF5DD	0x8E3A	
+0xF5DE	0x8E40	
+0xF5DF	0x8E39	
+0xF5E0	0x8E35	
+0xF5E1	0x8E3D	
+0xF5E2	0x8E31	
+0xF5E3	0x8E49	
+0xF5E4	0x8E41	
+0xF5E5	0x8E42	
+0xF5E6	0x8E51	
+0xF5E7	0x8E52	
+0xF5E8	0x8E4A	
+0xF5E9	0x8E70	
+0xF5EA	0x8E76	
+0xF5EB	0x8E7C	
+0xF5EC	0x8E6F	
+0xF5ED	0x8E74	
+0xF5EE	0x8E85	
+0xF5EF	0x8E8F	
+0xF5F0	0x8E94	
+0xF5F1	0x8E90	
+0xF5F2	0x8E9C	
+0xF5F3	0x8E9E	
+0xF5F4	0x8C78	
+0xF5F5	0x8C82	
+0xF5F6	0x8C8A	
+0xF5F7	0x8C85	
+0xF5F8	0x8C98	
+0xF5F9	0x8C94	
+0xF5FA	0x659B	
+0xF5FB	0x89D6	
+0xF5FC	0x89DE	
+0xF5FD	0x89DA	
+0xF5FE	0x89DC	
+0xF640	0x9BDC	
+0xF641	0x9BDD	
+0xF642	0x9BDE	
+0xF643	0x9BDF	
+0xF644	0x9BE0	
+0xF645	0x9BE1	
+0xF646	0x9BE2	
+0xF647	0x9BE3	
+0xF648	0x9BE4	
+0xF649	0x9BE5	
+0xF64A	0x9BE6	
+0xF64B	0x9BE7	
+0xF64C	0x9BE8	
+0xF64D	0x9BE9	
+0xF64E	0x9BEA	
+0xF64F	0x9BEB	
+0xF650	0x9BEC	
+0xF651	0x9BED	
+0xF652	0x9BEE	
+0xF653	0x9BEF	
+0xF654	0x9BF0	
+0xF655	0x9BF1	
+0xF656	0x9BF2	
+0xF657	0x9BF3	
+0xF658	0x9BF4	
+0xF659	0x9BF5	
+0xF65A	0x9BF6	
+0xF65B	0x9BF7	
+0xF65C	0x9BF8	
+0xF65D	0x9BF9	
+0xF65E	0x9BFA	
+0xF65F	0x9BFB	
+0xF660	0x9BFC	
+0xF661	0x9BFD	
+0xF662	0x9BFE	
+0xF663	0x9BFF	
+0xF664	0x9C00	
+0xF665	0x9C01	
+0xF666	0x9C02	
+0xF667	0x9C03	
+0xF668	0x9C04	
+0xF669	0x9C05	
+0xF66A	0x9C06	
+0xF66B	0x9C07	
+0xF66C	0x9C08	
+0xF66D	0x9C09	
+0xF66E	0x9C0A	
+0xF66F	0x9C0B	
+0xF670	0x9C0C	
+0xF671	0x9C0D	
+0xF672	0x9C0E	
+0xF673	0x9C0F	
+0xF674	0x9C10	
+0xF675	0x9C11	
+0xF676	0x9C12	
+0xF677	0x9C13	
+0xF678	0x9C14	
+0xF679	0x9C15	
+0xF67A	0x9C16	
+0xF67B	0x9C17	
+0xF67C	0x9C18	
+0xF67D	0x9C19	
+0xF67E	0x9C1A	
+0xF680	0x9C1B	
+0xF681	0x9C1C	
+0xF682	0x9C1D	
+0xF683	0x9C1E	
+0xF684	0x9C1F	
+0xF685	0x9C20	
+0xF686	0x9C21	
+0xF687	0x9C22	
+0xF688	0x9C23	
+0xF689	0x9C24	
+0xF68A	0x9C25	
+0xF68B	0x9C26	
+0xF68C	0x9C27	
+0xF68D	0x9C28	
+0xF68E	0x9C29	
+0xF68F	0x9C2A	
+0xF690	0x9C2B	
+0xF691	0x9C2C	
+0xF692	0x9C2D	
+0xF693	0x9C2E	
+0xF694	0x9C2F	
+0xF695	0x9C30	
+0xF696	0x9C31	
+0xF697	0x9C32	
+0xF698	0x9C33	
+0xF699	0x9C34	
+0xF69A	0x9C35	
+0xF69B	0x9C36	
+0xF69C	0x9C37	
+0xF69D	0x9C38	
+0xF69E	0x9C39	
+0xF69F	0x9C3A	
+0xF6A0	0x9C3B	
+0xF6A1	0x89E5	
+0xF6A2	0x89EB	
+0xF6A3	0x89EF	
+0xF6A4	0x8A3E	
+0xF6A5	0x8B26	
+0xF6A6	0x9753	
+0xF6A7	0x96E9	
+0xF6A8	0x96F3	
+0xF6A9	0x96EF	
+0xF6AA	0x9706	
+0xF6AB	0x9701	
+0xF6AC	0x9708	
+0xF6AD	0x970F	
+0xF6AE	0x970E	
+0xF6AF	0x972A	
+0xF6B0	0x972D	
+0xF6B1	0x9730	
+0xF6B2	0x973E	
+0xF6B3	0x9F80	
+0xF6B4	0x9F83	
+0xF6B5	0x9F85	
+0xF6B6	0x9F86	
+0xF6B7	0x9F87	
+0xF6B8	0x9F88	
+0xF6B9	0x9F89	
+0xF6BA	0x9F8A	
+0xF6BB	0x9F8C	
+0xF6BC	0x9EFE	
+0xF6BD	0x9F0B	
+0xF6BE	0x9F0D	
+0xF6BF	0x96B9	
+0xF6C0	0x96BC	
+0xF6C1	0x96BD	
+0xF6C2	0x96CE	
+0xF6C3	0x96D2	
+0xF6C4	0x77BF	
+0xF6C5	0x96E0	
+0xF6C6	0x928E	
+0xF6C7	0x92AE	
+0xF6C8	0x92C8	
+0xF6C9	0x933E	
+0xF6CA	0x936A	
+0xF6CB	0x93CA	
+0xF6CC	0x938F	
+0xF6CD	0x943E	
+0xF6CE	0x946B	
+0xF6CF	0x9C7F	
+0xF6D0	0x9C82	
+0xF6D1	0x9C85	
+0xF6D2	0x9C86	
+0xF6D3	0x9C87	
+0xF6D4	0x9C88	
+0xF6D5	0x7A23	
+0xF6D6	0x9C8B	
+0xF6D7	0x9C8E	
+0xF6D8	0x9C90	
+0xF6D9	0x9C91	
+0xF6DA	0x9C92	
+0xF6DB	0x9C94	
+0xF6DC	0x9C95	
+0xF6DD	0x9C9A	
+0xF6DE	0x9C9B	
+0xF6DF	0x9C9E	
+0xF6E0	0x9C9F	
+0xF6E1	0x9CA0	
+0xF6E2	0x9CA1	
+0xF6E3	0x9CA2	
+0xF6E4	0x9CA3	
+0xF6E5	0x9CA5	
+0xF6E6	0x9CA6	
+0xF6E7	0x9CA7	
+0xF6E8	0x9CA8	
+0xF6E9	0x9CA9	
+0xF6EA	0x9CAB	
+0xF6EB	0x9CAD	
+0xF6EC	0x9CAE	
+0xF6ED	0x9CB0	
+0xF6EE	0x9CB1	
+0xF6EF	0x9CB2	
+0xF6F0	0x9CB3	
+0xF6F1	0x9CB4	
+0xF6F2	0x9CB5	
+0xF6F3	0x9CB6	
+0xF6F4	0x9CB7	
+0xF6F5	0x9CBA	
+0xF6F6	0x9CBB	
+0xF6F7	0x9CBC	
+0xF6F8	0x9CBD	
+0xF6F9	0x9CC4	
+0xF6FA	0x9CC5	
+0xF6FB	0x9CC6	
+0xF6FC	0x9CC7	
+0xF6FD	0x9CCA	
+0xF6FE	0x9CCB	
+0xF740	0x9C3C	
+0xF741	0x9C3D	
+0xF742	0x9C3E	
+0xF743	0x9C3F	
+0xF744	0x9C40	
+0xF745	0x9C41	
+0xF746	0x9C42	
+0xF747	0x9C43	
+0xF748	0x9C44	
+0xF749	0x9C45	
+0xF74A	0x9C46	
+0xF74B	0x9C47	
+0xF74C	0x9C48	
+0xF74D	0x9C49	
+0xF74E	0x9C4A	
+0xF74F	0x9C4B	
+0xF750	0x9C4C	
+0xF751	0x9C4D	
+0xF752	0x9C4E	
+0xF753	0x9C4F	
+0xF754	0x9C50	
+0xF755	0x9C51	
+0xF756	0x9C52	
+0xF757	0x9C53	
+0xF758	0x9C54	
+0xF759	0x9C55	
+0xF75A	0x9C56	
+0xF75B	0x9C57	
+0xF75C	0x9C58	
+0xF75D	0x9C59	
+0xF75E	0x9C5A	
+0xF75F	0x9C5B	
+0xF760	0x9C5C	
+0xF761	0x9C5D	
+0xF762	0x9C5E	
+0xF763	0x9C5F	
+0xF764	0x9C60	
+0xF765	0x9C61	
+0xF766	0x9C62	
+0xF767	0x9C63	
+0xF768	0x9C64	
+0xF769	0x9C65	
+0xF76A	0x9C66	
+0xF76B	0x9C67	
+0xF76C	0x9C68	
+0xF76D	0x9C69	
+0xF76E	0x9C6A	
+0xF76F	0x9C6B	
+0xF770	0x9C6C	
+0xF771	0x9C6D	
+0xF772	0x9C6E	
+0xF773	0x9C6F	
+0xF774	0x9C70	
+0xF775	0x9C71	
+0xF776	0x9C72	
+0xF777	0x9C73	
+0xF778	0x9C74	
+0xF779	0x9C75	
+0xF77A	0x9C76	
+0xF77B	0x9C77	
+0xF77C	0x9C78	
+0xF77D	0x9C79	
+0xF77E	0x9C7A	
+0xF780	0x9C7B	
+0xF781	0x9C7D	
+0xF782	0x9C7E	
+0xF783	0x9C80	
+0xF784	0x9C83	
+0xF785	0x9C84	
+0xF786	0x9C89	
+0xF787	0x9C8A	
+0xF788	0x9C8C	
+0xF789	0x9C8F	
+0xF78A	0x9C93	
+0xF78B	0x9C96	
+0xF78C	0x9C97	
+0xF78D	0x9C98	
+0xF78E	0x9C99	
+0xF78F	0x9C9D	
+0xF790	0x9CAA	
+0xF791	0x9CAC	
+0xF792	0x9CAF	
+0xF793	0x9CB9	
+0xF794	0x9CBE	
+0xF795	0x9CBF	
+0xF796	0x9CC0	
+0xF797	0x9CC1	
+0xF798	0x9CC2	
+0xF799	0x9CC8	
+0xF79A	0x9CC9	
+0xF79B	0x9CD1	
+0xF79C	0x9CD2	
+0xF79D	0x9CDA	
+0xF79E	0x9CDB	
+0xF79F	0x9CE0	
+0xF7A0	0x9CE1	
+0xF7A1	0x9CCC	
+0xF7A2	0x9CCD	
+0xF7A3	0x9CCE	
+0xF7A4	0x9CCF	
+0xF7A5	0x9CD0	
+0xF7A6	0x9CD3	
+0xF7A7	0x9CD4	
+0xF7A8	0x9CD5	
+0xF7A9	0x9CD7	
+0xF7AA	0x9CD8	
+0xF7AB	0x9CD9	
+0xF7AC	0x9CDC	
+0xF7AD	0x9CDD	
+0xF7AE	0x9CDF	
+0xF7AF	0x9CE2	
+0xF7B0	0x977C	
+0xF7B1	0x9785	
+0xF7B2	0x9791	
+0xF7B3	0x9792	
+0xF7B4	0x9794	
+0xF7B5	0x97AF	
+0xF7B6	0x97AB	
+0xF7B7	0x97A3	
+0xF7B8	0x97B2	
+0xF7B9	0x97B4	
+0xF7BA	0x9AB1	
+0xF7BB	0x9AB0	
+0xF7BC	0x9AB7	
+0xF7BD	0x9E58	
+0xF7BE	0x9AB6	
+0xF7BF	0x9ABA	
+0xF7C0	0x9ABC	
+0xF7C1	0x9AC1	
+0xF7C2	0x9AC0	
+0xF7C3	0x9AC5	
+0xF7C4	0x9AC2	
+0xF7C5	0x9ACB	
+0xF7C6	0x9ACC	
+0xF7C7	0x9AD1	
+0xF7C8	0x9B45	
+0xF7C9	0x9B43	
+0xF7CA	0x9B47	
+0xF7CB	0x9B49	
+0xF7CC	0x9B48	
+0xF7CD	0x9B4D	
+0xF7CE	0x9B51	
+0xF7CF	0x98E8	
+0xF7D0	0x990D	
+0xF7D1	0x992E	
+0xF7D2	0x9955	
+0xF7D3	0x9954	
+0xF7D4	0x9ADF	
+0xF7D5	0x9AE1	
+0xF7D6	0x9AE6	
+0xF7D7	0x9AEF	
+0xF7D8	0x9AEB	
+0xF7D9	0x9AFB	
+0xF7DA	0x9AED	
+0xF7DB	0x9AF9	
+0xF7DC	0x9B08	
+0xF7DD	0x9B0F	
+0xF7DE	0x9B13	
+0xF7DF	0x9B1F	
+0xF7E0	0x9B23	
+0xF7E1	0x9EBD	
+0xF7E2	0x9EBE	
+0xF7E3	0x7E3B	
+0xF7E4	0x9E82	
+0xF7E5	0x9E87	
+0xF7E6	0x9E88	
+0xF7E7	0x9E8B	
+0xF7E8	0x9E92	
+0xF7E9	0x93D6	
+0xF7EA	0x9E9D	
+0xF7EB	0x9E9F	
+0xF7EC	0x9EDB	
+0xF7ED	0x9EDC	
+0xF7EE	0x9EDD	
+0xF7EF	0x9EE0	
+0xF7F0	0x9EDF	
+0xF7F1	0x9EE2	
+0xF7F2	0x9EE9	
+0xF7F3	0x9EE7	
+0xF7F4	0x9EE5	
+0xF7F5	0x9EEA	
+0xF7F6	0x9EEF	
+0xF7F7	0x9F22	
+0xF7F8	0x9F2C	
+0xF7F9	0x9F2F	
+0xF7FA	0x9F39	
+0xF7FB	0x9F37	
+0xF7FC	0x9F3D	
+0xF7FD	0x9F3E	
+0xF7FE	0x9F44	
+0xF840	0x9CE3	
+0xF841	0x9CE4	
+0xF842	0x9CE5	
+0xF843	0x9CE6	
+0xF844	0x9CE7	
+0xF845	0x9CE8	
+0xF846	0x9CE9	
+0xF847	0x9CEA	
+0xF848	0x9CEB	
+0xF849	0x9CEC	
+0xF84A	0x9CED	
+0xF84B	0x9CEE	
+0xF84C	0x9CEF	
+0xF84D	0x9CF0	
+0xF84E	0x9CF1	
+0xF84F	0x9CF2	
+0xF850	0x9CF3	
+0xF851	0x9CF4	
+0xF852	0x9CF5	
+0xF853	0x9CF6	
+0xF854	0x9CF7	
+0xF855	0x9CF8	
+0xF856	0x9CF9	
+0xF857	0x9CFA	
+0xF858	0x9CFB	
+0xF859	0x9CFC	
+0xF85A	0x9CFD	
+0xF85B	0x9CFE	
+0xF85C	0x9CFF	
+0xF85D	0x9D00	
+0xF85E	0x9D01	
+0xF85F	0x9D02	
+0xF860	0x9D03	
+0xF861	0x9D04	
+0xF862	0x9D05	
+0xF863	0x9D06	
+0xF864	0x9D07	
+0xF865	0x9D08	
+0xF866	0x9D09	
+0xF867	0x9D0A	
+0xF868	0x9D0B	
+0xF869	0x9D0C	
+0xF86A	0x9D0D	
+0xF86B	0x9D0E	
+0xF86C	0x9D0F	
+0xF86D	0x9D10	
+0xF86E	0x9D11	
+0xF86F	0x9D12	
+0xF870	0x9D13	
+0xF871	0x9D14	
+0xF872	0x9D15	
+0xF873	0x9D16	
+0xF874	0x9D17	
+0xF875	0x9D18	
+0xF876	0x9D19	
+0xF877	0x9D1A	
+0xF878	0x9D1B	
+0xF879	0x9D1C	
+0xF87A	0x9D1D	
+0xF87B	0x9D1E	
+0xF87C	0x9D1F	
+0xF87D	0x9D20	
+0xF87E	0x9D21	
+0xF880	0x9D22	
+0xF881	0x9D23	
+0xF882	0x9D24	
+0xF883	0x9D25	
+0xF884	0x9D26	
+0xF885	0x9D27	
+0xF886	0x9D28	
+0xF887	0x9D29	
+0xF888	0x9D2A	
+0xF889	0x9D2B	
+0xF88A	0x9D2C	
+0xF88B	0x9D2D	
+0xF88C	0x9D2E	
+0xF88D	0x9D2F	
+0xF88E	0x9D30	
+0xF88F	0x9D31	
+0xF890	0x9D32	
+0xF891	0x9D33	
+0xF892	0x9D34	
+0xF893	0x9D35	
+0xF894	0x9D36	
+0xF895	0x9D37	
+0xF896	0x9D38	
+0xF897	0x9D39	
+0xF898	0x9D3A	
+0xF899	0x9D3B	
+0xF89A	0x9D3C	
+0xF89B	0x9D3D	
+0xF89C	0x9D3E	
+0xF89D	0x9D3F	
+0xF89E	0x9D40	
+0xF89F	0x9D41	
+0xF8A0	0x9D42	
+# 0xF8A1	 	
+# 0xF8A2	 	
+# 0xF8A3	 	
+# 0xF8A4	 	
+# 0xF8A5	 	
+# 0xF8A6	 	
+# 0xF8A7	 	
+# 0xF8A8	 	
+# 0xF8A9	 	
+# 0xF8AA	 	
+# 0xF8AB	 	
+# 0xF8AC	 	
+# 0xF8AD	 	
+# 0xF8AE	 	
+# 0xF8AF	 	
+# 0xF8B0	 	
+# 0xF8B1	 	
+# 0xF8B2	 	
+# 0xF8B3	 	
+# 0xF8B4	 	
+# 0xF8B5	 	
+# 0xF8B6	 	
+# 0xF8B7	 	
+# 0xF8B8	 	
+# 0xF8B9	 	
+# 0xF8BA	 	
+# 0xF8BB	 	
+# 0xF8BC	 	
+# 0xF8BD	 	
+# 0xF8BE	 	
+# 0xF8BF	 	
+# 0xF8C0	 	
+# 0xF8C1	 	
+# 0xF8C2	 	
+# 0xF8C3	 	
+# 0xF8C4	 	
+# 0xF8C5	 	
+# 0xF8C6	 	
+# 0xF8C7	 	
+# 0xF8C8	 	
+# 0xF8C9	 	
+# 0xF8CA	 	
+# 0xF8CB	 	
+# 0xF8CC	 	
+# 0xF8CD	 	
+# 0xF8CE	 	
+# 0xF8CF	 	
+# 0xF8D0	 	
+# 0xF8D1	 	
+# 0xF8D2	 	
+# 0xF8D3	 	
+# 0xF8D4	 	
+# 0xF8D5	 	
+# 0xF8D6	 	
+# 0xF8D7	 	
+# 0xF8D8	 	
+# 0xF8D9	 	
+# 0xF8DA	 	
+# 0xF8DB	 	
+# 0xF8DC	 	
+# 0xF8DD	 	
+# 0xF8DE	 	
+# 0xF8DF	 	
+# 0xF8E0	 	
+# 0xF8E1	 	
+# 0xF8E2	 	
+# 0xF8E3	 	
+# 0xF8E4	 	
+# 0xF8E5	 	
+# 0xF8E6	 	
+# 0xF8E7	 	
+# 0xF8E8	 	
+# 0xF8E9	 	
+# 0xF8EA	 	
+# 0xF8EB	 	
+# 0xF8EC	 	
+# 0xF8ED	 	
+# 0xF8EE	 	
+# 0xF8EF	 	
+# 0xF8F0	 	
+# 0xF8F1	 	
+# 0xF8F2	 	
+# 0xF8F3	 	
+# 0xF8F4	 	
+# 0xF8F5	 	
+# 0xF8F6	 	
+# 0xF8F7	 	
+# 0xF8F8	 	
+# 0xF8F9	 	
+# 0xF8FA	 	
+# 0xF8FB	 	
+# 0xF8FC	 	
+# 0xF8FD	 	
+# 0xF8FE	 	
+0xF940	0x9D43	
+0xF941	0x9D44	
+0xF942	0x9D45	
+0xF943	0x9D46	
+0xF944	0x9D47	
+0xF945	0x9D48	
+0xF946	0x9D49	
+0xF947	0x9D4A	
+0xF948	0x9D4B	
+0xF949	0x9D4C	
+0xF94A	0x9D4D	
+0xF94B	0x9D4E	
+0xF94C	0x9D4F	
+0xF94D	0x9D50	
+0xF94E	0x9D51	
+0xF94F	0x9D52	
+0xF950	0x9D53	
+0xF951	0x9D54	
+0xF952	0x9D55	
+0xF953	0x9D56	
+0xF954	0x9D57	
+0xF955	0x9D58	
+0xF956	0x9D59	
+0xF957	0x9D5A	
+0xF958	0x9D5B	
+0xF959	0x9D5C	
+0xF95A	0x9D5D	
+0xF95B	0x9D5E	
+0xF95C	0x9D5F	
+0xF95D	0x9D60	
+0xF95E	0x9D61	
+0xF95F	0x9D62	
+0xF960	0x9D63	
+0xF961	0x9D64	
+0xF962	0x9D65	
+0xF963	0x9D66	
+0xF964	0x9D67	
+0xF965	0x9D68	
+0xF966	0x9D69	
+0xF967	0x9D6A	
+0xF968	0x9D6B	
+0xF969	0x9D6C	
+0xF96A	0x9D6D	
+0xF96B	0x9D6E	
+0xF96C	0x9D6F	
+0xF96D	0x9D70	
+0xF96E	0x9D71	
+0xF96F	0x9D72	
+0xF970	0x9D73	
+0xF971	0x9D74	
+0xF972	0x9D75	
+0xF973	0x9D76	
+0xF974	0x9D77	
+0xF975	0x9D78	
+0xF976	0x9D79	
+0xF977	0x9D7A	
+0xF978	0x9D7B	
+0xF979	0x9D7C	
+0xF97A	0x9D7D	
+0xF97B	0x9D7E	
+0xF97C	0x9D7F	
+0xF97D	0x9D80	
+0xF97E	0x9D81	
+0xF980	0x9D82	
+0xF981	0x9D83	
+0xF982	0x9D84	
+0xF983	0x9D85	
+0xF984	0x9D86	
+0xF985	0x9D87	
+0xF986	0x9D88	
+0xF987	0x9D89	
+0xF988	0x9D8A	
+0xF989	0x9D8B	
+0xF98A	0x9D8C	
+0xF98B	0x9D8D	
+0xF98C	0x9D8E	
+0xF98D	0x9D8F	
+0xF98E	0x9D90	
+0xF98F	0x9D91	
+0xF990	0x9D92	
+0xF991	0x9D93	
+0xF992	0x9D94	
+0xF993	0x9D95	
+0xF994	0x9D96	
+0xF995	0x9D97	
+0xF996	0x9D98	
+0xF997	0x9D99	
+0xF998	0x9D9A	
+0xF999	0x9D9B	
+0xF99A	0x9D9C	
+0xF99B	0x9D9D	
+0xF99C	0x9D9E	
+0xF99D	0x9D9F	
+0xF99E	0x9DA0	
+0xF99F	0x9DA1	
+0xF9A0	0x9DA2	
+# 0xF9A1	 	
+# 0xF9A2	 	
+# 0xF9A3	 	
+# 0xF9A4	 	
+# 0xF9A5	 	
+# 0xF9A6	 	
+# 0xF9A7	 	
+# 0xF9A8	 	
+# 0xF9A9	 	
+# 0xF9AA	 	
+# 0xF9AB	 	
+# 0xF9AC	 	
+# 0xF9AD	 	
+# 0xF9AE	 	
+# 0xF9AF	 	
+# 0xF9B0	 	
+# 0xF9B1	 	
+# 0xF9B2	 	
+# 0xF9B3	 	
+# 0xF9B4	 	
+# 0xF9B5	 	
+# 0xF9B6	 	
+# 0xF9B7	 	
+# 0xF9B8	 	
+# 0xF9B9	 	
+# 0xF9BA	 	
+# 0xF9BB	 	
+# 0xF9BC	 	
+# 0xF9BD	 	
+# 0xF9BE	 	
+# 0xF9BF	 	
+# 0xF9C0	 	
+# 0xF9C1	 	
+# 0xF9C2	 	
+# 0xF9C3	 	
+# 0xF9C4	 	
+# 0xF9C5	 	
+# 0xF9C6	 	
+# 0xF9C7	 	
+# 0xF9C8	 	
+# 0xF9C9	 	
+# 0xF9CA	 	
+# 0xF9CB	 	
+# 0xF9CC	 	
+# 0xF9CD	 	
+# 0xF9CE	 	
+# 0xF9CF	 	
+# 0xF9D0	 	
+# 0xF9D1	 	
+# 0xF9D2	 	
+# 0xF9D3	 	
+# 0xF9D4	 	
+# 0xF9D5	 	
+# 0xF9D6	 	
+# 0xF9D7	 	
+# 0xF9D8	 	
+# 0xF9D9	 	
+# 0xF9DA	 	
+# 0xF9DB	 	
+# 0xF9DC	 	
+# 0xF9DD	 	
+# 0xF9DE	 	
+# 0xF9DF	 	
+# 0xF9E0	 	
+# 0xF9E1	 	
+# 0xF9E2	 	
+# 0xF9E3	 	
+# 0xF9E4	 	
+# 0xF9E5	 	
+# 0xF9E6	 	
+# 0xF9E7	 	
+# 0xF9E8	 	
+# 0xF9E9	 	
+# 0xF9EA	 	
+# 0xF9EB	 	
+# 0xF9EC	 	
+# 0xF9ED	 	
+# 0xF9EE	 	
+# 0xF9EF	 	
+# 0xF9F0	 	
+# 0xF9F1	 	
+# 0xF9F2	 	
+# 0xF9F3	 	
+# 0xF9F4	 	
+# 0xF9F5	 	
+# 0xF9F6	 	
+# 0xF9F7	 	
+# 0xF9F8	 	
+# 0xF9F9	 	
+# 0xF9FA	 	
+# 0xF9FB	 	
+# 0xF9FC	 	
+# 0xF9FD	 	
+# 0xF9FE	 	
+0xFA40	0x9DA3	
+0xFA41	0x9DA4	
+0xFA42	0x9DA5	
+0xFA43	0x9DA6	
+0xFA44	0x9DA7	
+0xFA45	0x9DA8	
+0xFA46	0x9DA9	
+0xFA47	0x9DAA	
+0xFA48	0x9DAB	
+0xFA49	0x9DAC	
+0xFA4A	0x9DAD	
+0xFA4B	0x9DAE	
+0xFA4C	0x9DAF	
+0xFA4D	0x9DB0	
+0xFA4E	0x9DB1	
+0xFA4F	0x9DB2	
+0xFA50	0x9DB3	
+0xFA51	0x9DB4	
+0xFA52	0x9DB5	
+0xFA53	0x9DB6	
+0xFA54	0x9DB7	
+0xFA55	0x9DB8	
+0xFA56	0x9DB9	
+0xFA57	0x9DBA	
+0xFA58	0x9DBB	
+0xFA59	0x9DBC	
+0xFA5A	0x9DBD	
+0xFA5B	0x9DBE	
+0xFA5C	0x9DBF	
+0xFA5D	0x9DC0	
+0xFA5E	0x9DC1	
+0xFA5F	0x9DC2	
+0xFA60	0x9DC3	
+0xFA61	0x9DC4	
+0xFA62	0x9DC5	
+0xFA63	0x9DC6	
+0xFA64	0x9DC7	
+0xFA65	0x9DC8	
+0xFA66	0x9DC9	
+0xFA67	0x9DCA	
+0xFA68	0x9DCB	
+0xFA69	0x9DCC	
+0xFA6A	0x9DCD	
+0xFA6B	0x9DCE	
+0xFA6C	0x9DCF	
+0xFA6D	0x9DD0	
+0xFA6E	0x9DD1	
+0xFA6F	0x9DD2	
+0xFA70	0x9DD3	
+0xFA71	0x9DD4	
+0xFA72	0x9DD5	
+0xFA73	0x9DD6	
+0xFA74	0x9DD7	
+0xFA75	0x9DD8	
+0xFA76	0x9DD9	
+0xFA77	0x9DDA	
+0xFA78	0x9DDB	
+0xFA79	0x9DDC	
+0xFA7A	0x9DDD	
+0xFA7B	0x9DDE	
+0xFA7C	0x9DDF	
+0xFA7D	0x9DE0	
+0xFA7E	0x9DE1	
+0xFA80	0x9DE2	
+0xFA81	0x9DE3	
+0xFA82	0x9DE4	
+0xFA83	0x9DE5	
+0xFA84	0x9DE6	
+0xFA85	0x9DE7	
+0xFA86	0x9DE8	
+0xFA87	0x9DE9	
+0xFA88	0x9DEA	
+0xFA89	0x9DEB	
+0xFA8A	0x9DEC	
+0xFA8B	0x9DED	
+0xFA8C	0x9DEE	
+0xFA8D	0x9DEF	
+0xFA8E	0x9DF0	
+0xFA8F	0x9DF1	
+0xFA90	0x9DF2	
+0xFA91	0x9DF3	
+0xFA92	0x9DF4	
+0xFA93	0x9DF5	
+0xFA94	0x9DF6	
+0xFA95	0x9DF7	
+0xFA96	0x9DF8	
+0xFA97	0x9DF9	
+0xFA98	0x9DFA	
+0xFA99	0x9DFB	
+0xFA9A	0x9DFC	
+0xFA9B	0x9DFD	
+0xFA9C	0x9DFE	
+0xFA9D	0x9DFF	
+0xFA9E	0x9E00	
+0xFA9F	0x9E01	
+0xFAA0	0x9E02	
+# 0xFAA1	 	
+# 0xFAA2	 	
+# 0xFAA3	 	
+# 0xFAA4	 	
+# 0xFAA5	 	
+# 0xFAA6	 	
+# 0xFAA7	 	
+# 0xFAA8	 	
+# 0xFAA9	 	
+# 0xFAAA	 	
+# 0xFAAB	 	
+# 0xFAAC	 	
+# 0xFAAD	 	
+# 0xFAAE	 	
+# 0xFAAF	 	
+# 0xFAB0	 	
+# 0xFAB1	 	
+# 0xFAB2	 	
+# 0xFAB3	 	
+# 0xFAB4	 	
+# 0xFAB5	 	
+# 0xFAB6	 	
+# 0xFAB7	 	
+# 0xFAB8	 	
+# 0xFAB9	 	
+# 0xFABA	 	
+# 0xFABB	 	
+# 0xFABC	 	
+# 0xFABD	 	
+# 0xFABE	 	
+# 0xFABF	 	
+# 0xFAC0	 	
+# 0xFAC1	 	
+# 0xFAC2	 	
+# 0xFAC3	 	
+# 0xFAC4	 	
+# 0xFAC5	 	
+# 0xFAC6	 	
+# 0xFAC7	 	
+# 0xFAC8	 	
+# 0xFAC9	 	
+# 0xFACA	 	
+# 0xFACB	 	
+# 0xFACC	 	
+# 0xFACD	 	
+# 0xFACE	 	
+# 0xFACF	 	
+# 0xFAD0	 	
+# 0xFAD1	 	
+# 0xFAD2	 	
+# 0xFAD3	 	
+# 0xFAD4	 	
+# 0xFAD5	 	
+# 0xFAD6	 	
+# 0xFAD7	 	
+# 0xFAD8	 	
+# 0xFAD9	 	
+# 0xFADA	 	
+# 0xFADB	 	
+# 0xFADC	 	
+# 0xFADD	 	
+# 0xFADE	 	
+# 0xFADF	 	
+# 0xFAE0	 	
+# 0xFAE1	 	
+# 0xFAE2	 	
+# 0xFAE3	 	
+# 0xFAE4	 	
+# 0xFAE5	 	
+# 0xFAE6	 	
+# 0xFAE7	 	
+# 0xFAE8	 	
+# 0xFAE9	 	
+# 0xFAEA	 	
+# 0xFAEB	 	
+# 0xFAEC	 	
+# 0xFAED	 	
+# 0xFAEE	 	
+# 0xFAEF	 	
+# 0xFAF0	 	
+# 0xFAF1	 	
+# 0xFAF2	 	
+# 0xFAF3	 	
+# 0xFAF4	 	
+# 0xFAF5	 	
+# 0xFAF6	 	
+# 0xFAF7	 	
+# 0xFAF8	 	
+# 0xFAF9	 	
+# 0xFAFA	 	
+# 0xFAFB	 	
+# 0xFAFC	 	
+# 0xFAFD	 	
+# 0xFAFE	 	
+0xFB40	0x9E03	
+0xFB41	0x9E04	
+0xFB42	0x9E05	
+0xFB43	0x9E06	
+0xFB44	0x9E07	
+0xFB45	0x9E08	
+0xFB46	0x9E09	
+0xFB47	0x9E0A	
+0xFB48	0x9E0B	
+0xFB49	0x9E0C	
+0xFB4A	0x9E0D	
+0xFB4B	0x9E0E	
+0xFB4C	0x9E0F	
+0xFB4D	0x9E10	
+0xFB4E	0x9E11	
+0xFB4F	0x9E12	
+0xFB50	0x9E13	
+0xFB51	0x9E14	
+0xFB52	0x9E15	
+0xFB53	0x9E16	
+0xFB54	0x9E17	
+0xFB55	0x9E18	
+0xFB56	0x9E19	
+0xFB57	0x9E1A	
+0xFB58	0x9E1B	
+0xFB59	0x9E1C	
+0xFB5A	0x9E1D	
+0xFB5B	0x9E1E	
+0xFB5C	0x9E24	
+0xFB5D	0x9E27	
+0xFB5E	0x9E2E	
+0xFB5F	0x9E30	
+0xFB60	0x9E34	
+0xFB61	0x9E3B	
+0xFB62	0x9E3C	
+0xFB63	0x9E40	
+0xFB64	0x9E4D	
+0xFB65	0x9E50	
+0xFB66	0x9E52	
+0xFB67	0x9E53	
+0xFB68	0x9E54	
+0xFB69	0x9E56	
+0xFB6A	0x9E59	
+0xFB6B	0x9E5D	
+0xFB6C	0x9E5F	
+0xFB6D	0x9E60	
+0xFB6E	0x9E61	
+0xFB6F	0x9E62	
+0xFB70	0x9E65	
+0xFB71	0x9E6E	
+0xFB72	0x9E6F	
+0xFB73	0x9E72	
+0xFB74	0x9E74	
+0xFB75	0x9E75	
+0xFB76	0x9E76	
+0xFB77	0x9E77	
+0xFB78	0x9E78	
+0xFB79	0x9E79	
+0xFB7A	0x9E7A	
+0xFB7B	0x9E7B	
+0xFB7C	0x9E7C	
+0xFB7D	0x9E7D	
+0xFB7E	0x9E80	
+0xFB80	0x9E81	
+0xFB81	0x9E83	
+0xFB82	0x9E84	
+0xFB83	0x9E85	
+0xFB84	0x9E86	
+0xFB85	0x9E89	
+0xFB86	0x9E8A	
+0xFB87	0x9E8C	
+0xFB88	0x9E8D	
+0xFB89	0x9E8E	
+0xFB8A	0x9E8F	
+0xFB8B	0x9E90	
+0xFB8C	0x9E91	
+0xFB8D	0x9E94	
+0xFB8E	0x9E95	
+0xFB8F	0x9E96	
+0xFB90	0x9E97	
+0xFB91	0x9E98	
+0xFB92	0x9E99	
+0xFB93	0x9E9A	
+0xFB94	0x9E9B	
+0xFB95	0x9E9C	
+0xFB96	0x9E9E	
+0xFB97	0x9EA0	
+0xFB98	0x9EA1	
+0xFB99	0x9EA2	
+0xFB9A	0x9EA3	
+0xFB9B	0x9EA4	
+0xFB9C	0x9EA5	
+0xFB9D	0x9EA7	
+0xFB9E	0x9EA8	
+0xFB9F	0x9EA9	
+0xFBA0	0x9EAA	
+# 0xFBA1	 	
+# 0xFBA2	 	
+# 0xFBA3	 	
+# 0xFBA4	 	
+# 0xFBA5	 	
+# 0xFBA6	 	
+# 0xFBA7	 	
+# 0xFBA8	 	
+# 0xFBA9	 	
+# 0xFBAA	 	
+# 0xFBAB	 	
+# 0xFBAC	 	
+# 0xFBAD	 	
+# 0xFBAE	 	
+# 0xFBAF	 	
+# 0xFBB0	 	
+# 0xFBB1	 	
+# 0xFBB2	 	
+# 0xFBB3	 	
+# 0xFBB4	 	
+# 0xFBB5	 	
+# 0xFBB6	 	
+# 0xFBB7	 	
+# 0xFBB8	 	
+# 0xFBB9	 	
+# 0xFBBA	 	
+# 0xFBBB	 	
+# 0xFBBC	 	
+# 0xFBBD	 	
+# 0xFBBE	 	
+# 0xFBBF	 	
+# 0xFBC0	 	
+# 0xFBC1	 	
+# 0xFBC2	 	
+# 0xFBC3	 	
+# 0xFBC4	 	
+# 0xFBC5	 	
+# 0xFBC6	 	
+# 0xFBC7	 	
+# 0xFBC8	 	
+# 0xFBC9	 	
+# 0xFBCA	 	
+# 0xFBCB	 	
+# 0xFBCC	 	
+# 0xFBCD	 	
+# 0xFBCE	 	
+# 0xFBCF	 	
+# 0xFBD0	 	
+# 0xFBD1	 	
+# 0xFBD2	 	
+# 0xFBD3	 	
+# 0xFBD4	 	
+# 0xFBD5	 	
+# 0xFBD6	 	
+# 0xFBD7	 	
+# 0xFBD8	 	
+# 0xFBD9	 	
+# 0xFBDA	 	
+# 0xFBDB	 	
+# 0xFBDC	 	
+# 0xFBDD	 	
+# 0xFBDE	 	
+# 0xFBDF	 	
+# 0xFBE0	 	
+# 0xFBE1	 	
+# 0xFBE2	 	
+# 0xFBE3	 	
+# 0xFBE4	 	
+# 0xFBE5	 	
+# 0xFBE6	 	
+# 0xFBE7	 	
+# 0xFBE8	 	
+# 0xFBE9	 	
+# 0xFBEA	 	
+# 0xFBEB	 	
+# 0xFBEC	 	
+# 0xFBED	 	
+# 0xFBEE	 	
+# 0xFBEF	 	
+# 0xFBF0	 	
+# 0xFBF1	 	
+# 0xFBF2	 	
+# 0xFBF3	 	
+# 0xFBF4	 	
+# 0xFBF5	 	
+# 0xFBF6	 	
+# 0xFBF7	 	
+# 0xFBF8	 	
+# 0xFBF9	 	
+# 0xFBFA	 	
+# 0xFBFB	 	
+# 0xFBFC	 	
+# 0xFBFD	 	
+# 0xFBFE	 	
+0xFC40	0x9EAB	
+0xFC41	0x9EAC	
+0xFC42	0x9EAD	
+0xFC43	0x9EAE	
+0xFC44	0x9EAF	
+0xFC45	0x9EB0	
+0xFC46	0x9EB1	
+0xFC47	0x9EB2	
+0xFC48	0x9EB3	
+0xFC49	0x9EB5	
+0xFC4A	0x9EB6	
+0xFC4B	0x9EB7	
+0xFC4C	0x9EB9	
+0xFC4D	0x9EBA	
+0xFC4E	0x9EBC	
+0xFC4F	0x9EBF	
+0xFC50	0x9EC0	
+0xFC51	0x9EC1	
+0xFC52	0x9EC2	
+0xFC53	0x9EC3	
+0xFC54	0x9EC5	
+0xFC55	0x9EC6	
+0xFC56	0x9EC7	
+0xFC57	0x9EC8	
+0xFC58	0x9ECA	
+0xFC59	0x9ECB	
+0xFC5A	0x9ECC	
+0xFC5B	0x9ED0	
+0xFC5C	0x9ED2	
+0xFC5D	0x9ED3	
+0xFC5E	0x9ED5	
+0xFC5F	0x9ED6	
+0xFC60	0x9ED7	
+0xFC61	0x9ED9	
+0xFC62	0x9EDA	
+0xFC63	0x9EDE	
+0xFC64	0x9EE1	
+0xFC65	0x9EE3	
+0xFC66	0x9EE4	
+0xFC67	0x9EE6	
+0xFC68	0x9EE8	
+0xFC69	0x9EEB	
+0xFC6A	0x9EEC	
+0xFC6B	0x9EED	
+0xFC6C	0x9EEE	
+0xFC6D	0x9EF0	
+0xFC6E	0x9EF1	
+0xFC6F	0x9EF2	
+0xFC70	0x9EF3	
+0xFC71	0x9EF4	
+0xFC72	0x9EF5	
+0xFC73	0x9EF6	
+0xFC74	0x9EF7	
+0xFC75	0x9EF8	
+0xFC76	0x9EFA	
+0xFC77	0x9EFD	
+0xFC78	0x9EFF	
+0xFC79	0x9F00	
+0xFC7A	0x9F01	
+0xFC7B	0x9F02	
+0xFC7C	0x9F03	
+0xFC7D	0x9F04	
+0xFC7E	0x9F05	
+0xFC80	0x9F06	
+0xFC81	0x9F07	
+0xFC82	0x9F08	
+0xFC83	0x9F09	
+0xFC84	0x9F0A	
+0xFC85	0x9F0C	
+0xFC86	0x9F0F	
+0xFC87	0x9F11	
+0xFC88	0x9F12	
+0xFC89	0x9F14	
+0xFC8A	0x9F15	
+0xFC8B	0x9F16	
+0xFC8C	0x9F18	
+0xFC8D	0x9F1A	
+0xFC8E	0x9F1B	
+0xFC8F	0x9F1C	
+0xFC90	0x9F1D	
+0xFC91	0x9F1E	
+0xFC92	0x9F1F	
+0xFC93	0x9F21	
+0xFC94	0x9F23	
+0xFC95	0x9F24	
+0xFC96	0x9F25	
+0xFC97	0x9F26	
+0xFC98	0x9F27	
+0xFC99	0x9F28	
+0xFC9A	0x9F29	
+0xFC9B	0x9F2A	
+0xFC9C	0x9F2B	
+0xFC9D	0x9F2D	
+0xFC9E	0x9F2E	
+0xFC9F	0x9F30	
+0xFCA0	0x9F31	
+# 0xFCA1	 	
+# 0xFCA2	 	
+# 0xFCA3	 	
+# 0xFCA4	 	
+# 0xFCA5	 	
+# 0xFCA6	 	
+# 0xFCA7	 	
+# 0xFCA8	 	
+# 0xFCA9	 	
+# 0xFCAA	 	
+# 0xFCAB	 	
+# 0xFCAC	 	
+# 0xFCAD	 	
+# 0xFCAE	 	
+# 0xFCAF	 	
+# 0xFCB0	 	
+# 0xFCB1	 	
+# 0xFCB2	 	
+# 0xFCB3	 	
+# 0xFCB4	 	
+# 0xFCB5	 	
+# 0xFCB6	 	
+# 0xFCB7	 	
+# 0xFCB8	 	
+# 0xFCB9	 	
+# 0xFCBA	 	
+# 0xFCBB	 	
+# 0xFCBC	 	
+# 0xFCBD	 	
+# 0xFCBE	 	
+# 0xFCBF	 	
+# 0xFCC0	 	
+# 0xFCC1	 	
+# 0xFCC2	 	
+# 0xFCC3	 	
+# 0xFCC4	 	
+# 0xFCC5	 	
+# 0xFCC6	 	
+# 0xFCC7	 	
+# 0xFCC8	 	
+# 0xFCC9	 	
+# 0xFCCA	 	
+# 0xFCCB	 	
+# 0xFCCC	 	
+# 0xFCCD	 	
+# 0xFCCE	 	
+# 0xFCCF	 	
+# 0xFCD0	 	
+# 0xFCD1	 	
+# 0xFCD2	 	
+# 0xFCD3	 	
+# 0xFCD4	 	
+# 0xFCD5	 	
+# 0xFCD6	 	
+# 0xFCD7	 	
+# 0xFCD8	 	
+# 0xFCD9	 	
+# 0xFCDA	 	
+# 0xFCDB	 	
+# 0xFCDC	 	
+# 0xFCDD	 	
+# 0xFCDE	 	
+# 0xFCDF	 	
+# 0xFCE0	 	
+# 0xFCE1	 	
+# 0xFCE2	 	
+# 0xFCE3	 	
+# 0xFCE4	 	
+# 0xFCE5	 	
+# 0xFCE6	 	
+# 0xFCE7	 	
+# 0xFCE8	 	
+# 0xFCE9	 	
+# 0xFCEA	 	
+# 0xFCEB	 	
+# 0xFCEC	 	
+# 0xFCED	 	
+# 0xFCEE	 	
+# 0xFCEF	 	
+# 0xFCF0	 	
+# 0xFCF1	 	
+# 0xFCF2	 	
+# 0xFCF3	 	
+# 0xFCF4	 	
+# 0xFCF5	 	
+# 0xFCF6	 	
+# 0xFCF7	 	
+# 0xFCF8	 	
+# 0xFCF9	 	
+# 0xFCFA	 	
+# 0xFCFB	 	
+# 0xFCFC	 	
+# 0xFCFD	 	
+# 0xFCFE	 	
+0xFD40	0x9F32	
+0xFD41	0x9F33	
+0xFD42	0x9F34	
+0xFD43	0x9F35	
+0xFD44	0x9F36	
+0xFD45	0x9F38	
+0xFD46	0x9F3A	
+0xFD47	0x9F3C	
+0xFD48	0x9F3F	
+0xFD49	0x9F40	
+0xFD4A	0x9F41	
+0xFD4B	0x9F42	
+0xFD4C	0x9F43	
+0xFD4D	0x9F45	
+0xFD4E	0x9F46	
+0xFD4F	0x9F47	
+0xFD50	0x9F48	
+0xFD51	0x9F49	
+0xFD52	0x9F4A	
+0xFD53	0x9F4B	
+0xFD54	0x9F4C	
+0xFD55	0x9F4D	
+0xFD56	0x9F4E	
+0xFD57	0x9F4F	
+0xFD58	0x9F52	
+0xFD59	0x9F53	
+0xFD5A	0x9F54	
+0xFD5B	0x9F55	
+0xFD5C	0x9F56	
+0xFD5D	0x9F57	
+0xFD5E	0x9F58	
+0xFD5F	0x9F59	
+0xFD60	0x9F5A	
+0xFD61	0x9F5B	
+0xFD62	0x9F5C	
+0xFD63	0x9F5D	
+0xFD64	0x9F5E	
+0xFD65	0x9F5F	
+0xFD66	0x9F60	
+0xFD67	0x9F61	
+0xFD68	0x9F62	
+0xFD69	0x9F63	
+0xFD6A	0x9F64	
+0xFD6B	0x9F65	
+0xFD6C	0x9F66	
+0xFD6D	0x9F67	
+0xFD6E	0x9F68	
+0xFD6F	0x9F69	
+0xFD70	0x9F6A	
+0xFD71	0x9F6B	
+0xFD72	0x9F6C	
+0xFD73	0x9F6D	
+0xFD74	0x9F6E	
+0xFD75	0x9F6F	
+0xFD76	0x9F70	
+0xFD77	0x9F71	
+0xFD78	0x9F72	
+0xFD79	0x9F73	
+0xFD7A	0x9F74	
+0xFD7B	0x9F75	
+0xFD7C	0x9F76	
+0xFD7D	0x9F77	
+0xFD7E	0x9F78	
+0xFD80	0x9F79	
+0xFD81	0x9F7A	
+0xFD82	0x9F7B	
+0xFD83	0x9F7C	
+0xFD84	0x9F7D	
+0xFD85	0x9F7E	
+0xFD86	0x9F81	
+0xFD87	0x9F82	
+0xFD88	0x9F8D	
+0xFD89	0x9F8E	
+0xFD8A	0x9F8F	
+0xFD8B	0x9F90	
+0xFD8C	0x9F91	
+0xFD8D	0x9F92	
+0xFD8E	0x9F93	
+0xFD8F	0x9F94	
+0xFD90	0x9F95	
+0xFD91	0x9F96	
+0xFD92	0x9F97	
+0xFD93	0x9F98	
+0xFD94	0x9F9C	
+0xFD95	0x9F9D	
+0xFD96	0x9F9E	
+0xFD97	0x9FA1	
+0xFD98	0x9FA2	
+0xFD99	0x9FA3	
+0xFD9A	0x9FA4	
+0xFD9B	0x9FA5	
+0xFD9C	0xF92C	
+0xFD9D	0xF979	
+0xFD9E	0xF995	
+0xFD9F	0xF9E7	
+0xFDA0	0xF9F1	
+# 0xFDA1	 	
+# 0xFDA2	 	
+# 0xFDA3	 	
+# 0xFDA4	 	
+# 0xFDA5	 	
+# 0xFDA6	 	
+# 0xFDA7	 	
+# 0xFDA8	 	
+# 0xFDA9	 	
+# 0xFDAA	 	
+# 0xFDAB	 	
+# 0xFDAC	 	
+# 0xFDAD	 	
+# 0xFDAE	 	
+# 0xFDAF	 	
+# 0xFDB0	 	
+# 0xFDB1	 	
+# 0xFDB2	 	
+# 0xFDB3	 	
+# 0xFDB4	 	
+# 0xFDB5	 	
+# 0xFDB6	 	
+# 0xFDB7	 	
+# 0xFDB8	 	
+# 0xFDB9	 	
+# 0xFDBA	 	
+# 0xFDBB	 	
+# 0xFDBC	 	
+# 0xFDBD	 	
+# 0xFDBE	 	
+# 0xFDBF	 	
+# 0xFDC0	 	
+# 0xFDC1	 	
+# 0xFDC2	 	
+# 0xFDC3	 	
+# 0xFDC4	 	
+# 0xFDC5	 	
+# 0xFDC6	 	
+# 0xFDC7	 	
+# 0xFDC8	 	
+# 0xFDC9	 	
+# 0xFDCA	 	
+# 0xFDCB	 	
+# 0xFDCC	 	
+# 0xFDCD	 	
+# 0xFDCE	 	
+# 0xFDCF	 	
+# 0xFDD0	 	
+# 0xFDD1	 	
+# 0xFDD2	 	
+# 0xFDD3	 	
+# 0xFDD4	 	
+# 0xFDD5	 	
+# 0xFDD6	 	
+# 0xFDD7	 	
+# 0xFDD8	 	
+# 0xFDD9	 	
+# 0xFDDA	 	
+# 0xFDDB	 	
+# 0xFDDC	 	
+# 0xFDDD	 	
+# 0xFDDE	 	
+# 0xFDDF	 	
+# 0xFDE0	 	
+# 0xFDE1	 	
+# 0xFDE2	 	
+# 0xFDE3	 	
+# 0xFDE4	 	
+# 0xFDE5	 	
+# 0xFDE6	 	
+# 0xFDE7	 	
+# 0xFDE8	 	
+# 0xFDE9	 	
+# 0xFDEA	 	
+# 0xFDEB	 	
+# 0xFDEC	 	
+# 0xFDED	 	
+# 0xFDEE	 	
+# 0xFDEF	 	
+# 0xFDF0	 	
+# 0xFDF1	 	
+# 0xFDF2	 	
+# 0xFDF3	 	
+# 0xFDF4	 	
+# 0xFDF5	 	
+# 0xFDF6	 	
+# 0xFDF7	 	
+# 0xFDF8	 	
+# 0xFDF9	 	
+# 0xFDFA	 	
+# 0xFDFB	 	
+# 0xFDFC	 	
+# 0xFDFD	 	
+# 0xFDFE	 	
+0xFE40	0xFA0C	
+0xFE41	0xFA0D	
+0xFE42	0xFA0E	
+0xFE43	0xFA0F	
+0xFE44	0xFA11	
+0xFE45	0xFA13	
+0xFE46	0xFA14	
+0xFE47	0xFA18	
+0xFE48	0xFA1F	
+0xFE49	0xFA20	
+0xFE4A	0xFA21	
+0xFE4B	0xFA23	
+0xFE4C	0xFA24	
+0xFE4D	0xFA27	
+0xFE4E	0xFA28	
+0xFE4F	0xFA29	
+0xFE50	0xE815	
+0xFE51	0xE816	
+0xFE52	0xE817	
+0xFE53	0xE818	
+0xFE54	0xE819	
+0xFE55	0xE81A	
+0xFE56	0xE81B	
+0xFE57	0xE81C	
+0xFE58	0xE81D	
+0xFE59	0xE81E	
+0xFE5A	0xE81F	
+0xFE5B	0xE820	
+0xFE5C	0xE821	
+0xFE5D	0xE822	
+0xFE5E	0xE823	
+0xFE5F	0xE824	
+0xFE60	0xE825	
+0xFE61	0xE826	
+0xFE62	0xE827	
+0xFE63	0xE828	
+0xFE64	0xE829	
+0xFE65	0xE82A	
+0xFE66	0xE82B	
+0xFE67	0xE82C	
+0xFE68	0xE82D	
+0xFE69	0xE82E	
+0xFE6A	0xE82F	
+0xFE6B	0xE830	
+0xFE6C	0xE831	
+0xFE6D	0xE832	
+0xFE6E	0xE833	
+0xFE6F	0xE834	
+0xFE70	0xE835	
+0xFE71	0xE836	
+0xFE72	0xE837	
+0xFE73	0xE838	
+0xFE74	0xE839	
+0xFE75	0xE83A	
+0xFE76	0xE83B	
+0xFE77	0xE83C	
+0xFE78	0xE83D	
+0xFE79	0xE83E	
+0xFE7A	0xE83F	
+0xFE7B	0xE840	
+0xFE7C	0xE841	
+0xFE7D	0xE842	
+0xFE7E	0xE843	
+0xFE80	0xE844	
+0xFE81	0xE845	
+0xFE82	0xE846	
+0xFE83	0xE847	
+0xFE84	0xE848	
+0xFE85	0xE849	
+0xFE86	0xE84A	
+0xFE87	0xE84B	
+0xFE88	0xE84C	
+0xFE89	0xE84D	
+0xFE8A	0xE84E	
+0xFE8B	0xE84F	
+0xFE8C	0xE850	
+0xFE8D	0xE851	
+0xFE8E	0xE852	
+0xFE8F	0xE853	
+0xFE90	0xE854	
+0xFE91	0xE855	
+0xFE92	0xE856	
+0xFE93	0xE857	
+0xFE94	0xE858	
+0xFE95	0xE859	
+0xFE96	0xE85A	
+0xFE97	0xE85B	
+0xFE98	0xE85C	
+0xFE99	0xE85D	
+0xFE9A	0xE85E	
+0xFE9B	0xE85F	
+0xFE9C	0xE860	
+0xFE9D	0xE861	
+0xFE9E	0xE862	
+0xFE9F	0xE863	
+0xFEA0	0xE864	
+# 0xFEA1	 	
+# 0xFEA2	 	
+# 0xFEA3	 	
+# 0xFEA4	 	
+# 0xFEA5	 	
+# 0xFEA6	 	
+# 0xFEA7	 	
+# 0xFEA8	 	
+# 0xFEA9	 	
+# 0xFEAA	 	
+# 0xFEAB	 	
+# 0xFEAC	 	
+# 0xFEAD	 	
+# 0xFEAE	 	
+# 0xFEAF	 	
+# 0xFEB0	 	
+# 0xFEB1	 	
+# 0xFEB2	 	
+# 0xFEB3	 	
+# 0xFEB4	 	
+# 0xFEB5	 	
+# 0xFEB6	 	
+# 0xFEB7	 	
+# 0xFEB8	 	
+# 0xFEB9	 	
+# 0xFEBA	 	
+# 0xFEBB	 	
+# 0xFEBC	 	
+# 0xFEBD	 	
+# 0xFEBE	 	
+# 0xFEBF	 	
+# 0xFEC0	 	
+# 0xFEC1	 	
+# 0xFEC2	 	
+# 0xFEC3	 	
+# 0xFEC4	 	
+# 0xFEC5	 	
+# 0xFEC6	 	
+# 0xFEC7	 	
+# 0xFEC8	 	
+# 0xFEC9	 	
+# 0xFECA	 	
+# 0xFECB	 	
+# 0xFECC	 	
+# 0xFECD	 	
+# 0xFECE	 	
+# 0xFECF	 	
+# 0xFED0	 	
+# 0xFED1	 	
+# 0xFED2	 	
+# 0xFED3	 	
+# 0xFED4	 	
+# 0xFED5	 	
+# 0xFED6	 	
+# 0xFED7	 	
+# 0xFED8	 	
+# 0xFED9	 	
+# 0xFEDA	 	
+# 0xFEDB	 	
+# 0xFEDC	 	
+# 0xFEDD	 	
+# 0xFEDE	 	
+# 0xFEDF	 	
+# 0xFEE0	 	
+# 0xFEE1	 	
+# 0xFEE2	 	
+# 0xFEE3	 	
+# 0xFEE4	 	
+# 0xFEE5	 	
+# 0xFEE6	 	
+# 0xFEE7	 	
+# 0xFEE8	 	
+# 0xFEE9	 	
+# 0xFEEA	 	
+# 0xFEEB	 	
+# 0xFEEC	 	
+# 0xFEED	 	
+# 0xFEEE	 	
+# 0xFEEF	 	
+# 0xFEF0	 	
+# 0xFEF1	 	
+# 0xFEF2	 	
+# 0xFEF3	 	
+# 0xFEF4	 	
+# 0xFEF5	 	
+# 0xFEF6	 	
+# 0xFEF7	 	
+# 0xFEF8	 	
+# 0xFEF9	 	
+# 0xFEFA	 	
+# 0xFEFB	 	
+# 0xFEFC	 	
+# 0xFEFD	 	
+# 0xFEFE	 	
+	
Index: /main/tags/2.25/gsdl/unicode/MAPPINGS/EASTASIA/GB/makemapfile.pl
===================================================================
--- /main/tags/2.25/gsdl/unicode/MAPPINGS/EASTASIA/GB/makemapfile.pl	(revision 21064)
+++ /main/tags/2.25/gsdl/unicode/MAPPINGS/EASTASIA/GB/makemapfile.pl	(revision 21064)
@@ -0,0 +1,329 @@
+#! /usr/local/bin/perl5 -w
+
+# useful methods for dealing with the GuoBiao (GB) encoding
+
+BEGIN {
+    die "GSDLHOME not set\n" unless defined $ENV{'GSDLHOME'};
+    unshift (@INC, "$ENV{'GSDLHOME'}/perllib");
+}
+
+use unicode;
+use util;
+
+# %encodings is of the form:
+#
+# encodings{encodingname-encodingname}->blocktranslation
+# blocktranslation->[[0-255],[256-511], ..., [65280-65535]]
+#
+# Any of the top translation blocks can point to an undefined
+# value. This data structure aims to allow fast translation and 
+# efficient storage.
+
+# @array256 is used for initialisation, there must be
+# a better way...
+@array256 = (0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+	     0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+	     0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+	     0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+	     0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+	     0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+	     0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+	     0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+	     0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+	     0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+	     0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+	     0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+	     0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+	     0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+	     0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+	     0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0);
+
+
+%translations = ();
+
+&main ();
+
+
+
+# gb2unicode uses the GBK translation table
+sub gb2unicode {
+    generalgb2unicode ("GBK", @_);
+}
+
+# returns a pointer to unicode array
+sub generalgb2unicode {
+    my ($encoding, $intext) = @_;
+    my $mapfile = &util::filename_cat($ENV{'GSDLHOME'}, 
+				      "unicode/MAPPINGS/EASTASIA/GB",
+				      "$encoding.TXT");
+    if (!&loadencoding ($encoding, $mapfile)) {
+	print STDERR "gb: ERROR - could not load encoding $encoding\n";
+	return [];
+    }
+    
+    my @outtext = ();
+    my $encodename = "$encoding-unicode";
+    my $len = length($intext);
+    my ($c1, $c2);
+    my $i = 0;
+
+    while ($i < $len) {
+	if (($c1 = ord(substr($intext, $i, 1))) >= 0x81) {
+	    if ($i+1 < $len) {
+		# found a GB character, put black square if cannot translate
+		$c2 = ord(substr($intext, $i+1, 1));
+		my $c = &transchar ($encodename, ($c1 << 8) | $c2);
+		$c = 0x25a1 if $c == 0;
+		push (@outtext, $c);
+		$i += 2;
+		
+	    } else {
+		# error
+		print STDERR "gb: ERROR missing second half of GB character\n";
+		$i++;
+	    }
+	    
+	} else {
+	    # normal ascii character
+	    push (@outtext, $c1) if ($c1 < 0x80);
+	    $i++;
+	}
+    }
+    
+    return \@outtext;
+}
+
+
+# unicode2gb uses the GBK translation table
+sub unicode2gb {
+    generalunicode2gb ("GBK", @_);
+}
+
+# returns a gb string. Note that this will not translate
+# traditional forms of characters to their simplified forms
+# Any traditional characters in the unicode will not be translated
+sub generalunicode2gb {
+    my ($encoding, $intext) = @_;
+
+    # load the encoding (if it is not already loaded)
+    my $mapfile = &util::filename_cat($ENV{'GSDLHOME'}, 
+				      "unicode/MAPPINGS/EASTASIA/GB",
+				      "$encoding.TXT");
+    if (!&loadencoding ($encoding, $mapfile)) {
+	print STDERR "gb: ERROR - could not load encoding $encoding\n";
+	return "";
+    }
+    
+    # translate the string
+    my ($num, $gbc);
+    my $outtext = "";
+    my $encodename = "unicode-$encoding";
+    foreach $num (@$intext) {
+	if ($num < 0x80) {
+	    # normal ascii character
+	    $outtext .= chr ($num);
+	} else {
+	    # gb character
+	    my $gbc = &transchar ($encodename, $num);
+	    $gbc = 0xa1f5 if $gbc == 0;
+	    $outtext .= chr ($gbc >> 8);
+	    $outtext .= chr ($gbc & 0xff);
+	}
+    }
+
+    return $outtext;
+}
+
+
+# loadmapfile expects the mapfile to contain (at least) two
+# tab-seperated fields. The first field is the mapped value
+# and the second field is the unicode value.
+#
+# It returns 1 if successful, 0 if unsuccessful
+sub loadencoding {
+    my ($encoding, $mapfile) = @_;
+    
+    my $to = "$encoding-unicode";
+    my $from = "unicode-$encoding";
+
+    # check to see if the encoding has already been loaded
+    if (defined $translations{$to} && defined $translations{$from}) {
+	return 1;
+    }
+
+    return 0 unless open (MAPFILE, $mapfile);
+
+    my ($line, @line);
+    $translations{$to} = [@array256];
+    $translations{$from} = [@array256];
+    while (defined ($line = <MAPFILE>)) {
+	# remove comments
+	$line =~ s/\#.*$//;
+	next unless $line =~ /\S/;
+
+	# split the line into fields and do a few
+	# simple sanity checks
+	@line = split (/\t/, $line);
+	next unless (scalar(@line) >= 2 &&
+		     $line[0] =~ /^0x/ &&
+		     $line[1] =~ /^0x/);
+
+	my $gbc = hex($line[0]);
+	my $unic = hex($line[1]);
+
+	# gbk has already had the necessary most significant
+	# bits set (it is used in the encoding
+	$gbc = $gbc | 0x8080 unless ($encoding =~ /gbk/i);
+
+	&addchartrans ($translations{$to}, $gbc, $unic);
+	&addchartrans ($translations{$from}, $unic, $gbc);
+    }
+
+    close (MAPFILE);
+
+    return 1;
+}
+
+sub showfilled {
+    my ($block) = @_;
+    my $count = 0;
+    foreach $el (@$block) {
+	if (ref ($el) eq "ARRAY") {
+	    print "1";
+	    $count++;
+	} else {
+	    print "0";
+	}
+    }
+    print "\n";
+    print "total: $count\n";
+}
+
+
+# addchartrans adds one character translation to a translation block.
+# It also simplifies the translation block if possible.
+sub addchartrans {
+    my ($block, $from, $to) = @_;
+    my $i = 0;
+
+    my $high = ($from / 256) % 256;
+    my $low = $from % 256;
+
+    if (ref ($block->[$high]) ne "ARRAY") {
+	$block->[$high] = [@array256];
+    }
+    $block->[$high]->[$low] = $to;
+}
+
+
+sub transchar {
+    my ($encoding, $from) = @_;
+    my $high = ($from / 256) % 256;
+    my $low = $from % 256;
+
+    return 0 unless defined $translations{$encoding};
+
+    my $block = $translations{$encoding};
+
+    if (ref ($block->[$high]) ne "ARRAY") {
+	return 0;
+    }
+    return $block->[$high]->[$low];
+}
+
+# It returns 1 if successful, 0 if unsuccessful
+sub loadmapencoding {
+    my ($encoding) = @_;
+    
+    my $to = "$encoding-unicode";
+    my $from = "unicode-$encoding";
+
+    # check to see if the encoding has already been loaded
+    if (defined $translations{$to} && defined $translations{$from}) {
+	return 1;
+    }
+    
+    &readmapfile ($to);
+    &readmapfile ($from);
+    return 1;
+}
+
+sub readmapfile {
+    my ($encoding) = @_;
+    my $filename = $encoding;
+
+    $filename =~ s/\-//;
+    $filename =~ s/unicode/u/i;
+    $filename =~ tr/A-Z/a-z/;
+    $filename .= ".ump"; # unicode map file
+
+    $translations{$encoding} = [@array256];
+    my $block = $translations{$encoding};
+
+    open (MAPFILE, "$ENV{'GSDLHOME'}/unicode/$filename") || die;
+
+    my ($in,$i,$j);
+    while (read(MAPFILE, $in, 1) == 1) {
+	$i = unpack ("C", $in);
+	$block->[$i] = [@array256];
+	for ($j=0; $j<256 && read(MAPFILE, $in, 2)==2; $j++) {
+	    my ($n1, $n2) = unpack ("CC", $in);
+	    $block->[$i]->[$j] = ($n1*256) + $n2;
+	}
+    }
+
+    close (MAPFILE);
+}
+
+sub writemapfile {
+    my ($encoding) = @_;
+    my $filename = $encoding;
+
+    $filename =~ s/\-//;
+    $filename =~ s/unicode/u/i;
+    $filename =~ tr/A-Z/a-z/;
+    $filename .= ".ump"; # unicode map file
+
+    die "translation not defined" if (!defined $translations{$encoding});
+    my $block = $translations{$encoding};
+
+    print "writing $ENV{'GSDLHOME'}/unicode/$filename\n";
+    open (MAPFILE, ">$ENV{'GSDLHOME'}/unicode/$filename") || die;
+
+    my ($i, $j);
+    for ($i=0; $i<256; $i++) {
+	if (ref ($block->[$i]) eq "ARRAY") {
+	    print MAPFILE pack ("C", $i);
+	    for ($j=0; $j<256; $j++) {
+		# unsigned short in network order
+		print MAPFILE pack ("CC", int($block->[$i]->[$j] / 256), 
+				    $block->[$i]->[$j] % 256);
+	    }
+	}
+    }
+
+    close (MAPFILE);
+}
+
+sub makeencodingmapfile {
+    my ($encoding) = @_;
+
+    my $mapfile = &util::filename_cat($ENV{'GSDLHOME'}, 
+				      "unicode/MAPPINGS/EASTASIA/GB",
+				      "$encoding.TXT");
+    if (!&loadencoding ($encoding, $mapfile)) {
+#    if (!&loadmapencoding ($encoding)) {
+	die "couldn't load encoding $encoding";
+    }
+
+    # write out map files
+    &writemapfile ("$encoding-unicode");
+    &writemapfile ("unicode-$encoding");
+}
+
+sub main {
+    makeencodingmapfile ("BIG5");
+#    makeencodingmapfile ("GBK");
+#    makeencodingmapfile ("GB2312");
+#    makeencodingmapfile ("GB12345");
+}
Index: /main/tags/2.25/gsdl/unicode/MAPPINGS/WINDOWS/1256.TXT
===================================================================
--- /main/tags/2.25/gsdl/unicode/MAPPINGS/WINDOWS/1256.TXT	(revision 21064)
+++ /main/tags/2.25/gsdl/unicode/MAPPINGS/WINDOWS/1256.TXT	(revision 21064)
@@ -0,0 +1,134 @@
+# Microsoft Windows Codepage : 1256 (Arabic)
+
+# This table was generated by Stefan Boddie (sjboddie@cs.waikato.ac.nz) for
+# the Greenstone Digital Library software from the codepage found at
+# http://www.microsoft.com/globaldev/reference/sbcs/1256.htm
+
+0x80	0x20AC	# EURO SIGN
+0x81	0x067E	# ARABIC LETTER PEH
+0x82	0x201A	# SINGLE LOW-9 QUOTATION MARK
+0x83	0x0192	# LATIN SMALL LETTER F WITH HOOK
+0x84	0x201E	# DOUBLE LOW-9 QUOTATION MARK
+0x85	0x2026	# HORIZONTAL ELLIPSIS
+0x86	0x2020	# DAGGER
+0x87	0x2021	# DOUBLE DAGGER
+0x88	0x02C6	# MODIFIER LETTER CIRCUMFLEX ACCENT
+0x89	0x2030	# PER MILLE SIGN
+0x8A	0x0679	# ARABIC LETTER TTEH
+0x8B	0x2039	# SINGLE LEFT-POINTING ANGLE QUOTATION MARK
+0x8C	0x0152	# LATIN CAPITAL LIGATURE OE
+0x8D	0x0686	# ARABIC LETTER TCHEH
+0x8E	0x0698	# ARABIC LETTER JEH
+0x8F	0x0688	# ARABIC LETTER DDAL
+0x90	0x06AF	# ARABIC LETTER GAF
+0x91	0x2018	# LEFT SINGLE QUOTATION MARK
+0x92	0x2019	# RIGHT SINGLE QUOTATION MARK
+0x93	0x201C	# LEFT DOUBLE QUOTATION MARK
+0x94	0x201D	# RIGHT DOUBLE QUOTATION MARK
+0x95	0x2022	# BULLET
+0x96	0x2013	# EN DASH
+0x97	0x2014	# EM DASH
+0x98	0x06A9	# ARABIC LETTER KEHEH
+0x99	0x2122	# TRADE MARK SIGN
+0x9A	0x0691	# ARABIC LETTER RREH
+0x9B	0x203A	# SINGLE RIGHT-POINTING ANGLE QUOTATION MARK
+0x9C	0x0153	# LATIN SMALL LIGATURE OE
+0x9D	0x200C	# ZERO WIDTH NON-JOINER
+0x9E	0x200D	# ZERO WIDTH JOINER
+0x9F	0x06BA	# ARABIC LETTER NOON GHUNNA
+0xA0	0x00A0	# NO-BREAK SPACE
+0xA1	0x060C	# ARABIC COMMA
+0xA2	0x00A2	# CENT SIGN
+0xA3	0x00A3	# POUND SIGN
+0xA4	0x00A4	# CURRENCY SIGN
+0xA5	0x00A5	# YEN SIGN
+0xA6	0x00A6	# BROKEN BAR
+0xA7	0x00A7	# SECTION SIGN
+0xA8	0x00A8	# DIAERESIS
+0xA9	0x00A9	# COPYRIGHT SIGN
+0xAA	0x06BE	# ARABIC LETTER HEH DOACHASHMEE
+0xAB	0x00AB	# LEFT-POINTING DOUBLE ANGLE QUOTATION MARK
+0xAC	0x00AC	# NOT SIGN
+0xAD	0x00AD	# SOFT HYPHEN
+0xAE	0x00AE	# REGISTERED SIGN
+0xAF	0x00AF	# MACRON
+0xB0	0x00B0	# DEGREE SIGN
+0xB1	0x00B1	# PLUS-MINUS SIGN
+0xB2	0x00B2	# SUPERSCRIPT TWO
+0xB3	0x00B3	# SUPERSCRIPT THREE
+0xB4	0x00B4	# ACUTE ACCENT
+0xB5	0x00B5	# MICRO SIGN
+0xB6	0x00B6	# PILCROW SIGN
+0xB7	0x00B7	# MIDDLE DOT
+0xB8	0x00B8	# CEDILLA
+0xB9	0x00B9	# SUPERSCRIPT ONE
+0xBA	0x061B	# ARABIC SEMICOLON
+0xBB	0x00BB	# RIGHT-POINTING DOUBLE ANGLE QUOTATION MARK
+0xBC	0x00BC	# VULGAR FRACTION ONE QUARTER
+0xBD	0x00BD	# VULGAR FRACTION ONE HALF
+0xBE	0x00BE	# VULGAR FRACTION THREE QUARTERS
+0xBF	0x061F	# ARABIC QUESTION MARK
+0xC0	0x06C1	# ARABIC LETTER HEH GOAL
+0xC1	0x0621	# ARABIC LETTER HAMZA
+0xC2	0x0622	# ARABIC LETTER ALEF WITH MADDA ABOVE
+0xC3	0x0623	# ARABIC LETTER ALEF WITH HAMZA ABOVE
+0xC4	0x0624	# ARABIC LETTER WAW WITH HAMZA ABOVE
+0xC5	0x0625	# ARABIC LETTER ALEF WITH HAMZA BELOW
+0xC6	0x0626	# ARABIC LETTER YEH WITH HAMZA ABOVE
+0xC7	0x0627	# ARABIC LETTER ALEF
+0xC8	0x0628	# ARABIC LETTER BEH
+0xC9	0x0629	# ARABIC LETTER TEH MARBUTA
+0xCA	0x062A	# ARABIC LETTER TEH
+0xCB	0x062B	# ARABIC LETTER THEH
+0xCC	0x062C	# ARABIC LETTER JEEM
+0xCD	0x062D	# ARABIC LETTER HAH
+0xCE	0x062E	# ARABIC LETTER KHAH
+0xCF	0x062F	# ARABIC LETTER DAL
+0xD0	0x0630	# ARABIC LETTER THAL
+0xD1	0x0631	# ARABIC LETTER REH
+0xD2	0x0632	# ARABIC LETTER ZAIN
+0xD3	0x0633	# ARABIC LETTER SEEN
+0xD4	0x0634	# ARABIC LETTER SHEEN
+0xD5	0x0635	# ARABIC LETTER SAD
+0xD6	0x0636	# ARABIC LETTER DAD
+0xD7	0x00D7	# MULTIPLICATION SIGN
+0xD8	0x0637	# ARABIC LETTER TAH
+0xD9	0x0638	# ARABIC LETTER ZAH
+0xDA	0x0639	# ARABIC LETTER AIN
+0xDB	0x063A	# ARABIC LETTER GHAIN
+0xDC	0x0640	# ARABIC TATWEEL
+0xDD	0x0641	# ARABIC LETTER FEH
+0xDE	0x0642	# ARABIC LETTER QAF
+0xDF	0x0643	# ARABIC LETTER KAF
+0xE0	0x00E0	# LATIN SMALL LETTER A WITH GRAVE
+0xE1	0x0644	# ARABIC LETTER LAM
+0xE2	0x00E2	# LATIN SMALL LETTER A WITH CIRCUMFLEX
+0xE3	0x0645	# ARABIC LETTER MEEM
+0xE4	0x0646	# ARABIC LETTER NOON
+0xE5	0x0647	# ARABIC LETTER HEH
+0xE6	0x0648	# ARABIC LETTER WAW
+0xE7	0x00E7	# LATIN SMALL LETTER C WITH CEDILLA
+0xE8	0x00E8	# LATIN SMALL LETTER E WITH GRAVE
+0xE9	0x00E9	# LATIN SMALL LETTER E WITH ACUTE
+0xEA	0x00EA	# LATIN SMALL LETTER E WITH CIRCUMFLEX
+0xEB	0x00EB	# LATIN SMALL LETTER E WITH DIAERESIS
+0xEC	0x0649	# ARABIC LETTER ALEF MAKSURA
+0xED	0x064A	# ARABIC LETTER YEH
+0xEE	0x00EE	# LATIN SMALL LETTER I WITH CIRCUMFLEX
+0xEF	0x00EF	# LATIN SMALL LETTER I WITH DIAERESIS
+0xF0	0x064B	# ARABIC FATHATAN
+0xF1	0x064C	# ARABIC DAMMATAN
+0xF2	0x064D	# ARABIC KASRATAN
+0xF3	0x064E	# ARABIC FATHA
+0xF4	0x00F4	# LATIN SMALL LETTER O WITH CIRCUMFLEX
+0xF5	0x064F	# ARABIC DAMMA
+0xF6	0x0650	# ARABIC KASRA
+0xF7	0x00F7	# DIVISION SIGN
+0xF8	0x0651	# ARABIC SHADDA
+0xF9	0x00F9	# LATIN SMALL LETTER U WITH GRAVE
+0xFA	0x0652	# ARABIC SUKUN
+0xFB	0x00FB	# LATIN SMALL LETTER U WITH CIRCUMFLEX
+0xFC	0x00FC	# LATIN SMALL LETTER U WITH DIAERESIS
+0xFD	0x200E	# LEFT-TO-RIGHT MARK
+0xFE	0x200F	# RIGHT-TO-LEFT MARK
+0xFF	0x06D2	# ARABIC LETTER YEH BARREE
Index: /main/tags/2.25/gsdl/win32.mak
===================================================================
--- /main/tags/2.25/gsdl/win32.mak	(revision 21064)
+++ /main/tags/2.25/gsdl/win32.mak	(revision 21064)
@@ -0,0 +1,57 @@
+###########################################################################
+#
+# win32 makefile -- gsdl
+# A component of the Greenstone digital library software
+# from the New Zealand Digital Library Project at the
+# University of Waikato, New Zealand.
+#
+# Copyright (C) 1999  The 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.
+#
+###########################################################################
+
+GSDLHOME = d:\home\dl\gsdl
+
+AR = lib
+CC = cl
+CPPFLAGS =
+
+MAKE = nmake
+MDEFINES = /nologo /c /s /f win32.mak
+COMPILE = $(CC) -c $(CPPFLAGS) $(DEFS) $(INCLUDES)
+
+SOURCES = 
+
+OBJECTS = 
+
+ALLFILES = $(OBJECTS)
+
+DIRS = packages\wingdbm packages\mg\lib packages\mg\src\text lib \
+       src\colservr src\recpt src\w32server src\txt2db src\db2txt src\hashfile
+
+INSTALLDIRS = src\recpt src\w32server src\txt2db src\db2txt src\hashfile packages\mg\src\text
+
+all:
+	for %%o in ($(DIRS)) do \
+	  (cd %%o && $(MAKE) $(MDEFINES) $@ && cd $(GSDLHOME)) || exit 1
+
+install:
+	for %%i in ($(INSTALLDIRS)) do \
+	  (cd %%i && $(MAKE) $(MDEFINES) install && cd $(GSDLHOME)) || exit 1
+clean:
+	for %%s in ($(DIRS)) do \
+	  (cd %%s && $(MAKE) $(MDEFINES) clean && cd $(GSDLHOME)) || exit 1
Index: /main/tags/2.25/niupepa/Makefile.in
===================================================================
--- /main/tags/2.25/niupepa/Makefile.in	(revision 21064)
+++ /main/tags/2.25/niupepa/Makefile.in	(revision 21064)
@@ -0,0 +1,94 @@
+###########################################################################
+#
+# Makefile -- niupepa
+# A component of the Greenstone digital library software
+# from the New Zealand Digital Library Project at the
+# University of Waikato, New Zealand.
+#
+# Copyright (C) 1999  The 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 = @PACKAGE@
+VERSION = @VERSION@
+
+@SET_MAKE@
+CC = @CC@
+CPP = @CXX@
+CFLAGS = @CFLAGS@
+LIBS   = @LIBS@
+MDEFINES =
+TOPSRC = `pwd`
+
+GSDLOS = @gsdlos@
+
+COMPILE = $(CC) -c
+
+SOURCES = 
+
+OBJECTS = 
+
+ALLFILES = $(OBJECTS)
+
+DIRS = src/recpt
+
+all:
+	for odir in $(DIRS); do \
+	  echo making $@ in $$odir; \
+	  (cd $$odir && $(MAKE) $(MDEFINES) $@) || exit 1; \
+	done
+
+install:
+	for idir in $(DIRS); do \
+	  echo installing $$idir; \
+	  (cd $$idir && $(MAKE) install) || exit 1; \
+	done
+
+distclean:
+	rm -f Makefile config.cache config.h config.log stamp-h config.status
+	for subdir in $(DIRS); do \
+	  echo cleaning $@ in $$subdir; \
+	  (cd $$subdir && $(MAKE) distclean) || exit 1; \
+	done
+
+clean:
+	for subdir in $(DIRS); do \
+	  echo cleaning $@ in $$subdir; \
+	  (cd $$subdir && $(MAKE) clean) || exit 1; \
+	done
+
+
+# For an explanation of the following Makefile rules, see node
+# `Automatic Remaking' in GNU Autoconf documentation.
+Makefile: Makefile.in config.status
+	CONFIG_FILES=$@ CONFIG_HEADERS= ./config.status
+config.status: configure
+	./config.status --recheck
+configure: configure.in aclocal.m4
+	cd $(srcdir) && autoconf
+
+config.h: stamp-h
+stamp-h: config.h.in config.status
+	CONFIG_FILES= CONFIG_HEADERS=config.h ./config.status
+config.h.in: stamp-h.in
+stamp-h.in: configure.in aclocal.m4 acconfig.h
+	cd $(srcdir) && autoheader
+	$(TOUCH) $(srcdir)/stamp-h.in
+
+
+
Index: /main/tags/2.25/niupepa/acconfig.h
===================================================================
--- /main/tags/2.25/niupepa/acconfig.h	(revision 21064)
+++ /main/tags/2.25/niupepa/acconfig.h	(revision 21064)
@@ -0,0 +1,43 @@
+/* Special definitions for mg, processed by autoheader.
+   Created by [TS:Aug/95] 
+   by grepping for AC_DEFINE on configure.in and using the appropriate defs 
+   of acconfig.h used by GNU tar.
+*/
+
+/* Define to the name of the distribution.  */
+#undef PACKAGE
+
+/* Define to the version of the distribution.  */
+#undef VERSION
+
+/* Define if `union wait' is the type of the first arg to wait functions.  */
+#undef HAVE_UNION_WAIT
+
+/* Define to 1 if you have the valloc function.  */
+#undef HAVE_VALLOC
+
+/* Define to 1 if ANSI function prototypes are usable.  */
+#undef PROTOTYPES
+ 
+/* Define to 1 for better use of the debugging malloc library.  See
+   site ftp.antaire.com in antaire/src, file dmalloc/dmalloc.tar.gz.  */
+#undef WITH_DMALLOC
+ 
+/* Define to 1 if GNU regex should be used instead of GNU rx.  */
+#undef WITH_REGEX
+
+/* Some braindead header files do not have the requ'd function declarations */
+#undef HAVE_FGETC_DECL
+#undef HAVE_FREAD_DECL
+
+/* See if have this field in the prstatus_t structure */
+/* It stores the size of the process heap */
+#undef HAVE_PR_BRKSIZE
+
+/* Define FASTCGI if needsbe */
+#undef USE_FASTCGI
+
+
+
+
+
Index: /main/tags/2.25/niupepa/aclocal.m4
===================================================================
--- /main/tags/2.25/niupepa/aclocal.m4	(revision 21064)
+++ /main/tags/2.25/niupepa/aclocal.m4	(revision 21064)
@@ -0,0 +1,141 @@
+# Local additions to Autoconf macros.
+# Copyright (C) 1992, 1994, 1995 Free Software Foundation, Inc.
+# François Pinard <pinard@iro.umontreal.ca>, 1992.
+
+# [TS:Aug/95] - chopped out the NLS stuff which I don't support
+
+## ------------------------------- ##
+## Check for function prototypes.  ##
+## ------------------------------- ##
+
+AC_DEFUN(fp_C_PROTOTYPES,
+[AC_REQUIRE([fp_PROG_CC_STDC])
+AC_MSG_CHECKING([for function prototypes])
+if test "$ac_cv_prog_cc_stdc" != no; then
+  AC_MSG_RESULT(yes)
+  AC_DEFINE(PROTOTYPES)
+  U= ANSI2KNR=
+else
+  AC_MSG_RESULT(no)
+  U=_ ANSI2KNR=ansi2knr
+fi
+AC_SUBST(U)dnl
+AC_SUBST(ANSI2KNR)dnl
+])
+
+## ----------------------------------------- ##
+## ANSIfy the C compiler whenever possible.  ##
+## ----------------------------------------- ##
+
+# @defmac AC_PROG_CC_STDC
+# @maindex PROG_CC_STDC
+# @ovindex CC
+# If the C compiler in not in ANSI C mode by default, try to add an option
+# to output variable @code{CC} to make it so.  This macro tries various
+# options that select ANSI C on some system or another.  It considers the
+# compiler to be in ANSI C mode if it defines @code{__STDC__} to 1 and
+# handles function prototypes correctly.
+#
+# If you use this macro, you should check after calling it whether the C
+# compiler has been set to accept ANSI C; if not, the shell variable
+# @code{ac_cv_prog_cc_stdc} is set to @samp{no}.  If you wrote your source
+# code in ANSI C, you can make an un-ANSIfied copy of it by using the
+# program @code{ansi2knr}, which comes with Ghostscript.
+# @end defmac
+
+AC_DEFUN(fp_PROG_CC_STDC,
+[AC_MSG_CHECKING(for ${CC-cc} option to accept ANSI C)
+AC_CACHE_VAL(ac_cv_prog_cc_stdc,
+[ac_cv_prog_cc_stdc=no
+ac_save_CFLAGS="$CFLAGS"
+# Don't try gcc -ansi; that turns off useful extensions and
+# breaks some systems' header files.
+# AIX			-qlanglvl=ansi
+# Ultrix and OSF/1	-std1
+# HP-UX			-Aa -D_HPUX_SOURCE
+# SVR4			-Xc
+for ac_arg in "" -qlanglvl=ansi -std1 "-Aa -D_HPUX_SOURCE" -Xc
+do
+  CFLAGS="$ac_save_CFLAGS $ac_arg"
+  AC_TRY_COMPILE(
+[#if !defined(__STDC__) || __STDC__ != 1
+choke me
+#endif	
+], [int test (int i, double x);
+struct s1 {int (*f) (int a);};
+struct s2 {int (*f) (double a);};],
+[ac_cv_prog_cc_stdc="$ac_arg"; break])
+done
+CFLAGS="$ac_save_CFLAGS"
+])
+AC_MSG_RESULT($ac_cv_prog_cc_stdc)
+case "x$ac_cv_prog_cc_stdc" in
+  x|xno) ;;
+  *) CC="$CC $ac_cv_prog_cc_stdc" ;;
+esac
+])
+
+## --------------------------------------------------------- ##
+## Use AC_PROG_INSTALL, supplementing it with INSTALL_SCRIPT ##
+## substitution.					     ##
+## --------------------------------------------------------- ##
+
+AC_DEFUN(fp_PROG_INSTALL,
+[AC_PROG_INSTALL
+test -z "$INSTALL_SCRIPT" && INSTALL_SCRIPT='${INSTALL} -m 755'
+AC_SUBST(INSTALL_SCRIPT)dnl
+])
+
+## ----------------------------------- ##
+## Check if --with-dmalloc was given.  ##
+## ----------------------------------- ##
+
+# I just checked, and GNU rx seems to work fine with a slightly
+# modified GNU m4.  So, I put out the test below in my aclocal.m4,
+# and will try to use it in my things.  The idea is to distribute
+# rx.[hc] and regex.[hc] together, for a while.  The WITH_REGEX symbol
+# (which should also be documented in acconfig.h) is used to decide
+# which of regex.h or rx.h should be included in the application.
+#
+# If `./configure --with-regex' is given, the package will use
+# the older regex.  Else, a check is made to see if rx is already
+# installed, as with newer Linux'es.  If not found, the package will
+# use the rx from the distribution.  If found, the package will use
+# the system's rx which, on Linux at least, will result in a smaller
+# executable file.
+
+AC_DEFUN(fp_WITH_DMALLOC,
+[AC_MSG_CHECKING(if malloc debugging is wanted)
+AC_ARG_WITH(dmalloc,
+[  --with-dmalloc          use dmalloc, as in
+                          ftp://ftp.letters.com/src/dmalloc/dmalloc.tar.gz],
+[if test "$withval" = yes; then
+  AC_MSG_RESULT(yes)
+  AC_DEFINE(WITH_DMALLOC)
+  LIBS="$LIBS -ldmalloc"
+  LDFLAGS="$LDFLAGS -g"
+else
+  AC_MSG_RESULT(no)
+fi], [AC_MSG_RESULT(no)])
+])
+
+## --------------------------------- ##
+## Check if --with-regex was given.  ##
+## --------------------------------- ##
+
+AC_DEFUN(fp_WITH_REGEX,
+[AC_MSG_CHECKING(which of rx or regex is wanted)
+AC_ARG_WITH(regex,
+[  --with-regex            use older regex in lieu of GNU rx for matching],
+[if test "$withval" = yes; then
+  ac_with_regex=1
+  AC_MSG_RESULT(regex)
+  AC_DEFINE(WITH_REGEX)
+  LIBOBJS="$LIBOBJS regex.o"
+fi])
+if test -z "$ac_with_regex"; then
+  AC_MSG_RESULT(rx)
+  AC_CHECK_FUNC(re_rx_search, , [LIBOBJS="$LIBOBJS rx.o"])
+fi
+AC_SUBST(LIBOBJS)dnl
+])
Index: /main/tags/2.25/niupepa/config.h.in
===================================================================
--- /main/tags/2.25/niupepa/config.h.in	(revision 21064)
+++ /main/tags/2.25/niupepa/config.h.in	(revision 21064)
@@ -0,0 +1,192 @@
+/* config.h.in.  Generated automatically from configure.in by autoheader.  */
+
+/* Define if on AIX 3.
+   System headers sometimes define this.
+   We just want to avoid a redefinition error message.  */
+#ifndef _ALL_SOURCE
+#undef _ALL_SOURCE
+#endif
+
+/* Define if using alloca.c.  */
+#undef C_ALLOCA
+
+/* Define to empty if the keyword does not work.  */
+#undef const
+
+/* Define to one of _getb67, GETB67, getb67 for Cray-2 and Cray-YMP systems.
+   This function is required for alloca.c support on those systems.  */
+#undef CRAY_STACKSEG_END
+
+/* Define if you have alloca, as a function or macro.  */
+#undef HAVE_ALLOCA
+
+/* Define if you have <alloca.h> and it should be used (not on Ultrix).  */
+#undef HAVE_ALLOCA_H
+
+/* Define if you don't have vprintf but do have _doprnt.  */
+#undef HAVE_DOPRNT
+
+/* Define if you have the vprintf function.  */
+#undef HAVE_VPRINTF
+
+/* Define if on MINIX.  */
+#undef _MINIX
+
+/* Define to `long' if <sys/types.h> doesn't define.  */
+#undef off_t
+
+/* Define if the system does not provide POSIX.1 features except
+   with this defined.  */
+#undef _POSIX_1_SOURCE
+
+/* Define if you need to in order for stat and other things to work.  */
+#undef _POSIX_SOURCE
+
+/* Define as the return type of signal handlers (int or void).  */
+#undef RETSIGTYPE
+
+/* Define to `unsigned' if <sys/types.h> doesn't define.  */
+#undef size_t
+
+/* If using the C implementation of alloca, define if you know the
+   direction of stack growth for your system; otherwise it will be
+   automatically deduced at run-time.
+ STACK_DIRECTION > 0 => grows toward higher addresses
+ STACK_DIRECTION < 0 => grows toward lower addresses
+ STACK_DIRECTION = 0 => direction of growth unknown
+ */
+#undef STACK_DIRECTION
+
+/* Define if you have the ANSI C header files.  */
+#undef STDC_HEADERS
+
+/* Define if you can safely include both <sys/time.h> and <time.h>.  */
+#undef TIME_WITH_SYS_TIME
+
+/* Define if your <sys/time.h> declares struct tm.  */
+#undef TM_IN_SYS_TIME
+
+/* Define to the name of the distribution.  */
+#undef PACKAGE
+
+/* Define to the version of the distribution.  */
+#undef VERSION
+
+/* Define to 1 if you have the valloc function.  */
+#undef HAVE_VALLOC
+
+/* Define to 1 if ANSI function prototypes are usable.  */
+#undef PROTOTYPES
+
+ 
+/* Define to 1 for better use of the debugging malloc library.  See
+   site ftp.antaire.com in antaire/src, file dmalloc/dmalloc.tar.gz.  */
+#undef WITH_DMALLOC
+
+ 
+/* Define to 1 if GNU regex should be used instead of GNU rx.  */
+#undef WITH_REGEX
+
+/* Some braindead header files do not have the requ'd function declarations */
+#undef HAVE_FGETC_DECL
+#undef HAVE_FREAD_DECL
+
+/* See if have this field in the prstatus_t structure */
+/* It stores the size of the process heap */
+#undef HAVE_PR_BRKSIZE
+
+/* Define FASTCGI if needsbe */
+#undef USE_FASTCGI
+
+/* Define if you have the ftime function.  */
+#undef HAVE_FTIME
+
+/* Define if you have the ftruncate function.  */
+#undef HAVE_FTRUNCATE
+
+/* Define if you have the getpagesize function.  */
+#undef HAVE_GETPAGESIZE
+
+/* Define if you have the getrusage function.  */
+#undef HAVE_GETRUSAGE
+
+/* Define if you have the mallinfo function.  */
+#undef HAVE_MALLINFO
+
+/* Define if you have the select function.  */
+#undef HAVE_SELECT
+
+/* Define if you have the setbuffer function.  */
+#undef HAVE_SETBUFFER
+
+/* Define if you have the strcasecmp function.  */
+#undef HAVE_STRCASECMP
+
+/* Define if you have the strerror function.  */
+#undef HAVE_STRERROR
+
+/* Define if you have the strftime function.  */
+#undef HAVE_STRFTIME
+
+/* Define if you have the strstr function.  */
+#undef HAVE_STRSTR
+
+/* Define if you have the strtol function.  */
+#undef HAVE_STRTOL
+
+/* Define if you have the times function.  */
+#undef HAVE_TIMES
+
+/* Define if you have the valloc function.  */
+#undef HAVE_VALLOC
+
+/* Define if you have the <crypt.h> header file.  */
+#undef HAVE_CRYPT_H
+
+/* Define if you have the <dirent.h> header file.  */
+#undef HAVE_DIRENT_H
+
+/* Define if you have the <fcntl.h> header file.  */
+#undef HAVE_FCNTL_H
+
+/* Define if you have the <limits.h> header file.  */
+#undef HAVE_LIMITS_H
+
+/* Define if you have the <memory.h> header file.  */
+#undef HAVE_MEMORY_H
+
+/* Define if you have the <ndir.h> header file.  */
+#undef HAVE_NDIR_H
+
+/* Define if you have the <string.h> header file.  */
+#undef HAVE_STRING_H
+
+/* Define if you have the <sys/dir.h> header file.  */
+#undef HAVE_SYS_DIR_H
+
+/* Define if you have the <sys/ndir.h> header file.  */
+#undef HAVE_SYS_NDIR_H
+
+/* Define if you have the <sys/procfs.h> header file.  */
+#undef HAVE_SYS_PROCFS_H
+
+/* Define if you have the <sys/time.h> header file.  */
+#undef HAVE_SYS_TIME_H
+
+/* Define if you have the <unistd.h> header file.  */
+#undef HAVE_UNISTD_H
+
+/* Define if you have the crypt library (-lcrypt).  */
+#undef HAVE_LIBCRYPT
+
+/* Define if you have the g library (-lg).  */
+#undef HAVE_LIBG
+
+/* Define if you have the gdbm library (-lgdbm).  */
+#undef HAVE_LIBGDBM
+
+/* Define if you have the m library (-lm).  */
+#undef HAVE_LIBM
+
+/* Define if you have the stdc++ library (-lstdc++).  */
+#undef HAVE_LIBSTDC__
Index: /main/tags/2.25/niupepa/configtest.pl
===================================================================
--- /main/tags/2.25/niupepa/configtest.pl	(revision 21064)
+++ /main/tags/2.25/niupepa/configtest.pl	(revision 21064)
@@ -0,0 +1,1 @@
+print $]
Index: /main/tags/2.25/niupepa/configure
===================================================================
--- /main/tags/2.25/niupepa/configure	(revision 21064)
+++ /main/tags/2.25/niupepa/configure	(revision 21064)
@@ -0,0 +1,3675 @@
+#! /bin/sh
+
+# Guess values for system-dependent variables and create Makefiles.
+# Generated automatically using autoconf version 2.13 
+# Copyright (C) 1992, 93, 94, 95, 96 Free Software Foundation, Inc.
+#
+# This configure script is free software; the Free Software Foundation
+# gives unlimited permission to copy, distribute and modify it.
+
+# Defaults:
+ac_help=
+ac_default_prefix=/usr/local
+# Any additions from configure.in:
+ac_help="$ac_help
+  --with-dmalloc          use dmalloc, as in
+                          ftp://ftp.letters.com/src/dmalloc/dmalloc.tar.gz"
+ac_help="$ac_help
+  --with-regex            use older regex in lieu of GNU rx for matching"
+ac_help="$ac_help
+  --with-dmalloc          use dmalloc, as in
+                          ftp://ftp.letters.com/src/dmalloc/dmalloc.tar.gz"
+ac_help="$ac_help
+  --with-regex            use older regex in lieu of GNU rx for matching"
+
+# Initialize some variables set by options.
+# The variables have the same names as the options, with
+# dashes changed to underlines.
+build=NONE
+cache_file=./config.cache
+exec_prefix=NONE
+host=NONE
+no_create=
+nonopt=NONE
+no_recursion=
+prefix=NONE
+program_prefix=NONE
+program_suffix=NONE
+program_transform_name=s,x,x,
+silent=
+site=
+srcdir=
+target=NONE
+verbose=
+x_includes=NONE
+x_libraries=NONE
+bindir='${exec_prefix}/bin'
+sbindir='${exec_prefix}/sbin'
+libexecdir='${exec_prefix}/libexec'
+datadir='${prefix}/share'
+sysconfdir='${prefix}/etc'
+sharedstatedir='${prefix}/com'
+localstatedir='${prefix}/var'
+libdir='${exec_prefix}/lib'
+includedir='${prefix}/include'
+oldincludedir='/usr/include'
+infodir='${prefix}/info'
+mandir='${prefix}/man'
+
+# Initialize some other variables.
+subdirs=
+MFLAGS= MAKEFLAGS=
+SHELL=${CONFIG_SHELL-/bin/sh}
+# Maximum number of lines to put in a shell here document.
+ac_max_here_lines=12
+
+ac_prev=
+for ac_option
+do
+
+  # If the previous option needs an argument, assign it.
+  if test -n "$ac_prev"; then
+    eval "$ac_prev=\$ac_option"
+    ac_prev=
+    continue
+  fi
+
+  case "$ac_option" in
+  -*=*) ac_optarg=`echo "$ac_option" | sed 's/[-_a-zA-Z0-9]*=//'` ;;
+  *) ac_optarg= ;;
+  esac
+
+  # Accept the important Cygnus configure options, so we can diagnose typos.
+
+  case "$ac_option" in
+
+  -bindir | --bindir | --bindi | --bind | --bin | --bi)
+    ac_prev=bindir ;;
+  -bindir=* | --bindir=* | --bindi=* | --bind=* | --bin=* | --bi=*)
+    bindir="$ac_optarg" ;;
+
+  -build | --build | --buil | --bui | --bu)
+    ac_prev=build ;;
+  -build=* | --build=* | --buil=* | --bui=* | --bu=*)
+    build="$ac_optarg" ;;
+
+  -cache-file | --cache-file | --cache-fil | --cache-fi \
+  | --cache-f | --cache- | --cache | --cach | --cac | --ca | --c)
+    ac_prev=cache_file ;;
+  -cache-file=* | --cache-file=* | --cache-fil=* | --cache-fi=* \
+  | --cache-f=* | --cache-=* | --cache=* | --cach=* | --cac=* | --ca=* | --c=*)
+    cache_file="$ac_optarg" ;;
+
+  -datadir | --datadir | --datadi | --datad | --data | --dat | --da)
+    ac_prev=datadir ;;
+  -datadir=* | --datadir=* | --datadi=* | --datad=* | --data=* | --dat=* \
+  | --da=*)
+    datadir="$ac_optarg" ;;
+
+  -disable-* | --disable-*)
+    ac_feature=`echo $ac_option|sed -e 's/-*disable-//'`
+    # Reject names that are not valid shell variable names.
+    if test -n "`echo $ac_feature| sed 's/[-a-zA-Z0-9_]//g'`"; then
+      { echo "configure: error: $ac_feature: invalid feature name" 1>&2; exit 1; }
+    fi
+    ac_feature=`echo $ac_feature| sed 's/-/_/g'`
+    eval "enable_${ac_feature}=no" ;;
+
+  -enable-* | --enable-*)
+    ac_feature=`echo $ac_option|sed -e 's/-*enable-//' -e 's/=.*//'`
+    # Reject names that are not valid shell variable names.
+    if test -n "`echo $ac_feature| sed 's/[-_a-zA-Z0-9]//g'`"; then
+      { echo "configure: error: $ac_feature: invalid feature name" 1>&2; exit 1; }
+    fi
+    ac_feature=`echo $ac_feature| sed 's/-/_/g'`
+    case "$ac_option" in
+      *=*) ;;
+      *) ac_optarg=yes ;;
+    esac
+    eval "enable_${ac_feature}='$ac_optarg'" ;;
+
+  -exec-prefix | --exec_prefix | --exec-prefix | --exec-prefi \
+  | --exec-pref | --exec-pre | --exec-pr | --exec-p | --exec- \
+  | --exec | --exe | --ex)
+    ac_prev=exec_prefix ;;
+  -exec-prefix=* | --exec_prefix=* | --exec-prefix=* | --exec-prefi=* \
+  | --exec-pref=* | --exec-pre=* | --exec-pr=* | --exec-p=* | --exec-=* \
+  | --exec=* | --exe=* | --ex=*)
+    exec_prefix="$ac_optarg" ;;
+
+  -gas | --gas | --ga | --g)
+    # Obsolete; use --with-gas.
+    with_gas=yes ;;
+
+  -help | --help | --hel | --he)
+    # Omit some internal or obsolete options to make the list less imposing.
+    # This message is too long to be a string in the A/UX 3.1 sh.
+    cat << EOF
+Usage: configure [options] [host]
+Options: [defaults in brackets after descriptions]
+Configuration:
+  --cache-file=FILE       cache test results in FILE
+  --help                  print this message
+  --no-create             do not create output files
+  --quiet, --silent       do not print \`checking...' messages
+  --version               print the version of autoconf that created configure
+Directory and file names:
+  --prefix=PREFIX         install architecture-independent files in PREFIX
+                          [$ac_default_prefix]
+  --exec-prefix=EPREFIX   install architecture-dependent files in EPREFIX
+                          [same as prefix]
+  --bindir=DIR            user executables in DIR [EPREFIX/bin]
+  --sbindir=DIR           system admin executables in DIR [EPREFIX/sbin]
+  --libexecdir=DIR        program executables in DIR [EPREFIX/libexec]
+  --datadir=DIR           read-only architecture-independent data in DIR
+                          [PREFIX/share]
+  --sysconfdir=DIR        read-only single-machine data in DIR [PREFIX/etc]
+  --sharedstatedir=DIR    modifiable architecture-independent data in DIR
+                          [PREFIX/com]
+  --localstatedir=DIR     modifiable single-machine data in DIR [PREFIX/var]
+  --libdir=DIR            object code libraries in DIR [EPREFIX/lib]
+  --includedir=DIR        C header files in DIR [PREFIX/include]
+  --oldincludedir=DIR     C header files for non-gcc in DIR [/usr/include]
+  --infodir=DIR           info documentation in DIR [PREFIX/info]
+  --mandir=DIR            man documentation in DIR [PREFIX/man]
+  --srcdir=DIR            find the sources in DIR [configure dir or ..]
+  --program-prefix=PREFIX prepend PREFIX to installed program names
+  --program-suffix=SUFFIX append SUFFIX to installed program names
+  --program-transform-name=PROGRAM
+                          run sed PROGRAM on installed program names
+EOF
+    cat << EOF
+Host type:
+  --build=BUILD           configure for building on BUILD [BUILD=HOST]
+  --host=HOST             configure for HOST [guessed]
+  --target=TARGET         configure for TARGET [TARGET=HOST]
+Features and packages:
+  --disable-FEATURE       do not include FEATURE (same as --enable-FEATURE=no)
+  --enable-FEATURE[=ARG]  include FEATURE [ARG=yes]
+  --with-PACKAGE[=ARG]    use PACKAGE [ARG=yes]
+  --without-PACKAGE       do not use PACKAGE (same as --with-PACKAGE=no)
+  --x-includes=DIR        X include files are in DIR
+  --x-libraries=DIR       X library files are in DIR
+EOF
+    if test -n "$ac_help"; then
+      echo "--enable and --with options recognized:$ac_help"
+    fi
+    exit 0 ;;
+
+  -host | --host | --hos | --ho)
+    ac_prev=host ;;
+  -host=* | --host=* | --hos=* | --ho=*)
+    host="$ac_optarg" ;;
+
+  -includedir | --includedir | --includedi | --included | --include \
+  | --includ | --inclu | --incl | --inc)
+    ac_prev=includedir ;;
+  -includedir=* | --includedir=* | --includedi=* | --included=* | --include=* \
+  | --includ=* | --inclu=* | --incl=* | --inc=*)
+    includedir="$ac_optarg" ;;
+
+  -infodir | --infodir | --infodi | --infod | --info | --inf)
+    ac_prev=infodir ;;
+  -infodir=* | --infodir=* | --infodi=* | --infod=* | --info=* | --inf=*)
+    infodir="$ac_optarg" ;;
+
+  -libdir | --libdir | --libdi | --libd)
+    ac_prev=libdir ;;
+  -libdir=* | --libdir=* | --libdi=* | --libd=*)
+    libdir="$ac_optarg" ;;
+
+  -libexecdir | --libexecdir | --libexecdi | --libexecd | --libexec \
+  | --libexe | --libex | --libe)
+    ac_prev=libexecdir ;;
+  -libexecdir=* | --libexecdir=* | --libexecdi=* | --libexecd=* | --libexec=* \
+  | --libexe=* | --libex=* | --libe=*)
+    libexecdir="$ac_optarg" ;;
+
+  -localstatedir | --localstatedir | --localstatedi | --localstated \
+  | --localstate | --localstat | --localsta | --localst \
+  | --locals | --local | --loca | --loc | --lo)
+    ac_prev=localstatedir ;;
+  -localstatedir=* | --localstatedir=* | --localstatedi=* | --localstated=* \
+  | --localstate=* | --localstat=* | --localsta=* | --localst=* \
+  | --locals=* | --local=* | --loca=* | --loc=* | --lo=*)
+    localstatedir="$ac_optarg" ;;
+
+  -mandir | --mandir | --mandi | --mand | --man | --ma | --m)
+    ac_prev=mandir ;;
+  -mandir=* | --mandir=* | --mandi=* | --mand=* | --man=* | --ma=* | --m=*)
+    mandir="$ac_optarg" ;;
+
+  -nfp | --nfp | --nf)
+    # Obsolete; use --without-fp.
+    with_fp=no ;;
+
+  -no-create | --no-create | --no-creat | --no-crea | --no-cre \
+  | --no-cr | --no-c)
+    no_create=yes ;;
+
+  -no-recursion | --no-recursion | --no-recursio | --no-recursi \
+  | --no-recurs | --no-recur | --no-recu | --no-rec | --no-re | --no-r)
+    no_recursion=yes ;;
+
+  -oldincludedir | --oldincludedir | --oldincludedi | --oldincluded \
+  | --oldinclude | --oldinclud | --oldinclu | --oldincl | --oldinc \
+  | --oldin | --oldi | --old | --ol | --o)
+    ac_prev=oldincludedir ;;
+  -oldincludedir=* | --oldincludedir=* | --oldincludedi=* | --oldincluded=* \
+  | --oldinclude=* | --oldinclud=* | --oldinclu=* | --oldincl=* | --oldinc=* \
+  | --oldin=* | --oldi=* | --old=* | --ol=* | --o=*)
+    oldincludedir="$ac_optarg" ;;
+
+  -prefix | --prefix | --prefi | --pref | --pre | --pr | --p)
+    ac_prev=prefix ;;
+  -prefix=* | --prefix=* | --prefi=* | --pref=* | --pre=* | --pr=* | --p=*)
+    prefix="$ac_optarg" ;;
+
+  -program-prefix | --program-prefix | --program-prefi | --program-pref \
+  | --program-pre | --program-pr | --program-p)
+    ac_prev=program_prefix ;;
+  -program-prefix=* | --program-prefix=* | --program-prefi=* \
+  | --program-pref=* | --program-pre=* | --program-pr=* | --program-p=*)
+    program_prefix="$ac_optarg" ;;
+
+  -program-suffix | --program-suffix | --program-suffi | --program-suff \
+  | --program-suf | --program-su | --program-s)
+    ac_prev=program_suffix ;;
+  -program-suffix=* | --program-suffix=* | --program-suffi=* \
+  | --program-suff=* | --program-suf=* | --program-su=* | --program-s=*)
+    program_suffix="$ac_optarg" ;;
+
+  -program-transform-name | --program-transform-name \
+  | --program-transform-nam | --program-transform-na \
+  | --program-transform-n | --program-transform- \
+  | --program-transform | --program-transfor \
+  | --program-transfo | --program-transf \
+  | --program-trans | --program-tran \
+  | --progr-tra | --program-tr | --program-t)
+    ac_prev=program_transform_name ;;
+  -program-transform-name=* | --program-transform-name=* \
+  | --program-transform-nam=* | --program-transform-na=* \
+  | --program-transform-n=* | --program-transform-=* \
+  | --program-transform=* | --program-transfor=* \
+  | --program-transfo=* | --program-transf=* \
+  | --program-trans=* | --program-tran=* \
+  | --progr-tra=* | --program-tr=* | --program-t=*)
+    program_transform_name="$ac_optarg" ;;
+
+  -q | -quiet | --quiet | --quie | --qui | --qu | --q \
+  | -silent | --silent | --silen | --sile | --sil)
+    silent=yes ;;
+
+  -sbindir | --sbindir | --sbindi | --sbind | --sbin | --sbi | --sb)
+    ac_prev=sbindir ;;
+  -sbindir=* | --sbindir=* | --sbindi=* | --sbind=* | --sbin=* \
+  | --sbi=* | --sb=*)
+    sbindir="$ac_optarg" ;;
+
+  -sharedstatedir | --sharedstatedir | --sharedstatedi \
+  | --sharedstated | --sharedstate | --sharedstat | --sharedsta \
+  | --sharedst | --shareds | --shared | --share | --shar \
+  | --sha | --sh)
+    ac_prev=sharedstatedir ;;
+  -sharedstatedir=* | --sharedstatedir=* | --sharedstatedi=* \
+  | --sharedstated=* | --sharedstate=* | --sharedstat=* | --sharedsta=* \
+  | --sharedst=* | --shareds=* | --shared=* | --share=* | --shar=* \
+  | --sha=* | --sh=*)
+    sharedstatedir="$ac_optarg" ;;
+
+  -site | --site | --sit)
+    ac_prev=site ;;
+  -site=* | --site=* | --sit=*)
+    site="$ac_optarg" ;;
+
+  -srcdir | --srcdir | --srcdi | --srcd | --src | --sr)
+    ac_prev=srcdir ;;
+  -srcdir=* | --srcdir=* | --srcdi=* | --srcd=* | --src=* | --sr=*)
+    srcdir="$ac_optarg" ;;
+
+  -sysconfdir | --sysconfdir | --sysconfdi | --sysconfd | --sysconf \
+  | --syscon | --sysco | --sysc | --sys | --sy)
+    ac_prev=sysconfdir ;;
+  -sysconfdir=* | --sysconfdir=* | --sysconfdi=* | --sysconfd=* | --sysconf=* \
+  | --syscon=* | --sysco=* | --sysc=* | --sys=* | --sy=*)
+    sysconfdir="$ac_optarg" ;;
+
+  -target | --target | --targe | --targ | --tar | --ta | --t)
+    ac_prev=target ;;
+  -target=* | --target=* | --targe=* | --targ=* | --tar=* | --ta=* | --t=*)
+    target="$ac_optarg" ;;
+
+  -v | -verbose | --verbose | --verbos | --verbo | --verb)
+    verbose=yes ;;
+
+  -version | --version | --versio | --versi | --vers)
+    echo "configure generated by autoconf version 2.13"
+    exit 0 ;;
+
+  -with-* | --with-*)
+    ac_package=`echo $ac_option|sed -e 's/-*with-//' -e 's/=.*//'`
+    # Reject names that are not valid shell variable names.
+    if test -n "`echo $ac_package| sed 's/[-_a-zA-Z0-9]//g'`"; then
+      { echo "configure: error: $ac_package: invalid package name" 1>&2; exit 1; }
+    fi
+    ac_package=`echo $ac_package| sed 's/-/_/g'`
+    case "$ac_option" in
+      *=*) ;;
+      *) ac_optarg=yes ;;
+    esac
+    eval "with_${ac_package}='$ac_optarg'" ;;
+
+  -without-* | --without-*)
+    ac_package=`echo $ac_option|sed -e 's/-*without-//'`
+    # Reject names that are not valid shell variable names.
+    if test -n "`echo $ac_package| sed 's/[-a-zA-Z0-9_]//g'`"; then
+      { echo "configure: error: $ac_package: invalid package name" 1>&2; exit 1; }
+    fi
+    ac_package=`echo $ac_package| sed 's/-/_/g'`
+    eval "with_${ac_package}=no" ;;
+
+  --x)
+    # Obsolete; use --with-x.
+    with_x=yes ;;
+
+  -x-includes | --x-includes | --x-include | --x-includ | --x-inclu \
+  | --x-incl | --x-inc | --x-in | --x-i)
+    ac_prev=x_includes ;;
+  -x-includes=* | --x-includes=* | --x-include=* | --x-includ=* | --x-inclu=* \
+  | --x-incl=* | --x-inc=* | --x-in=* | --x-i=*)
+    x_includes="$ac_optarg" ;;
+
+  -x-libraries | --x-libraries | --x-librarie | --x-librari \
+  | --x-librar | --x-libra | --x-libr | --x-lib | --x-li | --x-l)
+    ac_prev=x_libraries ;;
+  -x-libraries=* | --x-libraries=* | --x-librarie=* | --x-librari=* \
+  | --x-librar=* | --x-libra=* | --x-libr=* | --x-lib=* | --x-li=* | --x-l=*)
+    x_libraries="$ac_optarg" ;;
+
+  -*) { echo "configure: error: $ac_option: invalid option; use --help to show usage" 1>&2; exit 1; }
+    ;;
+
+  *)
+    if test -n "`echo $ac_option| sed 's/[-a-z0-9.]//g'`"; then
+      echo "configure: warning: $ac_option: invalid host type" 1>&2
+    fi
+    if test "x$nonopt" != xNONE; then
+      { echo "configure: error: can only configure for one host and one target at a time" 1>&2; exit 1; }
+    fi
+    nonopt="$ac_option"
+    ;;
+
+  esac
+done
+
+if test -n "$ac_prev"; then
+  { echo "configure: error: missing argument to --`echo $ac_prev | sed 's/_/-/g'`" 1>&2; exit 1; }
+fi
+
+trap 'rm -fr conftest* confdefs* core core.* *.core $ac_clean_files; exit 1' 1 2 15
+
+# File descriptor usage:
+# 0 standard input
+# 1 file creation
+# 2 errors and warnings
+# 3 some systems may open it to /dev/tty
+# 4 used on the Kubota Titan
+# 6 checking for... messages and results
+# 5 compiler messages saved in config.log
+if test "$silent" = yes; then
+  exec 6>/dev/null
+else
+  exec 6>&1
+fi
+exec 5>./config.log
+
+echo "\
+This file contains any messages produced by compilers while
+running configure, to aid debugging if configure makes a mistake.
+" 1>&5
+
+# Strip out --no-create and --no-recursion so they do not pile up.
+# Also quote any args containing shell metacharacters.
+ac_configure_args=
+for ac_arg
+do
+  case "$ac_arg" in
+  -no-create | --no-create | --no-creat | --no-crea | --no-cre \
+  | --no-cr | --no-c) ;;
+  -no-recursion | --no-recursion | --no-recursio | --no-recursi \
+  | --no-recurs | --no-recur | --no-recu | --no-rec | --no-re | --no-r) ;;
+  *" "*|*"	"*|*[\[\]\~\#\$\^\&\*\(\)\{\}\\\|\;\<\>\?]*)
+  ac_configure_args="$ac_configure_args '$ac_arg'" ;;
+  *) ac_configure_args="$ac_configure_args $ac_arg" ;;
+  esac
+done
+
+# NLS nuisances.
+# Only set these to C if already set.  These must not be set unconditionally
+# because not all systems understand e.g. LANG=C (notably SCO).
+# Fixing LC_MESSAGES prevents Solaris sh from translating var values in `set'!
+# Non-C LC_CTYPE values break the ctype check.
+if test "${LANG+set}"   = set; then LANG=C;   export LANG;   fi
+if test "${LC_ALL+set}" = set; then LC_ALL=C; export LC_ALL; fi
+if test "${LC_MESSAGES+set}" = set; then LC_MESSAGES=C; export LC_MESSAGES; fi
+if test "${LC_CTYPE+set}"    = set; then LC_CTYPE=C;    export LC_CTYPE;    fi
+
+# confdefs.h avoids OS command line length limits that DEFS can exceed.
+rm -rf conftest* confdefs.h
+# AIX cpp loses on an empty file, so make sure it contains at least a newline.
+echo > confdefs.h
+
+# A filename unique to this package, relative to the directory that
+# configure is in, which we can look for to find out if srcdir is correct.
+ac_unique_file=src/recpt/niupepalibrarymain.cpp
+
+# Find the source files, if location was not specified.
+if test -z "$srcdir"; then
+  ac_srcdir_defaulted=yes
+  # Try the directory containing this script, then its parent.
+  ac_prog=$0
+  ac_confdir=`echo $ac_prog|sed 's%/[^/][^/]*$%%'`
+  test "x$ac_confdir" = "x$ac_prog" && ac_confdir=.
+  srcdir=$ac_confdir
+  if test ! -r $srcdir/$ac_unique_file; then
+    srcdir=..
+  fi
+else
+  ac_srcdir_defaulted=no
+fi
+if test ! -r $srcdir/$ac_unique_file; then
+  if test "$ac_srcdir_defaulted" = yes; then
+    { echo "configure: error: can not find sources in $ac_confdir or .." 1>&2; exit 1; }
+  else
+    { echo "configure: error: can not find sources in $srcdir" 1>&2; exit 1; }
+  fi
+fi
+srcdir=`echo "${srcdir}" | sed 's%\([^/]\)/*$%\1%'`
+
+# Prefer explicitly selected file to automatically selected ones.
+if test -z "$CONFIG_SITE"; then
+  if test "x$prefix" != xNONE; then
+    CONFIG_SITE="$prefix/share/config.site $prefix/etc/config.site"
+  else
+    CONFIG_SITE="$ac_default_prefix/share/config.site $ac_default_prefix/etc/config.site"
+  fi
+fi
+for ac_site_file in $CONFIG_SITE; do
+  if test -r "$ac_site_file"; then
+    echo "loading site script $ac_site_file"
+    . "$ac_site_file"
+  fi
+done
+
+if test -r "$cache_file"; then
+  echo "loading cache $cache_file"
+  . $cache_file
+else
+  echo "creating cache $cache_file"
+  > $cache_file
+fi
+
+ac_ext=c
+# CFLAGS is not in ac_cpp because -g, -O, etc. are not valid cpp options.
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='${CC-cc} -c $CFLAGS $CPPFLAGS conftest.$ac_ext 1>&5'
+ac_link='${CC-cc} -o conftest${ac_exeext} $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS 1>&5'
+cross_compiling=$ac_cv_prog_cc_cross
+
+ac_exeext=
+ac_objext=o
+if (echo "testing\c"; echo 1,2,3) | grep c >/dev/null; then
+  # Stardent Vistra SVR4 grep lacks -e, says ghazi@caip.rutgers.edu.
+  if (echo -n testing; echo 1,2,3) | sed s/-n/xn/ | grep xn >/dev/null; then
+    ac_n= ac_c='
+' ac_t='	'
+  else
+    ac_n=-n ac_c= ac_t=
+  fi
+else
+  ac_n= ac_c='\c' ac_t=
+fi
+
+
+
+if test "$program_transform_name" = s,x,x,; then
+  program_transform_name=
+else
+  # Double any \ or $.  echo might interpret backslashes.
+  cat <<\EOF_SED > conftestsed
+s,\\,\\\\,g; s,\$,$$,g
+EOF_SED
+  program_transform_name="`echo $program_transform_name|sed -f conftestsed`"
+  rm -f conftestsed
+fi
+test "$program_prefix" != NONE &&
+  program_transform_name="s,^,${program_prefix},; $program_transform_name"
+# Use a double $ so make ignores it.
+test "$program_suffix" != NONE &&
+  program_transform_name="s,\$\$,${program_suffix},; $program_transform_name"
+
+# sed with no file args requires a program.
+test "$program_transform_name" = "" && program_transform_name="s,x,x,"
+
+
+PACKAGE=gsdl
+VERSION=2.1
+cat >> confdefs.h <<EOF
+#define PACKAGE "$PACKAGE"
+EOF
+
+cat >> confdefs.h <<EOF
+#define VERSION "$VERSION"
+EOF
+
+
+
+
+USE_FASTCGI=0
+if test USE_FASTCGI = 1; then
+cat >> confdefs.h <<\EOF
+#define USE_FASTCGI 1
+EOF
+
+
+fi
+
+LDFLAGS=
+CFLAGS=-O2
+
+
+# Extract the first word of "gcc", so it can be a program name with args.
+set dummy gcc; ac_word=$2
+echo $ac_n "checking for $ac_word""... $ac_c" 1>&6
+echo "configure:585: checking for $ac_word" >&5
+if eval "test \"`echo '$''{'ac_cv_prog_CC'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  if test -n "$CC"; then
+  ac_cv_prog_CC="$CC" # Let the user override the test.
+else
+  IFS="${IFS= 	}"; ac_save_ifs="$IFS"; IFS=":"
+  ac_dummy="$PATH"
+  for ac_dir in $ac_dummy; do
+    test -z "$ac_dir" && ac_dir=.
+    if test -f $ac_dir/$ac_word; then
+      ac_cv_prog_CC="gcc"
+      break
+    fi
+  done
+  IFS="$ac_save_ifs"
+fi
+fi
+CC="$ac_cv_prog_CC"
+if test -n "$CC"; then
+  echo "$ac_t""$CC" 1>&6
+else
+  echo "$ac_t""no" 1>&6
+fi
+
+if test -z "$CC"; then
+  # Extract the first word of "cc", so it can be a program name with args.
+set dummy cc; ac_word=$2
+echo $ac_n "checking for $ac_word""... $ac_c" 1>&6
+echo "configure:615: checking for $ac_word" >&5
+if eval "test \"`echo '$''{'ac_cv_prog_CC'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  if test -n "$CC"; then
+  ac_cv_prog_CC="$CC" # Let the user override the test.
+else
+  IFS="${IFS= 	}"; ac_save_ifs="$IFS"; IFS=":"
+  ac_prog_rejected=no
+  ac_dummy="$PATH"
+  for ac_dir in $ac_dummy; do
+    test -z "$ac_dir" && ac_dir=.
+    if test -f $ac_dir/$ac_word; then
+      if test "$ac_dir/$ac_word" = "/usr/ucb/cc"; then
+        ac_prog_rejected=yes
+	continue
+      fi
+      ac_cv_prog_CC="cc"
+      break
+    fi
+  done
+  IFS="$ac_save_ifs"
+if test $ac_prog_rejected = yes; then
+  # We found a bogon in the path, so make sure we never use it.
+  set dummy $ac_cv_prog_CC
+  shift
+  if test $# -gt 0; then
+    # We chose a different compiler from the bogus one.
+    # However, it has the same basename, so the bogon will be chosen
+    # first if we set CC to just the basename; use the full file name.
+    shift
+    set dummy "$ac_dir/$ac_word" "$@"
+    shift
+    ac_cv_prog_CC="$@"
+  fi
+fi
+fi
+fi
+CC="$ac_cv_prog_CC"
+if test -n "$CC"; then
+  echo "$ac_t""$CC" 1>&6
+else
+  echo "$ac_t""no" 1>&6
+fi
+
+  if test -z "$CC"; then
+    case "`uname -s`" in
+    *win32* | *WIN32*)
+      # Extract the first word of "cl", so it can be a program name with args.
+set dummy cl; ac_word=$2
+echo $ac_n "checking for $ac_word""... $ac_c" 1>&6
+echo "configure:666: checking for $ac_word" >&5
+if eval "test \"`echo '$''{'ac_cv_prog_CC'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  if test -n "$CC"; then
+  ac_cv_prog_CC="$CC" # Let the user override the test.
+else
+  IFS="${IFS= 	}"; ac_save_ifs="$IFS"; IFS=":"
+  ac_dummy="$PATH"
+  for ac_dir in $ac_dummy; do
+    test -z "$ac_dir" && ac_dir=.
+    if test -f $ac_dir/$ac_word; then
+      ac_cv_prog_CC="cl"
+      break
+    fi
+  done
+  IFS="$ac_save_ifs"
+fi
+fi
+CC="$ac_cv_prog_CC"
+if test -n "$CC"; then
+  echo "$ac_t""$CC" 1>&6
+else
+  echo "$ac_t""no" 1>&6
+fi
+ ;;
+    esac
+  fi
+  test -z "$CC" && { echo "configure: error: no acceptable cc found in \$PATH" 1>&2; exit 1; }
+fi
+
+echo $ac_n "checking whether the C compiler ($CC $CFLAGS $LDFLAGS) works""... $ac_c" 1>&6
+echo "configure:698: checking whether the C compiler ($CC $CFLAGS $LDFLAGS) works" >&5
+
+ac_ext=c
+# CFLAGS is not in ac_cpp because -g, -O, etc. are not valid cpp options.
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='${CC-cc} -c $CFLAGS $CPPFLAGS conftest.$ac_ext 1>&5'
+ac_link='${CC-cc} -o conftest${ac_exeext} $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS 1>&5'
+cross_compiling=$ac_cv_prog_cc_cross
+
+cat > conftest.$ac_ext << EOF
+
+#line 709 "configure"
+#include "confdefs.h"
+
+main(){return(0);}
+EOF
+if { (eval echo configure:714: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+  ac_cv_prog_cc_works=yes
+  # If we can't run a trivial program, we are probably using a cross compiler.
+  if (./conftest; exit) 2>/dev/null; then
+    ac_cv_prog_cc_cross=no
+  else
+    ac_cv_prog_cc_cross=yes
+  fi
+else
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  ac_cv_prog_cc_works=no
+fi
+rm -fr conftest*
+ac_ext=c
+# CFLAGS is not in ac_cpp because -g, -O, etc. are not valid cpp options.
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='${CC-cc} -c $CFLAGS $CPPFLAGS conftest.$ac_ext 1>&5'
+ac_link='${CC-cc} -o conftest${ac_exeext} $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS 1>&5'
+cross_compiling=$ac_cv_prog_cc_cross
+
+echo "$ac_t""$ac_cv_prog_cc_works" 1>&6
+if test $ac_cv_prog_cc_works = no; then
+  { echo "configure: error: installation or configuration problem: C compiler cannot create executables." 1>&2; exit 1; }
+fi
+echo $ac_n "checking whether the C compiler ($CC $CFLAGS $LDFLAGS) is a cross-compiler""... $ac_c" 1>&6
+echo "configure:740: checking whether the C compiler ($CC $CFLAGS $LDFLAGS) is a cross-compiler" >&5
+echo "$ac_t""$ac_cv_prog_cc_cross" 1>&6
+cross_compiling=$ac_cv_prog_cc_cross
+
+echo $ac_n "checking whether we are using GNU C""... $ac_c" 1>&6
+echo "configure:745: checking whether we are using GNU C" >&5
+if eval "test \"`echo '$''{'ac_cv_prog_gcc'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  cat > conftest.c <<EOF
+#ifdef __GNUC__
+  yes;
+#endif
+EOF
+if { ac_try='${CC-cc} -E conftest.c'; { (eval echo configure:754: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }; } | egrep yes >/dev/null 2>&1; then
+  ac_cv_prog_gcc=yes
+else
+  ac_cv_prog_gcc=no
+fi
+fi
+
+echo "$ac_t""$ac_cv_prog_gcc" 1>&6
+
+if test $ac_cv_prog_gcc = yes; then
+  GCC=yes
+else
+  GCC=
+fi
+
+ac_test_CFLAGS="${CFLAGS+set}"
+ac_save_CFLAGS="$CFLAGS"
+CFLAGS=
+echo $ac_n "checking whether ${CC-cc} accepts -g""... $ac_c" 1>&6
+echo "configure:773: checking whether ${CC-cc} accepts -g" >&5
+if eval "test \"`echo '$''{'ac_cv_prog_cc_g'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  echo 'void f(){}' > conftest.c
+if test -z "`${CC-cc} -g -c conftest.c 2>&1`"; then
+  ac_cv_prog_cc_g=yes
+else
+  ac_cv_prog_cc_g=no
+fi
+rm -f conftest*
+
+fi
+
+echo "$ac_t""$ac_cv_prog_cc_g" 1>&6
+if test "$ac_test_CFLAGS" = set; then
+  CFLAGS="$ac_save_CFLAGS"
+elif test $ac_cv_prog_cc_g = yes; then
+  if test "$GCC" = yes; then
+    CFLAGS="-g -O2"
+  else
+    CFLAGS="-g"
+  fi
+else
+  if test "$GCC" = yes; then
+    CFLAGS="-O2"
+  else
+    CFLAGS=
+  fi
+fi
+
+for ac_prog in $CCC c++ g++ gcc CC cxx cc++ cl
+do
+# Extract the first word of "$ac_prog", so it can be a program name with args.
+set dummy $ac_prog; ac_word=$2
+echo $ac_n "checking for $ac_word""... $ac_c" 1>&6
+echo "configure:809: checking for $ac_word" >&5
+if eval "test \"`echo '$''{'ac_cv_prog_CXX'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  if test -n "$CXX"; then
+  ac_cv_prog_CXX="$CXX" # Let the user override the test.
+else
+  IFS="${IFS= 	}"; ac_save_ifs="$IFS"; IFS=":"
+  ac_dummy="$PATH"
+  for ac_dir in $ac_dummy; do
+    test -z "$ac_dir" && ac_dir=.
+    if test -f $ac_dir/$ac_word; then
+      ac_cv_prog_CXX="$ac_prog"
+      break
+    fi
+  done
+  IFS="$ac_save_ifs"
+fi
+fi
+CXX="$ac_cv_prog_CXX"
+if test -n "$CXX"; then
+  echo "$ac_t""$CXX" 1>&6
+else
+  echo "$ac_t""no" 1>&6
+fi
+
+test -n "$CXX" && break
+done
+test -n "$CXX" || CXX="gcc"
+
+
+echo $ac_n "checking whether the C++ compiler ($CXX $CXXFLAGS $LDFLAGS) works""... $ac_c" 1>&6
+echo "configure:841: checking whether the C++ compiler ($CXX $CXXFLAGS $LDFLAGS) works" >&5
+
+ac_ext=C
+# CXXFLAGS is not in ac_cpp because -g, -O, etc. are not valid cpp options.
+ac_cpp='$CXXCPP $CPPFLAGS'
+ac_compile='${CXX-g++} -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext 1>&5'
+ac_link='${CXX-g++} -o conftest${ac_exeext} $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS 1>&5'
+cross_compiling=$ac_cv_prog_cxx_cross
+
+cat > conftest.$ac_ext << EOF
+
+#line 852 "configure"
+#include "confdefs.h"
+
+int main(){return(0);}
+EOF
+if { (eval echo configure:857: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+  ac_cv_prog_cxx_works=yes
+  # If we can't run a trivial program, we are probably using a cross compiler.
+  if (./conftest; exit) 2>/dev/null; then
+    ac_cv_prog_cxx_cross=no
+  else
+    ac_cv_prog_cxx_cross=yes
+  fi
+else
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  ac_cv_prog_cxx_works=no
+fi
+rm -fr conftest*
+ac_ext=c
+# CFLAGS is not in ac_cpp because -g, -O, etc. are not valid cpp options.
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='${CC-cc} -c $CFLAGS $CPPFLAGS conftest.$ac_ext 1>&5'
+ac_link='${CC-cc} -o conftest${ac_exeext} $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS 1>&5'
+cross_compiling=$ac_cv_prog_cc_cross
+
+echo "$ac_t""$ac_cv_prog_cxx_works" 1>&6
+if test $ac_cv_prog_cxx_works = no; then
+  { echo "configure: error: installation or configuration problem: C++ compiler cannot create executables." 1>&2; exit 1; }
+fi
+echo $ac_n "checking whether the C++ compiler ($CXX $CXXFLAGS $LDFLAGS) is a cross-compiler""... $ac_c" 1>&6
+echo "configure:883: checking whether the C++ compiler ($CXX $CXXFLAGS $LDFLAGS) is a cross-compiler" >&5
+echo "$ac_t""$ac_cv_prog_cxx_cross" 1>&6
+cross_compiling=$ac_cv_prog_cxx_cross
+
+echo $ac_n "checking whether we are using GNU C++""... $ac_c" 1>&6
+echo "configure:888: checking whether we are using GNU C++" >&5
+if eval "test \"`echo '$''{'ac_cv_prog_gxx'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  cat > conftest.C <<EOF
+#ifdef __GNUC__
+  yes;
+#endif
+EOF
+if { ac_try='${CXX-g++} -E conftest.C'; { (eval echo configure:897: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }; } | egrep yes >/dev/null 2>&1; then
+  ac_cv_prog_gxx=yes
+else
+  ac_cv_prog_gxx=no
+fi
+fi
+
+echo "$ac_t""$ac_cv_prog_gxx" 1>&6
+
+if test $ac_cv_prog_gxx = yes; then
+  GXX=yes
+else
+  GXX=
+fi
+
+ac_test_CXXFLAGS="${CXXFLAGS+set}"
+ac_save_CXXFLAGS="$CXXFLAGS"
+CXXFLAGS=
+echo $ac_n "checking whether ${CXX-g++} accepts -g""... $ac_c" 1>&6
+echo "configure:916: checking whether ${CXX-g++} accepts -g" >&5
+if eval "test \"`echo '$''{'ac_cv_prog_cxx_g'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  echo 'void f(){}' > conftest.cc
+if test -z "`${CXX-g++} -g -c conftest.cc 2>&1`"; then
+  ac_cv_prog_cxx_g=yes
+else
+  ac_cv_prog_cxx_g=no
+fi
+rm -f conftest*
+
+fi
+
+echo "$ac_t""$ac_cv_prog_cxx_g" 1>&6
+if test "$ac_test_CXXFLAGS" = set; then
+  CXXFLAGS="$ac_save_CXXFLAGS"
+elif test $ac_cv_prog_cxx_g = yes; then
+  if test "$GXX" = yes; then
+    CXXFLAGS="-g -O2"
+  else
+    CXXFLAGS="-g"
+  fi
+else
+  if test "$GXX" = yes; then
+    CXXFLAGS="-O2"
+  else
+    CXXFLAGS=
+  fi
+fi
+
+for ac_prog in mawk gawk nawk awk
+do
+# Extract the first word of "$ac_prog", so it can be a program name with args.
+set dummy $ac_prog; ac_word=$2
+echo $ac_n "checking for $ac_word""... $ac_c" 1>&6
+echo "configure:952: checking for $ac_word" >&5
+if eval "test \"`echo '$''{'ac_cv_prog_AWK'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  if test -n "$AWK"; then
+  ac_cv_prog_AWK="$AWK" # Let the user override the test.
+else
+  IFS="${IFS= 	}"; ac_save_ifs="$IFS"; IFS=":"
+  ac_dummy="$PATH"
+  for ac_dir in $ac_dummy; do
+    test -z "$ac_dir" && ac_dir=.
+    if test -f $ac_dir/$ac_word; then
+      ac_cv_prog_AWK="$ac_prog"
+      break
+    fi
+  done
+  IFS="$ac_save_ifs"
+fi
+fi
+AWK="$ac_cv_prog_AWK"
+if test -n "$AWK"; then
+  echo "$ac_t""$AWK" 1>&6
+else
+  echo "$ac_t""no" 1>&6
+fi
+
+test -n "$AWK" && break
+done
+
+for ac_prog in 'bison -y' byacc
+do
+# Extract the first word of "$ac_prog", so it can be a program name with args.
+set dummy $ac_prog; ac_word=$2
+echo $ac_n "checking for $ac_word""... $ac_c" 1>&6
+echo "configure:986: checking for $ac_word" >&5
+if eval "test \"`echo '$''{'ac_cv_prog_YACC'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  if test -n "$YACC"; then
+  ac_cv_prog_YACC="$YACC" # Let the user override the test.
+else
+  IFS="${IFS= 	}"; ac_save_ifs="$IFS"; IFS=":"
+  ac_dummy="$PATH"
+  for ac_dir in $ac_dummy; do
+    test -z "$ac_dir" && ac_dir=.
+    if test -f $ac_dir/$ac_word; then
+      ac_cv_prog_YACC="$ac_prog"
+      break
+    fi
+  done
+  IFS="$ac_save_ifs"
+fi
+fi
+YACC="$ac_cv_prog_YACC"
+if test -n "$YACC"; then
+  echo "$ac_t""$YACC" 1>&6
+else
+  echo "$ac_t""no" 1>&6
+fi
+
+test -n "$YACC" && break
+done
+test -n "$YACC" || YACC="yacc"
+
+ac_aux_dir=
+for ac_dir in $srcdir $srcdir/.. $srcdir/../..; do
+  if test -f $ac_dir/install-sh; then
+    ac_aux_dir=$ac_dir
+    ac_install_sh="$ac_aux_dir/install-sh -c"
+    break
+  elif test -f $ac_dir/install.sh; then
+    ac_aux_dir=$ac_dir
+    ac_install_sh="$ac_aux_dir/install.sh -c"
+    break
+  fi
+done
+if test -z "$ac_aux_dir"; then
+  { echo "configure: error: can not find install-sh or install.sh in $srcdir $srcdir/.. $srcdir/../.." 1>&2; exit 1; }
+fi
+ac_config_guess=$ac_aux_dir/config.guess
+ac_config_sub=$ac_aux_dir/config.sub
+ac_configure=$ac_aux_dir/configure # This should be Cygnus configure.
+
+# Find a good install program.  We prefer a C program (faster),
+# so one script is as good as another.  But avoid the broken or
+# incompatible versions:
+# SysV /etc/install, /usr/sbin/install
+# SunOS /usr/etc/install
+# IRIX /sbin/install
+# AIX /bin/install
+# AIX 4 /usr/bin/installbsd, which doesn't work without a -g flag
+# AFS /usr/afsws/bin/install, which mishandles nonexistent args
+# SVR4 /usr/ucb/install, which tries to use the nonexistent group "staff"
+# ./install, which can be erroneously created by make from ./install.sh.
+echo $ac_n "checking for a BSD compatible install""... $ac_c" 1>&6
+echo "configure:1047: checking for a BSD compatible install" >&5
+if test -z "$INSTALL"; then
+if eval "test \"`echo '$''{'ac_cv_path_install'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+    IFS="${IFS= 	}"; ac_save_IFS="$IFS"; IFS=":"
+  for ac_dir in $PATH; do
+    # Account for people who put trailing slashes in PATH elements.
+    case "$ac_dir/" in
+    /|./|.//|/etc/*|/usr/sbin/*|/usr/etc/*|/sbin/*|/usr/afsws/bin/*|/usr/ucb/*) ;;
+    *)
+      # OSF1 and SCO ODT 3.0 have their own names for install.
+      # Don't use installbsd from OSF since it installs stuff as root
+      # by default.
+      for ac_prog in ginstall scoinst install; do
+        if test -f $ac_dir/$ac_prog; then
+	  if test $ac_prog = install &&
+            grep dspmsg $ac_dir/$ac_prog >/dev/null 2>&1; then
+	    # AIX install.  It has an incompatible calling convention.
+	    :
+	  else
+	    ac_cv_path_install="$ac_dir/$ac_prog -c"
+	    break 2
+	  fi
+	fi
+      done
+      ;;
+    esac
+  done
+  IFS="$ac_save_IFS"
+
+fi
+  if test "${ac_cv_path_install+set}" = set; then
+    INSTALL="$ac_cv_path_install"
+  else
+    # As a last resort, use the slow shell script.  We don't cache a
+    # path for INSTALL within a source directory, because that will
+    # break other packages using the cache if that directory is
+    # removed, or if the path is relative.
+    INSTALL="$ac_install_sh"
+  fi
+fi
+echo "$ac_t""$INSTALL" 1>&6
+
+# Use test -z because SunOS4 sh mishandles braces in ${var-val}.
+# It thinks the first close brace ends the variable substitution.
+test -z "$INSTALL_PROGRAM" && INSTALL_PROGRAM='${INSTALL}'
+
+test -z "$INSTALL_SCRIPT" && INSTALL_SCRIPT='${INSTALL_PROGRAM}'
+
+test -z "$INSTALL_DATA" && INSTALL_DATA='${INSTALL} -m 644'
+
+echo $ac_n "checking whether ln -s works""... $ac_c" 1>&6
+echo "configure:1100: checking whether ln -s works" >&5
+if eval "test \"`echo '$''{'ac_cv_prog_LN_S'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  rm -f conftestdata
+if ln -s X conftestdata 2>/dev/null
+then
+  rm -f conftestdata
+  ac_cv_prog_LN_S="ln -s"
+else
+  ac_cv_prog_LN_S=ln
+fi
+fi
+LN_S="$ac_cv_prog_LN_S"
+if test "$ac_cv_prog_LN_S" = "ln -s"; then
+  echo "$ac_t""yes" 1>&6
+else
+  echo "$ac_t""no" 1>&6
+fi
+
+echo $ac_n "checking whether ${MAKE-make} sets \${MAKE}""... $ac_c" 1>&6
+echo "configure:1121: checking whether ${MAKE-make} sets \${MAKE}" >&5
+set dummy ${MAKE-make}; ac_make=`echo "$2" | sed 'y%./+-%__p_%'`
+if eval "test \"`echo '$''{'ac_cv_prog_make_${ac_make}_set'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  cat > conftestmake <<\EOF
+all:
+	@echo 'ac_maketemp="${MAKE}"'
+EOF
+# GNU make sometimes prints "make[1]: Entering...", which would confuse us.
+eval `${MAKE-make} -f conftestmake 2>/dev/null | grep temp=`
+if test -n "$ac_maketemp"; then
+  eval ac_cv_prog_make_${ac_make}_set=yes
+else
+  eval ac_cv_prog_make_${ac_make}_set=no
+fi
+rm -f conftestmake
+fi
+if eval "test \"`echo '$ac_cv_prog_make_'${ac_make}_set`\" = yes"; then
+  echo "$ac_t""yes" 1>&6
+  SET_MAKE=
+else
+  echo "$ac_t""no" 1>&6
+  SET_MAKE="MAKE=${MAKE-make}"
+fi
+
+# Extract the first word of "ranlib", so it can be a program name with args.
+set dummy ranlib; ac_word=$2
+echo $ac_n "checking for $ac_word""... $ac_c" 1>&6
+echo "configure:1150: checking for $ac_word" >&5
+if eval "test \"`echo '$''{'ac_cv_prog_RANLIB'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  if test -n "$RANLIB"; then
+  ac_cv_prog_RANLIB="$RANLIB" # Let the user override the test.
+else
+  IFS="${IFS= 	}"; ac_save_ifs="$IFS"; IFS=":"
+  ac_dummy="$PATH"
+  for ac_dir in $ac_dummy; do
+    test -z "$ac_dir" && ac_dir=.
+    if test -f $ac_dir/$ac_word; then
+      ac_cv_prog_RANLIB="ranlib"
+      break
+    fi
+  done
+  IFS="$ac_save_ifs"
+  test -z "$ac_cv_prog_RANLIB" && ac_cv_prog_RANLIB=":"
+fi
+fi
+RANLIB="$ac_cv_prog_RANLIB"
+if test -n "$RANLIB"; then
+  echo "$ac_t""$RANLIB" 1>&6
+else
+  echo "$ac_t""no" 1>&6
+fi
+
+
+
+echo $ac_n "checking how to run the C preprocessor""... $ac_c" 1>&6
+echo "configure:1180: checking how to run the C preprocessor" >&5
+# On Suns, sometimes $CPP names a directory.
+if test -n "$CPP" && test -d "$CPP"; then
+  CPP=
+fi
+if test -z "$CPP"; then
+if eval "test \"`echo '$''{'ac_cv_prog_CPP'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+    # This must be in double quotes, not single quotes, because CPP may get
+  # substituted into the Makefile and "${CC-cc}" will confuse make.
+  CPP="${CC-cc} -E"
+  # On the NeXT, cc -E runs the code through the compiler's parser,
+  # not just through cpp.
+  cat > conftest.$ac_ext <<EOF
+#line 1195 "configure"
+#include "confdefs.h"
+#include <assert.h>
+Syntax Error
+EOF
+ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out"
+{ (eval echo configure:1201: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }
+ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"`
+if test -z "$ac_err"; then
+  :
+else
+  echo "$ac_err" >&5
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -rf conftest*
+  CPP="${CC-cc} -E -traditional-cpp"
+  cat > conftest.$ac_ext <<EOF
+#line 1212 "configure"
+#include "confdefs.h"
+#include <assert.h>
+Syntax Error
+EOF
+ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out"
+{ (eval echo configure:1218: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }
+ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"`
+if test -z "$ac_err"; then
+  :
+else
+  echo "$ac_err" >&5
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -rf conftest*
+  CPP="${CC-cc} -nologo -E"
+  cat > conftest.$ac_ext <<EOF
+#line 1229 "configure"
+#include "confdefs.h"
+#include <assert.h>
+Syntax Error
+EOF
+ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out"
+{ (eval echo configure:1235: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }
+ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"`
+if test -z "$ac_err"; then
+  :
+else
+  echo "$ac_err" >&5
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -rf conftest*
+  CPP=/lib/cpp
+fi
+rm -f conftest*
+fi
+rm -f conftest*
+fi
+rm -f conftest*
+  ac_cv_prog_CPP="$CPP"
+fi
+  CPP="$ac_cv_prog_CPP"
+else
+  ac_cv_prog_CPP="$CPP"
+fi
+echo "$ac_t""$CPP" 1>&6
+
+echo $ac_n "checking for AIX""... $ac_c" 1>&6
+echo "configure:1260: checking for AIX" >&5
+cat > conftest.$ac_ext <<EOF
+#line 1262 "configure"
+#include "confdefs.h"
+#ifdef _AIX
+  yes
+#endif
+
+EOF
+if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
+  egrep "yes" >/dev/null 2>&1; then
+  rm -rf conftest*
+  echo "$ac_t""yes" 1>&6; cat >> confdefs.h <<\EOF
+#define _ALL_SOURCE 1
+EOF
+
+else
+  rm -rf conftest*
+  echo "$ac_t""no" 1>&6
+fi
+rm -f conftest*
+
+
+echo $ac_n "checking for POSIXized ISC""... $ac_c" 1>&6
+echo "configure:1284: checking for POSIXized ISC" >&5
+if test -d /etc/conf/kconfig.d &&
+  grep _POSIX_VERSION /usr/include/sys/unistd.h >/dev/null 2>&1
+then
+  echo "$ac_t""yes" 1>&6
+  ISC=yes # If later tests want to check for ISC.
+  cat >> confdefs.h <<\EOF
+#define _POSIX_SOURCE 1
+EOF
+
+  if test "$GCC" = yes; then
+    CC="$CC -posix"
+  else
+    CC="$CC -Xp"
+  fi
+else
+  echo "$ac_t""no" 1>&6
+  ISC=
+fi
+
+ac_safe=`echo "minix/config.h" | sed 'y%./+-%__p_%'`
+echo $ac_n "checking for minix/config.h""... $ac_c" 1>&6
+echo "configure:1306: checking for minix/config.h" >&5
+if eval "test \"`echo '$''{'ac_cv_header_$ac_safe'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  cat > conftest.$ac_ext <<EOF
+#line 1311 "configure"
+#include "confdefs.h"
+#include <minix/config.h>
+EOF
+ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out"
+{ (eval echo configure:1316: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }
+ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"`
+if test -z "$ac_err"; then
+  rm -rf conftest*
+  eval "ac_cv_header_$ac_safe=yes"
+else
+  echo "$ac_err" >&5
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -rf conftest*
+  eval "ac_cv_header_$ac_safe=no"
+fi
+rm -f conftest*
+fi
+if eval "test \"`echo '$ac_cv_header_'$ac_safe`\" = yes"; then
+  echo "$ac_t""yes" 1>&6
+  MINIX=yes
+else
+  echo "$ac_t""no" 1>&6
+MINIX=
+fi
+
+if test "$MINIX" = yes; then
+  cat >> confdefs.h <<\EOF
+#define _POSIX_SOURCE 1
+EOF
+
+  cat >> confdefs.h <<\EOF
+#define _POSIX_1_SOURCE 2
+EOF
+
+  cat >> confdefs.h <<\EOF
+#define _MINIX 1
+EOF
+
+fi
+
+echo $ac_n "checking for ${CC-cc} option to accept ANSI C""... $ac_c" 1>&6
+echo "configure:1354: checking for ${CC-cc} option to accept ANSI C" >&5
+if eval "test \"`echo '$''{'ac_cv_prog_cc_stdc'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  ac_cv_prog_cc_stdc=no
+ac_save_CFLAGS="$CFLAGS"
+# Don't try gcc -ansi; that turns off useful extensions and
+# breaks some systems' header files.
+# AIX			-qlanglvl=ansi
+# Ultrix and OSF/1	-std1
+# HP-UX			-Aa -D_HPUX_SOURCE
+# SVR4			-Xc
+for ac_arg in "" -qlanglvl=ansi -std1 "-Aa -D_HPUX_SOURCE" -Xc
+do
+  CFLAGS="$ac_save_CFLAGS $ac_arg"
+  cat > conftest.$ac_ext <<EOF
+#line 1370 "configure"
+#include "confdefs.h"
+#if !defined(__STDC__) || __STDC__ != 1
+choke me
+#endif	
+
+int main() {
+int test (int i, double x);
+struct s1 {int (*f) (int a);};
+struct s2 {int (*f) (double a);};
+; return 0; }
+EOF
+if { (eval echo configure:1382: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
+  rm -rf conftest*
+  ac_cv_prog_cc_stdc="$ac_arg"; break
+else
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+fi
+rm -f conftest*
+done
+CFLAGS="$ac_save_CFLAGS"
+
+fi
+
+echo "$ac_t""$ac_cv_prog_cc_stdc" 1>&6
+case "x$ac_cv_prog_cc_stdc" in
+  x|xno) ;;
+  *) CC="$CC $ac_cv_prog_cc_stdc" ;;
+esac
+
+
+echo $ac_n "checking for function prototypes""... $ac_c" 1>&6
+echo "configure:1403: checking for function prototypes" >&5
+if test "$ac_cv_prog_cc_stdc" != no; then
+  echo "$ac_t""yes" 1>&6
+  cat >> confdefs.h <<\EOF
+#define PROTOTYPES 1
+EOF
+
+  U= ANSI2KNR=
+else
+  echo "$ac_t""no" 1>&6
+  U=_ ANSI2KNR=ansi2knr
+fi
+
+echo $ac_n "checking for working const""... $ac_c" 1>&6
+echo "configure:1417: checking for working const" >&5
+if eval "test \"`echo '$''{'ac_cv_c_const'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  cat > conftest.$ac_ext <<EOF
+#line 1422 "configure"
+#include "confdefs.h"
+
+int main() {
+
+/* Ultrix mips cc rejects this.  */
+typedef int charset[2]; const charset x;
+/* SunOS 4.1.1 cc rejects this.  */
+char const *const *ccp;
+char **p;
+/* NEC SVR4.0.2 mips cc rejects this.  */
+struct point {int x, y;};
+static struct point const zero = {0,0};
+/* AIX XL C 1.02.0.0 rejects this.
+   It does not let you subtract one const X* pointer from another in an arm
+   of an if-expression whose if-part is not a constant expression */
+const char *g = "string";
+ccp = &g + (g ? g-g : 0);
+/* HPUX 7.0 cc rejects these. */
+++ccp;
+p = (char**) ccp;
+ccp = (char const *const *) p;
+{ /* SCO 3.2v4 cc rejects this.  */
+  char *t;
+  char const *s = 0 ? (char *) 0 : (char const *) 0;
+
+  *t++ = 0;
+}
+{ /* Someone thinks the Sun supposedly-ANSI compiler will reject this.  */
+  int x[] = {25, 17};
+  const int *foo = &x[0];
+  ++foo;
+}
+{ /* Sun SC1.0 ANSI compiler rejects this -- but not the above. */
+  typedef const int *iptr;
+  iptr p = 0;
+  ++p;
+}
+{ /* AIX XL C 1.02.0.0 rejects this saying
+     "k.c", line 2.27: 1506-025 (S) Operand must be a modifiable lvalue. */
+  struct s { int j; const int *ap[3]; };
+  struct s *b; b->j = 5;
+}
+{ /* ULTRIX-32 V3.1 (Rev 9) vcc rejects this */
+  const int foo = 10;
+}
+
+; return 0; }
+EOF
+if { (eval echo configure:1471: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
+  rm -rf conftest*
+  ac_cv_c_const=yes
+else
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -rf conftest*
+  ac_cv_c_const=no
+fi
+rm -f conftest*
+fi
+
+echo "$ac_t""$ac_cv_c_const" 1>&6
+if test $ac_cv_c_const = no; then
+  cat >> confdefs.h <<\EOF
+#define const 
+EOF
+
+fi
+
+echo $ac_n "checking for ANSI C header files""... $ac_c" 1>&6
+echo "configure:1492: checking for ANSI C header files" >&5
+if eval "test \"`echo '$''{'ac_cv_header_stdc'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  cat > conftest.$ac_ext <<EOF
+#line 1497 "configure"
+#include "confdefs.h"
+#include <stdlib.h>
+#include <stdarg.h>
+#include <string.h>
+#include <float.h>
+EOF
+ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out"
+{ (eval echo configure:1505: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }
+ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"`
+if test -z "$ac_err"; then
+  rm -rf conftest*
+  ac_cv_header_stdc=yes
+else
+  echo "$ac_err" >&5
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -rf conftest*
+  ac_cv_header_stdc=no
+fi
+rm -f conftest*
+
+if test $ac_cv_header_stdc = yes; then
+  # SunOS 4.x string.h does not declare mem*, contrary to ANSI.
+cat > conftest.$ac_ext <<EOF
+#line 1522 "configure"
+#include "confdefs.h"
+#include <string.h>
+EOF
+if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
+  egrep "memchr" >/dev/null 2>&1; then
+  :
+else
+  rm -rf conftest*
+  ac_cv_header_stdc=no
+fi
+rm -f conftest*
+
+fi
+
+if test $ac_cv_header_stdc = yes; then
+  # ISC 2.0.2 stdlib.h does not declare free, contrary to ANSI.
+cat > conftest.$ac_ext <<EOF
+#line 1540 "configure"
+#include "confdefs.h"
+#include <stdlib.h>
+EOF
+if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
+  egrep "free" >/dev/null 2>&1; then
+  :
+else
+  rm -rf conftest*
+  ac_cv_header_stdc=no
+fi
+rm -f conftest*
+
+fi
+
+if test $ac_cv_header_stdc = yes; then
+  # /bin/cc in Irix-4.0.5 gets non-ANSI ctype macros unless using -ansi.
+if test "$cross_compiling" = yes; then
+  :
+else
+  cat > conftest.$ac_ext <<EOF
+#line 1561 "configure"
+#include "confdefs.h"
+#include <ctype.h>
+#define ISLOWER(c) ('a' <= (c) && (c) <= 'z')
+#define TOUPPER(c) (ISLOWER(c) ? 'A' + ((c) - 'a') : (c))
+#define XOR(e, f) (((e) && !(f)) || (!(e) && (f)))
+int main () { int i; for (i = 0; i < 256; i++)
+if (XOR (islower (i), ISLOWER (i)) || toupper (i) != TOUPPER (i)) exit(2);
+exit (0); }
+
+EOF
+if { (eval echo configure:1572: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext} && (./conftest; exit) 2>/dev/null
+then
+  :
+else
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -fr conftest*
+  ac_cv_header_stdc=no
+fi
+rm -fr conftest*
+fi
+
+fi
+fi
+
+echo "$ac_t""$ac_cv_header_stdc" 1>&6
+if test $ac_cv_header_stdc = yes; then
+  cat >> confdefs.h <<\EOF
+#define STDC_HEADERS 1
+EOF
+
+fi
+
+echo $ac_n "checking for off_t""... $ac_c" 1>&6
+echo "configure:1596: checking for off_t" >&5
+if eval "test \"`echo '$''{'ac_cv_type_off_t'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  cat > conftest.$ac_ext <<EOF
+#line 1601 "configure"
+#include "confdefs.h"
+#include <sys/types.h>
+#if STDC_HEADERS
+#include <stdlib.h>
+#include <stddef.h>
+#endif
+EOF
+if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
+  egrep "(^|[^a-zA-Z_0-9])off_t[^a-zA-Z_0-9]" >/dev/null 2>&1; then
+  rm -rf conftest*
+  ac_cv_type_off_t=yes
+else
+  rm -rf conftest*
+  ac_cv_type_off_t=no
+fi
+rm -f conftest*
+
+fi
+echo "$ac_t""$ac_cv_type_off_t" 1>&6
+if test $ac_cv_type_off_t = no; then
+  cat >> confdefs.h <<\EOF
+#define off_t long
+EOF
+
+fi
+
+echo $ac_n "checking for size_t""... $ac_c" 1>&6
+echo "configure:1629: checking for size_t" >&5
+if eval "test \"`echo '$''{'ac_cv_type_size_t'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  cat > conftest.$ac_ext <<EOF
+#line 1634 "configure"
+#include "confdefs.h"
+#include <sys/types.h>
+#if STDC_HEADERS
+#include <stdlib.h>
+#include <stddef.h>
+#endif
+EOF
+if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
+  egrep "(^|[^a-zA-Z_0-9])size_t[^a-zA-Z_0-9]" >/dev/null 2>&1; then
+  rm -rf conftest*
+  ac_cv_type_size_t=yes
+else
+  rm -rf conftest*
+  ac_cv_type_size_t=no
+fi
+rm -f conftest*
+
+fi
+echo "$ac_t""$ac_cv_type_size_t" 1>&6
+if test $ac_cv_type_size_t = no; then
+  cat >> confdefs.h <<\EOF
+#define size_t unsigned
+EOF
+
+fi
+
+echo $ac_n "checking whether time.h and sys/time.h may both be included""... $ac_c" 1>&6
+echo "configure:1662: checking whether time.h and sys/time.h may both be included" >&5
+if eval "test \"`echo '$''{'ac_cv_header_time'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  cat > conftest.$ac_ext <<EOF
+#line 1667 "configure"
+#include "confdefs.h"
+#include <sys/types.h>
+#include <sys/time.h>
+#include <time.h>
+int main() {
+struct tm *tp;
+; return 0; }
+EOF
+if { (eval echo configure:1676: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
+  rm -rf conftest*
+  ac_cv_header_time=yes
+else
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -rf conftest*
+  ac_cv_header_time=no
+fi
+rm -f conftest*
+fi
+
+echo "$ac_t""$ac_cv_header_time" 1>&6
+if test $ac_cv_header_time = yes; then
+  cat >> confdefs.h <<\EOF
+#define TIME_WITH_SYS_TIME 1
+EOF
+
+fi
+
+echo $ac_n "checking whether struct tm is in sys/time.h or time.h""... $ac_c" 1>&6
+echo "configure:1697: checking whether struct tm is in sys/time.h or time.h" >&5
+if eval "test \"`echo '$''{'ac_cv_struct_tm'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  cat > conftest.$ac_ext <<EOF
+#line 1702 "configure"
+#include "confdefs.h"
+#include <sys/types.h>
+#include <time.h>
+int main() {
+struct tm *tp; tp->tm_sec;
+; return 0; }
+EOF
+if { (eval echo configure:1710: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
+  rm -rf conftest*
+  ac_cv_struct_tm=time.h
+else
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -rf conftest*
+  ac_cv_struct_tm=sys/time.h
+fi
+rm -f conftest*
+fi
+
+echo "$ac_t""$ac_cv_struct_tm" 1>&6
+if test $ac_cv_struct_tm = sys/time.h; then
+  cat >> confdefs.h <<\EOF
+#define TM_IN_SYS_TIME 1
+EOF
+
+fi
+
+
+if test "$ac_cv_prog_cc_stdc" = '-Xc'; then
+cat > conftest.$ac_ext <<EOF
+#line 1733 "configure"
+#include "confdefs.h"
+#include <stdio.h>
+
+int main() {
+ FILE *rubbish = popen("yes", "r"); 
+; return 0; }
+EOF
+if { (eval echo configure:1741: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
+  :
+else
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -rf conftest*
+  CC="`echo $CC | sed 's/-Xc/-Xa/'`"    ac_cv_prog_cc_stdc='-Xa'
+fi
+rm -f conftest*
+fi
+
+
+echo $ac_n "checking for main in -lg""... $ac_c" 1>&6
+echo "configure:1754: checking for main in -lg" >&5
+ac_lib_var=`echo g'_'main | sed 'y%./+-%__p_%'`
+if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  ac_save_LIBS="$LIBS"
+LIBS="-lg  $LIBS"
+cat > conftest.$ac_ext <<EOF
+#line 1762 "configure"
+#include "confdefs.h"
+
+int main() {
+main()
+; return 0; }
+EOF
+if { (eval echo configure:1769: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+  rm -rf conftest*
+  eval "ac_cv_lib_$ac_lib_var=yes"
+else
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -rf conftest*
+  eval "ac_cv_lib_$ac_lib_var=no"
+fi
+rm -f conftest*
+LIBS="$ac_save_LIBS"
+
+fi
+if eval "test \"`echo '$ac_cv_lib_'$ac_lib_var`\" = yes"; then
+  echo "$ac_t""yes" 1>&6
+    ac_tr_lib=HAVE_LIB`echo g | sed -e 's/[^a-zA-Z0-9_]/_/g' \
+    -e 'y/abcdefghijklmnopqrstuvwxyz/ABCDEFGHIJKLMNOPQRSTUVWXYZ/'`
+  cat >> confdefs.h <<EOF
+#define $ac_tr_lib 1
+EOF
+
+  LIBS="-lg $LIBS"
+
+else
+  echo "$ac_t""no" 1>&6
+fi
+
+echo $ac_n "checking for main in -lgdbm""... $ac_c" 1>&6
+echo "configure:1797: checking for main in -lgdbm" >&5
+ac_lib_var=`echo gdbm'_'main | sed 'y%./+-%__p_%'`
+if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  ac_save_LIBS="$LIBS"
+LIBS="-lgdbm  $LIBS"
+cat > conftest.$ac_ext <<EOF
+#line 1805 "configure"
+#include "confdefs.h"
+
+int main() {
+main()
+; return 0; }
+EOF
+if { (eval echo configure:1812: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+  rm -rf conftest*
+  eval "ac_cv_lib_$ac_lib_var=yes"
+else
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -rf conftest*
+  eval "ac_cv_lib_$ac_lib_var=no"
+fi
+rm -f conftest*
+LIBS="$ac_save_LIBS"
+
+fi
+if eval "test \"`echo '$ac_cv_lib_'$ac_lib_var`\" = yes"; then
+  echo "$ac_t""yes" 1>&6
+    ac_tr_lib=HAVE_LIB`echo gdbm | sed -e 's/[^a-zA-Z0-9_]/_/g' \
+    -e 'y/abcdefghijklmnopqrstuvwxyz/ABCDEFGHIJKLMNOPQRSTUVWXYZ/'`
+  cat >> confdefs.h <<EOF
+#define $ac_tr_lib 1
+EOF
+
+  LIBS="-lgdbm $LIBS"
+
+else
+  echo "$ac_t""no" 1>&6
+fi
+
+echo $ac_n "checking for main in -lm""... $ac_c" 1>&6
+echo "configure:1840: checking for main in -lm" >&5
+ac_lib_var=`echo m'_'main | sed 'y%./+-%__p_%'`
+if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  ac_save_LIBS="$LIBS"
+LIBS="-lm  $LIBS"
+cat > conftest.$ac_ext <<EOF
+#line 1848 "configure"
+#include "confdefs.h"
+
+int main() {
+main()
+; return 0; }
+EOF
+if { (eval echo configure:1855: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+  rm -rf conftest*
+  eval "ac_cv_lib_$ac_lib_var=yes"
+else
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -rf conftest*
+  eval "ac_cv_lib_$ac_lib_var=no"
+fi
+rm -f conftest*
+LIBS="$ac_save_LIBS"
+
+fi
+if eval "test \"`echo '$ac_cv_lib_'$ac_lib_var`\" = yes"; then
+  echo "$ac_t""yes" 1>&6
+    ac_tr_lib=HAVE_LIB`echo m | sed -e 's/[^a-zA-Z0-9_]/_/g' \
+    -e 'y/abcdefghijklmnopqrstuvwxyz/ABCDEFGHIJKLMNOPQRSTUVWXYZ/'`
+  cat >> confdefs.h <<EOF
+#define $ac_tr_lib 1
+EOF
+
+  LIBS="-lm $LIBS"
+
+else
+  echo "$ac_t""no" 1>&6
+fi
+
+echo $ac_n "checking for main in -lstdc++""... $ac_c" 1>&6
+echo "configure:1883: checking for main in -lstdc++" >&5
+ac_lib_var=`echo stdc++'_'main | sed 'y%./+-%__p_%'`
+if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  ac_save_LIBS="$LIBS"
+LIBS="-lstdc++  $LIBS"
+cat > conftest.$ac_ext <<EOF
+#line 1891 "configure"
+#include "confdefs.h"
+
+int main() {
+main()
+; return 0; }
+EOF
+if { (eval echo configure:1898: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+  rm -rf conftest*
+  eval "ac_cv_lib_$ac_lib_var=yes"
+else
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -rf conftest*
+  eval "ac_cv_lib_$ac_lib_var=no"
+fi
+rm -f conftest*
+LIBS="$ac_save_LIBS"
+
+fi
+if eval "test \"`echo '$ac_cv_lib_'$ac_lib_var`\" = yes"; then
+  echo "$ac_t""yes" 1>&6
+    ac_tr_lib=HAVE_LIB`echo stdc++ | sed -e 's/[^a-zA-Z0-9_]/_/g' \
+    -e 'y/abcdefghijklmnopqrstuvwxyz/ABCDEFGHIJKLMNOPQRSTUVWXYZ/'`
+  cat >> confdefs.h <<EOF
+#define $ac_tr_lib 1
+EOF
+
+  LIBS="-lstdc++ $LIBS"
+
+else
+  echo "$ac_t""no" 1>&6
+fi
+
+echo $ac_n "checking for main in -lcrypt""... $ac_c" 1>&6
+echo "configure:1926: checking for main in -lcrypt" >&5
+ac_lib_var=`echo crypt'_'main | sed 'y%./+-%__p_%'`
+if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  ac_save_LIBS="$LIBS"
+LIBS="-lcrypt  $LIBS"
+cat > conftest.$ac_ext <<EOF
+#line 1934 "configure"
+#include "confdefs.h"
+
+int main() {
+main()
+; return 0; }
+EOF
+if { (eval echo configure:1941: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+  rm -rf conftest*
+  eval "ac_cv_lib_$ac_lib_var=yes"
+else
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -rf conftest*
+  eval "ac_cv_lib_$ac_lib_var=no"
+fi
+rm -f conftest*
+LIBS="$ac_save_LIBS"
+
+fi
+if eval "test \"`echo '$ac_cv_lib_'$ac_lib_var`\" = yes"; then
+  echo "$ac_t""yes" 1>&6
+    ac_tr_lib=HAVE_LIB`echo crypt | sed -e 's/[^a-zA-Z0-9_]/_/g' \
+    -e 'y/abcdefghijklmnopqrstuvwxyz/ABCDEFGHIJKLMNOPQRSTUVWXYZ/'`
+  cat >> confdefs.h <<EOF
+#define $ac_tr_lib 1
+EOF
+
+  LIBS="-lcrypt $LIBS"
+
+else
+  echo "$ac_t""no" 1>&6
+fi
+
+
+
+ac_header_dirent=no
+for ac_hdr in dirent.h sys/ndir.h sys/dir.h ndir.h
+do
+ac_safe=`echo "$ac_hdr" | sed 'y%./+-%__p_%'`
+echo $ac_n "checking for $ac_hdr that defines DIR""... $ac_c" 1>&6
+echo "configure:1975: checking for $ac_hdr that defines DIR" >&5
+if eval "test \"`echo '$''{'ac_cv_header_dirent_$ac_safe'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  cat > conftest.$ac_ext <<EOF
+#line 1980 "configure"
+#include "confdefs.h"
+#include <sys/types.h>
+#include <$ac_hdr>
+int main() {
+DIR *dirp = 0;
+; return 0; }
+EOF
+if { (eval echo configure:1988: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
+  rm -rf conftest*
+  eval "ac_cv_header_dirent_$ac_safe=yes"
+else
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -rf conftest*
+  eval "ac_cv_header_dirent_$ac_safe=no"
+fi
+rm -f conftest*
+fi
+if eval "test \"`echo '$ac_cv_header_dirent_'$ac_safe`\" = yes"; then
+  echo "$ac_t""yes" 1>&6
+    ac_tr_hdr=HAVE_`echo $ac_hdr | sed 'y%abcdefghijklmnopqrstuvwxyz./-%ABCDEFGHIJKLMNOPQRSTUVWXYZ___%'`
+  cat >> confdefs.h <<EOF
+#define $ac_tr_hdr 1
+EOF
+ ac_header_dirent=$ac_hdr; break
+else
+  echo "$ac_t""no" 1>&6
+fi
+done
+# Two versions of opendir et al. are in -ldir and -lx on SCO Xenix.
+if test $ac_header_dirent = dirent.h; then
+echo $ac_n "checking for opendir in -ldir""... $ac_c" 1>&6
+echo "configure:2013: checking for opendir in -ldir" >&5
+ac_lib_var=`echo dir'_'opendir | sed 'y%./+-%__p_%'`
+if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  ac_save_LIBS="$LIBS"
+LIBS="-ldir  $LIBS"
+cat > conftest.$ac_ext <<EOF
+#line 2021 "configure"
+#include "confdefs.h"
+/* Override any gcc2 internal prototype to avoid an error.  */
+/* We use char because int might match the return type of a gcc2
+    builtin and then its argument prototype would still apply.  */
+char opendir();
+
+int main() {
+opendir()
+; return 0; }
+EOF
+if { (eval echo configure:2032: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+  rm -rf conftest*
+  eval "ac_cv_lib_$ac_lib_var=yes"
+else
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -rf conftest*
+  eval "ac_cv_lib_$ac_lib_var=no"
+fi
+rm -f conftest*
+LIBS="$ac_save_LIBS"
+
+fi
+if eval "test \"`echo '$ac_cv_lib_'$ac_lib_var`\" = yes"; then
+  echo "$ac_t""yes" 1>&6
+  LIBS="$LIBS -ldir"
+else
+  echo "$ac_t""no" 1>&6
+fi
+
+else
+echo $ac_n "checking for opendir in -lx""... $ac_c" 1>&6
+echo "configure:2054: checking for opendir in -lx" >&5
+ac_lib_var=`echo x'_'opendir | sed 'y%./+-%__p_%'`
+if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  ac_save_LIBS="$LIBS"
+LIBS="-lx  $LIBS"
+cat > conftest.$ac_ext <<EOF
+#line 2062 "configure"
+#include "confdefs.h"
+/* Override any gcc2 internal prototype to avoid an error.  */
+/* We use char because int might match the return type of a gcc2
+    builtin and then its argument prototype would still apply.  */
+char opendir();
+
+int main() {
+opendir()
+; return 0; }
+EOF
+if { (eval echo configure:2073: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+  rm -rf conftest*
+  eval "ac_cv_lib_$ac_lib_var=yes"
+else
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -rf conftest*
+  eval "ac_cv_lib_$ac_lib_var=no"
+fi
+rm -f conftest*
+LIBS="$ac_save_LIBS"
+
+fi
+if eval "test \"`echo '$ac_cv_lib_'$ac_lib_var`\" = yes"; then
+  echo "$ac_t""yes" 1>&6
+  LIBS="$LIBS -lx"
+else
+  echo "$ac_t""no" 1>&6
+fi
+
+fi
+
+echo $ac_n "checking for ANSI C header files""... $ac_c" 1>&6
+echo "configure:2096: checking for ANSI C header files" >&5
+if eval "test \"`echo '$''{'ac_cv_header_stdc'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  cat > conftest.$ac_ext <<EOF
+#line 2101 "configure"
+#include "confdefs.h"
+#include <stdlib.h>
+#include <stdarg.h>
+#include <string.h>
+#include <float.h>
+EOF
+ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out"
+{ (eval echo configure:2109: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }
+ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"`
+if test -z "$ac_err"; then
+  rm -rf conftest*
+  ac_cv_header_stdc=yes
+else
+  echo "$ac_err" >&5
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -rf conftest*
+  ac_cv_header_stdc=no
+fi
+rm -f conftest*
+
+if test $ac_cv_header_stdc = yes; then
+  # SunOS 4.x string.h does not declare mem*, contrary to ANSI.
+cat > conftest.$ac_ext <<EOF
+#line 2126 "configure"
+#include "confdefs.h"
+#include <string.h>
+EOF
+if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
+  egrep "memchr" >/dev/null 2>&1; then
+  :
+else
+  rm -rf conftest*
+  ac_cv_header_stdc=no
+fi
+rm -f conftest*
+
+fi
+
+if test $ac_cv_header_stdc = yes; then
+  # ISC 2.0.2 stdlib.h does not declare free, contrary to ANSI.
+cat > conftest.$ac_ext <<EOF
+#line 2144 "configure"
+#include "confdefs.h"
+#include <stdlib.h>
+EOF
+if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
+  egrep "free" >/dev/null 2>&1; then
+  :
+else
+  rm -rf conftest*
+  ac_cv_header_stdc=no
+fi
+rm -f conftest*
+
+fi
+
+if test $ac_cv_header_stdc = yes; then
+  # /bin/cc in Irix-4.0.5 gets non-ANSI ctype macros unless using -ansi.
+if test "$cross_compiling" = yes; then
+  :
+else
+  cat > conftest.$ac_ext <<EOF
+#line 2165 "configure"
+#include "confdefs.h"
+#include <ctype.h>
+#define ISLOWER(c) ('a' <= (c) && (c) <= 'z')
+#define TOUPPER(c) (ISLOWER(c) ? 'A' + ((c) - 'a') : (c))
+#define XOR(e, f) (((e) && !(f)) || (!(e) && (f)))
+int main () { int i; for (i = 0; i < 256; i++)
+if (XOR (islower (i), ISLOWER (i)) || toupper (i) != TOUPPER (i)) exit(2);
+exit (0); }
+
+EOF
+if { (eval echo configure:2176: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext} && (./conftest; exit) 2>/dev/null
+then
+  :
+else
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -fr conftest*
+  ac_cv_header_stdc=no
+fi
+rm -fr conftest*
+fi
+
+fi
+fi
+
+echo "$ac_t""$ac_cv_header_stdc" 1>&6
+if test $ac_cv_header_stdc = yes; then
+  cat >> confdefs.h <<\EOF
+#define STDC_HEADERS 1
+EOF
+
+fi
+
+for ac_hdr in fcntl.h limits.h sys/time.h unistd.h crypt.h string.h memory.h sys/procfs.h
+do
+ac_safe=`echo "$ac_hdr" | sed 'y%./+-%__p_%'`
+echo $ac_n "checking for $ac_hdr""... $ac_c" 1>&6
+echo "configure:2203: checking for $ac_hdr" >&5
+if eval "test \"`echo '$''{'ac_cv_header_$ac_safe'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  cat > conftest.$ac_ext <<EOF
+#line 2208 "configure"
+#include "confdefs.h"
+#include <$ac_hdr>
+EOF
+ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out"
+{ (eval echo configure:2213: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }
+ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"`
+if test -z "$ac_err"; then
+  rm -rf conftest*
+  eval "ac_cv_header_$ac_safe=yes"
+else
+  echo "$ac_err" >&5
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -rf conftest*
+  eval "ac_cv_header_$ac_safe=no"
+fi
+rm -f conftest*
+fi
+if eval "test \"`echo '$ac_cv_header_'$ac_safe`\" = yes"; then
+  echo "$ac_t""yes" 1>&6
+    ac_tr_hdr=HAVE_`echo $ac_hdr | sed 'y%abcdefghijklmnopqrstuvwxyz./-%ABCDEFGHIJKLMNOPQRSTUVWXYZ___%'`
+  cat >> confdefs.h <<EOF
+#define $ac_tr_hdr 1
+EOF
+ 
+else
+  echo "$ac_t""no" 1>&6
+fi
+done
+
+cat > conftest.$ac_ext <<EOF
+#line 2240 "configure"
+#include "confdefs.h"
+#include <stdio.h>
+EOF
+if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
+  egrep "fread" >/dev/null 2>&1; then
+  rm -rf conftest*
+  cat >> confdefs.h <<\EOF
+#define HAVE_FREAD_DECL 1
+EOF
+
+fi
+rm -f conftest*
+
+cat > conftest.$ac_ext <<EOF
+#line 2255 "configure"
+#include "confdefs.h"
+#include <stdio.h>
+EOF
+if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
+  egrep "fgetc" >/dev/null 2>&1; then
+  rm -rf conftest*
+  cat >> confdefs.h <<\EOF
+#define HAVE_FGETC_DECL 1
+EOF
+
+fi
+rm -f conftest*
+
+cat > conftest.$ac_ext <<EOF
+#line 2270 "configure"
+#include "confdefs.h"
+#include <sys/procfs.h>
+EOF
+if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
+  egrep "pr_brksize" >/dev/null 2>&1; then
+  rm -rf conftest*
+  cat >> confdefs.h <<\EOF
+#define HAVE_PR_BRKSIZE 1
+EOF
+
+fi
+rm -f conftest*
+
+
+# The Ultrix 4.2 mips builtin alloca declared by alloca.h only works
+# for constant arguments.  Useless!
+echo $ac_n "checking for working alloca.h""... $ac_c" 1>&6
+echo "configure:2288: checking for working alloca.h" >&5
+if eval "test \"`echo '$''{'ac_cv_header_alloca_h'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  cat > conftest.$ac_ext <<EOF
+#line 2293 "configure"
+#include "confdefs.h"
+#include <alloca.h>
+int main() {
+char *p = alloca(2 * sizeof(int));
+; return 0; }
+EOF
+if { (eval echo configure:2300: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+  rm -rf conftest*
+  ac_cv_header_alloca_h=yes
+else
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -rf conftest*
+  ac_cv_header_alloca_h=no
+fi
+rm -f conftest*
+fi
+
+echo "$ac_t""$ac_cv_header_alloca_h" 1>&6
+if test $ac_cv_header_alloca_h = yes; then
+  cat >> confdefs.h <<\EOF
+#define HAVE_ALLOCA_H 1
+EOF
+
+fi
+
+echo $ac_n "checking for alloca""... $ac_c" 1>&6
+echo "configure:2321: checking for alloca" >&5
+if eval "test \"`echo '$''{'ac_cv_func_alloca_works'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  cat > conftest.$ac_ext <<EOF
+#line 2326 "configure"
+#include "confdefs.h"
+
+#ifdef __GNUC__
+# define alloca __builtin_alloca
+#else
+# ifdef _MSC_VER
+#  include <malloc.h>
+#  define alloca _alloca
+# else
+#  if HAVE_ALLOCA_H
+#   include <alloca.h>
+#  else
+#   ifdef _AIX
+ #pragma alloca
+#   else
+#    ifndef alloca /* predefined by HP cc +Olibcalls */
+char *alloca ();
+#    endif
+#   endif
+#  endif
+# endif
+#endif
+
+int main() {
+char *p = (char *) alloca(1);
+; return 0; }
+EOF
+if { (eval echo configure:2354: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+  rm -rf conftest*
+  ac_cv_func_alloca_works=yes
+else
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -rf conftest*
+  ac_cv_func_alloca_works=no
+fi
+rm -f conftest*
+fi
+
+echo "$ac_t""$ac_cv_func_alloca_works" 1>&6
+if test $ac_cv_func_alloca_works = yes; then
+  cat >> confdefs.h <<\EOF
+#define HAVE_ALLOCA 1
+EOF
+
+fi
+
+if test $ac_cv_func_alloca_works = no; then
+  # The SVR3 libPW and SVR4 libucb both contain incompatible functions
+  # that cause trouble.  Some versions do not even contain alloca or
+  # contain a buggy version.  If you still want to use their alloca,
+  # use ar to extract alloca.o from them instead of compiling alloca.c.
+  ALLOCA=alloca.${ac_objext}
+  cat >> confdefs.h <<\EOF
+#define C_ALLOCA 1
+EOF
+
+
+echo $ac_n "checking whether alloca needs Cray hooks""... $ac_c" 1>&6
+echo "configure:2386: checking whether alloca needs Cray hooks" >&5
+if eval "test \"`echo '$''{'ac_cv_os_cray'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  cat > conftest.$ac_ext <<EOF
+#line 2391 "configure"
+#include "confdefs.h"
+#if defined(CRAY) && ! defined(CRAY2)
+webecray
+#else
+wenotbecray
+#endif
+
+EOF
+if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
+  egrep "webecray" >/dev/null 2>&1; then
+  rm -rf conftest*
+  ac_cv_os_cray=yes
+else
+  rm -rf conftest*
+  ac_cv_os_cray=no
+fi
+rm -f conftest*
+
+fi
+
+echo "$ac_t""$ac_cv_os_cray" 1>&6
+if test $ac_cv_os_cray = yes; then
+for ac_func in _getb67 GETB67 getb67; do
+  echo $ac_n "checking for $ac_func""... $ac_c" 1>&6
+echo "configure:2416: checking for $ac_func" >&5
+if eval "test \"`echo '$''{'ac_cv_func_$ac_func'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  cat > conftest.$ac_ext <<EOF
+#line 2421 "configure"
+#include "confdefs.h"
+/* System header to define __stub macros and hopefully few prototypes,
+    which can conflict with char $ac_func(); below.  */
+#include <assert.h>
+/* Override any gcc2 internal prototype to avoid an error.  */
+/* We use char because int might match the return type of a gcc2
+    builtin and then its argument prototype would still apply.  */
+char $ac_func();
+
+int main() {
+
+/* The GNU C library defines this for functions which it implements
+    to always fail with ENOSYS.  Some functions are actually named
+    something starting with __ and the normal name is an alias.  */
+#if defined (__stub_$ac_func) || defined (__stub___$ac_func)
+choke me
+#else
+$ac_func();
+#endif
+
+; return 0; }
+EOF
+if { (eval echo configure:2444: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+  rm -rf conftest*
+  eval "ac_cv_func_$ac_func=yes"
+else
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -rf conftest*
+  eval "ac_cv_func_$ac_func=no"
+fi
+rm -f conftest*
+fi
+
+if eval "test \"`echo '$ac_cv_func_'$ac_func`\" = yes"; then
+  echo "$ac_t""yes" 1>&6
+  cat >> confdefs.h <<EOF
+#define CRAY_STACKSEG_END $ac_func
+EOF
+
+  break
+else
+  echo "$ac_t""no" 1>&6
+fi
+
+done
+fi
+
+echo $ac_n "checking stack direction for C alloca""... $ac_c" 1>&6
+echo "configure:2471: checking stack direction for C alloca" >&5
+if eval "test \"`echo '$''{'ac_cv_c_stack_direction'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  if test "$cross_compiling" = yes; then
+  ac_cv_c_stack_direction=0
+else
+  cat > conftest.$ac_ext <<EOF
+#line 2479 "configure"
+#include "confdefs.h"
+find_stack_direction ()
+{
+  static char *addr = 0;
+  auto char dummy;
+  if (addr == 0)
+    {
+      addr = &dummy;
+      return find_stack_direction ();
+    }
+  else
+    return (&dummy > addr) ? 1 : -1;
+}
+main ()
+{
+  exit (find_stack_direction() < 0);
+}
+EOF
+if { (eval echo configure:2498: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext} && (./conftest; exit) 2>/dev/null
+then
+  ac_cv_c_stack_direction=1
+else
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -fr conftest*
+  ac_cv_c_stack_direction=-1
+fi
+rm -fr conftest*
+fi
+
+fi
+
+echo "$ac_t""$ac_cv_c_stack_direction" 1>&6
+cat >> confdefs.h <<EOF
+#define STACK_DIRECTION $ac_cv_c_stack_direction
+EOF
+
+fi
+
+if test $ac_cv_prog_gcc = yes; then
+    echo $ac_n "checking whether ${CC-cc} needs -traditional""... $ac_c" 1>&6
+echo "configure:2521: checking whether ${CC-cc} needs -traditional" >&5
+if eval "test \"`echo '$''{'ac_cv_prog_gcc_traditional'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+    ac_pattern="Autoconf.*'x'"
+  cat > conftest.$ac_ext <<EOF
+#line 2527 "configure"
+#include "confdefs.h"
+#include <sgtty.h>
+Autoconf TIOCGETP
+EOF
+if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
+  egrep "$ac_pattern" >/dev/null 2>&1; then
+  rm -rf conftest*
+  ac_cv_prog_gcc_traditional=yes
+else
+  rm -rf conftest*
+  ac_cv_prog_gcc_traditional=no
+fi
+rm -f conftest*
+
+
+  if test $ac_cv_prog_gcc_traditional = no; then
+    cat > conftest.$ac_ext <<EOF
+#line 2545 "configure"
+#include "confdefs.h"
+#include <termio.h>
+Autoconf TCGETA
+EOF
+if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
+  egrep "$ac_pattern" >/dev/null 2>&1; then
+  rm -rf conftest*
+  ac_cv_prog_gcc_traditional=yes
+fi
+rm -f conftest*
+
+  fi
+fi
+
+echo "$ac_t""$ac_cv_prog_gcc_traditional" 1>&6
+  if test $ac_cv_prog_gcc_traditional = yes; then
+    CC="$CC -traditional"
+  fi
+fi
+
+echo $ac_n "checking return type of signal handlers""... $ac_c" 1>&6
+echo "configure:2567: checking return type of signal handlers" >&5
+if eval "test \"`echo '$''{'ac_cv_type_signal'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  cat > conftest.$ac_ext <<EOF
+#line 2572 "configure"
+#include "confdefs.h"
+#include <sys/types.h>
+#include <signal.h>
+#ifdef signal
+#undef signal
+#endif
+#ifdef __cplusplus
+extern "C" void (*signal (int, void (*)(int)))(int);
+#else
+void (*signal ()) ();
+#endif
+
+int main() {
+int i;
+; return 0; }
+EOF
+if { (eval echo configure:2589: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
+  rm -rf conftest*
+  ac_cv_type_signal=void
+else
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -rf conftest*
+  ac_cv_type_signal=int
+fi
+rm -f conftest*
+fi
+
+echo "$ac_t""$ac_cv_type_signal" 1>&6
+cat >> confdefs.h <<EOF
+#define RETSIGTYPE $ac_cv_type_signal
+EOF
+
+
+echo $ac_n "checking for vprintf""... $ac_c" 1>&6
+echo "configure:2608: checking for vprintf" >&5
+if eval "test \"`echo '$''{'ac_cv_func_vprintf'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  cat > conftest.$ac_ext <<EOF
+#line 2613 "configure"
+#include "confdefs.h"
+/* System header to define __stub macros and hopefully few prototypes,
+    which can conflict with char vprintf(); below.  */
+#include <assert.h>
+/* Override any gcc2 internal prototype to avoid an error.  */
+/* We use char because int might match the return type of a gcc2
+    builtin and then its argument prototype would still apply.  */
+char vprintf();
+
+int main() {
+
+/* The GNU C library defines this for functions which it implements
+    to always fail with ENOSYS.  Some functions are actually named
+    something starting with __ and the normal name is an alias.  */
+#if defined (__stub_vprintf) || defined (__stub___vprintf)
+choke me
+#else
+vprintf();
+#endif
+
+; return 0; }
+EOF
+if { (eval echo configure:2636: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+  rm -rf conftest*
+  eval "ac_cv_func_vprintf=yes"
+else
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -rf conftest*
+  eval "ac_cv_func_vprintf=no"
+fi
+rm -f conftest*
+fi
+
+if eval "test \"`echo '$ac_cv_func_'vprintf`\" = yes"; then
+  echo "$ac_t""yes" 1>&6
+  cat >> confdefs.h <<\EOF
+#define HAVE_VPRINTF 1
+EOF
+
+else
+  echo "$ac_t""no" 1>&6
+fi
+
+if test "$ac_cv_func_vprintf" != yes; then
+echo $ac_n "checking for _doprnt""... $ac_c" 1>&6
+echo "configure:2660: checking for _doprnt" >&5
+if eval "test \"`echo '$''{'ac_cv_func__doprnt'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  cat > conftest.$ac_ext <<EOF
+#line 2665 "configure"
+#include "confdefs.h"
+/* System header to define __stub macros and hopefully few prototypes,
+    which can conflict with char _doprnt(); below.  */
+#include <assert.h>
+/* Override any gcc2 internal prototype to avoid an error.  */
+/* We use char because int might match the return type of a gcc2
+    builtin and then its argument prototype would still apply.  */
+char _doprnt();
+
+int main() {
+
+/* The GNU C library defines this for functions which it implements
+    to always fail with ENOSYS.  Some functions are actually named
+    something starting with __ and the normal name is an alias.  */
+#if defined (__stub__doprnt) || defined (__stub____doprnt)
+choke me
+#else
+_doprnt();
+#endif
+
+; return 0; }
+EOF
+if { (eval echo configure:2688: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+  rm -rf conftest*
+  eval "ac_cv_func__doprnt=yes"
+else
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -rf conftest*
+  eval "ac_cv_func__doprnt=no"
+fi
+rm -f conftest*
+fi
+
+if eval "test \"`echo '$ac_cv_func_'_doprnt`\" = yes"; then
+  echo "$ac_t""yes" 1>&6
+  cat >> confdefs.h <<\EOF
+#define HAVE_DOPRNT 1
+EOF
+
+else
+  echo "$ac_t""no" 1>&6
+fi
+
+fi
+
+for ac_func in ftime select strftime strtol getrusage times mallinfo setbuffer getpagesize strerror
+do
+echo $ac_n "checking for $ac_func""... $ac_c" 1>&6
+echo "configure:2715: checking for $ac_func" >&5
+if eval "test \"`echo '$''{'ac_cv_func_$ac_func'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  cat > conftest.$ac_ext <<EOF
+#line 2720 "configure"
+#include "confdefs.h"
+/* System header to define __stub macros and hopefully few prototypes,
+    which can conflict with char $ac_func(); below.  */
+#include <assert.h>
+/* Override any gcc2 internal prototype to avoid an error.  */
+/* We use char because int might match the return type of a gcc2
+    builtin and then its argument prototype would still apply.  */
+char $ac_func();
+
+int main() {
+
+/* The GNU C library defines this for functions which it implements
+    to always fail with ENOSYS.  Some functions are actually named
+    something starting with __ and the normal name is an alias.  */
+#if defined (__stub_$ac_func) || defined (__stub___$ac_func)
+choke me
+#else
+$ac_func();
+#endif
+
+; return 0; }
+EOF
+if { (eval echo configure:2743: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+  rm -rf conftest*
+  eval "ac_cv_func_$ac_func=yes"
+else
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -rf conftest*
+  eval "ac_cv_func_$ac_func=no"
+fi
+rm -f conftest*
+fi
+
+if eval "test \"`echo '$ac_cv_func_'$ac_func`\" = yes"; then
+  echo "$ac_t""yes" 1>&6
+    ac_tr_func=HAVE_`echo $ac_func | tr 'abcdefghijklmnopqrstuvwxyz' 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'`
+  cat >> confdefs.h <<EOF
+#define $ac_tr_func 1
+EOF
+ 
+else
+  echo "$ac_t""no" 1>&6
+fi
+done
+
+for ac_func in ftruncate strstr strcasecmp
+do
+echo $ac_n "checking for $ac_func""... $ac_c" 1>&6
+echo "configure:2770: checking for $ac_func" >&5
+if eval "test \"`echo '$''{'ac_cv_func_$ac_func'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  cat > conftest.$ac_ext <<EOF
+#line 2775 "configure"
+#include "confdefs.h"
+/* System header to define __stub macros and hopefully few prototypes,
+    which can conflict with char $ac_func(); below.  */
+#include <assert.h>
+/* Override any gcc2 internal prototype to avoid an error.  */
+/* We use char because int might match the return type of a gcc2
+    builtin and then its argument prototype would still apply.  */
+char $ac_func();
+
+int main() {
+
+/* The GNU C library defines this for functions which it implements
+    to always fail with ENOSYS.  Some functions are actually named
+    something starting with __ and the normal name is an alias.  */
+#if defined (__stub_$ac_func) || defined (__stub___$ac_func)
+choke me
+#else
+$ac_func();
+#endif
+
+; return 0; }
+EOF
+if { (eval echo configure:2798: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+  rm -rf conftest*
+  eval "ac_cv_func_$ac_func=yes"
+else
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -rf conftest*
+  eval "ac_cv_func_$ac_func=no"
+fi
+rm -f conftest*
+fi
+
+if eval "test \"`echo '$ac_cv_func_'$ac_func`\" = yes"; then
+  echo "$ac_t""yes" 1>&6
+    ac_tr_func=HAVE_`echo $ac_func | tr 'abcdefghijklmnopqrstuvwxyz' 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'`
+  cat >> confdefs.h <<EOF
+#define $ac_tr_func 1
+EOF
+ 
+else
+  echo "$ac_t""no" 1>&6
+LIBOBJS="$LIBOBJS ${ac_func}.${ac_objext}"
+fi
+done
+
+
+
+
+# *** Custom checking (based on GNU tar configure.in) ***
+# ---------------------------------------------------------------------------
+echo $ac_n "checking for HP-UX needing gmalloc""... $ac_c" 1>&6
+echo "configure:2829: checking for HP-UX needing gmalloc" >&5
+if test "`(uname -s) 2> /dev/null`" = 'HP-UX'; then
+  echo "$ac_t""yes" 1>&6
+  LIBOBJS="$LIBOBJS gmalloc.o"
+  cat >> confdefs.h <<\EOF
+#define HAVE_VALLOC 1
+EOF
+
+else
+  echo "$ac_t""no" 1>&6
+  for ac_func in valloc
+do
+echo $ac_n "checking for $ac_func""... $ac_c" 1>&6
+echo "configure:2842: checking for $ac_func" >&5
+if eval "test \"`echo '$''{'ac_cv_func_$ac_func'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  cat > conftest.$ac_ext <<EOF
+#line 2847 "configure"
+#include "confdefs.h"
+/* System header to define __stub macros and hopefully few prototypes,
+    which can conflict with char $ac_func(); below.  */
+#include <assert.h>
+/* Override any gcc2 internal prototype to avoid an error.  */
+/* We use char because int might match the return type of a gcc2
+    builtin and then its argument prototype would still apply.  */
+char $ac_func();
+
+int main() {
+
+/* The GNU C library defines this for functions which it implements
+    to always fail with ENOSYS.  Some functions are actually named
+    something starting with __ and the normal name is an alias.  */
+#if defined (__stub_$ac_func) || defined (__stub___$ac_func)
+choke me
+#else
+$ac_func();
+#endif
+
+; return 0; }
+EOF
+if { (eval echo configure:2870: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+  rm -rf conftest*
+  eval "ac_cv_func_$ac_func=yes"
+else
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -rf conftest*
+  eval "ac_cv_func_$ac_func=no"
+fi
+rm -f conftest*
+fi
+
+if eval "test \"`echo '$ac_cv_func_'$ac_func`\" = yes"; then
+  echo "$ac_t""yes" 1>&6
+    ac_tr_func=HAVE_`echo $ac_func | tr 'abcdefghijklmnopqrstuvwxyz' 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'`
+  cat >> confdefs.h <<EOF
+#define $ac_tr_func 1
+EOF
+ 
+else
+  echo "$ac_t""no" 1>&6
+fi
+done
+
+fi
+
+echo $ac_n "checking if malloc debugging is wanted""... $ac_c" 1>&6
+echo "configure:2897: checking if malloc debugging is wanted" >&5
+# Check whether --with-dmalloc or --without-dmalloc was given.
+if test "${with_dmalloc+set}" = set; then
+  withval="$with_dmalloc"
+  if test "$withval" = yes; then
+  echo "$ac_t""yes" 1>&6
+  cat >> confdefs.h <<\EOF
+#define WITH_DMALLOC 1
+EOF
+
+  LIBS="$LIBS -ldmalloc"
+  LDFLAGS="$LDFLAGS -g"
+else
+  echo "$ac_t""no" 1>&6
+fi
+else
+  echo "$ac_t""no" 1>&6
+fi
+
+
+echo $ac_n "checking which of rx or regex is wanted""... $ac_c" 1>&6
+echo "configure:2918: checking which of rx or regex is wanted" >&5
+# Check whether --with-regex or --without-regex was given.
+if test "${with_regex+set}" = set; then
+  withval="$with_regex"
+  if test "$withval" = yes; then
+  ac_with_regex=1
+  echo "$ac_t""regex" 1>&6
+  cat >> confdefs.h <<\EOF
+#define WITH_REGEX 1
+EOF
+
+  LIBOBJS="$LIBOBJS regex.o"
+fi
+fi
+
+if test -z "$ac_with_regex"; then
+  echo "$ac_t""rx" 1>&6
+  echo $ac_n "checking for re_rx_search""... $ac_c" 1>&6
+echo "configure:2936: checking for re_rx_search" >&5
+if eval "test \"`echo '$''{'ac_cv_func_re_rx_search'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  cat > conftest.$ac_ext <<EOF
+#line 2941 "configure"
+#include "confdefs.h"
+/* System header to define __stub macros and hopefully few prototypes,
+    which can conflict with char re_rx_search(); below.  */
+#include <assert.h>
+/* Override any gcc2 internal prototype to avoid an error.  */
+/* We use char because int might match the return type of a gcc2
+    builtin and then its argument prototype would still apply.  */
+char re_rx_search();
+
+int main() {
+
+/* The GNU C library defines this for functions which it implements
+    to always fail with ENOSYS.  Some functions are actually named
+    something starting with __ and the normal name is an alias.  */
+#if defined (__stub_re_rx_search) || defined (__stub___re_rx_search)
+choke me
+#else
+re_rx_search();
+#endif
+
+; return 0; }
+EOF
+if { (eval echo configure:2964: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+  rm -rf conftest*
+  eval "ac_cv_func_re_rx_search=yes"
+else
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -rf conftest*
+  eval "ac_cv_func_re_rx_search=no"
+fi
+rm -f conftest*
+fi
+
+if eval "test \"`echo '$ac_cv_func_'re_rx_search`\" = yes"; then
+  echo "$ac_t""yes" 1>&6
+  :
+else
+  echo "$ac_t""no" 1>&6
+LIBOBJS="$LIBOBJS rx.o"
+fi
+
+fi
+
+
+# ---------------------------------------------------------------------------
+if test "$ac_cv_func_alloca" = 'no'; then
+  LIBOBJS="$LIBOBJS xmalloc.o error.o"
+fi
+
+
+# ---------------------------------------------------------------------------
+
+ac_ext=C
+# CXXFLAGS is not in ac_cpp because -g, -O, etc. are not valid cpp options.
+ac_cpp='$CXXCPP $CPPFLAGS'
+ac_compile='${CXX-g++} -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext 1>&5'
+ac_link='${CXX-g++} -o conftest${ac_exeext} $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS 1>&5'
+cross_compiling=$ac_cv_prog_cxx_cross
+
+
+echo $ac_n "checking "that the GDBM library is available"""... $ac_c" 1>&6
+echo "configure:3004: checking "that the GDBM library is available"" >&5
+cat > conftest.$ac_ext <<EOF
+#line 3006 "configure"
+#include "confdefs.h"
+#include <gdbm.h>
+
+int main() {
+
+; return 0; }
+EOF
+if { (eval echo configure:3014: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
+  rm -rf conftest*
+  success=yes
+else
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -rf conftest*
+  success=no
+
+fi
+rm -f conftest*
+echo "$ac_t""$success" 1>&6
+if test $success = "no"; then
+{ echo "configure: error: "GDBM Library not available - cannot install"" 1>&2; exit 1; }
+fi
+
+echo $ac_n "checking "that Perl 5 is available"""... $ac_c" 1>&6
+echo "configure:3031: checking "that Perl 5 is available"" >&5
+success="no"
+pl_path="$PATH"
+IFS="${IFS=   }"; pl_save_ifs="$IFS"; IFS=":"
+for pl_dir in $pl_path; do
+  test -z "$pl_dir" && pl_dir=.
+  if test -x $pl_dir/perl; then
+    success="yes"
+    break
+  fi
+done
+IFS="$pl_save_ifs"
+
+if test $success = "yes"; then
+try=`perl configtest.pl` || try="0"
+try=`expr $try \> 5.000`
+if test $try = "1"; then
+echo "$ac_t"""yes"" 1>&6
+else
+success="no"
+fi
+fi
+
+if test $success = "no"; then
+echo "$ac_t"""no"" 1>&6
+{ echo "configure: error: "Perl 5 not available - cannot install"" 1>&2; exit 1; }
+fi
+
+success=no
+echo $ac_n "checking "whether STL library has known faults"""... $ac_c" 1>&6
+echo "configure:3061: checking "whether STL library has known faults"" >&5
+
+cat > conftest.$ac_ext <<EOF
+#line 3064 "configure"
+#include "confdefs.h"
+#include <vector>
+
+int main() {
+
+; return 0; }
+EOF
+if { (eval echo configure:3072: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
+  rm -rf conftest*
+  success=yes
+else
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+fi
+rm -f conftest*
+
+if test $success = "no"; then
+cat > conftest.$ac_ext <<EOF
+#line 3083 "configure"
+#include "confdefs.h"
+#include <vector.h>
+
+int main() {
+
+; return 0; }
+EOF
+if { (eval echo configure:3091: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
+  rm -rf conftest*
+  success="yes"
+else
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+fi
+rm -f conftest*
+fi
+
+if test $success = "no"; then
+cat > conftest.$ac_ext <<EOF
+#line 3103 "configure"
+#include "confdefs.h"
+#include <ospace\\std\\vector>
+
+int main() {
+
+; return 0; }
+EOF
+if { (eval echo configure:3111: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
+  rm -rf conftest*
+  success="yes"
+else
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+fi
+rm -f conftest*
+fi
+
+if test $success = yes; then
+echo "$ac_t"""no"" 1>&6
+else
+echo "$ac_t"""yes"" 1>&6
+{ echo "configure: error: "STL Broken - Obtain newer version of GNU C Compiler"" 1>&2; exit 1; }
+fi
+
+gsdlos=`uname | tr A-Z a-z`
+
+
+echo $ac_n "checking for HP-UX needing gmalloc""... $ac_c" 1>&6
+echo "configure:3132: checking for HP-UX needing gmalloc" >&5
+if test "`(uname -s) 2> /dev/null`" = 'HP-UX'; then
+  echo "$ac_t""yes" 1>&6
+  LIBOBJS="$LIBOBJS gmalloc.o"
+  cat >> confdefs.h <<\EOF
+#define HAVE_VALLOC 1
+EOF
+
+else
+  echo "$ac_t""no" 1>&6
+  for ac_func in valloc
+do
+echo $ac_n "checking for $ac_func""... $ac_c" 1>&6
+echo "configure:3145: checking for $ac_func" >&5
+if eval "test \"`echo '$''{'ac_cv_func_$ac_func'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  cat > conftest.$ac_ext <<EOF
+#line 3150 "configure"
+#include "confdefs.h"
+/* System header to define __stub macros and hopefully few prototypes,
+    which can conflict with char $ac_func(); below.  */
+#include <assert.h>
+/* Override any gcc2 internal prototype to avoid an error.  */
+#ifdef __cplusplus
+extern "C"
+#endif
+/* We use char because int might match the return type of a gcc2
+    builtin and then its argument prototype would still apply.  */
+char $ac_func();
+
+int main() {
+
+/* The GNU C library defines this for functions which it implements
+    to always fail with ENOSYS.  Some functions are actually named
+    something starting with __ and the normal name is an alias.  */
+#if defined (__stub_$ac_func) || defined (__stub___$ac_func)
+choke me
+#else
+$ac_func();
+#endif
+
+; return 0; }
+EOF
+if { (eval echo configure:3176: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+  rm -rf conftest*
+  eval "ac_cv_func_$ac_func=yes"
+else
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -rf conftest*
+  eval "ac_cv_func_$ac_func=no"
+fi
+rm -f conftest*
+fi
+
+if eval "test \"`echo '$ac_cv_func_'$ac_func`\" = yes"; then
+  echo "$ac_t""yes" 1>&6
+    ac_tr_func=HAVE_`echo $ac_func | tr 'abcdefghijklmnopqrstuvwxyz' 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'`
+  cat >> confdefs.h <<EOF
+#define $ac_tr_func 1
+EOF
+ 
+else
+  echo "$ac_t""no" 1>&6
+fi
+done
+
+fi
+
+echo $ac_n "checking if malloc debugging is wanted""... $ac_c" 1>&6
+echo "configure:3203: checking if malloc debugging is wanted" >&5
+# Check whether --with-dmalloc or --without-dmalloc was given.
+if test "${with_dmalloc+set}" = set; then
+  withval="$with_dmalloc"
+  if test "$withval" = yes; then
+  echo "$ac_t""yes" 1>&6
+  cat >> confdefs.h <<\EOF
+#define WITH_DMALLOC 1
+EOF
+
+  LIBS="$LIBS -ldmalloc"
+  LDFLAGS="$LDFLAGS -g"
+else
+  echo "$ac_t""no" 1>&6
+fi
+else
+  echo "$ac_t""no" 1>&6
+fi
+
+
+echo $ac_n "checking which of rx or regex is wanted""... $ac_c" 1>&6
+echo "configure:3224: checking which of rx or regex is wanted" >&5
+# Check whether --with-regex or --without-regex was given.
+if test "${with_regex+set}" = set; then
+  withval="$with_regex"
+  if test "$withval" = yes; then
+  ac_with_regex=1
+  echo "$ac_t""regex" 1>&6
+  cat >> confdefs.h <<\EOF
+#define WITH_REGEX 1
+EOF
+
+  LIBOBJS="$LIBOBJS regex.o"
+fi
+fi
+
+if test -z "$ac_with_regex"; then
+  echo "$ac_t""rx" 1>&6
+  echo $ac_n "checking for re_rx_search""... $ac_c" 1>&6
+echo "configure:3242: checking for re_rx_search" >&5
+if eval "test \"`echo '$''{'ac_cv_func_re_rx_search'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  cat > conftest.$ac_ext <<EOF
+#line 3247 "configure"
+#include "confdefs.h"
+/* System header to define __stub macros and hopefully few prototypes,
+    which can conflict with char re_rx_search(); below.  */
+#include <assert.h>
+/* Override any gcc2 internal prototype to avoid an error.  */
+#ifdef __cplusplus
+extern "C"
+#endif
+/* We use char because int might match the return type of a gcc2
+    builtin and then its argument prototype would still apply.  */
+char re_rx_search();
+
+int main() {
+
+/* The GNU C library defines this for functions which it implements
+    to always fail with ENOSYS.  Some functions are actually named
+    something starting with __ and the normal name is an alias.  */
+#if defined (__stub_re_rx_search) || defined (__stub___re_rx_search)
+choke me
+#else
+re_rx_search();
+#endif
+
+; return 0; }
+EOF
+if { (eval echo configure:3273: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+  rm -rf conftest*
+  eval "ac_cv_func_re_rx_search=yes"
+else
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -rf conftest*
+  eval "ac_cv_func_re_rx_search=no"
+fi
+rm -f conftest*
+fi
+
+if eval "test \"`echo '$ac_cv_func_'re_rx_search`\" = yes"; then
+  echo "$ac_t""yes" 1>&6
+  :
+else
+  echo "$ac_t""no" 1>&6
+LIBOBJS="$LIBOBJS rx.o"
+fi
+
+fi
+
+
+# ---------------------------------------------------------------------------
+if test "$ac_cv_func_alloca" = 'no'; then
+  LIBOBJS="$LIBOBJS xmalloc.o error.o"
+fi
+
+
+# ---------------------------------------------------------------------------
+
+trap '' 1 2 15
+cat > confcache <<\EOF
+# This file is a shell script that caches the results of configure
+# tests run on this system so they can be shared between configure
+# scripts and configure runs.  It is not useful on other systems.
+# If it contains results you don't want to keep, you may remove or edit it.
+#
+# By default, configure uses ./config.cache as the cache file,
+# creating it if it does not exist already.  You can give configure
+# the --cache-file=FILE option to use a different cache file; that is
+# what configure does when it calls configure scripts in
+# subdirectories, so they share the cache.
+# Giving --cache-file=/dev/null disables caching, for debugging configure.
+# config.status only pays attention to the cache file if you give it the
+# --recheck option to rerun configure.
+#
+EOF
+# The following way of writing the cache mishandles newlines in values,
+# but we know of no workaround that is simple, portable, and efficient.
+# So, don't put newlines in cache variables' values.
+# Ultrix sh set writes to stderr and can't be redirected directly,
+# and sets the high bit in the cache file unless we assign to the vars.
+(set) 2>&1 |
+  case `(ac_space=' '; set | grep ac_space) 2>&1` in
+  *ac_space=\ *)
+    # `set' does not quote correctly, so add quotes (double-quote substitution
+    # turns \\\\ into \\, and sed turns \\ into \).
+    sed -n \
+      -e "s/'/'\\\\''/g" \
+      -e "s/^\\([a-zA-Z0-9_]*_cv_[a-zA-Z0-9_]*\\)=\\(.*\\)/\\1=\${\\1='\\2'}/p"
+    ;;
+  *)
+    # `set' quotes correctly as required by POSIX, so do not add quotes.
+    sed -n -e 's/^\([a-zA-Z0-9_]*_cv_[a-zA-Z0-9_]*\)=\(.*\)/\1=${\1=\2}/p'
+    ;;
+  esac >> confcache
+if cmp -s $cache_file confcache; then
+  :
+else
+  if test -w $cache_file; then
+    echo "updating cache $cache_file"
+    cat confcache > $cache_file
+  else
+    echo "not updating unwritable cache $cache_file"
+  fi
+fi
+rm -f confcache
+
+trap 'rm -fr conftest* confdefs* core core.* *.core $ac_clean_files; exit 1' 1 2 15
+
+test "x$prefix" = xNONE && prefix=$ac_default_prefix
+# Let make expand exec_prefix.
+test "x$exec_prefix" = xNONE && exec_prefix='${prefix}'
+
+# Any assignment to VPATH causes Sun make to only execute
+# the first set of double-colon rules, so remove it if not needed.
+# If there is a colon in the path, we need to keep it.
+if test "x$srcdir" = x.; then
+  ac_vpsub='/^[ 	]*VPATH[ 	]*=[^:]*$/d'
+fi
+
+trap 'rm -f $CONFIG_STATUS conftest*; exit 1' 1 2 15
+
+DEFS=-DHAVE_CONFIG_H
+
+# Without the "./", some shells look in PATH for config.status.
+: ${CONFIG_STATUS=./config.status}
+
+echo creating $CONFIG_STATUS
+rm -f $CONFIG_STATUS
+cat > $CONFIG_STATUS <<EOF
+#! /bin/sh
+# Generated automatically by configure.
+# Run this file to recreate the current configuration.
+# This directory was configured as follows,
+# on host `(hostname || uname -n) 2>/dev/null | sed 1q`:
+#
+# $0 $ac_configure_args
+#
+# Compiler output produced by configure, useful for debugging
+# configure, is in ./config.log if it exists.
+
+ac_cs_usage="Usage: $CONFIG_STATUS [--recheck] [--version] [--help]"
+for ac_option
+do
+  case "\$ac_option" in
+  -recheck | --recheck | --rechec | --reche | --rech | --rec | --re | --r)
+    echo "running \${CONFIG_SHELL-/bin/sh} $0 $ac_configure_args --no-create --no-recursion"
+    exec \${CONFIG_SHELL-/bin/sh} $0 $ac_configure_args --no-create --no-recursion ;;
+  -version | --version | --versio | --versi | --vers | --ver | --ve | --v)
+    echo "$CONFIG_STATUS generated by autoconf version 2.13"
+    exit 0 ;;
+  -help | --help | --hel | --he | --h)
+    echo "\$ac_cs_usage"; exit 0 ;;
+  *) echo "\$ac_cs_usage"; exit 1 ;;
+  esac
+done
+
+ac_given_srcdir=$srcdir
+ac_given_INSTALL="$INSTALL"
+
+trap 'rm -fr `echo "src/recpt/Makefile Makefile config.h" | sed "s/:[^ ]*//g"` conftest*; exit 1' 1 2 15
+EOF
+cat >> $CONFIG_STATUS <<EOF
+
+# Protect against being on the right side of a sed subst in config.status.
+sed 's/%@/@@/; s/@%/@@/; s/%g\$/@g/; /@g\$/s/[\\\\&%]/\\\\&/g;
+ s/@@/%@/; s/@@/@%/; s/@g\$/%g/' > conftest.subs <<\\CEOF
+$ac_vpsub
+$extrasub
+s%@SHELL@%$SHELL%g
+s%@CFLAGS@%$CFLAGS%g
+s%@CPPFLAGS@%$CPPFLAGS%g
+s%@CXXFLAGS@%$CXXFLAGS%g
+s%@FFLAGS@%$FFLAGS%g
+s%@DEFS@%$DEFS%g
+s%@LDFLAGS@%$LDFLAGS%g
+s%@LIBS@%$LIBS%g
+s%@exec_prefix@%$exec_prefix%g
+s%@prefix@%$prefix%g
+s%@program_transform_name@%$program_transform_name%g
+s%@bindir@%$bindir%g
+s%@sbindir@%$sbindir%g
+s%@libexecdir@%$libexecdir%g
+s%@datadir@%$datadir%g
+s%@sysconfdir@%$sysconfdir%g
+s%@sharedstatedir@%$sharedstatedir%g
+s%@localstatedir@%$localstatedir%g
+s%@libdir@%$libdir%g
+s%@includedir@%$includedir%g
+s%@oldincludedir@%$oldincludedir%g
+s%@infodir@%$infodir%g
+s%@mandir@%$mandir%g
+s%@PACKAGE@%$PACKAGE%g
+s%@VERSION@%$VERSION%g
+s%@USE_FASTCGI@%$USE_FASTCGI%g
+s%@CC@%$CC%g
+s%@CXX@%$CXX%g
+s%@AWK@%$AWK%g
+s%@YACC@%$YACC%g
+s%@INSTALL_PROGRAM@%$INSTALL_PROGRAM%g
+s%@INSTALL_SCRIPT@%$INSTALL_SCRIPT%g
+s%@INSTALL_DATA@%$INSTALL_DATA%g
+s%@LN_S@%$LN_S%g
+s%@SET_MAKE@%$SET_MAKE%g
+s%@RANLIB@%$RANLIB%g
+s%@CPP@%$CPP%g
+s%@U@%$U%g
+s%@ANSI2KNR@%$ANSI2KNR%g
+s%@ALLOCA@%$ALLOCA%g
+s%@LIBOBJS@%$LIBOBJS%g
+s%@gsdlos@%$gsdlos%g
+
+CEOF
+EOF
+
+cat >> $CONFIG_STATUS <<\EOF
+
+# Split the substitutions into bite-sized pieces for seds with
+# small command number limits, like on Digital OSF/1 and HP-UX.
+ac_max_sed_cmds=90 # Maximum number of lines to put in a sed script.
+ac_file=1 # Number of current file.
+ac_beg=1 # First line for current file.
+ac_end=$ac_max_sed_cmds # Line after last line for current file.
+ac_more_lines=:
+ac_sed_cmds=""
+while $ac_more_lines; do
+  if test $ac_beg -gt 1; then
+    sed "1,${ac_beg}d; ${ac_end}q" conftest.subs > conftest.s$ac_file
+  else
+    sed "${ac_end}q" conftest.subs > conftest.s$ac_file
+  fi
+  if test ! -s conftest.s$ac_file; then
+    ac_more_lines=false
+    rm -f conftest.s$ac_file
+  else
+    if test -z "$ac_sed_cmds"; then
+      ac_sed_cmds="sed -f conftest.s$ac_file"
+    else
+      ac_sed_cmds="$ac_sed_cmds | sed -f conftest.s$ac_file"
+    fi
+    ac_file=`expr $ac_file + 1`
+    ac_beg=$ac_end
+    ac_end=`expr $ac_end + $ac_max_sed_cmds`
+  fi
+done
+if test -z "$ac_sed_cmds"; then
+  ac_sed_cmds=cat
+fi
+EOF
+
+cat >> $CONFIG_STATUS <<EOF
+
+CONFIG_FILES=\${CONFIG_FILES-"src/recpt/Makefile Makefile"}
+EOF
+cat >> $CONFIG_STATUS <<\EOF
+for ac_file in .. $CONFIG_FILES; do if test "x$ac_file" != x..; then
+  # Support "outfile[:infile[:infile...]]", defaulting infile="outfile.in".
+  case "$ac_file" in
+  *:*) ac_file_in=`echo "$ac_file"|sed 's%[^:]*:%%'`
+       ac_file=`echo "$ac_file"|sed 's%:.*%%'` ;;
+  *) ac_file_in="${ac_file}.in" ;;
+  esac
+
+  # Adjust a relative srcdir, top_srcdir, and INSTALL for subdirectories.
+
+  # Remove last slash and all that follows it.  Not all systems have dirname.
+  ac_dir=`echo $ac_file|sed 's%/[^/][^/]*$%%'`
+  if test "$ac_dir" != "$ac_file" && test "$ac_dir" != .; then
+    # The file is in a subdirectory.
+    test ! -d "$ac_dir" && mkdir "$ac_dir"
+    ac_dir_suffix="/`echo $ac_dir|sed 's%^\./%%'`"
+    # A "../" for each directory in $ac_dir_suffix.
+    ac_dots=`echo $ac_dir_suffix|sed 's%/[^/]*%../%g'`
+  else
+    ac_dir_suffix= ac_dots=
+  fi
+
+  case "$ac_given_srcdir" in
+  .)  srcdir=.
+      if test -z "$ac_dots"; then top_srcdir=.
+      else top_srcdir=`echo $ac_dots|sed 's%/$%%'`; fi ;;
+  /*) srcdir="$ac_given_srcdir$ac_dir_suffix"; top_srcdir="$ac_given_srcdir" ;;
+  *) # Relative path.
+    srcdir="$ac_dots$ac_given_srcdir$ac_dir_suffix"
+    top_srcdir="$ac_dots$ac_given_srcdir" ;;
+  esac
+
+  case "$ac_given_INSTALL" in
+  [/$]*) INSTALL="$ac_given_INSTALL" ;;
+  *) INSTALL="$ac_dots$ac_given_INSTALL" ;;
+  esac
+
+  echo creating "$ac_file"
+  rm -f "$ac_file"
+  configure_input="Generated automatically from `echo $ac_file_in|sed 's%.*/%%'` by configure."
+  case "$ac_file" in
+  *Makefile*) ac_comsub="1i\\
+# $configure_input" ;;
+  *) ac_comsub= ;;
+  esac
+
+  ac_file_inputs=`echo $ac_file_in|sed -e "s%^%$ac_given_srcdir/%" -e "s%:% $ac_given_srcdir/%g"`
+  sed -e "$ac_comsub
+s%@configure_input@%$configure_input%g
+s%@srcdir@%$srcdir%g
+s%@top_srcdir@%$top_srcdir%g
+s%@INSTALL@%$INSTALL%g
+" $ac_file_inputs | (eval "$ac_sed_cmds") > $ac_file
+fi; done
+rm -f conftest.s*
+
+# These sed commands are passed to sed as "A NAME B NAME C VALUE D", where
+# NAME is the cpp macro being defined and VALUE is the value it is being given.
+#
+# ac_d sets the value in "#define NAME VALUE" lines.
+ac_dA='s%^\([ 	]*\)#\([ 	]*define[ 	][ 	]*\)'
+ac_dB='\([ 	][ 	]*\)[^ 	]*%\1#\2'
+ac_dC='\3'
+ac_dD='%g'
+# ac_u turns "#undef NAME" with trailing blanks into "#define NAME VALUE".
+ac_uA='s%^\([ 	]*\)#\([ 	]*\)undef\([ 	][ 	]*\)'
+ac_uB='\([ 	]\)%\1#\2define\3'
+ac_uC=' '
+ac_uD='\4%g'
+# ac_e turns "#undef NAME" without trailing blanks into "#define NAME VALUE".
+ac_eA='s%^\([ 	]*\)#\([ 	]*\)undef\([ 	][ 	]*\)'
+ac_eB='$%\1#\2define\3'
+ac_eC=' '
+ac_eD='%g'
+
+if test "${CONFIG_HEADERS+set}" != set; then
+EOF
+cat >> $CONFIG_STATUS <<EOF
+  CONFIG_HEADERS="config.h"
+EOF
+cat >> $CONFIG_STATUS <<\EOF
+fi
+for ac_file in .. $CONFIG_HEADERS; do if test "x$ac_file" != x..; then
+  # Support "outfile[:infile[:infile...]]", defaulting infile="outfile.in".
+  case "$ac_file" in
+  *:*) ac_file_in=`echo "$ac_file"|sed 's%[^:]*:%%'`
+       ac_file=`echo "$ac_file"|sed 's%:.*%%'` ;;
+  *) ac_file_in="${ac_file}.in" ;;
+  esac
+
+  echo creating $ac_file
+
+  rm -f conftest.frag conftest.in conftest.out
+  ac_file_inputs=`echo $ac_file_in|sed -e "s%^%$ac_given_srcdir/%" -e "s%:% $ac_given_srcdir/%g"`
+  cat $ac_file_inputs > conftest.in
+
+EOF
+
+# Transform confdefs.h into a sed script conftest.vals that substitutes
+# the proper values into config.h.in to produce config.h.  And first:
+# Protect against being on the right side of a sed subst in config.status.
+# Protect against being in an unquoted here document in config.status.
+rm -f conftest.vals
+cat > conftest.hdr <<\EOF
+s/[\\&%]/\\&/g
+s%[\\$`]%\\&%g
+s%#define \([A-Za-z_][A-Za-z0-9_]*\) *\(.*\)%${ac_dA}\1${ac_dB}\1${ac_dC}\2${ac_dD}%gp
+s%ac_d%ac_u%gp
+s%ac_u%ac_e%gp
+EOF
+sed -n -f conftest.hdr confdefs.h > conftest.vals
+rm -f conftest.hdr
+
+# This sed command replaces #undef with comments.  This is necessary, for
+# example, in the case of _POSIX_SOURCE, which is predefined and required
+# on some systems where configure will not decide to define it.
+cat >> conftest.vals <<\EOF
+s%^[ 	]*#[ 	]*undef[ 	][ 	]*[a-zA-Z_][a-zA-Z_0-9]*%/* & */%
+EOF
+
+# Break up conftest.vals because some shells have a limit on
+# the size of here documents, and old seds have small limits too.
+
+rm -f conftest.tail
+while :
+do
+  ac_lines=`grep -c . conftest.vals`
+  # grep -c gives empty output for an empty file on some AIX systems.
+  if test -z "$ac_lines" || test "$ac_lines" -eq 0; then break; fi
+  # Write a limited-size here document to conftest.frag.
+  echo '  cat > conftest.frag <<CEOF' >> $CONFIG_STATUS
+  sed ${ac_max_here_lines}q conftest.vals >> $CONFIG_STATUS
+  echo 'CEOF
+  sed -f conftest.frag conftest.in > conftest.out
+  rm -f conftest.in
+  mv conftest.out conftest.in
+' >> $CONFIG_STATUS
+  sed 1,${ac_max_here_lines}d conftest.vals > conftest.tail
+  rm -f conftest.vals
+  mv conftest.tail conftest.vals
+done
+rm -f conftest.vals
+
+cat >> $CONFIG_STATUS <<\EOF
+  rm -f conftest.frag conftest.h
+  echo "/* $ac_file.  Generated automatically by configure.  */" > conftest.h
+  cat conftest.in >> conftest.h
+  rm -f conftest.in
+  if cmp -s $ac_file conftest.h 2>/dev/null; then
+    echo "$ac_file is unchanged"
+    rm -f conftest.h
+  else
+    # Remove last slash and all that follows it.  Not all systems have dirname.
+      ac_dir=`echo $ac_file|sed 's%/[^/][^/]*$%%'`
+      if test "$ac_dir" != "$ac_file" && test "$ac_dir" != .; then
+      # The file is in a subdirectory.
+      test ! -d "$ac_dir" && mkdir "$ac_dir"
+    fi
+    rm -f $ac_file
+    mv conftest.h $ac_file
+  fi
+fi; done
+
+EOF
+cat >> $CONFIG_STATUS <<EOF
+
+EOF
+cat >> $CONFIG_STATUS <<\EOF
+
+exit 0
+EOF
+chmod +x $CONFIG_STATUS
+rm -fr confdefs* $ac_clean_files
+test "$no_create" = yes || ${CONFIG_SHELL-/bin/sh} $CONFIG_STATUS || exit 1
+
+
+
Index: /main/tags/2.25/niupepa/configure.in
===================================================================
--- /main/tags/2.25/niupepa/configure.in	(revision 21064)
+++ /main/tags/2.25/niupepa/configure.in	(revision 21064)
@@ -0,0 +1,246 @@
+dnl Process this file with autoconf to produce a configure script.
+AC_INIT(src/recpt/niupepalibrarymain.cpp)
+AC_CONFIG_HEADER(config.h)
+AC_ARG_PROGRAM
+
+PACKAGE=gsdl
+VERSION=2.1
+AC_DEFINE_UNQUOTED(PACKAGE, "$PACKAGE")
+AC_DEFINE_UNQUOTED(VERSION, "$VERSION")
+AC_SUBST(PACKAGE)
+AC_SUBST(VERSION)
+
+USE_FASTCGI=0
+if test USE_FASTCGI = 1; then
+AC_DEFINE(USE_FASTCGI)
+AC_SUBST(USE_FASTCGI)
+fi
+
+dnl Checks for programs.
+LDFLAGS=
+CFLAGS=-O2
+AC_SUBST(CFLAGS)
+
+AC_PROG_CC
+AC_PROG_CXX
+AC_PROG_AWK
+AC_PROG_YACC
+AC_PROG_INSTALL
+AC_PROG_LN_S
+AC_PROG_MAKE_SET
+AC_PROG_RANLIB
+
+
+dnl Checks for typedefs, structures, and compiler characteristics.
+AC_AIX
+AC_ISC_POSIX
+AC_MINIX
+fp_C_PROTOTYPES
+AC_C_CONST
+AC_TYPE_OFF_T
+AC_TYPE_SIZE_T
+AC_HEADER_TIME
+AC_STRUCT_TM
+
+dnl --- This should be in the stdc checking -----------------
+if test "$ac_cv_prog_cc_stdc" = '-Xc'; then
+dnl The Pyramids running SMP_DC.OSx on MIPS r3000 chips with
+dnl /usr/opt/cc3.11/bin/cc treat -Xc as full ANSI mode - no POSIX or
+dnl XOPEN extensions (like popen).
+dnl Unfortunately -D_{XOPEN,POSIX}_SOURCE can't provide all that mg
+dnl needs. So drop back to -Xa
+AC_TRY_COMPILE(
+[#include <stdio.h>
+], [ FILE *rubbish = popen("yes", "r"); ],,
+[CC="`echo $CC | sed 's/-Xc/-Xa/'`"    ac_cv_prog_cc_stdc='-Xa'])
+fi
+dnl ----------------------
+
+
+dnl Checks for libraries.
+dnl Replace `main' with a function in -lg:
+AC_CHECK_LIB(g, main)
+dnl Replace `main' with a function in -lgdbm:
+AC_CHECK_LIB(gdbm, main)
+dnl Replace `main' with a function in -lm:
+AC_CHECK_LIB(m, main)
+dnl Replace `main' with a function in -lstdc++:
+AC_CHECK_LIB(stdc++, main)
+dnl Replace `main' with a function in -lcrypt:
+AC_CHECK_LIB(crypt, main)
+
+
+dnl Checks for header files.
+AC_HEADER_DIRENT
+AC_HEADER_STDC
+AC_CHECK_HEADERS(fcntl.h limits.h sys/time.h unistd.h crypt.h string.h memory.h sys/procfs.h)
+AC_EGREP_HEADER(fread, stdio.h, AC_DEFINE(HAVE_FREAD_DECL))
+AC_EGREP_HEADER(fgetc, stdio.h, AC_DEFINE(HAVE_FGETC_DECL))
+AC_EGREP_HEADER(pr_brksize, sys/procfs.h, AC_DEFINE(HAVE_PR_BRKSIZE))
+
+dnl Checks for library functions.
+AC_FUNC_ALLOCA
+AC_PROG_GCC_TRADITIONAL
+AC_TYPE_SIGNAL
+AC_FUNC_VPRINTF
+AC_CHECK_FUNCS(ftime select strftime strtol getrusage times mallinfo setbuffer getpagesize strerror)
+AC_REPLACE_FUNCS(ftruncate strstr strcasecmp)
+
+
+# *** Custom checking (based on GNU tar configure.in) ***
+# ---------------------------------------------------------------------------
+AC_MSG_CHECKING(for HP-UX needing gmalloc)
+if test "`(uname -s) 2> /dev/null`" = 'HP-UX'; then
+  AC_MSG_RESULT(yes)
+  LIBOBJS="$LIBOBJS gmalloc.o"
+  AC_DEFINE(HAVE_VALLOC)
+else
+  AC_MSG_RESULT(no)
+  AC_CHECK_FUNCS(valloc)
+fi
+
+fp_WITH_DMALLOC
+fp_WITH_REGEX
+
+# ---------------------------------------------------------------------------
+if test "$ac_cv_func_alloca" = 'no'; then
+dnl    support functions for alloca.c
+  LIBOBJS="$LIBOBJS xmalloc.o error.o"
+fi
+
+
+# ---------------------------------------------------------------------------
+
+dnl
+dnl Switch into C++
+dnl
+AC_LANG_CPLUSPLUS
+
+dnl
+dnl Check that the GDBM library is available
+dnl
+AC_MSG_CHECKING("that the GDBM library is available")
+AC_TRY_COMPILE(
+[#include <gdbm.h>
+],
+[],
+success=yes,
+success=no
+)
+AC_MSG_RESULT($success)
+if test $success = "no"; then
+AC_MSG_ERROR("GDBM Library not available - cannot install")
+fi
+
+dnl
+dnl Now check that Perl is actually around, and can be found
+dnl
+AC_MSG_CHECKING("that Perl 5 is available")
+success="no"
+pl_path="$PATH"
+IFS="${IFS=   }"; pl_save_ifs="$IFS"; IFS=":"
+for pl_dir in $pl_path; do
+  test -z "$pl_dir" && pl_dir=.
+  if test -x $pl_dir/perl; then
+    success="yes"
+    break
+  fi
+done
+IFS="$pl_save_ifs"
+
+dnl
+dnl Perl actually can be run; now we see if it is version 5 by
+dnl running a sample script (which returns a "clean" version number
+dnl and then tests the result using expr.  If perl errors in some
+dnl way (eg. broken Perl executable, missing script), we set a failure
+dnl value ("0") and then proceed as best we can
+dnl
+if test $success = "yes"; then
+try=`perl configtest.pl` || try="0"
+try=`expr $try \> 5.000`
+if test $try = "1"; then
+AC_MSG_RESULT("yes")
+else
+success="no"
+fi
+fi
+
+if test $success = "no"; then
+AC_MSG_RESULT("no")
+AC_MSG_ERROR("Perl 5 not available - cannot install")
+fi
+
+dnl
+dnl Check if the STL library has any known faults;
+dnl In GCC 2.7.2.x series, some STL library headers are missing
+dnl a file called "new" which is referred to by other headers
+dnl (eg. vector/vector.h); if this applies, then all use of the
+dnl STL will cause a compile fail, so we'd better let the user
+dnl know now, before things really go wrong!
+dnl
+success=no
+AC_MSG_CHECKING("whether STL library has known faults")
+
+dnl - first shot, try simple good old vector on its own
+AC_TRY_COMPILE(
+[#include <vector>
+], 
+[],
+success=yes,
+)
+
+dnl - try using the .h equivalent
+if test $success = "no"; then
+AC_TRY_COMPILE(
+[#include <vector.h>
+], 
+[],
+success="yes",
+)
+fi
+
+dnl - now try for the objectspace headers
+if test $success = "no"; then
+AC_TRY_COMPILE(
+[#include <ospace\\std\\vector>
+], 
+[],
+success="yes",
+)
+fi
+
+if test $success = yes; then
+AC_MSG_RESULT("no")
+else
+AC_MSG_RESULT("yes")
+AC_MSG_ERROR("STL Broken - Obtain newer version of GNU C Compiler")
+fi
+
+gsdlos=`uname | tr A-Z a-z`
+AC_SUBST(gsdlos)
+
+AC_MSG_CHECKING(for HP-UX needing gmalloc)
+if test "`(uname -s) 2> /dev/null`" = 'HP-UX'; then
+  AC_MSG_RESULT(yes)
+  LIBOBJS="$LIBOBJS gmalloc.o"
+  AC_DEFINE(HAVE_VALLOC)
+else
+  AC_MSG_RESULT(no)
+  AC_CHECK_FUNCS(valloc)
+fi
+
+fp_WITH_DMALLOC
+fp_WITH_REGEX
+
+# ---------------------------------------------------------------------------
+if test "$ac_cv_func_alloca" = 'no'; then
+dnl    support functions for alloca.c
+  LIBOBJS="$LIBOBJS xmalloc.o error.o"
+fi
+
+
+# ---------------------------------------------------------------------------
+
+AC_OUTPUT(src/recpt/Makefile Makefile)
+
+
Index: /main/tags/2.25/niupepa/etc/collect.cfg
===================================================================
--- /main/tags/2.25/niupepa/etc/collect.cfg	(revision 21064)
+++ /main/tags/2.25/niupepa/etc/collect.cfg	(revision 21064)
@@ -0,0 +1,41 @@
+creator                sjboddie@cs.waikato.ac.nz
+maintainer             sjboddie@cs.waikato.ac.nz
+public                 true
+beta                   true
+
+macrofiles             style.dm base.dm query.dm help.dm \
+                       pref.dm about.dm home.dm document.dm \
+	               status.dm npepa.dm abexpl.dm \
+		       english.dm chinese.dm maori.dm
+
+subcollection          commentaries   Filename/\.commentary$/
+subcollection          abstracts      Filename/\.abstract$/
+subcollection          papers         !Filename/\.(abstract|commentary)$/
+indexsubcollections    papers,commentaries,abstracts papers commentaries abstracts
+defaultsubcollection   papers,commentaries,abstracts
+
+indexes                section:text
+defaultindex           section:text
+
+plugin                 GMLPlug 
+plugin                 NPPlug -create_log
+plugin                 ArcPlug 
+plugin                 RecPlug
+
+classify               NPepaList
+classify               NPDateList
+
+format                 SearchVList "<td valign=top>[link][icon][/link]</td><td>{If}{[parent:Series],[parent:Series],[Series]}: {If}{[parent(All': '):Title],[parent(All': '):Title]: }[link][Title][/link]</td>"
+
+# [link] is overridden for CL1VList in this collection (to include links/icons to abstracts as well as papers)
+format                 CL1VList "<td valign=top>[link]</td><td valign=top>[Title]{If}{[numleafdocs], <i>([numleafdocs])</i>}</td><td valign=top>{If}{[Date],[Date]}</td>"
+
+format                 CL2DateList "<td valign=top>{If}{[abstract],<a href=_httpdocument_&cl=_cgiargcl_&d=[abstract]>_document:iconabstract_}[link][icon][/link]</td><td>[Series]: [Title]</td><td>[Date]</td>"
+
+format                 DocumentHeading "<h3>{If}{[parent(Top):Title],[parent(Top):Title],[Title]}<br>{If}{[parent(Top):Date],[parent(Top):Date],[Date]}"
+
+receptionist           /fast-cgi-bin/niupepalibrary?a=p&p=about&c=niupepa&l=mi
+
+collectionmeta         collectionname      "Niupepa: M&auml;ori Newspapers"
+collectionmeta         iconcollection      "/gsdl/collect/niupepa/images/niupepa.gif"
+collectionmeta         iconcollectionsmall "/gsdl/collect/niupepa/images/niupepsm.gif"
Index: /main/tags/2.25/niupepa/install-sh
===================================================================
--- /main/tags/2.25/niupepa/install-sh	(revision 21064)
+++ /main/tags/2.25/niupepa/install-sh	(revision 21064)
@@ -0,0 +1,238 @@
+#! /bin/sh
+#
+# install - install a program, script, or datafile
+# This comes from X11R5.
+#
+# Calling this script install-sh is preferred over install.sh, to prevent
+# `make' implicit rules from creating a file called install from it
+# when there is no Makefile.
+#
+# This script is compatible with the BSD install script, but was written
+# from scratch.
+#
+
+
+# set DOITPROG to echo to test this script
+
+# Don't use :- since 4.3BSD and earlier shells don't like it.
+doit="${DOITPROG-}"
+
+
+# put in absolute paths if you don't have them in your path; or use env. vars.
+
+mvprog="${MVPROG-mv}"
+cpprog="${CPPROG-cp}"
+chmodprog="${CHMODPROG-chmod}"
+chownprog="${CHOWNPROG-chown}"
+chgrpprog="${CHGRPPROG-chgrp}"
+stripprog="${STRIPPROG-strip}"
+rmprog="${RMPROG-rm}"
+mkdirprog="${MKDIRPROG-mkdir}"
+
+tranformbasename=""
+transform_arg=""
+instcmd="$mvprog"
+chmodcmd="$chmodprog 0755"
+chowncmd=""
+chgrpcmd=""
+stripcmd=""
+rmcmd="$rmprog -f"
+mvcmd="$mvprog"
+src=""
+dst=""
+dir_arg=""
+
+while [ x"$1" != x ]; do
+    case $1 in
+	-c) instcmd="$cpprog"
+	    shift
+	    continue;;
+
+	-d) dir_arg=true
+	    shift
+	    continue;;
+
+	-m) chmodcmd="$chmodprog $2"
+	    shift
+	    shift
+	    continue;;
+
+	-o) chowncmd="$chownprog $2"
+	    shift
+	    shift
+	    continue;;
+
+	-g) chgrpcmd="$chgrpprog $2"
+	    shift
+	    shift
+	    continue;;
+
+	-s) stripcmd="$stripprog"
+	    shift
+	    continue;;
+
+	-t=*) transformarg=`echo $1 | sed 's/-t=//'`
+	    shift
+	    continue;;
+
+	-b=*) transformbasename=`echo $1 | sed 's/-b=//'`
+	    shift
+	    continue;;
+
+	*)  if [ x"$src" = x ]
+	    then
+		src=$1
+	    else
+		# this colon is to work around a 386BSD /bin/sh bug
+		:
+		dst=$1
+	    fi
+	    shift
+	    continue;;
+    esac
+done
+
+if [ x"$src" = x ]
+then
+	echo "install:	no input file specified"
+	exit 1
+else
+	true
+fi
+
+if [ x"$dir_arg" != x ]; then
+	dst=$src
+	src=""
+	
+	if [ -d $dst ]; then
+		instcmd=:
+	else
+		instcmd=mkdir
+	fi
+else
+
+# Waiting for this to be detected by the "$instcmd $src $dsttmp" command
+# might cause directories to be created, which would be especially bad 
+# if $src (and thus $dsttmp) contains '*'.
+
+	if [ -f $src -o -d $src ]
+	then
+		true
+	else
+		echo "install:  $src does not exist"
+		exit 1
+	fi
+	
+	if [ x"$dst" = x ]
+	then
+		echo "install:	no destination specified"
+		exit 1
+	else
+		true
+	fi
+
+# If destination is a directory, append the input filename; if your system
+# does not like double slashes in filenames, you may need to add some logic
+
+	if [ -d $dst ]
+	then
+		dst="$dst"/`basename $src`
+	else
+		true
+	fi
+fi
+
+## this sed command emulates the dirname command
+dstdir=`echo $dst | sed -e 's,[^/]*$,,;s,/$,,;s,^$,.,'`
+
+# Make sure that the destination directory exists.
+#  this part is taken from Noah Friedman's mkinstalldirs script
+
+# Skip lots of stat calls in the usual case.
+if [ ! -d "$dstdir" ]; then
+defaultIFS='	
+'
+IFS="${IFS-${defaultIFS}}"
+
+oIFS="${IFS}"
+# Some sh's can't handle IFS=/ for some reason.
+IFS='%'
+set - `echo ${dstdir} | sed -e 's@/@%@g' -e 's@^%@/@'`
+IFS="${oIFS}"
+
+pathcomp=''
+
+while [ $# -ne 0 ] ; do
+	pathcomp="${pathcomp}${1}"
+	shift
+
+	if [ ! -d "${pathcomp}" ] ;
+        then
+		$mkdirprog "${pathcomp}"
+	else
+		true
+	fi
+
+	pathcomp="${pathcomp}/"
+done
+fi
+
+if [ x"$dir_arg" != x ]
+then
+	$doit $instcmd $dst &&
+
+	if [ x"$chowncmd" != x ]; then $doit $chowncmd $dst; else true ; fi &&
+	if [ x"$chgrpcmd" != x ]; then $doit $chgrpcmd $dst; else true ; fi &&
+	if [ x"$stripcmd" != x ]; then $doit $stripcmd $dst; else true ; fi &&
+	if [ x"$chmodcmd" != x ]; then $doit $chmodcmd $dst; else true ; fi
+else
+
+# If we're going to rename the final executable, determine the name now.
+
+	if [ x"$transformarg" = x ] 
+	then
+		dstfile=`basename $dst`
+	else
+		dstfile=`basename $dst $transformbasename | 
+			sed $transformarg`$transformbasename
+	fi
+
+# don't allow the sed command to completely eliminate the filename
+
+	if [ x"$dstfile" = x ] 
+	then
+		dstfile=`basename $dst`
+	else
+		true
+	fi
+
+# Make a temp file name in the proper directory.
+
+	dsttmp=$dstdir/#inst.$$#
+
+# Move or copy the file name to the temp name
+
+	$doit $instcmd $src $dsttmp &&
+
+	trap "rm -f ${dsttmp}" 0 &&
+
+# and set any options; do chmod last to preserve setuid bits
+
+# If any of these fail, we abort the whole thing.  If we want to
+# ignore errors from any of these, just make sure not to ignore
+# errors from the above "$doit $instcmd $src $dsttmp" command.
+
+	if [ x"$chowncmd" != x ]; then $doit $chowncmd $dsttmp; else true;fi &&
+	if [ x"$chgrpcmd" != x ]; then $doit $chgrpcmd $dsttmp; else true;fi &&
+	if [ x"$stripcmd" != x ]; then $doit $stripcmd $dsttmp; else true;fi &&
+	if [ x"$chmodcmd" != x ]; then $doit $chmodcmd $dsttmp; else true;fi &&
+
+# Now rename the file to the real destination.
+
+	$doit $rmcmd -f $dstdir/$dstfile &&
+	$doit $mvcmd $dsttmp $dstdir/$dstfile 
+
+fi &&
+
+
+exit 0
Index: /main/tags/2.25/niupepa/macros/abexpl.dm
===================================================================
--- /main/tags/2.25/niupepa/macros/abexpl.dm	(revision 21064)
+++ /main/tags/2.25/niupepa/macros/abexpl.dm	(revision 21064)
@@ -0,0 +1,49 @@
+package abexpl
+
+_imagethispage_ {}
+_pagetitle_ {English Abstracts of the M&auml;ori Language Newspapers}
+
+_content_ {
+<center>
+_navigationbar_
+</center>
+<h2>English Abstracts of the M&auml;ori Language Newspapers</h2>
+<h3>Introduction</h3>
+<P>The English abstracts of the M&auml;ori language newspapers are designed to give an impression of a whole newspaper 
+issue and to guide researchers to particular topics or information for translation. Although every item in an issue 
+is noted, the abstracts do not represent a full translation of the entire contents. They summarise long items such 
+as editorials, articles, and letters, and briefly record, sometimes by a complete translation, small items such as 
+notices, advertisements, short news reports. In sum the abstracts represent an abbreviated form of a newspaper and 
+so to ensure a complete reading of any item researchers will need to refer to or seek translation of the M&auml;ori text.
+
+<P>The abstracts follow the order of  items in a newspaper and include the titles and subtitles. Apart from occasional 
+additions in square brackets to clarify or inform, the abstracts report only what is in the newspaper. Where English 
+translation is published in the paper this is noted together with a brief statement of content.
+<P>A few M&auml;ori words remain in the abstracts without translation because they are key words for researchers of M&auml;ori 
+language and culture. These are highlighted and can be clicked on for explanation in the glossary. M&auml;ori names (personal, 
+place and tribal) have been written according to contemporary spelling as far as this is known.
+<P>The English abstracts are being created by a team of researchers who, in 1999, began a three-year project into the 
+history and contents of  these newspapers. The project is funded by grants from the Marsden Fund and the Trustees of 
+the National Library. The research team, from the Department of M&auml;ori Studies at the University of Auckland, comprises 
+Professor Ngapare Hopa, Dr Jane McRae, Jenifer Curnow, and postgraduate researchers Dinah Paul, Hazel Petrie, Yvonne 
+Sutherland, and Lyn Waymouth. They work collaboratively with the History of Print Culture in New Zealand Research Project, 
+and with Professor Mark Apperley and Te Taka Keegan of the Computer Science Department, University of Waikato, who are 
+carrying out the on-line conversion of the abstracts.
+
+<h3>Glossary</h3>
+<P>M&auml;ori words
+<P>The following M&auml;ori words have been retained in the abstracts because they are key words for researchers into 
+M&auml;ori language and culture. They are used here generically and so refer to all the different kinds of texts within 
+these genres.
+<P>karakia: incantations
+<P>k&ouml;rero: narratives 
+<P>waiata: sung and recited poetry
+<P>whakapapa: genealogy
+<P>whakatauk&iuml;: sayings, set expressions
+
+<h3>Abbreviations</h3>
+CMS: Church Missionary Society
+<P>MLC: Member of the Legislative Council
+<P>MHR: Member of the House of Representatives
+<P>WMMS: Wesleyan Missionary Society
+}
Index: /main/tags/2.25/niupepa/macros/about.dm
===================================================================
--- /main/tags/2.25/niupepa/macros/about.dm	(revision 21064)
+++ /main/tags/2.25/niupepa/macros/about.dm	(revision 21064)
@@ -0,0 +1,135 @@
+package about
+
+#######################################################################
+# Icons
+#######################################################################
+
+_imagethispage_ [c=niupepa] {<img src="_httpiconhabout_" width=_widthhabout_ height=_heighthabout_>}
+
+# don't want link to 'about' page
+_imagecollection_ [c=niupepa] {<img src="_iconcollection_" border=0>}
+
+_imagemined_ [c=niupepa] {<a href="http://www.minedu.govt.nz/">_iconmined_</a>}
+
+_iconmined_ [c=niupepa] {<img src="_httpcollection_/images/mined.gif" border=0>}
+
+#######################################################################
+# English language text 
+#######################################################################
+
+_texthelpexpl_ [c=niupepa] {For help at any time, press this button at the top of the page}
+
+_textretabout_ {To return to this "about" page, click the "collection"
+icon at the top left of the page.}
+
+_textabcol_ [c=niupepa] {About this collection}
+
+_textabout_ [c=niupepa] {
+<h3>_textabcol_</h3>
+<p>This is a small but growing collection based on "Niupepa 1842-1933", a microfiche collection 
+produced by the Alexander Turnbull Library. Niupepa are periodicals published in Maori or 
+for a Maori readership. Between 1842 and 1933 there were three main types of Niupepa published: 
+Government sponsored, Iwi based and religious. By the twentieth century most Niupepa were religious 
+publications. 
+<p>
+Niupepa are an important source of information on individuals, Iwi, whaikorero, waiata, Maori 
+opinions and the development of Maori as a written language. 
+<p>
+There are four main parts to the collection:
+<ul>
+<li>facsimile images of the original images
+<li>text extracted from the newspapers (used for searching)
+<li>bibliographic commentaries for each newspaper title
+<li><a href="_httppagex_(abexpl)">English abstracts</a> for each issue
+</ul>
+<p>
+The newspapers are also available on 35mm microfilm and microfiche. They can be borrowed on 
+Interloan through your local library or they can be purchased from:
+<p>
+Copying Services<br>
+Alexander Turnbull Library<br>
+PO Box 12349<br>
+Wellington<br>
+04 474 3113<br>
+04 474 6063 (fax)<br>
+<a href="mailto:atl@natlib.govt.nz">atl@natlib.govt.nz</a>
+<p>
+Commentaries on titles provided by Gail Dallimore.
+<p>
+Digital image capture carried out by New Zealand Micrographic Services Ltd.
+<p>
+OCR work sponsored by:<br>
+_imagemined_
+<p>
+}
+
+
+
+
+#######################################################################
+# Maori language text 
+#######################################################################
+
+_texthelpexpl_ [c=niupepa,l=mi] {Kia titiro ki ng_amn_ kupu _amn_whina p_amn_whiritia t_emn_nei
+p_amn_tene kei runga r_amn_ o ia wh_amn_rangi}
+
+_textabcol_ [c=niupepa,l=mi] {He kupu whakam_amn_rama i te kohikohinga niupepa}
+
+_textabout_ [c=niupepa,l=mi] {
+<h3>_textabcol_</h3>
+<p>E puaki ana _emn_nei pukapuka i te kohinga "Niupepa 1842-1933". Ko taua kohinga he 
+mea whakaemia e te Alexander Turnball Library ki runga i te kiriata mororiki. 
+Kua t_amn_ngia aua niupepa hei p_amn_nuitanga m_amn_ te iwi M_amn_ori, _amn_, ko te nuinga kua 
+tuhia ki te reo M_amn_ori. E toru ng_amn_ kaupapa matua o ng_amn_ niupepa: he h_amn_painga m_omn_ 
+te Kawanatanga, he p_amn_nuitanga r_amn_nei n_omn_ ng_amn_ iwi M_amn_ori, he kupu whakapono r_amn_nei 
+n_omn_ ng_amn_ h_amn_hi. I te huringa o te rautau 1900 i rahi haere te kaupapa h_amn_hi.
+<p>
+Ka nui ng_amn_ taonga ka noho mai nei i ng_amn_ Niupepa: ko ng_amn_ whaikorero, ng_amn_ waiata, 
+me ng_amn_ karakia, ng_amn_ k_omn_rero o te tangata, o te Iwi, o te whenua, o ng_amn_ 
+huihuinga, o ng_amn_ whakaaro me ng_amn_ _amn_huatanga o taua w_amn_, _amn_, ko ng_amn_ tauira hoki o 
+te reo M_amn_ori.
+
+<p>
+Kei runga te kohinga "Niupepa 1842-1933" katoa i te kiriata m_omn_kito 35mm me te 
+kiriata mororiki. Ka taea te tono _emn_nei i te whare pukapuka o t_omn_ rohe, ka taea 
+r_amn_nei te hoko mai i te
+<p>
+Copying Services<br>
+Alexander Turnbull Library<br>
+PO Box 12349<br>
+Wellington<br>
+04 474 3113<br>
+04 474 6063 (fax)<br>
+<a href="mailto:atl@natlib.govt.nz">atl@natlib.govt.nz</a>
+<p>
+ko ng_amn_ mahi OCR ka tautokohia e:<br>
+_imagemined_
+<p>
+}
+
+
+##############
+# about page #
+##############
+
+
+_aboutextra_ [c=niupepa] {
+_If_("_cgiargl_" eq "mi",<a href="_httppageabout_&l=en">English language version</a><p>)
+<h3>_help:textsimplehelpheading_</h3>
+_help:simplehelp_
+}
+
+_pagetitle_ [c=niupepa] {_collectionname_: About this collection}
+
+_content_ [c=niupepa] {
+<center>
+_navigationbar_
+</center>
+_query:queryform_
+<p>
+_iconblankbar_<br>
+_aboutextra_
+<p>
+_iconblankbar_<br>
+_textabout_
+}
Index: /main/tags/2.25/niupepa/macros/npepa.dm
===================================================================
--- /main/tags/2.25/niupepa/macros/npepa.dm	(revision 21064)
+++ /main/tags/2.25/niupepa/macros/npepa.dm	(revision 21064)
@@ -0,0 +1,424 @@
+package Global
+
+_textbiblio_ [c=niupepa] {Bibliographic Details}
+_textbackground_ [c=niupepa] {Background}
+_textsubmat_ [c=niupepa] {Subject Matter}
+_textavail_ [c=niupepa] {Availability}
+_commentary_ [c=niupepa] {Commentary}
+
+_missingtext_ [c=niupepa] {Text has yet to be digitised for this page}
+
+_iconclosedbook_ [c=niupepa] {<img src="_httpcollection_/images/np.gif" valign=top width=20 height=20 border=0 alt="_texticonclosedbook_">}
+_texticonclosedbook_ [c=niupepa] {view niupepa}
+_texticonclosedbook_ [c=niupepa,l=mi] {tirohia niupepa}
+
+_textbiblio_ [c=niupepa,l=mi] {K_omn_rero T_amn_}
+_textbackground_ [c=niupepa,l=mi] {He Whakam_amn_rama}
+_textsubmat_ [c=niupepa,l=mi] {Kaupapa}
+_textavail_ [c=niupepa,l=mi] {Nohoanga}
+_commentary_ [c=niupepa,l=mi] {Kupu Whakataki}
+
+_abstract_ [c=niupepa] {Abstract: }
+
+_abstract_ [c=niupepa,l=mi] {R_amn_popoto reo P_amn_keh_amn_: }
+
+#######################################################################
+# index option macros
+#######################################################################
+
+_stx_ [c=niupepa] {}
+
+_ab_ [c=niupepa] {english abstracts}
+_ab_ [c=niupepa,l=mi] {ng_amn_ r_amn_popoto reo P_amn_keh_amn_ anake}
+_cm_ [c=niupepa] {bibliographic commentaries}
+_cm_ [c=niupepa,l=mi] {ng_amn_ kupu whakataki anake}
+_pc_ [c=niupepa] {papers, commentaries, and abstracts}
+_pc_ [c=niupepa,l=mi] {niupepa, kupu whakataki, me ng_amn_ r_amn_popoto}
+_pp_ [c=niupepa] {newspapers}
+_pp_ [c=niupepa,l=mi] {ng_amn_ niupepa anake}
+
+
+package document
+
+#_abstract_ [c=niupepa] {Abstract<br>}
+#_abstract_ [c=niupepa,l=mi] {R_amn_popoto reo P_amn_keh_amn_<br>}
+
+_httpthiscommentary_ [c=niupepa] {}
+_httpiconthispaper_ [c=niupepa] {}
+_thispapericonwidth_ [c=niupepa] {0}
+_thispapericonheight_ [c=niupepa] {0}
+
+_01width_ {314}
+_01height_ {126}
+_03width_ {320}
+_03height_ {205}
+_04width_ {322}
+_04height_ {195}
+_05width_ {320}
+_05height_ {210}
+_06awidth_ {320}
+_06aheight_ {80}
+_08width_ {330}
+_08height_ {139}
+_09width_ {330}
+_09height_ {76}
+_10width_ {320}
+_10height_ {43}
+_12width_ {330}
+_12height_ {95}
+_13width_ {310}
+_13height_ {316}
+_14width_ {330}
+_14height_ {81}
+_15width_ {320}
+_15height_ {110}
+_18width_ {310}
+_18height_ {120}
+_19width_ {333}
+_19height_ {230}
+_25width_ {312}
+_25height_ {56}
+_36awidth_ {327}
+_36aheight_ {153}
+_39width_ {320}
+_39height_ {102}
+_40width_ {298}
+_40height_ {153}
+
+
+_iconabstract_ [c=niupepa] {<img src="_httpiconiabstr_" valign=top border=0 alt="_texticonabstract_">}
+_iconabstract_ [c=niupepa,v=1] {_texticonabstract_}
+
+_iconcommentary_ [c=niupepa] {<img src="_httpcollection_/images/icomm.gif" valign=top border=0 alt="_texticoncommentary_">}
+_iconcommentary_ [c=niupepa,v=1] {_texticoncommentary_}
+
+# javalinks specific to this collection
+_javafullimage_ [c=niupepa] {
+        fullimage\_on = new Image(_widthefix_, _heightefix_); 
+        fullimage\_on.src = "_httpiconefion_";
+        fullimage\_off = new Image(_widthefix_, _heightefix_); 
+        fullimage\_off.src = "_httpiconefiof_";
+}
+
+_javaprevimage_ [c=niupepa] {
+        previmage\_on = new Image(_widthepix_, _widthepix_); 
+        previmage\_on.src = "_httpiconepion_";
+        previmage\_off = new Image(_widthepix_, _heightepix_); 
+        previmage\_off.src = "_httpiconepiof_";
+}
+
+_javaviewtext_ [c=niupepa] {
+        viewtext\_on = new Image(_widthetextx_, _heightetextx_); 
+        viewtext\_on.src = "_httpiconetexton_";
+        viewtext\_off = new Image(_widthetextx_, _heightetextx_); 
+        viewtext\_off.src = "_httpiconetextof_";
+}
+
+_javacommentary_ [c=niupepa] {
+	commentary\_on = new Image(_thispapericonwidth_, _thispapericonheight_);
+	commentary\_on.src = "_httpiconthispaper_on.gif";
+	commentary\_off = new Image(_thispapericonwidth_, _thispapericonheight_);
+        commentary\_off.src = "_httpiconthispaper_of.gif"; 
+}
+
+_javaviewabstract_ [c=niupepa] {
+        abstract\_on = new Image(_widtheabstrx_, _heighteabstrx_); 
+        abstract\_on.src = "_httpiconeabstron_";
+        abstract\_off = new Image(_widtheabstrx_, _heighteabstrx_); 
+        abstract\_off.src = "_httpiconeabstrof_";
+}
+
+_javaviewpaper_ [c=niupepa] {
+        paper\_on = new Image(_widthenpepax_, _heightenpepax_); 
+        paper\_on.src = "_httpiconenpepaon_";
+        paper\_off = new Image(_widthenpepax_, _heightenpepax_); 
+        paper\_off.src = "_httpiconenpepaof_";
+}
+
+_javaabstractintro_ [c=niupepa] {
+        intro\_on = new Image(_widtheintrox_, _heighteintrox_); 
+        intro\_on.src = "_httpiconeintroon_";
+        intro\_off = new Image(_widtheintrox_, _heighteintrox_); 
+        intro\_off.src = "_httpiconeintroof_";
+}
+
+_prevarrow_ [c=niupepa] {_If_(_httpprevarrow_,<a href="_httpprevarrow__1_">_iconprev_</a>)}
+_nextarrow_ [c=niupepa] {_If_(_httpnextarrow_,<a href="_httpnextarrow__1_">_iconnext_</a>)}
+
+
+_iconfullimage_ [c=niupepa] {<img name="fullimage" src="_httpiconefiof_" width="_widthefix_" height="_heightefix_" alt="_texticonfullimage_" border="0">}
+_iconfullimage_ [c=niupepa,v=1] {_texticonfullimage_}
+
+_iconprevimage_ [c=niupepa] {<img name="previmage" src="_httpiconepiof_" width="_widthepix_" height="_heightepix_" alt="_texticonprevimage_" border="0">}
+_iconprevimage_ [c=niupepa,v=1] {_texticonprevimage_}
+
+_iconviewtext_ [c=niupepa] {<img name="viewtext" src="_httpiconetextof_" width="_widthetextx_" height="_heightetextx_" alt="_texticonviewtext_" border="0">}
+_iconviewtext_[c=niupepa,v=1] {_texticonviewtext_}
+
+_iconviewabstract_ [c=niupepa] {<img name="abstract" src="_httpiconeabstrof_" width="_widtheabstrx_" height="_heighteabstrx_" alt="_texticonviewabstract_" border="0">}
+_iconviewabstract_[c=niupepa,v=1] {_texticonviewabstract_}
+
+_iconviewpaper_ [c=niupepa] {<img name="paper" src="_httpiconenpepaof_" width="_widthenpepax_" height="_heightenpepax_" alt="_texticonviewpaper_" border="0">}
+_iconviewpaper_[c=niupepa,v=1] {_texticonviewpaper_}
+
+_iconabstractintro_ [c=niupepa] {<img name="intro" src="_httpiconeintroof_" width="_widtheintrox_" height="_heighteintrox_" alt="_texticonabstractintro_" border="0">}
+_iconabstractintro_[c=niupepa,v=1] {_texticonabstractintro_}
+
+_iconthispaper_ [c=niupepa] {<img name="commentary" src="_httpiconthispaper_of.gif" 
+width="_thispapericonwidth_" height="_thispapericonheight_" border="0" alt="_texticoncommentary_">}
+
+
+_imagedetach_ [c=niupepa] {<a href="_httpcurrentdocument_&x=1&gg=_cgiarggg_" target=\_blank onMouseover = "img\_on('detach')"
+onMouseout = "img\_off('detach')">_icondetach_</a>}
+_imagedetach_[c=niupepa,v=1] {<a href="_httpcurrentdocument_&x=1&gg=cgiarggg_" target=\_blank>_texticondetach_</a><br>}
+
+
+_imagefullimage_ [c=niupepa] {<a href="_httpcurrentdocument_&gg=full" onMouseover = "img\_on('fullimage')"
+onMouseout = "img\_off('fullimage')">_iconfullimage_</a>}
+_imagefullimage_ [c=niupepa,v=1] {<a href="_httpcurrentdocument_&gg=full">_texticonfullimage_</a><br>}
+
+_imageprevimage_ [c=niupepa] {<a href="_httpcurrentdocument_&gg=prev" onMouseover = "img\_on('previmage')"
+onMouseout = "img\_off('previmage')">_iconprevimage_</a>}
+_imageprevimage_ [c=niupepa,v=1] {<a href="_httpcurrentdocument_&gg=prev">_texticonprevimage_</a><br>}
+
+_imageviewtext_ [c=niupepa] {<a href="_httpcurrentdocument_&gg=text" onMouseover = "img\_on('viewtext')"
+onMouseout = "img\_off('viewtext')">_iconviewtext_</a>}
+_imageviewtext_ [c=niupepa,v=1] {<a href="_httpcurrentdocument_&gg=text">_texticonviewtext_</a><br>}
+
+_imageviewabstract_ [c=niupepa] {<a href="_httpdocument_&gg=text&&cl=_cgiargcl_&d=_1_" onMouseover = "img\_on('abstract')"
+onMouseout = "img\_off('abstract')">_iconviewabstract_</a>}
+_imageviewabstract_ [c=niupepa,v=1] {<a href="_httpdocument_&gg=text&cl=_cgiargcl_&d=_1_">_texticonviewabstract_</a><br>}
+
+_imageviewpaper_ [c=niupepa] {<a href="_httpdocument_&cl=_cgiargcl_&d=_1_" onMouseover = "img\_on('paper')"
+onMouseout = "img\_off('paper')">_iconviewpaper_</a>}
+_imageviewpaper_ [c=niupepa,v=1] {<a href="_httpdocument_&cl=_cgiargcl_&d=_1_">_texticonviewpaper_</a><br>}
+
+_imageabstractintro_ [c=niupepa] {<a href="_httppagex_(abexpl)" onMouseover = "img\_on('intro')"
+onMouseout = "img\_off('intro')">_iconabstractintro_</a>}
+_imageabstractintro_ [c=niupepa,v=1] {<a href="_httppagex_(abexpl)">_texticonabstractintro_</a><br>}
+
+_imagethispaper_ [c=niupepa] {_If_(_httpthiscommentary_,_linkthispaper_,_nolinkthispaper_)}
+
+_linkthispaper_ [c=niupepa] {<a href="_httpthiscommentary_" 
+    onMouseover = "img\_on('commentary')" 
+    onMouseout = "img\_off('commentary')">_iconthispaper_</a>}
+_imagethispaper_ [c=niupepa,v=1] {<a href="_httpthiscommentary_">_texticoncommentary_</a><br>
+}
+
+# this occurs when we're at a commentary page - (no alt text, no link)
+_nolinkthispaper_ [c=niupepa] {<img src="_httpiconthispaper_on.gif" width="_thispapericonwidth_" 
+height="_thispapericonheight_" border="0">}
+
+
+_httpiconefiof_ [c=niupepa] {_httpcollection_/images/efiof.gif}
+_httpiconefiof_ [c=niupepa,l=mi] {_httpcollection_/images/mi/efiof.gif}
+_httpiconefion_ [c=niupepa] {_httpcollection_/images/efion.gif}
+_httpiconefion_ [c=niupepa,l=mi] {_httpcollection_/images/mi/efion.gif}
+_widthefix_ [c=niupepa] {65}
+_widthefix_ [c=niupepa,l=mi] {65}
+_heightefix_ [c=niupepa] {30}
+
+_httpiconepiof_ [c=niupepa] {_httpcollection_/images/epiof.gif}
+_httpiconepiof_ [c=niupepa,l=mi] {_httpcollection_/images/mi/epiof.gif}
+_httpiconepion_ [c=niupepa] {_httpcollection_/images/epion.gif}
+_httpiconepion_ [c=niupepa,l=mi] {_httpcollection_/mi/epion.gif}
+_widthepix_ [c=niupepa] {65}
+_widthepix_ [c=niupepa,l=mi] {65}
+_heightepix_ [c=niupepa] {30}
+
+_httpiconetextof_ [c=niupepa] {_httpcollection_/images/etextof.gif}
+_httpiconetextof_ [c=niupepa,l=mi] {_httpcollection_/images/mi/etextof.gif}
+_httpiconetexton_ [c=niupepa] {_httpcollection_/images/etexton.gif}
+_httpiconetexton_ [c=niupepa,l=mi] {_httpcollection_/images/mi/etexton.gif}
+_widthetextx_ [c=niupepa,l=mi] {65}
+_widthetextx_ [c=niupepa] {65}
+_heightetextx_ [c=niupepa] {30}
+
+_httpiconeabstrof_ [c=niupepa] {_httpcollection_/images/eabstrof.gif}
+_httpiconeabstrof_ [c=niupepa,l=mi] {_httpcollection_/images/mi/eabstrof.gif}
+_httpiconeabstron_ [c=niupepa] {_httpcollection_/images/eabstron.gif}
+_httpiconeabstron_ [c=niupepa,l=mi] {_httpcollection_/images/mi/eabstron.gif}
+_widtheabstrx_ [c=niupepa] {65}
+_widtheabstrx_ [c=niupepa,l=mi] {65}
+_heighteabstrx_ [c=niupepa] {30}
+
+_httpiconenpepaof_ [c=niupepa] {_httpcollection_/images/enpepaof.gif}
+_httpiconenpepaof_ [c=niupepa,l=mi] {_httpcollection_/images/mi/enpepaof.gif}
+_httpiconenpepaon_ [c=niupepa] {_httpcollection_/images/enpepaon.gif}
+_httpiconenpepaon_ [c=niupepa,l=mi] {_httpcollection_/images/mi/enpepaon.gif}
+_widthenpepax_ [c=niupepa] {65}
+_widthenpepax_ [c=niupepa,l=mi] {65}
+_heightenpepax_ [c=niupepa] {30}
+
+_httpiconeintroof_ [c=niupepa] {_httpcollection_/images/eintroof.gif}
+_httpiconeintroof_ [c=niupepa,l=mi] {_httpcollection_/images/mi/eintroof.gif}
+_httpiconeintroon_ [c=niupepa] {_httpcollection_/images/eintroon.gif}
+_httpiconeintroon_ [c=niupepa,l=mi] {_httpcollection_/images/mi/eintroon.gif}
+_widtheintrox_ [c=niupepa] {65}
+_widtheintrox_ [c=niupepa,l=mi] {65}
+_heighteintrox_ [c=niupepa] {30}
+
+_httpiconiabstr_ [c=niupepa] {_httpcollection_/images/iabstr.gif}
+
+_texticonsmalltext_ [c=niupepa] {_texticoncommentary_}
+_texticonabstract_ [c=niupepa] {View the english abstract}
+_texticonfullimage_ [c=niupepa] {View fullsize image of this page}
+_texticonprevimage_ [c=niupepa] {View preview image of this page}
+_texticonviewtext_ [c=niupepa] {View the text of this page}
+_texticoncommentary_ [c=niupepa] {View the commentary of this paper}
+_texticonviewabstract_ [c=niupepa] {View the English abstract of this issue}
+_texticonviewpaper_ [c=niupepa] {View niupepa issue}
+_texticonabstractintro_ [c=niupepa] {View introduction to English abstracts}
+
+_texticonsmalltext_ [c=niupepa,l=mi] {Tirohia kupu whakataki}
+_texticonabstract_ [c=niupepa,l=mi] {Tirohia ng_amn_ r_amn_popoto reo P_amn_keh_amn_}
+_texticonfullimage_ [c=niupepa,l=mi] {Titiro ki te whakaahua nui o t_emn_nei wh_amn_rangi niupepa}
+_texticonprevimage_ [c=niupepa,l=mi] {Titiro ki te whakaahua iti o t_emn_nei wh_amn_rangi niupepa}
+_texticonviewtext_ [c=niupepa,l=mi] {Titiro ki ng_amn_ kupu kua tuhia k_emn_ ki te rorohiko}
+_texticoncommentary_ [c=niupepa,l=mi] {Tirohia ng_amn_ kupu whakataki o t_emn_nei niupepa}
+_texticonviewabstract_ [c=niupepa,l=mi] {Tirohia te r_amn_popoto reo P_amn_keh_amn_ e p_amn_ 
+ana ki t_emn_nei w_amn_hanga}
+_texticonviewpaper_ [c=niupepa,l=mi] {Tirohia te wh_amn_rangi niupepa}
+_texticonabstractintro_ [c=niupepa,l=mi] {He whakam_amn_rama i ng_amn_ r_amn_popoto reo P_amn_keh_amn_}
+
+
+
+#################
+package help
+#################
+
+# no scope help for this collection
+_texthelpscope_ [c=niupepa] {}
+
+_textexplainbuttons_ [c=niupepa] {
+<p>
+<table cellspacing="0" cellpadding="2" border="0">
+<tr><td><img src="_httpimg_/smtext.gif" border="0"></td><td>_document:texticonsmalltext_</td></tr>
+<tr><td><img src="_httpimg_/clsdfldr.gif" border="0"></td><td>_document:texticonclosedfolder_</td></tr>
+<tr><td><img src="_httpimg_/more.gif"></td><td>_textnextbutton_</td></tr>
+<tr><td><img src="_httpimg_/less.gif"></td><td>_textprevbutton_</td></tr>
+<tr><td><img src="_httpicondtchdemo_"></td><td valign="center">_document:texticondetach_</td></tr>
+<tr><td><img src="_httpiconealltdemo_"></td><td valign="center">_document:texticonexpandtext_</td></tr>
+<tr><td><img src="_document:httpiconefiof_"></td><td valign="center">_document:texticonfullimage_</td></tr>
+<tr><td><img src="_document:httpiconepiof_"></td><td valign="center">_document:texticonprevimage_</td></tr>
+<tr><td><img src="_document:httpiconehlof_"></td><td valign="center">_document:texticonhighlight_</td></tr>
+</table>
+}
+
+_texthelptopics_ [c=niupepa,l=mi] {
+<h2 align=left>Kaupapa</h2>
+<ul>
+  <li><a href="\#finding-information">Ng_amn_ huarahi hei rapu k_omn_rero</a>
+  <li><a href="\#reading-books">Te p_amn_nui niupepa/kupu whakataki</a>
+  <li><a href="\#searching">Te rapu kupu</a>
+<ul>
+  <li><a href="\#query-terms">Ng_amn_ kupu hei rapu</a>
+  <li><a href="\#query-type">Ng_amn_ t_umn_momo rapu</a>
+  <li><a href="\#stemming">Ng_amn_ p_umn_ matua, p_umn_ iti me ng_amn_ k_umn_muri hoki</a>
+</ul>
+</ul>
+}
+
+_texthelptopics_ [c=niupepa] {
+<h2 align=left>Topics</h2>
+<ul>
+  <li><a href="\#finding-information">_textsimplehelpheading_</a>
+  <li><a href="\#reading-books">How to read the books</a>
+  <li><a href="\#searching">How to search for particular words</a>
+<ul>
+  <li><a href="\#query-terms">Search terms</a>
+  <li><a href="\#query-type">Query type</a>
+  <li><a href="\#stemming">Case sensitivity and stemming</a>
+</ul>
+</ul>
+}
+
+
+_texthelpreadingbooks_ [c=niupepa] {
+<h2>How to read Niupepa Pages</h2>
+
+<p>You can tell when you are looking at a Niupepa page because there is a picture
+of the Niupepa's insignia on the top right of the screen. Also, on the top left
+of the screen, the issue and number of the Niupepa is displayed, along with the
+publication date and some navigation buttons.
+
+<p>The lower half of the screen displays the digitized text of the Niupepa.
+It must be remembered that this text is captured by the computer from the
+pictures of the Niupepa pages. If the pages are dirty then errors will occur in the
+digitized text. View the picture of the Niupepa page to see the correct text.
+
+<p>If you click on the insignia of the Niupepa you will see the Bibliographic
+Commentary for that Niupepa. Other buttons are:
+}
+
+_texthelpreadingbooks_ [c=niupepa,l=mi] {
+<h2>Te P_amn_nui Niupepa</h2>
+
+<p>Mehemea ka kite atu koe i t_emn_tehi tohu niupepa i te taha katau o runga,
+ka m_omn_hio mai koe kei te titiro ki t_emn_tehi wh_amn_rangi o taua niupepa.
+Kei te taha maui o runga ka kite atu hoki i te nama me te w_amn_hanga o taua
+niupepa, te r_amn_ o taua niupepa, _amn_, kei reira hoki _emn_tehi p_amn_tene 
+hei whakatere i ng_amn_ wh_amn_rangi o te niupepa.
+
+<p>Kei raro r_amn_ ka kite atu i ng_amn_ k_omn_rero o t_emn_tehi wh_amn_rangi
+o te niupepa. Kia maumahara mai, ko _emn_nei kupu _amn_-rorohiko he mea hangaia 
+e te rorohiko i t_amn_na titiro ki te whakaahua o te wh_amn_rangi. Mehemea ka 
+paruparu te _amn_hua o te whakaahua, ka h_emn_ _emn_tehi kupu. Kia kite atu 
+i ng_amn_ kupu tika tirohia k_emn_tia te whakaahua o te wh_amn_rangi.
+
+<p>Mehemea ka p_amn_whiritia te tohu o te niupepa ka puta mai ng_amn_ kupu
+whakam_amn_rama m_omn_ taua niupepa. Ka p_emn_nei _emn_tehi atu p_amn_tene:
+}
+
+
+_textSeriesshort_ [c=niupepa] {access the niupepa by series}
+_textSeriesshort_ [c=niupepa,l=mi] {tirohia te whakar_amn_rangi taitara}
+_textDateshort_ [c=niupepa] {access the niupepa by date}
+_textDateshort_ [c=niupepa,l=mi] {tirohia te whakar_amn_rangi e p_amn_ ana ki te w_amn_}
+
+_textSerieslong_ [c=niupepa] {
+<p>You can <i>access the niupepa by series</i> by pressing the <i>series</i> button. 
+This brings up a list of those niupepa series which are currently in the collection. 
+Each series also contains a brief commentary which can be accessed from here.
+}
+
+_textSerieslong_ [c=niupepa,l=mi] {
+<p>Kia <i>tirohia te whakar_amn_rangi taitara</i> p_amn_whiritia te p_amn_tene 
+<i>whakar_amn_rangi taitara</i>. Ka puta mai te whakar_amn_rangi o ng_amn_
+niupepa e p_amn_ ana ki ng_amn_ taitara.
+}
+
+_textDatelong_ [c=niupepa] {
+<p>You can <i>access the niupepa by date</i> by pressing the <i>dates</i> button. 
+This brings up a list of all the niupepa issues, sorted chronologically.
+}
+
+_textDatelong_ [c=niupepa,l=mi] {<p>Kia <i>tirohia te whakar_amn_rangi e p_amn_ ana ki te w_amn_</i> p_amn_whiritia te
+p_amn_tene <i>w_amn_taka</i>. Ka puta mai te whakar_amn_rangi o ng_amn_ niupepa
+e p_amn_ ana ki te w_amn_ i puta mai ai aua niupepa.
+}
+
+_iconexplain_ [c=niupepa] {
+<table cellspacing="0" cellpadding="2" border="0">
+<tr valign="top"><td><img src="_httpcollection_/images/np.gif" width="20" height="20" border="0"></td>
+<td>Click on a newspaper icon to read the corresponding niupepa issue</td></tr>
+<tr valign="top"><td><img src="_httpimg_/bshelf.gif" border="0" width=20 height=16></td>
+<td>Click on a bookshelf icon when browsing the niupepa series to view a list of all the issues
+in that series</td></tr>
+<tr valign="top"><td><img src="_httpiconiabstr_" border="0"></td>
+<td>Click on an abstract icon to read English abstracts of the given issue</td></tr>
+</table>
+}
+
+_iconexplain_ [c=niupepa,l=mi] {
+<table cellspacing="0" cellpadding="2" border="0">
+<tr valign="top"><td><img src="_httpcollection_/images/np.gif" width="20" height="20" border="0"></td>
+<td>P_amn_whiritia te p_amn_tene niupepa kia puta mai ai taua niupepa</td></tr>
+<tr valign="top"><td><img src="_httpimg_/bshelf.gif" border="0" width=20 height=16></td>
+<td>P_amn_whiritia te p_amn_tene kohinga kia puta mai ai ng_amn_ niupepa o taua kohinga</td></tr>
+<tr valign="top"><td><img src="_httpiconiabstr_" border="0"></td>
+<td>P_amn_whiritia te p_amn_tene wh_amn_rangi kia puta mai ai te r_amn_popoto i te reo P_amn_keh_amn_</td></tr>
+</table>
+}
+
+
Index: /main/tags/2.25/niupepa/perllib/classify/NPDateList.pm
===================================================================
--- /main/tags/2.25/niupepa/perllib/classify/NPDateList.pm	(revision 21064)
+++ /main/tags/2.25/niupepa/perllib/classify/NPDateList.pm	(revision 21064)
@@ -0,0 +1,57 @@
+###########################################################################
+#
+# NPDateList.pm -- classifier plugin for sorting by date
+# A component of the Greenstone digital library software
+# from the New Zealand Digital Library Project at the 
+# University of Waikato, New Zealand.
+#
+# Copyright (C) 1999 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.
+#
+###########################################################################
+
+# overridden for niupepa as we don't want to include abstracts directly in lists
+
+package NPDateList;
+
+use DateList;
+
+sub BEGIN {
+    @ISA = ('DateList');
+}
+
+sub classify {
+    my $self = shift (@_);
+    my ($doc_obj) = @_;
+
+    # want to ignore abstracts
+    my $doctype = $doc_obj->get_metadata_element($doc_obj->get_top_section(), 'doctype');
+    return if (defined $doctype && $doctype eq 'Description');
+
+    my $doc_OID = $doc_obj->get_OID();
+    my $date = $doc_obj->get_metadata_element ($doc_obj->get_top_section(), 'Date');
+
+    # if this document doesn't contain Date element we won't 
+    # include it in this classification
+    if (defined $date && $date =~ /\d/) {
+	if (defined $self->{'list'}->{$doc_OID}) {
+	    print STDERR "WARNING: DateList::classify called multiple times for $doc_OID\n";
+	} 
+	$self->{'list'}->{$doc_OID} = $date;
+    }
+}
+
+1;
Index: /main/tags/2.25/niupepa/perllib/classify/NPepaList.pm
===================================================================
--- /main/tags/2.25/niupepa/perllib/classify/NPepaList.pm	(revision 21064)
+++ /main/tags/2.25/niupepa/perllib/classify/NPepaList.pm	(revision 21064)
@@ -0,0 +1,111 @@
+###########################################################################
+#
+# NpepaList.pm -- website plugin
+#
+# A component of the Greenstone digital library software
+# from the New Zealand Digital Library Project at the 
+# University of Waikato, New Zealand.
+#
+# Copyright (C) 1999 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.
+#
+###########################################################################
+
+# There should probably be a general classifier to do this kind of stuff
+
+package NPepaList;
+
+sub new {
+    my ($class, @options) = @_;
+
+    return bless {
+	'list'=>{},
+	'metaname' => 'Series',
+	'sortname' => 'Date'
+	}, $class;
+}
+
+sub init {
+    my $self = shift (@_);
+
+    $self->{'list'} = {};
+}
+
+
+sub classify {
+    my $self = shift (@_);
+    my ($doc_obj) = @_;
+
+    my $doc_OID = $doc_obj->get_OID();
+
+    # want to ignore abstracts
+    my $doctype = $doc_obj->get_metadata_element($doc_obj->get_top_section(), 'doctype');
+    return if (defined $doctype && $doctype eq 'Description');
+
+    my $date = $doc_obj->get_metadata_element($doc_obj->get_top_section(),
+					      $self->{'sortname'});
+    # commentaries have no date but we want them to sort to the top
+    $date = '00000000' unless defined $date;
+
+    my $series = $doc_obj->get_metadata_element ($doc_obj->get_top_section(),
+						 $self->{'metaname'});
+
+    if (defined $series) {
+	if (!defined $self->{'list'}->{$series}) {
+	    $self->{'list'}->{$series} = {};
+	}
+	if (defined $self->{'list'}->{$series}->{$doc_OID}) {
+	    print STDERR "WARNING: NPepaList::classify called multiple times for $doc_OID\n";
+	} 
+	$self->{'list'}->{$series}->{$doc_OID} = $date;
+    } else {
+	print STDERR "WARNING: NpepaList::classify $doc_OID has no Series metadata\n";
+    }
+}
+
+
+sub get_classify_info {
+    my $self = shift (@_);
+
+    my $classifyinfo = $self->get_entry ('Series', 'VList', 'Invisible');
+
+    foreach $series (sort keys %{$self->{'list'}}) {
+	my $cinfo = $self->get_entry ($series, 'VList');
+	foreach $OID (sort {$self->{'list'}->{$series}->{$a} 
+			    cmp $self->{'list'}->{$series}->{$b};} keys %{$self->{'list'}->{$series}}) {
+	    push (@{$cinfo->{'contains'}}, {'OID'=>$OID});
+	}
+	push (@{$classifyinfo->{'contains'}}, $cinfo);
+    }
+
+    return $classifyinfo;
+}
+
+sub get_entry {
+    my $self = shift (@_);
+    my ($title, $childtype, $thistype) = @_;
+    
+    # organise into classification structure
+    my %classifyinfo = ('childtype'=>$childtype,
+			'Title'=>$title,
+			'contains'=>[]);
+    $classifyinfo{'thistype'} = $thistype 
+	if defined $thistype && $thistype =~ /\w/;
+
+    return \%classifyinfo;
+}
+
+1;
Index: /main/tags/2.25/niupepa/perllib/plugins/NPPlug.pm
===================================================================
--- /main/tags/2.25/niupepa/perllib/plugins/NPPlug.pm	(revision 21064)
+++ /main/tags/2.25/niupepa/perllib/plugins/NPPlug.pm	(revision 21064)
@@ -0,0 +1,424 @@
+###########################################################################
+#
+# NPPlug.pm -- Plugin for the niupepa collection
+# A component of the Greenstone digital library software
+# from the New Zealand Digital Library Project at the 
+# University of Waikato, New Zealand.
+#
+# Copyright (C) 1999 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.
+#
+###########################################################################
+
+# The niupepa collection has a file structure as follows:
+# Each niupepa series has its own directory containing some/all 
+# of the following:
+
+# meta.txt - file contains metadata to be associated with all documents
+# in series.
+# *.issue - each issue should have a .issue file which may or may not
+# contain metadata to associate with the issue. also contains the list
+# of filenames that make up the issue (i.e. one for each page). meta.txt
+# is read before *.issue so metadata in .issue files will override that in
+# meta.txt
+# *.commentary - the commentary of the niupepa series (1 per series)
+# text/*.txt/htm - text/html files of issue pages (1 per page) -
+# text files are expected to be either .htm or .txt (lower case).
+# images/*.gif - image files of issue pages (1 per page)
+# abstracts/*.abstract - html files of issue abstracts (1 per issue) 
+
+
+package NPPlug;
+
+use BasPlug;
+use util;
+
+sub BEGIN {
+    @ISA = ('BasPlug');
+}
+
+use strict;
+
+sub print_usage {
+    print STDERR "\nIncorrect options passed to NPPlug, check your collect.cfg configuration file\n";
+
+    print STDERR "\n  usage: plugin NPPlug [options]\n\n";
+    print STDERR "  options:\n";
+    print STDERR "   -create_log            Creates a log file containing info about which portions\n";
+    print STDERR "                          of papers are missing\n";
+    print STDERR "   -logfile               Path of logfile (defaults to ./log.txt)\n\n";
+}
+
+sub new {
+    my ($class) = @_;
+    my $self = new BasPlug ();
+
+    if (!parsargv::parse(\@_, 
+			 q^create_log^, \$self->{'create_log'},
+			 q^logfile/.*/./log.txt^, \$self->{'logfile'})) {
+	&print_usage();
+	die "\n";
+    }
+
+    $self->{'commentaries'} = {};
+    $self->{'num_issues'} = 0;
+    $self->{'num_text_pages'} = 0;
+    $self->{'num_image_pages'} = 0;
+    $self->{'num_abstracts'} = 0;
+    return bless $self, $class;
+}
+
+sub is_recursive {
+    my $self = shift (@_);
+
+    return 0; # this is not a recursive plugin
+}
+
+sub begin {
+    my $self = shift (@_);
+    my ($pluginfo, $base_dir, $processor, $maxdocs) = @_;
+
+    # open up logfile
+    # note that we append to logfile as building will otherwise
+    # overwrite a file generated at import time
+    if ($self->{'create_log'}) {
+	open (LOGFILE, ">>$self->{'logfile'}") || die 
+	    "NPPlug.pm: Couldn't open log file $self->{'logfile'}\n";
+
+	my @time = localtime (time);
+
+	print LOGFILE "------------------------------------------------------------\n";
+	print LOGFILE "Log start $time[3]/$time[4]/" . (1900 + $time[5]) . "\n";
+	print LOGFILE "------------------------------------------------------------\n";
+    }
+}
+
+sub end {
+    my $self = shift (@_);
+
+    if ($self->{'create_log'}) {
+	my $numseries = 0;
+	my $numcommentaries = 0;
+
+	# record missing commentaries in logfile
+	foreach my $key (keys %{$self->{'commentaries'}}) {
+	    $numseries ++;
+	    if (!$self->{'commentaries'}->{$key}) {
+		print LOGFILE "Commentary missing for series $key\n";
+	    } else {
+		$numcommentaries ++;
+	    }
+	}
+	
+	print LOGFILE "\n\nStatistics:\n";
+	print LOGFILE "series: $numseries\n";
+	print LOGFILE "commentaries: $numcommentaries\n";
+	print LOGFILE "issues: $self->{'num_issues'}\n";
+	print LOGFILE "abstracts: $self->{'num_abstracts'}\n";
+	print LOGFILE "text pages: $self->{'num_text_pages'}\n";
+	print LOGFILE "image pages: $self->{'num_image_pages'}\n";
+
+	# close logfile
+	close LOGFILE;
+    }
+}
+
+# return number of files processed, undef if can't process
+# Note that $base_dir might be "" and that $file might 
+# include directories
+sub read {
+    my $self = shift (@_);
+    my ($pluginfo, $base_dir, $file, $metadata, $processor) = @_;
+
+    my $filename = &util::filename_cat($base_dir, $file);
+
+    # we don't want RecPlug to go recursing into the text, images or 
+    # abstracts directories
+    return 0 if (-d $filename && $filename =~ /(abstracts|images|text)/);
+
+    return 0 if $filename =~ /meta\.txt$/i;
+
+    return undef unless ($filename =~ /\.(issue|commentary)$/i && (-e $filename));
+
+    $self->{'verbosity'} = $processor->{'verbosity'};
+    print STDERR "NPPlug: processing $filename\n" if $self->{'verbosity'};
+
+    my ($dir);
+    ($dir, $file) = $filename =~ /^(.*?)([^\/\\]*)$/;
+    my ($issuekey) = $file =~ /^([^\.\_]*)/;
+
+    if ($filename =~ /\.commentary$/i) {
+	# commentary
+	return $self->process_commentary ($filename, $issuekey, $dir, $file, $processor);
+    }
+
+    my $numprocessed = 0;
+    $self->{'commentaries'}->{$issuekey} = 0 unless defined $self->{'commentaries'}->{$issuekey};
+
+    my ($abstractfile) = $file =~ /^([^\.]*)\.issue/i;
+    my $abstractOID = $abstractfile . "abstract";
+    $abstractfile .= ".abstract";
+    my $afile = &util::filename_cat($dir, "abstracts", $abstractfile);
+    my $hasabstract = 0;
+    if (-e $afile) {$hasabstract = 1;}
+    else {$abstractOID = undef;}
+
+    # process the .issue file
+    my %meta = ();
+    $numprocessed += $self->process_issue ($filename, $issuekey, $dir, $file, 
+					   $abstractOID, $processor, \%meta);
+
+    # process abstract of this issue
+    if ($hasabstract) {
+	$numprocessed += $self->process_abstract ($afile, $issuekey, $dir, 
+						  $abstractfile, $processor, \%meta);
+    }
+
+    return $numprocessed;
+}
+
+sub process_issue {
+    my $self = shift (@_);
+    my ($filename, $issuekey, $dir, $file, $abstract, $processor, $meta) = @_;
+
+    $self->{'num_issues'} ++;
+    my $doc_obj = new doc ($file, "indexed_doc");
+    my $topsection = $doc_obj->get_top_section();
+    my $cursection = $topsection;
+    $self->associate_cover_images ($doc_obj, $dir, $issuekey);
+    $doc_obj->set_metadata_element ($topsection, 'Title', $self->get_title_string($file));
+    $doc_obj->set_metadata_element ($topsection, 'abstract', $abstract) if defined $abstract;
+    $self->set_main_metadata ($doc_obj, $dir);
+
+    open (ISSUEFILE, $filename) || die "couldn't open $filename\n";
+    my $line = "";
+    while (defined ($line = <ISSUEFILE>)) {
+	next unless $line =~ /\w/;
+	chomp $line;
+	if ($line =~ /^<([^>]*)>(.*?)\s*$/) {
+	    $doc_obj->set_metadata_element ($topsection, $1, $2);
+	    $meta->{$1} = $2;
+	} else {
+	    # should be a section name
+	    $line =~ s/^\s+//;
+	    $line =~ s/\s+$//;
+	    $cursection = $doc_obj->insert_section($doc_obj->get_end_child($topsection));
+	    my ($pagenum) = $line =~ /(\d+)$/;
+	    $doc_obj->set_metadata_element($cursection, 'Title', $pagenum);
+	    $self->process_text ($dir, $line, $doc_obj, $cursection);
+	    $self->process_images ($dir, $line, $doc_obj, $cursection);
+	}
+    }
+    $file =~ s/\.issue//i;
+    $doc_obj->set_OID ($file);
+    $processor->process ($doc_obj);
+    return 1;
+}
+
+sub process_images {
+    my $self = shift (@_);
+    my ($dir, $page, $doc_obj, $cursection) = @_;
+
+    my $filename = &util::filename_cat ($dir, "images", $page);
+
+    if (-e "$filename.gif") {
+	$self->{'num_image_pages'} ++;
+	$doc_obj->set_metadata_element ($cursection, "hasimg", "1");
+	$doc_obj->set_metadata_element ($cursection, "Source", $page);
+	$doc_obj->associate_file("$filename.gif", "$page.gif", "image/gif");	
+    } elsif ($self->{'create_log'}) {
+	$doc_obj->set_metadata_element ($cursection, "hasimg", "0");
+	print LOGFILE "no fullsize image file for $page\n";
+    }
+
+    if (-e "${filename}_p.gif") {
+	$doc_obj->set_metadata_element ($cursection, "hasprevimg", "1");
+	$doc_obj->set_metadata_element ($cursection, "Source", $page);
+	$doc_obj->associate_file("${filename}_p.gif", "${page}_p.gif", "image/gif");	
+    } elsif ($self->{'create_log'}) {
+	$doc_obj->set_metadata_element ($cursection, "hasprevimg", "0");
+	print LOGFILE "no preview image file for $page\n";
+    }
+}
+
+sub process_text {
+    my $self = shift (@_);
+    my ($dir, $page, $doc_obj, $cursection) = @_;
+    my ($text);
+
+    my $filename = &util::filename_cat ($dir, "text", $page);
+    if (-e "$filename.htm") {
+	$text = $self->get_text ("$filename.htm");
+    } elsif (-e "$filename.txt") {
+	$text = $self->get_text ("$filename.txt");
+    }
+
+    if (defined $text) {
+	$self->{'num_text_pages'} ++;
+	$doc_obj->add_text ($cursection, $text);
+    } elsif ($self->{'create_log'}) {
+	print LOGFILE "no txt or htm file for $page\n";
+    }
+}
+
+sub process_abstract {
+    my $self = shift (@_);
+    my ($filename, $issuekey, $dir, $file, $processor, $meta) = @_;
+
+    my $text = $self->get_text ($filename);
+    if (defined $text) {
+	# remove html header and stuff (assumes all future abstracts
+	# are same format as those for niupepa 01)
+	$text =~ s/^.*?<b>.*?<\/b>//is;
+	
+	$self->{'num_abstracts'} ++;
+	my $doc_obj = new doc ($file, "indexed_doc");
+	my $cursection = $doc_obj->get_top_section();
+	$self->associate_cover_images ($doc_obj, $dir, $issuekey);
+	$doc_obj->set_metadata_element ($cursection, 'Title', "_abstract_ " . 
+					$self->get_title_string($file));
+	$self->set_main_metadata ($doc_obj, $dir);
+	map { $doc_obj->set_metadata_element ($cursection, $_, $meta->{$_}); } keys %$meta;
+	$doc_obj->set_metadata_element ($cursection, "doctype", "Description");
+	$doc_obj->add_text ($cursection, $text);
+	$file =~ s/\.abstract//i;
+	$doc_obj->set_OID ($file . "abstract");
+	$processor->process ($doc_obj);
+	return 1;
+    }
+
+    if ($self->{'create_log'}) {
+	print LOGFILE "abstract file $filename doesn't exist\n";
+    }
+    return 0;
+}
+
+sub process_commentary { 
+    my $self = shift (@_);
+    my ($filename, $issuekey, $dir, $file, $processor) = @_;
+
+    my $text = $self->get_text ($filename);
+
+    return 0 unless defined $text;
+
+    $self->{'commentaries'}->{$issuekey} = 1;
+    my $doc_obj = new doc ($file, "indexed_doc");
+    my $cursection = $doc_obj->get_top_section();
+    $self->associate_cover_images ($doc_obj, $dir, $issuekey);
+    $doc_obj->set_metadata_element ($cursection, 'Title', "_commentary_");
+    $self->set_main_metadata ($doc_obj, $dir);
+    $doc_obj->set_metadata_element ($cursection, "doctype", "Commentary");
+    $doc_obj->add_text ($cursection, $text);
+    $doc_obj->set_OID ($issuekey . "commentary");
+    $processor->process ($doc_obj);
+    return 1;
+}
+
+sub associate_cover_images {
+    my $self = shift (@_);
+    my ($doc_obj, $dir, $issuekey) = @_;
+
+    my $cover = &util::filename_cat ($dir, $issuekey);
+    $doc_obj->associate_file("${cover}on.gif", "${issuekey}/coveron.gif", "image/gif");
+    $doc_obj->associate_file("${cover}of.gif", "${issuekey}/coverof.gif", "image/gif");
+}
+
+# reads in the meta.txt file and sets metadata
+sub set_main_metadata {
+    my $self = shift (@_);
+    my ($doc_obj, $dir) = @_;
+
+    my $metafile = &util::filename_cat ($dir, "meta.txt");
+    return unless (-e $metafile);
+
+    if (!open (METAFILE, $metafile)) {
+	print STDERR "NPPlug: Couldn't read $metafile\n" if $self->{'verbosity'};
+	return;
+    }
+
+    my $cursection = $doc_obj->get_top_section();
+    my $line = "";
+    while (defined ($line = <METAFILE>)) {
+	next unless $line =~ /\w/;
+	chomp $line;
+	if ($line =~ /<([^>]*)>(.*)$/) {
+	    # note we're using set_metadata_element (not add_metadata_element)
+	    # this will override any previously set metadata of the same name
+	    $doc_obj->set_metadata_element ($cursection, $1, $2);
+	} elsif ($self->{'verbosity'}) {
+	    print STDERR "NPPlug: Badly formatted line in $metafile\n";
+	    print STDERR "meta.txt lines should be formatted '<metaname>metavalue'\n";
+	}
+    }
+}
+
+sub get_text {
+    my $self = shift (@_);
+    my ($filename) = @_;
+
+    if (open (FILE, $filename)) {
+	my $text = "";
+	my $line = "";
+	if ($filename =~ /\.(htm|commentary|abstract)$/i) {
+	    my $savedtext = "";
+	    my $foundbody = 0;
+	    while (defined ($line = <FILE>)) {
+		if ($line =~ s/.*?<body[^>]*>//i) {
+		    $foundbody = 1;
+		}
+		$line =~ s/(<\/?html[^>]*>|<\/?head[^>]*>|<\/p>|<\/?font[^>]*>|<\/?body[^>]*>)//ig;
+		if ($foundbody) {
+		    $text .= $line; 
+		} else {
+		    $savedtext .= $line;
+		}
+	    }
+	    close FILE;
+	    if ($foundbody) {return $text;}
+	    else {return $savedtext;}
+
+	} else {
+	    while (defined ($line = <FILE>)) {
+		$line = "<p>\n" unless $line =~ /\w/;
+		$text .= $line;
+	    }
+	    close FILE;
+	    return $text;
+	}
+
+    } else {
+	print STDERR "NPPlug: Warning: get_text() couldn't open $filename\n" 
+	    if $self->{'verbosity'};
+	return undef;
+    }
+}
+
+sub get_title_string {
+    my $self = shift (@_);
+    my ($filename) = @_;
+
+    $filename =~ s/\.(issue|abstract)$//i;
+    my ($series, $vol, $num) = split /\_/, $filename;
+    my $title = "";
+    $title .= "_vol_ $vol" if defined $vol && $vol =~ /\w/;
+    if (defined $num && $num =~ /\w/) {
+	$title .= ": " if defined $vol && $vol =~ /\w/;
+	$title .= "_num_ $num";
+    }
+    return $title;
+}
+
+1;
Index: /main/tags/2.25/niupepa/src/recpt/Makefile.in
===================================================================
--- /main/tags/2.25/niupepa/src/recpt/Makefile.in	(revision 21064)
+++ /main/tags/2.25/niupepa/src/recpt/Makefile.in	(revision 21064)
@@ -0,0 +1,159 @@
+###########################################################################
+#
+# Makefile -- Makefile for niupepalibrary
+# A component of the Greenstone digital library software
+# from the New Zealand Digital Library Project at the 
+# University of Waikato, New Zealand.
+#
+# Copyright (C) 1999 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.
+#
+###########################################################################
+
+GD = ../../../..
+MAINRECPTDIR = $(GD)/src/recpt
+MAINCOLSERVRDIR = $(GD)/src/colservr
+
+
+AR = ar
+CC = @CC@
+CCFLAGS = @CFLAGS@ -Wall -Wunused -pedantic -W -Woverloaded-virtual
+DEFS = -DNZDL -DQUIET -DSHORT_SUFFIX -DPARADOCNUM -DGSDLSERVER @DEFS@
+
+USE_FASTCGI = @USE_FASTCGI@
+ifneq ($(USE_FASTCGI), 1)
+INCLUDES = -I$(MAINRECPTDIR) -I$(MAINCOLSERVRDIR) -I$(GD)/lib \
+	   -I$(GD)/packages/mg -I$(GD)/packages/mg/lib -I$(GD)/packages/mg/src/text 
+else
+INCLUDES = -I$(MAINRECPTDIR) -I$(MAINCOLSERVRDIR) -I$(GD)/lib \
+	   -I$(GD)/packages/mg -I$(GD)/packages/mg/lib -I$(GD)/packages/mg/src/text \
+           -I$(GD)/packages/fcgi/include
+endif
+
+RANLIB = @RANLIB@
+LDFLAGS = @LDFLAGS@
+LIBS = @LIBS@
+
+GSDLOS = @gsdlos@
+
+
+COMPILE = $(CC) -c $(CCFLAGS) $(DEFS) $(INCLUDES)
+LINK = $(CC) $(LDFLAGS) -o $@
+
+.SUFFIXES:
+.SUFFIXES: .c .o
+.c.o:
+	$(COMPILE) $<
+
+.SUFFIXES: .cpp .o
+.cpp.o:
+	$(COMPILE) $< 
+
+
+HEADERS = niupepadocaction.h niupepapagedbrowserclass.h \
+	  niupepabrowsetools.h niupepavlistbrowserclass.h \
+	  niupepahlistbrowserclass.h
+
+SOURCES = niupepalibrarymain.cpp niupepadocaction.cpp \
+	  niupepapagedbrowserclass.cpp niupepabrowsetools.cpp \
+	  niupepavlistbrowserclass.cpp niupepahlistbrowserclass.cpp
+
+OBJECTS = niupepalibrarymain.o niupepadocaction.o \
+	  niupepapagedbrowserclass.o niupepabrowsetools.o \
+	  niupepavlistbrowserclass.o niupepahlistbrowserclass.o
+
+EXEC    = niupepalibrary
+
+all : $(EXEC)
+
+install: $(EXEC)
+	install -m 755 -s $(EXEC) $(GD)/cgi-bin/$(EXEC)
+
+distclean:
+	rm -f $(OBJECTS) $(EXEC) Makefile
+
+clean:
+	rm -f $(OBJECTS) $(EXEC)
+
+depend:
+	makedepend -Y -- $(DEFS) $(INCLUDES) $(CCFLAGS) -- $(SOURCES)
+
+
+# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
+
+
+NIUPEPALIBRARY_OBJS = $(OBJECTS) \
+    $(MAINRECPTDIR)/querytools.o \
+    $(MAINRECPTDIR)/browsetools.o \
+    $(MAINRECPTDIR)/browserclass.o \
+    $(MAINRECPTDIR)/vlistbrowserclass.o \
+    $(MAINRECPTDIR)/hlistbrowserclass.o \
+    $(MAINRECPTDIR)/datelistbrowserclass.o \
+    $(MAINRECPTDIR)/invbrowserclass.o \
+    $(MAINRECPTDIR)/pagedbrowserclass.o \
+    $(MAINRECPTDIR)/htmlbrowserclass.o \
+    $(MAINRECPTDIR)/receptionist.o \
+    $(MAINRECPTDIR)/recptconfig.o \
+    $(MAINRECPTDIR)/cgiwrapper.o \
+    $(MAINRECPTDIR)/cgiargs.o \
+    $(MAINRECPTDIR)/action.o \
+    $(MAINRECPTDIR)/converter.o \
+    $(MAINRECPTDIR)/cgiutils.o \
+    $(MAINRECPTDIR)/OIDtools.o \
+    $(MAINRECPTDIR)/htmlgen.o \
+    $(MAINRECPTDIR)/statusaction.o \
+    $(MAINRECPTDIR)/pageaction.o \
+    $(MAINRECPTDIR)/comtypes.o \
+    $(MAINRECPTDIR)/recptproto.o \
+    $(MAINRECPTDIR)/pingaction.o \
+    $(MAINRECPTDIR)/queryaction.o \
+    $(MAINRECPTDIR)/documentaction.o \
+    $(MAINRECPTDIR)/htmlutils.o \
+    $(MAINRECPTDIR)/nullproto.o \
+    $(MAINRECPTDIR)/infodbclass.o \
+    $(MAINRECPTDIR)/formattools.o \
+    $(MAINRECPTDIR)/tipaction.o \
+    $(MAINRECPTDIR)/authenaction.o \
+    $(MAINRECPTDIR)/usersaction.o \
+    $(MAINRECPTDIR)/userdb.o \
+    $(MAINRECPTDIR)/delhistoryaction.o \
+    $(MAINRECPTDIR)/historydb.o \
+    $(MAINCOLSERVRDIR)/mgq.o \
+    $(MAINCOLSERVRDIR)/querycache.o \
+    $(MAINCOLSERVRDIR)/queryinfo.o \
+    $(MAINCOLSERVRDIR)/collectserver.o \
+    $(MAINCOLSERVRDIR)/colservrconfig.o \
+    $(MAINCOLSERVRDIR)/maptools.o \
+    $(MAINCOLSERVRDIR)/filter.o \
+    $(MAINCOLSERVRDIR)/source.o \
+    $(MAINCOLSERVRDIR)/browsefilter.o \
+    $(MAINCOLSERVRDIR)/queryfilter.o \
+    $(MAINCOLSERVRDIR)/phrasequeryfilter.o \
+    $(MAINCOLSERVRDIR)/phrasesearch.o \
+    $(MAINCOLSERVRDIR)/mggdbmsource.o \
+    $(MAINCOLSERVRDIR)/mgsearch.o \
+    $(GD)/lib/gsdllib.a  \
+    $(GD)/packages/mg/src/text/libtextin.a \
+    $(GD)/packages/mg/lib/libmg.a
+
+ifneq ($(USE_FASTCGI), 1)
+NIUPEPALIB_OBJS = $(NIUPEPALIBRARY_OBJS)
+else
+NIUPEPALIB_OBJS = $(NIUPEPALIBRARY_OBJS) $(GD)/packages/fcgi/libfcgi/libfcgi.a
+endif
+
+niupepalibrary: $(NIUPEPALIB_OBJS)
+	$(LINK) $(NIUPEPALIB_OBJS) $(LIBS) 
Index: /main/tags/2.25/niupepa/src/recpt/niupepabrowsetools.cpp
===================================================================
--- /main/tags/2.25/niupepa/src/recpt/niupepabrowsetools.cpp	(revision 21064)
+++ /main/tags/2.25/niupepa/src/recpt/niupepabrowsetools.cpp	(revision 21064)
@@ -0,0 +1,186 @@
+/**********************************************************************
+ *
+ * niupepabrowsetools.cpp -- 
+ * Copyright (C) 1999  The New Zealand Digital Library Project
+ *
+ * A component of the Greenstone digital library software
+ * from the New Zealand Digital Library Project at the
+ * University of Waikato, New Zealand.
+ *
+ * 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.
+ *
+ * $Id$
+ *
+ *********************************************************************/
+
+#include "niupepabrowsetools.h"
+#include "OIDtools.h"
+#include "cgiutils.h"
+#include "browsetools.h"
+
+static void output_niupepa_controls (cgiargsclass &args, const text_tarray &ibuttons, 
+				     recptproto *collectproto, displayclass &disp,
+				     outconvertclass &outconvert, ostream &textout, 
+				     ostream &logout) {
+
+  bool hastxt = false, hasimg = false, hasprevimg = false;
+  text_tarray buttons;
+  text_t &arg_gg = args["gg"];
+  text_t &arg_d = args["d"];
+  FilterResponse_t response;
+  text_tset metadata;
+  text_t doctype;
+  metadata.insert ("hastxt");
+  metadata.insert ("hasimg");
+  metadata.insert ("hasprevimg");
+  metadata.insert ("doctype");
+  if (!get_info (arg_d, args["c"], metadata, false, collectproto, response, logout))
+    return;
+
+  if (response.docInfo[0].metadata["hastxt"].values[0] == "1") hastxt = true;
+  if (response.docInfo[0].metadata["hasimg"].values[0] == "1") hasimg = true;
+  if (response.docInfo[0].metadata["hasprevimg"].values[0] == "1") hasprevimg = true;
+
+  MetadataInfo_tmap::iterator it = response.docInfo[0].metadata.find ("doctype");
+  if (it != response.docInfo[0].metadata.end()) {
+    if (! (*it).second.values.empty()) doctype = (*it).second.values[0];
+  }
+
+  if (doctype == "Description") {
+    // abstract
+    text_t paper = substr (arg_d.begin(), (arg_d.end() - 8));
+    buttons.push_back ("_document:imageviewpaper_(" + paper + ")");
+    buttons.push_back ("_document:imageabstractintro_");
+
+  } else if (doctype == "Commentary") {
+    // commentary
+
+
+  } else {
+    // newspaper page
+
+    if (arg_gg == "full") {
+      if (hastxt) buttons.push_back ("_document:imageviewtext_");
+      if (hasprevimg) buttons.push_back ("_document:imageprevimage_");
+    } else if (arg_gg == "prev") {
+      if (hastxt) buttons.push_back ("_document:imageviewtext_");
+      if (hasimg) buttons.push_back ("_document:imagefullimage_");
+    } else {
+      if (hasimg) buttons.push_back ("_document:imagefullimage_");
+      if (hasprevimg) buttons.push_back ("_document:imageprevimage_");
+    }
+
+    // see if paper has an abstract
+    text_t abstract;
+    get_top (arg_d, abstract);
+    abstract += "abstract";
+    metadata.erase (metadata.begin(), metadata.end());
+    if (get_info (abstract, args["c"], metadata, false, collectproto, response, logout))
+      buttons.push_back ("_document:imageviewabstract_(" + abstract + "&gg=text)");
+  } 
+
+  if (args["u"] != "1") {
+
+    text_tarray::const_iterator here = ibuttons.begin();
+    text_tarray::const_iterator end = ibuttons.end();
+    
+    while (here != end) {
+      
+      if (*here == "Detach")
+	buttons.push_back ("_document:imagedetach_");
+      else if (*here == "Highlight" && arg_gg == "text") {
+	if (args["hl"] == "1") 
+	  buttons.push_back ("_document:imagenohighlight_");
+	else 
+	  buttons.push_back ("_document:imagehighlight_");
+	
+      } else if ((*here == "Expand Text") && (doctype.empty()) && (arg_gg == "text")) {
+	if (args.getintarg("gt"))
+	  buttons.push_back ("_document:imagecontracttext_");
+	else 
+	  buttons.push_back ("_document:imageexpandtext_");
+      }
+      here ++;
+    }
+    
+    here = buttons.begin();
+    end = buttons.end();
+    int count = 0;
+    while (here != end) {
+      if ((count != 0) && ((count % 3) == 0)) textout << "<br>\n";
+      textout << outconvert << disp << *here;
+      count ++;
+      here ++;
+    }
+  }
+}
+
+
+
+void output_niupepa_toc (cgiargsclass &args, browsermapclass *browsermap,
+			 formatinfo_t &formatinfo, recptproto *collectproto,
+			 displayclass &disp, outconvertclass &outconvert,
+			 ostream &textout, ostream &logout) {
+
+  int tabcount = 0;
+  text_t &arg_d = args["d"];
+  
+  // get the cover image (if there is one) and the control buttons
+  // if we're inside a book
+  if (!arg_d.empty()) {
+    textout << outconvert << disp 
+	    << "<center>\n"
+	    << "<p><table cellpadding=0 cellspacing=0 width=_pagewidth_><tr>\n"
+	    << "<td align=left valign=top>\n";
+    output_titles (args, collectproto, formatinfo, disp, outconvert, textout, logout);
+    textout << "<p>\n";
+  }
+
+  if (formatinfo.DocumentContents || arg_d.empty()) {
+    if (args.getintarg("gc") == 1) {
+      
+      // expanded table of contents
+      expanded_contents (args, tabcount, false, browsermap, formatinfo, 
+			 collectproto, disp, outconvert, textout, logout);
+    } else {
+      
+      // contracted table of contents
+      contracted_contents (args, tabcount, false, browsermap, formatinfo, 
+			   collectproto, disp, outconvert, textout, logout);
+    }
+  }
+
+  if (!arg_d.empty()) {
+    output_niupepa_controls (args, formatinfo.DocumentButtons, collectproto, 
+			     disp, outconvert, textout, logout);
+
+    textout << outconvert << disp
+	    << "</td>\n"
+	    << "<td align=right valign=top>"
+	    << "_document:imagethispaper_\n"
+	    << "</td></tr>\n"
+	    << "</table>\n"
+	    << "</center>\n";
+  }
+  textout << outconvert << disp << "_iconblankbar_\n";
+}
+
+
+
+
+
+
+
+
Index: /main/tags/2.25/niupepa/src/recpt/niupepabrowsetools.h
===================================================================
--- /main/tags/2.25/niupepa/src/recpt/niupepabrowsetools.h	(revision 21064)
+++ /main/tags/2.25/niupepa/src/recpt/niupepabrowsetools.h	(revision 21064)
@@ -0,0 +1,45 @@
+/**********************************************************************
+ *
+ * niupepabrowsetools.h -- 
+ * Copyright (C) 1999  The New Zealand Digital Library Project
+ *
+ * A component of the Greenstone digital library software
+ * from the New Zealand Digital Library Project at the
+ * University of Waikato, New Zealand.
+ *
+ * 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.
+ *
+ * $Id$
+ *
+ *********************************************************************/
+
+
+#ifndef NIUPEPABROWSETOOLS_H
+#define NIUPEPABROWSETOOLS_H
+
+#include "gsdlconf.h"
+#include "text_t.h"
+#include "cgiargs.h"
+#include "display.h"
+#include "recptproto.h"
+#include "formattools.h"
+#include "browsetools.h"
+
+void output_niupepa_toc (cgiargsclass &args, browsermapclass *browsermap,
+			 formatinfo_t &formatinfo, recptproto *collectproto,
+			 displayclass &disp, outconvertclass &outconvert,
+			 ostream &textout, ostream &logout);
+#endif
+
Index: /main/tags/2.25/niupepa/src/recpt/niupepadocaction.cpp
===================================================================
--- /main/tags/2.25/niupepa/src/recpt/niupepadocaction.cpp	(revision 21064)
+++ /main/tags/2.25/niupepa/src/recpt/niupepadocaction.cpp	(revision 21064)
@@ -0,0 +1,281 @@
+/**********************************************************************
+ *
+ * niupepadocaction.cpp -- 
+ * A component of the Greenstone digital library software
+ * from the New Zealand Digital Library Project at the
+ * University of Waikato, New Zealand.
+ *
+ * Copyright (C) 1999  The 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.
+ *
+ * $Id$
+ *
+ *********************************************************************/
+
+/*
+   $Log$
+   Revision 1.1  2000/03/08 20:44:50  sjboddie
+   Initial revision
+
+   Revision 1.2  1999/09/07 22:19:50  sjboddie
+   added GPL header
+
+   Revision 1.1  1999/08/29 23:35:07  sjboddie
+   niupepa receptionist
+
+ */
+
+
+#include <string.h>
+#include "niupepadocaction.h"
+#include "niupepabrowsetools.h"
+#include "OIDtools.h"
+#include "querytools.h"
+#include "unitool.h"
+
+niupepadocaction::niupepadocaction () {
+  // this action uses cgi variable "gg" as well as
+  // those used by the standard documentaction
+
+  cgiarginfo arg_ainfo;
+
+  // in this action "gg" is the format of the
+  // document to view (i.e. "text", "prev" or "full")
+  arg_ainfo.shortname = "gg";
+  arg_ainfo.longname = "document format";
+  arg_ainfo.multiplechar = true;
+  arg_ainfo.defaultstatus = cgiarginfo::weak;
+  arg_ainfo.argdefault = "text";
+  arg_ainfo.savedarginfo = cgiarginfo::must;
+  argsinfo.addarginfo (NULL, arg_ainfo);
+}
+
+niupepadocaction::~niupepadocaction () {
+}
+
+void niupepadocaction::set_java_macros (cgiargsclass &args, displayclass &disp) {
+
+  text_t javaimagescontent = "_javaextras__javacommentary__javaviewabstract__javaviewpaper__javaabstractintro_";
+
+  text_t &arg_gg = args["gg"];
+
+  if (arg_gg == "full")
+    javaimagescontent += "_javaprevimage__javaviewtext_";
+  else if (arg_gg == "prev")
+    javaimagescontent += "_javafullimage__javaviewtext_";
+  else 
+    javaimagescontent += "_javafullimage__javaprevimage_";
+
+	
+  int arg_gt = args.getintarg("gt");
+  int arg_hl = args.getintarg("hl");
+
+  text_tarray::const_iterator button_here = formatinfo.DocumentButtons.begin();
+  text_tarray::const_iterator button_end = formatinfo.DocumentButtons.end();
+
+  while (button_here != button_end) {
+    if (*button_here == "Detach") 
+      javaimagescontent += "_javadetach_";
+    else if (*button_here == "Expand Text" && arg_gg == "text") {
+      if (arg_gt == 1)
+	javaimagescontent += "_javacontracttext__javacontinue_";
+      else if (arg_gt == 2)
+	javaimagescontent += "_javacontracttext_";
+      else
+	javaimagescontent += "_javaexpandtext_";
+    } else if (*button_here == "Highlight" && arg_gg == "text") {
+      if (arg_hl == 1)
+	javaimagescontent += "_javanohighlighting_";
+      else 
+	javaimagescontent += "_javahighlighting_";
+    }
+    button_here ++;
+  }
+  disp.setmacro ("javaimagescontent", "document", javaimagescontent);
+}
+
+// define all the macros which are related to pages generated
+// by this action. we also load up the formatinfo structure 
+// here (it's used in do_action as well as here)
+void niupepadocaction::define_internal_macros (displayclass &disp, cgiargsclass &args,
+					       recptprotolistclass *protos, ostream &logout) {
+
+
+  // define_internal_macros sets the following macros (as well as those defined
+  // by documentaction::define_internal_macros)
+
+  // _httpthiscommentary_   the link to the papers commentary
+
+  // _httpiconthispaper_    the http address of the cover image
+  
+  // _thispapericonwidth_   the width and height of the cover image
+  // _thispapericonheight_ 
+
+
+  documentaction::define_internal_macros (disp, args, protos, logout);
+
+  text_t &arg_d = args["d"];
+  text_t &collection = args["c"];
+  text_tset metadata;
+  FilterResponse_t response;
+
+  recptproto *collectproto = protos->getrecptproto (collection, logout);
+  if (collectproto == NULL) return;
+
+  if (!arg_d.empty()) {
+    // we're at document level
+
+    text_t series = substr (arg_d.begin(), findchar (arg_d.begin(), arg_d.end(), '_'));
+    if ((series.size() > 10) && (substr ((series.end()-10), series.end()) == "commentary")) {
+      series = substr (series.begin(), (series.end()-10));
+    } else {
+      text_t commentaryOID = series + "commentary";
+
+      // set _httpthiscommentary_ if commentary exists
+      if (get_info (commentaryOID, collection, metadata, false, collectproto, response, logout))
+	disp.setmacro ("httpthiscommentary", "document", "_httpdocument_&gg=text&d=" + commentaryOID);
+    }
+    // _httpiconthispaper_
+    disp.setmacro ("httpiconthispaper", "document", "_httpcollimg_/" + series + "/cover");
+
+    // _thispapericonwidth_ and _thispapericonheight_
+    disp.setmacro ("thispapericonwidth", "document", "_" + series + "width_");
+    disp.setmacro ("thispapericonheight", "document", "_" + series + "height_");
+  }
+}
+
+void niupepadocaction::output_document (const text_t &OID, cgiargsclass &args, 
+					recptproto *collectproto, displayclass &disp, 
+					outconvertclass &outconvert, ostream &textout, 
+					ostream &logout) {
+  FilterResponse_t response;
+  text_tset metadata;
+  text_t &arg_gg = args["gg"];
+  text_t &collection = args["c"];
+
+  if (arg_gg == "full") {
+    
+    // fullsize image
+
+    metadata.insert ("hasimg");
+    metadata.insert ("Source");
+    if (!get_info (OID, collection, metadata, false, collectproto, response, logout))
+      return;
+    if (response.docInfo[0].metadata["hasimg"].values[0] == "1") {
+      textout << outconvert << disp 
+	      << "<p><img src=\"_httpcollimg_/_thisOID_/" 
+	      << response.docInfo[0].metadata["Source"].values[0] << ".gif\">\n";
+    } else {
+      textout << outconvert << disp << "_missingimage_\n";
+    }
+
+  } else if (arg_gg == "prev") {
+
+    // preview image
+
+    metadata.insert ("hasprevimg");
+    metadata.insert ("Source");
+    if (!get_info (OID, collection, metadata, false, collectproto, response, logout))
+      return;
+    if (response.docInfo[0].metadata["hasprevimg"].values[0] == "1") {
+      textout << outconvert << disp 
+	      << "<center>\n"
+	      << "<p><img src=\"_httpcollimg_/_thisOID_/" 
+	      << response.docInfo[0].metadata["Source"].values[0] << "_p.gif\">\n"
+	      << "</center>\n";
+    } else {
+      textout << outconvert << disp << "_missingimage_\n";
+    }
+  } else {
+
+    // text
+    metadata.insert ("hastxt");
+    if (!get_info (OID, collection, metadata, false, collectproto, response, logout))
+      return;
+    if (response.docInfo[0].metadata["hastxt"].values[0] == "1") {
+      documentaction::output_document (OID, args, collectproto, disp, 
+				       outconvert, textout, logout);
+    } else {
+      textout << outconvert << disp << "_missingtext_\n";
+    }
+  }
+}
+
+
+// this is only overridden so we can call output_niupepa_toc instead
+// of output_toc -- we should find a tidier way to do this both here
+// and in the cstr collection
+bool niupepadocaction::do_action (cgiargsclass &args, recptprotolistclass *protos, 
+				  browsermapclass *browsers, displayclass &disp, 
+				  outconvertclass &outconvert, ostream &textout, 
+				  ostream &logout) {
+
+
+  // must have a valid collection server
+  recptproto *collectproto = protos->getrecptproto (args["c"], logout);
+  if (collectproto == NULL) {
+    logout << "documentaction::do_action called with NULL collectproto\n";
+    textout << outconvert << disp << "_document:header_\n" 
+	    << "Error: Attempt to get document without setting collection\n"
+	    << "_document:footer_\n";
+  } else {  
+    
+    text_t OID = args["d"];
+    if (OID.empty()) OID = args["cl"];
+    if (OID.empty()) {
+      textout << outconvert << disp << "Document contains no data_document:footer_\n";
+      return true;
+    }
+
+    if (formatinfo.DocumentUseHTML) {
+      
+      if (!args["d"].empty()) {
+	if (args["f"] == "1") {
+	  textout << outconvert << disp 
+		  << "<html><head></head>\n"
+		  << "<frameset rows=\"68,*\" noresize border=0>\n"
+		  << "<frame scrolling=no frameborder=0 src=\"_gwcgi_?e=_compressedoptions_&a=p&p=nav\">\n"
+		  << "<frame name=\"documenttop\" frameborder=0 src=\"_gwcgi_?e=_compressedoptions_&a=d&d=" 
+		  << args["d"] << "\">"
+		  << "<noframes>\n"
+		  << "<p>You must have a frame enabled browser to view this.</p>\n"
+		  << "</noframes>\n"
+		  << "</frameset>\n"
+		  << "</html>\n";
+	} else {
+	  output_document (OID, args, collectproto, disp, outconvert, textout, logout);	
+	}
+	return true;
+      }
+    }
+
+    textout << outconvert << disp << "_document:header_\n"
+	    << "_document:content_\n";
+      
+    // output the table of contents
+    output_niupepa_toc (args, browsers, formatinfo, collectproto, 
+			disp, outconvert, textout, logout);
+    
+    // output the document text
+    if (!args["d"].empty()) {
+      textout << "<p>\n";
+      output_document (OID, args, collectproto, disp, outconvert, textout, logout);
+    }
+
+    textout << outconvert << disp << "_document:footer_\n";
+  }
+  return true;
+}
Index: /main/tags/2.25/niupepa/src/recpt/niupepadocaction.h
===================================================================
--- /main/tags/2.25/niupepa/src/recpt/niupepadocaction.h	(revision 21064)
+++ /main/tags/2.25/niupepa/src/recpt/niupepadocaction.h	(revision 21064)
@@ -0,0 +1,62 @@
+/**********************************************************************
+ *
+ * niupepadocaction.h -- 
+ * A component of the Greenstone digital library software
+ * from the New Zealand Digital Library Project at the
+ * University of Waikato, New Zealand.
+ *
+ * Copyright (C) 1999  The 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.
+ *
+ * $Id$
+ *
+ *********************************************************************/
+
+
+#ifndef NIUPEPADOCACTION_H
+#define NIUPEPADOCACTION_H
+
+#include "documentaction.h"
+
+class niupepadocaction : public documentaction {
+
+protected:
+
+  void set_java_macros (cgiargsclass &args, displayclass &disp);
+
+  void output_document (const text_t &OID, cgiargsclass &args, 
+  			recptproto *collectproto, displayclass &disp, 
+  			outconvertclass &outconvert, ostream &textout, 
+  			ostream &logout);
+
+public:
+  niupepadocaction ();
+  virtual ~niupepadocaction ();
+
+  bool do_action (cgiargsclass &args, recptprotolistclass *protos, 
+		  browsermapclass *browsers, displayclass &disp, 
+		  outconvertclass &outconvert, ostream &textout, 
+		  ostream &logout);
+  
+  void define_internal_macros (displayclass &disp, cgiargsclass &args,
+			       recptprotolistclass *protos, ostream &logout);
+};
+
+
+
+#endif
+
+
Index: /main/tags/2.25/niupepa/src/recpt/niupepahlistbrowserclass.cpp
===================================================================
--- /main/tags/2.25/niupepa/src/recpt/niupepahlistbrowserclass.cpp	(revision 21064)
+++ /main/tags/2.25/niupepa/src/recpt/niupepahlistbrowserclass.cpp	(revision 21064)
@@ -0,0 +1,129 @@
+/**********************************************************************
+ *
+ * niupepahlistbrowserclass.cpp -- 
+ * Copyright (C) 1999  The New Zealand Digital Library Project
+ *
+ * A component of the Greenstone digital library software
+ * from the New Zealand Digital Library Project at the
+ * University of Waikato, New Zealand.
+ *
+ * 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.
+ *
+ * $Id$
+ *
+ *********************************************************************/
+
+/*
+   $Log$
+   Revision 1.2  2000/03/22 02:00:13  nzdl
+   updated niupepa collection
+
+   Revision 1.1.1.1  2000/03/08 20:44:50  sjboddie
+   added niupepa to CVS
+
+
+ */
+
+
+#include "niupepahlistbrowserclass.h"
+#include <assert.h>
+#include "OIDtools.h"
+
+niupepahlistbrowserclass::niupepahlistbrowserclass () {
+}
+
+niupepahlistbrowserclass::~niupepahlistbrowserclass () {
+}
+
+
+// overridden for niupepa so CL2 (date classification) wraps in the correct place
+// should probably do this in a more general way some time
+int niupepahlistbrowserclass::output_section_group (ResultDocInfo_t &section, cgiargsclass &args,
+						    const text_t &/*collection*/, int colnumber, 
+						    format_t *formatlistptr, bool use_table, 
+						    text_tset &metadata, bool &getParents, 
+						    recptproto *collectproto, displayclass &disp, 
+						    outconvertclass &outconvert, ostream &textout, 
+						    ostream &logout) {
+
+  // expanded contents are going to cause some nasty recursions
+  // so we'll only continue if being passed the current section
+  if ((args["gc"] == 1) && (section.OID != args["d"])) return 0;
+
+  // get all siblings
+  FilterResponse_t response;
+  text_t &arg_cl = args["cl"];
+  get_children (section.OID + ".pr", args["c"], metadata, getParents, 
+		collectproto, response, logout);
+
+					
+  if (use_table || colnumber > 0) {
+    textout << "<table><tr><td>";
+    // get tab size
+    text_t tab; int itab;
+    disp.expandstring ("Global", "_tabwidth_", tab);
+    itab = tab.getint();
+    if (colnumber > 0) textout << outconvert << disp 
+			       << "<img src=\"_httpimg_/space.gif\" width=" 
+			       << (itab*colnumber) << ">";
+    textout << "</td>\n";
+  }
+
+  textout << "<center><table cellspacing=0><tr>\n";
+
+  ResultDocInfo_tarray::iterator tsibling = response.docInfo.begin();
+  ResultDocInfo_tarray::iterator esibling = response.docInfo.end();
+
+  text_t icon, link;
+  int scount = 1;
+  while (tsibling != esibling) {
+
+    bool highlight = false;
+    textout << "<td";
+    if (scount != 3 && scount != 5 && scount != 6 &&
+	scount != 7 && scount != 8 && scount != 9 &&
+	scount != 10 && scount != 12 && scount != 13)
+      textout << " colspan=2";
+    textout << ">";
+
+    text_t &doctype = (*tsibling).metadata["doctype"].values[0];
+
+    if ((*tsibling).OID == section.OID) {
+      link.clear();
+      highlight = true;
+    } else {
+      link = "<a href=\"_httpdocument_";
+      if (doctype == "classify") 
+	link += "&cl=" + (*tsibling).OID + "\">";
+      else
+	link += "&cl=" + arg_cl + "&d=" + (*tsibling).OID + "\">";
+    }
+
+    textout << outconvert << disp 
+	    << get_formatted_string (*tsibling, formatlistptr, link, icon, highlight);
+
+    textout << "</td>\n";
+    if (scount == 10 || scount == 18)
+      textout << "</tr><tr>\n";
+
+    tsibling ++;
+    scount ++;
+  }
+
+  textout << "<td colspan=2></td></tr></table></center>\n";
+  if (use_table  || colnumber > 0) textout << "</tr></table>\n";
+  return 0;
+}
+
Index: /main/tags/2.25/niupepa/src/recpt/niupepahlistbrowserclass.h
===================================================================
--- /main/tags/2.25/niupepa/src/recpt/niupepahlistbrowserclass.h	(revision 21064)
+++ /main/tags/2.25/niupepa/src/recpt/niupepahlistbrowserclass.h	(revision 21064)
@@ -0,0 +1,51 @@
+/**********************************************************************
+ *
+ * niupepahlistbrowserclass.h -- 
+ * Copyright (C) 1999  The New Zealand Digital Library Project
+ *
+ * A component of the Greenstone digital library software
+ * from the New Zealand Digital Library Project at the
+ * University of Waikato, New Zealand.
+ *
+ * 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.
+ *
+ * $Id$
+ *
+ *********************************************************************/
+
+
+#ifndef NIUPEPAHLISTBROWSERCLASS_H
+#define NIUPEPAHLISTBROWSERCLASS_H
+
+#include "hlistbrowserclass.h"
+
+class niupepahlistbrowserclass : public hlistbrowserclass {
+protected:
+
+public:
+  niupepahlistbrowserclass ();
+  virtual ~niupepahlistbrowserclass ();
+
+  int output_section_group (ResultDocInfo_t &section, cgiargsclass &args,
+			    const text_t &collection, int colnumber, format_t *formatlistptr, 
+			    bool use_table, text_tset &metadata, bool &getParents,
+			    recptproto *collectproto, displayclass &disp, 
+			    outconvertclass &outconvert, ostream &textout, 
+			    ostream &logout);
+  
+};
+
+#endif
+
Index: /main/tags/2.25/niupepa/src/recpt/niupepalibrarymain.cpp
===================================================================
--- /main/tags/2.25/niupepa/src/recpt/niupepalibrarymain.cpp	(revision 21064)
+++ /main/tags/2.25/niupepa/src/recpt/niupepalibrarymain.cpp	(revision 21064)
@@ -0,0 +1,191 @@
+/**********************************************************************
+ *
+ * niupepalibrarymain.cpp -- 
+ * A component of the Greenstone digital library software
+ * from the New Zealand Digital Library Project at the
+ * University of Waikato, New Zealand.
+ *
+ * Copyright (C) 1999  The 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.
+ *
+ * $Id$
+ *
+ *********************************************************************/
+
+/*
+   $Log$
+   Revision 1.1  2000/03/08 20:44:49  sjboddie
+   Initial revision
+
+   Revision 1.2  1999/09/07 22:19:50  sjboddie
+   added GPL header
+
+   Revision 1.1  1999/08/29 23:35:08  sjboddie
+   niupepa receptionist
+
+ */
+
+#include "receptionist.h"
+#include "cgiwrapper.h"
+#include "nullproto.h"
+#include "collectserver.h"
+#include "filter.h"
+#include "browsefilter.h"
+#include "queryfilter.h"
+#include "infodbclass.h"
+#include "mgsearch.h"
+#include "mggdbmsource.h"
+#include "fileutil.h"
+#include <assert.h>
+
+#include "action.h"
+#include "statusaction.h"
+#include "pageaction.h"
+#include "pingaction.h"
+#include "queryaction.h"
+#include "niupepadocaction.h"
+#include "authenaction.h"
+#include "usersaction.h"
+#include "authenaction.h"
+
+#include "browserclass.h"
+#include "niupepavlistbrowserclass.h"
+#include "niupepahlistbrowserclass.h"
+#include "datelistbrowserclass.h"
+#include "invbrowserclass.h"
+#include "niupepapagedbrowserclass.h"
+#include "htmlbrowserclass.h"
+
+#include "recptconfig.h"
+
+int main () {
+  receptionist recpt;
+  nullproto nproto;
+  
+  // add a collection server
+  text_tarray collections;
+  collections.push_back ("niupepa");
+
+  // get gsdlhome (if we fail the error will be picked up later -- in
+  // cgiwrapper)
+  text_t gsdlhome;
+  site_cfg_read (gsdlhome);
+
+  text_tarray::const_iterator thiscol = collections.begin();
+  text_tarray::const_iterator endcol = collections.end();
+
+  while (thiscol != endcol) {
+
+    // this memory is created but never destroyed
+    // we're also not doing any error checking to make sure we didn't
+    // run out of memory
+    collectserver *cserver = new collectserver();
+    gdbmclass *gdbmhandler = new gdbmclass();
+    mgsearchclass *mgsearch = new mgsearchclass();
+    
+    // add a null filter
+    filterclass *filter = new filterclass ();
+    cserver->add_filter (filter);
+    
+    // add a browse filter
+    browsefilterclass *browsefilter = new browsefilterclass();
+    browsefilter->set_gdbmptr (gdbmhandler);
+    cserver->add_filter (browsefilter);
+    
+    // add a query filter
+    queryfilterclass *queryfilter = new queryfilterclass();
+    queryfilter->set_gdbmptr (gdbmhandler);
+    queryfilter->set_mgsearchptr (mgsearch);
+    cserver->add_filter (queryfilter);
+
+    // add a mg and gdbm source
+    mggdbmsourceclass *mggdbmsource = new mggdbmsourceclass ();
+    mggdbmsource->set_gdbmptr (gdbmhandler);
+    mggdbmsource->set_mgsearchptr (mgsearch);
+    cserver->add_source (mggdbmsource);
+    
+    // inform collection server and everything it contains about its
+    // collection name
+    cserver->configure ("collection", *thiscol);
+    
+    nproto.add_collectserver (cserver);
+    thiscol ++;
+  }
+  
+  // add the protocol to the receptionist
+  recpt.add_protocol (&nproto);
+
+  // add other converters
+  utf8inconvertclass utf8inconvert;
+  utf8outconvertclass utf8outconvert;
+  recpt.add_converter ("u", &utf8inconvert, &utf8outconvert);
+
+  if (!gsdlhome.empty()) {
+    mapinconvertclass gbinconvert;
+    gbinconvert.setmapfile (gsdlhome, "gbku", 0x25a1);
+    mapoutconvertclass gboutconvert;
+    gboutconvert.setmapfile (gsdlhome, "ugbk", 0xa1f5);
+    recpt.add_converter ("g", &gbinconvert, &gboutconvert);
+  }
+
+  // the list of actions. Note: these actions will become invalid
+  // at the end of this function.
+  statusaction astatusaction;
+  astatusaction.set_receptionist (&recpt);
+  recpt.add_action (&astatusaction);
+
+  pageaction apageaction;
+  recpt.add_action (&apageaction);
+
+  pingaction apingaction;
+  recpt.add_action (&apingaction);
+
+  queryaction aqueryaction;
+  recpt.add_action (&aqueryaction);
+
+  niupepadocaction adocumentaction;
+  recpt.add_action (&adocumentaction);
+
+  usersaction ausersaction;
+  recpt.add_action (&ausersaction);
+
+  authenaction aauthenaction;
+  aauthenaction.set_receptionist(&recpt);
+  recpt.add_action (&aauthenaction);
+
+  // list of browsers
+  niupepavlistbrowserclass avlistbrowserclass;
+  recpt.add_browser (&avlistbrowserclass);
+  recpt.setdefaultbrowser ("VList");
+
+  niupepahlistbrowserclass ahlistbrowserclass;
+  recpt.add_browser (&ahlistbrowserclass);
+
+  datelistbrowserclass adatelistbrowserclass;
+  recpt.add_browser (&adatelistbrowserclass);
+
+  invbrowserclass ainvbrowserclass;
+  recpt.add_browser (&ainvbrowserclass);
+
+  niupepapagedbrowserclass apagedbrowserclass;
+  recpt.add_browser (&apagedbrowserclass);
+
+  htmlbrowserclass ahtmlbrowserclass;
+  recpt.add_browser (&ahtmlbrowserclass);
+
+  cgiwrapper (recpt, "niupepa");
+  return 0;
+}
Index: /main/tags/2.25/niupepa/src/recpt/niupepapagedbrowserclass.cpp
===================================================================
--- /main/tags/2.25/niupepa/src/recpt/niupepapagedbrowserclass.cpp	(revision 21064)
+++ /main/tags/2.25/niupepa/src/recpt/niupepapagedbrowserclass.cpp	(revision 21064)
@@ -0,0 +1,113 @@
+/**********************************************************************
+ *
+ * niupepapagedbrowserclass.cpp -- 
+ * Copyright (C) 1999  The New Zealand Digital Library Project
+ *
+ * A component of the Greenstone digital library software
+ * from the New Zealand Digital Library Project at the
+ * University of Waikato, New Zealand.
+ *
+ * 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.
+ *
+ * $Id$
+ *
+ *********************************************************************/
+
+/*
+   $Log$
+   Revision 1.1  2000/03/08 20:44:50  sjboddie
+   Initial revision
+
+
+ */
+
+
+#include "niupepapagedbrowserclass.h"
+#include <assert.h>
+#include "OIDtools.h"
+
+niupepapagedbrowserclass::niupepapagedbrowserclass () {
+}
+
+niupepapagedbrowserclass::~niupepapagedbrowserclass () {
+}
+
+// if the "gp" (go to page) argument is set we need to set
+// the "d" argument to the corresponding page
+// also want to set "d" argument to first child if we're at
+// an 'Invisible' top level
+// this is overridden for niupepa collection as we want to set "gg"
+// argument to be 'prev' if it's text and there isn't any text,
+// 'full' if it's prev and there is no prev, 'text' if it's prev
+// and there's no full or prev, 'prev' if it's full and there's
+// no full, 'text' if it's full and there's no full or prev.
+// default to text if all else fails 
+void niupepapagedbrowserclass::processOID (cgiargsclass &args, recptproto *collectproto,
+					   ostream &logout) {
+
+  text_t &arg_d = args["d"];
+  text_t &arg_gp = args["gp"];
+  text_t &arg_gg = args["gg"];
+  text_tset metadata;
+  FilterResponse_t response;
+
+  bool hastxt = false, hasimg = false, hasprevimg = false; 
+
+  if ((!arg_d.empty()) && (!arg_gp.empty()) && (is_number (arg_gp))) {
+    text_t top;
+    get_top (arg_d, top);
+    metadata.insert ("Title");
+    get_children (top, args["c"], metadata, false, collectproto, response, logout);
+    ResultDocInfo_tarray::iterator dochere = response.docInfo.begin();
+    ResultDocInfo_tarray::iterator docend = response.docInfo.end();
+    while (dochere != docend) {
+      if ((*dochere).metadata["Title"].values[0] == arg_gp) {
+        arg_d = (*dochere).OID;
+        break;
+      }
+      dochere ++;
+    }
+
+  } else if (!arg_d.empty() && is_top(arg_d)) { // if top level doc, check if not invisible
+    metadata.insert("thistype");
+    if (get_info(arg_d, args["c"], metadata, false, collectproto, response, logout)) {
+      text_t type = response.docInfo[0].metadata["thistype"].values[0];
+      if (type=="Invisible") { // display first child
+        arg_d = arg_d + ".fc";
+      }
+    }
+  }
+
+  metadata.erase (metadata.begin(), metadata.end());
+  metadata.insert ("hastxt");
+  metadata.insert ("hasimg");
+  metadata.insert ("hasprevimg");
+  if (get_info(arg_d, args["c"], metadata, false, collectproto, response, logout)) {
+    if (response.docInfo[0].metadata["hastxt"].values[0] == "1") hastxt = true;
+    if (response.docInfo[0].metadata["hasimg"].values[0] == "1") hasimg = true;
+    if (response.docInfo[0].metadata["hasprevimg"].values[0] == "1") hasprevimg = true;
+  }
+
+  if (arg_gg == "text" && !hastxt) {
+    if (hasprevimg) arg_gg = "prev";
+    else if (hasimg) arg_gg = "full";
+  } else if (arg_gg == "prev" && !hasprevimg) {
+    if (hasimg) arg_gg = "full";
+    else arg_gg = "text";
+  } else if (arg_gg == "full" && !hasimg) {
+    if (hasprevimg) arg_gg = "prev";
+    else arg_gg = "text";
+  }
+}
Index: /main/tags/2.25/niupepa/src/recpt/niupepapagedbrowserclass.h
===================================================================
--- /main/tags/2.25/niupepa/src/recpt/niupepapagedbrowserclass.h	(revision 21064)
+++ /main/tags/2.25/niupepa/src/recpt/niupepapagedbrowserclass.h	(revision 21064)
@@ -0,0 +1,46 @@
+/**********************************************************************
+ *
+ * niupepapagedbrowserclass.h -- 
+ * Copyright (C) 1999  The New Zealand Digital Library Project
+ *
+ * A component of the Greenstone digital library software
+ * from the New Zealand Digital Library Project at the
+ * University of Waikato, New Zealand.
+ *
+ * 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.
+ *
+ * $Id$
+ *
+ *********************************************************************/
+
+
+#ifndef NIUPEPAPAGEDBROWSERCLASS_H
+#define NIUPEPAPAGEDBROWSERCLASS_H
+
+#include "pagedbrowserclass.h"
+
+class niupepapagedbrowserclass : public pagedbrowserclass {
+protected:
+
+public:
+
+  niupepapagedbrowserclass ();
+  virtual ~niupepapagedbrowserclass ();
+
+  virtual void processOID (cgiargsclass &args, recptproto *collectproto,
+			   ostream &logout);
+};
+
+#endif
Index: /main/tags/2.25/niupepa/src/recpt/niupepavlistbrowserclass.cpp
===================================================================
--- /main/tags/2.25/niupepa/src/recpt/niupepavlistbrowserclass.cpp	(revision 21064)
+++ /main/tags/2.25/niupepa/src/recpt/niupepavlistbrowserclass.cpp	(revision 21064)
@@ -0,0 +1,145 @@
+/**********************************************************************
+ *
+ * niupepavlistbrowserclass.cpp -- 
+ * Copyright (C) 1999  The New Zealand Digital Library Project
+ *
+ * A component of the Greenstone digital library software
+ * from the New Zealand Digital Library Project at the
+ * University of Waikato, New Zealand.
+ *
+ * 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.
+ *
+ * $Id$
+ *
+ *********************************************************************/
+
+/*
+   $Log$
+   Revision 1.1  2000/03/08 20:44:50  sjboddie
+   Initial revision
+
+
+ */
+
+#include "niupepavlistbrowserclass.h"
+#include <assert.h>
+#include "OIDtools.h"
+
+niupepavlistbrowserclass::niupepavlistbrowserclass () {
+}
+
+niupepavlistbrowserclass::~niupepavlistbrowserclass () {
+}
+
+void niupepavlistbrowserclass::load_metadata_defaults (text_tset &metadata) {
+  metadata.insert ("haschildren");
+  metadata.insert ("doctype");
+  metadata.insert ("abstract");
+}
+
+// get_link_icon attempts to work out what type of icon should be displayed for
+// the given section and what it should link to.
+// overridden for niupepa to add links/icons for abstracts as well as 
+// papers
+void niupepavlistbrowserclass::get_link_icon (ResultDocInfo_t &section, cgiargsclass &args,
+					      const text_t &collink, text_t &link, text_t &icon) {
+
+  link = "<a href=\"_httpdocument_" + collink;
+  icon = "_document:icontext_";
+  int haschildren = 0;
+
+  if (section.metadata.count("haschildren") > 0)
+    haschildren = section.metadata["haschildren"].values[0].getint();
+
+  text_t doctype;
+  if (section.metadata.count("doctype") > 0)
+    doctype = section.metadata["doctype"].values[0];
+
+  text_t abstract;
+  if (section.metadata.count("abstract") > 0)
+    abstract = section.metadata["abstract"].values[0];
+
+  text_t &arg_d = args["d"];
+  text_t &arg_cl = args["cl"];
+
+  if (args["a"] == "q") {
+    // query results
+    if (doctype == "Description") {
+      icon = "_document:iconabstract_";
+      link += "&gg=text";
+    } else if (doctype == "Commentary") {
+      icon = "_document:iconcommentary_";
+      link += "&gg=text";
+    } else {
+      if (is_top (section.OID)) icon = "_document:iconclosedbook_";
+      else if (haschildren == 1) icon = "_document:iconclosedfolder_";
+    }
+    link += "&cl=search&d=" + section.OID + "\">";
+
+  } else if (!arg_d.empty()) {
+    // document level
+    if (is_top(section.OID)) {
+      icon = "_document:iconopenbook_";
+      if (arg_cl == "search") link = "<a href=\"_httpquery_\">";
+      else link += "&cl=" + arg_cl + "\">";
+    
+    } else if (haschildren == 1) {
+      if ((args["gc"] == "1") || 
+	  (is_child_of (section.OID, arg_d)) ||
+	  (section.OID == arg_d)) {
+	icon = "_document:iconopenfolder_";
+	link += "&cl=" + arg_cl + "&d=" + section.OID + ".pr\">";
+      } else {
+	icon = "_document:iconclosedfolder_";
+	link += "&cl=" + arg_cl + "&d=" + section.OID + "\">";
+      }
+    } else link += "&cl=" + arg_cl + "&d=" + section.OID + "\">";
+
+  } else {
+    // classification level
+    if (haschildren == 1) {
+      if (doctype == "classify") {
+	if ((args["gc"] == "1") || 
+	    (is_child_of (section.OID, arg_cl)) || 
+	    (section.OID == arg_cl)) {
+	  icon = "_document:iconopenbookshelf_";
+	  link += "&cl=" + section.OID + ".pr\">" + icon + "</a>";
+	} else {
+	  icon = "_document:iconclosedbookshelf_";
+	  link += "&cl=" + section.OID + "\">" + icon + "</a>";
+	}
+      } else {
+	icon = "_document:iconclosedbook_";
+	if (!abstract.empty())
+	  link += "&gg=text&cl=" + arg_cl + "&d=" + abstract + "\">"
+	    + "_document:iconabstract_</a>" + link +
+	    "&cl=" + arg_cl + "&d=" + section.OID + "\">"
+	    + icon + "</a>";
+	else 
+	  link += "&cl=" + arg_cl + "&d=" + section.OID + "\">"
+	    + icon + "</a>";
+      }
+    } else {
+      if (doctype == "classify") link = "";
+      else if (doctype == "Commentary")
+	link += "&gg=text&cl=" + arg_cl + "&d=" + section.OID + "\">"
+	  + "_document:iconcommentary_</a>";
+      else if (doctype == "Description")
+	link += "&cl=" + arg_cl + "&d=" + section.OID + "\">"
+	  + "_document:iconabstract_</a>";
+      else link += "&cl=" + arg_cl + "&d=" + section.OID + "\">";
+    }
+  }
+}
Index: /main/tags/2.25/niupepa/src/recpt/niupepavlistbrowserclass.h
===================================================================
--- /main/tags/2.25/niupepa/src/recpt/niupepavlistbrowserclass.h	(revision 21064)
+++ /main/tags/2.25/niupepa/src/recpt/niupepavlistbrowserclass.h	(revision 21064)
@@ -0,0 +1,49 @@
+/**********************************************************************
+ *
+ * niupepavlistbrowserclass.h -- 
+ * Copyright (C) 1999  The New Zealand Digital Library Project
+ *
+ * A component of the Greenstone digital library software
+ * from the New Zealand Digital Library Project at the
+ * University of Waikato, New Zealand.
+ *
+ * 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.
+ *
+ * $Id$
+ *
+ *********************************************************************/
+
+
+#ifndef NIUPEPAVLISTBROWSERCLASS_H
+#define NIUPEPAVLISTBROWSERCLASS_H
+
+#include "vlistbrowserclass.h"
+
+class niupepavlistbrowserclass : public vlistbrowserclass {
+protected:
+
+public:
+  niupepavlistbrowserclass ();
+  virtual ~niupepavlistbrowserclass ();
+
+  void load_metadata_defaults (text_tset &metadata);
+
+protected:
+  
+  void get_link_icon (ResultDocInfo_t &section, cgiargsclass &args,
+		      const text_t &collink, text_t &link, text_t &icon);
+};
+
+#endif
